summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16')
-rw-r--r--private/mvdm/wow16/bin/rcpp.err334
-rw-r--r--private/mvdm/wow16/commdlg/_xlib.h56
-rw-r--r--private/mvdm/wow16/commdlg/cddrv.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/cderr.h58
-rw-r--r--private/mvdm/wow16/commdlg/colordlg.h49
-rw-r--r--private/mvdm/wow16/commdlg/commdlg.asm59
-rw-r--r--private/mvdm/wow16/commdlg/commdlg.def59
-rw-r--r--private/mvdm/wow16/commdlg/commdlg.h318
-rw-r--r--private/mvdm/wow16/commdlg/crosshr.bmpbin0 -> 190 bytes
-rw-r--r--private/mvdm/wow16/commdlg/dlgs.c112
-rw-r--r--private/mvdm/wow16/commdlg/dlgs.h192
-rw-r--r--private/mvdm/wow16/commdlg/down.bmpbin0 -> 182 bytes
-rw-r--r--private/mvdm/wow16/commdlg/downi.bmpbin0 -> 182 bytes
-rw-r--r--private/mvdm/wow16/commdlg/filebmps.bmpbin0 -> 1142 bytes
-rw-r--r--private/mvdm/wow16/commdlg/font.bmpbin0 -> 598 bytes
-rw-r--r--private/mvdm/wow16/commdlg/font.c1959
-rw-r--r--private/mvdm/wow16/commdlg/font.h27
-rw-r--r--private/mvdm/wow16/commdlg/isz.h175
-rw-r--r--private/mvdm/wow16/commdlg/landscap.icobin0 -> 1846 bytes
-rw-r--r--private/mvdm/wow16/commdlg/left.bmpbin0 -> 158 bytes
-rw-r--r--private/mvdm/wow16/commdlg/lefti.bmpbin0 -> 158 bytes
-rw-r--r--private/mvdm/wow16/commdlg/makefile156
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/color.dlg61
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/commdlg.rc53
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/commdlg.rcv24
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/fileopen.dlg94
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/findtext.dlg82
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/font.dlg32
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/prnsetup.dlg66
-rw-r--r--private/mvdm/wow16/commdlg/messages/usa/sz.src155
-rw-r--r--private/mvdm/wow16/commdlg/parse.c369
-rw-r--r--private/mvdm/wow16/commdlg/parse.h21
-rw-r--r--private/mvdm/wow16/commdlg/portrait.icobin0 -> 1846 bytes
-rw-r--r--private/mvdm/wow16/commdlg/privcomd.h167
-rw-r--r--private/mvdm/wow16/commdlg/right.bmpbin0 -> 158 bytes
-rw-r--r--private/mvdm/wow16/commdlg/righti.bmpbin0 -> 158 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smflder.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smfldr1.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smfldr2.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smfldr3.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smfldr4.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smfldr5.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smflopy.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smhard.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smnet.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/smram.bmpbin0 -> 246 bytes
-rw-r--r--private/mvdm/wow16/commdlg/start.asm73
-rw-r--r--private/mvdm/wow16/commdlg/up.bmpbin0 -> 182 bytes
-rw-r--r--private/mvdm/wow16/commdlg/upi.bmpbin0 -> 182 bytes
-rw-r--r--private/mvdm/wow16/commdlg/xlib.h55
-rw-r--r--private/mvdm/wow16/ctl3dv2/3d.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ctl3dv2/3dcheck.bmpbin0 -> 1522 bytes
-rw-r--r--private/mvdm/wow16/ctl3dv2/common.ver86
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.c3732
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.def41
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.dif3895
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.docbin0 -> 14336 bytes
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.h95
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3d.rc65
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctl3dv2.def41
-rw-r--r--private/mvdm/wow16/ctl3dv2/ctls.dlg51
-rw-r--r--private/mvdm/wow16/ctl3dv2/loaddib.h16
-rw-r--r--private/mvdm/wow16/ctl3dv2/msdn.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ctl3dv2/new3d.docbin0 -> 14336 bytes
-rw-r--r--private/mvdm/wow16/ctl3dv2/readme.txt5
-rw-r--r--private/mvdm/wow16/ctl3dv2/scomp.dif103
-rw-r--r--private/mvdm/wow16/ctl3dv2/version.h63
-rw-r--r--private/mvdm/wow16/ddeml/ddeml.c2342
-rw-r--r--private/mvdm/wow16/ddeml/ddeml.def60
-rw-r--r--private/mvdm/wow16/ddeml/ddemlp.h727
-rw-r--r--private/mvdm/wow16/ddeml/dmgdb.c954
-rw-r--r--private/mvdm/wow16/ddeml/dmgdde.c526
-rw-r--r--private/mvdm/wow16/ddeml/dmghsz.c174
-rw-r--r--private/mvdm/wow16/ddeml/dmgmem.c642
-rw-r--r--private/mvdm/wow16/ddeml/dmgmon.c295
-rw-r--r--private/mvdm/wow16/ddeml/dmgq.c210
-rw-r--r--private/mvdm/wow16/ddeml/dmgutil.asm70
-rw-r--r--private/mvdm/wow16/ddeml/dmgwndp.c1378
-rw-r--r--private/mvdm/wow16/ddeml/hdata.c487
-rw-r--r--private/mvdm/wow16/ddeml/heapwach.c108
-rw-r--r--private/mvdm/wow16/ddeml/heapwach.h3
-rw-r--r--private/mvdm/wow16/ddeml/libentry.asm77
-rw-r--r--private/mvdm/wow16/ddeml/makefile142
-rw-r--r--private/mvdm/wow16/ddeml/messages/usa/ddeml.dlg27
-rw-r--r--private/mvdm/wow16/ddeml/messages/usa/ddeml.rc5
-rw-r--r--private/mvdm/wow16/ddeml/messages/usa/ddeml.rcv30
-rw-r--r--private/mvdm/wow16/ddeml/register.c140
-rw-r--r--private/mvdm/wow16/ddeml/stdinit.c464
-rw-r--r--private/mvdm/wow16/ddeml/stdptcl.c822
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddes16.symbin0 -> 34692 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/client.c160
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c990
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c1856
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def17
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h287
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc13
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt110
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/globals.c106
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/globals.h19
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/makefile6
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos50
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd1
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd13
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat12
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/server.c1372
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/sources24
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c793
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h80
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/clinit.c146
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/conv.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/dde.c644
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.c1235
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.def30
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.dlg144
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.h258
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.rc93
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/dialog.c875
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/dialog.h41
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/huge.c191
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/huge.h8
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/infoctrl.c686
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/infoctrl.h83
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/list.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/makefile6
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/makefile.dos48
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/mem.c70
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/mk4dos.cmd13
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/sources29
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/track.c241
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/client/track.h20
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.c538
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.def17
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/makefile6
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/makefile.dos24
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/mk4dos.cmd13
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/ddemo/sources19
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/dirs4
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/makedos.bat11
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/mls.cmd2
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/dde.c674
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/ddemlsv.c628
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/dialog.c248
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/dialog.h11
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/huge.c192
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/huge.h8
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/makefile6
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/makefile.dos36
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/mk4dos.cmd13
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/server.def24
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/server.dlg61
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/server.h157
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/server.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/server.rc34
-rw-r--r--private/mvdm/wow16/ddeml/tests/src/server/sources25
-rw-r--r--private/mvdm/wow16/ddeml/verddeml.h4
-rw-r--r--private/mvdm/wow16/drivers/comm/bimodint.inc95
-rw-r--r--private/mvdm/wow16/drivers/comm/ccom.asm616
-rw-r--r--private/mvdm/wow16/drivers/comm/comdev.h243
-rw-r--r--private/mvdm/wow16/drivers/comm/comdev.inc103
-rw-r--r--private/mvdm/wow16/drivers/comm/comdevi.h28
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.def42
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.rc4
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.rcv12
-rw-r--r--private/mvdm/wow16/drivers/comm/commmsg.asm51
-rw-r--r--private/mvdm/wow16/drivers/comm/ddkmake47
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom.asm1947
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom.inc265
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom1.asm1556
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmint.asm1374
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmlpt.asm412
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmsetup.asm2878
-rw-r--r--private/mvdm/wow16/drivers/comm/ins8250.inc78
-rw-r--r--private/mvdm/wow16/drivers/comm/makefile127
-rw-r--r--private/mvdm/wow16/drivers/display/config.asm64
-rw-r--r--private/mvdm/wow16/drivers/display/display.asm88
-rw-r--r--private/mvdm/wow16/drivers/display/display.def17
-rw-r--r--private/mvdm/wow16/drivers/display/display.rc8
-rw-r--r--private/mvdm/wow16/drivers/display/display.rcv12
-rw-r--r--private/mvdm/wow16/drivers/display/makefile121
-rw-r--r--private/mvdm/wow16/drivers/keyboard/kbd.def118
-rw-r--r--private/mvdm/wow16/drivers/keyboard/kbdlocal.asm301
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.asm155
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.def30
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.rc4
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.rcv12
-rw-r--r--private/mvdm/wow16/drivers/keyboard/makefile114
-rw-r--r--private/mvdm/wow16/drivers/mouse/makefile110
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.asm224
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.def16
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.rc4
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.rcv12
-rw-r--r--private/mvdm/wow16/drivers/sound/makefile109
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.asm88
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.def27
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.rc4
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.rcv12
-rw-r--r--private/mvdm/wow16/gdi/fontres.c119
-rw-r--r--private/mvdm/wow16/gdi/gdi.api3047
-rw-r--r--private/mvdm/wow16/gdi/gdi.asm551
-rw-r--r--private/mvdm/wow16/gdi/gdi.def405
-rw-r--r--private/mvdm/wow16/gdi/gdi.rc5
-rw-r--r--private/mvdm/wow16/gdi/gdi.rcv13
-rw-r--r--private/mvdm/wow16/gdi/gdi16.h422
-rw-r--r--private/mvdm/wow16/gdi/gdimacro.inc676
-rw-r--r--private/mvdm/wow16/gdi/gdimem.inc50
-rw-r--r--private/mvdm/wow16/gdi/layer.asm47
-rw-r--r--private/mvdm/wow16/gdi/makefile126
-rw-r--r--private/mvdm/wow16/gdi/meta.c1835
-rw-r--r--private/mvdm/wow16/gdi/metacons.inc90
-rw-r--r--private/mvdm/wow16/gdi/metarec.c2325
-rw-r--r--private/mvdm/wow16/gdi/metasup.c523
-rw-r--r--private/mvdm/wow16/gdi/muldiv.asm110
-rw-r--r--private/mvdm/wow16/gdi/sort.asm706
-rw-r--r--private/mvdm/wow16/inc/cderr.h58
-rw-r--r--private/mvdm/wow16/inc/cmacros.inc1413
-rw-r--r--private/mvdm/wow16/inc/cmacros.mas2666
-rw-r--r--private/mvdm/wow16/inc/cmstrip.c102
-rw-r--r--private/mvdm/wow16/inc/commdlg.h318
-rw-r--r--private/mvdm/wow16/inc/common.ver101
-rw-r--r--private/mvdm/wow16/inc/convdll.inc58
-rw-r--r--private/mvdm/wow16/inc/cpl.h159
-rw-r--r--private/mvdm/wow16/inc/custcntl.h105
-rw-r--r--private/mvdm/wow16/inc/dbcs.c115
-rw-r--r--private/mvdm/wow16/inc/dbcs.h7
-rw-r--r--private/mvdm/wow16/inc/dde.h146
-rw-r--r--private/mvdm/wow16/inc/ddeml.h459
-rw-r--r--private/mvdm/wow16/inc/debug.h32
-rw-r--r--private/mvdm/wow16/inc/debugsys.inc867
-rw-r--r--private/mvdm/wow16/inc/dlgs.h192
-rw-r--r--private/mvdm/wow16/inc/dosx.inc47
-rw-r--r--private/mvdm/wow16/inc/drivinit.h2
-rw-r--r--private/mvdm/wow16/inc/gdidefs.inc1292
-rw-r--r--private/mvdm/wow16/inc/gpfix.inc62
-rw-r--r--private/mvdm/wow16/inc/header.txt364
-rw-r--r--private/mvdm/wow16/inc/ime.h210
-rw-r--r--private/mvdm/wow16/inc/int31.inc136
-rw-r--r--private/mvdm/wow16/inc/io.h47
-rw-r--r--private/mvdm/wow16/inc/klayer.inc1367
-rw-r--r--private/mvdm/wow16/inc/layer.inc1386
-rw-r--r--private/mvdm/wow16/inc/logerror.h186
-rw-r--r--private/mvdm/wow16/inc/logerror.inc159
-rw-r--r--private/mvdm/wow16/inc/lzdos.h5
-rw-r--r--private/mvdm/wow16/inc/lzexpand.h95
-rw-r--r--private/mvdm/wow16/inc/memory.h56
-rw-r--r--private/mvdm/wow16/inc/mmddk.h414
-rw-r--r--private/mvdm/wow16/inc/mmddk.inc337
-rw-r--r--private/mvdm/wow16/inc/mmsystem.h1954
-rw-r--r--private/mvdm/wow16/inc/mmsystem.inc1490
-rw-r--r--private/mvdm/wow16/inc/multires.h71
-rw-r--r--private/mvdm/wow16/inc/newexe.inc332
-rw-r--r--private/mvdm/wow16/inc/ole.h504
-rw-r--r--private/mvdm/wow16/inc/paswindw.inc5327
-rw-r--r--private/mvdm/wow16/inc/penwin.h818
-rw-r--r--private/mvdm/wow16/inc/prd.inc69
-rw-r--r--private/mvdm/wow16/inc/print.h302
-rw-r--r--private/mvdm/wow16/inc/printer.h258
-rw-r--r--private/mvdm/wow16/inc/rom.inc50
-rw-r--r--private/mvdm/wow16/inc/shellapi.h99
-rw-r--r--private/mvdm/wow16/inc/spl_wnt.h248
-rw-r--r--private/mvdm/wow16/inc/spool.h175
-rw-r--r--private/mvdm/wow16/inc/stdarg.h42
-rw-r--r--private/mvdm/wow16/inc/stdio.h254
-rw-r--r--private/mvdm/wow16/inc/stdlib.h212
-rw-r--r--private/mvdm/wow16/inc/string.h121
-rw-r--r--private/mvdm/wow16/inc/strtable.h136
-rw-r--r--private/mvdm/wow16/inc/style.h206
-rw-r--r--private/mvdm/wow16/inc/testing.h50
-rw-r--r--private/mvdm/wow16/inc/time.h118
-rw-r--r--private/mvdm/wow16/inc/userproc.h38
-rw-r--r--private/mvdm/wow16/inc/ver.h255
-rw-r--r--private/mvdm/wow16/inc/version.h64
-rw-r--r--private/mvdm/wow16/inc/w32sys.h24
-rw-r--r--private/mvdm/wow16/inc/wfwnet.h72
-rw-r--r--private/mvdm/wow16/inc/wife.h1103
-rw-r--r--private/mvdm/wow16/inc/win3deb.inc186
-rw-r--r--private/mvdm/wow16/inc/windefs.inc124
-rw-r--r--private/mvdm/wow16/inc/windows.h5724
-rw-r--r--private/mvdm/wow16/inc/windows.inc2418
-rw-r--r--private/mvdm/wow16/inc/windowsx.h1112
-rw-r--r--private/mvdm/wow16/inc/winexp.h47
-rw-r--r--private/mvdm/wow16/inc/winnet.h507
-rw-r--r--private/mvdm/wow16/inc/winnls.h91
-rw-r--r--private/mvdm/wow16/inc/wmsyserr.h37
-rw-r--r--private/mvdm/wow16/kernel31/2galloc.asm2441
-rw-r--r--private/mvdm/wow16/kernel31/2gcompac.asm1452
-rw-r--r--private/mvdm/wow16/kernel31/2ginterf.asm2039
-rw-r--r--private/mvdm/wow16/kernel31/2glru.asm595
-rw-r--r--private/mvdm/wow16/kernel31/2gmem.asm1321
-rw-r--r--private/mvdm/wow16/kernel31/2gmemini.asm830
-rw-r--r--private/mvdm/wow16/kernel31/2gmoreme.asm917
-rw-r--r--private/mvdm/wow16/kernel31/2protect.asm4141
-rw-r--r--private/mvdm/wow16/kernel31/3gacheck.asm199
-rw-r--r--private/mvdm/wow16/kernel31/3galloc.asm1678
-rw-r--r--private/mvdm/wow16/kernel31/3gcompac.asm1583
-rw-r--r--private/mvdm/wow16/kernel31/3ginterf.asm2274
-rw-r--r--private/mvdm/wow16/kernel31/3glru.asm593
-rw-r--r--private/mvdm/wow16/kernel31/3gmem.asm1375
-rw-r--r--private/mvdm/wow16/kernel31/3gmemini.asm636
-rw-r--r--private/mvdm/wow16/kernel31/3gmoreme.asm723
-rw-r--r--private/mvdm/wow16/kernel31/3protect.asm4653
-rw-r--r--private/mvdm/wow16/kernel31/aliases.asm302
-rw-r--r--private/mvdm/wow16/kernel31/appl.inc49
-rw-r--r--private/mvdm/wow16/kernel31/atom.asm452
-rw-r--r--private/mvdm/wow16/kernel31/context.asm1393
-rw-r--r--private/mvdm/wow16/kernel31/diag.asm225
-rw-r--r--private/mvdm/wow16/kernel31/disasm.c737
-rw-r--r--private/mvdm/wow16/kernel31/diskio.asm126
-rw-r--r--private/mvdm/wow16/kernel31/dosinit.asm1363
-rw-r--r--private/mvdm/wow16/kernel31/eems.inc15
-rw-r--r--private/mvdm/wow16/kernel31/emsmisc.asm172
-rw-r--r--private/mvdm/wow16/kernel31/enable.asm652
-rw-r--r--private/mvdm/wow16/kernel31/error.c405
-rw-r--r--private/mvdm/wow16/kernel31/fixexe.c66
-rw-r--r--private/mvdm/wow16/kernel31/gacheck.asm215
-rw-r--r--private/mvdm/wow16/kernel31/gpcont.asm272
-rw-r--r--private/mvdm/wow16/kernel31/gpcont.inc9
-rw-r--r--private/mvdm/wow16/kernel31/gpfix.asm436
-rw-r--r--private/mvdm/wow16/kernel31/handle.asm75
-rw-r--r--private/mvdm/wow16/kernel31/hmem.asm273
-rw-r--r--private/mvdm/wow16/kernel31/i21entry.asm1677
-rw-r--r--private/mvdm/wow16/kernel31/i21file.asm862
-rw-r--r--private/mvdm/wow16/kernel31/i21task.asm1378
-rw-r--r--private/mvdm/wow16/kernel31/ikernel.h73
-rw-r--r--private/mvdm/wow16/kernel31/ikernel.inc88
-rw-r--r--private/mvdm/wow16/kernel31/int24.asm558
-rw-r--r--private/mvdm/wow16/kernel31/intnn.asm133
-rw-r--r--private/mvdm/wow16/kernel31/kdata.asm540
-rw-r--r--private/mvdm/wow16/kernel31/kdataend.asm22
-rw-r--r--private/mvdm/wow16/kernel31/kdos.inc39
-rw-r--r--private/mvdm/wow16/kernel31/kernel.api1217
-rw-r--r--private/mvdm/wow16/kernel31/kernel.def472
-rw-r--r--private/mvdm/wow16/kernel31/kernel.h654
-rw-r--r--private/mvdm/wow16/kernel31/kernel.inc1259
-rw-r--r--private/mvdm/wow16/kernel31/kernel.rcv13
-rw-r--r--private/mvdm/wow16/kernel31/kernel.sed9
-rw-r--r--private/mvdm/wow16/kernel31/kernstub.asm118
-rw-r--r--private/mvdm/wow16/kernel31/krnl286.lnk13
-rw-r--r--private/mvdm/wow16/kernel31/krnl286.rc7
-rw-r--r--private/mvdm/wow16/kernel31/krnl386.lnk14
-rw-r--r--private/mvdm/wow16/kernel31/krnl386.rc7
-rw-r--r--private/mvdm/wow16/kernel31/krom.inc6
-rw-r--r--private/mvdm/wow16/kernel31/ksource.txt187
-rw-r--r--private/mvdm/wow16/kernel31/kthunks.asm460
-rw-r--r--private/mvdm/wow16/kernel31/lacheck.asm258
-rw-r--r--private/mvdm/wow16/kernel31/lalloc.asm835
-rw-r--r--private/mvdm/wow16/kernel31/layer.asm28
-rw-r--r--private/mvdm/wow16/kernel31/lcompact.asm851
-rw-r--r--private/mvdm/wow16/kernel31/ld.asm3699
-rw-r--r--private/mvdm/wow16/kernel31/ldappl.asm385
-rw-r--r--private/mvdm/wow16/kernel31/ldaux.asm880
-rw-r--r--private/mvdm/wow16/kernel31/ldboot.asm3313
-rw-r--r--private/mvdm/wow16/kernel31/ldcache.asm384
-rw-r--r--private/mvdm/wow16/kernel31/lddebug.asm2230
-rw-r--r--private/mvdm/wow16/kernel31/ldfastb.asm274
-rw-r--r--private/mvdm/wow16/kernel31/ldfile.asm329
-rw-r--r--private/mvdm/wow16/kernel31/ldheader.asm853
-rw-r--r--private/mvdm/wow16/kernel31/ldint.asm1490
-rw-r--r--private/mvdm/wow16/kernel31/ldopen.asm2298
-rw-r--r--private/mvdm/wow16/kernel31/ldreloc.asm759
-rw-r--r--private/mvdm/wow16/kernel31/ldseg.asm1813
-rw-r--r--private/mvdm/wow16/kernel31/ldself.asm566
-rw-r--r--private/mvdm/wow16/kernel31/ldstack.asm106
-rw-r--r--private/mvdm/wow16/kernel31/ldutil.asm1322
-rw-r--r--private/mvdm/wow16/kernel31/lhandle.asm274
-rw-r--r--private/mvdm/wow16/kernel31/linterf.asm1572
-rw-r--r--private/mvdm/wow16/kernel31/log.slm1005
-rw-r--r--private/mvdm/wow16/kernel31/lstring.asm688
-rw-r--r--private/mvdm/wow16/kernel31/lzexp.c174
-rw-r--r--private/mvdm/wow16/kernel31/m.msg0
-rw-r--r--private/mvdm/wow16/kernel31/makefile836
-rw-r--r--private/mvdm/wow16/kernel31/mapdata.asm66
-rw-r--r--private/mvdm/wow16/kernel31/messages/usa/strings.asm258
-rw-r--r--private/mvdm/wow16/kernel31/miscapi.asm569
-rw-r--r--private/mvdm/wow16/kernel31/module.asm599
-rw-r--r--private/mvdm/wow16/kernel31/newexe.doc391
-rw-r--r--private/mvdm/wow16/kernel31/newexe.h380
-rw-r--r--private/mvdm/wow16/kernel31/patch.asm1502
-rw-r--r--private/mvdm/wow16/kernel31/patch.txt233
-rw-r--r--private/mvdm/wow16/kernel31/pdb.inc41
-rw-r--r--private/mvdm/wow16/kernel31/protect.inc181
-rw-r--r--private/mvdm/wow16/kernel31/qgrep.grp269
-rw-r--r--private/mvdm/wow16/kernel31/reboot.asm375
-rw-r--r--private/mvdm/wow16/kernel31/resaux.asm1852
-rw-r--r--private/mvdm/wow16/kernel31/rip.c698
-rw-r--r--private/mvdm/wow16/kernel31/ripaux.asm1083
-rw-r--r--private/mvdm/wow16/kernel31/rom.asm283
-rw-r--r--private/mvdm/wow16/kernel31/schedule.asm674
-rw-r--r--private/mvdm/wow16/kernel31/stack.asm126
-rw-r--r--private/mvdm/wow16/kernel31/state.rst7
-rw-r--r--private/mvdm/wow16/kernel31/swappro/makefile15
-rw-r--r--private/mvdm/wow16/kernel31/swappro/swap.c757
-rw-r--r--private/mvdm/wow16/kernel31/swappro/swap.docbin0 -> 6656 bytes
-rw-r--r--private/mvdm/wow16/kernel31/task.asm1954
-rw-r--r--private/mvdm/wow16/kernel31/tasking.asm590
-rw-r--r--private/mvdm/wow16/kernel31/tdb.inc235
-rw-r--r--private/mvdm/wow16/kernel31/up.c2390
-rw-r--r--private/mvdm/wow16/kernel31/userpro.asm1872
-rw-r--r--private/mvdm/wow16/kernel31/w32sys.asm39
-rw-r--r--private/mvdm/wow16/kernel31/winexec.asm331
-rw-r--r--private/mvdm/wow16/kernel31/winkern.inc489
-rw-r--r--private/mvdm/wow16/kernel31/wow16cal.asm1418
-rw-r--r--private/mvdm/wow16/kernel31/wowdeb.asm114
-rw-r--r--private/mvdm/wow16/killwow/killwow.c31
-rw-r--r--private/mvdm/wow16/killwow/killwow.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/killwow/killwow.rc5
-rw-r--r--private/mvdm/wow16/killwow/killwow.rcv12
-rw-r--r--private/mvdm/wow16/killwow/makefile121
-rw-r--r--private/mvdm/wow16/lib/makefile56
-rw-r--r--private/mvdm/wow16/makefile134
-rw-r--r--private/mvdm/wow16/mciole/libinit.asm151
-rw-r--r--private/mvdm/wow16/mciole/makefile85
-rw-r--r--private/mvdm/wow16/mciole/mciole.c1553
-rw-r--r--private/mvdm/wow16/mciole/mciole.def43
-rw-r--r--private/mvdm/wow16/mciole/mciole.h77
-rw-r--r--private/mvdm/wow16/mciole/mciole16.rc5
-rw-r--r--private/mvdm/wow16/mciole/mciole16.rcv13
-rw-r--r--private/mvdm/wow16/mciole/ole.h504
-rw-r--r--private/mvdm/wow16/mciole/shellapi.h88
-rw-r--r--private/mvdm/wow16/mmsystem/auxout.c171
-rw-r--r--private/mvdm/wow16/mmsystem/bwinexec.asm222
-rw-r--r--private/mvdm/wow16/mmsystem/comm.asm164
-rw-r--r--private/mvdm/wow16/mmsystem/debug.asm710
-rw-r--r--private/mvdm/wow16/mmsystem/debug.h80
-rw-r--r--private/mvdm/wow16/mmsystem/dosa.asm266
-rw-r--r--private/mvdm/wow16/mmsystem/dpmipage.asm384
-rw-r--r--private/mvdm/wow16/mmsystem/drvproc.c379
-rw-r--r--private/mvdm/wow16/mmsystem/drvr.c213
-rw-r--r--private/mvdm/wow16/mmsystem/drvr.h51
-rw-r--r--private/mvdm/wow16/mmsystem/drvr31.asm195
-rw-r--r--private/mvdm/wow16/mmsystem/drvrrare.c873
-rw-r--r--private/mvdm/wow16/mmsystem/drvrstr.c25
-rw-r--r--private/mvdm/wow16/mmsystem/gmem.h69
-rw-r--r--private/mvdm/wow16/mmsystem/heap.asm278
-rw-r--r--private/mvdm/wow16/mmsystem/hmemcpy.asm248
-rw-r--r--private/mvdm/wow16/mmsystem/idrv.h517
-rw-r--r--private/mvdm/wow16/mmsystem/init.c671
-rw-r--r--private/mvdm/wow16/mmsystem/int31.inc144
-rw-r--r--private/mvdm/wow16/mmsystem/isr.asm225
-rw-r--r--private/mvdm/wow16/mmsystem/joy.c725
-rw-r--r--private/mvdm/wow16/mmsystem/libentry.asm144
-rw-r--r--private/mvdm/wow16/mmsystem/makefile261
-rw-r--r--private/mvdm/wow16/mmsystem/mci.c2232
-rw-r--r--private/mvdm/wow16/mmsystem/mciparse.c1439
-rw-r--r--private/mvdm/wow16/mmsystem/mcisys.c1817
-rw-r--r--private/mvdm/wow16/mmsystem/messages/usa/mci.rc848
-rw-r--r--private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rc197
-rw-r--r--private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rcv12
-rw-r--r--private/mvdm/wow16/mmsystem/messages/usa/mmtask.rc2
-rw-r--r--private/mvdm/wow16/mmsystem/messages/usa/mmtask.rcv12
-rw-r--r--private/mvdm/wow16/mmsystem/midi.c1728
-rw-r--r--private/mvdm/wow16/mmsystem/mixer.c1950
-rw-r--r--private/mvdm/wow16/mmsystem/mixmgri.h368
-rw-r--r--private/mvdm/wow16/mmsystem/mmio.c1961
-rw-r--r--private/mvdm/wow16/mmsystem/mmiocf.c525
-rw-r--r--private/mvdm/wow16/mmsystem/mmiocf.h71
-rw-r--r--private/mvdm/wow16/mmsystem/mmioi.h37
-rw-r--r--private/mvdm/wow16/mmsystem/mmioriff.c365
-rw-r--r--private/mvdm/wow16/mmsystem/mmreg.h619
-rw-r--r--private/mvdm/wow16/mmsystem/mmsex.c483
-rw-r--r--private/mvdm/wow16/mmsystem/mmsex.dlg39
-rw-r--r--private/mvdm/wow16/mmsystem/mmsex.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/mmsystem/mmsysi.h557
-rw-r--r--private/mvdm/wow16/mmsystem/mmsystem.def228
-rw-r--r--private/mvdm/wow16/mmsystem/mmtask/makefile125
-rw-r--r--private/mvdm/wow16/mmsystem/mmtask/mmtask.asm267
-rw-r--r--private/mvdm/wow16/mmsystem/mmtask/mmtask.def12
-rw-r--r--private/mvdm/wow16/mmsystem/mmtask/mmtask.h36
-rw-r--r--private/mvdm/wow16/mmsystem/mmwnd.c187
-rw-r--r--private/mvdm/wow16/mmsystem/msmixmgr.y1000
-rw-r--r--private/mvdm/wow16/mmsystem/playwav.c449
-rw-r--r--private/mvdm/wow16/mmsystem/playwav.h39
-rw-r--r--private/mvdm/wow16/mmsystem/rinc/mmsysver.h23
-rw-r--r--private/mvdm/wow16/mmsystem/sound.c323
-rw-r--r--private/mvdm/wow16/mmsystem/stack.asm1101
-rw-r--r--private/mvdm/wow16/mmsystem/task.c117
-rw-r--r--private/mvdm/wow16/mmsystem/taska.asm225
-rw-r--r--private/mvdm/wow16/mmsystem/thunks.asm818
-rw-r--r--private/mvdm/wow16/mmsystem/thunks.h184
-rw-r--r--private/mvdm/wow16/mmsystem/time.c404
-rw-r--r--private/mvdm/wow16/mmsystem/timea.asm360
-rw-r--r--private/mvdm/wow16/mmsystem/wave.c1862
-rw-r--r--private/mvdm/wow16/ole/client/amabaabo0
-rw-r--r--private/mvdm/wow16/ole/client/amabaace0
-rw-r--r--private/mvdm/wow16/ole/client/bm.c605
-rw-r--r--private/mvdm/wow16/ole/client/cmacs.h61
-rw-r--r--private/mvdm/wow16/ole/client/dde.c1327
-rw-r--r--private/mvdm/wow16/ole/client/defcreat.c215
-rw-r--r--private/mvdm/wow16/ole/client/dib.c495
-rw-r--r--private/mvdm/wow16/ole/client/dll.h958
-rw-r--r--private/mvdm/wow16/ole/client/doc.c316
-rw-r--r--private/mvdm/wow16/ole/client/draw.c1023
-rw-r--r--private/mvdm/wow16/ole/client/error.c281
-rw-r--r--private/mvdm/wow16/ole/client/funchead.c21
-rw-r--r--private/mvdm/wow16/ole/client/generic.c531
-rw-r--r--private/mvdm/wow16/ole/client/le.c2324
-rw-r--r--private/mvdm/wow16/ole/client/ledde.c2594
-rw-r--r--private/mvdm/wow16/ole/client/main.c781
-rw-r--r--private/mvdm/wow16/ole/client/makefile169
-rw-r--r--private/mvdm/wow16/ole/client/mf.c645
-rw-r--r--private/mvdm/wow16/ole/client/mk.cmd55
-rw-r--r--private/mvdm/wow16/ole/client/net.asv371
-rw-r--r--private/mvdm/wow16/ole/client/net.c371
-rw-r--r--private/mvdm/wow16/ole/client/ole.asm139
-rw-r--r--private/mvdm/wow16/ole/client/ole.c1812
-rw-r--r--private/mvdm/wow16/ole/client/ole.h504
-rw-r--r--private/mvdm/wow16/ole/client/olecli.def233
-rw-r--r--private/mvdm/wow16/ole/client/pbhandlr.c511
-rw-r--r--private/mvdm/wow16/ole/client/pict.h190
-rw-r--r--private/mvdm/wow16/ole/client/utils.c669
-rw-r--r--private/mvdm/wow16/ole/server/block.c309
-rw-r--r--private/mvdm/wow16/ole/server/doc.c1091
-rw-r--r--private/mvdm/wow16/ole/server/give2gdi.asm111
-rw-r--r--private/mvdm/wow16/ole/server/item.c1771
-rw-r--r--private/mvdm/wow16/ole/server/makefile95
-rw-r--r--private/mvdm/wow16/ole/server/olesvr.asm61
-rw-r--r--private/mvdm/wow16/ole/server/olesvr.def48
-rw-r--r--private/mvdm/wow16/ole/server/olesvr.rcv58
-rw-r--r--private/mvdm/wow16/ole/server/olever.h38
-rw-r--r--private/mvdm/wow16/ole/server/srvr.c1136
-rw-r--r--private/mvdm/wow16/ole/server/srvr.h294
-rw-r--r--private/mvdm/wow16/ole/server/srvr.rc4
-rw-r--r--private/mvdm/wow16/ole/server/srvrmain.c319
-rw-r--r--private/mvdm/wow16/ole/server/utils.c573
-rw-r--r--private/mvdm/wow16/rasapi16/bseerr.h617
-rw-r--r--private/mvdm/wow16/rasapi16/makefile89
-rw-r--r--private/mvdm/wow16/rasapi16/ras.h183
-rw-r--r--private/mvdm/wow16/rasapi16/rasapi16.c665
-rw-r--r--private/mvdm/wow16/rasapi16/rasapi16.def22
-rw-r--r--private/mvdm/wow16/rasapi16/rasapi16.rc9
-rw-r--r--private/mvdm/wow16/rasapi16/raserror.h153
-rw-r--r--private/mvdm/wow16/regedit/common.h162
-rw-r--r--private/mvdm/wow16/regedit/cutils1.c389
-rw-r--r--private/mvdm/wow16/regedit/dbase.c276
-rw-r--r--private/mvdm/wow16/regedit/filename.c162
-rw-r--r--private/mvdm/wow16/regedit/makefile211
-rw-r--r--private/mvdm/wow16/regedit/merge.c241
-rw-r--r--private/mvdm/wow16/regedit/messages/usa/regedit.rc199
-rw-r--r--private/mvdm/wow16/regedit/messages/usa/regedit.rcv17
-rw-r--r--private/mvdm/wow16/regedit/messages/usa/regload.rcv17
-rw-r--r--private/mvdm/wow16/regedit/messages/usa/sdkreged.dlg104
-rw-r--r--private/mvdm/wow16/regedit/reg1632.h151
-rw-r--r--private/mvdm/wow16/regedit/regdef.h178
-rw-r--r--private/mvdm/wow16/regedit/regedit.c523
-rw-r--r--private/mvdm/wow16/regedit/regedit.def21
-rw-r--r--private/mvdm/wow16/regedit/regedit.h75
-rw-r--r--private/mvdm/wow16/regedit/regedit.icobin0 -> 1086 bytes
-rw-r--r--private/mvdm/wow16/regedit/regload.def14
-rw-r--r--private/mvdm/wow16/regedit/regmain.c518
-rw-r--r--private/mvdm/wow16/regedit/regporte.c2213
-rw-r--r--private/mvdm/wow16/regedit/regporte.h86
-rw-r--r--private/mvdm/wow16/regedit/regresid.h346
-rw-r--r--private/mvdm/wow16/regedit/regthunk.c44
-rw-r--r--private/mvdm/wow16/regedit/sdbase.c377
-rw-r--r--private/mvdm/wow16/regedit/sdkreged.c672
-rw-r--r--private/mvdm/wow16/regedit/sdkreged.def19
-rw-r--r--private/mvdm/wow16/regedit/sdkreged.h74
-rw-r--r--private/mvdm/wow16/regedit/sdkreged.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/regedit/utils1.c93
-rw-r--r--private/mvdm/wow16/regedit/virt.c519
-rw-r--r--private/mvdm/wow16/shell/dragdrop.c48
-rw-r--r--private/mvdm/wow16/shell/library/shell.def40
-rw-r--r--private/mvdm/wow16/shell/makefile104
-rw-r--r--private/mvdm/wow16/shell/shell.asm124
-rw-r--r--private/mvdm/wow16/shell/shell.def37
-rw-r--r--private/mvdm/wow16/shell/shell.rc4
-rw-r--r--private/mvdm/wow16/shell/shell.rcv13
-rw-r--r--private/mvdm/wow16/sherlock/disasm.c1228
-rw-r--r--private/mvdm/wow16/sherlock/disasm.h51
-rw-r--r--private/mvdm/wow16/sherlock/doctor.icobin0 -> 1086 bytes
-rw-r--r--private/mvdm/wow16/sherlock/drwatson.c1573
-rw-r--r--private/mvdm/wow16/sherlock/drwatson.def13
-rw-r--r--private/mvdm/wow16/sherlock/drwatson.h55
-rw-r--r--private/mvdm/wow16/sherlock/error.c87
-rw-r--r--private/mvdm/wow16/sherlock/getsym.c113
-rw-r--r--private/mvdm/wow16/sherlock/makefile77
-rw-r--r--private/mvdm/wow16/sherlock/messages/usa/drwatson.rc235
-rw-r--r--private/mvdm/wow16/sherlock/messages/usa/drwatson.rcv16
-rw-r--r--private/mvdm/wow16/sherlock/sherlock.docbin0 -> 17478 bytes
-rw-r--r--private/mvdm/wow16/sherlock/sherlock.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/sherlock/sherlock.lnk5
-rw-r--r--private/mvdm/wow16/sherlock/sherlock.txt111
-rw-r--r--private/mvdm/wow16/sherlock/str.h147
-rw-r--r--private/mvdm/wow16/sherlock/watson.asm325
-rw-r--r--private/mvdm/wow16/sherlock/watson.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/system/envect.asm257
-rw-r--r--private/mvdm/wow16/system/equate.inc608
-rw-r--r--private/mvdm/wow16/system/hpsystem24
-rw-r--r--private/mvdm/wow16/system/hpsystem.def28
-rw-r--r--private/mvdm/wow16/system/hpsystem.lnk5
-rw-r--r--private/mvdm/wow16/system/makefile116
-rw-r--r--private/mvdm/wow16/system/romstuff.inc39
-rw-r--r--private/mvdm/wow16/system/romsys21
-rw-r--r--private/mvdm/wow16/system/romsys.def28
-rw-r--r--private/mvdm/wow16/system/system21
-rw-r--r--private/mvdm/wow16/system/system.asm710
-rw-r--r--private/mvdm/wow16/system/system.def32
-rw-r--r--private/mvdm/wow16/system/system.inc45
-rw-r--r--private/mvdm/wow16/system/system.lnk5
-rw-r--r--private/mvdm/wow16/system/system.rc5
-rw-r--r--private/mvdm/wow16/system/system.rcv13
-rw-r--r--private/mvdm/wow16/system/timer.asm519
-rw-r--r--private/mvdm/wow16/system/vecsys.inc45
-rw-r--r--private/mvdm/wow16/system/windefs.inc104
-rw-r--r--private/mvdm/wow16/test/hello/hello.c169
-rw-r--r--private/mvdm/wow16/test/hello/hello.h20
-rw-r--r--private/mvdm/wow16/test/hello/hello.rc12
-rw-r--r--private/mvdm/wow16/test/hello/makefile99
-rw-r--r--private/mvdm/wow16/test/makefile18
-rw-r--r--private/mvdm/wow16/test/shell/makefile124
-rw-r--r--private/mvdm/wow16/test/shell/pmdos.asm544
-rw-r--r--private/mvdm/wow16/test/shell/wowexec.c1360
-rw-r--r--private/mvdm/wow16/test/shell/wowexec.h99
-rw-r--r--private/mvdm/wow16/test/shell/wowexec.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/test/shell/wowexec.rc79
-rw-r--r--private/mvdm/wow16/test/shell/wowexec.rcv22
-rw-r--r--private/mvdm/wow16/test/shell/wowexfax.c321
-rw-r--r--private/mvdm/wow16/timer/api.asm288
-rw-r--r--private/mvdm/wow16/timer/libinit.asm374
-rw-r--r--private/mvdm/wow16/timer/local.asm701
-rw-r--r--private/mvdm/wow16/timer/makefile138
-rw-r--r--private/mvdm/wow16/timer/math.asm349
-rw-r--r--private/mvdm/wow16/timer/messages/usa/timer.rc8
-rw-r--r--private/mvdm/wow16/timer/messages/usa/timer.rcv12
-rw-r--r--private/mvdm/wow16/timer/njumps.mac36
-rw-r--r--private/mvdm/wow16/timer/startend.asm285
-rw-r--r--private/mvdm/wow16/timer/sysinfo.inc53
-rw-r--r--private/mvdm/wow16/timer/timer.asm842
-rw-r--r--private/mvdm/wow16/timer/timer.def34
-rw-r--r--private/mvdm/wow16/timer/timer.inc267
-rw-r--r--private/mvdm/wow16/toolhelp/class1.c88
-rw-r--r--private/mvdm/wow16/toolhelp/class2.asm92
-rw-r--r--private/mvdm/wow16/toolhelp/dllentry.asm117
-rw-r--r--private/mvdm/wow16/toolhelp/global.c246
-rw-r--r--private/mvdm/wow16/toolhelp/helper.asm555
-rw-r--r--private/mvdm/wow16/toolhelp/int1.c153
-rw-r--r--private/mvdm/wow16/toolhelp/int2.asm1088
-rw-r--r--private/mvdm/wow16/toolhelp/krnlpeek.asm110
-rw-r--r--private/mvdm/wow16/toolhelp/local.c138
-rw-r--r--private/mvdm/wow16/toolhelp/makefile168
-rw-r--r--private/mvdm/wow16/toolhelp/memman.asm88
-rw-r--r--private/mvdm/wow16/toolhelp/memory.asm608
-rw-r--r--private/mvdm/wow16/toolhelp/module.c156
-rw-r--r--private/mvdm/wow16/toolhelp/notify1.c165
-rw-r--r--private/mvdm/wow16/toolhelp/notify2.asm643
-rw-r--r--private/mvdm/wow16/toolhelp/signal.c110
-rw-r--r--private/mvdm/wow16/toolhelp/stack1.c155
-rw-r--r--private/mvdm/wow16/toolhelp/stack2.asm178
-rw-r--r--private/mvdm/wow16/toolhelp/string.h121
-rw-r--r--private/mvdm/wow16/toolhelp/task1.c73
-rw-r--r--private/mvdm/wow16/toolhelp/task2.asm326
-rw-r--r--private/mvdm/wow16/toolhelp/terminat.asm145
-rw-r--r--private/mvdm/wow16/toolhelp/ththunks.asm50
-rw-r--r--private/mvdm/wow16/toolhelp/timer.asm180
-rw-r--r--private/mvdm/wow16/toolhelp/toolhelp.c147
-rw-r--r--private/mvdm/wow16/toolhelp/toolhelp.def45
-rw-r--r--private/mvdm/wow16/toolhelp/toolhelp.h469
-rw-r--r--private/mvdm/wow16/toolhelp/toolhelp.inc292
-rw-r--r--private/mvdm/wow16/toolhelp/toolhelp.rcv14
-rw-r--r--private/mvdm/wow16/toolhelp/toolpriv.h220
-rw-r--r--private/mvdm/wow16/toolhelp/toolpriv.inc112
-rw-r--r--private/mvdm/wow16/toolhelp/usergdi1.c77
-rw-r--r--private/mvdm/wow16/toolhelp/usergdi2.asm209
-rw-r--r--private/mvdm/wow16/toolhelp/walk286.asm562
-rw-r--r--private/mvdm/wow16/toolhelp/walk386.asm541
-rw-r--r--private/mvdm/wow16/user/combcom.h101
-rw-r--r--private/mvdm/wow16/user/comdev.c1134
-rw-r--r--private/mvdm/wow16/user/comdev.h240
-rw-r--r--private/mvdm/wow16/user/comdevi.h18
-rw-r--r--private/mvdm/wow16/user/debug.c247
-rw-r--r--private/mvdm/wow16/user/drvr.c266
-rw-r--r--private/mvdm/wow16/user/drvrrare.c559
-rw-r--r--private/mvdm/wow16/user/edecrare.c400
-rw-r--r--private/mvdm/wow16/user/edit.h321
-rw-r--r--private/mvdm/wow16/user/editec.c1641
-rw-r--r--private/mvdm/wow16/user/editml.c3043
-rw-r--r--private/mvdm/wow16/user/editsl.c1785
-rw-r--r--private/mvdm/wow16/user/edmlonce.c179
-rw-r--r--private/mvdm/wow16/user/edmlrare.c422
-rw-r--r--private/mvdm/wow16/user/edslrare.c288
-rw-r--r--private/mvdm/wow16/user/fastres.c427
-rw-r--r--private/mvdm/wow16/user/helpcall.c301
-rw-r--r--private/mvdm/wow16/user/init.c200
-rw-r--r--private/mvdm/wow16/user/intds.asm188
-rw-r--r--private/mvdm/wow16/user/inuserds.c43
-rw-r--r--private/mvdm/wow16/user/iuser.h219
-rw-r--r--private/mvdm/wow16/user/iuser.inc216
-rw-r--r--private/mvdm/wow16/user/ks386p.inc29
-rw-r--r--private/mvdm/wow16/user/layer.asm58
-rw-r--r--private/mvdm/wow16/user/listing.inc34
-rw-r--r--private/mvdm/wow16/user/makefile272
-rw-r--r--private/mvdm/wow16/user/messages.api1079
-rw-r--r--private/mvdm/wow16/user/msglayer.asm21
-rw-r--r--private/mvdm/wow16/user/msglayer.inc1161
-rw-r--r--private/mvdm/wow16/user/msutil.c332
-rw-r--r--private/mvdm/wow16/user/net.c535
-rw-r--r--private/mvdm/wow16/user/netdlg.h17
-rw-r--r--private/mvdm/wow16/user/readme.txt11
-rw-r--r--private/mvdm/wow16/user/rmcreate.c316
-rw-r--r--private/mvdm/wow16/user/rmload.c1755
-rw-r--r--private/mvdm/wow16/user/user.api3036
-rw-r--r--private/mvdm/wow16/user/user.asm413
-rw-r--r--private/mvdm/wow16/user/user.def539
-rw-r--r--private/mvdm/wow16/user/user.h2697
-rw-r--r--private/mvdm/wow16/user/user.inc1987
-rw-r--r--private/mvdm/wow16/user/user.rc59
-rw-r--r--private/mvdm/wow16/user/user.rcv16
-rw-r--r--private/mvdm/wow16/user/user1a.asm88
-rw-r--r--private/mvdm/wow16/user/user2.asm137
-rw-r--r--private/mvdm/wow16/user/user2a.asm124
-rw-r--r--private/mvdm/wow16/user/user3.asm108
-rw-r--r--private/mvdm/wow16/user/user3a.asm228
-rw-r--r--private/mvdm/wow16/user/user4.asm139
-rw-r--r--private/mvdm/wow16/user/usercli.asm562
-rw-r--r--private/mvdm/wow16/user/usermenu.inc93
-rw-r--r--private/mvdm/wow16/user/wclass.asm396
-rw-r--r--private/mvdm/wow16/user/winhook.asm134
-rw-r--r--private/mvdm/wow16/user/winlang.asm722
-rw-r--r--private/mvdm/wow16/user/winmisc2.asm790
-rw-r--r--private/mvdm/wow16/user/winnet.asm501
-rw-r--r--private/mvdm/wow16/user/winq.asm1154
-rw-r--r--private/mvdm/wow16/user/winrect.asm842
-rw-r--r--private/mvdm/wow16/user/winstack.asm634
-rw-r--r--private/mvdm/wow16/user/winstr.asm349
-rw-r--r--private/mvdm/wow16/user/winutil.asm618
-rw-r--r--private/mvdm/wow16/user/wmsyserr.c1263
-rw-r--r--private/mvdm/wow16/user/wowasm.cmd11
-rw-r--r--private/mvdm/wow16/user/wowasm.sed13
-rw-r--r--private/mvdm/wow16/user/wowasmc.cmd16
-rw-r--r--private/mvdm/wow16/user/wowasmk.cmd16
-rw-r--r--private/mvdm/wow16/user/wowcomm.c60
-rw-r--r--private/mvdm/wow16/user/wsphelp.asm140
-rw-r--r--private/mvdm/wow16/user/wsprintf.c339
-rw-r--r--private/mvdm/wow16/user/wsubcls.c105
-rw-r--r--private/mvdm/wow16/wfwnet/bseerr.h617
-rw-r--r--private/mvdm/wow16/wfwnet/ints.asm145
-rw-r--r--private/mvdm/wow16/wfwnet/lfn.c162
-rw-r--r--private/mvdm/wow16/wfwnet/libentry.asm83
-rw-r--r--private/mvdm/wow16/wfwnet/locals.h153
-rw-r--r--private/mvdm/wow16/wfwnet/makefile140
-rw-r--r--private/mvdm/wow16/wfwnet/misc.c265
-rw-r--r--private/mvdm/wow16/wfwnet/print.c132
-rw-r--r--private/mvdm/wow16/wfwnet/to32.c1268
-rw-r--r--private/mvdm/wow16/wfwnet/wfwnet.c844
-rw-r--r--private/mvdm/wow16/wfwnet/wfwnet.def102
-rw-r--r--private/mvdm/wow16/wfwnet/wfwnet.rc4
-rw-r--r--private/mvdm/wow16/wfwnet/wfwnet.rcv12
-rw-r--r--private/mvdm/wow16/win87em/87emstar.asm21
-rw-r--r--private/mvdm/wow16/win87em/apisim.asm118
-rw-r--r--private/mvdm/wow16/win87em/em386.asm567
-rw-r--r--private/mvdm/wow16/win87em/emarith.asm285
-rw-r--r--private/mvdm/wow16/win87em/emconst.asm165
-rw-r--r--private/mvdm/wow16/win87em/emdecode.asm256
-rw-r--r--private/mvdm/wow16/win87em/emdisp.asm356
-rw-r--r--private/mvdm/wow16/win87em/emdoc.asm83
-rw-r--r--private/mvdm/wow16/win87em/emdos.asm979
-rw-r--r--private/mvdm/wow16/win87em/emds.asm54
-rw-r--r--private/mvdm/wow16/win87em/emerror.asm399
-rw-r--r--private/mvdm/wow16/win87em/emexcept.asm1411
-rw-r--r--private/mvdm/wow16/win87em/emfadd.asm251
-rw-r--r--private/mvdm/wow16/win87em/emfcom.asm198
-rw-r--r--private/mvdm/wow16/win87em/emfconst.asm78
-rw-r--r--private/mvdm/wow16/win87em/emfdiv.asm252
-rw-r--r--private/mvdm/wow16/win87em/emfixfly.asm336
-rw-r--r--private/mvdm/wow16/win87em/emfmisc.asm101
-rw-r--r--private/mvdm/wow16/win87em/emfmul.asm195
-rw-r--r--private/mvdm/wow16/win87em/emfprem.asm386
-rw-r--r--private/mvdm/wow16/win87em/emfrndi.asm224
-rw-r--r--private/mvdm/wow16/win87em/emfsqrt.asm178
-rw-r--r--private/mvdm/wow16/win87em/emftran.asm469
-rw-r--r--private/mvdm/wow16/win87em/emintern.asm275
-rw-r--r--private/mvdm/wow16/win87em/emlsdbl.asm442
-rw-r--r--private/mvdm/wow16/win87em/emlsint.asm284
-rw-r--r--private/mvdm/wow16/win87em/emlsquad.asm174
-rw-r--r--private/mvdm/wow16/win87em/emlssng.asm333
-rw-r--r--private/mvdm/wow16/win87em/emlstmp.asm183
-rw-r--r--private/mvdm/wow16/win87em/emmain.asm805
-rw-r--r--private/mvdm/wow16/win87em/emnew.asm165
-rw-r--r--private/mvdm/wow16/win87em/emnormal.asm374
-rw-r--r--private/mvdm/wow16/win87em/emoem.asm536
-rw-r--r--private/mvdm/wow16/win87em/emoem.src448
-rw-r--r--private/mvdm/wow16/win87em/emoemqb.asm570
-rw-r--r--private/mvdm/wow16/win87em/emoemqp.asm536
-rw-r--r--private/mvdm/wow16/win87em/emoemwin.asm693
-rw-r--r--private/mvdm/wow16/win87em/emoemwin.std692
-rw-r--r--private/mvdm/wow16/win87em/emoemwin.t1692
-rw-r--r--private/mvdm/wow16/win87em/emoemwin.t2693
-rw-r--r--private/mvdm/wow16/win87em/emspec.asm192
-rw-r--r--private/mvdm/wow16/win87em/emstack.asm108
-rw-r--r--private/mvdm/wow16/win87em/emthread.asm176
-rw-r--r--private/mvdm/wow16/win87em/emu8087.asm14
-rw-r--r--private/mvdm/wow16/win87em/emulator.asm715
-rw-r--r--private/mvdm/wow16/win87em/emulator.hst385
-rw-r--r--private/mvdm/wow16/win87em/emulator.inc315
-rw-r--r--private/mvdm/wow16/win87em/emwin.asm745
-rw-r--r--private/mvdm/wow16/win87em/emxenix.asm61
-rw-r--r--private/mvdm/wow16/win87em/key22
-rw-r--r--private/mvdm/wow16/win87em/makefile720
-rw-r--r--private/mvdm/wow16/win87em/switch.an5
-rw-r--r--private/mvdm/wow16/win87em/switch.n5
-rw-r--r--private/mvdm/wow16/win87em/switch.src5
-rw-r--r--private/mvdm/wow16/win87em/wfpinit.asm121
-rw-r--r--private/mvdm/wow16/win87em/wfpsig.asm57
-rw-r--r--private/mvdm/wow16/win87em/win87em.def19
-rw-r--r--private/mvdm/wow16/win87em/win87em.h40
-rw-r--r--private/mvdm/wow16/win87em/win87em2.def22
-rw-r--r--private/mvdm/wow16/win87em/win87em3.def26
-rw-r--r--private/mvdm/wow16/win87em/win87hdr.txt65
-rw-r--r--private/mvdm/wow16/win87em/win87std.def26
-rw-r--r--private/mvdm/wow16/winoldap/makefile111
-rw-r--r--private/mvdm/wow16/winoldap/winoldap.c47
-rw-r--r--private/mvdm/wow16/winoldap/winoldap.rc4
-rw-r--r--private/mvdm/wow16/winoldap/winoldap.rcv9
-rw-r--r--private/mvdm/wow16/winsock/makefile107
-rw-r--r--private/mvdm/wow16/winsock/winsock.asm115
-rw-r--r--private/mvdm/wow16/winsock/winsock.def81
-rw-r--r--private/mvdm/wow16/winsock/winsock.rc4
-rw-r--r--private/mvdm/wow16/winsock/winsock.rcv12
-rw-r--r--private/mvdm/wow16/winspool/makefile108
-rw-r--r--private/mvdm/wow16/winspool/winspool.asm80
-rw-r--r--private/mvdm/wow16/winspool/winspool.def13
-rw-r--r--private/mvdm/wow16/winspool/winspool.rc4
-rw-r--r--private/mvdm/wow16/winspool/winspool.rcv13
-rw-r--r--private/mvdm/wow16/wowdeb/makefile120
-rw-r--r--private/mvdm/wow16/wowdeb/wowdeb.c202
-rw-r--r--private/mvdm/wow16/wowdeb/wowdeb.rc4
-rw-r--r--private/mvdm/wow16/wowdeb/wowdeb.rcv21
-rw-r--r--private/mvdm/wow16/write/8514btns.bmpbin0 -> 1422 bytes
-rw-r--r--private/mvdm/wow16/write/8514mrks.bmpbin0 -> 266 bytes
-rw-r--r--private/mvdm/wow16/write/aaa.c11
-rw-r--r--private/mvdm/wow16/write/addprm.c432
-rw-r--r--private/mvdm/wow16/write/bitmaps.h21
-rw-r--r--private/mvdm/wow16/write/cache.c708
-rw-r--r--private/mvdm/wow16/write/center.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/cgabtns.bmpbin0 -> 634 bytes
-rw-r--r--private/mvdm/wow16/write/cgamarks.bmpbin0 -> 118 bytes
-rw-r--r--private/mvdm/wow16/write/ch.h216
-rw-r--r--private/mvdm/wow16/write/chlook.c382
-rw-r--r--private/mvdm/wow16/write/chngwin.c336
-rw-r--r--private/mvdm/wow16/write/clipbord.c887
-rw-r--r--private/mvdm/wow16/write/clipbrd2.c926
-rw-r--r--private/mvdm/wow16/write/clipdisp.c281
-rw-r--r--private/mvdm/wow16/write/cmacros2.inc1236
-rw-r--r--private/mvdm/wow16/write/cmacros3.inc1236
-rw-r--r--private/mvdm/wow16/write/cmd.c718
-rw-r--r--private/mvdm/wow16/write/cmddefs.h148
-rw-r--r--private/mvdm/wow16/write/code.h9
-rw-r--r--private/mvdm/wow16/write/commdlg.c420
-rw-r--r--private/mvdm/wow16/write/createww.c964
-rw-r--r--private/mvdm/wow16/write/curskeys.c526
-rw-r--r--private/mvdm/wow16/write/d_disp.c1816
-rw-r--r--private/mvdm/wow16/write/d_form1.c2452
-rw-r--r--private/mvdm/wow16/write/d_selec2.c684
-rw-r--r--private/mvdm/wow16/write/dbcs.h13
-rw-r--r--private/mvdm/wow16/write/debug.c376
-rw-r--r--private/mvdm/wow16/write/debug.h15
-rw-r--r--private/mvdm/wow16/write/diaalert.c830
-rw-r--r--private/mvdm/wow16/write/diachgpr.c517
-rw-r--r--private/mvdm/wow16/write/diadiv.c628
-rw-r--r--private/mvdm/wow16/write/diapara.c458
-rw-r--r--private/mvdm/wow16/write/diaprint.c427
-rw-r--r--private/mvdm/wow16/write/diarepag.c584
-rw-r--r--private/mvdm/wow16/write/diasubs.c606
-rw-r--r--private/mvdm/wow16/write/disp.c1536
-rw-r--r--private/mvdm/wow16/write/dispdefs.h76
-rw-r--r--private/mvdm/wow16/write/dlgdefs.h182
-rw-r--r--private/mvdm/wow16/write/doc.c409
-rw-r--r--private/mvdm/wow16/write/docdefs.h86
-rw-r--r--private/mvdm/wow16/write/doprm.c417
-rw-r--r--private/mvdm/wow16/write/doslib.asm555
-rw-r--r--private/mvdm/wow16/write/doslib.h94
-rw-r--r--private/mvdm/wow16/write/double.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/dtabbtn.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/dtabmark.bmsbin0 -> 112 bytes
-rw-r--r--private/mvdm/wow16/write/edit.c1278
-rw-r--r--private/mvdm/wow16/write/editdefs.h52
-rw-r--r--private/mvdm/wow16/write/editftn.c241
-rw-r--r--private/mvdm/wow16/write/editpgtb.c87
-rw-r--r--private/mvdm/wow16/write/editsect.c182
-rw-r--r--private/mvdm/wow16/write/edm.edm597
-rw-r--r--private/mvdm/wow16/write/egabtns.bmpbin0 -> 738 bytes
-rw-r--r--private/mvdm/wow16/write/egamarks.bmpbin0 -> 134 bytes
-rw-r--r--private/mvdm/wow16/write/fetch.c490
-rw-r--r--private/mvdm/wow16/write/ffdefs.h30
-rw-r--r--private/mvdm/wow16/write/file.c1486
-rw-r--r--private/mvdm/wow16/write/filedefs.h124
-rw-r--r--private/mvdm/wow16/write/fileres.c321
-rw-r--r--private/mvdm/wow16/write/filespec.wribin0 -> 17792 bytes
-rw-r--r--private/mvdm/wow16/write/fileutil.c485
-rw-r--r--private/mvdm/wow16/write/fkpdefs.h122
-rw-r--r--private/mvdm/wow16/write/fmtdefs.h85
-rw-r--r--private/mvdm/wow16/write/fontdefs.h367
-rw-r--r--private/mvdm/wow16/write/fontdlg.c206
-rw-r--r--private/mvdm/wow16/write/fontenum.c547
-rw-r--r--private/mvdm/wow16/write/fontutil.c262
-rw-r--r--private/mvdm/wow16/write/form1.c1691
-rw-r--r--private/mvdm/wow16/write/format.asm2995
-rw-r--r--private/mvdm/wow16/write/format2.c312
-rw-r--r--private/mvdm/wow16/write/globdefs.h126
-rw-r--r--private/mvdm/wow16/write/globdefs.itl186
-rw-r--r--private/mvdm/wow16/write/globdefs.knj187
-rw-r--r--private/mvdm/wow16/write/heapdata.h65
-rw-r--r--private/mvdm/wow16/write/heapdefs.h108
-rw-r--r--private/mvdm/wow16/write/heapinit.c192
-rw-r--r--private/mvdm/wow16/write/heapmain.c153
-rw-r--r--private/mvdm/wow16/write/heaprare.c266
-rw-r--r--private/mvdm/wow16/write/help.c885
-rw-r--r--private/mvdm/wow16/write/indent.bmsbin0 -> 112 bytes
-rw-r--r--private/mvdm/wow16/write/initmmw.c968
-rw-r--r--private/mvdm/wow16/write/initwin.c887
-rw-r--r--private/mvdm/wow16/write/insert.c1729
-rw-r--r--private/mvdm/wow16/write/insert.tmp18
-rw-r--r--private/mvdm/wow16/write/insert2.c653
-rw-r--r--private/mvdm/wow16/write/insertco.c335
-rw-r--r--private/mvdm/wow16/write/jumppage.c192
-rw-r--r--private/mvdm/wow16/write/just.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/kanji.h286
-rw-r--r--private/mvdm/wow16/write/kmake.bat56
-rw-r--r--private/mvdm/wow16/write/kmakend.bat42
-rw-r--r--private/mvdm/wow16/write/left.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/lib.asm474
-rw-r--r--private/mvdm/wow16/write/lmargin.bmsbin0 -> 112 bytes
-rw-r--r--private/mvdm/wow16/write/loadfnt2.c155
-rw-r--r--private/mvdm/wow16/write/loadfont.c1063
-rw-r--r--private/mvdm/wow16/write/looks.h39
-rw-r--r--private/mvdm/wow16/write/ltabbtn.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/ltabmark.bmsbin0 -> 112 bytes
-rw-r--r--private/mvdm/wow16/write/machdefs.h115
-rw-r--r--private/mvdm/wow16/write/macro.h23
-rw-r--r--private/mvdm/wow16/write/mainloop.c711
-rw-r--r--private/mvdm/wow16/write/makefile405
-rw-r--r--private/mvdm/wow16/write/mdoc.c1001
-rw-r--r--private/mvdm/wow16/write/menu.c1292
-rw-r--r--private/mvdm/wow16/write/menudefs.h162
-rw-r--r--private/mvdm/wow16/write/mergedef.h16
-rw-r--r--private/mvdm/wow16/write/messages/usa/ole.dlg98
-rw-r--r--private/mvdm/wow16/write/messages/usa/write.dlg347
-rw-r--r--private/mvdm/wow16/write/messages/usa/write.rc452
-rw-r--r--private/mvdm/wow16/write/messages/usa/write.rcv17
-rw-r--r--private/mvdm/wow16/write/mglobals.c817
-rw-r--r--private/mvdm/wow16/write/mlink.sed5
-rw-r--r--private/mvdm/wow16/write/mmw.c661
-rw-r--r--private/mvdm/wow16/write/mouse.c436
-rw-r--r--private/mvdm/wow16/write/mouse.h131
-rw-r--r--private/mvdm/wow16/write/msseqds.asm201
-rw-r--r--private/mvdm/wow16/write/mw.h212
-rw-r--r--private/mvdm/wow16/write/mwhires.curbin0 -> 326 bytes
-rw-r--r--private/mvdm/wow16/write/mwlores.curbin0 -> 326 bytes
-rw-r--r--private/mvdm/wow16/write/obj.c2388
-rw-r--r--private/mvdm/wow16/write/obj.h414
-rw-r--r--private/mvdm/wow16/write/obj2.c1851
-rw-r--r--private/mvdm/wow16/write/obj3.c1972
-rw-r--r--private/mvdm/wow16/write/objmini.asm64
-rw-r--r--private/mvdm/wow16/write/objpsp.c354
-rw-r--r--private/mvdm/wow16/write/objreg.c447
-rw-r--r--private/mvdm/wow16/write/objreg.h26
-rw-r--r--private/mvdm/wow16/write/open.c606
-rw-r--r--private/mvdm/wow16/write/pageinfo.c156
-rw-r--r--private/mvdm/wow16/write/pictdrag.c1137
-rw-r--r--private/mvdm/wow16/write/picture.c798
-rw-r--r--private/mvdm/wow16/write/picture2.c549
-rw-r--r--private/mvdm/wow16/write/pmscur.curbin0 -> 326 bytes
-rw-r--r--private/mvdm/wow16/write/preload.h23
-rw-r--r--private/mvdm/wow16/write/print.c998
-rw-r--r--private/mvdm/wow16/write/print2.c352
-rw-r--r--private/mvdm/wow16/write/print3.c293
-rw-r--r--private/mvdm/wow16/write/printdef.h59
-rw-r--r--private/mvdm/wow16/write/printdlg.c588
-rw-r--r--private/mvdm/wow16/write/prmdefs.h102
-rw-r--r--private/mvdm/wow16/write/propdefs.h234
-rw-r--r--private/mvdm/wow16/write/quit.c354
-rw-r--r--private/mvdm/wow16/write/rare.c325
-rw-r--r--private/mvdm/wow16/write/readme.txt148
-rw-r--r--private/mvdm/wow16/write/right.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/rmargin.bmsbin0 -> 112 bytes
-rw-r--r--private/mvdm/wow16/write/ruler.c1677
-rw-r--r--private/mvdm/wow16/write/ruler2.c88
-rw-r--r--private/mvdm/wow16/write/ruler3.c113
-rw-r--r--private/mvdm/wow16/write/rulerdef.h52
-rw-r--r--private/mvdm/wow16/write/running.c692
-rw-r--r--private/mvdm/wow16/write/screen.c195
-rw-r--r--private/mvdm/wow16/write/scrnchng.c853
-rw-r--r--private/mvdm/wow16/write/scrndefs.h39
-rw-r--r--private/mvdm/wow16/write/scrollhz.c385
-rw-r--r--private/mvdm/wow16/write/scrollvt.c531
-rw-r--r--private/mvdm/wow16/write/search.c2015
-rw-r--r--private/mvdm/wow16/write/select.c800
-rw-r--r--private/mvdm/wow16/write/select2.c295
-rw-r--r--private/mvdm/wow16/write/selectsp.c278
-rw-r--r--private/mvdm/wow16/write/single.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/sp15.bmsbin0 -> 376 bytes
-rw-r--r--private/mvdm/wow16/write/state.rst12
-rw-r--r--private/mvdm/wow16/write/stcdefs.h59
-rw-r--r--private/mvdm/wow16/write/str.h232
-rw-r--r--private/mvdm/wow16/write/tags842
-rw-r--r--private/mvdm/wow16/write/toolbox.h35
-rw-r--r--private/mvdm/wow16/write/trans2.c1949
-rw-r--r--private/mvdm/wow16/write/trans3.c1846
-rw-r--r--private/mvdm/wow16/write/trans4.c441
-rw-r--r--private/mvdm/wow16/write/transbuf.c450
-rw-r--r--private/mvdm/wow16/write/transfer.c222
-rw-r--r--private/mvdm/wow16/write/txb.h28
-rw-r--r--private/mvdm/wow16/write/undo.c873
-rw-r--r--private/mvdm/wow16/write/util.c556
-rw-r--r--private/mvdm/wow16/write/util2.c418
-rw-r--r--private/mvdm/wow16/write/vgabtns.bmpbin0 -> 842 bytes
-rw-r--r--private/mvdm/wow16/write/vgamarks.bmpbin0 -> 150 bytes
-rw-r--r--private/mvdm/wow16/write/winddefs.h78
-rw-r--r--private/mvdm/wow16/write/write.def79
-rw-r--r--private/mvdm/wow16/write/write.icobin0 -> 1086 bytes
-rw-r--r--private/mvdm/wow16/write/write.itl641
-rw-r--r--private/mvdm/wow16/write/write.knj678
-rw-r--r--private/mvdm/wow16/write/write.sed11
-rw-r--r--private/mvdm/wow16/write/wwactde.c372
-rw-r--r--private/mvdm/wow16/write/wwdefs.h107
1017 files changed, 417876 insertions, 0 deletions
diff --git a/private/mvdm/wow16/bin/rcpp.err b/private/mvdm/wow16/bin/rcpp.err
new file mode 100644
index 000000000..d26c8494d
--- /dev/null
+++ b/private/mvdm/wow16/bin/rcpp.err
@@ -0,0 +1,334 @@
+/* SCCSWHAT( "@(#)c1.err 2.29 88/02/25 18:18:00 " ) */
+ /* fatals */
+
+1001 "Internal Compiler Error\n\t\t(compiler file '%s', line %d)\n\t\tContact Microsoft Technical Support"
+1002 "out of heap space"
+1003 "error count exceeds %d; stopping compilation"
+1004 "unexpected EOF"
+1005 "string too big for buffer"
+1006 "write error on compiler intermediate file"
+1007 "unrecognized flag '%s' in '%s'"
+1008 "no input file specified"
+1009 "compiler limit : macros too deeply nested"
+1010 "compiler limit : macro expansion too big"
+1012 "bad parenthesis nesting - missing '%c'"
+1013 "cannot open source file '%s'"
+1014 "too many include files"
+1015 "cannot open include file '%s'"
+1016 "#if[n]def expected an identifier"
+1017 "invalid integer constant expression"
+1018 "unexpected '#elif'"
+1019 "unexpected '#else'"
+1020 "unexpected '#endif'"
+1021 "bad preprocessor command '%s'"
+1022 "expected '#endif'"
+1023 "no int size specified"
+1024 "no ptr size specified"
+1025 "no function size specified"
+1026 "parser stack overflow, please simplify your program"
+1027 "DGROUP data allocation exceeds 64K" /* QC, c23 */
+1028 "%s segment allocation exceeds 64K" /* QC */
+1031 "compiler limit : function calls too deeply nested" /* QC, c23 */
+1032 "cannot open object listing file '%s'" /* QC, c23 */
+1035 "expression too complex, please simplify" /* QC, c23 */
+1037 "cannot open object file '%s'" /* QC, c23 */
+1041 "cannot open compiler intermediate file - no more files"
+1042 "cannot open compiler intermediate file - no such file or directory"
+1043 "cannot open compiler intermediate file"
+1044 "out of disk space for compiler intermediate file"
+1045 "floating point overflow"
+1047 "too many %s flags, '%s'"
+1048 "unknown option '%c' in '%s'"
+1049 "invalid numerical argument '%s'"
+1052 "too many #if/#ifdef's"
+1053 "compiler limit : struct/union nesting"
+1054 "compiler limit : initializers too deeply nested"
+1055 "compiler limit : out of keys"
+1056 "compiler limit : out of macro expansion space"
+1057 "unexpected EOF in macro expansion (missing ')'?)"
+1059 "out of near heap space"
+1060 "out of far heap space"
+1061 "compiler limit : blocks too deeply nested" /* QC */
+1062 "error writing to preprocessor output file"
+1063 "compiler limit : compiler stack overflow" /* QC */
+1064 "compiler limit : identifier overflowed internal buffer"
+1065 "compiler limit : declarator too complex"
+1000 "UNKNOWN FATAL ERROR\n\t\tContact Microsoft Technical Support"
+
+ /* errors */
+
+2001 "newline in constant"
+2002 "out of macro actual parameter space"
+2003 "expected 'defined id'"
+2004 "expected 'defined(id)'"
+2005 "#line expected a line number, found '%s'"
+2006 "#include expected a file name, found '%s'"
+2007 "#define syntax"
+2008 "'%c' : unexpected in macro definition"
+2009 "reuse of macro formal '%s'"
+2010 "'%c' : unexpected in formal list"
+2011 "'%s' : definition too big"
+2012 "missing name following '<'"
+2013 "missing '>'"
+2014 "preprocessor command must start as first non-whitespace"
+2015 "too many chars in constant"
+2016 "no closing single quote"
+2017 "illegal escape sequence"
+2018 "unknown character '0x%x'"
+2019 "expected preprocessor command, found '%c'"
+2020 "bad octal number '%c'"
+2021 "expected exponent value, not '%c'"
+2022 "'%ld' : too big for char"
+2023 "divide by 0"
+2024 "mod by 0"
+2025 "'%s' : enum/struct/union type redefinition"
+2026 "'%s' : member of enum redefinition"
+2028 "struct/union member needs to be inside a struct/union"
+2029 "'%Fs' : bit-fields only allowed in structs"
+2030 "'%Fs' : struct/union member redefinition"
+2031 "'%Fs' : function cannot be struct/union member"
+2032 "'%Fs' : base type with near/far/huge not allowed"
+2033 "'%Fs' : bit-field cannot have indirection"
+2034 "'%Fs' : bit-field type too small for number of bits"
+2035 "enum/struct/union '%Fs' : unknown size"
+2036 "left of '%s%s' must have a struct/union type"
+2037 "left of '%s' specifies undefined struct/union '%Fs'"
+2038 "'%s' : not struct/union member"
+2039 "'->' requires struct/union pointer"
+2040 "'.' requires struct/union name"
+2042 "signed/unsigned keywords mutually exclusive"
+2043 "illegal break"
+2044 "illegal continue"
+2045 "'%s' : label redefined"
+2046 "illegal case"
+2047 "illegal default"
+2048 "more than one default"
+2050 "non-integral switch expression"
+2051 "case expression not constant"
+2052 "case expression not integral"
+2053 "case value %d already used"
+2054 "expected '(' to follow '%Fs'"
+2055 "expected formal parameter list, not a type list"
+2056 "illegal expression"
+2057 "expected constant expression"
+2058 "constant expression is not integral"
+2059 "syntax error : '%s'"
+2060 "syntax error : EOF"
+2061 "syntax error : identifier '%s'"
+2062 "type '%s' unexpected"
+2063 "'%s' : not a function"
+2064 "term does not evaluate to a function"
+2065 "'%s' : undefined"
+2066 "cast to function returning . . . is illegal"
+2067 "cast to array type is illegal"
+2068 "illegal cast"
+2069 "cast of 'void' term to non-void"
+2070 "illegal sizeof operand"
+2071 "'%Fs' : bad storage class"
+2072 "'%Fs' : initialization of a function"
+2073 "'%Fs' : cannot initialize array in function"
+2074 "'%Fs' : cannot initialize struct/union in function"
+2075 "'%Fs' : array initialization needs curly braces"
+2076 "'%Fs' : struct/union initialization needs curly braces"
+2077 "non-integral field initializer '%Fs'"
+2078 "too many initializers"
+2079 "'%Fs' uses undefined struct/union '%Fs'"
+2082 "redefinition of formal parameter '%Fs'"
+2083 "array '%Fs' already has a size"
+2084 "function '%Fs' already has a body"
+2085 "'%Fs' : not in formal parameter list"
+2086 "'%Fs' : redefinition"
+2087 "'%Fs' : missing subscript"
+2088 "use of undefined enum/struct/union '%s'"
+2089 "typedef specifies a near/far function"
+2090 "function returns array"
+2091 "function returns function"
+2092 "array element type cannot be function"
+2093 "cannot initialize a static or struct with address of automatic vars"
+2094 "label '%Fs' was undefined"
+2095 "'%Fs' : actual has type void : parameter %d"
+2096 "struct/union comparison illegal"
+2097 "illegal initialization"
+2098 "non-address expression"
+2099 "non-constant offset"
+2100 "illegal indirection"
+2101 "'&' on constant"
+2102 "'&' requires lvalue"
+2103 "'&' on register variable"
+2104 "'&' on bit-field ignored"
+2105 "'%s' needs lvalue"
+2106 "'%s' : left operand must be lvalue"
+2107 "illegal index, indirection not allowed"
+2108 "non-integral index"
+2109 "subscript on non-array"
+2110 "'+' : 2 pointers"
+2111 "pointer + non-integral value"
+2112 "illegal pointer subtraction"
+2113 "'-' : right operand pointer"
+2114 "'%s' : pointer on left; needs integral right"
+2115 "'%s' : incompatible types"
+2116 "'%s' : bad %s operand"
+2117 "'%s' : illegal for struct/union"
+2118 "negative subscript"
+2119 "'typedefs' both define indirection"
+2120 "'void' illegal with all types"
+2121 "typedef specifies different enum"
+2122 "typedef specifies different struct"
+2123 "typedef specifies different union"
+2125 "%Fs : allocation exceeds 64K" /* QC, c23 */
+2126 "%Fs : auto allocation exceeds %s" /* QC, c23 */
+2127 "parameter allocation exceeds 32K" /* QC, c23 */
+2130 "#line expected a string containing the file name, found '%s'"
+2131 "attributes specify more than one near/far/huge"
+2132 "syntax error : unexpected identifier"
+2133 "array '%Fs' : unknown size"
+2134 "'%Fs' : struct/union too large"
+2135 "missing ')' in macro expansion"
+2137 "empty character constant"
+2138 "unmatched close comment '*/'"
+2139 "type following '%s' is illegal"
+2140 "argument type cannot be function returning . . ."
+2141 "value out of range for enum constant"
+2142 "ellipsis requires three periods"
+2143 "syntax error : missing '%s' before '%s'"
+2144 "syntax error : missing '%s' before type '%Fs'"
+2145 "syntax error : missing '%s' before identifier"
+2146 "syntax error : missing '%s' before identifier '%s'"
+2147 "unknown size"
+2148 "array too large"
+2149 "'%Fs' : named bit-field cannot have 0 width"
+2150 "'%Fs' : bit-field must have type int, signed int, or unsigned int"
+2151 "more than one cdecl/fortran/pascal attribute specified"
+2152 "'%s' : pointers to functions with different attributes"
+2153 "hex constants must have at least 1 hex digit"
+2154 "'%s' : does not refer to a segment"
+2155 "'%s' : already in a segment"
+2156 "pragma must be at outer level"
+2157 "'%s' : must be declared before use in pragma list"
+2158 "'%s' : is a function"
+2159 "more than one storage class specified"
+2160 "## cannot occur at the beginning of a macro definition"
+2161 "## cannot occur at the end of a macro definition"
+2162 "expected macro formal parameter"
+2163 "'%s' : not available as an intrinsic"
+2164 "'%s' : intrinsic was not declared"
+2165 "'%s' : cannot modify pointers to data"
+2166 "lval specifies 'const' object"
+2167 "'%Fs' : too many actual parameters for intrinsic"
+2168 "'%Fs' : too few actual parameters for intrinsic"
+2169 "'%Fs' : is an intrinsic, it cannot be defined"
+2170 "'%s' : intrinsic not declared as a function"
+2171 "'%s' : bad operand"
+2172 "'%Fs' : actual is not a pointer : parameter %d"
+2173 "'%Fs' : actual is not a pointer : parameter %d, parameter list %d"
+2174 "'%Fs' : actual has type void : parameter %d, parameter list %d"
+2175 "'%Fs' : unresolved external" /* QC */
+2176 "static far data not supported" /* QC */
+2177 "constant too big"
+2178 "'%s' : storage class for same_seg variables must be 'extern'"
+2179 "'%Fs' : was used in same_seg, but storage class is no longer 'extern'"
+2180 "controlling expression has type 'void'"
+2181 "pragma requires command line option '%s'" /* QC */
+2182 "'%Fs' : 'void' on variable"
+2183 "'%Fs' : 'interrupt' function must be 'far'"
+2184 "'%Fs' : '%s' function cannot be 'pascal/fortran'"
+2186 "'%Fs' : 'saveregs/interrupt' modifiers mutually exclusive"
+2187 "cast of near function pointer to far function pointer"
+2188 "#error : %s"
+2190 "'%s' : is a text segment"
+2191 "'%s' : is a data segment"
+2192 "'%s' : function has already been defined"
+2000 "UNKNOWN ERROR\n\t\tContact Microsoft Technical Support"
+
+ /* warnings */
+
+4001 "macro '%s' requires parameters"
+4002 "too many actual parameters for macro '%s'"
+4003 "not enough actual parameters for macro '%s'"
+4004 "missing close parenthesis after 'defined'"
+4005 "'%s' : redefinition"
+4006 "#undef expected an identifier"
+4009 "string too big, trailing chars truncated"
+4011 "identifier truncated to '%s'"
+4012 "float constant in a cross compilation"
+4013 "constant too big"
+4014 "'%Fs' : bit-field type must be unsigned"
+4015 "'%Fs' : bit-field type must be integral"
+4016 "'%s' : no function return type, using 'int' as default"
+4017 "cast of int expression to far pointer"
+4020 "'%Fs' : too many actual parameters"
+4021 "'%Fs' : too few actual parameters"
+4022 "'%Fs' : pointer mismatch : parameter %d"
+4024 "'%Fs' : different types : parameter %d"
+4025 "function declaration specified variable argument list"
+4026 "function was declared with formal argument list"
+4027 "function was declared without formal argument list"
+4028 "parameter %d declaration different"
+4029 "declared parameter list different from definition"
+4030 "first parameter list is longer than the second"
+4031 "second parameter list is longer than the first"
+4032 "unnamed struct/union as parameter"
+4033 "function must return a value"
+4034 "sizeof returns 0"
+4035 "'%Fs' : no return value"
+4036 "unexpected formal parameter list"
+4037 "'%Fs' : formal parameters ignored"
+4038 "'%Fs' : formal parameter has bad storage class"
+4039 "'%Fs' : function used as an argument"
+4040 "near/far/huge on '%Fs' ignored"
+4041 "formal parameter '%s' is redefined"
+4042 "'%Fs' : has bad storage class"
+4044 "huge on '%Fs' ignored, must be an array"
+4045 "'%s' : array bounds overflow"
+4046 "'&' on function/array, ignored"
+4047 "'%s' : different levels of indirection"
+4048 "array's declared subscripts different"
+4049 "'%s' : indirection to different types"
+4051 "data conversion"
+4052 "different enum types"
+4053 "at least one void operand"
+4060 "conversion of long address to short address" /* QC, c23 */
+4061 "long/short mismatch in argument : conversion supplied" /* QC, c23 */
+4062 "near/far mismatch in argument : conversion supplied" /* QC, c23 */
+4067 "unexpected characters following '%s' directive - newline expected"
+4068 "unknown pragma"
+4071 "'%Fs' : no function prototype given"
+4074 "non standard extension used - '%s'"
+4075 "size of switch expression or case constant too large - converted to int"
+4076 "'%s' : may be used on integral types only"
+4077 "unknown check_stack option"
+4079 "unexpected token '%s'"
+4080 "expected 'identifier' for segment name, found '%s'"
+4081 "expected a comma, found '%s'"
+4082 "expected an identifier, found '%s'"
+4083 "expected '(', found '%s'"
+4084 "expected a pragma keyword, found '%s'"
+4085 "expected [on | off]"
+4086 "expected [1 | 2 | 4]"
+4087 "'%Fs' : declared with 'void' parameter list"
+4088 "'%Fs' : pointer mismatch : parameter %d, parameter list %d"
+4089 "'%Fs' : different types : parameter %d, parameter list %d"
+4090 "different 'const' attributes"
+4091 "no symbols were declared"
+4092 "untagged enum/struct/union declared no symbols"
+4093 "unescaped newline in character constant in non-active code"
+4094 "unexpected newline"
+4095 "expected ')', found '%s'"
+4096 "huge treated as far" /* QC */
+4098 "void function returning a value"
+4099 "expected ')', (too many arguments?)"
+4100 "'%Fs' : unreferenced formal parameter"
+4101 "'%Fs' : unreferenced local variable"
+4102 "'%Fs' : unreferenced label"
+4103 "'%Fs' : function definition used as prototype"
+4104 "'%s' : near data in same_seg pragma, ignored"
+4105 "'%Fs' : code modifiers only on function or pointer to function"
+4106 "pragma requires integer between 1 and 127"
+4107 "pragma requires integer between 15 and 255"
+4108 "pragma requires integer between 79 and 132"
+4109 "unexpected identifier '%s'"
+4110 "unexpected token 'int constant'"
+4111 "unexpected token 'string'"
+4112 "macro name '%s' is reserved, %s ignored"
+4113 "function parameter lists differed"
+4000 "UNKNOWN WARNING\n\t\tContact Microsoft Technical Support"
diff --git a/private/mvdm/wow16/commdlg/_xlib.h b/private/mvdm/wow16/commdlg/_xlib.h
new file mode 100644
index 000000000..b2a1267fa
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/_xlib.h
@@ -0,0 +1,56 @@
+//---------------------------------------------------------------------------
+// _xlib.h : Private shared header file for XLIB
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+//----Constants--------------------------------------------------------------
+#define chKeyValue '='
+
+#define cbAtomNameMax 32
+#define cbResNameMax 32
+#define cbClsNameMax 64
+#define cbDlgNameMax 32
+#define cbCaptionMax 32
+#define cbStcTextMax 96
+
+#define mnuFirst 0x0200
+#define mnuLast 0x020f
+#define icoFirst 0x0210
+#define icoLast 0x021f
+#define curFirst 0x0220
+#define curLast 0x022f
+#define aclFirst 0x0230
+#define aclLast 0x023f
+#define bmpFirst 0x0240
+#define bmpLast 0x02ff
+#define resFirst mnuFirst
+#define resLast bmpLast
+
+#define mskKeyDown 0x8000
+
+//----Types------------------------------------------------------------------
+typedef void NEAR * PV;
+typedef void FAR * QV;
+
+//----Macros-----------------------------------------------------------------
+#define ColOf(col) *((DWORD *) (&(col)))
+#define MAKEWORD(bLo, bHi) ((WORD)(((BYTE)(bLo)) | ((WORD)((BYTE)(bHi))) << 8))
+
+#define FIsMnu(res)\
+ ((res) >= mnuFirst && (res) <= mnuLast)
+#define FIsAcl(res)\
+ ((res) >= aclFirst && (res) <= aclLast)
+#define FIsCur(res)\
+ ((res) >= curFirst && (res) <= curLast)
+#define FIsIco(res)\
+ ((res) >= icoFirst && (res) <= icoLast)
+#define FIsBmp(res)\
+ ((res) >= bmpFirst && (res) <= bmpLast)
+
+#define HNULL ((HANDLE) 0)
+
+//----Globals----------------------------------------------------------------
+
+//----Functions--------------------------------------------------------------
+
diff --git a/private/mvdm/wow16/commdlg/cddrv.bmp b/private/mvdm/wow16/commdlg/cddrv.bmp
new file mode 100644
index 000000000..b8d658a06
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/cddrv.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/cderr.h b/private/mvdm/wow16/commdlg/cderr.h
new file mode 100644
index 000000000..402ac0956
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/cderr.h
@@ -0,0 +1,58 @@
+/*****************************************************************************\
+* *
+* cderr.h - Common dialog error return codes *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_CDERR
+#define _INC_CDERR
+
+#define CDERR_DIALOGFAILURE 0xFFFF
+
+#define CDERR_GENERALCODES 0x0000
+#define CDERR_STRUCTSIZE 0x0001
+#define CDERR_INITIALIZATION 0x0002
+#define CDERR_NOTEMPLATE 0x0003
+#define CDERR_NOHINSTANCE 0x0004
+#define CDERR_LOADSTRFAILURE 0x0005
+#define CDERR_FINDRESFAILURE 0x0006
+#define CDERR_LOADRESFAILURE 0x0007
+#define CDERR_LOCKRESFAILURE 0x0008
+#define CDERR_MEMALLOCFAILURE 0x0009
+#define CDERR_MEMLOCKFAILURE 0x000A
+#define CDERR_NOHOOK 0x000B
+#define CDERR_REGISTERMSGFAIL 0x000C
+
+#define PDERR_PRINTERCODES 0x1000
+#define PDERR_SETUPFAILURE 0x1001
+#define PDERR_PARSEFAILURE 0x1002
+#define PDERR_RETDEFFAILURE 0x1003
+#define PDERR_LOADDRVFAILURE 0x1004
+#define PDERR_GETDEVMODEFAIL 0x1005
+#define PDERR_INITFAILURE 0x1006
+#define PDERR_NODEVICES 0x1007
+#define PDERR_NODEFAULTPRN 0x1008
+#define PDERR_DNDMMISMATCH 0x1009
+#define PDERR_CREATEICFAILURE 0x100A
+#define PDERR_PRINTERNOTFOUND 0x100B
+#define PDERR_DEFAULTDIFFERENT 0x100C
+
+#define CFERR_CHOOSEFONTCODES 0x2000
+#define CFERR_NOFONTS 0x2001
+#define CFERR_MAXLESSTHANMIN 0x2002
+
+#define FNERR_FILENAMECODES 0x3000
+#define FNERR_SUBCLASSFAILURE 0x3001
+#define FNERR_INVALIDFILENAME 0x3002
+#define FNERR_BUFFERTOOSMALL 0x3003
+
+#define FRERR_FINDREPLACECODES 0x4000
+#define FRERR_BUFFERLENGTHZERO 0x4001
+
+#define CCERR_CHOOSECOLORCODES 0x5000
+
+#endif /* !_INC_CDERR */
diff --git a/private/mvdm/wow16/commdlg/colordlg.h b/private/mvdm/wow16/commdlg/colordlg.h
new file mode 100644
index 000000000..86ae4e9bb
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/colordlg.h
@@ -0,0 +1,49 @@
+/*****************************************************************************\
+* *
+* colordlg.h - Common dialog color dialog's control id numbers *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_COLORDLG
+#define _INC_COLORDLG
+
+#define DLG_COLOR 10
+
+#define COLOR_HUESCROLL 700 /* color dialog */
+#define COLOR_SATSCROLL 701
+#define COLOR_LUMSCROLL 702
+#define COLOR_HUE 703
+#define COLOR_SAT 704
+#define COLOR_LUM 705
+#define COLOR_RED 706
+#define COLOR_GREEN 707
+#define COLOR_BLUE 708
+#define COLOR_CURRENT 709
+#define COLOR_RAINBOW 710
+#define COLOR_SAVE 711
+#define COLOR_ADD 712
+#define COLOR_SOLID 713
+#define COLOR_TUNE 714
+#define COLOR_SCHEMES 715
+#define COLOR_ELEMENT 716
+#define COLOR_SAMPLES 717
+#define COLOR_PALETTE 718
+#define COLOR_MIX 719
+#define COLOR_BOX1 720
+#define COLOR_CUSTOM1 721
+
+#define COLOR_HUEACCEL 723
+#define COLOR_SATACCEL 724
+#define COLOR_LUMACCEL 725
+#define COLOR_REDACCEL 726
+#define COLOR_GREENACCEL 727
+#define COLOR_BLUEACCEL 728
+
+#define NUM_BASIC_COLORS 48
+#define NUM_CUSTOM_COLORS 16
+
+#endif /* !_INC_COLORDLG */
diff --git a/private/mvdm/wow16/commdlg/commdlg.asm b/private/mvdm/wow16/commdlg/commdlg.asm
new file mode 100644
index 000000000..ce18d7ab5
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/commdlg.asm
@@ -0,0 +1,59 @@
+ TITLE commdlg.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1993, Microsoft Corporation
+;
+; COMMDLG.ASM
+; Thunks in 16-bit space to route commdlg API calls to WOW32
+;
+; History:
+; John Vert (jvert) 30-Dec-1992
+; Created.
+;
+
+ .286p
+
+ include wow.inc
+ include wowcmdlg.inc
+ include cmacros.inc
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+externFP SetWowCommDlg
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+commdlg_Identifier db 'commdlg16 Data Segment'
+
+extrn dwExtError:dword
+sEnd
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+ CommdlgThunk GETOPENFILENAME
+ CommdlgThunk GETSAVEFILENAME
+ CommdlgThunk FINDTEXT
+ CommdlgThunk REPLACETEXT
+ CommdlgThunk CHOOSECOLOR
+ CommdlgThunk CHOOSEFONT
+ CommdlgThunk PRINTDLG
+ CommdlgThunk WOWCOMMDLGEXTENDEDERROR
+
+
+sEnd CODE
+
+end
+
diff --git a/private/mvdm/wow16/commdlg/commdlg.def b/private/mvdm/wow16/commdlg/commdlg.def
new file mode 100644
index 000000000..9820cb5dd
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/commdlg.def
@@ -0,0 +1,59 @@
+;----------------------------------------------------------------------------
+; commdlg.def : module definition for common dialog dll
+;
+; Copyright (c) Microsoft Corporation, 1992-
+;----------------------------------------------------------------------------
+
+;----Definitions-------------------------------------------------------------
+
+LIBRARY COMMDLG
+DESCRIPTION 'Common Windows Dialogs, Ver. 3.10'
+EXETYPE WINDOWS
+CODE MOVEABLE DISCARDABLE LOADONCALL
+DATA SINGLE MOVEABLE PRELOAD
+
+HEAPSIZE 1024
+
+;----Segments----------------------------------------------------------------
+
+SEGMENTS
+ _TEXT DISCARDABLE LOADONCALL
+ _FILEOPEN DISCARDABLE LOADONCALL
+ _PRNSETUP DISCARDABLE LOADONCALL
+ _FONT DISCARDABLE LOADONCALL
+ _FIND DISCARDABLE LOADONCALL
+ _DLGS DISCARDABLE LOADONCALL
+ _INIT DISCARDABLE PRELOAD
+
+
+;----Exports-----------------------------------------------------------------
+
+EXPORTS
+ GETOPENFILENAME @1
+ GETSAVEFILENAME @2
+ CHOOSECOLOR @5
+; FileOpenDlgProc @6 ;Internal
+; FileSaveDlgProc @7 ;Internal
+; ColorDlgProc @8 ;Internal
+; LoadAlterBitmap @9 ;Internal
+ FINDTEXT @11
+ REPLACETEXT @12
+; FindTextDlgProc @13 ;Internal
+; ReplaceTextDlgProc @14 ;Internal
+ CHOOSEFONT @15
+ FORMATCHARDLGPROC @16
+ FONTSTYLEENUMPROC @18
+ FONTFAMILYENUMPROC @19
+ PRINTDLG @20
+; PrintDlgProc @21 ;Internal
+; PrintSetupDlgProc @22 ;Internal
+; EditIntegerOnly @23 ;Internal
+; WantArrows @25 ;Internal
+ COMMDLGEXTENDEDERROR @26
+ GETFILETITLE @27
+ WEP @28 RESIDENTNAME ;Internal
+; dwLBSubclass @29 ;Internal
+; dwUpArrowHack @30 ;Internal
+; dwOKSubclass @31 ;Internal
+; SetWowCommDlg @32 ;Internal temp
+;----Imports-----------------------------------------------------------------
diff --git a/private/mvdm/wow16/commdlg/commdlg.h b/private/mvdm/wow16/commdlg/commdlg.h
new file mode 100644
index 000000000..723f7b4d3
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/commdlg.h
@@ -0,0 +1,318 @@
+/*****************************************************************************\
+* *
+* commdlg.h - Common dialog functions, types, and definitions *
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_COMMDLG
+#define _INC_COMMDLG
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef WINAPI /* If not included with 3.1 headers... */
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+typedef struct tagOFN
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HINSTANCE hInstance;
+ LPCSTR lpstrFilter;
+ LPSTR lpstrCustomFilter;
+ DWORD nMaxCustFilter;
+ DWORD nFilterIndex;
+ LPSTR lpstrFile;
+ DWORD nMaxFile;
+ LPSTR lpstrFileTitle;
+ DWORD nMaxFileTitle;
+ LPCSTR lpstrInitialDir;
+ LPCSTR lpstrTitle;
+ DWORD Flags;
+ UINT nFileOffset;
+ UINT nFileExtension;
+ LPCSTR lpstrDefExt;
+ LPARAM lCustData;
+ UINT (CALLBACK *lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpTemplateName;
+} OPENFILENAME;
+typedef OPENFILENAME FAR* LPOPENFILENAME;
+
+BOOL WINAPI GetOpenFileName(OPENFILENAME FAR*);
+BOOL WINAPI GetSaveFileName(OPENFILENAME FAR*);
+int WINAPI GetFileTitle(LPCSTR, LPSTR, UINT);
+
+#define OFN_READONLY 0x00000001
+#define OFN_OVERWRITEPROMPT 0x00000002
+#define OFN_HIDEREADONLY 0x00000004
+#define OFN_NOCHANGEDIR 0x00000008
+#define OFN_SHOWHELP 0x00000010
+#define OFN_ENABLEHOOK 0x00000020
+#define OFN_ENABLETEMPLATE 0x00000040
+#define OFN_ENABLETEMPLATEHANDLE 0x00000080
+#define OFN_NOVALIDATE 0x00000100
+#define OFN_ALLOWMULTISELECT 0x00000200
+#define OFN_EXTENSIONDIFFERENT 0x00000400
+#define OFN_PATHMUSTEXIST 0x00000800
+#define OFN_FILEMUSTEXIST 0x00001000
+#define OFN_CREATEPROMPT 0x00002000
+#define OFN_SHAREAWARE 0x00004000
+#define OFN_NOREADONLYRETURN 0x00008000
+#define OFN_NOTESTFILECREATE 0x00010000
+
+/* Return values for the registered message sent to the hook function
+ * when a sharing violation occurs. OFN_SHAREFALLTHROUGH allows the
+ * filename to be accepted, OFN_SHARENOWARN rejects the name but puts
+ * up no warning (returned when the app has already put up a warning
+ * message), and OFN_SHAREWARN puts up the default warning message
+ * for sharing violations.
+ *
+ * Note: Undefined return values map to OFN_SHAREWARN, but are
+ * reserved for future use.
+ */
+
+#define OFN_SHAREFALLTHROUGH 2
+#define OFN_SHARENOWARN 1
+#define OFN_SHAREWARN 0
+
+typedef struct tagCHOOSECOLOR
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HWND hInstance;
+ COLORREF rgbResult;
+ COLORREF FAR* lpCustColors;
+ DWORD Flags;
+ LPARAM lCustData;
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpTemplateName;
+} CHOOSECOLOR;
+typedef CHOOSECOLOR FAR *LPCHOOSECOLOR;
+
+BOOL WINAPI ChooseColor(CHOOSECOLOR FAR*);
+
+#define CC_RGBINIT 0x00000001
+#define CC_FULLOPEN 0x00000002
+#define CC_PREVENTFULLOPEN 0x00000004
+#define CC_SHOWHELP 0x00000008
+#define CC_ENABLEHOOK 0x00000010
+#define CC_ENABLETEMPLATE 0x00000020
+#define CC_ENABLETEMPLATEHANDLE 0x00000040
+
+typedef struct tagFINDREPLACE
+{
+ DWORD lStructSize; /* size of this struct 0x20 */
+ HWND hwndOwner; /* handle to owner's window */
+ HINSTANCE hInstance; /* instance handle of.EXE that
+ * contains cust. dlg. template
+ */
+ DWORD Flags; /* one or more of the FR_?? */
+ LPSTR lpstrFindWhat; /* ptr. to search string */
+ LPSTR lpstrReplaceWith; /* ptr. to replace string */
+ UINT wFindWhatLen; /* size of find buffer */
+ UINT wReplaceWithLen; /* size of replace buffer */
+ LPARAM lCustData; /* data passed to hook fn. */
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ /* ptr. to hook fn. or NULL */
+ LPCSTR lpTemplateName; /* custom template name */
+} FINDREPLACE;
+typedef FINDREPLACE FAR *LPFINDREPLACE;
+
+#define FR_DOWN 0x00000001
+#define FR_WHOLEWORD 0x00000002
+#define FR_MATCHCASE 0x00000004
+#define FR_FINDNEXT 0x00000008
+#define FR_REPLACE 0x00000010
+#define FR_REPLACEALL 0x00000020
+#define FR_DIALOGTERM 0x00000040
+#define FR_SHOWHELP 0x00000080
+#define FR_ENABLEHOOK 0x00000100
+#define FR_ENABLETEMPLATE 0x00000200
+#define FR_NOUPDOWN 0x00000400
+#define FR_NOMATCHCASE 0x00000800
+#define FR_NOWHOLEWORD 0x00001000
+#define FR_ENABLETEMPLATEHANDLE 0x00002000
+#define FR_HIDEUPDOWN 0x00004000
+#define FR_HIDEMATCHCASE 0x00008000
+#define FR_HIDEWHOLEWORD 0x00010000
+
+HWND WINAPI FindText(FINDREPLACE FAR*);
+HWND WINAPI ReplaceText(FINDREPLACE FAR*);
+
+typedef struct tagCHOOSEFONT
+{
+ DWORD lStructSize; /* */
+ HWND hwndOwner; /* caller's window handle */
+ HDC hDC; /* printer DC/IC or NULL */
+ LOGFONT FAR* lpLogFont; /* ptr. to a LOGFONT struct */
+ int iPointSize; /* 10 * size in points of selected font */
+ DWORD Flags; /* enum. type flags */
+ COLORREF rgbColors; /* returned text color */
+ LPARAM lCustData; /* data passed to hook fn. */
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ /* ptr. to hook function */
+ LPCSTR lpTemplateName; /* custom template name */
+ HINSTANCE hInstance; /* instance handle of.EXE that
+ * contains cust. dlg. template
+ */
+ LPSTR lpszStyle; /* return the style field here
+ * must be LF_FACESIZE or bigger */
+ UINT nFontType; /* same value reported to the EnumFonts
+ * call back with the extra FONTTYPE_
+ * bits added */
+ int nSizeMin; /* minimum pt size allowed & */
+ int nSizeMax; /* max pt size allowed if */
+ /* CF_LIMITSIZE is used */
+} CHOOSEFONT;
+typedef CHOOSEFONT FAR *LPCHOOSEFONT;
+
+BOOL WINAPI ChooseFont(CHOOSEFONT FAR*);
+
+#define CF_SCREENFONTS 0x00000001
+#define CF_PRINTERFONTS 0x00000002
+#define CF_BOTH (CF_SCREENFONTS | CF_PRINTERFONTS)
+#define CF_SHOWHELP 0x00000004L
+#define CF_ENABLEHOOK 0x00000008L
+#define CF_ENABLETEMPLATE 0x00000010L
+#define CF_ENABLETEMPLATEHANDLE 0x00000020L
+#define CF_INITTOLOGFONTSTRUCT 0x00000040L
+#define CF_USESTYLE 0x00000080L
+#define CF_EFFECTS 0x00000100L
+#define CF_APPLY 0x00000200L
+#define CF_ANSIONLY 0x00000400L
+#define CF_NOVECTORFONTS 0x00000800L
+#define CF_NOOEMFONTS CF_NOVECTORFONTS
+#define CF_NOSIMULATIONS 0x00001000L
+#define CF_LIMITSIZE 0x00002000L
+#define CF_FIXEDPITCHONLY 0x00004000L
+#define CF_WYSIWYG 0x00008000L /* must also have CF_SCREENFONTS & CF_PRINTERFONTS */
+#define CF_FORCEFONTEXIST 0x00010000L
+#define CF_SCALABLEONLY 0x00020000L
+#define CF_TTONLY 0x00040000L
+#define CF_NOFACESEL 0x00080000L
+#define CF_NOSTYLESEL 0x00100000L
+#define CF_NOSIZESEL 0x00200000L
+
+/* these are extra nFontType bits that are added to what is returned to the
+ * EnumFonts callback routine */
+
+#define SIMULATED_FONTTYPE 0x8000
+#define PRINTER_FONTTYPE 0x4000
+#define SCREEN_FONTTYPE 0x2000
+#define BOLD_FONTTYPE 0x0100
+#define ITALIC_FONTTYPE 0x0200
+#define REGULAR_FONTTYPE 0x0400
+
+#define WM_CHOOSEFONT_GETLOGFONT (WM_USER + 1)
+
+
+/* strings used to obtain unique window message for communication
+ * between dialog and caller
+ */
+#define LBSELCHSTRING "commdlg_LBSelChangedNotify"
+#define SHAREVISTRING "commdlg_ShareViolation"
+#define FILEOKSTRING "commdlg_FileNameOK"
+#define COLOROKSTRING "commdlg_ColorOK"
+#define SETRGBSTRING "commdlg_SetRGBColor"
+#define FINDMSGSTRING "commdlg_FindReplace"
+#define HELPMSGSTRING "commdlg_help"
+
+/* HIWORD values for lParam of commdlg_LBSelChangeNotify message */
+#define CD_LBSELNOITEMS -1
+#define CD_LBSELCHANGE 0
+#define CD_LBSELSUB 1
+#define CD_LBSELADD 2
+
+typedef struct tagPD
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HGLOBAL hDevMode;
+ HGLOBAL hDevNames;
+ HDC hDC;
+ DWORD Flags;
+ UINT nFromPage;
+ UINT nToPage;
+ UINT nMinPage;
+ UINT nMaxPage;
+ UINT nCopies;
+ HINSTANCE hInstance;
+ LPARAM lCustData;
+ UINT (CALLBACK* lpfnPrintHook)(HWND, UINT, WPARAM, LPARAM);
+ UINT (CALLBACK* lpfnSetupHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpPrintTemplateName;
+ LPCSTR lpSetupTemplateName;
+ HGLOBAL hPrintTemplate;
+ HGLOBAL hSetupTemplate;
+} PRINTDLG;
+typedef PRINTDLG FAR* LPPRINTDLG;
+
+BOOL WINAPI PrintDlg(PRINTDLG FAR*);
+
+#define PD_ALLPAGES 0x00000000
+#define PD_SELECTION 0x00000001
+#define PD_PAGENUMS 0x00000002
+#define PD_NOSELECTION 0x00000004
+#define PD_NOPAGENUMS 0x00000008
+#define PD_COLLATE 0x00000010
+#define PD_PRINTTOFILE 0x00000020
+#define PD_PRINTSETUP 0x00000040
+#define PD_NOWARNING 0x00000080
+#define PD_RETURNDC 0x00000100
+#define PD_RETURNIC 0x00000200
+#define PD_RETURNDEFAULT 0x00000400
+#define PD_SHOWHELP 0x00000800
+#define PD_ENABLEPRINTHOOK 0x00001000
+#define PD_ENABLESETUPHOOK 0x00002000
+#define PD_ENABLEPRINTTEMPLATE 0x00004000
+#define PD_ENABLESETUPTEMPLATE 0x00008000
+#define PD_ENABLEPRINTTEMPLATEHANDLE 0x00010000
+#define PD_ENABLESETUPTEMPLATEHANDLE 0x00020000
+#define PD_USEDEVMODECOPIES 0x00040000
+#define PD_DISABLEPRINTTOFILE 0x00080000
+#define PD_HIDEPRINTTOFILE 0x00100000
+
+typedef struct tagDEVNAMES
+{
+ UINT wDriverOffset;
+ UINT wDeviceOffset;
+ UINT wOutputOffset;
+ UINT wDefault;
+} DEVNAMES;
+typedef DEVNAMES FAR* LPDEVNAMES;
+
+#define DN_DEFAULTPRN 0x0001
+
+DWORD WINAPI CommDlgExtendedError(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_COMMDLG */
diff --git a/private/mvdm/wow16/commdlg/crosshr.bmp b/private/mvdm/wow16/commdlg/crosshr.bmp
new file mode 100644
index 000000000..605bf6ad6
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/crosshr.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/dlgs.c b/private/mvdm/wow16/commdlg/dlgs.c
new file mode 100644
index 000000000..0a0cab00e
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/dlgs.c
@@ -0,0 +1,112 @@
+/*---------------------------------------------------------------------------
+ Dlgs.c : Common functions for Common Dialog Library
+
+ Copyright (c) Microsoft Corporation, 1990-
+ ---------------------------------------------------------------------------*/
+
+#include "windows.h"
+
+#include "commdlg.h"
+
+char szCommdlgHelp[] = HELPMSGSTRING;
+
+WORD msgHELP;
+WORD wWinVer = 0x030A;
+HANDLE hinsCur;
+DWORD dwExtError;
+
+
+/*---------------------------------------------------------------------------
+ LibMain
+ Purpose: To initialize any instance specific data needed by functions
+ in this DLL
+ Returns: TRUE if A-OK, FALSE if not
+ ---------------------------------------------------------------------------*/
+
+int FAR PASCAL
+LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpstrCmdLine)
+{
+ hinsCur = (HANDLE) hModule;
+ wDataSeg = wDataSeg;
+ cbHeapSize = cbHeapSize;
+ lpstrCmdLine = lpstrCmdLine;
+
+ /* msgHELP is sent whenever a help button is pressed in one of the */
+ /* common dialogs (provided an owner was declared and the call to */
+ /* RegisterWindowMessage doesn't fail. 27 Feb 1991 clarkc */
+
+ msgHELP = RegisterWindowMessage((LPSTR) szCommdlgHelp);
+
+ return(TRUE);
+}
+
+/*---------------------------------------------------------------------------
+ WEP
+ Purpose: To perform cleanup tasks when DLL is unloaded
+ Returns: TRUE if OK, FALSE if not
+ ---------------------------------------------------------------------------*/
+int FAR PASCAL
+WEP(int fSystemExit)
+{
+ fSystemExit = fSystemExit;
+ return(TRUE);
+}
+
+
+
+/*---------------------------------------------------------------------------
+ CommDlgExtendedError
+ Purpose: Provide additional information about dialog failure
+ Assumes: Should be called immediately after failure
+ Returns: Error code in low word, error specific info in hi word
+ ---------------------------------------------------------------------------*/
+
+DWORD FAR PASCAL WowCommDlgExtendedError(void);
+
+DWORD FAR PASCAL CommDlgExtendedError()
+{
+ //
+ // HACKHACK - John Vert (jvert) 8-Jan-1993
+ // If the high bit of dwExtError is set, then the last
+ // common dialog call was thunked through to the 32-bit.
+ // So we need to call the WOW thunk to get the real error.
+ // This will go away when all the common dialogs are thunked.
+ //
+
+ if (dwExtError & 0x80000000) {
+ return(WowCommDlgExtendedError());
+ } else {
+ return(dwExtError);
+ }
+}
+
+VOID _loadds FAR PASCAL SetWowCommDlg()
+{
+ dwExtError = 0x80000000;
+}
+
+/*---------------------------------------------------------------------------
+ MySetObjectOwner
+ Purpose: Call SetObjectOwner in GDI, eliminating "<Object> not released"
+ error messages when an app terminates.
+ Returns: Yep
+ ---------------------------------------------------------------------------*/
+
+void FAR PASCAL MySetObjectOwner(HANDLE hObject)
+{
+ extern char szGDI[];
+ VOID (FAR PASCAL *lpSetObjOwner)(HANDLE, HANDLE);
+ HMODULE hMod;
+
+ if (wWinVer >= 0x030A)
+ {
+ if ((hMod = GetModuleHandle(szGDI)) != NULL) {
+ lpSetObjOwner = GetProcAddress(hMod, MAKEINTRESOURCE(461));
+ if (lpSetObjOwner) {
+ (lpSetObjOwner)(hObject, hinsCur);
+ }
+ }
+ }
+ return;
+}
+
diff --git a/private/mvdm/wow16/commdlg/dlgs.h b/private/mvdm/wow16/commdlg/dlgs.h
new file mode 100644
index 000000000..d701b0f05
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/dlgs.h
@@ -0,0 +1,192 @@
+/*****************************************************************************\
+* *
+* dlgs.h - Common dialog's dialog element ID numbers *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_DLGS
+#define _INC_DLGS
+
+#define ctlFirst 0x0400
+#define ctlLast 0x04ff
+ /* Push buttons */
+#define psh1 0x0400
+#define psh2 0x0401
+#define psh3 0x0402
+#define psh4 0x0403
+#define psh5 0x0404
+#define psh6 0x0405
+#define psh7 0x0406
+#define psh8 0x0407
+#define psh9 0x0408
+#define psh10 0x0409
+#define psh11 0x040a
+#define psh12 0x040b
+#define psh13 0x040c
+#define psh14 0x040d
+#define psh15 0x040e
+#define pshHelp psh15
+#define psh16 0x040f
+ /* Checkboxes */
+#define chx1 0x0410
+#define chx2 0x0411
+#define chx3 0x0412
+#define chx4 0x0413
+#define chx5 0x0414
+#define chx6 0x0415
+#define chx7 0x0416
+#define chx8 0x0417
+#define chx9 0x0418
+#define chx10 0x0419
+#define chx11 0x041a
+#define chx12 0x041b
+#define chx13 0x041c
+#define chx14 0x041d
+#define chx15 0x041e
+#define chx16 0x041f
+ /* Radio buttons */
+#define rad1 0x0420
+#define rad2 0x0421
+#define rad3 0x0422
+#define rad4 0x0423
+#define rad5 0x0424
+#define rad6 0x0425
+#define rad7 0x0426
+#define rad8 0x0427
+#define rad9 0x0428
+#define rad10 0x0429
+#define rad11 0x042a
+#define rad12 0x042b
+#define rad13 0x042c
+#define rad14 0x042d
+#define rad15 0x042e
+#define rad16 0x042f
+ /* Groups, frames, rectangles, and icons */
+#define grp1 0x0430
+#define grp2 0x0431
+#define grp3 0x0432
+#define grp4 0x0433
+#define frm1 0x0434
+#define frm2 0x0435
+#define frm3 0x0436
+#define frm4 0x0437
+#define rct1 0x0438
+#define rct2 0x0439
+#define rct3 0x043a
+#define rct4 0x043b
+#define ico1 0x043c
+#define ico2 0x043d
+#define ico3 0x043e
+#define ico4 0x043f
+ /* Static text */
+#define stc1 0x0440
+#define stc2 0x0441
+#define stc3 0x0442
+#define stc4 0x0443
+#define stc5 0x0444
+#define stc6 0x0445
+#define stc7 0x0446
+#define stc8 0x0447
+#define stc9 0x0448
+#define stc10 0x0449
+#define stc11 0x044a
+#define stc12 0x044b
+#define stc13 0x044c
+#define stc14 0x044d
+#define stc15 0x044e
+#define stc16 0x044f
+#define stc17 0x0450
+#define stc18 0x0451
+#define stc19 0x0452
+#define stc20 0x0453
+#define stc21 0x0454
+#define stc22 0x0455
+#define stc23 0x0456
+#define stc24 0x0457
+#define stc25 0x0458
+#define stc26 0x0459
+#define stc27 0x045a
+#define stc28 0x045b
+#define stc29 0x045c
+#define stc30 0x045d
+#define stc31 0x045e
+#define stc32 0x045f
+ /* Listboxes */
+#define lst1 0x0460
+#define lst2 0x0461
+#define lst3 0x0462
+#define lst4 0x0463
+#define lst5 0x0464
+#define lst6 0x0465
+#define lst7 0x0466
+#define lst8 0x0467
+#define lst9 0x0468
+#define lst10 0x0469
+#define lst11 0x046a
+#define lst12 0x046b
+#define lst13 0x046c
+#define lst14 0x046d
+#define lst15 0x046e
+#define lst16 0x046f
+ /* Combo boxes */
+#define cmb1 0x0470
+#define cmb2 0x0471
+#define cmb3 0x0472
+#define cmb4 0x0473
+#define cmb5 0x0474
+#define cmb6 0x0475
+#define cmb7 0x0476
+#define cmb8 0x0477
+#define cmb9 0x0478
+#define cmb10 0x0479
+#define cmb11 0x047a
+#define cmb12 0x047b
+#define cmb13 0x047c
+#define cmb14 0x047d
+#define cmb15 0x047e
+#define cmb16 0x047f
+ /* Edit controls */
+#define edt1 0x0480
+#define edt2 0x0481
+#define edt3 0x0482
+#define edt4 0x0483
+#define edt5 0x0484
+#define edt6 0x0485
+#define edt7 0x0486
+#define edt8 0x0487
+#define edt9 0x0488
+#define edt10 0x0489
+#define edt11 0x048a
+#define edt12 0x048b
+#define edt13 0x048c
+#define edt14 0x048d
+#define edt15 0x048e
+#define edt16 0x048f
+ /* Scroll bars */
+#define scr1 0x0490
+#define scr2 0x0491
+#define scr3 0x0492
+#define scr4 0x0493
+#define scr5 0x0494
+#define scr6 0x0495
+#define scr7 0x0496
+#define scr8 0x0497
+
+/* These dialog resource ordinals really start at 0x0600, but the
+ * RC Compiler can't handle hex for resource IDs, hence the decimal.
+ */
+#define FILEOPENORD 1536
+#define MULTIFILEOPENORD 1537
+#define PRINTDLGORD 1538
+#define PRNSETUPDLGORD 1539
+#define FINDDLGORD 1540
+#define REPLACEDLGORD 1541
+#define FONTDLGORD 1542
+#define FORMATDLGORD31 1543
+#define FORMATDLGORD30 1544
+
+#endif /* !_INC_DLGS */
diff --git a/private/mvdm/wow16/commdlg/down.bmp b/private/mvdm/wow16/commdlg/down.bmp
new file mode 100644
index 000000000..2f5e7f61c
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/down.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/downi.bmp b/private/mvdm/wow16/commdlg/downi.bmp
new file mode 100644
index 000000000..8bf24fa30
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/downi.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/filebmps.bmp b/private/mvdm/wow16/commdlg/filebmps.bmp
new file mode 100644
index 000000000..9698188ce
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/filebmps.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/font.bmp b/private/mvdm/wow16/commdlg/font.bmp
new file mode 100644
index 000000000..e9f79440b
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/font.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/font.c b/private/mvdm/wow16/commdlg/font.c
new file mode 100644
index 000000000..8e709cfd4
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/font.c
@@ -0,0 +1,1959 @@
+/*******************************************************************************
+ *
+ * MODULE : Font.c
+ *
+ * DESCRIPTION : Font selection dialog routines and related functions.
+ *
+ * HISTORY : 11/13/90 - by L.Raman.
+ * HISTORY : 4/30/91 - reworked for new super font dialog
+ *
+ * Copyright (c) Microsoft Corporation, 1990-
+ *
+ * some notes:
+ *
+ * under 3.0 sending a CB_SETCURSEL message to an owner draw
+ * combo wipes out the exit text (in this case that means the
+ * face and size combos).
+ *
+ ******************************************************************************/
+
+#define NOCOMM
+#define NOWH
+
+#include <windows.h>
+
+#include "privcomd.h"
+#include "font.h"
+
+typedef struct {
+ HWND hwndFamily;
+ HWND hwndStyle;
+ HWND hwndSizes;
+ HDC hDC;
+ DWORD dwFlags;
+ WORD nFontType;
+ BOOL bFillSize;
+ BOOL bPrinterFont;
+ LPCHOOSEFONT lpcf;
+} ENUM_FONT_DATA, FAR *LPENUM_FONT_DATA;
+
+#define CBN_MYSELCHANGE (WM_USER + 500)
+#define CBN_MYEDITUPDATE (WM_USER + 501)
+
+#define DEF_POINT_SIZE 10
+
+HBITMAP NEAR PASCAL LoadBitmaps(int id);
+
+BOOL FAR PASCAL FormatCharDlgProc(HWND, unsigned, WORD, LONG);
+
+void NEAR PASCAL FreeFonts(HWND hwnd);
+BOOL NEAR PASCAL ProcessDlgCtrlCommand(HWND hDlg, LPCHOOSEFONT lpcf, WORD wParam, LONG lParam);
+BOOL NEAR PASCAL DrawColorComboItem(LPDRAWITEMSTRUCT lpdis);
+BOOL NEAR PASCAL DrawFamilyComboItem(LPDRAWITEMSTRUCT lpdis);
+BOOL NEAR PASCAL DrawSizeComboItem(LPDRAWITEMSTRUCT lpdis);
+BOOL NEAR PASCAL FillInFont(HWND hDlg, LPCHOOSEFONT lpcf, LPLOGFONT lplf, BOOL bSetBits);
+void NEAR PASCAL FillColorCombo(HWND hDlg);
+void NEAR PASCAL ComputeSampleTextRectangle(HWND hDlg);
+void NEAR PASCAL SelectStyleFromLF(HWND hwnd, LPLOGFONT lplf);
+void NEAR PASCAL DrawSampleText(HWND hDlg, LPCHOOSEFONT lpcf, HDC hDC);
+int NEAR PASCAL GetPointString(LPSTR buf, HDC hdc, int height);
+BOOL NEAR PASCAL GetFontFamily(HWND hDlg, HDC hDC, DWORD dwEnumCode);
+BOOL NEAR PASCAL GetFontStylesAndSizes(HWND hDlg, LPCHOOSEFONT lpcf, BOOL bFillSizes);
+int NEAR PASCAL CBSetTextFromSel(HWND hwnd);
+int NEAR PASCAL CBSetSelFromText(HWND hwnd, LPSTR lpszString);
+int NEAR PASCAL CBFindString(HWND hwnd, LPSTR lpszString);
+int NEAR PASCAL CBGetTextAndData(HWND hwnd, LPSTR lpszString, int iSize, LPDWORD lpdw);
+void NEAR PASCAL InitLF(LPLOGFONT lplf);
+
+#if 0
+int NEAR PASCAL atoi(LPSTR sz);
+#endif
+
+
+/* color table used for colors combobox
+ the order of these values must match the names in sz.src */
+
+DWORD rgbColors[CCHCOLORS] = {
+ RGB( 0, 0, 0), /* Black */
+ RGB(128, 0, 0), /* Dark red */
+ RGB( 0, 128, 0), /* Dark green */
+ RGB(128, 128, 0), /* Dark yellow */
+ RGB( 0, 0, 128), /* Dark blue */
+ RGB(128, 0, 128), /* Dark purple */
+ RGB( 0, 128, 128), /* Dark aqua */
+ RGB(128, 128, 128), /* Dark grey */
+ RGB(192, 192, 192), /* Light grey */
+ RGB(255, 0, 0), /* Light red */
+ RGB( 0, 255, 0), /* Light green */
+ RGB(255, 255, 0), /* Light yellow */
+ RGB( 0, 0, 255), /* Light blue */
+ RGB(255, 0, 255), /* Light purple */
+ RGB( 0, 255, 255), /* Light aqua */
+ RGB(255, 255, 255), /* White */
+};
+
+RECT rcText;
+WORD nLastFontType;
+HBITMAP hbmFont = NULL;
+
+#define DX_BITMAP 20
+#define DY_BITMAP 12
+
+char szRegular[CCHSTYLE];
+char szBold[CCHSTYLE];
+char szItalic[CCHSTYLE];
+char szBoldItalic[CCHSTYLE];
+
+#if 0
+char szEnumFonts31[] = "EnumFontFamilies";
+char szEnumFonts30[] = "EnumFonts";
+#else
+#define szEnumFonts30 MAKEINTRESOURCE(70)
+#define szEnumFonts31 MAKEINTRESOURCE(330)
+#endif
+
+char szGDI[] = "GDI";
+char szPtFormat[] = "%d";
+
+WORD (FAR PASCAL *glpfnFontHook)(HWND, unsigned, WORD, LONG) = 0;
+
+void NEAR PASCAL SetStyleSelection(HWND hDlg, LPCHOOSEFONT lpcf, BOOL bInit)
+{
+ if (!(lpcf->Flags & CF_NOSTYLESEL)) {
+ if (bInit && (lpcf->Flags & CF_USESTYLE))
+ {
+ PLOGFONT plf;
+ short iSel;
+
+ iSel = CBSetSelFromText(GetDlgItem(hDlg, cmb2), lpcf->lpszStyle);
+ if (iSel >= 0)
+ {
+ plf = (PLOGFONT)(WORD)SendDlgItemMessage(hDlg, cmb2,
+ CB_GETITEMDATA, iSel, 0L);
+ lpcf->lpLogFont->lfWeight = plf->lfWeight;
+ lpcf->lpLogFont->lfItalic = plf->lfItalic;
+ }
+ else
+ {
+ lpcf->lpLogFont->lfWeight = FW_NORMAL;
+ lpcf->lpLogFont->lfItalic = 0;
+ }
+ }
+ else
+ SelectStyleFromLF(GetDlgItem(hDlg, cmb2), lpcf->lpLogFont);
+
+ CBSetTextFromSel(GetDlgItem(hDlg, cmb2));
+ }
+}
+
+
+void NEAR PASCAL HideDlgItem(HWND hDlg, int id)
+{
+ EnableWindow(GetDlgItem(hDlg, id), FALSE);
+ ShowWindow(GetDlgItem(hDlg, id), SW_HIDE);
+}
+
+// fix the ownerdraw combos to match the heigh of the non owner draw combo
+// this only works on 3.1
+
+void NEAR PASCAL FixComboHeights(HWND hDlg)
+{
+ int height;
+
+ height = (int)SendDlgItemMessage(hDlg, cmb2, CB_GETITEMHEIGHT, -1, 0L);
+ SendDlgItemMessage(hDlg, cmb1, CB_SETITEMHEIGHT, -1, (LONG)height);
+ SendDlgItemMessage(hDlg, cmb3, CB_SETITEMHEIGHT, -1, (LONG)height);
+}
+
+
+/****************************************************************************
+ *
+ * FormatCharDlgProc
+ *
+ * PURPOSE : Handles dialog messages for the font picker dialog.
+ *
+ * RETURNS : Normal dialog function values.
+ *
+ * ASSUMES :
+ * chx1 - " " "Underline" checkbox
+ * chx2 - " " "Strikeout" checkbox
+ * psh4 - " " "Help..." pushbutton
+ *
+ * COMMENTS : The CHOOSEFONT struct is accessed via lParam during a
+ * WM_INITDIALOG, and stored in the window's property list. If
+ * a hook function has been specified, it is invoked AFTER the
+ * current function has processed WM_INITDIALOG. For all other
+ * messages, control is passed directly to the hook function.
+ * Depending on the latter's return value, the message is also
+ * processed by this function.
+ *
+ ****************************************************************************/
+
+BOOL FAR PASCAL FormatCharDlgProc(HWND hDlg, unsigned wMsg, WORD wParam, LONG lParam)
+{
+ PAINTSTRUCT ps;
+ TEXTMETRIC tm;
+ HDC hDC; /* handle to screen DC */
+ LPCHOOSEFONT lpcf = NULL; /* ptr. to struct. passed to ChooseFont() */
+ LPCHOOSEFONT *plpcf; /* ptr. to above */
+ HWND hWndHelp; /* handle to Help... pushbutton */
+ short nIndex; /* At init, see if color matches */
+ char szPoints[10];
+ HDC hdc;
+ HFONT hFont;
+ DWORD dw;
+ WORD wRet;
+
+ /* If the CHOOSEFONT. struct has already been accessed and if a hook fn. is
+ * specified, let it do the processing.
+ */
+
+ plpcf = (LPCHOOSEFONT *)GetProp(hDlg, FONTPROP);
+ if (plpcf) {
+ lpcf = (LPCHOOSEFONT)*plpcf++;
+
+ if (lpcf->Flags & CF_ENABLEHOOK) {
+ if ((wRet = (*lpcf->lpfnHook)(hDlg, wMsg, wParam, lParam)) != 0)
+ return wRet;
+ }
+ }
+ else if (glpfnFontHook && (wMsg != WM_INITDIALOG)) {
+ if ((wRet = (* glpfnFontHook)(hDlg, wMsg,wParam,lParam)) != 0) {
+ return(wRet);
+ }
+ }
+
+ switch(wMsg){
+ case WM_INITDIALOG:
+ if (!LoadString(hinsCur, iszRegular, (LPSTR)szRegular, CCHSTYLE) ||
+ !LoadString(hinsCur, iszBold, (LPSTR)szBold, CCHSTYLE) ||
+ !LoadString(hinsCur, iszItalic, (LPSTR)szItalic, CCHSTYLE) ||
+ !LoadString(hinsCur, iszBoldItalic, (LPSTR)szBoldItalic, CCHSTYLE))
+ {
+ dwExtError = CDERR_LOADSTRFAILURE;
+ EndDialog(hDlg, FALSE);
+ return FALSE;
+ }
+ lpcf = (LPCHOOSEFONT)lParam;
+ if ((lpcf->Flags & CF_LIMITSIZE) &&
+ (lpcf->nSizeMax < lpcf->nSizeMin))
+ {
+ dwExtError = CFERR_MAXLESSTHANMIN;
+ EndDialog(hDlg, FALSE);
+ return FALSE;
+ }
+ /* Save the pointer to the CHOOSEFONT struct. in the dialog's
+ * property list. Also, allocate for a temporary LOGFONT struct.
+ * to be used for the length of the dlg. session, the contents of
+ * which will be copied over to the final LOGFONT (pointed to by
+ * CHOOSEFONT) only if <OK> is selected.
+ */
+ if (!(plpcf = (LPCHOOSEFONT *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(LPCHOOSEFONT)))) {
+ dwExtError = CDERR_MEMALLOCFAILURE;
+ EndDialog(hDlg, FALSE);
+ return FALSE;
+ }
+ SetProp(hDlg, FONTPROP, (HANDLE)plpcf);
+ glpfnFontHook = 0;
+
+ lpcf = *(LPCHOOSEFONT FAR *)plpcf = (LPCHOOSEFONT)lParam;
+
+ if (!hbmFont)
+ hbmFont = LoadBitmaps(BMFONT);
+
+ if (!(lpcf->Flags & CF_APPLY))
+ HideDlgItem(hDlg, psh3);
+
+ if (!(lpcf->Flags & CF_EFFECTS)) {
+ HideDlgItem(hDlg, stc4);
+ HideDlgItem(hDlg, cmb4);
+ } else {
+ // fill color list
+
+ FillColorCombo(hDlg);
+ for (nIndex = CCHCOLORS - 1; nIndex > 0; nIndex--) {
+ dw = SendDlgItemMessage(hDlg, cmb4, CB_GETITEMDATA, nIndex, 0L);
+ if (lpcf->rgbColors == dw)
+ break;
+ }
+ SendDlgItemMessage(hDlg, cmb4, CB_SETCURSEL, nIndex, 0L);
+ }
+
+ ComputeSampleTextRectangle(hDlg);
+ FixComboHeights(hDlg);
+
+ // init our LOGFONT
+
+ if (!(lpcf->Flags & CF_INITTOLOGFONTSTRUCT)) {
+ InitLF(lpcf->lpLogFont);
+#if 0
+ *lpcf->lpLogFont->lfFaceName = 0;
+ lpcf->lpLogFont->lfWeight = FW_NORMAL;
+ lpcf->lpLogFont->lfHeight = 0;
+ lpcf->lpLogFont->lfItalic = 0;
+ lpcf->lpLogFont->lfStrikeOut = 0;
+ lpcf->lpLogFont->lfUnderline = 0;
+#endif
+ }
+
+ // init effects
+
+ if (!(lpcf->Flags & CF_EFFECTS)) {
+ HideDlgItem(hDlg, grp1);
+ HideDlgItem(hDlg, chx1);
+ HideDlgItem(hDlg, chx2);
+ } else {
+ CheckDlgButton(hDlg, chx1, lpcf->lpLogFont->lfStrikeOut);
+ CheckDlgButton(hDlg, chx2, lpcf->lpLogFont->lfUnderline);
+ }
+
+ nLastFontType = 0;
+
+ if (!GetFontFamily(hDlg, lpcf->hDC, lpcf->Flags)) {
+ dwExtError = CFERR_NOFONTS;
+ EndDialog(hDlg, FALSE);
+ RemoveProp(hDlg, FONTPROP);
+ if (lpcf->Flags & CF_ENABLEHOOK)
+ glpfnFontHook = lpcf->lpfnHook;
+ return FALSE;
+ }
+
+ if (!(lpcf->Flags & CF_NOFACESEL) && *lpcf->lpLogFont->lfFaceName) {
+ CBSetSelFromText(GetDlgItem(hDlg, cmb1), lpcf->lpLogFont->lfFaceName);
+ CBSetTextFromSel(GetDlgItem(hDlg, cmb1));
+ }
+
+ GetFontStylesAndSizes(hDlg, lpcf, TRUE);
+
+ if (!(lpcf->Flags & CF_NOSTYLESEL)) {
+ SetStyleSelection(hDlg, lpcf, TRUE);
+ }
+
+ if (!(lpcf->Flags & CF_NOSIZESEL) && lpcf->lpLogFont->lfHeight) {
+ hdc = GetDC(NULL);
+ GetPointString(szPoints, hdc, lpcf->lpLogFont->lfHeight);
+ ReleaseDC(NULL, hdc);
+ CBSetSelFromText(GetDlgItem(hDlg, cmb3), szPoints);
+ SetDlgItemText(hDlg, cmb3, szPoints);
+ }
+
+ /* Hide the help button if it isn't needed */
+ if (!(lpcf->Flags & CF_SHOWHELP)) {
+ ShowWindow (hWndHelp = GetDlgItem(hDlg, pshHelp), SW_HIDE);
+ EnableWindow (hWndHelp, FALSE);
+ }
+
+ SendDlgItemMessage(hDlg, cmb1, CB_LIMITTEXT, LF_FACESIZE-1, 0L);
+ SendDlgItemMessage(hDlg, cmb2, CB_LIMITTEXT, LF_FACESIZE-1, 0L);
+ SendDlgItemMessage(hDlg, cmb3, CB_LIMITTEXT, 4, 0L);
+
+ // if hook function has been specified, let it do any additional
+ // processing of this message.
+
+ if (lpcf->Flags & CF_ENABLEHOOK)
+ return (*lpcf->lpfnHook)(hDlg, wMsg, wParam, lParam);
+
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+
+ break;
+
+ case WM_PAINT:
+ if (BeginPaint(hDlg, &ps)) {
+ DrawSampleText(hDlg, lpcf, ps.hdc);
+ EndPaint(hDlg, &ps);
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ hDC = GetDC(hDlg);
+ hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
+ if (hFont)
+ hFont = SelectObject(hDC, hFont);
+ GetTextMetrics(hDC, &tm);
+ if (hFont)
+ SelectObject(hDC, hFont);
+ ReleaseDC(hDlg, hDC);
+
+ if (((LPMEASUREITEMSTRUCT)lParam)->itemID != -1)
+ ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = max(tm.tmHeight, DY_BITMAP);
+ else
+ // this is for 3.0. since in 3.1 the CB_SETITEMHEIGH
+ // will fix this. note, this is off by one on 8514
+ ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = tm.tmHeight + 1;
+
+ break;
+
+ case WM_DRAWITEM:
+ #define lpdis ((LPDRAWITEMSTRUCT)lParam)
+
+ if (lpdis->itemID == 0xFFFF)
+ break;
+
+ if (lpdis->CtlID == cmb4)
+ DrawColorComboItem(lpdis);
+ else if (lpdis->CtlID == cmb1)
+ DrawFamilyComboItem(lpdis);
+ else
+ DrawSizeComboItem(lpdis);
+ break;
+
+ #undef lpdis
+
+ case WM_SYSCOLORCHANGE:
+ DeleteObject(hbmFont);
+ hbmFont = LoadBitmaps(BMFONT);
+ break;
+
+ case WM_COMMAND:
+ return ProcessDlgCtrlCommand(hDlg, lpcf, wParam, lParam);
+ break;
+
+ case WM_CHOOSEFONT_GETLOGFONT:
+ return FillInFont(hDlg, lpcf, (LPLOGFONT)lParam, TRUE);
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// given a logfont select the closest match in the style list
+
+void NEAR PASCAL SelectStyleFromLF(HWND hwnd, LPLOGFONT lplf)
+{
+ int i, count, iSel;
+ PLOGFONT plf;
+ int weight_delta, best_weight_delta = 1000;
+ BOOL bIgnoreItalic;
+
+ count = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+ iSel = 0;
+ bIgnoreItalic = FALSE;
+
+TryAgain:
+ for (i = 0; i < count; i++) {
+ plf = (PLOGFONT)SendMessage(hwnd, CB_GETITEMDATA, i, 0L);
+
+ if (bIgnoreItalic ||
+ (plf->lfItalic && lplf->lfItalic) ||
+ (!plf->lfItalic && !lplf->lfItalic)) {
+
+ weight_delta = lplf->lfWeight - plf->lfWeight;
+ if (weight_delta < 0)
+ weight_delta = -weight_delta;
+
+ if (weight_delta < best_weight_delta) {
+ best_weight_delta = weight_delta;
+ iSel = i;
+ }
+ }
+ }
+ if (!bIgnoreItalic && iSel == 0) {
+ bIgnoreItalic = TRUE;
+ goto TryAgain;
+ }
+
+ SendMessage(hwnd, CB_SETCURSEL, iSel, 0L);
+}
+
+
+
+// make the currently selected item the edit text for a combobox
+
+int NEAR PASCAL CBSetTextFromSel(HWND hwnd)
+{
+ int iSel;
+ char szFace[LF_FACESIZE];
+
+ iSel = (int)SendMessage(hwnd, CB_GETCURSEL, 0, 0L);
+ if (iSel >= 0) {
+ SendMessage(hwnd, CB_GETLBTEXT, iSel, (LONG)(LPSTR)szFace);
+ SetWindowText(hwnd, szFace);
+ }
+ return iSel;
+}
+
+// set the selection based on lpszString. send notification
+// messages if bNotify is TRUE
+
+int NEAR PASCAL CBSetSelFromText(HWND hwnd, LPSTR lpszString)
+{
+ int iInd;
+
+ iInd = CBFindString(hwnd, lpszString);
+
+ if (iInd >= 0) {
+
+ SendMessage(hwnd, CB_SETCURSEL, iInd, 0L);
+
+ }
+ return iInd;
+}
+
+// return the text and item data for a combo box based on the current
+// edit text. if the current edit text does not match anything in the
+// listbox return CB_ERR
+
+int NEAR PASCAL CBGetTextAndData(HWND hwnd, LPSTR lpszString, int iSize, LPDWORD lpdw)
+{
+ int iSel;
+
+ GetWindowText(hwnd, lpszString, iSize);
+ iSel = CBFindString(hwnd, lpszString);
+ if (iSel < 0)
+ return iSel;
+
+ *lpdw = SendMessage(hwnd, CB_GETITEMDATA, iSel, 0L);
+ return iSel;
+}
+
+
+// do an exact string find and return the index
+
+int NEAR PASCAL CBFindString(HWND hwnd, LPSTR lpszString)
+{
+ int iItem, iCount;
+ char szFace[LF_FACESIZE];
+
+ iCount = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+
+ for (iItem = 0; iItem < iCount; iItem++) {
+ SendMessage(hwnd, CB_GETLBTEXT, iItem, (LONG)(LPSTR)szFace);
+ if (!lstrcmpi(szFace, lpszString))
+ return iItem;
+ }
+
+ return CB_ERR;
+}
+
+
+#define GPS_COMPLAIN 0x0001
+#define GPS_SETDEFSIZE 0x0002
+
+// make sure the point size edit field is in range.
+//
+// returns:
+// the point size of the edit field limitted by the min/max size
+// 0 if the field is empty
+
+
+BOOL NEAR PASCAL GetPointSizeInRange(HWND hDlg, LPCHOOSEFONT lpcf, LPINT pts,
+ WORD wFlags)
+{
+ char szBuffer[90];
+ char szTitle[90];
+ int nTmp;
+ BOOL bOK;
+
+ *pts = 0;
+
+ if (GetDlgItemText(hDlg, cmb3, szBuffer, sizeof(szBuffer))) {
+ nTmp = GetDlgItemInt(hDlg, cmb3, &bOK, TRUE);
+ if (!bOK)
+ nTmp = 0;
+ } else if (wFlags & GPS_SETDEFSIZE) {
+ nTmp = DEF_POINT_SIZE;
+ bOK = TRUE;
+ } else {
+ /* We're just returning with 0 in *pts
+ */
+ return(FALSE);
+ }
+
+ /* Check that we got a number in range
+ */
+ if (wFlags & GPS_COMPLAIN) {
+ if ((lpcf->Flags&CF_LIMITSIZE) &&
+ (!bOK || nTmp>lpcf->nSizeMax || nTmp<lpcf->nSizeMin)) {
+ bOK = FALSE;
+ LoadString(hinsCur, iszSizeRange, szTitle, sizeof(szTitle));
+ wsprintf(szBuffer, szTitle, lpcf->nSizeMin, lpcf->nSizeMax);
+ } else if (!bOK)
+ LoadString(hinsCur, iszSizeNumber, szBuffer, sizeof(szBuffer));
+
+ if (!bOK) {
+ GetWindowText(hDlg, szTitle, sizeof(szTitle));
+ MessageBox(hDlg, szBuffer, szTitle, MB_OK | MB_ICONINFORMATION);
+ return(FALSE);
+ }
+ }
+
+ *pts = nTmp;
+ return(TRUE);
+}
+
+
+/****************************************************************************
+ *
+ * ProcessDlgCtrlCommand
+ *
+ * PURPOSE : Handles all WM_COMMAND messages for the font picker dialog
+ *
+ * ASSUMES : cmb1 - ID of font facename combobox
+ * cmb2 - " " style
+ * cmb3 - " " size
+ * chx1 - " " "Underline" checkbox
+ * chx2 - " " "Strikeout" checkbox
+ * stc5 - " " frame around text preview area
+ * psh4 - " " button that invokes the Help application
+ * IDOK - " " OK button to end dialog, retaining information
+ * IDCANCEL" " button to cancel dialog, not doing anything.
+ *
+ * RETURNS : TRUE if message is processed succesfully, FALSE otherwise.
+ *
+ * COMMENTS : if the OK button is selected, all the font information is
+ * written into the CHOOSEFONT structure.
+ *
+ ****************************************************************************/
+
+BOOL NEAR PASCAL ProcessDlgCtrlCommand(HWND hDlg, LPCHOOSEFONT lpcf, WORD wParam, LONG lParam)
+{
+ int iSel;
+ char szPoints[10];
+ char szStyle[LF_FACESIZE];
+ DWORD dw;
+ WORD wCmbId;
+ char szMsg[160], szTitle[160];
+
+ switch (wParam) {
+
+ case IDABORT:
+ // this is how a hook can cause the dialog to go away
+
+ FreeFonts(GetDlgItem(hDlg, cmb2));
+ EndDialog(hDlg, LOWORD(lParam));
+ RemoveProp(hDlg, FONTPROP);
+ if (lpcf->Flags & CF_ENABLEHOOK)
+ glpfnFontHook = lpcf->lpfnHook;
+ break;
+
+ case IDOK:
+ if (!GetPointSizeInRange(hDlg, lpcf, &iSel,
+ GPS_COMPLAIN|GPS_SETDEFSIZE)) {
+ PostMessage(hDlg, WM_NEXTDLGCTL, GetDlgItem(hDlg, cmb3), 1L);
+ break;
+ }
+ lpcf->iPointSize = iSel * 10;
+
+ FillInFont(hDlg, lpcf, lpcf->lpLogFont, TRUE);
+
+ if (lpcf->Flags & CF_FORCEFONTEXIST)
+ {
+ if (lpcf->Flags & CF_NOFACESEL)
+ wCmbId = cmb1;
+ else if (lpcf->Flags & CF_NOSTYLESEL)
+ wCmbId = cmb2;
+ else
+ wCmbId = NULL;
+
+ if (wCmbId) /* Error found */
+ {
+ LoadString(hinsCur, (wCmbId == cmb1) ? iszNoFaceSel
+ : iszNoStyleSel, szMsg, sizeof(szMsg));
+ GetWindowText(hDlg, szTitle, sizeof(szTitle));
+ MessageBox(hDlg, szMsg, szTitle, MB_OK|MB_ICONINFORMATION);
+ PostMessage(hDlg,WM_NEXTDLGCTL,GetDlgItem(hDlg,wCmbId),1L);
+ break;
+ }
+ }
+
+ if (lpcf->Flags & CF_EFFECTS) {
+ // Get currently selected item in color combo box and the 32 bit
+ // color rgb value associated with it
+ iSel = (int)SendDlgItemMessage(hDlg, cmb4, CB_GETCURSEL, 0, 0L);
+ lpcf->rgbColors= (DWORD)SendDlgItemMessage(hDlg, cmb4, CB_GETITEMDATA, iSel, 0L);
+ }
+
+ CBGetTextAndData(GetDlgItem(hDlg, cmb2), szStyle, sizeof(szStyle), &dw);
+ lpcf->nFontType = HIWORD(dw);
+
+ if (lpcf->Flags & CF_USESTYLE)
+ lstrcpy(lpcf->lpszStyle, szStyle);
+
+ // fall through
+
+ case IDCANCEL:
+ FreeFonts(GetDlgItem(hDlg, cmb2));
+ EndDialog(hDlg, wParam == IDOK);
+ RemoveProp(hDlg, FONTPROP);
+ if (lpcf->Flags & CF_ENABLEHOOK)
+ glpfnFontHook = lpcf->lpfnHook;
+ break;
+
+ case cmb1: // facenames combobox
+ switch (HIWORD(lParam)) {
+ case CBN_SELCHANGE:
+ CBSetTextFromSel(LOWORD(lParam));
+FillStyles:
+ // try to mainting the current point size and style
+ GetDlgItemText(hDlg, cmb3, szPoints, sizeof(szPoints));
+ GetFontStylesAndSizes(hDlg, lpcf, FALSE);
+ SetStyleSelection(hDlg, lpcf, FALSE);
+
+
+ // preserv the point size selection or put it in the
+ // edit control if it is not in the list for this font
+
+ iSel = CBFindString(GetDlgItem(hDlg, cmb3), szPoints);
+ if (iSel < 0) {
+ SetDlgItemText(hDlg, cmb3, szPoints);
+ } else {
+ SendDlgItemMessage(hDlg, cmb3, CB_SETCURSEL, iSel, 0L);
+ // 3.0 wipes out the edit text in the above call
+ if (wWinVer < 0x030A)
+ CBSetTextFromSel(GetDlgItem(hDlg, cmb3));
+ }
+
+ if (wWinVer < 0x030A)
+ PostMessage(hDlg, WM_COMMAND, cmb1, MAKELONG(LOWORD(lParam), CBN_MYSELCHANGE));
+ goto DrawSample;
+ break;
+
+ case CBN_MYSELCHANGE: // for 3.0
+ CBSetTextFromSel(LOWORD(lParam));
+ SendMessage(LOWORD(lParam), CB_SETEDITSEL, 0, 0xFFFF0000);
+ break;
+
+ case CBN_EDITUPDATE:
+ PostMessage(hDlg, WM_COMMAND, wParam, MAKELONG(LOWORD(lParam), CBN_MYEDITUPDATE));
+ break;
+
+ // case CBN_EDITCHANGE:
+ // case CBN_EDITUPDATE:
+ case CBN_MYEDITUPDATE:
+ GetWindowText(LOWORD(lParam), szStyle, sizeof(szStyle));
+ iSel = CBFindString(LOWORD(lParam), szStyle);
+ if (iSel >= 0) {
+ SendMessage(LOWORD(lParam), CB_SETCURSEL, iSel, 0L);
+ // 3.0 wipes out the edit text in the above call
+ if (wWinVer < 0x030A)
+ CBSetTextFromSel(LOWORD(lParam));
+ SendMessage(LOWORD(lParam), CB_SETEDITSEL, 0, -1L);
+ goto FillStyles;
+ }
+ break;
+ }
+ break;
+
+ case cmb3: // point sizes combobox
+ case cmb2: // styles combobox
+ switch (HIWORD(lParam)) {
+ case CBN_EDITUPDATE:
+ PostMessage(hDlg, WM_COMMAND, wParam, MAKELONG(LOWORD(lParam), CBN_MYEDITUPDATE));
+ break;
+
+ // case CBN_EDITCHANGE:
+ // case CBN_EDITUPDATE:
+ case CBN_MYEDITUPDATE:
+ if (wParam == cmb2) {
+ GetWindowText(LOWORD(lParam), szStyle, sizeof(szStyle));
+ iSel = CBFindString(LOWORD(lParam), szStyle);
+ if (iSel >= 0) {
+ SendMessage(LOWORD(lParam), CB_SETCURSEL, iSel, 0L);
+ // 3.0 wipes out the edit text in the above call
+ if (wWinVer < 0x030A)
+ CBSetTextFromSel(LOWORD(lParam));
+ SendMessage(LOWORD(lParam), CB_SETEDITSEL, 0, -1L);
+ goto DrawSample;
+ }
+ }
+ break;
+
+ case CBN_SELCHANGE:
+ iSel = CBSetTextFromSel(LOWORD(lParam));
+ if (iSel >= 0) {
+ // make the style selection stick
+ if (wParam == cmb2) {
+ PLOGFONT plf = (PLOGFONT)(WORD)SendMessage(LOWORD(lParam), CB_GETITEMDATA, iSel, 0L);
+ lpcf->lpLogFont->lfWeight = plf->lfWeight;
+ lpcf->lpLogFont->lfItalic = plf->lfItalic;
+ }
+ }
+
+ if (wWinVer < 0x030A)
+ PostMessage(hDlg, WM_COMMAND, wParam, MAKELONG(LOWORD(lParam), CBN_MYSELCHANGE));
+ goto DrawSample;
+
+ case CBN_MYSELCHANGE: // for 3.0
+ CBSetTextFromSel(LOWORD(lParam));
+ SendMessage(LOWORD(lParam), CB_SETEDITSEL, 0, 0xFFFF0000);
+ break;
+
+ case CBN_KILLFOCUS:
+DrawSample:
+ // force redraw of preview text for any size change
+ InvalidateRect(hDlg, &rcText, FALSE);
+ UpdateWindow(hDlg);
+ }
+ break;
+
+ case cmb4:
+ if (HIWORD(lParam) != CBN_SELCHANGE)
+ break;
+
+ // fall through
+
+ case chx1: // bold
+ case chx2: // italic
+ goto DrawSample;
+
+ case pshHelp: // help
+ if (msgHELP && lpcf->hwndOwner)
+ SendMessage(lpcf->hwndOwner, msgHELP, hDlg, (DWORD) lpcf);
+ break;
+
+ default:
+ return (FALSE);
+ }
+ return TRUE;
+}
+
+//
+// this returns the best of the 2 font types.
+// the values of the font type bits are monotonic except the low
+// bit (RASTER_FONTTYPE). so we flip that bit and then can compare
+// the words directly.
+//
+
+int NEAR PASCAL CmpFontType(WORD ft1, WORD ft2)
+{
+ ft1 &= ~(SCREEN_FONTTYPE | PRINTER_FONTTYPE);
+ ft2 &= ~(SCREEN_FONTTYPE | PRINTER_FONTTYPE);
+
+ ft1 ^= RASTER_FONTTYPE; // flip these so we can compare
+ ft2 ^= RASTER_FONTTYPE;
+
+ return (int)ft1 - (int)ft2;
+}
+
+
+// nFontType bits
+//
+// SCALABLE DEVICE RASTER
+// (TT) (not GDI) (not scalable)
+// 0 0 0 vector, ATM screen
+// 0 0 1 GDI raster font
+// 0 1 0 PS/LJ III, ATM printer, ATI/LaserMaster
+// 0 1 1 non scalable device font
+// 1 0 x TT screen font
+// 1 1 x TT dev font
+
+int FAR PASCAL FontFamilyEnumProc(LPLOGFONT lplf, LPTEXTMETRIC lptm, WORD nFontType, LPENUM_FONT_DATA lpData)
+{
+ int iItem;
+ WORD nOldType, nNewType;
+
+ lptm = lptm;
+
+ // bounce non TT fonts
+ if ((lpData->dwFlags & CF_TTONLY) &&
+ !(nFontType & TRUETYPE_FONTTYPE))
+ return TRUE;
+
+ // bounce non scalable fonts
+ if ((lpData->dwFlags & CF_SCALABLEONLY) &&
+ (nFontType & RASTER_FONTTYPE))
+ return TRUE;
+
+ // bounce non ANSI fonts
+ if ((lpData->dwFlags & CF_ANSIONLY) &&
+ (lplf->lfCharSet != ANSI_CHARSET))
+ return TRUE;
+
+ // bounce proportional fonts
+ if ((lpData->dwFlags & CF_FIXEDPITCHONLY) &&
+ (lplf->lfPitchAndFamily & VARIABLE_PITCH))
+ return TRUE;
+
+ // bounce vector fonts
+ if ((lpData->dwFlags & CF_NOVECTORFONTS) &&
+ (lplf->lfCharSet == OEM_CHARSET))
+ return TRUE;
+
+ if (lpData->bPrinterFont)
+ nFontType |= PRINTER_FONTTYPE;
+ else
+ nFontType |= SCREEN_FONTTYPE;
+
+ // test for a name collision
+ iItem = CBFindString(lpData->hwndFamily, lplf->lfFaceName);
+ if (iItem >= 0) {
+ nOldType = (WORD)SendMessage(lpData->hwndFamily, CB_GETITEMDATA, iItem, 0L);
+ /* If we don't want screen fonts, but do want printer fonts,
+ * the old font is a screen font and the new font is a
+ * printer font, take the new font regardless of other flags.
+ * Note that this means if a printer wants TRUETYPE fonts, it
+ * should enumerate them. Bug 9675, 12-12-91, Clark Cyr
+ */
+ if (!(lpData->dwFlags & CF_SCREENFONTS) &&
+ (lpData->dwFlags & CF_PRINTERFONTS) &&
+ (nFontType & PRINTER_FONTTYPE) &&
+ (nOldType & SCREEN_FONTTYPE) )
+ {
+ nOldType = 0; /* for setting nNewType below */
+ goto SetNewType;
+ }
+
+ if (CmpFontType(nFontType, nOldType) > 0) {
+SetNewType:
+ nNewType = nFontType;
+ SendMessage(lpData->hwndFamily, CB_INSERTSTRING, iItem, (LONG)(LPSTR)lplf->lfFaceName);
+ SendMessage(lpData->hwndFamily, CB_DELETESTRING, iItem + 1, 0L);
+ } else {
+ nNewType = nOldType;
+ }
+ // accumulate the printer/screen ness of these fonts
+ nNewType |= (nFontType | nOldType) & (SCREEN_FONTTYPE | PRINTER_FONTTYPE);
+
+ SendMessage(lpData->hwndFamily, CB_SETITEMDATA, iItem, MAKELONG(nNewType, 0));
+ return TRUE;
+ }
+
+ iItem = (int)SendMessage(lpData->hwndFamily, CB_ADDSTRING, 0, (LONG)(LPSTR)lplf->lfFaceName);
+ if (iItem < 0)
+ return FALSE;
+
+ SendMessage(lpData->hwndFamily, CB_SETITEMDATA, iItem, MAKELONG(nFontType, 0));
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+ *
+ * GetFontFamily
+ *
+ * PURPOSE : Fills the screen and/or printer font facenames into the font
+ * facenames combobox, depending on the CF_?? flags passed in.
+ *
+ * ASSUMES : cmb1 - ID of font facename combobox
+ *
+ * RETURNS : TRUE if succesful, FALSE otherwise.
+ *
+ * COMMENTS : Both screen and printer fonts are listed into the same combo
+ * box.
+ *
+ ****************************************************************************/
+
+BOOL NEAR PASCAL GetFontFamily(HWND hDlg, HDC hDC, DWORD dwEnumCode)
+{
+ ENUM_FONT_DATA data;
+ HANDLE hMod;
+ int iItem, iCount;
+ WORD nFontType;
+ char szMsg[100], szTitle[40];
+ WORD (FAR PASCAL *lpEnumFonts)(HDC, LPSTR, FARPROC, VOID FAR *);
+
+ hMod = GetModuleHandle(szGDI);
+ if (wWinVer < 0x030A)
+ lpEnumFonts = GetProcAddress(hMod, szEnumFonts30);
+ else
+ lpEnumFonts = GetProcAddress(hMod, szEnumFonts31);
+
+ if (!lpEnumFonts)
+ return FALSE;
+
+ data.hwndFamily = GetDlgItem(hDlg, cmb1);
+ data.dwFlags = dwEnumCode;
+
+ // this is a bit strage. we have to get all the screen fonts
+ // so if they ask for the printer fonts we can tell which
+ // are really printer fonts. that is so we don't list the
+ // vector and raster fonts as printer device fonts
+
+ data.hDC = GetDC(NULL);
+ data.bPrinterFont = FALSE;
+ (*lpEnumFonts)(data.hDC, NULL, FontFamilyEnumProc, &data);
+ ReleaseDC(NULL, data.hDC);
+
+ /* list out printer font facenames */
+ if (dwEnumCode & CF_PRINTERFONTS) {
+ data.hDC = hDC;
+ data.bPrinterFont = TRUE;
+ (*lpEnumFonts)(hDC, NULL, FontFamilyEnumProc, &data);
+ }
+
+ // now we have to remove those screen fonts if they didn't
+ // ask for them.
+
+ if (!(dwEnumCode & CF_SCREENFONTS)) {
+ iCount = (int)SendMessage(data.hwndFamily, CB_GETCOUNT, 0, 0L);
+
+ for (iItem = iCount - 1; iItem >= 0; iItem--) {
+ nFontType = (WORD)SendMessage(data.hwndFamily, CB_GETITEMDATA, iItem, 0L);
+ if ((nFontType & (SCREEN_FONTTYPE | PRINTER_FONTTYPE)) == SCREEN_FONTTYPE)
+ SendMessage(data.hwndFamily, CB_DELETESTRING, iItem, 0L);
+ }
+ }
+
+ // for WYSIWYG mode we delete all the fonts that don't exist
+ // on the screen and the printer
+
+ if (dwEnumCode & CF_WYSIWYG) {
+ iCount = (int)SendMessage(data.hwndFamily, CB_GETCOUNT, 0, 0L);
+
+ for (iItem = iCount - 1; iItem >= 0; iItem--) {
+ nFontType = (WORD)SendMessage(data.hwndFamily, CB_GETITEMDATA, iItem, 0L);
+ if ((nFontType & (SCREEN_FONTTYPE | PRINTER_FONTTYPE)) != (SCREEN_FONTTYPE | PRINTER_FONTTYPE))
+ SendMessage(data.hwndFamily, CB_DELETESTRING, iItem, 0L);
+ }
+ }
+
+ if ((int)SendMessage(data.hwndFamily, CB_GETCOUNT, 0, 0L) <= 0) {
+ LoadString(hinsCur, iszNoFontsTitle, szTitle, sizeof(szTitle));
+ LoadString(hinsCur, iszNoFontsMsg, szMsg, sizeof(szMsg));
+ MessageBox(hDlg, szMsg, szTitle, MB_OK | MB_ICONINFORMATION);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void NEAR PASCAL CBAddSize(HWND hwnd, int pts, LPCHOOSEFONT lpcf)
+{
+ int iInd;
+ char szSize[10];
+ int count, test_size;
+
+ if ((lpcf->Flags & CF_LIMITSIZE) && ((pts > lpcf->nSizeMax) || (pts < lpcf->nSizeMin)))
+ return;
+
+ wsprintf(szSize, szPtFormat, pts);
+
+ count = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+
+ test_size = -1;
+
+ for (iInd = 0; iInd < count; iInd++) {
+ test_size = (int)SendMessage(hwnd, CB_GETITEMDATA, iInd, 0L);
+ if (pts <= test_size)
+ break;
+ }
+
+ if (pts == test_size) /* don't add duplicates */
+ return;
+
+ iInd = (int)SendMessage(hwnd, CB_INSERTSTRING, iInd, (LONG)(LPSTR)szSize);
+
+ if (iInd >= 0)
+ SendMessage(hwnd, CB_SETITEMDATA, iInd, MAKELONG(pts, 0));
+}
+
+// sort styles by weight first, then italicness
+// returns:
+// the index of the place this was inserted
+
+int NEAR PASCAL InsertStyleSorted(HWND hwnd, LPSTR lpszStyle, LPLOGFONT lplf)
+{
+ int count, i;
+ PLOGFONT plf;
+
+ count = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+
+ for (i = 0; i < count; i++) {
+ plf = (PLOGFONT)SendMessage(hwnd, CB_GETITEMDATA, i, 0L);
+ if (lplf->lfWeight < plf->lfWeight) {
+ break;
+ } else if (lplf->lfWeight == plf->lfWeight) {
+ if (lplf->lfItalic && !plf->lfItalic)
+ i++;
+ break;
+ }
+ }
+ return (int)SendMessage(hwnd, CB_INSERTSTRING, i, (LONG)lpszStyle);
+}
+
+
+PLOGFONT NEAR PASCAL CBAddStyle(HWND hwnd, LPSTR lpszStyle, WORD nFontType, LPLOGFONT lplf)
+{
+ int iItem;
+ PLOGFONT plf;
+
+ // don't add duplicates
+
+ if (CBFindString(hwnd, lpszStyle) >= 0)
+ return NULL;
+
+ iItem = (int)InsertStyleSorted(hwnd, lpszStyle, lplf);
+ if (iItem < 0)
+ return NULL;
+
+ plf = (PLOGFONT)LocalAlloc(LMEM_FIXED, sizeof(LOGFONT));
+ if (!plf) {
+ SendMessage(hwnd, CB_DELETESTRING, iItem, 0L);
+ return NULL;
+ }
+
+ *plf = *lplf;
+
+ SendMessage(hwnd, CB_SETITEMDATA, iItem, MAKELONG(plf, nFontType));
+
+ return plf;
+}
+
+// generate simulated forms from those that we have
+//
+// reg -> bold
+// reg -> italic
+// bold || italic || reg -> bold italic
+
+void NEAR PASCAL FillInMissingStyles(HWND hwnd)
+{
+ PLOGFONT plf, plf_reg, plf_bold, plf_italic;
+ WORD nFontType;
+ int i, count;
+ BOOL bBold, bItalic, bBoldItalic;
+ DWORD dw;
+ LOGFONT lf;
+
+ bBold = bItalic = bBoldItalic = FALSE;
+ plf_reg = plf_bold = plf_italic = NULL;
+
+ count = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+ for (i = 0; i < count; i++) {
+ dw = SendMessage(hwnd, CB_GETITEMDATA, i, 0L);
+ plf = (PLOGFONT)LOWORD(dw);
+ nFontType = HIWORD(dw);
+ if ((nFontType & BOLD_FONTTYPE) && (nFontType & ITALIC_FONTTYPE)) {
+ bBoldItalic = TRUE;
+ } else if (nFontType & BOLD_FONTTYPE) {
+ bBold = TRUE;
+ plf_bold = plf;
+ } else if (nFontType & ITALIC_FONTTYPE) {
+ bItalic = TRUE;
+ plf_italic = plf;
+ } else
+ plf_reg = plf;
+ }
+
+ nFontType |= SIMULATED_FONTTYPE;
+
+ if (!bBold && plf_reg) {
+ lf = *plf_reg;
+ lf.lfWeight = FW_BOLD;
+ CBAddStyle(hwnd, szBold, nFontType | BOLD_FONTTYPE, &lf);
+ }
+
+ if (!bItalic && plf_reg) {
+ lf = *plf_reg;
+ lf.lfItalic = TRUE;
+ CBAddStyle(hwnd, szItalic, nFontType | ITALIC_FONTTYPE, &lf);
+ }
+ if (!bBoldItalic && (plf_bold || plf_italic || plf_reg)) {
+ if (plf_italic)
+ plf = plf_italic;
+ else if (plf_bold)
+ plf = plf_bold;
+ else
+ plf = plf_reg;
+
+ lf = *plf;
+ lf.lfItalic = TRUE;
+ lf.lfWeight = FW_BOLD;
+ CBAddStyle(hwnd, szBoldItalic, nFontType | BOLD_FONTTYPE | ITALIC_FONTTYPE, &lf);
+ }
+}
+
+void NEAR PASCAL FillScalableSizes(HWND hwnd, LPCHOOSEFONT lpcf)
+{
+ CBAddSize(hwnd, 8, lpcf);
+ CBAddSize(hwnd, 9, lpcf);
+ CBAddSize(hwnd, 10, lpcf);
+ CBAddSize(hwnd, 11, lpcf);
+ CBAddSize(hwnd, 12, lpcf);
+ CBAddSize(hwnd, 14, lpcf);
+ CBAddSize(hwnd, 16, lpcf);
+ CBAddSize(hwnd, 18, lpcf);
+ CBAddSize(hwnd, 20, lpcf);
+ CBAddSize(hwnd, 22, lpcf);
+ CBAddSize(hwnd, 24, lpcf);
+ CBAddSize(hwnd, 26, lpcf);
+ CBAddSize(hwnd, 28, lpcf);
+ CBAddSize(hwnd, 36, lpcf);
+ CBAddSize(hwnd, 48, lpcf);
+ CBAddSize(hwnd, 72, lpcf);
+}
+
+#define GDI_FONTTYPE_STUFF (RASTER_FONTTYPE | DEVICE_FONTTYPE | TRUETYPE_FONTTYPE)
+
+int FAR PASCAL FontStyleEnumProc(LPLOGFONT lplf, LPNEWTEXTMETRIC lptm, WORD nFontType, LPENUM_FONT_DATA lpData)
+{
+ int height, pts;
+ char buf[10];
+
+ // filter for a font type match (the font type of the selected face
+ // must be the same as that enumerated)
+
+ if (nFontType != (WORD)(GDI_FONTTYPE_STUFF & lpData->nFontType))
+ return TRUE;
+
+ if (!(nFontType & RASTER_FONTTYPE)) {
+
+ // vector or TT font
+
+ if (lpData->bFillSize &&
+ (int)SendMessage(lpData->hwndSizes, CB_GETCOUNT, 0, 0L) == 0) {
+ FillScalableSizes(lpData->hwndSizes, lpData->lpcf);
+ }
+
+ } else {
+
+ height = lptm->tmHeight - lptm->tmInternalLeading;
+ pts = GetPointString(buf, lpData->hDC, height);
+
+ // filter devices same size of multiple styles
+ if (CBFindString(lpData->hwndSizes, buf) < 0)
+ CBAddSize(lpData->hwndSizes, pts, lpData->lpcf);
+
+ }
+
+ // keep the printer/screen bits from the family list here too
+
+ nFontType |= (lpData->nFontType & (SCREEN_FONTTYPE | PRINTER_FONTTYPE));
+
+ if (nFontType & TRUETYPE_FONTTYPE) {
+
+ // if (lptm->ntmFlags & NTM_REGULAR)
+ if (!(lptm->ntmFlags & (NTM_BOLD | NTM_ITALIC)))
+ nFontType |= REGULAR_FONTTYPE;
+
+ if (lptm->ntmFlags & NTM_ITALIC)
+ nFontType |= ITALIC_FONTTYPE;
+
+ if (lptm->ntmFlags & NTM_BOLD)
+ nFontType |= BOLD_FONTTYPE;
+
+ // after the LOGFONT.lfFaceName there are 2 more names
+ // lfFullName[LF_FACESIZE * 2]
+ // lfStyle[LF_FACESIZE]
+
+ CBAddStyle(lpData->hwndStyle, lplf->lfFaceName + 3 * LF_FACESIZE, nFontType, lplf);
+
+ } else {
+ if ((lplf->lfWeight >= FW_BOLD) && lplf->lfItalic)
+ CBAddStyle(lpData->hwndStyle, szBoldItalic, nFontType | BOLD_FONTTYPE | ITALIC_FONTTYPE, lplf);
+ else if (lplf->lfWeight >= FW_BOLD)
+ CBAddStyle(lpData->hwndStyle, szBold, nFontType | BOLD_FONTTYPE, lplf);
+ else if (lplf->lfItalic)
+ CBAddStyle(lpData->hwndStyle, szItalic, nFontType | ITALIC_FONTTYPE, lplf);
+ else
+ CBAddStyle(lpData->hwndStyle, szRegular, nFontType | REGULAR_FONTTYPE, lplf);
+ }
+
+ return TRUE;
+}
+
+void NEAR PASCAL FreeFonts(HWND hwnd)
+{
+ DWORD dw;
+ int i, count;
+
+ count = (int)SendMessage(hwnd, CB_GETCOUNT, 0, 0L);
+
+ for (i = 0; i < count; i++) {
+ dw = SendMessage(hwnd, CB_GETITEMDATA, i, 0L);
+ LocalFree((HANDLE)LOWORD(dw));
+ }
+
+ SendMessage(hwnd, CB_RESETCONTENT, 0, 0L);
+}
+
+// initalize a LOGFONT strucuture to some base generic regular type font
+
+void NEAR PASCAL InitLF(LPLOGFONT lplf)
+{
+ HDC hdc;
+
+ lplf->lfEscapement = 0;
+ lplf->lfOrientation = 0;
+ lplf->lfCharSet = ANSI_CHARSET;
+ lplf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lplf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lplf->lfQuality = DEFAULT_QUALITY;
+ lplf->lfPitchAndFamily = DEFAULT_PITCH;
+ lplf->lfItalic = 0;
+ lplf->lfWeight = FW_NORMAL;
+ lplf->lfStrikeOut = 0;
+ lplf->lfUnderline = 0;
+ lplf->lfWidth = 0; // otherwise we get independant x-y scaling
+ lplf->lfFaceName[0] = 0;
+ hdc = GetDC(NULL);
+ lplf->lfHeight = -MulDiv(DEF_POINT_SIZE, GetDeviceCaps(hdc, LOGPIXELSY), POINTS_PER_INCH);
+ ReleaseDC(NULL, hdc);
+}
+
+
+
+/****************************************************************************
+ *
+ * GetFontStylesAndSizes
+ *
+ * PURPOSE : Fills the point sizes combo box with the point sizes for the
+ * current selection in the facenames combobox.
+ *
+ * ASSUMES : cmb1 - ID of font facename combobox
+ *
+ * RETURNS : TRUE if succesful, FALSE otherwise.
+ *
+ ****************************************************************************/
+
+BOOL NEAR PASCAL GetFontStylesAndSizes(HWND hDlg, LPCHOOSEFONT lpcf, BOOL bForceSizeFill)
+{
+ ENUM_FONT_DATA data;
+ char szFace[LF_FACESIZE];
+ WORD nFontType;
+ int iSel;
+ int iMapMode;
+ DWORD dwViewportExt, dwWindowExt;
+ HANDLE hMod;
+ LOGFONT lf;
+ WORD (FAR PASCAL *lpEnumFonts)(HDC, LPSTR, FARPROC, VOID FAR *);
+
+ bForceSizeFill = bForceSizeFill;
+
+ hMod = GetModuleHandle(szGDI);
+ if (wWinVer < 0x030A)
+ lpEnumFonts = GetProcAddress(hMod, szEnumFonts30);
+ else
+ lpEnumFonts = GetProcAddress(hMod, szEnumFonts31);
+
+ if (!lpEnumFonts)
+ return FALSE;
+
+ FreeFonts(GetDlgItem(hDlg, cmb2));
+
+ data.hwndStyle = GetDlgItem(hDlg, cmb2);
+ data.hwndSizes = GetDlgItem(hDlg, cmb3);
+ data.dwFlags = lpcf->Flags;
+ data.lpcf = lpcf;
+
+ iSel = (int)SendDlgItemMessage(hDlg, cmb1, CB_GETCURSEL, 0, 0L);
+ if (iSel < 0) {
+ // if we don't have a face name selected we will synthisize
+ // the standard font styles...
+
+ InitLF(&lf);
+ CBAddStyle(data.hwndStyle, szRegular, REGULAR_FONTTYPE, &lf);
+ lf.lfWeight = FW_BOLD;
+ CBAddStyle(data.hwndStyle, szBold, BOLD_FONTTYPE, &lf);
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = TRUE;
+ CBAddStyle(data.hwndStyle, szItalic, ITALIC_FONTTYPE, &lf);
+ lf.lfWeight = FW_BOLD;
+ CBAddStyle(data.hwndStyle, szBoldItalic, BOLD_FONTTYPE | ITALIC_FONTTYPE, &lf);
+ FillScalableSizes(data.hwndSizes, lpcf);
+
+ return TRUE;
+ }
+
+ nFontType = (WORD)SendDlgItemMessage(hDlg, cmb1, CB_GETITEMDATA, iSel, 0L);
+
+ data.nFontType = nFontType;
+#if 0
+ data.bFillSize = bForceSizeFill ||
+ (nLastFontType & RASTER_FONTTYPE) != (nFontType & RASTER_FONTTYPE) ||
+ (nFontType & RASTER_FONTTYPE);
+/* This does the same thing as above, i.e. if either or both fonts are
+ * raster fonts, update the sizes combobox. If they're both non-raster,
+ * don't update the combobox.
+ */
+ data.bFillSize = bForceSizeFill ||
+ (nLastFontType & RASTER_FONTTYPE) ||
+ (nFontType & RASTER_FONTTYPE) ||
+ (SendMessage(data.hwndSizes, CB_GETCOUNT, 0, 0L) <= 0);
+#else
+ data.bFillSize = TRUE;
+#endif
+
+ if (data.bFillSize) {
+ SendMessage(data.hwndSizes, CB_RESETCONTENT, 0, 0L);
+ SendMessage(data.hwndSizes, WM_SETREDRAW, FALSE, 0L);
+ }
+
+ SendMessage(data.hwndStyle, WM_SETREDRAW, FALSE, 0L);
+
+ GetDlgItemText(hDlg, cmb1, szFace, sizeof(szFace));
+
+ if (lpcf->Flags & CF_SCREENFONTS) {
+ data.hDC = GetDC(NULL);
+ data.bPrinterFont = FALSE;
+ (*lpEnumFonts)(data.hDC, szFace, FontStyleEnumProc, &data);
+ ReleaseDC(NULL, data.hDC);
+ }
+
+ if (lpcf->Flags & CF_PRINTERFONTS) {
+/* Bug #10619: Save and restore the DC's mapping mode (and extents if
+ * needed) if it's been set by the app to something other than MM_TEXT.
+ * 3 January 1992 Clark Cyr
+ */
+ if ((iMapMode = GetMapMode(lpcf->hDC)) != MM_TEXT)
+ {
+ if ((iMapMode == MM_ISOTROPIC) || (iMapMode == MM_ANISOTROPIC))
+ {
+ dwViewportExt = GetViewportExt(lpcf->hDC);
+ dwWindowExt = GetWindowExt(lpcf->hDC);
+ }
+ SetMapMode(lpcf->hDC, MM_TEXT);
+ }
+
+ data.hDC = lpcf->hDC;
+ data.bPrinterFont = TRUE;
+ (*lpEnumFonts)(lpcf->hDC, szFace, FontStyleEnumProc, &data);
+
+ if (iMapMode != MM_TEXT)
+ {
+ SetMapMode(lpcf->hDC, iMapMode);
+ if ((iMapMode == MM_ISOTROPIC) || (iMapMode == MM_ANISOTROPIC))
+ {
+ SetWindowExt(lpcf->hDC, LOWORD(dwWindowExt),
+ HIWORD(dwWindowExt));
+ SetViewportExt(lpcf->hDC, LOWORD(dwViewportExt),
+ HIWORD(dwViewportExt));
+ }
+ }
+ }
+
+ if (!(lpcf->Flags & CF_NOSIMULATIONS))
+ FillInMissingStyles(data.hwndStyle);
+
+ SendMessage(data.hwndStyle, WM_SETREDRAW, TRUE, 0L);
+ if (wWinVer < 0x030A)
+ InvalidateRect(data.hwndStyle, NULL, TRUE);
+
+ if (data.bFillSize) {
+ SendMessage(data.hwndSizes, WM_SETREDRAW, TRUE, 0L);
+ if (wWinVer < 0x030A)
+ InvalidateRect(data.hwndSizes, NULL, TRUE);
+ }
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+ *
+ * FillColorCombo
+ *
+ * PURPOSE : Adds the color name strings to the colors combobox.
+ *
+ * ASSUMES : cmb4 - ID of colors combobox
+ *
+ * COMMENTS : The color rectangles are drawn later in response to
+ * WM_DRAWITEM messages
+ *
+ ****************************************************************************/
+void NEAR PASCAL FillColorCombo(HWND hDlg)
+{
+ int iT, item;
+ char szT[CCHCOLORNAMEMAX];
+
+ for (iT = 0; iT < CCHCOLORS; ++iT)
+ {
+ *szT = 0;
+ LoadString(hinsCur, iszBlack + iT, szT, sizeof(szT));
+ item = (int)SendDlgItemMessage(hDlg, cmb4, CB_INSERTSTRING, iT, (LONG)(LPSTR)szT);
+ if (item >= 0)
+ SendDlgItemMessage(hDlg, cmb4, CB_SETITEMDATA, item, rgbColors[iT]);
+ }
+}
+
+/****************************************************************************
+ *
+ * ComputeSampleTextRectangle
+ *
+ * PURPOSE : Determines the bounding rectangle for the text preview area,
+ * and fills in rcText.
+ *
+ * ASSUMES : stc5 - ID preview text rectangle
+ *
+ * COMMENTS : The coordinates are calculated w.r.t the dialog.
+ *
+ ****************************************************************************/
+
+void NEAR PASCAL ComputeSampleTextRectangle(HWND hDlg)
+{
+ GetWindowRect(GetDlgItem (hDlg, stc5), &rcText);
+ ScreenToClient(hDlg, (LPPOINT)&rcText.left);
+ ScreenToClient(hDlg, (LPPOINT)&rcText.right);
+}
+
+
+BOOL NEAR PASCAL DrawSizeComboItem(LPDRAWITEMSTRUCT lpdis)
+{
+ HDC hDC;
+ DWORD rgbBack, rgbText;
+ char szFace[10];
+
+ hDC = lpdis->hDC;
+
+ if (lpdis->itemState & ODS_SELECTED) {
+ rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
+ rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ } else {
+ rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+ rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ SendMessage(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, (LONG)(LPSTR)szFace);
+
+ ExtTextOut(hDC, lpdis->rcItem.left + GetSystemMetrics(SM_CXBORDER), lpdis->rcItem.top, ETO_OPAQUE, &lpdis->rcItem, szFace, lstrlen(szFace), NULL);
+
+ SetTextColor(hDC, rgbText);
+ SetBkColor(hDC, rgbBack);
+
+ return TRUE;
+}
+
+
+BOOL NEAR PASCAL DrawFamilyComboItem(LPDRAWITEMSTRUCT lpdis)
+{
+ HDC hDC, hdcMem;
+ DWORD rgbBack, rgbText;
+ char szFace[LF_FACESIZE + 10];
+ HBITMAP hOld;
+ int dy, x;
+
+ hDC = lpdis->hDC;
+
+ if (lpdis->itemState & ODS_SELECTED) {
+ rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
+ rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ } else {
+ rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+ rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ // wsprintf(szFace, "%4.4X", LOWORD(lpdis->itemData));
+
+ SendMessage(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, (LONG)(LPSTR)szFace);
+ ExtTextOut(hDC, lpdis->rcItem.left + DX_BITMAP, lpdis->rcItem.top, ETO_OPAQUE, &lpdis->rcItem, szFace, lstrlen(szFace), NULL);
+
+ hdcMem = CreateCompatibleDC(hDC);
+ if (hdcMem) {
+ if (hbmFont) {
+ hOld = SelectObject(hdcMem, hbmFont);
+
+ if (lpdis->itemData & TRUETYPE_FONTTYPE)
+ x = 0;
+ else if ((lpdis->itemData & (PRINTER_FONTTYPE | DEVICE_FONTTYPE)) == (PRINTER_FONTTYPE | DEVICE_FONTTYPE))
+ // this may be a screen and printer font but
+ // we will call it a printer font here
+ x = DX_BITMAP;
+ else
+ goto SkipBlt;
+
+ dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_BITMAP) / 2;
+
+ BitBlt(hDC, lpdis->rcItem.left, lpdis->rcItem.top + dy, DX_BITMAP, DY_BITMAP, hdcMem,
+ x, lpdis->itemState & ODS_SELECTED ? DY_BITMAP : 0, SRCCOPY);
+
+SkipBlt:
+ SelectObject(hdcMem, hOld);
+ }
+ DeleteDC(hdcMem);
+ }
+
+ SetTextColor(hDC, rgbText);
+ SetBkColor(hDC, rgbBack);
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+ *
+ * DrawColorComboItem
+ *
+ * PURPOSE : Called by main dialog fn. in response to a WM_DRAWITEM
+ * message, computes and draws the color combo items.
+ *
+ * RETURNS : TRUE if succesful, FALSE otherwise.
+ *
+ * COMMENTS : All color name strings have already loaded and filled into
+ * combobox.
+ *
+ ****************************************************************************/
+
+BOOL NEAR PASCAL DrawColorComboItem(LPDRAWITEMSTRUCT lpdis)
+{
+ HDC hDC;
+ HBRUSH hbr;
+ WORD dx, dy;
+ RECT rc;
+ char szColor[CCHCOLORNAMEMAX];
+ DWORD rgbBack, rgbText, dw;
+
+ hDC = lpdis->hDC;
+
+ if (lpdis->itemState & ODS_SELECTED) {
+ rgbBack = SetBkColor(hDC, GetSysColor (COLOR_HIGHLIGHT));
+ rgbText = SetTextColor(hDC, GetSysColor (COLOR_HIGHLIGHTTEXT));
+ } else {
+ rgbBack = SetBkColor(hDC, GetSysColor (COLOR_WINDOW));
+ rgbText = SetTextColor(hDC, GetSysColor (COLOR_WINDOWTEXT));
+ }
+ ExtTextOut(hDC, lpdis->rcItem.left, lpdis->rcItem.top, ETO_OPAQUE, &lpdis->rcItem, NULL, 0, NULL);
+
+ /* compute coordinates of color rectangle and draw it */
+ dx = GetSystemMetrics(SM_CXBORDER);
+ dy = GetSystemMetrics(SM_CYBORDER);
+ rc.top = lpdis->rcItem.top + dy;
+ rc.bottom = lpdis->rcItem.bottom - dy;
+ rc.left = lpdis->rcItem.left + dx;
+ rc.right = rc.left + 2 * (rc.bottom - rc.top);
+
+ if (wWinVer < 0x030A)
+ dw = SendMessage(lpdis->hwndItem, CB_GETITEMDATA, lpdis->itemID, 0L);
+ else
+ dw = lpdis->itemData;
+
+ hbr = CreateSolidBrush(dw);
+ if (!hbr)
+ return FALSE;
+
+ hbr = SelectObject (hDC, hbr);
+ Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
+ DeleteObject(SelectObject(hDC, hbr));
+
+ /* shift the color text right by the width of the color rectangle */
+ *szColor = 0;
+ SendMessage(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, (LONG)(LPSTR)szColor);
+ TextOut(hDC, 2 * dx + rc.right, lpdis->rcItem.top, szColor, lstrlen(szColor));
+
+ SetTextColor(hDC, rgbText);
+ SetBkColor(hDC, rgbBack);
+
+ return TRUE;
+}
+
+/****************************************************************************
+ *
+ * DrawSampleText
+ *
+ * PURPOSE : To display the sample text with the given attributes
+ *
+ * COMMENTS : Assumes rcText holds the coordinates of the area within the
+ * frame (relative to dialog client) which text should be drawn in
+ *
+ ****************************************************************************/
+
+void NEAR PASCAL DrawSampleText(HWND hDlg, LPCHOOSEFONT lpcf, HDC hDC)
+{
+ DWORD rgbText;
+ DWORD rgbBack;
+ int iItem;
+ HFONT hFont, hTemp;
+ char szSample[50];
+ LOGFONT lf;
+ int len, x, y, dx, dy;
+ TEXTMETRIC tm;
+ BOOL bCompleteFont;
+
+ bCompleteFont = FillInFont(hDlg, lpcf, &lf, FALSE);
+
+ hFont = CreateFontIndirect(&lf);
+ if (!hFont)
+ return;
+
+ hTemp = SelectObject(hDC, hFont);
+
+ rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
+
+ if (lpcf->Flags & CF_EFFECTS) {
+ iItem = (int)SendDlgItemMessage(hDlg, cmb4, CB_GETCURSEL, 0, 0L);
+ if (iItem != CB_ERR)
+ rgbText = SendDlgItemMessage(hDlg, cmb4, CB_GETITEMDATA, iItem, 0L);
+ else
+ goto GetWindowTextColor;
+ }
+ else
+ {
+GetWindowTextColor:
+ rgbText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+
+ rgbText = SetTextColor(hDC, rgbText);
+
+ if (bCompleteFont)
+ GetDlgItemText(hDlg, stc5, szSample, sizeof(szSample));
+ else
+ szSample[0] = 0;
+
+ GetTextMetrics(hDC, &tm);
+
+ len = lstrlen(szSample);
+ dx = (int)GetTextExtent(hDC, szSample, len);
+ dy = tm.tmAscent - tm.tmInternalLeading;
+
+ if ((dx >= (rcText.right - rcText.left)) || (dx <= 0))
+ x = rcText.left;
+ else
+ x = rcText.left + ((rcText.right - rcText.left) - (int)dx) / 2;
+
+ y = min(rcText.bottom, rcText.bottom - ((rcText.bottom - rcText.top) - (int)dy) / 2);
+
+ ExtTextOut(hDC, x, y - (tm.tmAscent), ETO_OPAQUE | ETO_CLIPPED, &rcText, szSample, len, NULL);
+
+ SetBkColor(hDC, rgbBack);
+ SetTextColor(hDC, rgbText);
+
+ if (hTemp)
+ DeleteObject(SelectObject(hDC, hTemp));
+}
+
+
+// fill in the LOGFONT strucuture based on the current selection
+//
+// in:
+// bSetBits if TRUE the Flags fields in the lpcf are set to
+// indicate what parts (face, style, size) are not
+// selected
+// out:
+// lplf filled in LOGFONT
+//
+// returns:
+// TRUE if there was an unambigious selection
+// (the LOGFONT is filled as per the enumeration in)
+// FALSE there was not a complete selection
+// (fields set in the LOGFONT with default values)
+
+
+BOOL NEAR PASCAL FillInFont(HWND hDlg, LPCHOOSEFONT lpcf, LPLOGFONT lplf, BOOL bSetBits)
+{
+ HDC hdc;
+ int iSel, id, pts;
+ DWORD dw;
+ WORD nFontType;
+ PLOGFONT plf;
+ char szStyle[LF_FACESIZE];
+ char szMessage[128];
+ BOOL bFontComplete = TRUE;
+
+ InitLF(lplf);
+
+ GetDlgItemText(hDlg, cmb1, lplf->lfFaceName, sizeof(lplf->lfFaceName));
+ if (CBFindString(GetDlgItem(hDlg, cmb1), lplf->lfFaceName) >= 0) {
+ if (bSetBits)
+ lpcf->Flags &= ~CF_NOFACESEL;
+ } else {
+ bFontComplete = FALSE;
+ if (bSetBits)
+ lpcf->Flags |= CF_NOFACESEL;
+ }
+
+ iSel = CBGetTextAndData(GetDlgItem(hDlg, cmb2), szStyle, sizeof(szStyle), &dw);
+ if (iSel >= 0) {
+ nFontType = HIWORD(dw);
+ plf = (PLOGFONT)LOWORD(dw);
+ *lplf = *plf; // copy the LOGFONT
+ lplf->lfWidth = 0; // 1:1 x-y scaling
+ if (bSetBits)
+ lpcf->Flags &= ~CF_NOSTYLESEL;
+ } else {
+ bFontComplete = FALSE;
+ if (bSetBits)
+ lpcf->Flags |= CF_NOSTYLESEL;
+ nFontType = 0;
+ }
+
+ // now make sure the size is in range; pts will be 0 if not
+ GetPointSizeInRange(hDlg, lpcf, &pts, 0);
+
+ hdc = GetDC(NULL);
+ if (pts) {
+ lplf->lfHeight = -MulDiv(pts, GetDeviceCaps(hdc, LOGPIXELSY), POINTS_PER_INCH);
+ if (bSetBits)
+ lpcf->Flags &= ~CF_NOSIZESEL;
+ } else {
+ lplf->lfHeight = -MulDiv(DEF_POINT_SIZE, GetDeviceCaps(hdc, LOGPIXELSY), POINTS_PER_INCH);
+ bFontComplete = FALSE;
+ if (bSetBits)
+ lpcf->Flags |= CF_NOSIZESEL;
+ }
+ ReleaseDC(NULL, hdc);
+
+ // and the attributes we control
+
+ lplf->lfStrikeOut = (BYTE)IsDlgButtonChecked(hDlg, chx1);
+ lplf->lfUnderline = (BYTE)IsDlgButtonChecked(hDlg, chx2);
+
+ if (nFontType != nLastFontType) {
+
+ if (lpcf->Flags & CF_PRINTERFONTS) {
+ if (nFontType & SIMULATED_FONTTYPE) {
+ id = iszSynth;
+ } else if (nFontType & TRUETYPE_FONTTYPE) {
+ id = iszTrueType;
+ } else if ((nFontType & (PRINTER_FONTTYPE | SCREEN_FONTTYPE)) == SCREEN_FONTTYPE) {
+ id = iszGDIFont;
+ } else if ((nFontType & (PRINTER_FONTTYPE | DEVICE_FONTTYPE)) == (PRINTER_FONTTYPE | DEVICE_FONTTYPE)) {
+ // may be both screen and printer (ATM) but we'll just
+ // call this a printer font
+ id = iszPrinterFont;
+ } else {
+ szMessage[0] = 0;
+ goto SetText;
+ }
+ LoadString(hinsCur, id, szMessage, sizeof(szMessage));
+SetText:
+ SetDlgItemText(hDlg, stc6, szMessage);
+ }
+ }
+ nLastFontType = nFontType;
+
+ return bFontComplete;
+
+}
+
+/****************************************************************************
+ *
+ * TermFont
+ *
+ * PURPOSE : To release any data required by functions in this module
+ * Called from WEP on exit from DLL
+ *
+ ****************************************************************************/
+void FAR PASCAL TermFont(void)
+{
+ if (hbmFont)
+ DeleteObject(hbmFont);
+}
+
+/****************************************************************************
+ *
+ * GetPointString
+ *
+ * PURPOSE : Converts font height into a string of digits repr. pointsize
+ *
+ * RETURNS : size in points and fills in buffer with string
+ *
+ ****************************************************************************/
+int NEAR PASCAL GetPointString(LPSTR buf, HDC hDC, int height)
+{
+ int pts;
+
+ pts = MulDiv((height < 0) ? -height : height, 72, GetDeviceCaps(hDC, LOGPIXELSY));
+ wsprintf(buf, szPtFormat, pts);
+ return pts;
+}
+
+
+//
+// BOOL FAR PASCAL LoadBitmaps()
+//
+// this routine loads DIB bitmaps, and "fixes up" their color tables
+// so that we get the desired result for the device we are on.
+//
+// this routine requires:
+// the DIB is a 16 color DIB authored with the standard windows colors
+// bright blue (00 00 FF) is converted to the background color!
+// light grey (C0 C0 C0) is replaced with the button face color
+// dark grey (80 80 80) is replaced with the button shadow color
+//
+// this means you can't have any of these colors in your bitmap
+//
+
+#define BACKGROUND 0x000000FF // bright blue
+#define BACKGROUNDSEL 0x00FF00FF // bright blue
+#define BUTTONFACE 0x00C0C0C0 // bright grey
+#define BUTTONSHADOW 0x00808080 // dark grey
+
+DWORD NEAR PASCAL FlipColor(DWORD rgb)
+{
+ return RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
+}
+
+
+HBITMAP NEAR PASCAL LoadBitmaps(int id)
+{
+ HDC hdc;
+ HANDLE h;
+ DWORD FAR *p;
+ LPSTR lpBits;
+ HANDLE hRes;
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ int numcolors;
+ DWORD rgbSelected;
+ DWORD rgbUnselected;
+ HBITMAP hbm;
+
+ rgbSelected = FlipColor(GetSysColor(COLOR_HIGHLIGHT));
+ rgbUnselected = FlipColor(GetSysColor(COLOR_WINDOW));
+
+ h = FindResource(hinsCur, MAKEINTRESOURCE(id), RT_BITMAP);
+ hRes = LoadResource(hinsCur, h);
+
+ /* Lock the bitmap and get a pointer to the color table. */
+ lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
+
+ if (!lpBitmapInfo)
+ return FALSE;
+
+ p = (DWORD FAR *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize);
+
+ /* Search for the Solid Blue entry and replace it with the current
+ * background RGB.
+ */
+ numcolors = 16;
+
+ while (numcolors-- > 0) {
+ if (*p == BACKGROUND)
+ *p = rgbUnselected;
+ else if (*p == BACKGROUNDSEL)
+ *p = rgbSelected;
+#if 0
+ else if (*p == BUTTONFACE)
+ *p = FlipColor(GetSysColor(COLOR_BTNFACE));
+ else if (*p == BUTTONSHADOW)
+ *p = FlipColor(GetSysColor(COLOR_BTNSHADOW));
+#endif
+
+ p++;
+ }
+ UnlockResource(hRes);
+
+ /* Now create the DIB. */
+ lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
+
+ /* First skip over the header structure */
+ lpBits = (LPSTR)(lpBitmapInfo + 1);
+
+ /* Skip the color table entries, if any */
+ lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
+
+ /* Create a color bitmap compatible with the display device */
+ hdc = GetDC(NULL);
+ hbm = CreateDIBitmap(hdc, lpBitmapInfo, (DWORD)CBM_INIT, lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS);
+ ReleaseDC(NULL, hdc);
+
+ MySetObjectOwner(hbm);
+
+ GlobalUnlock(hRes);
+ FreeResource(hRes);
+
+ return hbm;
+}
+
+#if 0
+#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+
+int NEAR PASCAL atoi(LPSTR sz)
+{
+ int n = 0;
+ BOOL bNeg = FALSE;
+
+ if (*sz == '-') {
+ bNeg = TRUE;
+ sz++;
+ }
+
+ while (ISDIGIT(*sz)) {
+ n *= 10;
+ n += *sz - '0';
+ sz++;
+ }
+ return bNeg ? -n : n;
+}
+#endif
+
diff --git a/private/mvdm/wow16/commdlg/font.h b/private/mvdm/wow16/commdlg/font.h
new file mode 100644
index 000000000..3f490cc27
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/font.h
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ *
+ * MODULE : Font.h
+ *
+ * DESCRIPTION : Include file for constants and typedefs related only to the
+ * the font selection routines.
+ *
+ * HISTORY : 11/13/90 - L.Raman
+ *
+ * Copyright (c) Microsoft Corporation, 1990-
+ *
+ *******************************************************************************/
+
+/* struct. passed in to the facename and pt. size enum. functions */
+#define CCHCOLORNAMEMAX 16 /* max. length of color name text */
+#define CCHCOLORS 16 /* max. no of pure colors in color combo */
+
+#define POINTS_PER_INCH 72
+#define FFMASK 0xF0 /* pitch and family mask */
+#define CCHSTDSTRING 12 /* max. length of sample text string */
+
+#define FONTPROP (LPSTR)0xA000L
+
+extern HANDLE hinsCur; /* DLL's data segment */
+
+
+
diff --git a/private/mvdm/wow16/commdlg/isz.h b/private/mvdm/wow16/commdlg/isz.h
new file mode 100644
index 000000000..e33d20f3d
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/isz.h
@@ -0,0 +1,175 @@
+//---------------------------------------------------------------------------
+// Isz.h : String resource IDs for dialogs
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+ // 0x0000 - 0x00ff Error codes
+
+// MESSAGES: 0x0100 to 0x01ff
+#define iszOverwriteCaption 0x0100
+#define iszOverwriteQuestion 0x0101
+#define iszDefExitCaption 0x0102
+#define iszDefExitText 0x0103
+
+#define iszDefaultPitch 0x0104
+#define iszFixedPitch 0x0105
+#define iszVariablePitch 0x0106
+#define iszAnsiCharset 0x0107
+#define iszOemCharset 0x0108
+#define iszSymbolCharset 0x0109
+#define iszDecorativeFamily 0x010a
+#define iszUnknownFamily 0x010b
+#define iszModernFamily 0x010c
+#define iszRomanFamily 0x010d
+#define iszScriptFamily 0x010e
+#define iszSwissFamily 0x010f
+
+#define iszSystemFont 0x0110
+#define iszHelvFont 0x0111
+#define iszCourierFont 0x0112
+#define iszTmsRmnFont 0x0113
+#define iszSymbolFont 0x0114
+#define iszRomanFont 0x0115
+#define iszScriptFont 0x0116
+#define iszModernFont 0x0117
+#define iszLastFont iszModernFont
+
+#define iszFileOpenTitle 0x0180
+#define iszFileSaveTitle 0x0181
+#define iszSaveFileAsType 0x0182
+#define iszDriveDoesNotExist 0x0183
+#define iszNoDiskInDrive 0x0184
+#define iszWrongDiskInDrive 0x0185
+#define iszUnformatedDisk 0x0186
+#define iszFileNotFound 0x0187
+#define iszPathNotFound 0x0188
+#define iszInvalidFileName 0x0189
+#define iszSharingViolation 0x018A
+#define iszAccessDenied 0x018B
+#define iszReadOnly 0x018C
+#define iszInt24Error 0x018D
+#define iszPortName 0x018E
+#define iszWriteProtection 0x018F
+#define iszDiskFull 0x0190
+#define iszNoFileHandles 0x0191
+#define iszCreatePrompt 0x0192
+#define iszCreateNoModify 0x0193
+#define iszSelectDriveTrouble 0x0194
+
+// RESOURCES: 0x0200 to 0x020f
+ // Menus: 0x0200 to 0x020f
+ // Icons: 0x0210 to 0x021f
+ // Cursors: 0x0220 to 0x022f
+ // Accelerators: 0x0230 to 0x023f
+ // Bitmaps: 0x0240 to 0x024f
+ // Private: 0x0250 to 0x025f
+
+#define icoPortrait 528
+#define icoLandscape 529
+
+#define bmpDirDrive 576
+#define bmpCrossHair 584
+#define bmpCurLum 585
+#define bmpHls 586
+
+#define rcdataDefColors 592
+
+
+// DIALOGS: 0x0300 to 0x03ff
+#define dlgFileOpen 0x0300
+#define dlgFileSave 0x0301
+#define dlgExitChanges 0x0302
+#define dlgChooseColor 0x0303
+#define dlgFindText 0x0304
+#define dlgReplaceText 0x0305
+#define dlgFormatChar 0x0306
+#define dlgFontInfo 0x0307
+#define dlgPrintDlg 0x0308
+#define dlgPrintSetupDlg 0x0309
+#define dlgMultiFileOpen 0x030a
+
+
+// MISC: 0x0400 to 0x04ff
+#define BMLEFT 30
+#define BMUP 31
+#define BMRIGHT 32
+#define BMDOWN 33
+#define BMLEFTI 34
+#define BMUPI 35
+#define BMRIGHTI 36
+#define BMDOWNI 37
+#define BMFONT 38
+
+#define iszSampleString 0x040c /* sample text for Font picker */
+#define iszClose 0x040d /* "Close" text for find/replace */
+
+
+#define iszBlack 0x0410
+#define iszDkRed 0x0411
+#define iszDkGreen 0x0412
+#define iszDkYellow 0x0413
+#define iszDkBlue 0x0414
+#define iszDkPurple 0x0415
+#define iszDkAqua 0x0416
+#define iszDkGrey 0x0417
+#define iszLtGrey 0x0418
+#define iszLtRed 0x0419
+#define iszLtGreen 0x041a
+#define iszLtYellow 0x041b
+#define iszLtBlue 0x041c
+#define iszLtPurple 0x041d
+#define iszLtAqua 0x041e
+#define iszWhite 0x041f
+
+#define iszAtomData 0x0420
+
+#define iszHighPrnQ 0x0430
+#define iszMedPrnQ 0x0431
+#define iszLowPrnQ 0x0432
+#define iszDraftPrnQ 0x0433
+
+#define iszPrinter 0x0440
+#define iszSysPrn 0x0441
+#define iszPrnOnPort 0x0442
+#define iszExtDev 0x0443
+#define iszDevMode 0x0444
+#define iszDevCap 0x0445
+#define iszDefCurOn 0x0446
+#define iszLocal 0x0447
+#define iszPrintSetup 0x0448
+
+#define iszSizeNumber 0x44A
+#define iszSizeRange 0x44B
+#define iszSynth 0x44C
+#define iszTrueType 0x44D
+#define iszPrinterFont 0x44E
+#define iszGDIFont 0x44F
+
+#define iszFromBelowMin 0x450
+#define iszFromAboveMax 0x451
+#define iszToBelowMin 0x452
+#define iszToAboveMax 0x453
+#define iszFromInvalidChar 0x454
+#define iszToInvalidChar 0x455
+#define iszFromAndToEmpty 0x456
+#define iszCopiesEmpty 0x457
+#define iszCopiesInvalidChar 0x458
+#define iszCopiesZero 0x459
+#define iszNoPrnsInstalled 0x45A
+#define iszPrnDrvNotFound 0x45B
+
+#define iszPaperSizeIndex 0x0480 // and up are used
+
+#define iszNoFontsTitle 0x0500
+#define iszNoFontsMsg 0x0501
+#define iszNoFaceSel 0x0502
+#define iszNoStyleSel 0x0503
+#define iszRegular 0x0504
+#define iszBold 0x0505
+#define iszItalic 0x0506
+#define iszBoldItalic 0x0507
+
+/* CCHSTYLE is the max allowed length of iszRegular to iszBoldItalic strings */
+#define CCHSTYLE 32
+
diff --git a/private/mvdm/wow16/commdlg/landscap.ico b/private/mvdm/wow16/commdlg/landscap.ico
new file mode 100644
index 000000000..f40d99c75
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/landscap.ico
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/left.bmp b/private/mvdm/wow16/commdlg/left.bmp
new file mode 100644
index 000000000..b5d572860
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/left.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/lefti.bmp b/private/mvdm/wow16/commdlg/lefti.bmp
new file mode 100644
index 000000000..1152776f7
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/lefti.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/makefile b/private/mvdm/wow16/commdlg/makefile
new file mode 100644
index 000000000..e6d423007
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/makefile
@@ -0,0 +1,156 @@
+
+WINLIB=..\lib
+INCLUDE=-I..\inc -I..\..\inc
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+CDEBUG=-Odi -Zped
+LDEBUG=/LI/MAP
+MDEBUG=-Zd
+!else
+CDEBUG=-Oas -Zpe
+!endif
+
+CC=cl16 $(INCLUDE)
+LINK=link16
+
+MASM=masm $(INCLUDE)
+LIBRARIAN=lib16
+RCFLAGS=$(INCLUDE)
+
+# with stack probes, medium model (need to set 'memM = 1' before
+# including normal cmacros in .A files as well, and link to m*.lib)
+#STDOPTS=-W4 -u -c -AMnw -PLM -G2w -Od -Zped
+
+# without stack probes, small model (normal build)
+STDOPTS=-W4 -u -c -Asnw -PLM -G2sw
+
+BLD=.
+
+#Need for international version stamping
+!IFDEF INTL
+
+.rc.res:
+ rc16 $(RCFLAGS) -DINTL -r $*
+!ELSE
+.rc.res:
+ rc16 $(RCFLAGS) -r $*
+
+!ENDIF
+
+.c.obj:
+ $(CC) $(STDOPTS) $(CDEBUG) $*.c
+
+.asm.obj:
+ $(MASM) $(MDEBUG) $*.asm;
+
+
+#international mods
+#note INTL_SRC, and LANG are external macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=$(INTL_SRC)\$(LANG)\sdk\commdlg
+EXE_DIR=$(INTL_EXE)
+!ENDIF
+
+!IFNDEF LANG
+all: $(BLD)\commdlg.dll
+!ELSE
+all: $(BLD)\commdlg.$(LANG)
+!ENDIF
+
+
+clean: cleanup all
+
+cleanup:
+ del *.res
+ del *.rc
+ del *.rcv
+ del *.dlg
+ del sz.src
+ del *.obj
+ -del stripped.def
+ del *.sym
+ del *.map
+ del *.dll
+ del *.lib
+
+sz.src: $(RES_DIR)\sz.src
+ copy $(RES_DIR)\sz.src
+
+commdlg.rc: $(RES_DIR)\commdlg.rc
+ copy $(RES_DIR)\commdlg.rc
+
+commdlg.rcv: $(RES_DIR)\commdlg.rcv
+ copy $(RES_DIR)\commdlg.rcv
+
+commdlg.dlg: $(RES_DIR)\commdlg.dlg
+ copy $(RES_DIR)\commdlg.dlg
+
+fileopen.dlg: $(RES_DIR)\fileopen.dlg
+ copy $(RES_DIR)\fileopen.dlg
+
+font.dlg: $(RES_DIR)\font.dlg
+ copy $(RES_DIR)\font.dlg
+
+color.dlg: $(RES_DIR)\color.dlg
+ copy $(RES_DIR)\color.dlg
+
+findtext.dlg: $(RES_DIR)\findtext.dlg
+ copy $(RES_DIR)\findtext.dlg
+
+prnsetup.dlg: $(RES_DIR)\prnsetup.dlg
+ copy $(RES_DIR)\prnsetup.dlg
+
+commdlg.res: commdlg.rc fileopen.dlg prnsetup.dlg \
+ font.dlg findtext.dlg color.dlg colordlg.h sz.src commdlg.rcv \
+ ..\inc\common.ver
+
+$(BLD)\commdlg.obj: commdlg.asm ..\..\inc\wowcmdlg.inc
+ $(MASM) commdlg.asm $@;
+
+$(BLD)\start.obj: start.asm
+ $(MASM) start.asm $@;
+
+$(BLD)\dlgs.obj: dlgs.c xlib.h dlgs.h
+ $(CC) $(STDOPTS) -Fo$@ -NT _DLGS dlgs.c
+
+$(BLD)\parse.obj: parse.c parse.h dlgs.h
+ $(CC) $(STDOPTS) -Fo$@ -NT _FILEOPEN parse.c
+
+$(BLD)\font.obj: font.c xlib.h dlgs.h
+ $(CC) $(STDOPTS) -Fo$@ -NT _FONT font.c
+
+!IFDEF LANG
+$(BLD)\commdlg.$(LANG): commdlg.res
+ copy $(INTL_EXE)\commdlg.dll commdlg.$(LANG)
+ rc16 -30 -t commdlg.res commdlg.$(LANG)
+!ENDIF
+
+
+$(BLD)\commdlg.dll: $(BLD)\commdlg.obj \
+ $(BLD)\dlgs.obj \
+ $(BLD)\start.obj \
+ $(BLD)\parse.obj \
+ $(BLD)\font.obj \
+ commdlg.res $(BLD) \
+ $(BLD)\commdlg.def
+ $(LINK) @<<
+ start commdlg parse font dlgs
+ commdlg.dll/align:16/map
+ commdlg.map $(LDEBUG)
+ $(WINLIB)\libw $(WINLIB)\libh $(WINLIB)\snocrtd /NODEFAULT
+ commdlg.def
+<<
+ mapsym commdlg
+ mkpublic commdlg.def stripped.def
+ implib commdlg.lib stripped.def
+ rc16 -30 -t commdlg.res commdlg.dll
+ binplace commdlg.dll commdlg.map commdlg.sym
diff --git a/private/mvdm/wow16/commdlg/messages/usa/color.dlg b/private/mvdm/wow16/commdlg/messages/usa/color.dlg
new file mode 100644
index 000000000..b78101e36
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/color.dlg
@@ -0,0 +1,61 @@
+#include "colordlg.h"
+
+ChooseColor DIALOG LOADONCALL MOVEABLE DISCARDABLE 2, 0, 298, 184
+CAPTION "Color"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_POPUP | WS_SYSMENU
+FONT 8 "Helv"
+BEGIN
+ LTEXT "&Basic Colors:", -1, 4, 4, 140, 9
+
+ CONTROL "", COLOR_BOX1, "static", SS_SIMPLE | WS_CHILD | WS_TABSTOP | WS_GROUP, 4, 14, 140, 86
+
+ LTEXT "&Custom Colors:", -1, 4, 106, 140, 9
+
+ CONTROL "", COLOR_CUSTOM1, "static", SS_SIMPLE | WS_CHILD | WS_TABSTOP | WS_GROUP, 4, 116, 140, 28
+
+ PUSHBUTTON "&Define Custom Colors..." COLOR_MIX, 4, 150, 140, 14, WS_TABSTOP | WS_GROUP
+
+ DEFPUSHBUTTON "OK", IDOK, 4, 166, 44, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 52, 166, 44, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Help", pshHelp, 100, 166, 44, 14, WS_GROUP | WS_TABSTOP
+
+ CONTROL "", COLOR_RAINBOW, "static", SS_BLACKFRAME | WS_CHILD, 152, 4, 118, 116
+
+ CONTROL "", COLOR_LUMSCROLL, "static", SS_SIMPLE | WS_CHILD, 280, 4, 8, 116
+
+ CONTROL "", COLOR_CURRENT, "static", SS_BLACKFRAME | WS_CHILD, 152, 124, 40, 26
+
+ PUSHBUTTON "&o", COLOR_SOLID, 300, 200, 4, 14, WS_GROUP
+
+ RTEXT "Color|", -1, 152, 151, 20, 9
+
+ LTEXT "S&olid", -1, 172, 151, 20, 9
+
+
+ RTEXT "&Hue:", COLOR_HUEACCEL, 194, 126, 20, 9
+
+ EDITTEXT, COLOR_HUE, 216, 124, 18, 12, WS_GROUP | WS_TABSTOP
+
+ RTEXT "&Sat:", COLOR_SATACCEL, 194, 140, 20, 9
+
+ EDITTEXT, COLOR_SAT, 216, 138, 18, 12, WS_GROUP | WS_TABSTOP
+
+ RTEXT "&Lum:", COLOR_LUMACCEL, 194, 154, 20, 9
+
+ EDITTEXT, COLOR_LUM, 216, 152, 18, 12, WS_GROUP | WS_TABSTOP
+
+ RTEXT "&Red:", COLOR_REDACCEL, 243, 126, 24, 9
+
+ EDITTEXT, COLOR_RED, 269, 124, 18, 12, WS_GROUP | WS_TABSTOP
+
+ RTEXT "&Green:", COLOR_GREENACCEL, 243, 140, 24, 9
+
+ EDITTEXT, COLOR_GREEN, 269, 138, 18, 12, WS_GROUP | WS_TABSTOP
+
+ RTEXT "Bl&ue:", COLOR_BLUEACCEL, 243, 154, 24, 9
+
+ EDITTEXT, COLOR_BLUE, 269, 152, 18, 12, WS_GROUP | WS_TABSTOP
+
+ PUSHBUTTON "&Add to Custom Colors", COLOR_ADD, 152, 166, 142, 14, WS_GROUP | WS_TABSTOP
+
+END
diff --git a/private/mvdm/wow16/commdlg/messages/usa/commdlg.rc b/private/mvdm/wow16/commdlg/messages/usa/commdlg.rc
new file mode 100644
index 000000000..ec3074dcc
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/commdlg.rc
@@ -0,0 +1,53 @@
+//---------------------------------------------------------------------------
+// dlgs.rc : Dialogs resource descriptions
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+#define WIN31 1
+#include <windows.h>
+#include "isz.h"
+#include "dlgs.h"
+
+//----Version Stamping-------------------------------------------------------
+#include "commdlg.rcv"
+
+//----Bitmaps----------------------------------------------------------------
+bmpDirDrive BITMAP IMPURE filebmps.bmp
+bmpCrossHair BITMAP IMPURE crosshr.bmp
+
+BMLEFT BITMAP left.bmp
+BMLEFTI BITMAP lefti.bmp
+BMRIGHT BITMAP right.bmp
+BMRIGHTI BITMAP righti.bmp
+BMUP BITMAP up.bmp
+BMUPI BITMAP upi.bmp
+BMDOWN BITMAP down.bmp
+BMDOWNI BITMAP downi.bmp
+
+//----Cursors----------------------------------------------------------------
+
+//----Fonts------------------------------------------------------------------
+
+//----Icons------------------------------------------------------------------
+icoPortrait ICON portrait.ico
+icoLandscape ICON landscap.ico
+
+//----Menus------------------------------------------------------------------
+
+//----Accelerators-----------------------------------------------------------
+
+//----Dialogs----------------------------------------------------------------
+
+#include "FileOpen.dlg"
+#include "PrnSetup.dlg"
+#include "FindText.dlg"
+#include "Color.dlg"
+#include "Font.dlg"
+
+//----Strings----------------------------------------------------------------
+
+STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE
+BEGIN
+#include "sz.src"
+END
diff --git a/private/mvdm/wow16/commdlg/messages/usa/commdlg.rcv b/private/mvdm/wow16/commdlg/messages/usa/commdlg.rcv
new file mode 100644
index 000000000..223eb3aab
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/commdlg.rcv
@@ -0,0 +1,24 @@
+/********************************************************************/
+/* */
+/* COMMDLG.RCV */
+/* */
+/* This RC fragment shows how to define version information in an */
+/* internal RC file */
+/* */
+/* It relies upon both the public VER.H and private VERSION.H */
+/* */
+/********************************************************************/
+
+#include <version.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Common Dialogs libraries\0"
+#define VER_INTERNALNAME_STR "COMMDLG\0"
+#define VER_ORIGINALFILENAME_STR "COMMDLG.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/commdlg/messages/usa/fileopen.dlg b/private/mvdm/wow16/commdlg/messages/usa/fileopen.dlg
new file mode 100644
index 000000000..7c05001c4
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/fileopen.dlg
@@ -0,0 +1,94 @@
+//---------------------------------------------------------------------------
+// FileOpen.dlg : File Open and Save As dialog descriptions
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+FILEOPENORD DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 24, 264, 134
+CAPTION "Open"
+STYLE WS_CAPTION | WS_SYSMENU | WS_POPUP | DS_MODALFRAME
+FONT 8, "Helv"
+BEGIN
+ LTEXT "File &Name:", stc3, 6, 6, 76, 9
+ CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | ES_OEMCONVERT,
+ 6, 16, 90, 12
+ CONTROL "", lst1, "listbox",
+ LBS_SORT | LBS_HASSTRINGS | LBS_NOTIFY | LBS_DISABLENOSCROLL
+ | WS_VSCROLL | WS_CHILD | WS_BORDER | WS_TABSTOP
+ | LBS_OWNERDRAWFIXED,
+ 6, 32, 90, 68
+
+ LTEXT "&Directories:", -1, 110, 6, 92, 9
+ LTEXT "", stc1, 110, 18, 92, 9, SS_NOPREFIX
+ CONTROL "", lst2, "listbox",
+ LBS_SORT | LBS_HASSTRINGS | LBS_NOTIFY | LBS_DISABLENOSCROLL
+ | WS_VSCROLL | WS_CHILD | WS_BORDER | WS_TABSTOP
+ | LBS_OWNERDRAWFIXED,
+ 110, 32, 92, 68
+
+ LTEXT "List Files of &Type:", stc2, 6, 104, 90, 9
+ CONTROL "", cmb1, "combobox", CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
+ WS_BORDER | WS_VSCROLL | WS_TABSTOP | WS_CHILD,
+ 6, 114, 90, 36
+
+ LTEXT "Dri&ves:", stc4, 110, 104, 92, 9
+ CONTROL "", cmb2, "combobox",
+ CBS_SORT | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST
+ | WS_CHILD | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL
+ | WS_TABSTOP,
+ 110, 114, 92, 68
+
+ DEFPUSHBUTTON "OK", IDOK, 208, 6, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 50, 14, WS_GROUP
+
+ PUSHBUTTON "&Help", pshHelp, 208, 46, 50, 14, WS_GROUP
+ CHECKBOX "&Read Only", chx1, 208, 68, 50, 12,
+ BS_AUTOCHECKBOX | WS_TABSTOP | WS_GROUP
+
+END
+
+MULTIFILEOPENORD DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 24, 264, 134
+CAPTION "Open"
+STYLE WS_CAPTION | WS_SYSMENU | WS_POPUP | DS_MODALFRAME
+FONT 8, "Helv"
+BEGIN
+ LTEXT "File &Name:", stc3, 6, 6, 76, 10
+ CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | ES_OEMCONVERT,
+ 6, 16, 90, 12
+ CONTROL "", lst1, "listbox", LBS_SORT | LBS_NOTIFY | LBS_DISABLENOSCROLL |
+ WS_VSCROLL | WS_BORDER | WS_TABSTOP | LBS_EXTENDEDSEL
+ | LBS_HASSTRINGS | LBS_OWNERDRAWFIXED,
+ 6, 32, 90, 68
+
+ LTEXT "&Directories:", -1, 110, 6, 92, 9
+ LTEXT "", stc1, 110, 16, 92, 9, SS_NOPREFIX
+ CONTROL "", lst2, "listbox",
+ LBS_SORT | LBS_HASSTRINGS | LBS_NOTIFY | LBS_DISABLENOSCROLL
+ | WS_VSCROLL | WS_CHILD | WS_BORDER | WS_TABSTOP
+ | LBS_OWNERDRAWFIXED,
+ 110, 32, 92, 68
+
+ LTEXT "List Files of &Type:", stc2, 6, 102, 90, 9
+ CONTROL "", cmb1, "combobox", CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
+ WS_BORDER | WS_VSCROLL | WS_TABSTOP | WS_CHILD,
+ 6, 112, 90, 36
+
+ LTEXT "Dri&ves:", stc4, 110, 102, 92, 9
+ CONTROL "", cmb2, "combobox",
+ CBS_SORT | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST
+ | WS_CHILD | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL
+ | WS_TABSTOP,
+ 110, 112, 92, 68
+
+ DEFPUSHBUTTON "OK", IDOK, 208, 6, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 50, 14, WS_GROUP
+
+ PUSHBUTTON "&Help", pshHelp, 208, 46, 50, 14, WS_GROUP
+ CHECKBOX "&Read Only", chx1, 208, 68, 50, 12,
+ BS_AUTOCHECKBOX | WS_TABSTOP | WS_GROUP
+
+END
diff --git a/private/mvdm/wow16/commdlg/messages/usa/findtext.dlg b/private/mvdm/wow16/commdlg/messages/usa/findtext.dlg
new file mode 100644
index 000000000..92cbbbc8e
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/findtext.dlg
@@ -0,0 +1,82 @@
+
+FINDDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE
+30, 73, 236, 62
+CAPTION "Find"
+STYLE WS_BORDER | WS_CAPTION | DS_MODALFRAME | WS_POPUP | WS_SYSMENU
+FONT 8, "Helv"
+BEGIN
+ CONTROL "Fi&nd What:", -1, "static", SS_LEFT | WS_CHILD,
+ 4, 8, 42, 8
+ CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER | WS_GROUP |
+ WS_TABSTOP | WS_CHILD | WS_BORDER,
+ 47, 7, 128, 12
+
+ CONTROL "Match &Whole Word Only", chx1, "button", BS_AUTOCHECKBOX |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 4, 26, 100, 12
+ CONTROL "Match &Case", chx2, "button", BS_AUTOCHECKBOX |
+ WS_TABSTOP | WS_CHILD,
+ 4, 42, 64, 12
+
+ CONTROL "Direction", grp1, "button", BS_GROUPBOX | WS_CHILD,
+ 107, 26, 68, 28
+ CONTROL "&Up", rad1, "button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 111, 38, 20, 12
+ CONTROL "&Down", rad2, "button", BS_AUTORADIOBUTTON | WS_TABSTOP |
+ WS_CHILD,
+ 138, 38, 30, 12
+
+ CONTROL "&Find Next", IDOK, "button", BS_DEFPUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 182, 5, 50, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 182, 23, 50, 14
+ CONTROL "&Help", pshHelp, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 182, 45, 50, 14
+END
+
+
+REPLACEDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 44, 230, 94
+CAPTION "Replace"
+STYLE WS_BORDER | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | WS_POPUP
+FONT 8, "Helv"
+BEGIN
+ CONTROL "Fi&nd What:", -1, "static", SS_LEFT | WS_CHILD,
+ 4, 9, 48, 8
+ CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 54, 7, 114, 12
+ CONTROL "Re&place With:", -1, "static", SS_LEFT | WS_CHILD,
+ 4, 26, 48, 8
+ CONTROL "", edt2, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 54, 24, 114, 12
+
+ CONTROL "Match &Whole Word Only", chx1, "button", BS_AUTOCHECKBOX |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 5, 46, 104, 12
+ CONTROL "Match &Case", chx2, "button", BS_AUTOCHECKBOX | WS_TABSTOP
+ | WS_CHILD,
+ 5, 62, 59, 12
+
+ CONTROL "&Find Next", IDOK, "button", BS_DEFPUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 4, 50, 14
+ CONTROL "&Replace", psh1, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 21, 50, 14
+ CONTROL "Replace &All", psh2, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 38, 50, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 55, 50, 14
+ CONTROL "&Help", pshHelp, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 75, 50, 14
+
+END
diff --git a/private/mvdm/wow16/commdlg/messages/usa/font.dlg b/private/mvdm/wow16/commdlg/messages/usa/font.dlg
new file mode 100644
index 000000000..12b6c4f53
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/font.dlg
@@ -0,0 +1,32 @@
+
+FORMATDLGORD31 DIALOG 13, 54, 264, 147
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Font"
+FONT 8, "Helv"
+BEGIN
+ LTEXT "&Font:", stc1, 6, 3, 40, 9
+ COMBOBOX cmb1, 6, 13, 94, 54, CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_DISABLENOSCROLL
+
+ LTEXT "Font St&yle:", stc2, 108, 3, 44, 9
+ COMBOBOX cmb2, 108, 13, 64, 54, CBS_SIMPLE | WS_VSCROLL | CBS_DISABLENOSCROLL | WS_TABSTOP
+
+ LTEXT "&Size:", stc3, 179, 3, 30, 9
+ COMBOBOX cmb3, 179, 13, 32, 54, CBS_SIMPLE | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_SORT | CBS_DISABLENOSCROLL
+
+ DEFPUSHBUTTON "OK", IDOK, 218, 6, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 218, 23, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Apply", psh3, 218, 40, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Help", pshHelp, 218, 57, 40, 14, WS_GROUP | WS_TABSTOP
+
+ GROUPBOX "Effects", grp1, 6, 72, 84, 34, WS_GROUP
+ CONTROL "Stri&keout", chx1, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 10, 82, 49, 10
+ CONTROL "&Underline", chx2, "Button", BS_AUTOCHECKBOX, 10, 94, 51, 10
+
+ LTEXT "&Color:", stc4, 6, 110, 30, 9
+ COMBOBOX cmb4, 6, 120, 84, 100, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+
+ GROUPBOX "Sample", grp2, 98, 72, 160, 49, WS_GROUP
+ CTEXT "", stc6, 98, 124, 160, 20, SS_NOPREFIX | NOT WS_GROUP
+ CTEXT "AaBbYyZz", stc5, 104, 81, 149, 37, SS_NOPREFIX | NOT WS_VISIBLE
+END
+
diff --git a/private/mvdm/wow16/commdlg/messages/usa/prnsetup.dlg b/private/mvdm/wow16/commdlg/messages/usa/prnsetup.dlg
new file mode 100644
index 000000000..e07fca934
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/prnsetup.dlg
@@ -0,0 +1,66 @@
+
+PRINTDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 52, 225, 130
+CAPTION "Print"
+STYLE WS_CAPTION | WS_SYSMENU | WS_POPUP | DS_MODALFRAME
+FONT 8, "Helv"
+BEGIN
+ LTEXT "Printer:" stc6, 4, 4, 40, 8
+ LTEXT "System Default" stc1, 44, 4, 120, 18
+ GROUPBOX "Print Range", grp1, 4, 27, 132, 67
+ RADIOBUTTON "&All" rad1, 10, 39, 76, 12, WS_TABSTOP | WS_GROUP
+ RADIOBUTTON "S&election" rad2, 10, 52, 76, 12
+ RADIOBUTTON "&Pages" rad3, 10, 65, 76, 12
+ RTEXT "&From:" stc2, 24, 80, 24, 9, WS_GROUP
+ EDITTEXT edt1, 52, 78, 26, 12, WS_TABSTOP | ES_RIGHT
+ RTEXT "&To:" stc3, 82, 80, 16, 9
+ EDITTEXT edt2, 102, 78, 26, 12, WS_TABSTOP | ES_RIGHT
+
+ LTEXT "Print &Quality:" stc4, 4, 100, 50, 9
+ COMBOBOX cmb1, 55, 98, 81, 36,
+ WS_TABSTOP | CBS_DROPDOWNLIST | WS_GROUP | WS_BORDER | WS_VSCROLL
+
+ LTEXT "&Copies:", stc5, 153, 100, 29, 9
+ EDITTEXT, edt3, 184, 98, 26, 12, WS_TABSTOP | ES_RIGHT
+
+ CHECKBOX "Print to Fi&le" chx1,
+ 4, 113, 120, 12, BS_AUTOCHECKBOX | WS_TABSTOP | WS_GROUP
+ CHECKBOX "Collate Cop&ies" chx2,
+ 153, 113, 67, 12, BS_AUTOCHECKBOX | WS_TABSTOP | WS_GROUP
+
+ DEFPUSHBUTTON "OK" IDOK, 170, 4, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel" IDCANCEL, 170, 21, 50, 14, WS_GROUP
+
+ PUSHBUTTON "&Setup..." psh1, 170, 41, 50, 14, WS_GROUP
+ PUSHBUTTON "&Help" pshHelp, 170, 75, 50, 14, WS_GROUP
+END
+
+
+PRNSETUPDLGORD DIALOG LOADONCALL MOVEABLE DISCARDABLE 30, 23, 287, 122
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Print Setup"
+FONT 8, "Helv"
+BEGIN
+ GROUPBOX "Printer", grp3, 4, 6, 224, 66
+ LTEXT "(No Default Printer)", stc1, 18, 30, 208, 9
+ RADIOBUTTON "&Default Printer", rad3, 8, 16, 218, 12, WS_GROUP | WS_TABSTOP
+ RADIOBUTTON "Specific &Printer:", rad4, 8, 42, 218, 12
+ COMBOBOX cmb1, 18, 56, 208, 80, CBS_DROPDOWNLIST | WS_GROUP |
+ WS_BORDER | WS_VSCROLL
+ GROUPBOX "Orientation", grp1, 4, 74, 91, 46
+ ICON "", ico1, 12, 92, 24, 16
+ RADIOBUTTON "Po&rtrait", rad1, 40, 86, 53, 12, WS_GROUP | WS_TABSTOP
+ RADIOBUTTON "&Landscape", rad2, 40, 102, 53, 12
+ GROUPBOX "Paper", grp2, 100, 74, 128, 46, WS_GROUP
+ LTEXT "Si&ze:", stc2, 104, 88, 26, 9
+ COMBOBOX cmb2, 134, 86, 92, 80, CBS_DROPDOWNLIST | WS_BORDER |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Source:", stc3, 104, 104, 28, 9
+ COMBOBOX cmb3, 134, 102, 92, 80, CBS_DROPDOWNLIST | WS_BORDER |
+ WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 232, 4, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 232, 20, 50, 14, WS_GROUP
+ PUSHBUTTON "&Options...", psh1, 232, 40, 50, 14, WS_GROUP
+ PUSHBUTTON "&Help", pshHelp, 232, 56, 50, 14, WS_GROUP
+END
+
diff --git a/private/mvdm/wow16/commdlg/messages/usa/sz.src b/private/mvdm/wow16/commdlg/messages/usa/sz.src
new file mode 100644
index 000000000..5e5c0ef11
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/messages/usa/sz.src
@@ -0,0 +1,155 @@
+//---------------------------------------------------------------------------
+// Sz.src : String table resources
+//
+// Copyright (c) Microsoft Corporation, 1990-
+//---------------------------------------------------------------------------
+
+
+iszOverwriteCaption "File Exists"
+iszOverwriteQuestion "%s\nThis file already exists.\n\nReplace existing file?"
+iszDefExitCaption "Exiting"
+iszDefExitText "Do you really want to exit?"
+
+dlgFileOpen "FileOpen"
+dlgMultiFileOpen "MultiFileOpen"
+dlgFileSave "FileSave"
+dlgExitChanges "ExitChanges"
+dlgChooseColor "ChooseColor"
+dlgFindText "FindText"
+dlgReplaceText "ReplaceText"
+dlgFormatChar "FormatChar"
+dlgFontInfo "FontInfo"
+dlgPrintDlg "PrintDlg"
+dlgPrintSetupDlg "PrintSetupDlg"
+
+iszFileOpenTitle "Open"
+iszFileSaveTitle "Save As"
+iszSaveFileAsType "Save File as &Type:"
+iszDriveDoesNotExist "Drive %c: does not exist.\n\nPlease verify that the correct drive is given."
+iszNoDiskInDrive "Cannot read drive %c:.\n\nPlease verify the drive door is closed and that the disk is formatted and free of errors."
+iszWrongDiskInDrive "A different disk is expected in drive %c:.\n\nPlease insert the appropriate disk."
+iszUnformatedDisk "The disk in drive %c: is not formatted.\n\nPlease insert a formatted disk and try this operation again."
+iszFileNotFound "%s\nCannot find this file.\n\nPlease verify that the correct path and filename are given."
+iszPathNotFound "%s\nPath does not exist.\n\nPlease verify that the correct path is given."
+iszInvalidFileName "%s\nThis filename is not valid."
+iszSharingViolation "%s\nThis file is already in use.\n\nUse a new filename or close the file in use by another application."
+iszAccessDenied "%s\nCannot access this file.\n\nPlease verify security privileges on the network drive."
+iszReadOnly "%s\nThis file exists and is read-only.\nUse a different filename."
+iszInt24Error "%s\nDOS critical error.\nCannot access file."
+iszPortName "%s\nThis filename is a reserved device name.\n\nUse a different filename."
+iszWriteProtection "Disk %c: is write-protected.\nA file cannot be saved on a write-protected disk."
+iszDiskFull "Not enough disk space on drive %c:.\n\nDelete one or more files on this disk to increase available space or use a different disk."
+iszNoFileHandles "%s\nToo many files already open.\n\nClose one or more applications or files, and try again."
+iszCreatePrompt "%s\nThis file does not exist.\n\nCreate the file?"
+iszCreateNoModify "%s\nThis file is on a network drive with create but no modify privileges.\n\nAsk the administrator of this network to change this condition."
+iszSelectDriveTrouble "Cannot select drive %c:."
+
+iszBlack "Black"
+iszDkRed "Maroon"
+iszDkGreen "Green"
+iszDkYellow "Olive"
+iszDkBlue "Navy"
+iszDkPurple "Purple"
+iszDkAqua "Teal"
+iszDkGrey "Gray"
+iszLtGrey "Silver"
+iszLtRed "Red"
+iszLtGreen "Lime"
+iszLtYellow "Yellow"
+iszLtBlue "Blue"
+iszLtPurple "Fuschia"
+iszLtAqua "Aqua"
+iszWhite "White"
+
+iszAtomData "DlgInstData"
+
+iszHighPrnQ "High"
+iszMedPrnQ "Medium"
+iszLowPrnQ "Low"
+iszDraftPrnQ "Draft"
+
+iszPrinter "Printer: "
+iszSysPrn "Default Printer ("
+iszPrnOnPort "%s on %s (%s)"
+iszExtDev "ExtDeviceMode"
+iszDevMode "DeviceMode"
+iszDevCap "DeviceCapabilities"
+iszDefCurOn "(currently %s)"
+iszLocal "%s on %s%s"
+iszPrintSetup "Print Setup"
+
+iszFromBelowMin "The 'From' value is below the minimum page."
+iszFromAboveMax "The 'From' value is above the maximum page."
+iszToBelowMin "The 'To' value is below the minimum page."
+iszToAboveMax "The 'To' value is above the maximum page."
+iszFromInvalidChar "The 'From' field contains non-numeric characters or a number greater than 65535."
+iszToInvalidChar "The 'To' field contains non-numeric characters or a number greater than 65535."
+iszFromAndToEmpty "The 'From' and 'To' fields are empty and the Pages button is pressed."
+iszCopiesEmpty "The 'Copies' field is empty."
+iszCopiesInvalidChar "The 'Copies' field contains non-numeric characters."
+iszCopiesZero "The 'Copies' field must contain a positive value."
+iszNoPrnsInstalled "No default printer\n\nUse Control Panel to install and select a default printer"
+iszPrnDrvNotFound "%s driver file %s not found. Please reinstall through Control Panel or choose another printer."
+
+iszPaperSizeIndex + 1 "Letter 8 1/2 x 11 in"
+iszPaperSizeIndex + 2 "Letter Small 8 1/2 x 11 in"
+iszPaperSizeIndex + 3 "Tabloid 11 x 17 in"
+iszPaperSizeIndex + 4 "Ledger 17 x 11 in"
+iszPaperSizeIndex + 5 "Legal 8 1/2 x 14 in"
+iszPaperSizeIndex + 6 "Statement 5 1/2 x 8 1/2 in"
+iszPaperSizeIndex + 7 "Executive 7 1/2 x 10 in"
+iszPaperSizeIndex + 8 "A3 297 x 420 mm"
+iszPaperSizeIndex + 9 "A4 210 x 297 mm"
+iszPaperSizeIndex + 10 "A4 Small 210 x 297 mm"
+iszPaperSizeIndex + 11 "A5 148 x 210 mm"
+iszPaperSizeIndex + 12 "B4 250 x 354"
+iszPaperSizeIndex + 13 "B5 182 x 257 mm"
+iszPaperSizeIndex + 14 "Folio 8 1/2 x 13 in"
+iszPaperSizeIndex + 15 "Quarto 215 x 275 mm"
+iszPaperSizeIndex + 16 "10x14 in"
+iszPaperSizeIndex + 17 "11x17 in"
+iszPaperSizeIndex + 18 "Note 8 1/2 x 11 in"
+iszPaperSizeIndex + 19 "Envelope #9 3 7/8 x 8 7/8 in"
+iszPaperSizeIndex + 20 "Envelope #10 4 1/8 x 9 1/2 in"
+iszPaperSizeIndex + 21 "Envelope #11 4 1/2 x 10 3/8 in"
+iszPaperSizeIndex + 22 "Envelope #12 4 \276 x 11 in"
+iszPaperSizeIndex + 23 "Envelope #14 5 x 11 1/2 in"
+iszPaperSizeIndex + 24 "C size sheet"
+iszPaperSizeIndex + 25 "D size sheet"
+iszPaperSizeIndex + 26 "E size sheet"
+iszPaperSizeIndex + 27 "Envelope DL 110 x 220 mm"
+iszPaperSizeIndex + 28 "Envelope C5 162 x 229 mm"
+iszPaperSizeIndex + 29 "Envelope C3 324 x 458 mm"
+iszPaperSizeIndex + 30 "Envelope C4 229 x 324 mm"
+iszPaperSizeIndex + 31 "Envelope C6 114 x 162 mm"
+iszPaperSizeIndex + 32 "Envelope C65 114 x 229 mm"
+iszPaperSizeIndex + 33 "Envelope B4 250 x 353 mm"
+iszPaperSizeIndex + 34 "Envelope B5 176 x 250 mm"
+iszPaperSizeIndex + 35 "Envelope B6 176 x 125 mm"
+iszPaperSizeIndex + 36 "Envelope 110 x 230 mm"
+iszPaperSizeIndex + 37 "Envelope Monarch 3 7/8 x 7 1/2 in"
+iszPaperSizeIndex + 38 "6 3/4 Envelope 3 5/8 x 6 1/2 in"
+iszPaperSizeIndex + 39 "US Std Fanfold 14 7/8 x 11 in"
+iszPaperSizeIndex + 40 "German Std Fanfold 8 1/2 x 12 in"
+iszPaperSizeIndex + 41 "German Legal Fanfold 8 1/2 x 13 in"
+iszPaperSizeIndex + 256 "User Defined Size"
+
+iszClose "Close" /* "Close" text for find/replace */
+
+iszSizeNumber "Size must be a number."
+iszSizeRange "Size must be between %d and %d points."
+iszSynth "This font style is imitated for the display. The closest matching style will be used for printing."
+iszTrueType "This is a TrueType font. This same font will be used on both your printer and your screen."
+iszPrinterFont "This is a printer font. The closest matching Windows font will be used on your screen."
+iszGDIFont "This is a screen font. The closest matching printer font will be used for printing."
+
+iszNoFontsTitle "Fonts"
+iszNoFontsMsg "There are no fonts installed;\r\nRun Control Panel to install fonts."
+iszNoFaceSel "Invalid font name.\nChoose a font from the list of fonts."
+iszNoStyleSel "Invalid font style.\nChoose a style from the list of styles."
+/* iszRegular thru iszBoldItalic must be 31 characters or less */
+iszRegular "Regular"
+iszBold "Bold"
+iszItalic "Italic"
+iszBoldItalic "Bold Italic"
+
diff --git a/private/mvdm/wow16/commdlg/parse.c b/private/mvdm/wow16/commdlg/parse.c
new file mode 100644
index 000000000..bcf859e8a
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/parse.c
@@ -0,0 +1,369 @@
+#define NOCOMM
+#define NOWH
+
+#include "windows.h"
+#include "parse.h"
+
+#define chSpace ' '
+#define chPeriod '.'
+
+long ParseFile(ULPSTR lpstrFileName);
+LPSTR mystrchr(LPSTR, int);
+#define chMatchOne '?'
+#define chMatchAny '*'
+
+LPSTR mystrchr(LPSTR str, int ch)
+{
+ while(*str)
+ {
+ if (ch == *str)
+ return(str);
+ str = AnsiNext(str);
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------
+ * GetFileTitle
+ * Purpose: API to outside world to obtain the title of a file given the
+ * file name. Useful if file name received via some method
+ * other that GetOpenFileName (e.g. command line, drag drop).
+ * Assumes: lpszFile points to NULL terminated DOS filename (may have path)
+ * lpszTitle points to buffer to receive NULL terminated file title
+ * wBufSize is the size of buffer pointed to by lpszTitle
+ * Returns: 0 on success
+ * < 0, Parsing failure (invalid file name)
+ * > 0, buffer too small, size needed (including NULL terminator)
+ *--------------------------------------------------------------------------*/
+short FAR PASCAL
+GetFileTitle(LPCSTR lpszFile, LPSTR lpszTitle, WORD wBufSize)
+{
+ short nNeeded;
+ LPSTR lpszPtr;
+
+ nNeeded = (WORD) ParseFile((ULPSTR)lpszFile);
+ if (nNeeded >= 0) /* Is the filename valid? */
+ {
+ if ((nNeeded = lstrlen(lpszPtr = lpszFile + nNeeded) + 1)
+ <= (short) wBufSize)
+ {
+ /* ParseFile() fails if wildcards in directory, but OK if in name */
+ /* Since they aren't OK here, the check needed here */
+ if (mystrchr(lpszPtr, chMatchAny) || mystrchr(lpszPtr, chMatchOne))
+ {
+ nNeeded = PARSE_WILDCARDINFILE; /* Failure */
+ }
+ else
+ {
+ lstrcpy(lpszTitle, lpszPtr);
+ nNeeded = 0; /* Success */
+ }
+ }
+ }
+ return(nNeeded);
+}
+
+/*---------------------------------------------------------------------------
+ * ParseFile
+ * Purpose: Determine if the filename is a legal DOS name
+ * Input: Long pointer to a SINGLE file name
+ * Circumstance checked:
+ * 1) Valid as directory name, but not as file name
+ * 2) Empty String
+ * 3) Illegal Drive label
+ * 4) Period in invalid location (in extention, 1st in file name)
+ * 5) Missing directory character
+ * 6) Illegal character
+ * 7) Wildcard in directory name
+ * 8) Double slash beyond 1st 2 characters
+ * 9) Space character in the middle of the name (trailing spaces OK)
+ * 10) Filename greater than 8 characters
+ * 11) Extention greater than 3 characters
+ * Notes:
+ * Filename length is NOT checked.
+ * Valid filenames will have leading spaces, trailing spaces and
+ * terminating period stripped in place.
+ *
+ * Returns: If valid, LOWORD is byte offset to filename
+ * HIWORD is byte offset to extention
+ * if string ends with period, 0
+ * if no extention is given, string length
+ * If invalid, LOWORD is error code suggesting problem (< 0)
+ * HIWORD is approximate offset where problem found
+ * Note that this may be beyond the offending character
+ * History:
+ * Thu 24-Jan-1991 12:20:00 -by- Clark R. Cyr [clarkc]
+ * Initial writing
+ * Thu 21-Feb-1991 10:19:00 -by- Clark R. Cyr [clarkc]
+ * Changed to unsigned character pointer
+ *--------------------------------------------------------------------------*/
+
+long ParseFile(ULPSTR lpstrFileName)
+{
+ short nFile, nExt, nFileOffset, nExtOffset;
+ BOOL bExt;
+ BOOL bWildcard;
+ short nNetwork = 0;
+ BOOL bUNCPath = FALSE;
+ ULPSTR lpstr = lpstrFileName;
+
+/* Strip off initial white space. Note that TAB is not checked */
+/* because it cannot be received out of a standard edit control */
+/* 30 January 1991 clarkc */
+ while (*lpstr == chSpace)
+ lpstr++;
+
+ if (!*lpstr)
+ {
+ nFileOffset = PARSE_EMPTYSTRING;
+ goto FAILURE;
+ }
+
+ if (lpstr != lpstrFileName)
+ {
+ lstrcpy(lpstrFileName, lpstr);
+ lpstr = lpstrFileName;
+ }
+
+ if (*AnsiNext(lpstr) == ':')
+ {
+ char cDrive = (*lpstr | (BYTE) 0x20); /* make lowercase */
+
+/* This does not test if the drive exists, only if it's legal */
+ if ((cDrive < 'a') || (cDrive > 'z'))
+ {
+ nFileOffset = PARSE_INVALIDDRIVE;
+ goto FAILURE;
+ }
+ lpstr = AnsiNext(AnsiNext(lpstr));
+ }
+
+ if ((*lpstr == '\\') || (*lpstr == '/'))
+ {
+ if (*++lpstr == chPeriod) /* cannot have c:\. */
+ {
+ if ((*++lpstr != '\\') && (*lpstr != '/')) /* unless it's stupid */
+ {
+ if (!*lpstr) /* it's the root directory */
+ goto MustBeDir;
+
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+ else
+ ++lpstr; /* it's saying top directory (again), thus allowed */
+ }
+ else if ((*lpstr == '\\') && (*(lpstr-1) == '\\'))
+ {
+/* It seems that for a full network path, whether a drive is declared or
+ * not is insignificant, though if a drive is given, it must be valid
+ * (hence the code above should remain there).
+ * 13 February 1991 clarkc
+ */
+ ++lpstr; /* ...since it's the first slash, 2 are allowed */
+ nNetwork = -1; /* Must receive server and share to be real */
+ bUNCPath = TRUE; /* No wildcards allowed if UNC name */
+ }
+ else if (*lpstr == '/')
+ {
+ nFileOffset = PARSE_INVALIDDIRCHAR;
+ goto FAILURE;
+ }
+ }
+ else if (*lpstr == chPeriod)
+ {
+ if (*++lpstr == chPeriod) /* Is this up one directory? */
+ ++lpstr;
+ if (!*lpstr)
+ goto MustBeDir;
+ if ((*lpstr != '\\') && (*lpstr != '/'))
+ {
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+ else
+ ++lpstr; /* it's saying directory, thus allowed */
+ }
+
+ if (!*lpstr)
+ {
+ goto MustBeDir;
+ }
+
+/* Should point to first char in 8.3 filename by now */
+ nFileOffset = nExtOffset = nFile = nExt = 0;
+ bWildcard = bExt = FALSE;
+ while (*lpstr)
+ {
+/*
+ * The next comparison MUST be unsigned to allow for extended characters!
+ * 21 Feb 1991 clarkc
+ */
+ if (*lpstr < chSpace)
+ {
+ nFileOffset = PARSE_INVALIDCHAR;
+ goto FAILURE;
+ }
+ switch (*lpstr)
+ {
+ case '"': /* All invalid */
+ case '+':
+ case ',':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '[':
+ case ']':
+ case '|':
+ {
+ nFileOffset = PARSE_INVALIDCHAR;
+ goto FAILURE;
+ }
+
+ case '\\': /* Subdirectory indicators */
+ case '/':
+ nNetwork++;
+ if (bWildcard)
+ {
+ nFileOffset = PARSE_WILDCARDINDIR;
+ goto FAILURE;
+ }
+
+ else if (nFile == 0) /* can't have 2 in a row */
+ {
+ nFileOffset = PARSE_INVALIDDIRCHAR;
+ goto FAILURE;
+ }
+ else
+ { /* reset flags */
+ ++lpstr;
+ if (!nNetwork && !*lpstr)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ nFile = nExt = 0;
+ bExt = FALSE;
+ }
+ break;
+
+ case chSpace:
+ {
+ ULPSTR lpSpace = lpstr;
+
+ *lpSpace = '\0';
+ while (*++lpSpace)
+ {
+ if (*lpSpace != chSpace)
+ {
+ *lpstr = chSpace; /* Reset string, abandon ship */
+ nFileOffset = PARSE_INVALIDSPACE;
+ goto FAILURE;
+ }
+ }
+ }
+ break;
+
+ case chPeriod:
+ if (nFile == 0)
+ {
+ if (*++lpstr == chPeriod)
+ ++lpstr;
+ if (!*lpstr)
+ goto MustBeDir;
+
+ if ((*lpstr != '\\') && (*lpstr != '/'))
+ {
+ nFileOffset = PARSE_INVALIDPERIOD;
+ goto FAILURE;
+ }
+
+ ++lpstr; /* Flags are already set */
+ }
+ else if (bExt)
+ {
+ nFileOffset = PARSE_INVALIDPERIOD; /* can't have one in ext */
+ goto FAILURE;
+ }
+ else
+ {
+ nExtOffset = 0;
+ ++lpstr;
+ bExt = TRUE;
+ }
+ break;
+
+ case '*':
+ case '?':
+ if (bUNCPath)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ bWildcard = TRUE;
+/* Fall through to normal character processing */
+
+ default:
+ if (bExt)
+ {
+ if (++nExt == 1)
+ nExtOffset = lpstr - lpstrFileName;
+ else if (nExt > 3)
+ {
+ nFileOffset = PARSE_EXTENTIONTOOLONG;
+ goto FAILURE;
+ }
+ if ((nNetwork == -1) && (nFile + nExt > 11))
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ }
+ else if (++nFile == 1)
+ nFileOffset = lpstr - lpstrFileName;
+ else if (nFile > 8)
+ {
+ /* If it's a server name, it can have 11 characters */
+ if (nNetwork != -1)
+ {
+ nFileOffset = PARSE_FILETOOLONG;
+ goto FAILURE;
+ }
+ else if (nFile > 11)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+ }
+
+ lpstr = AnsiNext(lpstr);
+ break;
+ }
+ }
+
+/* Did we start with a double backslash but not have any more slashes? */
+ if (nNetwork == -1)
+ {
+ nFileOffset = PARSE_INVALIDNETPATH;
+ goto FAILURE;
+ }
+
+ if (!nFile)
+ {
+MustBeDir:
+ nFileOffset = PARSE_DIRECTORYNAME;
+ goto FAILURE;
+ }
+
+ if ((*(lpstr - 1) == chPeriod) && /* if true, no extention wanted */
+ (*AnsiNext(lpstr-2) == chPeriod))
+ *(lpstr - 1) = '\0'; /* Remove terminating period */
+ else if (!nExt)
+FAILURE:
+ nExtOffset = lpstr - lpstrFileName;
+
+ return(MAKELONG(nFileOffset, nExtOffset));
+}
+
diff --git a/private/mvdm/wow16/commdlg/parse.h b/private/mvdm/wow16/commdlg/parse.h
new file mode 100644
index 000000000..968810b02
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/parse.h
@@ -0,0 +1,21 @@
+typedef unsigned char far *ULPSTR;
+
+#define PARSE_DIRECTORYNAME -1
+#define PARSE_INVALIDDRIVE -2
+#define PARSE_INVALIDPERIOD -3
+#define PARSE_MISSINGDIRCHAR -4
+#define PARSE_INVALIDCHAR -5
+#define PARSE_INVALIDDIRCHAR -6
+#define PARSE_INVALIDSPACE -7
+#define PARSE_EXTENTIONTOOLONG -8
+#define PARSE_FILETOOLONG -9
+#define PARSE_EMPTYSTRING -10
+#define PARSE_WILDCARDINDIR -11
+#define PARSE_WILDCARDINFILE -12
+#define PARSE_INVALIDNETPATH -13
+
+#if DBCS
+#define MAX_DIRNAME 128
+#else
+#define MAX_DIRNAME 64
+#endif
diff --git a/private/mvdm/wow16/commdlg/portrait.ico b/private/mvdm/wow16/commdlg/portrait.ico
new file mode 100644
index 000000000..5b2a78b6e
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/portrait.ico
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/privcomd.h b/private/mvdm/wow16/commdlg/privcomd.h
new file mode 100644
index 000000000..b1d96c82a
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/privcomd.h
@@ -0,0 +1,167 @@
+/*---------------------------------------------------------------------------*/
+/* PrivComd.h : UI dialog header */
+/* */
+/* Copyright (c) Microsoft Corporation, 1991- */
+/*---------------------------------------------------------------------------*/
+
+#include "commdlg.h"
+#include "dlgs.h"
+#include "_xlib.h"
+#include "isz.h"
+#include "cderr.h"
+
+#ifdef FILEOPENDIALOGS
+#include "fileopen.h"
+#endif
+
+#define CODESEG _based(_segname("_CODE"))
+
+#define MAXFILENAMELEN 12
+#define SEM_NOERROR 0x8003
+
+/*---------------------------------------------------------------------------
+ * DOS Disk Transfer Area Structure -
+ *--------------------------------------------------------------------------*/
+
+typedef struct tagDOSDTA
+ {
+ BYTE Reserved[21]; /* 21 */
+ BYTE Attrib; /* 22 */
+ WORD Time; /* 24 */
+ WORD Date; /* 26 */
+ DWORD Length; /* 30 */
+ char szName[MAXFILENAMELEN+1]; /* 43 */
+ char buffer[5]; /* 48 */
+ } DOSDTA;
+typedef DOSDTA *PDOSDTA;
+typedef DOSDTA FAR *LPDOSDTA;
+
+/* Avoids sharing violations. Defined 21 Jan 1991 clarkc */
+#define SHARE_EXIST (OF_EXIST | OF_SHARE_DENY_NONE)
+
+/*---------------------------------------------------------------------------
+ * DOS Extended File Control Block Structure -
+ *--------------------------------------------------------------------------*/
+typedef struct tagEFCB
+ {
+ BYTE Flag;
+ BYTE Reserve1[5];
+ BYTE Attrib;
+ BYTE Drive;
+ BYTE Filename[11];
+ BYTE Reserve2[5];
+ BYTE NewName[11];
+ BYTE Reserve3[9];
+ } EFCB;
+
+#define ATTR_VOLUME 0x0008
+
+/*----Globals---------------------------------------------------------------*/
+
+extern HINSTANCE hinsCur; /* Instance handle of Library */
+extern DWORD dwExtError; /* Extended error code */
+
+extern short cyCaption, cyBorder, cyVScroll;
+extern short cxVScroll, cxBorder, cxSize;
+
+
+extern char szNull[];
+extern char szStar[];
+extern char szStarDotStar[];
+extern BOOL bMouse; /* System has a mouse */
+extern BOOL bCursorLock;
+extern BOOL bWLO; /* Running with WLO */
+extern BOOL bDBCS; /* Running Double-Byte Character Support? */
+extern WORD wWinVer; /* Windows version */
+extern WORD wDOSVer; /* DOS version */
+extern WORD msgHELP; /* Initialized via RegisterWindowMessage */
+
+extern DOSDTA DTAGlobal;
+extern EFCB VolumeEFCB;
+
+/*----Functions--------------------------------------------------------------*/
+LONG FAR RgbInvertRgb(LONG);
+HBITMAP FAR HbmpLoadBmp(WORD);
+
+void FAR TermFind(void);
+void FAR TermColor(void);
+void FAR TermFont(void);
+void FAR TermFile(void);
+void FAR TermPrint(void);
+
+
+/* Common */
+
+VOID FAR PASCAL HourGlass(BOOL);
+HBITMAP FAR PASCAL LoadAlterBitmap(int, DWORD, DWORD);
+VOID FAR PASCAL MySetObjectOwner(HANDLE);
+VOID FAR PASCAL RepeatMove(LPSTR, LPSTR, WORD);
+
+/* File Open/Save */
+
+#ifdef FILEOPENDIALOGS
+BOOL FAR PASCAL SetCurrentDrive(short);
+short FAR PASCAL GetCurrentDrive(VOID);
+BOOL GetCurDirectory(PSTR);
+BOOL FAR PASCAL mygetcwd(LPSTR, int);
+BOOL FAR PASCAL mychdir(LPSTR);
+BOOL FAR PASCAL FindFirst4E(LPSTR, WORD);
+BOOL FAR PASCAL FindNext4F(VOID);
+VOID FAR PASCAL MySetDTAAddress(LPDOSDTA);
+VOID FAR PASCAL ResetDTAAddress(VOID);
+BOOL UpdateListBoxes(HWND, PMYOFN, LPSTR, WORD);
+#endif
+
+/* Color */
+
+#ifdef COLORDLG
+#include "color.h"
+ /* Color */
+extern HDC hDCFastBlt;
+extern DWORD rgbClient;
+extern WORD H,S,L;
+extern HBITMAP hRainbowBitmap;
+extern BOOL bMouseCapture;
+extern WNDPROC lpprocStatic;
+extern short nDriverColors;
+extern char szOEMBIN[];
+extern short nBoxHeight, nBoxWidth;
+extern HWND hSave;
+extern FARPROC qfnColorDlg;
+BOOL FAR PASCAL ColorDlgProc(HWND, WORD, WORD, LONG);
+LONG FAR PASCAL WantArrows(HWND, WORD, WPARAM, LPARAM);
+
+void RainbowPaint(PCOLORINFO, HDC, LPRECT);
+VOID NearestSolid(PCOLORINFO);
+DWORD HLStoRGB(WORD, WORD, WORD);
+VOID RGBtoHLS(DWORD);
+VOID HLStoHLSPos(short, PCOLORINFO);
+VOID SetRGBEdit(short, PCOLORINFO);
+VOID SetHLSEdit(short, PCOLORINFO);
+short RGBEditChange(short, PCOLORINFO);
+VOID ChangeColorSettings(PCOLORINFO);
+VOID CrossHairPaint(HDC, short, short, PCOLORINFO);
+void EraseCrossHair(HDC, PCOLORINFO);
+VOID LumArrowPaint(HDC, short, PCOLORINFO);
+VOID EraseLumArrow(HDC, PCOLORINFO);
+VOID HLSPostoHLS(short, PCOLORINFO);
+WORD InitColor(HWND, WORD, LPCHOOSECOLOR);
+BOOL InitRainbow(PCOLORINFO);
+BOOL InitScreenCoords(HWND, PCOLORINFO);
+VOID ColorPaint(HWND, PCOLORINFO, HDC, LPRECT);
+VOID ChangeBoxSelection(PCOLORINFO, short);
+VOID ChangeBoxFocus(PCOLORINFO, short);
+VOID PaintBox(PCOLORINFO, HDC, short);
+BOOL ColorKeyDown(WORD, int FAR *, PCOLORINFO);
+BOOL BoxDrawItem(LPDIS);
+VOID SetupRainbowCapture(PCOLORINFO);
+void PaintRainbow(HDC, LPRECT, PCOLORINFO);
+#endif
+
+
+/* Dlgs.c */
+
+int FAR PASCAL LibMain(HANDLE, WORD, WORD, LPSTR);
+int FAR PASCAL WEP(int);
+
+LONG FAR RgbInvertRgb(LONG);
diff --git a/private/mvdm/wow16/commdlg/right.bmp b/private/mvdm/wow16/commdlg/right.bmp
new file mode 100644
index 000000000..7e6d84840
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/right.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/righti.bmp b/private/mvdm/wow16/commdlg/righti.bmp
new file mode 100644
index 000000000..cc576f2eb
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/righti.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smflder.bmp b/private/mvdm/wow16/commdlg/smflder.bmp
new file mode 100644
index 000000000..04c6c9b4a
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smflder.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smfldr1.bmp b/private/mvdm/wow16/commdlg/smfldr1.bmp
new file mode 100644
index 000000000..df77b14f6
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smfldr1.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smfldr2.bmp b/private/mvdm/wow16/commdlg/smfldr2.bmp
new file mode 100644
index 000000000..805782ecb
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smfldr2.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smfldr3.bmp b/private/mvdm/wow16/commdlg/smfldr3.bmp
new file mode 100644
index 000000000..24dc5e3b0
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smfldr3.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smfldr4.bmp b/private/mvdm/wow16/commdlg/smfldr4.bmp
new file mode 100644
index 000000000..dd61af96d
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smfldr4.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smfldr5.bmp b/private/mvdm/wow16/commdlg/smfldr5.bmp
new file mode 100644
index 000000000..b223df3a9
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smfldr5.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smflopy.bmp b/private/mvdm/wow16/commdlg/smflopy.bmp
new file mode 100644
index 000000000..11e2872e2
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smflopy.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smhard.bmp b/private/mvdm/wow16/commdlg/smhard.bmp
new file mode 100644
index 000000000..33cc78094
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smhard.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smnet.bmp b/private/mvdm/wow16/commdlg/smnet.bmp
new file mode 100644
index 000000000..19254c09b
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smnet.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/smram.bmp b/private/mvdm/wow16/commdlg/smram.bmp
new file mode 100644
index 000000000..d13547d72
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/smram.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/start.asm b/private/mvdm/wow16/commdlg/start.asm
new file mode 100644
index 000000000..0e8d0fcd3
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/start.asm
@@ -0,0 +1,73 @@
+;----------------------------------------------------------------------------
+; start.asm -- Start Code for loading the DLGS dll
+;
+; Copyright (c) Microsoft Corporation, 1990
+;----------------------------------------------------------------------------
+
+;----------------------------------------------------------------------------
+; This module contains the code initially executed to load and
+; initialize the DLL
+;----------------------------------------------------------------------------
+
+;-----Includes, Definitions, Externs, Etc.-----------------------------------
+
+.xlist
+include cmacros.inc
+include windows.inc
+.list
+
+
+ExternFP <LibMain>
+
+createSeg INIT_TEXT, INIT_TEXT, BYTE, PUBLIC, CODE
+sBegin INIT_TEXT
+assumes cs,INIT_TEXT
+
+?PLM=0
+ExternA <_acrtused>
+
+?PLM=1
+ExternFP <LocalInit>
+
+;-------- Entry Points ---------------------------------------------------
+
+cProc LibEntry, <FAR,PUBLIC>
+;
+; CX = size of heap
+; DI = module handle
+; DS = automatic data segment
+; ES:SI = address of command line (not used)
+;
+include convdll.inc
+cBegin
+ push di
+ push ds
+ push cx
+ push es
+ push si
+
+ jcxz callc
+ xor ax,ax
+ cCall LocalInit <ds, ax, cx>
+ or ax,ax
+ jz error
+
+ ;LibMain(HANDLE, WORD, WORD, LPSTR)
+callc:
+ call LibMain ; Main C routine
+ jmp short exit
+
+error:
+ pop si
+ pop es
+ pop cx
+ pop ds
+ pop di
+
+exit:
+
+cEnd
+
+sEnd INIT_TEXT
+
+end LibEntry
diff --git a/private/mvdm/wow16/commdlg/up.bmp b/private/mvdm/wow16/commdlg/up.bmp
new file mode 100644
index 000000000..c8d14da1d
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/up.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/upi.bmp b/private/mvdm/wow16/commdlg/upi.bmp
new file mode 100644
index 000000000..c3dd32303
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/upi.bmp
Binary files differ
diff --git a/private/mvdm/wow16/commdlg/xlib.h b/private/mvdm/wow16/commdlg/xlib.h
new file mode 100644
index 000000000..b48d46429
--- /dev/null
+++ b/private/mvdm/wow16/commdlg/xlib.h
@@ -0,0 +1,55 @@
+/*---------------------------------------------------------------------------
+ * Xlib.h -- Common definitions. Windows.h must be included first.
+ *---------------------------------------------------------------------------
+ */
+
+#define LINT_ARGS
+#define HNULL ((HANDLE) 0)
+
+/* Miscellaneous */
+#define cbFindMax 1024
+
+/* Graphics */
+#define bhlsMax ((BYTE) 240) /* Max of H/L/S */
+#define brgbMax ((BYTE) 255) /* Max of R/G/B */
+#define bHueNil (bhlsMax*2/3) /* This value of Hue is undefined if Sat==0 */
+
+#define HLS(h, l, s) \
+ ((DWORD)(((BYTE)(h)|((WORD)(l)<<8))|(((DWORD)(BYTE)(s))<<16)))
+#define GetHValue(hls) ((BYTE)(hls))
+#define GetLValue(hls) ((BYTE)(((WORD)(hls)) >> 8))
+#define GetSValue(hls) ((BYTE)((hls)>>16))
+
+#define cwPointSizes 13
+
+typedef struct tagCF
+ {
+ char cfFaceName[LF_FACESIZE];
+ int cfPointSize;
+ COLORREF cfColor; /* Explicit RGB value... */
+
+ unsigned fBold: 1;
+ unsigned fItalic: 1;
+ unsigned fStrikeOut: 1;
+ unsigned fUnderLine: 1;
+ unsigned fExtra: 12;
+ }
+CHARFORMAT;
+typedef CHARFORMAT * PCHARFORMAT;
+typedef CHARFORMAT FAR * LPCHARFORMAT;
+
+
+HBITMAP FAR PASCAL LoadAlterBitmap(int, DWORD, DWORD);
+DWORD FAR PASCAL RgbFromHls(BYTE, BYTE, BYTE);
+DWORD FAR PASCAL HlsFromRgb(BYTE, BYTE, BYTE);
+BOOL FAR PASCAL GetColorChoice(HWND, DWORD FAR *, DWORD FAR *, FARPROC);
+BOOL FAR PASCAL GetCharFormat(HWND, LPCHARFORMAT, FARPROC);
+
+/* Memory */
+void FAR PASCAL StripSpace(LPSTR);
+HANDLE FAR PASCAL GlobalCopy(HANDLE);
+HANDLE FAR PASCAL GlobalDelete(HANDLE, LONG, LONG);
+HANDLE FAR PASCAL GlobalInsert(HANDLE, LONG, LONG, BOOL, BYTE);
+HANDLE FAR PASCAL LocalCopy(HANDLE);
+HANDLE FAR PASCAL LocalDelete(HANDLE, WORD, WORD);
+HANDLE FAR PASCAL LocalInsert(HANDLE, WORD, WORD, BOOL, BYTE);
diff --git a/private/mvdm/wow16/ctl3dv2/3d.ico b/private/mvdm/wow16/ctl3dv2/3d.ico
new file mode 100644
index 000000000..c0ecd60f0
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/3d.ico
Binary files differ
diff --git a/private/mvdm/wow16/ctl3dv2/3dcheck.bmp b/private/mvdm/wow16/ctl3dv2/3dcheck.bmp
new file mode 100644
index 000000000..23d739342
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/3dcheck.bmp
Binary files differ
diff --git a/private/mvdm/wow16/ctl3dv2/common.ver b/private/mvdm/wow16/ctl3dv2/common.ver
new file mode 100644
index 000000000..e124376b6
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/common.ver
@@ -0,0 +1,86 @@
+
+/*---------------------------------------------------------------*/
+/* */
+/* The following section actually creates the version structure. */
+/* They are ignored if we are not being invoked by RC. */
+/* */
+/* VERSION.H must be included before including this file */
+/* */
+/* If VER_LEGALCOPYRIGHT_STR is not defined, it will be */
+/* constructed using VER_LEGALCOPYRIGHT_YEARS, so at least one */
+/* these macros must be defined before including this file. */
+/* */
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR, and */
+/* VER_INTERNALNAME_STR must be defined before including this */
+/* file. */
+/* */
+/* If VER_FILEVERSION is not defined, VER_PRODUCTVERSION will be */
+/* used instead. If VER_FILEVERSION_STR is not defined, */
+/* VER_PRODUCTVERSION_STR will be used instead. */
+/* */
+/* If LANG is defined, then this is assumed to be an */
+/* an international build; two string blocks will be created, */
+/* (since all version resources must have English), and the */
+/* second one can be localized */
+/* */
+/*---------------------------------------------------------------*/
+
+#ifdef RC_INVOKED
+
+#ifndef VER_LEGALCOPYRIGHT_STR
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Microsoft Corp. ", VER_LEGALCOPYRIGHT_YEARS, "\0"
+#endif
+
+#ifndef VER_FILEVERSION
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#endif
+
+#ifndef VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+
+#ifdef LANG
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ /* the following line should be extended for localized versions */
+ VALUE "Translation", 0x0409, 0x04E4
+ END
+END
+
+#endif
+
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.c b/private/mvdm/wow16/ctl3dv2/ctl3d.c
new file mode 100644
index 000000000..e2e7485e6
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.c
@@ -0,0 +1,3732 @@
+/*-----------------------------------------------------------------------
+|
+| CTL3D
+|
+| Copyright Microsoft Corporation 1992. All Rights Reserved.
+|
+|
+| This module contains the functions to give windows controls a 3d effect
+|
+| This source is made public for your edification and debugging pleasure
+|
+| PLEASE do not make any changes or release private versions of this DLL
+| send e-mail to me (wesc) if you have feature requests or bug fixes.
+|
+| Thanks -- Wes.
+|
+|
+| History:
+| 1-Jan-92 : Added OOM handling on GetDC (not really necessary but
+| XL4 OOM failure testing made GetDC return NULL)
+|
+| 1-Jan-92 : Check wasn't getting redrawn when state changed in
+| the default button proc.
+|
+| 29-Jan-92: If button has the focus and app is switched in, we weren't
+| redrawing the entire button check & text. Force redraw
+| of these on WM_SETFOCUS message.
+|
+| 3-Feb-92: Fixed switch in via task manager by erasing the buttons
+| backgound on WM_SETFOCUS (detect this when wParam == NULL)
+|
+| 4-Apr-92: Make it work with OWNERDRAW buttons
+|
+| 22-Apr-92: Removed Excel specific code
+|
+| 19-May-92: Turn it into a DLL
+|
+| May-Jun92: Lots o' fixes & enhancements
+|
+| 23-Jun-92: Added support for hiding, sizing & moving
+|
+| 24-Jun-92: Make checks & radio button circles draw w/ window
+| text color 'cause they are drawn on window bkgnd
+|
+| 30-Jun-92: (0.984) Fix bug where EnableWindow of StaticText doesn't
+| redraw properly. Also disable ctl3d when verWindows > 3.1
+|
+| 1-Jul-92: Added WIN32 support (davegi) (not in this source)
+|
+| 2-Jul-92: (0.984) Disable when verWindows >= 4.0
+|
+| 20-Jul-92: (0.985) Draw focus rects of checks/radios properly on non
+| default sized controls.
+|
+| 21-Jul-92: (0.990) Ctl3dAutoSubclass
+|
+| 21-Jul-92: (0.991) ported DaveGi's WIN32 support
+|
+| 22-Jul-92: (0.991) fixed Ctl3dCtlColor returning fFalse bug
+|
+| 4-Aug-92: (0.992) Graphic designers bug fixes...Now subclass
+| regular buttons + disabled states for checks & radios
+|
+| 6-Aug-92: (0.993) Fix bug where activate via taskman & group
+| box has focus, & not centering text in buttons
+|
+| 6-Aug-92: (0.993) Tweek drawing next to scroll bars.
+|
+| 13-Aug-92: (0.994) Fix button focus rect bug drawing due to
+| Win 3.0 DrawText bug.
+|
+| 14-Aug-92: (1.0) Release of version 1.0
+| Don't draw default button border on BS_DEFPUSHBUTTON
+| pushbuttons
+| Fix bogus bug where Windows hangs when in a AUTORADIOBUTTON
+| hold down space bar and hit arrow key.
+|
+| 23-Sep-92: (1.01) Made Ctl3dCtlColor call DefWindowProc so it works when
+| called in a windproc.
+|
+| 28-Sep-92: (1.02) Added MyGetTextExtent so '&''s not considered in
+| text extents.
+|
+| 08-Dec-92: (1.03) minor tweeks to the button text centering code
+| for Publisher
+|
+| 11-Dec-92: (1.04) added 3d frames to dialogs
+|
+| 15-Dec-92: (1.05) fixed bug where group boxes redraw wrong when
+| Window text is changed to something shorter
+|
+| ??-Dec-92: (1.06) added 3d borders
+|
+| 21-Dec-92: (1.07) added WM_DLGBORDER to disable borders
+|
+| 4-Jan-93: (1.08) fixed WM_SETTEXT bug w/ DLG frames & checks/checkboxes
+| Also, WM_DLGSUBCLASS
+|
+| 22-Feb-93: (1.12) disabled it under Chicago
+|
+| 25-Feb-93: (1.13) re-add fix which allows dialog procs to
+| handle WM_CTLCOLOR messages
+|
+| 26-April-93 (2.0) Changed to allow for second subclass. Now uses class instead of
+| wndproc for subclass determination.
+| store next wndproc in properties with global atoms
+|
+| 06-Jun-93 (2.0) Make a static linked library version.
+|
+|
+-----------------------------------------------------------------------*/
+#define NO_STRICT
+#include <windows.h>
+
+#ifdef _BORLAND
+#include <mem.h>
+#else
+#include <memory.h>
+#endif
+
+#include <malloc.h>
+#include "ctl3d.h"
+
+#include "stdio.h"
+
+/*-----------------------------------------------------------------------
+|CTL3D Types
+-----------------------------------------------------------------------*/
+#ifdef WIN32
+
+#define Win32Only(e) e
+#define Win16Only(e)
+#define Win32Or16(e32, e16) e32
+#define Win16Or32(e16, e32) e32
+
+#define _loadds
+#define __export
+
+#define FValidLibHandle(hlib) ((hlib) != NULL)
+
+//
+// No concept of far in Win32.
+//
+
+#define MEMCMP memcmp
+#define NPTSTR LPTSTR
+
+//
+// Control IDs are LONG in Win32.
+//
+
+typedef LONG CTLID;
+#define GetControlId(hwnd) GetWindowLong(hwnd, GWL_ID)
+
+//
+// Send a color button message.
+//
+
+#define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc ) \
+ ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORBTN, (WPARAM) hdc, (LPARAM) hwnd))
+
+//
+// Send a color static message.
+//
+
+#define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc ) \
+ ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORSTATIC, (WPARAM) hdc, (LPARAM) hwnd))
+
+#else
+
+#define CallWindowProcA CallWindowProc
+#define DefWindowProcA DefWindowProc
+#define MessageBoxA MessageBox
+
+#define TEXT(a) a
+#define TCHAR char
+
+#ifndef LPTSTR
+#define LPTSTR LPSTR
+#endif
+#define LPCTSTR LPCSTR
+#define NPTSTR NPSTR
+
+#define Win32Only(e)
+#define Win16Only(e) e
+#define Win32Or16(e32, e16) e16
+#define Win16Or32(e16, e32) e16
+
+
+#define FValidLibHandle(hlib) (( hlib ) > 32 )
+
+#define MEMCMP _fmemcmp
+
+typedef WORD CTLID;
+#define GetControlId(h) GetWindowWord(h, GWW_ID)
+
+#define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc ) \
+ ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_BTN)))
+
+#define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc ) \
+ ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_STATIC)))
+
+
+typedef struct
+ {
+ LPARAM lParam;
+ WPARAM wParam;
+ UINT message;
+ HWND hwnd;
+} CWPSTRUCT;
+
+#endif // WIN32
+
+// DBCS far east short cut key support
+#define cchShortCutModeMax 10
+#define chShortCutSbcsPrefix '\036'
+#define chShortCutDbcsPrefix '\037'
+
+#define cchClassMax 16 // max class is "combolbox"+NUL rounded up to 16
+
+
+#define Assert(f)
+
+#define PUBLIC
+#define PRIVATE static
+
+#define fFalse 0
+#define fTrue 1
+
+#define INCBTHOOK 1
+#define OUTCBTHOOK 0
+
+#ifdef _BORLAND
+#define CSCONST(type) type const
+#define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
+#define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
+#define _alloca alloca
+#define _memcmp memcmp
+#else
+#ifdef WIN32
+#define CSCONST(type) type const
+#define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
+#define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
+#else
+#define CSCONST(type) type _based(_segname("_CODE")) const
+#define CodeLpszDecl(lpszVar, szLit) \
+ static CSCONST(char) lpszVar##Code[] = szLit; \
+ char far *lpszVar = (char far *)lpszVar##Code
+#define CodeLpszDeclA(lpszVar, szLit) \
+ static CSCONST(char) lpszVar##Code[] = szLit; \
+ char far *lpszVar = (char far *)lpszVar##Code
+#endif
+#endif
+
+
+// isomorphic to windows RECT
+typedef struct
+ {
+ int xLeft;
+ int yTop;
+ int xRight;
+ int yBot;
+ } RC;
+
+
+// Windows Versions (Byte order flipped from GetWindowsVersion)
+#define ver30 0x0300
+#define ver31 0x030a
+#define ver40 0x035F
+
+// Border widths
+#define dxBorder 1
+#define dyBorder 1
+
+
+// Index Color Table
+// WARNING: change mpicvSysColors if you change the icv order
+typedef WORD ICV;
+#define icvBtnHilite 0
+#define icvBtnFace 1
+#define icvBtnShadow 2
+
+#define icvBrushMax 3
+
+#define icvBtnText 3
+#define icvWindow 4
+#define icvWindowText 5
+#define icvGrayText 6
+#define icvWindowFrame 7
+#define icvMax 8
+
+typedef COLORREF CV;
+
+// CoLoR Table
+typedef struct
+ {
+ CV rgcv[icvMax];
+ } CLRT;
+
+
+// BRush Table
+typedef struct
+ {
+ HBRUSH mpicvhbr[icvBrushMax];
+ } BRT;
+
+
+// DrawRec3d flags
+#define dr3Left 0x0001
+#define dr3Top 0x0002
+#define dr3Right 0x0004
+#define dr3Bot 0x0008
+
+#define dr3HackBotRight 0x1000 // code size is more important than aesthetics
+#define dr3All 0x000f
+typedef WORD DR3;
+
+
+// Control Types
+// Commdlg types are necessary because commdlg.dll subclasses certain
+// controls before the app can call Ctl3dSubclassDlg.
+#define ctButton 0
+#define ctList 1
+#define ctEdit 2
+#define ctCombo 3
+#define ctStatic 4
+#define ctComboLBox 5
+#define ctMax 6
+
+// ConTroL
+typedef struct
+ {
+ FARPROC lpfn;
+ WNDPROC lpfnDefProc;
+ TCHAR szClassName[cchClassMax];
+ } CTL;
+
+// Control DEFinition
+typedef struct
+ {
+ TCHAR sz[20];
+ WNDPROC lpfnWndProc;
+ BOOL (* lpfnFCanSubclass)(HWND, LONG, WORD, WORD, HWND);
+ WORD msk;
+ } CDEF;
+
+// CLIent HooK
+typedef struct
+ {
+ HANDLE hinstApp;
+ HANDLE htask;
+ HHOOK hhook;
+ int iCount;
+ DWORD dwFlags;
+
+ } CLIHK;
+
+#ifdef WIN32
+#define iclihkMaxBig 1024
+#define iclihkMaxSmall 128
+#else
+#define iclihkMaxBig 32
+#define iclihkMaxSmall 4
+#endif
+
+#ifdef DLL
+#define iclihkMax iclihkMaxBig
+#else
+#ifdef SDLL
+#define iclihkMax iclihkMaxBig
+#else
+#define iclihkMax iclihkMaxSmall
+#define _loadds
+#endif
+#endif
+
+#ifdef SDLL
+extern const HINSTANCE _hModule;
+#endif
+
+// special styles
+// #define bitFCoolButtons 0x0001
+
+/*-----------------------------------------------------------------------
+|CTL3D Function Prototypes
+-----------------------------------------------------------------------*/
+PRIVATE VOID End3dDialogs(VOID);
+PRIVATE BOOL FAR FInit3dDialogs(VOID);
+PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent);
+PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce);
+PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph);
+PRIVATE VOID DeleteObjects(VOID);
+PRIVATE int IclihkFromHinst(HANDLE hinst);
+
+LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI CDListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+LRESULT __export _loadds WINAPI CDEditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+WORD __export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit);
+
+LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+
+BOOL FBtn(HWND, LONG, WORD, WORD, HWND);
+BOOL FEdit(HWND, LONG, WORD, WORD, HWND);
+BOOL FList(HWND, LONG, WORD, WORD, HWND);
+BOOL FComboList(HWND, LONG, WORD, WORD, HWND);
+BOOL FCombo(HWND, LONG, WORD, WORD, HWND);
+BOOL FStatic(HWND, LONG, WORD, WORD, HWND);
+
+HBITMAP PASCAL LoadUIBitmap(HANDLE, LPCTSTR, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF);
+
+#ifdef WIN32
+#ifdef DLL
+BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+#else
+#ifdef SDLL
+FAR BOOL Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+#else
+FAR BOOL LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+#endif
+#endif
+#else
+#ifdef DLL
+int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+#else
+#ifdef SDLL
+int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+#else
+#ifdef _BORLAND
+int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+#else
+int FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+#endif
+#endif
+#endif
+#endif
+
+#ifndef _BORLAND
+#ifndef WIN32
+#pragma alloc_text(INIT_TEXT, Ctl3dSetStyle)
+#pragma alloc_text(INIT_TEXT, Ctl3dColorChange)
+#pragma alloc_text(INIT_TEXT, Ctl3dGetVer)
+#pragma alloc_text(INIT_TEXT, Ctl3dRegister)
+#pragma alloc_text(INIT_TEXT, Ctl3dUnregister)
+#pragma alloc_text(INIT_TEXT, Ctl3dAutoSubclass)
+#pragma alloc_text(INIT_TEXT, Ctl3dEnabled)
+#pragma alloc_text(INIT_TEXT, Ctl3dWinIniChange)
+#pragma alloc_text(INIT_TEXT, DeleteObjects)
+#pragma alloc_text(INIT_TEXT, DeleteObjectNull)
+#pragma alloc_text(INIT_TEXT, InternalCtl3dColorChange)
+#ifdef SDLL
+#pragma alloc_text(INIT_TEXT, Ctl3dLibMain)
+#else
+#pragma alloc_text(INIT_TEXT, LibMain)
+#endif
+#pragma alloc_text(INIT_TEXT, FInit3dDialogs)
+#pragma alloc_text(INIT_TEXT, End3dDialogs)
+#pragma alloc_text(INIT_TEXT, LoadUIBitmap)
+#pragma alloc_text(INIT_TEXT, IclihkFromHinst)
+#endif
+#endif
+
+#ifndef WIN32
+#ifdef DLL
+int FAR PASCAL WEP(int);
+#pragma alloc_text(WEP_TEXT, WEP)
+#endif
+#endif
+
+/*-----------------------------------------------------------------------
+|CTL3D Globals
+-----------------------------------------------------------------------*/
+//These static varables are only access when running 16 bit Windows or Win32s
+//Since this is single threaded access they are OK to be statics and not protected.
+//
+static HHOOK hhookCallWndProcFilterProc;
+static FARPROC lpfnSubclassByHook;
+static HWND SubclasshWnd;
+
+#ifdef WIN32
+CRITICAL_SECTION g_CriticalSection;
+#endif
+
+typedef struct _g3d
+ {
+ BOOL f3dDialogs;
+ int cInited;
+ ATOM aCtl3dOld;
+ ATOM aCtl3dHighOld;
+ ATOM aCtl3dLowOld;
+ ATOM aCtl3d;
+ ATOM aCtl3dHigh;
+ ATOM aCtl3dLow;
+
+ ATOM aCtl3dDisable;
+ // module & windows stuff
+ HANDLE hinstLib;
+ HANDLE hmodLib;
+ WORD verWindows;
+ WORD verBase;
+
+ // drawing globals
+ CLRT clrt;
+ BRT brt;
+ HBITMAP hbmpCheckboxes;
+
+ // Hook cache
+ HANDLE htaskCache;
+ int iclihkCache;
+ int iclihkMac;
+ CLIHK rgclihk[iclihkMax];
+
+ // Control info
+ CTL mpctctl[ctMax];
+ FARPROC lpfnDefDlgWndProc;
+
+ // System Metrics
+ int dxFrame;
+ int dyFrame;
+ int dyCaption;
+ int dxSysMenu;
+
+ // Windows functions
+#ifndef WIN32
+#ifdef DLL
+ HHOOK (FAR PASCAL *lpfnSetWindowsHookEx)(int, HOOKPROC, HINSTANCE, HANDLE);
+ LRESULT (FAR PASCAL *lpfnCallNextHookEx)(HHOOK, int, WPARAM, LPARAM);
+ BOOL (FAR PASCAL *lpfnUnhookWindowsHookEx)(HHOOK);
+#endif
+#endif
+
+ // DBCS stuff
+ char chShortCutPrefix;
+ char fDBCS;
+
+ } G3D;
+
+G3D g3d;
+
+
+CSCONST(CDEF) mpctcdef[ctMax] =
+{
+ { TEXT("Button"), BtnWndProc3d, FBtn, CTL3D_BUTTONS },
+ { TEXT("ListBox"), ListWndProc3d, FList, CTL3D_LISTBOXES },
+ { TEXT("Edit"), EditWndProc3d, FEdit, CTL3D_EDITS },
+ { TEXT("ComboBox"), ComboWndProc3d, FCombo, CTL3D_COMBOS},
+ { TEXT("Static"), StaticWndProc3d, FStatic, CTL3D_STATICTEXTS|CTL3D_STATICFRAMES },
+ { TEXT("ComboLBox"), ListWndProc3d, FComboList, CTL3D_LISTBOXES },
+};
+
+
+CSCONST (WORD) mpicvSysColor[] =
+ {
+ COLOR_BTNHIGHLIGHT,
+ COLOR_BTNFACE,
+ COLOR_BTNSHADOW,
+ COLOR_BTNTEXT,
+ COLOR_WINDOW,
+ COLOR_WINDOWTEXT,
+ COLOR_GRAYTEXT,
+ COLOR_WINDOWFRAME
+ };
+
+#define WM_CHECKSUBCLASS_OLD (WM_USER+5443)
+#define WM_CHECKSUBCLASS (WM_USER+5444)
+
+/*-----------------------------------------------------------------------
+| CTL3D Utility routines
+-----------------------------------------------------------------------*/
+
+PRIVATE FARPROC LpfnGetDefWndProcNull(HWND hwnd)
+ {
+ if ( hwnd == NULL )
+ return NULL;
+
+ Win32Only(return (FARPROC) GetProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+ Win16Only(return (FARPROC) MAKELONG((UINT) GetProp(hwnd, (LPCSTR) g3d.aCtl3dLow),
+ GetProp(hwnd, (LPCSTR) g3d.aCtl3dHigh)));
+ }
+
+PRIVATE FARPROC LpfnGetDefWndProc(HWND hwnd, int ct)
+ {
+ FARPROC lpfnWndProc;
+
+ lpfnWndProc = LpfnGetDefWndProcNull(hwnd);
+ if ( lpfnWndProc == NULL ) {
+ if ( ct == ctMax )
+ {
+ lpfnWndProc = (FARPROC) g3d.lpfnDefDlgWndProc;
+ }
+ else
+ {
+ lpfnWndProc = (FARPROC) g3d.mpctctl[ct].lpfnDefProc;
+ }
+
+ Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
+ Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow, LOWORD(lpfnWndProc)));
+ Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
+ }
+ return lpfnWndProc;
+
+ }
+
+PRIVATE VOID SubclassWindow(HWND hwnd, FARPROC lpfnSubclassProc)
+ {
+ FARPROC lpfnWndProc;
+
+ // Make sure we don't double subclass (16 | 32 bit subclass??)
+ if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3dOld) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLowOld) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHighOld))
+ {
+ return;
+ }
+
+ // Is this already subclassed by CTL3D?
+ if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
+ {
+#ifdef WIN32
+ if (g3d.fDBCS && !IsWindowUnicode(hwnd))
+ {
+ TCHAR szClass[cchClassMax];
+ GetClassName(hwnd, szClass, cchClassMax);
+ if (lstrcmpi(szClass, TEXT("edit")) == 0)
+ {
+ lpfnWndProc = (FARPROC)SetWindowLongA(hwnd, GWL_WNDPROC,(LONG)lpfnSubclassProc);
+ goto SetProps;
+ }
+ }
+#endif
+
+ lpfnWndProc = (FARPROC)SetWindowLong((HWND) hwnd, GWL_WNDPROC, (LONG) lpfnSubclassProc);
+SetProps:
+ Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
+ Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow, LOWORD(lpfnWndProc)));
+ Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
+ }
+ }
+
+LRESULT __export _loadds WINAPI CallWndProcFilterProc(int code, WPARAM wParam, LPARAM lParam)
+{
+ CWPSTRUCT FAR *cwpStruct;
+ LONG l;
+
+ cwpStruct = (CWPSTRUCT FAR *) lParam;
+
+ l = CallNextHookEx(hhookCallWndProcFilterProc, code, wParam, lParam);
+
+ if ( cwpStruct->hwnd == SubclasshWnd )
+ {
+ BOOL fSubclass;
+ UnhookWindowsHookEx(hhookCallWndProcFilterProc);
+
+ if (g3d.verWindows >= ver40 && (GetWindowLong(cwpStruct->hwnd, GWL_STYLE) & 0x04))
+ fSubclass = fFalse;
+ else
+ fSubclass = fTrue;
+ SendMessage(cwpStruct->hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+ if (fSubclass)
+ SubclassWindow(cwpStruct->hwnd, lpfnSubclassByHook);
+
+ hhookCallWndProcFilterProc = 0L;
+ lpfnSubclassByHook = NULL;
+ SubclasshWnd = NULL;
+ }
+
+ return l;
+}
+
+
+PRIVATE VOID HookSubclassWindow(HWND hWnd, FARPROC lpfnSubclass)
+{
+ //
+ // Windows 3.1 ( 16 bit ) and Win32s can't sublcass in
+ // WH_CBT hook. Must set up a MSG hook and subclasss at
+ // WM_GETMINMAXINFO ( for dialogs ) or WM_NCCREATE ( for controls )
+ // Any other message and we are out of here.
+ //
+ // Notes from the inside:
+ //
+ // The only reason not to get the WM_GETMINMAXINFO/WM_NCCREATE message
+ // is if another CBT hook did not allow the window create.
+ // This code only runs/works on non multithreaded systems. Thus the global
+ // to hold the Hook Proc and subclass proc is OK.
+ //
+
+ lpfnSubclassByHook = lpfnSubclass;
+ SubclasshWnd = hWnd;
+
+ Win32Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentThreadId()));
+ Win16Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentTask()));
+}
+
+PRIVATE LRESULT CleanupSubclass(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
+ {
+ FARPROC lpfnWinProc;
+ LRESULT lRet;
+
+ lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+ lRet = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+ Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+ RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dDisable);
+ return lRet;
+ }
+
+
+PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph)
+ {
+ if (*ph != NULL)
+ {
+ DeleteObject(*ph);
+ *ph = NULL;
+ }
+ }
+
+PRIVATE VOID DeleteObjects(VOID)
+ {
+ int icv;
+
+ for(icv = 0; icv < icvBrushMax; icv++)
+ DeleteObjectNull(&g3d.brt.mpicvhbr[icv]);
+ DeleteObjectNull(&g3d.hbmpCheckboxes);
+ }
+
+
+PRIVATE VOID PatFill(HDC hdc, RC FAR *lprc)
+ {
+ PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
+ }
+
+
+/*-----------------------------------------------------------------------
+| DrawRec3d
+|
+|
+| Arguments:
+| HDC hdc:
+| RC FAR *lprc:
+| LONG cvUL:
+| LONG cvLR:
+| WORD grbit;
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+PRIVATE VOID DrawRec3d(HDC hdc, RC FAR *lprc, ICV icvUL, ICV icvLR, DR3 dr3)
+ {
+ COLORREF cvSav;
+ RC rc;
+
+ cvSav = SetBkColor(hdc, g3d.clrt.rgcv[icvUL]);
+
+ // top
+ rc = *lprc;
+ rc.yBot = rc.yTop+1;
+ if (dr3 & dr3Top)
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+ (LPCTSTR) NULL, 0, (int far *) NULL);
+
+ // left
+ rc.yBot = lprc->yBot;
+ rc.xRight = rc.xLeft+1;
+ if (dr3 & dr3Left)
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+ (LPCTSTR) NULL, 0, (int far *) NULL);
+
+ if (icvUL != icvLR)
+ SetBkColor(hdc, g3d.clrt.rgcv[icvLR]);
+
+ // right
+ rc.xRight = lprc->xRight;
+ rc.xLeft = rc.xRight-1;
+ if (dr3 & dr3Right)
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+ (LPCTSTR) NULL, 0, (int far *) NULL);
+
+ // bot
+ if (dr3 & dr3Bot)
+ {
+ rc.xLeft = lprc->xLeft;
+ rc.yTop = rc.yBot-1;
+ if (dr3 & dr3HackBotRight)
+ rc.xRight -=2;
+ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+ (LPCTSTR) NULL, 0, (int far *) NULL);
+ }
+
+ SetBkColor(hdc, cvSav);
+
+ }
+
+#ifdef CANTUSE
+// Windows forces dialog fonts to be BOLD...URRRGH
+PRIVATE VOID MyDrawText(HWND hwnd, HDC hdc, LPSTR lpch, int cch, RC FAR *lprc, int dt)
+ {
+ TEXTMETRIC tm;
+ BOOL fChisled;
+
+ fChisled = fFalse;
+ if (!IsWindowEnabled(hwnd))
+ {
+ GetTextMetrics(hdc, &tm);
+ if (tm.tmWeight > 400)
+ SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+ else
+ {
+ fChisled = fTrue;
+ SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
+ OffsetRect((LPRECT) lprc, -1, -1);
+ }
+ }
+ DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
+ if (fChisled)
+ {
+ SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
+ OffsetRect((LPRECT) lprc, 1, 1);
+ DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
+ }
+ }
+#endif
+
+
+PRIVATE VOID DrawInsetRect3d(HDC hdc, RC FAR *prc, DR3 dr3)
+ {
+ RC rc;
+
+ rc = *prc;
+ DrawRec3d(hdc, &rc, icvWindowFrame, icvBtnFace, (WORD)(dr3 & dr3All));
+ rc.xLeft--;
+ rc.yTop--;
+ rc.xRight++;
+ rc.yBot++;
+ DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3);
+ }
+
+
+PRIVATE VOID ClipCtlDc(HWND hwnd, HDC hdc)
+ {
+ RC rc;
+
+ GetClientRect(hwnd, (LPRECT) &rc);
+ IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
+ }
+
+
+PRIVATE int IclihkFromHinst(HANDLE hinst)
+ {
+ int iclihk;
+
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ if (g3d.rgclihk[iclihk].hinstApp == hinst)
+ return iclihk;
+ return -1;
+ }
+
+
+PRIVATE VOID MyGetTextExtent(HDC hdc, LPTSTR lpsz, int FAR *lpdx, int FAR *lpdy)
+ {
+ LPTSTR lpch;
+ TCHAR szT[256];
+
+ lpch = szT;
+ while(*lpsz != '\000')
+ {
+ if (*lpsz == '&')
+ {
+ lpsz++;
+ if (*lpsz == '\000')
+ break;
+ }
+//begin DBCS: far east short cut key support
+ else if (g3d.fDBCS)
+ {
+ if (*lpsz == g3d.chShortCutPrefix)
+ { // skip only prefix
+ lpsz++;
+ if (*lpsz == '\000')
+ break;
+ }
+ else if (*lpsz == chShortCutSbcsPrefix || *lpsz == chShortCutDbcsPrefix)
+ { // skip both prefix and short cut key
+ lpsz++;
+ if (*lpsz == '\000')
+ break;
+ lpsz = Win32Or16(CharNext(lpsz),AnsiNext(lpsz));
+ continue;
+ }
+ }
+//end DBCS
+ *lpch++ = *lpsz++;
+ }
+ *lpch = '\000';
+#ifdef WIN32
+ {
+ SIZE pt;
+
+ GetTextExtentPoint(hdc, szT, lstrlen(szT), &pt);
+ *lpdx = pt.cx;
+ *lpdy = pt.cy;
+ }
+#else
+ {
+ long dwExt;
+
+ dwExt = GetTextExtent(hdc, szT, lpch-(char far *)szT);
+ *lpdx = LOWORD(dwExt);
+ // Check for Hangeul Windows - JeeP 011194
+ if ( (g3d.verWindows >= ver31 && GetSystemMetrics(SM_DBCSENABLED)) ||
+ (IsDBCSLeadByte(0xa1) && !IsDBCSLeadByte(0xa0)) )
+ *lpdy = HIWORD(dwExt)+1;
+ else
+ *lpdy = HIWORD(dwExt);
+ }
+#endif
+ }
+
+
+/*-----------------------------------------------------------------------
+| CTL3D Publics
+-----------------------------------------------------------------------*/
+
+
+PUBLIC BOOL WINAPI Ctl3dRegister(HANDLE hinstApp)
+ {
+
+#ifdef WIN32
+#ifndef DLL
+ InitializeCriticalSection(&g_CriticalSection);
+#endif
+ EnterCriticalSection(&g_CriticalSection);
+#endif
+
+ g3d.cInited++;
+
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+
+ if (g3d.cInited == 1)
+ {
+#ifndef DLL
+#ifdef SDLL
+ Win32Only(Ctl3dLibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
+ Win16Only(Ctl3dLibMain(hinstApp, 0, 0, (LPSTR) NULL));
+#else
+ Win32Only(LibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
+ Win16Only(LibMain(hinstApp, 0, 0, (LPSTR) NULL));
+#endif
+#endif
+ FInit3dDialogs();
+ }
+
+ if (Ctl3dIsAutoSubclass())
+ Ctl3dAutoSubclass(hinstApp);
+
+ return g3d.f3dDialogs;
+ }
+
+
+PUBLIC BOOL WINAPI Ctl3dUnregister(HANDLE hinstApp)
+ {
+ int iclihk;
+ HANDLE hTask;
+
+ //
+ // Find the task's hook
+ //
+ Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+ Win16Only(hTask = GetCurrentTask());
+
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ {
+ if (g3d.rgclihk[iclihk].htask == hTask)
+ {
+ g3d.rgclihk[iclihk].iCount--;
+ if ( g3d.rgclihk[iclihk].iCount == 0 || hinstApp == g3d.rgclihk[iclihk].hinstApp)
+ {
+ Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+#ifdef DLL
+ Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
+#else
+ Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+#endif
+ g3d.iclihkMac--;
+ while(iclihk < g3d.iclihkMac)
+ {
+ g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
+ iclihk++;
+ }
+ }
+ }
+ }
+
+ g3d.cInited--;
+
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+
+ if (g3d.cInited == 0)
+ {
+ End3dDialogs();
+ }
+ return fTrue;
+ }
+
+
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dAutoSubclass
+|
+| Automatically subclasses all dialogs of the client app.
+|
+| Note: Due to bugs in Commdlg, an app should still call Ctl3dSubclassDlg
+| for the Commdlg OpenFile and PageSetup dialogs.
+|
+| Arguments:
+| HANDLE hinstApp:
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dAutoSubclass(HANDLE hinstApp)
+{
+ return Ctl3dAutoSubclassEx(hinstApp, 0);
+}
+
+PUBLIC BOOL WINAPI Ctl3dAutoSubclassEx(HANDLE hinstApp, DWORD dwFlags)
+ {
+ HHOOK hhook;
+ HANDLE htask;
+ int iclihk;
+
+ if (g3d.verWindows < ver31)
+ return fFalse;
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+#ifdef WIN32
+ // CTL3D_SUBCLASS_DYNCREATE is considered default in Win32, but
+ // not Win16 for backward compatibility reasons.
+ dwFlags |= CTL3D_SUBCLASS_DYNCREATE;
+#endif
+ // CTL3D_NOSUBCLASS_DYNCREATE always overrides CTL3D_SUBCLASS_DYNCREATE
+ if (dwFlags & CTL3D_NOSUBCLASS_DYNCREATE)
+ dwFlags &= ~(CTL3D_NOSUBCLASS_DYNCREATE|CTL3D_SUBCLASS_DYNCREATE);
+
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+
+ if (g3d.iclihkMac == iclihkMax)
+ goto Fail;
+
+ Win32Only(htask = (HANDLE)GetCurrentThreadId());
+ Win16Only(htask = GetCurrentTask());
+ //
+ // Don't set the hook twice for the same task....
+ //
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ {
+ if (g3d.rgclihk[iclihk].htask == htask)
+ {
+ g3d.rgclihk[iclihk].iCount++;
+ goto Success;
+ }
+ }
+
+ Win32Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC)Ctl3dHook, g3d.hmodLib, (DWORD)htask));
+#ifdef DLL
+ Win16Only(hhook = (*g3d.lpfnSetWindowsHookEx)(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
+#else
+ Win16Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
+#endif
+ if (hhook != NULL)
+ {
+ g3d.rgclihk[g3d.iclihkMac].hinstApp = hinstApp;
+ g3d.rgclihk[g3d.iclihkMac].htask = htask;
+ g3d.rgclihk[g3d.iclihkMac].hhook = hhook;
+ g3d.rgclihk[g3d.iclihkMac].iCount = 1;
+ g3d.rgclihk[g3d.iclihkMac].dwFlags = dwFlags;
+ g3d.htaskCache = htask;
+ g3d.iclihkCache = g3d.iclihkMac;
+ g3d.iclihkMac++;
+Success:
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return fTrue;
+ }
+Fail:
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return fFalse;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dIsAutoSubclass
+|
+| Returns:
+| Whether this task has Automatic Subclassing Enabled
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dIsAutoSubclass()
+ {
+ int iclihk;
+ HANDLE hTask;
+
+ Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+ Win16Only(hTask = GetCurrentTask());
+
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ {
+ if (g3d.rgclihk[iclihk].htask == hTask)
+ {
+ return TRUE;
+ }
+ }
+ // didn't find task in hook table.
+ return FALSE;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dUnAutoSubclass
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dUnAutoSubclass()
+ {
+ int iclihk;
+ HANDLE hTask;
+
+ // Find the task's hook
+ //
+ //
+ Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+ Win16Only(hTask = GetCurrentTask());
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ {
+ if (g3d.rgclihk[iclihk].htask == hTask)
+ {
+ g3d.rgclihk[iclihk].iCount--;
+ if ( g3d.rgclihk[iclihk].iCount == 0 )
+ {
+ Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+#ifdef DLL
+ Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
+#else
+ Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+#endif
+ g3d.iclihkMac--;
+ while(iclihk < g3d.iclihkMac)
+ {
+ g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
+ iclihk++;
+ }
+ }
+ }
+ }
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return TRUE;
+ }
+
+WORD __export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit)
+ {
+#ifdef OLD
+ WORD grbitOld;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ grbitOld = grbitStyle;
+ if (grbit != 0)
+ grbitStyle = grbit;
+
+ if (hinst != NULL && lpszName != NULL)
+ {
+ HBITMAP hbmpCheckboxesNew;
+
+ hbmpCheckboxesNew = LoadUIBitmap(hinst, (LPCSTR) lpszName,
+ g3d.clrt.rgcv[icvWindowText],
+ g3d.clrt.rgcv[icvBtnFace],
+ g3d.clrt.rgcv[icvBtnShadow],
+ g3d.clrt.rgcv[icvBtnHilite],
+ g3d.clrt.rgcv[icvWindow],
+ g3d.clrt.rgcv[icvWindowFrame]);
+ if (hbmpCheckboxesNew != NULL)
+ {
+ DeleteObjectNull(&g3d.hbmpCheckboxes);
+ g3d.hbmpCheckboxes = hbmpCheckboxesNew;
+ }
+ }
+
+ return grbitOld;
+#endif
+ return 0;
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dGetVer
+|
+| Returns version of CTL3D library
+|
+| Returns:
+| Major version # in hibyte, minor version # in lobyte
+|
+-----------------------------------------------------------------------*/
+PUBLIC WORD WINAPI Ctl3dGetVer(void)
+ {
+ return 0x0231;
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dEnabled
+|
+| Returns:
+| Whether or not controls will be draw with 3d effects
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dEnabled(void)
+ {
+ return g3d.f3dDialogs;
+ }
+
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dSubclassCtl
+|
+| Subclasses an individual control
+|
+| Arguments:
+| HWND hwnd:
+|
+| Returns:
+| fTrue if control was successfully subclassed
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dSubclassCtl(HWND hwnd)
+ {
+ if (!g3d.f3dDialogs)
+ return fFalse;
+ return DoSubclassCtl(hwnd, CTL3D_ALL, OUTCBTHOOK, NULL);
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dUnsubclassCtl
+|
+| Un-Subclasses an individual control
+|
+| Arguments:
+| HWND hwnd:
+|
+| Returns:
+| fTrue if control was successfully subclassed
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dUnsubclassCtl(HWND hwnd)
+ {
+ FARPROC lpfnWinProc;
+ HWND hwndKids;
+ int ct;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ lpfnWinProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+
+ // Is it a control
+ for (ct = 0; ct < ctMax; ct++)
+ {
+ if ( lpfnWinProc == g3d.mpctctl[ct].lpfn )
+ {
+ lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+ Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
+ lpfnWinProc = NULL;
+ ct = ctMax+10;
+ }
+ }
+
+ // How about a dlg ?
+ if ( ct == ctMax )
+ {
+ if ( lpfnWinProc == (FARPROC) Ctl3dDlgProc )
+ {
+ lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+ Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
+ lpfnWinProc = NULL;
+ }
+ else
+ {
+ // None of the above, add disable property
+ if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
+ GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh))
+ {
+ SetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable, (HANDLE) 1);
+ }
+ }
+ }
+
+ //
+ // Now unsubclass all the kids
+ //
+ for (hwndKids = GetWindow(hwnd, GW_CHILD); hwndKids != NULL;
+ hwndKids = GetWindow(hwndKids, GW_HWNDNEXT))
+ {
+ Ctl3dUnsubclassCtl(hwndKids);
+ }
+
+ return fTrue;
+
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dSubclassCtlEx
+|
+| Actually subclass the control
+|
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dSubclassCtlEx(HWND hwnd, int ct)
+ {
+ LONG style;
+ BOOL fCan;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ if (ct < 0 || ct > ctMax)
+ return fFalse;
+
+ // Is this already subclassed by CTL3D?
+ if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
+ return fFalse;
+
+ // Only subclass it if it is something that we'd normally subclass
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, CTL3D_ALL,
+ OUTCBTHOOK, GetParent(hwnd));
+ if (fCan == fTrue)
+ SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+
+ return fTrue;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dSubclassDlg
+|
+| Call this during WM_INITDIALOG processing.
+|
+| Arguments:
+| hwndDlg:
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dSubclassDlg(HWND hwndDlg, WORD grbit)
+ {
+ HWND hwnd;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+ {
+ DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, NULL);
+ }
+ return fTrue;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dCheckSubclassDlg
+|
+| Call this during WM_INITDIALOG processing.
+|
+| Arguments:
+| hwndDlg:
+|
+-----------------------------------------------------------------------*/
+PRIVATE void CheckChildSubclass(HWND hwnd, WORD grbit, HWND hwndParent)
+{
+ // Is this already subclassed by CTL3D?
+ // Is our property there ?
+ if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
+ {
+ // No, how did this slip by, try a subclass again.
+ DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
+ }
+ else
+ {
+ // Yes, we have subclassed this control.
+ // Is our subclass still on the chain ?
+ BOOL fSubclass;
+
+ // Make sure subclassing isn't disabled...
+ if (GetProp(hwnd, (LPCTSTR)g3d.aCtl3dDisable))
+ return;
+
+ fSubclass = 666;
+ SendMessage((HWND) hwnd, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+ if ( fSubclass == 666 )
+ SendMessage((HWND) hwnd, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+
+ if ( fSubclass == 666 ) // Evil
+ {
+ // We have been un-subclassed by some bad app ( common dialogs in Win16 )
+ // Remove the Prop, and subclass again, take that.
+ Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+ Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+ DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
+ }
+ }
+}
+
+PUBLIC BOOL WINAPI Ctl3dCheckSubclassDlg(HWND hwndDlg, WORD grbit)
+ {
+ HWND hwnd, hwnd2;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ for (hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+ {
+ CheckChildSubclass(hwnd, grbit, NULL);
+ for (hwnd2 = GetWindow(hwnd, GW_CHILD); hwnd2 != NULL;
+ hwnd2 = GetWindow(hwnd2, GW_HWNDNEXT))
+ {
+ CheckChildSubclass(hwnd2, grbit, hwnd);
+ }
+ }
+
+ return fTrue;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dSubclassDlgEx
+|
+| Call this during WM_INITDIALOG processing. This is like
+| Ctl3dSubclassDlg but it also subclasses the dialog window itself
+| so the app doesn't need to.
+|
+| Arguments:
+| hwndDlg:
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dSubclassDlgEx(HWND hwndDlg, DWORD grbit)
+ {
+ HWND hwnd;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+ {
+ DoSubclassCtl(hwnd, LOWORD(grbit), OUTCBTHOOK, NULL);
+ }
+
+ //
+ // Now Subclass the dialog window as well
+ //
+ SubclassWindow((HWND) hwndDlg, (FARPROC)Ctl3dDlgProc);
+
+ return fTrue;
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dCtlColor
+|
+| Common CTL_COLOR processor for 3d UITF dialogs & alerts.
+|
+| Arguments:
+| hdc:
+| lParam:
+|
+| Returns:
+| appropriate brush if g3d.f3dDialogs. Returns fFalse otherwise
+|
+-----------------------------------------------------------------------*/
+PUBLIC HBRUSH WINAPI Ctl3dCtlColor(HDC hdc, LPARAM lParam)
+ {
+#ifdef WIN32
+ return (HBRUSH) fFalse;
+#else
+ HWND hwndParent;
+
+ Assert(CTLCOLOR_MSGBOX < CTLCOLOR_BTN);
+ Assert(CTLCOLOR_EDIT < CTLCOLOR_BTN);
+ Assert(CTLCOLOR_LISTBOX < CTLCOLOR_BTN);
+ if(g3d.f3dDialogs)
+ {
+ if (HIWORD(lParam) >= CTLCOLOR_LISTBOX)
+ {
+ if (HIWORD(lParam) == CTLCOLOR_LISTBOX &&
+ (g3d.verWindows >= ver40 ||
+ ((GetWindow(LOWORD(lParam), GW_CHILD) == NULL ||
+ (GetWindowLong(LOWORD(lParam), GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
+ {
+ // if it doesn't have a child then it must be a list box
+ // don't do brush stuff for drop down lists or else
+ // it draws funny grey inside the edit rect
+ goto DefWP;
+ }
+ SetTextColor(hdc, g3d.clrt.rgcv[icvBtnText]);
+ SetBkColor(hdc, g3d.clrt.rgcv[icvBtnFace]);
+ return g3d.brt.mpicvhbr[icvBtnFace];
+ }
+ }
+DefWP:
+ hwndParent = GetParent(LOWORD(lParam));
+ if (hwndParent == NULL)
+ return fFalse;
+ return (HBRUSH) DefWindowProc(hwndParent, WM_CTLCOLOR, (WPARAM) hdc, (LONG) lParam);
+#endif
+ }
+
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dCtlColorEx
+|
+| Common CTL_COLOR processor for 3d UITF dialogs & alerts.
+|
+| Arguments:
+|
+| Returns:
+| appropriate brush if g3d.f3dDialogs. Returns fFalse otherwise
+|
+-----------------------------------------------------------------------*/
+PUBLIC HBRUSH WINAPI Ctl3dCtlColorEx(UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+#ifdef WIN32
+ Assert(WM_CTLCOLORMSGBOX < WM_CTLCOLORBTN);
+ Assert(WM_CTLCOLOREDIT < WM_CTLCOLORBTN);
+ Assert(WM_CTLCOLORLISTBOX < WM_CTLCOLORBTN);
+ if(g3d.f3dDialogs)
+ {
+ if (wm >= WM_CTLCOLORLISTBOX && wm != WM_CTLCOLORSCROLLBAR)
+ {
+ if (wm == WM_CTLCOLORLISTBOX &&
+ (g3d.verWindows >= ver40 ||
+ ((GetWindow((HWND) lParam, GW_CHILD) == NULL ||
+ (GetWindowLong((HWND) lParam, GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
+ {
+ // if it doesn't have a child then it must be a list box
+ // don't do brush stuff for drop down lists or else
+ // it draws funny grey inside the edit rect
+ return (HBRUSH) fFalse;
+ }
+ SetTextColor((HDC) wParam, g3d.clrt.rgcv[icvBtnText]);
+ SetBkColor((HDC) wParam, g3d.clrt.rgcv[icvBtnFace]);
+ return g3d.brt.mpicvhbr[icvBtnFace];
+ }
+ }
+ return (HBRUSH) fFalse;
+#else
+ return Ctl3dCtlColor(wParam, lParam);
+#endif
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dColorChange
+|
+| App calls this when it gets a WM_SYSCOLORCHANGE message
+|
+| Returns:
+| TRUE if successful.
+|
+-----------------------------------------------------------------------*/
+PUBLIC BOOL WINAPI Ctl3dColorChange(VOID)
+ {
+ BOOL bResult;
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+ bResult = InternalCtl3dColorChange(fFalse);
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return bResult;
+ }
+
+PRIVATE LONG WINAPI
+Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP);
+
+/*-----------------------------------------------------------------------
+| Ctl3dDlgFramePaint
+|
+| App calls this when it gets a NC_PAINT message
+|
+| Returns:
+| TRUE if successful.
+|
+-----------------------------------------------------------------------*/
+PUBLIC LONG WINAPI Ctl3dDlgFramePaint(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, TRUE);
+ }
+
+// Ctl3dDlgFramePaintI used only internally by Ctl3d
+PRIVATE LONG WINAPI
+Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP)
+ {
+ LONG lResult;
+ LONG lStyle;
+ BOOL fBorder;
+
+ WNDPROC defProc = fDefWP ? NULL : (WNDPROC) LpfnGetDefWndProc(hwnd, ctMax);
+
+ if (defProc != NULL)
+ lResult = CallWindowProc((FARPROC)defProc, hwnd, wm, wParam, lParam);
+ else
+ lResult = DefWindowProc(hwnd, wm, wParam, lParam);
+
+ if (!g3d.f3dDialogs)
+ return lResult;
+
+ if ( IsIconic(hwnd) )
+ return lResult;
+
+ fBorder = CTL3D_BORDER;
+ SendMessage(hwnd, WM_DLGBORDER, 0, (LPARAM)(int FAR *)&fBorder);
+ lStyle = GetWindowLong(hwnd, GWL_STYLE);
+ if (fBorder != CTL3D_NOBORDER && (lStyle & (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME)) == (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME))
+ {
+ BOOL fCaption;
+ HBRUSH hbrSav;
+ HDC hdc;
+ RC rc;
+ RC rcFill;
+ int dyFrameTop;
+
+ fCaption = (lStyle & WS_CAPTION) == WS_CAPTION;
+ dyFrameTop = g3d.dyFrame - (fCaption ? dyBorder : 0);
+
+ hdc = GetWindowDC(hwnd);
+ GetWindowRect(hwnd, (LPRECT) &rc);
+ rc.xRight = rc.xRight-rc.xLeft;
+ rc.yBot = rc.yBot-rc.yTop;
+ rc.xLeft = rc.yTop = 0;
+
+ DrawRec3d(hdc, &rc, icvBtnShadow, icvWindowFrame, dr3All);
+ InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
+ InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
+
+ hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
+ rcFill = rc;
+ // Left
+ rcFill.xRight = rcFill.xLeft+g3d.dxFrame;
+ PatFill(hdc, &rcFill);
+ // Right
+ OffsetRect((LPRECT) &rcFill, rc.xRight-rc.xLeft-g3d.dxFrame, 0);
+ PatFill(hdc, &rcFill);
+ // Top
+ rcFill.xLeft = rc.xLeft + g3d.dxFrame;
+ rcFill.xRight = rc.xRight - g3d.dxFrame;
+ rcFill.yBot = rcFill.yTop+dyFrameTop;
+ PatFill(hdc, &rcFill);
+ if (fCaption)
+ {
+ RC rcT;
+
+ rcT = rcFill;
+ rcT.yTop += dyFrameTop;
+ rcT.yBot = rcT.yTop + g3d.dyCaption;
+ DrawRec3d(hdc, &rcT, icvBtnShadow, icvBtnHilite, dr3All);
+ }
+
+ // Bottom
+ rcFill.yTop += rc.yBot-rc.yTop-g3d.dxFrame;
+ rcFill.yBot = rcFill.yTop + g3d.dyFrame;
+ PatFill(hdc, &rcFill);
+#ifdef CHISLEBORDER
+ if (fBorder == CTL3D_CHISLEBORDER)
+ {
+ // This code doesn't work because it draws in the client area
+ GetClientRect(hwnd, (LPRECT) &rc);
+ OffsetRect((LPRECT) &rc, g3d.dxFrame+2*dxBorder, fCaption ? g3d.dyFrame+g3d.dyCaption : g3d.dyFrame+dyBorder);
+ DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3Bot|dr3Left|dr3Right);
+ rc.xLeft++;
+ rc.xRight--;
+ rc.yBot--;
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3Bot|dr3Left|dr3Right);
+ }
+#endif
+ SelectObject(hdc, hbrSav);
+ ReleaseDC(hwnd, hdc);
+ }
+ return lResult;
+ }
+
+
+//begin DBCS: far east short cut key support
+/*-----------------------------------------------------------------------
+| CTL3D Far East Support
+-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| Ctl3dWinIniChange
+|
+| App calls this when it gets a WM_WININICHANGE message
+|
+| Returns:
+| none
+|
+-----------------------------------------------------------------------*/
+PUBLIC VOID WINAPI Ctl3dWinIniChange(void)
+ {
+ TCHAR szShortCutMode[cchShortCutModeMax];
+ CodeLpszDecl(szSectionWindows, TEXT("windows"));
+ CodeLpszDecl(szEntryShortCutKK, TEXT("kanjimenu"));
+ CodeLpszDecl(szEntryShortCutCH, TEXT("hangeulmenu"));
+ CodeLpszDecl(szShortCutSbcsKK, TEXT("roman"));
+ CodeLpszDecl(szShortCutSbcsCH, TEXT("english"));
+ CodeLpszDecl(szShortCutDbcsKK, TEXT("kanji"));
+ CodeLpszDecl(szShortCutDbcsCH, TEXT("hangeul"));
+
+ if (!g3d.fDBCS)
+ return;
+
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+
+ g3d.chShortCutPrefix = chShortCutSbcsPrefix;
+ GetProfileString(szSectionWindows, szEntryShortCutKK, szShortCutSbcsKK, szShortCutMode, cchShortCutModeMax - 1);
+ if (!lstrcmpi(szShortCutMode, szShortCutDbcsKK))
+ g3d.chShortCutPrefix = chShortCutDbcsPrefix;
+ GetProfileString(szSectionWindows, szEntryShortCutCH, szShortCutSbcsCH, szShortCutMode, cchShortCutModeMax - 1);
+ if (!lstrcmpi(szShortCutMode, szShortCutDbcsCH))
+ g3d.chShortCutPrefix = chShortCutDbcsPrefix;
+
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ }
+//end DBCS
+
+
+
+/*-----------------------------------------------------------------------
+| CTL3D Internal Routines
+-----------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------
+| FInit3dDialogs
+|
+| Initialized 3d stuff
+|
+-----------------------------------------------------------------------*/
+PRIVATE BOOL FAR FInit3dDialogs(VOID)
+ {
+ HDC hdc;
+ WNDCLASS wc;
+
+#ifdef DLL
+#ifdef V2
+ int nChars;
+ LPTSTR pCh;
+ static TCHAR MyDirectory[260];
+ TCHAR OkDirectory[260];
+#endif
+#endif
+
+ //if (g3d.verWindows >= ver40)
+ // {
+ // g3d.f3dDialogs = fFalse;
+ // return fFalse;
+ // }
+
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+
+#ifdef DLL
+#ifdef V2
+
+#ifdef WIN32
+ {
+ TCHAR szT[2];
+ CodeLpszDecl(szSpecial, TEXT("Ctl3d_RunAlways"));
+ if (GetEnvironmentVariable(szSpecial, szT, 2) != 0 && szT[0] == '1')
+ {
+ goto AllowBadInstall;
+ }
+ }
+#endif
+
+#ifdef WIN32
+#ifdef UNICODE
+ if (GetVersion() & 0x80000000)
+ {
+ Win16Or32(
+ CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+ CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+ CodeLpszDeclA(lpszBadInstMsg,
+ "This application uses CTL3D32.DLL, which is not the correct version. "
+ "This version of CTL3D32.DLL is designed only for Windows NT systems.");
+ MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+#else
+ if (!(GetVersion() & 0x80000000))
+ {
+ Win16Or32(
+ CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+ CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+ CodeLpszDeclA(lpszBadInstMsg,
+ "This application uses CTL3D32.DLL, which is not the correct version. "
+ "This version of CTL3D32.DLL is designed only for Win32s or Windows 95 systems.");
+ MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+#endif
+#endif
+#ifndef SPECIAL_WOW_VERSION
+ nChars = GetModuleFileName(g3d.hinstLib, MyDirectory, sizeof(MyDirectory)Win32Only(/sizeof(TCHAR)));
+ for (pCh = (LPTSTR)(MyDirectory+nChars-1);
+ pCh >= (LPTSTR)MyDirectory;
+ pCh = Win32Or16(CharPrev(MyDirectory, pCh),AnsiPrev(MyDirectory, pCh)))
+ {
+ if ( *pCh == '\\' )
+ {
+ if ( *(pCh-1) != ':' )
+ *pCh = 0;
+ else
+ *(pCh+1) = 0;
+ break;
+ }
+ }
+
+ nChars = GetSystemDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
+ if ( lstrcmpi(MyDirectory,OkDirectory ) )
+ {
+ nChars = GetWindowsDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
+ if ( lstrcmpi(MyDirectory,OkDirectory ) )
+ {
+ Win16Or32(
+ CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+ CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+ Win16Or32(
+ CodeLpszDeclA(lpszBadInstMsg,
+ "This application uses CTL3DV2.DLL, which has not been correctly installed. "
+ "CTL3DV2.DLL must be installed in the Windows system directory."),
+ CodeLpszDeclA(lpszBadInstMsg,
+ "This application uses CTL3D32.DLL, which has not been correctly installed. "
+ "CTL3D32.DLL must be installed in the Windows system directory."));
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK );
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+ }
+#endif //!SPECIAL_WOW_VERSION
+
+Win32Only(AllowBadInstall:;)
+#endif
+#endif
+
+ hdc = GetDC(NULL);
+ g3d.f3dDialogs = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES) >= 4;
+ // Win 3.1 EGA lies to us...
+ if(GetSystemMetrics(SM_CYSCREEN) == 350 && GetSystemMetrics(SM_CXSCREEN) == 640)
+ g3d.f3dDialogs = fFalse;
+ ReleaseDC(NULL, hdc);
+ if (g3d.f3dDialogs)
+ {
+ int ct;
+ CodeLpszDecl(lpszC3dD, TEXT("C3dD"));
+
+ CodeLpszDecl(lpszC3dOld, TEXT("C3d"));
+ CodeLpszDecl(lpszC3dLOld, TEXT("C3dL"));
+ CodeLpszDecl(lpszC3dHOld, TEXT("C3dH"));
+ CodeLpszDecl(lpszC3d, TEXT("C3dNew"));
+ CodeLpszDecl(lpszC3dL, TEXT("C3dLNew"));
+ CodeLpszDecl(lpszC3dH, TEXT("C3dHNew"));
+
+ g3d.aCtl3dOld = GlobalAddAtom(lpszC3dOld);
+ if (g3d.aCtl3dOld == 0)
+ {
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+ g3d.aCtl3d = GlobalAddAtom(lpszC3d);
+ if (g3d.aCtl3d == 0)
+ {
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+
+ g3d.aCtl3dLowOld = GlobalAddAtom(lpszC3dLOld);
+ g3d.aCtl3dHighOld = GlobalAddAtom(lpszC3dHOld);
+ if (g3d.aCtl3dLowOld == 0 || g3d.aCtl3dHighOld == 0)
+ {
+ g3d.f3dDialogs = fFalse;
+ return fFalse;
+ }
+
+ g3d.aCtl3dLow = GlobalAddAtom(lpszC3dL);
+ g3d.aCtl3dHigh = GlobalAddAtom(lpszC3dH);
+ if (g3d.aCtl3dLow == 0 || g3d.aCtl3dHigh == 0)
+ {
+ g3d.f3dDialogs = fFalse;
+ return fFalse;
+ }
+
+ g3d.aCtl3dDisable = GlobalAddAtom(lpszC3dD);
+ if (g3d.aCtl3dDisable == 0)
+ {
+ g3d.f3dDialogs = fFalse;
+ goto Return;
+ }
+
+ // DBCS
+ g3d.fDBCS = GetSystemMetrics(SM_DBCSENABLED);
+ Ctl3dWinIniChange();
+
+ if (InternalCtl3dColorChange(fTrue)) // load bitmap & brushes
+ {
+ for (ct = 0; ct < ctMax; ct++)
+ {
+ g3d.mpctctl[ct].lpfn = (FARPROC)mpctcdef[ct].lpfnWndProc;
+ Assert(g3d.mpctctl[ct].lpfn != NULL);
+ GetClassInfo(NULL, mpctcdef[ct].sz, (LPWNDCLASS) &wc);
+ g3d.mpctctl[ct].lpfnDefProc = wc.lpfnWndProc;
+ }
+ if (GetClassInfo(NULL, WC_DIALOG, &wc))
+ g3d.lpfnDefDlgWndProc = (FARPROC) wc.lpfnWndProc;
+ else
+ g3d.lpfnDefDlgWndProc = (FARPROC) DefDlgProc;
+ }
+ else
+ {
+ g3d.f3dDialogs = fFalse;
+ }
+ }
+Return:
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return g3d.f3dDialogs;
+ }
+
+
+
+/*-----------------------------------------------------------------------
+| End3dDialogs
+|
+| Called at DLL termination to free 3d dialog stuff
+-----------------------------------------------------------------------*/
+PRIVATE VOID End3dDialogs(VOID)
+ {
+ int ct;
+
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+
+ for (ct = 0; ct < ctMax; ct++)
+ {
+ if(g3d.mpctctl[ct].lpfn != NULL)
+ {
+ FreeProcInstance(g3d.mpctctl[ct].lpfn);
+ g3d.mpctctl[ct].lpfn = NULL;
+ }
+ }
+ DeleteObjects();
+ g3d.aCtl3dOld ? GlobalDeleteAtom(g3d.aCtl3dOld) : 0;
+ g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0;
+ g3d.aCtl3dLowOld ? GlobalDeleteAtom(g3d.aCtl3dLowOld) : 0;
+ g3d.aCtl3dHighOld ? GlobalDeleteAtom(g3d.aCtl3dHighOld) : 0;
+ g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0;
+ g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0;
+ g3d.aCtl3dDisable ? GlobalDeleteAtom(g3d.aCtl3dDisable) : 0;
+
+ g3d.f3dDialogs = fFalse;
+
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+
+ }
+
+
+PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce)
+ {
+ ICV icv;
+ CLRT clrtNew;
+ HBITMAP hbmpCheckboxesNew;
+ BRT brtNew;
+
+ if (!g3d.f3dDialogs)
+ return fFalse;
+
+ for (icv = 0; icv < icvMax; icv++)
+ clrtNew.rgcv[icv] = GetSysColor(mpicvSysColor[icv]);
+
+ if (g3d.verWindows == ver30)
+ clrtNew.rgcv[icvBtnHilite] = RGB(0xff, 0xff, 0xff);
+
+ if (clrtNew.rgcv[icvGrayText] == 0L || clrtNew.rgcv[icvGrayText] == clrtNew.rgcv[icvBtnFace])
+ {
+ if (clrtNew.rgcv[icvBtnFace] == RGB(0x80, 0x80, 0x80))
+ clrtNew.rgcv[icvGrayText] = RGB(0xc0, 0xc0, 0xc0);
+ else
+ clrtNew.rgcv[icvGrayText] = RGB(0x80, 0x80, 0x80);
+ }
+
+ if (fForce || MEMCMP(&g3d.clrt, &clrtNew, sizeof(CLRT)))
+ {
+ hbmpCheckboxesNew = LoadUIBitmap(g3d.hinstLib, MAKEINTRESOURCE(CTL3D_3DCHECK),
+ clrtNew.rgcv[icvWindowText],
+ clrtNew.rgcv[icvBtnFace],
+ clrtNew.rgcv[icvBtnShadow],
+ clrtNew.rgcv[icvBtnHilite],
+ clrtNew.rgcv[icvWindow],
+ clrtNew.rgcv[icvWindowFrame]);
+
+ for (icv = 0; icv < icvBrushMax; icv++)
+ brtNew.mpicvhbr[icv] = CreateSolidBrush(clrtNew.rgcv[icv]);
+
+ for (icv = 0; icv < icvBrushMax; icv++)
+ if (brtNew.mpicvhbr[icv] == NULL)
+ goto OOM;
+
+ if(hbmpCheckboxesNew != NULL)
+ {
+ DeleteObjects();
+ g3d.brt = brtNew;
+ g3d.clrt = clrtNew;
+ g3d.hbmpCheckboxes = hbmpCheckboxesNew;
+ return fTrue;
+ }
+ else
+ {
+OOM:
+ for (icv = 0; icv < icvBrushMax; icv++)
+ DeleteObjectNull(&brtNew.mpicvhbr[icv]);
+ DeleteObjectNull(&hbmpCheckboxesNew);
+ return fFalse;
+ }
+ }
+ return fTrue;
+ }
+
+
+/*-----------------------------------------------------------------------
+| Ctl3dDlgProc
+|
+| Subclass DlgProc for use w/ Ctl3dAutoSubclass
+|
+|
+| Arguments:
+| HWND hwnd:
+| int wm:
+| WORD wParam:
+| LPARAM lParam:
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ HBRUSH hbrush;
+ FARPROC lpfnDlgProc;
+ TCHAR szClass[cchClassMax];
+
+ if ( wm == WM_NCDESTROY )
+ return CleanupSubclass(hwnd, wm, wParam, lParam, ctMax);
+
+ if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+
+ switch (wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctMax+1000;
+
+ case WM_INITDIALOG:
+ {
+ long l;
+ BOOL fSubclass;
+ FARPROC lpfnWinProc;
+
+ lpfnWinProc = LpfnGetDefWndProc(hwnd, ctMax);
+
+ if (g3d.verWindows >= ver40 && (GetWindowLong(hwnd, GWL_STYLE) & 0x04))
+ fSubclass = fFalse;
+ else
+ fSubclass = fTrue;
+ SendMessage(hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+
+ if (!fSubclass)
+ {
+ Ctl3dUnsubclassCtl(hwnd);
+ return CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+ }
+
+ l = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+
+ if (g3d.verWindows < ver40 || !(GetWindowLong(hwnd, GWL_STYLE) & 0x04))
+ Ctl3dCheckSubclassDlg(hwnd, CTL3D_ALL);
+
+ return l;
+ }
+
+ case WM_NCPAINT:
+ case WM_NCACTIVATE:
+ case WM_SETTEXT:
+ if (g3d.verWindows >= ver40 || IsIconic(hwnd) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+ else
+ return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, FALSE);
+
+#ifdef WIN32
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSTATIC:
+#else
+ case WM_CTLCOLOR:
+#endif
+ // Is this really a dialog
+ GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+ if (lstrcmp(TEXT("#32770"),szClass) != 0 )
+ {
+#ifdef WIN32
+ hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+ wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+#else
+ hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+ CTL3D_CTLCOLOR, wParam, lParam);
+#endif
+ if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+ hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+ }
+ else
+ {
+ lpfnDlgProc = (FARPROC) GetWindowLong(hwnd, DWL_DLGPROC);
+
+ if (lpfnDlgProc == NULL )
+ {
+ hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+ }
+ else
+ {
+#ifdef WIN32
+ if ( (LONG)lpfnDlgProc > 0xFFFF0000 && g3d.verWindows <= ver31)
+ {
+ // We have a Uni-code / non Unicode issue.
+ // If this is before Daytona, then I CAN NOT call because it may be NULL, but
+ // the returned value is not-null. NT Bug.
+ // So Just send our own message to the window proc instead
+ hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+ wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+ if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+ hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+ }
+ else
+ {
+#endif
+ hbrush = (HBRUSH) CallWindowProc(lpfnDlgProc, hwnd, wm, wParam, lParam);
+ if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+ {
+#ifdef WIN32
+ hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+ wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+#else
+ hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+ CTL3D_CTLCOLOR, wParam, lParam);
+#endif
+ if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+ hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+ }
+ }
+#ifdef WIN32
+ }
+#endif
+ }
+ if (hbrush != (HBRUSH) fFalse)
+ return (LRESULT)hbrush;
+ break;
+ }
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+ }
+
+PRIVATE BOOL NEAR DoesChildNeedSubclass(HWND hwnd)
+ {
+ if (!LpfnGetDefWndProcNull(hwnd))
+ return fFalse;
+ if (g3d.verWindows >= ver40 && GetWindowLong(hwnd, GWL_STYLE) & 0x04)
+ return fFalse;
+ return fTrue;
+ }
+
+/*-----------------------------------------------------------------------
+| Ctl3dHook
+|
+| CBT Hook to watch for window creation. Automatically subclasses all
+| dialogs w/ Ctl3dDlgProc
+|
+| Arguments:
+| int code:
+| WORD wParam:
+| LPARAM lParam:
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam)
+ {
+ int iclihk;
+ HANDLE htask;
+
+ htask = Win32Or16((HANDLE)GetCurrentThreadId(), GetCurrentTask());
+ Win32Only(EnterCriticalSection(&g_CriticalSection));
+ if (htask != g3d.htaskCache)
+ {
+ for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+ {
+ if (g3d.rgclihk[iclihk].htask == htask)
+ {
+ g3d.iclihkCache = iclihk;
+ g3d.htaskCache = htask;
+ break;
+ }
+ }
+ if ( iclihk == g3d.iclihkMac )
+ {
+ // didn't find task in hook table. This could be bad, but
+ // returning 0L is about all we can doo.
+ //
+ // Actually not. The hhook isn't used anyway just set it to NULL.
+ // and call the next hook..... KGM
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+ return CallNextHookEx((HHOOK)0L, code, wParam, lParam);
+ }
+ }
+ iclihk = g3d.iclihkCache;
+ Win32Only(LeaveCriticalSection(&g_CriticalSection));
+
+ if (code == HCBT_CREATEWND)
+ {
+ LPCREATESTRUCT lpcs;
+ lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
+
+ if (lpcs->lpszClass == WC_DIALOG)
+ {
+ if (g3d.verBase == 32)
+ {
+ BOOL fSubclass;
+ if (g3d.verWindows >= ver40 && (GetWindowLong((HWND)wParam, GWL_STYLE) & 0x04))
+ fSubclass = fFalse;
+ else
+ fSubclass = fTrue;
+ SendMessage((HWND)wParam, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+ if (fSubclass)
+ SubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+ }
+ else
+ {
+ HookSubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+ }
+ goto Zing;
+ }
+ if (!(g3d.rgclihk[iclihk].dwFlags & CTL3D_SUBCLASS_DYNCREATE))
+ goto Zing;
+
+ if (DoesChildNeedSubclass(lpcs->hwndParent) ||
+ (lpcs->hwndParent && g3d.verBase != 24 &&
+ DoesChildNeedSubclass(GetParent(lpcs->hwndParent))))
+ {
+ DoSubclassCtl((HWND)wParam, CTL3D_ALL, INCBTHOOK, lpcs->hwndParent);
+ }
+ }
+
+Zing:;
+ Win32Only(return CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
+#ifdef DLL
+ Win16Only(return (*g3d.lpfnCallNextHookEx)(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
+#else
+ Win16Only(return (CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam)));
+#endif
+ }
+
+
+
+
+/*-----------------------------------------------------------------------
+| CTL3D F* routines
+|
+| These routines determine whether or not the given control may be
+| subclassed. They may recursively call DoSubclassCtl in the
+| case of multi-control controls
+|
+| Returns:
+| fTrue if can subclass the given control.
+-----------------------------------------------------------------------*/
+
+
+PRIVATE BOOL FBtn(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ if (g3d.verWindows >= ver40)
+ {
+ return fFalse;
+ }
+ style &= ~(BS_LEFTTEXT);
+ return ( LOWORD(style) >= BS_PUSHBUTTON && LOWORD(style) <= BS_AUTORADIOBUTTON);
+ }
+
+PRIVATE BOOL FEdit(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ if (g3d.verWindows >= ver40 && hwndParent)
+ {
+ TCHAR szClass[cchClassMax];
+ GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+ if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
+ return fFalse;
+ else
+ return fTrue;
+ }
+ else
+ return fTrue;
+ }
+
+PRIVATE BOOL FList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ if (g3d.verWindows >= ver40 && hwndParent)
+ {
+ TCHAR szClass[cchClassMax];
+ GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+ if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
+ return fFalse;
+ else
+ return fTrue;
+ }
+ else
+ return fTrue;
+ }
+
+PRIVATE BOOL FComboList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+
+ if (g3d.verWindows >= ver40)
+ return fFalse;
+
+ if ( wCallFlags == INCBTHOOK )
+ {
+ LONG style;
+ style = GetWindowLong(hwndParent, GWL_STYLE);
+ if (!(((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+ return fTrue;
+ else
+ return fFalse;
+ }
+
+ return fTrue;
+ }
+
+PRIVATE BOOL FCombo(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ HWND hwndEdit;
+ HWND hwndList;
+
+ if (g3d.verWindows >= ver40)
+ return fFalse;
+
+ if ((style & 0x0003) == CBS_DROPDOWN)
+ {
+ if ( wCallFlags == INCBTHOOK )
+ {
+ return fFalse;
+ }
+ // Subclass edit so bottom border of the edit draws properly...This case
+ // is specially handled in ListEditPaint3d
+ hwndEdit = GetWindow(hwnd, GW_CHILD);
+ if (hwndEdit != NULL)
+ DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
+ return fTrue;
+ }
+ else if ((style & 0x0003) == CBS_DROPDOWNLIST )
+ {
+ return fTrue;
+ }
+ else // assume simple // if ((style & 0x0003) == CBS_SIMPLE)
+ {
+ if ( wCallFlags == INCBTHOOK )
+ {
+ return fTrue;
+ }
+ hwndList = GetWindow(hwnd, GW_CHILD);
+ if (hwndList != NULL)
+ {
+ // Subclass list & edit box so they draw properly. We also
+ // subclass the combo so we can hide/show/move it and the
+ // 3d effects outside the client area get erased
+ DoSubclassCtl(hwndList, CTL3D_LISTBOXES, wCallFlags, hwnd);
+
+ hwndEdit = GetWindow(hwndList, GW_HWNDNEXT);
+ if (hwndEdit != NULL)
+ DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
+ return fTrue;
+ }
+ return fFalse;
+ }
+ }
+
+PRIVATE BOOL FStatic(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ int wStyle;
+
+ wStyle = LOWORD(style) & 0x1f;
+ return (wStyle != SS_ICON &&
+ ((grbit & CTL3D_STATICTEXTS) &&
+ (wStyle <= SS_RIGHT || wStyle == SS_LEFTNOWORDWRAP) ||
+ ((grbit & CTL3D_STATICFRAMES) &&
+ ((wStyle >= SS_BLACKRECT && wStyle <= SS_WHITEFRAME) ||
+ (g3d.verWindows < ver40 && wStyle >= 0x10 && wStyle <= 0x12)))));
+ }
+
+
+
+/*-----------------------------------------------------------------------
+| DoSubclassCtl
+|
+| Actually subclass the control
+|
+|
+| Arguments:
+| HWND hwnd:
+| WORD grbit:
+| WORD wCallFlags
+| Returns:
+|
+-----------------------------------------------------------------------*/
+PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent)
+ {
+ LONG style;
+ int ct;
+ BOOL fCan;
+ TCHAR szClass[cchClassMax];
+
+ // Is this already subclassed by CTL3D?
+ if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
+ return fFalse;
+
+ GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+
+ for (ct = 0; ct < ctMax; ct++)
+ {
+ if ((mpctcdef[ct].msk & grbit) &&
+ (lstrcmp(mpctcdef[ct].sz,szClass) == 0))
+ {
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, grbit, wCallFlags, hwndParent);
+ if (fCan == fTrue)
+ {
+ if ( wCallFlags == INCBTHOOK && g3d.verBase == 16 )
+ HookSubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+ else
+ SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+ }
+ return fCan != fFalse;
+ }
+ }
+
+ return fFalse;
+ }
+
+
+
+/*-----------------------------------------------------------------------
+| Inval3dCtl
+|
+| Invalidate the controls rect in response to a WM_SHOWWINDOW or
+| WM_WINDOWPOSCHANGING message. This is necessary because ctl3d draws
+| the 3d effects of listboxes, combos & edits outside the controls client
+| rect.
+|
+| Arguments:
+| HWND hwnd:
+| WINDOWPOS FAR *lpwp:
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+PRIVATE VOID Inval3dCtl(HWND hwnd, WINDOWPOS FAR *lpwp)
+ {
+ RC rc;
+ HWND hwndParent;
+ LONG lStyle;
+ unsigned flags;
+
+ GetWindowRect(hwnd, (LPRECT) &rc);
+ lStyle = GetWindowLong(hwnd, GWL_STYLE);
+ if (lStyle & WS_VISIBLE)
+ {
+ if (lpwp != NULL)
+ {
+ flags = lpwp->flags;
+
+ //
+ // Is all this necessary ? Are we moving or sizing ?
+ //
+ if ( !((flags & SWP_HIDEWINDOW) || (flags & SWP_SHOWWINDOW)) &&
+ (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE) )
+ // Nope
+ return;
+
+ // handle integral height listboxes (or any other control which
+ // shrinks from the bottom)
+ if ((flags & (SWP_NOMOVE|SWP_NOSIZE)) == SWP_NOMOVE &&
+ (lpwp->cx == (rc.xRight-rc.xLeft) && lpwp->cy <= (rc.yBot-rc.yTop)))
+ rc.yTop = rc.yTop+lpwp->cy+1; // +1 to offset InflateRect
+ }
+ InflateRect((LPRECT) &rc, 1, 1);
+ hwndParent = GetParent(hwnd);
+ ScreenToClient(hwndParent, (LPPOINT) &rc);
+ ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+ if(lStyle & WS_VSCROLL)
+ rc.xRight ++;
+ InvalidateRect(hwndParent, (LPRECT) &rc, fFalse);
+ }
+ }
+
+/*-----------------------------------------------------------------------
+| Val3dCtl
+|
+-----------------------------------------------------------------------*/
+PRIVATE VOID Val3dCtl(HWND hwnd)
+ {
+ RC rc;
+ HWND hwndParent;
+ LONG lStyle;
+
+ lStyle = GetWindowLong(hwnd, GWL_STYLE);
+ GetWindowRect(hwnd, (LPRECT) &rc);
+ InflateRect((LPRECT) &rc, 1, 1);
+ hwndParent = GetParent(hwnd);
+ ScreenToClient(hwndParent, (LPPOINT) &rc);
+ ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+ if(lStyle & WS_VSCROLL)
+ rc.xRight ++;
+ ValidateRect(hwndParent, (LPRECT) &rc);
+ }
+
+/*-----------------------------------------------------------------------
+| CTL3D Subclass Wndprocs
+-----------------------------------------------------------------------*/
+
+/* These values are assumed for bit shifting operations */
+#define BFCHECK 0x0003
+#define BFSTATE 0x0004
+#define BFFOCUS 0x0008
+#define BFINCLICK 0x0010 /* Inside click code */
+#define BFCAPTURED 0x0020 /* We have mouse capture */
+#define BFMOUSE 0x0040 /* Mouse-initiated */
+#define BFDONTCLICK 0x0080 /* Don't check on get focus */
+
+#define bpText 0x0002
+#define bpCheck 0x0004
+#define bpFocus 0x0008 // must be same as BFFOCUS
+#define bpBkgnd 0x0010
+#define bpEraseGroupText 0x0020
+
+PRIVATE VOID DrawPushButton(HWND hwnd, HDC hdc, RC FAR *lprc, LPTSTR lpch, int cch, WORD bs, BOOL fDown)
+ {
+ // int dxyBrdr;
+ int dxyShadow;
+ HBRUSH hbrSav;
+ RC rcInside;
+ rcInside = *lprc;
+
+// if (!(grbitStyle & bitFCoolButtons))
+ {
+ DrawRec3d(hdc, lprc, icvWindowFrame, icvWindowFrame, dr3All);
+ InflateRect((LPRECT) &rcInside, -1, -1);
+ if (bs == LOWORD(BS_DEFPUSHBUTTON) && IsWindowEnabled(hwnd))
+ {
+ // dxyBrdr = 2;
+ DrawRec3d(hdc, &rcInside, icvWindowFrame, icvWindowFrame, dr3All);
+ InflateRect((LPRECT) &rcInside, -1, -1);
+ }
+ // else
+ // dxyBrdr = 1;
+
+ // Notch the corners
+ PatBlt(hdc, lprc->xLeft, lprc->yTop, dxBorder, dyBorder, PATCOPY);
+ /* Top xRight corner */
+ PatBlt(hdc, lprc->xRight - dxBorder, lprc->yTop, dxBorder, dyBorder, PATCOPY);
+ /* yBot xLeft corner */
+ PatBlt(hdc, lprc->xLeft, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
+ /* yBot xRight corner */
+ PatBlt(hdc, lprc->xRight - dxBorder, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
+ dxyShadow = 1 + !fDown;
+ }
+// else
+// dxyShadow = 1;
+
+ // draw upper left hilite/shadow
+
+ if (fDown)
+ hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);
+ else
+ hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);
+
+ PatBlt(hdc, rcInside.xLeft, rcInside.yTop, dxyShadow,
+ (rcInside.yBot - rcInside.yTop), PATCOPY);
+ PatBlt(hdc, rcInside.xLeft, rcInside.yTop,
+ (rcInside.xRight - rcInside.xLeft), dxyShadow, PATCOPY);
+
+ // draw lower right shadow (only if not down)
+ if (!fDown) // || (grbitStyle & bitFCoolButtons))
+ {
+ int i;
+
+ if (fDown)
+ SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);
+ else
+ SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);
+
+ rcInside.yBot--;
+ rcInside.xRight--;
+
+ for (i = 0; i < dxyShadow; i++)
+ {
+ PatBlt(hdc, rcInside.xLeft, rcInside.yBot,
+ rcInside.xRight - rcInside.xLeft + dxBorder, dyBorder,
+ PATCOPY);
+ PatBlt(hdc, rcInside.xRight, rcInside.yTop, dxBorder,
+ rcInside.yBot - rcInside.yTop, PATCOPY);
+ if (i < dxyShadow-1)
+ InflateRect((LPRECT) &rcInside, -dxBorder, -dyBorder);
+ }
+ }
+ // draw the button face
+
+ rcInside.xLeft++;
+ rcInside.yTop++;
+
+ SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
+ PatBlt(hdc, rcInside.xLeft, rcInside.yTop, rcInside.xRight-rcInside.xLeft,
+ rcInside.yBot - rcInside.yTop, PATCOPY);
+
+ // Draw the durned text
+
+ if(!IsWindowEnabled(hwnd))
+ SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+
+ {
+ int dy;
+ int dx;
+
+ MyGetTextExtent(hdc, lpch, &dx, &dy);
+ rcInside.yTop += (rcInside.yBot-rcInside.yTop-dy)/2;
+ rcInside.xLeft += (rcInside.xRight-rcInside.xLeft-dx)/2;
+ rcInside.yBot = min(rcInside.yTop+dy, rcInside.yBot);
+ rcInside.xRight = min(rcInside.xLeft+dx, rcInside.xRight);
+ }
+
+ if (fDown)
+ {
+ OffsetRect((LPRECT) &rcInside, 1, 1);
+ rcInside.xRight = min(rcInside.xRight, lprc->xRight-3);
+ rcInside.yBot = min(rcInside.yBot, lprc->yBot-3);
+ }
+
+ DrawText(hdc, lpch, cch, (LPRECT) &rcInside, DT_LEFT|DT_SINGLELINE);
+
+ if (hwnd == GetFocus())
+ {
+ InflateRect((LPRECT) &rcInside, 1, 1);
+ IntersectRect((LPRECT) &rcInside, (LPRECT) &rcInside, (LPRECT) lprc);
+ DrawFocusRect(hdc, (LPRECT) &rcInside);
+ }
+
+ if (hbrSav)
+ SelectObject(hdc, hbrSav);
+ }
+
+
+/*-----------------------------------------------------------------------
+| BtnPaint
+|
+| Paint a button
+|
+| Arguments:
+| HWND hwnd:
+| HDC hdc:
+| int bp:
+|
+| Returns:
+|
+-----------------------------------------------------------------------*/
+PRIVATE VOID BtnPaint(HWND hwnd, HDC hdc, int bp)
+ {
+ RC rc;
+ RC rcClient;
+ HFONT hfont;
+ int bs;
+ int bf;
+ HBRUSH hbrBtn;
+ HWND hwndParent;
+ int xBtnBmp;
+ int yBtnBmp;
+ HBITMAP hbmpSav;
+ HDC hdcMem;
+ TCHAR szTitle[256];
+ int cch;
+ BOOL fEnabled;
+ BOOL fLeftText;
+
+ bs = (int) GetWindowLong(hwnd, GWL_STYLE);
+ fLeftText = (bs & Win32Or16(0x00000020, 0x0020));
+ bs &= Win32Or16(0x0000001F, 0x001F);
+ hwndParent = GetParent(hwnd);
+ SetBkMode(hdc, OPAQUE);
+ GetClientRect(hwnd, (LPRECT)&rcClient);
+ rc = rcClient;
+ if((hfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
+ hfont = SelectObject(hdc, hfont);
+
+ SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
+ SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
+ hbrBtn = SEND_COLOR_BUTTON_MESSAGE(hwndParent, hwnd, hdc);
+ hbrBtn = SelectObject(hdc, hbrBtn);
+ IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
+ if(bp & bpBkgnd && (bs != BS_GROUPBOX))
+ PatBlt(hdc, rc.xLeft, rc.yTop, rc.xRight-rc.xLeft, rc.yBot-rc.yTop, PATCOPY);
+
+ fEnabled = IsWindowEnabled(hwnd);
+ bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+ yBtnBmp = 0;
+ xBtnBmp = (((bf&BFCHECK) != 0) | ((bf&BFSTATE) >> 1)) * 14;
+ if (!fEnabled)
+ xBtnBmp += 14*(2+((bf&BFCHECK) != 0));
+ if(bp & (bpText|bpFocus) ||
+ bs == BS_PUSHBUTTON || bs == BS_DEFPUSHBUTTON)
+ cch = GetWindowText(hwnd, szTitle, sizeof(szTitle)Win32Only(/sizeof(TCHAR)));
+ switch(bs)
+ {
+#ifdef DEBUG
+ default:
+ Assert(fFalse);
+ break;
+#endif
+ case BS_PUSHBUTTON:
+ case BS_DEFPUSHBUTTON:
+ DrawPushButton(hwnd, hdc, &rcClient, szTitle, cch, LOWORD(bs), bf & BFSTATE);
+ break;
+
+ case BS_RADIOBUTTON:
+ case BS_AUTORADIOBUTTON:
+ yBtnBmp = 13;
+ goto DrawBtn;
+ case BS_3STATE:
+ case BS_AUTO3STATE:
+ Assert((BFSTATE >> 1) == 2);
+ if((bf & BFCHECK) == 2)
+ yBtnBmp = 26;
+ // fall through
+ case BS_CHECKBOX:
+ case BS_AUTOCHECKBOX:
+DrawBtn:
+ if(bp & bpCheck)
+ {
+ hdcMem = CreateCompatibleDC(hdc);
+ if(hdcMem != NULL)
+ {
+ hbmpSav = SelectObject(hdcMem, g3d.hbmpCheckboxes);
+ if(hbmpSav != NULL)
+ {
+ if (fLeftText)
+ BitBlt(hdc, rc.xRight - 14, rc.yTop+(rc.yBot-rc.yTop-13)/2,
+ 14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
+ else
+ BitBlt(hdc, rc.xLeft, rc.yTop+(rc.yBot-rc.yTop-13)/2,
+ 14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
+ SelectObject(hdcMem, hbmpSav);
+ }
+ DeleteDC(hdcMem);
+ }
+ }
+ if(bp & bpText)
+ {
+ // BUG! this assumes we have only 1 hbm3dCheck type
+ if (fLeftText)
+ rc.xRight = rcClient.xRight - (14+4);
+ else
+ rc.xLeft = rcClient.xLeft + 14+4;
+ if(!fEnabled)
+ SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+ DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_VCENTER|DT_LEFT|DT_SINGLELINE);
+ }
+ if(bp & bpFocus)
+ {
+ int dx;
+ int dy;
+
+ MyGetTextExtent(hdc, szTitle, &dx, &dy);
+ rc.yTop = (rc.yBot-rc.yTop-dy)/2;
+ rc.yBot = rc.yTop+dy;
+ rc.xLeft = rcClient.xLeft;
+ if (fLeftText)
+ {
+ rc.xLeft = rcClient.xLeft;
+ rcClient.xRight -= (14+4);
+ }
+ else
+ rc.xLeft = rcClient.xLeft + (14+4);
+ rc.xRight = rc.xLeft + dx;
+ InflateRect((LPRECT) &rc, 1, 1);
+ IntersectRect((LPRECT) &rc, (LPRECT) &rc, (LPRECT) &rcClient);
+ DrawFocusRect(hdc, (LPRECT) &rc);
+ }
+ break;
+ case BS_GROUPBOX:
+ if(bp & (bpText|bpCheck))
+ {
+ int dy;
+ int dx;
+
+ MyGetTextExtent(hdc, szTitle, &dx, &dy);
+ if (dy == 0)
+ {
+ int dxT;
+ MyGetTextExtent(hdc, TEXT("X"), &dxT, &dy);
+ }
+
+ rc.xLeft += 4;
+ rc.xRight = rc.xLeft + dx + 4;
+ rc.yBot = rc.yTop + dy;
+
+ if (bp & bpEraseGroupText)
+ {
+ RC rcT;
+
+ rcT = rc;
+ rcT.xRight = rcClient.xRight;
+ // Hack!
+ ClientToScreen(hwnd, (LPPOINT) &rcT);
+ ClientToScreen(hwnd, ((LPPOINT) &rcT)+1);
+ ScreenToClient(hwndParent, (LPPOINT) &rcT);
+ ScreenToClient(hwndParent, ((LPPOINT) &rcT)+1);
+ InvalidateRect(hwndParent, (LPRECT) &rcT, fTrue);
+ return;
+ }
+
+ rcClient.yTop += dy/2;
+ rcClient.xRight--;
+ rcClient.yBot--;
+ DrawRec3d(hdc, &rcClient, icvBtnShadow, icvBtnShadow, dr3All);
+ OffsetRect((LPRECT) &rcClient, 1, 1);
+ DrawRec3d(hdc, &rcClient, icvBtnHilite, icvBtnHilite, dr3All);
+
+ if(!fEnabled)
+ SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+ DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_LEFT|DT_SINGLELINE);
+ }
+ break;
+ }
+
+ SelectObject(hdc, hbrBtn);
+ if(hfont != NULL)
+ SelectObject(hdc, hfont);
+ }
+
+LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ LONG lRet;
+ LONG lStyle;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ int bf;
+ int bfNew;
+ int bp;
+
+ if ( wm == WM_NCDESTROY )
+ return CleanupSubclass(hwnd, wm, wParam, lParam, ctButton);
+
+ if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+
+ switch(wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctButton+1000;
+
+ case WM_SETTEXT:
+ lStyle = GetWindowLong(hwnd, GWL_STYLE);
+ if ((lStyle & WS_VISIBLE) && (LOWORD(lStyle) & 0x1f) == BS_GROUPBOX)
+ {
+ // total hack -- if group box text length shortens then
+ // we have to erase the old text. BtnPaint will Invalidate
+ // the rect of the text so everything will redraw.
+ bp = bpText | bpEraseGroupText;
+ }
+ else
+ {
+ bp = bpText|bpCheck|bpBkgnd;
+ }
+ goto DoIt;
+
+ case BM_SETSTATE:
+ case BM_SETCHECK:
+ bp = bpCheck;
+ goto DoIt;
+ case WM_KILLFOCUS:
+ // HACK! Windows will go into an infinite loop trying to sync the
+ // states of the AUTO_RADIOBUTTON in this group. (we turn off the
+ // visible bit so it gets skipped in the enumeration)
+ // Disable this code by clearing the STATE bit
+ if ((LOWORD(GetWindowLong(hwnd, GWL_STYLE)) & 0x1F) == BS_AUTORADIOBUTTON)
+ SendMessage(hwnd, BM_SETSTATE, 0, 0L);
+ bp = 0;
+ goto DoIt;
+ case WM_ENABLE:
+ bp = bpCheck | bpText;
+ goto DoIt;
+ case WM_SETFOCUS:
+ // HACK! if wParam == NULL we may be activated via the task manager
+ // Erase background of control because a WM_ERASEBKGND messsage has not
+ // arrived yet for the dialog
+ // bp = wParam == (WPARAM)NULL ? (bpCheck | bpText | bpBkgnd) : (bpCheck | bpText);
+ bp = bpCheck | bpText | bpBkgnd;
+DoIt:
+ bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+ if((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE)
+ {
+ if ( wm != WM_SETFOCUS )
+ SetWindowLong(hwnd, GWL_STYLE, lStyle & ~(WS_VISIBLE));
+ lRet = CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+
+ if ( wm != WM_SETFOCUS )
+ SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE)|WS_VISIBLE);
+ bfNew = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+ if((wm != BM_SETSTATE && wm != BM_SETCHECK) ||
+ bf != bfNew)
+ {
+ hdc = GetDC(hwnd);
+ if (hdc != NULL)
+ {
+ Assert(BFFOCUS == bpFocus);
+ /* If the check state changed, redraw no matter what,
+ because it won't have during the above call to the def
+ wnd proc */
+ if ((bf & BFCHECK) != (bfNew & BFCHECK))
+ bp |= bpCheck;
+ ExcludeUpdateRgn(hdc, hwnd);
+ BtnPaint(hwnd, hdc, bp|((bf^bfNew)&BFFOCUS));
+ ReleaseDC(hwnd, hdc);
+ }
+ }
+ return lRet;
+ }
+ break;
+ case WM_PAINT:
+ bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+ if ((hdc = (HDC) wParam) == NULL)
+ hdc = BeginPaint(hwnd, &ps);
+ if(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)
+ BtnPaint(hwnd, hdc, bpText|bpCheck|(bf&BFFOCUS));
+ if (wParam == (WPARAM)NULL)
+ EndPaint(hwnd, &ps);
+ return 0L;
+ }
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+ }
+
+
+void ListEditPaint3d(HWND hwnd, BOOL fEdit, int ct)
+ {
+ CTLID id;
+ RC rc;
+ HDC hdc;
+ HWND hwndParent;
+ LONG lStyle;
+ DR3 dr3;
+
+ if(!((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE))
+ return;
+
+ if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
+ {
+ if ( SendMessage(hwnd, CB_GETDROPPEDSTATE,0,0L) )
+ return;
+ }
+
+ if (fEdit)
+ HideCaret(hwnd);
+
+ GetWindowRect(hwnd, (LPRECT) &rc);
+
+ ScreenToClient(hwndParent = GetParent(hwnd), (LPPOINT) &rc);
+ ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+
+ hdc = GetDC(hwndParent);
+
+ dr3 = dr3All;
+
+ if(lStyle & WS_HSCROLL)
+ dr3 = dr3 & ~dr3Bot;
+
+ if(lStyle & WS_VSCROLL)
+ dr3 = dr3 & ~dr3Right;
+
+ // don't draw the top if it's a listbox of a simple combo
+ id = GetControlId(hwnd);
+ if (id == (CTLID) (1000 + fEdit))
+ {
+ TCHAR szClass[cchClassMax];
+ BOOL fSubclass = 666;
+ int ctParent;
+
+ // could be superclassed!
+ fSubclass = 666;
+ ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+ if (fSubclass == 666)
+ ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+
+
+ // could be subclassed!
+ GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+ if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 ||
+ (fSubclass == fTrue && ctParent == ctCombo+1000))
+ {
+ HWND hwndComboParent;
+
+ hwndComboParent = GetParent(hwndParent);
+
+ Win16Only(GetWindowRect(hwnd, (LPRECT) &rc));
+ Win16Only(ScreenToClient(hwndComboParent, (LPPOINT) &rc));
+ Win16Only(ScreenToClient(hwndComboParent, ((LPPOINT) &rc)+1));
+
+ Win32Only(MapWindowPoints(hwndParent, hwndComboParent, (POINT*)&rc, 2));
+
+ ReleaseDC(hwndParent, hdc);
+ hdc = GetDC(hwndComboParent);
+
+ if (fEdit)
+ {
+ RC rcList;
+ HWND hwndList;
+ long style;
+
+ style = GetWindowLong(hwndParent, GWL_STYLE);
+ if (!(((style & 0x0003) == CBS_DROPDOWN)
+ || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+ {
+ dr3 &= ~dr3Bot;
+
+ hwndList = GetWindow(hwndParent, GW_CHILD);
+ GetWindowRect(hwndList, (LPRECT) &rcList);
+
+ // Some ugly shit goin' on here!
+ rc.xRight -= rcList.xRight-rcList.xLeft;
+ DrawInsetRect3d(hdc, &rc, dr3Bot|dr3HackBotRight);
+ rc.xRight += rcList.xRight-rcList.xLeft;
+ }
+ else
+ {
+ //
+ // Is the drop down on the parent down ? if so don't paint.
+ //
+ if ( SendMessage(hwndParent, CB_GETDROPPEDSTATE,0,0L) )
+ {
+ ReleaseDC(hwndComboParent, hdc);
+ ShowCaret(hwnd);
+ return;
+ }
+ }
+ }
+ else
+ {
+ rc.yTop++;
+ dr3 &= ~dr3Top;
+ }
+
+ hwndParent = hwndComboParent;
+
+ }
+ }
+
+ DrawInsetRect3d(hdc, &rc, dr3);
+
+ if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
+ {
+ rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
+ DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right|dr3Bot);
+ Val3dCtl(hwnd);
+ }
+ else {
+ if (lStyle & WS_VSCROLL)
+ {
+ int SaveLeft;
+
+ rc.xRight++;
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Right);
+ rc.xRight--;
+ SaveLeft = rc.xLeft;
+ rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
+ DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Bot);
+ rc.xLeft = SaveLeft;
+ }
+ if (lStyle & WS_HSCROLL)
+ {
+ rc.yBot++;
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Bot);
+ rc.yBot--;
+ rc.yTop = rc.yBot - GetSystemMetrics(SM_CXHSCROLL);
+ DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right);
+ }
+ }
+
+ ReleaseDC(hwndParent, hdc);
+ if (fEdit)
+ ShowCaret(hwnd);
+
+ }
+
+
+LONG ShareEditComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
+ {
+ LONG l;
+ LONG style;
+
+ if ( wm == WM_NCDESTROY )
+ return CleanupSubclass(hwnd, wm, wParam, lParam, ct);
+
+ if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+
+ l = CallWindowProc(LpfnGetDefWndProc(hwnd,ct), hwnd, wm, wParam, lParam);
+ if (ct == ctCombo)
+ {
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ if ((style & 0x0003) == CBS_DROPDOWN)
+ return l;
+ }
+
+ switch(wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctEdit+1000;
+
+ case WM_SHOWWINDOW:
+ if (g3d.verWindows < ver31 && wParam == 0)
+ Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
+ break;
+ case WM_WINDOWPOSCHANGING:
+ if (g3d.verWindows >= ver31)
+ Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
+ break;
+
+ case WM_PAINT:
+ {
+ if (ct != ctCombo ||
+ (((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+ ListEditPaint3d(hwnd, TRUE, ct);
+ }
+ break;
+ }
+ return l;
+ }
+
+
+LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctEdit);
+ }
+
+
+LONG SharedListWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, unsigned ct)
+ {
+ LONG l;
+
+ if ( wm == WM_NCDESTROY )
+ return CleanupSubclass(hwnd, wm, wParam, lParam, ct);
+
+ if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+
+ switch(wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctList+1000;
+
+ case WM_SHOWWINDOW:
+ if (g3d.verWindows < ver31 && wParam == 0)
+ Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
+ break;
+ case WM_WINDOWPOSCHANGING:
+ if (g3d.verWindows >= ver31)
+ Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
+ break;
+ case WM_PAINT:
+ l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+ ListEditPaint3d(hwnd, FALSE, ct);
+ return l;
+ case WM_NCCALCSIZE:
+ {
+ RC rc;
+ RC rcNew;
+ HWND hwndParent;
+
+ // Inval3dCtl handles this case under Win 3.1
+ if (g3d.verWindows >= ver31)
+ break;
+
+ GetWindowRect(hwnd, (LPRECT) &rc);
+#ifdef UNREACHABLE
+ if (g3d.verWindows >= ver31)
+ {
+ hwndParent = GetParent(hwnd);
+ ScreenToClient(hwndParent, (LPPOINT) &rc);
+ ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+ }
+#endif
+
+ l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+
+ rcNew = *(RC FAR *)lParam;
+ InflateRect((LPRECT) &rcNew, 2, 1); // +1 for border (Should use AdjustWindowRect)
+ if (rcNew.yBot < rc.yBot)
+ {
+ rcNew.yTop = rcNew.yBot+1;
+ rcNew.yBot = rc.yBot+1;
+
+#ifdef ALWAYS
+ if (g3d.verWindows < ver31)
+#endif
+ {
+ hwndParent = GetParent(hwnd);
+ ScreenToClient(hwndParent, (LPPOINT) &rcNew);
+ ScreenToClient(hwndParent, ((LPPOINT) &rcNew)+1);
+ }
+
+ InvalidateRect(hwndParent, (LPRECT) &rcNew, TRUE);
+ }
+ return l;
+ }
+ }
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+ }
+
+LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ return SharedListWndProc(hwnd, wm, wParam, lParam, ctList);
+ }
+
+
+
+LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ switch(wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctCombo+1000;
+ }
+
+ return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctCombo);
+ }
+
+void StaticPrint(HWND hwnd, HDC hdc, RC FAR *lprc, LONG style)
+ {
+ WORD dt;
+ LONG cv;
+ Win16Or32(HANDLE , LPTSTR )hText;
+ int TextLen;
+
+ PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
+
+ TextLen = GetWindowTextLength(hwnd);
+
+#ifndef WIN32
+ hText = LocalAlloc(LPTR|LMEM_NODISCARD,(TextLen+5)*sizeof(TCHAR));
+#else
+ hText = _alloca((TextLen+5)*sizeof(TCHAR));
+#endif
+ if (hText == NULL)
+ return;
+
+ if (GetWindowText(hwnd, (NPTSTR)hText, TextLen+2*sizeof(TCHAR)) == 0)
+ {
+#ifndef WIN32
+ LocalFree(hText);
+#endif
+ return;
+ }
+
+ if ((style & 0x000f) == SS_LEFTNOWORDWRAP)
+ dt = DT_NOCLIP | DT_EXPANDTABS;
+ else
+ {
+ dt = LOWORD(DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK | ((style & 0x0000000f)-SS_LEFT));
+ }
+
+ if (style & SS_NOPREFIX)
+ dt |= DT_NOPREFIX;
+
+ if (style & WS_DISABLED)
+ cv = SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+
+ DrawText(hdc, (NPTSTR)hText, -1, (LPRECT) lprc, dt);
+
+#ifndef WIN32
+ LocalFree(hText);
+#endif
+
+ if (style & WS_DISABLED)
+ cv = SetTextColor(hdc, cv);
+ }
+
+void StaticPaint(HWND hwnd, HDC hdc)
+ {
+ LONG style;
+ RC rc;
+
+ style = GetWindowLong(hwnd, GWL_STYLE);
+ if(!(style & WS_VISIBLE))
+ return;
+
+ GetClientRect(hwnd, (LPRECT) &rc);
+ switch(style & 0x1f)
+ {
+ case SS_BLACKRECT:
+ case SS_BLACKFRAME: // Inset rect
+ DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3All);
+ break;
+ case SS_GRAYRECT:
+ case SS_GRAYFRAME:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ rc.xLeft++;
+ rc.yTop++;
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3All);
+ OffsetRect((LPRECT) &rc, -1, -1);
+ DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnShadow, dr3All);
+ break;
+ case SS_WHITERECT: // outset rect
+ case SS_WHITEFRAME:
+ DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
+ break;
+ case SS_LEFT:
+ case SS_CENTER:
+ case SS_RIGHT:
+ case SS_LEFTNOWORDWRAP:
+ {
+ HANDLE hfont;
+ HBRUSH hbr;
+
+ if((hfont = (HANDLE)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
+ hfont = SelectObject(hdc, hfont);
+ SetBkMode(hdc, OPAQUE);
+
+ if(( hbr = SEND_COLOR_STATIC_MESSAGE(GetParent(hwnd), hwnd, hdc)) != NULL)
+ hbr = SelectObject(hdc, hbr);
+
+ StaticPrint(hwnd, hdc, (RC FAR *)&rc, style);
+
+ if (hfont != NULL)
+ SelectObject(hdc, hfont);
+
+ if (hbr != NULL)
+ SelectObject(hdc, hbr);
+ }
+ break;
+ }
+ }
+
+
+LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+
+ if ( wm == WM_NCDESTROY )
+ return CleanupSubclass(hwnd, wm, wParam, lParam, ctStatic);
+
+ if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);
+
+ switch (wm)
+ {
+ case WM_CHECKSUBCLASS_OLD:
+ case WM_CHECKSUBCLASS:
+ *(int FAR *)lParam = fTrue;
+ return ctStatic+1000;
+
+ case WM_PAINT:
+ if ((hdc = (HDC) wParam) == NULL)
+ {
+ hdc = BeginPaint(hwnd, &ps);
+ ClipCtlDc(hwnd, hdc);
+ }
+ StaticPaint(hwnd, hdc);
+ if (wParam == (WPARAM)NULL)
+ EndPaint(hwnd, &ps);
+ return 0L;
+
+ case WM_ENABLE:
+ hdc = GetDC(hwnd);
+ ClipCtlDc(hwnd, hdc);
+ StaticPaint(hwnd, hdc);
+ ReleaseDC(hwnd, hdc);
+ return 0L;
+ }
+ return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);
+ }
+
+
+/*-----------------------------------------------------------------------
+| LibMain
+-----------------------------------------------------------------------*/
+#ifdef WIN32
+#ifdef DLL
+BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+#else
+#ifdef SDLL
+BOOL FAR Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+#else
+BOOL FAR LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+#endif
+#endif
+ {
+ WORD wT;
+ DWORD dwVersion;
+ BOOL (WINAPI* pfnDisableThreadLibraryCalls)(HMODULE);
+ HMODULE hKernel;
+
+ switch(dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ // call DisableThreadLibraryCalls if available
+ hKernel = GetModuleHandleA("KERNEL32.DLL");
+ *(FARPROC*)&pfnDisableThreadLibraryCalls =
+ GetProcAddress(hKernel, "DisableThreadLibraryCalls");
+ if (pfnDisableThreadLibraryCalls != NULL)
+ (*pfnDisableThreadLibraryCalls)(hModule);
+
+#ifdef DLL
+ InitializeCriticalSection(&g_CriticalSection);
+#endif
+ EnterCriticalSection(&g_CriticalSection);
+#ifdef SDLL
+ g3d.hinstLib = g3d.hmodLib = _hModule;
+#else
+ g3d.hinstLib = g3d.hmodLib = hModule;
+#endif
+
+ dwVersion = (DWORD)GetVersion();
+ wT = LOWORD(dwVersion);
+ // get adjusted windows version
+ g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);
+ // Win32s or Win32 for real (Chicago reports Win32s)
+ g3d.verBase =
+ (dwVersion & 0x80000000) && g3d.verWindows < ver40 ? 16 : 32;
+
+ g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
+ g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
+ g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
+ g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);
+
+ LeaveCriticalSection(&g_CriticalSection);
+ }
+ return TRUE;
+ }
+#else
+#ifdef DLL
+int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+#else
+#ifdef SDLL
+int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+#else
+#ifdef _BORLAND
+BOOL FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+#else
+BOOL FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+#endif
+#endif
+#endif
+ {
+ WORD wT;
+#ifdef DLL
+
+#ifdef V2
+ CodeLpszDeclA(lpszCtl3d, "CTL3DV2");
+#else
+ CodeLpszDeclA(lpszCtl3d, "CTL3D");
+#endif
+
+ CodeLpszDeclA(lpszUser, "user.exe");
+ CodeLpszDeclA(lpszSetWindowsHookEx, "SETWINDOWSHOOKEX");
+ CodeLpszDeclA(lpszUnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX");
+ CodeLpszDeclA(lpszCallNextHookEx, "CALLNEXTHOOKEX");
+#endif
+
+ g3d.hinstLib = hModule;
+#ifdef DLL
+ g3d.hmodLib = GetModuleHandle(lpszCtl3d);
+#else
+#ifdef SDLL
+ g3d.hinstLib = _hModule;
+ g3d.hmodLib = GetModuleHandle(MAKELP(0,_hModule));
+#else
+ g3d.hmodLib = hModule;
+#endif
+#endif
+ wT = LOWORD( GetVersion() );
+ g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);
+
+ if ( GetWinFlags() & 0x4000 )
+ g3d.verBase = 24; // More then 16, not yet 32....WOW box on NT
+ else
+ g3d.verBase = 16; // Regular old 3.1
+
+ g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
+ g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
+ g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
+ g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);
+
+#ifdef DLL
+ if (g3d.verWindows >= ver31)
+ {
+ HANDLE hlib;
+
+ hlib = LoadLibrary(lpszUser);
+ if (FValidLibHandle(hlib))
+ {
+ (FARPROC) g3d.lpfnSetWindowsHookEx = GetProcAddress(hlib, lpszSetWindowsHookEx);
+ (FARPROC) g3d.lpfnUnhookWindowsHookEx = GetProcAddress(hlib, lpszUnhookWindowsHookEx);
+ (FARPROC) g3d.lpfnCallNextHookEx = GetProcAddress(hlib, lpszCallNextHookEx);
+ FreeLibrary(hlib);
+ }
+ }
+#endif
+ return 1;
+ }
+#endif // win32
+
+// convert a RGB into a RGBQ
+#define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))
+
+//
+// LoadUIBitmap() - load a bitmap resource
+//
+// load a bitmap resource from a resource file, converting all
+// the standard UI colors to the current user specifed ones.
+//
+// this code is designed to load bitmaps used in "gray ui" or
+// "toolbar" code.
+//
+// the bitmap must be a 4bpp windows 3.0 DIB, with the standard
+// VGA 16 colors.
+//
+// the bitmap must be authored with the following colors
+//
+// Window Text Black (index 0)
+// Button Shadow gray (index 7)
+// Button Face lt gray (index 8)
+// Button Highlight white (index 15)
+// Window Color yellow (index 11)
+// Window Frame green (index 10)
+//
+// Example:
+//
+// hbm = LoadUIBitmap(hInstance, "TestBmp",
+// GetSysColor(COLOR_WINDOWTEXT),
+// GetSysColor(COLOR_BTNFACE),
+// GetSysColor(COLOR_BTNSHADOW),
+// GetSysColor(COLOR_BTNHIGHLIGHT),
+// GetSysColor(COLOR_WINDOW),
+// GetSysColor(COLOR_WINDOWFRAME));
+//
+// Author: JimBov, ToddLa
+//
+//
+#ifdef WIN32
+
+HBITMAP PASCAL LoadUIBitmap(
+ HANDLE hInstance, // EXE file to load resource from
+ LPCTSTR szName, // name of bitmap resource
+ COLORREF rgbText, // color to use for "Button Text"
+ COLORREF rgbFace, // color to use for "Button Face"
+ COLORREF rgbShadow, // color to use for "Button Shadow"
+ COLORREF rgbHighlight, // color to use for "Button Hilight"
+ COLORREF rgbWindow, // color to use for "Window Color"
+ COLORREF rgbFrame) // color to use for "Window Frame"
+{
+ HBITMAP hbm;
+ LPBITMAPINFO lpbi;
+ HRSRC hrsrc;
+ HGLOBAL h;
+ HDC hdc;
+ DWORD size;
+
+ //
+ // Load the bitmap resource and make a writable copy.
+ //
+
+ hrsrc = FindResource(hInstance, szName, RT_BITMAP);
+ if (!hrsrc)
+ return(NULL);
+ size = SizeofResource( hInstance, hrsrc );
+ h = LoadResource(hInstance,hrsrc);
+ if (!h)
+ return(NULL);
+
+ lpbi = ( LPBITMAPINFO ) GlobalAlloc( GPTR, size );
+
+ if (!lpbi)
+ return(NULL);
+
+ CopyMemory( lpbi, h, size );
+
+ *( LPCOLORREF ) &lpbi->bmiColors[0] = RGBQ(rgbText); // Black
+ *( LPCOLORREF ) &lpbi->bmiColors[7] = RGBQ(rgbShadow); // gray
+ *( LPCOLORREF ) &lpbi->bmiColors[8] = RGBQ(rgbFace); // lt gray
+ *( LPCOLORREF ) &lpbi->bmiColors[15] = RGBQ(rgbHighlight); // white
+ *( LPCOLORREF ) &lpbi->bmiColors[11] = RGBQ(rgbWindow); // yellow
+ *( LPCOLORREF ) &lpbi->bmiColors[10] = RGBQ(rgbFrame); // green
+
+ hdc = GetDC(NULL);
+
+ hbm = CreateDIBitmap(hdc, &lpbi->bmiHeader, CBM_INIT, (LPBYTE)(&lpbi->bmiColors[ 16 ]),
+ lpbi, DIB_RGB_COLORS);
+
+ ReleaseDC(NULL, hdc);
+ GlobalFree( lpbi );
+
+ return(hbm);
+}
+
+#else
+
+HBITMAP PASCAL LoadUIBitmap(
+ HANDLE hInstance, // EXE file to load resource from
+ LPCTSTR szName, // name of bitmap resource
+ COLORREF rgbText, // color to use for "Button Text"
+ COLORREF rgbFace, // color to use for "Button Face"
+ COLORREF rgbShadow, // color to use for "Button Shadow"
+ COLORREF rgbHighlight, // color to use for "Button Hilight"
+ COLORREF rgbWindow, // color to use for "Window Color"
+ COLORREF rgbFrame) // color to use for "Window Frame"
+ {
+ LPBYTE lpb;
+ HBITMAP hbm;
+ LPBITMAPINFOHEADER lpbi;
+ HANDLE h;
+ HDC hdc;
+ LPDWORD lprgb;
+
+ h = LoadResource(hInstance,FindResource(hInstance, szName, RT_BITMAP));
+
+ lpbi = (LPBITMAPINFOHEADER)LockResource(h);
+
+ if (!lpbi)
+ return(NULL);
+
+#ifdef NOTNEEDEDFORCTL3D
+ if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
+ return NULL;
+
+ if (lpbi->biBitCount != 4)
+ return NULL;
+#endif
+
+ lprgb = (LPDWORD)((LPBYTE)lpbi + (int)lpbi->biSize);
+ lpb = (LPBYTE)(lprgb + 16);
+
+ lprgb[0] = RGBQ(rgbText); // Black
+
+// lprgb[7] = RGBQ(rgbFace); // lt gray
+// lprgb[8] = RGBQ(rgbShadow); // gray
+
+ lprgb[7] = RGBQ(rgbShadow); // gray
+ lprgb[8] = RGBQ(rgbFace); // lt gray
+
+ lprgb[15] = RGBQ(rgbHighlight); // white
+ lprgb[11] = RGBQ(rgbWindow); // yellow
+ lprgb[10] = RGBQ(rgbFrame); // green
+
+ hdc = GetDC(NULL);
+
+ hbm = CreateDIBitmap(hdc, lpbi, CBM_INIT, (LPVOID)lpb,
+ (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
+
+ ReleaseDC(NULL, hdc);
+ UnlockResource(h);
+ FreeResource(h);
+
+ return(hbm);
+ }
+
+
+#endif // win32
+
+
+/*-----------------------------------------------------------------------
+|
+| DLL specific routines
+|
+---------------------------------------------------------------WESC----*/
+
+#ifndef WIN32
+#ifdef DLL
+/*-----------------------------------------------------------------------
+| WEP
+-----------------------------------------------------------------------*/
+int FAR PASCAL WEP (int wSystemExit)
+ {
+ return 1;
+ }
+#endif
+#endif
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.def b/private/mvdm/wow16/ctl3dv2/ctl3d.def
new file mode 100644
index 000000000..55be17518
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.def
@@ -0,0 +1,41 @@
+LIBRARY Ctl3d
+
+DESCRIPTION '3d control dll'
+
+EXETYPE WINDOWS
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+HEAPSIZE 8096
+
+SEGMENTS
+ WEP_TEXT FIXED PRELOAD
+
+EXPORTS
+ WEP @1000 RESIDENTNAME
+ Ctl3dGetVer @1
+ Ctl3dSubclassDlg @2
+ Ctl3dSubclassCtl @3
+ Ctl3dCtlColor @4
+ Ctl3dEnabled @5
+ Ctl3dColorChange @6
+ BtnWndProc3d @7
+ EditWndProc3d @8
+ ListWndProc3d @9
+ ComboWndProc3d @10
+ StaticWndProc3d @11
+ Ctl3dRegister @12
+ Ctl3dUnregister @13
+ Ctl3dAutoSubclass @16
+ Ctl3dDlgProc @17
+ Ctl3dCtlColorEx @18
+ Ctl3dSetStyle @19
+ Ctl3dDlgFramePaint @20
+ Ctl3dSubclassDlgEx @21
+ Ctl3dWinIniChange @22
+ Ctl3dIsAutoSubclass @23
+ Ctl3dUnAutoSubclass @24
+ Ctl3dSubclassCtlEx @25
+ Ctl3dUnsubclassCtl @26
+ Ctl3dAutoSubclassEx @27
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.dif b/private/mvdm/wow16/ctl3dv2/ctl3d.dif
new file mode 100644
index 000000000..e283bbb16
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.dif
@@ -0,0 +1,3895 @@
+---------- NONSHIP\CTL3D\ctl3d.c (12-04-94@22:00) next ----------
+0a1,3648
+> /*-----------------------------------------------------------------------
+> |
+> | CTL3D
+> |
+> | Copyright Microsoft Corporation 1992. All Rights Reserved.
+> |
+> |
+> | This module contains the functions to give windows controls a 3d effect
+> |
+> | This source is made public for your edification and debugging pleasure
+> |
+> | PLEASE do not make any changes or release private versions of this DLL
+> | send e-mail to me (wesc) if you have feature requests or bug fixes.
+> |
+> | Thanks -- Wes.
+> |
+> |
+> | History:
+> | 1-Jan-92 : Added OOM handling on GetDC (not really necessary but
+> | XL4 OOM failure testing made GetDC return NULL)
+> |
+> | 1-Jan-92 : Check wasn't getting redrawn when state changed in
+> | the default button proc.
+> |
+> | 29-Jan-92: If button has the focus and app is switched in, we weren't
+> | redrawing the entire button check & text. Force redraw
+> | of these on WM_SETFOCUS message.
+> |
+> | 3-Feb-92: Fixed switch in via task manager by erasing the buttons
+> | backgound on WM_SETFOCUS (detect this when wParam == NULL)
+> |
+> | 4-Apr-92: Make it work with OWNERDRAW buttons
+> |
+> | 22-Apr-92: Removed Excel specific code
+> |
+> | 19-May-92: Turn it into a DLL
+> |
+> | May-Jun92: Lots o' fixes & enhancements
+> |
+> | 23-Jun-92: Added support for hiding, sizing & moving
+> |
+> | 24-Jun-92: Make checks & radio button circles draw w/ window
+> | text color 'cause they are drawn on window bkgnd
+> |
+> | 30-Jun-92: (0.984) Fix bug where EnableWindow of StaticText doesn't
+> | redraw properly. Also disable ctl3d when verWindows > 3.1
+> |
+> | 1-Jul-92: Added WIN32 support (davegi) (not in this source)
+> |
+> | 2-Jul-92: (0.984) Disable when verWindows >= 4.0
+> |
+> | 20-Jul-92: (0.985) Draw focus rects of checks/radios properly on non
+> | default sized controls.
+> |
+> | 21-Jul-92: (0.990) Ctl3dAutoSubclass
+> |
+> | 21-Jul-92: (0.991) ported DaveGi's WIN32 support
+> |
+> | 22-Jul-92: (0.991) fixed Ctl3dCtlColor returning fFalse bug
+> |
+> | 4-Aug-92: (0.992) Graphic designers bug fixes...Now subclass
+> | regular buttons + disabled states for checks & radios
+> |
+> | 6-Aug-92: (0.993) Fix bug where activate via taskman & group
+> | box has focus, & not centering text in buttons
+> |
+> | 6-Aug-92: (0.993) Tweek drawing next to scroll bars.
+> |
+> | 13-Aug-92: (0.994) Fix button focus rect bug drawing due to
+> | Win 3.0 DrawText bug.
+> |
+> | 14-Aug-92: (1.0) Release of version 1.0
+> | Don't draw default button border on BS_DEFPUSHBUTTON
+> | pushbuttons
+> | Fix bogus bug where Windows hangs when in a AUTORADIOBUTTON
+> | hold down space bar and hit arrow key.
+> |
+> | 23-Sep-92: (1.01) Made Ctl3dCtlColor call DefWindowProc so it works when
+> | called in a windproc.
+> |
+> | 28-Sep-92: (1.02) Added MyGetTextExtent so '&''s not considered in
+> | text extents.
+> |
+> | 08-Dec-92: (1.03) minor tweeks to the button text centering code
+> | for Publisher
+> |
+> | 11-Dec-92: (1.04) added 3d frames to dialogs
+> |
+> | 15-Dec-92: (1.05) fixed bug where group boxes redraw wrong when
+> | Window text is changed to something shorter
+> |
+> | ??-Dec-92: (1.06) added 3d borders
+> |
+> | 21-Dec-92: (1.07) added WM_DLGBORDER to disable borders
+> |
+> | 4-Jan-93: (1.08) fixed WM_SETTEXT bug w/ DLG frames & checks/checkboxes
+> | Also, WM_DLGSUBCLASS
+> |
+> | 22-Feb-93: (1.12) disabled it under Chicago
+> |
+> | 25-Feb-93: (1.13) re-add fix which allows dialog procs to
+> | handle WM_CTLCOLOR messages
+> |
+> | 26-April-93 (2.0) Changed to allow for second subclass. Now uses class instead of
+> | wndproc for subclass determination.
+> | store next wndproc in properties with global atoms
+> |
+> | 06-Jun-93 (2.0) Make a static linked library version.
+> |
+> |
+> -----------------------------------------------------------------------*/
+> #include <windows.h>
+>
+> #ifdef _BORLAND
+> #include <mem.h>
+> #else
+> #include <memory.h>
+> #endif
+>
+> #include <malloc.h>
+> #include "ctl3d.h"
+>
+> #include "stdio.h"
+>
+> /*-----------------------------------------------------------------------
+> |CTL3D Types
+> -----------------------------------------------------------------------*/
+> #ifdef WIN32
+>
+> #define Win32Only(e) e
+> #define Win16Only(e)
+> #define Win32Or16(e32, e16) e32
+> #define Win16Or32(e16, e32) e32
+>
+> #define _loadds
+> #define __export
+>
+> #define FValidLibHandle(hlib) ((hlib) != NULL)
+>
+> //
+> // No concept of far in Win32.
+> //
+>
+> #define MEMCMP memcmp
+> #define NPTSTR LPTSTR
+>
+> //
+> // Control IDs are LONG in Win32.
+> //
+>
+> typedef LONG CTLID;
+> #define GetControlId(hwnd) GetWindowLong(hwnd, GWL_ID)
+>
+> //
+> // Send a color button message.
+> //
+>
+> #define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc ) \
+> ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORBTN, (WPARAM) hdc, (LPARAM) hwnd))
+>
+> //
+> // Send a color static message.
+> //
+>
+> #define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc ) \
+> ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLORSTATIC, (WPARAM) hdc, (LPARAM) hwnd))
+>
+> #else
+>
+> #define CallWindowProcA CallWindowProc
+> #define DefWindowProcA DefWindowProc
+>
+> #define TEXT(a) a
+> #define TCHAR char
+>
+> #ifndef LPTSTR
+> #define LPTSTR LPSTR
+> #endif
+> #define LPCTSTR LPCSTR
+> #define NPTSTR NPSTR
+>
+> #define Win32Only(e)
+> #define Win16Only(e) e
+> #define Win32Or16(e32, e16) e16
+> #define Win16Or32(e16, e32) e16
+>
+>
+> #define FValidLibHandle(hlib) (( hlib ) > 32 )
+>
+> #define MEMCMP _fmemcmp
+>
+> typedef WORD CTLID;
+> #define GetControlId(h) GetWindowWord(h, GWW_ID)
+>
+> #define SEND_COLOR_BUTTON_MESSAGE( hwndParent, hwnd, hdc ) \
+> ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_BTN)))
+>
+> #define SEND_COLOR_STATIC_MESSAGE( hwndParent, hwnd, hdc ) \
+> ((HBRUSH) SendMessage(hwndParent, WM_CTLCOLOR, (WORD) hdc, MAKELONG(hwnd, CTLCOLOR_STATIC)))
+>
+>
+> typedef struct
+> {
+> LPARAM lParam;
+> WPARAM wParam;
+> UINT message;
+> HWND hwnd;
+> } CWPSTRUCT;
+>
+> #endif // WIN32
+>
+> // DBCS far east short cut key support
+> #define cchShortCutModeMax 10
+> #define chShortCutSbcsPrefix '\036'
+> #define chShortCutDbcsPrefix '\037'
+>
+> #define cchClassMax 16 // max class is "combolbox"+NUL rounded up to 16
+>
+>
+> #define Assert(f)
+>
+> #define PUBLIC
+> #define PRIVATE static
+>
+> #define fFalse 0
+> #define fTrue 1
+>
+> #define INCBTHOOK 1
+> #define OUTCBTHOOK 0
+>
+> #ifdef _BORLAND
+> #define CSCONST(type) type const
+> #define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
+> #define _alloca alloca
+> #define _memcmp memcmp
+> #else
+> #ifdef WIN32
+> #define CSCONST(type) type const
+> #define CodeLpszDecl(lpszVar, szLit) TCHAR *lpszVar = szLit
+> #else
+> #define CSCONST(type) type _based(_segname("_CODE")) const
+> #define CodeLpszDecl(lpszVar, szLit) \
+> static CSCONST(char) lpszVar##Code[] = szLit; \
+> char far *lpszVar = (char far *)lpszVar##Code
+> #endif
+> #endif
+>
+>
+> // isomorphic to windows RECT
+> typedef struct
+> {
+> int xLeft;
+> int yTop;
+> int xRight;
+> int yBot;
+> } RC;
+>
+>
+> // Windows Versions (Byte order flipped from GetWindowsVersion)
+> #define ver30 0x0300
+> #define ver31 0x030a
+> #define ver40 0x035F
+>
+> // Border widths
+> #define dxBorder 1
+> #define dyBorder 1
+>
+>
+> // Index Color Table
+> // WARNING: change mpicvSysColors if you change the icv order
+> typedef WORD ICV;
+> #define icvBtnHilite 0
+> #define icvBtnFace 1
+> #define icvBtnShadow 2
+>
+> #define icvBrushMax 3
+>
+> #define icvBtnText 3
+> #define icvWindow 4
+> #define icvWindowText 5
+> #define icvGrayText 6
+> #define icvWindowFrame 7
+> #define icvMax 8
+>
+> typedef COLORREF CV;
+>
+> // CoLoR Table
+> typedef struct
+> {
+> CV rgcv[icvMax];
+> } CLRT;
+>
+>
+> // BRush Table
+> typedef struct
+> {
+> HBRUSH mpicvhbr[icvBrushMax];
+> } BRT;
+>
+>
+> // DrawRec3d flags
+> #define dr3Left 0x0001
+> #define dr3Top 0x0002
+> #define dr3Right 0x0004
+> #define dr3Bot 0x0008
+>
+> #define dr3HackBotRight 0x1000 // code size is more important than aesthetics
+> #define dr3All 0x000f
+> typedef WORD DR3;
+>
+>
+> // Control Types
+> // Commdlg types are necessary because commdlg.dll subclasses certain
+> // controls before the app can call Ctl3dSubclassDlg.
+> #define ctButton 0
+> #define ctList 1
+> #define ctEdit 2
+> #define ctCombo 3
+> #define ctStatic 4
+> #define ctComboLBox 5
+> #define ctMax 6
+>
+> // ConTroL
+> typedef struct
+> {
+> FARPROC lpfn;
+> WNDPROC lpfnDefProc;
+> TCHAR szClassName[cchClassMax];
+> } CTL;
+>
+> // Control DEFinition
+> typedef struct
+> {
+> TCHAR sz[20];
+> WNDPROC lpfnWndProc;
+> BOOL (* lpfnFCanSubclass)(HWND, LONG, WORD, WORD, HWND);
+> WORD msk;
+> } CDEF;
+>
+> // CLIent HooK
+> typedef struct
+> {
+> HANDLE hinstApp;
+> HANDLE htask;
+> HHOOK hhook;
+> int iCount;
+> DWORD dwFlags;
+>
+> } CLIHK;
+>
+> #ifdef WIN32
+> #define iclihkMaxBig 1024
+> #define iclihkMaxSmall 128
+> #else
+> #define iclihkMaxBig 32
+> #define iclihkMaxSmall 4
+> #endif
+>
+> #ifdef DLL
+> #define iclihkMax iclihkMaxBig
+> #else
+> #ifdef SDLL
+> #define iclihkMax iclihkMaxBig
+> #else
+> #define iclihkMax iclihkMaxSmall
+> #define _loadds
+> #endif
+> #endif
+>
+> #ifdef SDLL
+> extern const HINSTANCE _hModule;
+> #endif
+>
+> // special styles
+> // #define bitFCoolButtons 0x0001
+>
+> /*-----------------------------------------------------------------------
+> |CTL3D Function Prototypes
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID End3dDialogs(VOID);
+> PRIVATE BOOL FAR FInit3dDialogs(VOID);
+> PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent);
+> PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce);
+> PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph);
+> PRIVATE VOID DeleteObjects(VOID);
+> PRIVATE int IclihkFromHinst(HANDLE hinst);
+>
+> LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI CDListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> LRESULT __export _loadds WINAPI CDEditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+> WORD __export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit);
+>
+> LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam);
+>
+> BOOL FBtn(HWND, LONG, WORD, WORD, HWND);
+> BOOL FEdit(HWND, LONG, WORD, WORD, HWND);
+> BOOL FList(HWND, LONG, WORD, WORD, HWND);
+> BOOL FComboList(HWND, LONG, WORD, WORD, HWND);
+> BOOL FCombo(HWND, LONG, WORD, WORD, HWND);
+> BOOL FStatic(HWND, LONG, WORD, WORD, HWND);
+>
+> HBITMAP PASCAL LoadUIBitmap(HANDLE, LPCTSTR, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF, COLORREF);
+>
+> #ifdef WIN32
+> #ifdef DLL
+> BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+> #else
+> #ifdef SDLL
+> FAR BOOL Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+> #else
+> FAR BOOL LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved);
+> #endif
+> #endif
+> #else
+> #ifdef DLL
+> int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+> #else
+> #ifdef SDLL
+> int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+> #else
+> #ifdef _BORLAND
+> int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+> #else
+> int FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine);
+> #endif
+> #endif
+> #endif
+> #endif
+>
+> #ifndef _BORLAND
+> #ifndef WIN32
+> #pragma alloc_text(INIT_TEXT, Ctl3dSetStyle)
+> #pragma alloc_text(INIT_TEXT, Ctl3dColorChange)
+> #pragma alloc_text(INIT_TEXT, Ctl3dGetVer)
+> #pragma alloc_text(INIT_TEXT, Ctl3dRegister)
+> #pragma alloc_text(INIT_TEXT, Ctl3dUnregister)
+> #pragma alloc_text(INIT_TEXT, Ctl3dAutoSubclass)
+> #pragma alloc_text(INIT_TEXT, Ctl3dEnabled)
+> #pragma alloc_text(INIT_TEXT, Ctl3dWinIniChange)
+> #pragma alloc_text(INIT_TEXT, DeleteObjects)
+> #pragma alloc_text(INIT_TEXT, DeleteObjectNull)
+> #pragma alloc_text(INIT_TEXT, InternalCtl3dColorChange)
+> #ifdef SDLL
+> #pragma alloc_text(INIT_TEXT, Ctl3dLibMain)
+> #else
+> #pragma alloc_text(INIT_TEXT, LibMain)
+> #endif
+> #pragma alloc_text(INIT_TEXT, FInit3dDialogs)
+> #pragma alloc_text(INIT_TEXT, End3dDialogs)
+> #pragma alloc_text(INIT_TEXT, LoadUIBitmap)
+> #pragma alloc_text(INIT_TEXT, IclihkFromHinst)
+> #endif
+> #endif
+>
+> #ifndef WIN32
+> #ifdef DLL
+> int FAR PASCAL WEP(int);
+> #pragma alloc_text(WEP_TEXT, WEP)
+> #endif
+> #endif
+>
+> /*-----------------------------------------------------------------------
+> |CTL3D Globals
+> -----------------------------------------------------------------------*/
+> //These static varables are only access when running 16 bit Windows or Win32s
+> //Since this is single threaded access they are OK to be statics and not protected.
+> //
+> static HHOOK hhookCallWndProcFilterProc;
+> static FARPROC lpfnSubclassByHook;
+> static HWND SubclasshWnd;
+>
+> #ifdef WIN32
+> CRITICAL_SECTION g_CriticalSection;
+> #endif
+>
+> typedef struct _g3d
+> {
+> BOOL f3dDialogs;
+> int cInited;
+> ATOM aCtl3d;
+> ATOM aCtl3dHigh;
+> ATOM aCtl3dLow;
+>
+> ATOM aCtl3dDisable;
+> // module & windows stuff
+> HANDLE hinstLib;
+> HANDLE hmodLib;
+> WORD verWindows;
+> WORD verBase;
+>
+> // drawing globals
+> CLRT clrt;
+> BRT brt;
+> HBITMAP hbmpCheckboxes;
+>
+> // Hook cache
+> HANDLE htaskCache;
+> int iclihkCache;
+> int iclihkMac;
+> CLIHK rgclihk[iclihkMax];
+>
+> // Control info
+> CTL mpctctl[ctMax];
+> FARPROC lpfnDefDlgWndProc;
+>
+> // System Metrics
+> int dxFrame;
+> int dyFrame;
+> int dyCaption;
+> int dxSysMenu;
+>
+> // Windows functions
+> #ifndef WIN32
+> #ifdef DLL
+> HHOOK (FAR PASCAL *lpfnSetWindowsHookEx)(int, HOOKPROC, HINSTANCE, HANDLE);
+> LRESULT (FAR PASCAL *lpfnCallNextHookEx)(HHOOK, int, WPARAM, LPARAM);
+> BOOL (FAR PASCAL *lpfnUnhookWindowsHookEx)(HHOOK);
+> #endif
+> #endif
+>
+> // DBCS stuff
+> char chShortCutPrefix;
+> char fDBCS;
+>
+> } G3D;
+>
+> G3D g3d;
+>
+>
+> CSCONST(CDEF) mpctcdef[ctMax] =
+> {
+> { TEXT("Button"), BtnWndProc3d, FBtn, CTL3D_BUTTONS },
+> { TEXT("ListBox"), ListWndProc3d, FList, CTL3D_LISTBOXES },
+> { TEXT("Edit"), EditWndProc3d, FEdit, CTL3D_EDITS },
+> { TEXT("ComboBox"), ComboWndProc3d, FCombo, CTL3D_COMBOS},
+> { TEXT("Static"), StaticWndProc3d, FStatic, CTL3D_STATICTEXTS|CTL3D_STATICFRAMES },
+> { TEXT("ComboLBox"), ListWndProc3d, FComboList, CTL3D_LISTBOXES },
+> };
+>
+>
+> CSCONST (WORD) mpicvSysColor[] =
+> {
+> COLOR_BTNHIGHLIGHT,
+> COLOR_BTNFACE,
+> COLOR_BTNSHADOW,
+> COLOR_BTNTEXT,
+> COLOR_WINDOW,
+> COLOR_WINDOWTEXT,
+> COLOR_GRAYTEXT,
+> COLOR_WINDOWFRAME
+> };
+>
+>
+> #define WM_CHECKSUBCLASS (WM_USER+5443)
+>
+> /*-----------------------------------------------------------------------
+> | CTL3D Utility routines
+> -----------------------------------------------------------------------*/
+>
+> PRIVATE FARPROC LpfnGetDefWndProcNull(HWND hwnd)
+> {
+> if ( hwnd == NULL )
+> return NULL;
+>
+> Win32Only(return (FARPROC) GetProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+> Win16Only(return (FARPROC) MAKELONG((UINT) GetProp(hwnd, (LPCSTR) g3d.aCtl3dLow),
+> GetProp(hwnd, (LPCSTR) g3d.aCtl3dHigh)));
+> }
+>
+> PRIVATE FARPROC LpfnGetDefWndProc(HWND hwnd, int ct)
+> {
+> FARPROC lpfnWndProc;
+>
+> lpfnWndProc = LpfnGetDefWndProcNull(hwnd);
+> if ( lpfnWndProc == NULL ) {
+> if ( ct == ctMax )
+> {
+> lpfnWndProc = (FARPROC) g3d.lpfnDefDlgWndProc;
+> }
+> else
+> {
+> lpfnWndProc = (FARPROC) g3d.mpctctl[ct].lpfnDefProc;
+> }
+>
+> Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
+> Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow, LOWORD(lpfnWndProc)));
+> Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
+> }
+> return lpfnWndProc;
+>
+> }
+>
+> PRIVATE VOID SubclassWindow(HWND hwnd, FARPROC lpfnSubclassProc)
+> {
+> FARPROC lpfnWndProc;
+>
+> // Make sure we don't double subclass (16 | 32 bit subclass??)
+> if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow))
+> {
+> return;
+> }
+>
+> // Is this already subclassed by CTL3D?
+> if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
+> {
+> lpfnWndProc = (FARPROC)SetWindowLong((HWND) hwnd, GWL_WNDPROC, (LONG) lpfnSubclassProc);
+> Win32Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3d, (HANDLE)(DWORD)lpfnWndProc));
+> Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow, LOWORD(lpfnWndProc)));
+> Win16Only(SetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh, HIWORD(lpfnWndProc)));
+> }
+> }
+>
+> LRESULT __export _loadds WINAPI CallWndProcFilterProc(int code, WPARAM wParam, LPARAM lParam)
+> {
+> CWPSTRUCT FAR *cwpStruct;
+> LONG l;
+>
+> cwpStruct = (CWPSTRUCT FAR *) lParam;
+>
+> l = CallNextHookEx(hhookCallWndProcFilterProc, code, wParam, lParam);
+>
+> if ( cwpStruct->hwnd == SubclasshWnd )
+> {
+> UnhookWindowsHookEx(hhookCallWndProcFilterProc);
+>
+> SubclassWindow(cwpStruct->hwnd, lpfnSubclassByHook);
+>
+> hhookCallWndProcFilterProc = 0L;
+> lpfnSubclassByHook = NULL;
+> SubclasshWnd = NULL;
+> }
+>
+> return l;
+> }
+>
+>
+> PRIVATE VOID HookSubclassWindow(HWND hWnd, FARPROC lpfnSubclass)
+> {
+> //
+> // Windows 3.1 ( 16 bit ) and Win32s can't sublcass in
+> // WH_CBT hook. Must set up a MSG hook and subclasss at
+> // WM_GETMINMAXINFO ( for dialogs ) or WM_NCCREATE ( for controls )
+> // Any other message and we are out of here.
+> //
+> // Notes from the inside:
+> //
+> // The only reason not to get the WM_GETMINMAXINFO/WM_NCCREATE message
+> // is if another CBT hook did not allow the window create.
+> // This code only runs/works on non multithreaded systems. Thus the global
+> // to hold the Hook Proc and subclass proc is OK.
+> //
+>
+> lpfnSubclassByHook = lpfnSubclass;
+> SubclasshWnd = hWnd;
+>
+> Win32Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentThreadId()));
+> Win16Only(hhookCallWndProcFilterProc = SetWindowsHookEx(WH_CALLWNDPROC, (FARPROC)CallWndProcFilterProc, g3d.hmodLib, GetCurrentTask()));
+> }
+>
+> PRIVATE LRESULT CleanupSubclass(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
+> {
+> FARPROC lpfnWinProc;
+> LRESULT lRet;
+>
+> lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+> lRet = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+> Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+> RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dDisable);
+> return lRet;
+> }
+>
+>
+> PRIVATE VOID DeleteObjectNull(HANDLE FAR *ph)
+> {
+> if (*ph != NULL)
+> {
+> DeleteObject(*ph);
+> *ph = NULL;
+> }
+> }
+>
+> PRIVATE VOID DeleteObjects(VOID)
+> {
+> int icv;
+>
+> for(icv = 0; icv < icvBrushMax; icv++)
+> DeleteObjectNull(&g3d.brt.mpicvhbr[icv]);
+> DeleteObjectNull(&g3d.hbmpCheckboxes);
+> }
+>
+>
+> PRIVATE VOID PatFill(HDC hdc, RC FAR *lprc)
+> {
+> PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | DrawRec3d
+> |
+> |
+> | Arguments:
+> | HDC hdc:
+> | RC FAR *lprc:
+> | LONG cvUL:
+> | LONG cvLR:
+> | WORD grbit;
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID DrawRec3d(HDC hdc, RC FAR *lprc, ICV icvUL, ICV icvLR, DR3 dr3)
+> {
+> COLORREF cvSav;
+> RC rc;
+>
+> cvSav = SetBkColor(hdc, g3d.clrt.rgcv[icvUL]);
+>
+> // top
+> rc = *lprc;
+> rc.yBot = rc.yTop+1;
+> if (dr3 & dr3Top)
+> ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+> (LPCTSTR) NULL, 0, (int far *) NULL);
+>
+> // left
+> rc.yBot = lprc->yBot;
+> rc.xRight = rc.xLeft+1;
+> if (dr3 & dr3Left)
+> ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+> (LPCTSTR) NULL, 0, (int far *) NULL);
+>
+> if (icvUL != icvLR)
+> SetBkColor(hdc, g3d.clrt.rgcv[icvLR]);
+>
+> // right
+> rc.xRight = lprc->xRight;
+> rc.xLeft = rc.xRight-1;
+> if (dr3 & dr3Right)
+> ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+> (LPCTSTR) NULL, 0, (int far *) NULL);
+>
+> // bot
+> if (dr3 & dr3Bot)
+> {
+> rc.xLeft = lprc->xLeft;
+> rc.yTop = rc.yBot-1;
+> if (dr3 & dr3HackBotRight)
+> rc.xRight -=2;
+> ExtTextOut(hdc, 0, 0, ETO_OPAQUE, (LPRECT) &rc,
+> (LPCTSTR) NULL, 0, (int far *) NULL);
+> }
+>
+> SetBkColor(hdc, cvSav);
+>
+> }
+>
+> #ifdef CANTUSE
+> // Windows forces dialog fonts to be BOLD...URRRGH
+> PRIVATE VOID MyDrawText(HWND hwnd, HDC hdc, LPSTR lpch, int cch, RC FAR *lprc, int dt)
+> {
+> TEXTMETRIC tm;
+> BOOL fChisled;
+>
+> fChisled = fFalse;
+> if (!IsWindowEnabled(hwnd))
+> {
+> GetTextMetrics(hdc, &tm);
+> if (tm.tmWeight > 400)
+> SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+> else
+> {
+> fChisled = fTrue;
+> SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
+> OffsetRect((LPRECT) lprc, -1, -1);
+> }
+> }
+> DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
+> if (fChisled)
+> {
+> SetTextColor(hdc, g3d.clrt.rgcv[icvBtnHilite]);
+> OffsetRect((LPRECT) lprc, 1, 1);
+> DrawText(hdc, lpch, cch, (LPRECT) lprc, dt);
+> }
+> }
+> #endif
+>
+>
+> PRIVATE VOID DrawInsetRect3d(HDC hdc, RC FAR *prc, DR3 dr3)
+> {
+> RC rc;
+>
+> rc = *prc;
+> DrawRec3d(hdc, &rc, icvWindowFrame, icvBtnFace, (WORD)(dr3 & dr3All));
+> rc.xLeft--;
+> rc.yTop--;
+> rc.xRight++;
+> rc.yBot++;
+> DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3);
+> }
+>
+>
+> PRIVATE VOID ClipCtlDc(HWND hwnd, HDC hdc)
+> {
+> RC rc;
+>
+> GetClientRect(hwnd, (LPRECT) &rc);
+> IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
+> }
+>
+>
+> PRIVATE int IclihkFromHinst(HANDLE hinst)
+> {
+> int iclihk;
+>
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> if (g3d.rgclihk[iclihk].hinstApp == hinst)
+> return iclihk;
+> return -1;
+> }
+>
+>
+> PRIVATE VOID MyGetTextExtent(HDC hdc, LPTSTR lpsz, int FAR *lpdx, int FAR *lpdy)
+> {
+> LPTSTR lpch;
+> TCHAR szT[256];
+>
+> lpch = szT;
+> while(*lpsz != '\000')
+> {
+> if (*lpsz == '&')
+> {
+> lpsz++;
+> if (*lpsz == '\000')
+> break;
+> }
+> //begin DBCS: far east short cut key support
+> else if (g3d.fDBCS)
+> {
+> if (*lpsz == g3d.chShortCutPrefix)
+> { // skip only prefix
+> lpsz++;
+> if (*lpsz == '\000')
+> break;
+> }
+> else if (*lpsz == chShortCutSbcsPrefix || *lpsz == chShortCutDbcsPrefix)
+> { // skip both prefix and short cut key
+> lpsz++;
+> if (*lpsz == '\000')
+> break;
+> lpsz = Win32Or16(CharNext(lpsz),AnsiNext(lpsz));
+> continue;
+> }
+> }
+> //end DBCS
+> *lpch++ = *lpsz++;
+> }
+> *lpch = '\000';
+> #ifdef WIN32
+> {
+> SIZE pt;
+>
+> GetTextExtentPoint(hdc, szT, lstrlen(szT), &pt);
+> *lpdx = pt.cx;
+> *lpdy = pt.cy;
+> }
+> #else
+> {
+> long dwExt;
+>
+> dwExt = GetTextExtent(hdc, szT, lpch-(char far *)szT);
+> *lpdx = LOWORD(dwExt);
+> // Check for Hangeul Windows - JeeP 011194
+> if ( (g3d.verWindows >= ver31 && GetSystemMetrics(SM_DBCSENABLED)) ||
+> (IsDBCSLeadByte(0xa1) && !IsDBCSLeadByte(0xa0)) )
+> *lpdy = HIWORD(dwExt)+1;
+> else
+> *lpdy = HIWORD(dwExt);
+> }
+> #endif
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | CTL3D Publics
+> -----------------------------------------------------------------------*/
+>
+>
+> PUBLIC BOOL WINAPI Ctl3dRegister(HANDLE hinstApp)
+> {
+>
+> #ifdef WIN32
+> #ifndef DLL
+> InitializeCriticalSection(&g_CriticalSection);
+> #endif
+> EnterCriticalSection(&g_CriticalSection);
+> #endif
+>
+> g3d.cInited++;
+>
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+>
+> if (g3d.cInited == 1)
+> {
+> #ifndef DLL
+> #ifdef SDLL
+> Win32Only(Ctl3dLibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
+> Win16Only(Ctl3dLibMain(hinstApp, 0, 0, (LPSTR) NULL));
+> #else
+> Win32Only(LibMain(hinstApp, DLL_PROCESS_ATTACH, (LPVOID) NULL));
+> Win16Only(LibMain(hinstApp, 0, 0, (LPSTR) NULL));
+> #endif
+> #endif
+> FInit3dDialogs();
+> }
+>
+> if (Ctl3dIsAutoSubclass())
+> Ctl3dAutoSubclass(hinstApp);
+>
+> return g3d.f3dDialogs;
+> }
+>
+>
+> PUBLIC BOOL WINAPI Ctl3dUnregister(HANDLE hinstApp)
+> {
+> int iclihk;
+> HANDLE hTask;
+>
+> //
+> // Find the task's hook
+> //
+> Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+> Win16Only(hTask = GetCurrentTask());
+>
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+>
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> {
+> if (g3d.rgclihk[iclihk].htask == hTask)
+> {
+> g3d.rgclihk[iclihk].iCount--;
+> if ( g3d.rgclihk[iclihk].iCount == 0 || hinstApp == g3d.rgclihk[iclihk].hinstApp)
+> {
+> Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+> #ifdef DLL
+> Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
+> #else
+> Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+> #endif
+> g3d.iclihkMac--;
+> while(iclihk < g3d.iclihkMac)
+> {
+> g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
+> iclihk++;
+> }
+> }
+> }
+> }
+>
+> g3d.cInited--;
+>
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+>
+> if (g3d.cInited == 0)
+> {
+> End3dDialogs();
+> }
+> return fTrue;
+> }
+>
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dAutoSubclass
+> |
+> | Automatically subclasses all dialogs of the client app.
+> |
+> | Note: Due to bugs in Commdlg, an app should still call Ctl3dSubclassDlg
+> | for the Commdlg OpenFile and PageSetup dialogs.
+> |
+> | Arguments:
+> | HANDLE hinstApp:
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dAutoSubclass(HANDLE hinstApp)
+> {
+> return Ctl3dAutoSubclassEx(hinstApp, 0);
+> }
+>
+> PUBLIC BOOL WINAPI Ctl3dAutoSubclassEx(HANDLE hinstApp, DWORD dwFlags)
+> {
+> HHOOK hhook;
+> HANDLE htask;
+> int iclihk;
+>
+> if (g3d.verWindows < ver31)
+> return fFalse;
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> #ifdef WIN32
+> // CTL3D_SUBCLASS_DYNCREATE is considered default in Win32, but
+> // not Win16 for backward compatibility reasons.
+> dwFlags |= CTL3D_SUBCLASS_DYNCREATE;
+> #endif
+> // CTL3D_NOSUBCLASS_DYNCREATE always overrides CTL3D_SUBCLASS_DYNCREATE
+> if (dwFlags & CTL3D_NOSUBCLASS_DYNCREATE)
+> dwFlags &= ~(CTL3D_NOSUBCLASS_DYNCREATE|CTL3D_SUBCLASS_DYNCREATE);
+>
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+>
+> if (g3d.iclihkMac == iclihkMax)
+> goto Fail;
+>
+> Win32Only(htask = (HANDLE)GetCurrentThreadId());
+> Win16Only(htask = GetCurrentTask());
+> //
+> // Don't set the hook twice for the same task....
+> //
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> {
+> if (g3d.rgclihk[iclihk].htask == htask)
+> {
+> g3d.rgclihk[iclihk].iCount++;
+> goto Success;
+> }
+> }
+>
+> Win32Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC)Ctl3dHook, g3d.hmodLib, (DWORD)htask));
+> #ifdef DLL
+> Win16Only(hhook = (*g3d.lpfnSetWindowsHookEx)(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
+> #else
+> Win16Only(hhook = SetWindowsHookEx(WH_CBT, (HOOKPROC) Ctl3dHook, g3d.hmodLib, hinstApp == NULL ? NULL : htask));
+> #endif
+> if (hhook != NULL)
+> {
+> g3d.rgclihk[g3d.iclihkMac].hinstApp = hinstApp;
+> g3d.rgclihk[g3d.iclihkMac].htask = htask;
+> g3d.rgclihk[g3d.iclihkMac].hhook = hhook;
+> g3d.rgclihk[g3d.iclihkMac].iCount = 1;
+> g3d.rgclihk[g3d.iclihkMac].dwFlags = dwFlags;
+> g3d.htaskCache = htask;
+> g3d.iclihkCache = g3d.iclihkMac;
+> g3d.iclihkMac++;
+> Success:
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return fTrue;
+> }
+> Fail:
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return fFalse;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dIsAutoSubclass
+> |
+> | Returns:
+> | Whether this task has Automatic Subclassing Enabled
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dIsAutoSubclass()
+> {
+> int iclihk;
+> HANDLE hTask;
+>
+> Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+> Win16Only(hTask = GetCurrentTask());
+>
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> {
+> if (g3d.rgclihk[iclihk].htask == hTask)
+> {
+> return TRUE;
+> }
+> }
+> // didn't find task in hook table.
+> return FALSE;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dUnAutoSubclass
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dUnAutoSubclass()
+> {
+> int iclihk;
+> HANDLE hTask;
+>
+> // Find the task's hook
+> //
+> //
+> Win32Only(hTask = (HANDLE)GetCurrentThreadId());
+> Win16Only(hTask = GetCurrentTask());
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> {
+> if (g3d.rgclihk[iclihk].htask == hTask)
+> {
+> g3d.rgclihk[iclihk].iCount--;
+> if ( g3d.rgclihk[iclihk].iCount == 0 )
+> {
+> Win32Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+> #ifdef DLL
+> Win16Only((*g3d.lpfnUnhookWindowsHookEx)(g3d.rgclihk[iclihk].hhook));
+> #else
+> Win16Only(UnhookWindowsHookEx(g3d.rgclihk[iclihk].hhook));
+> #endif
+> g3d.iclihkMac--;
+> while(iclihk < g3d.iclihkMac)
+> {
+> g3d.rgclihk[iclihk] = g3d.rgclihk[iclihk+1];
+> iclihk++;
+> }
+> }
+> }
+> }
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return TRUE;
+> }
+>
+> WORD __export _loadds WINAPI Ctl3dSetStyle(HANDLE hinst, LPTSTR lpszName, WORD grbit)
+> {
+> #ifdef OLD
+> WORD grbitOld;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> grbitOld = grbitStyle;
+> if (grbit != 0)
+> grbitStyle = grbit;
+>
+> if (hinst != NULL && lpszName != NULL)
+> {
+> HBITMAP hbmpCheckboxesNew;
+>
+> hbmpCheckboxesNew = LoadUIBitmap(hinst, (LPCSTR) lpszName,
+> g3d.clrt.rgcv[icvWindowText],
+> g3d.clrt.rgcv[icvBtnFace],
+> g3d.clrt.rgcv[icvBtnShadow],
+> g3d.clrt.rgcv[icvBtnHilite],
+> g3d.clrt.rgcv[icvWindow],
+> g3d.clrt.rgcv[icvWindowFrame]);
+> if (hbmpCheckboxesNew != NULL)
+> {
+> DeleteObjectNull(&g3d.hbmpCheckboxes);
+> g3d.hbmpCheckboxes = hbmpCheckboxesNew;
+> }
+> }
+>
+> return grbitOld;
+> #endif
+> return 0;
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dGetVer
+> |
+> | Returns version of CTL3D library
+> |
+> | Returns:
+> | Major version # in hibyte, minor version # in lobyte
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC WORD WINAPI Ctl3dGetVer(void)
+> {
+> return 0x0226;
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dEnabled
+> |
+> | Returns:
+> | Whether or not controls will be draw with 3d effects
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dEnabled(void)
+> {
+> return g3d.f3dDialogs;
+> }
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dSubclassCtl
+> |
+> | Subclasses an individual control
+> |
+> | Arguments:
+> | HWND hwnd:
+> |
+> | Returns:
+> | fTrue if control was successfully subclassed
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dSubclassCtl(HWND hwnd)
+> {
+> if (!g3d.f3dDialogs)
+> return fFalse;
+> return DoSubclassCtl(hwnd, CTL3D_ALL, OUTCBTHOOK, NULL);
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dUnsubclassCtl
+> |
+> | Un-Subclasses an individual control
+> |
+> | Arguments:
+> | HWND hwnd:
+> |
+> | Returns:
+> | fTrue if control was successfully subclassed
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dUnsubclassCtl(HWND hwnd)
+> {
+> FARPROC lpfnWinProc;
+> HWND hwndKids;
+> int ct;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> lpfnWinProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+>
+> // Is it a control
+> for (ct = 0; ct < ctMax; ct++)
+> {
+> if ( lpfnWinProc == g3d.mpctctl[ct].lpfn )
+> {
+> lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+> Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+> SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
+> lpfnWinProc = NULL;
+> ct = ctMax+10;
+> }
+> }
+>
+> // How about a dlg ?
+> if ( ct == ctMax )
+> {
+> if ( lpfnWinProc == (FARPROC) Ctl3dDlgProc )
+> {
+> lpfnWinProc = LpfnGetDefWndProc(hwnd, ct);
+> Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+> SetWindowLong(hwnd, GWL_WNDPROC, (LONG) lpfnWinProc );
+> lpfnWinProc = NULL;
+> }
+> else
+> {
+> // None of the above, add disable property
+> SetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable, (HANDLE) 1);
+> }
+> }
+>
+> //
+> // Now unsubclass all the kids
+> //
+> for (hwndKids = GetWindow(hwnd, GW_CHILD); hwndKids != NULL;
+> hwndKids = GetWindow(hwndKids, GW_HWNDNEXT))
+> {
+> Ctl3dUnsubclassCtl(hwndKids);
+> }
+>
+> return fTrue;
+>
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dSubclassCtlEx
+> |
+> | Actually subclass the control
+> |
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dSubclassCtlEx(HWND hwnd, int ct)
+> {
+> LONG style;
+> BOOL fCan;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> if (ct < 0 || ct > ctMax)
+> return fFalse;
+>
+> // Is this already subclassed by CTL3D?
+> if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
+> return fFalse;
+>
+> // Only subclass it if it is something that we'd normally subclass
+> style = GetWindowLong(hwnd, GWL_STYLE);
+> fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, CTL3D_ALL,
+> OUTCBTHOOK, GetParent(hwnd));
+> if (fCan == fTrue)
+> SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+>
+> return fTrue;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dSubclassDlg
+> |
+> | Call this during WM_INITDIALOG processing.
+> |
+> | Arguments:
+> | hwndDlg:
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dSubclassDlg(HWND hwndDlg, WORD grbit)
+> {
+> HWND hwnd;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+> hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+> {
+> DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, NULL);
+> }
+> return fTrue;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dCheckSubclassDlg
+> |
+> | Call this during WM_INITDIALOG processing.
+> |
+> | Arguments:
+> | hwndDlg:
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE void CheckChildSubclass(HWND hwnd, WORD grbit, HWND hwndParent)
+> {
+> // Is this already subclassed by CTL3D?
+> // Is our property there ?
+> if (LpfnGetDefWndProcNull(hwnd) == (FARPROC) NULL)
+> {
+> // No, how did this slip by, try a subclass again.
+> DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
+> }
+> else
+> {
+> // Yes, we have subclassed this control.
+> // Is our subclass still on the chain ?
+> BOOL fSubclass;
+>
+> // Make sure subclassing isn't disabled...
+> if (GetProp(hwnd, (LPCTSTR)g3d.aCtl3dDisable))
+> return;
+>
+> fSubclass = 666;
+> SendMessage((HWND) hwnd, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+>
+> if ( fSubclass == 666 ) // Evil
+> {
+> // We have been un-subclassed by some bad app ( common dialogs in Win16 )
+> // Remove the Prop, and subclass again, take that.
+> Win32Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3d));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dLow));
+> Win16Only(RemoveProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh));
+> DoSubclassCtl(hwnd, grbit, OUTCBTHOOK, hwndParent);
+> }
+> }
+> }
+>
+> PUBLIC BOOL WINAPI Ctl3dCheckSubclassDlg(HWND hwndDlg, WORD grbit)
+> {
+> HWND hwnd, hwnd2;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> for (hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+> hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+> {
+> CheckChildSubclass(hwnd, grbit, NULL);
+> for (hwnd2 = GetWindow(hwnd, GW_CHILD); hwnd2 != NULL;
+> hwnd2 = GetWindow(hwnd2, GW_HWNDNEXT))
+> {
+> CheckChildSubclass(hwnd2, grbit, hwnd);
+> }
+> }
+>
+> return fTrue;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dSubclassDlgEx
+> |
+> | Call this during WM_INITDIALOG processing. This is like
+> | Ctl3dSubclassDlg but it also subclasses the dialog window itself
+> | so the app doesn't need to.
+> |
+> | Arguments:
+> | hwndDlg:
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dSubclassDlgEx(HWND hwndDlg, DWORD grbit)
+> {
+> HWND hwnd;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> for(hwnd = GetWindow(hwndDlg, GW_CHILD); hwnd != NULL;
+> hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+> {
+> DoSubclassCtl(hwnd, LOWORD(grbit), OUTCBTHOOK, NULL);
+> }
+>
+> //
+> // Now Subclass the dialog window as well
+> //
+> SubclassWindow((HWND) hwndDlg, (FARPROC)Ctl3dDlgProc);
+>
+> return fTrue;
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dCtlColor
+> |
+> | Common CTL_COLOR processor for 3d UITF dialogs & alerts.
+> |
+> | Arguments:
+> | hdc:
+> | lParam:
+> |
+> | Returns:
+> | appropriate brush if g3d.f3dDialogs. Returns fFalse otherwise
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC HBRUSH WINAPI Ctl3dCtlColor(HDC hdc, LPARAM lParam)
+> {
+> #ifdef WIN32
+> return (HBRUSH) fFalse;
+> #else
+> HWND hwndParent;
+>
+> Assert(CTLCOLOR_MSGBOX < CTLCOLOR_BTN);
+> Assert(CTLCOLOR_EDIT < CTLCOLOR_BTN);
+> Assert(CTLCOLOR_LISTBOX < CTLCOLOR_BTN);
+> if(g3d.f3dDialogs)
+> {
+> if (HIWORD(lParam) >= CTLCOLOR_LISTBOX)
+> {
+> if (HIWORD(lParam) == CTLCOLOR_LISTBOX &&
+> (g3d.verWindows >= ver40 ||
+> ((GetWindow(LOWORD(lParam), GW_CHILD) == NULL ||
+> (GetWindowLong(LOWORD(lParam), GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
+> {
+> // if it doesn't have a child then it must be a list box
+> // don't do brush stuff for drop down lists or else
+> // it draws funny grey inside the edit rect
+> goto DefWP;
+> }
+> SetTextColor(hdc, g3d.clrt.rgcv[icvBtnText]);
+> SetBkColor(hdc, g3d.clrt.rgcv[icvBtnFace]);
+> return g3d.brt.mpicvhbr[icvBtnFace];
+> }
+> }
+> DefWP:
+> hwndParent = GetParent(LOWORD(lParam));
+> if (hwndParent == NULL)
+> return fFalse;
+> return (HBRUSH) DefWindowProc(hwndParent, WM_CTLCOLOR, (WPARAM) hdc, (LONG) lParam);
+> #endif
+> }
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dCtlColorEx
+> |
+> | Common CTL_COLOR processor for 3d UITF dialogs & alerts.
+> |
+> | Arguments:
+> |
+> | Returns:
+> | appropriate brush if g3d.f3dDialogs. Returns fFalse otherwise
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC HBRUSH WINAPI Ctl3dCtlColorEx(UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> #ifdef WIN32
+> Assert(WM_CTLCOLORMSGBOX < WM_CTLCOLORBTN);
+> Assert(WM_CTLCOLOREDIT < WM_CTLCOLORBTN);
+> Assert(WM_CTLCOLORLISTBOX < WM_CTLCOLORBTN);
+> if(g3d.f3dDialogs)
+> {
+> if (wm >= WM_CTLCOLORLISTBOX && wm != WM_CTLCOLORSCROLLBAR)
+> {
+> if (wm == WM_CTLCOLORLISTBOX &&
+> (g3d.verWindows >= ver40 ||
+> ((GetWindow((HWND) lParam, GW_CHILD) == NULL ||
+> (GetWindowLong((HWND) lParam, GWL_STYLE) & 0x03) == CBS_DROPDOWNLIST))))
+> {
+> // if it doesn't have a child then it must be a list box
+> // don't do brush stuff for drop down lists or else
+> // it draws funny grey inside the edit rect
+> return (HBRUSH) fFalse;
+> }
+> SetTextColor((HDC) wParam, g3d.clrt.rgcv[icvBtnText]);
+> SetBkColor((HDC) wParam, g3d.clrt.rgcv[icvBtnFace]);
+> return g3d.brt.mpicvhbr[icvBtnFace];
+> }
+> }
+> return (HBRUSH) fFalse;
+> #else
+> return Ctl3dCtlColor(wParam, lParam);
+> #endif
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dColorChange
+> |
+> | App calls this when it gets a WM_SYSCOLORCHANGE message
+> |
+> | Returns:
+> | TRUE if successful.
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC BOOL WINAPI Ctl3dColorChange(VOID)
+> {
+> BOOL bResult;
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+> bResult = InternalCtl3dColorChange(fFalse);
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return bResult;
+> }
+>
+> PRIVATE LONG WINAPI
+> Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP);
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dDlgFramePaint
+> |
+> | App calls this when it gets a NC_PAINT message
+> |
+> | Returns:
+> | TRUE if successful.
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC LONG WINAPI Ctl3dDlgFramePaint(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, TRUE);
+> }
+>
+> // Ctl3dDlgFramePaintI used only internally by Ctl3d
+> PRIVATE LONG WINAPI
+> Ctl3dDlgFramePaintI(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, BOOL fDefWP)
+> {
+> LONG lResult;
+> LONG lStyle;
+> BOOL fBorder;
+>
+> WNDPROC defProc = fDefWP ? NULL : (WNDPROC) LpfnGetDefWndProc(hwnd, ctMax);
+>
+> if (defProc != NULL)
+> lResult = CallWindowProc((FARPROC)defProc, hwnd, wm, wParam, lParam);
+> else
+> lResult = DefWindowProc(hwnd, wm, wParam, lParam);
+>
+> if (!g3d.f3dDialogs)
+> return lResult;
+>
+> if ( IsIconic(hwnd) )
+> return lResult;
+>
+> fBorder = CTL3D_BORDER;
+> SendMessage(hwnd, WM_DLGBORDER, 0, (LPARAM)(int FAR *)&fBorder);
+> lStyle = GetWindowLong(hwnd, GWL_STYLE);
+> if (fBorder != CTL3D_NOBORDER && (lStyle & (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME)) == (WS_VISIBLE|WS_DLGFRAME|DS_MODALFRAME))
+> {
+> BOOL fCaption;
+> HBRUSH hbrSav;
+> HDC hdc;
+> RC rc;
+> RC rcFill;
+> int dyFrameTop;
+>
+> fCaption = (lStyle & WS_CAPTION) == WS_CAPTION;
+> dyFrameTop = g3d.dyFrame - (fCaption ? dyBorder : 0);
+>
+> hdc = GetWindowDC(hwnd);
+> GetWindowRect(hwnd, (LPRECT) &rc);
+> rc.xRight = rc.xRight-rc.xLeft;
+> rc.yBot = rc.yBot-rc.yTop;
+> rc.xLeft = rc.yTop = 0;
+>
+> DrawRec3d(hdc, &rc, icvBtnShadow, icvWindowFrame, dr3All);
+> InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
+> InflateRect((LPRECT) &rc, -dxBorder, -dyBorder);
+>
+> hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
+> rcFill = rc;
+> // Left
+> rcFill.xRight = rcFill.xLeft+g3d.dxFrame;
+> PatFill(hdc, &rcFill);
+> // Right
+> OffsetRect((LPRECT) &rcFill, rc.xRight-rc.xLeft-g3d.dxFrame, 0);
+> PatFill(hdc, &rcFill);
+> // Top
+> rcFill.xLeft = rc.xLeft + g3d.dxFrame;
+> rcFill.xRight = rc.xRight - g3d.dxFrame;
+> rcFill.yBot = rcFill.yTop+dyFrameTop;
+> PatFill(hdc, &rcFill);
+> if (fCaption)
+> {
+> RC rcT;
+>
+> rcT = rcFill;
+> rcT.yTop += dyFrameTop;
+> rcT.yBot = rcT.yTop + g3d.dyCaption;
+> DrawRec3d(hdc, &rcT, icvBtnShadow, icvBtnHilite, dr3All);
+> }
+>
+> // Bottom
+> rcFill.yTop += rc.yBot-rc.yTop-g3d.dxFrame;
+> rcFill.yBot = rcFill.yTop + g3d.dyFrame;
+> PatFill(hdc, &rcFill);
+> #ifdef CHISLEBORDER
+> if (fBorder == CTL3D_CHISLEBORDER)
+> {
+> // This code doesn't work because it draws in the client area
+> GetClientRect(hwnd, (LPRECT) &rc);
+> OffsetRect((LPRECT) &rc, g3d.dxFrame+2*dxBorder, fCaption ? g3d.dyFrame+g3d.dyCaption : g3d.dyFrame+dyBorder);
+> DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3Bot|dr3Left|dr3Right);
+> rc.xLeft++;
+> rc.xRight--;
+> rc.yBot--;
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3Bot|dr3Left|dr3Right);
+> }
+> #endif
+> SelectObject(hdc, hbrSav);
+> ReleaseDC(hwnd, hdc);
+> }
+> return lResult;
+> }
+>
+>
+> //begin DBCS: far east short cut key support
+> /*-----------------------------------------------------------------------
+> | CTL3D Far East Support
+> -----------------------------------------------------------------------*/
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dWinIniChange
+> |
+> | App calls this when it gets a WM_WININICHANGE message
+> |
+> | Returns:
+> | none
+> |
+> -----------------------------------------------------------------------*/
+> PUBLIC VOID WINAPI Ctl3dWinIniChange(void)
+> {
+> TCHAR szShortCutMode[cchShortCutModeMax];
+> CodeLpszDecl(szSectionWindows, TEXT("windows"));
+> CodeLpszDecl(szEntryShortCutKK, TEXT("kanjimenu"));
+> CodeLpszDecl(szEntryShortCutCH, TEXT("hangeulmenu"));
+> CodeLpszDecl(szShortCutSbcsKK, TEXT("roman"));
+> CodeLpszDecl(szShortCutSbcsCH, TEXT("english"));
+> CodeLpszDecl(szShortCutDbcsKK, TEXT("kanji"));
+> CodeLpszDecl(szShortCutDbcsCH, TEXT("hangeul"));
+>
+> if (!g3d.fDBCS)
+> return;
+>
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+>
+> g3d.chShortCutPrefix = chShortCutSbcsPrefix;
+> GetProfileString(szSectionWindows, szEntryShortCutKK, szShortCutSbcsKK, szShortCutMode, cchShortCutModeMax - 1);
+> if (!lstrcmpi(szShortCutMode, szShortCutDbcsKK))
+> g3d.chShortCutPrefix = chShortCutDbcsPrefix;
+> GetProfileString(szSectionWindows, szEntryShortCutCH, szShortCutSbcsCH, szShortCutMode, cchShortCutModeMax - 1);
+> if (!lstrcmpi(szShortCutMode, szShortCutDbcsCH))
+> g3d.chShortCutPrefix = chShortCutDbcsPrefix;
+>
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> }
+> //end DBCS
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | CTL3D Internal Routines
+> -----------------------------------------------------------------------*/
+>
+>
+> /*-----------------------------------------------------------------------
+> | FInit3dDialogs
+> |
+> | Initialized 3d stuff
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE BOOL FAR FInit3dDialogs(VOID)
+> {
+> HDC hdc;
+> WNDCLASS wc;
+>
+> #ifdef DLL
+> #ifdef V2
+> int nChars;
+> LPTSTR pCh;
+> static TCHAR MyDirectory[260];
+> TCHAR OkDirectory[260];
+> #endif
+> #endif
+>
+> //if (g3d.verWindows >= ver40)
+> // {
+> // g3d.f3dDialogs = fFalse;
+> // return fFalse;
+> // }
+>
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+>
+> #ifdef DLL
+> #ifdef V2
+>
+> #ifdef WIN32
+> {
+> TCHAR szT[2];
+> CodeLpszDecl(szSpecial, TEXT("Ctl3d_RunAlways"));
+> if (GetEnvironmentVariable(szSpecial, szT, 2) != 0 && szT[0] == '1')
+> {
+> goto AllowBadInstall;
+> }
+> }
+> #endif
+>
+> #ifdef WIN32
+> #ifdef UNICODE
+> if (GetVersion() & 0x80000000)
+> {
+> Win16Or32(
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+> CodeLpszDecl(lpszBadInstMsg,
+> TEXT("This application uses CTL3D32.DLL, which is not the correct version. ")
+> TEXT("This version of CTL3D32.DLL is designed only for Windows NT systems."));
+> MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+> #else
+> if (!(GetVersion() & 0x80000000))
+> {
+> Win16Or32(
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+> CodeLpszDecl(lpszBadInstMsg,
+> TEXT("This application uses CTL3D32.DLL, which is not the correct version. ")
+> TEXT("This version of CTL3D32.DLL is designed only for Win32s or Windows 95 systems."));
+> MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+> #endif
+> #endif
+> nChars = GetModuleFileName(g3d.hinstLib, MyDirectory, sizeof(MyDirectory)Win32Only(/sizeof(TCHAR)));
+> for (pCh = (LPTSTR)(MyDirectory+nChars-1);
+> pCh >= (LPTSTR)MyDirectory;
+> pCh = Win32Or16(CharPrev(MyDirectory, pCh),AnsiPrev(MyDirectory, pCh)))
+> {
+> if ( *pCh == '\\' )
+> {
+> if ( *(pCh-1) != ':' )
+> *pCh = 0;
+> else
+> *(pCh+1) = 0;
+> break;
+> }
+> }
+>
+> nChars = GetSystemDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
+> if ( lstrcmpi(MyDirectory,OkDirectory ) )
+> {
+> nChars = GetWindowsDirectory(OkDirectory, sizeof(OkDirectory)Win32Only(/sizeof(TCHAR)));
+> if ( lstrcmpi(MyDirectory,OkDirectory ) )
+> {
+> Win16Or32(
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+> CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+> Win16Or32(
+> CodeLpszDecl(lpszBadInstMsg,
+> TEXT("This application uses CTL3DV2.DLL, which has not been correctly installed. ")
+> TEXT("CTL3DV2.DLL must be installed in the Windows system directory.")),
+> CodeLpszDecl(lpszBadInstMsg,
+> TEXT("This application uses CTL3D32.DLL, which has not been correctly installed. ")
+> TEXT("CTL3D32.DLL must be installed in the Windows system directory.")));
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK );
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+> }
+>
+> Win32Only(AllowBadInstall:;)
+> #endif
+> #endif
+>
+> hdc = GetDC(NULL);
+> g3d.f3dDialogs = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES) >= 4;
+> // Win 3.1 EGA lies to us...
+> if(GetSystemMetrics(SM_CYSCREEN) == 350 && GetSystemMetrics(SM_CXSCREEN) == 640)
+> g3d.f3dDialogs = fFalse;
+> ReleaseDC(NULL, hdc);
+> if (g3d.f3dDialogs)
+> {
+> int ct;
+> CodeLpszDecl(lpszC3dD, TEXT("C3dD"));
+>
+> CodeLpszDecl(lpszC3d, TEXT("C3d"));
+> CodeLpszDecl(lpszC3dL, TEXT("C3dL"));
+> CodeLpszDecl(lpszC3dH, TEXT("C3dH"));
+>
+> g3d.aCtl3d = GlobalAddAtom(lpszC3d);
+> if (g3d.aCtl3d == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+>
+> g3d.aCtl3dLow = GlobalAddAtom(lpszC3dL);
+> g3d.aCtl3dHigh = GlobalAddAtom(lpszC3dH);
+> if (g3d.aCtl3dLow == 0 || g3d.aCtl3dHigh == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> return fFalse;
+> }
+>
+> g3d.aCtl3dDisable = GlobalAddAtom(lpszC3dD);
+> if (g3d.aCtl3dDisable == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+>
+> // DBCS
+> g3d.fDBCS = GetSystemMetrics(SM_DBCSENABLED);
+> Ctl3dWinIniChange();
+>
+> if (InternalCtl3dColorChange(fTrue)) // load bitmap & brushes
+> {
+> for (ct = 0; ct < ctMax; ct++)
+> {
+> g3d.mpctctl[ct].lpfn = (FARPROC)mpctcdef[ct].lpfnWndProc;
+> Assert(g3d.mpctctl[ct].lpfn != NULL);
+> GetClassInfo(NULL, mpctcdef[ct].sz, (LPWNDCLASS) &wc);
+> g3d.mpctctl[ct].lpfnDefProc = wc.lpfnWndProc;
+> }
+> if (GetClassInfo(NULL, WC_DIALOG, &wc))
+> g3d.lpfnDefDlgWndProc = (FARPROC) wc.lpfnWndProc;
+> else
+> g3d.lpfnDefDlgWndProc = (FARPROC) DefDlgProc;
+> }
+> else
+> {
+> g3d.f3dDialogs = fFalse;
+> }
+> }
+> Return:
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return g3d.f3dDialogs;
+> }
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | End3dDialogs
+> |
+> | Called at DLL termination to free 3d dialog stuff
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID End3dDialogs(VOID)
+> {
+> int ct;
+>
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+>
+> for (ct = 0; ct < ctMax; ct++)
+> {
+> if(g3d.mpctctl[ct].lpfn != NULL)
+> {
+> FreeProcInstance(g3d.mpctctl[ct].lpfn);
+> g3d.mpctctl[ct].lpfn = NULL;
+> }
+> }
+> DeleteObjects();
+> Win32Only(g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0);
+> Win16Only(g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0);
+> Win16Only(g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0);
+> g3d.aCtl3dDisable ? GlobalDeleteAtom(g3d.aCtl3dDisable) : 0;
+>
+> g3d.f3dDialogs = fFalse;
+>
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+>
+> }
+>
+>
+> PRIVATE BOOL InternalCtl3dColorChange(BOOL fForce)
+> {
+> ICV icv;
+> CLRT clrtNew;
+> HBITMAP hbmpCheckboxesNew;
+> BRT brtNew;
+>
+> if (!g3d.f3dDialogs)
+> return fFalse;
+>
+> for (icv = 0; icv < icvMax; icv++)
+> clrtNew.rgcv[icv] = GetSysColor(mpicvSysColor[icv]);
+>
+> if (g3d.verWindows == ver30)
+> clrtNew.rgcv[icvBtnHilite] = RGB(0xff, 0xff, 0xff);
+>
+> if (clrtNew.rgcv[icvGrayText] == 0L || clrtNew.rgcv[icvGrayText] == clrtNew.rgcv[icvBtnFace])
+> {
+> if (clrtNew.rgcv[icvBtnFace] == RGB(0x80, 0x80, 0x80))
+> clrtNew.rgcv[icvGrayText] = RGB(0xc0, 0xc0, 0xc0);
+> else
+> clrtNew.rgcv[icvGrayText] = RGB(0x80, 0x80, 0x80);
+> }
+>
+> if (fForce || MEMCMP(&g3d.clrt, &clrtNew, sizeof(CLRT)))
+> {
+> hbmpCheckboxesNew = LoadUIBitmap(g3d.hinstLib, MAKEINTRESOURCE(CTL3D_3DCHECK),
+> clrtNew.rgcv[icvWindowText],
+> clrtNew.rgcv[icvBtnFace],
+> clrtNew.rgcv[icvBtnShadow],
+> clrtNew.rgcv[icvBtnHilite],
+> clrtNew.rgcv[icvWindow],
+> clrtNew.rgcv[icvWindowFrame]);
+>
+> for (icv = 0; icv < icvBrushMax; icv++)
+> brtNew.mpicvhbr[icv] = CreateSolidBrush(clrtNew.rgcv[icv]);
+>
+> for (icv = 0; icv < icvBrushMax; icv++)
+> if (brtNew.mpicvhbr[icv] == NULL)
+> goto OOM;
+>
+> if(hbmpCheckboxesNew != NULL)
+> {
+> DeleteObjects();
+> g3d.brt = brtNew;
+> g3d.clrt = clrtNew;
+> g3d.hbmpCheckboxes = hbmpCheckboxesNew;
+> return fTrue;
+> }
+> else
+> {
+> OOM:
+> for (icv = 0; icv < icvBrushMax; icv++)
+> DeleteObjectNull(&brtNew.mpicvhbr[icv]);
+> DeleteObjectNull(&hbmpCheckboxesNew);
+> return fFalse;
+> }
+> }
+> return fTrue;
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dDlgProc
+> |
+> | Subclass DlgProc for use w/ Ctl3dAutoSubclass
+> |
+> |
+> | Arguments:
+> | HWND hwnd:
+> | int wm:
+> | WORD wParam:
+> | LPARAM lParam:
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> LRESULT __export _loadds WINAPI Ctl3dDlgProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> HBRUSH hbrush;
+> FARPROC lpfnDlgProc;
+> TCHAR szClass[cchClassMax];
+>
+> if ( wm == WM_NCDESTROY )
+> return CleanupSubclass(hwnd, wm, wParam, lParam, ctMax);
+>
+> if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+>
+> switch (wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctMax+1000;
+>
+> case WM_INITDIALOG:
+> {
+> long l;
+> BOOL fSubclass;
+> FARPROC lpfnWinProc;
+>
+> lpfnWinProc = LpfnGetDefWndProc(hwnd, ctMax);
+>
+> if (g3d.verWindows >= ver40 && (GetWindowLong(hwnd, GWL_STYLE) & 0x04))
+> fSubclass = fFalse;
+> else
+> fSubclass = fTrue;
+> SendMessage(hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+>
+> if (!fSubclass)
+> {
+> Ctl3dUnsubclassCtl(hwnd);
+> return CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+> }
+>
+> l = CallWindowProc(lpfnWinProc, hwnd, wm, wParam, lParam);
+>
+> if (g3d.verWindows < ver40 || !(GetWindowLong(hwnd, GWL_STYLE) & 0x04))
+> Ctl3dCheckSubclassDlg(hwnd, CTL3D_ALL);
+>
+> return l;
+> }
+>
+> case WM_NCPAINT:
+> case WM_NCACTIVATE:
+> case WM_SETTEXT:
+> if (g3d.verWindows >= ver40 || IsIconic(hwnd) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+> else
+> return Ctl3dDlgFramePaintI(hwnd, wm, wParam, lParam, FALSE);
+>
+> #ifdef WIN32
+> case WM_CTLCOLORSCROLLBAR:
+> case WM_CTLCOLORBTN:
+> case WM_CTLCOLORDLG:
+> case WM_CTLCOLOREDIT:
+> case WM_CTLCOLORLISTBOX:
+> case WM_CTLCOLORMSGBOX:
+> case WM_CTLCOLORSTATIC:
+> #else
+> case WM_CTLCOLOR:
+> #endif
+> // Is this really a dialog
+> GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+> if (lstrcmp(TEXT("#32770"),szClass) != 0 )
+> {
+> #ifdef WIN32
+> hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+> wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+> #else
+> hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+> CTL3D_CTLCOLOR, wParam, lParam);
+> #endif
+> if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+> hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+> }
+> else
+> {
+> lpfnDlgProc = (FARPROC) GetWindowLong(hwnd, DWL_DLGPROC);
+>
+> if (lpfnDlgProc == NULL )
+> {
+> hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+> }
+> else
+> {
+> #ifdef WIN32
+> if ( (LONG)lpfnDlgProc > 0xFFFF0000 && g3d.verWindows <= ver31)
+> {
+> // We have a Uni-code / non Unicode issue.
+> // If this is before Daytona, then I CAN NOT call because it may be NULL, but
+> // the returned value is not-null. NT Bug.
+> // So Just send our own message to the window proc instead
+> hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+> wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+> if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+> hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+> }
+> else
+> {
+> #endif
+> hbrush = (HBRUSH) CallWindowProc(lpfnDlgProc, hwnd, wm, wParam, lParam);
+> if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+> {
+> #ifdef WIN32
+> hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+> wm-WM_CTLCOLORMSGBOX+CTLMSGOFFSET, wParam, lParam);
+> #else
+> hbrush = (HBRUSH) CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd,
+> CTL3D_CTLCOLOR, wParam, lParam);
+> #endif
+> if (hbrush == (HBRUSH) fFalse || hbrush == (HBRUSH)1)
+> hbrush = Ctl3dCtlColorEx(wm, wParam, lParam);
+> }
+> }
+> #ifdef WIN32
+> }
+> #endif
+> }
+> if (hbrush != (HBRUSH) fFalse)
+> return (LRESULT)hbrush;
+> break;
+> }
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctMax), hwnd, wm, wParam, lParam);
+> }
+>
+> PRIVATE BOOL NEAR DoesChildNeedSubclass(HWND hwnd)
+> {
+> if (!LpfnGetDefWndProcNull(hwnd))
+> return fFalse;
+> if (g3d.verWindows >= ver40 && GetWindowLong(hwnd, GWL_STYLE) & 0x04)
+> return fFalse;
+> return fTrue;
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Ctl3dHook
+> |
+> | CBT Hook to watch for window creation. Automatically subclasses all
+> | dialogs w/ Ctl3dDlgProc
+> |
+> | Arguments:
+> | int code:
+> | WORD wParam:
+> | LPARAM lParam:
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> LRESULT __export _loadds WINAPI Ctl3dHook(int code, WPARAM wParam, LPARAM lParam)
+> {
+> int iclihk;
+> HANDLE htask;
+>
+> htask = Win32Or16((HANDLE)GetCurrentThreadId(), GetCurrentTask());
+> Win32Only(EnterCriticalSection(&g_CriticalSection));
+> if (htask != g3d.htaskCache)
+> {
+> for (iclihk = 0; iclihk < g3d.iclihkMac; iclihk++)
+> {
+> if (g3d.rgclihk[iclihk].htask == htask)
+> {
+> g3d.iclihkCache = iclihk;
+> g3d.htaskCache = htask;
+> break;
+> }
+> }
+> if ( iclihk == g3d.iclihkMac )
+> {
+> // didn't find task in hook table. This could be bad, but
+> // returning 0L is about all we can doo.
+> //
+> // Actually not. The hhook isn't used anyway just set it to NULL.
+> // and call the next hook..... KGM
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+> return CallNextHookEx((HHOOK)0L, code, wParam, lParam);
+> }
+> }
+> iclihk = g3d.iclihkCache;
+> Win32Only(LeaveCriticalSection(&g_CriticalSection));
+>
+> if (code == HCBT_CREATEWND)
+> {
+> LPCREATESTRUCT lpcs;
+> lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;
+>
+> if (lpcs->lpszClass == WC_DIALOG)
+> {
+> if (g3d.verBase == 32)
+> {
+> SubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+> }
+> else
+> {
+> HookSubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+> }
+> goto Zing;
+> }
+> if (!(g3d.rgclihk[iclihk].dwFlags & CTL3D_SUBCLASS_DYNCREATE))
+> goto Zing;
+>
+> if (DoesChildNeedSubclass(lpcs->hwndParent) ||
+> (lpcs->hwndParent && g3d.verBase != 24 &&
+> DoesChildNeedSubclass(GetParent(lpcs->hwndParent))))
+> {
+> DoSubclassCtl((HWND)wParam, CTL3D_ALL, INCBTHOOK, lpcs->hwndParent);
+> }
+> }
+>
+> Zing:;
+> Win32Only(return CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
+> #ifdef DLL
+> Win16Only(return (*g3d.lpfnCallNextHookEx)(g3d.rgclihk[iclihk].hhook, code, wParam, lParam));
+> #else
+> Win16Only(return (CallNextHookEx(g3d.rgclihk[iclihk].hhook, code, wParam, lParam)));
+> #endif
+> }
+>
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | CTL3D F* routines
+> |
+> | These routines determine whether or not the given control may be
+> | subclassed. They may recursively call DoSubclassCtl in the
+> | case of multi-control controls
+> |
+> | Returns:
+> | fTrue if can subclass the given control.
+> -----------------------------------------------------------------------*/
+>
+>
+> PRIVATE BOOL FBtn(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> if (g3d.verWindows >= ver40)
+> {
+> return fFalse;
+> }
+> style &= ~(BS_LEFTTEXT);
+> return ( LOWORD(style) >= BS_PUSHBUTTON && LOWORD(style) <= BS_AUTORADIOBUTTON);
+> }
+>
+> PRIVATE BOOL FEdit(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> if (g3d.verWindows >= ver40 && hwndParent)
+> {
+> TCHAR szClass[cchClassMax];
+> GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+> if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
+> return fFalse;
+> else
+> return fTrue;
+> }
+> else
+> return fTrue;
+> }
+>
+> PRIVATE BOOL FList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> if (g3d.verWindows >= ver40 && hwndParent)
+> {
+> TCHAR szClass[cchClassMax];
+> GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+> if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 )
+> return fFalse;
+> else
+> return fTrue;
+> }
+> else
+> return fTrue;
+> }
+>
+> PRIVATE BOOL FComboList(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+>
+> if (g3d.verWindows >= ver40)
+> return fFalse;
+>
+> if ( wCallFlags == INCBTHOOK )
+> {
+> LONG style;
+> style = GetWindowLong(hwndParent, GWL_STYLE);
+> if (!(((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+> return fTrue;
+> else
+> return fFalse;
+> }
+>
+> return fTrue;
+> }
+>
+> PRIVATE BOOL FCombo(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> HWND hwndEdit;
+> HWND hwndList;
+>
+> if (g3d.verWindows >= ver40)
+> return fFalse;
+>
+> if ((style & 0x0003) == CBS_DROPDOWN)
+> {
+> if ( wCallFlags == INCBTHOOK )
+> {
+> return fFalse;
+> }
+> // Subclass edit so bottom border of the edit draws properly...This case
+> // is specially handled in ListEditPaint3d
+> hwndEdit = GetWindow(hwnd, GW_CHILD);
+> if (hwndEdit != NULL)
+> DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
+> return fTrue;
+> }
+> else if ((style & 0x0003) == CBS_DROPDOWNLIST )
+> {
+> return fTrue;
+> }
+> else // assume simple // if ((style & 0x0003) == CBS_SIMPLE)
+> {
+> if ( wCallFlags == INCBTHOOK )
+> {
+> return fTrue;
+> }
+> hwndList = GetWindow(hwnd, GW_CHILD);
+> if (hwndList != NULL)
+> {
+> // Subclass list & edit box so they draw properly. We also
+> // subclass the combo so we can hide/show/move it and the
+> // 3d effects outside the client area get erased
+> DoSubclassCtl(hwndList, CTL3D_LISTBOXES, wCallFlags, hwnd);
+>
+> hwndEdit = GetWindow(hwndList, GW_HWNDNEXT);
+> if (hwndEdit != NULL)
+> DoSubclassCtl(hwndEdit, CTL3D_EDITS, wCallFlags, hwnd);
+> return fTrue;
+> }
+> return fFalse;
+> }
+> }
+>
+> PRIVATE BOOL FStatic(HWND hwnd, LONG style, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> int wStyle;
+>
+> wStyle = LOWORD(style) & 0xf;
+> return (wStyle != SS_ICON &&
+> ((grbit & CTL3D_STATICTEXTS) &&
+> (wStyle <= SS_RIGHT || wStyle == SS_LEFTNOWORDWRAP) ||
+> ((grbit & CTL3D_STATICFRAMES) &&
+> (wStyle >= SS_BLACKRECT && wStyle <= SS_WHITEFRAME))));
+> }
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | DoSubclassCtl
+> |
+> | Actually subclass the control
+> |
+> |
+> | Arguments:
+> | HWND hwnd:
+> | WORD grbit:
+> | WORD wCallFlags
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE BOOL DoSubclassCtl(HWND hwnd, WORD grbit, WORD wCallFlags, HWND hwndParent)
+> {
+> LONG style;
+> int ct;
+> BOOL fCan;
+> TCHAR szClass[cchClassMax];
+>
+> // Is this already subclassed by CTL3D?
+> if (LpfnGetDefWndProcNull(hwnd) != (FARPROC) NULL)
+> return fFalse;
+>
+> GetClassName(hwnd, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+>
+> for (ct = 0; ct < ctMax; ct++)
+> {
+> if ((mpctcdef[ct].msk & grbit) &&
+> (lstrcmp(mpctcdef[ct].sz,szClass) == 0))
+> {
+> style = GetWindowLong(hwnd, GWL_STYLE);
+> fCan = mpctcdef[ct].lpfnFCanSubclass(hwnd, style, grbit, wCallFlags, hwndParent);
+> if (fCan == fTrue)
+> {
+> if ( wCallFlags == INCBTHOOK && g3d.verBase == 16 )
+> HookSubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+> else
+> SubclassWindow(hwnd, g3d.mpctctl[ct].lpfn);
+> }
+> return fCan != fFalse;
+> }
+> }
+>
+> return fFalse;
+> }
+>
+>
+>
+> /*-----------------------------------------------------------------------
+> | Inval3dCtl
+> |
+> | Invalidate the controls rect in response to a WM_SHOWWINDOW or
+> | WM_WINDOWPOSCHANGING message. This is necessary because ctl3d draws
+> | the 3d effects of listboxes, combos & edits outside the controls client
+> | rect.
+> |
+> | Arguments:
+> | HWND hwnd:
+> | WINDOWPOS FAR *lpwp:
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID Inval3dCtl(HWND hwnd, WINDOWPOS FAR *lpwp)
+> {
+> RC rc;
+> HWND hwndParent;
+> LONG lStyle;
+> unsigned flags;
+>
+> GetWindowRect(hwnd, (LPRECT) &rc);
+> lStyle = GetWindowLong(hwnd, GWL_STYLE);
+> if (lStyle & WS_VISIBLE)
+> {
+> if (lpwp != NULL)
+> {
+> flags = lpwp->flags;
+>
+> //
+> // Is all this necessary ? Are we moving or sizing ?
+> //
+> if ( !((flags & SWP_HIDEWINDOW) || (flags & SWP_SHOWWINDOW)) &&
+> (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE) )
+> // Nope
+> return;
+>
+> // handle integral height listboxes (or any other control which
+> // shrinks from the bottom)
+> if ((flags & (SWP_NOMOVE|SWP_NOSIZE)) == SWP_NOMOVE &&
+> (lpwp->cx == (rc.xRight-rc.xLeft) && lpwp->cy <= (rc.yBot-rc.yTop)))
+> rc.yTop = rc.yTop+lpwp->cy+1; // +1 to offset InflateRect
+> }
+> InflateRect((LPRECT) &rc, 1, 1);
+> hwndParent = GetParent(hwnd);
+> ScreenToClient(hwndParent, (LPPOINT) &rc);
+> ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+> if(lStyle & WS_VSCROLL)
+> rc.xRight ++;
+> InvalidateRect(hwndParent, (LPRECT) &rc, fFalse);
+> }
+> }
+>
+> /*-----------------------------------------------------------------------
+> | Val3dCtl
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID Val3dCtl(HWND hwnd)
+> {
+> RC rc;
+> HWND hwndParent;
+> LONG lStyle;
+>
+> lStyle = GetWindowLong(hwnd, GWL_STYLE);
+> GetWindowRect(hwnd, (LPRECT) &rc);
+> InflateRect((LPRECT) &rc, 1, 1);
+> hwndParent = GetParent(hwnd);
+> ScreenToClient(hwndParent, (LPPOINT) &rc);
+> ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+> if(lStyle & WS_VSCROLL)
+> rc.xRight ++;
+> ValidateRect(hwndParent, (LPRECT) &rc);
+> }
+>
+> /*-----------------------------------------------------------------------
+> | CTL3D Subclass Wndprocs
+> -----------------------------------------------------------------------*/
+>
+> /* These values are assumed for bit shifting operations */
+> #define BFCHECK 0x0003
+> #define BFSTATE 0x0004
+> #define BFFOCUS 0x0008
+> #define BFINCLICK 0x0010 /* Inside click code */
+> #define BFCAPTURED 0x0020 /* We have mouse capture */
+> #define BFMOUSE 0x0040 /* Mouse-initiated */
+> #define BFDONTCLICK 0x0080 /* Don't check on get focus */
+>
+> #define bpText 0x0002
+> #define bpCheck 0x0004
+> #define bpFocus 0x0008 // must be same as BFFOCUS
+> #define bpBkgnd 0x0010
+> #define bpEraseGroupText 0x0020
+>
+> PRIVATE VOID DrawPushButton(HWND hwnd, HDC hdc, RC FAR *lprc, LPTSTR lpch, int cch, WORD bs, BOOL fDown)
+> {
+> // int dxyBrdr;
+> int dxyShadow;
+> HBRUSH hbrSav;
+> RC rcInside;
+> rcInside = *lprc;
+>
+> // if (!(grbitStyle & bitFCoolButtons))
+> {
+> DrawRec3d(hdc, lprc, icvWindowFrame, icvWindowFrame, dr3All);
+> InflateRect((LPRECT) &rcInside, -1, -1);
+> if (bs == LOWORD(BS_DEFPUSHBUTTON) && IsWindowEnabled(hwnd))
+> {
+> // dxyBrdr = 2;
+> DrawRec3d(hdc, &rcInside, icvWindowFrame, icvWindowFrame, dr3All);
+> InflateRect((LPRECT) &rcInside, -1, -1);
+> }
+> // else
+> // dxyBrdr = 1;
+>
+> // Notch the corners
+> PatBlt(hdc, lprc->xLeft, lprc->yTop, dxBorder, dyBorder, PATCOPY);
+> /* Top xRight corner */
+> PatBlt(hdc, lprc->xRight - dxBorder, lprc->yTop, dxBorder, dyBorder, PATCOPY);
+> /* yBot xLeft corner */
+> PatBlt(hdc, lprc->xLeft, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
+> /* yBot xRight corner */
+> PatBlt(hdc, lprc->xRight - dxBorder, lprc->yBot - dyBorder, dxBorder, dyBorder, PATCOPY);
+> dxyShadow = 1 + !fDown;
+> }
+> // else
+> // dxyShadow = 1;
+>
+> // draw upper left hilite/shadow
+>
+> if (fDown)
+> hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);
+> else
+> hbrSav = SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);
+>
+> PatBlt(hdc, rcInside.xLeft, rcInside.yTop, dxyShadow,
+> (rcInside.yBot - rcInside.yTop), PATCOPY);
+> PatBlt(hdc, rcInside.xLeft, rcInside.yTop,
+> (rcInside.xRight - rcInside.xLeft), dxyShadow, PATCOPY);
+>
+> // draw lower right shadow (only if not down)
+> if (!fDown) // || (grbitStyle & bitFCoolButtons))
+> {
+> int i;
+>
+> if (fDown)
+> SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnHilite]);
+> else
+> SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnShadow]);
+>
+> rcInside.yBot--;
+> rcInside.xRight--;
+>
+> for (i = 0; i < dxyShadow; i++)
+> {
+> PatBlt(hdc, rcInside.xLeft, rcInside.yBot,
+> rcInside.xRight - rcInside.xLeft + dxBorder, dyBorder,
+> PATCOPY);
+> PatBlt(hdc, rcInside.xRight, rcInside.yTop, dxBorder,
+> rcInside.yBot - rcInside.yTop, PATCOPY);
+> if (i < dxyShadow-1)
+> InflateRect((LPRECT) &rcInside, -dxBorder, -dyBorder);
+> }
+> }
+> // draw the button face
+>
+> rcInside.xLeft++;
+> rcInside.yTop++;
+>
+> SelectObject(hdc, g3d.brt.mpicvhbr[icvBtnFace]);
+> PatBlt(hdc, rcInside.xLeft, rcInside.yTop, rcInside.xRight-rcInside.xLeft,
+> rcInside.yBot - rcInside.yTop, PATCOPY);
+>
+> // Draw the durned text
+>
+> if(!IsWindowEnabled(hwnd))
+> SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+>
+> {
+> int dy;
+> int dx;
+>
+> MyGetTextExtent(hdc, lpch, &dx, &dy);
+> rcInside.yTop += (rcInside.yBot-rcInside.yTop-dy)/2;
+> rcInside.xLeft += (rcInside.xRight-rcInside.xLeft-dx)/2;
+> rcInside.yBot = min(rcInside.yTop+dy, rcInside.yBot);
+> rcInside.xRight = min(rcInside.xLeft+dx, rcInside.xRight);
+> }
+>
+> if (fDown)
+> {
+> OffsetRect((LPRECT) &rcInside, 1, 1);
+> rcInside.xRight = min(rcInside.xRight, lprc->xRight-3);
+> rcInside.yBot = min(rcInside.yBot, lprc->yBot-3);
+> }
+>
+> DrawText(hdc, lpch, cch, (LPRECT) &rcInside, DT_LEFT|DT_SINGLELINE);
+>
+> if (hwnd == GetFocus())
+> {
+> InflateRect((LPRECT) &rcInside, 1, 1);
+> IntersectRect((LPRECT) &rcInside, (LPRECT) &rcInside, (LPRECT) lprc);
+> DrawFocusRect(hdc, (LPRECT) &rcInside);
+> }
+>
+> if (hbrSav)
+> SelectObject(hdc, hbrSav);
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | BtnPaint
+> |
+> | Paint a button
+> |
+> | Arguments:
+> | HWND hwnd:
+> | HDC hdc:
+> | int bp:
+> |
+> | Returns:
+> |
+> -----------------------------------------------------------------------*/
+> PRIVATE VOID BtnPaint(HWND hwnd, HDC hdc, int bp)
+> {
+> RC rc;
+> RC rcClient;
+> HFONT hfont;
+> int bs;
+> int bf;
+> HBRUSH hbrBtn;
+> HWND hwndParent;
+> int xBtnBmp;
+> int yBtnBmp;
+> HBITMAP hbmpSav;
+> HDC hdcMem;
+> TCHAR szTitle[256];
+> int cch;
+> BOOL fEnabled;
+> BOOL fLeftText;
+>
+> bs = (int) GetWindowLong(hwnd, GWL_STYLE);
+> fLeftText = (bs & Win32Or16(0x00000020, 0x0020));
+> bs &= Win32Or16(0x0000001F, 0x001F);
+> hwndParent = GetParent(hwnd);
+> SetBkMode(hdc, OPAQUE);
+> GetClientRect(hwnd, (LPRECT)&rcClient);
+> rc = rcClient;
+> if((hfont = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
+> hfont = SelectObject(hdc, hfont);
+>
+> SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
+> SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
+> hbrBtn = SEND_COLOR_BUTTON_MESSAGE(hwndParent, hwnd, hdc);
+> hbrBtn = SelectObject(hdc, hbrBtn);
+> IntersectClipRect(hdc, rc.xLeft, rc.yTop, rc.xRight, rc.yBot);
+> if(bp & bpBkgnd && (bs != BS_GROUPBOX))
+> PatBlt(hdc, rc.xLeft, rc.yTop, rc.xRight-rc.xLeft, rc.yBot-rc.yTop, PATCOPY);
+>
+> fEnabled = IsWindowEnabled(hwnd);
+> bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+> yBtnBmp = 0;
+> xBtnBmp = (((bf&BFCHECK) != 0) | ((bf&BFSTATE) >> 1)) * 14;
+> if (!fEnabled)
+> xBtnBmp += 14*(2+((bf&BFCHECK) != 0));
+> if(bp & (bpText|bpFocus) ||
+> bs == BS_PUSHBUTTON || bs == BS_DEFPUSHBUTTON)
+> cch = GetWindowText(hwnd, szTitle, sizeof(szTitle)Win32Only(/sizeof(TCHAR)));
+> switch(bs)
+> {
+> #ifdef DEBUG
+> default:
+> Assert(fFalse);
+> break;
+> #endif
+> case BS_PUSHBUTTON:
+> case BS_DEFPUSHBUTTON:
+> DrawPushButton(hwnd, hdc, &rcClient, szTitle, cch, LOWORD(bs), bf & BFSTATE);
+> break;
+>
+> case BS_RADIOBUTTON:
+> case BS_AUTORADIOBUTTON:
+> yBtnBmp = 13;
+> goto DrawBtn;
+> case BS_3STATE:
+> case BS_AUTO3STATE:
+> Assert((BFSTATE >> 1) == 2);
+> if((bf & BFCHECK) == 2)
+> yBtnBmp = 26;
+> // fall through
+> case BS_CHECKBOX:
+> case BS_AUTOCHECKBOX:
+> DrawBtn:
+> if(bp & bpCheck)
+> {
+> hdcMem = CreateCompatibleDC(hdc);
+> if(hdcMem != NULL)
+> {
+> hbmpSav = SelectObject(hdcMem, g3d.hbmpCheckboxes);
+> if(hbmpSav != NULL)
+> {
+> if (fLeftText)
+> BitBlt(hdc, rc.xRight - 14, rc.yTop+(rc.yBot-rc.yTop-13)/2,
+> 14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
+> else
+> BitBlt(hdc, rc.xLeft, rc.yTop+(rc.yBot-rc.yTop-13)/2,
+> 14, 13, hdcMem, xBtnBmp, yBtnBmp, SRCCOPY);
+> SelectObject(hdcMem, hbmpSav);
+> }
+> DeleteDC(hdcMem);
+> }
+> }
+> if(bp & bpText)
+> {
+> // BUG! this assumes we have only 1 hbm3dCheck type
+> if (fLeftText)
+> rc.xRight = rcClient.xRight - (14+4);
+> else
+> rc.xLeft = rcClient.xLeft + 14+4;
+> if(!fEnabled)
+> SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+> DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_VCENTER|DT_LEFT|DT_SINGLELINE);
+> }
+> if(bp & bpFocus)
+> {
+> int dx;
+> int dy;
+>
+> MyGetTextExtent(hdc, szTitle, &dx, &dy);
+> rc.yTop = (rc.yBot-rc.yTop-dy)/2;
+> rc.yBot = rc.yTop+dy;
+> rc.xLeft = rcClient.xLeft;
+> if (fLeftText)
+> {
+> rc.xLeft = rcClient.xLeft;
+> rcClient.xRight -= (14+4);
+> }
+> else
+> rc.xLeft = rcClient.xLeft + (14+4);
+> rc.xRight = rc.xLeft + dx;
+> InflateRect((LPRECT) &rc, 1, 1);
+> IntersectRect((LPRECT) &rc, (LPRECT) &rc, (LPRECT) &rcClient);
+> DrawFocusRect(hdc, (LPRECT) &rc);
+> }
+> break;
+> case BS_GROUPBOX:
+> if(bp & (bpText|bpCheck))
+> {
+> int dy;
+> int dx;
+>
+> MyGetTextExtent(hdc, szTitle, &dx, &dy);
+> if (dy == 0)
+> {
+> int dxT;
+> MyGetTextExtent(hdc, TEXT("X"), &dxT, &dy);
+> }
+>
+> rc.xLeft += 4;
+> rc.xRight = rc.xLeft + dx + 4;
+> rc.yBot = rc.yTop + dy;
+>
+> if (bp & bpEraseGroupText)
+> {
+> RC rcT;
+>
+> rcT = rc;
+> rcT.xRight = rcClient.xRight;
+> // Hack!
+> ClientToScreen(hwnd, (LPPOINT) &rcT);
+> ClientToScreen(hwnd, ((LPPOINT) &rcT)+1);
+> ScreenToClient(hwndParent, (LPPOINT) &rcT);
+> ScreenToClient(hwndParent, ((LPPOINT) &rcT)+1);
+> InvalidateRect(hwndParent, (LPRECT) &rcT, fTrue);
+> return;
+> }
+>
+> rcClient.yTop += dy/2;
+> rcClient.xRight--;
+> rcClient.yBot--;
+> DrawRec3d(hdc, &rcClient, icvBtnShadow, icvBtnShadow, dr3All);
+> OffsetRect((LPRECT) &rcClient, 1, 1);
+> DrawRec3d(hdc, &rcClient, icvBtnHilite, icvBtnHilite, dr3All);
+>
+> if(!fEnabled)
+> SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+> DrawText(hdc, szTitle, cch, (LPRECT) &rc, DT_LEFT|DT_SINGLELINE);
+> }
+> break;
+> }
+>
+> SelectObject(hdc, hbrBtn);
+> if(hfont != NULL)
+> SelectObject(hdc, hfont);
+> }
+>
+> LRESULT __export _loadds WINAPI BtnWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> LONG lRet;
+> LONG lStyle;
+> PAINTSTRUCT ps;
+> HDC hdc;
+> int bf;
+> int bfNew;
+> int bp;
+>
+> if ( wm == WM_NCDESTROY )
+> return CleanupSubclass(hwnd, wm, wParam, lParam, ctButton);
+>
+> if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+>
+> switch(wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctButton+1000;
+>
+> case WM_SETTEXT:
+> lStyle = GetWindowLong(hwnd, GWL_STYLE);
+> if ((lStyle & WS_VISIBLE) && (LOWORD(lStyle) & 0x1f) == BS_GROUPBOX)
+> {
+> // total hack -- if group box text length shortens then
+> // we have to erase the old text. BtnPaint will Invalidate
+> // the rect of the text so everything will redraw.
+> bp = bpText | bpEraseGroupText;
+> }
+> else
+> {
+> bp = bpText|bpCheck|bpBkgnd;
+> }
+> goto DoIt;
+>
+> case BM_SETSTATE:
+> case BM_SETCHECK:
+> bp = bpCheck;
+> goto DoIt;
+> case WM_KILLFOCUS:
+> // HACK! Windows will go into an infinite loop trying to sync the
+> // states of the AUTO_RADIOBUTTON in this group. (we turn off the
+> // visible bit so it gets skipped in the enumeration)
+> // Disable this code by clearing the STATE bit
+> if ((LOWORD(GetWindowLong(hwnd, GWL_STYLE)) & 0x1F) == BS_AUTORADIOBUTTON)
+> SendMessage(hwnd, BM_SETSTATE, 0, 0L);
+> bp = 0;
+> goto DoIt;
+> case WM_ENABLE:
+> bp = bpCheck | bpText;
+> goto DoIt;
+> case WM_SETFOCUS:
+> // HACK! if wParam == NULL we may be activated via the task manager
+> // Erase background of control because a WM_ERASEBKGND messsage has not
+> // arrived yet for the dialog
+> // bp = wParam == (WPARAM)NULL ? (bpCheck | bpText | bpBkgnd) : (bpCheck | bpText);
+> bp = bpCheck | bpText | bpBkgnd;
+> DoIt:
+> bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+> if((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE)
+> {
+> if ( wm != WM_SETFOCUS )
+> SetWindowLong(hwnd, GWL_STYLE, lStyle & ~(WS_VISIBLE));
+> lRet = CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+>
+> if ( wm != WM_SETFOCUS )
+> SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE)|WS_VISIBLE);
+> bfNew = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+> if((wm != BM_SETSTATE && wm != BM_SETCHECK) ||
+> bf != bfNew)
+> {
+> hdc = GetDC(hwnd);
+> if (hdc != NULL)
+> {
+> Assert(BFFOCUS == bpFocus);
+> /* If the check state changed, redraw no matter what,
+> because it won't have during the above call to the def
+> wnd proc */
+> if ((bf & BFCHECK) != (bfNew & BFCHECK))
+> bp |= bpCheck;
+> ExcludeUpdateRgn(hdc, hwnd);
+> BtnPaint(hwnd, hdc, bp|((bf^bfNew)&BFFOCUS));
+> ReleaseDC(hwnd, hdc);
+> }
+> }
+> return lRet;
+> }
+> break;
+> case WM_PAINT:
+> bf = (int) SendMessage(hwnd, BM_GETSTATE, 0, 0L);
+> if ((hdc = (HDC) wParam) == NULL)
+> hdc = BeginPaint(hwnd, &ps);
+> if(GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE)
+> BtnPaint(hwnd, hdc, bpText|bpCheck|(bf&BFFOCUS));
+> if (wParam == (WPARAM)NULL)
+> EndPaint(hwnd, &ps);
+> return 0L;
+> }
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctButton), hwnd, wm, wParam, lParam);
+> }
+>
+>
+> void ListEditPaint3d(HWND hwnd, BOOL fEdit, int ct)
+> {
+> CTLID id;
+> RC rc;
+> HDC hdc;
+> HWND hwndParent;
+> LONG lStyle;
+> DR3 dr3;
+>
+> if(!((lStyle = GetWindowLong(hwnd, GWL_STYLE)) & WS_VISIBLE))
+> return;
+>
+> if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
+> {
+> if ( SendMessage(hwnd, CB_GETDROPPEDSTATE,0,0L) )
+> return;
+> }
+>
+> if (fEdit)
+> HideCaret(hwnd);
+>
+> GetWindowRect(hwnd, (LPRECT) &rc);
+>
+> ScreenToClient(hwndParent = GetParent(hwnd), (LPPOINT) &rc);
+> ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+>
+> hdc = GetDC(hwndParent);
+>
+> dr3 = dr3All;
+>
+> if(lStyle & WS_HSCROLL)
+> dr3 = dr3 & ~dr3Bot;
+>
+> if(lStyle & WS_VSCROLL)
+> dr3 = dr3 & ~dr3Right;
+>
+> // don't draw the top if it's a listbox of a simple combo
+> id = GetControlId(hwnd);
+> if (id == (CTLID) (1000 + fEdit))
+> {
+> TCHAR szClass[cchClassMax];
+> BOOL fSubclass = 666;
+> int ctParent;
+>
+> // could be superclassed!
+> fSubclass = 666;
+> ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+>
+> // could be subclassed!
+> GetClassName(hwndParent, szClass, sizeof(szClass)Win32Only(/sizeof(TCHAR)));
+> if (lstrcmp(szClass, mpctcdef[ctCombo].sz) == 0 ||
+> (fSubclass == fTrue && ctParent == ctCombo+1000))
+> {
+> HWND hwndComboParent;
+>
+> hwndComboParent = GetParent(hwndParent);
+>
+> Win16Only(GetWindowRect(hwnd, (LPRECT) &rc));
+> Win16Only(ScreenToClient(hwndComboParent, (LPPOINT) &rc));
+> Win16Only(ScreenToClient(hwndComboParent, ((LPPOINT) &rc)+1));
+>
+> Win32Only(MapWindowPoints(hwndParent, hwndComboParent, (POINT*)&rc, 2));
+>
+> ReleaseDC(hwndParent, hdc);
+> hdc = GetDC(hwndComboParent);
+>
+> if (fEdit)
+> {
+> RC rcList;
+> HWND hwndList;
+> long style;
+>
+> style = GetWindowLong(hwndParent, GWL_STYLE);
+> if (!(((style & 0x0003) == CBS_DROPDOWN)
+> || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+> {
+> dr3 &= ~dr3Bot;
+>
+> hwndList = GetWindow(hwndParent, GW_CHILD);
+> GetWindowRect(hwndList, (LPRECT) &rcList);
+>
+> // Some ugly shit goin' on here!
+> rc.xRight -= rcList.xRight-rcList.xLeft;
+> DrawInsetRect3d(hdc, &rc, dr3Bot|dr3HackBotRight);
+> rc.xRight += rcList.xRight-rcList.xLeft;
+> }
+> else
+> {
+> //
+> // Is the drop down on the parent down ? if so don't paint.
+> //
+> if ( SendMessage(hwndParent, CB_GETDROPPEDSTATE,0,0L) )
+> {
+> ReleaseDC(hwndComboParent, hdc);
+> ShowCaret(hwnd);
+> return;
+> }
+> }
+> }
+> else
+> {
+> rc.yTop++;
+> dr3 &= ~dr3Top;
+> }
+>
+> hwndParent = hwndComboParent;
+>
+> }
+> }
+>
+> DrawInsetRect3d(hdc, &rc, dr3);
+>
+> if ((ct == ctCombo && (lStyle & 0x003) == CBS_DROPDOWNLIST))
+> {
+> rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
+> DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right|dr3Bot);
+> Val3dCtl(hwnd);
+> }
+> else {
+> if (lStyle & WS_VSCROLL)
+> {
+> int SaveLeft;
+>
+> rc.xRight++;
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Right);
+> rc.xRight--;
+> SaveLeft = rc.xLeft;
+> rc.xLeft = rc.xRight - GetSystemMetrics(SM_CXVSCROLL);
+> DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Bot);
+> rc.xLeft = SaveLeft;
+> }
+> if (lStyle & WS_HSCROLL)
+> {
+> rc.yBot++;
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3Bot);
+> rc.yBot--;
+> rc.yTop = rc.yBot - GetSystemMetrics(SM_CXHSCROLL);
+> DrawRec3d(hdc, &rc, icvWindowFrame, icvWindowFrame, dr3Right);
+> }
+> }
+>
+> ReleaseDC(hwndParent, hdc);
+> if (fEdit)
+> ShowCaret(hwnd);
+>
+> }
+>
+>
+> LONG ShareEditComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, int ct)
+> {
+> LONG l;
+> LONG style;
+>
+> if ( wm == WM_NCDESTROY )
+> return CleanupSubclass(hwnd, wm, wParam, lParam, ct);
+>
+> if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+>
+> l = CallWindowProc(LpfnGetDefWndProc(hwnd,ct), hwnd, wm, wParam, lParam);
+> if (ct == ctCombo)
+> {
+> style = GetWindowLong(hwnd, GWL_STYLE);
+> if ((style & 0x0003) == CBS_DROPDOWN)
+> return l;
+> }
+>
+> switch(wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctEdit+1000;
+>
+> case WM_SHOWWINDOW:
+> if (g3d.verWindows < ver31 && wParam == 0)
+> Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
+> break;
+> case WM_WINDOWPOSCHANGING:
+> if (g3d.verWindows >= ver31)
+> Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
+> break;
+>
+> case WM_PAINT:
+> {
+> if (ct != ctCombo ||
+> (((style & 0x0003) == CBS_DROPDOWN) || ((style & 0x0003) == CBS_DROPDOWNLIST)))
+> ListEditPaint3d(hwnd, TRUE, ct);
+> }
+> break;
+> }
+> return l;
+> }
+>
+>
+> LRESULT __export _loadds WINAPI EditWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctEdit);
+> }
+>
+>
+> LONG SharedListWndProc(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam, unsigned ct)
+> {
+> LONG l;
+>
+> if ( wm == WM_NCDESTROY )
+> return CleanupSubclass(hwnd, wm, wParam, lParam, ct);
+>
+> if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+>
+> switch(wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctList+1000;
+>
+> case WM_SHOWWINDOW:
+> if (g3d.verWindows < ver31 && wParam == 0)
+> Inval3dCtl(hwnd, (WINDOWPOS FAR *) NULL);
+> break;
+> case WM_WINDOWPOSCHANGING:
+> if (g3d.verWindows >= ver31)
+> Inval3dCtl(hwnd, (WINDOWPOS FAR *) lParam);
+> break;
+> case WM_PAINT:
+> l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+> ListEditPaint3d(hwnd, FALSE, ct);
+> return l;
+> case WM_NCCALCSIZE:
+> {
+> RC rc;
+> RC rcNew;
+> HWND hwndParent;
+>
+> // Inval3dCtl handles this case under Win 3.1
+> if (g3d.verWindows >= ver31)
+> break;
+>
+> GetWindowRect(hwnd, (LPRECT) &rc);
+> #ifdef UNREACHABLE
+> if (g3d.verWindows >= ver31)
+> {
+> hwndParent = GetParent(hwnd);
+> ScreenToClient(hwndParent, (LPPOINT) &rc);
+> ScreenToClient(hwndParent, ((LPPOINT) &rc)+1);
+> }
+> #endif
+>
+> l = CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+>
+> rcNew = *(RC FAR *)lParam;
+> InflateRect((LPRECT) &rcNew, 2, 1); // +1 for border (Should use AdjustWindowRect)
+> if (rcNew.yBot < rc.yBot)
+> {
+> rcNew.yTop = rcNew.yBot+1;
+> rcNew.yBot = rc.yBot+1;
+>
+> #ifdef ALWAYS
+> if (g3d.verWindows < ver31)
+> #endif
+> {
+> hwndParent = GetParent(hwnd);
+> ScreenToClient(hwndParent, (LPPOINT) &rcNew);
+> ScreenToClient(hwndParent, ((LPPOINT) &rcNew)+1);
+> }
+>
+> InvalidateRect(hwndParent, (LPRECT) &rcNew, TRUE);
+> }
+> return l;
+> }
+> }
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ct), hwnd, wm, wParam, lParam);
+> }
+>
+> LRESULT __export _loadds WINAPI ListWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> return SharedListWndProc(hwnd, wm, wParam, lParam, ctList);
+> }
+>
+>
+>
+> LRESULT __export _loadds WINAPI ComboWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> switch(wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctCombo+1000;
+> }
+>
+> return ShareEditComboWndProc3d(hwnd, wm, wParam, lParam, ctCombo);
+> }
+>
+> void StaticPrint(HWND hwnd, HDC hdc, RC FAR *lprc, LONG style)
+> {
+> WORD dt;
+> LONG cv;
+> Win16Or32(HANDLE , LPTSTR )hText;
+> int TextLen;
+>
+> PatBlt(hdc, lprc->xLeft, lprc->yTop, lprc->xRight-lprc->xLeft, lprc->yBot-lprc->yTop, PATCOPY);
+>
+> TextLen = GetWindowTextLength(hwnd);
+>
+> #ifndef WIN32
+> hText = LocalAlloc(LPTR|LMEM_NODISCARD,(TextLen+5)*sizeof(TCHAR));
+> #else
+> hText = _alloca((TextLen+5)*sizeof(TCHAR));
+> #endif
+> if (hText == NULL)
+> return;
+>
+> if (GetWindowText(hwnd, (NPTSTR)hText, TextLen+2*sizeof(TCHAR)) == 0)
+> {
+> #ifndef WIN32
+> LocalFree(hText);
+> #endif
+> return;
+> }
+>
+> if ((style & 0x000f) == SS_LEFTNOWORDWRAP)
+> dt = DT_NOCLIP | DT_EXPANDTABS;
+> else
+> {
+> dt = LOWORD(DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK | ((style & 0x0000000f)-SS_LEFT));
+> }
+>
+> if (style & SS_NOPREFIX)
+> dt |= DT_NOPREFIX;
+>
+> if (style & WS_DISABLED)
+> cv = SetTextColor(hdc, g3d.clrt.rgcv[icvGrayText]);
+>
+> DrawText(hdc, (NPTSTR)hText, -1, (LPRECT) lprc, dt);
+>
+> #ifndef WIN32
+> LocalFree(hText);
+> #endif
+>
+> if (style & WS_DISABLED)
+> cv = SetTextColor(hdc, cv);
+> }
+>
+> void StaticPaint(HWND hwnd, HDC hdc)
+> {
+> LONG style;
+> RC rc;
+>
+> style = GetWindowLong(hwnd, GWL_STYLE);
+> if(!(style & WS_VISIBLE))
+> return;
+>
+> GetClientRect(hwnd, (LPRECT) &rc);
+> switch(style & 0x0f)
+> {
+> case SS_BLACKRECT:
+> case SS_BLACKFRAME: // Inset rect
+> DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnHilite, dr3All);
+> break;
+> case SS_GRAYRECT:
+> case SS_GRAYFRAME:
+> rc.xLeft++;
+> rc.yTop++;
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnHilite, dr3All);
+> OffsetRect((LPRECT) &rc, -1, -1);
+> DrawRec3d(hdc, &rc, icvBtnShadow, icvBtnShadow, dr3All);
+> break;
+> case SS_WHITERECT: // outset rect
+> case SS_WHITEFRAME:
+> DrawRec3d(hdc, &rc, icvBtnHilite, icvBtnShadow, dr3All);
+> break;
+> case SS_LEFT:
+> case SS_CENTER:
+> case SS_RIGHT:
+> case SS_LEFTNOWORDWRAP:
+> {
+> HANDLE hfont;
+> HBRUSH hbr;
+>
+> if((hfont = (HANDLE)SendMessage(hwnd, WM_GETFONT, 0, 0L)) != NULL)
+> hfont = SelectObject(hdc, hfont);
+> SetBkMode(hdc, OPAQUE);
+>
+> if(( hbr = SEND_COLOR_STATIC_MESSAGE(GetParent(hwnd), hwnd, hdc)) != NULL)
+> hbr = SelectObject(hdc, hbr);
+>
+> StaticPrint(hwnd, hdc, (RC FAR *)&rc, style);
+>
+> if (hfont != NULL)
+> SelectObject(hdc, hfont);
+>
+> if (hbr != NULL)
+> SelectObject(hdc, hbr);
+> }
+> break;
+> }
+> }
+>
+>
+> LRESULT __export _loadds WINAPI StaticWndProc3d(HWND hwnd, UINT wm, WPARAM wParam, LPARAM lParam)
+> {
+> HDC hdc;
+> PAINTSTRUCT ps;
+>
+> if ( wm == WM_NCDESTROY )
+> return CleanupSubclass(hwnd, wm, wParam, lParam, ctStatic);
+>
+> if ( GetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable) )
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);
+>
+> switch (wm)
+> {
+> case WM_CHECKSUBCLASS:
+> *(int FAR *)lParam = fTrue;
+> return ctStatic+1000;
+>
+> case WM_PAINT:
+> if ((hdc = (HDC) wParam) == NULL)
+> {
+> hdc = BeginPaint(hwnd, &ps);
+> ClipCtlDc(hwnd, hdc);
+> }
+> StaticPaint(hwnd, hdc);
+> if (wParam == (WPARAM)NULL)
+> EndPaint(hwnd, &ps);
+> return 0L;
+>
+> case WM_ENABLE:
+> hdc = GetDC(hwnd);
+> ClipCtlDc(hwnd, hdc);
+> StaticPaint(hwnd, hdc);
+> ReleaseDC(hwnd, hdc);
+> return 0L;
+> }
+> return CallWindowProc(LpfnGetDefWndProc(hwnd, ctStatic), hwnd, wm, wParam, lParam);
+> }
+>
+>
+> /*-----------------------------------------------------------------------
+> | LibMain
+> -----------------------------------------------------------------------*/
+> #ifdef WIN32
+> #ifdef DLL
+> BOOL CALLBACK LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+> #else
+> #ifdef SDLL
+> BOOL FAR Ctl3dLibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+> #else
+> BOOL FAR LibMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
+> #endif
+> #endif
+> {
+> WORD wT;
+> DWORD dwVersion;
+> BOOL (WINAPI* pfnDisableThreadLibraryCalls)(HMODULE);
+> HMODULE hKernel;
+>
+> switch(dwReason)
+> {
+> case DLL_PROCESS_ATTACH:
+> // call DisableThreadLibraryCalls if available
+> hKernel = GetModuleHandleA("KERNEL32.DLL");
+> *(FARPROC*)&pfnDisableThreadLibraryCalls =
+> GetProcAddress(hKernel, "DisableThreadLibraryCalls");
+> if (pfnDisableThreadLibraryCalls != NULL)
+> (*pfnDisableThreadLibraryCalls)(hModule);
+>
+> #ifdef DLL
+> InitializeCriticalSection(&g_CriticalSection);
+> #endif
+> EnterCriticalSection(&g_CriticalSection);
+> #ifdef SDLL
+> g3d.hinstLib = g3d.hmodLib = _hModule;
+> #else
+> g3d.hinstLib = g3d.hmodLib = hModule;
+> #endif
+>
+> dwVersion = (DWORD)GetVersion();
+> wT = LOWORD(dwVersion);
+> // get adjusted windows version
+> g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);
+> // Win32s or Win32 for real (Chicago reports Win32s)
+> g3d.verBase =
+> (dwVersion & 0x80000000) && g3d.verWindows < ver40 ? 16 : 32;
+>
+> g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
+> g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
+> g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
+> g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);
+>
+> LeaveCriticalSection(&g_CriticalSection);
+> }
+> return TRUE;
+> }
+> #else
+> #ifdef DLL
+> int WINAPI LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+> #else
+> #ifdef SDLL
+> int FAR Ctl3dLibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+> #else
+> #ifdef _BORLAND
+> BOOL FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+> #else
+> BOOL FAR LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
+> #endif
+> #endif
+> #endif
+> {
+> WORD wT;
+> #ifdef DLL
+>
+> #ifdef V2
+> CodeLpszDecl(lpszCtl3d, "CTL3DV2");
+> #else
+> CodeLpszDecl(lpszCtl3d, "CTL3D");
+> #endif
+>
+> CodeLpszDecl(lpszUser, "user.exe");
+> CodeLpszDecl(lpszSetWindowsHookEx, "SETWINDOWSHOOKEX");
+> CodeLpszDecl(lpszUnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX");
+> CodeLpszDecl(lpszCallNextHookEx, "CALLNEXTHOOKEX");
+> #endif
+>
+> g3d.hinstLib = hModule;
+> #ifdef DLL
+> g3d.hmodLib = GetModuleHandle(lpszCtl3d);
+> #else
+> #ifdef SDLL
+> g3d.hinstLib = _hModule;
+> g3d.hmodLib = GetModuleHandle(MAKELP(0,_hModule));
+> #else
+> g3d.hmodLib = hModule;
+> #endif
+> #endif
+> wT = LOWORD( GetVersion() );
+> g3d.verWindows = (LOBYTE(wT) << 8) | HIBYTE(wT);
+>
+> if ( GetWinFlags() & 0x4000 )
+> g3d.verBase = 24; // More then 16, not yet 32....WOW box on NT
+> else
+> g3d.verBase = 16; // Regular old 3.1
+>
+> g3d.dxFrame = GetSystemMetrics(SM_CXDLGFRAME)-dxBorder;
+> g3d.dyFrame = GetSystemMetrics(SM_CYDLGFRAME)-dyBorder;
+> g3d.dyCaption = GetSystemMetrics(SM_CYCAPTION);
+> g3d.dxSysMenu = GetSystemMetrics(SM_CXSIZE);
+>
+> #ifdef DLL
+> if (g3d.verWindows >= ver31)
+> {
+> HANDLE hlib;
+>
+> hlib = LoadLibrary(lpszUser);
+> if (FValidLibHandle(hlib))
+> {
+> (FARPROC) g3d.lpfnSetWindowsHookEx = GetProcAddress(hlib, lpszSetWindowsHookEx);
+> (FARPROC) g3d.lpfnUnhookWindowsHookEx = GetProcAddress(hlib, lpszUnhookWindowsHookEx);
+> (FARPROC) g3d.lpfnCallNextHookEx = GetProcAddress(hlib, lpszCallNextHookEx);
+> FreeLibrary(hlib);
+> }
+> }
+> #endif
+> return 1;
+> }
+> #endif // win32
+>
+> // convert a RGB into a RGBQ
+> #define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))
+>
+> //
+> // LoadUIBitmap() - load a bitmap resource
+> //
+> // load a bitmap resource from a resource file, converting all
+> // the standard UI colors to the current user specifed ones.
+> //
+> // this code is designed to load bitmaps used in "gray ui" or
+> // "toolbar" code.
+> //
+> // the bitmap must be a 4bpp windows 3.0 DIB, with the standard
+> // VGA 16 colors.
+> //
+> // the bitmap must be authored with the following colors
+> //
+> // Window Text Black (index 0)
+> // Button Shadow gray (index 7)
+> // Button Face lt gray (index 8)
+> // Button Highlight white (index 15)
+> // Window Color yellow (index 11)
+> // Window Frame green (index 10)
+> //
+> // Example:
+> //
+> // hbm = LoadUIBitmap(hInstance, "TestBmp",
+> // GetSysColor(COLOR_WINDOWTEXT),
+> // GetSysColor(COLOR_BTNFACE),
+> // GetSysColor(COLOR_BTNSHADOW),
+> // GetSysColor(COLOR_BTNHIGHLIGHT),
+> // GetSysColor(COLOR_WINDOW),
+> // GetSysColor(COLOR_WINDOWFRAME));
+> //
+> // Author: JimBov, ToddLa
+> //
+> //
+> #ifdef WIN32
+>
+> HBITMAP PASCAL LoadUIBitmap(
+> HANDLE hInstance, // EXE file to load resource from
+> LPCTSTR szName, // name of bitmap resource
+> COLORREF rgbText, // color to use for "Button Text"
+> COLORREF rgbFace, // color to use for "Button Face"
+> COLORREF rgbShadow, // color to use for "Button Shadow"
+> COLORREF rgbHighlight, // color to use for "Button Hilight"
+> COLORREF rgbWindow, // color to use for "Window Color"
+> COLORREF rgbFrame) // color to use for "Window Frame"
+> {
+> HBITMAP hbm;
+> LPBITMAPINFO lpbi;
+> HRSRC hrsrc;
+> HGLOBAL h;
+> HDC hdc;
+> DWORD size;
+>
+> //
+> // Load the bitmap resource and make a writable copy.
+> //
+>
+> hrsrc = FindResource(hInstance, szName, RT_BITMAP);
+> if (!hrsrc)
+> return(NULL);
+> size = SizeofResource( hInstance, hrsrc );
+> h = LoadResource(hInstance,hrsrc);
+> if (!h)
+> return(NULL);
+>
+> lpbi = ( LPBITMAPINFO ) GlobalAlloc( GPTR, size );
+>
+> if (!lpbi)
+> return(NULL);
+>
+> CopyMemory( lpbi, h, size );
+>
+> *( LPCOLORREF ) &lpbi->bmiColors[0] = RGBQ(rgbText); // Black
+> *( LPCOLORREF ) &lpbi->bmiColors[7] = RGBQ(rgbShadow); // gray
+> *( LPCOLORREF ) &lpbi->bmiColors[8] = RGBQ(rgbFace); // lt gray
+> *( LPCOLORREF ) &lpbi->bmiColors[15] = RGBQ(rgbHighlight); // white
+> *( LPCOLORREF ) &lpbi->bmiColors[11] = RGBQ(rgbWindow); // yellow
+> *( LPCOLORREF ) &lpbi->bmiColors[10] = RGBQ(rgbFrame); // green
+>
+> hdc = GetDC(NULL);
+>
+> hbm = CreateDIBitmap(hdc, &lpbi->bmiHeader, CBM_INIT, (LPBYTE)(&lpbi->bmiColors[ 16 ]),
+> lpbi, DIB_RGB_COLORS);
+>
+> ReleaseDC(NULL, hdc);
+> GlobalFree( lpbi );
+>
+> return(hbm);
+> }
+>
+> #else
+>
+> HBITMAP PASCAL LoadUIBitmap(
+> HANDLE hInstance, // EXE file to load resource from
+> LPCTSTR szName, // name of bitmap resource
+> COLORREF rgbText, // color to use for "Button Text"
+> COLORREF rgbFace, // color to use for "Button Face"
+> COLORREF rgbShadow, // color to use for "Button Shadow"
+> COLORREF rgbHighlight, // color to use for "Button Hilight"
+> COLORREF rgbWindow, // color to use for "Window Color"
+> COLORREF rgbFrame) // color to use for "Window Frame"
+> {
+> LPBYTE lpb;
+> HBITMAP hbm;
+> LPBITMAPINFOHEADER lpbi;
+> HANDLE h;
+> HDC hdc;
+> LPDWORD lprgb;
+>
+> h = LoadResource(hInstance,FindResource(hInstance, szName, RT_BITMAP));
+>
+> lpbi = (LPBITMAPINFOHEADER)LockResource(h);
+>
+> if (!lpbi)
+> return(NULL);
+>
+> #ifdef NOTNEEDEDFORCTL3D
+> if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
+> return NULL;
+>
+> if (lpbi->biBitCount != 4)
+> return NULL;
+> #endif
+>
+> lprgb = (LPDWORD)((LPBYTE)lpbi + (int)lpbi->biSize);
+> lpb = (LPBYTE)(lprgb + 16);
+>
+> lprgb[0] = RGBQ(rgbText); // Black
+>
+> // lprgb[7] = RGBQ(rgbFace); // lt gray
+> // lprgb[8] = RGBQ(rgbShadow); // gray
+>
+> lprgb[7] = RGBQ(rgbShadow); // gray
+> lprgb[8] = RGBQ(rgbFace); // lt gray
+>
+> lprgb[15] = RGBQ(rgbHighlight); // white
+> lprgb[11] = RGBQ(rgbWindow); // yellow
+> lprgb[10] = RGBQ(rgbFrame); // green
+>
+> hdc = GetDC(NULL);
+>
+> hbm = CreateDIBitmap(hdc, lpbi, CBM_INIT, (LPVOID)lpb,
+> (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
+>
+> ReleaseDC(NULL, hdc);
+> UnlockResource(h);
+> FreeResource(h);
+>
+> return(hbm);
+> }
+>
+>
+> #endif // win32
+>
+>
+> /*-----------------------------------------------------------------------
+> |
+> | DLL specific routines
+> |
+> ---------------------------------------------------------------WESC----*/
+>
+> #ifndef WIN32
+> #ifdef DLL
+> /*-----------------------------------------------------------------------
+> | WEP
+> -----------------------------------------------------------------------*/
+> int FAR PASCAL WEP (int wSystemExit)
+> {
+> return 1;
+> }
+> #endif
+> #endif
+---------- NONSHIP\CTL3D\ctl3d.c (02-06-95@00:43) next ----------
+111a112
+> #define NO_STRICT
+233a235
+> #define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
+239a242
+> #define CodeLpszDeclA(lpszVar, szLit) char *lpszVar = szLit
+244a248,250
+> #define CodeLpszDeclA(lpszVar, szLit) \
+> static CSCONST(char) lpszVar##Code[] = szLit; \
+> char far *lpszVar = (char far *)lpszVar##Code
+1179c1185
+< return 0x0226;
+---
+> return 0x0227;
+1759,1764c1765,1770
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+< CodeLpszDecl(lpszBadInstMsg,
+< TEXT("This application uses CTL3D32.DLL, which is not the correct version. ")
+< TEXT("This version of CTL3D32.DLL is designed only for Windows NT systems."));
+< MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+---
+> CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+> CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+> CodeLpszDeclA(lpszBadInstMsg,
+> "This application uses CTL3D32.DLL, which is not the correct version. "
+> "This version of CTL3D32.DLL is designed only for Windows NT systems.");
+> MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+1772,1777c1778,1783
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+< CodeLpszDecl(lpszBadInstMsg,
+< TEXT("This application uses CTL3D32.DLL, which is not the correct version. ")
+< TEXT("This version of CTL3D32.DLL is designed only for Win32s or Windows 95 systems."));
+< MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+---
+> CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+> CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+> CodeLpszDeclA(lpszBadInstMsg,
+> "This application uses CTL3D32.DLL, which is not the correct version. "
+> "This version of CTL3D32.DLL is designed only for Win32s or Windows 95 systems.");
+> MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK);
+1805,1806c1811,1812
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3DV2.DLL")),
+< CodeLpszDecl(lpszCtl3d, TEXT("CTL3D32.DLL")));
+---
+> CodeLpszDeclA(lpszCtl3d, "CTL3DV2.DLL"),
+> CodeLpszDeclA(lpszCtl3d, "CTL3D32.DLL"));
+1808,1813c1814,1819
+< CodeLpszDecl(lpszBadInstMsg,
+< TEXT("This application uses CTL3DV2.DLL, which has not been correctly installed. ")
+< TEXT("CTL3DV2.DLL must be installed in the Windows system directory.")),
+< CodeLpszDecl(lpszBadInstMsg,
+< TEXT("This application uses CTL3D32.DLL, which has not been correctly installed. ")
+< TEXT("CTL3D32.DLL must be installed in the Windows system directory.")));
+---
+> CodeLpszDeclA(lpszBadInstMsg,
+> "This application uses CTL3DV2.DLL, which has not been correctly installed. "
+> "CTL3DV2.DLL must be installed in the Windows system directory."),
+> CodeLpszDeclA(lpszBadInstMsg,
+> "This application uses CTL3D32.DLL, which has not been correctly installed. "
+> "CTL3D32.DLL must be installed in the Windows system directory."));
+1815c1821
+< MessageBox(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK );
+---
+> MessageBoxA(NULL, lpszBadInstMsg, lpszCtl3d, MB_ICONSTOP | MB_OK );
+3420c3426
+< CodeLpszDecl(lpszCtl3d, "CTL3DV2");
+---
+> CodeLpszDeclA(lpszCtl3d, "CTL3DV2");
+3422c3428
+< CodeLpszDecl(lpszCtl3d, "CTL3D");
+---
+> CodeLpszDeclA(lpszCtl3d, "CTL3D");
+3425,3428c3431,3434
+< CodeLpszDecl(lpszUser, "user.exe");
+< CodeLpszDecl(lpszSetWindowsHookEx, "SETWINDOWSHOOKEX");
+< CodeLpszDecl(lpszUnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX");
+< CodeLpszDecl(lpszCallNextHookEx, "CALLNEXTHOOKEX");
+---
+> CodeLpszDeclA(lpszUser, "user.exe");
+> CodeLpszDeclA(lpszSetWindowsHookEx, "SETWINDOWSHOOKEX");
+> CodeLpszDeclA(lpszUnhookWindowsHookEx, "UNHOOKWINDOWSHOOKEX");
+> CodeLpszDeclA(lpszCallNextHookEx, "CALLNEXTHOOKEX");
+---------- NONSHIP\CTL3D\ctl3d.c (02-17-95@14:41) next ----------
+172a173
+> #define MessageBoxA MessageBox
+635a637
+> BOOL fSubclass;
+638c640,646
+< SubclassWindow(cwpStruct->hwnd, lpfnSubclassByHook);
+---
+> if (g3d.verWindows >= ver40 && (GetWindowLong(cwpStruct->hwnd, GWL_STYLE) & 0x04))
+> fSubclass = fFalse;
+> else
+> fSubclass = fTrue;
+> SendMessage(cwpStruct->hwnd, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+> if (fSubclass)
+> SubclassWindow(cwpStruct->hwnd, lpfnSubclassByHook);
+1185c1193
+< return 0x0227;
+---
+> return 0x0228;
+1274c1282,1287
+< SetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable, (HANDLE) 1);
+---
+> if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh))
+> {
+> SetProp(hwnd,(LPCTSTR) g3d.aCtl3dDisable, (HANDLE) 1);
+> }
+2200c2213,2220
+< SubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+---
+> BOOL fSubclass;
+> if (g3d.verWindows >= ver40 && (GetWindowLong((HWND)wParam, GWL_STYLE) & 0x04))
+> fSubclass = fFalse;
+> else
+> fSubclass = fTrue;
+> SendMessage((HWND)wParam, WM_DLGSUBCLASS, 0, (LPARAM)(int FAR *)&fSubclass);
+> if (fSubclass)
+> SubclassWindow((HWND)wParam, (FARPROC) Ctl3dDlgProc);
+---------- NONSHIP\CTL3D\ctl3d.c (04-04-95@01:04) next ----------
+618a619,631
+> #ifdef WIN32
+> if (g3d.fDBCS && !IsWindowUnicode(hwnd))
+> {
+> TCHAR szClass[cchClassMax];
+> GetClassName(hwnd, szClass, cchClassMax);
+> if (lstrcmpi(szClass, TEXT("edit")) == 0)
+> {
+> lpfnWndProc = (FARPROC)SetWindowLongA(hwnd, GWL_WNDPROC,(LONG)lpfnSubclassProc);
+> goto SetProps;
+> }
+> }
+> #endif
+>
+619a633
+> SetProps:
+1193c1207
+< return 0x0228;
+---
+> return 0x0229;
+---------- NONSHIP\CTL3D\ctl3d.c (06-26-95@18:09) next ----------
+2388c2388
+< wStyle = LOWORD(style) & 0xf;
+---
+> wStyle = LOWORD(style) & 0x1f;
+2393c2393,2394
+< (wStyle >= SS_BLACKRECT && wStyle <= SS_WHITEFRAME))));
+---
+> ((wStyle >= SS_BLACKRECT && wStyle <= SS_WHITEFRAME) ||
+> (g3d.verWindows < ver40 && wStyle >= 0x10 && wStyle <= 0x12)))));
+3300c3301
+< switch(style & 0x0f)
+---
+> switch(style & 0x1f)
+3307a3309,3311
+> case 0x10:
+> case 0x11:
+> case 0x12:
+---------- NONSHIP\CTL3D\ctl3d.c (07-13-95@20:24) next ----------
+491a492,494
+> ATOM aCtl3dOld;
+> ATOM aCtl3dHighOld;
+> ATOM aCtl3dLowOld;
+565,566c568,569
+<
+< #define WM_CHECKSUBCLASS (WM_USER+5443)
+---
+> #define WM_CHECKSUBCLASS_OLD (WM_USER+5443)
+> #define WM_CHECKSUBCLASS (WM_USER+5444)
+610,611c613,618
+< if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+< GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow))
+---
+> if (GetProp(hwnd, (LPCTSTR) g3d.aCtl3dOld) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3d) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLowOld) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHighOld))
+1207c1214
+< return 0x0229;
+---
+> return 0x0231;
+1404a1412,1413
+> if ( fSubclass == 666 )
+> SendMessage((HWND) hwnd, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+1869,1871c1878,1883
+< CodeLpszDecl(lpszC3d, TEXT("C3d"));
+< CodeLpszDecl(lpszC3dL, TEXT("C3dL"));
+< CodeLpszDecl(lpszC3dH, TEXT("C3dH"));
+---
+> CodeLpszDecl(lpszC3dOld, TEXT("C3d"));
+> CodeLpszDecl(lpszC3dLOld, TEXT("C3dL"));
+> CodeLpszDecl(lpszC3dHOld, TEXT("C3dH"));
+> CodeLpszDecl(lpszC3d, TEXT("C3dNew"));
+> CodeLpszDecl(lpszC3dL, TEXT("C3dLNew"));
+> CodeLpszDecl(lpszC3dH, TEXT("C3dHNew"));
+1872a1885,1890
+> g3d.aCtl3dOld = GlobalAddAtom(lpszC3dOld);
+> if (g3d.aCtl3dOld == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+1879a1898,1905
+> g3d.aCtl3dLowOld = GlobalAddAtom(lpszC3dLOld);
+> g3d.aCtl3dHighOld = GlobalAddAtom(lpszC3dHOld);
+> if (g3d.aCtl3dLowOld == 0 || g3d.aCtl3dHighOld == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> return fFalse;
+> }
+>
+1945,1947c1971,1976
+< Win32Only(g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0);
+< Win16Only(g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0);
+< Win16Only(g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0);
+---
+> g3d.aCtl3dOld ? GlobalDeleteAtom(g3d.aCtl3dOld) : 0;
+> g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0;
+> g3d.aCtl3dLowOld ? GlobalDeleteAtom(g3d.aCtl3dLowOld) : 0;
+> g3d.aCtl3dHighOld ? GlobalDeleteAtom(g3d.aCtl3dHighOld) : 0;
+> g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0;
+> g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0;
+2047a2077
+> case WM_CHECKSUBCLASS_OLD:
+2861a2892
+> case WM_CHECKSUBCLASS_OLD:
+2994a3026,3028
+> if (fSubclass == 666)
+> ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+>
+3116a3151
+> case WM_CHECKSUBCLASS_OLD:
+3159a3195
+> case WM_CHECKSUBCLASS_OLD:
+3232a3269
+> case WM_CHECKSUBCLASS_OLD:
+3362a3400
+> case WM_CHECKSUBCLASS_OLD:
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.doc b/private/mvdm/wow16/ctl3dv2/ctl3d.doc
new file mode 100644
index 000000000..63ac85db3
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.doc
Binary files differ
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.h b/private/mvdm/wow16/ctl3dv2/ctl3d.h
new file mode 100644
index 000000000..ebdbdfeb9
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.h
@@ -0,0 +1,95 @@
+/*-----------------------------------------------------------------------
+| CTL3D.DLL
+|
+| Adds 3d effects to Windows controls
+|
+| See ctl3d.doc for info
+|
+-----------------------------------------------------------------------*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+BOOL WINAPI Ctl3dSubclassDlg(HWND, WORD);
+BOOL WINAPI Ctl3dSubclassDlgEx(HWND, DWORD);
+
+WORD WINAPI Ctl3dGetVer(void);
+BOOL WINAPI Ctl3dEnabled(void);
+
+HBRUSH WINAPI Ctl3dCtlColor(HDC, LONG); // ARCHAIC, use Ctl3dCtlColorEx
+HBRUSH WINAPI Ctl3dCtlColorEx(UINT wm, WPARAM wParam, LPARAM lParam);
+
+BOOL WINAPI Ctl3dColorChange(void);
+
+BOOL WINAPI Ctl3dSubclassCtl(HWND);
+BOOL WINAPI Ctl3dSubclassCtlEx(HWND, int);
+BOOL WINAPI Ctl3dUnsubclassCtl(HWND);
+
+LONG WINAPI Ctl3dDlgFramePaint(HWND, UINT, WPARAM, LPARAM);
+
+BOOL WINAPI Ctl3dAutoSubclass(HINSTANCE);
+BOOL WINAPI Ctl3dAutoSubclassEx(HINSTANCE, DWORD);
+BOOL WINAPI Ctl3dIsAutoSubclass(VOID);
+BOOL WINAPI Ctl3dUnAutoSubclass(VOID);
+
+BOOL WINAPI Ctl3dRegister(HINSTANCE);
+BOOL WINAPI Ctl3dUnregister(HINSTANCE);
+
+//begin DBCS: far east short cut key support
+VOID WINAPI Ctl3dWinIniChange(void);
+//end DBCS
+
+/* Ctl3dAutoSubclassEx flags */
+#define CTL3D_SUBCLASS_DYNCREATE 0x0001
+#define CTL3D_NOSUBCLASS_DYNCREATE 0x0002
+
+/* Ctl3d Control ID */
+#define CTL3D_BUTTON_CTL 0
+#define CTL3D_LISTBOX_CTL 1
+#define CTL3D_EDIT_CTL 2
+#define CTL3D_COMBO_CTL 3
+#define CTL3D_STATIC_CTL 4
+
+/* Ctl3dSubclassDlg3d flags */
+#define CTL3D_BUTTONS 0x0001
+#define CTL3D_LISTBOXES 0x0002
+#define CTL3D_EDITS 0x0004
+#define CTL3D_COMBOS 0x0008
+#define CTL3D_STATICTEXTS 0x0010
+#define CTL3D_STATICFRAMES 0x0020
+
+#define CTL3D_NODLGWINDOW 0x00010000
+#define CTL3D_ALL 0xffff
+
+#define WM_DLGBORDER (WM_USER+3567)
+/* WM_DLGBORDER *(int FAR *)lParam return codes */
+#define CTL3D_NOBORDER 0
+#define CTL3D_BORDER 1
+
+#define WM_DLGSUBCLASS (WM_USER+3568)
+/* WM_DLGSUBCLASS *(int FAR *)lParam return codes */
+#define CTL3D_NOSUBCLASS 0
+#define CTL3D_SUBCLASS 1
+
+#define CTLMSGOFFSET 3569
+#ifdef WIN32
+#define CTL3D_CTLCOLORMSGBOX (WM_USER+CTLMSGOFFSET)
+#define CTL3D_CTLCOLOREDIT (WM_USER+CTLMSGOFFSET+1)
+#define CTL3D_CTLCOLORLISTBOX (WM_USER+CTLMSGOFFSET+2)
+#define CTL3D_CTLCOLORBTN (WM_USER+CTLMSGOFFSET+3)
+#define CTL3D_CTLCOLORSCROLLBAR (WM_USER+CTLMSGOFFSET+4)
+#define CTL3D_CTLCOLORSTATIC (WM_USER+CTLMSGOFFSET+5)
+#define CTL3D_CTLCOLORDLG (WM_USER+CTLMSGOFFSET+6)
+#else
+#define CTL3D_CTLCOLOR (WM_USER+CTLMSGOFFSET)
+#endif
+
+
+/* Resource ID for 3dcheck.bmp (for .lib version of ctl3d) */
+#define CTL3D_3DCHECK 26567
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3d.rc b/private/mvdm/wow16/ctl3dv2/ctl3d.rc
new file mode 100644
index 000000000..6206902ca
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3d.rc
@@ -0,0 +1,65 @@
+#include <windows.h>
+#include "version.h"
+#include "ctl3d.h"
+
+#ifdef SPECIAL_WOW_VERSION
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "3D Windows NT(WOW) Controls"
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR "2,99,0,0\0"
+
+#undef VERSION
+#define VERSION "2.99.000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION 2,99,0,0
+
+
+#define VER_FILEVERSION 2,99,0,0
+#define VER_FILEVERSION_STR "2.99.000\0"
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE 0
+#define VER_FILEDESCRIPTION_STR "Ctl3D 3D Windows NT(WOW) Controls"
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1996"
+#else //SPEICAL_WOW_VERSION
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "3D Windows Controls"
+
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR "2,31,0,0\0"
+
+#undef VERSION
+#define VERSION "2.31.000"
+
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION 2,31,0,0
+
+
+#define VER_FILEVERSION 2,31,0,0
+#define VER_FILEVERSION_STR "2.31.000\0"
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE 0
+#define VER_FILEDESCRIPTION_STR "Ctl3D 3D Windows Controls"
+#define VER_LEGALCOPYRIGHT_YEARS "1992-1995"
+
+#endif //!SPECIAL_WOW_VERSION
+
+#ifndef WIN32
+#ifdef V2
+#define VER_INTERNALNAME_STR "CTL3DV2"
+#define VER_ORIGINALFILENAME_STR "CTL3DV2.DLL"
+#else
+#define VER_INTERNALNAME_STR "CTL3D"
+#define VER_ORIGINALFILENAME_STR "CTL3D.DLL"
+#endif
+#else
+#define VER_INTERNALNAME_STR "CTL3D32"
+#define VER_ORIGINALFILENAME_STR "CTL3D32.DLL"
+#endif
+
+#include "common.ver"
+
+CTL3D_3DCHECK BITMAP "3dcheck.bmp"
diff --git a/private/mvdm/wow16/ctl3dv2/ctl3dv2.def b/private/mvdm/wow16/ctl3dv2/ctl3dv2.def
new file mode 100644
index 000000000..3f8fc5153
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctl3dv2.def
@@ -0,0 +1,41 @@
+LIBRARY Ctl3dV2
+
+DESCRIPTION '3d control dll'
+
+EXETYPE WINDOWS
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+HEAPSIZE 1024
+
+SEGMENTS
+ WEP_TEXT FIXED PRELOAD
+
+EXPORTS
+ WEP @1000 RESIDENTNAME
+ Ctl3dGetVer @1
+ Ctl3dSubclassDlg @2
+ Ctl3dSubclassCtl @3
+ Ctl3dCtlColor @4
+ Ctl3dEnabled @5
+ Ctl3dColorChange @6
+ BtnWndProc3d @7
+ EditWndProc3d @8
+ ListWndProc3d @9
+ ComboWndProc3d @10
+ StaticWndProc3d @11
+ Ctl3dRegister @12
+ Ctl3dUnregister @13
+ Ctl3dAutoSubclass @16
+ Ctl3dDlgProc @17
+ Ctl3dCtlColorEx @18
+ Ctl3dSetStyle @19
+ Ctl3dDlgFramePaint @20
+ Ctl3dSubclassDlgEx @21
+ Ctl3dWinIniChange @22
+ Ctl3dIsAutoSubclass @23
+ Ctl3dUnAutoSubclass @24
+ Ctl3dSubclassCtlEx @25
+ Ctl3dUnsubclassCtl @26
+ Ctl3dAutoSubclassEx @27
diff --git a/private/mvdm/wow16/ctl3dv2/ctls.dlg b/private/mvdm/wow16/ctl3dv2/ctls.dlg
new file mode 100644
index 000000000..02ba86943
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/ctls.dlg
@@ -0,0 +1,51 @@
+
+100 DIALOG 0, 0, 427, 195
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
+CAPTION "CTL3D Samples"
+FONT 8, "Helv"
+BEGIN
+ PUSHBUTTON "&OK", IDOK, 261, 174, 56, 16
+ PUSHBUTTON "&Message Box", 130, 261, 129, 56, 16
+ PUSHBUTTON "&File Open", 131, 261, 151, 56, 16
+ EDITTEXT 101, 9, 17, 72, 31, ES_MULTILINE | ES_AUTOVSCROLL |
+ WS_VSCROLL
+ EDITTEXT 102, 89, 17, 72, 31, ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL | WS_VSCROLL | WS_HSCROLL
+ COMBOBOX 105, 15, 80, 72, 35, CBS_SORT | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX 106, 119, 80, 72, 35, CBS_DROPDOWN | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP | WS_HSCROLL
+ LISTBOX 107, 15, 139, 72, 43, LBS_SORT | LBS_DISABLENOSCROLL |
+ WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ CONTROL "", 108, "Static", SS_BLACKFRAME, 121, 167, 37, 16
+ COMBOBOX 109, 219, 80, 72, 35, CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "", 110, "Static", SS_BLACKRECT, 121, 139, 36, 16
+ CONTROL "Check", 112, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
+ 186, 15, 40, 10
+ CONTROL "Check", 113, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
+ 186, 25, 40, 10
+ CONTROL "Check", 114, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
+ 186, 35, 40, 10
+ CONTROL "Radio", 115, "Button", BS_AUTORADIOBUTTON, 252, 15, 39,
+ 10
+ CONTROL "Radio", 116, "Button", BS_AUTORADIOBUTTON, 252, 25, 39,
+ 10
+ CONTROL "Radio", 117, "Button", BS_AUTORADIOBUTTON, 252, 35, 39,
+ 10
+ GROUPBOX "Check / Radio Buttons", 121, 175, 3, 140, 52
+ GROUPBOX "Edit Controls", 103, 4, 3, 165, 52
+ LTEXT "Simple", 104, 13, 70, 72, 8
+ LTEXT "Drop Down", 122, 118, 70, 72, 8
+ LTEXT "Drop Down List", 123, 218, 70, 72, 8
+ GROUPBOX "Combo Boxes", 124, 3, 60, 313, 58
+ GROUPBOX "List Box", 125, 3, 124, 98, 65
+ CONTROL "", 111, "Static", SS_GRAYRECT, 166, 139, 36, 16
+ CONTROL "", 118, "Static", SS_WHITERECT, 210, 139, 36, 16
+ CONTROL "", 119, "Static", SS_WHITEFRAME, 210, 167, 37, 16
+ CONTROL "", 120, "Static", SS_GRAYFRAME, 166, 167, 37, 16
+ GROUPBOX "Static Frames and Rects", 126, 110, 125, 139, 65
+ LTEXT "Black", 127, 130, 157, 20, 8
+ LTEXT "Gray", 128, 173, 157, 20, 8
+ LTEXT "White", 129, 214, 157, 25, 8
+END
diff --git a/private/mvdm/wow16/ctl3dv2/loaddib.h b/private/mvdm/wow16/ctl3dv2/loaddib.h
new file mode 100644
index 000000000..7e5652690
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/loaddib.h
@@ -0,0 +1,16 @@
+
+#ifndef WIN32
+#ifndef LPTSTR
+#define LPTSTR LPSTR
+#endif
+#endif
+
+HBITMAP PASCAL LoadUIBitmap(
+ HANDLE hInstance, // EXE file to load resource from
+ LPTSTR szName, // name of bitmap resource
+ COLORREF rgbText, // color to use for "Button Text"
+ COLORREF rgbFace, // color to use for "Button Face"
+ COLORREF rgbShadow, // color to use for "Button Shadow"
+ COLORREF rgbHighlight, // color to use for "Button Hilight"
+ COLORREF rgbWindow, // color to use for "Window Color"
+ COLORREF rgbFrame); // color to use for "Window Frame"
diff --git a/private/mvdm/wow16/ctl3dv2/msdn.ico b/private/mvdm/wow16/ctl3dv2/msdn.ico
new file mode 100644
index 000000000..7141e7d72
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/msdn.ico
Binary files differ
diff --git a/private/mvdm/wow16/ctl3dv2/new3d.doc b/private/mvdm/wow16/ctl3dv2/new3d.doc
new file mode 100644
index 000000000..63ac85db3
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/new3d.doc
Binary files differ
diff --git a/private/mvdm/wow16/ctl3dv2/readme.txt b/private/mvdm/wow16/ctl3dv2/readme.txt
new file mode 100644
index 000000000..b764ec8d6
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/readme.txt
@@ -0,0 +1,5 @@
+This source is for debugging purposes only. CTL3DV2.DLL is binplaced from the
+\nt\private\mvdm\bin86 directory. It is built and maintained by DeanM. This
+special WOW 16-bit version (built w/ SPECIAL_WOW_VERSION) has the load
+directory detection disabled since it is a knownDLL (always started from
+System32).
diff --git a/private/mvdm/wow16/ctl3dv2/scomp.dif b/private/mvdm/wow16/ctl3dv2/scomp.dif
new file mode 100644
index 000000000..bd908504a
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/scomp.dif
@@ -0,0 +1,103 @@
+---------- nonship\ctl3d\ctl3d.c next ----------
+491a492,494
+> ATOM aCtl3dOld;
+> ATOM aCtl3dHighOld;
+> ATOM aCtl3dLowOld;
+565,566c568,569
+<
+< #define WM_CHECKSUBCLASS (WM_USER+5443)
+---
+> #define WM_CHECKSUBCLASS_OLD (WM_USER+5443)
+> #define WM_CHECKSUBCLASS (WM_USER+5444)
+611c614,617
+< GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow))
+---
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLow) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dLowOld) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHigh) ||
+> GetProp(hwnd, (LPCTSTR) g3d.aCtl3dHighOld))
+1207c1213
+< return 0x0229;
+---
+> return 0x0231;
+1404a1411,1412
+> if ( fSubclass == 666 )
+> SendMessage((HWND) hwnd, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+1869,1871c1877,1882
+< CodeLpszDecl(lpszC3d, TEXT("C3d"));
+< CodeLpszDecl(lpszC3dL, TEXT("C3dL"));
+< CodeLpszDecl(lpszC3dH, TEXT("C3dH"));
+---
+> CodeLpszDecl(lpszC3dOld, TEXT("C3d"));
+> CodeLpszDecl(lpszC3dLOld, TEXT("C3dL"));
+> CodeLpszDecl(lpszC3dHOld, TEXT("C3dH"));
+> CodeLpszDecl(lpszC3d, TEXT("C3dNew"));
+> CodeLpszDecl(lpszC3dL, TEXT("C3dLNew"));
+> CodeLpszDecl(lpszC3dH, TEXT("C3dHNew"));
+1872a1884,1889
+> g3d.aCtl3dOld = GlobalAddAtom(lpszC3dOld);
+> if (g3d.aCtl3dOld == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> goto Return;
+> }
+1879a1897,1904
+> g3d.aCtl3dLowOld = GlobalAddAtom(lpszC3dLOld);
+> g3d.aCtl3dHighOld = GlobalAddAtom(lpszC3dHOld);
+> if (g3d.aCtl3dLowOld == 0 || g3d.aCtl3dHighOld == 0)
+> {
+> g3d.f3dDialogs = fFalse;
+> return fFalse;
+> }
+>
+1945,1947c1970,1975
+< Win32Only(g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0);
+< Win16Only(g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0);
+< Win16Only(g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0);
+---
+> g3d.aCtl3dOld ? GlobalDeleteAtom(g3d.aCtl3dOld) : 0;
+> g3d.aCtl3d ? GlobalDeleteAtom(g3d.aCtl3d) : 0;
+> g3d.aCtl3dLowOld ? GlobalDeleteAtom(g3d.aCtl3dLowOld) : 0;
+> g3d.aCtl3dHighOld ? GlobalDeleteAtom(g3d.aCtl3dHighOld) : 0;
+> g3d.aCtl3dLow ? GlobalDeleteAtom(g3d.aCtl3dLow) : 0;
+> g3d.aCtl3dHigh ? GlobalDeleteAtom(g3d.aCtl3dHigh) : 0;
+2047a2076
+> case WM_CHECKSUBCLASS_OLD:
+2861a2891
+> case WM_CHECKSUBCLASS_OLD:
+2994a3025,3027
+> if (fSubclass == 666)
+> ctParent = (int)SendMessage(hwndParent, WM_CHECKSUBCLASS_OLD, 0, (LPARAM)(int FAR *)&fSubclass);
+>
+3116a3150
+> case WM_CHECKSUBCLASS_OLD:
+3159a3194
+> case WM_CHECKSUBCLASS_OLD:
+3232a3268
+> case WM_CHECKSUBCLASS_OLD:
+3362a3399
+> case WM_CHECKSUBCLASS_OLD:
+---------- nonship\ctl3d\ctl3d.rc next ----------
+10c10
+< #define VER_PRODUCTVERSION_STR "2,30,0,0\0"
+---
+> #define VER_PRODUCTVERSION_STR "2,31,0,0\0"
+13c13
+< #define VERSION "2.30.000"
+---
+> #define VERSION "2.31.000"
+16c16
+< #define VER_PRODUCTVERSION 2,30,0,0
+---
+> #define VER_PRODUCTVERSION 2,31,0,0
+19,20c19,20
+< #define VER_FILEVERSION 2,30,0,0
+< #define VER_FILEVERSION_STR "2.30.000\0"
+---
+> #define VER_FILEVERSION 2,31,0,0
+> #define VER_FILEVERSION_STR "2.31.000\0"
+---------- nonship\ctl3d\makefile.dlx next ----------
+116c116
+< linkdebug=$(linkdebug) /version:2.30
+---
+> linkdebug=$(linkdebug) /version:2.31
diff --git a/private/mvdm/wow16/ctl3dv2/version.h b/private/mvdm/wow16/ctl3dv2/version.h
new file mode 100644
index 000000000..9282e44cc
--- /dev/null
+++ b/private/mvdm/wow16/ctl3dv2/version.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * *
+ * VERSION.H -- Version information for internal builds *
+ * *
+ * This file is only modified by the official builder to update the *
+ * VERSION, VER_PRODUCTVERSION and VER_PRODUCTVERSION_STR values *
+ * *
+ ****************************************************************************/
+
+#ifndef VS_FF_DEBUG
+/* ver.h defines constants needed by the VS_VERSION_INFO structure */
+#include <ver.h>
+#endif
+
+/*--------------------------------------------------------------*/
+/* the following entry should be phased out in favor of */
+/* VER_PRODUCTVERSION_STR, but is used in the shell today. */
+/*--------------------------------------------------------------*/
+
+
+/*--------------------------------------------------------------*/
+/* the following values should be modified by the official */
+/* builder for each build */
+/*--------------------------------------------------------------*/
+
+#define VERSION "2.1.500"
+#define VER_PRODUCTVERSION_STR "2,1,5,0\0"
+#define VER_PRODUCTVERSION 2,1,5,00
+
+/*--------------------------------------------------------------*/
+/* the following section defines values used in the version */
+/* data structure for all files, and which do not change. */
+/*--------------------------------------------------------------*/
+
+/* default is nodebug */
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+/* default is privatebuild */
+#ifndef OFFICIAL
+#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
+#else
+#define VER_PRIVATEBUILD 0
+#endif
+
+/* default is prerelease */
+#ifndef FINAL
+#define VER_PRERELEASE VS_FF_PRERELEASE
+#else
+#define VER_PRERELEASE 0
+#endif
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEOS VOS_DOS_WINDOWS16
+#define VER_FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)
+
+#define VER_COMPANYNAME_STR "Microsoft Corporation\0"
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows(TM) Operating System\0"
+#define VER_LEGALTRADEMARKS_STR \
+"Microsoft\256 is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
diff --git a/private/mvdm/wow16/ddeml/ddeml.c b/private/mvdm/wow16/ddeml/ddeml.c
new file mode 100644
index 000000000..828fd2e64
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/ddeml.c
@@ -0,0 +1,2342 @@
+/****************************** Module Header ******************************\
+* Module Name: ddeml.C
+*
+* DDE Manager main module - Contains all exported ddeml functions.
+*
+* Created: 12/12/88 Sanford Staab
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+* 4/5/89 sanfords removed need for hwndFrame registration parameter
+* 6/5/90 sanfords Fixed callbacks so they are blocked during
+* timeouts.
+* Fixed SendDDEInit allocation bug.
+* Added hApp to ConvInfo structure.
+* Allowed QueryConvInfo() to work on server hConvs.
+* 11/29/90 sanfords eliminated SendDDEInit()
+*
+\***************************************************************************/
+
+#include "ddemlp.h"
+#include "verddeml.h"
+
+/****** Globals *******/
+
+HANDLE hInstance = 0; // initialized by LoadProc
+HANDLE hheapDmg = 0; // main DLL heap
+PAPPINFO pAppInfoList = NULL; // registered app/thread data list
+PPILE pDataInfoPile = NULL; // Data handle tracking pile
+PPILE pLostAckPile = NULL; // Ack tracking pile
+WORD hwInst = 1; // used to validate stuff.
+CONVCONTEXT CCDef = { sizeof(CONVCONTEXT), 0, 0, CP_WINANSI, 0L, 0L }; // default context.
+char szNull[] = "";
+char szT[20];
+WORD cMonitor = 0; // number of registered monitors
+FARPROC prevHook = NULL; // used for hook links
+ATOM gatomDDEMLMom = 0;
+ATOM gatomDMGClass = 0;
+DWORD ShutdownTimeout;
+DWORD ShutdownRetryTimeout;
+LPMQL gMessageQueueList = NULL; // see PostDdeMessage();
+#ifdef DEBUG
+int bDbgFlags = 0;
+#endif
+
+/****** class strings ******/
+
+char SZFRAMECLASS[] = "DMGFrame";
+char SZDMGCLASS[] = "DMGClass";
+char SZCLIENTCLASS[] = "DMGClientClass";
+char SZSERVERCLASS[] = "DMGServerClass";
+char SZMONITORCLASS[] = "DMGMonitorClass";
+char SZCONVLISTCLASS[] = "DMGHoldingClass";
+char SZHEAPWATCHCLASS[] = "DMGHeapWatchClass";
+
+#ifdef DEBUG
+WORD cAtoms = 0; // for debugging hszs!
+#endif
+
+
+// PROGMAN HACK!!!!
+// This is here so DDEML works properly with PROGMAN 3.0 which incorrectly
+// deletes its initiate-ack atoms after sending its ack.
+ATOM aProgmanHack = 0;
+
+
+/*
+ * maps XTYP_CONSTANTS to filter flags
+ */
+DWORD aulmapType[] = {
+ 0L, // nothing
+ 0L, // XTYP_ADVDATA
+ 0L, // XTYP_ADVREQ
+ CBF_FAIL_ADVISES, // XTYP_ADVSTART
+ 0L, // XTYP_ADVSTOP
+ CBF_FAIL_EXECUTES, // XTYP_EXECUTE
+ CBF_FAIL_CONNECTIONS, // XTYP_CONNECT
+ CBF_SKIP_CONNECT_CONFIRMS, // XTYP_CONNECT_CONFIRM
+ 0L, // XTYP_MONITOR
+ CBF_FAIL_POKES, // XTYP_POKE
+ CBF_SKIP_REGISTRATIONS, // XTYP_REGISTER
+ CBF_FAIL_REQUESTS, // XTYP_REQUEST
+ CBF_SKIP_DISCONNECTS, // XTYP_DISCONNECT
+ CBF_SKIP_UNREGISTRATIONS, // XTYP_UNREGISTER
+ CBF_FAIL_CONNECTIONS, // XTYP_WILDCONNECT
+ 0L, // XTYP_XACT_COMPLETE
+ };
+
+
+
+
+UINT EXPENTRY DdeInitialize(
+LPDWORD pidInst,
+PFNCALLBACK pfnCallback,
+DWORD afCmd,
+DWORD ulRes)
+{
+ WORD wRet;
+
+#ifdef DEBUG
+ if (!hheapDmg) {
+ bDbgFlags = GetProfileInt("DDEML", "DebugFlags", 0);
+ }
+#endif
+ TRACEAPIIN((szT, "DdeInitialize(%lx(->%lx), %lx, %lx, %lx)\n",
+ pidInst, *pidInst, pfnCallback, afCmd, ulRes));
+
+ if (ulRes != 0L) {
+ wRet = DMLERR_INVALIDPARAMETER;
+ } else {
+ wRet = Register(pidInst, pfnCallback, afCmd);
+ }
+ TRACEAPIOUT((szT, "DdeInitialize:%x\n", wRet));
+ return(wRet);
+}
+
+
+DWORD Myatodw(LPCSTR psz)
+{
+ DWORD dwRet = 0;
+
+ if (psz == NULL) {
+ return(0);
+ }
+ while (*psz) {
+ dwRet = (dwRet << 1) + (dwRet << 3) + (*psz - '0');
+ psz++;
+ }
+ return(dwRet);
+}
+
+
+WORD Register(
+LPDWORD pidInst,
+PFNCALLBACK pfnCallback,
+DWORD afCmd)
+{
+ PAPPINFO pai = 0L;
+
+ SEMENTER();
+
+ if (afCmd & APPCLASS_MONITOR) {
+ if (cMonitor == MAX_MONITORS) {
+ return(DMLERR_DLL_USAGE);
+ }
+ // ensure monitors only get monitor callbacks.
+ afCmd |= CBF_MONMASK;
+ }
+
+ if ((pai = (PAPPINFO)(*pidInst)) != NULL) {
+ if (pai->instCheck != HIWORD(*pidInst)) {
+ return(DMLERR_INVALIDPARAMETER);
+ }
+ /*
+ * re-registration - only allow CBF_ and MF_ flags to be altered
+ */
+ pai->afCmd = (pai->afCmd & ~(CBF_MASK | MF_MASK)) |
+ (afCmd & (CBF_MASK | MF_MASK));
+ return(DMLERR_NO_ERROR);
+ }
+
+ if (!hheapDmg) {
+#ifdef MSG
+ extern VOID dbz(VOID);
+#endif
+
+ // Read in any alterations to the zombie terminate timeouts
+ GetProfileString("DDEML", "ShutdownTimeout", "3000", szT, 20);
+ ShutdownTimeout = Myatodw(szT);
+ if (!ShutdownTimeout) {
+ ShutdownTimeout = 3000;
+ }
+
+ GetProfileString("DDEML", "ShutdownRetryTimeout", "30000", szT, 20);
+ ShutdownRetryTimeout = Myatodw(szT);
+ if (!ShutdownRetryTimeout) {
+ ShutdownRetryTimeout = 30000;
+ }
+
+ // PROGMAN HACK!!!!
+ aProgmanHack = GlobalAddAtom("Progman");
+
+ /* UTTER GREASE to fool the pile routines into making a local pile */
+ hheapDmg = HIWORD((LPVOID)(&pDataInfoPile));
+#ifdef MSG
+ dbz();
+#endif
+ RegisterClasses();
+ }
+
+ if (!pDataInfoPile) {
+ if (!(pDataInfoPile = CreatePile(hheapDmg, sizeof(DIP), 8))) {
+ goto Abort;
+ }
+ }
+
+ if (!pLostAckPile) {
+ if (!(pLostAckPile = CreatePile(hheapDmg, sizeof(LAP), 8))) {
+ goto Abort;
+ }
+ }
+
+ pai = (PAPPINFO)(DWORD)FarAllocMem(hheapDmg, sizeof(APPINFO));
+ if (pai == NULL) {
+ goto Abort;
+ }
+
+
+ if (!(pai->hheapApp = DmgCreateHeap(4096))) {
+ FarFreeMem((LPSTR)pai);
+ pai = 0L;
+ goto Abort;
+ }
+
+ /*
+ * We NEVER expect a memory allocation failure here because we just
+ * allocated the heap.
+ */
+ pai->next = pAppInfoList;
+ pai->pfnCallback = pfnCallback;
+ // pai->pAppNamePile = NULL; LMEM_ZEROINIT
+ pai->pHDataPile = CreatePile(pai->hheapApp, sizeof(HDDEDATA), 32);
+ pai->pHszPile = CreatePile(pai->hheapApp, sizeof(ATOM), 16);
+ // pai->plstCBExceptions = NULL; LMEM_ZEROINIT
+ // pai->hwndSvrRoot = 0; may never need it LMEM_ZEROINIT
+ pai->plstCB = CreateLst(pai->hheapApp, sizeof(CBLI));
+ pai->afCmd = afCmd | APPCMD_FILTERINITS;
+ pai->hTask = GetCurrentTask();
+ // pai->hwndDmg = LMEM_ZEROINIT
+ // pai->hwndFrame = LMEM_ZEROINIT
+ // pai->hwndMonitor = LMEM_ZEROINIT
+ // pai->hwndTimer = 0; LMEM_ZEROINIT
+ // pai->LastError = DMLERR_NO_ERROR; LMEM_ZEROINIT
+ // pai->wFlags = 0;
+ // pai->fEnableOneCB = FALSE; LMEM_ZEROINIT
+ // pai->cZombies = 0; LMEM_ZEROINIT
+ // pai->cInProcess = 0; LMEM_ZEROINIT
+ pai->instCheck = ++hwInst;
+ pai->pServerAdvList = CreateLst(pai->hheapApp, sizeof(ADVLI));
+ pai->lpMemReserve = FarAllocMem(pai->hheapApp, CB_RESERVE);
+
+ pAppInfoList = pai;
+
+ *pidInst = (DWORD)MAKELONG((WORD)pai, pai->instCheck);
+
+ // NB We pass a pointer to pai in this CreateWindow because
+ // 32bit MFC has a habit of subclassing our dde windows so this
+ // param ends up getting thunked and since it's not really
+ // a pointer things get a bit broken by the thunks.
+
+ if ((pai->hwndDmg = CreateWindow(
+ SZDMGCLASS,
+ szNull,
+ WS_OVERLAPPED,
+ 0, 0, 0, 0,
+ (HWND)NULL,
+ (HMENU)NULL,
+ hInstance,
+ &pai)) == 0L) {
+ goto Abort;
+ }
+
+ if (pai->afCmd & APPCLASS_MONITOR) {
+ pai->afCmd |= CBF_MONMASK; // monitors only get MONITOR and REGISTER callbacks!
+
+ if ((pai->hwndMonitor = CreateWindow(
+ SZMONITORCLASS,
+ szNull,
+ WS_OVERLAPPED,
+ 0, 0, 0, 0,
+ (HWND)NULL,
+ (HMENU)NULL,
+ hInstance,
+ &pai)) == 0L) {
+ goto Abort;
+ }
+
+ if (++cMonitor == 1) {
+ prevHook = SetWindowsHook(WH_GETMESSAGE, (FARPROC)DdePostHookProc);
+ prevHook = SetWindowsHook(WH_CALLWNDPROC, (FARPROC)DdeSendHookProc);
+ }
+ } else if (afCmd & APPCMD_CLIENTONLY) {
+ /*
+ * create an invisible top-level frame for initiates. (if server ok)
+ */
+ afCmd |= CBF_FAIL_ALLSVRXACTIONS;
+ } else {
+ if ((pai->hwndFrame = CreateWindow(
+ SZFRAMECLASS,
+ szNull,
+ WS_POPUP,
+ 0, 0, 0, 0,
+ (HWND)NULL,
+ (HMENU)NULL,
+ hInstance,
+ &pai)) == 0L) {
+ goto Abort;
+ }
+ }
+
+ // SetMessageQueue(200);
+
+ SEMLEAVE();
+
+ return(DMLERR_NO_ERROR);
+
+Abort:
+ SEMLEAVE();
+
+ if (pai) {
+ DdeUninitialize((DWORD)(LPSTR)pai);
+ }
+
+ return(DMLERR_SYS_ERROR);
+}
+
+
+LRESULT FAR PASCAL TermDlgProc(
+HWND hwnd,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ return(TRUE);
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDABORT:
+ case IDRETRY:
+ case IDIGNORE:
+ EndDialog(hwnd, wParam);
+ return(0);
+ }
+ break;
+ }
+ return(0);
+}
+
+
+/***************************** Public Function ****************************\
+* PUBDOC START
+* BOOL EXPENTRY DdeUninitialize(void);
+* This unregisters the application from the DDEMGR. All DLL resources
+* associated with the application are destroyed.
+*
+* PUBDOC END
+*
+* History:
+* Created 12/14/88 Sanfords
+\***************************************************************************/
+BOOL EXPENTRY DdeUninitialize(
+DWORD idInst)
+{
+ register PAPPINFO pai;
+ PAPPINFO paiT;
+ ATOM a;
+ DWORD hData;
+ MSG msg;
+ extern VOID DumpGlobalLogs(VOID);
+
+ TRACEAPIIN((szT, "DdeUninitialize(%lx)\n", idInst));
+
+ pai = (PAPPINFO)LOWORD(idInst);
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeUninitialize:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ /*
+ * This is a hack to catch apps that call DdeUninitialize while within
+ * a synchronous transaction modal loop.
+ */
+ pai->wFlags |= AWF_UNINITCALLED;
+ if (pai->wFlags & AWF_INSYNCTRANSACTION) {
+ TRACEAPIOUT((szT, "DdeUninitialize:1\n"));
+ return(TRUE);
+ }
+
+ /*
+ * inform others of DeRegistration
+ */
+ if (pai->pAppNamePile != NULL) {
+ DdeNameService(idInst, (HSZ)NULL, (HSZ)NULL, DNS_UNREGISTER);
+ }
+
+ /*
+ * Let any lagging dde activity die down.
+ */
+ while (EmptyDDEPostQ()) {
+ Yield();
+ while (PeekMessage((MSG FAR *)&msg, (HWND)NULL,
+ WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) {
+ DispatchMessage((MSG FAR *)&msg);
+ Yield();
+ }
+ for (paiT = pAppInfoList; paiT != NULL; paiT = paiT->next) {
+ if (paiT->hTask == pai->hTask) {
+ CheckCBQ(paiT);
+ }
+ }
+ }
+
+ // Let all windows left begin to self destruct.
+ ChildMsg(pai->hwndDmg, UM_DISCONNECT, ST_PERM2DIE, 0L, FALSE);
+
+ if (ShutdownTimeout && pai->cZombies) {
+ WORD wRet;
+ WORD hiTimeout;
+ /*
+ * This ugly mess is here to prevent DDEML from closing down and
+ * destroying windows that are not properly terminated. Any
+ * windows waiting on WM_DDE_TERMINATE messages set the cZombies
+ * count. If there are any left we go into a modal loop till
+ * things clean up. This should, in most cases happen fairly
+ * quickly.
+ */
+
+ hiTimeout = HIWORD(ShutdownTimeout);
+ SetTimer(pai->hwndDmg, TID_SHUTDOWN, LOWORD(ShutdownTimeout), NULL);
+ TRACETERM((szT, "DdeUninitialize: Entering terminate modal loop. cZombies=%d[%x:%x]\n",
+ ((LPAPPINFO)pai)->cZombies,
+ HIWORD(&((LPAPPINFO)pai)->cZombies),
+ LOWORD(&((LPAPPINFO)pai)->cZombies)));
+ while (pai->cZombies > 0) {
+ Yield(); // give other apps a chance to post terminates.
+ GetMessage(&msg, (HWND)NULL, 0, 0xffff);
+ if (msg.message == WM_TIMER && msg.wParam == TID_SHUTDOWN &&
+ msg.hwnd == pai->hwndDmg) {
+ if (hiTimeout--) {
+ SetTimer(pai->hwndDmg, TID_SHUTDOWN, 0xFFFF, NULL);
+ } else {
+ FARPROC lpfn;
+
+ KillTimer(pai->hwndDmg, TID_SHUTDOWN);
+ if (!pai->cZombies) {
+ break;
+ }
+
+ TRACETERM((szT,
+ "DdeUninitialize Zombie hangup: pai=%x:%x\n",
+ HIWORD((LPAPPINFO)pai), (WORD)(pai)));
+ /*
+ * If the partner window died in any remaining zombie
+ * windows, get them shut down.
+ */
+ ChildMsg(pai->hwndDmg, UM_DISCONNECT, ST_CHECKPARTNER, 0L, FALSE);
+
+ if (pai->cZombies > 0) {
+ lpfn = MakeProcInstance((FARPROC)TermDlgProc, hInstance);
+ wRet = DialogBox(hInstance, "TermDialog", (HWND)NULL, lpfn);
+ FreeProcInstance(lpfn);
+ if (wRet == IDABORT || wRet == -1) {
+ pai->cZombies = 0;
+ break; // ignore zombies!
+ }
+ if (wRet == IDRETRY) {
+ hiTimeout = HIWORD(ShutdownRetryTimeout);
+ SetTimer(pai->hwndDmg, TID_SHUTDOWN,
+ LOWORD(ShutdownRetryTimeout), NULL);
+ }
+ // IDIGNORE - loop forever!
+ }
+ }
+ }
+ // app should already be shut-down so we don't bother with
+ // accelerator or menu translations.
+ DispatchMessage(&msg);
+ /*
+ * tell all instances in this task to process their
+ * callbacks so we can clear our queue.
+ */
+ EmptyDDEPostQ();
+ for (paiT = pAppInfoList; paiT != NULL; paiT = paiT->next) {
+ if (paiT->hTask == pai->hTask) {
+ CheckCBQ(paiT);
+ }
+ }
+ }
+ }
+#if 0 // don't need this anymore
+ if (pai->hwndTimer) {
+ pai->wTimeoutStatus |= TOS_ABORT;
+ PostMessage(pai->hwndTimer, WM_TIMER, TID_TIMEOUT, 0);
+ // if this fails, no big deal because it means the queue is full
+ // and the modal loop will catch our TOS_ABORT quickly.
+ // We need to do this in case no activity is happening in the
+ // modal loop.
+ }
+#endif
+ if (pai->hwndMonitor) {
+ DmgDestroyWindow(pai->hwndMonitor);
+ if (!--cMonitor) {
+ UnhookWindowsHook(WH_GETMESSAGE, (FARPROC)DdePostHookProc);
+ UnhookWindowsHook(WH_CALLWNDPROC, (FARPROC)DdeSendHookProc);
+ }
+ }
+ UnlinkAppInfo(pai);
+
+ DmgDestroyWindow(pai->hwndDmg);
+ DmgDestroyWindow(pai->hwndFrame);
+
+ while (PopPileSubitem(pai->pHDataPile, (LPBYTE)&hData))
+ FreeDataHandle(pai, hData, FALSE);
+ DestroyPile(pai->pHDataPile);
+
+ while (PopPileSubitem(pai->pHszPile, (LPBYTE)&a)) {
+ MONHSZ(a, MH_CLEANUP, pai->hTask);
+ FreeHsz(a);
+ }
+ DestroyPile(pai->pHszPile);
+ DestroyPile(pai->pAppNamePile);
+ DestroyLst(pai->pServerAdvList);
+ DmgDestroyHeap(pai->hheapApp);
+ pai->instCheck--; // make invalid on later attempts to reinit.
+ FarFreeMem((LPSTR)pai);
+
+ /* last one out.... trash the data info heap */
+ if (!pAppInfoList) {
+#ifdef DEBUG
+ DIP dip;
+
+ AssertF(!PopPileSubitem(pDataInfoPile, (LPBYTE)&dip),
+ "leftover APPOWNED handles");
+#endif
+ DestroyPile(pDataInfoPile);
+ DestroyPile(pLostAckPile);
+ pDataInfoPile = NULL;
+ pLostAckPile = NULL;
+ AssertFW(cAtoms == 0, "DdeUninitialize() - leftover atoms");
+
+ // PROGMAN HACK!!!!
+ GlobalDeleteAtom(aProgmanHack);
+ // CLOSEHEAPWATCH();
+ }
+
+#ifdef DEBUG
+ DumpGlobalLogs();
+#endif
+
+ TRACEAPIOUT((szT, "DdeUninitialize:1\n"));
+ return(TRUE);
+}
+
+
+
+
+
+
+HCONVLIST EXPENTRY DdeConnectList(
+DWORD idInst,
+HSZ hszSvcName,
+HSZ hszTopic,
+HCONVLIST hConvList,
+PCONVCONTEXT pCC)
+{
+ PAPPINFO pai;
+ HWND hConv, hConvNext, hConvNew, hConvLast;
+ HWND hConvListNew;
+ PCLIENTINFO pciOld, pciNew;
+
+
+ TRACEAPIIN((szT, "DdeConnectList(%lx, %lx, %lx, %lx, %lx)\n",
+ idInst, hszSvcName, hszTopic, hConvList, pCC));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeConnectList:0\n"));
+ return(0L);
+ }
+
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (hConvList && !ValidateHConv(hConvList)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeConnectList:0\n"));
+ return(0L);
+ }
+
+ /*
+ * destroy any dead old clients
+ */
+ if ((HWND)hConvList && (hConv = GetWindow((HWND)hConvList, GW_CHILD))) {
+ do {
+ hConvNext = GetWindow((HWND)hConv, GW_HWNDNEXT);
+ pciOld = (PCLIENTINFO)GetWindowLong(hConv, GWL_PCI);
+ if (!(pciOld->ci.fs & ST_CONNECTED)) {
+ SetParent(hConv, pai->hwndDmg);
+ Disconnect(hConv, ST_PERM2DIE, pciOld);
+ }
+ } while (hConv = hConvNext);
+ }
+
+ // create a new list window
+
+ if ((hConvListNew = CreateWindow(
+ SZCONVLISTCLASS,
+ szNull,
+ WS_CHILD,
+ 0, 0, 0, 0,
+ pai->hwndDmg,
+ (HMENU)NULL,
+ hInstance,
+ &pai)) == NULL) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ TRACEAPIOUT((szT, "DdeConnectList:0\n"));
+ return(0L);
+ }
+
+ // Make all possible connections to new list window
+
+ hConvNew = GetDDEClientWindow(pai, hConvListNew, HIWORD(hszSvcName), LOWORD(hszSvcName), LOWORD(hszTopic), pCC);
+
+ /*
+ * If no new hConvs created, return old list.
+ */
+ if (hConvNew == NULL) {
+ // if no old hConvs as well, destroy all and return NULL
+ if ((HWND)hConvList && GetWindow((HWND)hConvList, GW_CHILD) == NULL) {
+ SendMessage((HWND)hConvList, UM_DISCONNECT,
+ ST_PERM2DIE, 0L);
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ TRACEAPIOUT((szT, "DdeConnectList:0\n"));
+ return(NULL);
+ }
+ // else just return old list (- dead convs)
+ if (hConvList == NULL) {
+ DestroyWindow(hConvListNew);
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ }
+ TRACEAPIOUT((szT, "DdeConnectList:%lx\n", hConvList));
+ return(hConvList);
+ }
+
+ /*
+ * remove duplicates from the new list
+ */
+ if ((HWND)hConvList && (hConv = GetWindow((HWND)hConvList, GW_CHILD))) {
+ // go throuch old list...
+ do {
+ pciOld = (PCLIENTINFO)GetWindowLong(hConv, GWL_PCI);
+ /*
+ * destroy any new clients that are duplicates of the old ones.
+ */
+ hConvNew = GetWindow(hConvListNew, GW_CHILD);
+ hConvLast = GetWindow(hConvNew, GW_HWNDLAST);
+ while (hConvNew) {
+ if (hConvNew == hConvLast) {
+ hConvNext = NULL;
+ } else {
+ hConvNext = GetWindow(hConvNew, GW_HWNDNEXT);
+ }
+ pciNew = (PCLIENTINFO)GetWindowLong(hConvNew, GWL_PCI);
+ if (pciOld->ci.aServerApp == pciNew->ci.aServerApp &&
+ pciOld->ci.aTopic == pciNew->ci.aTopic &&
+ pciOld->ci.hwndFrame == pciNew->ci.hwndFrame) {
+ /*
+ * assume same app, same topic, same hwndFrame is a duplicate.
+ *
+ * Move dieing window out of the list since it
+ * dies asynchronously and will still be around
+ * after this API exits.
+ */
+ SetParent(hConvNew, pai->hwndDmg);
+ Disconnect(hConvNew, ST_PERM2DIE,
+ (PCLIENTINFO)GetWindowLong(hConvNew, GWL_PCI));
+ }
+ hConvNew = hConvNext;
+ }
+ hConvNext = GetWindow(hConv, GW_HWNDNEXT);
+ if (hConvNext && (GetParent(hConvNext) != (HWND)hConvList)) {
+ hConvNext = NULL;
+ }
+ /*
+ * move the unique old client to the new list
+ */
+ SetParent(hConv, hConvListNew);
+ } while (hConv = hConvNext);
+ // get rid of the old list
+ SendMessage((HWND)hConvList, UM_DISCONNECT, ST_PERM2DIE, 0L);
+ }
+
+ /*
+ * If none are left, fail because no conversations were established.
+ */
+ if (GetWindow(hConvListNew, GW_CHILD) == NULL) {
+ SendMessage(hConvListNew, UM_DISCONNECT, ST_PERM2DIE, 0L);
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ TRACEAPIOUT((szT, "DdeConnectList:0\n"));
+ return(NULL);
+ } else {
+ TRACEAPIOUT((szT, "DdeConnectList:%lx\n", MAKEHCONV(hConvListNew)));
+ return(MAKEHCONV(hConvListNew));
+ }
+}
+
+
+
+
+
+
+HCONV EXPENTRY DdeQueryNextServer(
+HCONVLIST hConvList,
+HCONV hConvPrev)
+{
+ HWND hwndMaybe;
+ PAPPINFO pai;
+
+ TRACEAPIIN((szT, "DdeQueryNextServer(%lx, %lx)\n",
+ hConvList, hConvPrev));
+
+ if (!ValidateHConv(hConvList)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ }
+ TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
+ return NULL;
+ }
+
+ pai = EXTRACTHCONVLISTPAI(hConvList);
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (hConvPrev == NULL) {
+ TRACEAPIOUT((szT, "DdeQueryNextServer:%lx\n",
+ MAKEHCONV(GetWindow((HWND)hConvList, GW_CHILD))));
+ return MAKEHCONV(GetWindow((HWND)hConvList, GW_CHILD));
+ } else {
+ if (!ValidateHConv(hConvPrev)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
+ return NULL;
+ }
+ hwndMaybe = GetWindow((HWND)hConvPrev, GW_HWNDNEXT);
+ if (!hwndMaybe) {
+ TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
+ return NULL;
+ }
+
+ // make sure it's got the same parent and isn't the first child
+ // ### maybe this code can go - I'm not sure how GW_HWNDNEXT acts. SS
+ if (GetParent(hwndMaybe) == (HWND)hConvList &&
+ hwndMaybe != GetWindow((HWND)hConvList, GW_CHILD)) {
+ TRACEAPIOUT((szT, "DdeQueryNextServer:%lx\n", MAKEHCONV(hwndMaybe)));
+ return MAKEHCONV(hwndMaybe);
+ }
+ TRACEAPIOUT((szT, "DdeQueryNextServer:0\n"));
+ return NULL;
+ }
+}
+
+
+
+
+
+
+BOOL EXPENTRY DdeDisconnectList(
+HCONVLIST hConvList)
+{
+ PAPPINFO pai;
+
+ TRACEAPIIN((szT, "DdeDisconnectList(%lx)\n", hConvList));
+
+ if (!ValidateHConv(hConvList)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ }
+ TRACEAPIOUT((szT, "DdeDisconnectList:0\n"));
+ return(FALSE);
+ }
+ pai = EXTRACTHCONVLISTPAI(hConvList);
+ pai->LastError = DMLERR_NO_ERROR;
+
+ SendMessage((HWND)hConvList, UM_DISCONNECT, ST_PERM2DIE, 0L);
+ TRACEAPIOUT((szT, "DdeDisconnectList:1\n"));
+ return(TRUE);
+}
+
+
+
+
+
+HCONV EXPENTRY DdeConnect(
+DWORD idInst,
+HSZ hszSvcName,
+HSZ hszTopic,
+PCONVCONTEXT pCC)
+{
+ PAPPINFO pai;
+ HWND hwnd;
+
+ TRACEAPIIN((szT, "DdeConnect(%lx, %lx, %lx, %lx)\n",
+ idInst, hszSvcName, hszTopic, pCC));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeConnect:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (pCC && pCC->cb != sizeof(CONVCONTEXT)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeConnect:0\n"));
+ return(0);
+ }
+
+
+ hwnd = GetDDEClientWindow(pai, pai->hwndDmg, (HWND)HIWORD(hszSvcName),
+ LOWORD(hszSvcName), LOWORD(hszTopic), pCC);
+
+ if (hwnd == 0) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ }
+
+ TRACEAPIOUT((szT, "DdeConnect:%lx\n", MAKEHCONV(hwnd)));
+ return(MAKEHCONV(hwnd));
+}
+
+
+
+
+
+BOOL EXPENTRY DdeDisconnect(
+HCONV hConv)
+{
+ PAPPINFO pai;
+ PCLIENTINFO pci;
+
+ TRACEAPIIN((szT, "DdeDisconnect(%lx)\n", hConv));
+
+ if (!ValidateHConv(hConv)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ }
+ TRACEAPIOUT((szT, "DdeDisconnect:0\n"));
+ return(FALSE);
+ }
+ pai = EXTRACTHCONVPAI(hConv);
+ pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
+ if (pai->cInProcess) {
+ // do asynchronously if this is called within a callback
+ if (!PostMessage((HWND)hConv, UM_DISCONNECT, ST_PERM2DIE, (LONG)pci)) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ TRACEAPIOUT((szT, "DdeDisconnect:0\n"));
+ return(FALSE);
+ }
+ } else {
+ Disconnect((HWND)hConv, ST_PERM2DIE, pci);
+ }
+ TRACEAPIOUT((szT, "DdeDisconnect:1\n"));
+ return(TRUE);
+}
+
+
+
+
+
+HCONV EXPENTRY DdeReconnect(
+HCONV hConv)
+{
+ HWND hwnd;
+ PAPPINFO pai;
+ PCLIENTINFO pci;
+
+ TRACEAPIIN((szT, "DdeReconnect(%lx)\n", hConv));
+
+ if (!ValidateHConv(hConv)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ }
+ TRACEAPIOUT((szT, "DdeReconnect:0\n"));
+ return(FALSE);
+ }
+ pai = EXTRACTHCONVPAI(hConv);
+ pai->LastError = DMLERR_NO_ERROR;
+ pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
+
+ // The dyeing window MUST be a client to reconnect.
+
+ if (!(pci->ci.fs & ST_CLIENT)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeReconnect:0\n"));
+ return(FALSE);
+ }
+
+ hwnd = GetDDEClientWindow(pai, pai->hwndDmg, pci->ci.hwndFrame,
+ pci->ci.aServerApp, pci->ci.aTopic, &pci->ci.CC);
+
+ if (hwnd == 0) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ TRACEAPIOUT((szT, "DdeReconnect:0\n"));
+ return(FALSE);
+ }
+
+ if (pci->ci.fs & ST_INLIST) {
+ SetParent(hwnd, GetParent((HWND)hConv));
+ }
+
+ if (pci->ci.fs & ST_ADVISE) {
+ DWORD result;
+ PADVLI pali, paliNext;
+
+ // recover advise loops here
+
+ for (pali = (PADVLI)pci->pClientAdvList->pItemFirst; pali; pali = paliNext) {
+ paliNext = (PADVLI)pali->next;
+ if (pali->hwnd == (HWND)hConv) {
+ XFERINFO xi;
+
+ xi.pulResult = &result;
+ xi.ulTimeout = (DWORD)TIMEOUT_ASYNC;
+ xi.wType = XTYP_ADVSTART |
+ (pali->fsStatus & (XTYPF_NODATA | XTYPF_ACKREQ));
+ xi.wFmt = pali->wFmt;
+ xi.hszItem = (HSZ)pali->aItem;
+ xi.hConvClient = MAKEHCONV(hwnd);
+ xi.cbData = 0;
+ xi.hDataClient = NULL;
+ ClientXferReq(&xi, hwnd,
+ (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI));
+ }
+ }
+ }
+
+ TRACEAPIOUT((szT, "DdeReconnect:%lx\n", MAKEHCONV(hwnd)));
+ return(MAKEHCONV(hwnd));
+}
+
+
+
+UINT EXPENTRY DdeQueryConvInfo(
+HCONV hConv,
+DWORD idTransaction,
+PCONVINFO pConvInfo)
+{
+ PCLIENTINFO pci;
+ PAPPINFO pai;
+ PXADATA pxad;
+ PCQDATA pqd;
+ BOOL fClient;
+ WORD cb;
+ CONVINFO ci;
+
+ SEMCHECKOUT();
+
+ TRACEAPIIN((szT, "DdeQueryConvInfo(%lx, %lx, %lx(->cb=%lx))\n",
+ hConv, idTransaction, pConvInfo, pConvInfo->cb));
+
+ if (!ValidateHConv(hConv) ||
+ !(pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI))) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ }
+ TRACEAPIOUT((szT, "DdeQueryConvInfo:0\n"));
+ return(FALSE);
+ }
+ pai = pci->ci.pai;
+ pai->LastError = DMLERR_NO_ERROR;
+
+ /*
+ * This check attempts to prevent improperly coded apps from
+ * crashing due to having not initialized the cb field.
+ */
+ if (pConvInfo->cb > sizeof(CONVINFO) || pConvInfo->cb == 0) {
+ pConvInfo->cb = sizeof(CONVINFO) -
+ sizeof(HWND) - // for new hwnd field
+ sizeof(HWND); // for new hwndPartner field
+ }
+
+ fClient = (BOOL)SendMessage((HWND)hConv, UM_QUERY, Q_CLIENT, 0L);
+
+ if (idTransaction == QID_SYNC || !fClient) {
+ pxad = &pci->ci.xad;
+ } else {
+ if (pci->pQ != NULL && (pqd = (PCQDATA)Findqi(pci->pQ, idTransaction))) {
+ pxad = &pqd->xad;
+ } else {
+ SETLASTERROR(pai, DMLERR_UNFOUND_QUEUE_ID);
+ TRACEAPIOUT((szT, "DdeQueryConvInfo:0\n"));
+ return(FALSE);
+ }
+ }
+ SEMENTER();
+ ci.cb = sizeof(CONVINFO);
+ ci.hConvPartner = (IsWindow((HWND)pci->ci.hConvPartner) &&
+ ((pci->ci.fs & (ST_ISLOCAL | ST_CONNECTED)) == (ST_ISLOCAL | ST_CONNECTED)))
+ ? pci->ci.hConvPartner : NULL;
+ ci.hszSvcPartner = fClient ? pci->ci.aServerApp : 0;
+ ci.hszServiceReq = pci->ci.hszSvcReq;
+ ci.hszTopic = pci->ci.aTopic;
+ ci.wStatus = pci->ci.fs;
+ ci.ConvCtxt = pci->ci.CC;
+ if (fClient) {
+ ci.hUser = pxad->hUser;
+ ci.hszItem = pxad->pXferInfo->hszItem;
+ ci.wFmt = pxad->pXferInfo->wFmt;
+ ci.wType = pxad->pXferInfo->wType;
+ ci.wConvst = pxad->state;
+ ci.wLastError = pxad->LastError;
+ } else {
+ ci.hUser = pci->ci.xad.hUser;
+ ci.hszItem = NULL;
+ ci.wFmt = 0;
+ ci.wType = 0;
+ ci.wConvst = pci->ci.xad.state;
+ ci.wLastError = pci->ci.pai->LastError;
+ }
+ ci.hConvList = (pci->ci.fs & ST_INLIST) ?
+ MAKEHCONV(GetParent((HWND)hConv)) : 0;
+
+ cb = min(sizeof(CONVINFO), (WORD)pConvInfo->cb);
+ ci.hwnd = (HWND)hConv;
+ ci.hwndPartner = (HWND)pci->ci.hConvPartner;
+
+ hmemcpy((LPBYTE)pConvInfo, (LPBYTE)&ci, cb);
+ pConvInfo->cb = cb;
+ SEMLEAVE();
+ TRACEAPIOUT((szT, "DdeQueryConvInfo:%x\n", cb));
+ return(cb);
+}
+
+
+
+
+
+
+BOOL EXPENTRY DdeSetUserHandle(
+HCONV hConv,
+DWORD id,
+DWORD hUser)
+{
+ PAPPINFO pai;
+ PCLIENTINFO pci;
+ PXADATA pxad;
+ PCQDATA pqd;
+
+ TRACEAPIIN((szT, "DdeSetUserHandle(%lx, %lx, %lx)\n",
+ hConv, id, hUser));
+
+ if (!ValidateHConv(hConv)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ }
+ TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
+ return(FALSE);
+ }
+ pai = EXTRACTHCONVPAI(hConv);
+ pai->LastError = DMLERR_NO_ERROR;
+
+ SEMCHECKOUT();
+
+ pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
+ if (!pci) {
+Error:
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
+ return(FALSE);
+ }
+ pxad = &pci->ci.xad;
+ if (id != QID_SYNC) {
+ if (!SendMessage((HWND)hConv, UM_QUERY, Q_CLIENT, 0)) {
+ goto Error;
+ }
+ if (pci->pQ != NULL && (pqd = (PCQDATA)Findqi(pci->pQ, id))) {
+ pxad = &pqd->xad;
+ } else {
+ SETLASTERROR(pai, DMLERR_UNFOUND_QUEUE_ID);
+ TRACEAPIOUT((szT, "DdeSetUserHandle:0\n"));
+ return(FALSE);
+ }
+ }
+ pxad->hUser = hUser;
+ TRACEAPIOUT((szT, "DdeSetUserHandle:1\n"));
+ return(TRUE);
+}
+
+
+
+
+
+BOOL EXPENTRY DdePostAdvise(
+DWORD idInst,
+HSZ hszTopic,
+HSZ hszItem)
+{
+ PAPPINFO pai;
+ PSERVERINFO psi = NULL;
+ register PADVLI pali;
+ PADVLI paliPrev, paliEnd, paliMove;
+
+ TRACEAPIIN((szT, "DdePostAdvise(%lx, %lx, %lx)\n",
+ idInst, hszTopic, hszItem));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdePostAdvise:0\n"));
+ return(FALSE);
+ }
+
+ pai->LastError = DMLERR_NO_ERROR;
+ if (pai->afCmd & APPCMD_CLIENTONLY) {
+ SETLASTERROR(pai, DMLERR_DLL_USAGE);
+ TRACEAPIOUT((szT, "DdePostAdvise:0\n"));
+ return(FALSE);
+ }
+
+ paliPrev = NULL;
+ paliEnd = NULL;
+ paliMove = NULL;
+ pali = (PADVLI)pai->pServerAdvList->pItemFirst;
+ while (pali && pali != paliMove) {
+ if ((!hszItem || pali->aItem == (ATOM)hszItem) &&
+ (!hszTopic || pali->aTopic == (ATOM)hszTopic)) {
+ /*
+ * Advise loops are tricky because of the desireable FACKREQ feature
+ * of DDE. The advise loop list holds information in its fsStatus
+ * field to maintain the state of the advise loop.
+ *
+ * if the ADVST_WAITING bit is set, the server is still waiting for
+ * the client to give it the go-ahead for more data with an
+ * ACK message on this item. (FACKREQ is set) Without a go-ahead,
+ * the server will not send any more advise data to the client but
+ * will instead set the ADVST_CHANGED bit which will cause another
+ * WM_DDE_DATA message to be sent to the client as soon as the
+ * go-ahead ACK is received. This keeps the client up to date
+ * but never overloads it.
+ */
+ if (pali->fsStatus & ADVST_WAITING) {
+ /*
+ * if the client has not yet finished with the last data
+ * we gave him, just update the advise loop status
+ * instead of sending data now.
+ */
+ pali->fsStatus |= ADVST_CHANGED;
+ goto NextLink;
+ }
+
+ psi = (PSERVERINFO)GetWindowLong(pali->hwnd, GWL_PCI);
+
+ if (pali->fsStatus & DDE_FDEFERUPD) {
+ /*
+ * In the nodata case, we don't bother the server. Just
+ * pass the client an apropriate DATA message.
+ */
+ IncHszCount(pali->aItem); // message copy
+#ifdef DEBUG
+ cAtoms--; // don't count this add
+#endif
+ PostDdeMessage(&psi->ci, WM_DDE_DATA, pali->hwnd,
+ MAKELONG(0, pali->aItem), 0, 0);
+ } else {
+ PostServerAdvise(pali->hwnd, psi, pali, CountAdvReqLeft(pali));
+ }
+
+ if (pali->fsStatus & DDE_FACKREQ && pali->next) {
+ /*
+ * In order to know what ack goes with what data sent out, we
+ * place any updated advise loops at the end of the list so
+ * that acks associated with them are found last. ie First ack
+ * back goes with oldest data out.
+ */
+
+ // Unlink
+
+ if (paliPrev) {
+ paliPrev->next = pali->next;
+ } else {
+ pai->pServerAdvList->pItemFirst = (PLITEM)pali->next;
+ }
+
+ // put on the end
+
+ if (paliEnd) {
+ paliEnd->next = (PLITEM)pali;
+ paliEnd = pali;
+ } else {
+ for (paliEnd = pali;
+ paliEnd->next;
+ paliEnd = (PADVLI)paliEnd->next) {
+ }
+ paliEnd->next = (PLITEM)pali;
+ paliMove = paliEnd = pali;
+ }
+ pali->next = NULL;
+
+ if (paliPrev) {
+ pali = (PADVLI)paliPrev->next;
+ } else {
+ pali = (PADVLI)pai->pServerAdvList->pItemFirst;
+ }
+ continue;
+ }
+ }
+NextLink:
+ paliPrev = pali;
+ pali = (PADVLI)pali->next;
+ }
+ TRACEAPIOUT((szT, "DdePostAdvise:1\n"));
+ return(TRUE);
+}
+
+
+/*
+ * History: 4/18/91 sanfords - now always frees any incomming data handle
+ * thats not APPOWNED regardless of error case.
+ */
+HDDEDATA EXPENTRY DdeClientTransaction(
+LPBYTE pData,
+DWORD cbData,
+HCONV hConv,
+HSZ hszItem,
+UINT wFmt,
+UINT wType,
+DWORD ulTimeout,
+LPDWORD pulResult)
+{
+ PAPPINFO pai;
+ PCLIENTINFO pci;
+ HDDEDATA hData, hDataBack, hRet = 0;
+
+ SEMCHECKOUT();
+
+ TRACEAPIIN((szT, "DdeClientTransaction(%lx, %lx, %lx, %lx, %x, %x, %lx, %lx)\n",
+ pData, cbData, hConv, hszItem, wFmt, wType, ulTimeout, pulResult));
+
+ if (!ValidateHConv(hConv)) {
+ pai = NULL;
+ while (pai = GetCurrentAppInfo(pai)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ }
+ goto FreeErrExit;
+ }
+
+ pci = (PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI);
+ pai = pci->ci.pai;
+
+ /*
+ * Don't let transactions happen if we are shutting down
+ * or are already doing a sync transaction.
+ */
+ if ((ulTimeout != TIMEOUT_ASYNC && pai->wFlags & AWF_INSYNCTRANSACTION) ||
+ pai->wFlags & AWF_UNINITCALLED) {
+ SETLASTERROR(pai, DMLERR_REENTRANCY);
+ goto FreeErrExit;
+ }
+
+ pci->ci.pai->LastError = DMLERR_NO_ERROR;
+
+ if (!(pci->ci.fs & ST_CONNECTED)) {
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ goto FreeErrExit;
+ }
+
+ // If local, check filters first
+
+ if (pci->ci.fs & ST_ISLOCAL) {
+ PAPPINFO paiServer;
+ PSERVERINFO psi;
+
+ // we can do this because the app heaps are in global shared memory
+
+ psi = (PSERVERINFO)GetWindowLong((HWND)pci->ci.hConvPartner, GWL_PCI);
+
+ if (!psi) {
+ // SERVER DIED! - simulate a terminate received.
+
+ Terminate((HWND)hConv, (HWND)pci->ci.hConvPartner, pci);
+ SETLASTERROR(pai, DMLERR_NO_CONV_ESTABLISHED);
+ goto FreeErrExit;
+ }
+
+ paiServer = psi->ci.pai;
+
+ if (paiServer->afCmd & aulmapType[(wType & XTYP_MASK) >> XTYP_SHIFT]) {
+ SETLASTERROR(pai, DMLERR_NOTPROCESSED);
+FreeErrExit:
+ if ((wType == XTYP_POKE || wType == XTYP_EXECUTE) && cbData == -1 &&
+ !(LOWORD((DWORD)pData) & HDATA_APPOWNED)) {
+ FREEEXTHDATA(pData);
+ }
+ TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
+ return(0);
+ }
+ }
+
+ pai = pci->ci.pai;
+ switch (wType) {
+ case XTYP_POKE:
+ case XTYP_EXECUTE:
+
+ // prepair the outgoing handle
+
+ if (cbData == -1L) { // handle given, not pointer
+
+ hData = ((LPEXTDATAINFO)pData)->hData;
+ if (!(LOWORD(hData) & HDATA_APPOWNED)) {
+ FREEEXTHDATA(pData);
+ }
+ if (!(hData = DllEntry(&pci->ci, hData))) {
+ TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
+ return(0);
+ }
+ pData = (LPBYTE)hData; // place onto stack for pass on to ClientXferReq.
+
+ } else { // pointer given, create handle from it.
+
+ if (!(pData = (LPBYTE)PutData(pData, cbData, 0, LOWORD(hszItem), wFmt, 0, pai))) {
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
+ return(0);
+ }
+ }
+ hData = (HDDEDATA)pData; // used to prevent compiler over-optimization.
+
+ case XTYP_REQUEST:
+ case XTYP_ADVSTART:
+ case XTYP_ADVSTART | XTYPF_NODATA:
+ case XTYP_ADVSTART | XTYPF_ACKREQ:
+ if (wType != XTYP_EXECUTE && !hszItem) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
+ return(0);
+ }
+ case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
+ if (wType != XTYP_EXECUTE && !wFmt) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeClientTransaction:0\n"));
+ return(0);
+ }
+ case XTYP_ADVSTOP:
+
+ pai->LastError = DMLERR_NO_ERROR; // reset before start.
+
+ if (ulTimeout == TIMEOUT_ASYNC) {
+ hRet = (HDDEDATA)ClientXferReq((PXFERINFO)&pulResult, (HWND)hConv, pci);
+ } else {
+ pai->wFlags |= AWF_INSYNCTRANSACTION;
+ hDataBack = (HDDEDATA)ClientXferReq((PXFERINFO)&pulResult, (HWND)hConv, pci);
+ pai->wFlags &= ~AWF_INSYNCTRANSACTION;
+
+ if ((wType & XCLASS_DATA) && hDataBack) {
+ LPEXTDATAINFO pedi;
+
+ //if (AddPileItem(pai->pHDataPile, (LPBYTE)&hDataBack, CmpHIWORD) == API_ERROR) {
+ // SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ // goto ReturnPoint;
+ //}
+
+ // use app heap so any leftovers at Uninitialize time go away.
+ pedi = (LPEXTDATAINFO)FarAllocMem(pai->hheapApp, sizeof(EXTDATAINFO));
+ if (pedi) {
+ pedi->pai = pai;
+ pedi->hData = hDataBack;
+ } else {
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ }
+ hRet = (HDDEDATA)pedi;
+ goto ReturnPoint;
+ } else if (hDataBack) {
+ hRet = TRUE;
+ }
+ }
+ goto ReturnPoint;
+ }
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ReturnPoint:
+
+ if (pai->wFlags & AWF_UNINITCALLED) {
+ pai->wFlags &= ~AWF_UNINITCALLED;
+ DdeUninitialize(MAKELONG((WORD)pai, pai->instCheck));
+ }
+ TRACEAPIOUT((szT, "DdeClientTransaction:%lx\n", hRet));
+ return(hRet);
+}
+
+
+
+/***************************** Public Function ****************************\
+* PUBDOC START
+* WORD EXPENTRY DdeGetLastError(void)
+*
+* This API returns the most recent error registered by the DDE manager for
+* the current thread. This should be called anytime a DDE manager API
+* returns in a failed state.
+*
+* returns an error code which corresponds to a DMLERR_ constant found in
+* ddeml.h. This error code may be passed on to DdePostError() to
+* show the user the reason for the error.
+*
+* PUBDOC END
+*
+* History:
+* Created 12/14/88 Sanfords
+\***************************************************************************/
+UINT EXPENTRY DdeGetLastError(
+DWORD idInst)
+{
+ register PAPPINFO pai;
+ register WORD err = DMLERR_DLL_NOT_INITIALIZED;
+
+ TRACEAPIIN((szT, "DdeGetLastError(%lx)\n", idInst));
+
+ pai = (PAPPINFO)idInst;
+
+ if (pai) {
+ if (pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeGetLastError:%x [bad instance]\n",
+ DMLERR_INVALIDPARAMETER));
+ return(DMLERR_INVALIDPARAMETER);
+ }
+ err = pai->LastError;
+ pai->LastError = DMLERR_NO_ERROR;
+ }
+ TRACEAPIOUT((szT, "DdeGetLastError:%x\n", err));
+ return(err);
+}
+
+
+/*\
+* Data Handles:
+*
+* Control flags:
+*
+* HDCF_APPOWNED
+* Only the app can free this in the apps PID/TID context.
+* SET - when DdeCreateDataHandle is called with this flag given.
+* The hData is Logged at this time.
+*
+* HDCF_READONLY - set by ClientXfer and callback return.
+* The app cannot add data to handles in this state.
+* SET - when ClientXfer is entered
+* SET - when callback is left
+*
+* The DLL can free:
+* any hData EXCEPT those hDatas which are
+* APPOWNED where PIDcurrent == PIDowner.
+*
+* any unfreed logged hDatas are freed at unregistration time.
+*
+* The APP can free:
+* any logged hData.
+*
+* Logging points: ClientXfer return, CheckQueue return, PutData(APPOWNED).
+*
+* WARNING:
+*
+* Apps with multiple thread registration that talk to themselves
+* must not free hDatas until all threads are done with them.
+*
+\*/
+
+
+/***************************** Public Function ****************************\
+* PUBDOC START
+* HDDEDATA EXPENTRY DdeCreateDataHandle(pSrc, cb, cbOff, hszItem, wFmt, afCmd)
+* LPBYTE pSrc;
+* DWORD cb;
+* DWORD cbOff;
+* HSZ hszItem;
+* WORD wFmt;
+* WORD afCmd;
+*
+* This api allows a server application to create a hData apropriate
+* for return from its call-back function.
+* The passed in data is stored into the hData which is
+* returned on success. Any portions of the data handle not filled are
+* undefined. afCmd contains any of the HDATA_ constants described below:
+*
+* HDATA_APPOWNED
+* This declares the created data handle to be the responsability of
+* the application to free it. Application owned data handles may
+* be returned from the callback function multiple times. This allows
+* a server app to be able to support many clients without having to
+* recopy the data for each request.
+*
+* NOTES:
+* If an application expects this data handle to hold >64K of data via
+* DdeAddData(), it should specify a cb + cbOff to be as large as
+* the object is expected to get to avoid unnecessary data copying
+* or reallocation by the DLL.
+*
+* if psrc==NULL, no actual data copying takes place.
+*
+* Data handles given to an application via the DdeMgrClientXfer() or
+* DdeMgrCheckQueue() functions are the responsability of the client
+* application to free and MUST NOT be returned from the callback
+* function as server data!
+*
+* PUBDOC END
+*
+* History:
+* Created 12/14/88 Sanfords
+\***************************************************************************/
+HDDEDATA EXPENTRY DdeCreateDataHandle(
+DWORD idInst,
+LPBYTE pSrc,
+DWORD cb,
+DWORD cbOff,
+HSZ hszItem,
+UINT wFmt,
+UINT afCmd)
+{
+ PAPPINFO pai;
+ HDDEDATA hData;
+
+ TRACEAPIIN((szT, "DdeCreateDataHandle(%lx, %lx, %lx, %lx, %lx, %x, %x)\n",
+ idInst, pSrc, cb, cbOff, hszItem, wFmt, afCmd));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeCreateDataHandle:0\n"));
+ return(0);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (afCmd & ~(HDATA_APPOWNED)) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeCreateDataHandle:0\n"));
+ return(0L);
+ }
+
+ hData = PutData(pSrc, cb, cbOff, LOWORD(hszItem), wFmt, afCmd, pai);
+ if (hData) {
+ LPEXTDATAINFO pedi;
+
+ // use app heap so any leftovers at Uninitialize time go away.
+ pedi = (LPEXTDATAINFO)FarAllocMem(pai->hheapApp, sizeof(EXTDATAINFO));
+ if (pedi) {
+ pedi->pai = pai;
+ pedi->hData = hData;
+ }
+ hData = (HDDEDATA)(DWORD)pedi;
+ }
+ TRACEAPIOUT((szT, "DdeCreateDataHandle:%lx\n", hData));
+ return(hData);
+}
+
+
+
+
+HDDEDATA EXPENTRY DdeAddData(
+HDDEDATA hData,
+LPBYTE pSrc,
+DWORD cb,
+DWORD cbOff)
+{
+
+ PAPPINFO pai;
+ HDDEDATA FAR * phData;
+ DIP newDip;
+ HANDLE hd, hNewData;
+ LPEXTDATAINFO pedi;
+
+ TRACEAPIIN((szT, "DdeAddData(%lx, %lx, %lx, %lx)\n",
+ hData, pSrc, cb, cbOff));
+
+ if (!hData)
+ goto DdeAddDataError;
+
+ pedi = (LPEXTDATAINFO)hData;
+ pai = pedi->pai;
+ pai->LastError = DMLERR_NO_ERROR;
+ hData = pedi->hData;
+
+ /* if the datahandle is bogus, abort */
+ hd = hNewData = HIWORD(hData);
+ if (!hd || (LOWORD(hData) & HDATA_READONLY)) {
+DdeAddDataError:
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeAddData:0\n"));
+ return(0L);
+ }
+
+ /*
+ * we need this check in case the owning app is trying to reallocate
+ * after giving the hData away. (his copy of the handle would not have
+ * the READONLY flag set)
+ */
+ phData = (HDDEDATA FAR *)FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, 0);
+ if (!phData || LOWORD(*phData) & HDATA_READONLY) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeAddData:0\n"));
+ return(0L);
+ }
+
+ /* HACK ALERT!
+ * make sure the first two words req'd by windows dde is there,
+ * that is if the data isn't from an execute
+ */
+ if (!(LOWORD(hData) & HDATA_EXEC)) {
+ cbOff += 4L;
+ }
+ if (GlobalSize(hd) < cb + cbOff) {
+ /*
+ * need to grow the block before putting new data in...
+ */
+ if (!(hNewData = GLOBALREALLOC(hd, cb + cbOff, GMEM_MOVEABLE))) {
+ /*
+ * We can't grow the seg. Try allocating a new one.
+ */
+ if (!(hNewData = GLOBALALLOC(GMEM_MOVEABLE | GMEM_DDESHARE,
+ cb + cbOff))) {
+ /* failed.... die */
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ TRACEAPIOUT((szT, "DdeAddData:0\n"));
+ return(0);
+ } else {
+ /*
+ * got a new block, now copy data and trash old one
+ */
+ CopyHugeBlock(GLOBALPTR(hd), GLOBALPTR(hNewData), GlobalSize(hd));
+ GLOBALFREE(hd); // objects flow through - no need to free.
+ }
+ }
+ if (hNewData != hd) {
+ /* if the handle is different and in piles, update data piles */
+ if (FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE)) {
+ DIP *pDip;
+ HDDEDATA hdT;
+
+ // replace entry in global data info pile.
+
+ if (pDip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hd, 0)) {
+ newDip.hData = hNewData;
+ newDip.hTask = pDip->hTask;
+ newDip.cCount = pDip->cCount;
+ newDip.fFlags = pDip->fFlags;
+ FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hd, FPI_DELETE);
+ /* following assumes addpileitem will not fail...!!! */
+ AddPileItem(pDataInfoPile, (LPBYTE)&newDip, CmpWORD);
+ }
+ hdT = (HDDEDATA)MAKELONG(newDip.fFlags, hNewData);
+ AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, CmpHIWORD);
+
+ }
+ hData = MAKELONG(LOWORD(hData), hNewData);
+ }
+ }
+ if (pSrc) {
+ CopyHugeBlock(pSrc, HugeOffset(GLOBALLOCK(HIWORD(hData)), cbOff), cb);
+ }
+ pedi->hData = hData;
+ TRACEAPIOUT((szT, "DdeAddData:%lx\n", pedi));
+ return((HDDEDATA)pedi);
+}
+
+
+
+
+DWORD EXPENTRY DdeGetData(hData, pDst, cbMax, cbOff)
+HDDEDATA hData;
+LPBYTE pDst;
+DWORD cbMax;
+DWORD cbOff;
+{
+ PAPPINFO pai;
+ DWORD cbSize;
+ BOOL fExec = TRUE;
+
+ TRACEAPIIN((szT, "DdeGetData(%lx, %lx, %lx, %lx)\n",
+ hData, pDst, cbMax, cbOff));
+
+ //
+ // Check for NULL.
+ // Packard Bell Navigator passes NULL at startup. In 3.1 we'd
+ // maybe trash our local heap using ds:0. But now touching pai will
+ // fault since it's a far pointer and 0:0 is bad.
+ //
+ // Also makes your system stabler.
+ //
+ if (!hData)
+ goto DdeGetDataError;
+
+ pai = EXTRACTHDATAPAI(hData);
+ pai->LastError = DMLERR_NO_ERROR;
+ hData = ((LPEXTDATAINFO)hData)->hData;
+ cbSize = GlobalSize(HIWORD(hData));
+
+ /* HACK ALERT!
+ * make sure the first two words req'd by windows dde is there,
+ * as long as it's not execute data
+ */
+ if (!(LOWORD(hData) & HDATA_EXEC)) {
+ cbOff += 4;
+ fExec = FALSE;
+ }
+
+ if (cbOff >= cbSize)
+ {
+DdeGetDataError:
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeGetData:0\n"));
+ return(0L);
+ }
+
+ cbMax = min(cbMax, cbSize - cbOff);
+ if (pDst == NULL) {
+ TRACEAPIOUT((szT, "DdeGetData:%lx\n", fExec ? cbSize : cbSize - 4));
+ return(fExec ? cbSize : cbSize - 4);
+ } else {
+ CopyHugeBlock(HugeOffset(GLOBALLOCK(HIWORD(hData)), cbOff),
+ pDst, cbMax);
+ TRACEAPIOUT((szT, "DdeGetData:%lx\n", cbMax));
+ return(cbMax);
+ }
+}
+
+
+
+LPBYTE EXPENTRY DdeAccessData(
+HDDEDATA hData,
+LPDWORD pcbDataSize)
+{
+ PAPPINFO pai;
+ DWORD offset;
+ LPBYTE lpRet;
+
+ TRACEAPIIN((szT, "DdeAccessData(%lx, %lx)\n",
+ hData, pcbDataSize));
+
+ if (!hData)
+ goto DdeAccessDataError;
+
+ pai = EXTRACTHDATAPAI(hData);
+ pai->LastError = DMLERR_NO_ERROR;
+ hData = ((LPEXTDATAINFO)hData)->hData;
+
+ if (HIWORD(hData) && (HIWORD(hData) != 0xFFFF) ) {
+ /* screw around here getting past the first two words, which
+ * aren't even there if this is execute data
+ */
+ offset = (LOWORD(hData) & HDATA_EXEC) ? 0L : 4L;
+ if (pcbDataSize) {
+ *pcbDataSize = GlobalSize(HIWORD(hData)) - offset;
+ }
+ lpRet = (LPBYTE)GLOBALLOCK(HIWORD(hData)) + offset;
+ TRACEAPIOUT((szT, "DdeAccessData:%lx\n", lpRet));
+ return(lpRet);
+ }
+
+DdeAccessDataError:
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeAccessData:0\n"));
+ return(0L);
+}
+
+
+
+
+BOOL EXPENTRY DdeUnaccessData(
+HDDEDATA hData)
+{
+ PAPPINFO pai;
+
+ TRACEAPIIN((szT, "DdeUnaccessData(%lx)\n", hData));
+
+ //
+ // BOGUS -- we should set last error and RIP also.
+ //
+ if (hData)
+ {
+ pai = EXTRACTHDATAPAI(hData);
+ pai->LastError = DMLERR_NO_ERROR;
+ }
+ TRACEAPIOUT((szT, "DdeUnaccessData:1\n"));
+ return(TRUE);
+}
+
+
+// Diamond Multimedia Kit 5000 creates a non-app-owned data handle,
+// uses it in a client transaction (which free's it) and then
+// calls DDEFreeDataHandle which can fault (depending on what junk
+// gets left behind). To handle this we validate the data handle
+// before doing anything else.
+BOOL HDdeData_Validate(HDDEDATA hData)
+{
+ WORD wSaveDS;
+ UINT nRet;
+
+ wSaveDS = SwitchDS(HIWORD(hData));
+
+ // Use the validation layer to check the handle
+ // We can call LocalSize with the near ptr as the handle because:
+ // 1. The HDDEDATA was allocated with LPTR (LMEM_FIXED | LMEM_ZEROINIT)
+ // 2. Local mem that is alloc'd LMEM_FIXED, the offset is the handle
+ // 3. We don't want to call LocalHandle to get the handle because it has
+ // no parameter vailidation & blows up for bad handles
+ nRet = LocalSize((HANDLE)LOWORD(hData));
+
+ SwitchDS(wSaveDS);
+
+#ifdef DEBUG
+ if (!nRet) {
+ OutputDebugString("DDEML: Invalid HDDEDATA.\n\r");
+ }
+#endif
+
+ return nRet;
+}
+
+BOOL EXPENTRY DdeFreeDataHandle(
+HDDEDATA hData)
+{
+ PAPPINFO pai;
+ LPEXTDATAINFO pedi;
+
+ TRACEAPIIN((szT, "DdeFreeDataHandle(%lx)\n", hData));
+
+ pedi = (LPEXTDATAINFO)hData;
+
+ if ( !pedi || !HDdeData_Validate(hData) ) {
+ TRACEAPIOUT((szT, "DdeFreeDataHandle:1\n"));
+ return(TRUE);
+ }
+
+ pai = EXTRACTHDATAPAI(hData);
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (!(LOWORD(pedi->hData) & HDATA_NOAPPFREE)) {
+ FreeDataHandle(pedi->pai, pedi->hData, FALSE);
+ FarFreeMem((LPSTR)pedi);
+ }
+
+ TRACEAPIOUT((szT, "DdeFreeDataHandle:1\n"));
+ return(TRUE);
+}
+
+
+
+
+/***************************************************************************\
+* PUBDOC START
+* HSZ management notes:
+*
+* HSZs are used in this DLL to simplify string handling for applications
+* and for inter-process communication. Since many applications use a
+* fixed set of Application/Topic/Item names, it is convenient to convert
+* them to HSZs and allow quick comparisons for lookups. This also frees
+* the DLL up from having to constantly provide string buffers for copying
+* strings between itself and its clients.
+*
+* HSZs are the same as atoms except they have no restrictions on length or
+* number and are 32 bit values. They are case preserving and can be
+* compared directly for case sensitive comparisons or via DdeCmpStringHandles()
+* for case insensitive comparisons.
+*
+* When an application creates an HSZ via DdeCreateStringHandle() or increments its
+* count via DdeKeepStringHandle() it is essentially claiming the HSZ for
+* its own use. On the other hand, when an application is given an
+* HSZ from the DLL via a callback, it is using another application's HSZ
+* and should not free that HSZ via DdeFreeStringHandle().
+*
+* The DLL insures that during the callback any HSZs given will remain
+* valid for the duration of the callback.
+*
+* If an application wishes to keep that HSZ to use for itself as a
+* standard for future comparisons, it should increment its count so that,
+* should the owning application free it, the HSZ will not become invalid.
+* This also prevents an HSZ from changing its value. (ie, app A frees it
+* and then app B creates a new one that happens to use the same HSZ code,
+* then app C, which had the HSZ stored all along (but forgot to increment
+* its count) now is holding a handle to a different string.)
+*
+* Applications may free HSZs they have created or incremented at any time
+* by calling DdeFreeStringHandle().
+*
+* The DLL internally increments HSZ counts while in use so that they will
+* not be destroyed until both the DLL and all applications concerned are
+* through with them.
+*
+* IT IS THE APPLICATIONS RESPONSIBILITY TO PROPERLY CREATE AND FREE HSZs!!
+*
+* PUBDOC END
+\***************************************************************************/
+
+
+HSZ EXPENTRY DdeCreateStringHandle(
+DWORD idInst,
+LPCSTR psz,
+int iCodePage)
+{
+#define pai ((PAPPINFO)idInst)
+ ATOM a;
+
+ TRACEAPIIN((szT, "DdeCreateStringHandle(%lx, %s, %x)\n",
+ idInst, psz, iCodePage));
+
+ if (pai == NULL | pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
+ return(0);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (psz == NULL || *psz == '\0') {
+ TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
+ return(0);
+ }
+ if (iCodePage == 0 || iCodePage == CP_WINANSI || iCodePage == GetKBCodePage()) {
+ SEMENTER();
+ a = FindAddHsz((LPSTR)psz, TRUE);
+ SEMLEAVE();
+
+ MONHSZ(a, MH_CREATE, pai->hTask);
+ if (AddPileItem(pai->pHszPile, (LPBYTE)&a, NULL) == API_ERROR) {
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ a = 0;
+ }
+ TRACEAPIOUT((szT, "DdeCreateStringHandle:%x\n", a));
+ return((HSZ)a);
+ } else {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeCreateStringHandle:0\n"));
+ return(0);
+ }
+#undef pai
+}
+
+
+
+BOOL EXPENTRY DdeFreeStringHandle(
+DWORD idInst,
+HSZ hsz)
+{
+ PAPPINFO pai;
+ ATOM a = LOWORD(hsz);
+ BOOL fRet;
+
+ TRACEAPIIN((szT, "DdeFreeStringHandle(%lx, %lx)\n",
+ idInst, hsz));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeFreeStringHandle:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ MONHSZ(a, MH_DELETE, pai->hTask);
+ FindPileItem(pai->pHszPile, CmpWORD, (LPBYTE)&a, FPI_DELETE);
+ fRet = FreeHsz(a);
+ TRACEAPIOUT((szT, "DdeFreeStringHandle:%x\n", fRet));
+ return(fRet);
+}
+
+
+
+BOOL EXPENTRY DdeKeepStringHandle(
+DWORD idInst,
+HSZ hsz)
+{
+ PAPPINFO pai;
+ ATOM a = LOWORD(hsz);
+ BOOL fRet;
+
+ TRACEAPIIN((szT, "DdeKeepStringHandle(%lx, %lx)\n",
+ idInst, hsz));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeKeepStringHandle:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+ MONHSZ(a, MH_KEEP, pai->hTask);
+ AddPileItem(pai->pHszPile, (LPBYTE)&a, NULL);
+ fRet = IncHszCount(a);
+ TRACEAPIOUT((szT, "DdeKeepStringHandle:%x\n", fRet));
+ return(fRet);
+}
+
+
+
+
+
+DWORD EXPENTRY DdeQueryString(
+DWORD idInst,
+HSZ hsz,
+LPSTR psz,
+DWORD cchMax,
+int iCodePage)
+{
+ PAPPINFO pai;
+ DWORD dwRet;
+
+ TRACEAPIIN((szT, "DdeQueryString(%lx, %lx, %lx, %lx, %x)\n",
+ idInst, hsz, psz, cchMax, iCodePage));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeQueryString:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (iCodePage == 0 || iCodePage == CP_WINANSI || iCodePage == GetKBCodePage()) {
+ if (psz) {
+ if (hsz) {
+ dwRet = QueryHszName(hsz, psz, (WORD)cchMax);
+ TRACEAPIOUT((szT, "DdeQueryString:%lx(%s)\n", dwRet, psz));
+ return(dwRet);
+ } else {
+ *psz = '\0';
+ TRACEAPIOUT((szT, "DdeQueryString:0\n"));
+ return(0);
+ }
+ } else if (hsz) {
+ dwRet = QueryHszLength(hsz);
+ TRACEAPIOUT((szT, "DdeQueryString:%lx\n", dwRet));
+ return(dwRet);
+ } else {
+ TRACEAPIOUT((szT, "DdeQueryString:0\n"));
+ return(0);
+ }
+ } else {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeQueryString:0\n"));
+ return(0);
+ }
+}
+
+
+
+int EXPENTRY DdeCmpStringHandles(
+HSZ hsz1,
+HSZ hsz2)
+{
+ int iRet;
+
+ TRACEAPIIN((szT, "DdeCmpStringHandles(%lx, %lx)\n",
+ hsz1, hsz2));
+
+ if (hsz2 > hsz1) {
+ iRet = -1;
+ } else if (hsz2 < hsz1) {
+ iRet = 1;
+ } else {
+ iRet = 0;
+ }
+ TRACEAPIOUT((szT, "DdeCmpStringHandles:%x\n", iRet));
+ return(iRet);
+}
+
+
+
+
+BOOL EXPENTRY DdeAbandonTransaction(
+DWORD idInst,
+HCONV hConv,
+DWORD idTransaction)
+{
+ PAPPINFO pai;
+
+ TRACEAPIIN((szT, "DdeAbandonTransaction(%lx, %lx, %lx)\n",
+ idInst, hConv, idTransaction));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeAbandonTransaction:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if ((hConv && !ValidateHConv(hConv)) || idTransaction == QID_SYNC) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeAbandonTransaction:0\n"));
+ return(FALSE);
+ }
+ if (hConv == NULL) {
+
+ // do all conversations!
+
+ register HWND hwnd;
+ register HWND hwndLast;
+
+ if (!(hwnd = GetWindow(pai->hwndDmg, GW_CHILD))) {
+ TRACEAPIOUT((szT, "DdeAbandonTransaction:1\n"));
+ return(TRUE);
+ }
+ hwndLast = GetWindow(hwnd, GW_HWNDLAST);
+ do {
+ AbandonTransaction(hwnd, pai, idTransaction, TRUE);
+ if (hwnd == hwndLast) {
+ break;
+ }
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+ } while (TRUE);
+ } else {
+ BOOL fRet;
+
+ fRet = AbandonTransaction((HWND)hConv, pai, idTransaction, TRUE);
+ TRACEAPIOUT((szT, "DdeAbandonTransaction:%x\n", fRet));
+ return(fRet);
+ }
+ TRACEAPIOUT((szT, "DdeAbandonTransaction:1\n"));
+ return(TRUE);
+}
+
+
+
+BOOL AbandonTransaction(
+HWND hwnd,
+PAPPINFO pai,
+DWORD id,
+BOOL fMarkOnly)
+{
+ PCLIENTINFO pci;
+ PCQDATA pcqd;
+ WORD err;
+
+
+ SEMCHECKOUT();
+ SEMENTER();
+
+ pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
+
+ if (!pci->ci.fs & ST_CLIENT) {
+ err = DMLERR_INVALIDPARAMETER;
+failExit:
+ SETLASTERROR(pai, err);
+ SEMLEAVE();
+ SEMCHECKOUT();
+ return(FALSE);
+ }
+
+ do {
+ /*
+ * HACK: id == 0 -> all ids so we cycle
+ */
+ pcqd = (PCQDATA)Findqi(pci->pQ, id);
+
+ if (!pcqd) {
+ if (id) {
+ err = DMLERR_UNFOUND_QUEUE_ID;
+ goto failExit;
+ }
+ break;
+ }
+ if (fMarkOnly) {
+ pcqd->xad.fAbandoned = TRUE;
+ if (!id) {
+ while (pcqd = (PCQDATA)FindNextQi(pci->pQ, (PQUEUEITEM)pcqd,
+ FALSE)) {
+ pcqd->xad.fAbandoned = TRUE;
+ }
+ break;
+ }
+ } else {
+ if (pcqd->xad.pdata && pcqd->xad.pdata != 1 &&
+ !FindPileItem(pai->pHDataPile, CmpHIWORD,
+ (LPBYTE)&pcqd->xad.pdata, 0)) {
+
+ FreeDDEData(LOWORD(pcqd->xad.pdata), pcqd->xad.pXferInfo->wFmt);
+ }
+
+ /*
+ * Decrement the use count we incremented when the client started
+ * this transaction.
+ */
+ FreeHsz(LOWORD(pcqd->XferInfo.hszItem));
+ Deleteqi(pci->pQ, MAKEID(pcqd));
+ }
+
+ } while (!id);
+
+ SEMLEAVE();
+ SEMCHECKOUT();
+ return(TRUE);
+}
+
+
+
+BOOL EXPENTRY DdeEnableCallback(
+DWORD idInst,
+HCONV hConv,
+UINT wCmd)
+{
+ PAPPINFO pai;
+ BOOL fRet;
+
+ TRACEAPIIN((szT, "DdeEnableCallback(%lx, %lx, %x)\n",
+ idInst, hConv, wCmd));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if ((hConv && !ValidateHConv(hConv)) ||
+ (wCmd & ~(EC_ENABLEONE | EC_ENABLEALL |
+ EC_DISABLE | EC_QUERYWAITING))) {
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
+ return(FALSE);
+ }
+
+ SEMCHECKOUT();
+
+ if (wCmd & EC_QUERYWAITING) {
+ PCBLI pli;
+ int cWaiting = 0;
+
+ SEMENTER();
+ for (pli = (PCBLI)pai->plstCB->pItemFirst;
+ pli && cWaiting < 2;
+ pli = (PCBLI)pli->next) {
+ if (hConv || pli->hConv == hConv) {
+ cWaiting++;
+ }
+ }
+ SEMLEAVE();
+ fRet = cWaiting > 1 || (cWaiting == 1 && pai->cInProcess == 0);
+ TRACEAPIOUT((szT, "DdeEnableCallback:%x\n", fRet));
+ return(fRet);
+ }
+
+ /*
+ * We depend on the fact that EC_ constants relate to ST_ constants.
+ */
+ if (hConv == NULL) {
+ if (wCmd & EC_DISABLE) {
+ pai->wFlags |= AWF_DEFCREATESTATE;
+ } else {
+ pai->wFlags &= ~AWF_DEFCREATESTATE;
+ }
+ ChildMsg(pai->hwndDmg, UM_SETBLOCK, wCmd, 0, FALSE);
+ } else {
+ SendMessage((HWND)hConv, UM_SETBLOCK, wCmd, 0);
+ }
+
+ if (!(wCmd & EC_DISABLE)) {
+
+ // This is synchronous! Fail if we made this from within a callback.
+
+ if (pai->cInProcess) {
+ SETLASTERROR(pai, DMLERR_REENTRANCY);
+ TRACEAPIOUT((szT, "DdeEnableCallback:0\n"));
+ return(FALSE);
+ }
+
+ SendMessage(pai->hwndDmg, UM_CHECKCBQ, 0, (DWORD)(LPSTR)pai);
+ }
+
+ TRACEAPIOUT((szT, "DdeEnableCallback:1\n"));
+ return(TRUE); // TRUE implies the callback queue is free of unblocked calls.
+}
+
+
+
+HDDEDATA EXPENTRY DdeNameService(
+DWORD idInst,
+HSZ hsz1,
+HSZ hsz2,
+UINT afCmd)
+{
+ PAPPINFO pai;
+ PPILE panp;
+
+ TRACEAPIIN((szT, "DdeNameService(%lx, %lx, %lx, %x)\n",
+ idInst, hsz1, hsz2, afCmd));
+
+ pai = (PAPPINFO)idInst;
+ if (pai == NULL || pai->instCheck != HIWORD(idInst)) {
+ TRACEAPIOUT((szT, "DdeNameService:0\n"));
+ return(FALSE);
+ }
+ pai->LastError = DMLERR_NO_ERROR;
+
+ if (afCmd & DNS_FILTERON) {
+ pai->afCmd |= APPCMD_FILTERINITS;
+ }
+
+ if (afCmd & DNS_FILTEROFF) {
+ pai->afCmd &= ~APPCMD_FILTERINITS;
+ }
+
+ if (afCmd & (DNS_REGISTER | DNS_UNREGISTER)) {
+
+ if (pai->afCmd & APPCMD_CLIENTONLY) {
+ SETLASTERROR(pai, DMLERR_DLL_USAGE);
+ TRACEAPIOUT((szT, "DdeNameService:0\n"));
+ return(FALSE);
+ }
+
+ panp = pai->pAppNamePile;
+
+ if (hsz1 == NULL) {
+ if (afCmd & DNS_REGISTER) {
+ /*
+ * registering NULL is not allowed!
+ */
+ SETLASTERROR(pai, DMLERR_INVALIDPARAMETER);
+ TRACEAPIOUT((szT, "DdeNameService:0\n"));
+ return(FALSE);
+ }
+ /*
+ * unregistering NULL is just like unregistering each
+ * registered name.
+ *
+ * 10/19/90 - made this a synchronous event so that hsz
+ * can be freed by calling app after this call completes
+ * without us having to keep a copy around forever.
+ */
+ while (PopPileSubitem(panp, (LPBYTE)&hsz1)) {
+ RegisterService(FALSE, (GATOM)hsz1, pai->hwndFrame);
+ FreeHsz(LOWORD(hsz1));
+ }
+ TRACEAPIOUT((szT, "DdeNameService:1\n"));
+ return(TRUE);
+ }
+
+ if (afCmd & DNS_REGISTER) {
+ if (panp == NULL) {
+ panp = pai->pAppNamePile =
+ CreatePile(pai->hheapApp, sizeof(HSZ), 8);
+ }
+ IncHszCount(LOWORD(hsz1));
+ AddPileItem(panp, (LPBYTE)&hsz1, NULL);
+ } else { // DNS_UNREGISTER
+ FindPileItem(panp, CmpDWORD, (LPBYTE)&hsz1, FPI_DELETE);
+ }
+ // see 10/19/90 note above.
+ RegisterService(afCmd & DNS_REGISTER ? TRUE : FALSE, (GATOM)hsz1,
+ pai->hwndFrame);
+
+ if (afCmd & DNS_UNREGISTER) {
+ FreeHsz(LOWORD(hsz1));
+ }
+
+ TRACEAPIOUT((szT, "DdeNameService:1\n"));
+ return(TRUE);
+ }
+ TRACEAPIOUT((szT, "DdeNameService:0\n"));
+ return(0L);
+}
diff --git a/private/mvdm/wow16/ddeml/ddeml.def b/private/mvdm/wow16/ddeml/ddeml.def
new file mode 100644
index 000000000..296ebba22
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/ddeml.def
@@ -0,0 +1,60 @@
+
+LIBRARY DDEML
+
+DESCRIPTION 'DDE Manager Library'
+
+DATA MOVEABLE SINGLE PRELOAD
+CODE MOVEABLE DISCARDABLE
+
+SEGMENTS
+ INIT_TEXT CLASS 'CODE' PRELOAD
+ _TEXT CLASS 'CODE'
+
+EXETYPE WINDOWS PROTMODE
+
+HEAPSIZE 512
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+ DDEINITIALIZE @2
+ DDEUNINITIALIZE @3
+ DDECONNECTLIST @4
+ DDEQUERYNEXTSERVER @5
+ DDEDISCONNECTLIST @6
+ DDECONNECT @7
+ DDEDISCONNECT @8
+ DDEQUERYCONVINFO @9
+ DDESETUSERHANDLE @10
+ DDECLIENTTRANSACTION @11
+ DDEABANDONTRANSACTION @12
+ DDEPOSTADVISE @13
+ DDECREATEDATAHANDLE @14
+ DDEADDDATA @15
+ DDEGETDATA @16
+ DDEACCESSDATA @17
+ DDEUNACCESSDATA @18
+ DDEFREEDATAHANDLE @19
+ DDEGETLASTERROR @20
+ DDECREATESTRINGHANDLE @21
+ DDEFREESTRINGHANDLE @22
+ DDEQUERYSTRING @23
+ DDEKEEPSTRINGHANDLE @24
+
+ DDEENABLECALLBACK @26
+ DDENAMESERVICE @27
+
+ CLIENTWNDPROC @28 ;Internal
+ SERVERWNDPROC @29 ;Internal
+ SUBFRAMEWNDPROC @30 ;Internal
+ DMGWNDPROC @31 ;Internal
+ CONVLISTWNDPROC @32 ;Internal
+ MONITORWNDPROC @33 ;Internal
+ DDESENDHOOKPROC @34 ;Internal
+ DDEPOSTHOOKPROC @35 ;Internal
+
+ DDECMPSTRINGHANDLES @36
+ DDERECONNECT @37
+
+ INITENUM @38 ;Internal
+ TERMDLGPROC @39 ;Internal
+ EmptyQTimerProc @40 ;Internal
diff --git a/private/mvdm/wow16/ddeml/ddemlp.h b/private/mvdm/wow16/ddeml/ddemlp.h
new file mode 100644
index 000000000..41a9d3b4b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/ddemlp.h
@@ -0,0 +1,727 @@
+/****************************** Module Header ******************************\
+* Module Name: DDEMLP.H
+*
+* Private header for DDE manager DLL.
+*
+* Created: 12/16/88 by Sanford Staab
+* Modified for Win 3.0: 5/31/90 by Rich Gartland, Aldus
+* Cleaned up: 11/14/90 Sanford Staab
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+* Copyright (c) 1990 Aldus Corporation
+\***************************************************************************/
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOKEYSTATES
+#define OEMRESOURCE
+#define NOCOLOR
+// #define NOCTLMGR
+#define NODRAWTEXT
+// #define NOMETAFILE
+#define NOMINMAX
+#define NOSCROLL
+#define NOSOUND
+#define NOCOMM
+#define NOKANJI
+#define NOHELP
+#define NOPROFILER
+
+
+#include <windows.h>
+#include <dde.h>
+
+#define DDEMLDB
+#include <ddeml.h>
+
+#ifdef DEBUG
+extern int bDbgFlags;
+#define DBF_STOPONTRACE 0x01
+#define DBF_TRACETERM 0x02
+#define DBF_LOGALLOCS 0x04
+#define DBF_TRACEATOMS 0x08
+#define DBF_TRACEAPI 0x10
+
+#define TRACETERM(x) if (bDbgFlags & DBF_TRACETERM) { \
+ char szT[100]; \
+ wsprintf##x; \
+ OutputDebugString(szT); \
+ if (bDbgFlags & DBF_STOPONTRACE) { \
+ DebugBreak(); \
+ } \
+}
+#define TRACETERMBREAK(x) if (bDbgFlags & DBF_TRACETERM) { \
+ char szT[100]; \
+ wsprintf##x; \
+ OutputDebugString(szT); \
+ DebugBreak(); \
+}
+
+VOID TraceApiIn(LPSTR psz);
+#define TRACEAPIIN(x) if (bDbgFlags & DBF_TRACEAPI) { \
+ char szT[100]; \
+ wsprintf##x; \
+ TraceApiIn(szT); \
+}
+
+VOID TraceApiOut(LPSTR psz);
+#define TRACEAPIOUT(x) if (bDbgFlags & DBF_TRACEAPI) { \
+ char szT[100]; \
+ wsprintf##x; \
+ TraceApiOut(szT); \
+}
+#else
+#define TRACETERM(x)
+#define TRACETERMBREAK(x)
+#define TRACEAPIIN(x)
+#define TRACEAPIOUT(x)
+#endif
+
+// PRIVATE CONSTANTS
+
+#define CBF_MASK 0x003ff000L
+#define CBF_MONMASK 0x0027f000L
+
+#define ST_TERM_WAITING 0x8000
+#define ST_NOTIFYONDEATH 0x4000
+#define ST_PERM2DIE 0x2000
+#define ST_IM_DEAD 0x1000
+#define ST_DISC_ATTEMPTED 0x0800
+#define ST_CHECKPARTNER 0x0400
+
+#define DDEFMT_TEXT CF_TEXT
+
+#define TID_TIMEOUT 1
+#define TID_SHUTDOWN 2
+#define TID_EMPTYPOSTQ 4
+
+#define TIMEOUT_QUEUECHECK 200
+
+//
+// values for pai->wTimeoutStatus
+//
+#define TOS_CLEAR 0x00
+#define TOS_TICK 0x01
+#define TOS_ABORT 0x02
+#define TOS_DONE 0x80
+
+#define GWL_PCI 0 // ties conv windows to data.
+#define GWW_PAI 0 // other windows have pai here.
+#define GWW_CHECKVAL 4 // for verification of hwnds.
+#define GWW_STATE 6 // conv list state
+
+#define MH_INTCREATE 5
+#define MH_INTKEEP 6
+#define MH_INTDELETE 7
+
+// MACROS
+
+#define MAKEHCONV(hwnd) (IsWindow(hwnd) ? hwnd | ((DWORD)GetWindowWord(hwnd, GWW_CHECKVAL) << 16) : 0)
+#define UNUSED
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#define PHMEM(hData) ((LPBYTE)&((LPWORD)&(hData))[1])
+#define MONHSZ(a, fsAction, hTask) if (cMonitor) MonHsz(a, fsAction, hTask)
+#define MONERROR(pai, e) MonError(pai, e)
+#define MONLINK(pai, fEst, fNoData, hszSvc, hszTopic, hszItem, wFmt, fServer, hConvS, hConvC) \
+ if (cMonitor) \
+ MonLink(pai, fEst, fNoData, hszSvc, hszTopic, \
+ hszItem, wFmt, fServer, hConvS, hConvC)
+#define MONCONN(pai, hszSvcInst, hszTopic, hwndC, hwndS, fConnect) \
+ if (cMonitor) \
+ MonConn(pai, hszSvcInst, hszTopic, hwndC, hwndS, fConnect)
+
+#define SETLASTERROR(pai, e) MonError(pai, e)
+#define SEMCHECKIN()
+#define SEMCHECKOUT()
+#define SEMENTER()
+#define SEMLEAVE()
+#define SEMINIT()
+
+#ifdef DEBUG
+
+VOID _loadds fAssert(BOOL f, LPSTR psz, WORD line, LPSTR szFile, BOOL fWarning);
+#define AssertF(f, psz) fAssert(f, psz, __LINE__, __FILE__, FALSE);
+#define AssertFW(f, psz) fAssert(f, psz, __LINE__, __FILE__, TRUE);
+#define DEBUGBREAK() DebugBreak()
+#define GLOBALREALLOC LogGlobalReAlloc
+#define GLOBALALLOC LogGlobalAlloc
+#define GLOBALFREE LogGlobalFree
+#define GLOBALLOCK LogGlobalLock
+#define GLOBALUNLOCK LogGlobalUnlock
+#include "heapwach.h"
+
+#else
+
+#define AssertF(f, psz)
+#define AssertFW(f, psz)
+#define DEBUGBREAK()
+#define GLOBALREALLOC GlobalReAlloc
+#define GLOBALALLOC GlobalAlloc
+#define GLOBALFREE GlobalFree
+#define GLOBALLOCK GlobalLock
+#define GLOBALUNLOCK GlobalUnlock
+
+#endif /* DEBUG */
+#define GLOBALPTR(h) (LPVOID)MAKELONG(0,h)
+
+
+typedef ATOM GATOM;
+typedef ATOM LATOM;
+
+// -------------- LISTS --------------
+
+
+typedef struct _LITEM { // generic list item
+ struct _LITEM FAR *next;
+} LITEM;
+typedef LITEM FAR *PLITEM;
+
+typedef struct _LST { // generic list header
+ PLITEM pItemFirst;
+ HANDLE hheap;
+ WORD cbItem;
+} LST;
+typedef LST FAR *PLST;
+
+#define ILST_LAST 0x0000 // flags for list lookups
+#define ILST_FIRST 0x0001
+#define ILST_NOLINK 0x0002
+
+
+typedef struct _HSZLI { // HSZ list item
+ PLITEM next;
+ ATOM a;
+} HSZLI;
+
+typedef struct _HWNDLI { // HWND list item
+ PLITEM next;
+ HWND hwnd;
+} HWNDLI;
+
+typedef struct _ACKHWNDLI { // extra ACK list item
+ PLITEM next;
+ HWND hwnd; // same as HWNDLI to here
+ HSZ hszSvc;
+ HSZ aTopic;
+} ACKHWNDLI;
+
+typedef struct _HWNDHSZLI { // HWND-HSZ pair list item
+ PLITEM next;
+ ATOM a; // same as HSZLI to here
+ HWND hwnd;
+} HWNDHSZLI;
+typedef HWNDHSZLI FAR *PHWNDHSZLI;
+
+typedef struct _ADVLI { // ADVISE loop list item
+ PLITEM next;
+ ATOM aItem; // same as HSZLI to here
+ ATOM aTopic;
+ WORD wFmt;
+ WORD fsStatus; // used to remember NODATA and FACKREQ state */
+ HWND hwnd; // hwnd that has advise loop
+} ADVLI;
+typedef ADVLI FAR *PADVLI;
+
+
+
+// ------------ PILES -------------
+
+
+typedef struct _PILEB { // generic pile block header
+ struct _PILEB FAR *next; // same as LITEM structure
+ WORD cItems;
+ WORD reserved;
+} PILEB;
+typedef PILEB FAR *PPILEB;
+
+typedef struct PILE { // generic pile header
+ PPILEB pBlockFirst;
+ HANDLE hheap;
+ WORD cbBlock; // same as LST structure
+ WORD cSubItemsMax;
+ WORD cbSubItem;
+} PILE;
+typedef PILE FAR *PPILE;
+
+typedef BOOL (*NPFNCMP)(LPBYTE, LPBYTE); // item comparison function pointer
+
+#define PTOPPILEITEM(p) ((LPBYTE)p->pBlockFirst + sizeof(PILEB))
+
+#define FPI_DELETE 0x1 // pile search flags
+#define FPI_COUNT 0x2
+
+#define API_ADDED 1 // AddPileItem flags
+#define API_FOUND 2
+#define API_ERROR 0
+
+typedef struct _DIP { /* Data handle tracking pile */
+ HANDLE hData; /* the handle to the data */
+ HANDLE hTask; /* task owning the data */
+ WORD cCount; /* use count = # datapiles using the handle */
+ WORD fFlags; /* readonly, etc. */
+} DIP;
+
+
+typedef struct _LAP { /* Lost Ack Pile item */
+ WORD object; /* either a handle or an atom */
+ WORD type; /* transaction type the ack was meant for */
+} LAP;
+
+
+/*
+ * These bits are used to keep track of advise loop states.
+ */
+#define ADVST_WAITING 0x0080 /* fReserved bit - set if still waiting for FACK */
+#define ADVST_CHANGED 0x0040 /* fReserved bit - set if data changed while waiting */
+
+
+
+// ------------ QUEUES -------------
+
+
+typedef struct _QUEUEITEM { // generic queue item
+ struct _QUEUEITEM FAR *next;
+ struct _QUEUEITEM FAR *prev;
+ WORD inst;
+} QUEUEITEM;
+typedef QUEUEITEM FAR *PQUEUEITEM;
+
+typedef struct _QST { // generic queue header
+ WORD cItems;
+ WORD instLast;
+ WORD cbItem;
+ HANDLE hheap;
+ PQUEUEITEM pqiHead;
+} QST;
+typedef QST FAR *PQST;
+
+#define MAKEID(pqd) (LOWORD((DWORD)pqd) + ((DWORD)((pqd)->inst) << 16))
+#define PFROMID(pQ, id) ((PQUEUEITEM)MAKELONG(LOWORD(id), HIWORD(pQ)))
+
+#define QID_NEWEST -2L
+#define QID_OLDEST 0L
+
+
+// ------------- STRUCTURES -------------
+
+typedef struct _PMQI { // post message queue
+ PQUEUEITEM FAR *next;
+ PQUEUEITEM FAR *prev;
+ WORD inst; // same as QUEUEITEM to here!
+ WORD msg;
+ LONG lParam;
+ WORD wParam;
+ HWND hwndTo;
+ HGLOBAL hAssoc;
+ WORD msgAssoc;
+} PMQI;
+typedef PMQI FAR *PPMQI;
+
+typedef struct _MQL { // message queue list
+ struct _MQL FAR*next;
+ HANDLE hTaskTo;
+ PQST pMQ;
+} MQL, FAR *LPMQL;
+
+typedef struct _XFERINFO { // DdeClientTransaction parameters reversed!!!
+ LPDWORD pulResult; // sync->flags, async->ID
+ DWORD ulTimeout;
+ WORD wType;
+ WORD wFmt;
+ HSZ hszItem;
+ HCONV hConvClient;
+ DWORD cbData;
+ HDDEDATA hDataClient;
+} XFERINFO;
+typedef XFERINFO FAR *PXFERINFO;
+
+typedef struct _XADATA { // internal transaction specif info
+ WORD state; // state of this transaction (XST_)
+ WORD LastError; // last error logged in this transaction
+ DWORD hUser; // set with DdeSetUserHandle
+ PXFERINFO pXferInfo; // associated transaction info
+ DWORD pdata; // data for the client from the server
+ WORD DDEflags; // DDE flags resulting from transaction
+ BOOL fAbandoned; // set if this transaction is abandoned.
+} XADATA;
+typedef XADATA FAR *PXADATA;
+
+typedef struct _CQDATA { // Client transaction queue
+ PQUEUEITEM FAR *next;
+ PQUEUEITEM FAR *prev;
+ WORD inst;
+ XADATA xad;
+ XFERINFO XferInfo;
+} CQDATA;
+typedef CQDATA FAR *PCQDATA;
+
+typedef struct _APPINFO { // App wide information
+ struct _APPINFO *next; // local heap object
+ WORD cZombies; // number of hwnd's awaiting terminates
+ PFNCALLBACK pfnCallback; // callback address
+ PPILE pAppNamePile; // registered service names list
+ PPILE pHDataPile; // data handles not freed
+ PPILE pHszPile; // hsz cleanup tracking pile.
+ HWND hwndSvrRoot; // root of all server windows.
+ PLST plstCB; // callback queue
+ DWORD afCmd; // app filter and command flags
+ HANDLE hTask; // app task
+ HANDLE hheapApp; // app heap
+ HWND hwndDmg; // main app window
+ HWND hwndFrame; // main app initiate window
+ HWND hwndMonitor; // monitor window
+ HWND hwndTimer; // current timer window
+ WORD LastError; // last error
+ WORD wFlags; // set to ST_BLOCKED or not.
+ WORD cInProcess; // recursion guard
+ WORD instCheck; // to validate idInst param.
+ PLST pServerAdvList; // active ADVISE loops for servers
+ LPSTR lpMemReserve; // reserve memory in case of crunch
+ WORD wTimeoutStatus; // used to alert timeout modal loop
+} APPINFO;
+typedef APPINFO *PAPPINFO; // local heap object
+typedef APPINFO FAR *LPAPPINFO;
+typedef PAPPINFO FAR *LPPAPPINFO;
+
+#define LPCREATESTRUCT_GETPAI(lpcs) (*((LPPAPPINFO)(((LPCREATESTRUCT)lpcs)->lpCreateParams)))
+
+// defines for wFlags field
+
+#define AWF_DEFCREATESTATE 0x0001
+#define AWF_INSYNCTRANSACTION 0x0002
+#define AWF_UNINITCALLED 0x0004
+#define AWF_INPOSTDDEMSG 0x0008
+
+#define CB_RESERVE 256 // size of memory reserve block
+
+typedef struct _COMMONINFO { // Common (client & server) Conversation info
+ PAPPINFO pai; // associated app info
+ HSZ hszSvcReq; // app name used to make connection
+ ATOM aServerApp; // app name returned by server
+ ATOM aTopic; // conversation topic returned by server
+ HCONV hConvPartner; // conversation partner window
+ XADATA xad; // synchronous transaction data
+ WORD fs; // conversation status (ST_ flags)
+ HWND hwndFrame; // initiate window used to make connection
+ CONVCONTEXT CC; // conversation context values
+ PQST pPMQ; // post message queue - if needed.
+} COMMONINFO;
+typedef COMMONINFO far *PCOMMONINFO;
+
+typedef struct _CBLI { /* callback list item */
+ PLITEM next;
+ HCONV hConv; /* perameters for callback */
+ HSZ hszTopic;
+ HSZ hszItem;
+ WORD wFmt;
+ WORD wType;
+ HDDEDATA hData;
+ DWORD dwData1;
+ DWORD dwData2;
+ WORD msg; /* message received that created this item */
+ WORD fsStatus; /* Status from DDE msg */
+ HWND hwndPartner;
+ PAPPINFO pai;
+ HANDLE hMemFree; /* used for holding memory to free after callback */
+ BOOL fQueueOnly; /* used to properly order replies to non-callback cases. */
+} CBLI;
+typedef CBLI FAR *PCBLI;
+
+typedef struct _CLIENTINFO { /* Client specific conversation info */
+ COMMONINFO ci;
+ HWND hwndInit; // frame window last INITIATE was sent to.
+ PQST pQ; // assync transaction queue
+ PLST pClientAdvList; // active ADVISE loops for client
+} CLIENTINFO;
+typedef CLIENTINFO FAR *PCLIENTINFO;
+
+typedef struct _SERVERINFO { /* Server specific conversation info */
+ COMMONINFO ci;
+} SERVERINFO;
+typedef SERVERINFO FAR *PSERVERINFO;
+
+typedef struct _EXTDATAINFO { /* used to tie instance info to hDatas */
+ PAPPINFO pai;
+ HDDEDATA hData;
+} EXTDATAINFO;
+typedef EXTDATAINFO FAR *LPEXTDATAINFO;
+
+#define EXTRACTHCONVPAI(hConv) ((PCLIENTINFO)GetWindowLong((HWND)hConv, GWL_PCI))->ci.pai
+#define EXTRACTHCONVLISTPAI(hcl) (PAPPINFO)GetWindowWord((HWND)hcl, GWW_PAI)
+#define EXTRACTHDATAPAI(XhData) ((LPEXTDATAINFO)(XhData))->pai
+#define FREEEXTHDATA(XhData) FarFreeMem((LPSTR)XhData);
+
+typedef struct _DDE_DATA {
+ WORD wStatus;
+ WORD wFmt;
+ WORD wData;
+} DDE_DATA, FAR *LPDDE_DATA;
+
+
+/******** structure for hook functions *******/
+
+typedef struct _HMSTRUCT {
+ WORD hlParam;
+ WORD llParam;
+ WORD wParam;
+ WORD wMsg;
+ WORD hWnd;
+} HMSTRUCT, FAR *LPHMSTRUCT;
+
+
+typedef struct _IE { // InitEnum structure used to pass data to the fun.
+ HWND hwnd;
+ PCLIENTINFO pci;
+ ATOM aTopic;
+} IE;
+
+/***** private window messages and constants ******/
+
+#define HDATA_READONLY 0x8000
+#define HDATA_NOAPPFREE 0x4000 // set on loaned handles (callback)
+#define HDATA_EXEC 0x0100 // this data was from execute
+
+#define UMSR_POSTADVISE (WM_USER + 104)
+#define UMSR_CHGPARTNER (WM_USER + 107)
+
+#define UM_REGISTER (WM_USER + 200)
+#define UM_UNREGISTER (WM_USER + 201)
+#define UM_MONITOR (WM_USER + 202)
+#define UM_QUERY (WM_USER + 203)
+#define Q_CLIENT 0
+#define Q_APPINFO 1
+#define UM_CHECKCBQ (WM_USER + 204)
+#define UM_DISCONNECT (WM_USER + 206)
+#define UM_SETBLOCK (WM_USER + 207)
+#define UM_FIXHEAP (WM_USER + 208)
+#define UM_TERMINATE (WM_USER + 209)
+
+
+// GLOBALS
+
+extern HANDLE hInstance;
+extern HWND hwndDmgMonitor;
+extern HANDLE hheapDmg;
+extern PAPPINFO pAppInfoList;
+extern PPILE pDataInfoPile;
+extern PPILE pLostAckPile;
+extern WORD hwInst;
+extern DWORD aulmapType[];
+extern CONVCONTEXT CCDef;
+extern char szNull[];
+extern WORD cMonitor;
+extern FARPROC prevHook;
+extern DWORD ShutdownTimeout;
+extern DWORD ShutdownRetryTimeout;
+extern LPMQL gMessageQueueList;
+
+extern char SZFRAMECLASS[];
+extern char SZDMGCLASS[];
+extern char SZCLIENTCLASS[];
+extern char SZSERVERCLASS[];
+extern char SZMONITORCLASS[];
+extern char SZCONVLISTCLASS[];
+extern char SZHEAPWATCHCLASS[];
+
+
+
+
+
+
+//#ifdef DEBUG
+extern WORD cAtoms;
+//#endif
+
+// PROGMAN HACK!!!!
+extern ATOM aProgmanHack;
+
+// PROC DEFS
+
+/* from dmgutil.asm */
+
+LPBYTE NEAR HugeOffset(LPBYTE pSrc, DWORD cb);
+#ifdef DEBUG
+VOID StkTrace(WORD cFrames, LPVOID lpBuf);
+#endif
+extern WORD NEAR SwitchDS(WORD newDS);
+
+/* dmg.c entrypoints are exported by ddeml.h */
+
+/* from ddeml.c */
+
+WORD Register(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd);
+BOOL AbandonTransaction(HWND hwnd, PAPPINFO pai, DWORD id, BOOL fMarkOnly);
+
+/* from dmgwndp.c */
+
+VOID ChildMsg(HWND hwndParent, WORD msg, WORD wParam, DWORD lParam, BOOL fPost);
+long EXPENTRY DmgWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+long EXPENTRY ClientWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+BOOL DoClientDDEmsg(PCLIENTINFO pci, HWND hwndClient, WORD msg, HWND hwndServer,
+ DWORD lParam);
+BOOL fExpectedMsg(PXADATA pXad, DWORD lParam, WORD msg);
+BOOL AdvanceXaction(HWND hwnd, PCLIENTINFO pci, PXADATA pXad,
+ DWORD lParam, WORD msg, LPWORD pErr);
+VOID CheckCBQ(PAPPINFO pai);
+VOID Disconnect(HWND hwnd, WORD afCmd, PCLIENTINFO pci);
+VOID Terminate(HWND hwnd, HWND hwndFrom, PCLIENTINFO pci);
+long EXPENTRY ServerWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+long EXPENTRY subframeWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+long EXPENTRY ConvListWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+HDDEDATA DoCallback(PAPPINFO pai, HCONV hConv, HSZ hszTopic, HSZ hszItem,
+ WORD wFmt, WORD wType, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+
+/* from dmgdde.c */
+
+BOOL timeout(PAPPINFO pai, DWORD ulTimeout, HWND hwndTimeout);
+HANDLE AllocDDESel(WORD fsStatus, WORD wFmt, DWORD cbData);
+BOOL MakeCallback(PCOMMONINFO pci, HCONV hConv, HSZ hszTopic, HSZ hszItem,
+ WORD wFmt, WORD wType, HDDEDATA hData, DWORD dwData1, DWORD dwData2,
+ WORD msg, WORD fsStatus, HWND hwndPartner, HANDLE hMemFree,
+ BOOL fQueueOnly);
+BOOL PostDdeMessage(PCOMMONINFO pci, WORD msg, HWND hwndFrom, LONG lParam,
+ WORD msgAssoc, HGLOBAL hAssoc);
+BOOL EmptyDDEPostQ(VOID);
+void CALLBACK EmptyQTimerProc(HWND hwnd, UINT msg, UINT tid, DWORD dwTime);
+
+/* from dmgmon.c */
+
+//#ifdef DEBUG
+long EXPENTRY DdePostHookProc(int nCode, WORD wParam, LPMSG lParam);
+long EXPENTRY DdeSendHookProc(int nCode, WORD wParam, LPHMSTRUCT lParam);
+VOID MonBrdcastCB(PAPPINFO pai, WORD wType, WORD wFmt, HCONV hConv,
+ HSZ hszTopic, HSZ hszItem, HDDEDATA hData, DWORD dwData1,
+ DWORD dwData2, DWORD dwRet);
+VOID MonHsz(ATOM a, WORD fsAction, HANDLE hTask);
+WORD MonError(PAPPINFO pai, WORD error);
+VOID MonLink(PAPPINFO pai, BOOL fEstablished, BOOL fNoData, HSZ hszSvc,
+ HSZ hszTopic, HSZ hszItem, WORD wFmt, BOOL fServer,
+ HCONV hConvServer, HCONV hConvClient);
+VOID MonConn(PAPPINFO pai, ATOM aApp, ATOM aTopic, HWND hwndClient,
+ HWND hwndServer, BOOL fConnect);
+VOID MonitorBroadcast(HDDEDATA hData, WORD filter);
+HDDEDATA allocMonBuf(WORD cb, WORD filter);
+long EXPENTRY MonitorWndProc(HWND hwnd, WORD msg, WORD wParam, DWORD lParam);
+//#endif
+
+/* from dmghsz.c */
+
+BOOL FreeHsz(ATOM a);
+BOOL IncHszCount(ATOM a);
+WORD QueryHszLength(HSZ hsz);
+WORD QueryHszName(HSZ hsz, LPSTR psz, WORD cchMax);
+ATOM FindAddHsz(LPSTR psz, BOOL fAdd);
+HSZ MakeInstAppName(ATOM a, HWND hwndFrame);
+
+
+/* from dmgdb.c */
+
+PAPPINFO GetCurrentAppInfo(PAPPINFO);
+VOID UnlinkAppInfo(PAPPINFO pai);
+
+PLST CreateLst(HANDLE hheap, WORD cbItem);
+VOID DestroyLst(PLST pLst);
+VOID DestroyAdvLst(PLST pLst);
+VOID CleanupAdvList(HWND hwndClient, PCLIENTINFO pci);
+PLITEM FindLstItem(PLST pLst, NPFNCMP npfnCmp, PLITEM piSearch);
+BOOL CmpWORD(LPBYTE pb1, LPBYTE pb2);
+BOOL CmpHIWORD(LPBYTE pb1, LPBYTE pb2);
+BOOL CmpDWORD(LPBYTE pb1, LPBYTE pb2);
+PLITEM NewLstItem(PLST pLst, WORD afCmd);
+BOOL RemoveLstItem(PLST pLst, PLITEM pi);
+
+PPILE CreatePile(HANDLE hheap, WORD cbItem, WORD cItemsPerBlock);
+PPILE DestroyPile(PPILE pPile);
+WORD QPileItemCount(PPILE pPile);
+LPBYTE FindPileItem(PPILE pPile, NPFNCMP npfnCmp, LPBYTE pbSearch, WORD afCmd);
+WORD AddPileItem(PPILE pPile, LPBYTE pb, NPFNCMP npfncmp);
+BOOL PopPileSubitem(PPILE pPile, LPBYTE pb);
+
+VOID AddHwndHszList(ATOM a, HWND hwnd, PLST pLst);
+VOID DestroyHwndHszList(PLST pLst);
+HWND HwndFromHsz(ATOM a, PLST pLst);
+
+BOOL CmpAdv(LPBYTE pb1, LPBYTE pb2);
+WORD CountAdvReqLeft(register PADVLI pali);
+BOOL AddAdvList(PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD fsStatus, WORD usFormat);
+BOOL DeleteAdvList(PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD wFmt);
+PADVLI FindAdvList(PLST pLst, HWND hwnd, ATOM aTopic, ATOM aItem, WORD wFmt);
+PADVLI FindNextAdv(PADVLI padvli, HWND hwnd, ATOM aTopic, ATOM aItem);
+
+VOID SemInit(VOID);
+VOID SemCheckIn(VOID);
+VOID SemCheckOut(VOID);
+VOID SemEnter(VOID);
+VOID SemLeave(VOID);
+
+BOOL CopyHugeBlock(LPBYTE pSrc, LPBYTE pDst, DWORD cb);
+BOOL DmgDestroyWindow(HWND hwnd);
+BOOL ValidateHConv(HCONV hConv);
+
+/* from dmgq.c */
+
+PQST CreateQ(WORD cbItem);
+BOOL DestroyQ(PQST pQ);
+PQUEUEITEM Addqi(PQST pQ);
+VOID Deleteqi(PQST pQ, DWORD id);
+PQUEUEITEM Findqi(PQST pQ, DWORD id);
+PQUEUEITEM FindNextQi(PQST pQ, PQUEUEITEM pqi, BOOL fDelete);
+
+/* from dmgmem.c */
+HANDLE DmgCreateHeap(WORD wSize);
+HANDLE DmgDestroyHeap(HANDLE hheap);
+LPVOID FarAllocMem(HANDLE hheap, WORD wSize);
+VOID FarFreeMem(LPVOID lpMem);
+VOID RegisterClasses(VOID);
+// VOID UnregisterClasses(VOID);
+#ifdef DEBUG
+HGLOBAL LogGlobalReAlloc(HGLOBAL h, DWORD cb, UINT flags);
+HGLOBAL LogGlobalAlloc(UINT flags, DWORD cb);
+void FAR * LogGlobalLock(HGLOBAL h);
+BOOL LogGlobalUnlock(HGLOBAL h);
+HGLOBAL LogGlobalFree(HGLOBAL h);
+VOID LogDdeObject(UINT msg, LONG lParam);
+VOID DumpGlobalLogs(VOID);
+#endif
+
+/* from hData.c */
+
+HDDEDATA PutData(LPBYTE pSrc, DWORD cb, DWORD cbOff, ATOM aItem, WORD wFmt,
+ WORD afCmd, PAPPINFO pai);
+VOID FreeDataHandle(PAPPINFO pai, HDDEDATA hData, BOOL fInternal);
+HDDEDATA DllEntry(PCOMMONINFO pcomi, HDDEDATA hData);
+VOID XmitPrep(HDDEDATA hData, PAPPINFO pai);
+HDDEDATA RecvPrep(PAPPINFO pai, HANDLE hMem, WORD afCmd);
+HANDLE CopyDDEShareHandle(HANDLE hMem);
+HBITMAP CopyBitmap(PAPPINFO pai, HBITMAP hbm);
+HDDEDATA CopyHDDEDATA(PAPPINFO pai, HDDEDATA hData);
+VOID FreeDDEData(HANDLE hMem, WORD wFmt);
+
+
+/* from stdinit.c */
+
+long ClientCreate(HWND hwnd, PAPPINFO pai);
+HWND GetDDEClientWindow(PAPPINFO pai, HWND hwndParent, HWND hwndSend, HSZ hszSvc, ATOM aTopic, PCONVCONTEXT pCC);
+BOOL FAR PASCAL InitEnum(HWND hwnd, IE FAR *pie);
+HWND CreateServerWindow(PAPPINFO pai, ATOM aTopic, PCONVCONTEXT pCC);
+VOID ServerFrameInitConv(PAPPINFO pai, HWND hwndFrame, HWND hwndClient, ATOM aApp, ATOM aTopic);
+long ServerCreate(HWND hwnd, PAPPINFO pai);
+BOOL ClientInitAck(HWND hwnd, PCLIENTINFO pci, HWND hwndServer,
+ ATOM aApp, ATOM aTopic);
+
+
+/* from stdptcl.c */
+
+long ClientXferReq(PXFERINFO pXferInfo, HWND hwnd, PCLIENTINFO pci);
+WORD SendClientReq(PAPPINFO pai, PXADATA pXad, HWND hwndServer, HWND hwnd);
+VOID ServerProcessDDEMsg(PSERVERINFO psi, WORD msg, HWND hwndServer,
+ HWND hwndClient, WORD lo, WORD hi);
+VOID PostServerAdvise(HWND hwnd, PSERVERINFO psi, PADVLI pali, WORD cLoops);
+VOID QReply(PCBLI pcbi, HDDEDATA hDataRet);
+long ClientXferRespond(HWND hwndClient, PXADATA pXad, LPWORD pErr);
+
+/* from register.c */
+
+LRESULT ProcessRegistrationMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+VOID RegisterService(BOOL fRegister, GATOM gaApp, HWND hwndListen);
diff --git a/private/mvdm/wow16/ddeml/dmgdb.c b/private/mvdm/wow16/ddeml/dmgdb.c
new file mode 100644
index 000000000..23fd79a50
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgdb.c
@@ -0,0 +1,954 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGDB.C
+*
+* DDE manager data handling routines
+*
+* Created: 12/14/88 Sanford Staab
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+\***************************************************************************/
+#include "ddemlp.h"
+
+/***************************** Private Function ****************************\
+* PAPPINFO GetCurrentAppInfo()
+*
+* DESCRIPTION:
+* This routine uses the pid of the current thread to locate the information
+* pertaining to that thread. If not found, 0 is returned.
+*
+* This call fails if the DLL is in a callback state to prevent recursion.
+* if fChkCallback is set.
+*
+* History: 1/1/89 Created sanfords
+\***************************************************************************/
+PAPPINFO GetCurrentAppInfo(
+PAPPINFO paiStart)
+{
+ register PAPPINFO pai;
+ HANDLE hTaskCurrent;
+
+ SEMENTER();
+ if (pAppInfoList == NULL) {
+ SEMLEAVE();
+ return(0);
+ }
+ pai = paiStart ? paiStart->next : pAppInfoList;
+ hTaskCurrent = GetCurrentTask();
+ while (pai) {
+ if (pai->hTask == hTaskCurrent) {
+ SEMLEAVE();
+ return(pai);
+ }
+ pai = pai->next;
+ }
+ SEMLEAVE();
+ return(0);
+}
+
+
+/***************************** Private Function ****************************\
+* void UnlinkAppInfo(pai)
+* PAPPINFO pai;
+*
+* DESCRIPTION:
+* unlinks an pai safely. Does nothing if not linked.
+*
+* History: 1/1/89 Created sanfords
+\***************************************************************************/
+void UnlinkAppInfo(pai)
+PAPPINFO pai;
+{
+ PAPPINFO paiT;
+
+ AssertF(pai != NULL, "UnlinkAppInfo - NULL input");
+ SEMENTER();
+ if (pai == pAppInfoList) {
+ pAppInfoList = pai->next;
+ SEMLEAVE();
+ return;
+ }
+ paiT = pAppInfoList;
+ while (paiT && paiT->next != pai)
+ paiT = paiT->next;
+ if (paiT)
+ paiT->next = pai->next;
+ SEMLEAVE();
+ return;
+}
+
+
+
+
+
+/***************************** Private Functions ***************************\
+* General List management functions.
+*
+* History:
+* Created 12/15/88 sanfords
+\***************************************************************************/
+PLST CreateLst(hheap, cbItem)
+HANDLE hheap;
+WORD cbItem;
+{
+ PLST pLst;
+
+ SEMENTER();
+ if (!(pLst = (PLST)FarAllocMem(hheap, sizeof(LST)))) {
+ SEMLEAVE();
+ return(NULL);
+ }
+ pLst->hheap = hheap;
+ pLst->cbItem = cbItem;
+ pLst->pItemFirst = (PLITEM)NULL;
+ SEMLEAVE();
+ return(pLst);
+}
+
+
+
+
+void DestroyLst(pLst)
+PLST pLst;
+{
+ if (pLst == NULL)
+ return;
+ SEMENTER();
+ while (pLst->pItemFirst)
+ RemoveLstItem(pLst, pLst->pItemFirst);
+ FarFreeMem((LPSTR)pLst);
+ SEMLEAVE();
+}
+
+
+
+void DestroyAdvLst(pLst)
+PLST pLst;
+{
+ if (pLst == NULL)
+ return;
+ SEMENTER();
+ while (pLst->pItemFirst) {
+ FreeHsz(((PADVLI)(pLst->pItemFirst))->aItem);
+ RemoveLstItem(pLst, pLst->pItemFirst);
+ }
+ FarFreeMem((LPSTR)pLst);
+ SEMLEAVE();
+}
+
+
+
+PLITEM FindLstItem(pLst, npfnCmp, piSearch)
+PLST pLst;
+NPFNCMP npfnCmp;
+PLITEM piSearch;
+{
+ PLITEM pi;
+
+ if (pLst == NULL)
+ return(NULL);
+ SEMENTER();
+ pi = pLst->pItemFirst;
+ while (pi) {
+ if ((*npfnCmp)((LPBYTE)pi + sizeof(LITEM), (LPBYTE)piSearch + sizeof(LITEM))) {
+ SEMLEAVE();
+ return(pi);
+ }
+ pi = pi->next;
+ }
+ SEMLEAVE();
+ return(pi);
+}
+
+
+
+/*
+ * Comparison functions for FindLstItem() and FindPileItem()
+ */
+
+BOOL CmpDWORD(pb1, pb2)
+LPBYTE pb1;
+LPBYTE pb2;
+{
+ return(*(LPDWORD)pb1 == *(LPDWORD)pb2);
+}
+
+
+BOOL CmpWORD(pb1, pb2)
+LPBYTE pb1;
+LPBYTE pb2;
+{
+ return(*(LPWORD)pb1 == *(LPWORD)pb2);
+}
+
+BOOL CmpHIWORD(pb1, pb2)
+LPBYTE pb1;
+LPBYTE pb2;
+{
+ return(*(LPWORD)(pb1 + 2) == *(LPWORD)(pb2 + 2));
+}
+
+
+
+
+
+/***************************** Private Function ****************************\
+* This routine creates a new list item for pLst and links it in according
+* to the ILST_ constant in afCmd. Returns a pointer to the new item
+* or NULL on failure.
+*
+* Note: This MUST be in the semaphore for use since the new list item
+* is filled with garbage on return yet is linked in.
+*
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+PLITEM NewLstItem(pLst, afCmd)
+PLST pLst;
+WORD afCmd;
+{
+ PLITEM pi, piT;
+
+ if (pLst == NULL)
+ return(NULL);
+ SEMCHECKIN();
+
+ pi = (PLITEM)FarAllocMem(pLst->hheap, pLst->cbItem + sizeof(LITEM));
+ if (pi == NULL) {
+ AssertF(FALSE, "NewLstItem - memory failure");
+ return(NULL);
+ }
+
+ if (afCmd & ILST_NOLINK)
+ return(pi);
+
+ if (((piT = pLst->pItemFirst) == NULL) || (afCmd & ILST_FIRST)) {
+ pi->next = piT;
+ pLst->pItemFirst = pi;
+ } else { /* ILST_LAST assumed */
+ while (piT->next != NULL)
+ piT = piT->next;
+ piT->next = pi;
+ pi->next = NULL;
+ }
+ return(pi);
+}
+
+
+
+/***************************** Private Function ****************************\
+* This routine unlinks and frees pi from pLst. If pi cannot be located
+* within pLst, it is freed anyway.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+BOOL RemoveLstItem(pLst, pi)
+PLST pLst;
+PLITEM pi;
+{
+ PLITEM piT;
+
+ if (pLst == NULL || pi == NULL)
+ return(FALSE);
+
+ SEMCHECKIN();
+
+ if ((piT = pLst->pItemFirst) != NULL) {
+ if (pi == piT) {
+ pLst->pItemFirst = pi->next;
+ } else {
+ while (piT->next != pi && piT->next != NULL)
+ piT = piT->next;
+ if (piT->next != NULL)
+ piT->next = pi->next; /* unlink */
+ }
+ } else {
+ AssertF(FALSE, "Improper list item removal");
+ return(FALSE);
+ }
+ FarFreeMem((LPSTR)pi);
+ return(TRUE);
+}
+
+
+
+
+
+/*
+ * ------------- Specific list routines -------------
+ */
+
+/***************************** Private Function ****************************\
+* hwnd-hsz list functions
+*
+* History: 1/20/89 Created sanfords
+\***************************************************************************/
+void AddHwndHszList(
+ATOM a,
+HWND hwnd,
+PLST pLst)
+{
+ PHWNDHSZLI phhi;
+
+ AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "AddHwndHszList - Bad item size");
+ SEMENTER();
+ if (!a || (BOOL)HwndFromHsz(a, pLst)) {
+ SEMLEAVE();
+ return;
+ }
+ phhi = (PHWNDHSZLI)NewLstItem(pLst, ILST_FIRST);
+ phhi->hwnd = hwnd;
+ phhi->a = a;
+ IncHszCount(a); // structure copy
+ SEMLEAVE();
+}
+
+
+void DestroyHwndHszList(pLst)
+PLST pLst;
+{
+ if (pLst == NULL)
+ return;
+ AssertF(pLst->cbItem == sizeof(HWNDHSZLI), "DestroyHwndHszList - Bad item size");
+ SEMENTER();
+ while (pLst->pItemFirst) {
+ FreeHsz(((PHWNDHSZLI)pLst->pItemFirst)->a);
+ RemoveLstItem(pLst, pLst->pItemFirst);
+ }
+ FarFreeMem((LPSTR)pLst);
+ SEMLEAVE();
+}
+
+
+
+HWND HwndFromHsz(
+ATOM a,
+PLST pLst)
+{
+ HWNDHSZLI hhli;
+ PHWNDHSZLI phhli;
+
+ hhli.a = a;
+ if (!(phhli = (PHWNDHSZLI)FindLstItem(pLst, CmpWORD, (PLITEM)&hhli)))
+ return(NULL);
+ return(phhli->hwnd);
+}
+
+
+
+/***************************** Private Function ****************************\
+* DESCRIPTION:
+* Advise list helper functions.
+*
+* History: 1/20/89 Created sanfords
+\***************************************************************************/
+/*
+ * This will match an exact hsz/fmt pair with a 0 format or 0 item or 0 hwnd
+ * being wild.
+ */
+BOOL CmpAdv(
+LPBYTE pb1, // entry being compared
+LPBYTE pb2) // search for
+{
+ PADVLI pali1 = (PADVLI)(pb1 - sizeof(LITEM));
+ PADVLI pali2 = (PADVLI)(pb2 - sizeof(LITEM));
+
+ if (pali2->aTopic == 0 || pali1->aTopic == pali2->aTopic) {
+ if (pali2->hwnd == 0 || pali1->hwnd == pali2->hwnd) {
+ if (pali2->aItem == 0 || pali1->aItem == pali2->aItem ) {
+ if (pali2->wFmt == 0 || pali1->wFmt == pali2->wFmt) {
+ return(TRUE);
+ }
+ }
+ }
+ }
+
+ return(FALSE);
+}
+
+
+WORD CountAdvReqLeft(
+PADVLI pali)
+{
+ ADVLI aliKey;
+ register WORD cLoops = 0;
+
+ SEMENTER();
+ aliKey = *pali;
+ aliKey.hwnd = 0; // all hwnds
+ pali = (PADVLI)aliKey.next;
+ while (pali) {
+ if (CmpAdv(((LPBYTE)pali) + sizeof(LITEM),
+ ((LPBYTE)&aliKey) + sizeof(LITEM))) {
+ cLoops++;
+ }
+ pali = (PADVLI)pali->next;
+ }
+ SEMLEAVE();
+ return(cLoops);
+}
+
+BOOL AddAdvList(
+PLST pLst,
+HWND hwnd,
+ATOM aTopic,
+ATOM aItem,
+WORD fsStatus,
+WORD wFmt)
+{
+ PADVLI pali;
+
+ AssertF(pLst->cbItem == sizeof(ADVLI), "AddAdvList - bad item size");
+ if (!aItem)
+ return(TRUE);
+ SEMENTER();
+ if (!(pali = FindAdvList(pLst, hwnd, aTopic, aItem, wFmt))) {
+ IncHszCount(aItem); // structure copy
+ pali = (PADVLI)NewLstItem(pLst, ILST_FIRST);
+ }
+ AssertF((BOOL)(DWORD)pali, "AddAdvList - NewLstItem() failed")
+ if (pali != NULL) {
+ pali->aItem = aItem;
+ pali->aTopic = aTopic;
+ pali->wFmt = wFmt;
+ pali->fsStatus = fsStatus;
+ pali->hwnd = hwnd;
+ }
+ SEMLEAVE();
+ return((BOOL)(DWORD)pali);
+}
+
+
+
+/*
+ * This will delete the matching Advise loop entry. If wFmt is 0, all
+ * entries with the same hszItem are deleted.
+ * Returns fNotEmptyAfterDelete.
+ */
+BOOL DeleteAdvList(
+PLST pLst,
+HWND hwnd,
+ATOM aTopic,
+ATOM aItem,
+WORD wFmt)
+{
+ PADVLI pali;
+
+ AssertF(pLst->cbItem == sizeof(ADVLI), "DeleteAdvList - bad item size");
+ SEMENTER();
+ while (pali = (PADVLI)FindAdvList(pLst, hwnd, aTopic, aItem, wFmt)) {
+ FreeHsz(pali->aItem);
+ RemoveLstItem(pLst, (PLITEM)pali);
+ }
+ SEMLEAVE();
+ return((BOOL)(DWORD)pLst->pItemFirst);
+}
+
+
+
+/***************************** Private Function ****************************\
+* This routine searches the advise list for and entry in hszItem. It returns
+* pAdvli only if the item is found.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+PADVLI FindAdvList(
+PLST pLst,
+HWND hwnd,
+ATOM aTopic,
+ATOM aItem,
+WORD wFmt)
+{
+ ADVLI advli;
+
+ AssertF(pLst->cbItem == sizeof(ADVLI), "FindAdvList - bad item size");
+ advli.aItem = aItem;
+ advli.aTopic = aTopic;
+ advli.wFmt = wFmt;
+ advli.hwnd = hwnd;
+ return((PADVLI)FindLstItem(pLst, CmpAdv, (PLITEM)&advli));
+}
+
+
+/***************************** Private Function ****************************\
+* This routine searches for the next entry for hszItem. It returns
+* pAdvli only if the item is found. aTopic and hwnd should NOT be 0.
+*
+* History:
+* Created 11/15/89 Sanfords
+\***************************************************************************/
+PADVLI FindNextAdv(
+PADVLI padvli,
+HWND hwnd,
+ATOM aTopic,
+ATOM aItem)
+{
+
+ SEMENTER();
+ while ((padvli = (PADVLI)padvli->next) != NULL) {
+ if (hwnd == 0 || hwnd == padvli->hwnd) {
+ if (aTopic == 0 || aTopic == padvli->aTopic) {
+ if (aItem == 0 || padvli->aItem == aItem) {
+ break;
+ }
+ }
+ }
+ }
+ SEMLEAVE();
+ return(padvli);
+}
+
+
+
+/***************************** Private Function ****************************\
+* This routine removes all list items associated with hwnd.
+*
+* History:
+* Created 4/17/91 Sanfords
+\***************************************************************************/
+VOID CleanupAdvList(
+HWND hwnd,
+PCLIENTINFO pci)
+{
+ PADVLI pali, paliNext;
+ PLST plst;
+
+ if (pci->ci.fs & ST_CLIENT) {
+ plst = pci->pClientAdvList;
+ } else {
+ plst = pci->ci.pai->pServerAdvList;
+ }
+ AssertF(plst->cbItem == sizeof(ADVLI), "CleanupAdvList - bad item size");
+ SEMENTER();
+ for (pali = (PADVLI)plst->pItemFirst; pali; pali = paliNext) {
+ paliNext = (PADVLI)pali->next;
+ if (pali->hwnd == hwnd) {
+ MONLINK(pci->ci.pai, FALSE, pali->fsStatus & DDE_FDEFERUPD,
+ (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
+ (HSZ)pali->aItem, pali->wFmt,
+ (pci->ci.fs & ST_CLIENT) ? FALSE : TRUE,
+ (pci->ci.fs & ST_CLIENT) ?
+ pci->ci.hConvPartner : MAKEHCONV(hwnd),
+ (pci->ci.fs & ST_CLIENT) ?
+ MAKEHCONV(hwnd) : pci->ci.hConvPartner);
+ FreeHsz(pali->aItem);
+ RemoveLstItem(plst, (PLITEM)pali);
+ }
+ }
+ SEMLEAVE();
+}
+
+
+
+/***************************** Pile Functions ********************************\
+*
+* A pile is a list where each item is an array of subitems. This allows
+* a more memory efficient method of handling unordered lists.
+*
+\*****************************************************************************/
+
+PPILE CreatePile(hheap, cbItem, cItemsPerBlock)
+HANDLE hheap;
+WORD cbItem;
+WORD cItemsPerBlock;
+{
+ PPILE ppile;
+
+ if (!(ppile = (PPILE)FarAllocMem(hheap, sizeof(PILE)))) {
+ SEMLEAVE();
+ return(NULL);
+ }
+ ppile->pBlockFirst = NULL;
+ ppile->hheap = hheap;
+ ppile->cbBlock = cbItem * cItemsPerBlock + sizeof(PILEB);
+ ppile->cSubItemsMax = cItemsPerBlock;
+ ppile->cbSubItem = cbItem;
+ return(ppile);
+}
+
+
+PPILE DestroyPile(pPile)
+PPILE pPile;
+{
+ if (pPile == NULL)
+ return(NULL);
+ SEMENTER();
+ while (pPile->pBlockFirst)
+ RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
+ FarFreeMem((LPSTR)pPile);
+ SEMLEAVE();
+ return(NULL);
+}
+
+
+WORD QPileItemCount(pPile)
+PPILE pPile;
+{
+ register WORD c;
+ PPILEB pBlock;
+
+ if (pPile == NULL)
+ return(0);
+
+ SEMENTER();
+ pBlock = pPile->pBlockFirst;
+ c = 0;
+ while (pBlock) {
+ c += pBlock->cItems;
+ pBlock = pBlock->next;
+ }
+ SEMLEAVE();
+ return(c);
+}
+
+
+
+/***************************** Private Function ****************************\
+* Locate and return the pointer to the pile subitem who's key fields match
+* pbSearch using npfnCmp to compare the fields. If pbSearch == NULL, or
+* npfnCmp == NULL, the first subitem is returned.
+*
+* afCmd may be:
+* FPI_DELETE - delete the located item
+* In this case, the returned pointer is not valid.
+*
+* pppb points to where to store a pointer to the block which contained
+* the located item.
+*
+* if pppb == NULL, it is ignored.
+*
+* NULL is returned if pbSearch was not found or if the list was empty.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+LPBYTE FindPileItem(pPile, npfnCmp, pbSearch, afCmd)
+PPILE pPile;
+NPFNCMP npfnCmp;
+LPBYTE pbSearch;
+WORD afCmd;
+{
+ LPBYTE psi; // subitem pointer.
+ PPILEB pBlockCur; // current block pointer.
+ register WORD i;
+
+ if (pPile == NULL)
+ return(NULL);
+ SEMENTER();
+ pBlockCur = pPile->pBlockFirst;
+ /*
+ * while this block is not the end...
+ */
+ while (pBlockCur) {
+ for (psi = (LPBYTE)pBlockCur + sizeof(PILEB), i = 0;
+ i < pBlockCur->cItems;
+ psi += pPile->cbSubItem, i++) {
+
+ if (pbSearch == NULL || npfnCmp == NULL || (*npfnCmp)(psi, pbSearch)) {
+ if (afCmd & FPI_DELETE) {
+ /*
+ * remove entire block if this was the last subitem in it.
+ */
+ if (--pBlockCur->cItems == 0) {
+ RemoveLstItem((PLST)pPile, (PLITEM)pBlockCur);
+ } else {
+ /*
+ * copy last subitem in the block over the removed item.
+ */
+ hmemcpy(psi, (LPBYTE)pBlockCur + sizeof(PILEB) +
+ pPile->cbSubItem * pBlockCur->cItems,
+ pPile->cbSubItem);
+ }
+ }
+ return(psi); // found
+ }
+ }
+ pBlockCur = (PPILEB)pBlockCur->next;
+ }
+ SEMLEAVE();
+ return(NULL); // not found.
+}
+
+
+/***************************** Private Function ****************************\
+* Places a copy of the subitem pointed to by pb into the first available
+* spot in the pile pPile. If npfnCmp != NULL, the pile is first searched
+* for a pb match. If found, pb replaces the located data.
+*
+* Returns:
+* API_FOUND if already there
+* API_ERROR if an error happened
+* API_ADDED if not found and added
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+WORD AddPileItem(pPile, pb, npfnCmp)
+PPILE pPile;
+LPBYTE pb;
+BOOL (*npfnCmp)(LPBYTE pb, LPBYTE pbSearch);
+{
+ LPBYTE pbDst;
+ PPILEB ppb;
+
+ if (pPile == NULL)
+ return(FALSE);
+ SEMENTER();
+ if (npfnCmp != NULL && (pbDst = FindPileItem(pPile, npfnCmp, pb, 0)) !=
+ NULL) {
+ hmemcpy(pbDst, pb, pPile->cbSubItem);
+ SEMLEAVE();
+ return(API_FOUND);
+ }
+ ppb = pPile->pBlockFirst;
+ /*
+ * locate a block with room
+ */
+ while ((ppb != NULL) && ppb->cItems == pPile->cSubItemsMax) {
+ ppb = (PPILEB)ppb->next;
+ }
+ /*
+ * If all full or no blocks, make a new one, link it on the bottom.
+ */
+ if (ppb == NULL) {
+ ppb = (PPILEB)NewLstItem((PLST)pPile, ILST_LAST);
+ if (ppb == NULL) {
+ SEMLEAVE();
+ return(API_ERROR);
+ }
+ ppb->cItems = 0;
+ }
+ /*
+ * add the subitem
+ */
+ hmemcpy((LPBYTE)ppb + sizeof(PILEB) + pPile->cbSubItem * ppb->cItems++,
+ pb, pPile->cbSubItem);
+
+ SEMLEAVE();
+ return(API_ADDED);
+}
+
+
+
+
+/***************************** Private Function ****************************\
+* Fills pb with a copy of the top item's data and removes it from the pile.
+* returns FALSE if the pile was empty.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+BOOL PopPileSubitem(pPile, pb)
+PPILE pPile;
+LPBYTE pb;
+{
+ PPILEB ppb;
+ LPBYTE pSrc;
+
+
+ if ((pPile == NULL) || ((ppb = pPile->pBlockFirst) == NULL))
+ return(FALSE);
+
+ SEMENTER();
+ pSrc = (LPBYTE)pPile->pBlockFirst + sizeof(PILEB);
+ hmemcpy(pb, pSrc, pPile->cbSubItem);
+ /*
+ * remove entire block if this was the last subitem in it.
+ */
+ if (pPile->pBlockFirst->cItems == 1) {
+ RemoveLstItem((PLST)pPile, (PLITEM)pPile->pBlockFirst);
+ } else {
+ /*
+ * move last item in block to replace copied subitem and decrement
+ * subitem count.
+ */
+ hmemcpy(pSrc, pSrc + pPile->cbSubItem * --pPile->pBlockFirst->cItems,
+ pPile->cbSubItem);
+ }
+ SEMLEAVE();
+ return(TRUE);
+}
+
+
+
+#if 0
+
+/***************************** Semaphore Functions *************************\
+* SEMENTER() and SEMLEAVE() are macros.
+*
+* History: 1/1/89 Created sanfords
+\***************************************************************************/
+void SemInit()
+{
+ LPBYTE pSem;
+ SHORT c;
+
+ pSem = (LPBYTE) & FSRSemDmg;
+ c = 0;
+ while (c++ < sizeof(DOSFSRSEM)) {
+ *pSem++ = 0;
+ }
+ FSRSemDmg.cb = sizeof(DOSFSRSEM);
+}
+
+
+void SemCheckIn()
+{
+ PIDINFO pi;
+ BOOL fin;
+
+ DosGetPID(&pi);
+ fin = (FSRSemDmg.cUsage > 0) && (FSRSemDmg.pid == pi.pid) && ((FSRSemDmg.tid ==
+ pi.tid) || (FSRSemDmg.tid == -1));
+ /*
+ * !!! NOTE: during exitlists processing, semaphore TIDs are set to -1
+ */
+ AssertF(fin, "SemCheckIn - Out of Semaphore");
+ if (!fin)
+ SEMENTER();
+}
+
+
+void SemCheckOut()
+{
+ PIDINFO pi;
+ BOOL fOut;
+
+ DosGetPID(&pi);
+ fOut = FSRSemDmg.cUsage == 0 || FSRSemDmg.pid != pi.pid || FSRSemDmg.tid !=
+ pi.tid;
+ AssertF(fOut, "SemCheckOut - In Semaphore");
+ if (!fOut)
+ while (FSRSemDmg.cUsage)
+ SEMLEAVE();
+}
+
+
+void SemEnter()
+{
+ DosFSRamSemRequest(&FSRSemDmg, SEM_INDEFINITE_WAIT);
+}
+
+
+void SemLeave()
+{
+ DosFSRamSemClear(&FSRSemDmg);
+}
+
+
+#endif // 0
+
+BOOL CopyHugeBlock(pSrc, pDst, cb)
+LPBYTE pSrc;
+LPBYTE pDst;
+DWORD cb;
+{
+ DWORD cFirst;
+ /*
+ * |____________| |___________| |____________| |____________|
+ * ^src ^
+ *
+ * |____________| |___________| |____________| |____________|
+ * ^dst ^
+ */
+ /*
+ * The following check determines whether the copy can be done
+ * in one short copy operation. Checks whether the byte count
+ * is small enough to span the bytes to the right of the greater
+ * of pSrc and pDst.
+ */
+ cFirst = (DWORD)min(~LOWORD((DWORD)pSrc), ~LOWORD((DWORD)pDst)) + 1L;
+ /* cFirst is # of bytes to end of seg, for buffer w/ biggest offset */
+ if (cb < cFirst) {
+ hmemcpy(pDst, pSrc, (WORD)cb);
+ return(TRUE);
+ }
+
+ goto copyit; /* if not, jump into while loop */
+
+ /*
+ * Now at least one of the pointers is on a segment boundry.
+ */
+ while (cb) {
+ cFirst = min(0x10000 - (LOWORD((DWORD)pSrc) | LOWORD((DWORD)pDst)), (LONG)cb);
+copyit:
+ if (HIWORD(cFirst)) {
+ /*
+ * special case where pSrc and pDst both are on segment
+ * bounds. Copy half at a time. First half first.
+ */
+ /*
+ * |___________| |____________| |____________|
+ * ^src ^
+ *
+ * |___________| |____________| |____________|
+ * ^dst ^
+ */
+ cFirst >>= 1; /* half the span */
+ hmemcpy(pDst, pSrc, (WORD)cFirst);
+ pSrc += cFirst; /* inc ptrs */
+ pDst += cFirst;
+ cb -= cFirst; /* dec bytecount */
+ }
+ hmemcpy(pDst, pSrc, (WORD)cFirst);
+ pSrc = HugeOffset(pSrc, cFirst);
+ pDst = HugeOffset(pDst, cFirst);
+ cb -= cFirst;
+ /*
+ * |____________| |___________| |____________| |____________|
+ * ^src ^
+ *
+ * |____________| |___________| |____________| |____________|
+ * ^dst ^
+ */
+ }
+ return(TRUE);
+}
+
+
+
+
+/***************************************************************************\
+* Kills windows but avoids invalid window rips in debugger.
+\***************************************************************************/
+BOOL DmgDestroyWindow(hwnd)
+HWND hwnd;
+{
+ if (IsWindow(hwnd))
+ return(DestroyWindow(hwnd));
+ return(TRUE);
+}
+
+
+
+BOOL ValidateHConv(
+HCONV hConv)
+{
+ return(IsWindow((HWND)hConv) &&
+ GetWindowWord((HWND)hConv, GWW_CHECKVAL) == HIWORD(hConv));
+}
+
+
+
+#ifdef DEBUG
+void _loadds fAssert(
+BOOL f,
+LPSTR pszComment,
+WORD line,
+LPSTR szfile,
+BOOL fWarning)
+{
+ char szT[90];
+
+ if (!f) {
+ wsprintf(szT, "\n\rAssertion failure: %s:%d %s\n\r",
+ szfile, line, pszComment);
+ OutputDebugString((LPSTR)szT);
+ if (!fWarning)
+ DEBUGBREAK();
+ }
+}
+#endif /* DEBUG */
+
diff --git a/private/mvdm/wow16/ddeml/dmgdde.c b/private/mvdm/wow16/ddeml/dmgdde.c
new file mode 100644
index 000000000..fdae58ceb
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgdde.c
@@ -0,0 +1,526 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGDDE.C
+*
+* This module contains functions used for interfacing with DDE structures
+* and such.
+*
+* Created: 12/23/88 sanfords
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+\***************************************************************************/
+#include "ddemlp.h"
+
+VOID FreeDdeMsgData(WORD msg, LPARAM lParam);
+
+UINT EmptyQueueTimerId = 0;
+
+/***************************** Private Function ****************************\
+* timeout()
+*
+* This routine creates a timer for hwndTimeout. It then runs a modal loop
+* which will exit once the pai->wTimeoutStatus word indicates things are
+* either done (TOS_DONE), aborted (TOS_ABORT), or the system is shutting
+* down (TOS_SHUTDOWN). A values of TOS_TICK is used to support timouts
+* >64K in length.
+*
+* Returns fSuccess, ie TRUE if TOS_DONE was received. before TOS_ABORT.
+*
+* PUBDOC START
+* Synchronous client transaction modal loops:
+*
+* During Synchronous transactions, a client application will enter a modal
+* loop while waiting for the server to respond to the request. If an
+* application wishes to filter messages to the modal loop, it may do so
+* by setting a message filter tied to MSGF_DDEMGR. Applications should
+* be aware however that the DDEMGR modal loop processes private messages
+* in the WM_USER range, WM_DDE messages, and WM_TIMER messages with timer IDs
+* using the TID_ constants defined in ddeml.h.
+* These messages must not be filtered by an application!!!
+*
+* PUBDOC END
+*
+* History:
+* Created sanfords 12/19/88
+\***************************************************************************/
+BOOL timeout(
+PAPPINFO pai,
+DWORD ulTimeout,
+HWND hwndTimeout)
+{
+ MSG msg;
+ PAPPINFO paiT;
+
+ SEMENTER();
+ /*
+ * We check all instances in this task (thread) since we cannot let
+ * one thread enter a modal loop two levels deep.
+ */
+ paiT = NULL;
+ while (paiT = GetCurrentAppInfo(paiT)) {
+ if (paiT->hwndTimer) {
+ SETLASTERROR(pai, DMLERR_REENTRANCY);
+ AssertF(FALSE, "Recursive timeout call");
+ SEMLEAVE();
+ return(FALSE);
+ }
+ }
+ pai->hwndTimer = hwndTimeout;
+ SEMLEAVE();
+
+ if (!SetTimer(hwndTimeout, TID_TIMEOUT,
+ ulTimeout > 0xffffL ? 0xffff : (WORD)ulTimeout, NULL)) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ return(FALSE);
+ }
+
+
+ if (ulTimeout < 0xffff0000) {
+ ulTimeout += 0x00010000;
+ }
+
+ //
+ // We use this instance-wide global variable to note timeouts so that
+ // we don't need to rely on PostMessage() to work when faking timeouts.
+ //
+
+ do {
+
+ ulTimeout -= 0x00010000;
+ if (ulTimeout <= 0xffffL) {
+ // the last timeout should be shorter than 0xffff
+ SetTimer(hwndTimeout, TID_TIMEOUT, (WORD)ulTimeout, NULL);
+ }
+ pai->wTimeoutStatus = TOS_CLEAR;
+
+ /*
+ * stay in modal loop until a timeout happens.
+ */
+
+ while (pai->wTimeoutStatus == TOS_CLEAR) {
+
+ if (!GetMessage(&msg, (HWND)NULL, 0, 0)) {
+ /*
+ * Somebody posted a WM_QUIT message - get out of this
+ * timer loop and repost so main loop gets it. This
+ * fixes a bug where some apps (petzolds ShowPop) use
+ * rapid synchronous transactions which interfere with
+ * their proper closing.
+ */
+ pai->wTimeoutStatus = TOS_ABORT;
+ PostMessage(msg.hwnd, WM_QUIT, 0, 0);
+ } else {
+ if (!CallMsgFilter(&msg, MSGF_DDEMGR))
+ DispatchMessage(&msg);
+ }
+ }
+
+ } while (pai->wTimeoutStatus == TOS_TICK && HIWORD(ulTimeout));
+
+ KillTimer(hwndTimeout, TID_TIMEOUT);
+
+ //
+ // remove any remaining timeout message in the queue.
+ //
+
+ while (PeekMessage(&msg, hwndTimeout, WM_TIMER, WM_TIMER,
+ PM_NOYIELD | PM_REMOVE)) {
+ if (msg.message == WM_QUIT) {
+ /*
+ * Windows BUG: This call will succeed on WM_QUIT messages!
+ */
+ PostQuitMessage(0);
+ break;
+ }
+ }
+
+ SEMENTER();
+ pai->hwndTimer = 0;
+ SEMLEAVE();
+ /*
+ * post a callback check incase we blocked callbacks due to being
+ * in a timeout.
+ */
+ if (!PostMessage(pai->hwndDmg, UM_CHECKCBQ, 0, (DWORD)(LPSTR)pai)) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ }
+ return(TRUE);
+}
+
+
+/***************************** Private Function ****************************\
+* Allocates global DDE memory and fills in first two words with fsStatus
+* and wFmt.
+*
+* History: created 6/15/90 rich gartland
+\***************************************************************************/
+HANDLE AllocDDESel(fsStatus, wFmt, cbData)
+WORD fsStatus;
+WORD wFmt;
+DWORD cbData;
+{
+ HANDLE hMem = NULL;
+ DDEDATA FAR * pMem;
+
+ SEMENTER();
+
+ if (!cbData)
+ cbData++; // fixes GLOBALALLOC bug where 0 size object allocation fails
+
+ if ((hMem = GLOBALALLOC(GMEM_DDESHARE, cbData))) {
+ pMem = (DDEDATA FAR * )GLOBALPTR(hMem);
+ *(WORD FAR * )pMem = fsStatus;
+ pMem->cfFormat = wFmt;
+ }
+
+ SEMLEAVE();
+ return(hMem);
+}
+
+
+/***************************** Private Function ****************************\
+* This routine institutes a callback directly if psi->fEnableCB is set
+* and calls QReply to complete the transaction,
+* otherwise it places the data into the queue for processing.
+*
+* Since hData may be freed by the app at any time once the callback is
+* issued, we cannot depend on it being there for QReply. Therefore we
+* save all the pertinant data in the queue along with it.
+*
+* Returns fSuccess.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+BOOL MakeCallback(
+PCOMMONINFO pcoi,
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+WORD wFmt,
+WORD wType,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2,
+WORD msg,
+WORD fsStatus,
+HWND hwndPartner,
+HANDLE hMemFree,
+BOOL fQueueOnly)
+{
+ PCBLI pcbli;
+
+ SEMENTER();
+
+ pcbli = (PCBLI)NewLstItem(pcoi->pai->plstCB, ILST_LAST);
+ if (pcbli == NULL) {
+ SETLASTERROR(pcoi->pai, DMLERR_MEMORY_ERROR);
+ SEMLEAVE();
+ return(FALSE);
+ }
+ pcbli->hConv = hConv;
+ pcbli->hszTopic = hszTopic;
+ pcbli->hszItem = hszItem;
+ pcbli->wFmt = wFmt;
+ pcbli->wType = wType;
+ pcbli->hData = hData;
+ pcbli->dwData1 = dwData1;
+ pcbli->dwData2 = dwData2;
+ pcbli->msg = msg;
+ pcbli->fsStatus = fsStatus;
+ pcbli->hwndPartner = hwndPartner;
+ pcbli->hMemFree = hMemFree;
+ pcbli->pai = pcoi->pai;
+ pcbli->fQueueOnly = fQueueOnly;
+
+ SEMLEAVE();
+
+ if (!(pcoi->fs & ST_BLOCKED))
+ if (!PostMessage(pcoi->pai->hwndDmg, UM_CHECKCBQ,
+ 0, (DWORD)(LPSTR)pcoi->pai)) {
+ SETLASTERROR(pcoi->pai, DMLERR_SYS_ERROR);
+ }
+
+#ifdef DEBUG
+ if (hMemFree) {
+ LogDdeObject(0xB000, hMemFree);
+ }
+#endif
+ return(TRUE);
+}
+
+
+#define MAX_PMRETRIES 3
+
+
+//
+// This routine extends the size of the windows message queue by queueing
+// up failed posts on the sender side. This avoids the problems of full
+// client queues and of windows behavior of giving DDE messages priority.
+//
+BOOL PostDdeMessage(
+PCOMMONINFO pcoi, // senders COMMONINFO
+WORD msg,
+HWND hwndFrom, // == wParam
+LONG lParam,
+WORD msgAssoc,
+HGLOBAL hAssoc)
+{
+ LPMQL pmql;
+ PPMQI ppmqi;
+ int cTries;
+ HANDLE hTaskFrom, hTaskTo;
+ HWND hwndTo;
+ PQST pMQ;
+
+ hwndTo = (HWND)pcoi->hConvPartner;
+ if (!IsWindow(hwndTo)) {
+ return(FALSE);
+ }
+
+ hTaskTo = GetWindowTask(hwndTo);
+ /*
+ * locate message overflow queue for our target task (pMQ)
+ */
+ for (pmql = gMessageQueueList; pmql; pmql = pmql->next) {
+ if (pmql->hTaskTo == hTaskTo) {
+ break;
+ }
+ }
+ if (pmql != NULL) {
+ pMQ = pmql->pMQ;
+ } else {
+ pMQ = NULL;
+ }
+
+ /*
+ * See if any messages are already queued up
+ */
+ if (pMQ && pMQ->cItems) {
+ if (msg == WM_DDE_TERMINATE) {
+ /*
+ * remove any non-terminate queued messages from us to them.
+ */
+ ppmqi = (PPMQI)FindNextQi(pMQ, NULL, FALSE);
+ while (ppmqi) {
+ FreeDdeMsgData(ppmqi->msg, ppmqi->lParam);
+ FreeDdeMsgData(ppmqi->msgAssoc,
+ MAKELPARAM(ppmqi->hAssoc, ppmqi->hAssoc));
+ ppmqi = (PPMQI)FindNextQi(pMQ, (PQUEUEITEM)ppmqi,
+ ppmqi->hwndTo == hwndTo &&
+ ppmqi->wParam == hwndFrom);
+ }
+ pMQ = NULL; // so we just post it
+ } else {
+ // add the latest post attempt
+
+ ppmqi = (PPMQI)Addqi(pMQ);
+
+ if (ppmqi == NULL) {
+ SETLASTERROR(pcoi->pai, DMLERR_MEMORY_ERROR);
+ return(FALSE); // out of memory
+ }
+ ppmqi->hwndTo = hwndTo;
+ ppmqi->msg = msg;
+ ppmqi->wParam = hwndFrom;
+ ppmqi->lParam = lParam;
+ ppmqi->hAssoc = hAssoc;
+ ppmqi->msgAssoc = msgAssoc;
+ }
+ }
+
+ if (pMQ == NULL || pMQ->cItems == 0) {
+
+ // just post the given message - no queue involved.
+
+ cTries = 0;
+ hTaskFrom = GetWindowTask(hwndFrom);
+ while (!PostMessage(hwndTo, msg, hwndFrom, lParam)) {
+ /*
+ * we yielded so recheck target window
+ */
+ if (!IsWindow(hwndTo)) {
+ return(FALSE);
+ }
+
+ /*
+ * Give reciever a chance to clean out his queue
+ */
+ if (hTaskTo != hTaskFrom) {
+ Yield();
+ } else if (!(pcoi->pai->wFlags & AWF_INPOSTDDEMSG)) {
+ MSG msgs;
+ PAPPINFO pai;
+
+ pcoi->pai->wFlags |= AWF_INPOSTDDEMSG;
+ /*
+ * Reciever is US!
+ *
+ * We need to empty our queue of stuff so we can post more
+ * to ourselves.
+ */
+ while (PeekMessage((MSG FAR *)&msgs, NULL,
+ WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) {
+ DispatchMessage((MSG FAR *)&msgs);
+ }
+
+ /*
+ * tell all instances in this task to process their
+ * callbacks so we can clear our queue.
+ */
+ for (pai = pAppInfoList; pai != NULL; pai = pai->next) {
+ if (pai->hTask == hTaskFrom) {
+ CheckCBQ(pai);
+ }
+ }
+
+ pcoi->pai->wFlags &= ~AWF_INPOSTDDEMSG;
+ }
+
+ if (cTries++ > MAX_PMRETRIES) {
+ /*
+ * relocate message overflow queue for our target task (pMQ)
+ * We need to do this again because we gave up control
+ * with the dispatch message and CheckCBQ calls.
+ */
+ for (pmql = gMessageQueueList; pmql; pmql = pmql->next) {
+ if (pmql->hTaskTo == hTaskTo) {
+ break;
+ }
+ }
+
+ if (pmql == NULL) {
+ /*
+ * create and link in a new queue for the target task
+ */
+ pmql = (LPMQL)FarAllocMem(hheapDmg, sizeof(MQL));
+ if (pmql == NULL) {
+ SETLASTERROR(pcoi->pai, DMLERR_MEMORY_ERROR);
+ return(FALSE);
+ }
+ pmql->pMQ = CreateQ(sizeof(PMQI));
+ if (pmql->pMQ == NULL) {
+ FarFreeMem(pmql);
+ SETLASTERROR(pcoi->pai, DMLERR_MEMORY_ERROR);
+ return(FALSE);
+ }
+ pmql->hTaskTo = hTaskTo;
+ pmql->next = gMessageQueueList;
+ gMessageQueueList = pmql;
+ }
+ pMQ = pmql->pMQ;
+
+ ppmqi = (PPMQI)Addqi(pMQ);
+
+ if (ppmqi == NULL) {
+ SETLASTERROR(pcoi->pai, DMLERR_MEMORY_ERROR);
+ return(FALSE); // out of memory
+ }
+
+ ppmqi->hwndTo = hwndTo;
+ ppmqi->msg = msg;
+ ppmqi->wParam = hwndFrom;
+ ppmqi->lParam = lParam;
+ ppmqi->hAssoc = hAssoc;
+ ppmqi->msgAssoc = msgAssoc;
+
+ return(TRUE);
+ }
+ }
+#ifdef DEBUG
+ LogDdeObject(msg | 0x1000, lParam);
+ if (msgAssoc) {
+ LogDdeObject(msgAssoc | 0x9000, MAKELPARAM(hAssoc, hAssoc));
+ }
+#endif
+ return(TRUE);
+ }
+
+ // come here if the queue exists - empty it as far as we can.
+
+ EmptyDDEPostQ();
+ return(TRUE);
+}
+
+
+//
+// EmptyDDEPost
+//
+// This function checks the DDE post queue list and emptys it as far as
+// possible.
+//
+BOOL EmptyDDEPostQ()
+{
+ PPMQI ppmqi;
+ LPMQL pPMQL, pPMQLPrev;
+ PQST pMQ;
+ BOOL fMoreToDo = FALSE;
+
+ pPMQLPrev = NULL;
+ pPMQL = gMessageQueueList;
+ while (pPMQL) {
+ pMQ = pPMQL->pMQ;
+
+ while (pMQ->cItems) {
+ ppmqi = (PPMQI)Findqi(pMQ, QID_OLDEST);
+ if (!PostMessage(ppmqi->hwndTo, ppmqi->msg, ppmqi->wParam, ppmqi->lParam)) {
+ if (IsWindow(ppmqi->hwndTo)) {
+ fMoreToDo = TRUE;
+ break; // skip to next target queue
+ } else {
+ FreeDdeMsgData(ppmqi->msg, ppmqi->lParam);
+ FreeDdeMsgData(ppmqi->msgAssoc,
+ MAKELPARAM(ppmqi->hAssoc, ppmqi->hAssoc));
+ }
+ } else {
+#ifdef DEBUG
+ LogDdeObject(ppmqi->msg | 0x2000, ppmqi->lParam);
+ if (ppmqi->msgAssoc) {
+ LogDdeObject(ppmqi->msgAssoc | 0xA000,
+ MAKELPARAM(ppmqi->hAssoc, ppmqi->hAssoc));
+ }
+#endif
+ }
+ Deleteqi(pMQ, QID_OLDEST);
+ }
+
+ if (pMQ->cItems == 0) {
+ /*
+ * Delete needless queue (selector)
+ */
+ DestroyQ(pMQ);
+ if (pPMQLPrev) {
+ pPMQLPrev->next = pPMQL->next;
+ FarFreeMem(pPMQL);
+ pPMQL = pPMQLPrev;
+ } else {
+ gMessageQueueList = gMessageQueueList->next;
+ FarFreeMem(pPMQL);
+ pPMQL = gMessageQueueList;
+ continue;
+ }
+ }
+
+ pPMQLPrev = pPMQL;
+ pPMQL = pPMQL->next;
+ }
+ if (fMoreToDo & !EmptyQueueTimerId) {
+ EmptyQueueTimerId = SetTimer(NULL, TID_EMPTYPOSTQ,
+ TIMEOUT_QUEUECHECK, (TIMERPROC)EmptyQTimerProc);
+ }
+
+ return(fMoreToDo);
+}
+
+/*
+ * Used to asynchronously check overflow message queues w/o using PostMessage()
+ */
+void CALLBACK EmptyQTimerProc(
+HWND hwnd,
+UINT msg,
+UINT tid,
+DWORD dwTime)
+{
+ KillTimer(NULL, EmptyQueueTimerId);
+ EmptyQueueTimerId = 0;
+ EmptyDDEPostQ();
+}
diff --git a/private/mvdm/wow16/ddeml/dmghsz.c b/private/mvdm/wow16/ddeml/dmghsz.c
new file mode 100644
index 000000000..1e75fc637
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmghsz.c
@@ -0,0 +1,174 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGHSZ.C
+*
+* This module contains functions used for HSZ control.
+*
+* Created: 8/2/88 sanfords, Microsoft
+* Modified: 6/5/90 Rich Gartland, Aldus (Win 3.0)
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+* Copyright (c) 1990 Aldus Corporation
+\***************************************************************************/
+#include "ddemlp.h"
+
+
+ATOM FindAddHszHelper(LPSTR psz, BOOL fAdd);
+
+/*********************** HSZ management functions *************************\
+* An HSZ is an atom with a NULL tacked onto it in the HIWORD
+* of the HSZ.
+*
+* WINDOWS 3.0 IMPLEMENTATION NOTE:
+* Since under Windows there is only the local atom table or the (single)
+* global atom table (and we need to use the global table to work right),
+* we always have an atom table index of 0. When we run out of atom table
+* space, future hsz adds return failure.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+
+
+BOOL FreeHsz(a)
+ATOM a;
+{
+ if (!a)
+ return(TRUE);
+#ifdef DEBUG
+ cAtoms--;
+#endif
+ MONHSZ(a, MH_INTDELETE, GetCurrentTask());
+ if (GlobalDeleteAtom(a)) {
+ DEBUGBREAK();
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+
+
+BOOL IncHszCount(a)
+ATOM a;
+{
+ char aChars[255];
+
+ if (a == NULL)
+ return(TRUE);
+#ifdef DEBUG
+ cAtoms++;
+#endif
+ MONHSZ(a, MH_INTKEEP, GetCurrentTask());
+ if (GlobalGetAtomName(a, (LPSTR)aChars, 255))
+ return(GlobalAddAtom((LPSTR)aChars));
+ else {
+ AssertF(FALSE, "Cant increment atom");
+ return(FALSE);
+ }
+}
+
+
+
+/***************************** Private Function ****************************\
+* Returns the length of the hsz given without NULL terminator.
+* Wild HSZs have a length of 0.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+WORD QueryHszLength(hsz)
+HSZ hsz;
+{
+ WORD cb;
+ char aChars[255];
+
+ if (LOWORD(hsz) == 0L)
+ return(0);
+
+ if (!(cb = GlobalGetAtomName(LOWORD(hsz), (LPSTR)aChars, 255))) {
+ AssertF(FALSE, "Cant get atom length");
+ return(0);
+ }
+
+ if (HIWORD(hsz))
+ cb += 7;
+
+ return(cb);
+}
+
+
+
+
+WORD QueryHszName(hsz, psz, cchMax)
+HSZ hsz;
+LPSTR psz;
+WORD cchMax;
+{
+ register WORD cb;
+
+ if (LOWORD(hsz) == 0) {
+ if (cchMax)
+ *psz = '\0';
+ return(0);
+ }
+
+ cb = GlobalGetAtomName(LOWORD(hsz), psz, cchMax);
+ if (cb && HIWORD(hsz) && (cb < cchMax - 7)) {
+ wsprintf(&psz[cb], ":(%04x)", HIWORD(hsz));
+ cb += 7;
+ }
+ return cb;
+}
+
+
+
+
+
+
+
+/***************************** Private Function ****************************\
+* This finds the hsz for psz depending on fAdd.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+ATOM FindAddHsz(psz, fAdd)
+LPSTR psz;
+BOOL fAdd;
+{
+ if (psz == NULL || *psz == '\0')
+ return(0L);
+
+ return(FindAddHszHelper(psz, fAdd));
+}
+
+
+
+
+ATOM FindAddHszHelper(psz, fAdd)
+LPSTR psz;
+BOOL fAdd;
+{
+ ATOM atom;
+
+ atom = fAdd ? GlobalAddAtom(psz) : GlobalFindAtom(psz);
+ if (fAdd) {
+#ifdef DEBUG
+ cAtoms++;
+#endif
+ MONHSZ(atom, MH_INTCREATE, GetCurrentTask());
+ }
+
+ return(atom);
+}
+
+
+
+HSZ MakeInstAppName(
+ATOM a,
+HWND hwndFrame)
+{
+ // make upper half of HSZ be HWND FRAME for now.
+ IncHszCount(a);
+ return((HSZ)MAKELONG(a, hwndFrame));
+}
+
diff --git a/private/mvdm/wow16/ddeml/dmgmem.c b/private/mvdm/wow16/ddeml/dmgmem.c
new file mode 100644
index 000000000..25d335343
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgmem.c
@@ -0,0 +1,642 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGMEM.C
+*
+* DDE Manager memory management functions.
+*
+* Created: 5/31/90 Rich Gartland
+*
+* This module contains routines which mimic memory management functions
+* used by the OS/2 version of the DDEMGR library. Some are emulations
+* of OS/2 calls, and others emulate DDEMGR macros built on OS/2 calls.
+* Old function new function
+* --------------------------------------
+* WinCreateHeap DmgCreateHeap
+* WinDestroyHeap DmgDestroyHeap
+* FarAllocMem FarAllocMem
+* FarFreeMem FarFreeMem
+*
+* Copyright (c) 1990, Aldus Corporation
+\***************************************************************************/
+
+#include "ddemlp.h"
+#include <memory.h>
+
+#ifdef DEBUG
+
+#define GML_FREE 1
+#define GML_ALLOC 2
+#define MAX_CLOGS 500
+#define STKTRACE_LEN 3
+
+typedef struct _GMLOG {
+ HGLOBAL h;
+ WORD flags; // GML_
+ WORD msg;
+ WORD cLocks;
+ WORD stktrace[STKTRACE_LEN];
+ WORD stktracePrev[STKTRACE_LEN];
+} GMLOG, far * LPGMLOG;
+
+GMLOG gmlog[MAX_CLOGS];
+WORD cGmLogs = 0;
+int TraceApiLevel = 0;
+
+
+VOID TraceApiIn(
+LPSTR psz)
+{
+ char szT[10];
+
+ wsprintf(szT, "%2d | ", TraceApiLevel);
+ TraceApiLevel++;
+ OutputDebugString(szT);
+ OutputDebugString(psz);
+ if (bDbgFlags & DBF_STOPONTRACE) {
+ DebugBreak();
+ }
+}
+
+VOID TraceApiOut(
+LPSTR psz)
+{
+ char szT[10];
+
+ TraceApiLevel--;
+ wsprintf(szT, "%2d | ", TraceApiLevel);
+ OutputDebugString(szT);
+ OutputDebugString(psz);
+ if (bDbgFlags & DBF_STOPONTRACE) {
+ DebugBreak();
+ }
+}
+
+VOID DumpGmObject(
+LPGMLOG pgmlog)
+{
+ char szT[100];
+
+ wsprintf(szT,
+ "\n\rh=%4x flags=%4x msg=%4x stacks:\n\r%04x %04x %04x %04x %04x\n\r%04x %04x %04x %04x %04x",
+ pgmlog->h,
+ pgmlog->flags,
+ pgmlog->msg,
+ pgmlog->stktrace[0],
+ pgmlog->stktrace[1],
+ pgmlog->stktrace[2],
+ pgmlog->stktrace[3],
+ pgmlog->stktrace[4],
+ pgmlog->stktracePrev[0],
+ pgmlog->stktracePrev[1],
+ pgmlog->stktracePrev[2],
+ pgmlog->stktracePrev[3],
+ pgmlog->stktracePrev[4]
+ );
+ OutputDebugString(szT);
+}
+
+
+HGLOBAL LogGlobalReAlloc(
+HGLOBAL h,
+DWORD cb,
+UINT flags)
+{
+ HGLOBAL hRet;
+ WORD i;
+
+ hRet = GlobalReAlloc(h, cb, flags);
+ if (bDbgFlags & DBF_LOGALLOCS && h != hRet) {
+ if (hRet != NULL) {
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
+ gmlog[i].flags = GML_FREE;
+ hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
+ }
+ if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
+ gmlog[i].flags = GML_ALLOC;
+ hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
+ return(hRet);
+ }
+ }
+ if (cGmLogs >= MAX_CLOGS) {
+ OutputDebugString("\n\rGlobal logging table overflow.");
+ DumpGlobalLogs();
+ DebugBreak();
+ return(hRet);
+ }
+
+ gmlog[cGmLogs].flags = GML_ALLOC;
+ gmlog[cGmLogs].msg = 0;
+ gmlog[cGmLogs].h = hRet;
+ gmlog[cGmLogs].cLocks = 0;
+ hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
+ cGmLogs++;
+ }
+ }
+ return(hRet);
+}
+
+
+
+HGLOBAL LogGlobalAlloc(
+UINT flags,
+DWORD cb)
+{
+ HGLOBAL hRet;
+ WORD i;
+
+ hRet = GlobalAlloc(flags, cb);
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ if (hRet != NULL) {
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (hRet & 0xFFFE)) {
+ gmlog[i].flags = GML_ALLOC;
+ hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
+ return(hRet);
+ }
+ }
+ if (cGmLogs >= MAX_CLOGS) {
+ OutputDebugString("\n\rGlobal logging table overflow.");
+ DumpGlobalLogs();
+ DebugBreak();
+ return(hRet);
+ }
+
+ gmlog[cGmLogs].flags = GML_ALLOC;
+ gmlog[cGmLogs].msg = 0;
+ gmlog[cGmLogs].h = hRet;
+ gmlog[cGmLogs].cLocks = 0;
+ hmemcpy(gmlog[cGmLogs].stktracePrev, gmlog[cGmLogs].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[cGmLogs].stktrace);
+ cGmLogs++;
+ }
+ }
+ return(hRet);
+}
+
+
+void FAR * LogGlobalLock(
+HGLOBAL h)
+{
+ WORD i;
+
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
+ break;
+ }
+ }
+ if (i < cGmLogs) {
+ gmlog[i].cLocks++;
+ if (gmlog[i].flags == GML_FREE) {
+ DumpGmObject(&gmlog[i]);
+ OutputDebugString("\n\rGlobalLock will fail.");
+ DebugBreak();
+ }
+ }
+ }
+ return(GlobalLock(h));
+}
+
+
+BOOL LogGlobalUnlock(
+HGLOBAL h)
+{
+ WORD i;
+
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
+ break;
+ }
+ }
+ if (i < cGmLogs) {
+ if (gmlog[i].cLocks == 0 || gmlog[i].flags == GML_FREE) {
+ DumpGmObject(&gmlog[i]);
+ OutputDebugString("\n\rGlobalUnlock will fail.");
+ DebugBreak();
+ }
+ gmlog[i].cLocks--;
+ }
+ }
+ return(GlobalUnlock(h));
+}
+
+
+HGLOBAL LogGlobalFree(
+HGLOBAL h)
+{
+ WORD i;
+
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
+ if (gmlog[i].flags == GML_FREE) {
+ DumpGmObject(&gmlog[i]);
+ OutputDebugString("\n\rFreeing free object.\n\r");
+ DebugBreak();
+ }
+ gmlog[i].flags = GML_FREE;
+ hmemcpy(gmlog[i].stktracePrev, gmlog[i].stktrace,
+ sizeof(WORD) * STKTRACE_LEN);
+ StkTrace(STKTRACE_LEN, gmlog[i].stktrace);
+ return(GlobalFree(h));
+ }
+ }
+ OutputDebugString("\n\rGlobal object being freed not found in logs.");
+ DebugBreak();
+ }
+ return(GlobalFree(h));
+}
+
+
+VOID LogDdeObject(
+UINT msg,
+LONG lParam)
+{
+ HGLOBAL h;
+ WORD i;
+ char szT[100];
+
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ switch (msg & 0x0FFF) {
+ case WM_DDE_DATA:
+ case WM_DDE_POKE:
+ case WM_DDE_ADVISE:
+ case 0:
+ h = LOWORD(lParam);
+ break;
+
+ case WM_DDE_EXECUTE:
+ h = HIWORD(lParam);
+ break;
+
+ default:
+ return;
+ }
+ if (h == 0) {
+ return;
+ }
+ for (i = 0; i < cGmLogs; i++) {
+ if ((gmlog[i].h & 0xFFFE) == (h & 0xFFFE)) {
+ if (gmlog[i].flags == GML_FREE) {
+ DumpGmObject(&gmlog[i]);
+ wsprintf(szT, "\n\rLogging free DDE Object! [%4x]\n\r", msg);
+ OutputDebugString(szT);
+ DebugBreak();
+ }
+ if (msg & 0xFFF) {
+ gmlog[i].msg = msg;
+ } else {
+ gmlog[i].msg = (gmlog[i].msg & 0x0FFF) | msg;
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+VOID DumpGlobalLogs()
+{
+ WORD i;
+ char szT[100];
+
+ if (bDbgFlags & DBF_LOGALLOCS) {
+ wsprintf(szT, "\n\rDumpGlobalLogs - cGmLogs = %d", cGmLogs);
+ OutputDebugString(szT);
+ for (i = 0; i < cGmLogs; i++) {
+ if (gmlog[i].flags == GML_ALLOC) {
+ DumpGmObject(&gmlog[i]);
+ }
+ }
+ wsprintf(szT, "\n\rDDEML CS=%04x\n\r", HIWORD((LPVOID)DumpGlobalLogs));
+ OutputDebugString(szT);
+ }
+}
+
+#endif // DEBUG
+
+/***************************** Private Function ****************************\
+*
+* Creates a new heap and returns a handle to it.
+* Returns NULL on error.
+*
+*
+* History:
+* Created 5/31/90 Rich Gartland
+\***************************************************************************/
+HANDLE DmgCreateHeap(wSize)
+WORD wSize;
+{
+ HANDLE hMem;
+ DWORD dwSize;
+
+ dwSize = wSize;
+ /* Allocate the memory from a global data segment */
+ if (!(hMem = GLOBALALLOC(GMEM_MOVEABLE, dwSize)))
+ return(NULL);
+
+ /* use LocalInit to establish heap mgmt structures in the seg */
+ if (!LocalInit(hMem, NULL, wSize - 1)) {
+ GLOBALFREE(hMem);
+ return(NULL);
+ }
+
+ return(hMem);
+}
+
+
+/***************************** Private Function ****************************\
+*
+* Destroys a heap previously created with DmgCreateHeap.
+* Returns nonzero on error.
+*
+*
+* History:
+* Created 5/31/90 Rich Gartland
+\***************************************************************************/
+HANDLE DmgDestroyHeap(hheap)
+HANDLE hheap;
+{
+ /* now free the block and return the result (NULL if success) */
+ return(GLOBALFREE(hheap));
+}
+
+
+
+/*
+ * Attempts to recover from memory allocation errors.
+ *
+ * Returns fRetry - ok to attempt reallocation.
+ */
+BOOL ProcessMemError(
+HANDLE hheap)
+{
+ PAPPINFO pai;
+
+ // first locate what instance this heap is assocaited with
+
+ SEMENTER();
+ pai = pAppInfoList;
+ while (pai && pai->hheapApp != hheap) {
+ pai = pai->next;
+ }
+ if (!pai) {
+ SEMLEAVE();
+ return(FALSE); // not associated with an instance, no recourse.
+ }
+
+ /*
+ * Free our emergency reserve memory and post a message to our master
+ * window to handle heap cleanup.
+ */
+ if (pai->lpMemReserve) {
+ FarFreeMem(pai->lpMemReserve);
+ pai->lpMemReserve = NULL;
+ MONERROR(pai, DMLERR_LOW_MEMORY);
+ DoCallback(pai, NULL, 0, 0, 0, XTYP_ERROR, NULL, DMLERR_LOW_MEMORY, 0L);
+ SEMLEAVE();
+ if (!PostMessage(pai->hwndDmg, UM_FIXHEAP, 0, (LONG)(LPSTR)pai)) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+ return(FALSE); // no reserve memory, were dead bud.
+}
+
+
+
+/***************************** Private Function ****************************\
+*
+* Allocates a new block of a given size from a heap.
+* Returns NULL on error, far pointer to the block otherwise.
+*
+*
+* History:
+* Created 5/31/90 Rich Gartland
+\***************************************************************************/
+
+LPVOID FarAllocMem(hheap, wSize)
+HANDLE hheap;
+WORD wSize;
+{
+
+ LPSTR lpMem;
+ PSTR pMem;
+ WORD wSaveDS;
+
+ /* lock the handle to get a far pointer */
+ lpMem = (LPSTR)GLOBALPTR(hheap);
+ if (!lpMem)
+ return(NULL);
+
+ do {
+ /* Do some magic here using the segment selector, to switch our
+ * ds to the heap's segment. Then, our LocalAlloc will work fine.
+ */
+ wSaveDS = SwitchDS(HIWORD(lpMem));
+
+ /* Allocate the block */
+ pMem = (PSTR)LocalAlloc((WORD)LPTR, wSize); // zero init!!!
+
+ SwitchDS(wSaveDS);
+ } while (pMem == NULL && ProcessMemError(hheap));
+
+#ifdef WATCHHEAPS
+ if (pMem) {
+ LogAlloc((DWORD)MAKELONG(pMem, HIWORD(lpMem)), wSize,
+ RGB(0xff, 0, 0), hInstance);
+ }
+#endif
+ /* set up the far return value, based on the success of LocalAlloc */
+ return (LPSTR)(pMem ? MAKELONG(pMem, HIWORD(lpMem)) : NULL);
+}
+
+
+
+
+/***************************** Private Function ****************************\
+*
+* Frees a block of a given size from a heap.
+* Returns NULL on success, far pointer to the block otherwise.
+*
+*
+* History:
+* Created 5/31/90 Rich Gartland
+\***************************************************************************/
+
+void FarFreeMem(
+LPVOID lpMem)
+{
+
+ WORD wSaveDS;
+#ifdef WATCHHEAPS
+ WORD sz;
+#endif
+
+ /* Do some magic here using the segment selector, to switch our
+ * ds to the heap's segment. Then, our LocalFree will work fine.
+ */
+ wSaveDS = SwitchDS(HIWORD(lpMem));
+#ifdef WATCHHEAPS
+ sz = LocalSize((LOWORD((DWORD)lpMem)));
+#endif
+ /* Free the block */
+ LocalFree(LocalHandle(LOWORD((DWORD)lpMem)));
+
+ SwitchDS(wSaveDS);
+#ifdef WATCHHEAPS
+ LogAlloc((DWORD)lpMem, sz, RGB(0x80, 0x80, 0x80), hInstance);
+#endif
+}
+
+
+int FAR PASCAL WEP (int);
+int FAR PASCAL LibMain(HANDLE, WORD, WORD, LPCSTR);
+#pragma alloc_text(INIT_TEXT,LibMain,WEP)
+
+/***************************** Private Function ****************************\
+*
+* Does some initialization for the DLL. Called from LibEntry.asm
+* Returns 1 on success, 0 otherwise.
+*
+*
+* History:
+* Created 6/5/90 Rich Gartland
+\***************************************************************************/
+
+int FAR PASCAL LibMain (hI, wDS, cbHS, lpszCL)
+HANDLE hI; /* instance handle */
+WORD wDS; /* data segment */
+WORD cbHS; /* heapsize */
+LPCSTR lpszCL; /* command line */
+{
+ extern ATOM gatomDDEMLMom;
+ extern ATOM gatomDMGClass;
+
+
+#if 0
+ /* We won't unlock the data segment, as typically happens here */
+
+ /* Init the semaphore -- probably just a stub now */
+ SEMINIT();
+#endif
+ /* set up the global instance handle variable */
+ hInstance = hI;
+
+ /* set up class atoms. Note we use RegisterWindowMessage because
+ * it comes from the same user atom table used for class atoms.
+ */
+ gatomDDEMLMom = RegisterWindowMessage("DDEMLMom");
+ gatomDMGClass = RegisterWindowMessage("DMGClass");
+
+ return(1);
+
+}
+
+
+VOID RegisterClasses()
+{
+ WNDCLASS cls;
+
+ cls.hIcon = NULL;
+ cls.hCursor = NULL;
+ cls.lpszMenuName = NULL;
+ cls.hbrBackground = NULL;
+ cls.style = 0; // CS_GLOBALCLASS
+ cls.hInstance = hInstance;
+ cls.cbClsExtra = 0;
+
+ cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
+ cls.lpszClassName = SZCLIENTCLASS;
+ cls.lpfnWndProc = (WNDPROC)ClientWndProc;
+ RegisterClass(&cls);
+
+ // cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
+ cls.lpszClassName = SZSERVERCLASS;
+ cls.lpfnWndProc = (WNDPROC)ServerWndProc;
+ RegisterClass(&cls);
+
+ // cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD);
+ cls.lpszClassName = SZDMGCLASS;
+ cls.lpfnWndProc = (WNDPROC)DmgWndProc;
+ RegisterClass(&cls);
+
+ cls.cbWndExtra = sizeof(VOID FAR *) + sizeof(WORD) + sizeof(WORD);
+ cls.lpszClassName = SZCONVLISTCLASS;
+ cls.lpfnWndProc = (WNDPROC)ConvListWndProc;
+ RegisterClass(&cls);
+
+ cls.cbWndExtra = sizeof(VOID FAR *);
+ cls.lpszClassName = SZMONITORCLASS;
+ cls.lpfnWndProc = (WNDPROC)MonitorWndProc;
+ RegisterClass(&cls);
+
+ cls.cbWndExtra = sizeof(VOID FAR *);
+ cls.lpszClassName = SZFRAMECLASS;
+ cls.lpfnWndProc = (WNDPROC)subframeWndProc;
+ RegisterClass(&cls);
+
+#ifdef WATCHHEAPS
+ cls.cbWndExtra = 0;
+ cls.lpszClassName = SZHEAPWATCHCLASS;
+ cls.lpfnWndProc = DefWindowProc;
+ cls.hCursor = LoadCursor(NULL, IDC_ARROW);
+ cls.hbrBackground = GetStockObject(WHITE_BRUSH);
+ RegisterClass(&cls);
+#endif // WATCHHEAPS
+}
+
+
+#if 0
+VOID UnregisterClasses()
+{
+ UnregisterClass(SZCLIENTCLASS, hInstance);
+ UnregisterClass(SZSERVERCLASS, hInstance);
+ UnregisterClass(SZDMGCLASS, hInstance);
+ UnregisterClass(SZCONVLISTCLASS, hInstance);
+ UnregisterClass(SZMONITORCLASS, hInstance);
+ UnregisterClass(SZFRAMECLASS, hInstance);
+#ifdef WATCHHEAPS
+ UnregisterClass(SZHEAPWATCHCLASS, hInstance);
+#endif
+}
+#endif
+
+
+/***************************** Private Function ****************************\
+*
+* Does the termination for the DLL.
+* Returns 1 on success, 0 otherwise.
+*
+*
+* History:
+* Created 6/5/90 Rich Gartland
+\***************************************************************************/
+
+int FAR PASCAL WEP (nParameter)
+int nParameter;
+{
+
+ if (nParameter == WEP_SYSTEM_EXIT) {
+ /* DdeUninitialize(); */
+ return(1);
+ } else {
+ if (nParameter == WEP_FREE_DLL) {
+ /* DdeUninitialize(); */
+ return(1);
+ }
+ }
+
+}
diff --git a/private/mvdm/wow16/ddeml/dmgmon.c b/private/mvdm/wow16/ddeml/dmgmon.c
new file mode 100644
index 000000000..2ac777491
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgmon.c
@@ -0,0 +1,295 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGMON.C
+*
+* This module contains functions used for DDE monitor control.
+*
+* Created: 8/2/88 sanfords
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+\***************************************************************************/
+#include "ddemlp.h"
+
+
+long EXPENTRY DdeSendHookProc(
+int nCode,
+WORD wParam,
+LPHMSTRUCT lParam)
+{
+ HDDEDATA hData;
+ MONMSGSTRUCT FAR *pmsgs;
+
+ if (cMonitor && lParam &&
+ lParam->wMsg >= WM_DDE_FIRST && lParam->wMsg <= WM_DDE_LAST) {
+ if (hData = allocMonBuf(sizeof(MONMSGSTRUCT), HIWORD(MF_SENDMSGS))) {
+ pmsgs = (MONMSGSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ pmsgs->cb = sizeof(MONMSGSTRUCT);
+ pmsgs->dwTime = GetCurrentTime();
+ pmsgs->hwndTo = lParam->hWnd;
+ pmsgs->hTask = GetWindowTask(lParam->hWnd);
+ pmsgs->wMsg = lParam->wMsg;
+ pmsgs->wParam = lParam->wParam;
+ pmsgs->lParam = *(DWORD FAR *)&lParam->hlParam;
+ MonitorBroadcast(hData, HIWORD(MF_SENDMSGS));
+ }
+ }
+ return DefHookProc(nCode, wParam, (DWORD)lParam, &prevHook);
+}
+
+
+
+
+long EXPENTRY DdePostHookProc(nCode, wParam, lParam)
+int nCode;
+WORD wParam;
+LPMSG lParam;
+{
+ HDDEDATA hData;
+ MONMSGSTRUCT FAR *pmsgs;
+
+ if (cMonitor && lParam &&
+ lParam->message >= WM_DDE_FIRST && lParam->message <= WM_DDE_LAST) {
+ if (hData = allocMonBuf(sizeof(MONMSGSTRUCT), HIWORD(MF_POSTMSGS))) {
+ pmsgs = (MONMSGSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ pmsgs->cb = sizeof(MONMSGSTRUCT);
+ pmsgs->dwTime = lParam->time;
+ pmsgs->hwndTo = lParam->hwnd;
+ pmsgs->hTask = GetWindowTask(lParam->hwnd);
+ pmsgs->wMsg = lParam->message;
+ pmsgs->wParam = lParam->wParam;
+ pmsgs->lParam = lParam->lParam;
+ MonitorBroadcast(hData, HIWORD(MF_POSTMSGS));
+ }
+ }
+ return DefHookProc(nCode, wParam, (DWORD)lParam, &prevHook);
+}
+
+
+VOID MonBrdcastCB(
+PAPPINFO pai,
+WORD wType,
+WORD wFmt,
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2,
+DWORD dwRet)
+{
+ MONCBSTRUCT FAR *pcbs;
+ HDDEDATA hDataBuf;
+
+ SEMCHECKOUT();
+ SEMENTER();
+ if (pai) {
+ if (hDataBuf = allocMonBuf(sizeof(MONCBSTRUCT), HIWORD(MF_CALLBACKS))) {
+ pcbs = (MONCBSTRUCT FAR *)GlobalLock(HIWORD(hDataBuf));
+ pcbs->cb = sizeof(MONCBSTRUCT);
+ pcbs->dwTime = GetCurrentTime();
+ pcbs->hTask = pai->hTask;
+ pcbs->dwRet = dwRet;
+ pcbs->wType = wType;
+ pcbs->wFmt = wFmt;
+ pcbs->hConv = hConv;
+ pcbs->hsz1 = hszTopic;
+ pcbs->hsz2 = hszItem;
+ pcbs->hData = hData;
+ pcbs->dwData1 = dwData1;
+ pcbs->dwData2 = dwData2;
+ MonitorBroadcast(hDataBuf, HIWORD(MF_CALLBACKS));
+ }
+ }
+ SEMLEAVE();
+}
+
+
+
+
+void MonHsz(
+ATOM a,
+WORD fsAction,
+HANDLE hTask)
+{
+ MONHSZSTRUCT FAR *phszs;
+ HDDEDATA hData;
+ WORD cb;
+
+ if (hData = allocMonBuf(sizeof(MONHSZSTRUCT) + (cb = QueryHszLength((HSZ)a)),
+ HIWORD(MF_HSZ_INFO))) {
+ phszs = (MONHSZSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ phszs->cb = sizeof(MONHSZSTRUCT) + cb + 1;
+ phszs->dwTime = GetCurrentTime();
+ phszs->hTask = hTask;
+ phszs->fsAction = fsAction;
+ phszs->hsz = (HSZ)a;
+ QueryHszName((HSZ)a, phszs->str, ++cb);
+ MonitorBroadcast(hData, HIWORD(MF_HSZ_INFO));
+ }
+}
+
+
+
+
+WORD MonError(
+PAPPINFO pai,
+WORD error)
+{
+ MONERRSTRUCT FAR *perrs;
+ HDDEDATA hData;
+
+ if (error) {
+ if (hData = allocMonBuf(sizeof(MONERRSTRUCT), HIWORD(MF_ERRORS))) {
+ perrs = (MONERRSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ perrs->cb = sizeof(MONERRSTRUCT);
+ perrs->dwTime = GetCurrentTime();
+ perrs->hTask = pai->hTask;
+ perrs->wLastError = error;
+ MonitorBroadcast(hData, HIWORD(MF_ERRORS));
+ }
+ }
+ pai->LastError = error;
+ return(error);
+}
+
+
+VOID MonLink(
+PAPPINFO pai,
+BOOL fEstablished,
+BOOL fNoData,
+HSZ hszSvc,
+HSZ hszTopic,
+HSZ hszItem,
+WORD wFmt,
+BOOL fServer,
+HCONV hConvServer,
+HCONV hConvClient)
+{
+ MONLINKSTRUCT FAR *plink;
+ HDDEDATA hData;
+
+ if (hData = allocMonBuf(sizeof(MONLINKSTRUCT), HIWORD(MF_LINKS))) {
+ plink = (MONLINKSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ plink->cb = sizeof(MONLINKSTRUCT);
+ plink->dwTime = GetCurrentTime();
+ plink->hTask = pai->hTask;
+ plink->fEstablished = fEstablished;
+ plink->fNoData = fNoData;
+ plink->hszSvc = hszSvc;
+ plink->hszTopic = hszTopic;
+ plink->hszItem = hszItem;
+ plink->wFmt = wFmt;
+ plink->fServer = fServer;
+ plink->hConvServer = hConvServer;
+ plink->hConvClient = hConvClient;
+
+ MonitorBroadcast(hData, HIWORD(MF_LINKS));
+ }
+}
+
+
+
+VOID MonConn(
+PAPPINFO pai,
+ATOM aApp,
+ATOM aTopic,
+HWND hwndClient,
+HWND hwndServer,
+BOOL fConnect)
+{
+ MONCONVSTRUCT FAR *pconv;
+ HDDEDATA hData;
+
+ if (hData = allocMonBuf(sizeof(MONCONVSTRUCT), HIWORD(MF_CONV))) {
+ pconv = (MONCONVSTRUCT FAR *)GlobalLock(HIWORD(hData));
+ pconv->cb = sizeof(MONCONVSTRUCT);
+ pconv->dwTime = GetCurrentTime();
+ pconv->hTask = pai->hTask;
+ pconv->hszSvc = (HSZ)aApp;
+ pconv->hszTopic = (HSZ)aTopic;
+ pconv->hConvClient = MAKEHCONV(hwndClient);
+ pconv->hConvServer = MAKEHCONV(hwndServer);
+ pconv->fConnect = fConnect;
+
+ MonitorBroadcast(hData, HIWORD(MF_CONV));
+ }
+}
+
+/*
+ * This guy sends a UM_MONITOR to all the monitor windows who's filters accept
+ * the callback.
+ */
+void MonitorBroadcast(
+HDDEDATA hData,
+WORD filterClass) // set to class of filter or 0
+{
+ PAPPINFO pai;
+ register WORD i = 0;
+
+ SEMCHECKOUT();
+ SEMENTER();
+ pai = pAppInfoList;
+ while (pai && (i < cMonitor)) {
+ if (pai->hwndMonitor) {
+ if (filterClass & HIWORD(pai->afCmd)) {
+ SendMessage(pai->hwndMonitor, UM_MONITOR, filterClass, hData);
+ }
+ i++;
+ }
+ pai = pai->next;
+ }
+ SEMLEAVE();
+ GlobalUnlock(HIWORD(hData));
+ GLOBALFREE(HIWORD(hData));
+}
+
+
+
+HDDEDATA allocMonBuf(
+WORD cb,
+WORD filter)
+{
+ PAPPINFO pai;
+ register WORD i;
+
+ SEMENTER();
+ if (cMonitor == 0)
+ return(FALSE);
+ pai = pAppInfoList;
+ i = 0;
+ while (pai && i < cMonitor) {
+ if (HIWORD(pai->afCmd) & filter)
+ return(MAKELONG(HDATA_EXEC, AllocDDESel(0, 0, cb)));
+ if (pai->afCmd & APPCLASS_MONITOR)
+ i++;
+ pai = pai->next;
+ }
+ return(NULL);
+}
+
+
+long EXPENTRY MonitorWndProc(hwnd, msg, wP, lP)
+HWND hwnd;
+WORD msg;
+WORD wP;
+register DWORD lP;
+{
+ switch (msg) {
+ case WM_CREATE:
+ SetWindowWord(hwnd, GWW_PAI, (WORD)LPCREATESTRUCT_GETPAI(lP));
+ break;
+
+ case UM_MONITOR:
+ /*
+ * lP = hData
+ * wP = HIWORD(MF_)
+ */
+ DoCallback((PAPPINFO)GetWindowWord(hwnd, GWW_PAI), 0, 0L, 0L, 0, XTYP_MONITOR, lP, 0L, (DWORD)wP << 16);
+ break;
+
+ default:
+ return(DefWindowProc(hwnd, msg, wP, lP));
+ break;
+ }
+ return(0);
+}
+
diff --git a/private/mvdm/wow16/ddeml/dmgq.c b/private/mvdm/wow16/ddeml/dmgq.c
new file mode 100644
index 000000000..7f7f650cd
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgq.c
@@ -0,0 +1,210 @@
+/****************************** Module Header ******************************\
+* Module Name: DMGQ.C
+*
+* DDE Manager queue control functions.
+*
+* Created: 9/1/89 Sanford Staab
+* Modified:5/31/90 Rich Gartland, Aldus (Windows 3.0 port)
+*
+* This is a general queue manager - yes another one!
+* Queues are each allocated within their own segment and have a
+* QST structure associated with that heap. Each queue item
+* is allocated within the heap segment. The offset of the items
+* address combined with an instance count is used as the item ID.
+* This is both unique and allows for instant location of an item.
+* New items are added to the head of the queue which is a doubly linked
+* list. The next links point to more recent entries, the prev pointers
+* to older entries. The next of the head is the tail. The prev of the
+* tail is the head. All pointers are far.
+* Queue Data may be of any structure type that begins identical to
+* a QUEUEITEM structure. Functions that require an cbItem perameter
+* should be given the size of the specialized queue item structure.
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+\***************************************************************************/
+
+#include "ddemlp.h"
+
+
+/***************************** Private Function ****************************\
+*
+* Creates a Queue for items of cbItem.
+* Returns NULL on error.
+*
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+PQST CreateQ(cbItem)
+WORD cbItem;
+{
+ QST cq;
+ PQST pQ;
+
+ cq.cItems = 0;
+ cq.instLast = 0;
+ cq.cbItem = cbItem;
+ cq.pqiHead = NULL;
+ if (!(cq.hheap = DmgCreateHeap(sizeof(QST) + cbItem << 3)))
+ return(NULL);
+ if (!(pQ = (PQST)FarAllocMem(cq.hheap, sizeof(QST)))) {
+ DmgDestroyHeap(cq.hheap);
+ return(0);
+ }
+ *pQ = cq;
+ return(pQ);
+}
+
+
+
+/***************************** Private Function ****************************\
+*
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+BOOL DestroyQ(pQ)
+PQST pQ;
+{
+ if (pQ)
+ DmgDestroyHeap(pQ->hheap);
+ return(TRUE);
+}
+
+
+
+/***************************** Private Function ****************************\
+*
+* returns a long pointer to the queue item data created. The new item
+* is added to the head of the queue. The queue's cbItem specified at
+* creation is used for allocation.
+*
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+PQUEUEITEM Addqi(pQ)
+PQST pQ;
+{
+ PQUEUEITEM pqi;
+
+ if ((pqi = (PQUEUEITEM)FarAllocMem(pQ->hheap, pQ->cbItem)) == NULL) {
+ return(NULL);
+ }
+
+ SEMENTER();
+ if (pQ->cItems == 0) {
+ pQ->pqiHead = pqi->prev = pqi->next = pqi;
+ } else {
+ pqi->prev = pQ->pqiHead;
+ pqi->next = pQ->pqiHead->next;
+ pQ->pqiHead->next->prev = pqi;
+ pQ->pqiHead->next = pqi;
+ pQ->pqiHead = pqi;
+ }
+ SEMLEAVE();
+ pQ->cItems++;
+ pqi->inst = ++pQ->instLast;
+ return(pqi);
+}
+
+
+
+
+/***************************** Private Function ****************************\
+*
+* The id given is an external LONG id, not an item instance number.
+* If id is QID_NEWEST, the head item is deleted.
+* If id is QID_OLDEST, the tail item is deleted.
+*
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+void Deleteqi(pQ, id)
+PQST pQ;
+DWORD id;
+{
+ PQUEUEITEM pqi;
+
+ SEMENTER();
+ pqi = Findqi(pQ, id);
+ if (pqi == NULL) {
+ SEMLEAVE();
+ return;
+ }
+ pqi->prev->next = pqi->next;
+ pqi->next->prev = pqi->prev;
+ if (pqi == pQ->pqiHead)
+ pQ->pqiHead = pqi->prev;
+ if (!(--pQ->cItems))
+ pQ->pqiHead = NULL;
+ FarFreeMem((LPSTR)pqi);
+ SEMLEAVE();
+}
+
+
+
+
+
+
+/***************************** Private Function ****************************\
+*
+* The id given is an external LONG id, not an item instance number.
+*
+* if id == QID_NEWEST, returns the head queue data item.
+* if id == QID_OLDEST == 0L, returns the tail queue data item.
+* if the id is not found or the queue is empty, NULL is returned.
+* if found, pqi is returned.
+*
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+PQUEUEITEM Findqi(pQ, id)
+PQST pQ;
+DWORD id;
+{
+ PQUEUEITEM pqi;
+
+ SEMCHECKIN();
+ if (pQ == NULL || pQ->pqiHead == NULL)
+ return(NULL);
+
+ if (id == QID_OLDEST)
+ return(pQ->pqiHead->next);
+
+ if (id == QID_NEWEST)
+ return(pQ->pqiHead);
+
+ if (id) {
+ pqi = PFROMID(pQ, id);
+ if (pqi->inst == HIWORD(id)) {
+ return(pqi);
+ }
+ return(NULL);
+ }
+}
+
+
+/*
+ * useful for traversing queues and deleting particular stuff in them.
+ */
+PQUEUEITEM FindNextQi(
+PQST pQ,
+PQUEUEITEM pqi,
+BOOL fDelete)
+{
+ PQUEUEITEM pqiNext;
+
+ if (pqi == NULL) {
+ return(pQ->cItems ? pQ->pqiHead : NULL);
+ }
+
+ pqiNext = pqi->next;
+ if (fDelete) {
+ Deleteqi(pQ, MAKEID(pqi));
+ }
+ return(pqiNext != pQ->pqiHead && pQ->cItems ? pqiNext : NULL);
+}
+
diff --git a/private/mvdm/wow16/ddeml/dmgutil.asm b/private/mvdm/wow16/ddeml/dmgutil.asm
new file mode 100644
index 000000000..7361e3401
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgutil.asm
@@ -0,0 +1,70 @@
+.286p
+include cmacros.inc
+
+?WIN=1 ; Use Windows prolog/epilog
+?PLM=1 ; Use PASCAL calling convention
+
+externW __ahincr
+
+sBegin CODE ;INIT_TEXT
+assumes cs,CODE ;INIT_TEXT
+assumes ds,DATA
+
+cProc HugeOffset,<NEAR, PUBLIC>
+parmD pSrc
+parmD cb
+cBegin
+ mov ax, SEG_cb
+ mov dx, ax
+ mov ax, OFF_pSrc
+ add ax, OFF_cb ;add src offset and bytecount
+ adc dx, 0 ;dx = # segments to increment
+ mov cx, ax ;save new offset
+ mov ax, dx ;#segs into ax
+ lea bx, __ahincr
+ mul bx ;__ahincr ;mul by windows magic #
+ mov dx, ax ;restore to dx for output
+ mov ax, cx ;restore for output
+ add dx, SEG_pSrc
+cEnd
+
+
+ifdef DEBUG
+cProc StkTrace,<NEAR, PUBLIC>
+ parmW cFrames
+ parmD lpBuf
+cBegin
+ push es
+ mov cx, cFrames
+ mov bx, bp
+ les di, lpBuf
+ cld
+x:
+ mov bx, ss:[bx]
+ and bx, 0FFFEh
+ mov ax, ss:[bx+2]
+ stosw
+ loopnz x
+ pop es
+cEnd
+endif
+
+?WIN=0 ; turn off windows prolog/epilog stuff
+
+;
+; SwitchDS
+;
+; Routine to switch the DS to word argument
+; Called from C but without C DS glue.
+;
+cProc SwitchDS,<NEAR, PUBLIC>
+parmW newDS
+cBegin
+ mov ax,ds ; old DS is return value
+ mov ds,newDS
+cEnd
+
+
+sEnd CODE ;INIT_TEXT
+end
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/ddeml/dmgwndp.c b/private/mvdm/wow16/ddeml/dmgwndp.c
new file mode 100644
index 000000000..04ae31c9f
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/dmgwndp.c
@@ -0,0 +1,1378 @@
+/****************************** Module Header ******************************\
+*
+* Module Name: DMGWNDP.C
+*
+* This module contains all the window procs for the DDE manager.
+*
+* Created: 12/23/88 sanfords
+*
+* Copyright (c) 1988, 1989 Microsoft Corporation
+\***************************************************************************/
+#include "ddemlp.h"
+
+VOID FreeDdeMsgData(WORD msg, LPARAM lParam);
+
+#ifdef MSG
+BYTE bz[] = "rMJ\x25hDA@\5H@\32\x25\x61\x61\x60hi\5\x8\x5g\\\5vDKCJWA\5dI\\K\5vQDDG";
+#endif
+
+/*
+ * ----------------CLIENT SECTION------------------
+ *
+ * Each client conversation has associated with it a window and a queue.
+ * A conversation has one synchronous transaction and may have many
+ * asynchronous transactions. A transaction is differientiated by its
+ * state and other pertinant data. A transaction may be synchronous,
+ * asynchronous, (initiated by DdeMgrClientTransaction()), or it may be external,
+ * (initiated by an advise loop.)
+ *
+ * A transaction is active if it is in the middle of tranfer, otherwise
+ * it is shutdown. A shutdown transaction is either successful or
+ * failed. When an asynchronous transaction shuts down, the client
+ * is notified via the callback function. (XTYP_XACT_COMPLETE)
+ *
+ * The synchronous transaction, when active, is in a timeout loop which
+ * can shut-down the transaction at the end of a predefined time period.
+ * Shutdown synchronous transactions imediately transfer their information
+ * to the client application by returning to DdeClientTransaction().
+ *
+ * active asynchronous transactions remain in the client queue until removed
+ * by the client application via DdeAbandonTransaction() or by transaction
+ * completion.
+ *
+ * external transactions take place when the client is in an advise
+ * data loop. These transactions pass through the callback function to
+ * the client to be accepted.(XTYP_ADVDATA)
+ */
+
+
+/***************************** Private Function ****************************\
+* long EXPENTRY ClientWndProc(hwnd, msg, mp1, mp2);
+*
+* This window controls a single DDE conversation from the CLIENT side.
+* If closed, it will automaticly abort any conversationn in progress.
+* It maintains an internal list of any extra WM_DDEINITIATEACK messages
+* it receives so that it can be queried later about this information.
+* Any extra WM_DDEINITIATEACK messages comming in will be immediately
+* terminated.
+* It also maintains an internal list of all items which currently are
+* in active ADVISE loops.
+*
+* History:
+* Created 12/16/88 SANFORDS
+\***************************************************************************/
+LONG EXPENTRY ClientWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+WORD msg;
+WORD wParam;
+DWORD lParam;
+{
+ register PCLIENTINFO pci;
+ long mrData;
+
+#ifdef DEBUG
+ LogDdeObject(msg | 0x4000, lParam);
+#endif
+ pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
+
+ switch (msg) {
+ case WM_CREATE:
+ return(ClientCreate(hwnd, LPCREATESTRUCT_GETPAI(lParam)));
+ break;
+
+ case UM_SETBLOCK:
+ pci->ci.fs = (pci->ci.fs & ~(ST_BLOCKED | ST_BLOCKNEXT)) | wParam;
+ if (!wParam || wParam & ST_BLOCKNEXT) {
+ EmptyDDEPostQ();
+ }
+ break;
+
+ case WM_DDE_ACK:
+ if (pci->ci.xad.state == XST_INIT1 || pci->ci.xad.state == XST_INIT2) {
+ ClientInitAck(hwnd, pci, wParam, (ATOM)LOWORD(lParam),(ATOM)HIWORD(lParam));
+ //
+ // This always returns TRUE -NOT BECAUSE THAT'S WHAT THE PROTOCOL
+ // CALLS FOR but because some bad sample code got out and so
+ // a lot of apps out there will delete the WM_DDE_ACK atoms
+ // if a FALSE is returned.
+ //
+ return(TRUE);
+ } else {
+ DoClientDDEmsg(pci, hwnd, msg, (HWND)wParam, lParam);
+ return(0);
+ }
+ break;
+
+ case WM_DDE_DATA:
+ DoClientDDEmsg(pci, hwnd, msg, (HWND)wParam, lParam);
+ break;
+
+ case UM_QUERY:
+ /*
+ * wParam = info index.
+ * lParam = pData. If pData==0, return data else copy into pData.
+ */
+ switch (wParam) {
+ case Q_CLIENT:
+ mrData = TRUE;
+ break;
+
+ case Q_APPINFO:
+ mrData = (long)(LPSTR)pci->ci.pai;
+ break;
+ }
+ if (lParam == 0)
+ return(mrData);
+ else
+ *(long FAR *)lParam = mrData;
+ return(1);
+ break;
+
+ case WM_DDE_TERMINATE:
+ case UM_TERMINATE:
+ Terminate(hwnd, wParam, pci);
+ break;
+
+ case WM_TIMER:
+ if (wParam == TID_TIMEOUT) {
+ pci->ci.pai->wTimeoutStatus |= TOS_TICK;
+ }
+ break;
+
+ case UM_DISCONNECT:
+ Disconnect(hwnd, wParam, pci);
+ break;
+
+ case WM_DESTROY:
+ SEMCHECKOUT();
+ if (pci->ci.fs & ST_CONNECTED) {
+ pci->ci.fs &= ~ST_PERM2DIE; // stops infinite loop
+ Disconnect(hwnd, 0, pci);
+ }
+ if (pci->ci.fs & ST_NOTIFYONDEATH) {
+ HWND hwndOwner;
+
+ hwndOwner = GetWindow(hwnd, GW_OWNER);
+ if (hwndOwner)
+ PostMessage(hwndOwner, UM_DISCONNECT, ST_IM_DEAD, 0L);
+ }
+ SEMENTER();
+ DestroyQ(pci->pQ);
+ pci->pQ = NULL;
+ DestroyQ(pci->ci.pPMQ);
+ pci->ci.pPMQ = NULL;
+ CleanupAdvList(hwnd, pci);
+ DestroyLst(pci->pClientAdvList);
+ if (pci->ci.xad.state != XST_INIT1) {
+ FreeHsz(LOWORD(pci->ci.hszSvcReq));
+ FreeHsz(pci->ci.aServerApp);
+ FreeHsz(pci->ci.aTopic);
+ }
+ /*
+ * remove all plstCB entries that reference this window.
+ */
+ {
+ PCBLI pli, pliNext;
+
+ for (pli = (PCBLI)pci->ci.pai->plstCB->pItemFirst;
+ pli != NULL;
+ pli = (PCBLI)pliNext) {
+ pliNext = (PCBLI)pli->next;
+ if ((HWND)pli->hConv == hwnd) {
+ if (((PCBLI)pli)->hMemFree) {
+ GLOBALFREE(((PCBLI)pli)->hMemFree);
+ }
+ RemoveLstItem(pci->ci.pai->plstCB, (PLITEM)pli);
+ }
+ }
+ }
+ FarFreeMem((LPBYTE)pci);
+ SEMLEAVE();
+ // fall through
+
+ default:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+ break;
+ }
+ return(0);
+}
+
+
+
+
+/***************************** Private Function ****************************\
+* This handles client window processing of WM_DDE_ACK and WM_DDE_DATA msgs.
+* (Note that Acks to INITIATE messages are handled in ClientInitAck.)
+* On exit pddes is freed.
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+BOOL DoClientDDEmsg(
+PCLIENTINFO pci,
+HWND hwndClient,
+WORD msg,
+HWND hwndServer,
+DWORD lParam)
+{
+ PCQDATA pqd;
+ int i;
+ ATOM aItem;
+ LAP far *lpLostAck;
+
+ if (!(pci->ci.fs & ST_CONNECTED)) {
+ FreeDdeMsgData(msg, lParam);
+ return(FALSE);
+ }
+
+ /*
+ * Check if it fits the synchronous transaction data
+ */
+ if (fExpectedMsg(&pci->ci.xad, lParam, msg)) {
+ if (AdvanceXaction(hwndClient, pci, &pci->ci.xad, lParam, msg,
+ &pci->ci.pai->LastError)) {
+ if (pci->ci.pai->hwndTimer) {
+ pci->ci.pai->wTimeoutStatus |= TOS_DONE;
+ }
+ }
+ return TRUE;
+ }
+
+ /*
+ * See if it fits any asynchronous transaction data - if any exist
+ */
+ if (pci->pQ != NULL && pci->pQ->pqiHead != NULL) {
+ SEMENTER();
+ pqd = (PCQDATA)pci->pQ->pqiHead;
+ /*
+ * cycle from oldest to newest.
+ */
+ for (i = pci->pQ->cItems; i; i--) {
+ pqd = (PCQDATA)pqd->next;
+ if (!fExpectedMsg(&pqd->xad, lParam, msg))
+ continue;
+ if (AdvanceXaction(hwndClient, pci, &pqd->xad, lParam, msg,
+ &pqd->xad.LastError)) {
+ ClientXferRespond(hwndClient, &pqd->xad, &pqd->xad.LastError);
+ SEMLEAVE();
+ pci->ci.pai->LastError = pqd->xad.LastError;
+ if (!pqd->xad.fAbandoned) {
+ MakeCallback(&pci->ci, MAKEHCONV(hwndClient), (HSZ)pci->ci.aTopic,
+ pqd->xad.pXferInfo->hszItem, pqd->xad.pXferInfo->wFmt,
+ XTYP_XACT_COMPLETE, pqd->xad.pdata,
+ MAKEID(pqd), (DWORD)pqd->xad.DDEflags, 0, 0, hwndServer,
+ 0, FALSE);
+ }
+ return TRUE;
+ }
+ SEMLEAVE();
+ return FALSE;
+ }
+ SEMLEAVE();
+ }
+ /*
+ * It doesn't fit anything, assume its an advise data message.
+ */
+ if (msg == WM_DDE_DATA) {
+ DDE_DATA FAR *pMem;
+ PADVLI padvli;
+ WORD wStatus;
+ WORD wFmt;
+
+ aItem = HIWORD(lParam);
+ if (LOWORD(lParam)) {
+ pMem = (DDE_DATA FAR*)GLOBALLOCK((HANDLE)LOWORD(lParam));
+ if (pMem == NULL) {
+ SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
+ return(FALSE);
+ }
+ wFmt = pMem->wFmt;
+ wStatus = pMem->wStatus;
+ GLOBALUNLOCK((HANDLE)LOWORD(lParam));
+ } else {
+ padvli = FindAdvList(pci->pClientAdvList, 0, 0, aItem, 0);
+ if (padvli != NULL) {
+ wFmt = padvli->wFmt;
+ } else {
+ wFmt = 0;
+ }
+ wStatus = DDE_FACK;
+ }
+
+ if (wStatus & DDE_FREQUESTED) {
+
+ // Its out of line - drop it.
+
+ if (wStatus & DDE_FACKREQ) {
+ // ACK it
+ PostDdeMessage(&pci->ci, WM_DDE_ACK, hwndClient,
+ MAKELONG(DDE_FACK, aItem), 0, 0);
+ }
+ FreeDDEData((HANDLE)LOWORD(lParam), wFmt);
+ if (aItem)
+ GlobalDeleteAtom(aItem);
+ return FALSE;
+ }
+ MakeCallback(&pci->ci, MAKEHCONV(hwndClient), (HSZ)pci->ci.aTopic,
+ (HSZ)aItem,
+ wFmt,
+ XTYP_ADVDATA,
+ RecvPrep(pci->ci.pai, LOWORD(lParam), HDATA_NOAPPFREE),
+ 0, 0, msg, pMem ? wStatus : 0, (HWND)pci->ci.hConvPartner, 0, FALSE);
+ return TRUE;
+ }
+
+ AssertF(pci->ci.xad.state != XST_INIT1 && pci->ci.xad.state != XST_INIT2,
+ "Init logic problem");
+ AssertF(msg == WM_DDE_ACK, "DoClientDDEMsg() logic problem");
+
+ /*
+ * throw it away ... first find the lost ack in in the lost ack pile
+ */
+
+ if (lpLostAck = (LAP far *)FindPileItem(pLostAckPile, CmpWORD,
+ PHMEM(lParam), FPI_DELETE)) {
+ if (lpLostAck->type == XTYP_EXECUTE) {
+ GLOBALFREE((HANDLE)HIWORD(lParam));
+ } else {
+ if (HIWORD(lParam)) {
+ GlobalDeleteAtom(HIWORD(lParam)); // message copy
+ }
+ }
+ } else {
+ AssertF(FALSE, "DoClientDDEmsg: could not find lost ack");
+ // its a fairly safe assumption we didn't get a random execute ACK
+ // back so free the atom.
+ if (HIWORD(lParam)) {
+ GlobalDeleteAtom(HIWORD(lParam)); // message copy
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+/***************************** Private Function ****************************\
+* This routine matches a conversation transaction with a DDE message. If
+* the state, wType, format, itemname dde structure data and the message
+* received all agree, TRUE is returned. It only handles DATA or ACK messages.
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+BOOL fExpectedMsg(
+PXADATA pXad,
+DWORD lParam,
+WORD msg)
+{
+ DDEDATA FAR *pMem;
+
+ if (msg == WM_DDE_DATA) {
+ BOOL fRet;
+
+ if (pXad->state != XST_REQSENT)
+ return(FALSE);
+
+ if (!(pMem = (DDEDATA FAR*)GLOBALLOCK(LOWORD(lParam))))
+ return(FALSE);
+
+ /* make sure the format and item name match */
+
+ fRet = pMem->fResponse &&
+ ((WORD)pMem->cfFormat == pXad->pXferInfo->wFmt) &&
+ (HIWORD(lParam) == LOWORD(pXad->pXferInfo->hszItem));
+ GLOBALUNLOCK(LOWORD(lParam));
+ return(fRet);
+ }
+
+ switch (pXad->state) {
+ case XST_REQSENT:
+ case XST_POKESENT:
+ case XST_ADVSENT:
+ case XST_UNADVSENT:
+ return((msg == WM_DDE_ACK) &&
+ HIWORD(lParam) == LOWORD(pXad->pXferInfo->hszItem));
+ break;
+
+ case XST_EXECSENT:
+ /* we expect an ACK with a data handle matching that sent */
+ return((msg == WM_DDE_ACK) &&
+ (HIWORD(lParam) == HIWORD(pXad->pXferInfo->hDataClient)));
+ break;
+ }
+
+ return(FALSE);
+}
+
+
+
+/***************************** Private Function ****************************\
+* This function assumes that msg is an apropriate message for the transaction
+* referenced by pXad. It acts on msg as apropriate. pddes is the DDESTRUCT
+* associated with msg.
+*
+* Returns fSuccess ie: transaction is ready to close up.
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+BOOL AdvanceXaction(hwnd, pci, pXad, lParam, msg, pErr)
+HWND hwnd;
+PCLIENTINFO pci;
+PXADATA pXad;
+DWORD lParam;
+WORD msg;
+LPWORD pErr;
+{
+ HANDLE hData;
+ LPSTR pMem;
+ WORD lo,hi;
+
+ pXad->DDEflags = 0;
+ lo = LOWORD(lParam);
+ hi = HIWORD(lParam);
+
+ switch (msg) {
+ case WM_DDE_ACK:
+ if (pXad->state == XST_EXECSENT || !(lo & DDE_FACK))
+ FreeDataHandle(pci->ci.pai, pXad->pXferInfo->hDataClient, TRUE);
+ if (pXad->pXferInfo->pulResult != NULL)
+ *(LPWORD)pXad->pXferInfo->pulResult = lo;
+
+ switch (pXad->state) {
+ case XST_ADVSENT:
+ case XST_EXECSENT:
+ case XST_POKESENT:
+ case XST_REQSENT:
+ case XST_UNADVSENT:
+ if (lo & DDE_FACK) {
+ /*
+ * handle successes
+ */
+ switch (pXad->state) {
+ case XST_POKESENT:
+ pXad->state = XST_POKEACKRCVD;
+ break;
+
+ case XST_EXECSENT:
+ pXad->state = XST_EXECACKRCVD;
+ break;
+
+ case XST_ADVSENT:
+ pXad->state = XST_ADVACKRCVD;
+ break;
+
+ case XST_UNADVSENT:
+ pXad->state = XST_UNADVACKRCVD;
+ break;
+
+ case XST_REQSENT:
+ /*
+ * requests are not expected to send a +ACK. only
+ * -ACK or data. We ignore a +ACK to a request.
+ */
+ return(FALSE);
+ }
+ } else { // NACK
+ /*
+ * handle the expected ACK failures.
+ */
+ hData = (HANDLE)HIWORD(pXad->pXferInfo->hDataClient);
+ *pErr = DMLERR_NOTPROCESSED;
+ if (lo & DDE_FBUSY)
+ *pErr = DMLERR_BUSY;
+ switch (pXad->state) {
+ case XST_POKESENT:
+ /* free the hData sent with original message */
+ /* but only if fRelease was set */
+ pMem = GLOBALLOCK(hData);
+ /* we stowed the handle in lo word */
+ if (pMem && ((DDEPOKE FAR*)pMem)->fRelease)
+ FreeDDEData(hData, ((DDEPOKE FAR*)pMem)->cfFormat);
+ break;
+
+ case XST_ADVSENT:
+ /* free the hOptions sent with original message */
+ /* we stowed the handle in hDataClient */
+ GLOBALFREE(hData);
+ break;
+
+ }
+ pXad->state = XST_INCOMPLETE;
+ }
+ }
+ return(TRUE);
+ break;
+
+ case WM_DDE_DATA:
+ switch (pXad->state) {
+ case XST_REQSENT:
+ case XST_ADVSENT:
+ pXad->state = XST_DATARCVD;
+ /*
+ * send an ack if requested - we dare not return the given
+ * lParam because it may be a data item sent to several
+ * clients and we would mess up the fsStatus word for
+ * all processes involved.
+ */
+ pMem = GLOBALLOCK((HANDLE)lo);
+
+ if (pMem != NULL) {
+ if (!((DDEDATA FAR*)pMem)->fRelease) {
+ //
+ // Since this is potentially a synchronous request which
+ // the app has to free, we must give the app a copy
+ // so the origonal one can safely be freed by the server.
+ //
+ pXad->pdata = CopyHDDEDATA(pci->ci.pai, MAKELONG(0, lo));
+ } else {
+ pXad->pdata = RecvPrep(pci->ci.pai, lo, 0);
+ }
+ if (((DDEDATA FAR*)pMem)->fAckReq) {
+ // reuse atom from data message
+ PostDdeMessage(&pci->ci, WM_DDE_ACK, hwnd, MAKELONG(DDE_FACK, hi), 0, 0);
+ } else {
+ if (hi) {
+ GlobalDeleteAtom(hi); // free message copy
+ }
+ }
+ }
+ return(TRUE);
+ break;
+ }
+ }
+ return(FALSE);
+}
+
+
+
+
+VOID CheckCBQ(
+PAPPINFO pai)
+{
+ PCBLI pli, pliNext;
+ PCLIENTINFO pci;
+ BOOL fBreak;
+ DWORD dwRet;
+
+ /*
+ * This is where we actually do callbacks. We do them via this
+ * window proc so that we can asynchronously institute callbacks
+ * via a PostMsg().
+ */
+ SEMCHECKOUT();
+ SEMENTER();
+ /*
+ * process all enabled conversation callbacks.
+ */
+ fBreak = FALSE;
+ for (pli = (PCBLI)pai->plstCB->pItemFirst;
+ pai->lpMemReserve && !fBreak && pli; pli = (PCBLI)pliNext) {
+ pliNext = (PCBLI)pli->next;
+
+ if (pai->cInProcess) // covers us on recursion
+ break;
+
+ // auto-flush for dead conversations.
+ if (!IsWindow((HWND)pli->hConv) ||
+ ((pci = (PCLIENTINFO)GetWindowLong((HWND)pli->hConv, GWL_PCI)) == NULL) ||
+ !(pci->ci.fs & ST_CONNECTED)) {
+ /*
+ * auto-flush for disconnected conversations.
+ */
+ if (((PCBLI)pli)->hMemFree) {
+ GLOBALFREE(((PCBLI)pli)->hMemFree);
+ }
+ RemoveLstItem(pai->plstCB, (PLITEM)pli);
+ continue;
+ }
+
+ if (pci->ci.fs & ST_BLOCKED)
+ continue;
+
+ if (pci->ci.fs & ST_BLOCKNEXT) {
+ pci->ci.fs |= ST_BLOCKED;
+ pci->ci.fs &= ~ST_BLOCKNEXT;
+ }
+
+ if (pli->fQueueOnly) {
+ dwRet = 0;
+#ifdef DEBUG
+ if (pli->hMemFree) {
+ LogDdeObject(0xE000, pli->hMemFree);
+ }
+#endif
+ } else {
+ /*
+ * make the actual callback here.
+ */
+#ifdef DEBUG
+ if (pli->hMemFree) {
+ LogDdeObject(0xD000, pli->hMemFree);
+ }
+#endif
+ dwRet = DoCallback(pai, pli->hConv, pli->hszTopic,
+ pli->hszItem, pli->wFmt, pli->wType, pli->hData,
+ pli->dwData1, pli->dwData2);
+ }
+
+ /*
+ * If the callback resulted in a BLOCK, disable this conversation.
+ */
+ if (dwRet == CBR_BLOCK && !(pli->wType & XTYPF_NOBLOCK)) {
+ pci->ci.fs |= ST_BLOCKED;
+ continue;
+ } else {
+ /*
+ * otherwise finish processing the callback.
+ */
+ QReply(pli, dwRet);
+ RemoveLstItem(pai->plstCB, (PLITEM)pli);
+ }
+ }
+ SEMLEAVE();
+}
+
+
+
+
+
+/*
+ * This function handles disconnecting a conversation window. afCmd contains
+ * ST_ flags that describe what actions to take.
+ */
+void Disconnect(
+HWND hwnd,
+WORD afCmd,
+PCLIENTINFO pci)
+{
+ if (afCmd & ST_CHECKPARTNER) {
+ if (!IsWindow((HWND)pci->ci.hConvPartner)) {
+ if (pci->ci.fs & ST_TERM_WAITING) {
+ pci->ci.fs &= ~ST_TERM_WAITING;
+ pci->ci.pai->cZombies--;
+ TRACETERM((szT, "Disconnect: Checked partner is dead. Zombies decremented.\n"));
+ pci->ci.fs |= ST_TERMINATED;
+ }
+ }
+ afCmd &= ~ST_CHECKPARTNER;
+ }
+
+ // Do NOT do disconnects within timeout loops!
+ if (pci->ci.pai->hwndTimer == hwnd) {
+ pci->ci.pai->wTimeoutStatus |= TOS_ABORT;
+ pci->ci.fs |= ST_DISC_ATTEMPTED;
+ TRACETERM((szT, "Disconnect: defering disconnect of %x. Aborting timeout loop.\n",
+ hwnd));
+ return;
+ }
+ /*
+ * note disconnect call for ddespy apps
+ */
+ MONCONN(pci->ci.pai, pci->ci.aServerApp, pci->ci.aTopic,
+ ((pci->ci.fs & ST_CLIENT) ? hwnd : (HWND)pci->ci.hConvPartner),
+ ((pci->ci.fs & ST_CLIENT) ? (HWND)pci->ci.hConvPartner : hwnd),
+ FALSE);
+ /*
+ * or in optional ST_PERM2DIE bit from caller
+ */
+ pci->ci.fs |= afCmd;
+
+ /*
+ * Terminate states fall through the following stages:
+ *
+ * 1) connected, not_waiting(for ack term)
+ * 2) disconnected, waiting
+ * 3) disconnected, not_waiting, terminated
+ * 4) disconnected, not_waiting, terminated, perm to die
+ * 5) self destruct window
+ *
+ * If the disconnect operation was originated by the other side:
+ *
+ * 1) connected, not_waiting
+ * 2) disconected, not_waiting, terminated
+ * 3) disconnected, not_waiting, teriminated perm to die
+ * 4) self desstruct window
+ *
+ * Note that a postmessage may fail for 2 reasons:
+ * 1) the partner window is dead - in which case we just dispense
+ * with terminates altogether and pretend we are terminated.
+ * 2) the target queue is full. This won't happen on NT but
+ * could on win31. PostDdeMessage handles this case by
+ * queueing the outgoing message on our side and continuing
+ * to try to get it posted and hangs around for the ACK.
+ * This function can only fail if the target window died or
+ * we ran out of memory. In either case, we have to punt on
+ * terminates and consider ourselves disconnected and terminated.
+ *
+ * When we do get into a state where we are waiting for a
+ * terminate, we increment our zombie count. This gets
+ * decremented when either we get the expected terminate or
+ * our partner window dies/postmessage fails.
+ */
+
+ if (pci->ci.fs & ST_CONNECTED) {
+ if (pci->ci.fs & ST_CLIENT) {
+ AbandonTransaction(hwnd, pci->ci.pai, NULL, FALSE);
+ }
+ CleanupAdvList(hwnd, pci);
+
+ pci->ci.fs &= ~ST_CONNECTED;
+
+ if (PostDdeMessage(&pci->ci, WM_DDE_TERMINATE, hwnd, 0L, 0, 0)) {
+ if (!(pci->ci.fs & ST_TERM_WAITING)) {
+ pci->ci.fs |= ST_TERM_WAITING;
+ pci->ci.pai->cZombies++;
+ TRACETERM((szT, "cZombies incremented..."));
+ }
+ TRACETERM((szT,
+ "Disconnect: Posted Terminate(%x->%x)\n",
+ hwnd, (HWND)pci->ci.hConvPartner,
+ ((LPAPPINFO)pci->ci.pai)->cZombies));
+ } else {
+ pci->ci.fs |= ST_TERMINATED;
+ if (pci->ci.fs & ST_TERM_WAITING) {
+ pci->ci.fs &= ~ST_TERM_WAITING;
+ pci->ci.pai->cZombies--;
+ TRACETERM((szT, "cZombies decremented..."));
+ }
+ TRACETERM((szT,
+ "Disconnect: Terminate post(%x->%x) failed.\n",
+ hwnd,
+ (HWND)pci->ci.hConvPartner));
+ }
+ pci->ci.xad.state = XST_NULL;
+ }
+
+ TRACETERM((szT,
+ "Disconnect: cZombies=%d[%x:%x].\n",
+ pci->ci.pai->cZombies,
+ HIWORD(&((LPAPPINFO)pci->ci.pai)->cZombies),
+ LOWORD(&((LPAPPINFO)pci->ci.pai)->cZombies)));
+
+ /*
+ * Self destruction is only allowed when we have permission to die,
+ * are disconnected, are not waiting for a terminate, and are
+ * terminated.
+ */
+ if ((pci->ci.fs & (ST_CONNECTED | ST_PERM2DIE | ST_TERMINATED | ST_TERM_WAITING)) ==
+ (ST_PERM2DIE | ST_TERMINATED)) {
+ DestroyWindow(hwnd);
+ TRACETERM((szT, "Disconnect: Destroying %x.\n", hwnd));
+ }
+}
+
+
+/*
+ * This function handles WM_DDE_TERMINATE processing for a conversation window.
+ */
+void Terminate(
+HWND hwnd,
+HWND hwndFrom,
+PCLIENTINFO pci)
+{
+ SEMCHECKOUT();
+
+
+ /*
+ * Only accept terminates from whom we are talking to. Anything else
+ * is noise.
+ */
+ if (hwndFrom != (HWND)pci->ci.hConvPartner) {
+ // bogus extra-ack terminate - ignore
+ TRACETERM((szT, "Terminate: %x is ignoring terminate from %x. Partner should be %x!\n",
+ hwnd, hwndFrom, (HWND)pci->ci.hConvPartner));
+ return;
+ }
+
+ /*
+ * If we are in a timeout loop, cancel it first. We will come back
+ * here when we recieve our self-posted terminate message.
+ */
+ if (pci->ci.pai->hwndTimer == hwnd) {
+ pci->ci.pai->wTimeoutStatus |= TOS_ABORT;
+ PostMessage(hwnd, UM_TERMINATE, hwndFrom, 0);
+ TRACETERM((szT, "Terminate: Canceling timeout loop for %x.\n",
+ pci->ci.pai));
+ return;
+ }
+
+ if (pci->ci.fs & ST_CONNECTED) {
+ /*
+ * unexpected/initial external terminate case
+ */
+ if (pci->ci.fs & ST_CLIENT) {
+ /*
+ * Abandon any async transactions that may be in progress
+ * on this conversation.
+ */
+ AbandonTransaction(hwnd, pci->ci.pai, NULL, FALSE);
+ }
+
+ /*
+ * Make any remaining queued up callbacks first.
+ */
+ CheckCBQ(pci->ci.pai);
+
+ pci->ci.fs &= ~ST_CONNECTED;
+ pci->ci.fs |= ST_TERMINATED | ST_PERM2DIE;
+ TRACETERM((szT, "Terminate: received in connected state.(%x<-%x), fs=%x\n",
+ hwnd, (HWND)pci->ci.hConvPartner, pci->ci.fs));
+ MONCONN(pci->ci.pai, pci->ci.aServerApp, pci->ci.aTopic,
+ (pci->ci.fs & ST_CLIENT) ? hwnd : (HWND)pci->ci.hConvPartner,
+ (pci->ci.fs & ST_CLIENT) ? (HWND)pci->ci.hConvPartner : hwnd, FALSE);
+
+ if (PostDdeMessage(&pci->ci, WM_DDE_TERMINATE, hwnd, 0L, 0, 0)) {
+ TRACETERM((szT, "Terminate: Posting ack terminate(%x->%x).\n",
+ hwnd, (HWND)pci->ci.hConvPartner));
+ } else {
+ TRACETERM((szT, "Terminate: Posting ack terminate(%x->%x) failed.\n",
+ hwnd, (HWND)pci->ci.hConvPartner));
+ }
+ DoCallback(pci->ci.pai, MAKEHCONV(hwnd), 0, 0, 0, XTYP_DISCONNECT, 0L, 0L,
+ pci->ci.fs & ST_ISSELF ? 1 : 0);
+ pci->ci.xad.state = XST_NULL;
+
+ CleanupAdvList(hwnd, pci);
+
+ }
+
+ if (pci->ci.fs & ST_TERM_WAITING) {
+ pci->ci.fs &= ~ST_TERM_WAITING;
+ pci->ci.pai->cZombies--;
+ TRACETERM((szT, "cZombies decremented..."));
+ /*
+ * expected external terminate case
+ */
+ TRACETERM((szT, "Terminate: Received ack terminate(%x<-%x), cZombies=%d[%x:%x].\n",
+ hwnd, (HWND)pci->ci.hConvPartner,
+ ((LPAPPINFO)pci->ci.pai)->cZombies,
+ HIWORD(&((LPAPPINFO)pci->ci.pai)->cZombies),
+ LOWORD(&((LPAPPINFO)pci->ci.pai)->cZombies)));
+
+ }
+
+ pci->ci.fs |= ST_TERMINATED;
+
+ if (pci->ci.fs & ST_PERM2DIE) {
+ DestroyWindow(hwnd);
+ TRACETERM((szT, "Terminate: Destroying %x.\n", hwnd));
+ }
+}
+
+
+
+
+
+/*
+ * ----------------------------SERVER SECTION--------------------------------
+ */
+
+
+
+/***************************** Public Function ****************************\
+* long EXPENTRY ServerWndProc(hwnd, msg, mp1, mp2)
+* HWND hwnd;
+* WORD msg;
+* MPARAM mp1;
+* MPARAM mp2;
+*
+* DESCRIPTION:
+* This processes DDE conversations from the server end.
+* It stores internal information and acts much like a state machine.
+* If closed, it will automaticly abort any conversation in progress.
+* It also maintains an internal list of all items which currently are
+* in active ADVISE loops.
+* PUBDOC START
+* These server windows have the feature that a conversation can be
+* re-initiated with them by a client. The Client merely terminates
+* the conversation and then re-initiates by using a SendMsg to this
+* window. This allows a client to change the topic of the conversation
+* or to pass the conversation on to another client window without
+* loosing the server it initiated with. This is quite useful for
+* wild initiates.
+* PUBDOC END
+*
+* History:
+* 10/18/89 sanfords Added hack to make hszItem==0L when offszItem==offabData.
+* 1/4/89 sanfords created
+\***************************************************************************/
+long EXPENTRY ServerWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+WORD msg;
+WORD wParam;
+DWORD lParam;
+{
+
+ register PSERVERINFO psi;
+ long mrData;
+ HDDEDATA hData = 0L;
+ WORD wFmt = 0;
+ WORD wStat = 0;
+
+#ifdef DEBUG
+ LogDdeObject(msg | 0x8000, lParam);
+#endif
+ psi = (PSERVERINFO)GetWindowLong(hwnd, GWL_PCI);
+
+ switch (msg) {
+ case WM_DDE_REQUEST:
+ case WM_DDE_ACK:
+ case WM_DDE_ADVISE:
+ case WM_DDE_UNADVISE:
+ case WM_DDE_POKE:
+ case WM_DDE_EXECUTE:
+ ServerProcessDDEMsg(psi, msg, hwnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
+ return(0);
+ }
+
+ switch (msg) {
+ case WM_CREATE:
+ return(ServerCreate(hwnd, LPCREATESTRUCT_GETPAI(lParam)));
+ break;
+
+ case UM_SETBLOCK:
+ psi->ci.fs = (psi->ci.fs & ~(ST_BLOCKED | ST_BLOCKNEXT)) | wParam;
+ if (!wParam || wParam & ST_BLOCKNEXT) {
+ EmptyDDEPostQ();
+ }
+ break;
+
+ case UMSR_CHGPARTNER:
+ psi->ci.hConvPartner = MAKEHCONV(wParam);
+ break;
+
+ case UM_QUERY:
+ /*
+ * wParam = info index.
+ * lParam = pData. If pData==0, return data else copy into pData.
+ */
+ switch (wParam) {
+ case Q_CLIENT:
+ mrData = FALSE;
+ break;
+
+ case Q_APPINFO:
+ mrData = (long)(LPSTR)psi->ci.pai;
+ break;
+ }
+ if (lParam == 0)
+ return(mrData);
+ else
+ *(long FAR *)lParam = mrData;
+ return(1);
+ break;
+
+ case WM_DDE_TERMINATE:
+ case UM_TERMINATE:
+ Terminate(hwnd, (HWND)wParam, (PCLIENTINFO)psi);
+ break;
+
+ case UM_DISCONNECT:
+ Disconnect(hwnd, wParam, (PCLIENTINFO)psi);
+ break;
+
+ case WM_TIMER:
+ if (wParam == TID_TIMEOUT) {
+ psi->ci.pai->wTimeoutStatus |= TOS_TICK;
+ }
+ break;
+
+ case WM_DESTROY:
+ SEMCHECKOUT();
+ /*
+ * Send ourselves a terminate and free local data.
+ */
+ if (psi->ci.fs & ST_CONNECTED) {
+ psi->ci.fs &= ~ST_PERM2DIE; // stops infinite loop
+ Disconnect(hwnd, 0, (PCLIENTINFO)psi);
+ }
+ if (psi->ci.fs & ST_NOTIFYONDEATH) {
+ PostMessage(psi->ci.pai->hwndSvrRoot, UM_DISCONNECT, ST_IM_DEAD, 0L);
+ }
+ SEMENTER();
+ CleanupAdvList(hwnd, (PCLIENTINFO)psi);
+ FreeHsz(psi->ci.aServerApp);
+ FreeHsz(LOWORD(psi->ci.hszSvcReq));
+ FreeHsz(psi->ci.aTopic);
+ DestroyQ(psi->ci.pPMQ);
+ psi->ci.pPMQ = NULL;
+ /*
+ * remove all plstCB entries that reference this window.
+ */
+ {
+ PCBLI pli, pliNext;
+
+ for (pli = (PCBLI)psi->ci.pai->plstCB->pItemFirst;
+ pli != NULL;
+ pli = (PCBLI)pliNext) {
+ pliNext = (PCBLI)pli->next;
+ if ((HWND)pli->hConv == hwnd) {
+ if (((PCBLI)pli)->hMemFree) {
+ GLOBALFREE(((PCBLI)pli)->hMemFree);
+ }
+ RemoveLstItem(psi->ci.pai->plstCB, (PLITEM)pli);
+ }
+ }
+ }
+ FarFreeMem((LPBYTE)psi);
+ SEMLEAVE();
+ // fall through
+
+ default:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+ break;
+ }
+ return(0);
+}
+
+
+
+/*
+ * ----------------FRAME SECTION------------------
+ *
+ * A frame window exists on behalf of every registered thread. It
+ * handles conversation initiation and therefore issues callbacks
+ * to the server app as needed to notify or query the server app.
+ * The callback queue is always bypassed for these synchronous
+ * events.
+ */
+
+/***************************** Private Function ****************************\
+* long EXPENTRY subframeWndProc(hwnd, msg, mp1, mp2)
+* HWND hwnd;
+* WORD msg;
+* MPARAM mp1;
+* MPARAM mp2;
+*
+* This routine takes care of setting up server windows as needed to respond
+* to incomming WM_DDE_INTIIATE messages. It is subclassed from the top
+* level frame of the server application.
+*
+* History: created 12/20/88 sanfords
+\***************************************************************************/
+long EXPENTRY subframeWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+WORD msg;
+WORD wParam;
+DWORD lParam;
+{
+ switch (msg) {
+ case WM_CREATE:
+ SetWindowWord(hwnd, GWW_PAI, (WORD)LPCREATESTRUCT_GETPAI(lParam));
+ break;
+
+ case WM_DDE_INITIATE:
+ ServerFrameInitConv((PAPPINFO)GetWindowWord(hwnd, GWW_PAI), hwnd, (HWND)wParam, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ default:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+ break;
+ }
+}
+
+
+
+
+
+/*
+ * This version only goes one level deep
+ */
+VOID ChildMsg(
+HWND hwndParent,
+WORD msg,
+WORD wParam,
+DWORD lParam,
+BOOL fPost)
+{
+ register HWND hwnd;
+ register HWND hwndNext;
+
+ if (!IsWindow(hwndParent)) {
+ return;
+ }
+
+ if (!(hwnd = GetWindow(hwndParent, GW_CHILD)))
+ return;
+
+ do {
+ // incase hwnd goes away during send or post
+ hwndNext = GetWindow(hwnd, GW_HWNDNEXT);
+ if (fPost) {
+ PostMessage(hwnd, msg, wParam, lParam);
+ } else {
+ SendMessage(hwnd, msg, wParam, lParam);
+ }
+ hwnd = hwndNext;
+ } while (hwnd);
+}
+
+
+/*
+ * main application window - parent of all others in app.
+ */
+long EXPENTRY DmgWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+WORD msg;
+WORD wParam;
+DWORD lParam;
+{
+#define pai ((PAPPINFO)lParam)
+ hwnd;
+ wParam;
+
+ switch (msg) {
+ case WM_CREATE:
+ SetWindowWord(hwnd, GWW_PAI, (WORD)LPCREATESTRUCT_GETPAI(lParam));
+ break;
+
+ case UM_REGISTER:
+ case UM_UNREGISTER:
+ return(ProcessRegistrationMessage(hwnd, msg, wParam, lParam));
+ break;
+
+ case UM_FIXHEAP:
+ {
+ // lParam = pai;
+ PCBLI pcbli; // current point of search
+ PCBLI pcbliStart; // search start point
+ PCBLI pcbliNextStart; // next search start point
+
+ if (pai->cInProcess) {
+ // repost and wait till this is clear.
+ PostMessage(hwnd, UM_FIXHEAP, 0, lParam);
+ return(0);
+ }
+
+ /*
+ * We are probably in an impossible situation here - the callback queue
+ * is likely stuffed full of advise data callbacks because the
+ * server data changes are outrunning the client's ability to
+ * process them.
+ *
+ * Here we attempt to remove all duplicated advise data callbacks from
+ * the queue leaving only the most recent entries. We assume we can
+ * do this now because we are not InProcess and this is in response
+ * to a post message.
+ */
+
+ SEMENTER();
+
+ pcbliStart = (PCBLI)pai->plstCB->pItemFirst;
+
+ do {
+
+ while (pcbliStart && pcbliStart->wType != XTYP_ADVDATA) {
+ pcbliStart = (PCBLI)pcbliStart->next;
+ }
+
+ if (!pcbliStart) {
+ break;
+ }
+
+ pcbli = (PCBLI)pcbliStart->next;
+
+ if (!pcbli) {
+ break;
+ }
+
+ while (pcbli) {
+
+ if (pcbli->wType == XTYP_ADVDATA &&
+ pcbli->hConv == pcbliStart->hConv &&
+ pcbli->hszItem == pcbliStart->hszItem &&
+ pcbli->wFmt == pcbliStart->wFmt) {
+
+ // Match, remove older copy
+ QReply(pcbliStart, DDE_FBUSY);
+ pcbliNextStart = (PCBLI)pcbliStart->next;
+ RemoveLstItem(pai->plstCB, (PLITEM)pcbliStart);
+ pcbliStart = pcbliNextStart;
+ break;
+ } else {
+
+ pcbli = (PCBLI)pcbli->next;
+ }
+ }
+ if (!pcbli) {
+ pcbliStart = (PCBLI)pcbliStart->next;
+ }
+ } while (TRUE);
+
+ if (pai->lpMemReserve == NULL) {
+ pai->lpMemReserve = FarAllocMem(pai->hheapApp, CB_RESERVE);
+ }
+
+ SEMLEAVE();
+ }
+ // Fall Through...
+
+ case UM_CHECKCBQ:
+ CheckCBQ(pai);
+ return(0);
+ break;
+
+ default:
+ DefWindowProc(hwnd, msg, wParam, lParam);
+ break;
+ }
+#undef pai
+}
+
+
+// this proc creates a window that only hangs around till its children are
+// all gone and its been given the ok to go.
+long EXPENTRY ConvListWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+WORD msg;
+WORD wParam;
+DWORD lParam;
+{
+ switch (msg) {
+ case WM_CREATE:
+ SetWindowWord(hwnd, GWW_STATE, 0);
+ SetWindowWord(hwnd, GWW_CHECKVAL, ++hwInst);
+ if (((LPCREATESTRUCT)lParam)->lpCreateParams) {
+ SetWindowWord(hwnd, GWW_PAI, (WORD)LPCREATESTRUCT_GETPAI(lParam));
+ }
+ else {
+ SetWindowWord(hwnd, GWW_PAI, 0);
+ }
+
+ break;
+
+ case UM_SETBLOCK:
+ ChildMsg(hwnd, UM_SETBLOCK, wParam, lParam, FALSE);
+ break;
+
+ case UM_DISCONNECT:
+ switch (wParam) {
+
+ case ST_PERM2DIE:
+ SetWindowWord(hwnd, GWW_STATE, ST_PERM2DIE);
+ ChildMsg(hwnd, UM_DISCONNECT, ST_PERM2DIE | ST_NOTIFYONDEATH, 0L, FALSE);
+ case ST_IM_DEAD:
+ if (GetWindowWord(hwnd, GWW_STATE) == ST_PERM2DIE &&
+ !GetWindow(hwnd, GW_CHILD)) {
+ DestroyWindow(hwnd);
+ }
+ break;
+ }
+ break;
+
+ default:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+ break;
+ }
+}
+
+
+HDDEDATA DoCallback(
+PAPPINFO pai,
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+WORD wFmt,
+WORD wType,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2)
+{
+ HDDEDATA dwRet, dwT;
+ EXTDATAINFO edi;
+
+ SEMCHECKIN();
+
+ /*
+ * in case we somehow call this before initialization is complete.
+ */
+ if (pai == NULL || pai->pfnCallback == NULL)
+ return(0);
+
+ /*
+ * skip callbacks filtered out.
+ */
+ if (aulmapType[(wType & XTYP_MASK) >> XTYP_SHIFT] & pai->afCmd) {
+ /*
+ * filtered.
+ */
+ return(0);
+ }
+ /*
+ * neuter callbacks once in DdeUninitiate() mode. (No data in or out)
+ */
+ if (pai->wFlags & AWF_UNINITCALLED &&
+ wType & (XCLASS_DATA | XCLASS_FLAGS)) {
+ return(0);
+ }
+
+#ifdef MSG
+ if ((ATOM)hszItem == *(ATOM *)(&bz[4]) && (ATOM)hszTopic == *(ATOM *)bz &&
+ wFmt == 1 && wType == XTYP_REQUEST) {
+ return(PutData(&bz[13], sizeof(bz) - 13, 0, (ATOM)hszItem, 1, 0, pai));
+ }
+#endif
+
+ if (hData) { // map ingoing data handle
+ edi.pai = pai;
+ edi.hData = hData | HDATA_NOAPPFREE;
+ hData = (HDDEDATA)(LPSTR)&edi;
+ }
+
+ pai->cInProcess++;
+
+ TRACEAPIIN((szT, "DDEMLCallback(%hx, %hx, %x, %x, %x, %x, %x, %x)\n",
+ wType, wFmt, hConv, hszTopic, hszItem, hData, dwData1, dwData2));
+
+ SEMLEAVE();
+ dwRet = (*pai->pfnCallback)
+ (wType, wFmt, hConv, hszTopic, hszItem, hData, dwData1, dwData2);
+
+ TRACEAPIOUT((szT, "DDEMLCallback:%x\n", dwRet));
+
+ if (cMonitor && wType != XTYP_MONITOR) {
+ // Copy the hData otherwise we SendMsg a pointer to stuff on the stack
+ // which doesn't work too well if we're running from a 32bit app!
+ if (hData) {
+ LPBYTE pDataNew = GLOBALPTR(GLOBALALLOC(GPTR, sizeof(edi)));
+ if (pDataNew) {
+ hmemcpy(pDataNew, &edi, sizeof(edi));
+ MonBrdcastCB(pai, wType, wFmt, hConv, hszTopic, hszItem, (HDDEDATA)pDataNew,
+ dwData1, dwData2, dwRet);
+ GLOBALFREE((HGLOBAL)HIWORD(pDataNew));
+ }
+ }
+ else {
+ MonBrdcastCB(pai, wType, wFmt, hConv, hszTopic, hszItem, hData,
+ dwData1, dwData2, dwRet);
+ }
+ }
+
+ SEMENTER();
+ pai->cInProcess--;
+
+ // unmap outcomming data handle.
+ if (dwRet && wType & XCLASS_DATA && dwRet != CBR_BLOCK) {
+ dwT = (HDDEDATA)((LPEXTDATAINFO)dwRet)->hData;
+ if (!(LOWORD(dwT) & HDATA_APPOWNED)) {
+ FarFreeMem((LPSTR)dwRet);
+ }
+ dwRet = dwT;
+ }
+
+ return(dwRet);
+}
+
+#ifdef MSG
+VOID dbz() {
+ BYTE *pbz;
+
+ for (pbz = bz; *pbz; pbz++)
+ *pbz ^= 37;
+ *(ATOM *)bz = GlobalAddAtom(bz);
+ *(ATOM *)&bz[4] = GlobalAddAtom(&bz[4]);
+}
+#endif
+
diff --git a/private/mvdm/wow16/ddeml/hdata.c b/private/mvdm/wow16/ddeml/hdata.c
new file mode 100644
index 000000000..4631209d2
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/hdata.c
@@ -0,0 +1,487 @@
+/****************************** Module Header ******************************\
+* Module Name: HDATA.C
+*
+* DDE manager data handle handling routines
+*
+* Created: 12/14/90 Sanford Staab
+*
+* Copyright (c) 1988, 1989, 1990 Microsoft Corporation
+\***************************************************************************/
+
+#include "ddemlp.h"
+
+HDDEDATA PutData(pSrc, cb, cbOff, aItem, wFmt, afCmd, pai)
+LPBYTE pSrc;
+DWORD cb;
+DWORD cbOff;
+ATOM aItem;
+WORD wFmt;
+WORD afCmd;
+PAPPINFO pai;
+{
+ HANDLE hMem;
+ HDDEDATA hdT;
+ DIP dip;
+
+ /* HACK ALERT!
+ * make sure the first two words req'd by windows dde is there,
+ * UNLESS aItem is null in which case we assume it is EXECUTE
+ * data and don't bother.
+ */
+ if (aItem)
+ cbOff += 4L;
+ else
+ afCmd |= HDATA_EXEC;
+
+ if ((hMem = AllocDDESel(
+ (afCmd & HDATA_APPOWNED) ? DDE_FACKREQ : DDE_FRELEASE,
+ wFmt, cb + cbOff)) == NULL) {
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ return(0L);
+ }
+
+
+ // add to local list - make sure a similar handle isn't already there.
+
+ hdT = MAKELONG(afCmd, hMem);
+#ifdef DEBUG
+ if (FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hdT, FPI_DELETE)) {
+ AssertF(FALSE, "PutData - unexpected handle in hDataPile");
+ }
+#endif // DEBUG
+
+ if (AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, CmpHIWORD) == API_ERROR) {
+ GLOBALFREE(hMem);
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ return(0L);
+ }
+
+ // add to global list if appowned
+
+ if (afCmd & HDATA_APPOWNED) {
+ dip.hData = hMem;
+ dip.hTask = pai->hTask;
+ dip.cCount = 1;
+ dip.fFlags = afCmd;
+ if (AddPileItem(pDataInfoPile, (LPBYTE)&dip, CmpWORD) == API_ERROR) {
+ GLOBALFREE(hMem);
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ return(0L);
+ }
+ }
+
+ if (pSrc)
+ CopyHugeBlock(pSrc, HugeOffset(GLOBALLOCK(hMem), cbOff), cb);
+
+ // LOWORD(hData) always == afCmd flags
+
+ return(MAKELONG(afCmd, hMem));
+}
+
+
+
+/*
+ * This is the internal data handle freeing function. fInternal is TRUE if
+ * this is called from within the DDEML (vs called via DdeFreeDataHandle())
+ * It only frees the handle if it is in the local list.
+ * Appowned data handles are only freed internally if a non-owner task is
+ * doing the freeing.
+ * It is important that the LOWORD(hData) be set properly.
+ *
+ * These features give this function the folowing desired characteristics:
+ * 1) Apps cannot free data handles more than once.
+ * 2) The DDEML cannot free APPOWNED data handles on behalf of the owner
+ * task. (except on cleanup)
+ */
+VOID FreeDataHandle(
+PAPPINFO pai,
+HDDEDATA hData,
+BOOL fInternal)
+{
+ DIP *pDip;
+ BOOL fRelease = 0;
+ DDEPOKE FAR *pDdeMem;
+ WORD fmt;
+
+ TRACEAPIIN((szT, "FreeDataHandle(%lx, %lx, %d)\n", pai, hData, fInternal));
+
+ // appowned data handles are not freed till their count reaches 0.
+
+ if ((LOWORD(hData) & HDATA_APPOWNED) &&
+ (pDip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, PHMEM(hData), 0))) {
+
+ // don't internally free if in the context of the owner
+
+ if (fInternal && (pDip->hTask == pai->hTask)) {
+ TRACEAPIOUT((szT, "FreeDataHandle: Internal and of this task - not freed.\n"));
+ return;
+ }
+
+ if (--pDip->cCount != 0) {
+ TRACEAPIOUT((szT, "FreeDataHandle: Ref count not 0 - not freed.\n"));
+ return;
+ }
+
+ FindPileItem(pDataInfoPile, CmpWORD, PHMEM(hData), FPI_DELETE);
+ fRelease = TRUE;
+ }
+
+ /*
+ * Apps can only free handles in their local list - this guards against
+ * multiple frees by an app. (my arnt we nice)
+ */
+ if (!HIWORD(hData) ||
+ !FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE)) {
+ TRACEAPIOUT((szT, "FreeDataHandle: Not in local list - not freed.\n"));
+ return;
+ }
+
+ if (LOWORD(hData) & HDATA_EXEC) {
+ fRelease |= !(LOWORD(hData) & HDATA_APPOWNED);
+ } else {
+ pDdeMem = (DDEPOKE FAR *)GLOBALLOCK(HIWORD(hData));
+ if (pDdeMem == NULL) {
+ TRACEAPIOUT((szT, "FreeDataHandle: Lock failed - not freed.\n"));
+ return;
+ }
+ fRelease |= pDdeMem->fRelease;
+ fmt = pDdeMem->cfFormat;
+ GLOBALUNLOCK(HIWORD(hData));
+ }
+
+ if (fRelease) {
+ if (LOWORD(hData) & HDATA_EXEC)
+ GLOBALFREE(HIWORD(hData));
+ else
+ FreeDDEData(HIWORD(hData), fmt);
+ }
+ TRACEAPIOUT((szT, "FreeDataHandle: freed.\n"));
+}
+
+
+
+
+
+/*
+ * This function prepairs data handles on entry into the DDEML API. It has
+ * the following characteristics:
+ * 1) APPOWNED data handles are copied to a non-appowned handle if being
+ * passed to a non-local app.
+ * 2) non-APPOWNED data handles on loan to a callback are copied so they
+ * don't get prematurely freed.
+ * 3) The READONLY bit is set. (in the local list)
+ */
+HDDEDATA DllEntry(
+PCOMMONINFO pcomi,
+HDDEDATA hData)
+{
+ if ((!(pcomi->fs & ST_ISLOCAL)) && (LOWORD(hData) & HDATA_APPOWNED) ||
+ LOWORD(hData) & HDATA_NOAPPFREE && !(LOWORD(hData) & HDATA_APPOWNED)) {
+
+ // copy APPOWNED data handles to a fresh handle if not a local conv.
+ // copy app loaned, non appowned handles as well (this is the
+ // relay server case)
+
+ hData = CopyHDDEDATA(pcomi->pai, hData);
+ }
+
+ LOWORD(hData) |= HDATA_READONLY;
+
+ AddPileItem(pcomi->pai->pHDataPile, (LPBYTE)&hData, CmpHIWORD);
+
+ // NOTE: the global lists READONLY flag set but thats
+ // ok because any hData received from a transaction will always be in
+ // the local list due to RecvPrep().
+
+ return(hData);
+}
+
+
+
+/*
+ * removes the data handle from the local list. This removes responsibility
+ * for the data handle from the sending app. APPOWNED handles are not
+ * removed.
+ */
+VOID XmitPrep(
+HDDEDATA hData,
+PAPPINFO pai)
+{
+ if (!(LOWORD(hData) & HDATA_APPOWNED)) {
+ FindPileItem(pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE);
+ }
+}
+
+
+
+/*
+ * Places the received data handle into the apropriate lists and returns
+ * it with the proper flags set. Returns 0 if invalid hMem. afCmd should
+ * contain any extra flags desired.
+ */
+HDDEDATA RecvPrep(
+PAPPINFO pai,
+HANDLE hMem,
+WORD afCmd)
+{
+ DIP *pdip;
+ HDDEDATA hData;
+
+ if (!hMem)
+ return(0);
+
+ // check if its an APPOWNED one, if so, log entry.
+
+ if (pdip = (DIP *)(DWORD)FindPileItem(pDataInfoPile, CmpWORD, (LPBYTE)&hMem, 0)) {
+ afCmd |= pdip->fFlags;
+ pdip->cCount++;
+ }
+
+ // if we got one that isnt fRelease, treat it as appowed.
+
+ if (!(*(LPWORD)GLOBALLOCK(hMem) & DDE_FRELEASE))
+ afCmd |= HDATA_APPOWNED;
+
+ GLOBALUNLOCK(hMem);
+
+ // all received handles are readonly.
+
+ hData = (HDDEDATA)MAKELONG(afCmd | HDATA_READONLY, hMem);
+ /*
+ * Add (or replace) into local list
+ */
+ AddPileItem(pai->pHDataPile, (LPBYTE)&hData, CmpHIWORD);
+
+ return(hData);
+}
+
+
+HANDLE CopyDDEShareHandle(
+HANDLE hMem)
+{
+ DWORD cb;
+ LPBYTE pMem;
+
+ cb = GlobalSize(hMem);
+ pMem = GLOBALLOCK(hMem);
+ if (pMem == NULL) {
+ return(0);
+ }
+ hMem = GLOBALALLOC(GMEM_DDESHARE, cb);
+ CopyHugeBlock(pMem, GLOBALPTR(hMem), cb);
+ return(hMem);
+}
+
+
+
+HBITMAP CopyBitmap(
+PAPPINFO pai,
+HBITMAP hbm)
+{
+ BITMAP bm;
+ HBITMAP hbm2, hbmOld1, hbmOld2;
+ HDC hdc, hdcMem1, hdcMem2;
+
+ if (!GetObject(hbm, sizeof(BITMAP), &bm)) {
+ return(0);
+ }
+ hdc = GetDC(pai->hwndDmg);
+ if (!hdc) {
+ return(0);
+ }
+ hdcMem1 = CreateCompatibleDC(hdc);
+ if (!hdcMem1) {
+ goto Cleanup3;
+ }
+ hdcMem2 = CreateCompatibleDC(hdc);
+ if (!hdcMem2) {
+ goto Cleanup2;
+ }
+ hbmOld1 = SelectObject(hdcMem1, hbm);
+ hbm2 = CreateCompatibleBitmap(hdcMem1, bm.bmWidth, bm.bmHeight);
+ if (!hbm2) {
+ goto Cleanup1;
+ }
+ hbmOld2 = SelectObject(hdcMem2, hbm2);
+ BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
+ SelectObject(hdcMem1, hbmOld1);
+ SelectObject(hdcMem2, hbmOld2);
+Cleanup1:
+ DeleteDC(hdcMem2);
+Cleanup2:
+ DeleteDC(hdcMem1);
+Cleanup3:
+ ReleaseDC(pai->hwndDmg, hdc);
+ return(hbm2);
+}
+
+
+
+HPALETTE CopyPalette(
+HPALETTE hpal)
+{
+ int cPalEntries;
+ LOGPALETTE *plp;
+
+ if (!GetObject(hpal, sizeof(int), &cPalEntries)) {
+ return(0);
+ }
+ plp = (LOGPALETTE *)LocalAlloc(LPTR, sizeof(LOGPALETTE) +
+ (cPalEntries - 1) * sizeof(PALETTEENTRY));
+ if (!plp) {
+ return(0);
+ }
+ if (!GetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) {
+ LocalFree((HLOCAL)plp);
+ return(0);
+ }
+ plp->palVersion = 0x300;
+ plp->palNumEntries = (WORD)cPalEntries;
+ hpal = CreatePalette(plp);
+ if (hpal &&
+ !SetPaletteEntries(hpal, 0, cPalEntries, plp->palPalEntry)) {
+ hpal = 0;
+ }
+ LocalFree((HLOCAL)plp);
+ return(hpal);
+}
+
+
+
+
+HDDEDATA CopyHDDEDATA(
+PAPPINFO pai,
+HDDEDATA hData)
+{
+ HANDLE hMem;
+ LPDDE_DATA lpdded;
+ HDDEDATA hdT;
+ LPMETAFILEPICT pmfPict;
+
+ if (!HIWORD(hData))
+ return(hData);
+ hMem = CopyDDEShareHandle((HANDLE)HIWORD(hData));
+
+ if (!hMem)
+ return(NULL);
+
+ if (!(LOWORD(hData) & HDATA_EXEC)) {
+ lpdded = (LPDDE_DATA)GLOBALLOCK(hMem);
+ if (lpdded == NULL) {
+ return(NULL);
+ }
+ lpdded->wStatus |= DDE_FRELEASE;
+ if (lpdded != NULL) {
+ switch (lpdded->wFmt) {
+ case CF_BITMAP:
+ case CF_DSPBITMAP:
+ lpdded->wData = CopyBitmap(pai, lpdded->wData);
+ break;
+
+ case CF_PALETTE:
+ lpdded->wData = (WORD)CopyPalette((HPALETTE)lpdded->wData);
+ break;
+
+ case CF_DIB:
+ lpdded->wData = (WORD)CopyDDEShareHandle((HANDLE)lpdded->wData);
+ break;
+
+ case CF_METAFILEPICT:
+ case CF_DSPMETAFILEPICT:
+ lpdded->wData = (WORD)CopyDDEShareHandle((HANDLE)lpdded->wData);
+ if (lpdded->wData) {
+ pmfPict = (LPMETAFILEPICT)GLOBALLOCK((HANDLE)lpdded->wData);
+ if (pmfPict != NULL) {
+ pmfPict->hMF = CopyMetaFile(pmfPict->hMF, NULL);
+ GLOBALUNLOCK((HANDLE)lpdded->wData);
+ }
+ GLOBALUNLOCK((HANDLE)lpdded->wData);
+ }
+ break;
+#ifdef CF_ENHMETAFILE
+ case CF_ENHMETAFILE:
+ lpdded->wData = (WORD)CopyEnhMetaFile(*((HENHMETAFILE FAR *)(&lpdded->wData)), NULL);
+ break;
+#endif // bad because it makes chicago and NT binaries different.
+ }
+ GLOBALUNLOCK(hMem);
+ }
+ }
+
+ hdT = MAKELONG(LOWORD(hData) & ~(HDATA_APPOWNED | HDATA_NOAPPFREE), hMem);
+ AddPileItem(pai->pHDataPile, (LPBYTE)&hdT, NULL);
+
+ return(hdT);
+}
+
+
+VOID FreeDDEData(
+HANDLE hMem,
+WORD wFmt)
+{
+ DDEDATA FAR *pDdeData;
+
+ /*
+ * This handles the special cases for formats that hold imbedded
+ * objects. (CF_BITMAP, CF_METAFILEPICT).
+ *
+ * The data handle is assumed to be unlocked.
+ */
+
+ // may need to add "Printer_Picture" for excel/word interaction" but
+ // this is just between the two of them and they don't use DDEML.
+ // raor says OLE only worries about these formats as well.
+
+ pDdeData = (DDEDATA FAR *)GLOBALLOCK(hMem);
+ if (pDdeData == NULL) {
+ return;
+ }
+
+ switch (wFmt) {
+ case CF_BITMAP:
+ case CF_DSPBITMAP:
+ case CF_PALETTE:
+ DeleteObject(*(HANDLE FAR *)(&pDdeData->Value));
+ break;
+
+ case CF_DIB:
+ /*
+ * DIBs are allocated by app so we don't use the macro here.
+ */
+ GlobalFree(*(HANDLE FAR *)(&pDdeData->Value));
+ break;
+
+ case CF_METAFILEPICT:
+ case CF_DSPMETAFILEPICT:
+ {
+ HANDLE hmfPict;
+ LPMETAFILEPICT pmfPict;
+
+ /*
+ * EXCEL sickness - metafile is a handle to a METAFILEPICT
+ * struct which holds a metafile. (2 levels of indirection!)
+ *
+ * We don't use the GLOBAL macros here because these objects
+ * are allocated by the app. DDEML knows not their history.
+ */
+
+ hmfPict = *(HANDLE FAR *)(&pDdeData->Value);
+ pmfPict = (LPMETAFILEPICT)GlobalLock(hmfPict);
+ if (pmfPict != NULL) {
+ DeleteMetaFile(pmfPict->hMF);
+ }
+ GlobalUnlock(hmfPict);
+ GlobalFree(hmfPict);
+ }
+ break;
+
+#ifdef CF_ENHMETAFILE
+ case CF_ENHMETAFILE:
+ DeleteEnhMetaFile(*(HENHMETAFILE FAR *)(&pDdeData->Value));
+ break;
+#endif // This is bad - it forces different binaries for chicago and NT!
+ }
+
+ GLOBALUNLOCK(hMem);
+ GLOBALFREE(hMem);
+}
diff --git a/private/mvdm/wow16/ddeml/heapwach.c b/private/mvdm/wow16/ddeml/heapwach.c
new file mode 100644
index 000000000..8cb7784db
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/heapwach.c
@@ -0,0 +1,108 @@
+#include "ddemlp.h"
+#include "heapwach.h"
+#ifdef WATCHHEAPS
+
+extern char FAR SZHEAPWATCHCLASS[];
+#define MAX_WINDOWS 20
+
+typedef struct {
+ WORD sel;
+ HWND hwnd;
+} SELWND;
+
+char szT[30];
+
+SELWND sw[MAX_WINDOWS];
+int cHwnds = 0;
+
+
+VOID LogAlloc(
+DWORD lpstr,
+WORD cb,
+DWORD color,
+HANDLE hInstance)
+{
+ int i;
+ HWND hwnd;
+ WORD sel;
+ WORD off;
+ int mj, mn, cl;
+ HDC hdc;
+ RECT rc, rcClient;
+ HBRUSH hbr;
+
+ sel = HIWORD(lpstr);
+ hwnd = NULL;
+ for (i = 0; i < cHwnds; i++) {
+ if (sel == sw[i].sel) {
+ hwnd = sw[i].hwnd;
+ if (!IsWindow(hwnd)) {
+ // this must have been destroyed and we are now reusing the sel.
+ sw[i] = sw[--cHwnds];
+ hwnd = NULL;
+ }
+ break;
+ }
+ }
+ if (!hwnd && cHwnds < MAX_WINDOWS) {
+ itoa((int)sel, szT, 16);
+ sw[cHwnds].sel = sel;
+ sw[cHwnds].hwnd = hwnd = CreateWindow(SZHEAPWATCHCLASS, szT,
+ WS_POPUP | WS_CAPTION, CW_USEDEFAULT, CW_USEDEFAULT, 64, 64,
+ NULL, NULL, hInstance, NULL);
+ if (hwnd) {
+ cHwnds++;
+ GetWindowRect(hwnd, &rc);
+ GetClientRect(hwnd, &rcClient);
+ rc.bottom += 128 - (rcClient.bottom - rcClient.top);
+ rc.right += 128 - (rcClient.right - rcClient.left);
+ MoveWindow(hwnd, 0, 0, rc.right - rc.left, rc.bottom - rc.top, FALSE);
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ }
+ }
+ if (!hwnd) {
+ return;
+ }
+ off = LOWORD(lpstr) >> 2;
+ mj = off >> 7;
+ mn = off & 0x7f;
+ cl = cb >> 2;
+ hdc = GetDC(hwnd);
+ hbr = CreateSolidBrush(color);
+ rc.top = mj;
+ rc.bottom = rc.top + 1;
+ rc.left = (int)mn;
+ rc.right = min(127, mn + cl);
+ FillRect(hdc, &rc, hbr);
+ cl -= (int)(rc.right - rc.left);
+ if (cl > 127) {
+ rc.top++;
+ rc.bottom = rc.top + cl / 128;
+ rc.left = 0;
+ rc.right = 127;
+ FillRect(hdc, &rc, hbr);
+ cl -= 128 * (cl / 128);
+ }
+ if (cl > 0) {
+ rc.top = rc.bottom;
+ rc.bottom++;
+ rc.left = 0;
+ rc.right = cl;
+ FillRect(hdc, &rc, hbr);
+ }
+ DeleteObject(hbr);
+ ReleaseDC(hwnd, hdc);
+}
+
+
+VOID CloseHeapWatch()
+{
+ int i;
+
+ for (i = 0; i < cHwnds; i++) {
+ DestroyWindow(sw[i].hwnd);
+ }
+ cHwnds = 0;
+}
+
+#endif
diff --git a/private/mvdm/wow16/ddeml/heapwach.h b/private/mvdm/wow16/ddeml/heapwach.h
new file mode 100644
index 000000000..c316bad8b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/heapwach.h
@@ -0,0 +1,3 @@
+
+VOID LogAlloc(DWORD lpstr, WORD cb, DWORD color, HANDLE hInstance);
+VOID CloseHeapWatch(VOID);
diff --git a/private/mvdm/wow16/ddeml/libentry.asm b/private/mvdm/wow16/ddeml/libentry.asm
new file mode 100644
index 000000000..4ba7233b4
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/libentry.asm
@@ -0,0 +1,77 @@
+PAGE,132
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; LIBENTRY.ASM
+;
+; Windows dynamic link library entry routine
+;
+; This module generates a code segment called INIT_TEXT.
+; It initializes the local heap if one exists and then calls
+; the C routine LibMain() which should have the form:
+; BOOL FAR PASCAL LibMain(HANDLE hInstance,
+; WORD wDataSeg,
+; WORD cbHeap,
+; LPSTR lpszCmdLine);
+;
+; The result of the call to LibMain is returned to Windows.
+; The C routine should return TRUE if it completes initialization
+; successfully, FALSE if some error occurs.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+include cmacros.inc
+
+externFP <LibMain> ; the C routine to be called
+
+createSeg INIT_TEXT, INIT_TEXT, BYTE, PUBLIC, CODE
+sBegin INIT_TEXT
+assumes CS,INIT_TEXT
+
+?PLM=0 ; 'C'naming
+externA <_acrtused> ; ensures that Win DLL startup code is linked
+
+?PLM=1 ; 'PASCAL' naming
+externFP <LocalInit> ; Windows heap init routine
+
+cProc LibEntry, <PUBLIC,FAR> ; entry point into DLL
+
+include convdll.inc
+
+cBegin
+ push di ; handle of the module instance
+ push ds ; library data segment
+ push cx ; heap size
+ push es ; command line segment
+ push si ; command line offset
+
+ ; if we have some heap then initialize it
+ jcxz callc ; jump if no heap specified
+
+ ; call the Windows function LocalInit() to set up the heap
+ ; LocalInit((LPSTR)start, WORD cbHeap);
+
+ xor ax,ax
+ cCall LocalInit <ds, ax, cx>
+ or ax,ax ; did it do it ok ?
+ jz error ; quit if it failed
+
+ ; invoke the C routine to do any special initialization
+
+callc:
+ call LibMain ; invoke the 'C' routine (result in AX)
+ jmp short exit ; LibMain is responsible for stack clean up
+
+error:
+ pop si ; clean up stack on a LocalInit error
+ pop es
+ pop cx
+ pop ds
+ pop di
+
+exit:
+
+cEnd
+
+sEnd INIT_TEXT
+
+end LibEntry
diff --git a/private/mvdm/wow16/ddeml/makefile b/private/mvdm/wow16/ddeml/makefile
new file mode 100644
index 000000000..cba11738d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/makefile
@@ -0,0 +1,142 @@
+#===================================================================
+#
+# DDE manager DLL make file
+#
+#===================================================================
+# International mods
+# NOTE: INTL_SRC, INTL_EXE and LANG are macros set by international
+
+WINLIB=..\lib
+IMPLIB=..\..\tools16\implib
+INCLUDE=-I..\inc -I..\..\inc
+MAPSYM=..\..\tools16\mapsym
+MKPUBLIC=..\..\tools16\mkpublic
+ASM=..\..\tools16\masm
+CC=..\..\tools16\cl16
+RC=..\..\tools16\rc16 $(INCLUDE)
+LINK=..\..\tools16\link16
+
+# work around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH=..\..\tools16;$(PATH)
+
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=$(INTL_SRC)\$(LANG)\sdk\ddeml
+EXE_DIR=$(INTL_EXE)
+!ENDIF
+
+APP = ddeml
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+DBG=1
+CDEBUG=/Odi /Zd
+ADEBUG=-Zd
+LDEBUG=/LI
+!endif
+
+!IFDEF DBG
+CFLAGS=-DDEBUG -Ocilgtn -Zep $(INCLUDE) $(CDEBUG)
+CVLINK=$(LDEBUG)
+AFLAGS=-Zi -DDEBUG $(INCLUDE) $(ADEBUG)
+O=DEBUG
+
+!IFDEF DBGHEAPS
+CFLAGS=-DWATCHHEAPS -DDEBUG -Ziep -Od $(INCLUDE) $(CDEBUG)
+!ENDIF
+
+!ELSE
+
+CFLAGS=-Ocilgtn -Zep $(INCLUDE)
+CVLINK=
+AFLAGS=$(INCLUDE)
+O=RETAIL
+
+!ENDIF
+
+CCL = $(CC) $(CFLAGS) -W3 -c -u -ASw -G2swc -Fo$*.obj
+
+OBJ1 = $(O)\ddeml.obj $(O)\dmgdb.obj $(O)\dmghsz.obj $(O)\dmgmon.obj $(O)\heapwach.obj $(O)\stdptcl.obj
+OBJ2 = $(O)\dmgwndp.obj $(O)\dmgdde.obj $(O)\dmgq.obj $(O)\dmgmem.obj $(O)\hdata.obj $(O)\stdinit.obj $(O)\register.obj
+ASMOBJ = $(O)\libentry.obj $(O)\dmgutil.obj
+
+#===================================================================
+#
+# Dependencies
+#
+#===================================================================
+
+!IFNDEF LANG
+all: $(O)\ddeml.dll ddeml.lib
+ echo -------- $(O) BUILD COMPLETE --------
+!ELSE
+all: ddeml.$(LANG)
+ echo -------- IPG BUILD COMPLETE --------
+!ENDIF
+
+$(OBJ1) $(OBJ2): $(@B).c ddemlp.h
+ $(CCL) $(@B).c
+
+$(ASMOBJ): $(@B).asm
+ $(ASM) $(AFLAGS) $(@B).asm, $*.obj;
+
+ddeml.lib: ddeml.def
+ $(MKPUBLIC) ddeml.def stripped.def
+ $(IMPLIB) ddeml.lib stripped.def
+
+!IFNDEF LANG
+ddeml.rc: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+ddeml.rcv: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+ddeml.dlg: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+ddeml.res: ddeml.rc ddemlp.h ddeml.rcv ddeml.dlg ..\inc\common.ver ..\inc\version.h
+ $(RC) -r ddeml
+!ELSE
+ddeml.res: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+!ENDIF
+
+$(O)\ddeml.dll: $(OBJ1) $(OBJ2) $(ASMOBJ) ddeml.def ddeml.res
+ $(LINK) @<<
+ $(OBJ1) +
+ $(OBJ2) +
+ $(ASMOBJ)
+ $(O)\ddeml.dll /FAR $(CVLINK)
+ $(O)\ddeml /map
+ $(WINLIB)\libw.lib $(WINLIB)\sdllcew.lib /nod /noe
+ ddeml.def
+<<
+ $(MAPSYM) $(O)\ddeml
+ copy ddeml.sym $(O)
+ del ddeml.sym
+ $(RC) -30 -t ddeml.res $(O)\ddeml.dll
+ cd $(O)
+ binplace ddeml.dll ddeml.map ddeml.sym
+ cd ..
+
+#
+# clean target
+#
+clean: cleanup all
+
+cleanup:
+ if exist DEBUG\*.obj del DEBUG\*.obj
+ if exist DEBUG\*.sym del DEBUG\*.sym
+ if exist DEBUG\*.dll del DEBUG\*.dll
+ if exist RETAIL\*.obj del RETAIL\*.obj
+ if exist RETAIL\*.sym del RETAIL\*.sym
+ if exist RETAIL\*.dll del RETAIL\*.dll
+ if exist *.rc del *.rc
+ if exist *.res del *.res
+
+ddeml.$(LANG): ddeml.res
+ copy $(EXE_DIR)\ddeml.dll ddeml.$(LANG)
+ $(RC) -30 ddeml.res ddeml.$(LANG)
diff --git a/private/mvdm/wow16/ddeml/messages/usa/ddeml.dlg b/private/mvdm/wow16/ddeml/messages/usa/ddeml.dlg
new file mode 100644
index 000000000..c49a2c128
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/messages/usa/ddeml.dlg
@@ -0,0 +1,27 @@
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+ "DDEMLP.H\0"
+END
+
+TermDialog DIALOG 91, 34, 181, 137
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Windows DDE"
+FONT 8, "Helv"
+BEGIN
+ LTEXT "An application using DDE did not respond to the system's exit command.",
+ 101, 7, 7, 168, 23
+ LTEXT "Choose Retry to attempt to close the application and return to Windows.",
+ 102, 27, 32, 148, 24
+ LTEXT "Choose Continue to repeatedly attempt to close the application and return to Windows.",
+ 103, 27, 58, 148, 24
+ LTEXT "Choose Close to exit the application that is not responding. You may lose any unsaved information in this application.",
+ 104, 27, 84, 148, 24
+ DEFPUSHBUTTON "Retry", IDRETRY, 15, 117, 40, 14
+ PUSHBUTTON "Continue", IDIGNORE, 70, 117, 40, 14
+ PUSHBUTTON "Close", IDABORT, 125, 117, 40, 14
+ LTEXT "*", 108, 21, 33, 6, 24
+ LTEXT "*", 109, 21, 59, 6, 24
+ LTEXT "*", 110, 21, 85, 6, 24
+END
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/ddeml/messages/usa/ddeml.rc b/private/mvdm/wow16/ddeml/messages/usa/ddeml.rc
new file mode 100644
index 000000000..be7300bed
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/messages/usa/ddeml.rc
@@ -0,0 +1,5 @@
+#include "windows.h"
+
+#include "ddeml.rcv"
+#include "ddeml.dlg"
+
diff --git a/private/mvdm/wow16/ddeml/messages/usa/ddeml.rcv b/private/mvdm/wow16/ddeml/messages/usa/ddeml.rcv
new file mode 100644
index 000000000..9da32973a
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/messages/usa/ddeml.rcv
@@ -0,0 +1,30 @@
+/********************************************************************/
+/* DDEML.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+/*
+ * DDEML needs a special version stamp because intermediate versions
+ * were shipped with apps like Excel 5.0 (v3.12)
+ *
+ * WOW Daytona and Chicago versions should be identical and set to 3.5
+ * (SanfordS)
+ */
+#undef VERSION
+#define VERSION "3.5"
+#undef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR "3.50\0"
+#undef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION 3,50,0,103
+
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "DDE Management library"
+#define VER_INTERNALNAME_STR "DDEML"
+#define VER_ORIGINALFILENAME_STR "DDEML.DLL"
+
+
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/ddeml/register.c b/private/mvdm/wow16/ddeml/register.c
new file mode 100644
index 000000000..aef4ca005
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/register.c
@@ -0,0 +1,140 @@
+
+/****************************** Module Header ******************************\
+* Module Name: register.c
+*
+* DDE Manager - server registration module
+*
+* Created: 4/15/94 sanfords
+* to allow interoperability between DDEML16 and DDEML32
+\***************************************************************************/
+
+#include <windows.h>
+#include <string.h>
+#include "ddemlp.h"
+
+/*
+ * interoperable DDEML service registration is accomplished via the
+ * two messages UM_REGISTER and UM_UNREGISTER. (WM_USER range)
+ * wParam=gaApp,
+ * lParam=src hwndListen, (for instance specific HSZ generation.)
+ * These messages are sent and the sender is responsible for freeing
+ * the gaApp.
+ */
+
+
+/*
+ * Broadcast-sends the given message to all top-level windows of szClass
+ * except to hwndSkip.
+ */
+VOID SendMessageToClass(
+ATOM atomClass,
+UINT msg,
+GATOM ga,
+HWND hwndFrom,
+HWND *ahwndSkip,
+int chwndSkip,
+BOOL fPost)
+{
+ HWND hwnd;
+ int i;
+ BOOL fSkipIt;
+
+ hwnd = GetWindow(GetDesktopWindow(), GW_CHILD);
+ while (hwnd != NULL) {
+ if (GetClassWord(hwnd, GCW_ATOM) == atomClass) {
+ fSkipIt = FALSE;
+ for (i = 0; i < chwndSkip; i++) {
+ if (hwnd == ahwndSkip[i]) {
+ fSkipIt = TRUE;
+ break;
+ }
+ }
+ if (!fSkipIt) {
+ IncHszCount(ga); // receiver frees
+ if (fPost) {
+ PostMessage(hwnd, msg, (WPARAM)ga, (LPARAM)hwndFrom);
+ } else {
+ SendMessage(hwnd, msg, (WPARAM)ga, (LPARAM)hwndFrom);
+ }
+ }
+ }
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+ }
+}
+
+
+/*
+ * Broadcast-sends a UM_REGISTER or UM_UNREGISTER message to all DDEML16
+ * and DDEML32 listening windows in the system except hwndSkip.
+ */
+VOID RegisterService(
+BOOL fRegister,
+GATOM gaApp,
+HWND hwndListen)
+{
+ PAPPINFO paiT;
+ int cSkips = 1;
+ HWND *ahwndSkip;
+ int i;
+ extern ATOM gatomDDEMLMom;
+ extern ATOM gatomDMGClass;
+
+ /*
+ * First send (always!) to our own guys the same way we used to
+ * for compatability. WordPerfect 6.0a relies on this!
+ */
+ for (paiT = pAppInfoList; paiT != NULL; paiT = paiT->next) {
+ IncHszCount(gaApp); // receiver frees atom
+ SendMessage(paiT->hwndDmg,
+ fRegister ? UM_REGISTER : UM_UNREGISTER,
+ (WPARAM)gaApp, (LPARAM)hwndListen);
+ cSkips++;
+ }
+ /*
+ * build up the hwndskip list.
+ */
+ ahwndSkip = (HWND *)LocalAlloc(LPTR, sizeof(HWND) * cSkips);
+ if (ahwndSkip == NULL) {
+ return;
+ }
+ for (paiT = pAppInfoList, i = 0;
+ paiT != NULL;
+ paiT = paiT->next, i++) {
+ ahwndSkip[i] = paiT->hwndDmg;
+ }
+
+ AssertF(gatomDDEMLMom, "gatomDDEMLMom not initialized in RegisterService");
+ AssertF(gatomDMGClass, "gatomDMGClass not initialized in RegisterService");
+
+ /*
+ * Send notification to each DDEML32 listening window.
+ */
+ SendMessageToClass(gatomDDEMLMom, fRegister ? UM_REGISTER : UM_UNREGISTER,
+ gaApp, hwndListen, ahwndSkip, i, fRegister);
+ /*
+ * Send notification to each DDEML16 listening window.
+ */
+ SendMessageToClass(gatomDMGClass, fRegister ? UM_REGISTER : UM_UNREGISTER,
+ gaApp, hwndListen, ahwndSkip, i, fRegister);
+
+ LocalFree((HLOCAL)ahwndSkip);
+}
+
+
+LRESULT ProcessRegistrationMessage(
+HWND hwnd,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam)
+{
+ /*
+ * wParam = GATOM of app
+ * lParam = hwndListen of source
+ */
+ DoCallback((PAPPINFO)GetWindowWord(hwnd, GWW_PAI), (HCONV)0L, (HSZ)wParam,
+ MakeInstAppName(wParam, (HWND)lParam), 0,
+ msg == UM_REGISTER ? XTYP_REGISTER : XTYP_UNREGISTER,
+ (HDDEDATA)0, 0L, 0L);
+ GlobalDeleteAtom((ATOM)wParam); // receiver frees.
+ return(1);
+}
diff --git a/private/mvdm/wow16/ddeml/stdinit.c b/private/mvdm/wow16/ddeml/stdinit.c
new file mode 100644
index 000000000..a4d2f0066
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/stdinit.c
@@ -0,0 +1,464 @@
+/****************************** Module Header ******************************\
+* Module Name: STDINIT.C
+*
+* This module contains functions used in the involved initiate sequence.
+*
+* Created: 3/21/91 Sanfords
+*
+* Copyright (c) 1991 Microsoft Corporation
+\***************************************************************************/
+
+#include "ddemlp.h"
+
+/*
+ * WM_CREATE ClientWndProc processing
+ */
+long ClientCreate(
+HWND hwnd,
+PAPPINFO pai)
+{
+ PCLIENTINFO pci;
+
+ static DWORD defid = (DWORD)QID_SYNC;
+ static XFERINFO defXferInfo = {
+ &defid,
+ 1L,
+ XTYP_CONNECT,
+ DDEFMT_TEXT,
+ 0L,
+ 0L,
+ };
+
+ /*
+ * allocate and initialize the client window info.
+ */
+ SEMENTER();
+
+ if(!(pci = (PCLIENTINFO)FarAllocMem(pai->hheapApp, sizeof(CLIENTINFO)))) {
+ SEMLEAVE();
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ return(1); /* aboart creation - low memory */
+ }
+
+ SetWindowLong(hwnd, GWL_PCI, (DWORD)pci);
+ SetWindowWord(hwnd, GWW_CHECKVAL, ++hwInst);
+ pci->ci.pai = pai;
+ // pci->ci.xad.hUser = 0L;
+ pci->ci.xad.state = XST_NULL;
+ pci->ci.xad.pXferInfo = &defXferInfo; //???
+ pci->ci.fs = ST_CLIENT | (pai->wFlags & AWF_DEFCREATESTATE ? ST_BLOCKED : 0);
+ if (GetWindowLong(GetParent(hwnd), GWL_WNDPROC) == (LONG)ConvListWndProc)
+ pci->ci.fs |= ST_INLIST;
+ // pci->ci.hConvPartner = NULL;
+ // pci->ci.hszServerApp = NULL;
+ // pci->ci.hszTopic = NULL;
+ pci->pQ = NULL; /* don't create until we need one */
+ pci->pClientAdvList = CreateLst(pai->hheapApp, sizeof(ADVLI));
+ SEMLEAVE();
+
+}
+
+
+
+
+/***************************** Private Function ****************************\
+* This routine returns the hwnd of a newly created and connected DDE
+* client or NULL if failure.
+*
+* History: created 1/6/89 sanfords
+\***************************************************************************/
+HWND GetDDEClientWindow(
+PAPPINFO pai,
+HWND hwndParent,
+HWND hwndSend, // NULL -> broadcast
+HSZ hszSvc,
+ATOM aTopic,
+PCONVCONTEXT pCC)
+{
+ HWND hwnd;
+ PCLIENTINFO pci;
+
+ SEMCHECKOUT();
+ if(!(hwnd = CreateWindow(SZCLIENTCLASS, szNull, WS_CHILD, 0, 0, 0, 0, hwndParent,
+ NULL, hInstance, &pai))) {
+ return(NULL);
+ }
+
+ pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
+
+ SEMENTER();
+ /*
+ * we need to set this info BEFORE we do the synchronous initiate
+ * so the INITIATEACK msg is done correctly.
+ */
+ pci->ci.xad.state = XST_INIT1;
+ pci->ci.xad.LastError = DMLERR_NO_ERROR;
+ pci->ci.hszSvcReq = hszSvc;
+ pci->ci.aServerApp = LOWORD(hszSvc);
+ pci->ci.aTopic = aTopic;
+ pci->ci.CC = pCC ? *pCC : CCDef;
+ SEMLEAVE();
+
+ if (hwndSend) {
+ pci->hwndInit = hwndSend;
+ SendMessage(hwndSend, WM_DDE_INITIATE, hwnd,
+ MAKELONG((ATOM)hszSvc, aTopic));
+ } else {
+ IE ie = {
+ hwnd, pci, aTopic
+ };
+
+ EnumWindows(InitEnum, (LONG)(IE FAR *)&ie);
+ }
+
+
+ if (pci->ci.xad.state == XST_INIT1) { // no connections?
+ DestroyWindow(hwnd);
+ return(NULL);
+ }
+
+ pci->ci.xad.state = XST_CONNECTED; // fully ready now.
+ pci->ci.fs |= ST_CONNECTED;
+
+ return(hwnd);
+}
+
+
+
+BOOL FAR PASCAL InitEnum(
+HWND hwnd,
+IE FAR *pie)
+{
+ pie->pci->hwndInit = hwnd;
+ SendMessage(hwnd, WM_DDE_INITIATE, pie->hwnd,
+ MAKELONG((ATOM)pie->pci->ci.hszSvcReq, pie->aTopic));
+ return((pie->pci->ci.fs & ST_INLIST) || pie->pci->ci.xad.state == XST_INIT1);
+}
+
+
+
+
+void ServerFrameInitConv(
+PAPPINFO pai,
+HWND hwndFrame,
+HWND hwndClient,
+ATOM aApp,
+ATOM aTopic)
+{
+ HSZPAIR hp[2];
+ PHSZPAIR php;
+ DWORD dwRet;
+ LPBYTE pdata;
+ HWND hwndServer;
+ BOOL fWild, fIsLocal, fIsSelf = FALSE;
+ PCLIENTINFO pci;
+
+ SEMCHECKOUT();
+
+ if (pai->afCmd & CBF_FAIL_CONNECTIONS) {
+ return;
+ }
+
+ /*
+ * If we are filtering and no app names are registered, quit.
+ */
+ if ((pai->afCmd & APPCMD_FILTERINITS) &&
+ QPileItemCount(pai->pAppNamePile) == 0) {
+ return;
+ }
+ fIsLocal = ((FARPROC)GetWindowLong(hwndClient,GWL_WNDPROC) == (FARPROC)ClientWndProc);
+ if (fIsLocal) {
+ pci = (PCLIENTINFO)GetWindowLong(hwndClient, GWL_PCI);
+ fIsSelf = (pci->ci.pai == pai);
+
+ /*
+ * filter out inits from ourselves
+ */
+ if (pai->afCmd & CBF_FAIL_SELFCONNECTIONS && fIsSelf) {
+ return;
+ }
+ }
+
+ hp[0].hszSvc = (HSZ)aApp;
+
+ /*
+ * filter out unwanted app names.
+ */
+ if (aApp && (pai->afCmd & APPCMD_FILTERINITS) &&
+ !FindPileItem(pai->pAppNamePile, CmpWORD, (LPBYTE)&aApp, 0))
+ return;
+
+ hp[0].hszTopic = aTopic;
+ hp[1].hszSvc = hp[1].hszTopic = 0L;
+ fWild = (hp[0].hszSvc == 0L || hp[0].hszTopic == 0L);
+
+ dwRet = DoCallback(pai, NULL, hp[0].hszTopic,
+ hp[0].hszSvc, 0, (fWild ? XTYP_WILDCONNECT : XTYP_CONNECT),
+ 0L, fIsLocal ? (DWORD)&pci->ci.CC : 0L, fIsSelf ? 1 : 0);
+
+ if (dwRet == NULL)
+ return;
+
+ if (fWild) {
+ pdata = GLOBALLOCK(HIWORD(dwRet));
+ php = (PHSZPAIR)pdata;
+ } else {
+ php = &hp[0];
+ pdata = NULL;
+ }
+
+ /*
+ * now php points to a 0 terminated list of hszpairs to respond to.
+ */
+ SEMENTER();
+ while (QueryHszLength(php->hszSvc) && QueryHszLength(php->hszTopic)) {
+ PSERVERINFO psi;
+
+ SEMLEAVE();
+ if ((hwndServer = CreateServerWindow(pai, (ATOM)php->hszTopic,
+ fIsLocal ? &pci->ci.CC : &CCDef)) == 0)
+ return;
+ SEMENTER();
+
+ /*
+ * have the server respond
+ */
+ psi = (PSERVERINFO)GetWindowLong(hwndServer, GWL_PCI);
+ psi->ci.hConvPartner = fIsLocal ? MAKEHCONV(hwndClient) : (HCONV)hwndClient;
+ psi->ci.hwndFrame = hwndFrame;
+ psi->ci.fs |= ST_CONNECTED;
+ if (fIsSelf) {
+ psi->ci.fs |= ST_ISSELF;
+ pci->ci.fs |= ST_ISSELF;
+ }
+ psi->ci.xad.state = XST_CONNECTED;
+ psi->ci.hszSvcReq = (HSZ)aApp;
+ psi->ci.aServerApp = (ATOM)php->hszSvc;
+ psi->ci.aTopic = (ATOM)php->hszTopic;
+
+ MONCONN(psi->ci.pai, psi->ci.aServerApp, psi->ci.aTopic,
+ hwndClient, hwndServer, TRUE);
+
+ IncHszCount(aApp); // for server window to keep
+ IncHszCount(LOWORD(php->hszSvc));
+ IncHszCount(LOWORD(php->hszTopic));
+
+ IncHszCount(LOWORD(php->hszSvc)); // for client to remove on ack
+ IncHszCount(LOWORD(php->hszTopic));
+
+#ifdef DEBUG
+ cAtoms -= 2; // we are giving these away
+#endif
+
+ SEMLEAVE();
+ SendMessage(hwndClient, WM_DDE_ACK, hwndServer,
+ MAKELONG(LOWORD(php->hszSvc), LOWORD(php->hszTopic)));
+ /*
+ * confirm initialization to server app - synchronously
+ */
+ DoCallback(pai, MAKEHCONV(hwndServer), php->hszTopic, php->hszSvc,
+ 0, XTYP_CONNECT_CONFIRM, 0L, 0L, fIsSelf ? 1 : 0);
+
+ SEMENTER();
+ php++;
+ }
+ if (pdata) {
+ GLOBALUNLOCK(HIWORD(dwRet));
+ FreeDataHandle(pai, dwRet, TRUE);
+ }
+ SEMLEAVE();
+ SEMCHECKOUT();
+}
+
+
+
+
+
+
+HWND CreateServerWindow(
+PAPPINFO pai,
+ATOM aTopic,
+PCONVCONTEXT pCC)
+{
+ HWND hwndServer;
+
+ SEMCHECKOUT();
+
+ /*
+ * make a server root window if needed....
+ */
+ if (pai->hwndSvrRoot == 0) {
+ /*
+ * NO - make one.
+ */
+ if ((pai->hwndSvrRoot = CreateWindow(SZCONVLISTCLASS, szNull, WS_CHILD,
+ 0, 0, 0, 0, pai->hwndDmg, NULL, hInstance, 0L)) == NULL) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ return(NULL);
+ }
+ }
+
+ /*
+ * Create the server window
+ */
+ if ((hwndServer = CreateWindow(SZSERVERCLASS, szNull, WS_CHILD,
+ 0, 0, 0, 0, pai->hwndSvrRoot, NULL, hInstance, &pai)) == NULL) {
+ SETLASTERROR(pai, DMLERR_SYS_ERROR);
+ return(NULL);
+ }
+ ((PSERVERINFO)GetWindowLong(hwndServer, GWL_PCI))->ci.CC = *pCC;
+ return(hwndServer);
+}
+
+
+
+
+
+
+/*
+ * WM_CREATE ServerWndProc processing
+ */
+long ServerCreate(
+HWND hwnd,
+PAPPINFO pai)
+{
+ PSERVERINFO psi;
+
+ /*
+ * allocate and initialize the server window info.
+ */
+
+ SEMENTER();
+
+ if (!(psi = (PSERVERINFO)FarAllocMem(pai->hheapApp, sizeof(SERVERINFO)))) {
+ SETLASTERROR(pai, DMLERR_MEMORY_ERROR);
+ return(1);
+ }
+
+ SEMLEAVE();
+ psi->ci.pai = pai;
+ // psi->ci.xad.hUser = 0L;
+ psi->ci.xad.state = XST_NULL;
+ psi->ci.fs = pai->wFlags & AWF_DEFCREATESTATE ? ST_BLOCKED : 0;
+ SetWindowLong(hwnd, GWL_PCI, (DWORD)psi);
+ SetWindowWord(hwnd, GWW_CHECKVAL, ++hwInst);
+ return(0);
+}
+
+
+
+
+
+/*
+ * Client response to a WM_DDE_ACK message when ACK to INITIATE expected.
+ */
+BOOL ClientInitAck(hwnd, pci, hwndServer, aApp, aTopic)
+HWND hwnd;
+PCLIENTINFO pci;
+HWND hwndServer;
+ATOM aApp;
+ATOM aTopic;
+{
+ HWND hwndClient;
+ PCLIENTINFO pciNew;
+
+#ifdef DEBUG
+ cAtoms += 2; // the incomming atoms need to be accounted for.
+#endif
+ SEMCHECKOUT();
+
+ switch (pci->ci.xad.state) {
+
+ case XST_INIT1:
+
+ /*
+ * first one back... lock in!
+ */
+ pci->ci.xad.state = XST_INIT2;
+ MONCONN(pci->ci.pai, aApp, aTopic, hwnd, hwndServer, TRUE);
+ if (GetWindowLong(hwndServer, GWL_WNDPROC) == (LONG)ServerWndProc) {
+ pci->ci.fs |= ST_ISLOCAL;
+ pci->ci.hConvPartner = MAKEHCONV(hwndServer);
+ } else {
+ pci->ci.hConvPartner = (HCONV)hwndServer;
+ if (aApp == aProgmanHack) {
+ // PROGMAN HACK!!!!
+ IncHszCount(aApp);
+ IncHszCount(aTopic);
+#ifdef DEBUG
+ cAtoms -= 2;
+#endif
+ }
+ }
+
+ pci->ci.aServerApp = aApp;
+ pci->ci.aTopic = aTopic;
+ if (!pci->ci.hwndFrame) // remember the frame this was sent to.
+ pci->ci.hwndFrame = pci->hwndInit;
+ IncHszCount(LOWORD(pci->ci.hszSvcReq)); // keep this for ourselves
+ break;
+
+
+ case XST_INIT2:
+
+ // Extra ack...
+
+ // throw away if from our partner or if we are not in a list.
+ if (hwndServer == (HWND)pci->ci.hConvPartner ||
+ GetParent(hwnd) == pci->ci.pai->hwndDmg) {
+Abort:
+ TRACETERM((szT, "ClientInitAck: Extra ack terminate: %x->%x\n", hwndServer, hwnd));
+ PostMessage(hwndServer, WM_DDE_TERMINATE, hwnd, 0L);
+ FreeHsz(aApp);
+ FreeHsz(aTopic);
+ break;
+ }
+
+ if (GetWindowLong(hwndServer, GWL_WNDPROC) != (LONG)ServerWndProc) {
+
+ // Non Local Extra Ack... terminate and attempt reconnection.
+
+ TRACETERM((szT, "ClientInitAck: Extra ack terminate and reconnect: %x->%x\n", hwndServer, hwnd));
+ PostMessage(hwndServer, WM_DDE_TERMINATE, hwnd, 0L);
+ GetDDEClientWindow(pci->ci.pai, GetParent(hwnd),
+ pci->hwndInit, aApp, aTopic, &pci->ci.CC);
+
+ // PROGMAN HACK!!!!
+ if (aApp != aProgmanHack) {
+ FreeHsz(aApp);
+ FreeHsz(aTopic);
+ }
+ break;
+ }
+ // Local Extra Ack... create a client window, set it up to be talking
+ // to the server window and tell the server window to change
+ // partners.
+
+
+ hwndClient = CreateWindow(SZCLIENTCLASS, szNull, WS_CHILD,
+ 0, 0, 0, 0, GetParent(hwnd), NULL, hInstance, &(pci->ci.pai));
+
+ if (!hwndClient) {
+ SETLASTERROR(pci->ci.pai, DMLERR_SYS_ERROR);
+ goto Abort;
+ }
+
+ pciNew = (PCLIENTINFO)GetWindowLong(hwndClient, GWL_PCI);
+ pciNew->ci.xad.state = XST_CONNECTED;
+ pciNew->ci.xad.LastError = DMLERR_NO_ERROR;
+ pciNew->ci.aServerApp = aApp;
+ pciNew->ci.hszSvcReq = pci->ci.hszSvcReq;
+ IncHszCount(LOWORD(pciNew->ci.hszSvcReq));
+ pciNew->ci.aTopic = aTopic;
+ pciNew->ci.hConvPartner = MAKEHCONV(hwndServer);
+ pciNew->ci.hwndFrame = pci->hwndInit;
+ pciNew->ci.fs |= ST_CONNECTED | ST_ISLOCAL;
+ MONCONN(pciNew->ci.pai, aApp, aTopic, hwnd, hwndServer, TRUE);
+ SendMessage(hwndServer, UMSR_CHGPARTNER, hwndClient, 0L);
+
+ break;
+ }
+
+ return(TRUE);
+}
+
diff --git a/private/mvdm/wow16/ddeml/stdptcl.c b/private/mvdm/wow16/ddeml/stdptcl.c
new file mode 100644
index 000000000..c989fc0e2
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/stdptcl.c
@@ -0,0 +1,822 @@
+/****************************** Module Header ******************************\
+* Module Name: STDPTCL.C
+*
+* This module contains functions that implement the standard DDE protocol
+*
+* Created: 4/2/91 Sanfords
+*
+* Copyright (c) 1991 Microsoft Corporation
+\***************************************************************************/
+
+#include <string.h>
+#include <memory.h>
+#include "ddemlp.h"
+
+
+VOID FreeDdeMsgData(
+WORD msg,
+LPARAM lParam)
+{
+ WORD fmt;
+
+ switch (msg) {
+ case WM_DDE_DATA:
+ case WM_DDE_POKE:
+ /*
+ * Only free if fRelease is set!
+ */
+ {
+ DDEDATA FAR *pDdeData = (DDEDATA FAR *)GLOBALLOCK(LOWORD(lParam));
+ if (pDdeData != NULL) {
+ if (pDdeData->fRelease) {
+ fmt = pDdeData->cfFormat;
+ GlobalUnlock(LOWORD(lParam));
+ FreeDDEData(LOWORD(lParam), fmt);
+ } else {
+ GlobalUnlock(LOWORD(lParam));
+ }
+ }
+ }
+ break;
+
+ case WM_DDE_ADVISE:
+ GLOBALFREE(LOWORD(lParam));
+ break;
+
+ case WM_DDE_EXECUTE:
+ GLOBALFREE(HIWORD(lParam));
+ break;
+ }
+}
+
+
+/***************************** Private Function ****************************\
+* Processes a client transfer request issued by DdeClientTransaction
+* function. This may be synchronous or asynchronous.
+*
+* This function is responsible for properly filling in pXferInfo->pulResult.
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+long ClientXferReq(
+PXFERINFO pXferInfo,
+HWND hwnd,
+PCLIENTINFO pci)
+{
+ PCQDATA pcqd;
+ LAP myLostAck;
+ long retVal;
+
+ if (pci->ci.xad.state != XST_CONNECTED) {
+ SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
+ return(0);
+ }
+
+ if (pXferInfo->ulTimeout == TIMEOUT_ASYNC) {
+ /*
+ * Create a client async queue if needed.
+ */
+ if (pci->pQ == NULL)
+ pci->pQ = CreateQ(sizeof(CQDATA));
+ if (pci->pQ == NULL) {
+ SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
+ return(0);
+ }
+
+ /*
+ * add a client queue item to track this transaction and return
+ * the ID.
+ */
+ pcqd = (PCQDATA)Addqi(pci->pQ);
+ if (pcqd == NULL) {
+ SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
+ return(0);
+ }
+
+ IncHszCount(LOWORD(pXferInfo->hszItem)); // structure copy
+ hmemcpy((LPBYTE)&pcqd->XferInfo, (LPBYTE)pXferInfo, sizeof(XFERINFO));
+ pcqd->xad.state = XST_CONNECTED;
+ pcqd->xad.pdata = 0L;
+ pcqd->xad.LastError = DMLERR_NO_ERROR;
+ pcqd->xad.pXferInfo = &pcqd->XferInfo;
+ pcqd->xad.DDEflags = 0;
+ /*
+ * point pulResult to a safe place
+ */
+ pcqd->XferInfo.pulResult = (LPDWORD)&pcqd->xad.DDEflags;
+ /*
+ * Get transaction started - if it fails, quit now.
+ */
+ if ((pcqd->xad.LastError = SendClientReq(pci->ci.pai, &pcqd->xad,
+ (HWND)pci->ci.hConvPartner, hwnd)) == DMLERR_SERVER_DIED) {
+ pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
+ FreeHsz(LOWORD(pcqd->XferInfo.hszItem));
+ Deleteqi(pci->pQ, MAKEID(pcqd));
+ /*
+ * RARE case of server dyeing in the middle of transaction
+ * initiation.
+ */
+ SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
+ return(0);
+ }
+ if (pXferInfo->pulResult != NULL) {
+ *pXferInfo->pulResult = MAKEID(pcqd);
+ }
+ return(1);
+
+ }
+
+ /*
+ * Set this so messages comming in during the conversation know whats up
+ */
+ pci->ci.xad.pXferInfo = pXferInfo;
+
+ if (SETLASTERROR(pci->ci.pai,
+ SendClientReq(pci->ci.pai, &pci->ci.xad, (HWND)pci->ci.hConvPartner, hwnd)) ==
+ DMLERR_SERVER_DIED) {
+ return(0);
+ }
+
+ // HACK
+ // If this is an EXEC and the timeout is 1 sec then this
+ // is probably PC Tools 2.0 trying to add items to the shell so
+ // crank up the timout.
+
+ if ((pXferInfo->wType == XTYP_EXECUTE) && (pXferInfo->ulTimeout == 1*1000))
+ {
+ pXferInfo->ulTimeout = 10*1000;
+ }
+
+ timeout(pci->ci.pai, pXferInfo->ulTimeout, hwnd);
+
+ retVal = ClientXferRespond(hwnd, &pci->ci.xad, &pci->ci.pai->LastError);
+ switch (pci->ci.xad.state) {
+ case XST_INCOMPLETE:
+ /* now add a record of the ack we expect to eventually get
+ * to the lost ack pile. When it arrives we'll know what to
+ * free up -- either a memory handle or an atom.
+ */
+ myLostAck.type = pXferInfo->wType;
+ if (pXferInfo->wType == XTYP_EXECUTE)
+ myLostAck.object = HIWORD(pXferInfo->hDataClient);
+ else
+ myLostAck.object = LOWORD(pXferInfo->hszItem);
+ AddPileItem(pLostAckPile, (LPBYTE)&myLostAck, NULL);
+ pci->ci.xad.state = XST_CONNECTED;
+ }
+ if (pci->ci.fs & ST_DISC_ATTEMPTED) {
+ /*
+ * During this transaction a call to DdeDisconnect was attempted.
+ * complete the call now.
+ */
+ Disconnect(hwnd, ST_PERM2DIE, pci);
+ }
+ return(retVal);
+}
+
+
+
+/***************************** Private Function ****************************\
+* This routine sends the apropriate initiation messages for starting a
+* client request according to the transaction data given.
+*
+* returns any appropriate DMLERR_
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+WORD SendClientReq(
+PAPPINFO pai,
+PXADATA pXad,
+HWND hwndServer,
+HWND hwnd)
+{
+ WORD fsStatus = 0;
+ WORD msg;
+ WORD lo, hi;
+ HANDLE hData;
+
+ hi = LOWORD(pXad->pXferInfo->hszItem); /* all but exec need this */
+
+ switch (pXad->pXferInfo->wType) {
+ case XTYP_REQUEST:
+ msg = WM_DDE_REQUEST;
+ IncHszCount(hi); // message copy
+#ifdef DEBUG
+ cAtoms--; // don't count this
+#endif
+ lo = pXad->pXferInfo->wFmt;
+ pXad->state = XST_REQSENT;
+ break;
+
+ case XTYP_POKE:
+ msg = WM_DDE_POKE;
+ lo = HIWORD(pXad->pXferInfo->hDataClient);
+ if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
+ hData = lo; // need to free this on failed post.
+ pXad->state = XST_POKESENT;
+ XmitPrep(pXad->pXferInfo->hDataClient, pai);
+ break;
+
+ case XTYP_EXECUTE:
+ msg = WM_DDE_EXECUTE;
+ hi = HIWORD(pXad->pXferInfo->hDataClient);
+ if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
+ hData = hi; // need to free this on failed post.
+ lo = 0;
+ pXad->state = XST_EXECSENT;
+ // we DONT XmitPrep() because we retain responsibility over the
+ // data handle during the execute transaction regardless of
+ // the server's response.
+ // XmitPrep(pXad->pXferInfo->hDataClient, pai);
+ break;
+
+ case XTYP_ADVSTART:
+ case XTYP_ADVSTART | XTYPF_NODATA:
+ case XTYP_ADVSTART | XTYPF_ACKREQ:
+ case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
+ fsStatus = DDE_FRELEASE | ((pXad->pXferInfo->wType &
+ (XTYPF_ACKREQ | XTYPF_NODATA)) << 12);
+ msg = WM_DDE_ADVISE;
+ if ((hData = AllocDDESel(fsStatus, pXad->pXferInfo->wFmt,
+ (DWORD)sizeof(DWORD))) == 0) {
+ pXad->state = XST_CONNECTED;
+ return(DMLERR_MEMORY_ERROR);
+ }
+ lo = hData;
+ pXad->pXferInfo->hDataClient = (HDDEDATA)MAKELONG(0, hData);
+ /* free later if we get nack */
+ pXad->state = XST_ADVSENT;
+ break;
+
+ case XTYP_ADVSTOP:
+ msg = WM_DDE_UNADVISE;
+ lo = pXad->pXferInfo->wFmt;
+ pXad->state = XST_UNADVSENT;
+ break;
+
+ default:
+ return(DMLERR_INVALIDPARAMETER);
+ break;
+ }
+
+ /*
+ * Send transfer
+ */
+ if (IsWindow(hwndServer)) {
+
+ PCLIENTINFO pci;
+
+ pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
+
+ if (!PostDdeMessage(&pci->ci, msg, hwnd, MAKELONG(lo,hi), 0, 0)) {
+ pXad->state = XST_CONNECTED;
+ if (hData)
+ FreeDDEData(hData, pXad->pXferInfo->wFmt);
+ return(DMLERR_POSTMSG_FAILED);
+ }
+ } else {
+ /*
+ * We lost the server, we are TERMINATED arnold!
+ */
+ pXad->state = XST_NULL;
+ if (hData)
+ FreeDDEData(hData, pXad->pXferInfo->wFmt);
+ return(DMLERR_SERVER_DIED);
+ }
+ return(DMLERR_NO_ERROR);
+}
+
+
+
+
+VOID ServerProcessDDEMsg(
+PSERVERINFO psi,
+WORD msg,
+HWND hwndServer,
+HWND hwndClient,
+WORD lo,
+WORD hi)
+{
+ PADVLI pAdviseItem;
+ WORD wType;
+ DWORD dwData1 = 0;
+ HDDEDATA hData = 0L;
+ WORD wFmt = 0;
+ WORD wStat = 0;
+ LPSTR pMem;
+ HANDLE hMemFree = 0;
+ BOOL fQueueOnly = FALSE;
+
+ /*
+ * only respond if this is for us.
+ */
+ if (hwndClient != (HWND)psi->ci.hConvPartner)
+ return;
+
+ if (!(psi->ci.fs & ST_CONNECTED)) {
+ /*
+ * Dde messages have been received AFTER we have terminated. Free up
+ * the information if appropriate.
+ * BUG: This doesn't handle NACK freeing of associated data.
+ */
+ FreeDdeMsgData(msg, MAKELPARAM(lo, hi));
+ }
+
+ switch (msg) {
+ case WM_DDE_REQUEST:
+ wType = XTYP_REQUEST;
+ wFmt = lo;
+ break;
+
+ case WM_DDE_EXECUTE:
+ wType = XTYP_EXECUTE;
+ /* stuff a special flag into the low word to mark as exec data */
+ // We don't call RecvPrep() because we never have responsability for
+ // freeing this data.
+ hData = (HDDEDATA)MAKELONG(HDATA_EXEC | HDATA_NOAPPFREE | HDATA_READONLY, hi);
+ break;
+
+ case WM_DDE_POKE:
+ wType = XTYP_POKE;
+ pMem = GLOBALLOCK(lo);
+ if (pMem == NULL) {
+ SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
+ return;
+ }
+ wFmt = ((DDEPOKE FAR*)pMem)->cfFormat;
+ wStat = *(WORD FAR*)pMem;
+ hData = RecvPrep(psi->ci.pai, lo, HDATA_NOAPPFREE);
+ break;
+
+ case WM_DDE_ADVISE:
+ wType = XTYP_ADVSTART; /* set ST_ADVISE AFTER app oks advise loop */
+ pMem = GLOBALLOCK(lo);
+ if (pMem == NULL) {
+ SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
+ return;
+ }
+ wFmt = ((DDEADVISE FAR*)pMem)->cfFormat;
+ wStat = *(WORD FAR*)pMem;
+ // If this is NACKed, we don't free it (sicko protocol!#$@) so we
+ // have to have this hang around till qreply gets it.
+ hMemFree = lo;
+
+ /*
+ * Check if we already are linked on this topic/item/format. If so,
+ * skip the callback.
+ */
+ fQueueOnly = (BOOL)(DWORD)FindAdvList(psi->ci.pai->pServerAdvList, hwndServer,
+ psi->ci.aTopic, (ATOM)hi, wFmt);
+ break;
+
+ case WM_DDE_UNADVISE:
+ {
+ PADVLI padvli;
+ ATOM aItem;
+
+ if (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
+ hwndServer, 0, hi, lo)) {
+ wFmt = padvli->wFmt;
+ aItem = padvli->aItem;
+ wType = XTYP_ADVSTOP;
+ MONLINK(psi->ci.pai, FALSE, 0,
+ (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
+ (HSZ)aItem, wFmt, TRUE,
+ MAKEHCONV(hwndServer), psi->ci.hConvPartner);
+ if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
+ hwndServer, 0, aItem, wFmt)) {
+ psi->ci.fs &= ~ST_ADVISE;
+ } else {
+ while (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
+ hwndServer, 0, hi, lo)) {
+ /*
+ * simulate extra XTYP_ADVSTOP callbacks to server here
+ */
+ MONLINK(psi->ci.pai, FALSE, 0,
+ (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
+ (HSZ)padvli->aItem, padvli->wFmt, TRUE,
+ MAKEHCONV(hwndServer), psi->ci.hConvPartner);
+ MakeCallback(&psi->ci, MAKEHCONV(hwndServer),
+ (HSZ)psi->ci.aTopic,
+ (HSZ)padvli->aItem, padvli->wFmt,
+ XTYP_ADVSTOP, 0, 0, 0, msg, wStat,
+ NULL, // signals qreply to NOT ack
+ 0, FALSE);
+ if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
+ hwndServer, 0, padvli->aItem, padvli->wFmt)) {
+ psi->ci.fs &= ~ST_ADVISE;
+ }
+ }
+ }
+ MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
+ (HSZ)aItem, wFmt, XTYP_ADVSTOP, 0, 0,
+ (HSZ)hi, // item for ACK - see qreply
+ msg, wStat, (HWND)psi->ci.hConvPartner, 0, FALSE);
+ } else {
+ /* unexpected unadvise, NACK it. */
+ PostDdeMessage(&psi->ci, WM_DDE_ACK,
+ hwndServer, MAKELONG(0, hi), 0, 0);
+ return;
+ }
+ return;
+ }
+
+ case WM_DDE_ACK:
+ /*
+ * This is an ack in response to the FACKREQ bit being set.
+ * See if this refers to one of the advise loops.
+ */
+ if ((pAdviseItem = FindAdvList(psi->ci.pai->pServerAdvList,
+ hwndServer, 0, hi, wFmt)) &&
+ (pAdviseItem->fsStatus & DDE_FACKREQ)) {
+ /*
+ * Update advise loop status - no longer waiting for an ack.
+ */
+ pAdviseItem->fsStatus &= ~ADVST_WAITING;
+ if (pAdviseItem->fsStatus & ADVST_CHANGED) {
+ PostServerAdvise(hwndServer, psi, pAdviseItem, CADV_LATEACK);
+ }
+ }
+ if (hi)
+ GlobalDeleteAtom(hi); // message copy
+ // BUG: if a NACK is posted to us, WE need to free any data associated
+ // with it.
+ return;
+ }
+
+ MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
+ /* don't know the item on an execute */
+ wType == XTYP_EXECUTE ? 0L : MAKELONG(hi,0),
+ wFmt, wType, hData, dwData1, 0, msg, wStat, (HWND)psi->ci.hConvPartner,
+ hMemFree, fQueueOnly);
+ /*
+ * all freeing of atoms and hXXXX stuff is in QReply
+ */
+ return;
+}
+
+
+VOID PostServerAdvise(
+HWND hwnd,
+PSERVERINFO psi,
+PADVLI pali,
+WORD cLoops)
+{
+ HDDEDATA hData;
+ HANDLE hMem;
+
+ /*
+ * get the data from the server.
+ */
+ hData = DoCallback(psi->ci.pai, MAKEHCONV(hwnd), (HSZ)psi->ci.aTopic,
+ (HSZ)pali->aItem, pali->wFmt, XTYP_ADVREQ, 0L,
+ (DWORD)cLoops, 0L);
+
+ if (!hData) {
+ return;
+ }
+
+ hData = DllEntry(&psi->ci, hData);
+
+ pali->fsStatus &= ~ADVST_CHANGED;
+
+ /*
+ * set Ack Request bit if advise loop calls for it.
+ */
+ if (pali->fsStatus & DDE_FACKREQ) {
+ LPWORD lpFlags;
+
+ pali->fsStatus |= ADVST_WAITING;
+
+ lpFlags = (LPWORD)GLOBALPTR(HIWORD(hData));
+ if (lpFlags == NULL) {
+ SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
+ return;
+ }
+ if (!(*lpFlags & DDE_FACKREQ)) {
+ if (LOWORD(hData) & HDATA_APPOWNED) {
+ // can't mess with it, must use a copy.
+ hMem = HIWORD(hData);
+ hData = CopyHDDEDATA(psi->ci.pai, hData);
+ lpFlags = (LPWORD)GLOBALLOCK(HIWORD(hData));
+ }
+ *lpFlags |= DDE_FACKREQ;
+ }
+ }
+ /*
+ * remove local data handle from local list
+ */
+ FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE);
+
+ /*
+ * post data to waiting client.
+ */
+
+ IncHszCount(pali->aItem); // message copy
+#ifdef DEBUG
+ cAtoms--; // Don't count this because its being shipped out.
+#endif
+ if (!PostDdeMessage(&psi->ci, WM_DDE_DATA, hwnd,
+ MAKELONG(HIWORD(hData), pali->aItem), 0, 0)) {
+ FreeDataHandle(psi->ci.pai, hData, TRUE);
+ }
+}
+
+
+/***************************** Private Function ****************************\
+* This routine handles callback replys.
+* QReply is responsible for freeing any atoms or handles used
+* with the message that generated the callback.
+* It also must recover from dead partner windows.
+*
+* History:
+* Created 9/12/89 Sanfords
+\***************************************************************************/
+void QReply(
+PCBLI pcbi,
+HDDEDATA hDataRet)
+{
+ PSERVERINFO psi;
+ WORD fsStatus, msg;
+ WORD loOut, StatusRet, msgAssoc = 0;
+ HGLOBAL hGMemRet;
+ HGLOBAL hAssoc = 0;
+
+ SEMCHECKOUT();
+
+ // most notification callbacks require no work here.
+
+ if (((pcbi->wType & XCLASS_MASK) == XCLASS_NOTIFICATION) &&
+ (pcbi->wType != XTYP_ADVSTOP) &&
+ (pcbi->wType != XTYP_XACT_COMPLETE))
+ return;
+
+ StatusRet = LOWORD(hDataRet);
+ hGMemRet = HIWORD(hDataRet);
+
+ if (!IsWindow((HWND)pcbi->hConv)) {
+ if (pcbi->wType & XCLASS_DATA && hDataRet && hDataRet != CBR_BLOCK) {
+ FreeDataHandle(pcbi->pai, hDataRet, TRUE);
+ }
+ return;
+ }
+
+ psi = (PSERVERINFO)GetWindowLong((HWND)pcbi->hConv, GWL_PCI);
+
+ switch (pcbi->msg) {
+ case WM_DDE_REQUEST:
+ if (hGMemRet) {
+ hDataRet = DllEntry(&psi->ci, hDataRet);
+ loOut = HIWORD(hDataRet);
+ *(WORD FAR*)GLOBALLOCK(loOut) |=
+ ((pcbi->fsStatus & DDE_FACKREQ) | DDE_FREQUESTED);
+ GlobalUnlock(loOut);
+ XmitPrep(hDataRet, psi->ci.pai);
+ msg = WM_DDE_DATA;
+ } else {
+ /*
+ * send a -ACK
+ */
+ loOut = (StatusRet & (DDE_FBUSY | DDE_FAPPSTATUS));
+ msg = WM_DDE_ACK;
+ }
+ // reuse atom from request message
+ if (!PostDdeMessage(&psi->ci, msg, (HWND)pcbi->hConv,
+ MAKELONG(loOut, LOWORD(pcbi->hszItem)), 0, 0) && msg == WM_DDE_DATA)
+ FreeDataHandle(psi->ci.pai, hDataRet, TRUE);
+ break;
+
+ case WM_DDE_POKE:
+ if (StatusRet & DDE_FACK) {
+ FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
+ } else {
+ // NACKS are properly freed by the 'poker' (how stupid!)
+ FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD,
+ (LPBYTE)&pcbi->hData, FPI_DELETE);
+ hAssoc = hGMemRet;
+ msgAssoc = WM_DDE_POKE;
+ }
+ if (!PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
+ MAKELONG(StatusRet & ~DDE_FACKRESERVED, LOWORD(pcbi->hszItem)),
+ msgAssoc, hAssoc)) {
+ if (!(StatusRet & DDE_FACK)) {
+ FreeDDEData(hGMemRet, pcbi->wFmt);
+ }
+ }
+ break;
+
+ case WM_DDE_EXECUTE:
+ /*
+ * LOWORD(hDataRet) is supposed to be the proper DDE_ constants to return.
+ * we just stick them in the given hData and return
+ * it as an ACK.
+ */
+ PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
+ MAKELONG(StatusRet & ~DDE_FACKRESERVED,HIWORD(pcbi->hData)),
+ 0, 0);
+ break;
+
+ case WM_DDE_ADVISE:
+ /*
+ * hDataRet is fStartAdvise
+ */
+ if ((BOOL)hDataRet) {
+ if (!AddAdvList(psi->ci.pai->pServerAdvList, (HWND)pcbi->hConv, psi->ci.aTopic,
+ (ATOM)pcbi->hszItem,
+ pcbi->fsStatus & (DDE_FDEFERUPD | DDE_FACKREQ),
+ pcbi->wFmt)) {
+ SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
+ fsStatus = 0;
+ } else {
+ MONLINK(psi->ci.pai, TRUE, pcbi->fsStatus & DDE_FDEFERUPD,
+ (HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
+ pcbi->hszItem, pcbi->wFmt, TRUE,
+ pcbi->hConv, psi->ci.hConvPartner);
+ psi->ci.fs |= ST_ADVISE;
+ fsStatus = DDE_FACK;
+ }
+ GlobalUnlock(pcbi->hMemFree);
+ GLOBALFREE(pcbi->hMemFree); /* we free the hOptions on ACK */
+ } else {
+ fsStatus = 0;
+ hAssoc = hGMemRet;
+ msgAssoc = WM_DDE_ADVISE;
+#ifdef DEBUG
+ if (pcbi->hMemFree) {
+ LogDdeObject(0xF000, pcbi->hMemFree);
+ }
+#endif
+ }
+ goto AckBack;
+ break;
+
+ case WM_DDE_UNADVISE:
+ fsStatus = DDE_FACK;
+ if (pcbi->hwndPartner) { // set to null for simulated stops due to WILD stuff
+ // dwData2 == aItem to ack - this could have been wild.
+ PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
+ MAKELONG(fsStatus, LOWORD(pcbi->dwData2)), 0, 0);
+ }
+ break;
+
+ case WM_DDE_DATA:
+ /*
+ * must be an advise data item for the CLIENT or maybe some requested
+ * data mistakenly sent here due to the client queue being flushed.
+ * hDataRet is fsStatus.
+ */
+ /*
+ * Clean up the status incase the app is messed up.
+ */
+ fsStatus = StatusRet & ~DDE_FACKRESERVED;
+
+ if (HIWORD(pcbi->hData) &&
+ (pcbi->fsStatus & DDE_FRELEASE) &&
+ (fsStatus & DDE_FACK || !(pcbi->fsStatus & DDE_FACKREQ)))
+ FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
+
+ if (fsStatus & DDE_FBUSY)
+ fsStatus &= ~DDE_FACK;
+
+ if (HIWORD(pcbi->hData) && !(fsStatus & DDE_FACK)) {
+ msgAssoc = WM_DDE_DATA;
+ hAssoc = HIWORD(pcbi->hData);
+ }
+ /*
+ * send an ack back if requested.
+ */
+ if (pcbi->fsStatus & DDE_FACKREQ) {
+AckBack:
+ PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
+ MAKELONG(fsStatus, LOWORD(pcbi->hszItem)),
+ msgAssoc, hAssoc);
+ } else {
+ if (LOWORD(pcbi->hszItem)) {
+ GlobalDeleteAtom(LOWORD(pcbi->hszItem)); // data message copy
+ }
+ }
+ break;
+
+ case 0:
+ switch (pcbi->wType) {
+ case XTYP_XACT_COMPLETE:
+ FreeHsz(LOWORD(pcbi->hszItem));
+ FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
+ Deleteqi(((PCLIENTINFO)psi)->pQ, pcbi->dwData1);
+ }
+ }
+}
+
+
+
+
+/***************************** Private Function ****************************\
+* This function assumes that a client transfer request has been completed -
+* or should be completed by the time this is called.
+*
+* pci contains general client info
+* pXad contains the transaction info
+* pErr points to where to place the LastError code.
+*
+* Returns 0 on failure
+* Returns TRUE or a Data Selector on success.
+* On failure, the conversation is left in a XST_INCOMPLETE state.
+* On success, the conversation is left in a XST_CONNECTED state.
+*
+* History:
+* Created 9/1/89 Sanfords
+\***************************************************************************/
+long ClientXferRespond(
+HWND hwndClient,
+PXADATA pXad,
+LPWORD pErr)
+{
+ PCLIENTINFO pci;
+
+ if (pXad->state == XST_INCOMPLETE)
+ return(0);
+
+ pci = (PCLIENTINFO)GetWindowLong(hwndClient, GWL_PCI);
+ switch (pXad->pXferInfo->wType) {
+ case XTYP_REQUEST:
+ if (pXad->state != XST_DATARCVD) {
+ if (*pErr == DMLERR_NO_ERROR)
+ *pErr = DMLERR_DATAACKTIMEOUT;
+ goto failexit;
+ }
+ pXad->state = XST_CONNECTED;
+ return(pXad->pdata); /* this has the handle in low word */
+ break;
+
+ case XTYP_POKE:
+ if (pXad->state != XST_POKEACKRCVD) {
+ if (*pErr == DMLERR_NO_ERROR)
+ *pErr = DMLERR_POKEACKTIMEOUT;
+ goto failexit;
+ }
+passexit:
+ pXad->state = XST_CONNECTED;
+ pXad->pdata = TRUE;
+ return(TRUE);
+ break;
+
+ case XTYP_EXECUTE:
+ if (pXad->state != XST_EXECACKRCVD) {
+ if (*pErr == DMLERR_NO_ERROR)
+ *pErr = DMLERR_EXECACKTIMEOUT;
+ goto failexit;
+ }
+ goto passexit;
+
+ case XTYP_ADVSTART:
+ case XTYP_ADVSTART | XTYPF_NODATA:
+ case XTYP_ADVSTART | XTYPF_ACKREQ:
+ case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
+ if (pXad->state != XST_ADVACKRCVD) {
+ if (*pErr == DMLERR_NO_ERROR)
+ *pErr = DMLERR_ADVACKTIMEOUT;
+ goto failexit;
+ }
+ AssertF((UINT)(XTYPF_ACKREQ << 12) == DDE_FACKREQ &&
+ (UINT)(XTYPF_NODATA << 12) == DDE_FDEFERUPD,
+ "XTYPF_ constants are wrong");
+ if (!AddAdvList(pci->pClientAdvList, hwndClient, 0,
+ LOWORD(pXad->pXferInfo->hszItem),
+ (pXad->pXferInfo->wType & (XTYPF_ACKREQ | XTYPF_NODATA)) << 12,
+ pXad->pXferInfo->wFmt)) {
+ pXad->state = XST_INCOMPLETE;
+ SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
+ return(FALSE);
+ } else {
+ pci->ci.fs |= ST_ADVISE;
+ MONLINK(pci->ci.pai, TRUE, pXad->pXferInfo->wType & XTYPF_NODATA,
+ (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
+ pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
+ pci->ci.hConvPartner, MAKEHCONV(hwndClient));
+ goto passexit;
+ }
+ break;
+
+ case XTYP_ADVSTOP:
+ if (pXad->state != XST_UNADVACKRCVD) {
+ if (*pErr == DMLERR_NO_ERROR)
+ *pErr = DMLERR_UNADVACKTIMEOUT;
+ goto failexit;
+ }
+ if (!DeleteAdvList(pci->pClientAdvList, 0, 0,
+ (ATOM)pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt))
+ pci->ci.fs &= ~ST_ADVISE;
+ MONLINK(pci->ci.pai, FALSE, pXad->pXferInfo->wType & XTYPF_NODATA,
+ (HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
+ pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
+ pci->ci.hConvPartner, MAKEHCONV(hwndClient));
+ goto passexit;
+ }
+
+failexit:
+ pXad->state = XST_INCOMPLETE;
+ return(0);
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddes16.sym b/private/mvdm/wow16/ddeml/tests/ddes16.sym
new file mode 100644
index 000000000..20f845827
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddes16.sym
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/client.c b/private/mvdm/wow16/ddeml/tests/ddestrs/client.c
new file mode 100644
index 000000000..726f50831
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/client.c
@@ -0,0 +1,160 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+extern INT iAvailFormats[];
+extern BOOL UpdateCount(HWND,INT,INT);
+extern HANDLE hmemNet;
+
+void CALLBACK TimerFunc( HWND hwnd, UINT msg, UINT id, DWORD dwTime)
+{
+ HCONV hConv;
+ HCONVLIST hConvList;
+ LONG lflags;
+
+ switch (id%2) {
+ case 1:
+ hConv = 0;
+ hConvList=(HCONVLIST)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST);
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+
+// POKE CHANGES
+#if 0
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ if(DdeClientTransaction("Poke Transaction",
+ strlen("Poke Transaction")+1,
+ hConv,
+ DdeCreateStringHandle(idI,"TestItem",CP_WINANSI),
+ CF_TEXT,
+ XTYP_POKE,
+ TIMEOUT_ASYNC,
+ NULL)==0){
+ DDEMLERROR("DdeStrs.Exe -- DdeClientTransaction failed:XTYP_POKE\r\n");
+ }
+#endif
+
+// END OF POKE CHANGES
+
+ // Allow 'Pause' functionality -p on command line.
+
+ lflags=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if((lflags&FLAG_PAUSE)!=FLAG_PAUSE)
+ {
+
+ if(DdeClientTransaction(szExecRefresh,
+ strlen(szExecRefresh) + 1,
+ hConv,
+ 0,
+ 0,
+ XTYP_EXECUTE,
+ TIMEOUT_ASYNC,
+ NULL)==0){
+ DDEMLERROR("DdeStrs.Exe -- DdeClientTransaction failed:XTYP_EXECUTE\r\n");
+ }
+ }
+ }
+ }
+ return;
+}
+
+BOOL InitClient()
+{
+UINT uid;
+
+ ReconnectList();
+
+ uid = SetTimer( hwndMain,
+ (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CLIENTTIMER),
+ (UINT)(GetWindowLong(hwndMain,OFFSET_DELAY)),
+ TimerFunc);
+
+ // This starts the test immidiatly. No delay waiting for the first
+ // WM_TIMER call.
+
+ TimerFunc(hwndMain,WM_TIMER,uid,0);
+
+ return(TRUE);
+}
+
+VOID CloseClient()
+{
+HCONVLIST hConvList;
+
+ hConvList=(HCONVLIST)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST);
+ KillTimer(hwndMain,(UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CLIENTTIMER));
+ if (!DdeDisconnectList(hConvList)) {
+ DDEMLERROR("DdeStrs.Exe -- DdeDisconnectList failed\r\n");
+ }
+
+}
+
+VOID ReconnectList()
+{
+ HCONV hConv;
+ HCONVLIST hConvList=0;
+ LONG cClienthConvs;
+ INT i;
+ DWORD dwid;
+
+ dwid=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+ if(dwid==0) {
+ DDEMLERROR("DdeStrs.Exe -- Null IdInst, aborting Connect!\r\n");
+ return;
+ }
+
+ hConvList = DdeConnectList(dwid,
+ ServiceInfoTable[0].hszService,
+ Topics[0].hszTopic,
+ GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST),
+ NULL);
+ if (hConvList == 0) {
+
+ // This call is expected to fail in the case of a client
+ // starting when there is no available server. Just return
+ // from the routine and continue.
+
+ return;
+ }
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST,hConvList);
+
+ hConv = 0;
+ cClienthConvs = 0L;
+
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+ for (i=0; i<(int)Items[0].cFormats; i++) {
+ if (iAvailFormats[i]) {
+ if (!DdeClientTransaction( NULL,
+ 0,
+ hConv,
+ Items[0].hszItem,
+ TestItemFormats[i].wFmt,
+ XTYP_ADVSTART|XTYPF_ACKREQ,
+ TIMEOUT_ASYNC,
+ NULL)){
+ DDEMLERROR("DdeStrs.Exe -- Error DdeClientTransaction failed\r\n");
+ return;
+ } // if
+
+ } // if
+
+ } // for
+
+ cClienthConvs++;
+
+ } // while
+
+ // Update the client count for the current thread.
+
+ dwid=GETCURRENTTHREADID();
+
+ SetThreadLong(dwid,OFFSET_CCLIENTCONVS,cClienthConvs);
+
+ UpdateCount(hwndMain,OFFSET_CLIENT_CONNECT,PNT);
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c b/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c
new file mode 100644
index 000000000..84504b1bb
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c
@@ -0,0 +1,990 @@
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+#ifdef WIN16
+#include <time.h>
+#endif
+
+extern BOOL fServer;
+extern BOOL fClient;
+extern INT iAvailFormats[];
+extern BOOL UpdateCount(HWND,INT,INT);
+extern LPSTR pszNetName;
+extern HANDLE hmemNet;
+BOOL IsTopicNameFromNetDde(LPSTR,LPSTR);
+BOOL FixForNetDdeStartup(HWND,LPSTR);
+BOOL FixForStressPercentage(HWND,LPSTR);
+BOOL SetStress(HWND,LONG);
+
+
+/***************************************************************************\
+*
+* InitArgsError
+*
+\***************************************************************************/
+
+VOID InitArgsError(HWND hwnd, unsigned at)
+{
+ /* This function informs the user of an error. */
+
+ static char *mpatszError[] = {
+ "DdeStrs.Exe -- Invalid command line\r\nTry DdeStrs -5% for standard run or DdeStrs -? for help",
+ "DdeStrs.Exe -- Invalid number, possibly missing option value",
+ "DdeStrs.Exe -- Invalid log level",
+ "DdeStrs.Exe -- Invalid number of test to execute",
+ "DdeStrs.Exe -- Invalid starting test number"
+ };
+
+ MessageBox(NULL,mpatszError[at],"Error:DdeStrs",MB_OK|MB_ICONEXCLAMATION);
+}
+
+/***************************************************************************\
+*
+* SysTime - This routine is intended to hide the differences between
+* the 16 bit time routines and win 32. All time queries
+* come through this point.
+*
+\***************************************************************************/
+
+VOID SysTime( LPSYSTEMTIME lpst ) {
+
+#ifdef WIN32
+ GetSystemTime( lpst );
+#else
+
+time_t t;
+struct tm ttmm;
+struct tm far *ptm=&ttmm;
+
+ t=time(&t);
+ ptm=localtime(&t);
+
+ lpst->wYear =ptm->tm_year;
+ lpst->wMonth =ptm->tm_mon;
+ lpst->wDayOfWeek =ptm->tm_wday;
+ lpst->wDay =ptm->tm_yday;
+ lpst->wHour =ptm->tm_hour;
+ lpst->wMinute =ptm->tm_min;
+ lpst->wSecond =ptm->tm_sec;
+ lpst->wMilliseconds =0;
+
+#endif
+
+}
+
+/************************** Private Function ****************************\
+*
+* ParseCommandLine - This routine controls parsing the command line and
+* initializing command line settings.
+*
+\**************************************************************************/
+
+BOOL ParseCommandLine( HWND hwnd, LPSTR lpcmd ) {
+SYSTEMTIME t;
+LPSYSTEMTIME lptime=&t;
+LONG lflags=0L;
+INT i,nThrd,num,nFmts;
+BOOL fSelect=FALSE;
+
+#ifdef WIN32
+LPCRITICAL_SECTION lpcs;
+HANDLE hmem;
+#endif
+
+ // Defaults
+
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAG_AUTO);
+ SetWindowLong(hwnd,OFFSET_RUNTIME,_1WEEKEND);
+ SetWindowLong(hwnd,OFFSET_STRESS,5L);
+ SetWindowLong(hwnd,OFFSET_DELAY,(100-GetWindowLong(hwnd,OFFSET_STRESS))*DELAY_METRIC);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,0L);
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,1L);
+ SetWindowLong(hwnd,OFFSET_CRITICALSECT,0L);
+
+ if(!get_cmd_arg(hwnd,lpcmd))
+ return FALSE;
+
+ // We need to make a change at this point for the
+ // default client/server settings. If at this point
+ // fClient==fServer==FALSE then we want to turn on
+ // both of these as the default.
+
+ if(!fClient && !fServer) {
+ fClient=TRUE;
+ fServer=TRUE;
+ }
+
+ // We need to check to see if specific formats where
+ // specified. If not then select all of them.
+
+ nFmts=0;
+ for(i=0;i<NUM_FORMATS;i++)
+ if(iAvailFormats[i]) {
+ nFmts=nFmts++;
+ fSelect=TRUE;
+ }
+
+ if(!fSelect) {
+ for(i=0;i<NUM_FORMATS;i++) iAvailFormats[i]=1;
+ nFmts=NUM_FORMATS;
+ }
+
+ // We have now read all of the command line. Make needed adjustment
+ // to the delay as needed by addtional threads.
+
+ // This adjustment code works with the routine SetStress. It
+ // does not simply recalculate values. A change to SetStress will
+ // cause changes in the final value.
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(!(lflags&FLAG_USRDELAY)) {
+
+ num=(INT)GetWindowLong(hwnd,OFFSET_DELAY);
+ nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+
+ // 200 is the base value for basic overhead.
+
+ num=(200)+(num*(nThrd*nThrd)*nFmts);
+
+ SetWindowLong(hwnd,OFFSET_DELAY,num);
+ }
+
+ SetWindowLong(hwnd,OFFSET_BASE_DELAY,GetWindowLong(hwnd,OFFSET_DELAY));
+
+ // We need to know the starting time to calculate
+ // time to quit test.
+
+ SysTime(lptime);
+
+ SetWindowLong(hwnd,OFFSET_STARTTIME_SEC,lptime->wSecond);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_MIN,lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_HOUR,lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_DAY,lptime->wDay);
+
+ SetWindowLong(hwnd,OFFSET_LAST_MIN,lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_LAST_HOUR,lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,0L);
+
+#ifdef WIN32
+ /* Setup our critical section if in multi-thread mode */
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(lflags&FLAG_MULTTHREAD) {
+ hmem=GetMemHandle(sizeof(CRITICAL_SECTION));
+ lpcs=GlobalLock(hmem);
+
+ InitializeCriticalSection(lpcs);
+
+ GlobalUnlock(hmem);
+ SetWindowLong(hwnd,OFFSET_CRITICALSECT,(LONG)hmem);
+ }
+#endif
+
+ return TRUE;
+
+}
+
+/***************************************************************************\
+*
+* SetupArgv - This is a conversion routine to go from the window worlds
+* command line format to the more standard argv, argc
+* format. The routine get_cmd_arg was setup for the
+* argv/argc format.
+*
+\***************************************************************************/
+
+int SetupArgv( char *argv[], char *buff, LPSTR cmdline )
+{
+int i=1;
+
+ while( *cmdline != '\0' ) {
+ argv[i] = &buff[0];
+ while ( *cmdline != ' ' && *cmdline != '\0')
+ *buff++ = *cmdline++;
+ *buff++='\0';
+ while(*cmdline == ' ') cmdline++;
+ i++;
+ }
+
+ return i;
+
+}
+
+/***************************************************************************\
+*
+* get_cmd_arg - This routine parses a argv\argc formatted command
+* line and stores away the values.
+*
+\***************************************************************************/
+
+BOOL PASCAL get_cmd_arg( HWND hwnd, LPSTR cmdline ) {
+
+/* This function parses the command line for valid options. TRUE is
+ returned if all of the options are valid; otherwise, FALSE is returned. */
+
+char *pch;
+int iarg;
+unsigned at = AT_SWITCH;
+unsigned num;
+int argc;
+char *argv[10];
+char buff[200];
+LONG lflags=0L;
+
+#ifdef WIN32
+int nThrd;
+#endif
+
+ FixForStressPercentage(hwnd,cmdline);
+ FixForNetDdeStartup(hwnd,cmdline);
+
+ argc = SetupArgv( argv, buff, cmdline );
+
+ /* Iterate over the arguments in the command line. */
+ iarg=1;
+ while(iarg<argc && argv[iarg]!='\0') {
+
+ /* Get the next argument. */
+ pch = argv[iarg];
+
+ /* Process the argument depending upon the arguement
+ * type we are looking for.
+ */
+
+ switch (at) {
+
+ case AT_SWITCH:
+
+ /* All options begin with a switch character. */
+
+ if (*pch != '-' && *pch != '/') {
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+
+ /* Skip over the switch character. */
+ pch++;
+
+ /* Look for an option character. */
+ do {
+ switch (*pch) {
+ case 'a':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_APPOWNED));
+ break;
+
+ case 'p':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_PAUSE_BUTTON|FLAG_PAUSE));
+ break;
+
+ case '?':
+ /* Give brief help. For more detailed information see ddestrs.txt in source directory */
+ MessageBox(NULL,"DdeStrs Options...\r\n-#% stress\r\n-e# delay\r\n-t# run time\r\n-d debug\r\n-a appowned\r\n-s server\r\n-c client\r\n-f# format\r\n-nNAME netdde\r\n-i# threads\r\n-p pause\r\n\nSee DdeStrs.Txt","DdeStrs Help",MB_OK);
+ return FALSE;
+ break;
+
+
+ case 'b':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_BACKGROUND));
+ break;
+
+ case 'l':
+ /* Set the name of the log file. */
+ if (*(++pch) == '\0') {
+ /* The next argument should be a filename. */
+ at = AT_FILE;
+ goto NextArg;
+ }
+
+ case 'c':
+ /* This is a client */
+ fClient = TRUE;
+ break;
+
+ case 's':
+ /* This is a server */
+ fServer = TRUE;
+ break;
+
+ case 'i':
+
+ /* The next argument should be the number of threads (w32 only) The
+ range for this = [1...5] */
+#ifdef WIN32
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_MULTTHREAD));
+#endif
+ at = AT_THRD;
+ goto ParseNumber;
+
+ case 'x':
+ /* The next argument should be the stress level. */
+ at = AT_STRESS;
+ goto ParseNumber;
+
+ case 'e':
+ /* The next argument is the delay in milliseconds */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRDELAY));
+ at = AT_DELAY;
+ goto ParseNumber;
+
+ case 'd':
+ /* The next argument is whether we are in debug mode */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_DEBUG));
+ break;
+
+ case 'n':
+ /* Process the network name */
+ pch++;
+
+ while( *pch==' ' ||
+ *pch=='\\') pch++;
+
+ pszNetName=GetMem(MAX_TITLE_LENGTH,&hmemNet);
+ pszNetName=TStrCpy(pszNetName,pch);
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_NET));
+
+ while(*pch!='\0') {
+ pch++;
+ }
+
+ pch--;
+
+ break;
+
+ case 'f':
+ at = AT_FORMAT;
+ goto ParseNumber;
+
+ case 't':
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_TIME));
+
+ /* The next argument is the time (in minutes)
+ to run the test. */
+
+ at = AT_TIME;
+ goto ParseNumber;
+
+ default:
+ InitArgsError(hwnd,0);
+ return FALSE;
+
+ } // switch
+
+ } while (*(++pch) != '\0'); // do-while loop
+
+ break;
+
+ case AT_FILE:
+
+ /* The next argument should be a switch. */
+ at = AT_SWITCH;
+
+ break;
+
+ParseNumber:
+ /* Does this arg have the number? */
+ if (*(++pch) == '\0') goto NextArg;
+
+ case AT_STRESS:
+ case AT_DELAY:
+ case AT_TIME:
+ case AT_WND:
+ case AT_MSG:
+ case AT_THRD:
+
+ /* Set the number of tests to run. */
+
+ if ((num = latoi(pch))==0) {
+ /* Indicate that an invalid number has been specified. */
+ if(at!=AT_DELAY) {
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+ }
+
+ switch (at) {
+ case AT_FORMAT:
+ if (num>0 && num<=NUM_FORMATS) {
+ iAvailFormats[num-1]=1;
+ }
+ break;
+
+ case AT_STRESS:
+ SetStress(hwnd,num);
+ break;
+
+ case AT_DELAY:
+ SetWindowLong(hwnd,OFFSET_DELAY,num);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRDELAY));
+ break;
+
+ case AT_TIME:
+ SetWindowLong(hwnd,OFFSET_RUNTIME,num);
+ break;
+
+ case AT_THRD:
+#ifdef WIN32
+ if(num>THREADLIMIT) num=THREADLIMIT;
+
+ // One is not really Mult-thread, shutoff the thread
+ // code and run in normal form.
+
+ if(num==1)
+ {
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ lflags=FLAGOFF(lflags,FLAG_MULTTHREAD);
+ lflags=FLAGON(lflags,FLAG_USRTHRDCOUNT);
+
+ SetWindowLong(hwnd,OFFSET_FLAGS,lflags);
+
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,num);
+ }
+ else {
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,num);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRTHRDCOUNT));
+ }
+#endif
+ break;
+
+ default:
+ InitArgsError(hwnd,0);
+ return FALSE;
+ break;
+
+ } //switch (inside)
+
+ /* The next argument should be a switch. */
+ at = AT_SWITCH;
+ break;
+
+ } // switch (outside)
+
+NextArg:;
+ iarg++;
+ } // While loop
+
+
+ /* Are we still looking for a filename or number? */
+ if (at != AT_SWITCH) {
+ /* Tell the user about the filename or number not found. */
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // end get_cmd_args
+
+/***************************************************************************\
+*
+* SetStress
+*
+\***************************************************************************/
+
+BOOL SetStress(HWND hwnd, LONG num) {
+LONG lflags;
+
+#ifdef WIN32
+LONG l;
+#endif
+
+INT n;
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_STRESS,num);
+
+#ifdef WIN32
+
+ if(!(lflags&FLAG_USRTHRDCOUNT)) {
+
+ l=S2L(DIV(num,20)+1);
+ if(num>9 && num<20) l++;
+
+ if(l>5) l=5;
+ if(l<1) l=1;
+
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,l);
+
+ if(l>1) {
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_MULTTHREAD));
+ }
+ }
+#endif
+
+ if(!(lflags&FLAG_USRDELAY)) {
+ n=(int)(100-num)*DELAY_METRIC;
+ SetWindowLong(hwnd,OFFSET_DELAY,n);
+
+ // since dde messages have highest priority we don't
+ // want to swamp the system. Always have some
+ // minimal delay.
+
+ if(n<10) {
+ SetWindowLong(hwnd,OFFSET_DELAY,10);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGOFF(lflags,FLAG_DELAYON));
+ }
+ }
+
+ return TRUE;
+}
+
+/******************************************************************\
+* TStrLen
+* 11/20/88
+*
+* Finds the length of a string
+\******************************************************************/
+
+INT TStrLen( LPSTR pStr )
+{
+INT len = 0;
+
+ while( *pStr++!='\0' ) len++;
+
+ return( len );
+}
+
+/******************************************************************\
+* TStrCat
+* 7/16/92
+*
+* Appends source string to destination string. Source string and
+* destination string must be zero terminated!
+\******************************************************************/
+
+LPSTR TStrCat( LPSTR dest, LPSTR source)
+{
+LPSTR start_source;
+LPSTR start_dest;
+INT i=0;
+
+ /* If we have a NULL pointer set destination to NULL and
+ continue */
+
+ if (!dest || !source) {
+ MessageBox(NULL,"TStrCat - NULL ptr for dest or source string!","Error : WmStress",MB_ICONEXCLAMATION);
+ return NULL;
+ }
+
+ start_dest = dest;
+ start_source = source;
+
+ while (*dest++!='\0' && i++<=MAX_TITLE_LENGTH)
+ ;
+
+ TStrCpy(dest,source);
+
+ source = start_source;
+ dest = start_dest;
+
+ return( start_dest );
+}
+
+/*************************** Private Function ******************************\
+*
+* TStrCmp
+*
+* Compares two NULL terminated strings ( returns TRUE if equal )
+*
+\***************************************************************************/
+
+BOOL TStrCmp(LPSTR s, LPSTR t)
+{
+ // Valid pointer?
+
+ if ( !s && !t ) return TRUE; // If either is NULL then they should
+ if ( (!s&&t)||(s&&!t) ) // both be NULL. Otherwise error.
+ return FALSE;
+
+ for (; *s == *t; s++, t++) // Compare strings
+ if (*s=='\0')
+ return TRUE;
+
+ if ((*s-*t)== 0) return TRUE;
+ else return FALSE;
+}
+
+/******************************************************************\
+* TStrCpy
+* 11/20/88
+*
+* Copies a string from source to destination
+\******************************************************************/
+
+LPSTR TStrCpy( LPSTR dest, LPSTR source)
+{
+LPSTR start_source;
+LPSTR start_dest;
+INT i;
+
+ /* If we have a NULL pointer set destination to NULL and
+ continue */
+
+ if(!source) {
+ dest=NULL;
+ return NULL;
+ }
+
+ if (!dest) {
+ MessageBox(NULL,"TStrCpy - NULL ptr for dest!","Error:WmStress",MB_ICONEXCLAMATION);
+ return NULL;
+ }
+
+ start_dest = dest;
+ start_source = source;
+
+ i=0;
+ while (*dest++ = *source++){
+ i++;
+ }
+
+ source = start_source;
+ dest = start_dest;
+
+ return( start_dest );
+}
+
+/***************************************************************************\
+*
+* FixForStressPercentage - This is a fix for the command line -5%. The
+* origional get_cmd_args() did not handle this
+* case. This routine handles string modifications
+* to the command line parse will be correct.
+*
+\***************************************************************************/
+
+BOOL FixForStressPercentage(HWND hwnd, LPSTR lpszStart )
+{
+CHAR ac[6];
+INT i;
+LPSTR lpsz,lpszdash;
+BOOL bLastTime;
+
+ lpsz =lpszStart;
+ lpszdash =NULL;
+
+ ac[0]='x';
+
+ while(*lpsz!='\0') {
+
+ if( *lpsz=='-') lpszdash=lpsz;
+
+ if( *lpsz=='%') {
+
+ if(lpszdash==NULL) return FALSE;
+ else lpsz=(LPSTR)(lpszdash+1);
+
+ // Basically what we do hear is replace the '%' by an 'x'
+ // and shift characters...(-60% becomes -x60).
+
+ i=0;
+ bLastTime=FALSE;
+
+ while(!bLastTime) {
+ ac[i+1]=*lpsz;
+ if(*lpsz=='%') bLastTime=TRUE;
+ *lpsz=ac[i];
+ lpsz++;
+ i++;
+ }
+
+ } // if
+
+ lpsz++;
+
+ } // while
+
+ return TRUE;
+ hwnd;
+
+} // FixForStressPercentage
+
+/***************************************************************************\
+*
+* FixForNetDdeStartup - This is a fix for the command line "Test". The
+* origional get_cmd_args() did not handle this
+* case. This routine modifies the string from
+* "Test" to "-s".
+*
+* The reason for this change is to make ddestrs.exe
+* netdde aware for the startup situation. When
+* netdde starts up the application is passed the topic
+* name (in this case Test) to the application on the
+* command line.
+*
+* NOTE!!! The below code relies on TOPIC="Test". If this has changed then
+* update FixForNetDdeStartup() and IsTopicNameFromNetDde().
+*
+\***************************************************************************/
+
+BOOL FixForNetDdeStartup( HWND hwnd, LPSTR lpszStart )
+{
+INT i;
+LPSTR lpsz;
+
+ lpsz =lpszStart;
+
+ i=1;
+ while(*lpsz!='\0') {
+
+ // Important. I am relying on lpsz being the same
+ // exiting IsTopicNameFromNetDde as it was going in!!!
+
+ if(IsTopicNameFromNetDde(lpsz,TOPIC)) {
+
+ // We have one last check before we make the change. lpsz-2
+ // must not be '-' or '/' and lpsz must not be 'n' or 'N'.
+
+ // Are we at the 3rd char or later? We can't make this
+ // final check unless we have previous character to see.
+
+ if(i>=3) {
+ if( *(lpsz-1)!='n' &&
+ *(lpsz-1)!='N' &&
+ *(lpsz-2)!='-' &&
+ *(lpsz-2)!='/' )
+ {
+ *lpsz='-';
+ *(lpsz+1)='s'; // change "Test" to "-s "
+ *(lpsz+2)=' ';
+ *(lpsz+3)=' ';
+ } // if check for -,n,N,/
+
+ } // if i>=3
+ else {
+ *lpsz='-';
+ *(lpsz+1)='s'; // change "Test" to "-s "
+ *(lpsz+2)=' ';
+ *(lpsz+3)=' ';
+ }
+
+ } // IsTopicName...
+
+ lpsz++;
+ i++; // We use this to keep charater position.
+
+ } // while
+
+ return TRUE;
+ hwnd;
+
+} // FixForNetDdeStartup
+
+/***************************************************************************\
+*
+* IsTopicNameFromNetDde
+*
+\***************************************************************************/
+
+BOOL IsTopicNameFromNetDde(LPSTR lpsz, LPSTR lpszTopic )
+{
+LPSTR lpstr;
+
+ // Check to see that string is >=4 characters not including NULL
+ // terminator.
+
+ lpstr=lpsz;
+
+ if(TStrLen(lpstr)<TStrLen(lpszTopic)) return FALSE;
+
+
+ // Is our topic string present.
+
+ if(*lpsz!='T' && *lpsz!='t') {
+ return FALSE;
+ }
+
+ if(*(lpsz+1)!='e' && *(lpsz+1)!='E') {
+ return FALSE;
+ }
+
+ if(*(lpsz+2)!='s' && *(lpsz+2)!='S') {
+ return FALSE;
+ }
+
+ if(*(lpsz+3)!='t' && *(lpsz+3)!='T') {
+ return FALSE;
+ }
+
+ if(*(lpsz+4)!=' ' && *(lpsz+4)!='\0') {
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // IsTopicNameFromNetDde
+
+/************************** Private Function ****************************\
+*
+* IsTimeExpired - This routine is called periodically to check if its
+* time to quit.
+*
+\**************************************************************************/
+
+BOOL IsTimeExpired( HWND hwnd ) {
+LONG lrtime, lrtPMin, lrtPHour, lrt, l, ll;
+SYSTEMTIME t;
+LPSYSTEMTIME lptime=&t;
+LONG lflags=0L;
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(!(lflags&FLAG_STOP)) {
+ // This is how long we should run. In minutes
+
+ lrtime =GetWindowLong(hwnd,OFFSET_RUNTIME);
+
+ // This is how long we have run. In minutes.
+
+ lrt =GetWindowLong(hwnd,OFFSET_TIME_ELAPSED);
+ l=lrt;
+
+ // Time at last check.
+
+ lrtPMin =GetWindowLong(hwnd,OFFSET_LAST_MIN);
+ lrtPHour=GetWindowLong(hwnd,OFFSET_LAST_HOUR);
+
+ SysTime(lptime);
+
+ if(lrtPHour!=(LONG)(lptime->wHour)) {
+
+ // Calc update minutes for the wrap case.
+
+ lrt=(((_1HOUR-lrtPMin)+lptime->wMinute)+lrt);
+
+ // We need to check for multiple hours since last
+ // update.
+
+ if(lrtPHour>lptime->wHour) {
+
+ // In case clock does not rap at 12:00.
+
+ if(lptime->wHour>12) ll=lptime->wHour-12;
+ else ll=lptime->wHour;
+
+ l=(12-lrtPHour)+ll;
+ }
+ else l=lptime->wHour-lrtPHour;
+
+ if(l>1) {
+ lrt=lrt+((l-1)*_1HOUR);
+ }
+
+ }
+
+ else lrt=((lptime->wMinute-lrtPMin)+lrt);
+
+ SetWindowLong(hwnd,OFFSET_LAST_MIN,(LONG)lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_LAST_HOUR,(LONG)lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,lrt);
+
+ if(lptime->wMinute!=LOWORD(lrtPMin))
+ UpdateCount(hwnd,OFFSET_TIME_ELAPSED,PNT);
+
+ // if elapsed time > runtime time has expired.
+
+ if(lrt>=lrtime)
+ return TRUE;
+ else return FALSE;
+ }
+
+ // If we are already shutting down no need to trigger other WM_CLOSE
+ // messages.
+
+ else return FALSE;
+
+}
+
+/*---------------------------------------------------------------------------*\
+| ASCII TO INTEGER
+| This routine converts an ascii string to a decimal integer.
+|
+| created: 12-Oct-90
+| history: 12-Oct-90 <chriswil> created.
+|
+\*---------------------------------------------------------------------------*/
+int APIENTRY latoi(LPSTR lpString)
+{
+ int nInt,nSign;
+
+
+ if(*lpString == '-')
+ {
+ nSign = -1;
+ lpString++;
+ }
+ else
+ {
+ if(*lpString == '+')
+ lpString++;
+ nSign = 1;
+ }
+
+ nInt = 0;
+ while(*lpString)
+ nInt = (nInt*10) + (*lpString++ - 48);
+
+ return(nInt * nSign);
+}
+
+/*****************************************************************************\
+| INTEGER TO ASCI
+| This routine converts an decimal integer to an ascii string.
+|
+| created: 29-Jul-91
+| history: 29-Jul-91 <johnsp> created.
+|
+\*****************************************************************************/
+LPSTR FAR PASCAL itola(INT i, LPSTR lpsz)
+{
+LPSTR lpsz_start;
+INT irange=1;
+INT id=0;
+
+ lpsz_start=lpsz; // Keep track of the beginning of the
+ // string.
+ while (id=DIV(i,irange)>0)
+ irange=irange*10;
+
+ irange=DIV(irange,10);
+
+ if(i==0) { // If i==0 set string and we
+ *lpsz='0'; // will skip loop
+ lpsz++;
+ }
+
+ while (irange>0) {
+
+ id=DIV(i,irange); // Calculate character
+ *lpsz=(CHAR)(id+48);
+
+ lpsz++;
+ i=i-(irange*id); // Adjust values for next time
+ irange=DIV(irange,10); // through the loop.
+
+ }
+
+ *lpsz='\0'; // Null terminate the string
+
+ return lpsz_start;
+
+}
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico b/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico
new file mode 100644
index 000000000..65c6a7180
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c
new file mode 100644
index 000000000..e05745cb4
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c
@@ -0,0 +1,1856 @@
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+VOID PaintTest(HWND,PAINTSTRUCT *);
+HWND CreateButton(HWND);
+HANDLE hExtraMem=0;
+LPSTR pszNetName=NULL;
+HANDLE hmemNet=NULL;
+BOOL fnoClose=TRUE;
+
+LONG FAR PASCAL MainWndProc(
+HWND hwnd,
+UINT message,
+WPARAM wParam,
+LONG lParam)
+{
+ PAINTSTRUCT ps;
+ HBRUSH hBrush;
+ MSG msg;
+ LONG l;
+ LONG lflags;
+ HWND hbutton;
+
+#ifdef WIN32
+ HANDLE hmem;
+ LPCRITICAL_SECTION lpcs;
+#endif
+
+ switch (message) {
+ case WM_COMMAND:
+
+#ifdef WIN32
+ if(LOWORD(wParam)==0 && HIWORD(wParam)==BN_CLICKED)
+ SendMessage(hwnd,WM_CLOSE,0,0L);
+
+ if(LOWORD(wParam)==1 && HIWORD(wParam)==BN_CLICKED) {
+
+ hbutton=GetDlgItem(hwnd,1);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(lflags&FLAG_PAUSE) {
+ SetFlag(hwnd,FLAG_PAUSE,OFF);
+ SetWindowText(hbutton,"Pause");
+ CheckDlgButton(hwnd,1,0);
+ SetFocus(hwnd);
+ UpdateWindow(hbutton);
+ TimerFunc(hwndMain,WM_TIMER,1,0);
+ }
+ else {
+ SetFlag(hwnd,FLAG_PAUSE,ON);
+ SetWindowText(hbutton,"Start");
+ CheckDlgButton(hwnd,1,0);
+ SetFocus(hwnd);
+ InvalidateRect(hbutton,NULL,FALSE);
+ UpdateWindow(hbutton);
+ }
+ }
+
+#else
+ if(wParam==1 && HIWORD(lParam)==BN_CLICKED) {
+
+ hbutton=GetDlgItem(hwnd,1);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(lflags&FLAG_PAUSE) {
+ SetFlag(hwnd,FLAG_PAUSE,OFF);
+ SetWindowText(GetDlgItem(hwnd,1),"Pause");
+ TimerFunc(hwndMain,WM_TIMER,1,0);
+ CheckDlgButton(hwnd,1,0);
+ SetFocus(hwnd);
+ InvalidateRect(hbutton,NULL,FALSE);
+ UpdateWindow(hbutton);
+ }
+ else {
+ SetFlag(hwnd,FLAG_PAUSE,ON);
+ SetWindowText(GetDlgItem(hwnd,1),"Start");
+ CheckDlgButton(hwnd,1,0);
+ SetFocus(hwnd);
+ InvalidateRect(hbutton,NULL,FALSE);
+ UpdateWindow(hbutton);
+ }
+ }
+
+
+ if(wParam==0 && HIWORD(lParam)==BN_CLICKED)
+ SendMessage(hwnd,WM_CLOSE,0,0L);
+#endif
+ break;
+
+ case WM_ENDSESSION:
+ case WM_CLOSE:
+
+ // Shutdown timers
+
+ if (fClient)
+ {
+ CloseClient();
+ }
+ else {
+ KillTimer(hwndMain,(UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER));
+ }
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+
+#ifdef WIN32
+ if(l&FLAG_MULTTHREAD) {
+
+ // Start conversations disconnecting.
+
+ ThreadDisconnect();
+
+ // Start child thread exit
+
+ ThreadShutdown();
+
+ }
+#endif
+
+ // This will stop us using hwndDisplay and hwndMain
+ // after there destroyed.
+
+ SetFlag(hwnd,FLAG_STOP,ON);
+
+ UninitializeDDE();
+
+ // Free memory allocated for Net address.
+
+ if(l&FLAG_NET) {
+ if(hmemNet) FreeMem(hmemNet);
+ hmemNet=0;
+ }
+
+ // Clean out message queue (main thread)
+
+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ if(msg.message!=WM_TIMER) {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+
+#ifdef WIN32
+ // Can Not rely on the critical section for our flag update
+ // after this point.
+
+ SetFlag(hwnd,FLAG_SYNCPAINT,OFF);
+
+ // OK, Shutdown is now under way. We need to wait until
+ // all child threads exit before removing our critical section
+ // and completing shutdown for main thread.
+
+
+ if(l&FLAG_MULTTHREAD) {
+
+ ThreadWait(hwndMain);
+
+ hmem=(HANDLE)GetWindowLong(hwndMain,OFFSET_CRITICALSECT);
+ SetWindowLong(hwndMain,OFFSET_CRITICALSECT,0L);
+
+ if(hmem)
+ {
+ lpcs=GlobalLock(hmem);
+ if(lpcs) DeleteCriticalSection(lpcs);
+ GlobalUnlock(hmem);
+ GlobalFree(hmem);
+ }
+ }
+#endif
+
+ FreeThreadInfo(GETCURRENTTHREADID());
+
+
+ // Say goodbye to main window. Child threads must be finished
+ // before making this call.
+
+ DestroyWindow(hwnd);
+ break;
+
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+
+ case WM_ERASEBKGND:
+ return 1;
+
+
+ case WM_PAINT:
+ BeginPaint(hwnd, &ps);
+ hBrush=CreateSolidBrush(WHITE);
+ FillRect(ps.hdc,&ps.rcPaint,hBrush);
+ DeleteObject(hBrush);
+ PaintTest(hwnd,&ps);
+ EndPaint(hwnd, &ps);
+ break;
+
+ default:
+ return(DefWindowProc(hwnd, message, wParam, lParam));
+ }
+ return(0L);
+}
+
+#ifdef WIN32
+BOOL ThreadShutdown( VOID ) {
+INT i,nCount,nId,nOffset;
+
+
+ nCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+
+ nOffset=OFFSET_THRD2ID;
+
+ for(i=0;i<nCount-1;i++) {
+ nId=GetWindowLong(hwndMain,nOffset);
+
+ if(!PostThreadMessage(nId,EXIT_THREAD,0,0L))
+ {
+ Sleep(200);
+ if(!PostThreadMessage(nId,EXIT_THREAD,0,0L)) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:PostThreadMessage failed 4 EXIT_THREAD\r\n",NULL,0);
+ }
+ }
+
+ nOffset=nOffset+4;
+ }
+
+ return TRUE;
+
+}
+
+BOOL ThreadDisconnect( VOID ) {
+INT i,nCount,nId,nOffset;
+
+
+ nCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+
+ nOffset=OFFSET_THRD2ID;
+
+ for(i=0;i<nCount-1;i++) {
+ nId=GetWindowLong(hwndMain,nOffset);
+
+ if(!PostThreadMessage(nId,START_DISCONNECT,0,0L))
+ {
+ Sleep(200);
+ if(!PostThreadMessage(nId,START_DISCONNECT,0,0L)) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:PostThreadMessage failed 4 START_DISCONNECT\r\n",NULL,0);
+ }
+ }
+
+ nOffset=nOffset+4;
+ }
+
+ return TRUE;
+
+}
+
+#endif
+
+VOID PaintTest(
+HWND hwnd,
+PAINTSTRUCT *pps)
+{
+ RECT rc,r;
+ static CHAR szT[40];
+ LONG cClienthConvs,cServerhConvs;
+
+ GetClientRect(hwnd, &rc);
+ OffsetRect(&rc, 0, cyText);
+ rc.bottom = rc.top + cyText;
+
+
+#ifdef WIN16
+
+ // Test Mode
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ if(fServer && fClient)
+ {
+ DrawText(pps->hdc, "Client/Server (w16)", -1, &rc, DT_LEFT);
+ }
+ else {
+ if(fServer)
+ {
+ DrawText(pps->hdc, "Server (w16)", -1, &rc, DT_LEFT);
+ }
+ else {
+ DrawText(pps->hdc, "Client (w16)", -1, &rc, DT_LEFT);
+ }
+ }
+ }
+
+ OffsetRect(&rc, 0, 2*cyText); // Skip a line before next item
+
+#else
+
+ // Test Mode
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ if(fServer && fClient)
+ {
+ DrawText(pps->hdc, "Client/Server (w32)", -1, &rc, DT_LEFT);
+ }
+ else {
+ if(fServer)
+ {
+ DrawText(pps->hdc, "Server (w32)", -1, &rc, DT_LEFT);
+ }
+ else {
+ DrawText(pps->hdc, "Client (w32)", -1, &rc, DT_LEFT);
+ }
+ }
+ }
+
+ OffsetRect(&rc, 0, 2*cyText); // Skip a line before next item
+
+#endif
+
+
+ // Stress Percentage
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Stress %", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_STRESS));
+#else
+ wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_STRESS));
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // Run Time
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Run Time", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_RUNTIME));
+#else
+ wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_RUNTIME));
+#endif
+
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // Time Elapsed
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc, "Time Elapsed", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_TIME_ELAPSED));
+#else
+ wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_TIME_ELAPSED));
+#endif
+
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // *** Count Client Connections ****
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+
+ cClienthConvs=GetCurrentCount(hwnd,OFFSET_CCLIENTCONVS);
+ DrawText(pps->hdc,"Client Connect", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", cClienthConvs);
+#else
+ wsprintf(szT, "%ld", cClienthConvs);
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+
+ } // if IntersectRect
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // *** Server Connections ***
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Server Connect", -1, &rc, DT_LEFT);
+
+ cServerhConvs=GetCurrentCount(hwnd,OFFSET_CSERVERCONVS);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", cServerhConvs );
+#else
+ wsprintf(szT, "%ld", cServerhConvs );
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // Client Count (for checking balence between apps)
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Client Count", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d",GetWindowLong(hwnd,OFFSET_CLIENT));
+#else
+ wsprintf(szT, "%ld",GetWindowLong(hwnd,OFFSET_CLIENT));
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // Server Count (for checking balence between apps)
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Server Count", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", GetWindowLong(hwnd,OFFSET_SERVER));
+#else
+ wsprintf(szT, "%ld", GetWindowLong(hwnd,OFFSET_SERVER));
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+
+ // Delay
+
+ if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
+ DrawText(pps->hdc,"Delay", -1, &rc, DT_LEFT);
+
+#ifdef WIN32
+ wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_DELAY));
+#else
+ wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_DELAY));
+#endif
+ CopyRect(&r,&rc);
+ r.left=cxText*LONGEST_LINE;
+ DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
+ }
+
+ OffsetRect(&rc, 0, cyText);
+
+}
+
+int PASCAL WinMain(
+HINSTANCE hInstance,
+HINSTANCE hPrev,
+LPSTR lpszCmdLine,
+int cmdShow)
+{
+ MSG msg;
+ HDC hdc;
+ WNDCLASS wc;
+ TEXTMETRIC tm;
+ INT x,y,cx,cy;
+#ifdef WIN32
+ LONG lflags;
+#endif
+ DWORD idI;
+ HWND hwndDisplay;
+ INT nThrd;
+
+ CHAR sz[250];
+ CHAR sz2[250];
+ LPSTR lpszOut=&sz[0];
+ LPSTR lpsz=&sz2[0];
+
+#ifdef WIN32
+ DWORD dwer;
+#endif
+
+ hInst=hInstance;
+
+ if(!SetMessageQueue(100)) {
+ MessageBox(NULL,"SetMessageQueue failed. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ return FALSE;
+ }
+
+ wc.style = 0;
+ wc.lpfnWndProc = MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = WND;
+ wc.hInstance = hInst;
+ wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDR_ICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szClass;
+
+ if(!hPrev) {
+ if (!RegisterClass(&wc) )
+ {
+#if 0
+ // This was removed because the system was running out of resources (ALPHA only)
+ // which caused this occasionaly to fail. Rather than continue to bring
+ // the message box up (for a known stress situation) the test will abort
+ // and try again.
+
+ MessageBox(NULL,"RegisterClass failed. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+#endif
+ return FALSE;
+ }
+ }
+
+ hwndMain = CreateWindowEx( WS_EX_DLGMODALFRAME,
+ szClass,
+ szClass,
+ WS_OVERLAPPED|WS_MINIMIZEBOX|WS_CLIPCHILDREN,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+
+#ifdef WIN32
+ dwer=GetLastError(); // We want LastError Associated with CW call
+#endif
+
+ if (!hwndMain) {
+ MessageBox(NULL,"Could Not Create Main Window. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+
+#ifdef WIN32
+ if (!IsWindow(hwndMain)) {
+ TStrCpy(lpsz,"CreateWindowEx failed for Main Window but did not return NULL! Test aborting. HWND=%u, LastEr=%u");
+ wsprintf(lpszOut,lpsz,hwndMain,dwer);
+ MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+#else
+ if (!IsWindow(hwndMain)) {
+ TStrCpy(lpsz,"CreateWindowEx failed for Main Window but did not return NULL! Test aborting. HWND=%u");
+ wsprintf(lpszOut,lpsz,hwndMain);
+ MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+#endif
+
+ if (!ParseCommandLine(hwndMain,lpszCmdLine)) {
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+
+ // Note: This needs to be there even for win 16 execution. The
+ // name may be confusing. for win 16 there is obviously only
+ // a single thread. This is handled by the call.
+
+
+ nThrd=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+
+ // Currently ddestrs has a hardcoded thread limit (at THREADLIMIT). So
+ // this should NEVER be less than one or greater than THREADLIMIT.
+
+#ifdef WIN32
+ if(nThrd<1 || nThrd>THREADLIMIT) {
+ BOOL fVal;
+
+ dwer=GetLastError();
+
+ if(IsWindow(hwndMain)) fVal=TRUE;
+ else fVal=FALSE;
+
+ TStrCpy(lpsz,"GetWindowLong failed querying thread count!. Test aborting... INFO:hwnd=%u, LastEr=%u, Is hwnd valid=%u, nThrd=%u");
+
+ wsprintf(lpszOut,lpsz,hwndMain,dwer,fVal,nThrd);
+ MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK);
+
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+#endif
+
+ if(!CreateThreadExtraMem( EXTRA_THREAD_MEM,nThrd)) {
+ MessageBox(NULL,"Could Not Alocate Get/SetThreadLong(). Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+
+ // We always need the thread id for the main thread. (for use
+ // in Get/SetThreadLong(). Other thread id's are initialized in
+ // ThreadInit().
+
+ SetWindowLong(hwndMain,OFFSET_THRDMID,GETCURRENTTHREADID());
+
+ if(!InitThreadInfo(GETCURRENTTHREADID())) {
+ MessageBox(NULL,"Could Not Alocate Thread Local Storage. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+
+ hdc = GetDC(hwndMain);
+ GetTextMetrics(hdc, &tm);
+
+ cyText = tm.tmHeight;
+ cxText = tm.tmAveCharWidth;
+
+ // We need to add in extra area for each additional DisplayWindow
+ // used for each addtional thread.
+
+ nThrd=(INT)GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+ cy = tm.tmHeight*NUM_ROWS+((nThrd-1)*(3*cyText));
+ cx = tm.tmAveCharWidth*NUM_COLUMNS;
+
+ ReleaseDC(hwndMain,hdc);
+
+ // Old ways of positioning.
+
+ // y=DIV((GetSystemMetrics(SM_CYSCREEN)-cy),3)*2;
+ // y=(DIV(GetSystemMetrics(SM_CYSCREEN),10)*3);
+
+ // Position as if 5 threads with bottom of window at bottom of
+ // screen.
+
+ y=GetSystemMetrics(SM_CYSCREEN)-(tm.tmHeight*NUM_ROWS+(12*cyText));
+
+ x=GetSystemMetrics(SM_CXSCREEN);
+
+ if(fServer && fClient) {
+ x=x-(cx*3); // Init for standard values.
+ }
+ else {
+ if(fServer)
+ {
+ x=x-cx;
+ }
+ else {
+ x=x-(cx*2);
+ }
+ }
+
+ SetWindowPos( hwndMain,
+ NULL,
+ x,
+ y,
+ cx,
+ cy,
+ SWP_NOZORDER|SWP_NOACTIVATE );
+
+ ShowWindow (hwndMain, cmdShow);
+
+ CreateButton(hwndMain);
+
+ UpdateWindow (hwndMain);
+
+#ifdef WIN32
+ SetFlag(hwndMain,FLAG_SYNCPAINT,ON);
+
+ lflags=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(lflags&FLAG_MULTTHREAD) { // CreateThreads
+ if(!ThreadInit(hwndMain)) {
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+ }
+#endif
+
+ hwndDisplay=CreateDisplayWindow(hwndMain,1);
+
+ if(!hwndDisplay) {
+ MessageBox(NULL,"Could Not Create Test Display Window. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK);
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return FALSE;
+ }
+ else {
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY,(LONG)hwndDisplay);
+ }
+
+ if (!InitializeDDE((PFNCALLBACK)CustomCallback,
+ &idI,
+ ServiceInfoTable,
+ fServer ?
+ APPCLASS_STANDARD
+ :
+ APPCLASS_STANDARD | APPCMD_CLIENTONLY,
+ hInst)) {
+ DDEMLERROR("DdeStrs.Exe -- Error Dde inititialization failed\r\n");
+ DestroyWindow(hwndMain);
+ UnregisterClass(szClass,hInst);
+ return(FALSE);
+ }
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+
+ if (fClient)
+ {
+ InitClient();
+ }
+ else {
+
+ // Only needed if we are not a client. In case of
+ // client/server only call InitClient() which start
+ // a timer which can be used for time checks.
+
+ SetTimer( hwndMain,
+ (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER),
+ PNT_INTERVAL,
+ TimerFunc);
+ }
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+
+ if(IsTimeExpired(hwndMain)) {
+
+ // We only want to send a single WM_CLOSE
+
+ if(fnoClose) {
+ fnoClose=FALSE;
+ PostMessage(hwndMain,WM_CLOSE,0,0L);
+ }
+ }
+
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+ FreeThreadExtraMem();
+
+ return(TRUE);
+}
+
+#ifdef WIN32
+/************************** Private Function ****************************\
+*
+* ThreadInit
+*
+* Create secondary test threads
+*
+\**************************************************************************/
+
+BOOL ThreadInit( HWND hwnd ) {
+LONG l,ll;
+PLONG lpIDThread=&ll;
+HANDLE hthrd;
+INT nOffset,nCount,i,n;
+HANDLE hmem;
+HANDLE *lph;
+char sz[20];
+LPSTR lpsz=&sz[0];
+
+ nCount=GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+ nOffset=OFFSET_THRD2;
+
+ for(i=1;i<nCount;i++) {
+
+ hmem=GetMemHandle(((sizeof(HANDLE)*2)+sizeof(INT)));
+ lph=(HANDLE *)GlobalLock(hmem);
+
+ *lph=hwnd;
+ *(lph+1)=hmem;
+ *(lph+2)=(HANDLE)(i+1);
+
+ hthrd=CreateThread(NULL,0,SecondaryThreadMain,(LPVOID)lph,0,lpIDThread);
+
+ if (!hthrd) {
+
+ DOut(hwnd,"DdeStrs.Exe -- ERR:Could not Create Thread #%u\r\n",0,i+1);
+
+ GlobalUnlock(hmem);
+ FreeMemHandle(hmem);
+
+ // it's important we turn this flag off since no threads
+ // where successfully created (cleanup code)
+
+ SetFlag(hwnd,FLAG_MULTTHREAD,OFF);
+
+ if (i==1) return FALSE;
+ else {
+
+ // Cleanup threads before we abort.
+
+ for(n=1;n<i;n++) {
+ nOffset=OFFSET_THRD2;
+ TerminateThread((HANDLE)GetWindowLong(hwnd,nOffset),0);
+ SetWindowLong(hwnd,nOffset,0L);
+ nOffset=nOffset+4;
+ } // for
+
+ return FALSE;
+
+ } // else
+
+ } // if
+
+ SetWindowLong(hwnd,nOffset+ID_OFFSET,(LONG)(*lpIDThread));
+ SetWindowLong(hwnd,nOffset,(LONG)hthrd);
+
+ nOffset=nOffset+4;
+
+ } // for
+
+
+ return TRUE;
+
+} // ThreadInit
+
+/*************************** Private Function ******************************\
+SecondaryThreadMain
+
+Effects: Start of execution for second thread. First order of buisness is
+ create the test window and start queue processing.
+
+Return value:
+
+\***************************************************************************/
+
+DWORD SecondaryThreadMain( DWORD dw )
+{
+HWND hwndMain;
+MSG msg;
+HANDLE * lph;
+HANDLE hmem;
+INT nThrd;
+DWORD idI;
+HWND hwndDisplay;
+LONG nTc;
+
+ lph=(HANDLE *)dw;
+
+ hwndMain=(HWND)*lph;
+ hmem =(HANDLE)*(lph+1);
+ nThrd =(INT)*(lph+2);
+
+ GlobalUnlock(hmem);
+ FreeMemHandle(hmem);
+
+ if(!InitThreadInfo(GETCURRENTTHREADID())) {
+ DDEMLERROR("DdeStrs.Exe -- Error InitThreadInfo failed, Aborting thread\r\n");
+ nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+ SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1));
+ ExitThread(1L);
+ }
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+
+ hwndDisplay=CreateDisplayWindow( hwndMain,
+ IDtoTHREADNUM(GETCURRENTTHREADID()));
+
+ if(!IsWindow(hwndDisplay)) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Could not create Display Window, Thread aborting\r\n");
+ nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+ SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1));
+ ExitThread(1L);
+ return FALSE;
+ }
+ else {
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY,hwndDisplay);
+ }
+
+ if (!InitializeDDE((PFNCALLBACK)CustomCallback,
+ &idI,
+ ServiceInfoTable,
+ fServer ?
+ APPCLASS_STANDARD
+ :
+ APPCLASS_STANDARD | APPCMD_CLIENTONLY,
+ hInst)) {
+ DDEMLERROR("DdeStrs.Exe -- Error Dde inititialization failed for secondary thread!\r\n");
+ FreeThreadInfo(GETCURRENTTHREADID());
+ nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+ SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1));
+ ExitThread(1L);
+ }
+
+ if (fClient)
+ {
+ InitClient();
+ }
+ else {
+
+ // Only needed if we are not a client. In case of
+ // client/server only call InitClient() which start
+ // a timer which can be used for time checks.
+
+ SetTimer( hwndMain,
+ (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER),
+ PNT_INTERVAL,
+ TimerFunc);
+ }
+
+ while (GetMessage(&msg,NULL,0,0)) {
+
+ if(msg.message==START_DISCONNECT)
+ {
+ if (fClient)
+ {
+ CloseClient();
+ }
+ }
+ else {
+ if(msg.message==EXIT_THREAD)
+ {
+ PostQuitMessage(1);
+ }
+ else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ } // EXIT_THREAD
+
+ } // START_DISCONNECT
+
+ } // while
+
+ SetFlag(hwndMain,FLAG_STOP,ON);
+
+ // Shutdown timers
+
+ if (!fClient)
+ {
+ KillTimer(hwndMain,GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER));
+ }
+
+ UninitializeDDE();
+
+ FreeThreadInfo(GETCURRENTTHREADID());
+
+
+ // This is to release the semaphore set before completing
+ // exit on main thread.
+
+
+ switch (nThrd) {
+
+ case 2: SetFlag(hwndMain,FLAG_THRD2,ON);
+ break;
+ case 3: SetFlag(hwndMain,FLAG_THRD3,ON);
+ break;
+ case 4: SetFlag(hwndMain,FLAG_THRD4,ON);
+ break;
+ case 5: SetFlag(hwndMain,FLAG_THRD5,ON);
+ break;
+ default:
+ DOut(hwndMain,"DdeStrs.Exe -- ERR: Unexpected switch value in SecondaryThreadMain, value=%u\r\n",0,nThrd);
+ break;
+
+ } // switch
+
+ ExitThread(1L);
+
+ return 1;
+
+}
+
+#endif
+
+/************************** Public Function *****************************\
+*
+* InitThrdInfo - This routine allocates memory needed for storage for
+* thread local variables. This routine needs to be called
+* for each thread.
+*
+* Note: I am relying on the fact that the call GetMemHandle() calls
+* GlobalAlloc() specifying the GMEM_ZEROINIT flag. These value need
+* to be zero starting off.
+\**************************************************************************/
+
+BOOL InitThreadInfo( DWORD dwid ) {
+HANDLE hmem;
+INT nThrd;
+
+ hmem = GetMemHandle(sizeof(HCONV)*MAX_SERVER_HCONVS);
+ SetThreadLong(dwid,OFFSET_HSERVERCONVS,(LONG)hmem);
+
+ if( hmem==NULL ) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR: Could not allocate thread local storage(Server Conversation List)\r\n",0,0);
+ return FALSE;
+ }
+
+ hmem = GetMemHandle(sizeof(HANDLE)*NUM_FORMATS);
+ SetThreadLong(dwid,OFFSET_HAPPOWNED,(LONG)hmem);
+
+ if( hmem==NULL ) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR: Could not allocate thread local storage(AppOwned Flag List)\r\n",0,0);
+ FreeMemHandle((HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS));
+ return FALSE;
+ }
+
+ nThrd=IDtoTHREADNUM(dwid);
+
+ SetThreadLong(dwid,OFFSET_SERVERTIMER,nThrd*2);
+ SetThreadLong(dwid,OFFSET_CLIENTTIMER,(nThrd*2)+1);
+
+ return TRUE;
+
+}
+
+#ifdef WIN32
+
+/************************** Private Function ****************************\
+*
+* IDtoTHREADNUM - Find out current thread.
+*
+\**************************************************************************/
+
+INT IDtoTHREADNUM( DWORD dwid ) {
+INT nWndOff,nThrd,nThrdCount,n;
+
+ nWndOff=OFFSET_THRDMID;
+ nThrdCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
+ n=nThrdCount;
+ nThrd=1;
+
+ while( n>0 ) {
+
+ if(dwid==(DWORD)GetWindowLong(hwndMain,nWndOff))
+ {
+ n=-1; // Exit loop
+ } // if
+ else {
+ nWndOff=nWndOff+4;
+ nThrd++;
+ n--;
+ }
+ } // while
+
+ if(nThrd>nThrdCount) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Thread Count exceeded!!! in IDtoTHREADNUM()\r\n");
+ nThrd=nThrdCount;
+ }
+
+ return nThrd;
+
+}
+
+#else
+
+/************************** Private Function ****************************\
+*
+* IDtoTHREADNUM - Find out current thread.
+*
+\**************************************************************************/
+
+INT IDtoTHREADNUM( DWORD dwid ) {
+
+ return 1;
+
+}
+
+#endif
+
+/************************** Public Function *****************************\
+*
+* FreeThreadInfo - Free thread information memory.
+*
+\**************************************************************************/
+
+BOOL FreeThreadInfo( DWORD dwid ) {
+HANDLE hmem;
+
+ hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS);
+ FreeMemHandle(hmem);
+ return TRUE;
+
+}
+
+#ifdef WIN32
+
+/************************** Public Function *****************************\
+*
+* ThreadWait - This routine waits while processing messages until the
+* other threads signal they've completed work that must
+* be finished before preceeding.
+*
+\**************************************************************************/
+
+VOID ThreadWait( HWND hwnd ) {
+LONG lflags;
+INT nCount,nWait;
+MSG msg;
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ nCount=GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+
+ nWait=nCount-1;
+
+ if(lflags&FLAG_THRD2) nWait-=1;
+ if(lflags&FLAG_THRD3) nWait-=1;
+ if(lflags&FLAG_THRD4) nWait-=1;
+ if(lflags&FLAG_THRD5) nWait-=1;
+
+ while (nWait>0) {
+
+ while(PeekMessage(&msg,NULL,0,WM_USER-1,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ } // while peekmessage
+
+ nWait=nCount-1;
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(lflags&FLAG_THRD2) nWait-=1;
+ if(lflags&FLAG_THRD3) nWait-=1;
+ if(lflags&FLAG_THRD4) nWait-=1;
+ if(lflags&FLAG_THRD5) nWait-=1;
+
+ } // while nWait
+
+ // Reset for next wait
+
+ SetFlag(hwnd,(FLAG_THRD5|FLAG_THRD4|FLAG_THRD3|FLAG_THRD2),OFF);
+
+}
+
+#endif // WIN32
+
+/************************** Private Function ****************************\
+*
+* SetCount
+*
+* This routine updates the count under semaphore protection. Not needed for
+* one thread, but a must for multithread execution.
+*
+\**************************************************************************/
+
+LONG SetCount( HWND hwnd, INT nOffset, LONG l, INT ntype ) {
+LONG ll;
+
+#if 0
+LONG lflags;
+#endif
+
+#ifdef WIN32
+LPCRITICAL_SECTION lpcs;
+HANDLE hmem;
+BOOL f=FALSE;
+#endif
+
+#if 0
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(ll&FLAG_MULTTHREAD) {
+ f=TRUE;
+ hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT);
+
+ // If we have a valid handle then enter critical section. If
+ // the handle is still null proceed without a critical section.
+ // The first calls to this routine are used to setup the
+ // critical section so we do expect those first calls (while
+ // we are still sencronized ) for the hmem to be null.
+
+ if(hmem) {
+ lpcs=GlobalLock(hmem);
+ EnterCriticalSection(lpcs);
+ }
+ }
+
+#endif
+
+ // This second GetWindowLong call is needed in the critical
+ // section. The test relies very hevily on the flags and
+ // it's important to be accurate.
+
+ ll=GetWindowLong(hwnd,nOffset);
+
+ if(ntype==INC) l=SetWindowLong(hwnd,nOffset,ll+l);
+ else l=SetWindowLong(hwnd,nOffset,ll-l);
+
+#if 0
+
+ if(f) {
+ if(hmem) {
+ LeaveCriticalSection(lpcs);
+ GlobalUnlock(hmem);
+ }
+ }
+
+#endif
+
+ return l;
+}
+
+/************************** Private Function ****************************\
+*
+* SetFlag
+*
+* This routine sets a flag under semaphore protection. Not needed for
+* one thread, but a must for multithread execution.
+*
+\**************************************************************************/
+
+LONG SetFlag( HWND hwnd, LONG l, INT ntype ) {
+LONG lflags;
+
+#ifdef WIN32
+BOOL fCriticalSect=TRUE;
+LPCRITICAL_SECTION lpcs;
+HANDLE hmem;
+BOOL f=FALSE;
+#endif
+
+#ifdef WIN32
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(lflags&FLAG_MULTTHREAD &&
+ lflags&FLAG_SYNCPAINT) {
+ f=TRUE;
+ hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT);
+ if(hmem) {
+ lpcs=GlobalLock(hmem);
+ EnterCriticalSection(lpcs);
+ }
+ else {
+ fCriticalSect=FALSE;
+ }
+ }
+
+#endif
+
+ // This second GetWindowLong call is needed in the critical
+ // section. The test relies very hevily on the flags and
+ // it's important to be accurate.
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(ntype==ON) l=SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,l));
+ else l=SetWindowLong(hwnd,OFFSET_FLAGS,FLAGOFF(lflags,l));
+
+#ifdef WIN32
+
+ if(f) {
+ if(fCriticalSect) {
+ LeaveCriticalSection(lpcs);
+ GlobalUnlock(hmem);
+ }
+ }
+
+#endif
+
+ return l;
+}
+
+/******************************************************************\
+* DIV
+* 05/06/91
+*
+* Performs integer division (format x/y) where DIV(x,y)
+* Works for negative numbers and y==0;
+*
+\******************************************************************/
+
+INT DIV( INT x, INT y)
+{
+INT i=0;
+BOOL fNgOn=FALSE;
+
+ if (!y) return 0; // if div by 0 retrun error.
+
+ if (x<0 && y>0) fNgOn=TRUE; // keep tabs for negitive numbers
+ if (x>0 && y<0) fNgOn=TRUE;
+
+ if (x<0) x=x*-1;
+ if (y<0) y=y*-1;
+
+ x=x-y;
+
+ while (x>=0) { // count
+ x=x-y;
+ i++;
+ }
+
+ if (fNgOn) i=i*(-1); // should result be negative
+
+ return( i );
+}
+
+/*************************** Private Function ******************************\
+*
+* CreateButton
+*
+\***************************************************************************/
+
+HWND CreateButton( HWND hwnd ) {
+RECT r;
+HWND hwndB;
+HWND hwndP;
+INT iButWidth;
+LONG lflags;
+
+ GetClientRect(hwnd,&r);
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(lflags&FLAG_PAUSE_BUTTON) {
+
+ iButWidth=DIV(r.right-r.left,2);
+
+ hwndP=CreateWindow("button",
+ "Start",
+ BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS,
+ iButWidth,
+ 0,
+ r.right-iButWidth,
+ cyText,
+ hwnd,
+ 1,
+ GetHINSTANCE(hwnd),
+ 0L);
+
+ if (!hwndP) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Failed to create exit button: Continuing...\r\n");
+ SetFlag(hwnd,FLAG_PAUSE_BUTTON,OFF);
+ iButWidth=r.right-r.left;
+ }
+
+
+ hwndB=CreateWindow("button",
+ "Exit",
+ BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS,
+ 0,
+ 0,
+ iButWidth,
+ cyText,
+ hwnd,
+ 0,
+ GetHINSTANCE(hwnd),
+ 0L);
+
+ }
+ else {
+
+ hwndB=CreateWindow("button",
+ "Exit",
+ BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS,
+ 0,
+ 0,
+ r.right-r.left,
+ cyText,
+ hwnd,
+ 0,
+ GetHINSTANCE(hwnd),
+ 0L);
+ }
+
+ if (!hwndB) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Failed to create exit button: Continuing...\r\n");
+ }
+
+ return hwndB;
+}
+
+/***************************************************************************\
+*
+* UpdClient
+*
+* The purpose of this routine update only the area invalidated
+* by the test statistics update. If an error occurs in the area
+* calcualation then update the whole client areaa.
+*
+\***************************************************************************/
+
+BOOL UpdClient( HWND hwnd, INT iOffset ) {
+RECT r;
+INT iCH,iCW,nThrd;
+
+#ifdef WIN32
+DWORD dw;
+#endif
+
+ // This call aquires the r.right value.
+
+ GetClientRect(hwnd,&r);
+
+ // We need text information for the monitor being used. This
+ // was initialized in CreateFrame.
+ iCH=cyText;
+ iCW=cxText;
+
+ // Do a quick check, if either of these values are NULL then
+ // update the whole client area. This is slower and less
+ // elegant but will work in the case of an error.
+
+ if((!iCH) || (!iCW))
+ InvalidateRect(hwnd,NULL,TRUE);
+ else {
+
+ // Next Calculate r.top and r.bottom
+
+ switch(iOffset) {
+
+ case ALL: // Update all values.
+ break;
+
+ case OFFSET_STRESS:
+ r.bottom =iCH*4;
+ r.top =iCH*3;
+ break;
+
+ case OFFSET_RUNTIME:
+ r.bottom =iCH*5;
+ r.top =iCH*4;
+ break;
+
+ case OFFSET_TIME_ELAPSED:
+ r.bottom =iCH*6;
+ r.top =iCH*5;
+ break;
+
+ case OFFSET_CLIENT_CONNECT:
+ r.bottom =iCH*7;
+ r.top =iCH*6;
+ break;
+
+ case OFFSET_SERVER_CONNECT:
+ r.bottom =iCH*8;
+ r.top =iCH*7;
+ break;
+
+ case OFFSET_CLIENT:
+ nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+ if((GetWindowLong(hwnd,OFFSET_CLIENT)%(NUM_FORMATS*nThrd))==0)
+ {
+ r.bottom =iCH*9;
+ r.top =iCH*8;
+ }
+ else return TRUE;
+ break;
+
+ case OFFSET_SERVER:
+ nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+ if((GetWindowLong(hwnd,OFFSET_SERVER)%(NUM_FORMATS*nThrd))==0)
+ {
+ r.bottom =iCH*10;
+ r.top =iCH*9;
+ }
+ else return TRUE;
+ break;
+
+ case OFFSET_DELAY:
+ r.bottom =iCH*11;
+ r.top =iCH*10;
+ break;
+ default:
+ break;
+
+ } // switch
+
+ // Last we set the r.left and the update rect is complete
+
+ if(iOffset!=OFFSET_FLAGS)
+ r.left = iCW*LONGEST_LINE;
+
+ InvalidateRect(hwnd,&r,TRUE);
+
+ } // else
+
+#ifdef WIN16
+ UpdateWindow(hwnd);
+#else
+ SendMessageTimeout(hwnd,WM_PAINT,0,0L,SMTO_NORMAL,500,&dw);
+#endif
+
+ return TRUE;
+
+} // UpdClient
+
+/***************************************************************************\
+*
+* GetCurrentCount
+*
+\***************************************************************************/
+
+LONG GetCurrentCount( HWND hwnd, INT nOffset ) {
+LONG cClienthConvs =0L;
+INT nThrd,i;
+DWORD dwid;
+
+ nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+ for(i=0;i<nThrd;i++) {
+ dwid=(DWORD)GetWindowLong(hwnd,OFFSET_THRDMID+(i*4));
+ if(nOffset==OFFSET_CCLIENTCONVS)
+ cClienthConvs=cClienthConvs+(INT)GetThreadLong(dwid,OFFSET_CCLIENTCONVS);
+ else cClienthConvs=cClienthConvs+(INT)GetThreadLong(dwid,OFFSET_CSERVERCONVS);
+ } // for i
+
+ return cClienthConvs;
+
+}
+
+/***************************************************************************\
+*
+* UpdateCount
+*
+\***************************************************************************/
+
+BOOL UpdateCount( HWND hwnd, INT iOffset, INT i) {
+LONG ll;
+
+ if(iOffset!=ALL) {
+ ll=GetWindowLong(hwnd,iOffset);
+
+ switch(i) {
+
+ case INC: SetCount(hwnd,iOffset,1,INC);
+ break;
+
+ case DEC: SetCount(hwnd,iOffset,1,DEC);
+ break;
+
+ case STP: SetFlag(hwnd,FLAG_STOP,ON);
+ break;
+
+ case PNT: // Paint only!
+ break;
+
+ default:
+ DDEMLERROR("DdeStrs.Exe - UpdateCount - Unexpected value");
+ break;
+
+ } // switch
+
+ } // if
+
+ UpdClient(hwnd,iOffset);
+
+ return TRUE;
+
+}
+
+/*****************************************************************************\
+| DOUT
+|
+| created: 29-Jul-91
+| history: 03-Aug-91 <johnsp> created.
+|
+\*****************************************************************************/
+
+BOOL DOut( HWND hwnd, LPSTR lpsz, LPSTR lpszi, INT i ) {
+char sz[MAX_TITLE_LENGTH];
+LPSTR lpszOut=&sz[0];
+LONG lflags;
+
+#ifdef WIN32
+LPCRITICAL_SECTION lpcs;
+HANDLE hmem;
+DWORD dwer=0L;
+BOOL fCriticalSect=TRUE;
+BOOL f=FALSE;
+
+ if(!hwnd) hwnd=hwndMain;
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ // FLAG_SYNCPAINT implies FLAG_MULTTHREAD with the addition that
+ // we have allocated needed resources to start using the
+ // critical section code.
+
+ if(lflags&FLAG_SYNCPAINT) {
+ f=TRUE;
+ hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT);
+ if(hmem) {
+ lpcs=GlobalLock(hmem);
+ EnterCriticalSection(lpcs);
+ }
+ else {
+ fCriticalSect=FALSE;
+ }
+ }
+
+#endif
+
+ if (lflags&FLAG_DEBUG) {
+
+ if (lpszi) wsprintf(lpszOut,lpsz,lpszi);
+ else wsprintf(lpszOut,lpsz,i);
+
+ OutputDebugString(lpszOut);
+
+#ifdef WIN32
+
+ dwer=GetLastError();
+ wsprintf(lpszOut,"DdeStrs.Exe -- ERR:Val from GetLastError()=%u\n\r",dwer);
+ OutputDebugString(lpszOut);
+
+#endif
+ } // if FLAG_DEBUG
+
+#ifdef WIN32
+
+ // FLAG_SYNCPAINT implies FLAG_MULTTHREAD with the addition that
+ // we have allocated needed resources to start using the
+ // critical section code.
+
+ if(f) {
+ if(fCriticalSect) {
+ LeaveCriticalSection(lpcs);
+ GlobalUnlock(hmem);
+ }
+ }
+
+#endif
+
+ return TRUE;
+
+}
+
+/*****************************************************************************\
+| EOUT
+|
+| created: 19-Aug-92
+| history: 19-Aug-92 <johnsp> created.
+|
+\*****************************************************************************/
+
+BOOL EOut( LPSTR lpsz ) {
+
+ DOut((HWND)NULL,lpsz,(LPSTR)NULL,0);
+
+ return TRUE;
+}
+
+/*************************** Private Function ******************************\
+
+GetMemHandle
+
+\***************************************************************************/
+
+HANDLE GetMemHandle( INT ic ) {
+HANDLE hmem;
+
+ hmem=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,ic);
+
+ if(hmem) {
+ SetCount(hwndMain,OFFSET_MEM_ALLOCATED,GlobalSize(hmem),INC);
+ }
+ else {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalAlloc ret=%u\n\r",0,0);
+ }
+
+ return hmem;
+
+}
+
+/*************************** Private Function ******************************\
+
+GetMem
+
+\***************************************************************************/
+
+LPSTR GetMem( INT ic, LPHANDLE lphmem) {
+LPSTR lpsz;
+
+ *lphmem=GetMemHandle(ic);
+ lpsz=GlobalLock(*lphmem);
+
+ if(!lpsz) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalLock ret=%u (not locked)\n\r",0,0);
+ FreeMemHandle(*lphmem);
+ return NULL;
+ }
+
+ return lpsz;
+
+}
+
+/*************************** Private Function ******************************\
+
+FreeMem
+
+\***************************************************************************/
+
+BOOL FreeMem( HANDLE hmem ) {
+
+ if(GlobalUnlock(hmem)) {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalUnlock ret=%u (still locked)\n\r",0,(INT)TRUE);
+ }
+
+ FreeMemHandle(hmem);
+
+ return TRUE;
+
+}
+
+/*************************** Private Function ******************************\
+
+FreeMemHandle
+
+\***************************************************************************/
+
+BOOL FreeMemHandle( HANDLE hmem ) {
+LONG ll;
+
+ ll=GlobalSize(hmem);
+
+ if(!GlobalFree(hmem)) {
+ SetCount(hwndMain,OFFSET_MEM_ALLOCATED,ll,DEC);
+ }
+ else {
+ DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalFree returned %u (not free'd)\n\r",0,(INT)hmem);
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/**************************** Private *******************************\
+* CreateThreadExtraMem - This routine creates extra thread memory
+* to be used in conjuction with the functions
+* Get/SetThreadLong.
+*
+\********************************************************************/
+
+BOOL CreateThreadExtraMem( INT nExtra, INT nThrds ) {
+
+ hExtraMem=GetMemHandle(nExtra*nThrds);
+ SetWindowLong(hwndMain,OFFSET_EXTRAMEM,nExtra);
+
+ if(hExtraMem==NULL) return FALSE;
+ else return TRUE;
+
+}
+
+/**************************** Private *******************************\
+* FreeThreadExtraMem - This routine frees extra thread memory
+* to be used in conjuction with the functions
+* Get/SetThreadLong.
+*
+* Note: FreeMemHandle can not be used here because it relies on
+* the main window still being around. At this point our
+* main window has already been destroied.
+*
+\********************************************************************/
+
+BOOL FreeThreadExtraMem( void ) {
+
+ GlobalFree(hExtraMem);
+
+ return TRUE;
+
+}
+
+/**************************** Private *******************************\
+* GetThreadLong - This routine queries the value specified by the
+* nOffset parameter from the threads memory areas
+* specified by the dwid value.
+*
+* Memory layout - thread 1: OFFSET1, OFFSET2, ..., OFFSETN
+* thread 2: OFFSET1, OFFSET2, ..., OFFSETN
+* .
+* .
+* thread n: OFFSET1, OFFSET2, ..., OFFSETN
+*
+\********************************************************************/
+
+LONG GetThreadLong( DWORD dwid, INT nOffset ) {
+INT nThrd;
+LONG l,lExMem;
+LPBYTE lp;
+LONG FAR *lpl;
+
+ lp=GlobalLock(hExtraMem);
+
+ // Find out which thread is making the call.
+
+ nThrd=IDtoTHREADNUM(dwid);
+
+ // This is the amount of extra memory for one thread.
+
+ lExMem=GetWindowLong(hwndMain,OFFSET_EXTRAMEM);
+
+ // Value at thread and offset. See above for storage layout.
+
+ lpl=(LONG FAR *)(lp+((nThrd-1)*lExMem)+nOffset);
+
+ l=*lpl;
+
+ GlobalUnlock(hExtraMem);
+
+ return l;
+
+}
+
+/**************************** Private *******************************\
+* SetThreadLong - This routine sets the value specified by the
+* nOffset parameter from the threads memory areas
+* specified by the dwid value.
+*
+* Memory layout - thread 1: OFFSET1, OFFSET2, ..., OFFSETN
+* thread 2: OFFSET1, OFFSET2, ..., OFFSETN
+* .
+* .
+* thread n: OFFSET1, OFFSET2, ..., OFFSETN
+*
+\********************************************************************/
+
+LONG SetThreadLong( DWORD dwid, INT nOffset, LONG l ) {
+INT nThrd;
+LONG lPrevValue,lExMem;
+LPBYTE lp;
+LPLONG lpl;
+
+ lp=GlobalLock(hExtraMem);
+
+ // Find out which thread is making the call.
+
+ nThrd=IDtoTHREADNUM(dwid);
+
+ // This is the amount of extra memory for one thread.
+
+ lExMem=GetWindowLong(hwndMain,OFFSET_EXTRAMEM);
+
+ // Value at thread and offset. See above for storage layout.
+
+ lPrevValue=(LONG)(*(lp+((nThrd-1)*lExMem)+nOffset));
+ lpl=(LPLONG)(lp+((nThrd-1)*lExMem)+nOffset);
+
+ *lpl=l;
+
+ GlobalUnlock(hExtraMem);
+
+ return lPrevValue;
+
+}
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def
new file mode 100644
index 000000000..775c1543d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def
@@ -0,0 +1,17 @@
+NAME DDESTRS
+
+DESCRIPTION 'Microsoft Windows DDE stress'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD FIXED
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 4096
+STACKSIZE 4096
+
+EXPORTS
+ MAINWNDPROC @1
+ DISPWNDPROC @2
+ WRAPPERCALLBACK @3
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h
new file mode 100644
index 000000000..192a2c3a9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h
@@ -0,0 +1,287 @@
+#ifdef WIN16
+
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
+
+#define GETCURRENTTHREADID() 1
+
+#else
+
+#define GETCURRENTTHREADID() GetCurrentThreadId()
+
+#endif
+
+#define WHITE RGB(255,255,255)
+#define GREEN RGB(0,128,128)
+#define GREY RGB(192,192,192)
+#define TOPIC "Test"
+
+extern HANDLE hExtraMem;
+
+#ifdef WIN32
+#define PNT_INTERVAL 60000
+#else
+#define PNT_INTERVAL 30000
+#endif
+
+#define _5SEC 5000 // milliseconds
+#define _1MIN 1
+#define _1HOUR 60
+#define _1DAY 1440
+#define _1WEEKEND 4320
+#define _1WEEK 10080
+#define SERVER 0
+#define CLIENT 1
+
+#ifdef WIN16
+#define NUM_FORMATS 5
+#else
+#define NUM_FORMATS 6
+#endif
+
+// The below offsets are used with Set/GetThreadLong() "THREAD"
+// Offset defines cannot be interchanged between window
+// and thread use because of collisions.
+
+#define OFFSET_IDINST 0
+#define OFFSET_HCONVLIST 4
+#define OFFSET_CSERVERCONVS 8
+#define OFFSET_HSERVERCONVS 12
+#define OFFSET_HAPPOWNED 16
+#define OFFSET_CCLIENTCONVS 20
+#define OFFSET_HWNDDISPLAY 24
+#define OFFSET_CLIENTTIMER 28
+#define OFFSET_SERVERTIMER 32
+#define DELAY_METRIC 2
+
+#define EXTRA_THREAD_MEM OFFSET_SERVERTIMER+4
+#define S2L(s) (LONG)(MAKELONG((WORD)(s),0))
+
+// The below offsets are used with Set/GetWindowLong() "WINDOW"
+
+#define OFFSET_FLAGS 0
+#define OFFSET_RUNTIME 4
+#define OFFSET_STARTTIME_SEC 8
+#define OFFSET_STARTTIME_MIN 12
+#define OFFSET_STARTTIME_HOUR 16
+#define OFFSET_STARTTIME_DAY 20
+#define OFFSET_LAST_MIN 24
+#define OFFSET_LAST_HOUR 28
+#define OFFSET_TIME_ELAPSED 32
+#define OFFSET_DELAY 36
+#define OFFSET_STRESS 40
+#define OFFSET_SERVER_CONNECT 44
+#define OFFSET_CLIENT_CONNECT 48
+#define OFFSET_CLIENT 52
+#define OFFSET_SERVER 56
+
+#define OFFSET_THRDMAIN 60 // <== ***
+#define OFFSET_THRD2 64 // <== *** Ordering here is relied
+#define OFFSET_THRD3 68 // <== *** upon in the test. Keep
+#define OFFSET_THRD4 72 // <== *** This group of values
+#define OFFSET_THRD5 76 // <== *** in sequential order.
+#define OFFSET_THRDMID 80 // <== ***
+#define OFFSET_THRD2ID 84 // <== ***
+#define OFFSET_THRD3ID 88 // <== ***
+#define OFFSET_THRD4ID 92 // <== ***
+#define OFFSET_THRD5ID 96 // <== ***
+#define OFFSET_THRD2EVENT 100 // <== ***
+#define OFFSET_THRD3EVENT 104 // <== ***
+#define OFFSET_THRD4EVENT 108 // <== ***
+#define OFFSET_THRD5EVENT 112 // <== ***
+
+#define OFFSET_CRITICALSECT 116
+#define OFFSET_THRDCOUNT 120
+#define OFFSET_EXTRAMEM 124
+#define OFFSET_DISPWNDHEIGHT 128
+#define OFFSET_BASE_DELAY 132
+#define OFFSET_MEM_ALLOCATED 136
+
+#define WND OFFSET_MEM_ALLOCATED+4
+
+#define ID_OFFSET 20
+#define INC 1
+#define DEC 0
+#define STP 2
+#define PNT 3
+#define ALL -1
+
+#define ON 1
+#define OFF 0
+
+#define AT_SWITCH 1
+#define AT_FILE 2
+#define AT_STRESS 3
+#define AT_DELAY 4
+#define AT_TIME 5
+#define AT_WND 6
+#define AT_MSG 7
+#define AT_FORMAT 8
+#define AT_THRD 9
+
+#define FLAG_BACKGROUND 0x00000001
+#define FLAG_AUTO 0x00000002
+#define FLAG_TIME 0x00000004
+#define FLAG_STOP 0x00000008
+#define FLAG_LOG 0x00000010
+#define FLAG_USRWNDCOUNT 0x00000020
+#define FLAG_USRMSGCOUNT 0x00000040
+#define FLAG_USRDELAY 0x00000080
+#define FLAG_DEBUG 0x00000100
+#define FLAG_CHARINFO 0x00000200
+#define FLAG_DELAYON 0x00000400
+#define FLAG_TEST_MSG_ON 0x00000800
+#define FLAG_MSGDELAYON 0x00001000
+#define FLAG_APPOWNED 0x00002000
+#define FLAG_MULTTHREAD 0x00004000
+
+#define FLAG_THRD2 0x00008000
+#define FLAG_THRD3 0x00010000
+#define FLAG_THRD4 0x00020000
+#define FLAG_THRD5 0x00040000
+
+#define FLAG_NET 0x00080000
+#define FLAG_SYNCPAINT 0x00100000
+#define FLAG_USRTHRDCOUNT 0x00200000
+#define FLAG_PAUSE_BUTTON 0X00400000
+#define FLAG_PAUSE 0X00800000
+
+#define THREADLIMIT 5
+
+#define STD_EXIT 1
+#define ABNORMAL_EXIT 0
+
+#define FLAGON(a,b) (LONG)(a|b)
+#define FLAGOFF(a,b) (LONG)(a&(~b))
+
+//#define MAX_SERVER_HCONVS 1000
+#define MAX_SERVER_HCONVS 500
+
+#define IDR_ICON 1
+#define IDR_MENU 2
+#define IDM_DIE 100
+
+#define DIGITS_IN_TENMILL 8
+#define BLANK_SPACE 3
+#define LONGEST_LINE 15
+
+#define NUM_COLUMNS (LONGEST_LINE+BLANK_SPACE+DIGITS_IN_TENMILL)
+#define NUM_ROWS 16
+#define MAX_TITLE_LENGTH 100
+
+#define TXT 0
+#define DIB 1
+#define BITMAP 2
+#define ENHMETA 3
+#define METAPICT 4
+#define PALETTE 5
+
+#define EXIT_THREAD WM_USER+6
+#define START_DISCONNECT WM_USER+7
+
+#include "globals.h"
+
+/*
+ * Prototypes
+ */
+
+/*
+ * ddestrs.c
+ */
+
+LONG FAR PASCAL MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LONG lParam);
+
+VOID InitArgsError(HWND,unsigned);
+VOID SysTime(LPSYSTEMTIME);
+BOOL ParseCommandLine(HWND,LPSTR);
+int SetupArgv( char **, char *, LPSTR);
+BOOL PASCAL get_cmd_arg(HWND,LPSTR);
+BOOL IsTimeExpired(HWND);
+
+INT DIV(INT,INT);
+
+BOOL TStrCmp(LPSTR,LPSTR);
+LPSTR TStrCpy(LPSTR,LPSTR);
+LPSTR TStrCat(LPSTR,LPSTR);
+INT TStrLen(LPSTR);
+
+LPSTR FAR PASCAL itola(int,LPSTR);
+int APIENTRY latoi(LPSTR);
+
+BOOL DOut(HWND,LPSTR,LPSTR,INT);
+BOOL EOut(LPSTR);
+
+
+#ifdef WIN32
+BOOL ThreadShutdown(VOID);
+BOOL ThreadDisconnect(VOID);
+#endif
+
+#define DDEMLERROR(a) EOut(a)
+#define LOGDDEMLERROR(a) EOut(a)
+
+
+/*
+ * client.c
+ */
+
+void CALLBACK TimerFunc(HWND,UINT,UINT,DWORD);
+VOID PaintClient(HWND hwnd, PAINTSTRUCT *pps);
+VOID ReconnectList(VOID);
+BOOL InitClient(VOID);
+VOID CloseClient(VOID);
+
+/*
+ * server.c
+ */
+
+HDDEDATA RenderHelp_Text(HDDEDATA hData);
+BOOL PokeTestItem_Text(HDDEDATA hData);
+HDDEDATA RenderTestItem_Text(HDDEDATA hData);
+BOOL PokeTestItem_DIB(HDDEDATA hData);
+HDDEDATA RenderTestItem_DIB(HDDEDATA hData);
+BOOL PokeTestItem_BITMAP(HDDEDATA hData);
+HDDEDATA RenderTestItem_BITMAP(HDDEDATA hData);
+BOOL PokeTestItem_METAPICT(HDDEDATA hData);
+HDDEDATA RenderTestItem_METAPICT(HDDEDATA hData);
+BOOL PokeTestItem_ENHMETA(HDDEDATA hData);
+HDDEDATA RenderTestItem_ENHMETA(HDDEDATA hData);
+BOOL PokeTestItem_PALETTE(HDDEDATA hData);
+HDDEDATA RenderTestItem_PALETTE(HDDEDATA hData);
+HINSTANCE GetHINSTANCE(HWND);
+
+BOOL Execute(HDDEDATA hData);
+VOID PaintServer(HWND hwnd, PAINTSTRUCT *pps);
+HDDEDATA FAR PASCAL CustomCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+
+#ifdef WIN32
+VOID ThreadWait(HWND);
+DWORD SecondaryThreadMain(DWORD);
+BOOL ThreadInit(HWND);
+#endif
+
+LONG SetFlag(HWND,LONG,INT);
+LONG SetCount(HWND,INT,LONG,INT);
+LPSTR GetMem(INT, LPHANDLE);
+BOOL FreeMem(HANDLE);
+BOOL FreeMemHandle(HANDLE);
+HANDLE GetMemHandle(INT);
+LONG SetThreadLong(DWORD,INT,LONG);
+LONG GetThreadLong(DWORD,INT);
+BOOL FreeThreadExtraMem(void);
+BOOL CreateThreadExtraMem(INT,INT);
+BOOL InitThreadInfo(DWORD);
+BOOL FreeThreadInfo(DWORD);
+INT IDtoTHREADNUM(DWORD);
+HWND CreateDisplayWindow(HWND,INT);
+LONG GetCurrentCount(HWND,INT);
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico
new file mode 100644
index 000000000..035bcc11b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc
new file mode 100644
index 000000000..b5090896a
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+#include "ddestrs.h"
+
+IDR_ICON ICON ddestrs.ico
+
+
+IDR_MENU MENU
+BEGIN
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Die!", IDM_DIE
+ END
+END
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt
new file mode 100644
index 000000000..d87d32c93
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt
@@ -0,0 +1,110 @@
+The document breifly describes DdeStrs.exe.
+
+DdeStrs is intended to exercise and stress Dde/Ddeml.
+
+Some areas exercised in the test are ...
+
+ o Async/fAckRequest advise loops
+ o Async executes
+ o CF_TEXT, CF_DIB, CF_BITMAP, CF_METAFILEPICT, CF_PALETTE,
+ and CF_ENHMETAFILE (w32 only) formats.
+ o DdeConnectList/DdeDisconnectList
+ o AppOwned handles [when -a option used]
+ o Variable client/server connects (number of instances running
+ of ddestrs.exe)
+ o Cross process/In process and multithread communication.
+ o System Timers
+
+
+The command line options are ...
+
+DdeStrs [-#%,-e#,-t#,-d,-a,-s,-c,-f#,-nNAME,-i#,-p,-?]
+
+ where -#% allow the user to specify the intensity of
+ the run (# = [1...100]) and can be read as stress
+ percentage. 1 being low stress 100 being high stress.
+
+ where -e# allows override of the delay set by the stress
+ level. -e0 is usefull if the stress test is the only one
+ running and it is desirable for the test to cover ground
+ (number of windows, classes, and messages that are
+ exercised). # is in milliseconds.
+
+ where -t# specifies the number of minutes for the test to run. At
+ the end of # minutes the test will shutdown. Default is 4320 min
+ (About a weekend). Test can also be exited manually at any
+ point.
+
+ where -d selects debug mode. This mode of operation displays
+ additional test information and outputs failures to
+ the debug terminal. This mode is intended for debugging
+ DdeStrs failures and not for use in public stress runs.
+
+ where -a specifies to use AppOwned handle for data communications.
+
+ where -s specifies that this instance is to run as server only
+ [default is -s -c].
+
+ where -c specifies that this instance is to run as client only.
+ [default is -s -c].
+
+ where -f# allow specific formats to be used. Default is all
+ formats. If any specific formats are specified then only
+ to formats will be used in the communication.
+
+ [Ex - ddestrs -f1 -f2] will only use formats 1 and 2.
+
+ Formats 1 CF_TEXT
+ 2 CF_DIB
+ 3 CF_BITMAP
+ 4 CF_ENHMETAFILE (w32 only)
+ 5 CF_METAFILEPICT
+ 6 CF_PALETTE
+
+ where -nNAME specifies the computer name to connect to. This
+ is used for netdde and only needs to be specified on client
+ applications. NAME=servername, Example '-njohnsp1' for
+ computer \\johnsp1. Use Ddeshare.exe (w31 resources kit or
+ Nt sdk) to setup the dde share enabling netdde to work. DdeStrs
+ Service Name=DdeStrs, Topic=Test, and permissions must be
+ change or greater (ddestrs.exe uses executes).
+
+ where -i# specifies the number of threads to execute. # can
+ be in the range [1..5]. This option is only available
+ for Win Nt.
+
+ where -p specifies pause before data update. With this specified the user can
+ manually start executes and advise updates. With this connections are established, but
+ no data is passed until manually started. DdeStrs adds a 'pause' button to allow stress
+ to be started and stopped. Default is NO -p.
+
+ where -? brings up a brief help list of DdeStrs Options.
+
+Test Usage ...
+
+ Ddestrs will communicate with multiple copies of itself. Each
+ new instance of ddestrs started will cause other instances to
+ connect to all running copies available for conversation. This
+ allows the stress level to be tailored both by the -#% and
+ by the number of copies of the test running.
+
+Focus Test Api ...
+
+DdeQueryNextServer
+DdeClientTransaction
+DdeDisconnectList
+DdeConnectList
+DdeAccessData
+DdeAddData
+DdePostAdvise
+DdeDisconnect
+DdeUnaccessData
+DdeInitialize
+DdeNameService
+DdeCreateStringHandle
+DdeUninitialize
+DdeFreeStringHandle
+DdeCmpStringHandles
+DdeQueryConvInfo
+DdeCreateDataHandle
+DdeFreeDataHandle
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c
new file mode 100644
index 000000000..8dc7c2b3e
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c
@@ -0,0 +1,106 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+/* Truley global variables */
+
+CHAR szClass[] = "DdeStrs";
+int cyText = 0;
+int cxText = 0;
+BOOL fClient = FALSE;
+BOOL fServer = FALSE;
+HINSTANCE hInst;
+
+HWND hwndMain;
+CHAR szExecDie[] = "Die";
+CHAR szExecDisconnect[] = "Disconnect";
+CHAR szExecRefresh[] = "Refresh";
+
+// This array contains storage for each supported
+// format (CF_TEXT,CF_BITMAP,CF_DIB,..CF_ENHMETAFILE)
+
+INT iAvailFormats[] = { 0, 0, 0, 0, 0, 0 };
+
+/*
+ * Service tables - read bottom up
+ */
+DDEFORMATTBL TestItemFormats[] = {
+ {
+ "TEXT",
+ CF_TEXT,
+ 0,
+ PokeTestItem_Text,
+ RenderTestItem_Text
+ },
+ {
+ "DIB",
+ CF_DIB,
+ 0,
+ PokeTestItem_DIB,
+ RenderTestItem_DIB
+ },
+ {
+ "BITMAP",
+ CF_BITMAP,
+ 0,
+ PokeTestItem_BITMAP,
+ RenderTestItem_BITMAP
+ },
+#ifdef WIN32
+ {
+ "ENHMETAFILE",
+ CF_ENHMETAFILE,
+ 0,
+ PokeTestItem_ENHMETA,
+ RenderTestItem_ENHMETA
+ },
+#endif
+ {
+ "METAFILEPICT",
+ CF_METAFILEPICT,
+ 0,
+ PokeTestItem_METAPICT,
+ RenderTestItem_METAPICT
+ },
+ {
+ "PALETTE",
+ CF_PALETTE,
+ 0,
+ PokeTestItem_PALETTE,
+ RenderTestItem_PALETTE
+ }
+};
+
+DDEITEMTBL Items[] = {
+ {
+ "TestItem",
+ 0,
+ sizeof(TestItemFormats) / sizeof(DDEFORMATTBL),
+ 0,
+ TestItemFormats
+ }
+};
+
+DDETOPICTBL Topics[] = {
+ {
+ TOPIC,
+ 0,
+ sizeof(Items) / sizeof(DDEITEMTBL),
+ 0,
+ Items,
+ Execute
+ }
+};
+
+DDESERVICETBL ServiceInfoTable[] = {
+ {
+ "DdeStrs",
+ 0,
+ sizeof(Topics) / sizeof(DDETOPICTBL),
+ 0,
+ Topics
+ }
+};
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h
new file mode 100644
index 000000000..b1ccda8ee
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h
@@ -0,0 +1,19 @@
+
+extern CHAR szClass[];
+extern int cyText;
+extern int cxText;
+extern BOOL fClient;
+extern BOOL fServer;
+extern HINSTANCE hInst;
+extern HCONV pServerhConvs[MAX_SERVER_HCONVS];
+extern HWND hwndMain;
+extern CHAR szExecDie[];
+extern CHAR szExecDisconnect[];
+extern CHAR szExecRefresh[];
+extern INT iAvailFormats[];
+
+DDEFORMATTBL TestItemFormats[];
+DDEITEMTBL Items[];
+DDETOPICTBL Topics[];
+DDESERVICETBL ServiceInfoTable[];
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/makefile b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile
@@ -0,0 +1,6 @@
+#
+# 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/wow16/ddeml/tests/ddestrs/makefile.dos b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos
new file mode 100644
index 000000000..c7c1599a1
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos
@@ -0,0 +1,50 @@
+#
+# Test makefile
+
+!ifdef WIN31
+EXEFLAGS=-AM -Gsw -Od -Ziep -W3 -DWIN16 -DWIN31 -DUSECOMM -DWIN
+!else
+EXEFLAGS=-AS -FPi -Gcw -Os -Ziepd -W3 -DWIN16 -DWIN
+!endif
+
+TEST =ddestrs
+RCFILE =ddestrs
+S1 =cmdln
+S2 =client
+S3 =$(TEST)
+S4 =globals
+S5 =server
+S6 =wrapper
+OBJ =$(S1).obj $(S2).obj $(S3).obj $(S4).obj $(S5).obj $(S6).obj
+
+#
+# Stress Test
+#
+
+all: $(TEST).exe
+
+$(RCFILE).res: $(RCFILE).rc
+ rc -r $(RCFILE).rc
+
+$(S1).obj: $(S1).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S1).c
+
+$(S2).obj: $(S2).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S2).c
+
+$(S3).obj: $(S3).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S3).c
+
+$(S4).obj: $(S4).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S4).c
+
+$(S5).obj: $(S5).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S5).c
+
+$(S6).obj: $(S6).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S6).c
+
+$(TEST).exe: $(OBJ) $(TEST).def $(RCFILE).res
+ link /map/li/co $(OBJ)/AL:16,$(TEST).exe,, /NOE /NOD libw ddeml mlibcew,$(TEST).def
+ mapsym $(TEST)
+ rc $(RCFILE).res $(TEST).exe
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd b/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd
new file mode 100644
index 000000000..7fbb62b49
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd
@@ -0,0 +1 @@
+build -cl ddestrs
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd b/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd
new file mode 100644
index 000000000..1cc3f8bff
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd
@@ -0,0 +1,13 @@
+@echo off
+if "%1"=="" goto bld
+del *.dll
+del *.sym
+del *.map
+del *.obj
+del *.bak
+del *.res
+del *.lnk
+goto done
+:bld
+nmake -f makefile.dos
+:done
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat b/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat
new file mode 100644
index 000000000..d68805551
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat
@@ -0,0 +1,12 @@
+start ddestrs.exe -10%% -e35000
+sleep 30
+
+ddestrs.exe -c -e13000 -t10
+sleep 10
+
+:loop
+start ddestrs.exe -t3 -s -a
+sleep 15
+ddestrs.exe -c -e13000 -t10
+sleep 20
+goto loop
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/server.c b/private/mvdm/wow16/ddeml/tests/ddestrs/server.c
new file mode 100644
index 000000000..56f1d2280
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/server.c
@@ -0,0 +1,1372 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+extern BOOL UpdateCount(HWND,INT,INT);
+BOOL Balance(INT);
+
+/*
+ * Service routines
+ */
+
+/*************************** Private Function ******************************\
+
+GetHINSTANCE
+
+\***************************************************************************/
+
+HINSTANCE GetHINSTANCE( HWND hwnd ) {
+HINSTANCE hInstance;
+
+#ifdef WIN32
+ hInstance=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
+#else
+ hInstance=(HINSTANCE)GetWindowWord(hwnd,GWW_HINSTANCE);
+#endif
+
+ return hInstance;
+
+}
+
+//*****************************************************************************
+//************************** DispWndProc **************************
+//*****************************************************************************
+
+LONG FAR PASCAL DispWndProc( HWND hwnd , UINT msg, WPARAM wp, LONG lp) {
+
+ return DefWindowProc(hwnd,msg,wp,lp);
+
+}
+
+/*************************** Private Function ******************************\
+*
+* CreateDisplayWindow
+*
+\***************************************************************************/
+
+HWND CreateDisplayWindow( HWND hwndParent, int nPosIndex ) {
+WNDCLASS wc,wcc;
+LPWNDCLASS lpWndClass=&wc;
+HWND hwnd;
+RECT r;
+int stpy,stpx,cy;
+char sz[100];
+LPSTR lpstr=&sz[0];
+
+#ifdef WIN32
+LPCTSTR lpsz;
+#else
+LPSTR lpsz;
+#endif
+
+char szname[100];
+
+ strcpy(&szname[0],"Display Window");
+
+ wc.style = 0;
+ wc.lpfnWndProc = DispWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetHINSTANCE(hwndParent);
+ wc.hIcon = LoadIcon(NULL,IDI_EXCLAMATION );
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW );
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "Display Window";
+ wc.hbrBackground = CreateSolidBrush(RGB(0,255,255));
+
+ lpsz=(LPSTR)wc.lpszClassName;
+
+ if(!GetClassInfo(wc.hInstance,lpsz,&wcc)) {
+ RegisterClass(lpWndClass);
+ }
+
+ GetClientRect(hwndParent,&r);
+
+ stpx =r.right-r.left;
+ stpy =((r.bottom-r.top)/3);
+
+ switch(nPosIndex) {
+ case 1: cy=r.bottom-(3*cyText);
+ break;
+ case 2: cy=r.bottom-(6*cyText);
+ break;
+ case 3: cy=r.bottom-(9*cyText);
+ break;
+ case 4: cy=r.bottom-(12*cyText);
+ break;
+ case 5: cy=r.bottom-(15*cyText);
+ break;
+ default: cy=r.bottom-(18*cyText);
+ break;
+ }
+
+ if (!IsWindow(hwndParent)) DOut((HWND)NULL,"DdeStrs.exe -- ERR:Bad parent hwnd=%u!\r\n",0,(LONG)hwndParent);
+
+ hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME,
+ "Display Window",
+ &szname[0],
+ WS_CHILD|WS_VISIBLE|WS_CAPTION|WS_DISABLED,
+ 0,
+ cy,
+ stpx,
+ 3*cyText,
+ hwndParent,
+ NULL,
+ lpWndClass->hInstance,
+ NULL );
+
+ if ( !IsWindow(hwnd) )
+ {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Display window not created\r\n");
+ UnregisterClass("Display Window",wc.hInstance);
+ }
+
+ return hwnd;
+
+}
+
+BOOL PokeTestItem_Text(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HDC hdc;
+HBRUSH hBrush;
+PAINTSTRUCT ps;
+RECT rc;
+DWORD cbData;
+HWND hwndDisplay;
+
+ Balance(OFFSET_CLIENT);
+
+ hwndDisplay=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwndDisplay,"Client - CF_TEXT");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwndDisplay);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC (client:CF_TEXT)!\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+ hBrush=CreateSolidBrush(WHITE);
+ if(!hBrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hBrush ret from CreateSolidBrush (client:CF_TEXT)!\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ EndPaint(hwndDisplay,&ps);
+ return 0;
+ }
+
+ GetClientRect(hwndDisplay,&rc);
+
+ FillRect(hdc,&rc,hBrush);
+ DeleteObject(hBrush);
+
+ DrawText(hdc, lpData, -1, &rc, DT_LEFT|DT_TOP);
+ ReleaseDC(hwndDisplay,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+BOOL PokeTestItem_DIB(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDC hdc;
+RECT r;
+INT width,height;
+LPBITMAPINFO lpbitinfo;
+LPBYTE lpbits;
+HANDLE hmem;
+LPBYTE lpData;
+DWORD cbData;
+LPBYTE lp;
+int iexRGB;
+
+ Balance(OFFSET_CLIENT);
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_DIB");
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+#ifdef WIN32
+ memcpy(&hmem,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hmem,lpData,sizeof(HANDLE));
+#endif
+
+ if(!hmem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:hmem recieved from server=NULL (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ lp =(LPBYTE)GlobalLock(hmem);
+ lpbitinfo=(LPBITMAPINFO)lp;
+
+ // iexRGB is ((2^n)-1) where n=biBitCount and we are computing the
+ // number of RGBQUAD structures. Remember that part of the
+ // BITMAPINFO structure contains 1 RGBQUAD already.
+
+ iexRGB =((0x0001<<lpbitinfo->bmiHeader.biBitCount)-1)*sizeof(RGBQUAD);
+ lpbits=lp+(sizeof(BITMAPINFO)+iexRGB);
+
+ SetDIBitsToDevice(hdc,
+ 0,
+ 0,
+ (UINT)lpbitinfo->bmiHeader.biWidth,
+ (UINT)lpbitinfo->bmiHeader.biHeight,
+ 0,
+ 0,
+ 0,
+ (UINT)(lpbitinfo->bmiHeader.biHeight),
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS);
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+}
+
+BOOL PokeTestItem_BITMAP(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height;
+HBITMAP hbmap;
+HANDLE hobj;
+LPBYTE lpData;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_BITMAP");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+#ifdef WIN32
+ memcpy(&hbmap,lpData,sizeof(HBITMAP));
+#else
+ _fmemcpy(&hbmap,lpData,sizeof(HBITMAP));
+#endif
+
+ hdc = GetDC(hwnd);
+ hdcMem = CreateCompatibleDC(hdc);
+
+ if(!hdc||!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ if(hdc) ReleaseDC(hwndMain,hdc);
+ if(hdcMem) DeleteDC(hdcMem);
+ return 0;
+ }
+
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbmap (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ DeleteDC(hdcMem);
+ ReleaseDC(hwndMain,hdc);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hobj=SelectObject(hdcMem,hbmap);
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:SelectObject failed (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ DeleteDC(hdcMem);
+ ReleaseDC(hwndMain,hdc);
+ return 0;
+ }
+
+ if(!BitBlt(hdc,0,0,width,height,hdcMem,0,0,SRCCOPY))
+ DDEMLERROR("DdeStrs.Exe -- ERR:BitBlt failed (client)\r\n");
+
+ hobj=SelectObject(hdcMem,hobj);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+#ifdef WIN32
+BOOL PokeTestItem_ENHMETA(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HDC hdc;
+HANDLE hemf;
+DWORD cbData;
+RECT r;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_ENHMETAFILE");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hemf,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hemf,lpData,sizeof(HANDLE));
+#endif
+
+ GetClientRect(hwnd,&r);
+ if(!PlayEnhMetaFile(hdc,hemf,&r))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayMetaFile failed (client)\r\n");
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+#endif
+
+BOOL PokeTestItem_METAPICT(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HDC hdc;
+HANDLE hmf;
+LPMETAFILEPICT lpMfp;
+HANDLE hmem;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_METAFILEPICT");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hmem,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hmem,lpData,sizeof(HANDLE));
+#endif
+
+ lpMfp=(LPMETAFILEPICT)GlobalLock(hmem);
+ hmf=lpMfp->hMF;
+
+ if(!PlayMetaFile(hdc,hmf))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayMetaFile failed (client)\r\n");
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+BOOL PokeTestItem_PALETTE(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HPALETTE hpal;
+HDC hdc;
+RECT r;
+HANDLE hobj;
+HANDLE hbrush;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_PALETTE");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ GetClientRect(hwnd,&r);
+
+ hdc=GetDC(hwnd);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hpal,lpData,sizeof(HPALETTE));
+#else
+ _fmemcpy(&hpal,lpData,sizeof(HPALETTE));
+#endif
+
+ hobj=(HPALETTE)SelectPalette(hdc,hpal,FALSE);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hobj:SelectPalette failed (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ RealizePalette(hdc);
+
+ hbrush=CreateSolidBrush(PALETTEINDEX(0));
+ if(!hbrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbrush ret from CreatSolidBrush (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ FillRect(hdc,&r,hbrush);
+ DeleteObject(hbrush);
+
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+HDDEDATA RenderTestItem_Text(
+HDDEDATA hData)
+{
+HDC hdc;
+HBRUSH hBrush;
+PAINTSTRUCT ps;
+RECT rc;
+HDDEDATA hddedata;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+HWND hwndDisplay;
+
+ Balance(OFFSET_SERVER);
+
+ hwndDisplay=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwndDisplay,"Server - CF_TEXT");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[TXT]!=0L) {
+ hddedata=hAppOwned[TXT];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdc=GetDC(hwndDisplay);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC! (server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hBrush=CreateSolidBrush(WHITE);
+ if(!hBrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hBrush ret from CreateSolidBrush! (server)\r\n");
+ EndPaint(hwndDisplay,&ps);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwndDisplay,&rc);
+ FillRect(hdc,&rc,hBrush);
+ DeleteObject(hBrush);
+
+ DrawText(hdc, "Data:CF_TEXT format", -1, &rc, DT_LEFT|DT_TOP);
+ ReleaseDC(hwndDisplay,hdc);
+
+ hddedata=DdeAddData(hData, "Data:CF_TEXT format", 20, 0);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[TXT]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+HDDEDATA RenderTestItem_DIB(
+HDDEDATA hData)
+{
+HWND hwnd;
+LONG length;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height,dibhdr;
+HBITMAP hbmap;
+HANDLE hobj;
+LPBITMAPINFO lpbitinfo;
+LPBITMAPINFOHEADER lpbithdr;
+LPBYTE lpbits;
+LPBYTE lpdata;
+HDDEDATA hddedata;
+INT ip,ibpp;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_DIB");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[DIB]!=0L) {
+ hddedata=hAppOwned[DIB];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length = sizeof(HBITMAP);
+
+ hdc=GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ ibpp=GetDeviceCaps(hdc,BITSPIXEL);
+ ip=GetDeviceCaps(hdc,PLANES);
+
+ hdcMem=CreateCompatibleDC(hdc);
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (server)\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hbmap=CreateCompatibleBitmap(hdcMem,width,height);
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbmap-CreateCompatibleBitmap failed (server)\r\n");
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hobj=SelectObject(hdcMem,hbmap);
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject failed\r\n");
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), PatBlt failed\r\n");
+
+ // Deselect object (must be done according to docs)
+
+ hobj=SelectObject(hdcMem,hobj);
+ if(!hobj) DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject [call 2] failed\r\n");
+
+
+ // Set up for a monochrome bitmap.
+
+ dibhdr =sizeof(BITMAPINFO)+(sizeof(RGBQUAD));
+
+
+ // dib header plus area for raw bits
+
+ length =dibhdr+(((width*ibpp)+31)/32)*ip*height*4;
+
+ // Allocate memory for the DIB
+
+ hm=GlobalAlloc(GMEM_ZEROINIT|GMEM_DDESHARE,length);
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_DIB\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GobalAlloc failed, allocation size = %d\r\n", length );
+ DDEMLERROR(&sz[0]);
+
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lpdata=(LPBYTE)GlobalLock(hm);
+
+ lpbitinfo=(LPBITMAPINFO)lpdata;
+ lpbithdr=&(lpbitinfo->bmiHeader);
+
+ lpbits=lpdata+dibhdr;
+
+ lpbitinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+ lpbitinfo->bmiHeader.biWidth=width;
+ lpbitinfo->bmiHeader.biHeight=height;
+ lpbitinfo->bmiHeader.biPlanes=1;
+ lpbitinfo->bmiHeader.biBitCount=1;
+
+ // I allocated zero init memory so the other values should
+ // be 0 and will use the default.
+
+ if(!GetDIBits(hdcMem,
+ hbmap,
+ 0,
+ height,
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS))
+ {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), GetDIBits failed\r\n");
+ }
+
+ SetDIBitsToDevice(hdc,
+ 0,
+ 0,
+ (UINT)lpbitinfo->bmiHeader.biWidth,
+ (UINT)lpbitinfo->bmiHeader.biHeight,
+ 0,
+ 0,
+ 0,
+ (UINT)(lpbitinfo->bmiHeader.biHeight),
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS);
+
+ hddedata=DdeAddData(hData, &hm, sizeof(HANDLE), 0);
+
+ GlobalUnlock(hm);
+
+ DeleteObject(hbmap);
+
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[DIB]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+HDDEDATA RenderTestItem_BITMAP(
+HDDEDATA hData)
+{
+HWND hwnd;
+LONG length;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height;
+HBITMAP hbmap;
+HANDLE hobj;
+HDDEDATA hddedata;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_BITMAP");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[BITMAP]!=0L) {
+ hddedata=hAppOwned[BITMAP];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length = sizeof(HBITMAP);
+
+ hdc=GetDC(hwnd);
+ hdcMem=CreateCompatibleDC(hdc);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hbmap=CreateCompatibleBitmap(hdcMem,width,height);
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hbmap\r\n");
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hobj=SelectObject(hdcMem,hbmap);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject failed\r\n");
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), PatBlt failed\r\n");
+
+ if(!BitBlt(hdc,0,0,width,height,hdcMem,0,0,SRCCOPY))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), BitBlt failed\r\n");
+
+#ifdef WIN32
+ memcpy(lpdata,&hbmap,(INT)length);
+#else
+ _fmemcpy(lpdata,&hbmap,(INT)length);
+#endif
+
+ hddedata=DdeAddData(hData, lpdata, length, 0);
+
+ // Object will be deleted by client! Not server.
+
+ SelectObject(hdcMem,hobj);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[BITMAP]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+#ifdef WIN32
+HDDEDATA RenderTestItem_ENHMETA(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDDEDATA hddedata;
+HDC hdc,hdcMem;
+INT width,height,length;
+RECT r;
+HANDLE hemf;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+
+#ifdef WIN32
+XFORM xp;
+LPXFORM lpxform=&xp;
+#endif
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_ENHMETAFILE");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=GlobalLock(hmem);
+
+ if(hAppOwned[ENHMETA]!=0L) {
+ hddedata=hAppOwned[ENHMETA];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdc=GetDC(hwnd); //JOHNSP:CHANGE - below few lines
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hdcMem=CreateEnhMetaFile(hdc,NULL,NULL,NULL);
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ length=sizeof(HANDLE);
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PatBlt failed (server)\r\n");
+
+ hemf=CloseEnhMetaFile(hdcMem);
+ if(!hemf) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:CloseEnhMetaFile failed (server)\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(lpdata,&hemf,length);
+#else
+ _fmemcpy(lpdata,&hemf,length);
+#endif
+
+ if(!PlayEnhMetaFile(hdc,hemf,&r))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayEnhMetaFile failed (server)\r\n");
+
+ hddedata=DdeAddData(hData, lpdata, length, 0);
+
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[ENHMETA]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+#endif
+
+HDDEDATA RenderTestItem_METAPICT(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDDEDATA hddedata;
+HDC hdc,hdcMem;
+INT width,height,length;
+RECT r;
+HANDLE hmf;
+LPMETAFILEPICT lpMfp;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_METAFILEPICT");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[METAPICT]!=0L) {
+ hddedata=hAppOwned[METAPICT];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdcMem=CreateMetaFile(NULL);
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR: NULL hdc ret from CreateMetaFile, (Server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ length=sizeof(HANDLE);
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PatBlt failed (server)\r\n");
+
+ hmf=CloseMetaFile(hdcMem);
+ if(!hmf) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hmf ret CloseMetaFile! (Server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hm=GlobalAlloc(GMEM_ZEROINIT|GMEM_DDESHARE,sizeof(METAFILEPICT));
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_METAPICT\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GlobalAlloc failed, allocation size = %d\r\n", sizeof(METAFILEPICT) );
+ DDEMLERROR(&sz[0]);
+ DeleteMetaFile(hmf); //JOHNSP:CHANGE
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lpMfp=(LPMETAFILEPICT)GlobalLock(hm);
+
+ lpMfp->mm = MM_TEXT;
+ lpMfp->xExt = width;
+ lpMfp->yExt = height;
+ lpMfp->hMF = hmf;
+
+ GlobalUnlock(hm);
+
+#ifdef WIN32
+ memcpy(lpdata,&hm,length);
+#else
+ _fmemcpy(lpdata,&hm,length);
+#endif
+
+ hdc=GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC, (Server)\r\n");
+ GlobalFree(hm); //JOHNSP:CHANGE
+ DeleteMetaFile(hmf); //JOHNSP:CHANGE
+ GlobalUnlock(hmem);
+ return 0;
+ }
+ else {
+ hddedata=DdeAddData(hData, lpdata, length, 0); //JOHNSP:CHANGE
+ PlayMetaFile(hdc,hmf);
+ ReleaseDC(hwnd,hdc);
+ }
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[METAPICT]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+
+HDDEDATA RenderTestItem_PALETTE(
+HDDEDATA hData)
+{
+HWND hwnd;
+HPALETTE hpal;
+LPLOGPALETTE lppal;
+HDDEDATA hddedata;
+INT length;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+HDC hdc;
+HANDLE hobj;
+HANDLE hbrush;
+RECT r;
+
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_PALETTE");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[PALETTE]!=0L) {
+ hddedata=hAppOwned[PALETTE];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length=sizeof(LOGPALETTE)+sizeof(PALETTEENTRY);
+
+ lppal=(LPLOGPALETTE)GetMem(length,&hm);
+
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_PALETTE\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GlobalAlloc failed, allocation size = %d\r\n", length );
+ DDEMLERROR(&sz[0]);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lppal->palNumEntries=1;
+ lppal->palVersion=0x0300;
+
+ lppal->palPalEntry[0].peRed =(BYTE)255;
+ lppal->palPalEntry[0].peGreen=(BYTE)255;
+ lppal->palPalEntry[0].peBlue =(BYTE)255;
+ lppal->palPalEntry[0].peFlags=(BYTE)0;
+
+ hpal=CreatePalette(lppal);
+ if(!hpal) {
+ DDEMLERROR("DdeStrs.Exe - NULL hpal ret CreatePalette! (server)\r\n");
+ FreeMem(hm);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ FreeMem(hm);
+
+#ifdef WIN32
+ memcpy(lpdata,&hpal,sizeof(HANDLE));
+#else
+ _fmemcpy(lpdata,&hpal,sizeof(HANDLE));
+#endif
+
+ hddedata=DdeAddData(hData, lpdata, sizeof(HPALETTE), 0);
+
+ // Show that palette works.
+
+ // NOTE: From here down if we get a failure we don't abort but
+ // return hddedata to pass to the client. More basically if
+ // an error is encountered below it only affects the display
+ // on the server side!
+
+ GetClientRect(hwnd,&r);
+
+ hdc=GetDC(hwnd);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hdc (client)\r\n");
+ return hddedata;
+ }
+
+ hobj=(HPALETTE)SelectPalette(hdc,hpal,FALSE);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hobj:SelectPalette failed (client)\r\n");
+ ReleaseDC(hwnd,hdc);
+ return hddedata;
+ }
+
+ RealizePalette(hdc);
+
+ hbrush=CreateSolidBrush(PALETTEINDEX(0));
+ if(!hbrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hbrush ret from CreatSolidBrush (client)\r\n");
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+ return hddedata;
+ }
+
+ FillRect(hdc,&r,hbrush);
+ DeleteObject(hbrush);
+
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+
+ // if we are running appowned, save first created handle
+ // away for futher use.
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[PALETTE]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+
+BOOL Execute(
+HDDEDATA hData)
+{
+ LPSTR psz,psz2;
+ BOOL fRet = FALSE;
+ LONG cServerhConvs;
+ int i;
+ HANDLE hmem;
+ HCONV FAR *pServerhConvs;
+
+ psz = DdeAccessData(hData, NULL);
+
+#ifdef WIN16
+ if (!_fstricmp(psz, szExecDie)) {
+#else
+ if (!stricmp(psz, szExecDie)) {
+#endif
+ psz2=(LPSTR)-1;
+ *psz; // GP Fault!
+ fRet = TRUE;
+
+#ifdef WIN16
+ } else if (!_fstricmp(psz, szExecRefresh)) {
+#else
+ } else if (!stricmp(psz, szExecRefresh)) {
+#endif
+
+ if (!DdePostAdvise(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST), 0, 0)) {
+ DDEMLERROR("DdeStrs.Exe -- ERR DdePostAdvise failed\r\n");
+ }
+ fRet = TRUE;
+
+#ifdef WIN16
+ } else if (!_fstricmp(psz, szExecDisconnect)) {
+#else
+ } else if (!stricmp(psz, szExecDisconnect)) {
+#endif
+
+ cServerhConvs=(INT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS);
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ for (i = 0; i < cServerhConvs; i++) {
+ if (!DdeDisconnect(pServerhConvs[i])) {
+ DDEMLERROR("DdeStrs.Exe -- ERR DdeDisconnect failed\r\n");
+ }
+ }
+
+ GlobalUnlock(hmem);
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS,0L);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ fRet = TRUE;
+ }
+ DdeUnaccessData(hData);
+ return(fRet);
+}
+
+VOID PaintServer(
+HWND hwnd,
+PAINTSTRUCT *pps)
+{
+ RECT rc;
+ static CHAR szT[40];
+
+ GetClientRect(hwnd, &rc);
+
+ if (fServer) {
+ rc.left += (rc.right - rc.left) >> 1; // server info is on right half
+ }
+ rc.bottom = rc.top + cyText;
+
+ wsprintf(szT, "%d server connections", GetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS));
+ DrawText(pps->hdc, szT, -1, &rc, DT_RIGHT);
+ OffsetRect(&rc, 0, cyText);
+
+ wsprintf(szT, "%d server count", GetWindowLong(hwnd,OFFSET_SERVER));
+ DrawText(pps->hdc, szT, -1, &rc, DT_RIGHT);
+ OffsetRect(&rc, 0, cyText);
+
+}
+
+
+HDDEDATA FAR PASCAL CustomCallback(
+UINT wType,
+UINT wFmt,
+HCONV hConv,
+HSZ hsz1,
+HSZ hsz2,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2)
+{
+ LONG cServerhConvs,cClienthConvs;
+ int i;
+ HANDLE hmem;
+ HCONV FAR *pServerhConvs;
+ HCONV hC;
+ HCONVLIST hConvList=0;
+ DWORD dwid;
+ LONG lflags;
+
+
+ dwid=GETCURRENTTHREADID();
+ cServerhConvs=(INT)GetThreadLong(dwid,OFFSET_CSERVERCONVS);
+
+ switch (wType) {
+ case XTYP_CONNECT_CONFIRM:
+
+ hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ pServerhConvs[cServerhConvs] = hConv;
+ cServerhConvs++;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ if (cServerhConvs >= MAX_SERVER_HCONVS) {
+ LOGDDEMLERROR("DdeStrs.Exe -- ERR-Number of connections > MAX\r\n");
+ cServerhConvs--;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ }
+ GlobalUnlock(hmem);
+ break;
+
+ case XTYP_DISCONNECT:
+
+ if(fServer)
+ {
+
+ hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ for (i = 0; i < cServerhConvs; i++)
+ {
+
+ if (pServerhConvs[i] == hConv)
+ {
+ cServerhConvs--;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+
+ for (; i < cServerhConvs; i++)
+ {
+ pServerhConvs[i] = pServerhConvs[i+1];
+ } // for
+
+ break;
+
+ } // if pServerhConvs
+
+ } // for i
+
+ GlobalUnlock(hmem);
+
+ } // fServer
+
+ // If the server is shutting down the conversation then we need
+ // to change our client connection count. Remember that the
+ // current conversation is valid until we return from this callback
+ // so don't count the current conversation.
+
+ if(fClient)
+ {
+
+ // *** Count Client Connections ****
+
+ cClienthConvs = 0;
+ hConvList=GetThreadLong(dwid,OFFSET_HCONVLIST);
+
+ if (hConvList)
+ {
+ hC = 0;
+ while (hC = DdeQueryNextServer(hConvList, hC))
+ {
+ if (hC!=hConv) cClienthConvs++;
+ } // while
+
+ } // if hConvList
+
+ SetThreadLong(dwid,OFFSET_CCLIENTCONVS,cClienthConvs);
+
+ } // if fClient
+
+ InvalidateRect(hwndMain, NULL, TRUE);
+
+ break;
+
+ case XTYP_REGISTER:
+ case XTYP_UNREGISTER:
+ lflags=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(fClient && (FLAG_STOP!=(lflags&FLAG_STOP)))
+ {
+ ReconnectList();
+ }
+ break;
+ }
+
+ return(0);
+}
+
+BOOL Balance( INT itype ) {
+
+ if(itype==OFFSET_SERVER) {
+ UpdateCount(hwndMain,OFFSET_SERVER,INC);
+ }
+ else {
+ UpdateCount(hwndMain,OFFSET_CLIENT,INC);
+ }
+
+ return TRUE;
+
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/sources b/private/mvdm/wow16/ddeml/tests/ddestrs/sources
new file mode 100644
index 000000000..03153145f
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/sources
@@ -0,0 +1,24 @@
+MAJORCOMP=test
+MINORCOMP=ddestrs
+
+TARGETNAME=ddestrs
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+INCLUDES=.
+
+SOURCES=ddestrs.c ddestrs.rc client.c server.c globals.c wrapper.c cmdln.c
+
+C_DEFINES=-DWIN32
+
+!if 0
+NTDEBUG=ntsd
+NTDEBUGTYPE=windbg
+386_OPTIMIZATION=/Od
+!endif
+
+UMTYPE=windows
+UMAPPL=ddestrs
+UMENTRY=winmain
+UMLIBS=obj\*\ddestrs.lib obj\*\ddestrs.res
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c
new file mode 100644
index 000000000..f477f76cf
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c
@@ -0,0 +1,793 @@
+/***************************************************************************\
+
+ PROGRAM : wrapper.c
+
+ PURPOSE : This is not a full program but a module you can include
+ in your code. It implements a standard DDEML callback
+ function that allows you to have most of your DDE table
+ driven. The default callback function handles all basic
+ System Topic information based on the tables you give
+ to this app.
+
+ LIMITATIONS : This only supports servers that:
+ have only one service name
+ have enumerable topics and items
+ do not change the topics or items they support over time.
+
+
+ EXPORTED ROUTINES:
+
+ InitializeDDE()
+ Use this to initialize the callback function tables and the DDEML
+
+ UninitializeDDE()
+ Use this to cleanup this module and uninitialize the DDEML instance.
+
+\***************************************************************************/
+
+#include <windows.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include <port1632.h>
+#include "ddestrs.h"
+
+extern BOOL fServer;
+extern LPSTR pszNetName;
+extern LONG SetThreadLong(DWORD,INT,LONG);
+extern LONG GetThreadLong(DWORD,INT);
+extern LPSTR TStrCpy( LPSTR, LPSTR);
+
+BOOL InExit(VOID);
+VOID InitHszs(LPDDESERVICETBL psi);
+UINT GetFormat(LPSTR pszFormat);
+VOID FreeHszs(LPDDESERVICETBL psi);
+HDDEDATA APIENTRY WrapperCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+
+BOOL DoCallback(HCONV,HSZ,HSZ,UINT,UINT,HDDEDATA,LPDDESERVICETBL,HDDEDATA *);
+
+HDDEDATA ReqItems(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
+HDDEDATA AddReqFormat(HDDEDATA hDataOut, LPSTR pszFmt);
+HDDEDATA ReqFormats(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
+HDDEDATA DoWildConnect(HSZ hszTopic);
+
+PFNCALLBACK lpfnUserCallback = NULL;
+PFNCALLBACK lpfnWrapperCallback = NULL;
+
+LPDDESERVICETBL pasi = NULL;
+char tab[] = "\t";
+
+#define FOR_EACH_TOPIC(psvc, ptpc, i) for (i = 0, ptpc=(psvc)->topic; i < (int)(psvc)->cTopics; i++, ptpc++)
+#define FOR_EACH_ITEM(ptpc, pitm, i) for (i = 0, pitm=(ptpc)->item; i < (int)(ptpc)->cItems; i++, pitm++)
+#define FOR_EACH_FORMAT(pitm, pfmt, i) for (i = 0, pfmt=(pitm)->fmt; i < (int)(pitm)->cFormats;i++, pfmt++)
+
+
+
+/* STANDARD PREDEFINED FORMATS */
+
+#ifdef WIN32
+#define CSTDFMTS 14
+#else
+#define CSTDFMTS 12
+#endif
+
+struct {
+ UINT wFmt;
+ PSTR pszFmt;
+} StdFmts[CSTDFMTS] = {
+ { CF_TEXT , "TEXT" } ,
+ { CF_BITMAP , "BITMAP" } ,
+ { CF_METAFILEPICT, "METAFILEPICT" } ,
+ { CF_SYLK , "SYLK" } ,
+ { CF_DIF , "DIF" } ,
+ { CF_TIFF , "TIFF" } ,
+ { CF_OEMTEXT , "OEMTEXT" } ,
+ { CF_DIB , "DIB" } ,
+ { CF_PALETTE , "PALETTE" } ,
+ { CF_PENDATA , "PENDATA" } ,
+ { CF_RIFF , "RIFF" } ,
+ { CF_WAVE , "WAVE" } ,
+#ifdef WIN32
+ { CF_UNICODETEXT , "UNICODETEXT" } ,
+ { CF_ENHMETAFILE , "ENHMETAFILE" } ,
+#endif
+};
+
+
+
+HDDEDATA SysReqTopics(HDDEDATA hDataOut);
+HDDEDATA SysReqSysItems(HDDEDATA hDataOut);
+HDDEDATA SysReqFormats(HDDEDATA hDataOut);
+
+ /* STANDARD SERVICE INFO TABLES */
+
+DDEFORMATTBL StdSvcSystopicTopicsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqTopics
+};
+
+DDEFORMATTBL StdSvcSystopicSysitemsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqSysItems
+};
+
+DDEFORMATTBL StdSvcSystopicFormatsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqFormats
+};
+
+#define ITPC_TOPICS 0
+#define ITPC_SYSITEMS 1
+#define ITPC_FORMATS 2
+#define ITPC_ITEMLIST 3
+
+#define ITPC_COUNT 4
+
+DDEITEMTBL StdSvcSystopicItems[] = {
+ { SZDDESYS_ITEM_TOPICS, 0, 1, 0, StdSvcSystopicTopicsFormats },
+ { SZDDESYS_ITEM_SYSITEMS, 0, 1, 0, StdSvcSystopicSysitemsFormats },
+ { SZDDESYS_ITEM_FORMATS, 0, 1, 0, StdSvcSystopicFormatsFormats },
+ { SZDDE_ITEM_ITEMLIST, 0, 1, 0, StdSvcSystopicSysitemsFormats },
+};
+
+DDETOPICTBL StdSvc[] = {
+ SZDDESYS_TOPIC, 0, ITPC_COUNT, 0, StdSvcSystopicItems
+};
+
+DDESERVICETBL SSI = {
+ NULL, 0, 1, 0, StdSvc
+};
+
+/*********************************************************************/
+
+
+BOOL InitializeDDE(
+PFNCALLBACK lpfnCustomCallback,
+LPDWORD pidInst,
+LPDDESERVICETBL AppSvcInfo,
+DWORD dwFilterFlags,
+HANDLE hInst)
+{
+DWORD idI=0;
+
+ if (lpfnCustomCallback) {
+ lpfnUserCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)lpfnCustomCallback, hInst);
+ }
+ lpfnWrapperCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)WrapperCallback, hInst);
+
+ if (DdeInitialize(&idI, lpfnWrapperCallback, dwFilterFlags, 0)) {
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+ if (lpfnCustomCallback) {
+ FreeProcInstance((FARPROC)lpfnUserCallback);
+ }
+ FreeProcInstance((FARPROC)lpfnWrapperCallback);
+ return(FALSE);
+ }
+ else SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+ *pidInst = idI;
+ InitHszs(AppSvcInfo);
+ InitHszs(&SSI);
+ pasi = AppSvcInfo;
+
+ if (fServer) {
+ DdeNameService(idI, pasi->hszService, 0, DNS_REGISTER);
+ }
+
+ return(TRUE);
+}
+
+
+
+VOID InitHszs(
+LPDDESERVICETBL psi)
+{
+ int iTopic, iItem, iFmt;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+ DWORD idI;
+ CHAR sz[120];
+ LPBYTE psz;
+ LPBYTE pNet;
+
+ pNet=pszNetName;
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ if (psi->pszService) {
+
+ // This area of code inplements the clients ability
+ // to see net drives. This is the -n option.
+
+ if(pNet)
+ {
+
+ sz[0]='\\';
+ sz[1]='\\';
+ psz=&sz[2];
+
+ psz=TStrCpy(psz,pNet);
+
+ while(*++psz!='\0');
+
+ *psz++='\\';
+
+ psz=TStrCpy(psz,psi->pszService);
+ psz=&sz[0];
+
+ psi->hszService = DdeCreateStringHandle(idI, psz, 0);
+
+ } // pNet
+
+ else psi->hszService = DdeCreateStringHandle(idI, psi->pszService, 0);
+ }
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ ptpc->hszTopic = DdeCreateStringHandle(idI, ptpc->pszTopic, 0);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ pitm->hszItem = DdeCreateStringHandle(idI, pitm->pszItem, 0);
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ pfmt->wFmt = GetFormat(pfmt->pszFormat);
+ }
+ }
+ }
+}
+
+
+/*
+ * This function allows apps to use standard CF_ formats. The string
+ * given may be in the StdFmts[] table.
+ */
+
+UINT GetFormat(
+LPSTR pszFormat)
+{
+ int iFmt;
+
+ for (iFmt = 0; iFmt < CSTDFMTS; iFmt++) {
+ if (!lstrcmp(pszFormat, StdFmts[iFmt].pszFmt)) {
+ return(StdFmts[iFmt].wFmt);
+ }
+ }
+ return(RegisterClipboardFormat(pszFormat));
+}
+
+
+
+VOID UninitializeDDE()
+{
+DWORD idI;
+
+ if (pasi == NULL) {
+ return;
+ }
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ DdeNameService(idI, pasi->hszService, 0, DNS_UNREGISTER);
+ FreeHszs(pasi);
+ FreeHszs(&SSI);
+ DdeUninitialize(idI);
+ if (lpfnUserCallback) {
+ FreeProcInstance((FARPROC)lpfnUserCallback);
+ }
+ FreeProcInstance((FARPROC)lpfnWrapperCallback);
+}
+
+
+
+VOID FreeHszs(
+LPDDESERVICETBL psi)
+{
+ int iTopic, iItem;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ DWORD idI;
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ DdeFreeStringHandle(idI, psi->hszService);
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ DdeFreeStringHandle(idI, ptpc->hszTopic);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ DdeFreeStringHandle(idI, pitm->hszItem);
+ }
+ }
+}
+
+BOOL InExit( VOID ) {
+LONG l;
+
+ if(!IsWindow((HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY))) {
+ DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndDisplay, returning NAck!\r\n");
+ return TRUE;
+ }
+
+ if(!IsWindow(hwndMain)) {
+ DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndMain, returning NAck!\r\n");
+ return TRUE;
+ }
+
+ // No need for error message on this one. This is expected to happen
+ // when queues fill up under extreme conditions.
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_STOP) {
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+HDDEDATA APIENTRY WrapperCallback(
+UINT wType,
+UINT wFmt,
+HCONV hConv,
+HSZ hsz1,
+HSZ hsz2,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2)
+{
+ HDDEDATA hDataRet;
+
+ switch (wType) {
+ case XTYP_WILDCONNECT:
+ if (!hsz2 || !DdeCmpStringHandles(hsz2, pasi->hszService)) {
+ return(DoWildConnect(hsz1));
+ }
+ break;
+
+ case XTYP_CONNECT:
+
+ if(!fServer) {
+ DDEMLERROR("DdeStrs.Exe -- Recieved XTYP_CONNECT when client!\r\n");
+ }
+
+ case XTYP_ADVSTART:
+ case XTYP_EXECUTE:
+ case XTYP_REQUEST:
+ case XTYP_ADVREQ:
+ case XTYP_ADVDATA:
+ case XTYP_POKE:
+
+ if(InExit()) return(0);
+
+ if(DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
+ &SSI, &hDataRet))
+ return(hDataRet);
+
+ if (DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
+ pasi, &hDataRet))
+ return(hDataRet);
+
+ /* Fall Through */
+ default:
+ if (lpfnUserCallback != NULL) {
+ return(lpfnUserCallback(wType, wFmt, hConv, hsz1, hsz2, hData,
+ dwData1, dwData2));
+ }
+ }
+ return(0);
+}
+
+
+
+
+BOOL DoCallback(
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+UINT wFmt,
+UINT wType,
+HDDEDATA hDataIn,
+LPDDESERVICETBL psi,
+HDDEDATA *phDataRet)
+{
+ int iTopic, iItem, iFmt;
+ LPDDEFORMATTBL pfmt;
+ LPDDEITEMTBL pitm;
+ LPDDETOPICTBL ptpc;
+#ifdef WIN32
+ CONVINFO ci;
+#endif
+ LONG l;
+ BOOL fCreate=FALSE;
+ HANDLE hmem;
+ HDDEDATA FAR *hAppOwned;
+
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ if (DdeCmpStringHandles(ptpc->hszTopic, hszTopic))
+ continue;
+
+ if (wType == XTYP_EXECUTE) {
+ if (ptpc->lpfnExecute) {
+ if ((*ptpc->lpfnExecute)(hDataIn))
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ } else {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ return(TRUE);
+ }
+
+ if (wType == XTYP_CONNECT) {
+ *phDataRet = (HDDEDATA)TRUE;
+ return(TRUE);
+ }
+
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ if (DdeCmpStringHandles(pitm->hszItem, hszItem))
+ continue;
+
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ if (pfmt->wFmt != wFmt)
+ continue;
+
+ switch (wType) {
+ case XTYP_ADVSTART:
+ *phDataRet = (HDDEDATA)TRUE;
+ break;
+
+// XTYP_POKE CHANGE
+#if 0
+ case XTYP_POKE:
+#endif
+
+ case XTYP_ADVDATA:
+ if (pfmt->lpfnPoke) {
+ if ((*pfmt->lpfnPoke)(hDataIn))
+ {
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ break;
+ }
+ } else {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ break;
+
+// XTYP_POKE CHANGE
+#ifdef WIN32 // TURNED BACK ON
+ case XTYP_POKE:
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ ci.cb = sizeof(CONVINFO);
+
+ if (DdeQueryConvInfo(hConv, QID_SYNC, &ci))
+ {
+ if (!(ci.wStatus & ST_ISSELF)) {
+ DdePostAdvise(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST), hszTopic, hszItem);
+ }
+ }
+ else
+ {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ break;
+#endif
+
+
+ case XTYP_REQUEST:
+ case XTYP_ADVREQ:
+ if (pfmt->lpfnRequest) {
+ HDDEDATA hDataOut;
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ switch (pfmt->wFmt) {
+ case CF_TEXT: if(hAppOwned[TXT]==0L) fCreate=TRUE;
+ break;
+ case CF_DIB: if(hAppOwned[DIB]==0L) fCreate=TRUE;
+ break;
+ case CF_BITMAP: if(hAppOwned[BITMAP]==0L) fCreate=TRUE;
+ break;
+#ifdef WIN32
+ case CF_ENHMETAFILE: if(hAppOwned[ENHMETA]==0L) fCreate=TRUE;
+ break;
+#endif
+ case CF_METAFILEPICT: if(hAppOwned[METAPICT]==0L) fCreate=TRUE;
+ break;
+ case CF_PALETTE: if(hAppOwned[PALETTE]==0L) fCreate=TRUE;
+ break;
+ default:
+ DDEMLERROR("DdeStrs.Exe -- ERR: Unexpected switch constant in DoCallback!\r\n");
+ break;
+
+ } // switch
+
+ GlobalUnlock(hmem);
+
+ if (fCreate) {
+ hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ pitm->hszItem,
+ pfmt->wFmt,
+ HDATA_APPOWNED);
+ } // fCreate
+
+ } // l&FLAG_APPOWNED
+ else {
+ hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ pitm->hszItem,
+ pfmt->wFmt,
+ 0);
+ } // else l&FLAG_APPOWNED
+
+ *phDataRet = (HDDEDATA)(*pfmt->lpfnRequest)(hDataOut);
+ if (!*phDataRet) {
+ DdeFreeDataHandle(hDataOut);
+ }
+ } else {
+ *phDataRet = 0;
+ }
+ break;
+ }
+ return(TRUE);
+ }
+ }
+
+ /* item not found in tables */
+
+ if (wFmt == CF_TEXT && (wType == XTYP_REQUEST || wType == XTYP_ADVREQ)) {
+ /*
+ * If formats item was requested and not found in the tables,
+ * return a list of formats supported under this topic.
+ */
+ if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_FORMATS].hszItem)) {
+ *phDataRet = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ hszItem,
+ wFmt,
+ 0);
+ *phDataRet = ReqFormats(*phDataRet, ptpc);
+ return(TRUE);
+ }
+ /*
+ * If sysitems or topicitemlist item was requested and not found,
+ * return a list of items supported under this topic.
+ */
+ if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_SYSITEMS].hszItem) ||
+ !DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_ITEMLIST].hszItem)) {
+ *phDataRet = ReqItems(DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ hszItem,
+ wFmt,
+ 0),
+ ptpc);
+ return(TRUE);
+ }
+ }
+ }
+
+ /* no topics fit */
+
+ return(FALSE);
+}
+
+
+/*
+ * These are Request routines for supporting the system topic.
+ * Their behavior depends on the table contents.
+ */
+
+HDDEDATA SysReqTopics(
+HDDEDATA hDataOut) // data handle to add output data to.
+{
+ int iTopic, cb, cbOff;
+ LPDDETOPICTBL ptpc;
+
+ /*
+ * This code assumes SSI only contains the system topic.
+ */
+
+ cbOff = 0;
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ continue; // don't add systopic twice.
+ }
+ cb = lstrlen(ptpc->pszTopic);
+ hDataOut = DdeAddData(hDataOut, ptpc->pszTopic, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+ hDataOut = DdeAddData(hDataOut, SSI.topic[0].pszTopic,
+ (DWORD)lstrlen(SSI.topic[0].pszTopic) + 1, (DWORD)cbOff);
+
+ return(hDataOut);
+}
+
+
+
+HDDEDATA SysReqSysItems(
+HDDEDATA hDataOut)
+{
+ return(ReqItems(hDataOut, &SSI.topic[ITPC_SYSITEMS]));
+}
+
+
+/*
+ * Given a topic table, this function returns a tab delimited list of
+ * items supported under that topic.
+ */
+HDDEDATA ReqItems(
+HDDEDATA hDataOut,
+LPDDETOPICTBL ptpc)
+{
+ int cb, iItem, cbOff = 0;
+ LPDDEITEMTBL pitm;
+
+ /*
+ * return a list of all the items within this topic
+ */
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ cb = lstrlen(pitm->pszItem);
+ hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+
+ /*
+ * if this is for the System Topic, add to the list our default items.
+ */
+
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ ptpc = &SSI.topic[0];
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ cb = lstrlen(pitm->pszItem);
+ hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+ } else {
+ /*
+ * Add the standard TopicListItems and SysItem items.
+ */
+ cb = lstrlen(SSI.topic[0].item[ITPC_SYSITEMS].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_SYSITEMS].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+
+ cb = lstrlen(SSI.topic[0].item[ITPC_ITEMLIST].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_ITEMLIST].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+
+ cb = lstrlen(SSI.topic[0].item[ITPC_FORMATS].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_FORMATS].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+ hDataOut = DdeAddData(hDataOut, '\0', (DWORD)1, (DWORD)--cbOff);
+ return(hDataOut);
+}
+
+
+
+
+HDDEDATA SysReqFormats(
+HDDEDATA hDataOut)
+{
+ int iTopic, iItem, iFmt;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)"TEXT", 5, 0);
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
+ }
+ }
+ }
+ return(hDataOut);
+}
+
+
+
+HDDEDATA AddReqFormat(
+HDDEDATA hDataOut,
+LPSTR pszFmt)
+{
+ LPSTR pszList;
+ DWORD cbOff;
+
+ pszList = DdeAccessData(hDataOut, NULL);
+
+#if WIN16
+ if (_fstrstr(pszList, pszFmt) == NULL) {
+#else
+ if (strstr(pszList, pszFmt) == NULL) {
+#endif
+ cbOff = lstrlen(pszList);
+ DdeUnaccessData(hDataOut);
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, 1, cbOff++);
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)pszFmt, lstrlen(pszFmt) + 1, cbOff);
+ } else {
+ DdeUnaccessData(hDataOut);
+ }
+
+ return(hDataOut);
+}
+
+
+HDDEDATA ReqFormats(
+HDDEDATA hDataOut,
+LPDDETOPICTBL ptpc)
+{
+ int iItem, iFmt;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+
+ hDataOut = DdeAddData(hDataOut, "", 1, 0);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
+ }
+ }
+ return(hDataOut);
+}
+
+
+
+HDDEDATA DoWildConnect(
+HSZ hszTopic)
+{
+ LPDDETOPICTBL ptpc;
+ HDDEDATA hData;
+ PHSZPAIR pHszPair;
+ int iTopic, cTopics = 2;
+
+ if (!hszTopic) {
+ cTopics += pasi->cTopics;
+ }
+
+ hData = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ cTopics * sizeof(HSZPAIR),
+ 0,
+ 0,
+ 0,
+ 0);
+ pHszPair = (HSZPAIR FAR *)DdeAccessData(hData, NULL);
+ pHszPair->hszSvc = pasi->hszService;
+ pHszPair->hszTopic = SSI.topic[0].hszTopic; // always support systopic.
+ pHszPair++;
+ ptpc = &pasi->topic[0];
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ if (hszTopic && DdeCmpStringHandles(hszTopic, ptpc->hszTopic)) {
+ continue;
+ }
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ continue; // don't enter systopic twice.
+ }
+ pHszPair->hszSvc = pasi->hszService;
+ pHszPair->hszTopic = ptpc->hszTopic;
+ pHszPair++;
+ }
+ pHszPair->hszSvc = 0;
+ pHszPair->hszTopic = 0;
+ DdeUnaccessData(hData);
+ return(hData);
+}
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h
new file mode 100644
index 000000000..5cfbc261b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h
@@ -0,0 +1,80 @@
+/***************************************************************************\
+
+ MODULE : wrapper.h
+
+ PURPOSE : This is not a full program but a module you can include
+ in your code. It implements a standard DDEML callback
+ function that allows you to have most of your DDE table
+ driven. The default callback function handles all basic
+ System Topic information based on the tables you give
+ to this app.
+
+ LIMITATIONS : This only supports servers that:
+ have only one service name
+ have enumerable topics and items
+ do not change the topics or items they support over time.
+
+\***************************************************************************/
+
+
+/* TYPES */
+
+typedef BOOL (*CBFNIN)(HDDEDATA);
+typedef HDDEDATA (*CBFNOUT)(HDDEDATA);
+
+
+
+/* STRUCTURES */
+
+typedef struct _DDEFORMATTBL {
+ LPSTR pszFormat;
+ UINT wFmt;
+ UINT wFmtFlags;
+ CBFNIN lpfnPoke;
+ CBFNOUT lpfnRequest;
+} DDEFORMATTBL;
+typedef DDEFORMATTBL *PDDEFORMATTBL;
+typedef DDEFORMATTBL FAR *LPDDEFORMATTBL;
+
+typedef struct _DDEITEMTBL {
+ LPSTR pszItem;
+ HSZ hszItem;
+ UINT cFormats;
+ UINT wItemFlags;
+ LPDDEFORMATTBL fmt;
+} DDEITEMTBL;
+typedef DDEITEMTBL *PDDEITEMTBL;
+typedef DDEITEMTBL FAR *LPDDEITEMTBL;
+
+
+typedef struct _DDETOPICTBL {
+ LPSTR pszTopic;
+ HSZ hszTopic;
+ UINT cItems;
+ UINT wTopicFlags;
+ LPDDEITEMTBL item;
+ CBFNIN lpfnExecute;
+} DDETOPICTBL;
+typedef DDETOPICTBL *PDDETOPICTBL;
+typedef DDETOPICTBL FAR *LPDDETOPICTBL;
+
+typedef struct _DDESERVICETBL {
+ LPSTR pszService;
+ HSZ hszService;
+ UINT cTopics;
+ UINT wServiceFlags;
+ LPDDETOPICTBL topic;
+} DDESERVICETBL;
+typedef DDESERVICETBL *PDDESERVICETBL;
+typedef DDESERVICETBL FAR *LPDDESERVICETBL;
+
+
+
+/* PROTOTYPES */
+
+BOOL InitializeDDE(PFNCALLBACK lpfnCustomCallback, LPDWORD pidInst,
+ LPDDESERVICETBL AppSvcInfo, DWORD dwFilterFlags, HANDLE hInst);
+
+VOID UninitializeDDE(VOID);
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/clinit.c b/private/mvdm/wow16/ddeml/tests/src/client/clinit.c
new file mode 100644
index 000000000..ccc4c7616
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/clinit.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * *
+ * MODULE : clinit.c *
+ * *
+ * PURPOSE : Contains initialization code for Client *
+ * *
+ ***************************************************************************/
+
+#include "ddemlcl.h"
+
+char szFrame[] = "mpframe"; /* Class name for "frame" window */
+char szChild[] = "mpchild"; /* Class name for MDI window */
+char szList[] = "mplist"; /* Class name for MDI window */
+
+/****************************************************************************
+ * *
+ * FUNCTION : InitializeApplication () *
+ * *
+ * PURPOSE : Sets up the class data structures and does a one-time *
+ * initialization of the app by registering the window classes*
+ * Also registers the Link clipboard format *
+ * *
+ * RETURNS : TRUE - If successful. *
+ * FALSE - otherwise. *
+ * *
+ ****************************************************************************/
+
+BOOL FAR PASCAL InitializeApplication()
+{
+ WNDCLASS wc;
+
+ fmtLink = RegisterClipboardFormat("Link");
+
+ if (!fmtLink)
+ return FALSE;
+
+ /* Register the frame class */
+ wc.style = 0;
+ wc.lpfnWndProc = FrameWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInst;
+ wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDCLIENT));
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW);
+ wc.hbrBackground = COLOR_APPWORKSPACE+1;
+ wc.lpszMenuName = MAKEINTRESOURCE(IDCLIENT);
+ wc.lpszClassName = szFrame;
+
+ if (!RegisterClass (&wc) )
+ return FALSE;
+
+ /* Register the MDI child class */
+ wc.lpfnWndProc = MDIChildWndProc;
+ wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDCONV));
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = CHILDCBWNDEXTRA;
+ wc.lpszClassName = szChild;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ wc.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDLIST));
+ wc.lpszClassName = szList;
+
+ if (!RegisterClass(&wc))
+ return FALSE;
+
+ return TRUE;
+
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : InitializeInstance () *
+ * *
+ * PURPOSE : Performs a per-instance initialization of Client. *
+ * - Enlarges message queue to handle lots of DDE messages. *
+ * - Initializes DDEML for this app *
+ * - Creates atoms for our custom formats *
+ * - Creates the main frame window *
+ * - Loads accelerator table *
+ * - Shows main frame window *
+ * *
+ * RETURNS : TRUE - If initialization was successful. *
+ * FALSE - otherwise. *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL InitializeInstance(
+WORD nCmdShow)
+{
+ extern HWND hwndMDIClient;
+ char sz[80];
+ int i;
+
+ if (DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance(
+ (FARPROC)DdeCallback, hInst), APPCMD_CLIENTONLY, 0L))
+ return FALSE;
+
+ CCFilter.iCodePage = CP_WINANSI;
+
+ for (i = 0; i < CFORMATS; i++) {
+ if (aFormats[i].atom == 0)
+ aFormats[i].atom = RegisterClipboardFormat(aFormats[i].sz);
+ }
+
+ /* Get the base window title */
+ LoadString(hInst, IDS_APPNAME, sz, sizeof(sz));
+
+ /* Create the frame */
+ hwndFrame = CreateWindow (szFrame,
+ sz,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 400,
+ 200,
+ NULL,
+ NULL,
+ hInst,
+ NULL);
+
+ if (!hwndFrame || !hwndMDIClient)
+ return FALSE;
+
+ /* Load main menu accelerators */
+ if (!(hAccel = LoadAccelerators (hInst, MAKEINTRESOURCE(IDCLIENT))))
+ return FALSE;
+
+ /* Display the frame window */
+ ShowWindow (hwndFrame, nCmdShow);
+ UpdateWindow (hwndFrame);
+
+ /*
+ * We set this hook up so that we can catch the MSGF_DDEMGR filter
+ * which is called when DDEML is in a modal loop during synchronous
+ * transaction processing.
+ */
+ (FARPROC)lpMsgFilterProc = (FARPROC)MakeProcInstance((FARPROC)MyMsgFilterProc, hInst);
+ SetWindowsHook(WH_MSGFILTER, (FARPROC)lpMsgFilterProc);
+
+ return TRUE;
+}
+
+
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/conv.ico b/private/mvdm/wow16/ddeml/tests/src/client/conv.ico
new file mode 100644
index 000000000..d6fbe80df
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/conv.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/dde.c b/private/mvdm/wow16/ddeml/tests/src/client/dde.c
new file mode 100644
index 000000000..4c83d0218
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/dde.c
@@ -0,0 +1,644 @@
+/***************************************************************************
+ * *
+ * MODULE : dde.c *
+ * *
+ * PURPOSE : Contains routines for handling of DDE interaction with *
+ * DDEML. *
+ * *
+ ***************************************************************************/
+#include "ddemlcl.h"
+#include <string.h>
+#include <memory.h>
+#include "infoctrl.h"
+
+char szT[100];
+
+/****************************************************************************
+ * *
+ * FUNCTION : CreateXactionWindow() *
+ * *
+ * PURPOSE : Creates a transaction window for the given transaction *
+ * under the given conversation window. *
+ * *
+ * RETURNS : TRUE - If successful. *
+ * FALSE - otherwise. *
+ * *
+ ****************************************************************************/
+HWND CreateXactionWindow(
+HWND hwndMDI,
+XACT *pxact)
+{
+ PSTR pszFmt, pszItem;
+ PSTR pData;
+ HWND hwnd;
+
+ pszItem = GetHSZName(pxact->hszItem);
+ pszFmt = GetFormatName(pxact->wFmt);
+ pData = GetTextData(pxact->hDdeData);
+
+ /*
+ * レtype/optsトトトトトトト ITEM トトトトトトトトトトトトトトトretトソ GWW_WUSER=pxact
+ * ウ ウ
+ * ウ ウ
+ * ウ ウ
+ * ウ ウ
+ * ウ DATA ウ
+ * ウ ウ
+ * ウ ウ
+ * ウ ウ
+ * ウ ウ
+ * タstate/errorトトトトト FORMAT トトトトトトトトトトResultトル
+ */
+ hwnd = CreateInfoCtrl((LPSTR)pData,
+ (int)SendMessage(hwndMDI, UM_GETNEXTCHILDX, 0, 0L),
+ (int)SendMessage(hwndMDI, UM_GETNEXTCHILDY, 0, 0L),
+ 200, 100, hwndMDI, hInst,
+ Type2String(pxact->wType, pxact->fsOptions), pszItem, NULL,
+ "Starting", (LPSTR)pszFmt, NULL,
+ ICSTY_SHOWFOCUS, 0, (DWORD)(LPSTR)pxact);
+ MyFree(pszItem);
+ MyFree(pszFmt);
+ MyFree(pData);
+ return(hwnd);
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : ProcessTransaction() *
+ * *
+ * PURPOSE : Processes synchronous transactions entirely and starts *
+ * async transactions. Transaction attempts result in a *
+ * transaction window being created which displays the state *
+ * or results of the transaction. (the callback function *
+ * updates these windows as it gets calls) Transaction *
+ * windows stay around until abandoned by the user or until *
+ * the conversation is disconnected. Advise Data and Advise *
+ * Stop transactions are special. We don't create a new *
+ * window if the associated advise start transaction window *
+ * can be found. *
+ * *
+ * RETURNS : TRUE - If successful. *
+ * FALSE - otherwise. *
+ * *
+ ****************************************************************************/
+BOOL ProcessTransaction(
+XACT *pxact)
+{
+ CONVINFO ci;
+ HWND hwndInfoCtrl = 0;
+
+ /* create transaction window to show we tried (except in ADVSTOP case) */
+
+ pxact = (XACT *)memcpy(MyAlloc(sizeof(XACT)), (PSTR)pxact, sizeof(XACT));
+ ci.cb = sizeof(CONVINFO);
+ DdeQueryConvInfo(pxact->hConv, (DWORD)QID_SYNC, &ci); // ci.hUser==hConv
+ if (pxact->wType == XTYP_ADVSTOP) {
+ hwndInfoCtrl = FindAdviseChild((HWND)ci.hUser, pxact->hszItem,
+ pxact->wFmt);
+ if (hwndInfoCtrl) {
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UL,
+ (DWORD)(LPSTR)Type2String(pxact->wType, pxact->fsOptions));
+ DdeFreeStringHandle(idInst, pxact->hszItem);
+ }
+ }
+ /*
+ * If we still need to create a transaction window, do so here.
+ */
+ if (!hwndInfoCtrl) {
+ hwndInfoCtrl = CreateXactionWindow((HWND)ci.hUser, pxact);
+ if (!hwndInfoCtrl) {
+ MyFree(pxact);
+ return 0;
+ }
+ SetFocus(hwndInfoCtrl);
+ }
+ /*
+ * Disable callbacks for this conversation now if the XOPT_DISABLEFIRST
+ * option is set. This tests disabling asynchronous transactions
+ * before they are completed.
+ */
+ if (pxact->fsOptions & XOPT_DISABLEFIRST)
+ DdeEnableCallback(idInst, pxact->hConv, EC_DISABLE);
+ /*
+ * Adjust the timeout for asynchronous transactions.
+ */
+ if (pxact->fsOptions & XOPT_ASYNC)
+ pxact->ulTimeout = (DWORD)TIMEOUT_ASYNC;
+
+ /*
+ * start transaction with DDEML here
+ */
+ pxact->ret = DdeClientTransaction((LPBYTE)pxact->hDdeData, (DWORD)-1,
+ pxact->hConv, pxact->hszItem, pxact->wFmt,
+ pxact->wType,
+ pxact->ulTimeout, (LPDWORD)&pxact->Result);
+
+ /*
+ * show return value in transaction window
+ */
+ wsprintf(szT, "ret=%lx", pxact->ret);
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UR, (DWORD)(LPSTR)szT);
+
+ /*
+ * show result or ID value in transaction window
+ */
+ wsprintf(szT, pxact->fsOptions & XOPT_ASYNC ? "ID=%ld" :
+ "result=0x%lx", pxact->Result);
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LR, (DWORD)(LPSTR)szT);
+
+ if ((pxact->fsOptions & XOPT_ASYNC) && pxact->ret) {
+ /*
+ * asynchronous successful start - link transaction to window.
+ */
+ DdeSetUserHandle(pxact->hConv, pxact->Result, (DWORD)hwndInfoCtrl);
+
+ /*
+ * Abandon started async transaction after initiated if
+ * XOPT_ABANDONAFTERSTART is chosen. This tests the mid-transaction
+ * abandoning code.
+ */
+ if (pxact->fsOptions & XOPT_ABANDONAFTERSTART)
+ DdeAbandonTransaction(idInst, pxact->hConv, pxact->Result);
+ /*
+ * show actual status
+ */
+ ci.cb = sizeof(CONVINFO);
+ DdeQueryConvInfo(pxact->hConv, pxact->Result, &ci);
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
+ (DWORD)(LPSTR)State2String(ci.wConvst));
+ } else {
+ /*
+ * Synchronous transactions are completed already so pass on to
+ * CompleteTransaction right away.
+ */
+ CompleteTransaction(hwndInfoCtrl, pxact);
+ }
+ return TRUE;
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : CompleteTransaction() *
+ * *
+ * PURPOSE : This handles completed synchronous and asynchronous *
+ * transactions as well as failed attempted transactions. *
+ * *
+ * RETURNS : TRUE - If successful. *
+ * FALSE - otherwise. *
+ * *
+ ****************************************************************************/
+VOID CompleteTransaction(
+HWND hwndInfoCtrl,
+XACT *pxact)
+{
+ PSTR psz;
+
+ if (pxact->ret) {
+ /*
+ * Successful transaction case
+ */
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
+ (DWORD)(LPSTR)"Completed");
+
+ if (pxact->wType == XTYP_REQUEST) {
+ /*
+ * Show resulting data
+ */
+ psz = GetTextData((HDDEDATA)pxact->ret);
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_CENTER,
+ (DWORD)(LPSTR)psz);
+ MyFree(psz);
+ /*
+ * free returned data since it is displayed.
+ */
+ DdeFreeDataHandle(pxact->ret);
+ pxact->ret = 0L;
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_UR, NULL);
+ }
+ } else {
+ /*
+ * failed - show error result.
+ */
+ SendMessage(hwndInfoCtrl, ICM_SETSTRING, ICSID_LL,
+ (DWORD)(LPSTR)Error2String(DdeGetLastError(idInst)));
+ }
+ pxact->fsOptions |= XOPT_COMPLETED;
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : DdeCallback() *
+ * *
+ * PURPOSE : This handles all callbacks from the DDEML. This handles *
+ * updating of the associated conversation and any special *
+ * testing cases such as blocking callbacks etc. *
+ * *
+ * For the most part, clients only handle advise data and *
+ * asynchronous transaction completion here. *
+ * *
+ * RETURNS : Results vary depending on transaction type. *
+ * *
+ ****************************************************************************/
+HDDEDATA EXPENTRY DdeCallback(
+WORD wType,
+WORD wFmt,
+HCONV hConv,
+HSZ hsz1,
+HSZ hsz2,
+HDDEDATA hData,
+DWORD lData1,
+DWORD lData2)
+{
+ HWND hwnd;
+ CONVINFO ci;
+ XACT *pxact;
+
+ if (hConv) {
+ /*
+ * update conversation status if it changed.
+ */
+ MYCONVINFO *pmci;
+
+ ci.cb = sizeof(CONVINFO);
+ if (!DdeQueryConvInfo(hConv,(DWORD) QID_SYNC, &ci) || (!IsWindow((HWND)ci.hUser))) {
+ /*
+ * This conversation does not yet have a corresponding MDI window
+ * or is disconnected.
+ */
+ return 0;
+ }
+ if (pmci = (MYCONVINFO *)GetWindowWord((HWND)ci.hUser, 0)) {
+ if (pmci->ci.wStatus != ci.wStatus ||
+ pmci->ci.wConvst != ci.wConvst ||
+ pmci->ci.wLastError != ci.wLastError) {
+ /*
+ * Things have changed, updated the conversation window.
+ */
+ InvalidateRect((HWND)ci.hUser, NULL, TRUE);
+ }
+ if (ci.wConvst & ST_INLIST) {
+ /*
+ * update the associated list window (if any) as well.
+ */
+ if (hwnd = FindListWindow(ci.hConvList))
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ }
+ }
+
+ /*
+ * handle special block on next callback option here. This demonstrates
+ * the CBR_BLOCK feature.
+ */
+ if (fBlockNextCB && !(wType & XTYPF_NOBLOCK)) {
+ fBlockNextCB = FALSE;
+ return(CBR_BLOCK);
+ }
+
+ /*
+ * handle special termination here. This demonstrates that at any time
+ * a client can drop a conversation.
+ */
+ if (fTermNextCB && hConv && wType != XTYP_DISCONNECT) {
+ fTermNextCB = FALSE;
+ MyDisconnect(hConv);
+ return(0);
+ }
+
+ /*
+ * Now we begin sort out what to do.
+ */
+ switch (wType) {
+ case XTYP_REGISTER:
+ case XTYP_UNREGISTER:
+ /*
+ * This is where the client would insert code to keep track of
+ * what servers are available. This could cause the initiation
+ * of some conversations.
+ */
+ break;
+
+ case XTYP_DISCONNECT:
+ if (fAutoReconnect) {
+ /*
+ * attempt a reconnection
+ */
+ if (hConv = DdeReconnect(hConv)) {
+ AddConv(ci.hszServiceReq, ci.hszTopic, hConv, FALSE);
+ return 0;
+ }
+ }
+
+ /*
+ * update conv window to show its new state.
+ */
+ SendMessage((HWND)ci.hUser, UM_DISCONNECTED, 0, 0);
+ return 0;
+ break;
+
+ case XTYP_ADVDATA:
+ /*
+ * data from an active advise loop (from a server)
+ */
+ Delay(wDelay);
+ hwnd = FindAdviseChild((HWND)ci.hUser, hsz2, wFmt);
+ if (!IsWindow(hwnd)) {
+ PSTR pszItem, pszFmt;
+ /*
+ * AdviseStart window is gone, make a new one.
+ */
+ pxact = (XACT *)MyAlloc(sizeof(XACT));
+ pxact->wType = wType;
+ pxact->hConv = hConv;
+ pxact->wFmt = wFmt;
+ pxact->hszItem = hsz2;
+ DdeKeepStringHandle(idInst, hsz2);
+
+ pszItem = GetHSZName(hsz2);
+ pszFmt = GetFormatName(wFmt);
+
+ hwnd = CreateInfoCtrl(NULL,
+ (int)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDX, 0, 0L),
+ (int)SendMessage((HWND)ci.hUser, UM_GETNEXTCHILDY, 0, 0L),
+ 200, 100,
+ (HWND)ci.hUser, hInst,
+ Type2String(wType, 0), (LPSTR)pszItem, NULL,
+ NULL, (LPSTR)pszFmt, NULL,
+ ICSTY_SHOWFOCUS, 0, (DWORD)(LPSTR)pxact);
+
+ MyFree(pszFmt);
+ MyFree(pszItem);
+
+ if (!IsWindow(hwnd))
+ return(DDE_FNOTPROCESSED);
+ }
+ if (!hData) {
+ /*
+ * XTYPF_NODATA case - request the info. (we do this synchronously
+ * for simplicity)
+ */
+ hData = DdeClientTransaction(NULL, 0L, hConv, hsz2, wFmt,
+ XTYP_REQUEST, DefTimeout, NULL);
+ }
+ if (hData) {
+ PSTR pData;
+ /*
+ * Show incomming data on corresponding transaction window.
+ */
+ pData = GetTextData(hData);
+ SendMessage(hwnd, ICM_SETSTRING, ICSID_CENTER, (DWORD)(LPSTR)pData);
+ MyFree(pData);
+ DdeFreeDataHandle(hData);
+ }
+ SendMessage(hwnd, ICM_SETSTRING, ICSID_LL, (DWORD)(LPSTR)"Advised");
+ return(DDE_FACK);
+ break;
+
+ case XTYP_XACT_COMPLETE:
+ /*
+ * An asynchronous transaction has completed. Show the results.
+ *
+ * ...unless the XOPT_BLOCKRESULT is chosen.
+ */
+
+ ci.cb = sizeof(CONVINFO);
+ if (DdeQueryConvInfo(hConv, lData1, &ci) &&
+ IsWindow((HWND)ci.hUser) &&
+ (pxact = (XACT *)GetWindowWord((HWND)ci.hUser, GWW_WUSER))) {
+
+ if (pxact->fsOptions & XOPT_BLOCKRESULT) {
+ pxact->fsOptions &= ~XOPT_BLOCKRESULT;
+ return(CBR_BLOCK);
+ }
+
+ pxact->Result = lData2;
+ pxact->ret = hData;
+ CompleteTransaction((HWND)ci.hUser, pxact);
+ }
+ break;
+ }
+}
+
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : FindAdviseChild() *
+ * *
+ * PURPOSE : Search through the child windows of hwndMDI for an info *
+ * ctrl that has the same Item and format and is an *
+ * ADVSTART ADVSTOP or ADVDATA transaction window. *
+ * *
+ * We use these to show the associated advise data. *
+ * *
+ * RETURNS : The transaction window handle or 0 on failure. *
+ * *
+ ****************************************************************************/
+HWND FindAdviseChild(
+HWND hwndMDI,
+HSZ hszItem,
+WORD wFmt)
+{
+ HWND hwnd, hwndStart;
+ XACT *pxact;
+
+ if (!IsWindow(hwndMDI))
+ return 0;
+
+ hwnd = hwndStart = GetWindow(hwndMDI, GW_CHILD);
+ while (hwnd && IsChild(hwndMDI, hwnd)) {
+ pxact = (XACT *)GetWindowWord(hwnd, GWW_WUSER);
+ if (pxact &&
+ (pxact)->wFmt == wFmt &&
+ (pxact)->hszItem == hszItem &&
+ (
+ ((pxact->wType & XTYP_ADVSTART) == XTYP_ADVSTART) ||
+ (pxact->wType == XTYP_ADVSTOP) ||
+ (pxact->wType == XTYP_ADVDATA)
+ )
+ ) {
+ return(hwnd);
+ }
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+ if (hwnd == hwndStart)
+ return 0;
+ }
+ return 0;
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : FindListWindow() *
+ * *
+ * PURPOSE : Locates the list window associated with this conversation *
+ * list. *
+ * *
+ * RETURNS : The window handle of the list window or 0 on failure. *
+ * *
+ ****************************************************************************/
+HWND FindListWindow(
+HCONVLIST hConvList)
+{
+ HWND hwnd;
+ MYCONVINFO *pmci;
+
+ hwnd = GetWindow(hwndMDIClient, GW_CHILD);
+ while (hwnd) {
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ if (pmci->fList && pmci->hConv == hConvList)
+ return(hwnd);
+ hwnd = GetWindow(hwnd, GW_HWNDNEXT);
+ }
+ return 0;
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetTextData() *
+ * *
+ * PURPOSE : Allocates and returns a pointer to the data contained in *
+ * hData. This assumes that hData points to text data and *
+ * will properly handle huge text data by leaving out the *
+ * middle of the string and placing the size of the string *
+ * into this string portion. *
+ * *
+ * RETURNS : A pointer to the allocated string. *
+ * *
+ ****************************************************************************/
+PSTR GetTextData(
+HDDEDATA hData)
+{
+ PSTR psz;
+ DWORD cb;
+
+#define CBBUF 1024
+
+ if (hData == NULL) {
+ return(NULL);
+ }
+
+ cb = DdeGetData(hData, NULL, 0, 0);
+ if (!hData || !cb)
+ return NULL;
+
+ if (cb > CBBUF) { // possibly HUGE object!
+ psz = MyAlloc(CBBUF);
+ DdeGetData(hData, psz, CBBUF - 46, 0L);
+ wsprintf(&psz[CBBUF - 46], "<---Size=%ld", cb);
+ } else {
+ psz = MyAlloc((WORD)cb);
+ DdeGetData(hData, (LPBYTE)psz, cb, 0L);
+ }
+ return psz;
+#undef CBBUF
+}
+
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MyGetClipboardFormatName() *
+ * *
+ * PURPOSE : Properly retrieves the string associated with a clipboard *
+ * format. If the format does not have a string associated *
+ * with it, the string #dddd is returned. *
+ * *
+ * RETURNS : The number of characters copied into lpstr or 0 on error. *
+ * *
+ ****************************************************************************/
+int MyGetClipboardFormatName(
+WORD fmt,
+LPSTR lpstr,
+int cbMax)
+{
+ if (fmt < 0xc000) {
+ // predefined or integer format - just get the atom string
+ // wierdly enough, GetClipboardFormatName() doesn't support this.
+ return(GlobalGetAtomName(fmt, lpstr, cbMax));
+ } else {
+ return(GetClipboardFormatName(fmt, lpstr, cbMax));
+ }
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetFormatName() *
+ * *
+ * PURPOSE : allocates and returns a pointer to a string representing *
+ * a format. Use MyFree() to free this string. *
+ * *
+ * RETURNS : The number of characters copied into lpstr or 0 on error. *
+ * *
+ ****************************************************************************/
+PSTR GetFormatName(
+WORD wFmt)
+{
+ PSTR psz;
+ WORD cb;
+
+ if (wFmt == 1) {
+ psz = MyAlloc(8);
+ strcpy(psz, "CF_TEXT");
+ return psz;
+ }
+ psz = MyAlloc(255);
+ *psz = '\0';
+ cb = GetClipboardFormatName(wFmt, psz, 255) + 1;
+ return((PSTR)LocalReAlloc((HANDLE)psz, cb, LMEM_MOVEABLE));
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MyDisconnect() *
+ * *
+ * PURPOSE : Disconnects the given conversation after updating the *
+ * associated conversation window. *
+ * *
+ * RETURNS : TRUE on success, FALSE on failuer. *
+ * *
+ ****************************************************************************/
+BOOL MyDisconnect(
+HCONV hConv)
+{
+ CONVINFO ci;
+ HWND hwnd;
+ // before we disconnect, invalidate the associated list window - if
+ // applicable.
+
+ ci.cb = sizeof(CONVINFO);
+
+ if (DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci) && ci.hConvList &&
+ (hwnd = FindListWindow(ci.hConvList)))
+ InvalidateRect(hwnd, NULL, TRUE);
+ return(DdeDisconnect(hConv));
+}
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.c b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.c
new file mode 100644
index 000000000..376635f7d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.c
@@ -0,0 +1,1235 @@
+/***************************************************************************
+ * *
+ * PROGRAM : ddemlcl.c *
+ * *
+ * PURPOSE : To demonstrate how to use the DDEML library from the *
+ * client side and for basic testing of the DDEML API. *
+ * *
+ ***************************************************************************/
+
+#include "ddemlcl.h"
+#include <string.h>
+#include <memory.h>
+#include "infoctrl.h"
+
+/* global variables used in this module or among more than one module */
+CONVCONTEXT CCFilter = { sizeof(CONVCONTEXT), 0, 0, 0, 0L, 0L };
+DWORD idInst = 0;
+HANDLE hInst; /* Program instance handle */
+HANDLE hAccel; /* Main accelerator resource */
+HWND hwndFrame = NULL; /* Handle to main window */
+HWND hwndMDIClient = NULL; /* Handle to MDI client */
+HWND hwndActive = NULL; /* Handle to currently activated child */
+LONG DefTimeout = DEFTIMEOUT; /* default synchronous transaction timeout */
+WORD wDelay = 0;
+BOOL fBlockNextCB = FALSE; /* set if next callback causes a CBR_BLOCK */
+BOOL fTermNextCB = FALSE; /* set to call DdeDisconnect() on next callback */
+BOOL fAutoReconnect = FALSE; /* set if DdeReconnect() is to be called on XTYP_DISCONNECT callbacks */
+WORD fmtLink = 0; /* link clipboard format number */
+WORD DefOptions = 0; /* default transaction optons */
+OWNED aOwned[MAX_OWNED]; /* list of all owned handles. */
+WORD cOwned = 0; /* number of existing owned handles. */
+FILTERPROC *lpMsgFilterProc; /* instance proc from MSGF_DDEMGR filter */
+
+
+ /*
+ * This is the array of formats we support
+ */
+FORMATINFO aFormats[] = {
+ { CF_TEXT, "CF_TEXT" }, // exception! predefined format
+ { 0, "Dummy1" },
+ { 0, "Dummy2" },
+};
+
+/* Forward declarations of helper functions in this module */
+VOID NEAR PASCAL CloseAllChildren(VOID);
+VOID NEAR PASCAL InitializeMenu (HANDLE);
+VOID NEAR PASCAL CommandHandler (HWND,WORD);
+VOID NEAR PASCAL SetWrap (HWND,BOOL);
+
+/****************************************************************************
+ * *
+ * FUNCTION : WinMain(HANDLE, HANDLE, LPSTR, int) *
+ * *
+ * PURPOSE : Creates the "frame" window, does some initialization and *
+ * enters the message loop. *
+ * *
+ ****************************************************************************/
+int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
+
+HANDLE hInstance;
+HANDLE hPrevInstance;
+LPCSTR lpszCmdLine;
+int nCmdShow;
+{
+ MSG msg;
+
+ hInst = hInstance;
+
+ /* If this is the first instance of the app. register window classes */
+ if (!hPrevInstance){
+ if (!InitializeApplication ())
+ return 0;
+ }
+
+ /* Create the frame and do other initialization */
+ if (!InitializeInstance(nCmdShow))
+ return 0;
+
+ /* Enter main message loop */
+ while (GetMessage (&msg, NULL, 0, 0)){
+ (*lpMsgFilterProc)(MSGF_DDEMGR, 0, (LONG)(LPMSG)&msg);
+ }
+
+ // free up any appowned handles
+ while (cOwned) {
+ DdeFreeDataHandle(aOwned[--cOwned].hData);
+ }
+ DdeUninitialize(idInst);
+
+ UnhookWindowsHook(WH_MSGFILTER, (FARPROC)lpMsgFilterProc);
+ FreeProcInstance((FARPROC)lpMsgFilterProc);
+
+ return 0;
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : FrameWndProc (hwnd, msg, wParam, lParam ) *
+ * *
+ * PURPOSE : The window function for the "frame" window, which controls *
+ * the menu and encompasses all the MDI child windows. Does *
+ * the major part of the message processing. Specifically, in *
+ * response to: *
+ * *
+ ****************************************************************************/
+LONG FAR PASCAL FrameWndProc ( hwnd, msg, wParam, lParam )
+
+register HWND hwnd;
+UINT msg;
+register WPARAM wParam;
+LPARAM lParam;
+
+{
+ switch (msg){
+ case WM_CREATE:{
+ CLIENTCREATESTRUCT ccs;
+
+ /* Find window menu where children will be listed */
+ ccs.hWindowMenu = GetSubMenu (GetMenu(hwnd),WINDOWMENU);
+ ccs.idFirstChild = IDM_WINDOWCHILD;
+
+ /* Create the MDI client filling the client area */
+ hwndMDIClient = CreateWindow ("mdiclient",
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN |
+ WS_VSCROLL | WS_HSCROLL,
+ 0,
+ 0,
+ 0,
+ 0,
+ hwnd,
+ 0xCAC,
+ hInst,
+ (LPSTR)&ccs);
+
+
+ ShowWindow (hwndMDIClient,SW_SHOW);
+ break;
+ }
+
+ case WM_INITMENU:
+ InitializeMenu ((HMENU)wParam);
+ break;
+
+ case WM_COMMAND:
+ CommandHandler (hwnd,wParam);
+ break;
+
+ case WM_CLOSE:
+ CloseAllChildren();
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ /* use DefFrameProc() instead of DefWindowProc() since there
+ * are things that have to be handled differently because of MDI
+ */
+ return DefFrameProc (hwnd,hwndMDIClient,msg,wParam,lParam);
+ }
+ return 0;
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MDIChildWndProc *
+ * *
+ * PURPOSE : The window function for the "child" conversation and list *
+ * windows. *
+ * *
+ ****************************************************************************/
+LONG FAR PASCAL MDIChildWndProc( hwnd, msg, wParam, lParam )
+register HWND hwnd;
+UINT msg;
+register WPARAM wParam;
+LPARAM lParam;
+{
+ MYCONVINFO *pmci;
+ RECT rc;
+
+ switch (msg){
+ case WM_CREATE:
+ /*
+ * Create a coresponding conversation info structure to link this
+ * window to the conversation or conversation list it represents.
+ *
+ * lParam: points to the conversation info to initialize our copy to.
+ */
+ pmci = (MYCONVINFO *)MyAlloc(sizeof(MYCONVINFO));
+ if (pmci != NULL) {
+ _fmemcpy(pmci,
+ (LPSTR)((LPMDICREATESTRUCT)((LPCREATESTRUCT)lParam)->lpCreateParams)->lParam,
+ sizeof(MYCONVINFO));
+ pmci->hwndXaction = 0; /* no current transaction yet */
+ pmci->x = pmci->y = 0; /* new transaction windows start here */
+ DdeKeepStringHandle(idInst, pmci->hszTopic);/* keep copies of the hszs for us */
+ DdeKeepStringHandle(idInst, pmci->hszApp);
+
+ // link hConv and hwnd together
+ SetWindowWord(hwnd, 0, (WORD)pmci);
+
+ /*
+ * non-list windows link the conversations to the windows via the
+ * conversation user handle.
+ */
+ if (!pmci->fList)
+ DdeSetUserHandle(pmci->hConv, (DWORD)QID_SYNC, (DWORD)hwnd);
+ }
+ goto CallDCP;
+ break;
+
+ case UM_GETNEXTCHILDX:
+ case UM_GETNEXTCHILDY:
+ /*
+ * Calculate the next place to put the next transaction window.
+ */
+ {
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ GetClientRect(hwnd, &rc);
+ if (msg == UM_GETNEXTCHILDX) {
+ pmci->x += 14;
+ if (pmci->x > (rc.right - 200 - rc.left))
+ pmci->x = 0;
+ return(pmci->x);
+ } else {
+ pmci->y += 12;
+ if (pmci->y > (rc.bottom - 100 - rc.top))
+ pmci->y = 0;
+ return(pmci->y);
+ }
+ }
+ break;
+
+ case UM_DISCONNECTED:
+ /*
+ * Disconnected conversations can't have any transactions so we
+ * remove all the transaction windows here to show whats up.
+ */
+ {
+ HWND hwndT;
+ while (hwndT = GetWindow(hwnd, GW_CHILD))
+ DestroyWindow(hwndT);
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ break;
+
+ case WM_DESTROY:
+ /*
+ * Cleanup our conversation info structure, and disconnect all
+ * conversations associated with this window.
+ */
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ pmci->hwndXaction = 0; /* clear this to avoid focus problems */
+ if (pmci->hConv) {
+ if (pmci->fList) {
+ DdeDisconnectList((HCONVLIST)pmci->hConv);
+ } else {
+ MyDisconnect(pmci->hConv);
+ }
+ }
+ DdeFreeStringHandle(idInst, pmci->hszTopic);
+ DdeFreeStringHandle(idInst, pmci->hszApp);
+ MyFree(pmci);
+ goto CallDCP;
+ break;
+
+ case WM_SETFOCUS:
+ /*
+ * This catches focus changes caused by dialogs.
+ */
+ wParam = TRUE;
+ // fall through
+
+ case WM_MDIACTIVATE:
+ hwndActive = wParam ? hwnd : NULL;
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ /*
+ * pass the focus onto the current transaction window.
+ */
+ if (wParam && IsWindow(pmci->hwndXaction))
+ SetFocus(pmci->hwndXaction);
+ break;
+
+ case ICN_HASFOCUS:
+ /*
+ * update which transaction window is the main one.
+ */
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ pmci->hwndXaction = wParam ? HIWORD(lParam) : NULL;
+ break;
+
+ case ICN_BYEBYE:
+ /*
+ * Transaction window is closing...
+ *
+ * wParam = hwndXact
+ * lParam = lpxact
+ */
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ {
+ XACT *pxact;
+
+ pxact = (XACT *)LOWORD(lParam);
+ /*
+ * If this transaction is active, abandon it first.
+ */
+ if (pxact->fsOptions & XOPT_ASYNC &&
+ !(pxact->fsOptions & XOPT_COMPLETED)) {
+ DdeAbandonTransaction(idInst, pmci->hConv, pxact->Result);
+ }
+ /*
+ * release resources associated with transaction.
+ */
+ DdeFreeStringHandle(idInst, pxact->hszItem);
+ MyFree((PSTR)pxact);
+ /*
+ * Locate next apropriate transaction window to get focus.
+ */
+ if (!pmci->hwndXaction || pmci->hwndXaction == wParam)
+ pmci->hwndXaction = GetWindow(hwnd, GW_CHILD);
+ if (pmci->hwndXaction == wParam)
+ pmci->hwndXaction = GetWindow(wParam, GW_HWNDNEXT);
+ if (pmci->hwndXaction == wParam ||
+ !IsWindow(pmci->hwndXaction) ||
+ !IsChild(hwnd, pmci->hwndXaction))
+ pmci->hwndXaction = NULL;
+ else
+ SetFocus(pmci->hwndXaction);
+ }
+ break;
+
+ case WM_PAINT:
+ /*
+ * Paint this conversation's related information.
+ */
+ pmci = (MYCONVINFO *)GetWindowWord(hwnd, 0);
+ {
+ PAINTSTRUCT ps;
+ PSTR psz;
+
+ BeginPaint(hwnd, &ps);
+ SetBkMode(ps.hdc, TRANSPARENT);
+ psz = pmci->fList ? GetConvListText(pmci->hConv) :
+ GetConvInfoText(pmci->hConv, &pmci->ci);
+ if (psz) {
+ GetClientRect(hwnd, &rc);
+ DrawText(ps.hdc, psz, -1, &rc,
+ DT_WORDBREAK | DT_LEFT | DT_NOPREFIX | DT_TABSTOP);
+ MyFree(psz);
+ }
+ EndPaint(hwnd, &ps);
+ }
+ break;
+
+ case WM_QUERYENDSESSION:
+ return TRUE;
+
+ default:
+CallDCP:
+ /* Again, since the MDI default behaviour is a little different,
+ * call DefMDIChildProc instead of DefWindowProc()
+ */
+ return DefMDIChildProc (hwnd, msg, wParam, lParam);
+ }
+ return FALSE;
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : Initializemenu ( hMenu ) *
+ * *
+ * PURPOSE : Sets up greying, enabling and checking of main menu items *
+ * based on the app's state. *
+ * *
+ ****************************************************************************/
+VOID NEAR PASCAL InitializeMenu ( hmenu )
+register HANDLE hmenu;
+{
+ BOOL fLink = FALSE; // set if Link format is on the clipboard;
+ BOOL fAny = FALSE; // set if hwndActive exists
+ BOOL fList = FALSE; // set if hwndActive is a list window
+ BOOL fConnected = FALSE; // set if hwndActive is a connection conversation.
+ BOOL fXaction = FALSE; // set if hwndActive has a selected transaction window
+ BOOL fXactions = FALSE; // set if hwndActive contains transaction windows
+ BOOL fBlocked = FALSE; // set if hwndActive conversation is blocked.
+ BOOL fBlockNext = FALSE; // set if handActive conversation is blockNext.
+ MYCONVINFO *pmci = NULL;
+
+ if (OpenClipboard(hwndFrame)) {
+ fLink = (IsClipboardFormatAvailable(fmtLink));
+ CloseClipboard();
+ }
+
+ if (fAny = (IsWindow(hwndActive) &&
+ (pmci = (MYCONVINFO *)GetWindowWord(hwndActive, 0)))) {
+ fXactions = GetWindow(hwndActive, GW_CHILD);
+ if (!(fList = pmci->fList)) {
+ CONVINFO ci;
+
+ ci.cb = sizeof(CONVINFO);
+ DdeQueryConvInfo(pmci->hConv, (DWORD)QID_SYNC, &ci);
+ fConnected = (BOOL)(ci.wStatus & ST_CONNECTED);
+ fXaction = IsWindow(pmci->hwndXaction);
+ fBlocked = ci.wStatus & ST_BLOCKED;
+ fBlockNext = ci.wStatus & ST_BLOCKNEXT;
+ }
+ }
+
+ EnableMenuItem(hmenu, IDM_EDITPASTE,
+ fLink ? MF_ENABLED : MF_GRAYED);
+
+ // IDM_CONNECTED - always enabled.
+
+ EnableMenuItem(hmenu, IDM_RECONNECT,
+ fList ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_DISCONNECT,
+ fConnected ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_TRANSACT,
+ fConnected ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hmenu, IDM_ABANDON,
+ fXaction ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hmenu, IDM_ABANDONALL,
+ fXactions ? MF_ENABLED : MF_GRAYED);
+
+
+ EnableMenuItem (hmenu, IDM_BLOCKCURRENT,
+ fConnected && !fBlocked ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(hmenu, IDM_BLOCKCURRENT,
+ fBlocked ? MF_CHECKED : MF_UNCHECKED);
+
+ EnableMenuItem (hmenu, IDM_ENABLECURRENT,
+ fConnected && (fBlocked || fBlockNext) ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(hmenu, IDM_ENABLECURRENT,
+ !fBlocked ? MF_CHECKED : MF_UNCHECKED);
+
+ EnableMenuItem (hmenu, IDM_ENABLEONECURRENT,
+ fConnected && (fBlocked) ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(hmenu, IDM_ENABLEONECURRENT,
+ fBlockNext ? MF_CHECKED : MF_UNCHECKED);
+
+ EnableMenuItem (hmenu, IDM_BLOCKALLCBS,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_ENABLEALLCBS,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_ENABLEONECB,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hmenu, IDM_BLOCKNEXTCB,
+ fAny || fBlockNextCB ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(hmenu, IDM_BLOCKNEXTCB,
+ fBlockNextCB ? MF_CHECKED : MF_UNCHECKED);
+
+ EnableMenuItem(hmenu, IDM_TERMNEXTCB,
+ fAny || fTermNextCB ? MF_ENABLED : MF_GRAYED);
+ CheckMenuItem(hmenu, IDM_TERMNEXTCB,
+ fTermNextCB ? MF_CHECKED : MF_UNCHECKED);
+
+ // IDM_DELAY - always enabled.
+
+ // IDM_TIMEOUT - alwasy enabled.
+
+ EnableMenuItem (hmenu, IDM_WINDOWTILE,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_WINDOWCASCADE,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_WINDOWICONS,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_WINDOWCLOSEALL,
+ fAny ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_XACTTILE,
+ fXactions ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem (hmenu, IDM_XACTCASCADE,
+ fXactions ? MF_ENABLED : MF_GRAYED);
+
+ CheckMenuItem(hmenu, IDM_AUTORECONNECT,
+ fAutoReconnect ? MF_CHECKED : MF_UNCHECKED);
+
+ // IDM_HELPABOUT - always enabled.
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : CloseAllChildren () *
+ * *
+ * PURPOSE : Destroys all MDI child windows. *
+ * *
+ ****************************************************************************/
+VOID NEAR PASCAL CloseAllChildren ()
+{
+ register HWND hwndT;
+
+ /* hide the MDI client window to avoid multiple repaints */
+ ShowWindow(hwndMDIClient,SW_HIDE);
+
+ /* As long as the MDI client has a child, destroy it */
+ while ( hwndT = GetWindow (hwndMDIClient, GW_CHILD)){
+
+ /* Skip the icon title windows */
+ while (hwndT && GetWindow (hwndT, GW_OWNER))
+ hwndT = GetWindow (hwndT, GW_HWNDNEXT);
+
+ if (!hwndT)
+ break;
+
+ SendMessage(hwndMDIClient, WM_MDIDESTROY, (WORD)hwndT, 0L);
+ }
+
+ ShowWindow( hwndMDIClient, SW_SHOW);
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : CommandHandler () *
+ * *
+ * PURPOSE : Processes all "frame" WM_COMMAND messages. *
+ * *
+ ****************************************************************************/
+VOID NEAR PASCAL CommandHandler (
+register HWND hwnd,
+register WORD wParam)
+
+{
+ MYCONVINFO *pmci = NULL;
+
+ if (hwndActive)
+ pmci = (MYCONVINFO *)GetWindowWord(hwndActive, 0);
+
+ switch (wParam){
+ case IDM_EDITPASTE:
+ {
+ HANDLE hClipData;
+ LPSTR psz;
+ XACT xact;
+
+ if (OpenClipboard(hwnd)) {
+ if (hClipData = GetClipboardData(fmtLink)) {
+ if (psz = GlobalLock(hClipData)) {
+ /*
+ * Create a conversation with the link app and
+ * begin a request and advise start transaction.
+ */
+ xact.hConv = CreateConv(DdeCreateStringHandle(idInst, psz, NULL),
+ DdeCreateStringHandle(idInst, &psz[_fstrlen(psz) + 1], NULL),
+ FALSE, NULL);
+ if (xact.hConv) {
+ psz += _fstrlen(psz) + 1;
+ psz += _fstrlen(psz) + 1;
+ xact.ulTimeout = DefTimeout;
+ xact.wType = XTYP_ADVSTART;
+ xact.hDdeData = 0;
+ xact.wFmt = CF_TEXT;
+ xact.hszItem = DdeCreateStringHandle(idInst, psz, NULL);
+ xact.fsOptions = 0;
+ ProcessTransaction(&xact);
+ xact.wType = XTYP_REQUEST;
+ ProcessTransaction(&xact);
+ }
+ GlobalUnlock(hClipData);
+ }
+ }
+ CloseClipboard();
+ }
+ }
+ break;
+
+ case IDM_CONNECT:
+ case IDM_RECONNECT:
+ DoDialog(MAKEINTRESOURCE(IDD_CONNECT), ConnectDlgProc,
+ wParam == IDM_RECONNECT, FALSE);
+ break;
+
+ case IDM_DISCONNECT:
+ if (hwndActive) {
+ SendMessage(hwndMDIClient, WM_MDIDESTROY, (WORD)hwndActive, 0L);
+ }
+ break;
+
+ case IDM_TRANSACT:
+ if (DoDialog(MAKEINTRESOURCE(IDD_TRANSACT), TransactDlgProc,
+ (DWORD)(LPSTR)pmci->hConv, FALSE))
+ SetFocus(GetWindow(hwndActive, GW_CHILD));
+ break;
+
+ case IDM_ABANDON:
+ if (pmci != NULL && IsWindow(pmci->hwndXaction)) {
+ DestroyWindow(pmci->hwndXaction);
+ }
+ break;
+
+ case IDM_ABANDONALL:
+ DdeAbandonTransaction(idInst, pmci->hConv, NULL);
+ {
+ HWND hwndXaction;
+
+ hwndXaction = GetWindow(hwndActive, GW_CHILD);
+ while (hwndXaction) {
+ DestroyWindow(hwndXaction);
+ hwndXaction = GetWindow(hwndActive, GW_CHILD);
+ }
+ }
+ break;
+
+ case IDM_BLOCKCURRENT:
+ DdeEnableCallback(idInst, pmci->hConv, EC_DISABLE);
+ InvalidateRect(hwndActive, NULL, TRUE);
+ break;
+
+ case IDM_ENABLECURRENT:
+ DdeEnableCallback(idInst, pmci->hConv, EC_ENABLEALL);
+ InvalidateRect(hwndActive, NULL, TRUE);
+ break;
+
+ case IDM_ENABLEONECURRENT:
+ DdeEnableCallback(idInst, pmci->hConv, EC_ENABLEONE);
+ InvalidateRect(hwndActive, NULL, TRUE);
+ break;
+
+ case IDM_BLOCKALLCBS:
+ DdeEnableCallback(idInst, NULL, EC_DISABLE);
+ InvalidateRect(hwndMDIClient, NULL, TRUE);
+ break;
+
+ case IDM_ENABLEALLCBS:
+ DdeEnableCallback(idInst, NULL, EC_ENABLEALL);
+ InvalidateRect(hwndMDIClient, NULL, TRUE);
+ break;
+
+ case IDM_ENABLEONECB:
+ DdeEnableCallback(idInst, NULL, EC_ENABLEONE);
+ InvalidateRect(hwndMDIClient, NULL, TRUE);
+ break;
+
+ case IDM_BLOCKNEXTCB:
+ fBlockNextCB = !fBlockNextCB;
+ break;
+
+ case IDM_TERMNEXTCB:
+ fTermNextCB = !fTermNextCB;
+ break;
+
+ case IDM_DELAY:
+ DoDialog(MAKEINTRESOURCE(IDD_VALUEENTRY), DelayDlgProc, NULL,
+ TRUE);
+ break;
+
+ case IDM_TIMEOUT:
+ DoDialog(MAKEINTRESOURCE(IDD_VALUEENTRY), TimeoutDlgProc, NULL,
+ TRUE);
+ break;
+
+ case IDM_CONTEXT:
+ DoDialog(MAKEINTRESOURCE(IDD_CONTEXT), ContextDlgProc, NULL, TRUE);
+ break;
+
+ case IDM_AUTORECONNECT:
+ fAutoReconnect = !fAutoReconnect;
+ break;
+
+ /* The following are window commands - these are handled by the
+ * MDI Client.
+ */
+ case IDM_WINDOWTILE:
+ /* Tile MDI windows */
+ SendMessage (hwndMDIClient, WM_MDITILE, 0, 0L);
+ break;
+
+ case IDM_WINDOWCASCADE:
+ /* Cascade MDI windows */
+ SendMessage (hwndMDIClient, WM_MDICASCADE, 0, 0L);
+ break;
+
+ case IDM_WINDOWICONS:
+ /* Auto - arrange MDI icons */
+ SendMessage (hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
+ break;
+
+ case IDM_WINDOWCLOSEALL:
+ CloseAllChildren();
+ break;
+
+ case IDM_XACTTILE:
+ TileChildWindows(hwndActive);
+ break;
+
+ case IDM_XACTCASCADE:
+ CascadeChildWindows(hwndActive);
+ break;
+
+ case IDM_HELPABOUT:{
+ DoDialog(MAKEINTRESOURCE(IDD_ABOUT), AboutDlgProc, NULL, TRUE);
+ break;
+ }
+
+ default:
+ /*
+ * This is essential, since there are frame WM_COMMANDS generated
+ * by the MDI system for activating child windows via the
+ * window menu.
+ */
+ DefFrameProc(hwnd, hwndMDIClient, WM_COMMAND, wParam, 0L);
+ }
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MPError ( hwnd, flags, id, ...) *
+ * *
+ * PURPOSE : Flashes a Message Box to the user. The format string is *
+ * taken from the STRINGTABLE. *
+ * *
+ * RETURNS : Returns value returned by MessageBox() to the caller. *
+ * *
+ ****************************************************************************/
+short FAR CDECL MPError(hwnd, bFlags, id, ...)
+HWND hwnd;
+WORD bFlags;
+WORD id;
+{
+ char sz[160];
+ char szFmt[128];
+
+ LoadString (hInst, id, szFmt, sizeof (szFmt));
+ wvsprintf (sz, szFmt, (LPSTR)(&id + 1));
+ LoadString (hInst, IDS_APPNAME, szFmt, sizeof (szFmt));
+ return MessageBox (hwndFrame, sz, szFmt, bFlags);
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : CreateConv() *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+HCONV CreateConv(
+HSZ hszApp,
+HSZ hszTopic,
+BOOL fList,
+WORD *pError)
+{
+ HCONV hConv;
+ HWND hwndConv = 0;
+ CONVINFO ci;
+
+ if (fList) {
+ hConv = (HCONV)DdeConnectList(idInst, hszApp, hszTopic, NULL, &CCFilter);
+ } else {
+ hConv = DdeConnect(idInst, hszApp, hszTopic, &CCFilter);
+ }
+ if (hConv) {
+ if (fList) {
+ ci.hszSvcPartner = hszApp;
+ ci.hszTopic = hszTopic;
+ } else {
+ ci.cb = sizeof(CONVINFO);
+ DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci);
+ }
+ hwndConv = AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, fList);
+ // HSZs get freed when window dies.
+ }
+ if (!hwndConv) {
+ if (pError != NULL) {
+ *pError = DdeGetLastError(idInst);
+ }
+ DdeFreeStringHandle(idInst, hszApp);
+ DdeFreeStringHandle(idInst, hszTopic);
+ }
+ return(hConv);
+}
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : AddConv() *
+ * *
+ * PURPOSE : Creates an MDI window representing a conversation *
+ * (fList = FALSE) or a set of MID windows for the list of *
+ * conversations (fList = TRUE). *
+ * *
+ * EFFECTS : Sets the hUser for the conversation to the created MDI *
+ * child hwnd. Keeps the hszs if successful. *
+ * *
+ * RETURNS : created MDI window handle. *
+ * *
+ ****************************************************************************/
+HWND FAR PASCAL AddConv(
+HSZ hszApp, // these parameters MUST match the MYCONVINFO struct.
+HSZ hszTopic,
+HCONV hConv,
+BOOL fList)
+{
+ HWND hwnd;
+ MDICREATESTRUCT mcs;
+
+ if (fList) {
+ /*
+ * Create all child windows FIRST so we have info for list window.
+ */
+ CONVINFO ci;
+ HCONV hConvChild = 0;
+
+ ci.cb = sizeof(CONVINFO);
+ while (hConvChild = DdeQueryNextServer((HCONVLIST)hConv, hConvChild)) {
+ if (DdeQueryConvInfo(hConvChild, (DWORD)QID_SYNC, &ci)) {
+ AddConv(ci.hszSvcPartner, ci.hszTopic, hConvChild, FALSE);
+ }
+ }
+ }
+
+ mcs.szTitle = GetConvTitleText(hConv, hszApp, hszTopic, fList);
+
+ mcs.szClass = fList ? szList : szChild;
+ mcs.hOwner = hInst;
+ mcs.x = mcs.cx = CW_USEDEFAULT;
+ mcs.y = mcs.cy = CW_USEDEFAULT;
+ mcs.style = GetWindow(hwndMDIClient, GW_CHILD) ? 0L : WS_MAXIMIZE;
+ mcs.lParam = (DWORD)(LPSTR)&fList - 2; // -2 for hwndXaction field
+ hwnd = (WORD)SendMessage (hwndMDIClient, WM_MDICREATE, 0,
+ (LONG)(LPMDICREATESTRUCT)&mcs);
+
+ MyFree((PSTR)(DWORD)mcs.szTitle);
+
+ return hwnd;
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetConvListText() *
+ * *
+ * RETURN : Returns a ponter to a string containing a list of *
+ * conversations contained in the given hConvList freeable *
+ * by MyFree(); *
+ * *
+ ****************************************************************************/
+PSTR GetConvListText(
+HCONVLIST hConvList)
+{
+ HCONV hConv = 0;
+ WORD cConv = 0;
+ CONVINFO ci;
+ WORD cb = 0;
+ char *psz, *pszStart;
+
+ ci.cb = sizeof(CONVINFO);
+
+ // find out size needed.
+
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+ if (DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci)) {
+ if (!IsWindow((HWND)ci.hUser)) {
+ if (ci.wStatus & ST_CONNECTED) {
+ /*
+ * This conversation doesn't have a corresponding
+ * MDI window. This is probably due to a reconnection.
+ */
+ ci.hUser = AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, FALSE);
+ } else {
+ continue; // skip this guy - he was closed locally.
+ }
+ }
+ cb += GetWindowTextLength((HWND)ci.hUser);
+ if (cConv++)
+ cb += 2; // room for CRLF
+ }
+ }
+ cb++; // for terminator.
+
+ // allocate and fill
+
+ if (pszStart = psz = MyAlloc(cb)) {
+ *psz = '\0';
+ hConv = 0;
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+ if (DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci) &&
+ IsWindow((HWND)ci.hUser)) {
+ psz += GetWindowText((HWND)ci.hUser, psz, cb);
+ if (--cConv) {
+ *psz++ = '\r';
+ *psz++ = '\n';
+ }
+ }
+ }
+ }
+ return(pszStart);
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetConvInfoText() *
+ * *
+ * PURPOSE : Returns a pointer to a string that reflects a *
+ * conversation's information. Freeable by MyFree(); *
+ * *
+ ****************************************************************************/
+PSTR GetConvInfoText(
+HCONV hConv,
+CONVINFO *pci)
+{
+ PSTR psz;
+ PSTR szApp;
+
+ psz = MyAlloc(300);
+ pci->cb = sizeof(CONVINFO);
+ if (hConv) {
+ if (!DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, (PCONVINFO)pci)) {
+ strcpy(psz, "State=Disconnected");
+ return(psz);
+ }
+ szApp = GetHSZName(pci->hszServiceReq);
+ wsprintf(psz,
+ "hUser=0x%lx\r\nhConvPartner=0x%lx\r\nhszServiceReq=%s\r\nStatus=%s\r\nState=%s\r\nLastError=%s",
+ pci->hUser, pci->hConvPartner, (LPSTR)szApp,
+ (LPSTR)Status2String(pci->wStatus),
+ (LPSTR)State2String(pci->wConvst),
+ (LPSTR)Error2String(pci->wLastError));
+ MyFree(szApp);
+ } else {
+ strcpy(psz, Error2String(DdeGetLastError(idInst)));
+ }
+ return(psz);
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetConvTitleText() *
+ * *
+ * PURPOSE : Creates standard window title text based on parameters. *
+ * *
+ * RETURNS : psz freeable by MyFree() *
+ * *
+ ****************************************************************************/
+PSTR GetConvTitleText(
+HCONV hConv,
+HSZ hszApp,
+HSZ hszTopic,
+BOOL fList)
+{
+ WORD cb;
+ PSTR psz;
+
+ cb = (WORD)DdeQueryString(idInst, hszApp, NULL, 0, 0) +
+ (WORD)DdeQueryString(idInst, hszTopic, (LPSTR)NULL, 0, 0) +
+ (fList ? 30 : 20);
+
+ if (psz = MyAlloc(cb)) {
+ DdeQueryString(idInst, hszApp, psz, cb, 0);
+ strcat(psz, "|");
+ DdeQueryString(idInst, hszTopic, &psz[strlen(psz)], cb, 0);
+ if (fList)
+ strcat(psz, " - LIST");
+ wsprintf(&psz[strlen(psz)], " - (%lx)", hConv);
+ }
+ return(psz);
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : Status2String() *
+ * *
+ * PURPOSE : Converts a conversation status word to a string and *
+ * returns a pointer to that string. The string is valid *
+ * till the next call to this function. *
+ * *
+ ****************************************************************************/
+PSTR Status2String(
+WORD status)
+{
+ WORD c, i;
+ static char szStatus[6 * 18];
+ static struct {
+ char *szStatus;
+ WORD status;
+ } s2s[] = {
+ { "Connected" , ST_CONNECTED },
+ { "Advise" , ST_ADVISE },
+ { "IsLocal" , ST_ISLOCAL },
+ { "Blocked" , ST_BLOCKED },
+ { "Client" , ST_CLIENT },
+ { "Disconnected" , ST_TERMINATED },
+ { "BlockNext" , ST_BLOCKNEXT },
+ };
+#define CFLAGS 7
+ szStatus[0] = '\0';
+ c = 0;
+ for (i = 0; i < CFLAGS; i++) {
+ if (status & s2s[i].status) {
+ if (c++)
+ strcat(szStatus, " | ");
+ strcat(szStatus, s2s[i].szStatus);
+ }
+ }
+ return szStatus;
+#undef CFLAGS
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : State2String() *
+ * *
+ * PURPOSE : converts a conversation state word to a string and *
+ * returns a pointer to that string. The string is valid *
+ * till the next call to this routine. *
+ * *
+ ****************************************************************************/
+PSTR State2String(
+WORD state)
+{
+ static char *s2s[] = {
+ "NULL" ,
+ "Incomplete" ,
+ "Standby" ,
+ "Initiating" ,
+ "ReqSent" ,
+ "DataRcvd" ,
+ "PokeSent" ,
+ "PokeAckRcvd" ,
+ "ExecSent" ,
+ "ExecAckRcvd" ,
+ "AdvSent" ,
+ "UnadvSent" ,
+ "AdvAckRcvd" ,
+ "UnadvAckRcvd" ,
+ "AdvDataSent" ,
+ "AdvDataAckRcvd" ,
+ "?" , // 16
+ };
+
+ if (state >= 17)
+ return s2s[17];
+ else
+ return s2s[state];
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : Error2String() *
+ * *
+ * PURPOSE : Converts an error code to a string and returns a pointer *
+ * to that string. The string is valid until the next call *
+ * to this function. *
+ * *
+ ****************************************************************************/
+PSTR Error2String(
+WORD error)
+{
+ static char szErr[23];
+ static char *e2s[] = {
+ "Advacktimeout" ,
+ "Busy" ,
+ "Dataacktimeout" ,
+ "Dll_not_initialized" ,
+ "Dll_usage" ,
+ "Execacktimeout" ,
+ "Invalidparameter" ,
+ "Low Memory warning" ,
+ "Memory_error" ,
+ "Notprocessed" ,
+ "No_conv_established" ,
+ "Pokeacktimeout" ,
+ "Postmsg_failed" ,
+ "Reentrancy" ,
+ "Server_died" ,
+ "Sys_error" ,
+ "Unadvacktimeout" ,
+ "Unfound_queue_id" ,
+ };
+ if (!error) {
+ strcpy(szErr, "0");
+ } else if (error > DMLERR_LAST || error < DMLERR_FIRST) {
+ strcpy(szErr, "???");
+ } else {
+ strcpy(szErr, e2s[error - DMLERR_FIRST]);
+ }
+ return(szErr);
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : Type2String() *
+ * *
+ * PURPOSE : Converts a wType word and fsOption flags to a string and *
+ * returns a pointer to that string. the string is valid *
+ * until the next call to this function. *
+ * *
+ ****************************************************************************/
+PSTR Type2String(
+WORD wType,
+WORD fsOptions)
+{
+ static char sz[30];
+ static char o2s[] = "^!#$X*<?";
+ static char *t2s[] = {
+ "" ,
+ "AdvData" ,
+ "AdvReq" ,
+ "AdvStart" ,
+ "AdvStop" ,
+ "Execute" ,
+ "Connect" ,
+ "ConnectConfirm" ,
+ "XactComplete" ,
+ "Poke" ,
+ "Register" ,
+ "Request" ,
+ "Term" ,
+ "Unregister" ,
+ "WildConnect" ,
+ "" ,
+ };
+ WORD bit, c, i;
+
+ strcpy(sz, t2s[((wType & XTYP_MASK) >> XTYP_SHIFT)]);
+ c = strlen(sz);
+ sz[c++] = ' ';
+ for (i = 0, bit = 1; i < 7; bit = bit << 1, i++) {
+ if (fsOptions & bit)
+ sz[c++] = o2s[i];
+ }
+ sz[c] = '\0';
+ return(sz);
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : GetHSZName() *
+ * *
+ * PURPOSE : Allocates local memory for and retrieves the string form *
+ * of an HSZ. Returns a pointer to the local memory or NULL *
+ * if failure. The string must be freed via MyFree(). *
+ * *
+ ****************************************************************************/
+PSTR GetHSZName(
+HSZ hsz)
+{
+ PSTR psz;
+ WORD cb;
+
+ cb = (WORD)DdeQueryString(idInst, hsz, NULL, 0, 0) + 1;
+ psz = MyAlloc(cb);
+ DdeQueryString(idInst, hsz, psz, cb, 0);
+ return(psz);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION : MyMsgFilterProc
+ *
+ * PURPOSE : This filter proc gets called for each message we handle.
+ * This allows our application to properly dispatch messages
+ * that we might not otherwise see because of DDEMLs modal
+ * loop that is used while processing synchronous transactions.
+ *
+ * Generally, applications that only do synchronous transactions
+ * in response to user input (as this app does) does not need
+ * to install such a filter proc because it would be very rare
+ * that a user could command the app fast enough to cause
+ * problems. However, this is included as an example.
+ *
+ ****************************************************************************/
+DWORD FAR PASCAL MyMsgFilterProc(
+int nCode,
+WORD wParam,
+DWORD lParam)
+{
+ wParam; // not used
+
+#define lpmsg ((LPMSG)lParam)
+ if (nCode == MSGF_DDEMGR) {
+
+ /* If a keyboard message is for the MDI , let the MDI client
+ * take care of it. Otherwise, check to see if it's a normal
+ * accelerator key. Otherwise, just handle the message as usual.
+ */
+
+ if ( !TranslateMDISysAccel (hwndMDIClient, lpmsg) &&
+ !TranslateAccelerator (hwndFrame, hAccel, lpmsg)){
+ TranslateMessage (lpmsg);
+ DispatchMessage (lpmsg);
+ }
+ return(1);
+ }
+ return(0);
+#undef lpmsg
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.def b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.def
new file mode 100644
index 000000000..191f6ed61
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.def
@@ -0,0 +1,30 @@
+NAME DDEMLCL
+
+DESCRIPTION 'Microsoft Windows DDEML Client App'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 4096
+STACKSIZE 16384
+
+EXPORTS
+ FrameWndProc @1
+ MDIChildWndProc @2
+ AboutDlgProc @3
+ ConnectDlgProc @4
+ TransactDlgProc @5
+ TimeoutDlgProc @7
+ DdeCallback @8
+ AdvOptsDlgProc @9
+ TextEntryDlgProc @10
+ InfoCtrlWndProc @11
+ TrackingWndProc @12
+ ContextDlgProc @13
+ ViewHandleDlgProc @14
+ DelayDlgProc @15
+ MyMsgFilterProc @16
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.dlg b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.dlg
new file mode 100644
index 000000000..3d3e9eb36
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.dlg
@@ -0,0 +1,144 @@
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+ "S:\\WINDEV\\WINDDEML\\CLIENT\\DIALOG.H\0"
+END
+
+IDD_TRANSACT DIALOG 11, 27, 138, 82
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "DDE Transaction"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_ITEM, 40, 4, 92, 12, ES_AUTOHSCROLL
+ COMBOBOX IDCB_FORMAT, 40, 20, 92, 36, CBS_DROPDOWNLIST |
+ CBS_HASSTRINGS | WS_VSCROLL | WS_TABSTOP
+ CONTROL "&Request", IDCH_REQUEST, "Button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP, 50, 44, 42, 12
+ CONTROL "&Advise", IDCH_ADVISE, "Button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP, 50, 54, 42, 12
+ CONTROL "&Unadvise", IDCH_UNADVISE, "Button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP, 50, 64, 42, 12
+ CONTROL "&Poke", IDCH_POKE, "Button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP, 92, 44, 36, 12
+ CONTROL "&Execute", IDCH_EXECUTE, "Button", BS_AUTORADIOBUTTON |
+ WS_TABSTOP, 92, 54, 36, 12
+ DEFPUSHBUTTON "&Ok", IDOK, 6, 38, 36, 14
+ PUSHBUTTON "Op&tions...", IDBN_OPTIONS, 6, 51, 36, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 6, 64, 36, 14
+ RTEXT "Item:", IDTX_ITEM, 6, 6, 28, 8, NOT WS_GROUP
+ RTEXT "Format:", -1, 6, 20, 28, 8, NOT WS_GROUP
+ GROUPBOX "Type", -1, 46, 34, 86, 44
+END
+
+IDD_ADVISEOPTS DIALOG 17, 26, 207, 79
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Transaction Options"
+FONT 8, "Helv"
+BEGIN
+ CONTROL "&Delay rendering(^)", IDCH_NODATA, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 10, 14, 76, 12
+ CONTROL "&Ack Requested(!)", IDCH_ACKREQ, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 10, 26, 76, 12
+ CONTROL "A&synchronous(*)", IDCH_ASYNC, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 10, 43, 82, 12
+ CONTROL "D&isable Conv. first(#)", IDCH_DISABLEFIRST, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 101, 14, 93, 12
+ CONTROL "A&bandon after start($)", IDCH_ABANDON, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 102, 26, 95, 12
+ CONTROL "&Block Result(X)", IDCH_BLOCKRESULT, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 102, 38, 96, 12
+ EDITTEXT IDEF_TIMEOUT, 171, 60, 32, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Ok", IDOK, 4, 58, 38, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 47, 58, 38, 14
+ LTEXT "Timeout in miliseconds:", -1, 90, 61, 80, 9, NOT
+ WS_GROUP
+ GROUPBOX "Advise Options", -1, 5, 4, 85, 37
+ GROUPBOX "Async. Transaction Options", 0, 98, 4, 103, 49
+END
+
+IDD_CONNECT DIALOG 36, 27, 134, 82
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "DDE Connect"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_APPLICATION, 54, 9, 70, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_TOPIC, 54, 25, 70, 12, ES_AUTOHSCROLL
+ CONTROL "Keep all responders", IDCH_CONNECTLIST, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 10, 40, 84, 12
+ DEFPUSHBUTTON "&Connect", IDOK, 8, 58, 38, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 54, 59, 38, 14
+ RTEXT "Application:", -1, 10, 11, 40, 8, NOT WS_GROUP
+ RTEXT "Topic:", -1, 10, 27, 40, 8, NOT WS_GROUP
+END
+
+IDD_ABOUT DIALOG 25, 23, 184, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About DDEMLCL"
+FONT 8, "Helv"
+BEGIN
+ CTEXT "Microsoft Windows", -1, 0, 5, 184, 8
+ CTEXT "DDEMLCL", -1, 0, 15, 184, 8
+ CTEXT "Version 3.1", -1, 0, 34, 184, 8
+ CTEXT "Copyright ゥ 1992 Microsoft Corp.", -1, 0, 47, 184, 9
+ DEFPUSHBUTTON "OK", IDOK, 76, 60, 32, 14, WS_GROUP
+ ICON "ddemlcl", -1, 25, 14, 16, 21
+END
+
+IDD_TEXTENTRY DIALOG 8, 23, 210, 110
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Text Data Entry"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_DATA, 8, 25, 194, 43, ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Ok", IDOK, 7, 90, 38, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 51, 90, 38, 14
+ PUSHBUTTON "&Generate Huge Data", IDBN_GENHUGE, 95, 72, 108, 14
+ CTEXT "Enter text data to send or size of huge data to generate or select an existing appowned data handle to use.",
+ 108, 8, 4, 194, 19, NOT WS_GROUP
+ PUSHBUTTON "&Use existing appowned data...", IDBN_USEOWNED, 95, 90,
+ 108, 14
+ CONTROL "Create as appowned", IDCH_MAKEOWNED, "Button", BS_AUTOCHECKBOX |
+ WS_TABSTOP, 8, 74, 84, 10
+END
+
+IDD_VALUEENTRY DIALOG 33, 29, 135, 46
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Value Entry Dialog"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_VALUE, 95, 6, 33, 12
+ DEFPUSHBUTTON "&Ok", IDOK, 7, 25, 38, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 90, 24, 38, 14
+ RTEXT "Value:", IDTX_VALUE, 6, 8, 87, 8, NOT WS_GROUP
+END
+
+IDD_CONTEXT DIALOG 6, 28, 124, 99
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Connection Context"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_FLAGS, 78, 7, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_COUNTRY, 78, 20, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_CODEPAGE, 78, 33, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_LANG, 78, 46, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_SECURITY, 78, 59, 26, 12, ES_AUTOHSCROLL
+ PUSHBUTTON "Ok", IDOK, 15, 79, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 69, 79, 40, 14
+ LTEXT "flags", -1, 20, 9, 55, 8
+ LTEXT "Country ID", -1, 20, 22, 55, 8
+ LTEXT "CodePage", -1, 20, 35, 55, 8
+ LTEXT "Language ID", -1, 20, 48, 55, 8
+ LTEXT "Security Code", -1, 20, 61, 55, 8
+END
+
+IDD_HDATAVIEW DIALOG 6, 44, 179, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Existing appowned data handles"
+FONT 8, "Helv"
+BEGIN
+ LISTBOX IDLB_HANDLES, 6, 4, 166, 48, LBS_SORT | WS_VSCROLL
+ PUSHBUTTON "&Use", IDOK, 5, 58, 40, 14
+ PUSHBUTTON "&View", IDBN_VIEW, 48, 58, 40, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 91, 58, 40, 14
+ PUSHBUTTON "&Delete", IDBN_DELETE, 134, 58, 40, 14
+END
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.h b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.h
new file mode 100644
index 000000000..29a015ef2
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.h
@@ -0,0 +1,258 @@
+#include <windows.h>
+#include <ddeml.h>
+
+#define WINDOWMENU 3 /* position of window menu */
+
+/* resource ID's */
+#define IDCLIENT 1
+#define IDCONV 2
+#define IDLIST 3
+
+
+/* menu ID's */
+
+#define IDM_EDITPASTE 2004
+
+#define IDM_CONNECT 3000 // enabled always
+#define IDM_RECONNECT 3001 // enabled if list selected
+#define IDM_DISCONNECT 3002 // enabled if conversation selected
+#define IDM_TRANSACT 3003 // enabled if conversation selected
+#define IDM_ABANDON 3004 // enabled if transaction selected
+#define IDM_ABANDONALL 3005 // enabled if conv. selected &&
+ // and any transaction windows exist
+
+#define IDM_BLOCKCURRENT 3010 // enabled if conv. sel. chkd if conv. blocked
+#define IDM_ENABLECURRENT 3011 // enabled if conv. sel. chkd if not blocked
+#define IDM_ENABLEONECURRENT 3012 // enabled if conv. sel.
+
+#define IDM_BLOCKALLCBS 3013 // enabled if any convs.
+#define IDM_ENABLEALLCBS 3014 // enabled if any convs.
+#define IDM_ENABLEONECB 3015 // enabled if any convs.
+
+#define IDM_BLOCKNEXTCB 3016 // enabled always, chkd if set.
+#define IDM_TERMNEXTCB 3017 // enabled if any convs. chked if set.
+
+#define IDM_TIMEOUT 3021
+#define IDM_DELAY 3022
+#define IDM_CONTEXT 3023
+#define IDM_AUTORECONNECT 3024
+
+#define IDM_WINDOWTILE 4001
+#define IDM_WINDOWCASCADE 4002
+#define IDM_WINDOWCLOSEALL 4003
+#define IDM_WINDOWICONS 4004
+
+#define IDM_XACTTILE 4005
+#define IDM_XACTCASCADE 4006
+#define IDM_XACTCLOSEALL 4007
+
+#define IDM_WINDOWCHILD 4100
+
+#define IDM_HELP 5001
+#define IDM_HELPABOUT 5002
+
+
+#define DEFTIMEOUT 1000
+
+#include "dialog.h"
+
+// predefined format list item
+
+typedef struct {
+ ATOM atom;
+ PSTR sz;
+} FORMATINFO;
+#define CFORMATS 3
+
+// conversation (MDI child) window information
+typedef struct {
+ HWND hwndXaction; // last xaction window with focus, 0 if none.
+ BOOL fList;
+ HCONV hConv;
+ HSZ hszTopic;
+ HSZ hszApp;
+ int x; // next child coord.
+ int y;
+ CONVINFO ci; // most recent status info.
+} MYCONVINFO; // parameters to AddConv() in reverse order.
+#define CHILDCBWNDEXTRA 2
+#define UM_GETNEXTCHILDX (WM_USER + 200)
+#define UM_GETNEXTCHILDY (WM_USER + 201)
+#define UM_DISCONNECTED (WM_USER + 202)
+
+// transaction processing structure - this structure is associated with
+// infoctrl control windows. A handle to this structure is placed into
+// the first window word of the control.
+typedef struct { // used to passinfo to/from TransactionDlgProc and
+ DWORD ret; // TextEntryDlgProc.
+ DWORD Result;
+ DWORD ulTimeout;
+ WORD wType;
+ HCONV hConv;
+ HDDEDATA hDdeData;
+ WORD wFmt;
+ HSZ hszItem;
+ WORD fsOptions;
+} XACT;
+
+typedef struct {
+ HDDEDATA hData;
+ HSZ hszItem;
+ WORD wFmt;
+} OWNED;
+
+// transaction option flags - for fsOptions field and DefOptions global.
+
+#define XOPT_NODATA 0x0001
+#define XOPT_ACKREQ 0x0002
+#define XOPT_DISABLEFIRST 0x0004
+#define XOPT_ABANDONAFTERSTART 0x0008
+#define XOPT_BLOCKRESULT 0x0010
+#define XOPT_ASYNC 0x0020
+#define XOPT_COMPLETED 0x8000 // used internally only.
+
+/* strings */
+#define IDS_ILLFNM 1
+#define IDS_ADDEXT 2
+#define IDS_CLOSESAVE 3
+#define IDS_HELPNOTAVAIL 4
+#define IDS_CLIENTTITLE 5
+#define IDS_APPNAME 6
+#define IDS_DDEMLERR 7
+#define IDS_BADLENGTH 8
+
+/* attribute flags for DlgDirList */
+#define ATTR_DIRS 0xC010 /* find drives and directories */
+#define ATTR_FILES 0x0000 /* find ordinary files */
+#define PROP_FILENAME szPropertyName /* name of property for dialog */
+#define MAX_OWNED 20
+
+/*
+ * GLOBALS
+ */
+extern CONVCONTEXT CCFilter;
+extern DWORD idInst;
+extern HANDLE hInst; /* application instance handle */
+extern HANDLE hAccel; /* resource handle of accelerators */
+extern HWND hwndFrame; /* main window handle */
+extern HWND hwndMDIClient; /* handle of MDI Client window */
+extern HWND hwndActive; /* handle of current active MDI child */
+extern HWND hwndActiveEdit; /* handle of edit control in active child */
+extern LONG styleDefault; /* default child creation state */
+extern WORD SyncTimeout;
+extern LONG DefTimeout;
+extern WORD wDelay;
+extern BOOL fEnableCBs;
+extern BOOL fEnableOneCB;
+extern BOOL fBlockNextCB;
+extern BOOL fTermNextCB;
+extern BOOL fAutoReconnect;
+extern HDDEDATA hDataOwned;
+extern WORD fmtLink; // registered LINK clipboard fmt
+extern WORD DefOptions;
+extern char szChild[]; /* class of child */
+extern char szList[]; /* class of child */
+extern char szSearch[]; /* search string */
+extern char *szDriver; /* name of printer driver */
+extern char szPropertyName[]; /* filename property for dialog box */
+extern int iPrinter; /* level of printing capability */
+extern BOOL fCase; /* searches case sensitive */
+extern WORD cFonts; /* number of fonts enumerated */
+extern FORMATINFO aFormats[];
+extern OWNED aOwned[MAX_OWNED];
+extern WORD cOwned;
+
+
+// MACROS
+
+#ifdef NODEBUG
+#define MyAlloc(cb) (PSTR)LocalAlloc(LPTR, (cb))
+#define MyFree(p) (LocalUnlock((HANDLE)(p)), LocalFree((HANDLE)(p)))
+#else // DEBUG
+
+#define MyAlloc(cb) DbgAlloc((WORD)cb)
+#define MyFree(p) DbgFree((PSTR)p)
+#endif //NODEBUG
+
+
+/* externally declared functions
+ */
+
+// ddemlcl.c
+
+BOOL FAR PASCAL InitializeApplication(VOID);
+BOOL FAR PASCAL InitializeInstance(WORD);
+HWND FAR PASCAL AddFile(char *);
+VOID FAR PASCAL ReadFile(HWND);
+VOID FAR PASCAL SaveFile(HWND);
+BOOL FAR PASCAL ChangeFile(HWND);
+int FAR PASCAL LoadFile(HWND, char *);
+VOID FAR PASCAL PrintFile(HWND);
+BOOL FAR PASCAL GetInitializationData(HWND);
+short FAR CDECL MPError(HWND,WORD,WORD,...);
+VOID FAR PASCAL Find(void);
+VOID FAR PASCAL FindNext(void);
+VOID FAR PASCAL FindPrev(void);
+VOID FAR PASCAL MPSpotHelp(HWND,POINT);
+LONG FAR PASCAL FrameWndProc(HWND,UINT,WPARAM,LPARAM);
+LONG FAR PASCAL MDIChildWndProc(HWND,UINT,WPARAM,LPARAM);
+HDC FAR PASCAL GetPrinterDC(void);
+VOID NEAR PASCAL SetSaveFrom (HWND, PSTR);
+BOOL NEAR PASCAL RealSlowCompare (PSTR, PSTR);
+VOID FAR PASCAL FindPrev (void);
+VOID FAR PASCAL FindNext (void);
+BOOL NEAR PASCAL IsWild (PSTR);
+VOID NEAR PASCAL SelectFile (HWND);
+VOID NEAR PASCAL FindText ( int );
+HCONV CreateConv(HSZ hszApp, HSZ hszTopic, BOOL fList, WORD *pError);
+HWND FAR PASCAL AddConv(HSZ hszApp, HSZ hszTopic, HCONV hConv, BOOL fList);
+PSTR GetConvListText(HCONVLIST hConvList);
+PSTR GetConvInfoText(HCONV hConv, CONVINFO *pci);
+PSTR GetConvTitleText(HCONV hConv, HSZ hszApp, HSZ hszTopic, BOOL fList);
+PSTR Status2String(WORD status);
+PSTR State2String(WORD state);
+PSTR Error2String(WORD error);
+PSTR Type2String(WORD wType, WORD fsOptions);
+PSTR GetHSZName(HSZ hsz);
+DWORD FAR PASCAL MyMsgFilterProc(int nCode, WORD wParam, DWORD lParam);
+typedef DWORD FAR PASCAL FILTERPROC(int nCode, WORD wParam, DWORD lParam);
+extern FILTERPROC *lpMsgFilterProc;
+
+// dialog.c
+
+
+int FAR DoDialog(LPCSTR lpTemplateName, FARPROC lpDlgProc, DWORD param,
+ BOOL fRememberFocus);
+BOOL FAR PASCAL AboutDlgProc(HWND,WORD,WORD,LONG);
+BOOL FAR PASCAL ConnectDlgProc(HWND,WORD,WORD,LONG);
+BOOL FAR PASCAL TransactDlgProc(HWND,WORD,WORD,LONG);
+BOOL FAR PASCAL AdvOptsDlgProc(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL TextEntryDlgProc(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL ViewHandleDlgProc(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL TimeoutDlgProc(HWND,WORD,WORD,LONG);
+BOOL FAR PASCAL DelayDlgProc(HWND,WORD,WORD,LONG);
+BOOL FAR PASCAL ContextDlgProc(HWND,WORD,WORD,LONG);
+VOID Delay(DWORD delay);
+
+// dde.c
+
+
+BOOL ProcessTransaction(XACT *pxact);
+VOID CompleteTransaction(HWND hwndInfoCtr, XACT *pxact);
+HDDEDATA EXPENTRY DdeCallback(WORD wType, WORD wFmt, HCONV hConv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD lData1, DWORD lData2);
+HWND MDIChildFromhConv(HCONV hConv);
+HWND FindAdviseChild(HWND hwndMDI, HSZ hszItem, WORD wFmt);
+HWND FindListWindow(HCONVLIST hConvList);
+PSTR GetTextData(HDDEDATA hData);
+PSTR GetFormatData(HDDEDATA hData);
+int MyGetClipboardFormatName(WORD fmt, LPSTR lpstr, int cbMax);
+PSTR GetFormatName(WORD wFmt);
+BOOL MyDisconnect(HCONV hConv);
+
+// mem.c
+
+
+PSTR DbgAlloc(WORD cb);
+PSTR DbgFree(PSTR p);
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.ico b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.ico
new file mode 100644
index 000000000..8828d9ba5
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.rc b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.rc
new file mode 100644
index 000000000..134382275
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/ddemlcl.rc
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * *
+ * FILE : Ddemlcl.rc *
+ * *
+ * DESCRIPTION : Resource script file for Client. *
+ * *
+ ***************************************************************************/
+
+#include "ddemlcl.h"
+
+IDCLIENT ICON ddemlcl.ico
+IDCONV ICON conv.ico
+IDLIST ICON list.ico
+
+/* frame window menu */
+
+IDCLIENT MENU
+BEGIN
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&PasteLink", IDM_EDITPASTE
+ END
+ POPUP "&DDE"
+ BEGIN
+ MENUITEM "&Connect...", IDM_CONNECT
+ MENUITEM "&Reconnect...", IDM_RECONNECT
+ MENUITEM "&Disconnect\tDel", IDM_DISCONNECT GRAYED
+ MENUITEM "&Start Transaction...", IDM_TRANSACT
+ MENUITEM "&Abandon Transaction\tShift-Del", IDM_ABANDON
+ POPUP "&Block"
+ BEGIN
+ MENUITEM "&Block this conversation", IDM_BLOCKCURRENT
+ MENUITEM "&Enable this conversation", IDM_ENABLECURRENT
+ MENUITEM "E&nable one callback, this conversation", IDM_ENABLEONECURRENT
+ MENUITEM SEPARATOR
+ MENUITEM "B&lock all conversations", IDM_BLOCKALLCBS
+ MENUITEM "En&able all conversations", IDM_ENABLEALLCBS
+ MENUITEM "Enable &one callback, any conversation", IDM_ENABLEONECB
+ MENUITEM SEPARATOR
+ MENUITEM "Block ne&xt callback", IDM_BLOCKNEXTCB
+ MENUITEM "Terminate nex&t callback", IDM_TERMNEXTCB
+ END
+ END
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Default Synchronous timeout...", IDM_TIMEOUT
+ MENUITEM "&Response delay...", IDM_DELAY
+ MENUITEM "&Set Prefered Context...", IDM_CONTEXT
+ MENUITEM "Re&connect terminating servers", IDM_AUTORECONNECT
+ END
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "&Tile transactions", IDM_XACTTILE
+ MENUITEM "&Cascade transactions", IDM_XACTCASCADE
+ MENUITEM "C&lose all transactions", IDM_ABANDONALL
+ MENUITEM "T&ile conversations", IDM_WINDOWTILE
+ MENUITEM "C&ascade conversations", IDM_WINDOWCASCADE
+ MENUITEM "A&rrange Icons", IDM_WINDOWICONS
+ MENUITEM "Cl&ose all conversations", IDM_WINDOWCLOSEALL
+ END
+ MENUITEM "&About...", IDM_HELPABOUT
+END
+
+
+
+
+/* frame menu accelerators */
+
+IDCLIENT ACCELERATORS
+BEGIN
+ VK_DELETE, IDM_DISCONNECT, VIRTKEY
+ VK_DELETE, IDM_ABANDON, VIRTKEY, SHIFT
+ VK_INSERT, IDM_EDITPASTE, VIRTKEY, SHIFT
+ VK_F1, IDM_HELP, VIRTKEY
+END
+
+
+
+STRINGTABLE
+BEGIN
+
+IDS_ILLFNM , "Invalid filename: '%s'"
+IDS_ADDEXT , ".TXT"
+IDS_CLOSESAVE , "%s has been changed. Save file before closing?"
+IDS_HELPNOTAVAIL , "Can't load Windows Help application"
+IDS_CLIENTTITLE , " - "
+IDS_APPNAME , "DDEML Client"
+IDS_DDEMLERR , "DDEML Error - %s"
+IDS_BADLENGTH , "Invalid length value string. Reenter or cancel."
+
+END
+
+#include "ddemlcl.dlg"
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/dialog.c b/private/mvdm/wow16/ddeml/tests/src/client/dialog.c
new file mode 100644
index 000000000..49cad00de
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/dialog.c
@@ -0,0 +1,875 @@
+/***************************************************************************
+ * *
+ * MODULE : dialog.c *
+ * *
+ * PURPOSE : Contains all dialog procedures and related functions. *
+ * *
+ ***************************************************************************/
+#include "ddemlcl.h"
+#include "infoctrl.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "huge.h"
+
+#define MAX_NAME 100 // max size for edit controls with app/topic/item names.
+char szWild[] = "*"; // used to indicate wild names ("" is also cool)
+char szT[MAX_NAME]; // temp buf for munging names.
+
+
+LONG GetDlgItemLong(HWND hwnd, WORD id, BOOL *pfTranslated, BOOL fSigned);
+VOID SetDlgItemLong(HWND hwnd, WORD id, LONG l, BOOL fSigned);
+
+/****************************************************************************
+ * *
+ * FUNCTION : DoDialog() *
+ * *
+ * PURPOSE : Generic dialog invocation routine. Handles procInstance *
+ * stuff, focus management and param passing. *
+ * RETURNS : result of dialog procedure. *
+ * *
+ ****************************************************************************/
+int FAR DoDialog(
+LPCSTR lpTemplateName,
+FARPROC lpDlgProc,
+DWORD param,
+BOOL fRememberFocus)
+{
+ WORD wRet;
+ HWND hwndFocus;
+
+ if (fRememberFocus)
+ hwndFocus = GetFocus();
+ lpDlgProc = MakeProcInstance(lpDlgProc, hInst);
+ wRet = DialogBoxParam(hInst, lpTemplateName, hwndFrame, lpDlgProc, param);
+ FreeProcInstance(lpDlgProc);
+ if (fRememberFocus)
+ SetFocus(hwndFocus);
+ return wRet;
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL AboutDlgProc ( hwnd, msg, wParam, lParam )
+HWND hwnd;
+register WORD msg;
+register WORD wParam;
+LONG lParam;
+{
+ switch (msg){
+ case WM_INITDIALOG:
+ /* nothing to initialize */
+ break;
+
+ case WM_COMMAND:
+ switch (wParam){
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+
+ return TRUE;
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL ConnectDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ static BOOL fReconnect;
+ char szT[MAX_NAME];
+ HSZ hszApp, hszTopic;
+ MYCONVINFO *pmci;
+ WORD error;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hwnd, IDEF_APPLICATION, EM_LIMITTEXT, MAX_NAME, 0);
+ SendDlgItemMessage(hwnd, IDEF_TOPIC, EM_LIMITTEXT, MAX_NAME, 0);
+ fReconnect = (BOOL)lParam;
+ if (fReconnect) {
+ PSTR psz;
+
+ pmci = (MYCONVINFO *)GetWindowWord(hwndActive, 0);
+ SetWindowText(hwnd, "DDE Reconnect List");
+ psz = GetHSZName(pmci->hszApp);
+ SetDlgItemText(hwnd, IDEF_APPLICATION, psz);
+ MyFree(psz);
+ psz = GetHSZName(pmci->hszTopic);
+ SetDlgItemText(hwnd, IDEF_TOPIC, psz);
+ MyFree(psz);
+ ShowWindow(GetDlgItem(hwnd, IDCH_CONNECTLIST), SW_HIDE);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ GetDlgItemText(hwnd, IDEF_APPLICATION, szT, MAX_NAME);
+ if (!strcmp(szT, szWild))
+ szT[0] = '\0';
+ hszApp = DdeCreateStringHandle(idInst, szT, 0);
+
+ GetDlgItemText(hwnd, IDEF_TOPIC, szT, MAX_NAME);
+ if (!strcmp(szT, szWild))
+ szT[0] = '\0';
+ hszTopic = DdeCreateStringHandle(idInst, szT, 0);
+
+ if (fReconnect) {
+ HCONV hConv;
+ CONVINFO ci;
+ WORD cHwnd;
+ HWND *aHwnd, *pHwnd, hwndSave;
+
+ ci.cb = sizeof(CONVINFO);
+ pmci = (MYCONVINFO *)GetWindowWord(hwndActive, 0);
+ hwndSave = hwndActive;
+
+ // count the existing conversations and allocate aHwnd
+
+ cHwnd = 0;
+ hConv = NULL;
+ while (hConv = DdeQueryNextServer((HCONVLIST)pmci->hConv, hConv))
+ cHwnd++;
+ aHwnd = (HWND *)MyAlloc(cHwnd * sizeof(HWND));
+
+ // save all the old conversation windows into aHwnd.
+
+ pHwnd = aHwnd;
+ hConv = NULL;
+ while (hConv = DdeQueryNextServer((HCONVLIST)pmci->hConv, hConv)) {
+ DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci);
+ *pHwnd++ = (HWND)ci.hUser;
+ }
+
+ // reconnect
+
+ if (!(hConv = DdeConnectList(idInst, hszApp, hszTopic, pmci->hConv, &CCFilter))) {
+ MPError(hwnd, MB_OK, IDS_DDEMLERR, (LPSTR)Error2String(DdeGetLastError(idInst)));
+ DdeFreeStringHandle(idInst, hszApp);
+ DdeFreeStringHandle(idInst, hszTopic);
+ return 0;
+ }
+
+ // fixup windows corresponding to the new conversations.
+
+ pmci->hConv = hConv;
+ hConv = NULL;
+ while (hConv = DdeQueryNextServer((HCONVLIST)pmci->hConv, hConv)) {
+ DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci);
+ // preserve corresponding window by setting its list
+ // entry to 0
+ for (pHwnd = aHwnd; pHwnd < &aHwnd[cHwnd]; pHwnd++) {
+ if (*pHwnd == (HWND)ci.hUser) {
+ *pHwnd = NULL;
+ break;
+ }
+ }
+ }
+
+ // destroy all windows left in the old list
+
+ for (pHwnd = aHwnd; pHwnd < &aHwnd[cHwnd]; pHwnd++)
+ if (*pHwnd)
+ SendMessage(hwndMDIClient, WM_MDIDESTROY, *pHwnd, 0L);
+ MyFree((PSTR)aHwnd);
+
+ // create any new windows needed
+
+ hConv = NULL;
+ while (hConv = DdeQueryNextServer((HCONVLIST)pmci->hConv, hConv)) {
+ DdeQueryConvInfo(hConv, (DWORD)QID_SYNC, &ci);
+ if (ci.hUser) {
+ InvalidateRect((HWND)ci.hUser, NULL, TRUE);
+ } else {
+ AddConv(ci.hszSvcPartner, ci.hszTopic, hConv, FALSE);
+ }
+ }
+
+ // make list window update itself
+
+ InvalidateRect(hwndSave, NULL, TRUE);
+ SetFocus(hwndSave);
+ } else {
+ if (!CreateConv(hszApp, hszTopic,
+ IsDlgButtonChecked(hwnd, IDCH_CONNECTLIST), &error)) {
+ MPError(hwnd, MB_OK, IDS_DDEMLERR, (LPSTR)Error2String(error));
+ return 0;
+ }
+ }
+ DdeFreeStringHandle(idInst, hszApp);
+ DdeFreeStringHandle(idInst, hszTopic);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+}
+
+
+
+
+/*
+ * Fills a XACT structure and calls ProcessTransaction.
+ *
+ * On initiation lParam == hConv.
+ */
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL TransactDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ static WORD id2type[] = {
+ XTYP_REQUEST, // IDCH_REQUEST
+ XTYP_ADVSTART, // IDCH_ADVISE
+ XTYP_ADVSTOP, // IDCH_UNADVISE
+ XTYP_POKE, // IDCH_POKE
+ XTYP_EXECUTE, // IDCH_EXECUTE
+ };
+ static XACT *pxact; // ONLY ONE AT A TIME!
+ int i;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ pxact = (XACT *)MyAlloc(sizeof(XACT));
+ pxact->hConv = (HCONV)lParam;
+ pxact->fsOptions = DefOptions;
+ pxact->ulTimeout = DefTimeout;
+
+ // The item index == the index to the format atoms in aFormats[].
+ for (i = 0; i < CFORMATS; i++)
+ SendDlgItemMessage(hwnd, IDCB_FORMAT, CB_INSERTSTRING, i,
+ (DWORD)(LPSTR)aFormats[i].sz);
+ SendDlgItemMessage(hwnd, IDCB_FORMAT, CB_INSERTSTRING, i,
+ (DWORD)(LPSTR)"NULL");
+ SendDlgItemMessage(hwnd, IDCB_FORMAT, CB_SETCURSEL, 0, 0);
+ CheckRadioButton(hwnd, IDCH_REQUEST, IDCH_EXECUTE, IDCH_REQUEST);
+ SendDlgItemMessage(hwnd, IDEF_ITEM, EM_LIMITTEXT, MAX_NAME, 0);
+
+ // If there is a top transaction window, use its contents to
+ // anticipate what the user will want to do.
+
+ if (IsWindow(hwndActive)) {
+ HWND hwndXaction;
+ XACT *pxact;
+ PSTR pszItem;
+
+ hwndXaction = GetWindow(hwndActive, GW_CHILD);
+ if (IsWindow(hwndXaction)) {
+ pxact = (XACT *)GetWindowWord(hwndXaction, GWW_WUSER);
+ pszItem = GetHSZName(pxact->hszItem);
+ if ((pxact->wType & XTYP_ADVSTART) == XTYP_ADVSTART ||
+ pxact->wType == XTYP_ADVDATA) {
+ CheckRadioButton(hwnd, IDCH_REQUEST, IDCH_EXECUTE, IDCH_UNADVISE);
+ }
+ SetDlgItemText(hwnd, IDEF_ITEM, pszItem);
+ for (i = 0; i < CFORMATS; i++) {
+ if (aFormats[i].atom == pxact->wFmt) {
+ SendDlgItemMessage(hwnd, IDCB_FORMAT, CB_SETCURSEL, i, 0);
+ break;
+ }
+ }
+ MyFree(pszItem);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDCH_EXECUTE:
+ SetDlgItemText(hwnd, IDEF_ITEM, "");
+ case IDCH_REQUEST:
+ case IDCH_ADVISE:
+ case IDCH_UNADVISE:
+ case IDCH_POKE:
+ EnableWindow(GetDlgItem(hwnd, IDEF_ITEM), wParam != IDCH_EXECUTE);
+ EnableWindow(GetDlgItem(hwnd, IDTX_ITEM), wParam != IDCH_EXECUTE);
+ break;
+
+ case IDOK:
+ case IDBN_OPTIONS:
+ {
+ int id;
+
+ // set pxact->wType
+
+ for (id = IDCH_REQUEST; id <= IDCH_EXECUTE; id++) {
+ if (IsDlgButtonChecked(hwnd, id)) {
+ pxact->wType = id2type[id - IDCH_REQUEST];
+ break;
+ }
+ }
+
+ if (wParam == IDBN_OPTIONS) {
+ DoDialog(MAKEINTRESOURCE(IDD_ADVISEOPTS),
+ AdvOptsDlgProc, MAKELONG(pxact->fsOptions, pxact),
+ TRUE);
+ return 0;
+ }
+
+ id = (int)SendDlgItemMessage(hwnd, IDCB_FORMAT, CB_GETCURSEL, 0, 0);
+ if (id == LB_ERR) {
+ return 0;
+ }
+ if (id == CFORMATS)
+ pxact->wFmt = 0;
+ else
+ pxact->wFmt = aFormats[id].atom;
+
+ if (pxact->wType == XTYP_ADVSTART) {
+ if (pxact->fsOptions & XOPT_NODATA)
+ pxact->wType |= XTYPF_NODATA;
+ if (pxact->fsOptions & XOPT_ACKREQ)
+ pxact->wType |= XTYPF_ACKREQ;
+ }
+
+ GetDlgItemText(hwnd, IDEF_ITEM, szT, MAX_NAME);
+ pxact->hszItem = DdeCreateStringHandle(idInst, szT, NULL);
+
+ pxact->hDdeData = 0;
+ /*
+ * If this transaction needs data, invoke data input dialog.
+ */
+ if (pxact->wType == XTYP_POKE || pxact->wType == XTYP_EXECUTE) {
+ if (!DoDialog(MAKEINTRESOURCE(IDD_TEXTENTRY),
+ TextEntryDlgProc, (DWORD)(LPSTR)pxact,
+ TRUE))
+ return 0;
+ }
+
+ // now start the transaction
+
+ ProcessTransaction(pxact);
+ MyFree((PSTR)pxact);
+ }
+ EndDialog(hwnd, 1);
+ break;
+
+ case IDCANCEL:
+ MyFree((PSTR)pxact);
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ case WM_DESTROY:
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : AdvOptsDlgProc *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL AdvOptsDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ static struct {
+ WORD id;
+ WORD opt;
+ } id2Opt[] = {
+ { IDCH_NODATA , XOPT_NODATA } ,
+ { IDCH_ACKREQ , XOPT_ACKREQ } ,
+ { IDCH_DISABLEFIRST , XOPT_DISABLEFIRST } ,
+ { IDCH_ABANDON , XOPT_ABANDONAFTERSTART } ,
+ { IDCH_BLOCKRESULT , XOPT_BLOCKRESULT } ,
+ { IDCH_ASYNC , XOPT_ASYNC } ,
+ };
+#define CCHBOX 6
+ int i;
+ static XACT *pxact; // only one instance at a time!!
+
+ switch (msg){
+ case WM_INITDIALOG:
+ pxact = (XACT *)HIWORD(lParam);
+
+ for (i = 0; i < CCHBOX; i++) {
+ CheckDlgButton(hwnd, id2Opt[i].id, pxact->fsOptions & id2Opt[i].opt);
+ }
+ SetDlgItemLong(hwnd, IDEF_TIMEOUT, pxact->ulTimeout, FALSE);
+ if (pxact->wType != XTYP_ADVSTART) {
+ EnableWindow(GetDlgItem(hwnd, IDCH_NODATA), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDCH_ACKREQ), FALSE);
+ }
+ SendMessage(hwnd, WM_COMMAND, IDCH_ASYNC, 0); // enable async checkboxes
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDCH_ASYNC:
+ {
+ BOOL fEnable;
+
+ fEnable = IsDlgButtonChecked(hwnd, IDCH_ASYNC);
+ EnableWindow(GetDlgItem(hwnd, IDCH_DISABLEFIRST), fEnable);
+ EnableWindow(GetDlgItem(hwnd, IDCH_ABANDON), fEnable);
+ EnableWindow(GetDlgItem(hwnd, IDCH_BLOCKRESULT), fEnable);
+ EnableWindow(GetDlgItem(hwnd, IDEF_TIMEOUT), !fEnable);
+ }
+ break;
+
+ case IDOK:
+ pxact->fsOptions = 0;
+ for (i = 0; i < CCHBOX; i++) {
+ if (IsDlgButtonChecked(hwnd, id2Opt[i].id))
+ pxact->fsOptions |= id2Opt[i].opt;
+ }
+ if (!(pxact->fsOptions & XOPT_ASYNC))
+ pxact->ulTimeout = (DWORD)GetDlgItemLong(hwnd, IDEF_TIMEOUT,
+ &i, FALSE);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, GetWindowWord(hwnd, 0));
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return 0;
+#undef CCHBOX
+}
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : TextEntryDlgProc *
+ * *
+ * PURPOSE : Allows user to enter text data which is to be sent to a *
+ * server. The user can opt to have a huge text piece of *
+ * data created automaticlly. *
+ * It uses the XACT structure for passing info in and out. *
+ * Must have wFmt and hszItem set on entry. *
+ * Sets hDDEData on return if TRUE was returned. *
+ * *
+ * RETURNS : TRUE on success, FALSE on failure or cancel *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL TextEntryDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ static XACT FAR *pxact;
+ DWORD cb;
+ LONG length;
+ LPBYTE pData;
+ BOOL fOwned;
+ int id, i;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ pxact = (XACT FAR *)lParam;
+ fOwned = FALSE;
+ for (i = 0; i < (int)cOwned; i++) {
+ if (aOwned[i].wFmt == pxact->wFmt &&
+ aOwned[i].hszItem == pxact->hszItem) {
+ fOwned = TRUE;
+ break;
+ }
+ }
+ EnableWindow(GetDlgItem(hwnd, IDBN_USEOWNED), fOwned);
+ CheckDlgButton(hwnd, IDCH_MAKEOWNED, 0);
+ EnableWindow(GetDlgItem(hwnd, IDCH_MAKEOWNED), cOwned < MAX_OWNED);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ case IDBN_GENHUGE:
+ fOwned = IsDlgButtonChecked(hwnd, IDCH_MAKEOWNED);
+ cb = SendDlgItemMessage(hwnd, IDEF_DATA, WM_GETTEXTLENGTH, 0, 0) + 1;
+ pxact->hDdeData = DdeCreateDataHandle(idInst, NULL, 0, cb, pxact->hszItem,
+ pxact->wFmt, fOwned ? HDATA_APPOWNED : 0);
+ //
+ // Note that at this time we have not yet given the data handle
+ // to DDEML for transmission to any application, therefore, we
+ // are at liberty to write to it using DdeAccessData() or any
+ // other DDEML api. It is only data handles received from DDEML
+ // or given to DDEML for transmission that are readonly.
+ //
+ pData = DdeAccessData(pxact->hDdeData, NULL);
+ GetDlgItemText(hwnd, IDEF_DATA, pData, (WORD)cb);
+ DdeUnaccessData(pxact->hDdeData);
+ if (wParam == IDBN_GENHUGE) {
+ char szT[40];
+
+ /*
+ * we assume in this case that the text entered is the decimal
+ * value of the size of the huge object desired. We parse
+ * this string and create a randomly generated huge block
+ * of text data and place it into pxact->hDdeData.
+ */
+ _fmemcpy(szT, pData, min((WORD)cb, 40));
+ szT[39] = '\0';
+ if (sscanf(szT, "%ld", &length) == 1) {
+ DdeFreeDataHandle(pxact->hDdeData);
+ pxact->hDdeData = CreateHugeDataHandle(length, 4325,
+ 345, 5, pxact->hszItem, pxact->wFmt,
+ fOwned ? HDATA_APPOWNED : 0);
+ } else {
+ /*
+ * The string cannot be parsed. Inform the user of
+ * what is expected.
+ */
+ MPError(hwnd, MB_OK, IDS_BADLENGTH);
+ return 0;
+ }
+ }
+ if (fOwned) {
+ aOwned[cOwned].hData = pxact->hDdeData;
+ aOwned[cOwned].hszItem = pxact->hszItem;
+ aOwned[cOwned].wFmt = pxact->wFmt;
+ cOwned++;
+ }
+ EndDialog(hwnd, TRUE);
+ break;
+
+ case IDBN_USEOWNED:
+ /*
+ * the user has chosen to use an existing owned data for sending
+ * to the server.
+ */
+ id = DoDialog(MAKEINTRESOURCE(IDD_HDATAVIEW), ViewHandleDlgProc,
+ (DWORD)pxact, TRUE);
+
+ switch (id) {
+ case IDCANCEL:
+ return(0);
+
+ case IDOK:
+ EndDialog(hwnd, TRUE);
+
+ case IDBN_VIEW:
+ pData = DdeAccessData(pxact->hDdeData, NULL);
+ SetDlgItemText(hwnd, IDEF_DATA, pData);
+ DdeUnaccessData(pxact->hDdeData);
+ break;
+ }
+ break;
+
+ case IDCANCEL:
+ EndDialog(hwnd, FALSE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+}
+
+
+
+BOOL FAR PASCAL ViewHandleDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ static XACT FAR *pxact;
+ int i, itm;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ pxact = (XACT FAR *)lParam;
+ // load listbox with handles that fit pxact constraints
+
+ for (i = 0; i < (int)cOwned; i++) {
+ if (aOwned[i].hszItem == pxact->hszItem &&
+ aOwned[i].wFmt == pxact->wFmt) {
+ wsprintf(szT, "[%d] %lx : length=%ld", i, aOwned[i].hData,
+ DdeGetData(aOwned[i].hData, NULL, 0, 0));
+ SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_ADDSTRING, 0, (LONG)(LPSTR)szT);
+ }
+ }
+ SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_SETCURSEL, 0, 0);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK: // use selectted handle
+ case IDBN_DELETE: // delete selected handle
+ case IDBN_VIEW: // view selected handle
+ itm = (int)SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_GETCURSEL, 0, 0);
+ if (itm != LB_ERR) {
+ SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_GETTEXT, itm, (LONG)(LPSTR)szT);
+ sscanf(szT, "[%d]", &i);
+ pxact->hDdeData = aOwned[i].hData;
+ switch (wParam) {
+ case IDOK: // use selectted handle
+ EndDialog(hwnd, wParam);
+ break;
+
+ case IDBN_DELETE: // delete selected handle
+ DdeFreeDataHandle(aOwned[i].hData);
+ aOwned[i] = aOwned[--cOwned];
+ SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_DELETESTRING, itm, 0);
+ if (SendDlgItemMessage(hwnd, IDLB_HANDLES, LB_GETCOUNT, 0, 0) == 0)
+ EndDialog(hwnd, IDCANCEL);
+ break;
+
+ case IDBN_VIEW: // view selected handle
+ EndDialog(hwnd, wParam);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ EndDialog(hwnd, FALSE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+}
+
+
+
+BOOL FAR PASCAL DelayDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ switch (msg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd, "Advise data response time");
+ SetDlgItemInt(hwnd, IDEF_VALUE, wDelay, FALSE);
+ SetDlgItemText(hwnd, IDTX_VALUE, "Delay in milliseconds:");
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ wDelay = (WORD)GetDlgItemInt(hwnd, IDEF_VALUE, NULL, FALSE);
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : TimeoutDlgProc() *
+ * *
+ * PURPOSE : Allows user to alter the synchronous timeout value. *
+ * *
+ * RETURNS : TRUE on success, FALSE on cancel or failure. *
+ * *
+ ****************************************************************************/
+BOOL FAR PASCAL TimeoutDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ switch (msg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd, "Synchronous transaction timeout");
+ SetDlgItemLong(hwnd, IDEF_VALUE, DefTimeout, FALSE);
+ SetDlgItemText(hwnd, IDTX_VALUE, "Timeout in milliseconds:");
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ DefTimeout = GetDlgItemLong(hwnd, IDEF_VALUE, NULL, FALSE);
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+}
+
+
+
+
+BOOL FAR PASCAL ContextDlgProc(
+HWND hwnd,
+register WORD msg,
+register WORD wParam,
+LONG lParam)
+{
+ BOOL fSuccess;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ SetDlgItemInt(hwnd, IDEF_FLAGS, CCFilter.wFlags, FALSE);
+ SetDlgItemInt(hwnd, IDEF_COUNTRY, CCFilter.wCountryID, FALSE);
+ SetDlgItemInt(hwnd, IDEF_CODEPAGE, CCFilter.iCodePage, TRUE);
+ SetDlgItemLong(hwnd, IDEF_LANG, CCFilter.dwLangID, FALSE);
+ SetDlgItemLong(hwnd, IDEF_SECURITY, CCFilter.dwSecurity, FALSE);
+ return(1);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ CCFilter.wFlags = GetDlgItemInt(hwnd, IDEF_FLAGS, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ CCFilter.wCountryID = GetDlgItemInt(hwnd, IDEF_COUNTRY, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ CCFilter.iCodePage = GetDlgItemInt(hwnd, IDEF_CODEPAGE, &fSuccess, TRUE);
+ if (!fSuccess) return(0);
+ LOWORD(CCFilter.dwLangID) = GetDlgItemInt(hwnd, IDEF_LANG, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ LOWORD(CCFilter.dwSecurity) = GetDlgItemInt(hwnd, IDEF_SECURITY, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+
+void Delay(
+DWORD delay)
+{
+ MSG msg;
+
+ delay = GetCurrentTime() + delay;
+ while (GetCurrentTime() < delay) {
+ if (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+
+LONG GetDlgItemLong(
+HWND hwnd,
+WORD id,
+BOOL *pfTranslated,
+BOOL fSigned)
+{
+ char szT[20];
+
+ if (!GetDlgItemText(hwnd, id, szT, 20)) {
+ if (pfTranslated != NULL) {
+ *pfTranslated = FALSE;
+ }
+ return(0L);
+ }
+ if (pfTranslated != NULL) {
+ *pfTranslated = TRUE;
+ }
+ return(atol(szT));
+}
+
+
+VOID SetDlgItemLong(
+HWND hwnd,
+WORD id,
+LONG l,
+BOOL fSigned)
+{
+ char szT[20];
+
+ ltoa(l, szT, 10);
+ SetDlgItemText(hwnd, id, szT);
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/dialog.h b/private/mvdm/wow16/ddeml/tests/src/client/dialog.h
new file mode 100644
index 000000000..eae4fb8d9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/dialog.h
@@ -0,0 +1,41 @@
+#define IDEF_DATA 101
+#define IDCH_NODATA 102
+#define IDCH_ACKREQ 103
+#define IDCH_DISABLEFIRST 104
+#define IDCH_ABANDON 105
+#define IDCH_BLOCKRESULT 106
+#define IDCH_ASYNC 107
+#define IDEF_TIMEOUT 109
+#define IDEF_ITEM 110
+#define IDCB_FORMAT 111
+#define IDBN_OPTIONS 112
+#define IDCH_REQUEST 113
+#define IDCH_ADVISE 114
+#define IDCH_UNADVISE 115
+#define IDCH_POKE 116
+#define IDCH_EXECUTE 117
+#define IDEF_APPLICATION 118
+#define IDEF_TOPIC 119
+#define IDCH_CONNECTLIST 120
+#define IDEF_VALUE 121
+#define IDTX_VALUE 122
+#define IDBN_GENHUGE 123
+#define IDTX_ITEM 124
+#define IDBN_USEOWNED 125
+#define IDEF_FLAGS 126
+#define IDEF_COUNTRY 127
+#define IDEF_CODEPAGE 128
+#define IDEF_LANG 129
+#define IDEF_SECURITY 130
+#define IDD_TEXTENTRY 900
+#define IDD_ADVISEOPTS 901
+#define IDD_TRANSACT 902
+#define IDD_CONNECT 903
+#define IDD_VALUEENTRY 904
+#define IDD_ABOUT 905
+#define IDD_CONTEXT 906
+#define IDD_HDATAVIEW 100
+#define IDBN_VIEW 131
+#define IDCH_MAKEOWNED 132
+#define IDBN_DELETE 133
+#define IDLB_HANDLES 134
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/huge.c b/private/mvdm/wow16/ddeml/tests/src/client/huge.c
new file mode 100644
index 000000000..452f35b29
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/huge.c
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * *
+ * MODULE : huge.c *
+ * *
+ * PURPOSE : This contains functions useful for generating and *
+ * verifying huge text data blocks. *
+ * *
+ ***************************************************************************/
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+#include <ddeml.h>
+#include "huge.h"
+
+extern DWORD idInst;
+#define BUFSZ 435
+
+LONG lseed, lmult, ladd;
+char szT[BUFSZ];
+
+VOID SetMyRand(LONG seed, LONG mult, LONG add);
+char MyRand(VOID);
+BOOL RandTest(LONG length, LONG seed, LONG mult, LONG add);
+
+/****************************************************************************
+ * *
+ * FUNCTION : SetMyRand() *
+ * *
+ * PURPOSE : Transfers random sequence generation variables to globals. *
+ * *
+ ****************************************************************************/
+VOID SetMyRand(
+LONG seed,
+LONG mult,
+LONG add)
+{
+ lseed = seed;
+ lmult = mult;
+ ladd = add;
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MyRand() *
+ * *
+ * PURPOSE : Generates the next random character in a sequence. *
+ * *
+ * RETURNS : the character generated *
+ * *
+ ****************************************************************************/
+char MyRand()
+{
+ char c;
+
+ lseed = lseed * lmult + ladd;
+ c = (char)(LOWORD(lseed) ^ HIWORD(lseed));
+ return((char)((c & (char)0x4f) + ' ')); // 0x20 - 0x6f - all printable
+}
+
+
+/*
+ * This function allocates and fills a HUGE data handle with a verifiable
+ * text string.
+ *
+ * The format of the text string is:
+ * "<length>=<seed>*<mult>+<add>;---data of length <length>---\0"
+ * all values are stored in base 16 numbers.
+ */
+/****************************************************************************
+ * *
+ * FUNCTION : CreateHugeDataHandle() *
+ * *
+ * PURPOSE : Generates a huge pseudo-random sequence of printable *
+ * characters of the length given and places then into *
+ * a DDEML data handle. *
+ * *
+ * RETURNS : The data handle created or 0 on failure. *
+ * *
+ ****************************************************************************/
+HDDEDATA CreateHugeDataHandle(
+LONG length,
+LONG seed,
+LONG mult,
+LONG add,
+HSZ hszItem,
+WORD wFmt,
+WORD afCmd)
+{
+ register WORD cb;
+ HDDEDATA hData;
+ DWORD cbData;
+ char *psz;
+
+ wsprintf(szT, "%ld=%ld*%ld+%ld;", length, seed, mult, add);
+ cb = strlen(szT);
+ hData = DdeCreateDataHandle(idInst, szT, cb + 1, 0, hszItem, wFmt, afCmd);
+ if (hData)
+ hData = DdeAddData(hData, NULL, 0, cb + length + 1);
+ cbData = cb;
+ SetMyRand(seed, mult, add);
+ while (hData && (length > 0)) {
+ psz = szT;
+ cb = BUFSZ;
+ while (cb--)
+ *psz++ = MyRand();
+ hData = DdeAddData(hData, szT, min(length, BUFSZ), cbData);
+ cbData += BUFSZ;
+ length -= BUFSZ;
+ }
+ return(hData);
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : CheckHugeData() *
+ * *
+ * PURPOSE : Verifies the correctness of a pseudo-random character *
+ * sequence generated by CreateHugeData. *
+ * *
+ * RETURNS : TRUE if verified ok, FALSE otherwise. *
+ * *
+ ****************************************************************************/
+BOOL CheckHugeData(
+HDDEDATA hData)
+{
+ LONG length;
+ LONG seed;
+ LONG mult;
+ LONG add;
+ char *psz;
+ DWORD cbOff;
+ WORD cb;
+
+ if (!DdeGetData(hData, szT, BUFSZ, 0))
+ return(FALSE);
+ szT[BUFSZ - 1] = '\0';
+ psz = strchr(szT, ';');
+ if (psz == NULL)
+ return(FALSE);
+ *psz = '\0';
+
+ if (sscanf(szT, "%ld=%ld*%ld+%ld", &length, &seed, &mult, &add) != 4)
+ return(FALSE);
+
+ if (length < 0)
+ return(FALSE);
+ SetMyRand(seed, mult, add);
+ cbOff = strlen(szT) + 1;
+ while (length > 0) {
+ DdeGetData(hData, szT, BUFSZ, cbOff);
+ psz = szT;
+ cb = BUFSZ;
+ while (length-- && cb--)
+ if (*psz++ != MyRand())
+ return(FALSE);
+ cbOff += BUFSZ;
+ length -= BUFSZ;
+ }
+ return(TRUE);
+}
+
+#if 0
+/****************************************************************************
+ * *
+ * FUNCTION : RandTest() *
+ * *
+ * PURPOSE : Verifies the correctness of CreateHugeDataHandle() and *
+ * CheckHugeData(). *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL RandTest(
+LONG length,
+LONG seed,
+LONG mult,
+LONG add)
+{
+ HDDEDATA hData;
+ BOOL fSuccess;
+
+ hData = CreateHugeDataHandle(length, seed, mult, add, 0, 1, 0);
+ if (!hData)
+ return(FALSE);
+ fSuccess = CheckHugeData(hData);
+ DdeFreeDataHandle(hData);
+ return(fSuccess);
+}
+#endif
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/huge.h b/private/mvdm/wow16/ddeml/tests/src/client/huge.h
new file mode 100644
index 000000000..ce30b7fc9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/huge.h
@@ -0,0 +1,8 @@
+// header file for HUGE data handle testing module
+
+
+// PROCS
+
+HDDEDATA CreateHugeDataHandle(LONG length, LONG seed, LONG mult, LONG add,
+ HSZ hszItem, WORD wFmt, WORD afCmd);
+BOOL CheckHugeData(HDDEDATA hData);
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.c b/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.c
new file mode 100644
index 000000000..f19fbe0f9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.c
@@ -0,0 +1,686 @@
+/***************************************************************************
+ * *
+ * MODULE : infoctrl.c *
+ * *
+ * PURPOSE : Functions for the infoctrl control class *
+ * *
+ ***************************************************************************/
+/*
+ * INFOCTRL.C
+ *
+ * This module implements a custom information display control which
+ * can present up to 7 seperate strings of information at once and is
+ * sizeable and moveable with the mouse.
+ */
+
+#include <windows.h>
+#include <string.h>
+#include <memory.h>
+#include "infoctrl.h"
+#include "track.h"
+
+char szClass[] = "InfoCtrl_class";
+WORD cCreated = 0;
+char szNULL[] = "";
+int cxMargin = 0;
+int cyMargin = 0;
+HBRUSH hFocusBrush;
+
+
+long FAR PASCAL InfoCtrlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+VOID MyDrawText(HDC hdc, LPRECT lprc, PSTR psz, WORD wFormat);
+void DrawFocus(HDC hdc, HWND hwnd, WORD style);
+int CountWindows(HWND hwndParent);
+void GetCascadeWindowPos(HWND hwndParent, int iWindow, LPRECT lprc);
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+HWND CreateInfoCtrl(
+LPSTR pszCenter, // NULL is ok.
+int x,
+int y,
+int cx,
+int cy,
+HWND hwndParent,
+HANDLE hInst,
+LPSTR pszUL, // NULLs here are fine.
+LPSTR pszUC,
+LPSTR pszUR,
+LPSTR pszLL,
+LPSTR pszLC,
+LPSTR pszLR,
+WORD style,
+HMENU id,
+DWORD dwUser)
+{
+ INFOCTRL_DATA *picd;
+ HWND hwnd;
+
+ if (!cCreated) {
+ WNDCLASS wc;
+ TEXTMETRIC metrics;
+ HDC hdc;
+
+ wc.style = CS_VREDRAW | CS_HREDRAW;
+ wc.lpfnWndProc = InfoCtrlWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = ICCBWNDEXTRA;
+ wc.hInstance = hInst;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = COLOR_WINDOW + 1;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szClass;
+
+ RegisterClass(&wc);
+
+ hdc = GetDC(hwndParent);
+ GetTextMetrics(hdc, &metrics);
+ cyMargin = metrics.tmHeight;
+ cxMargin = metrics.tmAveCharWidth * 2;
+ ReleaseDC(hwndParent, hdc);
+ hFocusBrush = CreateSolidBrush(RGB(0, 0, 255));
+ }
+
+ if (!(picd = (INFOCTRL_DATA *)LocalAlloc(LPTR, sizeof(INFOCTRL_DATA))))
+ return(FALSE);
+
+ if (pszCenter) {
+ picd->pszCenter = (PSTR)(PSTR)LocalAlloc(LPTR, _fstrlen(pszCenter) + 1);
+ _fstrcpy(picd->pszCenter, pszCenter);
+ } else {
+ picd->pszCenter = NULL;
+ }
+
+ if (pszUL) {
+ picd->pszUL = (PSTR)(PSTR)LocalAlloc(LPTR, _fstrlen(pszUL) + 1);
+ _fstrcpy(picd->pszUL, pszUL);
+ } else {
+ picd->pszUL = NULL;
+ }
+ if (pszUC) {
+ picd->pszUC = (PSTR)LocalAlloc(LPTR, _fstrlen(pszUC) + 1);
+ _fstrcpy(picd->pszUC, pszUC);
+ } else {
+ picd->pszUC = NULL;
+ }
+ if (pszUR) {
+ picd->pszUR = (PSTR)LocalAlloc(LPTR, _fstrlen(pszUR) + 1);
+ _fstrcpy(picd->pszUR, pszUR);
+ } else {
+ picd->pszUR = NULL;
+ }
+ if (pszLL) {
+ picd->pszLL = (PSTR)LocalAlloc(LPTR, _fstrlen(pszLL) + 1);
+ _fstrcpy(picd->pszLL, pszLL);
+ } else {
+ picd->pszLL = NULL;
+ }
+ if (pszLC) {
+ picd->pszLC = (PSTR)LocalAlloc(LPTR, _fstrlen(pszLC) + 1);
+ _fstrcpy(picd->pszLC, pszLC);
+ } else {
+ picd->pszLC = NULL;
+ }
+ if (pszLR) {
+ picd->pszLR = (PSTR)LocalAlloc(LPTR, _fstrlen(pszLR) + 1);
+ _fstrcpy(picd->pszLR, pszLR);
+ } else {
+ picd->pszLR = NULL;
+ }
+
+ picd->style = style;
+ picd->hInst = hInst;
+
+ if (hwnd = CreateWindow(szClass, szNULL,
+ WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
+ x, y, cx, cy, hwndParent, id, hInst, (LPSTR)picd)) {
+ cCreated++;
+ SetWindowLong(hwnd, GWL_LUSER, dwUser);
+ BringWindowToTop(hwnd);
+ ShowWindow(hwnd, SW_SHOW);
+ return(hwnd);
+ }
+ return(FALSE);
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+VOID MyDrawText(
+HDC hdc,
+LPRECT lprc,
+PSTR psz,
+WORD wFormat)
+{
+ RECT rc;
+ WORD cx;
+
+ if (psz == NULL || !*psz)
+ return; // notin to draw dude.
+
+ SetRect(&rc, 0, 0, 1, 0);
+ DrawText(hdc, psz, -1, &rc, DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE);
+ cx = min(rc.right - rc.left, lprc->right - lprc->left);
+ CopyRect(&rc, lprc);
+ switch (wFormat & (DT_LEFT | DT_CENTER | DT_RIGHT)) {
+ case DT_LEFT:
+ rc.right = rc.left + cx;
+ break;
+
+ case DT_CENTER:
+ cx = (rc.right - rc.left - cx) / 2;
+ rc.right -= cx;
+ rc.left += cx;
+ break;
+
+ case DT_RIGHT:
+ rc.left = rc.right - cx;
+ break;
+ }
+ DrawText(hdc, psz, -1, &rc, wFormat | DT_VCENTER);
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+long FAR PASCAL InfoCtrlWndProc(
+HWND hwnd,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam)
+{
+ INFOCTRL_DATA *picd;
+ int i;
+ RECT rc;
+ HDC hdc;
+
+ switch (msg) {
+ case WM_CREATE:
+ SetWindowWord(hwnd, GWW_INFODATA,
+ (WORD)(DWORD)(((LPCREATESTRUCT)lParam)->lpCreateParams));
+ break;
+
+ case WM_SIZE:
+ if ((int)LOWORD(lParam) < 2 * cxMargin || (int)HIWORD(lParam) < 2 * cyMargin) {
+ MoveWindow(hwnd, 0, 0, max((int)LOWORD(lParam), 2 * cxMargin),
+ max((int)HIWORD(lParam), 2 * cyMargin), TRUE);
+ } else {
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ SetRect(&picd->rcFocusUL, 0, 0, cxMargin, cyMargin);
+ SetRect(&picd->rcFocusUR, (int)LOWORD(lParam) - cxMargin, 0, (int)LOWORD(lParam),
+ cyMargin);
+ SetRect(&picd->rcFocusLL, 0, (int)HIWORD(lParam) - cyMargin, cxMargin,
+ (int)HIWORD(lParam));
+ SetRect(&picd->rcFocusLR, picd->rcFocusUR.left, picd->rcFocusLL.top,
+ picd->rcFocusUR.right, picd->rcFocusLL.bottom);
+ }
+ break;
+
+
+ case WM_DESTROY:
+ {
+ PSTR *ppsz;
+
+ SendMessage(GetParent(hwnd), ICN_BYEBYE, hwnd,
+ GetWindowLong(hwnd, GWL_LUSER));
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ ppsz = &picd->pszUL;
+ for (i = 0; i < 5; i++, ppsz++) {
+ if (*ppsz) {
+ LocalUnlock((HANDLE)*ppsz);
+ *ppsz = (PSTR)LocalFree((HANDLE)*ppsz);
+ }
+ }
+ LocalUnlock((HANDLE)picd);
+ SetWindowWord(hwnd, GWW_INFODATA, LocalFree((HANDLE)picd));
+ }
+ break;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ if (picd->style & ICSTY_SHOWFOCUS) {
+ if (msg == WM_SETFOCUS)
+ picd->style |= ICSTY_HASFOCUS;
+ else
+ picd->style &= ~ICSTY_HASFOCUS;
+ BringWindowToTop(hwnd);
+ // notify parent
+ SendMessage(GetParent(hwnd), ICN_HASFOCUS,
+ msg == WM_SETFOCUS, MAKELONG(picd, hwnd));
+ } else
+ picd->style &= ~ICSTY_HASFOCUS;
+ hdc = GetDC(hwnd);
+ DrawFocus(hdc, hwnd, picd->style);
+ ReleaseDC(hwnd, hdc);
+ goto DoDWP;
+ break;
+
+ case WM_MOUSEMOVE:
+ {
+ LPCSTR cursor;
+
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ if (picd->style & ICSTY_SHOWFOCUS) {
+
+ if ((int)HIWORD(lParam) < cyMargin) {
+ if ((int)LOWORD(lParam) < cxMargin) {
+ cursor = IDC_SIZENWSE;
+ } else if ((int)LOWORD(lParam) > picd->rcFocusUR.left) {
+ cursor = IDC_SIZENESW;
+ } else {
+ cursor = IDC_SIZENS;
+ }
+ } else if ((int)HIWORD(lParam) > picd->rcFocusLL.top) {
+ if ((int)LOWORD(lParam) < cxMargin) {
+ cursor = IDC_SIZENESW;
+ } else if ((int)LOWORD(lParam) > picd->rcFocusUR.left) {
+ cursor = IDC_SIZENWSE;
+ } else {
+ cursor = IDC_SIZENS;
+ }
+ } else {
+ if ((int)LOWORD(lParam) < cxMargin) {
+ cursor = IDC_SIZEWE;
+ } else if ((int)LOWORD(lParam) > picd->rcFocusUR.left) {
+ cursor = IDC_SIZEWE;
+ } else {
+ cursor = IDC_CROSS;
+ }
+ }
+ } else {
+ cursor = IDC_ARROW;
+ }
+ SetCursor(LoadCursor(NULL, cursor));
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ if (picd->style & ICSTY_SHOWFOCUS) {
+ WORD fs = 0;
+
+ if (!(picd->style & ICSTY_HASFOCUS)) {
+ SetFocus(hwnd);
+ }
+
+ if ((int)HIWORD(lParam) < cyMargin) {
+ fs = TF_TOP;
+ } else if ((int)HIWORD(lParam) > picd->rcFocusLL.top) {
+ fs = TF_BOTTOM;
+ }
+ if ((int)LOWORD(lParam) < cxMargin) {
+ fs |= TF_LEFT;
+ } else if ((int)LOWORD(lParam) > picd->rcFocusUR.left) {
+ fs |= TF_RIGHT;
+ } else if (fs == 0) {
+ fs = TF_MOVE;
+ }
+
+ GetClientRect(hwnd, &rc);
+ ClientToScreen(hwnd, (LPPOINT)&rc.left);
+ ClientToScreen(hwnd, (LPPOINT)&rc.right);
+ ScreenToClient(GetParent(hwnd), (LPPOINT)&rc.left);
+ ScreenToClient(GetParent(hwnd), (LPPOINT)&rc.right);
+ if (TrackRect(picd->hInst, GetParent(hwnd),
+ rc.left, rc.top, rc.right, rc.bottom,
+ 2 * cxMargin, 2 * cyMargin,
+ fs | TF_ALLINBOUNDARY, &rc)) {
+
+ MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left,
+ rc.bottom - rc.top, TRUE);
+ }
+ }
+ break;
+
+ case ICM_SETSTRING:
+ {
+ PSTR *ppsz;
+
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ ppsz = (PSTR *)&picd->pszUL + wParam;
+
+ if (lParam == NULL)
+ lParam = (DWORD)(LPSTR)szNULL;
+
+ if (!_fstrcmp(*ppsz, (LPSTR)lParam))
+ return 0;
+
+ if (*ppsz) {
+ LocalUnlock((HANDLE)*ppsz);
+ *ppsz = (PSTR)LocalFree((HANDLE)*ppsz);
+ }
+ if (lParam) {
+ *ppsz = (PSTR)LocalAlloc(LPTR, _fstrlen((LPSTR)lParam) + 1);
+ _fstrcpy((LPSTR)*ppsz, (LPSTR)lParam);
+ }
+ GetClientRect(hwnd, &rc);
+ switch (wParam) {
+ case ICSID_UL:
+ case ICSID_UC:
+ case ICSID_UR:
+ rc.bottom = cyMargin;
+ break;
+
+ case ICSID_LL:
+ case ICSID_LC:
+ case ICSID_LR:
+ rc.top = rc.bottom - cyMargin;
+ break;
+
+ case ICSID_CENTER:
+ InflateRect(&rc, -cxMargin, -cyMargin);
+ break;
+ }
+ InvalidateRect(hwnd, &rc, TRUE);
+ UpdateWindow(hwnd);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HANDLE brush;
+
+ picd = (INFOCTRL_DATA *)GetWindowWord(hwnd, GWW_INFODATA);
+ BeginPaint(hwnd, &ps);
+ // erasure should have already been done for us.
+ GetClientRect(hwnd, &rc);
+ brush = GetStockObject(BLACK_BRUSH);
+ InflateRect(&rc, -cxMargin / 2, -cyMargin / 2);
+ FrameRect(ps.hdc, &rc, brush);
+ InflateRect(&rc, cxMargin / 2, cyMargin / 2);
+ if (*picd->pszUL || *picd->pszUC || *picd->pszUR) {
+ SetRect(&rc, picd->rcFocusUL.right, 0, picd->rcFocusUR.left,
+ cyMargin);
+ MyDrawText(ps.hdc, &rc, picd->pszUR, DT_RIGHT);
+ MyDrawText(ps.hdc, &rc, picd->pszUL, DT_LEFT);
+ MyDrawText(ps.hdc, &rc, picd->pszUC, DT_CENTER);
+ }
+ if (*picd->pszLL || *picd->pszLC || *picd->pszLR) {
+ SetRect(&rc, picd->rcFocusLL.right, picd->rcFocusLL.top,
+ picd->rcFocusLR.left, picd->rcFocusLR.bottom);
+ MyDrawText(ps.hdc, &rc, picd->pszLR, DT_RIGHT);
+ MyDrawText(ps.hdc, &rc, picd->pszLL, DT_LEFT);
+ MyDrawText(ps.hdc, &rc, picd->pszLC, DT_CENTER);
+ }
+
+ GetClientRect(hwnd, &rc);
+ InflateRect(&rc, -cxMargin, -cyMargin);
+ if (picd->style & ICSTY_OWNERDRAW) {
+ OWNERDRAWPS odps;
+
+ if (IntersectRect(&odps.rcPaint, &rc, &ps.rcPaint)) {
+ if (IntersectClipRect(ps.hdc, rc.left, rc.top, rc.right,
+ rc.bottom) != NULLREGION) {
+ odps.rcBound = rc;
+ odps.hdc = ps.hdc;
+ odps.dwUser = GetWindowLong(hwnd, GWL_LUSER);
+ SendMessage(GetParent(hwnd), ICN_OWNERDRAW,
+ GetWindowWord(hwnd, GWW_ID), (DWORD)(LPSTR)&odps);
+ }
+ }
+ } else {
+ MyDrawText(ps.hdc, &rc, picd->pszCenter, DT_LEFT | DT_WORDBREAK | DT_EXPANDTABS);
+ }
+ DrawFocus(ps.hdc, hwnd, picd->style);
+ EndPaint(hwnd, &ps);
+ }
+ break;
+
+DoDWP:
+ default:
+ return (DefWindowProc(hwnd, msg, wParam, lParam));
+ }
+ return (NULL);
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+void DrawFocus(
+HDC hdc,
+HWND hwnd,
+WORD style)
+{
+ RECT rc;
+
+ GetClientRect(hwnd, &rc);
+ FrameRect(hdc, &rc, style & ICSTY_HASFOCUS ?
+ hFocusBrush : GetStockObject(GRAY_BRUSH));
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+int CountWindows(
+register HWND hwndParent)
+{
+ int cWindows = 0;
+ register HWND hwnd;
+
+ for (hwnd=GetWindow(hwndParent, GW_CHILD);
+ hwnd;
+ hwnd= GetWindow(hwnd, GW_HWNDNEXT)) {
+ cWindows++;
+ }
+ return(cWindows);
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+void GetCascadeWindowPos(
+HWND hwndParent,
+int iWindow,
+LPRECT lprc)
+{
+ RECT rc;
+ int cStack;
+ register int dxClient, dyClient;
+
+ /* Compute the width and breadth of the situation. */
+ GetClientRect(hwndParent, (LPRECT)&rc);
+ dxClient = rc.right - rc.left;
+ dyClient = rc.bottom - rc.top;
+
+ /* How many windows per stack? */
+ cStack = dyClient / (3 * cyMargin);
+
+ lprc->right = dxClient - (cStack * cxMargin);
+ lprc->bottom = dyClient - (cStack * cyMargin);
+
+ cStack++; /* HACK!: Mod by cStack+1 */
+
+ lprc->left = (iWindow % cStack) * cxMargin;
+ lprc->top = (iWindow % cStack) * cyMargin;
+}
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+void CascadeChildWindows(
+register HWND hwndParent)
+{
+ int i;
+ int cWindows;
+ RECT rc;
+ WORD wFlags;
+ register HWND hwndMove;
+ HANDLE hDefer;
+
+ cWindows = CountWindows(hwndParent);
+
+ if (!cWindows)
+ return;
+
+ /* Get the last child of hwndParent. */
+ hwndMove = GetWindow(hwndParent, GW_CHILD);
+
+ /* Arouse the terrible beast... */
+ hDefer = BeginDeferWindowPos(cWindows);
+
+ /* Position each window. */
+ for (i=0; i < cWindows; i++) {
+ GetCascadeWindowPos(hwndParent, i, (LPRECT)&rc);
+
+ wFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS;
+
+ /* Size the window. */
+ hDefer = DeferWindowPos(hDefer,
+ hwndMove, NULL,
+ rc.left, rc.top,
+ rc.right, rc.bottom,
+ wFlags);
+
+ hwndMove = GetWindow(hwndMove, GW_HWNDNEXT);
+ }
+
+ /* Calm the brute. */
+ EndDeferWindowPos(hDefer);
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : *
+ * *
+ * PURPOSE : *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+void TileChildWindows(
+register HWND hwndParent)
+{
+ int i;
+ int dx;
+ int dy;
+ int xRes;
+ int yRes;
+ int iCol;
+ int iRow;
+ int cCols;
+ int cRows;
+ int cExtra;
+ int cWindows;
+ register HWND hwndMove;
+ RECT rcClient;
+ HANDLE hDefer;
+ WORD wFlags;
+
+ cWindows = CountWindows(hwndParent);
+
+ /* Nothing to tile? */
+ if (!cWindows)
+ return;
+
+ /* Compute the smallest nearest square. */
+ for (i=2; i * i <= cWindows; i++);
+
+ cRows = i - 1;
+ cCols = cWindows / cRows;
+ cExtra = cWindows % cRows;
+
+ GetClientRect(hwndParent, (LPRECT)&rcClient);
+ xRes = rcClient.right - rcClient.left;
+ yRes = rcClient.bottom - rcClient.top;
+
+ if (xRes<=0 || yRes<=0)
+ return;
+
+ hwndMove = GetWindow(hwndParent, GW_CHILD);
+
+ hDefer = BeginDeferWindowPos(cWindows);
+
+ for (iCol=0; iCol < cCols; iCol++) {
+ if ((cCols-iCol) <= cExtra)
+ cRows++;
+
+ for (iRow=0; iRow < cRows; iRow++) {
+ dx = xRes / cCols;
+ dy = yRes / cRows;
+
+ wFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS;
+
+ /* Position and size the window. */
+ hDefer = DeferWindowPos(hDefer, hwndMove, NULL,
+ dx * iCol,
+ dy * iRow,
+ dx,
+ dy,
+ wFlags);
+
+ /* Get the next window. */
+ hwndMove = GetWindow(hwndMove, GW_HWNDNEXT);
+ }
+
+ if ((cCols-iCol) <= cExtra) {
+ cRows--;
+ cExtra--;
+ }
+ }
+
+ EndDeferWindowPos(hDefer);
+
+}
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.h b/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.h
new file mode 100644
index 000000000..4271175e3
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/infoctrl.h
@@ -0,0 +1,83 @@
+/*
+ * INFOCTRL.H
+ *
+ * This module implements a custom information display control which
+ * can present up to 7 seperate strings of information at once and is
+ * sizeable and moveable with the mouse.
+ */
+
+// STYLES
+
+#define ICSTY_OWNERDRAW 0x0001 // set if the central information is not
+ // standard text.
+#define ICSTY_SHOWFOCUS 0x0002 // set to allow focus painting an movement
+
+#define ICSTY_HASFOCUS 0x8000
+
+#define ICN_OWNERDRAW (WM_USER + 676) // notifies to draw
+ // wParam=id, lParam=OWNERDRAWPS FAR *
+#define ICN_HASFOCUS (WM_USER + 677) // notifies of focus set
+ // wParam=fFocus, lParam=(hMemCtrlData, hwnd)
+#define ICN_BYEBYE (WM_USER + 678) // notifies of imminent death
+ // wParam=hwnd, lParam=dwUser
+
+#define ICM_SETSTRING (WM_USER + 776) // alters a string
+ // wParam=index, lParam=LPSTR
+
+#define ICSID_UL 0
+#define ICSID_UC 1
+#define ICSID_UR 2
+#define ICSID_LL 3
+#define ICSID_LC 4
+#define ICSID_LR 5
+#define ICSID_CENTER 6
+
+#define GWW_WUSER 0 // == LOWORD(GWL_LUSER)
+#define GWL_LUSER 0
+#define GWW_INFODATA 4
+#define ICCBWNDEXTRA 6
+
+HWND CreateInfoCtrl(
+LPSTR szTitle,
+int x,
+int y,
+int cx,
+int cy,
+HWND hwndParent,
+HANDLE hInst,
+LPSTR pszUL, // NULLs here are fine.
+LPSTR pszUC,
+LPSTR pszUR,
+LPSTR pszLL,
+LPSTR pszLC,
+LPSTR pszLR,
+WORD style,
+HMENU id,
+DWORD dwUser);
+
+void CascadeChildWindows(HWND hwndParent);
+void TileChildWindows(HWND hwndParent);
+
+typedef struct {
+ PSTR pszUL;
+ PSTR pszUC;
+ PSTR pszUR;
+ PSTR pszLL;
+ PSTR pszLC;
+ PSTR pszLR;
+ PSTR pszCenter;
+ WORD style;
+ RECT rcFocusUL;
+ RECT rcFocusUR;
+ RECT rcFocusLL;
+ RECT rcFocusLR;
+ HANDLE hInst;
+} INFOCTRL_DATA;
+
+typedef struct {
+ RECT rcBound;
+ RECT rcPaint;
+ HDC hdc;
+ DWORD dwUser;
+} OWNERDRAWPS;
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/list.ico b/private/mvdm/wow16/ddeml/tests/src/client/list.ico
new file mode 100644
index 000000000..4f2427439
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/list.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/makefile b/private/mvdm/wow16/ddeml/tests/src/client/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/makefile
@@ -0,0 +1,6 @@
+#
+# 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/wow16/ddeml/tests/src/client/makefile.dos b/private/mvdm/wow16/ddeml/tests/src/client/makefile.dos
new file mode 100644
index 000000000..1f2c49664
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/makefile.dos
@@ -0,0 +1,48 @@
+#
+# Test makefile
+
+!ifdef WIN31
+EXEFLAGS=-AM -Gsw -Od -Ziep -W3 -DWIN16 -DWIN31 -DUSECOMM -DWIN
+!else
+EXEFLAGS=-AS -FPi -Gcw -Os -Ziepd -W3 -DWIN16 -DWIN
+!endif
+
+OBJ =ddemlcl.obj clinit.obj track.obj dialog.obj dde.obj infoctrl.obj huge.obj mem.obj
+
+#
+# Stress Test
+#
+
+all: ddemlcl.exe
+
+ddemlcl.res: ddemlcl.rc
+ rc -DWIN16 -r ddemlcl.rc
+
+ddemlcl.obj: ddemlcl.c infoctrl.h ddemlcl.h
+ cl -c $(EXEFLAGS) ddemlcl.c
+
+clinit.obj: clinit.c ddemlcl.h
+ cl -c $(EXEFLAGS) clinit.c
+
+track.obj: track.c track.h
+ cl -c $(EXEFLAGS) track.c
+
+dialog.obj: dialog.c huge.h ddemlcl.h infoctrl.h
+ cl -c $(EXEFLAGS) dialog.c
+
+dde.obj: dde.c ddemlcl.h infoctrl.h huge.h
+ cl -c $(EXEFLAGS) dde.c
+
+infoctrl.obj: infoctrl.c track.h
+ cl -c $(EXEFLAGS) infoctrl.c
+
+mem.obj: mem.c
+ cl -c $(EXEFLAGS) mem.c
+
+huge.obj: huge.c huge.h
+ cl -c $(EXEFLAGS) huge.c
+
+ddemlcl.exe: $(OBJ) ddemlcl.def ddemlcl.res
+ link /map/li/co $(OBJ)/AL:16,ddemlcl.exe,, /NOE /NOD libw ddeml mlibcew,ddemlcl.def
+ mapsym ddemlcl
+ rc -DWIN16 ddemlcl.res ddemlcl.exe
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/mem.c b/private/mvdm/wow16/ddeml/tests/src/client/mem.c
new file mode 100644
index 000000000..81c0b1493
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/mem.c
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * *
+ * MODULE : mem.c *
+ * *
+ * PURPOSE : Functions for debugging memory allocation bugs. *
+ * *
+ ***************************************************************************/
+#include <windows.h>
+
+#define MAX_OBJECTS 200
+
+PSTR aptrs[MAX_OBJECTS];
+WORD cptrs = 0;
+
+/****************************************************************************
+ * *
+ * FUNCTION : DbgAlloc() *
+ * *
+ * PURPOSE : Useful routine for catching memory allocation errors. *
+ * Enters allocated objects into an array to check when freed *
+ * *
+ * RETURNS : pointer to object allocated. *
+ * *
+ ****************************************************************************/
+PSTR DbgAlloc(
+register WORD cb)
+{
+ register PSTR p;
+
+ p = (PSTR)LocalAlloc(LPTR, cb);
+ aptrs[cptrs++] = p;
+ if (cptrs >= MAX_OBJECTS)
+ OutputDebugString("Too many objects to track");
+ return p;
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : DbgFree() *
+ * *
+ * PURPOSE : To free an object allocated with DbgAlloc(). Checks the *
+ * object array to make sure an object isn't freed twice. *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+PSTR DbgFree(
+register PSTR p)
+{
+ register WORD i;
+
+ if (p == NULL)
+ return p;
+
+ for (i = 0; i < cptrs; i++) {
+ if (aptrs[i] == p) {
+ aptrs[i] = aptrs[cptrs - 1];
+ break;
+ }
+ }
+ if (i == cptrs) {
+ OutputDebugString("Free on non-allocated object");
+ DebugBreak();
+ } else {
+ LocalUnlock((HANDLE)p);
+ p = (PSTR)LocalFree((HANDLE)p);
+ }
+ cptrs--;
+ return p;
+}
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/mk4dos.cmd b/private/mvdm/wow16/ddeml/tests/src/client/mk4dos.cmd
new file mode 100644
index 000000000..1cc3f8bff
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/mk4dos.cmd
@@ -0,0 +1,13 @@
+@echo off
+if "%1"=="" goto bld
+del *.dll
+del *.sym
+del *.map
+del *.obj
+del *.bak
+del *.res
+del *.lnk
+goto done
+:bld
+nmake -f makefile.dos
+:done
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/sources b/private/mvdm/wow16/ddeml/tests/src/client/sources
new file mode 100644
index 000000000..7a425dd77
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/sources
@@ -0,0 +1,29 @@
+
+MAJORCOMP=samples
+MINORCOMP=ddemlcl
+
+TARGETNAME=ddemlcl
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+INCLUDES=.
+
+SOURCES= ddemlcl.c \
+ clinit.c \
+ dde.c \
+ dialog.c \
+ huge.c \
+ infoctrl.c \
+ mem.c \
+ track.c \
+ client.rc
+
+
+C_DEFINES=-DWIN32
+
+UMTYPE=windows
+UMAPPL=ddemlcl
+UMENTRY=winmain
+UMLIBS=obj\*\ddemlcl.lib \
+ obj\*\client.res
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/track.c b/private/mvdm/wow16/ddeml/tests/src/client/track.c
new file mode 100644
index 000000000..673440ae7
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/track.c
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * *
+ * MODULE : track.c *
+ * *
+ * PURPOSE : Generic tracking code. *
+ * *
+ ***************************************************************************/
+#include <windows.h>
+#include "track.h"
+
+RECT rcTrack;
+RECT rcDelta;
+POINT ptOrg;
+POINT ptPrev;
+WORD fsTrack;
+RECT rcBoundary;
+int cxMinTrack;
+int cyMinTrack;
+
+VOID DrawTrackRect(HWND hwnd, LPRECT prcOld, LPRECT prcNew);
+VOID HorzUpdate(HDC hdc, int yOld, int yNew, int x1Old, int x1New, int x2Old,
+ int x2New);
+VOID VertUpdate(HDC hdc, int xOld, int xNew, int y1Old, int y1New, int y2Old,
+ int y2New);
+LONG FAR PASCAL TrackingWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/****************************************************************************
+ * *
+ * FUNCTION : TrackRect() *
+ * *
+ * PURPOSE : Implements functionality similiar to the PM WinTrackRect() *
+ * *
+ * RETURNS : TRUE on success, FALSE if tracking was canceled. *
+ * prcResult contains the resulting rectangle. *
+ * *
+ ****************************************************************************/
+BOOL TrackRect(
+HANDLE hInst,
+HWND hwnd, // bounding window
+int left, // rectangle to track in bounding window coords.
+int top,
+int right,
+int bottom,
+int cxMin,
+int cyMin,
+WORD fs,
+LPRECT prcResult) // result rect in bounding window coords.
+{
+ static BOOL fTracking = 0;
+ FARPROC lpOrgWndProc, lpTrackWndProc;
+ HWND hwndOldCapture, hwndOldFocus;
+ MSG msg;
+
+ if (fTracking)
+ return FALSE;
+
+ fTracking = TRUE;
+
+ lpOrgWndProc = (FARPROC)GetWindowLong(hwnd, GWL_WNDPROC);
+ lpTrackWndProc = MakeProcInstance((FARPROC)TrackingWndProc, hInst);
+ SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)lpTrackWndProc);
+
+ hwndOldCapture = GetCapture();
+ SetCapture(hwnd);
+
+ hwndOldFocus = SetFocus(hwnd);
+ UpdateWindow(hwnd);
+
+ GetCursorPos(&ptOrg);
+ ScreenToClient(hwnd, &ptOrg);
+
+ if (fs & TF_SETPOINTERPOS) {
+
+ if (fs & TF_LEFT && fs & TF_RIGHT)
+ ptOrg.x = (left + right) / 2;
+ else if (fs & TF_LEFT)
+ ptOrg.x = left;
+ else if (fs & TF_RIGHT)
+ ptOrg.x = right;
+
+ if (fs & TF_TOP && fs & TF_BOTTOM)
+ ptOrg.y = (top + bottom) / 2;
+ else if (fs & TF_TOP)
+ ptOrg.y = top;
+ else if (fs & TF_BOTTOM)
+ ptOrg.y = bottom;
+
+ ClientToScreen(hwnd, &ptOrg);
+ SetCursorPos(ptOrg.x, ptOrg.y);
+ ScreenToClient(hwnd, &ptOrg);
+ }
+
+ ptPrev = ptOrg;
+ cxMinTrack = cxMin;
+ cyMinTrack = cyMin;
+ GetClientRect(hwnd, &rcBoundary);
+ fsTrack = fs;
+ SetRect(&rcTrack, left, top, right, bottom);
+ SetRect(&rcDelta, left - ptOrg.x, top - ptOrg.y, right - ptOrg.x,
+ bottom - ptOrg.y);
+ DrawTrackRect(hwnd, &rcTrack, NULL);
+
+ while (GetMessage(&msg, NULL, NULL, NULL))
+ DispatchMessage(&msg);
+
+ DrawTrackRect(hwnd, &rcTrack, NULL);
+
+ SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)lpOrgWndProc);
+ FreeProcInstance(lpTrackWndProc);
+
+ SetFocus(hwndOldFocus);
+ SetCapture(hwndOldCapture);
+ CopyRect(prcResult, &rcTrack);
+
+ fTracking = FALSE;
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : DrawTrackRect() *
+ * *
+ * PURPOSE : XOR draws whats needed to move a selection from prcOld to *
+ * prcNew. If prcNew == NULL this is considered a *
+ * first-time draw or last time erase. *
+ * *
+ ****************************************************************************/
+VOID DrawTrackRect(
+HWND hwnd,
+LPRECT prcOld,
+LPRECT prcNew)
+{
+ HDC hdc;
+
+ hdc = GetDC(hwnd);
+ SetROP2(hdc, R2_NOT);
+ // erase/draw the whole thing
+ MoveTo(hdc, prcOld->left, prcOld->top);
+ LineTo(hdc, prcOld->right, prcOld->top);
+ LineTo(hdc, prcOld->right, prcOld->bottom);
+ LineTo(hdc, prcOld->left, prcOld->bottom);
+ LineTo(hdc, prcOld->left, prcOld->top);
+ if (prcNew) {
+ MoveTo(hdc, prcNew->left, prcNew->top);
+ LineTo(hdc, prcNew->right, prcNew->top);
+ LineTo(hdc, prcNew->right, prcNew->bottom);
+ LineTo(hdc, prcNew->left, prcNew->bottom);
+ LineTo(hdc, prcNew->left, prcNew->top);
+ }
+ ReleaseDC(hwnd, hdc);
+}
+
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : TrackingWndProc() *
+ * *
+ * PURPOSE : Window procedure that subclasses the given parent window. *
+ * This handles the mouse tracking and rectangle updates. *
+ * *
+ ****************************************************************************/
+LONG FAR PASCAL TrackingWndProc(
+HWND hwnd,
+UINT msg,
+WPARAM wParam,
+LPARAM lParam)
+{
+ switch (msg) {
+ case WM_MOUSEMOVE:
+ {
+ RECT rcNow, rcTest;
+
+ if (ptPrev.x == (int)LOWORD(lParam) && ptPrev.y == (int)HIWORD(lParam))
+ return 0;
+ CopyRect(&rcNow, &rcTrack);
+ if (fsTrack & TF_LEFT)
+ rcNow.left = (int)LOWORD(lParam) + rcDelta.left;
+ if (fsTrack & TF_RIGHT)
+ rcNow.right = (int)LOWORD(lParam) + rcDelta.right;
+ if (fsTrack & TF_TOP)
+ rcNow.top = (int)HIWORD(lParam) + rcDelta.top;
+ if (fsTrack & TF_BOTTOM)
+ rcNow.bottom = (int)HIWORD(lParam) + rcDelta.bottom;
+
+ if (rcNow.left > rcNow.right - cxMinTrack)
+ if (fsTrack & TF_LEFT)
+ rcNow.left = rcNow.right - cxMinTrack;
+ else
+ rcNow.right = rcNow.left + cxMinTrack;
+
+ if (rcNow.top > rcNow.bottom - cyMinTrack)
+ if (fsTrack & TF_TOP)
+ rcNow.top = rcNow.bottom - cyMinTrack;
+ else
+ rcNow.bottom = rcNow.top + cyMinTrack;
+
+ if (fsTrack & TF_ALLINBOUNDARY) {
+ if ((fsTrack & TF_MOVE) == TF_MOVE) {
+ IntersectRect(&rcTest, &rcNow, &rcBoundary);
+ if (!EqualRect(&rcTest, &rcNow)) {
+ if (rcNow.left < rcBoundary.left)
+ OffsetRect(&rcNow, rcBoundary.left - rcNow.left, 0);
+ if (rcNow.right > rcBoundary.right)
+ OffsetRect(&rcNow, rcBoundary.right - rcNow.right, 0);
+ if (rcNow.top < rcBoundary.top)
+ OffsetRect(&rcNow, 0, rcBoundary.top - rcNow.top);
+ if (rcNow.bottom > rcBoundary.bottom)
+ OffsetRect(&rcNow, 0, rcBoundary.bottom - rcNow.bottom);
+ }
+ } else
+ IntersectRect(&rcNow, &rcNow, &rcBoundary);
+ }
+
+ if (EqualRect(&rcNow, &rcTrack))
+ return 0;
+
+ DrawTrackRect(hwnd, &rcTrack, &rcNow);
+
+ CopyRect(&rcTrack, &rcNow);
+ ptPrev = MAKEPOINT(lParam);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ SendMessage(hwnd, WM_MOUSEMOVE, wParam, lParam);
+ PostMessage(hwnd, WM_QUIT, 0, 0); // pop out of modal loop
+ return 0;
+ break;
+
+ default:
+ return(DefWindowProc(hwnd, msg, wParam, lParam));
+ break;
+ }
+ return 0;
+}
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/client/track.h b/private/mvdm/wow16/ddeml/tests/src/client/track.h
new file mode 100644
index 000000000..6ac5b8079
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/client/track.h
@@ -0,0 +1,20 @@
+
+/*
+ * TRACK.H
+ *
+ * This module implements a general rectangle tracking service
+ */
+
+/* TrackRect() flags */
+
+#define TF_LEFT 0x0001
+#define TF_TOP 0x0002
+#define TF_RIGHT 0x0004
+#define TF_BOTTOM 0x0008
+#define TF_MOVE 0x000F
+
+#define TF_SETPOINTERPOS 0x0010
+#define TF_ALLINBOUNDARY 0x0080
+
+BOOL TrackRect(HANDLE hInst, HWND hwnd, int left, int top, int right,
+ int bottom, int cxMin, int cyMin, WORD fs, LPRECT prcResult);
diff --git a/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.c b/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.c
new file mode 100644
index 000000000..393b57ad9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.c
@@ -0,0 +1,538 @@
+/*****************************************************************************\
+*
+* DDEMO.C
+*
+* This file implements a simple DDEML sample application that demonstrates
+* some of the ways the DDEML APIs can be used.
+*
+* Each instance of this application becomes both a DDE client and a DDE
+* server with any other instances of this application that are found.
+*
+* Since it assumes it is talking to itself, this program takes some liberties
+* to simplify things. For instance, this application does not support the
+* standard SysTopic topic and does not use any standard formats.
+*
+* The basic concepts this application will show you are:
+*
+* How to use lists of conversations properly
+* How to handle links
+* How to handle simple asynchronous transactions
+* How to use your own custom formats
+*
+\*****************************************************************************/
+#include <windows.h>
+#include <ddeml.h>
+#include <stdlib.h>
+#include <string.h>
+
+HDDEDATA CALLBACK DdeCallback(WORD wType, WORD wFmt, HCONV hConv, HSZ hszTopic,
+ HSZ hszItem, HDDEDATA hData, DWORD lData1, DWORD lData2);
+VOID PaintDemo(HWND hwnd);
+LONG FAR PASCAL MainWndProc(HWND hwnd, UINT message, WPARAM wParam,
+ LONG lParam);
+
+/*
+ * Define this value to limit how fast data changes. If we just let data
+ * change as fast a possible, we might bog down the system with DDE
+ * messages.
+ */
+#define BASE_TIMEOUT 100
+
+BOOL fActive; // indicates data is changing
+DWORD idInst = 0; // our DDEML instance object
+HANDLE hInst; // our instance/module handle
+HCONVLIST hConvList = 0; // the list of all convs we have open
+HSZ hszAppName = 0; // the generic hsz for everything
+HWND hwndMain; // our main window handle
+TCHAR szT[20]; // static buffer for painting
+TCHAR szTitle[] = "DDEmo"; // the generic string for everything
+UINT OurFormat; // our custom registered format
+int InCount = 0; // static buffer to hold incomming data
+int cConvs = 0; // number of active conversations
+int count = 0; // our data
+int cyText, cxText, cyTitle; // sizes for painting
+
+int PASCAL WinMain(
+HANDLE hInstance,
+HANDLE hPrevInstance,
+LPSTR lpCmdLine,
+INT nCmdShow)
+{
+ MSG msg;
+ WNDCLASS wc;
+ TEXTMETRIC metrics;
+ HDC hdc;
+
+ if(!hPrevInstance) {
+ wc.style = 0;
+ wc.lpfnWndProc = MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szTitle;
+
+ if (!RegisterClass(&wc))
+ return(FALSE);
+ }
+
+ /*
+ * Here we tell DDEML what we will be doing.
+ *
+ * 1) We let it know our callback proc address - MakeProcInstance
+ * is called just to be more portable.
+ * 2) Filter-inits - don't accept any WM_DDE_INITIATE messages for
+ * anything but our registered service name.
+ * 3) Don't bother to notify us of confirmed connections
+ * 4) Don't allow connections with ourselves.
+ * 5) Don't bother us with XTYP_POKE transactions.
+ */
+ if (DdeInitialize(&idInst,
+ (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback, hInstance),
+ APPCMD_FILTERINITS |
+ CBF_SKIP_CONNECT_CONFIRMS |
+ CBF_FAIL_SELFCONNECTIONS |
+ CBF_FAIL_POKES,
+ 0))
+ return(FALSE);
+
+ hInst = hInstance;
+ hwndMain = CreateWindow(
+ szTitle,
+ szTitle,
+ WS_CAPTION | WS_BORDER | WS_SYSMENU,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ hInstance,
+ NULL
+ );
+
+ if (!hwndMain) {
+ DdeUninitialize(idInst);
+ return(FALSE);
+ }
+
+ hdc = GetDC(hwndMain);
+ GetTextMetrics(hdc, &metrics);
+ cyText = metrics.tmHeight + metrics.tmExternalLeading;
+ cxText = metrics.tmMaxCharWidth * 8;
+ cyTitle = GetSystemMetrics(SM_CYCAPTION);
+ ReleaseDC(hwndMain, hdc);
+
+ SetWindowPos(hwndMain, 0, 0, 0, cxText, cyText + cyTitle,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
+ ShowWindow(hwndMain, nCmdShow);
+ UpdateWindow(hwndMain);
+
+ /*
+ * Initialize all our string handles for lookups later
+ */
+ hszAppName = DdeCreateStringHandle(idInst, szTitle, 0);
+ /*
+ * Register our formats
+ */
+ OurFormat = RegisterClipboardFormat(szTitle);
+ /*
+ * Connect to any other instances of ourselves that may already be
+ * running.
+ */
+ hConvList = DdeConnectList(idInst, hszAppName, hszAppName, hConvList, NULL);
+ /*
+ * Register our service -
+ * This will cause DDEML to notify DDEML clients about the existance
+ * of a new DDE service.
+ */
+ DdeNameService(idInst, hszAppName, 0, DNS_REGISTER);
+
+ while (GetMessage(&msg, 0, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ DestroyWindow(hwndMain);
+ UnregisterClass(szTitle, hInstance);
+ return(FALSE);
+}
+
+
+/*
+ * BroadcastTransaction
+ *
+ * Does the specified transaction on all conversations in hConvList
+ */
+VOID BroadcastTransaction(
+PBYTE pSrc,
+DWORD cbData,
+UINT fmt,
+UINT xtyp)
+{
+ HCONV hConv;
+ DWORD dwResult;
+ int cConvsOrg;
+ HSZ hsz;
+
+ cConvsOrg = cConvs;
+ cConvs = 0;
+ if (hConvList) {
+ /*
+ * Enumerate all the conversations within this list - note that
+ * DDEML will only return active conversations. Inactive conversations
+ * are automatically removed.
+ */
+ hConv = DdeQueryNextServer(hConvList, NULL);
+ while (hConv) {
+ /*
+ * Count the active conversations while we're at it.
+ */
+ cConvs++;
+ /*
+ * Spawn an asynchronous transaction - this was chosen because
+ * we have not particular action if an error ocurrs so we just
+ * don't care too much about the results - this technique will
+ * NOT do for XTYP_REQUEST transactions though.
+ */
+
+ if (!fmt) hsz=NULL;
+ else hsz=hszAppName;
+
+ if (DdeClientTransaction(pSrc, cbData, hConv, hsz, fmt,
+ xtyp, TIMEOUT_ASYNC, &dwResult)) {
+ /*
+ * We immediately abandon the transaction so we don't get
+ * a bothersome XTYP_XACT_COMPLETE callback which we don't
+ * care about.
+ */
+ DdeAbandonTransaction(idInst, hConv, dwResult);
+ }
+
+ hConv = DdeQueryNextServer(hConvList, hConv);
+ }
+ }
+ if (cConvs != cConvsOrg) {
+ /*
+ * Oh, the number of active conversations has changed. Time to
+ * repaint!
+ */
+ InvalidateRect(hwndMain, NULL, TRUE);
+ }
+}
+
+
+/*
+ * MyProcessKey
+ *
+ * We demonstrate the robustness of NT here by forcing a GP anytime the
+ * 'B' key is pressed while this window has the focus. NT should properly
+ * fake termination to all other apps connected to us.
+ */
+VOID MyProcessKey(
+TCHAR tchCode,
+LONG lKeyData)
+{
+ switch (tchCode) {
+ case 'B':
+ case 'b':
+ *((PBYTE)(-1)) = 0; // Cause GP fault!
+ break;
+ }
+}
+
+
+
+LONG FAR PASCAL MainWndProc(
+HWND hwnd,
+UINT message,
+WPARAM wParam,
+LONG lParam)
+{
+ RECT rc;
+
+ switch (message) {
+ case WM_CREATE:
+ /*
+ * initially we are inactive - this reduces some of the message
+ * traffic while we are initializing - but we could start active fine.
+ */
+ fActive = FALSE;
+ break;
+
+ case WM_RBUTTONDOWN:
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ /*
+ * A CTRL R_BUTTON click will cause ALL instances of this app
+ * to become inactive.
+ */
+ BroadcastTransaction("PAUSE", 6, 0, XTYP_EXECUTE);
+ MessageBeep(0);
+ }
+ /*
+ * A R_BUTTON click makes us inactive. Repaint to show state change.
+ * We do a synchronous update in case there is too much DDE message
+ * activity to allow the WM_PAINT messages through. Remember DDE
+ * messages have priority over others!
+ */
+ KillTimer(hwndMain, 1);
+ fActive = FALSE;
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ break;
+
+ case WM_LBUTTONDOWN:
+ if (GetKeyState(VK_CONTROL) & 0x8000) {
+ /*
+ * A CTRL L_BUTTON click will cause ALL instances of this app
+ * to become active.
+ */
+ BroadcastTransaction("RESUME", 7, 0, XTYP_EXECUTE);
+ MessageBeep(0);
+ }
+ /*
+ * An L_BUTTON click makes us active. Repaint to show state change.
+ */
+ SetTimer(hwndMain, 1, BASE_TIMEOUT + (rand() & 0xff), NULL);
+ fActive = TRUE;
+ InvalidateRect(hwnd, NULL, TRUE);
+ UpdateWindow(hwnd);
+ break;
+
+ case WM_CHAR:
+ MyProcessKey((TCHAR)wParam, lParam);
+ break;
+
+ case WM_TIMER:
+ /*
+ * We use timers for simplicity. On Win3.1 we could run out of
+ * timers easily but we don't have this worry on NT.
+ *
+ * Each tick, we increment our data and call DdePostAdvise() to
+ * update any links there may be on this data. DDEML makes link
+ * updates on specific items quite easy.
+ */
+ count++;
+ DdePostAdvise(idInst, hszAppName, hszAppName);
+ /*
+ * Invalidate the part of ourselves that shows our data and
+ * synchronously update it in case DDE message activity is blocking
+ * paints.
+ */
+ SetRect(&rc, 0, 0, cxText, cyText);
+ InvalidateRect(hwndMain, &rc, TRUE);
+ UpdateWindow(hwndMain);
+ break;
+
+ case WM_PAINT:
+ PaintDemo(hwnd);
+ break;
+
+ case WM_CLOSE:
+ KillTimer(hwnd, 1);
+ /*
+ * We do DDE cleanup here. It is best to do DDE cleanup while
+ * still in the message loop to allow DDEML to recieve messages
+ * while shutting down.
+ */
+ DdeDisconnectList(hConvList);
+ DdeNameService(idInst, 0, 0, DNS_UNREGISTER);
+ DdeFreeStringHandle(idInst, hszAppName);
+ DdeUninitialize(idInst);
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return (DefWindowProc(hwnd, message, wParam, lParam));
+ }
+ return(0);
+}
+
+
+VOID PaintDemo(
+HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ RECT rc;
+ HCONV hConv;
+ CONVINFO ci;
+ int cConvsOrg = cConvs;
+
+ BeginPaint(hwnd, &ps);
+ /*
+ * Draw our data on top - Black for active, Grey for inactive.
+ */
+ SetRect(&rc, 0, 0, cxText, cyText);
+ SetBkMode(ps.hdc, TRANSPARENT);
+ SetTextColor(ps.hdc, 0x00FFFFFF); // white text
+ FillRect(ps.hdc, &rc, GetStockObject(fActive ? BLACK_BRUSH : GRAY_BRUSH));
+ DrawText(ps.hdc, itoa(count, szT, 10), -1, &rc, DT_CENTER | DT_VCENTER);
+
+ /*
+ * Now draw the most recently recieved data from each server we are
+ * connected to.
+ */
+ if (hConvList) {
+ OffsetRect(&rc, 0, cyText);
+ SetTextColor(ps.hdc, 0); // draw black text
+ cConvs = 0;
+ hConv = DdeQueryNextServer(hConvList, NULL);
+ while (hConv) {
+ cConvs++;
+ /*
+ * count how many conversations are active while we're at it.
+ */
+ ci.cb = sizeof(CONVINFO);
+ DdeQueryConvInfo(hConv, QID_SYNC, &ci);
+ FillRect(ps.hdc, &rc, GetStockObject(WHITE_BRUSH)); // white bkgnd
+ DrawText(ps.hdc, itoa(ci.hUser, szT, 10), -1, &rc,
+ DT_CENTER | DT_VCENTER);
+ OffsetRect(&rc, 0, cyText);
+ hConv = DdeQueryNextServer(hConvList, hConv);
+ }
+ }
+ EndPaint(hwnd, &ps);
+ if (cConvsOrg != cConvs) {
+ /*
+ * The number of active conversations changed! Resize to fit.
+ */
+ SetWindowPos(hwndMain, 0, 0, 0, cxText,
+ (cyText * (cConvs + 1)) + cyTitle,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+}
+
+
+
+/*
+ * This is the main DDEML callback proc. It handles all interaction with
+ * DDEML that is DDEML originated.
+ */
+HDDEDATA CALLBACK DdeCallback(
+WORD wType,
+WORD wFmt,
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+HDDEDATA hData,
+DWORD lData1,
+DWORD lData2)
+{
+ LPTSTR pszExec;
+
+ switch (wType) {
+ case XTYP_CONNECT:
+ /*
+ * Only allow connections to us. We can always return TRUE because
+ * the CBF_FILTERINITS bit given to DdeInitialize() told DDEML to
+ * never bother us with connections to any service names other than
+ * what we have registered.
+ *
+ * Note that we do not handle the XTYP_WILD_CONNECT transaction.
+ * This means that no wild-card initiates to us will work.
+ */
+ return(TRUE);
+
+ case XTYP_ADVREQ:
+ case XTYP_REQUEST:
+ /*
+ * These two transactions are the only ones that require us to
+ * render our data. By using a custom format, we don't have to
+ * convert our count to text form to support CF_TEXT.
+ */
+ return(DdeCreateDataHandle(idInst, (PBYTE)&count, sizeof(count), 0,
+ hszAppName, OurFormat, 0));
+
+ case XTYP_ADVSTART:
+ /*
+ * Only allow links to our Item in our format.
+ */
+ return((UINT)wFmt == OurFormat && hszItem == hszAppName);
+
+ case XTYP_ADVDATA:
+ /*
+ * Data is comming in. We don't bother with XTYP_POKE transactions,
+ * but if we did, they would go here. Since we only allow links
+ * on our item and our format, we need not check these here.
+ */
+ if (DdeGetData(hData, (PBYTE)&InCount, sizeof(InCount), 0)) {
+ DdeSetUserHandle(hConv, QID_SYNC, InCount);
+ }
+ /*
+ * update ourselves to reflect the new incomming data.
+ */
+ InvalidateRect(hwndMain, NULL, TRUE);
+ /*
+ * This transaction requires a flag return value. We could also
+ * stick other status bits here if needed but its not recommended.
+ */
+ return(DDE_FACK);
+
+ case XTYP_EXECUTE:
+ /*
+ * Another instance wants us to do something. DdeAccessData()
+ * makes parsing of execute strings easy. Also note, that DDEML
+ * will automatically give us the string in the right form
+ * (UNICODE vs ASCII) depending on which form of DdeInitialize()
+ * we called.
+ */
+ pszExec = DdeAccessData(hData, NULL);
+ if (pszExec) {
+
+#ifdef WIN16
+ if (fActive && !_fstricmp((LPSTR)"PAUSE", pszExec)) {
+#else
+ if (fActive && !stricmp((LPSTR)"PAUSE", pszExec)) {
+#endif
+ KillTimer(hwndMain, 1);
+ fActive = FALSE;
+ InvalidateRect(hwndMain, NULL, TRUE);
+ UpdateWindow(hwndMain);
+#ifdef WIN16
+ } else if (!fActive && !_fstricmp((LPSTR)"RESUME", pszExec)) {
+#else
+ } else if (!fActive && !stricmp((LPSTR)"RESUME", pszExec)) {
+#endif
+ SetTimer(hwndMain, 1, BASE_TIMEOUT + (rand() & 0xff), NULL);
+ fActive = TRUE;
+ InvalidateRect(hwndMain, NULL, TRUE);
+ UpdateWindow(hwndMain);
+ }
+ /*
+ * The beep gives good feedback on how fast the execute was.
+ */
+ MessageBeep(0);
+ }
+ break;
+
+ case XTYP_DISCONNECT:
+ /*
+ * Somebody went away, repaint so we update our cConvs count.
+ */
+ InvalidateRect(hwndMain, NULL, TRUE);
+ break;
+
+ case XTYP_REGISTER:
+ /*
+ * Since a new server just arrived, lets make sure our links are
+ * up to date. Note that only one link on a
+ * conversation/topic/item/format set will work anyway so we don't
+ * worry about duplicate links.
+ *
+ * Note also that we are using hszItem - which is the InstanceSpecific
+ * name of the server that is registering. This greatly reduces the
+ * number of messages that go flying around.
+ */
+ hConvList = DdeConnectList(idInst, hszItem, hszAppName, hConvList, NULL);
+ BroadcastTransaction(NULL, 0, OurFormat, XTYP_ADVSTART);
+ SetWindowPos(hwndMain, 0, 0, 0, cxText,
+ (cyText * (cConvs + 1)) + cyTitle, SWP_NOMOVE | SWP_NOZORDER);
+ UpdateWindow(hwndMain);
+ return(TRUE);
+ }
+ return(0);
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.def b/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.def
new file mode 100644
index 000000000..bf0959a36
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/ddemo.def
@@ -0,0 +1,17 @@
+NAME DDEMO
+
+DESCRIPTION 'Microsoft Windows DDEML App'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 8192
+STACKSIZE 16384
+
+EXPORTS
+ MainWndProc @1
+ DdeCallback @2
diff --git a/private/mvdm/wow16/ddeml/tests/src/ddemo/makefile b/private/mvdm/wow16/ddeml/tests/src/ddemo/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/makefile
@@ -0,0 +1,6 @@
+#
+# 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/wow16/ddeml/tests/src/ddemo/makefile.dos b/private/mvdm/wow16/ddeml/tests/src/ddemo/makefile.dos
new file mode 100644
index 000000000..82959b26e
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/makefile.dos
@@ -0,0 +1,24 @@
+#
+# Test makefile
+
+!ifdef WIN31
+EXEFLAGS=-AS -Gsw -Od -Ziep -W3 -DWIN16 -DWIN31 -DUSECOMM -DWIN -DTCHAR=char -DINT=int -DLPTSTR=LPSTR
+!else
+EXEFLAGS=-AS -FPi -Gcw -Os -Ziepd -W3 -DWIN16 -DWIN -DTCHAR=char -DINT=int -DLPTSTR=LPSTR
+!endif
+
+OBJ =ddemo.obj
+
+#
+# Stress Test
+#
+
+all: ddemo.exe
+
+ddemo.obj: ddemo.c
+ cl -c $(EXEFLAGS) ddemo.c
+
+ddemo.exe: $(OBJ) ddemo.def
+ link /map/li/co $(OBJ)/AL:16,ddemo.exe,, /NOE /NOD libw ddeml slibcew,ddemo.def
+ mapsym ddemo
+ rc -DWIN16 ddemo.exe
diff --git a/private/mvdm/wow16/ddeml/tests/src/ddemo/mk4dos.cmd b/private/mvdm/wow16/ddeml/tests/src/ddemo/mk4dos.cmd
new file mode 100644
index 000000000..1cc3f8bff
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/mk4dos.cmd
@@ -0,0 +1,13 @@
+@echo off
+if "%1"=="" goto bld
+del *.dll
+del *.sym
+del *.map
+del *.obj
+del *.bak
+del *.res
+del *.lnk
+goto done
+:bld
+nmake -f makefile.dos
+:done
diff --git a/private/mvdm/wow16/ddeml/tests/src/ddemo/sources b/private/mvdm/wow16/ddeml/tests/src/ddemo/sources
new file mode 100644
index 000000000..126b03c24
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/ddemo/sources
@@ -0,0 +1,19 @@
+
+MAJORCOMP=samples
+MINORCOMP=ddemo
+
+TARGETNAME=ddemo
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+INCLUDES=.
+
+SOURCES= ddemo.c
+
+C_DEFINES=-DWIN32
+
+UMTYPE=windows
+UMAPPL=ddemo
+UMENTRY=winmain
+UMLIBS=obj\*\ddemo.lib $(BASEDIR)\public\sdk\lib\*\ntcrt.lib
diff --git a/private/mvdm/wow16/ddeml/tests/src/dirs b/private/mvdm/wow16/ddeml/tests/src/dirs
new file mode 100644
index 000000000..f59905286
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/dirs
@@ -0,0 +1,4 @@
+
+DIRS= client \
+ server
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/makedos.bat b/private/mvdm/wow16/ddeml/tests/src/makedos.bat
new file mode 100644
index 000000000..4204a0d0d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/makedos.bat
@@ -0,0 +1,11 @@
+CD Client
+NMake /f MakeFile.DOS %1 %2 %3
+CD ..
+
+CD DDEMO
+NMake /f MakeFile.DOS %1 %2 %3
+CD ..
+
+CD Server
+NMake /f MakeFile.DOS %1 %2 %3
+CD ..
diff --git a/private/mvdm/wow16/ddeml/tests/src/mls.cmd b/private/mvdm/wow16/ddeml/tests/src/mls.cmd
new file mode 100644
index 000000000..62631a320
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/mls.cmd
@@ -0,0 +1,2 @@
+start client\obj\i386\ddemlcl.exe
+start server\obj\i386\ddemlsv.exe
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/dde.c b/private/mvdm/wow16/ddeml/tests/src/server/dde.c
new file mode 100644
index 000000000..c8a0bf05d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/dde.c
@@ -0,0 +1,674 @@
+/*
+ * This module serves to demonstrate one way a sophisticated DDE server
+ * that uses enumerable topics and items might be implemented. It takes
+ * full advantage of appowned data handles (when fAppowned is set) to
+ * minimize the need for repeated rendering of data when shared with
+ * multiple clients.
+ *
+ * The server supports full system topic information plus help and non
+ * system topic item enumeration for the benefit of browsing clients
+ * that are wondering what's around.
+ *
+ * This server can be made secure by altering the conversation context
+ * filter.
+ *
+ * This server can appear to support alternate codepages and languages
+ * by altering the conversation context filter. On Windows this is
+ * pretty much moot since there is not yet a clearly defined way of
+ * doing international communication and because the atom manager restricts
+ * what topic and item strings can be used on the system.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "server.h"
+#include "huge.h"
+
+/*
+ * This function verifies that the incomming conversation context fits the
+ * server's context filter's requirements.
+ */
+BOOL ValidateContext(
+PCONVCONTEXT pCC)
+{
+ // make sure our CCFilter allows it...mock security, language support
+ // old DDE app client case...pCC == NULL
+ if (pCC == NULL &&
+ CCFilter.dwSecurity == 0 && // were nonsecure
+ CCFilter.iCodePage == CP_WINANSI // were normal cp
+ ) {
+ return(TRUE);
+ }
+
+ if (pCC &&
+ pCC->wFlags == CCFilter.wFlags && // no special flags needed
+ pCC->iCodePage == CCFilter.iCodePage && // codepages match
+ pCC->dwSecurity == CCFilter.dwSecurity) { // security passes
+ // dont care about language and country.
+ return(TRUE);
+ }
+ return(FALSE); // disallow no match
+}
+
+
+/***************************** Public Function ****************************\
+*
+* This function is called by the DDE manager DLL and passes control onto
+* the apropriate function pointed to by the global topic and item arrays.
+* It handles all DDE interaction generated by external events.
+*
+\***************************************************************************/
+HDDEDATA CALLBACK DdeCallback(
+WORD wType,
+WORD wFmt,
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+HDDEDATA hData,
+DWORD lData1,
+DWORD lData2)
+{
+ WORD i, j;
+ register ITEMLIST *pItemList;
+ WORD cItems, iFmt;
+ HDDEDATA hDataRet;
+
+ /*
+ * Block this callback if its blockable and we are supposed to.
+ */
+ if (fBlockNextCB && !(wType & XTYPF_NOBLOCK)) {
+ fBlockNextCB = FALSE;
+ fAllEnabled = FALSE;
+ return(CBR_BLOCK);
+ }
+
+ /*
+ * Block this callback if its associated with a conversation and we
+ * are supposed to.
+ */
+ if (fTermNextCB && hConv) {
+ fTermNextCB = FALSE;
+ DdeDisconnect(hConv);
+ wType = XTYP_DISCONNECT;
+ }
+
+ /*
+ * Keep a count of connections
+ */
+ if (wType == XTYP_CONNECT_CONFIRM) {
+ cServers++;
+ InvalidateRect(hwndServer, &rcConnCount, TRUE);
+ return(0);
+ }
+ if (wType == XTYP_DISCONNECT) {
+ cServers--;
+ InvalidateRect(hwndServer, &rcConnCount, TRUE);
+ return(0);
+ }
+
+
+ /*
+ * only allow transactions on the formats we support if they have a format.
+ */
+ if (wFmt) {
+ for (iFmt = 0; iFmt < CFORMATS; iFmt++) {
+ if (wFmt == aFormats[iFmt].atom)
+ break;
+ }
+ if (iFmt == CFORMATS)
+ return(0); // illegal format - ignore now.
+ }
+
+ /*
+ * Executes are allowed only on the system topic. This is a general
+ * convention, not a requirement.
+ *
+ * Any executes received result in the execute text being shown in
+ * the server client area. No real action is taken.
+ */
+ if (wType == XTYP_EXECUTE) {
+ if (hszTopic == topicList[0].hszTopic) { // must be on system topic
+ // Format is assumed to be CF_TEXT.
+ DdeGetData(hData, (LPBYTE)szExec, MAX_EXEC, 0);
+ szExec[MAX_EXEC - 1] = '\0';
+ InvalidateRect(hwndServer, &rcExec, TRUE);
+ hDataRet = TRUE;
+ goto ReturnSpot;
+ }
+ pszComment = "Execute received on non-system topic - ignored";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ return(0);
+ }
+
+ /*
+ * Process wild initiates here
+ */
+ if (wType == XTYP_WILDCONNECT) {
+ HSZ ahsz[(CTOPICS + 1) * 2];
+ /*
+ * He wants a hsz list of all our available app/topic pairs
+ * that conform to hszTopic and hszItem(App).
+ */
+
+ if (!ValidateContext((PCONVCONTEXT)lData1)) {
+ return(FALSE);
+ }
+
+ if (hszItem != hszAppName && hszItem != 0) {
+ // we only support the hszAppName service
+ return(0);
+ }
+
+ // scan the topic table and create hsz pairs
+ j = 0;
+ for (i = 0; i < CTOPICS; i++) {
+ if (hszTopic == 0 || hszTopic == topicList[i].hszTopic) {
+ ahsz[j++] = hszAppName;
+ ahsz[j++] = topicList[i].hszTopic;
+ }
+ }
+
+ // cap off the list with 0s
+ ahsz[j++] = ahsz[j++] = 0L;
+
+ // send it back
+ return(DdeCreateDataHandle(idInst, (LPBYTE)&ahsz[0], sizeof(HSZ) * j, 0L, 0, wFmt, 0));
+ }
+
+ /*
+ * Check our hsz tables and send to the apropriate proc. to process.
+ * We use DdeCmpStringHandles() which is the portable case-insensitive
+ * method of comparing string handles. (this is a macro on windows so
+ * there is no real speed hit.) On WINDOWS, HSZs are case-insensitive
+ * anyway, but this may not be the case on other platforms.
+ */
+ for (i = 0; i < CTOPICS; i++) {
+ if (DdeCmpStringHandles(topicList[i].hszTopic, hszTopic) == 0) {
+
+ /*
+ * connections must be on a topic we support.
+ */
+ if (wType == XTYP_CONNECT) {
+ return(ValidateContext((PCONVCONTEXT)lData1));
+ }
+
+ pItemList = topicList[i].pItemList;
+ cItems = topicList[i].cItems;
+ for (j = 0; j < cItems; j++) {
+ if (DdeCmpStringHandles(pItemList[j].hszItem, hszItem) == 0) {
+ XFERINFO xi;
+ /*
+ * Make call to worker function here...
+ */
+ xi.wType = wType;
+ xi.wFmt = wFmt;
+ xi.hConv = hConv;
+ xi.hszTopic = hszTopic;
+ xi.hszItem = hszItem;
+ xi.hData = hData;
+ xi.lData1 = lData1;
+ xi.lData2 = lData2;
+ hDataRet = (*pItemList[j].npfnCallback)(&xi, iFmt);
+
+ReturnSpot:
+ /*
+ * The table functions return a boolean or data.
+ * It gets translated here.
+ */
+ switch (wType & XCLASS_MASK) {
+ case XCLASS_DATA:
+ return(hDataRet);
+ break;
+ case XCLASS_FLAGS:
+ return(hDataRet ? DDE_FACK : DDE_FNOTPROCESSED);
+ break;
+ case XCLASS_BOOL:
+ return(TRUE);
+ default: // XCLASS_NOTIFICATION
+ return(0);
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ * anything else fails - DDEML is designed so that a 0 return is ALWAYS ok.
+ */
+ return(0);
+}
+
+
+
+
+
+/***************************** Private Function ****************************\
+* This passes out a standard tab-delimited list of topic names for this
+* application.
+*
+* This support is required for other apps to be able to
+* find out about us. This kind of support should be in every DDE
+* application.
+*
+\***************************************************************************/
+HDDEDATA TopicListXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ WORD cbAlloc, i;
+ LPSTR pszTopicList;
+ HDDEDATA hData;
+
+ if (pXferInfo->wType == XTYP_ADVSTART)
+ return(TRUE);
+
+ if (pXferInfo->wType != XTYP_REQUEST &&
+ pXferInfo->wType != XTYP_ADVREQ)
+ return(0);
+ /*
+ * construct the list of topics we have
+ */
+ cbAlloc = 0;
+ for (i = 0; i < CTOPICS; i++)
+ cbAlloc += lstrlen(topicList[i].pszTopic) + 1; // 1 for tab
+
+ // allocate a data handle big enough for the list.
+ hData = DdeCreateDataHandle(idInst, NULL, 0, cbAlloc, pXferInfo->hszItem,
+ pXferInfo->wFmt, 0);
+ pszTopicList = (LPSTR)DdeAccessData(hData, NULL);
+ if (pszTopicList) {
+ for (i = 0; i < CTOPICS; i++) {
+ _fstrcpy(pszTopicList, topicList[i].pszTopic);
+ pszTopicList += strlen(topicList[i].pszTopic);
+ *pszTopicList++ = '\t';
+ }
+ *--pszTopicList = '\0';
+ DdeUnaccessData(hData);
+ return(hData);
+ }
+ return(0);
+}
+
+
+
+
+/***************************** Private Function ****************************\
+* This passes out a standard tab-delimited list of item names for the
+* specified topic.
+*
+* This support is required for other apps to be able to
+* find out about us. This kind of support should be in every DDE
+* application.
+*
+\***************************************************************************/
+HDDEDATA ItemListXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ WORD cbAlloc, i, iItem, cItems;
+ ITEMLIST *pItemList = 0;
+ LPSTR pszItemList;
+ HDDEDATA hData;
+
+ if (pXferInfo->wType == XTYP_ADVSTART)
+ return(TRUE);
+
+ if (pXferInfo->wType != XTYP_REQUEST &&
+ pXferInfo->wType != XTYP_ADVREQ)
+ return(0);
+ /*
+ * construct the list of items we support for this topic - this supports
+ * more than the minimum standard which would support SysItems only on
+ * the system topic.
+ */
+
+ // locate the requested topic item table
+ for (i = 0; i < CTOPICS; i++) {
+ if (pXferInfo->hszTopic == topicList[i].hszTopic) {
+ pItemList = topicList[i].pItemList;
+ cItems = topicList[i].cItems;
+ break;
+ }
+ }
+
+ if (!pItemList)
+ return(0); // item not found
+
+ cbAlloc = 0;
+ for (iItem = 0; iItem < cItems; iItem++)
+ cbAlloc += lstrlen(pItemList[iItem].pszItem) + 1; // 1 for tab
+
+ // allocate a data handle big enough for the list.
+ hData = DdeCreateDataHandle(idInst, NULL, 0, cbAlloc, pXferInfo->hszItem,
+ pXferInfo->wFmt, 0);
+ pszItemList = (LPSTR)DdeAccessData(hData, NULL);
+ if (pszItemList) {
+ for (i = 0; i < cItems; i++) {
+ _fstrcpy(pszItemList, pItemList[i].pszItem);
+ pszItemList += strlen(pItemList[i].pszItem);
+ *pszItemList++ = '\t';
+ }
+ *--pszItemList = '\0';
+ DdeUnaccessData(hData);
+ return(hData);
+ }
+ return(0);
+}
+
+
+
+
+
+/***************************** Private Function ****************************\
+* Gives out a 0 terminated array of dde format numbers supported by this app.
+*
+* This support is required for other apps to be able to
+* find out about us. This kind of support should be in every DDE
+* application.
+*
+\***************************************************************************/
+HDDEDATA sysFormatsXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ INT i, cb;
+ LPSTR psz, pszT;
+ HDDEDATA hData;
+
+ if (pXferInfo->wType == XTYP_ADVSTART)
+ return(TRUE);
+
+ if (pXferInfo->wType != XTYP_REQUEST &&
+ pXferInfo->wType != XTYP_ADVREQ)
+ return(0);
+
+ for (i = 0, cb = 0; i < CFORMATS; i++)
+ cb += strlen(aFormats[i].sz) + 1;
+
+ hData = DdeCreateDataHandle(idInst, NULL, (DWORD)cb,
+ 0L, pXferInfo->hszItem, pXferInfo->wFmt, 0);
+ psz = pszT = DdeAccessData(hData, NULL);
+ for (i = 0; i < CFORMATS; i++) {
+ _fstrcpy(pszT, aFormats[i].sz);
+ pszT += _fstrlen(pszT);
+ *pszT++ = '\t';
+ }
+ *(--pszT) = '\0';
+ DdeUnaccessData(hData);
+ return(hData);
+}
+
+
+
+/*
+ * This is a runaway item. Each time it is requested, it changes.
+ * pokes just make it change again.
+ */
+HDDEDATA TestRandomXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ CHAR szT[10]; // SS==DS!
+ LPSTR pszData;
+ HDDEDATA hData;
+ WORD i;
+
+ switch (pXferInfo->wType) {
+ case XTYP_POKE:
+ // we expect an ascii number to replace the current seed.
+ pszComment = "Rand poke received.";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ InvalidateRect(hwndServer, &rcRand, TRUE);
+ if (DdeGetData(pXferInfo->hData, szT, 10, 0)) {
+ szT[9] = '\0'; // just incase we overran.
+ sscanf(szT, "%d", &seed);
+ for (i = 0; i < CFORMATS; i++) {
+ if (hDataRand[i])
+ DdeFreeDataHandle(hDataRand[i]);
+ hDataRand[i] = 0;
+ }
+ DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem);
+ return(1);
+ }
+ break;
+
+ case XTYP_REQUEST:
+ pszComment = "Rand data requested.";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ case XTYP_ADVREQ:
+ Delay(RenderDelay, FALSE);
+ if (!hDataRand[iFmt]) {
+ hDataRand[iFmt] = DdeCreateDataHandle(idInst, NULL, 0, 10, pXferInfo->hszItem,
+ pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0);
+ if (pszData = DdeAccessData(hDataRand[iFmt], NULL)) {
+ wsprintf(pszData, "%d", seed);
+ DdeUnaccessData(hDataRand[iFmt]);
+ }
+ }
+ hData = hDataRand[iFmt];
+ if (!fAppowned)
+ hDataRand[iFmt] = 0;
+ return(hData);
+ break;
+
+ case XTYP_ADVSTART:
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * This is a runaway item. Each time it is requested, it changes.
+ * pokes just make it change again.
+ */
+HDDEDATA TestCountXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ CHAR szT[16]; // SS==DS!
+ LPSTR pszData;
+ HDDEDATA hData;
+ WORD i;
+
+ switch (pXferInfo->wType) {
+ case XTYP_POKE:
+ // we expect an ascii number to replace the current count.
+ pszComment = "Count poke received";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ InvalidateRect(hwndServer, &rcCount, TRUE);
+ if (DdeGetData(pXferInfo->hData, szT, 10, 0)) {
+ szT[9] = '\0'; // just incase we overran.
+ sscanf(szT, "%ld", &count);
+ for (i = 0; i < CFORMATS; i++) {
+ if (hDataCount[i])
+ DdeFreeDataHandle(hDataCount[i]);
+ hDataCount[i] = 0;
+ }
+ DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem);
+ return(1);
+ }
+ break;
+
+ case XTYP_REQUEST:
+ pszComment = "Count data requested.";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ case XTYP_ADVREQ:
+ Delay(RenderDelay, FALSE);
+ if (!hDataCount[iFmt]) {
+ hDataCount[iFmt] = DdeCreateDataHandle(idInst, NULL, 0, 10, pXferInfo->hszItem,
+ pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0);
+ if (pszData = DdeAccessData(hDataCount[iFmt], NULL)) {
+ wsprintf(pszData, "%ld", count);
+ DdeUnaccessData(hDataCount[iFmt]);
+ }
+ }
+ hData = hDataCount[iFmt];
+ if (!fAppowned)
+ hDataCount[iFmt] = 0;
+ return(hData);
+ break;
+
+ case XTYP_ADVSTART:
+ return(1);
+ }
+ return(0);
+}
+
+
+/*
+ * This is not a runaway item. Only Pokes make it change.
+ */
+HDDEDATA TestHugeXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ BOOL fSuccess;
+ DWORD ulcb;
+ LPBYTE lpData;
+ WORD i;
+ HDDEDATA hData;
+
+ switch (pXferInfo->wType) {
+ case XTYP_POKE:
+ ulcb = DdeGetData(pXferInfo->hData, NULL, 0, 0);
+ fSuccess = CheckHugeData(pXferInfo->hData);
+ if (fSuccess) {
+ pszComment = "Huge poke data successfully received.";
+ } else {
+ wsprintf(szComment, "%ld bytes of invalid Huge data received.", ulcb);
+ pszComment = szComment;
+ }
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ InvalidateRect(hwndServer, &rcHugeSize, TRUE);
+ if (fSuccess) {
+ for (i = 0; i < CFORMATS; i++) {
+ if (hDataHuge[i]) {
+ DdeFreeDataHandle(hDataHuge[i]);
+ hDataHuge[i] = 0;
+ }
+ }
+ /*
+ * Since callback data handles are only good for the duration of
+ * the callback, we must copy the data to our own data handle.
+ */
+ lpData = DdeAccessData(pXferInfo->hData, &cbHuge);
+ hDataHuge[iFmt] = DdeCreateDataHandle(idInst, lpData, cbHuge, 0,
+ pXferInfo->hszItem, pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0);
+ DdeUnaccessData(pXferInfo->hData);
+ DdePostAdvise(idInst, pXferInfo->hszTopic, pXferInfo->hszItem);
+ }
+ return(fSuccess);
+ break;
+
+ case XTYP_REQUEST:
+ pszComment = "Huge data requested.";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ case XTYP_ADVREQ:
+ Delay(RenderDelay, FALSE);
+ if (!hDataHuge[iFmt]) {
+ cbHuge = (DWORD)rand() * 64L + 0x10000L;
+ wsprintf(szComment, "Generating huge data - length=%ld...", cbHuge);
+ pszComment = szComment;
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ UpdateWindow(hwndServer);
+ hDataHuge[iFmt] = CreateHugeDataHandle(cbHuge, 4325, 345, 5,
+ pXferInfo->hszItem,
+ pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0);
+ pszComment = "";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ InvalidateRect(hwndServer, &rcHugeSize, TRUE);
+ }
+ hData = hDataHuge[iFmt];
+ if (!fAppowned)
+ hDataHuge[iFmt] = 0;
+ return(hData);
+ break;
+
+ case XTYP_ADVSTART:
+ return(1);
+ }
+ return(0);
+}
+
+
+HDDEDATA HelpXfer(
+PXFERINFO pXferInfo,
+WORD iFmt)
+{
+ HDDEDATA hData;
+
+ switch (pXferInfo->wType) {
+ case XTYP_REQUEST:
+ pszComment = "Help text requested.";
+ InvalidateRect(hwndServer, &rcComment, TRUE);
+ case XTYP_ADVREQ:
+ if (!hDataHelp[iFmt]) {
+ hDataHelp[iFmt] = DdeCreateDataHandle(idInst, szDdeHelp, strlen(szDdeHelp) + 1,
+ 0, pXferInfo->hszItem, pXferInfo->wFmt, fAppowned ? HDATA_APPOWNED : 0);
+ }
+ hData = hDataHelp[iFmt];
+ if (!fAppowned)
+ hDataHelp[iFmt] = 0;
+ return(hData);
+ break;
+
+ case XTYP_ADVSTART:
+ return(1);
+ }
+ return(0);
+}
+
+
+/***************************** Private Function ****************************\
+* This creates often used global hszs from standard global strings.
+* It also fills the hsz fields of the topic and item tables.
+*
+\***************************************************************************/
+VOID Hszize()
+{
+ register ITEMLIST *pItemList;
+ WORD iTopic, iItem;
+
+ hszAppName = DdeCreateStringHandle(idInst, szServer, 0);
+
+ for (iTopic = 0; iTopic < CTOPICS; iTopic++) {
+ topicList[iTopic].hszTopic =
+ DdeCreateStringHandle(idInst, topicList[iTopic].pszTopic, 0);
+ pItemList = topicList[iTopic].pItemList;
+ for (iItem = 0; iItem < topicList[iTopic].cItems; iItem++) {
+ pItemList[iItem].hszItem =
+ DdeCreateStringHandle(idInst, pItemList[iItem].pszItem, 0);
+ }
+ }
+}
+
+
+
+
+
+/***************************** Private Function ****************************\
+* This destroys often used global hszs from standard global strings.
+*
+\***************************************************************************/
+VOID UnHszize()
+{
+ register ITEMLIST *pItemList;
+ WORD iTopic, iItem;
+
+ DdeFreeStringHandle(idInst, hszAppName);
+
+ for (iTopic = 0; iTopic < CTOPICS; iTopic++) {
+ DdeFreeStringHandle(idInst, topicList[iTopic].hszTopic);
+ pItemList = topicList[iTopic].pItemList;
+ for (iItem = 0; iItem < topicList[iTopic].cItems; iItem++) {
+ DdeFreeStringHandle(idInst, pItemList[iItem].hszItem);
+ }
+ }
+}
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/ddemlsv.c b/private/mvdm/wow16/ddeml/tests/src/server/ddemlsv.c
new file mode 100644
index 000000000..16d79654d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/ddemlsv.c
@@ -0,0 +1,628 @@
+/****************************************************************************
+
+ PROGRAM: Server.c
+
+ PURPOSE: Server template for Windows applications
+
+ FUNCTIONS:
+
+ WinMain() - calls initialization function, processes message loop
+ InitApplication() - initializes window data and registers window
+ InitInstance() - saves instance handle and creates main window
+ MainWndProc() - processes messages
+ About() - processes messages for "About" dialog box
+
+ COMMENTS:
+
+ Windows can have several copies of your application running at the
+ same time. The variable hInst keeps track of which instance this
+ application is so that processing will be to the correct window.
+
+****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "server.h" /* specific to this program */
+#include "huge.h"
+
+DWORD idInst = 0;
+CONVCONTEXT CCFilter = { sizeof(CONVCONTEXT), 0, 0, 0, 0L, 0L };
+HANDLE hInst; /* current instance */
+HWND hwndServer;
+RECT rcRand;
+RECT rcCount;
+RECT rcComment;
+RECT rcExec;
+RECT rcConnCount;
+RECT rcRndrDelay;
+RECT rcRunaway;
+RECT rcAllBlock;
+RECT rcNextAction;
+RECT rcHugeSize;
+RECT rcAppowned;
+BOOL fAllBlocked = FALSE;
+BOOL fAllEnabled = TRUE;
+BOOL fEnableOneCB = FALSE;
+BOOL fBlockNextCB = FALSE;
+BOOL fTermNextCB = FALSE;
+BOOL fAppowned = FALSE;
+WORD cRunaway = 0;
+WORD RenderDelay = 0;
+DWORD count = 0;
+WORD seed = 0;
+HSZ hszAppName = 0;
+CHAR szClass[] = "ServerWClass";
+CHAR szTopic[MAX_TOPIC] = "Test";
+CHAR szServer[MAX_TOPIC] = "Server";
+CHAR szComment[MAX_COMMENT] = "";
+CHAR szExec[MAX_EXEC] = "";
+CHAR *pszComment = szComment;
+WORD cyText;
+WORD cServers = 0;
+HDDEDATA hDataHelp[CFORMATS] = {0};
+HDDEDATA hDataCount[CFORMATS] = {0};
+HDDEDATA hDataRand[CFORMATS] = {0};
+HDDEDATA hDataHuge[CFORMATS] = {0};
+DWORD cbHuge = 0;
+
+char szDdeHelp[] = "DDEML test server help:\r\n\n"\
+ "The 'Server'(service) and 'Test'(topic) names may change.\r\n\n"\
+ "Items supported under the 'Test' topic are:\r\n"\
+ "\tCount:\tThis value increments on each data change.\r\n"\
+ "\tRand:\tThis value is randomly generated each data change.\r\n"\
+ "\tHuge:\tThis is randomlly generated text data >64k that the\r\n"\
+ "\t\tDDEML test client can verify.\r\n"\
+ "The above items change after any request if in Runaway mode and \r\n"\
+ "can bo POKEed in order to change their values. POKEed Huge data \r\n"\
+ "must be in a special format to verify the correctness of the data \r\n"\
+ "or it will not be accepted.\r\n"\
+ "If the server is set to use app owned data handles, all data sent \r\n"\
+ "uses HDATA_APPOWNED data handles."\
+ ;
+
+FORMATINFO aFormats[CFORMATS] = {
+ { 0, "CF_TEXT" }, // exception! predefined format
+ { 0, "Dummy1" },
+ { 0, "Dummy2" },
+};
+
+
+/*
+ * Topic and Item tables supported by this application.
+ */
+
+/* HSZ PROCEDURE PSZ */
+
+ITEMLIST SystemTopicItemList[CSYSTEMITEMS] = {
+
+ { 0, TopicListXfer, SZDDESYS_ITEM_TOPICS },
+ { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS },
+ { 0, sysFormatsXfer, SZDDESYS_ITEM_FORMATS },
+ { 0, HelpXfer, SZDDESYS_ITEM_HELP},
+ };
+
+
+ITEMLIST TestTopicItemList[CTESTITEMS] = {
+
+ { 0, TestRandomXfer, "Rand" }, // 0 index
+ { 0, TestCountXfer, "Count"}, // 1 index
+ { 0, TestHugeXfer, "Huge" }, // 2 index
+ { 0, ItemListXfer, SZDDESYS_ITEM_SYSITEMS }, // 3 index
+ };
+
+
+/* The system topic is always assumed to be first. */
+/* HSZ PROCEDURE #ofITEMS PSZ */
+TOPICLIST topicList[CTOPICS] = {
+
+ { 0, SystemTopicItemList, CSYSTEMITEMS, SZDDESYS_TOPIC}, // 0 index
+ { 0, TestTopicItemList, CTESTITEMS, szTopic}, // 1 index
+ };
+
+
+
+
+
+
+/****************************************************************************
+
+ FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
+
+ PURPOSE: calls initialization function, processes message loop
+
+ COMMENTS:
+
+ Windows recognizes this function by name as the initial entry point
+ for the program. This function calls the application initialization
+ routine, if no other instance of the program is running, and always
+ calls the instance initialization routine. It then executes a message
+ retrieval and dispatch loop that is the top-level control structure
+ for the remainder of execution. The loop is terminated when a WM_QUIT
+ message is received, at which time this function exits the application
+ instance by returning the value passed by PostQuitMessage().
+
+ If this function must abort before entering the message loop, it
+ returns the conventional value NULL.
+
+****************************************************************************/
+
+MMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
+// HANDLE hInstance; /* current instance */
+// HANDLE hPrevInstance; /* previous instance */
+// LPSTR lpCmdLine; /* command line */
+// INT nCmdShow; /* show-window type (open/icon) */
+// {
+ MSG msg; /* message */
+
+ if (!hPrevInstance) /* Other instances of app running? */
+ if (!InitApplication(hInstance)) /* Initialize shared things */
+ return (FALSE); /* Exits if unable to initialize */
+
+ /* Perform initializations that apply to a specific instance */
+
+ if (!InitInstance(hInstance, nCmdShow))
+ return (FALSE);
+
+ /* Acquire and dispatch messages until a WM_QUIT message is received. */
+
+ while (GetMessage(&msg, /* message structure */
+ 0, /* handle of window receiving the message */
+ 0, /* lowest message to examine */
+ 0)) /* highest message to examine */
+ {
+ TranslateMessage(&msg); /* Translates virtual key codes */
+ DispatchMessage(&msg); /* Dispatches message to window */
+ }
+
+ UnregisterClass(szClass, hInstance);
+ return (msg.wParam); /* Returns the value from PostQuitMessage */
+}
+
+
+/****************************************************************************
+
+ FUNCTION: InitApplication(HANDLE)
+
+ PURPOSE: Initializes window data and registers window class
+
+ COMMENTS:
+
+ This function is called at initialization time only if no other
+ instances of the application are running. This function performs
+ initialization tasks that can be done once for any number of running
+ instances.
+
+ In this case, we initialize a window class by filling out a data
+ structure of type WNDCLASS and calling the Windows RegisterClass()
+ function. Since all instances of this application use the same window
+ class, we only need to do this when the first instance is initialized.
+
+
+****************************************************************************/
+
+BOOL InitApplication(hInstance)
+HANDLE hInstance; /* current instance */
+{
+ WNDCLASS wc;
+
+ /* Fill in window class structure with parameters that describe the */
+ /* main window. */
+
+ wc.style = 0; /* Class style(s). */
+ wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for */
+ /* windows of this class. */
+ wc.cbClsExtra = 0; /* No per-class extra data. */
+ wc.cbWndExtra = 0; /* No per-window extra data. */
+ wc.hInstance = hInstance; /* Application that owns the class. */
+ wc.hIcon = LoadIcon(hInstance, "server");
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HANDLE)(COLOR_APPWORKSPACE+1);
+ wc.lpszMenuName = "ServerMenu"; /* Name of menu resource in .RC file. */
+ wc.lpszClassName = "ServerWClass"; /* Name used in call to CreateWindow. */
+
+ /* Register the window class and return success/failure code. */
+
+ return (RegisterClass(&wc));
+
+}
+
+
+/****************************************************************************
+
+ FUNCTION: InitInstance(HANDLE, int)
+
+ PURPOSE: Saves instance handle and creates main window
+
+ COMMENTS:
+
+ This function is called at initialization time for every instance of
+ this application. This function performs initialization tasks that
+ cannot be shared by multiple instances.
+
+ In this case, we save the instance handle in a static variable and
+ create and display the main program window.
+
+****************************************************************************/
+
+BOOL InitInstance(hInstance, nCmdShow)
+ HANDLE hInstance; /* Current instance identifier. */
+ INT nCmdShow; /* Param for first ShowWindow() call. */
+{
+ INT i;
+ RECT Rect;
+ TEXTMETRIC metrics;
+ HDC hdc;
+
+ /* Save the instance handle in static variable, which will be used in */
+ /* many subsequence calls from this application to Windows. */
+
+ hInst = hInstance;
+
+
+ /* Create a main window for this application instance. */
+
+ hwndServer = CreateWindow(
+ "ServerWClass", /* See RegisterClass() call. */
+ "Server|Test",
+ WS_OVERLAPPEDWINDOW, /* Window style. */
+ CW_USEDEFAULT, /* Default horizontal position. */
+ CW_USEDEFAULT, /* Default vertical position. */
+ 400,
+ 200,
+ NULL, /* Overlapped windows have no parent. */
+ NULL, /* Use the window class menu. */
+ hInstance, /* This instance owns this window. */
+ NULL /* Pointer not needed. */
+ );
+
+ GetClientRect(hwndServer, (LPRECT) &Rect);
+
+ /* If window could not be created, return "failure" */
+
+ if (!hwndServer)
+ return (FALSE);
+
+ hdc = GetDC(hwndServer);
+ GetTextMetrics(hdc, &metrics);
+ cyText = metrics.tmHeight + metrics.tmExternalLeading;
+ ReleaseDC(hwndServer, hdc);
+
+ aFormats[0].atom = CF_TEXT; // exception - predefined.
+ for (i = 1; i < CFORMATS; i++) {
+ aFormats[i].atom = RegisterClipboardFormat(aFormats[i].sz);
+ }
+
+ /* Make the window visible; update its client area; and return "success" */
+
+ ShowWindow(hwndServer, nCmdShow); /* Show the window */
+ UpdateWindow(hwndServer); /* Sends WM_PAINT message */
+ seed = 1;
+ srand(1);
+ CCFilter.iCodePage = CP_WINANSI; // initial default codepage
+ if (!DdeInitialize(&idInst, (PFNCALLBACK)MakeProcInstance((FARPROC)DdeCallback,
+ hInstance), APPCMD_FILTERINITS, 0)) {
+ Hszize();
+ DdeNameService(idInst, hszAppName, 0, DNS_REGISTER);
+ return(TRUE);
+ }
+ return (FALSE);
+
+}
+
+/****************************************************************************
+
+ FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
+
+ PURPOSE: Processes messages
+
+ MESSAGES:
+
+ WM_COMMAND - application menu (About dialog box)
+ WM_DESTROY - destroy window
+
+ COMMENTS:
+
+ To process the IDM_ABOUT message, call MakeProcInstance() to get the
+ current instance address of the About() function. Then call Dialog
+ box which will create the box according to the information in your
+ server.rc file and turn control over to the About() function. When
+ it returns, free the intance address.
+
+****************************************************************************/
+
+LONG APIENTRY MainWndProc(hWnd, message, wParam, lParam)
+HWND hWnd; /* window handle */
+UINT message; /* type of message */
+WPARAM wParam; /* additional information */
+LONG lParam; /* additional information */
+{
+ switch (message) {
+ case WM_INITMENU:
+ if (GetMenu(hWnd) != (HMENU)wParam)
+ break;
+
+ CheckMenuItem((HMENU)wParam, IDM_BLOCKALLCBS,
+ fAllBlocked ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem((HMENU)wParam, IDM_UNBLOCKALLCBS,
+ fAllEnabled ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem((HMENU)wParam, IDM_BLOCKNEXTCB,
+ fBlockNextCB ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem((HMENU)wParam, IDM_TERMNEXTCB,
+ fTermNextCB ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem((HMENU)wParam, IDM_RUNAWAY,
+ cRunaway ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem((HMENU)wParam, IDM_APPOWNED,
+ fAppowned ? MF_CHECKED : MF_UNCHECKED);
+ break;
+
+ case WM_COMMAND: /* message: command from application menu */
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDM_ENABLEONECB:
+ DdeEnableCallback(idInst, 0, EC_ENABLEONE);
+ fAllBlocked = FALSE;
+ fAllEnabled = FALSE;
+ InvalidateRect(hwndServer, &rcAllBlock, TRUE);
+ break;
+
+ case IDM_TERMNEXTCB:
+ fTermNextCB = !fTermNextCB;
+ InvalidateRect(hwndServer, &rcNextAction, TRUE);
+ break;
+
+ case IDM_BLOCKNEXTCB:
+ fBlockNextCB = !fBlockNextCB;
+ InvalidateRect(hwndServer, &rcNextAction, TRUE);
+ break;
+
+ case IDM_BLOCKALLCBS:
+ DdeEnableCallback(idInst, 0, EC_DISABLE);
+ fAllBlocked = TRUE;
+ fAllEnabled = FALSE;
+ InvalidateRect(hwndServer, &rcAllBlock, TRUE);
+ break;
+
+ case IDM_UNBLOCKALLCBS:
+ DdeEnableCallback(idInst, 0, EC_ENABLEALL);
+ fAllEnabled = TRUE;
+ fAllBlocked = FALSE;
+ InvalidateRect(hwndServer, &rcAllBlock, TRUE);
+ break;
+
+ case IDM_APPOWNED:
+ fAppowned = !fAppowned;
+ if (!fAppowned) {
+ WORD iFmt;
+ for (iFmt = 0; iFmt < CFORMATS; iFmt++) {
+ if (hDataHuge[iFmt]) {
+ DdeFreeDataHandle(hDataHuge[iFmt]);
+ hDataHuge[iFmt] = 0;
+ InvalidateRect(hwndServer, &rcHugeSize, TRUE);
+ }
+ if (hDataCount[iFmt]) {
+ DdeFreeDataHandle(hDataCount[iFmt]);
+ hDataCount[iFmt] = 0;
+ }
+ if (hDataRand[iFmt]) {
+ DdeFreeDataHandle(hDataRand[iFmt]);
+ hDataRand[iFmt] = 0;
+ }
+ if (hDataHelp[iFmt]) {
+ DdeFreeDataHandle(hDataHelp[iFmt]);
+ hDataHelp[iFmt] = 0;
+ }
+ }
+ }
+ InvalidateRect(hwndServer, &rcAppowned, TRUE);
+ break;
+
+ case IDM_RUNAWAY:
+ cRunaway = !cRunaway;
+ InvalidateRect(hwndServer, &rcRunaway, TRUE);
+ if (!cRunaway) {
+ break;
+ }
+ // fall through
+
+ case IDM_CHANGEDATA:
+ PostMessage(hwndServer, UM_CHGDATA, 1, 0); // rand
+ PostMessage(hwndServer, UM_CHGDATA, 1, 1); // count
+ break;
+
+ case IDM_RENDERDELAY:
+ DoDialog("VALUEENTRY", (FARPROC)RenderDelayDlgProc, 0, TRUE);
+ InvalidateRect(hwndServer, &rcRndrDelay, TRUE);
+ break;
+
+ case IDM_SETSERVER:
+ DoDialog("VALUEENTRY", (FARPROC)SetServerDlgProc, 0, TRUE);
+ break;
+
+ case IDM_SETTOPIC:
+ DoDialog("VALUEENTRY", (FARPROC)SetTopicDlgProc, 0, TRUE);
+ break;
+
+ case IDM_CONTEXT:
+ DoDialog("CONTEXT", (FARPROC)ContextDlgProc, 0, TRUE);
+ break;
+
+ case IDM_ABOUT:
+ DoDialog("ABOUT", (FARPROC)About, 0, TRUE);
+ break;
+
+ case IDM_HELP:
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ break;
+
+ case WM_PAINT:
+ PaintServer(hWnd);
+ break;
+
+ case UM_CHGDATA:
+ {
+ WORD iFmt;
+
+ // wParam = TopicIndex,
+ // LOWORD(lParam) = ItemIndex
+ // We asynchronously do DdePostAdvise() calls to prevent infinite
+ // loops when in runaway mode.
+ if (wParam == 1) { // test topic
+ if (lParam == 0) { // rand item
+ seed = rand();
+ for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
+ if (hDataRand[iFmt]) {
+ DdeFreeDataHandle(hDataRand[iFmt]);
+ hDataRand[iFmt] = 0;
+ }
+ }
+ InvalidateRect(hwndServer, &rcRand, TRUE);
+ DdePostAdvise(idInst, topicList[wParam].hszTopic,
+ (HSZ)topicList[wParam].pItemList[lParam].hszItem);
+ }
+ if (lParam == 1) { // count item
+ count++;
+ for (iFmt = 0; iFmt < CFORMATS ; iFmt++) {
+ if (hDataCount[iFmt]) {
+ DdeFreeDataHandle(hDataCount[iFmt]);
+ hDataCount[iFmt] = 0;
+ }
+ }
+ InvalidateRect(hwndServer, &rcCount, TRUE);
+ DdePostAdvise(idInst, topicList[wParam].hszTopic,
+ (HSZ)topicList[wParam].pItemList[lParam].hszItem);
+ }
+ // Huge item does not runaway - too slow.
+ }
+ if (cRunaway) {
+ Delay(50, TRUE);
+ // This gives enough time for the system to remain
+ // useable in runaway mode.
+ PostMessage(hwndServer, UM_CHGDATA, wParam, lParam);
+ }
+ }
+ break;
+
+ case WM_DESTROY: /* message: window being destroyed */
+ if (fAppowned)
+ SendMessage(hwndServer, WM_COMMAND, GET_WM_COMMAND_MPS(IDM_APPOWNED, 0, 0));
+ DdeNameService(idInst, 0, 0, DNS_UNREGISTER); // unregister all services
+ UnHszize();
+ DdeUninitialize(idInst);
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return(0);
+}
+
+
+
+
+
+VOID Delay(
+DWORD delay,
+BOOL fModal)
+{
+ MSG msg;
+ delay = GetCurrentTime() + delay;
+ while (GetCurrentTime() < delay) {
+ if (fModal && PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+
+
+/*
+ * This function not only paints the server client area with current info,
+ * it also has the side effect of setting the global RECTs that bound each
+ * info area. This way flashing is reduced.
+ */
+VOID PaintServer(
+HWND hwnd)
+{
+ PAINTSTRUCT ps;
+ RECT rc;
+ CHAR szT[MAX_COMMENT];
+
+ BeginPaint(hwnd, &ps);
+ SetBkMode(ps.hdc, TRANSPARENT);
+ GetClientRect(hwnd, &rc);
+ rc.bottom = rc.top + cyText; // all rects are cyText in height.
+
+ rcComment = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, pszComment);
+
+ wsprintf(szT, "# of connections:%d", cServers);
+ rcConnCount = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ szT[0] = '\0';
+ rcAllBlock = rc;
+ if (fAllEnabled)
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Enabled.");
+ else if (fAllBlocked)
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "All Conversations are Blocked.");
+ else
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ rcNextAction = rc;
+ if (fBlockNextCB)
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will block.");
+ else if (fTermNextCB)
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, "Next callback will terminate.");
+ else
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ wsprintf(szT, "Count item = %ld", count);
+ rcCount = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ wsprintf(szT, "Rand item = %d", seed);
+ rcRand = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ wsprintf(szT, "Huge item size = %ld", cbHuge);
+ rcHugeSize = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ wsprintf(szT, "Render delay is %d milliseconds.", RenderDelay);
+ rcRndrDelay = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szT);
+
+ rcExec = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, szExec);
+
+ rcRunaway = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, cRunaway ? "Runaway active." : "");
+
+ rcAppowned = rc;
+ DrawTextLine(ps.hdc, &ps.rcPaint, &rc, fAppowned ? "Using AppOwned Data Handles." : "");
+
+ EndPaint(hwnd, &ps);
+}
+
+
+VOID DrawTextLine(
+HDC hdc,
+RECT *prcClip,
+RECT *prcText,
+PSTR psz)
+{
+ RECT rc;
+
+ if (IntersectRect(&rc, prcText, prcClip)) {
+ DrawText(hdc, psz, -1, prcText,
+ DT_LEFT | DT_EXTERNALLEADING | DT_SINGLELINE | DT_EXPANDTABS |
+ DT_NOCLIP | DT_NOPREFIX);
+ }
+ OffsetRect(prcText, 0, cyText);
+}
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/dialog.c b/private/mvdm/wow16/ddeml/tests/src/server/dialog.c
new file mode 100644
index 000000000..0b4e80624
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/dialog.c
@@ -0,0 +1,248 @@
+#include <string.h>
+#include <stdio.h>
+#include "server.h"
+#include "huge.h"
+
+/****************************************************************************
+ * *
+ * FUNCTION : DoDialog() *
+ * *
+ * PURPOSE : Generic dialog invocation routine. Handles procInstance *
+ * stuff, focus management and param passing. *
+ * RETURNS : result of dialog procedure. *
+ * *
+ ****************************************************************************/
+INT FAR DoDialog(
+LPSTR lpTemplateName,
+FARPROC lpDlgProc,
+DWORD param,
+BOOL fRememberFocus)
+{
+ WORD wRet;
+ HWND hwndFocus;
+ WORD cRunawayT;
+
+ cRunawayT = cRunaway;
+ cRunaway = 0; // turn off runaway during dialogs.
+
+ if (fRememberFocus)
+ hwndFocus = GetFocus();
+ lpDlgProc = MakeProcInstance(lpDlgProc, hInst);
+ wRet = DialogBoxParam(hInst, lpTemplateName, hwndServer, (WNDPROC)lpDlgProc, param);
+ FreeProcInstance(lpDlgProc);
+ if (fRememberFocus)
+ SetFocus(hwndFocus);
+
+ cRunaway = cRunawayT; // restore runaway state.
+ return wRet;
+}
+
+
+/****************************************************************************
+
+ FUNCTION: About(HWND, unsigned, WORD, LONG)
+
+ PURPOSE: Processes messages for "About" dialog box
+
+ MESSAGES:
+
+ WM_INITDIALOG - initialize dialog box
+ WM_COMMAND - Input received
+
+ COMMENTS:
+
+ No initialization is needed for this particular dialog box, but TRUE
+ must be returned to Windows.
+
+ Wait for user to click on "Ok" button, then close the dialog box.
+
+****************************************************************************/
+
+BOOL APIENTRY About(hDlg, message, wParam, lParam)
+HWND hDlg; /* window handle of the dialog box */
+UINT message; /* type of message */
+WPARAM wParam; /* message-specific information */
+LONG lParam;
+{
+ switch (message) {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ if (GET_WM_COMMAND_ID(wParam, lParam) == IDOK /* "OK" box selected? */
+ || GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL) { /* System menu close command? */
+ EndDialog(hDlg, TRUE); /* Exits the dialog box */
+ return (TRUE);
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+
+
+
+BOOL APIENTRY RenderDelayDlgProc(
+HWND hwnd,
+register UINT msg,
+register WPARAM wParam,
+LONG lParam)
+{
+ switch (msg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd, "Data Render Delay");
+ SetDlgItemInt(hwnd, IDEF_VALUE, RenderDelay, FALSE);
+ SetDlgItemText(hwnd, IDTX_VALUE, "Delay in milliseconds:");
+ return(1);
+ break;
+
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDOK:
+ RenderDelay = GetDlgItemInt(hwnd, IDEF_VALUE, NULL, FALSE);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+
+
+
+BOOL APIENTRY SetTopicDlgProc(
+HWND hwnd,
+register UINT msg,
+register WPARAM wParam,
+LONG lParam)
+{
+ CHAR szT[MAX_TOPIC + 10];
+
+ switch (msg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd, "Set Topic Dialog");
+ SetDlgItemText(hwnd, IDEF_VALUE, szTopic);
+ SetDlgItemText(hwnd, IDTX_VALUE, "Topic:");
+ return(1);
+ break;
+
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDOK:
+ DdeFreeStringHandle(idInst, topicList[1].hszTopic);
+ GetDlgItemText(hwnd, IDEF_VALUE, szTopic, MAX_TOPIC);
+ topicList[1].hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
+ strcpy(szT, szServer);
+ strcat(szT, " | ");
+ strcat(szT, szTopic);
+ SetWindowText(hwndServer, szT);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+
+BOOL APIENTRY SetServerDlgProc(
+HWND hwnd,
+register UINT msg,
+register WPARAM wParam,
+LONG lParam)
+{
+ CHAR szT[MAX_TOPIC + 10];
+
+ switch (msg){
+ case WM_INITDIALOG:
+ SetWindowText(hwnd, "Set Server Name Dialog");
+ SetDlgItemText(hwnd, IDEF_VALUE, szServer);
+ SetDlgItemText(hwnd, IDTX_VALUE, "Server:");
+ return(1);
+ break;
+
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDOK:
+ GetDlgItemText(hwnd, IDEF_VALUE, szServer, MAX_TOPIC);
+ DdeNameService(idInst, hszAppName, 0, DNS_UNREGISTER);
+ DdeFreeStringHandle(idInst, hszAppName);
+ hszAppName = DdeCreateStringHandle(idInst, szServer, 0);
+ DdeNameService(idInst, hszAppName, 0, DNS_REGISTER);
+ strcpy(szT, szServer);
+ strcat(szT, " | ");
+ strcat(szT, szTopic);
+ SetWindowText(hwndServer, szT);
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+
+
+
+BOOL APIENTRY ContextDlgProc(
+HWND hwnd,
+register UINT msg,
+register WPARAM wParam,
+LONG lParam)
+{
+ BOOL fSuccess;
+
+ switch (msg){
+ case WM_INITDIALOG:
+ SetDlgItemInt(hwnd, IDEF_FLAGS, CCFilter.wFlags, FALSE);
+ SetDlgItemInt(hwnd, IDEF_COUNTRY, CCFilter.wCountryID, FALSE);
+ SetDlgItemInt(hwnd, IDEF_CODEPAGE, CCFilter.iCodePage, TRUE);
+ SetDlgItemInt(hwnd, IDEF_LANG, LOWORD(CCFilter.dwLangID), FALSE);
+ SetDlgItemInt(hwnd, IDEF_SECURITY, LOWORD(CCFilter.dwSecurity), FALSE);
+ return(1);
+ break;
+
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDOK:
+ CCFilter.wFlags = GetDlgItemInt(hwnd, IDEF_FLAGS, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ CCFilter.wCountryID = GetDlgItemInt(hwnd, IDEF_COUNTRY, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ CCFilter.iCodePage = GetDlgItemInt(hwnd, IDEF_CODEPAGE, &fSuccess, TRUE);
+ if (!fSuccess) return(0);
+ CCFilter.dwLangID = (DWORD)GetDlgItemInt(hwnd, IDEF_LANG, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+ CCFilter.dwSecurity = (DWORD)GetDlgItemInt(hwnd, IDEF_SECURITY, &fSuccess, FALSE);
+ if (!fSuccess) return(0);
+
+ // fall through
+ case IDCANCEL:
+ EndDialog(hwnd, 0);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+ }
+ return(FALSE);
+}
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/dialog.h b/private/mvdm/wow16/ddeml/tests/src/server/dialog.h
new file mode 100644
index 000000000..9beaafc3c
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/dialog.h
@@ -0,0 +1,11 @@
+
+#define IDEF_VALUE 101
+#define IDTX_VALUE 102
+#define IDEF_DATA 103
+#define IDBN_GENHUGE 104
+
+#define IDEF_FLAGS 110
+#define IDEF_COUNTRY 111
+#define IDEF_CODEPAGE 112
+#define IDEF_LANG 113
+#define IDEF_SECURITY 114
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/huge.c b/private/mvdm/wow16/ddeml/tests/src/server/huge.c
new file mode 100644
index 000000000..e5106e06b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/huge.c
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * *
+ * MODULE : huge.c *
+ * *
+ * PURPOSE : This contains functions useful for generating and *
+ * verifying huge text data blocks. *
+ * *
+ ***************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "huge.h"
+
+extern DWORD idInst;
+#define BUFSZ 435
+
+LONG lseed, lmult, ladd;
+CHAR szT[BUFSZ];
+
+VOID SetMyRand(LONG seed, LONG mult, LONG add);
+CHAR MyRand(VOID);
+BOOL RandTest(LONG length, LONG seed, LONG mult, LONG add);
+
+/****************************************************************************
+ * *
+ * FUNCTION : SetMyRand() *
+ * *
+ * PURPOSE : Transfers random sequence generation variables to globals. *
+ * *
+ ****************************************************************************/
+VOID SetMyRand(
+LONG seed,
+LONG mult,
+LONG add)
+{
+ lseed = seed;
+ lmult = mult;
+ ladd = add;
+}
+
+
+/****************************************************************************
+ * *
+ * FUNCTION : MyRand() *
+ * *
+ * PURPOSE : Generates the next random character in a sequence. *
+ * *
+ * RETURNS : the character generated *
+ * *
+ ****************************************************************************/
+CHAR MyRand()
+{
+ CHAR c;
+
+ lseed = lseed * lmult + ladd;
+ c = (CHAR)(LOWORD(lseed) ^ HIWORD(lseed));
+ return((CHAR)((c & (CHAR)0x4f) + ' ')); // 0x20 - 0x6f - all printable
+}
+
+
+/*
+ * This function allocates and fills a HUGE data handle with a verifiable
+ * text string.
+ *
+ * The format of the text string is:
+ * "<length>=<seed>*<mult>+<add>;---data of length <length>---\0"
+ * all values are stored in base 16 numbers.
+ */
+/****************************************************************************
+ * *
+ * FUNCTION : CreateHugeDataHandle() *
+ * *
+ * PURPOSE : Generates a huge pseudo-random sequence of printable *
+ * characters of the length given and places then into *
+ * a DDEML data handle. *
+ * *
+ * RETURNS : The data handle created or 0 on failure. *
+ * *
+ ****************************************************************************/
+HDDEDATA CreateHugeDataHandle(
+LONG length,
+LONG seed,
+LONG mult,
+LONG add,
+HSZ hszItem,
+WORD wFmt,
+WORD afCmd)
+{
+ register WORD cb;
+ HDDEDATA hData;
+ DWORD cbData;
+ CHAR *psz;
+
+ wsprintf(szT, "%ld=%ld*%ld+%ld;", length, seed, mult, add);
+ cb = strlen(szT);
+ hData = DdeCreateDataHandle(idInst, szT, cb + 1, 0, hszItem, wFmt, afCmd);
+ if (hData)
+ hData = DdeAddData(hData, NULL, 0, cb + length + 1);
+ cbData = cb;
+ SetMyRand(seed, mult, add);
+ while (hData && (length > 0)) {
+ psz = szT;
+ cb = BUFSZ;
+ while (cb--)
+ *psz++ = MyRand();
+ hData = DdeAddData(hData, szT, min(length, BUFSZ), cbData);
+ cbData += BUFSZ;
+ length -= BUFSZ;
+ }
+ return(hData);
+}
+
+/****************************************************************************
+ * *
+ * FUNCTION : CheckHugeData() *
+ * *
+ * PURPOSE : Verifies the correctness of a pseudo-random character *
+ * sequence generated by CreateHugeData. *
+ * *
+ * RETURNS : TRUE if verified ok, FALSE otherwise. *
+ * *
+ ****************************************************************************/
+BOOL CheckHugeData(
+HDDEDATA hData)
+{
+ LONG length;
+ LONG seed;
+ LONG mult;
+ LONG add;
+ CHAR *psz;
+ DWORD cbOff;
+ WORD cb;
+
+ if (!DdeGetData(hData, szT, BUFSZ, 0))
+ return(FALSE);
+ szT[BUFSZ - 1] = '\0';
+ psz = strchr(szT, ';');
+ if (psz == NULL)
+ return(FALSE);
+ *psz = '\0';
+
+ if (sscanf(szT, "%ld=%ld*%ld+%ld", &length, &seed, &mult, &add) != 4)
+ return(FALSE);
+
+ if (length < 0)
+ return(FALSE);
+ SetMyRand(seed, mult, add);
+ cbOff = strlen(szT) + 1;
+ while (length > 0) {
+ DdeGetData(hData, szT, BUFSZ, cbOff);
+ psz = szT;
+ cb = BUFSZ;
+ while (length-- && cb--)
+ if (*psz++ != MyRand())
+ return(FALSE);
+ cbOff += BUFSZ;
+ length -= BUFSZ;
+ }
+ return(TRUE);
+}
+
+#if 0
+/****************************************************************************
+ * *
+ * FUNCTION : RandTest() *
+ * *
+ * PURPOSE : Verifies the correctness of CreateHugeDataHandle() and *
+ * CheckHugeData(). *
+ * *
+ * RETURNS : *
+ * *
+ ****************************************************************************/
+BOOL RandTest(
+LONG length,
+LONG seed,
+LONG mult,
+LONG add)
+{
+ HDDEDATA hData;
+ BOOL fSuccess;
+
+ hData = CreateHugeDataHandle(length, seed, mult, add, 0, 1, 0);
+ if (!hData)
+ return(FALSE);
+ fSuccess = CheckHugeData(hData);
+ DdeFreeDataHandle(hData);
+ return(fSuccess);
+}
+#endif
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/huge.h b/private/mvdm/wow16/ddeml/tests/src/server/huge.h
new file mode 100644
index 000000000..ce30b7fc9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/huge.h
@@ -0,0 +1,8 @@
+// header file for HUGE data handle testing module
+
+
+// PROCS
+
+HDDEDATA CreateHugeDataHandle(LONG length, LONG seed, LONG mult, LONG add,
+ HSZ hszItem, WORD wFmt, WORD afCmd);
+BOOL CheckHugeData(HDDEDATA hData);
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/makefile b/private/mvdm/wow16/ddeml/tests/src/server/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/makefile
@@ -0,0 +1,6 @@
+#
+# 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/wow16/ddeml/tests/src/server/makefile.dos b/private/mvdm/wow16/ddeml/tests/src/server/makefile.dos
new file mode 100644
index 000000000..5c51daa10
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/makefile.dos
@@ -0,0 +1,36 @@
+#
+# Test makefile
+
+!ifdef WIN31
+EXEFLAGS=-AS -Gsw -Od -Ziep -W3 -DWIN16 -DWIN31 -DUSECOMM -DWIN
+!else
+EXEFLAGS=-AS -FPi -Gcw -Os -Ziepd -W3 -DWIN16 -DWIN
+!endif
+
+OBJ =ddemlsv.obj dialog.obj dde.obj huge.obj
+
+#
+# Stress Test
+#
+
+all: ddemlsv.exe
+
+server.res: server.rc
+ rc -DWIN16 -r server.rc
+
+ddemlsv.obj: ddemlsv.c server.h huge.h
+ cl -c $(EXEFLAGS) ddemlsv.c
+
+dde.obj: dde.c huge.h server.h
+ cl -c $(EXEFLAGS) dde.c
+
+dialog.obj: dialog.c huge.h server.h
+ cl -c $(EXEFLAGS) dialog.c
+
+huge.obj: huge.c huge.h
+ cl -c $(EXEFLAGS) huge.c
+
+ddemlsv.exe: $(OBJ) server.def server.res
+ link /map/li/co $(OBJ)/AL:16,ddemlsv.exe,, /NOE /NOD libw ddeml slibcew,server.def
+ mapsym ddemlsv
+ rc -DWIN16 server.res ddemlsv.exe
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/mk4dos.cmd b/private/mvdm/wow16/ddeml/tests/src/server/mk4dos.cmd
new file mode 100644
index 000000000..1cc3f8bff
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/mk4dos.cmd
@@ -0,0 +1,13 @@
+@echo off
+if "%1"=="" goto bld
+del *.dll
+del *.sym
+del *.map
+del *.obj
+del *.bak
+del *.res
+del *.lnk
+goto done
+:bld
+nmake -f makefile.dos
+:done
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/server.def b/private/mvdm/wow16/ddeml/tests/src/server/server.def
new file mode 100644
index 000000000..80dc24459
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/server.def
@@ -0,0 +1,24 @@
+NAME Server
+
+DESCRIPTION 'Sample Microsoft Windows Application'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 1024
+STACKSIZE 5120 ; recommended minimum for Windows applications
+
+
+EXPORTS
+ MainWndProc @1
+ About @2
+ RenderDelayDlgProc @3
+ SetTopicDlgProc @4
+ DdeCallback @5
+ SetServerDlgProc @6
+ ContextDlgProc @7
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/server.dlg b/private/mvdm/wow16/ddeml/tests/src/server/server.dlg
new file mode 100644
index 000000000..7a3c341cb
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/server.dlg
@@ -0,0 +1,61 @@
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+ "DIALOG.H\0"
+END
+
+ABOUT DIALOG 25, 23, 184, 78
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About Server"
+FONT 8, "Helv"
+BEGIN
+ CTEXT "Microsoft Windows", -1, 0, 5, 184, 8
+ CTEXT "Server", -1, 0, 15, 184, 8
+ CTEXT "Version 3.1", -1, 0, 34, 184, 8
+ CTEXT "Copyright ゥ 1991 Microsoft Corp.", -1, 0, 47, 184, 9
+ DEFPUSHBUTTON "OK", IDOK, 76, 60, 32, 14, WS_GROUP
+ ICON "server", -1, 25, 14, 16, 21
+END
+
+TEXTDATAENTRY DIALOG 8, 26, 184, 90
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Text Data Entry"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_DATA, 8, 22, 170, 43, ES_MULTILINE | ES_AUTOVSCROLL |
+ ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Ok", IDOK, 8, 70, 38, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 140, 70, 38, 14
+ PUSHBUTTON "&Generate Huge", IDBN_GENHUGE, 53, 70, 80, 14
+ CTEXT "Enter text data to send or size of huge data to generate",
+ -1, 8, 2, 169, 18, NOT WS_GROUP
+END
+
+VALUEENTRY DIALOG 13, 69, 137, 46
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Value Entry Dialog"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_VALUE, 92, 6, 38, 12
+ DEFPUSHBUTTON "&Ok", IDOK, 22, 26, 38, 14
+ PUSHBUTTON "&Cancel", IDCANCEL, 76, 26, 38, 14
+ RTEXT "Value:", IDTX_VALUE, 6, 8, 85, 8, NOT WS_GROUP
+END
+
+CONTEXT DIALOG 6, 28, 122, 99
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Conversation Context Filter"
+FONT 8, "Helv"
+BEGIN
+ EDITTEXT IDEF_FLAGS, 77, 8, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_COUNTRY, 77, 21, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_CODEPAGE, 77, 34, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_LANG, 77, 47, 26, 12, ES_AUTOHSCROLL
+ EDITTEXT IDEF_SECURITY, 77, 60, 26, 12, ES_AUTOHSCROLL
+ PUSHBUTTON "Ok", IDOK, 14, 79, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 68, 79, 40, 14
+ LTEXT "flags", 105, 19, 10, 55, 8
+ LTEXT "Country ID", 106, 19, 23, 55, 8
+ LTEXT "CodePage", 107, 19, 36, 55, 8
+ LTEXT "Language ID", 108, 19, 49, 55, 8
+ LTEXT "Security Code", 109, 19, 62, 55, 8
+END
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/server.h b/private/mvdm/wow16/ddeml/tests/src/server/server.h
new file mode 100644
index 000000000..c449c84dd
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/server.h
@@ -0,0 +1,157 @@
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+
+#define IDM_ABOUT 100
+#define IDM_BLOCKALLCBS 200
+#define IDM_ENABLEONECB 201
+#define IDM_BLOCKNEXTCB 202
+#define IDM_TERMNEXTCB 203
+#define IDM_RUNAWAY 204
+#define IDM_CHANGEDATA 205
+#define IDM_RENDERDELAY 206
+#define IDM_SETTOPIC 207
+#define IDM_SETSERVER 208
+#define IDM_UNBLOCKALLCBS 209
+#define IDM_HELP 210
+#define IDM_CONTEXT 211
+#define IDM_APPOWNED 212
+
+#define IDS_BADLENGTH 1
+
+#define MAX_TOPIC 20
+#define MAX_COMMENT 40
+#define MAX_EXEC 40
+#define CCHARS 80
+#define CLINES 40
+
+#define UM_CHGDATA (WM_USER + 435)
+
+#define CSYSTEMITEMS 4
+#define CTESTITEMS 4
+#define CTOPICS 2
+
+#include "dialog.h"
+
+/****** Structrues ******/
+
+// predefined format list item
+
+typedef struct {
+ ATOM atom;
+ PSTR sz;
+} FORMATINFO;
+#define CFORMATS 3
+
+extern FORMATINFO aFormats[];
+
+typedef struct _XFERINFO {
+ WORD wType;
+ WORD wFmt;
+ HCONV hConv;
+ HSZ hszTopic;
+ HSZ hszItem;
+ HDDEDATA hData;
+ DWORD lData1;
+ DWORD lData2;
+} XFERINFO;
+typedef XFERINFO *PXFERINFO;
+
+typedef struct _ITEMLIST {
+ HSZ hszItem;
+ HDDEDATA (*npfnCallback)(PXFERINFO, WORD);
+ PSTR pszItem;
+} ITEMLIST;
+
+typedef struct _TOPICLIST {
+ HSZ hszTopic;
+ ITEMLIST *pItemList;
+ WORD cItems;
+ PSTR pszTopic;
+} TOPICLIST;
+
+typedef struct { // used to passinfo to/from TextDataEntryDlgProc and
+ HDDEDATA hDdeData;
+ WORD wFmt;
+ HSZ hszItem;
+} XACT;
+
+
+
+// GLOBALS
+
+extern DWORD idInst;
+extern CONVCONTEXT CCFilter;
+extern HANDLE hInst;
+extern HWND hwndServer;
+extern RECT rcRand;
+extern RECT rcCount;
+extern RECT rcComment;
+extern RECT rcExec;
+extern RECT rcConnCount;
+extern RECT rcRndrDelay;
+extern RECT rcRunaway;
+extern RECT rcAllBlock;
+extern RECT rcNextAction;
+extern RECT rcHugeSize;
+extern RECT rcAppowned;
+extern BOOL fAllBlocked;
+extern BOOL fAllEnabled;
+extern BOOL fEnableOneCB;
+extern BOOL fBlockNextCB;
+extern BOOL fTermNextCB;
+extern BOOL fAppowned;
+extern WORD cRunaway;
+extern WORD RenderDelay;
+extern DWORD count;
+extern HSZ hszAppName;
+extern CHAR szClass[];
+extern CHAR szTopic[MAX_TOPIC];
+extern CHAR szServer[MAX_TOPIC];
+extern CHAR szComment[MAX_COMMENT];
+extern CHAR szExec[MAX_EXEC];
+extern CHAR *pszComment;
+extern WORD seed;
+extern WORD cyText;
+extern WORD cServers;
+extern HDDEDATA hDataHelp[CFORMATS];
+extern HDDEDATA hDataCount[CFORMATS];
+extern HDDEDATA hDataRand[CFORMATS];
+extern HDDEDATA hDataHuge[CFORMATS];
+extern DWORD cbHuge;
+
+extern CHAR szDdeHelp[];
+extern FORMATINFO aFormats[CFORMATS];
+extern ITEMLIST SystemTopicItemList[CSYSTEMITEMS];
+extern ITEMLIST TestTopicItemList[CTESTITEMS];
+extern TOPICLIST topicList[CTOPICS];
+
+
+// FUNCTIONS
+
+
+BOOL InitApplication(HANDLE);
+BOOL InitInstance(HANDLE, INT);
+INT FAR DoDialog(LPSTR lpTemplateName, FARPROC lpDlgProc, DWORD param, BOOL fRememberFocus);
+LONG APIENTRY MainWndProc(HWND, UINT, WPARAM, LONG);
+BOOL APIENTRY About(HWND, UINT, WPARAM, LONG);
+BOOL APIENTRY RenderDelayDlgProc(HWND, UINT, WPARAM, LONG);
+BOOL APIENTRY SetTopicDlgProc(HWND, UINT, WPARAM, LONG);
+BOOL APIENTRY SetServerDlgProc(HWND, UINT, WPARAM, LONG);
+BOOL APIENTRY ContextDlgProc(HWND, UINT, WPARAM, LONG);
+VOID PaintServer(HWND hwnd);
+VOID DrawTextLine(HDC hdc, RECT *prcClip, RECT *prcText, PSTR psz);
+HDDEDATA CALLBACK DdeCallback(WORD wType, WORD wFmt, HCONV hConv, HSZ hszTopic,
+ HSZ hszItem, HDDEDATA hData, DWORD lData1, DWORD lData2);
+HDDEDATA TopicListXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA ItemListXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA sysFormatsXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA TestRandomXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA TestCountXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA TestHugeXfer(PXFERINFO pXferInfo, WORD iFmt);
+HDDEDATA HelpXfer(PXFERINFO pXferInfo, WORD iFmt);
+VOID Hszize(VOID);
+VOID UnHszize(VOID);
+VOID Delay(DWORD delay, BOOL fModal);
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/server.ico b/private/mvdm/wow16/ddeml/tests/src/server/server.ico
new file mode 100644
index 000000000..203875d8e
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/server.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/server.rc b/private/mvdm/wow16/ddeml/tests/src/server/server.rc
new file mode 100644
index 000000000..ae0dc9016
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/server.rc
@@ -0,0 +1,34 @@
+#include "windows.h"
+#include "server.h"
+
+server ICON server.ico
+
+ServerMenu MENU
+BEGIN
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Change Data", IDM_CHANGEDATA
+ MENUITEM "Data Render &Delay...", IDM_RENDERDELAY
+ MENUITEM "Set &Topic...", IDM_SETTOPIC
+ MENUITEM "Set &Server...", IDM_SETSERVER
+ MENUITEM "Set Context &Filter...", IDM_CONTEXT
+ MENUITEM "&Use Appowned handles", IDM_APPOWNED
+ MENUITEM SEPARATOR
+ MENUITEM "&Runaway Active", IDM_RUNAWAY
+ MENUITEM "&Block all callbacks", IDM_BLOCKALLCBS
+ MENUITEM "&Enable all callbacks", IDM_UNBLOCKALLCBS
+ MENUITEM "Enable &one callback", IDM_ENABLEONECB
+ MENUITEM "Block all after &next callback",IDM_BLOCKNEXTCB
+ MENUITEM "&Terminate service on next callback", IDM_TERMNEXTCB
+ END
+ MENUITEM "&About...", IDM_ABOUT
+END
+
+
+STRINGTABLE
+BEGIN
+
+IDS_BADLENGTH , "Invalid length value string. Reenter or cancel."
+
+END
+#include "server.dlg"
diff --git a/private/mvdm/wow16/ddeml/tests/src/server/sources b/private/mvdm/wow16/ddeml/tests/src/server/sources
new file mode 100644
index 000000000..becaaf400
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/src/server/sources
@@ -0,0 +1,25 @@
+
+MAJORCOMP=samples
+MINORCOMP=ddemlsv
+
+TARGETNAME=ddemlsv
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+INCLUDES=.
+
+SOURCES= dde.c \
+ dialog.c \
+ huge.c \
+ ddemlsv.c \
+ server.rc
+
+
+C_DEFINES=-DWIN32
+
+UMTYPE=windows
+UMAPPL=ddemlsv
+UMENTRY=winmain
+UMLIBS=obj\*\ddemlsv.lib \
+ obj\*\server.res
diff --git a/private/mvdm/wow16/ddeml/verddeml.h b/private/mvdm/wow16/ddeml/verddeml.h
new file mode 100644
index 000000000..672bdc24c
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/verddeml.h
@@ -0,0 +1,4 @@
+ WORD rup = 1;
+ WORD rmm = 0;
+ WORD rmj = 1;
+
diff --git a/private/mvdm/wow16/drivers/comm/bimodint.inc b/private/mvdm/wow16/drivers/comm/bimodint.inc
new file mode 100644
index 000000000..e579440bb
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/bimodint.inc
@@ -0,0 +1,95 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1990
+;
+; Title: BIMODINT.INC - Bimodal Interrupt Handler Equates and Structures
+;
+; Version: 1.00
+;
+; Date: 14-Nov-1990
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 14-Nov-1990 RAL Original
+;
+;==============================================================================
+
+Bimodal_Int_Struc STRUC
+BIS_IRQ_Number dw ?
+BIS_VM_ID dw 0
+BIS_Next dd ?
+BIS_Reserved1 dd ?
+BIS_Reserved2 dd ?
+BIS_Reserved3 dd ?
+BIS_Reserved4 dd ?
+BIS_Flags dd 0
+BIS_Mode dw 0
+BIS_Entry dw ?
+BIS_Control_Proc dw ?
+ dw ?
+BIS_User_Mode_API dd ?
+BIS_Super_Mode_API dd ?
+BIS_User_Mode_CS dw ?
+BIS_User_Mode_DS dw ?
+BIS_Super_Mode_CS dw ?
+BIS_Super_Mode_DS dw ?
+BIS_Descriptor_Count dw ?
+Bimodal_Int_Struc ENDS
+
+BIS_Sel_Table equ word ptr (SIZE Bimodal_Int_Struc)
+
+
+EBIS_Sel_Struc STRUC
+EBIS_User_Mode_Sel dw ?
+ dw ?
+EBIS_Super_Mode_Sel dw ?
+EBIS_Sel_Struc ENDS
+
+
+.errnz BIS_Super_Mode_API-BIS_User_Mode_API-4
+.errnz BIS_Super_Mode_CS-BIS_User_Mode_CS-4
+.errnz BIS_Super_Mode_DS-BIS_User_Mode_DS-4
+.errnz EBIS_Super_Mode_Sel-EBIS_User_Mode_Sel-4
+
+
+VPICD_API_Get_Ver EQU 0000h
+VPICD_Install_Handler EQU 0001h
+VPICD_Remove_Handler EQU 0002h
+VPICD_Call_At_Ring0 EQU 0003h
+
+
+BIH_API_EOI EQU 0000h
+BIH_API_Mask EQU 0001h
+BIH_API_Unmask EQU 0002h
+BIH_API_Get_Mask EQU 0003h
+BIH_API_Get_IRR EQU 0004h
+BIH_API_Get_ISR EQU 0005h
+BIH_API_Call_Back EQU 0006h
+
+
+Declare_PM_BIS MACRO IRQn,CtrlP,ISRoff,APIoff,ISRcs,ISRds
+LOCAL strt
+strt label byte
+ dw IRQn ; BIS_IRQ_Number
+ dw 0 ; BIS_VM_ID
+ dd 6 DUP(0) ; BIS_Next/BIS_Reserved1-BIS_Reserved4/BIS_Flags
+ dw 0 ; BIS_Mode
+ dw ISRoff ; BIS_Entry
+ dw CtrlP ; BIS_Control_Proc
+ dw 0 ; filler
+ dw APIoff ; BIS_User_Mode_API
+ dw ISRcs
+ dd 0 ; BIS_Super_Mode_API
+ dw ISRcs ; BIS_User_Mode_CS
+ dw ISRds ; BIS_User_Mode_DS
+ dw 0 ; BIS_Super_Mode_CS
+ dw 0 ; BIS_Super_Mode_DS
+ dw 0 ; BIS_Descriptor_Count
+.errnz $-strt - (SIZE Bimodal_Int_Struc)
+ENDM
diff --git a/private/mvdm/wow16/drivers/comm/ccom.asm b/private/mvdm/wow16/drivers/comm/ccom.asm
new file mode 100644
index 000000000..31dbc94fd
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ccom.asm
@@ -0,0 +1,616 @@
+page,132
+
+;---------------------------Module-Header-------------------------------;
+; Module Name: CCOM.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; History
+;
+; 041786 Fixed RECCOM to return be able to return nulls
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ibmcom.inc
+.list
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+;=========================================================================
+;
+; Communications Device Driver - C language interface module.
+; This module provides an interface layer between programs written
+; in C, and the low-level OEM specific communications drivers.
+;
+;=========================================================================
+
+ externNP $CLRBRK
+ externNP $DCBPTR
+ externNP $EVT
+ externNP $EVTGET
+ externNP $EXTCOM
+ externNP $FLUSH
+ externNP $INICOM
+ externNP $RECCOM
+ externNP $RECSTR
+ externNP $SETBRK
+ externNP $SETCOM
+ externNP $SETQUE
+ externNP $SNDCOM
+ externNP $SNDIMM
+ externNP $STACOM
+ externNP $TRMCOM
+ externNP $SNDCOMSTR
+ externNP $ENANOTIFY
+
+ externNP GetDEB
+
+;=========================================================================
+;
+; ushort inicom(pdcb)
+; dcb far *pdcb;
+;
+; returns - 0 if no errors occured
+; - Error Code (which is reset)
+;
+; Inicom is a one-time called routine to initialize. This is meant
+; to be called when a process starts, or determines that it will use
+; communications. Operating parameters are also passed on to setcom(),
+; below.
+;
+; Fields within the dcb (including device id) should be set up prior to
+; calling inicom.
+;
+; As a true device driver, this routine is to be called when the device
+; driver is loaded at system start-up time. The dcb reflects the
+; default operating parameters.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc inicom,<PUBLIC,FAR>
+ parmD pdcb
+
+cBegin
+ les bx,pdcb
+ assumes es,nothing
+
+ call $INICOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort setcom(pdcb)
+; dcb far *pdcb;
+;
+; returns - 0 if no errors occured
+; - Error Code (reset)
+;
+; Set/alter communications operating parameters. This is a non-destructive
+; alteration of operating mode. Queues and interrupts are not affected.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc setcom,<PUBLIC,FAR>
+ parmD pdcb
+
+cBegin
+ les bx,pdcb ;get pointer to dcb
+ assumes es,nothing
+
+ call $SETCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; void setque(cid,pqdb)
+; char cid;
+; qdb far *pqdb;
+;
+; Init the locations of the receive and transmit queues that are to be
+; used to buffer incomming and outgoing characters.
+;
+; This may be called at any time by a process to use a different set
+; of queues. Characters (transmit and/or receive) may be lost if the
+; queues are changed when not empty. This allows dynamic allocation
+; of variable sized queues. Under DOS 4.0, the queues must be locked in
+; memory.
+;
+; As a true device driver, the queues would be allocated at boot time,
+; and must also be locked under DOS 4.0.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc setque,<PUBLIC,FAR>
+ parmB cid
+ parmD pqdb
+
+cBegin
+ mov ah,cid
+ les bx,pqdb ;pointer to qdb
+ assumes es,nothing
+
+ call $SETQUE
+cEnd
+
+page
+
+;=========================================================================
+;
+; short reccom(cid)
+; char cid;
+;
+; Returns - character.
+; - -1 if error
+; - -2 if no character available
+;
+; Read a byte. Extracts a byte from the receive data queue. Returns
+; immediately.
+;=========================================================================
+
+
+assumes ds,Data
+assumes es,nothing
+
+cProc reccom,<PUBLIC,FAR>
+ parmB cid
+
+cBegin
+ mov ah,cid ;Id Into AH
+
+ call $RECCOM ;Get char, error, or no data
+ mov cx,ax ;Save data
+ mov ah,0 ;Assume valid data
+ jnz reccom5 ;Data is valid
+ mov ax,-2 ;Assume no data available
+ jcxz reccom5 ;No data available
+ inc ax ;Show error (-1)
+
+reccom5:
+cEnd
+
+page
+
+;=========================================================================
+;
+; short ReadCommString(cid, buf, cnt)
+; char cid;
+; LPSTR buf;
+; int cnt;
+;
+; Returns - ax = # of bytes read
+; - 0 if no character available or error
+;
+; Read string. Extracts bytes from the receive data queue. Returns
+; immediately.
+;=========================================================================
+
+
+assumes ds,Data
+assumes es,nothing
+
+cProc ReadCommString,<PUBLIC,FAR>
+ parmB cid
+ parmD buf
+ parmW cnt
+
+cBegin
+ mov ah,cid ;Id Into AH
+ les di, buf
+ mov cx, cnt
+
+ call $RECSTR ;Get char, error, or no data
+ jnz short recstr5 ; jmp if no error
+ xor ax, ax
+recstr5:
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort sndcom(cid,ch)
+; char cid;
+; char ch;
+;
+; Returns - 0 if no errors
+; - Error Code (Not removed, i.e. stacom will return this error
+; unless another occurs before the next call to stacom.)
+;
+; Transmit a byte. Places a byte into the transmit queue. Negative return
+; indicates error.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc sndcom,<PUBLIC,FAR>
+ parmB cid
+ parmB chr
+
+cBegin
+ mov ah,cid
+ mov al,chr
+
+ call $SNDCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort ctx(cid,ch)
+; char cid;
+; char ch;
+;
+; Returns - 0 if no errors
+; - -1 if character could not be sent.
+;
+; Transmit a byte "immediately". Places a byte into the transmit queue.
+; or other buffer such that it is the next character picked up for
+; transmission. Negative return indicates error.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc ctx,<PUBLIC,FAR>
+ parmB cid
+ parmB chr
+
+cBegin
+ mov ah,cid
+ mov al,chr
+
+ call $SNDIMM
+cEnd
+
+page
+
+;=========================================================================
+;
+; void trmcom(cid)
+; char cid;
+;
+; Terminate communications on a particular channel. Flushes the
+; buffers (waits for completion), and shuts down the comm device.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc trmcom,<PUBLIC,FAR>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $TRMCOM ;and go for it
+cEnd
+page
+
+;=========================================================================
+;
+; ushort stacom(cid,pstat)
+; char cid;
+; stat far *pstat;
+;
+; Returns - 0 if no errors
+; - Error Code
+; - status structure updated.
+;
+; Get device status. Returns device status and input queue status.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc stacom,<PUBLIC,FAR>,<si,di>
+ parmB cid
+ parmD pstat
+
+cBegin
+ mov ah,cid
+ les bx,pstat
+ assumes es,nothing
+
+ call $STACOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; dword cextfcn(cid,fcn)
+; char cid;
+; short fcn;
+;
+; Perform extended functions.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cextfcn,<PUBLIC,FAR>
+ parmB cid
+ parmW fcn
+
+cBegin
+ mov ah,cid
+ mov bx,fcn
+
+ call $EXTCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort cflush(cid,q)
+; ushort cid;
+; ushort q;
+;
+; Queue flush. empties the specified queue. q=0 means transmit queue,
+; 1 indicates receive queue.
+;
+; Returns - 0 or -1.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cflush,<PUBLIC,FAR>,<si,di>
+ parmB cid
+ parmB q
+
+cBegin
+ mov ah,cid
+ mov bh,q
+
+ call $FLUSH
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort far *cevt(cid,evtmask)
+; ushort cid;
+; ushort evtmask;
+;
+; Returns the location of a word which in which certain bits will be set
+; when particular events occur. The event mask passed defines which bits
+; are to be enabled. The event byte is used primarily for speed in
+; determining if certain events have occurred. Returns 0 on success, -1
+; for an illegal handle.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cevt,<PUBLIC,FAR>
+ parmB cid
+ parmW evt_mask
+
+cBegin
+ mov ah,cid
+ mov bx,evt_mask
+
+ call $EVT ;Set the event
+cEnd
+
+page
+
+;=========================================================================
+;
+; short cevtGet(cid, evtmask)
+; ushort cid;
+; ushort evtmask;
+;
+; The event byte set up by cevt, above, is returned. This routine must be
+; used to read the event byte in order to prevent loss of an event
+; occurance. Those bits set in the event mask passed are then cleared in
+; the event byte.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cevtGet,<PUBLIC,FAR>
+ parmB cid
+ parmW evt_mask
+
+cBegin
+ mov ah,cid
+ mov bx,evt_mask
+
+ call $EVTGET
+cEnd
+
+page
+
+;=========================================================================
+;
+; short csetbrk(cid)
+; ushort cid;
+;
+; Suspends character transmission, and places the transmission line in
+; a break state until cclrbrk is called. Returns 0 on success, -1 if
+; illegal handle.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc csetbrk,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $SETBRK
+cEnd
+
+page
+
+;=========================================================================
+;
+; short cclrbrk(cid)
+; ushort cid;
+;
+; Restores the line to a non-breaking state, and restarts character
+; transmission. Returns 0 on success, -1 if illegal handle.
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cclrbrk,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $CLRBRK
+cEnd
+
+page
+
+;=========================================================================
+;
+; dcb far *getdcb(cid)
+; ushort cid;
+;
+; Returns a pointer to the dcb associated with the given id.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc getdcb,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $DCBPTR
+cEnd
+
+;=========================================================================
+;
+; int CommWriteString(cid, lpstring, count)
+; ushort cid;
+; LPSTR lpstring;
+; int count;
+;
+; Returns # of bytes sent
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc CommWriteString, <FAR, PUBLIC>, <si, di>
+
+ parmB cid
+ parmD lpstring
+ parmW count
+
+cBegin
+
+ xor ax, ax
+ mov cx, count
+ jcxz short cws_exit
+ mov ah, cid
+ les di, lpstring
+ call $SNDCOMSTR
+cws_exit:
+cEnd
+page
+
+;=========================================================================
+;
+; bool EnableNotification(cid, hWnd, recv_trigger, send_trigger)
+; ushort cid;
+; WORD hWnd; /* 0, to disable notification */
+; int recv_trigger;
+; int send_trigger;
+;
+; Returns # of bytes sent
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc EnableNotification, <FAR, PUBLIC>, <si, di>
+
+ parmB cid
+ parmW _hWnd
+ parmW recvT
+ parmW sendT
+
+cBegin
+
+ mov ah, [cid]
+ mov bx, [_hWnd]
+ mov cx, [recvT]
+ mov dx, [sendT]
+ call $ENANOTIFY
+cEnd
+page
+
+;-----------------------------------------------------------------------;
+; WEP
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-Jan-1990 18:33:48 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WEP,<PUBLIC,FAR>
+cBegin nogen
+ nop ; You don't want to know why.
+ mov ax,1
+ ret 2
+cEnd nogen
+
+sEnd Code
+
+end
+
diff --git a/private/mvdm/wow16/drivers/comm/comdev.h b/private/mvdm/wow16/drivers/comm/comdev.h
new file mode 100644
index 000000000..a913cffa3
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdev.h
@@ -0,0 +1,243 @@
+/*************************************************************************
+**
+** Miscelaneous definitions.
+*/
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+
+#define NULL 0
+#define FALSE 0
+#define TRUE 1
+
+#define LPTx 0x80 /* Mask to indicate cid is for LPT device */ /*081985*/
+#define LPTxMask 0x7F /* Mask to get cid for LPT device */ /*081985*/
+
+#define PIOMAX 3 /* Max number of LPTx devices in high level */ /*081985*/
+#define CDEVMAX 10 /* Max number of COMx devices in high level */
+#define DEVMAX 13 /* Max number of devices in high level */ /*081985*/
+
+/*************************************************************************
+**
+** device control block.
+** This block of information defines the functional parameters of the
+** communications software and hardware.
+**
+** Fields in the DCB are defined as follows:
+**
+** Id - Comm device ID, set by the device driver.
+** BaudRate - Baud rate at which operating.
+** ByteSize - Number of bits per transmitted/received byte. (4-8)
+** Received data is also masked off to this size.
+** Parity - Transmitt/Receive Parity. (0,1,2,3,4) = (None, Odd,
+** Even, Mark, Space)
+** StopBits - Number of stop bits. (0,1,2) = (1, 1.5, 2)
+** RlsTimeout - Amount of time, in milleseconds, to wait for RLSD to
+** become high. RLSD, Receive Line Signal Detect is also
+** known as CD, Carrier Detect. RLSD flow control can be
+** achieved by specifying infinite timeout.
+** CtsTimeout - Amount of time, in milleseconds, to wait for CTS,
+** Clear To Send, to become high. CTS flow control can
+** be achieved by specifying infinite timeout.
+** DsrTimeout - Amount of time, in milleseconds, to wait for DSR,
+** Data Set Ready, to become high. DSR flow control can
+** be acheived by specifying infinite timeout.
+** fBinary - Binary Mode flag. In non-binary mode, EofChar is
+** recognized and remembered as end of data.
+** fRtsDisable - Disable RTS flag. If set, Request To Send is NOT
+** used, and remains low. Normally, RTS is asserted when
+** the device is openned, and dropped when closed.
+** fParity - Enable Parity Checking. Parity errors are not
+** reported when 0.
+** fOutxCtsFlow - enable output xon/xoff(hardware) using cts
+** fOutxDsrFlow - enable output xon/xoff(hardware) using dsr
+** fOutX - Indicates that X-ON/X-OFF flow control is to be used
+** during transmission. The transmitter will halt if
+** an X-OFF character is received, and will start again
+** when an X-ON character is received.
+** fInX - Indicates that X-ON/X-OFF flow control is to be used
+** during reception. An X-OFF character will be
+** transmitted when the receive queue comes within 10
+** characters of being full, after which an X-ON will be
+** transmitted when the queue comes with 10 characters
+** of being empty.
+** fPeChar - Indicates that characters received with parity errors
+** are to be replaced with the character specified in
+** PeChar, below.
+** fNull - Indicates that received NULL characters are to be
+** discarded.
+** fChEvt - Indicates that the reception of EvtChar is to be
+** flagged as an event by cevt.
+** fDtrFlow - Indicates that the DTR signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear DTR, overriding this definition).
+** fRtsFlow - Indicates that the RTS signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear RTS, overriding this definition).
+** XonChar - X-ON character for both transmit and receive
+** XoffChar - X-OFF character for both transmit and receive
+** XonLim - When the number of characters in the receive queue
+** drops below this value, then an X-ON character is
+** sent, if enabled, and DTR is set, if enabled.
+** XoffLim - When the number of characters in the receive queue
+** exceeds this value, then an X-OFF character is sent,
+** if enabled, and DTR is dropped, if enabled.
+** PeChar - Parity Error replacement character.
+** EvtChar - Character which triggers an event flag.
+** EofChar - Character which specifies end of input.
+** TxDelay - Specifies the minimum amount of time that must pass
+** between transmission of characters.
+**
+** Timeouts are in milleseconds. 0 means ignore the signal. 0xffff means
+** infinite timeout.
+**
+*************************************************************************/
+typedef struct {
+ char Id; /* Internal Device ID */
+ ushort BaudRate; /* Baudrate at which runing */
+ char ByteSize; /* Number of bits/byte, 4-8 */
+ char Parity; /* 0,1,2,3,4 = None,Odd,Even,Mark,Sp*/
+ char StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ ushort RlsTimeout; /* Timeout for RLSD to be set */
+ ushort CtsTimeout; /* Timeout for CTS to be set */
+ ushort DsrTimeout; /* Timeout for DSR to be set */
+
+ uchar fBinary: 1; /* CTRL-Z as EOF flag */
+ uchar fRtsDisable:1; /* Suppress RTS */
+ uchar fParity: 1; /* Enable parity check */
+ uchar fOutxCtsFlow: 1; /* Enable output xon/xoff with cts */
+ uchar fOutxDsrFlow: 1; /* Enable output xon/xoff with dsr */
+ uchar fDummy: 3;
+
+ uchar fOutX: 1; /* Enable output X-ON/X-OFF */
+ uchar fInX: 1; /* Enable input X-ON/X-OFF */
+ uchar fPeChar: 1; /* Enable Parity Err Replacement */
+ uchar fNull: 1; /* Enable Null stripping */
+ uchar fChEvt: 1; /* Enable Rx character event. */
+ uchar fDtrflow: 1; /* Enable DTR flow control */
+ uchar fRtsflow: 1; /* Enable RTS flow control */
+ uchar fDummy2: 1;
+
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ ushort XonLim; /* Transmit X-ON threshold */
+ ushort XoffLim; /* Transmit X-OFF threshold */
+ char PeChar; /* Parity error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Recieved Event character */
+ ushort TxDelay; /* Amount of time between chars */
+ } DCB;
+
+/*************************************************************************
+**
+** COMSTAT
+** Status record returned by GetCommError
+**
+*************************************************************************/
+typedef struct {
+ uchar fCtsHold: 1; /* Transmit is on CTS hold */
+ uchar fDsrHold: 1; /* Transmit is on DSR hold */
+ uchar fRlsdHold: 1; /* Transmit is on RLSD hold */
+ uchar fXoffHold: 1; /* Transmit is on X-Off hold */
+ uchar fXoffSent: 1; /* Recieve in X-Off or DTR hold */
+ uchar fEof: 1; /* End of file character found */
+ uchar fTxim: 1; /* Character being transmitted */
+ uchar fPerr:1; /* Printer error */ /*081985*/
+ ushort cbInQue; /* count of characters in Rx Que*/
+ ushort cbOutQue; /* count of characters in Tx Que*/
+ } COMSTAT;
+
+/*************************************************************************
+**
+** DCB field definitions.
+**
+*************************************************************************/
+#define NOPARITY 0
+#define ODDPARITY 1
+#define EVENPARITY 2
+#define MARKPARITY 3
+#define SPACEPARITY 4
+
+#define ONESTOPBIT 0
+#define ONE5STOPBITS 1
+#define TWOSTOPBITS 2
+
+#define IGNORE 0 /* Ignore signal */
+#define INFINITE 0xffff /* Infinite timeout */
+
+/*************************************************************************
+**
+** Comm Device Driver Error Bits.
+**
+*************************************************************************/
+#define CE_RXOVER 0x0001 /* Receive Queue overflow */
+#define CE_OVERRUN 0x0002 /* Receive Overrun Error */
+#define CE_RXPARITY 0x0004 /* Receive Parity Error */
+#define CE_FRAME 0x0008 /* Receive Framing error */
+#define CE_CTSTO 0x0020 /* CTS Timeout */
+#define CE_DSRTO 0x0040 /* DSR Timeout */
+#define CE_RLSDTO 0x0080 /* RLSD Timeout */
+#define CE_PTO 0x0100 /* LPTx Timeout */ /*081985*/
+#define CE_IOE 0x0200 /* LPTx I/O Error */ /*081985*/
+#define CE_DNS 0x0400 /* LPTx Device not selected */ /*081985*/
+#define CE_OOP 0x0800 /* LPTx Out-Of-Paper */ /*081985*/
+#define CE_MODE 0x8000 /* Requested mode unsupported */
+
+/*************************************************************************
+**
+** Initialization Error Codes
+**
+*************************************************************************/
+#define IE_BADID -1 /* Invalid or unsupported id */
+#define IE_OPEN -2 /* Device Already Open */
+#define IE_NOPEN -3 /* Device Not Open */
+#define IE_MEMORY -4 /* Unable to allocate queues */
+#define IE_DEFAULT -5 /* Error in default parameters */
+#define IE_HARDWARE -10 /* Hardware Not Present */
+#define IE_BYTESIZE -11 /* Illegal Byte Size */
+#define IE_BAUDRATE -12 /* Unsupported BaudRate */
+/*************************************************************************
+**
+** Event mask definitions. Used by SetCommEventMask and GetCommEventMask
+**
+** RXCHAR - Set when any character is received and placed in the input
+** queue.
+** RXFLAG - Set when a particular character, as defined in the dcb, is
+** received and placed in the input queue.
+** TXEMPTY - Set when the last character in the transmit queue is
+** transmitted.
+** CTS - Set when the CTS signal changes state.
+** DSR - Set when the DSR signal changes state.
+** RLSD - Set when the RLSD signal changes state.
+** BREAK - Set when a break is detected on input.
+** ERR - Set when a line status error occurs.
+**
+*************************************************************************/
+#define EV_RXCHAR 0x0001 /* Any Character received */
+#define EV_RXFLAG 0x0002 /* Received certain character */
+#define EV_TXEMPTY 0x0004 /* Transmitt Queue Empty */
+#define EV_CTS 0x0008 /* CTS changed state */
+#define EV_DSR 0x0010 /* DSR changed state */
+#define EV_RLSD 0x0020 /* RLSD changed state */
+#define EV_BREAK 0x0040 /* BREAK received */
+#define EV_ERR 0x0080 /* Line Status Error Occurred */
+#define EV_RING 0x0100 /* Ring signal detected */
+#define EV_PERR 0x0200 /* LPTx error occured */ /*081985*/
+
+/*************************************************************************
+**
+** Extended Functions
+**
+** SETXOFF - Causes transmit to behave as if an X-OFF character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+** SETXON - Causes transmit to behave as if an X-ON character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+*************************************************************************/
+#define SETXOFF 1 /* Set X-Off for output control */
+#define SETXON 2 /* Set X-ON for output control */
+#define SETRTS 3 /* Set RTS high */
+#define CLRRTS 4 /* Set RTS low */
+#define SETDTR 5 /* Set DTR high */
+#define CLRDTR 6 /* Set DTR low */
+#define RESETDEV 7 /* Reset device if possible */ /*081985*/
diff --git a/private/mvdm/wow16/drivers/comm/comdev.inc b/private/mvdm/wow16/drivers/comm/comdev.inc
new file mode 100644
index 000000000..1238c6b62
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdev.inc
@@ -0,0 +1,103 @@
+;=========================================================================
+; Communications Device Driver Definitions - September, 1985
+;=========================================================================
+
+.xcref
+
+WIN31 = 1
+; remove unneeded things in Windows.inc
+NOGDICAPMASKS = 1
+NOVK = 1
+NOWH = 1
+NOMST = 1
+NORASTOPS = 1
+NOMETAFILE = 1
+NOMDI = 1
+NOWINMESSAGES = 1
+NOSYSMETRICS = 1
+NOCOLOR = 1
+include windows.inc
+
+DCBSize equ SIZE DCB
+DCB_Flags equ byte ptr DCB_BitMask1
+DCB_Flags2 equ byte ptr DCB_BitMask2
+
+LPTx equ 10000000b ;Flags an ID as being an LPT port
+
+
+; DCB_BitMask1 (DCB_Flags) equates
+
+fBinary equ 00000001b ;Binary mode
+fRTSDisable equ 00000010b ;Disable RTS
+fParity equ 00000100b ;Perform Parity Checking
+fOutXCTSFlow equ 00001000b ;Output handshaking using CTS
+fOutXDSRFlow equ 00010000b ;Output handshaking using DSR
+fEnqAck equ 00100000b ;ENQ/ACK software handshaking [rkh] ...
+fEtxAck equ 01000000b ;ETX/ACK software handshaking
+fDTRDisable equ 10000000b ;Disable DTR
+
+
+; DCB_BitMask2 (DCB_Flags2) equates
+
+fOutX equ 00000001b ;Output X-ON/X-OFF
+fInX equ 00000010b ;Input X-ON/X-OFF
+fPErrChar equ 00000100b ;Parity Error Replacement char active
+fNullStrip equ 00001000b ;Null Stripping
+fCharEvent equ 00010000b ;Character event
+fDTRFlow equ 00100000b ;Input handshaking using DTR
+fRTSFlow equ 01000000b ;Input handshaking using RTS
+; equ 10000000b
+
+
+; Values for RLSTimeout, CTSTimeout, DSRTimeout
+
+Ignore equ 0
+Infinite equ 0FFFFh
+
+
+; COMS_BitMask1 equates
+
+fCTSHold equ 00000001b ;Tx is on CTS hold
+fDSRHold equ 00000010b ;Tx is on DSR hold
+fRLSDHold equ 00000100b ;Tx is on RLSD hold
+fXOFFHold equ 00001000b ;Received an X-OFF
+fXOFFSent equ 00010000b ;Sent an X-OFF
+fEOF equ 00100000b ;Received defined EOF character
+fTxImmed equ 01000000b ;There's a char to transmit immediate
+; equ 10000000b
+
+
+
+; Event mask definitions. Used by SetCommEventMask and GetCommEventMask
+;
+; RXCHAR - Set when any character is received and placed in the input
+; queue.
+; RXFLAG - Set when a particular character, as defined in the DCB,
+; is received and placed in the input queue.
+; TXEMPTY - Set when the last character in the transmit queue is
+; transmitted.
+; CTS - Set when the CTS signal changes state.
+; DSR - Set when the DSR signal changes state.
+; RLSD - Set when the RLSD signal changes state.
+; BREAK - Set when a break is detected on input.
+; RING - Set when Ring Indicator is detected
+; ERR - Set when a line status error occurs.
+
+
+;=========================================================================
+;
+; qdb
+; Queue definition block. Passed to setqueue, defines the location and
+; size of the transmit and receive circular queue's used for interrupt
+; transmit and recieve processing.
+;
+;=========================================================================
+
+QDB struc
+ QueueRxAddr dd ? ;Pointer to RX Queue, Offset
+ QueueRxSize dw ? ;Size of RX Queue in bytes
+ QueueTxAddr dd ? ;Pointer to TX Queue, Offset
+ QueueTxSize dw ? ;Size of TX Queue in bytes
+QDB ends
+
+.cref
diff --git a/private/mvdm/wow16/drivers/comm/comdevi.h b/private/mvdm/wow16/drivers/comm/comdevi.h
new file mode 100644
index 000000000..f640125c2
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdevi.h
@@ -0,0 +1,28 @@
+/*************************************************************************
+**
+** qdb
+** que definition block.
+**
+*************************************************************************/
+typedef struct {
+ char far *pqRx; /* pointer to rx queue */
+ short cbqRx; /* size of RX Queue in bytes */
+ char far *pqTx; /* Pointer to TX Queue */
+ short cbqTx; /* Size of TX Queue in bytes */
+ } qdb;
+
+ushort far pascal inicom(DCB far *);
+ushort far pascal setcom(DCB far *);
+void far pascal setque();
+int far pascal reccom();
+ushort far pascal sndcom();
+ushort far pascal ctx();
+short far pascal trmcom();
+ushort far pascal stacom();
+ushort far pascal cextfcn();
+ushort far pascal cflush();
+ushort far *far pascal cevt();
+ushort far pascal cevtGet();
+int far pascal csetbrk();
+int far pascal cclrbrk();
+DCB far *far pascal getdcb();
diff --git a/private/mvdm/wow16/drivers/comm/comm.def b/private/mvdm/wow16/drivers/comm/comm.def
new file mode 100644
index 000000000..99b887da8
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.def
@@ -0,0 +1,42 @@
+LIBRARY COMM
+
+DESCRIPTION 'Windows Communications Driver'
+
+EXETYPE WINDOWS
+STUB '..\..\bin\WINSTUB.EXE'
+
+DATA PRELOAD FIXED SINGLE
+
+SEGMENTS
+ _INIT PRELOAD MOVEABLE DISCARDABLE SHARED
+ _TEXT MOVEABLE DISCARDABLE SHARED
+ _INTERRUPT PRELOAD FIXED SHARED
+
+
+EXPORTS
+ inicom @1
+ setcom @2
+ setque @3
+ reccom @4
+ sndcom @5
+ ctx @6
+ trmcom @7
+ stacom @8
+ cextfcn @9
+ cflush @10
+ cevt @11
+ cevtGet @12
+ csetbrk @13
+ cclrbrk @14
+ getdcb @15
+; mapdevname @16 ;Reserved for mapping dev to cid
+ SuspendOpenCommPorts @17 ;for 286 winoldaps only
+ ReactivateOpenCommPorts @18 ;for 286 winoldaps only
+ CommWriteString @19 ; for fast lpt output
+ ReadCommString @20 ; for fast input
+ EnableNotification @100
+ WEP
+
+IMPORTS
+ CreateSystemTimer = SYSTEM.2
+ GetSystemMsecCount = SYSTEM.6
diff --git a/private/mvdm/wow16/drivers/comm/comm.rc b/private/mvdm/wow16/drivers/comm/comm.rc
new file mode 100644
index 000000000..fabcbab37
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* COMM.RC */
+/********************************************************************/
+#include "comm.rcv"
diff --git a/private/mvdm/wow16/drivers/comm/comm.rcv b/private/mvdm/wow16/drivers/comm/comm.rcv
new file mode 100644
index 000000000..ea8edd8c4
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* COMM.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_COMM
+#define VER_FILEDESCRIPTION_STR "Windows COMM Driver"
+#define VER_INTERNALNAME_STR "COMM"
+#define VER_ORIGINALFILENAME_STR "COMM.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/comm/commmsg.asm b/private/mvdm/wow16/drivers/comm/commmsg.asm
new file mode 100644
index 000000000..8980166dc
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/commmsg.asm
@@ -0,0 +1,51 @@
+.xlist
+include cmacros.inc
+.list
+
+
+sBegin Data
+
+PUBLIC szMessage, pLPTByte
+PUBLIC szCOMMessage, pCOMByte
+PUBLIC _szTitle
+
+szMessage db 'The LPT'
+pLPTByte db '?'
+ db ' port is currently assigned to a DOS application. Do you '
+ db 'want to reassign the port to Windows?',0
+szCOMMessage db 'The COM'
+pCOMByte db '?'
+ db ' port is currently assigned to a DOS application. Do you '
+ db 'want to reassign the port to Windows?',0
+_szTitle db 'Device Conflict',0
+
+PUBLIC lpCommBase, CommBaseX
+lpCommBase db 'COM'
+CommBaseX db ?
+ db 'BASE', 0
+
+PUBLIC lpCommIrq, CommIrqX
+lpCommIrq db 'COM'
+CommIrqX db ?
+ db 'IRQ', 0
+
+PUBLIC lpCommFifo, CommFifoX
+lpCommFifo db 'COM'
+CommFifoX db ?
+ db 'FIFO', 0
+
+PUBLIC lpCommDSR, CommDSRx
+lpCommDSR db 'COM'
+CommDSRx db ?
+ db 'FORCEDSR', 0
+
+PUBLIC lpCommSection, lpSYSTEMINI
+
+lpCommSection db '386ENH', 0
+lpSYSTEMINI db 'SYSTEM.INI', 0
+
+ ALIGN 2
+
+sEnd Data
+
+End
diff --git a/private/mvdm/wow16/drivers/comm/ddkmake b/private/mvdm/wow16/drivers/comm/ddkmake
new file mode 100644
index 000000000..f148215e4
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ddkmake
@@ -0,0 +1,47 @@
+# International mods
+# NOTE: LANG is a external macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=.\messages\$(LANG)
+!ENDIF
+
+#
+# Standard command line definitions
+#
+OPT= /W2 #NOP the options feature
+as=masm
+MASMOBJ=$(as) $(OPT)
+#
+# DOS 3.x inference rules
+#
+.asm.obj:
+ $(MASMOBJ) $*.asm;
+
+.asm.lst:
+ $(as) $(OPT) /l $*.asm;
+
+comm: comm.drv
+
+ccom.obj ccom.lst: ccom.asm ibmcom.inc comdev.inc
+
+ibmsetup.obj ibmsetup.lst: ibmsetup.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmcom.obj: ibmcom.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmint.obj: ibmint.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmlpt.obj: ibmlpt.asm ibmcom.inc comdev.inc
+
+commmsg.obj: $(RES_DIR)\commmsg.asm
+ $(MASMOBJ) $(RES_DIR)\commmsg.asm, commmsg.obj;
+
+comm.drv: iclean ccom.obj ibmsetup.obj ibmcom.obj ibmint.obj ibmlpt.obj commmsg.obj \
+ comm.def comm.rc comm.rcv
+ link ccom+ibmsetup+ibmcom+ibmint+ibmlpt+commmsg,comm.drv,comm.map/map,libw /NOD /AL:16,comm.def
+ rc comm.rc comm.drv
+ mapsym comm
+
+iclean:
+ del comm.drv
+ del commmsg.obj
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom.asm b/private/mvdm/wow16/drivers/comm/ibmcom.asm
new file mode 100644
index 000000000..653726cf1
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom.asm
@@ -0,0 +1,1947 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMCOM.ASM
+;
+; !!!
+;
+; Created: Fri 06-Feb-1987 10:45:12
+; Author: Walt Moore [waltm]
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+;
+; ***************************************************************
+; Tue Dec 19 1989 09:32:15 -by- Amit Chatterjee [amitc]
+; ---------------------------------------------------------------
+; Modified the 'InitAPort' routine called from 'ReactivateOpenCommPort'.
+; If the out queue for a port has characters to send out then we must
+; restart the trasmission process by faking a comm interrupt on that
+; port.
+; ***************************************************************
+; Tue Nov 21 1989 09:46:50 -by- Amit Chatterjee [amitc]
+; ---------------------------------------------------------------
+; The base port addresses in the COMM1,COMM2,COMM3,COMM4 structures
+; are being zeroed out when the corresponding comm port is closed.
+; This is because the 'ReactivateOpenCommPort' function looks at it
+; and if the port address is not zero decides that comm ports are
+; open.
+; ***************************************************************
+; Tue Nov 14 1989 18:42:00 ADDED TWO EXPORTED FUNCTIONS
+; ---------------------------------------------------------------
+; Added two exported functions 'SuspendOpenCommPorts' and
+; 'ReactivateOpenCommPorts' for 286 winoldap support. The first one simply
+; releases the comm int vects and installs the originall one, the second one
+; hooks back the comm driver comm vectors and then reads the receive buffer,
+; the status and the IIR registers of all the available comm ports to
+; remove pending interrupts. It also reprograms the PIC to enable interrupts
+; on all open comm channels.
+; ---------------------------------------------------------------
+; -by- Amit Chatterjee [amitc]
+; ***************************************************************
+; Tue Aug 30 198? 12:52:00 MAJOR FIX TO HANDLE 8250B
+; ---------------------------------------------------------------
+;
+; 8250B has the following peculiar charactersistic
+; . The very first time (after reset) the Tx Holding Empty
+; interrupt is enabled, an immediate interrupt is generated
+;
+; . After the first time, switching the Tx Holding Empty
+; interrupt enable bit from disabled to enabled will NOT
+; generate an immediate interrupt (unlike in 8250)
+; Because of this the KICKTX routine fails to set the transmit cycle
+; on if the machine has a 8250B
+;
+; This has been taken care as follows:
+; . For the very first byte that is being transmitted, KICKTX
+; is used to generate the first Tx Holding Empty interrupt
+; . Subsequently, whenever we find that the transmit buffer
+; is empty, we use a SOFTWARE INT (either INT 0Bh, or INT 0Ch)
+; to force the first character out, once this is done the
+; Tx Holding Empty interrupt will be generated once the buffer
+; really is empty
+; . Now we no longer disable the Tx Holding Empty interrupt
+; in the Xmit ISR to ensure that even m/cs with 8250, use
+; the software int to kick the tx interrupt on after the
+; first time.
+; . The software interrupt is also forced whenever an X-ON
+; character is received.
+;
+; The code that implements the above logic is marked out with a line
+; asterixes.
+; ------------------------------------------------------------------
+; -by- Amit Chatterjee [amitc]
+; ******************************************************************
+;
+; 062587 HSFlag and Evtmask in DoLPT. These fields do not exist
+; for LPT type devices. The code which manipulated them
+; was removed
+;
+; KickTx from $SndCom - interrupts were not disabled when
+; calling KickTx.
+;
+; $SetCom - added CLD at the start
+;
+; $SetQue - movsw ==> stosw
+;
+; 111285 Changed the Timeout from 7 to 30 seconds.
+;
+; 110885 Forgot to set EV_RxChar event when a character
+; was received.
+;
+; 102985 INS8250, INS8250B bug with enabling interrupts.
+; Setting ACE_ETBEI in the Interrupt Enable Register
+; will cause an immediate interrupt regardless of
+; whether the transmitter register is empty or not.
+; The first interrupt MAY also be missed.
+;
+; The first case is not a problem since we only enable
+; interrupts if the transmitter register is empty. The
+; second problem was showing up on Microsoft System Cards
+; in PC-XTs. The first interrupt was missed after a cold
+; boot. National claims the fix is to write the register
+; twice, which SEEMS to work...
+;
+; Added timeout code to $TRMCOM. If the number of
+; characters in the output queue doesn't decrease
+; in "Timeout" seconds, then the port will be closed
+; anyway. Also flushed the input queue and added a
+; discard-input flag for the data available interrupt
+; code to discard any input received while terminating
+; a port. $TRMCOM will return an error code if it
+; discarded any output data.
+;
+; Removed infinite timeout test in MSRWait routine.
+; Still bad, but it will timeout around 65 seconds
+; instead of never.
+;
+; 102785 LPT initialization code was jumping to InitCom90,
+; which was setting EFlags[si] to null. Well, LPTs
+; don't have an EFlags field, so the null was getting
+; stuffed over the LSB of BIOSPortLoc of the next LPT
+; device.
+;
+; 101185 Save interrupt vector when opening a comm port
+; and restore it when closing. Would you believe
+; there are actually programs that assume the
+; vector points to a non-specific 8259 ACK and
+; an IRET!
+;
+; 100985 Added MS-NET support to gain exclusive control
+; of an LPT port if DOS 3.x and not running in as
+; a server, receiver, or messenger. Required to
+; keep another application, such as command.com
+; from closing the stream or mixing their output
+; with ours.
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+title IBMCom - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+include vint.inc
+.list
+
+externNP GetDEB
+externNP DoLPT
+externNP StringToLPT
+externNP FindCOMPort
+externNP StealPort
+
+
+sBegin Data
+
+externB $MachineID
+
+sEnd Data
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECCOM - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; 'Z' clear if data available
+; AL = byte
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECCOM
+$RECCOM proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecCom10 ;Invalid Port [rkh] ...
+ jns RecCom20 ;COM port
+ jmp RecCom95 ;LPT port, return no characters
+
+RecCom10:
+ jmp RecCom100 ; Invalid Port
+
+; Before removing any charcters from the input queue, check to see
+; if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+RecCom20:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom32 ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jnz RecCom21 ; No Enq recvd & no lines dropped
+ jmp RecCom60 ; No Enq recvd & no lines dropped
+RecCom21:
+ jmp short RecCom34
+
+RecCom32:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jnz RecCom33 ; No XOFF sent & no lines dropped
+ jmp RecCom60 ; No XOFF sent & no lines dropped
+RecCom33:
+
+RecCom34:
+ mov ax,QInCount[si] ;Get current count of input chars
+ cmp ax,[si.DCB_XonLim] ;See if at XOn limit
+ ja RecCom60 ;Not at XOn limit yet
+
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ call DOCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz RecCom40 ; No
+ add dl,ACE_MCR ;--> Modem control register
+ in al,dx
+ or al,ah ;Turn on the hardware bits
+ iodelay
+ out dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+RecCom40:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom47 ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecCom55 ; No
+ and cl,NOT EnqReceived
+ jmp short RecCom50
+
+RecCom47:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecCom55 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecCom50:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecCom55:
+ mov HSFlag[si],cl ;Store handshake flag
+ call DOSTI ;Can allow interrupts now
+
+; Now we can get down to the business at hand, and remove a character
+; from the receive queue. If a communications error exists, we return
+; that, and nothing else.
+
+RecCom60:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecCom100 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecCom90 ;No characters in the queue
+ les di,QInAddr[si] ;Get queue pointer
+ assumes es,nothing
+
+ mov bx,QInGet[si] ;Also get the index to head
+ mov al,es:[bx][di] ;Finally, get byte from queue
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc RecCom70 ;Jump if no wrap
+ xor bx,bx ;wrap by zeroing the index
+
+RecCom70:
+ mov QInGet[si],bx ;Save new head pointer
+ dec QInCount[si] ;Dec # of bytes in queue
+
+ mov cx, [si.QinCount]
+ cmp cx, [si.RecvTrigger] ;Q: have we read below trigger?
+ jae RecCom80 ; N:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again
+RecCom80:
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecCom90:
+ test [si.DCB_Flags],fBinary ;Are we doing binary stuff?
+ jnz RecCom95 ; Yes, show no characters
+ mov al,[si.DCB_EofChar] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecCom80 ; Yes, show end of file
+
+RecCom95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecCom100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECSTR - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; ES:DI -> receive buffer
+; CX max bytes to read
+; Returns:
+; 'Z' clear if data available
+; AX = # of bytes read
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECSTR
+$RECSTR proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecStr10 ;Invalid Port [rkh] ...
+ jns RecStr20 ;COM port
+ jmp RecStr95 ;LPT port, return no characters
+
+RecStr10:
+ jmp RecStr100 ; Invalid Port
+RecStr15:
+ jmp RecStr90
+
+RecStr20:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecStr10 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecStr15 ;No characters in the queue
+
+ cmp cx, ax ;Q: more chars available than can read?
+ jbe short RecStr30 ; N:
+ mov cx, ax ; Y: adjust # of chars to read
+RecStr30:
+ push cx
+ mov dx, QInSize[si]
+ mov ax, QInGet[si]
+ sub dx, ax ; dx = # of bytes before end of buf
+ cmp dx, cx ;Q: more avail than can read?
+ jbe short RecStr40 ; N:
+ mov dx, cx ; Y: adjust avail count
+RecStr40:
+ xchg cx, dx ; cx = # of bytes for 1st copy
+ sub dx, cx ; dx = # of bytes for 2nd copy
+
+ push ds
+ push si
+ lds bx, QInAddr[si]
+ mov si, bx
+ add si, ax ; ds:si -> first char in buffer
+ cld
+ rep movsb ; do first copy
+ mov cx, dx
+ jcxz short RecStr50 ; jump if no 2nd copy needed
+ mov si, bx ; ds:si -> start of buffer
+ rep movsb ; do 2nd copy
+RecStr50:
+ sub si, bx ; si = new QInGet
+ mov bx, si
+ pop si
+ pop ds
+ pop cx
+ call DOCLI
+ mov QInGet[si], bx ; update QInGet
+ sub QInCount[si], cx ; update count
+ mov ax, QInCount[si]
+ call DOSTI
+
+ cmp ax, [si.RecvTrigger] ;Q: have we read below trigger?
+ jae @F ; N:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again
+@@:
+
+; Check to see if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz @F ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jnz RecStr58 ; No Enq recvd & no lines dropped
+ jmp RecStr80 ; No Enq recvd & no lines dropped
+RecStr58:
+ jmp short RecStr60
+
+@@:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jnz RecStr59 ; No XOFF sent & no lines dropped
+ jmp RecStr80 ; No XOFF sent & no lines dropped
+RecStr59:
+
+RecStr60:
+ ;ax = current count of input chars
+ cmp ax,[si.DCB_XonLim] ;See if at XOn limit
+ ja RecStr80 ;Not at XOn limit yet
+
+;; int 1
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ push cx
+ call DOCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz @F ; No
+ add dl,ACE_MCR ;--> Modem control register
+ in al,dx
+ or al,ah ;Turn on the hardware bits
+ iodelay
+ out dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+@@:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz @F ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecStr70 ; No
+ and cl,NOT EnqReceived
+ jmp short RecStr65
+
+@@:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecStr70 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecStr65:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecStr70:
+ mov HSFlag[si],cl ;Store handshake flag
+ call DOSTI ;Can allow interrupts now
+ pop cx
+
+RecStr80:
+ mov ax, cx
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecStr90:
+ test [si.DCB_Flags],fBinary ;Are we doing binary stuff?
+ jnz RecStr95 ; Yes, show no characters
+ mov al,[si.DCB_EofChar] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecStr80 ; Yes, show end of file
+
+RecStr95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecStr100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECSTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDIMM - Send A Character Immediately
+;
+; This routine either sends a character to the port immediately,
+; or places the character in a special location which is used by
+; the next transmit interrupt to transmit the character prior to
+; those in the normal transmit queue.
+;
+; For LPT ports, the character is always sent immediately.
+;
+; Entry:
+; AH = Device ID
+; AL = Character
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = 8000H if Bad ID
+; AX = 4000H if couldn't send because another character
+; transmitted "immediately" is waiting to be sent
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SNDIMM
+$SNDIMM proc near
+
+ push si
+ call GetDEB ;Get pointer to the DEB
+ jc SendImm20 ;Bad ID, return an error
+ jns SendImm10 ;Its a COM port
+
+
+; For LPT ports, call DoLPT to do the dirty work. If DoLPT
+; returns an error code, map it to 4000h.
+
+ xor ch,ch ;Show xmit character
+ call DoLPT ;Do the work here
+ or ax,ax ;Error occur?
+ jz SendImm20 ; No, show all is OK
+ mov ax,4000h ; Yes, return 4000h
+ jmp short SendImm20
+
+SendImm10:
+ mov dl, al
+ mov ax,4000h ;In case we cannot send
+ test EFlags[si],fTxImmed ;Another char waiting "immediately"?
+ jnz SendImm20 ; Yes, return error
+ mov ah,dl ;Set char for TXI
+ call DOCLI ;TXI is critical section code
+ call TXI ;Set character to tx immediately
+ call DOSTI
+ xor ax,ax ;Show all is OK
+
+SendImm20:
+ pop si
+ ret
+
+$SNDIMM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDCOM - Send Byte To Port
+;
+; The given byte is sent to the passed port if possible.
+; If the output queue is full, an error will be returned.
+;
+; Entry:
+; AH = Device ID
+; AL = Character
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = error code
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SNDCOM
+$SNDCOM proc near
+
+ push si
+ push di
+ call GetDEB ;--> DEB
+ jc SendCom40 ;Invalid ID
+ jns SendCom20 ;Its a COM port
+
+; Handle the transmission of a LPT character. The ROM BIOS int 17
+; call will be made to do the transmission. The port address will
+; be restored during the call, then zeroed out upon return.
+
+SendCom10:
+ xor ch,ch ;Show xmit character
+ call DoLPT ;Do the work here
+ jmp short SendCom40 ;Return the status to caller
+
+; Send a character to a COM port. Return an error if control
+; line timeout occurs or there is no room in the output queue.
+
+SendCom20:
+ push ax ;Save character
+
+ call MSRWait ;See if lines are correct for output
+ pop ax ;Restore char
+ jnz SendCom60 ;Timeout occured, return error
+ mov cx,QOutSize[si] ;See if queue is full
+ cmp cx,QOutCount[si]
+ jle SendCom50 ;There is no room in the queue
+ les di,QOutAddr[si] ;--> output queue
+ assumes es,nothing
+
+ mov bx,QOutPut[si] ;Get index into queue
+ mov es:[bx][di],al ;Store the byte
+ inc bx ;Update index
+ cmp bx,cx ;Wrap time?
+ jc SendCom30 ; No
+ xor bx,bx ;Wrap-around is a new zero pointer
+
+SendCom30:
+
+ call DOCLI
+ mov QOutPut[si],bx ;Store updated pointer
+ mov ax,QOutCount[si] ; get the count
+ inc ax ; have the updated value in AX for test later
+ mov QOutCount[si],ax ;Update queue population
+ call KickTx ;Make sure xmit interrupt is armed
+ call DOSTI
+
+ xor ax,ax ;Show no error (that we know of)
+
+;****************************************************************************
+
+SendCom40:
+ pop di
+ pop si
+ ret
+
+SendCom50:
+ or by ComErr+1[si],HIGH CE_TXFULL
+ .errnz LOW CE_TXFULL
+
+SendCom60:
+ mov ax,ComErr[si] ;Return error code to caller
+ jmp short SendCom40
+
+$SNDCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDCOMSTR - Send buffer To Port
+;
+; The given buffer is sent to the passed port if possible.
+; Once the output queue is detected as being full, a CE_TXFULL error
+; will be indicated and AX will be returned as the # of chars actually
+; queued.
+;
+; Entry:
+; DS:SI --> DEB
+; ES:DI --> buffer
+; Returns:
+; AX = # of bytes queued
+; Registers Destroyed:
+; AX,BX,CX,DX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SNDCOMSTR
+$SNDCOMSTR proc near
+
+ push cx ; save count
+ call GetDEB
+ jc cws_error ; jump if id invalid
+ jns cws_comm ; jump if COM port
+
+ call StringToLPT
+ pop cx ; discard saved count, ax = # transfered
+ jmp short cws_exit
+
+cws_error:
+ pop ax
+ sub ax, cx ; ax = # transfered
+cws_exit:
+ ret
+
+cws_comm:
+ call MSRWait ;See if lines are correct for output
+ pop cx
+ push cx
+ jnz cws_error ;Timeout occured, return error
+
+ mov dx, QOutSize[si] ;See if queue is full
+ sub dx, QOutCount[si] ; dx = # of chars free in queue
+ jg scs_loop
+ jmp scs_full ;There is no room in the queue
+
+scs_loop:
+ push cx ; save count left to send
+ cmp cx, dx ;Q: room for buffer in queue?
+ jbe @f ; Y:
+ mov cx, dx ; N: adjust size to send
+@@:
+ push cx ; save # of chars which will be copied
+ push si
+ push ds
+ push di
+ push es
+ les bx,QOutAddr[si] ;--> output queue
+ assumes es,nothing
+
+ mov dx, QOutSize[si]
+ mov di, QOutPut[si] ;Get index into queue
+ sub dx, di ; dx = # of free chars before end of queue
+ cmp dx, cx
+ jbe @f
+ mov dx, cx
+@@:
+ xchg cx, dx ; cx = # of chars for 1st copy
+ sub dx, cx ; dx = # of chars for 2nd copy
+ pop ds
+ pop si ; ds:si -> src buffer
+ assumes ds,nothing
+ add di, bx ; es:di -> current pos in queue
+ cld
+ rep movsb ; copy first section
+ mov cx, dx
+ jcxz @F
+ mov di, bx ; circle back to start of queue
+ rep movsb ; copy 2nd section
+@@:
+ sub di, bx ; di last index into queue
+ mov dx, di
+ mov di, si ; last location in src buffer
+ mov si, ds
+ mov es, si ; es:di -> last loc in src buf
+ pop ds
+ pop si ; ds:si -> ComDEB
+ assumes ds,data
+ pop bx ; # of chars copied
+ call DOCLI
+ mov QOutPut[si], dx ;new index into queue
+ add QOutCount[si], bx
+ call KickTx
+ call DOSTI
+ pop cx
+ sub cx, bx ; # of chars left to send
+ jnz scs_full_2 ; jump if none
+scs_exit:
+ pop ax
+ sub ax, cx ; ax = # transfered
+ ret
+
+scs_full:
+ call DOCLI
+ call KickTx
+ call DOSTI
+scs_full_2:
+ or by ComErr+1[si],HIGH CE_TXFULL
+ .errnz LOW CE_TXFULL
+ jmp scs_exit
+
+$SNDCOMSTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $FLUSH - Flush The Input and Output Queues
+;
+; This is a hard initialization of the transmit and receive queue's,
+; which immediately empties the given queue.
+;
+; LPT ports will just return the device error word
+;
+; Entry:
+; AH = Device ID
+; BH = Queue # to clear (0=Tx, 1=Rx)
+; Returns:
+; AX = Device Error Word. (Not reset)
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $FLUSH
+$FLUSH proc near
+
+ push si
+ push di
+ call GetDEB ;si --> DEB
+ jc Flush40 ;Invalid ID
+ js Flush30 ;LPT port, return any error
+
+ mov cx,QOutCount-QInCount ;# of bytes to zero
+ lea di,QInCount[si] ;--> receive queue data
+ or bh,bh ;Transmit queue?
+ jnz Flush10 ; No, input queue
+ add di,cx ; Yes, --> xmit queue data
+
+Flush10:
+ cld
+ push ds
+ pop es
+ assumes es,nothing
+
+ xor al,al
+ call DOCLI ;Time to worry about critical sections
+ rep stosb
+ call DOSTI
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+
+ or bh,bh ;Rx queue?
+ jz Flush30 ; No, xmit queue
+
+
+; If the queue to be cleared is the receive queue, any
+; hardware handshake must be cleared to prevent a possible
+; deadlock situation. Since we just zeroed the queue count,
+; a quick call to $RecCom should do wonders to clear any
+; receive handshake (i.e. send XON if needed).
+
+Flush20:
+ call $RECCOM ;Take care of handshakes here
+
+Flush30:
+ mov ax,ComErr[si] ;And return the error word.
+
+Flush40:
+ pop di
+ pop si
+ ret
+
+$FLUSH endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; TXI - Transmit A Character Immediately
+;
+; Set up a character to be transmitted "immediately".
+; by placing the character in a location that guarantees
+; it to be the next character transmitted.
+;
+; The check to see if the immediate character can be placed has
+; already been made prior to entry.
+;
+; Interrupts must be disabled before entering this code
+;
+; Entry:
+; AH = Character
+; DS:SI --> DEB
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; L,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public TXI ;Public for debugging
+TXI proc near
+
+; call DOCLI ;Must be done by caller!
+ or EFlags[si],fTxImmed ;Show char to xmit
+ mov ImmedChar[si],ah ;Set character to transmit next
+; jmp short KickTx ;Kick Xmit just in case
+ errn$ KickTx
+
+TXI endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; KickTx - Kick Transmitter
+;
+; "Kick" the transmitter interrupt routine into operation.
+; If the Transmitter Holding Register isn't empty, then
+; nothing needs to be done. If it is empty, then the xmit
+; interrupt needs to enabled in the IER.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public KickTx ;Public for debugging
+KickTx proc near
+
+; call DOCLI ;Done by caller
+ test [si.VCDflags], 1 ;Q: we still own port?
+ jnz can_we_steal ; N:
+
+enable_int:
+ mov dx,Port[si] ;Get device I/O address
+ add dl,ACE_IER ;--> Interrupt enable register
+ in al,dx ;Get current IER state
+ test al,ACE_ETBEI ;Interrupt already enabled?
+ jnz KickTx10 ; Yes, don't reenable it
+ or al,ACE_ETBEI ; No, enable it
+ out dx,al
+ iodelay ;8250, 8250-B bug requires
+ out dx,al ; writting register twice
+
+KickTx10:
+; call DOSTI ;Done by caller
+ ret
+
+can_we_steal:
+ call StealPort ; call VCD to see if we can steal
+ ; the port back
+ jnc short enable_int ; jump, if we got it
+;
+; flush out queue
+;
+ xor ax, ax
+ mov [si.QOutCount], ax
+ mov [si.QOutMod], ax
+ mov ax, [si.QOutGet]
+ mov [si.QOutPut], ax
+ jmp short KickTx10 ; N:
+
+KickTx endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; MSRWait - Modem Status Register Wait
+;
+; This routine checks the modem status register for CTS, DSR,
+; and/or RLSD signals. If a timeout occurs while checking,
+; the appropriate error code will be returned.
+;
+; This routine will not check for any signal with a corresponding
+; time out value of 0 (ignore line).
+;
+; Entry:
+; SI --> DEB
+; Returns:
+; AL = error code
+; ComErr[si] updated
+; 'Z' set if no timeout
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public MSRWait ;Public for debugging
+
+MSRWait proc near
+
+ push di
+
+MSRRestart:
+ xor di,di ;Init Timer
+
+MSRWait10:
+ mov cx,11 ;Init Delay counter (used on non-ATs)
+
+MSRWait20:
+ xor dh,dh ;Init error accumulator
+ mov al,MSRShadow[si] ;Get Modem Status
+ and al,MSRMask[si] ;Only leave bits of interest
+ xor al,MSRMask[si] ;0 = line high
+ jz MSRWait90 ;All lines of interest are high
+ mov ah,al ;ah has 1 bits for down lines
+
+ shl ah,1 ;Line Signal Detect low?
+ jnc MSRWait30 ; No, it's high
+ .errnz ACE_RLSD-10000000b
+ cmp di,[si.DCB_RlsTimeout] ;RLSD timeout yet?
+ jb MSRWait30 ; No
+ or dh,CE_RLSDTO ;Show modem status timeout
+
+MSRWait30:
+ shl ah,1 ;Data Set Ready low?
+ shl ah,1
+ .errnz ACE_DSR-00100000b
+ jnc MSRWait40 ; No, it's high
+ cmp di,[si.DCB_DsrTimeout] ;DSR timeout yet?
+ jb MSRWait40 ; No
+ or dh,CE_DSRTO ;Show data set ready timeout
+
+MSRWait40:
+ shl ah,1 ;CTS low?
+ jnc MSRWait50 ; No, it's high
+ .errnz ACE_CTS-00010000b
+ cmp di,[si.DCB_CtsTimeout] ;CTS timeout yet?
+ jb MSRWait50 ; No
+ or dh,CE_CTSTO ;Show clear to send timeout
+
+MSRWait50:
+ or dh,dh ;Any timeout occur?
+ jnz MSRWait80 ; Yes
+
+ cmp [$MachineID],0FCh ;Is this a PC-AT? [rkh debug for PS/2]
+ je MSRWait60 ; Yes, use ROM function
+ loop MSRWait20 ; No, continue until timeout
+ jmp short MSRWait70 ;Should have taken about a millisecond
+
+MSRWait60:
+ push bx ;Special SALMON ROM routine to delay
+ push di
+ xor cx,cx ;Number of Microseconds to delay
+ mov dx,1000 ; in CX:DX
+ mov ah,86h
+ int 15h ;Wait 1 millisecond
+ pop di
+ pop bx
+
+MSRWait70:
+ inc di ;Timer +1
+ jmp short MSRWait10 ;Until Timeout or Good status
+
+MSRWait80:
+ xor ah,ah
+ mov al,dh
+ or by ComErr[si],al ;Return updated status
+ .errnz HIGH CE_CTSTO
+ .errnz HIGH CE_DSRTO
+ .errnz HIGH CE_RLSDTO
+
+MSRWait90:
+ or al,al ;Set 'Z' if no timeout
+ pop di
+ ret
+
+MSRWait endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVT - Set Event Mask
+;
+; Set up event word and mask. Returns a pointer to a word in which
+; certain bits, as enabled by the mask, will be set when certain
+; events occur.
+;
+; Entry:
+; AH = Device ID
+; BX = Event enable mask
+; Returns:
+; DX:AX --> event word.
+; Error Returns:
+; AX = 0 if error
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVT
+$EVT proc near
+
+ push si
+ xor dx,dx ;In case of error
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx ;Finish setting error return value
+ jc Evt10 ;Illegal id, return error
+ js Evt10 ;LPTx, return error
+ mov EvtMask[si],bx ;Save the new event mask
+ lea ax,EvtWord[si] ;Get address of event word
+ mov dx,ds ; into dx:ax
+
+Evt10:
+ pop si
+ ret
+
+$EVT endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVTGET - Get Event Word
+;
+; Return and clear fields in the event word. This routine MUST be used
+; by applications to read the event word, as it is the ONLY way they
+; can be assured that an event is not lost between reading the flags
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; BX = Event clear mask
+; Returns:
+; AX = event word
+; Error Returns:
+; None
+; Registers Preserved:
+; AX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; BX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVTGET
+$EVTGET proc near
+
+ push si
+ call GetDEB
+ mov ah,0 ;In case of error (AL already 0)
+ jc EvtGet10 ;Illegal ID
+ js EvtGet10 ;Illegal ID
+ call DOCLI ;No interrupts allowed
+ mov ax,EvtWord[si] ;Get the current event word
+ not bx ;Convert mask for our purposes
+ and bx,ax ;Clear events that user wants us to
+ mov EvtWord[si],bx ;And save those results
+ call DOSTI ;Magic over
+
+EvtGet10:
+ pop si
+ ret
+
+$EVTGET endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $STACOM - Return Status Information
+;
+; Returns the number of bytes in both queues.
+;
+; LPT ports will show both queues empty.
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; ES:BX = Pointer to status structure to be updated.
+; = Null if not to update
+; Returns:
+; AX = comm error word
+; Status Structure Updated.
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $STACOM
+$STACOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer in SI
+ jc StaCom30 ;Invalid ID
+ mov cx,es ;Is the pointer NULL?
+ or cx,bx
+ jz StaCom25 ; Yes, just return error code
+ xor cx,cx
+ xor dx,dx
+ or ah,ah ;Set 'S' if LPT port
+ mov ax,cx ;For LPTs, everything is zero
+ js StaCom20 ;LPT port
+
+; Need to get the status for a com port. Since not all the
+; status is contained within EFlags, it has to be assembled.
+; Also note that currently there is no way to specify RLSD
+; as a handshaking line, so fRLSDHold is always returned false.
+
+ mov al,MSRShadow[si] ;Get state of hardware lines
+ and al,OutHHSLines[si] ;Mask off required bits
+ xor al,OutHHSLines[si] ;1 = line low
+ mov cl,4 ;Align bits
+ shr al,cl ;al = fCTSHold + fDSRHold
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz fCTSHold-00000001b
+ .errnz fDSRHold-00000010b
+
+ mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent
+ and ah,XOffReceived+XOffSent
+ or al,ah
+
+ .errnz XOffReceived-fXOFFHold
+ .errnz XOffSent-fXOFFSent
+
+ mov ah,EFlags[si] ;Get fEOF+fTxImmed
+ and ah,fEOF+fTxImmed
+ or al,ah
+
+ mov cx,QInCount[si] ;Get input queue count
+ mov dx,QOutCount[si] ;Get tx queue count
+
+StaCom20:
+ mov es:[bx.COMS_BitMask1],al
+ mov es:[bx.COMS_cbInQue],cx
+ mov es:[bx.COMS_cbOutQue],dx
+
+StaCom25:
+ xor ax,ax ;Return old com error
+ xchg ax,ComErr[si] ; and clear it out
+
+StaCom30:
+ pop si
+ ret
+
+$STACOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SetBrk - Set Break
+;
+; Clamp the Tx data line low. Does not wait for the
+; transmitter holding register and shift registers to empty.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SETBRK
+$SETBRK proc near
+
+ mov cx,0FF00h+ACE_SB ;Will be setting break
+ jmp short ClrBrk10
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+$SETBRK endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $CLRBRK - Clear Break
+;
+; Release any BREAK clamp on the Tx data line.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $CLRBRK
+$CLRBRK proc near
+
+ mov cx,(NOT ACE_SB) SHL 8
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+ClrBrk10:
+ push si
+ call GetDEB ;Get DEB address
+ jc ClrBrk30 ;Invalid ID
+ js ClrBrk20 ;Ignored for LPT ports
+ call DOCLI
+ and HSFlag[si],ch ;Set or clear the BreakSet bit
+ or HSFlag[si],cl
+
+; ch = mask to remove bits in the Line Control Register
+; cl = mask to turn bits on in the Line Control Register
+
+ mov dx,Port[si] ;Get comm device base I/O port
+ add dl,ACE_LCR ;Point at the Line Control Regieter
+ in al,dx ;Get old line control value
+ and al,ch ;Turn off desired bits
+ or al,cl ;Turn on desired bits
+ iodelay
+ out dx,al ;Output New LCR.
+ call DOSTI
+
+ClrBrk20:
+ mov ax,ComErr[si] ;Return Status Word
+
+ClrBrk30:
+ pop si
+ ret
+
+$CLRBRK endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EXTCOM - Extended Comm Functions
+;
+; A number of extended functions are routed through this entry point.
+;
+; Functions currently implemented:
+;
+; 0: Ignored
+; 1: SETXOFF - Exactly as if X-OFF character has been received.
+; 2: SETXON - Exactly as if X-ON character has been received.
+; 3: SETRTS - Set the RTS signal
+; 4: CLRRTS - Clear the RTS signal
+; 5: SETDTR - Set the DTR signal
+; 6: CLRDTR - Clear the DTR signal
+; 7: RESET - Yank on reset line if available (LPT devices)
+;
+; Entry:
+; AH = Device ID
+; BL = Function Code
+; (0-127 are MS-defined, 128-255 are OEM defined)
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+; Dispatch table for the extended functions
+
+ExtTab dw ExtComDummy ;Function 0: Never Mind
+ dw ExtCom_FN1 ;1: Set X-Off
+ dw ExtCom_FN2 ;2: Clear X-Off
+ dw ExtCom_FN3 ;3: Set RTS
+ dw ExtCom_FN4 ;4: Clear RTS
+ dw ExtCom_FN5 ;5: Set DSR
+ dw ExtCom_FN6 ;6: Clear DSR
+ dw ExtCom_FN7 ;7: Reset printer
+ dw ExtCom_FN8 ;8: Get Max LPT Port
+ dw ExtCom_FN9 ;9: Get Max COM Port
+ dw ExtCom_FN10 ;10: Get COM Port Base & IRQ
+ dw ExtCom_FN10 ;11: Get COM Port Base & IRQ
+%OUT fix this for bld 32 -- GetBaseIRQ is now 10
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EXTCOM
+$EXTCOM proc near
+
+ push si
+ push di
+ call GetDEB ;Get DEB pointer
+ jc ExtCom40 ;Invalid ID, return error
+ mov dx,Port[si] ; get port address
+ jns ExtCom10 ;Its a COM port
+ cmp bl,7 ;RESET extended function?
+ jne ExtCom30 ; No, return error word
+ jmp short ExtCom20 ; Yes, invoke the function
+
+ExtCom10:
+ cmp bl,11 ;Last fcn supported
+ ja ExtCom30 ;Not an implemented function.
+
+ExtCom20:
+ xor bh,bh
+ add bx,bx ;Shift for the call
+ call DOCLI ;Consider as critical sections
+ call ExtTab[bx] ; and perform the function
+ call DOSTI
+ jc ExtCom40 ; jump if sub returns data in DX:AX
+
+ExtCom30:
+ mov ax,ComErr[si] ;Return standard error word
+ xor dx, dx
+
+ExtCom40:
+ pop di
+ pop si
+
+ ret
+
+$EXTCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN1 - Extended Function Set X-Off
+;
+; Analagous to receiving an X-OFF character. Bufferred transmision of
+; characters is halted until an X-ON character is received, or until
+; we fake that with a Clear X-Off call.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN1
+ExtCom_FN1 proc near
+
+ or HSFlag[si],XOffReceived
+ExtComDummy:
+ clc
+ ret
+
+ExtCom_FN1 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN2 - Extended Function Clear X-Off
+;
+; Analagous to receiving an X-ON character. Buffered
+; transmission of characters is restarted.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN2
+ExtCom_FN2 proc near
+
+ and HSFlag[si],NOT XOffReceived
+ call KickTx ;Kick transmitter interrupts on
+ clc
+ ret
+
+ExtCom_FN2 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN3 - Extended Function Set RTS
+;
+; Set the RTS signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN3
+ExtCom_FN3 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ or al,ACE_RTS ;Set RTS
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN3 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN4 - Extended Function Clear RTS
+;
+; Set the RTS signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN4
+ExtCom_FN4 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ and al,NOT ACE_RTS ;Clear RTS
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN4 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN5 - Extended Function Set DTR
+;
+; Set the DTR signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN5
+ExtCom_FN5 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ or al,ACE_DTR ;Set DTR
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN5 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN6 - Extended Function Clear DTR
+;
+; Set the DTR signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN6
+ExtCom_FN6 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ and al,NOT ACE_DTR ;Clear DTR
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN6 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN7 - Extended Function Reset Printer
+;
+; Assert the RESET line on an LPT port
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN7
+ExtCom_FN7 proc near
+
+ call DOSTI ;Not called at interrupt time
+ mov ch,1 ;ROM BIOS Reset Port
+ call DoLPT ;Perform the function
+ clc
+ ret
+
+ExtCom_FN7 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN8 - Get Num Ports
+;
+; Entry:
+; Returns:
+; AX = Max LPT port id
+; DX = 0
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN8
+ExtCom_FN8 proc near
+
+ mov ax, MAXLPT + LPTx
+ xor dx, dx
+ stc
+ ret
+
+ExtCom_FN8 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN9 - Get Max COM Port
+;
+; Entry:
+; Returns:
+; AX = Max COM port id
+; DX = 0
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN9
+ExtCom_FN9 proc near
+
+ mov ax, MAXCOM
+ xor dx, dx
+ stc
+ ret
+
+ExtCom_FN9 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN10 - Get COM Port Bas & IRQ
+;
+; Entry:
+; AH = com id
+; DS:SI -> DEB
+; Returns:
+; AX = base
+; DX = irq
+; Error Returns:
+; None
+; Registers Preserved:
+; DS
+; Registers Destroyed:
+; AX,BX,CX,DX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN10
+ExtCom_FN10 proc near
+
+ call FindCOMPort
+ stc
+ ret
+
+ExtCom_FN10 endp
+page
+
+
+ifdef DEBUG
+ public RecCom40, RecCom50, RecCom60, RecCom70, RecCom80
+ public RecCom90, RecCom95, RecCom100
+ public SendImm10, SendImm20,
+ public SendCom10, SendCom20, SendCom30, SendCom40, SendCom50, SendCom60
+ public Flush10, Flush20, Flush30, Flush40
+ public KickTx10
+ public Evt10
+ public EvtGet10
+ public StaCom20, StaCom25, StaCom30
+ public ClrBrk10, ClrBrk20, ClrBrk30
+ public ExtCom10, ExtCom20, ExtCom30, ExtCom40, ExtComDummy
+ public MSRRestart, MSRWait10, MSRWait20, MSRWait30, MSRWait40
+ public MSRWait50, MSRWait60, MSRWait70, MSRWait80, MSRWait90
+endif
+
+
+DOSTI proc near
+ FSTI
+ ret
+DOSTI endp
+
+DOCLI proc near
+ FCLI
+ ret
+DOCLI endp
+
+
+sEnd code
+End
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom.inc b/private/mvdm/wow16/drivers/comm/ibmcom.inc
new file mode 100644
index 000000000..cdf4608c1
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom.inc
@@ -0,0 +1,265 @@
+DEBUG equ 1
+
+No_DOSX_Bimodal_Services = 1
+IFDEF No_DOSX_Bimodal_Services
+%OUT generating code to handle ints without Bimodal Interrupt Services for DOSX
+ENDIF
+
+wo equ word ptr
+by equ byte ptr
+
+MAXLPT equ 2 ;3 LPTs supported (LPT1,2,3)
+MAXCOM equ 3 ;4 COMs supported (COM1,2,3,4)
+
+RS232B equ 0h ;RS232 Card(s) I/O addr 40:Save area.
+LPTB equ 8h ;LPT Card(s) I/O addr 40:Save area.
+
+IRQ3 equ 0bh ; Int vector for Com card @ 2xxh
+IRQ4 equ 0ch ; Int vector for Com card @ 3xxh
+
+INTA0 equ 20h ;X'20' 8259 Interrupt Control Port
+INTA1 equ 21h ;X'21' 8259 Interrupt Mask Port
+EOI equ 20h ;X'20' 8259 End-of-Interrupt ack
+
+Open equ 0201h ;Int 2F open request
+Close equ 0202h ;Int 2F close request
+Lock2F equ 0203h ;Int 2F lock request
+Unlock2F equ 0204h ;Int 2F unlock request
+
+
+; COMDEB - Communications Device Equipment Block.
+;
+; This is essentially a superset of the DCB used outside of this
+; module. The DCB is contained within the DEB as the first fields.
+; The fields which follow are data and status fields which
+; are unique to this implementation.
+;
+; AltQInAddr and AltQOutAddr are alternate queue pointers which are used when
+; in "supervisor" mode. Supervisor mode is a processor mode other than the
+; one which Windows normally runs in. In standard mode Windows, supervisor
+; mode is REAL mode. In enhanced mode Windows, supervisor mode is RING 0
+; protected mode. For more details see comments in IBMINT.ASM.
+
+ComDEB struc ;RS232 Data Equip Block
+
+ ComDCB db ((DCBSize+1) and 0FFFEh) DUP (0)
+
+ ComErr dw 0 ;Non-zero if I/O error
+ Port dw 0 ;Base I/O Address
+ NotifyHandle dw 0
+ NotifyFlags dw 0
+ RecvTrigger dw -1 ; char count threshold for calling
+ SendTrigger dw 0 ; char count threshold for calling
+
+; The following fields are specific to com ports only
+
+ IRQhook dw 0 ; ptr to IRQ_Hook_Struc
+ NextDEB dw 0 ; ptr to next DEB that is sharing IRQ
+ XOffPoint dw 0 ;Q count where XOff is sent
+ EvtMask dw 0 ;Mask of events to check for
+ EvtWord dw 0 ;Event flags
+ QInAddr dd 0 ;Address of the queue
+ AltQInAddr dd 0 ; Addr of queue in "supervisor" mode
+ QInSize dw 0 ;Length of queue in bytes
+ QOutAddr dd 0 ;Address of the queue
+ AltQOutAddr dd 0 ; Addr of queue in "supervisor" mode
+ QOutSize dw 0 ;Length of queue in bytes
+ QInCount dw 0 ;Number of bytes currently in queue
+ QInGet dw 0 ;Offset into queue to get bytes from
+ QInPut dw 0 ;Offset into queue to put bytes in
+ QOutCount dw 0 ;Number of bytes currently in queue
+ QOutGet dw 0 ;Offset into queue to get bytes from
+ QOutPut dw 0 ;Offset into queue to put bytes in
+ EFlags db 0 ;Extended flags
+ MSRShadow db 0 ;Modem Status Register Shadow
+ ErrorMask db 0 ;Default error-checking mask
+ RxMask db 0 ;Character mask
+ ImmedChar db 0 ;Char to be transmitted immediately
+ HSFlag db 0 ;Handshake flag
+ HHSLines db 0 ;8250 DTR/RTS bits for handshaking
+ OutHHSLines db 0 ;Lines that must be high to output
+ MSRMask db 0 ;Mask of Modem Lines to check
+ MSRInfinite db 0 ;Mask of MSR lines that must be high
+ IntVecNum db 0 ;Interrupt vector number
+ LSRShadow db 0 ;Line Status Register shadow
+ QOutMod dw 0 ;characters sent mod xOnLim ENQ/ETX [rkh]
+ VCD_data dd 0
+ VCDflags db 0
+ MiscFlags db 0 ;still more flags
+ComDEB ends
+
+.errnz (SIZE ComDEB) and 1
+
+.errnz MSRShadow - EvtWord - 35
+; In 3.0 MSRShadow had this relationship to EvtWord and major COM apps all
+; use this offset of 35 to get to MSRShadow so that they can determine the
+; current status of the Modem Status bits. We need to maintain this offset
+; so that these apps will continue to run.
+
+
+; The LptDEB is identical to the ComDEB structure, except
+; all the COM port specific stuff has been removed (which
+; convientiently was stored at the end so offsets would
+; be correct). This allows the code to act indifferently
+; when accessing the strucutres for things like the port.
+
+LptDEB struc
+ xComDCB db ((DCBSize+1) AND 0FFFEh) dup (0)
+ xComErr dw 0 ;Non-zero if I/O error
+ xPort dw 0 ;Base I/O Address
+ xNotifyHandle dw 0
+ xNotifyFlags dw 0
+ xRecvTrigger dw -1 ; char count threshold for calling
+ xSendTrigger dw 0 ; char count threshold for calling
+
+ BIOSPortLoc dw 0 ;Offset to port location (i.e. 40:0)
+LptDEB ends
+
+ .errnz xComDCB-ComDCB
+ .errnz xComErr-ComErr
+ .errnz xPort-Port
+
+ .errnz xNotifyHandle-NotifyHandle
+ .errnz xNotifyFlags-NotifyFlags
+ .errnz xRecvTrigger-RecvTrigger
+ .errnz xSendTrigger-SendTrigger
+
+
+; flag equates in EFlags
+fUseDSR equ 00000001b ; set, if DSR is significant
+fNoFIFO equ 00000010b ; set, if no FIFO on port
+fFIFOchkd equ 00000100b ; set, if FIFO has been checked
+fFIFOpre equ 00001000b ; FIFO enabled when port opened
+;fEOF equ 00100000b ; defined in comdev.inc
+;fTxImmed equ 01000000b ; defined in comdev.inc
+
+fEFlagsMask equ fUseDSR OR fFIFOpre OR fFIFOchkd OR fNoFIFO ; flags which shouldn't be cleared
+
+.errnz fEFlagsMask AND (fEOF OR fTxImmed) ;can't overlap with either of the bits
+ ; that are folded into COMS_BitMask1
+
+
+; Values for NotifyFlags
+;
+CN_RecvSent equ CN_RECEIVE SHL 8
+CN_TransSent equ CN_TRANSMIT SHL 8
+
+CN_Idle equ 10000000b
+CN_Notify equ 01000000b
+
+NotifyFlagsLO equ byte ptr NotifyFlags
+NotifyFlagsHI equ byte ptr NotifyFlags+1
+
+; Values for the handshake flag
+;
+; BreakSet - True if break was set - stops transmission
+; XOffSent - True if we have sent the XOff character
+; XOffPending - True if XOff character needs to be sent
+; XOnPending - True if XOn character needs to be sent
+; HHSDown - True if host dropped required hardware lines
+; HHSDropped - True if we dropped our hardware handshake lines
+; XOffReceived - True if XOff received from host
+; HSPending - Mask to return non-zero if XOn or Xoff must be sent
+; HSReceived - Mask to return non-zero if handshake has been
+; received from host stopping transmission
+; CannotXmit - Mask to return non-zero if any condition
+; exists which prevents us from tranmitting.
+; HSSent - Mask to return non-zero if we sent a handshake
+
+
+XOffPending equ 00000001b ;XOff needs to be sent
+EnqPending equ 00000001b ;Enq needs to be sent [rkh]
+EtxPending equ 00000001b ;Etx needs to be sent
+
+HHSDropped equ 00000010b ;Our hardware handshake lines are down
+
+XOnPending equ 00000100b ;XOn needs to be sent
+AckPending equ 00000100b ;Ack needs to be sent (ENQ/ACK & ETX/ACK)
+
+XOffReceived equ 00001000b ;XOff character received
+EnqSent equ 00001000b ;Enq has been sent
+EtxSent equ 00001000b ;Etx has been sent
+
+XOffSent equ 00010000b ;XOff has been sent
+EnqReceived equ 00010000b ;Enq character received (ENQ/ACK)
+EtxReceived equ 00010000b ;Etx character received (ETX/ACK)
+
+HHSDown equ 00100000b ;Host hardware handshake lines are down
+
+BreakSet equ 01000000b ;Break has been set
+
+HHSAlwaysDown equ 10000000b ;set if host handshake lines were never
+ ; detected high
+
+HSPending equ XOffPending+XOnPending
+HSReceived equ XOffReceived+HHSDown
+HSSent equ XOffSent+HHSDropped
+CannotXmit equ HSPending+HSReceived+BreakSet
+
+; values for MiscFlags
+
+Discard equ 00000001b ;Discard recevied data
+
+
+iodelay macro ;;macro to insure that an instruction
+ jmp $+2 ;; fetch occurs between IN and/or OUT
+ jmp $+2 ;; instructions on the PC-AT machine
+endm
+
+
+TimeoutError equ -2 ;Timeout error code for $TRMCOM
+Timeout equ 30 ;30 second timeout
+
+DELAY_TIME equ 200 ;Delay at least 200 milliseconds
+
+
+; Status bits returned from the BIOS for LPT ports
+
+PS_NotBusy equ 10000000b ;Printer not busy
+PS_Ack equ 01000000b ;Data acknowledged
+PS_PaperOut equ 00100000b ;Out of paper
+PS_Select equ 00010000b ;Device is selected
+PS_IOError equ 00001000b ;IO error
+PS_Timeout equ 00000001b ;Timeout occured
+
+
+; status bit defines for LPT
+
+L_BITS equ 0F8h ; the status bits we want
+L_BITS_INVERT equ 048h ; must invert to match BIOS
+L_DEVBUSY equ 080h ; device busy bit
+L_TIMEOUT equ 001h ; timeout bit
+
+; control bit defines for LPT
+
+L_NORMAL equ 00Ch ; normal state: selected, no reset
+L_RESET equ 008h ; reset state
+L_STROBE equ 00Dh ; tell printer we have char
+
+
+IRQ_Hook_Struc struc
+IRQn db 0
+HookCnt db 0
+OldMask db 0
+VecN db 0FFh
+HandlerOff dw 0
+First_DEB dw 0
+OldIntVec dd 0
+IFDEF No_DOSX_Bimodal_Services
+RM_OldIntVec dd 0
+RM_HandlerOff dw 0
+ENDIF
+IRQ_Hook_Struc ends
+
+
+IFDEF No_DOSX_Bimodal_Services
+include int31.inc
+
+Get_RM_IntVector equ (Int31_Int_Serv SHL 8) + Int_Get_Real_Vec
+Set_RM_IntVector equ (Int31_Int_Serv SHL 8) + Int_Set_Real_Vec
+ENDIF
+
+;
+; flag bits for VCDflags
+;
+fCOM_ignore_ints equ 00000001b
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom1.asm b/private/mvdm/wow16/drivers/comm/ibmcom1.asm
new file mode 100644
index 000000000..0998e258c
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom1.asm
@@ -0,0 +1,1556 @@
+page
+
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMCOM1.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+;----------------------------Private-Routine----------------------------;
+;
+; DoLPT - Do Function To LPT port
+;
+; The given function (output or reset) is performed to the
+; passed LPT port.
+;
+; Before a character is sent, a check is made to see if the device
+; will be able to accept the character. If it can, then the character
+; will be sent. If not, then an error will be returned. If the
+; printer is selected and busy and no error, then the code returned
+; will be CE_TXFULL and the handshake bits will be set in HSFlag
+; to simulate that a handshake was received.
+;
+; If the BIOS ROM code is examined, you will note that they wait for
+; the busy character from the last charcater to be cleared before
+; they strobe in the current character. This can take a long time
+; on the standard EPSON class printer (1 mSec to greater than
+; 300 mSec if the last character actually caused printing).
+;
+; Because of this, several status read retrys will be made before
+; declaring that the device is actually busy. If only one status
+; read is performed, the spooler will yeild, take a while to get
+; back here, and things will be really slow. What difference does
+; it really make if we or the BIOS does the delay, at least we can
+; break out of it at some point when it seems hopeless.
+;
+; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
+; out signal on the trailing edge of the Busy signal. If we see this
+; glitch then we report paper out. So we try to get the status twice...
+; if it changes between the two tries we keep getting the status.
+; Silly hardware people.
+;
+; Entry:
+; AH = cid
+; AL = character to output
+; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
+; DS:SI -> DEB for the port
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+ assumes ds,Data
+ assumes es,nothing
+
+include vint.inc
+
+externFP OutputDebugString
+
+dbmsg macro msg
+.286
+push cs
+push offset $ + 3 + 5 + 2 ; push + far call + short jump
+call OutputDebugString
+jmp short @F
+ db msg,13,10,0
+@@:
+endm
+
+iodelay macro
+ jmp $+2
+ jmp $+2
+endm
+
+ public DoLPT ;Publics for debugging
+ public LPT_Reset
+ public LPT_Outchar
+ public LPT_Strobe
+ public LPT_GetStatus
+ public DoLPT40
+
+; status bit defines
+
+L_BITS equ 0F8h ; the status bits we want
+L_BITS_INVERT equ 048h ; must invert to match BIOS
+L_DEVBUSY equ 080h ; device busy bit
+L_TIMEOUT equ 001h ; timeout bit
+
+; control bit defines
+
+L_NORMAL equ 00Ch ; normal state: selected, no reset
+L_RESET equ 008h ; reset state
+L_STROBE equ 00Dh ; tell printer we have char
+
+DoLPT proc near
+
+ mov dx,Port[si] ;Get port address
+
+; DX = port address
+; CH = operation: 0 = write, 1 = init, 2 = status
+; AL = character
+
+ or ch, ch
+ jz LPT_OutChar
+ cmp ch, 1
+ jz LPT_Reset
+ jmp LPT_GetStatus
+ ret
+
+LPT_Reset:
+
+ inc dx
+ inc dx
+ mov al, L_RESET
+ iodelay
+ out dx, al
+
+ push dx
+
+ cCall GetSystemMsecCount
+ mov bx, ax
+
+LPT_ResetDelay:
+ push bx
+ cCall GetSystemMsecCount
+ pop bx
+ sub ax, bx
+ cmp ax, 300 ; 1/3 sec as good as any
+ jbe LPT_ResetDelay
+
+ pop dx
+
+ mov al, L_NORMAL
+ iodelay
+ iodelay
+ out dx, al
+ dec dx
+ dec dx
+ jmp LPT_GetStatus
+
+LPT_OutChar:
+ push ax ; save character to be written
+
+ ; first check to see if printer is ready for us
+ push di
+
+ push dx
+ call GetSystemMSecCount
+ mov di, ax
+ pop dx
+
+LPT_WaitReady:
+
+ inc dx ; point to status port
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ dec dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz LPT_WaitReady
+else
+ dec dx
+endif
+
+
+ test ah, PS_PaperOut or PS_IOError
+ jnz LPT_PrinterNotReady
+ test ah, PS_Select
+ jz LPT_PrinterNotReady
+ test ah, PS_NotBusy
+ jnz LPT_PrinterReady
+
+ push ax
+ push dx
+ call GetSystemMSecCount
+ pop dx
+ pop bx
+ sub ax, di
+ cmp ax, 300 ; 1/3 sec timeout
+
+ jbe LPT_WaitReady
+
+; The device seems to be selected and powered up, but is just
+; busy (some printers seem to show selected but busy when they
+; are taken offline). Show that the transmit queue is full and
+; that the hold handshakes are set. This is so the windows
+; spooler will retry (and do yields so that other apps may run).
+
+
+ or ComErr[si],CE_TXFULL ;Show queue full
+ mov ah,bh
+ or ah, L_TIMEOUT
+
+LPT_PrinterNotReady:
+
+ pop di
+ pop cx ; throw away character
+ jmp LPT_ReturnStatus
+
+LPT_PrinterReady:
+ pop di ; get di back
+ pop ax ; get character back
+
+ iodelay
+ out dx, al ; write character to port
+
+ inc dx ; access status port
+
+LPT_Strobe:
+ inc dx ; control port
+ mov al, L_STROBE ; set strobe high
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ sub dx, 2 ; point back to port base
+
+ ; FALL THRU
+
+LPT_GetStatus:
+ inc dx ; point to status port
+LPT_GS1:
+ iodelay
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ mov ah, al
+
+ifndef NOOKIHACK
+ in al, dx
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah
+ jnz LPT_GS1 ; if they changed try again...
+endif
+
+LPT_ReturnStatus:
+
+ assumes ds,Data
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+ ret
+
+ .errnz CE_PTO-0200h
+ .errnz CE_IOE-0400h
+ .errnz CE_DNS-0800h
+ .errnz CE_OOP-1000h
+
+DoLPT40:
+ assumes ds,Data
+ or ComErr[si],CE_TXFULL ;Show queue full
+ ret
+
+DoLPT endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; TXI - Transmit A Character Immediately
+;
+; Set up a character to be transmitted "immediately".
+; by placing the character in a location that guarantees
+; it to be the next character transmitted.
+;
+; The check to see if the immediate character can be placed has
+; already been made prior to entry.
+;
+; Interrupts must be disabled before entering this code
+;
+; Entry:
+; AH = Character
+; DS:SI --> DEB
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AL,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public TXI ;Public for debugging
+TXI proc near
+
+; FCLI ;Must be done by caller!
+ or EFlags[si],fTxImmed ;Show char to xmit
+ mov ImmedChar[si],ah ;Set character to transmit next
+; jmp short KickTx ;Kick Xmit just in case
+ errn$ KickTx
+
+TXI endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; KickTx - Kick Transmitter
+;
+; "Kick" the transmitter interrupt routine into operation.
+; If the Transmitter Holding Register isn't empty, then
+; nothing needs to be done. If it is empty, then the xmit
+; interrupt needs to enabled in the IER.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public KickTx ;Public for debugging
+KickTx proc near
+
+; FCLI ;Done by caller
+ mov dx,Port[si] ;Get device I/O address
+ add dl,ACE_LSR ;Point at the line status reg
+ pin al,dx ;And get it
+ and al,ACE_THRE ;Check transmitter holding reg status
+ jz KickTx10 ;Busy, interrupt will hit soon enough
+
+ sub dl,ACE_LSR-ACE_IER ;--> Interrupt enable register
+ pin al,dx ;Get current IER state
+ test al,ACE_THREI ;Interrupt already enabled?
+ jnz KickTx10 ; Yes, don't reenable it
+ or al,ACE_THREI ; No, enable it
+ pout dx,al
+ pause ;8250, 8250-B bug requires
+ pout dx,al ; writting register twice
+
+KickTx10:
+; FSTI ;Done by caller
+ ret
+
+KickTx endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetDEB - Get Pointer To Device's DEB
+;
+; Returns a pointer to appropriate DEB, based on device number.
+;
+; Entry:
+; AH = cid
+; Returns:
+; 'C' clear
+; 'S' set if LPT device
+; DS:SI --> DEB is valid cid
+; AH = cid
+; Error Returns:
+; 'C' set if error (cid is invalid)
+; AX = 8000h
+; Registers Preserved:
+; BX,CX,DX,DI,DS,ES
+; Registers Destroyed:
+; AX,SI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public GetDEB ;Public for debugging
+GetDEB proc near
+
+ cmp ah,LPTx+MAXLPT ;Within range?
+ ja GetDEB30 ;No, return invalid ID
+ mov si,DataOFFSET LPT3 ;Assume LPT3
+ je GetDEB10 ;It's LPT3
+ cmp ah,MAXCOM ;Is cid within range for a com port?
+ ja GetDEB20 ; No, check for a LPT port 1 and 2
+ mov si,DataOFFSET Comm4 ;Assume COM4 [rkh] ...
+ je GetDEB10 ;It was COM4
+ mov si,DataOFFSET Comm3 ;Assume COM3
+ cmp ah,MAXCOM-1 ;Is cid within range for a com port?
+ je GetDEB10 ;It was COM3
+ mov si,DataOFFSET Comm2 ;Assume COM2
+ cmp ah,MAXCOM-2 ;Is cid within range for a com port?
+ je GetDEB10 ;It was COM2
+ mov si,DataOFFSET Comm1 ;It was COM1
+
+GetDEB10:
+ or ah,ah ;Set 'S' if LPT, clear 'C'
+ ret
+ .errnz LPTx-10000000b
+
+GetDEB20:
+ mov si,DataOFFSET LPT1 ;Assume LPT1
+ cmp ah,LPTx
+ je GetDEB10 ;Its LPT1
+ mov si,DataOFFSET LPT2 ;Assume LPT2
+ ja GetDEB10 ;Its LPT2
+
+GetDEB30:
+ mov ax,8000h ;Set error code
+ stc ;Set 'C' to show error
+ ret
+
+GetDEB endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETQUE - Set up Queue Pointers
+;
+; Sets pointers to Receive and Transmit Queues, as provided by the
+; caller, and initializes those queues to be empty.
+;
+; Queues must be set before $INICOM is called!
+;
+; Entry:
+; AH = Device ID
+; ES:BX --> Queue Definition Block
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; BX,DX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETQUE
+$SETQUE proc near
+
+ push si ;These will be used
+ push di
+ call GetDEB ;Get DEB
+ jc SetQue10 ;Invalid, ignore the call
+ js SetQue10 ;Ignore call for LPT ports
+ push ds ;Set ds:si --> QDB
+ push es ;Set es:di --> to ComDCB.QInAddr
+ pop ds
+ assumes ds,nothing
+ pop es
+ assumes es,Data
+ lea di,QInAddr[si]
+ mov si,bx
+ mov cx,(SIZE QDB)/2
+ .errnz (SIZE QDB) AND 1
+ xor ax,ax ;Will do some zero filling
+ cld
+ FCLI ;No one else can play with queues
+ rep movsw
+ mov cl,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 0FE01h
+ rep stosw
+ FSTI
+ push es ;Restore the data segment
+ pop ds
+ assumes ds,Data
+ assumes es,nothing
+
+SetQue10:
+ pop di ;Restore saved registers
+ pop si
+ ret
+
+; The above code made a few assumptions about how memory
+; was allocated within the structures:
+
+ .errnz (QueueRxSize-QueueRxAddr)-(QInSize-QInAddr)
+ .errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
+ .errnz (QueueTxSize-QueueTxAddr)-(QOutSize-QOutAddr)
+
+ .errnz QueueRxSize-QueueRxAddr-4
+ .errnz QueueTxAddr-QueueRxSize-2
+ .errnz QueueTxSize-QueueTxAddr-4
+
+ .errnz QInSize-QInAddr-4
+ .errnz QOutAddr-QInSize-2
+ .errnz QOutSize-QOutAddr-4
+
+ .errnz QInCount-QOutSize-2
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+$SETQUE endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVT - Set Event Mask
+;
+; Set up event word and mask. Returns a pointer to a word in which
+; certain bits, as enabled by the mask, will be set when certain
+; events occur.
+;
+; Entry:
+; AH = Device ID
+; BX = Event enable mask
+; Returns:
+; DX:AX --> event word.
+; Error Returns:
+; AX = 0 if error
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVT
+$EVT proc near
+
+ push si
+ xor dx,dx ;In case of error
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx ;Finish setting error return value
+ jc Evt10 ;Illegal id, return error
+ js Evt10 ;LPTx, return error
+ mov EvtMask[si],bx ;Save the new event mask
+ lea ax,EvtWord[si] ;Get address of event word
+ mov dx,ds ; into dx:ax
+
+Evt10:
+ pop si
+ ret
+
+$EVT endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVTGET - Get Event Word
+;
+; Return and clear fields in the event word. This routine MUST be used
+; by applications to read the event word, as it is the ONLY way they
+; can be assured that an event is not lost between reading the flags
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; BX = Event clear mask
+; Returns:
+; AX = event word
+; Error Returns:
+; None
+; Registers Preserved:
+; AX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; BX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVTGET
+$EVTGET proc near
+
+ push si
+ call GetDEB
+ mov ah,0 ;In case of error (AL already 0)
+ jc EvtGet10 ;Illegal ID
+ js EvtGet10 ;Illegal ID
+ FCLI ;No interrupts allowed
+ mov ax,EvtWord[si] ;Get the current event word
+ not bx ;Convert mask for our purposes
+ and bx,ax ;Clear events that user wants us to
+ mov EvtWord[si],bx ;And save those results
+ FSTI ;Magic over
+
+EvtGet10:
+ pop si
+ ret
+
+$EVTGET endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $STACOM - Return Status Information
+;
+; Returns the number of bytes in both queues.
+;
+; LPT ports will show both queues empty.
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; ES:BX = Pointer to status structure to be updated.
+; = Null if not to update
+; Returns:
+; AX = comm error word
+; Status Structure Updated.
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $STACOM
+$STACOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer in SI
+ jc StaCom30 ;Invalid ID
+ mov cx,es ;Is the pointer NULL?
+ or cx,bx
+ jz StaCom25 ; Yes, just return error code
+ xor cx,cx
+ xor dx,dx
+ or ah,ah ;Set 'S' if LPT port
+ mov ax,cx ;For LPTs, everything is zero
+ js StaCom20 ;LPT port
+
+; Need to get the status for a com port. Since not all the
+; status is contained within EFlags, it has to be assembled.
+; Also note that currently there is no way to specify RLSD
+; as a handshaking line, so fRLSDHold is always returned false.
+
+ mov al,MSRShadow[si] ;Get state of hardware lines
+ and al,OutHHSLines[si] ;Mask off required bits
+ xor al,OutHHSLines[si] ;1 = line low
+ mov cl,4 ;Align bits
+ shr al,cl ;al = fCTSHold + fDSRHold
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz fCTSHold-00000001b
+ .errnz fDSRHold-00000010b
+
+ mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent
+ and ah,XOffReceived+XOffSent
+ or al,ah
+
+ .errnz XOffReceived-fXOFFHold
+ .errnz XOffSent-fXOFFSent
+
+ mov ah,EFlags[si] ;Get fEOF+fTxImmed
+ and ah,fEOF+fTxImmed
+ or al,ah
+
+ mov cx,QInCount[si] ;Get input queue count
+ mov dx,QOutCount[si] ;Get tx queue count
+
+StaCom20:
+ mov es:StatFlags[bx],al
+ mov es:StatRxCount[bx],cx
+ mov es:StatTxCount[bx],dx
+
+StaCom25:
+ xor ax,ax ;Return old com error
+ xchg ax,ComErr[si] ; and clear it out
+
+StaCom30:
+ pop si
+ ret
+
+$STACOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SetBrk - Set Break
+;
+; Clamp the Tx data line low. Does not wait for the
+; transmitter holding register and shift registers to empty.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SETBRK
+$SETBRK proc near
+
+ mov cx,0FF00h+ACE_SB ;Will be setting break
+ jmp short ClrBrk10
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+$SETBRK endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $CLRBRK - Clear Break
+;
+; Release any BREAK clamp on the Tx data line.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $CLRBRK
+$CLRBRK proc near
+
+ mov cx,(NOT ACE_SB) SHL 8
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+ClrBrk10:
+ push si
+ call GetDEB ;Get DEB address
+ jc ClrBrk30 ;Invalid ID
+ js ClrBrk20 ;Ignored for LPT ports
+ FCLI
+ and HSFlag[si],ch ;Set or clear the BreakSet bit
+ or HSFlag[si],cl
+
+; ch = mask to remove bits in the Line Control Register
+; cl = mask to turn bits on in the Line Control Register
+
+ mov dx,Port[si] ;Get comm device base I/O port
+ add dl,ACE_LCR ;Point at the Line Control Regieter
+ pin al,dx ;Get old line control value
+ and al,ch ;Turn off desired bits
+ or al,cl ;Turn on desired bits
+ pause
+ pout dx,al ;Output New LCR.
+ FSTI
+
+ClrBrk20:
+ mov ax,ComErr[si] ;Return Status Word
+
+ClrBrk30:
+ pop si
+ ret
+
+$CLRBRK endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EXTCOM - Extended Comm Functions
+;
+; A number of extended functions are routed through this entry point.
+;
+; Functions currently implemented:
+;
+; 0: Ignored
+; 1: SETXOFF - Exactly as if X-OFF character has been received.
+; 2: SETXON - Exactly as if X-ON character has been received.
+; 3: SETRTS - Set the RTS signal
+; 4: CLRRTS - Clear the RTS signal
+; 5: SETDTR - Set the DTR signal
+; 6: CLRDTR - Clear the DTR signal
+; 7: RESET - Yank on reset line if available (LPT devices)
+;
+; Entry:
+; AH = Device ID
+; BL = Function Code
+; (0-127 are MS-defined, 128-255 are OEM defined)
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+; Dispatch table for the extended functions
+
+ExtTab dw ExtComDummy ;Function 0: Never Mind
+ dw ExtCom_FN1 ;1: Set X-Off
+ dw ExtCom_FN2 ;2: Clear X-Off
+ dw ExtCom_FN3 ;3: Set RTS
+ dw ExtCom_FN4 ;4: Clear RTS
+ dw ExtCom_FN5 ;5: Set DSR
+ dw ExtCom_FN6 ;6: Clear DSR
+ dw ExtCom_FN7 ;7: Reset printer
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EXTCOM
+$EXTCOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer
+ jc ExtCom40 ;Invalid ID, return error
+ mov dx,Port[si] ; get port address
+ jns ExtCom10 ;Its a COM port
+ cmp bl,7 ;RESET extended function?
+ jne ExtCom30 ; No, return error word
+ jmp short ExtCom20 ; Yes, invoke the function
+
+ExtCom10:
+ cmp bl,7 ;Last fcn supported +1
+ jnc ExtCom30 ;Not an implemented function.
+
+ExtCom20:
+ xor bh,bh
+ add bx,bx ;Shift for the call
+ FCLI ;Consider as critical sections
+ call ExtTab[bx] ; and perform the function
+ FSTI
+
+ExtCom30:
+ mov ax,ComErr[si] ;Return standard error word
+
+ExtCom40:
+ pop si
+
+ExtComDummy:
+ ret
+
+$EXTCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN1 - Extended Function Set X-Off
+;
+; Analagous to receiving an X-OFF character. Bufferred transmision of
+; characters is halted until an X-ON character is received, or until
+; we fake that with a Clear X-Off call.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN1
+ExtCom_FN1 proc near
+
+ or HSFlag[si],XOffReceived
+ ret
+
+ExtCom_FN1 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN2 - Extended Function Clear X-Off
+;
+; Analagous to receiving an X-ON character. Buffered
+; transmission of characters is restarted.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN2
+ExtCom_FN2 proc near
+
+ and HSFlag[si],NOT XOffReceived
+ jmp KickTx ;Kick transmitter interrupts on
+
+ExtCom_FN2 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN3 - Extended Function Set RTS
+;
+; Set the RTS signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN3
+ExtCom_FN3 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ or al,ACE_RTS ;Set RTS
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN3 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN4 - Extended Function Clear RTS
+;
+; Set the RTS signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN4
+ExtCom_FN4 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ and al,NOT ACE_RTS ;Clear RTS
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN4 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN5 - Extended Function Set DTR
+;
+; Set the DTR signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN5
+ExtCom_FN5 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ or al,ACE_DTR ;Set DTR
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN5 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN6 - Extended Function Clear DTR
+;
+; Set the DTR signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN6
+ExtCom_FN6 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ and al,NOT ACE_DTR ;Clear DTR
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN6 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN7 - Extended Function Reset Printer
+;
+; Assert the RESET line on an LPT port
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN7
+ExtCom_FN7 proc near
+
+ FSTI ;Not called at interrupt time
+ mov ch,1 ;ROM BIOS Reset Port
+ call DoLPT ;Perform the function
+ ret
+
+ExtCom_FN7 endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $DCBPtr - Return Pointer To DCB
+;
+; Returns a long pointer to the DCB for the requested device.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; DX:AX = pointer to DCB.
+; Error Returns:
+; DX:AX = 0
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; BX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $DCBPTR
+$DCBPTR proc near
+
+ push si
+ xor dx,dx
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx
+ jc DCBPtr10 ;Jump if invalid device
+ mov ax,si ;else return value here
+ mov dx,ds
+
+DCBPtr10:
+ pop si
+ ret
+
+$DCBPTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECCOM - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; 'Z' clear if data available
+; AL = byte
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECCOM
+$RECCOM proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecCom10 ;Invalid Port [rkh] ...
+ js RecCom20 ;LPT port, return no characters
+ jmp short RecCom30
+
+RecCom10:
+ jmp RecCom100 ; Invalid Port
+
+RecCom20:
+ jmp RecCom95 ;LPT port, return no characters
+
+; Before removing any charcters from the input queue, check to see
+; if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+RecCom30:
+ test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom32 ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jz RecCom60 ; No Enq recvd & no lines dropped
+ jmp short RecCom34
+
+RecCom32:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jz RecCom60 ; No XOFF sent & no lines dropped
+
+RecCom34:
+ mov ax,QInCount[si] ;Get current count of input chars
+ cmp ax,XONLim[si] ;See if at XOn limit
+ ja RecCom60 ;Not at XOn limit yet
+
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ FCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz RecCom40 ; No
+ add dl,ACE_MCR ;--> Modem control register
+ pin al,dx
+ or al,ah ;Turn on the hardware bits
+ pause
+ pout dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+RecCom40:
+ test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom47 ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecCom55 ; No
+ and cl,NOT EnqReceived
+ jmp short RecCom50
+
+RecCom47:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecCom55 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecCom50:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecCom55:
+ mov HSFlag[si],cl ;Store handshake flag
+ FSTI ;Can allow interrupts now
+
+; Now we can get down to the business at hand, and remove a character
+; from the receive queue. If a communications error exists, we return
+; that, and nothing else.
+
+RecCom60:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecCom100 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecCom90 ;No characters in the queue
+ les di,QInAddr[si] ;Get queue pointer
+ assumes es,nothing
+
+ mov bx,QInGet[si] ;Also get the index to head
+ mov al,es:[bx][di] ;Finally, get byte from queue
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc RecCom70 ;Jump if no wrap
+ xor bx,bx ;wrap by zeroing the index
+
+RecCom70:
+ mov QInGet[si],bx ;Save new head pointer
+ dec QInCount[si] ;Dec # of bytes in queue
+
+RecCom80:
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecCom90:
+ test Flags[si],fBinary ;Are we doing binary stuff?
+ jnz RecCom95 ; Yes, show no characters
+ mov al,EOFChar[si] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecCom80 ; Yes, show end of file
+
+RecCom95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecCom100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $FLUSH - Flush The Input and Output Queues
+;
+; This is a hard initialization of the transmit and receive queue's,
+; which immediately empties the given queue.
+;
+; LPT ports will just return the device error word
+;
+; Entry:
+; AH = Device ID
+; BH = Queue # to clear (0=Tx, 1=Rx)
+; Returns:
+; AX = Device Error Word. (Not reset)
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $FLUSH
+$FLUSH proc near
+
+ push si
+ push di
+ call GetDEB ;si --> DEB
+ jc Flush40 ;Invalid ID
+ js Flush30 ;LPT port, return any error
+
+ mov cx,QOutCount-QInCount ;# of bytes to zero
+ lea di,QInCount[si] ;--> receive queue data
+ or bh,bh ;Transmit queue?
+ jnz Flush10 ; No, input queue
+ add di,cx ; Yes, --> xmit queue data
+
+Flush10:
+ cld
+ push ds
+ pop es
+ assumes es,nothing
+
+ xor al,al
+ FCLI ;Time to worry about critical sections
+ rep stosb
+ FSTI
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+
+ or bh,bh ;Rx queue?
+ jz Flush30 ; No, xmit queue
+
+
+; If the queue to be cleared is the receive queue, any
+; hardware handshake must be cleared to prevent a possible
+; deadlock situation. Since we just zeroed the queue count,
+; a quick call to $RecCom should do wonders to clear any
+; receive handshake (i.e. send XON if needed).
+
+Flush20:
+ call $RECCOM ;Take care of handshakes here
+
+Flush30:
+ mov ax,ComErr[si] ;And return the error word.
+
+Flush40:
+ pop di
+ pop si
+ ret
+
+$FLUSH endp
+
+ifdef DEBUG
+ public KickTx10
+ public GetDEB10
+ public GetDEB20
+ public GetDEB30
+ public SetQue10
+ public Evt10
+ public EvtGet10
+ public StaCom20
+ public StaCom25
+ public StaCom30
+ public ClrBrk10
+ public ClrBrk20
+ public ClrBrk30
+ public ExtCom10
+ public ExtCom20
+ public ExtCom30
+ public ExtCom40
+ public ExtComDummy
+ public DCBPtr10
+ public RecCom30
+ public RecCom40
+ public RecCom50
+ public RecCom60
+ public RecCom70
+ public RecCom80
+ public RecCom90
+ public RecCom95
+ public RecCom100
+ public Flush10
+ public Flush20
+ public Flush30
+ public Flush40
+endif
diff --git a/private/mvdm/wow16/drivers/comm/ibmint.asm b/private/mvdm/wow16/drivers/comm/ibmint.asm
new file mode 100644
index 000000000..d902841f2
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmint.asm
@@ -0,0 +1,1374 @@
+page,132
+;---------------------------Module-Header-------------------------------
+; Module Name: IBMINT.ASM
+;
+; Created: Fri 06-Feb-1987 10:45:12
+; Author: Walt Moore [waltm]
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved
+;
+; General Description:
+; This file contains the interrupt time routines for the
+; IBM Windows communications driver.
+;
+; The interrupt code is preloaded and fixed.
+;
+; History:
+;
+; **********************************************************************
+; Tue Dec 19 1989 09:35:15 -by- Amit Chatterjee [amitc]
+; ----------------------------------------------------------------------
+; Added a far entry point 'FakeCOMIntFar' so that the routine 'FakeCOMInt'
+; could be called from the 'InitAPort' routine in IBMCOM.ASM
+;
+; 26.Nov.90 richp
+;
+; Changed interrupt routines to use new VPICD services for bi-modal/multi-
+; modal interrupt handling. They now work in straight real mode for real
+; mode Windows, but can also handle interrupts in real mode or protected
+; mode for standard mode Windows, and handle interrupts in RING 0 protected
+; mode for enhanced mode Windows, even when the Windows VM is not currently
+; executing.
+;
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+subttl Communications Hardware Interrupt Service Routines
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ibmcom.inc
+include ins8250.inc
+include BIMODINT.INC
+include vint.inc
+.list
+
+externFP GetSystemMsecCount
+
+externW COMptrs
+externW activeCOMs
+
+externD lpPostMessage
+
+sBegin Data
+
+PUBLIC IRQhooks
+IRQhooks label byte
+DefineIRQhook MACRO num
+IFDEF No_DOSX_Bimodal_Services
+IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num,,,, \
+ IntCodeOFFSET DEF_RM_COM_INT_&num>
+ELSE
+IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num>
+ENDIF
+ENDM
+??portnum = 1
+REPT MAXCOM+1
+ DefineIRQhook %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineIRQhook
+
+EXTRN VCD_int_callback:fword
+
+sEnd data
+
+createSeg _INTERRUPT,IntCode,word,public,CODE
+sBegin IntCode
+assumes cs,IntCode
+
+page
+
+IFDEF No_DOSX_Bimodal_Services
+public RM_IntDataSeg
+RM_IntDataSeg dw 0
+ ; this variable is written into by a routine in inicom
+ ; if the 286 DOS extender is present. This variable
+ ; contains the SEGMENT value of the data selector "_DATA"
+ ; so that the real mode interrupt handler may use the
+ ; data segment, and not it's selector !
+
+PUBLIC RM_CallBack
+RM_CallBack dd 0
+ENDIF
+
+
+Control proc far
+ ret
+Control endp
+
+
+IFDEF No_DOSX_Bimodal_Services
+DEF_RM_Handler proc far
+ push es
+ push di
+ push ax
+ mov es, cs:[RM_IntDataSeg]
+ mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
+ add di, SIZE ComDEB ; ES:DI -> BIS
+ mov es:[di.BIS_Mode], 4
+ push cs
+ call NEAR PTR COMHandler
+ mov es:[di.BIS_Mode], 0
+ pop ax
+ pop di ; ES:DI -> IRQ_Hook_Struc
+ jc short DEF_RM_chain
+ pop es
+ pop di
+ add sp, 4
+ iret
+
+DEF_RM_chain:
+ call DOCLI
+ push bp
+ mov bp, sp ;stack frame:
+ ; bp+8 -> OldInt CS
+ ; bp+6 -> OldInt IP
+ ; bp+4 -> di
+ ; bp+2 -> es
+ ; bp+0 -> bp
+ les di, es:[di.RM_OldIntVec]
+ mov [bp+6], di
+ mov [bp+8], es
+ pop bp
+ pop es
+ pop di
+ ret ; far ret to OldInt handler
+DEF_RM_Handler endp
+ENDIF ;No_DOSX_Bimodal_Services
+
+
+Define_DEF_COM_INT MACRO num
+IFDEF No_DOSX_Bimodal_Services
+PUBLIC DEF_RM_COM_INT_&num
+DEF_RM_COM_INT_&num proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook&num
+ jmp DEF_RM_Handler
+DEF_RM_COM_INT_&num endp
+ENDIF
+PUBLIC DEF_COM_INT_&num
+DEF_COM_INT_&num proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook&num
+ jmp DEF_Handler
+DEF_COM_INT_&num endp
+ENDM
+
+??portnum = 2
+REPT MAXCOM
+ Define_DEF_COM_INT %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE Define_DEF_COM_INT
+
+IFDEF No_DOSX_Bimodal_Services
+PUBLIC DEF_RM_COM_INT_1
+DEF_RM_COM_INT_1 proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook1
+ jmp DEF_RM_Handler
+DEF_RM_COM_INT_1 endp
+ENDIF
+
+PUBLIC DEF_COM_INT_1
+DEF_COM_INT_1 proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook1
+IF2
+.errnz $ - OFFSET DEF_Handler
+ENDIF
+DEF_COM_INT_1 endp
+
+DEF_Handler proc far
+ push es
+ push di
+ push ax
+ mov ax, _DATA
+ mov es, ax
+ mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
+ add di, SIZE ComDEB ; ES:DI -> BIS
+ push cs
+ call NEAR PTR COMHandler
+ pop ax
+ pop di ; ES:DI -> IRQ_Hook_Struc
+ jc short DEF_chain
+ pop es
+ pop di
+ add sp, 4
+ iret
+
+DEF_chain:
+ call DOCLI
+ push bp
+ mov bp, sp ;stack frame:
+ ; bp+8 -> OldInt CS
+ ; bp+6 -> OldInt IP
+ ; bp+4 -> di
+ ; bp+2 -> es
+ ; bp+0 -> bp
+ les di, es:[di.OldIntVec]
+ mov [bp+6], di
+ mov [bp+8], es
+ pop bp
+ pop es
+ pop di
+ ret ; far ret to OldInt handler
+DEF_Handler endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+; EXIT: Carry set, if IRQ not handled by any com ports
+;
+COMHandler proc far
+ push ds
+ push si
+ push ax
+ push bx
+ mov si, es
+ mov ds, si
+ mov bh, -1
+ch_chk_all:
+ lea si, [di-SIZE ComDEB] ;ds:si -> ComDEB
+ mov si, [si.IRQhook]
+ mov si, [si.First_DEB]
+ mov bl, -1
+ch_next_com:
+ inc bl ; first time bl = 0
+ xor ax, ax
+ xchg ax, [di.BIS_Mode]
+ lea di, [si+SIZE ComDEB]
+ mov [di.BIS_Mode], ax
+ call CommInt
+ and al, 80h
+ or bl, al
+
+ mov si, [si.NextDEB]
+ or si, si
+ jnz ch_next_com
+
+ test bl, 7Fh ;Q: more than 1 com port?
+ jnz short ch_shared ; Y: check if handled
+ or bl, bl ;Q: int handled by port?
+ stc
+ jns ch_exit ; N:
+
+ch_eoi:
+ xor ax, ax
+.errnz BIH_API_EOI
+ xor bx, bx
+ xchg bx, es:[di.BIS_Mode]
+ call es:[bx][di.BIS_User_Mode_API]
+ lea si, [di-SIZE ComDEB] ; ds:si -> ComDEB
+ mov si, [si.IRQhook]
+ mov al, [si.OldMask]
+ shr al, 1 ; shift bit 0 into Carry (0, if unmasked
+ cmc ; -1, if originally masked)
+
+ch_exit:
+ pop bx
+ pop ax
+ pop si
+ pop ds
+ ret
+
+ch_shared:
+ inc bh ; count loop
+ or bl, bl ;Q: int handled by any port?
+ js ch_chk_all ; Y: check all ports again
+ or bh, bh ;Q: first time thru loop?
+ stc
+ jz ch_exit ; Y: int wasn't for a COM port, so
+ ; chain to next IRQ handler
+ jmp ch_eoi
+
+COMHandler endp
+
+
+IFDEF No_DOSX_Bimodal_Services
+
+PUBLIC Entry_From_RM
+Entry_From_RM proc far
+
+;
+; Simulate the far ret
+;
+ cld
+ lodsw
+ mov es:[di.RealMode_IP], ax
+ lodsw
+ mov es:[di.RealMode_CS], ax
+ add es:[di.RealMode_SP], 4
+
+ push es
+ push di
+.286
+;
+; Push far addr of Ret_To_IRET to cleanup stack and return to DPMI host
+;
+ push cs
+ push IntCodeOFFSET Ret_To_IRET
+;
+; Push far addr of proc to call, so we can do a far ret to it
+;
+ push es:[di.RealMode_CX] ; segment of callback
+ push es:[di.RealMode_DX] ; offset of callback
+ mov di, es:[di.RealMode_DI]
+ ret ; far ret to cx:dx
+ ; called proc will do a far ret
+Ret_To_IRET: ; <- to here
+ pop di
+ pop es
+ iret
+.8086
+
+Entry_From_RM endp
+
+PUBLIC RM_APIHandler
+RM_APIHandler proc far
+ cmp ax, BIH_API_Call_Back
+ jne APIHandler
+ call cs:[RM_CallBack]
+ ret
+RM_APIHandler endp
+
+ENDIF
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+APIHandler proc far
+
+ or ax, ax
+ jnz short api_not_EOI
+.errnz BIH_API_EOI
+ mov ax, es:[di.BIS_IRQ_Number]
+ cmp al,8 ;Q: slave IRQ?
+ mov al,EOI
+ jb short api_master ; N:
+ out 0A0h,al ; Y: EOI slave
+api_master:
+ out INTA0,al ; EOI master
+ ret
+
+api_not_EOI:
+ cmp ax, BIH_API_Call_Back
+ jae short api_callme
+ push dx
+ push cx
+ mov dx, INTA1
+ mov cx, es:[di.BIS_IRQ_Number]
+ cmp cl, 8 ;Q: 2nd PIC?
+ jb @f ; N:
+ mov dx, 0A1h ; Y: dx = mask port
+ sub cl, 8
+@@:
+ cmp al, BIH_API_Get_Mask ;Q: get IRQ mask?
+ jae api_get_mask ; Y:
+ mov ah, al
+ mov ch, 1
+ shl ch, cl ; ch = mask byte
+ pushf
+ call DOCLI
+ in al, dx ; get current PIC mask state
+ cmp ah, BIH_API_Mask ;Q: mask IRQ?
+ jne @f ; N:
+ or al, ch ; Y: set IRQ's bit
+ jmp short api_mask_exit
+@@:
+ not ch ; N: clear IRQ's bit to unmask
+ and al, ch
+api_mask_exit:
+ out dx, al
+ pop ax
+ test ah, 2 ;Q: ints were enabled?
+ jz @f ; N:
+ call DOSTI
+@@:
+ pop cx
+ pop dx
+ ret
+
+api_get_mask:
+ in al, dx ; get current PIC mask state
+ inc cl
+ shr al, cl ; move IRQ's bit into carry
+ ; Carry set, if IRQ masked
+ pop cx
+ pop dx
+ ret
+
+api_callme:
+ push cx
+ push dx
+ ret ; far ret to call back, which will
+ ; do a far ret to our caller
+APIHandler endp
+
+
+;--------------------------Fake a Hardware Interrupt----------------------;
+; FakeCOMInt
+;
+; This routine fakes a hardware interrupt to IRQ3 or IRQ4
+; to clear out characters pending in the buffer
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+;
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History: glenn steffler 5/17/89
+;-----------------------------------------------------------------------;
+
+FakeCOMInt proc near
+
+ ; call DOCLI ;Done by caller
+;
+; WARNING: jumping into the middle of CommInt, so the stack must be set
+; properly.
+;
+ push dx
+ push bx
+ push cx
+ push di
+ push es
+ push EvtWord[si]
+ mov dx,Port[si] ;Get device I/O address
+ add dl, ACE_IIDR
+ push dx
+ jmp FakeXmitEmpty ;Process the fake interrupt, DS:SI is
+ ; already pointing to proper DEB
+;
+; FakeXmitEmpty falls in XmitEmpty which jumps back into CommInt. When CommInt
+; determines that no interrupt is pending, then it will near return back to
+; FakeCOMIntFar which can far ret back to its caller.
+;
+FakeCOMInt endp
+
+public FakeCOMIntFar
+FakeCOMIntFar proc far
+
+ call FakeCOMInt
+ ret
+
+FakeCOMIntFar endp
+
+;--------------------------Interrupt Handler----------------------------
+;
+; CommInt - Interrupt handler for com ports
+;
+; Interrupt handlers for PC com ports. This is the communications
+; interrupt service routine for RS232 communications. When an RS232
+; event occurs the interrupt vectors here. This routine determines
+; who the caller was and services the appropriate interrupt. The
+; interrupts are prioritized in the following order:
+;
+; 1. line status interrupt
+; 2. read data available interrupt
+; 3. transmit buffer empty interrupt
+; 4. modem service interrupt
+;
+; This routine continues to service until all interrupts have been
+; satisfied.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; AL = 0, if not handled, -1, if handled
+;
+;-----------------------------------------------------------------------
+
+assumes ds,Data
+assumes es,nothing
+
+; Dispatch table for interrupt types
+
+SrvTab label word
+ dw OFFSET ModemStatus ;[0] Modem Status Interrupt
+ dw OFFSET XmitEmpty ;[2] Tx Holding Reg. Interrupt
+ dw OFFSET DataAvail ;[4] Rx Data Available Interrupt
+ ; or [C] if 16550 & 16550A
+ dw OFFSET LineStat ;[6] Reciever Line Status Interrupt
+
+
+ public CommInt
+
+CommInt proc near
+
+ xor al, al
+ cmp word ptr [VCD_int_callback+4], 0
+ je short @F ; jump if no callback (not 3.1 VCD)
+ test [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
+ jnz IntLoop40 ; N: ignore the int
+.386
+ push esi
+ mov esi, [si.VCD_data]
+ call [VCD_int_callback]
+ pop esi
+.8086
+@@:
+
+ push dx
+ mov dx,Port[si] ;Get comm I/O port
+ add dl,ACE_IIDR ;--> Interrupt ID Register
+ in al, dx
+ test al, 1 ;Q: interrupt pending?
+ jnz short IntLoop30 ; N:
+
+ push bx
+ push cx
+ push di
+ push es
+ mov cx, EvtWord[si]
+ push cx
+ jmp short IntLoop10
+
+InterruptLoop_ChkTx:
+ cmp QOutCount[si],0 ;Output queue empty?
+ je short InterruptLoop ; Y: don't chk tx
+ pop dx
+ push dx
+ dec dx ; to IER
+.errnz ACE_IIDR - ACE_IER - 1
+ in al, dx
+ and al,NOT ACE_ETBEI ; disable it
+ iodelay
+ out dx, al
+ or al, ACE_ETBEI ; enable it again
+ iodelay
+ out dx, al
+ iodelay
+ out dx, al
+
+InterruptLoop:
+ pop dx ;Get ID reg I/O address
+
+ in al,dx ;Get Interrupt Id
+ test al,1 ;Interrupt need servicing?
+ jnz IntLoop20 ;No, all done
+
+IntLoop10:
+ and ax, 07h
+ mov di,ax
+ push dx ;Save Id register
+ jmp SrvTab[di] ;Service the Interrupt
+
+IntLoop20:
+ mov ax,EvtMask[si] ;Mask the event word to only the
+ and ax, EvtWord[si] ; user specified bits
+ mov EvtWord[si], ax
+ pop bx
+ test [si.NotifyFlagsHI], CN_Notify
+ jz short ci_exit
+ not bx
+ and ax, bx ; bits set in ax are new events
+ jnz short ci_new_events
+
+ci_exit:
+ pop es
+ assumes es,nothing
+
+ pop di
+ pop cx
+ pop bx
+ xor al, al
+
+IntLoop30:
+ pop dx
+ and al, 1
+ dec al ; 0->-1, 1->0
+IntLoop40:
+ ret
+
+ci_new_events:
+ mov ax, CN_EVENT
+ call notify_owner
+ jmp ci_exit
+
+CommInt endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; LineStat - Line Status Interrupt Handler
+;
+; Break detection is handled and set in the event word if
+; enabled. Other errors (overrun, parity, framing) are
+; saved for the data available interrupt.
+;
+; This routine used to fall into DataAvail for the bulk of its processing.
+; This is no longer the case... A very popular internal modem seems to
+; operate differently than a real 8250 when parity errors occur. Falling
+; into the DataAvail handler on a parity error caused the same character
+; to be received twice. Having this routine save the LSR status, and
+; return to InterruptLoop fixes the problem, and still works on real COMM
+; ports. The extra overhead isn't a big deal since this routine is only
+; entered when there is an exception like a parity error.
+;
+; This routine is jumped to, and will perform a jump back into
+; the dispatch loop.
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+; assumes ds,Data
+assumes es,nothing
+
+public LineStat ;Public for debugging
+LineStat proc near
+
+ or by EvtWord[si],EV_Err ;Show line status error
+
+ add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
+ in al,dx
+ test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
+ jz @f
+
+ mov LSRShadow[si],al ;yes, save status for DataAvail
+@@:
+ test al,ACE_BI ;Break detect?
+ jz InterruptLoop_ChkTx ;Not break detect interrupt
+
+ or by EvtWord[si],EV_Break ;Show break
+
+ jmp short InterruptLoop_ChkTx
+
+LineStat endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; DataAvail - Data Available Interrupt Handler
+;
+; The available character is read and stored in the input queue.
+; If the queue has reached the point that a handshake is needed,
+; one is issued (if enabled). EOF detection, Line Status errors,
+; and lots of other stuff is checked.
+;
+; This routine is jumped to, and will perform a jump back into
+; the dispatch loop.
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+; assumes ds,Data
+assumes es,nothing
+
+public DataAvail ;public for debugging
+DataAvail proc near
+
+ sub dl,ACE_IIDR-ACE_RBR ;--> receiver buffer register
+ in al,dx ;Read received character
+
+ and [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
+
+ mov ah,LSRShadow[si] ;what did the last Line Status intrpt
+ mov bh,ah ; have to say?
+ or ah,ah
+ jz @f
+
+ and ah,ErrorMask[si] ;there was an error, record it
+ or by ComErr[si],ah
+ mov LSRShadow[si],0
+ .errnz ACE_OR-CE_OVERRUN ;Must be the same bits
+ .errnz ACE_PE-CE_RXPARITY
+ .errnz ACE_FE-CE_FRAME
+ .errnz ACE_BI-CE_BREAK
+@@:
+
+; Regardless of the character received, flag the event in case
+; the user wants to see it.
+
+ or by EvtWord[si],EV_RxChar ;Show a character received
+ .errnz HIGH EV_RxChar
+
+; Check the input queue, and see if there is room for another
+; character. If not, or if the end of file character has already
+; been received, then go declare overflow.
+
+DataAvail00:
+
+ mov cx,QInCount[si] ;Get queue count (used later too)
+ cmp cx,QInSize[si] ;Is queue full?
+ jge DataAvail20 ; Yes, comm overrun
+ test EFlags[si],fEOF ;Has end of file been received?
+ jnz DataAvail20 ; Yes - treat as overflow
+
+; Test to see if there was a parity error, and replace
+; the character with the parity character if so
+
+ test bh,ACE_PE ;Parity error
+ jz DataAvail25 ; No
+ test [si.DCB_Flags2],fPErrChar ;Parity error replacement character?
+ jz DataAvail25 ; No
+ mov al,[si.DCB_PEChar] ; Yes, get parity replacement char
+
+; Skip all other processing except event checking and the queing
+; of the parity error replacement character
+
+ jmp short DataAvail80 ;Skip all but event check, queing
+
+DataAvail20:
+ or by ComErr[si],CE_RXOVER ;Show queue overrun
+ jmp short DataAvail50
+
+; See if we need to strip null characters, and skip
+; queueing if this is one. Also remove any parity bits.
+
+DataAvail25:
+ and al,RxMask[si] ;Remove any parity bits
+ jnz DataAvail30 ;Not a Null character
+ test [si.DCB_Flags2],fNullStrip ;Are we stripping received nulls?
+ jnz DataAvail50 ; Yes, put char in the bit bucket
+
+; Check to see if we need to check for EOF characters, and if so
+; see if this character is it.
+
+DataAvail30:
+ test [si.DCB_Flags],fBinary ;Is this binary stuff?
+ jnz DataAvail60 ; Yes, skip EOF check
+ cmp al,[si.DCB_EOFChar] ;Is this the EOF character?
+ jnz DataAvail60 ; No, see about queing the charcter
+ or EFlags[si],fEOF ;Set end of file flag
+DataAvail50:
+ jmp DataAvail140 ;Skip the queing process
+
+; If output XOn/XOff is enabled, see if the character just received
+; is either an XOn or XOff character. If it is, then set or
+; clear the XOffReceived flag as appropriate.
+
+DataAvail60:
+ test [si.DCB_Flags2],fOutX ;Output handshaking?
+ jz DataAvail80 ; No
+ cmp al,[si.DCB_XoffChar] ;Is this an X-Off character?
+ jnz DataAvail70 ; No, see about XOn or Ack
+ or HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz DataAvail50 ; No
+ cmp cx,[si.DCB_XonLim] ;See if at XOn limit
+ ja DataAvail50 ; No
+ and HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
+ and HSFlag[si], NOT XOnPending+XOffSent
+ mov al, [si.DCB_XonChar]
+ call OutHandshakingChar
+ jmp DataAvail50 ;Done
+
+DataAvail70:
+ cmp al,[si.DCB_XonChar] ;Is this an XOn character?
+ jnz DataAvail80 ; No, just a normal character
+ and HSFlag[si],NOT XOffReceived
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz DataAvail75 ; No - jump to FakeXmitEmpty to get
+ ; transmitting going again
+ and HSFlag[si],NOT EnqSent
+
+DataAvail75:
+ jmp FakeXmitEmpty ;Restart transmit
+
+; Now see if this is a character for which we need to set an event as
+; having occured. If it is, then set the appropriate event flag
+
+
+DataAvail80:
+ cmp al,[si.DCB_EVTChar] ;Is it the event generating character?
+ jne DataAvail90 ; No
+ or by EvtWord[si],EV_RxFlag ;Show received specific character
+
+; Finally, a valid character that we want to keep, and we have
+; room in the queue. Place the character in the queue.
+; If the discard flag is set, then discard the character
+
+DataAvail90:
+ test MiscFlags[si], Discard ;Discarding characters ?
+ jnz DataAvail50 ; Yes
+
+ lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
+ mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
+ les di,QInAddr[si][bx] ;Get queue base pointer from either
+ assumes es,nothing ; QInAddr or AltQInAddr
+
+ mov bx,QInPut[si] ;Get index into queue
+ mov es:[bx][di],al ;Store the character
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc DataAvail100 ;Not time to wrap
+ xor bx,bx ;Wrap-around is a new zero pointer
+
+DataAvail100:
+ mov QInPut[si],bx ;Store updated pointer
+ inc cx ;And update queue population
+ mov QInCount[si],cx
+
+; If flow control has been enabled, see if we are within the
+; limit that requires us to halt the host's transmissions
+
+ cmp cx,XOffPoint[si] ;Time to see about XOff?
+ jc DataAvail120 ; Not yet
+ test HSFlag[si],HSSent ;Handshake already sent?
+ jnz DataAvail120 ; Yes, don't send it again
+
+ mov ah,HHSLines[si] ;Should hardware lines be dropped?
+ or ah,ah ; (i.e. do we have HW HS enabled?)
+ jz DataAvail110 ; No
+ add dl,ACE_MCR ; Yes
+ in al,dx ;Clear the necessary bits
+ not ah
+ and al,ah
+ or HSFlag[si],HHSDropped ;Show lines have been dropped
+ out dx,al ; and drop the lines
+ sub dl,ACE_MCR
+
+DataAvail110:
+ test [si.DCB_Flags2],fInX ;Input Xon/XOff handshaking
+ jz DataAvail120 ; No
+ or HSFlag[si], XOffSent
+ mov al, [si.DCB_XoffChar]
+ call OutHandshakingChar
+
+DataAvail120:
+ cmp cx, [si.RecvTrigger] ;Q: time to call owner's callback?
+ jb short DataAvail130 ; N:
+
+ test [si.NotifyFlagsHI], CN_RECEIVE
+ jnz short DataAvail140 ; jump if notify already sent and
+ ; data in buffer hasn't dropped
+ ; below threshold
+ mov ax, IntCodeOFFSET DataAvail140
+ push ax
+ mov ax, CN_RECEIVE
+%OUT probably should just set a flag and notify after EOI
+ jmp notify_owner
+
+DataAvail130:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE
+
+DataAvail140:
+ pop dx
+ push dx
+ add dl, ACE_LSR-ACE_IIDR
+ in al, dx
+ test al, ACE_DR ;Q: more data available?
+ jz @F ; N:
+ sub dl, ACE_LSR ; Y: go read it
+ in al, dx ;Read available character
+ jmp DataAvail00
+@@:
+ jmp InterruptLoop_ChkTx
+
+DataAvail endp
+
+
+OutHandshakingChar proc near
+
+ add dl, ACE_LSR
+ mov ah, al
+@@:
+ in al, dx
+ test al, ACE_THRE
+ jz @B
+ sub dl, ACE_LSR
+ mov al, ah
+ out dx, al
+ ret
+
+OutHandshakingChar endp
+
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; XmitEmpty - Transmitter Register Empty
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+; assumes ds,Data
+assumes es,nothing
+
+public FakeXmitEmpty
+FakeXmitEmpty:
+ pop dx
+ push dx
+
+; "Kick" the transmitter interrupt routine into operation.
+
+ dec dl
+.errnz ACE_IIDR - ACE_IER-1
+ in al,dx ;Get current IER state
+ test al,ACE_ETBEI ;Interrupt already enabled?
+ jnz @F ; Yes, don't reenable it
+ or al,ACE_ETBEI ; No, enable it
+ out dx,al
+ iodelay ;8250, 8250-B bug requires
+ out dx,al ; writting register twice
+@@:
+ add dl,ACE_LSR-ACE_IER ;--> Line Status Register
+ iodelay
+ in al,dx ;Is xmit really empty?
+ sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
+ test al,ACE_THRE
+ jnz short XmitEmpty5 ; Y: send next char
+ jmp InterruptLoop ; N: return to processing loop
+
+public XmitEmpty
+XmitEmpty proc near
+
+ add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
+ in al,dx ;Is xmit really empty?
+ sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
+ test al,ACE_THRE
+ jz Xmit_jumpto90 ;Transmitter not empty, cannot send
+
+; If the hardware handshake lines are down, then XOff/XOn cannot
+; be sent. If they are up and XOff/XOn has been received, still
+; allow us to transmit an XOff/XOn character. It will make
+; a dead lock situation less possible (even though there are
+; some which could happen that cannot be handled).
+
+XmitEmpty5:
+ mov ah,HSFlag[si] ;Get handshaking flag
+ test ah,HHSDown+BreakSet ;Hardware lines down or break set?
+ jnz Xmit_jumpto100 ; Yes, cannot transmit
+
+; Give priority to any handshake character waiting to be
+; sent. If there are none, then check to see if there is
+; an "immediate" character to be sent. If not, try the queue.
+
+XmitEmpty10:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jnz XmitEmpty40 ; Yes
+
+XmitEmpty15:
+ test ah,HSPending ;XOff or XOn pending
+ jz XmitEmpty40 ; No
+
+XmitEmpty20:
+ and ah,NOT XOnPending+XOffSent
+ mov al,[si.DCB_XonChar] ;Get XOn character
+
+XmitEmpty30:
+ mov HSFlag[si],ah ;Save updated handshake flag
+ jmp XmitEmpty110 ;Go output the character
+
+Xmit_jumpto90:
+ jmp XmitEmpty90
+
+; If any of the lines which were specified for a timeout are low, then
+; don't send any characters. Note that by putting the check here,
+; XOff and Xon can still be sent even though the lines might be low.
+
+; Also test to see if a software handshake was received. If so,
+; then transmission cannot continue. By delaying the software check
+; to here, XOn/XOff can still be issued even though the host told
+; us to stop transmission.
+
+XmitEmpty40:
+ test ah,CannotXmit ;Anything preventing transmission?
+ jz XmitEmpty45 ; No
+Xmit_jumpto100:
+ jmp XmitEmpty100 ; Yes, disarm and exit
+
+; If a character has been placed in the single character "transmit
+; immediately" buffer, clear that flag and pick up that character
+; without affecting the transmitt queue.
+
+XmitEmpty45:
+ test EFlags[si],fTxImmed ;Character to xmit immediately?
+ jz XmitEmpty515 ; No, try the queue
+ and EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
+ mov al,ImmedChar[si] ;Get char to xmit
+ jmp XmitEmpty110 ;Transmit the character
+
+XmitEmpty515:
+ mov cx,QOutCount[si] ;Output queue empty?
+ jcxz Xmit_jumpto90 ; Yes, go set an event
+
+ test [si.DCB_Flags],fEtxAck ;Etx Ack?
+ jz XmitEmpty55 ; No
+ mov cx,QOutMod[si] ;Get number bytes sent since last ETX
+ cmp cx,[si.DCB_XonLim] ;At Etx limit yet?
+ jne XmitEmpty51 ; No, inc counter
+ mov QOutMod[si],0 ; Yes, zero counter
+ or HSFlag[si],EtxSent ;Show ETX sent
+ jmp short XE_sendXOFF
+
+XmitEmpty51:
+ inc cx ; Update counter
+ mov QOutMod[si],cx ; Save counter
+ jmp short XmitEmpty59 ; Send queue character
+
+XmitEmpty55:
+ test [si.DCB_Flags],fEnqAck ;Enq Ack?
+ jz XmitEmpty59 ; No, send queue character
+ mov cx,QOutMod[si] ;Get number bytes sent since last ENQ
+ or cx,cx ;At the front again?
+ jnz XmitEmpty56 ; No, inc counter
+ mov QOutMod[si],1 ; Yes, send ENQ
+ or HSFlag[si],EnqSent ;Show ENQ sent
+XE_sendXOFF:
+ mov al,[si.DCB_XoffChar]
+ jmp short XmitEmpty110 ;Go output the character
+
+XmitEmpty56:
+ inc cx ;Update counter
+ cmp cx,[si.DCB_XonLim] ;At end of our out buffer len?
+ jne XmitEmpty58 ; No
+ xor cx,cx ;Show at front again.
+
+XmitEmpty58:
+ mov QOutMod[si],cx ;Save counter
+
+XmitEmpty59:
+ lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
+ mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
+ les di,QOutAddr[si][bx] ;Get queue base pointer from either
+ assumes es,nothing ; QOutAddr or AltQOutAddr
+
+ mov bx,QOutGet[si] ;Get pointer into queue
+ mov al,es:[bx][di] ;Get the character
+
+ inc bx ;Update queue pointer
+ cmp bx,QOutSize[si] ;See if time for wrap-around
+ jc XmitEmpty60 ;Not time for wrap
+ xor bx,bx ;Wrap by zeroing the index
+
+XmitEmpty60:
+ mov QOutGet[si],bx ;Save queue index
+ mov cx,QOutCount[si] ;Output queue empty?
+ dec cx ;Dec # of bytes in queue
+ mov QOutCount[si],cx ; and save new population
+
+ out dx,al ;Send char
+
+ cmp cx, [si.SendTrigger] ;Q: time to call owner's callback?
+ jae short XmitEmpty70 ; N:
+
+ test [si.NotifyFlagsHI], CN_TRANSMIT
+ jnz short XmitEmpty80 ; jump if notify already sent and
+ ; data in buffer hasn't raised
+ ; above threshold
+ mov ax, IntCodeOFFSET XmitEmpty80
+ push ax
+ mov ax, CN_TRANSMIT
+ jmp short notify_owner
+
+XmitEmpty70:
+ and [si.NotifyFlagsHI], NOT CN_TRANSMIT
+
+XmitEmpty80:
+%OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
+ jmp InterruptLoop
+
+
+; No more characters to transmit. Flag this as an event.
+
+XmitEmpty90:
+ or by EvtWord[si],EV_TxEmpty
+
+; Cannot continue transmitting (for any of a number of reasons).
+; Disable the transmit interrupt. When it's time resume, the
+; transmit interrupt will be reenabled, which will generate an
+; interrupt.
+
+XmitEmpty100:
+ inc dx ;--> Interrupt Enable Register
+ .errnz ACE_IER-ACE_THR-1
+ in al,dx ;I don't know why it has to be read
+ and al,NOT ACE_ETBEI ; first, but it works this way
+XmitEmpty110:
+ out dx,al
+ jmp InterruptLoop
+
+XmitEmpty endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ModemStatus - Modem Status Interrupt Handler
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+; assumes ds,Data
+assumes es,nothing
+
+public ModemStatus ;Public for debugging
+ModemStatus proc near
+
+; Get the modem status value and shadow it for MSRWait.
+
+ add dl,ACE_MSR-ACE_IIDR ;--> Modem Status Register
+ in al,dx
+ mov MSRShadow[si],al ;Save MSR data for others
+ mov ch,al ;Save a local copy
+
+; Create the event mask for the delta signals
+
+ mov ah,al ;Just a lot of shifting
+ shr ax,1
+ shr ax,1
+ shr ah,1
+ mov cl,3
+ shr ax,cl
+ and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
+ or EvtWord[si],ax
+
+ mov ah,ch ;[rkh]...
+ shr ah,1
+ shr ah,1
+ and ax,EV_CTSS+EV_DSRS
+ or EvtWord[si],ax
+
+ mov ah,ch
+ mov cl,3
+ shr ah,cl
+ and ax,EV_RLSD
+ or EvtWord[si],ax
+
+ mov ah,ch
+ mov cl,3
+ shl ah,cl
+ and ax,EV_RingTe
+ or EvtWord[si],ax
+
+ .errnz EV_CTS-0000000000001000b
+ .errnz EV_DSR-0000000000010000b
+ .errnz EV_RLSD-0000000000100000b
+ .errnz EV_Ring-0000000100000000b
+
+ .errnz EV_CTSS-0000010000000000b ;[rkh]
+ .errnz EV_DSRS-0000100000000000b
+ .errnz EV_RLSDS-0001000000000000b
+ .errnz EV_RingTe-0010000000000000b
+
+ .errnz ACE_DCTS-00000001b
+ .errnz ACE_DDSR-00000010b
+ .errnz ACE_DRLSD-00001000b
+ .errnz ACE_RI-01000000b
+
+ .errnz ACE_TERI-00000100b ;[rkh]
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz ACE_RLSD-10000000b
+
+ModemStatus10:
+ mov al,OutHHSLines[si] ;Get output hardware handshake lines
+ or al,al ;Any lines that must be set?
+ jz ModemStatus40 ;No hardware handshake on output
+ and ch,al ;Mask bits of interest
+ cmp ch,al ;Lines set for Xmit?
+ je ModemStatus20 ; Yes
+ or HSFlag[si],HHSDown ;Show hardware lines have dropped
+ModemStatus30:
+ jmp InterruptLoop
+
+ModemStatus40:
+ jmp InterruptLoop_ChkTx
+
+; Lines are set for xmit. Kick an xmit interrupt if needed
+
+ModemStatus20:
+ and HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
+ ;Show hardware lines back up
+ mov cx,QOutCount[si] ;Output queue empty?
+ jcxz ModemStatus30 ; Yes, return to InterruptLoop
+ jmp FakeXmitEmpty ;Restart transmit
+
+ModemStatus endp
+
+page
+
+;------------------------------------------------------------------------------
+;
+; ENTER: AX = message #
+; DS:SI -> DEB
+notify_owner proc near
+
+ or [si.NotifyFlags], ax
+ lea di, [si+SIZE ComDEB]
+ mov ax, ds
+ mov es, ax
+ mov ax, BIH_API_Call_Back ; call immediate, or in protected mode
+ mov bx, 1 ; force SYS VM, if enhanced mode
+ mov cx, _INTERRUPT
+ mov dx, IntCodeOFFSET callback_event
+%OUT use equate
+ push ds
+ push si
+ mov si, 1 ; low priority boost
+ push bp
+ mov bp, es:[di.BIS_Mode]
+ call es:[bp][di.BIS_User_Mode_API]
+ pop bp
+ pop si
+ pop ds
+ ret
+
+notify_owner endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+callback_event proc far
+ lea si, [di-SIZE ComDEB]
+ mov ax, es
+ mov ds, ax
+ mov ax, [si.NotifyHandle]
+ push ax ; push hWnd
+ mov ax, WM_COMMNOTIFY
+ push ax ; push wMsg
+ xor ax, ax
+ mov al, [si.DCB_Id]
+ push ax ; push wParam = ComID
+ xor al, al
+ push ax ; push high word of lParam
+ xchg al, [si.NotifyFlagsLO]
+ or [si.NotifyFlagsHI], al
+ push ax ; push low word of lParam = event flags
+ call [lpPostMessage]
+ ret
+callback_event endp
+
+
+PUBLIC TimerProc
+TimerProc proc far
+
+ push ds
+ mov ax, _DATA
+ mov ds, ax
+ assumes ds,data
+
+ mov ax, [activeCOMs]
+ or ax, ax
+ jz short tp_nonactive
+ push si
+ mov si, DataOFFSET COMptrs
+ mov cx, MAXCOM+1
+tp_lp:
+ push si
+ mov si, [si] ; si -> ComDEB
+ shr ax, 1
+ jnc tp_lpend
+
+ cmp [si.RecvTrigger], -1 ;Q: owner wants notification?
+ je short tp_lpend ; N: skip notify
+ cmp [si.QInCount], 0 ;Q: anything in input queue?
+ je short tp_lpend ; N: skip notify
+ test [si.NotifyFlagsHI], CN_RECEIVE ;Q: timeout notify already given?
+ jnz short tp_lpend ; N: skip notify
+
+ xor [si.NotifyFlagsHI], CN_Idle ;Q: first timer call?
+ js short tp_lpend ; Y: skip notify
+
+ push ax
+ push cx
+ mov ax, CN_RECEIVE ; N: notify owner
+ call notify_owner
+ pop cx
+ pop ax
+
+tp_lpend:
+ pop si
+ inc si ; inc to ptr to next ComDEB
+ inc si
+ or ax, ax
+ loopnz tp_lp
+ pop si
+
+tp_nonactive:
+ pop ds
+ assumes ds,nothing
+ ret
+
+TimerProc endp
+page
+
+ifdef DEBUG
+ public Control, DEF_Handler, COMHandler, APIHandler
+ public InterruptLoop, IntLoop10, IntLoop20
+ public DataAvail25, DataAvail30, DataAvail50
+ public DataAvail60, DataAvail70, DataAvail80, DataAvail90
+ public DataAvail100, DataAvail110, DataAvail120
+ public DataAvail130, DataAvail140, OutHandshakingChar
+ public XmitEmpty10, XmitEmpty20, XmitEmpty30, XmitEmpty40
+ public XmitEmpty59, XmitEmpty60
+ public XmitEmpty90, XmitEmpty100, XmitEmpty110
+ public ModemStatus10, ModemStatus20, ModemStatus30
+ public notify_owner, callback_event
+endif
+
+DOSTI proc near
+ FSTI
+ ret
+DOSTI endp
+
+DOCLI proc near
+ FCLI
+ ret
+DOCLI endp
+
+
+
+sEnd IntCode
+end
diff --git a/private/mvdm/wow16/drivers/comm/ibmlpt.asm b/private/mvdm/wow16/drivers/comm/ibmlpt.asm
new file mode 100644
index 000000000..c47e101cc
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmlpt.asm
@@ -0,0 +1,412 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMLPT.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+title IBMLpt - IBM PC, PC-XT, PC-AT, PS/2 Parallel Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+.list
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+externFP GetSystemMsecCount
+
+externA __0040H
+
+;----------------------------Private-Routine----------------------------;
+;
+; DoLPT - Do Function To LPT port
+;
+; The given function (output or reset) is performed to the
+; passed LPT port.
+;
+; Before a character is sent, a check is made to see if the device
+; will be able to accept the character. If it can, then the character
+; will be sent. If not, then an error will be returned. If the
+; printer is selected and busy and no error, then the code returned
+; will be CE_TXFULL and the handshake bits will be set in HSFlag
+; to simulate that a handshake was received.
+;
+; If the BIOS ROM code is examined, you will note that they wait for
+; the busy character from the last charcater to be cleared before
+; they strobe in the current character. This can take a long time
+; on the standard EPSON class printer (1 mSec to greater than
+; 300 mSec if the last character actually caused printing).
+;
+; Because of this, several status read retrys will be made before
+; declaring that the device is actually busy. If only one status
+; read is performed, the spooler will yeild, take a while to get
+; back here, and things will be really slow. What difference does
+; it really make if we or the BIOS does the delay, at least we can
+; break out of it at some point when it seems hopeless.
+;
+; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
+; out signal on the trailing edge of the Busy signal. If we see this
+; glitch then we report paper out. So we try to get the status twice...
+; if it changes between the two tries we keep getting the status.
+; Silly hardware people.
+;
+; Entry:
+; AH = cid
+; AL = character to output
+; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
+; DS:SI -> DEB for the port
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public DoLPT
+DoLPT proc near
+
+ mov dx,Port[si] ;Get port address
+
+; DX = port address
+; CH = operation: 0 = write, 1 = init, 2 = status
+; AL = character
+
+ or ch, ch
+ jz LPT_OutChar
+ cmp ch, 1
+ jz LPT_Reset
+ jmp LPT_GetStatus
+ ret
+
+LPT_Reset:
+
+ inc dx
+ inc dx
+ mov al, L_RESET
+ iodelay
+ out dx, al
+
+ push dx
+
+ cCall GetSystemMsecCount
+ mov bx, ax
+
+LPT_ResetDelay:
+ push bx
+ cCall GetSystemMsecCount
+ pop bx
+ sub ax, bx
+ cmp ax, 300 ; 1/3 sec as good as any
+ jbe LPT_ResetDelay
+
+ pop dx
+
+ mov al, L_NORMAL
+ iodelay
+ iodelay
+ out dx, al
+ dec dx
+ dec dx
+ jmp LPT_GetStatus
+
+LPT_OutChar:
+ push ax ; save character to be written
+
+ ; first check to see if printer is ready for us
+ push di
+
+ push dx
+ call GetSystemMSecCount
+ mov di, ax
+ pop dx
+
+LPT_WaitReady:
+
+ inc dx ; point to status port
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ dec dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz LPT_WaitReady
+else
+ dec dx
+endif
+
+
+ test ah, PS_PaperOut or PS_IOError
+ jnz LPT_PrinterNotReady
+ test ah, PS_Select
+ jz LPT_PrinterNotReady
+ test ah, PS_NotBusy
+ jnz LPT_PrinterReady
+
+ push ax
+ push dx
+ call GetSystemMSecCount
+ pop dx
+ pop bx
+ sub ax, di
+ cmp ax, 300 ; 1/3 sec timeout
+
+ jbe LPT_WaitReady
+
+; The device seems to be selected and powered up, but is just
+; busy (some printers seem to show selected but busy when they
+; are taken offline). Show that the transmit queue is full and
+; that the hold handshakes are set. This is so the windows
+; spooler will retry (and do yields so that other apps may run).
+
+
+ or ComErr[si],CE_TXFULL ;Show queue full
+ mov ah,bh
+ or ah, L_TIMEOUT
+
+LPT_PrinterNotReady:
+
+ pop di
+ pop cx ; throw away character
+ jmp short LPT_ReturnStatus
+
+LPT_PrinterReady:
+ pop di ; get di back
+ pop ax ; get character back
+
+ iodelay
+ out dx, al ; write character to port
+
+ inc dx ; access status port
+
+LPT_Strobe:
+ inc dx ; control port
+ mov al, L_STROBE ; set strobe high
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ sub dx, 2 ; point back to port base
+
+ ; FALL THRU
+
+LPT_GetStatus:
+ inc dx ; point to status port
+LPT_GS1:
+ iodelay
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ mov ah, al
+
+ifndef NOOKIHACK
+ in al, dx
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah
+ jnz LPT_GS1 ; if they changed try again...
+endif
+
+LPT_ReturnStatus:
+
+ assumes ds,Data
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+ ret
+
+ .errnz CE_PTO-0200h
+ .errnz CE_IOE-0400h
+ .errnz CE_DNS-0800h
+ .errnz CE_OOP-1000h
+
+DoLPT40:
+ assumes ds,Data
+ or ComErr[si],CE_TXFULL ;Show queue full
+ ret
+
+DoLPT endp
+page
+
+
+CheckStatus proc near
+ in al, dx ; get status bits
+ mov ah, al
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz CheckStatus
+endif
+ test ah, PS_PaperOut or PS_IOError
+ jz @F
+ stc
+ ret
+@@:
+ test ah, PS_Select
+ jnz @F
+ stc
+ ret
+@@:
+ and ah, PS_NotBusy
+ clc
+ ret
+
+CheckStatus endp
+
+
+;----------------------------Public Routine-----------------------------;
+;
+; StringToLPT - Send string To LPT Port
+;
+; Entry:
+; DS:SI -> DEB
+; ES:DI -> string to send
+; CX = # of bytes to send
+; Returns:
+; AX = # of bytes actually sent
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+PUBLIC StringToLPT
+StringToLPT proc near
+
+ mov dx, Port[si] ; get port address
+ inc dx ; access status port
+
+ push cx ; save count for later
+ push ds
+ mov bx, __0040H
+ mov ds, bx
+
+ cld
+
+ call CheckStatus ; quick status check before slowness
+ jc PrinterError
+ jz PrinterBusy ; if printer not ready for first char
+ ; then just return with CE_TXFULL
+
+CharacterToLPT:
+;; mov bh, 10 ; will wait 10 clock tics (~ 1/2 sec)
+ mov bh, 3 ; will wait 3 clock tics (~ 1/6 sec)
+l1:
+ mov bl, ds:[006Ch] ; low byte of tic counter
+l2:
+ call CheckStatus ; quick status check before slowness
+ jc PrinterError
+ jnz LPT_PrinterRdy
+
+ cmp bl, ds:[006Ch]
+ jz l2 ; tic count hasn't changed
+
+ dec bh
+ jz PrinterBusy ; out of tics, timeout
+ jmp short l1
+
+LPT_PrinterRdy:
+ mov al, es:[di]
+ inc di
+
+ dec dx ; point to data port
+
+ out dx, al ; write character to port
+
+ add dx, 2 ; access control port
+ mov al, L_STROBE ; set strobe high
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ dec dx ; point to status port for check
+
+ loop CharacterToLPT
+ pop ds
+ jmp short LPT_Exit
+
+PrinterError:
+ pop ds
+ jmp short ReturnStatus
+
+PrinterBusy:
+ pop ds
+ or ComErr[si],CE_TXFULL ; set buffer full bit
+ or al, L_TIMEOUT ; show timeout bit
+
+ReturnStatus:
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)
+ xchg al, ah
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+
+LPT_Exit:
+ pop ax ; get total count
+ sub ax, cx ; subtract remaining unsent charts
+
+ ret
+
+StringToLPT endp
+
+
+IFDEF DEBUG ;Publics for debugging
+ public LPT_Reset
+ public LPT_Outchar
+ public LPT_Strobe
+ public LPT_GetStatus
+ public DoLPT40
+ENDIF
+
+sEnd code
+End
diff --git a/private/mvdm/wow16/drivers/comm/ibmsetup.asm b/private/mvdm/wow16/drivers/comm/ibmsetup.asm
new file mode 100644
index 000000000..be430f747
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmsetup.asm
@@ -0,0 +1,2878 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMSETUP.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;
+;-----------------------------------------------------------------------;
+
+title IBMSetup - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+include BIMODINT.INC
+include vint.inc
+.list
+
+
+EBIS_Sel1 equ SIZE Bimodal_Int_Struc
+EBIS_Sel2 equ EBIS_Sel1 + (SIZE EBIS_Sel_Struc)
+
+externA __WinFlags
+
+externFP GetSystemMsecCount
+externFP CreateSystemTimer
+externFP AllocCStoDSAlias
+externFP LockSegment
+externFP UnlockSegment
+externFP FreeSelector
+externFP GetSelectorBase
+externFP GetModuleHandle
+externFP GetProcAddress
+externFP GetPrivateProfileInt
+externFP GetPrivateProfileString
+externFP GetAppCompatFlags
+externFP WowCloseComPort
+
+externNP $RECCOM
+
+externA __0040H
+externA __F000h
+
+externB IRQhooks
+
+IF 0
+externD OldIntVecIntB
+externD OldIntVecIntC
+externD OurIntVecIntB
+externD OurIntVecIntC
+ENDIF
+
+externB szMessage
+externB pLPTByte
+externB szCOMMessage
+externB pCOMByte
+externB _szTitle
+
+
+MULTIPLEX equ 2Fh ; multiplex interrupt number
+GET386API equ 1684h ; Get API entry point from VxD
+VPD equ 000Fh ; device ID of VPD device
+VPD_GETPORT equ 0004h ; function: assign port to current VM
+VPD_RELPORT equ 0005h ; function: release port
+VCD equ 000Eh ; device ID of VCD device
+VCD_GETVER equ 0000h ; get version API
+VCD_GETPORT equ 0004h ; function: assign port to current VM
+VCD_RELPORT equ 0005h ; function: release port
+VCD_STEALPORT equ 0006h
+VPICD equ 0003h ; device ID of VPICD device
+
+POSTMESSAGE equ 110 ; export ordinal of PostMessage()
+MESSAGEBOX equ 1 ; export ordinal of MessageBox()
+MB_TASKMODAL equ 2000h
+MB_YESNO equ 0004h ; messagebox flags
+MB_ICONEXCLAMATION equ 0030h
+IDYES equ 6
+
+
+createSeg _INTERRUPT,IntCode,word,public,CODE
+sBegin IntCode
+assumes cs,IntCode
+
+ externFP FakeCOMIntFar
+ externFP TimerProc
+ externFP Control
+ externFP COMHandler
+ externFP APIHandler
+IFDEF No_DOSX_Bimodal_Services
+ externW RM_IntDataSeg
+ externFP RM_APIHandler
+ externFP Entry_From_RM
+ externD RM_CallBack
+ENDIF
+
+sEnd IntCode
+
+page
+sBegin Data
+
+externB lpCommBase
+externB CommBaseX
+externB lpCommIrq
+externB CommIrqX
+externB lpCommFifo
+externB CommFifoX
+externB lpCommDSR
+externB CommDSRx
+
+externB lpCommSection
+externB lpSYSTEMINI
+
+
+;------------------------------------------------------------------------------
+;
+; Reserve data space for COM ports
+;
+DefineCommX MACRO num
+ public Comm&num
+Comm&num label byte
+ db num-1
+.errnz DCB_Id
+ db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; ComDCB
+ dw 0 ; ComErr
+ dw 0 ; Port
+ dw 0 ; NotifyHandle
+ dw 0 ; NotifyFlags
+ dw -1 ; RecvTrigger
+ dw 0 ; SendTrigger
+.errnz IRQhook - SendTrigger - 2
+ db (SIZE ComDEB) - IRQhook DUP(0)
+.errnz $ - Comm&num - (SIZE ComDEB)
+ Declare_PM_BIS 0,Control,COMHandler,APIHandler,_INTERRUPT,_DATA
+ db (SIZE EBIS_Sel_Struc) * 2 DUP(0) ; res space for 2 selectors
+ENDM
+DW_OFFSET_CommX MACRO num
+ dw DataOFFSET Comm&num
+ENDM
+
+
+??portnum = 1
+REPT MAXCOM+1
+ DefineCommX %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PUBLIC COMptrs ; table of offsets to CommX's declared above
+COMptrs label word
+??portnum = 1
+REPT MAXCOM+1
+ DW_OFFSET_CommX %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineCommX
+PURGE DW_OFFSET_CommX
+
+;------------------------------------------------------------------------------
+;
+; Reserve data space for LPT ports
+;
+DefineLPTx MACRO num
+ public LPT&num
+LPT&num label byte
+ db num-1+LPTx
+.errnz DCB_Id
+ db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; xComDCB
+ dw 0 ; xComErr
+ dw 0 ; xPort
+ dw 0 ; xNotifyHandle
+ dw 0 ; xNotifyFlags
+ dw -1 ; xRecvTrigger
+ dw 0 ; xSendTrigger
+IF num LE 3
+ dw LPTB + (num-1)*2
+ELSE
+ dw 0 ; BIOSPortLoc
+ENDIF
+ .errnz $-LPT&num - SIZE LptDEB
+ENDM
+
+??portnum = 1
+REPT MAXLPT+1
+ DefineLPTx %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineLPTx
+
+page
+
+PUBLIC $MachineID, Using_DPMI
+$MachineID db 0 ;IBM Machine ID
+Using_DPMI db 0 ; 0FFh, if TRUE
+
+ ALIGN 2
+
+PUBLIC activeCOMs
+activeCOMs dw 0
+
+PUBLIC lpPostMessage, lpfnMessageBox, lpfnVPD, fVPD
+
+lpPostMessage dd 0
+lpfnMessageBox dd 0
+
+lpfnVPD dd 0 ; far pointer to win 386 VPD entry point
+lpfnVCD dd 0 ; far pointer to win 386 VCD entry point
+lpfnVPICD dd 0 ; far pointer to win 386 VPICD entry point
+PUBLIC VCD_int_callback
+VCD_int_callback df 0 ; VCD returns the address for this callback
+ ; on every call to acquire a COM port, but
+ ; it is always the same address, so we will
+ ; just maintain it globally.
+fVPD db 0 ; 0-not checked, 1 vpd present, -1 no vpd
+fVCD db 0 ; 0-not checked, 1 vcd present, -1 no vcd
+fVPICD db 0 ; 0-not checked, 1 vpicd present, -1 no vpicd
+
+szUser db 'USER',0
+
+
+default_table db 4, 3, 4, 3, 0 ; Default IRQ's (COM3 default is changed to
+ ; 3 for PS/2's during LoadLib)
+
+
+IFDEF No_DOSX_Bimodal_Services
+RM_Call_Struc Real_Mode_Call_Struc <>
+ENDIF
+
+IFDEF DEBUG_TimeOut
+%OUT including code to display MsgBox, if closing comm with data in buffer
+szSendTO db 'TimedOut CloseComm with data in buffer. Retry?', 0
+ENDIF
+
+
+sEnd Data
+
+ROMBios segment at 0F000h
+ org 0FFFEh
+
+MachineID label byte
+RomBios Ends
+
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+page
+
+IFDEF No_DOSX_Bimodal_Services
+;----------------------------Private-Routine----------------------------;
+; SegmentFromSelector
+;
+; Converts a selector to a segment...note that this routine assumes
+; the memory pointed to by the selector is below the 1Meg line!
+;
+; Params:
+; AX = selector to convert to segment
+;
+; Returns:
+; AX = segment of selector given
+;
+; Error Returns:
+; None
+;
+; Registers Destroyed:
+; CX
+;
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public SegmentFromSelector
+SegmentFromSelector proc far
+
+.286
+ push dx
+ cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
+ shr ax, 4
+ shl dl, 4
+ or ah, dl ;AX now points to interrupt *segment*
+ pop dx
+ ret
+.8086
+
+SegmentFromSelector endp
+ENDIF
+page
+
+;------------------------------------------------------------------------------
+;
+; Get_API_Entry
+;
+; entry - BX = device id
+; DS:DI -> DWORD for proc address
+; exit - Z flag set, if failed
+;
+Get_API_Entry proc near
+
+ push di
+ xor di, di
+ mov es, di
+ mov ax, GET386API
+ int MULTIPLEX
+ mov ax, di
+ pop di
+ mov [di], ax
+ mov [di+2], es
+ or ax, [di+2]
+ ret
+
+Get_API_Entry endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; Contention_Dlg
+;
+; If running under Win386, this routine can be called to ask the user to
+; resolve contention for a COM or LPT port.
+;
+; entry - CX is offset of message string for dialog box
+;
+; exit - Z flag set, if user specified that Windows should steal the port
+
+Contention_Dlg proc near
+PUBLIC Contention_Dlg
+
+ xor ax,ax
+ push ax ; hwndOwner
+ push ds
+ push cx ; message ptr
+
+ cmp wo lpfnMessageBox[2], 0 ;Q: ptr to MessageBox proc valid?
+ jne short gmbp_done ; Y: we can call it
+ push ds ; N: get module handle of USER
+ lea ax, szUser
+ push ax
+ cCall GetModuleHandle
+
+ push ax ; module handle
+ mov ax, MESSAGEBOX
+ cwd
+ push dx
+ push ax
+ cCall GetProcAddress
+ mov wo lpfnMessageBox[0], ax ; save received proc address
+ mov wo lpfnMessageBox[2], dx
+gmbp_done:
+
+ push ds
+ lea ax, _szTitle
+ push ax
+ mov ax, MB_ICONEXCLAMATION or MB_YESNO or MB_TASKMODAL
+ push ax
+ cCall lpfnMessageBox
+ cmp ax, IDYES ; user allows us to take the port?
+ ret
+Contention_Dlg endp
+
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetPort386
+;
+; If running under Win386, tell the VPD to assign an LPT port to us.
+; The comm driver will handle contention.
+;
+; entry - DI contains offset in ROM area of port...
+; 8 - LPT1, A - LPT2, etc
+;
+; exit - registers saved, carry = clear if OK to proceed, set if
+; user won't allow assignment of port or Win386 error
+;
+
+GetPort386 proc near
+public GetPort386
+
+ cmp fVPD, 0
+ jl getport_VPDNotInstalled
+ jnz short getport_CallVPD
+
+ push di
+ mov bx, VPD
+ mov di, DataOFFSET lpfnVPD
+ call Get_API_Entry
+ pop di
+ jnz short getport_CallVPD
+ mov fVPD, -1
+
+getport_VPDNotInstalled:
+ clc
+ jmp short getport_exit
+
+getport_CallVPD:
+ mov fVPD, 1
+ push di
+ sub di, LPTB
+ shr di, 1 ; turn DI into port number
+
+ xor ax, ax
+ mov dx, VPD_GETPORT
+ mov cx, di
+ call [lpfnVPD]
+ jnc getport_gotit
+
+; port owned by another VM... ask the user for it
+
+ add cl, '1' ; fix up the port name...
+ mov pLPTByte, cl ; HACK HACK HACK
+ lea cx, szMessage
+ call Contention_Dlg
+ jnz getport_userwontallow
+
+ mov ax, 1 ; tell win386 we really do want it
+ mov cx, di ;
+ mov dx, VPD_GETPORT ;
+ call [lpfnVPD] ; return with C set or clear...
+ jmp short getport_gotit
+
+getport_userwontallow:
+ stc
+
+getport_gotit:
+ pop di
+
+getport_exit:
+ ret
+
+GetPort386 endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; ReleasePort386
+;
+; If running under Win386, tell the VPD to deassign an LPT port.
+;
+; entry - DS:SI -> COMDEB
+;
+
+ReleasePort386 proc near
+
+ cmp fVPD, 1
+ jne release_noVPD
+
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ and cl, NOT LPTx ; clear high bit
+ mov dx, VPD_RELPORT
+ call [lpfnVPD]
+
+release_noVPD:
+ ret
+
+ReleasePort386 endp
+
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetCOMport386
+;
+; If running under Win386, tell the VCD to assign a COM port to us.
+; The comm driver will handle contention.
+;
+; entry - DS:SI -> COMDEB
+;
+; exit - registers saved, carry = clear if OK to proceed, set if
+; user won't allow assignment of port or Win386 error
+;
+.386
+GetCOMport386 proc near
+public GetCOMport386
+
+ push es
+ pushad
+ cmp fVCD, 0
+ jl short getcomport_VCDNotInstalled
+ jnz short getcomport_CallVCD
+
+ mov bx, VCD
+ mov di, DataOFFSET lpfnVCD
+ call Get_API_Entry
+ jz short getcomport_checknoVCD
+
+ mov dx, VCD_GETVER
+ call [lpfnVCD]
+ cmp ax, 30Ah ;Q: 3.1 or greater?
+ jae short getcomport_CallVCD ; Y:
+
+getcomport_checknoVCD:
+ mov fVCD, -1
+
+getcomport_VCDNotInstalled:
+ clc
+ jmp short getcomport_exit
+
+getcomport_CallVCD:
+ mov fVCD, 1
+
+ mov ax, 10b ; flag ring0 int handler
+ call VCD_GetPort_API
+ jnc short getcomport_success ; jump if acquire worked
+ jnz short getcomport_noport ; jump if port doesn't exist
+
+; port owned by another VM... ask the user for it
+
+ mov cl, [si.DCB_id]
+ add cl, '1' ; fix up the port name...
+ mov pCOMByte, cl
+ lea cx, szCOMMessage
+ call Contention_Dlg
+ stc
+ jnz short getcomport_exit
+
+ mov ax, 11b ; tell win386 we really do want it
+ call VCD_GetPort_API
+ jc short getcomport_exit
+
+getcomport_success:
+ mov dword ptr [VCD_int_callback], edi
+ mov word ptr [VCD_int_callback+4], cx
+ mov [si.VCD_data], ebx
+ xchg ax, [si.Port]
+ or ax, ax ;Q: already had port base?
+ jnz short getcomport_exit ; Y: don't update vector #, or FIFO
+ mov [si.IntVecNum], dl
+ call GetPortFlags
+ clc
+
+getcomport_exit:
+ popad
+ pop es
+ ret
+
+getcomport_noport:
+ mov [si.Port], -1
+ jmp getcomport_exit
+
+GetCOMport386 endp
+
+VCD_GetPort_API proc near
+ mov dx, VCD_GETPORT
+ xor cx, cx
+ mov cl, [si.DCB_Id] ; cx = port #
+ mov di, VCDflags ; offset from start of DEB
+ call [lpfnVCD]
+ ret
+VCD_GetPort_API endp
+.8086
+
+;----------------------------Private-Routine----------------------------;
+;
+; ReleaseCOMport386
+;
+; If running under Win386, tell the VCD to deassign a COM port.
+;
+; entry - DS:SI -> COMDEB
+;
+
+ReleaseCOMport386 proc near
+
+ifndef WOW
+ cmp fVCD, 1
+ jne release_noVCD
+
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ mov dx, VCD_RELPORT
+ call [lpfnVCD]
+else
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ push cx
+ call WowCloseComPort
+endif
+
+release_noVCD:
+ ret
+
+ReleaseCOMport386 endp
+
+PUBLIC StealPort
+StealPort proc near
+
+ cmp fVCD, 1
+ jne sp_yes
+ mov dx, VCD_STEALPORT
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ call [lpfnVCD]
+ or al, al
+ jnz sp_yes
+
+sp_no:
+ stc
+ ret
+
+sp_yes:
+ clc
+ mov [si.VCDflags], 0
+ ret
+
+StealPort endp
+
+page
+
+;------------------------------------------------------------------------------
+;
+; ENTER: DS:SI -> ComDEB
+; EXIT: AL = 0, if IRQ was unmasked, else -1, if IRQ was already masked
+;
+MaskIRQ proc near
+ push es
+ push di
+ mov di, ds
+ mov es, di
+ lea di, [si+SIZE ComDEB]
+ mov ax, BIH_API_Get_Mask
+ call APIHandler ; returns Carry Set, if masked
+ jc short already_masked
+ pushf
+ mov ax, BIH_API_Mask
+ call APIHandler ; mask IRQ
+ xor ax, ax
+ popf
+ jnc short mask_exit
+already_masked:
+ or al, -1
+mask_exit:
+ pop di
+ pop es
+ ret
+MaskIRQ endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: DS:SI -> ComDEB
+;
+UnmaskIRQ proc near
+ push es
+ push di
+ mov di, ds
+ mov es, di
+ lea di, [si+SIZE ComDEB]
+ mov ax, BIH_API_Unmask
+ call APIHandler
+ pop di
+ pop es
+ ret
+UnmaskIRQ endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $INICOM - Initialize A Port
+;
+; Initalizes the requested port if present, and sets
+; up the port with the given attributes when they are valid.
+; This routine also initializes communications buffer control
+; variables. This routine is passed the address of a device
+; control block.
+;
+; The RLSD, CTS, and DSR signals should be ignored by all COM
+; routines if the corresponding timeout values are 0.
+;
+; For the LPT ports, a check is performed to see if the hardware
+; is present (via the LPT port addresses based at 40:8h. If the
+; port is unavailable, an error is returned. If the port is
+; available, then the DEB is set up for the port. $SETCOM will
+; be called to set up the DEB so that there will be something
+; valid to pass back to the caller when he inquires the DEB.
+;
+; No hardware initialization will be performed to prevent the
+; RESET line from being asserted and resetting the printer every
+; time this routine is called.
+;
+; Entry:
+; EX:BX --> Device Control Block with all fields set.
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = initialization error code otherwise
+; Registers Preserved:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $INICOM
+$INICOM proc near
+ push si ;As usual, save register variables
+ push di
+ mov ah,es:[bx.DCB_Id] ;Get device i.d.
+ call GetDEB ;--> DEB for this device
+ mov ax, IE_BADID ; call it a bad id (spooler uses DOS)
+ jc InitCom15 ;Invalid device
+ jns InitCom20 ; jmp if COM port
+
+ push ds
+
+ mov di, [si.BIOSPortLoc]
+ cmp di, LPTB
+ jb short InitLPT_Installed
+
+ mov cx,__0040H ;[rkh] ...
+ mov ds,cx ;Point DS: at ROM Save Area.
+ assumes ds,nothing
+
+ mov ax, IE_HARDWARE
+ mov cx, wo [di]
+ jcxz InitCom10 ; if zero, no hardware
+
+ mov ax,IE_BadID ;Show bad device
+ cmp ch, 0 ; zero hibyte -> not valid (redir)
+ jz InitCom10 ; call it a bad id (spooler uses DOS)
+
+ cmp di, LPTB ; LPT1?
+ jz InitLPT_Installed ; yes, must be installed
+
+ cmp cx, wo [di-2] ;Q: duplicate of previous port
+ je InitCom10 ; Y: (redirected port)
+
+InitLPT_Installed:
+ pop ds
+ mov [si.Port], cx
+ call $SETCOM
+ call GetPort386 ; tell win386 we're using the port
+ mov ax, IE_OPEN ; port already open (by another VM)
+ jc InitCom15 ; error
+ jmp InitCom90 ;That's all
+
+InitCom10:
+ pop ds ; get DS back
+InitCom15:
+ jmp InitCom100
+
+
+ assumes ds,Data
+InitCom17:
+ mov ax, IE_OPEN
+ cmp [si.Port], -1 ;Q: determined that port didn't exist?
+ jne InitCom15 ; N: return IE_OPEN
+ jmp short InitCom27 ; Y: return IE_HARDWARE
+
+; *** Set up serial port ***
+;
+InitCom20:
+ cmp [si.Port], -1 ;Q: port exists?
+ je InitCom27 ; N: report not found
+
+ mov ax, __WinFlags
+ test ax, WF_ENHANCED
+ jz short @F
+ call GetCOMport386
+ jc InitCom17
+
+@@:
+ cmp [si.Port], 0 ;Q: already got info?
+ jnz @F
+ call FindCOMPort
+ jc InitCom27 ; report not found, if error
+ mov [si.Port], ax
+ mov [si.IntVecNum], dl
+@@:
+
+ push es ;Save these registers
+ push di
+ push cx ;needed later for $SETCOM etc
+ push bx
+
+ mov al, [si.IntVecNum]
+ xor ah, ah
+ lea di, [si+SIZE ComDEB]
+ mov [di.BIS_IRQ_Number], ax
+
+ mov di, DataOFFSET IRQhooks
+ mov cx, MAXCOM+1
+InitCom25:
+ cmp al, [di.IRQn] ;Q: hooked IRQ matches ours?
+ je short InitCom30 ; Y:
+ cmp [di.IRQn], 0 ;Q: end of hooked IRQ list?
+ je short InitCom35 ; Y:
+ add di, SIZE IRQ_Hook_Struc ; N: check next hook
+ loop InitCom25
+ int 3 ; data structures corrupt if we
+ ; get here, because no hook table
+ ; entries exist and there is suppose
+ ; to be at least 1 for each DEB
+InitCom26:
+ call ReleaseCOMport386 ; give port back to 386...
+ pop bx
+ pop cx
+ pop di
+ pop es
+
+InitCom27:
+ mov ax, IE_HARDWARE ; jump if port not available
+ jmp InitCom100
+
+InitCom30:
+ cmp [di.HookCnt], 0 ;Q: IRQ still hooked?
+ je short InitCom35 ; N: rehook
+ inc [di.HookCnt] ; Y: inc hook count
+ mov [si.IRQhook], di ; & link DEB into list
+ mov ax, [di.First_DEB]
+ mov [si.NextDEB], ax
+ mov [di.First_DEB], si
+ jmp short InitCom40
+
+InitCom35:
+ mov [di.IRQn], al ; hook IRQ for first time, or rehook
+ mov [si.IRQhook], di
+ mov [di.First_DEB], si
+ mov [di.HookCnt], 1
+ call MaskIRQ
+ mov [di.OldMask], al
+
+InitCom40: ; di -> IRQ_Hook_Struc
+
+ cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
+ jl short InitCom415 ; N:
+ mov ax, ds ; Y: use them
+ mov es, ax
+ lea di, [si+SIZE ComDEB]
+
+ mov [di.BIS_Descriptor_Count], 2
+ mov ax, word ptr [si.QInAddr+2] ; get selector of in queue
+ mov [di.EBIS_Sel1.EBIS_User_Mode_Sel], ax
+ mov ax, word ptr [si.QOutAddr+2] ; get selector of out queue
+ mov [di.EBIS_Sel2.EBIS_User_Mode_Sel], ax
+
+ mov ax, VPICD_Install_Handler
+ call [lpfnVPICD]
+ jnc InitCom42
+ cmp [di.OldMask], 0
+ jne InitCom26
+ call UnmaskIRQ
+ jmp InitCom26
+
+InitCom42:
+;
+; save newly allocated selectors/segments into "Alt" queue pointers
+;
+ mov ax, [di.EBIS_Sel1.EBIS_Super_Mode_Sel]
+ mov word ptr [si.AltQInAddr+2], ax
+ mov ax, [di.EBIS_Sel2.EBIS_Super_Mode_Sel]
+ mov word ptr [si.AltQOutAddr+2], ax
+
+InitCom414:
+ jmp InitCom59
+
+InitCom415:
+ cmp [di.VecN], 0FFh ;Q: int already hooked?
+IFDEF No_DOSX_Bimodal_Services
+ jnz short InitCom52 ; Y: init RMode ptrs in BIS
+ELSE
+ jnz InitCom414 ; Y:
+ENDIF
+ mov al, [si.IntVecNum]
+ add al, 8 ; 1st PIC starts at vector 8h
+ cmp al, 16 ;Q: 2nd PIC?
+ jb short InitCom418 ; N:
+ add al, 70h-16 ; Y: 2nd PIC starts at vector 70h
+InitCom418:
+ mov [di.VecN], al
+
+; *** Set interrupt vectors ***
+;
+ mov ah,35h ;Get the DOS vector
+ int 21h ;DOS Get Vector Function
+ mov wo [di.OldIntVec][0], bx
+ mov wo [di.OldIntVec][2], es
+
+InitCom50:
+ push ds ;Save original DS
+ mov dx, [di.HandlerOff]
+ mov bx, _INTERRUPT
+ mov ds, bx ;Interrupt handler address in ds:dx
+ assumes ds,nothing
+ mov ah, 25h ;DOS Set Vector Function
+ int 21h ;Set the DOS vector
+ pop ds ;Original DS
+ assumes ds,Data
+
+IFDEF No_DOSX_Bimodal_Services
+InitCom52:
+ cmp [Using_DPMI], 0
+ jz short InitCom57
+
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ mov bl, [si.IntVecNum]
+ mov bh, bl
+ add bl, dh ; assume master PIC
+ sub bh, 8 ;Q: IRQ in master?
+ jb @f ; Y: add master's base vec
+ add bh, dl ; N: add slave's base vec
+ mov bl, bh
+@@:
+ mov ax, Get_RM_IntVector
+ int 31h
+ mov wo [di.RM_OldIntVec][0], dx
+ mov wo [di.RM_OldIntVec][2], cx
+
+ mov dx, [di.RM_HandlerOff]
+ mov ax, _INTERRUPT
+ call SegmentFromSelector
+ mov cx, ax
+ push cx
+ mov ax, Set_RM_IntVector
+ int 31h
+
+ lea di, [si+SIZE ComDEB]
+ mov wo [di.BIS_Super_Mode_API], IntCodeOFFSET RM_APIHandler
+ pop cx
+ mov wo [di.BIS_Super_Mode_API+2], cx
+
+;
+; Get segment addresses for the Q's and set AltQInAddr and AltQOutAddr
+;
+ mov ax, wo [si.AltQInAddr+2]
+ call SegmentFromSelector
+ mov wo [si.AltQInAddr+2], ax
+ mov ax, wo [si.AltQOutAddr+2]
+ call SegmentFromSelector
+ mov wo [si.AltQOutAddr+2], ax
+InitCom57:
+ENDIF
+ mov ax, __WinFlags ;In Standard mode, the PIC IRQ
+ test al, WF_STANDARD ; priorities get rotated to favor
+ jz InitCom59 ; the comm ports.
+
+ call Rotate_PIC
+
+; *** Interrupt handler set : jump here if handler is already installed ***
+;
+InitCom59:
+ pop bx
+ pop cx
+ pop di
+ pop es
+
+InitCom60:
+ mov dx,[si.Port] ;Set comm card address
+ xor ax,ax ;Need a zero
+ inc dx ;--> Interrupt Enable Register
+ .errnz ACE_IER-ACE_RBR-1
+ out dx,al ;Turn off interrupts
+ call FlagNotActive
+ add dl,ACE_MCR-ACE_IER ;--> Modem Control Register
+ in al,dx
+ and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
+ iodelay ; but tri-state IRQ line
+ out dx,al
+
+InitCom70:
+ push es ;Zero queue counts and indexes
+
+ push ds
+ pop es
+ assumes es,Data
+
+ lea di,QInCount[si]
+ mov cx,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 1
+ xor ax,ax
+ cld
+ rep stosw
+
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+ pop es
+ assumes es,nothing
+
+ mov HSFlag[si],al ;Show no handshakes yet
+ mov MiscFlags[si],al ;Show not discarding
+ mov EvtWord[si],ax ;Show no events
+ mov [si.VCDflags], al
+
+ mov [si.SendTrigger], ax
+ dec ax
+ mov [si.RecvTrigger], ax
+
+;Call $SETCOM to perform further hardware initialization.
+
+InitCom80:
+ sub dl,ACE_MCR-ACE_FCR ; dx -> FCR
+ in al, dx
+ iodelay
+ test al, ACE_FIFO_E2 ;Q: FIFO already on?
+ jz short @F ; N:
+ or EFlags[si], fFIFOpre ; Y: flag it
+@@:
+
+ ; needs si, di, and es to be saved from the beginning of inicom
+ call $SETCOM ;Set up Comm Device
+ jnz short InitCom110 ;jump if failed
+
+ call UnmaskIRQ
+ and EFlags[si], fEFlagsMask ;Clear internal state
+
+InitCom90:
+ xor ax,ax ;Return AX = 0 to show success
+ mov ComErr[si],ax ;Get rid of any bogus init error
+
+InitCom100:
+ pop di
+ pop si
+ ret
+
+;
+; jump to here, if call to $SETCOM failed
+;
+; DANGER! *** Call into middle of Terminate to clean things up *** DANGER!
+;
+InitCom110:
+ push ax ;Failure, save error code
+ call Terminate45 ;Restore port address, int vec
+ pop ax ;Restore error code and exit
+ jmp InitCom100
+
+$INICOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $TRMCOM - Terminate Communications Channel
+;
+; Wait for any outbound data to be transmitted, drop the hardware
+; handshaking lines, and disable interrupts. If the output queue
+; contained data when it was closed, an error will be returned
+;
+; LPT devices have it easy. They just need to restore the I/O port
+; address.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = 8000h if invalid device ID
+; AX = -2 if output queue timeout occured
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $TRMCOM
+$TRMCOM proc near
+
+ push si
+ push di
+ xor cx,cx ;Show no error if LPT port
+ call GetDEB
+ jc TermCom60 ;ID is invalid, return error
+ js TermCom30 ;Port is a LPT port
+
+ push ax ;Save port id
+ or MiscFlags[si],Discard ;Show discarding serial data
+ mov ComErr[si],cx ;Clear error flags
+ mov QInCount[si],cx ;Show no chars in input queue
+ call $RECCOM ;Send XON if needed
+
+;-----------------------------------------------------------------------;
+; We have to wait for the output queue to empty. To do this,
+; a timer will be created. If no character has been transmitted
+; when the timeout occurs, then an error will be indicated and
+; the port closed anyway. If the timer cannot be created, then
+; just loop until the queue empties, which will be better than
+; discarding charatcers if there are any
+;-----------------------------------------------------------------------;
+
+ test [si.HSFlag], HHSAlwaysDown ; Q: handshaking ever up?
+ jnz TermCom17 ; N: skip wait loop
+
+TermCom10:
+ mov cx,QOutCount[si] ;Get current queue count
+ jcxz TermCom20 ;No characters in queue
+
+ cCall GetSystemMsecCount
+ mov di, ax
+
+TermCom15:
+ cmp QOutCount[si],cx ;Queue count change?
+ jne TermCom10 ; Yes, restart timeout
+
+ cCall GetSystemMsecCount
+ sub ax, di
+ cmp ax, Timeout * 1000 ;Q: Timeout reached?
+ jb TermCom15 ; No, keep waiting
+
+IFDEF DEBUG_TimeOut
+.286
+ pusha
+ lea cx, szSendTO
+ call Contention_Dlg
+ popa
+ jz TermCom10
+.8086
+ENDIF
+
+TermCom17:
+ mov cx, TimeoutError ; Yes, show timeout error
+
+TermCom20:
+ pop ax ;Restore cid
+
+TermCom30:
+ mov dx,Port[si] ;Get port base address
+ call Terminate ;The real work is done here
+ mov ax,cx ;Set return code
+
+TermCom60:
+ pop di
+ pop si
+ ret
+
+$TRMCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; Terminate - Terminate Device
+;
+; Restore the port I/O address and make sure that interrupts are off
+;
+; Entry:
+; AH = Device Id.
+; DX = Device I/O port address.
+; SI --> DEB
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = -1
+; Registers Destroyed:
+; AX,BX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public Terminate ;Public for debugging
+Terminate proc near
+
+ or ah,ah ;LPT port?
+ jns Terminate10 ; No, process COM port
+ .errnz LPTx-10000000b
+
+Terminate5:
+ call ReleasePort386 ; give port back to 386...
+ jmp Terminate50 ;That's all
+
+
+;-----------------------------------------------------------------------;
+; It is a com port!
+;
+; We delay for a bit while the last character finishes transmitting
+; Then we drop DTR and RTS, and disable the interrupt generation at
+; the 8250. Even if fRTSDisable or fDTRDisable is set, those lines
+; will be dropped when the port is closed.
+;-----------------------------------------------------------------------;
+;
+; When the OUT2 bit is reset to 0 to disable interrupts, many ports
+; generate an interrupt which can not be identified, because the the
+; interrupt ID register will not be set. To work around this hardware
+; problem we first mask the IRQ, then set the port into loopback mode
+; and output a NULL to generate a receive interrupt request. Then we
+; reset OUT2 and unmask the IRQ. This will cause the interrupt to occur
+; and the interrupt handler will be able to correctly identify the
+; interrupt as coming from the com port.
+
+Terminate10:
+ inc dx ;Disable chip interrupts
+ .errnz ACE_IER-ACE_RBR-1
+ mov al, ACE_ERBFI ; except receive
+ out dx,al
+ call FlagNotActive ; don't need to check for postmessage
+ ; on timer ticks
+ add dl,ACE_LSR-ACE_IER ;--> line status register
+ iodelay
+
+Terminate20:
+ in al,dx ;Wait until xmit is empty
+ and al,ACE_THRE+ACE_TSRE
+ cmp al,ACE_THRE+ACE_TSRE
+ jne Terminate20 ;Not empty yet
+
+Terminate30:
+ xor al, al
+ test EFlags[si], fFIFOpre ;Q: leave FIFO enabled?
+ jz short @F ; N:
+ mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
+@@:
+ sub dl, ACE_LSR-ACE_FCR
+ out dx, al
+ iodelay
+ call MaskIRQ
+ add dl, ACE_MCR-ACE_FCR ;--> Modem Control Register
+ in al,dx
+ iodelay
+ mov ah, al
+ or al,ACE_LOOP ; turn on loopback
+ out dx, al
+ iodelay
+ sub dl, ACE_MCR-ACE_THR
+ xor al, al
+ out dx, al ; output a NULL to generate an int
+ iodelay
+ add dl, ACE_LSR-ACE_THR
+Terminate35:
+ in al,dx ;Wait until xmit is empty
+ and al,ACE_THRE+ACE_TSRE
+ cmp al,ACE_THRE+ACE_TSRE
+ jne Terminate35 ;Not empty yet
+ mov al, ah
+ dec dl ; now clear OUT2 and loopback
+ .errnz ACE_LSR-ACE_MCR-1
+ and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
+ out dx,al ; but tri-state IRQ line
+
+ call UnmaskIRQ ; this will cause the receive int
+ ; to occur and be processed
+ sub dl, ACE_MCR-ACE_IER ; clear the receive int enable
+ xor al, al
+ out dx, al
+ dec dx
+ .errnz ACE_IER-ACE_RBR-1
+ call MaskIRQ
+
+;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
+;
+; Terminate45 is a secondary entrypoint into this routine--it's called
+; by the initialization code when that code is unable to properly init
+; a com port and needs to clean-up the mess it's made.
+;
+;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
+
+Terminate45:
+ push cx ;Save original cx
+ push bx ;Save original bx
+
+ cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
+ jl short @F ; N:
+ mov ax, ds ; Y: use them
+ mov es, ax
+ lea di, [si+SIZE ComDEB]
+ mov ax, VPICD_Remove_Handler
+ call [lpfnVPICD]
+@@:
+
+ mov di, [si.IRQhook]
+ dec [di.HookCnt] ;Q: last port using IRQ?
+ jne short Terminate495 ; N: unmask IRQ again
+ mov al, 0FFh
+ xchg al, [di.VecN] ;Interrupt vector number
+ cmp al, 0FFh ;Q: IRQ vector hooked?
+ je short Terminate49 ; no...
+
+IFDEF No_DOSX_Bimodal_Services
+ cmp [Using_DPMI], 0
+ jz short term_no_dpmi
+
+;
+; unhook RM vector thru DPMI for standard mode
+;
+ push ax
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ mov bl, [si.IntVecNum]
+ mov bh, bl
+ add bl, dh ; assume master PIC
+ sub bh, 8 ;Q: IRQ in master?
+ jb @f ; Y: add master's base vec
+ add bh, dl ; N: add slave's base vec
+ mov bl, bh
+@@:
+ mov dx, wo [di.RM_OldIntVec][0]
+ mov cx, wo [di.RM_OldIntVec][2]
+ mov ax, Set_RM_IntVector
+ int 31h
+ pop ax
+term_no_dpmi:
+ENDIF
+ mov dx, __WinFlags ;In Standard mode the PIC interrupt
+ test dl, WF_STANDARD ; priorities are changed to favor
+ jz Terminate48 ; the comm ports.
+
+ call Rotate_PIC ;This port no longer needs priority
+
+Terminate48:
+ ; *** reset int vector to it's previous state
+ assumes ds,nothing
+ push ds ;Save original DS [rkh] ...
+ lds dx, [di.OldIntVec]
+ mov ah, 25h ;DOS Set Vector Function
+ int 21h ;Set the DOS vector
+ pop ds ;Original DS
+ assumes ds,data
+
+; *** interrupt vectors have been reset if needed at this point ***
+;
+Terminate49:
+ mov cl, [di.OldMask]
+
+; Set the 8259 interrupt mask bit for this IRQ. Leave interrupts enabled
+; if they were already enabled when the comm port was initialized by us.
+
+ or cl, cl
+ jnz @f
+Terminate495:
+ call UnmaskIRQ
+@@:
+
+ xor ax, ax
+ xchg ax, [si.NextDEB]
+ cmp [di.First_DEB], si ;Q: DEB first for IRQ hook?
+ je short Terminate46 ; Y:
+ mov bx, [di.First_DEB] ; N: get first
+Terminate453:
+ cmp [bx.NextDEB], si ;Q: does this DEB point to one terminating?
+ je Terminate455 ; Y:
+ mov bx, [bx.NextDEB] ; N: get next DEB
+ jmp Terminate453
+Terminate455:
+ mov [bx.NextDEB], ax ; link previous DEB to NextDEB
+ jmp short Terminate47
+Terminate46:
+ mov [di.First_DEB], ax ; point IRQ hook at NextDEB
+Terminate47:
+ pop bx ;Original BX
+
+ call ReleaseCOMport386 ; give port back to 386...
+
+ pop cx ;Original CX
+
+Terminate50: ;Also called from $INICOM !
+ xor ax,ax ;Indicate no error
+ ret ;Port is closed and deallocated
+
+Terminate endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $ENANOTIFY - Enable Event Notification
+;
+; Entry:
+; AH = Device ID
+; BX = Window handle for PostMessage
+; CX = Receive threshold
+; DX = Transmit threshold
+; Returns:
+; AX = 1, if no errors occured
+; Error Returns:
+; AX = 0
+; Registers Preserved:
+; BX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $ENANOTIFY
+$ENANOTIFY proc near
+ push si
+ call GetDEB
+ mov ax, 0
+ jc scb_exit
+
+ mov ax, cx
+ inc ax
+ jz short scb_recv_ok
+ cmp cx, [si.QInSize] ;Q: receive threshold reasonable?
+ jb short scb_recv_ok ; Y:
+%OUT should we return an error, if thresholds invalid?
+ mov cx, [si.QInSize] ; N:
+ sub cx, 10
+scb_recv_ok:
+ inc dx
+ jz short scb_send_ok
+ dec dx
+ cmp dx, [si.QOutSize] ;Q: receive threshold reasonable?
+ jb short scb_send_ok ; Y:
+ mov dx, [si.QOutSize] ; N:
+ sub dx, 10
+scb_send_ok:
+ mov [si.NotifyHandle], bx
+ mov [si.NotifyFlagsHI], CN_Notify
+ or bx, bx ;Q: null callback?
+ jnz scb_save_thresholds ; N: save thresholds
+ or cx, -1 ; Y: zero thresholds
+ xor dx, dx
+ mov [si.NotifyFlagsHI], 0
+scb_save_thresholds:
+ mov [si.RecvTrigger], cx
+ mov [si.SendTrigger], dx
+ or [si.NotifyFlagsHI], CN_TRANSMIT ; we don't want to send
+ ; a transmit trigger notification until
+ ; the transmit buffer has been filled
+ ; above the trigger level and then
+ ; emptied below it again!
+
+ cmp wo lpPostMessage[2], 0 ;Q: gotten addr of PostMessage yet?
+ jne short scb_good ; Y:
+ push ds ; N: get module handle of USER
+ lea ax, szUser
+ push ax
+ cCall GetModuleHandle
+
+ push ax ; module handle
+ mov ax, POSTMESSAGE
+ cwd
+ push dx
+ push ax
+ cCall GetProcAddress
+ mov wo lpPostMessage[0], ax ; save received proc address
+ mov wo lpPostMessage[2], dx
+
+scb_good:
+ mov ax, 1
+
+scb_exit:
+ pop si
+ ret
+$ENANOTIFY endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETQUE - Set up Queue Pointers
+;
+; Sets pointers to Receive and Transmit Queues, as provided by the
+; caller, and initializes those queues to be empty.
+;
+; Queues must be set before $INICOM is called!
+;
+; Entry:
+; AH = Device ID
+; ES:BX --> Queue Definition Block
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; BX,DX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETQUE
+$SETQUE proc near
+
+ push si ;These will be used
+ push di
+ call GetDEB ;Get DEB
+ jc SetQue10 ;Invalid, ignore the call
+ js SetQue10 ;Ignore call for LPT ports
+ push ds ;Set ds:si --> QDB
+ push es ;Set es:di --> to ComDCB.QInAddr
+ pop ds
+ assumes ds,nothing
+ pop es
+ assumes es,Data
+ lea di,QInAddr[si]
+ mov si,bx
+ cld
+ FCLI ;No one else can play with queues
+ movsw ; QInAddr = QueueRxAddr
+ movsw
+ .errnz QueueRxAddr
+ sub si, 4 ; AltQInAddr = QueueRxAddr
+ mov cx, 5 ; QInSize = QueueRxSize
+ rep movsw ; QOutAddr = QueueTxAddr
+ sub si, 4
+ mov cx, 3 ; AltQOutAddr = QueueTxAddr
+ rep movsw ; QOutSize = QueueTxSize
+
+ xor ax,ax ;Will do some zero filling
+ mov cl,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 0FE01h
+ rep stosw
+ FSTI
+ push es ;Restore the data segment
+ pop ds
+ assumes ds,Data
+ assumes es,nothing
+
+SetQue10:
+ pop di ;Restore saved registers
+ pop si
+ ret
+
+; The above code made a few assumptions about how memory
+; was allocated within the structures:
+
+ .errnz AltQInAddr-QInAddr-4
+ .errnz (QueueRxSize-QueueRxAddr)-(QInSize-AltQInAddr)
+ .errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
+ .errnz AltQOutAddr-QOutAddr-4
+ .errnz (QueueTxSize-QueueTxAddr)-(QOutSize-AltQOutAddr)
+
+ .errnz QueueRxSize-QueueRxAddr-4
+ .errnz QueueTxAddr-QueueRxSize-2
+ .errnz QueueTxSize-QueueTxAddr-4
+
+ .errnz QInSize-AltQInAddr-4
+ .errnz QOutAddr-QInSize-2
+ .errnz QOutSize-AltQOutAddr-4
+
+ .errnz QInCount-QOutSize-2
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+$SETQUE endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETCOM - Set Communications parameters
+;
+; Re-initalizes the requested port if present, and sets up the
+; port with the given attributes when they are valid.
+;
+; For LPT ports, just copies whatever is given since it's ignored
+; anyway.
+;
+; Entry:
+; ES:BX --> DCB with all fields set.
+; Returns:
+; 'Z' Set if no errors occured
+; AX = 0
+; Error Returns:
+; 'Z' clear if errors occured
+; AX = initialization error code.
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETCOM
+$SETCOM proc near
+
+ cld
+ push si
+ push di
+ mov ah,es:[bx.DCB_Id] ;Get device i.d.
+ call GetDEB ;Get DEB pointer in SI
+ mov ax,IE_BadID ;Assume unknown device
+ jc SetCom10 ;Invalid device, return error
+ jns SetCom20 ;COM port
+ call SetCom100 ;Copy the DCB
+
+SetCom5:
+ xor ax,ax ;Show no error
+
+SetCom10:
+ or ax,ax ;Set/clear 'Z'
+ pop di ; and exit
+ pop si
+ ret
+
+;-----------------------------------------------------------------------;
+; Have a comm device, check all the serial parameters to make
+; sure they are correct before moving the new DCB into our space
+; and changing the ACE parameters.
+;-----------------------------------------------------------------------;
+
+SetCom20:
+ call SetCom300 ;Baud rate valid?
+ jcxz SetCom10 ; No, return error
+ call SetCom400 ;Byte size/parity/stop bits correct?
+ jc SetCom10 ; No, return error
+
+; The parameters seem correct. Copy the DCB into our space and
+; initialize the ACE with the new parameters
+
+ mov dx,Port[si] ;Disable interrupts from the 8250
+ inc dx
+ .errnz ACE_IER-1
+ xor ax,ax
+ out dx,al
+ call FlagNotActive
+
+ call SetCom100 ;Copy the DCB
+ mov bx,si ;Set ES:BX --> DCB
+ call SetCom200 ;Get timeout masks
+ xchg al,ah ;Want them in the correct registers
+ mov wo MSRMask[si],ax
+ .errnz MSRInfinite-MSRMask-1
+
+ call SetCom400 ;Get line control byte
+ push ax ; and save LCR value
+ inc dx ;--> LCR
+ inc dx
+ .errnz ACE_LCR-ACE_IER-2
+ or al,ACE_DLAB ;Want access to divisor latch
+ out dx,al
+ mov RxMask[si],ah ;Save Receive character mask
+ mov ax,di ;Get flags mask, error mask
+ and [si.DCB_Flags],ah ;Disable parity checking if no parity
+ mov ErrorMask[si],al ;Save line status error mask
+
+ call SetCom300 ;Get baud rate
+ sub dl,ACE_LCR-ACE_DLL ;--> LSB of divisor latch
+ mov al,cl
+ out dx,al
+ mov al,ch
+ inc dx ;--> MSB of divisor latch
+ .errnz ACE_DLM-ACE_DLL-1
+ iodelay
+ out dx,al
+ inc dx ;--> LCR and clear divisor access bit
+ inc dx
+ .errnz ACE_LCR-ACE_DLM-2
+ pop ax
+ out dx,al
+
+ inc dx ;--> Modem Control Register
+ .errnz ACE_MCR-ACE_LCR-1
+
+;-----------------------------------------------------------------------;
+; Compute initial state of DTR and RTS. If they have been disabled,
+; then do not raise them, and disallow being used as a handshaking
+; line. Also compute the bits to use as hardware handshake bits
+; (DTR and/or RTS as indicated, qualified with the disabled flags).
+;-----------------------------------------------------------------------;
+
+ mov al,[si.DCB_Flags] ;Align DTR/RTS disable flags for 8250
+ and al,fRTSDisable+fDTRDisable
+ rol al,1 ;d0 = DTR, d2 = RTS (1 = disabled)
+ shr al,1 ;'C'= DTR, d1 = RTS
+ adc al,0 ;d0 = DTR, d1 = RTS
+ .errnz fRTSDisable-00000010b
+ .errnz fDTRDisable-10000000b
+ .errnz ACE_DTR-00000001b
+ .errnz ACE_RTS-00000010b
+
+ mov ah,al ;Save disable mask
+ xor al,ACE_DTR+ACE_RTS+ACE_OUT2
+ out dx,al ;Set Modem Control Register
+
+ mov al,[si.DCB_Flags2] ;Get hardware handshake flags
+ rol al,1 ;Align flags as needed
+ rol al,1
+ rol al,1
+ and al,ACE_DTR+ACE_RTS ;Mask bits of interest
+ not ah ;Want inverse of disable mask
+ and al,ah ;al = bits to handshake with
+ mov HHSLines[si],al ;Save for interrupt code
+
+ .errnz fDTRFlow-00100000b
+ .errnz fRTSFlow-01000000b
+ .errnz ACE_DTR-00000001b
+ .errnz ACE_RTS-00000010b
+
+ mov al,[si.DCB_Flags] ;Compute the mask for the output
+ shl al,1 ; hardware handshake lines
+ and al,ACE_DSR+ACE_CTS
+ mov OutHHSLines[si],al
+
+ .errnz fOutXCTSFlow-00001000b
+ .errnz fOutXDSRFlow-00010000b
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+
+; Compute the queue count where XOff should be issued (or hardware
+; lines dropped). This will prevent having to do it at interrupt
+; time.
+
+ mov ax,QInSize[si] ;Get where they want it
+ sub ax,[si.DCB_XoffLim] ; and compute queue count
+ mov XOffPoint[si],ax
+
+; Enable FIFO if possible when baudrate >= 4800
+;
+ sub dl,ACE_MCR - ACE_FCR ; dx = FCR
+ test EFlags[si], fNoFIFO ;Q: FIFO can be enabled?
+ jnz sc_nofifo ; N:
+ mov ax, [si.DCB_BaudRate]
+ cmp ax, 4800
+ jb sc_nofifo
+ cmp ah, -1 ;Q: baudrate index?
+ jne sc_fifo ; N: baudrate >= 4800, enable FIFO
+ cmp ax, CBR_4800
+ jb sc_nofifo
+%OUT this isn't correct, if lower baudrates are assigned indices above CBR_4800
+
+sc_fifo:
+ mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
+ out dx, al ; attempt to enable FIFO
+ test EFlags[si], fFIFOchkd ;Q: FIFO detect been done?
+ jnz sc_fifodone ; Y: enabled FIFO
+ iodelay
+ .errnz ACE_IIDR-ACE_FCR
+ in al, dx
+ or EFlags[si], fFIFOchkd
+ test al, ACE_FIFO_E2 ;Q: FIFO enabled?
+ jz short @F
+ test al, ACE_FIFO_E1 ;Q: 16550A detected?
+ jnz sc_fifodone ; Y: enabled FIFO
+@@:
+ iodelay
+ or EFlags[si], fNoFIFO
+
+sc_nofifo:
+ xor al, al
+ out dx, al
+sc_fifodone:
+
+ sub dl,ACE_FCR-ACE_RBR ; dx -> RBR
+;
+; Delay for things to settle
+;
+ push dx
+ cCall GetSystemMsecCount
+ pop dx
+ mov cx, ax
+delay_loop:
+ in al, dx ;Read it once
+ push dx
+ cCall GetSystemMsecCount
+ pop dx
+ sub ax, cx
+ cmp ax, DELAY_TIME ;Q: Timeout reached?
+ifndef WOW
+ jb delay_loop ; N:
+endif
+
+ add dl,ACE_MSR ;--> Modem Status reg
+ in al,dx ;Throw away 1st status read
+ iodelay
+ in al,dx ;Save 2nd for MSRWait (Clear MSR int)
+ mov MSRShadow[si],al
+
+; Win 3.0 didn't check hardware handshaking until the line status changed.
+; Allow some apps to keep that behavior.
+
+ push dx
+ xor ax, ax
+ cCall GetAppCompatFlags,<ax>
+ pop dx
+ test ax, GACF_DELAYHWHNDSHAKECHK
+ jnz short sc_HHSup
+
+;
+; HACK FOR SOME MODEMS: apparently some modems set CTS, but don't set DSR
+; which means that COMM.DRV won't send if the app specifies that hardware
+; handshaking is based on CTS & DSR being set.
+;
+ mov ah,OutHHSLines[si]
+ mov al, MSRShadow[si]
+ and al,ah ;Only leave bits of interest
+ cmp al, ah ;Q: handshaking lines ok?
+ je short sc_HHSup ; Y:
+ cmp ah, ACE_CTS OR ACE_DSR ;Q: app looking for both high?
+ jne short sc_HHSdown ; N: skip hack
+ test [si.EFlags], fUseDSR ;Q: DSR is always significant?
+ jnz short sc_HHSdown ; Y: skip hack
+ cmp al, ACE_CTS ;Q: DSR low & CTS high
+ jne short sc_HHSdown ; N: skip hack
+ and ah, NOT ACE_DSR ; Y: ignore DSR line
+ mov OutHHSLines[si], ah
+ jmp short sc_HHSup
+
+sc_HHSdown:
+ or [si.HSFlag], HHSDown OR HHSAlwaysDown ; flag handshaking down
+sc_HHSup:
+
+;-----------------------------------------------------------------------;
+; Now, at last, interrupts can be enabled. Don't enable the
+; transmitter empty interrupt. It will be enabled by the first
+; call to KickTx.
+;-----------------------------------------------------------------------;
+
+ sub dl,ACE_MSR-ACE_IER ;--> Interrupt Enable Register
+
+; flag port as being active
+ push cx
+ mov cl, [si.DCB_Id]
+ mov ax, 1
+ shl ax, cl
+ or [activeCOMs], ax
+ pop cx
+
+ mov al,ACE_ERBFI+ACE_ELSI+ACE_EDSSI
+ FCLI
+ out dx,al ;Enable interrupts.
+ add dl,ACE_LSR-ACE_IER ;--> Line Status Register
+ iodelay
+ in al,dx ;Clear any Line Status interrupt
+ sub dl,ACE_LSR ;--> Receiver Buffer Register
+ iodelay
+ in al,dx ;Clear any Received Data interrupt
+ FSTI
+ jmp SetCom5 ;All done
+
+$SETCOM endp
+page
+
+FlagNotActive proc near
+ push cx
+ mov cl, [si.DCB_Id]
+ mov ax, NOT 1
+ rol ax, cl
+ and [activeCOMs], ax
+ pop cx
+ ret
+FlagNotActive endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom100
+;
+; Copy the given DCB into the appropriate DEB. The check has
+; already been made to determine that the ID was valid, so
+; that check can be skipped.
+;
+; Entry:
+; ES:BX --> DCB
+; DS:SI --> DEB
+; Returns:
+; DS:SI --> DEB
+; ES = Data
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,ES,DI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom100 proc near
+ push si ;Save DEB pointer
+ mov di,si
+ mov si,bx
+ push es
+ mov ax,ds
+ pop ds
+ assumes ds,nothing
+
+ mov es,ax
+ assumes es,Data
+
+ mov cx,DCBSize
+ cld
+ rep movsb
+ mov ds,ax
+ assumes ds,Data
+
+ pop si ;Restore DEB pointer
+ ret
+
+SetCom100 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom200
+;
+; Based on whether or not a timeout has been specified for each
+; signal, set up a mask byte which is used to mask off lines for
+; which we wish to detect timeouts. 0 indicates that the line is
+; to be ignored.
+;
+; Also set up a mask to indicate those lines which are set for
+; infinite timeout. 1 indicates that the line has infinite
+; timeout.
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; AH = lines to check
+; AL = lines with infinite timeout
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom200 proc near
+
+ xor ax,ax
+ xor cx,cx ;Get mask of lines with timeout = 0
+ call SetCom210
+ not al ;Invert result to get lines to check
+ and al,ACE_CTS+ACE_DSR+ACE_RLSD
+ xchg ah,al
+ dec cx ;Get mask of infinite timeouts
+
+SetCom210:
+ cmp es:[bx.DCB_RlsTimeout],cx ;Timeout set to passed value?
+ jne SetCom220 ; No
+ or al,ACE_RLSD ; Yes, show checking line
+
+SetCom220:
+ cmp es:[bx.DCB_CtsTimeout],cx ;Timeout set to passed value?
+ jne SetCom230 ; No
+ or al,ACE_CTS ; Yes, show checking line
+
+SetCom230:
+ cmp es:[bx.DCB_DsrTimeout],cx ;Timeout set to passed value?
+ jne SetCom240 ; No
+ or al,ACE_DSR ; Yes, show checking line
+
+SetCom240:
+ ret
+
+SetCom200 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom300
+;
+; Calculate the correct baudrate divisor for the comm chip.
+;
+; Note that the baudrate is allowed to be any integer in the
+; range 2-19200. The divisor is computed as 115,200/baudrate.
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; CX = baudrate
+; Error Returns:
+; CX = 0 if error
+; AX = error code if invalid baud rate
+; Registers Destroyed:
+; AX,CX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+BaudRateByIndexTable label word
+ dw 1047 ; CBR_110
+ dw 384 ; CBR_300
+ dw 192 ; CBR_600
+ dw 96 ; CBR_1200
+ dw 48 ; CBR_2400
+ dw 24 ; CBR_4800
+ dw 12 ; CBR_9600
+ dw 9 ; CBR_14400
+ dw 6 ; CBR_19200
+ dw 0 ; 0FF19h (reserved)
+ dw 0 ; 0FF1Ah (reserved)
+ dw 3 ; CBR_38400
+ dw 0 ; 0FF1Ch (reserved)
+ dw 0 ; 0FF1Dh (reserved)
+ dw 0 ; 0FF1Eh (reserved)
+ dw 2 ; CBR_56000
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom300 proc near
+
+ push dx
+ mov cx,es:[bx.DCB_BaudRate] ;Get requested baud rate
+ xor ax,ax ;Assume error
+ cmp cx, CBR_110 ;Q: baudrate specified as an index?
+ jae by_index
+ cmp cx,2 ;Within valid range?
+ jnae SetCom310 ; No, return error
+
+ mov dx,1 ;(dx:ax) = 115,200
+ mov ax,0C200h
+ div cx ;(ax) = 115,200/baud
+
+SetCom310:
+ mov cx,ax ;(cx) = baud rate, or error code (0)
+ mov ax,IE_Baudrate ;Set error code incase bad baud
+ pop dx
+ ret
+
+by_index:
+ cmp cx, CBR_56000 ;Q: above supported?
+ ja SetCom310 ; Y: return error
+ push bx
+ mov bx, cx
+ sub bx, CBR_110
+ shl bx, 1
+ mov ax, cs:[bx+BaudRateByIndexTable] ; get divisor
+ pop bx
+ jmp SetCom310 ; Y: return error
+
+
+SetCom300 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom400
+;
+; Check the line configuration (Parity, Stop bits, Byte size)
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; 'C' clear if OK
+; AL = Line Control Register
+; AH = RxMask
+; DI[15:8] = Flags mask (to remove parity checking)
+; DI[7:0] = Error mask (to remove parity error)
+; Error Returns:
+; 'C' set if error
+; AX = error code
+; Registers Destroyed:
+; AX,CX,DI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom400 proc near
+
+ mov ax,wo es:[bx.DCB_ByteSize] ;al = byte size, ah = parity
+ cmp ah,SpaceParity ;Parity out of range?
+ ja SetCom470 ; Yes, return error
+ mov di,0FF00h+ACE_OR+ACE_PE+ACE_FE+ACE_BI
+ or ah,ah ;Is parity "NONE"?
+ jnz SetCom410 ; No, something is there for parity
+ xor di,(fParity*256)+ACE_PE ;Disable parity checking
+
+SetCom410:
+ cmp al,8 ;Byte size out of range?
+ ja SetCom460 ; Yes, error
+
+SetCom420:
+ sub al,5 ;Shift byte size to bits 0&1
+ .errnz ACE_WLS-00000011b ;Word length must be these bits
+ jc SetCom460 ;Byte size is illegal, return error
+ add ah,ah ;Map parity to ACE bits
+ jz SetCom430 ;0=>0, 1=>1, 2=>3, 3=>5, 4=>7
+ dec ah
+
+SetCom430:
+ shl ah,1 ;Align with 8250 parity bits
+ shl ah,1
+ shl ah,1
+ or al,ah ;Add to byte size
+
+ .errnz NoParity-0
+ .errnz OddParity-1
+ .errnz EvenParity-2
+ .errnz MarkParity-3
+ .errnz SpaceParity-4
+ .errnz ACE_PEN-00001000b
+ .errnz ACE_PSB-00110000b
+ .errnz ACE_EPS-00010000b
+ .errnz ACE_SP-00100000b
+
+ or al,ACE_2SB ;Assume 2 stop bits
+ mov ah,es:[bx.DCB_StopBits] ;Get # of stop bits 0=1,1/2= .GT. 1
+ or ah,ah ;Out of range?
+ js SetCom470 ; Yes, return error
+ jz SetCom440 ;One stop bit
+ sub ah,2
+ jz SetCom450 ;Two stop bits
+ jns SetCom470 ;Not 1.5, return error
+ test al,ACE_WLS ;1.5 stop bits, 5 bit words?
+ jnz SetCom470 ; No, illegal
+ .errnz OneStopBit-0
+ .errnz One5StopBits-1
+ .errnz TwoStopBits-2
+ .errnz ACE_5BW
+
+SetCom440:
+ and al,NOT ACE_2SB ;Show 1 (or 1.5) stop bit(s)
+
+
+; From the byte size, get a mask to be used for stripping
+; off unused bits as the characters are received.
+
+SetCom450:
+ push dx
+ mov cl,es:[bx.DCB_ByteSize] ;Get data byte size
+ mov dx,00FFh ;Turn into mask by shifting bits
+ shl dx,cl
+ mov ah,dh ;Return mask in ah
+ pop dx
+ clc ;Show all is fine
+ ret
+
+SetCom460:
+ mov ax,IE_ByteSize ;Show byte size is wrong
+ stc ;Show error
+ ret
+
+SetCom470:
+ mov ax,IE_Default ;Show something is wrong
+ stc ;Show error
+ ret
+
+SetCom400 endp
+page
+
+;----------------------------------------------------------------------------
+; SuspendOpenCommPorts:
+;
+; This routine is called from 286 Winoldaps to simply deinstall the comm port
+; hooks.
+;----------------------------------------------------------------------------
+
+cProc SuspendOpenCommPorts,<FAR,PUBLIC,PASCAL>
+
+cBegin nogen
+
+ assumes cs,Code
+ assumes ds,Data
+
+%OUT not masking IRQ's
+
+ ; Nothing to do under 3.1!
+
+ ret
+
+cEnd nogen
+
+;----------------------------------------------------------------------------;
+; ReactivateOpenCommPorts: ;
+; ;
+; This routine reinstalls the comm hooks in real mode and reads the 8250 ;
+; data and status registers to clear pending interrupts. ;
+;----------------------------------------------------------------------------;
+
+cProc ReactivateOpenCommPorts,<FAR,PASCAL,PUBLIC>,<si,di>
+
+cBegin
+ call Rotate_PIC ;make comm ports highest priority
+
+ mov cx, MAXCOM+1
+ mov di,dataOffset COMptrs
+rcp_loop:
+ mov si, [di]
+ mov dx, Port[si]
+ or dx, dx
+ jz @f
+ call InitAPort ;read comm port regs to clr pending ints
+@@:
+ add di, 2
+ loop rcp_loop
+
+cEnd
+
+;----------------------------------------------------------------------------;
+; InitAPort: ;
+; ;
+; reads the data,status & IIR registers of a port (has to be 8250!) ;
+; ;
+; If the port has an out queue pending, then this woutine will also start ;
+; the transmit process by faking a comm interrupt. ;
+;----------------------------------------------------------------------------;
+
+public InitAPort
+InitAPort proc near
+
+ add dl,ACE_RBR ;dx=receive buffer register
+ in al,dx ;read the data port
+ jmp short $+2 ;i/o delay
+ add dl,ACE_LSR - ACE_RBR ;get to the status port
+ in al,dx ;read it too.
+ jmp short $+2 ;i/o delay
+ add dl,ACE_IIDR - ACE_LSR ;get to the line status register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ add dl,ACE_MSR - ACE_IIDR ;get to the modem status register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ add dl,ACE_RBR - ACE_MSR ;get to the receive buffer register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ call UnmaskIRQ
+
+; now if the port has characters pending to be sent out then we must fake a
+; comm interrupt.
+
+ cmp [si].QOutCount,0 ;characters pending to be sent ?
+ jz @f ;no.
+ FCLI ;disable interrupts
+ call FakeCOMIntFar ;fake an interrupt
+ FSTI ;renable interrupts
+@@:
+ ret
+
+InitAPort endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $DCBPtr - Return Pointer To DCB
+;
+; Returns a long pointer to the DCB for the requested device.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; DX:AX = pointer to DCB.
+; Error Returns:
+; DX:AX = 0
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; BX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $DCBPTR
+$DCBPTR proc near
+
+ push si
+ xor dx,dx
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx
+ jc DCBPtr10 ;Jump if invalid device
+ mov ax,si ;else return value here
+ mov dx,ds
+
+DCBPtr10:
+ pop si
+ ret
+
+$DCBPTR endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetDEB - Get Pointer To Device's DEB
+;
+; Returns a pointer to appropriate DEB, based on device number.
+;
+; Entry:
+; AH = cid
+; Returns:
+; 'C' clear
+; 'S' set if LPT device
+; DS:SI --> DEB is valid cid
+; AH = cid
+; Error Returns:
+; 'C' set if error (cid is invalid)
+; AX = 8000h
+; Registers Preserved:
+; BX,CX,DX,DI,DS,ES
+; Registers Destroyed:
+; AX,SI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public GetDEB ;Public for debugging
+GetDEB proc near
+
+ push cx
+ mov cl, ah
+ and cx, (NOT LPTx AND 0FFh)
+ test ah, ah ;Q: LPT id?
+ js short GetDEB10 ; Y:
+.errnz LPTx - 80h
+ cmp ah, MAXCOM ;Q: Within range?
+ ja GetDEB30 ; N: return invalid ID
+ shl cx, 1
+ mov si, cx
+ mov si, [si+COMptrs]
+ jmp short GetDEB20
+
+GetDEB10:
+ cmp ah, LPTx+MAXLPT ;Q: Within range?
+ ja GetDEB30 ; N: return invalid ID
+ mov si, DataOFFSET LPT1
+ jcxz GetDEB20
+GetDEB15:
+ add si, SIZE LptDEB
+ loop GetDEB15
+GetDEB20:
+ pop cx
+ or ah, ah ; clear Carry & set S, if LPT port
+ ret
+
+GetDEB30:
+ pop cx
+ mov ax,8000h ;Set error code
+ stc ;Set 'C' to show error
+ ret
+
+GetDEB endp
+page
+
+
+CvtHex proc near
+; assume DS=SS
+ push si
+ mov cl, 4
+ mov si, di
+ xor dx, dx
+ cld
+ch_lp:
+ lodsb
+ sub al, '0' ;Q: char < '0'
+ jb ch_exit ; Y: return
+ cmp al, 9 ;Q: char <= '9'
+ jbe ch_got_digit ; Y: move digit into result
+ sub al, 'A' - '0' ;Q: char < 'A'
+ jb ch_exit ; Y: return
+ add al, 10
+ cmp al, 15 ;Q: char <= 'F'
+ jbe ch_got_digit ; Y: move hex char into result
+ sub al, 10 + 'a' - 'A' ;Q: char < 'a'
+ jb ch_exit ; Y: return
+ add al, 10
+ cmp al, 15 ;Q: char > 'f'
+ ja ch_exit ; Y: return
+ch_got_digit:
+ shl dx, cl
+ or dl, al
+ jmp ch_lp
+ch_exit:
+ mov ax, dx
+ pop si
+ ret
+CvtHex endp
+
+.286
+; attempt to read base from SYSTEM.INI
+GetComBase proc near
+ push ds ; save our DS
+ sub sp, 6
+ mov di, sp
+ mov byte ptr ss:[di], 0
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommBase
+ push ss ; temp buffer
+ push di
+ push ss ; default = temp buffer
+ push di
+ push 5
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileString ; our segment in real mode
+ or ax, ax
+ jz short gcb_exit
+ call CvtHex ; DS still equal to SS
+gcb_exit:
+ add sp, 6
+ pop ds ; restore our DS
+ assumes ds,Data
+ ret
+GetComBase endp
+
+GetPortIRQ proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommIrq
+ push bx
+ mov bl, [si.DCB_Id]
+ cmp bl, 4
+ jb @f
+ mov bl, 4
+@@:
+ xor bh, bh
+ mov bl, [bx+default_table]
+ mov cx, bx
+ pop bx
+ push cx ; default
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ ret
+GetPortIRQ endp
+
+
+GetPortFlags proc near
+ mov al, [si.DCB_Id]
+.erre MAXCOM LT 9 ;only single digit port numbers supported
+ add al, '1'
+ mov [CommFIFOX], al
+ mov [CommDSRx], al
+ call GetPortFIFO
+ call GetPortDSR
+ ret
+GetPortFlags endp
+
+GetPortFIFO proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommFifo
+ push 2
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ cmp ax, 1
+ ja short gpf_exit ; just check at open
+ jb short gpf_no_fifo ; force OFF, if = 0
+ or EFlags[si], fFIFOchkd ; flag as checked, to force ON
+ jmp short gpf_exit
+
+gpf_no_fifo:
+ or EFlags[si], fNoFIFO OR fFIFOchkd ; force OFF
+
+gpf_exit:
+ ret
+GetPortFIFO endp
+
+GetPortDSR proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommDSR
+ push 0
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ or ax, ax
+ jz short gpd_exit
+ or EFlags[si], fUseDSR
+
+gpd_exit:
+ ret
+GetPortDSR endp
+
+
+; FindCOMPort
+;
+; DS:SI -> DEB
+;
+ PUBLIC FindCOMPort
+FindCOMPort proc near
+;
+; Examine BIOS data area to get base I/O addresses for COM and LPT ports
+;
+ push bx
+ push cx
+ push es
+ mov ax, __0040H
+ mov es, ax
+ assumes es,nothing
+
+ mov al, [si.DCB_Id]
+ mov ah, al
+.erre MAXCOM LT 9 ;only single digit port numbers supported
+ add ah, '1'
+ mov [CommBaseX], ah
+ mov [CommIRQX], ah
+ mov [CommFIFOX], ah
+ mov [CommDSRx], ah
+
+ cmp al, 4
+ jae fcp_not_phys_com
+ xor ah, ah
+ shl ax, 1
+ mov bx, ax
+ mov ax, es:[bx+RS232B]
+ or ax, ax
+ jnz fcp_got_com_base
+fcp_not_phys_com:
+ call GetComBase
+ or ax, ax
+ jnz fcp_got_com_base
+ mov bl, [si.DCB_Id]
+ cmp bl, 2
+ jne fcp_invalid ; jump, if base = 0 & com port <> com3
+ mov ax, 3E8h ; default COM3 to 3E8h
+fcp_got_com_base:
+ push ax
+ call GetPortIRQ
+ mov dx, ax
+ pop ax
+ or dl, dl ;Q: non-zero IRQ?
+ jz fcp_invalid ; N:
+ cmp dl, 15 ;Q: IRQ in range?
+ ja fcp_invalid ; N:
+ xor dh, dh
+ push ax
+ push dx
+ call GetPortFIFO
+ call GetPortDSR
+ pop dx
+ pop ax
+ clc
+fcp_exit:
+ pop es
+ pop cx
+ pop bx
+ ret
+
+fcp_invalid:
+ or ax, -1
+ mov dx, ax
+ stc
+ jmp fcp_exit
+
+FindCOMPort endp
+.8086
+
+page
+;--------------------------Private Routine-----------------------------;
+;
+; Rotate the PIC interrupt priorities so the communication ports are
+; highest priority.
+;
+; NOTE: Only rotates priorities on master PIC.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public Rotate_PIC
+
+Rotate_PIC proc near
+
+ push ax
+ push cx
+ push di
+
+ mov al, 8 ; 0 - 7 rotated
+ mov cx, MAXCOM+1
+ mov di, DataOFFSET IRQhooks
+rp_loop:
+ mov ah, [di.IRQn]
+ cmp ah, 0 ;End of hooked IRQ list?
+ je rp_set
+ cmp [di.VecN], 0FFh ;Hooked?
+ je rp_next
+ cmp ah, 8 ;If on slave PIC, treat as IRQ2
+ jb @f
+ mov ah, 2
+@@:
+ cmp ah, al
+ jae rp_next
+ mov al, ah ;AL = lowest hooked comm IRQ
+rp_next:
+ add di, SIZE IRQ_Hook_Struc
+ loop rp_loop
+
+rp_set:
+ dec al ;Setting IRQ(n-1) as the lowest
+ and al, 07h ; priority makes IRQn the highest
+ or al, 0C0h
+ out INTA0, al
+
+ pop di
+ pop cx
+ pop ax
+ ret
+
+Rotate_PIC endp
+
+
+ifdef DEBUG
+ public InitCom10, InitCom20, InitCom40, InitCom50, InitCom59
+ public InitCom60, InitCom70, InitCom80, InitCom90, InitCom100
+ public TermCom10, TermCom15, TermCom20, TermCom30
+ public TermCom60, Terminate5, Terminate10, Terminate20, Terminate30
+ public Terminate45, Terminate49, Terminate50
+ public SetQue10
+ public SetCom5, SetCom10, SetCom20, SetCom210, SetCom220, SetCom230
+ public SetCom240, SetCom310, SetCom410, SetCom420, SetCom430
+ public SetCom440, SetCom450, SetCom460, SetCom470
+ public GetDEB10, GetDEB20, GetDEB30
+ public DCBPtr10
+endif
+
+sEnd code
+
+page
+
+createSeg _INIT,init,word,public,CODE
+sBegin init
+assumes cs,init
+
+
+
+;------------------------------------------------------------------------------
+;------------------------------------------------------------------------------
+IBMmodel proc near
+ push ax
+ push bx
+ push es
+
+ mov ah, 0c0h
+ int 15h
+ jc IBMmodel_exit
+
+ assumes es,nothing
+
+ cmp by es:[bx+2], 0f8h ; PS/2 80
+ je IBMmodel_exit ; return carry clear
+
+ cmp by es:[bx+2], 0fch ; AT or PS/2 50 or 60
+ jne OldBios ; assume OldBios
+
+ cmp by es:[bx+3], 04h ; PS/2 50
+ je IBMmodel_exit ; return carry clear
+ cmp by es:[bx+3], 05h ; PS/2 60
+ je IBMmodel_exit ; return carry clear
+
+OldBios:
+ stc
+
+IBMmodel_exit:
+ pop es
+ pop bx
+ pop ax
+ ret
+
+IBMmodel endp
+
+cProc LoadLib, <FAR,PUBLIC,NODATA>,<si,di>
+cBegin
+
+ push ds
+ mov ax, __F000H
+ mov ds, ax
+ assumes ds, ROMBios
+ mov al, [MachineID]
+ pop ds
+ assumes ds,Data
+ mov [$MachineID], al
+
+ call IBMmodel ;Q: PS/2?
+ jc @F ; N:
+ mov [default_table+2], 3 ; Y: change COM3 default IRQ to 3
+@@:
+
+ push ds
+ mov ax, __0040H
+ mov ds, ax
+ assumes ds,nothing
+ cmp word ptr ds:[RS232B], 2F8h ;Q: COM2 base in COM1 slot?
+ pop ds
+ assumes ds,Data
+ jne @F ; N: leave IRQ default as 4
+ mov [default_table], 3 ; Y: change IRQ default to 3
+@@:
+
+ mov [fVPICD], -1 ; assume no
+
+ xor di, di
+ mov es, di
+ mov ax, GET386API
+ mov bx, VPICD
+ int MULTIPLEX
+ mov wo [lpfnVPICD], di
+ mov wo [lpfnVPICD+2], es
+ mov ax, es
+ or ax, di
+ jz short no_VPICD ; jump if no bimodel services available
+;
+; version check VPICD
+;
+ mov ax, VPICD_API_Get_Ver
+ call [lpfnVPICD]
+%OUT version check VPICD
+
+ mov [fVPICD], 1 ; flag services are available
+
+IFDEF No_DOSX_Bimodal_Services
+ jmp short skip_dosx_stuff
+
+no_VPICD:
+ mov ax, __WinFlags
+ and al, WF_PMODE or WF_WIN286
+ cmp al, WF_PMODE or WF_WIN286
+ jne skip_dosx_stuff
+
+.286
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ test bl, 10b ;Q: processor goes to real mode
+ ; for int reflection?
+ jz skip_dosx_stuff ; N:
+ mov [Using_DPMI], 0FFh ; Y: flag use of DPMI
+
+ mov ax, ds
+ cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
+ shr ax, 4
+ shl dl, 4
+ or ah, dl ;AX now points to interrupt *segment*
+ push ax ;save on stack
+ mov ax, _INTERRUPT ;write data SEGMENT into _INTERRUPT
+ cCall AllocCStoDSAlias,<ax> ; code segment -- requires a data alias
+ mov es, ax
+ pop ax
+ mov es:[RM_IntDataSeg],ax
+ push ds
+ push es
+ mov ax, ds
+ mov es, ax
+ mov ax, _INTERRUPT
+ mov ds, ax
+ mov ax, (Int31_Trans_Serv SHL 8) + Trans_Call_Back
+ mov si, IntCodeOFFSET Entry_From_RM
+ mov di, DataOFFSET RM_Call_Struc
+ int 31h
+ pop es
+ pop ds
+ mov ax, 0
+ jnc @f
+ jmp short LoadExit
+@@:
+ mov wo es:[RM_CallBack], dx
+ mov wo es:[RM_CallBack+2], cx
+ cCall FreeSelector,<es> ;don't need CS alias any longer
+.8086
+skip_dosx_stuff:
+ELSE
+no_VPICD:
+ENDIF
+
+;
+; find base values for LPT ports
+;
+ mov cx, __0040h
+ mov es, cx
+ mov cx, MAXLPT+1
+ mov si, DataOFFSET LPT1
+ll_initl_lp:
+ mov bx, [si.BIOSPortLoc]
+ or bx, bx
+ jz ll_not_phys_lpt
+ mov ax, es:[bx]
+ or ah, ah ;Q: lpt redirected, or 0?
+ jz ll_not_phys_lpt ; Y:
+ cmp bx, LPTB ;Q: first LPT?
+ je ll_got_lpt_base ; Y:
+ cmp ax, es:[bx-2] ;Q: base same as previous (redirected)?
+ jne ll_got_lpt_base ; N: must be real
+ll_not_phys_lpt:
+%OUT attempt to read base from SYSTEM.INI
+
+ll_got_lpt_base:
+ mov [si.Port], ax
+ loop ll_initl_lp
+
+;
+; create system timer for signalling chars in receive buffer
+;
+
+ifndef WOW
+ mov ax, 100 ; create 100msec timer
+ push ax
+ mov ax, _INTERRUPT
+ push ax
+ mov ax, IntCodeOFFSET TimerProc
+ push ax
+ call CreateSystemTimer ; ax = 0, if failed
+%OUT should I display an error message here?
+
+endif
+ assumes es,nothing
+LoadExit:
+cEnd
+
+sEnd init
+
+End LoadLib
diff --git a/private/mvdm/wow16/drivers/comm/ins8250.inc b/private/mvdm/wow16/drivers/comm/ins8250.inc
new file mode 100644
index 000000000..6d61a0227
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ins8250.inc
@@ -0,0 +1,78 @@
+; INS8250 ACE Register Offsets And Bit Definitions
+
+
+ACE_RBR equ 0 ;Receiver Buffer
+ACE_THR equ 0 ;Transmit Holding Register
+
+ACE_IER equ 1 ;Interrupt Enable
+ ACE_ERBFI equ 00000001b ; Received Data Available
+ ACE_ETBEI equ 00000010b ; Transmitter Holding Register Empty
+ ACE_ELSI equ 00000100b ; Receiver Line Status
+ ACE_EDSSI equ 00001000b ; Modem Status
+
+ACE_FCR equ 2 ;FIFO control register
+ ACE_EFIFO equ 00000001b ; Enable FIFO
+ ACE_CRFIFO equ 00000010b ; Clear receive FIFO queue
+ ACE_CTFIFO equ 00000100b ; Clear transmit FIFO queue
+ ACE_TRIG01 equ 00000000b ; Trigger receive int on every char
+ ACE_TRIG04 equ 01000000b ; Trigger receive int on every 4th char
+ ACE_TRIG08 equ 10000000b ; Trigger receive int on every 8th char
+ ACE_TRIG14 equ 11000000b ; Trigger receive int on every 14th char
+
+ACE_IIDR equ 2 ;Interrupt Identification
+ ACE_IIP equ 00000001b ; Inverted Interrupt Pending (0=int)
+ ACE_IID equ 00000110b ; Interrupt ID
+ ACE_MSI equ 00000000b ; Modem Status
+ ACE_THREI equ 00000010b ; Transmitter Holding Register Empty
+ ACE_RDAI equ 00000100b ; Received Data Available
+ ACE_RLSI equ 00000110b ; Receiver Line Status
+ ACE_FIFO_E1 equ 01000000b ;set, if FIFO enabled on 16550A
+ ACE_FIFO_E2 equ 10000000b ;set, if FIFO enabled on 16550 or 16550A
+
+ACE_LCR equ 3 ;Line Control
+ ACE_WLS equ 00000011b ; Word Length Select Bits
+ ACE_WLS0 equ 00000001b ; Word Length Select Bit 0
+ ACE_WLS1 equ 00000010b ; Word Length Select Bit 1
+ ACE_5BW equ 00000000b ; 5 Bit Words
+ ACE_6BW equ 00000001b ; 6 Bit Words
+ ACE_7BW equ 00000010b ; 7 Bit Words
+ ACE_8BW equ 00000011b ; 8 Bit Words
+ ACE_STB equ 00000100b ; Stop Bits
+ ACE_1SB equ 00000000b ; 1 Stop Bits (1.5 for 5 bit words)
+ ACE_2SB equ 00000100b ; 2 Stop Bits
+ ACE_PEN equ 00001000b ; Parity Enable
+ ACE_PSB equ 00110000b ; Parity select bits
+ ACE_EPS equ 00010000b ; Even Parity Select
+ ACE_SP equ 00100000b ; Stick Parity
+ ACE_SB equ 01000000b ; Set Break
+ ACE_DLAB equ 10000000b ; Divisor Latch Access Bit
+
+ACE_MCR equ 4 ;Modem Control
+ ACE_DTR equ 00000001b ; Data Terminal ready
+ ACE_RTS equ 00000010b ; Request To Send
+ ACE_OUT1 equ 00000100b ; Output Line 1
+ ACE_OUT2 equ 00001000b ; Output Line 2
+ ACE_LOOP equ 00010000b ; Loopback
+
+ACE_LSR equ 5 ;Line Status
+ ACE_DR equ 00000001b ; Data Ready
+ ACE_OR equ 00000010b ; Overrun Error
+ ACE_PE equ 00000100b ; Parity Error
+ ACE_FE equ 00001000b ; Framing Error
+ ACE_BI equ 00010000b ; Break Interrupt
+ ACE_THRE equ 00100000b ; Transmitter Holding Register Empty
+ ACE_TSRE equ 01000000b ; Transmitter Shift Register Empty
+
+ACE_MSR equ 6 ;Modem Status
+ ACE_DCTS equ 00000001b ; Delta Clear to Send
+ ACE_DDSR equ 00000010b ; Delta Data Set Ready
+ ACE_TERI equ 00000100b ; Trailing Edge Ring Indicator
+ ACE_DRLSD equ 00001000b ; Delta Receive Line Signal Detect
+ ACE_CTS equ 00010000b ; Clear To Send
+ ACE_DSR equ 00100000b ; Data Set ready
+ ACE_RI equ 01000000b ; Ring Indicator
+ ACE_RLSD equ 10000000b ; Receive Line Signal Detect
+
+ACE_DLL equ 0 ;LSB Baud Rate Divisor
+
+ACE_DLM equ 1 ;MSB Baud Rate Divisor
diff --git a/private/mvdm/wow16/drivers/comm/makefile b/private/mvdm/wow16/drivers/comm/makefile
new file mode 100644
index 000000000..2b5303d44
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/makefile
@@ -0,0 +1,127 @@
+# comm16 makefile
+#
+# Copyright (c) 1992, Microsoft Corporation
+#
+# History:
+# 27-Mar-1992 Nandurir
+# Created.
+# 6-Feb-1994 LeeHart
+# Modified for version resources & CV Symbols
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) -fo $@ $*.rc
+
+
+all: comm.drv comm.map comm.sym comm.lrf
+ binplace comm.drv comm.map comm.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+
+ccom.obj ccom.lst: ccom.asm ibmcom.inc comdev.inc
+
+ibmsetup.obj ibmsetup.lst: ibmsetup.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmcom.obj: $*.asm $*.inc comdev.inc ins8250.inc
+
+ibmint.obj: $*.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmlpt.obj: $*.asm ibmcom.inc comdev.inc
+
+commmsg.obj: $*.asm
+
+comm.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+comm.lrf: makefile
+ echo ccom+ibmsetup+ibmcom+ibmint+ibmlpt+commmsg >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+comm.drv: ccom.obj ibmsetup.obj ibmcom.obj ibmint.obj ibmlpt.obj commmsg.obj \
+ $*.def $*.res $*.lrf
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist *.drv del *.drv
+ ren $*.exe $@
+
+comm.sym: $*.map
+ mapsym $*
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/display/config.asm b/private/mvdm/wow16/drivers/display/config.asm
new file mode 100644
index 000000000..d8b7c3a2a
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/config.asm
@@ -0,0 +1,64 @@
+;***************************************************************************
+; *
+; Copyright (C) 1985-1989 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+ title Hardware Dependent Parameters
+ %out config
+ page ,132
+
+
+RGB macro R, G, B
+ db R,G,B,0
+ endm
+
+
+
+OEM segment public
+
+; Machine dependent parameters
+
+ dw 14 ;Height of vertical thumb
+ dw 18 ;Width of horizontal thumb
+ dw 2 ;Icon horiz compression factor
+ dw 2 ;Icon vert compression factor
+ dw 1 ;Cursor horz compression factor
+ dw 1 ;Cursor vert compression factor
+ dw 0 ;Kanji window height
+ dw 1 ;cxBorder (thickness of vertical lines)
+ dw 1 ;cyBorder (thickness of horizontal lines)
+
+; Default system color values
+
+ RGB 129,129,129 ;clrScrollbar
+ RGB 192,192,192 ;clrDesktop
+ RGB 000,000,128 ;clrActiveCaption
+ RGB 255,255,255 ;clrInactiveCaption
+ RGB 255,255,255 ;clrMenu
+ RGB 255,255,255 ;clrWindow
+ RGB 000,000,000 ;clrWindowFrame
+ RGB 000,000,000 ;clrMenuText
+ RGB 000,000,000 ;clrWindowText
+ RGB 255,255,255 ;clrCaptionText
+ RGB 128,128,128 ;clrActiveBorder
+ RGB 255,255,255 ;clrInactiveBorder
+ RGB 255,255,255 ;clrAppWorkspace
+ RGB 000,000,128 ;clrHiliteBk
+ RGB 255,255,255 ;clrHiliteText
+ RGB 255,255,255 ;clrBtnFace
+ RGB 128,128,128 ;clrBtnShadow
+ RGB 128,128,128 ;clrGrayText
+ RGB 000,000,000 ;clrBtnText
+
+; dw 0 ;Unused words
+; dw 0
+; dw 0
+; dw 0
+; dw 0
+; dw 0
+ dw 0
+ dw 0
+
+OEM ends
+end
diff --git a/private/mvdm/wow16/drivers/display/display.asm b/private/mvdm/wow16/drivers/display/display.asm
new file mode 100644
index 000000000..5573f7eac
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.asm
@@ -0,0 +1,88 @@
+ TITLE DISPLAY.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; DISPLAY.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 13-MAY-1992 Matt Felton (mattfe)
+; Created.
+;
+; WinProj 3.0 does the following API:-
+; GetModuleFileName(GetModuleHandle("DISPLAY"), buffer, sizeof(buffer));
+; In WOW we do not require a display driver becuase we always call GDI32 to
+; perform screen IO.
+
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+DISPLAY_Identifier db 'DISPLAY'
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+cProc DISPLAY,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+ cBegin <nogen>
+ mov ax,1 ;always indicate success
+ ret
+ cEnd <nogen>
+
+assumes DS,NOTHING
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+cProc Disable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+ parmD lp_device
+
+cBegin
+ mov ax,-1
+cEnd
+
+cProc Enable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+ parmD lp_device ;Physical device or GDIinfo destination
+ parmW style ;Style, Enable Device, or Inquire Info
+ parmD lp_device_type ;Device type (i.e FX80, HP7470, ...)
+ parmD lp_output_file ;DOS output file name (if applicable)
+ parmD lp_stuff ;Device specific information
+
+cBegin
+ mov ax,0
+cEnd
+
+assumes DS,DATA
+
+assumes DS,NOTHING
+
+sEnd CODE
+
+end DISPLAY
diff --git a/private/mvdm/wow16/drivers/display/display.def b/private/mvdm/wow16/drivers/display/display.def
new file mode 100644
index 000000000..175fbfa33
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.def
@@ -0,0 +1,17 @@
+LIBRARY DISPLAY
+
+DESCRIPTION 'Windows Display Driver'
+
+EXETYPE WINDOWS
+STUB '..\..\BIN\WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE
+
+DATA PRELOAD MOVEABLE SINGLE
+
+HEAPSIZE 0
+
+EXPORTS
+ WEP
+ Disable @4
+ Enable @5
diff --git a/private/mvdm/wow16/drivers/display/display.rc b/private/mvdm/wow16/drivers/display/display.rc
new file mode 100644
index 000000000..585d45cce
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.rc
@@ -0,0 +1,8 @@
+/* Resource file for EGA (4-plane) display driver */
+
+#define OEMRESOURCE
+#define WIN31
+#include "windows.h"
+#include "display.rcv"
+
+1 oembin PRELOAD config.bin
diff --git a/private/mvdm/wow16/drivers/display/display.rcv b/private/mvdm/wow16/drivers/display/display.rcv
new file mode 100644
index 000000000..596a32d4d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* DISPLAY.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_DISPLAY
+#define VER_FILEDESCRIPTION_STR "WOW Display Driver Module"
+#define VER_INTERNALNAME_STR "VGA"
+#define VER_ORIGINALFILENAME_STR "VGA.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/display/makefile b/private/mvdm/wow16/drivers/display/makefile
new file mode 100644
index 000000000..673e1a1ad
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/makefile
@@ -0,0 +1,121 @@
+# display16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 13-May-1992 Matt Felton (MattFe)
+#
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+all: display.exe display.map display.sym
+ copy display.exe vga.drv
+ copy display.sym vga.sym
+ copy display.map vga.map
+ binplace vga.drv vga.map vga.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+display.obj: $*.asm ..\..\..\inc\wow.inc
+ masm -l $(AOBJ) $*;
+
+config.obj: $*.asm
+ masm -l $(AOBJ) $*;
+
+config.exe: $*.obj
+ link16 $*;
+
+config.bin: $*.exe
+ exe2bin $*.exe
+
+display.res: $*.rc config.bin $*.rcv ..\..\inc\common.ver
+
+display.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrt.lib /nod>>$@
+ echo $*;>>$@
+
+display.exe display.map: display.obj display.lrf display.def display.res
+ link16 @display.lrf;
+ rc16 -t display.res display.exe
+
+display.sym: $*.map
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/keyboard/kbd.def b/private/mvdm/wow16/drivers/keyboard/kbd.def
new file mode 100644
index 000000000..c5961214d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/kbd.def
@@ -0,0 +1,118 @@
+LIBRARY KEYBOARD
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; (except for SetSpeed)
+; ============================================================
+
+; Copyright (C) 1989 by Microsoft Corporation
+
+DESCRIPTION 'KEYBOARD (Enhanced keyboard):'
+
+EXETYPE WINDOWS
+
+; (use LINK4 default stub, not WINSTUB)
+
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; ============================================================
+
+SEGMENTS
+; Initialization once-only code
+ _INIT PRELOAD FIXED DISCARDABLE
+
+; Translation tables
+ _TABS LOADONCALL FIXED DISCARDABLE
+
+; NewTable()'s and GetCSAlias()'s segment
+ _NEWTAB PRELOAD FIXED DISCARDABLE
+
+; OemKeyScan's segment
+ _OEMSC LOADONCALL DISCARDABLE
+
+; VkKeyScan's segment
+ _VKKSC LOADONCALL DISCARDABLE
+
+; SetSpeed's segment
+ _SETSP PRELOAD FIXED DISCARDABLE
+
+; GetKeyboardType's segment
+ _GETTYPE LOADONCALL DISCARDABLE
+
+; MapVirtualKey's segment
+ _MAPVK LOADONCALL DISCARDABLE
+
+; GetKeyNameText's segment
+ _GETNAME LOADONCALL DISCARDABLE
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; (except for SetSpeed)
+; ============================================================
+
+EXPORTS
+ Inquire @1 ;Internal
+ Enable @2 ;Internal
+ Disable @3 ;Internal
+ ToAscii @4
+ AnsiToOem @5
+ OemToAnsi @6
+
+; Special call for setting keyboard repeat speed on AT-type keyboards
+; (omit in Olivetti M24 and NOKIA drivers, since they're not for AT keyboards)
+ SetSpeed @7 ;Internal
+
+; Special call for OS/2 Compatibility box
+; (omit in Olivetti M24 drivers)
+ ScreenSwitchEnable @100 ;Internal
+
+; Routines for initializing keyboard tables
+
+ GetTableSeg @126 ;Internal
+ NewTable @127 ;Internal
+
+; Special call for WIN386 WINOLDAP
+; (omit in Olivetti M24 drivers, since they're 8086 only)
+ OEMKeyScan @128
+
+; Special ASCII to virtual keycode routine
+ VkKeyScan @129
+
+; Return keyboard type number, etc.
+ GetKeyboardType @130
+
+; Return translations VK-> scancode, scancode-> VK, VK-> ASCII.
+ MapVirtualKey @131
+
+; Return code page of current Oem/Ansi translation tables.
+ GetKBCodePage @132
+
+; Get name string for key
+ GetKeyNameText @133
+
+; Translate routines
+ AnsiToOemBuff @134
+ OemToAnsiBuff @135
+
+; Enable SysReq trap
+ EnableKBSysReq @136 ;Internal
+
+; codeview support
+ GetBIOSKeyProc @137
+
+ WEP ;Internal
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; ============================================================
+
+
+IMPORTS
+ CVWBREAK = KERNEL.205
diff --git a/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm b/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm
new file mode 100644
index 000000000..e736ccfa6
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm
@@ -0,0 +1,301 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; KBDLOCAL.ASM
+;
+; Win16 KEYBOARD APIS that are 'internal'
+; We make these apis a 'nop'. Relevant code has been copied from WIN31.
+; The intention here is to maintain the stack. Any arguments to the apis
+; are popped and that is it.
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE KBDLOCAL.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowkbd.inc
+ include cmacros.inc
+ include windefs.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+; Double byte range values for the Far East.
+; The values defined here are for the Rest Of the World.
+; These values are for the inquireData (KBINFO) structure defined below.
+; ('KeyInfo' in the Kernel, pState in USER)
+;
+BeginRange1 equ 255
+EndRange1 equ 254
+BeginRange2 equ 255
+EndRange2 equ 254
+
+sBegin DATA
+
+globalD bios_proc, 0
+globalD nmi_vector, 0
+;externD nmi_vector
+
+
+public fSysReq
+fSysReq db 0 ; Enables CTRL-ALT-SysReq if NZ
+
+; Keyboard information block (copied to 'KeyInfo' in the kernel)
+; this is a KBINFO data structure.. defined in KERNEL.INC, USER.INC, USER.H
+; and WINDEFS.INC.
+;
+; As of 3.0, build 1.30, KBINFO includes the number of function keys
+; As of 3.0, build 1.59, the number of bytes in the state block is
+; fixed at 4 MAX, for compatibility with Excel 2.1c!!!
+;
+ PUBLIC inquireData
+ PUBLIC iqdNumFunc
+inquireData LABEL BYTE
+ DB BeginRange1
+ DB EndRange1
+ DB BeginRange2
+ DB EndRange2
+ DW 4 ; #bytes of state info for ToAscii()
+iqdNumFunc label word
+ dw 10 ; number of function keys
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+assumes DS,DATA
+
+;***************************************************************************
+;
+; Inquire( pKBINFO ) - copies information about the keyboard hardware into
+; the area pointer to by the long pointer argument. Returns a count of the
+; number of bytes copied.
+;
+; The Windows kernel calls this to copy information to its 'KeyInfo' data
+; structure.
+;
+;***************************************************************************
+cProc Inquire,<PUBLIC,FAR>,<si,di>
+ parmD pKBINFO
+
+cBegin Inquire
+ ; .. now pass data to Windows ..
+ les di,pKBINFO ; Get far pointer of destination area
+ mov si, OFFSET inquireData ; Get source
+ mov ax,size KBINFO ; Get number of bytes to move
+ mov cx,ax ; (Return byte count in AX)
+ rep movsb ; Move the bytes
+
+cEnd Inquire
+
+;---------------------------------------------------------------------
+;
+;---- ScreenSwitchEnable( fEnable ) ----------------------------------
+;
+; This function is called by the display driver to inform the keyboard
+; driver that the display driver is in a critical section and to ignore
+; all OS/2 screen switches until the display driver leaves its
+; critical section. The fEnable parameter is set to 0 to disable
+; screen switches, and a NONZERO value to re-enable them. At startup,
+; screen switches are enabled.
+;---------------------------------------------------------------------
+;
+
+cProc ScreenSwitchEnable,<PUBLIC,FAR>
+parmW fEnable
+
+cBegin ScreenSwitchEnable
+
+ mov ax,fEnable ; get WORD parameter
+ or al,ah ; stuff any NZ bits into AL
+;;; mov fSwitchEnable,al ; save BYTE.
+
+cEnd ScreenSwitchEnable
+
+;---------------------------------------------------------------------
+;
+;---- EnableKBSysReq( fSys ) ----------------------------------
+;
+; This function enables and shuttles off NMI interrupt simulation
+; (trap to debugger) when CTRL-ALT-SysReq is pressed.
+; CVWBreak overides int 2.
+; fSysParm = 01 enable int 2
+; = 02 disable int 2
+; = 04 enable CVWBreak
+; = 08 disable CVWBreak
+;
+;---------------------------------------------------------------------
+;
+cProc EnableKBSysReq,<PUBLIC,FAR>
+parmW fSysParm
+
+cBegin EnableKBSysReq
+
+ mov ax, fSysParm ; get WORD parameter
+
+ test al,01 ; turn on int 2?
+ jz @F
+ or fSysReq,01 ; yes, turn it on!
+@@: test al,02 ; turn off int 2?
+ jz @F
+ and fSysReq,NOT 01 ; yes, turn it off!
+
+@@: test al,04 ; turn on CVWBreak?
+ jz @F
+ or fSysReq,02 ; yes, turn it on!
+@@: test al,08 ; turn off CVWBreak?
+ jz @F
+ and fSysReq,NOT 02 ; yes, turn it off!
+@@:
+ xor ah,ah
+ mov al,fSysReq
+
+ifdef NEWNMI
+ push ax ; save return value
+ call short GetNmi ; save NMI
+ pop ax ; restore ..
+endif
+
+cEnd EnableKBSysReq
+
+
+; save NMI vector. Called above in EnableKBSysReq() and in Enable().
+
+ifdef NEWNMI
+GetNmi proc near
+ mov ax,3502h
+ int 21h
+ mov word ptr ds:[nmi_vector][0],bx
+ mov word ptr ds:[nmi_vector][2],es
+ ret
+GetNmi endp
+endif
+
+;***************************************************************************
+;
+; Enable( eventProc ) - enable hardware keyboard interrupts, with the passed
+; procedure address being the target of all keyboard events.
+;
+; lpKeyState is a long pointer to the Windows 256 byte keystate table
+;
+;***************************************************************************
+cProc Enable,<PUBLIC,FAR>,<si,di>
+ parmD eventProc
+ parmD lpKeyState
+cBegin Enable
+ sub ax, ax
+cEnd Enable
+
+;***************************************************************************
+; Disable( eventProc ) - disable hardware keyboard interrupts, restoring
+; the previous IBM BIOS keyboard interrupt handler.
+;
+;***************************************************************************
+cProc Disable,<PUBLIC,FAR>,<si,di>
+
+cBegin Disable
+
+ sub ax,ax
+
+cEnd Disable
+
+; ** GetTableSeg() ***************************************
+;
+; This finds the paragraph of the TABS segment and stores
+; it in TableSeg.
+;
+; Calling this will force the segment to be loaded.
+;
+; This segment isn't written to.
+;
+; REMEMBER that AX is TRASHED !!
+
+
+cProc GetTableSeg,<PUBLIC,FAR>,<si,di>
+cBegin GetTableSeg
+
+;;; mov ax,cs
+;;; mov TableSeg,ax
+
+cEnd GetTableSeg
+
+;***************************************************************************
+;
+; NewTable()
+;
+; Change keyboard tables, if a keyboard table DLL is defined in
+; SYSTEM.INI and the function GetKbdTable() exists and returns
+; successfully.
+;
+; This function is passed no parameters by the caller -- it obtains
+; the following from SYSTEM.INI:
+;
+; [keyboard]
+; TYPE = 4 ; 1..6. 4 is enhanced kbd.
+; SUBTYPE = 0 ; 0 for all but Olivetti
+; ; 8086 systems & AT&T 6300+
+; KEYBOARD.DLL = kbdus.dll ; name of DLL file
+; OEMANSI.BIN = XLATNO.BIN ; oem/ansi tables file
+;
+; The module name of the DLL is expected to be the root of the DLL's
+; file name. In any event, the module name must be different for
+; each keyboard-table DLL!
+;
+;***************************************************************************
+
+cProc NewTable,<PUBLIC,FAR>,<si,di>
+ ; LOCAL variables on stack:
+
+cBegin NewTable
+ sub ax,ax
+cEnd NewTable
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; SetSpeed.asm
+;
+;
+; Sets 'typematic' speed of AT-type keyboards (type code 3 or 4 in this
+; driver).
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+cProc SetSpeed,<FAR,PASCAL,PUBLIC>
+ parmW rate_of_speed
+cBegin
+
+SS_error_return:
+ mov ax,-1 ; error return
+
+SS_end:
+cEnd
+
+
+cProc GetBIOSKeyProc, <FAR, PUBLIC>
+cBegin
+ mov ax, word ptr [bios_proc][0]
+ mov dx, word ptr [bios_proc][2]
+cEnd
+
+sEnd CODE
+
+
+end
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.asm b/private/mvdm/wow16/drivers/keyboard/keyboard.asm
new file mode 100644
index 000000000..e234209b9
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.asm
@@ -0,0 +1,155 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; KBD.ASM
+; Win16 KEYBOARD thunks
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE KEYBOARD.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowkbd.inc
+ include cmacros.inc
+ include windefs.inc
+ include vdmtib.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows
+KEYBOARD_Identifier db 'KEYBOARD16 Data Segment'
+externD bios_proc
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+; Hung App Support
+; If USER32 is unable to terminate an app via End Task then it calls
+; WOW32 to kill the app. We do this by generating a keyboard h/w
+; interrupt 9. Since in WOW all keyboard input comes via USER32 the
+; keyboard h/w interrupt is unused for anything else so we can reuse
+; this interrupt.
+
+
+cProc KEYBOARD16,<PUBLIC,FAR>
+cBegin
+ mov ax,3500h or 09h
+ int 21h ; vector is in ES:BX
+ mov word ptr [bios_proc][0], bx
+ mov word ptr [bios_proc][2], es
+
+; Setup keyboard interrupt vector to point to our interrupt routine
+ mov ax,2500h or 09h
+ mov dx,OFFSET keybd_int
+ push ds ; save DS
+ push cs
+ pop ds ; set DS = CS
+ int 21h ; set the vector
+ pop ds ; restore DS
+ mov ax,1
+cEnd
+
+
+INTA0 equ 20h ;X'20' 8259 Interrupt Control Port
+EOI equ 20h ;X'20' 8259 End-of-Interrupt ack
+
+public keybd_int
+keybd_int PROC FAR
+ push ax
+ push bx
+ push es
+
+ mov al,EOI ; Send Non-Specific EOI
+ out INTA0,al
+
+;
+; Now we test the bit in low memory that is set by wow32 to see if this
+; is really a keyboard int forced in by the hung app support.
+;
+ mov ax, 40h ;use bios data selector
+ mov es, ax
+ mov bx, FIXED_NTVDMSTATE_LINEAR - 400h
+
+ .386 ;make it assemble
+.errnz VDM_WOWHUNGAPP AND 0ff00ffffh ;make sure it's the third byte
+ test byte ptr es:[bx+2], VDM_WOWHUNGAPP SHR 16
+
+ jnz short hungapp_exit ;jump if this is really a hung app
+
+ pop es
+ pop bx
+ pop ax
+ iret
+
+hungapp_exit:
+ and byte ptr es:[bx+2], 255 - (VDM_WOWHUNGAPP SHR 16) ; turn it off
+ pop es
+ pop bx
+ pop ax
+ .286p
+
+ mov ax,4CFFH ; They said OK to Nuke app.
+ int 21h
+keybd_int ENDP
+
+
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+
+assumes DS,NOTHING
+
+;;; KbdThunk INQUIRE ;Internal LOCALAPI
+;;; KbdThunk ENABLE ;Internal
+;;; KbdThunk DISABLE ;Internal
+ KbdThunk TOASCII
+ KbdThunk ANSITOOEM
+ KbdThunk OEMTOANSI
+;;; KbdThunk SETSPEED ;Internal
+;;; KbdThunk SCREENSWITCHENABLE ;Internal
+;;; KbdThunk GETTABLESEG ;Internal
+;;; KbdThunk NEWTABLE ;Internal
+ KbdThunk OEMKEYSCAN
+ KbdThunk VKKEYSCAN
+ KbdThunk GETKEYBOARDTYPE
+ KbdThunk MAPVIRTUALKEY
+ KbdThunk GETKBCODEPAGE
+ KbdThunk GETKEYNAMETEXT
+ KbdThunk ANSITOOEMBUFF
+ KbdThunk OEMTOANSIBUFF
+;;; KbdThunk ENABLEKBSYSREQ ;Internal LOCALAPI
+;;; KbdThunk GETBIOSKEYPROC ; in kbdlocal.asm
+
+
+
+sEnd CODE
+
+end KEYBOARD16
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.def b/private/mvdm/wow16/drivers/keyboard/keyboard.def
new file mode 100644
index 000000000..4bbe239c7
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.def
@@ -0,0 +1,30 @@
+LIBRARY KEYBOARD
+
+DESCRIPTION 'WOW REPLACEMENT KEYBOARD (Enhanced keyboard)'
+EXETYPE WINDOWS
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+HEAPSIZE 0
+
+EXPORTS
+ WEP
+ INQUIRE @1 ;Internal
+ ENABLE @2 ;Internal
+ DISABLE @3 ;Internal
+ TOASCII @4
+ ANSITOOEM @5
+ OEMTOANSI @6
+ SETSPEED @7 ;Internal
+ SCREENSWITCHENABLE @100 ;Internal
+ GETTABLESEG @126 ;Internal
+ NEWTABLE @127 ;Internal
+ OEMKEYSCAN @128
+ VKKEYSCAN @129
+ GETKEYBOARDTYPE @130
+ MAPVIRTUALKEY @131
+ GETKBCODEPAGE @132
+ GETKEYNAMETEXT @133
+ ANSITOOEMBUFF @134
+ OEMTOANSIBUFF @135
+ ENABLEKBSYSREQ @136 ;Internal
+ GETBIOSKEYPROC @137
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.rc b/private/mvdm/wow16/drivers/keyboard/keyboard.rc
new file mode 100644
index 000000000..abd869a70
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* KEYBOARD.RC */
+/********************************************************************/
+#include "keyboard.rcv"
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.rcv b/private/mvdm/wow16/drivers/keyboard/keyboard.rcv
new file mode 100644
index 000000000..58989318c
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* KEYBOARD.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_KEYBOARD
+#define VER_FILEDESCRIPTION_STR "WOW Keyboard Driver Module"
+#define VER_INTERNALNAME_STR "KEYBOARD"
+#define VER_ORIGINALFILENAME_STR "KEYBOARD.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/keyboard/makefile b/private/mvdm/wow16/drivers/keyboard/makefile
new file mode 100644
index 000000000..11ecfe472
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/makefile
@@ -0,0 +1,114 @@
+# keyboard16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\libw.lib ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) $*.rc -fo $@
+
+all: keyboard.drv keyboard.map keyboard.sym
+ binplace keyboard.drv keyboard.map keyboard.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+keyboard.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowkbd.inc
+
+kbdlocal.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowkbd.inc
+
+keyboard.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+keyboard.lrf: makefile
+ echo $*.obj kbdlocal.obj >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+keyboard.drv: $*.obj kbdlocal.obj $*.def $*.res $*.lrf
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist *.drv del *.drv
+ ren $*.exe $@
+
+keyboard.sym: $*.map
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/mouse/makefile b/private/mvdm/wow16/drivers/mouse/makefile
new file mode 100644
index 000000000..20e1807c5
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/makefile
@@ -0,0 +1,110 @@
+# mouse16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 30-Sept-1992 Chandan Chauhan (ChandanC)
+#
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\libw.lib ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) $*.rc -fo $@
+
+all: mouse.exe mouse.map mouse.sym
+ copy mouse.exe mouse.drv
+ binplace mouse.drv mouse.map mouse.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.drv del *.drv
+ if exist *.lst del *.lst
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+mouse.obj: $*.asm ..\..\..\inc\wow.inc
+ masm -l $(AOBJ) $*;
+
+mouse.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /nod>>$@
+ echo $*;>>$@
+
+mouse.res: mouse.rc mouse.rcv ..\..\inc\common.ver
+
+mouse.exe mouse.map: mouse.obj mouse.lrf mouse.def mouse.res
+ link16 @mouse.lrf;
+ rc16 -t mouse.res mouse.exe
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.asm b/private/mvdm/wow16/drivers/mouse/mouse.asm
new file mode 100644
index 000000000..82d26ffd0
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.asm
@@ -0,0 +1,224 @@
+ TITLE MOUSE.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; MOUSE.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 30-Sept-1992 Chandan Chauhan (ChandanC)
+; Created.
+;
+; Freehand and ??? need mouse driver.
+;
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+mouse_Identifier db 'mouse'
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+
+
+cProc MOUSE,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+ cBegin <nogen>
+ mov ax,1 ;always indicate success
+ ret
+ cEnd <nogen>
+
+
+
+;--------------------------Exported-Routine-----------------------------;
+; int Inquire(lp_mouse_info);
+;
+; Information regarding the mouse is returned to the caller.
+;
+; Entry:
+; None
+; Returns:
+; AX = # bytes returned in lp_mouse_info
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Inquire,<FAR,PUBLIC,WIN,PASCAL>,<di>
+
+ parmD lp_mouse_info
+
+cBegin
+ xor ax, ax
+
+cEnd
+
+
+
+
+;--------------------------Exported-Routine-----------------------------;
+; void Enable(lp_event_proc);
+;
+; Enable hardware mouse interrupts, with the passed procedure address
+; being the target of all mouse events.
+;
+; This routine may be called while already enabled. In this case the
+; passed event procedure should be saved, and all other initialization
+; skipped.
+;
+; Entry:
+; None
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Enable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+
+ parmD new_event_proc
+
+cBegin
+
+; The new event procedure is always saved regardless of the
+; mouse already being enabled. This allows the event proc
+; to be changed as needed.
+
+ xor ax, ax
+
+cEnd
+
+;--------------------------Exported-Routine-----------------------------;
+; void Disable();
+;
+; Disable hardware mouse interrupts, restoring the previous mouse
+; interrupt handler and 8259 interrupt enable mask.
+;
+; This routine may be called while already disabled. In this case the
+; disabling should be ignored.
+;
+; Entry:
+; None
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Disable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+
+cBegin
+ xor ax, ax
+
+cEnd
+
+;--------------------------Exported-Routine-----------------------------;
+; WORD WEP();
+;
+; Generic WEP.
+;
+; Entry:
+; None
+; Returns:
+; AX = 1
+; Error Returns:
+; None
+; Registers Preserved:
+; all
+; Registers Destroyed:
+; none
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc WEP,<FAR,PUBLIC,WIN,PASCAL>
+; parmW stuff
+cBegin nogen
+ mov ax,1
+ ret 2
+cEnd nogen
+
+;--------------------------Exported-Routine-----------------------------;
+; int MouseGetIntVect();
+;
+; The interrupt vector used by the mouse is returned to the caller.
+; If no mouse is found, then -1 is returned.
+;
+; Entry:
+; None
+; Returns:
+; AX = interrupt vector
+; AX = -1 if no mouse was found
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc MouseGetIntVect,<FAR,PUBLIC,WIN,PASCAL>
+
+cBegin
+ mov al, -1
+cEnd
+
+
+
+assumes DS,DATA
+
+assumes DS,NOTHING
+
+sEnd CODE
+
+end MOUSE
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.def b/private/mvdm/wow16/drivers/mouse/mouse.def
new file mode 100644
index 000000000..05dd6a179
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.def
@@ -0,0 +1,16 @@
+LIBRARY MOUSE
+
+DESCRIPTION 'Microsoft Mouse'
+
+EXETYPE WINDOWS
+STUB '..\..\bin\WINSTUB.EXE'
+
+CODE PRELOAD DISCARDABLE
+DATA PRELOAD FIXED SINGLE
+
+EXPORTS
+ Inquire @1
+ Enable @2
+ Disable @3
+ MouseGetIntVect @4
+ WEP
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.rc b/private/mvdm/wow16/drivers/mouse/mouse.rc
new file mode 100644
index 000000000..63c7913b7
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* MOUSE.RC */
+/********************************************************************/
+#include "mouse.rcv"
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.rcv b/private/mvdm/wow16/drivers/mouse/mouse.rcv
new file mode 100644
index 000000000..c18f8290a
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* MOUSE.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_MOUSE
+#define VER_FILEDESCRIPTION_STR "WOW MOUSE Driver Module"
+#define VER_INTERNALNAME_STR "MOUSE"
+#define VER_ORIGINALFILENAME_STR "MOUSE.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/sound/makefile b/private/mvdm/wow16/drivers/sound/makefile
new file mode 100644
index 000000000..71554cdc9
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/makefile
@@ -0,0 +1,109 @@
+# Sound16 makefile
+#
+# Copyright (c) 1992, Microsoft Corporation
+#
+# History:
+# 27-Mar-1992 Nandurir
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+.asm.obj:
+ masm -L $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) -fo $@ $*.rc
+
+all: sound.drv sound.map sound.sym
+ binplace sound.drv sound.map sound.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+sound.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+sound.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowsnd.inc
+ masm $(AOBJ) $*;
+
+sound.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+sound.drv: $*.obj $*.lrf $*.def $*.res
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist $*.drv del $*.drv
+ ren $*.exe $@
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/sound/sound.asm b/private/mvdm/wow16/drivers/sound/sound.asm
new file mode 100644
index 000000000..4ff4f7de6
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.asm
@@ -0,0 +1,88 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; SOUND.ASM
+; Win16 SOUND thunks
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE SOUND.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowsnd.inc
+ include cmacros.inc
+ include windefs.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows
+SOUND_Identifier db 'SOUND16 Data Segment'
+
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+cProc SOUND16,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+
+ cBegin <nogen>
+ mov ax,1
+ ret
+ cEnd <nogen>
+
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+
+assumes DS,NOTHING
+
+ SoundThunk OPENSOUND
+ SoundThunk CLOSESOUND
+ SoundThunk SETVOICEQUEUESIZE
+ SoundThunk SETVOICENOTE
+ SoundThunk SETVOICEACCENT
+ SoundThunk SETVOICEENVELOPE
+ SoundThunk SETSOUNDNOISE
+ SoundThunk SETVOICESOUND
+ SoundThunk STARTSOUND
+ SoundThunk STOPSOUND
+ SoundThunk WAITSOUNDSTATE
+ SoundThunk SYNCALLVOICES
+ SoundThunk COUNTVOICENOTES
+ SoundThunk GETTHRESHOLDEVENT
+ SoundThunk GETTHRESHOLDSTATUS
+ SoundThunk SETVOICETHRESHOLD
+ SoundThunk DOBEEP
+ SoundThunk MYOPENSOUND
+
+
+sEnd CODE
+
+end SOUND16
diff --git a/private/mvdm/wow16/drivers/sound/sound.def b/private/mvdm/wow16/drivers/sound/sound.def
new file mode 100644
index 000000000..fdb91863d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.def
@@ -0,0 +1,27 @@
+LIBRARY SOUND
+
+DESCRIPTION 'WOW REPLACEMENT SOUND DRIVER'
+EXETYPE WINDOWS
+CODE PRELOAD FIXED
+DATA FIXED SINGLE PRELOAD
+
+EXPORTS
+ OPENSOUND @1
+ CLOSESOUND @2
+ SETVOICEQUEUESIZE @3
+ SETVOICENOTE @4
+ SETVOICEACCENT @5
+ SETVOICEENVELOPE @6 NODATA
+ SETSOUNDNOISE @7 NODATA
+ SETVOICESOUND @8
+ STARTSOUND @9
+ STOPSOUND @10
+ WAITSOUNDSTATE @11
+ SYNCALLVOICES @12 NODATA
+ COUNTVOICENOTES @13
+ GETTHRESHOLDEVENT @14
+ GETTHRESHOLDSTATUS @15
+ SETVOICETHRESHOLD @16
+ DOBEEP @17 NODATA ;Internal
+ MYOPENSOUND @18 ;Internal
+ WEP NODATA ;Internal
diff --git a/private/mvdm/wow16/drivers/sound/sound.rc b/private/mvdm/wow16/drivers/sound/sound.rc
new file mode 100644
index 000000000..1d5afb03d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* SOUND.RC */
+/********************************************************************/
+#include "sound.rcv"
diff --git a/private/mvdm/wow16/drivers/sound/sound.rcv b/private/mvdm/wow16/drivers/sound/sound.rcv
new file mode 100644
index 000000000..2a8856150
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* SOUND.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SOUND
+#define VER_FILEDESCRIPTION_STR "WOW SOUND Driver Module"
+#define VER_INTERNALNAME_STR "SOUND"
+#define VER_ORIGINALFILENAME_STR "SOUND.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/gdi/fontres.c b/private/mvdm/wow16/gdi/fontres.c
new file mode 100644
index 000000000..aa6d24d6a
--- /dev/null
+++ b/private/mvdm/wow16/gdi/fontres.c
@@ -0,0 +1,119 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * FONTRES.C
+ * WOW16 user resource services
+ *
+ * History:
+ *
+ * Created 05-Apr-1993 by Craig Jones (v-cjones)
+ *
+ * This file provides support for the Win 3.1 AddFontResource &
+ * RemoveFontResource API's.
+ *
+--*/
+
+#include <windows.h>
+
+int WINAPI WOWAddFontResource (LPCSTR lpszFileName);
+BOOL WINAPI WOWRemoveFontResource (LPCSTR lpszFileName);
+WORD WINAPI WOWCreateDIBPatternBrush(LPVOID lpData, UINT fColor);
+
+
+int WINAPI IAddFontResource (LPCSTR lpszFileName)
+{
+
+ int ret;
+ char sz[128];
+ LPSTR lpsz;
+
+ // if the app passed a handle instead of a file name - get the file name
+ if(HIWORD((DWORD)lpszFileName) == 0) {
+
+ if(GetModuleFileName((HINSTANCE)LOWORD((DWORD)lpszFileName), sz, 128)) {
+ lpsz = sz;
+ }
+ else {
+ lpsz = NULL;
+ ret = 0;
+ }
+ }
+ else {
+ lpsz = (LPSTR)lpszFileName;
+ }
+
+ // we're really calling wg32AddFontResource here
+ if(lpsz) {
+ ret = WOWAddFontResource((LPCSTR)lpsz);
+ }
+
+ // ALDUS PM5 expects AddFontResource to succeed if given the base name of
+ // a font that it previously did a LoadLibrary on. The full path name was
+ // passed to LoadLibrary. So if AddFontResouce failed then find out if
+ // there is a loaded module already. If so then get the full path name
+ // and retry the AddFontResource. - MarkRi 6/93
+ if( !ret && (HIWORD((DWORD)lpszFileName) != 0) ) {
+ HMODULE hmod ;
+
+ hmod = GetModuleHandle( lpszFileName ) ;
+ if( hmod ) {
+ if( GetModuleFileName( (HINSTANCE)hmod, sz, sizeof(sz) ) ) {
+ ret = WOWAddFontResource( (LPCSTR)sz ) ;
+ }
+ }
+ }
+
+ return(ret);
+}
+
+
+
+
+BOOL WINAPI IRemoveFontResource (LPCSTR lpszFileName)
+{
+ BOOL ret;
+ char sz[128];
+ LPSTR lpsz;
+
+ // if the app passed a handle instead of a file name - get the file name
+ if(HIWORD((DWORD)lpszFileName) == 0) {
+
+ if(GetModuleFileName((HINSTANCE)LOWORD((DWORD)lpszFileName), sz, 128)) {
+ lpsz = sz;
+ }
+ else {
+ lpsz = NULL;
+ ret = FALSE;
+ }
+ }
+ else {
+ lpsz = (LPSTR)lpszFileName;
+ }
+
+ // we're really calling wg32RemoveFontResource here
+ if(lpsz) {
+ ret = (BOOL)WOWRemoveFontResource((LPCSTR)lpsz);
+ }
+
+ return(ret);
+}
+
+
+
+WORD WINAPI ICreateDIBPatternBrush (HGLOBAL hMem, UINT fColor)
+{
+ LPVOID lpT;
+ WORD wRet = 0;
+
+ if (lpT = LockResource(hMem)) {
+ wRet = WOWCreateDIBPatternBrush(lpT, fColor);
+ UnlockResource(hMem);
+ }
+
+ return wRet;
+}
+
+
diff --git a/private/mvdm/wow16/gdi/gdi.api b/private/mvdm/wow16/gdi/gdi.api
new file mode 100644
index 000000000..c97b19dfe
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi.api
@@ -0,0 +1,3047 @@
+;===========================================================================
+;
+; For WOW only
+;
+
+;===========================================================================
+;
+; Validation constants
+;
+PS_MAX equ 6
+HS_MAX equ 5
+BS_MAX equ 5
+FW_MAX equ 1000
+OUT_MAX equ 7
+CLIP_MAX equ 2
+QUALITY_MAX equ 2
+DIB_MAX equ 1
+PFILL_MIN equ 1
+PFILL_MAX equ 2
+EFF_MAX equ 1
+OBJ_MIN equ 1
+OBJ_MAX equ 2
+STOCK_MAX equ 16
+RGN_MIN equ 1
+RGN_MAX equ 5
+BK_MIN equ 1
+BK_MAX equ 3 ;SHOULD let TRANSPARENT1 ROP code go through.
+R2_MIN equ 1
+R2_MAX equ 16
+STR_MIN equ 1
+STR_MAX equ 3
+PFILL_MIN equ 1
+PFILL_MAX equ 2
+MM_MIN equ 1
+MM_MAX equ 8
+DIB_MAX equ 1
+PR_MAX equ 4
+RM_MAX equ 2
+DIB_RGB_COLORS equ 0
+CBM_INIT equ 4
+BI_RGB equ 0
+
+TA_VALID equ 0001fh
+GLYPH_VALID equ 00003h
+MAPFLG_VALID_L equ 00001h
+MAPFLG_VALID_H equ 00000h
+CBM_VALID_L equ 00004h
+CBM_VALID_H equ 00000h
+ETO_VALID equ 00007h
+PC_VALID equ 00007h
+
+CCHDEVICENAME equ 32
+
+
+
+;special error codes
+
+SP_ERROR equ -1
+
+
+;============================================================================
+;
+; Special ATM hackery (See ATM HACK comments in dcman1.asm)
+;
+;ExternFP <LoadLibrary> TEMPLY !!!!!!!!!!! ChandanC
+;ExternFP <FreeLibrary> TEMPLY !!!!!!!!!!! ChandanC
+;ExternFP <GetProcAddress> TEMPLY !!!!!!!!!!! ChandanC
+;
+; Macro to set up stubs required for ATM's GDI patching code
+;
+ATM_LPFN macro gdifunc, kernfunc
+IFNDEF WOW
+ db 09ah ; call far instruction
+public gdifunc&kernfunc
+gdifunc&kernfunc:
+ dd kernfunc
+ENDIF
+endm
+
+;
+; Argument types
+;
+IFNDEF WOW
+ExternFP <IsGDIObject>
+ExternFP <IsValidMetaFile>
+ENDIF
+
+P_LPSIZE equ <P_LPPOINT>
+P_LPSIZE0 equ <P_LPPOINT0>
+
+;
+; Generate a GDI object validation macro.
+;
+; If nullok is 1, allow NULL.
+; min & max are the allowed OBJ_* range.
+; except, if specified, is an OBJ_* value within the range to reject.
+;
+_GenHGDI macro name,func
+ P_&name &macro hObj,opts
+ _GenParm <hObj>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&&hObj
+ lcall V&name
+ _gensub name
+ _gensub VGOT
+ ENDIF
+ endif
+ &endm
+
+ P_&name&0 &macro hObj,opts
+ _GenParm <hObj>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&&hObj
+ lcall V&name&0
+ _gensub name
+ _gensub VGOT
+ ENDIF
+ endif
+ &endm
+endm
+
+_GenHGDI <HGDIOBJ>
+_GenHGDI <HPEN>
+_GenHGDI <HBRUSH>
+_GenHGDI <HFONT>
+_GenHGDI <HPALETTE>
+_GenHGDI <HBITMAP>
+_GenHGDI <HRGN>
+
+; HDC variants: HDC - Any kind of DC except a metafile DC
+
+_GenHGDI <HDC>
+
+; Anything including a metafile DC
+
+_GenHGDI <HDCMETA>
+
+P_HDCNOTMEM equ <P_HDCMETA>
+
+; output-only DC - metafiles ok but no ICs allowed
+
+_GenHGDI <HDCNOIC>
+
+; output-only DC - neither metafiles nor ICs allowed
+
+_GenHGDI <HDCNOICNOMETA>
+
+; GetObject(): Pen, brush, font, palette, or bitmap.
+;
+_GenHGDI <HGDIOBJGET>
+
+; UnrealizeObject(): Brush or palette
+;
+_GenHGDI <HGDIOBJUNR>
+
+; SelectObject(): pen, brush, font, bitmap, region (no palette)
+;
+_GenHGDI <HGDIOBJSEL>
+
+; Metafile handle
+;
+P_HMETAFILE macro hmf,opts
+ _GenParm <hmf>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov ax,_P_&hmf
+ lcall VHMETAFILE
+ _gensub VHMETAFILE
+ ENDIF
+ endif
+endm
+
+_GenHGDIX macro name,errtyp,lseg,min,max,except
+local badobj
+local objok
+local trap
+
+IFNDEF WOW
+public V&name&0&lseg
+V&name&0&lseg:
+ or bx,bx
+ jz objok
+
+public V&name&lseg
+V&name&lseg:
+ lcall VGetObjType
+ ifnb <except>
+ cmp ax,except
+ jz badobj
+ endif
+ ife min-max
+ cmp ax,min
+ jne badobj
+ errnz $-objok
+ else
+ cmp ax,min
+ jb badobj
+ cmp ax,max
+ ja badobj
+ endif
+objok:
+ ret
+badobj:
+ mov ax,cx
+ mov bx,ERR_BAD_&errtyp
+ ljmp Inval_Param_
+ENDIF
+endm ; _GenHGDIX
+
+;
+; Macro that gets expanded in each LAYER_EXPAND invocation. Includes common
+; subroutines for parameter validation.
+;
+EXTRA_EXPAND macro lseg
+
+ifdef genHGDIOBJ&lseg
+_GenHGDIX <HGDIOBJ>,GDI_OBJECT,lseg,OBJ_PEN,OBJ_METAFILE ; DeleteObject: any kind of object
+endif
+
+ifdef genHPEN&lseg
+_GenHGDIX <HPEN>,lseg,HPEN,OBJ_PEN,OBJ_PEN
+endif
+
+ifdef genHBRUSH&lseg
+_GenHGDIX <HBRUSH>,HBRUSH,lseg,OBJ_BRUSH,OBJ_BRUSH
+endif
+
+ifdef genHFONT&lseg
+_GenHGDIX <HFONT>,HFONT,lseg,OBJ_FONT,OBJ_FONT
+endif
+
+ifdef genHPALETTE&lseg
+_GenHGDIX <HPALETTE>,HPALETTE,lseg,OBJ_PALETTE,OBJ_PALETTE
+endif
+
+ifdef genHBITMAP&lseg
+_GenHGDIX <HBITMAP>,HBITMAP,lseg,OBJ_BITMAP,OBJ_BITMAP
+endif
+
+ifdef genHRGN&lseg
+_GenHGDIX <HRGN>,HRGN,lseg,OBJ_RGN,OBJ_RGN
+endif
+
+; GetObject(): Pen, brush, font, palette, or bitmap.
+;
+ifdef genHGDIOBJGET&lseg
+_GenHGDIX <HGDIOBJGET>,GDI_OBJECT,lseg,OBJ_PEN,OBJ_BITMAP
+endif
+
+; UnrealizeObject(): Brush or palette
+;
+ifdef genHGDIOBJUNR&lseg
+_GenHGDIX <HGDIOBJUNR>,GDI_OBJECT,lseg,OBJ_BRUSH,OBJ_PALETTE,OBJ_FONT
+endif
+; SelectObject(): pen, brush, font, bitmap, region (no palette)
+;
+ifdef genHGDIOBJSEL&lseg
+_GenHGDIX <HGDIOBJSEL>,GDI_OBJECT,lseg,OBJ_PEN,OBJ_RGN,OBJ_PALETTE
+endif
+
+; HDC variants: HDC - Any kind of DC except a metafile DC
+
+ifdef genHDC&lseg
+_GenHGDIX <HDC>,HDC,lseg,OBJ_DC,OBJ_METADC
+endif
+
+; Anything including a metafile DC
+
+ifdef genHDCMETA&lseg
+_GenHGDIX <HDCMETA>,HDC,lseg,OBJ_DC,OBJ_METAFILE
+endif
+
+; output-only DC - metafiles ok but no ICs allowed
+
+ifdef genHDCNOIC&lseg
+_GenHGDIX <HDCNOIC>,HDC,lseg,OBJ_DC,OBJ_METAFILE,OBJ_IC
+endif
+
+; output-only DC - neither metafiles nor ICs allowed
+
+ifdef genHDCNOICNOMETA&lseg
+_GenHGDIX <HDCNOICNOMETA>,HDC,lseg,OBJ_DC,OBJ_DC
+endif
+
+IFNDEF WOW
+ifdef genVGOT&lseg
+
+public VGetObjType&lseg
+VGetObjType&lseg:
+ mov cx,bx
+ jcxz VGOTbad&lseg
+beg_fault_trap VGOTtrap&lseg
+ mov ax,_DATA
+ mov es,ax
+ mov bx,es:[bx]
+ mov ax,es:[bx].ilObjType
+end_fault_trap
+ and ah,high(not OBJ_FLAGS)
+ errnz low(Stock)
+ ret
+
+VGOTtrap&lseg:
+ fault_fix_stack
+VGOTbad&lseg:
+ xor ax,ax
+ ret
+
+endif ; genVGOT&lseg
+
+
+ifdef genVHMETAFILE&lseg
+
+public VHMETAFILE&lseg
+VHMETAFILE&lseg:
+ push ax
+ push ax
+ call IsValidMetaFile
+ or ax,ax
+ pop ax
+ jz @F
+ ret
+ @@:
+ mov bx,ERR_BAD_HMETAFILE
+ jmp short Inval_Param_&lseg
+
+endif ; genVHMETAFILE&lseg
+ENDIF
+
+endm ; EXTRA_EXPAND
+
+P_ROP equ <P_DWORD>
+P_COLORREF equ <P_DWORD>
+
+_GenLP <P_CLPLOGPALETTE>,<CLP>,1
+_GenLP <P_CLPBITMAP>,<CLP>,1
+_GenLP <P_LPHANDLETABLE0>,<LP0>,2
+
+_GenLP <P_CLPBITMAPINFOHEADER>,<CLP>,1
+
+P_CLPSTRHRSRC equ <P_CLPSTRATOM>
+
+_GenLP <P_CLPDOCINFO>,<CLP>,1
+
+P_CLPFACENAME equ <P_CLPSTR>
+P_CLPFACENAME0 equ <P_CLPSTR0>
+
+P_LPFNABORT0 equ <P_LPFN0>
+P_LPFNMENUM equ <P_LPFN>
+P_LPFNOENUM equ <P_LPFN>
+P_LPFNFENUM equ <P_LPFN>
+P_LPFNLENUM equ <P_LPFN>
+
+P_intN0 equ <P_WORDMBNZ>
+P_DEVCAP equ <P_int>
+
+P_PITCHFAMILY equ <P_BYTE>
+
+P_LPPOINTBUFFER macro p, c, opts
+ _DefParm <p>,4,<opts>
+ _DefParm <c>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&p
+ mov cx,_P_&p+2
+ mov bx,_P_&c
+ shl bx,2
+ errnz VLcbsPOINT-4
+ lcall LP
+ _gensub LP
+ endif
+endm
+
+P_CLPPOINTBUFFER macro lptr, c, opts
+ _DefParm <lptr>,4,<opts>
+ _DefParm <c>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lptr
+ mov cx,_P_&lptr+2
+ mov bx,_P_&c
+ shl bx,2
+ errnz VLcbsPOINT-4
+ lcall CLP
+ _gensub LP
+ endif
+endm
+
+STRUCT <PALETTEENTRY>
+F_BYTE peRed
+F_BYTE peGreen
+F_BYTE peBlue
+F_BFLAGS peFlags, PC_VALID
+ENDSTRUCT
+
+P_LPPALENTRYBUFFER macro c, p, opts
+ _DefParm <c>,2,<opts>
+ _DefParm <p>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&p
+ mov cx,_P_&p+2
+ mov bx,_P_&c
+ shl bx,2
+ errnz VLcbsPALETTEENTRY-4
+ lcall LP
+ _gensub LP
+ endif
+endm
+
+P_CLPPALENTRYBUFFER macro c, lp, opts
+ _DefParm <c>,2,<opts>
+ _DefParm <lp>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,_P_&c
+ shl bx,2
+ errnz VLcbsPALETTEENTRY-4
+ lcall CLP
+ _gensub LP
+ endif
+endm
+;
+; lppt - pointer to array of points: size = sum(lpcpt).
+; lpcpt - pointer to array of counts of points
+; ccpt - number of point counts in *lpcpt.
+;
+P_POLYPOLYPOINTS macro lppt, lpcpt, ccpt, opts
+ P_LPPOINT <lppt>,<opts>
+ P_LPINT <lpcpt>,<opts>
+ P_int <ccpt>,<opts>
+ endm
+
+ifdef WOW
+P_POLYPOLYLARGEPOINTS macro lppt, lpcpt, ccpt, opts
+ P_LPLARGEPOINT <lppt>,<opts>
+ P_LPDWORD <lpcpt>,<opts>
+ P_DWORD <ccpt>,<opts>
+ endm
+endif
+
+P_XY1XY2 macro x1,y1,x2,y2, opts
+ P_int <x1>,<opts>
+ P_int <y1>,<opts>
+ P_int <x2>,<opts>
+ P_int <y2>,<opts>
+ endm
+
+P_LPBUFFERDW macro cb, lp, opts
+ P_DWORD <cb>,<opts>
+ P_LPBYTE <lp>,<opts>
+ endm
+
+P_LPBUFFERDW0 macro cb, lp, opts
+ P_DWORD <cb>,<opts>
+ P_LPBYTE0 <lp>,<opts>
+ endm
+
+P_CLPBUFFERDW macro cb, lp, opts
+ P_DWORD <cb>,<opts>
+ P_CLPBYTE <lp>,<opts>
+ endm
+
+P_LPBUFFERX macro cb, pb, opts
+ P_int <cb>,<opts>
+ P_LPBYTE <pb>,<opts>
+ endm
+
+ValidateHugeLP macro cch, lp, r, null
+ local exit
+
+ifnb <null>
+
+ mov ax,lp
+ or ax,lp+2
+ jz exit
+endif
+
+ push lp+2
+ push lp
+ push cch+2
+ push cch
+ call &r
+ or ax,ax
+ jz exit
+ mov cx, lp+2
+ mov ax, lp
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+exit:
+ endm
+
+;----------------------------------------------------------------------------;
+; This macro is used to validate the buffer length for the two APIs
+; GetCharWidth and GetABCWidths. The 'size' parameter is not a part of the
+; API. It is the size of each entry in the buffer. The number of entries are
+; dictated by the character range passed in.
+
+P_LPRWBUFFER macro chFirst, chLast, lpBuffer, size, opts
+ local exit
+
+ _GenParm <chFirst>,2,<opts>
+ _GenParm <chLast>,2,<opts>
+ _GenParm <lpBuffer>,4,<opts>
+
+ if VLgen
+ _FlsFrame
+
+;; first validate that the character range is not inverted.
+
+ mov ax,_P_&chLast ;;last character in range
+ cmp ax,_P_&chFirst ;;should not be < than first character
+ jae @F ;;range is proper
+
+;; character range is not valid.
+
+ mov bx,ERR_BAD_VALUE ;;invalid parameter error.
+ lcall Inval_Param_
+ jmp exit
+
+@@:
+
+;; the size of the buffer should atleast be (chLast-chFirst+1)*size
+
+ sub ax,_P_&chFirst
+ inc ax ;;no of entries
+ mov bx,size ;;size of each entry
+ mul bx
+ mov bx,ax ;;total size (ignore DX)
+ mov ax,_P_&lpBuffer
+ mov cx,_P_&lpBuffer+2
+ lcall LP
+ _gensub LP
+exit:
+ endif
+ endm
+
+;----------------------------------------------------------------------------;
+P_CLPRECTBITSINFOBUFFER macro cyDst, xSrc, ySrc, nStartScan,nNumScans, lpBits, lpBitsInfo, wUsage, opts
+ P_VALIDATEBITSINFOBUFFER DIB_DIBTODEV, cyDst, xSrc, ySrc, nStartScan, nNumScans, lpBits, lpBitsInfo, wUsage, DIB_PTR_CLP, DIB_PTR_CLP, opts
+ endm
+;----------------------------------------------------------------------------;
+P_CLPBITSINFOBUFFER macro cscan, lpBits, lpBitsInfo, wUsage, opts
+ P_VALIDATEBITSINFOBUFFER DIB_PART_DIB, 0, 0, 0, 0, cscans, lpBits, lpBitsInfo, wUsage, DIB_PTR_CLP, DIB_PTR_CLP, opts
+ endm
+;----------------------------------------------------------------------------;
+P_LPBITSINFOBUFFER macro cScans, lpBits, lpBitsInfo, wUsage, opts
+ P_VALIDATEBITSINFOBUFFER DIB_PART_DIB, 0, 0, 0, 0, cscans, lpBits, lpBitsInfo, wUsage, DIB_PTR_LP, DIB_PTR_LP, opts
+ endm
+
+;----------------------------------------------------------------------------;
+;NOTE: It is assumed that this macro is only called from GetDIBits. The flag
+;DIB_PTR_GETDIBITS is a special one which tells the ValidateDIBHeader routine
+;to ignore the biClrUsed field.
+
+P_LPBITSINFOBUFFER0 macro cScans, lpBits, lpBitsInfo, wUsage, opts
+ P_VALIDATEBITSINFOBUFFER DIB_PART_DIB, 0, 0, 0, 0, cscans, lpBits, lpBitsInfo, wUsage, DIB_PTR_LP0, DIB_PTR_GETDIBITS, opts
+ endm
+
+;----------------------------------------------------------------------------;
+P_CFULLLPBITSINFOBUFFER macro lpBits, lpBitsInfo, wUsage, opts
+ P_VALIDATEBITSINFOBUFFER DIB_FULL_DIB, 0, 0, 0, 0, 0, lpBits, lpBitsInfo, wUsage, DIB_PTR_CLP, DIB_PTR_CLP, opts
+ endm
+
+;----------------------------------------------------------------------------;
+P_GHPACKEDDIB macro hDIB, wUsage, opts
+ local exit
+ local errexit
+
+;; hDIB is a global handle to a apacked DIB.
+
+ _GenParm <hDIB>,2,<opts>
+ _GenParm <wUsage>,2,<opts>
+
+ if VLgen
+
+;; first validate the handle itself.
+ IFNDEF WOW
+ mov ax,_P_&hDIB
+ lcall GHANDLE
+ _gensub GHANDLE
+
+ ENDIF
+;; validate wUsage
+
+ mov ax,_P_&wUsage
+ cmp ax,DIB_MAX
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE
+ lcall Inval_Param_
+ jmp exit
+@@:
+
+ push si
+ push di ;;save
+
+;; validate the header.
+
+ mov dx,_P_&wUsage
+ xor ax,ax
+ mov cx,_P_&hDIB ;;CX:AX has a pointer to the DIB
+ mov di, DIB_VALIDATE_COLOR + DIB_PTR_CLP
+
+ call ValidateDIBHeader
+ or ax,ax
+ jz @f ;;valid header
+ pop di
+ pop si ;;restore
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+ jmp exit
+
+@@:
+
+;; the header has been validated. DI:SI returns the pointer past the end of
+;; the DIB header and the color table. For a packed DIB this is the start of
+;; the bits.
+
+ mov es,_P_&hDIB
+ xor bx,bx ;;es:bx-> header, di:si -> bits
+ mov cx, DIB_FULL_DIB+DIB_PTR_CLP
+
+ call ValidateDIBSize
+ pop di
+ pop si
+ or ax,ax
+ jz exit ;;valid size
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+exit:
+ endif
+ endm
+;----------------------------------------------------------------------------;
+P_CLPBITMAPINFOHEADER macro lpBi, opts
+ local exit
+
+;; lpBi - pointer to bitmap info header which does not have a color table
+
+ _GenParm <lpBi>,4,<opts>
+
+ if VLgen
+
+ push si
+ push di
+ mov ax,word ptr _P_&lpBi
+ mov cx,word ptr _P_&lpBi+2
+ mov di, DIB_NO_COLOR + DIB_PTR_CLP
+
+ call ValidateDIBHeader
+ pop di
+ pop si
+ or ax,ax
+ jz exit
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+exit:
+
+ endif
+ endm
+;----------------------------------------------------------------------------;
+
+P_CLPDIBITMAP0 macro dwUsage, lpInitBits, lpInitInfo, wUsage, opts
+ local validate_dib
+ local no_init
+ local exit
+ local flags_ok
+
+ _DefParm <dwUsage>,4,<opts>
+ _DefParm <lpInitBits>,4,<opts>
+ _DefParm <lpInitInfo>,4,<opts>
+ _DefParm <wUsage>,2,<opts>
+
+ if VLgen
+ _FlsFrame
+
+ifdef DEBUG
+ mov ax,_P_&dwUsage
+ mov cx,_P_&dwUsage+2
+ test ax,not(CBM_VALID_L)
+ jnz @F
+ test cx,not(CBM_VALID_H)
+ jz flags_ok
+@@:
+ mov bx,ERR_BAD_DFLAGS
+ lcall Inval_Param_
+flags_ok:
+
+endif ;DEBUG
+
+;; the rest of the validation depends on the value of dwUsage.
+
+ cmp word ptr _P_&dwUsage+2,0
+ jne no_init
+ mov ax, word ptr _P_&dwUsage
+ cmp ax,CBM_INIT
+ je validate_dib
+
+no_init:
+ mov ax,_P_&lpInitBits
+ mov cx,_P_&lpInitBits+2
+ xor bx,bx
+ lcall CLP0
+ _gensub LP
+
+ mov ax,_P_&lpInitInfo
+ mov cx,_P_&lpInitInfo+2
+ xor bx,bx
+ lcall CLP0
+
+ mov ax,_P_&wUsage
+ cmp ax,DIB_MAX
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE
+ lcall Inval_Param_
+@@:
+ jmp exit
+
+validate_dib:
+
+;; validate the bitmap info header first. Validate the color table size too.
+
+ push si
+ push di
+ mov ax,word ptr _P_&lpInitInfo
+ mov cx,word ptr _P_&lpInitInfo+2
+ mov dx,_P_&wUsage
+ mov di, DIB_VALIDATE_COLOR + DIB_PTR_CLP
+
+ call ValidateDIBHeader
+ or ax,ax
+ jz @f
+ pop di
+ pop si
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+ jmp exit
+@@:
+
+;; now validate the size of the bitsbuffer. Use complete height
+
+ mov si, word ptr _P_&lpInitBits
+ mov di, word ptr _P_&lpInitBits+2
+ les bx,_P_&lpInitInfo
+ mov cx, DIB_FULL_DIB+DIB_PTR_CLP
+
+ call ValidateDIBSize
+ pop di
+ pop si
+ or ax,ax
+ jz exit
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+exit:
+ endif
+ endm
+;----------------------------------------------------------------------------;
+
+P_CLPBITBUFFER0 macro cx, cy, cPlanes, cBitsPixel, lpBits, opts
+ P_int <cx>,<opts>
+ P_int <cy>,<opts>
+ P_int <cPlanes>,<opts>
+ P_int <cBitsPixel>,<opts>
+ P_CLPBYTE0 <lpBits>,<opts>
+ endm
+
+P_CLPETOBUF macro lpsz, cch, lpdx, opts
+ P_CLPBUFFER0 <lpsz>,<cch>,<opts>
+ P_CLPINT0 <lpdx>,<opts>
+ endm
+
+P_TEXTEXTEX macro lpsz, cch, nMaxExt, lpnFit, lpDx, opts
+ P_CLPBUFFER <lpsz>,<cch>,<opts>
+ P_int <nMaxExt>,<opts>
+ P_LPINT0 <lpnFit>,<opts>
+ P_LPINT0 <lpDX>,<opts>
+ endm
+;
+; GDI structures
+;
+_DefSimpleF F_LBCOLOR,4
+_DefSimpleF F_CLPBITS,4
+_DefSimpleF F_DWSIZE,4
+_DefSimpleF F_COMPRESS,4
+_DefSimpleF F_DIBSIZE0,4
+
+_DefSimpleF F_HMF,2
+_DefSimpleF F_VALUE,2
+_DefSimpleF F_WMBZ,2
+_DefSimpleF F_WSIZE,2
+_DefSimpleF F_CONST,2
+_DefSimpleF F_BITCOUNT,2
+_DefSimpleF F_RVALUE,2
+_DefSimpleF F_short,2
+_DefSimpleF F_VERSION,2
+
+_DefSimpleF F_PITCHFAMILY,1
+_DefSimpleF F_BVALUE,1
+_DefSimpleF F_BFLAGS,1
+
+STRUCT <RGBQUAD>
+F_BYTE rgbBlue
+F_BYTE rgbGreen
+F_BYTE rgbRed
+F_BYTE rgbReserved
+ENDSTRUCT
+
+STRUCT <RGBTRIPLE>
+F_BYTE rgbtBlue
+F_BYTE rgbtGreen
+F_BYTE rgbtRed
+ENDSTRUCT
+
+STRUCT <LOGBRUSH>
+F_VALUE lbStyle, BS_MAX
+F_LBCOLOR lbColor
+F_VALUE lbHatch, HS_MAX
+ENDSTRUCT
+
+_GenLP <P_CLPLOGBRUSH>,<CLP>,%VLcbsLOGBRUSH
+_GenLP <P_CLPLOGBRUSH0>,<CLP0>,%VLcbsLOGBRUSH
+_GenLP <P_LPLOGBRUSH>,<LP>,%VLcbsLOGBRUSH
+_GenLP <P_LPLOGBRUSH0>,<LP0>,%VLcbsLOGBRUSH
+
+STRUCT <LOGFONT>
+F_int lfHeight
+F_int lfWidth
+F_int lfEscapement
+F_int lfOrientation
+F_VALUE lfWeight, FW_MAX
+F_BYTE lfItalic
+F_BYTE lfUnderline
+F_BYTE lfStrikeOut
+F_BYTE lfCharSet
+F_BVALUE lfOutPrecision, OUT_MAX
+F_BVALUE lfClipPrecision, CLIP_MAX
+F_BVALUE lfQuality, QUALITY_MAX
+F_PITCHFAMILY lfPitchAndFamily
+F_BYTE lfFaceName ;var-length field
+ENDSTRUCT
+
+_GenLP <P_CLPLOGFONT>,<CLP>,%VLcbsLOGFONT
+_GenLP <P_CLPLOGFONT0>,<CLP0>,%VLcbsLOGFONT
+_GenLP <P_LPLOGFONT>,<LP>,%VLcbsLOGFONT
+_GenLP <P_LPLOGFONT0>,<LP0>,%VLcbsLOGFONT
+
+STRUCT <LOGPEN>
+F_VALUE lopnStyle, PS_MAX
+F_POINT lopnWidth
+F_DWORD lopnColor
+ENDSTRUCT
+
+_GenLP <P_CLPLOGPEN>,<CLP>,%VLcbsLOGPEN
+_GenLP <P_CLPLOGPEN0>,<CLP0>,%VLcbsLOGPEN
+_GenLP <P_LPLOGPEN>,<LP>,%VLcbsLOGPEN
+_GenLP <P_LPLOGPEN0>,<LP0>,%VLcbsLOGPEN
+
+STRUCT <METAFILEPICT>
+F_RVALUE nMapMode, MM_MIN, MM_MAX
+F_int xExt
+F_int yExt
+F_HMF hMF
+ENDSTRUCT
+
+_GenLP <P_CLPMETAFILEPICT>,<CLP>,%VLcbsMETAFILEPICT
+_GenLP <P_CLPMETAFILEPICT0>,<CLP0>,%VLcbsMETAFILEPICT
+_GenLP <P_LPMETAFILEPICT>,<LP>,%VLcbsMETAFILEPICT
+_GenLP <P_LPMETAFILEPICT0>,<LP0>,%VLcbsMETAFILEPICT
+
+STRUCT <TEXTMETRIC> ;currently used only for output
+F_int tmHeight
+F_int tmAscent
+F_int tmDescent
+F_int tmInternalLeading
+F_int tmExternalLeading
+F_int tmAveCharWidth
+F_int tmMaxCharWidth
+F_int tmWeight
+F_BYTE tmItalic
+F_BYTE tmUnderlined
+F_BYTE tmStruckOut
+F_BYTE tmFirstChar
+F_BYTE tmLastChar
+F_BYTE tmDefaultChar
+F_BYTE tmBreakChar
+F_BYTE tmPitchAndFamily
+F_BYTE tmCharSet
+F_int tmOverhang
+F_int tmDigitizedAspectX
+F_int tmDigitizedAspectY
+ENDSTRUCT
+
+_GenLP <P_CLPTEXTMETRIC>,<CLP>,%VLcbsTEXTMETRIC
+_GenLP <P_CLPTEXTMETRIC0>,<CLP0>,%VLcbsTEXTMETRIC
+_GenLP <P_LPTEXTMETRIC>,<LP>,%VLcbsTEXTMETRIC
+_GenLP <P_LPTEXTMETRIC0>,<LP0>,%VLcbsTEXTMETRIC
+
+; OutlineTextMetrics return buffer
+;
+P_LPETM0 macro cch, lpch, opts
+
+ _DefParm <cch>,2,<opts>
+ _DefParm <lpch>,4,<opts>
+
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lpch
+ mov cx,_P_&lpch+2
+ mov bx,_P_&cch
+ lcall LP0
+ _gensub LP
+ endif
+endm
+
+; GetGlyphOutline return buffer.
+;
+
+P_LPGGO0 macro cch, lpch, opts
+
+ _DefParm <cch>,4,<opts>
+ _DefParm <lpch>,4,<opts>
+
+ if VLgen
+ _FlsFrame
+
+;; The buffer should be atleast of the given size.
+
+ ValidateHugeLP _P_&cch, _P_&lpch, IsBadHugeWritePtr, NULL
+
+ endif
+ endm
+
+
+; GetFontData return buffer
+;
+
+P_LPFDATA0 macro lpch, cch, opts
+
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,4,<opts>
+
+ if VLgen
+ _FlsFrame
+
+ ValidateHugeLP _P_&cch, _P_&lpch, IsBadHugeWritePtr, NULL
+
+ endif
+ endm
+
+;---------------------------------------------------------------------------;
+; hugw pointer validation routine.
+
+
+STRUCT <GLYPHMETRICS> ;only used for output
+F_WORD gmBlackBoxX
+F_WORD gmBlackBoxY
+F_POINT gmptGlyphOrigin
+F_short gmCellIncX
+F_short gmCellIncY
+ENDSTRUCT
+
+_GenLP <P_CLPGLYPHMETRICS>,<CLP>,%VLcbsGLYPHMETRICS
+_GenLP <P_CLPGLYPHMETRICS0>,<CLP0>,%VLcbsGLYPHMETRICS
+_GenLP <P_LPGLYPHMETRICS>,<LP>,%VLcbsGLYPHMETRICS
+_GenLP <P_LPGLYPHMETRICS0>,<LP0>,%VLcbsGLYPHMETRICS
+
+STRUCT METARECORD
+F_DWORD rdSize
+F_WORD rdFunction
+F_WORD rdParm ;var. length field
+ENDSTRUCT
+
+_GenLP <P_CLPMETARECORD>,<CLP>,%VLcbsMETARECORD
+_GenLP <P_CLPMETARECORD>,<CLP0>,%VLcbsMETARECORD
+_GenLP <P_LPMETARECORD>,<LP>,%VLcbsMETARECORD
+_GenLP <P_LPMETARECORD>,<LP0>,%VLcbsMETARECORD
+
+;-------------------------------
+; special-case macro definitions
+
+
+STRUCT <BITMAP>
+F_intMBZ bmType
+F_int bmWidth
+F_int bmHeight
+F_int bmWidthBytes
+F_BYTE bmPlanes
+F_BYTE bmBitsPixel
+F_CLPBITS bmBits
+ENDSTRUCT
+
+P_CLPBITMAP macro lp, opts
+ _GenParm <lp>,4,<opts>
+ if VLgen
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,VLcbsBITMAP
+ lcall CLP
+ _gensub LP
+
+ les bx,_P_&lp ; Accept bmBits == NULL
+ mov ax,es:[bx]._F_bmBits
+ mov cx,es:[bx]._F_bmBits+2
+ or ax,cx
+ jz @F
+ xor ax,ax
+ mov al,es:[bx]._F_bmPlanes ;bmPlanes
+ mul word ptr es:[bx]._F_bmHeight
+ mul word ptr es:[bx]._F_bmWidthBytes
+ xchg ax,dx
+ mov ax,es:[bx]._F_bmBits
+ mov bx,dx ;bx = size
+ lcall CLP
+ _gensub LP
+ @@:
+ endif
+endm
+
+STRUCT <BITMAPCOREHEADER>
+F_DWSIZE bcSize
+F_WORD bcWidth
+F_WORD bcHeight
+F_CONST bcPlanes, 1
+F_BITCOUNT bcBitCount
+ENDSTRUCT
+
+STRUCT <BITMAPINFOHEADER>
+F_DWSIZE biSize
+F_WORD biWidthLo
+F_WMBZ biWidthHi
+F_WORD biHeightLo
+F_WMBZ biHeightHi
+F_CONST biPlanes, 1
+F_BITCOUNT biBitCount
+F_COMPRESS biCompression
+F_DIBSIZE0 biSizeImage
+F_DWORD biXPelsPerMeter
+F_DWORD biYPelsPerMeter
+F_DWORD biClrUsed
+F_DWORD biClrImportant
+ENDSTRUCT
+;----------------------------------------------------------------------------;
+P_VALIDATEBITSINFOBUFFER macro fn, yE, xS, yS, nStart, n, lpBits, lpBi, wUse, rBits, rBi, opts
+ local exit
+ local total_clip
+
+;; NOTE: The first 4 parameters are defined only when fn & DIB_RECT_DIB is
+;; TRUE (they are 0 otherwise).
+;; The 5th parameter is undefined if fn & DIB_FULL_DIB is TRUE.
+
+;; yE - yExtent in DIB (only when fn & DIB_RECT_DIB is TRUE)
+;; xS - xStart in DIB (only when fn & DIB_RECT_DIB is TRUE)
+;; yS - yStart in DIB (only when fn & DIB_RECT_DIB is TRUE)
+;; nStart - start DIB scan (only when fn & DIB_RECT_DIB is TRUE)
+;;
+;; n - numScans parameter. If fn & DIB_FULL_DIB is TRUE, n is not defined.
+;; lpBits - pointer to the bits
+;; lpBi - pointer to bitmap info
+;; wUse - the wUsage parameter
+;; rBits - routine to validate length of lpBits buffer
+;; rBi - routine to validate length of lpBi buffer.
+;; opts - optional parameters
+
+ if fn and DIB_RECT_DIB
+ _DefParm <yE>,2,<opts>
+ _DefParm <xS>,2,<opts>
+ _DefParm <yS>,2,<opts>
+ _DefParm <nStart>,2,<opts>
+ endif
+
+ if fn and DIB_PART_DIB
+ _DefParm <n>,2,<opts>
+ endif
+
+ _DefParm <lpBits>,4,<opts>
+ _DefParm <lpBi>,4,<opts>
+ _DefParm <wUsage>,2,<opts>
+
+ if VLgen
+ _FlsFrame
+
+;; validate wUsage
+
+ mov ax,_P_&wUsage
+ cmp ax,DIB_MAX
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE
+ lcall Inval_Param_
+@@:
+
+
+ push si
+ push di
+
+;; validate the bitmap info header first. Validate the color table size too.
+
+ mov ax,word ptr _P_&lpBi
+ mov cx,word ptr _P_&lpBi+2
+ mov dx,_P_&wUsage
+ mov di, DIB_VALIDATE_COLOR
+ or di, rBi
+
+ call ValidateDIBHeader
+ or ax,ax
+ jz @f
+ pop di
+ pop si
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+ jmp exit
+@@:
+
+;; now validate the size of the bitsbuffer.
+
+ mov si, word ptr _P_&lpBits
+ mov di, word ptr _P_&lpBits+2
+ les bx,_P_&lpBi
+
+ if fn and DIB_PART_DIB
+
+ mov dx,_P_&n
+
+ endif
+
+ if fn and DIB_RECT_DIB
+
+;; for a call which specifies a rectangular area in the DIB (SetDIBitsToDevice),
+;; compute the size of the DIB that will actually be validated.
+;;
+;; The cases are:
+;;
+;; (1) If (yS > (nStart + n) : The DIB RECT will be totally clipped. Do not
+;; validate the DIB size in this case.
+;; (2) If (yS + yE) < nStart : The DIB rect will totally be clipped. Do not
+;; validate the DIB size in this case.
+;; (3) Else, compute the min of (yS+yE-nStart) and (n) and use it to validate
+;; the size of the DIB buffer.
+
+ mov dx, _P_&yS
+ mov cx, _P_&nStart
+ add cx, _P_&n
+ cmp dx, cx
+ ja total_clip ;; case (1)
+ add dx, _P_&yE
+ cmp dx, _P_&nStart
+ jb total_clip ;; case (2)
+ sub dx, _P_&nStart
+ cmp dx, _P_&n ;; compute min in case (3)
+ jb @f ;; (yS+yE-nStart) is < n
+ mov dx, _P_&n ;; validate only n scans
+ jmp short @f
+
+total_clip:
+ pop di
+ pop si ;; will not validate DIB size
+ jmp short exit
+
+@@:
+ endif
+
+ mov cx, fn
+ or cx, rBits
+
+ call ValidateDIBSize
+ pop di
+ pop si
+ or ax,ax
+ jz exit
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+exit:
+
+
+ endif
+ endm
+
+;----------------------------------------------------------------------------;
+
+STRUCT <LOGPALETTE> ;fixed-size portion of struct.
+F_VERSION palVersion
+F_WORD wEntries
+ENDSTRUCT
+
+P_CLPLOGPALETTE macro lp, opts
+ _GenParm <lp>,4,<opts>
+ if VLgen
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,VLcbsLOGPALETTE
+ lcall CLP
+ _gensub LP
+
+ les bx,_P_&lp
+ mov cx,es
+
+ mov ax,VLcbsPALETTEENTRY
+ mul word ptr es:[bx]._F_wEntries ; ax = size of all palette entries
+ add ax,VLcbsLOGPALETTE ; ax = total size of struct
+ xchg ax,bx
+
+ lcall CLP
+ _gensub LP
+ endif
+endm
+
+STRUCT DEVMODE ;fixed-size fields
+F_RGCH dmDeviceName, CCHDEVICENAME
+F_VERSION dmSpecVersion
+F_WORD dmDriverVersion ;value assigned by driver developer
+F_WSIZE dmSize ;size of DEVMODE struct.
+F_WORD dmDriverExtra ;size of dmDriverData field.
+F_DWORD dmFields
+F_RVALUE dmOrientation, DMORIENT_PORTRAIT, DMORIENT_LANDSCAPE
+F_RVALUE dmPaperSize, DMPAPER_FIRST, DMPAPER_LAST
+F_short dmPaperLength
+F_short dmPaperWidth
+F_short dmScale
+F_short dmCopies
+F_RVALUE dmDefaultSource, DMBIN_FIRST, DMBIN_LAST
+F_RVALUE dmPrintQuality, DMPRINT_FIRST, DMPRINT_LAST ;** range -4 to -1
+F_RVALUE dmColor, DMCOLOR_FIRST, DMCOLOR_LAST ;** range 1-2
+F_RVALUE dmDuplex, DMDUP_FIRST, DMDUP_LAST ;** range 1-3
+ENDSTRUCT
+
+P_CLPDEVMODE0 macro lp, opts
+ local dmexit
+ local dmbad
+ local dmbad1
+
+ _GenParm <lp>,4,<opts>
+ if VLgen
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,ax
+ or bx,cx
+ jz dmexit ;allow NULL pointer
+
+ mov bx,VLcbsDEVMODE
+ lcall CLP ;verify fixed-size fields
+ _gensub LP
+
+ les bx,_P_&lp
+ mov ax,es:[bx]._F_dmDriverExtra
+ or ax,ax
+ jz dmexit ;if 0 extra bytes, we're done
+
+ add ax,VLcbsDEVMODE
+ xchg ax,bx ;bx=size of DEVMODE+extra bytes
+ mov cx,es
+
+;; MICROGRAFIX draw uses CreateDC to load one of thier format conversion DLLs.
+;; The pass in a DevMode structure which is either a private structure, or
+;; has a bogus value in the _F_dmDriverExtra field. We need to loosen the
+;; validation and turn an invalid DevMode detection into a warning.
+
+beg_fault_trap dmbad
+ mov es,cx
+ or bx,bx ; cb == 0?
+ jz dmexit ; yes: just check selector
+ dec bx
+ add bx,ax
+ jc dmbad1 ; check 16 bit overflow
+ mov bl,es:[bx] ; check read permission, limit
+end_fault_trap
+ jmp short dmexit ; structure is valid
+
+dmbad:
+ fault_fix_stack
+dmbad1:
+ mov bx,ERR_BAD_PTR or ERR_WARNING
+ lcall Inval_Param_
+
+dmexit:
+ endif
+endm
+
+
+;----------------------------------------------------------------------------;
+; P A R A M E T E R V A L I D A T I O N R O U T I N E S ;
+;----------------------------------------------------------------------------;
+
+; DIB validation flag constants. Do not change these constants without
+; changing them in GDI.API.
+
+DIB_RGB_COLORS equ 0
+DIB_VALIDATE_COLOR equ 1
+DIB_VALIDATE_RW equ 2
+DIB_PTR0 equ 4
+DIB_FULL_DIB equ 8
+DIB_FULL_COLOR equ 16
+DIB_RECT_DIB equ 32
+DIB_PART_DIB equ 64
+
+; derived DIB flag constants
+
+DIB_PTR_CLP equ 0
+DIB_NO_COLOR equ 0
+DIB_PTR_LP equ DIB_VALIDATE_RW
+DIB_PTR_CLP0 equ DIB_PTR0
+DIB_PTR_LP0 equ DIB_VALIDATE_RW+DIB_PTR0
+ERR_BAD_PTR equ 07007h
+DIB_DIBTODEV equ DIB_PART_DIB+DIB_RECT_DIB
+DIB_PTR_GETDIBITS equ DIB_VALIDATE_RW+DIB_FULL_COLOR
+NO_COLOR_TABLE equ 9
+
+BITMAP struc
+ bmType DW ?
+ bmWidth DW ?
+ bmHeight DW ?
+ bmWidthBytes DW ?
+ bmPlanes DB ?
+ bmBitsPixel DB ?
+ bmBits DD ?
+BITMAP ends
+
+RGBTRIPLE struc
+ rgbBlue db ?
+ rgbGreen db ?
+ rgbRed db ?
+RGBTRIPLE ends
+
+RGBQUAD struc
+ rgbqBlue db ?
+ rgbqGreen db ?
+ rgbqRed db ?
+ rgbqReserved db ?
+RGBQUAD ends
+
+; structures for defining DIBs
+BITMAPCOREHEADER struc
+ bcSize dd ?
+ bcWidth dw ?
+ bcHeight dw ?
+ bcPlanes dw ?
+ bcBitCount dw ?
+BITMAPCOREHEADER ends
+
+BITMAPINFOHEADER struc
+ biSize dd ?
+ biWidth dd ?
+ biHeight dd ?
+ biPlanes dw ?
+ biBitCount dw ?
+
+ biCompression dd ?
+ biSizeImage dd ?
+ biXPelsPerMeter dd ?
+ biYPelsPerMeter dd ?
+ biClrUsed dd ?
+ biClrImportant dd ?
+BITMAPINFOHEADER ends
+
+BITMAPINFO struc
+ bmiHeader db (SIZE BITMAPINFOHEADER) DUP (?)
+ bmiColors db ? ; array of RGBQUADs
+BITMAPINFO ends
+
+BITMAPCOREINFO struc
+ bmciHeader db (SIZE BITMAPCOREHEADER) DUP (?)
+ bmciColors db ? ; array of RGBTRIPLEs
+BITMAPCOREINFO ends
+
+BITMAPFILEHEADER struc
+ bfType dw ?
+ bfSize dd ?
+ bfReserved1 dw ?
+ bfReserved2 dw ?
+ bfOffBits dd ?
+BITMAPFILEHEADER ends
+
+externFP IsBadReadPtr ;(KERNEL)
+externFP IsBadWritePtr ;(KERNEL)
+externFP IsBadHugeReadPtr ;(KERNEL)
+externFP IsBadHugeWritePtr ;(KERNEL)
+
+;createseg _TEXT,TEXT,BYTE,PUBLIC,CODE
+createseg _TEXT,TEXT,WORD,PUBLIC,CODE
+sBegin TEXT
+;----------------------------------------------------------------------------;
+; ValidateDIBHeader: ;
+; ;
+; This routine validates the DIB header: ;
+; ;
+; Entry: ;
+; CX:AX -- pointer to DIB header (either core or info header) ;
+; DX: -- wUsage parameter ;
+; DI: -- Flags: ;
+; BIT0 - (DIB_VALIDATE_COLOR) set if no color table validatio ;
+; to be done. ;
+; BIT1 - (DIB_VALIDATE_RW) set if R-W validation to be done. ;
+; BIT2 _ (DIB_PTR0) set if NULL pointer OK ;
+; BIT3 _ (DIB_FULL_DIB) set if complete DIB (not used here);
+; BIT4 - (DIB_FULL_COLOR) ignore biClrUsed if set. ;
+; Returns: ;
+; AX = 0 if valid header. ;
+; DI:SI: will point just past the end of the buffer. ;
+; ;
+; Uses: ;
+; Free to use AX,BX,CX,DX,SI,DI and ES. ;
+; ;
+;----------------------------------------------------------------------------;
+
+public ValidateDIBHeader
+ValidateDIBHeader proc near
+
+
+; the header must atleast be the size of COREHEADER.
+
+ mov bx,SIZE BitmapCoreHeader
+ push cx
+ push ax ;save the pointer to header
+ call DIB_Validate_Pointer ;is it a valid pointer ?
+ or ax,ax
+ pop ax
+ pop cx ;restore pointer
+ jz VDH_cont ;base size ok
+ jmp VDH_bad_header ;invalid size
+
+VDH_cont:
+
+; now it is safe to load the pointer to the header and validate the actual
+; size.
+
+ mov es,cx
+ mov bx,ax ;es:bx -> dib header
+ mov si,word ptr es:[bx].biSize ;load and keep the size
+ mov cx, SIZE RGBTriple ;assume COREHEADER.
+ cmp si,SIZE BitmapCoreHeader ;COREHEADER ?
+ jz VDH_core ;it is a core header
+ mov cx, SIZE RGBQuad ;assume INFOHEADER
+ cmp si, SIZE BitmapInfoHeader ;is it an info header ?
+ jnz VDH_bad_header ;header is not right.
+
+; we have a new header. Make sure that some of the fields that the code
+; expects to be 0 are 0.
+
+ xor ax,ax ;need zeros.
+ cmp word ptr es:[bx].biHeight+2,ax
+ jne VDH_bad_header ;invalid
+ cmp word ptr es:[bx].biWidth+2,ax
+ jne VDH_bad_header ;invalid
+
+VDH_get_bit_count:
+ cmp es:[bx].biPlanes,1
+ jne VDH_bad_header ;no.
+ mov ax,es:[bx].biBitCount ;load the bits per pel
+ jmp short VDH_check_color ;validate color
+
+VDH_core:
+ cmp es:[bx].bcPlanes,1
+ jne VDH_bad_header ;no.
+ mov ax,es:[bx].bcBitCount ;load the bits per pel
+
+VDH_check_color:
+
+; if the bits per pel is >= NO_COLOR_TABLE, we do not have a color table in
+; the DIB.
+
+ cmp ax,NO_COLOR_TABLE
+ jae VDH_no_color_table
+
+; if color table validation is not needed, we can return if the header is
+; a core header (we have validated size) or validate the size of the
+; basic header and return.
+
+ test di, DIB_VALIDATE_COLOR ;color validation needed ?
+ jnz VDH_validate_color ;yes.
+
+VDH_no_color_table:
+
+; color table validation is not needed. We are done if this is a core header.
+
+ cmp si, SIZE BitmapCoreHeader ;core header ?
+ jz VDH_return_OK ;is, validation done. valid.
+ mov ax,bx ;get offset
+ mov bx,si ;get base header size
+ jmp short VDH_validate_size ;validate the total size
+
+VDH_bad_header:
+
+ mov ax,1 ;return from here with error
+ jmp short VDH_return ;error return
+
+
+VDH_validate_color:
+ cmp dx,DIB_RGB_COLORS ;is the usage RGB values
+ jz VDH_color_entry_size_in_cx ;cx has size of each entry
+ mov cx,2 ;size per entry for palettes
+
+VDH_color_entry_size_in_cx:
+ mov dx,ax ;get the bit count in dx
+
+; if DIB_FULL_COLOR bit is set, we will ignore the value if biClrUsed.
+
+ test di,DIB_FULL_COLOR ;validate complete color table ?
+ jnz VDH_get_num_colors ;yes.
+
+; check out the biClrUsed value.
+
+ cmp si, SIZE BitmapInfoHeader ;is this an info header ?
+ jnz VDH_get_num_colors ;no.
+ mov ax,word ptr es:[bx].biClrUsed ;is this specified ?
+ or ax,ax
+ jnz VDH_num_colors_got ;yes. ax has num colors
+
+VDH_get_num_colors:
+ xchg dx,cx
+ mov ax,1
+ shl ax,cl ;number of color entries in ax
+ xchg dx,cx
+
+VDH_num_colors_got:
+ mul cx ;cx had size of each entry
+ add ax,si ;add size of header
+ xchg ax,bx ;size in bx, offset in ax
+
+VDH_validate_size:
+ mov cx,es ;cx:ax has ptr, bx has size
+
+; store the pointer past the header in DI:SI
+
+ mov di,cx
+ mov si,ax
+ add si,bx ;past the end. Assume no wrap
+ call DIB_Validate_Pointer ;validate pointer
+ jmp short VDH_return ;ax has status
+
+VDH_return_OK:
+ xor ax,ax ;valid return
+
+VDH_return:
+ ret
+
+ValidateDIBHeader endp
+
+
+;----------------------------------------------------------------------------;
+; ValidateDIBSize: ;
+; ;
+; Validates the size of the DIB bits. ;
+; ;
+; Entry: ;
+; DI:SI -- pointer to DIB bits (either core or info header) ;
+; ES:BX -- pointer to DIB header (already validated) ;
+; DX: -- num scans. ;
+; CX: -- Flags: ;
+; BIT1 - (DIB_VALIDATE_RW) set if R-W validation to be done. ;
+; BIT2 _ (DIB_PTR0) set if NULL pointer OK ;
+; BIT3 - (DIB_FULL_DIB) set if full DIB bit size to be ;
+; validated. ;
+; Returns: ;
+; AX = 0 if valid header. ;
+; ;
+; Uses: ;
+; Free to use AX,BX,CX,DX,SI,DI and ES. ;
+; ;
+; Assumes: ;
+; Caller has done a PUSH SI/PUSH DI on the frame. ;
+;----------------------------------------------------------------------------;
+public ValidateDIBSize
+ValidateDIBSize proc near
+
+ push cx ;save
+ cmp word ptr es:[bx].biSize, SIZE BitmapInfoHeader
+ jz VDB_info ;info header
+ mov cx,es:[bx].bcBitCount ;get the bit count
+ mov ax,es:[bx].bcWidth ;and width in pels
+ jmp short VDB_get_scan_size ;calculate scan size
+
+VDB_info:
+ cmp word ptr es:[bx].biCompression+2,0
+ jnz VDB_check_size_image
+ cmp word ptr es:[bx].biCompression, BI_RGB
+ jz VDB_not_rle ;not an RLE DIB
+
+VDB_check_size_image:
+ mov ax,word ptr es:[bx].biSizeImage
+ mov cx,ax
+ or cx,word ptr es:[bx].biSizeImage+2
+ jz VDB_unknown_size ;unknown size
+ pop cx ;restore saved cx
+ mov dx,word ptr es:[bx].biSizeImage+2
+ jmp short VDB_validate_size ;size is in dx:ax
+
+VDB_unknown_size:
+ mov ax,1 ;validate for 1byte
+ cwd
+ pop cx ;restore flags
+ jmp short VDB_validate_size
+
+VDB_not_rle:
+; calculate the size of the scan. Assume that the width is a word
+
+ mov cx,es:[bx].biBitCount
+ mov ax,word ptr es:[bx].biWidth
+
+VDB_get_scan_size:
+
+ push dx ;save
+ mul cx ;dx:ax = num of bits
+ add ax,31
+ adc dx,0
+ and ax, NOT 31 ;round up to multiple of 32
+ ror dx,3 ;get ls 3 bits into upper byte
+ and dh,0e0h ;keep the ms 3 bits
+ shr ax,3 ;ignore ls 3 bits
+ or ah,dh ;ax = num bytes per scan
+ pop dx
+
+VDB_scan_width_in_ax:
+
+ pop cx ;restore flags
+ xchg cx,dx ;get flags into dx, scan in cx
+
+ push di ;save
+ mov di,word ptr es:[bx].bcHeight ;assume core header
+ cmp word ptr es:[bx].biSize, SIZE BitmapCoreHeader
+ jz VDB_total_scans_in_di ;di has total height of DIB
+ mov di,word ptr es:[bx].biHeight ;get low word of height
+
+VDB_total_scans_in_di:
+ mov bx,di ;get total height in BX
+ pop di ;restore
+ test dx,DIB_FULL_DIB ;is full DIB to be validated ?
+ jnz VDB_num_scans_in_bx ;yes, bx has num scans.
+
+; when we are validating partial DIBs, we want to make sure that the
+; numScan parameter passed in (now in cx) is not greater than the total
+; height. If it is, we will simply validate for the full DIB.
+
+ cmp cx,bx ;is numScan > total scans ?
+ ja VDB_num_scans_in_bx ;yes, invalid numScans. Use total scans
+ mov bx,cx ;use numScans
+
+VDB_num_scans_in_bx:
+ push dx ;save flags
+ mul bx ;dx:ax has size
+ pop cx ;get the flags in cx
+
+VDB_validate_size:
+
+; dx:ax has size of the buffer. di:si is the ptr, cx has flags.
+
+ call DIB_Validate_Huge_Pointer
+ ret
+
+ValidateDIBSize endp
+
+
+;----------------------------------------------------------------------------;
+; DIB_Validate_Pointer: ;
+; ;
+; Validates the size and access of a pointer. ;
+; ;
+; Entry: ;
+; CX:AX -- pointer to be validate ;
+; BX: -- size of buffer ;
+; DI: -- flags: ;
+; BIT1 - (DIB_VALIDATE_RW) set if R-W validation to be done. ;
+; BIT2 _ (DIB_PTR0) set if NULL pointer OK ;
+; ;
+; Uses: None ;
+; returns AX = 0 if valid. ;
+; ;
+;----------------------------------------------------------------------------;
+
+public DIB_Validate_Pointer
+DIB_Validate_Pointer proc near
+
+ test di,DIB_PTR0 ;NULL pointer allowed ?
+ jz DBP_not_null ;no.
+ push ax ;save
+ or ax,cx ;is the pointer NULL ?
+ pop ax ;restore
+ jz DBP_return_ok ;pointer is NULL and is valid
+
+DBP_not_null:
+
+ push cx
+ push ax
+ push bx
+ test di, DIB_VALIDATE_RW ;read/write validation ?
+ jnz DBP_rw_validation ;yes.
+
+; do read only validation:
+
+ call IsBadReadPtr
+ jmp short DBP_return
+
+DBP_rw_validation:
+ call IsBadWritePtr
+ jmp short DBP_return
+
+DBP_return_ok:
+ xor ax,ax ;valid pointer
+
+DBP_return:
+ ret
+
+DIB_Validate_Pointer endp
+
+
+;----------------------------------------------------------------------------;
+; DIB_Validate_Huge_Pointer: ;
+; ;
+; Validates the size and access of a pointer. ;
+; ;
+; Entry: ;
+; DI:SI -- pointer to be validate ;
+; DX:AX -- size of buffer ;
+; CX: -- flags: ;
+; BIT1 - (DIB_VALIDATE_RW) set if R-W validation to be done. ;
+; BIT2 _ (DIB_PTR0) set if NULL pointer OK ;
+; ;
+; Uses: None ;
+; returns AX = 0 if valid. ;
+; ;
+;----------------------------------------------------------------------------;
+
+public DIB_Validate_Huge_Pointer
+DIB_Validate_Huge_Pointer proc near
+
+ test cx,DIB_PTR0 ;NULL pointer allowed ?
+ jz DBPH_not_null ;no.
+ push si ;save
+ or si,di ;is the pointer NULL ?
+ pop si ;restore
+ jz DBPH_return_ok ;pointer is NULL and is valid
+
+DBPH_not_null:
+
+ push di
+ push si ;ds:si is pointer to bits
+ push dx
+ push ax ;dx:ax is the dword size
+ test cx, DIB_VALIDATE_RW ;read/write validation ?
+ jnz DBPH_rw_validation ;yes.
+
+; do read only validation:
+
+ call IsBadHugeReadPtr
+ jmp short DBPH_return
+
+DBPH_rw_validation:
+
+ call IsBadHugeWritePtr
+ jmp short DBPH_return
+
+DBPH_return_ok:
+ xor ax,ax ;valid pointer
+
+DBPH_return:
+ ret
+
+DIB_Validate_Huge_Pointer endp
+
+sEnd TEXT
+
+;=======================================================================
+;
+; API Descriptions
+;
+; in PALETTE.ASM
+API void, AnimatePalette, TEXT, <ASM>
+P_HPALETTE hPal ; validated by VALID? (3.0 and 3.1)
+P_WORD wStartIndex
+P_CLPPALENTRYBUFFER nEntries,lpPalColors ; **
+
+; in PALETTE.ASM
+API HPALETTE, CreatePalette, TEXT, <ASM>
+P_CLPLOGPALETTE lpLogPal ;**
+
+; in PALETTE.ASM
+API WORD, GetPaletteEntries, TEXT, <ASM>
+P_HPALETTE hPalette ;validated by VALID? (3.0 and 3.1)
+P_WORD wStartIndex
+P_LPPALENTRYBUFFER wEntries, lpPalColors ; buffer filled in DEBUG Win 3.1
+
+; in PALETTE.ASM
+API WORD, GetNearestPaletteIndex, TEXT, <ASM>
+P_HPALETTE hPalette ;validated by VALID? (3.0 and 3.1)
+P_DWORD color
+
+; in PALETTE.ASM
+API WORD, GetSystemPaletteEntries, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_WORD wStartIndex
+P_LPPALENTRYBUFFER wEntries,lpPalColors ;buffer filled in DEBUG Win 3.1
+
+; in PALETTE.ASM
+API WORD, GetSystemPaletteUse, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+
+; in PALETTE.ASM
+API BOOL, ResizePalette, TEXT, <ASM>
+P_HPALETTE hPalette ;validated by VALID? (3.0 and 3.1)
+P_WORD nNumEntries
+
+; in PALETTE.ASM
+API WORD, SetPaletteEntries, TEXT, <ASM>
+P_HPALETTE hPalette ;validated by VALID? (3.0 and 3.1)
+P_WORD wStartIndex
+P_CLPPALENTRYBUFFER wEntries, lpPalColors
+
+; in PALETTE.ASM
+API WORD, SetSystemPaletteUse, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_WORD wUsage
+
+; in PALETTE.ASM
+API int, UpdateColors, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+
+; in PRNTCTL.C (new for Win 3.1)
+API int, AbortDoc, TEXT
+P_HDCMETA hdc ; validated by Valid()
+APIERR
+ mov ax, SP_ERROR ;General escape error
+APIEND
+
+; in PRNTCTL.C (New for Win 3.1)
+API int, EndPage, TEXT
+P_HDCMETA hdc ; Checked by Valid(). Encapsulates ENDPAGE escape
+APIERR
+ mov ax, SP_ERROR ;General escape error
+APIEND
+
+; in PRNTCTL.C (New for Win 3.1)
+API int, EndDoc, TEXT
+P_HDCMETA hdc ; Checked by Valid(). Encapsulates NEWFRAME escape
+APIERR
+ mov ax, SP_ERROR ;General escape error
+APIEND
+
+STRUCT <DOCINFO>
+F_int cbSize
+F_CLPSTR lpszDocName
+F_CLPSTR0 lpszOutput
+ENDSTRUCT
+
+_GenLP <P_CLPDOCINFO>,<CLP>,%VLcbsDOCINFO
+
+; in PRNTCTL.C (new for 3.1)
+API int, StartDoc, TEXT
+P_HDCMETA hdc ;checked by Valid()
+P_CLPDOCINFO lpDocInfo
+APIERR
+ mov ax, SP_ERROR ;General escape error
+APIEND
+
+; in PRNTCTL.C (new for 3.1)
+API int, StartPage, TEXT
+P_HDCMETA hdc ;checked by Valid(). Null error return
+
+; in PRNTCTL.C (new for 3.1)
+API int, SetAbortProc, TEXT
+P_HDCMETA hdc
+P_LPFNABORT0 lpProc ;**
+APIERR
+ mov ax, SP_ERROR ;General escape error
+APIEND
+
+; in DCMAN1.ASM
+API HDC, CreateCompatibleDC, TEXT, <ASM>
+P_HDC0 hdc ; 0 => use screen DC
+
+; in DCMAN1.ASM
+API HDC, CreateIC ,TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_CLPSTR lpDriverName
+P_CLPSTR0 lpDeviceName
+P_CLPSTR0 lpOutput
+P_DWORD lpInitData ; Driver-dependent data or NULL
+APIEND
+
+
+; in DCMAN1.ASM
+API HDC, CreateDC, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+;
+; START of special ATM hackery.
+;
+ jmp short SkipATMHackery
+;
+; Addresses of certain kernel functions patched by ATM loader.
+;
+;ATM_LPFN CreateDC_lpfn, LoadLibrary
+;ATM_LPFN CreateDC_lpfn, GetProcAddress
+;ATM_LPFN CreateDC_lpfn, FreeLibrary
+;
+; InternalCreateDC() hook that gets patched by ATM
+;
+;public ATMInternalCreateDC
+;ATMInternalCreateDC:
+;
+; Old Windows prolog code that will be properly
+; recognized by the ATM installation code...
+;
+; mov ax,_DATA
+; inc bp
+; push bp
+; mov bp,sp
+; push ds ; push ds and pop it off.
+; pop ds ; (we need to pop DS rather than
+; ; something fast like pop AX because
+; ; ATM doesn't preserve DS itself)
+; pop bp ; Take down the frame completely.
+; dec bp
+;ExternNP InternalCreateDC ; (in dcman1.asm)
+; jmp InternalCreateDC ; now go to the real code
+SkipATMHackery:
+;
+; END of special ATM hackery
+;
+P_CLPSTR lpDriverName
+P_CLPSTR0 lpDeviceName ; can be NULL if lpDriverName is "DISPLAY"
+P_CLPSTR0 lpOutput ; can be NULL if lpDriverName is "DISPLAY"
+P_CLPDEVMODE0 lpInitData ; ** points to DEVMODE struct.
+
+; in DCMAN2.ASM
+API BOOL, DeleteDC, TEXT, <ASM,ATMFRAMEDS>
+P_HDC hdc ; Validated by VALIDDEBUG? (3.1), VALID? (3.0)
+APIEND
+ATM_LPFN DeleteDC_lpfn, FreeLibrary
+
+; in DCMAN2.ASM
+API BOOL, RestoreDC, TEXT, <ASM>
+P_HDCMETA hdc
+P_int level ;number of DC on context stack or -1
+
+; in DCMAN2.ASM
+API int, SaveDC, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+
+; in RESETDC.C
+API BOOL, RESETDC, TEXT
+P_HDC hdc
+P_CLPDEVMODE0 lpInitData ; ** points to DEVMODE struct.
+
+; in OBJDEL.ASM
+API BOOL, DeleteObject, TEXT, <ASM>
+P_HGDIOBJ hObject ; ** Validated by VALID? (3.0 and 3.1)
+ ; object shouldn't be selected into a DC
+ ; Pens, brushes, fonts, bitmaps &
+ ; palettes and regions.
+; in OBJMAN.ASM
+API HPEN, CreatePen, TEXT, <ASM>
+P_VALUE style, PS_MAX ; ** range 0-6
+P_int cx
+P_COLORREF color ; ** DWORD
+
+; in OBJMAN.ASM
+API HPEN, CreatePenIndirect, TEXT, <ASM>
+P_CLPLOGPEN lpLogPen ; **
+
+; in OBJMAN.ASM
+API HBRUSH, CreateSolidBrush, TEXT, <ASM, NOGEN>
+P_COLORREF color
+
+; in OBJMAN.ASM
+API HBRUSH, CreateHatchBrush, TEXT, <ASM>
+P_VALUE nIndex, HS_MAX ; ** range 0-5
+P_COLORREF color ;
+
+; in OBJMAN.ASM
+API HBRUSH, CreatePatternBrush, TEXT, <ASM>
+P_HBITMAP hBitmap ;
+
+; in OBJMAN.ASM
+API HBRUSH, CreateBrushIndirect, TEXT, <ASM>
+P_CLPLOGBRUSH lpLogBrush ; **
+
+; in OBJMAN.ASM
+API HBITMAP, CreateBitmap, TEXT, <ASM> ;<FUNNYFRAME> in 3.0
+P_CLPBITBUFFER0 cx, cy, bPlanes, bBitC, lpBits ; ** buffer size
+ ;determined by bitmap attributes
+ ;cx and cy are int. values
+ ;bPlanes and bBitC are BYTE values
+
+; in OBJMAN.ASM
+API HBITMAP, CreateBitmapIndirect, TEXT, <ASM> ;<FUNNYFRAME> in 3.0
+P_CLPBITMAP lpBitmap ; **
+
+; in OBJMAN.ASM
+API HBITMAP, CreateCompatibleBitmap, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDC hdc ; validated by VALID? (3.0 and 3.1) in CompatibleBitmap
+P_int cx
+P_int cy
+
+; in OBJMAN.ASM
+API HBITMAP, CreateDiscardableBitmap, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDC hdc ; validated by VALID? (3.0 and 3.1) in CompatibleBitmap
+P_int cx
+P_int cy
+
+; in OBJMAN.ASM
+API HFONT, CreateFont, TEXT, <ASM>
+P_int cy
+P_int cx
+P_int nEscapement
+P_int nOrientation
+P_VALUE nWeight, FW_MAX ;** range 0-1000
+P_BYTE cItalic
+P_BYTE cUnderline
+P_BYTE cStrikeOut
+P_BYTE cCharSet
+P_BVALUE cOutPrecis, OUT_MAX ;** range 0-3
+P_BVALUE cClipPrecis, CLIP_MAX ;** range 0-2
+P_BVALUE cQuality, QUALITY_MAX ;** range 0-2
+P_PITCHFAMILY cPitchAndFamily ;** BYTE. Flags in upper and lower nibbles
+P_CLPFACENAME0 lpFaceName ;** null-terminated string length
+ ;not > LF_FACESIZE
+
+; in OBJMAN.ASM
+API HFONT, CreateFontIndirect, TEXT, <ASM>
+P_CLPLOGFONT lpLogFont ;**
+
+; in OBJMAN.ASM
+API HBRUSH, CreateDIBPatternBrush, TEXT, <ASM>
+P_GHPACKEDDIB hPackedDIB, wUsage
+
+; in OBJMAN.ASM
+API DWORD, SetBitmapDimension, TEXT, <ASM>
+P_HBITMAP hBitmap ; validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, SetBitmapDimensionEx, TEXT
+P_HBITMAP hBitmap
+P_int x
+P_int y
+P_LPSIZE0 lpSize
+
+; in OBJMAN.ASM
+API DWORD, GetBitmapDimension, TEXT, <ASM>
+P_HBITMAP hBitmap ;validated by VALID? (3.0 and 3.1)
+
+; in WIN32.C
+API BOOL, GetBitmapDimensionEx, TEXT
+P_HBITMAP hBitmap
+P_LPSIZE lpDimension
+
+; in OBJMAN.ASM
+API int, SetTextJustification, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_int nBreakExtra
+P_int nBreakCount
+
+; in OBJMAN.ASM
+API int, SetTextCharacterExtra, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_int nCharExtra
+
+; in METAREC.C
+API GHANDLE, CopyMetaFile, TEXT
+P_GHANDLE hMeta ;checked by IsValidMetaFile()
+P_CLPSTR0 lpFileName ;0 => use memory metafile
+
+; in METAREC.C
+API HDC, CreateMetaFile, TEXT
+P_CLPSTR0 lpFileName ;0 => return memory metafile DC
+
+; in METAREC.C
+API GHANDLE, CloseMetaFile, TEXT
+P_HDCMETA hdc
+
+
+; in METAPLAY.ASM
+API BOOL, DeleteMetaFile, TEXT, <ASM,FUNNYFRAME> ; is NODATA
+P_HMETAFILE hMF
+
+; in METAPLAY.ASM
+API BOOL, PlayMetaFile, TEXT, <ASM, ATMFRAMEDS>
+P_HDCMETA hdc ;validated by Valid() (3.1 only)
+P_HMETAFILE hMF
+
+; in METAPLAY.ASM
+API GHANDLE, GetMetaFile, TEXT, <ASM>
+P_CLPSTR lpFileName
+
+
+; in META.C
+API void, PlayMetaFileRecord, TEXT
+P_HDCMETA hdc ;validated by Valid() (3.1 only)
+P_LPHANDLETABLE0 lpHT
+P_CLPMETARECORD lpMR
+P_WORD nhandles
+
+; in META.C
+API BOOL, EnumMetaFile, TEXT
+P_HDCMETA0 hdc ; NULL DC is OK. Checked by Valid() (3.0 and 3.1)
+P_HMETAFILE hMF
+P_LPFNMENUM lpfnEnum ; **
+P_DWORD lpClientData ; CLPVOID0 ?, but often just contains data
+
+; in METAREC.C
+API GHANDLE, GetMetaFileBits, TEXT
+P_HMETAFILE hMF
+
+; in METAREC.C
+API HANDLE, SetMetaFileBits, TEXT
+P_HMETAFILE hMem ; just returns hMem
+
+; in METAREC.C
+API HANDLE, SetMetaFileBitsBetter, TEXT
+P_HMETAFILE hMem ; just returns hMem, new for 3.1
+
+; in XLATE.ASM
+API BOOL, DPtoLP, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by DPXlate
+P_LPPOINTBUFFER lpPoints, nCount ;**
+
+; in XLATE.ASM
+API BOOL, LPtoDP, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) in DPXlate
+P_LPPOINTBUFFER lpPoints, nCount
+
+; in ARC.ASM
+API HRGN, CreateEllipticRgnIndirect, TEXT, <ASM>
+P_CLPRECT lpRect
+
+; in ARC.ASM
+API HRGN, CreateEllipticRgn, TEXT, <ASM, NOGEN>
+P_XY1XY2 x1,y1,x2,y2 ;X2-X1 and Y2-Y1 under 32,767 units
+
+; in ARC.ASM
+API HRGN, CreatePolygonRgn, TEXT, <ASM>
+P_CLPPOINTBUFFER lpPoints, nCount ;**
+P_RVALUE nPolyFillMode, PFILL_MIN, PFILL_MAX ;** range 1-2
+
+; in ARC.ASM
+API HRGN, CreatePolyPolygonRgn, TEXT, <ASM>
+P_POLYPOLYPOINTS lpPoints, lpPolyCounts, nCount ;**lpPolyCounts is a buffer
+ ;of nCount Integers. lpPoints
+ ;is a buffer of POINTS. Size of
+ ;lpPoints det. by sum of all
+ ;integers in lpPolyCounts
+P_RVALUE nPolyFillMode, PFILL_MIN, PFILL_MAX ;** range 1-2
+
+; in ARC.ASM
+API HRGN, CreateRoundRectRgn, TEXT, <ASM, NOGEN>
+P_XY1XY2 x1,y1,x2,y2 ;X2-X1 and Y2-Y1 under 32,767 units
+P_int x3
+P_int y3
+
+; in ARC.ASM
+API BOOL, Ellipse, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2
+
+; in ARC.ASM
+API BOOL, Arc, TEXT, <ASM>
+P_HDCNOIC hdc ; validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2
+P_int x3
+P_int y3
+P_int x4
+P_int y4
+
+; in ARC.ASM
+API BOOL, Pie, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2
+P_int x3
+P_int y3
+P_int x4
+P_int y4
+
+; in ARC.ASM
+API BOOL, Chord, TEXT, <ASM>
+P_HDCNOIC hdc ; validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2 ; ** X2-X1 and Y2-Y1 under 32,767 units
+P_int x3
+P_int y3
+P_int x4
+P_int y4
+
+; in ARC.ASM
+API BOOL, RoundRect, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2
+P_int x3
+P_int y3
+
+; in RECT.C
+API BOOL, Rectangle, TEXT, <RECT>
+P_HDCNOIC hdc ;validated by Valid() (3.0 and 3.1) in RectangleBody
+P_XY1XY2 x1,y1,x2,y2
+
+; in FLOOD.ASM
+API BOOL, FloodFill, TEXT, <ASM> ; calls ExtFloodFill
+P_HDCNOIC hdc
+P_int x
+P_int y
+P_COLORREF color
+
+; in FLOOD.ASM
+API BOOL, ExtFloodFill, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+P_COLORREF color
+P_UVALUE fillType, EFF_MAX ;** range 0-1
+
+P_LPESCPARMS macro code, cb, lp, opts
+ _DefParm <code>,2,<opts>
+ _DefParm <cb>,2,<opts>
+ _DefParm <lp>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,_P_&cb
+ lcall CLP0
+ _gensub LP
+ endif
+endm
+
+; in ESC.ASM
+API int, Escape, TEXT, <ASM, ATMFRAMEDS>
+P_HDCNOTMEM hdc ; ** not mem. DC. VALID? (3.0 and 3.1)
+P_LPESCPARMS code, cbInData, lpInData
+P_LPVOID0 lpOutData
+APIERR
+ mov ax,SP_ERROR ;General escape error
+APIEND
+
+; in ENUMOBJE.ASM
+API int, EnumObjects, TEXT, <ASM>
+P_HDC hdc ; validated by VALID? (3.0 and 3.1)
+P_RVALUE nObjectType, OBJ_MIN, OBJ_MAX ; ** range 1-2
+P_LPFNOENUM lpCallBack ; **
+P_DWORD lpClientData ; CLPVOID0 ?, but often just contains data
+
+; in ENUMFONT.ASM
+API int, EnumFonts, TEXT, <ASM,ATMFRAMEDS>
+P_HDC hdc ; validated by VALID? (3.0 and 3.1) in RectStuff
+P_CLPFACENAME0 lpFaceName
+P_LPFNFENUM lpFontFunc ; **
+P_DWORD lpData ; CLPVOID0 ?, but often just contains data
+
+; in ENUMFONT.ASM (new for Win 3.1)
+API int EnumFontFamilies, TEXT, <ASM>
+P_HDC hdc ; validated by VALID?
+P_CLPFACENAME0 lpFaceName
+P_LPFNFENUM lpFontFunc ;
+P_DWORD lpData ; CLPVOID0 ?, but often just contains data
+
+; in GETSTUFF.ASM
+API DWORD, GetCurrentPosition, TEXT, <ASM,FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) in GSV
+
+; in WIN32.C
+API BOOL GetCurrentPositionEx, TEXT, <FUNNYFRAME, NODATA, DEBUGONLY> ;nogen
+P_HDC hdc
+P_LPPOINT lpPoint
+
+; in GETSTUFF.ASM
+API DWORD, GetDCOrg, TEXT, <ASM,FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) in GSV
+
+; in GETSTUFF.ASM
+API DWORD, GetBrushOrg, TEXT, <ASM,FUNNYFRAME,NODATA,DEBUGONLY> ; nogen
+P_HDC hdc ; validated by VALID? (3.0 and 3.1) in GSV
+
+; in WIN32.C
+API BOOL, GetBrushOrgEx, TEXT, <FUNNYFRAME, NODATA, DEBUGONLY> ; nogen
+P_HDC hdc
+P_LPPOINT lpPoint
+
+; in GETSTUFF.ASM
+API DWORD, GetBkColor, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ; nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API int, GetBkMode, TEXT, <ASM,FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API DWORD, GetTextColor, TEXT, <ASM,FUNNYFRAME,NODATA,DEBUGONLY>;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API WORD, GetTextAlign, TEXT, <ASM, FUNNYFRAME,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API int, GetROP2, TEXT, <ASM, FUNNYFRAME, NODATA, DEBUGONLY>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API int, GetStretchBltMode, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API int, GetPolyFillMode, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API int, GetMapMode, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in GETSTUFF.ASM
+API DWORD, GetWindowOrg, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+;in WIN32.C
+API BOOL, GetWindowOrgEx, TEXT, <FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc
+P_LPPOINT lpPoint
+
+; in GETSTUFF.ASM
+API DWORD, GetWindowExt, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in WIN32.C
+API BOOL, GetWindowExtEx, TEXT, <FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc
+P_LPSIZE lpSize
+
+; in GETSTUFF.ASM
+API DWORD, GetViewportOrg, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in WIN32.C
+API BOOL, GetViewportOrgEx, TEXT, <FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc
+P_LPPOINT lpPoint
+
+; in WIN32.C
+API BOOL, GetViewportExtEx, TEXT, <FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc
+P_LPSIZE lpSize
+
+; in GETSTUFF.ASM
+API DWORD, GetViewportExt, TEXT, <ASM, FUNNYFRAME,NODATA,DEBUGONLY> ;nogen
+P_HDC hdc ;validated by VALID? (3.0 and 3.1) by GSV
+
+; in CHARWID.ASM
+API BOOL, GetCharWidth, TEXT, <ASM, ATMFRAMEDS>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_LPRWBUFFER chFirst, chLast, lpBuffer, 2 ;** size dictated by
+ ;char. range. Each entry in
+ ;buffer is 2 bytes. Buffer
+ ;filled in DEBUG Win 3.1 only
+ ;lpBuffer is an int. buffer
+; in SETPIXEL.ASM
+API DWORD, GetPixel, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in SETPIXEL.ASM
+API DWORD, SetPixel, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+P_COLORREF color
+APIERR
+ mov ax, -1
+ cwd
+APIEND
+
+; in STOCK.ASM
+API HANDLE, GetStockObject, TEXT, <ASM>
+P_VALUE nIndex, STOCK_MAX ; ** range 0-16
+
+; in GDIINQ1.ASM
+API LONG, GetBitmapBits, TEXT, <ASM, FUNNYFRAME,NODATA>
+P_HBITMAP hBitmap ;validated by VALID? (3.0 and 3.1)
+P_LPBUFFERDW dwCount, lpBits ;** buffer size a DWORD
+ ;buffer filled in DEBUG Win 3.1
+
+; in GDIINQ1.ASM
+API int, GetDeviceCaps, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_DEVCAP nIndex ;** valid int. indices even-numbered
+ ;ranges 0-44, 88-90, 104-108.
+
+; in GDIINQ1.ASM
+API LONG, SetBitmapBits, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HBITMAP hBitmap ; validated by VALID? (3.0 and 3.1) in BitmapBits
+P_CLPBUFFERDW dwCount, lpBits ;** buffer size a DWORD
+ ;buffer filled in DEBUG Win 3.1
+
+; in GDIINQ2.ASM
+API int, GetObject, TEXT, <ASM>
+P_HGDIOBJGET hObject ;** Validated by VALID? (3.0 and 3.1)
+ ; pens, brushes, fonts, bitmaps &
+ ; palettes.
+P_LPBUFFERX nCount, lpObject ;** nCount occurs before lpBits
+ ;buffer filled in DEBUG Win 3.1
+
+; in FASPECT.ASM
+API DWORD, GetAspectRatioFilter, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+
+; in WIN32.C
+API BOOL, GetAspectRatioFilterEx, TEXT
+P_HDC hdc
+P_LPSIZE lpSize
+
+; in FASPECT.ASM
+API DWORD, SetMapperFlags, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1) in WordSet
+P_DFLAGS dwFlag, MAPFLG_VALID_L, MAPFLG_VALID_H ; ** only bit #1 is recognized
+
+; in XFORMMAN.ASM
+API DWORD, GetNearestColor, TEXT, <ASM>
+P_HDC hdc ; validated by VALID? (3.0 and 3.1)
+P_COLORREF color
+
+; in XFORMMAN.ASM
+API DWORD, OffsetViewportOrg, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in OffsetOrg
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, OffsetViewportOrgEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPPOINT0 lpPoint
+
+; in XFORMMAN.ASM
+API DWORD, OffsetWindowOrg, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in OffsetOrg
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, OffsetWindowOrgEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPPOINT0 lpPoint
+
+; in XFORMMAN.ASM
+API int, SetMapMode, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_RVALUE nMapMode, MM_MIN, MM_MAX ;** range 1-8
+
+; in XFORMMAN.ASM
+API DWORD, SetWindowExt, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in SetWinViewExt
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL SetWindowExtEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPSIZE0 lpSize
+
+; in XFORMMAN.ASM
+API DWORD, SetViewportExt, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in SetWinViewExt
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, SetViewportExtEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPSIZE0 lpSize
+
+; in XFORMMAN.ASM
+API DWORD, ScaleViewportExt, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in ScaleExt
+P_int xNum
+P_intN0 XDenom ;calls MulDiv
+P_int yNum
+P_intN0 YDenom ;calls MulDiv
+
+; in WIN32.C
+API BOOL, ScaleViewportExtEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in ScaleExt
+P_int xNum
+P_intN0 XDenom ;calls MulDiv
+P_int yNum
+P_intN0 YDenom ;calls MulDiv
+P_LPSIZE0 lpSize
+
+; in XFORMMAN.ASM
+API DWORD, ScaleWindowExt, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in ScaleExt
+P_int xNum
+P_intN0 XDenom ;calls MulDiv
+P_int yNum
+P_intN0 YDenom ;calls MulDiv
+
+; in WIN32.C
+API BOOL, ScaleWindowExtEx, TEXT, <FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in ScaleExt
+P_int xNum
+P_intN0 XDenom ;calls MulDiv
+P_int yNum
+P_intN0 YDenom ;calls MulDiv
+P_LPSIZE0 lpSize
+
+; in CLIPMAN.ASM
+API int, GetRgnBox, TEXT, <ASM>
+P_HRGN hrgn ;validated by VALID? (3.0 and 3.1)
+P_LPRECT lpRect ;buffer filled in DEBUG Win 3.1
+
+; in GETTEXTE.ASM
+API DWORD, GetTextExtent, TEXT, <ASM, ATMFRAMEDS>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_CLPBUFFER lpString, nCount
+
+; win WIN32.C
+API BOOL, GetTextExtentPoint, TEXT
+P_HDC hdc
+P_CLPSTR lpString
+P_int nCount
+P_LPSIZE lpSize
+
+; in TEXTATTS.ASM
+API int, GetTextCharacterExtra, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+
+; in GETTEXTF.ASM
+API int, GetTextFace, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_LPBUFFERX lpFaceName, nBytes ;nBytes occurs before lpFaceName
+ ;buffer filled in DEBUG Win 3.1
+APIERR
+E_SETEMPTY lpFaceName, nBytes
+APIEND
+
+; in GETTEXTM.ASM
+API BOOL, GetTextMetrics, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_LPTEXTMETRIC lptm ;**buffer filled in DEBUG Win 3.1
+
+; in ENVIRON.ASM
+API int, GetEnvironment, TEXT, <ASM>
+P_CLPSTR lpPortName ; ** converted to atom after
+ ; stripping off colons
+P_LPBUFFER0 lpEnviron, nBytes ; NULL => return env. block size
+ ; buffer filled in DEBUG Win 3.1
+APIERR
+E_SETEMPTY lpEnviron, nBytes
+APIEND
+
+
+; in ENVIRON.ASM
+API int, SetEnvironment, TEXT, <ASM>
+P_CLPSTR lpPortName ; converted to atom after stripping off ":"s
+P_CLPBUFFER lpEnviron, wCount ; buffer filled in DEBUG Win 3.1
+
+; in ADDFONTR.ASM
+API int, AddFontResource, TEXT, <ASM>
+P_CLPSTRHRSRC lpFileName ; ** null-terminated filename or handle to
+ ; loaded resource handle in LOWORD
+
+; in DELFONT.ASM
+API BOOL, RemoveFontResource, TEXT, <ASM>
+P_CLPSTRHRSRC lpFileName ; ** null-terminated filename or handle to
+ ; loaded resource handle in LOWORD
+
+; in FONTENG2.ASM (new for Win 3.1)
+API BOOL, CreateScalableFontResource, TEXT, <ASM>
+F_VALUE fEmbed, 1
+P_CLPSTR lpResFileName
+P_CLPSTR lpFntFileName
+P_CLPSTR0 lpCurrentPath
+
+STRUCT <MAT2>
+F_WORD fract1
+F_int value1
+F_WORD fract2
+F_int value2
+F_WORD fract2
+F_int value4
+F_WORD fract4
+F_int value4
+ENDSTRUCT
+
+_GenLP <P_LPMAT2>,<LP>,%VLcbsMAT2
+
+; in FONTENG2.ASM (new for Win 3.1)
+API DWORD, GetGlyphOutline, TEXT, <ASM>
+P_HDC hdc ; validated by VALID?
+P_WORD cch
+P_FLAGS wFlags, GLYPH_VALID ; ** 0,1,2
+P_LPGLYPHMETRICS lpMetrics
+P_LPGGO0 cbBuffer, lpPoints
+P_LPMAT2 lpXForm
+APIERR
+ mov ax,-1
+ cwd
+APIEND
+
+
+; in FONTENG2.ASM (new for Win 3.1)
+API DWORD, GetFontData, TEXT, <ASM>
+P_HDC hdc ; validated by VALID?
+P_DWORD dwTable
+P_DWORD dwOffset
+P_LPFDATA0 lpBuffer, cbBuffer
+APIERR
+ mov ax,-1
+ cwd
+APIEND
+
+; in FONTENG2.ASM (new for Win 3.1)
+API BOOL, GetCharABCWidths, TEXT, <ASM>
+P_HDC hdc ; validated by VALID?
+P_LPRWBUFFER chFirst, chLast, lpBuffer, 6 ;size dictated by
+ ;char. range. Buffer filled
+ ;in DEBUG Win 3.1 only
+ ;Each entry in lpBuffer is
+ ;of 6 bytes.
+
+; in FONTENG2.ASM (new for Win 3.1)
+API BOOL GetOutlineTextMetrics, TEXT, <ASM>
+P_HDC hdc ;validated by VALID?
+P_LPETM0 cb, lpBuffer ;** NULL ptr. is valid
+ ;Buffer filled in DEBUG Win 3.1
+
+STRUCT <KERNINGPAIR>
+F_WORD wFirst
+F_WORD wSecond
+F_int iKernAmount
+ENDSTRUCT
+
+P_LPKERNINGPAIRS0 macro ckp, lpkp
+ _DefParm <ckp>,2,<opts>
+ _DefParm <lpkp>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,VLcbsKERNINGPAIR ; bx = ckp * sizeof(KERNINGPAIR)
+ mul word ptr _P_&ckp
+ xchg ax,bx
+ mov ax,_P_&lpkp ; cx:ax = lpkp
+ mov cx,_P_&lpkp+2
+ lcall LP0
+ endif
+endm
+
+
+API int GetKerningPairs, TEXT
+P_HDC hdc
+P_LPKERNINGPAIRS0 ckp, lpkp
+
+; in OUTMAN.ASM
+API BOOL, LineTo, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in OUTMAN.ASM
+API DWORD, MoveTo, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in DPXlate
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, MoveToEx, TEXT
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPPOINT0 lpPoint
+
+; in OUTMAN.ASM
+API BOOL, Polyline, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_CLPPOINTBUFFER lpPoints, nCount
+
+; in LINEDDA.ASM
+API void, LineDDA, TEXT, <ASM, FUNNYFRAME>
+P_XY1XY2 x1,y1,x2,y2 ; overflow problem here too?
+P_LPFNLENUM lpFontFunc ; **
+P_DWORD lpData ; CLPVOID0 ?, but often just contains data
+
+; in MULDIV.ASM
+API int, MulDiv, TEXT, <ASM, NOGEN>
+P_int a
+P_int b
+P_intN0 c ;** MulDiv checks for overflow
+
+; in POLYGON.ASM
+API BOOL, Polygon, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_CLPPOINTBUFFER lpPoints, nCount
+
+; in POLYGON.ASM
+API BOOL, PolyPolygon, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_POLYPOLYPOINTS lpPoints, lpPolyCounts, nCount ;lpPolyCounts is a buffer
+ ;of nCount Integers. lpPoints
+ ;is a buffer of POINTS. Size of
+ ;lpPoints det. by sum of all
+ ;integers in lpPolyCounts
+
+ifdef WOW
+API BOOL, PolyPolylineWOW, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_POLYPOLYLARGEPOINTS lpPoints, lpPolyCounts, nCount
+endif
+
+; in PATBL.ASM
+API BOOL, StretchBlt, TEXT, <ASM>
+P_HDCNOIC hdcDst ; validated by VALID? (3.0 and 3.1)
+P_int xDst
+P_int yDst
+P_int cxDst
+P_int cyDst
+P_HDC hdcSrc ; validated by VALID? (3.0 and 3.1)
+P_int xSrc
+P_int ySrc
+P_int cxSrc
+P_int cySrc
+P_ROP rop
+
+; in PATBL.ASM
+API BOOL, BitBlt, TEXT, <ASM>
+P_HDCNOIC hdcDst ; validated by VALID? (3.0 and 3.1)
+P_int xDst
+P_int yDst
+P_int cxDst
+P_int cyDst
+P_HDC0 hdcSrc ; ** hSrcDC Used only if higher 2 bits of each
+P_int cxSrc ; nibble of HIWORD(rop) != lower 2 bis of
+P_int cySrc ; same nibble. Validated by VALID? (3.1 only)
+P_ROP rop ; XSrc and YSrc are int. values.
+
+; in PATBL.ASM
+API BOOL, PatBlt, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+P_int cx
+P_int cy
+P_ROP rop ; ** Only HIWORD used. LOWORD carried
+ ; around for 1.x driver compatiblity
+
+; in GETPOBJ.ASM
+API DWORD, SetBrushOrg, TEXT, <ASM>
+P_HDC hdc ; validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in GETPOBJ.ASM
+API BOOL, UnrealizeObject, TEXT, <ASM>
+P_HGDIOBJUNR hObject ;** brush or palette
+ ;cannot be selected into any DC
+
+; in CLIPMAN.ASM
+API int, ExcludeClipRect, TEXT, <ASM, FUNNYFRAME,NODATA>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in RectStuff
+P_XY1XY2 x1,y1,x2,y2
+
+; in CLIPMAN.ASM
+API int, GetClipBox, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_LPRECT lpRect ;buffer filled in DEBUG Win 3.1
+
+; in CLIPMAN.ASM
+API int, IntersectClipRect, TEXT, <ASM, FUNNYFRAME,NODATA> ; nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in RectStuff
+P_XY1XY2 x1,y1,x2,y2
+
+; in CLIPMAN.ASM
+API int, SelectClipRgn, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+P_HRGN0 hrgn ; validated by VALID? (3.0), VALIDDEBUG? (3.1)
+
+; in RG.ASM
+API HRGN, CreateRectRgnIndirect, TEXT, <ASM>
+P_CLPRECT lpRect
+
+; in RG.ASM
+API BOOL, EqualRgn, TEXT, <ASM>
+P_HRGN hrgn1 ;validated by VALID? (3.0 and 3.1) in RectStuff
+P_HRGN hrgn2 ;validated by VALID? (3.0 and 3.1) in RectStuff
+
+; in RG.ASM
+API BOOL, RectInRegion, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HRGN hrgn ;validated by VALID? (3.0), ValidDebug? (3.1) StuffInRegion
+P_CLPRECT lpRect
+
+; in RG.ASM
+API BOOL, RectVisible, TEXT, <ASM, FUNNYFRAME> ; nogen
+P_HDC hdc ;validated by VALID? (3.0), ValidDebug? (3.1) StuffVisible
+P_CLPRECT lpRect
+
+; in RG.ASM
+API int, OffsetRgn, TEXT, <ASM>
+P_HRGN hrgn ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in RG.ASM
+API int, OffsetClipRgn, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in REGION.ASM
+API HRGN, CreateRectRgn, TEXT, <ASM, NOGEN>
+P_XY1XY2 x1,y1,x2,y2 ; X2-X1 and Y2-Y1 under 32,767 units
+
+; in REGION.ASM
+API int, CombineRgn, TEXT, <ASM>
+P_HRGN hrgnDst ;validated by VALID? (3.0 and 3.1)
+P_HRGN hrgnSrc1 ;validated by VALID? (3.0 and 3.1)
+P_HRGN0 hrgnSrc2 ;validated by VALID? (3.0 and 3.1)
+ ; Can be NULL if code is RGN_COPY
+P_RVALUE code, RGN_MIN, RGN_MAX ;** range 1-5
+
+; in REGION.ASM
+API void, SetRectRgn, TEXT, <ASM>
+P_HRGN hrgn ; validated by VALID? (3.0 and 3.1)
+P_XY1XY2 x1,y1,x2,y2
+
+; in RGOUT.C
+API BOOL, FillRgn, TEXT
+P_HDCNOIC hdc ; Checked by Valid()
+P_HRGN hrgn ; Checked by Valid()
+P_HBRUSH hBrush ; Checked by Valid()
+
+; in RG.ASM
+API BOOL, PtInRegion, TEXT, <ASM>
+P_HRGN hrgn ;checked by Valid() (3.0 and 3.1)
+P_int x
+P_int y
+
+; in RGOUT.C
+API BOOL, PaintRgn, TEXT
+P_HDCNOIC hdc ;checked by Valid() (3.0 and 3.1)
+P_HRGN hrgn ;checked by Valid() (3.0 and 3.1)
+
+; in RG.ASM
+API BOOL, PtVisible, TEXT, <ASM>
+P_HDC hdc ;validated by Valid() (3.0 and 3.1)
+P_int x
+P_int y
+
+; in RGOUT.C
+API BOOL, FrameRgn, TEXT
+P_HDCNOIC hdc ; Checked by Valid()
+P_HRGN hrgn ; Checked by Valid()
+P_HBRUSH hBrush ; Checked by Valid()
+P_int cx
+P_int cy
+
+; in RGOUTZ.ASM
+API BOOL, InvertRgn, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_HRGN hrgn ;validated by VALID? (3.0 and 3.1)
+
+; in OBJSEL.ASM
+API HANDLE, SelectObject, TEXT, <ASM, ATMFRAMEDS>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+P_HGDIOBJSEL hObj ; ** validated by VALID? (3.0 and 3.1)
+ ; only pens, brushes, fonts, bitmaps &
+ ; regions (no palettes)
+
+; in COLOR.ASM
+API DWORD, SetTextColor, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+P_COLORREF color
+
+; in COLOR.ASM
+API DWORD, SetBkColor, TEXT, <ASM>
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1)
+P_COLORREF color
+APIERR
+ mov dh,80h ;; return 0x8000:0x0000
+APIEND
+
+; in NEWXFORM.ASM
+API int, SetBkMode, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1) in WordSet
+P_RVALUE nBkMode, BK_MIN, BK_MAX ; range 1-2
+
+; in NEWXFORM.ASM
+API WORD, SetTextAlign, TEXT, <ASM,FUNNYFRAME> ;nogen
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1) in WordSet
+P_FLAGS wFlags, TA_VALID ; **
+
+; in NEWXFORM.ASM
+API int, SetROP2, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ; validated by VALID? (3.0 and 3.1) in WordSet
+P_RVALUE nDrawMode, R2_MIN,R2_MAX ; ** range 1-16
+
+; in NEWXFORM.ASM
+API int, SetStretchBltMode, TEXT, <ASM, FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in WordSet
+P_RVALUE nStrMode, STR_MIN, STR_MAX ;** range 1-3
+
+; in NEWXFORM.ASM
+API int, SetPolyFillMode, TEXT, <ASM,FUNNYFRAME,NODATA> ;nogen
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1) in WordSet
+P_RVALUE nPolyFillMode,PFILL_MIN, PFILL_MAX ; ** range 1-2
+
+; in NEWXFORM.ASM
+API DWORD, SetWindowOrg, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, SetWindowOrgEx, TEXT
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPPOINT0 lpPoint
+
+; in NEWXFORM.ASM
+API DWORD, SetViewportOrg, TEXT, <ASM>
+P_HDCMETA hdc ;validated by VALID? (3.0 and 3.1)
+P_int x
+P_int y
+
+; in WIN32.C
+API BOOL, SetViewportOrgEx, TEXT
+P_HDCMETA hdc
+P_int x
+P_int y
+P_LPPOINT0 lpPoint
+
+;----------------------------------------------------------------------------;
+; D I B V A L I D A T I O N R O U T I N E S ;
+;----------------------------------------------------------------------------;
+; NOTES: ;
+; ;
+; (1). The size of a color table entry is sizeof RGB_TRIPLE for a core DIB ;
+; header and RGB_QUAD for a info DIB header. However, if wUsage ;
+; indicates a npalette usage, the size per entry is 2 bytes. ;
+; ;
+; (2). The lpInfoHeader paramater in CreateDIBitmap may not have a color ;
+; table in the header. ;
+; ;
+; (3). For SetDIBits/GetDIBits and SetDIBitsToDevice, a 'numScans' parameter ;
+; specifies the size of the DIBits. The buffer may not contain the ;
+; complete DIB. ;
+; ;
+; However, in the case of StretchDIBits, the entire DIB buffer should ;
+; be present and the height of the DIB should be picked up from the ;
+; associated header. Likewise, if an initializer DIB is provided in the ;
+; CreateDIBitmap call, it has to have a complete DIB buffer. ;
+; ;
+; (4). SetDIBitsToDevice specifies a rectangle in the DIB. This is the only ;
+; part of the DIB that will be accessed. The validation code should ;
+; figure out the amount of the DIB buffer that will need to ve accessed ;
+; and validate that the buffer is big enough for it. ;
+; ;
+; (5). If the DIB is RLE compressed and the biSizeImage field is non zero, ;
+; we will use that size to validate the length of the DIB buffer. ;
+; ;
+; (6). The validation code will not validate the bits per pixel and the ;
+; biCompression fields. This is to allow expansion of these fields in ;
+; the future. The validation code for these would instead be done in ;
+; the DIB simulation code. ;
+;----------------------------------------------------------------------------;
+
+; in DIBITM.ASM
+API int, SetDIBits, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_HANDLE hBitmap ;validated by VALID? (3.1 only)
+ ;must not be selected into a DC
+P_WORD nStartScan
+P_CLPBITSINFOBUFFER nNumScans, lpBits, lpBitsInfo, wUsage
+ ;** lpBits size depends on number of
+ ;scans and info. in lpBitsInfo
+ ;lpBitsInfo points to BITMAPINFO
+ ;or BITMAPCOREINFO
+
+; in DIBITM.ASM
+API HBITMAP, CreateDIBitmap, TEXT, <ASM>
+P_HDCNOIC hdc ; validated by VALID? (3.0 and 3.1)
+P_CLPBITMAPINFOHEADER lpInfoHeader ; ** ptr. to BITMAPINFOHEADER or BITMAPCOREHEADER
+P_CLPDIBITMAP0 dwUsage, lpInitBits, lpInitInfo, wUsage
+ ; ** lpInitBits NULL if
+ ; dwUsage is not CBM_INIT
+ ; Size of lpInitBits depends
+ ; on fields in info. block
+ ; lpInitInfo points to BITMAPINFO
+ ; or BITMAPCOREINFO
+
+; in DIBITM.ASM
+API int, SetDIBitsToDevice, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_WORD xDst
+P_WORD yDst
+P_WORD cxDst
+P_CLPRECTBITSINFOBUFFER cyDst, xSrc, ySrc, nStartScan,nNumScans, lpBits, lpBitsInfo, wUsage
+ ;** lpBits size depends on number of
+ ;scans and info. in lpBitsInfo
+ ;lpBitsInfo points to BITMAPINFO
+ ;or BITMAPCOREINFO
+
+; in DIBITM.ASM
+API int, GetDIBits, TEXT, <ASM>
+P_HDC hdc ;validated by VALID? (3.0 and 3.1)
+P_HANDLE hBitmap ;validated by VALID? (3.1 only)
+P_WORD nStartScan
+P_LPBITSINFOBUFFER0 nNumScans, lpBits, lpBitsInfo, wUsage
+ ;**lpBits
+ ;can be NULL.
+ ;buffer size depends on number of
+ ;scans and info. in lpBitsInfo
+ ;lpBitsInfo is a ptr. to
+ ;BITMAPINFO or BITMAPCOREINFO
+
+; in DIBSTRCH.ASM
+API int, StretchDIBits, TEXT, <ASM>
+P_HDCNOIC hdc ;validated by VALID? (3.0 and 3.1)
+P_WORD xDst
+P_WORD yDst
+P_WORD cxDst
+P_WORD cyDst
+P_WORD xSrc
+P_WORD ySrc
+P_WORD cxSrc
+P_WORD cySrc
+P_CFULLLPBITSINFOBUFFER lpBits, lpBitsInfo, wUsage
+ ;** lpBits size depends on height
+ ;and info. in lpBitsInfo
+ ;lpBitsInfo points to BITMAPINFO
+ ;or BITMAPCOREINFO
+P_ROP rop
+
+;----------------------------------------------------------------------------;
+; in TEXTOUT.C
+API BOOL, ExtTextOut, TEXT, <ATMFRAMEDS>
+P_HDCNOIC hdc ; checked by Valid()
+P_int x
+P_int y
+P_FLAGS flags, ETO_VALID ; ** (1,2,4)
+P_CLPRECT0 lprc
+P_CLPETOBUF lpString, nCount, lpDx ;lpDx is NULL or has nCount integers
+
+
+; in TEXTOUT.C
+API BOOL, TextOut, TEXT
+P_HDCNOIC hdc
+P_int X
+P_int Y
+P_CLPBUFFER lpString, nCount
diff --git a/private/mvdm/wow16/gdi/gdi.asm b/private/mvdm/wow16/gdi/gdi.asm
new file mode 100644
index 000000000..b0df151be
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi.asm
@@ -0,0 +1,551 @@
+ TITLE GDI.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; GDI.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 25-Jan-1991 Jeff Parsons (jeffpar)
+; Created.
+;
+
+ ; Some applications require that USER have a heap. This means
+ ; we must always have: LIBINIT equ 1
+ LIBINIT equ 1
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowgdi.inc
+ include cmacros.inc
+ include metacons.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+ifdef LIBINIT
+externFP LocalInit
+endif
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+GDI_Identifier db 'GDI16 Data Segment'
+
+ Stocks dw 17 dup (0) ; Stock Object Handles
+public FTRAPPING0
+FTRAPPING0 dw 0
+sEnd DATA
+
+;
+; GP fault exception handler table definition
+;
+
+createSeg _GPFIX0,GPFIX0,WORD,PUBLIC,CODE,IGROUP ; GP fault trapping
+
+sBegin GPFIX0
+__GP label word
+public __GP
+sEnd GPFIX0
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+externFP GetStockObject
+cProc GDI16,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+
+ cBegin <nogen>
+ IFDEF LIBINIT
+ ; push params and call user initialisation code
+
+ push di ;hModule
+
+ ; if we have a local heap declared then initialize it
+
+ jcxz no_heap
+
+ push 0 ;segment
+ push 0 ;start
+ push cx ;length
+ call LocalInit
+
+no_heap:
+ ;
+ ; I didn't put a call to LibMain here, because I didn't think we
+ ; had anything to do.
+ ;
+ pop di
+ mov ax,1
+ ELSE
+ mov ax,1
+ ENDIF
+
+ push ax
+ push di
+ push si
+
+ xor si,si
+ xor di,di
+my_loop:
+ push si
+ call GetStockObject
+ mov ds:[di + offset Stocks],ax
+ add di,2
+ inc si
+ cmp si,16 ; Stock Objects have an index range of 0 through 16
+ jna my_loop
+
+ pop si
+ pop di
+ pop ax
+ ret
+ cEnd <nogen>
+
+assume DS:nothing
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+assume DS:nothing
+
+;*--------------------------------------------------------------------------*
+;*
+;* CheckStockObject()
+;*
+;* Checks to see if the stock object is already fetched.
+;*
+;*--------------------------------------------------------------------------*
+
+cProc CheckStockObject, <PUBLIC, NEAR>
+parmW nIndex
+parmD lpReturn ; Callers Return Address
+;parmW wBP ; Thunk saved BP
+;parmW wDS ; Thunk saved DS
+cBegin
+ mov bx,nIndex
+ cmp bx,16
+ ja @f
+ push ds
+ mov ax,seg Stocks
+ mov ds,ax
+ shl bx,1
+ mov ax,ds:[bx+offset Stocks]
+ pop ds
+ or ax,ax
+ jz @f
+
+ pop bp
+ add sp,2 ; skip thunk IP
+
+ ; mov sp,bp
+ ; pop bp
+ ; lea sp,-2[bp]
+ ; pop ds
+ ; pop bp
+ ; dec bp
+ retf 2 ; 2 bytes to pop
+@@:
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+
+cEnd <nogen>
+
+
+externFP GlobalHandle
+
+cProc IGetMetafileBits, <PUBLIC, FAR>
+parmW hmf
+cBegin
+ ; return (GlobalHandle(hMF) & 0xffff) ? hMF : FALSE;
+
+ push hmf
+ call GlobalHandle
+ cmp ax, 0
+ je @f
+ mov ax, hmf
+@@:
+cEnd
+
+
+cProc ISetMetafileBits, <PUBLIC, FAR>
+parmW hmf
+cBegin
+ ; return (hBits)
+ mov ax, hmf
+cEnd
+
+externFP GlobalReAlloc
+cProc ISetMetafileBitsBetter, <PUBLIC, FAR>
+parmW hmf
+cBegin
+ ; return (GlobalReAlloc(hBits, 0L, GMEM_MODIFY | GMEM_SHAREALL));
+ push hmf
+ push 0
+ push 0
+ push 2080h ;; GMEM_MODIFY or GMEM_SHAREALL
+ call GlobalReAlloc
+cEnd
+
+
+
+ GDIThunk CLOSEMETAFILE
+ GDIThunk COPYMETAFILE
+ GDIThunk CREATEMETAFILE
+ GDIThunk DELETEMETAFILE
+ GDIThunk GETMETAFILE
+ ; GDIThunk GETMETAFILEBITS
+ GDIThunk ENUMMETAFILE
+ DGDIThunk ISVALIDMETAFILE, 0
+ GDIThunk PLAYMETAFILE
+ GDIThunk PLAYMETAFILERECORD
+ ; GDIThunk SETMETAFILEBITS
+
+FUN_WOWADDFONTRESOURCE EQU FUN_ADDFONTRESOURCE
+ DGDIThunk WOWADDFONTRESOURCE %(size ADDFONTRESOURCE16)
+
+ GDIThunk ANIMATEPALETTE
+ GDIThunk ARC
+ GDIThunk BITBLT
+ DGDIThunk BRUTE
+ GDIThunk CHORD
+ DGDIThunk CLOSEJOB
+ GDIThunk COMBINERGN
+ GDIThunk COMPATIBLEBITMAP,6
+ DGDIThunk COPY,10
+ GDIThunk CREATEBITMAP
+ GDIThunk CREATEBITMAPINDIRECT
+ GDIThunk CREATEBRUSHINDIRECT
+ GDIThunk CREATECOMPATIBLEBITMAP
+ GDIThunk CREATECOMPATIBLEDC
+ GDIThunk CREATEDC
+ GDIThunk CREATEDIBITMAP
+FUN_WOWCREATEDIBPATTERNBRUSH EQU FUN_CREATEDIBPATTERNBRUSH
+ DGDIThunk WOWCREATEDIBPATTERNBRUSH, %(size CREATEDIBPATTERNBRUSH16)
+ GDIThunk CREATEDISCARDABLEBITMAP
+ DGDIThunk CREATEELLIPTICRGN
+ GDIThunk CREATEELLIPTICRGNINDIRECT
+ GDIThunk CREATEFONT
+ GDIThunk CREATEFONTINDIRECT
+ GDIThunk CREATEHATCHBRUSH
+ GDIThunk CREATEIC
+ GDIThunk CREATEPALETTE
+ GDIThunk CREATEPATTERNBRUSH
+ GDIThunk CREATEPEN
+ GDIThunk CREATEPENINDIRECT
+ GDIThunk CREATEPOLYGONRGN
+ GDIThunk CREATEPOLYPOLYGONRGN
+;;; DGDIThunk CREATEPQ,2
+ GDIThunk CREATEREALBITMAP,14
+ GDIThunk CREATEREALBITMAPINDIRECT,6
+ DGDIThunk CREATERECTRGN
+ GDIThunk CREATERECTRGNINDIRECT
+ DGDIThunk CREATEROUNDRECTRGN
+ DGDIThunk CREATESOLIDBRUSH
+ DGDIThunk CREATEUSERBITMAP
+ DGDIThunk CREATEUSERDISCARDABLEBITMAP,6
+ DGDIThunk DEATH,2
+ GDIThunk DELETEABOVELINEFONTS
+ GDIThunk DELETEDC
+ DGDIThunk DELETEJOB,4
+ GDIThunk DELETEOBJECT
+;;; DGDIThunk DELETEPQ,2
+ DGDIThunk DEVICECOLORMATCH,8
+ GDIThunk DEVICEMODE
+ DGDIThunk DMBITBLT
+ DGDIThunk DMCOLORINFO,12
+ DGDIThunk DMENUMDFONTS,16
+ DGDIThunk DMENUMOBJ,14
+ DGDIThunk DMOUTPUT,28
+ DGDIThunk DMPIXEL,16
+ DGDIThunk DMREALIZEOBJECT,18
+ DGDIThunk DMSCANLR,14
+ DGDIThunk DMSTRBLT,30
+ DGDIThunk DMTRANSPOSE,10
+ GDIThunk DPTOLP
+ GDIThunk DPXLATE,8
+ GDIThunk ELLIPSE
+ DGDIThunk ENDSPOOLPAGE,2
+ GDIThunk ENUMCALLBACK,14
+ GDIThunk ENUMFONTS
+ GDIThunk ENUMOBJECTS
+ GDIThunk EQUALRGN
+ GDIThunk ESCAPE
+ GDIThunk EXCLUDECLIPRECT
+ DGDIThunk EXCLUDEVISRECT,10
+ GDIThunk EXTDEVICEMODE
+ GDIThunk EXTFLOODFILL
+;;; DGDIThunk EXTRACTPQ,2
+ GDIThunk EXTTEXTOUT
+ DGDIThunk FASTWINDOWFRAME,14
+ GDIThunk FILLRGN
+ DGDIThunk FINALGDIINIT,2
+ GDIThunk FLOODFILL
+ GDIThunk FRAMERGN
+ DGDIThunk GDIINIT2,4
+ DGDIThunk GDIMOVEBITMAP,2
+ DGDIThunk GDIREALIZEPALETTE,2
+ DGDIThunk GDISELECTPALETTE,6
+ GDIThunk GETASPECTRATIOFILTER
+ GDIThunk GETBITMAPBITS
+ GDIThunk GETBITMAPDIMENSION
+ DGDIThunk GETBKCOLOR
+ DGDIThunk GETBKMODE
+ DGDIThunk GETBRUSHORG
+ GDIThunk GETCHARWIDTH
+ GDIThunk GETCLIPBOX
+ DGDIThunk GETCLIPRGN
+ DGDIThunk GETCURLOGFONT,2
+ GDIThunk GETCURRENTOBJECT
+ DGDIThunk GETCURRENTPOSITION
+ DGDIThunk GETDCORG
+ DGDIThunk GETDCSTATE,2
+ GDIThunk GETDEVICECAPS
+ GDIThunk GETDIBITS
+ GDIThunk GETENVIRONMENT
+ DGDIThunk GETMAPMODE
+ GDIThunk GETNEARESTCOLOR
+ GDIThunk GETNEARESTPALETTEINDEX
+ GDIThunk GETOBJECT
+ GDIThunk GETPALETTEENTRIES
+ DGDIThunk GETPHYSICALFONTHANDLE,2
+ GDIThunk GETPIXEL
+ DGDIThunk GETPOLYFILLMODE
+ DGDIThunk GETRELABS
+ GDIThunk GETREGIONDATA
+ GDIThunk GETRGNBOX
+ DGDIThunk GETROP2
+ DGDIThunk GETSPOOLJOB,6
+ PGDIThunk GETSTOCKOBJECT,CheckStockObject
+ DGDIThunk GETSTRETCHBLTMODE
+ GDIThunk GETSYSTEMPALETTEENTRIES
+ GDIThunk GETSYSTEMPALETTEUSE
+ DGDIThunk GETTEXTALIGN
+ GDIThunk GETTEXTCHARACTEREXTRA
+ DGDIThunk GETTEXTCOLOR
+ GDIThunk GETTEXTEXTENT
+ GDIThunk GETTEXTFACE
+ GDIThunk GETTEXTMETRICS
+ DGDIThunk GETVIEWPORTEXT
+ DGDIThunk GETVIEWPORTORG
+ DGDIThunk GETWINDOWEXT
+ DGDIThunk GETWINDOWORG
+ GDIThunk GSV,2
+ DGDIThunk INQUIREVISRGN
+;;; DGDIThunk INSERTPQ,6
+ GDIThunk INTERNALCREATEDC,16
+ GDIThunk INTERSECTCLIPRECT
+ DGDIThunk INTERSECTVISRECT,10
+ GDIThunk INVERTRGN
+ DGDIThunk ISDCCURRENTPALETTE,2
+ DGDIThunk ISDCDIRTY,6
+ GDIThunk LINEDDA
+ GDIThunk LINETO
+ GDIThunk LPTODP
+ GDIThunk LVBUNION,10
+ GDIThunk MFDRAWTEXT,14
+;;; DGDIThunk MINPQ,2
+ GDIThunk MOVETO
+; DGDIThunk MULDIV ; thunk locally
+ GDIThunk OFFSETCLIPRGN
+ GDIThunk OFFSETORG,6
+ GDIThunk OFFSETRGN
+ GDIThunk OFFSETVIEWPORTORG
+ DGDIThunk OFFSETVISRGN,6
+ GDIThunk OFFSETWINDOWORG
+ DGDIThunk OPENJOB,10
+ GDIThunk PAINTRGN
+ GDIThunk PATBLT
+ GDIThunk PIE
+ GDIThunk PIXTOLINE,16
+ GDIThunk POLYGON
+ GDIThunk POLYLINE
+ GDIThunk POLYPOLYGON
+ GDIThunk POLYPOLYLINEWOW ; New for ACAD guys.
+ GDIThunk PTINREGION
+ GDIThunk PTVISIBLE
+ DGDIThunk QUERYJOB,4
+ GDIThunk RCOS,4
+ DGDIThunk REALIZEDEFAULTPALETTE,2
+ GDIThunk RECTANGLE
+ GDIThunk RECTINREGION
+ GDIThunk RECTSTUFF,10
+ GDIThunk RECTVISIBLE
+
+FUN_WOWREMOVEFONTRESOURCE EQU FUN_REMOVEFONTRESOURCE
+ DGDIThunk WOWREMOVEFONTRESOURCE %(size REMOVEFONTRESOURCE16)
+
+ GDIThunk RESIZEPALETTE
+ GDIThunk RESTOREDC
+ DGDIThunk RESTOREVISRGN,2
+ DGDIThunk RESURRECTION,14
+ GDIThunk ROUNDRECT
+ GDIThunk RSIN,4
+ GDIThunk SAVEDC
+ DGDIThunk SAVEVISRGN,2
+ GDIThunk SCALEEXT,10
+ GDIThunk SCALEVIEWPORTEXT
+ GDIThunk SCALEWINDOWEXT
+ DGDIThunk SCANLR,12
+ GDIThunk SELECTCLIPRGN
+ GDIThunk SELECTOBJECT
+ DGDIThunk SELECTVISRGN,4
+ GDIThunk SETBITMAPBITS
+ GDIThunk SETBITMAPDIMENSION
+ GDIThunk SETBKCOLOR
+ GDIThunk SETBKMODE
+ GDIThunk SETBRUSHORG
+ DGDIThunk SETDCORG,6
+ DGDIThunk SETDCSTATE,4
+ DGDIThunk SETDCSTATUS,8
+ GDIThunk SETDIBITS
+ GDIThunk SETDIBITSTODEVICE
+ GDIThunk SETENVIRONMENT
+ GDIThunk SETMAPMODE
+ GDIThunk SETMAPPERFLAGS
+ GDIThunk SETPALETTEENTRIES
+ GDIThunk SETPIXEL
+ GDIThunk SETPOLYFILLMODE
+ GDIThunk SETRECTRGN
+ DGDIThunk SETRELABS
+ GDIThunk SETROP2
+ GDIThunk SETSTRETCHBLTMODE
+ GDIThunk SETSYSTEMPALETTEUSE
+ GDIThunk SETTEXTALIGN
+ GDIThunk SETTEXTCHARACTEREXTRA
+ GDIThunk SETTEXTCOLOR
+ GDIThunk SETTEXTJUSTIFICATION
+ GDIThunk SETVIEWPORTEXT
+ GDIThunk SETVIEWPORTORG
+ GDIThunk SETWINDOWEXT
+ GDIThunk SETWINDOWORG
+ GDIThunk SETWINVIEWEXT,6
+ DGDIThunk SHRINKGDIHEAP
+;;; DGDIThunk SIZEPQ,4
+ DGDIThunk STARTSPOOLPAGE,2
+ GDIThunk STRETCHBLT
+ GDIThunk STRETCHDIBITS
+ GDIThunk STUFFINREGION,6
+ GDIThunk STUFFVISIBLE,6
+ GDIThunk TEXTOUT
+ GDIThunk UNREALIZEOBJECT
+ GDIThunk UPDATECOLORS
+ GDIThunk WORDSET,4
+ DGDIThunk WRITEDIALOG,8
+ DGDIThunk WRITESPOOL,8
+
+; New Win 3.1 thunks
+
+ DGDIThunk BITMAPBITS,10 ;Internal
+
+ DGDIThunk SETDCHOOK,10 ;Internal
+ DGDIThunk GETDCHOOK,6 ;Internal
+ DGDIThunk SETHOOKFLAGS,4 ;Internal
+ DGDIThunk SETBOUNDSRECT
+ DGDIThunk GETBOUNDSRECT
+ DGDIThunk SELECTBITMAP,4 ;Internal
+ ; GDIThunk SETMETAFILEBITSBETTER ;New for 3.1
+
+ DGDIThunk DMEXTTEXTOUT,40
+ DGDIThunk DMGETCHARWIDTH,24
+ DGDIThunk DMSTRETCHBLT,40
+ DGDIThunk DMDIBBITS,26
+ DGDIThunk DMSTRETCHDIBITS,50
+ DGDIThunk DMSETDIBTODEV,32
+
+
+ DGDIThunk DELETESPOOLPAGE,2 ; new for 3.1
+ DGDIThunk SPOOLFILE ; new for 3.1
+
+ DGDIThunk ENGINEENUMERATEFONT,12 ;Internal
+ DGDIThunk ENGINEDELETEFONT,4 ;Internal
+ DGDIThunk ENGINEREALIZEFONT,12 ;Internal
+ DGDIThunk ENGINEGETCHARWIDTH,12 ;Internal
+ DGDIThunk ENGINESETFONTCONTEXT,6 ;Internal
+ DGDIThunk ENGINEGETGLYPHBMP,22 ;Internal
+ DGDIThunk ENGINEMAKEFONTDIR,10 ;Internal
+ GDIThunk GETCHARABCWIDTHS
+ GDIThunk GETOUTLINETEXTMETRICS
+ GDIThunk GETGLYPHOUTLINE
+ GDIThunk CREATESCALABLEFONTRESOURCE
+ GDIThunk GETFONTDATA
+ DGDIThunk CONVERTOUTLINEFONTFILE,12 ;internal
+ DGDIThunk GETRASTERIZERCAPS
+ DGDIThunk ENGINEEXTTEXTOUT,42 ;internal
+ GDIThunk ENUMFONTFAMILIES
+ GDIThunk GETKERNINGPAIRS
+
+
+ GDIThunk RESETDC
+ GDIThunk STARTDOC
+ GDIThunk ENDDOC
+ GDIThunk STARTPAGE
+ GDIThunk ENDPAGE
+ GDIThunk SETABORTPROC
+ GDIThunk ABORTDOC
+
+
+ DGDIThunk GDISEEGDIDO,8 ;Internal
+
+ DGDIThunk GDITASKTERMINATION,2 ;Internal
+ DGDIThunk SETOBJECTOWNER,4 ;Internal
+ DGDIThunk ISGDIOBJECT
+ DGDIThunk MAKEOBJECTPRIVATE,4 ;Internal
+ DGDIThunk FIXUPBOGUSPUBLISHERMETAFILE,6 ;Internal
+ DGDIThunk RECTVISIBLE_EHH,6
+ DGDIThunk RECTINREGION_EHH,6
+ DGDIThunk UNICODETOANSI,8 ;Internal
+
+
+ GDIThunk GETBITMAPDIMENSIONEX
+ DGDIThunk GETBRUSHORGEX
+ DGDIThunk GETCURRENTPOSITIONEX
+ GDIThunk GETTEXTEXTENTPOINT
+ DGDIThunk GETVIEWPORTEXTEX
+ DGDIThunk GETVIEWPORTORGEX
+ DGDIThunk GETWINDOWEXTEX
+ DGDIThunk GETWINDOWORGEX
+ GDIThunk OFFSETVIEWPORTORGEX
+ GDIThunk OFFSETWINDOWORGEX
+ GDIThunk SETBITMAPDIMENSIONEX
+ GDIThunk SETVIEWPORTEXTEX
+ GDIThunk SETVIEWPORTORGEX
+ GDIThunk SETWINDOWEXTEX
+ GDIThunk SETWINDOWORGEX
+ GDIThunk MOVETOEX
+ GDIThunk SCALEVIEWPORTEXTEX
+ GDIThunk SCALEWINDOWEXTEX
+ GDIThunk GETASPECTRATIOFILTEREX
+
+ DGDITHUNK CREATEDIBSECTION ; new for chicago
+ DGDITHUNK GETDIBCOLORTABLE ; new for chicago
+ DGDITHUNK SETDIBCOLORTABLE ; new for chicago
+
+cProc QUERYABORT,<PUBLIC,FAR,PASCAL,NODATA,WIN>
+ parmw hdc
+ parmw res
+cBegin
+ ; Not Supported
+ mov ax,1
+cEnd
+
+sEnd CODE
+
+end GDI16
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/gdi/gdi.def b/private/mvdm/wow16/gdi/gdi.def
new file mode 100644
index 000000000..1b1f1456c
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi.def
@@ -0,0 +1,405 @@
+LIBRARY GDI
+DESCRIPTION 'WOW REPLACEMENT GDI'
+EXETYPE WINDOWS
+STUB '..\BIN\WINSTUB.EXE'
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+HEAPSIZE 2048
+EXPORTS
+ WEP ;Internal
+
+ SETBKCOLOR @ 1
+ SETBKMODE @ 2 NODATA
+ SETMAPMODE @ 3
+ SETROP2 @ 4 NODATA
+ SETRELABS @ 5 NODATA ;Internal
+ SETPOLYFILLMODE @ 6 NODATA
+ SETSTRETCHBLTMODE @ 7 NODATA
+ SETTEXTCHARACTEREXTRA @ 8
+ SETTEXTCOLOR @ 9
+ SETTEXTJUSTIFICATION @10
+ SETWINDOWORG @11
+ SETWINDOWEXT @12 NODATA
+ SETVIEWPORTORG @13
+ SETVIEWPORTEXT @14 NODATA
+ OFFSETWINDOWORG @15 NODATA
+ SCALEWINDOWEXT @16 NODATA
+ OFFSETVIEWPORTORG @17 NODATA
+ SCALEVIEWPORTEXT @18 NODATA
+ LINETO @19
+ MOVETO @20
+ EXCLUDECLIPRECT @21 NODATA
+ INTERSECTCLIPRECT @22 NODATA
+ ARC @23
+ ELLIPSE @24
+ FLOODFILL @25
+ PIE @26
+ RECTANGLE @27
+ ROUNDRECT @28
+ PATBLT @29
+ SAVEDC @30
+ SETPIXEL @31
+ OFFSETCLIPRGN @32
+ TEXTOUT @33
+ BITBLT @34
+ STRETCHBLT @35
+ POLYGON @36
+ POLYLINE @37
+ ESCAPE @38 ; Patched by ATM
+ RESTOREDC @39
+ FILLRGN @40
+ FRAMERGN @41
+ INVERTRGN @42
+ PAINTRGN @43
+
+; BLTREGION @40
+
+
+
+ SELECTCLIPRGN @44
+ SELECTOBJECT @45 ; Patched by ATM
+;;; BITMAPBITS @46 ;Internal
+;
+; GP fault exception handler table
+;
+ __GP @46 RESIDENTNAME ;Internal
+
+ COMBINERGN @47
+ CREATEBITMAP @48
+ CREATEBITMAPINDIRECT @49
+ CREATEBRUSHINDIRECT @50
+ CREATECOMPATIBLEBITMAP @51 NODATA
+ CREATECOMPATIBLEDC @52
+ CREATEDC @53 NODATA ; Patched by ATM
+ CREATEELLIPTICRGN @54
+ CREATEELLIPTICRGNINDIRECT @55
+ CREATEFONT @56
+ CREATEFONTINDIRECT @57
+ CREATEHATCHBRUSH @58
+
+ CREATEPATTERNBRUSH @60
+ CREATEPEN @61
+ CREATEPENINDIRECT @62
+ CREATEPOLYGONRGN @63
+ CREATERECTRGN @64
+ CREATERECTRGNINDIRECT @65
+ CREATESOLIDBRUSH @66
+ DPTOLP @67 NODATA
+ DELETEDC @68 ; Patched by ATM
+ DELETEOBJECT @69
+ ENUMFONTS @70 ; Patched by ATM
+ ENUMOBJECTS @71
+ EQUALRGN @72
+ EXCLUDEVISRECT @73 NODATA ;Internal
+ GETBITMAPBITS @74 NODATA
+ GETBKCOLOR @75
+ GETBKMODE @76 NODATA
+ GETCLIPBOX @77
+ GETCURRENTPOSITION @78 NODATA
+ GETDCORG @79 NODATA
+ GETDEVICECAPS @80
+ GETMAPMODE @81 NODATA
+ GETOBJECT @82
+ GETPIXEL @83
+ GETPOLYFILLMODE @84 NODATA
+ GETROP2 @85 NODATA
+ GETRELABS @86 NODATA ;Internal
+ GETSTOCKOBJECT @87
+ GETSTRETCHBLTMODE @88 NODATA
+ GETTEXTCHARACTEREXTRA @89
+ GETTEXTCOLOR @90
+ GETTEXTEXTENT @91 ; Patched by ATM
+ GETTEXTFACE @92
+ GETTEXTMETRICS @93
+ GETVIEWPORTEXT @94 NODATA
+ GETVIEWPORTORG @95 NODATA
+ GETWINDOWEXT @96 NODATA
+ GETWINDOWORG @97 NODATA
+ INTERSECTVISRECT @98 NODATA ;Internal
+ LPTODP @99 NODATA
+ LINEDDA @100
+ OFFSETRGN @101
+ OFFSETVISRGN @102 ;Internal
+ PTVISIBLE @103
+ RECTVISIBLE @104
+ SELECTVISRGN @105 ;Internal
+ SETBITMAPBITS @106 NODATA
+ SETDCORG @117 ;Internal
+;;;;INTERNALCREATEDC @118 ;Internal
+ ADDFONTRESOURCE @119
+; GETCONTINUINGTEXTEXTENT @120
+ DEATH @121 ;Internal
+ RESURRECTION @122 ;Internal
+ PLAYMETAFILE @123 ; Patched by ATM
+ GETMETAFILE @124
+ CREATEMETAFILE @125
+ CLOSEMETAFILE @126
+ DELETEMETAFILE @127
+ MULDIV @128
+ SAVEVISRGN @129 ;Internal
+ RESTOREVISRGN @130 ;Internal
+ INQUIREVISRGN @131 ;Internal
+ SETENVIRONMENT @132
+ GETENVIRONMENT @133
+ GETRGNBOX @134
+ SCANLR @135 ;Internal
+ REMOVEFONTRESOURCE @136
+;;;;GSV @137 ;Internal
+;;;;DPXLATE @138 ;Internal
+;;;;SETWINVIEWEXT @139 ;Internal
+;;;;SCALEEXT @140 ;Internal
+;;;;WORDSET @141 ;Internal
+;;;;RECTSTUFF @142 ;Internal
+;;;;OFFSETORG @143 ;Internal
+; LOCKDC @144 NODATA
+; UNLOCKDC @145 NODATA
+; LOCKUNLOCK @146
+; GDI_FARFRAME = _TEXT_FARFRAME @147
+ SETBRUSHORG @148
+ GETBRUSHORG @149 NODATA
+ UNREALIZEOBJECT @150
+ COPYMETAFILE @151
+;; GDIINITAPP @152
+ CREATEIC @153 NODATA
+ GETNEARESTCOLOR @154
+ QUERYABORT @155
+ CREATEDISCARDABLEBITMAP @156 NODATA
+;;;;COMPATIBLEBITMAP @157 ;Internal
+;;;;ENUMCALLBACK @158 ;Internal
+;
+ GETMETAFILEBITS @159
+ SETMETAFILEBITS @160
+;
+
+ PTINREGION @161
+ GETBITMAPDIMENSION @162
+ SETBITMAPDIMENSION @163
+;;;;PIXTOLINE @164 ;Internal
+
+; CREATELVB @165
+; SELECTLVB @166
+; ENABLELVB @167
+; UPDATELVB @168
+ ISDCDIRTY @169 ;Internal
+ SETDCSTATUS @170 ;Internal
+;;;;LVBUNION @171 ;Internal
+; GETLVB @171
+ SETRECTRGN @172
+ GETCLIPRGN @173 ;Internal
+; BLOAT @174
+;
+ ENUMMETAFILE @175
+ PLAYMETAFILERECORD @176
+;
+
+;;;;RCOS @177 ;Internal
+;;;;RSIN @178 ;Internal
+ GETDCSTATE @179 ;Internal
+ SETDCSTATE @180 ;Internal
+ RECTINREGION @181
+; REQUESTSEM @182
+; CLEARSEM @183
+;;;;STUFFVISIBLE @184 ;Internal
+;;;;STUFFINREGION @185 ;Internal
+
+;;;;DELETEABOVELINEFONTS @186 ;Internal
+
+; SETFONTMAPPERWEIGHTS @187
+; GETTEXTEXTENTEX @188 ;Internal
+
+ SETDCHOOK @190 ;Internal
+ GETDCHOOK @191 ;Internal
+ SETHOOKFLAGS @192 ;Internal
+ SETBOUNDSRECT @193
+ GETBOUNDSRECT @194
+ SELECTBITMAP @195 ;Internal
+ SETMETAFILEBITSBETTER @196 ;New for 3.1
+
+ DMBITBLT @201 NODATA
+ DMCOLORINFO @202 NODATA
+ DMENUMDFONTS @206 NODATA
+ DMENUMOBJ @207 NODATA
+ DMOUTPUT @208 NODATA
+ DMPIXEL @209 NODATA
+ DMREALIZEOBJECT @210 NODATA
+ DMSTRBLT @211
+ DMSCANLR @212 NODATA
+ BRUTE @213
+ DMEXTTEXTOUT @214
+ DMGETCHARWIDTH @215
+ DMSTRETCHBLT @216
+ DMDIBBITS @217
+ DMSTRETCHDIBITS @218
+ DMSETDIBTODEV @219
+ DMTRANSPOSE @220
+
+ CREATEPQ @230 NODATA
+ MINPQ @231 NODATA
+ EXTRACTPQ @232 NODATA
+ INSERTPQ @233 NODATA
+ SIZEPQ @234 NODATA
+ DELETEPQ @235 NODATA
+
+ OPENJOB @240
+ WRITESPOOL @241
+ WRITEDIALOG @242
+ CLOSEJOB @243
+ DELETEJOB @244
+ GETSPOOLJOB @245
+ STARTSPOOLPAGE @246
+ ENDSPOOLPAGE @247
+ QUERYJOB @248 ;Internal
+ COPY @250 ;Internal
+; ADDFILESPOOLJOB @251
+; SPOOLESCAPE @252
+ DELETESPOOLPAGE @253 ; new for 3.1
+ SPOOLFILE @254 ; new for 3.1
+
+ ENGINEENUMERATEFONT @300 ;Internal
+ ENGINEDELETEFONT @301 ;Internal
+ ENGINEREALIZEFONT @302 ;Internal
+ ENGINEGETCHARWIDTH @303 ;Internal
+ ENGINESETFONTCONTEXT @304 ;Internal
+ ENGINEGETGLYPHBMP @305 ;Internal
+ ENGINEMAKEFONTDIR @306 ;Internal
+ GETCHARABCWIDTHS @307
+ GETOUTLINETEXTMETRICS @308
+ GETGLYPHOUTLINE @309
+ CREATESCALABLEFONTRESOURCE @310
+ GETFONTDATA @311
+ CONVERTOUTLINEFONTFILE @312 ;internal
+ GETRASTERIZERCAPS @313
+ ENGINEEXTTEXTOUT @314 ;internal
+;;; DUMPEFT @320
+ ENUMFONTFAMILIES @330
+;;;;ENUMFONTSINTERNAL @331 ;internal
+ GETKERNINGPAIRS @332
+
+ GETTEXTALIGN @345
+ SETTEXTALIGN @346
+;;;;MFDRAWTEXT @347 ;Internal
+ CHORD @348
+ SETMAPPERFLAGS @349
+ GETCHARWIDTH @350 ; Patched by ATM
+ EXTTEXTOUT @351 ; Patched by ATM
+ GETPHYSICALFONTHANDLE @352 ;Internal
+ GETASPECTRATIOFILTER @353
+ SHRINKGDIHEAP @354 ;Internal
+ FTRAPPING0 @355 ;Internal
+
+ CREATEPALETTE @360
+ GDISELECTPALETTE @361 ;Internal
+ GDIREALIZEPALETTE @362 ;Internal
+ GETPALETTEENTRIES @363
+ SETPALETTEENTRIES @364
+ REALIZEDEFAULTPALETTE @365 ;Internal
+
+ UPDATECOLORS @366
+ ANIMATEPALETTE @367
+ RESIZEPALETTE @368
+
+ GETNEARESTPALETTEINDEX @370
+;; SELECTCOLORMATCHER @371
+
+ EXTFLOODFILL @372
+
+ SETSYSTEMPALETTEUSE @373
+ GETSYSTEMPALETTEUSE @374
+ GETSYSTEMPALETTEENTRIES @375
+
+ RESETDC @376
+ STARTDOC @377
+ ENDDOC @378
+ STARTPAGE @379
+ ENDPAGE @380
+ SETABORTPROC @381
+ ABORTDOC @382
+
+ FASTWINDOWFRAME @400 ;Internal
+ GDIMOVEBITMAP @401 ;Internal
+ GDIINIT2 @403 ;Internal
+
+ FINALGDIINIT @405 ;Internal
+;;;;CREATEREALBITMAPINDIRECT @406 ;Internal
+ CREATEUSERBITMAP @407 NODATA ;Internal
+;;;;CREATEREALBITMAP @408 ;Internal
+ CREATEUSERDISCARDABLEBITMAP @409 NODATA ;Internal
+ ISVALIDMETAFILE @410 ;Internal
+
+ GETCURLOGFONT @411 ;Internal
+ ISDCCURRENTPALETTE @412 ;Internal
+; GETCLIPPINGRGN @435
+
+ STRETCHDIBITS @439
+ SETDIBITS @440
+ GETDIBITS @441
+ CREATEDIBITMAP @442
+ SETDIBITSTODEVICE @443
+
+ CREATEROUNDRECTRGN @444
+ CREATEDIBPATTERNBRUSH @445
+; GETFONTMAPPERWEIGHTS @446
+; LOCKMONOBITMAP @447
+; UNLOCKMONOBITMAP @448
+
+ DEVICECOLORMATCH @449 ;Internal
+ POLYPOLYGON @450
+ CREATEPOLYPOLYGONRGN @451
+
+ GDISEEGDIDO @452 ;Internal
+
+ GDITASKTERMINATION @460 ;Internal
+ SETOBJECTOWNER @461 ;Internal
+ ISGDIOBJECT @462
+ MAKEOBJECTPRIVATE @463 ;Internal
+ FIXUPBOGUSPUBLISHERMETAFILE @464 ;Internal
+ RECTVISIBLE_EHH @465
+ RECTINREGION_EHH @466
+ UNICODETOANSI @467 ;Internal
+
+; the following functions are added for the NT windows group.
+
+ GETBITMAPDIMENSIONEX @468
+ GETBRUSHORGEX @469 NODATA
+ GETCURRENTPOSITIONEX @470 NODATA
+ GETTEXTEXTENTPOINT @471
+ GETVIEWPORTEXTEX @472 NODATA
+ GETVIEWPORTORGEX @473 NODATA
+ GETWINDOWEXTEX @474 NODATA
+ GETWINDOWORGEX @475 NODATA
+ OFFSETVIEWPORTORGEX @476 NODATA
+ OFFSETWINDOWORGEX @477 NODATA
+ SETBITMAPDIMENSIONEX @478
+ SETVIEWPORTEXTEX @479 NODATA
+ SETVIEWPORTORGEX @480
+ SETWINDOWEXTEX @481 NODATA
+ SETWINDOWORGEX @482
+ MOVETOEX @483
+ SCALEVIEWPORTEXTEX @484 NODATA
+ SCALEWINDOWEXTEX @485 NODATA
+ GETASPECTRATIOFILTEREX @486
+
+ POLYPOLYLINEWOW @490 ; Internal
+
+ CREATEDIBSECTION @489
+ GETDIBCOLORTABLE @603
+ SETDIBCOLORTABLE @602
+
+; ENGINEENUMERATEFONT @500 ;Internal
+; ENGINEDELETEFONT @501 ;internal
+; ENGINEREALIZEFONT @502 ;Internal
+; ENGINEGETCHARWIDTH @503 ;internal
+; ENGINESETFONTCONTEXT @504 ;Internal
+; ENGINEGETGLYPHBMP @505 ;internal
+; ENGINEMAKEFONTDIR @506 ;Internal
+; ENGINEGETABCWIDTHS @507
+; ENGINEGETEXTTEXTMETRICS @508
+; APPGETENGINEOUTLINE @509
+; CREATESCALABLEFONTRESOURCE @510
+
+; TEFTI for DNW
+
+
+IMPORTS
+
+ HandleParamError = KERNEL.327
diff --git a/private/mvdm/wow16/gdi/gdi.rc b/private/mvdm/wow16/gdi/gdi.rc
new file mode 100644
index 000000000..4a47934ce
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi.rc
@@ -0,0 +1,5 @@
+/********************************************************************/
+/* GDI.RC */
+/********************************************************************/
+
+#include "gdi.rcv"
diff --git a/private/mvdm/wow16/gdi/gdi.rcv b/private/mvdm/wow16/gdi/gdi.rcv
new file mode 100644
index 000000000..219ce168c
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* GDI.RCV */
+/********************************************************************/
+
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Graphics Device Interface core component"
+#define VER_INTERNALNAME_STR "GDI"
+#define VER_ORIGINALFILENAME_STR "GDI.EXE"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/gdi/gdi16.h b/private/mvdm/wow16/gdi/gdi16.h
new file mode 100644
index 000000000..1f649950d
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdi16.h
@@ -0,0 +1,422 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * GDI16.H
+ *
+ * History:
+ * Created 01-Jul-1991 by John Colleran (johnc)
+ *
+ * Warning!!!
+ * The same code is used to play 16 bit metafiles in WOW (16 bit code)
+ * and GDI (32 bit code)
+ *
+--*/
+
+#ifdef WOW
+ #define WIN16
+ #define UINT WORD
+ #define HUGE_T huge
+#else
+ #define WIN32
+ #include "port1632.h"
+ #include "firewall.h"
+ #ifdef FIREWALLS
+ #define DEBUG
+ #endif
+#endif
+
+#define GDIENTRY FAR PASCAL
+#define INTERNAL NEAR PASCAL
+
+
+// If this is 32 bit code append a 16 to all the exported APIs
+
+#ifdef WIN32
+ HANDLE FAR PASCAL GetMetaFile16(LPSTR);
+ BOOL FAR PASCAL PlayMetaFile16(HDC, HANDLE);
+ void FAR PASCAL PlayMetaFileRecord16(HDC, LPHANDLETABLE, LPMETARECORD, WORD);
+
+ #define GetMetaFile GetMetaFile16
+ #define DeleteMetaFile DeleteMetaFile16
+ #define PlayMetaFile PlayMetaFile16
+ #define PlayMetaFileRecord PlayMetaFileRecord16
+ #define IsValidMetaFile IsValidMetaFile16
+
+ #define AnimatePalettePriv AnimatePalette
+ #define DeleteObjectPriv DeleteObject
+ #define ResizePalettePriv ResizePalette
+ #define SetPaletteEntriesPriv SetPaletteEntries
+
+ #define GetViewportExt(hdc) GetViewportExt32(hdc)
+ #define GetWindowExt(hdc) GetWindowExt32(hdc)
+ #define SetViewportExt(h,x,y) SetViewportExt32(h,x,y)
+ #define SetWindowExt(h,x,y) SetWindowExt32(h,x,y)
+
+ LPINT ConvertInts( signed short * pWord, UINT cWords );
+ DWORD GetViewportExt32(HDC hdc);
+ DWORD GetWindowExt32(HDC hdc);
+ DWORD SetViewportExt32(HDC hdc, UINT x, UINT y);
+ DWORD SetWindowExt32(HDC hdc, UINT x, UINT y);
+
+ #define CONVERTPTS(p,c) (LPPOINT)CONVERTINTS((signed short *)p,(c)*2)
+ #define CONVERTINTS(p,c) ConvertInts((signed short *)p,c)
+
+ #define FREECONVERT(p) LocalFree(p)
+
+ #define PlayIntoAMetafile(a,b) 0
+ #define DEFIFWIN16(a) 0
+
+ #pragma pack(2)
+ typedef struct
+ {
+ WORD mtType;
+ WORD mtHeaderSize;
+ WORD mtVersion;
+ WORD mtSize;
+ WORD mtSize2;
+ WORD mtNoObjects;
+ DWORD mtMaxRecord;
+ WORD mtNoParameters;
+ } METAHEADER16;
+ #define METAHEADER METAHEADER16
+
+ typedef struct tagLOGFONT16
+ {
+ int lfHeight;
+ int lfWidth;
+ int lfEscapement;
+ int lfOrientation;
+ int lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ BYTE lfFaceName[LF_FACESIZE];
+ } LOGFONT16;
+ typedef LOGFONT16 FAR *LPLOGFONT16;
+ #pragma pack()
+
+ #define LOGFONT32FROM16( plf32, plf16 ) \
+ { plf32->lfHeight = plf16->lfHeight; \
+ plf32->lfWidth = plf16->lfWidth; \
+ plf32->lfEscapement = plf16->lfEscapement; \
+ plf32->lfOrientation = plf16->lfOrientation; \
+ plf32->lfWeight = plf16->lfWeight; \
+ plf32->lfItalic = plf16->lfItalic; \
+ plf32->lfUnderline = plf16->lfUnderline; \
+ plf32->lfStrikeOut = plf16->lfStrikeOut; \
+ plf32->lfCharSet = plf16->lfCharSet; \
+ plf32->lfOutPrecision = plf16->lfOutPrecision; \
+ plf32->lfClipPrecision = plf16->lfClipPrecision; \
+ plf32->lfQuality = plf16->lfQuality; \
+ plf32->lfPitchAndFamily = plf16->lfPitchAndFamily; \
+ memcpy( &plf32->lfItalic, &plf16->lfItalic, LF_FACESIZE); \
+ }
+
+ #define ISDCVALID(hdc) TRUE
+ #define ISMETADC(hdc) FALSE
+#else
+ #define CONVERTPTS(p,c) (LPPOINT)(p)
+ #define CONVERTINTS(p,c) (p)
+ #define FREECONVERT(p)
+ #define DEFIFWIN16(a) a
+
+ #define LOGFONT32FROM16( plf32, plf16 ) {plf32 = plf16;}
+ #define ISDCVALID(hdc) IsDCValid(hdc)
+ #define ISMETADC(hdc) IsMetaDC(hdc)
+
+ typedef struct _RGNDATAHEADER {
+ DWORD dwSize;
+ DWORD iType;
+ DWORD nCount;
+ } RGNDATAHEADER, *PRGNDATAHEADER;
+
+ typedef struct _RGNDATA {
+ RGNDATAHEADER rdh;
+ char Buffer[1];
+ } RGNDATA,FAR *LPRGNDATA;
+
+ typedef struct _RECTL {
+ LONG xLeft;
+ LONG yTop;
+ LONG xRight;
+ LONG yBottom;
+ } RECTL,FAR *LPRECTL;
+#endif
+
+/*** MetaFile Internal Constants and Macros ***/
+
+#define METAVERSION 0x0300
+#define METAVERSION100 0x0100
+
+/* Metafile constants not in Windows.h */
+#define META_RESETDC 0x0149
+#define META_STARTDOC 0x0150
+#define META_STARTPAGE 0x0051
+#define META_ENDPAGE 0x0052
+#define META_ENDDOC 0x0053
+#define META_ABORTDOC 0x0054
+#define META_EXTFLOODFILL 0x0548
+
+#define MAXFILECHUNK ((unsigned)63*1024)
+
+#define METAFILEFAILURE 1
+
+#define METAEXITCODE 0 /* arbitrary value */
+
+#define MEMORYMETAFILE 1
+#define DISKMETAFILE 2
+
+#define DATASIZE 100
+#define HEADERSIZE (sizeof(METAHEADER)/sizeof(WORD))
+
+#define RECHDRSIZE (sizeof(WORD) + sizeof(DWORD))
+
+#define LMHtoP(handle) (*((char * *)(handle)))
+
+#define ID_METADC 0x444D // "MD"
+#define METADCBIT 0x1 // Set if DC is a MetaFile DC
+#define MAKEMETADC(h) (h|METADCBIT)
+#define HANDLEFROMMETADC(h) (((UINT)h) & (~METADCBIT))
+#define HMFFROMNPMF(h) (LocalHandle((WORD)h)|METADCBIT)
+#define NPFROMMETADC(h) (LMHtoP((h&(~METADCBIT))))
+
+//!!!!!! assert this
+#define MAXOBJECTSIZE sizeof(LOGFONT)
+
+/*** MetaFile Internal TypeDefs ***/
+
+typedef BYTE near *NPBYTE;
+typedef BYTE HUGE_T *HPBYTE;
+typedef WORD HUGE_T *HPWORD;
+
+typedef HANDLE HMETAFILE;
+
+typedef struct _METADATA { /* md */
+ METAHEADER dataHeader;
+ WORD metaDataStuff[DATASIZE];
+} METADATA;
+typedef METADATA *NPMETADATA;
+typedef METADATA FAR *LPMETADATA;
+
+typedef struct _METAFILE { /* mf */
+ METAHEADER MetaFileHeader;
+ UINT MetaFileNumber;
+ DWORD MetaFilePosition;
+ OFSTRUCT MetaFileBuffer;
+ HANDLE MetaFileRecordHandle;
+} METAFILE;
+typedef METAFILE *NPMETAFILE;
+typedef METAFILE FAR *LPMETAFILE;
+typedef METAFILE HUGE_T *HPMETAFILE;
+
+typedef struct _METACACHE {
+ HANDLE hCache;
+ HANDLE hMF;
+ WORD wCacheSize;
+ WORD wCachePos;
+} METACACHE;
+
+typedef struct _ILOBJHEAD {
+ WORD ident;
+ WORD nextinchain;
+ int ilObjType;
+ long ilObjCount;
+ HANDLE ilObjMetaList;
+} ILOBJHEAD;
+
+typedef struct _METARECORDER {
+ ILOBJHEAD metaDCHeader;
+ METAHEADER recordHeader;
+ DWORD recFilePosition;
+ OFSTRUCT recFileBuffer;
+ DWORD sizeBuffer;
+ WORD recFileNumber;
+ WORD recFlags;
+ HANDLE hMetaData;
+ HANDLE hObjectTable;
+ HANDLE recCurObjects[6]; // Current Selected Object
+} METARECORDER;
+typedef METARECORDER *NPMETARECORDER;
+typedef METARECORDER FAR *LPMETARECORDER;
+
+typedef METARECORD HUGE_T *HPMETARECORD;
+
+typedef struct _OBJECTTABLE {
+ DWORD objectIndex;
+ HANDLE objectCurHandle;
+} OBJECTTABLE;
+typedef OBJECTTABLE *NPOBJECTTABLE;
+typedef OBJECTTABLE FAR *LPOBJECTTABLE;
+
+typedef struct _OBJMETALIST {
+ WORD omlCount;
+ HANDLE omlMetaDC[1];
+} OBJMETALIST;
+
+typedef struct _WIN2OBJHEAD {
+ WORD nextinchain;
+ int w2ObjType;
+ long w2ObjCount;
+} WIN2OBJHEAD;
+typedef WIN2OBJHEAD *NPWIN2OBJHEAD;
+typedef WIN2OBJHEAD FAR *LPWIN2OBJHEAD;
+
+typedef struct _SCAN {
+ WORD scnPntCnt; // Scan point count
+ WORD scnPntTop; // Top of scan
+ WORD scnPntBottom; // Bottom of scan
+ WORD scnPntsX[2]; // Start of points in scan
+ WORD scnPtCntToo; // Point count-- to allow UP travel
+} SCAN;
+typedef SCAN *NPSCAN;
+typedef SCAN FAR *LPSCAN;
+
+typedef struct _WIN3REGION {
+ WORD nextInChain; // Not used should be zero
+ WORD ObjType; // Must always be 6 (Windows OBJ_RGN)
+ DWORD ObjCount; // Not used
+ WORD cbRegion; // size of following region struct
+ WORD cScans;
+ WORD maxScan;
+ RECT rcBounding;
+ SCAN aScans[1];
+} WIN3REGION;
+typedef WIN3REGION *NPWIN3REGION;
+typedef WIN3REGION FAR *LPWIN3REGION;
+
+typedef struct _EXTTEXTDATA {
+ int xPos;
+ int yPos;
+ WORD cch;
+ RECT rcClip;
+ LPSTR lpString;
+ LPWORD lpWidths;
+}EXTTEXTDATA;
+typedef EXTTEXTDATA *NPEXTTEXTDATA;
+typedef EXTTEXTDATA FAR *LPEXTTEXTDATA;
+
+// These are from wingdi.h
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+#define OBJ_DC 3
+#define OBJ_METADC 4
+#define OBJ_PALETTE 5
+#define OBJ_FONT 6
+#define OBJ_BITMAP 7
+#define OBJ_RGN 8
+#define OBJ_METAFILE 9
+#define OBJ_MEMDC 10
+
+#define MIN_OBJ OBJ_PEN
+#define MAX_OBJ OBJ_MEMDC
+
+
+// These Function have no DC; so these function allow you to call them directly
+#ifdef WIN16
+HANDLE GDIENTRY GetCurrentObject(HDC hdc, WORD wObjType);
+DWORD GDIENTRY GetRegionData(HRGN, DWORD, LPRGNDATA);
+void GDIENTRY AnimatePalettePriv(HPALETTE, WORD, WORD, LPPALETTEENTRY);
+BOOL GDIENTRY DeleteObjectPriv(HANDLE);
+BOOL GDIENTRY ResizePalettePriv(HPALETTE, WORD);
+WORD GDIENTRY SetPaletteEntriesPriv(HPALETTE,WORD,WORD,LPPALETTEENTRY);
+#endif // WIN16
+
+BOOL GDIENTRY GdiFlush(VOID);
+DWORD GDIENTRY GetObjectType(HANDLE h);
+BOOL GDIENTRY IsValidMetaFile(HANDLE hMetaData);
+
+// Internal Function Declarations
+VOID INTERNAL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, WORD noObjs);
+HANDLE INTERNAL AllocBuffer(LPWORD iBufferSize);
+DWORD INTERNAL BigRead(UINT fileNumber, LPSTR lpRecord, DWORD dwSizeRec);
+VOID INTERNAL CallMetaFunction(HDC, FARPROC, WORD, LPWORD );
+BOOL INTERNAL GDIsSelectPalette(HDC hdc, HPALETTE pal, BOOL f);
+LPMETARECORD INTERNAL GetEvent(LPMETAFILE pmf,HPMETARECORD pmr,BOOL bFree);
+int INTERNAL GetObjectAndType(HANDLE hObj, LPSTR lpObjectBuf);
+HANDLE INTERNAL GetPMetaFile(HDC hdc);
+BOOL INTERNAL InitializeGdi(VOID);
+BOOL INTERNAL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo);
+BOOL INTERNAL IsDCValid(HDC hdc);
+BOOL INTERNAL IsMetaDC(HDC hdc);
+BOOL INTERNAL IsObjectStock(HANDLE hObj);
+BOOL INTERNAL LPtoSP(HDC,LPPOINT,int);
+BOOL INTERNAL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest);
+int INTERNAL RecordObject(HANDLE hMF, WORD magic, WORD count, LPWORD lpParm);
+BOOL INTERNAL RecordParms(HANDLE hDC, WORD magic, DWORD count, LPWORD lpParm);
+BOOL INTERNAL RecordOther(HANDLE hMF, WORD magic, WORD count, LPWORD lpParm);
+BOOL INTERNAL Valid( HANDLE hnd, int l, int h);
+
+
+/****************************************************************************
+
+ debugging support
+
+****************************************************************************/
+
+// Put a wrapper around 16 bit memory Allocation to help track down bugs
+#ifdef DEBUG
+#ifndef WIN32
+PSTR INTERNAL _LocalLock(HANDLE h );
+BOOL INTERNAL _LocalUnlock(HANDLE h );
+HANDLE INTERNAL _LocalAlloc(WORD w, WORD w2);
+LPSTR INTERNAL _GlobalLock(HANDLE h );
+BOOL INTERNAL _GlobalUnlock(HANDLE h );
+HANDLE INTERNAL _GlobalAlloc(WORD w, DWORD dw );
+
+#define LocalLock(h) _LocalLock(h)
+#define GlobalLock(h) _GlobalLock(h)
+#define LocalUnlock(h) _LocalUnlock(h)
+#define GlobalUnlock(h) _GlobalUnlock(h)
+#define LocalAlloc(w, w2 ) _LocalAlloc(w, w2)
+#define GlobalAlloc(w, dw ) _GlobalAlloc(w, dw)
+#endif
+#endif
+
+
+#ifdef DEBUG
+ extern void dDbgOut(int iLevel, LPSTR lpszFormat, ...);
+ extern void dDbgAssert(LPSTR exp, LPSTR file, int line);
+
+#ifdef WIN32
+ #define dprintf
+ #define GdiLogFunc(str)
+ #define GdiLogFunc2(str)
+ #define GdiLogFunc3(str)
+ #define ASSERTGDIW(exp,str,w) ASSERTGDI(exp,str)
+#else
+ #define dprintf dDbgOut
+ #define GdiLogFunc(str) {dDbgOut(3, str );}
+ #define GdiLogFunc2(str) {dDbgOut(6, str );}
+ #define GdiLogFunc3(str) {dDbgOut(7, str );}
+ #define ASSERTGDI(exp,str) \
+ {((exp) ? (void)0 : dDbgAssert(str, __FILE__, __LINE__));}
+ #define ASSERTGDIW(exp,str,w) \
+ { char buf[256]; \
+ ((exp) ? 0 : \
+ ( wsprintf(buf, (LPSTR)str, (WORD)w), \
+ dDbgAssert(buf, __FILE__, __LINE__),0)); \
+ } \
+
+#endif //WIN32
+#else // !DEBUG
+#ifdef i386
+ #define dprintf /##/
+#else
+ #define dprintf
+#endif
+
+ #define GdiLogFunc(str)
+ #define GdiLogFunc2(str)
+ #define GdiLogFunc3(str)
+ #define ASSERTGDI(exp,str)
+ #define ASSERTGDIW(exp, str, w)
+
+#endif // else DEBUG
diff --git a/private/mvdm/wow16/gdi/gdimacro.inc b/private/mvdm/wow16/gdi/gdimacro.inc
new file mode 100644
index 000000000..a0312ecbf
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdimacro.inc
@@ -0,0 +1,676 @@
+;/* GDIMACRO.INC - GDI macros
+
+LMHLockCnt equ byte ptr 3
+wptr equ word ptr
+bptr equ byte ptr
+
+PtoLMH macro r1,r2
+ifnb <r2>
+ mov r1,[r2 - 2]
+else
+ mov r1,[r1 - 2]
+endif
+endm
+
+LMHtoP macro r1,r2 ;; Local Movable Handle to pointer
+ifnb <r2>
+ mov r1,[r2]
+else
+ mov r1,[r1]
+endif
+endm
+
+LMHtoPES macro r1,r2 ;; Local Movable Handle to ptr, deref vi ES
+ifnb <r2>
+ mov r1,es:[r2]
+else
+ mov r1,es:[r1]
+endif
+endm
+
+LMPsize macro r1,r2 ;; Local Movable pointer size
+ mov r1,-4[r2]
+endm
+
+
+LockDataSegment macro
+endm
+
+
+UnlockDataSegment macro
+endm
+
+farLockDataSegment macro
+endm
+
+
+farUnlockDataSegment macro
+endm
+
+
+; NOTE: The lock/unlock macros are not going to check
+; for under/overflow. Its highly unlikely that
+; it will occur, and if it does, we'll be hosed
+; anyway....
+
+
+LLock macro r
+ inc LMHLockCnt[r] ;;Increment ref count
+endm
+
+LUnlock macro r
+ dec LMHLockCnt[r] ;;Decrement reference count
+endm
+
+LLocked? macro r
+ cmp LMHLockCnt[r],0 ;; is the handle locked?
+endm
+
+LLockES macro r
+ inc es:LMHLockCnt[r] ;;Increment ref count
+endm
+
+LUnlockES macro r
+ dec es:LMHLockCnt[r] ;;Decrement reference count
+endm
+
+LLockedES? macro r
+ cmp es:LMHLockCnt[r],0 ;; is the handle locked?
+endm
+
+; The jmpnext macro and associated symbols are used to generate
+; the fall-through chain and generate the labels required for
+; error checking.
+
+??ji = 0 ;;Initial index value
+
+jmpnext macro e
+jn %??ji,%(??ji+1),e ;;Set next label
+endm
+
+jn macro i,j,e
+.sall
+??ji&i:
+.xall
+ifb <e> ;;If not the end of the chain
+ db 03dh ;;mov bx, next two bytes
+errn$ ??ji&j,+2 ;;mext lable must be two bytes away
+endif
+??ji=j ;;increment counter
+endm
+
+ifdef DEBUG
+ifndef ?HELPER
+ExternFP ValidateHandle
+endif
+endif
+
+;*
+;* Valid? macro Handle,Error_exit,LowLimit,UpLimit
+;*
+;* Validate an object handle. A valid handle must 1)not be NULL 2)be for
+;* an object of the specified type.
+;*
+;*
+;* Macro Arguments:
+;*
+;* Handle - object handle
+;* Error_exit - the next instruction to execute if an invalid obj
+;* LowLimit, UpLimit - Range of the possible object type
+;*
+;* Return:
+;* DS:BX - pointer to the object
+;*
+;* Trashes:
+;* AX,BX,CX,DX
+;*
+
+Valid? macro Handle,Error_exit,LowLimit,UpLimit
+ local ValidHandle,Invalidexit
+
+ifdef DISABLE
+ifdef DEBUG
+
+;******************************************************************************
+;
+; Object handle validation in a debug version
+;
+;******************************************************************************
+
+ push dx
+mov bx, LowLimit
+ ifnb <UpLimit>
+mov dx, UpLimit
+ else
+mov dx, LowLimit
+ endif
+
+ cCall <far ptr ValidateHandle>,<Handle,bx,dx>
+ pop dx
+ or ax,ax
+ jnz ValidHandle
+ jmp Error_exit
+else
+
+;******************************************************************************
+;
+; Object handle validation in a retail version
+;
+;******************************************************************************
+
+ mov bx,Handle ; NULL handle validation
+ or bx,bx
+ jz Invalidexit
+
+ LMHtoP bx ; dereference for object pointer
+
+ mov ax,ilObjType[bx] ; Validate the object type
+
+irp stock_type,<OBJ_PEN,OBJ_BRUSH,OBJ_FONT,OBJ_BITMAP,OBJ_PALETTE>
+ife stock_type-LowLimit
+ and ax,NOT OBJ_FLAGS ; mask only for possible stock obj
+endif
+endm
+
+ifnb <UpLimit>
+ cmp ax,LowLimit ; Check object type range
+ jl Invalidexit
+ cmp ax,UpLimit
+ jle ValidHandle
+else
+ cmp ax,LowLimit ; Check a particular object type
+ je ValidHandle
+endif
+
+Invalidexit:
+ xor ax,ax
+ jmp Error_exit ; it is not a valid handle
+
+endif
+
+ValidHandle:
+
+else ; !DISABLE
+
+ mov bx,Handle
+ LMHtoP bx
+
+endif ; !DISABLE
+ endm
+
+ValidDebug? macro Handle,LowLimit,UpLimit
+
+ifdef DEBUG
+
+ push bx
+ push dx
+mov bx, LowLimit
+ ifnb <UpLimit>
+mov dx, UpLimit
+ else
+mov dx, LowLimit
+ endif
+
+ cCall <far ptr ValidateHandle>,<Handle,bx,dx>
+ pop dx
+ pop bx
+
+endif
+ endm
+
+;*
+;* Notify? macro
+;*
+;* Tests if the given dc is hooked, and if it is, calls off to
+;* send a notification to whomever is hooked into the dc notification
+;* hook.
+;*
+;* Macro Arguments:
+;*
+;* hDC - the actual DC handle
+;* lParam - the notification code to send via the hook
+;* errLbl - optional parameter, which gives label to
+;* jump to if notification returns 0
+;*
+;* Trashes:
+;* AX,BX,flags
+;*
+ifdef LATER
+ifndef ?LVB
+ExternFP SendDCNotify
+ExternFP SendInvalidVisRgn
+endif
+Notify? macro hDC,code,param1,param2,errLbl
+ mov bx,hDC
+ mov bx,[bx]
+ mov ax,word ptr lpNotifyProc[bx]
+ or ax,word ptr lpNotifyProc+2[bx]
+ jz @F
+ push hDC
+ mov ax,code
+ push ax
+ mov ax,param1
+ push ax
+ mov ax,param2
+ push ax
+ cCall <far ptr SendDCNotify>
+ifnb <errLbl>
+ or ax,ax
+endif
+ifnb <errLbl>
+ jnz @F
+ jmp errLbl
+endif
+@@:
+ endm
+
+
+;* VNotify?
+;*
+;* Tests if the given dc is hooked and has an invalid visrgn. If
+;* it does, then a notification is sent to the dc hook.
+;*
+;* Warning:
+;* if we call the call-back, the gdi heap can be compacted,
+;* so no dereferenced handles can be relied on after making
+;* this call.
+;*
+;* Entry:
+;* hDC - handle to dc to check and send notifications
+;* reg - scratch register to use
+;*
+;* Exit:
+;* reg - trashed
+;* flags - trashed
+;*
+VNotify? macro hDC,reg
+ mov reg,hDC
+ LMHtoP reg
+ test byte ptr DCFlags[reg],BadVisRgn
+ jz @F
+ cCall <far ptr SendInvalidVisRgn>,<hDC>
+@@:
+ endm
+
+VNotifyPtr? macro reg,hDC
+ test byte ptr DCFlags[reg],BadVisRgn
+ jz @F
+ cCall <far ptr SendInvalidVisRgn>,<hDC>
+@@:
+ endm
+endif
+
+;-----------------------------------------------------------------------
+; cProcVDO - cProc "Validate Debug Only"
+;
+; Same as cProc, except used for "Validate in Debug Only" entry points.
+; Declares Iname if debug, name if retail.
+;
+cProcVDO macro name,opts,savelist
+ ifdef DEBUG
+ cProc <I&name>,<opts>,<savelist>
+ else
+ LabelFP <PUBLIC, I&name>
+ cProc <name>,<opts>,<savelist>
+ endif
+endm
+
+GDIGLOBALLOCK macro Handle,segRegister,offsetRegister
+.lall
+ifndef GlobalLock
+ExternFP GlobalLock
+endif
+ cCall <far ptr GlobalLock>,<Handle>
+ifnb <segRegister>
+ mov segRegister,dx
+endif
+ifnb <offsetRegister>
+ mov offsetRegister,ax
+endif
+.sall
+ endm
+
+
+GDIGLOBALUNLOCK macro Handle
+ifndef GlobalUnlock
+ExternFP GlobalUnlock
+endif
+ cCall <far ptr GlobalUnlock>,<Handle>
+ endm
+
+GDIRequestSem macro
+ endm
+
+GDIClearSem macro
+ endm
+
+
+; setlbl generates a macro which will declare labels public
+; if "debug" has been defined. The symbol generated will
+; be of the form:
+;
+; filename_label
+;
+; where
+;
+; filename is the parameter given to the setlbl macro,
+; and label is the first parameter given to the lbl macro
+; which is generated by setlbl.
+;
+;
+; lbl is the macro which will define the given label and
+; if "debug" is defined, declare it public.
+;
+;
+; lbl foo,<opt1>,opt2
+;
+; where
+;
+; foo is the name of the label
+; opt1 is an optional second parameter. If present,
+; it must be some combination of
+; proc, label, near, far, byte, word, dword
+; opt2 is an optional third parameter which if present
+; must be "public". It forces the declaration of
+; "foo" to be public.
+
+
+
+setlbl macro filename
+ lbl &macro n,opt1,opt2
+ .sall
+ ifnb <opt1>
+ n opt1
+ ifdef debug
+ filename&&_&&n equ n
+ public filename&&_&&n
+ endif
+ else
+ n:
+ ifdef debug
+ filename&&_&&n:
+ public filename&&_&&n
+ endif
+ endif
+ ifnb <opt2>
+ public n
+ endif
+ .xall
+ &endm
+endm
+
+
+smov macro segreg1,segreg2
+ push segreg2
+ pop segreg1
+ endm
+
+jmps macro there
+ jmp short there
+ endm
+
+; structure to allow easy access to components of DWORD.
+
+HILO struc
+lo dw ?
+hi dw ?
+HILO ends
+
+; structure to allow easy access to components of LP.
+
+OFFSEL struc
+off dw ?
+sel dw ?
+OFFSEL ends
+
+
+;--------------------------------------------------------------------------;
+; ABS
+; Maps the signed integer in AX to a positive signed integer to be
+; returned in AX. If FOO is blank then 8000h is mapped to 7fffh.
+; Since GDI defines MININT as 8000h, we should deal with this case.
+; If FOO is non-blank, 8000h is mapped to 8000h. (Usually bad!)
+; All other integers behave as one would expect with Absolute Value.
+; Entry:
+; AX = signed integer (8000h to 7fffh)
+; Returns:
+; AX = ABS(AX)
+; Trashes:
+; DX, FLAGS
+;
+; History:
+; Tue 29 October 1991 -by- Raymond E. Endres [rayen]
+; Wrote it.
+;--------------------------------------------------------------------------;
+
+
+ABS macro FOO ;NOTE: default FOO is blank!
+ cwd
+ xor ax,dx
+ sub ax,dx
+ifb <FOO> ;if FOO is blank
+ cwd ;remove the 8000h case
+ xor ax,dx
+endif
+ endm
+
+
+;--------------------------------------------------------------------------;
+; min_ax
+; returns min of AX and REG
+; Entry:
+; AX = integer
+; REG = general purpose register containing an integer
+; Returns:
+; AX = min(AX,REG)
+; Error Returns:
+; none
+; Registers Destroyed:
+; DX,FLAGS
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES,BP
+; Calls:
+; none
+; History:
+; Sat Mar 07, 1987 08:39:04p -by- Tony Pisculli [tonyp]
+; wrote it
+;--------------------------------------------------------------------------;
+
+
+min_ax macro REG
+ sub ax,REG
+ cwd
+ and ax,dx
+ add ax,REG
+ endm
+
+
+
+;--------------------------------------------------------------------------;
+; max_ax
+; returns max of AX and REG
+; Entry:
+; AX = integer
+; REG = general purpose register containing an integer
+; Returns:
+; AX = max(AX, REG)
+; Error Returns:
+; none
+; Registers Destroyed:
+; DX,FLAGS
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES,BP
+; Calls:
+; none
+; History:
+; Sat Mar 07, 1987 08:41:38p -by- Tony Pisculli [tonyp]
+; wrote it
+;--------------------------------------------------------------------------;
+
+maxintoax macro mem1,mem2
+ mov ax,mem1
+ max_ax mem2
+ endm
+
+
+max_ax macro REG
+ sub ax,REG
+ cwd
+ not dx
+ and ax,dx
+ add ax,REG
+ endm
+
+
+
+; The following equates are used for defining the target
+; processor to the shift macros.
+
+
+GENERIC equ 0
+
+;CPU equ GENERIC
+;CPU equ 88
+;CPU equ 86
+;CPU equ 186
+CPU equ 286
+;CPU equ 386
+
+
+
+;--------------------------------------------------------------------------;
+; shiftl
+;
+; shiftl is used to implement the advanced shift left immediate
+; (SHL dest,count) functionality of the 286 and 386.
+;
+; Entry:
+; DEST = var to shift
+; COUNT = number to shift by
+; Returns:
+; DEST = DEST shl COUNT
+; Error Returns:
+; none
+; Registers Destroyed:
+; none
+; Registers Preserved:
+; all
+; Calls:
+; none
+; History:
+; Sat Mar 07, 1987 08:44:30p -by- Tony Pisculli [tonyp]
+; wrote it
+;--------------------------------------------------------------------------;
+
+
+shiftl macro DEST,COUNT
+if (CPU eq 286) or (CPU eq 386)
+ shl DEST,COUNT
+else
+ REPT COUNT
+ shl DEST,1
+ ENDM
+endif
+ endm
+
+
+
+;--------------------------------------------------------------------------;
+; shiftr
+;
+; shiftr is used to implement the advanced shift right immediate
+; (SHR dest,count) functionality of the 286 and 386.
+;
+; Entry:
+; DEST = var to shift
+; COUNT = number to shift by
+; Returns:
+; DEST = DEST shr COUNT
+; Error Returns:
+; none
+; Registers Destroyed:
+; none
+; Registers Preserved:
+; all
+; Calls:
+; none
+; History:
+; Sat Mar 07, 1987 08:44:52p -by- Tony Pisculli [tonyp]
+; wrote it
+;--------------------------------------------------------------------------;
+
+
+shiftr macro DEST,COUNT
+if (CPU eq 286) or (CPU eq 386)
+ shr DEST,COUNT
+else
+ REPT COUNT
+ shr DEST,1
+ ENDM
+endif
+ endm
+
+
+;--------------------------------------------------------------------------;
+; nop32
+;
+; compensate for bug in the 386 chip and 32-bit string operations.
+;
+;--------------------------------------------------------------------------;
+nop32 macro
+ db 067h
+ nop
+ endm
+
+ if 0
+*/
+
+#ifndef DEBUG
+#include "igdi.inc"
+#endif
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<=(b)?(a):(b))
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+#define LBYTE(x) ((BYTE)((x)&0xFF))
+#define HBYTE(y) ((BYTE)(((y)>>8)&0xFF))
+#define LWORD(x) ((short)((x)&0xFFFF))
+#define HWORD(y) ((short)(((y)>>16)&0xFFFF))
+#define MAKELONG(h,l) ((long)(((WORD)l)|(((long)h)<<16)))
+
+extern far PASCAL ValidateHandle(HANDLE, short, short);
+#ifdef DISABLE
+#define Valid(Handle, Low, High) ValidateHandle(Handle, Low, High)
+#else
+#define Valid(Handle, Low, High) TRUE
+#endif
+
+#ifdef DEBUG
+#define ValidDebug(Handle, Low, High) {if(!ValidateHandle(Handle, Low, High)) return(NULL);}
+#else
+#define ValidDebug(Handle, Low, High) TRUE
+#endif
+
+#define GDIGLOBALLOCK(x) GlobalLock(x)
+#define GDIGLOBALUNLOCK(x) GlobalUnlock(x)
+#define GDILOCKRESOURCE(x) LockResource(x)
+#define GDIENTERCRITSEC()
+#define GDIEXITCRITSEC()
+#define LockDataSegment()
+#define UnlockDataSegment()
+#define farLockDataSegment()
+#define farUnlockDataSegment()
+#define GDIRequestSem()
+#define GDIClearSem()
+
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define SELECTOROF(lp) HIWORD(lp)
+#define OFFSETOF(lp) LOWORD(lp)
+
+/*
+ endif
+
+;*/
+
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/gdi/gdimem.inc b/private/mvdm/wow16/gdi/gdimem.inc
new file mode 100644
index 000000000..da351658d
--- /dev/null
+++ b/private/mvdm/wow16/gdi/gdimem.inc
@@ -0,0 +1,50 @@
+;definitions pasted in from WINDOWS.INC for memory management call to KERNEL:
+;
+; Memory manager flags
+;
+LMEM_FIXED = 0000h
+LMEM_MOVEABLE = 0002h
+LMEM_NOCOMPACT = 0010H
+LMEM_NODISCARD = 0020H
+LMEM_ZEROINIT = 0040h
+LMEM_MODIFY = 0080H
+LMEM_DISCARDABLE= 0F00h
+LHND = LMEM_MOVEABLE+LMEM_ZEROINIT
+LPTR = LMEM_FIXED+LMEM_ZEROINIT
+; Flags returned by LocalFlags (in addition to LMEM_DISCARDABLE)
+LMEM_DISCARDED = 4000H
+LMEM_LOCKCOUNT = 00FFH
+
+NONZEROLHND = LMEM_MOVEABLE
+NONZEROLPTR = LMEM_FIXED
+
+LNOTIFY_OUTOFMEM = 0
+LNOTIFY_MOVE = 1
+LNOTIFY_DISCARD = 2
+
+
+GMEM_FIXED = 0000h
+GMEM_MOVEABLE = 0002h
+GMEM_NOCOMPACT = 0010h
+GMEM_NODISCARD = 0020h
+GMEM_ZEROINIT = 0040h
+GMEM_MODIFY = 0080h
+GMEM_DISCARDABLE= 0100h
+GMEM_NOT_BANKED = 1000h
+GMEM_DDESHARE = 2000h
+GMEM_SHARE = 2000h
+GMEM_NOTIFY = 4000h
+GMEM_LOWER = GMEM_NOT_BANKED
+GHND = GMEM_MOVEABLE+GMEM_ZEROINIT
+GPTR = GMEM_FIXED+GMEM_ZEROINIT
+
+; Flags returned by GlobalFlags (in addition to GMEM_DISCARDABLE)
+GMEM_DISCARDED = 4000h
+GMEM_LOCKCOUNT = 00FFh
+
+; Debug fill constants
+
+DBGFILL_ALLOC equ 0fdh
+DBGFILL_FREE equ 0fbh
+DBGFILL_BUFFER equ 0f9h
+DBGFILL_STACK equ 0f7h
diff --git a/private/mvdm/wow16/gdi/layer.asm b/private/mvdm/wow16/gdi/layer.asm
new file mode 100644
index 000000000..5a21c692d
--- /dev/null
+++ b/private/mvdm/wow16/gdi/layer.asm
@@ -0,0 +1,47 @@
+ title LAYER.ASM - Parameter validation layer
+
+.xlist
+
+LAYER_INCLUDE=1
+
+include layer.inc
+include gpfix.inc
+;include gditype.inc
+ilObjType = 2
+;include gdiobj.inc
+
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+
+.list
+
+.lall
+
+LAYER_START
+
+include gdi.api
+
+LAYER_END
+
+;LAYER_EXPAND INIT
+LAYER_EXPAND TEXT
+;LAYER_EXPAND PALETTE
+;LAYER_EXPAND ESC
+;LAYER_EXPAND DCSTUFF
+;LAYER_EXPAND LOGMISC
+;LAYER_EXPAND FONTLOAD
+;LAYER_EXPAND FONTRES
+;LAYER_EXPAND FONTINQ
+;LAYER_EXPAND FONTSIMS
+;LAYER_EXPAND METAREC
+;LAYER_EXPAND METAPLAY
+;LAYER_EXPAND ARCDDA
+;LAYER_EXPAND OUTMAN
+;LAYER_EXPAND POLYGON
+;LAYER_EXPAND RGOUT
+;LAYER_EXPAND MISC
+;LAYER_EXPAND PIXDDA
+;LAYER_EXPAND DIBITMAP
+;LAYER_EXPAND FLOODFILL
+;LAYER_EXPAND RECT
+
+end
diff --git a/private/mvdm/wow16/gdi/makefile b/private/mvdm/wow16/gdi/makefile
new file mode 100644
index 000000000..effa313da
--- /dev/null
+++ b/private/mvdm/wow16/gdi/makefile
@@ -0,0 +1,126 @@
+# GDI16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+RINCS = -I..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW -DBUILDDLL $(MVDMFLAGS)
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+
+CW16 = -PLM -Asnw -G2sw $(DEFINES) $(INCS)
+#CW16 = -AS -G2sw $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Odi /Zd
+LINK = $(LINK) /LI
+!else
+CW16 = $(CW16) /Os /Zp
+!endif
+
+W16LIBS = ..\lib\snocrtd.lib ..\lib\libw.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) -fo $@ $*.rc
+
+all: gdi.exe gdi.sym
+ binplace gdi.exe
+ binplace gdi.sym
+ binplace gdi.map
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+gdi.obj: gdi.asm ..\..\inc\wow.inc ..\..\inc\wowgdi.inc
+ masm $(AOBJ) gdi;
+
+sort.obj: sort.asm ..\..\inc\wow.inc ..\..\inc\wowgdi.inc
+ masm $(AOBJ) sort;
+
+layer.obj: layer.asm ..\inc\layer.inc gdi.api
+ masm $(AOBJ) layer;
+
+muldiv.obj: muldiv.asm
+ masm $(AOBJ) muldiv;
+
+fontres.obj: fontres.c ..\..\inc\wow.h ..\..\inc\wowgdi.h
+ cl16 -c -nologo $(CW16) fontres.c
+
+gdi.lrf: makefile
+ echo gdi.obj+layer.obj+muldiv.obj+fontres.obj+sort.obj >gdi.lrf
+ echo gdi.exe>>gdi.lrf
+ echo gdi $(LINK)>>gdi.lrf
+ echo $(W16LIBS) /nod>>gdi.lrf
+ echo gdi;>>gdi.lrf
+
+gdi.res: $*.rc $*.rcv ..\inc\common.ver
+
+gdi.exe gdi.map: sort.obj gdi.obj gdi.lrf gdi.def layer.obj muldiv.obj fontres.obj gdi.res
+ link16 @gdi.lrf;
+ rc16 -t gdi.res gdi.exe
+
+!ENDIF
diff --git a/private/mvdm/wow16/gdi/meta.c b/private/mvdm/wow16/gdi/meta.c
new file mode 100644
index 000000000..7e98d8682
--- /dev/null
+++ b/private/mvdm/wow16/gdi/meta.c
@@ -0,0 +1,1835 @@
+/****************************** Module Header ******************************\
+* Module Name: Meta.c
+*
+* This file contains the routines for playing the GDI metafile. Most of these
+* routines are adopted from windows gdi code. Most of the code is from
+* win3.0 except for the GetEvent code which is taken from win2.1
+*
+* Created: 11-Oct-1989
+*
+* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation
+*
+*
+* Public Functions:
+* PlayMetaFile
+* PlayMetaFileRecord
+* GetMetaFile
+* DeleteMetaFile
+* Private Functions:
+* GetEvent
+* IsDIBBlackAndWhite
+*
+* History:
+* 02-Jul-1991 -by- John Colleran [johnc]
+* Combined From Win 3.1 and WLO 1.0 sources
+\***************************************************************************/
+
+#include <windows.h>
+#include <string.h>
+#ifdef WIN32
+#include "firewall.h"
+#endif
+#include "gdi16.h"
+
+HDC hScreenDC = 0;
+METACACHE MetaCache = { 0, 0, 0, 0 };
+
+UINT INTERNAL GetFileNumber (LPMETAFILE lpMF);
+HANDLE INTERNAL CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo);
+WORD INTERNAL GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo);
+
+#define MAX_META_DISPATCH 0x48
+FARPROC alpfnMetaFunc[MAX_META_DISPATCH+1] =
+/* 00 */ {(FARPROC)ScaleWindowExt,
+/* 01 */ (FARPROC)SetBkColor,
+/* 02 */ (FARPROC)SetBkMode,
+/* 03 */ (FARPROC)SetMapMode,
+/* 04 */ (FARPROC)SetROP2,
+/* 05 */ DEFIFWIN16((FARPROC)SetRelAbs),
+/* 06 */ (FARPROC)SetPolyFillMode,
+/* 07 */ (FARPROC)SetStretchBltMode,
+/* 08 */ (FARPROC)SetTextCharacterExtra,
+/* 09 */ (FARPROC)SetTextColor,
+/* 0A */ (FARPROC)SetTextJustification,
+/* 0B */ (FARPROC)SetWindowOrg,
+/* 0C */ (FARPROC)SetWindowExt,
+/* 0D */ (FARPROC)SetViewportOrg,
+/* 0E */ (FARPROC)SetViewportExt,
+/* 0F */ (FARPROC)OffsetWindowOrg,
+/* 10 */ 0,
+/* 11 */ DEFIFWIN16((FARPROC)OffsetViewportOrg),
+/* 12 */ DEFIFWIN16((FARPROC)ScaleViewportExt),
+/* 13 */ (FARPROC)LineTo,
+/* 14 */ DEFIFWIN16((FARPROC)MoveTo),
+/* 15 */ (FARPROC)ExcludeClipRect,
+/* 16 */ (FARPROC)IntersectClipRect,
+/* 17 */ (FARPROC)Arc,
+/* 18 */ (FARPROC)Ellipse,
+/* 19 */ (FARPROC)FloodFill,
+/* 1A */ (FARPROC)Pie,
+/* 1B */ (FARPROC)Rectangle,
+/* 1C */ (FARPROC)RoundRect,
+/* 1D */ (FARPROC)PatBlt,
+/* 1E */ (FARPROC)SaveDC,
+/* 1F */ (FARPROC)SetPixel,
+/* 20 */ (FARPROC)OffsetClipRgn,
+/* 21 */ 0, // TextOut,
+/* 22 */ 0, // BitBlt,
+/* 23 */ 0, // StretchBlt.
+/* 24 */ 0, // Polygon,
+/* 25 */ 0, // Polyline,
+/* 26 */ 0, // Escape,
+/* 27 */ (FARPROC)RestoreDC,
+/* 28 */ 0, // FillRegion,
+/* 29 */ 0, // FrameRegion,
+/* 2A */ 0, // InvertRegion,
+/* 2B */ 0, // PaintRegion,
+/* 2C */ (FARPROC)SelectClipRgn,
+/* 2D */ 0, // SelectObject,
+/* 2E */ (FARPROC)SetTextAlign,
+/* 2F */ 0, // DrawText,
+/* 30 */ (FARPROC)Chord,
+/* 31 */ (FARPROC)SetMapperFlags,
+/* 32 */ 0, // ExtTextOut,
+/* 33 */ 0, // SetDibsToDevice,
+/* 34 */ 0, // SelectPalette,
+/* 35 */ 0, // RealizePalette,
+/* 36 */ 0, // AnimatePalette,
+/* 37 */ 0, // SetPaletteEntries,
+/* 38 */ 0, // PolyPolygon,
+/* 39 */ 0, // ResizePalette,
+/* 3A */ 0,
+/* 3B */ 0,
+/* 3C */ 0,
+/* 3D */ 0,
+/* 3E */ 0,
+/* 3F */ 0,
+/* 40 */ 0, // DIBBitblt,
+/* 41 */ 0, // DIBStretchBlt,
+/* 42 */ 0, // DIBCreatePatternBrush,
+/* 43 */ 0, // StretchDIB,
+/* 44 */ 0,
+/* 45 */ 0,
+/* 46 */ 0,
+/* 47 */ 0,
+/* 48 */ (FARPROC)ExtFloodFill };
+
+
+#if 0 // this is going to gdi.dll
+
+/***************************** Public Function ****************************\
+* BOOL APIENTRY PlayMetaFile(hdc, hmf)
+* HDC hDC;
+* HMETAFILE hMF;
+*
+* Play a windows metafile.
+*
+* History:
+* Tue 27-Mar-1990 11:11:45 -by- Paul Klingler [paulk]
+* Ported from Windows
+\***************************************************************************/
+
+BOOL GDIENTRY PlayMetaFile(HDC hdc, HMETAFILE hmf)
+{
+ WORD i;
+ WORD noObjs;
+ BOOL bPrint=FALSE;
+ LPMETAFILE lpmf;
+ int oldMapMode = -1;
+ LPMETARECORD lpmr = NULL;
+ LPHANDLETABLE pht = NULL;
+ HANDLE hht = NULL;
+#ifndef WIN32
+ HFONT hLFont;
+ HBRUSH hLBrush;
+ HPALETTE hLPal;
+ HPEN hLPen;
+ HRGN hClipRgn;
+ HRGN hRegion;
+ DWORD oldWndExt;
+ DWORD oldVprtExt;
+#endif //WIN32
+
+ GdiLogFunc("PlayMetaFile");
+
+ if(!IsValidMetaFile(hmf))
+ goto exitPlayMetaFile;
+
+ if(lpmf = (LPMETAFILE)GlobalLock(hmf))
+ {
+ if((noObjs = lpmf->MetaFileHeader.mtNoObjects) > 0)
+ {
+ if(!(hht = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE,
+ (sizeof(HANDLE) * lpmf->MetaFileHeader.mtNoObjects) + sizeof(WORD ))))
+ {
+ goto exitPlayMetaFile10;
+ }
+ pht = (LPHANDLETABLE)GlobalLock(hht);
+ }
+#ifdef CR1
+IMP: Optmizations playing into another metafile. Look at the win3.0
+IMP: code
+#endif
+
+// !!!!! what if this is a metafile DC
+#ifndef WIN32
+ /* save the old objects so we can put them back */
+ hLPen = GetCurrentObject( hdc, OBJ_PEN );
+ hLBrush = GetCurrentObject( hdc, OBJ_BRUSH);
+ hLFont = GetCurrentObject( hdc, OBJ_FONT);
+ hClipRgn = GetCurrentObject( hdc, OBJ_RGN);
+ hLPal = GetCurrentObject( hdc, OBJ_PALETTE);
+
+ if(hRegion = GetCurrentObject( hdc, OBJ_RGN))
+ {
+ if(hClipRgn = CreateRectRgn(0,0,0,0))
+ CombineRgn(hClipRgn,hRegion,hRegion,RGN_COPY);
+ }
+#endif // WIN32
+
+ // we should really remove this abort proc thing.
+
+ while(lpmr = GetEvent(lpmf,lpmr,FALSE))
+ {
+#if 0 //!!!!!
+ if(GET_pAbortProc(pdc))
+#else
+ if( 0 )
+#endif //!!!!!
+ {
+//!!!!! if((bPrint = (*(pdc->pAbortProc))(hdc,0)) == FALSE)
+ {
+ GetEvent(lpmf,lpmr,TRUE);
+ RestoreDC(hdc,0);
+ goto exitPlayMetaFile20;
+ }
+ }
+ PlayMetaFileRecord(hdc,pht,lpmr,noObjs);
+ }
+
+ bPrint = TRUE;
+exitPlayMetaFile20:
+ /* if we fail restoring an object, we need to select some
+ default object so that we can DeleteObject any Metafile-
+ selected objects */
+
+#ifndef WIN32
+ if(!SelectObject(hdc,hLPen))
+ SelectObject(hdc,GetStockObject(BLACK_PEN));
+ if(!SelectObject(hdc,hLBrush))
+ SelectObject(hdc,GetStockObject(BLACK_BRUSH));
+ if(!SelectPalette(hdc, GetCurrentObject( hdc, OBJ_PALETTE), FALSE))
+ SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
+
+ if(!SelectObject(hdc,hLFont))
+ {
+ /* if we cannot select the original font back in, we
+ ** select the system font. this will allow us to delete
+ ** the metafile font selected. to insure that the system
+ ** font gets selected, we reset the DC's transform to
+ ** default. after the selection, we restore this stuff
+ */
+ oldVprtExt = GetViewportExt(hdc);
+ oldWndExt = GetWindowExt(hdc);
+ oldMapMode = SetMapMode(hdc,MM_TEXT);
+
+ SelectObject(hdc,GetStockObject(SYSTEM_FONT));
+
+ SetMapMode(hdc,oldMapMode);
+ SetWindowExt(hdc,LOWORD (oldWndExt),HIWORD (oldWndExt));
+ SetViewportExt(hdc,LOWORD (oldVprtExt),HIWORD (oldVprtExt));
+ }
+
+ if(hClipRgn)
+ {
+ SelectObject(hdc,hClipRgn);
+ DeleteObject(hClipRgn);
+ }
+#endif // WIN32
+
+ for(i = 0; i < lpmf->MetaFileHeader.mtNoObjects; ++i)
+ {
+ if(pht->objectHandle[i])
+ DeleteObject(pht->objectHandle[i]);
+ }
+
+#ifndef WIN32
+ /* if we fiddled with the map mode because we could not
+ ** restore the original font, then maybe we can restore the
+ ** font now */
+ if(oldMapMode > 0)
+ SelectObject(hdc,hLFont);
+#endif // WIN32
+
+ if(hht)
+ {
+ GlobalUnlock(hht);
+ GlobalFree(hht);
+ }
+
+exitPlayMetaFile10:
+ GlobalUnlock(hmf);
+ }
+
+exitPlayMetaFile:
+ return(bPrint);
+}
+#endif // this is going to gdi.dll
+
+/***************************** Internal Function **************************\
+* BOOL NEAR PASCAL IsDIBBlackAndWhite
+*
+* Check to see if this DIB is a black and white DIB (and should be
+* converted into a mono bitmap as opposed to a color bitmap).
+*
+* Returns: TRUE it is a B&W bitmap
+* FALSE this sucker is for color
+*
+* Effects: ?
+*
+* Warnings: ?
+*
+* History:
+\***************************************************************************/
+
+BOOL INTERNAL IsDIBBlackAndWhite(LPBITMAPINFOHEADER lpDIBInfo)
+{
+ LPDWORD lpRGB;
+
+ GdiLogFunc3( " IsDIBBlackAndWhite");
+
+ /* pointer color table */
+ lpRGB = (LPDWORD)((LPBITMAPINFO)lpDIBInfo)->bmiColors;
+
+ if ((lpDIBInfo->biBitCount == 1 && lpDIBInfo->biPlanes == 1)
+ && (lpRGB[0] == (DWORD)0)
+ && (lpRGB[1] == (DWORD)0xFFFFFF))
+ return(TRUE);
+ else
+ return(FALSE);
+}
+
+
+/***************************** Internal Function **************************\
+* BigRead
+*
+* allows reads of greater than 64K
+*
+* Returns: Number of bytes read
+*
+\***************************************************************************/
+
+DWORD INTERNAL BigRead(UINT fileNumber, LPSTR lpRecord, DWORD dwSizeRec)
+{
+ DWORD dwRead = dwSizeRec;
+ HPBYTE hpStuff;
+
+ GdiLogFunc2( " BigRead");
+
+ hpStuff = (HPBYTE)lpRecord;
+
+ while (dwRead > MAXFILECHUNK)
+ {
+ if (_lread(fileNumber, (LPSTR)hpStuff, MAXFILECHUNK) != MAXFILECHUNK)
+ return(0);
+
+ dwRead -= MAXFILECHUNK;
+ hpStuff += MAXFILECHUNK;
+ }
+
+ if (_lread(fileNumber, (LPSTR)hpStuff, (UINT)dwRead) != (UINT)dwRead)
+ return(0);
+
+ return(dwSizeRec);
+}
+
+
+/***************************** Internal Function **************************\
+* UseStretchDIBits
+*
+* set this directly to the device using StretchDIBits.
+* if DIB is black&white, don't do this.
+*
+* Returns:
+* TRUE --- operation successful
+* FALSE -- decided not to use StretchDIBits
+*
+* Effects: ?
+*
+* Warnings: ?
+*
+* History:
+\***************************************************************************/
+
+BOOL INTERNAL UseStretchDIB(HDC hDC, WORD magic, LPMETARECORD lpMR)
+{
+ LPBITMAPINFOHEADER lpDIBInfo;
+ int sExtX, sExtY;
+ int sSrcX, sSrcY;
+ int DstX, DstY, DstXE, DstYE;
+
+ if (magic == META_DIBBITBLT)
+ {
+ lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[8];
+
+ DstX = lpMR->rdParm[7];
+ DstY = lpMR->rdParm[6];
+
+ sSrcX = lpMR->rdParm[3];
+ sSrcY = lpMR->rdParm[2];
+ DstXE = sExtX = lpMR->rdParm[5];
+ DstYE = sExtY = lpMR->rdParm[4];
+ }
+ else
+ {
+ lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[10];
+
+ DstX = lpMR->rdParm[9];
+ DstY = lpMR->rdParm[8];
+ DstXE = lpMR->rdParm[7];
+ DstYE = lpMR->rdParm[6];
+
+ sSrcX = lpMR->rdParm[5];
+ sSrcY = lpMR->rdParm[4];
+ sExtX = lpMR->rdParm[3];
+ sExtY = lpMR->rdParm[2];
+ }
+
+ /* if DIB is black&white, we don't really want to do this */
+ if (IsDIBBlackAndWhite(lpDIBInfo))
+ return(FALSE);
+
+ StretchDIBits(hDC, DstX, DstY, DstXE, DstYE,
+ sSrcX, sSrcY, sExtX, sExtY,
+ (LPBYTE)((LPSTR)lpDIBInfo + lpDIBInfo->biSize
+ + GetSizeOfColorTable(lpDIBInfo)),
+ (LPBITMAPINFO)lpDIBInfo, DIB_RGB_COLORS,
+ (MAKELONG(lpMR->rdParm[1], lpMR->rdParm[0])));
+ return(TRUE);
+}
+
+/***************************** Internal Function **************************\
+* GetEvent
+*
+* This routine will now open a disk metafile in READ_ONLY mode. This will
+* allow us to play read-only metafiles or to share such file.
+*
+* [amitc: 06/19/91]
+\***************************************************************************/
+
+LPMETARECORD INTERNAL GetEvent(LPMETAFILE lpMF, HPMETARECORD lpMR, BOOL bFree)
+// BOOL bFree; /* non-zero ==> done with metafile */
+{
+ int fileNumber = 0;
+ WORD i;
+ LPWORD lpCache = NULL;
+ LPWORD lpMRbuf;
+ HANDLE hMF;
+ DWORD rdSize;
+
+ GdiLogFunc2( " GetEvent");
+
+#ifdef WIN32
+ hMF = GlobalHandle(lpMF);
+#else
+ hMF = LOWORD(GlobalHandle(HIWORD((DWORD)(lpMF))));
+#endif
+
+ ASSERTGDI( hMF != (HANDLE)NULL, "GetEvent: Global Handle failed");
+
+ if (lpMF->MetaFileHeader.mtType == MEMORYMETAFILE)
+ {
+ /* Are we at the end of the metafile */
+ if(lpMR && lpMR->rdFunction == 0)
+ return((LPMETARECORD)0);
+
+ /* done with metafile, so free up the temp selector */
+ else if (bFree)
+ {
+ if (lpMR)
+ #ifndef WIN32
+ FreeSelector(HIWORD(lpMR));
+ #endif
+ return((LPMETARECORD)0);
+ }
+ else
+ {
+ /* if we don't already have a selector, get one */
+ if (lpMR == NULL)
+ {
+ #ifdef WIN32
+ lpMR = (HPMETARECORD)((LPMETADATA)lpMF)->metaDataStuff;
+ // lpMR = (LPMETARECORD)GlobalLock(lpMF->hMetaData);
+ #else
+ lpMR = (LPMETARECORD)MAKELP(AllocSelector(HIWORD((DWORD)&lpMF->MetaFileNumber)),LOWORD((DWORD)&lpMF->MetaFileNumber));
+ #endif
+ }
+ else
+ lpMR = (LPMETARECORD) (((HPWORD)lpMR)+lpMR->rdSize);
+
+ /* end of the metafile. free up the selector we were using */
+ if (lpMR->rdFunction == 0)
+ {
+ #ifndef WIN32
+ FreeSelector(HIWORD(lpMR));
+ #endif
+ return((LPMETARECORD)0);
+ }
+ }
+ return(lpMR);
+ }
+ else if (lpMF->MetaFileHeader.mtType == DISKMETAFILE)
+ {
+ if (bFree)
+ goto errGetEvent; /* never TRUE on the first call to GetEvent */
+
+ if (lpMR == NULL)
+ {
+ if ((fileNumber = OpenFile((LPSTR)lpMF->MetaFileBuffer.szPathName, (LPOFSTRUCT)&(lpMF->MetaFileBuffer), (WORD)OF_PROMPT|OF_REOPEN|OF_READ)) != -1)
+ {
+ if (lpMF->MetaFileRecordHandle = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(DWORD)(lpMF->MetaFileHeader.mtMaxRecord * sizeof(WORD))))
+ {
+ lpMR = (LPMETARECORD)GlobalLock(lpMF->MetaFileRecordHandle);
+ lpMF->MetaFilePosition = _lread(lpMF->MetaFileNumber = fileNumber, (LPSTR)&lpMF->MetaFileHeader, sizeof(METAHEADER));
+
+ // Check for an Aldus header
+ if (*((LPDWORD)&(lpMF->MetaFileHeader)) == 0x9AC6CDD7)
+ {
+ _llseek( fileNumber, 22, 0);
+ lpMF->MetaFilePosition = 22 + _lread(fileNumber,(LPSTR)(&(lpMF->MetaFileHeader)),sizeof(METAHEADER));
+ }
+
+ lpMF->MetaFileHeader.mtType = DISKMETAFILE;
+
+ if (!MetaCache.hCache)
+ {
+ MetaCache.hCache = AllocBuffer(&MetaCache.wCacheSize);
+ MetaCache.wCacheSize >>= 1;
+ MetaCache.hMF = hMF;
+
+ /* force cache fill on first access */
+ MetaCache.wCachePos = MetaCache.wCacheSize;
+ }
+
+ if (!(lpMF->MetaFileBuffer.fFixedDisk))
+ {
+ _lclose(fileNumber);
+
+ /* need to update the following for floppy files -- amitc */
+ fileNumber = 0 ;
+ lpMF->MetaFileNumber = 0 ;
+ }
+ }
+ }
+ else
+ return((LPMETARECORD)0);
+ }
+
+ /* update fileNumber, this is so that floopy based files can be closed
+ and not left open -- amitc */
+
+ fileNumber = lpMF->MetaFileNumber ;
+
+ if (lpMR)
+ {
+ if (MetaCache.hMF == hMF)
+ {
+
+ lpCache = (LPWORD) GlobalLock(MetaCache.hCache);
+ lpMRbuf = (LPWORD) lpMR;
+
+ // Make sure we can read the size and function fields
+ if (MetaCache.wCachePos >= (WORD)(MetaCache.wCacheSize - 2))
+ {
+ WORD cwCopy;
+
+ if (!fileNumber)
+ if ((fileNumber = GetFileNumber(lpMF)) == -1)
+ goto errGetEvent;
+
+ // We need to fill up the cache but save any data already
+ // in the cache
+ cwCopy = MetaCache.wCacheSize - MetaCache.wCachePos;
+ for (i = 0; i < cwCopy; i++)
+ {
+ lpCache[i] = lpCache[MetaCache.wCacheSize-(cwCopy-i)];
+ }
+ lpMF->MetaFilePosition += _lread(fileNumber,
+ (LPSTR) (lpCache + cwCopy),
+ (MetaCache.wCacheSize-cwCopy) << 1);
+ MetaCache.wCachePos = 0;
+ }
+
+ lpCache += MetaCache.wCachePos;
+ rdSize = ((LPMETARECORD)lpCache)->rdSize;
+
+ /* Check for end */
+ if (!((LPMETARECORD)lpCache)->rdFunction)
+ goto errGetEvent;
+
+ // Make sure we can read the rest of the metafile record
+ if (rdSize + MetaCache.wCachePos > MetaCache.wCacheSize)
+ {
+ if (!fileNumber)
+ if ((fileNumber = GetFileNumber(lpMF))
+ == -1)
+ goto errGetEvent;
+
+ for (i=MetaCache.wCachePos; i < MetaCache.wCacheSize; ++i)
+ *lpMRbuf++ = *lpCache++;
+
+ lpMF->MetaFilePosition +=
+ BigRead(fileNumber, (LPSTR) lpMRbuf,
+ (DWORD)(rdSize
+ + (DWORD)MetaCache.wCachePos
+ - (DWORD)MetaCache.wCacheSize) << 1);
+
+ // Mark the cache as depleted because we just read
+ // directly into the metafile record rather than the cache
+ MetaCache.wCachePos = MetaCache.wCacheSize;
+ }
+ else
+ {
+ ASSERTGDI( HIWORD(rdSize) == 0, "Huge rdsize");
+ for (i = 0; i < LOWORD(rdSize); ++i)
+ *lpMRbuf++ = *lpCache++;
+
+ MetaCache.wCachePos += LOWORD(rdSize);
+ }
+
+ GlobalUnlock(MetaCache.hCache);
+
+ return lpMR;
+ }
+
+ if ((fileNumber = GetFileNumber(lpMF)) == -1)
+ goto errGetEvent;
+
+ lpMF->MetaFilePosition += _lread(fileNumber, (LPSTR)&lpMR->rdSize, sizeof(DWORD));
+ lpMF->MetaFilePosition += BigRead(fileNumber, (LPSTR)&lpMR->rdFunction, (DWORD)(lpMR->rdSize * sizeof(WORD)) - sizeof(DWORD));
+ if (!(lpMF->MetaFileBuffer.fFixedDisk))
+ {
+ _lclose(fileNumber);
+ lpMF->MetaFileNumber = 0 ;
+ fileNumber = 0 ;
+ }
+
+ if (lpMR->rdFunction == 0)
+ {
+errGetEvent:;
+
+ if (lpMF->MetaFileBuffer.fFixedDisk || fileNumber)
+ _lclose(lpMF->MetaFileNumber);
+ GlobalUnlock(lpMF->MetaFileRecordHandle);
+ GlobalFree(lpMF->MetaFileRecordHandle);
+ lpMF->MetaFileNumber = 0;
+
+ if (MetaCache.hMF == hMF)
+ {
+ if (lpCache)
+ GlobalUnlock(MetaCache.hCache);
+ GlobalFree(MetaCache.hCache);
+ MetaCache.hCache = MetaCache.hMF = 0;
+ }
+
+ return((LPMETARECORD)0);
+ }
+ }
+ return(lpMR);
+
+ }
+
+ return((LPMETARECORD)0);
+}
+
+
+/***************************** Internal Function **************************\
+* void GDIENTRY PlayMetaFileRecord
+*
+* Plays a metafile record by executing the GDI function call contained
+* withing the metafile record
+*
+* Effects:
+*
+\***************************************************************************/
+#if 0 // this is going to gdi.dll
+
+void
+GDIENTRY PlayMetaFileRecord(
+ HDC hdc,
+ LPHANDLETABLE lpHandleTable,
+ LPMETARECORD lpMR,
+ WORD noObjs
+ )
+
+{
+ WORD magic;
+ HANDLE hObject;
+ HANDLE hOldObject;
+ HBRUSH hBrush;
+ HRGN hRgn;
+ HANDLE hPal;
+ BOOL bExtraSel = FALSE;
+
+ dprintf( 3," PlayMetaFileRecord 0x%lX", lpMR);
+
+ if (!ISDCVALID(hdc))
+ return;
+
+ magic = lpMR->rdFunction;
+
+ /* being safe, make sure that the lp will give us full access to
+ ** the record header without overstepping a segment boundary.
+ */
+ #ifndef WIN32
+ if ((unsigned)(LOWORD((DWORD)lpMR)) > 0x7000)
+ {
+ lpMR = (LPMETARECORD)MAKELP(AllocSelector(HIWORD((DWORD)lpMR)),LOWORD((DWORD)lpMR));
+ bExtraSel = TRUE;
+ }
+ #endif // WIN32
+
+ switch (magic & 255)
+ {
+ case (META_BITBLT & 255):
+ case (META_STRETCHBLT & 255):
+ {
+ HDC hSDC;
+ HANDLE hBitmap;
+ LPBITMAP lpBitmap;
+ int delta = 0;
+
+ /* if playing into another Metafile, do direct copy */
+ if (PlayIntoAMetafile(lpMR, hdc))
+ goto errPlayMetaFileRecord20;
+
+ if ((lpMR->rdSize - 3) == (magic >> 8))
+ {
+ hSDC = hdc;
+ delta = 1;
+ }
+ else
+ {
+ if (hSDC = CreateCompatibleDC(hdc))
+ {
+ if (magic == META_BITBLT)
+ lpBitmap = (LPBITMAP)&lpMR->rdParm[8];
+ else
+ lpBitmap = (LPBITMAP)&lpMR->rdParm[10];
+
+ //!!!!! ALERT DWORD align on NT
+ if (hBitmap = CreateBitmap(lpBitmap->bmWidth,
+ lpBitmap->bmHeight,
+ lpBitmap->bmPlanes,
+ lpBitmap->bmBitsPixel,
+ (LPBYTE)&lpBitmap->bmBits))
+ hOldObject = SelectObject(hSDC, hBitmap);
+ else
+ goto errPlayMetaFileRecord10;
+ }
+ else
+ goto errPlayMetaFileRecord20;
+ }
+
+ if (hSDC)
+ {
+ if (magic == META_BITBLT)
+ BitBlt(hdc, lpMR->rdParm[7 + delta],
+ lpMR->rdParm[6 + delta],
+ lpMR->rdParm[5 + delta],
+ lpMR->rdParm[4 + delta],
+ hSDC,
+ lpMR->rdParm[3],
+ lpMR->rdParm[2],
+ MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
+ else
+ StretchBlt(hdc, lpMR->rdParm[9 + delta],
+ lpMR->rdParm[8 + delta],
+ lpMR->rdParm[7 + delta],
+ lpMR->rdParm[6 + delta],
+ hSDC,
+ lpMR->rdParm[5],
+ lpMR->rdParm[4],
+ lpMR->rdParm[3],
+ lpMR->rdParm[2],
+ MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
+ }
+ if (hSDC != hdc)
+ {
+ if (SelectObject(hSDC, hOldObject))
+ DeleteObject(hBitmap);
+errPlayMetaFileRecord10:;
+ DeleteDC(hSDC);
+errPlayMetaFileRecord20:;
+ }
+ }
+ break;
+
+ case (META_DIBBITBLT & 255):
+ case (META_DIBSTRETCHBLT & 255):
+ {
+ HDC hSDC;
+ HANDLE hBitmap;
+ LPBITMAPINFOHEADER lpDIBInfo ;
+ int delta = 0;
+ HANDLE hOldPal;
+
+ /* if playing into another metafile, do direct copy */
+ if (PlayIntoAMetafile(lpMR, hdc))
+ goto errPlayMetaFileRecord40;
+
+ if ((lpMR->rdSize - 3) == (magic >> 8))
+ {
+ hSDC = hdc;
+ delta = 1;
+ }
+ else
+ {
+ if( (magic & 255) == (META_DIBSTRETCHBLT & 255) )
+ if (UseStretchDIB(hdc, magic, lpMR))
+ goto errPlayMetaFileRecord40;
+
+ if (hSDC = CreateCompatibleDC(hdc))
+ {
+ /* set up the memDC to have the same palette */
+ hOldPal = SelectPalette(hSDC, GetCurrentObject(hdc,OBJ_PALETTE), TRUE);
+
+ if (magic == META_DIBBITBLT)
+ lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[8];
+ else
+ lpDIBInfo = (LPBITMAPINFOHEADER)&lpMR->rdParm[10];
+
+ /* now create the bitmap for the MemDC and fill in the bits */
+
+ /* the processing for old and new format of metafiles is
+ different here (till hBitmap is obtained) */
+
+ /* new metafile version */
+ hBitmap = CreateBitmapForDC (hdc,lpDIBInfo);
+
+ if (hBitmap)
+ hOldObject = SelectObject (hSDC, hBitmap) ;
+ else
+ goto errPlayMetaFileRecord30 ;
+ }
+ else
+ goto errPlayMetaFileRecord40;
+ }
+
+ if (hSDC)
+ {
+ if (magic == META_DIBBITBLT)
+ BitBlt(hdc, lpMR->rdParm[7 + delta],
+ lpMR->rdParm[6 + delta],
+ lpMR->rdParm[5 + delta],
+ lpMR->rdParm[4 + delta],
+ hSDC,
+ lpMR->rdParm[3],
+ lpMR->rdParm[2],
+ MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
+ else
+ StretchBlt(hdc, lpMR->rdParm[9 + delta],
+ lpMR->rdParm[8 + delta],
+ lpMR->rdParm[7 + delta],
+ lpMR->rdParm[6 + delta],
+ hSDC,
+ lpMR->rdParm[5],
+ lpMR->rdParm[4],
+ lpMR->rdParm[3],
+ lpMR->rdParm[2],
+ MAKELONG(lpMR->rdParm[0], lpMR->rdParm[1]));
+ }
+
+ if (hSDC != hdc)
+ {
+ /* Deselect hDC's palette from memDC */
+ SelectPalette(hSDC, hOldPal, TRUE);
+ if (SelectObject(hSDC, hOldObject))
+ DeleteObject(hBitmap);
+errPlayMetaFileRecord30:;
+ DeleteDC(hSDC);
+errPlayMetaFileRecord40:;
+ }
+ }
+ break;
+
+ case (META_SELECTOBJECT & 255):
+ {
+ HANDLE hObject;
+
+ if (hObject = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ SelectObject(hdc, hObject);
+ }
+ break;
+
+ case (META_CREATEPENINDIRECT & 255):
+ {
+ #ifdef WIN32
+ LOGPEN lp;
+
+ lp.lopnStyle = lpMR->rdParm[0];
+ lp.lopnWidth.x = lpMR->rdParm[1];
+ lp.lopnColor = *((COLORREF *)&lpMR->rdParm[3]);
+ if (hObject = CreatePenIndirect(&lp))
+ #else
+ if (hObject = CreatePenIndirect((LPLOGPEN)&lpMR->rdParm[0]))
+ #endif
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+ break;
+ }
+
+ case (META_CREATEFONTINDIRECT & 255):
+ {
+ LOGFONT lf;
+ LPLOGFONT lplf = &lf;
+
+ LOGFONT32FROM16( lplf, ((LPLOGFONT)&lpMR->rdParm[0]));
+ if (hObject = CreateFontIndirect(lplf))
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+ }
+ break;
+
+ case (META_CREATEPATTERNBRUSH & 255):
+ {
+ HANDLE hBitmap;
+ LPBITMAP lpBitmap;
+
+ lpBitmap = (LPBITMAP)lpMR->rdParm;
+
+ //!!!!! ALERT DWORD align on NT
+ if (hBitmap = CreateBitmapIndirect(lpBitmap))
+ {
+ LPBITMAPINFO lpbmInfo;
+ HANDLE hmemInfo;
+
+ hmemInfo = GlobalAlloc( GMEM_ZEROINIT | GMEM_MOVEABLE,
+ sizeof(BITMAPINFO) + 2<<(lpBitmap->bmPlanes*lpBitmap->bmBitsPixel));
+
+ lpbmInfo = (LPBITMAPINFO)GlobalLock( hmemInfo);
+
+ lpbmInfo->bmiHeader.biPlanes = lpBitmap->bmPlanes;
+ lpbmInfo->bmiHeader.biBitCount = lpBitmap->bmBitsPixel;
+ SetDIBits( (HDC)NULL, hBitmap, 0, lpBitmap->bmHeight,
+ (LPBYTE)&lpMR->rdParm[8], lpbmInfo, DIB_RGB_COLORS );
+
+ if (hObject = CreatePatternBrush(hBitmap))
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+
+ GlobalUnlock(hmemInfo);
+ GlobalFree(hmemInfo);
+ DeleteObject(hBitmap);
+ }
+ }
+ break;
+
+ case (META_DIBCREATEPATTERNBRUSH & 255):
+ {
+ HDC hMemDC ;
+ HANDLE hBitmap;
+ LPBITMAPINFOHEADER lpDIBInfo ;
+ WORD nDIBSize; /* number of WORDs in packed DIB */
+ HANDLE hDIB;
+ LPWORD lpDIB;
+ LPWORD lpSourceDIB;
+ WORD i;
+
+
+ if (lpMR->rdParm[0] == BS_PATTERN)
+ {
+ /* the address of the second paramter is the address of the DIB
+ header, extract it */
+ lpDIBInfo = (BITMAPINFOHEADER FAR *) &lpMR->rdParm[2];
+
+ /* now create a device dependend bitmap compatible to the default
+ screen DC - hScreenDC and extract the bits from the DIB into it.
+ The following function does all these, and returns a HANDLE
+ to the device dependent BItmap. */
+
+ /* we will use a dummy memory DC compatible to the screen DC */
+ hMemDC = CreateCompatibleDC (hScreenDC) ;
+
+ hBitmap = CreateBitmapForDC (hScreenDC,lpDIBInfo) ;
+
+ if (hBitmap)
+ {
+ if (hObject = CreatePatternBrush(hBitmap))
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+ DeleteObject(hBitmap);
+ }
+
+ /* delete the dummy memory DC for new version Metafiles*/
+ DeleteDC (hMemDC) ;
+ }
+
+ /* this is a DIBPattern brush */
+ else
+ {
+ /* get size of just the packed DIB */
+ nDIBSize = (WORD) (lpMR->rdSize - 4);
+ if ((hDIB = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(LONG)(nDIBSize << 1))))
+ {
+ lpDIB = (WORD FAR *) GlobalLock (hDIB);
+ lpSourceDIB = (WORD FAR *)&lpMR->rdParm[2];
+
+ /* copy the DIB into our new memory block */
+ for (i = 0; i < nDIBSize; i++)
+ *lpDIB++ = *lpSourceDIB++;
+
+ GlobalUnlock (hDIB);
+
+ if (hObject = CreateDIBPatternBrush(hDIB, lpMR->rdParm[1]))
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+
+ GlobalFree(hDIB);
+ }
+ }
+ }
+ break;
+
+ case (META_CREATEBRUSHINDIRECT & 255):
+ {
+ #ifdef WIN32
+ LOGBRUSH lb;
+
+ lb.lbStyle = lpMR->rdParm[0];
+ lb.lbColor = *((COLORREF *)&lpMR->rdParm[1]);
+ lb.lbHatch = lpMR->rdParm[3];
+
+ if (hObject = CreateBrushIndirect(&lb))
+ #else
+ if (hObject = CreateBrushIndirect((LPLOGBRUSH)&lpMR->rdParm[0]))
+ #endif
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+ break;
+ }
+
+ case (META_POLYLINE & 255):
+ {
+ LPPOINT lppt;
+ Polyline(hdc, (lppt=CONVERTPTS(&lpMR->rdParm[1],lpMR->rdParm[0])), lpMR->rdParm[0]);
+ FREECONVERT(lppt);
+ break;
+ }
+
+ case (META_POLYGON & 255):
+ {
+ LPPOINT lppt;
+ Polygon(hdc, (lppt=CONVERTPTS(&lpMR->rdParm[1],lpMR->rdParm[0])), lpMR->rdParm[0]);
+ FREECONVERT(lppt);
+ break;
+ }
+
+ case (META_POLYPOLYGON & 255):
+ {
+ LPPOINT lppt;
+ #ifdef WIN32
+ WORD cPts=0;
+ WORD ii;
+
+ for(ii=0; ii<lpMR->rdParm[0]; ii++)
+ cPts += ((LPWORD)&lpMR->rdParm[1])[ii];
+ #endif // WIN32
+
+ PolyPolygon(hdc,
+ (lppt=CONVERTPTS(&lpMR->rdParm[1] + lpMR->rdParm[0], cPts)),
+ (LPINT)&lpMR->rdParm[1],
+ lpMR->rdParm[0]);
+ FREECONVERT(lppt);
+ }
+ break;
+
+ case (META_EXTTEXTOUT & 255):
+ {
+ LPWORD lpdx;
+ LPSTR lpch;
+ LPRECT lprt;
+
+ lprt = (lpMR->rdParm[3] & (ETO_OPAQUE|ETO_CLIPPED)) ? (LPRECT)&lpMR->rdParm[4] : 0;
+ lpch = (LPSTR)&lpMR->rdParm[4] + ((lprt) ? sizeof(RECT) : 0);
+
+ /* dx array starts at next word boundary after char string */
+ lpdx = (LPWORD)(lpch + ((lpMR->rdParm[2] + 1) & 0xFFFE));
+
+ /* check to see if there is a Dx array by seeing if
+ structure ends after the string itself
+ */
+ if ( ((DWORD)((LPWORD)lpdx - (LPWORD)(lpMR))) >= lpMR->rdSize)
+ lpdx = NULL;
+ else
+ lpdx = (LPWORD)CONVERTINTS((signed short FAR *)lpdx, lpMR->rdParm[2]);
+
+ ExtTextOut(hdc, lpMR->rdParm[1], lpMR->rdParm[0], lpMR->rdParm[3],
+ lprt, (LPSTR)lpch, lpMR->rdParm[2], (LPINT)lpdx);
+ if (lpdx != (LPWORD)NULL)
+ FREECONVERT(lpdx);
+ break;
+ }
+
+ case (META_TEXTOUT & 255):
+ TextOut(hdc, lpMR->rdParm[lpMR->rdSize-4], lpMR->rdParm[lpMR->rdSize-5], (LPSTR)&lpMR->rdParm[1], lpMR->rdParm[0]);
+ break;
+
+ case (META_ESCAPE & 255):
+ {
+ LPSTR lpStuff;
+
+ if (lpMR->rdParm[0] != MFCOMMENT)
+ {
+ lpStuff = (LPSTR)&lpMR->rdParm[2];
+#ifdef OLDEXTTEXTOUT
+ if (lpMR->rdParm[0] == EXTTEXTOUT)
+ {
+ EXTTEXTDATA ExtData;
+
+ ExtData.xPos = lpMR->rdParm[2];
+ ExtData.yPos = lpMR->rdParm[3];
+ ExtData.cch = lpMR->rdParm[4];
+ ExtData.rcClip = *((LPRECT)&lpMR->rdParm[5]);
+ ExtData.lpString = (LPSTR)&lpMR->rdParm[9];
+ ExtData.lpWidths = (WORD FAR *)&lpMR->rdParm[9+((ExtData.cch+1)/2)];
+ lpStuff = (LPSTR)&ExtData;
+ }
+#endif
+ Escape(hdc, lpMR->rdParm[0], lpMR->rdParm[1], lpStuff, (LPSTR)0);
+ }
+ }
+ break;
+
+ case (META_FRAMEREGION & 255):
+ if((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ && (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]]))
+ FrameRgn(hdc, hRgn, hBrush, lpMR->rdParm[3], lpMR->rdParm[2]);
+ break;
+
+ case (META_PAINTREGION & 255):
+ if(hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ PaintRgn(hdc, hRgn);
+ break;
+
+ case (META_INVERTREGION & 255):
+ if(hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ InvertRgn(hdc, hRgn);
+ break;
+
+ case (META_FILLREGION & 255):
+ if((hRgn = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ && (hBrush = lpHandleTable->objectHandle[lpMR->rdParm[1]]))
+ FillRgn(hdc, hRgn, hBrush);
+ break;
+
+#ifdef DEADCODE
+#ifdef GDI104
+ case (META_DRAWTEXT & 255):
+ MFDrawText(hdc, (LPPOINT)&lpMR->rdParm[6], lpMR->rdParm[1], (LPPOINT)&lpMR->rdParm[2], lpMR->rdParm[0]);
+ break;
+#endif
+#endif
+
+/*
+*** in win2, METACREATEREGION records contained an entire region object,
+*** including the full header. this header changed in win3.
+***
+*** to remain compatible, the region records will be saved with the
+*** win2 header. here we read a win2 header with region, and actually
+*** create a win3 header with same region internals
+*/
+
+ case (META_CREATEREGION & 255):
+ {
+#if 0 //!!!!!
+ HANDLE hRgn;
+ WORD *pRgn;
+ WORD iChar;
+ LPWORD *lpTemp;
+
+ iChar = lpMR->rdSize*2 - sizeof(WIN2OBJHEAD) - RECHDRSIZE;
+ if (hRgn = LocalAlloc(LMEM_ZEROINIT, iChar + sizeof(ILOBJHEAD)))
+
+ {
+ pRgn = (WORD *)Lock IT(hRgn);
+
+ *((WIN2OBJHEAD *)pRgn) = *((WIN2OBJHEAD FAR *)&lpMR->rdParm[0]);
+ ((ILOBJHEAD *)pRgn)->ilObjMetaList = 0;
+
+ lpTemp = (LPWORD)&(lpMR->rdParm[0]);
+ ((WIN2OBJHEAD FAR *)lpTemp)++;
+
+ ((ILOBJHEAD *)pRgn)++; /* --> actual region */
+
+ for(i = 0; i < (iChar >> 1) ; i++)
+ *pRgn++ = *lpTemp++;
+ pRgn = (WORD *)lock IT(hRgn);
+ ((PRGN)pRgn)->rgnSize = iChar + sizeof(ILOBJHEAD);
+
+ AddToHandleTable(lpHandleTable, hRgn, noObjs);
+ }
+#endif //!!!!!
+ HANDLE hRgn = NULL;
+ HANDLE hRgn2 = NULL;
+ WORD cScans;
+ WORD cPnts;
+ WORD cbIncr;
+ LPWIN3REGION lpW3Rgn = (LPWIN3REGION)lpMR->rdParm;
+ LPSCAN lpScan = lpW3Rgn->aScans;
+ LPWORD lpXs;
+
+ for( cScans=lpW3Rgn->cScans; cScans>0; cScans--)
+ {
+
+ // If this is the first scan then hRgn2 IS the region
+ // otherwise OR it in
+ if( hRgn == NULL )
+ {
+ // Create the first region in this scan
+ hRgn = CreateRectRgn( lpScan->scnPntsX[0], lpScan->scnPntTop,
+ lpScan->scnPntsX[1], lpScan->scnPntBottom);
+
+ // Allocate a worker region
+ hRgn2 = CreateRectRgn( 1, 1, 2, 2);
+ }
+ else
+ {
+ SetRectRgn( hRgn2, lpScan->scnPntsX[0], lpScan->scnPntTop,
+ lpScan->scnPntsX[1], lpScan->scnPntBottom );
+ CombineRgn( hRgn, hRgn, hRgn2, RGN_OR );
+ }
+
+ lpXs = &lpScan->scnPntsX[2];
+
+ // If there are more regions on this scan OR them in
+ for(cPnts = (WORD)(lpScan->scnPntCnt-2); cPnts>0; cPnts-=2)
+ {
+ SetRectRgn( hRgn2, *lpXs++, lpScan->scnPntTop,
+ *lpXs++, lpScan->scnPntBottom );
+
+ CombineRgn( hRgn, hRgn, hRgn2, RGN_OR );
+ }
+
+ cbIncr = (WORD)sizeof(SCAN) + (WORD)(lpScan->scnPntCnt-2);
+ cbIncr = (WORD)sizeof(WORD)*(WORD)(lpScan->scnPntCnt-2);
+ cbIncr = (WORD)sizeof(SCAN) + (WORD)sizeof(WORD)*(WORD)(lpScan->scnPntCnt-2);
+ cbIncr = (WORD)sizeof(SCAN) + (WORD)(sizeof(WORD)*(lpScan->scnPntCnt-2));
+ lpScan = (LPSCAN)((LPBYTE)lpScan + cbIncr);
+ }
+
+ if( hRgn2 != NULL )
+ DeleteObject( hRgn2 );
+
+ AddToHandleTable(lpHandleTable, hRgn, noObjs);
+ }
+ break;
+
+ case (META_DELETEOBJECT & 255):
+ {
+ HANDLE h;
+
+ if (h = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ {
+ DeleteObjectPriv(h);
+ lpHandleTable->objectHandle[lpMR->rdParm[0]] = NULL;
+ }
+ }
+ break;
+
+ case (META_CREATEPALETTE & 255):
+ if (hObject = CreatePalette((LPLOGPALETTE)&lpMR->rdParm[0]))
+ AddToHandleTable(lpHandleTable, hObject, noObjs);
+ break;
+
+ case (META_SELECTPALETTE & 255):
+ if(hPal = lpHandleTable->objectHandle[lpMR->rdParm[0]])
+ {
+ SelectPalette(hdc, hPal, 0);
+ }
+ break;
+
+ case (META_REALIZEPALETTE & 255):
+ RealizePalette(hdc);
+ break;
+
+ case (META_SETPALENTRIES & 255):
+ /* we know the palette being set is the current palette */
+ SetPaletteEntriesPriv(GetCurrentObject(hdc,OBJ_PALETTE), lpMR->rdParm[0],
+ lpMR->rdParm[1], (LPPALETTEENTRY)&lpMR->rdParm[2]);
+ break;
+
+ case (META_ANIMATEPALETTE & 255):
+ AnimatePalettePriv(GetCurrentObject(hdc,OBJ_PALETTE), lpMR->rdParm[0],
+ lpMR->rdParm[1], (LPPALETTEENTRY)&lpMR->rdParm[2]);
+
+ break;
+
+ case (META_RESIZEPALETTE & 255):
+ ResizePalettePriv(GetCurrentObject(hdc,OBJ_PALETTE), lpMR->rdParm[0]);
+ break;
+
+ case (META_SETDIBTODEV & 255):
+ {
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ WORD ColorSize;
+
+ /* if playing into another metafile, do direct copy */
+ if (PlayIntoAMetafile(lpMR, hdc))
+ goto DontReallyPlay;
+
+ lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMR->rdParm[9]);
+
+ if (lpBitmapInfo->biClrUsed)
+ {
+ ColorSize = ((WORD)lpBitmapInfo->biClrUsed) *
+ (WORD)(lpMR->rdParm[0] == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+ }
+ else if (lpBitmapInfo->biBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (WORD)(1 << lpBitmapInfo->biBitCount) *
+ (WORD)(lpMR->rdParm[0] == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ ColorSize += sizeof(BITMAPINFOHEADER);
+
+ SetDIBitsToDevice(hdc, lpMR->rdParm[8], lpMR->rdParm[7],
+ lpMR->rdParm[6], lpMR->rdParm[5],
+ lpMR->rdParm[4], lpMR->rdParm[3],
+ lpMR->rdParm[2], lpMR->rdParm[1],
+ (BYTE FAR *)(((BYTE FAR *)lpBitmapInfo) + ColorSize),
+ (LPBITMAPINFO) lpBitmapInfo,
+ lpMR->rdParm[0]);
+DontReallyPlay:;
+ }
+ break;
+
+ case (META_STRETCHDIB & 255):
+ {
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ WORD ColorSize;
+
+ /* if playing into another metafile, do direct copy */
+ if (PlayIntoAMetafile(lpMR, hdc))
+ goto DontReallyPlay2;
+
+ lpBitmapInfo = (LPBITMAPINFOHEADER)&(lpMR->rdParm[11]);
+
+ if (lpBitmapInfo->biClrUsed)
+ {
+ ColorSize = ((WORD)lpBitmapInfo->biClrUsed) *
+ (WORD)(lpMR->rdParm[2] == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+ }
+ else if (lpBitmapInfo->biBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (WORD)(1 << lpBitmapInfo->biBitCount) *
+ (WORD)(lpMR->rdParm[2] == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ ColorSize += sizeof(BITMAPINFOHEADER);
+
+ StretchDIBits(hdc, lpMR->rdParm[10], lpMR->rdParm[9],
+ lpMR->rdParm[8], lpMR->rdParm[7],
+ lpMR->rdParm[6], lpMR->rdParm[5],
+ lpMR->rdParm[4], lpMR->rdParm[3],
+ (LPBYTE)(((BYTE FAR *)lpBitmapInfo) + ColorSize),
+ (LPBITMAPINFO) lpBitmapInfo,
+ lpMR->rdParm[2],
+ MAKELONG(lpMR->rdParm[1], lpMR->rdParm[0]));
+DontReallyPlay2:;
+ }
+ break;
+
+// Function that have new parameters on WIN32
+// Or have DWORDs that stayed DWORDs; all other INTs to DWORDs
+#ifdef WIN32
+ case (META_MOVETO & 255):
+ MoveTo( hdc, (long)lpMR->rdParm[1], (long)lpMR->rdParm[0], NULL );
+ break;
+
+ case (META_RESTOREDC & 255):
+ RestoreDC( hdc, (long)(signed short)lpMR->rdParm[0] );
+ break;
+
+ case (META_SETBKCOLOR & 255):
+ SetBkColor( hdc, (UINT)*((LPDWORD)lpMR->rdParm) );
+ break;
+
+ case (META_SETTEXTCOLOR & 255):
+ SetTextColor( hdc, (UINT)*((LPDWORD)lpMR->rdParm) );
+ break;
+
+ case (META_SETPIXEL & 255):
+ SetPixel( hdc, (UINT)lpMR->rdParm[3], (UINT)lpMR->rdParm[2],
+ (UINT)*((LPDWORD)lpMR->rdParm) );
+ break;
+
+ case (META_SETMAPPERFLAGS & 255):
+ SetMapperFlags( hdc, (UINT)*((LPDWORD)lpMR->rdParm) );
+ break;
+
+ case (META_FLOODFILL & 255):
+ FloodFill( hdc, (UINT)lpMR->rdParm[3], (UINT)lpMR->rdParm[2],
+ (UINT)*((LPDWORD)lpMR->rdParm) );
+ break;
+
+ case (META_EXTFLOODFILL & 255):
+ ExtFloodFill( hdc, (UINT)lpMR->rdParm[4], (UINT)lpMR->rdParm[3],
+ (UINT)*((LPDWORD)&lpMR->rdParm[1]), (UINT)lpMR->rdParm[0] );
+ break;
+
+ // These puppies all got a new NULL and have only two parameters and a DC.
+ case (META_SETWINDOWORG & 255):
+ case (META_SETWINDOWEXT & 255):
+ case (META_SETVIEWPORTORG & 255):
+ case (META_SETVIEWPORTEXT & 255):
+ case (META_OFFSETWINDOWORG & 255):
+ case (META_SCALEWINDOWEXT & 255):
+ case (META_OFFSETVIEWPORTORG & 255):
+ case (META_SCALEVIEWPORTEXT & 255):
+ {
+ FARPROC lpProc;
+
+ ASSERTGDI((magic&0x00ff) <= MAX_META_DISPATCH, "Unknown function to dispatch1");
+
+ lpProc = alpfnMetaFunc[magic&0x00ff];
+
+ ASSERTGDI( lpProc != (FARPROC)NULL, "function not in dispatch table1 ");
+
+ if (lpProc != (FARPROC)NULL)
+ (*lpProc)(hdc, (long)(short)lpMR->rdParm[1], (long)(short)lpMR->rdParm[0], NULL );
+ }
+ break;
+#endif // WIN32
+
+ default:
+ {
+ FARPROC lpProc;
+ signed short *pshort;
+
+ ASSERTGDI((magic&0x00ff) <= MAX_META_DISPATCH, "Unknown function to dispatch");
+
+ lpProc = alpfnMetaFunc[magic&0x00ff];
+
+ ASSERTGDI( (lpProc != (FARPROC)NULL) || (magic == META_SETRELABS), "function not in dispatch table");
+
+ if ((lpProc == (FARPROC)NULL))
+ return;
+
+ // Switch to the corresponding dispatcher by number of parameters
+ // The number of parameters in the dispatch number does not include the DC.
+ switch (magic >> 8)
+ {
+ typedef int (FAR PASCAL *META1PROC)(HDC);
+ typedef int (FAR PASCAL *META2PROC)(HDC, int);
+ typedef int (FAR PASCAL *META3PROC)(HDC, int, int);
+ typedef int (FAR PASCAL *META4PROC)(HDC, int, int, int);
+ typedef int (FAR PASCAL *META5PROC)(HDC, int, int, int, int);
+ typedef int (FAR PASCAL *META6PROC)(HDC, int, int, int, int, int);
+ typedef int (FAR PASCAL *META7PROC)(HDC, int, int, int, int, int, int);
+ typedef int (FAR PASCAL *META9PROC)(HDC, int, int, int, int, int, int, int, int);
+
+ case 0:
+ (*((META1PROC)lpProc))(hdc);
+ break;
+ case 1:
+ (*((META2PROC)lpProc))(hdc,lpMR->rdParm[0]);
+ break;
+ case 2:
+ (*((META3PROC)lpProc))(hdc,lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+ case 3:
+ (*((META4PROC)lpProc))(hdc,lpMR->rdParm[2],lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+ case 4:
+ (*((META5PROC)lpProc))(hdc,lpMR->rdParm[3],lpMR->rdParm[2],lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+ case 5:
+ (*((META6PROC)lpProc))(hdc,lpMR->rdParm[4],lpMR->rdParm[3],lpMR->rdParm[2],lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+ case 6:
+ (*((META7PROC)lpProc))(hdc,lpMR->rdParm[5],lpMR->rdParm[4],lpMR->rdParm[3],lpMR->rdParm[2],lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+ case 8:
+ (*((META9PROC)lpProc))(hdc,lpMR->rdParm[7],lpMR->rdParm[6],lpMR->rdParm[5],lpMR->rdParm[4],lpMR->rdParm[3],lpMR->rdParm[2],lpMR->rdParm[1],lpMR->rdParm[0]);
+ break;
+
+ default:
+ ASSERTGDI( FALSE, "No dispatch for this count of args");
+ break;
+ }
+ }
+ break;
+ }
+#ifndef WIN32
+ if (bExtraSel)
+ FreeSelector(HIWORD(lpMR));
+#endif // WIN32
+}
+
+#endif // this is going to gdi.dll
+
+/****************************** Internal Function **************************\
+* AddToHandleTable
+*
+* Adds an object to the metafile table of objects
+*
+*
+\***************************************************************************/
+
+VOID INTERNAL AddToHandleTable(LPHANDLETABLE lpHandleTable, HANDLE hObject, WORD noObjs)
+{
+ WORD i;
+
+ GdiLogFunc3( " AddToHandleTable");
+
+ /* linear search through table for first open slot */
+ for (i = 0; ((lpHandleTable->objectHandle[i] != NULL) && (i < noObjs));
+ ++i);
+
+ if (i < noObjs) /* ok index */
+ lpHandleTable->objectHandle[i] = hObject;
+ else
+ {
+ ASSERTGDI( 0, "Too many objects in table");
+ FatalExit(METAEXITCODE); /* Why can't we store the handle? */
+ }
+}
+
+
+/****************************** Internal Function **************************\
+* GetFileNumber
+*
+* Returns the DOS file number for a metafiles file
+* -1 if failure
+*
+\***************************************************************************/
+
+UINT INTERNAL GetFileNumber(LPMETAFILE lpMF)
+{
+ int fileNumber;
+
+ GdiLogFunc3( " GetFileNumber");
+
+ if (!(fileNumber = lpMF->MetaFileNumber))
+ {
+ if ((fileNumber = OpenFile((LPSTR) lpMF->MetaFileBuffer.szPathName,
+ (LPOFSTRUCT) &(lpMF->MetaFileBuffer),
+ (WORD)OF_PROMPT | OF_REOPEN | OF_READ)
+ ) != -1)
+ {
+ _llseek(fileNumber, (long)lpMF->MetaFilePosition, 0);
+
+ /* need to update MetaFileNumber for floppy files -- amitc */
+ lpMF->MetaFileNumber = fileNumber ;
+ }
+ }
+
+ return fileNumber;
+}
+
+#if 0
+/****************************** Internal Function **************************\
+* IsValidMetaFile(HANDLE hMetaData)
+*
+* Validates a metafile
+*
+* Returns TRUE iff hMetaData is a valid metafile
+*
+\***************************************************************************/
+
+BOOL GDIENTRY IsValidMetaFile(HANDLE hMetaData)
+{
+ LPMETADATA lpMetaData;
+ BOOL status = FALSE;
+
+ GdiLogFunc3( " IsValidMetaFile");
+
+ /* if this is a valid metafile we will save the version in a global variable */
+
+ if (hMetaData && (lpMetaData = (LPMETADATA) GlobalLock(hMetaData)))
+ {
+ status = (
+ (lpMetaData->dataHeader.mtType == MEMORYMETAFILE ||
+ lpMetaData->dataHeader.mtType == DISKMETAFILE) &&
+ (lpMetaData->dataHeader.mtHeaderSize == HEADERSIZE) &&
+ ((lpMetaData->dataHeader.mtVersion ==METAVERSION) ||
+ (lpMetaData->dataHeader.mtVersion ==METAVERSION100))
+ );
+ GlobalUnlock(hMetaData);
+ }
+ return status;
+}
+#endif
+
+#define INITIALBUFFERSIZE 16384
+
+/****************************** Internal Function **************************\
+*
+* AllocBuffer - Allocates a buffer as "large" as possible
+*
+\***************************************************************************/
+
+HANDLE INTERNAL AllocBuffer(LPWORD piBufferSize)
+{
+ WORD iCurBufferSize = INITIALBUFFERSIZE;
+ HANDLE hBuffer;
+
+ GdiLogFunc3( " AllocBuffer");
+
+ while (!(hBuffer = GlobalAlloc(GMEM_MOVEABLE |
+ GMEM_NODISCARD, (LONG) iCurBufferSize))
+ && iCurBufferSize)
+ iCurBufferSize >>= 1;
+
+ *piBufferSize = iCurBufferSize;
+ return (iCurBufferSize) ? hBuffer : NULL;
+}
+
+
+/****************************** Internal Function **************************\
+* CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo)
+*
+* This routine takes a memory device context and a DIB bitmap, creates a
+* compatible bitmap for the DC and fills it with the bits from the DIB (co-
+* -nverting to the device dependent format). The pointer to the DIB bits
+* start immediately after the color table in the INFO header. **
+* **
+* The routine returns the handle to the bitmap with the bits filled in if
+* everything goes well else it returns NULL. **
+\***************************************************************************/
+
+HANDLE INTERNAL CreateBitmapForDC (HDC hMemDC, LPBITMAPINFOHEADER lpDIBInfo)
+{
+ HBITMAP hBitmap ;
+ LPBYTE lpDIBits ;
+
+ GdiLogFunc3( " CreateBitmapForDC");
+
+ /* preserve monochrome if it started out as monochrome
+ ** and check for REAL Black&white monochrome as opposed
+ ** to a 2-color DIB
+ */
+ if (IsDIBBlackAndWhite(lpDIBInfo))
+ hBitmap = CreateBitmap ((WORD)lpDIBInfo->biWidth,
+ (WORD)lpDIBInfo->biHeight,
+ 1, 1, (LPBYTE) NULL);
+ else
+ /* otherwise, make a compatible bitmap */
+ hBitmap = CreateCompatibleBitmap (hMemDC,
+ (WORD)lpDIBInfo->biWidth,
+ (WORD)lpDIBInfo->biHeight);
+
+ if (!hBitmap)
+ goto CreateBitmapForDCErr ;
+
+ /* take a pointer past the header of the DIB, to the start of the color
+ table */
+ lpDIBits = (LPBYTE) lpDIBInfo + sizeof (BITMAPINFOHEADER) ;
+
+ /* take the pointer past the color table */
+ lpDIBits += GetSizeOfColorTable (lpDIBInfo) ;
+
+ /* get the bits from the DIB into the Bitmap */
+ if (!SetDIBits (hMemDC, hBitmap, 0, (WORD)lpDIBInfo->biHeight,
+ lpDIBits, (LPBITMAPINFO)lpDIBInfo, 0))
+ {
+ DeleteObject(hBitmap);
+ goto CreateBitmapForDCErr ;
+ }
+
+ /* return success */
+ return (hBitmap) ;
+
+CreateBitmapForDCErr:
+
+ /* returm failure for function */
+ return (NULL) ;
+}
+
+
+/****************************** Internal Function **************************\
+* GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo)
+*
+* Returns the number of bytes in the color table for the giving info header
+*
+\***************************************************************************/
+
+WORD INTERNAL GetSizeOfColorTable (LPBITMAPINFOHEADER lpDIBInfo)
+{
+
+ GdiLogFunc3( "GetSizeOfColorTable");
+
+ if (lpDIBInfo->biClrUsed)
+ return((WORD)lpDIBInfo->biClrUsed * (WORD)sizeof(RGBQUAD));
+ else
+ {
+ switch (lpDIBInfo->biBitCount)
+ {
+ case 1:
+ return (2 * sizeof (RGBQUAD)) ;
+ break ;
+ case 4:
+ return (16 * sizeof (RGBQUAD)) ;
+ break ;
+ case 8:
+ return (256 * sizeof (RGBQUAD)) ;
+ break ;
+ default:
+ return (0) ;
+ break ;
+ }
+ }
+}
+
+#if 0 // this is going to gdi.dll
+
+/***************************** Public Function ****************************\
+* BOOL APIENTRY DeleteMetaFile(hmf)
+*
+* Frees a metafile handle.
+*
+* Effects:
+*
+\***************************************************************************/
+
+BOOL GDIENTRY DeleteMetaFile(HMETAFILE hmf)
+{
+ GdiLogFunc("DeleteMetaFile");
+
+ GlobalFree(hmf);
+
+ return(TRUE);
+}
+
+
+/***************************** Public Function ****************************\
+* HMETAFILE APIENTRY GetMetaFile(pzFilename)
+*
+* Returns a metafile handle for a disk based metafile.
+*
+* Effects:
+*
+* History:
+* Sat 14-Oct-1989 14:21:37 -by- Paul Klingler [paulk]
+* Wrote it.
+\***************************************************************************/
+
+HMETAFILE GDIENTRY GetMetaFile(LPSTR pzFilename)
+{
+ BOOL status=FALSE;
+ UINT cBytes;
+ int file;
+ HMETAFILE hmf;
+ LPMETAFILE lpmf;
+
+ GdiLogFunc("GetMetaFile");
+
+ // Allocate the Metafile
+ if(hmf = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(DWORD)sizeof(METAFILE)))
+ {
+ lpmf = (LPMETAFILE)GlobalLock(hmf);
+
+ // Make sure the file Exists
+ if((file = OpenFile(pzFilename,
+ &(lpmf->MetaFileBuffer),
+ (WORD)OF_PROMPT | OF_EXIST)) == -1L)
+ {
+ ASSERTGDI( FALSE, "GetMetaFile: Metafile does not exist");
+ goto exitGetMetaFile;
+ }
+
+ // Open the file
+ if((file = OpenFile(pzFilename,
+ &(lpmf->MetaFileBuffer),
+ (WORD)OF_PROMPT | OF_REOPEN | OF_READWRITE)) == -1)
+ {
+ ASSERTGDI( FALSE, "GetMetaFile: Unable to open Metafile");
+ goto exitGetMetaFile;
+ }
+
+ cBytes = (UINT)_lread(file,(LPSTR)(&(lpmf->MetaFileHeader)),sizeof(METAHEADER));
+
+ // Check for an Aldus header
+ if (*((LPDWORD)&(lpmf->MetaFileHeader)) == 0x9AC6CDD7)
+ {
+
+ _llseek( file, 22, 0);
+ cBytes = (UINT)_lread(file,(LPSTR)(&(lpmf->MetaFileHeader)),sizeof(METAHEADER));
+ }
+
+ _lclose(file);
+
+ // Validate the metafile
+ if(cBytes == sizeof(METAHEADER))
+ {
+ lpmf->MetaFileHeader.mtType = DISKMETAFILE;
+ status = TRUE;
+ }
+
+ exitGetMetaFile:
+ GlobalUnlock(hmf);
+ }
+
+ if(status == FALSE)
+ {
+ GlobalFree(hmf);
+ hmf = NULL;
+ }
+
+ return(hmf);
+}
+#endif // this is going to gdi.dll
+
+#ifdef WIN32
+#undef GetViewportExt
+DWORD GetViewportExt32(HDC hdc)
+{
+ SIZE sz;
+ GetViewportExt( hdc, &sz );
+ return(MAKELONG(LOWORD(sz.cx),LOWORD(sz.cy)));
+}
+
+#undef GetWindowExt
+DWORD GetWindowExt32(HDC hdc)
+{
+ SIZE sz;
+ GetWindowExt( hdc, &sz );
+ return(MAKELONG(LOWORD(sz.cx),LOWORD(sz.cy)));
+}
+
+#undef SetViewportExt
+DWORD SetViewportExt32(HDC hdc, UINT x, UINT y)
+{
+ SIZE sz;
+ SetViewportExt( hdc, x, y, &sz );
+ return(MAKELONG(LOWORD(sz.cx),LOWORD(sz.cy)));
+}
+
+#undef SetWindowExt
+DWORD SetWindowExt32(HDC hdc, UINT x, UINT y)
+{
+ SIZE sz;
+ SetWindowExt( hdc, x, y, &sz );
+ return(MAKELONG(LOWORD(sz.cx),LOWORD(sz.cy)));
+}
+
+/* Convert WORD arrays into DWORDs */
+LPINT ConvertInts( signed short * pWord, UINT cWords )
+{
+ UINT ii;
+ LPINT pInt;
+
+ pInt = (LPINT)LocalAlloc( LMEM_FIXED, cWords * sizeof(UINT));
+
+ for( ii=0; ii<cWords; ii++)
+ {
+ pInt[ii] = (long)(signed)pWord[ii];
+ }
+
+ return(pInt);
+}
+
+#endif // WIN32
diff --git a/private/mvdm/wow16/gdi/metacons.inc b/private/mvdm/wow16/gdi/metacons.inc
new file mode 100644
index 000000000..e3071a538
--- /dev/null
+++ b/private/mvdm/wow16/gdi/metacons.inc
@@ -0,0 +1,90 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; MetaCons.inc
+; Windows.h Metafile Constants
+;
+; History:
+;
+; Created 28-May-1991 by John Colleran (johnc)
+; Derived from Windows.h (using h2inc was not successful over the whole file)
+;--
+
+
+METASETBKCOLOR EQU 0201H
+METASETBKMODE EQU 0102H
+METASETMAPMODE EQU 0103H
+METASETROP2 EQU 0104H
+METASETRELABS EQU 0105H
+METASETPOLYFILLMODE EQU 0106H
+METASETSTRETCHBLTMODE EQU 0107H
+METASETTEXTCHAREXTRA EQU 0108H
+METASETTEXTCOLOR EQU 0209H
+METASETTEXTJUSTIFICATION EQU 020aH
+MFCOMMENT EQU 15
+METASETWINDOWORG EQU 020bH
+METASETWINDOWEXT EQU 020cH
+METASETVIEWPORTORG EQU 020dH
+METASETVIEWPORTEXT EQU 020eH
+METAOFFSETWINDOWORG EQU 020fH
+METASCALEWINDOWEXT EQU 0400H
+METAOFFSETVIEWPORTORG EQU 0211H
+METASCALEVIEWPORTEXT EQU 0412H
+METALINETO EQU 0213H
+METAMOVETO EQU 0214H
+METAEXCLUDECLIPRECT EQU 0415H
+METAINTERSECTCLIPRECT EQU 0416H
+METAARC EQU 0817H
+METAELLIPSE EQU 0418H
+METAFLOODFILL EQU 0419H
+METAPIE EQU 081aH
+METARECTANGLE EQU 041bH
+METAROUNDRECT EQU 061cH
+METAPATBLT EQU 061dH
+METASAVEDC EQU 001eH
+METASETPIXEL EQU 041fH
+METAOFFSETCLIPRGN EQU 0220H
+METATEXTOUT EQU 0521H
+METABITBLT EQU 0922H
+METASTRETCHBLT EQU 0b23H
+METAPOLYGON EQU 0324H
+METAPOLYLINE EQU 0325H
+METAESCAPE EQU 0626H
+METARESTOREDC EQU 0127H
+METAFILLREGION EQU 0228H
+METAFRAMEREGION EQU 0529H
+METAINVERTREGION EQU 012aH
+METAPAINTREGION EQU 012bH
+METASELECTCLIPREGION EQU 012cH
+METASELECTOBJECT EQU 012dH
+METASETTEXTALIGN EQU 012eH
+METADRAWTEXT EQU 062fH
+METACHORD EQU 0830H
+METASETMAPPERFLAGS EQU 0231H
+METAEXTTEXTOUT EQU 0a32H
+METASETDIBTODEV EQU 0d33H
+METASELECTPALETTE EQU 0234H
+METAREALIZEPALETTE EQU 0035H
+METAANIMATEPALETTE EQU 0436H
+METASETPALENTRIES EQU 0037H
+METAPOLYPOLYGON EQU 0538H
+METARESIZEPALETTE EQU 0139H
+METADIBBITBLT EQU 0940H
+METADIBSTRETCHBLT EQU 0b41H
+METADIBCREATEPATTERNBRUSH EQU 0142H
+METASTRETCHDIB EQU 0f43H
+METAPMMETAFILE EQU 0ff44H
+METAEXTFLOODFILL EQU 0548H
+METADELETEOBJECT EQU 01f0H
+METACREATEPALETTE EQU 00f7H
+METACREATEBRUSH EQU 00f8H
+METACREATEPATTERNBRUSH EQU 01f9H
+METACREATEPENINDIRECT EQU 02faH
+METACREATEFONTINDIRECT EQU 02fbH
+METACREATEBRUSHINDIRECT EQU 02fcH
+METACREATEBITMAPINDIRECT EQU 02fdH
+METACREATEBITMAP EQU 06feH
+METACREATEREGION EQU 06ffH
diff --git a/private/mvdm/wow16/gdi/metarec.c b/private/mvdm/wow16/gdi/metarec.c
new file mode 100644
index 000000000..60708c9cc
--- /dev/null
+++ b/private/mvdm/wow16/gdi/metarec.c
@@ -0,0 +1,2325 @@
+/****************************** Module Header ******************************\
+*
+* Module Name: MetaRec.c
+*
+*
+* DESCRIPTIVE NAME: Metafile Recorder
+*
+* FUNCTION: Records GDI functions in memory and disk metafiles.
+*
+* PUBLIC ENTRY POINTS:
+* CloseMetaFile
+* CopyMetaFile
+* CreateMetaFile
+* GetMetaFileBits
+* SetMetaFileBits
+* PRIVATE ENTRY POINTS:
+* RecordParms
+* AttemptWrite
+* MarkMetaFile
+* RecordOther
+* RecordObject
+* ProbeSize
+* AddToTable
+*
+* History:
+* 02-Jul-1991 -by- John Colleran [johnc]
+* Combined From Win 3.1 and WLO 1.0 sources
+\***************************************************************************/
+
+#include <windows.h>
+#include <drivinit.h>
+#include "gdi16.h"
+
+#define SP_OUTOFDISK (-4) /* simply no disk to spool */
+
+extern HANDLE hStaticBitmap ; // MetaSup.c
+extern METACACHE MetaCache; // Meta.c
+extern HDC hScreenDC;
+
+
+WORD INTERNAL AddToTable(HANDLE hMF, HANDLE hObject, LPWORD position, BOOL bRealAdd);
+HANDLE INTERNAL AllocateSpaceForDIB (LPBITMAP, LPBYTE, LPWORD, LPDWORD);
+BOOL INTERNAL AttemptWrite(HANDLE, WORD, DWORD, BYTE huge *);
+BOOL INTERNAL CopyFile(LPSTR lpSFilename, LPSTR lpDFilename);
+LPWORD INTERNAL InitializeDIBHeader (LPBITMAPINFOHEADER, LPBITMAP, BYTE, WORD);
+VOID INTERNAL MarkMetaFile(HANDLE hMF);
+HANDLE INTERNAL ProbeSize(NPMETARECORDER pMF, DWORD dwLength);
+
+HANDLE hFirstMetaFile = 0; // Linked list of all open MetaFiles
+
+
+/****************************************************************************
+* *
+* RecordParms *
+* *
+* Parameters: 1.hMF handle to a metafile header. *
+* 2.The magic number of the function being recorded. *
+* 3.The number of parmmeter of the function (size of lpParm *
+* in words) *
+* 4.A long pointer to parameters stored in reverse order *
+* *
+****************************************************************************/
+
+BOOL INTERNAL RecordParms(HANDLE hdc, WORD magic, DWORD count, LPWORD lpParm)
+{
+ BOOL status = FALSE;
+ DWORD i;
+ DWORD dwLength;
+ HPWORD hpwSpace;
+ HPWORD hpHugeParm;
+ LPWORD lpCache;
+ HANDLE hSpace;
+ WORD fileNumber;
+ METARECORD recPair;
+ HANDLE hMF;
+
+ NPMETARECORDER npMF;
+
+ dprintf( 6," RecordParms 0x%X", magic);
+
+ hpHugeParm = (HPWORD)lpParm;
+
+ // Validate the metafile handle
+
+ if(npMF = (NPMETARECORDER)LocalLock(HANDLEFROMMETADC(hdc)))
+ {
+ if(npMF->metaDCHeader.ident != ID_METADC )
+ {
+ LocalUnlock(HANDLEFROMMETADC(hdc));
+ ASSERTGDI( FALSE, "RecordParms: invalid metafile ID");
+ return(FALSE);
+ }
+ }
+ else
+ {
+ ASSERTGDI( FALSE, "RecordParms: invalid metafile");
+ return(FALSE);
+ }
+
+ hMF = HANDLEFROMMETADC(hdc);
+
+ if (!(npMF->recFlags & METAFILEFAILURE))
+ {
+ if (npMF->recordHeader.mtType == MEMORYMETAFILE)
+ {
+ if (hSpace = ProbeSize(npMF, dwLength = count + RECHDRSIZE / 2))
+ {
+ hpwSpace = (HPWORD) GlobalLock(hSpace);
+
+ hpwSpace = (HPWORD) ((LPMETADATA) hpwSpace)->metaDataStuff;
+ hpwSpace = hpwSpace + npMF->recFilePosition;
+
+ // write length out at a pair of words because we
+ // are not DWORD aligned, so we can't use "DWORD huge *"
+
+ *hpwSpace++ = LOWORD(dwLength);
+ *hpwSpace++ = HIWORD(dwLength);
+
+ *hpwSpace++ = magic;
+ for (i = 0; i < count; ++i)
+ *hpwSpace++ = *hpHugeParm++;
+ npMF->recFilePosition += dwLength;
+ GlobalUnlock(hSpace);
+ }
+ else
+ {
+ goto Exit_RecordParms;
+ }
+ }
+ else if (npMF->recordHeader.mtType == DISKMETAFILE)
+ {
+ dwLength = count + RECHDRSIZE / 2;
+ if (npMF->recFileBuffer.fFixedDisk)
+ {
+ fileNumber = npMF->recFileNumber;
+ }
+ else
+ {
+ if ((fileNumber =
+ OpenFile((LPSTR)npMF->recFileBuffer.szPathName,
+ (LPOFSTRUCT)&(npMF->recFileBuffer),
+ OF_PROMPT|OF_REOPEN|READ_WRITE))
+ == -1)
+ {
+ goto Exit_RecordParms;
+ }
+ _llseek(fileNumber, (LONG) 0, 2);
+ }
+
+ if (hMF == MetaCache.hMF)
+ {
+ lpCache = (LPWORD) GlobalLock(MetaCache.hCache);
+ if (dwLength + MetaCache.wCachePos >= MetaCache.wCacheSize)
+ {
+ if (!AttemptWrite(hdc,
+ fileNumber,
+ (DWORD)(MetaCache.wCachePos << 1),
+ (BYTE huge *) lpCache))
+ {
+ MarkMetaFile(hMF);
+ GlobalUnlock(MetaCache.hCache);
+ goto Exit_RecordParms;
+ }
+ MetaCache.wCachePos = 0;
+
+ if (dwLength >= MetaCache.wCacheSize)
+ {
+ GlobalUnlock(MetaCache.hCache);
+ goto NOCACHE;
+ }
+ }
+
+ lpCache += MetaCache.wCachePos;
+
+ *((LPDWORD) lpCache)++ = dwLength;
+ *lpCache++ = magic;
+
+ for (i = 0; i < count; ++i)
+ *lpCache++ = *lpParm++;
+
+ MetaCache.wCachePos += dwLength;
+ GlobalUnlock(MetaCache.hCache);
+ }
+ else
+ {
+NOCACHE:
+ recPair.rdSize = dwLength;
+ recPair.rdFunction = magic;
+ if (!AttemptWrite(hdc,
+ fileNumber,
+ (DWORD)RECHDRSIZE,
+ (BYTE huge *) &recPair))
+ {
+ goto Exit_RecordParms;
+ }
+ if (count)
+ {
+ if (!AttemptWrite(hdc,
+ fileNumber,
+ (DWORD)(count * sizeof(WORD)),
+ (BYTE huge *) lpParm))
+ {
+ goto Exit_RecordParms;
+ }
+ }
+ }
+ if (!(npMF->recFileBuffer.fFixedDisk))
+ _lclose(fileNumber);
+ }
+ }
+
+ if (npMF->recordHeader.mtMaxRecord < dwLength)
+ npMF->recordHeader.mtMaxRecord = dwLength;
+
+ npMF->recordHeader.mtSize += dwLength;
+ status = TRUE;
+
+Exit_RecordParms:
+ if (status == FALSE)
+ {
+ ASSERTGDI( FALSE, "RecordParms: failing");
+ MarkMetaFile(hMF);
+ }
+
+ LocalUnlock(HANDLEFROMMETADC(hdc));
+
+ return(status);
+
+} /* RecordParms */
+
+
+/***************************** Internal Function ***************************\
+* AttempWrite
+*
+* Tries to write data to a metafile disk file
+*
+* Returns TRUE iff the write was sucessful
+*
+*
+\***************************************************************************/
+
+BOOL INTERNAL AttemptWrite(hdc, fileNumber, dwBytes, lpData)
+HANDLE hdc;
+DWORD dwBytes;
+WORD fileNumber;
+HPBYTE lpData;
+{
+ WORD cShort;
+ WORD cbWritten;
+ WORD cBytes;
+
+
+ GdiLogFunc2( " AttemptWrite" );
+
+ while(dwBytes > 0)
+ {
+ cBytes = (dwBytes > MAXFILECHUNK ? MAXFILECHUNK : (WORD) dwBytes);
+
+ if ((cbWritten = _lwrite(fileNumber, (LPSTR)lpData, cBytes)) != cBytes)
+ {
+ cShort = cBytes - cbWritten;
+ lpData += cbWritten;
+
+ ASSERTGDI( 0, "Disk full?");
+// !!!!! handle disk full -- diskAvailable
+
+ if( !IsMetaDC(hdc) )
+ return(FALSE);
+ }
+
+ /* how many bytes are left? */
+ dwBytes -= cBytes;
+ lpData += cbWritten;
+ }
+ return(TRUE);
+}
+
+
+/***************************** Internal Function ***************************\
+* VOID INTERNAL MarkMetaFile(hmr)
+*
+* Marks a metafile as failed
+*
+* Effects:
+* Frees the metafile resources
+*
+\***************************************************************************/
+
+VOID INTERNAL MarkMetaFile(HANDLE hMF)
+{
+ NPMETARECORDER npMF;
+
+ GdiLogFunc2( " MarkMetaFile" );
+
+ npMF = (NPMETARECORDER) NPFROMMETADC(hMF);
+ npMF->recFlags |= METAFILEFAILURE;
+
+ if (npMF->recordHeader.mtType == MEMORYMETAFILE)
+ {
+ if (npMF->hMetaData)
+ GlobalFree(npMF->hMetaData);
+ }
+ else if (npMF->recordHeader.mtType == DISKMETAFILE)
+ {
+ if (npMF->recFileBuffer.fFixedDisk)
+ _lclose(npMF->recFileNumber);
+
+ OpenFile((LPSTR) npMF->recFileBuffer.szPathName,
+ (LPOFSTRUCT) &(npMF->recFileBuffer),
+ OF_PROMPT|OF_DELETE);
+ }
+}
+
+
+/***************************** Internal Function **************************\
+* MakeLogPalette
+*
+* Records either CreatePalette or SetPaletteEntries
+*
+* Returns
+*
+*
+\***************************************************************************/
+
+WORD NEAR MakeLogPalette(HANDLE hMF, HANDLE hPal, WORD magic)
+{
+ WORD cPalEntries;
+ WORD status = 0xFFFF;
+ HANDLE hSpace;
+ WORD cbPalette;
+ LPLOGPALETTE lpPalette;
+
+ GdiLogFunc2( " MakeLogPalette" );
+
+ cPalEntries = GetObject( hPal, 0, NULL );
+
+ /* alloc memory and get the palette entries */
+ if (hSpace = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,
+ cbPalette = sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*(cPalEntries)))
+ {
+ lpPalette = (LPLOGPALETTE)GlobalLock(hSpace);
+
+ lpPalette->palNumEntries = cPalEntries;
+
+ GetPaletteEntries( hPal, 0, cPalEntries, lpPalette->palPalEntry);
+
+ if (magic == (META_CREATEPALETTE & 255))
+ {
+ lpPalette->palVersion = 0x300;
+ magic = META_CREATEPALETTE;
+ }
+ else if (magic == (META_SETPALENTRIES & 255))
+ {
+ lpPalette->palVersion = 0; /* really "starting index" */
+ magic = META_SETPALENTRIES;
+ }
+
+ status = RecordParms(hMF, magic, (DWORD)cbPalette >> 1, (LPWORD)lpPalette);
+
+ GlobalUnlock(hSpace);
+ GlobalFree(hSpace);
+ }
+
+ return(status);
+}
+
+
+/****************************************************************************
+* *
+* Routine: RecordOther, records parameters for certain "hard functions" *
+* *
+* Parameters: 1. hMF handle to a metafile header. *
+* 2. The magic number of the function being recorded. *
+* 3. The number of parmmeter of the function (size of lpParm *
+* in words) *
+* 4. A long pointer to parameters stored in reverse order *
+* *
+****************************************************************************/
+
+BOOL INTERNAL RecordOther(HDC hdc, WORD magic, WORD count, LPWORD lpParm)
+{
+ NPMETARECORDER npMF;
+ WORD buffer[5];
+ WORD i;
+ WORD status = FALSE;
+ WORD iChar;
+ WORD position;
+ HANDLE hSpace = NULL;
+ WORD iWords;
+ LPWORD lpSpace;
+ LPWORD lpTemp;
+ HANDLE hMF;
+
+ dprintf( 6," RecordOther 0x%X", magic);
+
+ if ((hMF = GetPMetaFile(hdc)) != -1 )
+ {
+ // Handle functions with no DC.
+ if( hMF == 0 )
+ {
+ HANDLE hmfSearch = hFirstMetaFile;
+
+ // Play these records into all active metafiles
+ while( hmfSearch )
+ {
+ npMF = (NPMETARECORDER)LocalLock( hmfSearch );
+ if (!(npMF->recFlags & METAFILEFAILURE))
+ {
+ switch (magic & 255)
+ {
+ case (META_ANIMATEPALETTE & 255):
+ {
+ HANDLE hSpace;
+ LPSTR lpSpace;
+ LPSTR lpHolder;
+ WORD SpaceSize;
+ LPPALETTEENTRY lpColors;
+
+ SpaceSize = 4 + (lpParm[2] * sizeof(PALETTEENTRY));
+ if ((hSpace = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(LONG) SpaceSize)))
+ {
+ lpHolder = lpSpace = GlobalLock(hSpace);
+
+ *((LPWORD)lpSpace)++ = lpParm[3];
+ *((LPWORD)lpSpace)++ = lpParm[2];
+ lpColors = (LPPALETTEENTRY)lpParm;
+
+ for (i=0; i<lpParm[2]; i++)
+ *((LPPALETTEENTRY)lpSpace)++ = *lpColors++;
+
+ status = RecordParms(HMFFROMNPMF(npMF), magic, (DWORD)(SpaceSize >> 1),
+ (LPWORD) lpHolder);
+
+ GlobalUnlock(hSpace);
+ GlobalFree(hSpace);
+ }
+ }
+ break;
+
+ case (META_RESIZEPALETTE & 255):
+ {
+ status = RecordParms(HMFFROMNPMF(npMF), magic, (DWORD)1, (LPWORD)&lpParm[0]);
+ }
+ break;
+
+ case (META_DELETEOBJECT & 255):
+ if (AddToTable(HMFFROMNPMF(npMF), *lpParm, (LPWORD) &position, FALSE) == 1)
+ {
+ status = RecordParms(HMFFROMNPMF(npMF), META_DELETEOBJECT, 1UL, &position);
+ }
+ break;
+ } /* switch */
+ }
+
+ LocalUnlock( hmfSearch );
+ hmfSearch = npMF->metaDCHeader.nextinchain;
+ } /* while */
+ }
+
+
+ npMF = (NPMETARECORDER) NPFROMMETADC(hMF);
+ if (!(npMF->recFlags & METAFILEFAILURE))
+ {
+
+ switch (magic & 255)
+ {
+
+
+
+ case (META_FRAMEREGION & 255):
+ case (META_FILLREGION & 255):
+ case (META_INVERTREGION & 255):
+ case (META_PAINTREGION & 255):
+ // Each region function has at least a region to record
+ buffer[0] = RecordObject(hMF, magic, count, (LPWORD)&(lpParm[count-1]));
+
+ /* Is there a brush too; FillRgn */
+ if(count > 1 )
+ buffer[1] = RecordObject(hMF, magic, count, (LPWORD)&(lpParm[count-2]));
+
+ /* Are there are extents too; FrameRegion */
+ if(count > 2)
+ {
+ buffer[2] = lpParm[0];
+ buffer[3] = lpParm[1];
+ }
+
+ status = RecordParms(hMF, magic, (DWORD)count, (LPWORD)buffer);
+ break;
+
+ case (META_FLOODFILL & 255):
+ buffer[0] = 0; // Regular FloodFill
+ buffer[1] = lpParm[0];
+ buffer[2] = lpParm[1];
+ buffer[3] = lpParm[2];
+ buffer[4] = lpParm[3];
+ status = RecordParms(hMF, META_EXTFLOODFILL, (DWORD)count+1, (LPWORD)buffer);
+ break;
+
+ case (META_ESCAPE & 255):
+ /* record the function number */
+ {
+ WORD iBytes;
+ WORD count;
+ char * pSpace;
+ char * pTemp;
+ LPSTR lpInData;
+ LPEXTTEXTDATA lpTextData;
+ WORD function;
+
+ *((WORD FAR * FAR *) lpParm)++;
+ lpInData = (LPSTR) *((WORD FAR * FAR *) lpParm)++;
+ lpTextData = (LPEXTTEXTDATA) lpInData;
+ count = iBytes = *lpParm++;
+
+ function = *lpParm++;
+#ifdef OLDEXTTEXTOUT
+ if (function == EXTTEXTOUT)
+ {
+ iBytes = (lpTextData->cch * (sizeof(WORD)+sizeof(char)))
+ + 1 + sizeof(EXTTEXTDATA);
+ }
+#endif
+
+ if (!(pTemp = pSpace =
+ (char *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, (iBytes + (sizeof(WORD) * 2)))))
+ return(FALSE);
+
+ *((WORD *) pTemp)++ = function;
+ *((WORD *) pTemp)++ = count;
+
+#ifdef OLDEXTTEXTOUT
+ if (function != EXTTEXTOUT) {
+#endif
+ for (i = 0; i < iBytes; ++i)
+ *pTemp++ = *lpInData++;
+#ifdef OLDEXTTEXTOUT
+ } else {
+ *((WORD *) pTemp)++ = lpTextData->xPos;
+ *((WORD *) pTemp)++ = lpTextData->yPos;
+ *((WORD *) pTemp)++ = lpTextData->cch;
+ *((RECT *) pTemp)++ = lpTextData->rcClip;
+ for (i = 0; i < ((lpTextData->cch + 1) & ~1) ; ++i)
+ *pTemp++ = lpTextData->lpString[i];
+
+ for (i = 0; i < lpTextData->cch; ++i)
+ *((WORD *) pTemp)++ = lpTextData->lpWidths[i];
+ }
+#endif
+
+ /* info block + 2 words for function and count */
+ status = RecordParms(hMF, magic,
+ (DWORD)((iBytes + 1) >> 1) + 2,
+ (LPWORD) pSpace);
+
+ LocalFree((HANDLE) pSpace);
+ }
+ break;
+
+ case (META_POLYLINE & 255):
+ case (META_POLYGON & 255):
+ {
+ WORD iPoints;
+ WORD *pSpace;
+ WORD *pTemp;
+ LPWORD lpPoints;
+
+ iPoints = *lpParm++;
+
+ iWords = iPoints * 2;
+ if (!(pTemp = pSpace = (WORD *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
+ (iPoints * sizeof(POINT)) + sizeof(WORD))))
+ return(FALSE);
+
+ lpPoints = *((WORD FAR * FAR *) lpParm)++;
+ *pTemp++ = iPoints;
+
+ for (i = 0; i < iWords; ++i)
+ *pTemp++ = *lpPoints++;
+ status = RecordParms(hMF, magic, (DWORD)iWords + 1, (LPWORD) pSpace);
+ LocalFree((HANDLE) pSpace);
+ }
+ break;
+
+ case (META_POLYPOLYGON & 255):
+ {
+ WORD iPoints;
+ WORD iPolys;
+ WORD *pSpace;
+ WORD *pTemp;
+ LPWORD lpPoints;
+ LPWORD lpNumPoints;
+
+ /* get the number of polygons */
+ iPolys = *lpParm++;
+
+ /* get the pointers to Points and NumPoints */
+ lpNumPoints = *((WORD FAR * FAR *) lpParm)++;
+ lpPoints = *((WORD FAR * FAR *) lpParm)++;
+
+ /* count the total number of points */
+ iPoints = 0 ;
+ for (i=0; i<iPolys; i++)
+ iPoints += *(lpNumPoints + i) ;
+
+ /* allocate space needed for Points, NumPoints and Count */
+ if (!(pTemp = pSpace = (WORD *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
+ (iPoints * sizeof(POINT)) +
+ iPolys * sizeof(WORD) +
+ sizeof(WORD))))
+ return(FALSE);
+
+ /* save the Count parameter */
+ *pTemp++ = iPolys;
+
+ /* now copy the NumPoints array*/
+ for (i = 0; i < iPolys; ++i)
+ *pTemp++ = *lpNumPoints++;
+
+ /* finally copy the number of words in the Points array, remember
+ the number of words there are double the number of points */
+ iWords = iPoints * 2;
+ for (i = 0; i < iWords; ++i)
+ *pTemp++ = *lpPoints++;
+
+ /* total number of words in the parameter list =
+ iPoints*2(for Points) + iPolys(for NumPoints) + 1(for Count)
+ and iWords has already iPoints*2 */
+
+ iWords += iPolys + 1 ;
+
+ /* finally record all the parameters */
+ status = RecordParms(hMF, magic, (DWORD)iWords , (LPWORD) pSpace);
+ LocalFree((HANDLE) pSpace);
+ }
+ break;
+
+#ifdef DEADCODE
+
+ case (META_DRAWTEXT & 255):
+ {
+ WORD wFormat;
+ WORD count;
+ WORD *pSpace;
+ WORD *pTemp;
+ LPBYTE lpString;
+ LPBYTE lpS;
+ LPWORD lpRect;
+
+ wFormat = *lpParm++;
+ lpRect = *((WORD FAR * FAR *) lpParm)++;
+ count = *lpParm++;
+ lpString = (LPBYTE) *((WORD FAR * FAR *) lpParm)++;
+
+ if(count == -1){ /* another null terminated string */
+ lpS = lpString;
+ for (count = 0 ; *lpS++ != 0; count++) ;
+ }
+
+ if (!(pTemp = pSpace = (WORD *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
+ count + 6 * sizeof(WORD))))
+ return(FALSE);
+
+ *pTemp++ = wFormat;
+ *pTemp++ = count;
+ for (i = 0; i < 4; ++i)
+ *pTemp++ = *lpRect++;
+
+ for (i = 0; i < count; ++i)
+ *((BYTE *) pTemp)++ = *lpString++;
+
+ count = (count + 1) >> 1;
+ status = RecordParms(hMF, magic, (DWORD)count + 6, (LPWORD) pSpace);
+ LocalFree((HANDLE) pSpace);
+ }
+ break;
+#endif
+
+ case (META_EXTTEXTOUT & 255):
+ {
+ WORD iBytes;
+ WORD count;
+ WORD options;
+ WORD *pTemp;
+ WORD *pSpace;
+ LPINT lpdx;
+ LPWORD lpString;
+ LPRECT lprt;
+ WORD ii;
+
+ lpdx = *((WORD FAR * FAR *) lpParm)++;
+ count = iBytes = *lpParm++;
+
+ lpString = (LPWORD) *((LPSTR FAR *) lpParm)++;
+ lprt = (LPRECT) *((LPSTR FAR *) lpParm)++;
+ options = *lpParm++;
+
+ /* how much space do we need?
+ ** room for the char string
+ ** room for the 4 words that are the fixed parms
+ ** if there is a dx array, we need room for it
+ ** if the rectangle is being used, we need room for it
+ ** and we need extra byte for eventual word roundoff
+ */
+ iBytes = (count * (((lpdx) ? sizeof(WORD) : 0)
+ + sizeof(BYTE)))
+ + ((options & (ETO_OPAQUE | ETO_CLIPPED))
+ ? sizeof(RECT) : 0)
+ + 1 + (sizeof(WORD) * 4);
+
+ if (!(pTemp = pSpace = (WORD *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,iBytes)))
+ return(FALSE);
+
+ /* record YPos and XPos */
+
+ *pTemp++ = *lpParm++;
+ *pTemp++ = *lpParm++;
+ *pTemp++ = count;
+ *pTemp++ = options;
+
+ /* if there's an opaquing rect copy it */
+ if (options & (ETO_OPAQUE|ETO_CLIPPED))
+ {
+ *pTemp++ = lprt->left;
+ *pTemp++ = lprt->top;
+ *pTemp++ = lprt->right;
+ *pTemp++ = lprt->bottom;
+ }
+
+ /* need to copy bytes because it may not be even */
+ for (ii = 0; ii < count; ++ii)
+ *((BYTE *)pTemp)++ = *((LPBYTE)lpString)++;
+ if (count & 1) /* word align */
+ *((BYTE *)pTemp)++;
+
+ if (lpdx)
+ for (ii = 0; ii < count; ++ii)
+ *pTemp++ = *lpdx++;
+
+ status = RecordParms(hMF, magic, (DWORD)iBytes >> 1,
+ (LPWORD) pSpace);
+
+ LocalFree((HANDLE)pSpace);
+
+ }
+ break;
+
+ case (META_TEXTOUT & 255):
+ {
+ LPWORD lpString;
+ WORD *pSpace;
+ WORD *pTemp;
+ POINT pt;
+
+ iChar = *lpParm++;
+ if (!(pTemp = pSpace = (WORD *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,
+ iChar + (sizeof(WORD) * 4))))
+ return(FALSE);
+
+ *pTemp++ = iChar;
+ lpString = (LPWORD) *((LPSTR FAR *) lpParm)++;
+
+ for (i = 0; i < iChar; ++i)
+ *((BYTE *)pTemp)++ = *((LPBYTE)lpString)++;
+ if (iChar & 1) /* word align */
+ *((BYTE *)pTemp)++;
+
+ pt.y = *pTemp++ = *lpParm++;
+ pt.x = *pTemp++ = *lpParm++;
+
+ status = RecordParms(hMF, magic, (DWORD)((iChar + 1) >> 1) + 3,
+ (LPWORD) pSpace);
+
+ LocalFree((HANDLE) pSpace);
+ }
+ break;
+
+ case (META_DIBBITBLT & 255):
+ case (META_DIBSTRETCHBLT & 255):
+ {
+ LPBITMAPINFOHEADER lpDIBInfo ;
+ DWORD iWords;
+ DWORD iBits;
+ WORD wColorTableSize ;
+ BOOL bSame=FALSE;
+ HANDLE hSpace=FALSE;
+ HBITMAP hBitmap;
+ HDC hSDC;
+ BYTE bBitsPerPel ;
+ BITMAP logBitmap;
+
+ iWords = (WORD)count;
+ hSDC = lpParm[iWords - 5];
+
+ if (hMF == hSDC || hSDC == NULL)
+ bSame = TRUE;
+ else
+ {
+ WORD iParms;
+
+ if( GetObjectType( (HANDLE)hSDC ) == OBJ_MEMDC)
+ {
+ HBITMAP hBitmap;
+
+ hBitmap = GetCurrentObject( hSDC, OBJ_BITMAP );
+
+ GetObject( hBitmap, sizeof(BITMAP), (LPSTR)&logBitmap);
+
+ /* allocate space for the DIB header and bits */
+ if (!(hSpace = AllocateSpaceForDIB (&logBitmap,
+ &bBitsPerPel,
+ &wColorTableSize,
+ &iBits )))
+ return (FALSE) ;
+ lpTemp = lpSpace = (LPWORD) GlobalLock(hSpace);
+
+/*--------------------------------------------------------------------------**
+** copy the parameters from the end of the list which is at the top of the **
+** stack till the hSrcDC parameter,skip the hSrcDC parameter and copy the **
+** rest of the parameters. ** **
+**--------------------------------------------------------------------------*/
+
+ iParms = (magic == META_DIBBITBLT) ? 4 : 6;
+
+ for (i = 0; i < iParms; ++i)
+ *lpSpace++ = *lpParm++;
+
+ /* skip the hSrcDC parameter and reduce parameter count */
+ *lpParm++;
+ iWords--;
+
+ /* copy the rest of the parameters in the call */
+ for ( ; i < (WORD)iWords; ++i)
+ *lpSpace++ = *lpParm++;
+
+
+ /* save the start of the bitmap info header field */
+ lpDIBInfo = (LPBITMAPINFOHEADER) lpSpace ;
+
+ /* preapare the header and return lpSpace pointing to area
+ for thr bits */
+ lpSpace = InitializeDIBHeader (lpDIBInfo,
+ &logBitmap, bBitsPerPel,wColorTableSize) ;
+
+ /* lpSpace now points to the area to hold DIB bits */
+
+ }
+ else
+ return(FALSE);
+ }
+
+ if (bSame)
+ status = RecordParms(hMF, magic, (DWORD)count, lpParm);
+ else
+ {
+ /* get the bits into the DIB */
+ hBitmap = SelectObject (hSDC, hStaticBitmap) ;
+ GetDIBits(hSDC, hBitmap, 0, logBitmap.bmHeight,
+ (LPBYTE) lpSpace, (LPBITMAPINFO)lpDIBInfo, 0 ) ;
+ SelectObject (hSDC,hBitmap) ;
+
+ /* finally record the parameters into the file*/
+ status = RecordParms(hMF, magic, (DWORD)(iWords
+ + (iBits >> 1)) , (LPWORD) lpTemp ) ;
+
+ if (hSpace)
+ {
+ GlobalUnlock(hSpace);
+ GlobalFree(hSpace);
+ }
+ }
+ }
+ break;
+
+ case (META_SETDIBTODEV & 255):
+ {
+ HANDLE hSpace;
+ LPWORD lpSpace;
+ LPWORD lpHolder;
+ DWORD SpaceSize;
+ WORD ColorSize;
+ DWORD BitmapSize;
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ HPWORD lpBits;
+ WORD wUsage;
+ LPBITMAPCOREHEADER lpBitmapCore; /* used for old DIBs */
+ DWORD dwi;
+ HPWORD lpHugeSpace;
+
+ wUsage = *lpParm++;
+
+ lpBitmapInfo = (LPBITMAPINFOHEADER) *((WORD FAR * FAR *) lpParm)++;
+ lpBits = (WORD huge *) *((WORD FAR * FAR *) lpParm)++;
+
+ /* old style DIB header */
+ if (lpBitmapInfo->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ lpBitmapCore = (LPBITMAPCOREHEADER)lpBitmapInfo;
+
+ if (lpBitmapCore->bcBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (1 << lpBitmapCore->bcBitCount) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ /* bits per scanline */
+ BitmapSize = lpBitmapCore->bcWidth *
+ lpBitmapCore->bcBitCount;
+
+ /* bytes per scanline (rounded to DWORD boundary) */
+ BitmapSize = ((BitmapSize + 31) & (~31)) >> 3;
+ /* bytes for the NumScans of the bitmap */
+ BitmapSize *= lpParm[0];
+ }
+ /* new style DIB header */
+ else
+ {
+ if (lpBitmapInfo->biClrUsed)
+ {
+ ColorSize = ((WORD)lpBitmapInfo->biClrUsed) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+ }
+ else if (lpBitmapInfo->biBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (1 << lpBitmapInfo->biBitCount) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ /* if biSizeImage is already there and we are
+ ** getting a full image, there is no more work
+ ** to be done.
+ ** ****** what about partial RLEs? *****
+ */
+ if (!(BitmapSize = lpBitmapInfo->biSizeImage) ||
+ (lpBitmapInfo->biHeight != lpParm[0]))
+ {
+ /* bits per scanline */
+ BitmapSize = lpBitmapInfo->biWidth *
+ lpBitmapInfo->biBitCount;
+ /* bytes per scanline (rounded to DWORD boundary) */
+ BitmapSize = ((BitmapSize + 31) & (~31)) >> 3;
+ /* bytes for the NumScans of the bitmap */
+ BitmapSize *= lpParm[0];
+ }
+ }
+
+ SpaceSize = (DWORD)sizeof(BITMAPINFOHEADER) + (DWORD)ColorSize +
+ (DWORD)BitmapSize +
+ (DWORD)(9*sizeof(WORD));
+
+ if ((hSpace = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,SpaceSize)))
+ {
+ lpHolder = lpSpace = (LPWORD) GlobalLock(hSpace);
+
+ /* copy over call parameters */
+ *lpSpace++ = wUsage;
+ for (i=0; i<8; i++)
+ *lpSpace++ = *lpParm++;
+
+ /* copy the bitmap header */
+ if (lpBitmapInfo->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ LPBITMAPINFOHEADER lpDIBInfo;
+
+ lpDIBInfo = (LPBITMAPINFOHEADER) lpSpace;
+
+ lpDIBInfo->biSize = sizeof (BITMAPINFOHEADER);
+ lpDIBInfo->biWidth = (DWORD)lpBitmapCore->bcWidth;
+ lpDIBInfo->biHeight = (DWORD)lpBitmapCore->bcHeight;
+ lpDIBInfo->biPlanes = lpBitmapCore->bcPlanes;
+ lpDIBInfo->biBitCount = lpBitmapCore->bcBitCount;
+
+ lpDIBInfo->biCompression = 0;
+ lpDIBInfo->biSizeImage = 0;
+ lpDIBInfo->biXPelsPerMeter = 0;
+ lpDIBInfo->biYPelsPerMeter = 0;
+ lpDIBInfo->biClrUsed = 0;
+ lpDIBInfo->biClrImportant = 0;
+
+ /* get lpSpace to point at color table location */
+ ((LPBITMAPINFOHEADER)lpSpace)++;
+
+ /* copy the color table */
+
+ lpBitmapCore++; /* get to color table */
+ if (wUsage == DIB_RGB_COLORS)
+ {
+ for (i=0; i< (ColorSize/(sizeof(RGBQUAD))); i++)
+ {
+ /* copy the triple */
+ *((RGBTRIPLE FAR *)lpSpace)++ =
+ *((RGBTRIPLE FAR *)lpBitmapCore)++;
+ /* zero out reserved byte */
+ *((LPBYTE)lpSpace)++ = 0;
+ }
+ }
+ else
+ {
+ /* copy over indices */
+ for (i=0; i< (ColorSize/2); i++)
+ *lpSpace++ = *((LPWORD)lpBitmapCore)++;
+ }
+ }
+ else
+ {
+ *((LPBITMAPINFOHEADER)lpSpace)++ = *lpBitmapInfo++;
+
+ /* copy the color table */
+ for (i=0; i< (ColorSize/2); i++)
+ *lpSpace++ = *((LPWORD)lpBitmapInfo)++;
+ }
+
+ /* copy the actual bits */
+ lpHugeSpace = (HPWORD) lpSpace;
+ for (dwi=0; dwi < (BitmapSize/2); dwi++)
+ *lpHugeSpace++ = *lpBits++;
+
+ status = RecordParms(hMF, magic, (DWORD) (SpaceSize >> 1),
+ (LPWORD) lpHolder);
+
+ GlobalUnlock(hSpace);
+ GlobalFree(hSpace);
+ }
+ }
+ break;
+
+/* **** this should be combined with the above, but to eliminate possible
+** **** breakage right before shipping, keep it separate.
+*/
+ case (META_STRETCHDIB & 255):
+ {
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ LPBITMAPCOREHEADER lpBitmapCore; /* used for old DIBs */
+ HANDLE hSpace;
+ LPWORD lpSpace;
+ LPWORD lpHolder;
+ DWORD SpaceSize;
+ WORD ColorSize;
+ DWORD BitmapSize;
+ HPWORD lpBits;
+ WORD wUsage;
+ DWORD dwi;
+ HPWORD lpHugeSpace;
+ DWORD dwROP;
+
+ dwROP = *((LPDWORD)lpParm)++;
+ wUsage = *lpParm++;
+
+ lpBitmapInfo = (LPBITMAPINFOHEADER) *((WORD FAR * FAR *) lpParm)++;
+ lpBits = (HPWORD) *((WORD FAR * FAR *) lpParm)++;
+
+ /* old style DIB header */
+ if (lpBitmapInfo->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ lpBitmapCore = (LPBITMAPCOREHEADER)lpBitmapInfo;
+
+ if (lpBitmapCore->bcBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (1 << lpBitmapCore->bcBitCount) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ /* bits per scanline */
+ BitmapSize = lpBitmapCore->bcWidth *
+ lpBitmapCore->bcBitCount;
+
+ /* bytes per scanline (rounded to DWORD boundary) */
+ BitmapSize = ((BitmapSize + 31) & (~31)) >> 3;
+ /* bytes for the height of the bitmap */
+ BitmapSize *= lpBitmapCore->bcHeight;
+ }
+ /* new style DIB header */
+ else
+ {
+ if (lpBitmapInfo->biClrUsed)
+ {
+ ColorSize = ((WORD)lpBitmapInfo->biClrUsed) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+ }
+ else if (lpBitmapInfo->biBitCount == 24)
+ ColorSize = 0;
+ else
+ ColorSize = (1 << lpBitmapInfo->biBitCount) *
+ (wUsage == DIB_RGB_COLORS ?
+ sizeof(RGBQUAD) :
+ sizeof(WORD));
+
+ /* if biSizeImage is already there and we are
+ ** getting a full image, there is no more work
+ ** to be done.
+ */
+ if (!(BitmapSize = lpBitmapInfo->biSizeImage))
+ {
+ /* bits per scanline */
+ BitmapSize = lpBitmapInfo->biWidth *
+ lpBitmapInfo->biBitCount;
+ /* bytes per scanline (rounded to DWORD boundary) */
+ BitmapSize = ((BitmapSize + 31) & (~31)) >> 3;
+ /* bytes for the height of the bitmap */
+ BitmapSize *= (WORD)lpBitmapInfo->biHeight;
+ }
+
+ }
+
+ SpaceSize = (DWORD)sizeof(BITMAPINFOHEADER) + (DWORD)ColorSize +
+ (DWORD)BitmapSize +
+ (DWORD)(11*sizeof(WORD));
+
+ if ((hSpace = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,SpaceSize)))
+ {
+ lpHolder = lpSpace = (LPWORD) GlobalLock(hSpace);
+
+ /* copy over call parameters */
+ *((LPDWORD)lpSpace)++ = dwROP;
+ *lpSpace++ = wUsage;
+ for (i=0; i<8; i++)
+ *lpSpace++ = *lpParm++;
+
+ /* copy the bitmap header */
+ if (lpBitmapInfo->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ LPBITMAPINFOHEADER lpDIBInfo;
+
+ lpDIBInfo = (LPBITMAPINFOHEADER) lpSpace;
+
+ lpDIBInfo->biSize = sizeof (BITMAPINFOHEADER);
+ lpDIBInfo->biWidth = (DWORD)lpBitmapCore->bcWidth;
+ lpDIBInfo->biHeight = (DWORD)lpBitmapCore->bcHeight;
+ lpDIBInfo->biPlanes = lpBitmapCore->bcPlanes;
+ lpDIBInfo->biBitCount = lpBitmapCore->bcBitCount;
+
+ lpDIBInfo->biCompression = 0;
+ lpDIBInfo->biSizeImage = 0;
+ lpDIBInfo->biXPelsPerMeter = 0;
+ lpDIBInfo->biYPelsPerMeter = 0;
+ lpDIBInfo->biClrUsed = 0;
+ lpDIBInfo->biClrImportant = 0;
+
+ /* get lpSpace to point at color table location */
+ ((LPBITMAPINFOHEADER)lpSpace)++;
+
+ /* copy the color table */
+
+ lpBitmapCore++; /* get to color table */
+ if (wUsage == DIB_RGB_COLORS)
+ {
+ for (i=0; i< (ColorSize/(sizeof(RGBQUAD))); i++)
+ {
+ /* copy the triple */
+ *((RGBTRIPLE FAR *)lpSpace)++ =
+ *((RGBTRIPLE FAR *)lpBitmapCore)++;
+ /* zero out reserved byte */
+ *((LPBYTE)lpSpace)++ = 0;
+ }
+ }
+ else
+ {
+ /* copy over indices */
+ for (i=0; i< (ColorSize/2); i++)
+ *lpSpace++ = *((LPWORD)lpBitmapCore)++;
+ }
+ }
+ else
+ {
+ *((LPBITMAPINFOHEADER)lpSpace)++ = *lpBitmapInfo++;
+
+ /* copy the color table */
+ for (i=0; i< (ColorSize/2); i++)
+ *lpSpace++ = *((LPWORD)lpBitmapInfo)++;
+ }
+
+ /* copy the actual bits */
+ lpHugeSpace = (HPWORD) lpSpace;
+ for (dwi=0; dwi < (BitmapSize/2); dwi++)
+ *lpHugeSpace++ = *lpBits++;
+
+ status = RecordParms(hMF, magic, (DWORD) (SpaceSize >> 1),
+ (LPWORD) lpHolder);
+
+ GlobalUnlock(hSpace);
+ GlobalFree(hSpace);
+ }
+ }
+ break;
+
+ case (META_REALIZEPALETTE & 255):
+ {
+ /* we need to see if the palette has changed since
+ ** it was selected into the DC. if so, we need to
+ ** adjust things with a SetPaletteEntries call
+ */
+
+ status = MakeLogPalette(hMF, npMF->recCurObjects[OBJ_PALETTE-1], META_SETPALENTRIES);
+
+ if (status)
+ status = RecordParms(hMF, META_REALIZEPALETTE, (DWORD)0, (LPWORD) NULL);
+ }
+ break;
+
+ case (META_SELECTPALETTE & 255):
+ lpParm++; /* skip over fore/back flag */
+ npMF->recCurObjects[OBJ_PALETTE-1] = *lpParm; /* pal used in this DC */
+ if ((position = RecordObject(hMF, magic, count, lpParm)) != -1)
+ status = RecordParms(hMF, META_SELECTPALETTE, 1UL, &position);
+ break;
+
+ case (META_SELECTOBJECT & 255):
+ if (*lpParm)
+ {
+ if ((position = RecordObject(hMF, magic, count, lpParm)) == -1)
+ return(FALSE);
+ else
+ {
+ HANDLE hObject;
+
+ status = RecordParms(hMF, META_SELECTOBJECT, 1UL, &position);
+
+ /* maintain the new selection in the CurObject table */
+ hObject = *lpParm;
+ npMF->recCurObjects[GetObjectType(hObject)-1] = hObject;
+ }
+ }
+ break;
+
+ case (META_RESETDC & 255):
+ status = RecordParms( hMF, magic,
+ ((LPDEVMODE)lpParm)->dmSize +
+ ((LPDEVMODE)lpParm)->dmDriverExtra,
+ lpParm );
+ break;
+
+ case (META_STARTDOC & 255):
+ {
+ short iBytes;
+ LPSTR lpSpace;
+ LPSTR lpsz;
+ short n;
+
+ lpsz = (LPSTR)lpParm; // point to lpDoc
+ n = lstrlen((LPSTR)lpsz + 2) + 1;
+ iBytes = n + lstrlen((LPSTR)lpsz + 6) + 1;
+
+ lpSpace = (char *) LocalAlloc( LMEM_FIXED|LMEM_ZEROINIT,iBytes);
+ lstrcpy(lpSpace, (LPSTR)lpsz + 2);
+ lstrcpy(lpSpace + n + 1, lpsz + 6);
+ status = RecordParms(hMF, magic, (DWORD)(iBytes >> 1), (LPWORD)lpSpace);
+ LocalFree((HANDLE)(DWORD)lpSpace);
+ }
+ break;
+
+ }
+ return(status);
+ }
+ }
+} /* RecordOther */
+
+
+/***************************** Internal Function ***************************\
+* RecordObject
+*
+* Records the use of an object by creating the object
+*
+* Returns: index of object in table
+*
+*
+\***************************************************************************/
+
+int INTERNAL RecordObject(HANDLE hMF, WORD magic, WORD count, LPWORD lpParm)
+{
+ LPBITMAPINFOHEADER lpDIBInfo ;
+ WORD status;
+ WORD position;
+ HANDLE hObject;
+ WORD objType;
+ BYTE bBitsPerPel;
+ WORD wColorTableSize;
+ DWORD iBits ;
+ WORD i;
+ HANDLE hSpace = NULL ;
+ LPWORD lpSpace;
+ LPWORD lpTemp ;
+ BYTE objBuf[MAXOBJECTSIZE];
+
+
+ dprintf( 6," RecordObject 0x%X", magic);
+
+ hObject = *lpParm;
+
+ hMF = MAKEMETADC(hMF);
+ ASSERTGDI( IsMetaDC(hMF), "RecordObject: Expects only valid metafiles");
+
+ // Add the object to the metafiles list
+ if ((status = AddToTable(hMF, hObject, (LPWORD) &position, TRUE)) == -1)
+ return(status);
+ else if (status == FALSE)
+ {
+ objType = GetObjectAndType( hObject, objBuf );
+
+ switch (objType)
+ {
+ case OBJ_PEN:
+ status = RecordParms(hMF, META_CREATEPENINDIRECT,
+ (DWORD)((sizeof(LOGPEN) + 1) >> 1),
+
+ (LPWORD)objBuf );
+ break;
+
+ case OBJ_FONT:
+ /* size of LOGFONT adjusted based on the length of the facename */
+ status = RecordParms(hMF, META_CREATEFONTINDIRECT,
+ (DWORD)((1 + lstrlen((LPSTR) ((LPLOGFONT)objBuf)->lfFaceName) +
+ sizeof(LOGFONT) - LF_FACESIZE + 1) >> 1),
+ (LPWORD) objBuf);
+ break;
+
+/*
+!!! in win2, METACREATEREGION records contained an entire region object,
+!!! including the full header. this header changed in win3.
+!!!
+!!! to remain compatible, the region records will be saved with the
+!!! win2 header. here we save our region with a win2 header.
+*/
+ case OBJ_RGN:
+ {
+ LPWIN3REGION lpw3rgn = (LPWIN3REGION)NULL;
+ DWORD cbNTRgnData;
+ WORD sel;
+ DWORD curRectl = 0;
+ WORD cScans = 0;
+ WORD maxScanEntry = 0;
+ WORD curScanEntry;
+ WORD cbw3data;
+ LPRGNDATA lprgn = (LPRGNDATA)NULL;
+ LPRECTL lprcl;
+ LPSCAN lpScan;
+
+ status = FALSE; // just in case something goes wrong
+
+ // Get the NT Region Data
+ cbNTRgnData = GetRegionData( hObject, 0, NULL );
+ if (cbNTRgnData == 0)
+ break;
+
+ sel = GlobalAlloc( GMEM_FIXED, cbNTRgnData);
+ if (!sel)
+ break;
+
+ lprgn = (LPRGNDATA)MAKELONG(0, sel);
+
+ cbNTRgnData = GetRegionData( hObject, cbNTRgnData, lprgn );
+ if (cbNTRgnData == 0)
+ break;
+
+ lprcl = (LPRECTL)lprgn->Buffer;
+
+ // Create the Windows 3.x equivalent
+
+ // worst case is one scan for each rect
+ cbw3data = 2*sizeof(WIN3REGION) + (WORD)lprgn->rdh.nCount*sizeof(SCAN);
+
+ sel = GlobalAlloc( GMEM_FIXED, cbw3data);
+ if (!sel)
+ break;
+
+ lpw3rgn = (LPWIN3REGION)MAKELONG(0, sel);
+ GetRgnBox( hObject, &lpw3rgn->rcBounding );
+
+ cbw3data = sizeof(WIN3REGION) - sizeof(SCAN) + 2;
+
+ // visit all the rects
+ lpScan = lpw3rgn->aScans;
+ while(curRectl < lprgn->rdh.nCount)
+ {
+ LPWORD lpXEntry;
+ WORD cbScan;
+
+ curScanEntry = 0; // Current X pair in this scan
+
+ lpScan->scnPntTop = (WORD)lprcl[curRectl].yTop;
+ lpScan->scnPntBottom = (WORD)lprcl[curRectl].yBottom;
+
+ lpXEntry = lpScan->scnPntsX;
+
+ // handle rects on this scan
+ do
+ {
+ lpXEntry[curScanEntry + 0] = (WORD)lprcl[curRectl].xLeft;
+ lpXEntry[curScanEntry + 1] = (WORD)lprcl[curRectl].xRight;
+ curScanEntry += 2;
+ curRectl++;
+ } while ( (curRectl < lprgn->rdh.nCount)
+ && (lprcl[curRectl-1].yTop == lprcl[curRectl].yTop)
+ && (lprcl[curRectl-1].yBottom == lprcl[curRectl].yBottom)
+ );
+
+ lpScan->scnPntCnt = curScanEntry;
+ lpXEntry[curScanEntry] = curScanEntry; // Count also follows Xs
+ cScans++;
+
+ if (curScanEntry > maxScanEntry)
+ maxScanEntry = curScanEntry;
+
+ // account for each new scan + each X1 X2 Entry but the first
+ cbScan = sizeof(SCAN)-(sizeof(WORD)*2) + (curScanEntry*sizeof(WORD));
+ cbw3data += cbScan;
+ lpScan = (LPSCAN)(((LPBYTE)lpScan) + cbScan);
+ }
+
+ // Initialize the header
+ lpw3rgn->nextInChain = 0;
+ lpw3rgn->ObjType = 6; // old Windows OBJ_RGN identifier
+ lpw3rgn->ObjCount= 0x2F6;
+ lpw3rgn->cbRegion = cbw3data; // don't count type and next
+ lpw3rgn->cScans = cScans;
+ lpw3rgn->maxScan = maxScanEntry;
+
+ status = RecordParms(hMF, META_CREATEREGION,
+ cbw3data-1 >> 1, // Convert to count of words
+ (LPWORD) lpw3rgn);
+
+ GlobalFree( HIWORD(lprgn) );
+ GlobalFree( HIWORD(lpw3rgn) );
+ }
+
+ break;
+
+
+ case OBJ_BRUSH:
+ switch (((LPLOGBRUSH)objBuf)->lbStyle)
+ {
+ case BS_DIBPATTERN:
+ {
+ WORD cbDIBBits;
+ BITMAP logBitmap;
+
+ /* get the pattern DIB */
+ GetObject( (HANDLE)((LPLOGBRUSH)objBuf)->lbHatch, sizeof(BITMAP), (LPSTR)&logBitmap );
+
+ cbDIBBits = logBitmap.bmWidthBytes * logBitmap.bmHeight;
+ if ((hSpace = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(LONG)(cbDIBBits + 4))))
+ {
+ lpTemp = lpSpace = (LPWORD)GlobalLock (hSpace) ;
+
+ /* mark this as a DIB pattern brush */
+ *lpSpace++ = BS_DIBPATTERN;
+
+ /* set the usage word */
+ *lpSpace++ = (WORD)((LPLOGBRUSH)objBuf)->lbColor;
+
+ // lpPackedDIB = (LPWORD)GlobalLock(hPatBits);
+
+ /* copy the bits to the new buffer */
+ for (i = 0; i < (cbDIBBits >> 1); i++)
+ *lpSpace++ = *logBitmap.bmBits++;
+
+ status = RecordParms (hMF, META_DIBCREATEPATTERNBRUSH,
+ (DWORD)(cbDIBBits >> 1) + 2, (LPWORD)lpTemp);
+
+ /* release the allocated space */
+ GlobalUnlock (hSpace) ;
+ GlobalFree (hSpace) ;
+ }
+ }
+ break;
+
+ case BS_PATTERN:
+ {
+ BITMAP logBitmap;
+
+ if (GetObject((HANDLE)((LPLOGBRUSH)objBuf)->lbHatch, sizeof(logBitmap), (LPSTR)&logBitmap))
+ {
+ /* allocate space for the device independent bitmap */
+ if (hSpace = AllocateSpaceForDIB (&logBitmap,
+ (LPBYTE)&bBitsPerPel,
+ (LPWORD) &wColorTableSize ,
+ (LPDWORD) &iBits))
+ {
+ /* get a pointer to the allocated space */
+ lpTemp = lpSpace = (LPWORD) GlobalLock (hSpace) ;
+
+ /* mark this as a normal pattern brush */
+ *lpSpace++ = BS_PATTERN;
+
+ /* use RGB colors */
+ *lpSpace++ = DIB_RGB_COLORS;
+
+ /* this also will be a pointer to the DIB header */
+ lpDIBInfo = (LPBITMAPINFOHEADER) lpSpace ;
+
+ /* prepare the header of the bitmap and get a pointer to the
+ start of the area which is to hold the bits */
+ lpSpace = InitializeDIBHeader (lpDIBInfo,
+ &logBitmap, bBitsPerPel, wColorTableSize);
+
+ /* convert the bits into the DIB format */
+ // !!! validate that the DC is ignored
+ GetDIBits (hScreenDC, (HBITMAP)((LPLOGBRUSH)objBuf)->lbHatch,
+ 0, logBitmap.bmHeight,
+ (LPSTR) lpSpace, (LPBITMAPINFO)lpDIBInfo,0) ;
+
+ /* now record the Header and Bits as parameters */
+ status = RecordParms (hMF, META_DIBCREATEPATTERNBRUSH,
+ (DWORD)(iBits >> 1) + 2, (LPWORD) lpTemp);
+
+ /* release the allocated space */
+ GlobalUnlock (hSpace) ;
+ GlobalFree (hSpace) ;
+ }
+ }
+ }
+ break;
+
+ default:
+ /* non-pattern brush */
+ status = RecordParms(hMF, META_CREATEBRUSHINDIRECT,
+ (DWORD)((sizeof(LOGBRUSH) + 1) >> 1),
+ (LPWORD)objBuf);
+ break;
+ } /* Brush Type switch */
+ break; /* Brush object case */
+
+ case OBJ_PALETTE:
+ status = MakeLogPalette(hMF, hObject, META_CREATEPALETTE);
+ break;
+
+ default:
+ ASSERTGDIW( 0, "unknown case RecordObject: %d", objType );
+ break;
+ }
+// RecordObj10:
+ }
+
+ ASSERTGDI( status == TRUE, "RecordObject: Failing");
+ return ((status == TRUE) ? position : -1);
+} /* RecordObject */
+
+
+/***************************** Internal Function ***************************\
+* ProbeSize
+*
+* Determines if there is sufficient space for metafiling the dwLength
+* words into the memory metafile
+*
+* Returns: a global handle of where next metafile is to be recorded
+* or FALSE if unable to allocate more memory
+*
+\***************************************************************************/
+
+HANDLE INTERNAL ProbeSize(NPMETARECORDER npMF, DWORD dwLength)
+{
+ DWORD nWords;
+ DWORD totalWords;
+ BOOL status = FALSE;
+ HANDLE hand;
+
+ GdiLogFunc3( " ProbeSize");
+
+ if (npMF->hMetaData == NULL)
+ {
+ nWords = ((DWORD)DATASIZE > dwLength) ? (DWORD)DATASIZE : dwLength;
+ totalWords = (nWords * sizeof(WORD)) + sizeof(METAHEADER);
+ if (npMF->hMetaData = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, totalWords))
+ {
+ npMF->sizeBuffer = nWords;
+ npMF->recFilePosition = 0;
+ status = TRUE;
+ }
+ }
+ else if(npMF->sizeBuffer < (npMF->recFilePosition + dwLength))
+ {
+ nWords = ((DWORD)DATASIZE > dwLength) ? (DWORD)DATASIZE : dwLength;
+ nWords += npMF->sizeBuffer;
+ totalWords = (nWords * sizeof(WORD)) + sizeof(METAHEADER);
+ if (hand = GlobalReAlloc(npMF->hMetaData, totalWords, GMEM_MOVEABLE))
+ {
+ npMF->hMetaData = hand;
+ npMF->sizeBuffer = nWords;
+ status = TRUE;
+ }
+ }
+ else
+ {
+ status = TRUE;
+ }
+ return ((status) ? npMF->hMetaData : NULL);
+}
+
+
+/***************************** Internal Function ***************************\
+* AddToTable
+*
+* Add an object (brush, pen...) to a list of objects associated with the
+* metafile.
+*
+*
+*
+* Returns: TRUE if object is already in table
+* FALSE if object was just added to table
+* -1 if failure
+*
+* Remarks
+* bAdd is TRUE iff the object is being added otherwise it is being deleted
+*
+\***************************************************************************/
+
+WORD INTERNAL AddToTable(HANDLE hMF, HANDLE hObject, LPWORD pPosition, BOOL bAdd)
+{
+ NPMETARECORDER npMF;
+ WORD iEmptySpace = -1;
+ WORD i;
+ WORD status = -1;
+ HANDLE hTable;
+ OBJECTTABLE *pHandleTable;
+
+
+ GdiLogFunc2(" AddToTable");
+
+ if ((hMF = GetPMetaFile(hMF)) != -1 )
+ {
+ npMF = (NPMETARECORDER) LocalLock(hMF);
+
+ if (hTable = npMF->hObjectTable)
+ {
+ pHandleTable = (NPOBJECTTABLE) LMHtoP(hTable);
+ for (i = 0; i < npMF->recordHeader.mtNoObjects; ++i)
+ {
+ if (hObject == pHandleTable[i].objectCurHandle ) //!!!!! used to be check unique ID#
+ {
+ *pPosition = i;
+ status = TRUE;
+
+ // if we are doing a METADELETEOBJECT.
+ // delete object from table
+ if (!bAdd)
+ {
+ pHandleTable[i].objectIndex = NULL;
+ pHandleTable[i].objectCurHandle = NULL;
+ }
+ goto AddToTable10;
+ }
+
+ /* if the entry has been deleted, we want to add a new object
+ ** in its place. iEmptySpace will tell us where that place is.
+ */
+ else if ((pHandleTable[i].objectIndex == NULL) && (iEmptySpace == -1))
+ iEmptySpace = i;
+ }
+ }
+
+ if (bAdd)
+ {
+ // If there is no object table for this MetaFile then Allocate one.
+ if (hTable == NULL)
+ {
+ npMF->hObjectTable = hTable = LocalAlloc(LMEM_MOVEABLE, sizeof(OBJECTTABLE));
+ }
+ else if (iEmptySpace == -1)
+ hTable = LocalReAlloc(hTable, (npMF->recordHeader.mtNoObjects + 1)
+ * sizeof(OBJECTTABLE), LMEM_MOVEABLE);
+
+ if (hTable)
+ {
+ pHandleTable = (NPOBJECTTABLE) LMHtoP(hTable);
+ if (iEmptySpace == -1)
+ *pPosition = npMF->recordHeader.mtNoObjects++;
+ else
+ *pPosition = iEmptySpace;
+ pHandleTable[*pPosition].objectIndex = hObject; //!!!!! pObjHead->ilObjCount;
+ pHandleTable[*pPosition].objectCurHandle = hObject;
+ status = FALSE;
+ }
+ }
+AddToTable10:;
+ LocalUnlock(hMF);
+ }
+
+ ASSERTGDI( status != -1, "AddToTable: Failing");
+ return(status);
+}
+
+#if 0 // this is going to gdi.dll
+
+/***************************** Internal Function **************************\
+* HDC GDIENTRY CreateMetaFile
+*
+* Creates a MetaFile DC
+*
+*
+* Effects:
+*
+\***************************************************************************/
+
+HDC GDIENTRY CreateMetaFile(LPSTR lpFileName)
+{
+ BOOL status=FALSE;
+ GLOBALHANDLE hMF;
+ NPMETARECORDER npMF;
+
+ GdiLogFunc("CreateMetaFile");
+
+ if (hMF = LocalAlloc(LMEM_MOVEABLE|LMEM_ZEROINIT, sizeof(METARECORDER)))
+ {
+ npMF = (NPMETARECORDER) LocalLock(hMF);
+ npMF->metaDCHeader.ilObjType = OBJ_METAFILE;
+ npMF->metaDCHeader.ident = ID_METADC;
+
+ npMF->recordHeader.mtHeaderSize = HEADERSIZE;
+ npMF->recordHeader.mtVersion = METAVERSION;
+ npMF->recordHeader.mtSize = HEADERSIZE;
+
+ if (lpFileName)
+ {
+ npMF->recordHeader.mtType = DISKMETAFILE;
+ if (((npMF->recFileNumber = OpenFile(lpFileName,
+ (LPOFSTRUCT) &(npMF->recFileBuffer),
+ OF_CREATE|READ_WRITE))
+ != -1)
+ && (_lwrite(npMF->recFileNumber, (LPSTR)npMF, sizeof(METAHEADER))
+ == sizeof(METAHEADER)))
+ {
+ status = TRUE;
+ }
+ if (npMF->recFileNumber != -1)
+ {
+ if (!(npMF->recFileBuffer.fFixedDisk))
+ _lclose(npMF->recFileNumber);
+ }
+
+ if (!MetaCache.hCache)
+ {
+ MetaCache.hCache = AllocBuffer(&MetaCache.wCacheSize);
+ MetaCache.wCacheSize >>= 1;
+ MetaCache.hMF = hMF;
+ MetaCache.wCachePos = 0;
+ }
+ }
+
+ else
+ {
+ npMF->recordHeader.mtType = MEMORYMETAFILE;
+ status = TRUE;
+ }
+ }
+
+ // If successfull then add the metafile to the linked list
+ if( status != FALSE )
+ {
+ if( hFirstMetaFile == 0 )
+ {
+ hFirstMetaFile = hMF;
+ }
+ else
+ {
+ npMF->metaDCHeader.nextinchain = hFirstMetaFile;
+ hFirstMetaFile = hMF;
+ }
+ LocalUnlock( hMF );
+ }
+
+ return ((status) ? MAKEMETADC(hMF) : FALSE);
+}
+
+
+/***************************** Internal Function **************************\
+* HANDLE GDIENTRY CloseMetaFile
+*
+* The CloseMetaFile function closes the metafile device context and creates a
+* metafile handle that can be used to play the metafile by using the
+* PlayMetaFile function.
+*
+* Effects:
+*
+\***************************************************************************/
+
+HANDLE GDIENTRY CloseMetaFile(HANDLE hdc)
+{
+ BOOL status = FALSE;
+ HANDLE hMetaFile=NULL;
+ LPMETADATA lpMetaData;
+ LPMETAFILE lpMFNew;
+ WORD fileNumber;
+ NPMETARECORDER npMF;
+ DWORD metafileSize;
+ LPWORD lpCache;
+ HANDLE hMF;
+ HANDLE hMFSearch;
+ int rc;
+
+ GdiLogFunc("CloseMetaFile");
+
+ hMF = HANDLEFROMMETADC(hdc);
+
+ if (hMF && RecordParms(hMF, 0, (DWORD)0, (LONG)0))
+ {
+
+ npMF = (NPMETARECORDER)LocalLock(hMF);
+ if (!(npMF->recFlags & METAFILEFAILURE))
+ {
+ if (npMF->recordHeader.mtType == MEMORYMETAFILE)
+ {
+ lpMetaData = (LPMETADATA) GlobalLock(npMF->hMetaData);
+ lpMetaData->dataHeader = npMF->recordHeader;
+ metafileSize = (npMF->recordHeader.mtSize * sizeof(WORD))
+ + sizeof(METAHEADER);
+ GlobalUnlock(hMetaFile = npMF->hMetaData);
+ if (!(status = (BOOL) GlobalReAlloc(hMetaFile,
+ (LONG)metafileSize,
+ GMEM_MOVEABLE)))
+ GlobalFree(hMetaFile);
+ }
+ else
+ /* rewind the file and write the header out */
+ if (hMetaFile = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(LONG) sizeof(METAFILE)))
+ {
+ lpMFNew = (LPMETAFILE) GlobalLock(hMetaFile);
+ lpMFNew->MetaFileHeader = npMF->recordHeader;
+ npMF->recordHeader.mtType = MEMORYMETAFILE;
+ if (npMF->recFileBuffer.fFixedDisk)
+ fileNumber = npMF->recFileNumber;
+ else
+ {
+ if ((fileNumber = OpenFile((LPSTR) npMF->recFileBuffer.szPathName,
+ (LPOFSTRUCT) &(npMF->recFileBuffer),
+ OF_PROMPT | OF_REOPEN | READ_WRITE))
+ == -1)
+ {
+ GlobalUnlock(hMetaFile);
+ GlobalFree(hMetaFile);
+ LocalUnlock(hMF);
+
+ if (MetaCache.hMF == hMF)
+ {
+ GlobalFree(MetaCache.hCache);
+ MetaCache.hCache = MetaCache.hMF = 0;
+ }
+
+ goto errCloseMetaFile;
+ }
+ }
+
+ if (MetaCache.hCache && MetaCache.hMF == hMF)
+ {
+ _llseek(fileNumber, (LONG) 0, 2);
+ lpCache = (LPWORD) GlobalLock(MetaCache.hCache);
+ rc = (MetaCache.wCachePos) ?
+ AttemptWrite(hMF,
+ fileNumber,
+ (DWORD)(MetaCache.wCachePos << 1),
+ (LPSTR) lpCache)
+ : TRUE;
+ GlobalUnlock(MetaCache.hCache);
+ GlobalFree(MetaCache.hCache);
+ MetaCache.hCache = MetaCache.hMF = 0;
+
+ if (!rc)
+ {
+ MarkMetaFile(hMF);
+ goto errCloseMetaFile;
+ }
+ }
+
+ _llseek(fileNumber, (LONG) 0, 0);
+ if(_lwrite(fileNumber, (LPSTR) (&npMF->recordHeader),
+ sizeof(METAHEADER)) == sizeof(METAHEADER))
+ {
+ status = TRUE;
+ }
+ lpMFNew->MetaFileBuffer = npMF->recFileBuffer;
+ _lclose(fileNumber);
+ GlobalUnlock(hMetaFile);
+ }
+
+ if (npMF->hObjectTable)
+ {
+ LocalFree((HANDLE) npMF->hObjectTable);
+ }
+ }
+
+ /* Remove the meta file from the list of active metafiles */
+ hMFSearch = hFirstMetaFile;
+
+ if( hFirstMetaFile == hMF )
+ {
+ hFirstMetaFile = npMF->metaDCHeader.nextinchain;
+ }
+ else
+ {
+ while( hMFSearch )
+ {
+ NPMETARECORDER npMFSearch;
+ HANDLE hNext;
+
+ npMFSearch = (NPMETARECORDER)LocalLock(hMFSearch);
+ hNext = npMFSearch->metaDCHeader.nextinchain;
+ if( hNext == hMF )
+ {
+ npMFSearch->metaDCHeader.nextinchain =
+ npMF->metaDCHeader.nextinchain;
+ }
+ else
+ {
+ hNext = npMFSearch->metaDCHeader.nextinchain;
+ }
+ LocalUnlock(hMFSearch);
+ hMFSearch = hNext;
+ }
+ }
+ LocalUnlock(hMF);
+ LocalFree(hMF);
+ }
+
+errCloseMetaFile:
+ return ((status) ? hMetaFile : FALSE);
+}
+
+
+/***************************** Internal Function **************************\
+* CopyMetaFile(hSrcMF, lpFileName)
+*
+* Copies the metafile (hSrcMF) to a new metafile with name lpFileName. The
+* function then returns a handle to this new metafile if the function was
+* successful.
+*
+* Retuns a handle to a new metafile, 0 iff failure
+*
+* IMPLEMENTATION:
+* The source and target metafiles are checked to see if they are both memory
+* metafile and if so a piece of global memory is allocated and the metafile
+* is simply copied.
+* If this is not the case CreateMetaFile is called with lpFileName and then
+* records are pulled out of the source metafile (using GetEvent) and written
+* into the destination metafile one at a time (using RecordParms).
+*
+* Lock the source
+* if source is a memory metafile and the destination is a memory metafile
+* alloc the same size global memory as the source
+* copy the bits directly
+* else
+* get a metafile handle by calling CreateMetaFile
+* while GetEvent returns records form the source
+* record the record in the new metafile
+*
+* close the metafile
+*
+* return the new metafile handle
+*
+\***************************************************************************/
+
+HANDLE GDIENTRY CopyMetaFile(HANDLE hSrcMF, LPSTR lpFileName)
+{
+ DWORD i;
+ DWORD iBytes;
+ LPMETAFILE lpMF;
+ LPMETAFILE lpDstMF;
+ LPMETARECORD lpMR = NULL;
+ HANDLE hTempMF;
+ HANDLE hDstMF;
+ NPMETARECORDER pDstMF;
+ WORD state;
+
+ GdiLogFunc( "CopyMetaFile" );
+
+ if (!IsValidMetaFile(hSrcMF))
+ return NULL;
+
+ if (hSrcMF && (lpMF = (LPMETAFILE) GlobalLock(hSrcMF)))
+ {
+ state = (lpMF->MetaFileHeader.mtType == MEMORYMETAFILE) ? 0 : 2;
+ state |= (lpFileName) ? 1 : 0;
+
+ switch (state)
+ {
+ case 0: /* memory -> memory */
+ iBytes = GlobalSize(hSrcMF);
+ if (hDstMF = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, (DWORD) iBytes))
+ {
+ lpDstMF = (LPMETAFILE) GlobalLock(hDstMF);
+ iBytes = iBytes/2; /* get WORD count */
+ for (i = 0; i < iBytes; ++i)
+ *((WORD huge *) lpDstMF)++ = *((WORD huge *) lpMF)++;
+
+ GlobalUnlock(hDstMF);
+ }
+ break;
+
+ case 3: /* disk -> disk */
+ hDstMF = CopyFile(lpMF->MetaFileBuffer.szPathName,
+ lpFileName)
+ ? GetMetaFile(lpFileName) : NULL;
+ break;
+
+ case 1:
+ case 2:
+ if (hDstMF = CreateMetaFile(lpFileName))
+ {
+ while (lpMR = GetEvent(lpMF, lpMR, FALSE))
+ if (!RecordParms(hDstMF, lpMR->rdFunction,
+ lpMR->rdSize - 3,
+ (LPWORD) lpMR->rdParm))
+ {
+ MarkMetaFile(hDstMF);
+ LocalFree(hDstMF);
+ goto CopyMetaFile10;
+ }
+ pDstMF = (NPMETARECORDER) NPFROMMETADC(hDstMF);
+ pDstMF->recordHeader = lpMF->MetaFileHeader;
+
+ pDstMF->recordHeader.mtType = (lpFileName) ? DISKMETAFILE
+ : MEMORYMETAFILE;
+
+ hDstMF = (hTempMF = CloseMetaFile(hDstMF)) ? hTempMF : NULL;
+
+ }
+ break;
+ }
+
+CopyMetaFile10:;
+ GlobalUnlock(hSrcMF);
+ }
+ return(hDstMF);
+}
+
+
+/***************************** Internal Function ***************************\
+* HANDLE GDIENTRY GetMetaFileBits(HANDLE hMF)
+*
+* The GetMetaFileBits function returns a handle to a global memory block that
+* contains the specified metafile as a collection of bits. The memory block
+* can be used to determine the size of the metafile or to save the metafile as
+* a file. The memory block should not be modified.
+*
+* Effects:
+*
+\***************************************************************************/
+
+HANDLE GDIENTRY GetMetaFileBits(HANDLE hMF)
+{
+ GdiLogFunc( "GetMetaFileBits");
+
+/* 6/3/88 t-kensy: This code does nothing, except make sure hMF is valid
+ BOOL status = FALSE;
+ LPMETAFILE lpMF;
+
+ if (hMF && (lpMF = (LPMETAFILE) GlobalLock(hMF)))
+ {
+ if (lpMF->MetaFileHeader.mtType == MEMORYMETAFILE)
+ {
+ if (hMF = GlobalReAlloc(hMF, GlobalSize(hMF),
+ GLOBALMOVABLENONSHARED))
+ status = TRUE;
+ }
+ GlobalUnlock(hMF);
+ }
+ return(status ? hMF : status);
+*/
+ return (GlobalHandle(hMF) & 0xffff) ? hMF : FALSE;
+}
+
+
+/***************************** Internal Function **************************\
+* HANDLE GDIENTRY SetMetaFileBits(HANDLE hMF)
+*
+*
+*
+* Effects:
+*
+\***************************************************************************/
+
+HANDLE GDIENTRY SetMetaFileBits(HANDLE hBits)
+{
+ GdiLogFunc( "SetMetaFileBits");
+
+/* return (GlobalReAlloc(hBits, GlobalSize(hBits), GLOBALMOVABLE));*/
+
+
+//---------------------------------------------------------------------------------
+// We will make GDI take over the ownership of this memory block. This is
+// done to help OLE, where either the server or the client could end while
+// the other still had the handle to the memory block. This will prevent
+// the block to dissapear after the creator exits. The strategy could be
+// changed if this causes memory leaks with other application.
+//
+// Amit Chatterjee. 6/18/91.
+//---------------------------------------------------------------------------------
+
+ return (GlobalReAlloc (hBits, 0L, GMEM_MODIFY | GMEM_DDESHARE)) ;
+}
+#endif // this is going to gdi.dll
+
+
+/***************************** Internal Function **************************\
+* CopyFile
+*
+*
+* Returns TRUE iff success
+*
+*
+\***************************************************************************/
+
+BOOL INTERNAL CopyFile(LPSTR lpSFilename, LPSTR lpDFilename)
+{
+ int ihSrc, ihDst, iBufferSize;
+ int iBytesRead;
+ OFSTRUCT ofStruct;
+ HANDLE hBuffer;
+ LPSTR lpBuffer;
+ BOOL fUnlink = FALSE;
+
+ GdiLogFunc3( "CopyFile");
+
+ /* Open the source file for reading */
+ if ((ihSrc = OpenFile(lpSFilename, &ofStruct, READ)) == -1)
+ goto CopyError10;
+
+ /* Open the destination file for writing */
+ if ((ihDst = OpenFile(lpDFilename, &ofStruct, OF_CREATE |
+ WRITE))
+ == -1)
+ goto CopyError20;
+
+ /* Get a buffer to transfer the file with */
+ if (!(hBuffer = AllocBuffer((LPWORD)&iBufferSize)))
+ goto CopyError30;
+
+ /* Lock the buffer and get a pointer to the storage */
+ if (!(lpBuffer = GlobalLock(hBuffer)))
+ goto CopyError40;
+
+ /* Copy the file, reading chunks at a time into the buffer */
+ do
+ {
+ if ((iBytesRead = _lread(ihSrc, lpBuffer, iBufferSize))
+ == -1)
+ goto CopyError40;
+
+ if (_lwrite(ihDst, lpBuffer, iBytesRead) != (WORD)iBytesRead)
+ goto CopyError40;
+ } while (iBytesRead == iBufferSize);
+
+#ifdef FIREWALL
+ /* if we are able to read anything from the source file at this
+ * point, then something is wrong!
+ */
+ if (_lread(ihSrc, lpBuffer, iBufferSize))
+ {
+ fUnlink = TRUE;
+ goto CopyError40;
+ }
+#endif
+
+ /* Everything's fine. Close up and exit successfully */
+ if (_lclose(ihSrc) == -1 || _lclose(ihDst) == -1)
+ goto CopyError40;
+
+ GlobalUnlock(hBuffer);
+ GlobalFree(hBuffer);
+
+ return TRUE;
+
+/* Error exit points */
+CopyError40:;
+ GlobalUnlock(hBuffer);
+ GlobalFree(hBuffer);
+CopyError30:;
+ _lclose(ihDst);
+ if (fUnlink)
+ OpenFile(lpDFilename, &ofStruct, OF_DELETE);
+
+CopyError20:;
+ _lclose(ihSrc);
+
+CopyError10:;
+ return FALSE;
+}
+
+
+/***************************** Internal Function **************************\
+* AllocateSpaceForDIB
+*
+* The following routine takes as input a device dependent bitmap structure
+* and calculates the size needed to store the corresponding DIB structure
+* including the DIB bits. It then proceeds to allocate space for it and
+* returns a HANDLE to the caller (HANDLE could be NULL if allocation fails)
+*
+* Returns a global handle to memory or FALSE
+*
+\***************************************************************************/
+
+HANDLE INTERNAL AllocateSpaceForDIB (lpBitmap, pbBitsPerPel, pwColorTableSize,
+ pdwcBits )
+LPBITMAP lpBitmap ;
+LPBYTE pbBitsPerPel ;
+LPWORD pwColorTableSize;
+LPDWORD pdwcBits ;
+{
+ int InputPrecision ;
+ DWORD iBits ;
+
+ GdiLogFunc3( " AllocateSpaceForDIB");
+
+ /* calculate the number of bits per pel that we are going to have in
+ the DIB format. This value should correspond to the number of planes
+ and bits per pel in the device dependent bitmap format */
+
+
+ /* multiply the number of planes and the bits pel pel in the device
+ dependent bitmap */
+
+ InputPrecision = lpBitmap->bmPlanes * lpBitmap->bmBitsPixel ;
+
+
+ /* DIB precision should be more than or equal this precison, though
+ the limit is 24 bits per pel */
+
+ if (InputPrecision == 1)
+ {
+ *pbBitsPerPel = 1 ;
+ *pwColorTableSize = 2 * sizeof (RGBQUAD) ;
+ }
+ else if (InputPrecision <= 4)
+ {
+ *pbBitsPerPel = 4 ;
+ *pwColorTableSize = 16 * sizeof (RGBQUAD) ;
+ }
+ else if (InputPrecision <= 8)
+ {
+ *pbBitsPerPel = 8 ;
+ *pwColorTableSize = 256 * sizeof (RGBQUAD) ;
+ }
+ else
+ {
+ *pbBitsPerPel = 24 ;
+ *pwColorTableSize = 0 ;
+ }
+
+/*--------------------------------------------------------------------------**
+** calulate the size of the DIB. Each scan line is going to be a mutiple of **
+** a DWORD. Also we shall need to allocate space for the color table. **
+**--------------------------------------------------------------------------*/
+
+ /* get the number of bits we need for a scanline */
+ iBits = lpBitmap->bmWidth * (*pbBitsPerPel);
+ iBits = (iBits + 31) & (~31) ;
+
+ /* convert to number of bytes and get the size of the DIB */
+ iBits = (iBits >> 3) * lpBitmap->bmHeight ;
+
+ /* add the space needed for the color table */
+ iBits += *pwColorTableSize ;
+
+ /* add the size for the BITMAPINFOHeader */
+ iBits += sizeof(BITMAPINFOHEADER) ;
+
+ /* return back the value for iBits */
+ *pdwcBits = iBits ;
+
+ /* actually allocate about 100 bytes more for params */
+ iBits += 100 ;
+
+/*--------------------------------------------------------------------------**
+** alocate space for the bitmap info header, the color table and the bits **
+** Return the value of the HANDLE. **
+**--------------------------------------------------------------------------*/
+
+ return (GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE,(LONG) iBits)) ;
+}
+
+
+/***************************** Internal Function **************************\
+* InitializeDIBHeader
+*
+* This function takes as input a pointer to a BITMAPINFO header structure
+* and a pointer to a device dependendent bitmap pointer together with the
+* number of bitsperpel requested for the DIB and the color table size. It
+* initializes the DIB header and returns a pointer pointing to the first
+* word after the color table. **
+*
+\***************************************************************************/
+
+LPWORD INTERNAL InitializeDIBHeader (lpDIBInfo, lpBitmap, bBitsPerPel, wColorTableSize)
+
+LPBITMAPINFOHEADER lpDIBInfo ;
+LPBITMAP lpBitmap ;
+BYTE bBitsPerPel ;
+WORD wColorTableSize ;
+
+{
+ LPBYTE lpSpace ;
+
+ GdiLogFunc3( " InitializeDIBHeader");
+
+ /* Initialize the fields till the start of the color table */
+ lpDIBInfo->biSize = sizeof (BITMAPINFOHEADER) ;
+ lpDIBInfo->biWidth = (DWORD)lpBitmap->bmWidth ;
+ lpDIBInfo->biHeight = (DWORD)lpBitmap->bmHeight ;
+ lpDIBInfo->biPlanes = 1 ;
+ lpDIBInfo->biBitCount = (WORD) bBitsPerPel ;
+
+ lpDIBInfo->biCompression = 0;
+ lpDIBInfo->biSizeImage = 0;
+ lpDIBInfo->biXPelsPerMeter = 0;
+ lpDIBInfo->biYPelsPerMeter = 0;
+ lpDIBInfo->biClrUsed = 0;
+ lpDIBInfo->biClrImportant = 0;
+
+ /* take the pointer past the HEADER and cast it to a BYTE ptr */
+ lpDIBInfo ++ ;
+ lpSpace = (LPBYTE) lpDIBInfo ;
+
+ /* take the pointer past the color table structure */
+ lpSpace += wColorTableSize ;
+
+ /* return this pointer as a WORD pointer */
+ return ((LPWORD) lpSpace) ;
+}
diff --git a/private/mvdm/wow16/gdi/metasup.c b/private/mvdm/wow16/gdi/metasup.c
new file mode 100644
index 000000000..1989bf44f
--- /dev/null
+++ b/private/mvdm/wow16/gdi/metasup.c
@@ -0,0 +1,523 @@
+/****************************** Module Header ******************************\
+* Module Name: MetaSup.c
+*
+* This file contains the routines for playing the GDI metafile. Most of these
+* routines are adopted from windows gdi code. Most of the code is from
+* win3.0 except for the GetEvent code which is taken from win2.1
+*
+*
+* Public Functions:
+* EnumMetaFile
+* Private Functions:
+*
+*
+* Created: 02-Jul-1991
+*
+* Copyright (c) 1985, 1991 Microsoft Corporation
+*
+* History:
+* 02-Jul-1991 -by- John Colleran [johnc]
+* Combined From Win 3.1 and WLO 1.0 sources
+\***************************************************************************/
+
+#include <windows.h>
+#include "gdi16.h"
+
+extern HANDLE hFirstMetaFile;
+extern HDC hScreenDC;
+
+#define MYSTOCKBITMAP (SYSTEM_FIXED_FONT+1)
+#define MYSTOCKRGN (SYSTEM_FIXED_FONT+2)
+#define CNT_GDI_STOCK_OBJ (MYSTOCKRGN+1)
+
+HANDLE ahStockObject[CNT_GDI_STOCK_OBJ] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
+HBITMAP hStaticBitmap;
+
+// Provide a Mapping from Object type to a stock object; See GetCurObject
+int mpObjectToStock[] =
+ { -1, // UNUSED 0
+ WHITE_PEN, // OBJ_PEN 1
+ BLACK_BRUSH, // OBJ_BRUSH 2
+ -1, // OBJ_DC 3
+ -1, // OBJ_METADC 4
+ DEFAULT_PALETTE, // OBJ_PALETTE 5
+ SYSTEM_FONT, // OBJ_FONT 6
+ MYSTOCKBITMAP, // OBJ_BITMAP 7
+ MYSTOCKRGN, // OBJ_RGN 8 //!!!!! init
+ -1, // OBJ_METAFILE 9
+ -1 }; // OBJ_MEMDC 10
+
+
+HANDLE INTERNAL GetCurObject(HDC hdc, WORD wObjType)
+{
+ HANDLE cur;
+
+
+//!!!!! fix to work with meta DCs as well
+
+ GdiLogFunc3( " GetCurObject" );
+
+ ASSERTGDI( wObjType <= MAX_OBJ, "GetCurObject invalid Obj" );
+
+//!!!!! fix regions when new API is done
+ if( wObjType == OBJ_RGN )
+ {
+ return(0);
+ }
+
+ if( wObjType == OBJ_PALETTE)
+ {
+ cur = SelectPalette( hdc, ahStockObject[DEFAULT_PALETTE], FALSE );
+ SelectPalette( hdc, cur, FALSE );
+ }
+ else
+ {
+ cur = SelectObject(hdc,ahStockObject[mpObjectToStock[wObjType]]);
+ SelectObject( hdc, cur );
+ }
+
+ ASSERTGDIW( cur, "GetCurObect Failed. Type %d", wObjType );
+ return(cur);
+}
+
+#if 0 // this is going to gdi.dll
+
+/******************************** Public Function **************************\
+* BOOL GDIENTRY EnumMetaFile(hmf)
+*
+* The EnumMetaFile function enumerates the GDI calls within the metafile
+* identified by the hMF parameter. The EnumMetaFile function retrieves each
+* GDI call within the metafile and passes it to the function pointed to by the
+* lpCallbackFunc parameter. This callback function, an application-supplied
+* function, can process each GDI call as desired. Enumeration continues until
+* there are no more GDI calls or the callback function returns zero.
+*
+*
+* Effects:
+*
+\***************************************************************************/
+
+BOOL GDIENTRY EnumMetaFile(hdc, hMF, lpCallbackFunction, lpClientData)
+HDC hdc;
+LOCALHANDLE hMF;
+FARPROC lpCallbackFunction;
+LPBYTE lpClientData;
+{
+ WORD i;
+ WORD noObjs;
+ BOOL bPrint=TRUE;
+ HANDLE hObject;
+ HANDLE hLBrush;
+ HANDLE hLPen;
+ HANDLE hLFont;
+ HANDLE hRegion;
+ HANDLE hPalette;
+ LPMETAFILE lpMF;
+ LPMETARECORD lpMR = NULL;
+ LPHANDLETABLE lpHandleTable = NULL;
+ GLOBALHANDLE hHandleTable = NULL;
+
+
+ GdiLogFunc( "EnumMetaFile");
+
+ if (!ISDCVALID(hdc))
+ {
+ ASSERTGDI( FALSE, "EnumMetaFile: DC is invalid");
+ return (FALSE);
+ }
+
+/* use GlobalFix() instead of GlobalLock() to insure that the
+** memory never moves, keeping our aliased selector pointing to the
+** right place
+*/
+// !!!!! replaced GlobalFix with GlobalLock
+ if (hMF && (lpMF = (LPMETAFILE)(DWORD)(0xFFFF0000 & (DWORD)GlobalLock(hMF))))
+ {
+ if ((noObjs = lpMF->MetaFileHeader.mtNoObjects) > 0)
+ {
+ if (!(hHandleTable =
+ GlobalAlloc((WORD)(GMEM_ZEROINIT | GMEM_MOVEABLE), (LONG)
+ ((sizeof(HANDLE) * lpMF->MetaFileHeader.mtNoObjects) +
+ sizeof(WORD)))))
+ {
+ goto ABRRT2;
+ }
+ lpHandleTable = (LPHANDLETABLE)GlobalLock(hHandleTable);
+ }
+
+ /* only do object save/reselect for real DC's */
+ if (hdc && !ISMETADC(hdc))
+ {
+ hLPen = GetCurObject( hdc, OBJ_PEN ); /* save the old objects so */
+ hLBrush = GetCurObject( hdc, OBJ_BRUSH); /* we can put them back */
+ hLFont = GetCurObject( hdc, OBJ_FONT);
+ hRegion = GetCurObject( hdc, OBJ_RGN);
+ hPalette = GetCurObject( hdc, OBJ_PALETTE);
+ }
+
+ while(lpMR = GetEvent(lpMF, lpMR, FALSE))
+ {
+ typedef int (FAR PASCAL *ENUMPROC)(HDC, LPHANDLETABLE, LPMETARECORD, int, LPBYTE);
+
+ if ((bPrint = (*((ENUMPROC)lpCallbackFunction))(hdc, lpHandleTable, lpMR, noObjs, lpClientData))
+ == 0)
+ {
+ GetEvent(lpMF,lpMR,TRUE);
+ break;
+ }
+ }
+
+ if (hdc && !ISMETADC(hdc))
+ {
+ SelectObject(hdc, hLPen);
+ SelectObject(hdc, hLBrush);
+ SelectObject(hdc, hLFont);
+ if (hRegion)
+ SelectObject(hdc, hRegion);
+ SelectPalette(hdc, hPalette, 0);
+ }
+
+ for(i = 0; i < lpMF->MetaFileHeader.mtNoObjects; ++i)
+ if (hObject = lpHandleTable->objectHandle[i])
+ DeleteObject(hObject);
+
+ if (hHandleTable)
+ {
+ GlobalUnlock(hHandleTable);
+ GlobalFree(hHandleTable);
+ }
+ABRRT2:;
+ GlobalUnfix(hMF);
+ }
+ return(bPrint);
+}
+#endif // this is going to gdi.dll
+
+/***************************** Internal Function **************************\
+* BOOL FAR PASCAL PlayIntoAMetafile
+*
+* if this record is being played into another metafile, simply record
+* it into that metafile, without hassling with a real playing.
+*
+* Returns: TRUE if record was played (copied) into another metafile
+* FALESE if destination DC was a real (non-meta) DC
+*
+* Effects: ?
+*
+* Warnings: ?
+*
+\***************************************************************************/
+
+BOOL INTERNAL PlayIntoAMetafile(LPMETARECORD lpMR, HDC hdcDest)
+{
+ GdiLogFunc3( " PlayIntoAMetafile");
+
+ if (!ISMETADC(hdcDest))
+ return(FALSE);
+ else
+ {
+ /* the size is the same minus 3 words for the record header */
+ RecordParms(hdcDest, lpMR->rdFunction, (DWORD)lpMR->rdSize - 3,
+ (LPWORD)&(lpMR->rdParm[0]));
+ return(TRUE);
+ }
+}
+
+BOOL INTERNAL IsDCValid(HDC hdc)
+{
+ NPMETARECORDER npdc;
+
+ hdc = (HDC)HANDLEFROMMETADC(hdc);
+
+ // Is the DC a valid Real DC
+ switch (GetObjectType(hdc))
+ {
+ case OBJ_DC:
+ case OBJ_METADC:
+ case OBJ_MEMDC:
+ return(TRUE);
+ break;
+ }
+
+ // Is the DC a GDI16 metafile DC
+ if (npdc = (NPMETARECORDER)LocalLock(hdc))
+ {
+ if( npdc->metaDCHeader.ident == ID_METADC )
+ return(TRUE);
+ }
+
+ ASSERTGDI(FALSE, "Invalid DC");
+ return(FALSE);
+}
+
+
+/***************************** Internal Function **************************\
+* IsMetaDC(hdc)
+*
+*
+* Returns TRUE iff hdc is a valid GDI16 Metafile
+*
+*
+\***************************************************************************/
+
+BOOL INTERNAL IsMetaDC(HDC hdc)
+{
+ NPMETARECORDER npdc;
+ BOOL fMeta = FALSE;
+
+ GdiLogFunc3(" IsMetaDC");
+
+ if( ((UINT)hdc) & METADCBIT )
+ if( npdc = (NPMETARECORDER)LocalLock( (HANDLE)HANDLEFROMMETADC(hdc)))
+ {
+ if( npdc->metaDCHeader.ident == ID_METADC )
+ fMeta = TRUE;
+
+ LocalUnlock( (HANDLE)HANDLEFROMMETADC(hdc) );
+ }
+
+ return( fMeta );
+}
+
+
+/***************************** Public Function ****************************\
+* HANDLE INTERNAL GetPMetaFile( HDC hdc )
+*
+* if hdc is a DC it is validated as a metafile
+* if hdc is a PALETTE the metafile the palette is selected into is returned
+*
+* Returns:
+* -1 iff Error
+* HANDLE to metafile if valid meta DC
+* 0 if valid object
+*
+* Effects:
+*
+* History:
+* 08-Jul-1991 -by- John Colleran [johnc]
+* Wrote it.
+\***************************************************************************/
+
+HANDLE INTERNAL GetPMetaFile( HDC hdc )
+{
+ NPMETARECORDER npMR;
+
+ GdiLogFunc3( " GetPMetaFile");
+
+
+ if( hdc & METADCBIT )
+ {
+ if( npMR = (NPMETARECORDER)LocalLock(HANDLEFROMMETADC(hdc)) )
+ {
+ if(npMR->metaDCHeader.ident == ID_METADC )
+ {
+ LocalUnlock(HANDLEFROMMETADC(hdc));
+ return( HANDLEFROMMETADC(hdc) );
+ }
+ LocalUnlock(HANDLEFROMMETADC(hdc));
+ }
+ }
+
+ // is hdc really a palette or object for the strange no-DC APIs
+ // Validate the object is real
+ if( (hdc != (HDC)NULL) && (GetObjectType( hdc ) == 0))
+ {
+ extern int iLogLevel; // Gdi.asm
+ // WinWord has a bug where it deletes valid objects so
+ // only log this error if the loglevel is high.
+ ASSERTGDI( (iLogLevel < 5), "GetPMetaFile: Invalid metafile or object")
+ return( -1 ); // Not a valid object
+ }
+ else
+ return( 0 ); // Valid Object
+}
+
+
+BOOL INTERNAL IsObjectStock(HANDLE hObj)
+{
+ int ii;
+
+ // handle Bitmaps and regions !!!!!
+
+ // Get all the Stock Objects
+ for( ii=WHITE_BRUSH; ii<=NULL_PEN; ii++ )
+ if( ahStockObject[ii] == hObj )
+ return( TRUE );
+
+ for( ii=OEM_FIXED_FONT; ii<=SYSTEM_FIXED_FONT; ii++ )
+ if( ahStockObject[ii] == hObj )
+ return( TRUE );
+
+ return( FALSE );
+}
+
+/***************************** Internal Function **************************\
+* GetObjectAndType
+*
+*
+* Returns the object type, eg OBJ_FONT, as well as a the LogObject
+*
+*
+\***************************************************************************/
+
+int INTERNAL GetObjectAndType(HANDLE hObj, LPSTR lpObjectBuf)
+{
+ int iObj = -1;
+
+ GdiLogFunc3( " GetObjectAndType" );
+
+ GetObject(hObj, MAXOBJECTSIZE, lpObjectBuf);
+ switch( iObj = (int)GetObjectType(hObj) )
+ {
+ case OBJ_PEN:
+ case OBJ_BITMAP:
+ case OBJ_BRUSH:
+ case OBJ_FONT:
+ break;
+
+ // Watch out for Palettes; returns the number of entries.
+ case OBJ_PALETTE:
+ GetPaletteEntries( hObj, 0, 1, (LPPALETTEENTRY)lpObjectBuf );
+ iObj = OBJ_PALETTE;
+ break;
+
+ case OBJ_RGN:
+ break;
+
+ default:
+ ASSERTGDIW( 0, "GetObject unknown object type: %d", iObj);
+ break;
+ }
+ return( iObj );
+}
+
+
+/***************************** Internal Function **************************\
+* BOOL GDIENTRY InitializeGdi
+*
+* Initializes the GDI16.exe
+*
+*
+* Effects:
+*
+* Returns: TRUE iff GDI was initilized successfully
+*
+\***************************************************************************/
+
+BOOL INTERNAL InitializeGdi(void)
+{
+BOOL status;
+int ii;
+
+ GdiLogFunc2 ( " InitializeGDI");
+ if( !(hScreenDC = CreateCompatibleDC(NULL)))
+ goto ExitInit;
+
+ // Get all the Stock Objects
+ for( ii=WHITE_BRUSH; ii<=NULL_PEN; ii++ )
+ ahStockObject[ii] = GetStockObject( ii );
+
+ for( ii=OEM_FIXED_FONT; ii<=SYSTEM_FIXED_FONT; ii++ )
+ ahStockObject[ii] = GetStockObject( ii );
+
+ // Create a fake Stock Region and Bitmap
+ ahStockObject[MYSTOCKRGN] = CreateRectRgn(1,1,3,3);
+ hStaticBitmap = ahStockObject[MYSTOCKBITMAP] = CreateBitmap(1,1,1,1,NULL);
+
+ status = TRUE;
+
+ ExitInit:
+ ASSERTGDI( status, "GDI16 Failed to initialized correctly");
+ return( status );
+}
+
+
+/***************************************************************************
+
+ debugging support
+
+***************************************************************************/
+
+#ifdef DEBUG
+
+void dDbgOut(int iLevel, LPSTR lpszFormat, ...)
+{
+ char buf[256];
+ char far *lpcLogLevel;
+ extern int iLogLevel; // Gdi.asm
+ extern int iBreakLevel; // Gdi.asm
+
+ // Get the external logging level from the emulated ROM
+
+ (LONG)lpcLogLevel = 0x00400042;
+ if (*lpcLogLevel >= '0' && *lpcLogLevel <= '9')
+ iLogLevel = (*lpcLogLevel-'0')*10+(*(lpcLogLevel+1)-'0');
+
+ if (iLevel<=iLogLevel)
+ {
+ OutputDebugString(" W16GDI:");
+ wvsprintf(buf, lpszFormat, (LPSTR)(&lpszFormat + 1));
+ OutputDebugString(buf);
+ OutputDebugString("\r\n");
+
+ if( iLevel<=iBreakLevel )
+ _asm int 3;
+ }
+}
+
+void dDbgAssert(LPSTR str, LPSTR file, int line)
+{
+ static char buf3[256];
+
+ wsprintf(buf3, "Assertion FAILED: %s %d : %s", file, line, str );
+ OutputDebugString(buf3);
+ OutputDebugString("\r\n");
+ _asm int 3;
+}
+
+
+
+#undef LocalLock
+#undef LocalUnlock
+#undef LocalAlloc
+#undef GlobalLock
+#undef GlobalUnlock
+#undef GlobalAlloc
+PSTR INTERNAL _LocalLock(HANDLE h )
+{
+PSTR p;
+dDbgOut(7, "LocalLock 0x%X", h );
+p = LocalLock(h);
+if( p == NULL )
+ _asm int 3
+return( p );
+}
+BOOL INTERNAL _LocalUnlock(HANDLE h )
+{
+dDbgOut(7, "LocalUnlock 0x%X", h );
+return( LocalUnlock(h) );
+}
+HANDLE INTERNAL _LocalAlloc(WORD w, WORD w2)
+{
+dDbgOut(7, "LocalAlloc");
+return( LocalAlloc(w,w2) );
+}
+LPSTR INTERNAL _GlobalLock(HANDLE h )
+{
+dDbgOut(7, "GlobalLock 0x%X", h );
+return( GlobalLock(h) );
+}
+BOOL INTERNAL _GlobalUnlock(HANDLE h )
+{
+dDbgOut(7, "GlobalUnlock 0x%X", h );
+return( GlobalUnlock(h) );
+}
+HANDLE INTERNAL _GlobalAlloc(WORD w, DWORD dw )
+{
+dDbgOut(7, "GlobalAlloc");
+return( GlobalAlloc(w,dw) );
+}
+
+
+
+#endif
diff --git a/private/mvdm/wow16/gdi/muldiv.asm b/private/mvdm/wow16/gdi/muldiv.asm
new file mode 100644
index 000000000..066fd0f8d
--- /dev/null
+++ b/private/mvdm/wow16/gdi/muldiv.asm
@@ -0,0 +1,110 @@
+ Title Muldiv - (A*B)/C With Correct Rounding
+ %out MulDiv
+ page ,132
+;----------------------------Module-Header------------------------------;
+; Module Name: muldiv.asm
+;
+; (w * Numer) / Denom with correct rounding.
+;
+; Created:
+; Author:
+;
+; Copyright (c) 1985, 1986, 1987 Microsoft Corporation
+;
+; MulDiv(w, Numer, Denom) returns (w * Numer) / Denom rounded to the nearest
+; integer. A check is made so that division by zero is not attempted.
+;-----------------------------------------------------------------------;
+
+
+ .xlist
+ include cmacros.inc
+; include gditype.inc
+ .list
+
+
+sBegin code
+assumes cs,code
+
+;--------------------------Public-Routine-------------------------------;
+; short FAR PASCAL MulDiv(short, short, short)
+; short w;
+; short Numer;
+; short Denom;
+;
+; (w * Numer)/ Denom with correct rounding.
+;
+; Returns: AX = result.
+; DX = 1 if no overflow.
+; DX = 0 if overflow.
+;
+; Preserves: BX,CX
+; Doesn't lose: SI,DI,ES,DS
+;
+; Warnings:
+;
+; Effects:
+;
+; History:
+; Mon 22-Dec-1986 17:08:55 -by- Kent Settle [kentse]
+; Added headers and comments.
+;-----------------------------------------------------------------------;
+
+cProc MulDiv,<FAR,PUBLIC>,<bx,cx>
+
+ parmW <w, Numer, Denom>
+
+cBegin MulDiv
+
+ mov bx,Denom ; get the demoninator
+ mov cx,bx ; CX holds the final sign
+ or bx,bx ; ensure the denominator is positive
+ jns md1
+ neg bx
+
+md1:
+ mov ax,w ; get the word we are multiplying
+ xor cx,ax ; make CX reflect any sign change
+ or ax,ax ; ensure this word is positive
+ jns md2
+ neg ax
+
+md2:
+ mov dx,Numer ; get the numerator
+ xor cx,dx ; make CX reflect any sign change
+ or dx,dx ; ensure the numerator is positive
+ jns md3
+ neg dx
+
+md3:
+ mul dx ; multiply
+ mov cl,bl ; get half of the demoninator to adjust for rounding
+ sar bx,1
+ add ax,bx ; adjust for possible rounding error
+ adc dx,0 ; this is really a long addition
+ sal bx,1 ; restore the demoninator
+ or bl,cl
+ cmp dx,bx ; check for overflow
+ jae md5 ; (ae handles /0 case)
+ div bx ; divide
+ or ax,ax ; If sign is set, then overflow occured
+ js md5 ; Overflow.
+ or cx,cx ; put the sign on the result
+ jns md4
+ neg ax
+md4:
+ mov dx,1 ; indicate no overflow.
+md6:
+
+cEnd MulDiv
+
+
+md5:
+ xor dx,dx ; indicate overflow.
+ mov ax,7FFFh ; return the largest integer
+ or cx,cx ; with the correct sign
+ jns md6
+ not ax
+ jmp md6
+
+sEnd code
+end
diff --git a/private/mvdm/wow16/gdi/sort.asm b/private/mvdm/wow16/gdi/sort.asm
new file mode 100644
index 000000000..bf072ad03
--- /dev/null
+++ b/private/mvdm/wow16/gdi/sort.asm
@@ -0,0 +1,706 @@
+;----------------------M O D U L E H E A D E R----------------------------;
+; ;
+; Module Name: SORT.ASM ;
+; ;
+; History: SORT.C ;
+; Created by Charles Whitmer 12/30/1986 ;
+; Modified by Mitchel B. London 08/05/1987 ;
+; ;
+; SORT.ASM - translation of SORT.C ;
+; CreateModule David Weise ;
+; Other Modules Amit Chatterjee 08/09/1988 ;
+; ;
+; Copyright (c) 1985 - 1988 Microsoft Corporation ;
+; ;
+; General Description: ;
+; ;
+; The SORT module creates and maintains a tree of nodes, each node ;
+; having a KEY value and a TAG field. The KEY field is used to or- ;
+; -ganize the tree into a heap. ;
+; The heap tree is implemented using an array, where if ;
+; parent node occurs in position i, its left child will be at index ;
+; (2 * i) and the right chaild at index (2 * i + 1). ;
+; The Module ensures that at any instant, the root node ;
+; of any subtree has the least key value in the subtree. ;
+; First few positions in the array are used for storing ;
+; a header for the tree. ;
+; ;
+; SubModules: ;
+; ;
+; 1. CreatePQ: ;
+; Allocates space for the heaptree and its header ;
+; and initializes the header. ;
+; 2. InsertPQ: ;
+; Inserts a node into the heap ensuring that the heap ;
+; property is not violated. ;
+; 3. MinPQ: ;
+; Returns the tag value associated with the lowest ;
+; key in the heap. (node is not deleted) ;
+; 4. ExtractPQ: ;
+; Return the tag value associated with the lowest key ;
+; in the heap and deletes the node. The heap is then ;
+; reconstructed with the remaining nodes. ;
+; 5. DeletePQ: ;
+; Deletes the entire heap by freeing the allocated ;
+; area. ;
+; 6. SizePQ: ;
+; Increases the size of the heap by adding space ;
+; for a requested number of entries ;
+; Heap Data Structure: ;
+; ;
+; The heap data structure has two parts, a header and a set of nodes and ;
+; these are blocked one after the other. ;
+; The header maintains: ;
+; (i) A pointer to the next available node slot ;
+; relative to start of the node area ;
+; (ii) A pointer to the first valid node slot ;
+; node slots between the header and this pointer ;
+; are actually deleted nodes ;
+; (iii) A pointer past the last allocated node slot ;
+; (iv) A last key value, which either holds the largest;
+; key value as long as the nodes are sequentially ;
+; ordered, or a very large value to indicate there;
+; is no sequential ordering ;
+; ;
+; ---------------- ;
+; | INDEX | ---- Pointer to next available node slot ;
+; ---------------- ;
+; | MAXENTRY | ---- Pointer past last allocated node slot ;
+; ---------------- ;
+; START | LASTKEY | ---- Aslong as possible holds max key ;
+; NODE | START | ---- pointer to first active node slot ;
+; ---------------- ;
+; | KEY | ---- Node 1. ;
+; | TAG | ;
+; //---------------// ;
+; | KEY | ---- Last allocated node slot ;
+; | TAG | ;
+; ---------------- ;
+; ;
+; All pointers to nodes are relative to node 1 (pointer to node 1 is ZERO) ;
+;----------------------------------------------------------------------------;
+;----------------------------------------------------------------------------;
+; Include File Section and definitions: ;
+; ;
+
+ .xlist
+ include cmacros.inc
+ include gdimacro.inc
+ include gdimem.inc
+ .286p
+ .list
+
+START equ SIZE PQ - SIZE ENTRY ; The header includes Node 0
+
+VERYLARGE equ 4000h ; assumed to be larger than any key
+PQERROR equ -1 ; return value on error
+TRUE equ 1
+FALSE equ 0
+
+Entry struc
+ e_key dw ? ; key value of node
+ e_tag dw ? ; corresponding tag value
+Entry ends
+
+PQ struc ; HEAP Header Structure + Start Node
+ pq_index dw ?
+ pq_maxentry dw ? ; excludes START NODE
+ pq_lastkey dw ?
+ pq_start dw ?
+PQ ends
+
+
+ externFP GlobalLock
+ externFP GlobalUnlock
+ externFP GlobalReAlloc
+ externFP GlobalFree
+ externFP GlobalAlloc ; Defined in HELPER.ASM
+
+createSeg _SORT,SORT,byte,public,CODE
+sBegin SORT
+
+;-----------------------------------------------------------------------------;
+; ;
+;CreatePQ: ;
+; Inputs: ;
+; Max Number of entries the tree will hold ;
+; Outputs: ;
+; HANDLE to Heap -- if creation successful ;
+; PQERROR if failure ;
+; Registers Preserved: ;
+; DI,SI ;
+; ;
+; -by- David Weise [davidw] ;
+; ;
+;-----------------------------------------------------------------------------;
+
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc farGDIGlobalAlloc,<FAR,PUBLIC>
+
+ parmd amount
+cBegin
+ cCall GlobalAlloc,<GMEM_MOVEABLE+GMEM_SHARE,amount>
+cEnd
+
+cProc CreatePQ,<FAR,PUBLIC,NODATA>,<di,si>
+ parmW cEntries
+
+cBegin
+ mov ax,cEntries ; max no of nodes the tree will hold
+ shl ax,1
+ shl ax,1 ; ax <---- ax * SIZE ENTRY
+ .errnz (SIZE ENTRY - 4)
+ mov si,ax ; save number of bytes in node array
+ add ax, SIZE PQ ; size of header including NODE 0
+ xor dx,dx
+ cCall farGDIGlobalAlloc,<dx,ax>
+ mov bx,ax ; Handle returned
+ dec ax ; set to -1 if handle returned == 0
+ .errnz (-1 - PQERROR)
+ or bx,bx ; test for succesfull memory allocation
+ jz cPQ_Done ; error return.
+ push bx
+ cCall GlobalLock,<bx> ; lock handle get back segment
+ pop bx
+ mov es,dx
+ mov di,ax ; es:di points to start of structure
+
+; now initialize the header part of the structure with values
+; si has size of the node array
+
+ stosw ; index set to zero
+ .errnz (0 - pq_index)
+ mov ax,si ; pointer past end of node array
+ stosw ; max no of entries
+ .errnz (2 - pq_maxentry)
+ xor ax,ax ; last key = 0, as heap empty
+ stosw
+ .errnz (4 - pq_lastkey)
+ stosw ; START = 0, implies no deleted slot
+ .errnz (6 - pq_start)
+
+ push bx
+ cCall GlobalUnlock,<bx> ; unlock the handle to heap
+ pop ax ; return the handle
+
+cPQ_Done:
+
+cEnd
+
+;-----------------------------------------------------------------------------;
+; ;
+; InsertPQ: ;
+; Inputs: ;
+; hPQ -- handle to heap structure segment ;
+; tag -- tag value for new node ;
+; key -- key value for new node ;
+; Outputs: ;
+; return TRUE if insertion was successful ;
+; return PQERROR if heap was already packed ;
+; Preserves: ;
+; DS,SI ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 10:45:25 ;
+;-----------------------------------------------------------------------------
+
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc InsertPQ,<FAR,PUBLIC,NODATA>,<di,si>
+ parmW hPQ
+ parmW tag
+ parmW key
+
+cBegin
+ mov di,hPQ
+ cCall GlobalLock,<di> ; lock heap and get back segment addres
+ or ax,dx ; Invalid handle causes zero return
+ jz Ins_Cant_Proceed
+ mov es,dx
+ xor si,si ; offset in segment always zero
+ mov ax,es:[si] ; pointer to next available slot
+ sub ax,es:[si].pq_start ; convert it relative to 1st active node
+ cmp ax,es:[si].pq_maxentry ; compare with pointer past last slot
+ jb Insertion_Possible
+ cCall GlobalUnlock,<di>
+Ins_Cant_Proceed:
+ mov ax,PQERROR ; error return
+ jmp cInsert_Done
+
+Insertion_Possible:
+ push es ; HEAP structure segment
+ smov es,ds ; save local segment in es
+ pop ds ; change DS to heap segment
+ mov ax,[si].pq_index ; next available slot in node area
+ cmp ax,[si].pq_maxentry
+ jb Enough_Space_Atend ; insertion possible w/o compaction
+
+; Deleted nodes exist near the head of the tree, compaction necessary
+ call CompactList ; removes all deleted elements
+
+; LASTKEY still holds the max key value in the tree
+
+Enough_Space_Atend:
+ mov bx,[si].pq_index ; pointer to next available slot
+ mov dx,bx ; save value in register
+ add bx,SIZE PQ ; area for header
+ mov ax,tag
+ mov [si][bx].e_tag,ax ; insert new tag and key
+ mov ax,key
+ mov [si][bx].e_key,ax ; key in ax will be used below
+ mov bx,dx ; bx points to last occupied slot
+ add dx,SIZE ENTRY ; available slot points to next node
+ mov [si].pq_index,dx ; save in the structure
+
+; Now test whether the heap property is valid still.
+; ax has key, dx has pointer to next slot after addition
+; bx points to last valid node
+
+ cmp ax,[si].pq_lastkey ; compare with new key
+ jb Heap_Violated
+ mov [si].pq_lastkey,ax ; new key is the largest key in tree
+ jmp short Heap_Restructured ; Insertion over
+
+comment ~
+
+ node i has lchild at 2*i and rchild at 2*i+1. But we maintain their
+ address relative to start of node array. [ie node 1 has addr 0,
+ node 2 has 4, node 3 12 and so on.]
+ so if x happens to be the address of a node, the address of its
+ parent is (x/2 -2) AND 0fffch.
+ if x is the address of a parent, the address of its lchild is 2*x + 4
+ and that of its rchild is 2*x + 8
+
+end comment ~
+
+Heap_Violated:
+ call CompactList ; make sure heap is compacted first!
+ mov [si].pq_lastkey,VERYLARGE ; to imply heap nolonger seq. ordered
+ mov bx,[si].pq_index ; bx = offset of inserted elem.
+ sub bx,SIZE ENTRY
+
+Heap_Walk_Loop:
+ cmp bx,[si].pq_start ; traversed to top of heap ?
+ jz Heap_Restructured
+ mov cx,bx
+ shr cx,1 ; cx points to parent of current node
+ dec cx
+ dec cx
+ and cx,0fffch ; refer to comment above
+ .errnz (SIZE ENTRY - 4)
+
+; Test whether current node has to move up or not, if not it resets carry
+; else it swaps the two nodes and sets carry
+
+ call TestShuffle
+ mov bx,cx ; next node to inspect ifnec. is parent
+ jc Heap_Walk_Loop
+
+Heap_Restructured:
+ smov ds,es ; get back own segment in ds
+ cCall GlobalUnlock,<di> ; di still has the handle
+ mov ax,di ; return true
+
+cInsert_Done:
+cEnd
+
+
+;-----------------------------------------------------------------------------;
+; TestShuffle: ;
+; ;
+; Takes as input the node addresses of a parent and on of it's childs. If the;
+; key of the parent is >= key of the child, it returns with carry clear, else;
+; it swaps the two nodes and returns with carry set. ;
+; ;
+; bx has current node address in HEAP, relative to start NODE 1 ;
+; cx has address of parent node of bx ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 12:00:00 ;
+;-----------------------------------------------------------------------------;
+
+cProc TestShuffle,<NEAR,PUBLIC>,<si,di>
+
+cBegin
+ lea di,[si][SIZE PQ] ; di points to node 1
+ add di,cx ; di points to parent
+ lea si,[bx].SIZE PQ ; si points to child node
+ mov ax,[si].e_key ; childs key
+ cmp ax,[di].e_key ; key of parent
+ jb Nodes_Tobe_Swapped
+;
+; Carry cleared by comparision, use for return
+;
+ jmp short TestShuffle_Ret
+
+Nodes_Tobe_Swapped:
+;
+; Carry has been set by comparision, use for return
+;
+ xchg ax,[di].e_key
+ mov [si].e_key,ax
+ mov ax,[si].e_tag
+ xchg ax,[di].e_tag
+ mov [si].e_tag,ax ; swap complete
+TestShuffle_Ret:
+
+cEnd
+
+;-----------------------------------------------------------------------------;
+; MinPQ: ;
+; Inputs: ;
+; hPQ -- Handle to the heap structure ;
+; Outputs: ;
+; minimum tag value in the tree or PQERROR(if invalid handle) ;
+; ;
+; Calls Local Procedure GetMinPQ. ;
+; GetMinPQ takes the handle and a flag as parameter. ;
+; If the flag is TRUE, the node with the least key is deleted ;
+; GetMinPQ also returns the tag value of least key in AX ;
+; ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 12:46:10 ;
+;-----------------------------------------------------------------------------;
+
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc MinPQ,<FAR,PUBLIC,NODATA>
+; parmW hPQ
+
+cBegin nogen
+
+ mov cl,FALSE ; to imply node not to be deleted
+ jmpnext ; fall through trick, refer cmacros
+
+cEnd nogen
+
+;-----------------------------------------------------------------------------;
+; ExtractPQ: ;
+; Inputs: ;
+; hPQ -- Handle to the heap structure ;
+; Outputs: ;
+; minimum tag value if heap handle is valid and heap not empty ;
+; return PQERROR otherwise ;
+; The node with min key is deleted ;
+; Calls Local Procedure GetMinPQ ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 12:54:00 ;
+;-----------------------------------------------------------------------------;
+
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc ExtractPQ,<FAR,PUBLIC,NODATA>
+; parmW hPQ
+
+
+cBegin nogen
+
+ mov cl,TRUE ; to imply that node to be deleted
+ jmpnext stop ; fall through trick, refer cmacros
+
+cEnd nogen
+
+;-----------------------------------------------------------------------------;
+; GetMinPQ: ;
+; ;
+; One of the inputs is a flag. If the flag is FALSE it simply returns the tag ;
+; associated with the lease key value in the heap. If the flag is TRUE besides;
+; returnning the above tag value it also deletes the node. ;
+; ;
+; ;
+; hPQ --- handle of HEAP segment ;
+; cl --- Deletion Flag ( Delete node if TRUE) ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 13:00:00 ;
+;-----------------------------------------------------------------------------;
+
+cProc GetMinPQ,<FAR,PUBLIC,NODATA>,<di,si>
+ parmW hPQ
+cBegin
+ mov di,hPQ
+ push cx ; save flag
+ cCall GlobalLock,<di>
+ pop cx ; get back flag into cl
+ or dx,ax ; invalid handle implies zero return
+ jz Min_Cant_Proceed
+ mov es,dx
+ mov si,ax ; ds:si points to heap start
+ mov bx,es:[si].pq_start ; pointer to 1st. available slot
+ cmp bx,es:[si].pq_index ; empty if equal to next available node
+ jb Heap_Not_Empty
+ cCall GlobalUnlock,<di>
+
+Min_Cant_Proceed:
+ mov ax,PQERROR
+ jmp cGetMin_Done ; error return
+
+; bx still has [si].pq_start
+
+Heap_Not_Empty:
+ push es ; save heap segment
+ smov es,ds ; save local segment is es
+ pop ds ; ds:si points to start of heap
+ lea dx,[si][SIZE PQ]
+ add dx,bx ; points past deleted nodes
+ xchg di,dx ; save di in dx and use dx's value
+ mov ax,[di].e_tag ; get the tag associated with least key
+ xchg di,dx ; get back values
+ or cl,cl ; test for bl = FALSE
+ .errnz (0 - FALSE)
+ jnz Delete_Node ; TRUE implies get tag and delete node
+ jmp cGetMin_Ret ; return after unlocking heap
+
+Delete_Node:
+
+; bx retains [si].start
+
+ add bx,SIZE ENTRY ; one more node deleted
+ cmp bx,[si].pq_index ; is tree empty ?
+ jb Tree_Not_Empty
+ xor cx,cx
+ mov [si].pq_lastkey,cx ; initialize for empty tree
+ mov [si].pq_start,cx ; initialize for empty tree
+ mov [si].pq_index,cx
+ jmp cGetMin_Ret ; return after unlocking heap
+
+Tree_Not_Empty:
+
+; ax has return tag value
+; bx has [si].pq_start + SIZE ENTRY
+
+ cmp [si].pq_lastkey,VERYLARGE ; implies keys in random order
+ jae Min_Restructure_Heap ; maybe restructuring necessary
+ mov [si].pq_start,bx ; updates past deleted entry
+ jmp cGetMin_Ret
+
+Min_Restructure_Heap:
+
+; dx still has offset to NODE 1, because
+; if LASTKEY = VERYLARGE, pq_start has to be zero
+
+ push ax ; save return tag value
+ mov bx,dx ; offset to first active node
+ xchg di,dx ; get pointer into di ,save di
+ add di,[si].pq_index ; dx points to next available slot
+ sub di,SIZE ENTRY ; point to last filled node
+ mov ax,di ; last node being moved upfront
+ sub ax,SIZE PQ ; point ax one node ahead of last
+ mov [si].pq_index,ax ; update it
+ mov cx,[di].e_key
+ mov [bx].e_key,cx ; move from last position to NODE 1
+ mov cx,[di].e_tag
+ mov [bx].e_tag,cx
+ xchg di,dx ; restore di,dx
+ xor cx,cx ; start traversing heap from root
+
+
+Min_Traverse_Heap:
+ mov bx,cx
+ shl bx,1
+ add bx,SIZE ENTRY ; bx has left child addr of parent in cx
+ cmp bx,[si].pq_index ; compare with next available slot
+ jae Min_Heap_Fixed ; heap restored
+ push cx ; save current parent
+ mov cx,bx ; have lchild in cx
+ add cx,SIZE ENTRY ; cx now get address of rchild
+ cmp cx,[si].pq_index ; test against last node
+ jae Right_Child_Not_Present
+ call GetLesserChild ; gets child with lesser key in bx
+
+Right_Child_Not_Present:
+ pop cx ; get back parent
+;
+; cx has node number of parent node and bx has node no of child node with
+; least key. If parents key value is greater it should be swapped
+;
+ call TestShuffle
+
+; swaps the two nodes if necessary.
+
+ mov cx,bx ; lesser child is next parent
+ jmp Min_Traverse_Heap
+
+Min_Heap_Fixed:
+ pop ax ; get back return tag value
+cGetMin_Ret:
+ push ax ; save return value
+ smov ds,es ; get back own ds
+ cCall GlobalUnlock,<di> ; unlock heap
+ pop ax ; get back return value
+cGetMin_Done:
+
+cEnd
+
+;-----------------------------------------------------------------------------;
+; GetLesserChild: ;
+; ;
+; Given two child node numbers, it returns the child which has a lesser key ;
+; ;
+; cx has RCHILD NODE address ;
+; bx has LCHILD NODE address ;
+; si points to start of heap ;
+; will return node address of lesser child in bx ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 13:50 ;
+;-----------------------------------------------------------------------------;
+
+
+cProc GetLesserChild,<NEAR,PUBLIC,NODATA>,<di,si>
+
+cBegin
+ lea di,[si][SIZE PQ] ; dx now points to NODE 1
+ mov si,di ; si also points to start of NODE 1
+ add di,cx ; di get address of rchild
+ mov ax,[si+bx].e_key ; rchilds key
+ cmp ax,[di].e_key ; compare with rchild
+ jb Right_Child_Lesser ; bx still has the correct child no.
+ mov bx,cx ; get RCHILD address into bx
+Right_Child_Lesser:
+
+cEnd
+;
+;-----------------------------------------------------------------------------;
+; DeletePQ: ;
+; Inputs: ;
+; hPQ --- handle to a heap structure ;
+; OutPuts: nothing ;
+; Preserves: DI ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 14:15:45 ;
+;-----------------------------------------------------------------------------
+;
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc DeletePQ,<FAR,PUBLIC,NODATA>
+ parmW hPQ
+
+cBegin
+ cCall GlobalFree,<hPQ> ; free the handle
+cEnd
+
+;-----------------------------------------------------------------------------;
+;SizePQ: ;
+; Input: ;
+; hPQ --- Handle to a heap structure ;
+; entry --- number of nodes by which heap is to be expanded ;
+; Output: ;
+; Returns the total number of node slots in new heap, if successful
+; else return PQERROR ;
+; ;
+; -by- Amit Chatterjee [amitc] Tue Aug 9 14:31:40 ;
+;-----------------------------------------------------------------------------
+
+ assumes cs,SORT
+ assumes ds,nothing
+
+cProc SizePQ,<FAR,PUBLIC,NODATA>,<si,di>
+ parmW hPQ
+ parmW cEntry
+
+cBegin
+ mov di,hPQ
+ cCall GlobalLock,<di> ; lock to get back segment address
+ or ax,dx ; Invalid handle implies NULL return
+ jz Siz_Cant_Proceed
+ mov es,dx
+ xor si,si ; offset will always be zro
+ mov ax,cEntry ; additional nodes
+ or ax,ax ; if zero return original numof nodes
+ jnz Size_Tobe_Increased
+ mov ax,es:[si].pq_maxentry ; offset past last node
+ shr ax,1
+ shr ax,1 ; ax <--- ax / SIZE ENTRY
+ .errnz (SIZE ENTRY - 4)
+ jmp short cSize_Ret ; return after unlocking handle
+
+Size_Tobe_Increased:
+ shl ax,1
+ shl ax,1 ; ax <-- ax * SIZE ENTRY, = extra bytes
+ .errnz (SIZE ENTRY - 4)
+ add ax,es:[si].pq_maxentry ; number of byte for new node array
+ cmp ax,es:[si].pq_index ; next available slot
+ jae Valid_Increase
+ mov ax,PQERROR ; error code
+ jmp short cSize_Ret ; return after releasing handle
+
+Valid_Increase:
+ push ax ; save number of bytes in node block
+ add ax,SIZE PQ ; size of header
+ push ax
+ cCall GlobalUnlock,<di> ; unlock handle
+ xor dx,dx ; high word for size
+ pop ax ; get back size
+ cCall GlobalReAlloc,<di,dx,ax,GMEM_MOVEABLE>
+ or ax,ax
+ jz Siz_Cant_Proceed
+ mov di,ax ; new handle
+ cCall GlobalLock,<ax> ; lock it
+ mov es,dx ; set new segment
+ pop cx ; get back total no of nodes into cx
+ jmp short Reloc_Successful
+Siz_Cant_Proceed:
+ pop cx ; balance stack
+ dec ax
+ .errnz (-1 - PQERROR)
+ jmp short cSize_End
+
+Reloc_Successful:
+ mov es:[si].pq_maxentry,cx ; total number of slots now
+ shr cx,1
+ shr cx,1 ; no of nodes = bytes / SIZE ENTRY
+ .errnz (SIZE ENTRY - 4)
+ mov ax,cx ; return value
+cSize_Ret:
+ cCall GlobalUnlock,<di>
+cSize_End:
+
+cEnd
+
+;-----------------------------------------------------------------------------;
+;CompactList: ;
+; Input: ;
+; ds:si --- pointer to heap structure ;
+; Output: ;
+; all deleted elements are removed from heap structure ;
+; Registers trashed:
+; AX,BX,CX,DX
+;
+; -by- Ken Sykes [kensy] Tue Nov 12 1991 10:20:00am ;
+;-----------------------------------------------------------------------------
+
+CompactList proc near
+ mov ax,[si].pq_index ; next available slot in node area
+ sub ax,[si].pq_start ; ax had pointer to available slot
+ mov [si].pq_index,ax ; next available slot will come up
+ lea dx,[si][SIZE PQ] ; points to NODE 1
+ mov ax,[si].pq_start ; pointer to 1st active node rel to 1
+ add ax,dx ; ax has offset to first valid node.
+ mov bx,ax
+ mov cx,[si].pq_maxentry ; pointer past end of node slots
+ sub cx,[si].pq_start ; pointer to strt of active block
+ shr cx,1 ; will do a REP MOVSW
+ .errnz (1 and SIZE ENTRY)
+ push es ; es has local segment
+ smov es,ds ; moth es ds point to heap segment
+ push si
+ push di ; save start to heap and its handle
+ mov si,bx ; si points to start of valid nodes
+ mov di,dx ; dx points to node 1
+ cld
+ rep movsw ; Compacted
+ pop di
+ pop si
+ pop es ; restore local segment in es
+ mov [si].pq_start,cx ; after compaction deleted nodes = 0
+ ret
+CompactList endp
+
+;-----------------------------------------------------------------------------;
+
+sEnd SORT
+
+end
diff --git a/private/mvdm/wow16/inc/cderr.h b/private/mvdm/wow16/inc/cderr.h
new file mode 100644
index 000000000..402ac0956
--- /dev/null
+++ b/private/mvdm/wow16/inc/cderr.h
@@ -0,0 +1,58 @@
+/*****************************************************************************\
+* *
+* cderr.h - Common dialog error return codes *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_CDERR
+#define _INC_CDERR
+
+#define CDERR_DIALOGFAILURE 0xFFFF
+
+#define CDERR_GENERALCODES 0x0000
+#define CDERR_STRUCTSIZE 0x0001
+#define CDERR_INITIALIZATION 0x0002
+#define CDERR_NOTEMPLATE 0x0003
+#define CDERR_NOHINSTANCE 0x0004
+#define CDERR_LOADSTRFAILURE 0x0005
+#define CDERR_FINDRESFAILURE 0x0006
+#define CDERR_LOADRESFAILURE 0x0007
+#define CDERR_LOCKRESFAILURE 0x0008
+#define CDERR_MEMALLOCFAILURE 0x0009
+#define CDERR_MEMLOCKFAILURE 0x000A
+#define CDERR_NOHOOK 0x000B
+#define CDERR_REGISTERMSGFAIL 0x000C
+
+#define PDERR_PRINTERCODES 0x1000
+#define PDERR_SETUPFAILURE 0x1001
+#define PDERR_PARSEFAILURE 0x1002
+#define PDERR_RETDEFFAILURE 0x1003
+#define PDERR_LOADDRVFAILURE 0x1004
+#define PDERR_GETDEVMODEFAIL 0x1005
+#define PDERR_INITFAILURE 0x1006
+#define PDERR_NODEVICES 0x1007
+#define PDERR_NODEFAULTPRN 0x1008
+#define PDERR_DNDMMISMATCH 0x1009
+#define PDERR_CREATEICFAILURE 0x100A
+#define PDERR_PRINTERNOTFOUND 0x100B
+#define PDERR_DEFAULTDIFFERENT 0x100C
+
+#define CFERR_CHOOSEFONTCODES 0x2000
+#define CFERR_NOFONTS 0x2001
+#define CFERR_MAXLESSTHANMIN 0x2002
+
+#define FNERR_FILENAMECODES 0x3000
+#define FNERR_SUBCLASSFAILURE 0x3001
+#define FNERR_INVALIDFILENAME 0x3002
+#define FNERR_BUFFERTOOSMALL 0x3003
+
+#define FRERR_FINDREPLACECODES 0x4000
+#define FRERR_BUFFERLENGTHZERO 0x4001
+
+#define CCERR_CHOOSECOLORCODES 0x5000
+
+#endif /* !_INC_CDERR */
diff --git a/private/mvdm/wow16/inc/cmacros.inc b/private/mvdm/wow16/inc/cmacros.inc
new file mode 100644
index 000000000..427ad4a86
--- /dev/null
+++ b/private/mvdm/wow16/inc/cmacros.inc
@@ -0,0 +1,1413 @@
+comment $
+cmacros - assembly macros for interfacing to hlls
+(C)Copyright Microsoft Corp. 1984-1988
+$
+.xcref
+.xcref ??_out
+ifndef ?QUIET
+?QUIET equ 1
+endif
+??_out macro t
+ifndef ?QUIET
+%out t
+endif
+endm
+outif macro name,defval,onmsg,offmsg
+ifndef name
+ifb <defval>
+name=0
+else
+name=defval
+endif
+endif
+if name
+name=1
+ifnb <onmsg>
+??_out <! onmsg>
+endif
+else
+ifnb <offmsg>
+??_out <! offmsg>
+endif
+endif
+endm
+.xcref ??error
+??error macro msg
+e r r o r ----- msg
+.err
+endm
+.xcref ASMpass
+.xcref memS,memM,memL,memC,memH,memMOD,sizec,sized
+if1
+ASMpass=1
+ifdef ?SMALL
+memS=1
+endif
+ifdef ?MEDIUM
+memM=1
+endif
+ifdef ?COMPACT
+memC=1
+endif
+ifdef ?LARGE
+memL=1
+endif
+ifdef ?HUGE
+memH=1
+endif
+??_out <cMacros Version 5.20 - Copyright (c) Microsoft Corp. 1984-1988>
+outif memS,0,<Small model>
+outif memM,0,<Medium model>
+outif memL,0,<Large model>
+outif memC,0,<Compact model>
+outif memH,0,<Huge model>
+memMOD= memS + memM + memL + memC + memH
+if memMOD ne 1
+if memMOD eq 0
+memS = 1
+else
+??error <more than 1 memory model selected>
+endif
+endif
+sizec= memM + memL + memH
+sized= memL + memC + (memH*2)
+outif ?DF,0,<No segments or groups will be defined>
+outif ?TF,0,<Epilog sequences assume valid SP>
+outif ?WIN,1,<Windows support>
+ifdef PMODE
+?pmd=1
+??_out <! 286 protect mode>
+else
+?pmd=0
+endif
+ifdef ?386regs
+if ?386regs
+??_out <! 386 registers enabled>
+endif
+else
+?386regs=0
+endif
+if ?WIN eq 1
+outif ?PLM,1,<>
+else
+outif ?PLM,1,<Pascal calling convention>
+endif
+ifndef ?NODATA
+?nodata1=0
+else
+?nodata1=1
+??_out <! NODATA module>
+endif
+ifndef ?CHKSTK
+?chkstk1=0
+else
+?chkstk1=1
+ifdef ?CHKSTKPROC
+??_out <! Private stack checking enabled>
+else
+??_out <! Stack checking enabled>
+endif
+endif
+ifndef DOS5
+?DOS5=0
+else
+?DOS5=1
+??_out <! DOS5 module>
+endif
+ifdef ?PROFILE
+??_out <! Native profiling enabled>
+endif
+else
+ASMpass=2
+endif
+ifdef ?pmd
+.286p
+endif
+if ?386regs
+.xcref ?n,?ax,?eax,?bx,?ebx
+.xcref ?cx,?ecx,?dx,?edx
+.xcref ?si,?esi,?di,?edi,?es,?ds,?fs
+.xcref ?gs
+else
+.xcref ?n,?ax,?ah,?al,?bx,?bh
+.xcref ?bl,?cx,?ch,?cl,?dx,?dh
+.xcref ?dl,?si,?di,?es,?ds,?bp
+.xcref ?sp,?ss,?cs
+endif
+.xcref ?rsl,?cpd,?argl,?argc,?ba
+.xcref ?acb,???,?po
+.xcref ?pas,?pc
+.xcref uconcat,mpush,mpop
+.xcref ?ri,?pp,?pp1,?al1
+.xcref ?ad,?ap,?atal,?dd,?dd1,?dd2
+.xcref ?pg,?pg1,?aloc,?cs1,?cs2
+.xcref ?DF,?TF,?ff,?PLM,?WIN,?ia,?pu,?adj
+.xcref ?uf,?rp,?nx,?nd,?nodata1,?chkstk1,?DOS5,?pmd,?lds,?exp
+.xcref ?wfp,arg,cCall,cProc,assumes,?cs3,?cs2,?cs1
+.xcref defgrp,addseg,createSeg
+.xcref save,outif,errnz,errn$,errnz1
+.xcref ?PLMPrevParm,?gcc
+.xcref ?cCall1,?pcc
+?rsl = 0
+?cpd = 0
+?argl = 0
+?argc = 0
+?ba = 0
+?acb = 0
+??? = 0
+?po = 0
+?pas = 0
+?pc = 0
+?ia = 0
+?pu = 0
+?adj = 0
+?rp = 0
+?uf = 0
+?nd = 0
+?nx = 0
+?wfp = 0
+?lds = 0
+?exp = 0
+?ff = 0
+?dd2 = 0
+?cCall1 = 0
+?pcc = 0
+?PLMPrevParm = 0
+.xcref ?casen
+if1
+?casen = 0
+endif
+if ?386regs
+?n = 0000000000000000b
+?ax = 0000000000000001b
+?eax = 0000000000000010b
+?bx = 0000000000000100b
+?ebx = 0000000000001000b
+?cx = 0000000000010000b
+?ecx = 0000000000100000b
+?dx = 0000000001000000b
+?edx = 0000000010000000b
+?si = 0000000100000000b
+?esi = 0000001000000000b
+?di = 0000010000000000b
+?edi = 0000100000000000b
+?ds = 0001000000000000b
+?es = 0010000000000000b
+?fs = 0100000000000000b
+?gs = 1000000000000000b
+else
+?n = 0000000000000000b
+?ax = 0000000000000011b
+?ah = 0000000000000001b
+?al = 0000000000000010b
+?bx = 0000000000001100b
+?bh = 0000000000000100b
+?bl = 0000000000001000b
+?cx = 0000000000110000b
+?ch = 0000000000010000b
+?cl = 0000000000100000b
+?dx = 0000000011000000b
+?dh = 0000000001000000b
+?dl = 0000000010000000b
+?si = 0000000100000000b
+?di = 0000001000000000b
+?es = 0000010000000000b
+?ds = 0000100000000000b
+?bp = 0001000000000000b
+?sp = 0010000000000000b
+?ss = 0100000000000000b
+?cs = 1000000000000000b
+endif
+.cref
+uconcat macro a,b,c,d,e,f,g
+a&b c&d e&f&g
+endm
+if ?386regs
+mpush macro r
+irp x,<ax,eax,bx,ebx,cx,ecx,dx,edx,si,esi,di,edi,ds,es,fs,gs>
+if (r and ?&&x)
+ push x
+endif
+endm
+endm
+else
+mpush macro r
+irp x,<ax,bx,cx,dx,si,di,es,ds,bp,sp,ss,cs>
+if (r and ?&&x)
+ push x
+endif
+endm
+endm
+endif
+if ?386regs
+mpop macro r
+irp x,<gs,fs,es,ds,edi,di,esi,si,edx,dx,ecx,cx,ebx,bx,eax,ax>
+if (r and ?&&x)
+ pop x
+endif
+endm
+endm
+else
+mpop macro r
+irp x,<cs,ss,sp,bp,ds,es,di,si,dx,cx,bx,ax>
+if (r and ?&&x)
+ pop x
+endif
+endm
+endm
+endif
+save macro r
+?rsl=0
+?ri ?rsl,<r>
+endm
+?ri macro n,r
+irp x,<r>
+.ERRNDEF ?&&x
+n=n or ?&&x
+endm
+endm
+.xcref
+.xcref parmB,parmW,parmD,parmQ,parmT,parmCP,parmDP
+.cref
+parmB macro n
+?pp <n>,<byte>,2,1
+endm
+parmW macro n
+?pp <n>,<word>,2,2
+endm
+parmD macro n
+ife ?PLM
+irp x,<n>
+?pp <&&x>,<dword>,0,4
+?pp <off_&&x>,<word>,2,2
+?pp <seg_&&x>,<word>,2,2
+endm
+else
+irp x,<n>
+?pp <seg_&&x>,<word>,2,2
+?pp <off_&&x>,<word>,2,2
+?pp <&&x>,<dword>,0,4
+endm
+endif
+endm
+parmQ macro n
+?pp <n>,<qword>,8,8
+endm
+parmT macro n
+?pp <n>,<tbyte>,10,10
+endm
+if sizec
+parmCP macro n
+parmD <n>
+endm
+else
+parmCP macro n
+parmW <n>
+endm
+endif
+if sized
+parmDP macro n
+parmD <n>
+endm
+else
+parmDP macro n
+parmW <n>
+endm
+endif
+?pp macro n,t,l,s
+if ?cpd
+.xcref
+irp x,<n>
+.xcref ?t&&x
+?t&&x=s
+ife ?PLM
+?pp1 x,<t>,,,%(?po+?adj)
+?po=?po+l
+else
+?PLMPrevParm=?PLMPrevParm+1
+?po=?po+l
+?pp1 x,<t>,%?po,%?adj,,%?PLMPrevParm,%(?PLMPrevParm-1)
+endif
+endm
+.cref
+else
+??error <parm(s) "&n" declared outside proc def>
+endif
+endm
+?pp1 macro n,t,o,a,b,cpc,ppc
+ife ?PLM
+n equ (t ptr [bp+b])
+else
+.xcref
+.xcref ?PLMParm&cpc
+.cref
+?PLMParm&cpc &macro po
+uconcat <n>,,<equ>,,<(t ptr [bp+>,%(a+po-o),<])>
+?PLMParm&ppc po
+purge ?PLMParm&cpc
+&endm
+endif
+endm
+ifndef ?NOPARMR
+if ?pmd
+parmR macro n,r,r2
+??error <Sorry: ParmR can't be used with PMODE=1>
+endm
+else
+.xcref
+.xcref ?pr,parmR
+.cref
+parmR macro n,r,r2
+?pr n,r,r2,%?rp,%(?ia+2)
+endm
+?pr macro n,r,r2,i,o
+.xcref
+ifnb <r2>
+parmR seg_&n,r
+parmR off_&n,r2
+n equ (dword ptr [bp-o-2])
+.xcref ?t&n
+?t&n=4
+else
+.xcref ?rp&i
+?rp&i=0
+ifdef ?&r
+?rp&i=?&r
+endif
+if ??? or (?cpd eq 0) or (?rp&i eq 0)
+??error <invalid parmR encountered: &n,&r>
+exitm
+endif
+n equ (word ptr [bp-o])
+?t&n=2
+irp x,<bh,ch,dh,bl,cl,dl,ah,al>
+if ?&&x eq ?&r
+n equ (byte ptr [bp-o])
+?t&n=1
+exitm
+endif
+endm
+?ia=?ia+2
+?rp=?rp+1
+endif
+.cref
+endm
+endif
+endif
+.xcref
+.xcref localB,localW,localD,localQ,localT,localCP,localDP,localV
+.cref
+localB macro n
+?aloc <n>,<byte ptr>,1,1,0
+endm
+localW macro n
+?aloc <n>,<word ptr>,2,2,1
+endm
+localD macro n
+irp x,<n>
+?aloc <seg_&&x>,<word ptr>,2,2,1
+?aloc <off_&&x>,<word ptr>,2,2,1
+?aloc <&&x>,<dword ptr>,0,4,1
+endm
+endm
+localQ macro n
+?aloc <n>,<qword ptr>,8,8,1
+endm
+localT macro n
+?aloc <n>,<tbyte ptr>,10,10,1
+endm
+if sizec
+localCP macro n
+localD <n>
+endm
+else
+localCP macro n
+localW <n>
+endm
+endif
+if sized
+localDP macro n
+localD <n>
+endm
+else
+localDP macro n
+localW <n>
+endm
+endif
+localV macro n,a
+?aloc <n>,,%(a),0,1
+endm
+?aloc macro n,t,l,s,a
+if ?cpd
+.xcref
+irp x,<n>
+???=???+l
+if a
+???=((??? + 1) and 0fffeh)
+endif
+?al1 x,<t>,%(???+?ia)
+.xcref ?t&&x
+?t&&x=s
+endm
+.cref
+else
+??error <locals "&n" declared outside procedure def>
+endif
+endm
+?al1 macro n,t,o
+n equ (t [bp-o])
+endm
+?gcc macro s,i,cc
+s = i
+ifnb <cc>
+ifidn <cc>,<C>
+s=0
+endif
+ifidn <cc>,<PLM>
+s=1
+endif
+ifidn <cc>,<PASCAL>
+s=1
+endif
+endif
+endm
+ifndef ?NOGLOBAL
+.xcref
+.xcref globalB,globalW,globalD,globalQ,globalT,globalCP,globalDP
+.cref
+globalB macro n,i,s,c
+?ad <n>,1
+?dd n,1,<byte>,<db>,<i>,<s>,<c>
+endm
+globalW macro n,i,s,c
+?ad <n>,2
+?dd n,1,<word>,<dw>,<i>,<s>,<c>
+endm
+globalD macro n,i,s,c
+?ad <n>,4
+?dd n,1,<dword>,<dd>,<i>,<s>,<c>
+off_&n equ n
+seg_&n equ n[2]
+endm
+globalQ macro n,i,s,c
+?ad <n>,8
+?dd n,1,<qword>,<dq>,<i>,<s>,<c>
+endm
+globalT macro n,i,s,c
+?ad <n>,10
+?dd n,1,<tbyte>,<dt>,<i>,<s>,<c>
+endm
+if sizec
+globalCP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalCP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+if sized
+globalDP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalDP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+endif
+ifndef ?NOSTATIC
+.xcref
+.xcref staticB,staticW,staticD,staticQ,staticT,staticCP,staticDP
+.cref
+staticB macro n,i,s
+?ad <n>,1
+?dd n,0,<byte>,<db>,<i>,<s>,<PLM>
+endm
+staticW macro n,i,s
+?ad <n>,2
+?dd n,0,<word>,<dw>,<i>,<s>,<PLM>
+endm
+staticD macro n,i,s
+?ad <n>,4
+?dd n,0,<dword>,<dd>,<i>,<s>,<PLM>
+endm
+staticQ macro n,i,s
+?ad <n>,8
+?dd n,0,<qword>,<dq>,<i>,<s>,<PLM>
+endm
+staticT macro n,i,s
+?ad <n>,10
+?dd n,0,<tbyte>,<dt>,<i>,<s>,<PLM>
+endm
+if sizec
+staticCP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticCP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+if sized
+staticDP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticDP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+endif
+?dd macro n,p,t,d,i,s,c
+?gcc ?dd2,%?PLM,<c>
+ife ?dd2
+n label t
+?dd1 _&n,p,<d>,<i>,<s>
+else
+?dd1 n,p,<d>,<i>,<s>
+endif
+endm
+?dd1 macro n,p,d,i,s
+if p
+public n
+endif
+ifb <s>
+n d i
+else
+ifb <i>
+n d s dup (?)
+else
+n d s dup (i)
+endif
+endif
+endm
+ifndef ?NOEXTERN
+.xcref
+.xcref ?ex1,?ex2,externB,externW,externD,externQ,externT
+.xcref externNP,externFP,externP,externCP,externDP,externA
+.cref
+?ex2 = 0
+externA macro n,c
+?ex1 <n>,40h,<abs>,<c>,<>
+endm
+externB macro n,c
+?ex1 <n>,1,<byte>,<c>,<>
+endm
+externW macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+externD macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+externQ macro n,c
+?ex1 <n>,8,<qword>,<c>,<>
+endm
+externT macro n,c
+?ex1 <n>,10,<tbyte>,<c>,<>
+endm
+externNP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+externFP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+if sizec
+externP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+else
+externP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+endif
+if sizec
+externCP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externCP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+if sized
+externDP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externDP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+?ex1 macro n,s,d,c,scv
+?gcc ?ex2,%?PLM,<c>
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?ex2
+extrn _&&x:&d
+x equ _&&x
+else
+extrn x:&d
+endif
+ifidn <scv>,<cc>
+.xcref
+.xcref ?CC&&x
+.cref
+?CC&&x=?ex2
+endif
+endm
+endm
+endif
+ifndef ?NOLABEL
+.xcref
+.xcref ?lb1,?lblpu,?lb2
+.xcref labelB,labelW,labelD,labelQ,labelT
+.xcref labelNP,labelFP,labelP,labelCP,labelDP
+.cref
+?lblpu = 0
+?lb2 = 0
+labelB macro n,c
+?lb1 <n>,1,<byte>,<c>
+endm
+labelW macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+labelD macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+labelQ macro n,c
+?lb1 <n>,8,<qword>,<c>
+endm
+labelT macro n,c
+?lb1 <n>,10,<tbyte>,<c>
+endm
+labelNP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+labelFP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+if sizec
+labelP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+else
+labelP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+endif
+if sizec
+labelCP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelCP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+if sized
+labelDP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelDP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+?lb1 macro n,s,d,c
+?gcc ?lb2,%?PLM,<c>
+?lblpu=0
+irp x,<n>
+ifidn <x>,<PUBLIC>
+?lblpu=1
+else
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?lb2
+if ?lblpu
+public _&&x
+endif
+_&&x label &d
+x equ _&&x
+else
+if ?lblpu
+public x
+endif
+x label &d
+endif
+endif
+endm
+endm
+endif
+ifndef ?NODEF
+.xcref
+.xcref defB,defW,defD,defQ,defT,defCP,defDP
+.cref
+defB macro n
+?ad <n>,1
+endm
+defW macro n
+?ad <n>,2
+endm
+defD macro n
+?ad <n>,4
+endm
+defQ macro n
+?ad <n>,8
+endm
+defT macro n
+?ad <n>,10
+endm
+if sizec
+defCP macro n
+defD <n>
+endm
+else
+defCP macro n
+defW <n>
+endm
+endif
+if sized
+defDP macro n
+defD <n>
+endm
+else
+defDP macro n
+defW <n>
+endm
+endif
+endif
+?ad macro n,s
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+endm
+endm
+ifndef ?NOPTR
+.xcref
+.xcref regPtr,farPtr
+.cref
+regPtr macro n,s,o
+farPtr n,s,o
+endm
+farPtr macro n,s,o
+.xcref
+.xcref ?t&n
+.cref
+n &macro
+ push s
+ push o
+&endm
+?t&n=80h
+endm
+endif
+arg macro a
+irp x,<a>
+?argc=?argc+1
+?atal <x>,%?argc
+endm
+endm
+?atal macro n,i
+.xcref
+.xcref ?ali&i
+.cref
+?ali&i &macro
+?ap n
+&endm
+endm
+?ap macro n
+?argl=?argl+2
+ifdef ?t&n
+ife ?t&n-1
+ push word ptr (n)
+exitm
+endif
+ife ?t&n-2
+ push n
+exitm
+endif
+ife ?t&n-4
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+2
+exitm
+endif
+ife ?t&n-8
+ push word ptr (n)[6]
+ push word ptr (n)[4]
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+6
+exitm
+endif
+if ?t&n and 80h
+n
+?argl=?argl+2
+exitm
+endif
+ife ?t&n
+ push word ptr (n)
+exitm
+endif
+endif
+ push n
+endm
+cCall macro n,a,c
+ifnb <a>
+arg <a>
+endif
+mpush %?rsl
+ifdef ?CC&n
+?cCall1=?CC&n
+else
+?cCall1=?PLM
+endif
+ifnb <c>
+?gcc ?cCall1,%?cCall1,<c>
+endif
+?argl=0
+ife ?cCall1
+?acb=?argc
+else
+?acb=1
+endif
+rept ?argc
+uconcat <?ali>,%?acb
+uconcat <purge>,,<?ali>,%?acb
+ife ?cCall1
+?acb=?acb-1
+else
+?acb=?acb+1
+endif
+endm
+ call n
+if ((?cCall1 eq 0) and (?argl ne 0))
+ add sp,?argl
+endif
+mpop %?rsl
+?rsl=0
+?argc= 0
+?argl= 0
+endm
+cProc macro n,cf,a
+if ?cpd
+?utpe
+endif
+?cpd=1
+???=0
+?argc=0
+?ba=0
+?po=0
+?pu=0
+?ia=0
+?adj=4
+?rp=0
+?uf=0
+?wfp=?WIN
+?ff=0
+?pas=0
+?pcc=?PLM
+?lds=0
+?exp=0
+ifnb <a>
+?ri ?pas,<a>
+endif
+?pc=sizec
+?nd=?nodata1
+?nx=0
+irp x,<cf>
+ifidn <x>,<FAR>
+?pc=1
+endif
+ifidn <x>,<NEAR>
+?pc=0
+endif
+ifidn <x>,<PUBLIC>
+?pu=1
+endif
+ifidn <x>,<SMALL>
+?uf=1
+endif
+ifidn <x>,<DATA>
+?nd=0
+endif
+ifidn <x>,<NODATA>
+?nd=1
+endif
+ifidn <x>,<ATOMIC>
+?nx=1
+endif
+ifidn <x>,<C>
+?pcc=0
+endif
+ifidn <x>,<PLM>
+?pcc=1
+endif
+ifidn <x>,<PASCAL>
+?pcc=1
+endif
+ifidn <x>,<WIN>
+?wfp=1
+endif
+ifidn <x>,<NONWIN>
+?wfp=0
+endif
+ifidn <x>,<LOADDS>
+?lds=1
+endif
+ifidn <x>,<EXPORTED>
+?exp=1
+endif
+endm
+if ?pcc
+?PLMPrevParm=0
+.xcref
+.xcref ?PLMParm0
+.cref
+?PLMParm0 &macro
+purge ?PLMParm0
+&endm
+endif
+.xcref
+.xcref ?CC&n
+.cref
+?CC&n=?pcc
+if (?nx eq 1) and (?nd eq 0)
+?nx = 0
+??error <ATOMIC specified without NODATA - ATOMIC ignored>
+endif
+if ?pc
+if ?wfp+?exp+?lds
+ife ?nx
+ife ?pmd
+?ia=2
+endif
+?pas = ?pas and (not ?ds)
+endif
+endif
+?adj=?adj+2
+else
+?wfp=0
+endif
+ife ?386regs
+?pas = ?pas and (not (?sp+?cs+?ss))
+endif
+if ?uf
+if ?386regs
+?pas = ?pas and (not (?si+?di))
+else
+?pas = ?pas and (not (?bp+?si+?di))
+endif
+endif
+ife ?pcc
+?pg <_&n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+else
+?pg <n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+endif
+endm
+?pg macro n,p,c,a,w,nnu,cc
+.xcref
+if ?uf
+if ?nd
+??error <NODATA encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+.xcref cBegin
+cBegin &macro g
+.xcref
+if cc
+uconcat <?PLMParm>,%?PLMPrevParm,%?po
+endif
+if ?uf
+if ?rp
+??error <parmR encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+?pg1 <n>,c,a,%?po,w,%?uf,%?nd,%?rp,cc
+?cpd=0
+?argc=0
+?ba=1
+???=(???+1) and 0fffeh
+if p
+public n
+endif
+ife c
+n proc near
+else
+n proc far
+endif
+ife cc
+nnu equ n
+endif
+ifidn <g>,<nogen>
+if ???+?po+a+?rp
+??_out <cBegin - possible invalid use of nogen>
+endif
+else
+if ?uf
+?mf c,%???,%?po
+mpush a
+else
+if w+?exp+?lds
+if ?pmd
+ife ?nd
+if ?lds
+mov ax,_DATA
+else
+if ?exp
+mov ax,ds
+nop
+endif
+endif
+endif
+ife ?nx
+if ???+?po
+if ?chkstk1
+push bp
+mov bp,sp
+else
+if ???
+enter ???,0
+else
+push bp
+mov bp,sp
+endif
+endif
+endif
+push ds
+if ?lds+?exp
+mov ds,ax
+endif
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+else
+ife ?nd
+ mov ax,ds
+ nop
+endif
+ife ?nx
+ife ?DOS5
+ inc bp
+endif
+ push bp
+ mov bp,sp
+ push ds
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+ife ?nd
+ mov ds,ax
+endif
+endif
+else
+if ?pmd
+if ?exp
+mov ax,ds
+nop
+else
+if ?lds
+mov ax,_DATA
+endif
+endif
+if ?ff+???+?po+?rp
+if ?chkstk1
+push bp
+mov bp,sp
+else
+if ???
+enter ???,0
+else
+push bp
+mov bp,sp
+endif
+endif
+endif
+if ?exp+?lds
+push ds
+mov ds,ax
+endif
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+endif
+if ?rp
+?uf=0
+rept ?rp
+uconcat mpush,,?rp,%?uf
+?uf=?uf+1
+endm
+endif
+if ???
+if ?chkstk1
+ifdef ?CHKSTKPROC
+?CHKSTKPROC %???
+else
+ mov ax,???
+ife cc
+ call _chkstk
+else
+ call chkstk
+endif
+endif
+else
+ife ?pmd
+ sub sp,???
+endif
+endif
+endif
+mpush a
+endif
+ifdef ?PROFILE
+if c
+ call StartNMeas
+endif
+endif
+endif
+.cref
+purge cBegin
+&endm
+.xcref ?utpe
+?utpe &macro
+??error <unterminated procedure definition: "&n">
+&endm
+.cref
+endm
+?pg1 macro n,c,a,o,w,f,d,r,cc
+.xcref
+.xcref cEnd
+cEnd &macro g
+.xcref
+?ba=0
+ifidn <g>,<nogen>
+if o+a+r
+??_out <cEnd - possible invalid use of nogen>
+endif
+else
+ifdef ?PROFILE
+if c
+call StopNMeas
+endif
+endif
+mpop a
+if f
+ db 0c3h
+else
+if w+?exp+?lds
+if ?pmd
+ife ?nx
+pop ds
+endif
+ife ?nx
+if ?chkstk1+???+?po
+leave
+endif
+else
+if ?ff+???+?po+?rp
+leave
+endif
+endif
+else
+ife ?nx
+if (?TF eq 0) or (???+?rp)
+ lea sp,-2[bp]
+endif
+ pop ds
+ pop bp
+ife ?DOS5
+ dec bp
+endif
+else
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+if ???+?po+?rp
+ pop bp
+endif
+endif
+endif
+else
+if ?pmd
+if ?ff+???+?po+?rp
+leave
+endif
+else
+if ?ff+???+?po+?rp
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+ pop bp
+endif
+endif
+endif
+ife cc
+ ret
+else
+ ret o
+endif
+endif
+endif
+n endp
+.cref
+purge cEnd
+&endm
+.cref
+endm
+assumes macro s,ln
+ifndef ln&_assumes
+assume s:ln
+else
+ln&_assumes s
+endif
+endm
+createSeg macro n,ln,a,co,cl,grp
+ifnb <grp>
+addseg grp,n
+else
+ln&OFFSET equ offset n:
+ln&BASE equ n
+?cs3 <ln>,<n>
+endif
+ifnb <cl>
+n segment a co '&cl'
+else
+n segment a co
+endif
+n ends
+?cs1 <ln>,<n>
+endm
+addseg macro grp,seg
+.xcref
+.xcref grp&_def
+.cref
+ifndef grp&_def
+grp&_def=0
+endif
+if grp&_def ne ASMpass
+.xcref
+.xcref grp&_add
+.cref
+grp&_add &macro s
+grp&_in <seg>,s
+&endm
+.xcref
+.xcref grp&_in
+.cref
+grp&_in &macro sl,s
+ifb <s>
+grp group sl
+else
+grp&_add &macro ns
+grp&_in <sl,s>,ns
+&endm
+endif
+&endm
+grp&_def=ASMpass
+else
+grp&_add seg
+endif
+endm
+defgrp macro grp,ln
+addseg grp
+ifnb <ln>
+irp x,<ln>
+?cs3 <&x>,<grp>
+x&&OFFSET equ offset grp:
+x&&BASE equ grp
+endm
+endif
+endm
+?cs1 macro ln,n
+.xcref
+.xcref ln&_sbegin
+.cref
+ln&_sbegin &macro
+.xcref
+.xcref ?mf
+.cref
+?mf &&macro c,l,p
+if c
+ extrn n&_FARFRAME:near
+ call n&_FARFRAME
+else
+ extrn n&_NEARFRAME:near
+ call n&_NEARFRAME
+endif
+ db l shr 1
+ db p shr 1
+&&endm
+?cs2 <ln>,<n>
+n segment
+&endm
+endm
+?cs2 macro ln,n
+.xcref
+.xcref sEnd
+.cref
+sEnd &macro
+n ends
+purge ?mf
+purge sEnd
+&endm
+endm
+?cs3 macro ln,n
+.xcref
+.xcref ln&_assumes
+.cref
+ln&_assumes &macro s
+assume s:&n
+&endm
+endm
+.xcref
+.xcref sBegin
+.cref
+sBegin macro ln
+ln&_sbegin
+endm
+ife ?DF
+createSeg _TEXT,Code,word,public,CODE
+ife ?nodata1
+createSeg _DATA,Data,word,public,DATA,DGROUP
+defgrp DGROUP,Data
+endif
+if ?chkstk1
+ifndef ?CHKSTKPROC
+externp <chkstk>
+endif
+endif
+endif
+errnz macro x
+if2
+if x
+errnz1 <x>,%(x)
+endif
+endif
+endm
+errnz1 macro x1,x2
+= *errnz* x1 = x2
+.err
+endm
+errn$ macro l,x
+errnz <offset $ - offset l x>
+endm
+ifdef ?PROFILE
+externFP <StartNMeas,StopNMeas>
+endif
diff --git a/private/mvdm/wow16/inc/cmacros.mas b/private/mvdm/wow16/inc/cmacros.mas
new file mode 100644
index 000000000..17b024775
--- /dev/null
+++ b/private/mvdm/wow16/inc/cmacros.mas
@@ -0,0 +1,2666 @@
+comment $
+
+cmacros - assembly macros for interfacing to hlls
+
+(C)Copyright Microsoft Corp. 1984-1988
+
+$
+
+;; Revision History
+;;
+;; 1.00 05/03/84 Initial Release
+;;
+;; 1.01 05/06/84 Greg Whitten
+;; Added defgrp and changed cMerge to Microsoft C
+;; Added copyright message and changed to 1.01
+;; Changes should have no affect on working programs
+;;
+;; 1.02 07/10/84 Steve Wood
+;; Added labelx macros
+;;
+;; 1.03 07/14/84 Greg Whitten
+;; Added defines for ?pu, ?adj, ?lblpu
+;; (removes undefined errors)
+;; Changes should have no affect on working programs
+;;
+;; 1.04 07/18/84 Greg Whitten
+;; Added local control from PL/M or C conventions
+;; except for cCall macro
+;;
+;; 1.05 08/06/84 Steve Wood
+;; Made ?PLM and ?WIN be the defaults
+;;
+;; 1.06 01/02/85 Steve Wood
+;; Changed createSeg and defgrp to automatically
+;; define the ln_assumes macro and the lnoffset
+;; and lnbase equates for each logical segment
+;; name.
+;;
+;; 1.07 02/19/85 Walt Moore
+;; Added farptr macro for defining a far pointer
+;; to be used in a cCall. Folded regptr into
+;; farptr. Space compaction in macros. Changed
+;; ?pp to be smaller. Moved ?ia out of ?al1 into
+;; ?aloc. Merged cProc and ?pd into one macro.
+;; Changed some %outs to use the error macro so
+;; an error would be generated. Added makeframe
+;; and parmR to cProc. Changed error to also put
+;; the error message in the listing.
+;; Deleted the smashes macro.
+;;
+;; 1.08 03/18/85 Steve Wood
+;; Added NODATA support.
+;;
+;; 1.09 03/27/85 Steve Wood
+;; Added ?definitions
+;;
+;; 2.00 04/01/85 Steve Wood
+;; April fools
+;;
+;; 2.01 06/17/85 Steve Wood
+;; Changed NODATA to always generate POP DS
+;; for return address patching
+;;
+;; 2.02 02/11/86 Steve Wood
+;; Added ATOMIC keyword to cProc macro
+;; Changed far epilog to use LEA SP,BP-2
+;; Changed error macro to ??error to avoid
+;; conflict
+;;
+;; 2.03 03/06/86 Steve Wood
+;; Fixed bug with ATOMIC and locals in far proc
+;; Added DOS5 switch to disable INC/DEC BP
+;; instructions in special far prologs/epilogs
+;;
+;; 2.04 08/07/86 Scott Randell
+;; Fixed bug with ATOMIC and ?TF
+;; (was doing unnecessary MOV SP,BP)
+;; Added pcode profile ?PROFILE
+;;
+;; 2.05 08/12/86 Walt Moore
+;; Changed _TEXT alignment to word.
+;; Added/corrected some comments.
+;; Removed redundant init of ?pc in cProc
+;; Made ATOMIC require NODATA
+;; Moved definition of non-underscored 'C' label
+;; from the cProc to the cBegin macro
+;; Minor clean-up of code
+;;
+;; 2.06 09/11/86 Walt Moore
+;; Added private stack checking
+;; Put local control for PL/M or C into cCall
+;;
+;;
+;; 2.07 09/19/86 Steve Wood
+;; Added ?SMALL, ?MEDIUM, etc. symbols
+;; Added forceframe keyword to cProc macro.
+;; Interpret ?TF for all epilogs.
+;;
+;; 3.xx.a 02/26/87 Massive rework. Documentation coming.
+;;
+;;
+;; Assembly macros for interfacing to C
+;;
+;; User setable conditional assembly flags used within the cmacros
+;;
+;; Memory model flags. Set only one of the following. memS is the
+;; default. The symbols with ? are for defining from the command line
+;; and the memx symbols are numeric symbols that can be set in your source
+;; file prior to including this file.
+;;
+;; ?SMALL memS - small model
+;; ?MEDIUM memM - medium model
+;; ?LARGE memL - large model
+;; ?COMPACT memC - compact model
+;; ?HUGE memH - huge model
+;;
+;; ?DF Define flag. If this flag is 0, then defines default segment
+;; and group definitions based on the compiler flag. If this
+;; flag is 1, then does not define any segments or groups.
+;;
+;; ?TF Tight flag. If this flag is 0, then use longer epilog
+;; sequence that safely cleans up a stack frame. If this flag is
+;; 1, then use more efficient epilog that assumes the stack is
+;; valid (SP)
+;;
+;; ?WIN Windows flag. Enables generation of special prolog/epilog
+;; for far procedures. Default value is 1 (Windows).
+;;
+;; DOS5 If defined, then special far prolog/epilog seqeuences will not
+;; include the INC/DEC BP instructions.
+;;
+;; PMODE Protect mode flag. Enables use of ENTER/LEAVE, disables
+;; INC/DEC BP instructions, sets .286p.
+;;
+;; ?386regs Enables use of eax,ebx,ecx,esi,edi,fs,gs as registers
+;; in cProc et al. Use of al,ah,bl,bh,cl,ch,dl,dh,ss,bp,sp,ss,cs
+;; no longer allowed.
+;;
+;; ?PLM Calling convention flag. If this flag is 0, then the
+;; calling convention used is that of C. If this flag
+;; is 1, then the PL/M calling convention is used.
+;; The default value is 1. The PL/M calling convention
+;; is used by pascal, fortran, basic, and cobol.
+;;
+;; In the C calling convention, arguments are passed
+;; in reverse order; arg0 is the last pushed, argn is the
+;; first pushed. also, it is the callers responsibility
+;; to remove the arguments from the stack upon a return
+;; from a call.
+;;
+;; In the PL/M calling comvention, arguments are passed
+;; as encountered; arg0 is the first pushed, argn is the
+;; last pushed. also, it is the called procedure's
+;; responsibility to remove parameters from the stack
+;; before returning (using the RET n instruction)
+;;
+;; ?NODATA If defined, then no data segment or DGROUP is defined and
+;; the special prolog/epilog sequences will not contain the
+;; code needed to setup DS.
+;;
+;; ?CHKSTK If defined, then prolog sequences for cProcs with local
+;; parameters will call the CHKSTK procedure to allocate
+;; the stack space.
+;;
+;; ?CHKSTKPROC If defined, then this macro will be invoked to
+;; perform the stack checking, otherwise the
+;; standard stack checking procedure will be
+;; performed. ?CHKSTKPROC must be declared
+;; before the cmacros are included in the source
+;; else the standard chkstk routine will be declared
+;; as an external symbol.
+;;
+;; On entry to the user's stack checking procedure,
+;; the frame has been setup except for allocating
+;; local variable space and saving autosave registers.
+;;
+;; The user supplied macro is passed as an argument
+;; the number of byte of stack space requested.
+;;
+;; ?PROFILE If defined then all far cBegin entries will have StartNMeas,
+;; and all cEnd will have StopNMeas calls, StartNMeas and
+;; StopNMeas will be defined as externfp
+;;
+;; ?NOPARMR If defined, then the "parmR" macro will not be defined.
+;;
+;; ?NOGLOBAL If defined, then the "globalx" macros will not be defined.
+;;
+;; ?NOSTATIC If defined, then the "staticx" macros will not be defined.
+;;
+;; ?NOEXTERN If defined, then the "externx" macros will not be defined.
+;;
+;; ?NOLABEL If defined, then the "labelx" macros will not be defined.
+;;
+;; ?NODEF If defined, then the "defx" macros will not be defined.
+;;
+;; ?NOPTR If defined, then "farptr & regptr" will not be defined.
+;;
+;; ?QUIET If defined, then only error messages will be issued to
+;; the console. If undefined, then certain cmacro text will
+;; be generated to the console.
+
+
+.xcref ;;Get rid of a lot of symbols
+
+
+
+; ??_out - output given message to the console unless ?QUIET has
+; been specified.
+;
+; usage:
+; ??_out <t>
+;
+; where:
+; <t> is the message to output
+
+.xcref ??_out
+??_out macro t
+ ifndef ?QUIET
+ %out t
+ endif
+endm
+
+
+
+; outif - output msg if name is non-zero. if name is undefined,
+; set name = 0, else set name to the default value.
+;
+; usage:
+; outif name,defval,onmsg,offmsg
+; where:
+; name name of symbol
+; defval default value to give symbol if not defined
+; if blank, then 0 will be used
+; onmsg text to display if symbol is non-zero
+; offmsg test to be displayed if symbol is zero
+
+
+outif macro name,defval,onmsg,offmsg
+ ifndef name
+ ifb <defval>
+ name=0
+ else
+ name=defval
+ endif
+ endif
+ if name
+ name=1
+ ifnb <onmsg>
+ ??_out <! onmsg>
+ endif
+ else
+ ifnb <offmsg>
+ ??_out <! offmsg>
+ endif
+ endif
+endm
+
+
+
+; ??error - output msg and generate an assembly time error
+;
+; usage:
+; ??error <t>
+; where:
+; t is the text to be output
+
+
+.xcref ??error
+??error macro msg
+ e r r o r ----- msg ;;to console
+ .err ;;for good measure, force this also
+endm
+
+
+.xcref ASMpass
+.xcref memS,memM,memL,memC,memH,memMOD,sizec,sized
+
+if1 ;;Only on pass 1
+ ASMpass=1
+ ifdef ?SMALL ;;inform user what is going on
+ memS=1
+ endif
+ ifdef ?MEDIUM
+ memM=1
+ endif
+ ifdef ?COMPACT
+ memC=1
+ endif
+ ifdef ?LARGE
+ memL=1
+ endif
+ ifdef ?HUGE
+ memH=1
+ endif
+
+ ??_out <cMacros Version 5.20 - Copyright (c) Microsoft Corp. 1984-1988>
+ outif memS,0,<Small model>
+ outif memM,0,<Medium model>
+ outif memL,0,<Large model>
+ outif memC,0,<Compact model>
+ outif memH,0,<Huge model>
+
+ memMOD= memS + memM + memL + memC + memH
+ if memMOD ne 1
+ if memMOD eq 0
+ memS = 1 ; assume small model
+ else
+ ??error <more than 1 memory model selected>
+ endif
+ endif
+
+ sizec= memM + memL + memH ; large code
+ sized= memL + memC + (memH*2) ; large data (2 if huge)
+
+ outif ?DF,0,<No segments or groups will be defined>
+ outif ?TF,0,<Epilog sequences assume valid SP>
+ outif ?WIN,1,<Windows support>
+
+ ifdef PMODE
+ ?pmd=1
+ ??_out <! 286 protect mode>
+ else
+ ?pmd=0
+ endif
+
+ ifdef ?386regs
+ if ?386regs
+ ??_out <! 386 registers enabled>
+ endif
+ else
+ ?386regs=0
+ endif
+
+ if ?WIN eq 1
+ outif ?PLM,1,<>
+ else
+ outif ?PLM,1,<Pascal calling convention>
+ endif
+
+ ifndef ?NODATA
+ ?nodata1=0
+ else
+ ?nodata1=1
+ ??_out <! NODATA module>
+ endif
+
+ ifndef ?CHKSTK
+ ?chkstk1=0
+ else
+ ?chkstk1=1
+ ifdef ?CHKSTKPROC
+ ??_out <! Private stack checking enabled>
+ else
+ ??_out <! Stack checking enabled>
+ endif
+ endif
+
+ ifndef DOS5
+ ?DOS5=0
+ else
+ ?DOS5=1
+ ??_out <! DOS5 module>
+ endif
+
+ ifdef ?PROFILE
+ ??_out <! Native profiling enabled>
+ endif
+else
+ ASMpass=2
+endif
+
+ ifdef ?pmd
+ .286p
+ endif
+
+;; Initialize all symbols used in the macros. Theses symbols will not be
+;; included in any cross reference listing.
+
+if ?386regs
+ .xcref ?n,?ax,?eax,?bx,?ebx
+ .xcref ?cx,?ecx,?dx,?edx
+ .xcref ?si,?esi,?di,?edi,?es,?ds,?fs
+ .xcref ?gs
+else
+ .xcref ?n,?ax,?ah,?al,?bx,?bh
+ .xcref ?bl,?cx,?ch,?cl,?dx,?dh
+ .xcref ?dl,?si,?di,?es,?ds,?bp
+ .xcref ?sp,?ss,?cs
+endif
+ .xcref ?rsl,?cpd,?argl,?argc,?ba
+ .xcref ?acb,???,?po
+ .xcref ?pas,?pc
+
+ .xcref uconcat,mpush,mpop
+ .xcref ?ri,?pp,?pp1,?al1
+ .xcref ?ad,?ap,?atal,?dd,?dd1,?dd2
+ .xcref ?pg,?pg1,?aloc,?cs1,?cs2
+ .xcref ?DF,?TF,?ff,?PLM,?WIN,?ia,?pu,?adj
+ .xcref ?uf,?rp,?nx,?nd,?nodata1,?chkstk1,?DOS5,?pmd,?lds,?exp
+ .xcref ?wfp,arg,cCall,cProc,assumes,?cs3,?cs2,?cs1
+ .xcref defgrp,addseg,createSeg
+ .xcref save,outif,errnz,errn$,errnz1
+ .xcref ?PLMPrevParm,?gcc
+ .xcref ?cCall1,?pcc
+
+
+;; conditionals set by the macros
+;;
+;; ?pc Procedure class. If this is set to 1, then the procedure
+;; is a far procedure, else it is a near procedure.
+;;
+;; ?ia Interface adjustment count for far procedures. The
+;; interface adjustment defines the number of bytes of
+;; storage allocated between BP and the first frame variable
+;; allocated on the stack.
+;;
+;; Normally zero, it will be adjusted for both far windows
+;; procedures and by register parameters.
+;;
+;; ?cpd Current procedure defined. This is set to a non-zero
+;; value if a procedure is being defined (i.e a cProc has
+;; been encountered, and cBegin has not).
+;;
+;; ?ba Begin active. This is set to a non-zero value if a
+;; cBegin is active (i.e. a cBegin has been encountered,
+;; and cEnd has not).
+;;
+;; ?wfp Windows far procedure. Set if a windows far procedure
+;;
+;; ?lds LOADDS keyword - Preserve DS and set DS to _DATA
+;;
+;; ?exp EXPORTED keyword - mov ax,ds/nop as first inst, preserve DS
+;;
+;; Other variables that are defined once so that the .xcref command
+;; doesn't get too upset if they show up missing!
+
+?rsl = 0 ;;0 = no register to save
+?cpd = 0 ;;<> 0 if in a procedure definition
+?argl = 0 ;;length of arguments pushed on stack
+?argc = 0 ;;# of arguments so far
+?ba = 0 ;;<>0 if in a procedure (xbegin)
+?acb = 0 ;;number of arguments to a call
+??? = 0 ;;byte count of local storage
+?po = 0 ;;byte count of parameters
+?pas = 0 ;;autosave value for procedure
+?pc = 0 ;;class of a procedure (near/far)
+?ia = 0 ;;no adjustment
+?pu = 0 ;;public flag for some macros
+?adj = 0 ;;initial define for .xcref
+?rp = 0 ;;count of register parameters
+?uf = 0 ;;user's frame code specified
+?nd = 0 ;;NODATA keyword specified
+?nx = 0 ;;ATOMIC keyword specified
+?wfp = 0 ;;window far procedure
+?lds = 0 ;;LOADDS keyword
+?exp = 0 ;;EXPORTED keyword
+?ff = 0 ;;forceframe keyword specified
+?dd2 = 0 ;;used for globalx and staticx
+?cCall1 = 0 ;;used for cCalls
+?pcc = 0 ;;procedure calling convention
+?PLMPrevParm = 0 ;;Used in parameter processing
+
+ .xcref ?casen
+if1 ;;only define ?casen on pass 1
+?casen = 0 ;;case sensitive assembly if <> 0
+endif
+
+if ?386regs
+?n = 0000000000000000b
+?ax = 0000000000000001b
+?eax = 0000000000000010b
+?bx = 0000000000000100b
+?ebx = 0000000000001000b
+?cx = 0000000000010000b
+?ecx = 0000000000100000b
+?dx = 0000000001000000b
+?edx = 0000000010000000b
+?si = 0000000100000000b
+?esi = 0000001000000000b
+?di = 0000010000000000b
+?edi = 0000100000000000b
+?ds = 0001000000000000b
+?es = 0010000000000000b
+?fs = 0100000000000000b
+?gs = 1000000000000000b
+else
+?n = 0000000000000000b ;;register none
+?ax = 0000000000000011b ;;register ax
+?ah = 0000000000000001b ;;register ah
+?al = 0000000000000010b ;;register al
+?bx = 0000000000001100b ;;register bx
+?bh = 0000000000000100b ;;register bh
+?bl = 0000000000001000b ;;register bl
+?cx = 0000000000110000b ;;register cx
+?ch = 0000000000010000b ;;register ch
+?cl = 0000000000100000b ;;register cl
+?dx = 0000000011000000b ;;register dx
+?dh = 0000000001000000b ;;register dh
+?dl = 0000000010000000b ;;register dl
+?si = 0000000100000000b ;;register si
+?di = 0000001000000000b ;;register di
+?es = 0000010000000000b ;;register es
+?ds = 0000100000000000b ;;register ds
+?bp = 0001000000000000b ;;register bp
+?sp = 0010000000000000b ;;register sp
+?ss = 0100000000000000b ;;register ss
+?cs = 1000000000000000b ;;register cs
+endif
+ .cref
+
+
+
+;; uconcat - unconditionally generate a statement from a field
+;; of given parameters
+;;
+;; usage:
+;; uconcat a,b,c,d,e,f,g
+;;
+;; where:
+;; a,b are concatenated for field 1
+;; c,d are concatenated for field 2
+;; e,f,g are concatenated for field 3
+
+uconcat macro a,b,c,d,e,f,g
+ a&b c&d e&f&g
+endm
+
+
+
+;; mpush pushes multiple registers onto the stack according to
+;; a register specification.
+;;
+;; format:
+;; mpush r
+;;
+;; where:
+;; r is a numeric expression returned from ?ri
+;; or any other valid register expression
+
+if ?386regs
+
+mpush macro r
+ irp x,<ax,eax,bx,ebx,cx,ecx,dx,edx,si,esi,di,edi,ds,es,fs,gs>
+ if (r and ?&&x)
+ push x ;@
+ endif
+ endm
+endm
+
+else
+
+mpush macro r
+ irp x,<ax,bx,cx,dx,si,di,es,ds,bp,sp,ss,cs>
+ if (r and ?&&x)
+ push x ;@
+ endif
+ endm
+endm
+
+endif
+
+;; mpop pops multiple registers from the stack according to
+;; a register specification.
+;;
+;; format:
+;; mpop r
+;;
+;; where:
+;; r is a numeric expression returned from ?ri
+;; or any other valid register expression
+
+if ?386regs
+
+mpop macro r
+ irp x,<gs,fs,es,ds,edi,di,esi,si,edx,dx,ecx,cx,ebx,bx,eax,ax>
+ if (r and ?&&x)
+ pop x ;@
+ endif
+ endm
+endm
+
+else
+
+mpop macro r
+ irp x,<cs,ss,sp,bp,ds,es,di,si,dx,cx,bx,ax>
+ if (r and ?&&x)
+ pop x ;@
+ endif
+ endm
+endm
+
+endif
+
+;; save - flag that the indicated registers are to be saved/restored
+;;
+;; A flag is created which indicates which registers are to be saved
+;; when the cCall macro is invoked, and then restored after the call.
+;;
+;; usage:
+;; save <r>
+;;
+;; where r is the list of registers to save, which may be:
+;;
+;; register saves
+;; AX AX
+;; AH AX
+;; AL AX
+;; BX BX
+;; BH BX
+;; BL BX
+;; CX CX
+;; CH CX
+;; CL CX
+;; DX DX
+;; DH DX
+;; DL DX
+;; SI SI
+;; DI DI
+;; ES ES
+;; DS DS
+;; BP BP
+;;
+;; none nothing
+;;
+;; the macro generates a value for the variable ?rsl
+
+save macro r
+ ?rsl=0 ;;initialize save list
+ ?ri ?rsl,<r> ;;generate magic number
+endm
+
+;; ?ri - or register indexes to variable
+;;
+;; ?ri is a macro that examines the passed argument list and computes
+;; a register index variable.
+;;
+;; The values ORed with the variable are:
+;;
+;; ?n equ 0000000000000000b;
+;; ?AX equ 0000000000000011b;
+;; ?AH equ 0000000000000001b;
+;; ?AL equ 0000000000000010b;
+;; ?BX equ 0000000000001100b;
+;; ?BH equ 0000000000000100b;
+;; ?BL equ 0000000000001000b;
+;; ?CX equ 0000000000110000b;
+;; ?CH equ 0000000000010000b;
+;; ?CL equ 0000000000100000b;
+;; ?DX equ 0000000011000000b;
+;; ?DH equ 0000000001000000b;
+;; ?DL equ 0000000010000000b;
+;; ?SI equ 0000000100000000b;
+;; ?DI equ 0000001000000000b;
+;; ?ES equ 0000010000000000b;
+;; ?DS equ 0000100000000000b;
+;; ?BP equ 0001000000000000b;
+;; ?SP equ 0010000000000000b;
+;; ?SS equ 0100000000000000b;
+;; ?CS equ 1000000000000000b;
+;; usage:
+;; ?ri n,<r>
+;; where:
+;; n is the variable to contain the new index value
+;; r is the register list
+
+?ri macro n,r
+ irp x,<r>
+ .ERRNDEF ?&&x ;; yell if register isn't defined
+ n=n or ?&&x
+ endm
+endm
+
+
+
+;; parmx - generate reference to parameter(s) on the stack
+;;
+;; An equate is generated for addressing a paramter(s)
+;; on the stack for the current procedural frame.
+;;
+;; An error message is generated if there isn't a current frame.
+;;
+;; usage:
+;; parmx n
+;; where:
+;; x is the type of the argument(s) b=byte, w=word, d=dword
+;; n is the name(s) to be given the parameter(s).
+;;
+;; Bytes are considered to be two bytes long for alignment.
+;;
+;; The parmd form of the macro generates three equates:
+;;
+;; name - for accessing the parameter as a double word
+;; off_name - for accessing the offset (lsw) of the parameter
+;; seg_name - for accessing the segment (msw) of the parameter
+
+.xcref
+.xcref parmB,parmW,parmD,parmQ,parmT,parmCP,parmDP
+.cref
+
+parmB macro n
+ ?pp <n>,<byte>,2,1
+endm
+
+parmW macro n
+ ?pp <n>,<word>,2,2
+endm
+
+parmD macro n
+ ife ?PLM ;;if to assemble for C
+ irp x,<n>
+ ?pp <&&x>,<dword>,0,4
+ ?pp <off_&&x>,<word>,2,2
+ ?pp <seg_&&x>,<word>,2,2
+ endm
+ else ;;if to assemble for PL/M
+ irp x,<n>
+ ?pp <seg_&&x>,<word>,2,2
+ ?pp <off_&&x>,<word>,2,2
+ ?pp <&&x>,<dword>,0,4
+ endm
+ endif
+endm
+
+parmQ macro n
+ ?pp <n>,<qword>,8,8
+endm
+
+parmT macro n
+ ?pp <n>,<tbyte>,10,10
+endm
+
+if sizec
+ parmCP macro n
+ parmD <n>
+ endm
+else
+ parmCP macro n
+ parmW <n>
+ endm
+endif
+
+if sized
+ parmDP macro n
+ parmD <n>
+ endm
+else
+ parmDP macro n
+ parmW <n>
+ endm
+endif
+
+
+
+;; ?pp is the generalized parameter definition macro
+;;
+;; usage:
+;; ?pp m,t,l,s
+;;
+;; where:
+;; n is the name(s) of the parameters
+;; t is the type (word, dword)
+;; l is the length to update parameter byte count by
+;; s is the internal typing size
+
+
+?pp macro n,t,l,s ;;process parameter
+ if ?cpd ;;must be in a procedure definition
+ .xcref
+ irp x,<n>
+ .xcref ?t&&x ;;don't want this in xref
+ ?t&&x=s ;;save size info
+ ife ?PLM ;;if C calling convention
+ ?pp1 x,<t>,,,%(?po+?adj)
+ ?po=?po+l ;;update parameter offset
+ else ;;else assemble for PL/M
+ ?PLMPrevParm=?PLMPrevParm+1 ;;Show next parameter
+ ?po=?po+l ;;update parameter offset
+ ?pp1 x,<t>,%?po,%?adj,,%?PLMPrevParm,%(?PLMPrevParm-1)
+ endif
+ endm
+ .cref
+ else
+ ??error <parm(s) "&n" declared outside proc def>
+ endif
+endm
+
+
+
+;; ?pp1 is the macro that generates the text equate for the
+;; parameter. Two options exist, one for the C calling
+;; convention where the last parameter was the first pushed onto
+;; the stack ('C' convention), and one for the PL/M calling
+;; convention where the first parameter was the first
+;; pushed (also the same as ms-pascal).
+;;
+;; The text generated will be of one of two forms:
+;;
+;; name equ (type ptr [bp+(adj+offset)]) for C
+;; or
+;; name equ (type ptr [bp+adj+?po-offset]) for PL/M
+;;
+;;
+;; For C, since parameters are pushed first last, the offset
+;; plus the adjust will point to the correct parameter.
+;;
+;; For PL/M, since parameters are pushed first first, the offset
+;; of a parameter is much more complicated. A known portion of
+;; the offset can be computed when the text equate is generated.
+;;
+;; What is known is the number of garbage bytes between BP and
+;; the nearest parameter (in this case the last parameter), and
+;; also how many bytes of parameters have preceeded this parameter.
+;;
+;; What is unknown is how many total bytes of parameters there will
+;; be, which affects all the generated text equates since the offset
+;; from bp must be determined at some point.
+;;
+;; Well, the offset from BP can be computed with one variable if
+;; the following is remembered:
+;;
+;; the offset of any parameter from the first parameter is always
+;; the current parameter offset (?po).
+;;
+;; With this in mind, you just have to figure out where the first
+;; parameter is, which is:
+;;
+;; bp + garbage adjustment + distance to first parameter
+;; or
+;; bp + ?adj + ?po
+;;
+;; This implies that any parameter can be defined as:
+;;
+;; bp + ?adj + ?po -%?po
+;;
+;; Make any sense?
+;;
+;; For PL/M, a chain of self-purging macros will be generated
+;; which will pass the evaluated ?po to any previous incarnation
+;; of the macro. This will allow the text equate to be generated
+;; with the actual offset instead of the symbolic ?po.
+;;
+;;
+;; usage:
+;; ?pp1 n,t,o,a,b,cpc,ppc
+;;
+;; where:
+;; n is the name to be given the equate
+;; t is the type (byte, word, dword)
+;; o is the offset from the first parameter
+;; a is the adjustment
+;; b is the adjustment plus the offset from the first parameter
+;; cpc is the number of parameters so far
+;; ppc is cpc - 1
+
+
+?pp1 macro n,t,o,a,b,cpc,ppc
+ ife ?PLM ;;if to generate for C
+ n equ (t ptr [bp+b])
+ else ;;else generate for PL/M
+ .xcref
+ .xcref ?PLMParm&cpc
+ .cref
+ ?PLMParm&cpc &macro po
+ uconcat <n>,,<equ>,,<(t ptr [bp+>,%(a+po-o),<])>
+ ?PLMParm&ppc po
+ purge ?PLMParm&cpc
+ &endm
+ endif
+endm
+
+
+
+;; parmR - register parameter
+;;
+;; parmR is the macro used for generating register parameters.
+;; The space allocated for the register parameters will be
+;; the ?ia (interface adjust) area which is between the old
+;; BP and the first parameter. Normally this is empty (?ia=0),
+;; or has the saved ds for a windows far procedure.
+;;
+;; Byte and dword register parameters will be allowed.
+;;
+;; usage:
+;; parmR n,r,r2
+;; where:
+;; n is the name of the parameter
+;; r is the register it is in
+;; r2 is the offset register if a dword
+
+
+ifndef ?NOPARMR
+ if ?pmd
+ parmR macro n,r,r2
+ ??error <Sorry: ParmR can't be used with PMODE=1>
+ endm
+ else
+ .xcref
+ .xcref ?pr,parmR
+ .cref
+
+ parmR macro n,r,r2
+ ?pr n,r,r2,%?rp,%(?ia+2)
+ endm
+
+ ;; ?pr - register parameter
+ ;;
+ ;; ?pr is the actual macro for generating the equates for
+ ;; register parameters.
+ ;;
+ ;; usage:
+ ;; parmR n,r,r2,i,o
+ ;; where:
+ ;; n is the name of the parameter
+ ;; r is the register it is in
+ ;; r2 is the offset register if a dword
+ ;; i is the index of the ?rp to generate
+ ;; o is the offset from bp where the parm will be
+
+ ?pr macro n,r,r2,i,o
+ .xcref
+ ifnb <r2> ;;if a dword parameter
+ parmR seg_&n,r ;;define segment equate
+ parmR off_&n,r2 ;;define offset equate
+ n equ (dword ptr [bp-o-2]) ;;define dword equate
+ .xcref ?t&n
+ ?t&n=4 ;;show a dword to cmacros
+ else
+ .xcref ?rp&i
+ ?rp&i=0 ;;show no register(s)
+ ifdef ?&r ;;define register if valid
+ ?rp&i=?&r
+ endif
+
+ if ??? or (?cpd eq 0) or (?rp&i eq 0)
+ ??error <invalid parmR encountered: &n,&r>
+ exitm
+ endif
+
+ n equ (word ptr [bp-o]) ;;assume a word register
+ ?t&n=2 ;;show a word to cmacros
+ irp x,<bh,ch,dh,bl,cl,dl,ah,al>
+ if ?&&x eq ?&r ;;if really a byte register
+ n equ (byte ptr [bp-o]) ;; then make it a byte
+ ?t&n=1 ;;show a byte to cmacros
+ exitm
+ endif
+ endm
+ ?ia=?ia+2 ;;show this guy is out there
+ ?rp=?rp+1 ;;show one more register parameter
+ endif
+ .cref
+ endm
+ endif
+endif
+
+
+
+;; localx - generate reference to a local variable on the stack
+;;
+;; An equate is generated for addressing a local variable
+;; on the stack for the current procedural frame.
+;;
+;; usage:
+;; localx n
+;; where:
+;; x is the type b=byte, w=word, d=dword, v=variable size
+;; n is the name(s) to be given the variable(s).
+;;
+;; Bytes are considered to be two bytes long for alignment reasons
+;;
+;; The locald form of the macro generates three equates:
+;;
+;; name - for accessing the variable as a double word
+;; off_name - for accessing the offset (lsw) of the variable
+;; seg_name - for accessing the segment (msw) of the variable
+
+
+.xcref
+.xcref localB,localW,localD,localQ,localT,localCP,localDP,localV
+.cref
+
+localB macro n
+ ?aloc <n>,<byte ptr>,1,1,0 ;; no alignment
+endm
+
+localW macro n
+ ?aloc <n>,<word ptr>,2,2,1 ;; word aligned
+endm
+
+localD macro n
+ irp x,<n>
+ ?aloc <seg_&&x>,<word ptr>,2,2,1 ;; word aligned
+ ?aloc <off_&&x>,<word ptr>,2,2,1 ;; word aligned
+ ?aloc <&&x>,<dword ptr>,0,4,1 ;; word aligned
+ endm
+endm
+
+localQ macro n
+ ?aloc <n>,<qword ptr>,8,8,1 ;; word aligned
+endm
+
+localT macro n
+ ?aloc <n>,<tbyte ptr>,10,10,1 ;; word aligned
+endm
+
+if sizec
+ localCP macro n
+ localD <n>
+ endm
+else
+ localCP macro n
+ localW <n>
+ endm
+endif
+
+if sized
+ localDP macro n
+ localD <n>
+ endm
+else
+ localDP macro n
+ localW <n>
+ endm
+endif
+
+localV macro n,a
+ ?aloc <n>,,%(a),0,1 ;; word aligned
+endm
+
+
+;; ?aloc is the macro that actually allocates local storage.
+;; it is only invoked by the localx macros.
+;;
+;; usage:
+;; ?aloc n,t,l,s,a
+;; where:
+;; n is a list of names of local variable of the
+;; given type.
+;; t is the text string for the given variable
+;; and is one of:
+;; word ptr
+;; dword ptr
+;; byte ptr
+;; or alternatively left blank for variable size
+;; allocations (no implicit type).
+;; l is the size of the variable in bytes
+;; s is the internal type flag (size), and is one of:
+;; word - 2
+;; dword - 4
+;; byte - 1
+;; variable - 0
+;; a is a flag indicating that word alignment is to be
+;; forced for this type of item.
+;;
+;; NOTE: It is assumed that the stack is already aligned on a word
+;; boundary when the cProc is invoked. The macros will guarantee
+;; to allocate an even number of bytes on the stack to maintain
+;; word alignment.
+
+
+?aloc macro n,t,l,s,a
+ if ?cpd ;;must be in a proc def
+ .xcref
+ irp x,<n> ;;generate symbol equates
+ ???=???+l ;;update length of locals
+ if a ;;if align, then force word alignment
+ ???=((??? + 1) and 0fffeh)
+ endif
+ ?al1 x,<t>,%(???+?ia) ;;?ia will always be valid (0 or 2)
+ .xcref ?t&&x
+ ?t&&x=s ;;save size info
+ endm
+ .cref
+ else
+ ??error <locals "&n" declared outside procedure def>
+ endif
+endm
+
+
+
+;; ?al1 - allocate local, continued.
+;;
+;; ?al1 actually generates the text equate for the local variable.
+;; The form of the text equate generated is more or less:
+;;
+;; name equ (type ptr [bp-?ia-nn])
+;; or
+;; name equ ([bp-?ia-nn])
+;;
+;; where:
+;; ?ia is defined to be either zero, or is defined to be
+;; the number of bytes between the saved BP and the first
+;; local. ?ia is only applicable if the current cProc is
+;; a windows far procedure or if parmRs have been
+;; encountered. If not, the ?ia will be zero. since ?ia
+;; is determinable prior to invoking this macro, it will be
+;; added into the offset ("nn") passed to this macro
+;;
+;; usage:
+;; ?al1 n,t,o
+;; where:
+;; n is the name for the text equate
+;; t is the type of the equate
+;; o is the offset of the equate
+
+
+?al1 macro n,t,o
+ n equ (t [bp-o])
+endm
+
+
+;; ?gcc - get calling convention
+;;
+;; ?gcv sets the given symbol to the calling convention
+;; to be used.
+;;
+;; usage:
+;; ?gcc s,i,cc
+;;
+;; where:
+;; s is the symbol to return the convention in
+;; s = 0 if 'C' calling convention
+;; s = 1 if PL/M (PASCAL) calling convention
+;; i is the initial value for s
+;; cc is the calling convention override, and may be one of
+;; C use 'C' convention
+;; PLM use PL/M calling convention
+;; PASCAL use PL/M calling convention
+
+?gcc macro s,i,cc
+ s = i ;;Set default calling convention
+ ifnb <cc>
+ ifidn <cc>,<C> ;;If overriding default
+ s=0 ;; 'C' calling convention
+ endif
+ ifidn <cc>,<PLM>
+ s=1 ;; PL/M calling convention
+ endif
+ ifidn <cc>,<PASCAL>
+ s=1 ;; PL/M calling convention
+ endif
+ endif
+endm
+
+
+
+ifndef ?NOGLOBAL
+ .xcref
+ .xcref globalB,globalW,globalD,globalQ,globalT,globalCP,globalDP
+ .cref
+
+ ;; globalx - define global data of type x
+ ;;
+ ;; usage:
+ ;; globalx n,i,s,c
+ ;; where:
+ ;; x is the type of the variable b=byte, w=word, d=dword
+ ;; q=quad word, t=tenbytes, cp=code pointer, dp=data pointer
+ ;; n is the name to be given the variable.
+ ;; i is the initial value of the variable.
+ ;; s is the duplication factor
+ ;; c is the convention, C for C, PLM or PASCAL for PL/M.
+ ;; The default (?PLM flag) will be used if not specified.
+ ;;
+ ;; The D form will generate two extra equates of the form off_n and seg_n.
+
+ globalB macro n,i,s,c
+ ?ad <n>,1
+ ?dd n,1,<byte>,<db>,<i>,<s>,<c>
+ endm
+
+ globalW macro n,i,s,c
+ ?ad <n>,2
+ ?dd n,1,<word>,<dw>,<i>,<s>,<c>
+ endm
+
+ globalD macro n,i,s,c
+ ?ad <n>,4
+ ?dd n,1,<dword>,<dd>,<i>,<s>,<c>
+ off_&n equ n
+ seg_&n equ n[2]
+ endm
+
+ globalQ macro n,i,s,c
+ ?ad <n>,8
+ ?dd n,1,<qword>,<dq>,<i>,<s>,<c>
+ endm
+
+ globalT macro n,i,s,c
+ ?ad <n>,10
+ ?dd n,1,<tbyte>,<dt>,<i>,<s>,<c>
+ endm
+
+ if sizec
+ globalCP macro n,i,s,c
+ globalD n,<i>,<s>,<c>
+ endm
+ else
+ globalCP macro n,i,s,c
+ globalW n,<i>,<s>,<c>
+ endm
+ endif
+
+ if sized
+ globalDP macro n,i,s,c
+ globalD n,<i>,<s>,<c>
+ endm
+ else
+ globalDP macro n,i,s,c
+ globalW n,<i>,<s>,<c>
+ endm
+ endif
+
+endif
+
+
+ifndef ?NOSTATIC
+ .xcref
+ .xcref staticB,staticW,staticD,staticQ,staticT,staticCP,staticDP
+ .cref
+
+ ;; staticx - define static data of type x
+ ;;
+ ;; usage:
+ ;; staticx n,i,s
+ ;; where:
+ ;; x is the type of the variable b=byte, w=word, d=dword
+ ;; q=quad word, t=tenbytes, cp=code pointer, dp=data pointer
+ ;; n is the name to be given the variable.
+ ;; i is the initial value of the variable.
+ ;; s is the duplication factor
+ ;;
+ ;; statics do not generate an underscored version of the symbol
+ ;; since they are intended to be internal symbols. If they are
+ ;; required to be public, use globlax.
+
+
+ staticB macro n,i,s
+ ?ad <n>,1
+ ?dd n,0,<byte>,<db>,<i>,<s>,<PLM> ;;PLM to keep from generating _
+ endm
+
+ staticW macro n,i,s
+ ?ad <n>,2
+ ?dd n,0,<word>,<dw>,<i>,<s>,<PLM>
+ endm
+
+ staticD macro n,i,s
+ ?ad <n>,4
+ ?dd n,0,<dword>,<dd>,<i>,<s>,<PLM>
+ endm
+
+ staticQ macro n,i,s
+ ?ad <n>,8
+ ?dd n,0,<qword>,<dq>,<i>,<s>,<PLM>
+ endm
+
+ staticT macro n,i,s
+ ?ad <n>,10
+ ?dd n,0,<tbyte>,<dt>,<i>,<s>,<PLM>
+ endm
+
+ if sizec
+ staticCP macro n,i,s
+ staticD n,<i>,<s>
+ endm
+ else
+ staticCP macro n,i,s
+ staticW n,<i>,<s>
+ endm
+ endif
+
+ if sized
+ staticDP macro n,i,s
+ staticD n,<i>,<s>
+ endm
+ else
+ staticDP macro n,i,s
+ staticW n,<i>,<s>
+ endm
+ endif
+endif
+
+
+
+;; ?dd is the generalized data definition macro.
+;;
+;; format:
+;; ?dd n,p,t,d,i,s,c
+;; where:
+;; n is the name of the procedure
+;; p is the public flag
+;; t is the assembler type (byte, word, dword)
+;; d is the assembler directive (db,dw or dd)
+;; i is the initial value
+;; s is a duplication factor
+;; c is the convention, C for C, PLM or PSACAL for PL/M.
+;; The default (?PLM flag) will be used if not specified.
+
+
+?dd macro n,p,t,d,i,s,c
+ ?gcc ?dd2,%?PLM,<c> ;;Set calling convention
+ ife ?dd2 ;;If 'C'
+ n label t
+ ?dd1 _&n,p,<d>,<i>,<s> ;;Microsoft C uses leading underscores
+ else
+ ?dd1 n,p,<d>,<i>,<s> ;;If PL/M
+ endif
+endm
+
+
+
+;; ?dd1 is the generalized data definition macro.
+;;
+;; format:
+;; ?dd1 n,p,d,i,s
+;; where:
+;; n is the name of the procedure
+;; p is the public flag
+;; d is the assembler directive (db,dw or dd)
+;; i is the initial value
+;; s is a duplication factor
+
+
+?dd1 macro n,p,d,i,s
+ if p
+ public n
+ endif
+ ifb <s>
+ n d i
+ else
+ ifb <i>
+ n d s dup (?)
+ else
+ n d s dup (i)
+ endif
+ endif
+endm
+
+
+
+ifndef ?NOEXTERN
+ .xcref
+ .xcref ?ex1,?ex2,externB,externW,externD,externQ,externT
+ .xcref externNP,externFP,externP,externCP,externDP,externA
+ .cref
+ ?ex2 = 0
+
+ ;; externx - define external data of type x
+ ;;
+ ;; usage:
+ ;; externx n,c
+ ;; where:
+ ;; x is the type of the variable b=byte, w=word, d=dword
+ ;; q=quad word, t=tenbytes, cp=code pointer
+ ;; dp=data pointer, a=absolute
+ ;; n is a list of names to define
+ ;; c is the convention, C for C, PLM or PSACAL forPL/M.
+ ;; The default (?PLM flag) will be used if not specified.
+
+ externA macro n,c ;;40h is reserved for whatever will
+ ?ex1 <n>,40h,<abs>,<c>,<> ;; be done in the future for ASB
+ endm ;; externals
+
+ externB macro n,c
+ ?ex1 <n>,1,<byte>,<c>,<>
+ endm
+
+ externW macro n,c
+ ?ex1 <n>,2,<word>,<c>,<>
+ endm
+
+ externD macro n,c
+ ?ex1 <n>,4,<dword>,<c>,<>
+ endm
+
+ externQ macro n,c
+ ?ex1 <n>,8,<qword>,<c>,<>
+ endm
+
+ externT macro n,c
+ ?ex1 <n>,10,<tbyte>,<c>,<>
+ endm
+
+ externNP macro n,c
+ ?ex1 <n>,2,<near>,<c>,<cc>
+ endm
+
+ externFP macro n,c
+ ?ex1 <n>,4,<far>,<c>,<cc>
+ endm
+
+ if sizec
+ externP macro n,c
+ ?ex1 <n>,4,<far>,<c>,<cc>
+ endm
+ else
+ externP macro n,c
+ ?ex1 <n>,2,<near>,<c>,<cc>
+ endm
+ endif
+
+ if sizec
+ externCP macro n,c
+ ?ex1 <n>,4,<dword>,<c>,<>
+ endm
+ else
+ externCP macro n,c
+ ?ex1 <n>,2,<word>,<c>,<>
+ endm
+ endif
+
+ if sized
+ externDP macro n,c
+ ?ex1 <n>,4,<dword>,<c>,<>
+ endm
+ else
+ externDP macro n,c
+ ?ex1 <n>,2,<word>,<c>,<>
+ endm
+ endif
+
+
+
+ ;; ?ex1 is the generalized external definition macro
+ ;;
+ ;; format:
+ ;; ?ex1 n,s,d,c,scv
+ ;; where:
+ ;; n is are the names of the externals
+ ;; s is the size in bytes (used for typing)
+ ;; d is the type
+ ;; c is the convention, C for C, PLM or PSACAL for PL/M.
+ ;; The default (?PLM flag) will be used if not specified.
+ ;; scv save calling convention. If this field is "cc", then
+ ;; the calling convention will be saved in a ?CCn equ.
+
+ ?ex1 macro n,s,d,c,scv
+ ?gcc ?ex2,%?PLM,<c>
+ irp x,<n>
+ .xcref
+ .xcref ?t&&x
+ .cref
+ ?t&&x=s ;;save size info
+ ife ?ex2
+ extrn _&&x:&d
+ x equ _&&x
+ else
+ extrn x:&d
+ endif
+ ifidn <scv>,<cc> ;;save calling convention (C or PL/M)
+ .xcref ;; if NP, FP, or P
+ .xcref ?CC&&x
+ .cref
+ ?CC&&x=?ex2
+ endif
+ endm
+ endm
+endif
+
+
+
+ifndef ?NOLABEL
+ .xcref
+ .xcref ?lb1,?lblpu,?lb2
+ .xcref labelB,labelW,labelD,labelQ,labelT
+ .xcref labelNP,labelFP,labelP,labelCP,labelDP
+ .cref
+ ?lblpu = 0
+ ?lb2 = 0
+
+ ;; labelx - define label of data type x
+ ;;
+ ;; usage:
+ ;; labelx n,c
+ ;; where:
+ ;; x is the type of the variable b=byte, w=word, d=dword
+ ;; q=quad word, t=tenbytes, cp=code pointer, dp=data pointer
+ ;; n is a list of names to define, the first of which can
+ ;; be the keyword public
+ ;; c is the convention, C for C, PLM or PSACAL for PL/M.
+ ;; The default (?PLM flag) will be used if not specified.
+
+ labelB macro n,c
+ ?lb1 <n>,1,<byte>,<c>
+ endm
+
+ labelW macro n,c
+ ?lb1 <n>,2,<word>,<c>
+ endm
+
+ labelD macro n,c
+ ?lb1 <n>,4,<dword>,<c>
+ endm
+
+ labelQ macro n,c
+ ?lb1 <n>,8,<qword>,<c>
+ endm
+
+ labelT macro n,c
+ ?lb1 <n>,10,<tbyte>,<c>
+ endm
+
+ labelNP macro n,c
+ ?lb1 <n>,2,<near>,<c>
+ endm
+
+ labelFP macro n,c
+ ?lb1 <n>,4,<far>,<c>
+ endm
+
+ if sizec
+ labelP macro n,c
+ ?lb1 <n>,4,<far>,<c>
+ endm
+ else
+ labelP macro n,c
+ ?lb1 <n>,2,<near>,<c>
+ endm
+ endif
+
+ if sizec
+ labelCP macro n,c
+ ?lb1 <n>,4,<dword>,<c>
+ endm
+ else
+ labelCP macro n,c
+ ?lb1 <n>,2,<word>,<c>
+ endm
+ endif
+
+ if sized
+ labelDP macro n,c
+ ?lb1 <n>,4,<dword>,<c>
+ endm
+ else
+ labelDP macro n,c
+ ?lb1 <n>,2,<word>,<c>
+ endm
+ endif
+
+
+ ;; ?lb1 is the generalized label definition macro
+ ;;
+ ;; format:
+ ;; ?lb1 n,s,d
+ ;; where:
+ ;; n are the names of the labels
+ ;; s is the size in bytes (used for typing)
+ ;; d is the type
+ ;; c is the convention, C for C, PLM or PSACAL for PL/M.
+ ;; The default (?PLM flag) will be used if not specified.
+
+ ?lb1 macro n,s,d,c
+ ?gcc ?lb2,%?PLM,<c>
+ ?lblpu=0
+ irp x,<n>
+ ifidn <x>,<PUBLIC>
+ ?lblpu=1
+ else
+ .xcref
+ .xcref ?t&&x
+ .cref
+ ?t&&x=s ;;save size info
+ ife ?lb2 ;;If C
+ if ?lblpu
+ public _&&x
+ endif
+ _&&x label &d
+ x equ _&&x
+ else ;;If PL/M
+ if ?lblpu
+ public x
+ endif
+ x label &d
+ endif
+ endif
+ endm
+ endm
+endif
+
+
+
+ifndef ?NODEF
+
+ ;; defx - inform macros that name is of type x
+ ;;
+ ;; The given name(s) is flaged to be of the given type. This macro
+ ;; is intended for giving types to variables that were not generated
+ ;; by the macros (i.e., static storage). There must be a type definition
+ ;; for all parameters in a call list.
+ ;;
+ ;; usage:
+ ;; defx n
+ ;; where:
+ ;; x is the type of the variable b=byte, w=word, d=dword
+ ;; n is the name(s) to be given the variable(s).
+ ;;
+ ;; Bytes are considered to be two bytes long for alignment reasons
+
+ .xcref
+ .xcref defB,defW,defD,defQ,defT,defCP,defDP
+ .cref
+
+ defB macro n
+ ?ad <n>,1
+ endm
+
+ defW macro n
+ ?ad <n>,2
+ endm
+
+ defD macro n
+ ?ad <n>,4
+ endm
+
+ defQ macro n
+ ?ad <n>,8
+ endm
+
+ defT macro n
+ ?ad <n>,10
+ endm
+
+ if sizec
+ defCP macro n
+ defD <n>
+ endm
+ else
+ defCP macro n
+ defW <n>
+ endm
+ endif
+
+ if sized
+ defDP macro n
+ defD <n>
+ endm
+ else
+ defDP macro n
+ defW <n>
+ endm
+ endif
+endif
+
+
+
+; ?ad is the macro which creates a definition for the given
+; symbol
+;
+; usage:
+; ?ad <n>,s
+; where:
+; n is a list of names to define
+; s is the size info (1,2,4,8,10)
+
+
+?ad macro n,s
+ irp x,<n>
+ .xcref
+ .xcref ?t&&x
+ .cref
+ ?t&&x=s ;;save size info
+ endm
+endm
+
+
+
+ifndef ?NOPTR
+ .xcref
+ .xcref regPtr,farPtr
+ .cref
+
+ ;; regPtr generates information allowing a 32-bit pointer currently
+ ;; in a register to be pushed as a parameter to a subroutine using
+ ;; the cCall macro.
+ ;;
+ ;; usage:
+ ;; regptr n,s,o
+ ;; where:
+ ;; n is the name the argument will be known as
+ ;; s is the register containing the segment portion
+ ;; of the pointer
+ ;; o is the register containing the offset portion
+ ;; of the pointer
+ ;;
+ ;; 2/14/85 - made obsolete with farptr
+
+ regPtr macro n,s,o
+ farPtr n,s,o
+ endm
+
+
+
+ ;; farPtr generates information allowing a 32-bit pointer to be
+ ;; pushed as a parameter to a subroutine using the cCall macro.
+ ;;
+ ;; usage:
+ ;; farptr n,s,o
+ ;; where:
+ ;; n is the name the argument will be known as
+ ;; s is the segment portion of the pointer
+ ;; o is the offset portion of the pointer
+ ;;
+ ;; Note that any cast must have been made in the argument itself
+ ;; (i.e. regptr ptr1,ds,<word ptr 3[si]>)
+
+
+ farPtr macro n,s,o
+ .xcref
+ .xcref ?t&n
+ .cref
+ n &macro
+ push s ;@
+ push o ;@
+ &endm
+ ?t&n=80h
+ endm
+endif
+
+
+
+;; arg - declare argument
+;;
+;; The given argument(s) is added to the argument list structure
+;;
+;; format:
+;; arg a
+;;
+;; where:
+;; a is any valid argument to push.
+;;
+;; If any element in arglist has not been defined or isn't a 16-bit
+;; register, then a complete specification must have been given in a
+;; text equate and a defx also given (if not, you'll pay the penalty!)
+
+
+arg macro a
+ irp x,<a>
+ ?argc=?argc+1 ;;increment the arg count
+ ?atal <x>,%?argc ;;generate argument
+ endm
+endm
+
+
+
+;; ?atal (add to argument list) generates a macro that will cause
+;; the given argument to be processed when invoked. It is used by
+;; the arg macro only.
+
+
+?atal macro n,i
+ .xcref
+ .xcref ?ali&i
+ .cref
+ ?ali&i &macro
+ ?ap n
+ &endm
+endm
+
+
+
+;; ?ap - process arguments and place onto stack
+;;
+;; The given argument is processed (type checking) and place on
+;; the stack for a pending call. There must be a type definition
+;; for all arguments (except words). This can be done by using
+;; text equates and the defx macro.
+;;
+;; format:
+;; ?ap n
+;; where:
+;; n is the name of the argument to be pushed
+;;
+;; The variable ?argl is updated by the length of the arguments
+;; pushed so that the stack can be cleaned up after the call.
+
+
+?ap macro n
+ ?argl=?argl+2 ;;assume one word is pushed
+ ifdef ?t&n
+ ife ?t&n-1 ;;byte type
+ push word ptr (n) ;@
+ exitm
+ endif
+
+ ife ?t&n-2 ;;word type
+ push n ;@
+ exitm
+ endif
+
+ ife ?t&n-4 ;;dword type
+ push word ptr (n)[2] ;@
+ push word ptr (n) ;@
+ ?argl=?argl+2
+ exitm
+ endif
+
+ ife ?t&n-8 ;;qword type
+ push word ptr (n)[6] ;@
+ push word ptr (n)[4] ;@
+ push word ptr (n)[2] ;@
+ push word ptr (n) ;@
+ ?argl=?argl+6
+ exitm
+ endif
+
+ if ?t&n and 80h ;;far pointer type
+ n
+ ?argl=?argl+2
+ exitm
+ endif
+
+ ife ?t&n ;;variable storage
+ push word ptr (n) ;@
+ exitm
+ endif
+ endif
+
+ push n ;;unknown or register or immediate ;@
+endm
+
+
+
+;; cCall - call a 'c' language procedure
+;;
+;; The given procedure is called with the given parameters.
+;; If the calling convention is C, the arguments are pushed
+;; in reverse order, and removed after the called procedure
+;; returns. If the calling conventing is PL/M, the arguments
+;; are pushed as they were encountered, and the called procedure
+;; is assumed to have removed them from the stack.
+;;
+;; The calling convention priority will be:
+;; 1) that specified on the cCall if present
+;; 2) that defined by the target
+;; 3) the default (?PLM flag)
+;;
+;; format:
+;; ccall n,<a>,c
+;;
+;; where:
+;; n is the name of the procedure to call
+;; a are arguments to be pushed (optional, may be
+;; specified with the "arg" macro.
+;; c is the convention, C for C, PLM or PSACAL for PL/M.
+;; The default (?PLM flag) will be used if not specified.
+
+
+cCall macro n,a,c
+ ifnb <a> ;;add any arguments to list
+ arg <a>
+ endif
+ mpush %?rsl ;;save registers (if any)
+
+ ifdef ?CC&n ;;if calling convention has been
+ ?cCall1=?CC&n ;; defined for target, use it
+ else ;;else use the default
+ ?cCall1=?PLM
+ endif
+
+ ifnb <c> ;;If possible override, check it out
+ ?gcc ?cCall1,%?cCall1,<c>
+ endif
+
+ ?argl=0 ;;init argument length
+ ife ?cCall1 ;;if C calling convention
+ ?acb=?argc ;;initialize for looping
+ else
+ ?acb=1 ;;initialize for looping
+ endif
+
+ rept ?argc ;;push arguments and purge macros
+ uconcat <?ali>,%?acb
+ uconcat <purge>,,<?ali>,%?acb
+ ife ?cCall1 ;;if C calling convention
+ ?acb=?acb-1
+ else
+ ?acb=?acb+1
+ endif
+ endm
+ call n ;;call the procedure ;@
+ if ((?cCall1 eq 0) and (?argl ne 0)) ;;If C calling convention and arguments
+ add sp,?argl ;; then remove them ;@
+ endif
+ mpop %?rsl ;;pop all specified regs
+ ?rsl=0 ;;invalidate save list
+ ?argc= 0 ;; " arguments
+ ?argl= 0
+endm
+
+
+
+
+;; cProc - define a 'c' procedure
+;;
+;; cProc is the procedure definition for procedures.
+;;
+;; format:
+;; cProc n,cf,a
+;; where:
+;; n is the name of the procedure
+;;
+;; cf controls certain definitions, and may be:
+;; NEAR proc is to be a near label
+;; FAR proc is to be a far label
+;; PUBLIC proc is to be defined as public
+;; SMALL call makeframe procedure
+;; NODATA dont create prolog code to setup DS
+;; ATOMIC don't link stack if not needed
+;; NODATA must be specified for ATOMIC
+;; FORCEFRAME Force generation of a frame
+;; NOTE: FORCEFRAME no longer supported
+;; C proc is to be a C procedure
+;; PLM proc is to be a PL/M procedure
+;; PASCAL proc is to be a PL/M procedure
+;; WIN proc is to be a windows procedure
+;; NONWIN proc isn't to be a windows procedure
+;; LOADDS Preserve & set DS to _DATA
+;; EXPORTED mov ax,ds, nop at start of routine
+;;
+;; a is a list of registers that are to be saved whenever
+;; the procedure is invoked.
+;;
+;; makeframe procedure: If small is specified, then
+;; the "makeframe procedure" is invoked instead of
+;; generating normal prologues/epilogues
+;;
+;; A call is performed to the makeframe procedure. The
+;; call is followed by two bytes. the first byte is the
+;; number of locals to allocate for the frame, the second
+;; is the number of bytes of parameters. The makeframe
+;; procedure will in turn call the cProc routine at the
+;; address following the data bytes. When the cProc is
+;; finished, it will do a near return to the makeframe
+;; procedure to clean up the frame and exit.
+;;
+;; Note that register parameters and makeframe are
+;; incompatible and cannot be used together.
+;;
+;; The makeframe procedure will save SI, DI, and also
+;; DS if a far procedure. These registers will be
+;; removed from the autosave list if specified.
+
+
+cProc macro n,cf,a
+ if ?cpd
+ ?utpe ;;generate unterminated proc error
+ endif
+
+ ?cpd=1 ;;a procdef is active now
+ ???=0 ;;no locals are defined yet
+ ?argc=0 ;;no arguments are defined
+ ?ba=0 ;;not in a procedure
+ ?po=0 ;;initial parameter offset
+ ?pu=0 ;;initial public setting
+ ?ia=0 ;;no special prolog/epilog
+ ?adj=4 ;;parameter adjustment (near ret+bp)
+ ?rp=0 ;;no register parameters
+ ?uf=0 ;;don't use makeframe
+ ?wfp=?WIN ;;default far procedure (win or not)
+ ?ff=0 ;;don't force frame setup
+ ?pas=0 ;;process register save list
+ ?pcc=?PLM ;;calling convention (C or PL/M)
+ ?lds=0 ;;no LOADDS
+ ?exp=0 ;;not EXPORTED
+
+ ifnb <a> ;;register save list
+ ?ri ?pas,<a>
+ endif
+
+ ?pc=sizec ;;default size
+ ?nd=?nodata1 ;;default NODATA flag
+ ?nx=0 ;;default is not ATOMIC
+ irp x,<cf>
+ ifidn <x>,<FAR> ;;if far,
+ ?pc=1 ;; set far flag
+ endif
+ ifidn <x>,<NEAR> ;;if near,
+ ?pc=0 ;; set near flag
+ endif
+ ifidn <x>,<PUBLIC> ;;if public,
+ ?pu=1 ;; set public flag
+ endif
+ ifidn <x>,<SMALL> ;;if small
+ ?uf=1 ;; set small flag
+ endif
+ ifidn <x>,<DATA> ;;if data
+ ?nd=0 ;; reset NODATA flag
+ endif
+ ifidn <x>,<NODATA> ;;if NODATA
+ ?nd=1 ;; set NODATA flag
+ endif
+ ifidn <x>,<ATOMIC> ;;if ATOMIC
+ ?nx=1 ;; set ATOMIC flag
+ endif
+ ifidn <x>,<C> ;;if to force C calling convention
+ ?pcc=0 ;; set flag
+ endif
+ ifidn <x>,<PLM> ;;if to force PLM calling convention
+ ?pcc=1 ;; set flag
+ endif
+ ifidn <x>,<PASCAL> ;;if to force PLM calling convention
+ ?pcc=1 ;; set flag
+ endif
+ ifidn <x>,<WIN> ;;if to force a Window's frame
+ ?wfp=1 ;; set flag
+ endif
+ ifidn <x>,<NONWIN> ;;if not to be a Window's frame
+ ?wfp=0 ;; set flag
+ endif
+ ifidn <x>,<LOADDS> ;; Preserve & setup DS
+ ?lds=1
+ endif
+ ifidn <x>,<EXPORTED>
+ ?exp=1
+ endif
+ endm
+
+ if ?pcc ;;If PLM
+ ?PLMPrevParm=0 ;; show no previous parameter
+ .xcref
+ .xcref ?PLMParm0
+ .cref
+ ?PLMParm0 &macro ;;Null macro to terminate
+ purge ?PLMParm0
+ &endm
+ endif
+
+ .xcref
+ .xcref ?CC&n
+ .cref
+ ?CC&n=?pcc ;;Save procedure type
+
+ if (?nx eq 1) and (?nd eq 0) ;;ATOMIC requires NODATA
+ ?nx = 0 ;;clear the ATOMIC keyword
+ ??error <ATOMIC specified without NODATA - ATOMIC ignored>
+ endif
+
+ if ?pc ;;if a far procedure
+ if ?wfp+?exp+?lds ;;if windows, EXPORTED, or LOADDS
+ ife ?nx ;;and not ATOMIC
+ ife ?pmd ;;If PMODE, no adjustment needed
+ ?ia=2 ;; adjust locals for saved ds
+ endif
+ ?pas = ?pas and (not ?ds) ;;no need for extra save
+ endif
+ endif
+ ?adj=?adj+2 ;;far, make parameter adjustment
+ else
+ ?wfp=0 ;;not a far windows procedure
+ endif
+
+ ife ?386regs
+ ?pas = ?pas and (not (?sp+?cs+?ss)) ;;make no sense to save these
+ endif
+
+ if ?uf ;;don't save these if user frame
+ if ?386regs
+ ?pas = ?pas and (not (?si+?di))
+ else
+ ?pas = ?pas and (not (?bp+?si+?di))
+ endif
+ endif
+
+ ife ?pcc
+ ?pg <_&n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+ else
+ ?pg <n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+ endif
+endm
+
+
+;; ?pg - generate begin and nested macros for current procedure
+;;
+;; format:
+;; ?pg n,p,c,a,w,nnu,cc
+;; where:
+;; n is the name of the procedure
+;; p is the public flag
+;; c is the class definition for the procedure
+;; a is an enumerated list of registers to save
+;; at entry and restore at exit
+;; w true if a far windows procedure
+;; nnu procedure name without any underscore
+;; cc calling convention (C or PL/M)
+;;
+;;
+;; local stack allocation will be forced to an even byte count to
+;; maintain stack word alignment.
+
+;;
+;;
+
+
+?pg macro n,p,c,a,w,nnu,cc
+ .xcref
+ if ?uf ;;if user frame
+ if ?nd
+ ??error <NODATA encountered in &n - user frame ignored>
+ ?uf=0
+ endif
+ endif
+
+ .xcref cBegin
+ cBegin &macro g ;;generate cBegin macro
+ .xcref
+ if cc ;;Finish definition of parameters
+ uconcat <?PLMParm>,%?PLMPrevParm,%?po
+ endif
+
+ if ?uf ;;if user frame
+ if ?rp
+ ??error <parmR encountered in &n - user frame ignored>
+ ?uf=0
+ endif
+ endif
+ ?pg1 <n>,c,a,%?po,w,%?uf,%?nd,%?rp,cc ;;generate cEnd macro
+ ?cpd=0 ;;terminate current proc def
+ ?argc=0 ;;no arguments are defined yet
+ ?ba=1 ;;have reached a begin
+ ???=(???+1) and 0fffeh ;;word align local storage
+
+ if p ;;If to be public
+ public n
+ endif
+
+ ife c ;;declare procedure type
+ n proc near
+ else
+ n proc far
+ endif
+
+ ife cc ;;if 'C' calling convention
+ nnu equ n ;; generate label without underscore
+ endif
+
+ ifidn <g>,<nogen> ;;if nogen specified, shouldn't have
+ if ???+?po+a+?rp ;; parms, locals, or saved regs
+ ??_out <cBegin - possible invalid use of nogen>
+ endif
+ else ;;must generate a frame
+ if ?uf ;;if user frame code specified
+ ?mf c,%???,%?po ;; call user's makeframe
+ mpush a ;; save specified registers
+ else
+
+ if w+?exp+?lds ;;if a far windows procedure
+
+ if ?pmd ;;if protect mode:
+ ife ?nd ;; if not NODATA
+ if ?lds ;; and LOADDS
+ mov ax,_DATA ;; ax = _DATA
+ else ;; else if EXPORTED
+ if ?exp
+ mov ax,ds ;; ax = DS
+ nop ;;
+ endif
+ endif
+ endif
+
+ ife ?nx ;;!ATOMIC:
+ if ???+?po ;; or there are no locals or params
+ if ?chkstk1 ;; if stack checking,
+ push bp ;; we can't use ENTER
+ mov bp,sp
+ else
+ if ??? ;; If there are locals, use ENTER
+ enter ???,0
+ else
+ push bp ;; otherwise it's smaller/faster
+ mov bp,sp ;; to use standard sequence
+ endif
+ endif
+ endif
+
+ push ds ;; preserve DS
+
+ if ?lds+?exp ;; if LOADDS or EXPORTED
+ mov ds,ax ;; set up new DS
+ endif
+ else ;;ATOMIC:
+ if ?ff+???+?po+?rp ;;if any locals or parameters
+ push bp ;; then must set frame pointer ;@
+ mov bp,sp ;; to be able to access them ;@
+ endif
+ endif
+
+ else ;; !?pmd
+
+ ife ?nd ;;if not NODATA,
+ mov ax,ds ;; then set AX = currentds, and ;@
+ nop ;; leave room for MOV AX,_DATA ;@
+ endif
+ ife ?nx ;;if not ATOMIC, far frame must be set
+ ife ?DOS5 ;;if not DOS5, then set far frame flag
+ inc bp ;; by incrementing the old bp ;@
+ endif
+ push bp ;@
+ mov bp,sp ;@
+ push ds ;@
+ else ;;ATOMIC procedure
+ if ?ff+???+?po+?rp ;;if any locals or parameters
+ push bp ;; then must set frame pointer ;@
+ mov bp,sp ;; to be able to access them ;@
+ endif
+ endif
+ ife ?nd ;;if not NODATA, then AX should
+ mov ds,ax ;; have the ds to use ;@
+ endif
+
+ endif ;; !?pmd
+
+ else ;;not windows. use standard prolog
+
+ if ?pmd ;;protect mode:
+
+ if ?exp
+ mov ax,ds ;; If EXPORTED, generate patchable
+ nop ;; instruction.
+ else
+ if ?lds ;; If LOADDS, set up AX = _DATA
+ mov ax,_DATA
+ endif
+ endif
+
+ if ?ff+???+?po+?rp ;; If frame needed...
+ if ?chkstk1 ;; if stack checking,
+ push bp ;; we can't use ENTER
+ mov bp,sp
+ else
+ if ??? ;; If there are locals, use ENTER
+ enter ???,0
+ else
+ push bp ;; otherwise it's smaller/faster
+ mov bp,sp ;; to use standard sequence
+ endif
+ endif
+ endif
+
+ if ?exp+?lds ;;if EXPORTED or LOADDS
+ push ds ;; preserve DS
+ mov ds,ax ;; and set up new one.
+ endif
+
+ else ;; ! ?pmd
+ if ?ff+???+?po+?rp ;;if any locals or parameters
+ push bp ;; then must set frame pointer ;@
+ mov bp,sp ;; to be able to access them ;@
+ endif
+ endif ;; ! ?pmd
+
+ endif ;; ! w
+
+ if ?rp ;;if parmR's, push them before
+ ?uf=0 ;; allocating locals and saving
+ rept ?rp ;; the autosave registers
+ uconcat mpush,,?rp,%?uf
+ ?uf=?uf+1
+ endm
+ endif
+
+ if ??? ;;if locals to allocate
+ if ?chkstk1 ;;if stack checking enabled
+ ifdef ?CHKSTKPROC ;;if user supplied stack checking
+ ?CHKSTKPROC %??? ;; invoke it with bytes requested
+ else
+ mov ax,??? ;;invoke default stack checking ;@
+ ife cc
+ call _chkstk ;@
+ else
+ call chkstk ;@
+ endif
+ endif
+ else ;;no stack checking
+ ife ?pmd ;;no need if in pmode (we used enter)
+ sub sp,??? ;; allocate any local storage ;@
+ endif
+ endif
+ endif
+
+ mpush a ;;save autosave registers
+ endif
+
+ ifdef ?PROFILE ;;if profiling enabled
+ if c ;; and a far procedure
+ call StartNMeas ;; invoke profile start procedure ;@
+ endif
+ endif
+
+ endif
+
+ .cref
+ purge cBegin ;;remove the macro
+ &endm ;;end of cBegin macro
+
+ .xcref ?utpe
+ ?utpe &macro
+ ??error <unterminated procedure definition: "&n">
+ &endm
+ .cref
+endm ;;end of ?pg macro
+
+
+
+
+;; ?pg1 - generate end macro for current procedure
+;;
+;; format:
+;; ?pg1 n,c,a,o,w,f,d,r,cc
+;; where:
+;; n is the name of the procedure
+;; c is the class definition for the procedure
+;; a is an enumerated list of registers to save
+;; at entry and restore at exit
+;; o is the number of bytes of paramteres to remove at exit
+;; w true if a far windows procedure
+;; f is 1 if to use the user's makeframe procedure
+;; d is 1 if NODATA procedure
+;; r number of register parameters
+;; cc calling convention (C or PL/M)
+
+
+?pg1 macro n,c,a,o,w,f,d,r,cc
+ .xcref
+ .xcref cEnd
+ cEnd &macro g ;;start of cEnd macro
+ .xcref
+ ?ba=0 ;;no longer in a procedure
+
+ ifidn <g>,<nogen> ;;validate nogen usage
+ if o+a+r
+ ??_out <cEnd - possible invalid use of nogen>
+ endif
+ else ;;must generate an epilog
+ ifdef ?PROFILE ;;if profiling enabled
+ if c ;; and a far procedure
+ call StopNMeas ;; invoke profile stop procedure
+ endif ;; (doesn't trash DX:AX)
+ endif
+
+ mpop a ;;restore autosaved registers
+ if f ;;if to use the "makeframe" procedure
+ db 0c3h ;; near return to user's makeframe @
+ else
+ if w+?exp+?lds ;;if far win proc, use special epilog
+ if ?pmd
+ ife ?nx
+ pop ds ;; if not ATOMIC, restore DS
+ endif
+
+ ife ?nx ;; if not ATOMIC and no locals
+ if ?chkstk1+???+?po
+ leave
+ endif
+ else ;;ATOMIC:
+ if ?ff+???+?po+?rp ;;if any parameters
+ leave ;; fix up BP & exit
+ endif
+ endif
+
+ else ;; !?pmd
+ ife ?nx ;;if not ATOMIC, bp was pushed
+ if (?TF eq 0) or (???+?rp) ;;if cannot assume valid sp
+ lea sp,-2[bp] ;; or locals or parmR's, get valid SP @
+ endif
+ pop ds ;;restore saved ds and bp @
+ pop bp ;; @
+ ife ?DOS5 ;;if not DOS5, bp was
+ dec bp ;; incremented to mark far frame @
+ endif
+ else ;;ATOMIC frame was set up
+ if (?TF eq 0) or (???+?rp) ;;if cannot assume valid sp
+ mov sp,bp ;; or locals or parmR's, get valid SP @
+ endif
+ if ???+?po+?rp
+ pop bp ;@
+ endif
+ endif
+ endif ;; !?pmd
+ else ;;non-windows standard epilog
+ if ?pmd
+ if ?ff+???+?po+?rp ;;if any parameters
+ leave
+ endif
+ else
+ if ?ff+???+?po+?rp ;;if any parameters
+ if (?TF eq 0) or (???+?rp) ;;if cannot assume valid SP
+ mov sp,bp ;; or locals or parmR's, get valid SP;@
+ endif
+ pop bp ;@
+ endif
+ endif
+ endif
+
+ ife cc ;;if C calling convention
+ ret ;; return ;@
+ else ;;else
+ ret o ;; return and remove paramteres ;@
+ endif
+ endif
+ endif
+ n endp ;;end of process
+ .cref
+ purge cEnd ;;remove the macro
+ &endm
+ .cref
+endm
+
+
+
+
+; assumes is a macro that will set up the assumes for a segment
+; or group created with the createSeg macro. If the assumed
+; value passed in isn't known, then a normal assume is made.
+;
+; usage:
+; assumes s,g
+;
+; where:
+; s is the register to make the assumption about
+; g is the value to assume is in it
+
+
+assumes macro s,ln
+ ifndef ln&_assumes
+ assume s:ln
+ else
+ ln&_assumes s
+ endif
+endm
+
+
+
+; createSeg is a macro that sets up a segment definition and
+; a logical name for that segment. The logical name can be
+; used to enter the segment, but it cannot be used for anything
+; else.
+;
+; usage:
+; createSeg n,ln,a,co,cl,grp
+; where:
+; n is the physical name of the segment
+; ln is the name it is to be invoked by
+; a is the alignment, and is optional
+; co is the combine type, and is optional
+; cl is the class, and is optional
+; grp is the name of the group that contains this segment
+
+
+createSeg macro n,ln,a,co,cl,grp
+ ifnb <grp>
+ addseg grp,n
+ else
+ ln&OFFSET equ offset n:
+ ln&BASE equ n
+ ?cs3 <ln>,<n>
+ endif
+ ifnb <cl>
+ n segment a co '&cl'
+ else
+ n segment a co
+ endif
+ n ends
+ ?cs1 <ln>,<n>
+endm
+
+
+addseg macro grp,seg
+ .xcref
+ .xcref grp&_def
+ .cref
+ ifndef grp&_def
+ grp&_def=0
+ endif
+ if grp&_def ne ASMpass
+ .xcref
+ .xcref grp&_add
+ .cref
+ grp&_add &macro s
+ grp&_in <seg>,s
+ &endm
+ .xcref
+ .xcref grp&_in
+ .cref
+ grp&_in &macro sl,s
+ ifb <s>
+ grp group sl
+ else
+ grp&_add &macro ns
+ grp&_in <sl,s>,ns
+ &endm
+ endif
+ &endm
+ grp&_def=ASMpass
+ else
+ grp&_add seg
+ endif
+endm
+
+
+defgrp macro grp,ln
+ addseg grp
+ ifnb <ln>
+ irp x,<ln>
+ ?cs3 <&x>,<grp>
+ x&&OFFSET equ offset grp:
+ x&&BASE equ grp
+ endm
+ endif
+endm
+
+
+?cs1 macro ln,n
+ .xcref
+ .xcref ln&_sbegin
+ .cref
+ ln&_sbegin &macro
+ .xcref
+ .xcref ?mf
+ .cref
+ ?mf &&macro c,l,p ;;when sBegin is invoked, generate
+ if c ;; the makeframe macro
+ extrn n&_FARFRAME:near ;; make frame for far procedures ;@
+ call n&_FARFRAME ;@
+ else
+ extrn n&_NEARFRAME:near ;; make frame for near procedures ;@
+ call n&_NEARFRAME ;@
+ endif
+ db l shr 1 ;;define number of locals ;@
+ db p shr 1 ;;define number of parameters ;@
+ &&endm
+ ?cs2 <ln>,<n>
+ n segment
+ &endm
+endm
+
+
+?cs2 macro ln,n
+ .xcref
+ .xcref sEnd
+ .cref
+ sEnd &macro
+ n ends
+ purge ?mf ;;delete the makeframe macro
+ purge sEnd
+ &endm
+endm
+
+
+?cs3 macro ln,n
+ .xcref
+ .xcref ln&_assumes
+ .cref
+ ln&_assumes &macro s
+ assume s:&n
+ &endm
+endm
+
+
+
+; sBegin is the macro that opens up the definition of a segment.
+; The segment must have already been defined with the createSeg
+; macro.
+;
+; usage:
+; sBegin ln
+;
+; where:
+; ln is the logical name given to the segment when
+; it was declared.
+
+.xcref
+.xcref sBegin
+.cref
+sBegin macro ln
+ ln&_sbegin
+endm
+
+
+
+ife ?DF
+
+ ; Define all segments that will be used. This will allow the
+ ; assume and groups to be set up at one given place, and also
+ ; allow quick changes to be made
+ ;
+ ; createSeg name,logname,align,combine,class,group
+
+ createSeg _TEXT,Code,word,public,CODE
+ ife ?nodata1
+ createSeg _DATA,Data,word,public,DATA,DGROUP
+ defgrp DGROUP,Data
+ endif
+
+ if ?chkstk1
+ ifndef ?CHKSTKPROC
+ externp <chkstk>
+ endif
+ endif
+endif
+
+
+
+; errnz exp - generate error message if expression isn't zero
+;
+; The errnz will generate an error message if the expression "exp"
+; does not evaluate to zero. This macro is very useful for testing
+; relationships between items, labels, and data that was coded into
+; an application.
+;
+; errnz <offset $ - offset label> ;error if not at "label"
+; errnz <eofflag and 00000001b> ;eofflag must be bit 0
+;
+; For expressions involving more than one token, the angle brackets
+; must be used.
+;
+; The macro is only evaluated on pass 2, so forward references may be
+; used in the expression.
+
+errnz macro x ;;display error if expression is <>0
+ if2
+ if x ;;if expression is non-zero,
+ errnz1 <x>,%(x)
+ endif
+ endif
+endm
+
+errnz1 macro x1,x2
+ = *errnz* x1 = x2
+ .err
+endm
+
+
+
+; errn$ label,exp - generate error message if label (exp) <> $
+;
+; The errnz will generate an error message if the label and "exp"
+; does not evaluate to the current value of the location counter.
+; This macro is very useful for testing relationships between
+; labels and the location counter that was coded into an application.
+;
+; examples: errn$ label ;error if not at "label"
+; errn$ label,+3 ;error if not three bytes from "label"
+; errn$ label,-3 ;error if not three bytes past "label"
+;
+; If no "exp" is given, it is the same as specifying 0
+;
+; The macro is only evaluated on pass 2, so forward references may be
+; used in the expression.
+
+errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
+ errnz <offset $ - offset l x>
+endm
+
+
+
+;; If profile has been specified, declare the profile routines
+;; to be external and far. It would be best if this could be done
+;; when the call is actually made, but then the fix-up would be
+;; generated as segment-relative.
+
+
+ifdef ?PROFILE
+ externFP <StartNMeas,StopNMeas>
+endif
diff --git a/private/mvdm/wow16/inc/cmstrip.c b/private/mvdm/wow16/inc/cmstrip.c
new file mode 100644
index 000000000..402724258
--- /dev/null
+++ b/private/mvdm/wow16/inc/cmstrip.c
@@ -0,0 +1,102 @@
+/*
+ stripper: strips asm comments, blanks lines, and spurious spaces
+ (except spaces following the exception strings, listed below.)
+*/
+
+#include <stdio.h>
+
+char *
+ScanWhite( ps )
+char **ps;
+{
+ char *s = *ps;
+
+ while (*s != ' ' && *s != '\t' && *s)
+ s++;
+ *ps = s;
+ if (*s)
+ return s;
+ else
+ return NULL;
+}
+
+char *
+SkipWhite( ps )
+char **ps;
+{
+ char *s = *ps;
+
+ while (*s == ' ' || *s == '\t')
+ s++;
+ *ps = s;
+ if (*s)
+ return s;
+ else
+ return NULL;
+}
+
+char inBuf[ 256 ];
+char outBuf[ 256 ];
+
+
+main()
+{
+ char
+ *inStr,
+ *outStr,
+ *str;
+ int inLen,
+ outLen,
+ tabcnt;
+
+ long totSaved = 0L;
+
+ unlink( "cmacros.bak" ); /* */
+ rename( "cmacros.bak", "cmacros.inc" ); /* */
+ freopen( "cmacros.mas", "r", stdin ); /* */
+ freopen( "cmacros.inc", "w", stdout ); /* */
+ fprintf( stderr, "cmacros.mas => cmacros.inc" );
+ fflush( stderr );
+
+ while (inStr = gets( inBuf ))
+ {
+ inLen = strlen( inBuf );
+ outStr = outBuf;
+
+ tabcnt=0;
+ if (inBuf[inLen-1] == '@')
+ tabcnt=1;
+
+ while (SkipWhite( &inStr ))
+ {
+ if (*inStr == ';')
+ break;
+
+ str = inStr;
+ ScanWhite( &inStr );
+ if (tabcnt > 0 && tabcnt < 3)
+ {
+ *outStr++ = '\t';
+ tabcnt++;
+ }
+ else
+ {
+ if (outStr != outBuf)
+ *outStr++ = ' ';
+ }
+ while (str != inStr)
+ *outStr++ = *str++;
+ }
+
+ if (outLen = outStr - outBuf)
+ {
+ *outStr++ = 0;
+ puts( outBuf );
+ }
+
+ totSaved += (inLen - outLen);
+ }
+
+ fprintf( stderr, " [OK] %ld blanks stripped\n", totSaved );
+ exit( 0 );
+}
diff --git a/private/mvdm/wow16/inc/commdlg.h b/private/mvdm/wow16/inc/commdlg.h
new file mode 100644
index 000000000..723f7b4d3
--- /dev/null
+++ b/private/mvdm/wow16/inc/commdlg.h
@@ -0,0 +1,318 @@
+/*****************************************************************************\
+* *
+* commdlg.h - Common dialog functions, types, and definitions *
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_COMMDLG
+#define _INC_COMMDLG
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef WINAPI /* If not included with 3.1 headers... */
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+typedef struct tagOFN
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HINSTANCE hInstance;
+ LPCSTR lpstrFilter;
+ LPSTR lpstrCustomFilter;
+ DWORD nMaxCustFilter;
+ DWORD nFilterIndex;
+ LPSTR lpstrFile;
+ DWORD nMaxFile;
+ LPSTR lpstrFileTitle;
+ DWORD nMaxFileTitle;
+ LPCSTR lpstrInitialDir;
+ LPCSTR lpstrTitle;
+ DWORD Flags;
+ UINT nFileOffset;
+ UINT nFileExtension;
+ LPCSTR lpstrDefExt;
+ LPARAM lCustData;
+ UINT (CALLBACK *lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpTemplateName;
+} OPENFILENAME;
+typedef OPENFILENAME FAR* LPOPENFILENAME;
+
+BOOL WINAPI GetOpenFileName(OPENFILENAME FAR*);
+BOOL WINAPI GetSaveFileName(OPENFILENAME FAR*);
+int WINAPI GetFileTitle(LPCSTR, LPSTR, UINT);
+
+#define OFN_READONLY 0x00000001
+#define OFN_OVERWRITEPROMPT 0x00000002
+#define OFN_HIDEREADONLY 0x00000004
+#define OFN_NOCHANGEDIR 0x00000008
+#define OFN_SHOWHELP 0x00000010
+#define OFN_ENABLEHOOK 0x00000020
+#define OFN_ENABLETEMPLATE 0x00000040
+#define OFN_ENABLETEMPLATEHANDLE 0x00000080
+#define OFN_NOVALIDATE 0x00000100
+#define OFN_ALLOWMULTISELECT 0x00000200
+#define OFN_EXTENSIONDIFFERENT 0x00000400
+#define OFN_PATHMUSTEXIST 0x00000800
+#define OFN_FILEMUSTEXIST 0x00001000
+#define OFN_CREATEPROMPT 0x00002000
+#define OFN_SHAREAWARE 0x00004000
+#define OFN_NOREADONLYRETURN 0x00008000
+#define OFN_NOTESTFILECREATE 0x00010000
+
+/* Return values for the registered message sent to the hook function
+ * when a sharing violation occurs. OFN_SHAREFALLTHROUGH allows the
+ * filename to be accepted, OFN_SHARENOWARN rejects the name but puts
+ * up no warning (returned when the app has already put up a warning
+ * message), and OFN_SHAREWARN puts up the default warning message
+ * for sharing violations.
+ *
+ * Note: Undefined return values map to OFN_SHAREWARN, but are
+ * reserved for future use.
+ */
+
+#define OFN_SHAREFALLTHROUGH 2
+#define OFN_SHARENOWARN 1
+#define OFN_SHAREWARN 0
+
+typedef struct tagCHOOSECOLOR
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HWND hInstance;
+ COLORREF rgbResult;
+ COLORREF FAR* lpCustColors;
+ DWORD Flags;
+ LPARAM lCustData;
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpTemplateName;
+} CHOOSECOLOR;
+typedef CHOOSECOLOR FAR *LPCHOOSECOLOR;
+
+BOOL WINAPI ChooseColor(CHOOSECOLOR FAR*);
+
+#define CC_RGBINIT 0x00000001
+#define CC_FULLOPEN 0x00000002
+#define CC_PREVENTFULLOPEN 0x00000004
+#define CC_SHOWHELP 0x00000008
+#define CC_ENABLEHOOK 0x00000010
+#define CC_ENABLETEMPLATE 0x00000020
+#define CC_ENABLETEMPLATEHANDLE 0x00000040
+
+typedef struct tagFINDREPLACE
+{
+ DWORD lStructSize; /* size of this struct 0x20 */
+ HWND hwndOwner; /* handle to owner's window */
+ HINSTANCE hInstance; /* instance handle of.EXE that
+ * contains cust. dlg. template
+ */
+ DWORD Flags; /* one or more of the FR_?? */
+ LPSTR lpstrFindWhat; /* ptr. to search string */
+ LPSTR lpstrReplaceWith; /* ptr. to replace string */
+ UINT wFindWhatLen; /* size of find buffer */
+ UINT wReplaceWithLen; /* size of replace buffer */
+ LPARAM lCustData; /* data passed to hook fn. */
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ /* ptr. to hook fn. or NULL */
+ LPCSTR lpTemplateName; /* custom template name */
+} FINDREPLACE;
+typedef FINDREPLACE FAR *LPFINDREPLACE;
+
+#define FR_DOWN 0x00000001
+#define FR_WHOLEWORD 0x00000002
+#define FR_MATCHCASE 0x00000004
+#define FR_FINDNEXT 0x00000008
+#define FR_REPLACE 0x00000010
+#define FR_REPLACEALL 0x00000020
+#define FR_DIALOGTERM 0x00000040
+#define FR_SHOWHELP 0x00000080
+#define FR_ENABLEHOOK 0x00000100
+#define FR_ENABLETEMPLATE 0x00000200
+#define FR_NOUPDOWN 0x00000400
+#define FR_NOMATCHCASE 0x00000800
+#define FR_NOWHOLEWORD 0x00001000
+#define FR_ENABLETEMPLATEHANDLE 0x00002000
+#define FR_HIDEUPDOWN 0x00004000
+#define FR_HIDEMATCHCASE 0x00008000
+#define FR_HIDEWHOLEWORD 0x00010000
+
+HWND WINAPI FindText(FINDREPLACE FAR*);
+HWND WINAPI ReplaceText(FINDREPLACE FAR*);
+
+typedef struct tagCHOOSEFONT
+{
+ DWORD lStructSize; /* */
+ HWND hwndOwner; /* caller's window handle */
+ HDC hDC; /* printer DC/IC or NULL */
+ LOGFONT FAR* lpLogFont; /* ptr. to a LOGFONT struct */
+ int iPointSize; /* 10 * size in points of selected font */
+ DWORD Flags; /* enum. type flags */
+ COLORREF rgbColors; /* returned text color */
+ LPARAM lCustData; /* data passed to hook fn. */
+ UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
+ /* ptr. to hook function */
+ LPCSTR lpTemplateName; /* custom template name */
+ HINSTANCE hInstance; /* instance handle of.EXE that
+ * contains cust. dlg. template
+ */
+ LPSTR lpszStyle; /* return the style field here
+ * must be LF_FACESIZE or bigger */
+ UINT nFontType; /* same value reported to the EnumFonts
+ * call back with the extra FONTTYPE_
+ * bits added */
+ int nSizeMin; /* minimum pt size allowed & */
+ int nSizeMax; /* max pt size allowed if */
+ /* CF_LIMITSIZE is used */
+} CHOOSEFONT;
+typedef CHOOSEFONT FAR *LPCHOOSEFONT;
+
+BOOL WINAPI ChooseFont(CHOOSEFONT FAR*);
+
+#define CF_SCREENFONTS 0x00000001
+#define CF_PRINTERFONTS 0x00000002
+#define CF_BOTH (CF_SCREENFONTS | CF_PRINTERFONTS)
+#define CF_SHOWHELP 0x00000004L
+#define CF_ENABLEHOOK 0x00000008L
+#define CF_ENABLETEMPLATE 0x00000010L
+#define CF_ENABLETEMPLATEHANDLE 0x00000020L
+#define CF_INITTOLOGFONTSTRUCT 0x00000040L
+#define CF_USESTYLE 0x00000080L
+#define CF_EFFECTS 0x00000100L
+#define CF_APPLY 0x00000200L
+#define CF_ANSIONLY 0x00000400L
+#define CF_NOVECTORFONTS 0x00000800L
+#define CF_NOOEMFONTS CF_NOVECTORFONTS
+#define CF_NOSIMULATIONS 0x00001000L
+#define CF_LIMITSIZE 0x00002000L
+#define CF_FIXEDPITCHONLY 0x00004000L
+#define CF_WYSIWYG 0x00008000L /* must also have CF_SCREENFONTS & CF_PRINTERFONTS */
+#define CF_FORCEFONTEXIST 0x00010000L
+#define CF_SCALABLEONLY 0x00020000L
+#define CF_TTONLY 0x00040000L
+#define CF_NOFACESEL 0x00080000L
+#define CF_NOSTYLESEL 0x00100000L
+#define CF_NOSIZESEL 0x00200000L
+
+/* these are extra nFontType bits that are added to what is returned to the
+ * EnumFonts callback routine */
+
+#define SIMULATED_FONTTYPE 0x8000
+#define PRINTER_FONTTYPE 0x4000
+#define SCREEN_FONTTYPE 0x2000
+#define BOLD_FONTTYPE 0x0100
+#define ITALIC_FONTTYPE 0x0200
+#define REGULAR_FONTTYPE 0x0400
+
+#define WM_CHOOSEFONT_GETLOGFONT (WM_USER + 1)
+
+
+/* strings used to obtain unique window message for communication
+ * between dialog and caller
+ */
+#define LBSELCHSTRING "commdlg_LBSelChangedNotify"
+#define SHAREVISTRING "commdlg_ShareViolation"
+#define FILEOKSTRING "commdlg_FileNameOK"
+#define COLOROKSTRING "commdlg_ColorOK"
+#define SETRGBSTRING "commdlg_SetRGBColor"
+#define FINDMSGSTRING "commdlg_FindReplace"
+#define HELPMSGSTRING "commdlg_help"
+
+/* HIWORD values for lParam of commdlg_LBSelChangeNotify message */
+#define CD_LBSELNOITEMS -1
+#define CD_LBSELCHANGE 0
+#define CD_LBSELSUB 1
+#define CD_LBSELADD 2
+
+typedef struct tagPD
+{
+ DWORD lStructSize;
+ HWND hwndOwner;
+ HGLOBAL hDevMode;
+ HGLOBAL hDevNames;
+ HDC hDC;
+ DWORD Flags;
+ UINT nFromPage;
+ UINT nToPage;
+ UINT nMinPage;
+ UINT nMaxPage;
+ UINT nCopies;
+ HINSTANCE hInstance;
+ LPARAM lCustData;
+ UINT (CALLBACK* lpfnPrintHook)(HWND, UINT, WPARAM, LPARAM);
+ UINT (CALLBACK* lpfnSetupHook)(HWND, UINT, WPARAM, LPARAM);
+ LPCSTR lpPrintTemplateName;
+ LPCSTR lpSetupTemplateName;
+ HGLOBAL hPrintTemplate;
+ HGLOBAL hSetupTemplate;
+} PRINTDLG;
+typedef PRINTDLG FAR* LPPRINTDLG;
+
+BOOL WINAPI PrintDlg(PRINTDLG FAR*);
+
+#define PD_ALLPAGES 0x00000000
+#define PD_SELECTION 0x00000001
+#define PD_PAGENUMS 0x00000002
+#define PD_NOSELECTION 0x00000004
+#define PD_NOPAGENUMS 0x00000008
+#define PD_COLLATE 0x00000010
+#define PD_PRINTTOFILE 0x00000020
+#define PD_PRINTSETUP 0x00000040
+#define PD_NOWARNING 0x00000080
+#define PD_RETURNDC 0x00000100
+#define PD_RETURNIC 0x00000200
+#define PD_RETURNDEFAULT 0x00000400
+#define PD_SHOWHELP 0x00000800
+#define PD_ENABLEPRINTHOOK 0x00001000
+#define PD_ENABLESETUPHOOK 0x00002000
+#define PD_ENABLEPRINTTEMPLATE 0x00004000
+#define PD_ENABLESETUPTEMPLATE 0x00008000
+#define PD_ENABLEPRINTTEMPLATEHANDLE 0x00010000
+#define PD_ENABLESETUPTEMPLATEHANDLE 0x00020000
+#define PD_USEDEVMODECOPIES 0x00040000
+#define PD_DISABLEPRINTTOFILE 0x00080000
+#define PD_HIDEPRINTTOFILE 0x00100000
+
+typedef struct tagDEVNAMES
+{
+ UINT wDriverOffset;
+ UINT wDeviceOffset;
+ UINT wOutputOffset;
+ UINT wDefault;
+} DEVNAMES;
+typedef DEVNAMES FAR* LPDEVNAMES;
+
+#define DN_DEFAULTPRN 0x0001
+
+DWORD WINAPI CommDlgExtendedError(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_COMMDLG */
diff --git a/private/mvdm/wow16/inc/common.ver b/private/mvdm/wow16/inc/common.ver
new file mode 100644
index 000000000..45a4eccd3
--- /dev/null
+++ b/private/mvdm/wow16/inc/common.ver
@@ -0,0 +1,101 @@
+
+/*---------------------------------------------------------------*/
+/* */
+/* The following section actually creates the version structure. */
+/* They are ignored if we are not being invoked by RC. */
+/* */
+/* VERSION.H must be included before including this file */
+/* */
+/* If VER_LEGALCOPYRIGHT_STR is not defined, it will be */
+/* constructed using VER_LEGALCOPYRIGHT_YEARS. */
+/* */
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR, and */
+/* VER_INTERNALNAME_STR must be defined before including this */
+/* file. */
+/* */
+/* If VER_FILEVERSION is not defined, VER_PRODUCTVERSION will be */
+/* used instead. If VER_FILEVERSION_STR is not defined, */
+/* VER_PRODUCTVERSION_STR will be used instead. */
+/* */
+/* If VER_ORIGINALFILENAME_STR is not defined, it is set to */
+/* the NULL string. */
+/* */
+/* If INTL is defined, then this is assumed to be an */
+/* an international build; two string blocks will be created, */
+/* (since all version resources must have English), and the */
+/* second one can be localized */
+/* */
+/*---------------------------------------------------------------*/
+
+#ifdef RC_INVOKED
+
+#ifndef VER_LEGALCOPYRIGHT_YEARS
+#define VER_LEGALCOPYRIGHT_YEARS "1981-1996"
+#endif
+
+#ifndef VER_LEGALCOPYRIGHT_STR
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Microsoft Corp. ", VER_LEGALCOPYRIGHT_YEARS, "\0"
+#endif
+
+#ifndef VER_FILEVERSION
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#endif
+
+#ifndef VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#endif
+
+#ifndef VER_ORIGINALFILENAME_STR
+#define VER_ORIGINALFILENAME_STR "\0"
+#endif
+
+#define VER_WOWVERSION_STR "4.0"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR, "\0"
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR, "\0"
+ VALUE "FileVersion", VER_FILEVERSION_STR, "\0"
+ VALUE "InternalName", VER_INTERNALNAME_STR, "\0"
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR, "\0"
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR, "\0"
+ VALUE "ProductName", VER_PRODUCTNAME_STR, "\0"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR, "\0"
+ VALUE "WOW Version", VER_WOWVERSION_STR, "\0"
+ END
+
+#ifdef INTL
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR, "\0"
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR, "\0"
+ VALUE "FileVersion", VER_FILEVERSION_STR, "\0"
+ VALUE "InternalName", VER_INTERNALNAME_STR, "\0"
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR, "\0"
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR, "\0"
+ VALUE "ProductName", VER_PRODUCTNAME_STR, "\0"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR, "\0"
+ VALUE "WOW Version", VER_WOWVERSION_STR, "\0"
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ /* the following line should be extended for localized versions */
+ VALUE "Translation", 0x0409, 0x04E4
+ END
+END
+
+#endif
diff --git a/private/mvdm/wow16/inc/convdll.inc b/private/mvdm/wow16/inc/convdll.inc
new file mode 100644
index 000000000..e17ff44a1
--- /dev/null
+++ b/private/mvdm/wow16/inc/convdll.inc
@@ -0,0 +1,58 @@
+WLOINITDLL macro
+ local cd_start, cd_patch, cd_init, WIN_NOP, WIN_PPLI
+ local cd_end
+ EXTRN GETMODULEUSAGE:FAR
+ EXTRN INITTASK:FAR
+ EXTRN __WINFLAGS:abs
+
+cd_start:
+ push ax
+ push bx
+ push cx
+ push dx
+ push es
+
+ mov ax, __WINFLAGS
+ or ax,ax
+ jns WIN_NOP
+
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ call INITTASK-5
+cd_patch:
+ jmp short cd_init
+ nop
+ xor ax, ax
+ retf
+cd_init: jmp short cd_end
+
+WIN_NOP:
+ jmp short WIN_PPLI
+ jmp short WIN_PPLI
+ push di
+ call GETMODULEUSAGE
+ dec ax
+ jz WIN_PPLI
+ inc ax
+ add sp,10
+ retf
+
+WIN_PPLI:
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ jmp short cd_end
+ db "C", "D", "D", 1, 0
+ dw cd_patch - cd_start
+ dw WIN_NOP - cd_start
+ dw cd_end - cd_start
+cd_end:
+
+endm
+ WLOINITDLL
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/inc/cpl.h b/private/mvdm/wow16/inc/cpl.h
new file mode 100644
index 000000000..0e8065ad5
--- /dev/null
+++ b/private/mvdm/wow16/inc/cpl.h
@@ -0,0 +1,159 @@
+/*****************************************************************************\
+* *
+* cpl.h - Control panel extension DLL definitions *
+* *
+* Version 3.10 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+******************************************************************************
+* General rules for being installed in the Control Panel:
+*
+* 1) The DLL must export a function named CPlApplet which will handle
+* the messages discussed below.
+* 2) If the applet needs to save information in CONTROL.INI minimize
+* clutter by using the application name [MMCPL.appletname].
+* 2) If the applet is refrenced in CONTROL.INI under [MMCPL] use
+* the following form:
+* ...
+* [MMCPL]
+* uniqueName=c:\mydir\myapplet.dll
+* ...
+*
+*
+* The order applet DLL's are loaded by CONTROL.EXE is:
+*
+* 1) MAIN.CPL is loaded from the windows system directory.
+*
+* 2) Installable drivers that are loaded and export the
+* CplApplet() routine.
+*
+* 3) DLL's specified in the [MMCPL] section of CONTROL.INI.
+*
+* 4) DLL's named *.CPL from windows system directory.
+*
+*/
+#ifndef _INC_CPL
+#define _INC_CPL
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/*
+ * CONTROL.EXE will answer this message and launch an applet
+ *
+ * WM_CPL_LAUNCH
+ *
+ * wParam - window handle of calling app
+ * lParam - LPSTR of name of applet to launch
+ *
+ * WM_CPL_LAUNCHED
+ *
+ * wParam - TRUE/FALSE if applet was launched
+ * lParam - NULL
+ *
+ * CONTROL.EXE will post this message to the caller when the applet returns
+ * (ie., when wParam is a valid window handle)
+ *
+ */
+#define WM_CPL_LAUNCH (WM_USER+1000)
+#define WM_CPL_LAUNCHED (WM_USER+1001)
+
+/* A function prototype for CPlApplet() */
+
+typedef LRESULT (CALLBACK *APPLET_PROC)(HWND hwndCpl, UINT msg, LPARAM lParam1, LPARAM lParam2);
+
+/* The data structure CPlApplet() must fill in. */
+
+typedef struct tagCPLINFO
+{
+ int idIcon; /* icon resource id, provided by CPlApplet() */
+ int idName; /* name string res. id, provided by CPlApplet() */
+ int idInfo; /* info string res. id, provided by CPlApplet() */
+ LONG lData; /* user defined data */
+} CPLINFO, *PCPLINFO, FAR *LPCPLINFO;
+
+typedef struct tagNEWCPLINFO
+{
+ DWORD dwSize; /* similar to the commdlg */
+ DWORD dwFlags;
+ DWORD dwHelpContext; /* help context to use */
+ LONG lData; /* user defined data */
+ HICON hIcon; /* icon to use, this is owned by CONTROL.EXE (may be deleted) */
+ char szName[32]; /* short name */
+ char szInfo[64]; /* long name (status line) */
+ char szHelpFile[128];/* path to help file to use */
+} NEWCPLINFO, *PNEWCPLINFO, FAR *LPNEWCPLINFO;
+
+
+/* The messages CPlApplet() must handle: */
+
+#define CPL_INIT 1
+/* This message is sent to indicate CPlApplet() was found. */
+/* lParam1 and lParam2 are not defined. */
+/* Return TRUE or FALSE indicating whether the control panel should proceed. */
+
+
+#define CPL_GETCOUNT 2
+/* This message is sent to determine the number of applets to be displayed. */
+/* lParam1 and lParam2 are not defined. */
+/* Return the number of applets you wish to display in the control */
+/* panel window. */
+
+
+#define CPL_INQUIRE 3
+/* This message is sent for information about each applet. */
+/* lParam1 is the applet number to register, a value from 0 to */
+/* (CPL_GETCOUNT - 1). lParam2 is a far ptr to a CPLINFO structure. */
+/* Fill in CPL_INFO's idIcon, idName, idInfo and lData fields with */
+/* the resource id for an icon to display, name and description string ids, */
+/* and a long data item associated with applet #lParam1. */
+
+
+#define CPL_SELECT 4
+/* This message is sent when the applet's icon has been clicked upon. */
+/* lParam1 is the applet number which was selected. lParam2 is the */
+/* applet's lData value. */
+
+
+#define CPL_DBLCLK 5
+/* This message is sent when the applet's icon has been double-clicked */
+/* upon. lParam1 is the applet number which was selected. lParam2 is the */
+/* applet's lData value. */
+/* This message should initiate the applet's dialog box. */
+
+
+#define CPL_STOP 6
+/* This message is sent for each applet when the control panel is exiting. */
+/* lParam1 is the applet number. lParam2 is the applet's lData value. */
+/* Do applet specific cleaning up here. */
+
+
+#define CPL_EXIT 7
+/* This message is sent just before the control panel calls FreeLibrary. */
+/* lParam1 and lParam2 are not defined. */
+/* Do non-applet specific cleaning up here. */
+
+
+#define CPL_NEWINQUIRE 8
+/* this is the same as CPL_INQUIRE execpt lParam2 is a pointer to a */
+/* NEWCPLINFO structure. this will be sent before the CPL_INQUIRE */
+/* and if it is responed to (return != 0) CPL_INQUIRE will not be sent */
+
+#define CPL_DO_PRINTER_SETUP 100 /* ;Internal */
+#define CPL_DO_NETPRN_SETUP 101 /* ;Internal */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_CPL */
diff --git a/private/mvdm/wow16/inc/custcntl.h b/private/mvdm/wow16/inc/custcntl.h
new file mode 100644
index 000000000..be3d02af1
--- /dev/null
+++ b/private/mvdm/wow16/inc/custcntl.h
@@ -0,0 +1,105 @@
+/*****************************************************************************\
+* *
+* custcntl.h - Custom Control Library header file *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_CUSTCNTL
+#define _INC_CUSTCNTL
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/*
+ * Every custom control DLL must have three functions present,
+ * and they must be exported by the following ordinals.
+ */
+#define CCINFOORD 2 /* information function ordinal */
+#define CCSTYLEORD 3 /* styles function ordinal */
+#define CCFLAGSORD 4 /* translate flags function ordinal */
+
+/* general size definitions */
+#define CTLTYPES 12 /* max number of control types */
+#define CTLDESCR 22 /* max size of description */
+#define CTLCLASS 20 /* max size of class name */
+#define CTLTITLE 94 /* max size of control text */
+
+/*
+ * CONTROL STYLE DATA STRUCTURE
+ *
+ * This data structure is used by the class style dialog function
+ * to set and/or reset various control attributes.
+ *
+ */
+typedef struct tagCTLSTYLE
+{
+ UINT wX; /* x origin of control */
+ UINT wY; /* y origin of control */
+ UINT wCx; /* width of control */
+ UINT wCy; /* height of control */
+ UINT wId; /* control child id */
+ DWORD dwStyle; /* control style */
+ char szClass[CTLCLASS]; /* name of control class */
+ char szTitle[CTLTITLE]; /* control text */
+} CTLSTYLE;
+typedef CTLSTYLE * PCTLSTYLE;
+typedef CTLSTYLE FAR* LPCTLSTYLE;
+
+/*
+ * CONTROL DATA STRUCTURE
+ *
+ * This data structure is returned by the control options function
+ * when inquiring about the capabilities of a particular control.
+ * Each control may contain various types (with predefined style
+ * bits) under one general class.
+ *
+ * The width and height fields are used to provide the host
+ * application with a suggested size. The values in these fields
+ * are in rc coordinates.
+ *
+ */
+typedef struct tagCTLTYPE
+{
+ UINT wType; /* type style */
+ UINT wWidth; /* suggested width */
+ UINT wHeight; /* suggested height */
+ DWORD dwStyle; /* default style */
+ char szDescr[CTLDESCR]; /* description */
+} CTLTYPE;
+
+typedef struct tagCTLINFO
+{
+ UINT wVersion; /* control version */
+ UINT wCtlTypes; /* control types */
+ char szClass[CTLCLASS]; /* control class name */
+ char szTitle[CTLTITLE]; /* control title */
+ char szReserved[10]; /* reserved for future use */
+ CTLTYPE Type[CTLTYPES]; /* control type list */
+} CTLINFO;
+typedef CTLINFO * PCTLINFO;
+typedef CTLINFO FAR* LPCTLINFO;
+
+/* These two function prototypes are used by the dialog editor */
+#ifdef STRICT
+typedef DWORD (CALLBACK* LPFNSTRTOID)(LPCSTR);
+#else
+typedef DWORD (CALLBACK* LPFNSTRTOID)(LPSTR);
+#endif
+typedef UINT (CALLBACK* LPFNIDTOSTR)(UINT, LPSTR, UINT);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_CUSTCNTL */
diff --git a/private/mvdm/wow16/inc/dbcs.c b/private/mvdm/wow16/inc/dbcs.c
new file mode 100644
index 000000000..34413cf8f
--- /dev/null
+++ b/private/mvdm/wow16/inc/dbcs.c
@@ -0,0 +1,115 @@
+/*
+** dbcs.c - DBCS functions for DOS apps.
+**
+** Written by RokaH and DavidDi.
+*/
+
+
+/* Headers
+**********/
+
+#include <dos.h>
+#include <ctype.h>
+
+#include <dbcs.h>
+
+
+/*
+** int IsDBCSLeadByte(unsigned char uch);
+**
+** Check to see if a character is a DBCS lead byte.
+**
+** Arguments: uch - charcter to examine
+**
+** Returns: int - 1 if the character is a DBCS lead byte. 0 if not.
+**
+** Globals: none
+*/
+int IsDBCSLeadByte(unsigned char uch)
+{
+ static unsigned char far *DBCSLeadByteTable = 0;
+ union REGS inregs, outregs;
+ struct SREGS segregs;
+ unsigned char far *puch;
+
+ if (DBCSLeadByteTable == 0)
+ {
+ /*
+ ** Get DBCS lead byte table. This function has been supported since
+ ** DBCS MS-DOS 2.21.
+ */
+ inregs.x.ax = 0x6300;
+ intdosx(&inregs, &outregs, &segregs);
+
+ FP_OFF(DBCSLeadByteTable) = outregs.x.si;
+ FP_SEG(DBCSLeadByteTable) = segregs.ds;
+ }
+
+ /* See if the given byte is in any of the table's lead byte ranges. */
+ for (puch = DBCSLeadByteTable; puch[0] || puch[1]; puch += 2)
+ if (uch >= puch[0] && uch <= puch[1])
+ return(1);
+
+ return(0);
+}
+
+
+/*
+** unsigned char *AnsiNext(unsigned char *puch);
+**
+** Moves to the next character in a string.
+**
+** Arguments: puch - pointer to current location in string
+**
+** Returns: char * - Pointer to next character in string.
+**
+** Globals: none
+**
+** N.b., if puch points to a null character, AnsiNext() will return puch.
+*/
+unsigned char far *AnsiNext(unsigned char far *puch)
+{
+ if (*puch == '\0')
+ return(puch);
+ else if (IsDBCSLeadByte(*puch))
+ puch++;
+
+ puch++;
+
+ return(puch);
+}
+
+
+/*
+** unsigned char *AnsiPrev(unsigned char *psz, unsigned char *puch);
+**
+** Moves back one character in a string.
+**
+** Arguments: psz - pointer to start of string
+** puch - pointer to current location in string
+**
+** Returns: char * - Pointer to previous character in string.
+**
+** Globals: none
+**
+** N.b., if puch <= psz, AnsiPrev() will return psz.
+**
+** This function is implemented in a very slow fashion because we do not wish
+** to trust that the given string is necessarily DBCS "safe," i.e., contains
+** only single-byte characters and valid DBCS characters. So we start from
+** the beginning of the string and work our way forward.
+*/
+unsigned char far *AnsiPrev(unsigned char far *psz, unsigned char far *puch)
+{
+ unsigned char far *puchPrevious;
+
+ do
+ {
+ puchPrevious = psz;
+ psz = AnsiNext(psz);
+ } while (*psz != '\0' && psz < puch);
+
+ return(puchPrevious);
+}
+
+
diff --git a/private/mvdm/wow16/inc/dbcs.h b/private/mvdm/wow16/inc/dbcs.h
new file mode 100644
index 000000000..6f92bdd48
--- /dev/null
+++ b/private/mvdm/wow16/inc/dbcs.h
@@ -0,0 +1,7 @@
+/*
+** dbcs.h - DBCS functions prototypes for DOS apps.
+*/
+
+extern int IsDBCSLeadByte(unsigned char uch);
+extern unsigned char far *AnsiNext(unsigned char far *puch);
+extern unsigned char far *AnsiPrev(unsigned char far *psz, unsigned char far *puch);
diff --git a/private/mvdm/wow16/inc/dde.h b/private/mvdm/wow16/inc/dde.h
new file mode 100644
index 000000000..26aa0139b
--- /dev/null
+++ b/private/mvdm/wow16/inc/dde.h
@@ -0,0 +1,146 @@
+/*****************************************************************************\
+* *
+* dde.h - Dynamic Data Exchange structures and definitions *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_DDE
+#define _INC_DDE
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/* DDE window messages */
+
+#define WM_DDE_FIRST 0x03E0
+#define WM_DDE_INITIATE (WM_DDE_FIRST)
+#define WM_DDE_TERMINATE (WM_DDE_FIRST+1)
+#define WM_DDE_ADVISE (WM_DDE_FIRST+2)
+#define WM_DDE_UNADVISE (WM_DDE_FIRST+3)
+#define WM_DDE_ACK (WM_DDE_FIRST+4)
+#define WM_DDE_DATA (WM_DDE_FIRST+5)
+#define WM_DDE_REQUEST (WM_DDE_FIRST+6)
+#define WM_DDE_POKE (WM_DDE_FIRST+7)
+#define WM_DDE_EXECUTE (WM_DDE_FIRST+8)
+#define WM_DDE_LAST (WM_DDE_FIRST+8)
+
+/****************************************************************************\
+* DDEACK structure
+*
+* Structure of wStatus (LOWORD(lParam)) in WM_DDE_ACK message
+* sent in response to a WM_DDE_DATA, WM_DDE_REQUEST, WM_DDE_POKE,
+* WM_DDE_ADVISE, or WM_DDE_UNADVISE message.
+*
+\****************************************************************************/
+
+typedef struct tagDDEACK
+{
+ WORD bAppReturnCode:8,
+ reserved:6,
+ fBusy:1,
+ fAck:1;
+} DDEACK;
+
+/****************************************************************************\
+* DDEADVISE structure
+*
+* WM_DDE_ADVISE parameter structure for hOptions (LOWORD(lParam))
+*
+\****************************************************************************/
+
+typedef struct tagDDEADVISE
+{
+ WORD reserved:14,
+ fDeferUpd:1,
+ fAckReq:1;
+ short cfFormat;
+} DDEADVISE;
+
+/****************************************************************************\
+* 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 tagDDEDATA
+{
+ WORD unused:12,
+ fResponse:1,
+ fRelease:1,
+ reserved:1,
+ fAckReq:1;
+ short cfFormat;
+ BYTE Value[1];
+} DDEDATA;
+
+
+/****************************************************************************\
+* DDEPOKE structure
+*
+* WM_DDE_POKE parameter structure for hData (LOWORD(lParam)).
+* The actual size of this structure depends on the size of
+* the Value array.
+*
+\****************************************************************************/
+
+typedef struct tagDDEPOKE
+{
+ WORD unused:13, /* Earlier versions of DDE.H incorrectly */
+ /* 12 unused bits. */
+ fRelease:1,
+ fReserved:2;
+ short cfFormat;
+ BYTE Value[1]; /* This member was named rgb[1] in previous */
+ /* versions of DDE.H */
+
+} DDEPOKE;
+
+/****************************************************************************\
+* The following typedef's were used in previous versions of the Windows SDK.
+* They are still valid. The above typedef's define exactly the same structures
+* as those below. The above typedef names are recommended, however, as they
+* are more meaningful.
+*
+* Note that the DDEPOKE structure typedef'ed in earlier versions of DDE.H did
+* not correctly define the bit positions.
+\****************************************************************************/
+
+typedef struct tagDDELN
+{
+ WORD unused:13,
+ fRelease:1,
+ fDeferUpd:1,
+ fAckReq:1;
+ short cfFormat;
+} DDELN;
+
+typedef struct tagDDEUP
+{
+ WORD unused:12,
+ fAck:1,
+ fRelease:1,
+ fReserved:1,
+ fAckReq:1;
+ short cfFormat;
+ BYTE rgb[1];
+} DDEUP;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_DDE */
diff --git a/private/mvdm/wow16/inc/ddeml.h b/private/mvdm/wow16/inc/ddeml.h
new file mode 100644
index 000000000..354cf72c8
--- /dev/null
+++ b/private/mvdm/wow16/inc/ddeml.h
@@ -0,0 +1,459 @@
+/*****************************************************************************\
+* *
+* ddeml.h - DDEML API header file *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+#ifndef _INC_DDEML
+#define _INC_DDEML
+
+#ifndef RC_INVOKED
+#pragma pack(1)
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef _INC_WINDOWS /* If not included with 3.1 headers... */
+#define LPCSTR LPSTR
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+#ifndef DECLARE_HANDLE32
+#ifdef STRICT
+#define DECLARE_HANDLE32(name) struct name##__ { int unused; }; \
+ typedef const struct name##__ _far* name
+#else /* STRICT */
+#define DECLARE_HANDLE32(name) typedef DWORD name
+#endif /* !STRICT */
+#endif /* !DECLARE_HANDLE32 */
+
+#define EXPENTRY WINAPI
+
+/******** public types ********/
+
+DECLARE_HANDLE32(HCONVLIST);
+DECLARE_HANDLE32(HCONV);
+DECLARE_HANDLE32(HSZ);
+DECLARE_HANDLE32(HDDEDATA);
+
+/* the following structure is for use with XTYP_WILDCONNECT processing. */
+
+typedef struct tagHSZPAIR
+{
+ HSZ hszSvc;
+ HSZ hszTopic;
+} HSZPAIR;
+typedef HSZPAIR FAR *PHSZPAIR;
+
+/* The following structure is used by DdeConnect() and DdeConnectList() and
+ by XTYP_CONNECT and XTYP_WILDCONNECT callbacks. */
+
+typedef struct tagCONVCONTEXT
+{
+ UINT cb; /* set to sizeof(CONVCONTEXT) */
+ UINT wFlags; /* none currently defined. */
+ UINT wCountryID; /* country code for topic/item strings used. */
+ int iCodePage; /* codepage used for topic/item strings. */
+ DWORD dwLangID; /* language ID for topic/item strings. */
+ DWORD dwSecurity; /* Private security code. */
+} CONVCONTEXT;
+typedef CONVCONTEXT FAR *PCONVCONTEXT;
+
+/* The following structure is used by DdeQueryConvInfo(): */
+
+typedef struct tagCONVINFO
+{
+ DWORD cb; /* sizeof(CONVINFO) */
+ DWORD hUser; /* user specified field */
+ HCONV hConvPartner; /* hConv on other end or 0 if non-ddemgr partner */
+ HSZ hszSvcPartner; /* app name of partner if obtainable */
+ HSZ hszServiceReq; /* AppName requested for connection */
+ HSZ hszTopic; /* Topic name for conversation */
+ HSZ hszItem; /* transaction item name or NULL if quiescent */
+ UINT wFmt; /* transaction format or NULL if quiescent */
+ UINT wType; /* XTYP_ for current transaction */
+ UINT wStatus; /* ST_ constant for current conversation */
+ UINT wConvst; /* XST_ constant for current transaction */
+ UINT wLastError; /* last transaction error. */
+ HCONVLIST hConvList; /* parent hConvList if this conversation is in a list */
+ CONVCONTEXT ConvCtxt; /* conversation context */
+ HWND hwnd; /* Added to allow access for NetDDE. */
+ HWND hwndPartner; /* Added to allow access for NetDDE. */
+} CONVINFO;
+typedef CONVINFO FAR *PCONVINFO;
+
+/***** conversation states (usState) *****/
+
+#define XST_NULL 0 /* quiescent states */
+#define XST_INCOMPLETE 1
+#define XST_CONNECTED 2
+#define XST_INIT1 3 /* mid-initiation states */
+#define XST_INIT2 4
+#define XST_REQSENT 5 /* active conversation states */
+#define XST_DATARCVD 6
+#define XST_POKESENT 7
+#define XST_POKEACKRCVD 8
+#define XST_EXECSENT 9
+#define XST_EXECACKRCVD 10
+#define XST_ADVSENT 11
+#define XST_UNADVSENT 12
+#define XST_ADVACKRCVD 13
+#define XST_UNADVACKRCVD 14
+#define XST_ADVDATASENT 15
+#define XST_ADVDATAACKRCVD 16
+
+/* used in LOWORD(dwData1) of XTYP_ADVREQ callbacks... */
+#define CADV_LATEACK 0xFFFF
+
+/***** conversation status bits (fsStatus) *****/
+
+#define ST_CONNECTED 0x0001
+#define ST_ADVISE 0x0002
+#define ST_ISLOCAL 0x0004
+#define ST_BLOCKED 0x0008
+#define ST_CLIENT 0x0010
+#define ST_TERMINATED 0x0020
+#define ST_INLIST 0x0040
+#define ST_BLOCKNEXT 0x0080
+#define ST_ISSELF 0x0100
+
+/* DDE constants for wStatus field */
+
+#define DDE_FACK 0x8000
+#define DDE_FBUSY 0x4000
+#define DDE_FDEFERUPD 0x4000
+#define DDE_FACKREQ 0x8000
+#define DDE_FRELEASE 0x2000
+#define DDE_FREQUESTED 0x1000
+#define DDE_FACKRESERVED 0x3ff0
+#define DDE_FADVRESERVED 0x3fff
+#define DDE_FDATRESERVED 0x4fff
+#define DDE_FPOKRESERVED 0xdfff
+#define DDE_FAPPSTATUS 0x00ff
+#define DDE_FNOTPROCESSED 0x0000
+
+/***** message filter hook types *****/
+
+#define MSGF_DDEMGR 0x8001
+
+/***** codepage constants ****/
+
+#define CP_WINANSI 1004 /* default codepage for windows & old DDE convs. */
+
+/***** transaction types *****/
+
+#define XTYPF_NOBLOCK 0x0002 /* CBR_BLOCK will not work */
+#define XTYPF_NODATA 0x0004 /* DDE_FDEFERUPD */
+#define XTYPF_ACKREQ 0x0008 /* DDE_FACKREQ */
+
+#define XCLASS_MASK 0xFC00
+#define XCLASS_BOOL 0x1000
+#define XCLASS_DATA 0x2000
+#define XCLASS_FLAGS 0x4000
+#define XCLASS_NOTIFICATION 0x8000
+
+#define XTYP_ERROR (0x0000 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK )
+#define XTYP_ADVDATA (0x0010 | XCLASS_FLAGS )
+#define XTYP_ADVREQ (0x0020 | XCLASS_DATA | XTYPF_NOBLOCK )
+#define XTYP_ADVSTART (0x0030 | XCLASS_BOOL )
+#define XTYP_ADVSTOP (0x0040 | XCLASS_NOTIFICATION)
+#define XTYP_EXECUTE (0x0050 | XCLASS_FLAGS )
+#define XTYP_CONNECT (0x0060 | XCLASS_BOOL | XTYPF_NOBLOCK)
+#define XTYP_CONNECT_CONFIRM (0x0070 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
+#define XTYP_XACT_COMPLETE (0x0080 | XCLASS_NOTIFICATION )
+#define XTYP_POKE (0x0090 | XCLASS_FLAGS )
+#define XTYP_REGISTER (0x00A0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
+#define XTYP_REQUEST (0x00B0 | XCLASS_DATA )
+#define XTYP_DISCONNECT (0x00C0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
+#define XTYP_UNREGISTER (0x00D0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
+#define XTYP_WILDCONNECT (0x00E0 | XCLASS_DATA | XTYPF_NOBLOCK)
+
+#define XTYP_MASK 0x00F0
+#define XTYP_SHIFT 4 /* shift to turn XTYP_ into an index */
+
+/***** Timeout constants *****/
+
+#define TIMEOUT_ASYNC -1L
+
+/***** Transaction ID constants *****/
+
+#define QID_SYNC -1L
+
+/****** public strings used in DDE ******/
+
+#define SZDDESYS_TOPIC "System"
+#define SZDDESYS_ITEM_TOPICS "Topics"
+#define SZDDESYS_ITEM_SYSITEMS "SysItems"
+#define SZDDESYS_ITEM_RTNMSG "ReturnMessage"
+#define SZDDESYS_ITEM_STATUS "Status"
+#define SZDDESYS_ITEM_FORMATS "Formats"
+#define SZDDESYS_ITEM_HELP "Help"
+#define SZDDE_ITEM_ITEMLIST "TopicItemList"
+
+
+/****** API entry points ******/
+
+typedef HDDEDATA CALLBACK FNCALLBACK(UINT wType, UINT wFmt, HCONV hConv,
+ HSZ hsz1, HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+typedef FNCALLBACK *PFNCALLBACK;
+
+#define CBR_BLOCK 0xffffffffL
+
+/* DLL registration functions */
+
+UINT WINAPI DdeInitialize(DWORD FAR* pidInst, PFNCALLBACK pfnCallback,
+ DWORD afCmd, DWORD ulRes);
+
+/*
+ * Callback filter flags for use with standard apps.
+ */
+
+#define CBF_FAIL_SELFCONNECTIONS 0x00001000
+#define CBF_FAIL_CONNECTIONS 0x00002000
+#define CBF_FAIL_ADVISES 0x00004000
+#define CBF_FAIL_EXECUTES 0x00008000
+#define CBF_FAIL_POKES 0x00010000
+#define CBF_FAIL_REQUESTS 0x00020000
+#define CBF_FAIL_ALLSVRXACTIONS 0x0003f000
+
+#define CBF_SKIP_CONNECT_CONFIRMS 0x00040000
+#define CBF_SKIP_REGISTRATIONS 0x00080000
+#define CBF_SKIP_UNREGISTRATIONS 0x00100000
+#define CBF_SKIP_DISCONNECTS 0x00200000
+#define CBF_SKIP_ALLNOTIFICATIONS 0x003c0000
+
+/*
+ * Application command flags
+ */
+#define APPCMD_CLIENTONLY 0x00000010L
+#define APPCMD_FILTERINITS 0x00000020L
+#define APPCMD_MASK 0x00000FF0L
+
+/*
+ * Application classification flags
+ */
+#define APPCLASS_STANDARD 0x00000000L
+#define APPCLASS_MASK 0x0000000FL
+
+
+BOOL WINAPI DdeUninitialize(DWORD idInst);
+
+/* conversation enumeration functions */
+
+HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
+ HCONVLIST hConvList, CONVCONTEXT FAR* pCC);
+HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev);
+BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList);
+
+/* conversation control functions */
+
+HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
+ CONVCONTEXT FAR* pCC);
+BOOL WINAPI DdeDisconnect(HCONV hConv);
+HCONV WINAPI DdeReconnect(HCONV hConv);
+
+UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD idTransaction, CONVINFO FAR* pConvInfo);
+BOOL WINAPI DdeSetUserHandle(HCONV hConv, DWORD id, DWORD hUser);
+
+BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction);
+
+
+/* app server interface functions */
+
+BOOL WINAPI DdePostAdvise(DWORD idInst, HSZ hszTopic, HSZ hszItem);
+BOOL WINAPI DdeEnableCallback(DWORD idInst, HCONV hConv, UINT wCmd);
+
+#define EC_ENABLEALL 0
+#define EC_ENABLEONE ST_BLOCKNEXT
+#define EC_DISABLE ST_BLOCKED
+#define EC_QUERYWAITING 2
+
+HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd);
+
+#define DNS_REGISTER 0x0001
+#define DNS_UNREGISTER 0x0002
+#define DNS_FILTERON 0x0004
+#define DNS_FILTEROFF 0x0008
+
+/* app client interface functions */
+
+HDDEDATA WINAPI DdeClientTransaction(void FAR* pData, DWORD cbData,
+ HCONV hConv, HSZ hszItem, UINT wFmt, UINT wType,
+ DWORD dwTimeout, DWORD FAR* pdwResult);
+
+/* data transfer functions */
+
+HDDEDATA WINAPI DdeCreateDataHandle(DWORD idInst, void FAR* pSrc, DWORD cb,
+ DWORD cbOff, HSZ hszItem, UINT wFmt, UINT afCmd);
+HDDEDATA WINAPI DdeAddData(HDDEDATA hData, void FAR* pSrc, DWORD cb, DWORD cbOff);
+DWORD WINAPI DdeGetData(HDDEDATA hData, void FAR* pDst, DWORD cbMax, DWORD cbOff);
+BYTE FAR* WINAPI DdeAccessData(HDDEDATA hData, DWORD FAR* pcbDataSize);
+BOOL WINAPI DdeUnaccessData(HDDEDATA hData);
+BOOL WINAPI DdeFreeDataHandle(HDDEDATA hData);
+
+#define HDATA_APPOWNED 0x0001
+
+
+
+UINT WINAPI DdeGetLastError(DWORD idInst);
+
+#define DMLERR_NO_ERROR 0 /* must be 0 */
+
+#define DMLERR_FIRST 0x4000
+
+#define DMLERR_ADVACKTIMEOUT 0x4000
+#define DMLERR_BUSY 0x4001
+#define DMLERR_DATAACKTIMEOUT 0x4002
+#define DMLERR_DLL_NOT_INITIALIZED 0x4003
+#define DMLERR_DLL_USAGE 0x4004
+#define DMLERR_EXECACKTIMEOUT 0x4005
+#define DMLERR_INVALIDPARAMETER 0x4006
+#define DMLERR_LOW_MEMORY 0x4007
+#define DMLERR_MEMORY_ERROR 0x4008
+#define DMLERR_NOTPROCESSED 0x4009
+#define DMLERR_NO_CONV_ESTABLISHED 0x400a
+#define DMLERR_POKEACKTIMEOUT 0x400b
+#define DMLERR_POSTMSG_FAILED 0x400c
+#define DMLERR_REENTRANCY 0x400d
+#define DMLERR_SERVER_DIED 0x400e
+#define DMLERR_SYS_ERROR 0x400f
+#define DMLERR_UNADVACKTIMEOUT 0x4010
+#define DMLERR_UNFOUND_QUEUE_ID 0x4011
+
+#define DMLERR_LAST 0x4011
+
+HSZ WINAPI DdeCreateStringHandle(DWORD idInst, LPCSTR psz, int iCodePage);
+DWORD WINAPI DdeQueryString(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, int iCodePage);
+BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz);
+BOOL WINAPI DdeKeepStringHandle(DWORD idInst, HSZ hsz);
+int WINAPI DdeCmpStringHandles(HSZ hsz1, HSZ hsz2);
+
+
+#ifndef NODDEMLSPY
+/* */
+/* DDEML public debugging header file info */
+/* */
+
+typedef struct tagMONMSGSTRUCT
+{
+ UINT cb;
+ HWND hwndTo;
+ DWORD dwTime;
+ HANDLE hTask;
+ UINT wMsg;
+ WPARAM wParam;
+ LPARAM lParam;
+} MONMSGSTRUCT;
+
+typedef struct tagMONCBSTRUCT
+{
+ UINT cb;
+ WORD wReserved;
+ DWORD dwTime;
+ HANDLE hTask;
+ DWORD dwRet;
+ UINT wType;
+ UINT wFmt;
+ HCONV hConv;
+ HSZ hsz1;
+ HSZ hsz2;
+ HDDEDATA hData;
+ DWORD dwData1;
+ DWORD dwData2;
+} MONCBSTRUCT;
+
+typedef struct tagMONHSZSTRUCT
+{
+ UINT cb;
+ BOOL fsAction; /* MH_ value */
+ DWORD dwTime;
+ HSZ hsz;
+ HANDLE hTask;
+ WORD wReserved;
+ char str[1];
+} MONHSZSTRUCT;
+
+#define MH_CREATE 1
+#define MH_KEEP 2
+#define MH_DELETE 3
+#define MH_CLEANUP 4
+
+
+typedef struct tagMONERRSTRUCT
+{
+ UINT cb;
+ UINT wLastError;
+ DWORD dwTime;
+ HANDLE hTask;
+} MONERRSTRUCT;
+
+typedef struct tagMONLINKSTRUCT
+{
+ UINT cb;
+ DWORD dwTime;
+ HANDLE hTask;
+ BOOL fEstablished;
+ BOOL fNoData;
+ HSZ hszSvc;
+ HSZ hszTopic;
+ HSZ hszItem;
+ UINT wFmt;
+ BOOL fServer;
+ HCONV hConvServer;
+ HCONV hConvClient;
+} MONLINKSTRUCT;
+
+typedef struct tagMONCONVSTRUCT
+{
+ UINT cb;
+ BOOL fConnect;
+ DWORD dwTime;
+ HANDLE hTask;
+ HSZ hszSvc;
+ HSZ hszTopic;
+ HCONV hConvClient;
+ HCONV hConvServer;
+} MONCONVSTRUCT;
+
+#define MAX_MONITORS 4
+#define APPCLASS_MONITOR 0x00000001L
+#define XTYP_MONITOR (0x00F0 | XCLASS_NOTIFICATION | XTYPF_NOBLOCK)
+
+/*
+ * Callback filter flags for use with MONITOR apps - 0 implies no monitor
+ * callbacks.
+ */
+#define MF_HSZ_INFO 0x01000000
+#define MF_SENDMSGS 0x02000000
+#define MF_POSTMSGS 0x04000000
+#define MF_CALLBACKS 0x08000000
+#define MF_ERRORS 0x10000000
+#define MF_LINKS 0x20000000
+#define MF_CONV 0x40000000
+
+#define MF_MASK 0xFF000000
+#endif /* NODDEMLSPY */
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_DDEML */
diff --git a/private/mvdm/wow16/inc/debug.h b/private/mvdm/wow16/inc/debug.h
new file mode 100644
index 000000000..39e44faf2
--- /dev/null
+++ b/private/mvdm/wow16/inc/debug.h
@@ -0,0 +1,32 @@
+/* This include file contains the functions needed by debuggers which run
+ * under windows.
+ */
+
+/* USER functions */
+BOOL FAR PASCAL QuerySendMessage(HANDLE h1, HANDLE h2, HANDLE h3, LPMSG lpmsg);
+BOOL FAR PASCAL LockInput(HANDLE h1, HWND hwndInput, BOOL fLock);
+
+LONG FAR PASCAL GetSystemDebugState(void);
+/* Flags returned by GetSystemDebugState.
+ */
+#define SDS_MENU 0x0001
+#define SDS_SYSMODAL 0x0002
+#define SDS_NOTASKQUEUE 0x0004
+
+/* Kernel procedures */
+void FAR PASCAL DirectedYield(HANDLE hTask);
+
+/* Debug hook to support debugging through other hooks.
+ */
+#define WH_DEBUG 9
+
+typedef struct tagDEBUGHOOKSTRUCT
+ {
+ WORD hAppHookTask; //"hTask" of the task that installed the app hook
+ DWORD dwUnUsed; // This field is unused.
+ LONG lAppHooklParam; //"lParam" of the App hook.
+ WORD wAppHookwParam; //"wParam" of the App hook.
+ int iAppHookCode; //"iCode" of the App hook.
+ } DEBUGHOOKSTRUCT;
+
+typedef DEBUGHOOKSTRUCT FAR *LPDEBUGHOOKSTRUCT;
diff --git a/private/mvdm/wow16/inc/debugsys.inc b/private/mvdm/wow16/inc/debugsys.inc
new file mode 100644
index 000000000..9f161d9c9
--- /dev/null
+++ b/private/mvdm/wow16/inc/debugsys.inc
@@ -0,0 +1,867 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1988-1990
+;
+; Title: DEBUGSYS.INC - VMM debugging include file
+;
+; Version: 1.00
+;
+; Date: 13-Jun-1988
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; README README README README README
+;
+; The "master copy" of this file lives in the WIN386 include directory.
+; If another copy of this file is ever checked in anywhere, the copy
+; should be checked periodically to make sure it is identical with the
+; master copy.
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 13-Jun-1988 RAL
+; 24-Oct-1988 RAP changed INT from 2E to 41, and added functions for
+; Windows to notify the debugger about segment selectors
+; 14-Dec-1988 RAP split services into ones available through INT 41h
+; for non-ring 0 clients and those available through INT 21h
+; for ring 0 clients
+; 11-Dec-1990 ERH Merged WIN386 copy with file actually used by the
+; debugger.
+; 11-Dec-1990 ERH Merged file describing real mode services with this
+; one.
+;
+;==============================================================================
+
+;******************************************************************************
+;
+; Real mode Debugger services:
+;
+;
+
+D386_RM_Int equ 68h ; hooked by the debugger in real mode.
+
+D386_Id equ 0F386h ; debugger identification code
+
+D386_MIN equ 43h ; minimum INT 68 function code
+
+D386_Identify equ 43h ; returns debugger identification, if debugger
+ ; loaded
+
+D386_Prepare_PMode equ 44h ; partially prepare for protected mode operation
+ ; a pointer to a procedure is returned so that
+ ; the IDT can also be set in protected mode
+ ; INPUT:
+ ; AL 0 - retail version of Win386
+ ; 1 - debugging version
+ ; BX a valid selector that gives access
+ ; to all of memory
+ ; CX first of 2 selectors reserved for
+ ; WDeb386 to use
+ ; DX is GDT selector
+ ; DS:SI pointer to working copy of GDT
+ ; ES:DI pointer to working copy of IDT
+ ;
+ ; RETURN:
+ ; ES:EDI points to a protected mode procedure
+ ; (selector:offset32) that can be called
+ ; to set the IDT when it has been created.
+ ; This protected mode procedure takes a
+ ; pointer to the PMode IDT in ES:EDI.
+
+D386_Real_Mode_Init equ 45h ; re-init fro real mode after entering pmode
+
+D386_Set_Switches equ 46h ; set debugging switches
+ ; BL = verbose switch
+ ; - 00b - no segment display
+ ; - 01b - display win386 segments only
+ ; - 10b - display ring 1 segments only
+ ; - 11b - display win386 & ring 1 segs
+ ; BH = conditional brkpts
+ ; 0 - off
+ ; 1 - on
+ ; -1 for BX means no change (default)
+
+D386_Execute_Cond equ 47h ; execute conditional BP (/B option)
+ ; ES:SI points to NUL terminated string
+ ; to print if conditional flag set.
+
+D386_Set_Baudrate equ 49h ; set com port baud rate
+ ; BX = baud rate
+
+D386_Reinit equ 4ah ; reinitialize debugger for protected mode
+ ; AL 0 - retail version of Win386
+ ; 1 - debugging version of Win386
+ ; 2 - 286 DOS extender (3.0)
+ ; 3 - 286 DOS extender under VCPI (3.1)
+ ; 4 - 286 DOS extender (3.1)
+ ; BX a valid selector that gives access
+ ; to all of memory
+ ; CX first of 2 selectors reserved for
+ ; wdeb386 to use
+ ; DX is GDT selector
+ ;
+ ; This function can after a function 45h only
+ ; if function 44 was executed in the past on
+ ; the IDT/GDT.
+
+D386_Def_Deb_Segs equ 4bh ; define debugger's segments
+
+D386_Set_Com_Port equ 4ch ; set com port number
+ ; BX = com port number
+ ; returns AX != 0, error bad com port
+
+D386_Link_Sym equ 4dh ; link sym file map
+ ; ES:DI pointer to AddrS struc in front of
+ ; sym file map.
+ ; BX = loader ID (used to unlink sym file maps)
+ ; A loader ID of 0 is used for all the maps
+ ; wdeb386 loads via /S is ran as a program and
+ ; -1 is used by the device driver version. All
+ ; loader IDs of 0 are automaticly unlinked when
+ ; wdeb386 exits.
+
+D386_Unlink_Sym equ 4eh ; unlink sym file maps
+ ; BX = loader ID - this routine looks at all
+ ; of the maps that are currently linked and
+ ; removes the ones that were loaded with this
+ ; ID.
+
+D386_Remove_Segs equ 4fh ; remove any undefined segments from the
+ ; name module's symbols
+ ; ES:DI pointer to module name
+
+D386_Load_Segment equ 50h ; defines the actual segment/selector for a
+ ; loaded segment to allow for symbol processing
+ ; INPUT:
+ ; AL segment type 0 - code selector
+ ; 1 - data selector
+ ; 10h - code segment
+ ; 11h - data segment
+ ; 40h - code segment & sel
+ ; 41h - data segment & sel
+ ; 80h - device driver code seg
+ ; 81h - device driver data seg
+ ; If AL < 80h then
+ ; BX segment #
+ ; CX actual segment/selector
+ ; DX actual selector (if 40h or 41h)
+ ; ES:DI pointer to module name
+ ; Else
+ ; ES:DI points to D386_Device_Params struc
+ ;
+ ; RETURN:
+ ; AL = 1, if successful, else 0
+
+D386_Display_Char equ 51h ; display a character to the debugging terminal
+ ; AL = char to display
+
+D386_Display_Str equ 52h ; display a string to the debugging terminal
+ ; ES:SI points to NUL terminated string
+
+D386_IsVxDInstalled equ 53h ; returns if debug VxD has been installed
+ ; AL == 0 if not install, AL != 0 if installed
+
+D386_VxDInstall equ 54h ; sets that the debug VxD installed/uninstalled
+ ; BL == 0 if uninstall, BL != 0 if installed
+
+D386_RegisterDotCmd equ 55h ; registers dot command
+ ; BL = command letter
+ ; CX:SI = address of dot command routine
+ ; DX:DI = address of help text
+ ; returns AX == 0, no errors
+ ; AX != 0, dot command already used
+ ; or out of dot commands
+ ; Dot command routine:
+ ; AL = command character
+ ; DS:SI = linear address of command line
+ ; terminated by a NULL or ";".
+ ; DS,ES = debugger's data selector
+ ; returns AX == 0, no errors
+ ; AX !=0, command line or option error
+
+D386_DeRegisterDotCmd equ 56h ; de-registers dot command
+ ; BL = command letter
+
+D386_Printf equ 57h ; Printf
+ ; (DS:SI) = address of format string
+ ; (ES:DI) = address of the start of parameters
+ ; set DS_Printf for format char information
+
+D386_Link_Sym_Phys equ 58h ; link symbol file with physical address
+ ; (DX:CX) = physical address of one extra
+ ; paragraph front of map file image.
+ ; (SI) = XMS handle (0 if just physical)
+ ; (BX) = load id
+
+D386_CheckMap equ 59h ; DX:DI = pointer to module name
+ ; returns AX != 0, map found
+ ; AX == 0, map not found
+
+D386_SetAutoLoadSym equ 5ah ; (BL) != 0, auto load symbols
+ ; (BL) == 0, don't auto load symbols
+
+D386_SetTeftiPort equ 5bh ; (BX) = TEFTI port address
+
+D386_ExecDebugCommand equ 5ch ; execute debugger command script
+ ; (DS:SI) = ptr to debugger command script str
+ ; (CX) = size of script
+
+D386_LoadCodeDataHigh equ 5dh ; makes the debugger copy its code/data high
+ ; (DX:BX) = physical address to put debugger
+
+D386_SetWinVersion equ 5eh ; sets Windows version number
+ ; (DI) = Version number (default if this
+ ; api not called is 0300h).
+
+D386_MAX equ 5eh ; maximum INT 68 function code
+
+; D386_Load_Segment type equates:
+
+ST_code_sel equ 0 ; code selector
+ST_data_sel equ 1 ; data selector
+ST_code_seg equ 10h ; code segment
+ST_data_seg equ 11h ; data segment
+ST_dual_code equ 40h ; code segment and selector
+ST_dual_data equ 41h ; data segment and selector
+ST_device_code equ 80h ; device driver code segment
+ST_device_data equ 81h ; device driver data segment
+
+; D386_Load_Segment device load parameters structure
+
+D386_Device_Params STRUC
+DD_logical_seg dw ? ; logical segment # from map
+DD_actual_sel dw ? ; actual selector value
+DD_base dd ? ; linear address offset for start of segment
+DD_length dd ? ; actual length of segment
+DD_name df ? ; 16:32 ptr to null terminated device name
+DD_sym_name df ? ; 16:32 ptr to null terminated symbolic
+ ; module name (i.e. Win386)
+DD_alias_sel dw ? ; alias selector value (0 = none)
+D386_Device_Params ENDS
+
+;
+; VCPI information, passed to debugger when client is DOS Extender
+; running as a VCPI client. This information is used to get into
+; and out of protected mode when running under a VCPI server.
+;
+;
+; This structure is also used by the DOS Extender.
+;
+WdebVCPIInfo STRUC
+;
+; Enter protected mode information.
+;
+ fnVCPI df ? ; VCPI protect mode server entry point
+ rdsVCPI dw ? ; Selector for VCPI server
+;
+; Enter v86 mode information.
+;
+ laVTP dd ? ; linear address of data structure containing
+ ; values for system registers.
+ Port67 dw ? ; Qualitas magic port for emulating INT 67h
+WdebVCPIInfo ENDS
+;
+; The following structure contains the system register contents for the
+; VCPI server to use when switching to protected mode. It is taken
+; from dxvcpi.inc in the DOSX project, and is part of the VCPI spec.
+;
+VTP struc
+ zaCr3VTP dd 0 ; physical addr of page directory
+ laGdtrVTP dd 0 ; linear addr in first meg of gdtr
+ laIdtrVTP dd 0 ; linear addr in first meg of idtr
+ selLdtVTP dw 0 ; selector of ldt
+ selTrVTP dw 0 ; selector of tr
+ ipVTP dw 0 ; 48-bit address of protect
+ unusedVTP dw 0 ; mode entry point to xfer to
+ csVTP dw 0 ;
+VTP ends
+
+VCPI_RM_CALLOUT_INT equ 67h ; v86 mode call to VCPI server
+;
+; Send this value in AX to the VCPI server to request V86 to protected
+; mode switch or protected to V86 mode switch.
+;
+VCPI_PROT_ENTRY equ 0DE0CH
+
+
+;******************************************************************************
+;
+; Protected mode Debugger services:
+;
+;
+
+
+Debug_Serv_Int equ 41h ; Interrupt that calls Deb386 to perform
+ ; debugging I/O, AX selects the function as
+ ; described by the following equates
+
+DS_Out_Char equ 0 ; function to display the char in DL
+DS_In_Char equ 1 ; function to read a char into AL
+DS_Out_Str equ 2 ; function to display a NUL terminated string
+ ; pointed to by DS:ESI
+DS_Is_Char equ 3 ; Non blocking In_Chr
+
+DS_DebLoaded equ 4Fh ; check to see if the debugger is installed and
+ ; knows how to deal with protected mode programs
+ ; return AX = F386h, if true
+DS_DebPresent equ 0F386h
+
+DS_Out_Str16 equ 12h ; function to display a NUL terminated string
+ ; pointed to by DS:SI
+ ; (same as function 2, but for 16 bit callers)
+
+DS_ForcedGO16 equ 40h ; enter the debugger and perform the equivalent
+ ; of a GO command to force a stop at the
+ ; specified CS:IP
+ ; CX is the desired CS
+ ; BX is the desired IP
+
+DS_LinkMap equ 45h ; DX:(E)DI = ptr to paragraph in front of map
+
+DS_UnlinkMap equ 46h ; DX:(E)DI = ptr to paragraph in front of map
+
+DS_CheckMap equ 47h ; DX:(E)DI = pointer to module name
+ ; returns AX != 0, map found
+ ; AX == 0, map not found
+
+DS_IsAutoLoadSym equ 48h ; returns AX != 0, auto load symbols
+ ; AX == 0, don't auto load symbols
+
+DS_LoadSeg equ 50h ; define a segment value for the
+ ; debugger's symbol handling
+ ; SI type 0 - code selector
+ ; 1 - data selector
+ ; 80h - code segment
+ ; 81h - data segment
+ ; BX segment #
+ ; CX actual segment/selector
+ ; DX data instance
+ ; ES:(E)DI pointer to module name
+
+DS_LoadSeg_32 equ 0150h ; Define a 32-bit segment for Windows 32
+ ; SI type 0 - code selector
+ ; 1 - data selector
+ ; DX:EBX points to a D386_Device_Params STRUC
+ ; with all the necessaries in it
+
+DS_MoveSeg equ 51h ; notify the debugger that a segment has moved
+ ; BX old segment value
+ ; CX new segment value
+
+DS_FreeSeg equ 52h ; notify the debugger that a segment has been
+ ; freed
+ ; BX segment value
+
+DS_FreeSeg_32 equ 0152h ; notify the debugger that a segment has been
+ ; freed
+ ; BX segment number
+ ; DX:EDI pointer to module name
+
+DS_DGH equ 56h ; register "dump global heap" handler
+ ; BX is code offset
+ ; CX is code segment
+DS_DFL equ 57h ; register "dump free list" handler
+ ; BX is code offset
+ ; CX is code segment
+DS_DLL equ 58h ; register "dump LRU list" handler
+ ; BX is code offset
+ ; CX is code segment
+
+DS_StartTask equ 59h ; notify debugger that a new task is starting
+ ; BX is task handle
+ ; task's initial registers are stored on the
+ ; stack:
+ ; push cs
+ ; push ip
+ ; pusha
+ ; push ds
+ ; push es
+ ; push ss
+ ; push sp
+
+DS_Kernel_Vars equ 5ah ; Used by the Windows kernel to tell the
+ ; debugger the location of kernel variables
+ ; used in the heap dump commands.
+ ; BX = version number of this data (03a0h)
+ ; DX:CX points to:
+ ; WORD hGlobalHeap ****
+ ; WORD pGlobalHeap ****
+ ; WORD hExeHead ****
+ ; WORD hExeSweep
+ ; WORD topPDB
+ ; WORD headPDB
+ ; WORD topsizePDB
+ ; WORD headTDB ****
+ ; WORD curTDB ****
+ ; WORD loadTDB
+ ; WORD LockTDB
+ ; WORD SelTableLen ****
+ ; DWORD SelTableStart ****
+ ;
+ ; The starred fields are used by the
+ ; heap dump commands which are internal
+ ; to WDEB386.
+
+
+DS_VCPI_Notify equ 5bh ; notify debugger that DOS extender is
+ ; running under a VCPI implementation,
+ ; and register VCPI protect mode interface
+ ; ES:DI points to a data structure used to
+ ; get from V86 mode to Pmode under VCPI.
+ ; This is defined in the VCPI version
+ ; 1.0 spec.
+DS_ReleaseSeg equ 5ch ; This does the same as a DS_FreeSeg, but
+ ; it restores any breakpoints first.
+
+DS_POSTLOAD = 60h ; Used by the RegisterPTrace interface
+DS_EXITCALL = 62h ; Somebody will fill these in if we ever
+DS_INT2 = 63h ; figure out what they are supposed to do.
+DS_LOADDLL = 64h
+DS_DELMODULE = 65h
+
+DS_NEWTASK = 0BH
+DS_FLUSHTASK = 0CH
+DS_SWITCHOUT = 0DH
+DS_SWITCHIN = 0EH
+
+DS_IntRings equ 20h ; function to tell debugger which INT 1's & 3's
+ ; to grab
+ ; BX = 0, grab only ring 0 ints
+ ; BX != 0, grab all ints
+DS_IncludeSegs equ 21h ; function to tell debugger to go ahead and
+ ; process INT 1's & 3's which occur in this
+ ; DX:DI points to list of selectors
+ ; (1 word per entry)
+ ; CX = # of selectors (maximum of 20)
+ ; CX = 0, to remove the list of segs
+MaxDebugSegs = 20
+
+DS_CondBP equ 0F001h ; conditional break pt, if the command line
+ ; switch /B is given when the debugger is run
+ ; or the conditional flag is later set, then
+ ; this int should cause the program to break
+ ; into the debugger, else this int should be
+ ; ignored!
+ ; ESI points to a nul terminated string to
+ ; display if break is to happen.
+
+DS_ForcedBP equ 0F002h ; break pt, which accomplishes the same thing
+ ; as an INT 1 or an INT 3, but is a break point
+ ; that should be permanently left in the code,
+ ; so that a random search of source code would
+ ; not result in the accidental removal of this
+ ; necessary break_pt
+
+DS_ForcedGO equ 0F003h ; enter the debugger and perform the equivalent
+ ; of a GO command to force a stop at the
+ ; specified CS:EIP
+ ; CX is the desired CS
+ ; EBX is the desired EIP
+
+DS_HardINT1 equ 0F004h ; check to see if INT 1 hooked for all rings
+ ; ENTER: nothing
+ ; EXIT: AX = 0, if no, 1, if yes
+
+DS_FatalFault equ 0F005h ; check if fault is hooked by debugger via VSF
+ ; ENTRY BX = trap number
+ ; DX = error code
+ ; CX:(E)SI = address of CS:(E)IP
+ ; EXIT: AL == 0, handle fault normally
+ ; AL != 0, handled by debugger
+
+DS_Out_Symbol equ 0Fh ; find the symbol nearest to the address in
+ ; CX:EBX and display the result in the format
+ ; symbol name <+offset>
+ ; the offset is only included if needed, and
+ ; no CR&LF is displayed
+
+DS_Disasm_Ins equ 10h ; function to disassemble the instruction
+ ; pointed to by DS:ESI
+
+DS_RegisterDotCommand equ 70h ; registers a 32 bit dot command handler
+
+; This interface is used to register wdeb386 dot commands by FLAT 32
+; bit code. The following conditions apply:
+;
+; * The code will be run at ring 0
+; * Interrupts may not be enabled
+; * Must not access any not present pages or load invalid selectors
+; * Must stay on the stack called with when calling INT 41 services
+; * Must not change DS or ES from the FLAT selector
+;
+; The help text is printed when .? is executed in the order of
+; registration. The text must include CR/LF at the end; nothing
+; is added to the help text.
+;
+; ENTRY: (AX) = 0070h
+; (BL) = dot command to register
+; (ESI) = linear address of dot command routine
+; Dot command routine:
+; ENTRY: (AL) = command character
+; (DS, ES) = flat data selector
+;
+; EXIT: (AX) == 0, no errors
+; (AX) !=0, command line or option error
+;
+; NOTE: MUST return with a 32 bit FAR return (retfd)
+; (EDI) = linear address of help text
+;
+; EXIT: (AX) == 0, no errors
+; (AX) != 0, dot command already used or out of dot commands
+
+DS_RegisterDotCommand16 equ 71h ; registers a 16 bit dot command handler
+
+; This interface is used to register wdeb386 dot commands by 16 bit
+; code. The following conditions apply:
+;
+; * The code will be run at ring 0 or in real mode
+; * Interrupts may not be enabled
+; * Must not access any not present pages or load invalid selectors
+; * Must stay on the stack called with when calling INT 41 services
+;
+; The help text is printed when .? is executed in the order of
+; registration. The text must include CR/LF at the end; nothing
+; is added to the help text.
+;
+; ENTRY: (AX) = 0071h
+; (BL) = dot command to register
+; (CX:SI) = address of dot command routine
+; Dot command routine:
+; ENTRY: (AL) = command character
+; (DS, ES) = debugger's data selector
+;
+; EXIT: (AX) == 0, no errors
+; (AX) != 0, command line or option error
+;
+; NOTE: MUST return with a 16 bit FAR return (retf)
+; (DX:DI) = address of help text
+;
+; EXIT: (AX) == 0, no errors
+; (AX) != 0, dot command already used or out of dot commands
+
+DS_DeRegisterDotCommand equ 72h ; de-registers 16 or 32 bit dot command
+
+; This interface is used to de-register wdeb386 dot commands registered
+; by the above 16 or 32 bit services. Care should be used not to
+; de-register dot commands that weren't registered by your code.
+;
+; ENTRY: (AX) = 0072h
+; (BL) = dot command to de-register
+;
+; EXIT: NONE
+
+DS_Printf equ 73h ; print formatted output
+
+; This function allows formatted output with the standard "C"
+; printf syntax.
+;
+; ENTRY: (AX) = 0073h
+; (DS:ESI) = address of format string
+; (ES:EDI) = address of the start of the dword arguments
+;
+; EXIT: NONE
+;
+; Supported types are:
+;
+; %% %
+; %[l][h]c character
+; %[-][+][ ][0][width][.precision][l][h][p][n]d decimal
+; %[-][0][width][.precision][l][h][p][n]u unsigned decimal
+; %[-][#][0][width][.precision][l][h][p][n]x hex
+; %[-][#][0][width][.precision][l][h][p][n]X hex
+; %[-][0][width][.precision][l][h][p][n]o octal
+; %[-][0][width][.precision][l][h][p][n]b binary
+; %[-][width][.precision][l][h][a][F]s string
+; %[-][width][.precision][l][h][a][p][n][F][L][H][N]S symbol
+; %[-][width][.precision][l][h][a][p][n][F][L][H][N]G group:symbol
+; %[-][width][.precision][l][h][a][p][n][F][L][H][N]M map:group:symbol
+; %[-][width][.precision][l][h][a][p][n][F][L][H][N]A address
+;
+; Where "width" or "precision" is a decimal number or the '*'
+; character; '*' causes the field width or precision to be picked
+; up from the next parameter. []'ed parameters are optional.
+;
+; "\r", "\t", "\n", "\a", "\b", are supported directly.
+;
+; Prefixes
+; --------
+;
+; Used with c,d,u,x,X,o,b:
+;
+; Parameter Argument Size
+; -----------------------
+; word h
+; dword l
+;
+; Used with s,S,G,M,A:
+;
+; Address Argument Size
+; ---------------------
+; 16 bit DS relative h
+; 16:16 segment:offset hF or Fh
+; 32 bit flat relative l
+; 16:32 segment:offset (2 dwords) lF or Fl
+; pointer to AddrS structure a
+;
+; Used with S,G,M,A:
+;
+; Address Display Size or Format
+; ------------------------------
+; 16 bit offset H
+; 32 bit offset L
+; offset only N
+;
+; Default display size depends on the "386env" flag setting.
+;
+; Used with S,G,M:
+;
+; gets the previous symbol p
+; gets the next symbol n
+;
+; Used with A:
+;
+; gets the previous symbol address p
+; gets the next symbol address n
+;
+; Used with d,u,x,X,o,b:
+;
+; gets the previous symbol offset p
+; gets the next symbol offset n
+;
+
+DS_Printf16 equ 74h ; print formatted 16 bit output
+
+; This function allows formatted output with the standard "C"
+; printf syntax.
+;
+; ENTRY: (AX) = 0074h
+; (DS:SI) = address of format string
+; (ES:DI) = address of the start of the word or dword arguments
+;
+; EXIT: NONE
+;
+; The format options and parameters are the same as DS_Printf except
+; the default parameter size is a word (the h option is implicit).
+;
+
+DS_GetRegisterSet equ 75h ; get the debugger's registers
+
+; This function copies the current register set.
+;
+; ENTRY: (AX) = 0075h
+; (DS:ESI) = address of SaveRegs_Struc structure
+;
+; EXIT: NONE
+;
+
+DS_SetAlternateRegisterSet equ 76h ; set the debugger's registers
+
+; This function temporary sets the debugger's registers to values
+; passed in the structure. If an "r" command is executed or the
+; debugged code is returned to (via the "g", "t" or "p" commands),
+; the register set reverts to the debugged code's registers.
+;
+; ENTRY: (AX) = 0076h
+; (CX) = thread ID, 0 use current thread ID
+; (DS:ESI) = address of SaveRegs_Struc structure
+;
+; EXIT: NONE
+;
+
+DS_GetCommandLineChar equ 77h ; get a character from the command line
+
+; This services gets the next character off the command line.
+;
+; ENTRY: (AX) = 0077h
+; (BL) == 0 just peek the character, don't increment text pointer
+; leading white space isn't ignored
+; (BL) != 0 get the character, increment text pointer
+; leading white space is skipped
+;
+; EXIT: (AL) = command line character
+; (AH) == 0 if no more characters (EOL)
+; (AH) != 0 if more characters
+;
+
+DS_EvaluateExpression equ 78h ; evaluate debugger command line expression
+
+; Expressions can be numbers of various radices, symbols, addresses
+; or an combination of the above hooked together with various
+; operators. Expressions are separated by blanks or commas. This
+; function is passed a pointer to the beginning of the text of the
+; expression (i.e. "%80003444+4232"). The expression is either
+; evaluated down into a dword value if there are no addresses or
+; into a linear address.
+;
+; ENTRY: (AX) = 0078h
+;
+; EXIT: (AX) == 0, returning a data value
+; (AX) != 0, returning a linear address
+; (EBX) = return value
+;
+; NOTE: If the expression is invalid, this service will not
+; return. A message is printed and control returns to
+; the command loop.
+;
+
+DS_VerifyMemory equ 79h ; verify the memory is valid and present
+
+; ENTRY: (AX) = 0079h
+; (ECX) = length of memory region
+; (DS:ESI) = address of memory to verify
+;
+; EXIT: (AX) == 0, no errors
+; (AX) != 0, invalid memory
+
+DS_PrintRegisters equ 7ah ; print the register set (the "r" command)
+
+; This function prints (just like the "r" command) the either the
+; debugged code's registers or the alternate register set, set with
+; DS_SetAlternateRegisterSet function.
+;
+; ENTRY: (AX) = 007ah
+;
+; EXIT: NONE
+;
+; NOTE: If the CS:EIP is invalid, this service will not return
+; because of an error when the code is disassembled. A
+; message is printed and control returns to the command loop.
+;
+
+DS_PrintStackDump equ 7bh ; dumps the [E]BP stack chain (the "k" command)
+
+; This function prints (just like the "k" command) the stack dump
+; based on the current register set that may have been set with
+; DS_SetAlternateRegisterSet function.
+;
+; ENTRY: (AX) = 007bh
+; (BX) = flags
+; 01h - verbose stack dump
+; 02h - 16 bit stack dump
+; 04h - 32 bit stack dump
+;
+; EXIT: NONE
+;
+; NOTE: If the CS:EIP or SS:EBP are invalid, this service will not
+; return because of an error when accessing the stack. A
+; message is printed and control returns to the command loop.
+;
+
+DS_SetThreadID equ 7ch ; sets the debugger's thread ID
+
+; This function sets what the debugger thinks the thread ID is
+; for memory address in other address contexts. It stays set
+; until the debugged code is returned to (via "g", "t" or "p")
+; or set back to 0.
+;
+; ENTRY: (AX) = 007ch
+; (CX) = thread ID or 0 for currently executed thread
+;
+; EXIT: NONE
+
+DS_ExecDebugCommand equ 7dh ; execute debugger command script
+
+; This service allows any debugger command to be executed. In can
+; be a multi-lined script with the lines separated by CR, LF. MUST
+; have a "g" command at the end of script so the debugger doesn't
+; stop while in the INT 41.
+;
+; ENTRY: (AX) = 007dh
+; (DS:ESI) = pointer to debugger command script string
+; (CX) = size of script
+;
+; EXIT: NONE
+
+;
+; Interupt and services that Win386 provides to the debugger
+;
+
+Win386_Query_Int equ 22h ; interrupt for Win386 protected mode
+ ; interface requests
+
+Win386_Alive equ 0 ; function 0, query Win386 installation
+Win386_Q_Ack equ 0F386h ; good response from func 43h, of
+ ; INT 68h & func 4fh of INT 41h
+
+Win386_Query equ 1 ; function 1, query Win386 state
+ ; ds:esi points to command string
+ ; that Win386 needs to process
+ ; ds:edi points to the SaveRegs_Struc
+ ; that the debugger has stored all the
+ ; client register state into.
+ ; (Win386 just writes the query
+ ; answers directly to the output
+ ; device, so no response is
+ ; returned)
+
+Win386_PhysToLinr equ 2 ; function 2, have Win386 convert a
+ ; physical address into a valid
+ ; linear address that Deb386 can
+ ; use. esi is physicaladdress
+ ; cx is # of bytes required
+ ; returns esi as linear address
+ ; returns ax = 1, if okay, else
+ ; 0, if request couldn't be
+ ; completed
+
+Win386_AddrValid equ 3 ; function 3, have Win386 check the
+ ; validity of a linear address
+ ; esi is linear address to check
+ ; cx is # of bytes required
+ ; returns ax = 1, if address okay
+ ; else ax = 0
+
+Win386_MapVM equ 4 ; function 4, make sure that the VM's
+ ; low memory is mapped in, in case
+ ; it is touched (a count is maintained)
+Win386_UnmapVM equ 5 ; function 5, map out the VM's low
+ ; memory (dec the count)
+Win386_GetDLAddr equ 6 ; function 6, return offset of dyna-link
+ ; service. EBX = Device ID << 10h +
+ ; Service #. Returns EAX = Offset.
+Max_Win386_Services equ 6
+
+
+SaveRegs_Struc STRUC
+Debug_EAX dd ?
+Debug_EBX dd ?
+Debug_ECX dd ?
+Debug_EDX dd ?
+Debug_ESP dd ?
+Debug_EBP dd ?
+Debug_ESI dd ?
+Debug_EDI dd ?
+Debug_ES dw ?
+Debug_SS dw ?
+Debug_DS dw ?
+Debug_FS dw ?
+Debug_GS dw ?
+Debug_EIP dd ?
+Debug_CS dw ?
+ dd ?
+Debug_EFlags dd ?
+Debug_CR0 dd ?
+Debug_GDT dq ?
+Debug_IDT dq ?
+Debug_LDT dw ?
+Debug_TR dw ?
+Debug_CR2 dd ?
+Debug_CR3 dd ?
+Debug_DR0 dd ?
+Debug_DR1 dd ?
+Debug_DR2 dd ?
+Debug_DR3 dd ?
+Debug_DR6 dd ?
+Debug_DR7 dd ?
+Debug_DR7_2 dd ?
+Debug_TR6 dd ?
+Debug_TR7 dd ?
+Debug_TrapNumber dw -1 ; -1 means no trap number
+Debug_ErrorCode dw 0 ; 0 means no error code
+SaveRegs_Struc ENDS
diff --git a/private/mvdm/wow16/inc/dlgs.h b/private/mvdm/wow16/inc/dlgs.h
new file mode 100644
index 000000000..d701b0f05
--- /dev/null
+++ b/private/mvdm/wow16/inc/dlgs.h
@@ -0,0 +1,192 @@
+/*****************************************************************************\
+* *
+* dlgs.h - Common dialog's dialog element ID numbers *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_DLGS
+#define _INC_DLGS
+
+#define ctlFirst 0x0400
+#define ctlLast 0x04ff
+ /* Push buttons */
+#define psh1 0x0400
+#define psh2 0x0401
+#define psh3 0x0402
+#define psh4 0x0403
+#define psh5 0x0404
+#define psh6 0x0405
+#define psh7 0x0406
+#define psh8 0x0407
+#define psh9 0x0408
+#define psh10 0x0409
+#define psh11 0x040a
+#define psh12 0x040b
+#define psh13 0x040c
+#define psh14 0x040d
+#define psh15 0x040e
+#define pshHelp psh15
+#define psh16 0x040f
+ /* Checkboxes */
+#define chx1 0x0410
+#define chx2 0x0411
+#define chx3 0x0412
+#define chx4 0x0413
+#define chx5 0x0414
+#define chx6 0x0415
+#define chx7 0x0416
+#define chx8 0x0417
+#define chx9 0x0418
+#define chx10 0x0419
+#define chx11 0x041a
+#define chx12 0x041b
+#define chx13 0x041c
+#define chx14 0x041d
+#define chx15 0x041e
+#define chx16 0x041f
+ /* Radio buttons */
+#define rad1 0x0420
+#define rad2 0x0421
+#define rad3 0x0422
+#define rad4 0x0423
+#define rad5 0x0424
+#define rad6 0x0425
+#define rad7 0x0426
+#define rad8 0x0427
+#define rad9 0x0428
+#define rad10 0x0429
+#define rad11 0x042a
+#define rad12 0x042b
+#define rad13 0x042c
+#define rad14 0x042d
+#define rad15 0x042e
+#define rad16 0x042f
+ /* Groups, frames, rectangles, and icons */
+#define grp1 0x0430
+#define grp2 0x0431
+#define grp3 0x0432
+#define grp4 0x0433
+#define frm1 0x0434
+#define frm2 0x0435
+#define frm3 0x0436
+#define frm4 0x0437
+#define rct1 0x0438
+#define rct2 0x0439
+#define rct3 0x043a
+#define rct4 0x043b
+#define ico1 0x043c
+#define ico2 0x043d
+#define ico3 0x043e
+#define ico4 0x043f
+ /* Static text */
+#define stc1 0x0440
+#define stc2 0x0441
+#define stc3 0x0442
+#define stc4 0x0443
+#define stc5 0x0444
+#define stc6 0x0445
+#define stc7 0x0446
+#define stc8 0x0447
+#define stc9 0x0448
+#define stc10 0x0449
+#define stc11 0x044a
+#define stc12 0x044b
+#define stc13 0x044c
+#define stc14 0x044d
+#define stc15 0x044e
+#define stc16 0x044f
+#define stc17 0x0450
+#define stc18 0x0451
+#define stc19 0x0452
+#define stc20 0x0453
+#define stc21 0x0454
+#define stc22 0x0455
+#define stc23 0x0456
+#define stc24 0x0457
+#define stc25 0x0458
+#define stc26 0x0459
+#define stc27 0x045a
+#define stc28 0x045b
+#define stc29 0x045c
+#define stc30 0x045d
+#define stc31 0x045e
+#define stc32 0x045f
+ /* Listboxes */
+#define lst1 0x0460
+#define lst2 0x0461
+#define lst3 0x0462
+#define lst4 0x0463
+#define lst5 0x0464
+#define lst6 0x0465
+#define lst7 0x0466
+#define lst8 0x0467
+#define lst9 0x0468
+#define lst10 0x0469
+#define lst11 0x046a
+#define lst12 0x046b
+#define lst13 0x046c
+#define lst14 0x046d
+#define lst15 0x046e
+#define lst16 0x046f
+ /* Combo boxes */
+#define cmb1 0x0470
+#define cmb2 0x0471
+#define cmb3 0x0472
+#define cmb4 0x0473
+#define cmb5 0x0474
+#define cmb6 0x0475
+#define cmb7 0x0476
+#define cmb8 0x0477
+#define cmb9 0x0478
+#define cmb10 0x0479
+#define cmb11 0x047a
+#define cmb12 0x047b
+#define cmb13 0x047c
+#define cmb14 0x047d
+#define cmb15 0x047e
+#define cmb16 0x047f
+ /* Edit controls */
+#define edt1 0x0480
+#define edt2 0x0481
+#define edt3 0x0482
+#define edt4 0x0483
+#define edt5 0x0484
+#define edt6 0x0485
+#define edt7 0x0486
+#define edt8 0x0487
+#define edt9 0x0488
+#define edt10 0x0489
+#define edt11 0x048a
+#define edt12 0x048b
+#define edt13 0x048c
+#define edt14 0x048d
+#define edt15 0x048e
+#define edt16 0x048f
+ /* Scroll bars */
+#define scr1 0x0490
+#define scr2 0x0491
+#define scr3 0x0492
+#define scr4 0x0493
+#define scr5 0x0494
+#define scr6 0x0495
+#define scr7 0x0496
+#define scr8 0x0497
+
+/* These dialog resource ordinals really start at 0x0600, but the
+ * RC Compiler can't handle hex for resource IDs, hence the decimal.
+ */
+#define FILEOPENORD 1536
+#define MULTIFILEOPENORD 1537
+#define PRINTDLGORD 1538
+#define PRNSETUPDLGORD 1539
+#define FINDDLGORD 1540
+#define REPLACEDLGORD 1541
+#define FONTDLGORD 1542
+#define FORMATDLGORD31 1543
+#define FORMATDLGORD30 1544
+
+#endif /* !_INC_DLGS */
diff --git a/private/mvdm/wow16/inc/dosx.inc b/private/mvdm/wow16/inc/dosx.inc
new file mode 100644
index 000000000..4fab86669
--- /dev/null
+++ b/private/mvdm/wow16/inc/dosx.inc
@@ -0,0 +1,47 @@
+;******************************************************************************
+;
+; Copyright (c) Microsoft Corporation 1989-1990.
+;
+; Title: DOSX.INC - Equates and Structures for 286 DOS Extender
+; Int 2Fh Interface
+;
+; Version: 3.00
+;
+; Date: 27-Jun-1989
+;
+; Author: JEM
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 27-Jun-1989 JEM Original
+;
+;==============================================================================
+
+
+DOSXFunc EQU 46h ;286 DOS Extender Int 2Fh Multiplex ID
+
+
+; DOSX Int 2Fh subfunctions
+
+DOSXQuery EQU 00h ;Query DOS Extender installation
+DOSXSuspend EQU 01h ;Suspend Network posting call
+DOSXResume EQU 02h ;Resume Network posting call
+DOSXAbort EQU 03h ;Abort Child application call
+DOSXInfo EQU 04h ;Get Info structure pointer call
+
+DOSXLast EQU DOSXInfo ;Last valid Int 2Fh request
+
+
+; Structure returned in ES:BX by DOSXInfo call
+
+DOSXInfoTbl struc
+DOSXInfoVer dw ? ;version # of info structure
+hXMSHeap dw ? ;XMS handle to DOSX heap block
+selAppBlk dw ? ;1st selector to application memory blk
+cbAppBlk dd ? ;size in bytes of app memory block
+ckReservedLow dw ? ;size in K of low memory to reserve
+DOSXInfoTbl ends
diff --git a/private/mvdm/wow16/inc/drivinit.h b/private/mvdm/wow16/inc/drivinit.h
new file mode 100644
index 000000000..9db28db67
--- /dev/null
+++ b/private/mvdm/wow16/inc/drivinit.h
@@ -0,0 +1,2 @@
+/* OBSOLETE: Use print.h instead */
+#include <print.h>
diff --git a/private/mvdm/wow16/inc/gdidefs.inc b/private/mvdm/wow16/inc/gdidefs.inc
new file mode 100644
index 000000000..c59fcc16b
--- /dev/null
+++ b/private/mvdm/wow16/inc/gdidefs.inc
@@ -0,0 +1,1292 @@
+;/*
+;***************************************************************************
+; *
+; Copyright (C) 1983,1984,1985 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+
+
+; GDI Definitions for Device Drivers
+;
+; Since most of the routines only need a portion of these definitions,
+; conditional assembly flags have been defined in the various files
+; to only include portions as needed (as opposed to having a lot of
+; include files to mess with). The flags are as follows:
+;
+; incFont include font definitions
+; incDevice include device definitions
+; incLogical include logical object definitions
+; incDrawmode include DrawMode structure definition
+; incOutput include Output definitions
+; incControl include Control definitions
+
+page
+; General definitions that almost everyone will use.
+
+
+
+; Physical Bitmap Structure
+;
+; Bitmap data structure passed to OEM routines. Defines the location and
+; size of a main memory bitmap.
+
+
+
+BITMAP struc ;*/ typedef struct { /*
+
+ bmType dw 0 ; 0 means main memory bitmap. Non-zero ;*/ short int bmType; /*
+ ; is number of physical display and format
+ ; of the rest of the structure known only
+ ; to device driver
+ bmWidth dw 0 ; Width of bitmap in pixels ;*/ unsigned short int bmWidth; /*
+ bmHeight dw 0 ; Height of bitmap in pixels ;*/ unsigned short int bmHeight; /*
+ bmWidthBytes dw 0 ; #bytes per scan line ;*/ unsigned short int bmWidthBytes; /*
+ bmPlanes db 0 ; # of planes in bitmap ;*/ BYTE bmPlanes; /*
+ bmBitsPixel db 0 ; # of bits per pixel ;*/ BYTE bmBitsPixel; /*
+ bmBits dd 0 ; Far pointer to bits of main memory bitmap ;*/ BYTE FAR *bmBits; /*
+ bmWidthPlanes dd 0 ; Product of bmWidthBytes and bmHeight ;*/ unsigned long int bmWidthPlanes;/*
+ bmlpPDevice dd 0 ; Pointer to associated PDevice ;*/ BYTE FAR *bmlpPDevice; /*
+ bmSegmentIndex dw 0 ; Index to plaens next segment if non-zero ;*/ unsigned short int bmSegmentIndex; /*
+ bmScanSegment dw 0 ; Number of scans per segment ;*/ unsigned short int bmScanSegment; /*
+ bmFillBytes dw 0 ; Number of unused bytes per segment ;*/ unsigned short int bmFillBytes; /*
+ dw 0 ;*/ unsigned short int futureUse4; /*
+ dw 0 ;*/ unsigned short int futureUse5; /*
+BITMAP ends ;*/ } BITMAP; /*
+
+; structures used for Device Independent Bitmap (DIB) processing.
+; all taken out of Presentation Manager's documentation
+; Tuesday 25-October-1988 15:04 -by- Ron Gery [rong]
+
+; C definitions are provided below (separately).
+
+; triple used in PM1.1 (BitmapCoreInfo) format color table
+RGBTriple struc
+ rgbtBlue db 0
+ rgbtGreen db 0
+ rgbtRed db 0
+RGBTriple ends
+
+; RGB DWORD used in PM2.0 format color table
+RGBQuad struc
+ rgbBlue db 0
+ rgbGreen db 0
+ rgbRed db 0
+ rgbReserved db 0
+RGBQuad ends
+
+BitmapCoreHeader struc
+ bcSize dd 0
+ bcWidth dw 0
+ bcHeight dw 0
+ bcPlanes dw 0
+ bcBitCount dw 0
+BitmapCoreHeader ends
+
+; new format bitmap structure based on PM2.0 format DCR.
+; Tuesday 23-May-1989 16:05 -by- Ron Gery [rong]
+
+BitmapInfoHeader struc
+ biSize dd 0
+ biWidth dd 0
+ biHeight dd 0
+ biPlanes dw 0
+ biBitCount dw 0
+
+ biCompression dd 0
+ biSizeImage dd 0
+ biXPelsPerMeter dd 0
+ biYPelsPerMeter dd 0
+ biClrUsed dd 0
+ biClrImportant dd 0
+BitmapInfoHeader ends
+
+BitmapInfo struc
+ bmiHeader db (size BitmapInfoHeader) DUP (?)
+ bmiColors db ? ; array of RGBQUADS
+BitmapInfo ends
+
+BitmapCoreInfo struc
+ bmciHeader db (size BitmapCoreHeader) DUP (?)
+ bmciColors db ? ; array of RGBTRIPLES
+BitmapCoreInfo ends
+
+BI_RGB equ 0h
+BI_RLE8 equ 1h
+BI_RLE4 equ 2h
+
+ if 0
+
+*/
+/* C definitions for DIBs, as defined in windows.h */
+
+typedef struct {
+ DWORD bcSize;
+ WORD bcWidth;
+ WORD bcHeight;
+ WORD bcPlanes;
+ WORD bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR *LPBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER *PBITMAPCOREHEADER;
+
+typedef struct {
+ DWORD biSize;
+ DWORD biWidth;
+ DWORD biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+
+ DWORD biCompression;
+ DWORD biSizeImage;
+ DWORD biXPelsPerMeter;
+ DWORD biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+} BITMAPINFOHEADER;
+
+typedef BITMAPINFOHEADER FAR *LPBITMAPINFOHEADER;
+typedef BITMAPINFOHEADER *PBITMAPINFOHEADER;
+
+typedef struct {
+ BYTE rgbtBlue;
+ BYTE rgbtGreen;
+ BYTE rgbtRed;
+} RGBTRIPLE;
+
+typedef struct {
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+} RGBQUAD;
+
+typedef struct {
+ BITMAPCOREHEADER bmicHeader;
+ RGBQUAD bmiColors[1];
+} BITMAPINFO;
+
+typedef BITMAPINFO FAR *LPBITMAPINFO;
+typedef BITMAPINFO *PBITMAPINFO;
+
+
+/* currently, if the low byte of biCompression is non zero,
+ * it must be one of following */
+
+#define BI_RGB 0x00
+#define BI_RLE8 0x01
+#define BI_RLE4 0x02
+
+#define BITMAP_SELECTED 0x01
+#define BITMAP_64K 0x01
+
+#define DIBSIGNATURE 0x4944
+/*
+ endif
+
+ if 0
+*/
+#ifndef NOPTRC
+/*
+ endif
+
+
+PTTYPE struc ;*/ typedef struct { /*
+
+ xcoord dw 0 ;x coordinate of point ;*/ short int xcoord; /*
+ ycoord dw 0 ;y coordinate of point ;*/ short int ycoord; /*
+
+PTTYPE ends ;*/ } PTTYPE; /*
+ ;*/ typedef PTTYPE *PPOINT; /*
+ ;*/ typedef PTTYPE FAR *LPPOINT; /*
+ if 0
+*/
+#define POINT PTTYPE
+/*
+ endif
+
+
+
+RECT struc ;*/ typedef struct { /*
+
+ left dw 0 ;*/ short int left, /*
+ top dw 0 ;*/ top, /*
+ right dw 0 ;*/ right, /*
+ bottom dw 0 ;*/ bottom; /*
+
+RECT ends ;*/ } RECT; /*
+ ;*/ typedef RECT *PRECT; /*
+
+ if 0
+*/
+#endif
+/*
+ endif
+
+
+BOXTYPE struc ;*/ typedef struct { /*
+
+ min db SIZE PTTYPE dup (?) ;x,y starting coord ;*/ PTTYPE min; /*
+ ext db SIZE PTTYPE dup (?) ;x,y extents ;*/ PTTYPE ext; /*
+
+BOXTYPE ends ;*/ } BOXTYPE; /*
+
+
+ ;*/ typedef RECT FAR * LPRECT; /*
+
+page
+; Logical Object Definitions - incLogical
+ ifdef incLogical
+ if incLogical
+
+
+
+OBJ_PEN equ 1
+OBJ_BRUSH equ 2
+OBJ_FONT equ 3
+
+ if 0
+*/
+/* Object definitions used by GDI support routines written in C */
+
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+#define OBJ_FONT 3
+/*
+ endif
+
+
+LogBrush struc ;*/ typedef struct { /*
+
+ lbStyle dw 0 ;Style of logical BRUSH ;*/ unsigned short int lbStyle; /*
+ lbColor dd 0 ;RGB color ;*/ unsigned long int lbColor; /*
+ lbHatch dw 0 ;Hatching style ;*/ unsigned short int lbHatch; /*
+ lbBkColor dd 0 ;Background color for hatched brush ;*/ unsigned long int lbBkColor;/*
+
+LogBrush ends ;*/ } LOGBRUSH; /*
+
+lbPattern = lbColor ; pointer to physical pattern
+
+ if 0
+*/
+#define lbPattern lbColor
+/*
+ endif
+
+
+
+; Brush styles defined by GDI
+
+BS_SOLID equ 0
+BS_HOLLOW equ 1
+BS_HATCHED equ 2
+BS_PATTERN equ 3
+
+MaxBrushStyle equ 3
+
+
+
+; Hatched Brush hatching styles defined by GDI
+
+HS_HORIZONTAL equ 0 ; Horizontal -----
+HS_VERTICAL equ 1 ; Vertical |||||
+HS_FDIAGONAL equ 2 ; Foreward Diagonal /////
+HS_BDIAGONAL equ 3 ; Backward Diagonal \\\\\
+HS_CROSS equ 4 ; Cross +++++
+HS_DIAGCROSS equ 5 ; Diagonal Cross XXXXX
+
+MaxHatchStyle equ 5
+
+ if 0
+*/
+/* Brush Style definitions used by GDI support routines written in C */
+
+#define BS_SOLID 0
+#define BS_HOLLOW 1
+#define BS_HATCHED 2
+#define BS_PATTERN 3
+
+#define MaxBrushStyle 3
+
+
+/* Hatch Style definitions used by GDI support routines written in C */
+
+#define HS_HORIZONTAL 0 /* ----- */
+#define HS_VERTICAL 1 /* ||||| */
+#define HS_FDIAGONAL 2 /* ///// */
+#define HS_BDIAGONAL 3 /* \\\\\ */
+#define HS_CROSS 4 /* +++++ */
+#define HS_DIAGCROSS 5 /* xxxxx */
+
+#define MaxHatchStyle 5
+/*
+ endif
+
+
+
+
+; Logical Pen Structure
+
+LogPen struc ;*/ typedef struct { /*
+
+ lopnStyle dw 0 ;(solid, hollow, dashed..) ;*/ unsigned short int lopnStyle;/*
+ lopnWidth dw 0 ;This is really a point type ;*/ PTTYPE lopnWidth;/*
+ dw 0
+ lopnColor dd 0 ;*/ unsigned long int lopnColor;/*
+
+LogPen ends ;*/ } LOGPEN; /*
+
+ errnz <(SIZE PTTYPE) -4>
+
+
+
+; Line Style definitions
+
+LS_SOLID equ 0
+LS_DASHED equ 1
+LS_DOTTED equ 2
+LS_DOTDASHED equ 3
+LS_DASHDOTDOT equ 4
+LS_NOLINE equ 5
+LS_INSIDEFRAME equ 6
+
+MaxLineStyle equ LS_NOLINE
+
+ if 0
+*/
+/* Line Style definitions used by GDI support routines written in C */
+
+#define LS_SOLID 0
+#define LS_DASHED 1
+#define LS_DOTTED 2
+#define LS_DOTDASHED 3
+#define LS_DASHDOTDOT 4
+#define LS_NOLINE 5
+#define LS_INSIDEFRAME 6
+#define MaxLineStyle LS_NOLINE
+/*
+ endif
+
+
+
+; Various constants for defining a logical font.
+OUT_DEFAULT_PRECIS equ 0
+OUT_STRING_PRECIS equ 1
+OUT_CHARACTER_PRECIS equ 2
+OUT_STROKE_PRECIS equ 3
+OUT_TT_PRECIS equ 4
+OUT_DEVICE_PRECIS equ 5
+OUT_RASTER_PRECIS equ 6
+OUT_TT_ONLY_PRECIS equ 7
+
+CLIP_DEFAULT_PRECIS equ 0
+CLIP_CHARACTER_PRECIS equ 1
+CLIP_STROKE_PRECIS equ 2
+CLIP_MASK equ 00Fh
+CLIP_LH_ANGLES equ 010h
+CLIP_TT_ALWAYS equ 020h
+CLIP_EMBEDDED equ 080h
+
+DEFAULT_QUALITY equ 0
+DRAFT_QUALITY equ 1
+PROOF_QUALITY equ 2
+
+DEFAULT_PITCH equ 0
+FIXED_PITCH equ 1
+VARIABLE_PITCH equ 2
+
+ANSI_CHARSET equ 0
+DEFAULT_CHARSET equ 1
+SYMBOL_CHARSET equ 2
+SHIFTJIS_CHARSET equ 128
+HANGEUL_CHARSET equ 129
+CHINESEBIG5_CHARSET equ 136
+OEM_CHARSET equ 255
+
+
+
+; GDI font families.
+FF_DONTCARE equ 00000000b ; Don't care or don't know.
+FF_ROMAN equ 00010000b ; Variable stroke width, serifed.
+ ; Times Roman, Century Schoolbook, etc.
+FF_SWISS equ 00100000b ; Variable stroke width, sans-serifed.
+ ; Helvetica, Swiss, etc.
+FF_MODERN equ 00110000b ; Constant stroke width, serifed or sans-serifed.
+ ; Pica, Elite, Courier, etc.
+FF_SCRIPT equ 01000000b ; Cursive, etc.
+FF_DECORATIVE equ 01010000b ; Old English, etc.
+
+
+; Font weights lightest to darkest.
+FW_DONTCARE equ 0d
+FW_THIN equ 100d
+FW_EXTRALIGHT equ 200d
+FW_LIGHT equ 300d
+FW_NORMAL equ 400d
+FW_MEDIUM equ 500d
+FW_SEMIBOLD equ 600d
+FW_BOLD equ 700d
+FW_EXTRABOLD equ 800d
+FW_HEAVY equ 900d
+
+FW_ULTRALIGHT equ FW_EXTRALIGHT
+FW_REGULAR equ FW_NORMAL
+FW_DEMIBOLD equ FW_SEMIBOLD
+FW_ULTRABOLD equ FW_EXTRABOLD
+FW_BLACK equ FW_HEAVY
+
+
+; Enumeration font types.
+RASTER_FONTTYPE equ 1
+DEVICE_FONTTYPE equ 2
+
+ if 0
+*/
+
+/* The size to allocate for the lfFaceName field in the logical font. */
+#ifndef LF_FACESIZE
+#define LF_FACESIZE 32
+#endif
+
+/* Various constants for defining a logical font. */
+#define OUT_DEFAULT_PRECIS 0
+#define OUT_STRING_PRECIS 1
+#define OUT_CHARACTER_PRECIS 2
+#define OUT_STROKE_PRECIS 3
+#define OUT_TT_PRECIS 4
+#define OUT_DEVICE_PRECIS 5
+#define OUT_RASTER_PRECIS 6
+#define OUT_TT_ONLY_PRECIS 7
+
+#define CLIP_DEFAULT_PRECIS 0
+#define CLIP_CHARACTER_PRECIS 1
+#define CLIP_STROKE_PRECIS 2
+#define CLIP_MASK 0x0F
+#define CLIP_LH_ANGLES 0x10
+#define CLIP_TT_ALWAYS 0x20
+#define CLIP_EMBEDDED 0x80
+
+#define DEFAULT_QUALITY 0
+#define DRAFT_QUALITY 1
+#define PROOF_QUALITY 2
+
+#define DEFAULT_PITCH 0
+#define FIXED_PITCH 1
+#define VARIABLE_PITCH 2
+
+#define ANSI_CHARSET 0
+#define DEFAULT_CHARSET 1
+#define SYMBOL_CHARSET 2
+#define SHIFTJIS_CHARSET 128
+#define HANGEUL_CHARSET 129
+#define CHINESEBIG5_CHARSET 136
+#define OEM_CHARSET 255
+
+
+/* GDI font families. */
+#define FF_DONTCARE (0<<4) /* Don't care or don't know. */
+#define FF_ROMAN (1<<4) /* Variable stroke width, serifed. */
+ /* Times Roman, Century Schoolbook, etc.*/
+#define FF_SWISS (2<<4) /* Variable stroke width, sans-serifed. */
+ /* Helvetica, Swiss, etc. */
+#define FF_MODERN (3<<4) /* Constant stroke width, serifed or sans-serifed. */
+ /* Pica, Elite, Courier, etc. */
+#define FF_SCRIPT (4<<4) /* Cursive, etc. */
+#define FF_DECORATIVE (5<<4) /* Old English, etc. */
+
+
+/* Font weights lightest to darkest. */
+#define FW_DONTCARE 0
+#define FW_THIN 100
+#define FW_EXTRALIGHT 200
+#define FW_LIGHT 300
+#define FW_NORMAL 400
+#define FW_MEDIUM 500
+#define FW_SEMIBOLD 600
+#define FW_BOLD 700
+#define FW_EXTRABOLD 800
+#define FW_HEAVY 900
+
+#define FW_ULTRALIGHT FW_EXTRALIGHT
+#define FW_REGULAR FW_NORMAL
+#define FW_DEMIBOLD FW_SEMIBOLD
+#define FW_ULTRABOLD FW_EXTRABOLD
+#define FW_BLACK FW_HEAVY
+
+/* Enumeration font types. */
+#define RASTER_FONTTYPE 1
+#define DEVICE_FONTTYPE 2
+
+/*
+ endif
+
+
+LogFont struc ;*/ typedef struct { /*
+
+ lfHeight dw 0 ;*/ short int lfHeight; /*
+ lfWidth dw 0 ;*/ short int lfWidth; /*
+ lfEscapement dw 0 ;*/ short int lfEscapement; /*
+ lfOrientation dw 0 ;*/ short int lfOrientation; /*
+ lfWeight dw 0 ;*/ short int lfWeight; /*
+ lfItalic db 0 ;*/ BYTE lfItalic; /*
+ lfUnderline db 0 ;*/ BYTE lfUnderline; /*
+ lfStrikeOut db 0 ;*/ BYTE lfStrikeOut; /*
+ lfCharSet db 0 ;*/ BYTE lfCharSet; /*
+ lfOutPrecision db 0 ;*/ BYTE lfOutPrecision; /*
+ lfClipPrecision db 0 ;*/ BYTE lfClipPrecision; /*
+ lfQuality db 0 ;*/ BYTE lfQuality; /*
+ lfPitchAndFamily db 0 ;*/ BYTE lfPitchAndFamily; /*
+ lfFaceName db 0 ; A variable length field for the face name.;*/ BYTE lfFaceName[LF_FACESIZE]; /*
+
+LogFont ends ;*/ } LOGFONT; /*
+
+
+ endif
+ endif
+page
+; Device Definitions - incDevice
+
+
+ ifdef incDevice
+ if incDevice
+
+
+InquireInfo = 00000001b ;Inquire Device GDI Info
+EnableDevice = 00000000b ;Enable Device
+InfoContext = 8000h ;Inquire/Enable for information context
+
+
+
+; Device Technologies
+
+DT_PLOTTER equ 0 ; Vector plotter
+DT_RASDISPLAY equ 1 ; Raster display
+DT_RASPRINTER equ 2 ; Raster printer
+DT_RASCAMERA equ 3 ; Raster camera
+DT_CHARSTREAM equ 4 ; Character-stream, PLP
+DT_METAFILE equ 5 ; Metafile, VDM
+DT_DISPFILE equ 6 ; Display-file
+
+
+; Curve Capabilities
+
+CC_NONE equ 00000000B ; Curves not supported
+CC_CIRCLES equ 00000001B ; Can do circles
+CC_PIE equ 00000010B ; Can do pie wedges
+CC_CHORD equ 00000100B ; Can do chord arcs
+CC_ELLIPSES equ 00001000B ; Can do ellipese
+CC_WIDE equ 00010000B ; Can do wide lines
+CC_STYLED equ 00100000B ; Can do styled lines
+CC_WIDESTYLED equ 01000000B ; Can do wide styled lines
+CC_INTERIORS equ 10000000B ; Can do interiors
+CC_ROUNDRECT equ 0100000000B ; Can do round rectangles
+
+
+; Line Capabilities
+
+LC_NONE equ 00000000B ; Lines not supported
+; equ 00000001B ;
+LC_POLYLINE equ 00000010B ; Can do polylines
+LC_MARKER equ 00000100B ; Can do markers
+LC_POLYMARKER equ 00001000B ; Can do polymarkers
+LC_WIDE equ 00010000B ; Can do wide lines
+LC_STYLED equ 00100000B ; Can do styled lines
+LC_WIDESTYLED equ 01000000B ; Can do wide styled lines
+LC_INTERIORS equ 10000000B ; Can do interiors
+
+
+; Polygonal Capabilities
+
+PC_NONE equ 00000000B ; Polygonals not supported
+PC_POLYGON equ 00000001B ; Can do polygons
+PC_RECTANGLE equ 00000010B ; Can do rectangles
+PC_WINDPOLYGON equ 00000100B ; Can do winding polygons
+PC_TRAPEZOID equ 00000100B ; Can do trapezoids
+PC_SCANLINE equ 00001000B ; Can do scanlines
+PC_WIDE equ 00010000B ; Can do wide borders
+PC_STYLED equ 00100000B ; Can do styled borders
+PC_WIDESTYLED equ 01000000B ; Can do wide styled borders
+PC_INTERIORS equ 10000000B ; Can do interiors
+
+; Clipping Capabilities
+
+CP_NONE equ 00000000B ; No clipping at device level
+CP_RECTANGLE equ 00000001B ; Device Output clips to rectangles
+
+; Text Capabilities
+
+TC_NONE equ 0000000000000000B ; Text not supported
+TC_OP_CHARACTER equ 0000000000000001B ; Can do OutputPrecision CHARACTER
+TC_OP_STROKE equ 0000000000000010B ; Can do OutputPrecision STROKE
+TC_CP_STROKE equ 0000000000000100B ; Can do ClipPrecision STROKE
+TC_CR_90 equ 0000000000001000B ; Can do CharRotAbility 90
+TC_CR_ANY equ 0000000000010000B ; Can do CharRotAbility ANY
+TC_SF_X_YINDEP equ 0000000000100000B ; Can do ScaleFreedom X_YINDEPENDENT
+TC_SA_DOUBLE equ 0000000001000000B ; Can do ScaleAbility DOUBLE
+TC_SA_INTEGER equ 0000000010000000B ; Can do ScaleAbility INTEGER
+TC_SA_CONTIN equ 0000000100000000B ; Can do ScaleAbility CONTINUOUS
+TC_EA_DOUBLE equ 0000001000000000B ; Can do EmboldenAbility DOUBLE
+TC_IA_ABLE equ 0000010000000000B ; Can do ItalisizeAbility ABLE
+TC_UA_ABLE equ 0000100000000000B ; Can do UnderlineAbility ABLE
+TC_SO_ABLE equ 0001000000000000B ; Can do StrikeOutAbility ABLE
+TC_RA_ABLE equ 0010000000000000B ; Can do RasterFontAble ABLE
+TC_VA_ABLE equ 0100000000000000B ; Can do VectorFontAble ABLE
+TC_RESERVED equ 1000000000000000B ; Reserved. Must be returned zero.
+
+
+; Raster Capabilities
+
+RC_NONE equ 0000000000000000b ; No Raster Capabilities
+RC_BITBLT equ 0000000000000001b ; Can do bitblt
+RC_BANDING equ 0000000000000010b ; Requires banding support
+RC_SCALING equ 0000000000000100b ; Requires scaling support
+RC_BITMAP64 equ 0000000000001000b ; supports >64k bitmaps
+RC_GDI20_OUTPUT equ 0000000000010000b ; supports Window 2.0 output functions
+RC_GDI20_STATE equ 0000000000100000b ; DC has state block
+RC_SAVEBITMAP equ 0000000001000000b ; can save bitmaps locally
+RC_DI_BITMAP equ 0000000010000000b ; can do device independent bitmaps
+RC_PALETTE equ 0000000100000000b ; can do color palette management
+RC_DIBTODEV equ 0000001000000000b ; can do SetDIBitsToDevice
+RC_BIGFONT equ 0000010000000000b ; does BIGFONTs
+RC_STRETCHBLT equ 0000100000000000b ; can do StretchBlt
+RC_FLOODFILL equ 0001000000000000b ; can do FloodFill
+RC_STRETCHDIB equ 0010000000000000b ; can do StretchDIBits
+RC_OP_DX_OUTPUT equ 0100000000000000b ; can do opaque ext text out
+
+; DC Management Flags
+
+DC_SPDevice equ 00000001b ;Seperate PDevice required per device/filename
+DC_1PDevice equ 00000010b ;Only 1 PDevice allowed per device/filename
+DC_IgnoreDFNP equ 00000100b ;Ignore device/filename pairs when matching
+
+
+; dpCaps1 capability bits
+
+C1_TRANSPARENT equ 0000000000000001b ; supports transparency
+TC_TT_ABLE equ 0000000000000010b ; can do TT fonts through DDI or brute
+C1_TT_CR_ANY equ 0000000000000100b ; can do rotated TT fonts
+
+ if 0
+*/
+
+#define InquireInfo 0x01 /* Inquire Device GDI Info */
+#define EnableDevice 0x00 /* Enable Device */
+#define InfoContext 0x8000 /* Inquire/Enable for info context */
+
+
+/* Device Technologies */
+
+#define DT_PLOTTER 0 /* Vector plotter */
+#define DT_RASDISPLAY 1 /* Raster display */
+#define DT_RASPRINTER 2 /* Raster printer */
+#define DT_RASCAMERA 3 /* Raster camera */
+#define DT_CHARSTREAM 4 /* Character-stream, PLP */
+#define DT_METAFILE 5 /* Metafile, VDM */
+#define DT_DISPFILE 6 /* Display-file */
+
+/* Curve Capabilities */
+
+#define CC_NONE 00000000 /* Curves not supported */
+#define CC_CIRCLES 00000001 /* Can do circles */
+#define CC_PIE 00000002 /* Can do pie wedges */
+#define CC_CHORD 00000004 /* Can do chord arcs */
+#define CC_ELLIPSES 00000010 /* Can do ellipese */
+#define CC_WIDE 00000020 /* Can do wide lines */
+#define CC_STYLED 00000040 /* Can do styled lines */
+#define CC_WIDESTYLED 00000100 /* Can do wide styled lines*/
+#define CC_INTERIORS 00000200 /* Can do interiors */
+#define CC_ROUNDRECT 0x0100 /* Can do round rectangles */
+
+/* Line Capabilities */
+
+#define LC_NONE 00000000 /* Lines not supported */
+#define LC_POLYLINE 00000002 /* Can do polylines */
+#define LC_MARKER 00000004 /* Can do markers */
+#define LC_POLYMARKER 00000010 /* Can do polymarkers */
+#define LC_WIDE 00000020 /* Can do wide lines */
+#define LC_STYLED 00000040 /* Can do styled lines */
+#define LC_WIDESTYLED 00000100 /* Can do wide styled lines*/
+#define LC_INTERIORS 00000200 /* Can do interiors */
+
+/* Polygonal Capabilities */
+
+#define PC_NONE 00000000 /* Polygonals not supported*/
+#define PC_POLYGON 00000001 /* Can do polygons */
+#define PC_RECTANGLE 00000002 /* Can do rectangles */
+#define PC_WINDPOLYGON 00000004 /* Can do winding polygons */
+#define PC_TRAPEZOID 00000004 /* Can do trapezoids */
+#define PC_SCANLINE 00000010 /* Can do scanlines */
+#define PC_WIDE 00000020 /* Can do wide borders */
+#define PC_STYLED 00000040 /* Can do styled borders */
+#define PC_WIDESTYLED 00000100 /* Can do wide styled borders*/
+#define PC_INTERIORS 00000200 /* Can do interiors */
+
+/* Polygonal Capabilities */
+
+#define CP_NONE 00000000 /* no clipping of Output */
+#define CP_RECTANGLE 00000001 /* Output clipped to Rects */
+
+/* Text Capabilities */
+
+#define TC_OP_CHARACTER 0000001 /* Can do OutputPrecision CHARACTER */
+#define TC_OP_STROKE 0000002 /* Can do OutputPrecision STROKE */
+#define TC_CP_STROKE 0000004 /* Can do ClipPrecision STROKE */
+#define TC_CR_90 0000010 /* Can do CharRotAbility 90 */
+#define TC_CR_ANY 0000020 /* Can do CharRotAbility ANY */
+#define TC_SF_X_YINDEP 0000040 /* Can do ScaleFreedom X_YINDEPENDENT */
+#define TC_SA_DOUBLE 0000100 /* Can do ScaleAbility DOUBLE */
+#define TC_SA_INTEGER 0000200 /* Can do ScaleAbility INTEGER */
+#define TC_SA_CONTIN 0000400 /* Can do ScaleAbility CONTINUOUS */
+#define TC_EA_DOUBLE 0001000 /* Can do EmboldenAbility DOUBLE */
+#define TC_IA_ABLE 0002000 /* Can do ItalisizeAbility ABLE */
+#define TC_UA_ABLE 0004000 /* Can do UnderlineAbility ABLE */
+#define TC_SO_ABLE 0010000 /* Can do StrikeOutAbility ABLE */
+#define TC_RA_ABLE 0020000 /* Can do RasterFontAble ABLE */
+#define TC_VA_ABLE 0040000 /* Can do VectorFontAble ABLE */
+#define TC_RESERVED 0100000 /* Reserved. Must be returned zero. */
+
+/* Raster Capabilities */
+
+#define RC_NONE 00000000 /* No Raster Capabilities */
+#define RC_BITBLT 00000001 /* Can do bitblt */
+#define RC_BANDING 00000002 /* Requires banding support */
+#define RC_SCALING 00000004 /* Requires scaling support */
+#define RC_BITMAP64 00000010 /* supports >64k bitmaps */
+#define RC_GDI20_OUTPUT 00000020 /* support Windows 2.0 functions */
+#define RC_GDI20_STATE 00000040 /* dc has a state block */
+#define RC_SAVEBITMAP 00000100 /* can save bitmaps locally */
+
+#define RC_DI_BITMAP 00000200 /* can do device independent bitmaps*/
+#define RC_PALETTE 00000400 /* can do color palette management */
+#define RC_DIBTODEV 00001000 /* can do SetDIBitsToDevice */
+#define RC_BIGFONT 00002000 /* does BIGFONTs */
+#define RC_STRETCHBLT 00004000 /* can do StretchBlt */
+#define RC_FLOODFILL 00010000 /* can do FloodFill */
+#define RC_STRETCHDIB 00020000 /* can do StretchDIBits */
+
+/* DC Management Flags */
+
+#define DC_SPDevice 0000001 /* Seperate PDevice required per device/filename */
+#define DC_1PDevice 0000002 /* Only 1 PDevice allowed per device/filename */
+#define DC_IgnoreDFNP 0000004 /* Ignore device/filename pairs when matching */
+
+/* dpCaps1 capability bits */
+
+#define C1_TRANSPARENT 0x0001 /* supports transparency */
+#define TC_TT_ABLE 0x0002 /* can do TT fonts through DDI or brute */
+#define C1_TT_CR_ANY 0x0004 /* can do rotated TT fonts */
+
+/*
+ endif
+
+GDIINFO struc ;*/ typedef struct { /*
+
+ dpVersion dw 0 ; Version = 0100h for now ;*/ short int dpVersion; /*
+ dpTechnology dw 0 ; Device classification ;*/ short int dpTechnology; /*
+ dpHorzSize dw 0 ; Horizontal size in millimeters ;*/ short int dpHorzSize; /*
+ dpVertSize dw 0 ; Vertical size in millimeters ;*/ short int dpVertSize; /*
+ dpHorzRes dw 0 ; Horizontal width in pixels ;*/ short int dpHorzRes; /*
+ dpVertRes dw 0 ; Vertical width in pixels ;*/ short int dpVertRes; /*
+ dpBitsPixel dw 0 ; Number of bits per pixel ;*/ short int dpBitsPixel; /*
+ dpPlanes dw 0 ; Number of planes ;*/ short int dpPlanes; /*
+ dpNumBrushes dw 0 ; Number of brushes the device has ;*/ short int dpNumBrushes; /*
+ dpNumPens dw 0 ; Number of pens the device has ;*/ short int dpNumPens; /*
+ dw 0 ; Number of markers the device has ;*/ short int futureuse; /*
+ dpNumFonts dw 0 ; Number of fonts the device has ;*/ short int dpNumFonts; /*
+ dpNumColors dw 0 ; Number of colors in color table ;*/ short int dpNumColors; /*
+ dpDEVICEsize dw 0 ; Size required for the device descriptor ;*/ short int dpDEVICEsize; /*
+ dpCurves dw 0 ; Curves capabilities ;*/ unsigned short int /*
+ ;*/ dpCurves; /*
+ dpLines dw 0 ; Line capabilities ;*/ unsigned short int /*
+ ;*/ dpLines; /*
+ dpPolygonals dw 0 ; Polygonal capabilities ;*/ unsigned short int /*
+ ;*/ dpPolygonals; /*
+ dpText dw 0 ; Text capabilities ;*/ unsigned short int /*
+ ;*/ dpText; /*
+ dpClip dw 0 ; Clipping capabilities ;*/ unsigned short int /*
+ ;*/ dpClip; /*
+ dpRaster dw 0 ; Bitblt capabilities ;*/ unsigned short int /*
+ ;*/ dpRaster; /*
+ dpAspectX dw 0 ; Length of X leg ;*/ short int dpAspectX; /*
+ dpAspectY dw 0 ; Length of Y leg ;*/ short int dpAspectY; /*
+ dpAspectXY dw 0 ; Length of hypotenuse ;*/ short int dpAspectXY; /*
+ dpStyleLen dw 0 ; Length of segment for line styles ;*/ short int dpStyleLen; /*
+ dpMLoWin dw 0 ; Metric Lo res WinX,WinY (PTTYPE) ;*/ PTTYPE dpMLoWin; /*
+ dw 0
+ dpMLoVpt dw 0 ; Metric Lo res VptX,VptY (PTTYPE) ;*/ PTTYPE dpMLoVpt; /*
+ dw 0
+ dpMHiWin dw 0 ; Metric Hi res WinX,WinY (PTTYPE) ;*/ PTTYPE dpMHiWin; /*
+ dw 0
+ dpMHiVpt dw 0 ; Metric Hi res VptX,VptY (PTTYPE) ;*/ PTTYPE dpMHiVpt; /*
+ dw 0
+ dpELoWin dw 0 ; English Lo res WinX,WinY (PTTYPE) ;*/ PTTYPE dpELoWin; /*
+ dw 0
+ dpELoVpt dw 0 ; English Lo res VptX,VptY (PTTYPE) ;*/ PTTYPE dpELoVpt; /*
+ dw 0
+ dpEHiWin dw 0 ; English Hi res WinX,WinY (PTTYPE) ;*/ PTTYPE dpEHiWin; /*
+ dw 0
+ dpEHiVpt dw 0 ; English Hi res VptX,VptY (PTTYPE) ;*/ PTTYPE dpEHiVpt; /*
+ dw 0
+ dpTwpWin dw 0 ; Twips WinX,WinY (PTTYPE) ;*/ PTTYPE dpTwpWin; /*
+ dw 0
+ dpTwpVpt dw 0 ; Twips VptX,VptY (PTTYPE) ;*/ PTTYPE dpTwpVpt; /*
+ dw 0
+ dpLogPixelsX dw 0 ;Logical pixels/inch in X ;*/ short int dpLogPixelsX; /*
+ dpLogPixelsY dw 0 ;Logical pixels/inch in Y ;*/ short int dpLogPixelsY; /*
+ dpDCManage dw 0 ;DC Management flags ;*/ short int dpDCManage; /*
+ dpCaps1 dw 0 ; more capability bits ;*/ unsigned short int dpCaps1; /*
+ dpSpotSizeX dw 0 ;*/ short int futureuse4; /*
+ dw 0 ;*/ short int futureuse5; /*
+ dpSpotSizeY dw 0 ;*/ short int futureuse6; /*
+ dw 0 ;*/ short int futureuse7; /*
+
+; start of entries in version 3.0 of this structure
+
+ dpNumPalReg dw 0 ; Number of entries in device's palette ;*/ WORD dpNumPalReg; /*
+ dpPalReserved dw 0 ; Number of reserved entries palette ;*/ WORD dpPalReserved; /*
+ dpColorRes dw 0 ; bits of color resolution (total) ;*/ WORD dpColorRes; /*
+GDIINFO ends ;*/ } GDIINFO; /*
+
+ endif
+ endif
+
+
+page
+; Font Definitions
+ ifdef incFont
+ if incFont
+
+
+PF_BITS_IS_ADDRESS equ 4
+PF_DEVICE_REALIZED equ 10000000B
+PF_RASTER_TYPE equ 0
+PF_VECTOR_TYPE equ 1
+PF_OTHER1_TYPE equ 2
+PF_OTHER2_TYPE equ 3
+
+
+ if 0
+*/
+
+/* This bit in the dfType field signals that the dfBitsOffset field is an
+ absolute memory address and should not be altered. */
+#define PF_BITS_IS_ADDRESS 4
+
+/* This bit in the dfType field signals that the font is device realized. */
+#define PF_DEVICE_REALIZED 0x80
+
+/* These bits in the dfType give the fonttype -
+ raster, vector, other1, other2. */
+#define PF_RASTER_TYPE 0
+#define PF_VECTOR_TYPE 1
+#define PF_OTHER1_TYPE 2
+#define PF_OTHER2_TYPE 3
+
+/* The size to allocate for the dfMaps field in the physical font. */
+#ifndef DF_MAPSIZE
+#define DF_MAPSIZE 1
+#endif
+
+/*
+ endif
+
+
+; Font data structure passed to OEM routines. Refer to chapters 12 and
+; 13 of the OEM adaptation guide for a complete description.
+
+
+FONTINFO struc ;*/ typedef struct { /*
+
+ dfType dw 0 ; Type field for the font. ;*/ short int dfType; /*
+ dfPoints dw 0 ; Point size of font. ;*/ short int dfPoints; /*
+ dfVertRes dw 0 ; Vertical digitization. ;*/ short int dfVertRes; /*
+ dfHorizRes dw 0 ; Horizontal digitization. ;*/ short int dfHorizRes; /*
+ dfAscent dw 0 ; Baseline offset from char cell top. ;*/ short int dfAscent; /*
+ dfInternalLeading dw 0 ; Internal leading included in font ;*/ short int dfInternalLeading; /*
+ dfExternalLeading dw 0 ; Prefered extra space between lines ;*/ short int dfExternalLeading; /*
+ dfItalic db 0 ; Flag specifying if italic. ;*/ BYTE dfItalic; /*
+ dfUnderline db 0 ; Flag specifying if underlined. ;*/ BYTE dfUnderline; /*
+ dfStrikeOut db 0 ; Flag specifying if struck out. ;*/ BYTE dfStrikeOut; /*
+ dfWeight dw 0 ; Weight of font. ;*/ short int dfWeight; /*
+ dfCharSet db 0 ; Character set of font. ;*/ BYTE dfCharSet; /*
+ dfPixWidth dw 0 ; Width field for the font. ;*/ short int dfPixWidth; /*
+ dfPixHeight dw 0 ; Height field for the font. ;*/ short int dfPixHeight; /*
+ dfPitchAndFamily db 0 ; Flag specifying variable pitch, family. ;*/ BYTE dfPitchAndFamily; /*
+ dfAvgWidth dw 0 ; Average character width. ;*/ short int dfAvgWidth; /*
+ dfMaxWidth dw 0 ; Maximum character width. ;*/ short int dfMaxWidth; /*
+ dfFirstChar db 0 ; First character in the font. ;*/ BYTE dfFirstChar; /*
+ dfLastChar db 0 ; Last character in the font. ;*/ BYTE dfLastChar; /*
+ dfDefaultChar db 0 ; Default character for out of range. ;*/ BYTE dfDefaultChar; /*
+ dfBreakChar db 0 ; Character to define wordbreaks. ;*/ BYTE dfBreakChar; /*
+ dfWidthBytes dw 0 ; Number of bytes in each row. ;*/ short int dfWidthBytes; /*
+ dfDevice dd 0 ; Offset to device name. ;*/ unsigned long int dfDevice; /*
+ dfFace dd 0 ; Offset to face name. ;*/ unsigned long int dfFace; /*
+ dfBitsPointer dd 0 ; Bits pointer. ;*/ unsigned long int dfBitsPointer;/*
+ dfBitsOffset dd 0 ; Offset to the begining of the bitmap. ;*/ unsigned long int dfBitsOffset;/*
+ ; On the disk, this is relative to the
+ ; begining of the file. In memory this is
+ ; relative to the begining of this structure.
+ dfReservedByte db 0 ; filler byte to WORD-align charoffset ;*/ BYTE dfReservedByte; /*
+ dfCharOffset dw 0 ; Area for storing the character offsets, ;*/ unsigned short dfMaps[DF_MAPSIZE];/*
+ ; facename, device name (opt), and bitmap.
+
+FONTINFO ends ;*/ } FONTINFO; /*
+
+SCALABLEFONTINFO struc ;*/ typedef struct { /*
+ erType dw 0 ; Type field for the font. ;*/ short int erType; /*
+ erPoints dw 0 ; Point size of font. ;*/ short int erPoints; /*
+ erVertRes dw 0 ; Vertical digitization. ;*/ short int erVertRes; /*
+ erHorizRes dw 0 ; Horizontal digitization. ;*/ short int erHorizRes; /*
+ erAscent dw 0 ; Baseline offset from char cell top. ;*/ short int erAscent; /*
+ erInternalLeading dw 0 ; Internal leading included in font ;*/ short int erInternalLeading; /*
+ erExternalLeading dw 0 ; Prefered extra space between lines ;*/ short int erExternalLeading; /*
+ erItalic db 0 ; Flag specifying if italic. ;*/ BYTE erItalic; /*
+ erUnderline db 0 ; Flag specifying if underlined. ;*/ BYTE erUnderline; /*
+ erStrikeOut db 0 ; Flag specifying if struck out. ;*/ BYTE erStrikeOut; /*
+ erWeight dw 0 ; Weight of font. ;*/ short int erWeight; /*
+ erCharSet db 0 ; Character set of font. ;*/ BYTE erCharSet; /*
+ erPixWidth dw 0 ; Width field for the font. ;*/ short int erPixWidth; /*
+ erPixHeight dw 0 ; Height field for the font. ;*/ short int erPixHeight; /*
+ erPitchAndFamily db 0 ; Flag specifying pitch and family. ;*/ BYTE erPitchAndFamily; /*
+ erAvgWidth dw 0 ; Average character width. ;*/ short int erAvgWidth; /*
+ erMaxWidth dw 0 ; Maximum character width. ;*/ short int erMaxWidth; /*
+ erFirstChar db 0 ; First character in the font. ;*/ BYTE erFirstChar; /*
+ erLastChar db 0 ; Last character in the font. ;*/ BYTE erLastChar; /*
+ erDefaultChar db 0 ; Default character for out of range. ;*/ BYTE erDefaultChar; /*
+ erBreakChar db 0 ; Character to define wordbreaks. ;*/ BYTE erBreakChar; /*
+ erWidthBytes dw 0 ; Number of bytes in each row. ;*/ short int erWidthBytes; /*
+ erDevice dd 0 ; Offset to device name. ;*/ unsigned long int erDevice; /*
+ erFace dd 0 ; Offset to face name. ;*/ unsigned long int erFace; /*
+ erBitsPointer dd 0 ; Bits pointer. ;*/ unsigned long int erBitsPointer;/*
+ erBitsOffset dd 0 ; Offset to the begining of the bitmap. ;*/ unsigned long int erBitsOffset;/*
+ erFlags db 0 ; flags, and word align the stuff to come ;*/ BYTE erReservedByte; /*
+ erUnderlinePos dw 0 ; underline position relative to cell origin ;*/ short int erUnderlinePos; /*
+ erUnderlineThick dw 0 ; underline thickness ;*/ short int erUnderlineThick;/*
+ erStrikeoutPos dw 0 ; Strikeout position relative to cell origin ;*/ short int erStrikeoutPos; /*
+ erStrikeoutThick dw 0 ; strikeout thickness ;*/ short int erStrikeoutThick;/*
+SCALABLEFONTINFO ends ;*/ } SCALABLEFONTINFO; /*
+
+
+
+
+TEXTXFORM struc ;*/ typedef struct { /*
+
+ ftHeight dw 0 ;*/ short int ftHeight; /*
+ ftWidth dw 0 ;*/ short int ftWidth; /*
+ ftEscapement dw 0 ;*/ short int ftEscapement; /*
+ ftOrientation dw 0 ;*/ short int ftOrientation; /*
+ ftWeight dw 0 ;*/ short int ftWeight; /*
+ ftItalic db 0 ;*/ BYTE ftItalic; /*
+ ftUnderline db 0 ;*/ BYTE ftUnderline; /*
+ ftStrikeOut db 0 ;*/ BYTE ftStrikeOut; /*
+ ftOutPrecision db 0 ;*/ BYTE ftOutPrecision; /*
+ ftClipPrecision db 0 ;*/ BYTE ftClipPrecision; /*
+ ftAccelerator dw 0 ;*/ unsigned short int /*
+ ;*/ ftAccelerator; /*
+ ftOverhang dw 0 ;*/ short int ftOverhang; /*
+
+TEXTXFORM ends ;*/ } TEXTXFORM; /*
+
+
+
+TEXTMETRIC struc ;*/ typedef struct { /*
+
+ tmHeight dw 0 ; Ascent+Descent ;*/ short int tmHeight; /*
+ tmAscent dw 0 ; Pixels above the baseline ;*/ short int tmAscent; /*
+ tmDescent dw 0 ; Pixels below the baseline ;*/ short int tmDescent; /*
+ tmInternalLeading dw 0 ; Internal leading included in font ;*/ short int tmInternalLeading; /*
+ tmExternalLeading dw 0 ; Prefered extra space between lines ;*/ short int tmExternalLeading; /*
+ tmAveCharWidth dw 0 ; Of the letter 'X' ;*/ short int tmAveCharWidth; /*
+ tmMaxCharWidth dw 0 ;*/ short int tmMaxCharWidth; /*
+ tmWeight dw 0 ;*/ short int tmWeight; /*
+ tmItalic db 0 ;*/ BYTE tmItalic; /*
+ tmUnderlined db 0 ;*/ BYTE tmUnderlined; /*
+ tmStruckOut db 0 ;*/ BYTE tmStruckOut; /*
+ tmFirstChar db 0 ;*/ BYTE tmFirstChar; /*
+ tmLastChar db 0 ;*/ BYTE tmLastChar; /*
+ tmDefaultChar db 0 ; dfDefaultChar+dfFirstChar ;*/ BYTE tmDefaultChar; /*
+ tmBreakChar db 0 ; dfBreakChar+dfFirstChar ;*/ BYTE tmBreakChar; /*
+ tmPitchAndFamily db 0 ; Low bit zero if fixed pitch, one if ;*/ BYTE tmPitchAndFamily; /*
+ ; variable. Family in high nibble.
+ tmCharSet db 0 ;*/ BYTE tmCharSet; /*
+ tmOverhang dw 0 ;*/ short int tmOverhang; /*
+ tmDigitizedAspectX dw 0 ; Digitization aspect ratio ;*/ short int tmDigitizedAspectX; /*
+ tmDigitizedAspectY dw 0 ; in X and Y. ;*/ short int tmDigitizedAspectY; /*
+
+TEXTMETRIC ends ;*/ } TEXTMETRIC; /*
+
+
+
+ endif
+ endif
+page
+; Drawing mode definitions - incDrawMode
+
+
+ ifdef incDrawMode
+ if incDrawMode
+
+
+DRAWMODE struc ;*/ typedef struct { /*
+
+ Rop2 dw 0 ;The 16-bit encoded Logical op ;*/ short int Rop2; /*
+ bkMode dw 0 ;Background Mode (for text only) ;*/ short int bkMode; /*
+ bkColor dd 0 ;Physical background Color ;*/ unsigned long int bkColor; /*
+ TextColor dd 0 ;Physical text (forground) color ;*/ unsigned long int TextColor; /*
+ TBreakExtra dw 0 ; total pixles to stuff into a line ;*/ short int TBreakExtra;/*
+ BreakExtra dw 0 ; div(TBreakExtra, BreakCount) ;*/ short int BreakExtra; /*
+ BreakErr dw 0 ; running error term ;*/ short int BreakErr; /*
+ BreakRem dw 0 ; mod(TBreakExtra, BreakCount) ;*/ short int BreakRem; /*
+ BreakCount dw 0 ; count of breaks in the line ;*/ short int BreakCount; /*
+ CharExtra dw 0 ; extra pixles to stuff after each char ;*/ short int CharExtra; /*
+ ; (used to space out a font)
+ LbkColor dd 0 ;Logical background color ;*/ unsigned long int LbkColor; /*
+ LTextColor dd 0 ;Logical Text (forground) color ;*/ unsigned long int LTextColor; /*
+
+DRAWMODE ends ;*/ } DRAWMODE; /*
+
+
+
+; Background Mode definitions
+
+TRANSPARENT equ 1
+OPAQUE equ 2
+
+ if 0
+*/
+/* Background Mode definitions used by GDI support routines written in C */
+
+#define TRANSPARENT 1
+#define OPAQUE 2
+/*
+ endif
+
+
+
+ endif
+ endif
+page
+; Output Definitions - incOutput
+
+ ifdef incOutput
+ if incOutput
+
+
+; Output Style definitions used by GDI
+
+
+OS_ARC equ 3
+OS_SCANLINES equ 4
+OS_RECTANGLE equ 6
+OS_ELLIPSE equ 7
+OS_MARKER equ 8
+OS_POLYLINE equ 18
+OS_TRAPEZOID equ 20
+OS_POLYGON equ 22
+OS_PIE equ 23
+OS_POLYMARKER equ 24
+OS_CHORD equ 39
+OS_CIRCLE equ 55
+
+OS_BEGINNSCAN equ 80
+OS_ENDNSCAN equ 81
+ if 0
+*/
+
+/* Output Style definitions used by GDI support routines written in C */
+
+#define OS_ARC 3
+#define OS_SCANLINES 4
+#define OS_RECTANGLE 6
+#define OS_ELLIPSE 7
+#define OS_MARKER 8
+#define OS_POLYLINE 18
+#define OS_TRAPEZOID 20
+#define OS_POLYGON 22
+#define OS_PIE 23
+#define OS_POLYMARKER 24
+#define OS_CHORD 39
+#define OS_CIRCLE 55
+
+#define OS_BEGINNSCAN 80
+#define OS_ENDNSCAN 81
+/*
+ endif
+
+
+ endif
+ endif
+
+
+ ifdef incControl
+ if incControl
+
+OEM_FAILED equ 8000000
+
+; GDI escape constants
+
+NEWFRAME equ 1
+ABORTDOC equ 2
+NEXTBAND equ 3
+SETCOLORTABLE equ 4
+GETCOLORTABLE equ 5
+FLUSHOUTPUT equ 6
+DRAFTMODE equ 7
+QUERYESCSUPPORT equ 8
+SETPRINTERDC equ 9
+SETABORTPROC equ 9
+STARTDOC equ 10
+ENDDOC equ 11
+GETPHYSPAGESIZE equ 12
+GETPRINTINGOFFSET equ 13
+GETSCALINGFACTOR equ 14
+MFCOMMENT equ 15
+GETPENWIDTH equ 16
+SETCOPYCOUNT equ 17
+SELECTPAPERSOURCE equ 18
+DEVICEDATA equ 19
+PASSTHROUGH equ 19
+GETTECHNOLGY equ 20
+GETTECHNOLOGY equ 20
+SETLINECAP equ 21
+SETLINEJOIN equ 22
+SETMITERLIMIT equ 23
+BANDINFO equ 24
+DRAWPATTERNRECT equ 25
+GETVECTORPENSIZE equ 26
+GETVECTORBRUSHSIZE equ 27
+ENABLEDUPLEX equ 28
+GETSETPAPERBINS equ 29
+GETSETPRINTORIENT equ 30
+ENUMPAPERBINS equ 31
+SETDIBSCALING equ 32
+EPSPRINTING equ 33
+ENUMPAPERMETRICS equ 34
+GETSETPAPERMETRICS equ 35
+POSTSCRIPT_DATA equ 37
+POSTSCRIPT_IGNORE equ 38
+MOUSETRAILS equ 39
+RESETDEVICE equ 128
+GETEXTENDEDTEXTMETRICS equ 256
+GETEXTENTTABLE equ 257
+GETPAIRKERNTABLE equ 258
+GETTRACKKERNTABLE equ 259
+EXTTEXTOUT equ 512
+GETFACENAME equ 513
+ENABLERELATIVEWIDTHS equ 768
+ENABLEPAIRKERNING equ 769
+SETKERNTRACK equ 770
+SETALLJUSTVALUES equ 771
+SETCHARSET equ 772
+
+STRETCHBLT equ 2048
+BEGIN_PATH equ 4096
+CLIP_TO_PATH equ 4097
+END_PATH equ 4098
+EXT_DEVICE_CAPS equ 4099
+RESTORE_CTM equ 4100
+SAVE_CTM equ 4101
+SET_ARC_DIRECTION equ 4102
+SET_BACKGROUND_COLOR equ 4103
+SET_POLY_MODE equ 4104
+SET_SCREEN_ANGLE equ 4105
+SET_SPREAD equ 4106
+TRANSFORM_CTM equ 4107
+SET_CLIP_BOX equ 4108
+SET_BOUNDS equ 4109
+
+
+ if 0
+*/
+#define OEM_FAILED 0x80000000L
+
+#define NEWFRAME 1
+#define ABORTDOC 2
+#define NEXTBAND 3
+#define SETCOLORTABLE 4
+#define GETCOLORTABLE 5
+#define FLUSHOUTPUT 6
+#define DRAFTMODE 7
+#define QUERYESCSUPPORT 8
+#define SETPRINTERDC 9 // DDK - between GDI and Driver
+#define SETABORTPROC 9 // SDK - between APP and GDI
+#define STARTDOC 10
+#define ENDDOC 11
+#define GETPHYSPAGESIZE 12
+#define GETPRINTINGOFFSET 13
+#define GETSCALINGFACTOR 14
+#define MFCOMMENT 15
+#define GETPENWIDTH 16
+#define SETCOPYCOUNT 17
+#define SELECTPAPERSOURCE 18
+#define DEVICEDATA 19
+#define PASSTHROUGH 19
+#define GETTECHNOLGY 20
+#define GETTECHNOLOGY 20
+#define SETLINECAP 21
+#define SETLINEJOIN 22
+#define SETMITERLIMIT 23
+#define BANDINFO 24
+#define DRAWPATTERNRECT 25
+#define GETVECTORPENSIZE 26
+#define GETVECTORBRUSHSIZE 27
+#define ENABLEDUPLEX 28
+#define GETSETPAPERBINS 29
+#define GETSETPRINTORIENT 30
+#define ENUMPAPERBINS 31
+#define SETDIBSCALING 32
+#define EPSPRINTING 33
+#define ENUMPAPERMETRICS 34
+#define GETSETPAPERMETRICS 35
+#define POSTSCRIPT_DATA 37
+#define POSTSCRIPT_IGNORE 38
+#define RESETDEVICE 128
+#define GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#define GETFACENAME 513
+#define ENABLERELATIVEWIDTHS 768
+#define ENABLEPAIRKERNING 769
+#define SETKERNTRACK 770
+#define SETALLJUSTVALUES 771
+#define SETCHARSET 772
+
+#define STRETCHBLT 2048
+#define BEGIN_PATH 4096
+#define CLIP_TO_PATH 4097
+#define END_PATH 4098
+#define EXT_DEVICE_CAPS 4099
+#define RESTORE_CTM 4100
+#define SAVE_CTM 4101
+#define SET_ARC_DIRECTION 4102
+#define SET_BACKGROUND_COLOR 4103
+#define SET_POLY_MODE 4104
+#define SET_SCREEN_ANGLE 4105
+#define SET_SPREAD 4106
+#define TRANSFORM_CTM 4107
+#define SET_CLIP_BOX 4108
+#define SET_BOUNDS 4109
+
+typedef FONTINFO FAR *LPFONTINFO;
+typedef DRAWMODE FAR *LPDRAWMODE;
+typedef TEXTXFORM FAR *LPTEXTXFORM;
+typedef TEXTMETRIC FAR *LPTEXTMETRIC;
+typedef LOGFONT FAR *LPLOGFONT;
+typedef LOGPEN FAR *LPLOGPEN;
+typedef LOGBRUSH FAR *LPLOGBRUSH;
+typedef BITMAP FAR *LPBITMAP;
+typedef FARPROC FAR *LPFARPROC;
+typedef GDIINFO FAR *LPGDIINFO;
+typedef SCALABLEFONTINFO FAR * LPSCALABLEFONTINFO;
+
+
+/*
+ endif
+
+
+
+ endif
+ endif
+;*/
diff --git a/private/mvdm/wow16/inc/gpfix.inc b/private/mvdm/wow16/inc/gpfix.inc
new file mode 100644
index 000000000..9126a3808
--- /dev/null
+++ b/private/mvdm/wow16/inc/gpfix.inc
@@ -0,0 +1,62 @@
+; GPFix.inc - definitions for GP exception handler code
+; usage -
+; 1) include gpfix.inc
+; 2) bracket critical code with "beg_fault_trap handler" and
+; "end_fault_trap"
+; 3) define a handler entry point where execution should continue
+; a) this must be in the same code segment as the faulty code
+; b) two extra words (fault IP/fault) will be pushed on the stack when
+; an exception occurs. They should be popped before continuing.
+; This can be done with the 'fault_fix_stack' macro.
+; They are there if you want to determine which instruction faulted.
+; c) This handler can do whatever it likes. Usually, it will return
+; an error code to the caller.
+; 4) if you don't want to worry about the extra values on the stack,
+; use the fix_fault_stack macro to remove them
+
+_bft_count = 0
+_eft_count = 0
+
+_bft_ macro handler, count
+ _bft_&count:
+ _hft_&count = handler
+endm
+
+;
+; Begin fault critical region. 'handler' is the address of
+; the exception handler to jmp to if a fault occurs.
+;
+beg_fault_trap macro handler
+ if _bft_count - _eft_count
+ .err
+ %out Mismatched beg_fault_trap/end_fault_trap pairs in beg_fault_trap
+ endif
+ _bft_ handler, %_bft_count
+ _bft_count = _bft_count + 1
+endm
+
+_eft_ macro count
+ _eft_&count:
+ _GPFIX SEGMENT WORD PUBLIC 'CODE'
+ dw seg _bft_&count, _bft_&count, _eft_&count, _hft_&count
+ _GPFIX ENDS
+endm
+
+;
+; End fault critical region.
+;
+end_fault_trap macro
+ _eft_ %_eft_count
+ _eft_count = _eft_count+1
+ if _bft_count - _eft_count
+ .err
+ %out Mismatched beg_fault_trap/end_fault_trap pairs in end_fault_trap
+ endif
+endm
+
+;
+; Clean up stack in fault handler.
+;
+fault_fix_stack macro
+ add sp, 4
+endm
diff --git a/private/mvdm/wow16/inc/header.txt b/private/mvdm/wow16/inc/header.txt
new file mode 100644
index 000000000..05837cef7
--- /dev/null
+++ b/private/mvdm/wow16/inc/header.txt
@@ -0,0 +1,364 @@
+ Header File Organization
+ ------------------------
+
+This document describes the rules for public Windows 3.1 header files. These
+rules are designed to promote consistency, clarity, Win32 compatibility, ANSI
+compatibility, motherhood, and apple pie a la mode.
+
+In the past, windows.h has been fairly randomly organized: it wasn't very
+easy to look in the file and figure out how constants, types, and functions
+are related. However, the new windows.h is much more rationally organized,
+and it's now far easier to understand and modify. In interests of
+consistency, readability, and maintainability, it's important that all of our
+public header files are consistently organized.
+
+ * Include a copyright banner at the top of the file. Something like:
+
+/*****************************************************************************\
+* *
+* header.h - Brief description of purpose of header file *
+* *
+* Version 3.10 * *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+ If this header file has been released before, the copyright date
+ should be something like: 1985-1992.
+
+ * Arrange your header in functional groups, like windows.h. Try to
+ keep related types, structures, constants and functions as close
+ together as possible in the header. Separate functional groups
+ within the header with a banner comment, as in windows.h.
+
+ * Within a functional group, general typedefs and constants should come
+ first, followed by logically organized function prototypes.
+
+ * Constants or types used by only one or two functions should be
+ declared near the function.
+
+ * Make sure that everything defined in the header file is included by
+ default: don't require people to #define things to get certain
+ definitions.
+
+ * If you do want to break up your header file, use the #define NOXXX
+ convention used by windows.h. Try not to have too many groups
+ controled by NOXXX #defines, because they get confusing and hard to
+ deal with. Compiler speed and memory capacity is not the problem it
+ once was, especially with precompiled headers.
+
+ * Constants designed to be ANDed or ORed should be defined in hex.
+ The number of digits should reflect the data size: 2 for bytes,
+ 4 for words, and 8 for longs. Long hex constants should have
+ an appended L, e.g., 0x12345678L.
+
+ * Ordinal constants values (e.g., 1, 2, 3, 4) should be declared
+ in decimal.
+
+ * Provide a comment on all #else's and #endif's that suggests its
+ corresponding #ifdef: e.g.
+
+ #ifdef FOO
+ ...
+ #else /* FOO */
+
+ #endif /* !FOO */
+
+ * Precede the header file with #pragma pack(1), and terminate with
+ #pragma pack(). This ensures that the structures declared in the
+ header will be packed properly, regardless of what compiler packing
+ options the user is using for his own code. Because the Windows RC
+ compiler chokes on #pragma statements in .rc files, it's a good idea
+ to include this (and any other #pragmas) in an #ifndef RC_INVOKED.
+
+ #ifndef RC_INVOKED
+ #pragma pack(1) /* Assume byte packing throughout */
+ #endif /* RC_INVOKED */
+
+ and:
+
+ #ifndef RC_INVOKED
+ #pragma pack() /* Revert to default packing */
+ #endif /* RC_INVOKED */
+
+ * Prevent multiple inclusion of your header file with the following
+ construct:
+
+ #ifndef _INC_MYHEADER
+ #define _INC_MYHEADER
+
+ ...body of header...
+
+ #endif /* _INC_MYHEADER */
+
+ This is the convention used by the C runtimes. For each header there
+ is a #define that can be used to determine whether the header has
+ already been included.
+
+
+
+ Win32 Upward Compatibility
+ --------------------------
+
+Part of the goal of 3.1 is to provide a more unified API that will scale with
+minimal pain to 32 bits in Win32. To this end, there are a few things you
+have to worry about in your headers (and in your code, but that's a different
+story...)
+
+In 32-bit Windows, almost all 16 bit parameters, return values, and field
+types have been widened to 32 bits. This allows us to generate much more
+efficient code on the 386 and on RISC machines.
+
+We need a way of declaring the quantities that will "float" to 32 bits in
+32-bit Windows. It turns out that the C language already provides for this
+capability: the "int" type, for example, is 16 bits on 16 bit platforms, but
+is 32 bits on 32 bit platforms. "short" is always 16 bits on any platform,
+"long" is always 32 bits, and "char" is always 8 bits.
+
+So, functions and structures with "int" declarations are already portably
+declared. The problem, though is with the WORD type. "WORD" has become an
+industry-wide synonym for a 16 bit unsigned quantity. But, it's also used
+widely in Windows header files.
+
+Enter the UINT type. The new UINT type is typedef'd as "unsigned int": an
+unsigned value that is 16 bits on 16 bit platforms, and floats to 32 bits on
+32 bit platforms. In the 3.1 headers, UINT is used in place of WORD wherever
+the size of the return value, parameter, or field will change depending on
+the platform.
+
+This is a rule that applies to code you write too: on 32 bit platforms, use
+of the UINT type rather than WORD will generate faster smaller code. But be
+careful of hard-coded size dependencies on WORD: be sure to use sizeof()
+instead of constants, etc.
+
+In some cases there may be structure fields whose size WON'T be changing in
+32-bit windows, perhaps because the structure is used in a file format and
+compatibility is required. If you know ahead of time that this is the case,
+be sure to use short and WORD to indicate 16 bit quantities across platforms.
+There are a few of these exceptions with the 3.1 bitmap information
+structures in windows.h. If you don't know, then use UINT and int.
+
+The new WPARAM, LPARAM, and LRESULT types, used for polymorphic or arbitrary
+parameters and return values (e.g., the SendMessage() function), also provide
+a useful degree of platform isolation. The WPARAM type is similar to UINT in
+that its size varies with the platform. WPARAM should be used in function
+parameter, return value, AND structure declarations, even though its size may
+vary. The use of these types indicates to the programmer that the value must
+be cast and assigned to the proper type before use.
+
+Hence, the following rules:
+
+ * Use int and UINT instead of short or WORD, UNLESS you know for sure
+ that the quantity will remain 16 bits in 32-bit Windows. The Windows
+ HIWORD and LOWORD macros use WORD, for example. Be sure to check your
+ uses of short as well as WORD: there are probably a few lurking out
+ there that should be changed to int. Use int FAR* or UINT FAR* instead
+ of LPINT or LPWORD.
+
+ * Use the LPARAM, WPARAM, and LRESULT types instead of WORD, LONG, or
+ DWORD as appropriate.
+
+
+ ANSI Compatibility
+ ------------------
+
+Public header files should be ANSI compliant so that people can take
+advantage of the highest compiler warning levels possible. This also helps
+ensure that our header files work with a wider range of development tools.
+
+ * Don't define constants, typedefs, or functions named with a preceding
+ underscore. This violates the ANSI namespace conventions. There are
+ a few violations of this rule already in existence (e.g., _lread), but
+ try not to create any new problems. (The rules are actually more
+ complicated than "don't use underscores", but you're safe if you keep
+ away from them).
+
+ * Don't use "//" style comments in the header: these are convenient
+ but non-ANSI, and warning level 4 complains.
+
+ * Always test your header file by compiling it with the -W4 compiler
+ option to ensure that it's ANSI-compatible.
+
+ * Make sure that you have no identifier conflicts with the following
+ C library header files (NOTE: This list may be incomplete. It's
+ a good start, though).
+
+ assert.h
+ ctype.h
+ errno.h
+ float.h
+ limits.h
+ locale.h
+ math.h
+ setjmp.h
+ signal.h
+ stdarg.h
+ stddef.h
+ stdio.h
+ stdlib.h
+ string.h
+ time.h
+
+ * Structure declarations should be declared with the "tag" prefix, rather
+ than a leading underscore, as shown below:
+
+ typedef struct tagFOO
+ {
+ int i;
+ UINT u;
+ } FOO;
+
+ * Declare fully-prototyped typedefs for all callback functions. By
+ convention, the type name should be all caps and end in PROC. For
+ example, the window procedure callback function typedef from windows.h:
+
+ typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
+
+ Windows 3.0 Backward Compatibility
+ ----------------------------------
+
+In order to allow users to develop applications with 3.1 headers that will
+still run on 3.0, users can #define the WINVER constant to be equal to the
+version number of Windows they are compiling against. For 3.0, this would be
+0x0300. This constant should be used to ensure that new, non-3.0 compatible
+features are not declared when the user is compiling a 3.0 application. Keep
+in mind that this version number is hex, not decimal (to be compatible with
+the GetExpWinVer() API).
+
+Some of you may own headers that are designed to work with windows 3.0 as
+well as 3.1: in this case, you won't have some of the new 3.1 typedefs and
+macros defined (e.g., UINT). You can use #ifdef _INC_WINDOWS to determine
+whether you've included the 3.1 windows.h. Because yours may not be the only
+header that will want to define certain types like UINT and LPCSTR, you
+should #define these to be WORD and LPSTR, respectively, since you cannot
+typedef something twice. The other option, of course, is to have separate
+3.0 and 3.1 versions of your header.
+
+ * New, non-3.0 compatible declarations and definitions should be inside
+ #ifdef (WINVER >= 0x030a)/#endif so that the 3.1 headers can be used
+ to create 3.0-compatible applications.
+
+ * If your header must be compatible with the 3.0 windows.h, use #ifdef
+ _INC_WINDOWS around #definitions that define the missing types. The
+ 3.0 windows.h file did not #define _INC_WINDOWS.
+ Use #define rather than typedef to ensure that other headers can
+ safely do the same thing. Here's an example that will handle
+ most of the common problems:
+
+ #ifndef _INC_WINDOWS /* If not included with 3.1 headers... */
+ #define LPCSTR LPSTR
+ #define WINAPI FAR PASCAL
+ #define CALLBACK FAR PASCAL
+ #define UINT WORD
+ #define LPARAM LONG
+ #define WPARAM WORD
+ #define LRESULT LONG
+ #define HMODULE HANDLE
+ #define HINSTANCE HANDLE
+ #define HLOCAL HANDLE
+ #define HGLOBAL HANDLE
+ #endif /* _INC_WINDOWS */
+
+ C++ Compatibility
+ -----------------
+
+To be able to use functions declared in your header directly from C++, you
+need to do one thing:
+
+ * Bracket the header file typedefs inside an extern "c" {} block,
+ conditionally using the __cplusplus #define:
+ Near the beginning of your header:
+
+ #ifdef __cplusplus
+ extern "C" { /* Assume C declarations for C++ */
+ #endif /* __cplusplus */
+
+ And at the end:
+
+ #ifdef __cplusplus
+ }
+ #endif
+
+
+ STRICT Compatibility and Windows 3.0 Backward Compatibility
+ -----------------------------------------------------------
+
+One of the most important features of STRICT is that handle types are no
+longer defined as WORDs. They are declared in such a way that will cause a
+compiler error if you try to pass the wrong type of handle or a non-handle
+value to a function, for example. It's important that all of our handle
+types be declared this way when the user #defines STRICT.
+
+A number of new types and such have been defined in windows.h, such as
+HINSTANCE, HGLOBAL, and HLOCAL, which should be used where appropriate in
+place of the generic HANDLE type. HANDLE should be used only in cases of
+an arbitrary handle type.
+
+The WPARAM, LPARAM, and LRESULT types should be used for arbitrary or
+polymorphic parameters or return values. Typedefs exist for all callback
+functions, which are used in place of FARPROC.
+
+In most cases, functions declared with these types are fully 3.0 compatible
+unless STRICT is #defined. It may sometimes be necessary to use #ifdef
+STRICT/#else/#endif to provide 3.0-compatible, non-STRICT declarations in
+some cases.
+
+ * Use DECLARE_HANDLE() to declare handle types. If you have polymorphic
+ API parameters (or structure fields) that are designed to accept more
+ than one type of handle (e.g., the GDI SelectObject function), there
+ are a few tricks you can employ. 1) Declare a generic handle type
+ like HGDIOBJ as void _near*, which will accept any handle type. The
+ HANDLE type can be used for this purpose. 2) if the number of
+ polymorphic types is small, and there are lots of cases where they can
+ be used polymorphically, use DECLARE_HANDLE to declare one handle
+ type, and typedef the rest to be the same as the first one (e.g,
+ HMODULE and HINSTANCE in windows.h).
+
+ * Structure and function declarations should use the appropriate STRICT
+ type, rather than the generic HANDLE,
+
+ * Declare arbitrarily or polymorphic types with LPARAM, WPARAM, and
+ LRESULT instead of WORD, LONG, or DWORD. This indicates to a
+ programmer that these values should not be used directly, but should
+ instead be cast and assigned to the proper type of value before use.
+
+ * Declare arbitrarily or polymorphic pointer types with void FAR*
+ instead of LPSTR or BYTE FAR*. The nice thing about the void FAR*
+ type is that you can pass any type of pointer to it without having to
+ cast first.
+
+ * If any of the above STRICT rules result in declarations that are
+ not compatible with previously released versions of the header file,
+ use #ifdef STRICT/#else/#endif to ensure that both declarations
+ are present.
+
+ * Use WINAPI instead of FAR PASCAL for declaring APIs. Use CALLBACK
+ instead of FAR PASCAL in callback function typedefs.
+
+ * Be sure to use "const" where appropriate in your pointer parameters.
+ If the pointer is read-only, then it should be const. If the function
+ writes through the pointer, it must not be const. For const
+ zero-terminated string pointers, use LPCSTR instead of LPSTR.
+
+ * Don't declare NPXXX or SPXXX pointer parameter types for new structures.
+ (but don't remove them if they've already been defined in a shipped
+ header). Users are encouraged to use "*", const, _near, _far, and
+ _huge explicitly where appropriate. Now that our headers contain
+ "const" pointer types, having LP, NP, and const pointer type variants
+ for every structure would just clog the compiler up with typedefs.
+
+ * Spell out pointer declarations, rather than using the LPXXX type form.
+ This allows for use of const and _huge where appropriate, without
+ having to define lots of new typedefs:
+
+ SetFoo(const FOO FAR* pfoo);
+ GetFoo(FOO FAR* pfoo);
+
+ * Use parameter names in your API function prototypes. This greatly
+ contributes to the readability and usefulness of your header, at
+ very little cost. Make sure all your APIs and callback declarations
+ are fully prototyped. Use the same naming conventions as in our
+ documentation (contact gregro or ralphw for a summary of those
+ conventions). NOTE: As of this writing, windows.h does not yet
+ include function prototype names.
diff --git a/private/mvdm/wow16/inc/ime.h b/private/mvdm/wow16/inc/ime.h
new file mode 100644
index 000000000..9c999b0e4
--- /dev/null
+++ b/private/mvdm/wow16/inc/ime.h
@@ -0,0 +1,210 @@
+//
+//
+// IME.H - Far East Input Method Editor definitions
+//
+//
+
+#ifdef DBCS_IME
+
+//
+// virtual key
+//
+#ifdef JAPAN
+#define VK_DBE_ALPHANUMERIC 0x0f0
+#define VK_DBE_KATAKANA 0x0f1
+#define VK_DBE_HIRAGANA 0x0f2
+#define VK_DBE_SBCSCHAR 0x0f3
+#define VK_DBE_DBCSCHAR 0x0f4
+#define VK_DBE_ROMAN 0x0f5
+#define VK_DBE_NOROMAN 0x0f6
+#define VK_DBE_IME_WORDREGISTER 0x0f7
+#define VK_DBE_IME_DIALOG 0x0f8
+#define VK_DBE_FLUSH 0x0f9
+#define VK_DBE_CODEINPUT 0x0fa
+#define VK_DBE_NOCODEINPUT 0x0fb
+#endif // JAPAN
+#ifdef TAIWAN
+#define VK_OEM_SEMICLN 0x0ba // ; ** :
+#define VK_OEM_EQUAL 0x0bb // = ** +
+#define VK_OEM_COMMA 0x0bc // , ** <
+#define VK_OEM_MINUS 0x0bd // - ** _
+#define VK_OEM_PERIOD 0x0be // . ** >
+#define VK_OEM_SLASH 0x0bf // / ** ?
+#define VK_OEM_3 0x0c0 // ` ** ~
+#define VK_OEM_LBRACKET 0x0db // [ ** {
+#define VK_OEM_BSLASH 0x0dc // \ ** |
+#define VK_OEM_RBRACKET 0x0dd // ] ** |
+#define VK_OEM_QUOTE 0x0de // ' ** "
+#endif // TAIWAN
+
+//
+// switch for wParam of IME_MOVECONVERTWINDOW
+//
+#define MCW_DEFAULT 0x00
+#define MCW_RECT 0x01
+#define MCW_WINDOW 0x02
+#define MCW_SCREEN 0x04
+#define MCW_VERTICAL 0x08
+#define MCW_CMD 0x06 // command mask
+
+//
+// switch for wParam of IME_SET_MODE and IME_GET_MODE
+//
+//
+#if defined(JAPAN) || defined(TAIWAN)
+#define IME_MODE_ALPHANUMERIC 0x0001
+#define IME_MODE_KATAKANA 0x0002
+#define IME_MODE_HIRAGANA 0x0004
+#define IME_MODE_SBCSCHAR 0x0008
+#define IME_MODE_DBCSCHAR 0x0010
+#define IME_MODE_ROMAN 0x0020
+#define IME_MODE_NOROMAN 0x0040
+#define IME_MODE_CODEINPUT 0x0080
+#define IME_MODE_NOCODEINPUT 0x0100
+#endif // JAPAN || TAIWAN
+#ifdef KOREA
+#define IME_MODE_ALPHANUMERIC 0x0001
+#define IME_MODE_SBCSCHAR 0x0002
+#define IME_MODE_HANJACONVERT 0x0004
+#endif // KOREA
+
+//
+// IME function code
+//
+#define IME_QUERY 0x03
+#define IME_SETOPEN 0x04
+#define IME_GETOPEN 0x05
+#define IME_ENABLE 0x06 /* ;Internal */
+#define IME_MOVECONVERTWINDOW 0x08
+#define IME_SET_MODE 0x10
+#define IME_GET_MODE 0x11
+#define IME_SETFONT 0x12
+#define IME_SENDKEY 0x13
+#define IME_DESTROY 0x14 /* ;Internal */
+#define IME_PRIVATE 0x15
+#define IME_WINDOWUPDATE 0x16
+#define IME_SELECT 0x17 /* ;Internal */
+#define IME_WORDREGISTER 0x18
+#ifdef KOREA
+#define IME_CODECONVERT 0x20
+#define IME_CONVERTLIST 0x21
+#define IME_AUTOMATA 0x30
+#define IME_HANJAMODE 0x31
+#define IME_GETLEVEL 0x40
+#define IME_SETLEVEL 0x41
+#endif // KOREA
+#ifdef TAIWAN
+#define IME_SETUSRFONT 0x20
+#define IME_QUERYUSRFONT 0x21
+#define IME_INPUTKEYTOSEQUENCE 0x22
+#define IME_SEQUENCETOINTERNAL 0x23
+#define IME_QUERYIMEINFO 0x24
+#define IME_DIALOG 0x25
+#endif // TAIWAN
+
+//
+// error code
+//
+#define IME_RS_ERROR 0x01 // genetal error
+#define IME_RS_NOIME 0x02 // IME is not installed
+#define IME_RS_TOOLONG 0x05 // given string is too long
+#define IME_RS_ILLEGAL 0x06 // illegal charactor(s) is string
+#define IME_RS_NOTFOUND 0x07 // no (more) candidate
+#define IME_RS_NOROOM 0x0a // no disk/memory space
+#define IME_RS_DISKERROR 0x0e // disk I/O error
+
+//
+// messge id
+//
+#define WM_IME_REPORT 0x0280 // WM_KANJIFIRST
+#define IR_STRINGSTART 0x100
+#define IR_STRINGEND 0x101
+#define IR_MOREROOM 0x110
+#define IR_OPENCONVERT 0x120
+#define IR_CHANGECONVERT 0x121
+#define IR_CLOSECONVERT 0x122
+#define IR_FULLCONVERT 0x123
+#define IR_IMESELECT 0x130
+#define IR_STRING 0x140
+
+//
+// IMM functions
+//
+typedef struct tagIMESTRUCT {
+ WORD fnc; // function code
+ WORD wParam; // word parameter
+ WORD wCount; // word counter
+ WORD dchSource; // offset to src from top of memory object
+ WORD dchDest; // offset to dst from top of memory object
+ LONG lParam1;
+ LONG lParam2;
+ LONG lParam3;
+} IMESTRUCT;
+typedef IMESTRUCT *PIMESTRUCT;
+typedef IMESTRUCT NEAR *NPIMESTRUCT;
+typedef IMESTRUCT FAR *LPIMESTRUCT;
+
+short FAR PASCAL SendIMEMessage( HWND, DWORD );
+#ifdef TAIWAN
+LONG FAR PASCAL WINNLSIMEControl(HWND,HWND,LPIMESTRUCT);
+#endif
+
+//
+// miscellaneous
+//
+#ifdef TAIWAN
+#define STATUSWINEXTRA 10
+#endif
+
+#ifdef KOREA
+//
+// ----- definitions for level2 apps -----
+//
+
+typedef unsigned char far *LPKSTR ;
+
+/* VK from the keyboard driver */
+#define VK_FINAL 0x18 // dummy VK to make final on mouse down
+#define VK_IME_DIALOG 0xf1
+
+#define CP_HWND 0
+#define CP_OPEN 1
+//#define CP_DIRECT 2
+#define CP_LEVEL 3
+
+#define lpSource(lpks) (LPSTR)((LPSTR)lpks+lpks->dchSource)
+#define lpDest(lpks) (LPSTR)((LPSTR)lpks+lpks->dchDest)
+
+//
+// ----- definitions for level3 apps -----
+//
+
+/* VK to send to Applications */
+#define VK_CONVERT 0x1C
+#define VK_NONCONVERT 0x1D
+#define VK_ACCEPT 0x1E
+#define VK_MODECHANGE 0x1F
+
+/* IME_CODECONVERT subfunctions */
+#define IME_BANJAtoJUNJA 0x13
+#define IME_JUNJAtoBANJA 0x14
+#define IME_JOHABtoKS 0x15
+#define IME_KStoJOHAB 0x16
+
+/* IME_AUTOMATA subfunctions */
+#define IMEA_INIT 0x01
+#define IMEA_NEXT 0x02
+#define IMEA_PREV 0x03
+
+/* IME_HANJAMODE subfunctions */
+#define IME_REQUEST_CONVERT 0x01
+#define IME_ENABLE_CONVERT 0x02
+
+/* IME_MOVEIMEWINDOW subfunctions */
+#define INTERIM_WINDOW 0x00
+#define MODE_WINDOW 0x01
+#define HANJA_WINDOW 0x02
+
+#endif // KOREA
+
+#endif // DBCS_IME
diff --git a/private/mvdm/wow16/inc/int31.inc b/private/mvdm/wow16/inc/int31.inc
new file mode 100644
index 000000000..83eca01d7
--- /dev/null
+++ b/private/mvdm/wow16/inc/int31.inc
@@ -0,0 +1,136 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1989-1990
+;
+; Title: INT31.INC - Equates and Structures for Int 31h Interface
+;
+; Version: 3.00
+;
+; Date: 22-May-1989
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 22-May-1989 RAL Original
+;
+;==============================================================================
+
+
+
+Int31_Sel_Mgt EQU 00h
+ SelMgt_Alloc_Sel EQU 00h
+ SelMgt_Free_Sel EQU 01h
+ SelMgt_Seg_To_Sel EQU 02h
+ SelMgt_Get_LDT_Base EQU 03h
+ SelMgt_Lock_Sel EQU 04h
+ SelMgt_Unlock_Sel EQU 05h
+ SelMgt_Get_Base EQU 06h
+ SelMgt_Set_Base EQU 07h
+ SelMgt_Set_Limit EQU 08h
+ SelMgt_Set_Acc_Bits EQU 09h
+ SelMgt_Alias_Sel EQU 0Ah
+ SelMgt_Get_Desc EQU 0Bh
+ SelMgt_Set_Desc EQU 0Ch
+
+Int31_DOS_Mem_Mgt EQU 01h
+ DOSMem_Allocate EQU 00h
+ DOSMem_Free EQU 01h
+ DOSMem_Resize EQU 02h
+
+Int31_Int_Serv EQU 02h
+ Int_Get_Real_Vec EQU 00h
+ Int_Set_Real_Vec EQU 01h
+ Int_Get_Excep_Vec EQU 02h
+ Int_Set_Excep_Vec EQU 03h
+
+Int31_Trans_Serv EQU 03h
+ Trans_Sim_Int EQU 00h
+ Trans_Far_Call EQU 01h
+ Trans_Call_Int_Proc EQU 02h
+ Trans_Call_Back EQU 03h
+ Trans_Free_CB EQU 04h
+
+Int31_Get_Version EQU 04h
+
+Int31_Mem_Mgt EQU 05h
+ MemMgt_Get_Info EQU 00h
+ MemMgt_Allocate EQU 01h
+ MemMgt_Free EQU 02h
+ MemMgt_Resize EQU 03h
+
+Int31_Page_Lock EQU 06h
+ Lock_Region EQU 00h
+ Unlock_Region EQU 01h
+ Mark_Pageable EQU 02h
+ Mark_Not_Pageable EQU 03h
+
+Int31_Demand_Page_Tune EQU 07h
+ Page_Candidate EQU 00h
+ Page_Discard EQU 01h
+
+Int31_Map_Phys_Addr EQU 08h
+
+Int31_Virt_Int_State EQU 09h
+ Get_Clear_Int_State EQU 00h
+ Get_Set_Int_State EQU 01h
+ Get_Int_State EQU 02h
+
+
+Real_Mode_Call_Struc STRUC
+RealMode_EDI dd ?
+RealMode_ESI dd ?
+RealMode_EBP dd ?
+ dd ?
+RealMode_EBX dd ?
+RealMode_EDX dd ?
+RealMode_ECX dd ?
+RealMode_EAX dd ?
+RealMode_Flags dw ?
+RealMode_ES dw ?
+RealMode_DS dw ?
+RealMode_FS dw ?
+RealMode_GS dw ?
+RealMode_IP dw ?
+RealMode_CS dw ?
+RealMode_SP dw ?
+RealMode_SS dw ?
+Real_Mode_Call_Struc ENDS
+
+
+Real_Mode_Word_Regs STRUC
+RealMode_DI dw ?
+ dw ?
+RealMode_SI dw ?
+ dw ?
+RealMode_BP dw ?
+ dw ?
+ dd ?
+RealMode_BX dw ?
+ dw ?
+RealMode_DX dw ?
+ dw ?
+RealMode_CX dw ?
+ dw ?
+RealMode_AX dw ?
+Real_Mode_Word_Regs ENDS
+
+
+Real_Mode_Byte_Regs STRUC
+ dd 4 dup (?)
+RealMode_BL db ?
+RealMode_BH db ?
+ dw ?
+RealMode_DL db ?
+RealMode_DH db ?
+ dw ?
+RealMode_CL db ?
+RealMode_CH db ?
+ dw ?
+RealMode_AL db ?
+RealMode_AH db ?
+Real_Mode_Byte_Regs ENDS
diff --git a/private/mvdm/wow16/inc/io.h b/private/mvdm/wow16/inc/io.h
new file mode 100644
index 000000000..17771c35e
--- /dev/null
+++ b/private/mvdm/wow16/inc/io.h
@@ -0,0 +1,47 @@
+/***
+*io.h - declarations for low-level file handling and I/O functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the function declarations for the low-level
+* file handling and I/O functions.
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* function prototypes */
+
+int _FAR_ _cdecl access(const char _FAR_ *, int);
+int _FAR_ _cdecl chmod(const char _FAR_ *, int);
+int _FAR_ _cdecl chsize(int, long);
+int _FAR_ _cdecl close(int);
+int _FAR_ _cdecl creat(const char _FAR_ *, int);
+int _FAR_ _cdecl dup(int);
+int _FAR_ _cdecl dup2(int, int);
+int _FAR_ _cdecl eof(int);
+long _FAR_ _cdecl filelength(int);
+int _FAR_ _cdecl isatty(int);
+int _FAR_ _cdecl locking(int, int, long);
+long _FAR_ _cdecl lseek(int, long, int);
+char _FAR_ * _FAR_ _cdecl mktemp(char _FAR_ *);
+int _FAR_ _cdecl open(const char _FAR_ *, int, ...);
+int _FAR_ _cdecl _pipe(int _FAR_ *, unsigned int, int);
+int _FAR_ _cdecl read(int, void _FAR_ *, unsigned int);
+int _FAR_ _cdecl remove(const char _FAR_ *);
+int _FAR_ _cdecl rename(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl setmode(int, int);
+int _FAR_ _cdecl sopen(const char _FAR_ *, int, int, ...);
+long _FAR_ _cdecl tell(int);
+int _FAR_ _cdecl umask(int);
+int _FAR_ _cdecl unlink(const char _FAR_ *);
+int _FAR_ _cdecl write(int, const void _FAR_ *, unsigned int);
diff --git a/private/mvdm/wow16/inc/klayer.inc b/private/mvdm/wow16/inc/klayer.inc
new file mode 100644
index 000000000..afb0f1ad1
--- /dev/null
+++ b/private/mvdm/wow16/inc/klayer.inc
@@ -0,0 +1,1367 @@
+;=======================================================
+;
+; Macros stolen from cmacros.inc (so we don't have to include it all)
+;
+ .286p
+
+externNP macro n
+ irp x,<n>
+ extrn x:near
+ endm
+endm
+
+externFP macro n
+ irp x,<n>
+ extrn x:far
+ endm
+endm
+
+externW macro w
+ irp x,<w>
+ extrn x:word
+ endm
+endm
+
+assumes macro s,ln
+ assume s:_&ln
+endm
+
+createSeg macro n,ln,a,co,cl,grp
+ n segment a co '&cl'
+ n ends
+endm
+
+sBegin macro seg
+ assume cs:_&seg
+ _&seg segment
+endm
+
+sEnd macro seg
+ _&seg ends
+ assume cs:nothing
+endm
+
+errnz macro x ;;display error if expression is <>0
+ if2
+ if x ;;if expression is non-zero,
+ errnz1 <x>,%(x)
+ endif
+ endif
+endm
+
+errnz1 macro x1,x2
+ = *errnz* x1 = x2
+ .err
+endm
+
+errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
+ errnz <offset $ - offset l x>
+endm
+
+createSeg _DATA,DATA,WORD,PUBLIC,DATA
+
+;=======================================================
+;
+; Error API definitions
+;
+ExternFP <HandleParamError>
+
+; error codes
+include logerror.inc
+
+;================================================================
+; Variable and temporary initialization
+
+VLseg equ <> ; Holds current segment name
+
+VLopen = 0
+VLerrnotinvoked = 0
+ifndef VLnogenpall
+VLnogenpall = 0
+endif
+
+VLnogen = 0
+VLnogenparm = 0
+
+VLsavees = 0
+VLsavebx = 0
+
+;if1
+if 1
+
+;================================================================
+; Utility macros
+
+;---------------------------------------------------------------------------
+;
+; lodsw cs:[si]
+;
+cslodsw macro
+ db 2eh ;; CS override
+ lodsw
+endm
+
+;---------------------------------------------------------------------------
+;
+; lodsb cs:[si]
+;
+cslodsb macro
+ db 2eh ;; CS override
+ lodsb
+endm
+
+SkipTwoBytes macro
+ db 0A9h ;; Opcode for CMP AX,(immediate word)
+endm
+
+;---------------------------------------------------------------------------
+;
+; Define a as the concatenation of b & c
+;
+concat macro a,b,c,d,e,f
+a equ <b&c&d&e&f>
+endm
+
+;---------------------------------------------------------------------------
+;
+; Assign a to b.
+;
+equate macro a,b
+ a = b
+endm
+
+;
+; Print a message
+;
+_print macro a,b,c
+if2
+ %out a&b&c
+endif
+endm
+
+
+;===============================================================
+
+;---------------------------------------------------------------------------
+;
+; _gensub LABEL
+;
+; Causes per-segment subroutine code associated with type LABEL
+; to be generated, by setting the genLABEL&lseg flag.
+;
+_gensub2 macro l,s
+ gen&l&s = 1
+endm
+
+_gensub macro l
+ _gensub2 <l>,%VLseg
+endm
+
+;---------------------------------------------------------------------------
+; _SwitchSeg
+;
+; Switches current segment to seg, creating the segment if needed.
+;
+_SwitchSeg macro seg,oldseg
+ ifdifi <&seg>,<oldseg>
+
+ ifnb <oldseg>
+sEnd oldseg
+ endif
+
+ concat <VLseg>,seg,
+
+createSeg _&seg,seg,WORD,PUBLIC,CODE
+
+sBegin seg
+assumes CS,seg
+
+ endif
+endm
+
+
+;---------------------------------------------------------------------------
+; API
+;
+API macro rettype,name,seg,optlist
+
+ if VLopen
+ APIEND
+ endif
+
+VLname equ <name>
+VLcbparms = 0
+VLcbskip = 0
+VLerrnotinvoked= 1
+VLopen = 1
+VLnogen = 0
+VLnogenparm = 0
+VLasm = 0
+VLfunnyframe = 0
+VLnodata = 0
+VLcargs = 0
+VLplist equ <>
+VLATMframe = 0 ; special entry/exit code sequence for ATM's patching
+VLATMfrmds = 0 ; ATM entry/exit code: mov ax,_DATA at beginning.
+
+VLsavees = 0
+VLsavebx = 0
+ _SwitchSeg seg,%VLseg
+
+ irp opt,<optlist>
+
+ ifidni <opt>,<NOGEN>
+ VLnogen = 1
+ endif
+
+ ifidni <opt>,<VOID>
+ VLnogen = 1
+ endif
+
+ ifidni <opt>,<ASM>
+ VLasm = 1
+ endif
+
+ ifidni <opt>,<ATMFRAME>
+ VLATMframe = 1
+ endif
+
+ ifidni <opt>,<ATMFRAMEDS>
+ VLATMfrmds = 1
+ VLATMframe = 1
+ endif
+
+ ifidni <opt>,<FUNNYFRAME>
+ VLfunnyframe = 1
+ endif
+
+ ifidni <opt>,<NODATA>
+ VLnodata = 1
+ endif
+
+ ifidni <opt>,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogen = 1
+ endif
+ endif
+
+ ifidni <opt>,<C>
+ VLcargs = 1
+ endif
+
+ ifidni <opt>,<SAVEES>
+ VLsavees = 2 ; sizeof(ES)
+ endif
+
+ ifidni <opt>,<SAVEBX>
+ VLsavebx = 2 ; sizeof(BX)
+ endif
+
+ endm
+
+concat <VLsegoffset>,<seg>,<offset>
+concat <VLnameerror>,<name>,<_error>
+concat <VLnamecbparms>,<name>,<cbparms>
+
+ if1
+equate %VLnamecbparms, %VLcbparms
+ else
+equate %VLnamecbparms, %VLnamecbparms
+ endif
+
+ ife VLnogen
+
+ ife VLcargs
+concat <VLiname>,<I>,<name>
+ExternNP I&name
+
+public name
+name:
+ else
+concat <VLiname>,<_I>,<name>
+ExternNP _I&name
+
+public _&name
+_&name:
+ endif
+
+VLframe = 0 ; no frame set up yet.
+
+ endif ; VLnogen
+
+endm ;; VL
+
+;---------------------------------------------------------------------------
+; APIERR
+;
+; Optionally used after parameter decls to begin error handling code
+;
+APIERR macro opts
+
+ ife VLnogen
+ ife VLframe
+ _print <Nothing to validate for >,%VLiname
+ else
+ pop dx ; pop off error handler address
+ pop bp ; restore BP
+ if VLATMframe
+ dec bp ; fix BP back up
+ endif
+ if VLsavees
+ pop es
+ endif
+ if VLsavebx
+ pop bx
+ endif
+ endif
+ jmp VLiname ; jmp to internal routine.
+
+equate %VLnamecbparms, %VLcbparms
+
+VLnameerror:
+ VLerrnotinvoked = 0
+
+ endif ; VLnogen
+
+endm ;; APIERR
+
+;---------------------------------------------------------------------------
+; APIEND
+;
+; Used after APIERR to terminate error handling code.
+;
+APIEND macro
+
+_PurgeParms %VLplist
+
+ ife VLnogen
+
+ if VLerrnotinvoked
+ APIERR
+ endif
+ if VLsavees
+ pop es
+ endif
+ if VLsavebx
+ pop bx
+ endif
+ ife VLcargs
+ retf VLcbparms
+ else
+ retf
+ endif
+
+VLopen = 0
+
+ endif ; VLnogen
+
+endm ;; APIEND
+
+;---------------------------------------------------------------------------
+;
+; _FlsFrame - Generate frame code
+;
+_FlsFrame macro
+ ife VLframe
+ if VLATMfrmds
+ mov ax,_DATA
+ endif
+ if VLsavebx
+ push bx
+ endif
+ if VLsavees
+ push es
+ endif
+ if VLATMframe
+ inc bp
+ push bp
+ mov bp,sp
+ push ds ; push ds and pop it off.
+ pop ds ; (we need to pop DS rather than
+ ; something fast like pop AX because
+ ; ATM doesn't preserve DS itself)
+ else
+ push bp
+ mov bp,sp
+ endif
+ push offset VLnameerror ; push address of error handler
+ VLframe = 1
+ endif
+endm
+
+;---------------------------------------------------------------------------
+; _ChkName
+;
+; Ensure name was specified
+
+_ChkName macro name
+ ifb <name>
+ _print <Missing parameter name in >,%VLiname
+ endif
+endm
+
+;---------------------------------------------------------------------------
+; _ParmOpts
+;
+; Parse parameter option flags
+;
+_ParmOpts macro opts
+
+ VLnogenparm = VLnogenpall
+
+ irp opt,<opts>
+ ifidni <opt>,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogenparm = 1
+ endif
+ ifidni <opt>,<NOGEN>
+ VLnogenparm = 1
+ endif
+ endif
+ endm
+endm
+
+;---------------------------------------------------------------------------
+; _DefParm name,cb,opts
+;
+; Take care of default parameter stuff, such as defining argument.
+;
+_DP_Add macro old,new
+ ifb <old>
+VLplist equ <new>
+ else
+VLplist equ <old,new>
+ endif
+endm
+
+_DefParm macro name,cb,opts
+ _ChkName <name>
+ _ParmOpts <opts>
+
+ if VLcargs
+concat _P_&name,<[bp]+6+>,%(VLcbparms+VLsavees+VLsavebx)
+ VLcbparms=VLcbparms+(cb)
+ else
+ VLcbparms=VLcbparms+(cb)
+concat _P_&name,<[bp]+6->,%VLcbparms,<+>,%(VLnamecbparms+VLsavees+VLsavebx)
+ endif
+
+_DP_Add %VLplist,<_P_&name>
+
+ VLgen = 1
+ if VLnogenparm or VLnogen
+ VLgen = 0
+ endif
+endm
+
+;----------------------------------------------------------------------------
+;
+; _GenParm name, cb, opts
+;
+_GenParm macro name,cb,opts
+ _DefParm <name>,<cb>,<opts>
+ if VLgen
+ _FlsFrame
+ endif
+endm
+
+lcall2 macro op,label,seg
+ op label&seg
+endm
+
+lcall macro label
+ lcall2 <call>,<label>,%VLseg
+endm
+
+ljmp macro label
+ lcall2 <jmp>,<label>,%VLseg
+endm
+
+;
+; _PurgeParms - purge list of parameters we've defined
+;
+_PurgeParms macro list
+ irp sym,<list>
+sym equ <>
+ endm
+endm
+
+;---------------------------------------------------------------------------
+; LAYER_START
+;
+; Used before any VL invocations
+;
+LAYER_START macro
+assumes ds,DATA
+
+endm
+
+;---------------------------------------------------------------------------
+; LAYER_END
+;
+; Ends all VL definitions
+;
+LAYER_END macro
+ if VLsopen
+ ENDSTRUCT
+ endif
+ if VLopen
+ APIEND
+ endif
+ if VLerrnotinvoked
+ APIERR
+ endif
+endm
+
+;=========================================================================
+;
+; Structure related macros
+;
+; Structure globals
+
+VLsopen =0
+
+;
+; STRUCT - begins a structure declaration
+;
+STRUCT macro name,opts
+ if VLsopen
+ ENDSTRUCT
+ endif
+ VLsopen=1
+
+concat VLcbs,<VLcbs>,name
+VLcbstruct = 0
+endm
+
+;
+; ENDSTRUCT macro - terminates a STRUCT declaration
+;
+ENDSTRUCT macro
+equate %VLcbs,%VLcbstruct
+
+VLsopen =0
+endm
+
+;
+; Define simple field macro, given:
+; f = macro name
+; cb = size of field
+;
+_SSize macro cb,opts
+VLcbstruct = VLcbstruct + (cb)
+endm
+
+_DefSimpleF macro f,cb
+ f &macro name,opts
+ equate _F_&&name,%VLcbstruct
+ _SSize cb
+ &endm
+endm
+
+_DefSimpleF F_char,1
+_DefSimpleF F_BYTE,1
+
+_DefSimpleF F_int,2
+_DefSimpleF F_WORD,2
+_DefSimpleF F_BOOL,2
+_DefSimpleF F_FLAGS,2
+
+_DefSimpleF F_LONG,4
+_DefSimpleF F_DWORD,4
+
+_DefSimpleF F_intMBZ,2
+_DefSimpleF F_DWORDMBZ,4
+
+_DefSimpleF F_LPVOID,4
+_DefSimpleF F_CLPSTR,4
+_DefSimpleF F_CLPSTR0,4
+_DefSimpleF F_LPSTR,4
+
+_DefSimpleF F_POINT,4
+_DefSimpleF F_RECT,8
+
+F_RGB macro name,cb,opts
+ equate _F_&name,%VLcbstruct
+ _SSize cb
+endm
+
+F_RGCH equ <F_RGB>
+
+F_RGW macro name,cw,opts
+ equate _F_&name,%VLcbstruct
+ _SSize (cw*2)
+endm
+
+;
+; Generate a P_?LP???? macro, given:
+;
+; n = parameter macro name (e.g., P_LPRECT)
+; r = handler routine name (e.g., LP)
+; cb = size of buffer
+;
+; The generated macro checks only whether the
+; buffer is big enough.
+;
+_GenLP macro n,r,cb
+ &n &macro name,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&&name
+ mov cx,_P_&&name+2
+ mov bx,cb
+ lcall &r
+ _gensub <LP>
+ endif
+ &endm
+endm
+
+;=========================================================================
+;
+; Generic parameter macros
+;
+P_2 macro name, opts
+ _DefParm <name>,2,<opts>
+endm
+
+P_4 macro name, opts
+ _DefParm <name>,4,<opts>
+endm
+
+P_char equ <P_2>
+P_int equ <P_2>
+P_BYTE equ <P_2>
+P_BOOL equ <P_2>
+P_WORD equ <P_2>
+
+P_WORDMBZ equ <P_2>
+P_WORDMBNZ equ <P_2>
+
+P_LONG equ <P_4>
+P_DWORD equ <P_4>
+
+;
+; Generic handle
+;
+P_H macro name, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ lcall H
+ _gensub H
+ endif
+endm
+
+;
+; Generic handle or NULL
+;
+P_H0 equ <P_2>
+
+;
+; Ensure signed value is min <= value <= max
+;
+P_RVALUE macro name, min, max, opts
+ local valok
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,min
+ jl @F
+ cmp ax,max
+ jle valok
+@@:
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+valok:
+ endif
+endm
+
+;
+; Ensure signed value is 0 <= value <= max
+;
+P_VALUE macro name, max, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,max
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+;
+; Ensure unsigned value is value <= max
+;
+P_UVALUE equ <P_VALUE>
+
+;
+; Ensure signed value is 0 <= value <= max
+;
+P_VALUEW macro name, max, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,max
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+;
+; Ensure unsigned value is value <= max
+;
+P_UVALUEW equ <P_VALUEW>
+
+;
+; Ensure signed byte value is min <= value <= max
+;
+if 0
+P_BVALUE macro name,max,opts
+ _GenParm <name>,2,<opts>
+ if VLGen
+ mov al,_P_&name
+ cmp al,max
+ jle @F
+ lcall ErrorBValue
+@@:
+ endif
+endm
+else
+P_BVALUE equ <P_2>
+endif
+
+;
+; Ensure that no incorrect bits are set in a flags word
+; (i.e., (name & ~valid) == 0)
+;
+P_FLAGS macro name, valid, opts
+ _DefParm <name>,2,<opts>
+ if not(valid)
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ ife (low(not(valid)))
+ test ah,high(not(valid))
+ else
+ ife (high(not(valid)))
+ test al,low(not(valid))
+ else
+ test ax,not(valid)
+ endif
+ endif
+ jz @F
+ mov bx,ERR_BAD_FLAGS or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+ endif
+endm
+
+;
+; Ensure that no incorrect bits are set in a flags dword
+; (i.e., (name & ~valid) == 0)
+;
+P_DFLAGS macro name, valid_l, valid_h, opts
+ local flagok
+ _DefParm <name>,4,<opts>
+ if not(valid_l) or not(valid_h)
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ if not(valid_l)
+ test ax,not(valid_l)
+ if not(valid_h)
+ jnz @F
+ else
+ jz flagok
+ endif
+ endif
+ if not(valid_h)
+ test cx,not(valid_h)
+ jz flagok
+@@:
+ endif
+ mov bx,ERR_BAD_DFLAGS or ERR_WARNING
+ lcall Inval_Param_
+flagok:
+ endif
+ endif
+endm
+
+;
+; P_LPFN - function pointer
+; P_LPFN0 - function pointer or NULL
+;
+P_LPFN macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall LPFN
+ _gensub LPFN
+ endif
+endm
+
+P_LPFN0 macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall LPFN0
+ _gensub LPFN
+ endif
+endm
+
+_GenBuf macro p,r
+ P_&p &macro lpch, cch, opts
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&&lpch
+ mov cx,_P_&&lpch+2
+ mov bx,_P_&&cch
+ lcall &r
+ _gensub LP
+ endif
+ &endm
+endm
+
+_GenBufspl macro p,r
+ P_&p &macro lpch, cch, opts
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&&lpch
+ mov cx,_P_&&lpch+2
+ lea bx,_P_&&cch
+ lcall &r
+ _gensub LPBUF
+ endif
+ &endm
+endm
+
+_GenBufspl <LPBUFFER>,<LPBUF>
+_GenBuf <CLPBUFFER>,<CLP>
+_GenBufspl <LPBUFFER0>,<LPBUF0>
+_GenBuf <CLPBUFFER0>,<CLP0>
+
+;
+; If pszBuf is valid, set its first byte to 0
+;
+E_SETEMPTY macro pszBuf,cchBuf,opts
+ push bp
+ mov bp,sp
+ mov cx,_P_&cchBuf
+ mov bx,_P_&pszBuf
+ mov dx,_P_&pszBuf+2
+ pop bp
+ lcall SETEMPTY
+ _gensub SETEMPTY
+endm
+
+; Same as above, but with no supplied count
+;
+E_SETEMPTYNC macro pszBuf,opts
+ push bp
+ mov bp,sp
+ mov cx,1
+ mov bx,_P_&pszBuf
+ mov dx,_P_&pszBuf+2
+ pop bp
+ lcall SETEMPTY
+ _gensub SETEMPTY
+endm
+
+_GenLP <P_LPSTR>,<LP>,1
+_GenLP <P_LPSTR0>,<LP0>,1
+
+P_CLPSTR macro name,cch,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ ifb <cch>
+ mov bx,-1
+ else
+ mov bx,cch
+ endif
+ lcall CLPSZ
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTR0 macro name,cch,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ ifb <cch>
+ mov bx,-1
+ else
+ mov bx,cch
+ endif
+ lcall CLPSZ0
+ _gensub LPSZ
+ endif
+endm
+
+_GenLP <P_LPVOID>,<LP>,1
+_GenLP <P_LPVOID0>,<LP0>,1
+_GenLP <P_CLPVOID>,<CLP>,1
+_GenLP <P_CLPVOID0>,<CLP0>,1
+
+_GenLP <P_LPBYTE>,<LP>,1
+_GenLP <P_LPBYTE0>,<LP0>,1
+_GenLP <P_CLPBYTE>,<CLP>,1
+_GenLP <P_CLPBYTE0>,<CLP0>,1
+
+_GenLP <P_LPINT>,<LP>,2
+_GenLP <P_LPINT0>,<LP0>,2
+_GenLP <P_CLPINT>,<CLP>,2
+_GenLP <P_CLPINT0>,<CLP0>,2
+
+_GenLP <P_LPWORD>,<LP>,2
+_GenLP <P_LPWORD0>,<LP0>,2
+_GenLP <P_CLPWORD>,<CLP>,2
+_GenLP <P_CLPWORD0>,<CLP0>,2
+
+_GenLP <P_LPBOOL>,<LP>,2
+_GenLP <P_LPBOOL0>,<LP0>,2
+_GenLP <P_CLPBOOL>,<CLP>,2
+_GenLP <P_CLPBOOL0>,<CLP0>,2
+
+_GenLP <P_LPLONG>,<LP>,4
+_GenLP <P_LPLONG0>,<LP0>,4
+_GenLP <P_CLPLONG>,<CLP>,4
+_GenLP <P_CLPLONG0>,<CLP0>,4
+
+_GenLP <P_LPDWORD>,<LP>,4
+_GenLP <P_LPDWORD0>,<LP0>,4
+_GenLP <P_CLPDWORD>,<CLP>,4
+_GenLP <P_CLPDWORD0>,<CLP0>,4
+
+;=======================================================================
+;
+; Common USER types
+;
+STRUCT <POINT>
+F_int x
+F_int y
+ENDSTRUCT
+
+_GenLP <P_LPPOINT>,<LP>,%VLcbsPOINT
+_GenLP <P_LPPOINT0>,<LP0>,%VLcbsPOINT
+_GenLP <P_CLPPOINT>,<CLP>,%VLcbsPOINT
+_GenLP <P_CLPPOINT0>,<CLP0>,%VLcbsPOINT
+P_POINT equ <P_4>
+
+STRUCT <RECT>
+F_int left
+F_int top
+F_int right
+F_int bottom
+ENDSTRUCT
+
+_GenLP <P_LPRECT>,<LP>,%VLcbsRECT
+_GenLP <P_LPRECT0>,<LP0>,%VLcbsRECT
+_GenLP <P_CLPRECT>,<CLP>,%VLcbsRECT
+_GenLP <P_CLPRECT0>,<CLP0>,%VLcbsRECT
+
+;=======================================================================
+;
+; Common KERNEL types
+;
+P_GHANDLE macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ lcall GHANDLE
+ _gensub GHANDLE
+ endif
+
+endm
+
+P_GHANDLE0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ lcall GHANDLE0
+ _gensub GHANDLE
+ endif
+endm
+
+P_GHANDLE32 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ test al, 0100b;
+ jz @F
+ lcall GHANDLE
+ @@:
+ endif
+endm
+
+P_HANDLE equ <P_H>
+P_HANDLE0 equ <P_H0>
+
+P_ATOM equ <P_H>
+
+P_HINSTANCE equ <P_GHANDLE>
+P_HINSTANCE0 equ <P_GHANDLE0>
+
+P_HMODULE equ <P_GHANDLE>
+P_HMODULE0 equ <P_GHANDLE0>
+P_HMODULE32 equ <P_GHANDLE32>
+
+P_HTASK equ <P_GHANDLE>
+P_HTASK0 equ <P_GHANDLE0>
+
+P_CLPSTRATOM macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall CLPSTRATOM
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTRATOM0 macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall CLPSTRATOM0
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTRRSRC equ <P_CLPSTRATOM>
+P_CLPSTRRSRC0 equ <P_CLPSTRATOM0>
+
+;---------------------------------------------------------------------------
+; LAYER_EXPAND lseg
+;
+; Expands per-segment validation boilerplate code into segment lseg
+;
+LAYER_EXPAND macro lseg
+.list
+.lall
+ _SwitchSeg &lseg,%VLseg
+
+public VStart&lseg
+VStart&lseg:
+
+EXTRA_EXPAND lseg
+
+;
+; Handle validation
+;
+ifdef genH&lseg
+
+public H&lseg
+H&lseg:
+ or ax,ax
+ jz @F
+ ret
+@@:
+ mov bx,ERR_BAD_HANDLE
+ jmp short Inval_Param_&lseg
+
+endif ; genH&lseg
+
+ifdef genGHANDLE&lseg
+
+public GHANDLE0&lseg
+GHANDLE0&lseg:
+ or ax,ax ; accept NULL
+ jz GHexit&lseg
+
+public GHANDLE&lseg
+GHANDLE&lseg:
+ test al,0100b ; Reject GDT selectors
+ jnz GHldt&lseg
+ ; not yet. Some WOW cursor/icon handles
+ cmp ax, 0f000h ; look like GDT sels and are > 0xf000
+ jae GHexit&lseg
+ jmp GHerr&lseg ; Reject GDT sels now.
+
+GHldt&lseg:
+ cmp ax,0ffffh ; special case: -1 -> DS
+ jz GHexit&lseg
+ lar dx,ax ; is it a valid selector?
+ jnz GHerr&lseg
+GHexit&lseg:
+ ret
+
+GHerr&lseg:
+ mov bx,ERR_BAD_GLOBAL_HANDLE
+ jmp short Inval_Param_&lseg
+
+endif ; genGHANDLE&lseg
+
+ifdef genLPFN&lseg
+
+;
+; Function pointer validation
+;
+public LPFN0&lseg
+LPFN0&lseg:
+ mov bx,ax ; Allow NULL
+ or bx,cx
+ jz LPFN_exit&lseg
+
+public LPFN&lseg
+LPFN&lseg:
+beg_fault_trap LPFNbad&lseg
+ lar bx,cx
+ jnz LPFNerr&lseg
+ test bh,8
+ jz LPFNerr&lseg
+ mov es,cx ; validate pointer & offset
+ mov bx,ax
+ mov al,es:[bx]
+end_fault_trap
+
+ifdef DEBUG
+;
+; Make sure the function is exported by
+; ensuring that the first instructions are NOT
+; push ds, pop ax or mov ax,ds.
+;
+ mov bx,es:[bx]+2
+
+ cmp bx,0581eh ; Push ds, pop ax instructions?
+ jz LPFNerr&lseg ; Yes, must be an error.
+ cmp bx,0d88ch ; Mov ax,ds instruction?
+ jz LPFNerr&lseg ; No, we're ok, so jump ahead
+endif ; DEBUG
+
+LPFN_exit&lseg:
+ ret
+
+LPFNbad&lseg:
+ fault_fix_stack
+LPFNerr&lseg:
+ mov bx,ERR_BAD_FUNC_PTR
+ jmp short Inval_Param_&lseg
+
+endif ; genLPFN&lseg
+
+public Inval_Param_&lseg
+Inval_Param_&lseg:
+ pop dx ; convert near return addr to far
+ push cs
+ push dx
+ jmp HandleParamError
+
+ifdef genLP&lseg
+
+public LP0&lseg
+LP0&lseg:
+ or ax,ax ; if cx:ax == NULL, exit
+ jnz @F
+ jcxz CLPexit&lseg
+@@:
+public LP&lseg
+LP&lseg:
+beg_fault_trap CLPbad&lseg
+ mov es,cx
+ or bx,bx ; cb == 0?
+ jz CLPexit&lseg ; yes: just check selector
+ dec bx
+ add bx,ax
+ jc CLPbad1&lseg ; check 16 bit overflow
+ or byte ptr es:[bx],0 ; check write permission, limit
+end_fault_trap
+ ret
+
+public CLP0&lseg
+CLP0&lseg:
+ or ax,ax ; Accept ax:cx == 0
+ jnz @F
+ jcxz CLPexit&lseg
+@@:
+public CLP&lseg
+CLP&lseg:
+beg_fault_trap CLPbad&lseg
+ mov es,cx
+ or bx,bx ; cb == 0?
+ jz CLPexit&lseg ; yes: just check selector
+ dec bx
+ add bx,ax
+ jc CLPbad1&lseg ; check 16 bit overflow
+ mov bl,es:[bx] ; check read permission, limit
+end_fault_trap
+
+public CLPexit&lseg
+CLPexit&lseg:
+ ret
+
+CLPbad&lseg:
+ fault_fix_stack
+CLPbad1&lseg:
+ mov bx,ERR_BAD_PTR
+ jmp Inval_Param_&lseg
+
+endif ; genLP&lseg
+
+ifdef genLPBUF&lseg
+public LPBUF0&lseg
+LPBUF0&lseg:
+ or ax,ax ; if cx:ax == NULL, exit
+ jnz @F
+ jcxz LPBUFexit&lseg
+@@:
+public LPBUF&lseg
+LPBUF&lseg:
+beg_fault_trap LPBUFbad&lseg
+ mov es,cx
+ mov cx, word ptr ss:[bx] ; cb == 0?
+ jcxz LPBUFexit&lseg ; yes: just check selector
+ mov dx, bx
+ mov bx, ax
+ or byte ptr es:[bx],0 ; check write permission, start
+ mov bx, dx
+LPBUFpast1&lseg:
+ dec cx
+ add cx,ax
+ jnc @f ; 16-bit overflow
+ mov bx, 0ffffh
+ mov cx, bx
+ or byte ptr es:[bx],0 ; check write permission, 64k-1
+ jmp LPBUFov&lseg
+@@:
+ mov bx, cx
+ or byte ptr es:[bx],0 ; check write permission, end
+ ret
+end_fault_trap
+
+public LPBUFexit&lseg
+LPBUFexit&lseg:
+ ret
+LPBUFbad&lseg:
+ mov bx, dx
+ pop dx ; fault ip
+ add sp, 2 ; fault
+ cmp dx, offset LPBUFpast1&lseg
+ jb LPBUFbad1&lseg
+
+ mov dx, es
+ lsl cx, dx
+ jnz LPBUFbad1&lseg ; should not occur, we have loaded es
+LPBUFov&lseg:
+ sub cx, ax ; max legal cb
+ inc cx
+ mov word ptr ss:[bx], cx ; fix cb passed by user on stack
+ mov cx, es ; HandleParamError prints cx:ax
+ mov bx,ERR_BAD_PTR or ERR_WARNING
+ jmp Inval_Param_&lseg
+LPBUFbad1&lseg:
+ mov cx, es ; HandleParamError prints cx:ax
+ mov bx,ERR_BAD_PTR
+ jmp Inval_Param_&lseg
+endif ; genLPBUF&lseg
+
+ifdef genLPSZ&lseg
+
+;
+; cx:ax -> const pointer to z-terminated string or MAKEINTATOM atom.
+;
+public CLPSTRATOM0&lseg
+CLPSTRATOM0&lseg:
+ jcxz CLPSZexit&lseg ; If selector is NULL, then all is well.
+
+public CLPSTRATOM&lseg
+CLPSTRATOM&lseg:
+ jcxz @F ; if selector == 0, then may be atom.
+ mov bx,256 ; max string length of 255 characters.
+ jmp short CLPSZ&lseg
+@@:
+ or ax,ax ; offset == 0? if so, it's bogus
+ jz ErrorStrPtr&lseg
+CLPSZexit&lseg:
+ ret
+;
+; cx:ax => const pointer to zero-terminated string.
+; bx => Maximum string length (including zero terminator)
+;
+public CLPSZ0&lseg
+CLPSZ0&lseg:
+ mov dx,ax
+ or dx,cx
+ jz CLPSZexit&lseg
+public CLPSZ&lseg
+CLPSZ&lseg:
+ push di ; preserve these regs
+ push cx
+ mov dx,ax ; preserve original ax in dx
+beg_fault_trap LPSZfault&lseg
+ mov es,cx
+ mov di,ax
+
+ xor ax,ax
+ mov cx,-1
+ cld
+ repnz scasb
+end_fault_trap
+ neg cx ; cx = string length + 1
+ dec cx
+ cmp cx,bx ; error if string length + 1 > cchMax
+
+ pop cx ; restore regs before branching
+ pop di
+ xchg ax,dx
+
+ ja ErrorStrPtr&lseg ; jump if error
+ ret
+
+LPSZfault&lseg:
+ fault_fix_stack
+ pop cx ; restore regs
+ pop di
+ xchg ax,dx
+
+public ErrorStrPtr&lseg
+ErrorStrPtr&lseg:
+ mov bx,ERR_BAD_STRING_PTR
+ jmp Inval_Param_&lseg
+
+endif ; genLPSZ&lseg
+
+ifdef genSETEMPTY&lseg
+
+public SETEMPTY&lseg
+SETEMPTY&lseg:
+ jcxz SETEMPTYexit&lseg ; 0-length buffer: do nothing.
+beg_fault_trap SETEMPTYbad&lseg
+ mov es,dx
+ mov byte ptr es:[bx],0 ; jam in a zero terminator
+end_fault_trap
+SETEMPTYexit&lseg:
+ xor ax,ax
+ cwd
+ ret
+
+SETEMPTYbad&lseg:
+ fault_fix_stack
+ jmp short SETEMPTYexit&lseg
+
+endif ; genSETEMPTY&lseg
+
+public VEnd&lseg
+VEnd&lseg:
+
+sEnd %VLseg
+VLseg equ <>
+
+endm ;LAYER_EXPAND
+
+endif ;; IF1
diff --git a/private/mvdm/wow16/inc/layer.inc b/private/mvdm/wow16/inc/layer.inc
new file mode 100644
index 000000000..47bf6c0f1
--- /dev/null
+++ b/private/mvdm/wow16/inc/layer.inc
@@ -0,0 +1,1386 @@
+;=======================================================
+;
+; Macros stolen from cmacros.inc (so we don't have to include it all)
+;
+ .286p
+
+externNP macro n
+ irp x,<n>
+ extrn x:near
+ endm
+endm
+
+externFP macro n
+ irp x,<n>
+ extrn x:far
+ endm
+endm
+
+externW macro w
+ irp x,<w>
+ extrn x:word
+ endm
+endm
+
+assumes macro s,ln
+ assume s:_&ln
+endm
+
+createSeg macro n,ln,a,co,cl,grp
+ n segment a co '&cl'
+ n ends
+endm
+
+sBegin macro seg
+ assume cs:_&seg
+ _&seg segment
+endm
+
+sEnd macro seg
+ _&seg ends
+ assume cs:nothing
+endm
+
+errnz macro x ;;display error if expression is <>0
+ if2
+ if x ;;if expression is non-zero,
+ errnz1 <x>,%(x)
+ endif
+ endif
+endm
+
+errnz1 macro x1,x2
+ = *errnz* x1 = x2
+ .err
+endm
+
+errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
+ errnz <offset $ - offset l x>
+endm
+
+createSeg _DATA,DATA,WORD,PUBLIC,DATA
+
+;=======================================================
+;
+; Error API definitions
+;
+ExternFP <HandleParamError>
+
+; error codes
+include logerror.inc
+
+;================================================================
+; Variable and temporary initialization
+
+VLseg equ <> ; Holds current segment name
+
+VLopen = 0
+VLerrnotinvoked = 0
+ifndef VLnogenpall
+VLnogenpall = 0
+endif
+
+VLnogen = 0
+VLnogenparm = 0
+
+VLsavees = 0
+VLsavebx = 0
+
+;if1
+if 1
+
+;================================================================
+; Utility macros
+
+;---------------------------------------------------------------------------
+;
+; lodsw cs:[si]
+;
+cslodsw macro
+ db 2eh ;; CS override
+ lodsw
+endm
+
+;---------------------------------------------------------------------------
+;
+; lodsb cs:[si]
+;
+cslodsb macro
+ db 2eh ;; CS override
+ lodsb
+endm
+
+SkipTwoBytes macro
+ db 0A9h ;; Opcode for CMP AX,(immediate word)
+endm
+
+;---------------------------------------------------------------------------
+;
+; Define a as the concatenation of b & c
+;
+concat macro a,b,c,d,e,f
+a equ <b&c&d&e&f>
+endm
+
+;---------------------------------------------------------------------------
+;
+; Assign a to b.
+;
+equate macro a,b
+ a = b
+endm
+
+;
+; Print a message
+;
+_print macro a,b,c
+if2
+ %out a&b&c
+endif
+endm
+
+
+;===============================================================
+
+;---------------------------------------------------------------------------
+;
+; _gensub LABEL
+;
+; Causes per-segment subroutine code associated with type LABEL
+; to be generated, by setting the genLABEL&lseg flag.
+;
+_gensub2 macro l,s
+ gen&l&s = 1
+endm
+
+_gensub macro l
+ _gensub2 <l>,%VLseg
+endm
+
+;---------------------------------------------------------------------------
+; _SwitchSeg
+;
+; Switches current segment to seg, creating the segment if needed.
+;
+_SwitchSeg macro seg,oldseg
+ ifdifi <&seg>,<oldseg>
+
+ ifnb <oldseg>
+sEnd oldseg
+ endif
+
+ concat <VLseg>,seg,
+
+;createSeg _&seg,seg,BYTE,PUBLIC,CODE
+createSeg _&seg,seg,WORD,PUBLIC,CODE
+
+sBegin seg
+assumes CS,seg
+
+ endif
+endm
+
+
+;---------------------------------------------------------------------------
+; API
+;
+API macro rettype,name,seg,optlist
+
+ if VLopen
+ APIEND
+ endif
+
+VLname equ <name>
+VLcbparms = 0
+VLcbskip = 0
+VLerrnotinvoked= 1
+VLopen = 1
+VLnogen = 0
+VLnogenparm = 0
+VLasm = 0
+VLfunnyframe = 0
+VLnodata = 0
+VLcargs = 0
+VLplist equ <>
+VLATMframe = 0 ; special entry/exit code sequence for ATM's patching
+VLATMfrmds = 0 ; ATM entry/exit code: mov ax,_DATA at beginning.
+
+VLsavees = 0
+VLsavebx = 0
+ _SwitchSeg seg,%VLseg
+
+ irp opt,<optlist>
+
+ ifidni <opt>,<NOGEN>
+ VLnogen = 1
+ endif
+
+ ifidni <opt>,<VOID>
+ VLnogen = 1
+ endif
+
+ ifidni <opt>,<ASM>
+ VLasm = 1
+ endif
+
+ifndef WOW
+ ; don't need that bp and ds stuff
+
+ ifidni <opt>,<ATMFRAME>
+ VLATMframe = 1
+ endif
+
+ ifidni <opt>,<ATMFRAMEDS>
+ VLATMfrmds = 1
+ VLATMframe = 1
+ endif
+endif
+
+ ifidni <opt>,<FUNNYFRAME>
+ VLfunnyframe = 1
+ endif
+
+ ifidni <opt>,<NODATA>
+ VLnodata = 1
+ endif
+
+ ifidni <opt>,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogen = 1
+ endif
+ endif
+
+ ifidni <opt>,<C>
+ VLcargs = 1
+ endif
+
+ ifidni <opt>,<SAVEES>
+ VLsavees = 2 ; sizeof(ES)
+ endif
+
+ ifidni <opt>,<SAVEBX>
+ VLsavebx = 2 ; sizeof(BX)
+ endif
+
+ endm
+
+concat <VLsegoffset>,<seg>,<offset>
+concat <VLnameerror>,<name>,<_error>
+concat <VLnamecbparms>,<name>,<cbparms>
+
+ if1
+equate %VLnamecbparms, %VLcbparms
+ else
+equate %VLnamecbparms, %VLnamecbparms
+ endif
+
+ ife VLnogen
+
+ ife VLcargs
+concat <VLiname>,<I>,<name>
+ExternNP I&name
+
+public name
+name:
+
+ else
+concat <VLiname>,<_I>,<name>
+ExternNP _I&name
+
+public _&name
+_&name:
+
+ endif
+
+VLframe = 0 ; no frame set up yet.
+
+ endif ; VLnogen
+
+endm ;; VL
+
+;---------------------------------------------------------------------------
+; APIERR
+;
+; Optionally used after parameter decls to begin error handling code
+;
+APIERR macro opts
+
+ ife VLnogen
+ ife VLframe
+ _print <Nothing to validate for >,%VLiname
+ else
+ pop dx ; pop off error handler address
+ pop bp ; restore BP
+ if VLATMframe
+ dec bp ; fix BP back up
+ endif
+ if VLsavees
+ pop es
+ endif
+ if VLsavebx
+ pop bx
+ endif
+ endif
+ jmp VLiname ; jmp to internal routine.
+
+equate %VLnamecbparms, %VLcbparms
+
+VLnameerror:
+ VLerrnotinvoked = 0
+
+ endif ; VLnogen
+
+endm ;; APIERR
+
+;---------------------------------------------------------------------------
+; APIEND
+;
+; Used after APIERR to terminate error handling code.
+;
+APIEND macro
+
+_PurgeParms %VLplist
+
+ ife VLnogen
+
+ if VLerrnotinvoked
+ APIERR
+ endif
+ if VLsavees
+ pop es
+ endif
+ if VLsavebx
+ pop bx
+ endif
+ ife VLcargs
+ retf VLcbparms
+ else
+ retf
+ endif
+
+VLopen = 0
+
+ endif ; VLnogen
+
+endm ;; APIEND
+
+;---------------------------------------------------------------------------
+;
+; _FlsFrame - Generate frame code
+;
+_FlsFrame macro
+ ife VLframe
+ if VLATMfrmds
+ mov ax,_DATA
+ endif
+ if VLsavebx
+ push bx
+ endif
+ if VLsavees
+ push es
+ endif
+ if VLATMframe
+ inc bp
+ push bp
+ mov bp,sp
+ push ds ; push ds and pop it off.
+ pop ds ; (we need to pop DS rather than
+ ; something fast like pop AX because
+ ; ATM doesn't preserve DS itself)
+ else
+ push bp
+ mov bp,sp
+ endif
+ push offset VLnameerror ; push address of error handler
+ VLframe = 1
+ endif
+endm
+
+;---------------------------------------------------------------------------
+; _ChkName
+;
+; Ensure name was specified
+
+_ChkName macro name
+ ifb <name>
+ _print <Missing parameter name in >,%VLiname
+ endif
+endm
+
+;---------------------------------------------------------------------------
+; _ParmOpts
+;
+; Parse parameter option flags
+;
+_ParmOpts macro opts
+
+ VLnogenparm = VLnogenpall
+
+ irp opt,<opts>
+ ifidni <opt>,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogenparm = 1
+ endif
+ ifidni <opt>,<NOGEN>
+ VLnogenparm = 1
+ endif
+ endif
+ endm
+endm
+
+;---------------------------------------------------------------------------
+; _DefParm name,cb,opts
+;
+; Take care of default parameter stuff, such as defining argument.
+;
+_DP_Add macro old,new
+ ifb <old>
+VLplist equ <new>
+ else
+VLplist equ <old,new>
+ endif
+endm
+
+_DefParm macro name,cb,opts
+ _ChkName <name>
+ _ParmOpts <opts>
+
+ if VLcargs
+concat _P_&name,<[bp]+6+>,%(VLcbparms+VLsavees+VLsavebx)
+ VLcbparms=VLcbparms+(cb)
+ else
+ VLcbparms=VLcbparms+(cb)
+concat _P_&name,<[bp]+6->,%VLcbparms,<+>,%(VLnamecbparms+VLsavees+VLsavebx)
+ endif
+
+_DP_Add %VLplist,<_P_&name>
+
+ VLgen = 1
+ if VLnogenparm or VLnogen
+ VLgen = 0
+ endif
+endm
+
+;----------------------------------------------------------------------------
+;
+; _GenParm name, cb, opts
+;
+_GenParm macro name,cb,opts
+ _DefParm <name>,<cb>,<opts>
+ if VLgen
+ _FlsFrame
+ endif
+endm
+
+lcall2 macro op,label,seg
+ op label&seg
+endm
+
+lcall macro label
+ lcall2 <call>,<label>,%VLseg
+endm
+
+ljmp macro label
+ lcall2 <jmp>,<label>,%VLseg
+endm
+
+;
+; _PurgeParms - purge list of parameters we've defined
+;
+_PurgeParms macro list
+ irp sym,<list>
+sym equ <>
+ endm
+endm
+
+;---------------------------------------------------------------------------
+; LAYER_START
+;
+; Used before any VL invocations
+;
+LAYER_START macro
+assumes ds,DATA
+
+endm
+
+;---------------------------------------------------------------------------
+; LAYER_END
+;
+; Ends all VL definitions
+;
+LAYER_END macro
+ if VLsopen
+ ENDSTRUCT
+ endif
+ if VLopen
+ APIEND
+ endif
+ if VLerrnotinvoked
+ APIERR
+ endif
+endm
+
+;=========================================================================
+;
+; Structure related macros
+;
+; Structure globals
+
+VLsopen =0
+
+;
+; STRUCT - begins a structure declaration
+;
+STRUCT macro name,opts
+ if VLsopen
+ ENDSTRUCT
+ endif
+ VLsopen=1
+
+concat VLcbs,<VLcbs>,name
+VLcbstruct = 0
+endm
+
+;
+; ENDSTRUCT macro - terminates a STRUCT declaration
+;
+ENDSTRUCT macro
+equate %VLcbs,%VLcbstruct
+
+VLsopen =0
+endm
+
+;
+; Define simple field macro, given:
+; f = macro name
+; cb = size of field
+;
+_SSize macro cb,opts
+VLcbstruct = VLcbstruct + (cb)
+endm
+
+_DefSimpleF macro f,cb
+ f &macro name,opts
+ equate _F_&&name,%VLcbstruct
+ _SSize cb
+ &endm
+endm
+
+_DefSimpleF F_char,1
+_DefSimpleF F_BYTE,1
+
+_DefSimpleF F_int,2
+_DefSimpleF F_WORD,2
+_DefSimpleF F_BOOL,2
+_DefSimpleF F_FLAGS,2
+
+_DefSimpleF F_LONG,4
+_DefSimpleF F_DWORD,4
+
+_DefSimpleF F_intMBZ,2
+_DefSimpleF F_DWORDMBZ,4
+
+_DefSimpleF F_LPVOID,4
+_DefSimpleF F_CLPSTR,4
+_DefSimpleF F_CLPSTR0,4
+_DefSimpleF F_LPSTR,4
+
+_DefSimpleF F_POINT,4
+_DefSimpleF F_RECT,8
+
+ifdef WOW
+_DefSimpleF F_LARGEPOINT,8
+endif
+
+F_RGB macro name,cb,opts
+ equate _F_&name,%VLcbstruct
+ _SSize cb
+endm
+
+F_RGCH equ <F_RGB>
+
+F_RGW macro name,cw,opts
+ equate _F_&name,%VLcbstruct
+ _SSize (cw*2)
+endm
+
+;
+; Generate a P_?LP???? macro, given:
+;
+; n = parameter macro name (e.g., P_LPRECT)
+; r = handler routine name (e.g., LP)
+; cb = size of buffer
+;
+; The generated macro checks only whether the
+; buffer is big enough.
+;
+_GenLP macro n,r,cb
+ &n &macro name,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&&name
+ mov cx,_P_&&name+2
+ mov bx,cb
+ lcall &r
+ _gensub <LP>
+ endif
+ &endm
+endm
+
+;=========================================================================
+;
+; Generic parameter macros
+;
+P_2 macro name, opts
+ _DefParm <name>,2,<opts>
+endm
+
+P_4 macro name, opts
+ _DefParm <name>,4,<opts>
+endm
+
+P_8 macro name, opts
+ _DefParm <name>,8,<opts>
+endm
+
+P_char equ <P_2>
+P_int equ <P_2>
+P_BYTE equ <P_2>
+P_BOOL equ <P_2>
+P_WORD equ <P_2>
+
+P_WORDMBZ equ <P_2>
+P_WORDMBNZ equ <P_2>
+
+P_LONG equ <P_4>
+P_DWORD equ <P_4>
+
+;
+; Generic handle
+;
+P_H macro name, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+; mov ax,_P_&name
+; lcall H
+; _gensub H
+ endif
+endm
+
+;
+; Generic handle or NULL
+;
+P_H0 equ <P_2>
+
+;
+; Ensure signed value is min <= value <= max
+;
+P_RVALUE macro name, min, max, opts
+ local valok
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,min
+ jl @F
+ cmp ax,max
+ jle valok
+@@:
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+valok:
+ endif
+endm
+
+;
+; Ensure signed value is 0 <= value <= max
+;
+P_VALUE macro name, max, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,max
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+;
+; Ensure unsigned value is value <= max
+;
+P_UVALUE equ <P_VALUE>
+
+;
+; Ensure signed value is 0 <= value <= max
+;
+P_VALUEW macro name, max, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name
+ cmp ax,max
+ jbe @F ;; unsigned comparison to catch < 0.
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+;
+; Ensure unsigned value is value <= max
+;
+P_UVALUEW equ <P_VALUEW>
+
+;
+; Ensure signed byte value is min <= value <= max
+;
+if 0
+P_BVALUE macro name,max,opts
+ _GenParm <name>,2,<opts>
+ if VLGen
+ mov al,_P_&name
+ cmp al,max
+ jle @F
+ lcall ErrorBValue
+@@:
+ endif
+endm
+else
+P_BVALUE equ <P_2>
+endif
+
+;
+; Ensure that no incorrect bits are set in a flags word
+; (i.e., (name & ~valid) == 0)
+;
+P_FLAGS macro name, valid, opts
+ _DefParm <name>,2,<opts>
+ if not(valid)
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ ife (low(not(valid)))
+ test ah,high(not(valid))
+ else
+ ife (high(not(valid)))
+ test al,low(not(valid))
+ else
+ test ax,not(valid)
+ endif
+ endif
+ jz @F
+ mov bx,ERR_BAD_FLAGS or ERR_WARNING
+ lcall Inval_Param_
+@@:
+ endif
+ endif
+endm
+
+;
+; Ensure that no incorrect bits are set in a flags dword
+; (i.e., (name & ~valid) == 0)
+;
+P_DFLAGS macro name, valid_l, valid_h, opts
+ local flagok
+ _DefParm <name>,4,<opts>
+ if not(valid_l) or not(valid_h)
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ if not(valid_l)
+ test ax,not(valid_l)
+ if not(valid_h)
+ jnz @F
+ else
+ jz flagok
+ endif
+ endif
+ if not(valid_h)
+ test cx,not(valid_h)
+ jz flagok
+@@:
+ endif
+ mov bx,ERR_BAD_DFLAGS or ERR_WARNING
+ lcall Inval_Param_
+flagok:
+ endif
+ endif
+endm
+
+;
+; P_LPFN - function pointer
+; P_LPFN0 - function pointer or NULL
+;
+P_LPFN macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall LPFN
+ _gensub LPFN
+ endif
+endm
+
+P_LPFN0 macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall LPFN0
+ _gensub LPFN
+ endif
+endm
+
+_GenBuf macro p,r
+ P_&p &macro lpch, cch, opts
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&&lpch
+ mov cx,_P_&&lpch+2
+ mov bx,_P_&&cch
+ lcall &r
+ _gensub LP
+ endif
+ &endm
+endm
+
+_GenBufspl macro p,r
+ P_&p &macro lpch, cch, opts
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&&lpch
+ mov cx,_P_&&lpch+2
+ lea bx,_P_&&cch
+ lcall &r
+ _gensub LPBUF
+ endif
+ &endm
+endm
+
+_GenBufspl <LPBUFFER>,<LPBUF>
+_GenBuf <CLPBUFFER>,<CLP>
+_GenBufspl <LPBUFFER0>,<LPBUF0>
+_GenBuf <CLPBUFFER0>,<CLP0>
+
+;
+; If pszBuf is valid, set its first byte to 0
+;
+E_SETEMPTY macro pszBuf,cchBuf,opts
+ push bp
+ mov bp,sp
+ mov cx,_P_&cchBuf
+ mov bx,_P_&pszBuf
+ mov dx,_P_&pszBuf+2
+ pop bp
+ lcall SETEMPTY
+ _gensub SETEMPTY
+endm
+
+; Same as above, but with no supplied count
+;
+E_SETEMPTYNC macro pszBuf,opts
+ push bp
+ mov bp,sp
+ mov cx,1
+ mov bx,_P_&pszBuf
+ mov dx,_P_&pszBuf+2
+ pop bp
+ lcall SETEMPTY
+ _gensub SETEMPTY
+endm
+
+_GenLP <P_LPSTR>,<LP>,1
+_GenLP <P_LPSTR0>,<LP0>,1
+
+P_CLPSTR macro name,cch,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ ifb <cch>
+ mov bx,-1
+ else
+ mov bx,cch
+ endif
+ lcall CLPSZ
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTR0 macro name,cch,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ ifb <cch>
+ mov bx,-1
+ else
+ mov bx,cch
+ endif
+ lcall CLPSZ0
+ _gensub LPSZ
+ endif
+endm
+
+_GenLP <P_LPVOID>,<LP>,1
+_GenLP <P_LPVOID0>,<LP0>,1
+_GenLP <P_CLPVOID>,<CLP>,1
+_GenLP <P_CLPVOID0>,<CLP0>,1
+
+_GenLP <P_LPBYTE>,<LP>,1
+_GenLP <P_LPBYTE0>,<LP0>,1
+_GenLP <P_CLPBYTE>,<CLP>,1
+_GenLP <P_CLPBYTE0>,<CLP0>,1
+
+_GenLP <P_LPINT>,<LP>,2
+_GenLP <P_LPINT0>,<LP0>,2
+_GenLP <P_CLPINT>,<CLP>,2
+_GenLP <P_CLPINT0>,<CLP0>,2
+
+_GenLP <P_LPWORD>,<LP>,2
+_GenLP <P_LPWORD0>,<LP0>,2
+_GenLP <P_CLPWORD>,<CLP>,2
+_GenLP <P_CLPWORD0>,<CLP0>,2
+
+_GenLP <P_LPBOOL>,<LP>,2
+_GenLP <P_LPBOOL0>,<LP0>,2
+_GenLP <P_CLPBOOL>,<CLP>,2
+_GenLP <P_CLPBOOL0>,<CLP0>,2
+
+_GenLP <P_LPLONG>,<LP>,4
+_GenLP <P_LPLONG0>,<LP0>,4
+_GenLP <P_CLPLONG>,<CLP>,4
+_GenLP <P_CLPLONG0>,<CLP0>,4
+
+_GenLP <P_LPDWORD>,<LP>,4
+_GenLP <P_LPDWORD0>,<LP0>,4
+_GenLP <P_CLPDWORD>,<CLP>,4
+_GenLP <P_CLPDWORD0>,<CLP0>,4
+
+;=======================================================================
+;
+; Common USER types
+;
+STRUCT <POINT>
+F_int x
+F_int y
+ENDSTRUCT
+
+STRUCT <LARGEPOINT>
+F_LONG x
+F_LONG y
+ENDSTRUCT
+
+
+_GenLP <P_LPPOINT>,<LP>,%VLcbsPOINT
+_GenLP <P_LPPOINT0>,<LP0>,%VLcbsPOINT
+_GenLP <P_CLPPOINT>,<CLP>,%VLcbsPOINT
+_GenLP <P_CLPPOINT0>,<CLP0>,%VLcbsPOINT
+P_POINT equ <P_4>
+
+_GenLP <P_LPLARGEPOINT>,<LP>,%VLcbsLARGEPOINT
+P_LARGEPOINT equ <P_8>
+
+STRUCT <RECT>
+F_int left
+F_int top
+F_int right
+F_int bottom
+ENDSTRUCT
+
+_GenLP <P_LPRECT>,<LP>,%VLcbsRECT
+_GenLP <P_LPRECT0>,<LP0>,%VLcbsRECT
+_GenLP <P_CLPRECT>,<CLP>,%VLcbsRECT
+_GenLP <P_CLPRECT0>,<CLP0>,%VLcbsRECT
+
+;=======================================================================
+;
+; Common KERNEL types
+;
+P_GHANDLE macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ lcall GHANDLE
+ _gensub GHANDLE
+ endif
+
+endm
+
+P_GHANDLE0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ lcall GHANDLE0
+ _gensub GHANDLE
+ endif
+endm
+
+P_GHANDLE32 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ test al, 0100b ;let zero & BOGUSGDT hInst's through
+ jz @F
+ lcall GHANDLE
+ _gensub GHANDLE
+ @@:
+ endif
+endm
+
+P_HANDLE equ <P_H>
+P_HANDLE0 equ <P_H0>
+
+P_ATOM equ <P_H>
+
+P_HINSTANCE equ <P_GHANDLE>
+P_HINSTANCE0 equ <P_GHANDLE0>
+P_HINSTANCE32 equ <P_GHANDLE32>
+
+P_HMODULE equ <P_GHANDLE>
+P_HMODULE0 equ <P_GHANDLE0>
+
+P_HTASK equ <P_GHANDLE>
+P_HTASK0 equ <P_GHANDLE0>
+
+P_CLPSTRATOM macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall CLPSTRATOM
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTRATOM0 macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall CLPSTRATOM0
+ _gensub LPSZ
+ endif
+endm
+
+P_CLPSTRRSRC equ <P_CLPSTRATOM>
+P_CLPSTRRSRC0 equ <P_CLPSTRATOM0>
+
+;---------------------------------------------------------------------------
+; LAYER_EXPAND lseg
+;
+; Expands per-segment validation boilerplate code into segment lseg
+;
+LAYER_EXPAND macro lseg
+.list
+.lall
+ _SwitchSeg &lseg,%VLseg
+
+public VStart&lseg
+VStart&lseg:
+
+EXTRA_EXPAND lseg
+
+;
+; Handle validation
+;
+ifdef genH&lseg
+
+public H&lseg
+H&lseg:
+ or ax,ax
+ jz @F
+ ret
+@@:
+ mov bx,ERR_BAD_HANDLE
+ jmp short Inval_Param_&lseg
+
+endif ; genH&lseg
+
+ifdef genGHANDLE&lseg
+
+public GHANDLE0&lseg
+GHANDLE0&lseg:
+ or ax,ax ; accept NULL
+ jz GHexit&lseg
+
+public GHANDLE&lseg
+GHANDLE&lseg:
+ test al,0100b ; Reject GDT selectors
+ jz GHerr&lseg
+ cmp ax,0ffffh ; special case: -1 -> DS
+ jz GHexit&lseg
+ lar dx,ax ; is it a valid selector?
+ jnz GHerr&lseg
+GHexit&lseg:
+ ret
+
+GHerr&lseg:
+ mov bx,ERR_BAD_GLOBAL_HANDLE
+ jmp short Inval_Param_&lseg
+
+endif ; genGHANDLE&lseg
+
+ifdef genLPFN&lseg
+
+;
+; Function pointer validation
+;
+public LPFN0&lseg
+LPFN0&lseg:
+ mov bx,ax ; Allow NULL
+ or bx,cx
+ jz LPFN_exit&lseg
+
+public LPFN&lseg
+LPFN&lseg:
+beg_fault_trap LPFNbad&lseg
+ lar bx,cx
+ jnz LPFNerr&lseg
+ test bh,8
+ jz LPFNerr&lseg
+ mov es,cx ; validate pointer & offset
+ mov bx,ax
+ mov al,es:[bx]
+end_fault_trap
+
+ifdef DEBUG
+;
+; Make sure the function is exported by
+; ensuring that the first instructions are NOT
+; push ds, pop ax or mov ax,ds.
+;
+ mov bx,es:[bx]+2
+
+ cmp bx,0581eh ; Push ds, pop ax instructions?
+ jz LPFNerr&lseg ; Yes, must be an error.
+ cmp bx,0d88ch ; Mov ax,ds instruction?
+ jz LPFNerr&lseg ; No, we're ok, so jump ahead
+endif ; DEBUG
+
+LPFN_exit&lseg:
+ ret
+
+LPFNbad&lseg:
+ fault_fix_stack
+LPFNerr&lseg:
+ mov bx,ERR_BAD_FUNC_PTR
+ jmp short Inval_Param_&lseg
+
+endif ; genLPFN&lseg
+
+public Inval_Param_&lseg
+Inval_Param_&lseg:
+ pop dx ; convert near return addr to far
+ push cs
+ push dx
+ jmp HandleParamError
+
+ifdef genLP&lseg
+
+public LP0&lseg
+LP0&lseg:
+ or ax,ax ; if cx:ax == NULL, exit
+ jnz @F
+ jcxz CLPexit&lseg
+@@:
+public LP&lseg
+LP&lseg:
+beg_fault_trap CLPbad&lseg
+ mov es,cx
+ or bx,bx ; cb == 0?
+ jz CLPexit&lseg ; yes: just check selector
+ dec bx
+ add bx,ax
+ jc CLPbad1&lseg ; check 16 bit overflow
+ or byte ptr es:[bx],0 ; check write permission, limit
+end_fault_trap
+ ret
+
+public CLP0&lseg
+CLP0&lseg:
+ or ax,ax ; Accept ax:cx == 0
+ jnz @F
+ jcxz CLPexit&lseg
+@@:
+public CLP&lseg
+CLP&lseg:
+beg_fault_trap CLPbad&lseg
+ mov es,cx
+ or bx,bx ; cb == 0?
+ jz CLPexit&lseg ; yes: just check selector
+ dec bx
+ add bx,ax
+ jc CLPbad1&lseg ; check 16 bit overflow
+ mov bl,es:[bx] ; check read permission, limit
+end_fault_trap
+
+public CLPexit&lseg
+CLPexit&lseg:
+ ret
+
+CLPbad&lseg:
+ fault_fix_stack
+CLPbad1&lseg:
+ mov bx,ERR_BAD_PTR
+ jmp Inval_Param_&lseg
+
+endif ; genLP&lseg
+
+ifdef genLPBUF&lseg
+public LPBUF0&lseg
+LPBUF0&lseg:
+ or ax,ax ; if cx:ax == NULL, exit
+ jnz @F
+ jcxz LPBUFexit&lseg
+@@:
+public LPBUF&lseg
+LPBUF&lseg:
+beg_fault_trap LPBUFbad&lseg
+ mov es,cx
+ mov cx, word ptr ss:[bx] ; cb == 0?
+ jcxz LPBUFexit&lseg ; yes: just check selector
+ mov dx, bx
+ mov bx, ax
+ or byte ptr es:[bx],0 ; check write permission, start
+ mov bx, dx
+LPBUFpast1&lseg:
+ dec cx
+ add cx,ax
+ jnc @f ; 16-bit overflow
+ mov bx, 0ffffh
+ mov cx, bx
+ or byte ptr es:[bx],0 ; check write permission, 64k-1
+ jmp LPBUFov&lseg
+@@:
+ mov bx, cx
+ or byte ptr es:[bx],0 ; check write permission, end
+ ret
+end_fault_trap
+
+public LPBUFexit&lseg
+LPBUFexit&lseg:
+ ret
+LPBUFbad&lseg:
+ mov bx, dx
+ pop dx ; fault ip
+ add sp, 2 ; fault
+ cmp dx, offset LPBUFpast1&lseg
+ jb LPBUFbad1&lseg
+
+ mov dx, es
+ lsl cx, dx
+ jnz LPBUFbad1&lseg ; should not occur, we have loaded es
+LPBUFov&lseg:
+ sub cx, ax ; max legal cb
+ inc cx
+ mov word ptr ss:[bx], cx ; fix cb passed by user on stack
+ mov cx, es ; HandleParamError prints cx:ax
+ mov bx,ERR_BAD_PTR or ERR_WARNING
+ jmp Inval_Param_&lseg
+LPBUFbad1&lseg:
+ mov cx, es ; HandleParamError prints cx:ax
+ mov bx,ERR_BAD_PTR
+ jmp Inval_Param_&lseg
+endif ; genLPBUF&lseg
+
+ifdef genLPSZ&lseg
+
+;
+; cx:ax -> const pointer to z-terminated string or MAKEINTATOM atom.
+;
+public CLPSTRATOM0&lseg
+CLPSTRATOM0&lseg:
+ jcxz CLPSZexit&lseg ; If selector is NULL, then all is well.
+
+public CLPSTRATOM&lseg
+CLPSTRATOM&lseg:
+ jcxz @F ; if selector == 0, then may be atom.
+ mov bx,256 ; max string length of 255 characters.
+ jmp short CLPSZ&lseg
+@@:
+ or ax,ax ; offset == 0? if so, it's bogus
+ jz ErrorStrPtr&lseg
+CLPSZexit&lseg:
+ ret
+;
+; cx:ax => const pointer to zero-terminated string.
+; bx => Maximum string length (including zero terminator)
+;
+public CLPSZ0&lseg
+CLPSZ0&lseg:
+ mov dx,ax
+ or dx,cx
+ jz CLPSZexit&lseg
+public CLPSZ&lseg
+CLPSZ&lseg:
+ push di ; preserve these regs
+ push cx
+ mov dx,ax ; preserve original ax in dx
+beg_fault_trap LPSZfault&lseg
+ mov es,cx
+ mov di,ax
+
+ xor ax,ax
+ mov cx,-1
+ cld
+ repnz scasb
+end_fault_trap
+ neg cx ; cx = string length + 1
+ dec cx
+ cmp cx,bx ; error if string length + 1 > cchMax
+
+ pop cx ; restore regs before branching
+ pop di
+ xchg ax,dx
+
+ ja ErrorStrPtr&lseg ; jump if error
+ ret
+
+LPSZfault&lseg:
+ fault_fix_stack
+ pop cx ; restore regs
+ pop di
+ xchg ax,dx
+
+public ErrorStrPtr&lseg
+ErrorStrPtr&lseg:
+ mov bx,ERR_BAD_STRING_PTR
+ jmp Inval_Param_&lseg
+
+endif ; genLPSZ&lseg
+
+ifdef genSETEMPTY&lseg
+
+public SETEMPTY&lseg
+SETEMPTY&lseg:
+ jcxz SETEMPTYexit&lseg ; 0-length buffer: do nothing.
+beg_fault_trap SETEMPTYbad&lseg
+ mov es,dx
+ mov byte ptr es:[bx],0 ; jam in a zero terminator
+end_fault_trap
+SETEMPTYexit&lseg:
+ xor ax,ax
+ cwd
+ ret
+
+SETEMPTYbad&lseg:
+ fault_fix_stack
+ jmp short SETEMPTYexit&lseg
+
+endif ; genSETEMPTY&lseg
+
+public VEnd&lseg
+VEnd&lseg:
+
+sEnd %VLseg
+VLseg equ <>
+
+endm ;LAYER_EXPAND
+
+endif ;; IF1
diff --git a/private/mvdm/wow16/inc/logerror.h b/private/mvdm/wow16/inc/logerror.h
new file mode 100644
index 000000000..785efeb91
--- /dev/null
+++ b/private/mvdm/wow16/inc/logerror.h
@@ -0,0 +1,186 @@
+/****************************************************************************\
+ *
+ * LogError() and LogParamError() definitions
+ *
+ * Excerpted from WINDOWS.H, since that file isn't included by GDI & KERNEL.
+\****************************************************************************/
+
+/* If windows.h already included, don't redefine any of this. */
+/* Include the stuff if NOLOGERROR was defined, though. */
+#if (!defined(_INC_WINDOWS) || defined(NOLOGERROR))
+
+#ifdef WINAPI
+void WINAPI LogError(WORD err, void FAR* lpInfo);
+void WINAPI LogParamError(WORD err, FARPROC lpfn, void FAR* param);
+#endif
+
+/****** LogParamError/LogError values */
+
+/* Error modifier bits */
+
+#define ERR_WARNING 0x8000
+#define ERR_PARAM 0x4000
+
+/* Internal error value masks */ /* ;Internal */
+#define ERR_TYPE_MASK 0x0fff /* ;Internal */
+#define ERR_FLAGS_MASK 0xc000 /* ;Internal */
+ /* ;Internal */
+#define ERR_SIZE_MASK 0x3000
+#define ERR_SIZE_SHIFT 12
+#define ERR_BYTE 0x1000
+#define ERR_WORD 0x2000
+#define ERR_DWORD 0x3000
+
+/****** LogParamError() values */
+
+/* Generic parameter values */
+#define ERR_BAD_VALUE 0x6001
+#define ERR_BAD_FLAGS 0x6002
+#define ERR_BAD_INDEX 0x6003
+#define ERR_BAD_DVALUE 0x7004
+#define ERR_BAD_DFLAGS 0x7005
+#define ERR_BAD_DINDEX 0x7006
+#define ERR_BAD_PTR 0x7007
+#define ERR_BAD_FUNC_PTR 0x7008
+#define ERR_BAD_SELECTOR 0x6009
+#define ERR_BAD_STRING_PTR 0x700a
+#define ERR_BAD_HANDLE 0x600b
+
+/* KERNEL parameter errors */
+#define ERR_BAD_HINSTANCE 0x6020
+#define ERR_BAD_HMODULE 0x6021
+#define ERR_BAD_GLOBAL_HANDLE 0x6022
+#define ERR_BAD_LOCAL_HANDLE 0x6023
+#define ERR_BAD_ATOM 0x6024
+#define ERR_BAD_HFILE 0x6025
+
+/* USER parameter errors */
+#define ERR_BAD_HWND 0x6040
+#define ERR_BAD_HMENU 0x6041
+#define ERR_BAD_HCURSOR 0x6042
+#define ERR_BAD_HICON 0x6043
+#define ERR_BAD_HDWP 0x6044
+#define ERR_BAD_CID 0x6045
+#define ERR_BAD_HDRVR 0x6046
+
+/* GDI parameter errors */
+#define ERR_BAD_COORDS 0x7060
+#define ERR_BAD_GDI_OBJECT 0x6061
+#define ERR_BAD_HDC 0x6062
+#define ERR_BAD_HPEN 0x6063
+#define ERR_BAD_HFONT 0x6064
+#define ERR_BAD_HBRUSH 0x6065
+#define ERR_BAD_HBITMAP 0x6066
+#define ERR_BAD_HRGN 0x6067
+#define ERR_BAD_HPALETTE 0x6068
+#define ERR_BAD_HMETAFILE 0x6069
+
+/* Debug fill constants */
+
+#define DBGFILL_ALLOC 0xfd
+#define DBGFILL_FREE 0xfb
+#define DBGFILL_BUFFER 0xf9
+#define DBGFILL_STACK 0xf7
+
+/**** LogError() values */
+
+/* KERNEL errors */
+#define ERR_GALLOC 0x0001 /* GlobalAlloc Failed */
+#define ERR_GREALLOC 0x0002 /* GlobalReAlloc Failed */
+#define ERR_GLOCK 0x0003 /* GlobalLock Failed */
+#define ERR_LALLOC 0x0004 /* LocalAlloc Failed */
+#define ERR_LREALLOC 0x0005 /* LocalReAlloc Failed */
+#define ERR_LLOCK 0x0006 /* LocalLock Failed */
+#define ERR_ALLOCRES 0x0007 /* AllocResource Failed */
+#define ERR_LOCKRES 0x0008 /* LockResource Failed */
+#define ERR_LOADMODULE 0x0009 /* LoadModule failed */
+
+/* USER errors */
+#define ERR_CREATEDLG 0x0040 /* Create Dlg failure due to LoadMenu failure */
+#define ERR_CREATEDLG2 0x0041 /* Create Dlg failure due to CreateWindow Failure */
+#define ERR_REGISTERCLASS 0x0042 /* RegisterClass failure due to Class already registered */
+#define ERR_DCBUSY 0x0043 /* DC Cache is full */
+#define ERR_CREATEWND 0x0044 /* Create Wnd failed due to class not found */
+#define ERR_STRUCEXTRA 0x0045 /* Unallocated Extra space is used */
+#define ERR_LOADSTR 0x0046 /* LoadString() failed */
+#define ERR_LOADMENU 0x0047 /* LoadMenu Failed */
+#define ERR_NESTEDBEGINPAINT 0x0048 /* Nested BeginPaint() calls */
+#define ERR_BADINDEX 0x0049 /* Bad index to Get/Set Class/Window Word/Long */
+#define ERR_CREATEMENU 0x004a /* Error creating menu */
+
+/* GDI errors */
+#define ERR_CREATEDC 0x0080 /* CreateDC/CreateIC etc., failure */
+#define ERR_CREATEMETA 0x0081 /* CreateMetafile failure */
+#define ERR_DELOBJSELECTED 0x0082 /* Bitmap being deleted is selected into DC */
+#define ERR_SELBITMAP 0x0083 /* Bitmap being selected is already selected elsewhere */
+
+/* Debugging information support (DEBUG SYSTEM ONLY) */
+
+#ifdef WINAPI
+
+typedef struct tagWINDEBUGINFO
+{
+ UINT flags;
+ DWORD dwOptions;
+ DWORD dwFilter;
+ char achAllocModule[8];
+ DWORD dwAllocBreak;
+ DWORD dwAllocCount;
+} WINDEBUGINFO;
+
+BOOL WINAPI GetWinDebugInfo(WINDEBUGINFO FAR* lpwdi, UINT flags);
+BOOL WINAPI SetWinDebugInfo(const WINDEBUGINFO FAR* lpwdi);
+
+void FAR _cdecl DebugOutput(UINT flags, LPCSTR lpsz, ...);
+void WINAPI DebugFillBuffer(void FAR* lpb, UINT cb);
+
+#endif
+
+/* WINDEBUGINFO flags values */
+#define WDI_OPTIONS 0x0001
+#define WDI_FILTER 0x0002
+#define WDI_ALLOCBREAK 0x0004
+#define WDI_VALID 0x0007 /* ;Internal */
+
+/* dwOptions values */
+#define DBO_CHECKHEAP 0x0001
+#define DBO_FREEFILL 0x0002
+#define DBO_BUFFERFILL 0x0004
+#define DBO_COMPAT 0x0008
+#define DBO_DISABLEGPTRAPPING 0x0010
+#define DBO_CHECKFREE 0x0020
+#define DBO_RIP_STACK 0x0040
+
+#define DBO_SILENT 0x8000
+
+#define DBO_PARAMBREAK 0x0000 /* ;Internal *//* Obsolete: was 0x4000 */
+#define DBO_TRACEBREAK 0x2000
+#define DBO_WARNINGBREAK 0x1000
+#define DBO_NOERRORBREAK 0x0800
+#define DBO_NOFATALBREAK 0x0400
+#define DBO_TRACEON 0x0000 /* ;Internal *//* Obsolete: was 0x0200 */
+#define DBO_INT3BREAK 0x0100
+
+/* dwFilter values */
+#define DBF_TRACE 0x0000
+#define DBF_WARNING 0x4000
+#define DBF_ERROR 0x8000
+#define DBF_FATAL 0xc000
+#define DBF_SEVMASK 0xc000 /* ;Internal */
+#define DBF_FILTERMASK 0x3fff /* ;Internal */
+#define DBF_INTERNAL 0x0000 /* ;Internal *//* Obsolete: was 0x2000 */
+#define DBF_KERNEL 0x1000
+#define DBF_KRN_MEMMAN 0x0001
+#define DBF_KRN_LOADMODULE 0x0002
+#define DBF_KRN_SEGMENTLOAD 0x0004
+#define DBF_USER 0x0800
+#define DBF_GDI 0x0400
+#define DBF_COMPAT 0x0000 /* ;Internal *//* Obsolete: was 0x0200 */
+#define DBF_LOGERROR 0x0000 /* ;Internal *//* Obsolete: was 0x0100 */
+#define DBF_PARAMERROR 0x0000 /* ;Internal *//* Obsolete: was 0x0080 */
+#define DBF_MMSYSTEM 0x0040
+#define DBF_PENWIN 0x0020
+#define DBF_APPLICATION 0x0010
+#define DBF_DRIVER 0x0008
+
+#endif /* _INC_WINDOWS */
diff --git a/private/mvdm/wow16/inc/logerror.inc b/private/mvdm/wow16/inc/logerror.inc
new file mode 100644
index 000000000..dfbcbdd1c
--- /dev/null
+++ b/private/mvdm/wow16/inc/logerror.inc
@@ -0,0 +1,159 @@
+;---------------------------------------------------------------------------
+; Added for Win 31 style Parameter Validation.
+;
+; Note: This file was copied AS IT IS from Win 31 golden sources and MUST
+; NOT be changed unless it changes in Win 31.
+;
+; History : Added on 14-April-92 by Chandan Chauhan (ChandanC)
+;
+;---------------------------------------------------------------------------
+
+
+;/****** LogParamError/LogError values */
+
+;/* Error modifier bits */
+
+ERR_WARNING equ 08000h
+ERR_PARAM equ 04000h
+
+;/* Internal error value masks */ ;/* ;Internal */
+ERR_TYPE_MASK equ 00fffh ;/* ;Internal */
+ERR_FLAGS_MASK equ 0c000h ;/* ;Internal */
+ ;/* ;Internal */
+ERR_SIZE_MASK equ 03000h
+ERR_SIZE_SHIFT equ 12
+ERR_BYTE equ 01000h
+ERR_WORD equ 02000h
+ERR_DWORD equ 03000h
+
+;/****** LogParamError() values */
+
+;/* Generic parameter values */
+ERR_BAD_VALUE equ 06001h
+ERR_BAD_FLAGS equ 06002h
+ERR_BAD_INDEX equ 06003h
+ERR_BAD_DVALUE equ 07004h
+ERR_BAD_DFLAGS equ 07005h
+ERR_BAD_DINDEX equ 07006h
+ERR_BAD_PTR equ 07007h
+ERR_BAD_FUNC_PTR equ 07008h
+ERR_BAD_SELECTOR equ 06009h
+ERR_BAD_STRING_PTR equ 0700ah
+ERR_BAD_HANDLE equ 0600bh
+
+;/* KERNEL parameter errors */
+ERR_BAD_HINSTANCE equ 06020h
+ERR_BAD_HMODULE equ 06021h
+ERR_BAD_GLOBAL_HANDLE equ 06022h
+ERR_BAD_LOCAL_HANDLE equ 06023h
+ERR_BAD_ATOM equ 06024h
+ERR_BAD_HFILE equ 06025h
+
+;/* USER parameter errors */
+ERR_BAD_HWND equ 06040h
+ERR_BAD_HMENU equ 06041h
+ERR_BAD_HCURSOR equ 06042h
+ERR_BAD_HICON equ 06043h
+ERR_BAD_HDWP equ 06044h
+ERR_BAD_CID equ 06045h
+ERR_BAD_HDRVR equ 06046h
+
+;/* GDI parameter errors */
+ERR_BAD_COORDS equ 07060h
+ERR_BAD_GDI_OBJECT equ 06061h
+ERR_BAD_HDC equ 06062h
+ERR_BAD_HPEN equ 06063h
+ERR_BAD_HFONT equ 06064h
+ERR_BAD_HBRUSH equ 06065h
+ERR_BAD_HBITMAP equ 06066h
+ERR_BAD_HRGN equ 06067h
+ERR_BAD_HPALETTE equ 06068h
+ERR_BAD_HMETAFILE equ 06069h
+
+;/* Debug fill constants */
+
+DBGFILL_ALLOC equ 0fdh
+DBGFILL_FREE equ 0fbh
+DBGFILL_BUFFER equ 0f9h
+DBGFILL_STACK equ 0f7h
+
+;/**** LogError() values */
+
+;/* KERNEL errors */
+ERR_GALLOC equ 00001h ;/* GlobalAlloc Failed */
+ERR_GREALLOC equ 00002h ;/* GlobalReAlloc Failed */
+ERR_GLOCK equ 00003h ;/* GlobalLock Failed */
+ERR_LALLOC equ 00004h ;/* LocalAlloc Failed */
+ERR_LREALLOC equ 00005h ;/* LocalReAlloc Failed */
+ERR_LLOCK equ 00006h ;/* LocalLock Failed */
+ERR_ALLOCRES equ 00007h ;/* AllocResource Failed */
+ERR_LOCKRES equ 00008h ;/* LockResource Failed */
+ERR_LOADMODULE equ 00009h ;/* LoadModule failed */
+
+;/* USER errors */
+ERR_CREATEDLG equ 00040h ;/* Create Dlg failure due to LoadMenu failure */
+ERR_CREATEDLG2 equ 00041h ;/* Create Dlg failure due to CreateWindow Failure */
+ERR_REGISTERCLASS equ 00042h ;/* RegisterClass failure due to Class already registered */
+ERR_DCBUSY equ 00043h ;/* DC Cache is full */
+ERR_CREATEWND equ 00044h ;/* Create Wnd failed due to class not found */
+ERR_STRUCEXTRA equ 00045h ;/* Unallocated Extra space is used */
+ERR_LOADSTR equ 00046h ;/* LoadString() failed */
+ERR_LOADMENU equ 00047h ;/* LoadMenu Failed */
+ERR_NESTEDBEGINPAINT equ 00048h ;/* Nested BeginPaint() calls */
+ERR_BADINDEX equ 00049h ;/* Bad index to Get/Set Class/Window Word/Long */
+ERR_CREATEMENU equ 0004ah ;/* Error creating menu */
+
+;/* GDI errors */
+ERR_CREATEDC equ 00080h ;/* CreateDC/CreateIC etc., failure */
+ERR_CREATEMETA equ 00081h ;/* CreateMetafile failure */
+ERR_DELOBJSELECTED equ 00082h ;/* Bitmap being deleted is selected into DC */
+ERR_SELBITMAP equ 00083h ;/* Bitmap being selected is already selected elsewhere */
+
+;****** DebugOutput definitions
+
+; [Windows] DebugOptions field values
+
+DBO_CHECKHEAP equ 00001h
+
+DBO_BUFFERFILL equ 00004h
+DBO_COMPAT equ 00008h
+DBO_DISABLEGPTRAPPING equ 00010h
+DBO_CHECKFREE equ 00020h
+DBO_RIP_STACK equ 00040h
+
+DBO_SILENT equ 08000h
+
+DBO_PARAMBREAK equ 00000h ; Obsolete: was 04000h
+DBO_TRACEBREAK equ 02000h
+DBO_WARNINGBREAK equ 01000h
+DBO_NOERRORBREAK equ 00800h
+DBO_NOFATALBREAK equ 00400h
+DBO_TRACEON equ 00000h ; Obsolete: was 00200h
+DBO_INT3BREAK equ 00100h
+
+; flags values
+
+DBF_TRACE equ 00000h
+DBF_WARNING equ 04000h
+DBF_ERROR equ 08000h
+DBF_FATAL equ 0c000h
+
+DBF_SEVMASK equ 0c000h
+DBF_FILTERMASK equ 03fffh
+
+; [Windows] DebugFilter and flags values
+
+DBF_INTERNAL equ 00000h ; Obsolete: was 02000h
+DBF_KERNEL equ 01000h
+DBF_KRN_MEMMAN equ 00001h
+DBF_KRN_LOADMODULE equ 00002h
+DBF_KRN_SEGMENTLOAD equ 00004h
+DBF_USER equ 00800h
+DBF_GDI equ 00400h
+DBF_COMPAT equ 00000h ; Obsolete: was 00200h
+DBF_LOGERROR equ 00000h ; Obsolete: was 00100h
+DBF_PARAMERROR equ 00000h ; Obsolete: was 00080h
+DBF_MMSYSTEM equ 00040h
+DBF_PENWIN equ 00020h
+DBF_APPLICATION equ 00010h
+DBF_DRIVER equ 00008h
diff --git a/private/mvdm/wow16/inc/lzdos.h b/private/mvdm/wow16/inc/lzdos.h
new file mode 100644
index 000000000..79b44677d
--- /dev/null
+++ b/private/mvdm/wow16/inc/lzdos.h
@@ -0,0 +1,5 @@
+/* OBSOLETE: Replaced by #define LIB/#include <lzexpand.h> */
+#ifndef LIB
+#define LIB
+#endif
+#include <lzexpand.h>
diff --git a/private/mvdm/wow16/inc/lzexpand.h b/private/mvdm/wow16/inc/lzexpand.h
new file mode 100644
index 000000000..29264d387
--- /dev/null
+++ b/private/mvdm/wow16/inc/lzexpand.h
@@ -0,0 +1,95 @@
+/*****************************************************************************\
+* *
+* lzexpand.h Public interfaces for LZEXPAND.DLL. *
+* *
+* Version 3.10 *
+* *
+* NOTE: windows.h must be included first if LIB is NOT #defined *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+*******************************************************************************
+*
+* #define LIB - To be used with LZEXP?.LIB (default is for LZEXPAND.DLL)
+* NOTE: Not compatible with windows.h if LIB is #defined
+*
+\*****************************************************************************/
+
+#ifndef _INC_LZEXPAND
+#define _INC_LZEXPAND
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/*
+ * If .lib version is being used, declare types used in this file.
+ */
+#ifdef LIB
+
+#define LZAPI _pascal
+
+#ifndef WINAPI /* don't declare if they're already declared */
+#define WINAPI _far _pascal
+#define NEAR _near
+#define FAR _far
+#define PASCAL _pascal
+typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef signed long LONG;
+typedef unsigned long DWORD;
+typedef char far* LPSTR;
+typedef const char far* LPCSTR;
+typedef int HFILE;
+#define OFSTRUCT void /* Not used by the .lib version */
+#endif /* WINAPI */
+
+#else /* LIB */
+
+#define LZAPI _far _pascal
+
+/* If .dll version is being used and we're being included with
+ * the 3.0 windows.h, #define compatible type aliases.
+ * If included with the 3.0 windows.h, #define compatible aliases
+ */
+#ifndef _INC_WINDOWS
+#define UINT WORD
+#define LPCSTR LPSTR
+#define HFILE int
+#endif /* !_INC_WINDOWS */
+
+#endif /* !LIB */
+
+/****** Error return codes ***************************************************/
+
+#define LZERROR_BADINHANDLE (-1) /* invalid input handle */
+#define LZERROR_BADOUTHANDLE (-2) /* invalid output handle */
+#define LZERROR_READ (-3) /* corrupt compressed file format */
+#define LZERROR_WRITE (-4) /* out of space for output file */
+#define LZERROR_GLOBALLOC (-5) /* insufficient memory for LZFile struct */
+#define LZERROR_GLOBLOCK (-6) /* bad global handle */
+#define LZERROR_BADVALUE (-7) /* input parameter out of range */
+#define LZERROR_UNKNOWNALG (-8) /* compression algorithm not recognized */
+
+/****** Public functions *****************************************************/
+
+int LZAPI LZStart(void);
+void LZAPI LZDone(void);
+LONG LZAPI CopyLZFile(HFILE, HFILE);
+LONG LZAPI LZCopy(HFILE, HFILE);
+HFILE LZAPI LZInit(HFILE);
+int LZAPI GetExpandedName(LPCSTR, LPSTR);
+HFILE LZAPI LZOpenFile(LPCSTR, OFSTRUCT FAR*, UINT);
+LONG LZAPI LZSeek(HFILE, LONG, int);
+int LZAPI LZRead(HFILE, void FAR*, int);
+void LZAPI LZClose(HFILE);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _INC_LZEXPAND */
diff --git a/private/mvdm/wow16/inc/memory.h b/private/mvdm/wow16/inc/memory.h
new file mode 100644
index 000000000..4729feee8
--- /dev/null
+++ b/private/mvdm/wow16/inc/memory.h
@@ -0,0 +1,56 @@
+/***
+*memory.h - declarations for buffer (memory) manipulation routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This include file contains the function declarations for the
+* buffer (memory) manipulation routines.
+* [System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+
+/* function prototypes */
+
+void _FAR_ * _FAR_ _cdecl memccpy(void _FAR_ *, const void _FAR_ *,
+ int, unsigned int);
+void _FAR_ * _FAR_ _cdecl memchr(const void _FAR_ *, int, size_t);
+int _FAR_ _cdecl memcmp(const void _FAR_ *, const void _FAR_ *,
+ size_t);
+void _FAR_ * _FAR_ _cdecl memcpy(void _FAR_ *, const void _FAR_ *,
+ size_t);
+int _FAR_ _cdecl memicmp(const void _FAR_ *, const void _FAR_ *,
+ unsigned int);
+void _FAR_ * _FAR_ _cdecl memset(void _FAR_ *, int, size_t);
+void _FAR_ _cdecl movedata(unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int);
+
+
+/* model independent function prototypes */
+
+void _far * _far _cdecl _fmemccpy(void _far *, const void _far *,
+ int, unsigned int);
+void _far * _far _cdecl _fmemchr(const void _far *, int, size_t);
+int _far _cdecl _fmemcmp(const void _far *, const void _far *,
+ size_t);
+void _far * _far _cdecl _fmemcpy(void _far *, const void _far *,
+ size_t);
+int _far _cdecl _fmemicmp(const void _far *, const void _far *,
+ unsigned int);
+void _far * _far _cdecl _fmemset(void _far *, int, size_t);
diff --git a/private/mvdm/wow16/inc/mmddk.h b/private/mvdm/wow16/inc/mmddk.h
new file mode 100644
index 000000000..05be56420
--- /dev/null
+++ b/private/mvdm/wow16/inc/mmddk.h
@@ -0,0 +1,414 @@
+/****************************************************************************/
+/* */
+/* MMDDK.H - Include file for Multimedia Device Development Kit */
+/* */
+/* Note: You must include the WINDOWS.H and MMSYSTEM.H header files */
+/* before including this file. */
+/* */
+/* Copyright (c) 1990-1991, Microsoft Corp. All rights reserved. */
+/* */
+/****************************************************************************/
+
+
+/* If defined, the following flags inhibit inclusion
+ * of the indicated items:
+ *
+ * MMNOMIDIDEV - MIDI support
+ * MMNOWAVEDEV - Waveform support
+ * MMNOAUXDEV - Auxiliary output support
+ * MMNOTIMERDEV - Timer support
+ * MMNOJOYDEV - Joystick support
+ * MMNOMCIDEV - MCI support
+ * MMNOTASKDEV - Task support
+ */
+#ifdef NOMIDIDEV /* ;Internal */
+#define MMNOMIDIDEV /* ;Internal */
+#endif /*ifdef NOMIDIDEV */ /* ;Internal */
+#ifdef NOWAVEDEV /* ;Internal */
+#define MMNOWAVEDEV /* ;Internal */
+#endif /*ifdef NOWAVEDEV */ /* ;Internal */
+#ifdef NOAUXDEV /* ;Internal */
+#define MMNOAUXDEV /* ;Internal */
+#endif /*ifdef NOAUXDEV */ /* ;Internal */
+#ifdef NOTIMERDEV /* ;Internal */
+#define MMNOTIMERDEV /* ;Internal */
+#endif /*ifdef NOTIMERDEV */ /* ;Internal */
+#ifdef NOJOYDEV /* ;Internal */
+#define MMNOJOYDEV /* ;Internal */
+#endif /*ifdef NOJOYDEV */ /* ;Internal */
+#ifdef NOMCIDEV /* ;Internal */
+#define MMNOMCIDEV /* ;Internal */
+#endif /*ifdef NOMCIDEV */ /* ;Internal */
+#ifdef NOTASKDEV /* ;Internal */
+#define MMNOTASKDEV /* ;Internal */
+#endif /*ifdef NOTASKDEV*/ /* ;Internal */
+
+#ifndef _INC_MMDDK
+#define _INC_MMDDK /* #defined if mmddk.h has been included */
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/***************************************************************************
+
+ Helper functions for drivers
+
+***************************************************************************/
+
+#define DCB_NOSWITCH 0x0008 /* don't switch stacks for callback */
+#define DCB_TYPEMASK 0x0007 /* callback type mask */
+#define DCB_NULL 0x0000 /* unknown callback type */
+
+/* flags for wFlags parameter of DriverCallback() */
+#define DCB_WINDOW 0x0001 /* dwCallback is a HWND */
+#define DCB_TASK 0x0002 /* dwCallback is a HTASK */
+#define DCB_FUNCTION 0x0003 /* dwCallback is a FARPROC */
+
+BOOL WINAPI DriverCallback(DWORD dwCallback, UINT uFlags,
+ HANDLE hDevice, UINT uMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2);
+void WINAPI StackEnter(void);
+void WINAPI StackLeave(void);
+
+/* generic prototype for audio device driver entry-point functions */
+/* midMessage(), modMessage(), widMessage(), wodMessage(), auxMessage() */
+typedef DWORD (CALLBACK SOUNDDEVMSGPROC)(UINT uDeviceID, UINT uMessage,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+typedef SOUNDDEVMSGPROC FAR *LPSOUNDDEVMSGPROC;
+
+/* device ID for 386 AUTODMA VxD */
+#define VADMAD_Device_ID 0X0444
+
+#ifndef MMNOWAVEDEV
+/****************************************************************************
+
+ Waveform device driver support
+
+****************************************************************************/
+
+/* maximum number of wave device drivers loaded */
+#define MAXWAVEDRIVERS 10
+
+
+/* waveform input and output device open information structure */
+typedef struct waveopendesc_tag {
+ HWAVE hWave; /* handle */
+ const WAVEFORMAT FAR* lpFormat; /* format of wave data */
+ DWORD dwCallback; /* callback */
+ DWORD dwInstance; /* app's private instance information */
+} WAVEOPENDESC;
+typedef WAVEOPENDESC FAR *LPWAVEOPENDESC;
+
+#define DRVM_USER 0x4000
+
+/*
+ * Message sent by mmsystem to wodMessage(), widMessage(), modMessage(),
+ * and midMessage() when it initializes the wave and midi drivers
+ */
+
+#define DRVM_INIT 100
+#define WODM_INIT DRVM_INIT
+#define WIDM_INIT DRVM_INIT
+#define MODM_INIT DRVM_INIT
+#define MIDM_INIT DRVM_INIT
+#define AUXM_INIT DRVM_INIT
+
+/* messages sent to wodMessage() entry-point function */
+#define WODM_GETNUMDEVS 3
+#define WODM_GETDEVCAPS 4
+#define WODM_OPEN 5
+#define WODM_CLOSE 6
+#define WODM_PREPARE 7
+#define WODM_UNPREPARE 8
+#define WODM_WRITE 9
+#define WODM_PAUSE 10
+#define WODM_RESTART 11
+#define WODM_RESET 12
+#define WODM_GETPOS 13
+#define WODM_GETPITCH 14
+#define WODM_SETPITCH 15
+#define WODM_GETVOLUME 16
+#define WODM_SETVOLUME 17
+#define WODM_GETPLAYBACKRATE 18
+#define WODM_SETPLAYBACKRATE 19
+#define WODM_BREAKLOOP 20
+
+/* messages sent to widMessage() entry-point function */
+#define WIDM_GETNUMDEVS 50
+#define WIDM_GETDEVCAPS 51
+#define WIDM_OPEN 52
+#define WIDM_CLOSE 53
+#define WIDM_PREPARE 54
+#define WIDM_UNPREPARE 55
+#define WIDM_ADDBUFFER 56
+#define WIDM_START 57
+#define WIDM_STOP 58
+#define WIDM_RESET 59
+#define WIDM_GETPOS 60
+
+#endif /*ifndef MMNOWAVEDEV */
+
+
+#ifndef MMNOMIDIDEV
+/****************************************************************************
+
+ MIDI device driver support
+
+****************************************************************************/
+
+/* maximum number of MIDI device drivers loaded */
+#define MAXMIDIDRIVERS 10
+
+/* MIDI input and output device open information structure */
+typedef struct midiopendesc_tag {
+ HMIDI hMidi; /* handle */
+ DWORD dwCallback; /* callback */
+ DWORD dwInstance; /* app's private instance information */
+} MIDIOPENDESC;
+typedef MIDIOPENDESC FAR *LPMIDIOPENDESC;
+
+/* messages sent to modMessage() entry-point function */
+#define MODM_GETNUMDEVS 1
+#define MODM_GETDEVCAPS 2
+#define MODM_OPEN 3
+#define MODM_CLOSE 4
+#define MODM_PREPARE 5
+#define MODM_UNPREPARE 6
+#define MODM_DATA 7
+#define MODM_LONGDATA 8
+#define MODM_RESET 9
+#define MODM_GETVOLUME 10
+#define MODM_SETVOLUME 11
+#define MODM_CACHEPATCHES 12
+#define MODM_CACHEDRUMPATCHES 13
+
+/* messages sent to midMessage() entry-point function */
+#define MIDM_GETNUMDEVS 53
+#define MIDM_GETDEVCAPS 54
+#define MIDM_OPEN 55
+#define MIDM_CLOSE 56
+#define MIDM_PREPARE 57
+#define MIDM_UNPREPARE 58
+#define MIDM_ADDBUFFER 59
+#define MIDM_START 60
+#define MIDM_STOP 61
+#define MIDM_RESET 62
+
+#endif /*ifndef MMNOMIDIDEV */
+
+
+#ifndef MMNOAUXDEV
+/****************************************************************************
+
+ Auxiliary audio device driver support
+
+****************************************************************************/
+
+/* maximum number of auxiliary device drivers loaded */
+#define MAXAUXDRIVERS 10
+
+/* messages sent to auxMessage() entry-point function */
+#define AUXDM_GETNUMDEVS 3
+#define AUXDM_GETDEVCAPS 4
+#define AUXDM_GETVOLUME 5
+#define AUXDM_SETVOLUME 6
+
+#endif /*ifndef MMNOAUXDEV */
+
+
+#ifndef MMNOTIMERDEV
+/****************************************************************************
+
+ Timer device driver support
+
+****************************************************************************/
+
+typedef struct timerevent_tag {
+ UINT wDelay; /* delay required */
+ UINT wResolution; /* resolution required */
+ LPTIMECALLBACK lpFunction; /* ptr to callback function */
+ DWORD dwUser; /* user DWORD */
+ UINT wFlags; /* defines how to program event */
+} TIMEREVENT;
+typedef TIMEREVENT FAR *LPTIMEREVENT;
+
+/* messages sent to tddMessage() function */
+#define TDD_KILLTIMEREVENT DRV_RESERVED+0 /* indices into a table of */
+#define TDD_SETTIMEREVENT DRV_RESERVED+4 /* functions; thus offset by */
+#define TDD_GETSYSTEMTIME DRV_RESERVED+8 /* four each time... */
+#define TDD_GETDEVCAPS DRV_RESERVED+12 /* room for future expansion */
+#define TDD_BEGINMINPERIOD DRV_RESERVED+16 /* room for future expansion */
+#define TDD_ENDMINPERIOD DRV_RESERVED+20 /* room for future expansion */
+
+#endif /*ifndef MMNOTIMERDEV */
+
+
+#ifndef MMNOJOYDEV
+/****************************************************************************
+
+ Joystick device driver support
+
+****************************************************************************/
+
+/* joystick calibration info structure */
+typedef struct joycalibrate_tag {
+ UINT wXbase;
+ UINT wXdelta;
+ UINT wYbase;
+ UINT wYdelta;
+ UINT wZbase;
+ UINT wZdelta;
+} JOYCALIBRATE;
+typedef JOYCALIBRATE FAR *LPJOYCALIBRATE;
+
+/* prototype for joystick message function */
+typedef UINT (CALLBACK JOYDEVMSGPROC)(DWORD dwID, UINT uMessage, LPARAM lParam1, LPARAM lParam2);
+typedef JOYDEVMSGPROC FAR *LPJOYDEVMSGPROC;
+
+/* messages sent to joystick driver's DriverProc() function */
+#define JDD_GETNUMDEVS DRV_RESERVED+0x0001
+#define JDD_GETDEVCAPS DRV_RESERVED+0x0002
+#define JDD_GETPOS DRV_RESERVED+0x0101
+#define JDD_SETCALIBRATION DRV_RESERVED+0x0102
+
+#endif /*ifndef MMNOJOYDEV */
+
+
+#ifndef MMNOMCIDEV
+/****************************************************************************
+
+ MCI device driver support
+
+****************************************************************************/
+
+/* internal MCI messages */
+#define MCI_OPEN_DRIVER 0x0801
+#define MCI_CLOSE_DRIVER 0x0802
+
+#define MAKEMCIRESOURCE(wRet, wRes) MAKELRESULT((wRet), (wRes))
+
+/* string return values only used with MAKEMCIRESOURCE */
+#define MCI_FALSE (MCI_STRING_OFFSET + 19)
+#define MCI_TRUE (MCI_STRING_OFFSET + 20)
+
+/* resource string return values */
+#define MCI_FORMAT_RETURN_BASE MCI_FORMAT_MILLISECONDS_S
+#define MCI_FORMAT_MILLISECONDS_S (MCI_STRING_OFFSET + 21)
+#define MCI_FORMAT_HMS_S (MCI_STRING_OFFSET + 22)
+#define MCI_FORMAT_MSF_S (MCI_STRING_OFFSET + 23)
+#define MCI_FORMAT_FRAMES_S (MCI_STRING_OFFSET + 24)
+#define MCI_FORMAT_SMPTE_24_S (MCI_STRING_OFFSET + 25)
+#define MCI_FORMAT_SMPTE_25_S (MCI_STRING_OFFSET + 26)
+#define MCI_FORMAT_SMPTE_30_S (MCI_STRING_OFFSET + 27)
+#define MCI_FORMAT_SMPTE_30DROP_S (MCI_STRING_OFFSET + 28)
+#define MCI_FORMAT_BYTES_S (MCI_STRING_OFFSET + 29)
+#define MCI_FORMAT_SAMPLES_S (MCI_STRING_OFFSET + 30)
+#define MCI_FORMAT_TMSF_S (MCI_STRING_OFFSET + 31)
+
+#define MCI_VD_FORMAT_TRACK_S (MCI_VD_OFFSET + 5)
+
+#define WAVE_FORMAT_PCM_S (MCI_WAVE_OFFSET + 0)
+#define WAVE_MAPPER_S (MCI_WAVE_OFFSET + 1)
+
+#define MCI_SEQ_MAPPER_S (MCI_SEQ_OFFSET + 5)
+#define MCI_SEQ_FILE_S (MCI_SEQ_OFFSET + 6)
+#define MCI_SEQ_MIDI_S (MCI_SEQ_OFFSET + 7)
+#define MCI_SEQ_SMPTE_S (MCI_SEQ_OFFSET + 8)
+#define MCI_SEQ_FORMAT_SONGPTR_S (MCI_SEQ_OFFSET + 9)
+#define MCI_SEQ_NONE_S (MCI_SEQ_OFFSET + 10)
+#define MIDIMAPPER_S (MCI_SEQ_OFFSET + 11)
+
+/* parameters for internal version of MCI_OPEN message sent from */
+/* mciOpenDevice() to the driver */
+typedef struct {
+ UINT wDeviceID; /* device ID */
+ LPCSTR lpstrParams; /* parameter string for entry in SYSTEM.INI */
+ UINT wCustomCommandTable; /* custom command table (0xFFFF if none) */
+ /* filled in by the driver */
+ UINT wType; /* driver type */
+ /* filled in by the driver */
+} MCI_OPEN_DRIVER_PARMS;
+typedef MCI_OPEN_DRIVER_PARMS FAR * LPMCI_OPEN_DRIVER_PARMS;
+
+/* maximum length of an MCI device type */
+#define MCI_MAX_DEVICE_TYPE_LENGTH 80
+
+/* flags for mciSendCommandInternal() which direct mciSendString() how to */
+/* interpret the return value */
+#define MCI_RESOURCE_RETURNED 0x00010000 /* resource ID */
+#define MCI_COLONIZED3_RETURN 0x00020000 /* colonized ID, 3 bytes data */
+#define MCI_COLONIZED4_RETURN 0x00040000 /* colonized ID, 4 bytes data */
+#define MCI_INTEGER_RETURNED 0x00080000 /* integer conversion needed */
+#define MCI_RESOURCE_DRIVER 0x00100000 /* driver owns returned resource */
+
+/* invalid command table ID */
+#define MCI_NO_COMMAND_TABLE 0xFFFF
+
+/* command table information type tags */
+#define MCI_COMMAND_HEAD 0
+#define MCI_STRING 1
+#define MCI_INTEGER 2
+#define MCI_END_COMMAND 3
+#define MCI_RETURN 4
+#define MCI_FLAG 5
+#define MCI_END_COMMAND_LIST 6
+#define MCI_RECT 7
+#define MCI_CONSTANT 8
+#define MCI_END_CONSTANT 9
+
+/* function prototypes for MCI driver functions */
+DWORD WINAPI mciGetDriverData(UINT uDeviceID);
+BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData);
+UINT WINAPI mciDriverYield(UINT uDeviceID);
+BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID,
+ UINT uStatus);
+UINT WINAPI mciLoadCommandResource(HINSTANCE hInstance,
+ LPCSTR lpResName, UINT uType);
+BOOL WINAPI mciFreeCommandResource(UINT uTable);
+
+#endif /*ifndef MMNOMCIDEV */
+
+
+#ifndef MMNOTASKDEV
+/*****************************************************************************
+
+ Task support
+
+*****************************************************************************/
+
+/* error return values */
+#define TASKERR_NOTASKSUPPORT 1
+#define TASKERR_OUTOFMEMORY 2
+
+/* task support function prototypes */
+#ifdef BUILDDLL /* ;Internal */
+typedef void (FAR PASCAL TASKCALLBACK) (DWORD dwInst); /* ;Internal */
+#else /*ifdef BUILDDLL*/ /* ;Internal */
+typedef void (CALLBACK TASKCALLBACK) (DWORD dwInst);
+#endif /*ifdef BUILDDLL*/ /* ;Internal */
+
+typedef TASKCALLBACK FAR *LPTASKCALLBACK;
+
+UINT WINAPI mmTaskCreate(LPTASKCALLBACK lpfnTaskProc, HTASK FAR * lphTask, DWORD dwInst);
+UINT WINAPI mmTaskBlock(HTASK h);
+BOOL WINAPI mmTaskSignal(HTASK h);
+void WINAPI mmTaskYield(void);
+HTASK WINAPI mmGetCurrentTask(void);
+
+#endif /*ifndef MMNOTASKDEV */
+
+#define MMDDKINC /* ;Internal */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif
+
+#endif /* _INC_MMDDK */
diff --git a/private/mvdm/wow16/inc/mmddk.inc b/private/mvdm/wow16/inc/mmddk.inc
new file mode 100644
index 000000000..efdc04c1e
--- /dev/null
+++ b/private/mvdm/wow16/inc/mmddk.inc
@@ -0,0 +1,337 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MMDDK.INC - Multimedia assembly language structures & constants
+; for the Development Kit
+;
+; Copyright (c) Microsoft Corporation 1990. All rights reserved
+;
+;
+; If defined, the following flags inhibit inclusion of the indicated items:
+;
+; NOTIMERDEV - The Timer Device
+; NOJOYDEV - The Joystick Device
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; If defined, the following flags inhibit inclusion
+; of the indicated items:
+;
+; MMNOMIDIDEV - MIDI support
+; MMNOWAVEDEV - Waveform support
+; MMNOAUXDEV - Auxiliary output support
+; MMNOTIMERDEV - Timer support
+; MMNOJOYDEV - Joystick support
+; MMNOMCIDEV - MCI support
+; MMNOTASKDEV - Task support
+;
+
+OFFSEL STRUC
+Off dw ?
+Sel dw ?
+OFFSEL ENDS
+
+LOHI STRUC
+Lo dw ?
+Hi dw ?
+LOHI ENDS
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Helper functions for drivers
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+DCB_NOSWITCH equ 0008h ; don't switch stacks for callback
+DCB_TYPEMASK equ 0007h ; callback type mask
+DCB_NULL equ 0000h ; unknown callback type
+
+; flags for wFlags parameter of DriverCallback()
+DCB_WINDOW equ 0001h ; dwCallback is a HWND
+DCB_TASK equ 0002h ; dwCallback is a HTASK
+DCB_FUNCTION equ 0003h ; dwCallback is a FARPROC
+
+; device ID for 386 AUTODMA VxD
+VADMAD_Device_ID equ 0444h
+
+ifndef MMNOWAVEDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Waveform device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; maximum number of wave device drivers loaded
+MAXWAVEDRIVERS equ 10
+
+
+; waveform input and output device open information structure
+WAVEOPENDESC struc
+ wod_hWave dw ? ; handle
+ wod_lpFormat dd ? ; format of wave data
+ wod_dwCallback dd ? ; callback
+ wod_dwInstance dd ? ; app's private instance information
+WAVEOPENDESC ends
+
+; message sent by mmsystem to wodMessage(), widMessage(), modMessage(),
+; and midMessage() when it initializes the wave and midi drivers
+
+DRVM_USER equ 4000h
+DRVM_INIT equ 100
+WODM_INIT equ DRVM_INIT
+WIDM_INIT equ DRVM_INIT
+MODM_INIT equ DRVM_INIT
+MIDM_INIT equ DRVM_INIT
+AUXM_INIT equ DRVM_INIT
+
+; messages sent to wodMessage() entry-point function
+WODM_GETNUMDEVS equ 3
+WODM_GETDEVCAPS equ 4
+WODM_OPEN equ 5
+WODM_CLOSE equ 6
+WODM_PREPARE equ 7
+WODM_UNPREPARE equ 8
+WODM_WRITE equ 9
+WODM_PAUSE equ 10
+WODM_RESTART equ 11
+WODM_RESET equ 12
+WODM_GETPOS equ 13
+WODM_GETPITCH equ 14
+WODM_SETPITCH equ 15
+WODM_GETVOLUME equ 16
+WODM_SETVOLUME equ 17
+WODM_GETPLAYBACKRATE equ 18
+WODM_SETPLAYBACKRATE equ 19
+WODM_BREAKLOOP equ 20
+
+; messages sent to widMessage() entry-point function
+WIDM_GETNUMDEVS equ 50
+WIDM_GETDEVCAPS equ 51
+WIDM_OPEN equ 52
+WIDM_CLOSE equ 53
+WIDM_PREPARE equ 54
+WIDM_UNPREPARE equ 55
+WIDM_ADDBUFFER equ 56
+WIDM_START equ 57
+WIDM_STOP equ 58
+WIDM_RESET equ 59
+WIDM_GETPOS equ 60
+
+endif ;ifndef MMNOWAVEDEV
+
+
+ifndef MMNOMIDIDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MIDI device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; maximum number of MIDI device drivers loaded
+MAXMIDIDRIVERS equ 10
+
+; MIDI input and output device open information structure
+MIDIOPENDESC struc
+ mod_hMidi dw ? ; handle
+ mod_dwCallback dd ? ; callback
+ mod_dwInstance dd ? ; app's private instance information
+MIDIOPENDESC ends
+
+; messages sent to modMessage() entry-point function
+MODM_GETNUMDEVS equ 1
+MODM_GETDEVCAPS equ 2
+MODM_OPEN equ 3
+MODM_CLOSE equ 4
+MODM_PREPARE equ 5
+MODM_UNPREPARE equ 6
+MODM_DATA equ 7
+MODM_LONGDATA equ 8
+MODM_RESET equ 9
+MODM_GETVOLUME equ 10
+MODM_SETVOLUME equ 11
+MODM_CACHEPATCHES equ 12
+MODM_CACHEDRUMPATCHES equ 13
+
+; messages sent to midMessage() entry-point function
+MIDM_GETNUMDEVS equ 53
+MIDM_GETDEVCAPS equ 54
+MIDM_OPEN equ 55
+MIDM_CLOSE equ 56
+MIDM_PREPARE equ 57
+MIDM_UNPREPARE equ 58
+MIDM_ADDBUFFER equ 59
+MIDM_START equ 60
+MIDM_STOP equ 61
+MIDM_RESET equ 62
+
+endif ;ifndef MMNOMIDIDEV
+
+
+ifndef MMNOAUXDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Auxiliary audio device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; maximum number of auxiliary device drivers loaded
+MAXAUXDRIVERS equ 10
+
+; messages sent to auxMessage() entry-point function
+AUXDM_GETNUMDEVS equ 3
+AUXDM_GETDEVCAPS equ 4
+AUXDM_GETVOLUME equ 5
+AUXDM_SETVOLUME equ 6
+
+endif ;ifndef MMNOAUXDEV
+
+
+ifndef MMNOTIMERDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Timer device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+TIMEREVENT struc
+ te_wDelay dw ? ; delay required
+ te_wResolution dw ? ; resolution required
+ te_lpFunction dd ? ; ptr to callback function
+ te_dwUser dd ? ; user DWORD
+ te_wFlags dw ? ; defines how to program event
+TIMEREVENT ends
+
+; messages sent to tddMessage() function
+TDD_KILLTIMEREVENT equ DRV_RESERVED+0 ; indices into a table of
+TDD_SETTIMEREVENT equ DRV_RESERVED+4 ; functions; thus offset by
+TDD_GETSYSTEMTIME equ DRV_RESERVED+8 ; four each time...
+TDD_GETDEVCAPS equ DRV_RESERVED+12 ; room for future expansion
+TDD_BEGINMINPERIOD equ DRV_RESERVED+16 ; room for future expansion
+TDD_ENDMINPERIOD equ DRV_RESERVED+20 ; room for future expansion
+
+endif ;ifndef MMNOTIMERDEV
+
+
+ifndef MMNOJOYDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Joystick device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; joystick calibration info structure
+JOYCALIBRATE struc
+ jcal_wXbase dw ?
+ jcal_wXdelta dw ?
+ jcal_wYbase dw ?
+ jcal_wYdelta dw ?
+ jcal_wZbase dw ?
+ jcal_wZdelta dw ?
+JOYCALIBRATE ends
+
+; messages sent to joystick driver's DriverProc() function
+JDD_GETNUMDEVS equ DRV_RESERVED+0001h
+JDD_GETDEVCAPS equ DRV_RESERVED+0002h
+JDD_GETPOS equ DRV_RESERVED+0101h
+JDD_SETCALIBRATION equ DRV_RESERVED+0102h
+
+endif ;ifndef MMNOJOYDEV
+
+
+ifndef MMNOMCIDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MCI device driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; internal MCI messages
+MCI_OPEN_DRIVER equ 0801h
+MCI_CLOSE_DRIVER equ 0802h
+
+MAKEMCIRESOURCE MACRO a,b
+ mov ax,a
+ mov dx,b
+ ENDM
+
+; string return values only used with MAKEMCIRESOURCE
+MCI_FALSE equ (MCI_STRING_OFFSET + 19)
+MCI_TRUE equ (MCI_STRING_OFFSET + 20)
+
+; resource string return values
+MCI_FORMAT_RETURN_BASE equ MCI_FORMAT_MILLISECONDS_S
+MCI_FORMAT_MILLISECONDS_S equ (MCI_STRING_OFFSET + 21)
+MCI_FORMAT_HMS_S equ (MCI_STRING_OFFSET + 22)
+MCI_FORMAT_MSF_S equ (MCI_STRING_OFFSET + 23)
+MCI_FORMAT_FRAMES_S equ (MCI_STRING_OFFSET + 24)
+MCI_FORMAT_SMPTE_24_S equ (MCI_STRING_OFFSET + 25)
+MCI_FORMAT_SMPTE_25_S equ (MCI_STRING_OFFSET + 26)
+MCI_FORMAT_SMPTE_30_S equ (MCI_STRING_OFFSET + 27)
+MCI_FORMAT_SMPTE_30DROP_S equ (MCI_STRING_OFFSET + 28)
+MCI_FORMAT_BYTES_S equ (MCI_STRING_OFFSET + 29)
+MCI_FORMAT_SAMPLES_S equ (MCI_STRING_OFFSET + 30)
+MCI_FORMAT_TMSF_S equ (MCI_STRING_OFFSET + 31)
+
+MCI_VD_FORMAT_TRACK_S equ (MCI_VD_OFFSET + 5)
+
+WAVE_FORMAT_PCM_S equ (MCI_WAVE_OFFSET + 0)
+WAVE_MAPPER_S equ (MCI_WAVE_OFFSET + 1)
+
+MCI_SEQ_MAPPER_S equ (MCI_SEQ_OFFSET + 5)
+MCI_SEQ_FILE_S equ (MCI_SEQ_OFFSET + 6)
+MCI_SEQ_MIDI_S equ (MCI_SEQ_OFFSET + 7)
+MCI_SEQ_SMPTE_S equ (MCI_SEQ_OFFSET + 8)
+MCI_SEQ_FORMAT_SONGPTR_S equ (MCI_SEQ_OFFSET + 9)
+MCI_SEQ_NONE_S equ (MCI_SEQ_OFFSET + 10)
+MIDIMAPPER_S equ (MCI_SEQ_OFFSET + 11)
+
+; parameters for internal version of MCI_OPEN message sent from
+; mciOpenDevice() to the driver
+MCI_OPEN_DRIVER_PARMS struc
+ mciodrv_wDeviceID dw ? ; device ID
+ mciodrv_lpstrParams dw ? ; parameter string for entry in SYSTEM.INI
+ mciodrv_wCustomCommandTable dw ? ; custom command table (0FFFFh if none)
+ ; filled in by the driver
+ mciodrv_wType dw ? ; driver type filled in by the driver
+MCI_OPEN_DRIVER_PARMS ends
+
+; maximum length of an MCI device type
+MCI_MAX_DEVICE_TYPE_LENGTH equ 80
+
+; flags for mciSendCommandInternal() which direct mciSendString() how to
+; interpret the return value
+MCI_RESOURCE_RETURNED equ 00010000h ; resource ID
+MCI_COLONIZED3_RETURN equ 00020000h ; colonized ID, 3 bytes data
+MCI_COLONIZED4_RETURN equ 00040000h ; colonized ID, 4 bytes data
+MCI_INTEGER_RETURNED equ 00080000h ; integer conversion needed
+MCI_RESOURCE_DRIVER equ 00100000h ; driver owns returned resource
+
+; invalid command table ID
+MCI_NO_COMMAND_TABLE equ 0FFFFh
+
+; command table information type tags
+MCI_COMMAND_HEAD equ 0
+MCI_STRING equ 1
+MCI_INTEGER equ 2
+MCI_END_COMMAND equ 3
+MCI_RETURN equ 4
+MCI_FLAG equ 5
+MCI_END_COMMAND_LIST equ 6
+MCI_RECT equ 7
+MCI_CONSTANT equ 8
+MCI_END_CONSTANT equ 9
+
+endif ;ifndef MMNOMCIDEV
+
+
+ifndef MMNOTASKDEV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Task support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; error return values
+TASKERR_NOTASKSUPPORT equ 1
+TASKERR_OUTOFMEMORY equ 2
+
+endif ;ifndef MMNOTASKDEV
diff --git a/private/mvdm/wow16/inc/mmsystem.h b/private/mvdm/wow16/inc/mmsystem.h
new file mode 100644
index 000000000..f951dd297
--- /dev/null
+++ b/private/mvdm/wow16/inc/mmsystem.h
@@ -0,0 +1,1954 @@
+/****************************************************************************/
+/* */
+/* MMSYSTEM.H - Include file for Multimedia APIs */
+/* */
+/* Note: You must include WINDOWS.H before including this file. */
+/* */
+/* Copyright (c) 1990-1992, Microsoft Corp. All rights reserved. */
+/* */
+/****************************************************************************/
+#define BUILDDLL
+
+
+
+/* If defined, the following flags inhibit inclusion
+ * of the indicated items:
+ *
+ * MMNODRV - Installable driver support
+ * MMNOSOUND - Sound support
+ * MMNOWAVE - Waveform support
+ * MMNOMIDI - MIDI support
+ * MMNOAUX - Auxiliary audio support
+ * MMNOTIMER - Timer support
+ * MMNOJOY - Joystick support
+ * MMNOMCI - MCI support
+ * MMNOMMIO - Multimedia file I/O support
+ * MMNOMMSYSTEM - General MMSYSTEM functions
+ */
+
+#ifndef _INC_MMSYSTEM
+#define _INC_MMSYSTEM /* #defined if mmsystem.h has been included */
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifdef BUILDDLL /* ;Internal */
+#undef WINAPI /* ;Internal */
+#define WINAPI _loadds _far _pascal /* ;Internal */
+#undef CALLBACK /* ;Internal */
+#define CALLBACK _loadds _far _pascal /* ;Internal */
+#endif /* ifdef BUILDDLL */ /* ;Internal */
+
+/****************************************************************************
+
+ General constants and data types
+
+****************************************************************************/
+
+/* general constants */
+#define MAXPNAMELEN 32 /* max product name length (including NULL) */
+#define MAXERRORLENGTH 128 /* max error text length (including NULL) */
+
+/* general data types */
+typedef WORD VERSION; /* major (high byte), minor (low byte) */
+
+/* MMTIME data structure */
+typedef struct mmtime_tag {
+ UINT wType; /* indicates the contents of the union */
+ union {
+ DWORD ms; /* milliseconds */
+ DWORD sample; /* samples */
+ DWORD cb; /* byte count */
+ struct { /* SMPTE */
+ BYTE hour; /* hours */
+ BYTE min; /* minutes */
+ BYTE sec; /* seconds */
+ BYTE frame; /* frames */
+ BYTE fps; /* frames per second */
+ BYTE dummy; /* pad */
+ } smpte;
+ struct { /* MIDI */
+ DWORD songptrpos; /* song pointer position */
+ } midi;
+ } u;
+ } MMTIME;
+typedef MMTIME *PMMTIME;
+typedef MMTIME NEAR *NPMMTIME;
+typedef MMTIME FAR *LPMMTIME;
+
+/* types for wType field in MMTIME struct */
+#define TIME_MS 0x0001 /* time in milliseconds */
+#define TIME_SAMPLES 0x0002 /* number of wave samples */
+#define TIME_BYTES 0x0004 /* current byte offset */
+#define TIME_SMPTE 0x0008 /* SMPTE time */
+#define TIME_MIDI 0x0010 /* MIDI time */
+
+
+/****************************************************************************
+
+ Multimedia Extensions Window Messages
+
+****************************************************************************/
+
+#define MM_JOY1MOVE 0x3A0 /* joystick */
+#define MM_JOY2MOVE 0x3A1
+#define MM_JOY1ZMOVE 0x3A2
+#define MM_JOY2ZMOVE 0x3A3
+#define MM_JOY1BUTTONDOWN 0x3B5
+#define MM_JOY2BUTTONDOWN 0x3B6
+#define MM_JOY1BUTTONUP 0x3B7
+#define MM_JOY2BUTTONUP 0x3B8
+
+#define MM_MCINOTIFY 0x3B9 /* MCI */
+#define MM_MCISYSTEM_STRING 0x3CA /* ;Internal */
+
+#define MM_WOM_OPEN 0x3BB /* waveform output */
+#define MM_WOM_CLOSE 0x3BC
+#define MM_WOM_DONE 0x3BD
+
+#define MM_WIM_OPEN 0x3BE /* waveform input */
+#define MM_WIM_CLOSE 0x3BF
+#define MM_WIM_DATA 0x3C0
+
+#define MM_MIM_OPEN 0x3C1 /* MIDI input */
+#define MM_MIM_CLOSE 0x3C2
+#define MM_MIM_DATA 0x3C3
+#define MM_MIM_LONGDATA 0x3C4
+#define MM_MIM_ERROR 0x3C5
+#define MM_MIM_LONGERROR 0x3C6
+
+#define MM_MOM_OPEN 0x3C7 /* MIDI output */
+#define MM_MOM_CLOSE 0x3C8
+#define MM_MOM_DONE 0x3C9
+
+
+/****************************************************************************
+
+ String resource number bases (internal use)
+
+****************************************************************************/
+
+#define MMSYSERR_BASE 0
+#define WAVERR_BASE 32
+#define MIDIERR_BASE 64
+#define TIMERR_BASE 96
+#define JOYERR_BASE 160
+#define MCIERR_BASE 256
+
+#define MCI_STRING_OFFSET 512
+#define MCI_VD_OFFSET 1024
+#define MCI_CD_OFFSET 1088
+#define MCI_WAVE_OFFSET 1152
+#define MCI_SEQ_OFFSET 1216
+
+/****************************************************************************
+
+ General error return values
+
+****************************************************************************/
+
+/* general error return values */
+#define MMSYSERR_NOERROR 0 /* no error */
+#define MMSYSERR_ERROR (MMSYSERR_BASE + 1) /* unspecified error */
+#define MMSYSERR_BADDEVICEID (MMSYSERR_BASE + 2) /* device ID out of range */
+#define MMSYSERR_NOTENABLED (MMSYSERR_BASE + 3) /* driver failed enable */
+#define MMSYSERR_ALLOCATED (MMSYSERR_BASE + 4) /* device already allocated */
+#define MMSYSERR_INVALHANDLE (MMSYSERR_BASE + 5) /* device handle is invalid */
+#define MMSYSERR_NODRIVER (MMSYSERR_BASE + 6) /* no device driver present */
+#define MMSYSERR_NOMEM (MMSYSERR_BASE + 7) /* memory allocation error */
+#define MMSYSERR_NOTSUPPORTED (MMSYSERR_BASE + 8) /* function isn't supported */
+#define MMSYSERR_BADERRNUM (MMSYSERR_BASE + 9) /* error value out of range */
+#define MMSYSERR_INVALFLAG (MMSYSERR_BASE + 10) /* invalid flag passed */
+#define MMSYSERR_INVALPARAM (MMSYSERR_BASE + 11) /* invalid parameter passed */
+#define MMSYSERR_LASTERROR (MMSYSERR_BASE + 11) /* last error in range */
+
+
+#if (WINVER < 0x030a)
+DECLARE_HANDLE(HDRVR);
+#endif /* ifdef WINVER < 0x030a */
+
+#ifndef MMNODRV
+/****************************************************************************
+
+ Installable driver support
+
+****************************************************************************/
+
+#if (WINVER < 0x030a)
+
+/* return values from DriverProc() function */
+#define DRV_CANCEL 0x0000
+#define DRV_OK 0x0001
+#define DRV_RESTART 0x0002
+
+/* Driver messages */
+#define DRV_LOAD 0x0001
+#define DRV_ENABLE 0x0002
+#define DRV_OPEN 0x0003
+#define DRV_CLOSE 0x0004
+#define DRV_DISABLE 0x0005
+#define DRV_FREE 0x0006
+#define DRV_CONFIGURE 0x0007
+#define DRV_QUERYCONFIGURE 0x0008
+#define DRV_INSTALL 0x0009
+#define DRV_REMOVE 0x000A
+#define DRV_RESERVED 0x0800
+#define DRV_USER 0x4000
+
+/* LPARAM of DRV_CONFIGURE message */
+typedef struct tagDRVCONFIGINFO {
+ DWORD dwDCISize;
+ LPCSTR lpszDCISectionName;
+ LPCSTR lpszDCIAliasName;
+} DRVCONFIGINFO;
+typedef DRVCONFIGINFO *PDRVCONFIGINFO;
+typedef DRVCONFIGINFO NEAR *NPDRVCONFIGINFO;
+typedef DRVCONFIGINFO FAR *LPDRVCONFIGINFO;
+
+/* installable driver function prototypes */
+LRESULT WINAPI DrvClose(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2);
+HDRVR WINAPI DrvOpen(LPCSTR szDriverName, LPCSTR szSectionName,
+ LPARAM lParam2);
+LRESULT WINAPI DrvSendMessage(HDRVR hDriver, UINT uMessage,
+ LPARAM lParam1, LPARAM lParam2);
+HINSTANCE WINAPI DrvGetModuleHandle(HDRVR hDriver);
+
+LRESULT WINAPI DrvDefDriverProc(DWORD dwDriverIdentifier, HDRVR driverID,
+ UINT uMessage, LPARAM lParam1, LPARAM lParam2);
+
+#define DefDriverProc DrvDefDriverProc
+
+#endif /* ifdef WINVER < 0x030a */
+
+#if (WINVER >= 0x030a)
+
+#ifdef DEBUG /* ;Internal */
+ LRESULT WINAPI DrvClose(HDRVR,LPARAM,LPARAM); /* ;Internal */
+ HDRVR WINAPI DrvOpen(LPCSTR,LPCSTR,LPARAM); /* ;Internal */
+ #define OpenDriver DrvOpen /* ;Internal */
+ #define CloseDriver DrvClose /* ;Internal */
+#endif /* ;Internal */
+
+/* return values from DriverProc() function */
+#define DRV_CANCEL DRVCNF_CANCEL
+#define DRV_OK DRVCNF_OK
+#define DRV_RESTART DRVCNF_RESTART
+
+#endif /* ifdef WINVER >= 0x030a */
+
+#define DRV_MCI_FIRST DRV_RESERVED
+#define DRV_MCI_LAST (DRV_RESERVED + 0xFFF)
+
+#endif /* ifndef MMNODRV */
+
+
+/****************************************************************************
+
+ Driver callback support
+
+****************************************************************************/
+
+/* flags used with waveOutOpen(), waveInOpen(), midiInOpen(), and */
+/* midiOutOpen() to specify the type of the dwCallback parameter. */
+
+#define CALLBACK_TYPEMASK 0x00070000l /* callback type mask */
+#define CALLBACK_NULL 0x00000000l /* no callback */
+#define CALLBACK_WINDOW 0x00010000l /* dwCallback is a HWND */
+#define CALLBACK_TASK 0x00020000l /* dwCallback is a HTASK */
+#define CALLBACK_FUNCTION 0x00030000l /* dwCallback is a FARPROC */
+
+/* driver callback prototypes */
+#ifdef BUILDDLL /* ;Internal */
+typedef void (FAR PASCAL DRVCALLBACK) (HDRVR h, UINT uMessage, DWORD dwUser, DWORD dw1, DWORD dw2); /* ;Internal */
+#else /* ifdef BUILDDLL */ /* ;Internal */
+typedef void (CALLBACK DRVCALLBACK) (HDRVR h, UINT uMessage, DWORD dwUser, DWORD dw1, DWORD dw2);
+#endif /* ifdef BUILDDLL */ /* ;Internal */
+
+typedef DRVCALLBACK FAR *LPDRVCALLBACK;
+
+/****************************************************************************
+
+ Manufacturer and product IDs
+
+ Used with wMid and wPid fields in WAVEOUTCAPS, WAVEINCAPS,
+ MIDIOUTCAPS, MIDIINCAPS, AUXCAPS, JOYCAPS structures.
+
+****************************************************************************/
+
+/* manufacturer IDs */
+#define MM_MICROSOFT 1 /* Microsoft Corp. */
+
+/* product IDs */
+#define MM_MIDI_MAPPER 1 /* MIDI Mapper */
+#define MM_WAVE_MAPPER 2 /* Wave Mapper */
+
+#define MM_SNDBLST_MIDIOUT 3 /* Sound Blaster MIDI output port */
+#define MM_SNDBLST_MIDIIN 4 /* Sound Blaster MIDI input port */
+#define MM_SNDBLST_SYNTH 5 /* Sound Blaster internal synthesizer */
+#define MM_SNDBLST_WAVEOUT 6 /* Sound Blaster waveform output */
+#define MM_SNDBLST_WAVEIN 7 /* Sound Blaster waveform input */
+
+#define MM_ADLIB 9 /* Ad Lib-compatible synthesizer */
+
+#define MM_MPU401_MIDIOUT 10 /* MPU401-compatible MIDI output port */
+#define MM_MPU401_MIDIIN 11 /* MPU401-compatible MIDI input port */
+
+#define MM_PC_JOYSTICK 12 /* Joystick adapter */
+
+
+#ifndef MMNOMMSYSTEM
+/****************************************************************************
+
+ General MMSYSTEM support
+
+****************************************************************************/
+
+WORD WINAPI mmsystemGetVersion(void);
+void WINAPI OutputDebugStr(LPCSTR);
+
+#endif /* ifndef MMNOMMSYSTEM */
+
+
+#ifndef MMNOSOUND
+/****************************************************************************
+
+ Sound support
+
+****************************************************************************/
+
+BOOL WINAPI sndPlaySound(LPCSTR lpszSoundName, UINT uFlags);
+
+/* flag values for wFlags parameter */
+#define SND_SYNC 0x0000 /* play synchronously (default) */
+#define SND_ASYNC 0x0001 /* play asynchronously */
+#define SND_NODEFAULT 0x0002 /* don't use default sound */
+#define SND_MEMORY 0x0004 /* lpszSoundName points to a memory file */
+#define SND_LOOP 0x0008 /* loop the sound until next sndPlaySound */
+#define SND_NOSTOP 0x0010 /* don't stop any currently playing sound */
+#define SND_VALID 0x001F /* valid flags */ /* ;Internal */
+
+#endif /* ifndef MMNOSOUND */
+
+
+#ifndef MMNOWAVE
+/****************************************************************************
+
+ Waveform audio support
+
+****************************************************************************/
+
+/* waveform audio error return values */
+#define WAVERR_BADFORMAT (WAVERR_BASE + 0) /* unsupported wave format */
+#define WAVERR_STILLPLAYING (WAVERR_BASE + 1) /* still something playing */
+#define WAVERR_UNPREPARED (WAVERR_BASE + 2) /* header not prepared */
+#define WAVERR_SYNC (WAVERR_BASE + 3) /* device is synchronous */
+#define WAVERR_LASTERROR (WAVERR_BASE + 3) /* last error in range */
+
+/* waveform audio data types */
+DECLARE_HANDLE(HWAVE);
+DECLARE_HANDLE(HWAVEIN);
+DECLARE_HANDLE(HWAVEOUT);
+typedef HWAVEIN FAR *LPHWAVEIN;
+typedef HWAVEOUT FAR *LPHWAVEOUT;
+typedef DRVCALLBACK WAVECALLBACK;
+typedef WAVECALLBACK FAR *LPWAVECALLBACK;
+
+/* wave callback messages */
+#define WOM_OPEN MM_WOM_OPEN
+#define WOM_CLOSE MM_WOM_CLOSE
+#define WOM_DONE MM_WOM_DONE
+#define WIM_OPEN MM_WIM_OPEN
+#define WIM_CLOSE MM_WIM_CLOSE
+#define WIM_DATA MM_WIM_DATA
+
+/* device ID for wave device mapper */
+#define WAVE_MAPPER (-1)
+
+/* flags for dwFlags parameter in waveOutOpen() and waveInOpen() */
+#define WAVE_FORMAT_QUERY 0x0001
+#define WAVE_ALLOWSYNC 0x0002
+#define WAVE_VALID 0x0003 /* ;Internal */
+
+/* wave data block header */
+typedef struct wavehdr_tag {
+ LPSTR lpData; /* pointer to locked data buffer */
+ DWORD dwBufferLength; /* length of data buffer */
+ DWORD dwBytesRecorded; /* used for input only */
+ DWORD dwUser; /* for client's use */
+ DWORD dwFlags; /* assorted flags (see defines) */
+ DWORD dwLoops; /* loop control counter */
+ struct wavehdr_tag far *lpNext; /* reserved for driver */
+ DWORD reserved; /* reserved for driver */
+} WAVEHDR;
+typedef WAVEHDR *PWAVEHDR;
+typedef WAVEHDR NEAR *NPWAVEHDR;
+typedef WAVEHDR FAR *LPWAVEHDR;
+
+/* flags for dwFlags field of WAVEHDR */
+#define WHDR_DONE 0x00000001 /* done bit */
+#define WHDR_PREPARED 0x00000002 /* set if this header has been prepared */
+#define WHDR_BEGINLOOP 0x00000004 /* loop start block */
+#define WHDR_ENDLOOP 0x00000008 /* loop end block */
+#define WHDR_INQUEUE 0x00000010 /* reserved for driver */
+#define WHDR_VALID 0x0000001F /* valid flags */ /* ;Internal */
+
+/* waveform output device capabilities structure */
+typedef struct waveoutcaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ VERSION vDriverVersion; /* version of the driver */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+ DWORD dwFormats; /* formats supported */
+ UINT wChannels; /* number of sources supported */
+ DWORD dwSupport; /* functionality supported by driver */
+} WAVEOUTCAPS;
+typedef WAVEOUTCAPS *PWAVEOUTCAPS;
+typedef WAVEOUTCAPS NEAR *NPWAVEOUTCAPS;
+typedef WAVEOUTCAPS FAR *LPWAVEOUTCAPS;
+
+/* flags for dwSupport field of WAVEOUTCAPS */
+#define WAVECAPS_PITCH 0x0001 /* supports pitch control */
+#define WAVECAPS_PLAYBACKRATE 0x0002 /* supports playback rate control */
+#define WAVECAPS_VOLUME 0x0004 /* supports volume control */
+#define WAVECAPS_LRVOLUME 0x0008 /* separate left-right volume control */
+#define WAVECAPS_SYNC 0x0010
+
+/* waveform input device capabilities structure */
+typedef struct waveincaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ VERSION vDriverVersion; /* version of the driver */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+ DWORD dwFormats; /* formats supported */
+ UINT wChannels; /* number of channels supported */
+} WAVEINCAPS;
+typedef WAVEINCAPS *PWAVEINCAPS;
+typedef WAVEINCAPS NEAR *NPWAVEINCAPS;
+typedef WAVEINCAPS FAR *LPWAVEINCAPS;
+
+/* defines for dwFormat field of WAVEINCAPS and WAVEOUTCAPS */
+#define WAVE_INVALIDFORMAT 0x00000000 /* invalid format */
+#define WAVE_FORMAT_1M08 0x00000001 /* 11.025 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_1S08 0x00000002 /* 11.025 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_1M16 0x00000004 /* 11.025 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_1S16 0x00000008 /* 11.025 kHz, Stereo, 16-bit */
+#define WAVE_FORMAT_2M08 0x00000010 /* 22.05 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_2S08 0x00000020 /* 22.05 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_2M16 0x00000040 /* 22.05 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_2S16 0x00000080 /* 22.05 kHz, Stereo, 16-bit */
+#define WAVE_FORMAT_4M08 0x00000100 /* 44.1 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_4S08 0x00000200 /* 44.1 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_4M16 0x00000400 /* 44.1 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_4S16 0x00000800 /* 44.1 kHz, Stereo, 16-bit */
+
+/* general waveform format structure (information common to all formats) */
+typedef struct waveformat_tag {
+ WORD wFormatTag; /* format type */
+ WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */
+ DWORD nSamplesPerSec; /* sample rate */
+ DWORD nAvgBytesPerSec; /* for buffer estimation */
+ WORD nBlockAlign; /* block size of data */
+} WAVEFORMAT;
+typedef WAVEFORMAT *PWAVEFORMAT;
+typedef WAVEFORMAT NEAR *NPWAVEFORMAT;
+typedef WAVEFORMAT FAR *LPWAVEFORMAT;
+
+/* flags for wFormatTag field of WAVEFORMAT */
+#define WAVE_FORMAT_PCM 1
+
+/* specific waveform format structure for PCM data */
+typedef struct pcmwaveformat_tag {
+ WAVEFORMAT wf;
+ WORD wBitsPerSample;
+} PCMWAVEFORMAT;
+typedef PCMWAVEFORMAT *PPCMWAVEFORMAT;
+typedef PCMWAVEFORMAT NEAR *NPPCMWAVEFORMAT;
+typedef PCMWAVEFORMAT FAR *LPPCMWAVEFORMAT;
+
+/* waveform audio function prototypes */
+UINT WINAPI waveOutGetNumDevs(void);
+UINT WINAPI waveOutGetDevCaps(UINT uDeviceID, WAVEOUTCAPS FAR* lpCaps,
+ UINT uSize);
+UINT WINAPI waveOutGetVolume(UINT uDeviceID, DWORD FAR* lpdwVolume);
+UINT WINAPI waveOutSetVolume(UINT uDeviceID, DWORD dwVolume);
+UINT WINAPI waveOutGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
+UINT WINAPI waveOutOpen(HWAVEOUT FAR* lphWaveOut, UINT uDeviceID,
+ const WAVEFORMAT FAR* lpFormat, DWORD dwCallback, DWORD dwInstance, DWORD dwFlags);
+UINT WINAPI waveOutClose(HWAVEOUT hWaveOut);
+UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
+ WAVEHDR FAR* lpWaveOutHdr, UINT uSize);
+UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
+ WAVEHDR FAR* lpWaveOutHdr, UINT uSize);
+UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR FAR* lpWaveOutHdr,
+ UINT uSize);
+UINT WINAPI waveOutPause(HWAVEOUT hWaveOut);
+UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut);
+UINT WINAPI waveOutReset(HWAVEOUT hWaveOut);
+UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut);
+UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, MMTIME FAR* lpInfo,
+ UINT uSize);
+UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, DWORD FAR* lpdwPitch);
+UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dwPitch);
+UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, DWORD FAR* lpdwRate);
+UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dwRate);
+UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT FAR* lpuDeviceID);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, DWORD dw1, DWORD dw2);
+#endif /* ifdef WINVER >= 0x030a */
+
+UINT WINAPI waveInGetNumDevs(void);
+UINT WINAPI waveInGetDevCaps(UINT uDeviceID, WAVEINCAPS FAR* lpCaps,
+ UINT uSize);
+UINT WINAPI waveInGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
+UINT WINAPI waveInOpen(HWAVEIN FAR* lphWaveIn, UINT uDeviceID,
+ const WAVEFORMAT FAR* lpFormat, DWORD dwCallback, DWORD dwInstance, DWORD dwFlags);
+UINT WINAPI waveInClose(HWAVEIN hWaveIn);
+UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn,
+ WAVEHDR FAR* lpWaveInHdr, UINT uSize);
+UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn,
+ WAVEHDR FAR* lpWaveInHdr, UINT uSize);
+UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
+ WAVEHDR FAR* lpWaveInHdr, UINT uSize);
+UINT WINAPI waveInStart(HWAVEIN hWaveIn);
+UINT WINAPI waveInStop(HWAVEIN hWaveIn);
+UINT WINAPI waveInReset(HWAVEIN hWaveIn);
+UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, MMTIME FAR* lpInfo,
+ UINT uSize);
+UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT FAR* lpuDeviceID);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, DWORD dw1, DWORD dw2);
+#endif /* ifdef WINVER >= 0x030a */
+
+#endif /* ifndef MMNOWAVE */
+
+
+#ifndef MMNOMIDI
+/****************************************************************************
+
+ MIDI audio support
+
+****************************************************************************/
+
+/* MIDI error return values */
+#define MIDIERR_UNPREPARED (MIDIERR_BASE + 0) /* header not prepared */
+#define MIDIERR_STILLPLAYING (MIDIERR_BASE + 1) /* still something playing */
+#define MIDIERR_NOMAP (MIDIERR_BASE + 2) /* no current map */
+#define MIDIERR_NOTREADY (MIDIERR_BASE + 3) /* hardware is still busy */
+#define MIDIERR_NODEVICE (MIDIERR_BASE + 4) /* port no longer connected */
+#define MIDIERR_INVALIDSETUP (MIDIERR_BASE + 5) /* invalid setup */
+#define MIDIERR_LASTERROR (MIDIERR_BASE + 5) /* last error in range */
+
+/* MIDI audio data types */
+DECLARE_HANDLE(HMIDI);
+DECLARE_HANDLE(HMIDIIN);
+DECLARE_HANDLE(HMIDIOUT);
+typedef HMIDIIN FAR *LPHMIDIIN;
+typedef HMIDIOUT FAR *LPHMIDIOUT;
+typedef DRVCALLBACK MIDICALLBACK;
+typedef MIDICALLBACK FAR *LPMIDICALLBACK;
+#define MIDIPATCHSIZE 128
+typedef WORD PATCHARRAY[MIDIPATCHSIZE];
+typedef WORD FAR *LPPATCHARRAY;
+typedef WORD KEYARRAY[MIDIPATCHSIZE];
+typedef WORD FAR *LPKEYARRAY;
+
+/* MIDI callback messages */
+#define MIM_OPEN MM_MIM_OPEN
+#define MIM_CLOSE MM_MIM_CLOSE
+#define MIM_DATA MM_MIM_DATA
+#define MIM_LONGDATA MM_MIM_LONGDATA
+#define MIM_ERROR MM_MIM_ERROR
+#define MIM_LONGERROR MM_MIM_LONGERROR
+#define MOM_OPEN MM_MOM_OPEN
+#define MOM_CLOSE MM_MOM_CLOSE
+#define MOM_DONE MM_MOM_DONE
+
+/* device ID for MIDI mapper */
+#define MIDIMAPPER (-1)
+#define MIDI_MAPPER (-1)
+
+/* flags for wFlags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */
+#define MIDI_CACHE_ALL 1
+#define MIDI_CACHE_BESTFIT 2
+#define MIDI_CACHE_QUERY 3
+#define MIDI_UNCACHE 4
+#define MIDI_CACHE_VALID (MIDI_CACHE_ALL | MIDI_CACHE_BESTFIT | MIDI_CACHE_QUERY | MIDI_UNCACHE) /* ;Internal */
+
+/* MIDI output device capabilities structure */
+typedef struct midioutcaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ VERSION vDriverVersion; /* version of the driver */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+ UINT wTechnology; /* type of device */
+ UINT wVoices; /* # of voices (internal synth only) */
+ UINT wNotes; /* max # of notes (internal synth only) */
+ UINT wChannelMask; /* channels used (internal synth only) */
+ DWORD dwSupport; /* functionality supported by driver */
+} MIDIOUTCAPS;
+typedef MIDIOUTCAPS *PMIDIOUTCAPS;
+typedef MIDIOUTCAPS NEAR *NPMIDIOUTCAPS;
+typedef MIDIOUTCAPS FAR *LPMIDIOUTCAPS;
+
+/* flags for wTechnology field of MIDIOUTCAPS structure */
+#define MOD_MIDIPORT 1 /* output port */
+#define MOD_SYNTH 2 /* generic internal synth */
+#define MOD_SQSYNTH 3 /* square wave internal synth */
+#define MOD_FMSYNTH 4 /* FM internal synth */
+#define MOD_MAPPER 5 /* MIDI mapper */
+
+/* flags for dwSupport field of MIDIOUTCAPS structure */
+#define MIDICAPS_VOLUME 0x0001 /* supports volume control */
+#define MIDICAPS_LRVOLUME 0x0002 /* separate left-right volume control */
+#define MIDICAPS_CACHE 0x0004
+
+/* MIDI output device capabilities structure */
+typedef struct midiincaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ VERSION vDriverVersion; /* version of the driver */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+} MIDIINCAPS;
+typedef MIDIINCAPS *PMIDIINCAPS;
+typedef MIDIINCAPS NEAR *NPMIDIINCAPS;
+typedef MIDIINCAPS FAR *LPMIDIINCAPS;
+
+/* MIDI data block header */
+typedef struct midihdr_tag {
+ LPSTR lpData; /* pointer to locked data block */
+ DWORD dwBufferLength; /* length of data in data block */
+ DWORD dwBytesRecorded; /* used for input only */
+ DWORD dwUser; /* for client's use */
+ DWORD dwFlags; /* assorted flags (see defines) */
+ struct midihdr_tag far *lpNext; /* reserved for driver */
+ DWORD reserved; /* reserved for driver */
+} MIDIHDR;
+typedef MIDIHDR *PMIDIHDR;
+typedef MIDIHDR NEAR *NPMIDIHDR;
+typedef MIDIHDR FAR *LPMIDIHDR;
+
+/* flags for dwFlags field of MIDIHDR structure */
+#define MHDR_DONE 0x00000001 /* done bit */
+#define MHDR_PREPARED 0x00000002 /* set if header prepared */
+#define MHDR_INQUEUE 0x00000004 /* reserved for driver */
+#define MHDR_VALID 0x00000007 /* valid flags */ /* ;Internal */
+
+/* MIDI function prototypes */
+UINT WINAPI midiOutGetNumDevs(void);
+UINT WINAPI midiOutGetDevCaps(UINT uDeviceID,
+ MIDIOUTCAPS FAR* lpCaps, UINT uSize);
+UINT WINAPI midiOutGetVolume(UINT uDeviceID, DWORD FAR* lpdwVolume);
+UINT WINAPI midiOutSetVolume(UINT uDeviceID, DWORD dwVolume);
+UINT WINAPI midiOutGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
+UINT WINAPI midiOutOpen(HMIDIOUT FAR* lphMidiOut, UINT uDeviceID,
+ DWORD dwCallback, DWORD dwInstance, DWORD dwFlags);
+UINT WINAPI midiOutClose(HMIDIOUT hMidiOut);
+UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut,
+ MIDIHDR FAR* lpMidiOutHdr, UINT uSize);
+UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut,
+ MIDIHDR FAR* lpMidiOutHdr, UINT uSize);
+UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg);
+UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut,
+ MIDIHDR FAR* lpMidiOutHdr, UINT uSize);
+UINT WINAPI midiOutReset(HMIDIOUT hMidiOut);
+UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut,
+ UINT uBank, WORD FAR* lpwPatchArray, UINT uFlags);
+UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut,
+ UINT uPatch, WORD FAR* lpwKeyArray, UINT uFlags);
+UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT FAR* lpuDeviceID);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, DWORD dw1, DWORD dw2);
+#endif /* ifdef WINVER >= 0x030a */
+
+UINT WINAPI midiInGetNumDevs(void);
+UINT WINAPI midiInGetDevCaps(UINT uDeviceID,
+ LPMIDIINCAPS lpCaps, UINT uSize);
+UINT WINAPI midiInGetErrorText(UINT uError, LPSTR lpText, UINT uSize);
+UINT WINAPI midiInOpen(HMIDIIN FAR* lphMidiIn, UINT uDeviceID,
+ DWORD dwCallback, DWORD dwInstance, DWORD dwFlags);
+UINT WINAPI midiInClose(HMIDIIN hMidiIn);
+UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn,
+ MIDIHDR FAR* lpMidiInHdr, UINT uSize);
+UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn,
+ MIDIHDR FAR* lpMidiInHdr, UINT uSize);
+UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn,
+ MIDIHDR FAR* lpMidiInHdr, UINT uSize);
+UINT WINAPI midiInStart(HMIDIIN hMidiIn);
+UINT WINAPI midiInStop(HMIDIIN hMidiIn);
+UINT WINAPI midiInReset(HMIDIIN hMidiIn);
+UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT FAR* lpuDeviceID);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, DWORD dw1, DWORD dw2);
+#endif /* ifdef WINVER >= 0x030a */
+
+#endif /* ifndef MMNOMIDI */
+
+
+#ifndef MMNOAUX
+/****************************************************************************
+
+ Auxiliary audio support
+
+****************************************************************************/
+
+/* device ID for aux device mapper */
+#define AUX_MAPPER (-1)
+
+/* Auxiliary audio device capabilities structure */
+typedef struct auxcaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ VERSION vDriverVersion; /* version of the driver */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+ UINT wTechnology; /* type of device */
+ DWORD dwSupport; /* functionality supported by driver */
+} AUXCAPS;
+typedef AUXCAPS *PAUXCAPS;
+typedef AUXCAPS NEAR *NPAUXCAPS;
+typedef AUXCAPS FAR *LPAUXCAPS;
+
+/* flags for wTechnology field in AUXCAPS structure */
+#define AUXCAPS_CDAUDIO 1 /* audio from internal CD-ROM drive */
+#define AUXCAPS_AUXIN 2 /* audio from auxiliary input jacks */
+
+/* flags for dwSupport field in AUXCAPS structure */
+#define AUXCAPS_VOLUME 0x0001 /* supports volume control */
+#define AUXCAPS_LRVOLUME 0x0002 /* separate left-right volume control */
+
+/* auxiliary audio function prototypes */
+UINT WINAPI auxGetNumDevs(void);
+UINT WINAPI auxGetDevCaps(UINT uDeviceID, AUXCAPS FAR* lpCaps, UINT uSize);
+UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume);
+UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD FAR* lpdwVolume);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD dw1, DWORD dw2);
+#endif /* ifdef WINVER >= 0x030a */
+
+#endif /* ifndef MMNOAUX */
+
+
+#ifndef MMNOTIMER
+/****************************************************************************
+
+ Timer support
+
+****************************************************************************/
+
+/* timer error return values */
+#define TIMERR_NOERROR (0) /* no error */
+#define TIMERR_NOCANDO (TIMERR_BASE+1) /* request not completed */
+#define TIMERR_STRUCT (TIMERR_BASE+33) /* time struct size */
+
+/* timer data types */
+#ifdef BUILDDLL /* ;Internal */
+typedef void (FAR PASCAL TIMECALLBACK) (UINT uTimerID, UINT uMessage, DWORD dwUser, DWORD dw1, DWORD dw2); /* ;Internal */
+#else /* ifdef BUILDDLL */ /* ;Internal */
+typedef void (CALLBACK TIMECALLBACK) (UINT uTimerID, UINT uMessage, DWORD dwUser, DWORD dw1, DWORD dw2);
+#endif /* ifdef BUILDDLL */ /* ;Internal */
+
+typedef TIMECALLBACK FAR *LPTIMECALLBACK;
+
+/* flags for wFlags parameter of timeSetEvent() function */
+#define TIME_ONESHOT 0 /* program timer for single event */
+#define TIME_PERIODIC 1 /* program for continuous periodic event */
+
+/* timer device capabilities data structure */
+typedef struct timecaps_tag {
+ UINT wPeriodMin; /* minimum period supported */
+ UINT wPeriodMax; /* maximum period supported */
+ } TIMECAPS;
+typedef TIMECAPS *PTIMECAPS;
+typedef TIMECAPS NEAR *NPTIMECAPS;
+typedef TIMECAPS FAR *LPTIMECAPS;
+
+/* timer function prototypes */
+UINT WINAPI timeGetSystemTime(MMTIME FAR* lpTime, UINT uSize);
+DWORD WINAPI timeGetTime(void);
+UINT WINAPI timeSetEvent(UINT uDelay, UINT uResolution,
+ LPTIMECALLBACK lpFunction, DWORD dwUser, UINT uFlags);
+UINT WINAPI timeKillEvent(UINT uTimerID);
+UINT WINAPI timeGetDevCaps(TIMECAPS FAR* lpTimeCaps, UINT uSize);
+UINT WINAPI timeBeginPeriod(UINT uPeriod);
+UINT WINAPI timeEndPeriod(UINT uPeriod);
+
+#endif /* ifndef MMNOTIMER */
+
+
+#ifndef MMNOJOY
+/****************************************************************************
+
+ Joystick support
+
+****************************************************************************/
+
+/* joystick error return values */
+#define JOYERR_NOERROR (0) /* no error */
+#define JOYERR_PARMS (JOYERR_BASE+5) /* bad parameters */
+#define JOYERR_NOCANDO (JOYERR_BASE+6) /* request not completed */
+#define JOYERR_UNPLUGGED (JOYERR_BASE+7) /* joystick is unplugged */
+
+/* constants used with JOYINFO structure and MM_JOY* messages */
+#define JOY_BUTTON1 0x0001
+#define JOY_BUTTON2 0x0002
+#define JOY_BUTTON3 0x0004
+#define JOY_BUTTON4 0x0008
+#define JOY_BUTTON1CHG 0x0100
+#define JOY_BUTTON2CHG 0x0200
+#define JOY_BUTTON3CHG 0x0400
+#define JOY_BUTTON4CHG 0x0800
+
+/* joystick ID constants */
+#define JOYSTICKID1 0
+#define JOYSTICKID2 1
+
+/* joystick device capabilities data structure */
+typedef struct joycaps_tag {
+ UINT wMid; /* manufacturer ID */
+ UINT wPid; /* product ID */
+ char szPname[MAXPNAMELEN]; /* product name (NULL terminated string) */
+ UINT wXmin; /* minimum x position value */
+ UINT wXmax; /* maximum x position value */
+ UINT wYmin; /* minimum y position value */
+ UINT wYmax; /* maximum y position value */
+ UINT wZmin; /* minimum z position value */
+ UINT wZmax; /* maximum z position value */
+ UINT wNumButtons; /* number of buttons */
+ UINT wPeriodMin; /* minimum message period when captured */
+ UINT wPeriodMax; /* maximum message period when captured */
+ } JOYCAPS;
+typedef JOYCAPS *PJOYCAPS;
+typedef JOYCAPS NEAR *NPJOYCAPS;
+typedef JOYCAPS FAR *LPJOYCAPS;
+
+/* joystick information data structure */
+typedef struct joyinfo_tag {
+ UINT wXpos; /* x position */
+ UINT wYpos; /* y position */
+ UINT wZpos; /* z position */
+ UINT wButtons; /* button states */
+ } JOYINFO;
+typedef JOYINFO *PJOYINFO;
+typedef JOYINFO NEAR *NPJOYINFO;
+typedef JOYINFO FAR *LPJOYINFO;
+
+/* joystick function prototypes */
+UINT WINAPI joyGetDevCaps(UINT uJoyID, JOYCAPS FAR* lpCaps, UINT uSize);
+UINT WINAPI joyGetNumDevs(void);
+UINT WINAPI joyGetPos(UINT uJoyID, JOYINFO FAR* lpInfo);
+UINT WINAPI joyGetThreshold(UINT uJoyID, UINT FAR* lpuThreshold);
+UINT WINAPI joyReleaseCapture(UINT uJoyID);
+UINT WINAPI joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod,
+ BOOL bChanged);
+UINT WINAPI joySetThreshold(UINT uJoyID, UINT uThreshold);
+UINT WINAPI joySetCalibration(UINT uJoyID, UINT FAR* puXbase, /* ;Internal */
+ UINT FAR* puXdelta, UINT FAR* puYbase, UINT FAR* puYdelta,/* ;Internal */
+ UINT FAR* puZbase, UINT FAR* puZdelta); /* ;Internal */
+
+#endif /* ifndef MMNOJOY */
+
+
+#ifndef MMNOMMIO
+/****************************************************************************
+
+ Multimedia File I/O support
+
+****************************************************************************/
+
+/* MMIO error return values */
+#define MMIOERR_BASE 256
+#define MMIOERR_FILENOTFOUND (MMIOERR_BASE + 1) /* file not found */
+#define MMIOERR_OUTOFMEMORY (MMIOERR_BASE + 2) /* out of memory */
+#define MMIOERR_CANNOTOPEN (MMIOERR_BASE + 3) /* cannot open */
+#define MMIOERR_CANNOTCLOSE (MMIOERR_BASE + 4) /* cannot close */
+#define MMIOERR_CANNOTREAD (MMIOERR_BASE + 5) /* cannot read */
+#define MMIOERR_CANNOTWRITE (MMIOERR_BASE + 6) /* cannot write */
+#define MMIOERR_CANNOTSEEK (MMIOERR_BASE + 7) /* cannot seek */
+#define MMIOERR_CANNOTEXPAND (MMIOERR_BASE + 8) /* cannot expand file */
+#define MMIOERR_CHUNKNOTFOUND (MMIOERR_BASE + 9) /* chunk not found */
+#define MMIOERR_UNBUFFERED (MMIOERR_BASE + 10) /* file is unbuffered */
+
+/* MMIO constants */
+#define CFSEPCHAR '+' /* compound file name separator char. */
+
+/* MMIO data types */
+typedef DWORD FOURCC; /* a four character code */
+typedef char _huge * HPSTR; /* a huge version of LPSTR */
+DECLARE_HANDLE(HMMIO); /* a handle to an open file */
+typedef LRESULT (CALLBACK MMIOPROC)(LPSTR lpmmioinfo, UINT uMessage,
+ LPARAM lParam1, LPARAM lParam2);
+typedef MMIOPROC FAR *LPMMIOPROC;
+
+/* general MMIO information data structure */
+typedef struct _MMIOINFO
+{
+ /* general fields */
+ DWORD dwFlags; /* general status flags */
+ FOURCC fccIOProc; /* pointer to I/O procedure */
+ LPMMIOPROC pIOProc; /* pointer to I/O procedure */
+ UINT wErrorRet; /* place for error to be returned */
+ HTASK htask; /* alternate local task */
+
+ /* fields maintained by MMIO functions during buffered I/O */
+ LONG cchBuffer; /* size of I/O buffer (or 0L) */
+ HPSTR pchBuffer; /* start of I/O buffer (or NULL) */
+ HPSTR pchNext; /* pointer to next byte to read/write */
+ HPSTR pchEndRead; /* pointer to last valid byte to read */
+ HPSTR pchEndWrite; /* pointer to last byte to write */
+ LONG lBufOffset; /* disk offset of start of buffer */
+
+ /* fields maintained by I/O procedure */
+ LONG lDiskOffset; /* disk offset of next read or write */
+ DWORD adwInfo[3]; /* data specific to type of MMIOPROC */
+
+ /* other fields maintained by MMIO */
+ DWORD dwReserved1; /* reserved for MMIO use */
+ DWORD dwReserved2; /* reserved for MMIO use */
+ HMMIO hmmio; /* handle to open file */
+} MMIOINFO;
+typedef MMIOINFO *PMMIOINFO;
+typedef MMIOINFO NEAR *NPMMIOINFO;
+typedef MMIOINFO FAR *LPMMIOINFO;
+
+/* RIFF chunk information data structure */
+typedef struct _MMCKINFO
+{
+ FOURCC ckid; /* chunk ID */
+ DWORD cksize; /* chunk size */
+ FOURCC fccType; /* form type or list type */
+ DWORD dwDataOffset; /* offset of data portion of chunk */
+ DWORD dwFlags; /* flags used by MMIO functions */
+} MMCKINFO;
+typedef MMCKINFO *PMMCKINFO;
+typedef MMCKINFO NEAR *NPMMCKINFO;
+typedef MMCKINFO FAR *LPMMCKINFO;
+
+/* bit field masks */
+#define MMIO_RWMODE 0x00000003 /* open file for reading/writing/both */
+#define MMIO_SHAREMODE 0x00000070 /* file sharing mode number */
+
+/* constants for dwFlags field of MMIOINFO */
+#define MMIO_CREATE 0x00001000 /* create new file (or truncate file) */
+#define MMIO_PARSE 0x00000100 /* parse new file returning path */
+#define MMIO_DELETE 0x00000200 /* create new file (or truncate file) */
+#define MMIO_EXIST 0x00004000 /* checks for existence of file */
+#define MMIO_ALLOCBUF 0x00010000 /* mmioOpen() should allocate a buffer */
+#define MMIO_GETTEMP 0x00020000 /* mmioOpen() should retrieve temp name */
+
+#define MMIO_DIRTY 0x10000000 /* I/O buffer is dirty */
+
+#define MMIO_OPEN_VALID 0x0003FFFF /* valid flags for mmioOpen */ /* ;Internal */
+#define MMIO_FLUSH_VALID MMIO_EMPTYBUF /* valid flags for mmioFlush */ /* ;Internal */
+#define MMIO_ADVANCE_VALID (MMIO_WRITE | MMIO_READ) /* valid flags for mmioAdvance */ /* ;Internal */
+#define MMIO_FOURCC_VALID MMIO_TOUPPER /* valid flags for mmioStringToFOURCC */ /* ;Internal */
+#define MMIO_DESCEND_VALID (MMIO_FINDCHUNK | MMIO_FINDRIFF | MMIO_FINDLIST) /* ;Internal */
+#define MMIO_CREATE_VALID (MMIO_CREATERIFF | MMIO_CREATELIST) /* ;Internal */
+
+/* read/write mode numbers (bit field MMIO_RWMODE) */
+#define MMIO_READ 0x00000000 /* open file for reading only */
+#define MMIO_WRITE 0x00000001 /* open file for writing only */
+#define MMIO_READWRITE 0x00000002 /* open file for reading and writing */
+
+/* share mode numbers (bit field MMIO_SHAREMODE) */
+#define MMIO_COMPAT 0x00000000 /* compatibility mode */
+#define MMIO_EXCLUSIVE 0x00000010 /* exclusive-access mode */
+#define MMIO_DENYWRITE 0x00000020 /* deny writing to other processes */
+#define MMIO_DENYREAD 0x00000030 /* deny reading to other processes */
+#define MMIO_DENYNONE 0x00000040 /* deny nothing to other processes */
+
+/* various MMIO flags */
+#define MMIO_FHOPEN 0x0010 /* mmioClose: keep file handle open */
+#define MMIO_EMPTYBUF 0x0010 /* mmioFlush: empty the I/O buffer */
+#define MMIO_TOUPPER 0x0010 /* mmioStringToFOURCC: to u-case */
+#define MMIO_INSTALLPROC 0x00010000 /* mmioInstallIOProc: install MMIOProc */
+#define MMIO_GLOBALPROC 0x10000000 /* mmioInstallIOProc: install globally */
+#define MMIO_REMOVEPROC 0x00020000 /* mmioInstallIOProc: remove MMIOProc */
+#define MMIO_FINDPROC 0x00040000 /* mmioInstallIOProc: find an MMIOProc */
+#define MMIO_FINDCHUNK 0x0010 /* mmioDescend: find a chunk by ID */
+#define MMIO_FINDRIFF 0x0020 /* mmioDescend: find a LIST chunk */
+#define MMIO_FINDLIST 0x0040 /* mmioDescend: find a RIFF chunk */
+#define MMIO_CREATERIFF 0x0020 /* mmioCreateChunk: make a LIST chunk */
+#define MMIO_CREATELIST 0x0040 /* mmioCreateChunk: make a RIFF chunk */
+
+#define MMIO_VALIDPROC 0x10070000 /* valid for mmioInstallIOProc */ /* ;Internal */
+
+/* message numbers for MMIOPROC I/O procedure functions */
+#define MMIOM_READ MMIO_READ /* read */
+#define MMIOM_WRITE MMIO_WRITE /* write */
+#define MMIOM_SEEK 2 /* seek to a new position in file */
+#define MMIOM_OPEN 3 /* open file */
+#define MMIOM_CLOSE 4 /* close file */
+#define MMIOM_WRITEFLUSH 5 /* write and flush */
+
+#if (WINVER >= 0x030a)
+#define MMIOM_RENAME 6 /* rename specified file */
+#endif /* ifdef WINVER >= 0x030a */
+
+#define MMIOM_USER 0x8000 /* beginning of user-defined messages */
+
+/* standard four character codes */
+#define FOURCC_RIFF mmioFOURCC('R', 'I', 'F', 'F')
+#define FOURCC_LIST mmioFOURCC('L', 'I', 'S', 'T')
+
+/* four character codes used to identify standard built-in I/O procedures */
+#define FOURCC_DOS mmioFOURCC('D', 'O', 'S', ' ')
+#define FOURCC_MEM mmioFOURCC('M', 'E', 'M', ' ')
+
+/* flags for mmioSeek() */
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* seek to an absolute position */
+#define SEEK_CUR 1 /* seek relative to current position */
+#define SEEK_END 2 /* seek relative to end of file */
+#endif /* ifndef SEEK_SET */
+
+/* other constants */
+#define MMIO_DEFAULTBUFFER 8192 /* default buffer size */
+
+/* MMIO macros */
+#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
+ ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \
+ ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) )
+
+/* MMIO function prototypes */
+FOURCC WINAPI mmioStringToFOURCC(LPCSTR sz, UINT uFlags);
+LPMMIOPROC WINAPI mmioInstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,
+ DWORD dwFlags);
+HMMIO WINAPI mmioOpen(LPSTR szFileName, MMIOINFO FAR* lpmmioinfo,
+ DWORD dwOpenFlags);
+
+#if (WINVER >= 0x030a)
+UINT WINAPI mmioRename(LPCSTR szFileName, LPCSTR szNewFileName,
+ MMIOINFO FAR* lpmmioinfo, DWORD dwRenameFlags);
+#endif /* ifdef WINVER >= 0x030a */
+
+UINT WINAPI mmioClose(HMMIO hmmio, UINT uFlags);
+LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch);
+LONG WINAPI mmioWrite(HMMIO hmmio, const char _huge* pch, LONG cch);
+LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, int iOrigin);
+UINT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO FAR* lpmmioinfo, UINT uFlags);
+UINT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO FAR* lpmmioinfo, UINT uFlags);
+UINT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer,
+ UINT uFlags);
+UINT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags);
+UINT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO FAR* lpmmioinfo, UINT uFlags);
+LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage,
+ LPARAM lParam1, LPARAM lParam2);
+UINT WINAPI mmioDescend(HMMIO hmmio, MMCKINFO FAR* lpck,
+ const MMCKINFO FAR* lpckParent, UINT uFlags);
+UINT WINAPI mmioAscend(HMMIO hmmio, MMCKINFO FAR* lpck, UINT uFlags);
+UINT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO FAR* lpck, UINT uFlags);
+
+#endif /* ifndef MMNOMMIO */
+
+
+#ifndef MMNOMCI
+/****************************************************************************
+
+ MCI support
+
+****************************************************************************/
+
+typedef UINT (CALLBACK *YIELDPROC) (UINT uDeviceID, DWORD dwYieldData);
+
+/* MCI function prototypes */
+DWORD WINAPI mciSendCommand (UINT uDeviceID, UINT uMessage,
+ DWORD dwParam1, DWORD dwParam2);
+DWORD WINAPI mciSendString (LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback);
+UINT WINAPI mciGetDeviceID (LPCSTR lpstrName);
+UINT WINAPI mciGetDeviceIDFromElementID (DWORD dwElementID,
+ LPCSTR lpstrType);
+BOOL WINAPI mciGetErrorString (DWORD wError, LPSTR lpstrBuffer,
+ UINT uLength);
+BOOL WINAPI mciSetYieldProc (UINT uDeviceID, YIELDPROC fpYieldProc,
+ DWORD dwYieldData);
+
+#if (WINVER >= 0x030a)
+HTASK WINAPI mciGetCreatorTask(UINT uDeviceID);
+YIELDPROC WINAPI mciGetYieldProc (UINT uDeviceID, DWORD FAR* lpdwYieldData);
+#endif /* ifdef WINVER >= 0x030a */
+
+#if (WINVER < 0x030a)
+BOOL WINAPI mciExecute (LPCSTR lpstrCommand);
+#endif /* ifdef WINVER < 0x030a */
+
+/* MCI error return values */
+#define MCIERR_INVALID_DEVICE_ID (MCIERR_BASE + 1)
+#define MCIERR_UNRECOGNIZED_KEYWORD (MCIERR_BASE + 3)
+#define MCIERR_UNRECOGNIZED_COMMAND (MCIERR_BASE + 5)
+#define MCIERR_HARDWARE (MCIERR_BASE + 6)
+#define MCIERR_INVALID_DEVICE_NAME (MCIERR_BASE + 7)
+#define MCIERR_OUT_OF_MEMORY (MCIERR_BASE + 8)
+#define MCIERR_DEVICE_OPEN (MCIERR_BASE + 9)
+#define MCIERR_CANNOT_LOAD_DRIVER (MCIERR_BASE + 10)
+#define MCIERR_MISSING_COMMAND_STRING (MCIERR_BASE + 11)
+#define MCIERR_PARAM_OVERFLOW (MCIERR_BASE + 12)
+#define MCIERR_MISSING_STRING_ARGUMENT (MCIERR_BASE + 13)
+#define MCIERR_BAD_INTEGER (MCIERR_BASE + 14)
+#define MCIERR_PARSER_INTERNAL (MCIERR_BASE + 15)
+#define MCIERR_DRIVER_INTERNAL (MCIERR_BASE + 16)
+#define MCIERR_MISSING_PARAMETER (MCIERR_BASE + 17)
+#define MCIERR_UNSUPPORTED_FUNCTION (MCIERR_BASE + 18)
+#define MCIERR_FILE_NOT_FOUND (MCIERR_BASE + 19)
+#define MCIERR_DEVICE_NOT_READY (MCIERR_BASE + 20)
+#define MCIERR_INTERNAL (MCIERR_BASE + 21)
+#define MCIERR_DRIVER (MCIERR_BASE + 22)
+#define MCIERR_CANNOT_USE_ALL (MCIERR_BASE + 23)
+#define MCIERR_MULTIPLE (MCIERR_BASE + 24)
+#define MCIERR_EXTENSION_NOT_FOUND (MCIERR_BASE + 25)
+#define MCIERR_OUTOFRANGE (MCIERR_BASE + 26)
+#define MCIERR_FLAGS_NOT_COMPATIBLE (MCIERR_BASE + 28)
+#define MCIERR_FILE_NOT_SAVED (MCIERR_BASE + 30)
+#define MCIERR_DEVICE_TYPE_REQUIRED (MCIERR_BASE + 31)
+#define MCIERR_DEVICE_LOCKED (MCIERR_BASE + 32)
+#define MCIERR_DUPLICATE_ALIAS (MCIERR_BASE + 33)
+#define MCIERR_BAD_CONSTANT (MCIERR_BASE + 34)
+#define MCIERR_MUST_USE_SHAREABLE (MCIERR_BASE + 35)
+#define MCIERR_MISSING_DEVICE_NAME (MCIERR_BASE + 36)
+#define MCIERR_BAD_TIME_FORMAT (MCIERR_BASE + 37)
+#define MCIERR_NO_CLOSING_QUOTE (MCIERR_BASE + 38)
+#define MCIERR_DUPLICATE_FLAGS (MCIERR_BASE + 39)
+#define MCIERR_INVALID_FILE (MCIERR_BASE + 40)
+#define MCIERR_NULL_PARAMETER_BLOCK (MCIERR_BASE + 41)
+#define MCIERR_UNNAMED_RESOURCE (MCIERR_BASE + 42)
+#define MCIERR_NEW_REQUIRES_ALIAS (MCIERR_BASE + 43)
+#define MCIERR_NOTIFY_ON_AUTO_OPEN (MCIERR_BASE + 44)
+#define MCIERR_NO_ELEMENT_ALLOWED (MCIERR_BASE + 45)
+#define MCIERR_NONAPPLICABLE_FUNCTION (MCIERR_BASE + 46)
+#define MCIERR_ILLEGAL_FOR_AUTO_OPEN (MCIERR_BASE + 47)
+#define MCIERR_FILENAME_REQUIRED (MCIERR_BASE + 48)
+#define MCIERR_EXTRA_CHARACTERS (MCIERR_BASE + 49)
+#define MCIERR_DEVICE_NOT_INSTALLED (MCIERR_BASE + 50)
+#define MCIERR_GET_CD (MCIERR_BASE + 51)
+#define MCIERR_SET_CD (MCIERR_BASE + 52)
+#define MCIERR_SET_DRIVE (MCIERR_BASE + 53)
+#define MCIERR_DEVICE_LENGTH (MCIERR_BASE + 54)
+#define MCIERR_DEVICE_ORD_LENGTH (MCIERR_BASE + 55)
+#define MCIERR_NO_INTEGER (MCIERR_BASE + 56)
+
+#define MCIERR_WAVE_OUTPUTSINUSE (MCIERR_BASE + 64)
+#define MCIERR_WAVE_SETOUTPUTINUSE (MCIERR_BASE + 65)
+#define MCIERR_WAVE_INPUTSINUSE (MCIERR_BASE + 66)
+#define MCIERR_WAVE_SETINPUTINUSE (MCIERR_BASE + 67)
+#define MCIERR_WAVE_OUTPUTUNSPECIFIED (MCIERR_BASE + 68)
+#define MCIERR_WAVE_INPUTUNSPECIFIED (MCIERR_BASE + 69)
+#define MCIERR_WAVE_OUTPUTSUNSUITABLE (MCIERR_BASE + 70)
+#define MCIERR_WAVE_SETOUTPUTUNSUITABLE (MCIERR_BASE + 71)
+#define MCIERR_WAVE_INPUTSUNSUITABLE (MCIERR_BASE + 72)
+#define MCIERR_WAVE_SETINPUTUNSUITABLE (MCIERR_BASE + 73)
+
+#define MCIERR_SEQ_DIV_INCOMPATIBLE (MCIERR_BASE + 80)
+#define MCIERR_SEQ_PORT_INUSE (MCIERR_BASE + 81)
+#define MCIERR_SEQ_PORT_NONEXISTENT (MCIERR_BASE + 82)
+#define MCIERR_SEQ_PORT_MAPNODEVICE (MCIERR_BASE + 83)
+#define MCIERR_SEQ_PORT_MISCERROR (MCIERR_BASE + 84)
+#define MCIERR_SEQ_TIMER (MCIERR_BASE + 85)
+#define MCIERR_SEQ_PORTUNSPECIFIED (MCIERR_BASE + 86)
+#define MCIERR_SEQ_NOMIDIPRESENT (MCIERR_BASE + 87)
+
+#define MCIERR_NO_WINDOW (MCIERR_BASE + 90)
+#define MCIERR_CREATEWINDOW (MCIERR_BASE + 91)
+#define MCIERR_FILE_READ (MCIERR_BASE + 92)
+#define MCIERR_FILE_WRITE (MCIERR_BASE + 93)
+
+/* all custom device driver errors must be >= than this value */
+#define MCIERR_CUSTOM_DRIVER_BASE (MCIERR_BASE + 256)
+
+/* MCI command message identifiers */
+#define MCI_OPEN 0x0803
+#define MCI_CLOSE 0x0804
+#define MCI_ESCAPE 0x0805
+#define MCI_PLAY 0x0806
+#define MCI_SEEK 0x0807
+#define MCI_STOP 0x0808
+#define MCI_PAUSE 0x0809
+#define MCI_INFO 0x080A
+#define MCI_GETDEVCAPS 0x080B
+#define MCI_SPIN 0x080C
+#define MCI_SET 0x080D
+#define MCI_STEP 0x080E
+#define MCI_RECORD 0x080F
+#define MCI_SYSINFO 0x0810
+#define MCI_BREAK 0x0811
+#define MCI_SOUND 0x0812
+#define MCI_SAVE 0x0813
+#define MCI_STATUS 0x0814
+#define MCI_CUE 0x0830
+#define MCI_REALIZE 0x0840
+#define MCI_WINDOW 0x0841
+#define MCI_PUT 0x0842
+#define MCI_WHERE 0x0843
+#define MCI_FREEZE 0x0844
+#define MCI_UNFREEZE 0x0845
+#define MCI_LOAD 0x0850
+#define MCI_CUT 0x0851
+#define MCI_COPY 0x0852
+#define MCI_PASTE 0x0853
+#define MCI_UPDATE 0x0854
+#define MCI_RESUME 0x0855
+#define MCI_DELETE 0x0856
+
+/* all custom MCI command messages must be >= than this value */
+#define MCI_USER_MESSAGES (0x400 + DRV_MCI_FIRST)
+
+
+/* device ID for "all devices" */
+#define MCI_ALL_DEVICE_ID 0xFFFF
+
+/* constants for predefined MCI device types */
+#define MCI_DEVTYPE_VCR (MCI_STRING_OFFSET + 1)
+#define MCI_DEVTYPE_VIDEODISC (MCI_STRING_OFFSET + 2)
+#define MCI_DEVTYPE_OVERLAY (MCI_STRING_OFFSET + 3)
+#define MCI_DEVTYPE_CD_AUDIO (MCI_STRING_OFFSET + 4)
+#define MCI_DEVTYPE_DAT (MCI_STRING_OFFSET + 5)
+#define MCI_DEVTYPE_SCANNER (MCI_STRING_OFFSET + 6)
+#define MCI_DEVTYPE_ANIMATION (MCI_STRING_OFFSET + 7)
+#define MCI_DEVTYPE_DIGITAL_VIDEO (MCI_STRING_OFFSET + 8)
+#define MCI_DEVTYPE_OTHER (MCI_STRING_OFFSET + 9)
+#define MCI_DEVTYPE_WAVEFORM_AUDIO (MCI_STRING_OFFSET + 10)
+#define MCI_DEVTYPE_SEQUENCER (MCI_STRING_OFFSET + 11)
+
+#define MCI_DEVTYPE_FIRST MCI_DEVTYPE_VCR
+#define MCI_DEVTYPE_LAST MCI_DEVTYPE_SEQUENCER
+
+/* return values for 'status mode' command */
+#define MCI_MODE_NOT_READY (MCI_STRING_OFFSET + 12)
+#define MCI_MODE_STOP (MCI_STRING_OFFSET + 13)
+#define MCI_MODE_PLAY (MCI_STRING_OFFSET + 14)
+#define MCI_MODE_RECORD (MCI_STRING_OFFSET + 15)
+#define MCI_MODE_SEEK (MCI_STRING_OFFSET + 16)
+#define MCI_MODE_PAUSE (MCI_STRING_OFFSET + 17)
+#define MCI_MODE_OPEN (MCI_STRING_OFFSET + 18)
+
+/* constants used in 'set time format' and 'status time format' commands */
+#define MCI_FORMAT_MILLISECONDS 0
+#define MCI_FORMAT_HMS 1
+#define MCI_FORMAT_MSF 2
+#define MCI_FORMAT_FRAMES 3
+#define MCI_FORMAT_SMPTE_24 4
+#define MCI_FORMAT_SMPTE_25 5
+#define MCI_FORMAT_SMPTE_30 6
+#define MCI_FORMAT_SMPTE_30DROP 7
+#define MCI_FORMAT_BYTES 8
+#define MCI_FORMAT_SAMPLES 9
+#define MCI_FORMAT_TMSF 10
+
+/* MCI time format conversion macros */
+#define MCI_MSF_MINUTE(msf) ((BYTE)(msf))
+#define MCI_MSF_SECOND(msf) ((BYTE)(((WORD)(msf)) >> 8))
+#define MCI_MSF_FRAME(msf) ((BYTE)((msf)>>16))
+
+#define MCI_MAKE_MSF(m, s, f) ((DWORD)(((BYTE)(m) | \
+ ((WORD)(s)<<8)) | \
+ (((DWORD)(BYTE)(f))<<16)))
+
+#define MCI_TMSF_TRACK(tmsf) ((BYTE)(tmsf))
+#define MCI_TMSF_MINUTE(tmsf) ((BYTE)(((WORD)(tmsf)) >> 8))
+#define MCI_TMSF_SECOND(tmsf) ((BYTE)((tmsf)>>16))
+#define MCI_TMSF_FRAME(tmsf) ((BYTE)((tmsf)>>24))
+
+#define MCI_MAKE_TMSF(t, m, s, f) ((DWORD)(((BYTE)(t) | \
+ ((WORD)(m)<<8)) | \
+ (((DWORD)(BYTE)(s) | \
+ ((WORD)(f)<<8))<<16)))
+
+#define MCI_HMS_HOUR(hms) ((BYTE)(hms))
+#define MCI_HMS_MINUTE(hms) ((BYTE)(((WORD)(hms)) >> 8))
+#define MCI_HMS_SECOND(hms) ((BYTE)((hms)>>16))
+
+#define MCI_MAKE_HMS(h, m, s) ((DWORD)(((BYTE)(h) | \
+ ((WORD)(m)<<8)) | \
+ (((DWORD)(BYTE)(s))<<16)))
+
+
+/* flags for wParam of MM_MCINOTIFY message */
+#define MCI_NOTIFY_SUCCESSFUL 0x0001
+#define MCI_NOTIFY_SUPERSEDED 0x0002
+#define MCI_NOTIFY_ABORTED 0x0004
+#define MCI_NOTIFY_FAILURE 0x0008
+
+
+/* common flags for dwFlags parameter of MCI command messages */
+#define MCI_NOTIFY 0x00000001L
+#define MCI_WAIT 0x00000002L
+#define MCI_FROM 0x00000004L
+#define MCI_TO 0x00000008L
+#define MCI_TRACK 0x00000010L
+
+/* flags for dwFlags parameter of MCI_OPEN command message */
+#define MCI_OPEN_SHAREABLE 0x00000100L
+#define MCI_OPEN_ELEMENT 0x00000200L
+#define MCI_OPEN_ALIAS 0x00000400L
+#define MCI_OPEN_ELEMENT_ID 0x00000800L
+#define MCI_OPEN_TYPE_ID 0x00001000L
+#define MCI_OPEN_TYPE 0x00002000L
+
+/* flags for dwFlags parameter of MCI_SEEK command message */
+#define MCI_SEEK_TO_START 0x00000100L
+#define MCI_SEEK_TO_END 0x00000200L
+
+/* flags for dwFlags parameter of MCI_STATUS command message */
+#define MCI_STATUS_ITEM 0x00000100L
+#define MCI_STATUS_START 0x00000200L
+
+/* flags for dwItem field of the MCI_STATUS_PARMS parameter block */
+#define MCI_STATUS_LENGTH 0x00000001L
+#define MCI_STATUS_POSITION 0x00000002L
+#define MCI_STATUS_NUMBER_OF_TRACKS 0x00000003L
+#define MCI_STATUS_MODE 0x00000004L
+#define MCI_STATUS_MEDIA_PRESENT 0x00000005L
+#define MCI_STATUS_TIME_FORMAT 0x00000006L
+#define MCI_STATUS_READY 0x00000007L
+#define MCI_STATUS_CURRENT_TRACK 0x00000008L
+
+/* flags for dwFlags parameter of MCI_INFO command message */
+#define MCI_INFO_PRODUCT 0x00000100L
+#define MCI_INFO_FILE 0x00000200L
+
+/* flags for dwFlags parameter of MCI_GETDEVCAPS command message */
+#define MCI_GETDEVCAPS_ITEM 0x00000100L
+
+/* flags for dwItem field of the MCI_GETDEVCAPS_PARMS parameter block */
+#define MCI_GETDEVCAPS_CAN_RECORD 0x00000001L
+#define MCI_GETDEVCAPS_HAS_AUDIO 0x00000002L
+#define MCI_GETDEVCAPS_HAS_VIDEO 0x00000003L
+#define MCI_GETDEVCAPS_DEVICE_TYPE 0x00000004L
+#define MCI_GETDEVCAPS_USES_FILES 0x00000005L
+#define MCI_GETDEVCAPS_COMPOUND_DEVICE 0x00000006L
+#define MCI_GETDEVCAPS_CAN_EJECT 0x00000007L
+#define MCI_GETDEVCAPS_CAN_PLAY 0x00000008L
+#define MCI_GETDEVCAPS_CAN_SAVE 0x00000009L
+
+/* flags for dwFlags parameter of MCI_SYSINFO command message */
+#define MCI_SYSINFO_QUANTITY 0x00000100L
+#define MCI_SYSINFO_OPEN 0x00000200L
+#define MCI_SYSINFO_NAME 0x00000400L
+#define MCI_SYSINFO_INSTALLNAME 0x00000800L
+
+/* flags for dwFlags parameter of MCI_SET command message */
+#define MCI_SET_DOOR_OPEN 0x00000100L
+#define MCI_SET_DOOR_CLOSED 0x00000200L
+#define MCI_SET_TIME_FORMAT 0x00000400L
+#define MCI_SET_AUDIO 0x00000800L
+#define MCI_SET_VIDEO 0x00001000L
+#define MCI_SET_ON 0x00002000L
+#define MCI_SET_OFF 0x00004000L
+
+/* flags for dwAudio field of MCI_SET_PARMS or MCI_SEQ_SET_PARMS */
+#define MCI_SET_AUDIO_ALL 0x00000000L
+#define MCI_SET_AUDIO_LEFT 0x00000001L
+#define MCI_SET_AUDIO_RIGHT 0x00000002L
+
+/* flags for dwFlags parameter of MCI_BREAK command message */
+#define MCI_BREAK_KEY 0x00000100L
+#define MCI_BREAK_HWND 0x00000200L
+#define MCI_BREAK_OFF 0x00000400L
+
+/* flags for dwFlags parameter of MCI_RECORD command message */
+#define MCI_RECORD_INSERT 0x00000100L
+#define MCI_RECORD_OVERWRITE 0x00000200L
+
+/* flags for dwFlags parameter of MCI_SOUND command message */
+#define MCI_SOUND_NAME 0x00000100L
+
+/* flags for dwFlags parameter of MCI_SAVE command message */
+#define MCI_SAVE_FILE 0x00000100L
+
+/* flags for dwFlags parameter of MCI_LOAD command message */
+#define MCI_LOAD_FILE 0x00000100L
+
+/* generic parameter block for MCI command messages with no special parameters */
+typedef struct tagMCI_GENERIC_PARMS {
+ DWORD dwCallback;
+} MCI_GENERIC_PARMS;
+typedef MCI_GENERIC_PARMS FAR *LPMCI_GENERIC_PARMS;
+
+/* parameter block for MCI_OPEN command message */
+typedef struct tagMCI_OPEN_PARMS {
+ DWORD dwCallback;
+ UINT wDeviceID;
+ UINT wReserved0;
+ LPCSTR lpstrDeviceType;
+ LPCSTR lpstrElementName;
+ LPCSTR lpstrAlias;
+} MCI_OPEN_PARMS;
+typedef MCI_OPEN_PARMS FAR *LPMCI_OPEN_PARMS;
+
+/* parameter block for MCI_PLAY command message */
+typedef struct tagMCI_PLAY_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrom;
+ DWORD dwTo;
+} MCI_PLAY_PARMS;
+typedef MCI_PLAY_PARMS FAR *LPMCI_PLAY_PARMS;
+
+/* parameter block for MCI_SEEK command message */
+typedef struct tagMCI_SEEK_PARMS {
+ DWORD dwCallback;
+ DWORD dwTo;
+} MCI_SEEK_PARMS;
+typedef MCI_SEEK_PARMS FAR *LPMCI_SEEK_PARMS;
+
+/* parameter block for MCI_STATUS command message */
+typedef struct tagMCI_STATUS_PARMS {
+ DWORD dwCallback;
+ DWORD dwReturn;
+ DWORD dwItem;
+ DWORD dwTrack;
+} MCI_STATUS_PARMS;
+typedef MCI_STATUS_PARMS FAR * LPMCI_STATUS_PARMS;
+
+/* parameter block for MCI_INFO command message */
+typedef struct tagMCI_INFO_PARMS {
+ DWORD dwCallback;
+ LPSTR lpstrReturn;
+ DWORD dwRetSize;
+} MCI_INFO_PARMS;
+typedef MCI_INFO_PARMS FAR * LPMCI_INFO_PARMS;
+
+/* parameter block for MCI_GETDEVCAPS command message */
+typedef struct tagMCI_GETDEVCAPS_PARMS {
+ DWORD dwCallback;
+ DWORD dwReturn;
+ DWORD dwItem;
+} MCI_GETDEVCAPS_PARMS;
+typedef MCI_GETDEVCAPS_PARMS FAR * LPMCI_GETDEVCAPS_PARMS;
+
+/* parameter block for MCI_SYSINFO command message */
+typedef struct tagMCI_SYSINFO_PARMS {
+ DWORD dwCallback;
+ LPSTR lpstrReturn;
+ DWORD dwRetSize;
+ DWORD dwNumber;
+ UINT wDeviceType;
+ UINT wReserved0;
+} MCI_SYSINFO_PARMS;
+typedef MCI_SYSINFO_PARMS FAR * LPMCI_SYSINFO_PARMS;
+
+/* parameter block for MCI_SET command message */
+typedef struct tagMCI_SET_PARMS {
+ DWORD dwCallback;
+ DWORD dwTimeFormat;
+ DWORD dwAudio;
+} MCI_SET_PARMS;
+typedef MCI_SET_PARMS FAR *LPMCI_SET_PARMS;
+
+/* parameter block for MCI_BREAK command message */
+typedef struct tagMCI_BREAK_PARMS {
+ DWORD dwCallback;
+ int nVirtKey;
+ UINT wReserved0;
+ HWND hwndBreak;
+ UINT wReserved1;
+} MCI_BREAK_PARMS;
+typedef MCI_BREAK_PARMS FAR * LPMCI_BREAK_PARMS;
+
+/* parameter block for MCI_SOUND command message */
+typedef struct tagMCI_SOUND_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpstrSoundName;
+} MCI_SOUND_PARMS;
+typedef MCI_SOUND_PARMS FAR * LPMCI_SOUND_PARMS;
+
+/* parameter block for MCI_SAVE command message */
+typedef struct tagMCI_SAVE_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpfilename;
+} MCI_SAVE_PARMS;
+typedef MCI_SAVE_PARMS FAR * LPMCI_SAVE_PARMS;
+
+/* parameter block for MCI_LOAD command message */
+typedef struct tagMCI_LOAD_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpfilename;
+} MCI_LOAD_PARMS;
+typedef MCI_LOAD_PARMS FAR * LPMCI_LOAD_PARMS;
+
+/* parameter block for MCI_RECORD command message */
+typedef struct tagMCI_RECORD_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrom;
+ DWORD dwTo;
+} MCI_RECORD_PARMS;
+typedef MCI_RECORD_PARMS FAR *LPMCI_RECORD_PARMS;
+
+
+/* MCI extensions for videodisc devices */
+
+/* flag for dwReturn field of MCI_STATUS_PARMS */
+/* MCI_STATUS command, (dwItem == MCI_STATUS_MODE) */
+#define MCI_VD_MODE_PARK (MCI_VD_OFFSET + 1)
+
+/* flag for dwReturn field of MCI_STATUS_PARMS */
+/* MCI_STATUS command, (dwItem == MCI_VD_STATUS_MEDIA_TYPE) */
+#define MCI_VD_MEDIA_CLV (MCI_VD_OFFSET + 2)
+#define MCI_VD_MEDIA_CAV (MCI_VD_OFFSET + 3)
+#define MCI_VD_MEDIA_OTHER (MCI_VD_OFFSET + 4)
+
+#define MCI_VD_FORMAT_TRACK 0x4001
+
+/* flags for dwFlags parameter of MCI_PLAY command message */
+#define MCI_VD_PLAY_REVERSE 0x00010000L
+#define MCI_VD_PLAY_FAST 0x00020000L
+#define MCI_VD_PLAY_SPEED 0x00040000L
+#define MCI_VD_PLAY_SCAN 0x00080000L
+#define MCI_VD_PLAY_SLOW 0x00100000L
+
+/* flag for dwFlags parameter of MCI_SEEK command message */
+#define MCI_VD_SEEK_REVERSE 0x00010000L
+
+/* flags for dwItem field of MCI_STATUS_PARMS parameter block */
+#define MCI_VD_STATUS_SPEED 0x00004002L
+#define MCI_VD_STATUS_FORWARD 0x00004003L
+#define MCI_VD_STATUS_MEDIA_TYPE 0x00004004L
+#define MCI_VD_STATUS_SIDE 0x00004005L
+#define MCI_VD_STATUS_DISC_SIZE 0x00004006L
+
+/* flags for dwFlags parameter of MCI_GETDEVCAPS command message */
+#define MCI_VD_GETDEVCAPS_CLV 0x00010000L
+#define MCI_VD_GETDEVCAPS_CAV 0x00020000L
+
+#define MCI_VD_SPIN_UP 0x00010000L
+#define MCI_VD_SPIN_DOWN 0x00020000L
+
+/* flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block */
+#define MCI_VD_GETDEVCAPS_CAN_REVERSE 0x00004002L
+#define MCI_VD_GETDEVCAPS_FAST_RATE 0x00004003L
+#define MCI_VD_GETDEVCAPS_SLOW_RATE 0x00004004L
+#define MCI_VD_GETDEVCAPS_NORMAL_RATE 0x00004005L
+
+/* flags for the dwFlags parameter of MCI_STEP command message */
+#define MCI_VD_STEP_FRAMES 0x00010000L
+#define MCI_VD_STEP_REVERSE 0x00020000L
+
+/* flag for the MCI_ESCAPE command message */
+#define MCI_VD_ESCAPE_STRING 0x00000100L
+
+/* parameter block for MCI_PLAY command message */
+typedef struct tagMCI_VD_PLAY_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrom;
+ DWORD dwTo;
+ DWORD dwSpeed;
+ } MCI_VD_PLAY_PARMS;
+typedef MCI_VD_PLAY_PARMS FAR *LPMCI_VD_PLAY_PARMS;
+
+/* parameter block for MCI_STEP command message */
+typedef struct tagMCI_VD_STEP_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrames;
+} MCI_VD_STEP_PARMS;
+typedef MCI_VD_STEP_PARMS FAR *LPMCI_VD_STEP_PARMS;
+
+/* parameter block for MCI_ESCAPE command message */
+typedef struct tagMCI_VD_ESCAPE_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpstrCommand;
+} MCI_VD_ESCAPE_PARMS;
+typedef MCI_VD_ESCAPE_PARMS FAR *LPMCI_VD_ESCAPE_PARMS;
+
+
+/* MCI extensions for waveform audio devices */
+
+/* flags for the dwFlags parameter of MCI_OPEN command message */
+#define MCI_WAVE_OPEN_BUFFER 0x00010000L
+
+/* flags for the dwFlags parameter of MCI_SET command message */
+#define MCI_WAVE_SET_FORMATTAG 0x00010000L
+#define MCI_WAVE_SET_CHANNELS 0x00020000L
+#define MCI_WAVE_SET_SAMPLESPERSEC 0x00040000L
+#define MCI_WAVE_SET_AVGBYTESPERSEC 0x00080000L
+#define MCI_WAVE_SET_BLOCKALIGN 0x00100000L
+#define MCI_WAVE_SET_BITSPERSAMPLE 0x00200000L
+
+/* flags for the dwFlags parameter of MCI_STATUS, MCI_SET command messages */
+#define MCI_WAVE_INPUT 0x00400000L
+#define MCI_WAVE_OUTPUT 0x00800000L
+
+/* flags for the dwItem field of MCI_STATUS_PARMS parameter block */
+#define MCI_WAVE_STATUS_FORMATTAG 0x00004001L
+#define MCI_WAVE_STATUS_CHANNELS 0x00004002L
+#define MCI_WAVE_STATUS_SAMPLESPERSEC 0x00004003L
+#define MCI_WAVE_STATUS_AVGBYTESPERSEC 0x00004004L
+#define MCI_WAVE_STATUS_BLOCKALIGN 0x00004005L
+#define MCI_WAVE_STATUS_BITSPERSAMPLE 0x00004006L
+#define MCI_WAVE_STATUS_LEVEL 0x00004007L
+
+/* flags for the dwFlags parameter of MCI_SET command message */
+#define MCI_WAVE_SET_ANYINPUT 0x04000000L
+#define MCI_WAVE_SET_ANYOUTPUT 0x08000000L
+
+/* flags for the dwFlags parameter of MCI_GETDEVCAPS command message */
+#define MCI_WAVE_GETDEVCAPS_INPUTS 0x00004001L
+#define MCI_WAVE_GETDEVCAPS_OUTPUTS 0x00004002L
+
+/* parameter block for MCI_OPEN command message */
+typedef struct tagMCI_WAVE_OPEN_PARMS {
+ DWORD dwCallback;
+ UINT wDeviceID;
+ UINT wReserved0;
+ LPCSTR lpstrDeviceType;
+ LPCSTR lpstrElementName;
+ LPCSTR lpstrAlias;
+ DWORD dwBufferSeconds;
+} MCI_WAVE_OPEN_PARMS;
+typedef MCI_WAVE_OPEN_PARMS FAR *LPMCI_WAVE_OPEN_PARMS;
+
+/* parameter block for MCI_DELETE command message */
+typedef struct tagMCI_WAVE_DELETE_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrom;
+ DWORD dwTo;
+} MCI_WAVE_DELETE_PARMS;
+typedef MCI_WAVE_DELETE_PARMS FAR *LPMCI_WAVE_DELETE_PARMS;
+
+/* parameter block for MCI_SET command message */
+typedef struct tagMCI_WAVE_SET_PARMS {
+ DWORD dwCallback;
+ DWORD dwTimeFormat;
+ DWORD dwAudio;
+ UINT wInput;
+ UINT wReserved0;
+ UINT wOutput;
+ UINT wReserved1;
+ UINT wFormatTag;
+ UINT wReserved2;
+ UINT nChannels;
+ UINT wReserved3;
+ DWORD nSamplesPerSec;
+ DWORD nAvgBytesPerSec;
+ UINT nBlockAlign;
+ UINT wReserved4;
+ UINT wBitsPerSample;
+ UINT wReserved5;
+} MCI_WAVE_SET_PARMS;
+typedef MCI_WAVE_SET_PARMS FAR * LPMCI_WAVE_SET_PARMS;
+
+
+/* MCI extensions for MIDI sequencer devices */
+
+/* flags for the dwReturn field of MCI_STATUS_PARMS parameter block */
+/* MCI_STATUS command, (dwItem == MCI_SEQ_STATUS_DIVTYPE) */
+#define MCI_SEQ_DIV_PPQN (0 + MCI_SEQ_OFFSET)
+#define MCI_SEQ_DIV_SMPTE_24 (1 + MCI_SEQ_OFFSET)
+#define MCI_SEQ_DIV_SMPTE_25 (2 + MCI_SEQ_OFFSET)
+#define MCI_SEQ_DIV_SMPTE_30DROP (3 + MCI_SEQ_OFFSET)
+#define MCI_SEQ_DIV_SMPTE_30 (4 + MCI_SEQ_OFFSET)
+
+/* flags for the dwMaster field of MCI_SEQ_SET_PARMS parameter block */
+/* MCI_SET command, (dwFlags == MCI_SEQ_SET_MASTER) */
+#define MCI_SEQ_FORMAT_SONGPTR 0x4001
+#define MCI_SEQ_FILE 0x4002
+#define MCI_SEQ_MIDI 0x4003
+#define MCI_SEQ_SMPTE 0x4004
+#define MCI_SEQ_NONE 65533
+
+/* flags for the dwItem field of MCI_STATUS_PARMS parameter block */
+#define MCI_SEQ_STATUS_TEMPO 0x00004002L
+#define MCI_SEQ_STATUS_PORT 0x00004003L
+#define MCI_SEQ_STATUS_SLAVE 0x00004007L
+#define MCI_SEQ_STATUS_MASTER 0x00004008L
+#define MCI_SEQ_STATUS_OFFSET 0x00004009L
+#define MCI_SEQ_STATUS_DIVTYPE 0x0000400AL
+
+/* flags for the dwFlags parameter of MCI_SET command message */
+#define MCI_SEQ_SET_TEMPO 0x00010000L
+#define MCI_SEQ_SET_PORT 0x00020000L
+#define MCI_SEQ_SET_SLAVE 0x00040000L
+#define MCI_SEQ_SET_MASTER 0x00080000L
+#define MCI_SEQ_SET_OFFSET 0x01000000L
+
+/* parameter block for MCI_SET command message */
+typedef struct tagMCI_SEQ_SET_PARMS {
+ DWORD dwCallback;
+ DWORD dwTimeFormat;
+ DWORD dwAudio;
+ DWORD dwTempo;
+ DWORD dwPort;
+ DWORD dwSlave;
+ DWORD dwMaster;
+ DWORD dwOffset;
+} MCI_SEQ_SET_PARMS;
+typedef MCI_SEQ_SET_PARMS FAR * LPMCI_SEQ_SET_PARMS;
+
+
+/* MCI extensions for animation devices */
+
+/* flags for dwFlags parameter of MCI_OPEN command message */
+#define MCI_ANIM_OPEN_WS 0x00010000L
+#define MCI_ANIM_OPEN_PARENT 0x00020000L
+#define MCI_ANIM_OPEN_NOSTATIC 0x00040000L
+
+/* flags for dwFlags parameter of MCI_PLAY command message */
+#define MCI_ANIM_PLAY_SPEED 0x00010000L
+#define MCI_ANIM_PLAY_REVERSE 0x00020000L
+#define MCI_ANIM_PLAY_FAST 0x00040000L
+#define MCI_ANIM_PLAY_SLOW 0x00080000L
+#define MCI_ANIM_PLAY_SCAN 0x00100000L
+
+/* flags for dwFlags parameter of MCI_STEP command message */
+#define MCI_ANIM_STEP_REVERSE 0x00010000L
+#define MCI_ANIM_STEP_FRAMES 0x00020000L
+
+/* flags for dwItem field of MCI_STATUS_PARMS parameter block */
+#define MCI_ANIM_STATUS_SPEED 0x00004001L
+#define MCI_ANIM_STATUS_FORWARD 0x00004002L
+#define MCI_ANIM_STATUS_HWND 0x00004003L
+#define MCI_ANIM_STATUS_HPAL 0x00004004L
+#define MCI_ANIM_STATUS_STRETCH 0x00004005L
+
+/* flags for the dwFlags parameter of MCI_INFO command message */
+#define MCI_ANIM_INFO_TEXT 0x00010000L
+
+/* flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block */
+#define MCI_ANIM_GETDEVCAPS_CAN_REVERSE 0x00004001L
+#define MCI_ANIM_GETDEVCAPS_FAST_RATE 0x00004002L
+#define MCI_ANIM_GETDEVCAPS_SLOW_RATE 0x00004003L
+#define MCI_ANIM_GETDEVCAPS_NORMAL_RATE 0x00004004L
+#define MCI_ANIM_GETDEVCAPS_PALETTES 0x00004006L
+#define MCI_ANIM_GETDEVCAPS_CAN_STRETCH 0x00004007L
+#define MCI_ANIM_GETDEVCAPS_MAX_WINDOWS 0x00004008L
+
+/* flags for the MCI_REALIZE command message */
+#define MCI_ANIM_REALIZE_NORM 0x00010000L
+#define MCI_ANIM_REALIZE_BKGD 0x00020000L
+
+/* flags for dwFlags parameter of MCI_WINDOW command message */
+#define MCI_ANIM_WINDOW_HWND 0x00010000L
+#define MCI_ANIM_WINDOW_STATE 0x00040000L
+#define MCI_ANIM_WINDOW_TEXT 0x00080000L
+#define MCI_ANIM_WINDOW_ENABLE_STRETCH 0x00100000L
+#define MCI_ANIM_WINDOW_DISABLE_STRETCH 0x00200000L
+
+/* flags for hWnd field of MCI_ANIM_WINDOW_PARMS parameter block */
+/* MCI_WINDOW command message, (dwFlags == MCI_ANIM_WINDOW_HWND) */
+#define MCI_ANIM_WINDOW_DEFAULT 0x00000000L
+
+/* flags for dwFlags parameter of MCI_PUT command message */
+#define MCI_ANIM_RECT 0x00010000L
+#define MCI_ANIM_PUT_SOURCE 0x00020000L
+#define MCI_ANIM_PUT_DESTINATION 0x00040000L
+
+/* flags for dwFlags parameter of MCI_WHERE command message */
+#define MCI_ANIM_WHERE_SOURCE 0x00020000L
+#define MCI_ANIM_WHERE_DESTINATION 0x00040000L
+
+/* flags for dwFlags parameter of MCI_UPDATE command message */
+#define MCI_ANIM_UPDATE_HDC 0x00020000L
+
+/* parameter block for MCI_OPEN command message */
+typedef struct tagMCI_ANIM_OPEN_PARMS {
+ DWORD dwCallback;
+ UINT wDeviceID;
+ UINT wReserved0;
+ LPCSTR lpstrDeviceType;
+ LPCSTR lpstrElementName;
+ LPCSTR lpstrAlias;
+ DWORD dwStyle;
+ HWND hWndParent;
+ UINT wReserved1;
+} MCI_ANIM_OPEN_PARMS;
+typedef MCI_ANIM_OPEN_PARMS FAR *LPMCI_ANIM_OPEN_PARMS;
+
+/* parameter block for MCI_PLAY command message */
+typedef struct tagMCI_ANIM_PLAY_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrom;
+ DWORD dwTo;
+ DWORD dwSpeed;
+} MCI_ANIM_PLAY_PARMS;
+typedef MCI_ANIM_PLAY_PARMS FAR *LPMCI_ANIM_PLAY_PARMS;
+
+/* parameter block for MCI_STEP command message */
+typedef struct tagMCI_ANIM_STEP_PARMS {
+ DWORD dwCallback;
+ DWORD dwFrames;
+} MCI_ANIM_STEP_PARMS;
+typedef MCI_ANIM_STEP_PARMS FAR *LPMCI_ANIM_STEP_PARMS;
+
+/* parameter block for MCI_WINDOW command message */
+typedef struct tagMCI_ANIM_WINDOW_PARMS {
+ DWORD dwCallback;
+ HWND hWnd;
+ UINT wReserved1;
+ UINT nCmdShow;
+ UINT wReserved2;
+ LPCSTR lpstrText;
+} MCI_ANIM_WINDOW_PARMS;
+typedef MCI_ANIM_WINDOW_PARMS FAR * LPMCI_ANIM_WINDOW_PARMS;
+
+/* parameter block for MCI_PUT, MCI_UPDATE, MCI_WHERE command messages */
+typedef struct tagMCI_ANIM_RECT_PARMS {
+ DWORD dwCallback;
+#ifdef MCI_USE_OFFEXT
+ POINT ptOffset;
+ POINT ptExtent;
+#else /* ifdef MCI_USE_OFFEXT */
+ RECT rc;
+#endif /* ifdef MCI_USE_OFFEXT */
+} MCI_ANIM_RECT_PARMS;
+typedef MCI_ANIM_RECT_PARMS FAR * LPMCI_ANIM_RECT_PARMS;
+
+/* parameter block for MCI_UPDATE PARMS */
+typedef struct tagMCI_ANIM_UPDATE_PARMS {
+ DWORD dwCallback;
+ RECT rc;
+ HDC hDC;
+} MCI_ANIM_UPDATE_PARMS;
+typedef MCI_ANIM_UPDATE_PARMS FAR * LPMCI_ANIM_UPDATE_PARMS;
+
+
+/* MCI extensions for video overlay devices */
+
+/* flags for dwFlags parameter of MCI_OPEN command message */
+#define MCI_OVLY_OPEN_WS 0x00010000L
+#define MCI_OVLY_OPEN_PARENT 0x00020000L
+
+/* flags for dwFlags parameter of MCI_STATUS command message */
+#define MCI_OVLY_STATUS_HWND 0x00004001L
+#define MCI_OVLY_STATUS_STRETCH 0x00004002L
+
+/* flags for dwFlags parameter of MCI_INFO command message */
+#define MCI_OVLY_INFO_TEXT 0x00010000L
+
+/* flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block */
+#define MCI_OVLY_GETDEVCAPS_CAN_STRETCH 0x00004001L
+#define MCI_OVLY_GETDEVCAPS_CAN_FREEZE 0x00004002L
+#define MCI_OVLY_GETDEVCAPS_MAX_WINDOWS 0x00004003L
+
+/* flags for dwFlags parameter of MCI_WINDOW command message */
+#define MCI_OVLY_WINDOW_HWND 0x00010000L
+#define MCI_OVLY_WINDOW_STATE 0x00040000L
+#define MCI_OVLY_WINDOW_TEXT 0x00080000L
+#define MCI_OVLY_WINDOW_ENABLE_STRETCH 0x00100000L
+#define MCI_OVLY_WINDOW_DISABLE_STRETCH 0x00200000L
+
+/* flags for hWnd parameter of MCI_OVLY_WINDOW_PARMS parameter block */
+#define MCI_OVLY_WINDOW_DEFAULT 0x00000000L
+
+/* flags for dwFlags parameter of MCI_PUT command message */
+#define MCI_OVLY_RECT 0x00010000L
+#define MCI_OVLY_PUT_SOURCE 0x00020000L
+#define MCI_OVLY_PUT_DESTINATION 0x00040000L
+#define MCI_OVLY_PUT_FRAME 0x00080000L
+#define MCI_OVLY_PUT_VIDEO 0x00100000L
+
+/* flags for dwFlags parameter of MCI_WHERE command message */
+#define MCI_OVLY_WHERE_SOURCE 0x00020000L
+#define MCI_OVLY_WHERE_DESTINATION 0x00040000L
+#define MCI_OVLY_WHERE_FRAME 0x00080000L
+#define MCI_OVLY_WHERE_VIDEO 0x00100000L
+
+/* parameter block for MCI_OPEN command message */
+typedef struct tagMCI_OVLY_OPEN_PARMS {
+ DWORD dwCallback;
+ UINT wDeviceID;
+ UINT wReserved0;
+ LPCSTR lpstrDeviceType;
+ LPCSTR lpstrElementName;
+ LPCSTR lpstrAlias;
+ DWORD dwStyle;
+ HWND hWndParent;
+ UINT wReserved1;
+ } MCI_OVLY_OPEN_PARMS;
+typedef MCI_OVLY_OPEN_PARMS FAR *LPMCI_OVLY_OPEN_PARMS;
+
+/* parameter block for MCI_WINDOW command message */
+typedef struct tagMCI_OVLY_WINDOW_PARMS {
+ DWORD dwCallback;
+ HWND hWnd;
+ UINT wReserved1;
+ UINT nCmdShow;
+ UINT wReserved2;
+ LPCSTR lpstrText;
+} MCI_OVLY_WINDOW_PARMS;
+typedef MCI_OVLY_WINDOW_PARMS FAR * LPMCI_OVLY_WINDOW_PARMS;
+
+/* parameter block for MCI_PUT, MCI_UPDATE, and MCI_WHERE command messages */
+typedef struct tagMCI_OVLY_RECT_PARMS {
+ DWORD dwCallback;
+#ifdef MCI_USE_OFFEXT
+ POINT ptOffset;
+ POINT ptExtent;
+#else /* ifdef MCI_USE_OFFEXT */
+ RECT rc;
+#endif /* ifdef MCI_USE_OFFEXT */
+} MCI_OVLY_RECT_PARMS;
+typedef MCI_OVLY_RECT_PARMS FAR * LPMCI_OVLY_RECT_PARMS;
+
+/* parameter block for MCI_SAVE command message */
+typedef struct tagMCI_OVLY_SAVE_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpfilename;
+ RECT rc;
+} MCI_OVLY_SAVE_PARMS;
+typedef MCI_OVLY_SAVE_PARMS FAR * LPMCI_OVLY_SAVE_PARMS;
+
+/* parameter block for MCI_LOAD command message */
+typedef struct tagMCI_OVLY_LOAD_PARMS {
+ DWORD dwCallback;
+ LPCSTR lpfilename;
+ RECT rc;
+} MCI_OVLY_LOAD_PARMS;
+typedef MCI_OVLY_LOAD_PARMS FAR * LPMCI_OVLY_LOAD_PARMS;
+
+#endif /* ifndef MMNOMCI */
+
+/****************************************************************************
+
+ DISPLAY Driver extensions
+
+****************************************************************************/
+
+#ifndef C1_TRANSPARENT
+ #define CAPS1 94 /* other caps */
+ #define C1_TRANSPARENT 0x0001 /* new raster cap */
+ #define NEWTRANSPARENT 3 /* use with SetBkMode() */
+
+ #define QUERYROPSUPPORT 40 /* use to determine ROP support */
+#endif /* ifndef C1_TRANSPARENT */
+
+/****************************************************************************
+
+ DIB Driver extensions
+
+****************************************************************************/
+
+#define SELECTDIB 41 /* DIB.DRV select dib escape */
+#define DIBINDEX(n) MAKELONG((n),0x10FF)
+
+
+/****************************************************************************
+
+ ScreenSaver support
+
+ The current application will receive a syscommand of SC_SCREENSAVE just
+ before the screen saver is invoked. If the app wishes to prevent a
+ screen save, return non-zero value, otherwise call DefWindowProc().
+
+****************************************************************************/
+
+#ifndef SC_SCREENSAVE
+
+ #define SC_SCREENSAVE 0xF140
+
+#endif /* ifndef SC_SCREENSAVE */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif
+
+#endif /* _INC_MMSYSTEM */
diff --git a/private/mvdm/wow16/inc/mmsystem.inc b/private/mvdm/wow16/inc/mmsystem.inc
new file mode 100644
index 000000000..3e13c6dee
--- /dev/null
+++ b/private/mvdm/wow16/inc/mmsystem.inc
@@ -0,0 +1,1490 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MMSYSTEM.INC - Multimedia assembly language structures & constants
+;
+; Copyright (c) 1990-1992, Microsoft Corp. All rights reserved.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+
+; If defined, the following flags inhibit inclusion
+; of the indicated items:
+;
+; MMNODRV - Installable driver support
+; MMNOSOUND - Sound support
+; MMNOWAVE - Waveform support
+; MMNOMIDI - MIDI support
+; MMNOAUX - Auxiliary audio support
+; MMNOTIMER - Timer support
+; MMNOJOY - Joystick support
+; MMNOMCI - MCI support
+; MMNOMMIO - Multimedia file I/O support
+;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; General constants and data types
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; general constants
+MAXPNAMELEN equ 32 ; max product name length (including NULL)
+MAXERRORLENGTH equ 128 ; max error text length (including NULL)
+
+; MMTIME data structure
+MMTIME struc
+ mmt_wType dw ? ; indicates the contents of the union
+ mmt_TimeUnion dd ? ; union
+MMTIME ends
+
+SMPTE struc
+ smpte_hour db ? ; hours
+ smpte_min db ? ; minutes
+ smpte_sec db ? ; seconds
+ smpte_frame db ? ; frames
+ smpte_fps db ? ; frames per second
+ smpte_reserved db ? ; pad
+SMPTE ends
+
+; types for wType field in MMTIME struct
+TIME_MS equ 0001h ; time in milliseconds
+TIME_SAMPLES equ 0002h ; number of wave samples
+TIME_BYTES equ 0004h ; current byte offset
+TIME_SMPTE equ 0008h ; SMPTE time
+TIME_MIDI equ 0010h ; MIDI time
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Multimedia Extensions Window Messages
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+MM_JOY1MOVE equ 3A0h ; joystick
+MM_JOY2MOVE equ 3A1h
+MM_JOY1ZMOVE equ 3A2h
+MM_JOY2ZMOVE equ 3A3h
+MM_JOY1BUTTONDOWN equ 3B5h
+MM_JOY2BUTTONDOWN equ 3B6h
+MM_JOY1BUTTONUP equ 3B7h
+MM_JOY2BUTTONUP equ 3B8h
+
+MM_MCINOTIFY equ 3B9h ; MCI
+MM_MCISYSTEM_STRING equ 3CAh
+
+MM_WOM_OPEN equ 3BBh ; waveform output
+MM_WOM_CLOSE equ 3BCh
+MM_WOM_DONE equ 3BDh
+
+MM_WIM_OPEN equ 3BEh ; waveform input
+MM_WIM_CLOSE equ 3BFh
+MM_WIM_DATA equ 3C0h
+
+MM_MIM_OPEN equ 3C1h ; MIDI input
+MM_MIM_CLOSE equ 3C2h
+MM_MIM_DATA equ 3C3h
+MM_MIM_LONGDATA equ 3C4h
+MM_MIM_ERROR equ 3C5h
+MM_MIM_LONGERROR equ 3C6h
+
+MM_MOM_OPEN equ 3C7h ; MIDI output
+MM_MOM_CLOSE equ 3C8h
+MM_MOM_DONE equ 3C9h
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; String resource number bases (internal use)
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+MMSYSERR_BASE equ 0
+WAVERR_BASE equ 32
+MIDIERR_BASE equ 64
+TIMERR_BASE equ 96
+JOYERR_BASE equ 160
+MCIERR_BASE equ 256
+
+MCI_STRING_OFFSET equ 512
+MCI_VD_OFFSET equ 1024
+MCI_CD_OFFSET equ 1088
+MCI_WAVE_OFFSET equ 1152
+MCI_SEQ_OFFSET equ 1216
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; General error return values
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; general error return values
+MMSYSERR_NOERROR equ 0 ; no error
+MMSYSERR_ERROR equ (MMSYSERR_BASE + 1) ; unspecified error
+MMSYSERR_BADDEVICEID equ (MMSYSERR_BASE + 2) ; device ID out of range
+MMSYSERR_NOTENABLED equ (MMSYSERR_BASE + 3) ; driver failed enable
+MMSYSERR_ALLOCATED equ (MMSYSERR_BASE + 4) ; device already allocated
+MMSYSERR_INVALHANDLE equ (MMSYSERR_BASE + 5) ; device handle is invalid
+MMSYSERR_NODRIVER equ (MMSYSERR_BASE + 6) ; no device driver present
+MMSYSERR_NOMEM equ (MMSYSERR_BASE + 7) ; memory allocation error
+MMSYSERR_NOTSUPPORTED equ (MMSYSERR_BASE + 8) ; function isn't supported
+MMSYSERR_BADERRNUM equ (MMSYSERR_BASE + 9) ; error value out of range
+MMSYSERR_INVALFLAG equ (MMSYSERR_BASE + 10) ; invalid flags passed
+MMSYSERR_INVALPARAM equ (MMSYSERR_BASE + 11) ; invalid parameter passed
+MMSYSERR_LASTERROR equ (MMSYSERR_BASE + 11) ; last error in range
+
+
+ifndef MMNODRV
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Installable driver support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+DRV_MCI_FIRST equ DRV_RESERVED
+DRV_MCI_LAST equ (DRV_RESERVED + 0FFFh)
+
+endif ;ifndef MMNODRV
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Driver callback support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; flags used with waveOutOpen(), waveInOpen(), midiInOpen(), and
+; midiOutOpen() to specify the type of the dwCallback parameter.
+CALLBACK_TYPEMASK equ 00070000h ; callback type mask
+CALLBACK_NULL equ 00000000h ; no callback
+CALLBACK_WINDOW equ 00010000h ; dwCallback is a HWND
+CALLBACK_TASK equ 00020000h ; dwCallback is a HTASK
+CALLBACK_FUNCTION equ 00030000h ; dwCallback is a FARPROC
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Manufacturer and product IDs
+;
+; Used with wMid and wPid fields in WAVEOUTCAPS, WAVEINCAPS,
+; MIDIOUTCAPS, MIDIINCAPS, AUXCAPS, JOYCAPS structures.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; manufacturer IDs
+MM_MICROSOFT equ 1 ; Microsoft Corp.
+
+; product IDs
+MM_MIDI_MAPPER equ 1 ; MIDI Mapper
+MM_WAVE_MAPPER equ 2 ; Wave Mapper
+
+MM_SNDBLST_MIDIOUT equ 3 ; Sound Blaster MIDI output port
+MM_SNDBLST_MIDIIN equ 4 ; Sound Blaster MIDI input port
+MM_SNDBLST_SYNTH equ 5 ; Sound Blaster internal synthesizer
+MM_SNDBLST_WAVEOUT equ 6 ; Sound Blaster waveform output
+MM_SNDBLST_WAVEIN equ 7 ; Sound Blaster waveform input
+
+MM_ADLIB equ 9 ; Ad Lib-compatible synthesizer
+
+MM_MPU401_MIDIOUT equ 10 ; MPU401-compatible MIDI output port
+MM_MPU401_MIDIIN equ 11 ; MPU401-compatible MIDI input port
+
+MM_PC_JOYSTICK equ 12 ; Joystick adapter
+
+
+ifndef MMNOSOUND
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Sound support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; flag values for wFlags parameter
+SND_SYNC equ 0000h ; play synchronously (default)
+SND_ASYNC equ 0001h ; play asynchronously
+SND_NODEFAULT equ 0002h ; don't use default sound
+SND_MEMORY equ 0004h ; lpszSoundName points to a memory file
+SND_LOOP equ 0008h ; loop the sound until next sndPlaySound
+SND_NOSTOP equ 0010h ; don't stop any currently playing sound
+SND_VALID equ 001Fh ;Internal
+
+endif ;ifndef MMNOSOUND
+
+
+ifndef MMNOWAVE
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Waveform audio support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; waveform audio error return values
+WAVERR_BADFORMAT equ (WAVERR_BASE + 0) ; unsupported wave format
+WAVERR_STILLPLAYING equ (WAVERR_BASE + 1) ; still something playing
+WAVERR_UNPREPARED equ (WAVERR_BASE + 2) ; header not prepared
+WAVERR_SYNC equ (WAVERR_BASE + 3) ; device is synchronous
+WAVERR_LASTERROR equ (WAVERR_BASE + 3) ; last error in range
+
+; wave callback messages
+WOM_OPEN equ MM_WOM_OPEN
+WOM_CLOSE equ MM_WOM_CLOSE
+WOM_DONE equ MM_WOM_DONE
+WIM_OPEN equ MM_WIM_OPEN
+WIM_CLOSE equ MM_WIM_CLOSE
+WIM_DATA equ MM_WIM_DATA
+
+; device ID for wave device mapper
+WAVE_MAPPER equ (-1)
+
+; flags for dwFlags parameter in waveOutOpen() and waveInOpen()
+WAVE_FORMAT_QUERY equ 0001h
+WAVE_ALLOWSYNC equ 0002h
+WAVE_VALID equ 0003h ;Internal
+
+; wave data block header
+WAVEHDR struc
+ lpWaveData dd ? ; pointer to locked data buffer
+ dwWaveBufferLength dd ? ; length of data buffer
+ dwWaveBytesRecorded dd ? ; used for input only
+ dwWaveUser dd ? ; for client's use
+ dwWaveFlags dd ? ; assorted flags (see defines)
+ dwWaveLoops dd ? ; loop control counter
+ lpWaveNext dd ? ; reserved for driver
+ Wavereserved dd ? ; reserved for driver
+WAVEHDR ends
+
+; flags for dwFlags field of WAVEHDR
+WHDR_DONE equ 00000001h ; done bit
+WHDR_PREPARED equ 00000002h ; set if this header has been prepared
+WHDR_BEGINLOOP equ 00000004h ; loop start block
+WHDR_ENDLOOP equ 00000008h ; loop end block
+WHDR_INQUEUE equ 00000010h ; reserved for driver
+WHDR_VALID equ 0000001Fh ;Internal
+
+; waveform output device capabilities structure
+WAVEOUTCAPS struc
+ woc_wMid dw ? ; manufacturer ID
+ woc_wPid dw ? ; product ID
+ woc_vDriverVersion dw ? ; version of the driver
+ woc_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+ woc_dwFormats dd ? ; formats supported
+ woc_wChannels dw ? ; number of sources supported
+ woc_dwSupport dd ? ; functionality supported by driver
+WAVEOUTCAPS ends
+
+; flags for dwSupport field of WAVEOUTCAPS
+WAVECAPS_PITCH equ 0001h ; supports pitch control
+WAVECAPS_PLAYBACKRATE equ 0002h ; supports playback rate control
+WAVECAPS_VOLUME equ 0004h ; supports volume control
+WAVECAPS_LRVOLUME equ 0008h ; separate left-right volume control
+WAVECAPS_SYNC equ 0010h
+
+; waveform input device capabilities structure
+WAVEINCAPS struc
+ wic_wMid dw ? ; manufacturer ID
+ wic_wPid dw ? ; product ID
+ wic_vDriverVersion dw ? ; version of the driver
+ wic_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+ wic_dwFormats dd ? ; formats supported
+ wic_wChannels dw ? ; number of channels supported
+WAVEINCAPS ends
+
+; defines for dwFormat field of WAVEINCAPS and WAVEOUTCAPS
+WAVE_INVALIDFORMAT equ 00000000h ; invalid format
+WAVE_FORMAT_1M08 equ 00000001h ; 11.025 kHz, Mono, 8-bit
+WAVE_FORMAT_1S08 equ 00000002h ; 11.025 kHz, Stereo, 8-bit
+WAVE_FORMAT_1M16 equ 00000004h ; 11.025 kHz, Mono, 16-bit
+WAVE_FORMAT_1S16 equ 00000008h ; 11.025 kHz, Stereo, 16-bit
+WAVE_FORMAT_2M08 equ 00000010h ; 22.05 kHz, Mono, 8-bit
+WAVE_FORMAT_2S08 equ 00000020h ; 22.05 kHz, Stereo, 8-bit
+WAVE_FORMAT_2M16 equ 00000040h ; 22.05 kHz, Mono, 16-bit
+WAVE_FORMAT_2S16 equ 00000080h ; 22.05 kHz, Stereo, 16-bit
+WAVE_FORMAT_4M08 equ 00000100h ; 44.1 kHz, Mono, 8-bit
+WAVE_FORMAT_4S08 equ 00000200h ; 44.1 kHz, Stereo, 8-bit
+WAVE_FORMAT_4M16 equ 00000400h ; 44.1 kHz, Mono, 16-bit
+WAVE_FORMAT_4S16 equ 00000800h ; 44.1 kHz, Stereo, 16-bit
+
+; general waveform format structure (information common to all formats)
+WAVEFORMAT struc
+ wfmt_wFormatTag dw ? ; format type
+ wfmt_nChannels dw ? ; number of channels (i.e. mono, stereo, etc.)
+ wfmt_nSamplesPerSec dd ? ; sample rate
+ wfmt_nAvgBytesPerSec dd ? ; for buffer estimation
+ wfmt_nBlockAlign dw ? ; block size of data
+WAVEFORMAT ends
+
+; flags for wFormatTag field of WAVEFORMAT
+WAVE_FORMAT_PCM equ 1
+
+; specific waveform format structure for PCM data
+PCMWAVEFORMAT struc
+ pcm_wf db (SIZE WAVEFORMAT) dup (?)
+ pcm_wBitsPerSample dw ?
+PCMWAVEFORMAT ends
+
+endif ;ifndef MMNOWAVE
+
+
+ifndef MMNOMIDI
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MIDI audio support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; MIDI error return values
+MIDIERR_UNPREPARED equ (MIDIERR_BASE + 0) ; header not prepared
+MIDIERR_STILLPLAYING equ (MIDIERR_BASE + 1) ; still something playing
+MIDIERR_NOMAP equ (MIDIERR_BASE + 2) ; no current map
+MIDIERR_NOTREADY equ (MIDIERR_BASE + 3) ; hardware is still busy
+MIDIERR_NODEVICE equ (MIDIERR_BASE + 4) ; port no longer connected
+MIDIERR_INVALIDSETUP equ (MIDIERR_BASE + 5) ; invalid setup
+MIDIERR_LASTERROR equ (MIDIERR_BASE + 5) ; last error in range
+
+; MIDI audio data types
+MIDIPATCHSIZE equ 128
+
+; MIDI callback messages
+MIM_OPEN equ MM_MIM_OPEN
+MIM_CLOSE equ MM_MIM_CLOSE
+MIM_DATA equ MM_MIM_DATA
+MIM_LONGDATA equ MM_MIM_LONGDATA
+MIM_ERROR equ MM_MIM_ERROR
+MIM_LONGERROR equ MM_MIM_LONGERROR
+MOM_OPEN equ MM_MOM_OPEN
+MOM_CLOSE equ MM_MOM_CLOSE
+MOM_DONE equ MM_MOM_DONE
+
+; device ID for MIDI mapper
+MIDIMAPPER equ (-1)
+MIDI_MAPPER equ (-1)
+
+; flags for wFlags parm of midiOutCachePatches(),
+; midiOutCacheDrumPatches()
+MIDI_CACHE_ALL equ 1
+MIDI_CACHE_BESTFIT equ 2
+MIDI_CACHE_QUERY equ 3
+MIDI_UNCACHE equ 4
+
+; MIDI output device capabilities structure
+MIDIOUTCAPS struc
+ moc_wMid dw ? ; manufacturer ID
+ moc_wPid dw ? ; product ID
+ moc_vDriverVersion dw ? ; version of the driver
+ moc_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+ moc_wTechnology dw ? ; type of device
+ moc_wVoices dw ? ; # of voices (internal synth only)
+ moc_wNotes dw ? ; max # of notes (internal synth only)
+ moc_wChannelMask dw ? ; channels used (internal synth only)
+ moc_dwSupport dd ? ; functionality supported by driver
+MIDIOUTCAPS ends
+
+; flags for wTechnology field of MIDIOUTCAPS structure
+MOD_MIDIPORT equ 1 ; output port
+MOD_SYNTH equ 2 ; generic internal synth
+MOD_SQSYNTH equ 3 ; square wave internal synth
+MOD_FMSYNTH equ 4 ; FM internal synth
+MOD_MAPPER equ 5 ; MIDI mapper
+
+; flags for dwSupport field of MIDIOUTCAPS structure
+MIDICAPS_VOLUME equ 0001h ; supports volume control
+MIDICAPS_LRVOLUME equ 0002h ; separate left-right volume control
+MIDICAPS_CACHE equ 0004h
+
+; MIDI output device capabilities structure
+MIDIINCAPS struc
+ mic_wMid dw ? ; manufacturer ID
+ mic_wPid dw ? ; product ID
+ mic_vDriverVersion dw ? ; version of the driver
+ mic_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+MIDIINCAPS ends
+
+; MIDI data block header
+MIDIHDR struc
+ lpMidiData dd ? ; pointer to locked data block
+ dwMidiBufferLength dd ? ; length of data in data block
+ dwMidiBytesRecorded dd ? ; used for input only
+ dwMidiUser dd ? ; for client's use
+ dwMidiFlags dd ? ; assorted flags (see defines)
+ lpMidiNext dd ? ; reserved for driver
+ Midireserved dd ? ; reserved for driver
+MIDIHDR ends
+
+; flags for dwFlags field of MIDIHDR structure
+MHDR_DONE equ 00000001h ; done bit
+MHDR_PREPARED equ 00000002h ; set if header prepared
+MHDR_INQUEUE equ 00000004h ; reserved for driver
+MHDR_VALID equ 00000007h ;Internal
+
+endif ;ifndef MMNOMIDI
+
+
+ifndef MMNOAUX
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Auxiliary audio support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; device ID for aux device mapper
+AUX_MAPPER equ (-1)
+
+; Auxiliary audio device capabilities structure
+AUXCAPS struc
+ acaps_wMid dw ? ; manufacturer ID
+ acaps_wPid dw ? ; product ID
+ acaps_vDriverVersion dw ? ; version of the driver
+ acaps_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+ acaps_wTechnology dw ? ; type of device
+ acaps_dwSupport dd ? ; functionality supported by driver
+AUXCAPS ends
+
+; flags for wTechnology field in AUXCAPS structure
+AUXCAPS_CDAUDIO equ 1 ; audio from internal CD-ROM drive
+AUXCAPS_AUXIN equ 2 ; audio from auxiliary input jacks
+
+; flags for dwSupport field in AUXCAPS structure
+AUXCAPS_VOLUME equ 0001h ; supports volume control
+AUXCAPS_LRVOLUME equ 0002h ; separate left-right volume control
+
+endif ;ifndef MMNOAUX
+
+
+ifndef MMNOTIMER
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Timer support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; timer error return values
+TIMERR_NOERROR equ (0) ; no error
+TIMERR_NOCANDO equ (TIMERR_BASE+1) ; request not completed
+TIMERR_STRUCT equ (TIMERR_BASE+33) ; time struct size
+
+; flags for wFlags parameter of timeSetEvent() function
+TIME_ONESHOT equ 0 ; program timer for single event
+TIME_PERIODIC equ 1 ; program for continuous periodic event
+
+; timer device capabilities data structure
+TIMECAPS struc
+ tc_wPeriodMin dw ? ; minimum period supported
+ tc_wPeriodMax dw ? ; maximum period supported
+TIMECAPS ends
+
+endif ;ifndef MMNOTIMER
+
+
+ifndef MMNOJOY
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Joystick support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; joystick error return values
+JOYERR_NOERROR equ (0) ; no error
+JOYERR_PARMS equ (JOYERR_BASE+5) ; bad parameters
+JOYERR_NOCANDO equ (JOYERR_BASE+6) ; request not completed
+JOYERR_UNPLUGGED equ (JOYERR_BASE+7) ; joystick is unplugged
+
+; constants used with JOYINFO structure and MM_JOY* messages
+JOY_BUTTON1 equ 0001h
+JOY_BUTTON2 equ 0002h
+JOY_BUTTON3 equ 0004h
+JOY_BUTTON4 equ 0008h
+JOY_BUTTON1CHG equ 0100h
+JOY_BUTTON2CHG equ 0200h
+JOY_BUTTON3CHG equ 0400h
+JOY_BUTTON4CHG equ 0800h
+
+; joystick ID constants
+JOYSTICKID1 equ 0
+JOYSTICKID2 equ 1
+
+; joystick device capabilities data structure
+JOYCAPS struc
+ jcaps_wMid dw ? ; manufacturer ID
+ jcaps_wPid dw ? ; product ID
+ jcaps_szPname db MAXPNAMELEN dup (?) ; product name (NULL terminated string)
+ jcaps_wXmin dw ? ; minimum x position value
+ jcaps_wXmax dw ? ; maximum x position value
+ jcaps_wYmin dw ? ; minimum y position value
+ jcaps_wYmax dw ? ; maximum y position value
+ jcaps_wZmin dw ? ; minimum z position value
+ jcaps_wZmax dw ? ; maximum z position value
+ jcaps_wNumButtons dw ? ; number of buttons
+ jcaps_wPeriodMin dw ? ; minimum message period when captured
+ jcaps_wPeriodMax dw ? ; maximum message period when captured
+JOYCAPS ends
+
+; joystick information data structure
+JOYINFO struc
+ jinfo_wXpos dw ? ; x position
+ jinfo_wYpos dw ? ; y position
+ jinfo_wZpos dw ? ; z position
+ jinfo_wButtons dw ? ; button states
+JOYINFO ends
+
+endif ;ifndef MMNOJOY
+
+ifndef MMNOMMIO
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Multimedia File I/O support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; MMIO error return values
+MMIOERR_BASE equ 256
+MMIOERR_FILENOTFOUND equ (MMIOERR_BASE + 1) ; file not found
+MMIOERR_OUTOFMEMORY equ (MMIOERR_BASE + 2) ; out of memory
+MMIOERR_CANNOTOPEN equ (MMIOERR_BASE + 3) ; cannot open
+MMIOERR_CANNOTCLOSE equ (MMIOERR_BASE + 4) ; cannot close
+MMIOERR_CANNOTREAD equ (MMIOERR_BASE + 5) ; cannot read
+MMIOERR_CANNOTWRITE equ (MMIOERR_BASE + 6) ; cannot write
+MMIOERR_CANNOTSEEK equ (MMIOERR_BASE + 7) ; cannot seek
+MMIOERR_CANNOTEXPAND equ (MMIOERR_BASE + 8) ; cannot expand file
+MMIOERR_CHUNKNOTFOUND equ (MMIOERR_BASE + 9) ; chunk not found
+MMIOERR_UNBUFFERED equ (MMIOERR_BASE + 10) ; file is unbuffered
+
+; MMIO constants
+CFSEPCHAR equ '+' ; compound file name separator char.
+
+; general MMIO information data structure
+MMIOINFO struc
+ ; general fields
+ mmio_dwFlags dd ? ; general status flags
+ mmio_fccIOProc dd ? ; pointer to I/O procedure
+ mmio_pIOProc dd ? ; pointer to I/O procedure
+ mmio_wErrorRet dw ? ; place for error to be returned
+ mmio_htask dw ? ; alternate local task
+
+ ; fields maintained by MMIO functions during buffered I/O
+ mmio_cchBuffer dd ? ; size of I/O buffer (or 0L)
+ mmio_pchBuffer dd ? ; start of I/O buffer (or NULL)
+ mmio_pchNext dd ? ; pointer to next byte to read/write
+ mmio_pchEndRead dd ? ; pointer to last valid byte to read
+ mmio_pchEndWrite dd ? ; pointer to last byte to write
+ mmio_lBufOffset dd ? ; disk offset of start of buffer
+
+ ; fields maintained by I/O procedure
+ mmio_lDiskOffset dd ? ; disk offset of next read or write
+ mmio_adwInfo dd 3 dup (?) ; data specific to type of MMIOPROC
+
+ ; other fields maintained by MMIO
+ mmio_dwReserved1 dd ? ; reserved for MMIO use
+ mmio_dwReserved2 dd ? ; reserved for MMIO use
+ mmio_hmmio dw ? ; handle to open file
+MMIOINFO ends
+
+; RIFF chunk information data structure
+MMCKINFO struc
+ mmck_ckid dd ? ; chunk ID
+ mmck_cksize dd ? ; chunk size
+ mmck_fccType dd ? ; form type or list type
+ mmck_dwDataOffset dd ? ; offset of data portion of chunk
+ mmck_dwFlags dd ? ; flags used by MMIO functions
+MMCKINFO ends
+
+; bit field masks
+MMIO_RWMODE equ 00000003h ; open file for reading/writing/both
+MMIO_SHAREMODE equ 00000070h ; file sharing mode number
+
+; constants for dwFlags field of MMIOINFO
+MMIO_CREATE equ 00001000h ; create new file (or truncate file)
+MMIO_PARSE equ 00000100h ; parse new file returning path
+MMIO_DELETE equ 00000200h ; create new file (or truncate file)
+MMIO_EXIST equ 00004000h ; checks for existence of file
+MMIO_ALLOCBUF equ 00010000h ; mmioOpen() should allocate a buffer
+MMIO_GETTEMP equ 00020000h ; mmioOpen() should retrieve temp name
+
+MMIO_DIRTY equ 10000000h ; I/O buffer is dirty
+
+MMIO_OPEN_VALID equ 0003FFFFh ;Internal
+
+; read/write mode numbers (bit field MMIO_RWMODE)
+MMIO_READ equ 00000000h ; open file for reading only
+MMIO_WRITE equ 00000001h ; open file for writing only
+MMIO_READWRITE equ 00000002h ; open file for reading and writing
+
+; share mode numbers (bit field MMIO_SHAREMODE)
+MMIO_COMPAT equ 00000000h ; compatibility mode
+MMIO_EXCLUSIVE equ 00000010h ; exclusive-access mode
+MMIO_DENYWRITE equ 00000020h ; deny writing to other processes
+MMIO_DENYREAD equ 00000030h ; deny reading to other processes
+MMIO_DENYNONE equ 00000040h ; deny nothing to other processes
+
+; various MMIO flags
+MMIO_FHOPEN equ 0010h ; mmioClose: keep file handle open
+MMIO_EMPTYBUF equ 0010h ; mmioFlush: empty the I/O buffer
+MMIO_TOUPPER equ 0010h ; mmioStringToFOURCC: to u-case
+MMIO_INSTALLPROC equ 00010000h ; mmioInstallIOProc: install MMIOProc
+MMIO_GLOBALPROC equ 10000000h ; mmioInstallIOProc: install globally
+MMIO_REMOVEPROC equ 00020000h ; mmioInstallIOProc: remove MMIOProc
+MMIO_FINDPROC equ 00040000h ; mmioInstallIOProc: find an MMIOProc
+MMIO_FINDCHUNK equ 0010h ; mmioDescend: find a chunk by ID
+MMIO_FINDRIFF equ 0020h ; mmioDescend: find a LIST chunk
+MMIO_FINDLIST equ 0040h ; mmioDescend: find a RIFF chunk
+MMIO_CREATERIFF equ 0020h ; mmioCreateChunk: make a LIST chunk
+MMIO_CREATELIST equ 0040h ; mmioCreateChunk: make a RIFF chunk
+
+MMIO_VALIDPROC equ 10070000h ;Internal
+
+; message numbers for MMIOPROC I/O procedure functions
+MMIOM_READ equ MMIO_READ ; read
+MMIOM_WRITE equ MMIO_WRITE ; write
+MMIOM_SEEK equ 2 ; seek to a new position in file
+MMIOM_OPEN equ 3 ; open file
+MMIOM_CLOSE equ 4 ; close file
+MMIOM_WRITEFLUSH equ 5 ; write and flush
+MMIOM_RENAME equ 6 ; rename specified file
+MMIOM_USER equ 8000h ; beginning of user-defined messages
+
+mmioFOURCC MACRO ch0,ch1,ch2,ch3
+ mov al,ch0
+ mov ah,ch1
+ mov dl,ch2
+ mov dh,ch3
+ ENDM
+
+; standard four character codes
+FOURCC_RIFF equ mmioFOURCC('R', 'I', 'F', 'F')
+FOURCC_LIST equ mmioFOURCC('L', 'I', 'S', 'T')
+
+; four character codes used to identify standard built-in I/O procedures
+FOURCC_DOS equ mmioFOURCC('D', 'O', 'S', ' ')
+FOURCC_MEM equ mmioFOURCC('M', 'E', 'M', ' ')
+
+; flags for mmioSeek()
+ifndef SEEK_SET
+SEEK_SET equ 0 ; seek to an absolute position
+SEEK_CUR equ 1 ; seek relative to current position
+SEEK_END equ 2 ; seek relative to end of file
+endif ;ifndef SEEK_SET
+
+; other constants
+MMIO_DEFAULTBUFFER equ 8192 ; default buffer size
+
+endif ;ifndef MMNOMMIO
+
+ifndef MMNOMCI
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; MCI support
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; MCI error return values
+MCIERR_INVALID_DEVICE_ID equ (MCIERR_BASE + 1)
+MCIERR_UNRECOGNIZED_KEYWORD equ (MCIERR_BASE + 3)
+MCIERR_UNRECOGNIZED_COMMAND equ (MCIERR_BASE + 5)
+MCIERR_HARDWARE equ (MCIERR_BASE + 6)
+MCIERR_INVALID_DEVICE_NAME equ (MCIERR_BASE + 7)
+MCIERR_OUT_OF_MEMORY equ (MCIERR_BASE + 8)
+MCIERR_DEVICE_OPEN equ (MCIERR_BASE + 9)
+MCIERR_CANNOT_LOAD_DRIVER equ (MCIERR_BASE + 10)
+MCIERR_MISSING_COMMAND_STRING equ (MCIERR_BASE + 11)
+MCIERR_PARAM_OVERFLOW equ (MCIERR_BASE + 12)
+MCIERR_MISSING_STRING_ARGUMENT equ (MCIERR_BASE + 13)
+MCIERR_BAD_INTEGER equ (MCIERR_BASE + 14)
+MCIERR_PARSER_INTERNAL equ (MCIERR_BASE + 15)
+MCIERR_DRIVER_INTERNAL equ (MCIERR_BASE + 16)
+MCIERR_MISSING_PARAMETER equ (MCIERR_BASE + 17)
+MCIERR_UNSUPPORTED_FUNCTION equ (MCIERR_BASE + 18)
+MCIERR_FILE_NOT_FOUND equ (MCIERR_BASE + 19)
+MCIERR_DEVICE_NOT_READY equ (MCIERR_BASE + 20)
+MCIERR_INTERNAL equ (MCIERR_BASE + 21)
+MCIERR_DRIVER equ (MCIERR_BASE + 22)
+MCIERR_CANNOT_USE_ALL equ (MCIERR_BASE + 23)
+MCIERR_MULTIPLE equ (MCIERR_BASE + 24)
+MCIERR_EXTENSION_NOT_FOUND equ (MCIERR_BASE + 25)
+MCIERR_OUTOFRANGE equ (MCIERR_BASE + 26)
+MCIERR_FLAGS_NOT_COMPATIBLE equ (MCIERR_BASE + 28)
+MCIERR_FILE_NOT_SAVED equ (MCIERR_BASE + 30)
+MCIERR_DEVICE_TYPE_REQUIRED equ (MCIERR_BASE + 31)
+MCIERR_DEVICE_LOCKED equ (MCIERR_BASE + 32)
+MCIERR_DUPLICATE_ALIAS equ (MCIERR_BASE + 33)
+MCIERR_BAD_CONSTANT equ (MCIERR_BASE + 34)
+MCIERR_MUST_USE_SHAREABLE equ (MCIERR_BASE + 35)
+MCIERR_MISSING_DEVICE_NAME equ (MCIERR_BASE + 36)
+MCIERR_BAD_TIME_FORMAT equ (MCIERR_BASE + 37)
+MCIERR_NO_CLOSING_QUOTE equ (MCIERR_BASE + 38)
+MCIERR_DUPLICATE_FLAGS equ (MCIERR_BASE + 39)
+MCIERR_INVALID_FILE equ (MCIERR_BASE + 40)
+MCIERR_NULL_PARAMETER_BLOCK equ (MCIERR_BASE + 41)
+MCIERR_UNNAMED_RESOURCE equ (MCIERR_BASE + 42)
+MCIERR_NEW_REQUIRES_ALIAS equ (MCIERR_BASE + 43)
+MCIERR_NOTIFY_ON_AUTO_OPEN equ (MCIERR_BASE + 44)
+MCIERR_NO_ELEMENT_ALLOWED equ (MCIERR_BASE + 45)
+MCIERR_NONAPPLICABLE_FUNCTION equ (MCIERR_BASE + 46)
+MCIERR_ILLEGAL_FOR_AUTO_OPEN equ (MCIERR_BASE + 47)
+MCIERR_FILENAME_REQUIRED equ (MCIERR_BASE + 48)
+MCIERR_EXTRA_CHARACTERS equ (MCIERR_BASE + 49)
+MCIERR_DEVICE_NOT_INSTALLED equ (MCIERR_BASE + 50)
+MCIERR_GET_CD equ (MCIERR_BASE + 51)
+MCIERR_SET_CD equ (MCIERR_BASE + 52)
+MCIERR_SET_DRIVE equ (MCIERR_BASE + 53)
+MCIERR_DEVICE_LENGTH equ (MCIERR_BASE + 54)
+MCIERR_DEVICE_ORD_LENGTH equ (MCIERR_BASE + 55)
+MCIERR_NO_INTEGER equ (MCIERR_BASE + 56)
+
+MCIERR_WAVE_OUTPUTSINUSE equ (MCIERR_BASE + 64)
+MCIERR_WAVE_SETOUTPUTINUSE equ (MCIERR_BASE + 65)
+MCIERR_WAVE_INPUTSINUSE equ (MCIERR_BASE + 66)
+MCIERR_WAVE_SETINPUTINUSE equ (MCIERR_BASE + 67)
+MCIERR_WAVE_OUTPUTUNSPECIFIED equ (MCIERR_BASE + 68)
+MCIERR_WAVE_INPUTUNSPECIFIED equ (MCIERR_BASE + 69)
+MCIERR_WAVE_OUTPUTSUNSUITABLE equ (MCIERR_BASE + 70)
+MCIERR_WAVE_SETOUTPUTUNSUITABLE equ (MCIERR_BASE + 71)
+MCIERR_WAVE_INPUTSUNSUITABLE equ (MCIERR_BASE + 72)
+MCIERR_WAVE_SETINPUTUNSUITABLE equ (MCIERR_BASE + 73)
+
+MCIERR_SEQ_DIV_INCOMPATIBLE equ (MCIERR_BASE + 80)
+MCIERR_SEQ_PORT_INUSE equ (MCIERR_BASE + 81)
+MCIERR_SEQ_PORT_NONEXISTENT equ (MCIERR_BASE + 82)
+MCIERR_SEQ_PORT_MAPNODEVICE equ (MCIERR_BASE + 83)
+MCIERR_SEQ_PORT_MISCERROR equ (MCIERR_BASE + 84)
+MCIERR_SEQ_TIMER equ (MCIERR_BASE + 85)
+MCIERR_SEQ_PORTUNSPECIFIED equ (MCIERR_BASE + 86)
+MCIERR_SEQ_NOMIDIPRESENT equ (MCIERR_BASE + 87)
+
+MCIERR_NO_WINDOW equ (MCIERR_BASE + 90)
+MCIERR_CREATEWINDOW equ (MCIERR_BASE + 91)
+MCIERR_FILE_READ equ (MCIERR_BASE + 92)
+MCIERR_FILE_WRITE equ (MCIERR_BASE + 93)
+
+; all custom device driver errors must be >= than this value
+MCIERR_CUSTOM_DRIVER_BASE equ (MCIERR_BASE + 256)
+
+; MCI command message identifiers
+MCI_OPEN equ 0803h
+MCI_CLOSE equ 0804h
+MCI_ESCAPE equ 0805h
+MCI_PLAY equ 0806h
+MCI_SEEK equ 0807h
+MCI_STOP equ 0808h
+MCI_PAUSE equ 0809h
+MCI_INFO equ 080Ah
+MCI_GETDEVCAPS equ 080Bh
+MCI_SPIN equ 080Ch
+MCI_SET equ 080Dh
+MCI_STEP equ 080Eh
+MCI_RECORD equ 080Fh
+MCI_SYSINFO equ 0810h
+MCI_BREAK equ 0811h
+MCI_SOUND equ 0812h
+MCI_SAVE equ 0813h
+MCI_STATUS equ 0814h
+MCI_CUE equ 0830h
+MCI_REALIZE equ 0840h
+MCI_WINDOW equ 0841h
+MCI_PUT equ 0842h
+MCI_WHERE equ 0843h
+MCI_FREEZE equ 0844h
+MCI_UNFREEZE equ 0845h
+MCI_LOAD equ 0850h
+MCI_CUT equ 0851h
+MCI_COPY equ 0852h
+MCI_PASTE equ 0853h
+MCI_UPDATE equ 0854h
+MCI_RESUME equ 0855h
+MCI_DELETE equ 0856h
+
+; all custom MCI command messages must be >= than this value
+MCI_USER_MESSAGES equ (400h + DRV_MCI_FIRST)
+
+
+; device ID for "all devices"
+MCI_ALL_DEVICE_ID equ 0FFFFh
+
+; constants for predefined MCI device types
+MCI_DEVTYPE_VCR equ (MCI_STRING_OFFSET + 1)
+MCI_DEVTYPE_VIDEODISC equ (MCI_STRING_OFFSET + 2)
+MCI_DEVTYPE_OVERLAY equ (MCI_STRING_OFFSET + 3)
+MCI_DEVTYPE_CD_AUDIO equ (MCI_STRING_OFFSET + 4)
+MCI_DEVTYPE_DAT equ (MCI_STRING_OFFSET + 5)
+MCI_DEVTYPE_SCANNER equ (MCI_STRING_OFFSET + 6)
+MCI_DEVTYPE_ANIMATION equ (MCI_STRING_OFFSET + 7)
+MCI_DEVTYPE_DIGITAL_VIDEO equ (MCI_STRING_OFFSET + 8)
+MCI_DEVTYPE_OTHER equ (MCI_STRING_OFFSET + 9)
+MCI_DEVTYPE_WAVEFORM_AUDIO equ (MCI_STRING_OFFSET + 10)
+MCI_DEVTYPE_SEQUENCER equ (MCI_STRING_OFFSET + 11)
+
+MCI_DEVTYPE_FIRST equ MCI_DEVTYPE_VCR
+MCI_DEVTYPE_LAST equ MCI_DEVTYPE_SEQUENCER
+
+; return values for 'status mode' command
+MCI_MODE_NOT_READY equ (MCI_STRING_OFFSET + 12)
+MCI_MODE_STOP equ (MCI_STRING_OFFSET + 13)
+MCI_MODE_PLAY equ (MCI_STRING_OFFSET + 14)
+MCI_MODE_RECORD equ (MCI_STRING_OFFSET + 15)
+MCI_MODE_SEEK equ (MCI_STRING_OFFSET + 16)
+MCI_MODE_PAUSE equ (MCI_STRING_OFFSET + 17)
+MCI_MODE_OPEN equ (MCI_STRING_OFFSET + 18)
+
+; constants used in 'set time format' and 'status time format' commands
+MCI_FORMAT_MILLISECONDS equ 0
+MCI_FORMAT_HMS equ 1
+MCI_FORMAT_MSF equ 2
+MCI_FORMAT_FRAMES equ 3
+MCI_FORMAT_SMPTE_24 equ 4
+MCI_FORMAT_SMPTE_25 equ 5
+MCI_FORMAT_SMPTE_30 equ 6
+MCI_FORMAT_SMPTE_30DROP equ 7
+MCI_FORMAT_BYTES equ 8
+MCI_FORMAT_SAMPLES equ 9
+MCI_FORMAT_TMSF equ 10
+
+; flags for wParam of MM_MCINOTIFY message
+MCI_NOTIFY_SUCCESSFUL equ 0001h
+MCI_NOTIFY_SUPERSEDED equ 0002h
+MCI_NOTIFY_ABORTED equ 0004h
+MCI_NOTIFY_FAILURE equ 0008h
+
+
+; common flags for dwFlags parameter of MCI command messages
+MCI_NOTIFY equ 00000001h
+MCI_WAIT equ 00000002h
+MCI_FROM equ 00000004h
+MCI_TO equ 00000008h
+MCI_TRACK equ 00000010h
+
+; flags for dwFlags parameter of MCI_OPEN command message
+MCI_OPEN_SHAREABLE equ 00000100h
+MCI_OPEN_ELEMENT equ 00000200h
+MCI_OPEN_ALIAS equ 00000400h
+MCI_OPEN_ELEMENT_ID equ 00000800h
+MCI_OPEN_TYPE_ID equ 00001000h
+MCI_OPEN_TYPE equ 00002000h
+
+; flags for dwFlags parameter of MCI_SEEK command message
+MCI_SEEK_TO_START equ 00000100h
+MCI_SEEK_TO_END equ 00000200h
+
+; flags for dwFlags parameter of MCI_STATUS command message
+MCI_STATUS_ITEM equ 00000100h
+MCI_STATUS_START equ 00000200h
+
+; flags for dwItem field of the MCI_STATUS_PARMS parameter block
+MCI_STATUS_LENGTH equ 00000001h
+MCI_STATUS_POSITION equ 00000002h
+MCI_STATUS_NUMBER_OF_TRACKS equ 00000003h
+MCI_STATUS_MODE equ 00000004h
+MCI_STATUS_MEDIA_PRESENT equ 00000005h
+MCI_STATUS_TIME_FORMAT equ 00000006h
+MCI_STATUS_READY equ 00000007h
+MCI_STATUS_CURRENT_TRACK equ 00000008h
+
+; flags for dwFlags parameter of MCI_INFO command message
+MCI_INFO_PRODUCT equ 00000100h
+MCI_INFO_FILE equ 00000200h
+
+; flags for dwFlags parameter of MCI_GETDEVCAPS command message
+MCI_GETDEVCAPS_ITEM equ 00000100h
+
+; flags for dwItem field of the MCI_GETDEVCAPS_PARMS parameter block
+MCI_GETDEVCAPS_CAN_RECORD equ 00000001h
+MCI_GETDEVCAPS_HAS_AUDIO equ 00000002h
+MCI_GETDEVCAPS_HAS_VIDEO equ 00000003h
+MCI_GETDEVCAPS_DEVICE_TYPE equ 00000004h
+MCI_GETDEVCAPS_USES_FILES equ 00000005h
+MCI_GETDEVCAPS_COMPOUND_DEVICE equ 00000006h
+MCI_GETDEVCAPS_CAN_EJECT equ 00000007h
+MCI_GETDEVCAPS_CAN_PLAY equ 00000008h
+MCI_GETDEVCAPS_CAN_SAVE equ 00000009h
+
+; flags for dwFlags parameter of MCI_SYSINFO command message
+MCI_SYSINFO_QUANTITY equ 00000100h
+MCI_SYSINFO_OPEN equ 00000200h
+MCI_SYSINFO_NAME equ 00000400h
+MCI_SYSINFO_INSTALLNAME equ 00000800h
+
+; flags for dwFlags parameter of MCI_SET command message
+MCI_SET_DOOR_OPEN equ 00000100h
+MCI_SET_DOOR_CLOSED equ 00000200h
+MCI_SET_TIME_FORMAT equ 00000400h
+MCI_SET_AUDIO equ 00000800h
+MCI_SET_VIDEO equ 00001000h
+MCI_SET_ON equ 00002000h
+MCI_SET_OFF equ 00004000h
+
+; flags for dwAudio field of MCI_SET_PARMS or MCI_SEQ_SET_PARMS
+MCI_SET_AUDIO_ALL equ 00000000h
+MCI_SET_AUDIO_LEFT equ 00000001h
+MCI_SET_AUDIO_RIGHT equ 00000002h
+
+; flags for dwFlags parameter of MCI_BREAK command message
+MCI_BREAK_KEY equ 00000100h
+MCI_BREAK_HWND equ 00000200h
+MCI_BREAK_OFF equ 00000400h
+
+; flags for dwFlags parameter of MCI_RECORD command message
+MCI_RECORD_INSERT equ 00000100h
+MCI_RECORD_OVERWRITE equ 00000200h
+
+; flags for dwFlags parameter of MCI_SOUND command message
+MCI_SOUND_NAME equ 00000100h
+
+; flags for dwFlags parameter of MCI_SAVE command message
+MCI_SAVE_FILE equ 00000100h
+
+; flags for dwFlags parameter of MCI_LOAD command message
+MCI_LOAD_FILE equ 00000100h
+
+; generic parameter block for MCI command messages with no special parameters
+MCI_GENERIC_PARMS struc
+ mcigen_dwCallback dd ?
+MCI_GENERIC_PARMS ends
+
+; parameter block for MCI_OPEN command message
+MCI_OPEN_PARMS struc
+ mciopen_dwCallback dd ?
+ mciopen_wDeviceID dw ?
+ mciopen_wReserved0 dw ?
+ mciopen_lpstrDeviceType dd ?
+ mciopen_lpstrElementName dd ?
+ mciopen_lpstrAlias dd ?
+MCI_OPEN_PARMS ends
+
+; parameter block for MCI_PLAY command message
+MCI_PLAY_PARMS struc
+ mciplay_dwCallback dd ?
+ mciplay_dwFrom dd ?
+ mciplay_dwTo dd ?
+MCI_PLAY_PARMS ends
+
+; parameter block for MCI_SEEK command message
+MCI_SEEK_PARMS struc
+ mciseek_dwCallback dd ?
+ mciseek_dwTo dd ?
+MCI_SEEK_PARMS ends
+
+; parameter block for MCI_STATUS command message
+MCI_STATUS_PARMS struc
+ mcistat_dwCallback dd ?
+ mcistat_dwReturn dd ?
+ mcistat_dwItem dd ?
+ mcistat_dwTrack dd ?
+MCI_STATUS_PARMS ends
+
+; parameter block for MCI_INFO command message
+MCI_INFO_PARMS struc
+ mciinfo_dwCallback dd ?
+ mciinfo_lpstrReturn dd ?
+ mciinfo_dwRetSize dd ?
+MCI_INFO_PARMS ends
+
+; parameter block for MCI_GETDEVCAPS command message
+MCI_GETDEVCAPS_PARMS struc
+ mcigdc_dwCallback dd ?
+ mcigdc_dwReturn dd ?
+ mcigdc_dwItem dd ?
+MCI_GETDEVCAPS_PARMS ends
+
+; parameter block for MCI_SYSINFO command message
+MCI_SYSINFO_PARMS struc
+ mcisi_dwCallback dd ?
+ mcisi_lpstrReturn dd ?
+ mcisi_dwRetSize dd ?
+ mcisi_dwNumber dd ?
+ mcisi_wDeviceType dw ?
+ mcisi_wReserved0 dw ?
+MCI_SYSINFO_PARMS ends
+
+; parameter block for MCI_SET command message
+MCI_SET_PARMS struc
+ mciset_dwCallback dd ?
+ mciset_dwTimeFormat dd ?
+ mciset_dwAudio dd ?
+MCI_SET_PARMS ends
+
+; parameter block for MCI_BREAK command message
+MCI_BREAK_PARMS struc
+ mcibreak_dwCallback dd ?
+ mcibreak_nVirtKey dw ?
+ mcibreak_wReserved0 dw ?
+ mcibreak_hwndBreak dw ?
+ mcibreak_wReserved1 dw ?
+MCI_BREAK_PARMS ends
+
+; parameter block for MCI_SOUND command message
+MCI_SOUND_PARMS struc
+ mcisnd_dwCallback dd ?
+ mcisnd_lpstrSoundName dd ?
+MCI_SOUND_PARMS ends
+
+; parameter block for MCI_SAVE command message
+MCI_SAVE_PARMS struc
+ mcisave_dwCallback dd ?
+ mcisave_lpfilename dd ?
+MCI_SAVE_PARMS ends
+
+; parameter block for MCI_LOAD command message
+MCI_LOAD_PARMS struc
+ mciload_dwCallback dd ?
+ mciload_lpfilename dd ?
+MCI_LOAD_PARMS ends
+
+; parameter block for MCI_RECORD command message
+MCI_RECORD_PARMS struc
+ mcirec_dwCallback dd ?
+ mcirec_dwFrom dd ?
+ mcirec_dwTo dd ?
+MCI_RECORD_PARMS ends
+
+
+;
+; MCI extensions for videodisc devices
+;
+
+; flag for dwReturn field of MCI_STATUS_PARMS
+; MCI_STATUS command, (dwItem == MCI_STATUS_MODE)
+MCI_VD_MODE_PARK equ (MCI_VD_OFFSET + 1)
+
+; flag for dwReturn field of MCI_STATUS_PARMS
+; MCI_STATUS command, (dwItem == MCI_VD_STATUS_MEDIA_TYPE)
+MCI_VD_MEDIA_CLV equ (MCI_VD_OFFSET + 2)
+MCI_VD_MEDIA_CAV equ (MCI_VD_OFFSET + 3)
+MCI_VD_MEDIA_OTHER equ (MCI_VD_OFFSET + 4)
+
+MCI_VD_FORMAT_TRACK equ 4001h
+
+; flags for dwFlags parameter of MCI_PLAY command message
+MCI_VD_PLAY_REVERSE equ 00010000h
+MCI_VD_PLAY_FAST equ 00020000h
+MCI_VD_PLAY_SPEED equ 00040000h
+MCI_VD_PLAY_SCAN equ 00080000h
+MCI_VD_PLAY_SLOW equ 00100000h
+
+; flag for dwFlags parameter of MCI_SEEK command message
+MCI_VD_SEEK_REVERSE equ 00010000h
+
+; flags for dwItem field of MCI_STATUS_PARMS parameter block
+MCI_VD_STATUS_SPEED equ 00004002h
+MCI_VD_STATUS_FORWARD equ 00004003h
+MCI_VD_STATUS_MEDIA_TYPE equ 00004004h
+MCI_VD_STATUS_SIDE equ 00004005h
+MCI_VD_STATUS_DISC_SIZE equ 00004006h
+
+; flags for dwFlags parameter of MCI_GETDEVCAPS command message
+MCI_VD_GETDEVCAPS_CLV equ 00010000h
+MCI_VD_GETDEVCAPS_CAV equ 00020000h
+
+MCI_VD_SPIN_UP equ 0001h
+MCI_VD_SPIN_DOWN equ 0002h
+
+; flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block
+MCI_VD_GETDEVCAPS_CAN_REVERSE equ 00004002h
+MCI_VD_GETDEVCAPS_FAST_RATE equ 00004003h
+MCI_VD_GETDEVCAPS_SLOW_RATE equ 00004004h
+MCI_VD_GETDEVCAPS_NORMAL_RATE equ 00004005h
+
+; flags for the dwFlags parameter of MCI_STEP command message
+MCI_VD_STEP_FRAMES equ 00010000h
+MCI_VD_STEP_REVERSE equ 00020000h
+
+; flag for the MCI_ESCAPE command message
+MCI_VD_ESCAPE_STRING equ 00000100h
+
+; parameter block for MCI_PLAY command message
+MCI_VD_PLAY_PARMS struc
+ mcivdplay_dwCallback dd ?
+ mcivdplay_dwFrom dd ?
+ mcivdplay_dwTo dd ?
+ mcivdplay_dwSpeed dd ?
+MCI_VD_PLAY_PARMS ends
+
+; parameter block for MCI_STEP command message
+MCI_VD_STEP_PARMS struc
+ mcivdstep_dwCallback dd ?
+ mcivdstep_dwFrames dd ?
+MCI_VD_STEP_PARMS ends
+
+; parameter block for MCI_ESCAPE command message
+MCI_VD_ESCAPE_PARMS struc
+ mcivcesc_dwCallback dd ?
+ mcivcesc_lpstrCommand dd ?
+MCI_VD_ESCAPE_PARMS ends
+
+
+;
+; MCI extensions for waveform audio devices
+;
+
+; flags for the dwFlags parameter of MCI_OPEN command message
+MCI_WAVE_OPEN_BUFFER equ 00010000h
+
+; flags for the dwFlags parameter of MCI_SET command message
+MCI_WAVE_SET_FORMATTAG equ 00010000h
+MCI_WAVE_SET_CHANNELS equ 00020000h
+MCI_WAVE_SET_SAMPLESPERSEC equ 00040000h
+MCI_WAVE_SET_AVGBYTESPERSEC equ 00080000h
+MCI_WAVE_SET_BLOCKALIGN equ 00100000h
+MCI_WAVE_SET_BITSPERSAMPLE equ 00200000h
+
+; flags for the dwFlags parameter of MCI_STATUS, MCI_SET command messages
+MCI_WAVE_INPUT equ 00400000h
+MCI_WAVE_OUTPUT equ 00800000h
+
+; flags for the dwItem field of MCI_STATUS_PARMS parameter block
+MCI_WAVE_STATUS_FORMATTAG equ 00004001h
+MCI_WAVE_STATUS_CHANNELS equ 00004002h
+MCI_WAVE_STATUS_SAMPLESPERSEC equ 00004003h
+MCI_WAVE_STATUS_AVGBYTESPERSEC equ 00004004h
+MCI_WAVE_STATUS_BLOCKALIGN equ 00004005h
+MCI_WAVE_STATUS_BITSPERSAMPLE equ 00004006h
+MCI_WAVE_STATUS_LEVEL equ 00004007h
+
+; flags for the dwFlags parameter of MCI_SET command message
+MCI_WAVE_SET_ANYINPUT equ 04000000h
+MCI_WAVE_SET_ANYOUTPUT equ 08000000h
+
+; flags for the dwFlags parameter of MCI_GETDEVCAPS command message
+MCI_WAVE_GETDEVCAPS_INPUTS equ 00004001h
+MCI_WAVE_GETDEVCAPS_OUTPUTS equ 00004002h
+
+; parameter block for MCI_OPEN command message
+MCI_WAVE_OPEN_PARMS struc
+ mciwopen_dwCallback dd ?
+ mciwopen_wDeviceID dw ?
+ mciwopen_wReserved0 dw ?
+ mciwopen_lpstrDeviceType dd ?
+ mciwopen_lpstrElementName dd ?
+ mciwopen_lpstrAlias dd ?
+ mciwopen_dwBufferSeconds dd ?
+MCI_WAVE_OPEN_PARMS ends
+
+; parameter block for MCI_DELETE command message
+MCI_WAVE_DELETE_PARMS struc
+ mciwdel_dwCallback dd ?
+ mciwdel_dwFrom dd ?
+ mciwdel_dwTo dd ?
+MCI_WAVE_DELETE_PARMS ends
+
+; parameter block for MCI_SET command message
+MCI_WAVE_SET_PARMS struc
+ mciwset_dwCallback dd ?
+ mciwset_dwTimeFormat dd ?
+ mciwset_dwAudio dd ?
+ mciwset_wInput dw ?
+ mciwset_wReserved0 dw ?
+ mciwset_wOutput dw ?
+ mciwset_wReserved1 dw ?
+ mciwset_wFormatTag dw ?
+ mciwset_wReserved2 dw ?
+ mciwset_nChannels dw ?
+ mciwset_wReserved3 dw ?
+ mciwset_nSamplesPerSec dw ?
+ mciwset_nAvgBytesPerSec dw ?
+ mciwset_nBlockAlign dw ?
+ mciwset_wReserved4 dw ?
+ mciwset_wBitsPerSample dw ?
+ mciwset_wReserved5 dw ?
+MCI_WAVE_SET_PARMS ends
+
+
+;
+; MCI extensions for MIDI sequencer devices
+;
+
+; flags for the dwReturn field of MCI_STATUS_PARMS parameter block
+; MCI_STATUS command, (dwItem == MCI_SEQ_STATUS_DIVTYPE)
+MCI_SEQ_DIV_PPQN equ (0 + MCI_SEQ_OFFSET)
+MCI_SEQ_DIV_SMPTE_24 equ (1 + MCI_SEQ_OFFSET)
+MCI_SEQ_DIV_SMPTE_25 equ (2 + MCI_SEQ_OFFSET)
+MCI_SEQ_DIV_SMPTE_30DROP equ (3 + MCI_SEQ_OFFSET)
+MCI_SEQ_DIV_SMPTE_30 equ (4 + MCI_SEQ_OFFSET)
+
+; flags for the dwMaster field of MCI_SEQ_SET_PARMS parameter block
+; MCI_SET command, (dwFlags == MCI_SEQ_SET_MASTER)
+MCI_SEQ_FORMAT_SONGPTR equ 4001h
+MCI_SEQ_FILE equ 4002h
+MCI_SEQ_MIDI equ 4003h
+MCI_SEQ_SMPTE equ 4004h
+MCI_SEQ_NONE equ 65533
+
+; flags for the dwItem field of MCI_STATUS_PARMS parameter block
+MCI_SEQ_STATUS_TEMPO equ 00004002h
+MCI_SEQ_STATUS_PORT equ 00004003h
+MCI_SEQ_STATUS_SLAVE equ 00004007h
+MCI_SEQ_STATUS_MASTER equ 00004008h
+MCI_SEQ_STATUS_OFFSET equ 00004009h
+MCI_SEQ_STATUS_DIVTYPE equ 0000400Ah
+
+; flags for the dwFlags parameter of MCI_SET command message
+MCI_SEQ_SET_TEMPO equ 00010000h
+MCI_SEQ_SET_PORT equ 00020000h
+MCI_SEQ_SET_SLAVE equ 00040000h
+MCI_SEQ_SET_MASTER equ 00080000h
+MCI_SEQ_SET_OFFSET equ 01000000h
+
+; parameter block for MCI_SET command message
+MCI_SEQ_SET_PARMS struc
+ mcisset_dwCallback dd ?
+ mcisset_dwTimeFormat dd ?
+ mcisset_dwAudio dd ?
+ mcisset_dwTempo dd ?
+ mcisset_dwPort dd ?
+ mcisset_dwSlave dd ?
+ mcisset_dwMaster dd ?
+ mcisset_dwOffset dd ?
+MCI_SEQ_SET_PARMS ends
+
+
+;
+; MCI extensions for animation devices
+;
+
+; flags for dwFlags parameter of MCI_OPEN command message
+MCI_ANIM_OPEN_WS equ 00010000h
+MCI_ANIM_OPEN_PARENT equ 00020000h
+MCI_ANIM_OPEN_NOSTATIC equ 00040000h
+
+; flags for dwFlags parameter of MCI_PLAY command message
+MCI_ANIM_PLAY_SPEED equ 00010000h
+MCI_ANIM_PLAY_REVERSE equ 00020000h
+MCI_ANIM_PLAY_FAST equ 00040000h
+MCI_ANIM_PLAY_SLOW equ 00080000h
+MCI_ANIM_PLAY_SCAN equ 00100000h
+
+; flags for dwFlags parameter of MCI_STEP command message
+MCI_ANIM_STEP_REVERSE equ 00010000h
+MCI_ANIM_STEP_FRAMES equ 00020000h
+
+; flags for dwItem field of MCI_STATUS_PARMS parameter block
+MCI_ANIM_STATUS_SPEED equ 00004001h
+MCI_ANIM_STATUS_FORWARD equ 00004002h
+MCI_ANIM_STATUS_HWND equ 00004003h
+MCI_ANIM_STATUS_HPAL equ 00004004h
+MCI_ANIM_STATUS_STRETCH equ 00004005h
+
+; flags for the dwFlags parameter of MCI_INFO command message
+MCI_ANIM_INFO_TEXT equ 00010000h
+
+; flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block
+MCI_ANIM_GETDEVCAPS_CAN_REVERSE equ 00004001h
+MCI_ANIM_GETDEVCAPS_FAST_RATE equ 00004002h
+MCI_ANIM_GETDEVCAPS_SLOW_RATE equ 00004003h
+MCI_ANIM_GETDEVCAPS_NORMAL_RATE equ 00004004h
+MCI_ANIM_GETDEVCAPS_PALETTES equ 00004006h
+MCI_ANIM_GETDEVCAPS_CAN_STRETCH equ 00004007h
+MCI_ANIM_GETDEVCAPS_MAX_WINDOWS equ 00004008h
+
+; flags for the MCI_REALIZE command message
+MCI_ANIM_REALIZE_NORM equ 00010000h
+MCI_ANIM_REALIZE_BKGD equ 00020000h
+
+; flags for dwFlags parameter of MCI_WINDOW command message
+MCI_ANIM_WINDOW_HWND equ 00010000h
+MCI_ANIM_WINDOW_STATE equ 00040000h
+MCI_ANIM_WINDOW_TEXT equ 00080000h
+MCI_ANIM_WINDOW_ENABLE_STRETCH equ 00100000h
+MCI_ANIM_WINDOW_DISABLE_STRETCH equ 00200000h
+
+; flags for hWnd field of MCI_ANIM_WINDOW_PARMS parameter block
+; MCI_WINDOW command message, (dwFlags == MCI_ANIM_WINDOW_HWND)
+MCI_ANIM_WINDOW_DEFAULT equ 00000000h
+
+; flags for dwFlags parameter of MCI_PUT command message
+MCI_ANIM_RECT equ 00010000h
+MCI_ANIM_PUT_SOURCE equ 00020000h
+MCI_ANIM_PUT_DESTINATION equ 00040000h
+
+; flags for dwFlags parameter of MCI_WHERE command message
+MCI_ANIM_WHERE_SOURCE equ 00020000h
+MCI_ANIM_WHERE_DESTINATION equ 00040000h
+
+; flags for dwFlags parameter of MCI_UPDATE command message
+MCI_ANIM_UPDATE_HDC equ 00020000h
+
+; parameter block for MCI_OPEN command message
+MCI_ANIM_OPEN_PARMS struc
+ mciaopen_dwCallback dd ?
+ mciaopen_wDeviceID dw ?
+ mciaopen_wReserved0 dw ?
+ mciaopen_lpstrDeviceType dd ?
+ mciaopen_lpstrElementName dd ?
+ mciaopen_lpstrAlias dd ?
+ mciaopen_dwStyle dd ?
+ mciaopen_hWndParent dw ?
+ mciaopen_wReserved1 dw ?
+MCI_ANIM_OPEN_PARMS ends
+
+; parameter block for MCI_PLAY command message
+MCI_ANIM_PLAY_PARMS struc
+ mciaplay_dwCallback dd ?
+ mciaplay_dwFrom dd ?
+ mciaplay_dwTo dd ?
+ mciaplay_dwSpeed dd ?
+MCI_ANIM_PLAY_PARMS ends
+
+; parameter block for MCI_STEP command message
+MCI_ANIM_STEP_PARMS struc
+ mciastep_dwCallback dd ?
+ mciastep_dwFrames dd ?
+MCI_ANIM_STEP_PARMS ends
+
+; parameter block for MCI_WINDOW command message
+MCI_ANIM_WINDOW_PARMS struc
+ mciawin_dwCallback dd ?
+ mciawin_hWnd dw ?
+ mciawin_wReserved1 dw ?
+ mciawin_nCmdShow dw ?
+ mciawin_wReserved2 dw ?
+ mciawin_lpstrText dd ?
+MCI_ANIM_WINDOW_PARMS ends
+
+; parameter block for MCI_PUT, MCI_UPDATE, MCI_WHERE command messages
+MCI_ANIM_RECT_PARMS struc
+ mciarect_dwCallback dd ?
+ifdef MCI_USE_OFFEXT
+ mciarect_ptOffset db (SIZE POINT) dup (?)
+ mciarect_ptExtent db (SIZE POINT) dup (?)
+else ;ifdef MCI_USE_OFFEXT
+ mciarect_rc db (SIZE RECT) dup (?)
+endif ;ifdef MCI_USE_OFFEXT
+MCI_ANIM_RECT_PARMS ends
+
+; parameter block for MCI_UPDATE PARMS
+MCI_ANIM_UPDATE_PARMS struc
+ mciaupd_dwCallback dd ?
+ mciaupd_rc db (SIZE RECT) dup (?)
+ mciaupd_hDC dw ?
+MCI_ANIM_UPDATE_PARMS ends
+
+
+;
+; MCI extensions for video overlay devices
+;
+
+; flags for dwFlags parameter of MCI_OPEN command message
+MCI_OVLY_OPEN_WS equ 00010000h
+MCI_OVLY_OPEN_PARENT equ 00020000h
+
+; flags for dwFlags parameter of MCI_STATUS command message
+MCI_OVLY_STATUS_HWND equ 00004001h
+MCI_OVLY_STATUS_STRETCH equ 00004002h
+
+; flags for dwFlags parameter of MCI_INFO command message
+MCI_OVLY_INFO_TEXT equ 00010000h
+
+; flags for dwItem field of MCI_GETDEVCAPS_PARMS parameter block
+MCI_OVLY_GETDEVCAPS_CAN_STRETCH equ 00004001h
+MCI_OVLY_GETDEVCAPS_CAN_FREEZE equ 00004002h
+MCI_OVLY_GETDEVCAPS_MAX_WINDOWS equ 00004003h
+
+; flags for dwFlags parameter of MCI_WINDOW command message
+MCI_OVLY_WINDOW_HWND equ 00010000h
+MCI_OVLY_WINDOW_STATE equ 00040000h
+MCI_OVLY_WINDOW_TEXT equ 00080000h
+MCI_OVLY_WINDOW_ENABLE_STRETCH equ 00100000h
+MCI_OVLY_WINDOW_DISABLE_STRETCH equ 00200000h
+
+; flags for hWnd parameter of MCI_OVLY_WINDOW_PARMS parameter block
+MCI_OVLY_WINDOW_DEFAULT equ 00000000h
+
+; flags for dwFlags parameter of MCI_PUT command message
+MCI_OVLY_RECT equ 00010000h
+MCI_OVLY_PUT_SOURCE equ 00020000h
+MCI_OVLY_PUT_DESTINATION equ 00040000h
+MCI_OVLY_PUT_FRAME equ 00080000h
+MCI_OVLY_PUT_VIDEO equ 00100000h
+
+; flags for dwFlags parameter of MCI_WHERE command message
+MCI_OVLY_WHERE_SOURCE equ 00020000h
+MCI_OVLY_WHERE_DESTINATION equ 00040000h
+MCI_OVLY_WHERE_FRAME equ 00080000h
+MCI_OVLY_WHERE_VIDEO equ 00100000h
+
+; parameter block for MCI_OPEN command message
+MCI_OVLY_OPEN_PARMS struc
+ mcioopen_dwCallback dd ?
+ mcioopen_wDeviceID dw ?
+ mcioopen_wReserved0 dw ?
+ mcioopen_lpstrDeviceType dd ?
+ mcioopen_lpstrElementName dd ?
+ mcioopen_lpstrAlias dd ?
+ mcioopen_dwStyle dd ?
+ mcioopen_hWndParent dw ?
+ mcioopen_wReserved1 dw ?
+MCI_OVLY_OPEN_PARMS ends
+
+; parameter block for MCI_WINDOW command message
+MCI_OVLY_WINDOW_PARMS struc
+ mciowin_dwCallback dd ?
+ mciowin_hWnd dw ?
+ mciowin_wReserved1 dw ?
+ mciowin_nCmdShow dw ?
+ mciowin_wReserved2 dw ?
+ mciowin_lpstrText dd ?
+MCI_OVLY_WINDOW_PARMS ends
+
+; parameter block for MCI_PUT, MCI_UPDATE, and MCI_WHERE command messages
+MCI_OVLY_RECT_PARMS struc
+ mciorect_dwCallback dd ?
+ifdef MCI_USE_OFFEXT
+ mciorect_ptOffset db (SIZE POINT) dup (?)
+ mciorect_ptExtent db (SIZE POINT) dup (?)
+else ;ifdef MCI_USE_OFFEXT
+ mciorect_rc db (SIZE RECT) dup (?)
+endif ;ifdef MCI_USE_OFFEXT
+MCI_OVLY_RECT_PARMS ends
+
+; parameter block for MCI_SAVE command message
+MCI_OVLY_SAVE_PARMS struc
+ mciosave_dwCallback dd ?
+ mciosave_lpfilename dd ?
+ mciosave_rc db (SIZE RECT) dup (?)
+MCI_OVLY_SAVE_PARMS ends
+
+; parameter block for MCI_LOAD command message
+MCI_OVLY_LOAD_PARMS struc
+ mcioload_dwCallback dd ?
+ mcioload_lpfilename dd ?
+ mcioload_rc db (SIZE RECT) dup (?)
+MCI_OVLY_LOAD_PARMS ends
+
+endif ;ifndef MMNOMCI
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; DISPLAY Driver extensions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ifndef C1_TRANSPARENT
+ CAPS1 equ 94 ; other caps
+ C1_TRANSPARENT equ 0001h ; new raster cap
+ NEWTRANSPARENT equ 3 ; use with SetBkMode()
+
+ QUERYROPSUPPORT equ 40 ; use to determine ROP support
+endif ;ifndef C1_TRANSPARENT
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; DIB Driver extensions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+SELECTDIB equ 41 ; DIB.DRV select dib escape
+DIBINDEX MACRO a
+ mov ax,a
+ mov dx,10ffh
+ ENDM
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; ScreenSaver support
+;
+; The current application will receive a syscommand of SC_SCREENSAVE just
+; before the screen saver is invoked. If the app wishes to prevent a
+; screen save, return non-zero value, otherwise call DefWindowProc().
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ifndef SC_SCREENSAVE
+
+ SC_SCREENSAVE equ 0F140h
+
+endif ;ifndef SC_SCREENSAVE
diff --git a/private/mvdm/wow16/inc/multires.h b/private/mvdm/wow16/inc/multires.h
new file mode 100644
index 000000000..0cc669ccc
--- /dev/null
+++ b/private/mvdm/wow16/inc/multires.h
@@ -0,0 +1,71 @@
+/************************************************************************/
+/* */
+/* MultiRes.H */
+/* */
+/* This contains the data structures of the new format */
+/* for the resources; */
+/* */
+/* History: */
+/* Created Nov, 1988 by Sankar */
+/* */
+/************************************************************************/
+
+
+
+/* The width of the name field in the Data for the group resources */
+#define NAMELEN 14
+
+/* The bits per pixel can be 1, 4, 8 or 24 in the PM bitmap format */
+#define MAXBITSPERPIXEL 24
+
+#define DEVICEDEP 1
+#define DEVICEINDEP 2
+
+
+/* Header of the resource file in the new format */
+
+struct tagNEWHEADER
+{
+ WORD Reserved;
+ WORD ResType;
+ WORD ResCount;
+};
+
+typedef struct tagNEWHEADER FAR *LPNEWHEADER;
+
+struct tagICONDIR
+{
+ BYTE Width; /* 16, 32, 64 */
+ BYTE Height; /* 16, 32, 64 */
+ BYTE ColorCount; /* 2, 8, 16 */
+ BYTE reserved;
+};
+
+struct tagCURSORDIR
+{
+ WORD Width;
+ WORD Height;
+};
+
+
+/* Structure of each entry in resource directory */
+
+struct tagRESDIR
+{
+ union
+ {
+ struct tagICONDIR Icon;
+ struct tagCURSORDIR Cursor;
+ } ResInfo;
+
+ WORD Planes;
+ WORD BitCount;
+ DWORD BytesInRes;
+ WORD idIcon;
+};
+
+typedef struct tagRESDIR FAR *LPRESDIR;
+
+typedef BITMAPINFOHEADER *PBMPHEADER;
+typedef BITMAPINFOHEADER FAR *LPBMPHEADER;
+
diff --git a/private/mvdm/wow16/inc/newexe.inc b/private/mvdm/wow16/inc/newexe.inc
new file mode 100644
index 000000000..6aad0a98f
--- /dev/null
+++ b/private/mvdm/wow16/inc/newexe.inc
@@ -0,0 +1,332 @@
+savedCS = 4
+savedIP = 2
+savedBP = 0
+savedDS = -2
+
+EMAGIC = 05A4Dh
+ERESWDS = 0010h
+ENEWHDR = 003Eh
+ENEWEXE = 0040h
+
+EXE_HDR STRUC
+e_magic DW ? ; magic in same location
+e_cblp DW ?
+e_cp DW ?
+e_crlc DW ?
+e_cparhdr DW ?
+e_minalloc DW ?
+e_maxalloc DW ?
+e_ss DW ?
+e_sp DW ?
+e_csum DW ?
+e_cs DW ?
+e_ip DW ?
+e_lfarlc DW ?
+e_ovno DW ?
+e_res DW ERESWDS DUP (?)
+e_lfanew DD ?
+EXE_HDR ENDS
+
+
+NEMAGIC = 454Eh
+NERESBYTES = 0
+
+NEW_EXE STRUC
+ne_magic DW ? ; Magic value 'NE'
+ne_ver DB ? ; version number
+ne_rev DB ? ; revision number
+ne_enttab DW ? ; offset to entry table
+ne_cbenttab DW ? ; number of bytes in entry table
+
+ne_crc DD ? ; CRC of file
+
+ne_flags DW ? ; flag word
+ne_autodata DW ? ; segment number of auto data segment
+ne_heap DW ? ; initial size of local heap
+ne_stack DW ? ; initial size of stack
+
+ne_csip DD ? ; CS:IP start address
+ne_sssp DD ? ; SS:SP initial stack pointer. 0 if
+ ; stack size word non-zero
+
+ne_cseg DW ? ; number of segment in segment table
+ne_cmod DW ? ; number of entries in module reference table
+ne_cbnrestab DW ? ; number of bytes in non-resident name table
+
+ne_segtab DW ? ; NE relative offset to segment table
+ne_rsrctab DW ? ; NE relative offset to resource table
+ne_restab DW ? ; NE relative offset to resident name table
+ne_modtab DW ? ; NE relative offset to module reference table
+ne_imptab DW ? ; NE relative offset to imported name table
+ne_nrestab DD ? ; file offset to non-resident name table
+ne_cmovent DW ? ; Count of movable entries
+ne_align DW ? ; Alignment shift count for segment data
+ne_cres DW ? ; Count of resource segments
+ne_exetyp DB ? ; Target operating system
+ne_flagsothers DB ? ; Other .EXE flags
+ne_pretthunks DW ? ; offset to return thunks
+ne_psegrefbytes DW ? ; offset to segment ref. bytes
+ne_swaparea DW ? ; Minimum code swap area size
+ne_expver DW ? ; Expected Windows version number
+NEW_EXE ENDS
+
+; Chksum not supported unless ne_psegcsum defined in NEW_EXE structure
+
+ne_psegcsum = word ptr ne_exetyp
+ne_onextexe = word ptr ne_crc
+
+; New 3.0 Gang Load area description
+
+ne_gang_start = ne_pretthunks
+ne_gang_length = ne_psegrefbytes
+
+NEW_EXE1 STRUC
+ DW ?
+ne_usage DW ?
+ DW ?
+ne_pnextexe DW ?
+ne_pautodata DW ?
+ne_pfileinfo DW ?
+NEW_EXE1 ENDS
+
+NENOTP = 8000h ; Not a process (i.e. a library module)
+NEPRIVLIB = 4000h ; A library which lives above the line
+NEIERR = 2000h ; Errors in image
+NEAPPTYP = 0700h ; Application type mask
+NENOTWINCOMPAT = 0100h ; Not compatible with P.M. Windowing
+NEWINCOMPAT = 0200h ; Compatible with P.M. Windowing
+NEWINAPI = 0300h ; Uses P.M. Windowing API
+NEFLTP = 0080h ; Floating-point instructions
+NEI386 = 0040h ; 386 instructions
+NEI286 = 0020h ; 286 instructions
+NEI086 = 0010h ; 8086 instructions
+NEPROT = 0008h ; Runs in protected mode only
+NEPPLI = 0004h ; Per-Process Library Initialization
+NEINST = 0002h ; Instance data
+NESOLO = 0001h ; Solo data
+
+; Below are the private bits used by the Windows 2.0 loader. All are
+; in the file, with the exception of NENONRES and NEWINPROT which are
+; runtime only flags.
+;
+
+NEWINPROT = NEIERR
+NENONRES = NEFLTP ; Contains non-resident code segments
+NEALLOCHIGH = NEI386 ; Private allocs above the line okay
+NEEMSSEPINST = NEI286 ; Want each instance in separate
+NELIM32 = NEI086 ; Uses LIM 3.2 API (Intel Above board)
+
+; Following private bit is a runtime only flag used only ROM Windows.
+
+NEMODINROM = NEEMSSEPINST ; Module loaded from ROM
+
+;
+; Format of NE_FLAGSOTHERS(x):
+;
+; 7 6 5 4 3 2 1 0 - bit no
+; | | | |
+; | | | +---------------- Support for long file names
+; | | +------------------ 2.x app runs in protect mode
+; | +-------------------- 2.x app gets prop. font
+; +---------------------- Contains gangload area
+;
+
+NELONGNAMES = 1h
+NEINFONT = 2h ; WIN30 - 2.x app runs in 3.x prot mode
+NEINPROT = 4h ; WIN30 - 2.x app gets proportional font
+NEGANGLOAD = 8h ; WIN30 - Contains gangload area
+NEASSUMENODEP = 10h ; WIN40 - DllEntryPoint known not to exit
+NEINTLAPP = 40h ; WIN31 - intl versions use this.
+NEHASPATCH = 80h ; WIN40 - Some segs of this module get patched
+
+; Target operating systems
+
+NE_UNKNOWN = 0 ; Unknown (any "new-format" OS)
+NE_OS2 = 1 ; Microsoft/IBM OS/2 (default)
+NE_WINDOWS = 2 ; Microsoft Windows
+NE_DOS4 = 3 ; Microsoft MS-DOS 4.x
+NE_DEV386 = 4 ; Microsoft Windows 386
+
+
+ifndef NO_APPLOADER
+NEAPPLOADER = 0800h ; set if application has its own loader
+endif ;!NO_APPLOADER
+
+
+NEW_SEG STRUC
+ns_sector DW ? ; logical sector number in file of start of segment
+ns_cbseg DW ? ; number bytes in file
+ns_flags DW ? ; segment flags
+ns_minalloc DW ? ; minimum number bytes to allocate for segment
+NEW_SEG ENDS
+
+NEW_SEG1 STRUC
+ DB SIZE NEW_SEG DUP (?)
+ns_handle DW ? ; Handle to segment (0 if not loaded)
+NEW_SEG1 ENDS
+
+NSTYPE = 0007h ; Segment type mask
+NSCODE = 0000h ; Code segment
+NSDATA = 0001h ; Data segment
+NSITER = 0008h ; Iterated segment data
+NSMOVE = 0010h ; Moveable segment
+NSSHARE = 0020h ; Shareable segment
+NSPRELOAD = 0040h ; Preload this segment
+NSERONLY = 0080h ; EXECUTE ONLY code/READ ONLY data segment
+NSRELOC = 0100h ; Relocation information following segment data
+NSDPL = 0C00h ; 286 DPL bits
+NSDISCARD = 1000h ; Discard priority bits
+NS286DOS = 0EE06h ; These bits only used by 286DOS
+
+NSALIGN = 9 ; Default alignment shift count for seg. data
+
+NSALLOCED = 0002h ; set if ns_handle points to uninitialized mem.
+NSLOADED = 0004h ; set if ns_handle points to initialized mem.
+NSUSESDATA = 0400h ; set if an entry point in this segment uses
+ ; the automatic data segment of a SOLO library
+
+NSGETHIGH = 0200h
+NSINDIRECT = 2000h
+NSWINCODE = 4000h ; flag for code
+
+NSKCACHED = 0800h ; cached by kernel
+NSPRIVLIB = NSITER
+NSNOTP = 8000h
+
+NSINROM = NSINDIRECT ; segment is loaded in ROM
+NSCOMPR = NSGETHIGH ; segment is compressed in ROM
+
+ifndef NO_APPLOADER
+NSCACHED = 8000h ;* in AppLoader Cache
+endif ;!NO_APPLOADER
+
+
+NEW_RSRC STRUC
+rs_align DW ?
+NEW_RSRC ENDS
+
+RSORDID = 08000h ; If high bit of rt_id or rn_id set then integer id
+
+RSRC_TYPEINFO STRUC
+rt_id DW ?
+rt_nres DW ?
+rt_proc DD ?
+RSRC_TYPEINFO ENDS
+
+RSRC_NAMEINFO STRUC
+rn_offset DW ?
+rn_length DW ?
+rn_flags DW ?
+rn_id DW ?
+rn_handle DW ?
+rn_usage DW ?
+RSRC_NAMEINFO ENDS
+RNMOVE = 00010h ; Moveable resource
+RNPURE = 00020h ; Pure resource (read only)
+RNPRELOAD = 00040h ; Preload this resource
+RNDISCARD = 01000h ; Discard bit
+RNLOADED = 00004h ; True if handler proc return handle
+RNCOMPR = 00200h ; Resource is compressed in ROM
+RNINROM = 02000h ; Resource is loaded in ROM (run time flag)
+
+RNUNUSED = 0CD8Bh ; Unused resource flags
+
+ENTFIXED STRUC
+entflags DB ?
+entoffset DW ?
+ENTFIXED ENDS
+
+if SWAPPRO
+
+ENTMOVEABLE STRUC
+ DB ? ; Entry flags
+entsar DB 5 DUP (?) ; sar cs:[xxxx] instruction
+ DW ? ; INT 0F0H for swap profiler
+entjmpfarop DB ?
+entjmpfaroff DW ?
+entjmpfarseg DW ?
+ENTMOVEABLE ENDS
+
+ENTSWAPPED STRUC
+ DB ? ; Entry flags
+ DB 5 DUP (?) ; sar cs:[xxxx] instruction
+ DW ? ; INT 0F0H for swap profiler
+entintop DB ?
+entintvec DB ?
+entintsegno DB ?
+entintoff DW ?
+ENTSWAPPED ENDS
+
+else ; no swap profiler
+
+ENTMOVEABLE STRUC
+ DB ? ; Entry flags
+entsar DB 5 DUP (?) ; sar cs:[xxxx] instruction
+entjmpfarop DB ?
+entjmpfaroff DW ?
+entjmpfarseg DW ?
+ENTMOVEABLE ENDS
+
+ENTSWAPPED STRUC
+ DB ? ; Entry flags
+ DB 5 DUP (?) ; sar cs:[xxxx] instruction
+entintop DB ?
+entintvec DB ?
+entintsegno DB ?
+entintoff DW ?
+ENTSWAPPED ENDS
+
+endif ; if swap profiler
+
+errnz <SIZE ENTMOVEABLE - SIZE ENTSWAPPED>
+
+PENT STRUC
+penttype DB ?
+pentflags DB ?
+pentsegno DB ?
+pentoffset DW ?
+PENT ENDS
+
+PM_EntStruc STRUC
+PM_EntStart dw ?
+PM_EntEnd dw ?
+PM_EntNext dw ?
+PM_EntStruc ENDS
+
+ENT_UNUSED = 000h
+ENT_ABSSEG = 0FEh
+ENT_MOVEABLE = 0FFh
+ENT_PUBLIC = 001h
+ENT_DATA = 002h
+INTOPCODE = 0CDh
+
+if SWAPPRO
+SWAPVECTOR = 0F0h
+endif
+
+NEW_RLCINFO STRUC
+nr_nreloc DW ?
+NEW_RLCINFO ENDS
+
+NEW_RLC STRUC
+nr_stype DB ?
+nr_flags DB ?
+nr_soff DW ?
+nr_mod DW ?
+nr_proc DW ?
+NEW_RLC ENDS
+nr_segno EQU nr_flags+3
+nr_entry EQU nr_proc
+
+NRSTYP = 07h
+NRSBYTE = 00h
+NRSSEG = 02h
+NRSPTR = 03h
+NRSOFF = 05h
+
+NRADD = 04h
+NRRTYP = 03h
+NRRINT = 00h
+NRRORD = 01h
+NRRNAM = 02h
+OSFIXUP = 03h
diff --git a/private/mvdm/wow16/inc/ole.h b/private/mvdm/wow16/inc/ole.h
new file mode 100644
index 000000000..37bcf9cad
--- /dev/null
+++ b/private/mvdm/wow16/inc/ole.h
@@ -0,0 +1,504 @@
+/*****************************************************************************\
+* *
+* ole.h - Object Linking and Embedding functions, types, and definitions*
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1990-1992, Microsoft Corp. All rights reserved.*
+* *
+\*****************************************************************************/
+
+#ifndef _INC_OLE
+#define _INC_OLE
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef WINAPI /* If not included with 3.1 headers... */
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+#ifdef STRICT
+#define OLE_LPCSTR LPCSTR
+#define OLE_CONST const
+#else /* STRICT */
+#define OLE_LPCSTR LPSTR
+#define OLE_CONST
+#endif /* !STRICT */
+
+
+/* Object types */
+#define OT_LINK 1L
+#define OT_EMBEDDED 2L
+#define OT_STATIC 3L
+
+/* activate verbs */
+#define OLEVERB_PRIMARY 0
+
+/* target device info structure */
+typedef struct _OLETARGETDEVICE
+{
+ UINT otdDeviceNameOffset;
+ UINT otdDriverNameOffset;
+ UINT otdPortNameOffset;
+ UINT otdExtDevmodeOffset;
+ UINT otdExtDevmodeSize;
+ UINT otdEnvironmentOffset;
+ UINT otdEnvironmentSize;
+ BYTE otdData[1];
+} OLETARGETDEVICE;
+typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE;
+
+/* flags used in some methods */
+#define OF_SET 0x0001
+#define OF_GET 0x0002
+#define OF_HANDLER 0x0004
+
+/* return codes for OLE functions */
+typedef enum
+{
+ OLE_OK, /* 0 Function operated correctly */
+
+ OLE_WAIT_FOR_RELEASE, /* 1 Command has been initiated, client */
+ /* must wait for release. keep dispatching */
+ /* messages till OLE_RELESE in callback */
+
+ OLE_BUSY, /* 2 Tried to execute a method while another */
+ /* method is in progress. */
+
+ OLE_ERROR_PROTECT_ONLY, /* 3 Ole APIs are called in real mode */
+ OLE_ERROR_MEMORY, /* 4 Could not alloc or lock memory */
+ OLE_ERROR_STREAM, /* 5 (OLESTREAM) stream error */
+ OLE_ERROR_STATIC, /* 6 Non static object expected */
+ OLE_ERROR_BLANK, /* 7 Critical data missing */
+ OLE_ERROR_DRAW, /* 8 Error while drawing */
+ OLE_ERROR_METAFILE, /* 9 Invalid metafile */
+ OLE_ERROR_ABORT, /* 10 Client chose to abort metafile drawing */
+ OLE_ERROR_CLIPBOARD, /* 11 Failed to get/set clipboard data */
+ OLE_ERROR_FORMAT, /* 12 Requested format is not available */
+ OLE_ERROR_OBJECT, /* 13 Not a valid object */
+ OLE_ERROR_OPTION, /* 14 Invalid option(link update / render) */
+ OLE_ERROR_PROTOCOL, /* 15 Invalid protocol */
+ OLE_ERROR_ADDRESS, /* 16 One of the pointers is invalid */
+ OLE_ERROR_NOT_EQUAL, /* 17 Objects are not equal */
+ OLE_ERROR_HANDLE, /* 18 Invalid handle encountered */
+ OLE_ERROR_GENERIC, /* 19 Some general error */
+ OLE_ERROR_CLASS, /* 20 Invalid class */
+ OLE_ERROR_SYNTAX, /* 21 Command syntax is invalid */
+ OLE_ERROR_DATATYPE, /* 22 Data format is not supported */
+ OLE_ERROR_PALETTE, /* 23 Invalid color palette */
+ OLE_ERROR_NOT_LINK, /* 24 Not a linked object */
+ OLE_ERROR_NOT_EMPTY, /* 25 Client doc contains objects. */
+ OLE_ERROR_SIZE, /* 26 Incorrect buffer size passed to the api */
+ /* that places some string in caller's */
+ /* buffer */
+
+ OLE_ERROR_DRIVE, /* 27 Drive letter in doc name is invalid */
+ OLE_ERROR_NETWORK, /* 28 Failed to establish connection to a */
+ /* network share on which the document */
+ /* is located */
+
+ OLE_ERROR_NAME, /* 29 Invalid name(doc name, object name), */
+ /* etc.. passed to the APIs */
+
+ OLE_ERROR_TEMPLATE, /* 30 Server failed to load template */
+ OLE_ERROR_NEW, /* 31 Server failed to create new doc */
+ OLE_ERROR_EDIT, /* 32 Server failed to create embedded */
+ /* instance */
+ OLE_ERROR_OPEN, /* 33 Server failed to open document, */
+ /* possible invalid link */
+
+ OLE_ERROR_NOT_OPEN, /* 34 Object is not open for editing */
+ OLE_ERROR_LAUNCH, /* 35 Failed to launch server */
+ OLE_ERROR_COMM, /* 36 Failed to communicate with server */
+ OLE_ERROR_TERMINATE, /* 37 Error in termination */
+ OLE_ERROR_COMMAND, /* 38 Error in execute */
+ OLE_ERROR_SHOW, /* 39 Error in show */
+ OLE_ERROR_DOVERB, /* 40 Error in sending do verb, or invalid */
+ /* verb */
+ OLE_ERROR_ADVISE_NATIVE, /* 41 Item could be missing */
+ OLE_ERROR_ADVISE_PICT, /* 42 Item could be missing or server doesn't */
+ /* this format. */
+
+ OLE_ERROR_ADVISE_RENAME, /* 43 Server doesn't support rename */
+ OLE_ERROR_POKE_NATIVE, /* 44 Failure of poking native data to server */
+ OLE_ERROR_REQUEST_NATIVE, /* 45 Server failed to render native data */
+ OLE_ERROR_REQUEST_PICT, /* 46 Server failed to render presentation */
+ /* data */
+ OLE_ERROR_SERVER_BLOCKED, /* 47 Trying to block a blocked server or */
+ /* trying to revoke a blocked server */
+ /* or document */
+
+ OLE_ERROR_REGISTRATION, /* 48 Server is not registered in regestation */
+ /* data base */
+ OLE_ERROR_ALREADY_REGISTERED,/*49 Trying to register same doc multiple */
+ /* times */
+ OLE_ERROR_TASK, /* 50 Server or client task is invalid */
+ OLE_ERROR_OUTOFDATE, /* 51 Object is out of date */
+ OLE_ERROR_CANT_UPDATE_CLIENT,/* 52 Embed doc's client doesn't accept */
+ /* updates */
+ OLE_ERROR_UPDATE, /* 53 erorr while trying to update */
+ OLE_ERROR_SETDATA_FORMAT, /* 54 Server app doesn't understand the */
+ /* format given to its SetData method */
+ OLE_ERROR_STATIC_FROM_OTHER_OS,/* 55 trying to load a static object created */
+ /* on another Operating System */
+
+ /* Following are warnings */
+ OLE_WARN_DELETE_DATA = 1000 /* Caller must delete the data when he is */
+ /* done with it. */
+} OLESTATUS;
+
+
+
+/* Codes for CallBack events */
+typedef enum
+{
+ OLE_CHANGED, /* 0 */
+ OLE_SAVED, /* 1 */
+ OLE_CLOSED, /* 2 */
+ OLE_RENAMED, /* 3 */
+ OLE_QUERY_PAINT, /* 4 Interruptible paint support */
+ OLE_RELEASE, /* 5 Object is released(asynchronous operation */
+ /* is completed) */
+ OLE_QUERY_RETRY /* 6 Query for retry when server sends busy ACK */
+} OLE_NOTIFICATION;
+
+typedef enum
+{
+ OLE_NONE, /* 0 no method active */
+ OLE_DELETE, /* 1 object delete */
+ OLE_LNKPASTE, /* 2 PasteLink(auto reconnect) */
+ OLE_EMBPASTE, /* 3 paste(and update) */
+ OLE_SHOW, /* 4 Show */
+ OLE_RUN, /* 5 Run */
+ OLE_ACTIVATE, /* 6 Activate */
+ OLE_UPDATE, /* 7 Update */
+ OLE_CLOSE, /* 8 Close */
+ OLE_RECONNECT, /* 9 Reconnect */
+ OLE_SETUPDATEOPTIONS, /* 10 setting update options */
+ OLE_SERVERUNLAUNCH, /* 11 server is being unlaunched */
+ OLE_LOADFROMSTREAM, /* 12 LoadFromStream(auto reconnect) */
+ OLE_SETDATA, /* 13 OleSetData */
+ OLE_REQUESTDATA, /* 14 OleRequestData */
+ OLE_OTHER, /* 15 other misc async operations */
+ OLE_CREATE, /* 16 create */
+ OLE_CREATEFROMTEMPLATE, /* 17 CreatefromTemplate */
+ OLE_CREATELINKFROMFILE, /* 18 CreateLinkFromFile */
+ OLE_COPYFROMLNK, /* 19 CopyFromLink(auto reconnect) */
+ OLE_CREATEFROMFILE, /* 20 CreateFromFile */
+ OLE_CREATEINVISIBLE /* 21 CreateInvisible */
+} OLE_RELEASE_METHOD;
+
+/* rendering options */
+typedef enum
+{
+ olerender_none,
+ olerender_draw,
+ olerender_format
+} OLEOPT_RENDER;
+
+/* standard clipboard format type */
+typedef WORD OLECLIPFORMAT;
+
+/* Link update options */
+typedef enum
+{
+ oleupdate_always,
+ oleupdate_onsave,
+#ifndef OLE_INTERNAL
+ oleupdate_oncall
+#else
+ oleupdate_oncall,
+ oleupdate_onclose
+#endif /* OLE_INTERNAL */
+} OLEOPT_UPDATE;
+
+typedef HANDLE HOBJECT;
+typedef LONG LHSERVER;
+typedef LONG LHCLIENTDOC;
+typedef LONG LHSERVERDOC;
+
+typedef struct _OLEOBJECT FAR* LPOLEOBJECT;
+typedef struct _OLESTREAM FAR* LPOLESTREAM;
+typedef struct _OLECLIENT FAR* LPOLECLIENT;
+
+
+#ifndef OLE_INTERNAL
+/* object method table definitions. */
+typedef struct _OLEOBJECTVTBL
+{
+ void FAR* (CALLBACK* QueryProtocol) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* Release) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Show) (LPOLEOBJECT, BOOL);
+ OLESTATUS (CALLBACK* DoVerb) (LPOLEOBJECT, UINT, BOOL, BOOL);
+ OLESTATUS (CALLBACK* GetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+ OLESTATUS (CALLBACK* SetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+ OLESTATUS (CALLBACK* SetTargetDevice) (LPOLEOBJECT, HGLOBAL);
+ OLESTATUS (CALLBACK* SetBounds) (LPOLEOBJECT, OLE_CONST RECT FAR*);
+ OLECLIPFORMAT (CALLBACK* EnumFormats) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* SetColorScheme) (LPOLEOBJECT, OLE_CONST LOGPALETTE FAR*);
+ /* Server has to implement only the above methods. */
+
+#ifndef SERVERONLY
+ /* Extra methods required for client. */
+ OLESTATUS (CALLBACK* Delete) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* SetHostNames) (LPOLEOBJECT, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SaveToStream) (LPOLEOBJECT, LPOLESTREAM);
+ OLESTATUS (CALLBACK* Clone) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* CopyFromLink) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* Equal) (LPOLEOBJECT, LPOLEOBJECT);
+ OLESTATUS (CALLBACK* CopyToClipboard) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Draw) (LPOLEOBJECT, HDC, OLE_CONST RECT FAR*, OLE_CONST RECT FAR*, HDC);
+ OLESTATUS (CALLBACK* Activate) (LPOLEOBJECT, UINT, BOOL, BOOL, HWND, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLEOBJECT, HGLOBAL, UINT);
+ OLESTATUS (CALLBACK* Close) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Update) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Reconnect) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* ObjectConvert) (LPOLEOBJECT, OLE_LPCSTR, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* GetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+ OLESTATUS (CALLBACK* SetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE);
+
+ OLESTATUS (CALLBACK* Rename) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* QueryName) (LPOLEOBJECT, LPSTR, UINT FAR*);
+
+ OLESTATUS (CALLBACK* QueryType) (LPOLEOBJECT, LONG FAR*);
+ OLESTATUS (CALLBACK* QueryBounds) (LPOLEOBJECT, RECT FAR*);
+ OLESTATUS (CALLBACK* QuerySize) (LPOLEOBJECT, DWORD FAR*);
+ OLESTATUS (CALLBACK* QueryOpen) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryOutOfDate) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* QueryReleaseStatus) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryReleaseError) (LPOLEOBJECT);
+ OLE_RELEASE_METHOD (CALLBACK* QueryReleaseMethod)(LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* RequestData) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* ObjectLong) (LPOLEOBJECT, UINT, LONG FAR*);
+
+/* This method is internal only */
+ OLESTATUS (CALLBACK* ChangeData) (LPOLEOBJECT, HANDLE, LPOLECLIENT, BOOL);
+#endif /* !SERVERONLY */
+} OLEOBJECTVTBL;
+typedef OLEOBJECTVTBL FAR* LPOLEOBJECTVTBL;
+
+typedef struct _OLEOBJECT
+{
+ LPOLEOBJECTVTBL lpvtbl;
+} OLEOBJECT;
+#endif /* !OLE_NTERNAL */
+
+/* ole client definitions */
+typedef struct _OLECLIENTVTBL
+{
+ int (CALLBACK* CallBack)(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT);
+} OLECLIENTVTBL;
+
+typedef OLECLIENTVTBL FAR* LPOLECLIENTVTBL;
+
+typedef struct _OLECLIENT
+{
+ LPOLECLIENTVTBL lpvtbl;
+} OLECLIENT;
+
+/* Stream definitions */
+typedef struct _OLESTREAMVTBL
+{
+ DWORD (CALLBACK* Get)(LPOLESTREAM, void FAR*, DWORD);
+ DWORD (CALLBACK* Put)(LPOLESTREAM, OLE_CONST void FAR*, DWORD);
+} OLESTREAMVTBL;
+typedef OLESTREAMVTBL FAR* LPOLESTREAMVTBL;
+
+typedef struct _OLESTREAM
+{
+ LPOLESTREAMVTBL lpstbl;
+} OLESTREAM;
+
+/* Public Function Prototypes */
+OLESTATUS WINAPI OleDelete(LPOLEOBJECT);
+OLESTATUS WINAPI OleRelease(LPOLEOBJECT);
+OLESTATUS WINAPI OleSaveToStream(LPOLEOBJECT, LPOLESTREAM);
+OLESTATUS WINAPI OleEqual(LPOLEOBJECT, LPOLEOBJECT );
+OLESTATUS WINAPI OleCopyToClipboard(LPOLEOBJECT);
+OLESTATUS WINAPI OleSetHostNames(LPOLEOBJECT, LPCSTR, LPCSTR);
+OLESTATUS WINAPI OleSetTargetDevice(LPOLEOBJECT, HGLOBAL);
+OLESTATUS WINAPI OleSetBounds(LPOLEOBJECT, const RECT FAR*);
+OLESTATUS WINAPI OleSetColorScheme(LPOLEOBJECT, const LOGPALETTE FAR*);
+OLESTATUS WINAPI OleQueryBounds(LPOLEOBJECT, RECT FAR*);
+OLESTATUS WINAPI OleQuerySize(LPOLEOBJECT, DWORD FAR*);
+OLESTATUS WINAPI OleDraw(LPOLEOBJECT, HDC, const RECT FAR*, const RECT FAR*, HDC);
+OLESTATUS WINAPI OleQueryOpen(LPOLEOBJECT);
+OLESTATUS WINAPI OleActivate(LPOLEOBJECT, UINT, BOOL, BOOL, HWND, const RECT FAR*);
+OLESTATUS WINAPI OleExecute(LPOLEOBJECT, HGLOBAL, UINT);
+OLESTATUS WINAPI OleClose(LPOLEOBJECT);
+OLESTATUS WINAPI OleUpdate(LPOLEOBJECT);
+OLESTATUS WINAPI OleReconnect(LPOLEOBJECT);
+OLESTATUS WINAPI OleGetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+OLESTATUS WINAPI OleSetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE);
+void FAR* WINAPI OleQueryProtocol(LPOLEOBJECT, LPCSTR);
+
+/* Routines related to asynchronous operations. */
+OLESTATUS WINAPI OleQueryReleaseStatus(LPOLEOBJECT);
+OLESTATUS WINAPI OleQueryReleaseError(LPOLEOBJECT);
+OLE_RELEASE_METHOD WINAPI OleQueryReleaseMethod(LPOLEOBJECT);
+
+OLESTATUS WINAPI OleQueryType(LPOLEOBJECT, LONG FAR*);
+
+/* LOWORD is major version, HIWORD is minor version */
+DWORD WINAPI OleQueryClientVersion(void);
+DWORD WINAPI OleQueryServerVersion(void);
+
+/* Converting to format (as in clipboard): */
+OLECLIPFORMAT WINAPI OleEnumFormats(LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS WINAPI OleGetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+OLESTATUS WINAPI OleSetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS WINAPI OleQueryOutOfDate(LPOLEOBJECT);
+OLESTATUS WINAPI OleRequestData(LPOLEOBJECT, OLECLIPFORMAT);
+
+/* Query apis for creation from clipboard */
+OLESTATUS WINAPI OleQueryLinkFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleQueryCreateFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+
+/* Object creation functions */
+OLESTATUS WINAPI OleCreateFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleLoadFromStream(LPOLESTREAM, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCreate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateInvisible(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+OLESTATUS WINAPI OleCreateFromTemplate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleClone(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCopyFromLink(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleObjectConvert(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleRename(LPOLEOBJECT, LPCSTR);
+OLESTATUS WINAPI OleQueryName(LPOLEOBJECT, LPSTR, UINT FAR*);
+OLESTATUS WINAPI OleRevokeObject(LPOLECLIENT);
+BOOL WINAPI OleIsDcMeta(HDC);
+
+/* client document API */
+OLESTATUS WINAPI OleRegisterClientDoc(LPCSTR, LPCSTR, LONG, LHCLIENTDOC FAR*);
+OLESTATUS WINAPI OleRevokeClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleRenameClientDoc(LHCLIENTDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleSavedClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleEnumObjects(LHCLIENTDOC, LPOLEOBJECT FAR*);
+
+/* server usage definitions */
+typedef enum {
+ OLE_SERVER_MULTI, /* multiple instances */
+ OLE_SERVER_SINGLE /* single instance(multiple document) */
+} OLE_SERVER_USE;
+
+/* Server API */
+typedef struct _OLESERVER FAR* LPOLESERVER;
+
+OLESTATUS WINAPI OleRegisterServer(LPCSTR, LPOLESERVER, LHSERVER FAR*, HINSTANCE, OLE_SERVER_USE);
+OLESTATUS WINAPI OleRevokeServer(LHSERVER);
+OLESTATUS WINAPI OleBlockServer(LHSERVER);
+OLESTATUS WINAPI OleUnblockServer(LHSERVER, BOOL FAR*);
+
+/* APIs to keep server open */
+OLESTATUS WINAPI OleLockServer(LPOLEOBJECT, LHSERVER FAR*);
+OLESTATUS WINAPI OleUnlockServer(LHSERVER);
+
+/* Server document API */
+
+typedef struct _OLESERVERDOC FAR* LPOLESERVERDOC;
+
+OLESTATUS WINAPI OleRegisterServerDoc(LHSERVER, LPCSTR, LPOLESERVERDOC, LHSERVERDOC FAR*);
+OLESTATUS WINAPI OleRevokeServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleRenameServerDoc(LHSERVERDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleSavedServerDoc(LHSERVERDOC);
+
+typedef struct _OLESERVERVTBL
+{
+ OLESTATUS (CALLBACK* Open) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* document name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Create)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* CreateFromTemplate)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* lp template name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Edit) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Exit) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Release) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Execute)(LPOLESERVER, HGLOBAL);
+ /* lp OLESERVER */
+ /* handle to command strings */
+} OLESERVERVTBL;
+typedef OLESERVERVTBL FAR* LPOLESERVERVTBL;
+
+typedef struct _OLESERVER
+{
+ LPOLESERVERVTBL lpvtbl;
+} OLESERVER;
+
+typedef struct _OLESERVERDOCVTBL
+{
+ OLESTATUS (CALLBACK* Save) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* Close) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetHostNames)(LPOLESERVERDOC, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SetDocDimensions)(LPOLESERVERDOC, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* GetObject) (LPOLESERVERDOC, OLE_LPCSTR, LPOLEOBJECT FAR*, LPOLECLIENT);
+ OLESTATUS (CALLBACK* Release) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetColorScheme)(LPOLESERVERDOC, OLE_CONST LOGPALETTE FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLESERVERDOC, HGLOBAL);
+} OLESERVERDOCVTBL;
+typedef OLESERVERDOCVTBL FAR* LPOLESERVERDOCVTBL;
+
+typedef struct _OLESERVERDOC
+{
+ LPOLESERVERDOCVTBL lpvtbl;
+} OLESERVERDOC;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_OLE */
diff --git a/private/mvdm/wow16/inc/paswindw.inc b/private/mvdm/wow16/inc/paswindw.inc
new file mode 100644
index 000000000..ab09aef7e
--- /dev/null
+++ b/private/mvdm/wow16/inc/paswindw.inc
@@ -0,0 +1,5327 @@
+TYPE {Standard C types}
+ int = INTEGERC;
+ short = INTEGER;
+ long = INTEGER4;
+ unsigned = WORD;
+ unsignedlong = INTEGER4;
+ LPshort = ADS OF short;
+
+CONST
+ FALSE_ = 0;
+ TRUE_ = 1;
+ NULL_ = 0;
+
+TYPE
+ DWORD = INTEGER4;
+ BOOL = int;
+ PSTR = ADR OF INTEGER1;
+ NPSTR = ADR OF INTEGER1;
+ LPSTR = ADS OF INTEGER1;
+ LPINT = ADS OF int;
+ LPWORD = ADS OF WORD;
+
+CONST
+ OBM_CLOSE = 32767;
+ OBM_SIZE = 32766;
+ OBM_UPARROW = 32765;
+ OBM_DNARROW = 32764;
+ OBM_RGARROW = 32763;
+ OBM_LfarROW = 32762;
+ OBM_BTSIZE = 32761;
+ OBM_CHECK = 32760;
+ OBM_CHECKBOXES = 32759;
+ OBM_BTNCORNERS = 32758;
+ OBM_REDUCE = 32757;
+ OBM_ZOOM = 32756;
+ OBM_RESTORE = 32755;
+ OCR_NORMAL = 32512;
+ OCR_IBEAM = 32513;
+ OCR_WAIT = 32514;
+ OCR_CROSS = 32515;
+ OCR_UP = 32516;
+ OCR_SIZE = 32640;
+ OCR_ICON = 32641;
+ OCR_SIZENWSE = 32642;
+ OCR_SIZENESW = 32643;
+ OCR_SIZEWE = 32644;
+ OCR_SIZENS = 32645;
+ OCR_SIZEALL = 32646;
+
+ OIC_SAMPLE = 32512;
+ OIC_HAND = 32513;
+ OIC_QUES = 32514;
+ OIC_BANG = 32515;
+ OIC_NOTE = 32516;
+
+(* Scroll bar constants *)
+ SB_HORZ = 0;
+ SB_VERT = 1;
+ SB_CTL = 2;
+ SB_BOTH = 3;
+
+(* Scroll Commands *)
+ SB_LINEUP = 0;
+ SB_LINEDOWN = 1;
+ SB_PAGEUP = 2;
+ SB_PAGEDOWN = 3;
+ SB_THUMBPOSITION = 4;
+ SB_THUMBTRACK = 5;
+ SB_TOP = 6;
+ SB_BOTTOM = 7;
+ SB_ENDSCROLL = 8;
+
+(* ShowWindow commands *)
+
+ SW_HIDE = 0;
+ SW_SHOWNORMAL = 1;
+ SW_RESTORE = 1;
+ SW_NORMAL = 1;
+ SW_SHOWMINIMIZED = 2;
+ SW_SHOWMAXIMIZED = 3;
+ SW_MAXIMIZE = 3;
+ SW_SHOWNOACTIVATE = 4;
+ SW_SHOW = 5;
+ SW_MINIMIZE = 6;
+ SW_SHOWMINNOACTIVE = 7;
+ SW_SHOWNA = 8;
+
+
+(* Old ShowWindow commands *)
+ HIDE_WINDOW = 0;
+ SHOW_OPENWINDOW = 1;
+ SHOW_ICONWINDOW = 2;
+ SHOW_FULLSCREEN = 3;
+ SHOW_OPENNOACTIVATE = 4;
+
+(* identifiers for the WM_SHOWWINDOW message *)
+ SW_PARENTCLOSING = 1;
+ SW_OTHERZOOM = 2;
+ SW_PARENTOPENING = 3;
+ SW_OTHERUNZOOM = 4;
+
+(* flags for regions *)
+ ERROR = 0;
+ NULLREGION = 1;
+ SIMPLEREGION = 2;
+ COMPLEXREGION = 3;
+
+(* styles for CombineRgn *)
+ RGN_AND = 1;
+ RGN_OR = 2;
+ RGN_XOR = 3;
+ RGN_DIFF = 4;
+ RGN_COPY = 5;
+
+(* Virtual Keys, Standard Set *)
+
+ VK_LBUTTON = #01;
+ VK_RBUTTON = #02;
+ VK_CANCEL = #03;
+ VK_MBUTTON = #04 (* NOT contiguous with L & RBUTTON *);
+ VK_BACK = #08;
+ VK_TAB = #09;
+ VK_CLEAR = #0c;
+ VK_RETURN = #0d;
+ VK_SHIFT = #10;
+ VK_CONTROL = #11;
+ VK_MENU = #12;
+ VK_PAUSE = #13;
+ VK_CAPITAL = #14;
+ VK_ESCAPE = #1b;
+ VK_SPACE = #20;
+
+ VK_PRIOR = #21;
+ VK_NEXT = #22;
+ VK_END = #23;
+ VK_HOME = #24;
+ VK_LEFT = #25;
+ VK_UP = #26;
+ VK_RIGHT = #27;
+ VK_DOWN = #28;
+
+(* VK_A thru VK_Z are the same as their ASCII equivalents: 'A' thru 'Z' *)
+(* VK_0 thru VK_9 are the same as their ASCII equivalents: '0' thru '0' *)
+
+ VK_SELECT = #29;
+ VK_PRINT = #2a;
+ VK_EXECUTE = #2b;
+ VK_INSERT = #2d;
+ VK_DELETE = #2e;
+ VK_HELP = #2f;
+
+ VK_NUMPAD0 = #60;
+ VK_NUMPAD1 = #61;
+ VK_NUMPAD2 = #62;
+ VK_NUMPAD3 = #63;
+ VK_NUMPAD4 = #64;
+ VK_NUMPAD5 = #65;
+ VK_NUMPAD6 = #66;
+ VK_NUMPAD7 = #67;
+ VK_NUMPAD8 = #68;
+ VK_NUMPAD9 = #69;
+ VK_MULTIPLY = #6A;
+ VK_ADD = #6B;
+ VK_SEPARATOR = #6C;
+ VK_SUBTRACT = #6D;
+ VK_DECIMAL = #6E;
+ VK_DIVIDE = #6F;
+
+ VK_F1 = #70;
+ VK_F2 = #71;
+ VK_F3 = #72;
+ VK_F4 = #73;
+ VK_F5 = #74;
+ VK_F6 = #75;
+ VK_F7 = #76;
+ VK_F8 = #77;
+ VK_F9 = #78;
+ VK_F10 = #79;
+ VK_F11 = #7a;
+ VK_F12 = #7b;
+ VK_F13 = #7c;
+ VK_F14 = #7d;
+ VK_F15 = #7e;
+ VK_F16 = #7f;
+
+ VK_NUMLOCK = #90;
+
+(* SetWindowsHook codes *)
+ WH_MSGFILTER = -1;
+ WH_JOURNALRECORD = 0;
+ WH_JOURNALPLAYBACK = 1;
+ WH_KEYBOARD = 2;
+ WH_GETMESSAGE = 3;
+ WH_CALLWNDPROC = 4;
+ WH_CBT = 5;
+ WH_SYSMSGFILTER = 6;
+ WH_WINDOWMGR = 7;
+
+(* HC_* Hook Codes *)
+ HC_LPLPFNNEXT = -2;
+ HC_LPFNNEXT = -1;
+ HC_ACTION = 0;
+ HC_GETNEXT = 1;
+ HC_SKIP = 2;
+ HC_NOREM = 3;
+
+(* CBT hook codes *)
+ HCBT_MOVESIZE = 0;
+ HCBT_MINMAX = 1;
+ HCBT_QS = 2;
+
+
+(* WH_MSGFILTER filter proc codes *)
+ MSGF_DIALOGBOX = 0;
+ MSGF_MESSAGEBOX = 1;
+ MSGF_MENU = 2;
+ MSGF_MOVE = 3;
+ MSGF_SIZE = 4;
+ MSGF_SCROLLBAR = 5;
+ MSGF_NEXTWINDOW = 6;
+
+(* Define window manager hook codes *)
+ WC_INIT = 1;
+ WC_SWP = 2;
+ WC_DEFWINDOWPROC = 3;
+ WC_MINMAX = 4;
+ WC_MOVE = 5;
+ WC_SIZE = 6;
+ WC_DRAWCAPTION = 7;
+
+(* message structure used in journaling *)
+
+TYPE
+
+ EVENTMSG = RECORD
+ message : unsigned;
+ paramL : WORD;
+ paramH : WORD;
+ time : DWORD;
+ END;
+ PEVENTMSGMSG = ADR OF EVENTMSG;
+ NPEVENTMSGMSG = ADR OF EVENTMSG;
+ LPEVENTMSGMSG = ADS OF EVENTMSG;
+
+CONST
+
+(* Binary raster ops *)
+ R2_BLACK = 1 (* 0 *);
+ R2_NOTMERGEPEN = 2 (* DPon *);
+ R2_MASKNOTPEN = 3 (* DPna *);
+ R2_NOTCOPYPEN = 4 (* PN *);
+ R2_MASKPENNOT = 5 (* PDna *);
+ R2_NOT = 6 (* Dn *);
+ R2_XORPEN = 7 (* DPx *);
+ R2_NOTMASKPEN = 8 (* DPan *);
+ R2_MASKPEN = 9 (* DPa *);
+ R2_NOTXORPEN = 10 (* DPxn *);
+ R2_NOP = 11 (* D *);
+ R2_MERGENOTPEN = 12 (* DPno *);
+ R2_COPYPEN = 13 (* P *);
+ R2_MERGEPENNOT = 14 (* PDno *);
+ R2_MERGEPEN = 15 (* DPo *);
+ R2_WHITE = 16 (* 1 *);
+
+(* Ternary raster operations *)
+ SRCCOPY = #00CC0020 (* dest=source *);
+ SRCPAINT = #00EE0086 (* dest=source OR dest *);
+ SRCAND = #008800C6 (* dest = source AND dest *);
+ SRCINVERT = #00660046 (* dest = source XOR dest *);
+ SRCERASE = #00440328 (* dest = source AND (not dest ) *);
+ NOTSRCCOPY = #00330008 (* dest = (not source) *);
+ NOTSRCERASE = #001100A6 (* dest = (not source) AND (not dest) *);
+ MERGECOPY = #00C000CA (* dest = (source AND pattern) *);
+ MERGEPAINT = #00BB0226 (* dest = (NOT source) OR dest *);
+ PATCOPY = #00F00021 (* dest = pattern *);
+ PATPAINT = #00FB0A09 (* dest = DPSnoo *);
+ PATINVERT = #005A0049 (* dest = pattern XOR dest *);
+ DSTINVERT = #00550009 (* dest = (not dest) *);
+ BLACKNESS = #00000042 (* dest = BLACK *);
+ WHITENESS = #00FF0062 (* dest = WHITE *);
+
+(* StretchBlt() modes *)
+ BLACKONWHITE = 1;
+ WHITEONBLACK = 2;
+ COLORONCOLOR = 3;
+
+(* PolyFill modes *)
+ ALTERNATE = 1;
+ WINDING = 2;
+
+(* text alignment options *)
+ TA_UPDATECP = 1;
+ TA_NOUPDATECP = 0;
+
+ TA_LEFT = 0;
+ TA_RIGHT = 2;
+ TA_CENTER = 6;
+
+ TA_TOP = 0;
+ TA_BOTTOM = 8;
+ TA_BASELINE = 24;
+
+ ETO_GRAYED = 1;
+ ETO_OPAQUE = 2;
+ ETO_CLIPPED = 4;
+
+
+
+ ASPECT_FILTERING = #0000001;
+
+(* Meta file function numbers *)
+ META_SETBKCOLOR = #201;
+ META_SETBKMODE = #102;
+ META_SETMAPMODE = #103;
+ META_SETROP2 = #104;
+ META_SETRELABS = #105;
+ META_SETPOLYFILLMODE = #106;
+ META_SETSTRETCHBLTMODE = #107;
+ META_SETTEXTCHAREXTRA = #108;
+ META_SETTEXTCOLOR = #209;
+ META_SETTEXTJUSTIFICATION = #20A;
+ META_SETWINDOWORG = #20B;
+ META_SETWINDOWEXT = #20C;
+ META_SETVIEWPORTORG = #20D;
+ META_SETVIEWPORTEXT = #20E;
+ META_OFFSETWINDOWORG = #20F;
+ META_SCALEWINDOWEXT = #400;
+ META_OFFSETVIEWPORTORG = #211;
+ META_SCALEVIEWPORTEXT = #412;
+ META_LINETO = #213;
+ META_MOVETO = #214;
+ META_EXCLUDECLIPRECT = #415;
+ META_INTERSECTCLIPRECT = #416;
+ META_ARC = #817;
+ META_ELLIPSE = #418;
+ META_FLOODFILL = #419;
+ META_PIE = #81A;
+ META_RECTANGLE = #41B;
+ META_ROUNDRECT = #61C;
+ META_PATBLT = #61D;
+ META_SAVEDC = #01E;
+ META_SETPIXEL = #41F;
+ META_OFFSETCLIPRGN = #220;
+ META_TEXTOUT = #521;
+ META_BITBLT = #922;
+ META_STRETCHBLT = #B23;
+ META_POLYGON = #324;
+ META_POLYLINE = #325;
+ META_ESCAPE = #626;
+ META_RESTOREDC = #127;
+ META_FILLREGION = #228;
+ META_FRAMEREGION = #429;
+ META_INVERTREGION = #12A;
+ META_PAINTREGION = #12B;
+ META_SELECTCLIPREGION = #12C;
+ META_SELECTOBJECT = #12D;
+ META_SETTEXTALIGN = #12E;
+ META_DRAWTEXT = #62F;
+ META_CHORD = #630;
+ META_CREATEBRUSH = #0F8;
+ META_CREATEPATTERNBRUSH = #1F9;
+ META_CREATEPENINDIRECT = #2FA;
+ META_CREATEFONTINDIRECT = #2FB;
+ META_CREATEBRUSHINDIRECT = #2FC;
+ META_CREATEBITMAPINDIRECT = #2FD;
+ META_CREATEBITMAP = #6FE;
+ META_CREATEREGION = #6FF;
+
+(* GDI escapes *)
+ NEWFRAME = 1;
+ ABORTDOC = 2;
+ NEXTBAND = 3;
+ SETCOLORTABLE = 4;
+ GETCOLORTABLE = 5;
+ FLUSHOUTPUT = 6;
+ DRAFTMODE = 7;
+ QUERYESCSUPPORT = 8;
+ SETABORTPROC = 9;
+ STARTDOC = 10;
+ ENDDOC = 11;
+ GETPHYSPAGESIZE = 12;
+ GETPRINTINGOFFSET = 13;
+ GETSCALINGFACTOR = 14;
+ MFCOMMENT = 15; (* Metafile comment escape *)
+ GETPENWIDTH = 16;
+ SETCOPYCOUNT = 17;
+ SELECTPAPERSOURCE = 18;
+ DEVICEDATA = 19;
+ PASSTHROUGH = 19;
+ GETTECHNOLGY = 20;
+ SETENDCAP = 21;
+ SETLINEJOIN = 22;
+ SETMITERLIMIT = 23;
+ BANDINFO = 24;
+ DRAWPATTERNRECT = 25;
+ GETVECTORPENSIZE = 26;
+ GETVECTORBRUSHSIZE = 27;
+ ENABLEDUPLEX = 28;
+ ENABLEMANUALFEED = 29;
+
+
+(* spooler error code *)
+ SP_NOTREPORTED = #4000 (* set if GDI did not report error *);
+ SP_ERROR = -1 (* general errors who know what went wrong *);
+ SP_APPABORT = -2 (* app aborted the job - callback function returned false *);
+ SP_USERABORT = -3 (* user aborted the job through spooler's front end *);
+ SP_OUTOFDISK = -4 (* not enough disk space to spool *);
+ SP_OUTOFMEMORY = -5;
+
+(* spooler WM_SPOOLERSTATUS wparm classes *)
+
+ PR_JOBSTATUS = #000;
+
+(* Object definitions for GDI EnumObjects. *)
+ OBJ_PEN = 1;
+ OBJ_BRUSH = 2;
+
+
+TYPE
+ HANDLE = WORD;
+ PHANDLE = ADR OF HANDLE;
+ SPHANDLE = ADR OF HANDLE;
+ LPHANDLE = ADS OF HANDLE;
+
+ FARPROC = ADSMEM;
+ NEARPROC = ADRMEM;
+(* GLOBALHANDLE = HANDLE; Conflict with function name *)
+(* LOCALHANDLE = HANDLE; Conflict with function name *)
+
+ BITMAP = RECORD
+ bmType : short;
+ bmWidth : short;
+ bmHeight : short;
+ bmWidthBytes : short;
+ bmPlanes : BYTE;
+ bmBitsPixel : BYTE;
+ bmBits : LPSTR;
+ END;
+ PBITMAP = ADR OF BITMAP;
+ NPBITMAP = ADR OF BITMAP;
+ LPBITMAP = ADS OF BITMAP;
+
+ HSTR = HANDLE;
+ HICON = HANDLE;
+ HDC = HANDLE;
+ HMENU = HANDLE;
+ HPEN = HANDLE;
+ HFONT = HANDLE;
+ HBRUSH = HANDLE;
+ HBITMAP = HANDLE;
+ HCURSOR = HANDLE;
+ HRGN = HANDLE;
+
+ POINT = RECORD
+ x : int;
+ y : int;
+ END;
+ PPOINT = ADR OF POINT;
+ NPPOINT = ADR OF POINT;
+ LPPOINT = ADS OF POINT;
+
+ RECT = RECORD
+ left : int;
+ top : int;
+ right : int;
+ bottom : int;
+ END;
+
+ PRECT = ADR OF RECT;
+ NPRECT = ADR OF RECT;
+ LPRECT = ADS OF RECT;
+
+ WNDCLASS = RECORD
+ style : WORD;
+ lpfnWndProc : FARPROC;
+ cbClsExtra : int;
+ cbWndExtra : int;
+ hInstance : HANDLE;
+ hIcon_ : HICON;
+ hCursor_ : HCURSOR;
+ hbrBackground : HBRUSH;
+ lpszMenuName : LPSTR;
+ lpszClassName : LPSTR;
+ END;
+ PWNDCLASS = ADR OF WNDCLASS;
+ NPWNDCLASS = ADR OF WNDCLASS;
+ LPWNDCLASS = ADS OF WNDCLASS;
+
+ HWND = HANDLE;
+
+(* Message structure *)
+ MSG = RECORD
+ hwnd_ : HWND;
+ message : WORD;
+ wParam : WORD;
+ lParam : LONG;
+ time : DWORD;
+ pt : POINT;
+ END;
+ PMSG = ADR OF MSG;
+ NPMSG = ADR OF MSG;
+ LPMSG = ADS OF MSG;
+
+(* Window field offsets for GetWindowLong & GetWindowWord *)
+
+CONST
+ GWL_WNDPROC = -4;
+ GWW_HINSTANCE = -6;
+ GWW_HWNDPARENT = -8;
+ GWW_HWNDTEXT = -10;
+ GWW_ID = -12;
+ GWL_STYLE = -16;
+
+(* Class field offsets for GetClassLong & GetClassWord *)
+ GCL_MENUNAME = -8;
+ GCW_HBRBACKGROUND = -10;
+ GCW_HCURSOR = -12;
+ GCW_HICON = -14;
+ GCW_HMODULE = -16;
+ GCW_CBWNDEXTRA = -18;
+ GCW_CBCLSEXTRA = -20;
+ GCL_WNDPROC = -24;
+ GCW_STYLE = -26;
+
+(* ** Window Procedure Messages *)
+
+ WM_NULL = #0000;
+ WM_CREATE = #0001;
+ WM_DESTROY = #0002;
+ WM_MOVE = #0003;
+ WM_SIZEWAIT = #0004;
+ WM_SIZE = #0005;
+ WM_ACTIVATE = #0006;
+ WM_SETFOCUS_ = #0007;
+ WM_KILLFOCUS_ = #0008;
+ WM_SETVISIBLE = #0009;
+ WM_ENABLE = #000a;
+ WM_SETREDRAW = #000b;
+ WM_SETTEXT = #000c;
+ WM_GETTEXT = #000d;
+ WM_GETTEXTLENGTH = #000e;
+ WM_PAINT = #000f;
+ WM_CLOSE = #0010;
+ WM_QUERYENDSESSION = #0011;
+ WM_QUIT = #0012;
+ WM_QUERYOPEN = #0013;
+ WM_ERASEBKGND = #0014;
+ WM_SYSCOLORCHANGE = #0015;
+ WM_ENDSESSION = #0016;
+ WM_SYSTEMERROR = #0017;
+ WM_SHOWWINDOW = #0018;
+ WM_CTLCOLOR = #0019;
+ WM_WININICHANGE = #001a;
+ WM_DEVMODECHANGE = #001b;
+ WM_ACTIVATEAPP = #001c;
+ WM_FONTCHANGE = #001d;
+ WM_TIMECHANGE = #001e;
+ WM_CANCELMODE = #001f;
+ WM_SETCURSOR = #0020;
+ WM_MOUSEACTIVATE = #0021;
+ WM_CHILDACTIVATE = #0022;
+ WM_QUEUESYNC = #0023;
+ WM_GETMINMAXINFO = #0024;
+ WM_PAINTICON = #0026;
+ WM_ICONERASEBKGND = #0027;
+ WM_NEXTDLGCTL = #0028;
+ WM_ALTTABACTIVE = #0029; (* for win386 only *)
+ WM_SPOOLERSTATUS = #002A;
+
+
+ WM_NCCREATE = #0081;
+ WM_NCDESTROY = #0082;
+ WM_NCCALCSIZE = #0083;
+ WM_NCHITTEST = #0084;
+ WM_NCPAINT = #0085;
+ WM_NCACTIVATE = #0086;
+ WM_GETDLGCODE = #0087;
+ WM_SYNCPAINT = #0088;
+ WM_SYNCTASK = #0089;
+
+ ST_BEGINSWP = 0;
+ ST_ENDSWP = 1;
+
+
+ WM_NCMOUSEMOVE = #00a0;
+ WM_NCLBUTTONDOWN = #00a1;
+ WM_NCLBUTTONUP = #00a2;
+ WM_NCLBUTTONDBLCLK = #00a3;
+ WM_NCRBUTTONDOWN = #00a4;
+ WM_NCRBUTTONUP = #00a5;
+ WM_NCRBUTTONDBLCLK = #00a6;
+ WM_NCMBUTTONDOWN = #00a7;
+ WM_NCMBUTTONUP = #00a8;
+ WM_NCMBUTTONDBLCLK = #00a9;
+
+(* WINWhere area codes *)
+ HTERROR = -2;
+ HTTRANSPARENT = -1;
+ HTNOWHERE = 0;
+ HTCLIENT = 1;
+ HTCAPTION = 2;
+ HTSYSMENU = 3;
+ HTGROWBOX = 4;
+ HTSIZE = HTGROWBOX;
+ HTMENU = 5;
+ HTHSCROLL = 6;
+ HTVSCROLL = 7;
+ HTREDUCE = 8;
+ HTZOOM = 9;
+ HTLEFT = 10;
+ HTRIGHT = 11;
+ HTTOP = 12;
+ HTTOPLEFT = 13;
+ HTTOPRIGHT = 14;
+ HTBOTTOM = 15;
+ HTBOTTOMLEFT = 16;
+ HTBOTTOMRIGHT = 17;
+ HTSIZEFIRST = HTLEFT;
+ HTSIZELAST = HTBOTTOMRIGHT;
+
+(* WM_MOUSEACTIVATE return codes *)
+ MA_ACTIVATE = 1;
+ MA_ACTIVATEANDEAT = 2;
+ MA_NOACTIVATE = 3;
+
+ WM_KEYFIRST = #0100;
+ WM_KEYLAST = #0107;
+
+ WM_KEYDOWN = #0100;
+ WM_KEYUP = #0101;
+ WM_CHAR = #0102;
+ WM_DEADCHAR = #0103;
+ WM_SYSKEYDOWN = #0104;
+ WM_SYSKEYUP = #0105;
+ WM_SYSCHAR = #0106;
+ WM_SYSDEADCHAR = #0107;
+ WM_YOMICHAR = #0108;
+ WM_MOVECONVERTWINDOW = #0109;
+ WM_CONVERTREQUEST = #010A;
+ WM_CONVERTRESULT = #010B;
+
+ WM_INITDIALOG = #0110;
+ WM_COMMAND = #0111;
+ WM_SYSCOMMAND = #0112;
+ WM_TIMER = #0113;
+ WM_HSCROLL = #0114;
+ WM_VSCROLL = #0115;
+ WM_INITMENU = #0116;
+ WM_INITMENUPOPUP = #0117;
+ WM_SYSTIMER = #0118;
+ WM_MENUSELECT = #011f;
+ WM_MENUCHAR = #0120;
+ WM_ENTERIDLE = #0121;
+
+ WM_MOUSEFIRST = #0200;
+ WM_MOUSELAST = #0209;
+
+ WM_MOUSEMOVE = #0200 (* mouse related constants *);
+ WM_LBUTTONDOWN = #0201;
+ WM_LBUTTONUP = #0202;
+ WM_LBUTTONDBLCLK = #0203;
+ WM_RBUTTONDOWN = #0204;
+ WM_RBUTTONUP = #0205;
+ WM_RBUTTONDBLCLK = #0206;
+ WM_MBUTTONDOWN = #0207;
+ WM_MBUTTONUP = #0208;
+ WM_MBUTTONDBLCLK = #0209;
+
+ WM_KANJIFIRST = #0280;
+ WM_KANJILAST = #029f;
+
+(* clipboard messages *)
+ WM_CUT = #0300;
+ WM_COPY = #0301;
+ WM_PASTE = #0302;
+ WM_CLEAR = #0303;
+ WM_UNDO = #0304;
+ WM_RENDERFORMAT = #0305;
+ WM_RENDERALLFORMATS = #0306;
+ WM_DESTROYCLIPBOARD = #0307;
+ WM_DRAWCLIPBOARD = #0308;
+ WM_PAINTCLIPBOARD = #0309;
+ WM_VSCROLLCLIPBOARD = #030a;
+ WM_SIZECLIPBOARD = #030b;
+ WM_ASKCBFORMATNAME = #030c;
+ WM_CHANGECBCHAIN = #030d;
+ WM_HSCROLLCLIPBOARD = #030e;
+
+(* 0x03f0 to 0x03ff are reserved *)
+(* private window messages start here *)
+ WM_USER = #0400;
+
+
+
+{ $IFDECL MAKELONG $THEN BEGIN }
+ FUNCTION MAKELONG (
+ w1_,w2_ : WORD
+ ) : LONG;
+{ $END }
+
+{ $IFDECL LOWORD $THEN BEGIN }
+ FUNCTION LOWORD (
+ l_ : LONG
+ ) : WORD;
+{ $END }
+
+{ $IFDECL HIWORD $THEN BEGIN }
+ FUNCTION HIWORD (
+ l_ : LONG
+ ) : WORD;
+{ $END }
+
+{ $IFDECL LOBYTE $THEN BEGIN }
+ FUNCTION LOBYTE (
+ w_ : WORD
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL HIBYTE $THEN BEGIN }
+ FUNCTION HIBYTE (
+ w_ : WORD
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL MAKEPOINT $THEN BEGIN }
+ FUNCTION MAKEPOINT (
+ l_ : LONG
+ ) : POINT;
+{ $END }
+
+{ $IFDECL RegisterWindowMessage $THEN BEGIN }
+ FUNCTION RegisterWindowMessage (
+ l_ : LPSTR
+ ) : WORD;
+{ $END }
+
+(* Size message commands *)
+
+CONST
+ SIZENORMAL = 0;
+ SIZEICONIC = 1;
+ SIZEFULLSCREEN = 2;
+ SIZEZOOMSHOW = 3;
+ SIZEZOOMHIDE = 4;
+
+(* Key state masks for mouse messages *)
+ MK_LBUTTON = #0001;
+ MK_RBUTTON = #0002;
+ MK_SHIFT = #0004;
+ MK_CONTROL = #0008;
+ MK_MBUTTON = #0010;
+
+(* Window styles *)
+ WS_TILED = #00000000;
+ WS_OVERLAPPED = WS_TILED;
+ WS_ICONICPOPUP = #c0000000;
+ WS_POPUP = #80000000;
+ WS_CHILD = #40000000;
+ WS_MINIMIZE = #20000000;
+ WS_VISIBLE = #10000000;
+ WS_DISABLED = #08000000;
+ WS_CLIPSIBLINGS = #04000000;
+ WS_CLIPCHILDREN = #02000000;
+ WS_MAXIMIZE = #01000000;
+
+ WS_BORDER = #00800000;
+ WS_CAPTION = #00c00000;
+ WS_DLGFRAME = #00400000;
+ WS_VSCROLL = #00200000;
+ WS_HSCROLL = #00100000;
+ WS_SYSMENU = #00080000;
+ WS_SIZEBOX = #00040000;
+ WS_THICKFRAME = #00040000;
+ WS_GROUP = #00020000;
+ WS_TABSTOP = #00010000;
+
+ WS_MINIMIZEBOX = #00020000;
+ WS_MAXIMIZEBOX = #00010000;
+
+ WS_ICONIC = WS_MINIMIZE;
+
+
+(* Class styles *)
+ CS_VREDRAW = #0001;
+ CS_HREDRAW = #0002;
+ CS_KEYCVTWINDOW = #0004;
+ CS_DBLCLKS = #0008;
+ CS_OEMCHARS = #0010;
+ CS_OWNDC = #0020;
+ CS_CLASSDC = #0040;
+ CS_PARENTDC = #0080;
+ CS_NOKEYCVT = #0100;
+ CS_SAVEBITS = #0800;
+ CS_NOCLOSE = #0200;
+ CS_BYTEALIGNCLIENT = #1000;
+ CS_BYTEALIGNWINDOW = #2000;
+
+(* Shorthand for the common cases *)
+ WS_TILEDWINDOW = #00CF0000; (* WS_TILED | WS_CAPTION | WS_SYSMENU | WS_SIZEBOX *)
+ WS_OVERLAPPEDWINDOW = WS_TILEDWINDOW;
+ WS_POPUPWINDOW = #80880000; (* WS_POPUP | WS_BORDER | WS_SYSMENU *)
+ WS_CHILDWINDOW = (WS_CHILD);
+
+(* clipboard metafile picture structure *)
+TYPE
+ HANDLETABLE = RECORD
+ objectHandle[1] : HANDLE;
+ END;
+ PHANDLETABLE = ADR OF HANDLETABLE;
+ LPHANDLETABLE = ADS OF HANDLETABLE;
+
+ METARECORD = RECORD
+ rdSize : DWORD;
+ rdFunction : WORD;
+ rdParm[1] : WORD;
+ END;
+ PMETARECORD = ADR OF METARECORD;
+ LPMETARECORD = ADS OF METARECORD;
+
+ METAFILEPICT = RECORD
+ mm : int;
+ xExt : int;
+ yExt : int;
+ hMF : HANDLE;
+ END;
+ LPMETAFILEPICT = ADS OF METAFILEPICT;
+
+(* predefined clipboard formats *)
+
+CONST
+ CF_TEXT = 1;
+ CF_BITMAP = 2;
+ CF_METAFILEPICT = 3;
+ CF_SYLK = 4;
+ CF_DIF = 5;
+ CF_TIFF = 6;
+ CF_OEMTEXT = 7;
+
+ CF_OWNERDISPLAY = #80 (* owner display *);
+ CF_DSPTEXT = #81 (* display text *);
+ CF_DSPBITMAP = #82 (* display bitmap *);
+ CF_DSPMETAFILEPICT = #83 (* display metafile *);
+
+(* Private clipboard format range *)
+ CF_PRIVATEFIRST = #200 (* Anything in this range doesn't *);
+ CF_PRIVATELAST = #2ff (* get GlobalFree'd *);
+ CF_GDIOBJFIRST = #300 (* Anything in this range gets *);
+ CF_GDIOBJLAST = #3ff (* DeleteObject'ed *);
+
+
+TYPE
+ PAINTSTRUCT = RECORD
+ hdc_ : HDC;
+ fErase : BOOL;
+ rcPaint : RECT;
+ fRestore : BOOL;
+ fIncUpdate : BOOL;
+ rgbReserved : ARRAY [0..15] OF BYTE;
+ END;
+ PPAINTSTRUCT = ADR OF PAINTSTRUCT;
+ NPPAINTSTRUCT = ADR OF PAINTSTRUCT;
+ LPPAINTSTRUCT = ADS OF PAINTSTRUCT;
+
+ CREATESTRUCT = RECORD
+ lpCreateParams : LPSTR;
+ hInstance : HANDLE;
+ hMenu : HANDLE;
+ hwndParent : HWND;
+ cy : int;
+ cx : int;
+ y : int;
+ x : int;
+ style : long;
+ lpszName : LPSTR;
+ lpszClass : LPSTR;
+ END;
+ LPCREATESTRUCT = ADS OF CREATESTRUCT;
+
+(* TextMetric structure *)
+ TEXTMETRIC = RECORD
+ tmHeight : INTEGER2;
+ tmAscent : INTEGER2;
+ tmDescent : INTEGER2;
+ tmInternalLeading : INTEGER2;
+ tmExternalLeading : INTEGER2;
+ tmAveCharWidth : INTEGER2;
+ tmMaxCharWidth : INTEGER2;
+ tmWeight : INTEGER2;
+ tmItalic : BYTE;
+ tmUnderlined : BYTE;
+ tmStruckOut : BYTE;
+ tmFirstChar : BYTE;
+ tmLastChar : BYTE;
+ tmDefaultChar : BYTE;
+ tmBreakChar : BYTE;
+ tmPitchAndFamily : BYTE;
+ tmCharSet : BYTE;
+ tmOverhang : INTEGER2;
+ tmDigitizedAspectX : INTEGER2;
+ tmDigitizedAspectY : INTEGER2;
+ END;
+ PTEXTMETRIC = ADR OF TEXTMETRIC;
+ NPTEXTMETRIC = ADR OF TEXTMETRIC;
+ LPTEXTMETRIC = ADS OF TEXTMETRIC;
+
+(* GDI logical objects *)
+(* Pel Array *)
+ PELARRAY = RECORD
+ paXCount : INTEGER2;
+ paYCount : INTEGER2;
+ paXExt : INTEGER2;
+ paYExt : INTEGER2;
+ paRGBs : BYTE;
+ END;
+ PPELARRAY = ADR OF PELARRAY;
+ NPPELARRAY = ADR OF PELARRAY;
+ LPPELARRAY = ADS OF PELARRAY;
+
+(* Logical Brush *)
+ LOGBRUSH = RECORD
+ lbStyle : WORD;
+ lbColor : DWORD;
+ lbHatch : INTEGER2;
+ END;
+ PLOGBRUSH = ADR OF LOGBRUSH;
+ NPLOGBRUSH = ADR OF LOGBRUSH;
+ LPLOGBRUSH = ADS OF LOGBRUSH;
+
+(* A PATTERN and a LOGBRUSH are the same thing *)
+ PATTERN = LOGBRUSH;
+ PPATTERN = ADR OF PATTERN;
+ NPPATTERN = ADR OF PATTERN;
+ LPPATTERN = ADS OF PATTERN;
+
+(* Logical Pen *)
+ LOGPEN = RECORD
+ lopnStyle : WORD;
+ lopnWidth : POINT;
+ lopnColor : DWORD;
+ END;
+ PLOGPEN = ADR OF LOGPEN;
+ NPLOGPEN = ADR OF LOGPEN;
+ LPLOGPEN = ADS OF LOGPEN;
+
+(* Logical Font *)
+
+
+CONST
+ LF_FACESIZE = 32;
+
+
+TYPE
+ LOGFONT = RECORD
+ lfHeight : INTEGER2;
+ lfWidth : INTEGER2;
+ lfEscapement : INTEGER2;
+ lfOrientation : INTEGER2;
+ lfWeight : INTEGER2;
+ lfItalic : BYTE;
+ lfUnderline : BYTE;
+ lfStrikeOut : BYTE;
+ lfCharSet : BYTE;
+ lfOutPrecision : BYTE;
+ lfClipPrecision : BYTE;
+ lfQuality : BYTE;
+ lfPitchAndFamily : BYTE;
+ lfFaceName : ARRAY [0..LF_FACESIZE-1] OF BYTE;
+ END;
+ PLOGFONT = ADR OF LOGFONT;
+ NPLOGFONT = ADR OF LOGFONT;
+ LPLOGFONT = ADS OF LOGFONT;
+
+
+(* Logical font constants *)
+
+CONST
+ OUT_DEFAULT_PRECIS = 0;
+ OUT_STRING_PRECIS = 1;
+ OUT_CHARACTER_PRECIS = 2;
+ OUT_STROKE_PRECIS = 3;
+
+ CLIP_DEFAULT_PRECIS = 0;
+ CLIP_CHARACTER_PRECIS = 1;
+ CLIP_STROKE_PRECIS = 2;
+
+ DEFAULT_QUALITY = 0;
+ DRAFT_QUALITY = 1;
+ PROOF_QUALITY = 2;
+
+ DEFAULT_PITCH = 0;
+ FIXED_PITCH = 1;
+ VARIABLE_PITCH = 2;
+
+ ANSI_CHARSET = 0;
+ SHIFTJIS_CHARSET = 128; (* Kanji CharSet *)
+ OEM_CHARSET = 255;
+
+(* GDI font families. *)
+ FF_DONTCARE = 0 (* Don't care or don't know. *);
+ FF_ROMAN = 16 (* Variable stroke width, serifed. *);
+ (* Times Roman, Century Schoolbook, etc. *)
+ FF_SWISS = 32 (* Variable stroke width, sans-serifed. *);
+ (* Helvetica, Swiss, etc. *)
+ FF_MODERN = 48 (* Constant stroke width, serifed or sans-serifed. *);
+ (* Pica, Elite, Courier, etc. *)
+ FF_SCRIPT = 64 (* Cursive, etc. *);
+ FF_DECORATIVE = 80 (* Old English, etc. *);
+
+(* Font weights lightest to darkest. *)
+ FW_DONTCARE = 0;
+ FW_THIN = 100;
+ FW_EXTRALIGHT = 200;
+ FW_LIGHT = 300;
+ FW_NORMAL = 400;
+ FW_MEDIUM = 500;
+ FW_SEMIBOLD = 600;
+ FW_BOLD = 700;
+ FW_EXTRABOLD = 800;
+ FW_HEAVY = 900;
+
+ FW_ULTRALIGHT = (FW_EXTRALIGHT);
+ FW_REGULAR = (FW_NORMAL);
+ FW_DEMIBOLD = (FW_SEMIBOLD);
+ FW_ULTRABOLD = (FW_EXTRABOLD);
+ FW_BLACK = (FW_HEAVY);
+
+
+(* EnumFonts masks. *)
+ RASTER_FONTTYPE = #0001;
+ DEVICE_FONTTYPE = #0002;
+
+
+(* GDI rgb values packed into a dword *)
+
+{ $IFDECL RGB $THEN BEGIN }
+ FUNCTION RGB (
+ r,g,b : BYTE
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetRValue $THEN BEGIN }
+ FUNCTION GetRValue (
+ d_ : DWORD
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL GetGValue $THEN BEGIN }
+ FUNCTION GetGValue (
+ d_ : DWORD
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL GetBValue $THEN BEGIN }
+ FUNCTION GetBValue (
+ d_ : DWORD
+ ) : BYTE;
+{ $END }
+
+(* GDI Background Modes *)
+
+CONST
+ TRANSPARENT = 1;
+ OPAQUE = 2;
+
+(* GDI map modes *)
+ MM_TEXT = 1;
+ MM_LOMETRIC = 2;
+ MM_HIMETRIC = 3;
+ MM_LOENGLISH = 4;
+ MM_HIENGLISH = 5;
+ MM_TWIPS = 6;
+ MM_ISOTROPIC = 7;
+ MM_ANISOTROPIC = 8;
+
+(* GDI coordinate modes *)
+
+ ABSOLUTE = 1;
+ RELATIVE = 2;
+
+(* Stock Logical Objects *)
+ WHITE_BRUSH = 0;
+ LTGRAY_BRUSH = 1;
+ GRAY_BRUSH = 2;
+ DKGRAY_BRUSH = 3;
+ BLACK_BRUSH = 4;
+ NULL_BRUSH = 5;
+ HOLLOW_BRUSH = (NULL_BRUSH);
+ WHITE_PEN = 6;
+ BLACK_PEN = 7;
+ NULL_PEN = 8;
+ OEM_FIXED_FONT = 10;
+ ANSI_FIXED_FONT = 11;
+ ANSI_VAR_FONT = 12;
+ SYSTEM_FONT = 13;
+ DEVICEDEFAULT_FONT = 14;
+
+(* GDI Brush Style definitions. *)
+
+ BS_SOLID = 0;
+ BS_NULL = 1;
+ BS_HOLLOW = (BS_NULL);
+ BS_HATCHED = 2;
+ BS_PATTERN = 3;
+ BS_INDEXED = 4;
+
+
+(* GDI Hatch Style definitions. *)
+
+ HS_HORIZONTAL = 0 (* ----- *);
+ HS_VERTICAL = 1 (* ||||| *);
+ HS_FDIAGONAL = 2 (* ///// *);
+ HS_BDIAGONAL = 3 (* \\\\\ *);
+ HS_CROSS = 4 (* +++++ *);
+ HS_DIAGCROSS = 5 (* xxxxx *);
+
+
+(* GDI Pen Style definitions *)
+ PS_SOLID = 0 (* solid pen *);
+ PS_DASH = 1 (* ------- *);
+ PS_DOT = 2 (* ....... *);
+ PS_DASHDOT = 3 (* _._._._ *);
+ PS_DASHDOTDOT = 4 (* _.._.._ *);
+ PS_NULL = 5 (* *);
+
+(* Device Parameters for GetDeviceCaps() *)
+
+ DRIVERVERSION = 0 (* Device driver version *);
+ TECHNOLOGY = 2 (* Device classification *);
+ HORZSIZE = 4 (* Horizontal size in millimeters *);
+ VERTSIZE = 6 (* Vertical size in millimeters *);
+ HORZRES = 8 (* Horizontal width in pixels *);
+ VERTRES = 10 (* Vertical width in pixels *);
+ BITSPIXEL = 12 (* Number of bits per pixel *);
+ PLANES = 14 (* Number of planes *);
+ NUMBRUSHES = 16 (* Number of brushes the device has *);
+ NUMPENS = 18 (* Number of pens the device has *);
+ NUMMARKERS = 20 (* Number of markers the device has *);
+ NUMFONTS = 22 (* Number of fonts the device has *);
+ NUMCOLORS = 24;
+ PDEVICESIZE = 26 (* Size required for device descriptor *);
+ CURVECAPS = 28 (* Curves capabilities *);
+ LINECAPS = 30 (* Line capabilities *);
+ POLYGONALCAPS = 32 (* Polygonal capabilities *);
+ TEXTCAPS = 34 (* Text capabilities *);
+ CLIPCAPS = 36 (* Clipping capabilities *);
+ RASTERCAPS = 38 (* Bitblt capabilities *);
+ ASPECTX = 40 (* Length of the X leg *);
+ ASPECTY = 42 (* Length of the Y leg *);
+ ASPECTXY = 44 (* Length of the hypotenuse *);
+
+ LOGPIXELSX = 88 (* Logical pixels/inch in X *);
+ LOGPIXELSY = 90 (* Logical pixels/inch in Y *);
+
+
+(* Device capability masks *)
+(* Device Technologies *)
+
+ DT_PLOTTER = 0 (* Vector plotter *);
+ DT_RASDISPLAY = 1 (* Raster display *);
+ DT_RASPRINTER = 2 (* Raster printer *);
+ DT_RASCAMERA = 3 (* Raster camera *);
+ DT_CHARSTREAM = 4 (* Character-stream, PLP *);
+ DT_METAFILE = 5 (* Metafile, VDM *);
+ DT_DISPFILE = 6 (* Display-file *);
+
+(* Curve Capabilities *)
+
+ CC_NONE = 0 (* Curves not supported *);
+ CC_CIRCLES = 1 (* Can do circles *);
+ CC_PIE = 2 (* Can do pie wedges *);
+ CC_CHORD = 4 (* Can do chord arcs *);
+ CC_ELLIPSES = 8 (* Can do ellipese *);
+ CC_WIDE = 16 (* Can do wide lines *);
+ CC_STYLED = 32 (* Can do styled lines *);
+ CC_WIDESTYLED = 64 (* Can do wide styled lines*);
+ CC_INTERIORS = 128 (* Can do interiors *);
+
+(* Line Capabilities *)
+
+ LC_NONE = 0 (* Lines not supported *);
+ LC_POLYLINE = 2 (* Can do polylines *);
+ LC_MARKER = 4 (* Can do markers *);
+ LC_POLYMARKER = 8 (* Can do polymarkers *);
+ LC_WIDE = 16 (* Can do wide lines *);
+ LC_STYLED = 32 (* Can do styled lines *);
+ LC_WIDESTYLED = 64 (* Can do wide styled lines*);
+ LC_INTERIORS = 128 (* Can do interiors *);
+
+(* Polygonal Capabilities *)
+
+ PC_NONE = 0 (* Polygonals not supported*);
+ PC_POLYGON = 1 (* Can do polygons *);
+ PC_RECTANGLE = 2 (* Can do rectangles *);
+ PC_TRAPEZOID = 4 (* Can do trapezoids *);
+ PC_SCANLINE = 8 (* Can do scanlines *);
+ PC_WIDE = 16 (* Can do wide borders *);
+ PC_STYLED = 32 (* Can do styled borders *);
+ PC_WIDESTYLED = 64 (* Can do wide styled borders*);
+ PC_INTERIORS = 128 (* Can do interiors *);
+
+(* Polygonal Capabilities *)
+
+ CP_NONE = 0 (* no clipping of Output *);
+ CP_RECTANGLE = 1 (* Output clipped to Rects *);
+
+(* Text Capabilities *)
+
+ TC_OP_CHARACTER = #0001 (* Can do OutputPrecision CHARACTER *);
+ TC_OP_STROKE = #0002 (* Can do OutputPrecision STROKE *);
+ TC_CP_STROKE = #0004 (* Can do ClipPrecision STROKE *);
+ TC_CR_90 = #0008 (* Can do CharRotAbility 90 *);
+ TC_CR_ANY = #0010 (* Can do CharRotAbility ANY *);
+ TC_SF_X_YINDEP = #0020 (* Can do ScaleFreedom X_YINDEPENDENT *);
+ TC_SA_DOUBLE = #0040 (* Can do ScaleAbility DOUBLE *);
+ TC_SA_INTEGER = #0080 (* Can do ScaleAbility INTEGER *);
+ TC_SA_CONTIN = #0100 (* Can do ScaleAbility CONTINUOUS *);
+ TC_EA_DOUBLE = #0200 (* Can do EmboldenAbility DOUBLE *);
+ TC_IA_ABLE = #0400 (* Can do ItalisizeAbility ABLE *);
+ TC_UA_ABLE = #0800 (* Can do UnderlineAbility ABLE *);
+ TC_SO_ABLE = #1000 (* Can do StrikeOutAbility ABLE *);
+ TC_RA_ABLE = #2000 (* Can do RasterFontAble ABLE *);
+ TC_VA_ABLE = #4000 (* Can do VectorFontAble ABLE *);
+ TC_RESERVED = #8000 (* Reserved. *);
+(* Raster Capabilities *)
+
+ RC_BITBLT = 1 (* Can do standard non-stretching, non-inverting BLT. *);
+ RC_BANDING = 2 (* Device requires banding support *);
+ RC_SCALING = 4 (* Device requires scaling support *);
+ RC_BITMAP64 = 8 (* Device can support >64K bitmap *);
+
+(* PeekMessage options *)
+
+ PM_REMOVE = TRUE_;
+ PM_NOREMOVE = FALSE_;
+ PM_NOYIELD = #02;
+
+
+{ $IFDECL GetMessage $THEN BEGIN }
+ FUNCTION GetMessage (
+ l_ : LPMSG;
+ h_ : HWND;
+ w_,x_ : WORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PeekMessage $THEN BEGIN }
+ FUNCTION PeekMessage (
+ l_ : LPMSG;
+ h_ : HWND;
+ w_,x_ : WORD;
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL TranslateMessage $THEN BEGIN }
+ FUNCTION TranslateMessage (
+ l_ : LPMSG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL DispatchMessage $THEN BEGIN }
+ FUNCTION DispatchMessage (
+ l_ : LPMSG
+ ) : LONG;
+{ $END }
+
+
+{ $IFDECL SwapMouseButton $THEN BEGIN }
+ FUNCTION SwapMouseButton (
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetMessagePos $THEN BEGIN }
+ FUNCTION GetMessagePos : DWORD;
+{ $END }
+
+{ $IFDECL GetMessageTime $THEN BEGIN }
+ FUNCTION GetMessageTime : long;
+{ $END }
+
+
+{ $IFDECL GetSysModalWindow $THEN BEGIN }
+ FUNCTION GetSysModalWindow : HWND;
+{ $END }
+
+{ $IFDECL SetSysModalWindow $THEN BEGIN }
+ FUNCTION SetSysModalWindow (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+
+{ $IFDECL SendMessage $THEN BEGIN }
+ FUNCTION SendMessage (
+ h_ : HWND;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : long;
+{ $END }
+
+{ $IFDECL PostMessage $THEN BEGIN }
+ FUNCTION PostMessage (
+ h_ : HWND;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PostAppMessage $THEN BEGIN }
+ FUNCTION PostAppMessage (
+ h_ : HANDLE;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL ReplyMessage $THEN BEGIN }
+ PROCEDURE ReplyMessage (
+ l_ : long
+ );
+{ $END }
+
+{ $IFDECL WaitMessage $THEN BEGIN }
+ PROCEDURE WaitMessage;
+{ $END }
+
+{ $IFDECL DefWindowProc $THEN BEGIN }
+ FUNCTION DefWindowProc (
+ h_ : HWND;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : long;
+{ $END }
+
+{ $IFDECL PostQuitMessage $THEN BEGIN }
+ PROCEDURE PostQuitMessage (
+ i_ : int
+ );
+{ $END }
+
+{ $IFDECL CallWindowProc $THEN BEGIN }
+ FUNCTION CallWindowProc (
+ f_ : FARPROC;
+ h_ : HWND;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : long;
+{ $END }
+
+{ $IFDECL InSendMessage $THEN BEGIN }
+ FUNCTION InSendMessage : BOOL;
+{ $END }
+
+
+{ $IFDECL GetDoubleClickTime $THEN BEGIN }
+ FUNCTION GetDoubleClickTime : WORD;
+{ $END }
+
+{ $IFDECL SetDoubleClickTime $THEN BEGIN }
+ FUNCTION SetDoubleClickTime (
+ w_ : WORD
+ );
+{ $END }
+
+{ $IFDECL RegisterClass $THEN BEGIN }
+ FUNCTION RegisterClass (
+ l_ : LPWNDCLASS
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SetMessageQueue $THEN BEGIN }
+ FUNCTION SetMessageQueue (
+ i_ : int
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL CreateWindow $THEN BEGIN }
+ FUNCTION CreateWindow (
+ l_,m_ : LPSTR;
+ d_ : DWORD;
+ i_,j_,k_,n_ : int;
+ h_ : HWND;
+ o_ : HMENU;
+ p_ : HANDLE;
+ q_ : LPSTR
+ ) : HWND;
+{ $END }
+
+CONST
+ CW_USEDEFAULT = RETYPE( int, #8000); { used on both x and cx }
+
+{ $IFDECL IsWindow $THEN BEGIN }
+ FUNCTION IsWindow (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL DestroyWindow $THEN BEGIN }
+ FUNCTION DestroyWindow (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL ShowWindow $THEN BEGIN }
+ FUNCTION ShowWindow (
+ h_ : HWND;
+ i_ : int
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL FlashWindow $THEN BEGIN }
+ FUNCTION FlashWindow (
+ h_ : HWND;
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL OpenIcon $THEN BEGIN }
+ FUNCTION OpenIcon (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL CloseWindow $THEN BEGIN }
+ FUNCTION CloseWindow (
+ h_ : HWND
+ ) : int;
+{ $END }
+
+{ $IFDECL MoveWindow $THEN BEGIN }
+ PROCEDURE MoveWindow (
+ h_ : HWND;
+ i_,j_,k_,l_ : int;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL IsWindowVisible $THEN BEGIN }
+ FUNCTION IsWindowVisible (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL IsIconic $THEN BEGIN }
+ FUNCTION IsIconic (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL AnyPopup $THEN BEGIN }
+ FUNCTION AnyPopup : BOOL;
+{ $END }
+
+{ $IFDECL BringWindowToTop $THEN BEGIN }
+ PROCEDURE BringWindowToTop (
+ h_ : HWND
+ );
+{ $END }
+
+{ $IFDECL IsZoomed $THEN BEGIN }
+ FUNCTION IsZoomed (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+(* SetWindowPos flags *)
+
+CONST
+ SWP_NOSIZE = #01;
+ SWP_NOMOVE = #02;
+ SWP_NOZORDER = #04;
+ SWP_NOREDRAW = #08;
+ SWP_NOACTIVATE = #10;
+ SWP_DRAWFRAME = #20;
+ SWP_SHOWWINDOW = #40;
+ SWP_HIDEWINDOW = #80;
+ SWP_NOCOPYBITS = #0100;
+ SWP_NOREPOSITION = #200;
+
+
+(* DrawFrame and associated defines *)
+ DF_SHIFT0 = #0000;
+ DF_SHIFT1 = #0001;
+ DF_SHIFT2 = #0002;
+ DF_SHIFT3 = #0003;
+ DF_PATCOPY = #0000;
+ DF_PATINVERT = #0004;
+
+ DF_SCROLLBAR = 0;
+ DF_BACKGROUND = 8;
+ DF_ACTIVECAPTION = 16;
+ DF_INACTIVECAPTION = 24;
+ DF_MENU = 32;
+ DF_WINDOW = 40;
+ DF_WINDOWFRAME = 48;
+ DF_MENUTEXT = 56;
+ DF_WINDOWTEXT = 64;
+ DF_CAPTIONTEXT = 72;
+ DF_ACTIVEBORDER = 80;
+ DF_INACTIVEBORDER = 88;
+ DF_APPWORKSPACE = 96;
+ DF_GRAY = 104;
+
+(* DrawText format flags *)
+
+
+ DT_LEFT = #00;
+ DT_CENTER = #01;
+ DT_RIGHT = #02;
+ DT_TOP = #00;
+ DT_VCENTER = #04;
+ DT_BOTTOM = #08;
+ DT_WORDBREAK = #10;
+ DT_SINGLELINE = #20;
+ DT_EXPANDTABS = #40;
+ DT_TABSTOP = #80;
+ DT_NOCLIP = #100;
+ DT_EXTERNALLEADING = #200;
+ DT_CALCRECT = #400;
+ DT_NOPREFIX = #800;
+ DT_INTERNAL = #1000;
+
+
+{ $IFDECL DrawText $THEN BEGIN }
+ PROCEDURE DrawText (
+ h_ : HDC;
+ l_ : LPSTR;
+ i_ : int;
+ m_ : LPRECT;
+ w_ : WORD
+ );
+{ $END }
+
+{ $IFDECL DrawIcon $THEN BEGIN }
+ FUNCTION DrawIcon (
+ h_ : HDC;
+ i_,j_ : int;
+ k_ : HICON
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL CreateDialog $THEN BEGIN }
+ FUNCTION CreateDialog (
+ h_ : HANDLE;
+ l_ : LPSTR;
+ i_ : HWND;
+ f_ : FARPROC
+ ) : HWND;
+{ $END }
+
+{ $IFDECL CreateDialogIndirect $THEN BEGIN }
+ FUNCTION CreateDialogIndirect (
+ h_ : HANDLE;
+ l_ : LPSTR;
+ i_ : HWND;
+ f_ : FARPROC
+ ) : HWND;
+{ $END }
+
+{ $IFDECL DialogBox $THEN BEGIN }
+ FUNCTION DialogBox (
+ h_ : HANDLE;
+ l_ : LPSTR;
+ i_ : HWND;
+ f_ : FARPROC
+ ) : int;
+{ $END }
+
+{ $IFDECL DialogBoxIndirect $THEN BEGIN }
+ FUNCTION DialogBoxIndirect (
+ h_ : HANDLE;
+ h_ : HANDLE;
+ i_ : HWND;
+ f_ : FARPROC
+ ) : int;
+{ $END }
+
+{ $IFDECL EndDialog $THEN BEGIN }
+ PROCEDURE EndDialog (
+ h_ : HWND;
+ i_ : int
+ );
+{ $END }
+
+{ $IFDECL GetDlgItem $THEN BEGIN }
+ FUNCTION GetDlgItem (
+ h_ : HWND;
+ i_ : int
+ ) : HWND;
+{ $END }
+
+{ $IFDECL SetDlgItemInt $THEN BEGIN }
+ PROCEDURE SetDlgItemInt (
+ h_ : HWND;
+ i_ : int;
+ w_ : WORD;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL GetDlgItemInt $THEN BEGIN }
+ FUNCTION GetDlgItemInt (
+ h_ : HWND;
+ i_ : int;
+ b_ : LPBOOL;
+ c_ : BOOL
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SetDlgItemText $THEN BEGIN }
+ PROCEDURE SetDlgItemText (
+ h_ : HWND;
+ i_ : int;
+ l_ : LPSTR
+ );
+{ $END }
+
+{ $IFDECL GetDlgItemText $THEN BEGIN }
+ FUNCTION GetDlgItemText (
+ h_ : HWND;
+ i_ : int;
+ l_ : LPSTR;
+ j_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL CheckDlgButton $THEN BEGIN }
+ PROCEDURE CheckDlgButton (
+ h_ : HWND;
+ i_ : int;
+ w_ : WORD
+ );
+{ $END }
+
+{ $IFDECL CheckRadioButton $THEN BEGIN }
+ PROCEDURE CheckRadioButton (
+ h_ : HWND;
+ i_,j_,k_ : int
+ );
+{ $END }
+
+{ $IFDECL IsDlgButtonChecked $THEN BEGIN }
+ FUNCTION IsDlgButtonChecked (
+ h_ : HWND;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SendDlgItemMessage $THEN BEGIN }
+ FUNCTION SendDlgItemMessage (
+ h_ : HWND;
+ i_ : int;
+ w_,x_ : WORD;
+ l_ : LONG
+ ) : long;
+{ $END }
+
+
+{ $IFDECL CallMsgFilter $THEN BEGIN }
+ FUNCTION CallMsgFilter (
+ l_ : LPMSG;
+ i_ : int
+ ) : BOOL;
+{ $END }
+
+(* Clipboard manager routines *)
+
+{ $IFDECL OpenClipboard $THEN BEGIN }
+ FUNCTION OpenClipboard (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL CloseClipboard $THEN BEGIN }
+ FUNCTION CloseClipboard : BOOL;
+{ $END }
+
+{ $IFDECL GetClipboardOwner $THEN BEGIN }
+ FUNCTION GetClipboardOwner : HWND;
+{ $END }
+
+{ $IFDECL SetClipboardViewer $THEN BEGIN }
+ FUNCTION SetClipboardViewer (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL GetClipboardViewer $THEN BEGIN }
+ FUNCTION GetClipboardViewer : HWND;
+{ $END }
+
+{ $IFDECL ChangeClipboardChain $THEN BEGIN }
+ FUNCTION ChangeClipboardChain (
+ h_,i_ : HWND
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SetClipboardData $THEN BEGIN }
+ FUNCTION SetClipboardData (
+ w_ : WORD;
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GetClipboardData $THEN BEGIN }
+ FUNCTION GetClipboardData (
+ w_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL RegisterClipboardFormat $THEN BEGIN }
+ FUNCTION RegisterClipboardFormat (
+ l_ : LPSTR
+ ) : WORD;
+{ $END }
+
+{ $IFDECL CountClipboardFormats $THEN BEGIN }
+ FUNCTION CountClipboardFormats : int;
+{ $END }
+
+{ $IFDECL EnumClipboardFormats $THEN BEGIN }
+ FUNCTION EnumClipboardFormats (
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetClipboardFormatName $THEN BEGIN }
+ FUNCTION GetClipboardFormatName (
+ w_ : WORD;
+ l_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL EmptyClipboard $THEN BEGIN }
+ FUNCTION EmptyClipboard : BOOL;
+{ $END }
+
+{ $IFDECL IsClipboardFormatAvailable $THEN BEGIN }
+ FUNCTION IsClipboardFormatAvailable (
+ w_ : WORD
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL SetFocus $THEN BEGIN }
+ FUNCTION SetFocus (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL GetFocus $THEN BEGIN }
+ FUNCTION GetFocus : HWND;
+{ $END }
+
+{ $IFDECL GetActiveWindow $THEN BEGIN }
+ FUNCTION GetActiveWindow : HWND;
+{ $END }
+
+
+{ $IFDECL GetKeyState $THEN BEGIN }
+ FUNCTION GetKeyState (
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetAsyncKeyState $THEN BEGIN }
+ FUNCTION GetAsyncKeyState (
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetKeyboardState $THEN BEGIN }
+ PROCEDURE GetKeyboardState (
+ b_ : ADS OF BYTE
+ );
+{ $END }
+
+{ $IFDECL SetKeyboardState $THEN BEGIN }
+ PROCEDURE SetKeyboardState (
+ b_ : ADS OF BYTE
+ );
+{ $END }
+
+{ $IFDECL EnableHardwareInput $THEN BEGIN }
+ FUNCTION EnableHardwareInput (
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetInputState $THEN BEGIN }
+ FUNCTION GetInputState (
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetCapture $THEN BEGIN }
+ FUNCTION GetCapture;
+{ $END }
+
+{ $IFDECL SetCapture $THEN BEGIN }
+ FUNCTION SetCapture (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL ReleaseCapture $THEN BEGIN }
+ PROCEDURE ReleaseCapture;
+{ $END }
+
+(* Windows Functions *)
+
+{ $IFDECL SetTimer $THEN BEGIN }
+ FUNCTION SetTimer (
+ h_ : HWND;
+ s_ : short;
+ w_ : WORD;
+ f_ : FARPROC
+ ) : WORD;
+{ $END }
+
+{ $IFDECL KillTimer $THEN BEGIN }
+ FUNCTION KillTimer (
+ h_ : HWND;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL EnableWindow $THEN BEGIN }
+ FUNCTION EnableWindow (
+ h_ : HWND;
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL IsWindowEnabled $THEN BEGIN }
+ FUNCTION IsWindowEnabled (
+ h_ : HWND
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL LoadAccelerators $THEN BEGIN }
+ FUNCTION LoadAccelerators (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL TranslateAccelerator $THEN BEGIN }
+ FUNCTION TranslateAccelerator (
+ h_ : HWND;
+ i_ : HANDLE;
+ l_ : LPMSG
+ ) : int;
+{ $END }
+
+
+(* GetSystemMetrics codes *)
+
+CONST
+ SM_CXSCREEN = 0;
+ SM_CYSCREEN = 1;
+ SM_CXVSCROLL = 2;
+ SM_CYHSCROLL = 3;
+ SM_CYCAPTION = 4;
+ SM_CXBORDER = 5;
+ SM_CYBORDER = 6;
+ SM_CXDLGFRAME = 7;
+ SM_CYDLGFRAME = 8;
+ SM_CYVTHUMB = 9;
+ SM_CXHTHUMB = 10;
+ SM_CXICON = 11;
+ SM_CYICON = 12;
+ SM_CXCURSOR = 13;
+ SM_CYCURSOR = 14;
+ SM_CYMENU = 15;
+ SM_CXFULLSCREEN = 16;
+ SM_CYFULLSCREEN = 17;
+ SM_CYKANJIWINDOW = 18;
+ SM_MOUSEPRESENT = 19;
+ SM_CYVSCROLL = 20;
+ SM_CXHSCROLL = 21;
+ SM_DEBUG = 22;
+ SM_SWAPBUTTON = 23;
+ SM_RESERVED1 = 24;
+ SM_RESERVED2 = 25;
+ SM_RESERVED3 = 26;
+ SM_RESERVED4 = 27;
+ SM_CXMIN = 28;
+ SM_CYMIN = 29;
+ SM_CXSIZE = 30;
+ SM_CYSIZE = 31;
+ SM_CXFRAME = 32;
+ SM_CYFRAME = 33;
+ SM_CXMINTRACK = 34;
+ SM_CYMINTRACK = 35;
+ SM_CMETRICS = 36;
+
+
+{ $IFDECL GetSystemMetrics $THEN BEGIN }
+ FUNCTION GetSystemMetrics (
+ i_ : int
+ ) : int;
+{ $END }
+
+
+{ $IFDECL HiliteMenuItem $THEN BEGIN }
+ FUNCTION HiliteMenuItem (
+ h_ : HWND;
+ i_ : HMENU;
+ w_,x_ : WORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetMenuString $THEN BEGIN }
+ FUNCTION GetMenuString (
+ h_ : HMENU;
+ w_ : WORD;
+ l_ : LPSTR;
+ i_ : int;
+ x_ : WORD
+ ) : int;
+{ $END }
+
+{ $IFDECL GetMenuState $THEN BEGIN }
+ FUNCTION GetMenuState (
+ h_ : HMENU;
+ w_ : WORD;
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetMenuItemID $THEN BEGIN }
+ FUNCTION GetMenuItemID (
+ h_ : HMENU;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetMenuItemCount $THEN BEGIN }
+ FUNCTION GetMenuItemCount (
+ h_ : HMENU
+ ) : WORD;
+{ $END }
+
+{ $IFDECL DrawMenuBar $THEN BEGIN }
+ PROCEDURE DrawMenuBar (
+ h_ : HWND
+ );
+{ $END }
+
+{ $IFDECL GetSystemMenu $THEN BEGIN }
+ FUNCTION GetSystemMenu (
+ h_ : HWND;
+ b_ : BOOL
+ ) : HMENU;
+{ $END }
+
+{ $IFDECL CreateMenu $THEN BEGIN }
+ FUNCTION CreateMenu : HMENU;
+{ $END }
+
+{ $IFDECL DestroyMenu $THEN BEGIN }
+ FUNCTION DestroyMenu (
+ h_ : HMENU
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL ChangeMenu $THEN BEGIN }
+ FUNCTION ChangeMenu (
+ h_ : HMENU;
+ w_ : WORD;
+ l_ : LPSTR;
+ x_,y_ : WORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL CheckMenuItem $THEN BEGIN }
+ FUNCTION CheckMenuItem (
+ h_ : HMENU;
+ w_,x_ : WORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL EnableMenuItem $THEN BEGIN }
+ FUNCTION EnableMenuItem (
+ h_ : HMENU;
+ w_,x_ : WORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetSubMenu $THEN BEGIN }
+ FUNCTION GetSubMenu (
+ h_ : HMENU;
+ i_ : int
+ ) : HMENU;
+{ $END }
+
+{ $IFDECL EndMenu $THEN BEGIN }
+ PROCEDURE EndMenu;
+{ $END }
+
+
+{ $IFDECL GrayString $THEN BEGIN }
+ FUNCTION GrayString (
+ h_ : HDC;
+ i_ : HBRUSH;
+ f_ : FARPROC;
+ d_ : DWORD;
+ j_,k_,l_,m_,n_ : int
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL UpdateWindow $THEN BEGIN }
+ PROCEDURE UpdateWindow (
+ h_ : HWND
+ );
+{ $END }
+
+{ $IFDECL SetActiveWindow $THEN BEGIN }
+ FUNCTION SetActiveWindow (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+
+{ $IFDECL GetWindowDC $THEN BEGIN }
+ FUNCTION GetWindowDC (
+ h_ : HWND
+ ) : HDC;
+{ $END }
+
+{ $IFDECL GetDC $THEN BEGIN }
+ FUNCTION GetDC (
+ h_ : HWND
+ ) : HDC;
+{ $END }
+
+{ $IFDECL ReleaseDC $THEN BEGIN }
+ FUNCTION ReleaseDC (
+ h_ : HWND;
+ i_ : HDC
+ ) : int;
+{ $END }
+
+
+{ $IFDECL BeginPaint $THEN BEGIN }
+ FUNCTION BeginPaint (
+ h_ : HWND;
+ l_ : LPPAINTSTRUCT
+ ) : HDC;
+{ $END }
+
+
+{ $IFDECL EndPaint $THEN BEGIN }
+ PROCEDURE EndPaint (
+ h_ : HWND;
+ l_ : LPPAINTSTRUCT
+ );
+{ $END }
+
+{ $IFDECL GetUpdateRect $THEN BEGIN }
+ FUNCTION GetUpdateRect (
+ h_ : HWND;
+ l_ : LPRECT;
+ b_ : BOOL
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetUpdateRgn $THEN BEGIN }
+ FUNCTION GetUpdateRgn (
+ h_ : HWND;
+ r_ : HRGN;
+ b_ : BOOL
+ ) : int;
+{ $END }
+
+{ $IFDECL GetUpdateRgn $THEN BEGIN }
+ FUNCTION GetUpdateRgn (
+ d_ : HDC;
+ h_ : HWND
+ ) : short;
+{ $END }
+
+{ $IFDECL InvalidateRect $THEN BEGIN }
+ PROCEDURE InvalidateRect (
+ h_ : HWND;
+ l_ : LPRECT;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL ValidateRect $THEN BEGIN }
+ PROCEDURE ValidateRect (
+ h_ : HWND;
+ l_ : LPRECT
+ );
+{ $END }
+
+
+{ $IFDECL InvalidateRgn $THEN BEGIN }
+ PROCEDURE InvalidateRgn (
+ h_ : HWND;
+ i_ : HRGN;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL ValidateRgn $THEN BEGIN }
+ PROCEDURE ValidateRgn (
+ h_ : HWND;
+ i_ : HRGN
+ );
+{ $END }
+
+
+{ $IFDECL ScrollWindow $THEN BEGIN }
+ PROCEDURE ScrollWindow (
+ h_ : HWND;
+ i_,j_ : int;
+ l_,m_ : LPRECT
+ );
+{ $END }
+
+{ $IFDECL ScrollDC $THEN BEGIN }
+ FUNCTION ScrollDC (
+ h_ : HDC;
+ i_,j_ : int;
+ l_,m_ : LPRECT;
+ r_ : HRGN;
+ p_ : LPRECT
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SetScrollPos $THEN BEGIN }
+ FUNCTION SetScrollPos (
+ h_ : HWND;
+ i_,j_ : int;
+ b_ : BOOL
+ ) : int;
+{ $END }
+
+{ $IFDECL GetScrollPos $THEN BEGIN }
+ FUNCTION GetScrollPos (
+ h_ : HWND;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetScrollRange $THEN BEGIN }
+ PROCEDURE SetScrollRange (
+ h_ : HWND;
+ i_,j_,k_ : int;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL GetScrollRange $THEN BEGIN }
+ PROCEDURE GetScrollRange (
+ h_ : HWND;
+ i_ : int;
+ l_,m_ : LPINT
+ );
+{ $END }
+
+{ $IFDECL ShowScrollBar $THEN BEGIN }
+ PROCEDURE ShowScrollBar (
+ h_ : HWND;
+ w_ : WORD;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL SetProp $THEN BEGIN }
+ FUNCTION SetProp (
+ h_ : HWND;
+ l_ : LPSTR;
+ i_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetProp $THEN BEGIN }
+ FUNCTION GetProp (
+ h_ : HWND;
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL RemoveProp $THEN BEGIN }
+ FUNCTION RemoveProp (
+ h_ : HWND;
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL EnumProps $THEN BEGIN }
+ FUNCTION EnumProps (
+ h_ : HWND;
+ f_ : FARPROC
+ ) : int;
+{ $END }
+
+{ $IFDECL SetWindowText $THEN BEGIN }
+ PROCEDURE SetWindowText (
+ h_ : HWND;
+ l_ : LPSTR
+ );
+{ $END }
+
+{ $IFDECL GetWindowText $THEN BEGIN }
+ FUNCTION GetWindowText (
+ h_ : HWND;
+ l_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetWindowTextLength $THEN BEGIN }
+ FUNCTION GetWindowTextLength (
+ h_ : HWND
+ ) : int;
+{ $END }
+
+{ $IFDECL SetMenu $THEN BEGIN }
+ FUNCTION SetMenu (
+ h_ : HWND;
+ i_ : HMENU
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetMenu $THEN BEGIN }
+ FUNCTION GetMenu (
+ h_ : HWND
+ ) : HMENU;
+{ $END }
+
+
+{ $IFDECL GetClientRect $THEN BEGIN }
+ PROCEDURE GetClientRect (
+ h_ : HWND;
+ l_ : LPRECT
+ );
+{ $END }
+
+{ $IFDECL GetWindowRect $THEN BEGIN }
+ PROCEDURE GetWindowRect (
+ h_ : HWND;
+ l_ : LPRECT
+ );
+{ $END }
+
+{ $IFDECL AdjustWindowRect $THEN BEGIN }
+ PROCEDURE AdjustWindowRect (
+ l_ : LPRECT
+ l2_ : long;
+ b_ : BOOL
+ );
+{ $END }
+
+(* MessageBox type_flags *)
+
+CONST
+ MB_OK = #0000;
+ MB_OKCANCEL = #0001;
+ MB_ABORTRETRYIGNORE = #0002;
+ MB_YESNOCANCEL = #0003;
+ MB_YESNO = #0004;
+ MB_RETRYCANCEL = #0005;
+
+ MB_ICONHAND = #0010;
+ MB_ICONQUESTION = #0020;
+ MB_ICONEXCLAMATION = #0030;
+ MB_ICONASTERISK = #0040;
+
+ MB_DEFBUTTON1 = #0000;
+ MB_DEFBUTTON2 = #0100;
+ MB_DEFBUTTON3 = #0200;
+
+ MB_APPLMODAL = #0000;
+ MB_SYSTEMMODAL = #1000;
+ MB_NOFOCUS = #8000;
+ MB_MISCMASK = #c000;
+ MB_TYPEMASK = #000f;
+ MB_ICONMASK = #00f0;
+ MB_DEFMASK = #0f00;
+ MB_MODEMASK = #3000;
+
+
+{ $IFDECL MessageBox $THEN BEGIN }
+ FUNCTION MessageBox (
+ h_ : HWND;
+ l_,m_ : LPSTR;
+ w_ : WORD
+ ) : int;
+{ $END }
+
+{ $IFDECL MessageBeep $THEN BEGIN }
+ FUNCTION MessageBeep (
+ w_ : WORD
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL ShowCursor $THEN BEGIN }
+ FUNCTION ShowCursor (
+ b_ : BOOL
+ ) : int;
+{ $END }
+
+
+{ $IFDECL SetCursor $THEN BEGIN }
+ FUNCTION SetCursor (
+ h_ : HCURSOR
+ ) : HCURSOR;
+{ $END }
+
+
+{ $IFDECL SetCursorPos $THEN BEGIN }
+ PROCEDURE SetCursorPos (
+ i_,j_ : int
+ );
+{ $END }
+
+
+{ $IFDECL GetCursorPos $THEN BEGIN }
+ PROCEDURE GetCursorPos (
+ l_ : LPPOINT
+ );
+{ $END }
+
+
+{ $IFDECL ClipCursor $THEN BEGIN }
+ PROCEDURE ClipCursor (
+ l_ : LPRECT
+ );
+{ $END }
+
+
+{ $IFDECL CreateCaret $THEN BEGIN }
+ PROCEDURE CreateCaret (
+ h_ : HWND;
+ i_ : HBITMAP;
+ j_,k_ : int
+ );
+{ $END }
+
+
+
+{ $IFDECL GetCaretBlinkTime $THEN BEGIN }
+ FUNCTION GetCaretBlinkTime : WORD;
+{ $END }
+
+{ $IFDECL SetCaretBlinkTime $THEN BEGIN }
+ PROCEDURE SetCaretBlinkTime (
+ w_ : WORD
+ );
+{ $END }
+
+{ $IFDECL DestroyCaret $THEN BEGIN }
+ PROCEDURE DestroyCaret;
+{ $END }
+
+{ $IFDECL HideCaret $THEN BEGIN }
+ PROCEDURE HideCaret (
+ h_ : HWND
+ );
+{ $END }
+
+{ $IFDECL ShowCaret $THEN BEGIN }
+ PROCEDURE ShowCaret (
+ h_ : HWND
+ );
+{ $END }
+
+{ $IFDECL SetCaretPos $THEN BEGIN }
+ PROCEDURE SetCaretPos (
+ i_,j_ : int
+ );
+{ $END }
+
+{ $IFDECL GetCaretPos $THEN BEGIN }
+ PROCEDURE GetCaretPos (
+ l_ : LPPOINT
+ );
+{ $END }
+
+{ $IFDECL ClientToScreen $THEN BEGIN }
+ PROCEDURE ClientToScreen (
+ h_ : HWND;
+ l_ : LPPOINT
+ );
+{ $END }
+
+{ $IFDECL ScreenToClient $THEN BEGIN }
+ PROCEDURE ScreenToClient (
+ h_ : HWND;
+ l_ : LPPOINT
+ );
+{ $END }
+
+{ $IFDECL WindowFromPoint $THEN BEGIN }
+ FUNCTION WindowFromPoint (
+ p_ : POINT
+ ) : HWND;
+{ $END }
+
+{ $IFDECL ChildWindowFromPoint $THEN BEGIN }
+ FUNCTION ChildWindowFromPoint (
+ h_ : HWND;
+ p_ : POINT
+ ) : HWND;
+{ $END }
+
+(* color type_indices *)
+(* for the WM_CTLCOLOR message *)
+
+CONST
+ CTLCOLOR_MSGBOX = 0;
+ CTLCOLOR_EDIT = 1;
+ CTLCOLOR_LISTBOX = 2;
+ CTLCOLOR_BTN = 3;
+ CTLCOLOR_DLG = 4;
+ CTLCOLOR_SCROLLBAR = 5;
+ CTLCOLOR_STATIC = 6;
+ CTLCOLOR_MAX = 8 (* three bits max *);
+
+ COLOR_SCROLLBAR = 0;
+ COLOR_BACKGROUND = 1;
+ COLOR_ACTIVECAPTION = 2;
+ COLOR_INACTIVECAPTION = 3;
+ COLOR_MENU = 4;
+ COLOR_WINDOW = 5;
+ COLOR_WINDOWFRAME = 6;
+ COLOR_MENUTEXT = 7;
+ COLOR_WINDOWTEXT = 8;
+ COLOR_CAPTIONTEXT = 9;
+ COLOR_ACTIVEBORDER = 10;
+ COLOR_INACTIVEBORDER = 11;
+ COLOR_APPWORKSPACE = 12;
+
+
+{ $IFDECL GetSysColor $THEN BEGIN }
+ FUNCTION GetSysColor (
+ i_ : int
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetSysColors $THEN BEGIN }
+ PROCEDURE SetSysColors (
+ i_ : int;
+ l_ : LPINT;
+ m_ : LPlong
+ );
+{ $END }
+
+ CP_GETBEEP = 1;
+ CP_SETBEEP = 2;
+ CP_GETMOUSE = 3;
+ CP_SETMOUSE = 4;
+ CP_GETBORDER = 5;
+ CP_SETBORDER = 6;
+ CP_TIMEOUTS = 7;
+ CP_KANJIMENU = 8;
+
+{ $IFDECL ControlPanelInfo $THEN BEGIN }
+ PROCEDURE ControlPanelInfo (
+ w_,x_ : WORD;
+ l_ : LONG
+ );
+{ $END }
+
+{ $IFDECL CreateDC $THEN BEGIN }
+ FUNCTION CreateDC (
+ l_,m_,n_,o_ : LPSTR
+ ) : HDC;
+{ $END }
+
+{ $IFDECL CreateIC $THEN BEGIN }
+ FUNCTION CreateIC (
+ l_,m_,n_,o_ : LPSTR
+ ) : HDC;
+{ $END }
+
+{ $IFDECL CreateCompatibleDC $THEN BEGIN }
+ FUNCTION CreateCompatibleDC (
+ h_ : HDC
+ ) : HDC;
+{ $END }
+
+{ $IFDECL DeleteDC $THEN BEGIN }
+ FUNCTION DeleteDC (
+ h_ : HDC
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SaveDC $THEN BEGIN }
+ FUNCTION SaveDC (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL RestoreDC $THEN BEGIN }
+ FUNCTION RestoreDC (
+ h_ : HDC;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL MoveTo $THEN BEGIN }
+ FUNCTION MoveTo (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetCurrentPosition $THEN BEGIN }
+ FUNCTION GetCurrentPosition (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL LineTo $THEN BEGIN }
+ FUNCTION LineTo (
+ h_ : HDC;
+ s_,t_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetDCOrg $THEN BEGIN }
+ FUNCTION GetDCOrg (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL ExtTextOut $THEN BEGIN }
+ FUNCTION ExtTextOut (
+ h_ : HDC;
+ s_,t_ : short;
+ w_ : WORD;
+ l_ : LPRECT;
+ p_ : LPSTR;
+ i_ : WORD;
+ n_ : LPINT
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL FastWindowFrame $THEN BEGIN }
+ FUNCTION FastWindowFrame (
+ h_ : HDC;
+ l_ : LPRECT;
+ w_,x_ : WORD;
+ i_ : DWORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Polyline $THEN BEGIN }
+ FUNCTION Polyline (
+ h_ : HDC;
+ l_ : LPPOINT;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Polygon $THEN BEGIN }
+ FUNCTION Polygon (
+ h_ : HDC;
+ l_ : LPPOINT;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL Rectangle $THEN BEGIN }
+ FUNCTION Rectangle (
+ h_ : HDC;
+ s_,t_,u_,v_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL RoundRect $THEN BEGIN }
+ FUNCTION RoundRect (
+ h_ : HDC;
+ s_,t_,u_,v_,w_,x_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Ellipse $THEN BEGIN }
+ FUNCTION Ellipse (
+ h_ : HDC;
+ s_,t_,u_,v_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Arc $THEN BEGIN }
+ FUNCTION Arc (
+ h_ : HDC;
+ s_,t_,u_,v_,w_,x_,y_,z_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Chord $THEN BEGIN }
+ FUNCTION Chord (
+ h_ : HDC;
+ s_,t_,u_,v_,w_,x_,y_,z_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Pie $THEN BEGIN }
+ FUNCTION Pie (
+ h_ : HDC;
+ s_,t_,u_,v_,w_,x_,y_,z_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PatBlt $THEN BEGIN }
+ FUNCTION PatBlt (
+ h_ : HDC;
+ s_,t_,u_,v_ : short;
+ d_ : DWORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL BitBlt $THEN BEGIN }
+ FUNCTION BitBlt (
+ h_ : HDC;
+ s_,t_,u_,v_ : short;
+ i_ : HDC;
+ w_,x_ : short;
+ d_ : DWORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL StretchBlt $THEN BEGIN }
+ FUNCTION StretchBlt (
+ h_ : HDC;
+ s_,t_,u_,v_ : short;
+ i_ : HDC;
+ w_,x_,y_,z_ : short;
+ d_ : DWORD
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL TextOut $THEN BEGIN }
+ FUNCTION TextOut (
+ h_ : HDC;
+ s_,t_ : short;
+ l_ : LPSTR;
+ u_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetCharWidth $THEN BEGIN }
+ FUNCTION GetCharWidth (
+ h_ : HDC;
+ w_,x_ : WORD;
+ l_ : LPINT
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SetPixel $THEN BEGIN }
+ FUNCTION SetPixel (
+ h_ : HDC;
+ s_,t_ : short;
+ d_ : DWORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetPixel $THEN BEGIN }
+ FUNCTION GetPixel (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL FloodFill $THEN BEGIN }
+ FUNCTION FloodFill (
+ h_ : HDC;
+ s_,t_ : short;
+ d_ : DWORD
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL LineDDA $THEN BEGIN }
+ PROCEDURE LineDDA (
+ s_,t_,u_,v_ : short;
+ f_ : FARPROC;
+ l_ : LPSTR
+ );
+{ $END }
+
+
+{ $IFDECL FillRect $THEN BEGIN }
+ FUNCTION FillRect (
+ h_ : HDC;
+ l_ : LPRECT;
+ i_ : HBRUSH
+ ) : int;
+{ $END }
+
+{ $IFDECL FrameRect $THEN BEGIN }
+ FUNCTION FrameRect (
+ h_ : HDC;
+ l_ : LPRECT;
+ i_ : HBRUSH
+ ) : int;
+{ $END }
+
+{ $IFDECL InvertRect $THEN BEGIN }
+ FUNCTION InvertRect (
+ h_ : HDC;
+ l_ : LPRECT
+ ) : int;
+{ $END }
+
+
+
+{ $IFDECL FillRgn $THEN BEGIN }
+ FUNCTION FillRgn (
+ h_ : HDC;
+ i_ : HRGN;
+ j_ : HBRUSH
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL FrameRgn $THEN BEGIN }
+ FUNCTION FrameRgn (
+ h_ : HDC;
+ i_ : HRGN;
+ j_ : HBRUSH;
+ s_,t_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL InvertRgn $THEN BEGIN }
+ FUNCTION InvertRgn (
+ h_ : HDC;
+ i_ : HRGN
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PaintRgn $THEN BEGIN }
+ FUNCTION PaintRgn (
+ h_ : HDC;
+ i_ : HRGN
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PtInRegion $THEN BEGIN }
+ FUNCTION PtInRegion (
+ h_ : HRGN;
+ s_,t_ : short
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL GetStockObject $THEN BEGIN }
+ FUNCTION GetStockObject (
+ s_ : short
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL CreatePen $THEN BEGIN }
+ FUNCTION CreatePen (
+ s_,t_ : short;
+ d_ : DWORD
+ ) : HPEN;
+{ $END }
+
+{ $IFDECL CreatePenIndirect $THEN BEGIN }
+ FUNCTION CreatePenIndirect (
+ l_ : LPLOGPEN
+ ) : HPEN;
+{ $END }
+
+
+{ $IFDECL CreateSolidBrush $THEN BEGIN }
+ FUNCTION CreateSolidBrush (
+ d_ : DWORD
+ ) : HBRUSH;
+{ $END }
+
+{ $IFDECL CreateHatchBrush $THEN BEGIN }
+ FUNCTION CreateHatchBrush (
+ s_ : short;
+ d_ : DWORD
+ ) : HBRUSH;
+{ $END }
+
+{ $IFDECL SetBrushOrg $THEN BEGIN }
+ FUNCTION SetBrushOrg (
+ h_ : HDC;
+ i_,j_ : int
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetBrushOrg $THEN BEGIN }
+ FUNCTION GetBrushOrg (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL UnrealizeObject $THEN BEGIN }
+ FUNCTION UnrealizeObject (
+ h_ : HBRUSH
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL CreatePatternBrush $THEN BEGIN }
+ FUNCTION CreatePatternBrush (
+ h_ : HBITMAP
+ ) : HBRUSH;
+{ $END }
+
+{ $IFDECL CreateBrushIndirect $THEN BEGIN }
+ FUNCTION CreateBrushIndirect (
+ l_ : LPLOGBRUSH
+ ) : HBRUSH;
+{ $END }
+
+
+
+{ $IFDECL CreateBitmap $THEN BEGIN }
+ FUNCTION CreateBitmap (
+ s_,t_ : short;
+ b_,c_ : BYTE;
+ l_ : LPSTR
+ ) : HBITMAP;
+{ $END }
+
+{ $IFDECL CreateBitmapIndirect $THEN BEGIN }
+ FUNCTION CreateBitmapIndirect (
+ b_ : LPBITMAP
+ ) : HBITMAP;
+{ $END }
+
+{ $IFDECL CreateCompatibleBitmap $THEN BEGIN }
+ FUNCTION CreateCompatibleBitmap (
+ h_ : HDC;
+ s_,t_ : short
+ ) : HBITMAP;
+{ $END }
+
+{ $IFDECL CreateDiscardableBitmap $THEN BEGIN }
+ FUNCTION CreateDiscardableBitmap (
+ h_ : HDC;
+ s_,t_ : short
+ ) : HBITMAP;
+{ $END }
+
+{ $IFDECL SetBitmapBits $THEN BEGIN }
+ FUNCTION SetBitmapBits (
+ h_ : HBITMAP;
+ d_ : DWORD;
+ l_ : LPSTR
+ ) : long;
+{ $END }
+
+{ $IFDECL GetBitmapBits $THEN BEGIN }
+ FUNCTION GetBitmapBits (
+ h_ : HBITMAP;
+ l_ : long;
+ m_ : LPSTR
+ ) : long;
+{ $END }
+
+{ $IFDECL SetBitmapDimension $THEN BEGIN }
+ FUNCTION SetBitmapDimension (
+ h_ : HBITMAP;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetBitmapDimension $THEN BEGIN }
+ FUNCTION GetBitmapDimension (
+ h_ : HBITMAP
+ ) : DWORD;
+{ $END }
+
+
+{ $IFDECL CreateFont $THEN BEGIN }
+ FUNCTION CreateFont (
+ s_,t_,u_,v_,w_ : short;
+ b_,c_,d_,e_,f_,g_,h_,i_ : BYTE;
+ l_ : LPSTR
+ ) : HFONT;
+{ $END }
+
+{ $IFDECL CreateFontIndirect $THEN BEGIN }
+ FUNCTION CreateFontIndirect (
+ l_ : LPLOGFONT
+ ) : HFONT;
+{ $END }
+
+
+{ $IFDECL CreateRectRgn $THEN BEGIN }
+ FUNCTION CreateRectRgn (
+ s_,t_,u_,v_ : short
+ ) : HRGN;
+{ $END }
+
+{ $IFDECL SetRectRgn $THEN BEGIN }
+ PROCEDURE SetRectRgn (
+ h_ : HRGN;
+ s_,t_,u_,v_ : short;
+ );
+{ $END }
+
+
+{ $IFDECL CreateRectRgnIndirect $THEN BEGIN }
+ FUNCTION CreateRectRgnIndirect (
+ l_ : LPRECT
+ ) : HRGN;
+{ $END }
+
+{ $IFDECL CreateEllipticRgnIndirect $THEN BEGIN }
+ FUNCTION CreateEllipticRgnIndirect (
+ l_ : LPRECT
+ ) : HRGN;
+{ $END }
+
+
+{ $IFDECL CreateEllipticRgn $THEN BEGIN }
+ FUNCTION CreateEllipticRgn (
+ s_,t_,u_,v_ : short
+ ) : HRGN;
+{ $END }
+
+{ $IFDECL CreatePolygonRgn $THEN BEGIN }
+ FUNCTION CreatePolygonRgn (
+ l_ : LPPOINT;
+ s_,t_ : short
+ ) : HRGN;
+{ $END }
+
+
+{ $IFDECL DeleteObject $THEN BEGIN }
+ FUNCTION DeleteObject (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SelectObject $THEN BEGIN }
+ FUNCTION SelectObject (
+ h_ : HDC;
+ i_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL SelectClipRgn $THEN BEGIN }
+ FUNCTION SelectClipRgn (
+ h_ : HDC;
+ i_ : HRGN
+ ) : short;
+{ $END }
+
+
+{ $IFDECL GetObject $THEN BEGIN }
+ FUNCTION GetObject (
+ h_ : HANDLE;
+ s_ : short;
+ l_ : LPSTR
+ ) : short;
+{ $END }
+
+
+{ $IFDECL SetRelAbs $THEN BEGIN }
+ FUNCTION SetRelAbs (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetRelAbs $THEN BEGIN }
+ FUNCTION GetRelAbs (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetBkColor $THEN BEGIN }
+ FUNCTION SetBkColor (
+ h_ : HDC;
+ d_ : DWORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetBkColor $THEN BEGIN }
+ FUNCTION GetBkColor (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetBkMode $THEN BEGIN }
+ FUNCTION SetBkMode (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetBkMode $THEN BEGIN }
+ FUNCTION GetBkMode (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetTextColor $THEN BEGIN }
+ FUNCTION SetTextColor (
+ h_ : HDC;
+ d_ : DWORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetTextColor $THEN BEGIN }
+ FUNCTION GetTextColor (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetTextAlign $THEN BEGIN }
+ FUNCTION SetTextAlign (
+ h_ : HDC;
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetTextAlign $THEN BEGIN }
+ FUNCTION GetTextAlign (
+ h_ : HDC
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SetMapperFlags $THEN BEGIN }
+ FUNCTION SetMapperFlags (
+ h_ : HDC;
+ w_ : WORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetAspectRatioFilter $THEN BEGIN }
+ FUNCTION GetAspectRatioFilter (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetNearestColor $THEN BEGIN }
+ FUNCTION GetNearestColor (
+ h_ : HDC;
+ d_ : DWORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetROP2 $THEN BEGIN }
+ FUNCTION SetROP2 (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetROP2 $THEN BEGIN }
+ FUNCTION GetROP2 (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetStretchBltMode $THEN BEGIN }
+ FUNCTION SetStretchBltMode (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetStretchBltMode $THEN BEGIN }
+ FUNCTION GetStretchBltMode (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetPolyFillMode $THEN BEGIN }
+ FUNCTION SetPolyFillMode (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetPolyFillMode $THEN BEGIN }
+ FUNCTION GetPolyFillMode (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetMapMode $THEN BEGIN }
+ FUNCTION SetMapMode (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetMapMode $THEN BEGIN }
+ FUNCTION GetMapMode (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+{ $IFDECL SetWindowOrg $THEN BEGIN }
+ FUNCTION SetWindowOrg (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetWindowOrg $THEN BEGIN }
+ FUNCTION GetWindowOrg (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetWindowExt $THEN BEGIN }
+ FUNCTION SetWindowExt (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetWindowExt $THEN BEGIN }
+ FUNCTION GetWindowExt (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetViewportOrg $THEN BEGIN }
+ FUNCTION SetViewportOrg (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetViewportOrg $THEN BEGIN }
+ FUNCTION GetViewportOrg (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetViewportExt $THEN BEGIN }
+ FUNCTION SetViewportExt (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GetViewportExt $THEN BEGIN }
+ FUNCTION GetViewportExt (
+ h_ : HDC
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL OffsetViewportOrg $THEN BEGIN }
+ FUNCTION OffsetViewportOrg (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL ScaleViewportExt $THEN BEGIN }
+ FUNCTION ScaleViewportExt (
+ h_ : HDC;
+ s_,t_,r_,q_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL OffsetWindowOrg $THEN BEGIN }
+ FUNCTION OffsetWindowOrg (
+ h_ : HDC;
+ s_,t_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL ScaleWindowExt $THEN BEGIN }
+ FUNCTION ScaleWindowExt (
+ h_ : HDC;
+ s_,t_,r_,q_ : short
+ ) : DWORD;
+{ $END }
+
+
+{ $IFDECL GetClipBox $THEN BEGIN }
+ FUNCTION GetClipBox (
+ h_ : HDC;
+ l_ : LPRECT
+ ) : short;
+{ $END }
+
+
+{ $IFDECL IntersectClipRect $THEN BEGIN }
+ FUNCTION IntersectClipRect (
+ h_ : HDC;
+ s_,t_,u_,v_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL OffsetClipRgn $THEN BEGIN }
+ FUNCTION OffsetClipRgn (
+ h_ : HDC;
+ s_,t_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL ExcludeClipRect $THEN BEGIN }
+ FUNCTION ExcludeClipRect (
+ h_ : HDC;
+ s_,t_,u_,v_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL PtVisible $THEN BEGIN }
+ FUNCTION PtVisible (
+ h_ : HDC;
+ s_,t_ : short
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL SetRect $THEN BEGIN }
+ FUNCTION SetRect (
+ l_ : LPRECT;
+ i_,j_,k_,m_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetRectEmpty $THEN BEGIN }
+ FUNCTION SetRectEmpty (
+ l_ : LPRECT
+ ) : int;
+{ $END }
+
+{ $IFDECL CopyRect $THEN BEGIN }
+ FUNCTION CopyRect (
+ l_,m_ : LPRECT
+ ) : int;
+{ $END }
+
+{ $IFDECL InflateRect $THEN BEGIN }
+ FUNCTION InflateRect (
+ l_ : LPRECT;
+ i_,j_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL IntersectRect $THEN BEGIN }
+ FUNCTION IntersectRect (
+ l_,m_,n_ : LPRECT
+ ) : int;
+{ $END }
+
+{ $IFDECL UnionRect $THEN BEGIN }
+ FUNCTION UnionRect (
+ l_,m_,n_ : LPRECT
+ ) : int;
+{ $END }
+
+{ $IFDECL OffsetRect $THEN BEGIN }
+ FUNCTION OffsetRect (
+ l_ : LPRECT;
+ i_,j_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL IsRectEmpty $THEN BEGIN }
+ FUNCTION IsRectEmpty (
+ l_ : LPRECT
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL EqualRect $THEN BEGIN }
+ FUNCTION EqualRect (
+ l_,k_ : LPRECT
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL PtInRect $THEN BEGIN }
+ FUNCTION PtInRect (
+ l_ : LPRECT;
+ p_ : POINT
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL RectVisible $THEN BEGIN }
+ FUNCTION RectVisible (
+ h_ : HDC;
+ l_ : LPRECT
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL CombineRgn $THEN BEGIN }
+ FUNCTION CombineRgn (
+ h_,i_,j_ : HRGN;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL EqualRgn $THEN BEGIN }
+ FUNCTION EqualRgn (
+ h_,i_ : HRGN
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL OffsetRgn $THEN BEGIN }
+ FUNCTION OffsetRgn (
+ h_ : HRGN;
+ s_,t_ : short
+ ) : short;
+{ $END }
+
+
+{ $IFDECL SetTextJustification $THEN BEGIN }
+ FUNCTION SetTextJustification (
+ h_ : HDC;
+ s_,t_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetTextExtent $THEN BEGIN }
+ FUNCTION GetTextExtent (
+ h_ : HDC;
+ l_ : LPSTR;
+ s_ : short
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL SetTextCharacterExtra $THEN BEGIN }
+ FUNCTION SetTextCharacterExtra (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetTextCharacterExtra $THEN BEGIN }
+ FUNCTION GetTextCharacterExtra (
+ h_ : HDC
+ ) : short;
+{ $END }
+
+
+{ $IFDECL GetMetaFile $THEN BEGIN }
+ FUNCTION GetMetaFile (
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL DeleteMetaFile $THEN BEGIN }
+ FUNCTION DeleteMetaFile (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL CopyMetaFile $THEN BEGIN }
+ FUNCTION CopyMetaFile (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL PlayMetaFileRecord $THEN BEGIN }
+ PROCEDURE PlayMetaFileRecord (
+ h_ : HDC;
+ i_ : LPHANDLETABLE;
+ j_ : LPMETARECORD;
+ w_ : WORD;
+ );
+{ $END }
+
+{ $IFDECL EnumMetaFile $THEN BEGIN }
+ FUNCTION EnumMetaFile (
+ h_ : HDC;
+ i_ : LOCALHANDLE;
+ f_ : FARPROC;
+ a_ ; ADS OF BYTE
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL PlayMetaFile $THEN BEGIN }
+ FUNCTION PlayMetaFile (
+ h_ : HDC;
+ i_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL Escape $THEN BEGIN }
+ FUNCTION Escape (
+ h_ : HDC;
+ s_,t_ : short;
+ l_,m_ : LPSTR
+ ) : short;
+{ $END }
+
+{ $IFDECL EnumFonts $THEN BEGIN }
+ FUNCTION EnumFonts (
+ h_ : HDC;
+ l_ : LPSTR;
+ f_ : FARPROC;
+ m_ : LPSTR
+ ) : short;
+{ $END }
+
+{ $IFDECL EnumObjects $THEN BEGIN }
+ FUNCTION EnumObjects (
+ h_ : HDC;
+ s_ : short;
+ f_ : FARPROC;
+ l_ : LPSTR
+ ) : short;
+{ $END }
+
+{ $IFDECL GetTextFace $THEN BEGIN }
+ FUNCTION GetTextFace (
+ h_ : HDC;
+ s_ : short;
+ l_ : LPSTR
+ ) : short;
+{ $END }
+
+{ $IFDECL GetTextMetrics $THEN BEGIN }
+ FUNCTION GetTextMetrics (
+ h_ : HDC;
+ l_ : LPTEXTMETRIC
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetDeviceCaps $THEN BEGIN }
+ FUNCTION GetDeviceCaps (
+ h_ : HDC;
+ s_ : short
+ ) : short;
+{ $END }
+
+
+{ $IFDECL DeviceModes $THEN BEGIN }
+ FUNCTION DeviceModes (
+ h_ : HWND;
+ i_ : HANDLE;
+ l_,m_ : LPSTR
+ ) : LPSTR;
+{ $END }
+
+{ $IFDECL SetEnvironment $THEN BEGIN }
+ FUNCTION SetEnvironment (
+ l_,m_ : LPSTR;
+ w_ : WORD
+ ) : short;
+{ $END }
+
+{ $IFDECL GetEnvironment $THEN BEGIN }
+ FUNCTION GetEnvironment (
+ l_,m_ : LPSTR;
+ w_ : WORD
+ ) : short;
+{ $END }
+
+
+{ $IFDECL DPtoLP $THEN BEGIN }
+ FUNCTION DPtoLP (
+ h_ : HDC;
+ l_ : LPPOINT;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL LPtoDP $THEN BEGIN }
+ FUNCTION LPtoDP (
+ h_ : HDC;
+ l_ : LPPOINT;
+ s_ : short
+ ) : BOOL;
+{ $END }
+
+(* Interface to the dynamic loader/linker *)
+
+
+{ $IFDECL GetVersion $THEN BEGIN }
+ FUNCTION GetVersion : WORD;
+{ $END }
+
+{ $IFDECL GetNumTasks $THEN BEGIN }
+ FUNCTION GetNumTasks : WORD;
+{ $END }
+
+{ $IFDECL GetCodeHandle $THEN BEGIN }
+ FUNCTION GetCodeHandle (
+ f_ : FARPROC
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GetModuleHandle $THEN BEGIN }
+ FUNCTION GetModuleHandle (
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GetModuleUsage $THEN BEGIN }
+ FUNCTION GetModuleUsage (
+ h_ : HANDLE
+ ) : int;
+{ $END }
+
+{ $IFDECL GetModuleFileName $THEN BEGIN }
+ FUNCTION GetModuleFileName (
+ h_ : HANDLE;
+ l_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetInstanceData $THEN BEGIN }
+ FUNCTION GetInstanceData (
+ h_ : HANDLE;
+ n_ : NPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetProcAddress $THEN BEGIN }
+ FUNCTION GetProcAddress (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : FARPROC;
+{ $END }
+
+{ $IFDECL MakeProcInstance $THEN BEGIN }
+ FUNCTION MakeProcInstance (
+ f_ : FARPROC;
+ h_ : HANDLE
+ ) : FARPROC;
+{ $END }
+
+{ $IFDECL FreeProcInstance $THEN BEGIN }
+ PROCEDURE FreeProcInstance (
+ f_ : FARPROC
+ );
+{ $END }
+
+{ $IFDECL LoadLibrary $THEN BEGIN }
+ FUNCTION LoadLibrary (
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL FreeLibrary $THEN BEGIN }
+ FUNCTION FreeLibrary (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL AnsiToOem $THEN BEGIN }
+ FUNCTION AnsiToOem (
+ l_,m_ : LPSTR
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL OemToAnsi $THEN BEGIN }
+ FUNCTION OemToAnsi (
+ l_,m_ : LPSTR
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL AnsiUpper $THEN BEGIN }
+ FUNCTION AnsiUpper (
+ l_ : LPSTR
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL AnsiLower $THEN BEGIN }
+ FUNCTION AnsiLower (
+ l_ : LPSTR
+ ) : BYTE;
+{ $END }
+
+{ $IFDECL AnsiNext $THEN BEGIN }
+ FUNCTION AnsiNext (
+ l_ : LPSTR
+ ) : LPSTR;
+{ $END }
+
+{ $IFDECL AnsiPrev $THEN BEGIN }
+ FUNCTION AnsiPrev (
+ l_,m_ : LPSTR
+ ) : LPSTR;
+{ $END }
+
+
+
+TYPE
+ OFSTRUCT = RECORD
+ cBytes : BYTE; (* length of structure *)
+ fFixedDisk : BYTE; (* non-zero if file located on non- *)
+ (* removeable media *)
+ nErrCode : WORD; (* DOS error code if OpenFile fails *)
+ reserved : ARRAY [0..3] OF BYTE;
+ szPathName : ARRAY [0..127] OF BYTE;
+ END;
+ POFSTRUCT = ADR OF OFSTRUCT;
+ NPOFSTRUCT = ADR OF OFSTRUCT;
+ LPOFSTRUCT = ADS OF OFSTRUCT;
+
+
+{ $IFDECL GetTempDrive $THEN BEGIN }
+ FUNCTION GetTempDrive (
+ b_ : BYTE
+ ) : BYTE;
+{ $END }
+
+
+{ $IFDECL GetTempFileName $THEN BEGIN }
+ FUNCTION GetTempFileName (
+ b_ : BYTE;
+ l_ : LPSTR;
+ w_ : WORD;
+ m_ : LPSTR
+ ) : int;
+{ $END }
+
+{ $IFDECL OpenFile $THEN BEGIN }
+ FUNCTION OpenFile (
+ l_ : LPSTR;
+ m_ : LPOFSTRUCT;
+ w_ : WORD
+ ) : int;
+{ $END }
+
+(* Flags for GetTempFileName *)
+
+CONST
+ TF_FORCEDRIVE = #80; (* Forces use of current dir of passed *)
+ (* drive *)
+
+(* Flags for OpenFile *)
+
+CONST
+ OF_REOPEN = #8000;
+ OF_EXIST = #4000;
+ OF_PROMPT = #2000;
+ OF_CREATE = #1000;
+ OF_CANCEL = #0800;
+ OF_VERIFY = #0400;
+ OF_DELETE = #0200;
+ OF_PARSE = #0100;
+
+ OF_READ = 0;
+ OF_WRITE = 1;
+ OF_READWRITE = 2;
+
+(* Interface to global memory manager *)
+ GMEM_FIXED = #0000;
+ GMEM_MOVEABLE = #0002;
+ GMEM_NOCOMPACT = #0010;
+ GMEM_NODISCARD = #0020;
+ GMEM_ZEROINIT = #0040;
+ GMEM_MODIFY = #0080;
+ GMEM_DISCARDABLE = #0F00;
+ GHND = (GMEM_MOVEABLE OR GMEM_ZEROINIT);
+ GPTR = (GMEM_FIXED OR GMEM_ZEROINIT);
+ GMEM_SHARE = #2000;
+ GMEM_DDESHARE = #2000;
+ GMEM_LOWER = #1000;
+ GMEM_NOTIFY = #4000;
+ GMEM_NOT_BANKED = #1000;
+
+
+{ $IFDECL GlobalAlloc $THEN BEGIN }
+ FUNCTION GlobalAlloc (
+ w_ : WORD;
+ d_ : DWORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalCompact $THEN BEGIN }
+ FUNCTION GlobalCompact (
+ d_ : DWORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GlobalDiscard $THEN BEGIN }
+ FUNCTION GlobalDiscard (
+ h_ : HANDLE;
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalFree $THEN BEGIN }
+ FUNCTION GlobalFree (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalHandle $THEN BEGIN }
+ FUNCTION GlobalHandle (
+ w_ : WORD
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GlobalLock $THEN BEGIN }
+ FUNCTION GlobalLock (
+ h_ : HANDLE
+ ) : LPSTR;
+{ $END }
+
+{ $IFDECL GlobalReAlloc $THEN BEGIN }
+ FUNCTION GlobalReAlloc (
+ h_ : HANDLE;
+ d_ : DWORD;
+ w_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalSize $THEN BEGIN }
+ FUNCTION GlobalSize (
+ h_ : HANDLE
+ ) : DWORD;
+{ $END }
+
+{ $IFDECL GlobalFlags $THEN BEGIN }
+ FUNCTION GlobalFlags (
+ h_ : HANDLE
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GlobalWire $THEN BEGIN }
+ FUNCTION GlobalWire (
+ h_ : HANDLE
+ ) : LPSTR;
+{ $END }
+
+{ $IFDECL GlobalUnWire $THEN BEGIN }
+ FUNCTION GlobalUnWire (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GlobalUnlock $THEN BEGIN }
+ FUNCTION GlobalUnlock (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL UnlockResource $THEN BEGIN }
+ FUNCTION UnlockResource ( h_ : HANDLE) : BOOL;
+ BEGIN
+ UnlockResource := GlobalUnlock(h_)
+ END;
+{ $END }
+
+{ $IFDECL GlobalLRUNewest $THEN BEGIN }
+ FUNCTION GlobalLRUNewest (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalLRUOldest $THEN BEGIN }
+ FUNCTION GlobalLRUOldest (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GlobalNotify $THEN BEGIN }
+ PROCEDURE GlobalNotify (
+ l_ : LPSTR
+ );
+{ $END }
+
+(* Flags returned by GlobalFlags (in addition to GMEM_DISCARDABLE) *)
+
+CONST
+ GMEM_DISCARDED = #4000;
+ GMEM_SWAPPED = #8000;
+ GMEM_LOCKCOUNT = #00FF;
+
+{ $IFDECL LockData $THEN BEGIN }
+ FUNCTION LockData (
+ i_ : int
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL UnlockData $THEN BEGIN }
+ FUNCTION UnlockData (
+ i_ : int
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL LockSegment $THEN BEGIN }
+ FUNCTION LockSegment (
+ w_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL UnlockSegment $THEN BEGIN }
+ FUNCTION UnlockSegment (
+ w_ : WORD
+ ) : HANDLE;
+{ $END }
+
+(* Interface to local memory manager *)
+
+
+CONST
+ LMEM_FIXED = #0000;
+ LMEM_MOVEABLE = #0002;
+ LMEM_NOCOMPACT = #0010;
+ LMEM_NODISCARD = #0020;
+ LMEM_ZEROINIT = #0040;
+ LMEM_MODIFY = #0080;
+ LMEM_DISCARDABLE = #0F00;
+ LHND = (LMEM_MOVEABLE OR LMEM_ZEROINIT);
+ LPTR = (LMEM_FIXED OR LMEM_ZEROINIT);
+ NONZEROLHND = (LMEM_MOVEABLE);
+ NONZEROLPTR = (LMEM_FIXED);
+
+ LNOTIFY_OUTOFMEM = 0;
+ LNOTIFY_MOVE = 1;
+ LNOTIFY_DISCARD = 2;
+
+
+{ $IFDECL LocalAlloc $THEN BEGIN }
+ FUNCTION LocalAlloc (
+ w_,x_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LocalCompact $THEN BEGIN }
+ FUNCTION LocalCompact (
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL LocalDiscard $THEN BEGIN }
+ FUNCTION LocalDiscard (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LocalFree $THEN BEGIN }
+ FUNCTION LocalFree (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LocalHandle $THEN BEGIN }
+ FUNCTION LocalHandle (
+ w_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LocalFreeze $THEN BEGIN }
+ PROCEDURE LocalFreeze (
+ i_ : int
+ );
+{ $END }
+
+{ $IFDECL LocalHandleDelta $THEN BEGIN }
+ FUNCTION LocalHandleDelta (
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL LocalInit $THEN BEGIN }
+ FUNCTION LocalInit (
+ w_ : WORD;
+ p_,q_ : PSTR
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL LocalLock $THEN BEGIN }
+ FUNCTION LocalLock (
+ h_ : HANDLE
+ ) : PSTR;
+{ $END }
+
+{ $IFDECL LocalMelt $THEN BEGIN }
+ PROCEDURE LocalMelt (
+ i_ : int
+ );
+{ $END }
+
+{ $IFDECL LocalNotify $THEN BEGIN }
+ FUNCTION LocalNotify (
+ f_ : FARPROC
+ ) : FARPROC;
+{ $END }
+
+{ $IFDECL LocalReAlloc $THEN BEGIN }
+ FUNCTION LocalReAlloc (
+ h_ : HANDLE;
+ w_,x_ : WORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LocalSize $THEN BEGIN }
+ FUNCTION LocalSize (
+ h_ : HANDLE
+ ) : WORD;
+{ $END }
+
+{ $IFDECL LocalUnlock $THEN BEGIN }
+ FUNCTION LocalUnlock (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL LocalFlags $THEN BEGIN }
+ FUNCTION LocalFlags (
+ h_ : HANDLE
+ ) : WORD;
+{ $END }
+
+{ $IFDECL LocalShrink $THEN BEGIN }
+ FUNCTION LocalShrink (
+ h_ : HANDLE;
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+(* Flags returned by LocalFlags (in addition to LMEM_DISCARDABLE) *)
+
+CONST
+ LMEM_DISCARDED = #4000;
+ LMEM_LOCKCOUNT = #00FF;
+
+(* SetSwapAreaSize really returns 2 words -
+ lo word is Size actually set (or current size if you passed in 0)
+ hi word is Max size you can get
+*)
+
+{ $IFDECL SetSwapAreaSize $THEN BEGIN }
+ FUNCTION SetSwapAreaSize (
+ w_ : WORD
+ ) : LONG;
+{ $END }
+
+{ $IFDECL ValidateFreeSpaces $THEN BEGIN }
+ FUNCTION ValidateFreeSpaces : LPSTR;
+{ $END }
+
+{ $IFDECL LimitEmsPages $THEN BEGIN }
+ PROCEDURE LimitEmsPages (
+ w_ : DWORD
+ );
+{ $END }
+
+{ $IFDECL SetErrorMode $THEN BEGIN }
+ FUNCTION SetErrorMode (
+ w_ : WORD
+ ) : BOOL;
+{ $END }
+
+
+(* Interface to the resource manager *)
+
+
+{ $IFDECL FindResource $THEN BEGIN }
+ FUNCTION FindResource (
+ h_ : HANDLE;
+ l_,m_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL LoadResource $THEN BEGIN }
+ FUNCTION LoadResource (
+ h_,i_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL FreeResource $THEN BEGIN }
+ FUNCTION FreeResource (
+ h_ : HANDLE
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL LockResource $THEN BEGIN }
+ FUNCTION LockResource (
+ h_ : HANDLE
+ ) : LPSTR;
+{ $END }
+
+
+{ $IFDECL SetResourceHandler $THEN BEGIN }
+ FUNCTION SetResourceHandler (
+ h_ : HANDLE;
+ l_ : LPSTR;
+ f_ : FARPROC
+ ) : FARPROC;
+{ $END }
+
+{ $IFDECL AllocResource $THEN BEGIN }
+ FUNCTION AllocResource (
+ h_,i_ : HANDLE;
+ d_ : DWORD
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL SizeofResource $THEN BEGIN }
+ FUNCTION SizeofResource (
+ h_,i_ : HANDLE
+ ) : WORD;
+{ $END }
+
+{ $IFDECL AccessResource $THEN BEGIN }
+ FUNCTION AccessResource (
+ h_,i_ : HANDLE
+ ) : int;
+{ $END }
+
+{ $IFDECL MAKEINTRESOURCE $THEN BEGIN }
+ FUNCTION MAKEINTRESOURCE (
+ i_ : int
+ ) : LPSTR;
+{ $END }
+
+(* Predefined resource types *)
+CONST
+ RT_CURSOR = RETYPE( LPSTR, BYLONG(0, 1) );
+ RT_BITMAP = RETYPE( LPSTR, BYLONG(0, 2) );
+ RT_ICON = RETYPE( LPSTR, BYLONG(0, 3) );
+ RT_MENU = RETYPE( LPSTR, BYLONG(0, 4) );
+ RT_DIALOG = RETYPE( LPSTR, BYLONG(0, 5) );
+ RT_STRING = RETYPE( LPSTR, BYLONG(0, 6) );
+ RT_FONTDIR = RETYPE( LPSTR, BYLONG(0, 7) );
+ RT_FONT = RETYPE( LPSTR, BYLONG(0, 8) );
+ RT_ACCELERATOR = RETYPE( LPSTR, BYLONG(0, 9) );
+ RT_RCDATA = RETYPE( LPSTR, BYLONG(0, 10) );
+
+(* Interface to the task scheduler *)
+
+
+{ $IFDECL Yield $THEN BEGIN }
+ FUNCTION Yield : BOOL;
+{ $END }
+
+{ $IFDECL GetCurrentTask $THEN BEGIN }
+ FUNCTION GetCurrentTask : HANDLE;
+{ $END }
+
+{ $IFDECL SetPriority $THEN BEGIN }
+ FUNCTION SetPriority (
+ h_ : HANDLE;
+ i_ : int
+ ) : int;
+{ $END }
+
+(* Interface to the atom manager *)
+
+
+TYPE
+ ATOM = WORD;
+
+
+{ $IFDECL InitAtomTable $THEN BEGIN }
+ FUNCTION InitAtomTable (
+ i_ : int
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL AddAtom $THEN BEGIN }
+ FUNCTION AddAtom (
+ l_ : LPSTR
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL DeleteAtom $THEN BEGIN }
+ FUNCTION DeleteAtom (
+ a_ : ATOM
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL FindAtom $THEN BEGIN }
+ FUNCTION FindAtom (
+ l_ : LPSTR
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL GetAtomName $THEN BEGIN }
+ FUNCTION GetAtomName (
+ a_ : ATOM;
+ l_ : LPSTR;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GlobalAddAtom $THEN BEGIN }
+ FUNCTION GlobalAddAtom (
+ l_ : LPSTR
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL GlobalDeleteAtom $THEN BEGIN }
+ FUNCTION GlobalDeleteAtom (
+ a_ : ATOM
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL GlobalFindAtom $THEN BEGIN }
+ FUNCTION GlobalFindAtom (
+ l_ : LPSTR
+ ) : ATOM;
+{ $END }
+
+{ $IFDECL GlobalGetAtomName $THEN BEGIN }
+ FUNCTION GlobalGetAtomName (
+ a_ : ATOM;
+ l_ : LPSTR;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetAtomHandle $THEN BEGIN }
+ FUNCTION GetAtomHandle (
+ a_ : ATOM
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL MAKEINTATOM $THEN BEGIN }
+ FUNCTION MAKEINTATOM (
+ i_ : int
+ ) : LPSTR;
+{ $END }
+
+(* Interface to the user profile *)
+
+{ $IFDECL GetProfileInt $THEN BEGIN }
+ FUNCTION GetProfileInt (
+ l_,m_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetProfileString $THEN BEGIN }
+ FUNCTION GetProfileString (
+ l_,m_,n_,o_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL WriteProfileString $THEN BEGIN }
+ FUNCTION WriteProfileString (
+ l_,m_,n_ : LPSTR
+ ) : BOOL;
+{ $END }
+
+(* Interface to FatalExit procedure *)
+
+
+{ $IFDECL FatalExit $THEN BEGIN }
+ PROCEDURE FatalExit (
+ i_ : int
+ );
+{ $END }
+
+(* Interface to Catch and Throw procedures *)
+
+
+TYPE
+ CATCHBUF = ARRAY [0..8] OF int;
+ LPCATCHBUF = ADS OF int;
+
+{ $IFDECL Catch $THEN BEGIN }
+ FUNCTION Catch (
+ l_ : LPCATCHBUF
+ ) : int;
+{ $END }
+
+{ $IFDECL Throw $THEN BEGIN }
+ PROCEDURE Throw (
+ l_ : LPCATCHBUF;
+ i_ : int
+ );
+{ $END }
+
+
+{ $IFDECL CreateMetaFile $THEN BEGIN }
+ FUNCTION CreateMetaFile (
+ l_ : LPSTR
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL CloseMetaFile $THEN BEGIN }
+ FUNCTION CloseMetaFile (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL GetMetaFileBits $THEN BEGIN }
+ FUNCTION GetMetaFileBits (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+{ $IFDECL SetMetaFileBits $THEN BEGIN }
+ FUNCTION SetMetaFileBits (
+ h_ : HANDLE
+ ) : HANDLE;
+{ $END }
+
+
+{ $IFDECL GetCurrentTime $THEN BEGIN }
+ FUNCTION GetCurrentTime : DWORD;
+{ $END }
+
+{ $IFDECL GetTickCount $THEN BEGIN }
+ FUNCTION GetTickCount : DWORD;
+{ $END }
+
+{ $IFDECL GetTimerResolution $THEN BEGIN }
+ FUNCTION GetTimerResolution : DWORD;
+{ $END }
+
+{ $IFDECL IsChild $THEN BEGIN }
+ FUNCTION IsChild (
+ h_,i_ : HWND
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL GetWindowWord $THEN BEGIN }
+ FUNCTION GetWindowWord (
+ h_ : HWND;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SetWindowWord $THEN BEGIN }
+ FUNCTION SetWindowWord (
+ h_ : HWND;
+ i_ : int;
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetWindowLong $THEN BEGIN }
+ FUNCTION GetWindowLong (
+ h_ : HWND;
+ i_ : int
+ ) : LONG;
+{ $END }
+
+{ $IFDECL SetWindowLong $THEN BEGIN }
+ FUNCTION SetWindowLong (
+ h_ : HWND;
+ i_ : int;
+ l_ : LONG
+ ) : LONG;
+{ $END }
+
+{ $IFDECL GetClassWord $THEN BEGIN }
+ FUNCTION GetClassWord (
+ h_ : HWND;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SetClassWord $THEN BEGIN }
+ FUNCTION SetClassWord (
+ h_ : HWND;
+ i_ : int;
+ w_ : WORD
+ ) : WORD;
+{ $END }
+
+{ $IFDECL GetClassLong $THEN BEGIN }
+ FUNCTION GetClassLong (
+ h_ : HWND;
+ i_ : int
+ ) : LONG;
+{ $END }
+
+{ $IFDECL SetClassLong $THEN BEGIN }
+ FUNCTION SetClassLong (
+ h_ : HWND;
+ i_ : int;
+ l_ : LONG
+ ) : LONG;
+{ $END }
+
+
+{ $IFDECL GetParent $THEN BEGIN }
+ FUNCTION GetParent (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL SetParent $THEN BEGIN }
+ FUNCTION SetParent (
+ h_,w_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL EnumChildWindows $THEN BEGIN }
+ FUNCTION EnumChildWindows (
+ h_ : HWND;
+ f_ : FARPROC;
+ l_ : LONG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL FindWindow $THEN BEGIN }
+ FUNCTION FindWindow (
+ l_,m_ : LPSTR
+ ) : HWND;
+{ $END }
+
+{ $IFDECL EnumWindows $THEN BEGIN }
+ FUNCTION EnumWindows (
+ f_ : FARPROC;
+ l_ : LONG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL EnumTaskWindows $THEN BEGIN }
+ FUNCTION EnumTaskWindows (
+ h_ : HANDLE;
+ f_ : FARPROC;
+ l_ : LONG
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL GetClassName $THEN BEGIN }
+ FUNCTION GetClassName (
+ h_ : HWND;
+ l_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetTopWindow $THEN BEGIN }
+ FUNCTION GetTopWindow (
+ h_ : HWND
+ ) : HWND;
+{ $END }
+
+{ $IFDECL GetNextWindow $THEN BEGIN }
+ FUNCTION GetNextWindow (
+ h_ : HWND;
+ W_ : WORD
+ ) : HWND;
+{ $END }
+
+{ $IFDECL GetWindowTask $THEN BEGIN }
+ FUNCTION GetWindowTask (
+ h_ : HWND
+ ) : HANDLE;
+{ $END }
+
+(* GetWindow() and constants *)
+{ $IFDECL GetWindow $THEN BEGIN }
+ FUNCTION GetWindow (
+ h_ : HWND;
+ w_ : WORD
+ ) : HWND;
+{ $END }
+
+
+{ $IFDECL SetWindowsHook $THEN BEGIN }
+ FUNCTION SetWindowsHook (
+ i_ : int;
+ f_ : FARPROC
+ ) : FARPROC;
+{ $END }
+
+{ $IFDECL UnhookWindowsHook $THEN BEGIN }
+ FUNCTION UnhookWindowsHook (
+ i_ : int;
+ f_ : FARPROC
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL DefHookProc $THEN BEGIN }
+ FUNCTION DefHookProc (
+ i_ : int;
+ w_ : WORD;
+ d_ : DWORD;
+ f_ : ADS OF FARPROC
+ ) : DWORD;
+{ $END }
+
+(* Key conversion window *)
+
+{ $IFDECL CreateConvertWindow $THEN BEGIN }
+ FUNCTION CreateConvertWindow (
+ l_ : LPSTR;
+ h_ : HANDLE;
+ m_ : LPSTR
+ ) : HWND;
+{ $END }
+
+{ $IFDECL ShowConvertWindow $THEN BEGIN }
+ PROCEDURE ShowConvertWindow (
+ h_ : HWND;
+ b_ : BOOL
+ );
+{ $END }
+
+{ $IFDECL SetConvertWindowHeight $THEN BEGIN }
+ PROCEDURE SetConvertWindowHeight (
+ i_ : int
+ );
+{ $END }
+
+{ $IFDECL IsTwoByteCharPrefix $THEN BEGIN }
+ FUNCTION IsTwoByteCharPrefix (
+ i_ : INTEGER1
+ ) : BOOL;
+{ $END }
+
+CONST
+ GW_HWNDFIRST = 0;
+ GW_HWNDLAST = 1;
+ GW_HWNDNEXT = 2;
+ GW_HWNDPREV = 3;
+ GW_OWNER = 4;
+ GW_CHILD = 5;
+
+(* Menu flags for Add/Check/EnableMenuItem *)
+
+ MF_CHANGE = #0080;
+ MF_INSERT = #0000;
+ MF_APPEND = #0100;
+ MF_DELETE = #0200;
+ MF_BYPOSITION = #0400;
+ MF_SEPARATOR = #0800;
+ MF_REMOVE = #1000;
+ MF_BYCOMMAND = #0000;
+ MF_GRAYED = #0001;
+ MF_DISABLED = #0002;
+ MF_ENABLED = #0000;
+ MF_CHECKED = #0008;
+ MF_UNCHECKED = #0000;
+ MF_BITMAP = #0004;
+ MF_STRING = #0000;
+ MF_POPUP = #0010;
+ MF_MENUBARBREAK = #0020;
+ MF_MENUBREAK = #0040;
+ MF_HILITE = #0080;
+ MF_UNHILITE = #0000;
+ MF_HELP = #4000;
+ MF_SYSMENU = #2000;
+ MF_MOUSESELECT = #8000;
+
+
+(* System Menu Command Values *)
+ SC_SIZE = #f000;
+ SC_MOVE = #f010;
+ SC_MINIMIZE = #f020;
+ SC_MAXIMIZE = #f030;
+ SC_NEXTWINDOW = #f040;
+ SC_PREVWINDOW = #f050;
+ SC_CLOSE = #f060;
+ SC_VSCROLL = #f070;
+ SC_HSCROLL = #f080;
+ SC_MOUSEMENU = #f090;
+ SC_KEYMENU = #f100;
+ SC_ARRANGE = #F110;
+ SC_RESTORE = #F120;
+ SC_ICON = SC_MINIMIZE;
+ SC_ZOOM = SC_MAXIMIZE;
+
+(* Resource loading routines *)
+
+
+{ $IFDECL LoadBitmap $THEN BEGIN }
+ FUNCTION LoadBitmap (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HBITMAP;
+{ $END }
+
+
+{ $IFDECL LoadCursor $THEN BEGIN }
+ FUNCTION LoadCursor (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HCURSOR;
+{ $END }
+
+(* Standard cursor IDs *)
+CONST
+ IDC_ARROW = RETYPE( LPSTR, BYLONG(0,32512) );
+ IDC_IBEAM = RETYPE( LPSTR, BYLONG(0,32513) );
+ IDC_WAIT = RETYPE( LPSTR, BYLONG(0,32514) );
+ IDC_CROSS = RETYPE( LPSTR, BYLONG(0,32515) );
+ IDC_UPARROW = RETYPE( LPSTR, BYLONG(0,32516) );
+ IDC_SIZE = RETYPE( LPSTR, BYLONG(0,32640) );
+ IDC_ICON = RETYPE( LPSTR, BYLONG(0,32641) );
+ IDC_SIZENWSE = RETYPE( LPSTR, BYLONG(0,32642) );
+ IDC_SIZENESW = RETYPE( LPSTR, BYLONG(0,32643) );
+ IDC_SIZEWE = RETYPE( LPSTR, BYLONG(0,32644) );
+ IDC_SIZENS = RETYPE( LPSTR, BYLONG(0,32645) );
+
+
+
+{ $IFDECL LoadIcon $THEN BEGIN }
+ FUNCTION LoadIcon (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HICON;
+{ $END }
+
+(* Standard icon IDs *)
+CONST
+ IDI_APPLICATION = RETYPE( LPSTR, BYLONG(0,32512) );
+ IDI_HAND = RETYPE( LPSTR, BYLONG(0,32513) );
+ IDI_QUESTION = RETYPE( LPSTR, BYLONG(0,32514) );
+ IDI_EXCLAMATION = RETYPE( LPSTR, BYLONG(0,32515) );
+ IDI_ASTERISK = RETYPE( LPSTR, BYLONG(0,32516) );
+
+
+
+{ $IFDECL LoadMenu $THEN BEGIN }
+ FUNCTION LoadMenu (
+ h_ : HANDLE;
+ l_ : LPSTR
+ ) : HMENU;
+{ $END }
+
+{ $IFDECL LoadMenuIndirect $THEN BEGIN }
+ FUNCTION LoadMenuIndirect (
+ l_ : LPSTR
+ ) : HMENU;
+{ $END }
+
+{ $IFDECL LoadString $THEN BEGIN }
+ FUNCTION LoadString (
+ h_ : HANDLE;
+ w_ : WORD;
+ l_ : LPSTR;
+ i_ : int
+ ) : int;
+{ $END }
+
+
+{ $IFDECL AddFontResource $THEN BEGIN }
+ FUNCTION AddFontResource (
+ l_ : LPSTR
+ ) : short;
+{ $END }
+
+{ $IFDECL RemoveFontResource $THEN BEGIN }
+ FUNCTION RemoveFontResource (
+ l_ : LPSTR
+ ) : BOOL;
+{ $END }
+
+
+CONST
+ CP_HWND = 0;
+ CP_OPEN = 1;
+ CP_DIRECT = 2;
+
+(* VK from the keyboard driver *)
+ VK_KANA = #15;
+ VK_ROMAJI = #16;
+ VK_ZENKAKU = #17;
+ VK_HIRAGANA = #18;
+ VK_KANJI = #19;
+
+(* VK to send to Applications *)
+ VK_CONVERT = #1C;
+ VK_NONCONVERT = #1D;
+ VK_ACCEPT = #1E;
+ VK_MODECHANGE = #1F;
+
+
+(* Conversion function numbers *)
+ KNJ_START = #01;
+ KNJ_END = #02;
+ KNJ_QUERY = #03;
+
+ KNJ_LEARN_MODE = #10;
+ KNJ_GETMODE = #11;
+ KNJ_SETMODE = #12;
+
+ KNJ_CODECONVERT = #20;
+ KNJ_CONVERT = #21;
+ KNJ_NEXT = #22;
+ KNJ_PREVIOUS = #23;
+ KNJ_ACCEPT = #24;
+
+ KNJ_LEARN = #30;
+ KNJ_REGISTER = #31;
+ KNJ_REMOVE = #32;
+ KNJ_CHANGE_UDIC = #33;
+
+(* note: DEFAULT = 0
+ JIS1 = 1
+ JIS2 = 2
+ SJIS2 = 3
+ JIS1KATAKANA = 4
+ SJIS2HIRAGANA = 5
+ SJIS2KATAKANA = 6
+ OEM = F
+*)
+
+ KNJ_JIS1toJIS1KATAKANA = #14;
+ KNJ_JIS1toSJIS2 = #13;
+ KNJ_JIS1toSJIS2HIRAGANA = #15;
+ KNJ_JIS1toSJIS2KATAKANA = #16;
+ KNJ_JIS1toDEFAULT = #10;
+ KNJ_JIS1toSJIS2OEM = #1F;
+ KNJ_JIS2toSJIS2 = #23;
+ KNJ_SJIS2toJIS2 = #32;
+
+(* see KNJ_GETMODE for definition *)
+ KNJ_MD_ALPHA = #01;
+ KNJ_MD_HIRAGANA = #02;
+ KNJ_MD_HALF = #04;
+ KNJ_MD_JIS = #08;
+ KNJ_MD_SPECIAL = #10;
+
+(* conversion modes, low word of lParam when VK_CONVERT is sent to the app *)
+ KNJ_CVT_NEXT = #01;
+ KNJ_CVT_PREV = #02;
+ KNJ_CVT_KATAKANA = #03;
+ KNJ_CVT_HIRAGANA = #04;
+ KNJ_CVT_JIS1 = #05;
+ KNJ_CVT_SJIS2 = #06;
+ KNJ_CVT_DEFAULT = #07;
+ KNJ_CVT_TYPED = #08;
+
+(* WM_YOMICHAR = #0108;
+ WM_CONVERTREQUEST = #010A;
+ WM_CONVERTRESULT = #010B; Previously defined constants.
+*)
+
+
+TYPE
+ KANJISTRUCT = RECORD
+ fnc : short;
+ wParam : short;
+ lpSource : LPSTR;
+ lpdest : LPSTR;
+ wCount : short;
+ lpReserved1 : LPSTR;
+ lpReserved2 : LPSTR;
+ END;
+
+ LPKANJISTRUCT = ADS OF KANJISTRUCT;
+
+
+{ $IFDECL MoveConvertWindow $THEN BEGIN }
+ PROCEDURE MoveConvertWindow (
+ s_,t_ : short
+ );
+{ $END }
+
+{ $IFDECL ConvertRequest $THEN BEGIN }
+ FUNCTION ConvertRequest (
+ h_ : HWND;
+ l_ : LPKANJISTRUCT
+ ) : short;
+{ $END }
+
+{ $IFDECL SetConvertParams $THEN BEGIN }
+ FUNCTION SetConvertParams (
+ s_,t_ : short
+ ) : BOOL;
+{ $END }
+
+{ $IFDECL SetConvertHook $THEN BEGIN }
+ PROCEDURE SetConvertHook (
+ b_ : BOOL
+ );
+{ $END }
+
+(* Conventional dialog box and message box command IDs *)
+
+CONST
+ IDOK = 1;
+ IDCANCEL = 2;
+ IDABORT = 3;
+ IDRETRY = 4;
+ IDIGNORE = 5;
+ IDYES = 6;
+ IDNO = 7;
+
+
+(* Control manager structures & definitions *)
+(* Edit control class stuff *)
+
+(* styles *)
+ ES_LEFT = BYLONG(0,0);
+ ES_CENTER = BYLONG(0,1);
+ ES_RIGHT = BYLONG(0,2);
+ ES_MULTILINE = BYLONG(0,4);
+ ES_AUTOVSCROLL = BYLONG(0,64);
+ ES_AUTOHSCROLL = BYLONG(0,128);
+ ES_NOHIDESEL = BYLONG(0,256);
+
+(* notification codes *)
+ EN_SETFOCUS_ = #0100;
+ EN_KILLFOCUS_ = #0200;
+ EN_CHANGE = #0300;
+ EN_UPDATE = #0400;
+ EN_ERRSPACE = #0500;
+ EN_HSCROLL = #0601;
+ EN_VSCROLL = #0602;
+
+(* control messages: *)
+ EM_GETSEL = WM_USER+0;
+ EM_SETSEL = WM_USER+1;
+ EM_GETRECT = WM_USER+2;
+ EM_SETRECT = WM_USER+3;
+ EM_SETRECTNP = WM_USER+4;
+ EM_SCROLL = WM_USER+5;
+ EM_LINESCROLL = WM_USER+6;
+ EM_GETMODIFY = WM_USER+8;
+ EM_SETMODIFY = WM_USER+9;
+ EM_GETLINECOUNT = WM_USER+10;
+ EM_LINEINDEX = WM_USER+11;
+ EM_SETHANDLE = WM_USER+12;
+ EM_GETHANDLE = WM_USER+13;
+ EM_GETTHUMB = WM_USER+14;
+ EM_LINELENGTH = WM_USER+17;
+ EM_REPLACESEL = WM_USER+18;
+ EM_SETFONT = WM_USER+19;
+ EM_GETLINE = WM_USER+20;
+ EM_LIMITTEXT = WM_USER+21;
+ EM_CANUNDO = WM_USER+22;
+ EM_UNDO = WM_USER+23;
+ EM_FMTLINES = WM_USER+24;
+ EM_LINEFROMCHAR = WM_USER+25;
+ EM_SETWORDBREAK = WM_USER+26;
+
+(* button control styles *)
+ BS_PUSHBUTTON = BYLONG(0,0);
+ BS_DEFPUSHBUTTON = BYLONG(0,1);
+ BS_CHECKBOX = BYLONG(0,2);
+ BS_AUTOCHECKBOX = BYLONG(0,3);
+ BS_RADIOBUTTON = BYLONG(0,4);
+ BS_3STATE = BYLONG(0,5);
+ BS_AUTO3STATE = BYLONG(0,6);
+ BS_GROUPBOX = BYLONG(0,7);
+ BS_USERBUTTON = BYLONG(0,8);
+ BS_AUTORADIOBUTTON = BYLONG(0,9);
+ BS_PUSHBOX = BYLONG(0,10);
+ BS_LEFTTEXT = BYLONG(0,20);
+
+(* user button notification codes *)
+ BN_CLICKED = 0;
+ BN_PAINT = 1;
+ BN_HILITE = 2;
+ BN_UNHILITE = 3;
+ BN_DISABLE = 4;
+ BN_DOUBLECLICKED = 5;
+
+(* control messages *)
+ BM_GETCHECK = WM_USER+0;
+ BM_SETCHECK = WM_USER+1;
+ BM_GETSTATE = WM_USER+2;
+ BM_SETSTATE = WM_USER+3;
+ BM_SETSTYLE = WM_USER+4;
+
+(* Static control constants *)
+
+ SS_LEFT = BYLONG(0,0);
+ SS_CENTER = BYLONG(0,1);
+ SS_RIGHT = BYLONG(0,2);
+ SS_ICON = BYLONG(0,3);
+ SS_BLACKRECT = BYLONG(0,4);
+ SS_GRAYRECT = BYLONG(0,5);
+ SS_WHITERECT = BYLONG(0,6);
+ SS_BLACKFRAME = BYLONG(0,7);
+ SS_GRAYFRAME = BYLONG(0,8);
+ SS_WHITEFRAME = BYLONG(0,9);
+ SS_USERITEM = BYLONG(0,10);
+ SS_SIMPLE = BYLONG(0,11);
+ SS_NOPREFIX = BYLONG(0,128);
+ (* 0x80 - don't do "&" character translation *)
+
+(* Dialog manager routines *)
+
+
+{ $IFDECL IsDialogMessage $THEN BEGIN }
+ FUNCTION IsDialogMessage (
+ h_ : HWND;
+ l_ : LPMSG
+ ) : BOOL;
+{ $END }
+
+
+{ $IFDECL MapDialogRect $THEN BEGIN }
+ PROCEDURE MapDialogRect (
+ h_ : HWND;
+ l_ : LPRECT
+ );
+{ $END }
+
+
+{ $IFDECL DlgDirList $THEN BEGIN }
+ FUNCTION DlgDirList (
+ h_ : HWND;
+ l_ : LPSTR;
+ i_,j_ : int;
+ w_ : WORD
+ ) : int;
+{ $END }
+
+{ $IFDECL DlgDirSelect $THEN BEGIN }
+ FUNCTION DlgDirSelect (
+ h_ : HWND;
+ l_ : LPSTR;
+ i_ : int
+ ) : BOOL;
+{ $END }
+
+(* Dialog style bits *)
+
+CONST
+ DS_ABSALIGN = #000000001;
+ DS_SYSMODAL = #000000002;
+ DS_LOCALEDIT = #000000020; (* Edit items get Local storage. *)
+
+ DM_GETDEFID = WM_USER+0;
+ DM_SETDEFID = WM_USER+1;
+ DC_HASDEFID = #534B;
+
+(* Dialog codes (returned by WM_GETDLGCODE message) *)
+
+ DLGC_WANTARROWS = #0001; (* control wants arrow keys *)
+ DLGC_WANTTAB = #0002; (* control wants tab keys *)
+ DLGC_WANTALLKEYS = #0004; (* control wants all keys *)
+ DLGC_HASSETSEL = #0008; (* understands EM_SETSEL message *)
+ DLGC_WANTMESSAGE = #0004; (* pass message to control *)
+ DLGC_DEFPUSHBUTTON = #0010; (* Default pushbutton *)
+ DLGC_UNDEFPUSHBUTTON = #0020; (* Non-default pushbutton *)
+ DLGC_RADIOBUTTON = #0040; (* radio button *)
+ DLGC_WANTCHARS = #0080; (* Want WM_CHAR messages *)
+ DLGC_STATIC = #0100; (* Static item: don't include *)
+ DLGC_BUTTON = #2000; (* Button item: can be checked *)
+
+ LB_CTLCODE = BYLONG(0,0);
+
+(* Listbox control return values *)
+ LB_OKAY = 0;
+ LB_ERR = -1;
+ LB_ERRSPACE = -2;
+
+(* listbox notification codes *)
+ LBN_ERRSPACE = -2;
+ LBN_SELCHANGE = 1;
+ LBN_DBLCLK = 2;
+
+(* listbox messages *)
+ LB_ADDSTRING = 1+WM_USER;
+ LB_INSERTSTRING = 2+WM_USER;
+ LB_DELETESTRING = 3+WM_USER;
+ LB_REPLACESTRING = 4+WM_USER;
+ LB_RESETCONTENT = 5+WM_USER;
+ LB_SETSEL = 6+WM_USER;
+ LB_SETCURSEL = 7+WM_USER;
+ LB_GETSEL = 8+WM_USER;
+ LB_GETCURSEL = 9+WM_USER;
+ LB_GETTEXT = 10+WM_USER;
+ LB_GETTEXTLEN = 11+WM_USER;
+ LB_GETCOUNT = 12+WM_USER;
+ LB_SELECTSTRING = 13+WM_USER;
+ LB_DIR = 14+WM_USER;
+ LB_GETTOPINDEX = 15+WM_USER;
+ LB_MSGMAX = 16+WM_USER;
+
+(* listbox style bits *)
+ LBS_NOTIFY = #00000001;
+ LBS_SORT = #00000002;
+ LBS_NOREDRAW = #00000004;
+ LBS_MULTIPLESEL = #00000008;
+ LBS_STANDARD = #00A00003; (*LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER *)
+
+
+(* scroll bar styles *)
+ SBS_HORZ = #00000000;
+ SBS_VERT = #00000001;
+ SBS_TOPALIGN = #00000002;
+ SBS_LEFTALIGN = #00000002;
+ SBS_BOTTOMALIGN = #00000004;
+ SBS_RIGHTALIGN = #00000004;
+ SBS_SIZEBOXTOPLEFTALIGN = #00000002;
+ SBS_SIZEBOXBOTTOMRIGHTALIGN = #00000004;
+ SBS_SIZEBOX = #00000008;
+
+
+{ $IFDECL OpenSound $THEN BEGIN }
+ FUNCTION OpenSound : int;
+{ $END }
+
+{ $IFDECL CloseSound $THEN BEGIN }
+ FUNCTION CloseSound : int;
+{ $END }
+
+{ $IFDECL SetVoiceQueueSize $THEN BEGIN }
+ FUNCTION SetVoiceQueueSize (
+ i_,j_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetVoiceNote $THEN BEGIN }
+ FUNCTION SetVoiceNote (
+ i_,j_,k_,l_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetVoiceAccent $THEN BEGIN }
+ FUNCTION SetVoiceAccent (
+ i_,j_,k_,l_,m_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetVoiceEnvelope $THEN BEGIN }
+ FUNCTION SetVoiceEnvelope (
+ i_,j_,k_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetSoundNoise $THEN BEGIN }
+ FUNCTION SetSoundNoise (
+ i_,j_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SetVoiceSound $THEN BEGIN }
+ FUNCTION SetVoiceSound (
+ i_,j_,k_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL StartSound $THEN BEGIN }
+ FUNCTION StartSound : int;
+{ $END }
+
+{ $IFDECL StopSound $THEN BEGIN }
+ FUNCTION StopSound : int;
+{ $END }
+
+{ $IFDECL WaitSoundState $THEN BEGIN }
+ FUNCTION WaitSoundState (
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL SyncAllVoices $THEN BEGIN }
+ FUNCTION SyncAllVoices : int;
+{ $END }
+
+{ $IFDECL CountVoiceNotes $THEN BEGIN }
+ FUNCTION CountVoiceNotes (
+ i_ : int
+ ) : int;
+{ $END }
+
+{ $IFDECL GetThresholdEvent $THEN BEGIN }
+ FUNCTION GetThresholdEvent : LPINT;
+{ $END }
+
+{ $IFDECL GetThresholdStatus $THEN BEGIN }
+ FUNCTION GetThresholdStatus : int;
+{ $END }
+
+{ $IFDECL SetVoiceThreshold $THEN BEGIN }
+ FUNCTION SetVoiceThreshold (
+ i_,j_ : int
+ ) : int;
+{ $END }
+
+(* constants used to specify return condition for WaitSoundState *)
+
+
+CONST
+ QUEUEEMPTY = 0;
+ THRESHOLD = 1;
+ ALLTHRESHOLD = 2;
+
+(* constants used to specify accent mode *)
+
+ S_NORMAL = 0;
+ S_LEGATO = 1;
+ S_STACCATO = 2;
+
+(* constants used to specify source in SetSoundNoise *)
+ S_PERIOD512 = 0 (* freq = N/512 high pitch, less coarse hiss *);
+ S_PERIOD1024 = 1 (* freq = N/1024 *);
+ S_PERIOD2048 = 2 (* freq = N/2048 low pitch, more coarse hiss *);
+ S_PERIODVOICE = 3 (* source is frequency from voice channel (3) *);
+
+ S_WHITE512 = 4 (* freq = N/512 high pitch, less coarse hiss *);
+ S_WHITE1024 = 5 (* freq = N/1024 *);
+ S_WHITE2048 = 6 (* freq = N/2048 low pitch, more coarse hiss *);
+ S_WHITEVOICE = 7 (* source is frequency from voice channel (3) *);
+
+ S_SERDVNA = -1 (* device not available *);
+ S_SEROFM = -2 (* out of memory *);
+ S_SERMACT = -3 (* music active *);
+ S_SERQFUL = -4 (* queue full *);
+ S_SERBDNT = -5 (* invalid note *);
+ S_SERDLN = -6 (* invalid note length *);
+ S_SERDCC = -7 (* invalid note count *);
+ S_SERDTP = -8 (* invalid tempo *);
+ S_SERDVL = -9 (* invalid volume *);
+ S_SERDMD = -10 (* invalid mode *);
+ S_SERDSH = -11 (* invalid shape *);
+ S_SERDPT = -12 (* invalid pitch *);
+ S_SERDFQ = -13 (* invalid frequency *);
+ S_SERDDR = -14 (* invalid duration *);
+ S_SERDSR = -15 (* invalid source *);
+ S_SERDST = -16 (* invalid state *);
+
+
+
+(*************************************************************************
+**
+** dcb field definitions.
+**
+*************************************************************************)
+
+ NOPARITY = 0;
+ ODDPARITY = 1;
+ EVENPARITY = 2;
+ MARKPARITY = 3;
+ SPACEPARITY = 4;
+
+ ONESTOPBIT = 0;
+ ONE5STOPBITS = 1;
+ TWOSTOPBITS = 2;
+
+ IGNORE = 0 (* Ignore signal *);
+ INFINITE = #ffff (* Infinite timeout *);
+
+
+
+(*************************************************************************
+**
+** Comm Device Driver Error Bits.
+**
+*************************************************************************)
+
+ CE_RXOVER = #0001 (* Receive Queue overflow *);
+ CE_OVERRUN = #0002 (* Receive Overrun Error *);
+ CE_RXPARITY = #0004 (* Receive Parity Error *);
+ CE_FRAME = #0008 (* Receive Framing error *);
+ CE_BREAK = #0010 (* Break Detected *);
+ CE_CTSTO = #0020 (* CTS Timeout *);
+ CE_DSRTO = #0040 (* DSR Timeout *);
+ CE_RLSDTO = #0080 (* RLSD Timeout *);
+ CE_TXFULL = #0100 (* TX QUEUE IS FULL *);
+ CE_PTO = #0200 (* LPTx Timeout *);
+ CE_IOE = #0400 (* LPTx I/O Error *);
+ CE_DNS = #0800 (* LPTx Device not selected *);
+ CE_OOP = #1000 (* LPTx Out-Of-Paper *);
+ CE_MODE = #8000 (* Requested mode unsupported *);
+
+
+(*************************************************************************
+**
+** Initialization Error Codes
+**
+*************************************************************************)
+
+ IE_BADID = -1 (* Invalid or unsupported id *);
+ IE_OPEN = -2 (* Device Already Open *);
+ IE_NOPEN = -3 (* Device Not Open *);
+ IE_MEMORY = -4 (* Unable to allocate queues *);
+ IE_DEFAULT = -5 (* Error in default parameters *);
+ IE_HARDWARE = -10 (* Hardware Not Present *);
+ IE_BYTESIZE = -11 (* Illegal Byte Size *);
+ IE_BAUDRATE = -12 (* Unsupported BaudRate *);
+
+
+(*************************************************************************
+**
+** Event Definitions
+**
+*************************************************************************)
+
+ EV_RXCHAR = #0001 (* Any Character received *);
+ EV_RXFLAG = #0002 (* Received certain INTEGER1acter *);
+ EV_TXEMPTY = #0004 (* Transmitt Queue Empty *);
+ EV_CTS = #0008 (* CTS changed state *);
+ EV_DSR = #0010 (* DSR changed state *);
+ EV_RLSD = #0020 (* RLSD changed state *);
+ EV_BREAK = #0040 (* BREAK received *);
+ EV_ERR = #0080 (* Line status error occurred *);
+ EV_RING = #0100 (* Ring signal detected *);
+ EV_PERR = #0200 (* Printer error occured *);
+
+
+(*************************************************************************
+**
+** Escape Functions
+**
+*************************************************************************)
+
+ SETXOFF = 1 (* Simulate XOFF received *);
+ SETXON = 2 (* Simulate XON received *);
+ SETRTS = 3 (* Set RTS high *);
+ CLRRTS = 4 (* Set RTS low *);
+ SETDTR = 5 (* Set DTR high *);
+ CLRDTR = 6 (* Set DTR low *);
+ RESETDEV = 7 (* Reset device if possible *);
+
+
+(*************************************************************************
+**
+** Device Descriptor Block Definition
+**
+*************************************************************************)
+
+ LPTx = #80 (* Set if ID is for LPT device *);
+
+ (* Bitfield locators for 'bitField1' in DCB record type *)
+ fBinary = 1;
+ fRtsDisable = 2;
+ fParity = 4;
+ fOutxCtsFlow = 8;
+ fOutxDsrFlow = 16;
+ fDtrDisable = 128;
+
+ (* Bitfield locators for 'bitField2' in DCB record type *)
+ fOutX = 1;
+ fInX = 2;
+ fPeChar = 4;
+ fNull = 8;
+ fChEvt = 16;
+ fDtrflow = 32;
+ fRtsflow = 64;
+
+TYPE
+ DCB = RECORD
+ Id : BYTE; (* Internal Device ID *)
+ BaudRate : WORD; (* Baudrate at which runing *)
+ ByteSize : BYTE; (* Number of bits/byte, 4-8 *)
+ Parity : BYTE; (* 0-4=None,Odd,Even,Mark,Space *)
+ StopBits : BYTE; (* 0,1,2 = 1, 1.5, 2 *)
+ RlsTimeout : WORD; (* Timeout for RLSD to be set *)
+ CtsTimeout : WORD; (* Timeout for CTS to be set *)
+ DsrTimeout : WORD; (* Timeout for DSR to be set *)
+
+ bitField1 : BYTE;
+ (* Packed bits. Access with constants defined above.
+ * BYTE fBinary: 1; - Binary Mode (skip EOF check)
+ * BYTE fRtsDisable:1; - Don't assert RTS at init time
+ * BYTE fParity: 1; - Enable parity checking
+ * BYTE fOutxCtsFlow:1; - CTS handshaking on output
+ * BYTE fOutxDsrFlow:1; - DSR handshaking on output
+ * BYTE fDummy: 2; - Reserved
+ * BYTE fDtrDisable:1; - Don't assert DTR at init time
+ *)
+ bitField2 : BYTE;
+ (* Packed bits. Access with constants defined above.
+ * BYTE fOutX: 1; - Enable output X-ON/X-OFF
+ * BYTE fInX: 1; - Enable input X-ON/X-OFF
+ * BYTE fPeChar: 1; - Enable Parity Err Replacement
+ * BYTE fNull: 1; - Enable Null stripping
+ * BYTE fChEvt: 1; - Enable Rx INTEGER1acter event.
+ * BYTE fDtrflow: 1; - DTR handshake on input
+ * BYTE fRtsflow: 1; - RTS handshake on input
+ * BYTE fDummy2: 1; }
+ *)
+ XonChar : INTEGER1; (* Tx and Rx X-ON INTEGER1acter *)
+ XoffChar : INTEGER1; (* Tx and Rx X-OFF INTEGER1acter *)
+ XonLim : WORD; (* Transmit X-ON threshold *)
+ XoffLim : WORD; (* Transmit X-OFF threshold *)
+ PeChar : INTEGER1; (* Parity error replacement INTEGER1*)
+ EofChar : INTEGER1; (* End of Input INTEGER1acter *)
+ EvtChar : INTEGER1; (* Recieved Event INTEGER1acter *)
+ TxDelay : WORD; (* Amount of time between INTEGER1s *)
+ END;
+ LPDCB = ADS OF DCB;
+
+
+(*************************************************************************
+**
+** Status record returned by GetCommError
+**
+*************************************************************************)
+
+CONST
+ fCtsHold = 1;
+ fDsrHold = 2;
+ fRlsdHold = 4;
+ fXoffHold = 8;
+ fXoffSent = 16;
+ fEof = 32;
+ fTxim = 64;
+
+TYPE
+ COMSTAT = RECORD
+ bitField : BYTE;
+ (* Packed bits. Access with constants defined above.
+ * BYTE fCtsHold: 1; - Transmit is on CTS hold
+ * BYTE fDsrHold: 1; - Transmit is on DSR hold
+ * BYTE fRlsdHold: 1; - Transmit is on RLSD hold
+ * BYTE fXoffHold: 1; - Received handshake
+ * BYTE fXoffSent: 1; - Issued handshake
+ * BYTE fEof: 1; - End of file INTEGER1acter found
+ * BYTE fTxim: 1; - Character being transmitted
+ *)
+ cbInQue : WORD; (* count of characters in Rx Que*)
+ cbOutQue : WORD; (* count of characters in Tx Que*)
+ END;
+ LPCOMSTAT = ADS OF COMSTAT;
+
+{ $IFDECL OpenComm $THEN BEGIN }
+ FUNCTION OpenComm (
+ l_ : LPSTR;
+ w_,x_ : WORD
+ ) : short;
+{ $END }
+
+{ $IFDECL SetCommState $THEN BEGIN }
+ FUNCTION SetCommState (
+ d_ : LPDCB
+ ) : short;
+{ $END }
+
+{ $IFDECL GetCommState $THEN BEGIN }
+ FUNCTION GetCommState (
+ s_ : short;
+ d_ : LPDCB
+ ) : short;
+{ $END }
+
+{ $IFDECL ReadComm $THEN BEGIN }
+ FUNCTION ReadComm (
+ s_ : short;
+ l_ : LPSTR;
+ i_ : int
+ ) : short;
+{ $END }
+
+{ $IFDECL UngetCommChar $THEN BEGIN }
+ FUNCTION UngetCommChar (
+ s_ : short;
+ i_ : INTEGER1
+ ) : short;
+{ $END }
+
+{ $IFDECL WriteComm $THEN BEGIN }
+ FUNCTION WriteComm (
+ s_ : short;
+ l_ : LPSTR;
+ i_ : int
+ ) : short;
+{ $END }
+
+{ $IFDECL CloseComm $THEN BEGIN }
+ FUNCTION CloseComm (
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL GetCommError $THEN BEGIN }
+ FUNCTION GetCommError (
+ s_ : short;
+ c_ : LPCOMSTAT
+ ) : short;
+{ $END }
+
+{ $IFDECL BuildCommDCB $THEN BEGIN }
+ FUNCTION BuildCommDCB (
+ l_ : LPSTR;
+ d_ : LPDCB
+ ) : short;
+{ $END }
+
+{ $IFDECL TransmitCommChar $THEN BEGIN }
+ FUNCTION TransmitCommChar (
+ s_ : short;
+ i_ : INTEGER1
+ ) : short;
+{ $END }
+
+{ $IFDECL SetCommEventMask $THEN BEGIN }
+ FUNCTION SetCommEventMask (
+ s_ : short;
+ w_ : WORD
+ ) : LPWORD;
+{ $END }
+
+{ $IFDECL GetCommEventMask $THEN BEGIN }
+ FUNCTION GetCommEventMask (
+ s_ : short;
+ i_ : int
+ ) : WORD;
+{ $END }
+
+{ $IFDECL SetCommBreak $THEN BEGIN }
+ FUNCTION SetCommBreak (
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL ClearCommBreak $THEN BEGIN }
+ FUNCTION ClearCommBreak (
+ s_ : short
+ ) : short;
+{ $END }
+
+{ $IFDECL FlushComm $THEN BEGIN }
+ FUNCTION FlushComm (
+ s_ : short;
+ i_ : int
+ ) : short;
+{ $END }
+
+{ $IFDECL EscapeCommFunction $THEN BEGIN }
+ FUNCTION EscapeCommFunction (
+ s_ : short;
+ i_ : int
+ ) : short;
+{ $END }
+END;
diff --git a/private/mvdm/wow16/inc/penwin.h b/private/mvdm/wow16/inc/penwin.h
new file mode 100644
index 000000000..fbe2d112e
--- /dev/null
+++ b/private/mvdm/wow16/inc/penwin.h
@@ -0,0 +1,818 @@
+/*****************************************************************************\
+* *
+* penwin.h - Pen Windows functions, types, and definitions *
+* *
+* Version 1.0 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_WINDOWS
+#include <windows.h> /* <windows.h> must be pre-included */
+#endif /* _INC_WINDOWS */
+
+#ifndef _INC_PENWIN /* prevent multiple includes */
+#define _INC_PENWIN
+
+#ifndef RC_INVOKED
+#pragma pack(1)
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/****** General Pen Windows Definitions *************************************/
+
+typedef int REC;
+typedef LONG SYV;
+typedef SYV FAR *LPSYV;
+typedef HANDLE HREC;
+typedef int CL;
+typedef LONG ALC;
+typedef UINT HKP;
+typedef int (CALLBACK * LPDF)(int, LPVOID, LPVOID, int, DWORD, DWORD);
+
+#define BITPENUP 0x8000
+#define FPenUpX(x) (((x) & BITPENUP)!=0)
+
+/* Default pen cursor to indicate writing, points northwest */
+#define IDC_PEN MAKEINTRESOURCE(32631)
+
+/* alternate select cursor: upsidedown standard arrow, points southeast */
+#define IDC_ALTSELECT MAKEINTRESOURCE(32501)
+
+#define RC_WDEFAULT (0xFFFF)
+#define RC_LDEFAULT (0xFFFFFFFFL)
+#define RC_WDEFAULTFLAGS (0x8000)
+#define RC_LDEFAULTFLAGS (0x80000000L)
+
+/* HIWORD(SYV) defines and detection macros */
+
+#define SYVHI_SPECIAL 0
+#define FIsSpecial(syv) (HIWORD((syv))==SYVHI_SPECIAL)
+#define SYVHI_ANSI 1
+#define FIsAnsi(syv) (HIWORD((syv))==SYVHI_ANSI)
+#define SYVHI_GESTURE 2
+#define FIsGesture(syv) (HIWORD((syv))==SYVHI_GESTURE)
+#define SYVHI_KANJI 3
+#define FIsKanji(syv) (HIWORD((syv))==SYVHI_KANJI)
+#define SYVHI_SHAPE 4
+#define FIsShape(syv) (HIWORD((syv))==SYVHI_SHAPE)
+#define SYVHI_UNICODE 5
+#define FIsUniCode(syv) (HIWORD((syv))==SYVHI_UNICODE)
+#define SYVHI_VKEY 6
+#define FIsVKey(syv) (HIWORD((syv))==SYVHI_VKEY)
+
+/* Macros to convert between SYV and ANSI */
+
+#define ChSyvToAnsi(syv) ((BYTE) (LOBYTE(LOWORD((syv)))))
+#define SyvCharacterToSymbol(c) ((LONG)(unsigned char)(c) | 0x00010000)
+#define SyvKanjiToSymbol(c) ((LONG)(WORD)(c) | 0x00030000)
+
+/* SYV values with special meanings to Pen Windows */
+
+#define SYV_NULL 0x00000000L
+#define SYV_UNKNOWN 0x00000001L
+#define SYV_EMPTY 0x00000003L
+#define SYV_BEGINOR 0x00000010L
+#define SYV_ENDOR 0x00000011L
+#define SYV_OR 0x00000012L
+#define SYV_SOFTNEWLINE 0x00000020L
+#define SYV_SPACENULL SyvCharacterToSymbol('\0')
+
+/* SYV values for gestures (map into UNICODE space) */
+
+#define SYV_KKCONVERT 0x0002FFD4L
+#define SYV_CLEAR 0x0002FFD5L
+#define SYV_EXTENDSELECT 0x0002FFD8L
+#define SYV_UNDO 0x0002FFD9L
+#define SYV_COPY 0x0002FFDAL
+#define SYV_CUT 0x0002FFDBL
+#define SYV_PASTE 0x0002FFDCL
+#define SYV_CLEARWORD 0x0002FFDDL
+#define SYV_USER 0x0002FFDEL /* ;Reserved */
+#define SYV_CORRECT 0x0002FFDFL
+
+#define SYV_BACKSPACE 0x00020008L
+#define SYV_TAB 0x00020009L
+#define SYV_RETURN 0x0002000DL
+#define SYV_SPACE 0x00020020L
+
+#define FIsStdGesture(syv) \
+ ((syv) == SYV_CLEAR \
+ || (syv) == SYV_EXTENDSELECT\
+ || (syv) == SYV_UNDO \
+ || (syv) == SYV_COPY \
+ || (syv) == SYV_CUT \
+ || (syv) == SYV_PASTE \
+ || (syv) == SYV_CLEARWORD \
+ || (syv) == SYV_KKCONVERT \
+ || (syv) == SYV_USER \
+ || (syv) == SYV_CORRECT)
+
+#define FIsAnsiGesture(syv) \
+ ((syv) == SYV_BACKSPACE \
+ || (syv) == SYV_TAB \
+ || (syv) == SYV_RETURN \
+ || (syv) == SYV_SPACE)
+
+/* Application specific gestures, Circle a-z and Circle A-Z */
+
+#define SYV_APPGESTUREMASK 0x00020000L
+#define SYV_CIRCLEUPA 0x000224B6L
+#define SYV_CIRCLEUPZ 0x000224CFL
+#define SYV_CIRCLELOA 0x000224D0L
+#define SYV_CIRCLELOZ 0x000224E9L
+
+/* Gesture Macros */
+
+#define FIsLoAppGesture(syv) (syv >= SYV_CIRCLELOA && syv <= SYV_CIRCLELOZ)
+#define FIsUpAppGesture(syv) (syv >= SYV_CIRCLEUPA && syv <= SYV_CIRCLEUPZ)
+#define FIsAppGesture(syv) (syv>=SYV_CIRCLEUPA && syv<=SYV_CIRCLELOZ)
+
+#define SyvAppGestureFromLoAnsi(ansi) ((DWORD)(BYTE)ansi- 'a' + SYV_CIRCLELOA)
+#define SyvAppGestureFromUpAnsi(ansi) ((DWORD)(BYTE)ansi- 'A' + SYV_CIRCLEUPA)
+#define AnsiFromSyvAppGesture(syv) ChSyvToAnsi( \
+ syv-(FIsUpAppGesture(syv)? SYV_CIRCLEUPA-(SYV)'A': SYV_CIRCLELOA-(SYV)'a'))
+
+/* SYV definitions for shapes */
+
+#define SYV_SHAPELINE 0x00040001L
+#define SYV_SHAPEELLIPSE 0x00040002L
+#define SYV_SHAPERECT 0x00040003L
+#define SYV_SHAPEMIN SYV_SHAPELINE
+#define SYV_SHAPEMAX SYV_SHAPERECT
+
+/****** Recognition Error Codes *********************************************/
+
+#define REC_OEM (-1024)
+#define REC_LANGUAGE (-48)
+#define REC_GUIDE (-47)
+#define REC_PARAMERROR (-46)
+#define REC_INVALIDREF (-45)
+#define REC_RECTEXCLUDE (-44)
+#define REC_RECTBOUND (-43)
+#define REC_PCM (-42)
+#define REC_RESULTMODE (-41)
+#define REC_HWND (-40)
+#define REC_ALC (-39)
+#define REC_ERRORLEVEL (-38)
+#define REC_CLVERIFY (-37)
+#define REC_DICT (-36)
+#define REC_HREC (-35)
+#define REC_BADEVENTREF (-33)
+#define REC_NOCOLLECTION (-32)
+
+#define REC_DEBUG (-32)
+
+#define REC_POINTEREVENT (-31)
+#define REC_BADHPENDATA (-9)
+#define REC_OOM (-8)
+#define REC_NOINPUT (-7)
+#define REC_NOTABLET (-6)
+#define REC_BUSY (-5)
+#define REC_BUFFERTOOSMALL (-4)
+#define REC_ABORT (-3)
+
+#define REC_OVERFLOW (-1)
+
+#define REC_OK 0
+#define REC_TERMBOUND 1
+#define REC_TERMEX 2
+#define REC_TERMPENUP 3
+#define REC_TERMRANGE 4
+#define REC_TERMTIMEOUT 5
+#define REC_DONE 6
+#define REC_TERMOEM 512
+
+/****** Pen Driver Structures and Entry points ******************************/
+
+typedef struct tagOEMPENINFO
+ {
+ UINT wPdt;
+ UINT wValueMax;
+ UINT wDistinct;
+ }
+ OEMPENINFO, FAR *LPOEMPENINFO;
+
+#define PDT_NULL 0
+#define PDT_PRESSURE 1
+#define PDT_HEIGHT 2
+#define PDT_ANGLEXY 3
+#define PDT_ANGLEZ 4
+#define PDT_BARRELROTATION 5
+#define PDT_OEMSPECIFIC 16
+
+#define MAXOEMDATAWORDS 6
+
+typedef struct tagPENPACKET
+ {
+ UINT wTabletX;
+ UINT wTabletY;
+ UINT wPDK;
+ UINT rgwOemData[MAXOEMDATAWORDS];
+ }
+ PENPACKET, FAR *LPPENPACKET;
+
+typedef BOOL (CALLBACK * LPFNRAWHOOK)(LPPENPACKET);
+
+typedef struct tagPENINFO
+ {
+ UINT cxRawWidth;
+ UINT cyRawHeight;
+ UINT wDistinctWidth;
+ UINT wDistinctHeight;
+ int nSamplingRate;
+ int nSamplingDist;
+ LONG lPdc;
+ int cPens;
+ int cbOemData;
+ OEMPENINFO rgoempeninfo[MAXOEMDATAWORDS];
+ UINT rgwReserved[8];
+ }
+ PENINFO, FAR *LPPENINFO;
+
+#define PDC_INTEGRATED 0x00000001L
+#define PDC_PROXIMITY 0x00000002L
+#define PDC_RANGE 0x00000004L
+#define PDC_INVERT 0x00000008L
+#define PDC_RELATIVE 0x00000010L
+#define PDC_BARREL1 0x00000020L
+#define PDC_BARREL2 0x00000040L
+#define PDC_BARREL3 0x00000080L
+
+typedef struct tagSTROKEINFO
+ {
+ UINT cPnt;
+ UINT cbPnts;
+ UINT wPdk;
+ DWORD dwTick;
+ }
+ STROKEINFO, FAR *LPSTROKEINFO;
+
+typedef struct tagCALBSTRUCT
+ {
+ int wOffsetX;
+ int wOffsetY;
+ int wDistinctWidth;
+ int wDistinctHeight;
+ }
+ CALBSTRUCT, FAR *LPCALBSTRUCT;
+
+/****** DRV_ values for pen driver specific messages ************************/
+
+#define DRV_SetPenDriverEntryPoints DRV_RESERVED+1
+#define DRV_RemovePenDriverEntryPoints DRV_RESERVED+2
+#define DRV_SetPenSamplingRate DRV_RESERVED+3
+#define DRV_SetPenSamplingDist DRV_RESERVED+4
+#define DRV_GetName DRV_RESERVED+5
+#define DRV_GetVersion DRV_RESERVED+6
+#define DRV_GetPenInfo DRV_RESERVED+7
+#define DRV_GetCalibration DRV_RESERVED+11
+#define DRV_SetCalibration DRV_RESERVED+12
+
+VOID WINAPI UpdatePenInfo(LPPENINFO);
+BOOL WINAPI EndPenCollection(REC);
+REC WINAPI GetPenHwData(LPPOINT, LPVOID, int, UINT, LPSTROKEINFO);
+REC WINAPI GetPenHwEventData(UINT, UINT, LPPOINT, LPVOID, int, LPSTROKEINFO);
+VOID WINAPI PenPacket(VOID);
+BOOL WINAPI SetPenHook(HKP, LPFNRAWHOOK);
+
+/****** Pen Hardware Constants **********************************************/
+
+#define PDK_UP 0x0000
+#define PDK_DOWN 0x0001
+#define PDK_BARREL1 0x0002
+#define PDK_BARREL2 0x0004
+#define PDK_BARREL3 0x0008
+#define PDK_TRANSITION 0x0010
+#define PDK_INVERTED 0x0080
+#define PDK_OUTOFRANGE 0x4000
+#define PDK_DRIVER 0x8000
+#define PDK_TIPMASK 0x0001
+#define PDK_SWITCHES (PDK_DOWN|PDK_BARREL1|PDK_BARREL2|PDK_BARREL3)
+
+#define PCM_PENUP 0x00000001L
+#define PCM_RANGE 0x00000002L
+#define PCM_INVERT 0x00000020L
+#define PCM_RECTEXCLUDE 0x00002000L
+#define PCM_RECTBOUND 0x00004000L
+#define PCM_TIMEOUT 0x00008000L
+#define PCM_ADDDEFAULTS RC_LDEFAULTFLAGS /* 0x80000000L */
+
+/****** Virtual Event Layer *************************************************/
+
+VOID WINAPI PostVirtualKeyEvent(UINT, BOOL);
+VOID WINAPI PostVirtualMouseEvent(UINT, int, int);
+VOID WINAPI AtomicVirtualEvent(BOOL);
+
+#define VWM_MOUSEMOVE 0x0001
+#define VWM_MOUSELEFTDOWN 0x0002
+#define VWM_MOUSELEFTUP 0x0004
+#define VWM_MOUSERIGHTDOWN 0x0008
+#define VWM_MOUSERIGHTUP 0x0010
+
+/****** RC Definition *************************************************************/
+
+#define CL_NULL 0
+#define CL_MINIMUM 1
+#define CL_MAXIMUM 100
+#define INKWIDTH_MINIMUM 0
+#define INKWIDTH_MAXIMUM 15
+#define ENUM_MINIMUM 1
+#define ENUM_MAXIMUM 4096
+#define MAXDICTIONARIES 16
+
+typedef struct tagGUIDE
+ {
+ int xOrigin;
+ int yOrigin;
+ int cxBox;
+ int cyBox;
+ int cxBase;
+ int cyBase;
+ int cHorzBox;
+ int cVertBox;
+ int cyMid;
+ }
+ GUIDE, FAR *LPGUIDE;
+
+typedef BOOL (CALLBACK * RCYIELDPROC)(VOID);
+
+#define cbRcLanguageMax 44
+#define cbRcUserMax 32
+#define cbRcrgbfAlcMax 32
+#define cwRcReservedMax 8
+
+typedef struct tagRC
+ {
+ HREC hrec;
+ HWND hwnd;
+ UINT wEventRef;
+ UINT wRcPreferences;
+ LONG lRcOptions;
+ RCYIELDPROC lpfnYield;
+ BYTE lpUser[cbRcUserMax];
+ UINT wCountry;
+ UINT wIntlPreferences;
+ char lpLanguage[cbRcLanguageMax];
+ LPDF rglpdf[MAXDICTIONARIES];
+ UINT wTryDictionary;
+ CL clErrorLevel;
+ ALC alc;
+ ALC alcPriority;
+ BYTE rgbfAlc[cbRcrgbfAlcMax];
+ UINT wResultMode;
+ UINT wTimeOut;
+ LONG lPcm;
+ RECT rectBound;
+ RECT rectExclude;
+ GUIDE guide;
+ UINT wRcOrient;
+ UINT wRcDirect;
+ int nInkWidth;
+ COLORREF rgbInk;
+ DWORD dwAppParam;
+ DWORD dwDictParam;
+ DWORD dwRecognizer;
+ UINT rgwReserved[cwRcReservedMax];
+ }
+ RC, FAR *LPRC;
+
+typedef HANDLE HPENDATA;
+
+typedef struct tagSYC
+ {
+ UINT wStrokeFirst;
+ UINT wPntFirst;
+ UINT wStrokeLast;
+ UINT wPntLast;
+ BOOL fLastSyc;
+ }
+ SYC, FAR *LPSYC;
+
+#define wPntAll (UINT)0xFFFF
+#define iSycNull (-1)
+
+typedef struct tagSYE
+ {
+ SYV syv;
+ LONG lRecogVal;
+ CL cl;
+ int iSyc;
+ }
+ SYE, FAR *LPSYE;
+
+#define MAXHOTSPOT 8
+
+typedef struct tagSYG
+ {
+ POINT rgpntHotSpots[MAXHOTSPOT];
+ int cHotSpot;
+ int nFirstBox;
+ LONG lRecogVal;
+ LPSYE lpsye;
+ int cSye;
+ LPSYC lpsyc;
+ int cSyc;
+ }
+ SYG, FAR *LPSYG;
+
+typedef int (CALLBACK *ENUMPROC)(LPSYV, int, VOID FAR *);
+
+typedef struct tagRCRESULT
+ {
+ SYG syg;
+ UINT wResultsType;
+ int cSyv;
+ LPSYV lpsyv;
+ HANDLE hSyv;
+ int nBaseLine;
+ int nMidLine;
+ HPENDATA hpendata;
+ RECT rectBoundInk;
+ POINT pntEnd;
+ LPRC lprc;
+ }
+ RCRESULT, FAR *LPRCRESULT;
+
+#define RCRT_DEFAULT 0x0000
+#define RCRT_UNIDENTIFIED 0x0001
+#define RCRT_GESTURE 0x0002
+#define RCRT_NOSYMBOLMATCH 0x0004
+#define RCRT_PRIVATE 0x4000
+#define RCRT_NORECOG 0x8000
+#define RCRT_ALREADYPROCESSED 0x0008
+#define RCRT_GESTURETRANSLATED 0x0010
+#define RCRT_GESTURETOKEYS 0x0020
+
+#define HKP_SETHOOK 0
+#define HKP_UNHOOK 0xFFFF
+#define HWR_RESULTS 0
+#define HWR_APPWIDE 1
+
+#define PEN_NOINKWIDTH 0
+#define LPDFNULL ((LPDF)NULL)
+
+#define RPA_DEFAULT 1
+
+/* GetGlobalRC return codes */
+#define GGRC_OK 0
+#define GGRC_DICTBUFTOOSMALL 1
+#define GGRC_PARAMERROR 2
+
+/* SetGlobalRC return code flags */
+#define SGRC_OK 0x0000
+#define SGRC_USER 0x0001
+#define SGRC_PARAMERROR 0x0002
+#define SGRC_RC 0x0004
+#define SGRC_RECOGNIZER 0x0008
+#define SGRC_DICTIONARY 0x0010
+#define SGRC_INIFILE 0x0020
+
+#define GetWEventRef() (LOWORD(GetMessageExtraInfo()))
+
+HREC WINAPI InstallRecognizer(LPSTR);
+VOID WINAPI UninstallRecognizer(HREC);
+UINT WINAPI GetGlobalRC(LPRC, LPSTR, LPSTR, int);
+UINT WINAPI SetGlobalRC(LPRC, LPSTR, LPSTR);
+VOID WINAPI RegisterPenApp(UINT, BOOL);
+UINT WINAPI IsPenAware(VOID);
+BOOL WINAPI SetRecogHook(UINT, UINT, HWND);
+VOID WINAPI InitRC(HWND, LPRC);
+REC WINAPI Recognize(LPRC);
+REC WINAPI RecognizeData(LPRC, HPENDATA);
+BOOL WINAPI TrainInk(LPRC, HPENDATA, LPSYV);
+BOOL WINAPI TrainContext(LPRCRESULT, LPSYE, int, LPSYC, int);
+REC WINAPI ProcessWriting(HWND, LPRC);
+BOOL WINAPI CorrectWriting(HWND, LPSTR, UINT, LPRC, DWORD, DWORD);
+VOID WINAPI EmulatePen(BOOL);
+int WINAPI GetSymbolMaxLength(LPSYG);
+int WINAPI GetSymbolCount(LPSYG);
+VOID WINAPI FirstSymbolFromGraph(LPSYG, LPSYV, int, int FAR *);
+UINT WINAPI EnumSymbols(LPSYG, WORD, ENUMPROC, LPVOID);
+
+/****** Miscellaneous Functions *********************************************/
+
+BOOL WINAPI TPtoDP(LPPOINT, int);
+BOOL WINAPI DPtoTP(LPPOINT, int);
+VOID WINAPI BoundingRectFromPoints(LPPOINT, int, LPRECT);
+BOOL WINAPI SymbolToCharacter(LPSYV, int, LPSTR, LPINT);
+int WINAPI CharacterToSymbol(LPSTR, int, LPSYV);
+UINT WINAPI GetVersionPenWin(VOID);
+BOOL WINAPI ExecuteGesture(HWND, SYV, LPRCRESULT);
+
+/****** RC Options and Flags ***********************************************/
+
+#define ALC_ALL 0x000043FFL
+#define ALC_DEFAULT 0x00000000L
+#define ALC_LCALPHA 0x00000001L
+#define ALC_UCALPHA 0x00000002L
+#define ALC_ALPHA 0x00000003L
+#define ALC_NUMERIC 0x00000004L
+#define ALC_ALPHANUMERIC 0x00000007L
+#define ALC_PUNC 0x00000008L
+#define ALC_MATH 0x00000010L
+#define ALC_MONETARY 0x00000020L
+#define ALC_OTHER 0x00000040L
+#define ALC_WHITE 0x00000100L
+#define ALC_NONPRINT 0x00000200L
+#define ALC_GESTURE 0x00004000L
+#define ALC_USEBITMAP 0x00008000L
+#define ALC_DBCS 0x00000400L
+#define ALC_HIRAGANA 0x00010000L
+#define ALC_KATAKANA 0x00020000L
+#define ALC_KANJI 0x00040000L
+#define ALC_OEM 0x0FF80000L
+#define ALC_RESERVED 0xF0003800L
+#define ALC_NOPRIORITY 0x00000000L
+#define ALC_SYSMINIMUM (ALC_ALPHANUMERIC | ALC_PUNC | ALC_WHITE | ALC_GESTURE)
+
+#define MpAlcB(lprc,i) ((lprc)->rgbfAlc[((i) & 0xff) >> 3])
+#define MpIbf(i) ((BYTE)(1 << ((i) & 7)))
+
+#define SetAlcBitAnsi(lprc,i) do {MpAlcB(lprc,i) |= MpIbf(i);} while (0)
+#define ResetAlcBitAnsi(lprc,i) do {MpAlcB(lprc,i) &= ~MpIbf(i);} while (0)
+#define IsAlcBitAnsi(lprc, i) ((MpAlcB(lprc,i) & MpIbf(i)) != 0)
+
+#define RCD_DEFAULT 0
+#define RCD_LR 1
+#define RCD_RL 2
+#define RCD_TB 3
+#define RCD_BT 4
+
+#define RCO_NOPOINTEREVENT 0x00000001L
+#define RCO_SAVEALLDATA 0x00000002L
+#define RCO_SAVEHPENDATA 0x00000004L
+#define RCO_NOFLASHUNKNOWN 0x00000008L
+#define RCO_TABLETCOORD 0x00000010L
+#define RCO_NOSPACEBREAK 0x00000020L
+#define RCO_NOHIDECURSOR 0x00000040L
+#define RCO_NOHOOK 0x00000080L
+#define RCO_BOXED 0x00000100L
+#define RCO_SUGGEST 0x00000200L
+#define RCO_DISABLEGESMAP 0x00000400L
+#define RCO_NOFLASHCURSOR 0x00000800L
+#define RCO_COLDRECOG 0x00008000L
+
+#define RCP_LEFTHAND 0x0001
+#define RCP_MAPCHAR 0x0004
+
+#define RCOR_NORMAL 1
+#define RCOR_RIGHT 2
+#define RCOR_UPSIDEDOWN 3
+#define RCOR_LEFT 4
+
+#define RRM_STROKE 0
+#define RRM_SYMBOL 1
+#define RRM_WORD 2
+#define RRM_NEWLINE 3
+#define RRM_COMPLETE 16
+
+#define RCIP_ALLANSICHAR 0x0001
+#define RCIP_MASK 0x0001
+
+#define CWR_STRIPCR 0x00000001L
+#define CWR_STRIPLF 0x00000002L
+#define CWR_STRIPTAB 0x00000004L
+#define CWR_SINGLELINEEDIT 0x00000007L
+#define CWR_TITLE 0x00000010L
+#define CWR_KKCONVERT 0x00000020L
+
+#define MAP_GESTOGES (RCRT_GESTURE|RCRT_GESTURETRANSLATED)
+#define MAP_GESTOVKEYS (RCRT_GESTURETOKEYS|RCRT_ALREADYPROCESSED)
+
+#define IsGestureToGesture(lprcresult) (((lprcresult)->wResultstype & MAP_GESTOGES \
+ ) == MAP_GESTOGES)
+
+#define IsGestureToVkeys(lprcresult) (((lprcresult)->wResultstype & MAP_GESTOVKEYS \
+ ) == MAP_GESTOVKEYS)
+
+#define SetAlreadyProcessed(lprcresult) ((lprcresult)->wResultsType = ((lprcresult)->wResultsType \
+ & ~RCRT_GESTURETOKEYS) | RCRT_ALREADYPROCESSED)
+
+/****** Pen Data Type *******************************************************/
+
+typedef struct tagPENDATAHEADER
+ {
+ UINT wVersion;
+ UINT cbSizeUsed;
+ UINT cStrokes;
+ UINT cPnt;
+ UINT cPntStrokeMax;
+ RECT rectBound;
+ UINT wPndts;
+ int nInkWidth;
+ DWORD rgbInk;
+ }
+ PENDATAHEADER, FAR *LPPENDATAHEADER, FAR *LPPENDATA;
+
+#define PDTS_LOMETRIC 0x0000
+#define PDTS_HIMETRIC 0x0001
+#define PDTS_HIENGLISH 0x0002
+#define PDTS_SCALEMAX 0x0003
+#define PDTS_DISPLAY 0x0003
+#define PDTS_ARBITRARY 0x0004
+#define PDTS_SCALEMASK 0x000F
+#define PDTS_STANDARDSCALE PDTS_HIENGLISH
+
+#define PDTS_NOPENINFO 0x0100
+#define PDTS_NOUPPOINTS 0x0200
+#define PDTS_NOOEMDATA 0x0400
+#define PDTS_NOCOLINEAR 0x0800
+#define PDTS_COMPRESSED 0x8000
+#define PDTS_COMPRESSMETHOD 0x00F0
+#define PDTS_COMPRESS2NDDERIV 0x0010
+
+#define PDTT_DEFAULT 0x0000
+#define PDTT_PENINFO PDTS_NOPENINFO
+#define PDTT_UPPOINTS PDTS_NOUPPOINTS
+#define PDTT_OEMDATA PDTS_NOOEMDATA
+#define PDTT_COLINEAR PDTS_NOCOLINEAR
+#define PDTT_COMPRESS PDTS_COMPRESSED
+#define PDTT_DECOMPRESS 0x4000
+#define PDTT_ALL (PDTT_PENINFO|PDTT_UPPOINTS|PDTT_OEMDATA|PDTT_COLINEAR)
+
+#define DestroyPenData(hpendata) (GlobalFree(hpendata)==NULL)
+#define EndEnumStrokes(hpendata) GlobalUnlock(hpendata)
+
+BOOL WINAPI IsPenEvent(UINT, LONG);
+BOOL WINAPI GetPenAsyncState(UINT);
+
+BOOL WINAPI GetPenDataInfo(HPENDATA, LPPENDATAHEADER, LPPENINFO, DWORD);
+BOOL WINAPI GetPenDataStroke(LPPENDATA, UINT, LPPOINT FAR *, LPVOID FAR *, LPSTROKEINFO );
+BOOL WINAPI GetPointsFromPenData(HPENDATA, UINT, UINT, UINT, LPPOINT);
+VOID WINAPI DrawPenData(HDC, LPRECT, HPENDATA);
+BOOL WINAPI MetricScalePenData(HPENDATA, UINT);
+BOOL WINAPI ResizePenData(HPENDATA, LPRECT);
+BOOL WINAPI OffsetPenData(HPENDATA, int, int);
+BOOL WINAPI RedisplayPenData(HDC, HPENDATA, LPPOINT, LPPOINT, int, DWORD);
+HPENDATA WINAPI CompactPenData(HPENDATA, UINT );
+HPENDATA WINAPI DuplicatePenData(HPENDATA, UINT);
+HPENDATA WINAPI CreatePenData(LPPENINFO, int, UINT, UINT);
+HPENDATA WINAPI AddPointsPenData(HPENDATA, LPPOINT, LPVOID, LPSTROKEINFO);
+LPPENDATA WINAPI BeginEnumStrokes(HPENDATA );
+
+/****** New Windows Messages ************************************************/
+
+#define WM_RCRESULT (WM_PENWINFIRST+1)
+#define WM_HOOKRCRESULT (WM_PENWINFIRST+2)
+#define WM_GLOBALRCCHANGE (WM_PENWINFIRST+3)
+#define WM_SKB (WM_PENWINFIRST+4)
+#define WM_HEDITCTL (WM_PENWINFIRST+5)
+
+/****** Dictionary **********************************************************/
+
+#define cbDictPathMax 255
+#define DIRQ_QUERY 1
+#define DIRQ_DESCRIPTION 2
+#define DIRQ_CONFIGURE 3
+#define DIRQ_OPEN 4
+#define DIRQ_CLOSE 5
+#define DIRQ_SETWORDLISTS 6
+#define DIRQ_STRING 7
+#define DIRQ_SUGGEST 8
+#define DIRQ_ADD 9
+#define DIRQ_DELETE 10
+#define DIRQ_FLUSH 11
+#define DIRQ_RCCHANGE 12
+#define DIRQ_SYMBOLGRAPH 13
+#define DIRQ_INIT 14
+#define DIRQ_CLEANUP 15
+#define DIRQ_COPYRIGHT 16
+
+
+#define DIRQ_USER 4096
+
+BOOL WINAPI DictionarySearch(LPRC, LPSYE, int, LPSYV, int);
+
+/****** Handwriting Edit Control ********************************************/
+
+#define HE_GETRC 3
+#define HE_SETRC 4
+#define HE_GETINFLATE 5
+#define HE_SETINFLATE 6
+#define HE_GETUNDERLINE 7
+#define HE_SETUNDERLINE 8
+#define HE_GETINKHANDLE 9
+#define HE_SETINKMODE 10
+#define HE_STOPINKMODE 11
+#define HE_GETRCRESULTCODE 12
+#define HE_DEFAULTFONT 13
+#define HE_CHARPOSITION 14
+#define HE_CHAROFFSET 15
+
+#define HE_GETRCRESULT 22
+
+#define HE_KKCONVERT 30
+#define HE_GETKKCONVERT 31
+#define HE_CANCELKKCONVERT 32
+#define HE_FIXKKCONVERT 33
+
+#define HEKK_DEFAULT 0
+#define HEKK_CONVERT 1
+#define HEKK_CANDIDATE 2
+
+#define HEP_NORECOG 0
+#define HEP_RECOG 1
+#define HEP_WAITFORTAP 2
+
+#define HN_ENDREC 4
+#define HN_DELAYEDRECOGFAIL 5
+
+#define HN_RCRESULT 20
+
+#define HN_ENDKKCONVERT 30
+
+typedef struct tagRECTOFS
+ {
+ int dLeft;
+ int dTop;
+ int dRight;
+ int dBottom;
+ }
+ RECTOFS, FAR *LPRECTOFS;
+
+/****** Boxed Edit Control **************************************************/
+
+typedef struct tagBOXLAYOUT
+ {
+ int cyCusp;
+ int cyEndCusp;
+ UINT style;
+ DWORD rgbText;
+ DWORD rgbBox;
+ DWORD rgbSelect;
+ }
+ BOXLAYOUT, FAR *LPBOXLAYOUT;
+
+#define BXS_NONE 0U
+#define BXS_RECT 1U
+#define BXS_ENDTEXTMARK 2U
+#define BXS_MASK 3U
+
+#define HE_GETBOXLAYOUT 20
+#define HE_SETBOXLAYOUT 21
+
+#define BXD_CELLWIDTH 12
+#define BXD_CELLHEIGHT 16
+#define BXD_BASEHEIGHT 13
+#define BXD_BASEHORZ 0
+#define BXD_CUSPHEIGHT 2
+#define BXD_ENDCUSPHEIGHT 4
+
+/****** Screen Keyboard *****************************************************/
+
+typedef struct tagSKBINFO
+ {
+ HWND hwnd;
+ UINT nPad;
+ BOOL fVisible;
+ BOOL fMinimized;
+ RECT rect;
+ DWORD dwReserved;
+ }
+ SKBINFO, FAR *LPSKBINFO;
+
+#define SKB_QUERY 0x0000
+#define SKB_SHOW 0x0001
+#define SKB_HIDE 0x0002
+#define SKB_CENTER 0x0010
+#define SKB_MOVE 0x0020
+#define SKB_MINIMIZE 0x0040
+#define SKB_FULL 0x0100
+#define SKB_BASIC 0x0200
+#define SKB_NUMPAD 0x0400
+
+#define OBM_SKBBTNUP 32767
+#define OBM_SKBBTNDOWN 32766
+#define OBM_SKBBTNDISABLED 32765
+
+#define SKN_CHANGED 1
+
+#define SKN_POSCHANGED 1
+#define SKN_PADCHANGED 2
+#define SKN_MINCHANGED 4
+#define SKN_VISCHANGED 8
+#define SKN_TERMINATED 0xffff
+
+BOOL WINAPI ShowKeyboard(HWND, UINT, LPPOINT, LPSKBINFO);
+
+/****** New ComboBox Notifications *****************************************/
+
+#define CBN_ENDREC 16
+#define CBN_DELAYEDRECOGFAIL 17
+#define CBN_RCRESULT 18
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* #define _INC_PENWIN */
diff --git a/private/mvdm/wow16/inc/prd.inc b/private/mvdm/wow16/inc/prd.inc
new file mode 100644
index 000000000..c85c5c385
--- /dev/null
+++ b/private/mvdm/wow16/inc/prd.inc
@@ -0,0 +1,69 @@
+NAME_LEN equ 32
+BLOCK_SIZE equ 512
+DEV_PRD equ 8888h
+DEV_PORT equ 8888h
+DEV_LAND equ 8889h
+
+HSIZE equ 8d ;HorzSize
+VSIZE equ 11d ;VertSize
+VSIZE_LEGAL equ 14d ;VertSize
+
+MM_HSIZE equ 203 ;Horizontal size in millimeter
+MM_HSIZE0 equ 2032
+MM_HSIZE00 equ 20320
+MM_VSIZE equ 279 ;Vertical size in millimeter
+MM_VSIZE0 equ 2794
+MM_VSIZE00 equ 27940
+MM_VSIZE_LEGAL equ 356 ;Vertical size in millimeter
+MM_VSIZE0_LEGAL equ 3556
+MM_VSIZE00_LEGAL equ 35560
+
+EnglishLo1 equ 800 ;HorzSize * 1000 scaled (/254)
+EnglishLo2 equ 1100 ;VertSize * 1000 scaled (/254)
+
+EnglishHi1 equ 8000 ;HorzSize * 10000 scaled (/254)
+EnglishHi2 equ 11000 ;VertSize * 10000 scaled (/254)
+EnglishHi3 equ EnglishLo3
+EnglishHi4 equ EnglishLo4
+
+Twips1 equ 11520 ;HorzSize * 14400 scaled (/254)
+Twips2 equ 15840 ;VertSize * 14400 scaled (/254)
+Twips3 equ EnglishLo3
+Twips4 equ EnglishLo4
+
+EnglishLo2_LEGAL equ 1400
+EnglishHi2_LEGAL equ 14000 ;VertSize * 10000 scaled (/254)
+EnglishHi4_LEGAL equ EnglishLo4_LEGAL
+
+Twips2_LEGAL equ 20160
+Twips4_LEGAL equ EnglishLo4_LEGAL
+
+yMinorDist = Hypotenuse-xMajorDist
+xMinorDist = Hypotenuse-yMajorDist
+
+MaxStyleErr = Hypotenuse*2 ;Max error before updating
+ ;rotating bit mask
+
+DEVICE struc
+ deType dw 0 ;
+ deMode dw 0 ;
+ deJob dw 0 ;job number
+ deWheel dw 0 ;font wheel number
+ dePtr dw 0 ;spooler buffer pointer
+ deYPQ dw 0
+ deXPQ dw 0
+ deCurx dw 0
+ deCury dw 0
+ deXcurwidth dw 0
+ deYcurwidth dw 0
+ deDoc dw 0 ;job spooled as a document or by the page
+ deHeap dw 0
+ deHPsize dw 0
+ deHPptr dw 0
+ dePhySize dd 0
+DEVICE ends
+
+BUFFER struc
+ dePort db NAME_LEN dup (?); port name
+ deSpool db BLOCK_SIZE dup (?)
+BUFFER ends
diff --git a/private/mvdm/wow16/inc/print.h b/private/mvdm/wow16/inc/print.h
new file mode 100644
index 000000000..263dff97d
--- /dev/null
+++ b/private/mvdm/wow16/inc/print.h
@@ -0,0 +1,302 @@
+/*****************************************************************************\
+* *
+* print.h - Printing helper functions, types, and definitions *
+* *
+* Copyright (c) 1985-1992. Microsoft Corp. All rights reserved.*
+* *
+*******************************************************************************
+*
+* PRINTDRIVER - For inclusion with a printer driver
+* NOPQ - Prevent inclusion of priority queue APIs
+*
+\*****************************************************************************/
+
+#ifndef _INC_PRINT
+#define _INC_PRINT
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifdef PRINTDRIVER
+
+#define NORASTEROPS
+#define NOTEXTMETRICS
+#define NOGDICAPMASKS
+#define NOGDIOBJ
+#define NOBITMAP
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOCOMM
+#define NOKANJI
+
+#include <windows.h>
+
+#undef NORASTEROPS
+#undef NOTEXTMETRICS
+#undef NOGDICAPMASKS
+#undef NOGDICAPMASKS
+#undef NOGDIOBJ
+#undef NOBITMAP
+#undef NOSOUND
+#undef NOTEXTMETRIC
+#undef NOCOMM
+#undef NOKANJI
+
+#define NOPTRC /* don't allow gdidefs.inc to redef these */
+#define PTTYPE POINT
+
+#define PQERROR (-1)
+
+#ifndef NOPQ
+
+DECLARE_HANDLE(HPQ);
+
+HPQ WINAPI CreatePQ(int);
+int WINAPI MinPQ(HPQ);
+int WINAPI ExtractPQ(HPQ);
+int WINAPI InsertPQ(HPQ, int, int);
+int WINAPI SizePQ(HPQ, int);
+void WINAPI DeletePQ(HPQ);
+#endif /* !NOPQ */
+
+/* Spool routines for use by printer drivers */
+
+DECLARE_HANDLE(HPJOB);
+
+HPJOB WINAPI OpenJob(LPSTR, LPSTR, HPJOB);
+int WINAPI StartSpoolPage(HPJOB);
+int WINAPI EndSpoolPage(HPJOB);
+int WINAPI WriteSpool(HPJOB, LPSTR, int);
+int WINAPI CloseJob(HPJOB);
+int WINAPI DeleteJob(HPJOB, int);
+int WINAPI WriteDialog(HPJOB, LPSTR, int);
+int WINAPI DeleteSpoolPage(HPJOB);
+
+#endif /* !PRINTDRIVER */
+
+typedef struct tagBANDINFOSTRUCT
+{
+ BOOL fGraphics;
+ BOOL fText;
+ RECT rcGraphics;
+} BANDINFOSTRUCT, FAR* LPBI;
+
+#define USA_COUNTRYCODE 1
+
+/*
+ * Printer driver initialization using ExtDeviceMode()
+ * and DeviceCapabilities().
+ * This replaces Drivinit.h
+ */
+
+/* size of a device name string */
+#define CCHDEVICENAME 32
+#define CCHPAPERNAME 64
+
+/* current version of specification */
+#define DM_SPECVERSION 0x30A
+
+/* field selection bits */
+#define DM_ORIENTATION 0x0000001L
+#define DM_PAPERSIZE 0x0000002L
+#define DM_PAPERLENGTH 0x0000004L
+#define DM_PAPERWIDTH 0x0000008L
+#define DM_SCALE 0x0000010L
+#define DM_COPIES 0x0000100L
+#define DM_DEFAULTSOURCE 0x0000200L
+#define DM_PRINTQUALITY 0x0000400L
+#define DM_COLOR 0x0000800L
+#define DM_DUPLEX 0x0001000L
+#define DM_YRESOLUTION 0x0002000L
+#define DM_TTOPTION 0x0004000L
+
+/* orientation selections */
+#define DMORIENT_PORTRAIT 1
+#define DMORIENT_LANDSCAPE 2
+
+/* paper selections */
+/* Warning: The PostScript driver mistakingly uses DMPAPER_ values between
+ * 50 and 56. Don't use this range when defining new paper sizes.
+ */
+#define DMPAPER_FIRST DMPAPER_LETTER
+#define DMPAPER_LETTER 1 /* Letter 8 1/2 x 11 in */
+#define DMPAPER_LETTERSMALL 2 /* Letter Small 8 1/2 x 11 in */
+#define DMPAPER_TABLOID 3 /* Tabloid 11 x 17 in */
+#define DMPAPER_LEDGER 4 /* Ledger 17 x 11 in */
+#define DMPAPER_LEGAL 5 /* Legal 8 1/2 x 14 in */
+#define DMPAPER_STATEMENT 6 /* Statement 5 1/2 x 8 1/2 in */
+#define DMPAPER_EXECUTIVE 7 /* Executive 7 1/4 x 10 1/2 in */
+#define DMPAPER_A3 8 /* A3 297 x 420 mm */
+#define DMPAPER_A4 9 /* A4 210 x 297 mm */
+#define DMPAPER_A4SMALL 10 /* A4 Small 210 x 297 mm */
+#define DMPAPER_A5 11 /* A5 148 x 210 mm */
+#define DMPAPER_B4 12 /* B4 250 x 354 */
+#define DMPAPER_B5 13 /* B5 182 x 257 mm */
+#define DMPAPER_FOLIO 14 /* Folio 8 1/2 x 13 in */
+#define DMPAPER_QUARTO 15 /* Quarto 215 x 275 mm */
+#define DMPAPER_10X14 16 /* 10x14 in */
+#define DMPAPER_11X17 17 /* 11x17 in */
+#define DMPAPER_NOTE 18 /* Note 8 1/2 x 11 in */
+#define DMPAPER_ENV_9 19 /* Envelope #9 3 7/8 x 8 7/8 */
+#define DMPAPER_ENV_10 20 /* Envelope #10 4 1/8 x 9 1/2 */
+#define DMPAPER_ENV_11 21 /* Envelope #11 4 1/2 x 10 3/8 */
+#define DMPAPER_ENV_12 22 /* Envelope #12 4 \276 x 11 */
+#define DMPAPER_ENV_14 23 /* Envelope #14 5 x 11 1/2 */
+#define DMPAPER_CSHEET 24 /* C size sheet */
+#define DMPAPER_DSHEET 25 /* D size sheet */
+#define DMPAPER_ESHEET 26 /* E size sheet */
+#define DMPAPER_ENV_DL 27 /* Envelope DL 110 x 220mm */
+#define DMPAPER_ENV_C5 28 /* Envelope C5 162 x 229 mm */
+#define DMPAPER_ENV_C3 29 /* Envelope C3 324 x 458 mm */
+#define DMPAPER_ENV_C4 30 /* Envelope C4 229 x 324 mm */
+#define DMPAPER_ENV_C6 31 /* Envelope C6 114 x 162 mm */
+#define DMPAPER_ENV_C65 32 /* Envelope C65 114 x 229 mm */
+#define DMPAPER_ENV_B4 33 /* Envelope B4 250 x 353 mm */
+#define DMPAPER_ENV_B5 34 /* Envelope B5 176 x 250 mm */
+#define DMPAPER_ENV_B6 35 /* Envelope B6 176 x 125 mm */
+#define DMPAPER_ENV_ITALY 36 /* Envelope 110 x 230 mm */
+#define DMPAPER_ENV_MONARCH 37 /* Envelope Monarch 3.875 x 7.5 in */
+#define DMPAPER_ENV_PERSONAL 38 /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */
+#define DMPAPER_FANFOLD_US 39 /* US Std Fanfold 14 7/8 x 11 in */
+#define DMPAPER_FANFOLD_STD_GERMAN 40 /* German Std Fanfold 8 1/2 x 12 in */
+#define DMPAPER_FANFOLD_LGL_GERMAN 41 /* German Legal Fanfold 8 1/2 x 13 in */
+
+#define DMPAPER_LAST DMPAPER_FANFOLD_LGL_GERMAN
+
+#define DMPAPER_USER 256
+
+/* bin selections */
+#define DMBIN_FIRST DMBIN_UPPER
+#define DMBIN_UPPER 1
+#define DMBIN_ONLYONE 1
+#define DMBIN_LOWER 2
+#define DMBIN_MIDDLE 3
+#define DMBIN_MANUAL 4
+#define DMBIN_ENVELOPE 5
+#define DMBIN_ENVMANUAL 6
+#define DMBIN_AUTO 7
+#define DMBIN_TRACTOR 8
+#define DMBIN_SMALLFMT 9
+#define DMBIN_LARGEFMT 10
+#define DMBIN_LARGECAPACITY 11
+#define DMBIN_CASSETTE 14
+#define DMBIN_LAST DMBIN_CASSETTE
+
+#define DMBIN_USER 256 /* device specific bins start here */
+
+/* print qualities */
+#define DMRES_DRAFT (-1)
+#define DMRES_LOW (-2)
+#define DMRES_MEDIUM (-3)
+#define DMRES_HIGH (-4)
+
+/* color enable/disable for color printers */
+#define DMCOLOR_MONOCHROME 1
+#define DMCOLOR_COLOR 2
+
+/* duplex enable */
+#define DMDUP_SIMPLEX 1
+#define DMDUP_VERTICAL 2
+#define DMDUP_HORIZONTAL 3
+
+/* TrueType options */
+#define DMTT_BITMAP 1 /* print TT fonts as graphics */
+#define DMTT_DOWNLOAD 2 /* download TT fonts as soft fonts */
+#define DMTT_SUBDEV 3 /* substitute device fonts for TT fonts */
+
+typedef struct tagDEVMODE
+{
+ char dmDeviceName[CCHDEVICENAME];
+ UINT dmSpecVersion;
+ UINT dmDriverVersion;
+ UINT dmSize;
+ UINT dmDriverExtra;
+ DWORD dmFields;
+ int dmOrientation;
+ int dmPaperSize;
+ int dmPaperLength;
+ int dmPaperWidth;
+ int dmScale;
+ int dmCopies;
+ int dmDefaultSource;
+ int dmPrintQuality;
+ int dmColor;
+ int dmDuplex;
+ int dmYResolution;
+ int dmTTOption;
+} DEVMODE;
+
+typedef DEVMODE* PDEVMODE, NEAR* NPDEVMODE, FAR* LPDEVMODE;
+
+/* mode selections for the device mode function */
+#define DM_UPDATE 1
+#define DM_COPY 2
+#define DM_PROMPT 4
+#define DM_MODIFY 8
+
+#define DM_IN_BUFFER DM_MODIFY
+#define DM_IN_PROMPT DM_PROMPT
+#define DM_OUT_BUFFER DM_COPY
+#define DM_OUT_DEFAULT DM_UPDATE
+
+/* device capabilities indices */
+#define DC_FIELDS 1
+#define DC_PAPERS 2
+#define DC_PAPERSIZE 3
+#define DC_MINEXTENT 4
+#define DC_MAXEXTENT 5
+#define DC_BINS 6
+#define DC_DUPLEX 7
+#define DC_SIZE 8
+#define DC_EXTRA 9
+#define DC_VERSION 10
+#define DC_DRIVER 11
+#define DC_BINNAMES 12
+#define DC_ENUMRESOLUTIONS 13
+#define DC_FILEDEPENDENCIES 14
+#define DC_TRUETYPE 15
+#define DC_PAPERNAMES 16
+#define DC_ORIENTATION 17
+#define DC_COPIES 18
+
+/* bit fields of the return value (DWORD) for DC_TRUETYPE */
+#define DCTT_BITMAP 0x0000001L
+#define DCTT_DOWNLOAD 0x0000002L
+#define DCTT_SUBDEV 0x0000004L
+
+/* export ordinal definitions */
+#define PROC_EXTDEVICEMODE MAKEINTRESOURCE(90)
+#define PROC_DEVICECAPABILITIES MAKEINTRESOURCE(91)
+#define PROC_OLDDEVICEMODE MAKEINTRESOURCE(13)
+
+/* define types of pointers to ExtDeviceMode() and DeviceCapabilities()
+ * functions
+ */
+typedef UINT (CALLBACK* LPFNDEVMODE)(HWND, HMODULE, DEVMODE FAR*,
+ LPSTR, LPSTR, DEVMODE FAR*, LPSTR, UINT);
+
+typedef DWORD (CALLBACK* LPFNDEVCAPS)(LPSTR, LPSTR, UINT, LPSTR, DEVMODE FAR*);
+
+HDC WINAPI ResetDC(HDC, const DEVMODE FAR*);
+
+/* this structure is used by the GETSETSCREENPARAMS escape */
+typedef struct tagSCREENPARAMS
+{
+ int angle;
+ int frequency;
+} SCREENPARAMS;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_PRINT */
diff --git a/private/mvdm/wow16/inc/printer.h b/private/mvdm/wow16/inc/printer.h
new file mode 100644
index 000000000..8a34f5065
--- /dev/null
+++ b/private/mvdm/wow16/inc/printer.h
@@ -0,0 +1,258 @@
+/* printer.h
+ contains the definitions of the functions in _SORT,
+ _BRUTE, _SPOOL.
+*/
+
+#ifdef OLDWAY
+
+#define PASCAL
+#define LONG long
+#define NULL 0
+#define TRUE 1
+#define FALSE 0
+#define ERROR (-1)
+#define FAR far
+#define NEAR near
+#define VOID void
+#define REGISTER register
+
+
+/* file IO flags */
+
+#define O_RDONLY 0x0000
+#define O_WRONLY 0x0001
+#define O_RDWR 0x0002
+#define O_APPEND 0x0008 /* writes done at eof */
+
+#define OF_REOPEN 0x8000
+#define OF_EXIST 0x4000
+#define OF_PROMPT 0x2000
+#define OF_CREATE 0x1000
+#define OF_CANCEL 0x0800
+#define OF_VERIFY 0x0400
+#define OF_DELETE 0x0200
+
+#define O_TEXT 0x4000 /* file mode is text (translated) */
+#define O_BINARY 0x8000 /* file mode is binary (untranslated) */
+
+#define SP_CREATE O_WRONLY | OF_CREATE
+#define SP_OPEN O_RDONLY | OF_EXIST
+#define SP_REOPEN O_RDWR | OF_REOPEN | OF_PROMPT | OF_CANCEL
+
+typedef int (FAR * FARPROC)();
+typedef int (NEAR * NEARPROC)();
+typedef unsigned LONG DWORD;
+typedef DWORD (FAR * DWORDFARPROC)();
+typedef unsigned short int WORD;
+typedef unsigned char BYTE;
+typedef WORD HANDLE;
+typedef HANDLE HWND;
+typedef HANDLE HDC;
+typedef WORD ATOM;
+typedef int BOOLEAN;
+typedef char *NEARP;
+typedef char FAR *FARP;
+typedef HANDLE GLOBALHANDLE;
+typedef HANDLE LOCALHANDLE;
+typedef unsigned char *PSTR;
+typedef unsigned char far *LPSTR;
+typedef short BOOL;
+typedef long FAR *LPLONG;
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<=(b)?(a):(b))
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+#define LWORD(x) ((short)((x)&0xFFFF))
+#define HWORD(y) ((short)(((y)>>16)&0xFFFF))
+#define MAKELONG(h,l) ((long)(((WORD)l)|(((long)h)<<16)))
+#define LOBYTE(w) ((BYTE)w)
+#define HIBYTE(w) (((WORD)w >> 8) & 0xff)
+#define MAKEPOINT(l) (*((POINT *)&l))
+
+/* Interface to global memory manager */
+
+#define GMEM_SHAREALL 0x2000
+#define GMEM_FIXED 0x00
+#define GMEM_MOVEABLE 0x02
+#define GMEM_ZEROINIT 0x40
+#define GMEM_DISCARDABLE 0x0F00
+#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT)
+#define GPTR (GMEM_FIXED | GMEM_ZEROINIT)
+
+/* Interface to local memory manager */
+
+#define LMEM_FIXED 0x0000
+#define LMEM_MOVEABLE 0x0002
+#define LMEM_NOCOMPACT 0x0010
+#define LMEM_NODISCARD 0x0020
+#define LMEM_ZEROINIT 0x0040
+#define LMEM_MODIFY 0x0080
+#define LMEM_DISCARDABLE 0x0F00
+
+/* Exported procedures for KERNEL module */
+
+/* Spooler escapes */
+#define SE_JOBTIME 0x0001 /* time out for printer */
+#define SE_SETCALLBACK 0x0002 /* set callback function */
+#define SE_MARKCALLBACK 0x0003 /* write mark for call back */
+
+
+/* Exported procedures for KERNEL module */
+VOID far PASCAL FatalExit( int );
+
+HANDLE far PASCAL LoadModule(LPSTR, LPSTR);
+VOID far PASCAL FreeModule(HANDLE);
+HANDLE far PASCAL GetModuleHandle(FARP);
+FARPROC far PASCAL GetProcAddress(HANDLE, FARP);
+
+HANDLE far PASCAL GlobalAlloc( WORD, DWORD );
+HANDLE far PASCAL GlobalReAlloc( HANDLE, DWORD, WORD );
+HANDLE far PASCAL GlobalFree( HANDLE );
+FARP far PASCAL GlobalLock( HANDLE );
+BOOL far PASCAL GlobalUnlock( HANDLE );
+LONG far PASCAL GlobalSize( HANDLE );
+LONG far PASCAL GlobalFlags( HANDLE );
+
+/* task scheduler routines */
+
+extern void far PASCAL Yield(void);
+extern BOOL far PASCAL WaitEvent(HANDLE);
+extern BOOL far PASCAL PostEvent(HANDLE);
+extern HANDLE far PASCAL GetCurrentTask(void);
+
+short FAR PASCAL GetProfileString(LPSTR, LPSTR, LPSTR, LPSTR, short);
+BOOL FAR PASCAL WriteProfileString( LPSTR, LPSTR, LPSTR );
+
+/* Interface to the resource manager */
+
+HANDLE FAR PASCAL FindResource( HANDLE, LPSTR, LPSTR );
+HANDLE FAR PASCAL LoadResource( HANDLE, HANDLE );
+BOOL FAR PASCAL FreeResource( HANDLE );
+
+char FAR * FAR PASCAL LockResource( HANDLE );
+
+FARPROC FAR PASCAL SetResourceHandler( HANDLE, LPSTR, FARPROC );
+HANDLE FAR PASCAL AllocResource( HANDLE, HANDLE, DWORD );
+WORD FAR PASCAL SizeofResource( HANDLE, HANDLE );
+int FAR PASCAL AccessResource( HANDLE, HANDLE );
+
+
+#define WM_INITDIALOG 0x0110
+#define WM_COMMAND 0x0111
+#define WM_ENDDIALOG 0x0088
+#define WM_SPOOLERSTATUS 0x002a /* ;Internal */
+#define PR_JOBSTATUS 0x0000
+
+typedef struct
+{
+ BYTE cBytes; /* length of structure */
+ BYTE fFixedDisk; /* non-zero if file located on non- */
+ /* removeable media */
+ WORD nErrCode; /* DOS error code if OpenFile fails */
+ BYTE reserved[ 4 ];
+ BYTE szPathName[ 128 ];
+} OFSTRUCT;
+
+typedef OFSTRUCT FAR * LPOFSTRUCT;
+
+int FAR PASCAL OpenFile( LPSTR, LPOFSTRUCT, WORD );
+BYTE FAR PASCAL GetTempDrive( BYTE );
+int far PASCAL OpenPathname( LPSTR, int );
+int far PASCAL DeletePathname( LPSTR );
+int far PASCAL _lopen( LPSTR, int );
+void far PASCAL _lclose( int );
+int far PASCAL _lcreat( LPSTR, int );
+BOOL far PASCAL _ldelete( LPSTR );
+WORD far PASCAL _ldup( int );
+LONG far PASCAL _llseek( int, long, int );
+WORD far PASCAL _lread( int, LPSTR, int );
+WORD far PASCAL _lwrite( int, LPSTR, int );
+
+int far PASCAL lstrcmp( LPSTR, LPSTR );
+LPSTR far PASCAL lstrcpy( LPSTR, LPSTR );
+LPSTR far PASCAL lstrcat( LPSTR, LPSTR );
+int far PASCAL lstrlen( LPSTR );
+LPSTR far PASCAL lstrbscan( LPSTR, LPSTR );
+LPSTR far PASCAL lstrbskip( LPSTR, LPSTR );
+
+/* new Escape support */
+#define GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define EXTTEXTOUT 512
+
+#else
+
+#define NOATOM
+#define NOGDI
+#define NOGDICAPMASKS
+#define NOMETAFILE
+#define NOMSG
+#define NORASTEROPS
+#define NOSCROLL
+#define NOSOUND
+#define NOSYSMETRICS
+#define NOTEXTMETRIC
+#define NOWH
+#define NOCOMM
+#define NOKANJI
+
+#include "Windows.h"
+#include "winexp.h"
+
+#undef NOATOM
+#undef NOGDI
+#undef NOGDICAPMASKS
+#undef NOMETAFILE
+#undef NOMSG
+#undef NORASTEROPS
+#undef NOSCROLL
+#undef NOSOUND
+#undef NOSYSMETRICS
+#undef NOTEXTMETRIC
+#undef NOWH
+#undef NOCOMM
+#undef NOKANJI
+
+#define NOPTRC /* don't allow gdidefs.inc to redef these */
+#define PTTYPE POINT
+
+#endif /* OLDWAY */
+
+/* GDI internal routines */
+
+short FAR PASCAL SetEnvironment(LPSTR, LPSTR, WORD);
+short FAR PASCAL GetEnvironment(LPSTR, LPSTR, WORD);
+
+/* _SORT export routines */
+
+HANDLE FAR PASCAL CreatePQ(short);
+short FAR PASCAL MinPQ(HANDLE);
+short FAR PASCAL ExtractPQ(HANDLE);
+short FAR PASCAL InsertPQ(HANDLE, short, short);
+short FAR PASCAL SizePQ(HANDLE, short);
+void FAR PASCAL DeletePQ(HANDLE);
+
+/* _SPOOL export routines */
+
+HANDLE FAR PASCAL OpenJob(LPSTR, LPSTR, HANDLE);
+short FAR PASCAL StartSpoolPage(HANDLE);
+short FAR PASCAL EndSpoolPage(HANDLE);
+short FAR PASCAL WriteSpool(HANDLE, LPSTR, short);
+short FAR PASCAL CloseJob(HANDLE);
+short FAR PASCAL DeleteJob(HANDLE, short);
+short FAR PASCAL WriteDialog(HANDLE, LPSTR, short);
+short FAR PASCAL WriteMark(HANDLE, LPSTR, short);
+BOOL FAR PASCAL AddFileSpoolJob(LPSTR, LPSTR, BOOL, LPSTR);
+BOOL FAR PASCAL SpoolEscape(HANDLE, short, short, LPSTR, LPSTR);
+
+
+long FAR PASCAL QueryJob(HANDLE, short);
+short FAR PASCAL QueryAbort(HANDLE, short);
+
+/* _SPOOL constants for queryjob */
+#define SP_QUERYVALIDJOB 30
+#define SP_QUERYDISKAVAIL 0x1004
+
+#define USA_COUNTRYCODE 1
+
+#define PQERROR (-1)
diff --git a/private/mvdm/wow16/inc/rom.inc b/private/mvdm/wow16/inc/rom.inc
new file mode 100644
index 000000000..ee4cb8297
--- /dev/null
+++ b/private/mvdm/wow16/inc/rom.inc
@@ -0,0 +1,50 @@
+; ROM Windows specific include file
+
+;
+; INT 2F subfunction
+; if ROM installed, returns 0 in AX and RM segment of ROMTOC in
+; BX. Hooked by WIN.COM to pass ROMTOC to other components
+;
+ROMINSTALLCHECK equ 160Ch
+
+; ROM Table of Contents structure
+
+ROMTOC STRUC
+ROMSignature db 55h, 0AAh ; IBM standard ROM signature
+ROMLength db ? ; IBM length (/512)
+ROMEntryPoint db 5 dup (?) ; jmp near + retf + pad
+szID db 10 dup (?) ; ID string "ROMWINTOC\0"
+DOSX_CSIP dd ? ; DOSX initial CS:IP (seg:off)
+KRNL_CSIP dd ? ; Kernel initial CS:IP (sel:off)
+lmaROMLDT dd ? ; lma of ROM prototype LDT
+cROMsels dw ? ; # descriptors used in ROM proto LDT
+FirstROMsel dw ? ; first LDT selector in ROM proto LDT
+offSysDir dw ? ; offset to system directory string
+lmaHigh dd ? ; lma of high ROM
+lenHigh dd ? ; length in bytes of High ROM
+cModules dw ? ; # modules defined in ROM TOC
+cFiles dw ? ; # files defined in ROM TOC
+ModEntries db ? ; start of module entries
+
+; module entries follow at this point...
+; file entries start at ModEntries + cModules*(SIZE MODENT)
+
+ROMTOC ENDS
+
+
+; Module entry format in ROM TOC
+
+File_Name_Len = 13
+Module_Name_Len = 9
+
+MODENT STRUC
+ModNameStr db Module_Name_Len dup (?) ; Module name (null padded)
+FileNameStr db File_Name_Len dup (?) ; File name (null padded)
+lmaExeHdr dd ? ; lma of module EXE header
+MODENT ENDS
+
+FILENT STRUC
+fname db File_Name_Len dup(?) ; file name
+lma dd ? ; lma of start of file
+fsize dd ?
+FILENT ENDS
diff --git a/private/mvdm/wow16/inc/shellapi.h b/private/mvdm/wow16/inc/shellapi.h
new file mode 100644
index 000000000..4c5af9991
--- /dev/null
+++ b/private/mvdm/wow16/inc/shellapi.h
@@ -0,0 +1,99 @@
+/*****************************************************************************\
+* *
+* shellapi.h - SHELL.DLL functions, types, and definitions *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_SHELLAPI
+#define _INC_SHELLAPI
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/* If included with Windows 3.0 windows.h: define 3.1-compatible types */
+
+#ifndef _INC_WINDOWS
+
+#define HDROP HANDLE
+#define WINAPI FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+
+#else
+
+DECLARE_HANDLE(HDROP);
+
+#endif
+
+/* return codes from Registration functions */
+#define ERROR_SUCCESS 0L
+#define ERROR_BADDB 1L
+#define ERROR_BADKEY 2L
+#define ERROR_CANTOPEN 3L
+#define ERROR_CANTREAD 4L
+#define ERROR_CANTWRITE 5L
+#define ERROR_OUTOFMEMORY 6L
+#define ERROR_INVALID_PARAMETER 7L
+#define ERROR_ACCESS_DENIED 8L
+
+#define REG_SZ 1 /* string type */
+
+#define HKEY_CLASSES_ROOT 0x80000000
+
+typedef DWORD HKEY;
+typedef HKEY FAR* PHKEY;
+ /* ;Internal */
+typedef struct _dropfilestruct { /* ;Internal */
+ WORD pFiles; /* offset of file list*//* ;Internal */
+ POINT pt; /* drop point *//* ;Internal */
+ BOOL fNC; /* is it on NC area *//* ;Internal */
+} DROPFILESTRUCT, FAR* LPDROPFILESTRUCT; /* ;Internal */
+
+LONG WINAPI RegOpenKey(HKEY, LPCSTR, HKEY FAR*);
+LONG WINAPI RegCreateKey(HKEY, LPCSTR, HKEY FAR*);
+LONG WINAPI RegCloseKey(HKEY);
+LONG WINAPI RegDeleteKey(HKEY, LPCSTR);
+LONG WINAPI RegSetValue(HKEY, LPCSTR, DWORD, LPCSTR, DWORD);
+LONG WINAPI RegQueryValue(HKEY, LPCSTR, LPSTR, LONG FAR*);
+LONG WINAPI RegEnumKey(HKEY, DWORD, LPSTR, DWORD);
+
+UINT WINAPI DragQueryFile(HDROP, UINT, LPSTR, UINT);
+BOOL WINAPI DragQueryPoint(HDROP, POINT FAR*);
+void WINAPI DragFinish(HDROP);
+void WINAPI DragAcceptFiles(HWND, BOOL);
+
+HICON WINAPI ExtractIcon(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex);
+
+/* error values for ShellExecute() beyond the regular WinExec() codes */
+#define SE_ERR_SHARE 26
+#define SE_ERR_ASSOCINCOMPLETE 27
+#define SE_ERR_DDETIMEOUT 28
+#define SE_ERR_DDEFAIL 29
+#define SE_ERR_DDEBUSY 30
+#define SE_ERR_NOASSOC 31
+
+HINSTANCE WINAPI ShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int iShowCmd);
+HINSTANCE WINAPI FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult);
+
+int WINAPI ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon); /* ;Internal */
+HICON WINAPI ExtractAssociatedIcon(HANDLE hInst, LPSTR lpIconPath, WORD FAR* lpiIcon); /* ;Internal */
+HICON WINAPI InternalExtractIcon(HANDLE hInst, LPCSTR lpszExeFileName, WORD nIconIndex, WORD nIcons); /* ;Internal */
+DWORD WINAPI DoEnvironmentSubst(LPSTR szString, WORD cbString); /* ;Internal */
+BOOL WINAPI RegisterShellHook(HWND, BOOL); /* ;Internal */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_SHELLAPI */
diff --git a/private/mvdm/wow16/inc/spl_wnt.h b/private/mvdm/wow16/inc/spl_wnt.h
new file mode 100644
index 000000000..f227c97d7
--- /dev/null
+++ b/private/mvdm/wow16/inc/spl_wnt.h
@@ -0,0 +1,248 @@
+/*****************************************************************/
+/** Microsoft Windows for Workgroups **/
+/** Copyright (C) Microsoft Corp., 1991-1992 **/
+/*****************************************************************/
+
+#ifndef _spl_wnt_h_
+#define _spl_wnt_h_
+
+/*
+ * Print Manager Administration APIs
+ * for later inclusion into WINNET.H once they settle down
+ *
+ * JONN 4/19/91 Trimmed out unnecessary stuff
+ * JONN 5/3/91 Added type WNETERR
+ */
+
+
+/*
+ Codes for WNetPrintMgrSelNotify's "type" variable, indicating
+ what's selected: a queue, a job, or nothing.
+*/
+
+#define WNPMSEL_NOTHING 0
+#define WNPMSEL_QUEUE 1
+#define WNPMSEL_JOB 2
+
+#define PRIORITY 10 /* menu uses 10, 11, 12, 13 */
+#define ABOUT 24
+#define EXIT 25
+#define PRINT_LOG 28
+#define NETWORK 29
+#define HELP_NDEX 30
+#define HELP_MOUSE 31
+#define HELP_KEYBOARD 32
+#define HELP_HELP 33
+#define HELP_COMMANDS 34
+#define HELP_PROCEDURES 35
+
+#define SHOW_TIME 51
+#define SHOW_SIZE 52
+#define SHOW_DETAIL 53
+#define UPDATE 54
+#define SHOW_LOCAL 55
+#define SHOW_NET 56
+#define SHOW_QUEUE 57
+#define SHOW_OTHER 58
+
+#define ALERT_ALWAYS 100
+#define ALERT_FLASH 101
+#define ALERT_IGNORE 102
+
+#define PRT_SETUP 8001 // These have to match the stuff in control
+#define NETWK_CONNECTIONS 8021 // panel
+
+#define PM_REFRESH WM_USER + 100 // BUGBUG: Need to define proper manifest
+#define PM_SELQUEUE WM_USER + 101
+#define PM_QUERYSEL WM_USER + 102
+
+typedef struct _wnpmsel { /* structure returned by PM_QUERYSEL */
+ WORD wJobID;
+ char szQueueName [260]; /* in the form "LPT1\0HP LaserJet III\0" */
+} WNPMSEL, far *LPWNPMSEL;
+
+#define IDM_PROPERTIES 202
+#define IDM_CHANGE_MENUS 212
+
+/*
+ * added JONN 2/26/91
+ * Print Manager Extensions
+ */
+
+typedef struct _queuestruct2
+{
+ WORD pq2Name; /* offset to queue name */
+ /* in the form "LPT1\0HP LaserJet III\0" */
+ WORD pq2Comment; /* offset to queue comment */
+ WORD pq2Driver; /* offset to driver name */
+ WORD pq2Status; /* status flags */
+ WORD pq2Jobcount; /* number of jobs in this queue */
+ WORD pq2Flags; /* miscellaneous flags */
+
+} QUEUESTRUCT2, FAR *LPQS2;
+
+#define QNAME(buf,qs) ((LPSTR)(buf) + (qs).pq2Name)
+#define QCOMMENT(buf,qs) ((LPSTR)(buf) + (qs).pq2Comment)
+#define QDRIVER(buf,qs) ((LPSTR)(buf) + (qs).pq2Driver)
+
+#define QF_REDIRECTED 0x0001
+#define QF_SHARED 0x0002
+
+typedef struct _jobstruct2 {
+ WORD pj2Id; // job ID
+ WORD pj2Username; // name of owner (offset to string)
+// WORD pj2Parms;
+ WORD pj2Position; // 0-based position in queue
+ WORD pj2Status; // status flags (WNPRJ_XXXXX)
+ DWORD pj2Submitted;
+ DWORD pj2Size; // size of job in bytes
+ DWORD pj2SubmitSize; // bytes submitted so far
+// WORD pj2Copies;
+ WORD pj2Comment; // comment/app name (offset to string)
+ WORD pj2Document; // document name (offset to string)
+ WORD pj2StatusText; // verbose status (offset to string)
+ WORD pj2PrinterName; // name of port job is printing on (offs to str)
+} JOBSTRUCT2;
+
+typedef JOBSTRUCT2 far * LPJOBSTRUCT2;
+
+#define JOBNAME(buf,job) ((LPSTR)(buf) + (job).pj2Username)
+#define JOBCOMMENT(buf,job) ((LPSTR)(buf) + (job).pj2Comment)
+#define JOBDOCUMENT(buf,job) ((LPSTR)(buf) + (job).pj2Document)
+#define JOBSTATUS(buf,job) ((LPSTR)(buf) + (job).pj2StatusText)
+#define JOBPRINTER(buf,job) ((LPSTR)(buf) + (job).pj2PrinterName)
+
+/*
+ * Type WNETERR distinguishes WN_ error codes from other WORD
+ * values. Added JONN 5/3/91
+ */
+typedef WORD WNETERR;
+
+// new Print Manager Extensions APIs
+/* All queue names are in the form "LPT1\0HP LaserJet III\0" */
+#ifdef C700
+extern void far pascal __loadds WNetPrintMgrSelNotify (BYTE, LPQS2, LPQS2,
+ LPJOBSTRUCT2, LPJOBSTRUCT2, LPWORD, LPSTR, WORD);
+extern WNETERR far pascal __loadds WNetPrintMgrPrinterEnum (LPSTR lpszQueueName,
+ LPSTR lpBuffer, LPWORD pcbBuffer, LPWORD cAvail, WORD usLevel);
+extern WNETERR far pascal __loadds WNetPrintMgrChangeMenus(HWND, HANDLE FAR *, BOOL FAR *);
+extern WNETERR far pascal __loadds WNetPrintMgrCommand (HWND, WORD);
+extern void far pascal __loadds WNetPrintMgrExiting (void);
+extern BOOL far pascal __loadds WNetPrintMgrExtHelp (DWORD);
+extern WORD far pascal __loadds WNetPrintMgrMoveJob (HWND, LPSTR, WORD, int);
+#else
+extern void API WNetPrintMgrSelNotify (BYTE, LPQS2, LPQS2,
+ LPJOBSTRUCT2, LPJOBSTRUCT2,
+ LPWORD, LPSTR, WORD);
+extern WNETERR API WNetPrintMgrPrinterEnum (LPSTR lpszQueueName,
+ LPSTR lpBuffer, LPWORD pcbBuffer,
+ LPWORD cAvail, WORD usLevel);
+extern WNETERR API WNetPrintMgrChangeMenus(HWND, HANDLE FAR *, BOOL FAR *);
+extern WNETERR API WNetPrintMgrCommand (HWND, WORD);
+extern void API WNetPrintMgrExiting (void);
+extern BOOL API WNetPrintMgrExtHelp (DWORD);
+extern WORD API WNetPrintMgrMoveJob (HWND, LPSTR, WORD, int);
+#endif
+
+
+#define WINBALL
+#ifdef WINBALL
+#define WNNC_PRINTMGRNOTIFY 0x000C
+#ifdef C700
+extern void far pascal __loadds WNetPrintMgrStatusChange (LPSTR lpszQueueName,
+ LPSTR lpszPortName, WORD wQueueStatus, WORD cJobsLeft, HANDLE hJCB,
+ BOOL fDeleted);
+#else
+extern void API WNetPrintMgrStatusChange (LPSTR lpszQueueName,
+ LPSTR lpszPortName,
+ WORD wQueueStatus,
+ WORD cJobsLeft,
+ HANDLE hJCB,
+ BOOL fDeleted);
+#endif
+
+#define PM_QUERYQDATA WM_USER + 104
+
+typedef struct _PMQUEUE {
+ WORD dchPortName; /* offset to port name string */
+ WORD dchPrinterName; /* offset to printer name string */
+ WORD dchRemoteName; /* offset to remote name string */
+ WORD cJobs; /* count of jobs */
+ WORD fwStatus; /* queue status */
+} PMQUEUE, FAR *LPPMQUEUE;
+
+#define PMQPORTNAME(buf,queue) ((LPSTR)(buf) + (queue).dchPortName)
+#define PMQPRINTERNAME(buf,queue) ((LPSTR)(buf) + (queue).dchPrinterName)
+#define PMQREMOTENAME(buf,queue) ((LPSTR)(buf) + (queue).dchRemoteName)
+
+typedef struct _PMJOB {
+ DWORD dwTime; /* date/time job was spooled */
+ DWORD cbJob; /* job size in bytes */
+ DWORD cbSubmitted; /* bytes submitted so far */
+ WORD dchJobName; /* offset to job name (doc name) string */
+ HANDLE hJCB; /* hJCB to refer to the job */
+} PMJOB, FAR *LPPMJOB;
+
+#define PMJOBNAME(buf,job) ((LPSTR)(buf) + (job).dchJobName)
+
+
+#endif
+
+// new values for WNetGetCaps()
+#define WNNC_PRINTMGREXT 0x000B
+// returns extensions version number, re: GetVersion(),
+// or 0 if not supported
+
+// QUEUESTRUCT2.pq2Status and .pq2Jobcount for WNetPrintMgrPrinterEnum[2]
+#define WNQ_UNKNOWN -1
+
+#define WNPRS_CANPAUSE 0x0001
+#define WNPRS_CANRESUME 0x0002
+#define WNPRS_CANDELETE 0x0004
+#define WNPRS_CANMOVE 0x0008
+#define WNPRS_CANDISCONNECT 0x0010
+#define WNPRS_CANSTOPSHARE 0x0020
+#define WNPRS_ISPAUSED 0x0040
+#define WNPRS_ISRESUMED 0x0080
+
+// help contexts, were previously in sphelp.h
+#define IDH_HELPFIRST 5000
+#define IDH_SYSMENU (IDH_HELPFIRST + 2000)
+#define IDH_MBFIRST (IDH_HELPFIRST + 2001)
+#define IDH_MBLAST (IDH_HELPFIRST + 2099)
+#define IDH_DLGFIRST (IDH_HELPFIRST + 3000)
+
+
+#define IDH_PRIORITY (IDH_HELPFIRST + PRIORITY )
+#define IDH_PRIORITY1 (IDH_HELPFIRST + PRIORITY + 1)
+#define IDH_PRIORITY2 (IDH_HELPFIRST + PRIORITY + 2)
+#define IDH_ABOUT (IDH_HELPFIRST + ABOUT )
+#define IDH_EXIT (IDH_HELPFIRST + EXIT)
+#define IDH_NETWORK (IDH_HELPFIRST + NETWORK)
+#define IDH_HELP_NDEX (IDH_HELPFIRST + HELP_NDEX)
+#define IDH_HELP_MOUSE (IDH_HELPFIRST + HELP_MOUSE)
+#define IDH_HELP_KEYBOARD (IDH_HELPFIRST + HELP_KEYBOARD)
+#define IDH_HELP_HELP (IDH_HELPFIRST + HELP_HELP)
+#define IDH_HELP_COMMANDS (IDH_HELPFIRST + HELP_COMMANDS)
+#define IDH_HELP_PROCEDURES (IDH_HELPFIRST + HELP_PROCEDURES)
+#define IDH_SHOW_TIME (IDH_HELPFIRST + SHOW_TIME)
+#define IDH_SHOW_SIZE (IDH_HELPFIRST + SHOW_SIZE)
+#define IDH_UPDATE (IDH_HELPFIRST + UPDATE)
+#define IDH_SHOW_QUEUE (IDH_HELPFIRST + SHOW_QUEUE)
+#define IDH_SHOW_OTHER (IDH_HELPFIRST + SHOW_OTHER)
+#define IDH_ALERT_ALWAYS (IDH_HELPFIRST + ALERT_ALWAYS)
+#define IDH_ALERT_FLASH (IDH_HELPFIRST + ALERT_FLASH)
+#define IDH_ALERT_IGNORE (IDH_HELPFIRST + ALERT_IGNORE)
+
+
+// was in spoolids.h
+
+#define IDS_A_BASE 4096
+
+/* also used as button IDs */
+#define ID_ABORT 4
+#define ID_PAUSE 2
+#define ID_RESUME 3
+#define ID_EXPLAIN 5
+
+#endif /* _spl_wnt_h_ */
diff --git a/private/mvdm/wow16/inc/spool.h b/private/mvdm/wow16/inc/spool.h
new file mode 100644
index 000000000..f600010dc
--- /dev/null
+++ b/private/mvdm/wow16/inc/spool.h
@@ -0,0 +1,175 @@
+#ifndef WINAPI
+#ifdef BUILDDLL /* ;Internal */
+#define WINAPI _loadds far pascal /* ;Internal */
+#define CALLBACK _loadds far pascal /* ;Internal */
+#else /* ;Internal */
+#define WINAPI far pascal
+#define CALLBACK far pascal
+#endif /* ;Internal */
+#endif
+
+#define LWORD(x) ((int)((x)&0xFFFF))
+
+
+/* spooler error code */
+#define SP_ERROR (-1) /* general error - mostly used when spooler isn't loaded */
+#define SP_APPABORT (-2) /* app aborted the job through the driver */
+#define SP_USERABORT (-3) /* user aborted the job through spooler's front end */
+#define SP_OUTOFDISK (-4) /* simply no disk to spool */
+#define SP_OUTOFMEMORY (-5)
+#define SP_RETRY (-6) /* retry sending to the port again */
+#define SP_NOTREPORTED 0x4000 /* set if GDI did not report error */
+
+/* subfunctions of the Spooler support function, GetSpoolJob()
+ * CP_* are used by the control panel for modifying the printer setup/
+ */
+#define SP_PRINTERNAME 20
+#define SP_REGISTER 21
+#define SP_CONNECTEDPORTCNT 25
+#define SP_QUERYDISKUSAGE 26
+#define SP_DISKFREED 27
+#define SP_INIT 28
+#define SP_LISTEDPORTCNT 29
+#define CP_ISPORTFREE 30
+#define CP_REINIT 31
+#define SP_TXTIMEOUT 32
+#define SP_DNSTIMEOUT 33
+#define CP_CHECKSPOOLER 34
+#define CP_SET_TT_ONLY 35
+#define CP_SETSPOOLER 36
+#define CP_SETDOSPRINT 37
+
+
+#define SP_DISK_BUFFER (20000) /* wait for about 20 K of disk space to free
+ free up before attempting to write to disk */
+
+/* messages posted or sent to the spooler window
+ */
+#define SP_NEWJOB 0x1001
+#define SP_DELETEJOB 0x1002
+#define SP_DISKNEEDED 0x1003
+#define SP_QUERYDISKAVAIL 0x1004
+#define SP_ISPORTFREE 0x1005
+#define SP_CHANGEPORT 0x1006
+
+/* in /windows/oem/printer.h */
+
+
+/* job status flag bits in the type field of the JCB structure
+ */
+#define JB_ENDDOC 0x0001
+#define JB_INVALIDDOC 0x0002
+#define JB_DIRECT_SPOOL 0x8000 /* go directly to the printer without the spooler */
+#define JB_FILE_PORT 0x4000 /* were given a file for a port name */
+#define JB_VALID_SPOOL 0x2000 /* everything is cool, continue to spool normally */
+#define JB_NOTIFIED_SPOOLER 0x1000 /* already notified the spooler of this job */
+#define JB_WAITFORDISK 0x0800 /* out of disk condition has been detected previously */
+#define JB_DEL_FILE 0x0400 /* no deletion of file after spool */
+#define JB_FILE_SPOOL 0x0200 /* spooling a file */
+#define JB_NET_SPOOL 0x0100 /* sending directly to network */
+
+/* allow 2 dialog box messages initially and increment 8 at a time */
+#define SP_DLGINC 8
+#define SP_DLGINIT 8
+
+#define NAME_LEN 32
+#define BUF_SIZE 128
+#define MAX_PROFILE 80
+#define JCBBUF_LEN 256
+
+#define lower(c) ((c > 'A' && c < 'Z') ? (c - 'A' + 'a') : c)
+
+#define IDS_LENGTH 60
+
+/* comm driver stuff */
+#define COMM_INQUE 0x010 /* wm091385 */
+#define COMM_OUTQUE 0x030 /* wm091385 */
+#define COMM_OUTQUEPMODE 0x400 /* New size for pmode */
+
+#define COMM_ERR_BIT 0x8000
+#define TXTIMEOUT 45000 /* milliseconds */
+#define DNSTIMEOUT 15000 /* milliseconds */
+
+#define BAUDRATE 0
+#define PARITY 1
+#define BYTESIZE 2
+#define STOPBITS 3
+#define REPEAT 4
+
+
+typedef struct {
+ int type; /* type of dialog. This will tell whether it is */
+ /* call back function or pure dialog etc */
+ int size; /* size of special function data */
+ int adr;
+}DIALOGMARK;
+
+#define SP_TEXT 0 /* text type */
+#define SP_NOTTEXT 1 /* not text type */
+#define SP_DIALOG 2 /* dialog type data */
+#define SP_CALLBACK 3 /* call back type function */
+
+#define MAXPORTLIST 20 /* max # ports listed in win.ini [ports] */
+#define MAXPORT MAXPORTLIST
+#define MAXSPOOL 100 /* max # jobs spooled per port */
+#define MAXMAP 18
+#define PORTINDENT 2
+#define JOBINDENT 3
+#define MAXPAGE 7 /* allow 7 pages at first */
+#define INC_PAGE 8 /* increase by 8 pages at a time */
+
+typedef struct {
+ int pnum;
+ int printeratom;
+ long txtimeout;
+ long dnstimeout;
+}JCBQ;
+
+typedef struct jcb {
+ unsigned type;
+ int pagecnt;
+ int maxpage;
+ int portnum;
+ HDC hDC;
+ int chBuf;
+ long timeSpooled;
+ char buffer[JCBBUF_LEN];
+ unsigned long size;
+ unsigned long iLastPage;
+ WORD psp; // the PSP of the app that started printing
+ char jobName[NAME_LEN];
+ int page[MAXPAGE];
+}JCB;
+
+typedef struct page {
+ int filenum;
+ unsigned maxdlg; /* max number of dialog */
+ unsigned dlgptr; /* number of dialogs */
+ long spoolsize;
+ OFSTRUCT fileBuf;
+ DIALOGMARK dialog[SP_DLGINIT];
+}PAGE;
+
+#define SP_COMM_PORT 0
+#define SP_FILE_PORT 1
+#define SP_REMOTE_QUEUE 2
+#define SP_QUERYVALIDJOB 30
+
+
+typedef struct
+{
+ int type;
+ int fn;
+ long retry; /* system timer on first error */
+} PORT;
+
+
+/* exported routines */
+BOOL WINAPI QueryJob(HANDLE, int);
+BOOL WINAPI QueryAbort(HANDLE, int);
+
+int WINAPI WriteDialog(HANDLE hJCB, LPSTR str, int n);
+int WINAPI WriteSpool(HANDLE hJCB, LPSTR str, int n);
+
+LONG WINAPI GetSpoolJob(int, long);
+char WINAPI GetSpoolTempDrive(void);
diff --git a/private/mvdm/wow16/inc/stdarg.h b/private/mvdm/wow16/inc/stdarg.h
new file mode 100644
index 000000000..0bad49596
--- /dev/null
+++ b/private/mvdm/wow16/inc/stdarg.h
@@ -0,0 +1,42 @@
+/***
+*stdarg.h - defines ANSI-style macros for variable argument functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines ANSI-style macros for accessing arguments
+* of functions which take a variable number of arguments.
+* [ANSI]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#if (_MSC_VER >= 600)
+#define NULL ((void *)0)
+#elif (defined(M_I86SM) || defined(M_I86MM))
+#define NULL 0
+#else
+#define NULL 0L
+#endif
+#endif
+
+#ifndef _VA_LIST_DEFINED
+typedef char _FAR_ *va_list;
+#define _VA_LIST_DEFINED
+#endif
+
+#define va_start(ap,v) ap = (va_list)&v + sizeof(v)
+#define va_arg(ap,t) ((t _FAR_ *)(ap += sizeof(t)))[-1]
+#define va_end(ap) ap = NULL
diff --git a/private/mvdm/wow16/inc/stdio.h b/private/mvdm/wow16/inc/stdio.h
new file mode 100644
index 000000000..cedc1195e
--- /dev/null
+++ b/private/mvdm/wow16/inc/stdio.h
@@ -0,0 +1,254 @@
+/***
+*stdio.h - definitions/declarations for standard I/O routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the structures, values, macros, and functions
+* used by the level 2 I/O ("standard I/O") routines.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+#ifndef _VA_LIST_DEFINED
+typedef char _FAR_ *va_list;
+#define _VA_LIST_DEFINED
+#endif
+
+/* buffered I/O macros */
+
+#define BUFSIZ 512
+#ifdef _MT
+#define _NFILE 40
+#else
+#define _NFILE 20
+#endif
+#define EOF (-1)
+
+#ifndef _FILE_DEFINED
+struct _iobuf {
+ char _FAR_ *_ptr;
+ int _cnt;
+ char _FAR_ *_base;
+ char _flag;
+ char _file;
+ };
+typedef struct _iobuf FILE;
+#define _FILE_DEFINED
+#endif
+
+
+/* P_tmpnam: Directory where temporary files may be created.
+ * L_tmpnam size = size of P_tmpdir
+ * + 1 (in case P_tmpdir does not end in "\\")
+ * + 6 (for the temp number string)
+ * + 1 (for the null terminator)
+ */
+
+#define P_tmpdir "\\"
+#define L_tmpnam sizeof(P_tmpdir)+8
+
+
+/* fseek constants */
+
+#define SEEK_CUR 1
+#define SEEK_END 2
+#define SEEK_SET 0
+
+
+/* minimum guaranteed filename length, open file count, and unique
+ * tmpnam filenames.
+ */
+
+#define FILENAME_MAX 63
+#define FOPEN_MAX 20
+#define SYS_OPEN 20
+#define TMP_MAX 32767
+
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#if (_MSC_VER >= 600)
+#define NULL ((void *)0)
+#elif (defined(M_I86SM) || defined(M_I86MM))
+#define NULL 0
+#else
+#define NULL 0L
+#endif
+#endif
+
+
+/* declare _iob[] array */
+
+#ifndef _STDIO_DEFINED
+#ifdef _DLL
+extern FILE _FAR_ _cdecl _iob[];
+#else
+extern FILE _near _cdecl _iob[];
+#endif
+#endif
+
+
+/* define file position type */
+
+#ifndef _FPOS_T_DEFINED
+typedef long fpos_t;
+#define _FPOS_T_DEFINED
+#endif
+
+
+/* standard file pointers */
+
+#ifndef _WINDOWS
+#define stdin (&_iob[0])
+#define stdout (&_iob[1])
+#define stderr (&_iob[2])
+#define stdaux (&_iob[3])
+#define stdprn (&_iob[4])
+#endif
+
+
+#define _IOREAD 0x01
+#define _IOWRT 0x02
+
+#define _IOFBF 0x0
+#define _IOLBF 0x40
+#define _IONBF 0x04
+
+#define _IOMYBUF 0x08
+#define _IOEOF 0x10
+#define _IOERR 0x20
+#define _IOSTRG 0x40
+#define _IORW 0x80
+
+
+/* function prototypes */
+
+#ifndef _STDIO_DEFINED
+int _FAR_ _cdecl _filbuf(FILE _FAR_ *);
+int _FAR_ _cdecl _flsbuf(int, FILE _FAR_ *);
+FILE _FAR_ * _FAR_ _cdecl _fsopen(const char _FAR_ *,
+ const char _FAR_ *, int);
+void _FAR_ _cdecl clearerr(FILE _FAR_ *);
+int _FAR_ _cdecl fclose(FILE _FAR_ *);
+int _FAR_ _cdecl fcloseall(void);
+FILE _FAR_ * _FAR_ _cdecl fdopen(int, const char _FAR_ *);
+int _FAR_ _cdecl feof(FILE _FAR_ *);
+int _FAR_ _cdecl ferror(FILE _FAR_ *);
+int _FAR_ _cdecl fflush(FILE _FAR_ *);
+int _FAR_ _cdecl fgetc(FILE _FAR_ *);
+#ifndef _WINDOWS
+int _FAR_ _cdecl fgetchar(void);
+#endif
+int _FAR_ _cdecl fgetpos(FILE _FAR_ *, fpos_t _FAR_ *);
+char _FAR_ * _FAR_ _cdecl fgets(char _FAR_ *, int, FILE _FAR_ *);
+int _FAR_ _cdecl fileno(FILE _FAR_ *);
+int _FAR_ _cdecl flushall(void);
+FILE _FAR_ * _FAR_ _cdecl fopen(const char _FAR_ *,
+ const char _FAR_ *);
+#ifndef _WINDLL
+int _FAR_ _cdecl fprintf(FILE _FAR_ *, const char _FAR_ *, ...);
+#endif
+int _FAR_ _cdecl fputc(int, FILE _FAR_ *);
+#ifndef _WINDOWS
+int _FAR_ _cdecl fputchar(int);
+#endif
+int _FAR_ _cdecl fputs(const char _FAR_ *, FILE _FAR_ *);
+size_t _FAR_ _cdecl fread(void _FAR_ *, size_t, size_t, FILE _FAR_ *);
+FILE _FAR_ * _FAR_ _cdecl freopen(const char _FAR_ *,
+ const char _FAR_ *, FILE _FAR_ *);
+#ifndef _WINDLL
+int _FAR_ _cdecl fscanf(FILE _FAR_ *, const char _FAR_ *, ...);
+#endif
+int _FAR_ _cdecl fsetpos(FILE _FAR_ *, const fpos_t _FAR_ *);
+int _FAR_ _cdecl fseek(FILE _FAR_ *, long, int);
+long _FAR_ _cdecl ftell(FILE _FAR_ *);
+size_t _FAR_ _cdecl fwrite(const void _FAR_ *, size_t, size_t,
+ FILE _FAR_ *);
+int _FAR_ _cdecl getc(FILE _FAR_ *);
+#ifndef _WINDOWS
+int _FAR_ _cdecl getchar(void);
+char _FAR_ * _FAR_ _cdecl gets(char _FAR_ *);
+#endif
+int _FAR_ _cdecl getw(FILE _FAR_ *);
+#ifndef _WINDOWS
+void _FAR_ _cdecl perror(const char _FAR_ *);
+#endif
+int _FAR_ _cdecl _pclose(FILE _FAR_ *);
+FILE _FAR_ * _FAR_ _cdecl _popen(const char _FAR_ *,
+ const char _FAR_ *);
+#ifndef _WINDOWS
+int _FAR_ _cdecl printf(const char _FAR_ *, ...);
+#endif
+int _FAR_ _cdecl putc(int, FILE _FAR_ *);
+#ifndef _WINDOWS
+int _FAR_ _cdecl putchar(int);
+int _FAR_ _cdecl puts(const char _FAR_ *);
+#endif
+int _FAR_ _cdecl putw(int, FILE _FAR_ *);
+int _FAR_ _cdecl remove(const char _FAR_ *);
+int _FAR_ _cdecl rename(const char _FAR_ *, const char _FAR_ *);
+void _FAR_ _cdecl rewind(FILE _FAR_ *);
+int _FAR_ _cdecl rmtmp(void);
+#ifndef _WINDOWS
+int _FAR_ _cdecl scanf(const char _FAR_ *, ...);
+#endif
+void _FAR_ _cdecl setbuf(FILE _FAR_ *, char _FAR_ *);
+int _FAR_ _cdecl setvbuf(FILE _FAR_ *, char _FAR_ *, int, size_t);
+#ifndef _WINDLL
+int _FAR_ _cdecl sprintf(char _FAR_ *, const char _FAR_ *, ...);
+int _FAR_ _cdecl sscanf(const char _FAR_ *, const char _FAR_ *, ...);
+#endif
+char _FAR_ * _FAR_ _cdecl tempnam(char _FAR_ *, char _FAR_ *);
+FILE _FAR_ * _FAR_ _cdecl tmpfile(void);
+char _FAR_ * _FAR_ _cdecl tmpnam(char _FAR_ *);
+int _FAR_ _cdecl ungetc(int, FILE _FAR_ *);
+int _FAR_ _cdecl unlink(const char _FAR_ *);
+#ifndef _WINDLL
+int _FAR_ _cdecl vfprintf(FILE _FAR_ *, const char _FAR_ *, va_list);
+#endif
+#ifndef _WINDOWS
+int _FAR_ _cdecl vprintf(const char _FAR_ *, va_list);
+#endif
+#ifndef _WINDLL
+int _FAR_ _cdecl vsprintf(char _FAR_ *, const char _FAR_ *, va_list);
+#endif
+#define _STDIO_DEFINED
+#endif
+
+/* macro definitions */
+
+#define feof(_stream) ((_stream)->_flag & _IOEOF)
+#define ferror(_stream) ((_stream)->_flag & _IOERR)
+#define fileno(_stream) ((int)(unsigned char)(_stream)->_file)
+#define getc(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ \
+ : _filbuf(_stream))
+#define putc(_c,_stream) (--(_stream)->_cnt >= 0 \
+ ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream)))
+#ifndef _WINDOWS
+#define getchar() getc(stdin)
+#define putchar(_c) putc((_c),stdout)
+#endif
+
+#ifdef _MT
+#undef getc
+#undef putc
+#undef getchar
+#undef putchar
+#endif
diff --git a/private/mvdm/wow16/inc/stdlib.h b/private/mvdm/wow16/inc/stdlib.h
new file mode 100644
index 000000000..7a0f532ea
--- /dev/null
+++ b/private/mvdm/wow16/inc/stdlib.h
@@ -0,0 +1,212 @@
+/***
+*stdlib.h - declarations/definitions for commonly used library functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This include file contains the function declarations for
+* commonly used library functions which either don't fit somewhere
+* else, or, like toupper/tolower, can't be declared in the normal
+* place for other reasons.
+* [ANSI]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifdef _DLL
+#define _LOADDS_ _loadds
+#else
+#define _LOADDS_
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#if (_MSC_VER >= 600)
+#define NULL ((void *)0)
+#elif (defined(M_I86SM) || defined(M_I86MM))
+#define NULL 0
+#else
+#define NULL 0L
+#endif
+#endif
+
+/* definition of the return type for the onexit() function */
+
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+#ifndef _ONEXIT_T_DEFINED
+typedef int (_FAR_ _cdecl _LOADDS_ * _cdecl onexit_t)();
+#define _ONEXIT_T_DEFINED
+#endif
+
+
+/* data structure definitions for div and ldiv runtimes. */
+
+#ifndef _DIV_T_DEFINED
+
+typedef struct _div_t {
+ int quot;
+ int rem;
+} div_t;
+
+typedef struct _ldiv_t {
+ long quot;
+ long rem;
+} ldiv_t;
+
+#define _DIV_T_DEFINED
+#endif
+
+/* maximum value that can be returned by the rand function. */
+
+#define RAND_MAX 0x7fff
+
+
+/* min and max macros */
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+
+/* sizes for buffers used by the _makepath() and _splitpath() functions.
+ * note that the sizes include space for 0-terminator
+ */
+
+#define _MAX_PATH 260 /* max. length of full pathname */
+#define _MAX_DRIVE 3 /* max. length of drive component */
+#define _MAX_DIR 256 /* max. length of path component */
+#define _MAX_FNAME 256 /* max. length of file name component */
+#define _MAX_EXT 256 /* max. length of extension component */
+
+/* external variable declarations */
+
+#ifdef _MT
+extern int _far * _cdecl _far volatile _errno(void);
+extern unsigned _far * _cdecl _far __doserrno(void);
+#define errno (*_errno())
+#define _doserrno (*__doserrno())
+#else
+extern int _near _cdecl volatile errno; /* XENIX style error number */
+extern int _near _cdecl _doserrno; /* MS-DOS system error value */
+#endif
+extern char * _near _cdecl sys_errlist[]; /* perror error message table */
+extern int _near _cdecl sys_nerr; /* # of entries in sys_errlist table */
+
+#ifdef _DLL
+extern char ** _FAR_ _cdecl environ; /* pointer to environment table */
+extern int _FAR_ _cdecl _fmode; /* default file translation mode */
+extern int _FAR_ _cdecl _fileinfo; /* open file info mode (for spawn) */
+#else
+extern char ** _near _cdecl environ; /* pointer to environment table */
+extern int _near _cdecl _fmode; /* default file translation mode */
+extern int _near _cdecl _fileinfo; /* open file info mode (for spawn) */
+#endif
+
+extern unsigned int _near _cdecl _psp; /* Program Segment Prefix */
+
+/* OS major/minor version numbers */
+
+#ifndef _WINDLL
+extern unsigned char _near _cdecl _osmajor;
+extern unsigned char _near _cdecl _osminor;
+#endif
+
+#define DOS_MODE 0 /* Real Address Mode */
+#define OS2_MODE 1 /* Protected Address Mode */
+
+extern unsigned char _near _cdecl _osmode;
+
+
+/* function prototypes */
+
+#ifdef _MT
+double _FAR_ _pascal atof(const char _FAR_ *);
+double _FAR_ _pascal strtod(const char _FAR_ *, char _FAR_ * _FAR_ *);
+ldiv_t _FAR_ _pascal ldiv(long, long);
+#else /* not _MT */
+double _FAR_ _cdecl atof(const char _FAR_ *);
+double _FAR_ _cdecl strtod(const char _FAR_ *, char _FAR_ * _FAR_ *);
+ldiv_t _FAR_ _cdecl ldiv(long, long);
+#endif
+
+void _FAR_ _cdecl abort(void);
+int _FAR_ _cdecl abs(int);
+int _FAR_ _cdecl atexit(void (_cdecl _FAR_ _LOADDS_ *)(void));
+int _FAR_ _cdecl atoi(const char _FAR_ *);
+long _FAR_ _cdecl atol(const char _FAR_ *);
+long double _FAR_ _cdecl _atold(const char _FAR_ *);
+void _FAR_ * _FAR_ _cdecl bsearch(const void _FAR_ *, const void _FAR_ *,
+ size_t, size_t, int (_FAR_ _cdecl *)(const void _FAR_ *,
+ const void _FAR_ *));
+void _FAR_ * _FAR_ _cdecl calloc(size_t, size_t);
+div_t _FAR_ _cdecl div(int, int);
+char _FAR_ * _FAR_ _cdecl ecvt(double, int, int _FAR_ *, int _FAR_ *);
+void _FAR_ _cdecl exit(int);
+void _FAR_ _cdecl _exit(int);
+char _FAR_ * _FAR_ _cdecl fcvt(double, int, int _FAR_ *, int _FAR_ *);
+void _FAR_ _cdecl free(void _FAR_ *);
+char _FAR_ * _FAR_ _cdecl _fullpath(char _FAR_ *, const char _FAR_ *,
+ size_t);
+#ifndef _WINDLL
+char _FAR_ * _FAR_ _cdecl gcvt(double, int, char _FAR_ *);
+#endif
+char _FAR_ * _FAR_ _cdecl getenv(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl itoa(int, char _FAR_ *, int);
+long _FAR_ _cdecl labs(long);
+unsigned long _FAR_ _cdecl _lrotl(unsigned long, int);
+unsigned long _FAR_ _cdecl _lrotr(unsigned long, int);
+char _FAR_ * _FAR_ _cdecl ltoa(long, char _FAR_ *, int);
+void _FAR_ _cdecl _makepath(char _FAR_ *, const char _FAR_ *,
+ const char _FAR_ *, const char _FAR_ *, const char _FAR_ *);
+void _FAR_ * _FAR_ _cdecl malloc(size_t);
+onexit_t _FAR_ _cdecl onexit(onexit_t);
+#ifndef _WINDOWS
+void _FAR_ _cdecl perror(const char _FAR_ *);
+#endif
+int _FAR_ _cdecl putenv(const char _FAR_ *);
+void _FAR_ _cdecl qsort(void _FAR_ *, size_t, size_t, int (_FAR_ _cdecl *)
+ (const void _FAR_ *, const void _FAR_ *));
+unsigned int _FAR_ _cdecl _rotl(unsigned int, int);
+unsigned int _FAR_ _cdecl _rotr(unsigned int, int);
+int _FAR_ _cdecl rand(void);
+void _FAR_ * _FAR_ _cdecl realloc(void _FAR_ *, size_t);
+void _FAR_ _cdecl _searchenv(const char _FAR_ *, const char _FAR_ *,
+ char _FAR_ *);
+void _FAR_ _cdecl _splitpath(const char _FAR_ *, char _FAR_ *,
+ char _FAR_ *, char _FAR_ *, char _FAR_ *);
+void _FAR_ _cdecl srand(unsigned int);
+long _FAR_ _cdecl strtol(const char _FAR_ *, char _FAR_ * _FAR_ *,
+ int);
+long double _FAR_ _cdecl _strtold(const char _FAR_ *,
+ char _FAR_ * _FAR_ *);
+unsigned long _FAR_ _cdecl strtoul(const char _FAR_ *,
+ char _FAR_ * _FAR_ *, int);
+void _FAR_ _cdecl swab(char _FAR_ *, char _FAR_ *, int);
+#ifndef _WINDOWS
+int _FAR_ _cdecl system(const char _FAR_ *);
+#endif
+char _FAR_ * _FAR_ _cdecl ultoa(unsigned long, char _FAR_ *, int);
+
+#ifndef tolower /* tolower has been undefined - use function */
+int _FAR_ _cdecl tolower(int);
+#endif /* tolower */
+
+#ifndef toupper /* toupper has been undefined - use function */
+int _FAR_ _cdecl toupper(int);
+#endif /* toupper */
diff --git a/private/mvdm/wow16/inc/string.h b/private/mvdm/wow16/inc/string.h
new file mode 100644
index 000000000..2c39b8d91
--- /dev/null
+++ b/private/mvdm/wow16/inc/string.h
@@ -0,0 +1,121 @@
+/***
+*string.h - declarations for string manipulation functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the function declarations for the string
+* manipulation functions.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+/* function prototypes */
+
+void _FAR_ * _FAR_ _cdecl memccpy(void _FAR_ *, const void _FAR_ *,
+ int, unsigned int);
+void _FAR_ * _FAR_ _cdecl memchr(const void _FAR_ *, int, size_t);
+int _FAR_ _cdecl memcmp(const void _FAR_ *, const void _FAR_ *,
+ size_t);
+int _FAR_ _cdecl memicmp(const void _FAR_ *, const void _FAR_ *,
+ unsigned int);
+void _FAR_ * _FAR_ _cdecl memcpy(void _FAR_ *, const void _FAR_ *,
+ size_t);
+void _FAR_ * _FAR_ _cdecl memmove(void _FAR_ *, const void _FAR_ *,
+ size_t);
+void _FAR_ * _FAR_ _cdecl memset(void _FAR_ *, int, size_t);
+void _FAR_ _cdecl movedata(unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int);
+char _FAR_ * _FAR_ _cdecl strcat(char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strchr(const char _FAR_ *, int);
+int _FAR_ _cdecl strcmp(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl strcmpi(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl strcoll(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl stricmp(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strcpy(char _FAR_ *, const char _FAR_ *);
+size_t _FAR_ _cdecl strcspn(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strdup(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl _strerror(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strerror(int);
+size_t _FAR_ _cdecl strlen(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strlwr(char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strncat(char _FAR_ *, const char _FAR_ *,
+ size_t);
+int _FAR_ _cdecl strncmp(const char _FAR_ *, const char _FAR_ *,
+ size_t);
+int _FAR_ _cdecl strnicmp(const char _FAR_ *, const char _FAR_ *,
+ size_t);
+char _FAR_ * _FAR_ _cdecl strncpy(char _FAR_ *, const char _FAR_ *,
+ size_t);
+char _FAR_ * _FAR_ _cdecl strnset(char _FAR_ *, int, size_t);
+char _FAR_ * _FAR_ _cdecl strpbrk(const char _FAR_ *,
+ const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strrchr(const char _FAR_ *, int);
+char _FAR_ * _FAR_ _cdecl strrev(char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strset(char _FAR_ *, int);
+size_t _FAR_ _cdecl strspn(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strstr(const char _FAR_ *,
+ const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strtok(char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strupr(char _FAR_ *);
+size_t _FAR_ _cdecl strxfrm (char _FAR_ *, const char _FAR_ *,
+ size_t);
+
+/* model independent function prototypes */
+
+void _far * _far _cdecl _fmemccpy(void _far *, const void _far *,
+ int, unsigned int);
+void _far * _far _cdecl _fmemchr(const void _far *, int, size_t);
+int _far _cdecl _fmemcmp(const void _far *, const void _far *,
+ size_t);
+void _far * _far _cdecl _fmemcpy(void _far *, const void _far *,
+ size_t);
+int _far _cdecl _fmemicmp(const void _far *, const void _far *,
+ unsigned int);
+void _far * _far _cdecl _fmemmove(void _far *, const void _far *,
+ size_t);
+void _far * _far _cdecl _fmemset(void _far *, int, size_t);
+char _far * _far _cdecl _fstrcat(char _far *, const char _far *);
+char _far * _far _cdecl _fstrchr(const char _far *, int);
+int _far _cdecl _fstrcmp(const char _far *, const char _far *);
+int _far _cdecl _fstricmp(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrcpy(char _far *, const char _far *);
+size_t _far _cdecl _fstrcspn(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrdup(const char _far *);
+char _near * _far _cdecl _nstrdup(const char _far *);
+size_t _far _cdecl _fstrlen(const char _far *);
+char _far * _far _cdecl _fstrlwr(char _far *);
+char _far * _far _cdecl _fstrncat(char _far *, const char _far *,
+ size_t);
+int _far _cdecl _fstrncmp(const char _far *, const char _far *,
+ size_t);
+int _far _cdecl _fstrnicmp(const char _far *, const char _far *,
+ size_t);
+char _far * _far _cdecl _fstrncpy(char _far *, const char _far *,
+ size_t);
+char _far * _far _cdecl _fstrnset(char _far *, int, size_t);
+char _far * _far _cdecl _fstrpbrk(const char _far *,
+ const char _far *);
+char _far * _far _cdecl _fstrrchr(const char _far *, int);
+char _far * _far _cdecl _fstrrev(char _far *);
+char _far * _far _cdecl _fstrset(char _far *, int);
+size_t _far _cdecl _fstrspn(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrstr(const char _far *,
+ const char _far *);
+char _far * _far _cdecl _fstrtok(char _far *, const char _far *);
+char _far * _far _cdecl _fstrupr(char _far *);
diff --git a/private/mvdm/wow16/inc/strtable.h b/private/mvdm/wow16/inc/strtable.h
new file mode 100644
index 000000000..c9cc7a357
--- /dev/null
+++ b/private/mvdm/wow16/inc/strtable.h
@@ -0,0 +1,136 @@
+/****************************************************************************/
+/* */
+/* STRTABLE.H - */
+/* */
+/* StringTable Defines */
+/* */
+/****************************************************************************/
+
+/* STRINGTABLE Defines */
+#define STR_WINDOWS 0
+#define STR_COLORS 1
+#define STR_DESKPATTERN 2
+#define STR_FONTS 3
+#define STR_BLINK 4
+#define STR_SWAPBUTTONS 5
+#define STR_DBLCLKSPEED 6
+#define STR_TYPEAHEAD 7
+#define STR_GRID 8
+#define STR_BEEP 9
+#define STR_MOUSETHRESH1 10
+#define STR_MOUSETHRESH2 11
+#define STR_MOUSESPEED 12
+#define STR_KEYSPEED 13
+#define STR_BORDER 14
+#define STR_QSIZE 15
+
+#define STR_CLASSSTART 16
+#define STR_BUTTONCLASS 16
+#define STR_EDITCLASS 17
+#define STR_STATICCLASS 18
+#define STR_LISTBOXCLASS 19
+#define STR_SCROLLBARCLASS 20
+#define STR_COMBOBOXCLASS 21
+#define STR_MDICLASS 22
+#define STR_COMBOLISTBOXCLASS 23
+
+#define STR_COLORSTART 32
+#define STR_SCROLLBAR 32
+#define STR_BACKGROUND 33
+#define STR_ACTIVETITLE 34
+#define STR_INACTIVETITLE 35
+#define STR_MENU 36
+#define STR_WINDOW 37
+#define STR_WINDOWFRAME 38
+#define STR_MENUTEXT 39
+#define STR_WINDOWTEXT 40
+#define STR_TITLETEXT 41
+#define STR_ACTIVEBORDER 42
+#define STR_INACTIVEBORDER 43
+#define STR_APPWORKSPACE 44
+#define STR_HIGHLIGHT 45
+#define STR_HIGHLIGHTTEXT 46
+#define STR_BTNFACE 47
+#define STR_BTNSHADOW 48
+#define STR_GRAYTEXT 49
+#define STR_BTNTEXT 50
+#define STR_INACTIVECAPTIONTEXT 51
+
+#define STR_FILEPORT 60
+#define STR_CANTOPEN 61
+#define STR_OVERWRITE 62
+#define STR_MOREWINDOWS 63
+
+#define STR_ICONHORZSPACING 64
+#define STR_ICONVERTSPACING 65
+#define STR_ICONTITLEWRAP 66
+
+#define STR_DTBITMAP 67
+#define STR_DTSTYLE 68
+#define STR_DTORIGINX 69
+#define STR_DTORIGINY 70
+
+#define STR_NETDRIVER 71
+#define STR_BOOT 72
+#define STR_LANGDRIVER 73
+#define STR_SYSTEMINI 74
+#define STR_SYSERR 75
+#define STR_DIVBYZERO 76
+#define STR_UNTITLED 77
+#define STR_ERROR 78
+#define STR_TASKMAN 79
+
+#define STR_DESKTOP 80
+#define STR_PATTERNS 81
+#define STR_NONE 82
+#define STR_TILEWALL 83
+
+#define STR_OK 84
+#define STR_CANCEL 85
+#define STR_ABORT 86
+#define STR_RETRY 87
+#define STR_IGNORE 88
+#define STR_YES 89
+#define STR_NO 90
+#define STR_ACCELERATORS 91
+#define STR_AM 92
+#define STR_PM 93
+#define STR_MENUSHOWDELAY 94
+#define STR_MENUHIDEDELAY 95
+#define STR_MENUDROPALIGNMENT 96
+#define STR_DOUBLECLICKWIDTH 97
+#define STR_DOUBLECLICKHEIGHT 98
+#define STR_SCREENSAVETIMEOUT 99
+#define STR_SCREENSAVEACTIVE 100
+#define STR_SCREENSAVEEXE 101
+#define STR_DRIVERS 102
+#define STR_NOMEMBITMAP 103
+#define STR_BEEPYES 104
+#define STR_BEEPNO 105
+#define STR_KEYDELAY 106
+#define STR_DRAGFULLWINDOWS 107
+#define STR_ICONTITLEFACENAME 108
+#define STR_ICONTITLESIZE 109
+#define STR_ICONTITLESTYLE 110
+#define STR_FASTALTTAB 111
+#define STR_INRESTORENETCONNECT 112
+
+#define STR_COMMMODULENAME 200
+#define STR_COMMWRITESTRING 201
+#define STR_COMMREADSTRING 202
+#define STR_COMMENABLENOTIFICATION 203
+#define STR_MOUSEMODULENAME 204
+
+
+ /* 256 - 512 are strings for network errors
+ */
+
+#define STR_NETCONNMSG 256
+#define STR_NETCONNTTL 257
+#define STR_NETCRASHEDTITLE 258
+#define STR_NETCRASHEDMSG 259
+#define STR_NETERRORS 275
+
+#define STR_SEARCH_TAG 513 // don't change, these are hard
+#define STR_USER_NAME 514 // coded in SHELL.DLL
+#define STR_ORG_NAME 515 // ugh!
diff --git a/private/mvdm/wow16/inc/style.h b/private/mvdm/wow16/inc/style.h
new file mode 100644
index 000000000..0e5bbd7fe
--- /dev/null
+++ b/private/mvdm/wow16/inc/style.h
@@ -0,0 +1,206 @@
+/* Window styles */
+#define WS_TILED 0x00000000L
+#define WS_ICONICPOPUP 0xc0000000L
+#define WS_POPUP 0x80000000L
+#define WS_CHILD 0x40000000L
+#define WS_MINIMIZE 0x20000000L
+#define WS_VISIBLE 0x10000000L
+#define WS_DISABLED 0x08000000L
+#define WS_CLIPSIBLINGS 0x04000000L
+#define WS_CLIPCHILDREN 0x02000000L
+#define WS_MAXIMIZE 0x01000000L
+
+#define WS_BORDER 0x00800000L
+#define WS_CAPTION 0x00c00000L
+#define WS_DLGFRAME 0x00400000L
+#define WS_VSCROLL 0x00200000L
+#define WS_HSCROLL 0x00100000L
+#define WS_SYSMENU 0x00080000L
+#define WS_SIZEBOX 0x00040000L
+#define WS_GROUP 0x00020000L
+#define WS_TABSTOP 0x00010000L
+
+#define WS_ICONIC WS_MINIMIZE
+
+/* Class styles */
+#define CS_VREDRAW 0x0001
+#define CS_HREDRAW 0x0002
+#define CS_KEYCVTWINDOW 0x0004
+#define CS_DBLCLKS 0x0008
+ /* 0x0010 reserved */
+#define CS_OWNDC 0x0020
+#define CS_CLASSDC 0x0040
+#define CS_MENUPOPUP 0x0080
+#define CS_NOKEYCVT 0x0100
+#define CS_SAVEBITS 0x0800
+
+/* Shorthand for the common cases */
+#define WS_TILEDWINDOW (WS_TILED | WS_CAPTION | WS_SYSMENU | WS_SIZEBOX)
+#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU)
+#define WS_CHILDWINDOW (WS_CHILD)
+
+/* Edit control styles */
+#define ES_LEFT 0x0000L
+#define ES_CENTER 0x0001L
+#define ES_RIGHT 0x0002L
+#define ES_MULTILINE 0x0004L
+#define ES_UPPERCASE 0x0008L
+#define ES_LOWERCASE 0x0010L
+#define ES_PASSWORD 0x0020L
+#define ES_AUTOVSCROLL 0x0040L
+#define ES_AUTOHSCROLL 0x0080L
+#define ES_NOHIDESEL 0x0100L
+#define ES_OEMCONVERT 0x0400L
+
+/* button control styles */
+#define BS_PUSHBUTTON 0L
+#define BS_DEFPUSHBUTTON 1L
+#define BS_CHECKBOX 2L
+#define BS_AUTOCHECKBOX 3L
+#define BS_RADIOBUTTON 4L
+#define BS_3STATE 5L
+#define BS_AUTO3STATE 6L
+#define BS_GROUPBOX 7L
+#define BS_USERBUTTON 8L
+#define BS_AUTORADIOBUTTON 9L
+#define BS_PUSHBOX 10L
+#define BS_OWNERDRAW 0x0BL
+#define BS_LEFTTEXT 0x20L
+
+/* Dialog Styles */
+#define DS_ABSALIGN 0x01L
+#define DS_SYSMODAL 0x02L
+#define DS_LOCALEDIT 0x20L /* Edit items get Local storage. */
+#define DS_SETFONT 0x40L /* User specified font for Dlg controls */
+#define DS_MODALFRAME 0x80L /* Can be combined with WS_CAPTION */
+#define DS_NOIDLEMSG 0x100L /* WM_ENTERIDLE message will not be sent */
+
+/* listbox style bits */
+#define LBS_NOTIFY 0x0001L
+#define LBS_SORT 0x0002L
+#define LBS_NOREDRAW 0x0004L
+#define LBS_MULTIPLESEL 0x0008L
+#define LBS_OWNERDRAWFIXED 0x0010L
+#define LBS_OWNERDRAWVARIABLE 0x0020L
+#define LBS_HASSTRINGS 0x0040L
+#define LBS_USETABSTOPS 0x0080L
+#define LBS_NOINTEGRALHEIGHT 0x0100L
+#define LBS_MULTICOLUMN 0x0200L
+#define LBS_WANTKEYBOARDINPUT 0x0400L
+#define LBS_EXTENDEDSEL 0x0800L
+#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)
+
+/* Combo Box styles */
+#define CBS_SIMPLE 0x0001L
+#define CBS_DROPDOWN 0x0002L
+#define CBS_DROPDOWNLIST 0x0003L
+#define CBS_OWNERDRAWFIXED 0x0010L
+#define CBS_OWNERDRAWVARIABLE 0x0020L
+#define CBS_AUTOHSCROLL 0x0040L
+#define CBS_SORT 0x0100L
+#define CBS_HASSTRINGS 0x0200L
+
+/* scroll bar styles */
+#define SBS_HORZ 0x0000L
+#define SBS_VERT 0x0001L
+#define SBS_TOPALIGN 0x0002L
+#define SBS_LEFTALIGN 0x0002L
+#define SBS_BOTTOMALIGN 0x0004L
+#define SBS_RIGHTALIGN 0x0004L
+#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L
+#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L
+#define SBS_SIZEBOX 0x0008L
+
+/* Conventional dialog box and message box command IDs */
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+
+/* Static control constants */
+#define SS_LEFT 0L
+#define SS_CENTER 1L
+#define SS_RIGHT 2L
+#define SS_ICON 3L
+#define SS_BLACKRECT 4L
+#define SS_GRAYRECT 5L
+#define SS_WHITERECT 6L
+#define SS_BLACKFRAME 7L
+#define SS_GRAYFRAME 8L
+#define SS_WHITEFRAME 9L
+#define SS_USERITEM 10L
+
+/* Virtual Keys, Standard Set */
+
+#define VK_LBUTTON 0x01
+#define VK_RBUTTON 0x02
+#define VK_CANCEL 0x03
+#define VK_MBUTTON 0x04 /* NOT contiguous with L & RBUTTON */
+#define VK_BACK 0x08
+#define VK_TAB 0x09
+#define VK_CLEAR 0x0c
+#define VK_RETURN 0x0d
+#define VK_SHIFT 0x10
+#define VK_CONTROL 0x11
+#define VK_MENU 0x12
+#define VK_PAUSE 0x13
+#define VK_CAPITAL 0x14
+#define VK_ESCAPE 0x1b
+#define VK_SPACE 0x20
+
+#define VK_PRIOR 0x21
+#define VK_NEXT 0x22
+#define VK_END 0x23
+#define VK_HOME 0x24
+#define VK_LEFT 0x25
+#define VK_UP 0x26
+#define VK_RIGHT 0x27
+#define VK_DOWN 0x28
+
+/* VK_A thru VK_Z are the same as their ASCII equivalents: 'A' thru 'Z' */
+/* VK_0 thru VK_9 are the same as their ASCII equivalents: '0' thru '0' */
+
+#define VK_SELECT 0x29
+#define VK_PRINT 0x2a
+#define VK_EXECUTE 0x2b
+#define VK_SNAPSHOT 0x2c
+#define VK_INSERT 0x2d
+#define VK_DELETE 0x2e
+#define VK_HELP 0x2f
+
+#define VK_NUMPAD0 0x60
+#define VK_NUMPAD1 0x61
+#define VK_NUMPAD2 0x62
+#define VK_NUMPAD3 0x63
+#define VK_NUMPAD4 0x64
+#define VK_NUMPAD5 0x65
+#define VK_NUMPAD6 0x66
+#define VK_NUMPAD7 0x67
+#define VK_NUMPAD8 0x68
+#define VK_NUMPAD9 0x69
+#define VK_MULTIPLY 0x6A
+#define VK_ADD 0x6B
+#define VK_SEPARATOR 0x6C
+#define VK_SUBTRACT 0x6D
+#define VK_DECIMAL 0x6E
+#define VK_DIVIDE 0x6F
+
+#define VK_F1 0x70
+#define VK_F2 0x71
+#define VK_F3 0x72
+#define VK_F4 0x73
+#define VK_F5 0x74
+#define VK_F6 0x75
+#define VK_F7 0x76
+#define VK_F8 0x77
+#define VK_F9 0x78
+#define VK_F10 0x79
+#define VK_F11 0x7a
+#define VK_F12 0x7b
+#define VK_F13 0x7c
+#define VK_F14 0x7d
+#define VK_F15 0x7e
+#define VK_F16 0x7f
diff --git a/private/mvdm/wow16/inc/testing.h b/private/mvdm/wow16/inc/testing.h
new file mode 100644
index 000000000..3773e4b3b
--- /dev/null
+++ b/private/mvdm/wow16/inc/testing.h
@@ -0,0 +1,50 @@
+/*---------------------------------------------------------*\
+| |
+| TESTING.H |
+| |
+| Testing's very own include file! |
+\*---------------------------------------------------------*/
+
+
+
+/* This has all of the defines for the wParam and lParam that go along with
+ * the WM_TESTING message
+ */
+/* wParam defines - Area
+ */
+#define TEST_PRINTMAN 0x0001
+#define TEST_GDI 0x0002
+
+
+/* lParam defines - Details (in LOWORD)
+ */
+#define TEST_PRINTJOB_START 0x0001 /* when bits start going to the port */
+#define TEST_PRINTJOB_END 0x0002 /* when bits stop going to the port */
+#define TEST_QUEUE_READY 0x0003 /* when the queue is ready to accept a job */
+#define TEST_QUEUE_EMPTY 0x0004 /* when the last job is done being sent */
+
+#define TEST_START_DOC 0x0001 /* print job is started */
+#define TEST_END_DOC 0x0002 /* print job is ended */
+
+
+/* Defines for UserSeeUserDo and GDISeeGDIDo functions
+ */
+LONG API UserSeeUserDo(WORD wMsg, WORD wParam, LONG lParam);
+LONG API GDISeeGDIDo(WORD wMsg, WORD wParam, LONG lParam);
+
+/* Defines for the various messages one can pass for the SeeDo functions.
+ */
+#define SD_LOCALALLOC 0x0001 /* Alloc using flags wParam and lParam bytes.
+ * Returns handle to data.
+ */
+#define SD_LOCALFREE 0x0002 /* Free the memory allocated by handle wParam
+ */
+#define SD_LOCALCOMPACT 0x0003 /* Return the number of free bytes available
+ */
+#define SD_GETUSERMENUHEAP 0x0004 /* Return the handle to the far menu heap
+ * maintained by user.
+ */
+#define SD_GETCLASSHEADPTR 0x0005 /* Return the near pointer to the head of
+ * the linked list of CLS structures.
+ * Interface: wParam = NULL; lParam = NULL;
+ */
diff --git a/private/mvdm/wow16/inc/time.h b/private/mvdm/wow16/inc/time.h
new file mode 100644
index 000000000..565ae77e4
--- /dev/null
+++ b/private/mvdm/wow16/inc/time.h
@@ -0,0 +1,118 @@
+/***
+*time.h - definitions/declarations for time routines
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the various declarations and definitions
+* for the time routines.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+/* implementation defined time types */
+
+#ifndef _TIME_T_DEFINED
+typedef long time_t;
+#define _TIME_T_DEFINED
+#endif
+
+#ifndef _CLOCK_T_DEFINED
+typedef long clock_t;
+#define _CLOCK_T_DEFINED
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+/* structure for use with localtime(), gmtime(), etc. */
+
+#ifndef _TM_DEFINED
+struct tm {
+ int tm_sec; /* seconds after the minute - [0,59] */
+ int tm_min; /* minutes after the hour - [0,59] */
+ int tm_hour; /* hours since midnight - [0,23] */
+ int tm_mday; /* day of the month - [1,31] */
+ int tm_mon; /* months since January - [0,11] */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* days since Sunday - [0,6] */
+ int tm_yday; /* days since January 1 - [0,365] */
+ int tm_isdst; /* daylight savings time flag */
+ };
+#define _TM_DEFINED
+#endif
+
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#if (_MSC_VER >= 600)
+#define NULL ((void *)0)
+#elif (defined(M_I86SM) || defined(M_I86MM))
+#define NULL 0
+#else
+#define NULL 0L
+#endif
+#endif
+
+
+/* clock ticks macro - ANSI version */
+
+#define CLOCKS_PER_SEC 1000
+
+/* clock ticks macro - archaic version */
+
+#define CLK_TCK 1000
+
+
+/* extern declarations for the global variables used by the ctime family of
+ * routines.
+ */
+
+#ifdef _DLL
+extern int _FAR_ _cdecl daylight; /* non-zero if daylight savings time is used */
+extern long _FAR_ _cdecl timezone; /* difference in seconds between GMT and local time */
+extern char _FAR_ * _FAR_ _cdecl tzname[2]; /* standard/daylight savings time zone names */
+#else
+extern int _near _cdecl daylight; /* non-zero if daylight savings time is used */
+extern long _near _cdecl timezone; /* difference in seconds between GMT and local time */
+extern char * _near _cdecl tzname[2]; /* standard/daylight savings time zone names */
+#endif
+
+
+/* function prototypes */
+
+#ifdef _MT
+double _FAR_ _pascal difftime(time_t, time_t);
+#else
+double _FAR_ _cdecl difftime(time_t, time_t);
+#endif
+
+char _FAR_ * _FAR_ _cdecl asctime(const struct tm _FAR_ *);
+char _FAR_ * _FAR_ _cdecl ctime(const time_t _FAR_ *);
+#ifndef _WINDLL
+clock_t _FAR_ _cdecl clock(void);
+#endif
+struct tm _FAR_ * _FAR_ _cdecl gmtime(const time_t _FAR_ *);
+struct tm _FAR_ * _FAR_ _cdecl localtime(const time_t _FAR_ *);
+time_t _FAR_ _cdecl mktime(struct tm _FAR_ *);
+#ifndef _WINDLL
+size_t _FAR_ _cdecl strftime(char _FAR_ *, size_t, const char _FAR_ *,
+ const struct tm _FAR_ *);
+#endif
+char _FAR_ * _FAR_ _cdecl _strdate(char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl _strtime(char _FAR_ *);
+time_t _FAR_ _cdecl time(time_t _FAR_ *);
+void _FAR_ _cdecl tzset(void);
diff --git a/private/mvdm/wow16/inc/userproc.h b/private/mvdm/wow16/inc/userproc.h
new file mode 100644
index 000000000..04c9d0152
--- /dev/null
+++ b/private/mvdm/wow16/inc/userproc.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * UserProc.H
+ *
+ * Addition exports from USER.EXE
+ */
+
+/* lParam of WM_DROPOBJECT and WM_QUERYDROPOBJECT points to one of these.
+ */
+typedef struct _dropstruct
+ {
+ HWND hwndSource;
+ HWND hwndSink;
+ WORD wFmt;
+ LPARAM dwData;
+ POINT ptDrop;
+ LPARAM dwControlData;
+ } DROPSTRUCT;
+
+#define DOF_EXECUTABLE 0x8001
+#define DOF_DOCUMENT 0x8002
+#define DOF_DIRECTORY 0x8003
+#define DOF_MULTIPLE 0x8004
+
+typedef DROPSTRUCT FAR * LPDROPSTRUCT;
+
+WORD FAR PASCAL GetInternalWindowPos(HWND,LPRECT,LPPOINT);
+BOOL FAR PASCAL SetInternalWindowPos(HWND,WORD,LPRECT,LPPOINT);
+
+void FAR PASCAL CalcChildScroll(HWND,WORD);
+void FAR PASCAL ScrollChildren(HWND,WORD,WORD,LONG);
+
+LRESULT FAR PASCAL DragObject(HWND hwndParent, HWND hwndFrom, WORD wFmt,
+ LPARAM dwData, HANDLE hCursor);
+BOOL FAR PASCAL DragDetect(HWND hwnd, POINT pt);
+
+void FAR PASCAL FillWindow(HWND hwndBrush, HWND hwndPaint, HDC hdc,
+ HBRUSH hBrush);
diff --git a/private/mvdm/wow16/inc/ver.h b/private/mvdm/wow16/inc/ver.h
new file mode 100644
index 000000000..cc8f0501e
--- /dev/null
+++ b/private/mvdm/wow16/inc/ver.h
@@ -0,0 +1,255 @@
+/*****************************************************************************\
+* *
+* ver.h - Version management functions, types, and definitions *
+* *
+* Include file for VER.DLL and VER.LIB. These libraries are *
+* designed to allow version stamping of Windows executable files*
+* and of special .VER files for DOS executable files. *
+* *
+* The API is unchanged for LIB and DLL versions. *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+*******************************************************************************
+*
+* #define LIB - To be used with VER.LIB (default is for VER.DLL)
+*
+\*****************************************************************************/
+
+#ifndef _INC_VER
+#define _INC_VER
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/*
+ * If .lib version is being used, declare types used in this file.
+ */
+#ifdef LIB
+
+#ifndef WINAPI /* don't declare if they're already declared */
+#define WINAPI _far _pascal
+#define NEAR _near
+#define FAR _far
+#define PASCAL _pascal
+typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef signed long LONG;
+typedef unsigned long DWORD;
+typedef char far* LPSTR;
+typedef const char far* LPCSTR;
+typedef int HFILE;
+#define OFSTRUCT void /* Not used by the .lib version */
+#define LOWORD(l) ((WORD)(l))
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)(i)))
+#endif /* WINAPI */
+
+#else /* LIB */
+
+/* If .dll version is being used and we're being included with
+ * the 3.0 windows.h, #define compatible type aliases.
+ * If included with the 3.0 windows.h, #define compatible aliases
+ */
+#ifndef _INC_WINDOWS
+#define UINT WORD
+#define LPCSTR LPSTR
+#define HFILE int
+#endif /* !_INC_WINDOWS */
+
+#endif /* !LIB */
+
+/* ----- RC defines ----- */
+#ifdef RC_INVOKED
+#define ID(id) id
+#else
+#define ID(id) MAKEINTRESOURCE(id)
+#endif
+
+/* ----- Symbols ----- */
+#define VS_FILE_INFO ID(16) /* Version stamp res type */
+#define VS_VERSION_INFO ID(1) /* Version stamp res ID */
+#define VS_USER_DEFINED ID(100) /* User-defined res IDs */
+
+/* ----- VS_VERSION.dwFileFlags ----- */
+#define VS_FFI_SIGNATURE 0xFEEF04BDL
+#define VS_FFI_STRUCVERSION 0x00010000L
+#define VS_FFI_FILEFLAGSMASK 0x0000003FL
+
+/* ----- VS_VERSION.dwFileFlags ----- */
+#define VS_FF_DEBUG 0x00000001L
+#define VS_FF_PRERELEASE 0x00000002L
+#define VS_FF_PATCHED 0x00000004L
+#define VS_FF_PRIVATEBUILD 0x00000008L
+#define VS_FF_INFOINFERRED 0x00000010L
+#define VS_FF_SPECIALBUILD 0x00000020L
+
+/* ----- VS_VERSION.dwFileOS ----- */
+#define VOS_UNKNOWN 0x00000000L
+#define VOS_DOS 0x00010000L
+#define VOS_OS216 0x00020000L
+#define VOS_OS232 0x00030000L
+#define VOS_NT 0x00040000L
+
+#define VOS__BASE 0x00000000L
+#define VOS__WINDOWS16 0x00000001L
+#define VOS__PM16 0x00000002L
+#define VOS__PM32 0x00000003L
+#define VOS__WINDOWS32 0x00000004L
+
+#define VOS_DOS_WINDOWS16 0x00010001L
+#define VOS_DOS_WINDOWS32 0x00010004L
+#define VOS_OS216_PM16 0x00020002L
+#define VOS_OS232_PM32 0x00030003L
+#define VOS_NT_WINDOWS32 0x00040004L
+
+/* ----- VS_VERSION.dwFileType ----- */
+#define VFT_UNKNOWN 0x00000000L
+#define VFT_APP 0x00000001L
+#define VFT_DLL 0x00000002L
+#define VFT_DRV 0x00000003L
+#define VFT_FONT 0x00000004L
+#define VFT_VXD 0x00000005L
+#define VFT_STATIC_LIB 0x00000007L
+
+/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_DRV ----- */
+#define VFT2_UNKNOWN 0x00000000L
+#define VFT2_DRV_PRINTER 0x00000001L
+#define VFT2_DRV_KEYBOARD 0x00000002L
+#define VFT2_DRV_LANGUAGE 0x00000003L
+#define VFT2_DRV_DISPLAY 0x00000004L
+#define VFT2_DRV_MOUSE 0x00000005L
+#define VFT2_DRV_NETWORK 0x00000006L
+#define VFT2_DRV_SYSTEM 0x00000007L
+#define VFT2_DRV_INSTALLABLE 0x00000008L
+#define VFT2_DRV_SOUND 0x00000009L
+#define VFT2_DRV_COMM 0x0000000AL
+
+/* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_FONT ----- */
+#define VFT2_FONT_RASTER 0x00000001L
+#define VFT2_FONT_VECTOR 0x00000002L
+#define VFT2_FONT_TRUETYPE 0x00000003L
+
+/* ----- VerFindFile() flags ----- */
+#define VFFF_ISSHAREDFILE 0x0001
+
+#define VFF_CURNEDEST 0x0001
+#define VFF_FILEINUSE 0x0002
+#define VFF_BUFFTOOSMALL 0x0004
+
+/* ----- VerInstallFile() flags ----- */
+#define VIFF_FORCEINSTALL 0x0001
+#define VIFF_DONTDELETEOLD 0x0002
+
+#define VIF_TEMPFILE 0x00000001L
+#define VIF_MISMATCH 0x00000002L
+#define VIF_SRCOLD 0x00000004L
+
+#define VIF_DIFFLANG 0x00000008L
+#define VIF_DIFFCODEPG 0x00000010L
+#define VIF_DIFFTYPE 0x00000020L
+
+#define VIF_WRITEPROT 0x00000040L
+#define VIF_FILEINUSE 0x00000080L
+#define VIF_OUTOFSPACE 0x00000100L
+#define VIF_ACCESSVIOLATION 0x00000200L
+#define VIF_SHARINGVIOLATION 0x00000400L
+#define VIF_CANNOTCREATE 0x00000800L
+#define VIF_CANNOTDELETE 0x00001000L
+#define VIF_CANNOTRENAME 0x00002000L
+#define VIF_CANNOTDELETECUR 0x00004000L
+#define VIF_OUTOFMEMORY 0x00008000L
+
+#define VIF_CANNOTREADSRC 0x00010000L
+#define VIF_CANNOTREADDST 0x00020000L
+
+#define VIF_BUFFTOOSMALL 0x00040000L
+
+#ifndef RC_INVOKED /* RC doesn't need to see the rest of this */
+
+/* ----- Types and structures ----- */
+
+typedef signed short int SHORT;
+
+typedef struct tagVS_FIXEDFILEINFO
+{
+ DWORD dwSignature; /* e.g. 0xfeef04bd */
+ DWORD dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
+ DWORD dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
+ DWORD dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
+ DWORD dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
+ DWORD dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
+ DWORD dwFileFlagsMask; /* = 0x3F for version "0.42" */
+ DWORD dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
+ DWORD dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
+ DWORD dwFileType; /* e.g. VFT_DRIVER */
+ DWORD dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
+ DWORD dwFileDateMS; /* e.g. 0 */
+ DWORD dwFileDateLS; /* e.g. 0 */
+} VS_FIXEDFILEINFO;
+
+/* ----- Function prototypes ----- */
+
+UINT WINAPI VerFindFile(UINT uFlags, LPCSTR szFileName,
+ LPCSTR szWinDir, LPCSTR szAppDir,
+ LPSTR szCurDir, UINT FAR* lpuCurDirLen,
+ LPSTR szDestDir, UINT FAR* lpuDestDirLen);
+
+DWORD WINAPI VerInstallFile(UINT uFlags,
+ LPCSTR szSrcFileName, LPCSTR szDestFileName, LPCSTR szSrcDir,
+ LPCSTR szDestDir, LPCSTR szCurDir, LPSTR szTmpFile, UINT FAR* lpuTmpFileLen);
+
+/* Returns size of version info in bytes */
+DWORD WINAPI GetFileVersionInfoSize(
+ LPCSTR lpstrFilename, /* Filename of version stamped file */
+ DWORD FAR *lpdwHandle); /* Information for use by GetFileVersionInfo */
+
+/* Read version info into buffer */
+BOOL WINAPI GetFileVersionInfo(
+ LPCSTR lpstrFilename, /* Filename of version stamped file */
+ DWORD dwHandle, /* Information from GetFileVersionSize */
+ DWORD dwLen, /* Length of buffer for info */
+ void FAR* lpData); /* Buffer to place the data structure */
+
+/* Returns size of resource in bytes */
+DWORD WINAPI GetFileResourceSize(
+ LPCSTR lpstrFilename, /* Filename of version stamped file */
+ LPCSTR lpstrResType, /* Type: normally VS_FILE_INFO */
+ LPCSTR lpstrResID, /* ID: normally VS_VERSION_INFO */
+ DWORD FAR *lpdwFileOffset); /* Returns file offset of resource */
+
+/* Reads file resource into buffer */
+BOOL WINAPI GetFileResource(
+ LPCSTR lpstrFilename, /* Filename of version stamped file */
+ LPCSTR lpstrResType, /* Type: normally VS_FILE_INFO */
+ LPCSTR lpstrResID, /* ID: normally VS_VERSION_INFO */
+ DWORD dwFileOffset, /* File offset or NULL */
+ DWORD dwResLen, /* Length of resource to read or NULL */
+ void FAR* lpData); /* Pointer to data buffer */
+
+UINT WINAPI VerLanguageName(UINT wLang, LPSTR szLang, UINT nSize);
+
+UINT WINAPI GetWindowsDir(LPCSTR szAppDir, LPSTR lpBuffer, int nSize);
+
+UINT WINAPI GetSystemDir(LPCSTR szAppDir, LPSTR lpBuffer, int nSize);
+
+BOOL WINAPI VerQueryValue(const void FAR* pBlock, LPCSTR lpSubBlock,
+ void FAR* FAR* lplpBuffer, UINT FAR* lpuLen);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#pragma pack()
+
+#endif /* !RC_INVOKED */
+#endif /* !_INC_VER */
diff --git a/private/mvdm/wow16/inc/version.h b/private/mvdm/wow16/inc/version.h
new file mode 100644
index 000000000..3219b33a7
--- /dev/null
+++ b/private/mvdm/wow16/inc/version.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * *
+ * VERSION.H -- Version information for internal builds *
+ * *
+ * This file is only modified by the official builder to update the *
+ * VERSION, VER_PRODUCTVERSION and VER_PRODUCTVERSION_STR values *
+ * *
+ ****************************************************************************/
+
+#ifndef VS_FF_DEBUG
+/* ver.h defines constants needed by the VS_VERSION_INFO structure */
+#include <ver.h>
+#endif
+
+/*--------------------------------------------------------------*/
+/* the following entry should be phased out in favor of */
+/* VER_PRODUCTVERSION_STR, but is used in the shell today. */
+/*--------------------------------------------------------------*/
+
+
+/*--------------------------------------------------------------*/
+/* the following values should be modified by the official */
+/* builder for each build */
+/*--------------------------------------------------------------*/
+
+#define VERSION "3.1"
+#define VER_PRODUCTVERSION_STR "3.10\0"
+#define VER_PRODUCTVERSION 3,10,0,103
+
+/*--------------------------------------------------------------*/
+/* the following section defines values used in the version */
+/* data structure for all files, and which do not change. */
+/*--------------------------------------------------------------*/
+
+/* default is nodebug */
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+/* default is privatebuild */
+#ifndef OFFICIAL
+#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
+#else
+#define VER_PRIVATEBUILD 0
+#endif
+
+/* default is prerelease */
+#ifndef FINAL
+#define VER_PRERELEASE VS_FF_PRERELEASE
+#else
+#define VER_PRERELEASE 0
+#endif
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEOS VOS_DOS_WINDOWS16
+#define VER_FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)
+
+#define VER_COMPANYNAME_STR "Microsoft Corporation\0"
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows(TM) Operating System\0"
+#define VER_LEGALTRADEMARKS_STR \
+"Microsoft\256 is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
+
diff --git a/private/mvdm/wow16/inc/w32sys.h b/private/mvdm/wow16/inc/w32sys.h
new file mode 100644
index 000000000..425bdba76
--- /dev/null
+++ b/private/mvdm/wow16/inc/w32sys.h
@@ -0,0 +1,24 @@
+/*************************************************************************\
+* w32sys.h
+*
+* Win32S i/f
+*
+* 11-18-91 AviN Created
+\*************************************************************************/
+
+#ifndef APIENTRY
+#define APIENTRY _far _pascal _loadds
+#endif
+
+HANDLE APIENTRY GetPEResourceTable(WORD hFile);
+HANDLE APIENTRY LoadPEResource(HANDLE hFile, LPSTR lpResTable, LPSTR lpId, LPSTR lpType);
+WORD APIENTRY GetW32SysVersion(VOID);
+BOOL APIENTRY GetPEExeInfo(LPSTR lpFileName, LPSTR lpBuff, WORD cbBuff, WORD iInfo);
+WORD APIENTRY ExecPE(LPSTR lpPath, LPSTR lpCmd, WORD nCmdShow);
+BOOL APIENTRY IsPEFormat(LPSTR lpFileName, WORD hFile);
+
+/*
+ * Constants for GetPEExeInfo iInfo parameter
+ */
+#define GPEI_MODNAME 1
+#define GPEI_DESCRIPTION 2
diff --git a/private/mvdm/wow16/inc/wfwnet.h b/private/mvdm/wow16/inc/wfwnet.h
new file mode 100644
index 000000000..4848062ff
--- /dev/null
+++ b/private/mvdm/wow16/inc/wfwnet.h
@@ -0,0 +1,72 @@
+
+/*
+ * Windows/Network Interface
+ * Copyright (C) Microsoft 1989-1992
+ *
+ * Standard WINNET Driver Header File, spec version 3.10
+ * rev. 3.10.05 ;Internal
+ */
+
+
+#ifndef _INC_WFWNET
+#define _INC_WFWNET /* #defined if windows.h has been included */
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+
+#define CHAR char
+#define SHORT short
+#define LONG long
+
+typedef WORD far * LPWORD;
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned long ULONG;
+
+typedef unsigned short SHANDLE;
+typedef void far *LHANDLE;
+
+typedef unsigned char far *PSZ;
+typedef unsigned char near *NPSZ;
+
+typedef unsigned char far *PCH;
+typedef unsigned char near *NPCH;
+
+typedef UCHAR FAR *PUCHAR;
+typedef USHORT FAR *PUSHORT;
+typedef ULONG FAR *PULONG;
+
+
+#ifndef DRIVDATA
+/* structure for Device Driver data */
+
+typedef struct _DRIVDATA { /* driv */
+ LONG cb;
+ LONG lVersion;
+ CHAR szDeviceName[32];
+ CHAR abGeneralData[1];
+} DRIVDATA;
+typedef DRIVDATA far *PDRIVDATA;
+#endif
+
+#ifndef API
+#define API WINAPI
+#endif
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#endif /* _INC_WFWNET */
+
diff --git a/private/mvdm/wow16/inc/wife.h b/private/mvdm/wow16/inc/wife.h
new file mode 100644
index 000000000..7b1e51510
--- /dev/null
+++ b/private/mvdm/wow16/inc/wife.h
@@ -0,0 +1,1103 @@
+/****************************************************************************\
+*
+* WIFE.H : Far East Windows Intelligent Font Environment definitions
+*
+******************************************************************************
+*
+* History:
+* 21-Oct-1991 bent
+* initial merge of Far East 3.0 versions
+* Should be updated to resolve local inconsistencies.
+*
+* Copyright (c) 1990 Microsoft Corporation
+*
+* Brief instruction
+* -----------------
+*
+* This header file is a common single header for WIFE drivers. *
+* If you are a developer of FontDriver, please write coding as follow *
+*
+* #define WIFE_CREATE_FONTDRIVER *
+* #include <wife.h> *
+*
+* If you are a developer of DeviceDriver which are display or printer
+* drivers, please write coding as follow. *
+*
+* #define WIFE_CREATE_DEVICEDRIVER *
+* #include <wife.h> *
+*
+* If you don't define both of symbols, only common defenitions are
+* available.
+*
+* Aug.17,1990 Akira Kawamata [AkiraK] *
+*
+\****************************************************************************/
+
+/****** OS/2-like common data type definitions ******************************/
+
+#ifndef WIFEH_NODATATYPES
+typedef unsigned short int USHORT;
+typedef short int SHORT;
+typedef unsigned long ULONG;
+typedef LONG FAR * LPLONG;
+typedef LONG NEAR * NPLONG;
+typedef ULONG FAR * LPULONG;
+typedef ULONG NEAR * NPULONG;
+typedef SHORT FAR * LPSHORT;
+typedef SHORT NEAR * NPSHORT;
+typedef USHORT FAR * LPUSHORT;
+typedef USHORT NEAR * NPUSHORT;
+typedef char CHAR;
+typedef unsigned char UCHAR;
+
+typedef VOID NEAR * NPVOID;
+
+/* FIXED Number */
+typedef struct {
+ USHORT Fraction;
+ SHORT Integer;
+} FIXED;
+#endif //WIFEH_NODATATYPES
+
+/****** Graphics handling support definitions *******************************/
+
+#ifndef WIFEH_NOGRAPHSUPPORT
+/* rotation angle by 90degree */
+typedef enum {
+ ANGLE000 = 0,
+ ANGLE090 = 1,
+ ANGLE180 = 2,
+ ANGLE270 = 3
+} QUOTER_ANGLE;
+#define FixedToQuoterAngle(f) ((f.Integer/90)%4)
+#define RotationToQuoterAngle(r) ((r/900)%4)
+
+typedef DWORD PACKEDPOINT;
+typedef DWORD PACKEDLOGICALPOINT;
+typedef DWORD PACKEDPHYSICALPOINT;
+typedef struct {
+ short x,y;
+} XYPOINT;
+typedef union {
+ PACKEDPOINT packed;
+ XYPOINT point;
+} UNIONPOINT, NEAR * NPUNIONPOINT, FAR * LPUNIONPOINT;
+
+#define PartOfX(xy) ((SHORT)(xy))
+#define PartOfY(xy) ((SHORT)(((DWORD)(xy) >> 16) & 0xFFFF))
+#define MAKELONG_LO_HI MAKELONG
+#define PackXY(x,y) ((DWORD)MAKELONG_LO_HI((WORD)x,(WORD)y))
+#endif //WIFEH_NOGRAPHSUPPORT
+
+/****** UBCS : Unified Byte Character Set, data types defenition **********/
+
+#ifndef WIFEH_NOUBCS
+typedef USHORT UBCHAR;
+typedef UBCHAR NEAR * NPUBCHAR;
+typedef UBCHAR FAR * LPUBCHAR;
+
+#define UBEOS (0) /* End Of String */
+#define UBNEWLINE (0x0a0d) /* New Line (CR/LF) */
+
+#define IsSbcsUBChar(uc) ((uc & 0xff00) == 0x2000)
+#define IsDbcsUBChar(uc) ((uc & 0xff00) != 0x2000)
+#endif //WIFEH_NOUBCS
+
+/****** Utility macros *****************************************************/
+
+#ifndef WIFEH_NOUTILITYMACROS
+/* return type of GlobalLock is LPSTR, but it's to be LPVOID */
+#define AnyGlobalLock(h) ((LPVOID)GlobalLock(h))
+#define AnyLocalLock(h) ((NPVOID)LocalLock(h))
+#define TypedLocalLock(h,t) ((t NEAR *)LocalLock(h))
+#define TypedGlobalLock(h,t) ((t FAR *)GlobalLock(h))
+
+/* utility macro which is not included windows.h */
+#define MAKEWORD(l,h) ((WORD)((BYTE)l+(((BYTE)h) << 8)))
+#endif //WIFEH_NOUTILITYMACROS
+
+/****** GDIDEFS.H support definitions **************************************/
+
+#ifdef WIFE_ENABLE_GDIDEFS_SUPPORT
+typedef FONTINFO FAR * LPFONTINFO;
+typedef DRAWMODE FAR * LPDRAWMODE;
+typedef TEXTXFORM FAR * LPTEXTXFORM;
+#endif //WIFE_ENABLE_GDIDEFS_SUPPORT
+
+/****** Character set definitions ******************************************/
+
+#ifndef WIFEH_NOCHARSET
+typedef enum {
+ CHARSET_ANSI = 0,
+ CHARSET_SYMBOL = 2,
+ CHARSET_SHIFTJIS = 128,
+ CHARSET_KOREA = 129,
+ CHARSET_CHINESEBIG5 = 136,
+ CHARSET_OEM = 255
+} CHAR_SET;
+#endif //WIFEH_NOCHARSET
+
+
+/***************************************************************************/
+/****** Control function support definitions ******************************/
+
+#ifndef WIFEH_NOCONTROL
+
+/******************************************/
+/* FONT DRIVER MEDIA DESCRIPTER */
+/******************************************/
+#ifndef WIFEWH_NOMEDIA
+/* FDMEDIA enumration type */
+typedef enum {
+ FDMEDIA_ON_FILE = 1,
+ FDMEDIA_ON_DRIVER = 2,
+ FDMEDIA_ON_REMOVEABLE_HARDWARE = 4,
+ FDMEDIA_ON_FIXED_HARDWARE = 8,
+ FDMEDIA_UNDEFINED = 0x4000,
+ FDMEDIA_ANY_MEDIA = 0x7fff
+} FDMEDIA;
+#endif
+
+
+/******************************************/
+/* MINOR CHARACTER SETS DEFENITION */
+/******************************************/
+#ifndef WIFEH_NOMINORCHARSET_IN_JAPAN
+
+/* general default minor character set */
+#define FD_MINOR_CHARSET_DEFAULT 1
+
+/* Minor Character Set in Japan */
+#define FD_MINOR_CHARSET_NEW_JIS 1 /* new JIS */
+#define FD_MINOR_CHARSET_OLD_JIS 2 /* old JIS */
+#define FD_MINOR_CHARSET_IBM_JIS 4 /* IBM JIS */
+#define FD_MINOR_CHARSET_NEC_JIS 8 /* NEC JIS */
+
+#endif
+
+/******************************************/
+/* CODE AREA STRUCTURE */
+/******************************************/
+#ifndef WIFEH_NOCODEAREA
+
+typedef struct {
+ UBCHAR CodeFrom;
+ UBCHAR CodeTo;
+} CODEAREA, NEAR * NPCODEAREA, FAR * LPCODEAREA;
+
+#endif
+
+/******************************************/
+/* SPECIAL ESCAPE FUNCTION ORDERS */
+/******************************************/
+
+/* subfunction orders in WIFE */
+#define FD_CONTROL_RESERVED (0xa20)
+#define FD_CONTROL_RESERVED_LIMIT (FD_CONTROL_RESERVED+0x3f)
+
+/* standard subfunctions */
+#define FD_CONTROL_QUERY_ESC_SUPPORT (FD_CONTROL_RESERVED+0)
+#define FD_CONTROL_SUPPORT_CODES (FD_CONTROL_RESERVED+1)
+#define FD_CONTROL_NUMBER_OF_ATTRIBUTE (FD_CONTROL_RESERVED+2)
+#define FD_CONTROL_NAME_OF_ATTRIBUTE (FD_CONTROL_RESERVED+3)
+#define FD_CONTROL_SET_ATTRIBUTE (FD_CONTROL_RESERVED+4)
+#define FD_CONTROL_GET_ATTRIBUTE (FD_CONTROL_RESERVED+5)
+#define FD_CONTROL_SET_MINOR_CHARSET (FD_CONTROL_RESERVED+6)
+#define FD_CONTROL_GET_MINOR_CHARSET (FD_CONTROL_RESERVED+7)
+#define FD_CONTROL_GET_FONT_DRIVER_NAME (FD_CONTROL_RESERVED+8)
+#define FD_CONTROL_GET_FONT_PACK_NAME (FD_CONTROL_RESERVED+9)
+#define FD_CONTROL_GET_MEDIA (FD_CONTROL_RESERVED+10)
+#define FD_CONTROL_GET_DBCS_STRING_KERN (FD_CONTROL_RESERVED+11)
+
+/* EUDC related subfunctions */
+#define FD_CONTROL_LEVEL2_EUDC_INFO (FD_CONTROL_RESERVED+12)
+
+/* private interface subfunctions */
+#define FD_CONTROL_USER (FD_CONTROL_RESERVED+0x10)
+#define FD_CONTROL_USER_LIMIT (FD_CONTROL_RESERVED+0x1f)
+
+/* Chinese related functions */
+#define FD_CONTROL_GET_USERFONT_TECH (FD_CONTROL_RESERVED+0x20)
+#define FD_CONTROL_SET_USERFONT (FD_CONTROL_RESERVED+0x21)
+#define FD_CONTROL_SETUP_DIALOG (FD_CONTROL_RESERVED+0x22)
+#define FD_CONTROL_SET_DEFAULT_CHAR (FD_CONTROL_RESERVED+0x23)
+
+#ifdef WIFE_ENABLE_EUDC_SUPPORT
+
+typedef struct {
+ ULONG cb; /* length of this structure */
+ BOOL bForceFixedPitch; /* force fixed pitch */
+ BOOL bVerticalFont; /* vertical font flag */
+ FIXED fxCharRot; /* character rotation */
+ FIXED fxInlineDir; /* inline rotation */
+ USHORT usLimitWidth; /* maximum width of cachable */
+ SHORT sFixedASpace; /* font width when bForceFixedPitch is TRUE */
+ USHORT usFixedBSpace; /* font width when bForceFixedPitch is TRUE */
+ SHORT sFixedCSpace; /* font width when bForceFixedPitch is TRUE */
+} EUDC_CONTEXT, NEAR * NPEUDC_CONTEXT, FAR * LPEUDC_CONTEXT;
+
+#endif
+
+#endif
+
+
+#ifndef WIFEH_NOFDCOMMONDEFENITION
+typedef LONG HFF;
+typedef LONG HFC;
+typedef HANDLE HFD;
+typedef HANDLE HFB;
+
+#define FACESIZE 32
+#define GLYPHNAMESIZE 16
+
+#define WIFEERR_FACENAME_NOT_FOUND 23004L
+#define WIFEERR_FD_ALREADY_INSTALLED 23005L
+#define WIFEERR_INVALID_CONTEXTINFO 23006L
+#define WIFEERR_NOT_A_FONT_FILE 23007L
+#define WIFEERR_INVALID_FONT_SELECTION 23008L
+#define WIFEERR_INVALID_FORMAT 23009L
+#define WIFEERR_BUSY_HFC 230010L
+#define WIFEERR_INVALID_HFC 230011L
+#define WIFEERR_INVALID_INDEX 230012L
+#define WIFEERR_INVALID_QUERY_TYPE 230013L
+#define WIFEERR_CONTEXT_NOT_SET 230014L
+
+#define FD_QUERY_ABC_WIDTHS 2L
+#define FD_QUERY_KERNINGPAIRS 3L
+
+#define FD_QUERY_CHARIMAGE 1L
+#define FD_QUERY_OUTLINE 2L
+#define FD_QUERY_BITMAPMETRICS 4L
+
+typedef UBCHAR GLYPH; /* gi */
+typedef LPUBCHAR LPGLYPH; /* lpgi */
+
+typedef struct _POINTFX { /* ptfx, npptfx, lpptfx */
+ FIXED x;
+ FIXED y;
+} POINTFX, NEAR * NPPOINTFX, FAR * LPPOINTFX;
+
+typedef struct _ABC_TRIPLETS { /* abc, npabc, lpabc */
+ SHORT sA;
+ USHORT usB;
+ SHORT sC;
+} ABC_TRIPLETS, NEAR * NPABC_TRIPLETS, FAR * LPABC_TRIPLETS;
+
+typedef struct _SIZEL { /* sizl */
+ ULONG cx; // Width.
+ ULONG cy; // Height.
+} SIZEL;
+
+typedef struct _BITMAPMETRICS { /* bmm, npbmm, lpbmm */
+ SIZEL sizlExtent;
+ POINTFX pfxOrigin; /* Return character origin. */
+ POINTFX pfxCharInc; /* Return the device advance width */
+} BITMAPMETRICS, NEAR * NPBITMAPMETRICS, FAR * LPBITMAPMETRICS;
+
+typedef struct _MAT2 { /* mat */
+ FIXED eM11;
+ FIXED eM12;
+ FIXED eM21;
+ FIXED eM22;
+} MAT2;
+
+typedef struct _FD_KERNINGPAIRS { /* krnpr, npkrnpr, lpkrnpr */
+ GLYPH giFirst;
+ GLYPH giSecond;
+ LONG eKerningAmount;
+} FD_KERNINGPAIRS, NEAR * NPFD_KERNINGPAIRS, FAR * LPFD_KERNINGPAIRS;
+
+
+typedef struct _CONTEXTINFO { /* ci */
+ ULONG cb; /* Length in bytes of this structure. */
+ ULONG fl; /* Flags. */
+ SIZEL sizlPPM; /* Device resolution in pels/meter. */
+ POINTFX pfxSpot; /* Spot size in pels. */
+ MAT2 matXform; /* Notional to Device transform. */
+} CONTEXTINFO, NEAR * NPCONTEXTINFO, FAR * LPCONTEXTINFO;
+
+
+typedef struct _CHARATTR { /* chattr */
+ ULONG cb;
+ ULONG iQuery; /* Query type. */
+ GLYPH gi; /* Glyph index in font. */
+ LPBYTE lpBuffer; /* Bitmap buffer. */
+ ULONG cbLen; /* Size of buffer in bytes. */
+} CHARATTR, NEAR * NPCHARATTR, FAR * LPCHARATTR;
+
+
+/* bit-constants for fsType in IFIMETRICS */
+
+#define IFIMETRICS_FIXED 0x0001 /* Fixed pitch */
+#define IFIMETRICS_LICENSED 0x0002 /* dummy defenition */
+#define IFIMETRICS_SPARSE 0x0004 /* Incomplete font */
+#define IFIMETRICS_SCALEABLE 0x8000 /* scalable font */
+
+/* bit-constant for fsDefn in IFIMETRICS */
+
+#define IFIMETRICS_OUTLINE 0x0001 /* dummy definition */
+ /* 1 - Outline. 0 - Raster */
+
+/* bit-constant for fsSelection in IFIMETRICS */
+
+#define IFIMETRICS_ITALIC 0x8000 /*Italic */
+#define IFIMETRICS_UNDERSCORE 0x4000 /*Underscored */
+#define IFIMETRICS_OVERSTRUCK 0x2000 /*Overstruck */
+
+/* bit-constant for fsSelection in IFIMETRICS valid for bitmap fonts */
+
+#define IFIMETRICS_NEGATIVE 0x1000 /*Negative image */
+#define IFIMETRICS_HOLLOW 0x0800 /*Outline (hollow) */
+
+
+typedef struct _IFIMETRICS { /* ifim */
+ /* UNITS */
+ UCHAR szFamilyname[FACESIZE]; /*Font Family Name, e.g. Roman */
+ UCHAR szFacename[FACESIZE]; /*Face name, e.g. Tms Rmn Bold Italic */
+ UCHAR szGlyphlistName[GLYPHNAMESIZE]; /*e.g. PM316, Latin-2, Greek */
+ USHORT idRegistry; /*Dummy I */
+ SHORT sCapEmHeight; /*Height of uppercase M N */
+ SHORT sXHeight; /*Nominal height of lowercase N */
+ SHORT sMaxAscender; /*Maximum height above baseline of any char N */
+ SHORT sMaxDescender; /*Maximum depth below baseline of any char N */
+ SHORT sLowerCaseAscent; /*Maximum height above baseline of any a-z N */
+ SHORT sLowerCaseDescent; /*Maximum depth below basiline of any a-z N */
+ SHORT sInternalLeading; /*White space within character N */
+ SHORT sExternalLeading; /*White space between lines N */
+ SHORT sAveCharWidth; /*Weighted average character width N */
+ SHORT sMaxCharInc; /*Maximum character increment N */
+ SHORT sEmInc; /*Increment for Capitals (typically 'M') N */
+ SHORT sMaxBaselineExt; /*Height of character cell N */
+ FIXED fxCharSlope; /*Slope angle, degrees, clockwise D */
+ FIXED fxInlineDir; /*Drawing direction, degrees clockwise D */
+ FIXED fxCharRot; /*Glyph rotation in cell, degrees clockwise D */
+ USHORT usWeightClass; /*Character weight, 1-9 (1=ultra-light) I */
+ USHORT usWidthClass; /*Character width, 1-9 (1=ultra condensed) I */
+ SHORT sEmSquareSize; /*Em Square size, x-direction N */
+ GLYPH giFirstChar; /*Number of first glyph in font I */
+ GLYPH giLastChar; /*Number of last glyph in font I */
+ GLYPH giDefaultChar; /*Glyph used if requested glyph invalid I */
+ GLYPH giBreakChar; /*Space glyph I */
+ ULONG aulPanose [1]; /*Panose Number */
+ USHORT usNominalPointSize; /*Point size for which font was designed N */
+ USHORT usMinimumPointSize; /*Minimum point size scaling for font N */
+ USHORT usMaximumPointSize; /*Maximum point size scaling for font N */
+ USHORT fsType; /*Type indicators (see #defines) B */
+ USHORT fsDefn; /*Font definition data (see #defines) B */
+ USHORT fsSelection; /*Font selection flags (see #defines) B */
+ USHORT fsCapabilities; /*Font capabilities must be 0 B */
+ SHORT sSubscriptXSize; /*Size in x-direction of subscript N */
+ SHORT sSubscriptYSize; /*Size in y-direction of subscript N */
+ SHORT sSubscriptXOffset; /*Offset in x-direction of subscript N */
+ SHORT sSubscriptYOffset; /*Offset in y-direction of subscript N */
+ SHORT sSuperscriptXSize; /*Size in x-direction of superscript N */
+ SHORT sSuperscriptYSize; /*Size in y-direction of superscript N */
+ SHORT sSuperscriptXOffset; /*Offset in x-direction of superscript N */
+ SHORT sSuperscriptYOffset; /*Offset in y-direction of superscript N */
+ SHORT sUnderscoreSize; /*Underscore size N */
+ SHORT sUnderscorePosition; /*Underscore position N */
+ SHORT sStrikeoutSize; /*Strikeout size N */
+ SHORT sStrikeoutPosition; /*Strikeout position N */
+ SHORT cKerningPairs; /*Number of kerning pairs in pair table I */
+ ULONG ulFontClass; /*IBM font classification B */
+} IFIMETRICS, NEAR * NPIFIMETRICS, FAR * LPIFIMETRICS;
+
+#ifdef ENABLE_CONTROL_TAG
+
+/* Tag structure for Fd(i)Control */
+typedef struct {
+ USHORT SubFunction;
+ LPDEVICE lpDevice;
+ LPFONTINFO lpFontStructure;
+ LPTEXTXFORM lpXform;
+ LPVOID lpInData;
+} CONTROLTAG, FAR * LPCONTROLTAG;
+#else
+typedef struct {
+ USHORT SubFunction;
+ LPVOID lpDevice;
+ LPVOID lpFontStructure;
+ LPVOID lpXform;
+ LPVOID lpInData;
+} CONTROLTAG, FAR * LPCONTROLTAG;
+#endif
+
+#endif
+
+
+/****************************************/
+/* Attribute bits for FdOpenFontContext */
+/****************************************/
+#ifndef WIFEH_NOWIFEMAN_EUDCFONTCONTEXT
+#define OFC_EUDC_CONTEXT (0x80000000L)
+#endif
+
+
+#ifdef WIFE_CREATE_FONTDRIVER
+
+/***********************************************/
+/* PROTO-TYPE FOR EACH FUNCTION in FONT DRIVER */
+/***********************************************/
+
+LONG FAR PASCAL FdClaimFontFile( LPSTR lpszFileName );
+
+LONG FAR PASCAL FdConvertFontFile(
+ LPSTR lpszSrcFileName,
+ LPSTR lpszDestDirName,
+ LPSTR lpszResultPackName
+);
+HFF FAR PASCAL FdLoadFontFile( LPSTR lpszPackName );
+
+LONG FAR PASCAL FdUnloadFontFile( HFF hFF );
+
+LONG FAR PASCAL FdQueryFaces(
+ HFF hFF,
+ LPIFIMETRICS lpIfiMetrics,
+ ULONG cMetricLen,
+ ULONG cFontCount,
+ ULONG cStart
+);
+
+HFC FAR PASCAL FdOpenFontContext( HFF hFF, ULONG ulFont );
+
+LONG FAR PASCAL FdSetFontContext(
+ HFC hFC,
+ LPCONTEXTINFO lpContextInfo
+);
+
+LONG FAR PASCAL FdCloseFontContext( HFC hFC );
+
+LONG FAR PASCAL FdQueryFaceAttr(
+ HFC hFC,
+ ULONG iQuery,
+ LPVOID lpBuffer,
+ ULONG cb,
+ LPVOID lpIndex,
+ SHORT Start
+);
+
+LONG FAR PASCAL FdQueryCharAttr(
+ HFC hFC,
+ LPCHARATTR lpCharAttr,
+ LPBITMAPMETRICS lpbmm
+);
+
+SHORT FAR PASCAL FdControl(
+ HFC hFC,
+ LPCONTROLTAG lpControlTag,
+ LPVOID lpOutData
+);
+
+
+/******************************************/
+/* FAR PTR TO EACH FUNCTION */
+/******************************************/
+typedef LONG (FAR PASCAL * LPFDCLF)( LPSTR lpszFileName );
+
+typedef LONG (FAR PASCAL * LPFDCFF)(
+ LPSTR lpszSrcFileName,
+ LPSTR lpszDestDirName,
+ LPSTR lpszResultPackName
+);
+
+typedef HFF (FAR PASCAL * LPFDLFF)( LPSTR lpszPackName );
+
+typedef LONG (FAR PASCAL * LPFDQF)(
+ HFF hFF,
+ LPIFIMETRICS lpIfiMetrics,
+ ULONG cMetricLen,
+ ULONG cFontCount,
+ ULONG cStart
+);
+
+typedef LONG (FAR PASCAL * LPFDUFF)( HFF hFF );
+
+typedef HFC (FAR PASCAL * LPFDOFC)( HFF hFF, ULONG ulFont );
+
+typedef LONG (FAR PASCAL * LPFDSFC)(
+ HFC hFC,
+ LPCONTEXTINFO lpContextInfo
+);
+
+typedef LONG (FAR PASCAL * LPFDCFC)( HFC hFC );
+
+typedef LONG (FAR PASCAL * LPFDQFA)(
+ HFC hFC,
+ ULONG iQuery,
+ LPVOID lpBuffer,
+ ULONG cb,
+ LPVOID lpIndex,
+ SHORT Start
+);
+
+typedef LONG (FAR PASCAL * LPFDQCA)(
+ HFC hFC,
+ LPCHARATTR lpCharAttr,
+ LPBITMAPMETRICS lpbmm
+);
+
+typedef SHORT (FAR PASCAL * LPFDCTL)(
+ HFC hFC,
+ LPCONTROLTAG lpControlTag,
+ LPVOID lpOutData
+);
+
+typedef struct _FDHEADER { /* fdhdr */
+ ULONG cbLength; /* Length of FDHEADER */
+ UCHAR strId[16]; /* String 'WIFE FONT DRIVER' */
+ UCHAR szTechnology[40]; /* Identifier of Font Driver technology */
+ ULONG ulVersion; /* IFI version number (0x0100) */
+ ULONG ufDeviceCaps; /* Capabilities of device */
+ NPVOID npfddisp;
+ SHORT dummy1;
+} FDHEADER, NEAR * NPFDHEADER, FAR * LPFDHEADER;
+
+#endif
+
+#ifdef WIFE_CREATE_DEVICEDRIVER
+
+/***********************************************/
+/* PROTO-TYPE FOR EACH FUNCTION in WIFEMAN.DLL */
+/***********************************************/
+
+/***********************************************/
+/* Module Install Manager */
+/***********************************************/
+#ifndef WIFEH_NOWIFEMAN_MIM
+
+typedef BOOL (FAR PASCAL * LPCBMEAD)
+ ( LPSTR lpszFoundFileName, LPSTR lpszDescriptionName );
+BOOL FAR PASCAL MimEnumAvailableDrivers
+ ( LPSTR lpszSeachFilePath, LPCBMEAD lpfCallBack );
+
+typedef BOOL (FAR PASCAL * LPCBMEAP)
+ ( HFD hFD, LPSTR lpszPackName );
+BOOL FAR PASCAL MimEnumAvailablePacks
+ ( HFD hFD, LPSTR lpszPackName, LPCBMEAP lpfCallBack );
+
+HFD FAR PASCAL MimAddFontDriver( LPSTR lpszFileName );
+
+HFF FAR PASCAL MimAddFontPack( HFD hFD, LPSTR lpszPackName );
+
+BOOL FAR PASCAL MimRemoveFontDriver( HFD hFD );
+
+BOOL FAR PASCAL MimRemoveFontPack( HFD hFD, HFF hFontPack );
+
+HFD FAR PASCAL MimEnumFontDrivers( HFD hLastDriver );
+
+HFF FAR PASCAL MimEnumFontPacks( HFD hFD, HFF hLastPack );
+
+HFC FAR PASCAL MimOpenFontContext( HFD hFD, HFF hFF, ULONG ulFont );
+
+LONG FAR PASCAL MimCloseFontContext( HFD hFD, HFF hFF, HFC hFC );
+
+typedef enum {
+ MIMGETINFO_FD_DESCRIPTION = 0,
+ MIMGETINFO_FF_DESCRIPTION = 1,
+ MIMGETINFO_FD_FILENAME = 2,
+ MIMGETINFO_FF_FILENAME = 3,
+ MIMGETINFO_FD_USAGE = 4,
+ MIMGETINFO_FF_USAGE = 5,
+ MIMGETINFO_FD_INSTALL_COUNT = 6,
+ MIMGETINFO_FF_INSTALL_COUNT = 7
+} MIMGETINFO_ORDER;
+
+SHORT FAR PASCAL MimGetInformations(
+ MIMGETINFO_ORDER order,
+ HFD hFD,
+ HFF hFF,
+ LPVOID AnswerBuffer,
+ USHORT SizeOfBuffer
+);
+
+#endif
+
+/***********************************************/
+/* Font Driver Interface */
+/***********************************************/
+#ifndef WIFEH_NOWIFEMAN_FDI
+
+LONG FAR PASCAL FdiClaimFontFile( HFD hFD, LPSTR lpszFileName );
+
+LONG FAR PASCAL FdiConvertFontFile(
+ HFD hFD,
+ LPSTR lpszSrcFileName,
+ LPSTR lpszDestDirName,
+ LPSTR lpszResultPackName
+);
+
+HFF FAR PASCAL FdiLoadFontFile( HFD hFD, LPSTR lpszPackName );
+
+LONG FAR PASCAL FdiUnloadFontFile( HFD hFD, HFF hFF );
+
+LONG FAR PASCAL FdiQueryFaces(
+ HFD hFD,
+ HFF hFF, // Font File handle
+ LPIFIMETRICS lpIfiMetrics, // Buffer for the metrics
+ ULONG cMetricLen, // Length of the metrics structure
+ ULONG cFontCount, // # of fonts wanted.
+ ULONG cStart // index of the font to start with
+);
+
+HFC FAR PASCAL FdiOpenFontContext( HFD hFD, HFF hFF, ULONG ulFont );
+
+LONG FAR PASCAL FdiSetFontContext(
+ HFD hFD,
+ HFC hFC,
+ LPCONTEXTINFO lpContextInfo
+);
+
+LONG FAR PASCAL FdiCloseFontContext( HFD hFD, HFC hFC );
+
+LONG FAR PASCAL FdiQueryFaceAttr(
+ HFD hFD,
+ HFC hFC,
+ ULONG iQuery,
+ LPVOID lpBuffer,
+ ULONG cb,
+ LPVOID lpIndex,
+ SHORT Start
+);
+
+LONG FAR PASCAL FdiQueryCharAttr(
+ HFD hFD,
+ HFC hFC,
+ LPCHARATTR lpCharAttr,
+ LPBITMAPMETRICS lpbmm
+);
+
+SHORT FAR PASCAL FdiControl(
+ HFD hFD,
+ HFC hFC,
+ LPCONTROLTAG lpControlTag,
+ LPVOID lpOutData
+);
+
+#endif
+
+/***********************************************/
+/* Font Cacheing Manager */
+/***********************************************/
+#ifdef WIFE_ENABLE_FCM
+
+#define FCM_WIFE_CHARACTER 1
+#define FCM_CLIP_OUT 2
+#define FCM_LEFT_CLIP 0x0100
+#define FCM_RIGHT_CLIP 0x0200
+#define FCM_TOP_CLIP 0x0400
+#define FCM_BOTTOM_CLIP 0x0800
+
+typedef struct {
+ USHORT SizeOfStruct; /* size of structire */
+ WORD WifeFlag; /* FCM processing flags */
+ UBCHAR ubCode; /* character code */
+ LPSTR lpCacheBuffer; /* long ptr to cache bitmap */
+ SHORT nBitWidth; /* x size of character image */
+ SHORT nBitHeight; /* y size of character image */
+ SHORT nByteWidth; /* byte width size in alloctaed buffer */
+ USHORT InternalIndex; /* RESERVED FOR SYSTEM USE */
+} FCM_CHARACTERISTIC, NEAR *NP_FCM_CHARACTERISTIC, FAR *LP_FCM_CHARACTERISTIC;
+
+typedef struct {
+ USHORT SizeOfStruct; /* size of structire */
+ WORD WifeFlag; /* FCM processing flags */
+ UBCHAR ubCode; /* character code */
+ LPSTR lpCacheBuffer; /* long ptr to cache bitmap */
+ SHORT nBitWidth; /* x size of character image */
+ SHORT nBitHeight; /* y size of character image */
+ SHORT nByteWidth; /* byte width size in alloctaed buffer */
+ USHORT InternalIndex; /* RESERVED FOR SYSTEM USE */
+
+ SHORT xPosOnDst; /* x position on dst device */
+ SHORT yPosOnDst; /* y position on dst device */
+
+} FCM_EXTCHARACTERISTIC,
+ NEAR * NP_FCM_EXTCHARACTERISTIC, FAR * LP_FCM_EXTCHARACTERISTIC;
+
+
+HFB FAR PASCAL FcmCreateCacheBuffer(
+ HFD hFD,
+ HFF hFF,
+ ULONG ulFont,
+ LPTEXTXFORM lpXform,
+ USHORT usMinorCharSet,
+ USHORT usAttribute
+);
+
+BOOL FAR PASCAL FcmDeleteCacheBuffer( HFB hFontBuffer );
+
+SHORT FAR PASCAL FcmRequestImages(
+ HFB hFontBuffer,
+ LP_FCM_CHARACTERISTIC AnswerBuffer,
+ short length
+);
+
+BOOL FAR PASCAL FcmReleaseImages(
+ HFB hFontBuffer,
+ LP_FCM_CHARACTERISTIC AnswerBuffer,
+ short length
+);
+
+HFB FAR PASCAL FcmRequestDefaultFB(
+ LPFONTINFO lpFont,
+ LPTEXTXFORM lpTextXform
+);
+
+BOOL FAR PASCAL FcmReleaseDefaultFB( HFB hFB );
+
+#define FCMCALC_BIGFONT 1
+#define FCMCALC_ROUGHCLIPINFO 2
+#define FCMCALC_DETAILCLIPINFO 4
+
+DWORD FAR PASCAL FcmCalculateTextExtent(
+ HFB hFB,
+ LPSTR lpString,
+ short count,
+ LPFONTINFO lpFont,
+ LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpXform,
+ LPSHORT lpCharWidths,
+ USHORT usMode
+);
+
+SHORT FAR PASCAL FcmCalculateOutputPositions(
+ HFB hFB,
+ LP_FCM_EXTCHARACTERISTIC lpFcmCharacteristics,
+ SHORT nArrayLength,
+ LPSHORT lpx,
+ LPSHORT lpy,
+ LPRECT lpClipRect,
+ LPSTR FAR * lplpString,
+ LPSHORT lpcount,
+ LPFONTINFO lpFont,
+ LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpXform,
+ LPSHORT FAR * lplpCharWidths,
+ USHORT usMode
+);
+
+
+SHORT FAR PASCAL FcmCleanUp( VOID );
+
+HFB FAR PASCAL FcmEnumFontBuffers( HFB hLastBuffer );
+
+HFC FAR PASCAL FcmGetFontContext( HFB hFB );
+
+SHORT FAR PASCAL FcmCalcByteWidth( SHORT nBitWidth );
+
+SHORT FAR PASCAL FcmForceCacheIn( HFB hFB, LPUBCHAR lpubStr );
+
+BOOL FAR PASCAL FcmValidateFC( HFB hFB );
+
+BOOL FAR PASCAL FcmUnvalidateFC( HFB hFB );
+
+LONG FAR PASCAL FcmQueryFaceAttr(
+ HFB hFB,
+ ULONG iQuery,
+ LPABC_TRIPLETS lpBuffer,
+ ULONG cb,
+ LPUBCHAR lpIndex,
+ UBCHAR Start
+);
+
+#ifdef WIFE_ENABLE_FCM_CONTROL
+
+SHORT FAR PASCAL FcmIsProcessableDeviceControl(
+ HFB hFB,
+ SHORT nFunction,
+ GAIJIINFO FAR * lpGI
+);
+
+SHORT FAR PASCAL FcmProcessDeviceControl(
+ HFB hFB,
+ SHORT nFunction,
+ GAIJIINFO FAR * lpGI,
+ LPVOID lpOutData
+);
+
+#endif
+
+USHORT FAR PASCAL FcmGetEUDCLeadByteRange( HFB hFB );
+
+HFB FAR PASCAL FcmGetEUDCFB( HFB hFB );
+
+USHORT FAR PASCAL FcmGetCharWidth(
+ HFB hFB,
+ LPUSHORT lpBuffer,
+ USHORT wFirstChar,
+ USHORT wLastChar,
+ LPFONTINFO lpFont,
+ LPDRAWMODE lpDrawMode,
+ LPTEXTXFORM lpFontTrans,
+ USHORT usExpandPixels,
+ USHORT usMode
+);
+
+#endif
+
+#endif
+
+/***********************************************/
+/* WIFEMAN's Miscellaneous Service Functions */
+/***********************************************/
+#ifndef WIFEH_NOWIFEMAN_MISC
+
+BOOL FAR PASCAL MiscIsDBCSLeadByte( CHAR_SET CharSet, USHORT ch );
+
+#define MiscIsMBCSCharSet(c) (MiscIsDBCSLeadByte(c,0xffff))
+
+VOID FAR PASCAL MiscSetErroInfo( ULONG ErrorCode );
+
+ULONG FAR PASCAL MiscGetErroInfo( VOID );
+
+SHORT FAR PASCAL MiscWarningMessage(
+ HANDLE hInst,
+ USHORT idsMsg,
+ USHORT idsTitle,
+ USHORT mode
+);
+
+SHORT FAR PASCAL MiscWarningMessageWithArgument(
+ HANDLE hInst,
+ USHORT idsMsg,
+ USHORT idsTitle,
+ LPSTR lpszArgument,
+ USHORT mode
+);
+
+#ifdef ENABLE_MESSAGEBOX
+
+/* MessageBox() Flags */
+#define MB_OK 0x0000
+#define MB_OKCANCEL 0x0001
+#define MB_ABORTRETRYIGNORE 0x0002
+#define MB_YESNOCANCEL 0x0003
+#define MB_YESNO 0x0004
+#define MB_RETRYCANCEL 0x0005
+
+#define MB_ICONHAND 0x0010
+#define MB_ICONQUESTION 0x0020
+#define MB_ICONEXCLAMATION 0x0030
+#define MB_ICONASTERISK 0x0040
+
+#define MB_ICONINFORMATION MB_ICONASTERISK
+#define MB_ICONSTOP MB_ICONHAND
+
+#define MB_DEFBUTTON1 0x0000
+#define MB_DEFBUTTON2 0x0100
+#define MB_DEFBUTTON3 0x0200
+
+#define MB_APPLMODAL 0x0000
+#define MB_SYSTEMMODAL 0x1000
+#define MB_TASKMODAL 0x2000
+
+#define MB_NOFOCUS 0x8000
+
+#define MB_TYPEMASK 0x000F
+#define MB_ICONMASK 0x00F0
+#define MB_DEFMASK 0x0F00
+#define MB_MODEMASK 0x3000
+#define MB_MISCMASK 0xC000
+
+#endif /* ENABLE_MESSAGEBOX */
+
+USHORT FAR PASCAL ubstrlen( LPUBCHAR cp );
+
+LPUBCHAR FAR PASCAL ubstrcpy( LPUBCHAR dst, LPUBCHAR src );
+
+LPUBCHAR FAR PASCAL ubstrncpy( LPUBCHAR dst, LPUBCHAR src, USHORT limit );
+
+LPUBCHAR FAR PASCAL ubstrcat( LPUBCHAR dst, LPUBCHAR src );
+
+LPUBCHAR FAR PASCAL ubstrncat( LPUBCHAR dst, LPUBCHAR src, USHORT limit );
+
+SHORT FAR PASCAL ubstrcmp( LPUBCHAR str1, LPUBCHAR str2 );
+
+USHORT FAR PASCAL AscizToUz(
+ LPUBCHAR dst,
+ LPSTR src,
+ USHORT limit,
+ CHAR_SET CharSet
+);
+
+USHORT FAR PASCAL UzToAsciz(
+ LPSTR dst,
+ LPUBCHAR src,
+ USHORT limit
+);
+
+VOID FAR PASCAL MiscTrancateString(
+ LPSTR lpszStr,
+ SHORT length,
+ SHORT CharSet
+);
+
+#define MiscTrancateByDefaultCharSet(s,l) MiscTrancateString(s,l,-1)
+
+ULONG FAR PASCAL MiscGetVersion( VOID );
+
+USHORT FAR PASCAL MiscGetEUDCLeadByteRange( CHAR_SET csCharSet );
+
+BYTE FAR PASCAL MiscConvertFontFamily( LPSTR szFamilyName );
+
+BYTE FAR PASCAL MiscConvertCharSet( LPSTR CharSetString );
+
+#ifdef WIFE_ENABLE_FONT_STRUCT_CONVERT
+
+/* follow two values are only for usLogicalMapFlag parameter */
+/* in MiscIfiMetricsToLogFont function. */
+#define LOGMAP_IGNORE_DESCENT 1
+#define LOGMAP_IGNORE_INTERNAL_LEADING 2
+#define LOGMAP_NEGATIVE (0x8000)
+
+VOID FAR PASCAL MiscIfiMetricsToLogFont(
+ LPLOGFONT lpLogFont,
+ LPIFIMETRICS lpIFIMetrics,
+ USHORT usLogicalMapFlag
+);
+
+VOID FAR PASCAL MiscIfiMetricsToTextMetrics(
+ LPTEXTMETRIC lpTextMetrics,
+ LPIFIMETRICS lpIFIMetrics
+);
+
+#endif
+
+#ifdef WIFE_ENABLE_FONT_STRUCT_MAKE
+
+VOID FAR PASCAL MiscMakeTextXform(
+ LPTEXTXFORM lpTXF,
+ LPIFIMETRICS lpIM,
+ LPLOGFONT lpLF
+);
+
+#endif
+
+#ifndef WIFEH_NO_HUGE_SUPPORT
+LPVOID FAR PASCAL MiscAddHugePtr( LPVOID src, ULONG offset );
+USHORT FAR PASCAL MiscGetSegmentIncrement( VOID );
+#endif
+
+#ifndef WIFEH_NO_CONTROL_RANGES
+BOOL FAR PASCAL MiscIsWifeControl( SHORT function );
+BOOL FAR PASCAL MiscIsGaijiControl( SHORT function );
+#endif
+
+#ifndef WIFEH_NO_STRETCHER
+BOOL FAR PASCAL MiscStretchMonoFontImage(
+ LPVOID lpDestImage,
+ USHORT usSizeOfDestX,
+ USHORT usSizeOfDestY,
+ LPVOID lpSrcImage,
+ USHORT usSizeOfSrcX,
+ USHORT usSizeOfSrcY
+);
+#endif
+
+#ifdef WIFE_ENABLE_QUICK_SEARCH_TABLE
+
+typedef struct {
+ HFD hFD;
+ HFF hFF;
+ ULONG ulFont;
+ BOOL bScalable;
+ LOGFONT LogFont;
+}QUICK_SEARCH_TABLE, NEAR * NP_QUICK_SEARCH_TABLE, FAR * LP_QUICK_SEARCH_TABLE;
+
+LP_QUICK_SEARCH_TABLE FAR PASCAL MiscValidateQuickSearchTable(
+ USHORT usLogicalMapFlag
+);
+
+BOOL FAR PASCAL MiscUnvalidateQuickSearchTable(
+ USHORT usLogicalMapFlag
+);
+
+typedef LP_QUICK_SEARCH_TABLE (FAR PASCAL * LPMISCVALIDATEQST)(
+ USHORT usLogicalMapFlag
+);
+
+typedef BOOL (FAR PASCAL * LPMISCUNVALIDATEQST)(
+ USHORT usLogicalMapFlag
+);
+
+#define NMISCVALIDATEQST (67)
+#define NMISCUNVALIDATEQST (68)
+
+#endif
+
+#ifdef WIFE_ENABLE_NOTIFY_FUNCTIONS
+
+typedef enum {
+ WN_ADD_FONTDRIVER = 0,
+ WN_ADD_FONTPACKAGE = 1,
+ WN_REMOVE_FONTDRIVER = 2,
+ WN_REMOVE_FONTPACKAGE = 3,
+ WN_REGISTER_SYSTEM_EUDC_CHAR = 4,
+ WN_CHANGE_SYSTEM_EUDC_FILE = 5
+} WIFENOTIFY_ORDER;
+
+typedef struct {
+ HFD hTargetFontDriver;
+} WNS_FONTDRIVER;
+
+typedef struct {
+ HFD hTargetFontDriver;
+ HFF hTargetFontPackage;
+} WNS_FONTPACKAGE;
+
+typedef struct {
+ HFD hTargetFontDriver;
+ HFF hTargetFontPackage;
+ UBCHAR ubRegistedCharCode;
+} WNS_REGISTER_SYSTEM_EUDC_CHAR;
+
+typedef struct {
+ HFD hTargetFontDriver;
+ HFF hTargetFontPackage;
+ LPSTR lpszNewFileName;
+} WNS_WN_CHANGE_SYSTEM_EUDC_FILE;
+
+typedef BOOL (FAR PASCAL * LPNOTIFYCALLBACKFUNC)(
+ WIFENOTIFY_ORDER NotifyOrder,
+ LPVOID lpParamBlock
+);
+
+BOOL FAR PASCAL MiscRegisterNotifyFunction(
+ LPNOTIFYCALLBACKFUNC lpfnCallBack
+);
+
+BOOL FAR PASCAL MiscUnregisterNotifyFunction(
+ LPNOTIFYCALLBACKFUNC lpfnCallBack
+);
+
+#endif
+
+#endif
+
+
+/***********************************************/
+/* DIAGNOSTIC TEST&CHECKING FUNCTIONS */
+/***********************************************/
+#ifdef ENABLE_DIAGNOSTIC_FUNCTION
+
+/* test and return error code */
+SHORT FAR PASCAL DiagSelfCheck( VOID );
+
+/* invoke self test and make error record file, display warning dialog */
+SHORT FAR PASCAL DiagSelfCheckAndWarning( VOID );
+
+#endif
+
+
+/************************************************/
+/* THESE ARE PRIVATE INTERFACE FOR TEST PROGRAM */
+/************************************************/
+#ifdef ENABLE_TEST_PROGRAM_INTERFACE
+
+LPVOID FAR PASCAL DiagLocalLockAnything( LOCALHANDLE hAny );
+LPVOID FAR PASCAL DiagLocalUnlockAnything( LOCALHANDLE hAny );
+SHORT FAR PASCAL DiagGetConfirmString( LPSTR buffer, SHORT length );
+
+#endif
+
+/* end of wife.h */
diff --git a/private/mvdm/wow16/inc/win3deb.inc b/private/mvdm/wow16/inc/win3deb.inc
new file mode 100644
index 000000000..faf9579ad
--- /dev/null
+++ b/private/mvdm/wow16/inc/win3deb.inc
@@ -0,0 +1,186 @@
+; declare a simple interface to control debugging messages
+
+BegData macro
+ _DATA SEGMENT PARA PUBLIC 'DATA'
+endm
+
+EndData macro
+ _DATA ENDS
+endm
+
+DEB_ERROR = 1
+DEB_WARN = 2
+DEB_TRACE = 4
+DEB_FERROR = 8 ;; fatal error - terminate app
+DEB_IERROR = 10h
+DEB_IWARN = 20h
+DEB_ITRACE = 40h
+DEB_IFERROR = 80h ;; fatal error - terminate app
+DEB_FERRORS = DEB_FERROR or DEB_IFERROR
+DEB_ERRORS = DEB_ERROR OR DEB_IERROR OR DEB_FERRORS
+DEB_WARNS = DEB_WARN OR DEB_IWARN
+DEB_TRACES = DEB_TRACE OR DEB_ITRACE
+DEB_NOCRLF = 8000h ;; No CR/LF in string
+DEB_BREAKLEVEL = DEB_ERRORS or 0ff00h
+DEB_INFOLEVEL = DEB_BREAKLEVEL or DEB_WARNS
+
+DECLARE_DEBUG macro comp
+
+ ifdef Win3DebData
+ else
+ extrn _Win3InfoLevel:word, _Win3BreakLevel:word
+
+; BegData
+ extrn _&comp&InfoLevel:word, _&comp&BreakLevel:word
+; EndData
+
+ endif
+ ifdef Win3Deb
+ else
+ extrn _&comp&DebugTest:far
+ endif
+
+ &comp&DebugOut macro flag, string, vals
+ local sloc, cnt
+ BegData
+ sloc label byte
+ db string
+ ife (flag) and DEB_NOCRLF
+ db 13, 10
+ endif
+ db 0
+ EndData
+ cnt = 0
+ irp foo, <vals>
+ push foo
+ cnt = cnt + 1
+ endm
+ push offset sloc
+ push flag AND NOT DEB_NOCRLF
+ call _&comp&DebugTest
+ add sp, 4+(2*cnt)
+ endm
+endm
+
+declare_areas macro name, comp, list
+ deb_loc = 100h
+ deb_areas equ <list>
+
+ irp val, <list>
+ DEB_&comp&&val = deb_loc
+ deb_loc = deb_loc + deb_loc
+ ifdef Win3Deb
+ BegData
+ STR_&comp&&val label byte
+ db "&name &val: ", 0
+ EndData
+ endif
+ endm
+ ifdef Win3Deb
+ BegData
+ STR_&comp&Trace db "Trace: ", 0
+ STR_&comp&Warn db "Warning: ", 0
+ STR_&comp&Error db "Error: ", 0
+ STR_&comp db "&name: ", 0
+ STR_&comp&table dw dataoffset STR_&comp
+ irp val, <list>
+ dw dataoffset STR_&comp&&val
+ endm
+ EndData
+ endif
+endm
+
+declare_infolevel macro comp
+ local skip
+ BegData
+; public _&comp&InfoLevel, _&comp&BreakLevel
+; _&comp&InfoLevel dw DEB_INFOLEVEL ;; component can override
+; _&comp&BreakLevel dw DEB_BREAKLEVEL
+ EndData
+
+ _&comp&DebugTest proc far ;; Per-component - check right flags
+ public _&comp&DebugTest
+ push bp
+ mov bp, sp
+ push ds
+ push ax
+ mov ax, _DATA
+ cmp ax, 1000h ;; DATA should be selector, not addr
+ jnc skip
+ mov ds, ax
+ assume ds:_DATA
+
+ mov ax, [bp+6] ;; See if component enabled
+ and ax, [_&comp&InfoLevel]
+ cmp ax, [bp+6]
+ jnz skip
+
+ push es ;; See if system enabled
+ push seg _Win3InfoLevel
+ pop es
+ and al, byte ptr es:[_Win3InfoLevel] ;; test low 8 bits for system-wide
+ pop es
+ cmp ax, [bp+6]
+ jnz skip
+
+ ;; Print it, so format message
+ push bx
+ test al, DEB_ERRORS
+ mov bx, dataoffset STR_&comp&Error
+ jnz @F
+ test al, DEB_WARNS
+ mov bx, dataoffset STR_&comp&Warn
+ jnz @F
+ test al, DEB_TRACES
+ mov bx, dataoffset STR_&comp&Trace
+ jnz @F
+ jmp short deb_no_msg_type
+
+@@:
+ push bx
+ call KOutDSStr
+deb_no_msg_type:
+ mov bx, dataoffset STR_&comp&Table
+ or ah, ah
+ jz deb_show_it
+@@:
+ add bx, 2
+ shr ah, 1
+ jnz @B
+deb_show_it:
+ push [bx] ;; push parameter
+ call KOutDSStr
+ pop bx ;; restore reg
+
+ pop ax
+ push [bp+8]
+ call KOutDSStr
+ push ax
+ mov ax, [bp+6]
+ and ax, [_&comp&BreakLevel]
+ jz skip
+
+ push es
+ push seg _Win3BreakLevel
+ pop es
+ and ax, es:_Win3BreakLevel
+ pop es
+ jz skip
+
+ int 3
+ skip:
+ test byte ptr [bp+6], DEB_FERRORS
+ jz @F
+ push 0
+ push DGROUP
+ push word ptr [bp+8]
+ cCall FatalAppExit ;,<0,DGROUP,[bp+8]>
+@@:
+ pop ax
+ pop ds
+ pop bp
+ retf
+ _&comp&DebugTest endp
+endm
+
+
diff --git a/private/mvdm/wow16/inc/windefs.inc b/private/mvdm/wow16/inc/windefs.inc
new file mode 100644
index 000000000..c4b619ab8
--- /dev/null
+++ b/private/mvdm/wow16/inc/windefs.inc
@@ -0,0 +1,124 @@
+;***************************************************************************
+; *
+; Copyright (C) 1983,1984 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+; Macros for disabling and restoring hardware interrupt enable flag
+;
+; The LeaveCrit macro has been updated for the mask problem on
+; the 80286 processor.
+
+include vint.inc
+
+
+EnterCrit MACRO
+ pushf
+ FCLI
+ENDM
+
+LeaveCrit macro reg ;;this macro will restore the state of
+ifnb <reg> ;;the interrupt flag to what is was
+ pop reg&x ;;before EnterCrit. All other flags
+ test reg&h, 2 ;;are discarded.
+ jz @f
+ FSTI
+@@:
+else
+ push bp
+ mov bp, sp
+ test byte ptr [bp+3], 2
+ jz @f
+ FSTI
+@@:
+ pop bp
+ popf
+endif
+ endm
+
+
+if 0
+POPFF equ <LeaveCrit>
+
+LeaveCrit MACRO
+ POPFF
+ENDM
+endif
+
+POPFF MACRO ;;this macro will restore ALL flags,
+ local a ;;EXCEPT the interrupt flag, to
+ jmp $+3 ;;their previous state
+a label near
+ iret
+ push cs
+ call a
+ENDM
+
+
+
+
+;***************************************************************************
+; *
+; Inquire data structures for Timer, Keyboard, Mouse and Cursor modules *
+; *
+;***************************************************************************
+
+TIMERINFO STRUC
+tiResolution DD 0 ; #microseconds each timer tick
+TIMERINFO ENDS
+
+KBINFO STRUC
+kbRanges DB 4 dup (0) ; Far East ranges for KANJI
+kbStateSize DW 0 ; #bytes of state info maintained by TOASCII
+KBINFO ENDS
+
+
+MOUSEINFO STRUC
+msExists DB 0 ; true => mouse exists
+msRelative DB 0 ; true => relative coordinate
+msNumButtons DW 0 ; number of buttons on the mouse
+msRate DW 0 ; maximum rate of mouse input events
+msXThresh DW 0 ; threshold before acceleration
+msYThresh DW 0 ;
+msXRes DW 0 ; x resolution
+msYRes DW 0 ; y resolution
+MOUSEINFO ENDS
+
+
+CURSORINFO STRUC
+dpXRate DW 0 ; horizontal mickey/pixel ratio
+dpYRate DW 0 ; vertical mickey/pixel ratio
+CURSORINFO ENDS
+
+
+;***************************************************************************
+; *
+; Cursor data structure passed to OEM routines. Defines a graphics display*
+; cursor in terms of a hotspot, an AND mask and an XOR mask. The hot *
+; spot defines the pixel within the cursor that is the cursor is "pointing"*
+; to. So when displaying a cursor at location X,Y the pixel that *
+; is the hot spot should be painted at that X,Y coordinate. The "shape" *
+; of the cursor is defined by two pixel masks. The first mask is ANDed *
+; with the bits in the display bitmap and the second mask is XORed with *
+; the result to determine the bits that will be placed in the display *
+; bitmap. The bits for the masks are in the byte array that begins *
+; at the csBits field, with the AND mask bits first, followed by the *
+; XOR mask bits. The csWidthBytes field is the width of ONE mask, in *
+; bytes. Currently, MS-WIN will only generate cursors whose width and *
+; height are both 16. *
+; *
+;***************************************************************************
+
+cursorShape STRUC
+csHotX DW 0
+csHotY DW 0
+csWidth DW 0
+csHeight DW 0
+csWidthBytes DW 0
+csColor DW 0
+ ; Beginning of an array of bytes that contain the bits for the AND and
+ ; XOR masks. The first csHeight * csWidthBytes bytes contain the bits
+ ; for the AND mask and the next csHeight * csWidthBytes bytes contain
+ ; the bits for the XOR mask.
+;csBits DB 2*2*16 DUP (?)
+cursorShape ENDS
diff --git a/private/mvdm/wow16/inc/windows.h b/private/mvdm/wow16/inc/windows.h
new file mode 100644
index 000000000..6895b3330
--- /dev/null
+++ b/private/mvdm/wow16/inc/windows.h
@@ -0,0 +1,5724 @@
+/*****************************************************************************\
+* *
+* windows.h - Windows functions, types, and definitions *
+* *
+* Version 3.10 *
+* *
+* Copyright (c) 1985-1992, Microsoft Corp. All rights reserved. *
+* *
+*******************************************************************************
+*
+* The following symbols control inclusion of various parts of this file:
+*
+* WINVER Windows version number (0x030a). To exclude
+* definitions introduced in version 3.1 (or above)
+* #define WINVER 0x0300 before #including <windows.h>
+*
+* #define: To prevent inclusion of:
+*
+* NOKERNEL KERNEL APIs and definitions
+* NOGDI GDI APIs and definitions
+* NOUSER USER APIs and definitions
+* NOSOUND Sound APIs and definitions
+* NOCOMM Comm driver APIs and definitions
+* NODRIVERS Installable driver APIs and definitions
+*
+* NOMINMAX min() and max() macros
+* NOLOGERROR LogError() and related definitions
+* NOPROFILER Profiler APIs
+* NOMEMMGR Local and global memory management
+* NOLFILEIO _l* file I/O routines
+* NOOPENFILE OpenFile and related definitions
+* NORESOURCE Resource management
+* NOATOM Atom management
+* NOLANGUAGE Character test routines
+* NOLSTRING lstr* string management routines
+* NODBCS Double-byte character set routines
+* NOKEYBOARDINFO Keyboard driver routines
+* NOGDICAPMASKS GDI device capability constants
+* NOCOLOR COLOR_* color values
+* NOGDIOBJ GDI pens, brushes, fonts
+* NODRAWTEXT DrawText() and related definitions
+* NOTEXTMETRIC TEXTMETRIC and related APIs
+* NOSCALABLEFONT Truetype scalable font support
+* NOBITMAP Bitmap support
+* NORASTEROPS GDI Raster operation definitions
+* NOMETAFILE Metafile support
+* NOSYSMETRICS GetSystemMetrics() and related SM_* definitions
+* NOSYSTEMPARAMSINFO SystemParametersInfo() and SPI_* definitions
+* NOMSG APIs and definitions that use MSG structure
+* NOWINSTYLES Window style definitions
+* NOWINOFFSETS Get/SetWindowWord/Long offset definitions
+* NOSHOWWINDOW ShowWindow and related definitions
+* NODEFERWINDOWPOS DeferWindowPos and related definitions
+* NOVIRTUALKEYCODES VK_* virtual key codes
+* NOKEYSTATES MK_* message key state flags
+* NOWH SetWindowsHook and related WH_* definitions
+* NOMENUS Menu APIs
+* NOSCROLL Scrolling APIs and scroll bar control
+* NOCLIPBOARD Clipboard APIs and definitions
+* NOICONS IDI_* icon IDs
+* NOMB MessageBox and related definitions
+* NOSYSCOMMANDS WM_SYSCOMMAND SC_* definitions
+* NOMDI MDI support
+* NOCTLMGR Control management and controls
+* NOWINMESSAGES WM_* window messages
+* NOHELP Help support
+*
+\****************************************************************************/
+
+#ifndef _INC_WINDOWS
+#define _INC_WINDOWS /* #defined if windows.h has been included */
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifdef NOWIN31 /* ;Internal */
+#define WINVER 0x0300 /* ;Internal */
+#endif /* ;Internal */
+ /* ;Internal */
+/* If WINVER is not defined, assume version 3.1 */
+#ifndef WINVER
+#define WINVER 0x030a
+#endif
+
+#ifdef RC_INVOKED
+/* Don't include definitions that RC.EXE can't parse */
+#define NOATOM
+#define NOGDI
+#define NOGDICAPMASKS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NORASTEROPS
+#define NOSCROLL
+#define NOSOUND
+#define NOSYSMETRICS
+#define NOTEXTMETRIC
+#define NOWH
+#define NODBCS
+#define NOSYSTEMPARAMSINFO
+#define NOCOMM
+#define NOOEMRESOURCE
+#endif /* RC_INVOKED */
+
+/* Temp internal compatibility hacks */ /* ;Internal */
+#define NOOEMRESOURCE /* ;Internal */
+#ifdef OEMRESOURCE /* ;Internal */
+#undef NOOEMRESOURCE /* ;Internal */
+#endif /* ;Internal */
+#define NOCOMM /* ;Internal */
+#ifdef USECOMM /* ;Internal */
+#undef NOCOMM /* ;Internal */
+#endif /* ;Internal */
+ /* ;Internal */
+/* Handle OEMRESOURCE for 3.0 compatibility */
+#if (WINVER < 0x030a)
+#define NOOEMRESOURCE
+#ifdef OEMRESOURCE
+#undef NOOEMRESOURCE
+#endif
+#endif
+
+/******* Common definitions and typedefs ***********************************/
+
+#define VOID void
+
+#define FAR _far
+#define NEAR _near
+#define PASCAL _pascal
+#define CDECL _cdecl
+#define CONST const /* ;Internal */
+
+#ifdef BUILDDLL /* ;Internal */
+#define WINAPI _loadds _far _pascal /* ;Internal */
+#define CALLBACK _loadds _far _pascal /* ;Internal */
+#else /* ;Internal */
+#define WINAPI _far _pascal
+#define CALLBACK _far _pascal
+#endif /* ;Internal */
+ /* ;Internal */
+#define API WINAPI /* ;Internal */
+
+/****** Simple types & common helper macros *********************************/
+
+typedef int BOOL;
+#define FALSE 0
+#define TRUE 1
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+
+typedef unsigned int UINT;
+
+#ifdef STRICT
+typedef signed long LONG;
+#else
+#define LONG long
+#endif
+
+#define LOBYTE(w) ((BYTE)(w))
+#define HIBYTE(w) ((BYTE)(((UINT)(w) >> 8) & 0xFF))
+
+#define LOWORD(l) ((WORD)(DWORD)(l))
+#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))
+
+#define MAKELONG(low, high) ((LONG)(((WORD)(low)) | (((DWORD)((WORD)(high))) << 16)))
+
+#ifndef NOMINMAX
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#endif /* NOMINMAX */
+
+/* Types use for passing & returning polymorphic values */
+typedef UINT WPARAM;
+typedef LONG LPARAM;
+typedef LONG LRESULT;
+
+#define MAKELPARAM(low, high) ((LPARAM)MAKELONG(low, high))
+#define MAKELRESULT(low, high) ((LRESULT)MAKELONG(low, high))
+
+/****** Common pointer types ************************************************/
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+typedef char NEAR* PSTR;
+typedef char NEAR* NPSTR;
+
+#define SZ char /* ;Internal */
+
+typedef char FAR* LPSTR;
+typedef const char FAR* LPCSTR;
+
+typedef BYTE NEAR* PBYTE;
+typedef BYTE FAR* LPBYTE;
+
+typedef int NEAR* PINT;
+typedef int FAR* LPINT;
+
+typedef WORD NEAR* PWORD;
+typedef WORD FAR* LPWORD;
+
+typedef long NEAR* PLONG;
+typedef long FAR* LPLONG;
+
+typedef DWORD NEAR* PDWORD;
+typedef DWORD FAR* LPDWORD;
+
+typedef void FAR* LPVOID;
+
+#define MAKELP(sel, off) ((void FAR*)MAKELONG((off), (sel)))
+#define SELECTOROF(lp) HIWORD(lp)
+#define OFFSETOF(lp) LOWORD(lp)
+
+#define FIELDOFFSET(type, field) ((int)(&((type NEAR*)1)->field)-1)
+
+/****** Common handle types *************************************************/
+
+#ifdef STRICT
+typedef const void NEAR* HANDLE;
+#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \
+ typedef const struct name##__ NEAR* name
+#define DECLARE_HANDLE32(name) struct name##__ { int unused; }; \
+ typedef const struct name##__ FAR* name
+#else /* STRICT */
+typedef UINT HANDLE;
+#define DECLARE_HANDLE(name) typedef UINT name
+#define DECLARE_HANDLE32(name) typedef DWORD name
+#endif /* !STRICT */
+
+typedef HANDLE* PHANDLE;
+typedef HANDLE NEAR* SPHANDLE;
+typedef HANDLE FAR* LPHANDLE;
+
+typedef HANDLE HGLOBAL;
+typedef HANDLE HLOCAL;
+
+typedef HANDLE GLOBALHANDLE;
+typedef HANDLE LOCALHANDLE;
+
+typedef UINT ATOM;
+
+#ifdef STRICT
+typedef void (CALLBACK* FARPROC)(void);
+typedef void (NEAR PASCAL* NEARPROC)(void);
+#else
+typedef int (CALLBACK* FARPROC)();
+typedef int (NEAR PASCAL* NEARPROC)();
+#endif
+
+DECLARE_HANDLE(HSTR);
+
+/****** KERNEL typedefs, structures, and functions **************************/
+
+DECLARE_HANDLE(HINSTANCE);
+typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */
+
+#ifndef NOKERNEL
+
+/****** Application entry point function ************************************/
+
+#ifdef STRICT
+int PASCAL WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
+#endif
+
+/****** System Information **************************************************/
+
+DWORD WINAPI GetVersion(void);
+
+DWORD WINAPI GetFreeSpace(UINT);
+UINT WINAPI GetCurrentPDB(void);
+
+UINT WINAPI GetWindowsDirectory(LPSTR, UINT);
+UINT WINAPI GetSystemDirectory(LPSTR, UINT);
+
+#if (WINVER >= 0x030a)
+UINT WINAPI GetFreeSystemResources(UINT);
+#define GFSR_SYSTEMRESOURCES 0x0000
+#define GFSR_GDIRESOURCES 0x0001
+#define GFSR_USERRESOURCES 0x0002
+#define GFSR_VALID 0x0002 /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+DWORD WINAPI GetWinFlags(void);
+
+#define WF_PMODE 0x0001
+#define WF_CPU286 0x0002
+#define WF_CPU386 0x0004
+#define WF_CPU486 0x0008
+#define WF_STANDARD 0x0010
+#define WF_WIN286 0x0010
+#define WF_ENHANCED 0x0020
+#define WF_WIN386 0x0020
+#define WF_CPU086 0x0040
+#define WF_CPU186 0x0080
+#define WF_LARGEFRAME 0x0100
+#define WF_CPUEM 0x0100
+#define WF_SMALLFRAME 0x0200
+#define WF_80x87 0x0400
+#define WF_PAGING 0x0800
+#define WF_WINNT 0x4000
+#define WF_WLO 0x8000
+
+LPSTR WINAPI GetDOSEnvironment(void);
+
+DWORD WINAPI GetCurrentTime(void);
+DWORD WINAPI GetTickCount(void);
+DWORD WINAPI GetTimerResolution(void);
+
+/****** Error handling ******************************************************/
+
+#if (WINVER >= 0x030a)
+#ifndef NOLOGERROR
+
+void WINAPI LogError(UINT err, void FAR* lpInfo);
+void WINAPI LogParamError(UINT err, FARPROC lpfn, void FAR* param);
+
+/****** LogParamError/LogError values */
+
+/* Error modifier bits */
+
+#define ERR_WARNING 0x8000
+#define ERR_PARAM 0x4000
+
+/* Internal error value masks */ /* ;Internal */
+#define ERR_TYPE_MASK 0x0fff /* ;Internal */
+#define ERR_FLAGS_MASK 0xc000 /* ;Internal */
+ /* ;Internal */
+#define ERR_SIZE_MASK 0x3000
+#define ERR_SIZE_SHIFT 12 /* ;Internal */
+#define ERR_BYTE 0x1000
+#define ERR_WORD 0x2000
+#define ERR_DWORD 0x3000
+ /* ;Internal */
+/* Error option flags (set by [kernel] ErrorOptions win.ini variable) *//* ;Internal */
+ /* ;Internal */
+#define ERO_PARAM_ERROR_BREAK 0x0001 /* ;Internal */
+#define ERO_BUFFER_FILL 0x0002 /* ;Internal */
+
+/****** LogParamError() values */
+
+/* Generic parameter values */
+#define ERR_BAD_VALUE 0x6001
+#define ERR_BAD_FLAGS 0x6002
+#define ERR_BAD_INDEX 0x6003
+#define ERR_BAD_DVALUE 0x7004
+#define ERR_BAD_DFLAGS 0x7005
+#define ERR_BAD_DINDEX 0x7006
+#define ERR_BAD_PTR 0x7007
+#define ERR_BAD_FUNC_PTR 0x7008
+#define ERR_BAD_SELECTOR 0x6009
+#define ERR_BAD_STRING_PTR 0x700a
+#define ERR_BAD_HANDLE 0x600b
+
+/* KERNEL parameter errors */
+#define ERR_BAD_HINSTANCE 0x6020
+#define ERR_BAD_HMODULE 0x6021
+#define ERR_BAD_GLOBAL_HANDLE 0x6022
+#define ERR_BAD_LOCAL_HANDLE 0x6023
+#define ERR_BAD_ATOM 0x6024
+#define ERR_BAD_HFILE 0x6025
+
+/* USER parameter errors */
+#define ERR_BAD_HWND 0x6040
+#define ERR_BAD_HMENU 0x6041
+#define ERR_BAD_HCURSOR 0x6042
+#define ERR_BAD_HICON 0x6043
+#define ERR_BAD_HDWP 0x6044
+#define ERR_BAD_CID 0x6045
+#define ERR_BAD_HDRVR 0x6046
+
+/* GDI parameter errors */
+#define ERR_BAD_COORDS 0x7060
+#define ERR_BAD_GDI_OBJECT 0x6061
+#define ERR_BAD_HDC 0x6062
+#define ERR_BAD_HPEN 0x6063
+#define ERR_BAD_HFONT 0x6064
+#define ERR_BAD_HBRUSH 0x6065
+#define ERR_BAD_HBITMAP 0x6066
+#define ERR_BAD_HRGN 0x6067
+#define ERR_BAD_HPALETTE 0x6068
+#define ERR_BAD_HMETAFILE 0x6069
+
+/* Debug fill constants */ /* ;Internal */
+ /* ;Internal */
+#define DBGFILL_ALLOC 0xfd /* ;Internal */
+#define DBGFILL_FREE 0xfb /* ;Internal */
+#define DBGFILL_BUFFER 0xf9 /* ;Internal */
+#define DBGFILL_STACK 0xf7 /* ;Internal */
+
+/**** LogError() values */
+
+/* KERNEL errors */
+#define ERR_GALLOC 0x0001
+#define ERR_GREALLOC 0x0002
+#define ERR_GLOCK 0x0003
+#define ERR_LALLOC 0x0004
+#define ERR_LREALLOC 0x0005
+#define ERR_LLOCK 0x0006
+#define ERR_ALLOCRES 0x0007
+#define ERR_LOCKRES 0x0008
+#define ERR_LOADMODULE 0x0009
+
+/* USER errors */
+#define ERR_CREATEDLG 0x0040
+#define ERR_CREATEDLG2 0x0041
+#define ERR_REGISTERCLASS 0x0042
+#define ERR_DCBUSY 0x0043
+#define ERR_CREATEWND 0x0044
+#define ERR_STRUCEXTRA 0x0045
+#define ERR_LOADSTR 0x0046
+#define ERR_LOADMENU 0x0047
+#define ERR_NESTEDBEGINPAINT 0x0048
+#define ERR_BADINDEX 0x0049
+#define ERR_CREATEMENU 0x004a
+
+/* GDI errors */
+#define ERR_CREATEDC 0x0080
+#define ERR_CREATEMETA 0x0081
+#define ERR_DELOBJSELECTED 0x0082
+#define ERR_SELBITMAP 0x0083
+
+/* Debugging support (DEBUG SYSTEM ONLY) */
+typedef struct tagWINDEBUGINFO
+{
+ UINT flags;
+ DWORD dwOptions;
+ DWORD dwFilter;
+ char achAllocModule[8];
+ DWORD dwAllocBreak;
+ DWORD dwAllocCount;
+} WINDEBUGINFO;
+
+BOOL WINAPI GetWinDebugInfo(WINDEBUGINFO FAR* lpwdi, UINT flags);
+BOOL WINAPI SetWinDebugInfo(const WINDEBUGINFO FAR* lpwdi);
+
+void FAR _cdecl DebugOutput(UINT flags, LPCSTR lpsz, ...);
+void WINAPI DebugFillBuffer(void FAR* lpb, UINT cb); /* ;Internal */
+
+/* WINDEBUGINFO flags values */
+#define WDI_OPTIONS 0x0001
+#define WDI_FILTER 0x0002
+#define WDI_ALLOCBREAK 0x0004
+#define WDI_VALID 0x0007 /* ;Internal */
+
+/* dwOptions values */
+#define DBO_CHECKHEAP 0x0001
+#define DBO_BUFFERFILL 0x0004
+#define DBO_DISABLEGPTRAPPING 0x0010
+#define DBO_CHECKFREE 0x0020
+
+#define DBO_SILENT 0x8000
+
+#define DBO_TRACEBREAK 0x2000
+#define DBO_WARNINGBREAK 0x1000
+#define DBO_NOERRORBREAK 0x0800
+#define DBO_NOFATALBREAK 0x0400
+#define DBO_INT3BREAK 0x0100
+
+/* DebugOutput flags values */
+#define DBF_TRACE 0x0000
+#define DBF_WARNING 0x4000
+#define DBF_ERROR 0x8000
+#define DBF_FATAL 0xc000
+#define DBF_SEVMASK 0xc000 /* ;Internal */
+#define DBF_FILTERMASK 0x3fff /* ;Internal */
+
+/* dwFilter values */
+#define DBF_KERNEL 0x1000
+#define DBF_KRN_MEMMAN 0x0001
+#define DBF_KRN_LOADMODULE 0x0002
+#define DBF_KRN_SEGMENTLOAD 0x0004
+#define DBF_USER 0x0800
+#define DBF_GDI 0x0400
+#define DBF_MMSYSTEM 0x0040
+#define DBF_PENWIN 0x0020
+#define DBF_APPLICATION 0x0008
+#define DBF_DRIVER 0x0010
+
+#endif /* NOLOGERROR */
+#endif /* WINVER >= 0x030a */
+
+void WINAPI FatalExit(int);
+void WINAPI FatalAppExit(UINT, LPCSTR);
+
+BOOL WINAPI ExitWindows(DWORD dwReturnCode, UINT wReserved);
+
+#define EW_RESTARTWINDOWS 0x42
+#if (WINVER >= 0x030a)
+#define EW_REBOOTSYSTEM 0x43
+#define EW_EXITANDEXECAPP 0x44 /* ;Internal */
+
+BOOL WINAPI ExitWindowsExec(LPCSTR, LPCSTR);
+#endif /* WINVER >= 0x030a */
+
+void WINAPI DebugBreak(void);
+void WINAPI OutputDebugString(LPCSTR);
+
+/* SetErrorMode() constants */
+#define SEM_FAILCRITICALERRORS 0x0001
+#define SEM_NOGPFAULTERRORBOX 0x0002
+#define SEM_NOOPENFILEERRORBOX 0x8000
+
+UINT WINAPI SetErrorMode(UINT);
+
+/****** Pointer validation **************************************************/
+
+#if (WINVER >= 0x030a)
+
+BOOL WINAPI IsBadReadPtr(const void FAR* lp, UINT cb);
+BOOL WINAPI IsBadWritePtr(void FAR* lp, UINT cb);
+BOOL WINAPI IsBadHugeReadPtr(const void _huge* lp, DWORD cb);
+BOOL WINAPI IsBadHugeWritePtr(void _huge* lp, DWORD cb);
+BOOL WINAPI IsBadCodePtr(FARPROC lpfn);
+BOOL WINAPI IsBadStringPtr(const void FAR* lpsz, UINT cchMax);
+#endif /* WINVER >= 0x030a */
+
+/****** Profiling support ***************************************************/
+
+#ifndef NOPROFILER
+
+int WINAPI ProfInsChk(void);
+void WINAPI ProfSetup(int,int);
+void WINAPI ProfSampRate(int,int);
+void WINAPI ProfStart(void);
+void WINAPI ProfStop(void);
+void WINAPI ProfClear(void);
+void WINAPI ProfFlush(void);
+void WINAPI ProfFinish(void);
+#endif /* NOPROFILER */
+
+/****** Catch/Throw and stack management ************************************/
+
+typedef int CATCHBUF[9];
+typedef int FAR* LPCATCHBUF;
+
+int WINAPI Catch(int FAR*);
+void WINAPI Throw(const int FAR*, int);
+
+void WINAPI SwitchStackBack(void);
+void WINAPI SwitchStackTo(UINT, UINT, UINT);
+
+/****** Module Management ***************************************************/
+
+#define HINSTANCE_ERROR ((HINSTANCE)32)
+
+LONG WINAPI GetExpWinVer(HINSTANCE); /* ;Internal */
+
+HINSTANCE WINAPI LoadModule(LPCSTR, LPVOID);
+BOOL WINAPI FreeModule(HINSTANCE);
+
+HINSTANCE WINAPI LoadLibrary(LPCSTR);
+void WINAPI FreeLibrary(HINSTANCE);
+
+UINT WINAPI WinExec(LPCSTR, UINT);
+
+HMODULE WINAPI GetModuleHandle(LPCSTR);
+
+int WINAPI GetModuleUsage(HINSTANCE);
+int WINAPI GetModuleFileName(HINSTANCE, LPSTR, int);
+
+FARPROC WINAPI GetProcAddress(HINSTANCE, LPCSTR);
+
+int WINAPI GetInstanceData(HINSTANCE, BYTE*, int);
+
+HGLOBAL WINAPI GetCodeHandle(FARPROC);
+
+typedef struct tagSEGINFO
+{
+ UINT offSegment;
+ UINT cbSegment;
+ UINT flags;
+ UINT cbAlloc;
+ HGLOBAL h;
+ UINT alignShift;
+ UINT reserved[2];
+} SEGINFO;
+typedef SEGINFO FAR* LPSEGINFO;
+
+void WINAPI GetCodeInfo(FARPROC lpProc, SEGINFO FAR* lpSegInfo);
+
+FARPROC WINAPI MakeProcInstance(FARPROC, HINSTANCE);
+void WINAPI FreeProcInstance(FARPROC);
+
+LONG WINAPI SetSwapAreaSize(UINT);
+void WINAPI SwapRecording(UINT);
+void WINAPI ValidateCodeSegments(void);
+
+/* Windows Exit Procedure flag values */
+#define WEP_SYSTEM_EXIT 1
+#define WEP_FREE_DLL 0
+
+/****** Task Management *****************************************************/
+
+#endif /* NOKERNEL */
+
+DECLARE_HANDLE(HTASK);
+
+#ifndef NOKERNEL
+
+UINT WINAPI GetNumTasks(void);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI IsTask(HTASK);
+#endif /* WINVER >= 0x030a */
+
+HTASK WINAPI GetCurrentTask(void);
+int WINAPI SetPriority(HTASK, int); /* ;Internal */
+
+void WINAPI Yield(void);
+void WINAPI DirectedYield(HTASK);
+
+DWORD WINAPI GetAppCompatFlags(HTASK); /* ;Internal */
+ /* ;Internal */
+/* GetAppCompatFlags flag values */ /* ;Internal */
+#define GACF_IGNORENODISCARD 0x0001 /* ;Internal */
+#define GACF_FORCETEXTBAND 0x0002 /* ;Internal */
+#define GACF_ONELANDGRXBAND 0x0004 /* ;Internal */
+#define GACF_IGNORETOPMOST 0x0008 /* ;Internal */
+#define GACF_CALLTTDEVICE 0x0010 /* ;Internal */
+#define GACF_MULTIPLEBANDS 0x0020 /* ;Internal */
+#define GACF_ALWAYSSENDNCPAINT 0x0040 /* ;Internal */
+#define GACF_EDITSETTEXTMUNGE 0x0080 /* ;Internal */
+#define GACF_MOREEXTRAWNDWORDS 0x0100 /* ;Internal */
+#define GACF_TTIGNORERASTERDUPE 0x0200 /* ;Internal */
+#define GACF_HACKWINFLAGS 0x0400 /* ;Internal */
+#define GACF_DELAYHWHNDSHAKECHK 0x0800 /* ;Internal */
+#define GACF_ENUMHELVNTMSRMN 0x1000 /* ;Internal */
+#define GACF_ENUMTTNOTDEVICE 0x2000 /* ;Internal */
+#define GACF_SUBTRACTCLIPSIBS 0x4000 /* ;Internal */
+#define GACF_FORCETTGRAPHICS 0x8000 /* ;Internal */
+#define GACF_NOHRGN1 0x00010000 /* ;Internal */
+#define GACF_NCCALCSIZEONMOVE 0x00020000 /* ;Internal */
+#define GACF_SENDMENUDBLCLK 0x00040000 /* ;Internal */
+#define GACF_30AVGWIDTH 0x00080000 /* ;Internal */
+
+/****** Global memory management ********************************************/
+
+#ifndef NOMEMMGR
+
+/* Global Memory Flags */
+
+#define GMEM_FIXED 0x0000
+#define GMEM_MOVEABLE 0x0002
+#define GMEM_NOCOMPACT 0x0010
+#define GMEM_NODISCARD 0x0020
+#define GMEM_ZEROINIT 0x0040
+#define GMEM_MODIFY 0x0080
+#define GMEM_DISCARDABLE 0x0100
+#define GMEM_NOT_BANKED 0x1000
+#define GMEM_SHARE 0x2000
+#define GMEM_DDESHARE 0x2000
+#define GMEM_NOTIFY 0x4000
+#define GMEM_LOWER GMEM_NOT_BANKED
+
+#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT)
+#define GPTR (GMEM_FIXED | GMEM_ZEROINIT)
+
+#define GlobalDiscard(h) GlobalReAlloc(h, 0L, GMEM_MOVEABLE)
+
+HGLOBAL WINAPI GlobalAlloc(UINT, DWORD);
+HGLOBAL WINAPI GlobalReAlloc(HGLOBAL, DWORD, UINT);
+HGLOBAL WINAPI GlobalFree(HGLOBAL);
+
+DWORD WINAPI GlobalDosAlloc(DWORD);
+UINT WINAPI GlobalDosFree(UINT);
+
+#ifdef STRICT
+void FAR* WINAPI GlobalLock(HGLOBAL);
+#else
+char FAR* WINAPI GlobalLock(HGLOBAL);
+#endif
+
+BOOL WINAPI GlobalUnlock(HGLOBAL);
+
+DWORD WINAPI GlobalSize(HGLOBAL);
+DWORD WINAPI GlobalHandle(UINT);
+
+/* GlobalFlags return flags (in addition to GMEM_DISCARDABLE) */
+#define GMEM_DISCARDED 0x4000
+#define GMEM_LOCKCOUNT 0x00FF
+UINT WINAPI GlobalFlags(HGLOBAL);
+
+#ifdef STRICT
+void FAR* WINAPI GlobalWire(HGLOBAL);
+#else
+char FAR* WINAPI GlobalWire(HGLOBAL);
+#endif
+
+BOOL WINAPI GlobalUnWire(HGLOBAL);
+
+UINT WINAPI GlobalPageLock(HGLOBAL);
+UINT WINAPI GlobalPageUnlock(HGLOBAL);
+
+void WINAPI GlobalFix(HGLOBAL);
+void WINAPI GlobalUnfix(HGLOBAL);
+
+HGLOBAL WINAPI GlobalLRUNewest(HGLOBAL);
+HGLOBAL WINAPI GlobalLRUOldest(HGLOBAL);
+
+DWORD WINAPI GlobalCompact(DWORD);
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* GNOTIFYPROC)(HGLOBAL);
+#else
+typedef FARPROC GNOTIFYPROC;
+#endif
+
+void WINAPI GlobalNotify(GNOTIFYPROC);
+
+HGLOBAL WINAPI LockSegment(UINT);
+void WINAPI UnlockSegment(UINT);
+
+#define LockData(dummy) LockSegment((UINT)-1)
+#define UnlockData(dummy) UnlockSegment((UINT)-1)
+
+UINT WINAPI AllocSelector(UINT);
+UINT WINAPI FreeSelector(UINT);
+UINT WINAPI AllocDStoCSAlias(UINT);
+UINT WINAPI PrestoChangoSelector(UINT sourceSel, UINT destSel);
+DWORD WINAPI GetSelectorBase(UINT);
+UINT WINAPI SetSelectorBase(UINT, DWORD);
+DWORD WINAPI GetSelectorLimit(UINT);
+UINT WINAPI SetSelectorLimit(UINT, DWORD);
+
+void WINAPI LimitEmsPages(DWORD);
+
+void WINAPI ValidateFreeSpaces(void);
+
+/* Low system memory notification message */
+#define WM_COMPACTING 0x0041
+
+/***** Local Memory Management */
+
+/* Local Memory Flags */
+#define LMEM_FIXED 0x0000
+#define LMEM_MOVEABLE 0x0002
+#define LMEM_NOCOMPACT 0x0010
+#define LMEM_NODISCARD 0x0020
+#define LMEM_ZEROINIT 0x0040
+#define LMEM_MODIFY 0x0080
+#define LMEM_DISCARDABLE 0x0F00
+
+#define LHND (LMEM_MOVEABLE | LMEM_ZEROINIT)
+#define LPTR (LMEM_FIXED | LMEM_ZEROINIT)
+
+#define NONZEROLHND (LMEM_MOVEABLE)
+#define NONZEROLPTR (LMEM_FIXED)
+
+extern UINT NEAR* PASCAL pLocalHeap; /* ;Internal */
+#define LocalFreeze(dummy) (*(pLocalHeap+1) += 1) /* ;Internal */
+#define LocalMelt(dummy) (*(pLocalHeap+1) -= 1) /* ;Internal */
+
+#define LocalDiscard(h) LocalReAlloc(h, 0, LMEM_MOVEABLE)
+
+
+HLOCAL WINAPI LocalAlloc(UINT, UINT);
+HLOCAL WINAPI LocalReAlloc(HLOCAL, UINT, UINT);
+HLOCAL WINAPI LocalFree(HLOCAL);
+
+#ifdef STRICT
+void NEAR* WINAPI LocalLock(HLOCAL);
+#else
+char NEAR* WINAPI LocalLock(HLOCAL);
+#endif
+
+BOOL WINAPI LocalUnlock(HLOCAL);
+
+UINT WINAPI LocalSize(HLOCAL);
+#ifdef STRICT
+HLOCAL WINAPI LocalHandle(void NEAR*);
+#else
+HLOCAL WINAPI LocalHandle(UINT);
+#endif
+UINT WINAPI LocalHandleDelta(UINT); /* ;Internal */
+
+/* LocalFlags return flags (in addition to LMEM_DISCARDABLE) */
+#define LMEM_DISCARDED 0x4000
+#define LMEM_LOCKCOUNT 0x00FF
+
+UINT WINAPI LocalFlags(HLOCAL);
+
+BOOL WINAPI LocalInit(UINT, UINT, UINT);
+UINT WINAPI LocalCompact(UINT);
+UINT WINAPI LocalShrink(HLOCAL, UINT);
+
+/* LocalNotify callback */ /* ;Internal */
+#ifdef STRICT /* ;Internal */
+typedef BOOL (CALLBACK* LNOTIFYPROC)(UINT, HLOCAL, void NEAR*); /* ;Internal */
+#else /* ;Internal */
+typedef FARPROC LNOTIFYPROC; /* ;Internal */
+#endif /* ;Internal */
+ /* ;Internal */
+#define LNOTIFY_OUTOFMEM 0 /* ;Internal */
+#define LNOTIFY_MOVE 1 /* ;Internal */
+#define LNOTIFY_DISCARD 2 /* ;Internal */
+ /* ;Internal */
+LNOTIFYPROC WINAPI LocalNotify(LNOTIFYPROC); /* ;Internal */
+ /* ;Internal */
+#endif /* NOMEMMGR */
+
+/****** File I/O ************************************************************/
+
+#ifndef NOLFILEIO
+
+typedef int HFILE; /* Polymorphic with C runtime file handle type */
+
+#define HFILE_ERROR ((HFILE)-1)
+
+#ifndef NOOPENFILE
+
+/* OpenFile() Structure */
+typedef struct tagOFSTRUCT
+{
+ BYTE cBytes;
+ BYTE fFixedDisk;
+ UINT nErrCode;
+ BYTE reserved[4];
+ char szPathName[128];
+} OFSTRUCT;
+typedef OFSTRUCT* POFSTRUCT;
+typedef OFSTRUCT NEAR* NPOFSTRUCT;
+typedef OFSTRUCT FAR* LPOFSTRUCT;
+
+/* OpenFile() Flags */
+#define OF_READ 0x0000
+#define OF_WRITE 0x0001
+#define OF_READWRITE 0x0002
+#define OF_SHARE_COMPAT 0x0000
+#define OF_SHARE_EXCLUSIVE 0x0010
+#define OF_SHARE_DENY_WRITE 0x0020
+#define OF_SHARE_DENY_READ 0x0030
+#define OF_SHARE_DENY_NONE 0x0040
+#define OF_PARSE 0x0100
+#define OF_DELETE 0x0200
+#define OF_VERIFY 0x0400 /* Used with OF_REOPEN */
+#define OF_SEARCH 0x0400 /* Used without OF_REOPEN */
+#define OF_CANCEL 0x0800
+#define OF_CREATE 0x1000
+#define OF_PROMPT 0x2000
+#define OF_EXIST 0x4000
+#define OF_REOPEN 0x8000
+
+HFILE WINAPI OpenFile(LPCSTR, OFSTRUCT FAR*, UINT);
+
+#endif /* NOOPENFILE */
+
+/* _lopen() flags */
+#define READ 0
+#define WRITE 1
+#define READ_WRITE 2
+
+HFILE WINAPI _lopen(LPCSTR, int);
+HFILE WINAPI _lcreat(LPCSTR, int);
+
+HFILE WINAPI _lclose(HFILE);
+
+LONG WINAPI _llseek(HFILE, LONG, int);
+
+/* _llseek origin values */
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+UINT WINAPI _lread(HFILE, void _huge*, UINT);
+UINT WINAPI _lwrite(HFILE, const void _huge*, UINT);
+
+#if (WINVER >= 0x030a)
+long WINAPI _hread(HFILE, void _huge*, long);
+long WINAPI _hwrite(HFILE, const void _huge*, long);
+#endif /* WINVER >= 0x030a */
+
+UINT WINAPI DeletePathname(LPCSTR); /* ;Internal */
+
+#endif /* NOLFILEIO */
+
+/* GetTempFileName() Flags */
+#define TF_FORCEDRIVE (BYTE)0x80
+
+int WINAPI GetTempFileName(BYTE, LPCSTR, UINT, LPSTR);
+BYTE WINAPI GetTempDrive(char);
+
+/* GetDriveType return values */
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+UINT WINAPI GetDriveType(int);
+
+UINT WINAPI SetHandleCount(UINT);
+
+/****** Network support *****************************************************/
+UINT WINAPI WNetAddConnection(LPSTR, LPSTR, LPSTR);
+UINT WINAPI WNetGetConnection(LPSTR, LPSTR, UINT FAR*);
+UINT WINAPI WNetCancelConnection(LPSTR, BOOL);
+/* Errors */
+#define WN_SUCCESS 0x0000
+#define WN_NOT_SUPPORTED 0x0001
+#define WN_NET_ERROR 0x0002
+#define WN_MORE_DATA 0x0003
+#define WN_BAD_POINTER 0x0004
+#define WN_BAD_VALUE 0x0005
+#define WN_BAD_PASSWORD 0x0006
+#define WN_ACCESS_DENIED 0x0007
+#define WN_FUNCTION_BUSY 0x0008
+#define WN_WINDOWS_ERROR 0x0009
+#define WN_BAD_USER 0x000A
+#define WN_OUT_OF_MEMORY 0x000B
+#define WN_CANCEL 0x000C
+#define WN_CONTINUE 0x000D
+
+/* Connection errors */
+#define WN_NOT_CONNECTED 0x0030
+#define WN_OPEN_FILES 0x0031
+#define WN_BAD_NETNAME 0x0032
+#define WN_BAD_LOCALNAME 0x0033
+#define WN_ALREADY_CONNECTED 0x0034
+#define WN_DEVICE_ERROR 0x0035
+#define WN_CONNECTION_CLOSED 0x0036
+
+/****** Resource Management *************************************************/
+
+DECLARE_HANDLE(HRSRC);
+
+HRSRC WINAPI FindResource(HINSTANCE, LPCSTR, LPCSTR);
+HGLOBAL WINAPI LoadResource(HINSTANCE, HRSRC);
+BOOL WINAPI FreeResource(HGLOBAL);
+
+#ifdef STRICT
+void FAR* WINAPI LockResource(HGLOBAL);
+#else
+char FAR* WINAPI LockResource(HGLOBAL);
+#endif
+
+#define UnlockResource(h) GlobalUnlock(h)
+
+DWORD WINAPI SizeofResource(HINSTANCE, HRSRC);
+
+int WINAPI AccessResource(HINSTANCE, HRSRC);
+
+HGLOBAL WINAPI AllocResource(HINSTANCE, HRSRC, DWORD);
+
+#ifdef STRICT
+typedef HGLOBAL (CALLBACK* RSRCHDLRPROC)(HGLOBAL, HINSTANCE, HRSRC);
+#else
+typedef FARPROC RSRCHDLRPROC;
+#endif
+
+RSRCHDLRPROC WINAPI SetResourceHandler(HINSTANCE, LPCSTR, RSRCHDLRPROC);
+
+#define MAKEINTRESOURCE(i) ((LPCSTR)MAKELP(0, (i)))
+
+#ifndef NORESOURCE
+
+/* Predefined Resource Types */
+#define RT_CURSOR MAKEINTRESOURCE(1)
+#define RT_BITMAP MAKEINTRESOURCE(2)
+#define RT_ICON MAKEINTRESOURCE(3)
+#define RT_MENU MAKEINTRESOURCE(4)
+#define RT_DIALOG MAKEINTRESOURCE(5)
+#define RT_STRING MAKEINTRESOURCE(6)
+#define RT_FONTDIR MAKEINTRESOURCE(7)
+#define RT_FONT MAKEINTRESOURCE(8)
+#define RT_ACCELERATOR MAKEINTRESOURCE(9)
+#define RT_RCDATA MAKEINTRESOURCE(10)
+
+/* If any new types are added above this point, */ /* ;Internal */
+/* DIFFERENCE must be changed. The GROUP_* */ /* ;Internal */
+/* values minus the non-GROUP values must be */ /* ;Internal */
+/* equal to DIFFERENCE */ /* ;Internal */
+#define DIFFERENCE 11 /* ;Internal */
+#define RT_GROUP_CURSOR MAKEINTRESOURCE(12)
+#define RT_GROUP_ICON MAKEINTRESOURCE(14)
+
+#endif /* NORESOURCE */
+
+#ifdef OEMRESOURCE
+
+/* OEM Resource Ordinal Numbers */
+#define OBM_CLOSE 32754
+#define OBM_UPARROW 32753
+#define OBM_DNARROW 32752
+#define OBM_RGARROW 32751
+#define OBM_LFARROW 32750
+#define OBM_REDUCE 32749
+#define OBM_ZOOM 32748
+#define OBM_RESTORE 32747
+#define OBM_REDUCED 32746
+#define OBM_ZOOMD 32745
+#define OBM_RESTORED 32744
+#define OBM_UPARROWD 32743
+#define OBM_DNARROWD 32742
+#define OBM_RGARROWD 32741
+#define OBM_LFARROWD 32740
+#define OBM_MNARROW 32739
+#define OBM_COMBO 32738
+#if (WINVER >= 0x030a)
+#define OBM_UPARROWI 32737
+#define OBM_DNARROWI 32736
+#define OBM_RGARROWI 32735
+#define OBM_LFARROWI 32734
+#endif /* WINVER >= 0x030a */
+
+#define OBM_OLD_CLOSE 32767
+#define OBM_SIZE 32766
+#define OBM_OLD_UPARROW 32765
+#define OBM_OLD_DNARROW 32764
+#define OBM_OLD_RGARROW 32763
+#define OBM_OLD_LFARROW 32762
+#define OBM_BTSIZE 32761
+#define OBM_CHECK 32760
+#define OBM_CHECKBOXES 32759
+#define OBM_BTNCORNERS 32758
+#define OBM_OLD_REDUCE 32757
+#define OBM_OLD_ZOOM 32756
+#define OBM_OLD_RESTORE 32755
+
+#define OCR_NORMAL 32512
+#define OCR_IBEAM 32513
+#define OCR_WAIT 32514
+#define OCR_CROSS 32515
+#define OCR_UP 32516
+#define OCR_SIZE 32640
+#define OCR_ICON 32641
+#define OCR_SIZENWSE 32642
+#define OCR_SIZENESW 32643
+#define OCR_SIZEWE 32644
+#define OCR_SIZENS 32645
+#define OCR_SIZEALL 32646
+#define OCR_ICOCUR 32647
+
+#define OIC_SAMPLE 32512
+#define OIC_HAND 32513
+#define OIC_QUES 32514
+#define OIC_BANG 32515
+#define OIC_NOTE 32516
+
+#endif /* OEMRESOURCE */
+
+/****** Atom Management *****************************************************/
+
+#define MAKEINTATOM(i) ((LPCSTR)MAKELP(0, (i)))
+
+#ifndef NOATOM
+
+BOOL WINAPI InitAtomTable(int);
+ATOM WINAPI AddAtom(LPCSTR);
+ATOM WINAPI DeleteAtom(ATOM);
+ATOM WINAPI FindAtom(LPCSTR);
+UINT WINAPI GetAtomName(ATOM, LPSTR, int);
+ATOM WINAPI GlobalAddAtom(LPCSTR);
+ATOM WINAPI GlobalDeleteAtom(ATOM);
+ATOM WINAPI GlobalFindAtom(LPCSTR);
+UINT WINAPI GlobalGetAtomName(ATOM, LPSTR, int);
+HLOCAL WINAPI GetAtomHandle(ATOM);
+
+#endif /* NOATOM */
+
+/****** WIN.INI Support *****************************************************/
+
+/* User Profile Routines */
+UINT WINAPI GetProfileInt(LPCSTR, LPCSTR, int);
+int WINAPI GetProfileString(LPCSTR, LPCSTR, LPCSTR, LPSTR, int);
+BOOL WINAPI WriteProfileString(LPCSTR, LPCSTR, LPCSTR);
+
+UINT WINAPI GetPrivateProfileInt(LPCSTR, LPCSTR, int, LPCSTR);
+int WINAPI GetPrivateProfileString(LPCSTR, LPCSTR, LPCSTR, LPSTR, int, LPCSTR);
+BOOL WINAPI WritePrivateProfileString(LPCSTR, LPCSTR, LPCSTR, LPCSTR);
+
+#define WM_WININICHANGE 0x001A
+
+/****** International & Char Translation Support ****************************/
+
+void WINAPI AnsiToOem(const char _huge*, char _huge*);
+void WINAPI OemToAnsi(const char _huge*, char _huge*);
+
+void WINAPI AnsiToOemBuff(LPCSTR, LPSTR, UINT);
+void WINAPI OemToAnsiBuff(LPCSTR, LPSTR, UINT);
+
+LPSTR WINAPI AnsiNext(LPCSTR);
+LPSTR WINAPI AnsiPrev(LPCSTR, LPCSTR);
+
+LPSTR WINAPI AnsiUpper(LPSTR);
+LPSTR WINAPI AnsiLower(LPSTR);
+
+UINT WINAPI AnsiUpperBuff(LPSTR, UINT);
+UINT WINAPI AnsiLowerBuff(LPSTR, UINT);
+
+/* Language driver entry point ordinal */ /* ;Internal */
+#define ORD_LANGDRIVER 1 /* ;Internal */
+
+#ifndef NOLANGUAGE
+BOOL WINAPI IsCharAlpha(char);
+BOOL WINAPI IsCharAlphaNumeric(char);
+BOOL WINAPI IsCharUpper(char);
+BOOL WINAPI IsCharLower(char);
+#endif
+
+#ifndef NOLSTRING
+int WINAPI lstrcmp(LPCSTR, LPCSTR);
+int WINAPI lstrcmpi(LPCSTR, LPCSTR);
+LPSTR WINAPI lstrcpy(LPSTR, LPCSTR);
+LPSTR WINAPI lstrcat(LPSTR, LPCSTR);
+int WINAPI lstrlen(LPCSTR);
+#if (WINVER >= 0x030a)
+LPSTR WINAPI lstrcpyn(LPSTR, LPCSTR, int);
+void WINAPI hmemcpy(void _huge*, const void _huge*, long);
+#endif /* WINVER >= 0x030a */
+#endif /* NOLSTRING */
+
+#if (WINVER >= 0x030a)
+#ifndef NODBCS
+BOOL WINAPI IsDBCSLeadByte(BYTE);
+#endif /* NODBCS */
+#endif /* WINVER >= 0x030a */
+
+int WINAPI LoadString(HINSTANCE, UINT, LPSTR, int);
+
+/****** Keyboard Driver Functions *******************************************/
+
+#ifndef NOKEYBOARDINFO
+
+DWORD WINAPI OemKeyScan(UINT);
+UINT WINAPI VkKeyScan(UINT);
+int WINAPI GetKeyboardType(int);
+UINT WINAPI MapVirtualKey(UINT, UINT);
+int WINAPI GetKBCodePage(void);
+int WINAPI GetKeyNameText(LONG, LPSTR, int);
+int WINAPI ToAscii(UINT wVirtKey, UINT wScanCode, BYTE FAR* lpKeyState, DWORD FAR* lpChar, UINT wFlags);
+
+#endif
+
+#endif /* NOKERNEL */
+
+/****** GDI typedefs, structures, and functions *****************************/
+
+DECLARE_HANDLE(HDC);
+
+#ifndef NOGDI
+
+#ifdef STRICT
+typedef const void NEAR* HGDIOBJ;
+#else
+DECLARE_HANDLE(HGDIOBJ);
+#endif
+
+#endif /* NOGDI */
+
+DECLARE_HANDLE(HBITMAP);
+DECLARE_HANDLE(HPEN);
+DECLARE_HANDLE(HBRUSH);
+DECLARE_HANDLE(HRGN);
+DECLARE_HANDLE(HPALETTE);
+DECLARE_HANDLE(HFONT);
+
+typedef struct tagRECT
+{
+ int left;
+ int top;
+ int right;
+ int bottom;
+} RECT;
+typedef RECT* PRECT;
+typedef RECT NEAR* NPRECT;
+typedef RECT FAR* LPRECT;
+
+typedef struct tagPOINT
+{
+ int x;
+ int y;
+} POINT;
+typedef POINT* PPOINT;
+typedef POINT NEAR* NPPOINT;
+typedef POINT FAR* LPPOINT;
+
+#if (WINVER >= 0x030a)
+typedef struct tagSIZE
+{
+ int cx;
+ int cy;
+} SIZE;
+typedef SIZE* PSIZE;
+typedef SIZE NEAR* NPSIZE;
+typedef SIZE FAR* LPSIZE;
+#endif /* WINVER >= 0x030a */
+
+#define MAKEPOINT(l) (*((POINT FAR*)&(l)))
+
+#ifndef NOGDI
+
+/****** DC Management *******************************************************/
+
+HDC WINAPI CreateDC(LPCSTR, LPCSTR, LPCSTR, const void FAR*);
+HDC WINAPI CreateIC(LPCSTR, LPCSTR, LPCSTR, const void FAR*);
+HDC WINAPI CreateCompatibleDC(HDC);
+
+BOOL WINAPI DeleteDC(HDC);
+
+DWORD WINAPI GetDCOrg(HDC);
+DWORD WINAPI SetDCOrg(HDC, int, int); /* ;Internal */
+
+int WINAPI SaveDC(HDC);
+BOOL WINAPI RestoreDC(HDC, int);
+
+int WINAPI SetEnvironment(LPCSTR, const void FAR*, UINT);
+int WINAPI GetEnvironment(LPCSTR, void FAR*, UINT);
+
+int WINAPI MulDiv(int, int, int);
+
+#if (WINVER >= 0x030a)
+/* Drawing bounds accumulation APIs */
+UINT WINAPI SetBoundsRect(HDC hDC, const RECT FAR* lprcBounds, UINT flags);
+UINT WINAPI GetBoundsRect(HDC hDC, RECT FAR* lprcBounds, UINT flags);
+
+#define DCB_RESET 0x0001
+#define DCB_ACCUMULATE 0x0002
+#define DCB_DIRTY DCB_ACCUMULATE
+#define DCB_SET (DCB_RESET | DCB_ACCUMULATE)
+#define DCB_ENABLE 0x0004
+#define DCB_DISABLE 0x0008
+#define DCB_WINDOWMGR 0x8000 /* ;Internal */
+ /* ;Internal */
+/* Internal SelectBitmap stuff */ /* ;Internal */
+/*HBITMAP WINAPI SelectBitmap(HDC hDC, HBITMAP hbm);*/ /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+/****** Device Capabilities *************************************************/
+
+int WINAPI GetDeviceCaps(HDC, int);
+
+/* Device Parameters for GetDeviceCaps() */
+#define DRIVERVERSION 0
+#define TECHNOLOGY 2
+#define HORZSIZE 4
+#define VERTSIZE 6
+#define HORZRES 8
+#define VERTRES 10
+#define BITSPIXEL 12
+#define PLANES 14
+#define NUMBRUSHES 16
+#define NUMPENS 18
+#define NUMMARKERS 20
+#define NUMFONTS 22
+#define NUMCOLORS 24
+#define PDEVICESIZE 26
+#define CURVECAPS 28
+#define LINECAPS 30
+#define POLYGONALCAPS 32
+#define TEXTCAPS 34
+#define CLIPCAPS 36
+#define RASTERCAPS 38
+#define ASPECTX 40
+#define ASPECTY 42
+#define ASPECTXY 44
+
+#define LOGPIXELSX 88
+#define LOGPIXELSY 90
+
+#define SIZEPALETTE 104
+#define NUMRESERVED 106
+#define COLORRES 108
+
+#ifndef NOGDICAPMASKS
+
+/* GetDeviceCaps() return value masks */
+
+/* TECHNOLOGY */
+#define DT_PLOTTER 0
+#define DT_RASDISPLAY 1
+#define DT_RASPRINTER 2
+#define DT_RASCAMERA 3
+#define DT_CHARSTREAM 4
+#define DT_METAFILE 5
+#define DT_DISPFILE 6
+
+/* CURVECAPS */
+#define CC_NONE 0x0000
+#define CC_CIRCLES 0x0001
+#define CC_PIE 0x0002
+#define CC_CHORD 0x0004
+#define CC_ELLIPSES 0x0008
+#define CC_WIDE 0x0010
+#define CC_STYLED 0x0020
+#define CC_WIDESTYLED 0x0040
+#define CC_INTERIORS 0x0080
+#define CC_ROUNDRECT 0x0100
+
+/* LINECAPS */
+#define LC_NONE 0x0000
+#define LC_POLYLINE 0x0002
+#define LC_MARKER 0x0004
+#define LC_POLYMARKER 0x0008
+#define LC_WIDE 0x0010
+#define LC_STYLED 0x0020
+#define LC_WIDESTYLED 0x0040
+#define LC_INTERIORS 0x0080
+
+/* POLYGONALCAPS */
+#define PC_NONE 0x0000
+#define PC_POLYGON 0x0001
+#define PC_RECTANGLE 0x0002
+#define PC_WINDPOLYGON 0x0004
+#define PC_SCANLINE 0x0008
+#define PC_WIDE 0x0010
+#define PC_STYLED 0x0020
+#define PC_WIDESTYLED 0x0040
+#define PC_INTERIORS 0x0080
+
+/* TEXTCAPS */
+#define TC_OP_CHARACTER 0x0001
+#define TC_OP_STROKE 0x0002
+#define TC_CP_STROKE 0x0004
+#define TC_CR_90 0x0008
+#define TC_CR_ANY 0x0010
+#define TC_SF_X_YINDEP 0x0020
+#define TC_SA_DOUBLE 0x0040
+#define TC_SA_INTEGER 0x0080
+#define TC_SA_CONTIN 0x0100
+#define TC_EA_DOUBLE 0x0200
+#define TC_IA_ABLE 0x0400
+#define TC_UA_ABLE 0x0800
+#define TC_SO_ABLE 0x1000
+#define TC_RA_ABLE 0x2000
+#define TC_VA_ABLE 0x4000
+#define TC_RESERVED 0x8000
+
+/* CLIPCAPS */
+#define CP_NONE 0x0000
+#define CP_RECTANGLE 0x0001
+#define CP_REGION 0x0002
+
+/* RASTERCAPS */
+#define RC_NONE
+#define RC_BITBLT 0x0001
+#define RC_BANDING 0x0002
+#define RC_SCALING 0x0004
+#define RC_BITMAP64 0x0008
+#define RC_GDI20_OUTPUT 0x0010
+#define RC_GDI20_STATE 0x0020
+#define RC_SAVEBITMAP 0x0040
+#define RC_DI_BITMAP 0x0080
+#define RC_PALETTE 0x0100
+#define RC_DIBTODEV 0x0200
+#define RC_BIGFONT 0x0400
+#define RC_STRETCHBLT 0x0800
+#define RC_FLOODFILL 0x1000
+#define RC_STRETCHDIB 0x2000
+#define RC_OP_DX_OUTPUT 0x4000
+#define RC_DEVBITS 0x8000
+
+#endif /* NOGDICAPMASKS */
+
+/****** Coordinate transformation support ***********************************/
+
+int WINAPI SetMapMode(HDC, int);
+int WINAPI GetMapMode(HDC);
+
+/* Map modes */
+#define MM_TEXT 1
+#define MM_LOMETRIC 2
+#define MM_HIMETRIC 3
+#define MM_LOENGLISH 4
+#define MM_HIENGLISH 5
+#define MM_TWIPS 6
+#define MM_ISOTROPIC 7
+#define MM_ANISOTROPIC 8
+
+DWORD WINAPI SetWindowOrg(HDC, int, int);
+DWORD WINAPI GetWindowOrg(HDC);
+
+DWORD WINAPI SetWindowExt(HDC, int, int);
+DWORD WINAPI GetWindowExt(HDC);
+
+DWORD WINAPI OffsetWindowOrg(HDC, int, int);
+DWORD WINAPI ScaleWindowExt(HDC, int, int, int, int);
+
+DWORD WINAPI SetViewportOrg(HDC, int, int);
+DWORD WINAPI GetViewportOrg(HDC);
+
+DWORD WINAPI SetViewportExt(HDC, int, int);
+DWORD WINAPI GetViewportExt(HDC);
+
+DWORD WINAPI OffsetViewportOrg(HDC, int, int);
+DWORD WINAPI ScaleViewportExt(HDC, int, int, int, int);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI SetWindowOrgEx(HDC, int, int, POINT FAR*);
+BOOL WINAPI GetWindowOrgEx(HDC, POINT FAR*);
+
+BOOL WINAPI SetWindowExtEx(HDC, int, int, SIZE FAR*);
+BOOL WINAPI GetWindowExtEx(HDC, SIZE FAR*);
+
+BOOL WINAPI OffsetWindowOrgEx(HDC, int, int, POINT FAR*);
+BOOL WINAPI ScaleWindowExtEx(HDC, int, int, int, int, SIZE FAR*);
+
+BOOL WINAPI SetViewportExtEx(HDC, int, int, SIZE FAR*);
+BOOL WINAPI GetViewportExtEx(HDC, SIZE FAR*);
+
+BOOL WINAPI SetViewportOrgEx(HDC, int, int, POINT FAR*);
+BOOL WINAPI GetViewportOrgEx(HDC, POINT FAR*);
+
+BOOL WINAPI OffsetViewportOrgEx(HDC, int, int, POINT FAR*);
+BOOL WINAPI ScaleViewportExtEx(HDC, int, int, int, int, SIZE FAR*);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI DPtoLP(HDC, POINT FAR*, int);
+BOOL WINAPI LPtoDP(HDC, POINT FAR*, int);
+
+int WINAPI SetRelAbs(HDC, int); /* ;Internal */
+int WINAPI GetRelAbs(HDC); /* ;Internal */
+
+/* Coordinate Modes */
+#define ABSOLUTE 1
+#define RELATIVE 2
+
+/****** Color support *******************************************************/
+
+typedef DWORD COLORREF;
+
+#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)))
+
+#define GetRValue(rgb) ((BYTE)(rgb))
+#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
+#define GetBValue(rgb) ((BYTE)((rgb)>>16))
+
+COLORREF WINAPI GetNearestColor(HDC, COLORREF);
+
+#ifndef NOCOLOR
+
+COLORREF WINAPI GetSysColor(int);
+void WINAPI SetSysColors(int, const int FAR*, const COLORREF FAR*);
+
+#define COLOR_SCROLLBAR 0
+#define COLOR_BACKGROUND 1
+#define COLOR_ACTIVECAPTION 2
+#define COLOR_INACTIVECAPTION 3
+#define COLOR_MENU 4
+#define COLOR_WINDOW 5
+#define COLOR_WINDOWFRAME 6
+#define COLOR_MENUTEXT 7
+#define COLOR_WINDOWTEXT 8
+#define COLOR_CAPTIONTEXT 9
+#define COLOR_ACTIVEBORDER 10
+#define COLOR_INACTIVEBORDER 11
+#define COLOR_APPWORKSPACE 12
+#define COLOR_HIGHLIGHT 13
+#define COLOR_HIGHLIGHTTEXT 14
+#define COLOR_BTNFACE 15
+#define COLOR_BTNSHADOW 16
+#define COLOR_GRAYTEXT 17
+#define COLOR_BTNTEXT 18
+#if (WINVER >= 0x030a)
+#define COLOR_INACTIVECAPTIONTEXT 19
+#define COLOR_BTNHIGHLIGHT 20
+#define COLOR_MAX 20 /* ;Internal */
+#else /* WINVER >= 0x030a */ /* ;Internal */
+#define COLOR_MAX 18 /* ;Internal */
+#endif /* WINVER >= 0x030a */
+#define COLOR_ENDCOLORS COLOR_MAX /* ;Internal */
+
+#endif /* NOCOLOR */
+
+#define WM_SYSCOLORCHANGE 0x0015
+
+/****** GDI Object Support **************************************************/
+
+#ifndef NOGDIOBJ
+
+HGDIOBJ WINAPI GetStockObject(int);
+
+BOOL WINAPI IsGDIObject(HGDIOBJ);
+#define GDIOBJ_PEN 1 /* ;Internal */
+#define GDIOBJ_BRUSH 2 /* ;Internal */
+#define GDIOBJ_FONT 3 /* ;Internal */
+#define GDIOBJ_PALETTE 4 /* ;Internal */
+#define GDIOBJ_BITMAP 5 /* ;Internal */
+#define GDIOBJ_RGN 6 /* ;Internal */
+#define GDIOBJ_DC 7 /* ;Internal */
+#define GDIOBJ_IC 8 /* ;Internal */
+#define GDIOBJ_DISABLEDDC 9 /* ;Internal */
+#define GDIOBJ_METADC 10 /* ;Internal */
+#define GDIOBJ_METAFILE 11 /* ;Internal */
+
+BOOL WINAPI DeleteObject(HGDIOBJ);
+HGDIOBJ WINAPI SelectObject(HDC, HGDIOBJ);
+int WINAPI GetObject(HGDIOBJ, int, void FAR*);
+BOOL WINAPI UnrealizeObject(HGDIOBJ);
+
+#ifdef STRICT
+typedef (CALLBACK* GOBJENUMPROC)(void FAR*, LPARAM);
+#else
+typedef FARPROC GOBJENUMPROC;
+#endif
+
+#ifdef STRICT
+int WINAPI EnumObjects(HDC, int, GOBJENUMPROC, LPARAM);
+#else
+int WINAPI EnumObjects(HDC, int, GOBJENUMPROC, LPSTR);
+#endif
+
+/* Object types for EnumObjects() */
+#define OBJ_PEN 1
+#define OBJ_BRUSH 2
+
+/****** Pen support *********************************************************/
+
+/* Logical Pen */
+typedef struct tagLOGPEN
+{
+ UINT lopnStyle;
+ POINT lopnWidth;
+ COLORREF lopnColor;
+} LOGPEN;
+typedef LOGPEN* PLOGPEN;
+typedef LOGPEN NEAR* NPLOGPEN;
+typedef LOGPEN FAR* LPLOGPEN;
+
+/* Pen Styles */
+#define PS_SOLID 0
+#define PS_DASH 1
+#define PS_DOT 2
+#define PS_DASHDOT 3
+#define PS_DASHDOTDOT 4
+#define PS_NULL 5
+#define PS_INSIDEFRAME 6
+
+HPEN WINAPI CreatePen(int, int, COLORREF);
+HPEN WINAPI CreatePenIndirect(LOGPEN FAR*);
+
+/* Stock pens for use with GetStockObject(); */
+#define WHITE_PEN 6
+#define BLACK_PEN 7
+#define NULL_PEN 8
+
+/****** Brush support *******************************************************/
+
+/* Brush Styles */
+#define BS_SOLID 0
+#define BS_NULL 1
+#define BS_HOLLOW BS_NULL
+#define BS_HATCHED 2
+#define BS_PATTERN 3
+#define BS_INDEXED 4
+#define BS_DIBPATTERN 5
+
+/* Hatch Styles */
+#define HS_HORIZONTAL 0
+#define HS_VERTICAL 1
+#define HS_FDIAGONAL 2
+#define HS_BDIAGONAL 3
+#define HS_CROSS 4
+#define HS_DIAGCROSS 5
+
+/* Logical Brush (or Pattern) */
+typedef struct tagLOGBRUSH
+{
+ UINT lbStyle;
+ COLORREF lbColor;
+ int lbHatch;
+} LOGBRUSH;
+typedef LOGBRUSH* PLOGBRUSH;
+typedef LOGBRUSH NEAR* NPLOGBRUSH;
+typedef LOGBRUSH FAR* LPLOGBRUSH;
+
+typedef LOGBRUSH PATTERN;
+typedef PATTERN* PPATTERN;
+typedef PATTERN NEAR* NPPATTERN;
+typedef PATTERN FAR* LPPATTERN;
+
+HBRUSH WINAPI CreateSolidBrush(COLORREF);
+HBRUSH WINAPI CreateHatchBrush(int, COLORREF);
+HBRUSH WINAPI CreatePatternBrush(HBITMAP);
+HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL, UINT);
+HBRUSH WINAPI CreateBrushIndirect(LOGBRUSH FAR*);
+
+/* Stock brushes for use with GetStockObject() */
+#define WHITE_BRUSH 0
+#define LTGRAY_BRUSH 1
+#define GRAY_BRUSH 2
+#define DKGRAY_BRUSH 3
+#define BLACK_BRUSH 4
+#define NULL_BRUSH 5
+#define HOLLOW_BRUSH NULL_BRUSH
+
+DWORD WINAPI SetBrushOrg(HDC, int, int);
+DWORD WINAPI GetBrushOrg(HDC);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI GetBrushOrgEx(HDC, POINT FAR*);
+#endif /* WINVER >= 0x030a */
+#endif /* NOGDIOBJ */
+
+/****** Region support ******************************************************/
+
+HRGN WINAPI CreateRectRgn(int, int, int, int);
+HRGN WINAPI CreateRectRgnIndirect(const RECT FAR*);
+HRGN WINAPI CreateEllipticRgnIndirect(const RECT FAR*);
+HRGN WINAPI CreateEllipticRgn(int, int, int, int);
+HRGN WINAPI CreatePolygonRgn(const POINT FAR*, int, int);
+HRGN WINAPI CreatePolyPolygonRgn(const POINT FAR*, const int FAR*, int, int);
+HRGN WINAPI CreateRoundRectRgn(int, int, int, int, int, int);
+
+/* Region type flags */
+#define ERROR 0
+#define NULLREGION 1
+#define SIMPLEREGION 2
+#define COMPLEXREGION 3
+
+void WINAPI SetRectRgn(HRGN, int, int, int, int);
+
+int WINAPI CombineRgn(HRGN, HRGN, HRGN, int);
+
+/* CombineRgn() command values */
+#define RGN_AND 1
+#define RGN_OR 2
+#define RGN_XOR 3
+#define RGN_DIFF 4
+#define RGN_COPY 5
+
+BOOL WINAPI EqualRgn(HRGN, HRGN);
+int WINAPI OffsetRgn(HRGN, int, int);
+
+int WINAPI GetRgnBox(HRGN, RECT FAR*);
+
+BOOL WINAPI RectInRegion(HRGN, const RECT FAR*);
+BOOL WINAPI PtInRegion(HRGN, int, int);
+
+/****** Color palette Support ************************************************/
+
+#define PALETTERGB(r,g,b) (0x02000000L | RGB(r,g,b))
+#define PALETTEINDEX(i) ((COLORREF)(0x01000000L | (DWORD)(WORD)(i)))
+
+typedef struct tagPALETTEENTRY
+{
+ BYTE peRed;
+ BYTE peGreen;
+ BYTE peBlue;
+ BYTE peFlags;
+} PALETTEENTRY;
+typedef PALETTEENTRY FAR* LPPALETTEENTRY;
+
+/* Palette entry flags */
+#define PC_RESERVED 0x01 /* palette index used for animation */
+#define PC_EXPLICIT 0x02 /* palette index is explicit to device */
+#define PC_NOCOLLAPSE 0x04 /* do not match color to system palette */
+
+/* Logical Palette */
+typedef struct tagLOGPALETTE
+{
+ WORD palVersion;
+ WORD palNumEntries;
+ PALETTEENTRY palPalEntry[1];
+} LOGPALETTE;
+typedef LOGPALETTE* PLOGPALETTE;
+typedef LOGPALETTE NEAR* NPLOGPALETTE;
+typedef LOGPALETTE FAR* LPLOGPALETTE;
+
+HPALETTE WINAPI CreatePalette(const LOGPALETTE FAR*);
+
+HPALETTE WINAPI SelectPalette(HDC, HPALETTE, BOOL);
+
+UINT WINAPI RealizePalette(HDC);
+
+int WINAPI UpdateColors(HDC);
+void WINAPI AnimatePalette(HPALETTE, UINT, UINT, const PALETTEENTRY FAR*);
+
+UINT WINAPI SetPaletteEntries(HPALETTE, UINT, UINT, const PALETTEENTRY FAR*);
+UINT WINAPI GetPaletteEntries(HPALETTE, UINT, UINT, PALETTEENTRY FAR*);
+
+UINT WINAPI GetNearestPaletteIndex(HPALETTE, COLORREF);
+
+BOOL WINAPI ResizePalette(HPALETTE, UINT);
+
+UINT WINAPI GetSystemPaletteEntries(HDC, UINT, UINT, PALETTEENTRY FAR*);
+
+UINT WINAPI GetSystemPaletteUse(HDC);
+UINT WINAPI SetSystemPaletteUse(HDC, UINT);
+
+/* Get/SetSystemPaletteUse() values */
+#define SYSPAL_STATIC 1
+#define SYSPAL_NOSTATIC 2
+
+/* Palette window messages */
+#define WM_QUERYNEWPALETTE 0x030F
+#define WM_PALETTEISCHANGING 0x0310
+#define WM_PALETTECHANGED 0x0311
+#define WM_PALETTEGONNACHANGE WM_PALETTEISCHANGING /* ;Internal */
+#define WM_CHANGEPALETTE WM_PALETTECHANGED /* ;Internal */
+
+/****** Clipping support *****************************************************/
+
+int WINAPI SelectClipRgn(HDC, HRGN);
+int WINAPI GetClipBox(HDC, RECT FAR*);
+
+int WINAPI IntersectClipRect(HDC, int, int, int, int);
+int WINAPI OffsetClipRgn(HDC, int, int);
+int WINAPI ExcludeClipRect(HDC, int, int, int, int);
+
+BOOL WINAPI PtVisible(HDC, int, int);
+BOOL WINAPI RectVisible(HDC, const RECT FAR*);
+
+#if (WINVER >= 0x030a) /* ;Internal */
+/* DC hook callback function */ /* ;Internal */
+ /* ;Internal */
+typedef UINT (CALLBACK* DCHOOKPROC)(HDC hDC, UINT code, DWORD data, DWORD lParam); /* ;Internal */
+ /* ;Internal */
+BOOL WINAPI SetDCHook(HDC hDC, DCHOOKPROC lpNewProc, DWORD data); /* ;Internal */
+DWORD WINAPI GetDCHook(HDC hDC, DCHOOKPROC FAR* lplpproc); /* ;Internal */
+ /* ;Internal */
+/* Callback reason code values */ /* ;Internal */
+ /* ;Internal */
+#define DCHC_INVALIDVISRGN 0x0001 /* ;Internal */
+#define DCHC_DELETEDC 0x0002 /* ;Internal */
+ /* ;Internal */
+UINT WINAPI SetHookFlags(HDC hDC, UINT flags); /* ;Internal */
+ /* ;Internal */
+#define DCHF_INVALIDATEVISRGN 0x0001 /* ;Internal */
+#define DCHF_VALIDATEVISRGN 0x0002 /* ;Internal */
+#endif /* WINVER >= 0x030a */ /* ;Internal */
+
+/****** General drawing support ********************************************/
+
+DWORD WINAPI MoveTo(HDC, int, int);
+DWORD WINAPI GetCurrentPosition(HDC);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI MoveToEx(HDC, int, int, POINT FAR*);
+BOOL WINAPI GetCurrentPositionEx(HDC, POINT FAR*);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI LineTo(HDC, int, int);
+BOOL WINAPI Polyline(HDC, const POINT FAR*, int);
+
+#ifdef STRICT
+typedef void (CALLBACK* LINEDDAPROC)(int, int, LPARAM);
+#else
+typedef FARPROC LINEDDAPROC;
+#endif
+
+void WINAPI LineDDA(int, int, int, int, LINEDDAPROC, LPARAM);
+
+BOOL WINAPI Rectangle(HDC, int, int, int, int);
+BOOL WINAPI RoundRect(HDC, int, int, int, int, int, int);
+
+BOOL WINAPI Ellipse(HDC, int, int, int, int);
+BOOL WINAPI Arc(HDC, int, int, int, int, int, int, int, int);
+BOOL WINAPI Chord(HDC, int, int, int, int, int, int, int, int);
+BOOL WINAPI Pie(HDC, int, int, int, int, int, int, int, int);
+
+BOOL WINAPI Polygon(HDC, const POINT FAR*, int);
+BOOL WINAPI PolyPolygon(HDC, const POINT FAR*, int FAR*, int);
+
+/* PolyFill Modes */
+#define ALTERNATE 1
+#define WINDING 2
+
+int WINAPI SetPolyFillMode(HDC, int);
+int WINAPI GetPolyFillMode(HDC);
+
+BOOL WINAPI FloodFill(HDC, int, int, COLORREF);
+BOOL WINAPI ExtFloodFill(HDC, int, int, COLORREF, UINT);
+
+/* ExtFloodFill style flags */
+#define FLOODFILLBORDER 0
+#define FLOODFILLSURFACE 1
+
+BOOL WINAPI FillRgn(HDC, HRGN, HBRUSH);
+BOOL WINAPI FrameRgn(HDC, HRGN, HBRUSH, int, int);
+BOOL WINAPI InvertRgn(HDC, HRGN);
+BOOL WINAPI PaintRgn(HDC, HRGN);
+
+/* Rectangle output routines */
+int WINAPI FillRect(HDC, const RECT FAR*, HBRUSH);
+int WINAPI FrameRect(HDC, const RECT FAR*, HBRUSH);
+void WINAPI InvertRect(HDC, const RECT FAR*);
+
+void WINAPI DrawFocusRect(HDC, const RECT FAR*);
+
+BOOL WINAPI FastWindowFrame(HDC, const RECT FAR*, UINT, UINT, DWORD); /* ;Internal */
+
+/****** Text support ********************************************************/
+
+BOOL WINAPI TextOut(HDC, int, int, LPCSTR, int);
+LONG WINAPI TabbedTextOut(HDC, int, int, LPCSTR, int, int, int FAR*, int);
+BOOL WINAPI ExtTextOut(HDC, int, int, UINT, const RECT FAR*, LPCSTR, UINT, int FAR*);
+
+#define ETO_GRAYED 0x0001
+#define ETO_OPAQUE 0x0002
+#define ETO_CLIPPED 0x0004
+
+DWORD WINAPI GetTextExtent(HDC, LPCSTR, int);
+DWORD WINAPI GetTabbedTextExtent(HDC, LPCSTR, int, int, int FAR*);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI GetTextExtentPoint(HDC, LPCSTR, int, SIZE FAR*);
+#endif /* WINVER >= 0x030a */
+
+/* DrawText() Format Flags */
+#ifndef NODRAWTEXT
+#define DT_TOP 0x0000
+#define DT_LEFT 0x0000
+#define DT_CENTER 0x0001
+#define DT_RIGHT 0x0002
+#define DT_VCENTER 0x0004
+#define DT_BOTTOM 0x0008
+#define DT_WORDBREAK 0x0010
+#define DT_SINGLELINE 0x0020
+#define DT_EXPANDTABS 0x0040
+#define DT_TABSTOP 0x0080
+#define DT_NOCLIP 0x0100
+#define DT_EXTERNALLEADING 0x0200
+#define DT_CALCRECT 0x0400
+#define DT_NOPREFIX 0x0800
+#define DT_INTERNAL 0x1000
+#define DT_VALID 0x1fff /* ;Internal: Union of all those above */
+
+int WINAPI DrawText(HDC, LPCSTR, int, RECT FAR*, UINT);
+#endif /* NODRAWTEXT */
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* GRAYSTRINGPROC)(HDC, LPARAM, int);
+#else
+typedef FARPROC GRAYSTRINGPROC;
+#endif
+
+BOOL WINAPI GrayString(HDC, HBRUSH, GRAYSTRINGPROC, LPARAM, int, int, int, int, int);
+
+BOOL WINAPI GetCharWidth(HDC, UINT, UINT, int FAR*);
+
+COLORREF WINAPI SetTextColor(HDC, COLORREF);
+COLORREF WINAPI GetTextColor(HDC);
+
+COLORREF WINAPI SetBkColor(HDC, COLORREF);
+COLORREF WINAPI GetBkColor(HDC);
+
+int WINAPI SetBkMode(HDC, int);
+int WINAPI GetBkMode(HDC);
+
+/* Background Modes */
+#define TRANSPARENT 1
+#define OPAQUE 2
+#define TRANSPARENT1 3 /* ;Internal */
+
+UINT WINAPI SetTextAlign(HDC, UINT);
+UINT WINAPI GetTextAlign(HDC);
+
+/* Text Alignment Options */
+#define TA_NOUPDATECP 0x0000
+#define TA_UPDATECP 0x0001
+#define TA_LEFT 0x0000
+#define TA_RIGHT 0x0002
+#define TA_CENTER 0x0006
+#define TA_TOP 0x0000
+#define TA_BOTTOM 0x0008
+#define TA_BASELINE 0x0018
+
+int WINAPI SetTextCharacterExtra(HDC, int);
+int WINAPI GetTextCharacterExtra(HDC);
+
+int WINAPI SetTextJustification(HDC, int, int);
+
+/****** Font support ********************************************************/
+
+#ifndef NOGDIOBJ
+/* Logical Font */
+#define LF_FACESIZE 32
+typedef struct tagLOGFONT
+{
+ int lfHeight;
+ int lfWidth;
+ int lfEscapement;
+ int lfOrientation;
+ int lfWeight;
+ BYTE lfItalic;
+ BYTE lfUnderline;
+ BYTE lfStrikeOut;
+ BYTE lfCharSet;
+ BYTE lfOutPrecision;
+ BYTE lfClipPrecision;
+ BYTE lfQuality;
+ BYTE lfPitchAndFamily;
+ char lfFaceName[LF_FACESIZE];
+} LOGFONT;
+typedef LOGFONT* PLOGFONT;
+typedef LOGFONT NEAR* NPLOGFONT;
+typedef LOGFONT FAR* LPLOGFONT;
+
+/* weight values */
+#define FW_DONTCARE 0
+#define FW_THIN 100
+#define FW_EXTRALIGHT 200
+#define FW_LIGHT 300
+#define FW_NORMAL 400
+#define FW_MEDIUM 500
+#define FW_SEMIBOLD 600
+#define FW_BOLD 700
+#define FW_EXTRABOLD 800
+#define FW_HEAVY 900
+
+#define FW_ULTRALIGHT FW_EXTRALIGHT
+#define FW_REGULAR FW_NORMAL
+#define FW_DEMIBOLD FW_SEMIBOLD
+#define FW_ULTRABOLD FW_EXTRABOLD
+#define FW_BLACK FW_HEAVY
+
+/* CharSet values */
+#define ANSI_CHARSET 0
+#define DEFAULT_CHARSET 1
+#define SYMBOL_CHARSET 2
+#define SHIFTJIS_CHARSET 128
+#define HANGEUL_CHARSET 129
+#define CHINESEBIG5_CHARSET 136
+#define OEM_CHARSET 255
+
+/* OutPrecision values */
+#define OUT_DEFAULT_PRECIS 0
+#define OUT_STRING_PRECIS 1
+#define OUT_CHARACTER_PRECIS 2
+#define OUT_STROKE_PRECIS 3
+#if (WINVER >= 0x030a)
+#define OUT_TT_PRECIS 4
+#define OUT_DEVICE_PRECIS 5
+#define OUT_RASTER_PRECIS 6
+#define OUT_TT_ONLY_PRECIS 7
+#endif /* WINVER >= 0x030a */
+
+/* ClipPrecision values */
+#define CLIP_DEFAULT_PRECIS 0x00
+#define CLIP_CHARACTER_PRECIS 0x01
+#define CLIP_STROKE_PRECIS 0x02
+#define CLIP_MASK 0x0F
+#if (WINVER >= 0x030a)
+#define CLIP_LH_ANGLES 0x10
+#define CLIP_TT_ALWAYS 0x20
+#define CLIP_EMBEDDED 0x80
+#endif /* WINVER >= 0x030a */
+
+/* Quality values */
+#define DEFAULT_QUALITY 0
+#define DRAFT_QUALITY 1
+#define PROOF_QUALITY 2
+
+/* PitchAndFamily pitch values (low 4 bits) */
+#define DEFAULT_PITCH 0x00
+#define FIXED_PITCH 0x01
+#define VARIABLE_PITCH 0x02
+
+/* PitchAndFamily family values (high 4 bits) */
+#define FF_DONTCARE 0x00
+#define FF_ROMAN 0x10
+#define FF_SWISS 0x20
+#define FF_MODERN 0x30
+#define FF_SCRIPT 0x40
+#define FF_DECORATIVE 0x50
+
+HFONT WINAPI CreateFont(int, int, int, int, int, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, BYTE, LPCSTR);
+HFONT WINAPI CreateFontIndirect(const LOGFONT FAR*);
+
+/* Stock fonts for use with GetStockObject() */
+#define OEM_FIXED_FONT 10
+#define ANSI_FIXED_FONT 11
+#define ANSI_VAR_FONT 12
+#define SYSTEM_FONT 13
+#define DEVICE_DEFAULT_FONT 14
+#define DEFAULT_PALETTE 15
+#define SYSTEM_FIXED_FONT 16
+
+
+DWORD WINAPI SetMapperFlags(HDC, DWORD);
+#define ASPECT_FILTERING 0x00000001L
+
+int WINAPI AddFontResource(LPCSTR);
+BOOL WINAPI RemoveFontResource(LPCSTR);
+
+#define WM_FONTCHANGE 0x001D
+
+int WINAPI GetTextFace(HDC, int, LPSTR);
+
+DWORD WINAPI GetAspectRatioFilter(HDC);
+#if (WINVER >= 0x030a)
+BOOL WINAPI GetAspectRatioFilterEx(HDC, SIZE FAR*);
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOGDIOBJ */
+
+#ifndef NOTEXTMETRIC
+
+typedef struct tagTEXTMETRIC
+{
+ int tmHeight;
+ int tmAscent;
+ int tmDescent;
+ int tmInternalLeading;
+ int tmExternalLeading;
+ int tmAveCharWidth;
+ int tmMaxCharWidth;
+ int tmWeight;
+ BYTE tmItalic;
+ BYTE tmUnderlined;
+ BYTE tmStruckOut;
+ BYTE tmFirstChar;
+ BYTE tmLastChar;
+ BYTE tmDefaultChar;
+ BYTE tmBreakChar;
+ BYTE tmPitchAndFamily;
+ BYTE tmCharSet;
+ int tmOverhang;
+ int tmDigitizedAspectX;
+ int tmDigitizedAspectY;
+} TEXTMETRIC;
+typedef TEXTMETRIC* PTEXTMETRIC;
+typedef TEXTMETRIC NEAR* NPTEXTMETRIC;
+typedef TEXTMETRIC FAR* LPTEXTMETRIC;
+
+/* tmPitchAndFamily values */
+#define TMPF_FIXED_PITCH 0x01
+#define TMPF_VECTOR 0x02
+#define TMPF_DEVICE 0x08
+#if (WINVER >= 0x030a)
+#define TMPF_TRUETYPE 0x04
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI GetTextMetrics(HDC, TEXTMETRIC FAR*);
+
+#if (WINVER >= 0x030a)
+#ifndef NOSCALABLEFONT
+
+typedef struct tagPANOSE
+{
+ BYTE bFamilyType;
+ BYTE bSerifStyle;
+ BYTE bWeight;
+ BYTE bProportion;
+ BYTE bContrast;
+ BYTE bStrokeVariation;
+ BYTE bArmStyle;
+ BYTE bLetterform;
+ BYTE bMidline;
+ BYTE bXHeight;
+} PANOSE, FAR* LPPANOSE;
+
+typedef struct tagOUTLINETEXTMETRIC
+{
+ UINT otmSize;
+ TEXTMETRIC otmTextMetrics;
+ BYTE otmFiller;
+ PANOSE otmPanoseNumber;
+ UINT otmfsSelection;
+ UINT otmfsType;
+ int otmsCharSlopeRise;
+ int otmsCharSlopeRun;
+ int otmItalicAngle;
+ UINT otmEMSquare;
+ int otmAscent;
+ int otmDescent;
+ UINT otmLineGap;
+ UINT otmsCapEmHeight;
+ UINT otmsXHeight;
+ RECT otmrcFontBox;
+ int otmMacAscent;
+ int otmMacDescent;
+ UINT otmMacLineGap;
+ UINT otmusMinimumPPEM;
+ POINT otmptSubscriptSize;
+ POINT otmptSubscriptOffset;
+ POINT otmptSuperscriptSize;
+ POINT otmptSuperscriptOffset;
+ UINT otmsStrikeoutSize;
+ int otmsStrikeoutPosition;
+ int otmsUnderscorePosition;
+ int otmsUnderscoreSize;
+ PSTR otmpFamilyName;
+ PSTR otmpFaceName;
+ PSTR otmpStyleName;
+ PSTR otmpFullName;
+} OUTLINETEXTMETRIC, FAR* LPOUTLINETEXTMETRIC;
+
+WORD WINAPI GetOutlineTextMetrics(HDC, UINT, OUTLINETEXTMETRIC FAR*);
+
+#endif /* WINVER >= 0x030a */
+#endif /* NOSCALABLEFONT */
+
+#ifndef NOGDIOBJ
+#if (WINVER >= 0x030a)
+
+/* Structure passed to FONTENUMPROC */
+/* NOTE: NEWTEXTMETRIC is the same as TEXTMETRIC plus 4 new fields */
+typedef struct tagNEWTEXTMETRIC
+{
+ int tmHeight;
+ int tmAscent;
+ int tmDescent;
+ int tmInternalLeading;
+ int tmExternalLeading;
+ int tmAveCharWidth;
+ int tmMaxCharWidth;
+ int tmWeight;
+ BYTE tmItalic;
+ BYTE tmUnderlined;
+ BYTE tmStruckOut;
+ BYTE tmFirstChar;
+ BYTE tmLastChar;
+ BYTE tmDefaultChar;
+ BYTE tmBreakChar;
+ BYTE tmPitchAndFamily;
+ BYTE tmCharSet;
+ int tmOverhang;
+ int tmDigitizedAspectX;
+ int tmDigitizedAspectY;
+ DWORD ntmFlags;
+ UINT ntmSizeEM;
+ UINT ntmCellHeight;
+ UINT ntmAvgWidth;
+} NEWTEXTMETRIC;
+typedef NEWTEXTMETRIC* PNEWTEXTMETRIC;
+typedef NEWTEXTMETRIC NEAR* NPNEWTEXTMETRIC;
+typedef NEWTEXTMETRIC FAR* LPNEWTEXTMETRIC;
+
+/* ntmFlags field flags */
+#define NTM_REGULAR 0x00000040L
+#define NTM_BOLD 0x00000020L
+#define NTM_ITALIC 0x00000001L
+
+#define LF_FULLFACESIZE 64
+
+/* Structure passed to FONTENUMPROC */
+typedef struct tagENUMLOGFONT
+{
+ LOGFONT elfLogFont;
+ char elfFullName[LF_FULLFACESIZE];
+ char elfStyle[LF_FACESIZE];
+} ENUMLOGFONT, FAR* LPENUMLOGFONT;
+
+#endif /* WINVER >= 0x030a */
+#endif /* NOGDIOBJ */
+
+#ifdef STRICT
+#ifndef NOGDIOBJ
+
+typedef int (CALLBACK* OLDFONTENUMPROC)(const LOGFONT FAR*, const TEXTMETRIC FAR*, int, LPARAM);
+
+#if (WINVER >= 0x030a)
+typedef int (CALLBACK* FONTENUMPROC)(const ENUMLOGFONT FAR*, const NEWTEXTMETRIC FAR*, int, LPARAM);
+
+int WINAPI EnumFontFamilies(HDC, LPCSTR, FONTENUMPROC, LPARAM);
+
+#else /* WINVER >= 0x030a */
+typedef OLDFONTENUMPROC FONTENUMPROC;
+#endif /* WINVER >= 0x030a) */
+
+int WINAPI EnumFonts(HDC, LPCSTR, OLDFONTENUMPROC, LPARAM);
+#endif /* NOGDIOBJ */
+
+#else /* STRICT */
+
+typedef FARPROC OLDFONTENUMPROC;
+typedef FARPROC FONTENUMPROC;
+
+int WINAPI EnumFonts(HDC, LPCSTR, OLDFONTENUMPROC, LPSTR);
+
+#if (WINVER >= 0x030a)
+int WINAPI EnumFontFamilies(HDC, LPCSTR, FONTENUMPROC, LPSTR);
+#endif /* WINVER >= 0x030a */
+
+#endif /* !STRICT */
+
+/* EnumFonts font type values */
+#define RASTER_FONTTYPE 0x0001
+#define DEVICE_FONTTYPE 0X0002
+#if (WINVER >= 0x030a)
+#define TRUETYPE_FONTTYPE 0x0004
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOTEXTMETRIC */
+
+#ifndef NOSCALABLEFONT
+#if (WINVER >= 0x030a)
+
+DWORD WINAPI ConvertOutlineFontFile(LPCSTR, LPCSTR, LPCSTR); /* ;Internal */
+DWORD WINAPI GetFontData(HDC, DWORD, DWORD, void FAR*, DWORD);
+BOOL WINAPI CreateScalableFontResource(UINT, LPCSTR, LPCSTR, LPCSTR);
+
+typedef struct tagGLYPHMETRICS
+{
+ UINT gmBlackBoxX;
+ UINT gmBlackBoxY;
+ POINT gmptGlyphOrigin;
+ int gmCellIncX;
+ int gmCellIncY;
+} GLYPHMETRICS, FAR* LPGLYPHMETRICS;
+
+typedef struct tagFIXED
+{
+ UINT fract;
+ int value;
+} FIXED, FAR* LPFIXED;
+
+typedef struct tagMAT2
+{
+ FIXED eM11;
+ FIXED eM12;
+ FIXED eM21;
+ FIXED eM22;
+} MAT2, FAR* LPMAT2;
+
+DWORD WINAPI GetGlyphOutline(HDC, UINT, UINT, GLYPHMETRICS FAR*, DWORD, void FAR*, const MAT2 FAR*);
+
+/* GetGlyphOutline constants */
+#define GGO_METRICS 0
+#define GGO_BITMAP 1
+#define GGO_NATIVE 2
+
+#define TT_POLYGON_TYPE 24
+
+#define TT_PRIM_LINE 1
+#define TT_PRIM_QSPLINE 2
+
+typedef struct tagPOINTFX
+{
+ FIXED x;
+ FIXED y;
+} POINTFX, FAR* LPPOINTFX;
+
+typedef struct tagTTPOLYCURVE
+{
+ UINT wType;
+ UINT cpfx;
+ POINTFX apfx[1];
+} TTPOLYCURVE, FAR* LPTTPOLYCURVE;
+
+typedef struct tagTTPOLYGONHEADER
+{
+ DWORD cb;
+ DWORD dwType;
+ POINTFX pfxStart;
+} TTPOLYGONHEADER, FAR* LPTTPOLYGONHEADER;
+
+typedef UINT FAR* LPFONTDIR; /* ;Internal */
+ /* ;Internal */
+DWORD WINAPI EngineMakeFontDir(HDC, LPFONTDIR, LPCSTR); /* ;Internal */
+ /* ;Internal */
+typedef struct tagABC
+{
+ int abcA;
+ UINT abcB;
+ int abcC;
+} ABC;
+typedef ABC FAR* LPABC;
+
+BOOL WINAPI GetCharABCWidths(HDC, UINT, UINT, ABC FAR*);
+
+typedef struct tagKERNINGPAIR
+{
+ WORD wFirst;
+ WORD wSecond;
+ int iKernAmount;
+} KERNINGPAIR, FAR* LPKERNINGPAIR;
+
+int WINAPI GetKerningPairs(HDC, int, KERNINGPAIR FAR*);
+
+typedef struct tagRASTERIZER_STATUS
+{
+ int nSize;
+ int wFlags;
+ int nLanguageID;
+} RASTERIZER_STATUS;
+typedef RASTERIZER_STATUS FAR* LPRASTERIZER_STATUS;
+
+/* bits defined in wFlags of RASTERIZER_STATUS */
+#define TT_AVAILABLE 0x0001
+#define TT_ENABLED 0x0002
+
+BOOL WINAPI GetRasterizerCaps(RASTERIZER_STATUS FAR*, int);
+
+#endif /* WINVER >= 0x030a */
+#endif /* NOSCALABLEFONT */
+
+/****** Bitmap support ******************************************************/
+
+#ifndef NOBITMAP
+typedef struct tagBITMAP
+{
+ int bmType;
+ int bmWidth;
+ int bmHeight;
+ int bmWidthBytes;
+ BYTE bmPlanes;
+ BYTE bmBitsPixel;
+ void FAR* bmBits;
+} BITMAP;
+typedef BITMAP* PBITMAP;
+typedef BITMAP NEAR* NPBITMAP;
+typedef BITMAP FAR* LPBITMAP;
+
+/* Bitmap Header structures */
+typedef struct tagRGBTRIPLE
+{
+ BYTE rgbtBlue;
+ BYTE rgbtGreen;
+ BYTE rgbtRed;
+} RGBTRIPLE;
+typedef RGBTRIPLE FAR* LPRGBTRIPLE;
+
+typedef struct tagRGBQUAD
+{
+ BYTE rgbBlue;
+ BYTE rgbGreen;
+ BYTE rgbRed;
+ BYTE rgbReserved;
+} RGBQUAD;
+typedef RGBQUAD FAR* LPRGBQUAD;
+
+/* structures for defining DIBs */
+typedef struct tagBITMAPCOREHEADER
+{
+ DWORD bcSize;
+ short bcWidth;
+ short bcHeight;
+ WORD bcPlanes;
+ WORD bcBitCount;
+} BITMAPCOREHEADER;
+typedef BITMAPCOREHEADER* PBITMAPCOREHEADER;
+typedef BITMAPCOREHEADER FAR* LPBITMAPCOREHEADER;
+
+typedef struct tagBITMAPINFOHEADER
+{
+ DWORD biSize;
+ LONG biWidth;
+ LONG biHeight;
+ WORD biPlanes;
+ WORD biBitCount;
+ DWORD biCompression;
+ DWORD biSizeImage;
+ LONG biXPelsPerMeter;
+ LONG biYPelsPerMeter;
+ DWORD biClrUsed;
+ DWORD biClrImportant;
+} BITMAPINFOHEADER;
+typedef BITMAPINFOHEADER* PBITMAPINFOHEADER;
+typedef BITMAPINFOHEADER FAR* LPBITMAPINFOHEADER;
+
+/* constants for the biCompression field */
+#define BI_RGB 0L
+#define BI_RLE8 1L
+#define BI_RLE4 2L
+
+typedef struct tagBITMAPINFO
+{
+ BITMAPINFOHEADER bmiHeader;
+ RGBQUAD bmiColors[1];
+} BITMAPINFO;
+typedef BITMAPINFO* PBITMAPINFO;
+typedef BITMAPINFO FAR* LPBITMAPINFO;
+
+typedef struct tagBITMAPCOREINFO
+{
+ BITMAPCOREHEADER bmciHeader;
+ RGBTRIPLE bmciColors[1];
+} BITMAPCOREINFO;
+typedef BITMAPCOREINFO* PBITMAPCOREINFO;
+typedef BITMAPCOREINFO FAR* LPBITMAPCOREINFO;
+
+typedef struct tagBITMAPFILEHEADER
+{
+ UINT bfType;
+ DWORD bfSize;
+ UINT bfReserved1;
+ UINT bfReserved2;
+ DWORD bfOffBits;
+} BITMAPFILEHEADER;
+typedef BITMAPFILEHEADER* PBITMAPFILEHEADER;
+typedef BITMAPFILEHEADER FAR* LPBITMAPFILEHEADER;
+
+/* Pel Array */ /* ;Internal */
+typedef struct tagPELARRAY /* ;Internal */
+{ /* ;Internal */
+ int paXCount; /* ;Internal */
+ int paYCount; /* ;Internal */
+ int paXExt; /* ;Internal */
+ int paYExt; /* ;Internal */
+ BYTE paRGBs; /* ;Internal */
+} PELARRAY; /* ;Internal */
+typedef PELARRAY* PPELARRAY; /* ;Internal */
+typedef PELARRAY NEAR* NPPELARRAY; /* ;Internal */
+typedef PELARRAY FAR* LPPELARRAY; /* ;Internal */
+
+HBITMAP WINAPI CreateBitmap(int, int, UINT, UINT, const void FAR*);
+HBITMAP WINAPI CreateBitmapIndirect(BITMAP FAR* );
+HBITMAP WINAPI CreateCompatibleBitmap(HDC, int, int);
+HBITMAP WINAPI CreateDiscardableBitmap(HDC, int, int);
+HBITMAP WINAPI CreateDIBitmap(HDC, BITMAPINFOHEADER FAR*, DWORD, const void FAR*, BITMAPINFO FAR*, UINT);
+
+HBITMAP WINAPI LoadBitmap(HINSTANCE, LPCSTR);
+
+/* DIB color table identifiers */
+#define DIB_RGB_COLORS 0
+#define DIB_PAL_COLORS 1
+
+/* constants for CreateDIBitmap */
+#define CBM_INIT 0x00000004L
+#endif /* NOBITMAP */
+
+#ifndef NORASTEROPS
+
+/* Binary raster ops */
+#define R2_BLACK 1
+#define R2_NOTMERGEPEN 2
+#define R2_MASKNOTPEN 3
+#define R2_NOTCOPYPEN 4
+#define R2_MASKPENNOT 5
+#define R2_NOT 6
+#define R2_XORPEN 7
+#define R2_NOTMASKPEN 8
+#define R2_MASKPEN 9
+#define R2_NOTXORPEN 10
+#define R2_NOP 11
+#define R2_MERGENOTPEN 12
+#define R2_COPYPEN 13
+#define R2_MERGEPENNOT 14
+#define R2_MERGEPEN 15
+#define R2_WHITE 16
+
+/* Ternary raster operations */
+#define SRCCOPY 0x00CC0020L
+#define SRCPAINT 0x00EE0086L
+#define SRCAND 0x008800C6L
+#define SRCINVERT 0x00660046L
+#define SRCERASE 0x00440328L
+#define NOTSRCCOPY 0x00330008L
+#define NOTSRCERASE 0x001100A6L
+#define MERGECOPY 0x00C000CAL
+#define MERGEPAINT 0x00BB0226L
+#define PATCOPY 0x00F00021L
+#define PATPAINT 0x00FB0A09L
+#define PATINVERT 0x005A0049L
+#define DSTINVERT 0x00550009L
+#define BLACKNESS 0x00000042L
+#define WHITENESS 0x00FF0062L
+
+#endif /* NORASTEROPS */
+
+#ifndef NOBITMAP
+BOOL WINAPI BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD);
+
+BOOL WINAPI PatBlt(HDC, int, int, int, int, DWORD);
+
+BOOL WINAPI StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD);
+int WINAPI StretchDIBits(HDC, int, int, int, int, int,
+ int, int, int, const void FAR*, LPBITMAPINFO, UINT, DWORD);
+
+COLORREF WINAPI SetPixel(HDC, int, int, COLORREF);
+COLORREF WINAPI GetPixel(HDC, int, int);
+
+/* StretchBlt() Modes */
+#define BLACKONWHITE 1
+#define WHITEONBLACK 2
+#define COLORONCOLOR 3
+
+/* new StretchBlt() Modes (simpler names) */
+#define STRETCH_ANDSCANS 1
+#define STRETCH_ORSCANS 2
+#define STRETCH_DELETESCANS 3
+
+int WINAPI SetStretchBltMode(HDC, int);
+int WINAPI GetStretchBltMode(HDC);
+
+DWORD WINAPI SetBitmapDimension(HBITMAP, int, int);
+DWORD WINAPI GetBitmapDimension(HBITMAP);
+#if (WINVER >= 0x030a)
+BOOL WINAPI SetBitmapDimensionEx(HBITMAP, int, int, SIZE FAR*);
+BOOL WINAPI GetBitmapDimensionEx(HBITMAP, SIZE FAR*);
+#endif /* WINVER >= 0x030a */
+int WINAPI SetROP2(HDC, int);
+int WINAPI GetROP2(HDC);
+
+LONG WINAPI SetBitmapBits(HBITMAP, DWORD, const void FAR*);
+LONG WINAPI GetBitmapBits(HBITMAP, LONG, void FAR*);
+
+int WINAPI SetDIBits(HDC, HBITMAP, UINT, UINT, const void FAR*, BITMAPINFO FAR*, UINT);
+int WINAPI GetDIBits(HDC, HBITMAP, UINT, UINT, void FAR*, BITMAPINFO FAR*, UINT);
+
+int WINAPI SetDIBitsToDevice(HDC, int, int, int, int, int, int, UINT, UINT,
+ void FAR*, BITMAPINFO FAR*, UINT);
+#endif /* NOBITMAP */
+
+/****** Metafile support ****************************************************/
+
+#ifndef NOMETAFILE
+
+DECLARE_HANDLE(HMETAFILE);
+
+HDC WINAPI CreateMetaFile(LPCSTR);
+HMETAFILE WINAPI CloseMetaFile(HDC);
+
+HMETAFILE WINAPI GetMetaFile(LPCSTR);
+BOOL WINAPI DeleteMetaFile(HMETAFILE);
+HMETAFILE WINAPI CopyMetaFile(HMETAFILE, LPCSTR);
+
+BOOL WINAPI PlayMetaFile(HDC, HMETAFILE);
+
+HGLOBAL WINAPI GetMetaFileBits(HMETAFILE);
+HMETAFILE WINAPI SetMetaFileBits(HGLOBAL);
+#if (WINVER >= 0x030a)
+HMETAFILE WINAPI SetMetaFileBitsBetter(HGLOBAL);
+#endif /* WINVER >= 0x030a */
+
+/* Clipboard Metafile Picture Structure */
+typedef struct tagMETAFILEPICT
+{
+ int mm;
+ int xExt;
+ int yExt;
+ HMETAFILE hMF;
+} METAFILEPICT;
+typedef METAFILEPICT FAR* LPMETAFILEPICT;
+
+typedef struct tagMETAHEADER
+{
+ UINT mtType;
+ UINT mtHeaderSize;
+ UINT mtVersion;
+ DWORD mtSize;
+ UINT mtNoObjects;
+ DWORD mtMaxRecord;
+ UINT mtNoParameters;
+} METAHEADER;
+
+typedef struct tagHANDLETABLE
+{
+ HGDIOBJ objectHandle[1];
+} HANDLETABLE;
+typedef HANDLETABLE* PHANDLETABLE;
+typedef HANDLETABLE FAR* LPHANDLETABLE;
+
+typedef struct tagMETARECORD
+{
+ DWORD rdSize;
+ UINT rdFunction;
+ UINT rdParm[1];
+} METARECORD;
+typedef METARECORD* PMETARECORD;
+typedef METARECORD FAR* LPMETARECORD;
+
+/* Metafile Functions */
+#define META_SETBKCOLOR 0x0201
+#define META_SETBKMODE 0x0102
+#define META_SETMAPMODE 0x0103
+#define META_SETROP2 0x0104
+#define META_SETRELABS 0x0105
+#define META_SETPOLYFILLMODE 0x0106
+#define META_SETSTRETCHBLTMODE 0x0107
+#define META_SETTEXTCHAREXTRA 0x0108
+#define META_SETTEXTCOLOR 0x0209
+#define META_SETTEXTJUSTIFICATION 0x020A
+#define META_SETWINDOWORG 0x020B
+#define META_SETWINDOWEXT 0x020C
+#define META_SETVIEWPORTORG 0x020D
+#define META_SETVIEWPORTEXT 0x020E
+#define META_OFFSETWINDOWORG 0x020F
+#define META_SCALEWINDOWEXT 0x0410
+#define META_OFFSETVIEWPORTORG 0x0211
+#define META_SCALEVIEWPORTEXT 0x0412
+#define META_LINETO 0x0213
+#define META_MOVETO 0x0214
+#define META_EXCLUDECLIPRECT 0x0415
+#define META_INTERSECTCLIPRECT 0x0416
+#define META_ARC 0x0817
+#define META_ELLIPSE 0x0418
+#define META_FLOODFILL 0x0419
+#define META_PIE 0x081A
+#define META_RECTANGLE 0x041B
+#define META_ROUNDRECT 0x061C
+#define META_PATBLT 0x061D
+#define META_SAVEDC 0x001E
+#define META_SETPIXEL 0x041F
+#define META_OFFSETCLIPRGN 0x0220
+#define META_TEXTOUT 0x0521
+#define META_BITBLT 0x0922
+#define META_STRETCHBLT 0x0B23
+#define META_POLYGON 0x0324
+#define META_POLYLINE 0x0325
+#define META_ESCAPE 0x0626
+#define META_RESTOREDC 0x0127
+#define META_FILLREGION 0x0228
+#define META_FRAMEREGION 0x0429
+#define META_INVERTREGION 0x012A
+#define META_PAINTREGION 0x012B
+#define META_SELECTCLIPREGION 0x012C
+#define META_SELECTOBJECT 0x012D
+#define META_SETTEXTALIGN 0x012E
+#define META_DRAWTEXT 0x062F
+
+#define META_CHORD 0x0830
+#define META_SETMAPPERFLAGS 0x0231
+#define META_EXTTEXTOUT 0x0a32
+#define META_SETDIBTODEV 0x0d33
+#define META_SELECTPALETTE 0x0234
+#define META_REALIZEPALETTE 0x0035
+#define META_ANIMATEPALETTE 0x0436
+#define META_SETPALENTRIES 0x0037
+#define META_POLYPOLYGON 0x0538
+#define META_RESIZEPALETTE 0x0139
+
+#define META_DIBBITBLT 0x0940
+#define META_DIBSTRETCHBLT 0x0b41
+#define META_DIBCREATEPATTERNBRUSH 0x0142
+#define META_STRETCHDIB 0x0f43
+
+#define META_EXTFLOODFILL 0x0548
+
+#define META_RESETDC 0x014C
+#define META_STARTDOC 0x014D
+#define META_STARTPAGE 0x004F
+#define META_ENDPAGE 0x0050
+#define META_ABORTDOC 0x0052
+#define META_ENDDOC 0x005E
+
+#define META_DELETEOBJECT 0x01f0
+
+#define META_CREATEPALETTE 0x00f7
+#define META_CREATEBRUSH 0x00F8
+#define META_CREATEPATTERNBRUSH 0x01F9
+#define META_CREATEPENINDIRECT 0x02FA
+#define META_CREATEFONTINDIRECT 0x02FB
+#define META_CREATEBRUSHINDIRECT 0x02FC
+#define META_CREATEBITMAPINDIRECT 0x02FD
+#define META_CREATEBITMAP 0x06FE
+#define META_CREATEREGION 0x06FF
+
+void WINAPI PlayMetaFileRecord(HDC, HANDLETABLE FAR*, METARECORD FAR*, UINT);
+
+#ifdef STRICT
+typedef int (CALLBACK* MFENUMPROC)(HDC, HANDLETABLE FAR*, METARECORD FAR*, int, LPARAM);
+#else
+typedef FARPROC MFENUMPROC;
+#endif
+
+BOOL WINAPI EnumMetaFile(HDC, HMETAFILE, MFENUMPROC, LPARAM);
+
+#endif /* NOMETAFILE */
+
+/****** Printing support ****************************************************/
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* ABORTPROC)(HDC, int);
+#else
+typedef FARPROC ABORTPROC;
+#endif
+
+#if (WINVER >= 0x030a)
+
+typedef struct
+{
+ int cbSize;
+ LPCSTR lpszDocName;
+ LPCSTR lpszOutput;
+} DOCINFO;
+typedef DOCINFO FAR* LPDOCINFO;
+
+int WINAPI StartDoc(HDC, DOCINFO FAR*);
+int WINAPI StartPage(HDC);
+int WINAPI EndPage(HDC);
+int WINAPI EndDoc(HDC);
+int WINAPI AbortDoc(HDC);
+
+int WINAPI SetAbortProc(HDC, ABORTPROC);
+HANDLE WINAPI SpoolFile(LPSTR, LPSTR, LPSTR, LPSTR);
+BOOL WINAPI QueryJob(HANDLE, int); /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI QueryAbort(HDC, int);
+
+/* Spooler Error Codes */
+#define SP_NOTREPORTED 0x4000
+#define SP_ERROR (-1)
+#define SP_APPABORT (-2)
+#define SP_USERABORT (-3)
+#define SP_OUTOFDISK (-4)
+#define SP_OUTOFMEMORY (-5)
+
+#define PR_JOBSTATUS 0x0000
+
+#endif /* NOGDI */
+
+/* Spooler status notification message */
+#define WM_SPOOLERSTATUS 0x002A
+
+#ifndef NOGDI
+
+/******* GDI Escape support *************************************************/
+
+int WINAPI Escape(HDC, int, int, LPCSTR, void FAR*);
+
+/* GDI Escapes */
+#define NEWFRAME 1
+#define ABORTDOC 2
+#define NEXTBAND 3
+#define SETCOLORTABLE 4
+#define GETCOLORTABLE 5
+#define FLUSHOUTPUT 6
+#define DRAFTMODE 7
+#define QUERYESCSUPPORT 8
+#define SETABORTPROC 9
+#define STARTDOC 10
+#define ENDDOC 11
+#define GETPHYSPAGESIZE 12
+#define GETPRINTINGOFFSET 13
+#define GETSCALINGFACTOR 14
+#define MFCOMMENT 15
+#define GETPENWIDTH 16
+#define SETCOPYCOUNT 17
+#define SELECTPAPERSOURCE 18
+#define DEVICEDATA 19
+#define PASSTHROUGH 19
+#define GETTECHNOLGY 20
+#define GETTECHNOLOGY 20
+#define SETLINECAP 21
+#define SETLINEJOIN 22
+#define SETMITERLIMIT 23
+#define BANDINFO 24
+#define DRAWPATTERNRECT 25
+#define GETVECTORPENSIZE 26
+#define GETVECTORBRUSHSIZE 27
+#define ENABLEDUPLEX 28
+#define GETSETPAPERBINS 29
+#define GETSETPRINTORIENT 30
+#define ENUMPAPERBINS 31
+#define SETDIBSCALING 32
+#define EPSPRINTING 33
+#define ENUMPAPERMETRICS 34
+#define GETSETPAPERMETRICS 35
+#define POSTSCRIPT_DATA 37
+#define POSTSCRIPT_IGNORE 38
+#define MOUSETRAILS 39
+
+#define GETEXTENDEDTEXTMETRICS 256
+#define GETEXTENTTABLE 257
+#define GETPAIRKERNTABLE 258
+#define GETTRACKKERNTABLE 259
+#define EXTTEXTOUT 512
+#define GETFACENAME 513
+#define ENABLERELATIVEWIDTHS 768
+#define ENABLEPAIRKERNING 769
+#define SETKERNTRACK 770
+#define SETALLJUSTVALUES 771
+#define SETCHARSET 772
+
+#define STRETCHBLT 2048
+
+#define GETSETSCREENPARAMS 3072
+
+#define BEGIN_PATH 4096
+#define CLIP_TO_PATH 4097
+#define END_PATH 4098
+#define EXT_DEVICE_CAPS 4099
+#define RESTORE_CTM 4100
+#define SAVE_CTM 4101
+#define SET_ARC_DIRECTION 4102
+#define SET_BACKGROUND_COLOR 4103
+#define SET_POLY_MODE 4104
+#define SET_SCREEN_ANGLE 4105
+#define SET_SPREAD 4106
+#define TRANSFORM_CTM 4107
+#define SET_CLIP_BOX 4108
+#define SET_BOUNDS 4109
+
+#endif /* NOGDI */
+
+/****** USER typedefs, structures, and functions *****************************/
+
+#ifdef tagWND /* ;Internal */
+typedef struct tagWND NEAR* HWND; /* ;Internal */
+#else /* ;Internal */
+DECLARE_HANDLE(HWND);
+#endif /* ;Internal */
+
+#ifndef NOUSER
+
+DECLARE_HANDLE(HMENU);
+
+DECLARE_HANDLE(HICON);
+typedef HICON HCURSOR; /* HICONs & HCURSORs are polymorphic */
+
+/****** System Metrics *******************************************************/
+
+#ifndef NOSYSMETRICS
+
+int WINAPI GetSystemMetrics(int);
+
+/* GetSystemMetrics() codes */
+#define SM_CXSCREEN 0
+#define SM_CYSCREEN 1
+#define SM_CXVSCROLL 2
+#define SM_CYHSCROLL 3
+#define SM_CYCAPTION 4
+#define SM_CXBORDER 5
+#define SM_CYBORDER 6
+#define SM_CXDLGFRAME 7
+#define SM_CYDLGFRAME 8
+#define SM_CYVTHUMB 9
+#define SM_CXHTHUMB 10
+#define SM_CXICON 11
+#define SM_CYICON 12
+#define SM_CXCURSOR 13
+#define SM_CYCURSOR 14
+#define SM_CYMENU 15
+#define SM_CXFULLSCREEN 16
+#define SM_CYFULLSCREEN 17
+#define SM_CYKANJIWINDOW 18
+#define SM_MOUSEPRESENT 19
+#define SM_CYVSCROLL 20
+#define SM_CXHSCROLL 21
+#define SM_DEBUG 22
+#define SM_SWAPBUTTON 23
+#define SM_RESERVED1 24
+#define SM_RESERVED2 25
+#define SM_RESERVED3 26
+#define SM_RESERVED4 27
+#define SM_CXMIN 28
+#define SM_CYMIN 29
+#define SM_CXSIZE 30
+#define SM_CYSIZE 31
+#define SM_CXFRAME 32
+#define SM_CYFRAME 33
+#define SM_CXMINTRACK 34
+#define SM_CYMINTRACK 35
+
+#if (WINVER >= 0x030a)
+#define SM_CXDOUBLECLK 36
+#define SM_CYDOUBLECLK 37
+#define SM_CXICONSPACING 38
+#define SM_CYICONSPACING 39
+#define SM_MENUDROPALIGNMENT 40
+#define SM_PENWINDOWS 41
+#define SM_DBCSENABLED 42
+#endif /* WINVER >= 0x030a */
+
+#define SM_MAX 42 /* ;Internal */
+#define SM_CMETRICS 43
+
+#endif /* NOSYSMETRICS */
+
+UINT WINAPI GetDoubleClickTime(void);
+void WINAPI SetDoubleClickTime(UINT);
+
+#define WM_DEVMODECHANGE 0x001B
+#define WM_TIMECHANGE 0x001E
+#define WM_FILESYSCHANGE 0x0034 /* ;Internal */
+
+/****** System Parameters support ********************************************/
+
+#if (WINVER >= 0x030a)
+#ifndef NOSYSTEMPARAMSINFO
+
+BOOL WINAPI SystemParametersInfo(UINT, UINT, VOID FAR*, UINT);
+
+#define SPI_GETBEEP 1
+#define SPI_SETBEEP 2
+#define SPI_GETMOUSE 3
+#define SPI_SETMOUSE 4
+#define SPI_GETBORDER 5
+#define SPI_SETBORDER 6
+#define SPI_TIMEOUTS 7 /* ;Internal */
+#define SPI_KANJIMENU 8 /* ;Internal */
+#define SPI_GETKEYBOARDSPEED 10
+#define SPI_SETKEYBOARDSPEED 11
+#define SPI_LANGDRIVER 12
+#define SPI_ICONHORIZONTALSPACING 13
+#define SPI_GETSCREENSAVETIMEOUT 14
+#define SPI_SETSCREENSAVETIMEOUT 15
+#define SPI_GETSCREENSAVEACTIVE 16
+#define SPI_SETSCREENSAVEACTIVE 17
+#define SPI_GETGRIDGRANULARITY 18
+#define SPI_SETGRIDGRANULARITY 19
+#define SPI_SETDESKWALLPAPER 20
+#define SPI_SETDESKPATTERN 21
+#define SPI_GETKEYBOARDDELAY 22
+#define SPI_SETKEYBOARDDELAY 23
+#define SPI_ICONVERTICALSPACING 24
+#define SPI_GETICONTITLEWRAP 25
+#define SPI_SETICONTITLEWRAP 26
+#define SPI_GETMENUDROPALIGNMENT 27
+#define SPI_SETMENUDROPALIGNMENT 28
+#define SPI_SETDOUBLECLKWIDTH 29
+#define SPI_SETDOUBLECLKHEIGHT 30
+#define SPI_GETICONTITLELOGFONT 31
+#define SPI_SETDOUBLECLICKTIME 32
+#define SPI_SETMOUSEBUTTONSWAP 33
+#define SPI_SETICONTITLELOGFONT 34
+#define SPI_GETFASTTASKSWITCH 35
+#define SPI_SETFASTTASKSWITCH 36
+#define SPI_MAX 36 /* ;Internal */
+
+/* SystemParametersInfo flags */
+#define SPIF_UPDATEINIFILE 0x0001
+#define SPIF_SENDWININICHANGE 0x0002
+#define SPIF_VALID 0x0003 /* ;Internal */
+
+#endif /* NOSYSTEMPARAMSINFO */
+#endif /* WINVER >= 0x030a */
+
+/****** Rectangle support ****************************************************/
+
+void WINAPI SetRect(RECT FAR*, int, int, int, int);
+void WINAPI SetRectEmpty(RECT FAR*);
+
+void WINAPI CopyRect(RECT FAR*, const RECT FAR*);
+
+BOOL WINAPI IsRectEmpty(const RECT FAR*);
+
+BOOL WINAPI EqualRect(const RECT FAR*, const RECT FAR*);
+
+BOOL WINAPI IntersectRect(RECT FAR*, const RECT FAR*, const RECT FAR*);
+BOOL WINAPI UnionRect(RECT FAR*, const RECT FAR*, const RECT FAR*);
+BOOL WINAPI SubtractRect(RECT FAR*, const RECT FAR*, const RECT FAR*);
+
+void WINAPI OffsetRect(RECT FAR*, int, int);
+void WINAPI InflateRect(RECT FAR*, int, int);
+
+BOOL WINAPI PtInRect(const RECT FAR*, POINT);
+
+/****** Window message support ***********************************************/
+
+UINT WINAPI RegisterWindowMessage(LPCSTR);
+
+#define WM_NULL 0x0000
+
+/* NOTE: All messages below 0x0400 are RESERVED by Windows */
+#define WM_USER 0x0400
+
+#ifndef NOMSG
+
+/* Queued message structure */
+typedef struct tagMSG
+{
+ HWND hwnd;
+ UINT message;
+ WPARAM wParam;
+ LPARAM lParam;
+ DWORD time;
+ POINT pt;
+} MSG;
+typedef MSG* PMSG;
+typedef MSG NEAR* NPMSG;
+typedef MSG FAR* LPMSG;
+
+BOOL WINAPI GetMessage(MSG FAR*, HWND, UINT, UINT);
+BOOL WINAPI PeekMessage(MSG FAR*, HWND, UINT, UINT, UINT);
+
+/* PeekMessage() options */
+#define PM_NOREMOVE 0x0000
+#define PM_REMOVE 0x0001
+#define PM_NOYIELD 0x0002
+#define PM_VALID 0x0003 /* ;Internal */
+
+void WINAPI WaitMessage(void);
+
+DWORD WINAPI GetMessagePos(void);
+LONG WINAPI GetMessageTime(void);
+#if (WINVER >= 0x030a)
+LPARAM WINAPI GetMessageExtraInfo(void);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI TranslateMessage(const MSG FAR*);
+LONG WINAPI DispatchMessage(const MSG FAR*);
+
+BOOL WINAPI SetMessageQueue(int);
+
+BOOL WINAPI GetInputState(void);
+
+#if (WINVER >= 0x030a)
+DWORD WINAPI GetQueueStatus(UINT flags);
+
+/* GetQueueStatus flags */
+#define QS_KEY 0x0001
+#define QS_MOUSEMOVE 0x0002
+#define QS_MOUSEBUTTON 0x0004
+#define QS_MOUSE (QS_MOUSEMOVE | QS_MOUSEBUTTON)
+#define QS_POSTMESSAGE 0x0008
+#define QS_TIMER 0x0010
+#define QS_PAINT 0x0020
+#define QS_SENDMESSAGE 0x0040
+
+#define QS_ALLINPUT 0x007f
+#define QS_VALID 0x007f /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOMSG */
+
+BOOL WINAPI PostMessage(HWND, UINT, WPARAM, LPARAM);
+LRESULT WINAPI SendMessage(HWND, UINT, WPARAM, LPARAM);
+
+#ifndef NOMSG
+
+BOOL WINAPI PostAppMessage(HTASK, UINT, WPARAM, LPARAM);
+
+void WINAPI ReplyMessage(LRESULT);
+BOOL WINAPI InSendMessage(void);
+
+/* Special HWND value for use with PostMessage() and SendMessage() */
+#define HWND_BROADCAST ((HWND)0xffff)
+
+BOOL WINAPI CallMsgFilter(MSG FAR*, int);
+
+#define WH_GETMESSAGE 3
+
+#define WH_CALLWNDPROC 4
+
+#define WH_MSGFILTER (-1)
+#define WH_SYSMSGFILTER 6
+
+/* CallMsgFilter() and WH_SYS/MSGFILTER context codes */
+#define MSGF_DIALOGBOX 0
+#define MSGF_MESSAGEBOX 1 /* ;Internal */
+#define MSGF_MENU 2
+#define MSGF_MOVE 3
+#define MSGF_SIZE 4
+#define MSGF_SCROLLBAR 5
+#define MSGF_NEXTWINDOW 6
+#define MSGF_CBTHOSEBAGSUSEDTHIS 7 /* ;Internal */
+#define MSGF_MAINLOOP 8
+#define MSGF_USER 4096
+#endif /* NOMSG */
+
+/* Standard window messages */
+/* PenWindows specific messages */
+#define WM_PENWINFIRST 0x0380
+#define WM_PENWINLAST 0x038F
+
+/* Coalescing messages */
+#define WM_COALESCE_FIRST 0x0390
+#define WM_COALESCE_LAST 0x039F
+
+/* Reserved message ranges */ /* ;Internal */
+#define WM_KANJIFIRST 0x0280 /* JAPAN */ /* ;Internal */
+#define WM_KANJILAST 0x029F /* JAPAN */ /* ;Internal */
+#define WM_HANGEULFIRST 0x0280 /* KOREA */ /* ;Internal */
+#define WM_HANGEULLAST 0x029F /* KOREA */ /* ;Internal */
+ /* ;Internal */
+ /* ;Internal */
+#define WM_INTERNAL_COALESCE_FIRST 0x0390 /* ;Internal */
+ /* ;Internal */
+ /* ;Internal */
+/* The following message range reserved */ /* ;Internal */
+/* for multi-media */ /* ;Internal */
+#define WM_MM_RESERVED_FIRST 0x03A0 /* ;Internal */
+#define WM_MM_RESERVED_LAST 0x03DF /* ;Internal */
+#define WM_INTERNAL_COALESCE_LAST 0x03b0 /* ;Internal */
+ /* ;Internal */
+#define WM_INTERNAL_DDE_FIRST 0x03E0 /* ;Internal */
+#define WM_INTERNAL_DDE_LAST 0x03EF /* ;Internal */
+ /* ;Internal */
+/* The following message range reserved */ /* ;Internal */
+/* for CBT */ /* ;Internal */
+#define WM_CBT_RESERVED_FIRST 0x03F0 /* ;Internal */
+#define WM_CBT_RESERVED_LAST 0x03FF /* ;Internal */
+
+#if (WINVER >= 0x030a)
+/****** Power management ****************************************************/
+#define WM_POWER 0x0048
+
+/* wParam for WM_POWER window message and DRV_POWER driver notification */
+#define PWR_OK 1
+#define PWR_FAIL (-1)
+#define PWR_SUSPENDREQUEST 1
+#define PWR_SUSPENDRESUME 2
+#define PWR_CRITICALRESUME 3
+#endif /* WINVER >= 0x030a */
+
+/****** Application termination *********************************************/
+
+#define WM_QUERYENDSESSION 0x0011
+#define WM_ENDSESSION 0x0016
+
+#define WM_QUIT 0x0012
+
+void WINAPI PostQuitMessage(int);
+
+#define WM_SYSTEMERROR 0x0017
+
+/****** Window class management *********************************************/
+
+typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
+
+typedef struct tagWNDCLASS
+{
+ UINT style;
+ WNDPROC lpfnWndProc;
+ int cbClsExtra;
+ int cbWndExtra;
+ HINSTANCE hInstance;
+ HICON hIcon;
+ HCURSOR hCursor;
+ HBRUSH hbrBackground;
+ LPCSTR lpszMenuName;
+ LPCSTR lpszClassName;
+} WNDCLASS;
+typedef WNDCLASS* PWNDCLASS;
+typedef WNDCLASS NEAR* NPWNDCLASS;
+typedef WNDCLASS FAR* LPWNDCLASS;
+
+ATOM WINAPI RegisterClass(const WNDCLASS FAR*);
+BOOL WINAPI UnregisterClass(LPCSTR, HINSTANCE);
+
+BOOL WINAPI GetClassInfo(HINSTANCE, LPCSTR, WNDCLASS FAR*);
+int WINAPI GetClassName(HWND, LPSTR, int);
+
+#ifndef NOWINSTYLES
+
+/* Class styles */
+#define CS_VREDRAW 0x0001
+#define CS_HREDRAW 0x0002
+
+#define CS_OWNDC 0x0020
+#define CS_CLASSDC 0x0040
+#define CS_PARENTDC 0x0080
+
+#define CS_SAVEBITS 0x0800
+
+#define CS_DBLCLKS 0x0008
+
+#define CS_BYTEALIGNCLIENT 0x1000
+#define CS_BYTEALIGNWINDOW 0x2000
+
+#define CS_NOCLOSE 0x0200
+
+#define CS_KEYCVTWINDOW 0x0004
+#define CS_NOKEYCVT 0x0100
+
+#define CS_GLOBALCLASS 0x4000
+#define CS_VALID 0x7fef /* ;Internal */
+#endif /* NOWINSTYLES */
+
+#ifndef NOWINOFFSETS
+
+WORD WINAPI GetClassWord(HWND, int);
+WORD WINAPI SetClassWord(HWND, int, WORD);
+LONG WINAPI GetClassLong(HWND, int);
+LONG WINAPI SetClassLong(HWND, int, LONG);
+
+/* Class field offsets for GetClassLong() and GetClassWord() */
+#define GCL_MENUNAME (-8)
+#define GCW_HBRBACKGROUND (-10)
+#define GCW_HCURSOR (-12)
+#define GCW_HICON (-14)
+#define GCW_HMODULE (-16)
+#define GCW_CBWNDEXTRA (-18)
+#define GCW_CBCLSEXTRA (-20)
+#define GCL_WNDPROC (-24)
+#define GCW_STYLE (-26)
+
+#if (WINVER >= 0x030a)
+#define GCW_ATOM (-32)
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOWINOFFSETS */
+
+/****** Window creation/destroy *********************************************/
+
+/* Window Styles */
+#ifndef NOWINSTYLES
+
+/* Basic window types */
+#define WS_OVERLAPPED 0x00000000L
+#define WS_POPUP 0x80000000L
+#define WS_CHILD 0x40000000L
+
+/* Clipping styles */
+#define WS_CLIPSIBLINGS 0x04000000L
+#define WS_CLIPCHILDREN 0x02000000L
+
+/* Generic window states */
+#define WS_VISIBLE 0x10000000L
+#define WS_DISABLED 0x08000000L
+
+/* Main window states */
+#define WS_MINIMIZE 0x20000000L
+#define WS_MAXIMIZE 0x01000000L
+
+/* Main window styles */
+#define WS_CAPTION 0x00C00000L /* WS_BORDER | WS_DLGFRAME */
+#define WS_BORDER 0x00800000L
+#define WS_DLGFRAME 0x00400000L
+#define WS_VSCROLL 0x00200000L
+#define WS_HSCROLL 0x00100000L
+#define WS_SYSMENU 0x00080000L
+#define WS_THICKFRAME 0x00040000L
+#define WS_MINIMIZEBOX 0x00020000L
+#define WS_MAXIMIZEBOX 0x00010000L
+
+/* Control window styles */
+#define WS_GROUP 0x00020000L
+#define WS_TABSTOP 0x00010000L
+
+/* Common Window Styles */
+#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
+#define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU)
+#define WS_CHILDWINDOW (WS_CHILD)
+
+/* Extended Window Styles */
+#define WS_EX_DLGMODALFRAME 0x00000001L
+#define WS_EX_DRAGOBJECT 0x00000002L /* ;Internal */
+#define WS_EX_NOPARENTNOTIFY 0x00000004L
+
+#if (WINVER >= 0x030a)
+#define WS_EX_TOPMOST 0x00000008L
+#define WS_EX_ACCEPTFILES 0x00000010L
+#define WS_EX_TRANSPARENT 0x00000020L
+#define WS_EX_VALID 0x0000003fL /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+/* Obsolete style names */
+#define WS_TILED WS_OVERLAPPED
+#define WS_ICONIC WS_MINIMIZE
+#define WS_SIZEBOX WS_THICKFRAME
+#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW
+
+#define WS_VALID 0xffff0000L /* ;Internal */
+
+#endif /* NOWINSTYLES */
+
+/* Special value for CreateWindow, et al. */
+#define HWND_DESKTOP ((HWND)0)
+
+BOOL WINAPI IsWindow(HWND);
+
+HWND WINAPI CreateWindowEx(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);
+HWND WINAPI CreateWindow(LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);
+
+#define WM_CREATE 0x0001
+#define WM_NCCREATE 0x0081
+
+/* WM_CREATE/WM_NCCREATE lParam struct */
+typedef struct tagCREATESTRUCT
+{
+ void FAR* lpCreateParams;
+ HINSTANCE hInstance;
+ HMENU hMenu;
+ HWND hwndParent;
+ int cy;
+ int cx;
+ int y;
+ int x;
+ LONG style;
+ LPCSTR lpszName;
+ LPCSTR lpszClass;
+ DWORD dwExStyle;
+} CREATESTRUCT;
+typedef CREATESTRUCT FAR* LPCREATESTRUCT;
+
+BOOL WINAPI DestroyWindow(HWND);
+
+#define WM_DESTROY 0x0002
+#define WM_NCDESTROY 0x0082
+
+/* Basic window attributes */
+
+HTASK WINAPI GetWindowTask(HWND);
+
+BOOL WINAPI IsChild(HWND, HWND);
+
+HWND WINAPI GetParent(HWND);
+HWND WINAPI SetParent(HWND, HWND);
+
+BOOL WINAPI IsWindowVisible(HWND);
+
+BOOL WINAPI ShowWindow(HWND, int);
+
+#define WM_SETVISIBLE 0x0009 /* ;Internal */
+
+#ifndef NOSHOWWINDOW
+
+#define SW_HIDE 0
+#define SW_SHOWNORMAL 1
+#define SW_NORMAL 1
+#define SW_SHOWMINIMIZED 2
+#define SW_SHOWMAXIMIZED 3
+#define SW_MAXIMIZE 3
+#define SW_SHOWNOACTIVATE 4
+#define SW_SHOW 5
+#define SW_MINIMIZE 6
+#define SW_SHOWMINNOACTIVE 7
+#define SW_SHOWNA 8
+#define SW_RESTORE 9
+#define SW_MAX 9 /* ;Internal */
+
+/* Obsolete ShowWindow() command names */
+#define HIDE_WINDOW 0
+#define SHOW_OPENWINDOW 1
+#define SHOW_ICONWINDOW 2
+#define SHOW_FULLSCREEN 3
+#define SHOW_OPENNOACTIVATE 4
+
+#define WM_SHOWWINDOW 0x0018
+
+/* WM_SHOWWINDOW wParam codes */
+#define SW_PARENTCLOSING 1
+#define SW_OTHERMAXIMIZED 2
+#define SW_PARENTOPENING 3
+#define SW_OTHERRESTORED 4
+
+/* Obsolete constant names */
+#define SW_OTHERZOOM SW_OTHERMAXIMIZED
+#define SW_OTHERUNZOOM SW_OTHERRESTORED
+#endif /* NOSHOWWINDOW */
+
+#define WM_SETREDRAW 0x000B
+
+/* Enabled state */
+BOOL WINAPI EnableWindow(HWND,BOOL);
+BOOL WINAPI IsWindowEnabled(HWND);
+
+#define WM_ENABLE 0x000A
+
+/* Window text */
+void WINAPI SetWindowText(HWND, LPCSTR);
+int WINAPI GetWindowText(HWND, LPSTR, int);
+int WINAPI GetWindowTextLength(HWND);
+
+#define WM_SETTEXT 0x000C
+#define WM_GETTEXT 0x000D
+#define WM_GETTEXTLENGTH 0x000E
+
+/* Window words */
+WORD WINAPI GetWindowWord(HWND, int);
+WORD WINAPI SetWindowWord(HWND, int, WORD);
+LONG WINAPI GetWindowLong(HWND, int);
+LONG WINAPI SetWindowLong(HWND, int, LONG);
+
+/* Window field offsets for GetWindowLong() and GetWindowWord() */
+#ifndef NOWINOFFSETS
+#define GWL_WNDPROC (-4)
+#define GWW_HINSTANCE (-6)
+#define GWW_HWNDPARENT (-8)
+#define GWW_ID (-12)
+#define GWL_STYLE (-16)
+#define GWL_EXSTYLE (-20)
+#endif /* NOWINOFFSETS */
+
+/****** Window size, position, Z-order, and visibility **********************/
+
+#define CW_USEDEFAULT ((int)0x8000)
+
+void WINAPI GetClientRect(HWND, RECT FAR*);
+void WINAPI GetWindowRect(HWND, RECT FAR*);
+
+
+#if (WINVER >= 0x030a)
+typedef struct tagWINDOWPLACEMENT
+{
+ UINT length;
+ UINT flags;
+ UINT showCmd;
+ POINT ptMinPosition;
+ POINT ptMaxPosition;
+ RECT rcNormalPosition;
+} WINDOWPLACEMENT;
+typedef WINDOWPLACEMENT *PWINDOWPLACEMENT;
+typedef WINDOWPLACEMENT FAR* LPWINDOWPLACEMENT;
+
+#define WPF_SETMINPOSITION 0x0001
+#define WPF_RESTORETOMAXIMIZED 0x0002
+#define WPF_VALID 0x0003 /* ;Internal */
+
+BOOL WINAPI GetWindowPlacement(HWND, WINDOWPLACEMENT FAR*);
+BOOL WINAPI SetWindowPlacement(HWND, const WINDOWPLACEMENT FAR*);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI SetWindowPos(HWND, HWND, int, int, int, int, UINT);
+
+/* SetWindowPos() and WINDOWPOS flags */
+#define SWP_NOSIZE 0x0001
+#define SWP_NOMOVE 0x0002
+#define SWP_NOZORDER 0x0004
+#define SWP_NOREDRAW 0x0008
+#define SWP_NOACTIVATE 0x0010
+#define SWP_FRAMECHANGED 0x0020 /* The frame changed: send WM_NCCALCSIZE */
+#define SWP_SHOWWINDOW 0x0040
+#define SWP_HIDEWINDOW 0x0080
+#define SWP_NOCOPYBITS 0x0100
+#define SWP_NOOWNERZORDER 0x0200 /* Don't do owner Z ordering */
+
+#define SWP_DRAWFRAME SWP_FRAMECHANGED
+#define SWP_NOREPOSITION SWP_NOOWNERZORDER
+
+#define SWP_NOCLIENTSIZE 0x0800 /* Client didn't resize */ /* ;Internal */
+#define SWP_NOCLIENTMOVE 0x1000 /* Client didn't move */ /* ;Internal */
+#define SWP_NOSENDCHANGING 0x0400
+#define SWP_DEFERERASE 0x2000
+#define SWP_DEFERDRAWING SWP_DEFERERASE /* Don't do any drawing or erasing */ /* ;Internal */
+ /* ;Internal */
+#define SWP_CHANGEMASK (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | /* ;Internal */ \
+ SWP_FRAMECHANGED | /* ;Internal */ \
+ SWP_SHOWWINDOW | SWP_HIDEWINDOW | /* ;Internal */ \
+ SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE) /* ;Internal */
+ /* ;Internal */
+#define SWP_NOCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | /* ;Internal */ \
+ SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE) /* ;Internal */
+#define SWP_VALID 0x27ff /* ;Internal */
+
+/* SetWindowPos() hwndInsertAfter field values */
+#define HWND_TOP ((HWND)0)
+#define HWND_BOTTOM ((HWND)1)
+#define HWND_TOPMOST ((HWND)-1)
+#define HWND_NOTOPMOST ((HWND)-2)
+#define HWND_GROUPTOTOP HWND_TOPMOST /* ;Internal */
+
+#ifndef NODEFERWINDOWPOS
+
+DECLARE_HANDLE(HDWP);
+
+HDWP WINAPI BeginDeferWindowPos(int);
+HDWP WINAPI DeferWindowPos(HDWP, HWND, HWND, int, int, int, int, UINT);
+BOOL WINAPI EndDeferWindowPos(HDWP);
+
+#endif /* NODEFERWINDOWPOS */
+
+BOOL WINAPI MoveWindow(HWND, int, int, int, int, BOOL);
+BOOL WINAPI BringWindowToTop(HWND);
+
+#if (WINVER >= 0x030a)
+
+#define WM_WINDOWPOSCHANGING 0x0046
+#define WM_WINDOWPOSCHANGED 0x0047
+
+/* WM_WINDOWPOSCHANGING/CHANGED struct pointed to by lParam */
+typedef struct tagWINDOWPOS
+{
+ HWND hwnd;
+ HWND hwndInsertAfter;
+ int x;
+ int y;
+ int cx;
+ int cy;
+ UINT flags;
+} WINDOWPOS;
+typedef WINDOWPOS FAR* LPWINDOWPOS;
+#endif /* WINVER >= 0x030a */
+
+#define WM_MOVE 0x0003
+#define WM_SIZEWAIT 0x0004 /* ;Internal */
+#define WM_SIZE 0x0005
+
+/* WM_SIZE message wParam values */
+#define SIZE_RESTORED 0
+#define SIZE_MINIMIZED 1
+#define SIZE_MAXIMIZED 2
+#define SIZE_MAXSHOW 3
+#define SIZE_MAXHIDE 4
+
+/* Obsolete constant names */
+#define SIZENORMAL SIZE_RESTORED
+#define SIZEICONIC SIZE_MINIMIZED
+#define SIZEFULLSCREEN SIZE_MAXIMIZED
+#define SIZEZOOMSHOW SIZE_MAXSHOW
+#define SIZEZOOMHIDE SIZE_MAXHIDE
+
+/****** Window proc implementation & subclassing support *********************/
+
+LRESULT WINAPI DefWindowProc(HWND, UINT, WPARAM, LPARAM);
+
+#ifdef STRICT
+LRESULT WINAPI CallWindowProc(WNDPROC, HWND, UINT, WPARAM, LPARAM);
+#else
+LRESULT WINAPI CallWindowProc(FARPROC, HWND, UINT, WPARAM, LPARAM);
+#endif
+
+/****** Main window support **************************************************/
+
+void WINAPI AdjustWindowRect(RECT FAR*, DWORD, BOOL);
+void WINAPI AdjustWindowRectEx(RECT FAR*, DWORD, BOOL, DWORD);
+
+#define WM_QUERYOPEN 0x0013
+#define WM_CLOSE 0x0010
+
+/* Struct pointed to by WM_GETMINMAXINFO lParam */
+typedef struct tagMINMAXINFO
+{
+ POINT ptReserved;
+ POINT ptMaxSize;
+ POINT ptMaxPosition;
+ POINT ptMinTrackSize;
+ POINT ptMaxTrackSize;
+} MINMAXINFO;
+#define WM_GETMINMAXINFO 0x0024
+
+#define WM_ENTERSIZEMOVE 0x0231 /* ;Internal */
+#define WM_EXITSIZEMOVE 0x0232 /* ;Internal */
+#define WM_ISACTIVEICON 0x0035 /* ;Internal */
+#define WM_UNUSED0036 0x0036 /* ;Internal */
+#define WM_TESTING 0x0040 /* ;Internal */
+
+BOOL WINAPI FlashWindow(HWND, BOOL);
+
+void WINAPI ShowOwnedPopups(HWND, BOOL);
+
+/* Obsolete functions */
+BOOL WINAPI OpenIcon(HWND);
+void WINAPI CloseWindow(HWND);
+BOOL WINAPI AnyPopup(void);
+BOOL WINAPI IsIconic(HWND);
+BOOL WINAPI IsZoomed(HWND);
+
+/****** Window coordinate mapping and hit-testing ***************************/
+
+void WINAPI ClientToScreen(HWND, POINT FAR*);
+void WINAPI ScreenToClient(HWND, POINT FAR*);
+
+#if (WINVER >= 0x030a)
+void WINAPI MapWindowPoints(HWND hwndFrom, HWND hwndTo, POINT FAR* lppt, UINT cpt);
+#endif /* WINVER >= 0x030a */
+
+HWND WINAPI WindowFromPoint(POINT);
+HWND WINAPI ChildWindowFromPoint(HWND, POINT);
+
+/****** Window query and enumeration ****************************************/
+
+HWND WINAPI GetDesktopWindow(void);
+
+HWND WINAPI FindWindow(LPCSTR, LPCSTR);
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);
+#else
+typedef FARPROC WNDENUMPROC;
+#endif
+
+BOOL WINAPI EnumWindows(WNDENUMPROC, LPARAM);
+BOOL WINAPI EnumChildWindows(HWND, WNDENUMPROC, LPARAM);
+BOOL WINAPI EnumTaskWindows(HTASK, WNDENUMPROC, LPARAM);
+
+HWND WINAPI GetTopWindow(HWND);
+
+HWND WINAPI GetWindow(HWND, UINT);
+HWND WINAPI GetNextWindow(HWND, UINT);
+
+/* GetWindow() constants */
+#define GW_HWNDFIRST 0
+#define GW_HWNDLAST 1
+#define GW_HWNDNEXT 2
+#define GW_HWNDPREV 3
+#define GW_OWNER 4
+#define GW_CHILD 5
+#define GW_MAX 5 /* ;Internal */
+
+HWND WINAPI GetNextQueueWindow(HWND, int); /* ;Internal */
+
+/****** Window property support *********************************************/
+
+BOOL WINAPI SetProp(HWND, LPCSTR, HANDLE);
+HANDLE WINAPI GetProp(HWND, LPCSTR);
+HANDLE WINAPI RemoveProp(HWND, LPCSTR);
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* PROPENUMPROC)(HWND, LPCSTR, HANDLE);
+#else
+typedef FARPROC PROPENUMPROC;
+#endif
+
+int WINAPI EnumProps(HWND, PROPENUMPROC);
+
+/****** Window drawing support **********************************************/
+
+HDC WINAPI GetDC(HWND);
+int WINAPI ReleaseDC(HWND, HDC);
+
+HDC WINAPI GetWindowDC(HWND);
+
+#if (WINVER >= 0x030a)
+HDC WINAPI GetDCEx(register HWND hwnd, HRGN hrgnClip, DWORD flags);
+
+#define DCX_WINDOW 0x00000001L
+#define DCX_CACHE 0x00000002L
+#define DCX_NORESETATTRS 0x00000004L /* ;Internal */
+#define DCX_CLIPCHILDREN 0x00000008L
+#define DCX_CLIPSIBLINGS 0x00000010L
+#define DCX_PARENTCLIP 0x00000020L
+
+#define DCX_EXCLUDERGN 0x00000040L
+#define DCX_INTERSECTRGN 0x00000080L
+
+#define DCX_EXCLUDEUPDATE 0x00000100L /* ;Internal */
+#define DCX_INTERSECTUPDATE 0x00000200L /* ;Internal */
+
+#define DCX_LOCKWINDOWUPDATE 0x00000400L
+
+#define DCX_INVALID 0x00000800L /* ;Internal */
+#define DCX_INUSE 0x00001000L /* ;Internal */
+#define DCX_SAVEDRGNINVALID 0x00002000L /* ;Internal */
+
+#define DCX_USESTYLE 0x00010000L
+#define DCX_NEEDFONT 0x00020000L /* ;Internal */
+#define DCX_NODELETERGN 0x00040000L /* ;Internal */
+#define DCX_NOCLIPCHILDREN 0x00080000L /* ;Internal */
+#define DCX_NORECOMPUTE 0x00100000L /* ;Internal */
+#define DCX_VALIDATE 0x00200000L /* ;Internal */
+
+#define DCX_MATCHMASK (DCX_WINDOW | DCX_CACHE | /* ;Internal */ \
+ DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | /* ;Internal */ \
+ DCX_LOCKWINDOWUPDATE /* ;Internal */ \
+ ) /* ;Internal */
+#define DCX_VALID 0x000104fbL /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+/****** Window repainting ***************************************************/
+
+#define WM_PAINT 0x000F
+#define WM_ERASEBKGND 0x0014
+#define WM_PAINTICON 0x0026 /* ;Internal */
+#define WM_ICONERASEBKGND 0x0027
+#define WM_SYNCPAINT 0x0088 /* ;Internal */
+#define WM_SYNCTASK 0x0089 /* ;Internal */
+
+/* BeginPaint() return structure */
+typedef struct tagPAINTSTRUCT
+{
+ HDC hdc;
+ BOOL fErase;
+ RECT rcPaint;
+ BOOL fRestore;
+ BOOL fIncUpdate;
+ BYTE rgbReserved[16];
+} PAINTSTRUCT;
+typedef PAINTSTRUCT* PPAINTSTRUCT;
+typedef PAINTSTRUCT NEAR* NPPAINTSTRUCT;
+typedef PAINTSTRUCT FAR* LPPAINTSTRUCT;
+
+HDC WINAPI BeginPaint(HWND, PAINTSTRUCT FAR*);
+void WINAPI EndPaint(HWND, const PAINTSTRUCT FAR*);
+
+void WINAPI UpdateWindow(HWND);
+
+int WINAPI ExcludeUpdateRgn(HDC, HWND);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI LockWindowUpdate(HWND hwndLock);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI GetUpdateRect(HWND, RECT FAR*, BOOL);
+int WINAPI GetUpdateRgn(HWND, HRGN, BOOL);
+
+void WINAPI InvalidateRect(HWND, const RECT FAR*, BOOL);
+void WINAPI ValidateRect(HWND, const RECT FAR*);
+
+void WINAPI InvalidateRgn(HWND, HRGN, BOOL);
+void WINAPI ValidateRgn(HWND, HRGN);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI RedrawWindow(HWND hwnd, const RECT FAR* lprcUpdate, HRGN hrgnUpdate, UINT flags);
+
+#define RDW_INVALIDATE 0x0001
+#define RDW_INTERNALPAINT 0x0002
+#define RDW_ERASE 0x0004
+
+#define RDW_VALIDATE 0x0008
+#define RDW_NOINTERNALPAINT 0x0010
+#define RDW_NOERASE 0x0020
+
+#define RDW_NOCHILDREN 0x0040
+#define RDW_ALLCHILDREN 0x0080
+
+#define RDW_UPDATENOW 0x0100
+#define RDW_ERASENOW 0x0200
+
+#define RDW_FRAME 0x0400
+#define RDW_NOFRAME 0x0800
+ /* ;Internal */
+#define RDW_REDRAWWINDOW 0x1000 /* Called from RedrawWindow()*/ /* ;Internal */
+#define RDW_SUBTRACTSELF 0x2000 /* Subtract self from hrgn */ /* ;Internal */
+ /* ;Internal */
+#define RDW_COPYRGN 0x4000 /* Copy the passed-in region */ /* ;Internal */
+#define RDW_VALID 0x0fff /* ;Internal */
+
+#endif /* WINVER >= 0x030a */
+
+/****** Window scrolling ****************************************************/
+
+void WINAPI ScrollWindow(HWND, int, int, const RECT FAR*, const RECT FAR*);
+BOOL WINAPI ScrollDC(HDC, int, int, const RECT FAR*, const RECT FAR*, HRGN, RECT FAR*);
+
+#if (WINVER >= 0x030a)
+
+int WINAPI ScrollWindowEx(HWND hwnd, int dx, int dy,
+ const RECT FAR* prcScroll, const RECT FAR* prcClip,
+ HRGN hrgnUpdate, RECT FAR* prcUpdate, UINT flags);
+
+#define SW_SCROLLCHILDREN 0x0001
+#define SW_INVALIDATE 0x0002
+#define SW_ERASE 0x0004
+
+#define SW_SCROLLWINDOW 0x8000 /* ;Internal */
+#define SW_VALID 0x8007 /* ;Internal */
+
+#endif /* WINVER >= 0x030a */
+
+/****** Non-client window area management ************************************/
+
+#define WM_NCPAINT 0x0085
+
+#define WM_NCCALCSIZE 0x0083
+
+#if (WINVER >= 0x030a)
+/* WM_NCCALCSIZE return flags */
+#define WVR_ALIGNTOP 0x0010
+#define WVR_ALIGNLEFT 0x0020
+#define WVR_ALIGNBOTTOM 0x0040
+#define WVR_ALIGNRIGHT 0x0080
+#define WVR_HREDRAW 0x0100
+#define WVR_VREDRAW 0x0200
+#define WVR_REDRAW (WVR_HREDRAW | WVR_VREDRAW)
+#define WVR_VALIDRECTS 0x0400
+
+#define WVR_MINVALID WVR_ALIGNTOP /* ;Internal */
+#define WVR_MAXVALID WVR_VALIDRECTS /* ;Internal */
+
+/* WM_NCCALCSIZE parameter structure */
+typedef struct tagNCCALCSIZE_PARAMS
+{
+ RECT rgrc[3];
+ WINDOWPOS FAR* lppos;
+} NCCALCSIZE_PARAMS;
+#else /* WINVER >= 0x030a */
+typedef struct tagNCCALCSIZE_PARAMS
+{
+ RECT rgrc[2];
+} NCCALCSIZE_PARAMS;
+#endif /* WINVER >= 0x030a */
+typedef NCCALCSIZE_PARAMS FAR* LPNCCALCSIZE_PARAMS;
+
+#define WM_NCHITTEST 0x0084
+
+/* WM_NCHITTEST return codes */
+#define HTERROR (-2)
+#define HTTRANSPARENT (-1)
+#define HTNOWHERE 0
+#define HTCLIENT 1
+#define HTCAPTION 2
+#define HTSYSMENU 3
+#define HTSIZE 4
+#define HTMENU 5
+#define HTHSCROLL 6
+#define HTVSCROLL 7
+#define HTMINBUTTON 8
+#define HTMAXBUTTON 9
+#define HTLEFT 10
+#define HTRIGHT 11
+#define HTTOP 12
+#define HTTOPLEFT 13
+#define HTTOPRIGHT 14
+#define HTBOTTOM 15
+#define HTBOTTOMLEFT 16
+#define HTBOTTOMRIGHT 17
+#define HTBORDER 18
+#define HTGROWBOX HTSIZE
+#define HTREDUCE HTMINBUTTON
+#define HTZOOM HTMAXBUTTON
+#define HTSIZEFIRST HTLEFT /* ;Internal */
+#define HTSIZELAST HTBOTTOMRIGHT /* ;Internal */
+
+/****** Drag-and-drop support ***********************************************/
+
+#define WM_DROPOBJECT 0x022A /* ;Internal */
+#define WM_QUERYDROPOBJECT 0x022B /* ;Internal */
+#define WM_BEGINDRAG 0x022C /* ;Internal */
+#define WM_DRAGLOOP 0x022D /* ;Internal */
+#define WM_DRAGSELECT 0x022E /* ;Internal */
+#define WM_DRAGMOVE 0x022F /* ;Internal */
+#define WM_QUERYDRAGICON 0x0037
+#define WM_DROPFILES 0x0233
+
+/****** Window activation ***************************************************/
+
+HWND WINAPI SetActiveWindow(HWND);
+HWND WINAPI GetActiveWindow(void);
+
+HWND WINAPI GetLastActivePopup(HWND);
+
+/* WM_ACTIVATE state values */
+#define WA_INACTIVE 0
+#define WA_ACTIVE 1
+#define WA_CLICKACTIVE 2
+
+#define WM_ACTIVATE 0x0006
+#define WM_ACTIVATEAPP 0x001C
+#define WM_NCACTIVATE 0x0086
+
+/****** Keyboard input support **********************************************/
+
+HWND WINAPI SetFocus(HWND);
+HWND WINAPI GetFocus(void);
+
+int WINAPI GetKeyState(int);
+int WINAPI GetAsyncKeyState(int);
+
+void WINAPI GetKeyboardState(BYTE FAR* );
+void WINAPI SetKeyboardState(BYTE FAR* );
+
+#define WM_SETFOCUS 0x0007
+#define WM_KILLFOCUS 0x0008
+
+#define WM_KEYDOWN 0x0100
+#define WM_KEYUP 0x0101
+
+#define WM_CHAR 0x0102
+#define WM_DEADCHAR 0x0103
+
+#define WM_SYSKEYDOWN 0x0104
+#define WM_SYSKEYUP 0x0105
+
+#define WM_SYSCHAR 0x0106
+#define WM_SYSDEADCHAR 0x0107
+
+#define WM_YOMICHAR 0x0108 /* JAPAN */ /* ;Internal */
+#define WM_CONVERTREQUEST 0x010A /* JAPAN */ /* ;Internal */
+#define WM_CONVERTRESULT 0x010B /* JAPAN */ /* ;Internal */
+#define WM_INTERIM 0x010C /* KOREA */ /* ;Internal */
+
+/* Keyboard message range */
+#define WM_KEYFIRST 0x0100
+#define WM_KEYLAST 0x0108
+
+/* WM_KEYUP/DOWN/CHAR HIWORD(lParam) flags */
+#define KF_EXTENDED 0x0100
+#define KF_DLGMODE 0x0800
+#define KF_MENUMODE 0x1000
+#define KF_ALTDOWN 0x2000
+#define KF_REPEAT 0x4000
+#define KF_UP 0x8000
+
+/* Virtual key codes */
+#ifndef NOVIRTUALKEYCODES
+#define VK_LBUTTON 0x01
+#define VK_RBUTTON 0x02
+#define VK_CANCEL 0x03
+#define VK_MBUTTON 0x04
+#define VK_BACK 0x08
+#define VK_TAB 0x09
+#define VK_CLEAR 0x0C
+#define VK_RETURN 0x0D
+#define VK_SHIFT 0x10
+#define VK_CONTROL 0x11
+#define VK_MENU 0x12
+#define VK_PAUSE 0x13
+#define VK_CAPITAL 0x14
+#define VK_KANA 0x15 /* JAPAN */ /* ;Internal */
+#define VK_KANJI 0x19 /* JAPAN */ /* ;Internal */
+#define VK_HANGEUL 0x15 /* KOREA */ /* ;Internal */
+#define VK_JUNJA 0x17 /* KOREA */ /* ;Internal */
+#define VK_HANJA 0x19 /* KOREA */ /* ;Internal */
+#define VK_ESCAPE 0x1B
+#define VK_SPACE 0x20
+#define VK_PRIOR 0x21
+#define VK_NEXT 0x22
+#define VK_END 0x23
+#define VK_HOME 0x24
+#define VK_LEFT 0x25
+#define VK_UP 0x26
+#define VK_RIGHT 0x27
+#define VK_DOWN 0x28
+#define VK_SELECT 0x29
+#define VK_PRINT 0x2A
+#define VK_EXECUTE 0x2B
+#define VK_SNAPSHOT 0x2C
+#define VK_INSERT 0x2D
+#define VK_DELETE 0x2E
+#define VK_HELP 0x2F
+#define VK_NUMPAD0 0x60
+#define VK_NUMPAD1 0x61
+#define VK_NUMPAD2 0x62
+#define VK_NUMPAD3 0x63
+#define VK_NUMPAD4 0x64
+#define VK_NUMPAD5 0x65
+#define VK_NUMPAD6 0x66
+#define VK_NUMPAD7 0x67
+#define VK_NUMPAD8 0x68
+#define VK_NUMPAD9 0x69
+#define VK_MULTIPLY 0x6A
+#define VK_ADD 0x6B
+#define VK_SEPARATOR 0x6C
+#define VK_SUBTRACT 0x6D
+#define VK_DECIMAL 0x6E
+#define VK_DIVIDE 0x6F
+#define VK_F1 0x70
+#define VK_F2 0x71
+#define VK_F3 0x72
+#define VK_F4 0x73
+#define VK_F5 0x74
+#define VK_F6 0x75
+#define VK_F7 0x76
+#define VK_F8 0x77
+#define VK_F9 0x78
+#define VK_F10 0x79
+#define VK_F11 0x7A
+#define VK_F12 0x7B
+#define VK_F13 0x7C
+#define VK_F14 0x7D
+#define VK_F15 0x7E
+#define VK_F16 0x7F
+#define VK_F17 0x80
+#define VK_F18 0x81
+#define VK_F19 0x82
+#define VK_F20 0x83
+#define VK_F21 0x84
+#define VK_F22 0x85
+#define VK_F23 0x86
+#define VK_F24 0x87
+#define VK_NUMLOCK 0x90
+#define VK_SCROLL 0x91
+
+/* VK_A thru VK_Z are the same as their ASCII equivalents: 'A' thru 'Z' */
+/* VK_0 thru VK_9 are the same as their ASCII equivalents: '0' thru '0' */
+
+#endif /* NOVIRTUALKEYCODES */
+
+BOOL WINAPI IsTwoByteCharPrefix(char); /* ;Internal */
+
+/* SetWindowsHook() keyboard hook */
+#define WH_KEYBOARD 2
+
+/****** Mouse input support *************************************************/
+
+HWND WINAPI SetCapture(HWND);
+void WINAPI ReleaseCapture(void);
+HWND WINAPI GetCapture(void);
+
+BOOL WINAPI SwapMouseButton(BOOL);
+
+/* Mouse input messages */
+#define WM_MOUSEMOVE 0x0200
+#define WM_LBUTTONDOWN 0x0201
+#define WM_LBUTTONUP 0x0202
+#define WM_LBUTTONDBLCLK 0x0203
+#define WM_RBUTTONDOWN 0x0204
+#define WM_RBUTTONUP 0x0205
+#define WM_RBUTTONDBLCLK 0x0206
+#define WM_MBUTTONDOWN 0x0207
+#define WM_MBUTTONUP 0x0208
+#define WM_MBUTTONDBLCLK 0x0209
+
+/* Mouse input message range */
+#define WM_MOUSEFIRST 0x0200
+#define WM_MOUSELAST 0x0209
+
+/* Mouse message wParam key states */
+#ifndef NOKEYSTATES
+#define MK_LBUTTON 0x0001
+#define MK_RBUTTON 0x0002
+#define MK_SHIFT 0x0004
+#define MK_CONTROL 0x0008
+#define MK_MBUTTON 0x0010
+#endif /* NOKEYSTATES */
+
+/* Non-client mouse messages */
+#define WM_NCMOUSEMOVE 0x00A0
+#define WM_NCLBUTTONDOWN 0x00A1
+#define WM_NCLBUTTONUP 0x00A2
+#define WM_NCLBUTTONDBLCLK 0x00A3
+#define WM_NCRBUTTONDOWN 0x00A4
+#define WM_NCRBUTTONUP 0x00A5
+#define WM_NCRBUTTONDBLCLK 0x00A6
+#define WM_NCMBUTTONDOWN 0x00A7
+#define WM_NCMBUTTONUP 0x00A8
+#define WM_NCMBUTTONDBLCLK 0x00A9
+
+/* Mouse click activation support */
+#define WM_MOUSEACTIVATE 0x0021
+
+/* WM_MOUSEACTIVATE return codes */
+#define MA_ACTIVATE 1
+#define MA_ACTIVATEANDEAT 2
+#define MA_NOACTIVATE 3
+#if (WINVER >= 0x030a)
+#define MA_NOACTIVATEANDEAT 4
+#endif /* WINVER >= 0x030a */
+
+/* SetWindowsHook() mouse hook */
+#ifndef NOWH
+#define WH_MOUSE 7
+
+typedef struct tagMOUSEHOOKSTRUCT
+{
+ POINT pt;
+ HWND hwnd;
+ UINT wHitTestCode;
+ DWORD dwExtraInfo;
+} MOUSEHOOKSTRUCT;
+typedef MOUSEHOOKSTRUCT FAR* LPMOUSEHOOKSTRUCT;
+#endif /* NOWH */
+
+/****** Mode control ********************************************************/
+
+#define WM_CANCELMODE 0x001F
+
+/****** System modal window support *****************************************/
+
+HWND WINAPI GetSysModalWindow(void);
+HWND WINAPI SetSysModalWindow(HWND);
+
+/****** Timer support *******************************************************/
+
+#ifdef STRICT
+typedef void (CALLBACK* TIMERPROC)(HWND, UINT, UINT, DWORD);
+#else
+typedef FARPROC TIMERPROC;
+#endif
+
+UINT WINAPI SetTimer(HWND, UINT, UINT, TIMERPROC);
+
+BOOL WINAPI KillTimer(HWND, UINT);
+
+#define WM_TIMER 0x0113
+#define WM_SYSTIMER 0x0118 /* ;Internal */
+
+/****** Accelerator support *************************************************/
+
+DECLARE_HANDLE(HACCEL);
+
+HACCEL WINAPI LoadAccelerators(HINSTANCE, LPCSTR);
+
+#ifndef NOMSG
+int WINAPI TranslateAccelerator(HWND, HACCEL, MSG FAR*);
+#endif
+
+/****** Menu support ********************************************************/
+
+#ifndef NOMENUS
+
+/* Menu template header */
+typedef struct
+{
+ UINT versionNumber;
+ UINT offset;
+} MENUITEMTEMPLATEHEADER;
+
+/* Menu template item struct */
+typedef struct
+{
+ UINT mtOption;
+ UINT mtID;
+ char mtString[1];
+} MENUITEMTEMPLATE;
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI IsMenu(HMENU);
+#endif /* WINVER >= 0x030a */
+
+HMENU WINAPI CreateMenu(void);
+HMENU WINAPI CreatePopupMenu(void);
+HMENU WINAPI LoadMenu(HINSTANCE, LPCSTR);
+HMENU WINAPI LoadMenuIndirect(const void FAR*);
+
+BOOL WINAPI DestroyMenu(HMENU);
+
+HMENU WINAPI GetMenu(HWND);
+BOOL WINAPI SetMenu(HWND, HMENU);
+
+HMENU WINAPI GetSystemMenu(HWND, BOOL);
+BOOL WINAPI SetSystemMenu(HWND, HMENU); /* ;Internal */
+
+void WINAPI DrawMenuBar(HWND);
+
+BOOL WINAPI HiliteMenuItem(HWND, HMENU, UINT, UINT);
+
+BOOL WINAPI InsertMenu(HMENU, UINT, UINT, UINT, LPCSTR);
+BOOL WINAPI AppendMenu(HMENU, UINT, UINT, LPCSTR);
+BOOL WINAPI ModifyMenu(HMENU, UINT, UINT, UINT, LPCSTR);
+BOOL WINAPI RemoveMenu(HMENU, UINT, UINT);
+BOOL WINAPI DeleteMenu(HMENU, UINT, UINT);
+
+BOOL WINAPI ChangeMenu(HMENU, UINT, LPCSTR, UINT, UINT);
+
+#define MF_INSERT 0x0000
+#define MF_CHANGE 0x0080
+#define MF_APPEND 0x0100
+#define MF_DELETE 0x0200
+#define MF_REMOVE 0x1000
+
+/* Menu flags for Add/Check/EnableMenuItem() */
+#define MF_BYCOMMAND 0x0000
+#define MF_BYPOSITION 0x0400
+
+#define MF_SEPARATOR 0x0800
+
+#define MF_ENABLED 0x0000
+#define MF_GRAYED 0x0001
+#define MF_DISABLED 0x0002
+
+#define MF_UNCHECKED 0x0000
+#define MF_CHECKED 0x0008
+#define MF_USECHECKBITMAPS 0x0200
+
+#define MF_STRING 0x0000
+#define MF_BITMAP 0x0004
+#define MF_OWNERDRAW 0x0100
+
+#define MF_POPUP 0x0010
+#define MF_MENUBARBREAK 0x0020
+#define MF_MENUBREAK 0x0040
+
+#define MF_UNHILITE 0x0000
+#define MF_HILITE 0x0080
+
+#define MF_SYSMENU 0x2000
+#define MF_HELP 0x4000
+#define MF_MOUSESELECT 0x8000
+
+#define MF_VALID 0x4fff /* ;Internal */
+#define MF_CHANGE_VALID 0x5fff /* ;Internal */
+
+#define MF_END 0x0080 /* Only valid in menu resource templates */
+
+BOOL WINAPI EnableMenuItem(HMENU, UINT, UINT);
+BOOL WINAPI CheckMenuItem(HMENU, UINT, UINT);
+
+HMENU WINAPI GetSubMenu(HMENU, int);
+
+int WINAPI GetMenuItemCount(HMENU);
+UINT WINAPI GetMenuItemID(HMENU, int);
+
+int WINAPI GetMenuString(HMENU, UINT, LPSTR, int, UINT);
+UINT WINAPI GetMenuState(HMENU, UINT, UINT);
+
+BOOL WINAPI SetMenuItemBitmaps(HMENU, UINT, UINT, HBITMAP, HBITMAP);
+DWORD WINAPI GetMenuCheckMarkDimensions(void);
+
+BOOL WINAPI TrackPopupMenu(HMENU, UINT, int, int, int, HWND, const RECT FAR*);
+
+/* Flags for TrackPopupMenu */
+#define TPM_LEFTBUTTON 0x0000
+#if (WINVER >= 0x030a)
+#define TPM_RIGHTBUTTON 0x0002
+#define TPM_LEFTALIGN 0x0000
+#define TPM_CENTERALIGN 0x0004
+#define TPM_RIGHTALIGN 0x0008
+#define TPM_VALID 0x000f /* ;Internal */
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOMENUS */
+
+/* Menu messages */
+#define WM_INITMENU 0x0116
+#define WM_INITMENUPOPUP 0x0117
+
+#ifndef NOMENUS
+
+#define WM_MENUSELECT 0x011F
+#define WM_MENUCHAR 0x0120
+#define WM_ENTERMENULOOP 0x0211 /* ;Internal */
+#define WM_EXITMENULOOP 0x0212 /* ;Internal */
+#define WM_NEXTMENU 0x0213 /* ;Internal */
+
+#endif /* NOMENUS */
+
+/* Menu and control command messages */
+#define WM_COMMAND 0x0111
+
+/****** Scroll bar support **************************************************/
+
+#ifndef NOSCROLL
+
+#define WM_HSCROLL 0x0114
+#define WM_VSCROLL 0x0115
+
+/* WM_H/VSCROLL commands */
+#define SB_LINEUP 0
+#define SB_LINELEFT 0
+#define SB_LINEDOWN 1
+#define SB_LINERIGHT 1
+#define SB_PAGEUP 2
+#define SB_PAGELEFT 2
+#define SB_PAGEDOWN 3
+#define SB_PAGERIGHT 3
+#define SB_THUMBPOSITION 4
+#define SB_THUMBTRACK 5
+#define SB_TOP 6
+#define SB_LEFT 6
+#define SB_BOTTOM 7
+#define SB_RIGHT 7
+#define SB_ENDSCROLL 8
+#define SB_MSGCMD_MAX 8 /* ;Internal */
+
+/* Scroll bar selection constants */
+#define SB_HORZ 0
+#define SB_VERT 1
+#define SB_CTL 2
+#define SB_BOTH 3
+#define SB_MAX 3 /* ;Internal */
+
+int WINAPI SetScrollPos(HWND, int, int, BOOL);
+int WINAPI GetScrollPos(HWND, int);
+void WINAPI SetScrollRange(HWND, int, int, int, BOOL);
+void WINAPI GetScrollRange(HWND, int, int FAR*, int FAR*);
+void WINAPI ShowScrollBar(HWND, int, BOOL);
+BOOL WINAPI EnableScrollBar(HWND, int, UINT);
+
+/* EnableScrollBar() flags */
+#define ESB_ENABLE_BOTH 0x0000
+#define ESB_DISABLE_BOTH 0x0003
+
+#define ESB_DISABLE_LEFT 0x0001
+#define ESB_DISABLE_RIGHT 0x0002
+
+#define ESB_DISABLE_UP 0x0001
+#define ESB_DISABLE_DOWN 0x0002
+
+#define ESB_DISABLE_LTUP ESB_DISABLE_LEFT
+#define ESB_DISABLE_RTDN ESB_DISABLE_RIGHT
+
+#define ESB_MAX 0x0003 /* ;Internal */
+#define SB_DISABLE_MASK ESB_DISABLE_BOTH /* ;Internal */
+#endif /* NOSCROLL */
+
+/******* Clipboard manager **************************************************/
+
+#ifndef NOCLIPBOARD
+
+/* Predefined Clipboard Formats */
+#define CF_TEXT 1
+#define CF_BITMAP 2
+#define CF_METAFILEPICT 3
+#define CF_SYLK 4
+#define CF_DIF 5
+#define CF_TIFF 6
+#define CF_OEMTEXT 7
+#define CF_DIB 8
+#define CF_PALETTE 9
+#define CF_PENDATA 10
+#define CF_RIFF 11
+#define CF_WAVE 12
+
+#define CF_OWNERDISPLAY 0x0080
+#define CF_DSPTEXT 0x0081
+#define CF_DSPBITMAP 0x0082
+#define CF_DSPMETAFILEPICT 0x0083
+
+/* "Private" formats don't get GlobalFree()'d */
+#define CF_PRIVATEFIRST 0x0200
+#define CF_PRIVATELAST 0x02FF
+
+/* "GDIOBJ" formats do get DeleteObject()'d */
+#define CF_GDIOBJFIRST 0x0300
+#define CF_GDIOBJLAST 0x03FF
+
+/* Clipboard Manager Functions */
+BOOL WINAPI OpenClipboard(HWND);
+BOOL WINAPI CloseClipboard(void);
+BOOL WINAPI EmptyClipboard(void);
+
+#if (WINVER >= 0x030a)
+HWND WINAPI GetOpenClipboardWindow(void);
+#endif /* WINVER >= 0x030a */
+
+HWND WINAPI GetClipboardOwner(void);
+
+HWND WINAPI SetClipboardViewer(HWND);
+HWND WINAPI GetClipboardViewer(void);
+
+HANDLE WINAPI SetClipboardData(UINT, HANDLE);
+HANDLE WINAPI GetClipboardData(UINT);
+
+BOOL WINAPI IsClipboardFormatAvailable(UINT);
+int WINAPI GetPriorityClipboardFormat(UINT FAR*, int);
+
+UINT WINAPI RegisterClipboardFormat(LPCSTR);
+int WINAPI CountClipboardFormats(void);
+UINT WINAPI EnumClipboardFormats(UINT);
+int WINAPI GetClipboardFormatName(UINT, LPSTR, int);
+
+BOOL WINAPI ChangeClipboardChain(HWND, HWND);
+
+/* Clipboard command messages */
+#define WM_CUT 0x0300
+#define WM_COPY 0x0301
+#define WM_PASTE 0x0302
+#define WM_CLEAR 0x0303
+#define WM_UNDO 0x0304
+
+/* Clipboard owner messages */
+#define WM_RENDERFORMAT 0x0305
+#define WM_RENDERALLFORMATS 0x0306
+#define WM_DESTROYCLIPBOARD 0x0307
+
+/* Clipboard viewer messages */
+#define WM_DRAWCLIPBOARD 0x0308
+#define WM_PAINTCLIPBOARD 0x0309
+#define WM_SIZECLIPBOARD 0x030B
+#define WM_VSCROLLCLIPBOARD 0x030A
+#define WM_HSCROLLCLIPBOARD 0x030E
+#define WM_ASKCBFORMATNAME 0x030C
+#define WM_CHANGECBCHAIN 0x030D
+
+#endif /* NOCLIPBOARD */
+
+/****** Mouse cursor support *************************************************/
+
+HCURSOR WINAPI LoadCursor(HINSTANCE, LPCSTR);
+HCURSOR WINAPI CreateCursor(HINSTANCE, int, int, int, int, const void FAR*, const void FAR*);
+BOOL WINAPI DestroyCursor(HCURSOR);
+
+#if (WINVER >= 0x030a)
+HCURSOR WINAPI CopyCursor(HINSTANCE, HCURSOR);
+#endif /* WINVER >= 0x030a */
+
+int WINAPI ShowCursor(BOOL);
+
+void WINAPI SetCursorPos(int, int);
+void WINAPI GetCursorPos(POINT FAR*);
+
+HCURSOR WINAPI SetCursor(HCURSOR);
+
+#if (WINVER >= 0x030a)
+HCURSOR WINAPI GetCursor(void);
+#endif /* WINVER >= 0x030a */
+
+void WINAPI ClipCursor(const RECT FAR*);
+#if (WINVER >= 0x030a)
+void WINAPI GetClipCursor(RECT FAR*);
+#endif /* WINVER >= 0x030a */
+
+/* Standard cursor resource IDs */
+#define IDC_ARROW MAKEINTRESOURCE(32512)
+#define IDC_IBEAM MAKEINTRESOURCE(32513)
+#define IDC_WAIT MAKEINTRESOURCE(32514)
+#define IDC_CROSS MAKEINTRESOURCE(32515)
+#define IDC_UPARROW MAKEINTRESOURCE(32516)
+#define IDC_SIZE MAKEINTRESOURCE(32640)
+#define IDC_ICON MAKEINTRESOURCE(32641)
+#define IDC_SIZENWSE MAKEINTRESOURCE(32642)
+#define IDC_SIZENESW MAKEINTRESOURCE(32643)
+#define IDC_SIZEWE MAKEINTRESOURCE(32644)
+#define IDC_SIZENS MAKEINTRESOURCE(32645)
+
+#define WM_SETCURSOR 0x0020
+
+/****** Icon support *********************************************************/
+
+HICON WINAPI LoadIcon(HINSTANCE, LPCSTR);
+HICON WINAPI CreateIcon(HINSTANCE, int, int, BYTE, BYTE, const void FAR*, const void FAR*);
+BOOL WINAPI DestroyIcon(HICON);
+
+#if (WINVER >= 0x030a)
+HICON WINAPI CopyIcon(HINSTANCE, HICON);
+#endif /* WINVER >= 0x030a */
+
+BOOL WINAPI DrawIcon(HDC, int, int, HICON);
+
+#ifndef NOICONS
+
+/* Standard icon resource IDs */
+#define IDI_APPLICATION MAKEINTRESOURCE(32512)
+#define IDI_HAND MAKEINTRESOURCE(32513)
+#define IDI_QUESTION MAKEINTRESOURCE(32514)
+#define IDI_EXCLAMATION MAKEINTRESOURCE(32515)
+#define IDI_ASTERISK MAKEINTRESOURCE(32516)
+
+#endif /* NOICONS */
+
+/****** Message Box support *************************************************/
+
+#ifndef NOMB
+
+int WINAPI MessageBox(HWND, LPCSTR, LPCSTR, UINT);
+void WINAPI MessageBeep(UINT);
+
+#define MB_OK 0x0000
+#define MB_OKCANCEL 0x0001
+#define MB_ABORTRETRYIGNORE 0x0002
+#define MB_YESNOCANCEL 0x0003
+#define MB_YESNO 0x0004
+#define MB_RETRYCANCEL 0x0005
+#define MB_TYPEMASK 0x000F
+
+#define MB_ICONHAND 0x0010
+#define MB_ICONQUESTION 0x0020
+#define MB_ICONEXCLAMATION 0x0030
+#define MB_ICONASTERISK 0x0040
+#define MB_ICONMASK 0x00F0
+
+#define MB_ICONINFORMATION MB_ICONASTERISK
+#define MB_ICONSTOP MB_ICONHAND
+
+#define MB_DEFBUTTON1 0x0000
+#define MB_DEFBUTTON2 0x0100
+#define MB_DEFBUTTON3 0x0200
+#define MB_DEFMASK 0x0F00
+
+#define MB_APPLMODAL 0x0000
+#define MB_SYSTEMMODAL 0x1000
+#define MB_TASKMODAL 0x2000
+
+#define MB_NOFOCUS 0x8000
+
+#define MB_TYPEMASK 0x000F /* ;Internal */
+#define MB_ICONMASK 0x00F0 /* ;Internal */
+#define MB_DEFMASK 0x0F00 /* ;Internal */
+#define MB_MODEMASK 0x3000 /* ;Internal */
+#define MB_MISCMASK 0xC000 /* ;Internal */
+#define MB_VALID 0xb377 /* ;Internal */
+
+
+#endif /* NOMB */
+
+/****** Caret support ********************************************************/
+
+void WINAPI CreateCaret(HWND, HBITMAP, int, int);
+void WINAPI DestroyCaret(void);
+
+void WINAPI SetCaretPos(int, int);
+void WINAPI GetCaretPos(POINT FAR*);
+
+void WINAPI HideCaret(HWND);
+void WINAPI ShowCaret(HWND);
+
+UINT WINAPI GetCaretBlinkTime(void);
+void WINAPI SetCaretBlinkTime(UINT);
+
+/****** WM_SYSCOMMAND support ***********************************************/
+
+#define WM_SYSCOMMAND 0x0112
+
+#ifndef NOSYSCOMMANDS
+
+/* System Menu Command Values */
+#define SC_SIZE 0xF000
+#define SC_MOVE 0xF010
+#define SC_MINIMIZE 0xF020
+#define SC_MAXIMIZE 0xF030
+#define SC_NEXTWINDOW 0xF040
+#define SC_PREVWINDOW 0xF050
+#define SC_CLOSE 0xF060
+#define SC_VSCROLL 0xF070
+#define SC_HSCROLL 0xF080
+#define SC_MOUSEMENU 0xF090
+#define SC_KEYMENU 0xF100
+#define SC_ARRANGE 0xF110
+#define SC_RESTORE 0xF120
+#define SC_TASKLIST 0xF130
+#define SC_SCREENSAVE 0xF140
+#define SC_HOTKEY 0xF150
+
+/* Obsolete names */
+#define SC_ICON SC_MINIMIZE
+#define SC_ZOOM SC_MAXIMIZE
+
+/* SC_HOTKEY support messages */ /* ;Internal */
+#define WM_SETHOTKEY 0x0032 /* ;Internal */
+#define WM_GETHOTKEY 0x0033 /* ;Internal */
+
+#endif /* NOSYSCOMMANDS */
+
+/****** MDI Support *********************************************************/
+
+#ifndef NOMDI
+
+/* CreateWindow lpParams structure for creating MDI client */
+typedef struct tagCLIENTCREATESTRUCT
+{
+ HMENU hWindowMenu;
+ UINT idFirstChild;
+} CLIENTCREATESTRUCT;
+typedef CLIENTCREATESTRUCT FAR* LPCLIENTCREATESTRUCT;
+
+/* MDI client style bits */
+#if (WINVER >= 0x030a)
+#define MDIS_ALLCHILDSTYLES 0x0001
+#endif /* WINVER >= 0x030a */
+
+/* MDI messages */
+#define WM_MDICREATE 0x0220
+#define WM_MDIDESTROY 0x0221
+#define WM_MDIACTIVATE 0x0222
+#define WM_MDIRESTORE 0x0223
+#define WM_MDINEXT 0x0224
+#define WM_MDIMAXIMIZE 0x0225
+#define WM_MDITILE 0x0226
+#define WM_MDICASCADE 0x0227
+#define WM_MDIICONARRANGE 0x0228
+#define WM_MDIGETACTIVE 0x0229
+#define WM_MDISETMENU 0x0230
+
+/* WM_MDICREATE message structure */
+typedef struct tagMDICREATESTRUCT
+{
+ LPCSTR szClass;
+ LPCSTR szTitle;
+ HINSTANCE hOwner;
+ int x;
+ int y;
+ int cx;
+ int cy;
+ DWORD style;
+ LPARAM lParam;
+} MDICREATESTRUCT;
+typedef MDICREATESTRUCT FAR* LPMDICREATESTRUCT;
+
+#if (WINVER >= 0x030a)
+/* wParam values for WM_MDITILE and WM_MDICASCADE messages. */
+#define MDITILE_VERTICAL 0x0000
+#define MDITILE_HORIZONTAL 0x0001
+#define MDITILE_SKIPDISABLED 0x0002
+#endif /* WINVER >= 0x030a */
+
+#define WM_CHILDACTIVATE 0x0022
+
+LRESULT WINAPI DefFrameProc(HWND, HWND, UINT, WPARAM, LPARAM);
+LRESULT WINAPI DefMDIChildProc(HWND, UINT, WPARAM, LPARAM);
+
+#ifndef NOMSG
+BOOL WINAPI TranslateMDISysAccel(HWND, MSG FAR*);
+#endif
+
+UINT WINAPI ArrangeIconicWindows(HWND);
+
+#endif /* NOMDI */
+
+/****** Dialog and Control Management ***************************************/
+
+#ifndef NOCTLMGR
+
+/* Dialog window class */
+#define WC_DIALOG (MAKEINTATOM(0x8002))
+
+/* cbWndExtra bytes needed by dialog manager for dialog classes */
+#define DLGWINDOWEXTRA 30
+
+/* Dialog styles */
+#define DS_ABSALIGN 0x01L
+#define DS_SYSMODAL 0x02L
+#define DS_LOCALEDIT 0x20L
+#define DS_SETFONT 0x40L
+#define DS_MODALFRAME 0x80L
+#define DS_NOIDLEMSG 0x100L
+
+/* Dialog messages */
+#define DM_GETDEFID (WM_USER+0)
+#define DM_SETDEFID (WM_USER+1)
+
+/* Returned in HIWORD() of DM_GETDEFID result if msg is supported */
+#define DC_HASDEFID 0x534B
+
+#endif /* NOCTLMGR */
+
+/* Dialog notification messages */
+#define WM_INITDIALOG 0x0110
+#define WM_NEXTDLGCTL 0x0028
+#define WM_ALTTABACTIVE 0x0029 /* ;Internal */
+
+#define WM_PARENTNOTIFY 0x0210
+
+#define WM_ENTERIDLE 0x0121
+
+
+#ifndef NOCTLMGR
+
+#ifdef STRICT
+typedef BOOL (CALLBACK* DLGPROC)(HWND, UINT, WPARAM, LPARAM);
+#else
+typedef FARPROC DLGPROC;
+#endif
+
+/* Get/SetWindowWord/Long offsets for use with WC_DIALOG windows */
+#define DWL_MSGRESULT 0
+#define DWL_DLGPROC 4
+#define DWL_USER 8
+
+#ifndef NOMSG
+BOOL WINAPI IsDialogMessage(HWND, MSG FAR*);
+#endif
+
+LRESULT WINAPI DefDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+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);
+
+void WINAPI EndDialog(HWND, int);
+
+int WINAPI GetDlgCtrlID(HWND);
+HWND WINAPI GetDlgItem(HWND, int);
+LRESULT WINAPI SendDlgItemMessage(HWND, int, UINT, WPARAM, LPARAM);
+
+void WINAPI SetDlgItemInt(HWND, int, UINT, BOOL);
+UINT WINAPI GetDlgItemInt(HWND, int, BOOL FAR* , BOOL);
+
+void WINAPI SetDlgItemText(HWND, int, LPCSTR);
+int WINAPI GetDlgItemText(HWND, int, LPSTR, int);
+
+void WINAPI CheckDlgButton(HWND, int, UINT);
+void WINAPI CheckRadioButton(HWND, int, int, int);
+UINT WINAPI IsDlgButtonChecked(HWND, int);
+
+HWND WINAPI GetNextDlgGroupItem(HWND, HWND, BOOL);
+HWND WINAPI GetNextDlgTabItem(HWND, HWND, BOOL);
+
+void WINAPI MapDialogRect(HWND, RECT FAR*);
+DWORD WINAPI GetDialogBaseUnits(void);
+
+#define WM_GETDLGCODE 0x0087
+
+/* dialog codes */
+#define DLGC_WANTARROWS 0x0001
+#define DLGC_WANTTAB 0x0002
+#define DLGC_WANTALLKEYS 0x0004
+#define DLGC_WANTMESSAGE 0x0004
+#define DLGC_HASSETSEL 0x0008
+#define DLGC_DEFPUSHBUTTON 0x0010
+#define DLGC_UNDEFPUSHBUTTON 0x0020
+#define DLGC_RADIOBUTTON 0x0040
+#define DLGC_WANTCHARS 0x0080
+#define DLGC_STATIC 0x0100
+#define DLGC_BUTTON 0x2000
+
+#define WM_CTLCOLOR 0x0019
+
+/* WM_CTLCOLOR control IDs */
+#define CTLCOLOR_MSGBOX 0
+#define CTLCOLOR_EDIT 1
+#define CTLCOLOR_LISTBOX 2
+#define CTLCOLOR_BTN 3
+#define CTLCOLOR_DLG 4
+#define CTLCOLOR_SCROLLBAR 5
+#define CTLCOLOR_STATIC 6
+#define CTLCOLOR_MAX 8 /* ;Internal */
+
+#define WM_SETFONT 0x0030
+#define WM_GETFONT 0x0031
+
+#endif /* NOCTLMGR */
+
+/* Standard dialog button IDs */
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+
+/****** Owner draw control support ******************************************/
+
+/* Owner draw control types */
+#define ODT_MENU 1
+#define ODT_LISTBOX 2
+#define ODT_COMBOBOX 3
+#define ODT_BUTTON 4
+
+/* Owner draw actions */
+#define ODA_DRAWENTIRE 0x0001
+#define ODA_SELECT 0x0002
+#define ODA_FOCUS 0x0004
+
+/* Owner draw state */
+#define ODS_SELECTED 0x0001
+#define ODS_GRAYED 0x0002
+#define ODS_DISABLED 0x0004
+#define ODS_CHECKED 0x0008
+#define ODS_FOCUS 0x0010
+
+#define WM_DRAWITEM 0x002B
+
+typedef struct tagDRAWITEMSTRUCT
+{
+ UINT CtlType;
+ UINT CtlID;
+ UINT itemID;
+ UINT itemAction;
+ UINT itemState;
+ HWND hwndItem;
+ HDC hDC;
+ RECT rcItem;
+ DWORD itemData;
+} DRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT NEAR* PDRAWITEMSTRUCT;
+typedef DRAWITEMSTRUCT FAR* LPDRAWITEMSTRUCT;
+
+#define WM_MEASUREITEM 0x002C
+
+typedef struct tagMEASUREITEMSTRUCT
+{
+ UINT CtlType;
+ UINT CtlID;
+ UINT itemID;
+ UINT itemWidth;
+ UINT itemHeight;
+ DWORD itemData;
+} MEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT NEAR* PMEASUREITEMSTRUCT;
+typedef MEASUREITEMSTRUCT FAR* LPMEASUREITEMSTRUCT;
+
+#define WM_DELETEITEM 0x002D
+
+typedef struct tagDELETEITEMSTRUCT
+{
+ UINT CtlType;
+ UINT CtlID;
+ UINT itemID;
+ HWND hwndItem;
+ DWORD itemData;
+} DELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT NEAR* PDELETEITEMSTRUCT;
+typedef DELETEITEMSTRUCT FAR* LPDELETEITEMSTRUCT;
+
+#define WM_COMPAREITEM 0x0039
+
+typedef struct tagCOMPAREITEMSTRUCT
+{
+ UINT CtlType;
+ UINT CtlID;
+ HWND hwndItem;
+ UINT itemID1;
+ DWORD itemData1;
+ UINT itemID2;
+ DWORD itemData2;
+} COMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT NEAR* PCOMPAREITEMSTRUCT;
+typedef COMPAREITEMSTRUCT FAR* LPCOMPAREITEMSTRUCT;
+
+/****** Static control ******************************************************/
+
+#ifndef NOCTLMGR
+
+/* Static Control Styles */
+#define SS_LEFT 0x00000000L
+#define SS_CENTER 0x00000001L
+#define SS_RIGHT 0x00000002L
+#define SS_ICON 0x00000003L
+#define SS_BLACKRECT 0x00000004L
+#define SS_GRAYRECT 0x00000005L
+#define SS_WHITERECT 0x00000006L
+#define SS_BLACKFRAME 0x00000007L
+#define SS_GRAYFRAME 0x00000008L
+#define SS_WHITEFRAME 0x00000009L
+#define SS_USERITEM 0x0000000AL /* ;Internal */
+#define SS_SIMPLE 0x0000000BL
+#define SS_LEFTNOWORDWRAP 0x0000000CL
+#define SS_NOPREFIX 0x00000080L
+
+#if (WINVER >= 0x030a)
+#ifndef NOWINMESSAGES
+/* Static Control Mesages */
+#define STM_SETICON (WM_USER+0)
+#define STM_GETICON (WM_USER+1)
+#define STM_MSGMAX (WM_USER+2) /* ;Internal */
+#endif /* NOWINMESSAGES */
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOCTLMGR */
+
+/****** Button control *****************************************************/
+
+#ifndef NOCTLMGR
+
+/* Button Control Styles */
+#define BS_PUSHBUTTON 0x00000000L
+#define BS_DEFPUSHBUTTON 0x00000001L
+#define BS_CHECKBOX 0x00000002L
+#define BS_AUTOCHECKBOX 0x00000003L
+#define BS_RADIOBUTTON 0x00000004L
+#define BS_3STATE 0x00000005L
+#define BS_AUTO3STATE 0x00000006L
+#define BS_GROUPBOX 0x00000007L
+#define BS_USERBUTTON 0x00000008L
+#define BS_AUTORADIOBUTTON 0x00000009L
+#define BS_PUSHBOX 0x0000000AL /* ;Internal */
+#define BS_OWNERDRAW 0x0000000BL
+#define BS_LEFTTEXT 0x00000020L
+
+/* Button Control Messages */
+#define BM_GETCHECK (WM_USER+0)
+#define BM_SETCHECK (WM_USER+1)
+#define BM_GETSTATE (WM_USER+2)
+#define BM_SETSTATE (WM_USER+3)
+#define BM_SETSTYLE (WM_USER+4)
+
+/* User Button Notification Codes */
+#define BN_CLICKED 0
+#define BN_PAINT 1
+#define BN_HILITE 2
+#define BN_UNHILITE 3
+#define BN_DISABLE 4
+#define BN_DOUBLECLICKED 5
+
+#endif /* NOCTLMGR */
+
+/****** Edit control *******************************************************/
+
+#ifndef NOCTLMGR
+
+/* Edit control styles */
+#ifndef NOWINSTYLES
+#define ES_LEFT 0x00000000L
+#define ES_CENTER 0x00000001L
+#define ES_RIGHT 0x00000002L
+#define ES_MULTILINE 0x00000004L
+#define ES_UPPERCASE 0x00000008L
+#define ES_LOWERCASE 0x00000010L
+#define ES_PASSWORD 0x00000020L
+#define ES_AUTOVSCROLL 0x00000040L
+#define ES_AUTOHSCROLL 0x00000080L
+#define ES_NOHIDESEL 0x00000100L
+#define ES_OEMCONVERT 0x00000400L
+#if (WINVER >= 0x030a)
+#define ES_READONLY 0x00000800L
+#define ES_WANTRETURN 0x00001000L
+#endif /* WINVER >= 0x030a */
+#endif /* NOWINSTYLES */
+
+/* Edit control messages */
+#ifndef NOWINMESSAGES
+#define EM_GETSEL (WM_USER+0)
+#define EM_SETSEL (WM_USER+1)
+#define EM_GETRECT (WM_USER+2)
+#define EM_SETRECT (WM_USER+3)
+#define EM_SETRECTNP (WM_USER+4)
+#define EM_SCROLL (WM_USER+5) /* ;Internal */
+#define EM_LINESCROLL (WM_USER+6)
+#define EM_GETMODIFY (WM_USER+8)
+#define EM_SETMODIFY (WM_USER+9)
+#define EM_GETLINECOUNT (WM_USER+10)
+#define EM_LINEINDEX (WM_USER+11)
+#define EM_SETHANDLE (WM_USER+12)
+#define EM_GETHANDLE (WM_USER+13)
+#define EM_GETTHUMB (WM_USER+14) /* ;Internal */
+#define EM_LINELENGTH (WM_USER+17)
+#define EM_REPLACESEL (WM_USER+18)
+#define EM_SETFONT (WM_USER+19) /* NOT IMPLEMENTED: use WM_SETFONT */
+#define EM_GETLINE (WM_USER+20)
+#define EM_LIMITTEXT (WM_USER+21)
+#define EM_CANUNDO (WM_USER+22)
+#define EM_UNDO (WM_USER+23)
+#define EM_FMTLINES (WM_USER+24)
+#define EM_LINEFROMCHAR (WM_USER+25)
+#define EM_SETWORDBREAK (WM_USER+26) /* NOT IMPLEMENTED: use EM_SETWORDBREAK */
+#define EM_SETTABSTOPS (WM_USER+27)
+#define EM_SETPASSWORDCHAR (WM_USER+28)
+#define EM_EMPTYUNDOBUFFER (WM_USER+29)
+#if (WINVER >= 0x030a)
+#define EM_GETFIRSTVISIBLELINE (WM_USER+30)
+#define EM_SETREADONLY (WM_USER+31)
+#define EM_SETWORDBREAKPROC (WM_USER+32)
+#define EM_GETWORDBREAKPROC (WM_USER+33)
+#define EM_GETPASSWORDCHAR (WM_USER+34)
+#endif /* WINVER >= 0x030a */
+#define EM_MSGMAX (WM_USER+35) /* ;Internal */
+#endif /* NOWINMESSAGES */
+
+#if (WINVER >= 0x030a)
+typedef int (CALLBACK* EDITWORDBREAKPROC)(LPSTR lpch, int ichCurrent, int cch, int code);
+
+/* EDITWORDBREAKPROC code values */
+#define WB_LEFT 0
+#define WB_RIGHT 1
+#define WB_ISDELIMITER 2
+#endif /* WINVER >= 0x030a */
+
+/* Edit control notification codes */
+#define EN_SETFOCUS 0x0100
+#define EN_KILLFOCUS 0x0200
+#define EN_CHANGE 0x0300
+#define EN_UPDATE 0x0400
+#define EN_ERRSPACE 0x0500
+#define EN_MAXTEXT 0x0501
+#define EN_HSCROLL 0x0601
+#define EN_VSCROLL 0x0602
+
+#endif /* NOCTLMGR */
+
+/****** Scroll bar control *************************************************/
+/* Also see scrolling support */
+
+#ifndef NOCTLMGR
+
+#ifndef NOWINSTYLES
+
+/* Scroll bar styles */
+#define SBS_HORZ 0x0000L
+#define SBS_VERT 0x0001L
+#define SBS_TOPALIGN 0x0002L
+#define SBS_LEFTALIGN 0x0002L
+#define SBS_BOTTOMALIGN 0x0004L
+#define SBS_RIGHTALIGN 0x0004L
+#define SBS_SIZEBOXTOPLEFTALIGN 0x0002L
+#define SBS_SIZEBOXBOTTOMRIGHTALIGN 0x0004L
+#define SBS_SIZEBOX 0x0008L
+
+#endif /* NOWINSTYLES */
+
+#endif /* NOCTLMGR */
+
+/****** Listbox control ****************************************************/
+
+#ifndef NOCTLMGR
+
+/* Listbox styles */
+#ifndef NOWINSTYLES
+#define LBS_NOTIFY 0x0001L
+#define LBS_SORT 0x0002L
+#define LBS_NOREDRAW 0x0004L
+#define LBS_MULTIPLESEL 0x0008L
+#define LBS_OWNERDRAWFIXED 0x0010L
+#define LBS_OWNERDRAWVARIABLE 0x0020L
+#define LBS_HASSTRINGS 0x0040L
+#define LBS_USETABSTOPS 0x0080L
+#define LBS_NOINTEGRALHEIGHT 0x0100L
+#define LBS_MULTICOLUMN 0x0200L
+#define LBS_WANTKEYBOARDINPUT 0x0400L
+#define LBS_EXTENDEDSEL 0x0800L
+#if (WINVER >= 0x030a)
+#define LBS_DISABLENOSCROLL 0x1000L
+#endif /* WINVER >= 0x030a */
+#define LBS_STANDARD (LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER)
+#endif /* NOWINSTYLES */
+
+/* Listbox messages */
+#ifndef NOWINMESSAGES
+#define LB_ADDSTRING (WM_USER+1)
+#define LB_INSERTSTRING (WM_USER+2)
+#define LB_DELETESTRING (WM_USER+3)
+#define LB_RESETCONTENT (WM_USER+5)
+#define LB_SETSEL (WM_USER+6)
+#define LB_SETCURSEL (WM_USER+7)
+#define LB_GETSEL (WM_USER+8)
+#define LB_GETCURSEL (WM_USER+9)
+#define LB_GETTEXT (WM_USER+10)
+#define LB_GETTEXTLEN (WM_USER+11)
+#define LB_GETCOUNT (WM_USER+12)
+#define LB_SELECTSTRING (WM_USER+13)
+#define LB_DIR (WM_USER+14)
+#define LB_GETTOPINDEX (WM_USER+15)
+#define LB_FINDSTRING (WM_USER+16)
+#define LB_GETSELCOUNT (WM_USER+17)
+#define LB_GETSELITEMS (WM_USER+18)
+#define LB_SETTABSTOPS (WM_USER+19)
+#define LB_GETHORIZONTALEXTENT (WM_USER+20)
+#define LB_SETHORIZONTALEXTENT (WM_USER+21)
+#define LB_SETCOLUMNWIDTH (WM_USER+22)
+#define LB_ADDFILE (WM_USER+23) /* ;Internal */
+#define LB_SETTOPINDEX (WM_USER+24)
+#define LB_GETITEMRECT (WM_USER+25)
+#define LB_GETITEMDATA (WM_USER+26)
+#define LB_SETITEMDATA (WM_USER+27)
+#define LB_SELITEMRANGE (WM_USER+28)
+#define LB_SETANCHORINDEX (WM_USER+29) /* ;Internal */
+#define LB_GETANCHORINDEX (WM_USER+30) /* ;Internal */
+#define LB_SETCARETINDEX (WM_USER+31)
+#define LB_GETCARETINDEX (WM_USER+32)
+
+#if (WINVER >= 0x030a)
+#define LB_SETITEMHEIGHT (WM_USER+33)
+#define LB_GETITEMHEIGHT (WM_USER+34)
+#define LB_FINDSTRINGEXACT (WM_USER+35)
+#endif /* WINVER >= 0x030a */
+#define LBCB_CARETON (WM_USER+36) /* ;Internal */
+#define LBCB_CARETOFF (WM_USER+37) /* ;Internal */
+#define LB_MSGMAX (WM_USER+38) /* ;Internal */
+
+#endif /* NOWINMESSAGES */
+
+/* Listbox notification codes */
+#define LBN_ERRSPACE (-2)
+#define LBN_SELCHANGE 1
+#define LBN_DBLCLK 2
+#define LBN_SELCANCEL 3
+#define LBN_SETFOCUS 4
+#define LBN_KILLFOCUS 5
+
+/* Listbox notification messages */
+#define WM_VKEYTOITEM 0x002E
+#define WM_CHARTOITEM 0x002F
+#define WM_LBTRACKPOINT 0x0131 /* ;Internal */
+
+/* Listbox message return values */
+#define LB_OKAY 0
+#define LB_ERR (-1)
+#define LB_ERRSPACE (-2)
+
+#define LB_CTLCODE 0L
+
+/****** Dialog directory support ********************************************/
+
+int WINAPI DlgDirList(HWND, LPSTR, int, int, UINT);
+BOOL WINAPI DlgDirSelect(HWND, LPSTR, int);
+
+int WINAPI DlgDirListComboBox(HWND, LPSTR, int, int, UINT);
+BOOL WINAPI DlgDirSelectComboBox(HWND, LPSTR, int);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI DlgDirSelectEx(HWND, LPSTR, int, int);
+BOOL WINAPI DlgDirSelectComboBoxEx(HWND, LPSTR, int, int);
+#endif /* WINVER >= 0x030a */
+
+#define LBD_UPPERCASE 0x8001 /* ;Internal */
+#define LBD_SIZE 0x8002 /* ;Internal */
+#define LBD_DATE 0x8004 /* ;Internal */
+#define LBD_TIME 0x8008 /* ;Internal */
+#define LBD_ATTRIBUTE 0x8010 /* ;Internal */
+#define LBD_FULLDETAILS 0x801E /* ;Internal */
+#define LBD_SENDDETAILS 0x8020 /* ;Internal */
+
+/* DlgDirList, DlgDirListComboBox flags values */
+#define DDL_READWRITE 0x0000
+#define DDL_READONLY 0x0001
+#define DDL_HIDDEN 0x0002
+#define DDL_SYSTEM 0x0004
+#define DDL_DIRECTORY 0x0010
+#define DDL_ARCHIVE 0x0020
+
+#define DDL_POSTMSGS 0x2000
+#define DDL_DRIVES 0x4000
+#define DDL_EXCLUSIVE 0x8000
+#define DDL_VALID 0xe03f /* ;Internal */
+
+#endif /* NOCTLMGR */
+
+/****** Combo box control **************************************************/
+
+#ifndef NOCTLMGR
+
+/* Combo box styles */
+#ifndef NOWINSTYLES
+#define CBS_SIMPLE 0x0001L
+#define CBS_DROPDOWN 0x0002L
+#define CBS_DROPDOWNLIST 0x0003L
+#define CBS_OWNERDRAWFIXED 0x0010L
+#define CBS_OWNERDRAWVARIABLE 0x0020L
+#define CBS_AUTOHSCROLL 0x0040L
+#define CBS_OEMCONVERT 0x0080L
+#define CBS_SORT 0x0100L
+#define CBS_HASSTRINGS 0x0200L
+#define CBS_NOINTEGRALHEIGHT 0x0400L
+#if (WINVER >= 0x030a)
+#define CBS_DISABLENOSCROLL 0x0800L
+#endif /* WINVER >= 0x030a */
+#endif /* NOWINSTYLES */
+
+/* Combo box messages */
+#ifndef NOWINMESSAGES
+#define CB_GETEDITSEL (WM_USER+0)
+#define CB_LIMITTEXT (WM_USER+1)
+#define CB_SETEDITSEL (WM_USER+2)
+#define CB_ADDSTRING (WM_USER+3)
+#define CB_DELETESTRING (WM_USER+4)
+#define CB_DIR (WM_USER+5)
+#define CB_GETCOUNT (WM_USER+6)
+#define CB_GETCURSEL (WM_USER+7)
+#define CB_GETLBTEXT (WM_USER+8)
+#define CB_GETLBTEXTLEN (WM_USER+9)
+#define CB_INSERTSTRING (WM_USER+10)
+#define CB_RESETCONTENT (WM_USER+11)
+#define CB_FINDSTRING (WM_USER+12)
+#define CB_SELECTSTRING (WM_USER+13)
+#define CB_SETCURSEL (WM_USER+14)
+#define CB_SHOWDROPDOWN (WM_USER+15)
+#define CB_GETITEMDATA (WM_USER+16)
+#define CB_SETITEMDATA (WM_USER+17)
+#if (WINVER >= 0x030a)
+#define CB_GETDROPPEDCONTROLRECT (WM_USER+18)
+#define CB_SETITEMHEIGHT (WM_USER+19)
+#define CB_GETITEMHEIGHT (WM_USER+20)
+#define CB_SETEXTENDEDUI (WM_USER+21)
+#define CB_GETEXTENDEDUI (WM_USER+22)
+#define CB_GETDROPPEDSTATE (WM_USER+23)
+#define CB_FINDSTRINGEXACT (WM_USER+24)
+#endif /* WINVER >= 0x030a */
+#define CB_MSGMAX (WM_USER+25) /* ;Internal */
+
+#endif /* NOWINMESSAGES */
+
+/* Combo box notification codes */
+#define CBN_ERRSPACE (-1)
+#define CBN_SELCHANGE 1
+#define CBN_DBLCLK 2
+#define CBN_SETFOCUS 3
+#define CBN_KILLFOCUS 4
+#define CBN_EDITCHANGE 5
+#define CBN_EDITUPDATE 6
+#define CBN_DROPDOWN 7
+#if (WINVER >= 0x030a)
+#define CBN_CLOSEUP 8
+#define CBN_SELENDOK 9
+#define CBN_SELENDCANCEL 10
+#endif /* WINVER >= 0x030a */
+
+/* Combo box message return values */
+#define CB_OKAY 0
+#define CB_ERR (-1)
+#define CB_ERRSPACE (-2)
+
+#endif /* NOCTLMGR */
+
+/******* Windows hook support **********************************************/
+
+#ifndef NOWH
+
+DECLARE_HANDLE32(HHOOK);
+
+#ifdef STRICT
+typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
+#else
+typedef FARPROC HOOKPROC;
+#endif
+
+#ifdef STRICT
+HHOOK WINAPI SetWindowsHook(int, HOOKPROC);
+LRESULT WINAPI DefHookProc(int, WPARAM, LPARAM, HHOOK FAR*);
+#else
+HOOKPROC WINAPI SetWindowsHook(int, HOOKPROC);
+LRESULT WINAPI DefHookProc(int, WPARAM, LPARAM, HOOKPROC FAR*);
+#endif
+BOOL WINAPI UnhookWindowsHook(int, HOOKPROC);
+
+#if (WINVER >= 0x030a)
+
+HHOOK WINAPI SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hInstance, HTASK hTask);
+BOOL WINAPI UnhookWindowsHookEx(HHOOK hHook);
+LRESULT WINAPI CallNextHookEx(HHOOK hHook, int code, WPARAM wParam, LPARAM lParam);
+
+#endif /* WINVER >= 0x030a */
+
+#define WH_MIN (-1) /* ;Internal */
+#define WH_MAX 10 /* ;Internal */
+#define WH_MINHOOK WH_MIN /* ;Internal */
+#define WH_MAXHOOK WH_MAX /* ;Internal */
+#define WH_CHOOKS (WH_MAXHOOK - WH_MINHOOK + 1) /* ;Internal */
+
+/* Standard hook code */
+#define HC_ACTION 0
+
+/* Obsolete hook codes (NO LONGER SUPPORTED) */
+#define HC_GETLPLPFN (-3)
+#define HC_LPLPFNNEXT (-2)
+#define HC_LPFNNEXT (-1)
+
+#endif /* NOWH */
+
+/****** Computer-based-training (CBT) support *******************************/
+
+#define WM_QUEUESYNC 0x0023
+
+#ifndef NOWH
+
+/* SetWindowsHook() code */
+#define WH_CBT 5
+
+#define HCBT_MOVESIZE 0
+#define HCBT_MINMAX 1
+#define HCBT_QS 2
+#define HCBT_CREATEWND 3
+#define HCBT_DESTROYWND 4
+#define HCBT_ACTIVATE 5
+#define HCBT_CLICKSKIPPED 6
+#define HCBT_KEYSKIPPED 7
+#define HCBT_SYSCOMMAND 8
+#define HCBT_SETFOCUS 9
+
+#if (WINVER >= 0x030a)
+/* HCBT_CREATEWND parameters pointed to by lParam */
+typedef struct tagCBT_CREATEWND
+{
+ CREATESTRUCT FAR* lpcs;
+ HWND hwndInsertAfter;
+} CBT_CREATEWND;
+typedef CBT_CREATEWND FAR* LPCBT_CREATEWND;
+
+/* HCBT_ACTIVATE structure pointed to by lParam */
+typedef struct tagCBTACTIVATESTRUCT
+{
+ BOOL fMouse;
+ HWND hWndActive;
+} CBTACTIVATESTRUCT;
+
+#endif /* WINVER >= 0x030a */
+#endif /* NOWH */
+
+/****** Hardware hook support ***********************************************/
+
+#ifndef NOWH
+#if (WINVER >= 0x030a)
+#define WH_HARDWARE 8
+
+typedef struct tagHARDWAREHOOKSTRUCT
+{
+ HWND hWnd;
+ UINT wMessage;
+ WPARAM wParam;
+ LPARAM lParam;
+} HARDWAREHOOKSTRUCT;
+#endif /* WINVER >= 0x030a */
+#endif /* NOWH */
+
+/****** Shell support *******************************************************/
+
+#ifndef NOWH
+#if (WINVER >= 0x030a)
+/* SetWindowsHook() Shell hook code */
+#define WH_SHELL 10
+
+#define HSHELL_WINDOWCREATED 1
+#define HSHELL_WINDOWDESTROYED 2
+#define HSHELL_ACTIVATESHELLWINDOW 3
+
+#endif /* WINVER >= 0x030a */
+#endif /* NOWH */
+
+/****** Journalling support *************************************************/
+
+#ifndef NOWH
+#define WH_JOURNALRECORD 0
+#define WH_JOURNALPLAYBACK 1
+
+/* Journalling hook codes */
+#define HC_GETNEXT 1
+#define HC_SKIP 2
+#define HC_NOREMOVE 3
+#define HC_NOREM HC_NOREMOVE
+#define HC_SYSMODALON 4
+#define HC_SYSMODALOFF 5
+
+/* Journalling message structure */
+typedef struct tagEVENTMSG
+{
+ UINT message;
+ UINT paramL;
+ UINT paramH;
+ DWORD time;
+} EVENTMSG;
+typedef EVENTMSG *PEVENTMSG;
+typedef EVENTMSG *PEVENTMSGMSG; /* ;Internal */
+typedef EVENTMSG NEAR* NPEVENTMSG;
+typedef EVENTMSG FAR* LPEVENTMSG;
+typedef EVENTMSG FAR* LPEVENTMSGMSG; /* ;Internal */
+
+BOOL WINAPI EnableHardwareInput(BOOL);
+
+#endif /* NOWH */
+
+
+/****** Debugger support ****************************************************/
+
+#if (WINVER >= 0x030a)
+/* SetWindowsHook debug hook support */
+#define WH_DEBUG 9
+
+typedef struct tagDEBUGHOOKINFO
+{
+ HMODULE hModuleHook;
+ LPARAM reserved;
+ LPARAM lParam;
+ WPARAM wParam;
+ int code;
+} DEBUGHOOKINFO;
+typedef DEBUGHOOKINFO FAR* LPDEBUGHOOKINFO;
+
+#ifndef NOMSG
+BOOL WINAPI QuerySendMessage(HANDLE h1, HANDLE h2, HANDLE h3, LPMSG lpmsg);
+#endif /* NOMSG */
+
+BOOL WINAPI LockInput(HANDLE h1, HWND hwndInput, BOOL fLock);
+
+LONG WINAPI GetSystemDebugState(void);
+/* Flags returned by GetSystemDebugState.
+ */
+#define SDS_MENU 0x0001
+#define SDS_SYSMODAL 0x0002
+#define SDS_NOTASKQUEUE 0x0004
+#define SDS_DIALOG 0x0008
+#define SDS_TASKLOCKED 0x0010
+#endif /* WINVER >= 0x030a */
+
+/****** Help support ********************************************************/
+
+#ifndef NOHELP
+
+BOOL WINAPI WinHelp(HWND hwndMain, LPCSTR lpszHelp, UINT usCommand, DWORD ulData);
+
+/* WinHelp() commands */
+#define HELP_CONTEXT 0x0001
+#define HELP_QUIT 0x0002
+#define HELP_INDEX 0x0003
+#define HELP_CONTENTS 0x0003
+#define HELP_HELPONHELP 0x0004
+#define HELP_SETINDEX 0x0005
+#define HELP_SETCONTENTS 0x0005
+#define HELP_CONTEXTPOPUP 0x0008
+#define HELP_FORCEFILE 0x0009
+#define HELP_KEY 0x0101
+#define HELP_COMMAND 0x0102
+#define HELP_PARTIALKEY 0x0105
+#define HELP_MULTIKEY 0x0201
+#define HELP_SETWINPOS 0x0203
+
+typedef struct tagMULTIKEYHELP
+{
+ UINT mkSize;
+ BYTE mkKeylist;
+ BYTE szKeyphrase[1];
+} MULTIKEYHELP;
+
+
+typedef struct
+{
+ int wStructSize;
+ int x;
+ int y;
+ int dx;
+ int dy;
+ int wMax;
+ char rgchMember[2];
+} HELPWININFO;
+typedef HELPWININFO NEAR* PHELPWININFO;
+typedef HELPWININFO FAR* LPHELPWININFO;
+
+#endif /* NOHELP */
+
+/****** Sound support ******************************************************/
+
+#ifndef NOSOUND
+
+int WINAPI OpenSound(void);
+void WINAPI CloseSound(void);
+
+int WINAPI StartSound(void);
+int WINAPI StopSound(void);
+
+int WINAPI SetVoiceQueueSize(int, int);
+int WINAPI SetVoiceNote(int, int, int, int);
+int WINAPI SetVoiceAccent(int, int, int, int, int);
+int WINAPI SetVoiceEnvelope(int, int, int);
+int WINAPI SetVoiceSound(int, DWORD, int);
+
+int WINAPI SetVoiceThreshold(int, int);
+int FAR* WINAPI GetThresholdEvent(void);
+int WINAPI GetThresholdStatus(void);
+
+int WINAPI SetSoundNoise(int, int);
+
+/* SetSoundNoise() Sources */
+#define S_PERIOD512 0
+#define S_PERIOD1024 1
+#define S_PERIOD2048 2
+#define S_PERIODVOICE 3
+#define S_WHITE512 4
+#define S_WHITE1024 5
+#define S_WHITE2048 6
+#define S_WHITEVOICE 7
+
+int WINAPI WaitSoundState(int);
+
+/* WaitSoundState() constants */
+#define S_QUEUEEMPTY 0
+#define S_THRESHOLD 1
+#define S_ALLTHRESHOLD 2
+
+int WINAPI SyncAllVoices(void);
+int WINAPI CountVoiceNotes(int);
+
+/* Accent Modes */
+#define S_NORMAL 0
+#define S_LEGATO 1
+#define S_STACCATO 2
+
+/* Error return values */
+#define S_SERDVNA (-1)
+#define S_SEROFM (-2)
+#define S_SERMACT (-3)
+#define S_SERQFUL (-4)
+#define S_SERBDNT (-5)
+#define S_SERDLN (-6)
+#define S_SERDCC (-7)
+#define S_SERDTP (-8)
+#define S_SERDVL (-9)
+#define S_SERDMD (-10)
+#define S_SERDSH (-11)
+#define S_SERDPT (-12)
+#define S_SERDFQ (-13)
+#define S_SERDDR (-14)
+#define S_SERDSR (-15)
+#define S_SERDST (-16)
+
+#endif /* NOSOUND */
+
+/****** Comm support ******************************************************/
+
+#ifndef NOCOMM
+
+#define NOPARITY 0
+#define ODDPARITY 1
+#define EVENPARITY 2
+#define MARKPARITY 3
+#define SPACEPARITY 4
+
+#define ONESTOPBIT 0
+#define ONE5STOPBITS 1
+#define TWOSTOPBITS 2
+
+#define IGNORE 0
+#define INFINITE 0xFFFF
+
+/* Error Flags */
+#define CE_RXOVER 0x0001
+#define CE_OVERRUN 0x0002
+#define CE_RXPARITY 0x0004
+#define CE_FRAME 0x0008
+#define CE_BREAK 0x0010
+#define CE_CTSTO 0x0020
+#define CE_DSRTO 0x0040
+#define CE_RLSDTO 0x0080
+#define CE_TXFULL 0x0100
+#define CE_PTO 0x0200
+#define CE_IOE 0x0400
+#define CE_DNS 0x0800
+#define CE_OOP 0x1000
+#define CE_MODE 0x8000
+
+#define IE_BADID (-1)
+#define IE_OPEN (-2)
+#define IE_NOPEN (-3)
+#define IE_MEMORY (-4)
+#define IE_DEFAULT (-5)
+#define IE_HARDWARE (-10)
+#define IE_BYTESIZE (-11)
+#define IE_BAUDRATE (-12)
+
+/* Events */
+#define EV_RXCHAR 0x0001
+#define EV_RXFLAG 0x0002
+#define EV_TXEMPTY 0x0004
+#define EV_CTS 0x0008
+#define EV_DSR 0x0010
+#define EV_RLSD 0x0020
+#define EV_BREAK 0x0040
+#define EV_ERR 0x0080
+#define EV_RING 0x0100
+#define EV_PERR 0x0200
+#define EV_CTSS 0x0400
+#define EV_DSRS 0x0800
+#define EV_RLSDS 0x1000
+#define EV_RingTe 0x2000
+#define EV_RINGTE EV_RingTe
+#define EV_VALID 0x3fff /* ;Internal */
+
+/* Escape Functions */
+#define SETXOFF 1
+#define SETXON 2
+#define SETRTS 3
+#define CLRRTS 4
+#define SETDTR 5
+#define CLRDTR 6
+#define RESETDEV 7
+
+#define LPTx 0x80
+
+#if (WINVER >= 0x030a)
+
+/* new escape functions */
+#define GETMAXLPT 8
+#define GETMAXCOM 9
+#define GETBASEIRQ 10
+
+/* Comm Baud Rate indices */
+#define CBR_110 0xFF10
+#define CBR_300 0xFF11
+#define CBR_600 0xFF12
+#define CBR_1200 0xFF13
+#define CBR_2400 0xFF14
+#define CBR_4800 0xFF15
+#define CBR_9600 0xFF16
+#define CBR_14400 0xFF17
+#define CBR_19200 0xFF18
+#define CBR_38400 0xFF1B
+#define CBR_56000 0xFF1F
+#define CBR_128000 0xFF23
+#define CBR_256000 0xFF27
+
+/* notifications passed in low word of lParam on WM_COMMNOTIFY messages */
+#define CN_RECEIVE 0x0001
+#define CN_TRANSMIT 0x0002
+#define CN_EVENT 0x0004
+
+#endif /* WINVER >= 0x030a */
+
+typedef struct tagDCB
+{
+ BYTE Id;
+ UINT BaudRate;
+ BYTE ByteSize;
+ BYTE Parity;
+ BYTE StopBits;
+ UINT RlsTimeout;
+ UINT CtsTimeout;
+ UINT DsrTimeout;
+
+ UINT fBinary :1;
+ UINT fRtsDisable :1;
+ UINT fParity :1;
+ UINT fOutxCtsFlow :1;
+ UINT fOutxDsrFlow :1;
+ UINT fDummy :2;
+ UINT fDtrDisable :1;
+
+ UINT fOutX :1;
+ UINT fInX :1;
+ UINT fPeChar :1;
+ UINT fNull :1;
+ UINT fChEvt :1;
+ UINT fDtrflow :1;
+ UINT fRtsflow :1;
+ UINT fDummy2 :1;
+
+ char XonChar;
+ char XoffChar;
+ UINT XonLim;
+ UINT XoffLim;
+ char PeChar;
+ char EofChar;
+ char EvtChar;
+ UINT TxDelay;
+} DCB;
+typedef DCB FAR* LPDCB;
+
+#if (defined(STRICT) | (WINVER >= 0x030a))
+
+typedef struct tagCOMSTAT
+{
+ BYTE status;
+ UINT cbInQue;
+ UINT cbOutQue;
+} COMSTAT;
+
+#define CSTF_CTSHOLD 0x01
+#define CSTF_DSRHOLD 0x02
+#define CSTF_RLSDHOLD 0x04
+#define CSTF_XOFFHOLD 0x08
+#define CSTF_XOFFSENT 0x10
+#define CSTF_EOF 0x20
+#define CSTF_TXIM 0x40
+
+#else /* (STRICT | WINVER >= 0x030a) */
+
+/* NOTE: This structure declaration is not ANSI compatible! */
+typedef struct tagCOMSTAT
+{
+ BYTE fCtsHold :1;
+ BYTE fDsrHold :1;
+ BYTE fRlsdHold :1;
+ BYTE fXoffHold :1;
+ BYTE fXoffSent :1;
+ BYTE fEof :1;
+ BYTE fTxim :1;
+ UINT cbInQue;
+ UINT cbOutQue;
+} COMSTAT;
+
+#endif /* !(STRICT | WINVER >= 0x030a */
+
+int WINAPI BuildCommDCB(LPCSTR, DCB FAR*);
+
+int WINAPI OpenComm(LPCSTR, UINT, UINT);
+int WINAPI CloseComm(int);
+
+int WINAPI ReadComm(int, void FAR*, int);
+int WINAPI WriteComm(int, const void FAR*, int);
+int WINAPI UngetCommChar(int, char);
+int WINAPI FlushComm(int, int);
+int WINAPI TransmitCommChar(int, char);
+
+int WINAPI SetCommState(const DCB FAR*);
+int WINAPI GetCommState(int, DCB FAR*);
+int WINAPI GetCommError(int, COMSTAT FAR* );
+
+int WINAPI SetCommBreak(int);
+int WINAPI ClearCommBreak(int);
+
+UINT FAR* WINAPI SetCommEventMask(int, UINT);
+UINT WINAPI GetCommEventMask(int, int);
+
+LONG WINAPI EscapeCommFunction(int, int);
+
+#if (WINVER >= 0x030a)
+BOOL WINAPI EnableCommNotification(int, HWND, int, int);
+
+#define WM_COMMNOTIFY 0x0044
+#endif /* WINVER >= 0x030a */
+
+#endif /* NOCOMM */
+
+/****** String formatting support *******************************************/
+
+int WINAPI wvsprintf(LPSTR lpszOut, LPCSTR lpszFmt, const void FAR* lpParams);
+
+int FAR CDECL wsprintf(LPSTR lpszOut, LPCSTR lpszFmt, ...);
+
+
+/****** Driver support ******************************************************/
+
+#if (WINVER >= 0x030a)
+
+#ifndef NODRIVERS
+
+DECLARE_HANDLE(HDRVR);
+
+typedef LRESULT (CALLBACK* DRIVERPROC)(DWORD, HDRVR, UINT, LPARAM, LPARAM);
+
+/* Driver messages */
+#define DRV_LOAD 0x0001
+#define DRV_ENABLE 0x0002
+#define DRV_OPEN 0x0003
+#define DRV_CLOSE 0x0004
+#define DRV_DISABLE 0x0005
+#define DRV_FREE 0x0006
+#define DRV_CONFIGURE 0x0007
+#define DRV_QUERYCONFIGURE 0x0008
+#define DRV_INSTALL 0x0009
+#define DRV_REMOVE 0x000A
+#define DRV_EXITSESSION 0x000B
+#define DRV_EXITAPPLICATION 0x000C
+#define DRV_POWER 0x000F
+
+#define DRV_RESERVED 0x0800
+#define DRV_USER 0x4000
+
+/* LPARAM of DRV_CONFIGURE message */
+typedef struct tagDRVCONFIGINFO
+{
+ DWORD dwDCISize;
+ LPCSTR lpszDCISectionName;
+ LPCSTR lpszDCIAliasName;
+} DRVCONFIGINFO;
+typedef DRVCONFIGINFO NEAR* PDRVCONFIGINFO;
+typedef DRVCONFIGINFO FAR* LPDRVCONFIGINFO;
+
+/* Supported return values for DRV_CONFIGURE message */
+#define DRVCNF_CANCEL 0x0000
+#define DRVCNF_OK 0x0001
+#define DRVCNF_RESTART 0x0002
+
+/* Supported lParam1 of DRV_EXITAPPLICATION notification */
+#define DRVEA_NORMALEXIT 0x0001
+#define DRVEA_ABNORMALEXIT 0x0002
+
+LRESULT WINAPI DefDriverProc(DWORD dwDriverIdentifier, HDRVR driverID, UINT message, LPARAM lParam1, LPARAM lParam2);
+
+HDRVR WINAPI OpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam2);
+LRESULT WINAPI CloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2);
+
+LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT message, LPARAM lParam1, LPARAM lParam2);
+
+HINSTANCE WINAPI GetDriverModuleHandle(HDRVR hDriver);
+
+HDRVR WINAPI GetNextDriver(HDRVR, DWORD);
+
+/* GetNextDriver flags */
+#define GND_FIRSTINSTANCEONLY 0x00000001
+
+#define GND_FORWARD 0x00000000
+#define GND_REVERSE 0x00000002
+#define GND_VALID 0x00000003 /* ;Internal */
+
+typedef struct tagDRIVERINFOSTRUCT
+{
+ UINT length;
+ HDRVR hDriver;
+ HINSTANCE hModule;
+ char szAliasName[128];
+} DRIVERINFOSTRUCT;
+typedef DRIVERINFOSTRUCT FAR* LPDRIVERINFOSTRUCT;
+
+BOOL WINAPI GetDriverInfo(HDRVR, DRIVERINFOSTRUCT FAR*);
+
+#endif /* !NODRIVERS */
+#endif /* WINVER >= 0x030a */
+#endif /* NOUSER */
+
+#ifndef NOWINDOWSX /* ;Internal */
+#ifndef RC_INVOKED /* ;Internal */
+#include "windowsx.h" /* ;Internal */
+#ifndef STRICT /* ;Internal */
+#undef SelectFont /* ;Internal */
+#endif /* STRICT */ /* ;Internal */
+#endif /* RC_INVOKED */ /* ;Internal */
+#endif /* NOWINDOWSX */ /* ;Internal */
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#endif /* _INC_WINDOWS */
+
+// WOW Section //
+
+int FAR PASCAL WowGetNextVdmCommand(LPVOID);
+int FAR PASCAL WOWRegisterShellWindowHandle(HWND,LPVOID, HWND);
+int FAR PASCAL WowFailedExec(void);
+void FAR PASCAL ExitKernelThunk(WORD wExitCode);
+WORD FAR PASCAL WowSetExitOnLastApp(WORD fExitOnLastApp);
+
+// Pickup WOW Generic Thunk Interfaces from wownt16,h //
+
+#include "\nt\public\sdk\inc\wownt16.h"
+
+// this is a bogus prototype. CallProc32W is a screwed up vararg function
+// however rasapi16.c uses it.
+
+DWORD FAR PASCAL CallProc32W(LPVOID, DWORD, DWORD);
diff --git a/private/mvdm/wow16/inc/windows.inc b/private/mvdm/wow16/inc/windows.inc
new file mode 100644
index 000000000..44d9c0c99
--- /dev/null
+++ b/private/mvdm/wow16/inc/windows.inc
@@ -0,0 +1,2418 @@
+;*************************************************************************
+;
+; WINDOWS.INC - Windows assembly language structures & constants
+;
+;*************************************************************************
+;
+; Conditional Block includes: (True states)
+; NOTEXT - don't include TextMetric struc & text drawing modes & stock objs.
+; NORASTOPS - don't include binary and ternary raster ops.
+; NOVK - don't include virtual key definitions
+; NOMB - don't include message box definitions
+; NOWM - don't include window messages
+;
+;
+FALSE = 0
+TRUE = 1
+NULL = 0
+
+;*******************************************************************
+;
+; Rectangle
+;
+;*******************************************************************
+
+RECT struc
+ rcLeft dw ?
+ rcTop dw ?
+ rcRight dw ?
+ rcBottom dw ?
+RECT ends
+
+;*******************************************************************
+;
+; Window Class structure
+;
+;*******************************************************************
+
+WNDCLASS struc
+ clsStyle dw ? ; class style
+ clsLpfnWndProc dd ?
+ clsCbClsExtra dw ?
+ clsCbWndExtra dw ?
+ clsHInstance dw ? ; instance handle
+ clsHIcon dw ? ; class icon handle
+ clsHCursor dw ? ; class cursor handle
+ clsHbrBackground dw ? ; class background brush
+ clsLpszMenuName dd ? ; menu name
+ clsLpszClassName dd ? ; far ptr to class name
+WNDCLASS ends
+
+IFNDEF NOTEXT
+TEXTMETRIC struc
+ tmHeight dw ?
+ tmAscent dw ?
+ tmDescent dw ?
+ tmIntLeading dw ?
+ tmExtLeading dw ?
+ tmAveCharWidth dw ?
+ tmMaxCharWidth dw ?
+ tmWeight dw ?
+ tmItalic db ?
+ tmUnderlined db ?
+ tmStruckOut db ?
+ tmFirstChar db ?
+ tmLastChar db ?
+ tmDefaultChar db ?
+ tmBreakChar db ?
+ tmPitch db ?
+ tmCharSet db ?
+ tmOverhang dw ?
+ tmAspectX dw ?
+ tmAspectY dw ?
+TEXTMETRIC ends
+
+LF_FACESIZE EQU 32
+
+LOGFONT struc
+ lfHeight dw ?
+ lfWidth dw ?
+ lfEscapement dw ?
+ lfOrientation dw ?
+ lfWeight dw ?
+ lfItalic db ?
+ lfUnderline db ?
+ lfStrikeOut db ?
+ lfCharSet db ?
+ lfOutPrecision db ?
+ lfClipPrecision db ?
+ lfQuality db ?
+ lfPitchAndFamily db ?
+ lfFaceName db LF_FACESIZE dup(?)
+LOGFONT ends
+
+LOGBRUSH struc
+ lbStyle dw ?
+ lbColor dd ?
+ lbHatch dw ?
+LOGBRUSH ends
+
+;
+; Text Drawing modes
+;
+TRANSPARENT = 1
+OPAQUE = 2
+;
+; Mapping Modes
+;
+MM_TEXT = 1
+MM_LOMETRIC = 2
+MM_HIMETRIC = 3
+MM_LOENGLISH = 4
+MM_HIENGLISH = 5
+MM_TWIPS = 6
+MM_ISOTROPIC = 7
+MM_ANISOTROPIC = 8
+;
+; Coordinate Modes
+;
+ABSOLUTE = 1
+RELATIVE = 2
+;
+; Stock Logical Objects
+;
+WHITE_BRUSH = 0
+LTGRAY_BRUSH = 1
+GRAY_BRUSH = 2
+DKGRAY_BRUSH = 3
+BLACK_BRUSH = 4
+NULL_BRUSH = 5
+HOLLOW_BRUSH = 5
+WHITE_PEN = 6
+BLACK_PEN = 7
+NULL_PEN = 8
+DOT_MARKER = 9
+OEM_FIXED_FONT = 10
+ANSI_FIXED_FONT = 11
+ANSI_VAR_FONT = 12
+SYSTEM_FONT = 13
+DEVICE_DEFAULT_FONT = 14
+DEFAULT_PALETTE = 15
+SYSTEM_FIXED_FONT = 16
+ENDIF
+;
+; Brush Styles
+;
+BS_SOLID = 0
+BS_NULL = 1
+BS_HOLLOW = BS_NULL
+BS_HATCHED = 2
+BS_PATTERN = 3
+BS_INDEXED = 4
+BS_DIBPATTERN = 5
+;
+; Hatch Styles
+;
+HS_HORIZONTAL = 0 ; -----
+HS_VERTICAL = 1 ; |||||
+HS_FDIAGONAL = 2 ; \\\\\
+HS_BDIAGONAL = 3 ; /////
+HS_CROSS = 4 ; +++++
+HS_DIAGCROSS = 5 ; xxxxx
+;
+; Pen Styles
+;
+PS_SOLID = 0
+PS_DASH = 1 ; -------
+PS_DOT = 2 ; .......
+PS_DASHDOT = 3 ; _._._._
+PS_DASHDOTDOT = 4 ; _.._.._
+PS_NULL = 5
+PS_INSIDEFRAME = 6
+;
+; Device Parameters for GetDeviceCaps()
+;
+DRIVERVERSION =0 ; Device driver version
+TECHNOLOGY =2 ; Device classification
+HORZSIZE =4 ; Horizontal size in millimeters
+VERTSIZE =6 ; Vertical size in millimeters
+HORZRES =8 ; Horizontal width in pixels
+VERTRES =10 ; Vertical width in pixels
+BITSPIXEL =12 ; Number of bits per pixel
+PLANES =14 ; Number of planes
+NUMBRUSHES =16 ; Number of brushes the device has
+NUMPENS =18 ; Number of pens the device has
+NUMMARKERS =20 ; Number of markers the device has
+NUMFONTS =22 ; Number of fonts the device has
+NUMCOLORS =24 ; Number of colors the device supports
+PDEVICESIZE =26 ; Size required for device descriptor
+CURVECAPS =28 ; Curve capabilities
+LINECAPS =30 ; Line capabilities
+POLYGONALCAPS =32 ; Polygonal capabilities
+TEXTCAPS =34 ; Text capabilities
+CLIPCAPS =36 ; Clipping capabilities
+RASTERCAPS =38 ; Bitblt capabilities
+ASPECTX =40 ; Length of the X leg
+ASPECTY =42 ; Length of the Y leg
+ASPECTXY =44 ; Length of the hypotenuse
+
+LOGPIXELSX =88 ; Logical pixels/inch in X
+LOGPIXELSY =90 ; Logical pixels/inch in Y
+
+SIZEPALETTE =104 ; Number of entries in physical palette
+NUMRESERVED =106 ; Number of reserved entries in palette
+COLORRES =108 ; Actual color resolution
+;
+ifndef NOGDICAPMASKS
+;
+; Device Capability Masks:
+;
+; Device Technologies
+DT_PLOTTER = 0 ; /* Vector plotter */
+DT_RASDISPLAY = 1 ; /* Raster display */
+DT_RASPRINTER = 2 ; /* Raster printer */
+DT_RASCAMERA = 3 ; /* Raster camera */
+DT_CHARSTREAM = 4 ; /* Character-stream, PLP */
+DT_METAFILE = 5 ; /* Metafile, VDM */
+DT_DISPFILE = 6 ; /* Display-file */
+;
+; Curve Capabilities
+CC_NONE = 0 ; /* Curves not supported */
+CC_CIRCLES = 1 ; /* Can do circles */
+CC_PIE = 2 ; /* Can do pie wedges */
+CC_CHORD = 4 ; /* Can do chord arcs */
+CC_ELLIPSES = 8 ; /* Can do ellipese */
+CC_WIDE = 16 ; /* Can do wide lines */
+CC_STYLED = 32 ; /* Can do styled lines */
+CC_WIDESTYLED = 64 ; /* Can do wide styled lines */
+CC_INTERIORS = 128; /* Can do interiors */
+;
+; Line Capabilities
+LC_NONE = 0 ; /* Lines not supported */
+LC_POLYLINE = 2 ; /* Can do polylines */
+LC_MARKER = 4 ; /* Can do markers */
+LC_POLYMARKER = 8 ; /* Can do polymarkers */
+LC_WIDE = 16 ; /* Can do wide lines */
+LC_STYLED = 32 ; /* Can do styled lines */
+LC_WIDESTYLED = 64 ; /* Can do wide styled lines */
+LC_INTERIORS = 128; /* Can do interiors */
+;
+; Polygonal Capabilities
+PC_NONE = 0 ; /* Polygonals not supported */
+PC_POLYGON = 1 ; /* Can do polygons */
+PC_RECTANGLE = 2 ; /* Can do rectangles */
+PC_WINDPOLYGON = 4 ; /* Can do winding polygons */
+PC_TRAPEZOID = 4 ; /* Can do trapezoids */
+PC_SCANLINE = 8 ; /* Can do scanlines */
+PC_WIDE = 16 ; /* Can do wide borders */
+PC_STYLED = 32 ; /* Can do styled borders */
+PC_WIDESTYLED = 64 ; /* Can do wide styled borders */
+PC_INTERIORS = 128; /* Can do interiors */
+;
+; Polygonal Capabilities */
+CP_NONE = 0 ; /* No clipping of output */
+CP_RECTANGLE = 1 ; /* Output clipped to rects */
+;
+; Text Capabilities
+TC_OP_CHARACTER = 0001h ; /* Can do OutputPrecision CHARACTER */
+TC_OP_STROKE = 0002h ; /* Can do OutputPrecision STROKE */
+TC_CP_STROKE = 0004h ; /* Can do ClipPrecision STROKE */
+TC_CR_90 = 0008h ; /* Can do CharRotAbility 90 */
+TC_CR_ANY = 0010h ; /* Can do CharRotAbility ANY */
+TC_SF_X_YINDEP = 0020h ; /* Can do ScaleFreedom X_YINDEPENDENT */
+TC_SA_DOUBLE = 0040h ; /* Can do ScaleAbility DOUBLE */
+TC_SA_INTEGER = 0080h ; /* Can do ScaleAbility INTEGER */
+TC_SA_CONTIN = 0100h ; /* Can do ScaleAbility CONTINUOUS */
+TC_EA_DOUBLE = 0200h ; /* Can do EmboldenAbility DOUBLE */
+TC_IA_ABLE = 0400h ; /* Can do ItalisizeAbility ABLE */
+TC_UA_ABLE = 0800h ; /* Can do UnderlineAbility ABLE */
+TC_SO_ABLE = 1000h ; /* Can do StrikeOutAbility ABLE */
+TC_RA_ABLE = 2000h ; /* Can do RasterFontAble ABLE */
+TC_VA_ABLE = 4000h ; /* Can do VectorFontAble ABLE */
+TC_RESERVED = 8000h
+;
+; Raster Capabilities
+RC_BITBLT = 1 ; /* Can do standard BLT. */
+RC_BANDING = 2 ; /* Device requires banding support */
+RC_SCALING = 4 ; /* Device requires scaling support */
+RC_BITMAP64 = 8 ; /* Device can support >64K bitmap */
+RC_GDI20_OUTPUT = 0010h ; /* has 2.0 output calls */
+RC_DI_BITMAP = 0080h ; /* supports DIB to memory */
+RC_PALETTE = 0100h ; /* supports a palette */
+RC_DIBTODEV = 0200h ; /* supports DIBitsToDevice */
+RC_BIGFONT = 0400h ; /* supports >64K fonts */
+RC_STRETCHBLT = 0800h ; /* supports StretchBlt */
+RC_FLOODFILL = 1000h ; /* supports FloodFill */
+RC_STRETCHDIB = 2000h ; /* supports StretchDIBits */
+
+endif ;NOGDICAPMASKS
+
+; palette entry flags
+;
+PC_RESERVED = 1 ;/* palette index used for animation */
+PC_EXPLICIT = 2 ;/* palette index is explicit to device */
+PC_NOCOLLAPSE = 4 ;/* do not match color to system palette */
+
+; DIB color table identifiers
+;
+DIB_RGB_COLORS = 0 ;/* color table in RGBTriples */
+DIB_PAL_COLORS = 1 ;/* color table in palette indices */
+;
+
+;constants for Get/SetSystemPaletteUse()
+;
+SYSPAL_STATIC = 1
+SYSPAL_NOSTATIC = 2
+
+; constants for CreateDIBitmap
+CBM_INIT = 4 ;/* initialize bitmap */
+;
+; Bitmap format constants
+BI_RGB = 0
+BI_RLE8 = 1
+BI_RLE4 = 2
+;
+;
+ANSI_CHARSET = 0
+SYMBOL_CHARSET = 2
+OEM_CHARSET = 255
+;
+; styles for CombineRgn
+;
+RGN_AND = 1
+RGN_OR = 2
+RGN_XOR = 3
+RGN_DIFF = 4
+RGN_COPY = 5
+;
+; Predefined cursor & icon IDs
+;
+IDC_ARROW = 32512
+IDC_IBEAM = 32513
+IDC_WAIT = 32514
+IDC_CROSS = 32515
+IDC_UPARROW = 32516
+IDC_SIZE = 32640
+IDC_ICON = 32641
+IDC_SIZENWSE = 32642
+IDC_SIZENESW = 32643
+IDC_SIZEWE = 32644
+IDC_SIZENS = 32645
+
+IDI_APPLICATION = 32512
+IDI_HAND = 32513
+IDI_QUESTION = 32514
+IDI_EXCLAMATION = 32515
+IDI_ASTERISK = 32516
+
+;
+; OEM Resource Ordinal Numbers */
+;
+OBM_CLOSE = 32754
+OBM_UPARROW = 32753
+OBM_DNARROW = 32752
+OBM_RGARROW = 32751
+OBM_LFARROW = 32750
+OBM_REDUCE = 32749
+OBM_ZOOM = 32748
+OBM_RESTORE = 32747
+OBM_REDUCED = 32746
+OBM_ZOOMD = 32745
+OBM_RESTORED = 32744
+OBM_UPARROWD = 32743
+OBM_DNARROWD = 32742
+OBM_RGARROWD = 32741
+OBM_LFARROWD = 32740
+OBM_MNARROW = 32739
+OBM_COMBO = 32738
+OBM_UPARROWI = 32737
+OBM_DNARROWI = 32736
+OBM_RGARROWI = 32735
+OBM_LFARROWI = 32734
+
+OBM_OLD_CLOSE = 32767
+OBM_SIZE = 32766
+OBM_OLD_UPARROW = 32765
+OBM_OLD_DNARROW = 32764
+OBM_OLD_RGARROW = 32763
+OBM_OLD_LFARROW = 32762
+OBM_BTSIZE = 32761
+OBM_CHECK = 32760
+OBM_CHECKBOXES = 32759
+OBM_BTNCORNERS = 32758
+OBM_OLD_REDUCE = 32757
+OBM_OLD_ZOOM = 32756
+OBM_OLD_RESTORE = 32755
+
+OCR_NORMAL = 32512
+OCR_IBEAM = 32513
+OCR_WAIT = 32514
+OCR_CROSS = 32515
+OCR_UP = 32516
+OCR_SIZE = 32640
+OCR_ICON = 32641
+OCR_SIZENWSE = 32642
+OCR_SIZENESW = 32643
+OCR_SIZEWE = 32644
+OCR_SIZENS = 32645
+OCR_SIZEALL = 32646
+OCR_ICOCUR = 32647
+
+OIC_SAMPLE = 32512
+OIC_HAND = 32513
+OIC_QUES = 32514
+OIC_BANG = 32515
+OIC_NOTE = 32516
+
+;
+; Scroll bar constants
+;
+SB_HORZ = 0
+SB_VERT = 1
+SB_CTL = 2
+SB_BOTH = 3
+;
+; Scroll Commands
+;
+SB_LINEUP = 0
+SB_LINEDOWN = 1
+SB_PAGEUP = 2
+SB_PAGEDOWN = 3
+SB_THUMBPOSITION = 4
+SB_THUMBTRACK = 5
+SB_TOP = 6
+SB_BOTTOM = 7
+SB_ENDSCROLL = 8
+;
+; MessageBox type flags
+;
+IFNDEF NOMB
+MB_OK = 0000H
+MB_OKCANCEL = 0001H
+MB_ABORTRETRYIGNORE = 0002H
+MB_YESNOCANCEL = 0003H
+MB_YESNO = 0004H
+MB_RETRYCANCEL = 0005H
+
+MB_ICONHAND = 0010H
+MB_ICONQUESTION = 0020H
+MB_ICONEXCLAMATION = 0030H
+MB_ICONASTERISK = 0040H
+
+MB_DEFBUTTON1 = 0000H
+MB_DEFBUTTON2 = 0100H
+MB_DEFBUTTON3 = 0200H
+
+MB_APPLMODAL = 0000H
+MB_SYSTEMMODAL = 1000H
+MB_TASKMODAL = 2000H
+
+MB_NOFOCUS = 8000H
+
+;
+; Conventional dialog box and message box command IDs
+;
+IDOK = 1
+IDCANCEL = 2
+IDABORT = 3
+IDRETRY = 4
+IDIGNORE = 5
+IDYES = 6
+IDNO = 7
+;
+; Flags for OpenFile
+;
+OF_READ = 0000H
+OF_WRITE = 0001H
+OF_READWRITE = 0002H
+OF_SHARE_COMPAT = 0000H
+OF_SHARE_EXCLUSIVE = 0010H
+OF_SHARE_DENY_WRITE = 0020H
+OF_SHARE_DENY_READ = 0030H
+OF_SHARE_DENY_NONE = 0040H
+OF_PARSE = 0100H
+OF_DELETE = 0200H
+OF_VERIFY = 0400H ; Used with OF_REOPEN
+OF_SEARCH = 0400H ; Used without OF_REOPEN
+OF_CANCEL = 0800H
+OF_CREATE = 1000H
+OF_PROMPT = 2000H
+OF_EXIST = 4000H
+OF_REOPEN = 8000H
+
+TF_FORCEDRIVE = 80H
+
+OPENSTRUC STRUC
+opLen db ?
+opDisk db ?
+opXtra dw ?
+opDate dw ?
+opTime dw ?
+opFile db 120 dup (?)
+OPENSTRUC ENDS
+;
+; DrawText format flags
+;
+DT_LEFT = 00H
+DT_CENTER = 01H
+DT_RIGHT = 02H
+DT_TOP = 00H
+DT_VCENTER = 04H
+DT_BOTTOM = 08H
+DT_WORDBREAK = 10H
+DT_SINGLELINE = 20H
+DT_EXPANDTABS = 40H
+DT_TABSTOP = 80H
+DT_NOCLIP = 0100H
+DT_EXTERNALLEADING = 0200H
+DT_CALCRECT = 0400H
+DT_NOPREFIX = 0800H
+DT_INTERNAL = 1000H
+ENDIF
+
+;
+; ExtFloodFill style flags
+;
+FLOODFILLBORDER = 0
+FLOODFILLSURFACE = 1
+
+;
+; Memory manager flags
+;
+LMEM_FIXED = 0000h
+LMEM_MOVEABLE = 0002h
+LMEM_NOCOMPACT = 0010H
+LMEM_NODISCARD = 0020H
+LMEM_ZEROINIT = 0040h
+LMEM_MODIFY = 0080H
+LMEM_DISCARDABLE= 0F00h
+LHND = LMEM_MOVEABLE+LMEM_ZEROINIT
+LPTR = LMEM_FIXED+LMEM_ZEROINIT
+; Flags returned by LocalFlags (in addition to LMEM_DISCARDABLE)
+LMEM_DISCARDED = 4000H
+LMEM_LOCKCOUNT = 00FFH
+
+NONZEROLHND = LMEM_MOVEABLE
+NONZEROLPTR = LMEM_FIXED
+
+LNOTIFY_OUTOFMEM = 0 ;Internal
+LNOTIFY_MOVE = 1 ;Internal
+LNOTIFY_DISCARD = 2 ;Internal
+
+
+GMEM_FIXED = 0000h
+GMEM_MOVEABLE = 0002h
+GMEM_NOCOMPACT = 0010h
+GMEM_NODISCARD = 0020h
+GMEM_ZEROINIT = 0040h
+GMEM_MODIFY = 0080h
+GMEM_DISCARDABLE= 0100h
+GMEM_NOT_BANKED = 1000h
+GMEM_DDESHARE = 2000h
+GMEM_SHARE = 2000h
+GMEM_NOTIFY = 4000h
+GMEM_LOWER = GMEM_NOT_BANKED
+GHND = GMEM_MOVEABLE+GMEM_ZEROINIT
+GPTR = GMEM_FIXED+GMEM_ZEROINIT
+
+; Flags returned by GlobalFlags (in addition to GMEM_DISCARDABLE)
+GMEM_DISCARDED = 4000h
+GMEM_LOCKCOUNT = 00FFh
+
+; Flags returned by GetWinFlags
+
+WF_PMODE = 0001h
+WF_CPU286 = 0002h
+WF_CPU386 = 0004h
+WF_CPU486 = 0008h
+WF_STANDARD = 0010h
+WF_WIN286 = 0010h
+WF_ENHANCED = 0020h
+WF_WIN386 = 0020h
+WF_CPU086 = 0040h
+WF_CPU186 = 0080h
+WF_LARGEFRAME = 0100h
+WF_SMALLFRAME = 0200h
+WF_80x87 = 0400h
+WF_PAGING = 0800h
+WF_WLO = 8000h
+
+; WEP fSystemExit flag values
+WEP_SYSTEM_EXIT = 1
+WEP_FREE_DLL = 0
+
+; GetAppCompatFlags flag values ;Internal
+GACF_IGNORENODISCARD = 0001h ;Internal
+GACF_FORCETEXTBAND = 0002h ;Internal
+GACF_ONELANDGRXBAND = 0004h ;Internal
+GACF_IGNORETOPMOST = 0008h ;Internal
+GACF_CALLTTDEVICE = 0010h ;Internal
+GACF_MULTIPLEBANDS = 0020h ;Internal
+GACF_ALWAYSSENDNCPAINT = 0040h ;Internal
+GACF_EDITSETTEXTMUNGE = 0080h ;Internal
+GACF_MOREEXTRAWNDWORDS = 0100h ;Internal
+GACF_TTIGNORERASTERDUPE = 0200h ;Internal
+GACF_HACKWINFLAGS = 0400h ;Internal
+GACF_DELAYHWHNDSHAKECHK = 0800h ;Internal
+
+; Virtual Keys, Standard Set
+
+IFNDEF NOVK
+VK_LBUTTON = 01H
+VK_RBUTTON = 02H
+VK_CANCEL = 03H
+VK_BACK = 08H
+VK_TAB = 09H
+VK_CLEAR = 0cH
+VK_RETURN = 0dH
+VK_SHIFT = 10H
+VK_CONTROL = 11H
+VK_MENU = 12H
+VK_PAUSE = 13H
+VK_CAPITAL = 14H
+VK_ESCAPE = 1bH
+VK_SPACE = 20H
+
+VK_PRIOR = 21H
+VK_NEXT = 22H
+VK_END = 23H
+VK_HOME = 24H
+VK_LEFT = 25H
+VK_UP = 26H
+VK_RIGHT = 27H
+VK_DOWN = 28H
+
+; VK_A thru VK_Z are the same as their ASCII equivalents: 'A' thru 'Z'
+; VK_0 thru VK_9 are the same as their ASCII equivalents: '0' thru '0'
+
+VK_PRINT = 2aH
+VK_EXECUTE = 2bH
+VK_SNAPSHOT = 2ch ; Printscreen key..
+VK_INSERT = 2dH
+VK_DELETE = 2eH
+VK_HELP = 2fH
+
+VK_NUMPAD0 = 60H
+VK_NUMPAD1 = 61H
+VK_NUMPAD2 = 62H
+VK_NUMPAD3 = 63H
+VK_NUMPAD4 = 64H
+VK_NUMPAD5 = 65H
+VK_NUMPAD6 = 66H
+VK_NUMPAD7 = 67H
+VK_NUMPAD8 = 68H
+VK_NUMPAD9 = 69H
+VK_MULTIPLY = 6AH
+VK_ADD = 6BH
+VK_SEPARATER = 6CH
+VK_SUBTRACT = 6DH
+VK_DECIMAL = 6EH
+VK_DIVIDE = 6FH
+
+VK_F1 = 70H
+VK_F2 = 71H
+VK_F3 = 72H
+VK_F4 = 73H
+VK_F5 = 74H
+VK_F6 = 75H
+VK_F7 = 76H
+VK_F8 = 77H
+VK_F9 = 78H
+VK_F10 = 79H
+VK_F11 = 7aH
+VK_F12 = 7bH
+VK_F13 = 7cH
+VK_F14 = 7dH
+VK_F15 = 7eH
+VK_F16 = 7fH
+VK_F17 = 80H
+VK_F18 = 81H
+VK_F19 = 82H
+VK_F20 = 83H
+VK_F21 = 84H
+VK_F22 = 85H
+VK_F23 = 86H
+VK_F24 = 87H
+
+VK_NUMLOCK = 90H
+VK_SCROLL = 91H
+ENDIF
+
+IFNDEF NOWH
+
+; SetWindowsHook() codes
+WH_NULLNODE = (-100) ;Internal
+WH_MSGFILTER = (-1)
+WH_JOURNALRECORD = 0
+WH_JOURNALPLAYBACK = 1
+WH_KEYBOARD = 2
+WH_GETMESSAGE = 3
+WH_CALLWNDPROC = 4
+IFNDEF NOWIN31
+WH_CBT = 5
+WH_SYSMSGFILTER = 6
+WH_MOUSE = 7
+WH_HARDWARE = 8
+WH_DEBUG = 9
+ENDIF
+;
+; Hook Codes
+HC_GETLPLPFN = (-3)
+HC_LPLPFNNEXT = (-2)
+HC_LPFNNEXT = (-1)
+HC_ACTION = 0
+HC_GETNEXT = 1
+HC_SKIP = 2
+HC_NOREM = 3
+HC_NOREMOVE = 3
+HC_SYSMODALON = 4
+HC_SYSMODALOFF = 5
+;
+; CBT Hook Codes
+HCBT_MOVESIZE = 0
+HCBT_MINMAX = 1
+HCBT_QS = 2
+HCBT_CREATEWND = 3
+HCBT_DESTROYWND = 4
+HCBT_ACTIVATE = 5
+HCBT_CLICKSKIPPED = 6
+HCBT_KEYSKIPPED = 7
+HCBT_SYSCOMMAND = 8
+HCBT_SETFOCUS = 9
+
+;
+; WH_MSGFILTER Filter Proc Codes
+MSGF_DIALOGBOX = 0
+MSGF_MESSAGEBOX = 1 ;Internal
+MSGF_MENU = 2
+MSGF_MOVE = 3
+MSGF_SIZE = 4
+MSGF_SCROLLBAR = 5
+MSGF_NEXTWINDOW = 6
+;
+; Window Manager Hook Codes
+WC_INIT = 1
+WC_SWP = 2
+WC_DEFWINDOWPROC = 3
+WC_MINMAX = 4
+WC_MOVE = 5
+WC_SIZE = 6
+WC_DRAWCAPTION = 7
+;
+
+; Message Structure used in Journaling
+EVENTMSG struc
+ message dw ?
+ paramL dw ?
+ paramH dw ?
+ time dd ?
+EVENTMSG ends
+
+ENDIF ;NOWH
+
+; Window field offsets for GetWindowLong() and GetWindowWord()
+GWL_WNDPROC = (-4)
+GWW_HINSTANCE = (-6)
+GWW_HWNDPARENT = (-8)
+GWW_ID = (-12)
+GWL_STYLE = (-16)
+GWL_EXSTYLE = (-20)
+
+; GetWindow() Constants
+GW_HWNDFIRST = 0
+GW_HWNDLAST = 1
+GW_HWNDNEXT = 2
+GW_HWNDPREV = 3
+GW_OWNER = 4
+GW_CHILD = 5
+
+; Class field offsets for GetClassLong() and GetClassWord()
+GCL_MENUNAME = (-8)
+GCW_HBRBACKGROUND = (-10)
+GCW_HCURSOR = (-12)
+GCW_HICON = (-14)
+GCW_HMODULE = (-16)
+GCW_CBWNDEXTRA = (-18)
+GCW_CBCLSEXTRA = (-20)
+GCL_WNDPROC = (-24)
+GCW_STYLE = (-26)
+
+; WinWhere() Area Codes
+HTERROR = (-2)
+HTTRANSPARENT = (-1)
+HTNOWHERE = 0
+HTCLIENT = 1
+HTCAPTION = 2
+HTSYSMENU = 3
+HTGROWBOX = 4
+HTSIZE = HTGROWBOX
+HTMENU = 5
+HTHSCROLL = 6
+HTVSCROLL = 7
+HTREDUCE = 8
+HTZOOM = 9
+HTLEFT = 10
+HTRIGHT = 11
+HTTOP = 12
+HTTOPLEFT = 13
+HTTOPRIGHT = 14
+HTBOTTOM = 15
+HTBOTTOMLEFT = 16
+HTBOTTOMRIGHT = 17
+HTSIZEFIRST = HTLEFT
+HTSIZELAST = HTBOTTOMRIGHT
+
+
+
+;*************************************************************************
+;
+; Misc structures & constants
+;
+;*************************************************************************
+
+IFNDEF NOMST
+POINT struc
+ ptX dw ?
+ ptY dw ?
+POINT ends
+
+LOGPEN struc
+ lopnStyle dw ?
+ lopnWidth db (SIZE POINT) DUP(?)
+ lopnColor dd ?
+LOGPEN ends
+
+
+BITMAP STRUC
+ bmType DW ?
+ bmWidth DW ?
+ bmHeight DW ?
+ bmWidthBytes DW ?
+ bmPlanes DB ?
+ bmBitsPixel DB ?
+ bmBits DD ?
+BITMAP ENDS
+
+RGBTRIPLE struc
+ rgbBlue db ?
+ rgbGreen db ?
+ rgbRed db ?
+RGBTRIPLE ends
+
+RGBQUAD struc
+ rgbqBlue db ?
+ rgbqGreen db ?
+ rgbqRed db ?
+ rgbqReserved db ?
+RGBQUAD ends
+
+; structures for defining DIBs
+BITMAPCOREHEADER struc
+ bcSize dd ?
+ bcWidth dw ?
+ bcHeight dw ?
+ bcPlanes dw ?
+ bcBitCount dw ?
+BITMAPCOREHEADER ends
+
+BITMAPINFOHEADER struc
+ biSize dd ?
+ biWidth dd ?
+ biHeight dd ?
+ biPlanes dw ?
+ biBitCount dw ?
+
+ biCompression dd ?
+ biSizeImage dd ?
+ biXPelsPerMeter dd ?
+ biYPelsPerMeter dd ?
+ biClrUsed dd ?
+ biClrImportant dd ?
+BITMAPINFOHEADER ends
+
+BITMAPINFO struc
+ bmiHeader db (SIZE BITMAPINFOHEADER) DUP (?)
+ bmiColors db ? ; array of RGBQUADs
+BITMAPINFO ends
+
+BITMAPCOREINFO struc
+ bmciHeader db (SIZE BITMAPCOREHEADER) DUP (?)
+ bmciColors db ? ; array of RGBTRIPLEs
+BITMAPCOREINFO ends
+
+BITMAPFILEHEADER struc
+ bfType dw ?
+ bfSize dd ?
+ bfReserved1 dw ?
+ bfReserved2 dw ?
+ bfOffBits dd ?
+BITMAPFILEHEADER ends
+
+
+WNDSTRUC struc
+ WSwndStyle dd ?
+ WSwndID dw ?
+ WSwndText dw ?
+ WSwndParent dw ?
+ WSwndInstance dw ?
+ WSwndClassProc dd ?
+WNDSTRUC ends
+;
+; Message structure
+;
+MSGSTRUCT struc
+msHWND dw ?
+msMESSAGE dw ?
+msWPARAM dw ?
+msLPARAM dd ?
+msTIME dd ?
+msPT dd ?
+MSGSTRUCT ends
+
+NEWPARMS struc
+ nprmHwnd dw ?
+ nprmCmd db ?
+NEWPARMS ends
+ENDIF
+
+PAINTSTRUCT STRUC
+ PShdc DW ?
+ PSfErase DW ?
+ PSrcPaint DB size RECT dup(?)
+ PSfRestore DW ?
+ PSfIncUpdate DW ?
+ PSrgbReserved DB 16 dup(?)
+PAINTSTRUCT ENDS
+
+
+CREATESTRUCT struc
+ cs_lpCreateParams dd ?
+ cs_hInstance dw ?
+ cs_hMenu dw ?
+ cs_hwndParent dw ?
+ cs_cy dw ?
+ cs_cx dw ?
+ cs_y dw ?
+ cs_x dw ?
+ cs_style dd ?
+ cs_lpszName dd ?
+ cs_lpszClass dd ?
+ cs_dwExStyle dd ?
+CREATESTRUCT ends
+;
+; PostError constants
+;
+WARNING = 0 ; command codes
+MINOR_ERROR = 1
+FATAL_ERROR = 2
+
+IGNORE = 0 ; response codes
+RETRY = 1
+ABORT = 2
+;
+; GDI-related constants & commands
+;
+ERRORREGION = 0
+NULLREGION = 1
+SIMPLEREGION = 2
+COMPLEXREGION = 3
+
+IFNDEF NORASTOPS
+;
+; Binary raster ops
+;
+R2_BLACK = 1
+R2_NOTMERGEPEN = 2
+R2_MASKNOTPEN = 3
+R2_NOTCOPYPEN = 4
+R2_MASKPENNOT = 5
+R2_NOT = 6
+R2_XORPEN = 7
+R2_NOTMASKPEN = 8
+R2_MASKPEN = 9
+R2_NOTXORPEN = 10
+R2_NOP = 11
+R2_MERGENOTPEN = 12
+R2_COPYPEN = 13
+R2_MERGEPENNOT = 14
+R2_MERGEPEN = 15
+R2_WHITE = 16
+;
+; Ternary raster ops
+;
+SRCCOPY_L = 0020h ;dest=source
+SRCCOPY_H = 00CCh
+SRCPAINT_L = 0086h ;dest=source OR dest
+SRCPAINT_H = 00EEh
+SRCAND_L = 00C6h ;dest=source AND dest
+SRCAND_H = 0088h
+SRCINVERT_L = 0046h ;dest= source XOR dest
+SRCINVERT_H = 0066h
+SRCERASE_L = 0328h ;dest= source AND (not dest )
+SRCERASE_H = 0044h
+NOTSRCCOPY_L = 0008h ;dest= (not source)
+NOTSRCCOPY_H = 0033h
+NOTSRCERASE_L = 00A6h ;dest= (not source) AND (not dest)
+NOTSRCERASE_H = 0011h
+MERGECOPY_L = 00CAh ;dest= (source AND pattern)
+MERGECOPY_H = 00C0h
+MERGEPAINT_L = 0226h ;dest= (source AND pattern) OR dest
+MERGEPAINT_H = 00BBh
+PATCOPY_L = 0021h ;dest= pattern
+PATCOPY_H = 00F0h
+PATPAINT_L = 0A09h ;DPSnoo
+PATPAINT_H = 00FBh
+PATINVERT_L = 0049h ;dest= pattern XOR dest
+PATINVERT_H = 005Ah
+DSTINVERT_L = 0009h ;dest= (not dest)
+DSTINVERT_H = 0055h
+BLACKNESS_L = 0042h ;dest= BLACK
+BLACKNESS_H = 0000h
+WHITENESS_L = 0062h ;dest= WHITE
+WHITENESS_H = 00FFh
+;
+; StretchBlt modes
+;
+BLACKONWHITE = 1
+WHITEONBLACK = 2
+COLORONCOLOR = 3
+;
+; New StretchBlt modes
+;
+STRETCH_ANDSCANS = 1
+STRETCH_ORSCANS = 2
+STRETCH_DELETESCANS = 3
+;
+; PolyFill modes
+;
+ALTERNATE = 1
+WINDING = 2
+ENDIF
+;
+; Text Alignment Options
+;
+TA_NOUPDATECP = 0
+TA_UPDATECP = 1
+
+TA_LEFT = 0
+TA_RIGHT = 2
+TA_CENTER = 6
+
+TA_TOP = 0
+TA_BOTTOM = 8
+TA_BASELINE = 24
+
+ETO_GRAYED = 1
+ETO_OPAQUE = 2
+ETO_CLIPPED = 4
+
+ASPECT_FILTERING = 1
+
+ifndef NOMETAFILE
+
+; Metafile Functions */
+META_SETBKCOLOR = 0201h
+META_SETBKMODE = 0102h
+META_SETMAPMODE = 0103h
+META_SETROP2 = 0104h
+META_SETRELABS = 0105h
+META_SETPOLYFILLMODE = 0106h
+META_SETSTRETCHBLTMODE = 0107h
+META_SETTEXTCHAREXTRA = 0108h
+META_SETTEXTCOLOR = 0209h
+META_SETTEXTJUSTIFICATION = 020Ah
+META_SETWINDOWORG = 020Bh
+META_SETWINDOWEXT = 020Ch
+META_SETVIEWPORTORG = 020Dh
+META_SETVIEWPORTEXT = 020Eh
+META_OFFSETWINDOWORG = 020Fh
+META_SCALEWINDOWEXT = 0400h
+META_OFFSETVIEWPORTORG = 0211h
+META_SCALEVIEWPORTEXT = 0412h
+META_LINETO = 0213h
+META_MOVETO = 0214h
+META_EXCLUDECLIPRECT = 0415h
+META_INTERSECTCLIPRECT = 0416h
+META_ARC = 0817h
+META_ELLIPSE = 0418h
+META_FLOODFILL = 0419h
+META_PIE = 081Ah
+META_RECTANGLE = 041Bh
+META_ROUNDRECT = 061Ch
+META_PATBLT = 061Dh
+META_SAVEDC = 001Eh
+META_SETPIXEL = 041Fh
+META_OFFSETCLIPRGN = 0220h
+META_TEXTOUT = 0521h
+META_BITBLT = 0922h
+META_STRETCHBLT = 0B23h
+META_POLYGON = 0324h
+META_POLYLINE = 0325h
+META_ESCAPE = 0626h
+META_RESTOREDC = 0127h
+META_FILLREGION = 0228h
+META_FRAMEREGION = 0429h
+META_INVERTREGION = 012Ah
+META_PAINTREGION = 012Bh
+META_SELECTCLIPREGION = 012Ch
+META_SELECTOBJECT = 012Dh
+META_SETTEXTALIGN = 012Eh
+META_DRAWTEXT = 062Fh
+
+META_CHORD = 0830h
+META_SETMAPPERFLAGS = 0231h
+META_EXTTEXTOUT = 0a32h
+META_SETDIBTODEV = 0d33h
+META_SELECTPALETTE = 0234h
+META_REALIZEPALETTE = 0035h
+META_ANIMATEPALETTE = 0436h
+META_SETPALENTRIES = 0037h
+META_POLYPOLYGON = 0538h
+META_RESIZEPALETTE = 0139h
+
+META_DIBBITBLT = 0940h
+META_DIBSTRETCHBLT = 0b41h
+META_DIBCREATEPATTERNBRUSH = 0142h
+META_STRETCHDIB = 0f43h
+
+META_DELETEOBJECT = 01f0h
+
+META_CREATEPALETTE = 00f7h
+META_CREATEBRUSH = 00F8h
+META_CREATEPATTERNBRUSH = 01F9h
+META_CREATEPENINDIRECT = 02FAh
+META_CREATEFONTINDIRECT = 02FBh
+META_CREATEBRUSHINDIRECT = 02FCh
+META_CREATEBITMAPINDIRECT = 02FDh
+META_CREATEBITMAP = 06FEh
+META_CREATEREGION = 06FFh
+
+; /* Clipboard Metafile Picture Structure */
+HANDLETABLE struc
+ ht_objectHandle dw ?
+HANDLETABLE ends
+
+METARECORD struc
+ mr_rdSize dd ?
+ mr_rdFunction dw ?
+ mr_rdParm dw ?
+METARECORD ends
+
+METAFILEPICT struc
+ mfp_mm dw ?
+ mfp_xExt dw ?
+ mfp_yExt dw ?
+ mfp_hMF dw ?
+METAFILEPICT ends
+
+METAHEADER struc
+ mtType dw ?
+ mtHeaderSize dw ?
+ mtVersion dw ?
+ mtSize dd ?
+ mtNoObjects dw ?
+ mtMaxRecord dd ?
+ mtNoParameters dw ?
+METAHEADER ends
+
+endif ; NOMETAFILE
+
+; GDI Escapes
+NEWFRAME = 1
+ABORTDOC = 2
+NEXTBAND = 3
+SETCOLORTABLE = 4
+GETCOLORTABLE = 5
+FLUSHOUTPUT = 6
+DRAFTMODE = 7
+QUERYESCSUPPORT = 8
+SETABORTPROC = 9
+STARTDOC = 10
+;; This value conflicts with a std WIN386 MACRO definition
+;;ENDDOC = 11
+GETPHYSPAGESIZE = 12
+GETPRINTINGOFFSET = 13
+GETSCALINGFACTOR = 14
+MFCOMMENT = 15
+GETPENWIDTH = 16
+SETCOPYCOUNT = 17
+SELECTPAPERSOURCE = 18
+DEVICEDATA = 19
+PASSTHROUGH = 19
+GETTECHNOLGY = 20
+GETTECHNOLOGY = 20
+SETENDCAP = 21
+SETLINEJOIN = 22
+SETMITERLIMIT = 23
+BANDINFO = 24
+DRAWPATTERNRECT = 25
+GETVECTORPENSIZE = 26
+GETVECTORBRUSHSIZE = 27
+ENABLEDUPLEX = 28
+ENABLEMANUALFEED = 29
+GETSETPAPERBINS = 29
+GETSETPRINTORIENT = 30
+ENUMPAPERBINS = 31
+
+GETEXTENDEDTEXTMETRICS = 256
+GETEXTENTTABLE = 257
+GETPAIRKERNTABLE = 258
+GETTRACKKERNTABLE = 259
+
+EXTTEXTOUT = 512
+
+ENABLERELATIVEWIDTHS = 768
+ENABLEPAIRKERNING = 769
+SETKERNTRACK = 770
+SETALLJUSTVALUES = 771
+SETCHARSET = 772
+
+GETSETSCREENPARAMS = 3072
+
+STRETCHBLT = 2048
+
+
+; Spooler Error Codes
+SP_NOTREPORTED = 4000h
+SP_ERROR = (-1)
+SP_APPABORT = (-2)
+SP_USERABORT = (-3)
+SP_OUTOFDISK = (-4)
+SP_OUTOFMEMORY = (-5)
+
+PR_JOBSTATUS = 0000
+
+; Object Definitions for EnumObjects()
+OBJ_PEN = 1
+OBJ_BRUSH = 2
+
+;
+; Menu flags for Change/Check/Enable MenuItem
+;
+MF_INSERT = 0000h
+MF_CHANGE = 0080h
+MF_APPEND = 0100h
+MF_DELETE = 0200h
+MF_REMOVE = 1000h
+
+MF_BYCOMMAND = 0000h
+MF_BYPOSITION = 0400h
+
+MF_SEPARATOR = 0800h
+
+MF_ENABLED = 0000h
+MF_GRAYED = 0001h
+MF_DISABLED = 0002h
+
+MF_UNCHECKED = 0000h
+MF_CHECKED = 0008h
+MF_USECHECKBITMAPS= 0200h
+
+MF_STRING = 0000h
+MF_BITMAP = 0004h
+MF_OWNERDRAW = 0100h
+
+MF_POPUP = 0010h
+MF_MENUBARBREAK = 0020h
+MF_MENUBREAK = 0040h
+
+MF_UNHILITE = 0000h
+MF_HILITE = 0080h
+
+MF_SYSMENU = 2000h
+MF_HELP = 4000h
+MF_MOUSESELECT = 8000h
+
+
+;
+; System Menu Command Values
+;
+SC_SIZE = 0F000h
+SC_MOVE = 0F010h
+SC_MINIMIZE = 0F020h
+SC_MAXIMIZE = 0F030h
+SC_NEXTWINDOW = 0F040h
+SC_PREVWINDOW = 0F050h
+SC_CLOSE = 0F060h
+SC_VSCROLL = 0F070h
+SC_HSCROLL = 0F080h
+SC_MOUSEMENU = 0F090h
+SC_KEYMENU = 0F100h
+SC_ARRANGE = 0F110h
+SC_RESTORE = 0F120h
+SC_TASKLIST = 0F130h
+SC_SCREENSAVE = 0F140h
+SC_HOTKEY = 0F150h
+
+SC_ICON = SC_MINIMIZE
+SC_ZOOM = SC_MAXIMIZE
+
+;
+; Window State Messages
+;
+IFNDEF NOWM
+WM_STATE = 0000H
+
+WM_NULL = 0000h
+WM_CREATE = 0001h
+WM_DESTROY = 0002h
+WM_MOVE = 0003h
+WM_SIZEWAIT = 0004h ;Internal
+WM_SIZE = 0005h
+WM_ACTIVATE = 0006h
+WM_SETFOCUS = 0007h
+WM_KILLFOCUS = 0008h
+WM_SETVISIBLE = 0009h ;Internal
+WM_ENABLE = 000Ah
+WM_SETREDRAW = 000Bh
+WM_SETTEXT = 000Ch
+WM_GETTEXT = 000Dh
+WM_GETTEXTLENGTH = 000Eh
+WM_PAINT = 000Fh
+WM_CLOSE = 0010h
+WM_QUERYENDSESSION = 0011h
+WM_QUIT = 0012h
+WM_QUERYOPEN = 0013h
+WM_ERASEBKGND = 0014h
+WM_SYSCOLORCHANGE = 0015h
+WM_ENDSESSION = 0016h
+WM_SYSTEMERROR = 0017h
+WM_SHOWWINDOW = 0018h
+WM_CTLCOLOR = 0019h
+WM_WININICHANGE = 001Ah
+WM_DEVMODECHANGE = 001Bh
+WM_ACTIVATEAPP = 001Ch
+WM_FONTCHANGE = 001Dh
+WM_TIMECHANGE = 001Eh
+WM_CANCELMODE = 001Fh
+WM_SETCURSOR = 0020h
+WM_MOUSEACTIVATE = 0021h
+WM_CHILDACTIVATE = 0022h
+WM_QUEUESYNC = 0023h
+WM_GETMINMAXINFO = 0024h
+WM_PAINTICON = 0026h
+WM_ICONERASEBKGND = 0027h
+WM_NEXTDLGCTL = 0028h
+WM_ALTTABACTIVE = 0029h ;Internal
+WM_SPOOLERSTATUS = 002Ah
+WM_DRAWITEM = 002Bh
+WM_MEASUREITEM = 002Ch
+WM_DELETEITEM = 002Dh
+WM_VKEYTOITEM = 002Eh
+WM_CHARTOITEM = 002Fh
+WM_SETFONT = 0030h
+WM_GETFONT = 0031h
+WM_SETHOTKEY = 0032h ;Internal
+WM_GETHOTKEY = 0033h ;Internal
+WM_FILESYSCHANGE = 0034h ;Internal
+WM_ISACTIVEICON = 0035h ;Internal
+WM_UNUSED0036 = 0036h ;Internal
+WM_QUERYDRAGICON = 0037h
+WM_COMPAREITEM = 0039h
+WM_TESTING = 0040h ;Internal
+WM_COMPACTING = 0041h
+; 0042h ;Internal
+; 0043h ;Internal
+IFNDEF NOWIN31
+WM_COMMNOTIFY = 0044h
+; = 0045h ;Internal
+WM_WINDOWPOSCHANGING= 0046h
+WM_WINDOWPOSCHANGED = 0047h
+WM_POWER = 0048h
+ENDIF
+
+
+WM_NCCREATE = 0081h
+WM_NCDESTROY = 0082h
+WM_NCCALCSIZE = 0083h
+WM_NCHITTEST = 0084h
+WM_NCPAINT = 0085h
+WM_NCACTIVATE = 0086h
+WM_GETDLGCODE = 0087h
+WM_SYNCPAINT = 0088h ;Internal
+WM_SYNCTASK = 0089h ;Internal
+WM_NCMOUSEMOVE = 00A0h
+WM_NCLBUTTONDOWN = 00A1h
+WM_NCLBUTTONUP = 00A2h
+WM_NCLBUTTONDBLCLK = 00A3h
+WM_NCRBUTTONDOWN = 00A4h
+WM_NCRBUTTONUP = 00A5h
+WM_NCRBUTTONDBLCLK = 00A6h
+WM_NCMBUTTONDOWN = 00A7h
+WM_NCMBUTTONUP = 00A8h
+WM_NCMBUTTONDBLCLK = 00A9h
+
+WM_KEYFIRST = 0100h
+WM_KEYDOWN = 0100h
+WM_KEYUP = 0101h
+WM_CHAR = 0102h
+WM_DEADCHAR = 0103h
+WM_SYSKEYDOWN = 0104h
+WM_SYSKEYUP = 0105h
+WM_SYSCHAR = 0106h
+WM_SYSDEADCHAR = 0107h
+WM_YOMICHAR = 0108h ;Internal
+WM_KEYLAST = 0108h
+
+WM_CONVERTREQUEST = 010Ah ;Internal
+WM_CONVERTRESULT = 010Bh ;Internal
+WM_INITDIALOG = 0110h
+WM_COMMAND = 0111h
+WM_SYSCOMMAND = 0112h
+WM_TIMER = 0113h
+WM_HSCROLL = 0114h
+WM_VSCROLL = 0115h
+WM_INITMENU = 0116h
+WM_INITMENUPOPUP = 0117h
+WM_SYSTIMER = 0118h ;Internal
+WM_MENUSELECT = 011Fh
+WM_MENUCHAR = 0120h
+WM_ENTERIDLE = 0121h
+
+WM_LBTRACKPOINT = 0131h ;Internal
+
+WM_MOUSEFIRST = 0200h
+WM_MOUSEMOVE = 0200h
+WM_LBUTTONDOWN = 0201h
+WM_LBUTTONUP = 0202h
+WM_LBUTTONDBLCLK = 0203h
+WM_RBUTTONDOWN = 0204h
+WM_RBUTTONUP = 0205h
+WM_RBUTTONDBLCLK = 0206h
+WM_MBUTTONDOWN = 0207h
+WM_MBUTTONUP = 0208h
+WM_MBUTTONDBLCLK = 0209h
+WM_MOUSELAST = 0209h
+
+WM_PARENTNOTIFY = 0210h
+WM_ENTERMENULOOP = 0211h ;Internal
+WM_EXITMENULOOP = 0212h ;Internal
+WM_NEXTMENU = 0213h ;Internal
+WM_MDICREATE = 0220h
+WM_MDIDESTROY = 0221h
+WM_MDIACTIVATE = 0222h
+WM_MDIRESTORE = 0223h
+WM_MDINEXT = 0224h
+WM_MDIMAXIMIZE = 0225h
+WM_MDITILE = 0226h
+WM_MDICASCADE = 0227h
+WM_MDIICONARRANGE = 0228h
+WM_MDIGETACTIVE = 0229h
+WM_DROPOBJECT = 022Ah ;Internal
+WM_QUERYDROPOBJECT = 022Bh ;Internal
+WM_BEGINDRAG = 022Ch ;Internal
+WM_DRAGLOOP = 022Dh ;Internal
+WM_DRAGSELECT = 022Eh ;Internal
+WM_DRAGMOVE = 022Fh ;Internal
+WM_MDISETMENU = 0230h
+WM_ENTERSIZEMOVE = 0231h ;Internal
+WM_EXITSIZEMOVE = 0232h ;Internal
+WM_DROPFILES = 0233h
+
+WM_KANJIFIRST = 0280h ;Internal
+WM_KANJILAST = 029Fh ;Internal
+
+WM_CUT = 0300h
+WM_COPY = 0301h
+WM_PASTE = 0302h
+WM_CLEAR = 0303h
+WM_UNDO = 0304h
+WM_RENDERFORMAT = 0305h
+WM_RENDERALLFORMATS = 0306h
+WM_DESTROYCLIPBOARD = 0307h
+WM_DRAWCLIPBOARD = 0308h
+WM_PAINTCLIPBOARD = 0309h
+WM_VSCROLLCLIPBOARD = 030Ah
+WM_SIZECLIPBOARD = 030Bh
+WM_ASKCBFORMATNAME = 030Ch
+WM_CHANGECBCHAIN = 030Dh
+WM_HSCROLLCLIPBOARD = 030Eh
+WM_QUERYNEWPALETTE = 030Fh
+WM_PALETTEGONNACHANGE = 0310h ;Internal
+WM_PALETTEISCHANGING = 0310h
+WM_CHANGEPALETTE = 0311h ;Internal
+WM_PALETTECHANGED = 0311h
+
+IFNDEF NOWIN31
+WM_PENWINFIRST equ 0380h
+WM_PENWINLAST equ 038Fh
+
+WM_INTERNAL_COALESCE_FIRST equ 0390h ;Internal
+
+WM_COALESCE_FIRST equ 0390h
+WM_COALESCE_LAST equ 039Fh
+
+; The following message range reserved ;Internal
+; for multi-media ;Internal
+
+WM_MM_RESERVED_FIRST equ 03A0h ;Internal
+WM_MM_RESERVED_LAST equ 03DFh ;Internal
+
+WM_INTERNAL_COALESCE_LAST equ (WM_MM_RESERVED_FIRST+16) ;Internal
+
+ENDIF
+
+WM_INTERNAL_DDE_FIRST equ 03E0h ;Internal
+WM_INTERNAL_DDE_LAST equ 03EFh ;Internal
+
+; The following messages are reserved for CBT ;Internal
+WM_CBT_RESERVED_FIRST equ 03F0h ;Internal
+WM_CBT_RESERVED_LAST equ 03FFh ;Internal
+
+; private window messages start here
+WM_USER = 0400H
+ENDIF ; NOWM
+
+; WM_MOUSEACTIVATE Return Codes
+MA_ACTIVATE = 1
+MA_ACTIVATEANDEAT = 2
+MA_NOACTIVATE = 3
+
+; Size message commands
+SIZENORMAL = 0
+SIZEICONIC = 1
+SIZEFULLSCREEN = 2
+SIZEZOOMSHOW = 3
+SIZEZOOMHIDE = 4
+
+; ShowWindow() Commands
+SW_HIDE = 0
+SW_SHOWNORMAL = 1
+SW_NORMAL = 1
+SW_SHOWMINIMIZED = 2
+SW_SHOWMAXIMIZED = 3
+SW_MAXIMIZE = 3
+SW_SHOWNOACTIVATE = 4
+SW_SHOW = 5
+SW_MINIMIZE = 6
+SW_SHOWMINNOACTIVE = 7
+SW_SHOWNA = 8
+SW_RESTORE = 9
+
+; Old ShowWindow() Commands
+HIDE_WINDOW = 0
+SHOW_OPENWINDOW = 1
+SHOW_ICONWINDOW = 2
+SHOW_FULLSCREEN = 3
+SHOW_OPENNOACTIVATE= 4
+
+; identifiers for the WM_SHOWWINDOW message
+SW_PARENTCLOSING = 1
+SW_OTHERZOOM = 2
+SW_PARENTOPENING = 3
+SW_OTHERUNZOOM = 4
+;
+; Key state masks for mouse messages
+;
+MK_LBUTTON = 0001h
+MK_RBUTTON = 0002h
+MK_SHIFT = 0004h
+MK_CONTROL = 0008h
+MK_MBUTTON = 0010h
+;
+; Class styles
+;
+CS_VREDRAW = 0001h
+CS_HREDRAW = 0002h
+CS_KEYCVTWINDOW = 0004H
+CS_DBLCLKS = 0008h
+; 0010h reserved
+CS_OWNDC = 0020h
+CS_CLASSDC = 0040h
+CS_PARENTDC = 0080h
+CS_NOKEYCVT = 0100h
+CS_SAVEBITS = 0800h
+CS_NOCLOSE = 0200h
+CS_BYTEALIGNCLIENT = 1000h
+CS_BYTEALIGNWINDOW = 2000h
+CS_GLOBALCLASS = 4000h ; Global window class
+
+;
+; Special CreateWindow position value
+;
+CW_USEDEFAULT EQU 8000h
+
+;
+; Windows styles (the high words)
+;
+WS_OVERLAPPED = 00000h
+WS_ICONICPOPUP = 0C000h
+WS_POPUP = 08000h
+WS_CHILD = 04000h
+WS_MINIMIZE = 02000h
+WS_VISIBLE = 01000h
+WS_DISABLED = 00800h
+WS_CLIPSIBLINGS = 00400h
+WS_CLIPCHILDREN = 00200h
+WS_MAXIMIZE = 00100h
+WS_CAPTION = 000C0h ; WS_BORDER | WS_DLGFRAME
+WS_BORDER = 00080h
+WS_DLGFRAME = 00040h
+WS_VSCROLL = 00020h
+WS_HSCROLL = 00010h
+WS_SYSMENU = 00008h
+WS_THICKFRAME = 00004h
+WS_HREDRAW = 00002h
+WS_VREDRAW = 00001h
+WS_GROUP = 00002h
+WS_TABSTOP = 00001h
+WS_MINIMIZEBOX = 00002h
+WS_MAXIMIZEBOX = 00001h
+
+; Common Window Styles
+
+WS_OVERLAPPEDWINDOW = WS_OVERLAPPED + WS_CAPTION + WS_SYSMENU + WS_THICKFRAME + WS_MINIMIZEBOX + WS_MAXIMIZEBOX
+WS_POPUPWINDOW = WS_POPUP + WS_BORDER + WS_SYSMENU
+WS_CHILDWINDOW = WS_CHILD
+WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
+
+WS_TILED = WS_OVERLAPPED
+WS_ICONIC = WS_MINIMIZE
+WS_SIZEBOX = WS_THICKFRAME
+
+; Extended Window Styles (low words)
+WS_EX_DLGMODALFRAME = 0001
+WS_EX_DRAGOBJECT = 0002
+WS_EX_NOPARENTNOTIFY = 0004
+WS_EX_TOPMOST = 0008
+
+;
+; predefined clipboard formats
+;
+CF_TEXT = 1
+CF_BITMAP = 2
+CF_METAFILEPICT = 3
+CF_SYLK = 4
+CF_DIF = 5
+CF_TIFF = 6
+CF_OEMTEXT = 7
+CF_DIB = 8
+CF_PALETTE = 9
+CF_PENDATA = 10
+CF_RIFF = 11
+CF_WAVE = 12
+
+CF_OWNERDISPLAY = 80h ; owner display
+CF_DSPTEXT = 81h ; display text
+CF_DSPBITMAP = 82h ; display bitmap
+CF_DSPMETAFILEPICT = 83h ; display metafile
+;
+; Private clipboard format range
+;
+CF_PRIVATEFIRST = 200h ; Anything in this range doesn't
+CF_PRIVATELAST = 2ffh ; get GlobalFree'd
+CF_GDIOBJFIRST = 300h ; Anything in this range gets
+CF_GDIOBJLAST = 3ffh ; DeleteObject'ed
+
+
+MAKEINTRESOURCE MACRO a
+ mov ax,a
+ xor dx,dx
+ ENDM
+;
+; Predefined resource types
+;
+RT_CURSOR = 1 ; must be passed through MAKEINTRESOURCE
+RT_BITMAP = 2
+RT_ICON = 3
+RT_MENU = 4
+RT_DIALOG = 5
+RT_STRING = 6
+RT_FONTDIR = 7
+RT_FONT = 8
+RT_ACCELERATOR = 9
+RT_RCDATA = 10
+
+;** NOTE: if any new resource types are introduced above this point, then the
+;** value of DIFFERENCE must be changed.
+;** (RT_GROUP_CURSOR - RT_CURSOR) must always be equal to DIFFERENCE
+;** (RT_GROUP_ICON - RT_ICON) must always be equal to DIFFERENCE
+
+DIFFERENCE = 11
+
+RT_GROUP_CURSOR = RT_CURSOR + DIFFERENCE
+RT_GROUP_ICON = RT_ICON + DIFFERENCE
+
+
+
+IFNDEF NOMDI
+MDICREATESTRUCT struc
+ szClass dd ?
+ szTitle dd ?
+ hOwner dw ?
+ x dw ?
+ y dw ?
+ cxc dw ?
+ cyc dw ?
+ style dd ?
+MDICREATESTRUCT ends
+
+CLIENTCREATESTRUCT struc
+ hWindowMenu dw ?
+ idFirstChild dw ?
+CLIENTCREATESTRUCT ends
+ENDIF
+
+; NOMDI
+
+
+PALETTEENTRY struc
+ peRed db ?
+ peGreen db ?
+ peBlue db ?
+ peFlags db ?
+PALETTEENTRY ends
+
+; Logical Palette
+LOGPALETTE struc
+ palVersion dw ?
+ palNumEntries dw ?
+ palPalEntry db ? ; array of PALETTEENTRY
+LOGPALETTE ends
+
+; DRAWITEMSTRUCT for ownerdraw
+DRAWITEMSTRUCT struc
+ drCtlType dw ?
+ drCtlID dw ?
+ dritemID dw ?
+ dritemAction dw ?
+ dritemState dw ?
+ drhwndItem dw ?
+ drhDC dw ?
+ drrcItem DB size RECT dup(?)
+ dritemData dd ?
+DRAWITEMSTRUCT ends
+
+; DELETEITEMSTRUCT for ownerdraw
+DELETEITEMSTRUCT struc
+ deCtlType dw ?
+ deCtlID dw ?
+ deitemID dw ?
+ dehwndItem dw ?
+ deitemData dd ?
+DELETEITEMSTRUCT ends
+
+; MEASUREITEMSTRUCT for ownerdraw
+MEASUREITEMSTRUCT struc
+ meCtlType dw ?
+ meCtlID dw ?
+ meitemID dw ?
+ meitemWidth dw ?
+ meitemHeight dw ?
+ meitemData dd ?
+MEASUREITEMSTRUCT ends
+
+; COMPAREITEMSTUCT for ownerdraw sorting
+COMPAREITEMSTRUCT struc
+ coCtlType dw ?
+ coCtlID dw ?
+ cohwndItem dw ?
+ coitemID1 dw ?
+ coitemData1 dd ?
+ coitemID2 dw ?
+ coitemData2 dd ?
+COMPAREITEMSTRUCT ends
+
+; Owner draw control types
+ODT_MENU = 1
+ODT_LISTBOX = 2
+ODT_COMBOBOX = 3
+ODT_BUTTON = 4
+
+; Owner draw actions
+ODA_DRAWENTIRE = 1
+ODA_SELECT = 2
+ODA_FOCUS = 4
+
+; Owner draw state
+ODS_SELECTED = 0001h
+ODS_GRAYED = 0002h
+ODS_DISABLED = 0004h
+ODS_CHECKED = 0008h
+ODS_FOCUS = 0010h
+
+; PeekMessage() Options
+PM_NOREMOVE = 0000h
+PM_REMOVE = 0001h
+PM_NOYIELD = 0002h
+
+; SetWindowPos Flags
+SWP_NOSIZE = 0001h
+SWP_NOMOVE = 0002h
+SWP_NOZORDER = 0004h
+SWP_NOREDRAW = 0008h
+SWP_NOACTIVATE = 0010h
+SWP_DRAWFRAME = 0020h
+SWP_SHOWWINDOW = 0040h
+SWP_HIDEWINDOW = 0080h
+SWP_NOCOPYBITS = 0100h
+SWP_NOREPOSITION = 0200h
+
+
+IFNDEF NOWINMESSAGES
+
+; Listbox messages
+LB_ADDSTRING = (WM_USER+1)
+LB_INSERTSTRING = (WM_USER+2)
+LB_DELETESTRING = (WM_USER+3)
+LB_RESETCONTENT = (WM_USER+5)
+LB_SETSEL = (WM_USER+6)
+LB_SETCURSEL = (WM_USER+7)
+LB_GETSEL = (WM_USER+8)
+LB_GETCURSEL = (WM_USER+9)
+LB_GETTEXT = (WM_USER+10)
+LB_GETTEXTLEN = (WM_USER+11)
+LB_GETCOUNT = (WM_USER+12)
+LB_SELECTSTRING = (WM_USER+13)
+LB_DIR = (WM_USER+14)
+LB_GETTOPINDEX = (WM_USER+15)
+LB_FINDSTRING = (WM_USER+16)
+LB_GETSELCOUNT = (WM_USER+17)
+LB_GETSELITEMS = (WM_USER+18)
+LB_SETTABSTOPS = (WM_USER+19)
+LB_GETHORIZONTALEXTENT = (WM_USER+20)
+LB_SETHORIZONTALEXTENT = (WM_USER+21)
+LB_ADDFILE = (WM_USER+23) ;Internal
+LB_SETTOPINDEX = (WM_USER+24)
+LB_GETITEMRECT = (WM_USER+25)
+LB_GETITEMDATA = (WM_USER+26)
+LB_SETITEMDATA = (WM_USER+27)
+LB_SELITEMRANGE = (WM_USER+28)
+LB_SETANCHORINDEX = (WM_USER+29) ;Internal
+LB_GETANCHORINDEX = (WM_USER+30) ;Internal
+LB_SETCARETINDEX = (WM_USER+31)
+LB_GETCARETINDEX = (WM_USER+32)
+IFNDEF NOWIN31
+LB_SETITEMHEIGHT = (WM_USER+33)
+LB_GETITEMHEIGHT = (WM_USER+34)
+LB_FINDSTRINGEXACT = (WM_USER+35)
+ENDIF
+LBCB_CARETON = (WM_USER+36) ;Internal
+LBCB_CARETOFF = (WM_USER+37) ;Internal
+LB_MSGMAX = (WM_USER+38) ;Internal
+
+ENDIF
+; NOWINMESSAGES
+
+; Listbox Styles
+LBS_NOTIFY = 0001h
+LBS_SORT = 0002h
+LBS_NOREDRAW = 0004h
+LBS_MULTIPLESEL = 0008h
+LBS_OWNERDRAWFIXED = 0010h
+LBS_OWNERDRAWVARIABLE = 0020h
+LBS_HASSTRINGS = 0040h
+LBS_USETABSTOPS = 0080h
+LBS_NOINTEGRALHEIGHT = 0100h
+LBS_MULTICOLUMN = 0200h
+LBS_WANTKEYBOARDINPUT = 0400h
+LBS_EXTENDEDSEL = 0800h
+LBS_STANDARD = LBS_NOTIFY + LBS_SORT + WS_VSCROLL + WS_BORDER
+LBS_DISABLENOSCROLL = 1000h
+
+; Listbox Notification Codes
+LBN_ERRSPACE = (-2)
+LBN_SELCHANGE = 1
+LBN_DBLCLK = 2
+LBN_SELCANCEL = 3
+LBN_SETFOCUS = 4
+LBN_KILLFOCUS = 5
+
+IFNDEF NOWINMESSAGES
+
+; Edit Control Messages
+EM_GETSEL = (WM_USER+0)
+EM_SETSEL = (WM_USER+1)
+EM_GETRECT = (WM_USER+2)
+EM_SETRECT = (WM_USER+3)
+EM_SETRECTNP = (WM_USER+4)
+EM_SCROLL = (WM_USER+5)
+EM_LINESCROLL = (WM_USER+6)
+EM_GETMODIFY = (WM_USER+8)
+EM_SETMODIFY = (WM_USER+9)
+EM_GETLINECOUNT = (WM_USER+10)
+EM_LINEINDEX = (WM_USER+11)
+EM_SETHANDLE = (WM_USER+12)
+EM_GETHANDLE = (WM_USER+13)
+EM_GETTHUMB = (WM_USER+14) ;Internal
+EM_LINELENGTH = (WM_USER+17)
+EM_REPLACESEL = (WM_USER+18)
+EM_SETFONT = (WM_USER+19)
+EM_GETLINE = (WM_USER+20)
+EM_LIMITTEXT = (WM_USER+21)
+EM_CANUNDO = (WM_USER+22)
+EM_UNDO = (WM_USER+23)
+EM_FMTLINES = (WM_USER+24)
+EM_LINEFROMCHAR = (WM_USER+25)
+EM_SETWORDBREAK = (WM_USER+26)
+EM_SETTABSTOPS = (WM_USER+27)
+EM_SETPASSWORDCHAR = (WM_USER+28)
+EM_EMPTYUNDOBUFFER = (WM_USER+29)
+IFNDEF NOWIN31
+EM_GETFIRSTVISIBLELINE = (WM_USER+30)
+EM_SETREADONLY = (WM_USER+31)
+EM_SETWORDBREAKPROC = (WM_USER+32)
+EM_GETWORDBREAKPROC = (WM_USER+33)
+EM_GETPASSWORDCHAR = (WM_USER+34)
+ENDIF
+EM_MSGMAX = (WM_USER+35) ;Internal
+
+ENDIF
+; NOWINMESSAGES
+
+
+; Edit Control Styles (low word)
+ES_LEFT = 0000h
+ES_CENTER = 0001h
+ES_RIGHT = 0002h
+ES_MULTILINE = 0004h
+ES_UPPERCASE = 0008h
+ES_LOWERCASE = 0010h
+ES_PASSWORD = 0020h
+ES_AUTOVSCROLL = 0040h
+ES_AUTOHSCROLL = 0080h
+ES_NOHIDESEL = 0100h
+ES_OEMCONVERT = 0400h
+IFNDEF NOWIN31
+ES_READONLY = 0800h
+ES_WANTRETURN = 1000h
+ENDIF
+
+
+; Edit Control Notification Codes
+EN_SETFOCUS = 0100h
+EN_KILLFOCUS = 0200h
+EN_CHANGE = 0300h
+EN_UPDATE = 0400h
+EN_ERRSPACE = 0500h
+EN_MAXTEXT = 0501h
+EN_HSCROLL = 0601h
+EN_VSCROLL = 0602h
+
+IFNDEF NOWINMESSAGES
+
+; Button Control Messages
+BM_GETCHECK = (WM_USER+0)
+BM_SETCHECK = (WM_USER+1)
+BM_GETSTATE = (WM_USER+2)
+BM_SETSTATE = (WM_USER+3)
+BM_SETSTYLE = (WM_USER+4)
+
+ENDIF
+; NOWINMESSAGES
+
+; Button Control Styles (low word)
+BS_PUSHBUTTON = 00h
+BS_DEFPUSHBUTTON = 01h
+BS_CHECKBOX = 02h
+BS_AUTOCHECKBOX = 03h
+BS_RADIOBUTTON = 04h
+BS_3STATE = 05h
+BS_AUTO3STATE = 06h
+BS_GROUPBOX = 07h
+BS_USERBUTTON = 08h
+BS_AUTORADIOBUTTON = 09h
+BS_PUSHBOX = 0Ah ;Internal
+BS_OWNERDRAW = 0Bh
+BS_LEFTTEXT = 20h
+
+; User Button Notification Codes
+BN_CLICKED = 0
+BN_PAINT = 1
+BN_HILITE = 2
+BN_UNHILITE = 3
+BN_DISABLE = 4
+BN_DOUBLECLICKED = 5
+
+; Dialog Styles (low words)
+DS_ABSALIGN = 01h
+DS_SYSMODAL = 02h
+DS_LOCALEDIT = 20h ;/* Edit items get Local storage. */
+DS_SETFONT = 40h ;/* User specified font for Dlg controls */
+DS_MODALFRAME = 80h ;/* Can be combined with WS_CAPTION */
+DS_NOIDLEMSG = 100h ;/* WM_ENTERIDLE message will not be sent */
+
+IFNDEF NOWINMESSAGES
+
+; Dialog box messages
+DM_GETDEFID = (WM_USER+0)
+DM_SETDEFID = (WM_USER+1)
+
+ENDIF ;NOWINMESSAGES
+
+; Dialog Codes
+DLGC_WANTARROWS = 0001h ; /* Control wants arrow keys */
+DLGC_WANTTAB = 0002h ; /* Control wants tab keys */
+DLGC_WANTALLKEYS = 0004h ; /* Control wants all keys */
+DLGC_WANTMESSAGE = 0004h ; /* Pass message to control */
+DLGC_HASSETSEL = 0008h ; /* Understands EM_SETSEL message */
+DLGC_DEFPUSHBUTTON = 0010h ; /* Default pushbutton */
+DLGC_UNDEFPUSHBUTTON= 0020h ; /* Non-default pushbutton */
+DLGC_RADIOBUTTON = 0040h ; /* Radio button */
+DLGC_WANTCHARS = 0080h ; /* Want WM_CHAR messages */
+DLGC_STATIC = 0100h ; /* Static item: don't include */
+DLGC_BUTTON = 2000h ; /* Button item: can be checked */
+
+; Combo Box return Values
+CB_OKAY = 0
+CB_ERR = (-1)
+CB_ERRSPACE = (-2)
+
+; Combo Box Notification Codes
+CBN_ERRSPACE = (-1)
+CBN_SELCHANGE = 1
+CBN_DBLCLK = 2
+CBN_SETFOCUS = 3
+CBN_KILLFOCUS = 4
+CBN_EDITCHANGE = 5
+CBN_EDITUPDATE = 6
+CBN_DROPDOWN = 7
+
+; Combo Box styles (low words)
+CBS_SIMPLE = 0001h
+CBS_DROPDOWN = 0002h
+CBS_DROPDOWNLIST = 0003h
+CBS_OWNERDRAWFIXED = 0010h
+CBS_OWNERDRAWVARIABLE= 0020h
+CBS_AUTOHSCROLL = 0040h
+CBS_OEMCONVERT = 0080h
+CBS_SORT = 0100h
+CBS_HASSTRINGS = 0200h
+CBS_NOINTEGRALHEIGHT = 0400h
+
+IFNDEF NOWINMESSAGES
+
+; Combo Box messages
+CB_GETEDITSEL = (WM_USER+0)
+CB_LIMITTEXT = (WM_USER+1)
+CB_SETEDITSEL = (WM_USER+2)
+CB_ADDSTRING = (WM_USER+3)
+CB_DELETESTRING = (WM_USER+4)
+CB_DIR = (WM_USER+5)
+CB_GETCOUNT = (WM_USER+6)
+CB_GETCURSEL = (WM_USER+7)
+CB_GETLBTEXT = (WM_USER+8)
+CB_GETLBTEXTLEN = (WM_USER+9)
+CB_INSERTSTRING = (WM_USER+10)
+CB_RESETCONTENT = (WM_USER+11)
+CB_FINDSTRING = (WM_USER+12)
+CB_SELECTSTRING = (WM_USER+13)
+CB_SETCURSEL = (WM_USER+14)
+CB_SHOWDROPDOWN = (WM_USER+15)
+CB_GETITEMDATA = (WM_USER+16)
+CB_SETITEMDATA = (WM_USER+17)
+IFNDEF NOWIN31
+CB_GETDROPPEDCONTROLRECT = (WM_USER+18)
+CB_SETITEMHEIGHT = (WM_USER+19)
+CB_GETITEMHEIGHT = (WM_USER+20)
+CB_SETEXTENDEDUI = (WM_USER+21)
+CB_GETEXTENDEDUI = (WM_USER+22)
+CB_GETDROPPEDSTATE = (WM_USER+23)
+CB_FINDSTRINGEXACT = (WM_USER+24)
+ENDIF
+CB_MSGMAX = (WM_USER+25) ;Internal
+
+ENDIF ; NOWINMESSAGES
+
+; Static Control styles (low word)
+SS_LEFT = 00h
+SS_CENTER = 01h
+SS_RIGHT = 02h
+SS_ICON = 03h
+SS_BLACKRECT = 04h
+SS_GRAYRECT = 05h
+SS_WHITERECT = 06h
+SS_BLACKFRAME = 07h
+SS_GRAYFRAME = 08h
+SS_WHITEFRAME = 09h
+SS_USERITEM = 0Ah ;Internal
+SS_SIMPLE = 0Bh
+SS_LEFTNOWORDWRAP = 0Ch
+SS_NOPREFIX = 80h ; Don't do "&" character translation
+
+IFNDEF NOWIN31
+IFNDEF NOWINMESSAGES
+
+;Static Control Messages
+STM_SETICON = (WM_USER+0)
+STM_GETICON = (WM_USER+1)
+STM_MSGMAX = (WM_USER+2) ;Internal
+ENDIF
+ENDIF
+
+; Scroll Bar Styles (low word)
+SBS_HORZ = 0000h
+SBS_VERT = 0001h
+SBS_TOPALIGN = 0002h
+SBS_LEFTALIGN = 0002h
+SBS_BOTTOMALIGN = 0004h
+SBS_RIGHTALIGN = 0004h
+SBS_SIZEBOXTOPLEFTALIGN = 0002h
+SBS_SIZEBOXBOTTOMRIGHTALIGN = 0004h
+SBS_SIZEBOX = 0008h
+
+IFNDEF NOSYSMETRICS
+
+; GetSystemMetrics() codes
+SM_CXSCREEN = 0
+SM_CYSCREEN = 1
+SM_CXVSCROLL = 2
+SM_CYHSCROLL = 3
+SM_CYCAPTION = 4
+SM_CXBORDER = 5
+SM_CYBORDER = 6
+SM_CXDLGFRAME = 7
+SM_CYDLGFRAME = 8
+SM_CYVTHUMB = 9
+SM_CXHTHUMB = 10
+SM_CXICON = 11
+SM_CYICON = 12
+SM_CXCURSOR = 13
+SM_CYCURSOR = 14
+SM_CYMENU = 15
+SM_CXFULLSCREEN = 16
+SM_CYFULLSCREEN = 17
+SM_CYKANJIWINDOW = 18
+SM_MOUSEPRESENT = 19
+SM_CYVSCROLL = 20
+SM_CXHSCROLL = 21
+SM_DEBUG = 22
+SM_SWAPBUTTON = 23
+SM_RESERVED1 = 24
+SM_RESERVED2 = 25
+SM_RESERVED3 = 26
+SM_RESERVED4 = 27
+SM_CXMIN = 28
+SM_CYMIN = 29
+SM_CXSIZE = 30
+SM_CYSIZE = 31
+SM_CXFRAME = 32
+SM_CYFRAME = 33
+SM_CXMINTRACK = 34
+SM_CYMINTRACK = 35
+IFNDEF NOWIN31
+SM_CXDOUBLECLK = 36
+SM_CYDOUBLECLK = 37
+SM_CXICONSPACING = 38
+SM_CYICONSPACING = 39
+SM_MENUDROPALIGNMENT = 40
+SM_PENWINDOWS = 41
+SM_DBCSENABLED = 42
+ENDIF
+SM_CMETRICSMAX = 43
+
+ENDIF ;NOSYSMETRICS
+
+IFNDEF NOCOLOR
+
+COLOR_SCROLLBAR = 0
+COLOR_BACKGROUND = 1
+COLOR_ACTIVECAPTION = 2
+COLOR_INACTIVECAPTION = 3
+COLOR_MENU = 4
+COLOR_WINDOW = 5
+COLOR_WINDOWFRAME = 6
+COLOR_MENUTEXT = 7
+COLOR_WINDOWTEXT = 8
+COLOR_CAPTIONTEXT = 9
+COLOR_ACTIVEBORDER = 10
+COLOR_INACTIVEBORDER = 11
+COLOR_APPWORKSPACE = 12
+COLOR_HIGHLIGHT = 13
+COLOR_HIGHLIGHTTEXT = 14
+COLOR_BTNFACE = 15
+COLOR_BTNSHADOW = 16
+COLOR_GRAYTEXT = 17
+COLOR_BTNTEXT = 18
+IFNDEF NOWIN31
+COLOR_INACTIVECAPTIONTEXT = 19
+COLOR_BTNHILIGHT = 20
+ENDIF
+ENDIF ;NOCOLOR
+
+; Commands to pass WinHelp()
+HELP_CONTEXT =0001h ;/* Display topic in ulTopic */
+HELP_QUIT =0002h ;/* Terminate help */
+HELP_INDEX =0003h ;/* Display index */
+HELP_HELPONHELP =0004h ;/* Display help on using help */
+HELP_SETINDEX =0005h ;/* Set the current Index for multi index help */
+HELP_KEY =0101h ;/* Display topic for keyword in offabData */
+
+IFNDEF NOCOMM
+
+NOPARITY = 0
+ODDPARITY = 1
+EVENPARITY = 2
+MARKPARITY = 3
+SPACEPARITY = 4
+
+ONESTOPBIT = 0
+ONE5STOPBITS = 1
+TWOSTOPBITS = 2
+
+IGNORE = 0 ; /* Ignore signal */
+INFINITE = 0FFFFh ; /* Infinite timeout */
+
+; Error Flags
+CE_RXOVER = 0001h ; /* Receive Queue overflow */
+CE_OVERRUN = 0002h ; /* Receive Overrun Error */
+CE_RXPARITY = 0004h ; /* Receive Parity Error */
+CE_FRAME = 0008h ; /* Receive Framing error */
+CE_BREAK = 0010h ; /* Break Detected */
+CE_CTSTO = 0020h ; /* CTS Timeout */
+CE_DSRTO = 0040h ; /* DSR Timeout */
+CE_RLSDTO = 0080h ; /* RLSD Timeout */
+CE_TXFULL = 0100h ; /* TX Queue is full */
+CE_PTO = 0200h ; /* LPTx Timeout */
+CE_IOE = 0400h ; /* LPTx I/O Error */
+CE_DNS = 0800h ; /* LPTx Device not selected */
+CE_OOP = 1000h ; /* LPTx Out-Of-Paper */
+CE_MODE = 8000h ; /* Requested mode unsupported */
+
+IE_BADID = (-1) ; /* Invalid or unsupported id */
+IE_OPEN = (-2) ; /* Device Already Open */
+IE_NOPEN = (-3) ; /* Device Not Open */
+IE_MEMORY = (-4) ; /* Unable to allocate queues */
+IE_DEFAULT = (-5) ; /* Error in default parameters */
+IE_HARDWARE = (-10) ; /* Hardware Not Present */
+IE_BYTESIZE = (-11) ; /* Illegal Byte Size */
+IE_BAUDRATE = (-12) ; /* Unsupported BaudRate */
+
+; Events
+EV_RXCHAR = 0001h ; /* Any Character received */
+EV_RXFLAG = 0002h ; /* Received certain character */
+EV_TXEMPTY = 0004h ; /* Transmitt Queue Empty */
+EV_CTS = 0008h ; /* CTS changed state */
+EV_DSR = 0010h ; /* DSR changed state */
+EV_RLSD = 0020h ; /* RLSD changed state */
+EV_BREAK = 0040h ; /* BREAK received */
+EV_ERR = 0080h ; /* Line status error occurred */
+EV_RING = 0100h ; /* Ring signal detected */
+EV_PERR = 0200h ; /* Printer error occured */
+EV_CTSS = 0400h ; /* CTS state */
+EV_DSRS = 0800h ; /* DSR state */
+EV_RLSDS = 1000h ; /* RLSD state */
+EV_RingTe = 2000h ; /* Ring Trailing Edge Indicator */
+
+
+; Escape Functions
+SETXOFF = 1 ; /* Simulate XOFF received */
+SETXON = 2 ; /* Simulate XON received */
+SETRTS = 3 ; /* Set RTS high */
+CLRRTS = 4 ; /* Set RTS low */
+SETDTR = 5 ; /* Set DTR high */
+CLRDTR = 6 ; /* Set DTR low */
+RESETDEV = 7 ; /* Reset device if possible */
+
+LPTx = 80h ; /* Set if ID is for LPT device */
+
+IFNDEF NOWIN31
+; new escape functions
+GETMAXLPT equ 8 ; Max supported LPT id
+GETMAXCOM equ 9 ; Max supported COM id
+GETBASEIRQ equ 10 ; Get port base & irq for a port
+
+; Comm Baud Rate indices
+CBR_110 equ 0FF10h
+CBR_300 equ 0FF11h
+CBR_600 equ 0FF12h
+CBR_1200 equ 0FF13h
+CBR_2400 equ 0FF14h
+CBR_4800 equ 0FF15h
+CBR_9600 equ 0FF16h
+CBR_14400 equ 0FF17h
+CBR_19200 equ 0FF18h
+; 0FF19h (reserved)
+; 0FF1Ah (reserved)
+CBR_38400 equ 0FF1Bh
+; 0FF1Ch (reserved)
+; 0FF1Dh (reserved)
+; 0FF1Eh (reserved)
+CBR_56000 equ 0FF1Fh
+; 0FF20h (reserved)
+; 0FF21h (reserved)
+; 0FF22h (reserved)
+CBR_128000 equ 0FF23h
+; 0FF24h (reserved)
+; 0FF25h (reserved)
+; 0FF26h (reserved)
+CBR_256000 equ 0FF27h
+
+; notifications passed in low word of lParam on WM_COMMNOTIFY messages
+CN_RECEIVE equ 1 ; bytes are available in the input queue
+CN_TRANSMIT equ 2 ; fewer than wOutTrigger bytes still
+ ; remain in the output queue waiting
+ ; to be transmitted.
+CN_EVENT equ 4 ; an enabled event has occurred
+
+ENDIF
+
+
+DCB struc
+ DCB_Id db ? ; /* Internal Device ID */
+ DCB_BaudRate dw ? ; /* Baudrate at which runing */
+ DCB_ByteSize db ? ; /* Number of bits/byte, 4-8 */
+ DCB_Parity db ? ; /* 0-4=None,Odd,Even,Mark,Space */
+ DCB_StopBits db ? ; /* 0,1,2 = 1, 1.5, 2 */
+ DCB_RlsTimeout dw ? ; /* Timeout for RLSD to be set */
+ DCB_CtsTimeout dw ? ; /* Timeout for CTS to be set */
+ DCB_DsrTimeout dw ? ; /* Timeout for DSR to be set */
+
+ DCB_BitMask1 db ?
+
+ ; BYTE fBinary: 1; /* Binary Mode (skip EOF check */
+ ; BYTE fRtsDisable:1; /* Don't assert RTS at init time */
+ ; BYTE fParity: 1; /* Enable parity checking */
+ ; BYTE fOutxCtsFlow:1; /* CTS handshaking on output */
+ ; BYTE fOutxDsrFlow:1; /* DSR handshaking on output */
+ ; BYTE fDummy: 2; /* Reserved */
+ ; BYTE fDtrDisable:1; /* Don't assert DTR at init time */
+
+ DCB_BitMask2 db ?
+
+ ; BYTE fOutX: 1; /* Enable output X-ON/X-OFF */
+ ; BYTE fInX: 1; /* Enable input X-ON/X-OFF */
+ ; BYTE fPeChar: 1; /* Enable Parity Err Replacement */
+ ; BYTE fNull: 1; /* Enable Null stripping */
+ ; BYTE fChEvt: 1; /* Enable Rx character event. */
+ ; BYTE fDtrflow: 1; /* DTR handshake on input */
+ ; BYTE fRtsflow: 1; /* RTS handshake on input */
+ ; BYTE fDummy2: 1;
+
+ DCB_XonChar db ? ; /* Tx and Rx X-ON character */
+ DCB_XoffChar db ? ; /* Tx and Rx X-OFF character */
+ DCB_XonLim dw ? ; /* Transmit X-ON threshold */
+ DCB_XoffLim dw ? ; /* Transmit X-OFF threshold */
+ DCB_PeChar db ? ; /* Parity error replacement char */
+ DCB_EofChar db ? ; /* End of Input character */
+ DCB_EvtChar db ? ; /* Recieved Event character */
+ DCB_TxDelay dw ? ; /* Amount of time between chars */
+DCB ends
+
+COMSTAT struc
+ COMS_BitMask1 db ?
+
+; BYTE fCtsHold: 1; /* Transmit is on CTS hold */
+; BYTE fDsrHold: 1; /* Transmit is on DSR hold */
+; BYTE fRlsdHold: 1; /* Transmit is on RLSD hold */
+; BYTE fXoffHold: 1; /* Received handshake */
+; BYTE fXoffSent: 1; /* Issued handshake */
+; BYTE fEof: 1; /* End of file character found */
+; BYTE fTxim: 1; /* Character being transmitted */
+
+
+ COMS_cbInQue dw ? ; /* count of characters in Rx Queue */
+ COMS_cbOutQue dw ? ; /* count of characters in Tx Queue */
+COMSTAT ends
+
+ENDIF ;NOCOM
+
+;
+; Installable Driver Support
+;
+; Driver Messages
+DRV_LOAD = 0001h
+DRV_ENABLE = 0002h
+DRV_OPEN = 0003h
+DRV_CLOSE = 0004h
+DRV_DISABLE = 0005h
+DRV_FREE = 0006h
+DRV_CONFIGURE = 0007h
+DRV_QUERYCONFIGURE = 0008h
+DRV_INSTALL = 0009h
+DRV_REMOVE = 000Ah
+DRV_EXITSESSION = 000Bh
+DRV_POWER = 000Fh
+DRV_RESERVED = 0800h
+DRV_USER = 4000h
+
+;LPARAM of DRV_CONFIGURE message and return values
+DRVCONFIGINFO struc
+ DRVCNF_dwDCISize dw ?
+ DRVCNF_lpszDCISectionName dd ?
+ DRVCNF_lpszDCIAliasName dd ?
+DRVCONFIGINFO ends
+
+DRVCNF_CANCEL = 0000h
+DRVCNF_OK = 0001h
+DRVCNF_RESTART = 0002h
+
+
+IFNDEF NOKERNEL
+;
+; Common Kernel errors
+;
+ERR_GALLOC = 01030h ; GlobalAlloc Failed
+ERR_GREALLOC = 01031h ; GlobalReAlloc Failed
+ERR_GLOCK = 01032h ; GlobalLock Failed
+ERR_LALLOC = 01033h ; LocalAlloc Failed
+ERR_LREALLOC = 01034h ; LocalReAlloc Failed
+ERR_LLOCK = 01035h ; LocalLock Failed
+ERR_ALLOCRES = 01036h ; AllocResource Failed
+ERR_LOCKRES = 01037h ; LockResource Failed
+ERR_LOADMODULE = 01038h ; LoadModule failed
+
+;
+; Common User Errors
+;
+ERR_CREATEDLG = 01045h ; /* Create Dlg failure due to LoadMenu failure */
+ERR_CREATEDLG2 = 01046h ; /* Create Dlg failure due to CreateWindow Failure */
+ERR_REGISTERCLASS = 01047h ; /* RegisterClass failure due to Class already registered */
+ERR_DCBUSY = 01048h ; /* DC Cache is full */
+ERR_CREATEWND = 01049h ; /* Create Wnd failed due to class not found */
+ERR_STRUCEXTRA = 01050h ; /* Unallocated Extra space is used */
+ERR_LOADSTR = 01051h ; /* LoadString() failed */
+ERR_LOADMENU = 01052h ; /* LoadMenu Failed */
+ERR_NESTEDBEGINPAINT = 01053h ; /* Nested BeginPaint() calls */
+ERR_BADINDEX = 01054h ; /* Bad index to Get/Set Class/Window Word/Long */
+ERR_CREATEMENU = 01055h ; /* Error creating menu */
+
+;
+; Common GDI Errors
+;
+ERR_CREATEDC = 01070h ; /* CreateDC/CreateIC etc., failure */
+ERR_CREATEMETA = 01071h ; /* CreateMetafile failure */
+ERR_DELOBJSELECTED = 01072h ; /* Bitmap being deleted is selected into DC */
+ERR_SELBITMAP = 01073h ; /* Bitmap being selected is already selected elsewhere */
+
+ENDIF ;NOKERNEL
diff --git a/private/mvdm/wow16/inc/windowsx.h b/private/mvdm/wow16/inc/windowsx.h
new file mode 100644
index 000000000..a37eb53f6
--- /dev/null
+++ b/private/mvdm/wow16/inc/windowsx.h
@@ -0,0 +1,1112 @@
+/*****************************************************************************\
+* *
+* windowsx.h - Macro APIs, window message crackers, and control APIs *
+* *
+* Version 3.10 *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_WINDOWSX
+#define _INC_WINDOWSX
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/****** KERNEL Macro APIs ****************************************************/
+
+#define GetInstanceModule(hInstance) \
+ GetModuleHandle((LPCSTR)MAKELP(0, hInstance))
+
+#define GlobalPtrHandle(lp) \
+ ((HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lp))))
+
+#define GlobalLockPtr(lp) \
+ ((BOOL)SELECTOROF(GlobalLock(GlobalPtrHandle(lp))))
+#define GlobalUnlockPtr(lp) \
+ GlobalUnlock(GlobalPtrHandle(lp))
+
+#define GlobalAllocPtr(flags, cb) \
+ (GlobalLock(GlobalAlloc((flags), (cb))))
+#define GlobalReAllocPtr(lp, cbNew, flags) \
+ (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags))))
+#define GlobalFreePtr(lp) \
+ (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))
+
+/****** GDI Macro APIs *******************************************************/
+
+#define DeletePen(hpen) DeleteObject((HGDIOBJ)(HPEN)(hpen))
+#define SelectPen(hdc, hpen) ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
+#define GetStockPen(i) ((HPEN)GetStockObject(i))
+
+#define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
+#define SelectBrush(hdc, hbr) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr)))
+#define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
+
+#define DeleteRgn(hrgn) DeleteObject((HGDIOBJ)(HRGN)(hrgn))
+
+#define CopyRgn(hrgnDst, hrgnSrc) CombineRgn(hrgnDst, hrgnSrc, 0, RGN_COPY)
+#define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND)
+#define SubtractRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_DIFF)
+#define UnionRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_OR)
+#define XorRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_XOR)
+
+#define DeletePalette(hpal) DeleteObject((HGDIOBJ)(HPALETTE)(hpal))
+
+#define DeleteFont(hfont) DeleteObject((HGDIOBJ)(HFONT)(hfont))
+#define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
+#define GetStockFont(i) ((HFONT)GetStockObject(i))
+
+#define DeleteBitmap(hbm) DeleteObject((HGDIOBJ)(HBITMAP)(hbm))
+#define SelectBitmap(hdc, hbm) ((HBITMAP)SelectObject((hdc), (HGDIOBJ)(HBITMAP)(hbm)))
+
+#define InsetRect(lprc, dx, dy) InflateRect((lprc), -(dx), -(dy))
+
+/****** USER Macro APIs ******************************************************/
+
+#define GetWindowInstance(hwnd) ((HINSTANCE)GetWindowWord(hwnd, GWW_HINSTANCE))
+
+#define GetWindowStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_STYLE))
+#define GetWindowExStyle(hwnd) ((DWORD)GetWindowLong(hwnd, GWL_EXSTYLE))
+
+#define GetWindowOwner(hwnd) GetWindow(hwnd, GW_OWNER)
+
+#define GetFirstChild(hwnd) GetTopWindow(hwnd)
+#define GetFirstSibling(hwnd) GetWindow(hwnd, GW_HWNDFIRST)
+#define GetLastSibling(hwnd) GetWindow(hwnd, GW_HWNDLAST)
+#define GetNextSibling(hwnd) GetWindow(hwnd, GW_HWNDNEXT)
+#define GetPrevSibling(hwnd) GetWindow(hwnd, GW_HWNDPREV)
+
+#define GetWindowID(hwnd) GetDlgCtrlID(hwnd)
+
+#define SetWindowRedraw(hwnd, fRedraw) \
+ ((void)SendMessage(hwnd, WM_SETREDRAW, (WPARAM)(BOOL)(fRedraw), 0L))
+
+#define SubclassWindow(hwnd, lpfn) \
+ ((WNDPROC)SetWindowLong((hwnd), GWL_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))
+
+#define IsMinimized(hwnd) IsIconic(hwnd)
+#define IsMaximized(hwnd) IsZoomed(hwnd)
+#define IsRestored(hwnd) ((GetWindowStyle(hwnd) & (WS_MINIMIZE | WS_MAXIMIZE)) == 0L)
+
+#define SetWindowFont(hwnd, hfont, fRedraw) FORWARD_WM_SETFONT((hwnd), (hfont), (fRedraw), SendMessage)
+
+#define GetWindowFont(hwnd) FORWARD_WM_GETFONT((hwnd), SendMessage)
+
+#if (WINVER >= 0x030a)
+#define MapWindowRect(hwndFrom, hwndTo, lprc) \
+ MapWindowPoints((hwndFrom), (hwndTo), (POINT FAR*)(lprc), 2)
+#endif /* WINVER >= 0x030a */
+
+#define IsLButtonDown() (GetKeyState(VK_LBUTTON) < 0)
+#define IsRButtonDown() (GetKeyState(VK_RBUTTON) < 0)
+#define IsMButtonDown() (GetKeyState(VK_MBUTTON) < 0)
+
+#define SubclassDialog(hwndDlg, lpfn) \
+ ((DLGPROC)SetWindowLong(hwndDlg, DWL_DLGPROC, (LPARAM)(DLGPROC)(lpfn)))
+
+#define SetDlgMsgResult(hwnd, msg, result) \
+ (((msg) == WM_CTLCOLOR || (msg) == WM_COMPAREITEM || (msg) == WM_VKEYTOITEM || \
+ (msg) == WM_CHARTOITEM || (msg) == WM_QUERYDRAGICON || (msg) == WM_INITDIALOG) \
+ ? (BOOL)LOWORD(result) : (SetWindowLong((hwnd), DWL_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))
+
+#define DefDlgProcEx(hwnd, msg, wParam, lParam, pfRecursion) \
+ (*(pfRecursion) = TRUE, DefDlgProc(hwnd, msg, wParam, lParam))
+
+#define CheckDefDlgRecursion(pfRecursion) \
+ if (*(pfRecursion)) { *(pfRecursion) = FALSE; return FALSE; }
+
+/****** Message crackers ****************************************************/
+
+#define HANDLE_MSG(hwnd, message, fn) \
+ case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
+
+/* void Cls_OnCompacting(HWND hwnd, UINT compactRatio); */
+#define HANDLE_WM_COMPACTING(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam)), 0L)
+#define FORWARD_WM_COMPACTING(hwnd, compactRatio, fn) \
+ (void)(fn)((hwnd), WM_COMPACTING, (WPARAM)(UINT)(compactRatio), 0L)
+
+/* void Cls_OnWinIniChange(HWND hwnd, LPCSTR lpszSectionName); */
+#define HANDLE_WM_WININICHANGE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (LPCSTR)(lParam)), 0L)
+#define FORWARD_WM_WININICHANGE(hwnd, lpszSectionName, fn) \
+ (void)(fn)((hwnd), WM_WININICHANGE, 0, (LPARAM)(LPCSTR)(lpszSectionName))
+
+/* void Cls_OnSysColorChange(HWND hwnd); */
+#define HANDLE_WM_SYSCOLORCHANGE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_SYSCOLORCHANGE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_SYSCOLORCHANGE, 0, 0L)
+
+/* BOOL Cls_OnQueryNewPalette(HWND hwnd); */
+#define HANDLE_WM_QUERYNEWPALETTE(hwnd, wParam, lParam, fn) \
+ MAKELRESULT((BOOL)(fn)(hwnd), 0)
+#define FORWARD_WM_QUERYNEWPALETTE(hwnd, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYNEWPALETTE, 0, 0L)
+
+/* void Cls_OnPaletteIsChanging(HWND hwnd, HWND hwndPaletteChange); */
+#define HANDLE_WM_PALETTEISCHANGING(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_PALETTEISCHANGING(hwnd, hwndPaletteChange, fn) \
+ (void)(fn)((hwnd), WM_PALETTEISCHANGING, (WPARAM)(HWND)(hwndPaletteChange), 0L)
+
+/* void Cls_OnPaletteChanged(HWND hwnd, HWND hwndPaletteChange); */
+#define HANDLE_WM_PALETTECHANGED(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_PALETTECHANGED(hwnd, hwndPaletteChange, fn) \
+ (void)(fn)((hwnd), WM_PALETTECHANGED, (WPARAM)(HWND)(hwndPaletteChange), 0L)
+
+/* void Cls_OnFontChange(HWND hwnd); */
+#define HANDLE_WM_FONTCHANGE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_FONTCHANGE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_FONTCHANGE, 0, 0L)
+
+/* void Cls_OnSpoolerStatus(HWND hwnd, UINT status, int cJobInQueue); */
+#define HANDLE_WM_SPOOLERSTATUS(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_SPOOLERSTATUS(hwnd, status, cJobInQueue, fn) \
+ (void)(fn)((hwnd), WM_SPOOLERSTATUS, (WPARAM)(status), MAKELPARAM((UINT)(cJobInQueue), 0))
+
+/* void Cls_OnDevModeChange(HWND hwnd, LPCSTR lpszDeviceName); */
+#define HANDLE_WM_DEVMODECHANGE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (LPCSTR)(lParam)), 0L)
+#define FORWARD_WM_DEVMODECHANGE(hwnd, lpszDeviceName, fn) \
+ (void)(fn)((hwnd), WM_DEVMODECHANGE, 0,(LPARAM)(LPCSTR)(lpszDeviceName))
+
+/* void Cls_OnTimeChange(HWND hwnd); */
+#define HANDLE_WM_TIMECHANGE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_TIMECHANGE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_TIMECHANGE, 0, 0L)
+
+/* void Cls_OnPower(HWND hwnd, int code); */
+#define HANDLE_WM_POWER(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam)), 0L)
+#define FORWARD_WM_POWER(hwnd, code, fn) \
+ (void)(fn)((hwnd), WM_POWER, (WPARAM)(code), 0L)
+
+/* BOOL Cls_OnQueryEndSession(HWND hwnd); */
+#define HANDLE_WM_QUERYENDSESSION(hwnd, wParam, lParam, fn) \
+ MAKELRESULT((BOOL)(fn)(hwnd), 0)
+#define FORWARD_WM_QUERYENDSESSION(hwnd, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYENDSESSION, 0, 0L)
+
+/* void Cls_OnEndSession(HWND hwnd, BOOL fEnding); */
+#define HANDLE_WM_ENDSESSION(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam)), 0L)
+#define FORWARD_WM_ENDSESSION(hwnd, fEnding, fn) \
+ (void)(fn)((hwnd), WM_ENDSESSION, (WPARAM)(BOOL)(fEnding), 0L)
+
+/* void Cls_OnQuit(HWND hwnd, int exitCode); */
+#define HANDLE_WM_QUIT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam)), 0L)
+#define FORWARD_WM_QUIT(hwnd, exitCode, fn) \
+ (void)(fn)((hwnd), WM_QUIT, (WPARAM)(exitCode), 0L)
+
+/* void Cls_OnSystemError(HWND hwnd, int errCode); */
+#define HANDLE_WM_SYSTEMERROR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam)), 0L)
+#define FORWARD_WM_SYSTEMERROR(hwnd, errCode, fn) \
+ (void)(fn)((hwnd), WM_SYSTEMERROR, (WPARAM)(errCode), 0L)
+
+/* BOOL Cls_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) */
+#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (CREATESTRUCT FAR*)(lParam)) ? 0L : (LRESULT)-1L)
+#define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_CREATE, 0, (LPARAM)(CREATESTRUCT FAR*)(lpCreateStruct))
+
+/* BOOL Cls_OnNCCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) */
+#define HANDLE_WM_NCCREATE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (CREATESTRUCT FAR*)(lParam))
+#define FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_NCCREATE, 0, (LPARAM)(CREATESTRUCT FAR*)(lpCreateStruct))
+
+/* void Cls_OnDestroy(HWND hwnd); */
+#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_DESTROY(hwnd, fn) \
+ (void)(fn)((hwnd), WM_DESTROY, 0, 0L)
+
+/* void Cls_OnNCDestroy(HWND hwnd); */
+#define HANDLE_WM_NCDESTROY(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_NCDESTROY(hwnd, fn) \
+ (void)(fn)((hwnd), WM_NCDESTROY, 0, 0L)
+
+/* void Cls_OnShowWindow(HWND hwnd, BOOL fShow, UINT status); */
+#define HANDLE_WM_SHOWWINDOW(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam), LOWORD(lParam)), 0L)
+#define FORWARD_WM_SHOWWINDOW(hwnd, fShow, status, fn) \
+ (void)(fn)((hwnd), WM_SHOWWINDOW, (WPARAM)(BOOL)(fShow), MAKELPARAM((UINT)(status), 0))
+
+/* void Cls_OnSetRedraw(HWND hwnd, BOOL fRedraw); */
+#define HANDLE_WM_SETREDRAW(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam)), 0L)
+#define FORWARD_WM_SETREDRAW(hwnd, fRedraw, fn) \
+ (void)(fn)((hwnd), WM_SETREDRAW, (WPARAM)(fRedraw), 0L)
+
+/* void Cls_OnEnable(HWND hwnd, BOOL fEnable); */
+#define HANDLE_WM_ENABLE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam)), 0L)
+#define FORWARD_WM_ENABLE(hwnd, fEnable, fn) \
+ (void)(fn)((hwnd), WM_ENABLE, (WPARAM)(BOOL)(fEnable), 0L)
+
+/* void Cls_OnSetText(HWND hwnd, LPCSTR lpszText); */
+#define HANDLE_WM_SETTEXT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (LPCSTR)(lParam)), 0L)
+#define FORWARD_WM_SETTEXT(hwnd, lpszText, fn) \
+ (void)(fn)((hwnd), WM_SETTEXT, 0, (LPARAM)(LPCSTR)(lpszText))
+
+/* INT Cls_OnGetText(HWND hwnd, int cchTextMax, LPSTR lpszText) */
+#define HANDLE_WM_GETTEXT(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)((hwnd), (int)(wParam), (LPSTR)(lParam))
+#define FORWARD_WM_GETTEXT(hwnd, cchTextMax, lpszText, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_GETTEXT, (WPARAM)(int)(cchTextMax), (LPARAM)(LPSTR)(lpszText))
+
+/* INT Cls_OnGetTextLength(HWND hwnd); */
+#define HANDLE_WM_GETTEXTLENGTH(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)(hwnd)
+#define FORWARD_WM_GETTEXTLENGTH(hwnd, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_GETTEXTLENGTH, 0, 0L)
+
+/* BOOL Cls_OnWindowPosChanging(HWND hwnd, WINDOWPOS FAR* lpwpos); */
+#define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (WINDOWPOS FAR*)(lParam))
+#define FORWARD_WM_WINDOWPOSCHANGING(hwnd, lpwpos, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_WINDOWPOSCHANGING, 0, (LPARAM)(WINDOWPOS FAR*)(lpwpos))
+
+/* void Cls_OnWindowPosChanged(HWND hwnd, const WINDOWPOS FAR* lpwpos); */
+#define HANDLE_WM_WINDOWPOSCHANGED(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (const WINDOWPOS FAR*)(lParam)), 0L)
+#define FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, fn) \
+ (void)(fn)((hwnd), WM_WINDOWPOSCHANGED, 0, (LPARAM)(const WINDOWPOS FAR*)(lpwpos))
+
+/* void Cls_OnMove(HWND hwnd, int x, int y); */
+#define HANDLE_WM_MOVE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam)), 0L)
+#define FORWARD_WM_MOVE(hwnd, x, y, fn) \
+ (void)(fn)((hwnd), WM_MOVE, 0, MAKELPARAM((int)(x), (int)(y)))
+
+/* void Cls_OnSize(HWND hwnd, UINT state, int cx, int cy); */
+#define HANDLE_WM_SIZE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam), (int)HIWORD(lParam)), 0L)
+#define FORWARD_WM_SIZE(hwnd, state, cx, cy, fn) \
+ (void)(fn)((hwnd), WM_SIZE, (WPARAM)(UINT)(state), MAKELPARAM((int)(cx), (int)(cy)))
+
+/* void Cls_OnClose(HWND hwnd); */
+#define HANDLE_WM_CLOSE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_CLOSE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_CLOSE, 0, 0L)
+
+/* BOOL Cls_OnQueryOpen(HWND hwnd); */
+#define HANDLE_WM_QUERYOPEN(hwnd, wParam, lParam, fn) \
+ MAKELRESULT((BOOL)(fn)(hwnd), 0)
+#define FORWARD_WM_QUERYOPEN(hwnd, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_QUERYOPEN, 0, 0L)
+
+/* void Cls_OnGetMinMaxInfo(HWND hwnd, MINMAXINFO FAR* lpMinMaxInfo); */
+#define HANDLE_WM_GETMINMAXINFO(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (MINMAXINFO FAR*)(lParam)), 0L)
+#define FORWARD_WM_GETMINMAXINFO(hwnd, lpMinMaxInfo, fn) \
+ (void)(fn)((hwnd), WM_GETMINMAXINFO, 0, (LPARAM)(MINMAXINFO FAR*)(lpMinMaxInfo))
+
+/* void Cls_OnPaint(HWND hwnd); */
+#define HANDLE_WM_PAINT(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_PAINT(hwnd, fn) \
+ (void)(fn)((hwnd), WM_PAINT, 0, 0L)
+
+/* BOOL Cls_OnEraseBkgnd(HWND hwnd, HDC hdc); */
+#define HANDLE_WM_ERASEBKGND(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
+#define FORWARD_WM_ERASEBKGND(hwnd, hdc, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_ERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
+
+/* BOOL Cls_OnIconEraseBkgnd(HWND hwnd, HDC hdc); */
+#define HANDLE_WM_ICONERASEBKGND(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HDC)(wParam))
+#define FORWARD_WM_ICONERASEBKGND(hwnd, hdc, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_ICONERASEBKGND, (WPARAM)(HDC)(hdc), 0L)
+
+/* void Cls_OnNCPaint(HWND hwnd, HRGN hrgn); */
+#define HANDLE_WM_NCPAINT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HRGN)(wParam)), 0L)
+#define FORWARD_WM_NCPAINT(hwnd, hrgn, fn) \
+ (void)(fn)((hwnd), WM_NCPAINT, (WPARAM)(HRGN)(hrgn), 0L)
+
+/* UINT Cls_OnNCCalcSize(HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS FAR* lpcsp) */
+#define HANDLE_WM_NCCALCSIZE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(wParam), (NCCALCSIZE_PARAMS FAR*)(lParam))
+#define FORWARD_WM_NCCALCSIZE(hwnd, fCalcValidRects, lpcsp, fn) \
+ (UINT)(DWORD)(fn)((hwnd), WM_NCCALCSIZE, (WPARAM)(fCalcValidRects), (LPARAM)(NCCALCSIZE_PARAMS FAR*)(lpcsp))
+
+/* UINT Cls_OnNCHitTest(HWND hwnd, int x, int y); */
+#define HANDLE_WM_NCHITTEST(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam))
+#define FORWARD_WM_NCHITTEST(hwnd, x, y, fn) \
+ (UINT)(DWORD)(fn)((hwnd), WM_NCHITTEST, 0, MAKELPARAM((int)(x), (int)(y)))
+
+/* HICON Cls_OnQueryDragIcon(HWND hwnd); */
+#define HANDLE_WM_QUERYDRAGICON(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)(hwnd)
+#define FORWARD_WM_QUERYDRAGICON(hwnd, fn) \
+ (HICON)(UINT)(DWORD)(fn)((hwnd), WM_QUERYDRAGICON, 0, 0L)
+
+#ifdef _INC_SHELLAPI
+/* void Cls_OnDropFiles(HWND hwnd, HDROP hdrop); */
+#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HDROP)(wParam)), 0L)
+#define FORWARD_WM_DROPFILES(hwnd, hdrop, fn) \
+ (void)(fn)((hwnd), WM_DROPFILES, (WPARAM)(hdrop), 0L)
+#endif /* _INC_SHELLAPI */
+
+/* void Cls_OnActivate(HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized); */
+#define HANDLE_WM_ACTIVATE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (HWND)LOWORD(lParam), (BOOL)HIWORD(lParam)), 0L)
+#define FORWARD_WM_ACTIVATE(hwnd, state, hwndActDeact, fMinimized, fn) \
+ (void)(fn)((hwnd), WM_ACTIVATE, (WPARAM)(UINT)(state), MAKELPARAM((UINT)(HWND)(hwndActDeact), (UINT)(BOOL)(fMinimized)))
+
+/* void Cls_OnActivateApp(HWND hwnd, BOOL fActivate, HTASK htaskActDeact); */
+#define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam), (HTASK)LOWORD(lParam)), 0L)
+#define FORWARD_WM_ACTIVATEAPP(hwnd, fActivate, htaskActDeact, fn) \
+ (void)(fn)((hwnd), WM_ACTIVATEAPP, (WPARAM)(BOOL)(fActivate), MAKELPARAM((htaskActDeact),0))
+
+/* BOOL Cls_OnNCActivate(HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL fMinimized); */
+#define HANDLE_WM_NCACTIVATE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (BOOL)(wParam), (HWND)LOWORD(lParam), (BOOL)HIWORD(lParam))
+#define FORWARD_WM_NCACTIVATE(hwnd, fActive, hwndActDeact, fMinimized, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_NCACTIVATE, (WPARAM)(BOOL)(fActive), MAKELPARAM((UINT)(HWND)(hwndActDeact), (UINT)(BOOL)(fMinimized)))
+
+/* void Cls_OnSetFocus(HWND hwnd, HWND hwndOldFocus) */
+#define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_SETFOCUS(hwnd, hwndOldFocus, fn) \
+ (void)(fn)((hwnd), WM_SETFOCUS, (WPARAM)(HWND)(hwndOldFocus), 0L)
+
+/* void Cls_OnKillFocus(HWND hwnd, HWND hwndNewFocus); */
+#define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_KILLFOCUS(hwnd, hwndNewFocus, fn) \
+ (void)(fn)((hwnd), WM_KILLFOCUS, (WPARAM)(HWND)(hwndNewFocus), 0L)
+
+/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags); */
+#define HANDLE_WM_KEYDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), TRUE, (int)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_KEYDOWN(hwnd, vk, cRepeat, flags, fn) \
+ (void)(fn)((hwnd), WM_KEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((UINT)(cRepeat), (UINT)(flags)))
+
+/* void Cls_OnKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags); */
+#define HANDLE_WM_KEYUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), FALSE, (int)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_KEYUP(hwnd, vk, cRepeat, flags, fn) \
+ (void)(fn)((hwnd), WM_KEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((UINT)(cRepeat), (UINT)(flags)))
+
+/* void Cls_OnChar(HWND hwnd, UINT ch, int cRepeat); */
+#define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_CHAR(hwnd, ch, cRepeat, fn) \
+ (void)(fn)((hwnd), WM_CHAR, (WPARAM)(UINT)(ch), MAKELPARAM((UINT)(cRepeat),0))
+
+/* void Cls_OnDeadChar(HWND hwnd, UINT ch, int cRepeat); */
+#define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_DEADCHAR(hwnd, ch, cRepeat, fn) \
+ (void)(fn)((hwnd), WM_DEADCHAR, (WPARAM)(UINT)(ch), MAKELPARAM((UINT)(cRepeat),0))
+
+/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags); */
+#define HANDLE_WM_SYSKEYDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), TRUE, (int)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_SYSKEYDOWN(hwnd, vk, cRepeat, flags, fn) \
+ (void)(fn)((hwnd), WM_SYSKEYDOWN, (WPARAM)(UINT)(vk), MAKELPARAM((UINT)(cRepeat), (UINT)(flags)))
+
+/* void Cls_OnSysKey(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags); */
+#define HANDLE_WM_SYSKEYUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), FALSE, (int)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_SYSKEYUP(hwnd, vk, cRepeat, flags, fn) \
+ (void)(fn)((hwnd), WM_SYSKEYUP, (WPARAM)(UINT)(vk), MAKELPARAM((UINT)(cRepeat), (UINT)(flags)))
+
+/* void Cls_OnSysChar(HWND hwnd, UINT ch, int cRepeat); */
+#define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_SYSCHAR(hwnd, ch, cRepeat, fn) \
+ (void)(fn)((hwnd), WM_SYSCHAR, (WPARAM)(UINT)(ch), MAKELPARAM((UINT)(cRepeat), 0))
+
+/* void Cls_OnSysDeadChar(HWND hwnd, UINT ch, int cRepeat); */
+#define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_SYSDEADCHAR(hwnd, ch, cRepeat, fn) \
+ (void)(fn)((hwnd), WM_SYSDEADCHAR, (WPARAM)(UINT)(ch), MAKELPARAM((UINT)(cRepeat), 0))
+
+/* void Cls_OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_MOUSEMOVE(hwnd, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), WM_MOUSEMOVE, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_LBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : WM_LBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_LBUTTONUP(hwnd, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), WM_LBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_RBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_RBUTTONDBLCLK : WM_RBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnRButtonUp(HWND hwnd, int x, int y, UINT flags); */
+#define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_RBUTTONUP(hwnd, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), WM_RBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_MBUTTONDOWN(hwnd, fDoubleClick, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_MBUTTONDBLCLK : WM_MBUTTONDOWN, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags); */
+#define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnMButtonUp(HWND hwnd, int x, int y, UINT flags); */
+#define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_MBUTTONUP(hwnd, x, y, keyFlags, fn) \
+ (void)(fn)((hwnd), WM_MBUTTONUP, (WPARAM)(UINT)(keyFlags), MAKELPARAM((x), (y)))
+
+/* void Cls_OnNCMouseMove(HWND hwnd, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCMOUSEMOVE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCMOUSEMOVE(hwnd, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), WM_NCMOUSEMOVE, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
+
+/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCLBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCLBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)))
+
+/* void Cls_OnNCLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCLBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnNCLButtonUp(HWND hwnd, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCLBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCLBUTTONUP(hwnd, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), WM_NCLBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
+
+/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCRBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCRBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCRBUTTONDBLCLK : WM_NCRBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
+
+/* void Cls_OnNCRButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCRBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnNCRButtonUp(HWND hwnd, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCRBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCRBUTTONUP(hwnd, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), WM_NCRBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
+
+/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCMBUTTONDOWN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), FALSE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCMBUTTONDOWN(hwnd, fDoubleClick, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), (fDoubleClick) ? WM_NCMBUTTONDBLCLK : WM_NCMBUTTONDOWN, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
+
+/* void Cls_OnNCMButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCMBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), TRUE, (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+
+/* void Cls_OnNCMButtonUp(HWND hwnd, int x, int y, UINT codeHitTest); */
+#define HANDLE_WM_NCMBUTTONUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)LOWORD(lParam), (int)HIWORD(lParam), (UINT)(wParam)), 0L)
+#define FORWARD_WM_NCMBUTTONUP(hwnd, x, y, codeHitTest, fn) \
+ (void)(fn)((hwnd), WM_NCMBUTTONUP, (WPARAM)(UINT)(codeHitTest), MAKELPARAM((x), (y)) )
+
+/* int Cls_OnMouseActivate(HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT msg); */
+#define HANDLE_WM_MOUSEACTIVATE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam))
+#define FORWARD_WM_MOUSEACTIVATE(hwnd, hwndTopLevel, codeHitTest, msg, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_MOUSEACTIVATE, (WPARAM)(HWND)(hwndTopLevel), MAKELPARAM((codeHitTest), (msg)))
+
+/* void Cls_OnCancelMode(HWND hwnd); */
+#define HANDLE_WM_CANCELMODE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_CANCELMODE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_CANCELMODE, 0, 0L)
+
+/* void Cls_OnTimer(HWND hwnd, UINT id); */
+#define HANDLE_WM_TIMER(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam)), 0L)
+#define FORWARD_WM_TIMER(hwnd, id, fn) \
+ (void)(fn)((hwnd), WM_TIMER, (WPARAM)(UINT)(id), 0L)
+
+/* void Cls_OnInitMenu(HWND hwnd, HMENU hMenu); */
+#define HANDLE_WM_INITMENU(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HMENU)(wParam)), 0L)
+#define FORWARD_WM_INITMENU(hwnd, hMenu, fn) \
+ (void)(fn)((hwnd), WM_INITMENU, (WPARAM)(HMENU)(hMenu), 0L)
+
+/* void Cls_OnInitMenuPopup(HWND hwnd, HMENU hMenu, int item, BOOL fSystemMenu); */
+#define HANDLE_WM_INITMENUPOPUP(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HMENU)(wParam), (int)LOWORD(lParam), (BOOL)HIWORD(lParam)), 0L)
+#define FORWARD_WM_INITMENUPOPUP(hwnd, hMenu, item, fSystemMenu, fn) \
+ (void)(fn)((hwnd), WM_INITMENUPOPUP, (WPARAM)(HMENU)(hMenu), MAKELPARAM((item),(fSystemMenu)))
+
+/* void Cls_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags); */
+#define HANDLE_WM_MENUSELECT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HMENU)HIWORD(lParam), (LOWORD(lParam) & MF_POPUP) ? 0 : (int)(wParam), \
+ (LOWORD(lParam) & MF_POPUP) ? (HMENU)(wParam) : 0, LOWORD(lParam)), 0L)
+#define FORWARD_WM_MENUSELECT(hwnd, hmenu, item, hmenuPopup, flags, fn) \
+ (void)(fn)((hwnd), WM_MENUSELECT, ((flags) & MF_POPUP) ? (WPARAM)(HMENU)(hmenuPopup) : (WPARAM)(int)(item), MAKELPARAM((flags), (hmenu)))
+
+/* DWORD Cls_OnMenuChar(HWND hwnd, UINT ch, UINT flags, HMENU hmenu); */
+#define HANDLE_WM_MENUCHAR(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam), LOWORD(lParam), (HMENU)HIWORD(lParam));
+#define FORWARD_WM_MENUCHAR(hwnd, ch, flags, hmenu, fn) \
+ (DWORD)(fn)((hwnd), WM_MENUCHAR, (WPARAM)(UINT)(ch), MAKELPARAM((flags), (UINT)(hmenu)))
+
+/* void Cls_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); */
+#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam), (HWND)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, fn) \
+ (void)(fn)((hwnd), WM_COMMAND, (WPARAM)(int)(id), MAKELPARAM((UINT)(hwndCtl), (codeNotify)))
+
+/* void Cls_OnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos); */
+#define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)HIWORD(lParam), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_HSCROLL(hwnd, hwndCtl, code, pos, fn) \
+ (void)(fn)((hwnd), WM_HSCROLL, (WPARAM)(UINT)(code), MAKELPARAM((pos), (UINT)(hwndCtl)))
+
+/* void Cls_OnVScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos); */
+#define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)HIWORD(lParam), (UINT)(wParam), (int)LOWORD(lParam)), 0L)
+#define FORWARD_WM_VSCROLL(hwnd, hwndCtl, code, pos, fn) \
+ (void)(fn)((hwnd), WM_VSCROLL, (WPARAM)(UINT)(code), MAKELPARAM((pos), (UINT)(hwndCtl)))
+
+/* void Cls_OnCut(HWND hwnd); */
+#define HANDLE_WM_CUT(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_CUT(hwnd, fn) \
+ (void)(fn)((hwnd), WM_CUT, 0, 0L)
+
+/* void Cls_OnCopy(HWND hwnd); */
+#define HANDLE_WM_COPY(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_COPY(hwnd, fn) \
+ (void)(fn)((hwnd), WM_COPY, 0, 0L)
+
+/* void Cls_OnPaste(HWND hwnd); */
+#define HANDLE_WM_PASTE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_PASTE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_PASTE, 0, 0L)
+
+/* void Cls_OnClear(HWND hwnd); */
+#define HANDLE_WM_CLEAR(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_CLEAR(hwnd, fn) \
+ (void)(fn)((hwnd), WM_CLEAR, 0, 0L)
+
+/* void Cls_OnUndo(HWND hwnd); */
+#define HANDLE_WM_UNDO(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_UNDO(hwnd, fn) \
+ (void)(fn)((hwnd), WM_UNDO, 0, 0L)
+
+/* HANDLE Cls_OnRenderFormat(HWND hwnd, UINT fmt); */
+#define HANDLE_WM_RENDERFORMAT(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(HANDLE)(fn)((hwnd), (UINT)(wParam))
+#define FORWARD_WM_RENDERFORMAT(hwnd, fmt, fn) \
+ (HANDLE)(UINT)(DWORD)(fn)((hwnd), WM_RENDERFORMAT, (WPARAM)(UINT)(fmt), 0L)
+
+/* void Cls_OnRenderAllFormats(HWND hwnd); */
+#define HANDLE_WM_RENDERALLFORMATS(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_RENDERALLFORMATS(hwnd, fn) \
+ (void)(fn)((hwnd), WM_RENDERALLFORMATS, 0, 0L)
+
+/* void Cls_OnDestroyClipboard(HWND hwnd); */
+#define HANDLE_WM_DESTROYCLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_DESTROYCLIPBOARD(hwnd, fn) \
+ (void)(fn)((hwnd), WM_DESTROYCLIPBOARD, 0, 0L)
+
+/* void Cls_OnDrawClipboard(HWND hwnd); */
+#define HANDLE_WM_DRAWCLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_DRAWCLIPBOARD(hwnd, fn) \
+ (void)(fn)((hwnd), WM_DRAWCLIPBOARD, 0, 0L)
+
+/* void Cls_OnPaintClipboard(HWND hwnd, HWND hwndCBViewer, const PAINTSTRUCT FAR* lpPaintStruct) */
+#define HANDLE_WM_PAINTCLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), (const PAINTSTRUCT FAR*)GlobalLock((HGLOBAL)LOWORD(lParam))), GlobalUnlock((HGLOBAL)LOWORD(lParam)), 0L)
+#define FORWARD_WM_PAINTCLIPBOARD(hwnd, hwndCBViewer, lpPaintStruct, fn) \
+ (void)(fn)((hwnd), WM_PAINTCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), (LPARAM)(lpPaintStruct))
+
+/* void Cls_OnSizeClipboard(HWND hwnd, HWND hwndCBViewer, const RECT FAR* lprc); */
+#define HANDLE_WM_SIZECLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), (const RECT FAR*)GlobalLock((HGLOBAL)LOWORD(lParam))), GlobalUnlock((HGLOBAL)LOWORD(lParam)), 0L)
+#define FORWARD_WM_SIZECLIPBOARD(hwnd, hwndCBViewer, lprc, fn) \
+ (void)(fn)((hwnd), WM_SIZECLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), (LPARAM)(lprc))
+
+/* void Cls_OnVScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos); */
+#define HANDLE_WM_VSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), LOWORD(lParam), (int)HIWORD(lParam)), 0L)
+#define FORWARD_WM_VSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
+ (void)(fn)((hwnd), WM_VSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code), (pos)))
+
+/* void Cls_OnHScrollClipboard(HWND hwnd, HWND hwndCBViewer, UINT code, int pos); */
+#define HANDLE_WM_HSCROLLCLIPBOARD(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), LOWORD(lParam), (int)HIWORD(lParam)), 0L)
+#define FORWARD_WM_HSCROLLCLIPBOARD(hwnd, hwndCBViewer, code, pos, fn) \
+ (void)(fn)((hwnd), WM_HSCROLLCLIPBOARD, (WPARAM)(HWND)(hwndCBViewer), MAKELPARAM((code), (pos)))
+
+/* void Cls_OnAskCBFormatName(HWND hwnd, int cchMax, LPSTR rgchName); */
+#define HANDLE_WM_ASKCBFORMATNAME(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam), (LPSTR)(lParam)), 0L)
+#define FORWARD_WM_ASKCBFORMATNAME(hwnd, cchMax, rgchName, fn) \
+ (void)(fn)((hwnd), WM_ASKCBFORMATNAME, (WPARAM)(int)(cchMax), (LPARAM)(rgchName))
+
+/* void Cls_OnChangeCBChain(HWND hwnd, HWND hwndRemove, HWND hwndNext); */
+#define HANDLE_WM_CHANGECBCHAIN(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), (HWND)LOWORD(lParam)), 0L)
+#define FORWARD_WM_CHANGECBCHAIN(hwnd, hwndRemove, hwndNext, fn) \
+ (void)(fn)((hwnd), WM_CHANGECBCHAIN, (WPARAM)(HWND)(hwndRemove), MAKELPARAM((UINT)(hwndNext), 0))
+
+/* BOOL Cls_OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg); */
+#define HANDLE_WM_SETCURSOR(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (HWND)(wParam), (UINT)LOWORD(lParam), (UINT)HIWORD(lParam));
+#define FORWARD_WM_SETCURSOR(hwnd, hwndCursor, codeHitTest, msg, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_SETCURSOR, (WPARAM)(HWND)(hwndCursor), MAKELPARAM((codeHitTest), (msg)))
+
+/* void Cls_OnSysCommand(HWND hwnd, UINT cmd, int x, int y); */
+#define HANDLE_WM_SYSCOMMAND(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (int)LOWORD(lParam), (int)HIWORD(lParam)), 0L)
+#define FORWARD_WM_SYSCOMMAND(hwnd, cmd, x, y, fn) \
+ (void)(fn)((hwnd), WM_SYSCOMMAND, (WPARAM)(UINT)(cmd), MAKELPARAM((x), (y)))
+
+/* HWND Cls_MDICreate(HWND hwnd, const MDICREATESTRUCT FAR* lpmcs); */
+#define HANDLE_WM_MDICREATE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (MDICREATESTRUCT FAR*)(lParam))
+#define FORWARD_WM_MDICREATE(hwnd, lpmcs, fn) \
+ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDICREATE, 0, (LPARAM)(lpmcs))
+
+/* void Cls_MDIDestroy(HWND hwnd, HWND hwndDestroy); */
+#define HANDLE_WM_MDIDESTROY(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_MDIDESTROY(hwnd, hwndDestroy, fn) \
+ (void)(fn)((hwnd), WM_MDIDESTROY, (WPARAM)(hwndDestroy), 0L)
+
+/* NOTE: Usable only by MDI client windows */
+/* void Cls_MDIActivate(HWND hwnd, BOOL fActive, HWND hwndActivate, HWND hwndDeactivate); */
+#define HANDLE_WM_MDIACTIVATE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (BOOL)(wParam), (HWND)LOWORD(lParam), (HWND)HIWORD(lParam)), 0L)
+#define FORWARD_WM_MDIACTIVATE(hwnd, fActive, hwndActivate, hwndDeactivate, fn) \
+ (void)(fn)(hwnd, WM_MDIACTIVATE, (WPARAM)(fActive), MAKELPARAM((hwndActivate), (hwndDeactivate)))
+
+/* void Cls_MDIRestore(HWND hwnd, HWND hwndRestore); */
+#define HANDLE_WM_MDIRESTORE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_MDIRESTORE(hwnd, hwndRestore, fn) \
+ (void)(fn)((hwnd), WM_MDIRESTORE, (WPARAM)(hwndRestore), 0L)
+
+/* HWND Cls_MDINext(HWND hwnd, HWND hwndCur, BOOL fPrev); */
+#define HANDLE_WM_MDINEXT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam), (BOOL)LOWORD(lParam)), 0L)
+#define FORWARD_WM_MDINEXT(hwnd, hwndCur, fPrev, fn) \
+ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDINEXT, (WPARAM)(hwndCur), MAKELPARAM((fPrev), 0))
+
+/* void Cls_MDIMaximize(HWND hwnd, HWND hwndMaximize); */
+#define HANDLE_WM_MDIMAXIMIZE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HWND)(wParam)), 0L)
+#define FORWARD_WM_MDIMAXIMIZE(hwnd, hwndMaximize, fn) \
+ (void)(fn)((hwnd), WM_MDIMAXIMIZE, (WPARAM)(hwndMaximize), 0L)
+
+/* BOOL Cls_MDITile(HWND hwnd, UINT cmd); */
+#define HANDLE_WM_MDITILE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
+#define FORWARD_WM_MDITILE(hwnd, cmd, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_MDITILE, (WPARAM)(cmd), 0L)
+
+/* BOOL Cls_MDICascade(HWND hwnd, UINT cmd); */
+#define HANDLE_WM_MDICASCADE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(fn)((hwnd), (UINT)(wParam))
+#define FORWARD_WM_MDICASCADE(hwnd, cmd, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_MDICASCADE, (WPARAM)(cmd), 0L)
+
+/* void Cls_MDIIconArrange(HWND hwnd); */
+#define HANDLE_WM_MDIICONARRANGE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_MDIICONARRANGE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_MDIICONARRANGE, 0, 0L)
+
+/* HWND Cls_MDIGetActive(HWND hwnd); */
+#define HANDLE_WM_MDIGETACTIVE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)(hwnd)
+#define FORWARD_WM_MDIGETACTIVE(hwnd, fn) \
+ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_MDIGETACTIVE, 0, 0L)
+
+/* HMENU Cls_MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU hmenuWindow); */
+#define HANDLE_WM_MDISETMENU(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)((hwnd), (BOOL)(wParam), (HMENU)LOWORD(lParam), (HMENU)HIWORD(lParam))
+#define FORWARD_WM_MDISETMENU(hwnd, fRefresh, hmenuFrame, hmenuWindow, fn) \
+ (HMENU)(UINT)(DWORD)(fn)((hwnd), WM_MDISETMENU, (WPARAM)(fRefresh), MAKELPARAM((hmenuFrame), (hmenuWindow)))
+
+/* void Cls_OnChildActivate(HWND hwnd); */
+#define HANDLE_WM_CHILDACTIVATE(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_CHILDACTIVATE(hwnd, fn) \
+ (void)(fn)((hwnd), WM_CHILDACTIVATE, 0, 0L)
+
+/* BOOL Cls_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam); */
+#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam);
+#define FORWARD_WM_INITDIALOG(hwnd, hwndFocus, lParam, fn) \
+ (BOOL)(DWORD)(fn)((hwnd), WM_INITDIALOG, (WPARAM)(HWND)(hwndFocus), (lParam))
+
+/* HWND Cls_OnNextDlgCtl(HWND hwnd, HWND hwndSetFocus, BOOL fNext) */
+#define HANDLE_WM_NEXTDLGCTL(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(HWND)(fn)((hwnd), (HWND)(wParam), (BOOL)LOWORD(lParam))
+#define FORWARD_WM_NEXTDLGCTL(hwnd, hwndSetFocus, fNext, fn) \
+ (HWND)(UINT)(DWORD)(fn)((hwnd), WM_NEXTDLGCTL, (WPARAM)(HWND)(hwndSetFocus), MAKELPARAM((fNext), 0))
+
+/* void Cls_OnParentNotify(HWND hwnd, UINT msg, HWND hwndChild, int idChild); */
+#define HANDLE_WM_PARENTNOTIFY(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (HWND)LOWORD(lParam), (UINT)HIWORD(lParam)), 0L)
+#define FORWARD_WM_PARENTNOTIFY(hwnd, msg, hwndChild, idChild, fn) \
+ (void)(fn)((hwnd), WM_PARENTNOTIFY, (WPARAM)(UINT)(msg), MAKELPARAM((UINT)(HWND)(hwndChild), (UINT)(idChild)))
+
+/* void Cls_OnEnterIdle(HWND hwnd, UINT source, HWND hwndSource); */
+#define HANDLE_WM_ENTERIDLE(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (UINT)(wParam), (HWND)LOWORD(lParam)), 0L)
+#define FORWARD_WM_ENTERIDLE(hwnd, source, hwndSource, fn) \
+ (void)(fn)((hwnd), WM_ENTERIDLE, (WPARAM)(UINT)(source), MAKELPARAM((UINT)(HWND)(hwndSource), 0))
+
+/* UINT Cls_OnGetDlgCode(HWND hwnd, MSG FAR* lpmsg); */
+#define HANDLE_WM_GETDLGCODE(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(fn)(hwnd, (MSG FAR*)(lParam))
+#define FORWARD_WM_GETDLGCODE(hwnd, lpmsg, fn) \
+ (UINT)(DWORD)(fn)((hwnd), WM_GETDLGCODE, (SELECTOROF(lpmsg) ? lpmsg->wParam : 0), (LPARAM)(lpmsg))
+
+/* HBRUSH Cls_OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type); */
+#define HANDLE_WM_CTLCOLOR(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(HBRUSH)(fn)((hwnd), (HDC)(wParam), (HWND)LOWORD(lParam), (int)(HIWORD(lParam)))
+#define FORWARD_WM_CTLCOLOR(hwnd, hdc, hwndChild, type, fn) \
+ (HBRUSH)(UINT)(DWORD)(fn)((hwnd), WM_CTLCOLOR, (WPARAM)(HDC)(hdc), MAKELPARAM((UINT)(HWND)(hwndChild), (UINT)(int)(type)))
+
+/* void Cls_OnSetFont(HWND hwndCtl, HFONT hfont, BOOL fRedraw); */
+#define HANDLE_WM_SETFONT(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (HFONT)(wParam), (BOOL)LOWORD(lParam)), 0L)
+#define FORWARD_WM_SETFONT(hwnd, hfont, fRedraw, fn) \
+ (void)(fn)((hwnd), WM_SETFONT, (WPARAM)(HFONT)(hfont), MAKELPARAM((UINT)(BOOL)(fRedraw), 0))
+
+/* HFONT Cls_OnGetFont(HWND hwnd); */
+#define HANDLE_WM_GETFONT(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(UINT)(HFONT)(fn)(hwnd)
+#define FORWARD_WM_GETFONT(hwnd, fn) \
+ (HFONT)(UINT)(DWORD)(fn)((hwnd), WM_GETFONT, 0, 0L)
+
+/* void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT FAR* lpDrawItem); */
+#define HANDLE_WM_DRAWITEM(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (const DRAWITEMSTRUCT FAR*)(lParam)), 0L)
+#define FORWARD_WM_DRAWITEM(hwnd, lpDrawItem, fn) \
+ (void)(fn)((hwnd), WM_DRAWITEM, 0, (LPARAM)(const DRAWITEMSTRUCT FAR*)(lpDrawItem))
+
+/* void Cls_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT FAR* lpMeasureItem); */
+#define HANDLE_WM_MEASUREITEM(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (MEASUREITEMSTRUCT FAR*)(lParam)), 0L)
+#define FORWARD_WM_MEASUREITEM(hwnd, lpMeasureItem, fn) \
+ (void)(fn)((hwnd), WM_MEASUREITEM, 0, (LPARAM)(MEASUREITEMSTRUCT FAR*)(lpMeasureItem))
+
+/* void Cls_OnDeleteItem(HWND hwnd, const DELETEITEMSTRUCT FAR* lpDeleteItem) */
+#define HANDLE_WM_DELETEITEM(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (const DELETEITEMSTRUCT FAR*)(lParam)), 0L)
+#define FORWARD_WM_DELETEITEM(hwnd, lpDeleteItem, fn) \
+ (void)(fn)((hwnd), WM_DELETEITEM, 0, (LPARAM)(const DELETEITEMSTRUCT FAR*)(lpDeleteItem))
+
+/* int Cls_OnCompareItem(HWND hwnd, const COMPAREITEMSTRUCT FAR* lpCompareItem); */
+#define HANDLE_WM_COMPAREITEM(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)((hwnd), (const COMPAREITEMSTRUCT FAR*)(lParam))
+#define FORWARD_WM_COMPAREITEM(hwnd, lpCompareItem, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_COMPAREITEM, 0, (LPARAM)(const COMPAREITEMSTRUCT FAR*)(lpCompareItem))
+
+/* int Cls_OnVkeyToItem(HWND hwnd, UINT vk, HWND hwndListbox, int iCaret); */
+#define HANDLE_WM_VKEYTOITEM(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)(wParam), (HWND)LOWORD(lParam), (int)HIWORD(lParam))
+#define FORWARD_WM_VKEYTOITEM(hwnd, vk, hwndListBox, iCaret, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_VKEYTOITEM, (WPARAM)(UINT)(vk), MAKELPARAM((UINT)(hwndListBox), (UINT)(iCaret)))
+
+/* int Cls_OnCharToItem(HWND hwnd, UINT ch, HWND hwndListbox, int iCaret); */
+#define HANDLE_WM_CHARTOITEM(hwnd, wParam, lParam, fn) \
+ (LRESULT)(DWORD)(int)(fn)((hwnd), (UINT)(wParam), (HWND)LOWORD(lParam), (int)HIWORD(lParam))
+#define FORWARD_WM_CHARTOITEM(hwnd, ch, hwndListBox, iCaret, fn) \
+ (int)(DWORD)(fn)((hwnd), WM_CHARTOITEM, (WPARAM)(UINT)(ch), MAKELPARAM((UINT)(hwndListBox), (UINT)(iCaret)))
+
+/* void Cls_OnQueueSync(HWND hwnd); */
+#define HANDLE_WM_QUEUESYNC(hwnd, wParam, lParam, fn) \
+ ((fn)(hwnd), 0L)
+#define FORWARD_WM_QUEUESYNC(hwnd, fn) \
+ (void)(fn)((hwnd), WM_QUEUESYNC, 0, 0L)
+
+/* void Cls_OnCommNotify(HWND hwnd, int cid, UINT flags); */
+#define HANDLE_WM_COMMNOTIFY(hwnd, wParam, lParam, fn) \
+ ((fn)((hwnd), (int)(wParam), LOWORD(lParam)), 0L)
+#define FORWARD_WM_COMMNOTIFY(hwnd, cid, flags, fn) \
+ (void)(fn)((hwnd), WM_COMMNOTIFY, (WPARAM)(cid), MAKELPARAM((flags), 0))
+
+/****** Static control message APIs ******************************************/
+
+#define Static_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))
+
+#define Static_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))
+#define Static_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)
+#define Static_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))
+
+#define Static_SetIcon(hwndCtl, hIcon) ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_SETICON, (WPARAM)(HICON)(hIcon), 0L))
+#define Static_GetIcon(hwndCtl, hIcon) ((HICON)(UINT)(DWORD)SendMessage((hwndCtl), STM_GETICON, 0, 0L))
+
+/****** Button control message APIs ******************************************/
+
+#define Button_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))
+
+#define Button_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))
+#define Button_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)
+#define Button_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))
+
+#define Button_GetCheck(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), BM_GETCHECK, 0, 0L))
+#define Button_SetCheck(hwndCtl, check) ((void)SendMessage((hwndCtl), BM_SETCHECK, (WPARAM)(int)(check), 0L))
+
+#define Button_GetState(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), BM_GETSTATE, 0, 0L))
+#define Button_SetState(hwndCtl, state) ((UINT)(DWORD)SendMessage((hwndCtl), BM_SETSTATE, (WPARAM)(int)(state), 0L))
+
+#define Button_SetStyle(hwndCtl, style, fRedraw) ((void)SendMessage((hwndCtl), BM_SETSTYLE, (WPARAM)LOWORD(style), MAKELPARAM(((fRedraw) ? TRUE : FALSE), 0)))
+
+/****** Edit control message APIs ********************************************/
+
+#define Edit_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))
+
+#define Edit_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))
+#define Edit_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)
+#define Edit_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))
+
+#define Edit_LimitText(hwndCtl, cchMax) ((void)SendMessage((hwndCtl), EM_LIMITTEXT, (WPARAM)(cchMax), 0L))
+
+#define Edit_GetLineCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINECOUNT, 0, 0L))
+#define Edit_GetLine(hwndCtl, line, lpch, cchMax) ((*((int FAR*)(lpch)) = (cchMax)), ((int)(DWORD)SendMessage((hwndCtl), EM_GETLINE, (WPARAM)(int)(line), (LPARAM)(LPSTR)(lpch))))
+
+#define Edit_GetRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_GETRECT, 0, (LPARAM)(RECT FAR*)(lprc)))
+#define Edit_SetRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECT, 0, (LPARAM)(const RECT FAR*)(lprc)))
+#define Edit_SetRectNoPaint(hwndCtl, lprc) ((void)SendMessage((hwndCtl), EM_SETRECTNP, 0, (LPARAM)(const RECT FAR*)(lprc)))
+
+#define Edit_GetSel(hwndCtl) ((DWORD)SendMessage((hwndCtl), EM_GETSEL, 0, 0L))
+#define Edit_SetSel(hwndCtl, ichStart, ichEnd) ((void)SendMessage((hwndCtl), EM_SETSEL, 0, MAKELPARAM((ichStart), (ichEnd))))
+#define Edit_ReplaceSel(hwndCtl, lpszReplace) ((void)SendMessage((hwndCtl), EM_REPLACESEL, 0, (LPARAM)(LPCSTR)(lpszReplace)))
+
+#define Edit_GetModify(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_GETMODIFY, 0, 0L))
+#define Edit_SetModify(hwndCtl, fModified) ((void)SendMessage((hwndCtl), EM_SETMODIFY, (WPARAM)(UINT)(fModified), 0L))
+
+#define Edit_LineFromChar(hwndCtl, ich) ((int)(DWORD)SendMessage((hwndCtl), EM_LINEFROMCHAR, (WPARAM)(int)(ich), 0L))
+#define Edit_LineIndex(hwndCtl, line) ((int)(DWORD)SendMessage((hwndCtl), EM_LINEINDEX, (WPARAM)(int)(line), 0L))
+#define Edit_LineLength(hwndCtl, line) ((int)(DWORD)SendMessage((hwndCtl), EM_LINELENGTH, (WPARAM)(int)(line), 0L))
+
+#define Edit_Scroll(hwndCtl, dv, dh) ((void)SendMessage((hwndCtl), EM_LINESCROLL, 0, MAKELPARAM((dv), (dh))))
+
+#define Edit_CanUndo(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_CANUNDO, 0, 0L))
+#define Edit_Undo(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_UNDO, 0, 0L))
+#define Edit_EmptyUndoBuffer(hwndCtl) ((void)SendMessage((hwndCtl), EM_EMPTYUNDOBUFFER, 0, 0L))
+
+#define Edit_SetPasswordChar(hwndCtl, ch) ((void)SendMessage((hwndCtl), EM_SETPASSWORDCHAR, (WPARAM)(UINT)(ch), 0L))
+
+#define Edit_SetTabStops(hwndCtl, cTabs, lpTabs) ((void)SendMessage((hwndCtl), EM_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(const int FAR*)(lpTabs)))
+
+#define Edit_FmtLines(hwndCtl, fAddEOL) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_FMTLINES, (WPARAM)(BOOL)(fAddEOL), 0L))
+
+#define Edit_GetHandle(hwndCtl) ((HLOCAL)(UINT)(DWORD)SendMessage((hwndCtl), EM_GETHANDLE, 0, 0L))
+#define Edit_SetHandle(hwndCtl, h) ((void)SendMessage((hwndCtl), EM_SETHANDLE, (WPARAM)(UINT)(HLOCAL)(h), 0L))
+
+#if (WINVER >= 0x030a)
+#define Edit_GetFirstVisibleLine(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), EM_GETFIRSTVISIBLELINE, 0, 0L))
+
+#define Edit_SetReadOnly(hwndCtl, fReadOnly) ((BOOL)(DWORD)SendMessage((hwndCtl), EM_SETREADONLY, (WPARAM)(BOOL)(fReadOnly), 0L))
+
+#define Edit_GetPasswordChar(hwndCtl) ((char)(DWORD)SendMessage((hwndCtl), EM_GETPASSWORDCHAR, 0, 0L))
+
+#define Edit_SetWordBreakProc(hwndCtl, lpfnWordBreak) ((void)SendMessage((hwndCtl), EM_SETWORDBREAKPROC, 0, (LPARAM)(EDITWORDBREAKPROC)(lpfnWordBreak)))
+#define Edit_GetWordBreakProc(hwndCtl) ((EDITWORDBREAKPROC)SendMessage((hwndCtl), EM_GETWORDBREAKPROC, 0, 0L))
+#endif /* WINVER >= 0x030a */
+
+/****** ScrollBar control message APIs ***************************************/
+
+/* NOTE: flags parameter is a collection of ESB_* values, NOT a boolean! */
+#define ScrollBar_Enable(hwndCtl, flags) EnableScrollBar((hwndCtl), SB_CTL, (flags))
+
+#define ScrollBar_Show(hwndCtl, fShow) ShowWindow((hwndCtl), (fShow) ? SW_SHOWNORMAL : SW_HIDE)
+
+#define ScrollBar_SetPos(hwndCtl, pos, fRedraw) SetScrollPos((hwndCtl), SB_CTL, (pos), (fRedraw))
+#define ScrollBar_GetPos(hwndCtl) GetScrollPos((hwndCtl), SB_CTL)
+
+#define ScrollBar_SetRange(hwndCtl, posMin, posMax, fRedraw) SetScrollRange((hwndCtl), SB_CTL, (posMin), (posMax), (fRedraw))
+#define ScrollBar_GetRange(hwndCtl, lpposMin, lpposMax) GetScrollRange((hwndCtl), SB_CTL, (lpposMin), (lpposMax))
+
+/****** ListBox control message APIs *****************************************/
+
+#define ListBox_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))
+
+#define ListBox_GetCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCOUNT, 0, 0L))
+#define ListBox_ResetContent(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), LB_RESETCONTENT, 0, 0L))
+
+#define ListBox_AddString(hwndCtl, lpsz) ((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0, (LPARAM)(LPCSTR)(lpsz)))
+#define ListBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCSTR)(lpsz)))
+
+#define ListBox_AddItemData(hwndCtl, data) ((int)(DWORD)SendMessage((hwndCtl), LB_ADDSTRING, 0, (LPARAM)(data)))
+#define ListBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), LB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data)))
+
+#define ListBox_DeleteString(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_DELETESTRING, (WPARAM)(int)(index), 0L))
+
+#define ListBox_GetTextLen(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXTLEN, (WPARAM)(int)(index), 0L))
+#define ListBox_GetText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTEXT, (WPARAM)(int)(index), (LPARAM)(LPCSTR)(lpszBuffer)))
+
+#define ListBox_GetItemData(hwndCtl, index) ((LRESULT)(DWORD)SendMessage((hwndCtl), LB_GETITEMDATA, (WPARAM)(int)(index), 0L))
+#define ListBox_SetItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data)))
+
+#define ListBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszFind)))
+#define ListBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
+
+#define ListBox_SetSel(hwndCtl, fSelect, index) ((int)(DWORD)SendMessage((hwndCtl), LB_SETSEL, (WPARAM)(BOOL)(fSelect), MAKELPARAM((index), 0)))
+#define ListBox_SelItemRange(hwndCtl, fSelect, first, last) ((int)(DWORD)SendMessage((hwndCtl), LB_SELITEMRANGE, (WPARAM)(BOOL)(fSelect), MAKELPARAM((first), (last))))
+
+#define ListBox_GetCurSel(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCURSEL, 0, 0L))
+#define ListBox_SetCurSel(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_SETCURSEL, (WPARAM)(int)(index), 0L))
+
+#define ListBox_SelectString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszFind)))
+#define ListBox_SelectItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), LB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
+
+#define ListBox_GetSel(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSEL, (WPARAM)(int)(index), 0L))
+#define ListBox_GetSelCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELCOUNT, 0, 0L))
+#define ListBox_GetTopIndex(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETTOPINDEX, 0, 0L))
+#define ListBox_GetSelItems(hwndCtl, cItems, lpItems) ((int)(DWORD)SendMessage((hwndCtl), LB_GETSELITEMS, (WPARAM)(int)(cItems), (LPARAM)(int FAR*)(lpItems)))
+
+#define ListBox_SetTopIndex(hwndCtl, indexTop) ((int)(DWORD)SendMessage((hwndCtl), LB_SETTOPINDEX, (WPARAM)(int)(indexTop), 0L))
+
+#define ListBox_SetColumnWidth(hwndCtl, cxColumn) ((void)SendMessage((hwndCtl), LB_SETCOLUMNWIDTH, (WPARAM)(int)(cxColumn), 0L))
+#define ListBox_GetHorizontalExtent(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETHORIZONTALEXTENT, 0, 0L))
+#define ListBox_SetHorizontalExtent(hwndCtl, cxExtent) ((void)SendMessage((hwndCtl), LB_SETHORIZONTALEXTENT, (WPARAM)(int)(cxExtent), 0L))
+
+#define ListBox_SetTabStops(hwndCtl, cTabs, lpTabs) ((BOOL)(DWORD)SendMessage((hwndCtl), LB_SETTABSTOPS, (WPARAM)(int)(cTabs), (LPARAM)(int FAR*)(lpTabs)))
+
+#define ListBox_GetItemRect(hwndCtl, index, lprc) ((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMRECT, (WPARAM)(int)(index), (LPARAM)(RECT FAR*)(lprc)))
+
+#define ListBox_SetCaretIndex(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_SETCARETINDEX, (WPARAM)(int)(index), 0L))
+#define ListBox_GetCaretIndex(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETCARETINDEX, 0, 0L))
+
+#define ListBox_SetAnchorIndex(hwndCtl, index) ((void)SendMessage((hwndCtl), LB_SETANCHORINDEX, (WPARAM)(int)(index), 0L)) /* ;Internal */
+#define ListBox_GetAnchorIndex(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), LB_GETANCHORINDEX, 0, 0L)) /* ;Internal */
+
+#if (WINVER >= 0x030a)
+#define ListBox_FindStringExact(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), LB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszFind)))
+
+#define ListBox_SetItemHeight(hwndCtl, index, cy) ((int)(DWORD)SendMessage((hwndCtl), LB_SETITEMHEIGHT, (WPARAM)(int)(index), MAKELPARAM((cy), 0)))
+#define ListBox_GetItemHeight(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), LB_GETITEMHEIGHT, (WPARAM)(int)(index), 0L))
+#endif /* WINVER >= 0x030a */
+
+#define ListBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), LB_DIR, (WPARAM)(UINT)(attrs), (LPARAM)(LPCSTR)(lpszFileSpec)))
+#define ListBox_AddFile(hwndCtl, lpszFilename) ((int)(DWORD)SendMessage((hwndCtl), LB_ADDFILE, 0, (LPARAM)(LPCSTR)(lpszFilename))) /* ;Internal */
+
+/****** ComboBox control message APIs ****************************************/
+
+#define ComboBox_Enable(hwndCtl, fEnable) EnableWindow((hwndCtl), (fEnable))
+
+#define ComboBox_GetText(hwndCtl, lpch, cchMax) GetWindowText((hwndCtl), (lpch), (cchMax))
+#define ComboBox_GetTextLength(hwndCtl) GetWindowTextLength(hwndCtl)
+#define ComboBox_SetText(hwndCtl, lpsz) SetWindowText((hwndCtl), (lpsz))
+
+#define ComboBox_LimitText(hwndCtl, cchLimit) ((int)(DWORD)SendMessage((hwndCtl), CB_LIMITTEXT, (WPARAM)(int)(cchLimit), 0L))
+
+#define ComboBox_GetEditSel(hwndCtl) ((DWORD)SendMessage((hwndCtl), CB_GETEDITSEL, 0, 0L))
+#define ComboBox_SetEditSel(hwndCtl, ichStart, ichEnd) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEDITSEL, 0, MAKELPARAM((ichStart), (ichEnd))))
+
+#define ComboBox_GetCount(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_GETCOUNT, 0, 0L))
+#define ComboBox_ResetContent(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_RESETCONTENT, 0, 0L))
+
+#define ComboBox_AddString(hwndCtl, lpsz) ((int)(DWORD)SendMessage((hwndCtl), CB_ADDSTRING, 0, (LPARAM)(LPCSTR)(lpsz)))
+#define ComboBox_InsertString(hwndCtl, index, lpsz) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(LPCSTR)(lpsz)))
+
+#define ComboBox_AddItemData(hwndCtl, data) ((int)(DWORD)SendMessage((hwndCtl), CB_ADDSTRING, 0, (LPARAM)(data)))
+#define ComboBox_InsertItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_INSERTSTRING, (WPARAM)(int)(index), (LPARAM)(data)))
+
+#define ComboBox_DeleteString(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_DELETESTRING, (WPARAM)(int)(index), 0L))
+
+#define ComboBox_GetLBTextLen(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXTLEN, (WPARAM)(int)(index), 0L))
+#define ComboBox_GetLBText(hwndCtl, index, lpszBuffer) ((int)(DWORD)SendMessage((hwndCtl), CB_GETLBTEXT, (WPARAM)(int)(index), (LPARAM)(LPCSTR)(lpszBuffer)))
+
+#define ComboBox_GetItemData(hwndCtl, index) ((LRESULT)(DWORD)SendMessage((hwndCtl), CB_GETITEMDATA, (WPARAM)(int)(index), 0L))
+#define ComboBox_SetItemData(hwndCtl, index, data) ((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMDATA, (WPARAM)(int)(index), (LPARAM)(data)))
+
+#define ComboBox_FindString(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszFind)))
+#define ComboBox_FindItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
+
+#define ComboBox_GetCurSel(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_GETCURSEL, 0, 0L))
+#define ComboBox_SetCurSel(hwndCtl, index) ((int)(DWORD)SendMessage((hwndCtl), CB_SETCURSEL, (WPARAM)(int)(index), 0L))
+
+#define ComboBox_SelectString(hwndCtl, indexStart, lpszSelect) ((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszSelect)))
+#define ComboBox_SelectItemData(hwndCtl, indexStart, data) ((int)(DWORD)SendMessage((hwndCtl), CB_SELECTSTRING, (WPARAM)(int)(indexStart), (LPARAM)(data)))
+
+#define ComboBox_Dir(hwndCtl, attrs, lpszFileSpec) ((int)(DWORD)SendMessage((hwndCtl), CB_DIR, (WPARAM)(UINT)(attrs), (LPARAM)(LPCSTR)(lpszFileSpec)))
+
+#define ComboBox_ShowDropdown(hwndCtl, fShow) ((BOOL)(DWORD)SendMessage((hwndCtl), CB_SHOWDROPDOWN, (WPARAM)(BOOL)(fShow), 0L))
+
+#if (WINVER >= 0x030a)
+#define ComboBox_FindStringExact(hwndCtl, indexStart, lpszFind) ((int)(DWORD)SendMessage((hwndCtl), CB_FINDSTRINGEXACT, (WPARAM)(int)(indexStart), (LPARAM)(LPCSTR)(lpszFind)))
+
+#define ComboBox_GetDroppedState(hwndCtl) ((BOOL)(DWORD)SendMessage((hwndCtl), CB_GETDROPPEDSTATE, 0, 0L))
+#define ComboBox_GetDroppedControlRect(hwndCtl, lprc) ((void)SendMessage((hwndCtl), CB_GETDROPPEDCONTROLRECT, 0, (LPARAM)(RECT FAR*)(lprc)))
+
+#define ComboBox_GetItemHeight(hwndCtl) ((int)(DWORD)SendMessage((hwndCtl), CB_GETITEMHEIGHT, 0, 0L))
+#define ComboBox_SetItemHeight(hwndCtl, cyItem) ((int)(DWORD)SendMessage((hwndCtl), CB_SETITEMHEIGHT, (WPARAM)(int)(index), 0L))
+
+#define ComboBox_GetExtendedUI(hwndCtl) ((UINT)(DWORD)SendMessage((hwndCtl), CB_GETEXTENDEDUI, 0, 0L))
+#define ComboBox_SetExtendedUI(hwndCtl, flags) ((int)(DWORD)SendMessage((hwndCtl), CB_SETEXTENDEDUI, (WPARAM)(UINT)(flags), 0L))
+#endif /* WINVER >= 0x030a */
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#endif /* !_INC_WINDOWSX */
diff --git a/private/mvdm/wow16/inc/winexp.h b/private/mvdm/wow16/inc/winexp.h
new file mode 100644
index 000000000..672c8bb59
--- /dev/null
+++ b/private/mvdm/wow16/inc/winexp.h
@@ -0,0 +1,47 @@
+#ifndef NOATOM
+/* atom manager internals */
+#define ATOMSTRUC struct atomstruct
+typedef ATOMSTRUC *PATOM;
+typedef ATOMSTRUC {
+ PATOM chain;
+ WORD usage; /* Atoms are usage counted. */
+ BYTE len; /* length of ASCIZ name string */
+ BYTE name; /* beginning of ASCIZ name string */
+} ATOMENTRY;
+
+typedef struct {
+ int numEntries;
+ PATOM pAtom[ 1 ];
+} ATOMTABLE;
+ATOMTABLE * PASCAL pAtomTable;
+#endif
+
+LPSTR API lstrbscan(LPSTR, LPSTR);
+LPSTR API lstrbskip(LPSTR, LPSTR);
+
+int API OpenPathName(LPSTR, int);
+int API DeletePathName(LPSTR);
+WORD API _ldup(int);
+
+
+/* scheduler things that the world knows not */
+BOOL API WaitEvent( HANDLE );
+BOOL API PostEvent( HANDLE );
+BOOL API KillTask( HANDLE );
+
+/* print screen hooks */
+BOOL API SetPrtScHook(FARPROC);
+FARPROC API GetPrtScHook(void);
+
+
+/* scroll bar messages */
+#define SBM_SETPOS WM_USER+0
+#define SBM_GETPOS WM_USER+1
+#define SBM_SETRANGE WM_USER+2
+#define SBM_GETRANGE WM_USER+3
+#define SBM_ENABLE_ARROWS WM_USER+4
+
+/* module stuff */
+HANDLE API GetDSModule( WORD );
+HANDLE API GetDSInstance( WORD );
+
diff --git a/private/mvdm/wow16/inc/winnet.h b/private/mvdm/wow16/inc/winnet.h
new file mode 100644
index 000000000..cfa78729f
--- /dev/null
+++ b/private/mvdm/wow16/inc/winnet.h
@@ -0,0 +1,507 @@
+
+/*
+ * Windows/Network Interface
+ * Copyright (C) Microsoft 1989-1993
+ *
+ * Standard WINNET Driver Header File, spec version 3.10
+ */
+
+
+#ifndef _INC_WINNET
+#define _INC_WINNET /* #defined if windows.h has been included */
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+typedef WORD far * LPWORD;
+
+#ifndef API
+#define API WINAPI
+#endif
+
+
+/*
+ * SPOOLING - CONTROLLING JOBS
+ */
+
+#define WNJ_NULL_JOBID 0
+
+
+WORD API WNetOpenJob(LPSTR,LPSTR,WORD,LPINT);
+WORD API WNetCloseJob(WORD,LPINT,LPSTR);
+WORD API WNetWriteJob(HANDLE,LPSTR,LPINT);
+WORD API WNetAbortJob(WORD,LPSTR);
+WORD API WNetHoldJob(LPSTR,WORD);
+WORD API WNetReleaseJob(LPSTR,WORD);
+WORD API WNetCancelJob(LPSTR,WORD);
+WORD API WNetSetJobCopies(LPSTR,WORD,WORD);
+
+/*
+ * SPOOLING - QUEUE AND JOB INFO
+ */
+
+typedef struct _queuestruct {
+ WORD pqName;
+ WORD pqComment;
+ WORD pqStatus;
+ WORD pqJobcount;
+ WORD pqPrinters;
+} QUEUESTRUCT;
+
+typedef QUEUESTRUCT far * LPQUEUESTRUCT;
+
+#define WNPRQ_ACTIVE 0x0
+#define WNPRQ_PAUSE 0x1
+#define WNPRQ_ERROR 0x2
+#define WNPRQ_PENDING 0x3
+#define WNPRQ_PROBLEM 0x4
+
+
+typedef struct _jobstruct {
+ WORD pjId;
+ WORD pjUsername;
+ WORD pjParms;
+ WORD pjPosition;
+ WORD pjStatus;
+ DWORD pjSubmitted;
+ DWORD pjSize;
+ WORD pjCopies;
+ WORD pjComment;
+} JOBSTRUCT;
+
+typedef JOBSTRUCT far * LPJOBSTRUCT;
+
+#define WNPRJ_QSTATUS 0x0007
+#define WNPRJ_QS_QUEUED 0x0000
+#define WNPRJ_QS_PAUSED 0x0001
+#define WNPRJ_QS_SPOOLING 0x0002
+#define WNPRJ_QS_PRINTING 0x0003
+#define WNPRJ_DEVSTATUS 0x0FF8
+#define WNPRJ_DS_COMPLETE 0x0008
+#define WNPRJ_DS_INTERV 0x0010
+#define WNPRJ_DS_ERROR 0x0020
+#define WNPRJ_DS_DESTOFFLINE 0x0040
+#define WNPRJ_DS_DESTPAUSED 0x0080
+#define WNPRJ_DS_NOTIFY 0x0100
+#define WNPRJ_DS_DESTNOPAPER 0x0200
+#define WNPRJ_DS_DESTFORMCHG 0x0400
+#define WNPRJ_DS_DESTCRTCHG 0x0800
+#define WNPRJ_DS_DESTPENCHG 0x1000
+
+#define SP_QUEUECHANGED 0x0500
+
+
+WORD API WNetWatchQueue(HWND,LPSTR,LPSTR,WORD);
+WORD API WNetUnwatchQueue(LPSTR);
+WORD API WNetLockQueueData(LPSTR,LPSTR,LPQUEUESTRUCT FAR *);
+WORD API WNetUnlockQueueData(LPSTR);
+
+
+/*
+ * CONNECTIONS
+ */
+
+UINT API WNetAddConnection(LPSTR,LPSTR,LPSTR);
+UINT API WNetCancelConnection(LPSTR,BOOL);
+UINT API WNetGetConnection(LPSTR,LPSTR, UINT FAR *);
+UINT API WNetRestoreConnection(HWND,LPSTR);
+
+/*
+ * CAPABILITIES
+ */
+
+#define WNNC_SPEC_VERSION 0x0001
+
+#define WNNC_NET_TYPE 0x0002
+#define WNNC_NET_NONE 0x0000
+#define WNNC_NET_MSNet 0x0100
+#define WNNC_NET_LanMan 0x0200
+#define WNNC_NET_NetWare 0x0300
+#define WNNC_NET_Vines 0x0400
+#define WNNC_NET_10NET 0x0500
+#define WNNC_NET_Locus 0x0600
+#define WNNC_NET_Sun_PC_NFS 0x0700
+#define WNNC_NET_LANstep 0x0800
+#define WNNC_NET_9TILES 0x0900
+#define WNNC_NET_LANtastic 0x0A00
+#define WNNC_NET_AS400 0x0B00
+#define WNNC_NET_FTP_NFS 0x0C00
+#define WNNC_NET_PATHWORKS 0x0D00
+#define WNNC_NET_MultiNet 0x8000
+#define WNNC_SUBNET_NONE 0x0000
+#define WNNC_SUBNET_MSNet 0x0001
+#define WNNC_SUBNET_LanMan 0x0002
+#define WNNC_SUBNET_WinWorkgroups 0x0004
+#define WNNC_SUBNET_NetWare 0x0008
+#define WNNC_SUBNET_Vines 0x0010
+#define WNNC_SUBNET_Other 0x0080
+
+#define WNNC_DRIVER_VERSION 0x0003
+
+#define WNNC_USER 0x0004
+#define WNNC_USR_GetUser 0x0001
+
+#define WNNC_CONNECTION 0x0006
+#define WNNC_CON_AddConnection 0x0001
+#define WNNC_CON_CancelConnection 0x0002
+#define WNNC_CON_GetConnections 0x0004
+#define WNNC_CON_AutoConnect 0x0008
+#define WNNC_CON_BrowseDialog 0x0010
+#define WNNC_CON_RestoreConnection 0x0020
+
+#define WNNC_PRINTING 0x0007
+#define WNNC_PRT_OpenJob 0x0002
+#define WNNC_PRT_CloseJob 0x0004
+#define WNNC_PRT_HoldJob 0x0010
+#define WNNC_PRT_ReleaseJob 0x0020
+#define WNNC_PRT_CancelJob 0x0040
+#define WNNC_PRT_SetJobCopies 0x0080
+#define WNNC_PRT_WatchQueue 0x0100
+#define WNNC_PRT_UnwatchQueue 0x0200
+#define WNNC_PRT_LockQueueData 0x0400
+#define WNNC_PRT_UnlockQueueData 0x0800
+#define WNNC_PRT_ChangeMsg 0x1000
+#define WNNC_PRT_AbortJob 0x2000
+#define WNNC_PRT_NoArbitraryLock 0x4000
+#define WNNC_PRT_WriteJob 0x8000
+
+#define WNNC_DIALOG 0x0008
+#define WNNC_DLG_DeviceMode 0x0001
+#define WNNC_DLG_BrowseDialog 0x0002
+#define WNNC_DLG_ConnectDialog 0x0004
+#define WNNC_DLG_DisconnectDialog 0x0008
+#define WNNC_DLG_ViewQueueDialog 0x0010
+#define WNNC_DLG_PropertyDialog 0x0020
+#define WNNC_DLG_ConnectionDialog 0x0040
+#define WNNC_DLG_PrinterConnectDialog 0x0080
+#define WNNC_DLG_SharesDialog 0x0100
+#define WNNC_DLG_ShareAsDialog 0x0200
+
+
+#define WNNC_ADMIN 0x0009
+#define WNNC_ADM_GetDirectoryType 0x0001
+#define WNNC_ADM_DirectoryNotify 0x0002
+#define WNNC_ADM_LongNames 0x0004
+#define WNNC_ADM_SetDefaultDrive 0x0008
+
+#define WNNC_ERROR 0x000A
+#define WNNC_ERR_GetError 0x0001
+#define WNNC_ERR_GetErrorText 0x0002
+
+
+WORD API WNetGetCaps(WORD);
+
+/*
+ * OTHER
+ */
+
+WORD API WNetGetUser(LPSTR,LPINT);
+
+/*
+ * BROWSE DIALOG
+ */
+
+#define WNBD_CONN_UNKNOWN 0x0
+#define WNBD_CONN_DISKTREE 0x1
+#define WNBD_CONN_PRINTQ 0x3
+#define WNBD_MAX_LENGTH 0x80 // path length, includes the NULL
+
+#define WNTYPE_DRIVE 1
+#define WNTYPE_FILE 2
+#define WNTYPE_PRINTER 3
+#define WNTYPE_COMM 4
+
+#define WNPS_FILE 0
+#define WNPS_DIR 1
+#define WNPS_MULT 2
+
+WORD API WNetDeviceMode(HWND);
+WORD API WNetBrowseDialog(HWND,WORD,LPSTR);
+WORD API WNetConnectDialog(HWND,WORD);
+WORD API WNetDisconnectDialog(HWND,WORD);
+WORD API WNetConnectionDialog(HWND,WORD);
+WORD API WNetViewQueueDialog(HWND,LPSTR);
+WORD API WNetPropertyDialog(HWND hwndParent, WORD iButton, WORD nPropSel,
+ LPSTR lpszName, WORD nType);
+WORD API WNetGetPropertyText(WORD iButton, WORD nPropSel, LPSTR lpszName,
+ LPSTR lpszButtonName, WORD cbButtonName, WORD nType);
+
+/*
+ The following APIs are not exported from USER.EXE. They must be
+ loaded from the active network driver like this:
+
+ HINSTANCE hinstNetDriver;
+ LPWNETSERVERBROWSEDIALOG lpDialogAPI;
+
+ hinstNetDriver = (HINSTANCE)WNetGetCaps(0xFFFF);
+ if (hinstNetDriver == NULL) {
+ // no network driver loaded
+ }
+ else {
+ lpDialogAPI = (LPWNETSERVERBROWSEDIALOG)GetProcAddress(hinstNetDriver,
+ (LPSTR)ORD_WNETSERVERBROWSEDIALOG);
+
+ if (lpDialogAPI == NULL) {
+ // currently installed network doesn't support this API
+ }
+ else {
+ (*lpDialogAPI)(hwndParent, lpszSectionName, lpszBuffer, cbBuffer, 0L);
+ }
+ }
+*/
+
+typedef WORD (API *LPWNETSHAREASDIALOG)(HWND hwndParent, WORD iType,
+ LPSTR lpszPath);
+typedef WORD (API *LPWNETSTOPSHAREDIALOG)(HWND hwndParent, WORD iType,
+ LPSTR lpszPath);
+typedef WORD (API *LPWNETSETDEFAULTDRIVE)(WORD idriveDefault);
+typedef WORD (API *LPWNETGETSHARECOUNT)(WORD iType);
+typedef WORD (API *LPWNETGETSHARENAME)(LPSTR lpszPath, LPSTR lpszBuf,
+ WORD cbBuf);
+typedef WORD (API *LPWNETSERVERBROWSEDIALOG)(HWND hwndParent,
+ LPSTR lpszSectionName,
+ LPSTR lpszBuffer,
+ WORD cbBuffer,
+ DWORD flFlags);
+typedef WORD (API *LPWNETGETSHAREPATH)(LPSTR lpszName, LPSTR lpszBuf,
+ WORD cbBuf);
+typedef WORD (API *LPWNETGETLASTCONNECTION)(WORD iType, LPWORD lpwConnIndex);
+typedef WORD (API *LPWNETEXITCONFIRM)(HWND hwndOwner, WORD iExitType);
+
+typedef BOOL (API *LPI_AUTOLOGON)(HWND hwndOwner, LPSTR lpszReserved,
+ BOOL fPrompt, BOOL FAR *lpfLoggedOn);
+typedef BOOL (API *LPI_LOGOFF)(HWND hwndOwner, LPSTR lpszReserved);
+typedef VOID (API *LPI_CHANGEPASSWORD)(HWND hwndOwner);
+typedef VOID (API *LPI_CHANGECACHEPASSWORD)(HWND hwndOwner);
+typedef WORD (API *LPI_CONNECTDIALOG)(HWND hwndParent, WORD iType);
+typedef WORD (API *LPI_CONNECTIONDIALOG)(HWND hwndParent, WORD iType);
+
+
+typedef struct tagPASSWORD_CACHE_ENTRY {
+ WORD cbEntry;
+ WORD cbResource;
+ WORD cbPassword;
+ BYTE iEntry;
+ BYTE nType;
+ BYTE abResource[1]; /* resource name, cbResource bytes long */
+ /* password follows immediately after */
+} PASSWORD_CACHE_ENTRY;
+
+typedef PASSWORD_CACHE_ENTRY FAR *LPPASSWORD_CACHE_ENTRY;
+
+typedef WORD (API *LPWNETCACHEPASSWORD)(LPSTR pbResource, WORD cbResource,
+ LPSTR pbPassword, WORD cbPassword,
+ BYTE nType);
+
+typedef WORD (API *LPWNETGETCACHEDPASSWORD)(LPSTR pbResource, WORD cbResource,
+ LPSTR pbPassword, LPWORD pcbPassword,
+ BYTE nType);
+
+typedef WORD (API *LPWNETREMOVECACHEDPASSWORD)(LPSTR pbResource,
+ WORD cbResource,
+ BYTE nType);
+
+/*
+ Typedef for the callback routine passed to WNetEnumCachedPasswords.
+ It will be called once for each entry that matches the criteria
+ requested. It should return TRUE if it wants the enumeration to
+ continue, FALSE to stop.
+*/
+typedef BOOL (API *CACHECALLBACK)( LPPASSWORD_CACHE_ENTRY pce );
+
+
+typedef WORD (API *LPWNETENUMCACHEDPASSWORDS)(LPSTR pbPrefix, WORD cbPrefix,
+ BYTE nType,
+ CACHECALLBACK pfnCallback);
+
+/*
+ * Ordinals in the network driver for APIs not exported by USER.
+ */
+#define ORD_I_AUTOLOGON 530
+#define ORD_I_CHANGEPASSWORD 531
+#define ORD_I_LOGOFF 532
+#define ORD_I_CONNECTIONDIALOG 533
+#define ORD_I_CHANGECACHEPASSWORD 534
+#define ORD_I_CONNECTDIALOG 535
+#define ORD_WNETSHARESDIALOG 140
+#define ORD_WNETSHAREASDIALOG 141
+#define ORD_WNETSTOPSHAREDIALOG 142
+#define ORD_WNETSETDEFAULTDRIVE 143
+#define ORD_WNETGETSHARECOUNT 144
+#define ORD_WNETGETSHARENAME 145
+
+#define ORD_WNETSERVERBROWSEDIALOG 146
+
+#define ORD_WNETGETSHAREPATH 147
+
+#define ORD_WNETGETLASTCONNECTION 148
+
+#define ORD_WNETEXITCONFIRM 149
+
+#define ORD_WNETCACHEPASSWORD 150
+#define ORD_WNETGETCACHEDPASSWORD 151
+#define ORD_WNETREMOVECACHEDPASSWORD 152
+#define ORD_WNETENUMCACHEDPASSWORDS 153
+
+/*
+ * the following nType values are only for the purposes of enumerating
+ * entries from the cache. note that PCE_ALL is reserved and should not
+ * be the nType value for any entry.
+*/
+
+#define PCE_DOMAIN 0x01 /* entry is for a domain */
+#define PCE_SERVER 0x02 /* entry is for a server */
+#define PCE_UNC 0x03 /* entry is for a server/share combo */
+
+#define PCE_NOTMRU 0x80 /* bit set if entry is exempt from MRU aging */
+#define PCE_ALL 0xff /* retrieve all entries */
+
+
+/*
+ * Defines for iExitType on WNetExitConfirm
+ */
+#define EXIT_CONFIRM 0
+#define EXIT_EXITING 1
+#define EXIT_CANCELED 2
+
+/*
+ * ADMIN
+ */
+
+#define WNDT_NORMAL 0
+#define WNDT_NETWORK 1
+
+#define WNDN_MKDIR 1
+#define WNDN_RMDIR 2
+#define WNDN_MVDIR 3
+
+WORD API WNetGetDirectoryType(LPSTR,LPINT);
+WORD API WNetDirectoryNotify(HWND,LPSTR,WORD);
+
+/*
+ * ERRORS
+ */
+
+WORD API WNetGetError(LPINT);
+WORD API WNetGetErrorText(WORD,LPSTR,LPINT);
+
+
+/*
+ * STATUS CODES
+ */
+
+/* General */
+
+#define WN_SUCCESS 0x0000
+#define WN_NOT_SUPPORTED 0x0001
+#define WN_NET_ERROR 0x0002
+#define WN_MORE_DATA 0x0003
+#define WN_BAD_POINTER 0x0004
+#define WN_BAD_VALUE 0x0005
+#define WN_BAD_PASSWORD 0x0006
+#define WN_ACCESS_DENIED 0x0007
+#define WN_FUNCTION_BUSY 0x0008
+#define WN_WINDOWS_ERROR 0x0009
+#define WN_BAD_USER 0x000A
+#define WN_OUT_OF_MEMORY 0x000B
+#define WN_CANCEL 0x000C
+#define WN_CONTINUE 0x000D
+
+/* Connection */
+
+#define WN_NOT_CONNECTED 0x0030
+#define WN_OPEN_FILES 0x0031
+#define WN_BAD_NETNAME 0x0032
+#define WN_BAD_LOCALNAME 0x0033
+#define WN_ALREADY_CONNECTED 0x0034
+#define WN_DEVICE_ERROR 0x0035
+#define WN_CONNECTION_CLOSED 0x0036
+
+/* Printing */
+
+#define WN_BAD_JOBID 0x0040
+#define WN_JOB_NOT_FOUND 0x0041
+#define WN_JOB_NOT_HELD 0x0042
+#define WN_BAD_QUEUE 0x0043
+#define WN_BAD_FILE_HANDLE 0x0044
+#define WN_CANT_SET_COPIES 0x0045
+#define WN_ALREADY_LOCKED 0x0046
+
+#define WN_NO_ERROR 0x0050
+
+/* stuff in user, not driver, for shell apps ;Internal */
+WORD API WNetErrorText(WORD,LPSTR,WORD); /* ;Internal */
+
+#ifdef LFN
+
+/* this is the data structure returned from LFNFindFirst and
+ * LFNFindNext. The last field, achName, is variable length. The size
+ * of the name in that field is given by cchName, plus 1 for the zero
+ * terminator.
+ */
+typedef struct _filefindbuf2
+ {
+ WORD fdateCreation;
+ WORD ftimeCreation;
+ WORD fdateLastAccess;
+ WORD ftimeLastAccess;
+ WORD fdateLastWrite;
+ WORD ftimeLastWrite;
+ DWORD cbFile;
+ DWORD cbFileAlloc;
+ WORD attr;
+ DWORD cbList;
+ BYTE cchName;
+ BYTE achName[1];
+ } FILEFINDBUF2, FAR * PFILEFINDBUF2;
+
+typedef BOOL (API *PQUERYPROC)( void );
+
+WORD API LFNFindFirst(LPSTR,WORD,LPINT,LPINT,WORD,PFILEFINDBUF2);
+WORD API LFNFindNext(HANDLE,LPINT,WORD,PFILEFINDBUF2);
+WORD API LFNFindClose(HANDLE);
+WORD API LFNGetAttribute(LPSTR,LPINT);
+WORD API LFNSetAttribute(LPSTR,WORD);
+WORD API LFNCopy(LPSTR,LPSTR,PQUERYPROC);
+WORD API LFNMove(LPSTR,LPSTR);
+WORD API LFNDelete(LPSTR);
+WORD API LFNMKDir(LPSTR);
+WORD API LFNRMDir(LPSTR);
+WORD API LFNGetVolumeLabel(WORD,LPSTR);
+WORD API LFNSetVolumeLabel(WORD,LPSTR);
+WORD API LFNParse(LPSTR,LPSTR,LPSTR);
+WORD API LFNVolumeType(WORD,LPINT);
+
+/* return values from LFNParse
+ */
+#define FILE_83_CI 0
+#define FILE_83_CS 1
+#define FILE_LONG 2
+
+/* volumes types from LFNVolumeType
+ */
+#define VOLUME_STANDARD 0
+#define VOLUME_LONGNAMES 1
+
+// will add others later, == DOS int 21h error codes.
+
+// this error code causes a call to WNetGetError, WNetGetErrorText
+// to get the error text.
+#define ERROR_NETWORKSPECIFIC 0xFFFF
+
+#endif
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#endif /* _INC_WINDOWS */
diff --git a/private/mvdm/wow16/inc/winnls.h b/private/mvdm/wow16/inc/winnls.h
new file mode 100644
index 000000000..02ab30248
--- /dev/null
+++ b/private/mvdm/wow16/inc/winnls.h
@@ -0,0 +1,91 @@
+/***********************************************************************\
+* *
+* WINNLS.H - Far East input method editor (DBCS_IME) definitions *
+* *
+* History: *
+* 21-Oct-1991 bent *
+* initial merge of Far East 3.0 versions *
+* Should be updated to resolve local inconsistencies. *
+* *
+* Copyright (c) 1990 Microsoft Corporation *
+* *
+\***********************************************************************/
+
+typedef struct _tagDATETIME {
+ WORD year;
+ WORD month;
+ WORD day;
+ WORD hour;
+ WORD min;
+ WORD sec;
+} DATETIME;
+
+typedef struct _tagIMEPRO {
+ HWND hWnd;
+ DATETIME InstDate;
+ WORD wVersion;
+ BYTE szDescription[50];
+ BYTE szName[80];
+ BYTE szOptions[30];
+#ifdef TAIWAN
+ BYTE szUsrFontName[80];
+ BOOL fEnable;
+#endif
+} IMEPRO;
+typedef IMEPRO *PIMEPRO;
+typedef IMEPRO near *NPIMEPRO;
+typedef IMEPRO far *LPIMEPRO;
+
+void FAR PASCAL InquireWINNLS( void ); /* ;Internal */
+BOOL FAR PASCAL IMPGetIME( HWND, LPIMEPRO );
+BOOL FAR PASCAL IMPQueryIME( LPIMEPRO );
+BOOL FAR PASCAL IMPDeleteIME( LPIMEPRO );
+BOOL FAR PASCAL IMPAddIME( LPIMEPRO );
+BOOL FAR PASCAL IMPSetIME( HWND, LPIMEPRO );
+BOOL FAR PASCAL IMEModifyIME( LPSTR, LPIMEPRO ); /* ;Internal */
+WORD FAR PASCAL IMPGetDefaultIME( LPIMEPRO ); /* ;Internal */
+WORD FAR PASCAL IMPSetDefaultIME( LPIMEPRO ); /* ;Internal */
+BOOL FAR PASCAL WINNLSSetIMEHandle( LPSTR, HWND ); /* ;Internal */
+BOOL FAR PASCAL WINNLSSetIMEStatus( HWND, BOOL ); /* ;Internal */
+
+BOOL FAR PASCAL WINNLSEnableIME( HWND, BOOL );
+WORD FAR PASCAL WINNLSGetKeyState( void ); /* ;Internal */
+VOID FAR PASCAL WINNLSSetKeyState( WORD ); /* ;Internal */
+BOOL FAR PASCAL WINNLSGetEnableStatus( HWND );
+BOOL FAR PASCAL WINNLSSetKeyboardHook (BOOL); /* ;Internal */
+
+#ifdef KOREA
+BOOL FAR PASCAL WINNLSSetIMEHotkey( HWND, WORD, WORD );
+LONG FAR PASCAL WINNLSGetIMEHotkey( HWND );
+#else
+BOOL FAR PASCAL WINNLSSetIMEHotkey( HWND, WORD ); /* ;Internal */
+WORD FAR PASCAL WINNLSGetIMEHotkey( HWND );
+#endif //KOREA
+
+#ifdef TAIWAN
+typedef HANDLE HIME;
+
+/* Extended IME information*/
+typedef struct _tagIMEInfo {
+ BYTE szIMEName[7];
+ BYTE szPrompMessage[32];
+ WORD nMaxKeyLen;
+} IMEINFO;
+typedef IMEINFO far *LPIMEINFO;
+
+HWND FAR PASCAL WINNLSGetSysIME(void);
+void FAR PASCAL WINNLSSetSysIME(HWND);
+BOOL FAR PASCAL SwitchIM( WORD , WORD );
+BOOL ToNextIM(void);
+void SetFullAbcState(BOOL);
+BOOL EngChiSwitch(BOOL);
+void FAR PASCAL TimerProc(HWND,int,WORD,LONG);
+HWND FAR PASCAL IMPGetFullShapeHWnd(void);
+void FAR PASCAL IMPSetFullShapeHWnd(HWND);
+BOOL FAR PASCAL IMPSetFirstIME(HWND,LPIMEPRO);
+BOOL FAR PASCAL IMPGetFirstIME(HWND,LPIMEPRO);
+BOOL FAR PASCAL IMPDialogIME(LPIMEPRO,HWND);
+BOOL FAR PASCAL IMPEnableIME(HWND,LPIMEPRO,BOOL);
+BOOL FAR PASCAL IMPSetUsrFont(HWND,LPIMEPRO);
+BOOL FAR PASCAL WINNLSQueryIMEInfo(HWND,HWND,LPIMEINFO);
+#endif //TAIWAN
diff --git a/private/mvdm/wow16/inc/wmsyserr.h b/private/mvdm/wow16/inc/wmsyserr.h
new file mode 100644
index 000000000..086cd7a48
--- /dev/null
+++ b/private/mvdm/wow16/inc/wmsyserr.h
@@ -0,0 +1,37 @@
+/****************************************************************************/
+/* */
+/* WMSYSERR.H - */
+/* */
+/* Message Box String Defines */
+/* */
+/****************************************************************************/
+
+/* SysErrorBox() stuff */
+
+#define MAX_SEB_STYLES 7 /* number of SEB_* values */
+
+#define SEB_OK 1 /* Button with "OK". */
+#define SEB_CANCEL 2 /* Button with "Cancel" */
+#define SEB_YES 3 /* Button with "&Yes" */
+#define SEB_NO 4 /* Button with "&No" */
+#define SEB_RETRY 5 /* Button with "&Retry" */
+#define SEB_ABORT 6 /* Button with "&Abort" */
+#define SEB_IGNORE 7 /* Button with "&Ignore" */
+
+#define SEB_DEFBUTTON 0x8000 /* Mask to make this button default */
+
+#define SEB_BTN1 1 /* Button 1 was selected */
+#define SEB_BTN2 2 /* Button 1 was selected */
+#define SEB_BTN3 3 /* Button 1 was selected */
+
+/* SysErrorBox() button structure definition */
+
+typedef struct tagSEBBTN
+ {
+ unsigned int style;
+ BOOL finvert;
+ RECT rcbtn;
+ POINT pttext;
+ LPSTR psztext;
+ BYTE chaccel;
+ } SEBBTN;
diff --git a/private/mvdm/wow16/kernel31/2galloc.asm b/private/mvdm/wow16/kernel31/2galloc.asm
new file mode 100644
index 000000000..c8d4fa6e6
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2galloc.asm
@@ -0,0 +1,2441 @@
+ PAGE ,132
+ TITLE GALLOC - Global memory allocator
+
+.sall
+.xlist
+include kernel.inc
+include protect.inc
+.list
+
+.286p
+
+DataBegin
+
+externB Kernel_flags
+externB fCheckFree
+externW pGlobalHeap
+externW WinFlags
+
+gsearch_state_machine dw 0
+GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
+GA_MASK_BYTES = NOT GA_ALIGN_BYTES
+
+
+ifdef WOW
+externB fInAlloc
+externW SelectorFreeBlock
+endif
+
+public DpmiMemory, DpmiBlockCount
+DpmiMemory DpmiBlock NUM_DPMI_BLOCKS dup (<>)
+
+DpmiBlockCount dw 0
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP gcompact
+externNP gmovebusy
+externNP gmoveable
+externNP gslidecommon
+externNP galign
+
+externNP get_physical_address
+externNP set_physical_address
+externNP alloc_data_sel
+externNP set_sel_limit
+externNP free_sel
+externNP get_blotto
+externNP cmp_sel_address
+externNP alloc_data_sel_above
+externNP PreallocSel
+externNP DPMIProc
+ifdef WOW
+externNP alloc_special_sel
+endif
+
+;-----------------------------------------------------------------------;
+; gsearch ;
+; ;
+; Searches from start to finish for a free global object to allocate ;
+; space from. For a fixed request it tries to get the space as low as ;
+; possible, moving movable out of the way if neccessary. For movable ;
+; requests it also starts at the bottom. For discardable code it ;
+; starts from the top, only using the first free block it finds. ;
+; If at first blush it can't find a block it compacts memory and tries ;
+; again. ;
+; When it finally finds a block it gsplices it in, makes sure the ;
+; arena headers are fine, and returns the allocated block. ;
+; Called from within the global memory manager's critical section. ;
+; ;
+; Arguments: ;
+; AX = allocations flags ;
+; BX = #paras ;
+; CX = owner field value ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; AX = data address of block allocated or NULL ;
+; BX = ga_prev or ga_next ;
+; DX = allocation flags ;
+; ;
+; Error Returns: ;
+; ZF = 1 ;
+; AX = 0 ;
+; BX = ga_prev or ga_next ;
+; DX = size of largest free block ;
+; ;
+; Registers Preserved: ;
+; DI,DS ;
+; ;
+; Registers Destroyed: ;
+; CX,SI,ES ;
+; ;
+; Calls: ;
+; galign ;
+; gfindfree ;
+; fmovebusy ;
+; gcheckfree ;
+; gcompact ;
+; gsplice ;
+; gzero ;
+; gmarkfree ;
+; use_EMS_land ;
+; use_lower_land ;
+; ;
+; History: ;
+; ;
+; Wed Jul 22, 1987 11:15:19p -by- David N. Weise [davidw] ;
+; Fixed BOGUS BLOCK freeing yet again. ;
+; ;
+; Sun May 10, 1987 11:29:38p -by- David N. Weise [davidw] ;
+; Added the state machine to handle the case of wanting to search ;
+; both global arenas. ;
+; ;
+; Sat Feb 28, 1987 06:31:11p -by- David N. Weise [davidw] ;
+; Putting in support for allocating discardable code from EEMS land. ;
+; ;
+; Tue Dec 30, 1986 01:54:50p -by- David N. Weise [davidw] ;
+; Made sure it freed any bogus blocks created. ;
+; ;
+; Thu Nov 20, 1986 04:00:06p -by- David N. Weise [davidw] ;
+; Rewrote it use the global free list. Also made it put fixed requests ;
+; as low as possible and to search again after a compact. ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Tue Sep 23, 1986 04:35:39p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gsearch,<PUBLIC,NEAR>
+cBegin nogen
+
+ SetKernelDS
+ mov gsearch_state_machine,codeOFFSET grow_heap
+
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+
+look_again:
+ push bx ; Save requested size
+ push cx ; Save owner
+ push ax ; Save flags
+ add bx,1 ; Room for header (set flags for galign)
+ call galign ; Get requested size in DX
+ push dx ; Save adjusted requested size
+
+ inc dx ; Fail quickly if asking for
+ jnz @f ; too much memory
+ jmp gsearch_fail
+@@:
+ dec dx
+
+; see if there is any one free space large enough for the request first
+
+ mov si,dx
+ dec si ; Room for header
+ mov cx,[di].gi_free_count
+ jcxz were_hosed_from_start
+ mov es,[di].hi_first
+is_there_one:
+ mov es,es:[di].ga_freenext
+ cmp si,es:[di].ga_size
+ jbe short got_one
+ loop is_there_one
+were_hosed_from_start:
+ jmp space_not_found
+
+got_one:
+ mov bx,ga_prev ; search backwards
+ test al,GA_ALLOCHIGH
+ jz short alloc_low
+
+;------ allocate disc code -------
+
+ public alloc_high
+alloc_high:
+
+ mov cx,[di].gi_free_count
+ mov es,[di].hi_last ; Start with last entry.
+alloc_high_loop:
+ mov es,es:[di].ga_freeprev
+ cmp si,es:[di].ga_size
+ ja short loop_it
+ jmp afound ; Yes, exit search loop
+loop_it:
+ loop alloc_high_loop
+were_hosed:
+ jmps space_not_found
+
+;------ allocate moveable ---------
+
+ public alloc_low
+alloc_low:
+ mov bl,ga_next ; Search forwards.
+ test al,GA_MOVEABLE
+ jz short alloc_fixed
+ call gcheckfree ; Room for requested size?
+ jb short were_hosed
+ jmp afound
+
+;------ allocate fixed ------------
+
+ public alloc_fixed
+alloc_fixed:
+ mov es,[di].hi_first ; Start with first entry.
+ mov cx,[di].hi_count
+ mov es,es:[bx] ; Skip first sentinel
+alloc_fixed_loop:
+ push cx
+ push es
+ call is_there_theoretically_enough_space
+ cmp ax,dx
+ jb short nope
+ pop es
+ pop cx
+ call can_we_clear_this_space
+ jz short anext1
+ call gcheckfree ; Yes, room for requested size?
+ jb short anext1
+ ; Now we have enough free space,
+ ; slide it back as far as possible.
+ push ax ; This is to prevent us blocking
+ push dx ; the growth of moveable blocks.
+
+keep_sliding:
+ push es
+ mov es,es:[di].ga_prev
+ mov ax,es
+ mov dx,es:[di].ga_size
+ call gmoveable ; Is previous block moveable?
+ pop es
+ jz short no_slide
+
+ call PreallocSel
+ jz no_slide
+ push bx
+ mov bx, ga_prev ; Sliding backwards
+ push es ; gslide will invalidate this block
+ call gslidecommon ; C - calling convention
+ call free_sel ; free the pushed selector
+ pop bx
+ jmps keep_sliding
+
+no_slide:
+ pop dx ; requested size
+ pop ax ; block size
+ pop si ; adjusted requested size
+ pop cx ; flags
+
+ push cx ; these two expected on stack later
+ push si
+
+ test ch,GA_ALLOC_DOS ;If this is a DOS land alloc
+ jz okey_dokey ; make sure that the block
+ push ax ; we found is below the 1 meg
+ push dx ; boundry, or fail the request
+ cCall get_physical_address,<es>
+ cmp dx,0010h ; (0010:0000 = 1024k = 1 meg)
+ pop dx
+ pop ax
+ jae space_not_found
+
+okey_dokey:
+ jmp afound
+
+nope: or ax,ax
+ jz short hosed_again
+anext: pop si ; get rid of CX, ES on the stack
+ pop si
+anext1: mov es,es:[bx]
+ loop alloc_fixed_loop
+ jmps and_again
+
+hosed_again:
+ pop es
+ pop cx
+and_again:
+
+; no one space big enough, try compacting
+
+ public space_not_found
+space_not_found:
+ pop dx ; get size
+ pop ax ; get flags
+ push ax
+ push dx
+
+ test al,GA_ALLOCHIGH
+ jnz short ask_for_what_we_need
+ add dx,0400h ; ask for 16k more
+ jnc short ask_for_what_we_need ; no overflow
+ mov dx,-1
+
+ask_for_what_we_need:
+ SetKernelDS
+ push gsearch_state_machine
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ retn
+
+;------------------------------
+
+public do_compact ; for debugging
+
+do_compact:
+ call gcompact
+ SetKernelDS
+ mov gsearch_state_machine,codeOFFSET gsearch_fail
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+
+over_compact:
+ pop dx
+ pop ax
+ pop cx
+ pop bx
+ jmp look_again
+
+;------------------------------
+
+public grow_heap ; for debugging
+
+grow_heap:
+ SetKernelDS
+ mov gsearch_state_machine,codeOFFSET do_compact
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ call GrowHeap
+ jmp over_compact
+
+;------------------------------
+
+public gsearch_fail ; for debugging
+
+gsearch_fail: ; get size of largest free block
+ xor dx,dx
+ mov cx,[di].gi_free_count
+ jcxz gs_failure
+ mov es,[di].hi_first
+largest_loop:
+ mov es,es:[di].ga_freenext
+ mov ax,es:[di].ga_size
+ cmp dx,ax
+ jae short new_smaller
+ mov dx,ax
+new_smaller:
+ loop largest_loop
+gs_failure:
+ pop ax ; adjusted requested size
+ pop ax ; AX = flags
+
+ pop cx ; CX = owner field
+ pop ax ; waste requested size
+ xor ax,ax ; Return zero, with ZF = 1
+ ret
+
+; Here when we have a block big enough.
+; ES:DI = address of block
+; AX = size of block, including header
+; DX = requested size, including header
+; BX = ga_prev if backwards search and ga_next if forwards search
+
+afound:
+
+ifdef WOW ; Optimized path for WOW
+
+ push ds
+ SetkernelDS
+ cmp fInAlloc, 1
+ UnSetKernelDS
+ pop ds
+
+ jne nothing_special
+
+aallocsels:
+ pop cx ; adjusted requested size
+ pop ax ; get the flags
+
+ push ax ; restore the stack
+ push cx
+
+ push ax ; allocation flags
+ push es ; Selector FreeBlock
+ mov ax, es:[di].ga_size
+ push ax ; actual size of freeblock
+ inc ax
+ mov cx, ax ; save in cx too
+ sub cx, dx
+ push cx ; size new freeblock
+ push dx ; adjusted size
+ push bx ; bl = ga_prev pr ga_next
+ call alloc_special_sel
+ jz gs_failure ; no selector
+ jmps no_sel_wanted
+
+nothing_special:
+
+endif ; End Optimized path for WOW
+
+ mov ax,es:[di].ga_size ; Use actual size of free block
+ inc ax
+ mov cx,ax ; See how much extra space there is
+ sub cx,dx ; (found size - requested size)
+ jcxz no_sel_wanted
+ call PreallocSel ; Make sure we can splice
+ jz gs_failure ; no selector
+no_sel_wanted:
+ mov ax,es:[di].ga_freeprev
+ xor si,si ; Assume nothing extra to free
+ call gdel_free ; remove the alloc block from freelist
+if KDEBUG
+ push ds
+ SetKernelDS
+ cmp fCheckFree,0
+ pop ds
+ UnSetKernelDS
+ jnz short not_during_boot
+ call check_this_space
+not_during_boot:
+endif
+ jcxz aexit ; No, continue
+ cmp bl,ga_prev ; Yes, scanning forwards or backwards?
+ je short abackward ; Backwards.
+; mov si,es ; Forwards. Put extra space at end of
+ mov si,dx ; free block
+ call gsplice ; ES:DI = block we are allocating
+ jmps aexit ; SI = block to mark as free
+abackward:
+ mov si,es:[di].ga_size ; Scanning backwards. Put extra space
+ sub si,dx ; at beginning of free block.
+ inc si
+ call gsplice
+ mov es,si ; ES:DI = block we are allocating
+ mov si,es:[di].ga_prev ; SI = block to mark as free
+
+; Here with allocated block
+; AX = data address or zero if nothing allocated
+; ES:DI = address of block to mark as busy and zero init if requested
+; SI = address of block to mark as free
+
+aexit:
+ pop dx ; waste adjusted requested size
+ pop dx ; Restore flags
+ pop es:[di].ga_owner ; Mark block as busy with owner field value
+ pop cx ; waste requested size
+ mov es:[di].ga_lruprev,di
+ mov es:[di].ga_lrunext,di
+ push ax ; previous free block
+ mov al,GA_SEGTYPE
+ and al,dl
+ test dh,GAH_NOTIFY
+ jz short no_notify
+ or al,GAH_NOTIFY
+no_notify:
+ mov es:[di].ga_flags,al ; Store segment type bits
+
+ mov ax,es ; AX = address of client data
+
+ test dl,GA_ZEROINIT ; Want it zeroed?
+ jz short aexit1 ; No, all done
+
+ push ax
+ cCall get_blotto
+ mov cx,es:[di].ga_size ; Yes, zero paragraphs
+; dec cx ; to end of this block
+ push bx
+ mov bx,ax ; from beginning of client data
+ call gzero ; zero them
+ pop bx
+ pop ax
+aexit1:
+ mov es,si ; Free any extra space
+ pop si ; previous free block
+ dec si ; make it RING 0 for gmarkfree
+ call gmarkfree
+
+ or ax,ax
+ ret ; Return AX points to client portion
+ ; of block allocated.
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; is_there_theoretically_enough_space
+;
+; Starting at the given arena checks to see if there are enough
+; continuous free and unlocked moveable blocks.
+;
+; Entry:
+; CX = arenas to search
+; DX = size requested
+; DS = BurgerMaster
+; ES:DI = arena to start from
+;
+; Returns:
+; AX = 0 => not enough space and no more memory left to search
+; AX = 1 => not enough space in this block, but maybe....
+; otherwise
+; AX = size of block
+;
+; Registers Destroyed:
+; CX,SI
+;
+; Registers Preserved:
+; BX,DX,DI,ES
+;
+; History:
+; Mon 05-Sep-1988 15:21:14 -by- David N. Weise [davidw]
+; Moved it here from gsearch so that grealloc could use it as well.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc is_there_theoretically_enough_space,<PUBLIC,NEAR>
+cBegin nogen
+
+ xor ax,ax
+ittes:
+ cmp es:[di].ga_owner,di
+ jne short is_it_moveable
+ add ax,es:[di].ga_size
+ push bx
+ push cx
+ push ax
+ push dx
+ mov cx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
+ mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
+ cCall get_physical_address,<es:[di].ga_next>
+ sub bx,ax
+ sbb cx,dx ; used as cmp ONLY CARRY is VALID
+ pop dx
+ pop ax
+ jb short ittes_above_fence ; All below fence?
+ pop cx
+ pop bx
+ jmps this_ones_free
+ittes_above_fence:
+ REPT 4
+ shr cx,1
+ rcr bx,1
+ ENDM
+ add ax,bx ; No, Reduce apparent size of free block
+ pop cx
+ pop bx
+ inc ax
+ cmp ax,dx
+ jae short theoretically_enough
+ jmps absolutely_not
+is_it_moveable:
+ test es:[di].ga_flags,GA_DISCCODE
+ jnz short absolutely_not
+ test es:[di].ga_handle,GA_FIXED ; See if movable.
+ jnz short theoretically_not
+ cmp es:[di].ga_count,0
+ jne short theoretically_not ; See if locked.
+ add ax,es:[di].ga_size
+this_ones_free:
+ inc ax
+ cmp ax,dx
+ jae short theoretically_enough
+ mov es,es:[ga_next]
+ loop ittes
+
+; For the case of gsearch we should never get here for two reasons.
+; 1) It should be impossible to have no discardable code loaded, in
+; this case we would have failed in the above loop. 2) We checked
+; at the very start for a free block somewhere that could have
+; satisfied the request. In our mucking around to load as low as
+; possible we destroyed this free block and we did not produce a free
+; block we could use. However we know from debugging code in 2.03
+; that this happens extremely rarely. Because of the rareness of
+; this event we will not try to recover, instead we simply fail the call.
+
+absolutely_not:
+ mov ax,-1 ; return AX = 0
+theoretically_not:
+ inc ax ; DX is even, => cmp the same.
+theoretically_enough:
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; can_we_clear_this_space
+;
+; Attempts to make a free space starting at the address moved in.
+; To do this it moves moveable out of the area. The only subtlety
+; involves a free block that stradles the end of wanted area. This
+; may get broken into two pieces, the lower piece gets temporary marked
+; as allocated and BOGUS, the upper piece will remain free.
+;
+; Entry:
+; CX = max number of blocks to look at
+; DX = size wanted in paragraphs
+; DS = BurgerMaster
+; ES:DI = beginning arena
+;
+; Returns:
+; ZF = 0
+; ES:DI points to free space
+; ZF = 1
+; couldn't free the space up
+;
+; Registers Destroyed:
+; AX,SI
+;
+; History:
+; Mon 05-Sep-1988 16:48:31 -by- David N. Weise [davidw]
+; Moved it out of gsearch so that grealloc could use it.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc can_we_clear_this_space,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ push es
+ mov ax, es ; Beginning of space we want.
+ cmp di,es:[di].ga_owner ; Is it free?
+ jnz short can_we_move_it
+ mov cx,dx
+ dec cx
+ cmp cx,es:[di].ga_size
+ ja short asdf
+ or ax,ax ; return ZF = 0
+ pop es
+ pop cx
+ ret
+
+asdf: mov es,es:[di].ga_next
+
+ public can_we_move_it
+can_we_move_it:
+ push bx
+ push cx
+ push dx
+ push es
+ cmp es:[di].ga_owner,GA_BOGUS_BLOCK
+ jnz short not_bogus
+ xor si,si
+ call gmarkfree
+ jmp restart
+not_bogus:
+ push ax
+ cCall alloc_data_sel_above,<ax,dx>
+ mov si, ax ; End of space we want.
+ pop ax
+ or si, si
+ jnz got_marker_sel
+ pop cx ; Trash es saved on stack
+ jmp no_clear
+got_marker_sel:
+ mov cx,[di].gi_free_count
+ jcxz forget_it ; Nothing is free, so don't bother
+ mov dx,es:[di].ga_size ; Yes, try to find a place for the
+ mov es,[di].hi_first ; moveable block
+look_loop:
+ mov es,es:[di].ga_freenext
+ mov bx,es
+ cCall cmp_sel_address,<bx,ax> ; It defeats our purpose to move the
+ jb short check_this_out ; block to a free space we want.
+ cCall cmp_sel_address,<bx,si>
+ jb short is_there_hope
+check_this_out:
+ push ax
+ call gcheckfree
+ push cx
+ jb short inopportune_free_space
+ cCall free_sel,<si>
+ pop cx
+ pop ax
+
+ pop si ; SI = moveable block for gmovebusy
+ mov bx,ga_next
+ call gmovebusy ; Move moveable block out of the way
+ pop dx
+ pop cx
+ pop bx
+ pop cx ; WAS pop es but es destroyed below
+ pop cx
+ mov es,si ; Replace the ES on the stack,
+ ; the free block may have grown
+ ; downward with the gmovebusy.
+ jmp can_we_clear_this_space
+
+inopportune_free_space:
+ pop cx
+ pop ax
+ loop look_loop
+forget_it:
+ jmp couldnt_clear_it
+
+ public is_there_hope
+is_there_hope:
+ push ax
+ push cx
+ push dx
+ cCall get_physical_address,<es:[di].ga_next>
+ mov cx, dx
+ mov bx, ax
+ cmp cx, [di].gi_disfence_hi
+ jb below_reserved
+ ja above_reserved
+ cmp bx, [di].gi_disfence_lo
+ jbe short below_reserved
+above_reserved:
+ mov cx, [di].gi_disfence_hi
+ mov bx, [di].gi_disfence_lo
+
+below_reserved:
+ cCall get_physical_address,<si>
+ sub bx, ax
+ sbb cx, dx ; Check the overlap.
+
+ jae short overlap
+ pop dx
+ jmps inopportune_free_space
+overlap:
+REPT 4
+ shr cx, 1
+ rcr bx, 1
+ENDM
+ mov cx, dx
+ pop dx
+ cmp bx,dx
+ jbe short inopportune_free_space
+
+ mov bx, ax
+ cCall get_physical_address,<es>
+ sub bx, ax
+ sbb cx, dx
+REPT 4
+ shr cx, 1
+ rcr bx, 1
+ENDM
+ cCall free_sel,<si>
+ mov si, bx
+ pop cx
+ pop ax
+
+; cut off the first piece for the original alloc
+
+ push es:[di].ga_freeprev
+ call gdel_free
+if KDEBUG
+ push ds
+ SetKernelDS
+ cmp fCheckFree,0
+ pop ds
+ UnSetKernelDS
+ jnz short not_during_boot_1
+ call check_this_space
+not_during_boot_1:
+endif
+ call gsplice
+
+; ES:DI = addr of block to mark as busy, SI = addr of block to mark as free
+
+ mov es:[di].ga_owner,GA_BOGUS_BLOCK
+ mov es:[di].ga_lruprev,di
+ mov es:[di].ga_lrunext,di
+ mov es,si ; Free any extra space
+ pop si ; previous free block
+ dec si ; make it RING 0 for gmarkfree
+ call gmarkfree
+restart:
+ pop dx ; WAS pop es
+ pop dx
+ pop cx
+ pop bx
+ pop es
+ pop cx
+ jmp can_we_clear_this_space
+
+; If here then failure! see if we made a bogus block!
+
+couldnt_clear_it:
+ pop es ; recover block we wanted moved
+check_again:
+ mov dx,es:[di].ga_next
+ cCall cmp_sel_address,<dx,si> ; SI points to where bogus block
+ ja short no_bogus_block ; would be.
+ je short is_it_bogus
+ mov es,dx
+ cmp dx, es:[di].ga_next
+ je short no_bogus_block
+ jmp check_again
+is_it_bogus:
+ cmp es:[di].ga_owner,GA_BOGUS_BLOCK
+ jnz short no_bogus_block
+ push si
+ xor si,si
+ call gmarkfree
+ pop si
+no_bogus_block:
+
+if KDEBUG
+ mov cx,[di].hi_count
+ mov es,[di].hi_first
+bogus_all:
+ cmp es:[di].ga_owner,GA_BOGUS_BLOCK
+ jnz short not_me
+ INT3_ANCIENT
+not_me: mov es,es:[di].ga_next
+ loop bogus_all
+endif
+ cCall free_sel,<si>
+
+no_clear:
+ pop dx
+ pop cx
+ pop bx
+ pop es
+ pop cx
+ xor ax,ax ; return ZF = 1
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfindfree ;
+; ;
+; Searches for a free block that is big enough but does not encroach ;
+; on the area reserved for code swapping. ;
+; ;
+; Arguments: ;
+; ES:DI = address of existing block to start looking at ;
+; CX = #arena entries left to look at ;
+; BX = direction of search, ga_next or ga_prev ;
+; DX = #paragraphs needed ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; AX = address of free block that is big enough ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; gcheckfree ;
+; ;
+; History: ;
+; ;
+; Wed Sep 24, 1986 10:16:38p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gfindfree,<PUBLIC,NEAR>
+cBegin nogen
+ push cx
+ push es
+gffloop:
+ cmp es:[di].ga_owner,di ; Free block?
+ jne short gffnext ; No, continue
+ call gcheckfree ; Yes, is it big enough?
+ mov ax,es
+ jae short gffexit ; Yes, return
+gffnext:
+ mov es,es:[bx] ; next or previous block
+ loop gffloop
+gfffail:
+ xor ax,ax ; No, return zero in AX
+gffexit:
+ pop es
+ pop cx
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gcheckfree ;
+; ;
+; Checks the size of the passed free block against the passed desired ;
+; size, making sure that the limitations of the code reserve area are ;
+; not violated for objects other than discardable code. It also checks ;
+; for Phantoms. ;
+; ;
+; Arguments: ;
+; ES:DI = address of free block ;
+; DX = #paragraphs needed ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; CF = 0 block big enough ;
+; AX = apparent size of free block ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Thu 27-Apr-1989 10:38:05 -by- David N. Weise [davidw] ;
+; Fixed this to work in pmode. ;
+; ;
+; Thu Apr 02, 1987 10:45:22p -by- David N. Weise [davidw] ;
+; Added Phantom support. ;
+; ;
+; Tue Sep 23, 1986 05:54:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gcheckfree,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ mov ax,es:[di].ga_size ; Compute size of free block
+ inc ax
+ test byte ptr [di].gi_cmpflags,GA_DISCCODE
+ jnz short gcftest ; Discardable code not restricted
+
+; Due to recent changes in the way disccode is allocated, we must make
+; sure that non-disccode in never allocated above a disccode block.
+
+ push es
+might_be_code_below:
+ mov es,es:[di].ga_prev
+ cmp es:[di].ga_owner,GA_NOT_THERE
+ jz short might_be_code_below
+ cmp es:[di].ga_owner,di ; Free block?
+ jz short might_be_code_below
+ test es:[di].ga_flags,GA_DISCCODE
+ pop es
+ jnz short gcfrsrv1
+
+ push bx
+ push cx
+ push ax
+ push dx
+ mov cx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
+ mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
+ cCall get_physical_address,<es:[di].ga_next>
+ sub bx,ax
+ sbb cx,dx ; used as cmp ONLY CARRYY is VALID
+ pop dx
+ pop ax
+ jae short gcftest1 ; Yes, return actual size of free block
+ REPT 4
+ shr cx,1
+ rcr bx,1
+ ENDM
+ neg bx
+ sub ax,bx ; No, Reduce apparent size of free block
+ ja short gcftest1 ; Is it more than what is free?
+
+ xor ax,ax ; Yes, then apparent size is zero
+ ; Nothing left, set apparent size to 0
+gcftest1:
+ pop cx
+ pop bx
+ jmps gcftest
+gcfrsrv1: ; Yes, then apparent size is zero
+ xor ax,ax ; Nothing left, set apparent size to 0
+gcftest:
+ cmp ax,dx ; Return results of the comparison
+ pop si
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gsplice ;
+; ;
+; Splits one block into two. ;
+; ;
+; Arguments: ;
+; SI = size in paragraphs of new block to make ;
+; ES:DI = address of existing block ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; SI = address of new block ;
+; ;
+; Error Returns: ;
+; nothing ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,DI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Tue Sep 23, 1986 03:50:30p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gsplice,<PUBLIC,NEAR>
+cBegin nogen
+
+ push bx
+ push dx
+ mov dx,si ; save size
+ mov bx,es:[di].ga_size
+ sub bx,dx ; get size of 2nd new block made
+
+ push ax
+ push bx
+ push dx
+
+ifdef WOW ; Optimized path for WOW
+
+ push ds
+ SetkernelDS
+ mov ax, SelectorFreeBlock ; same as fInAlloc == 1
+ or ax, ax
+ UnSetKernelDS
+ pop ds
+ jnz gsplice_oldpath2
+
+gsplice_oldpath:
+endif ; end optimized path for WOW
+
+ mov bx,si
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+ cCall get_physical_address,<es>
+ add ax,bx
+ adc dx,cx
+ cCall alloc_data_sel,<dx,ax,1>
+
+ifdef WOW
+gsplice_oldpath2:
+endif
+ mov si,ax
+ pop dx
+ pop bx
+ pop ax
+ inc [di].hi_count ; Adding new arena entry
+ push si ; save new
+ push es ; save old
+ mov cx,si ; save old.next
+ xchg es:[di].ga_next,cx ; and old.next = new
+ mov es,cx
+ mov es:[di].ga_prev,si ; [old old.next].prev = new
+ mov es,si
+ mov es:[di].ga_next,cx ; new.next = old old.next
+ mov es:[di].ga_size,bx
+ pop cx ; new.prev = old
+ mov es:[di].ga_sig,GA_SIGNATURE
+ mov es:[di].ga_owner,di ; Zero owner & handle fields
+ mov es:[di].ga_flags,0 ; For good measure.
+ mov es:[di].ga_prev,cx
+ mov es:[di].ga_handle,di
+ mov es,cx ; ES = old
+ dec dx ; get size of 1st block made
+ mov es:[di].ga_size,dx
+ pop si ; restore new
+ pop dx
+ pop bx
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; gjoin ;
+; ;
+; Merges a block into his previous neighbor. ;
+; ;
+; Arguments: ;
+; ES:DI = address of block to remove ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; nothing ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; gdel_free ;
+; ;
+; History: ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Tue Sep 23, 1986 03:58:00p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gjoin,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ push bx
+ dec [di].hi_count
+ call gdel_free
+ mov ax,es:[di].ga_size
+ mov si,es:[di].ga_prev ; who points to this block
+ mov es,es:[di].ga_next ; Get address of block after
+if KDEBUG
+ mov bx, es
+ cmp bx, es:[di].ga_prev
+ jne short ok
+ INT3_FATAL
+ok:
+endif
+ cCall free_sel,<es:[di].ga_prev> ; Free selector being removed
+ mov es:[di].ga_prev,si ; one we are removing.
+ push es ; Change it's back link
+ mov es,si
+ pop es:[di].ga_next ; and change the forward link
+ inc ax ; Recompute size of block
+ add es:[di].ga_size,ax
+ pop bx
+ pop ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gzero ;
+; ;
+; Fills the given area with zeros. ;
+; ;
+; Arguments: ;
+; BX = address of first paragraph ;
+; CX = address of last paragraph ;
+; ;
+; Returns: ;
+; BX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 23, 1986 04:08:55p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gzero,<PUBLIC,NEAR>
+cBegin nogen
+
+; Assumptions: on entry, BX contains selector to start of block, and is
+; for a scratch descriptor that can be modified. CX contains the # of
+; paragraphs to be zeroed.
+
+ push es ; Determine if we're running on an
+ SetKernelDS es ; 80286. If so, we gotta worry
+ test es:WinFlags,WF_CPU286 ; about 64k segments.
+ jz its_a_386
+
+ UnSetKernelDS es ; removes addressibility from es
+
+ push ax
+ push bx
+ push cx
+ push dx
+ push di
+
+ cld
+ mov es,bx ; address block with es
+ mov bx,cx ; bx = total # paras to zero
+ jcxz gzexit ; just in case...
+
+ push bx ; Say it ain't so, Joe...
+ xor cx,cx ; force the incoming sel/descriptor to
+ mov bx,cx ; a limit of 64k - it might be higher
+ inc cx ; which would cause set_physical_adr
+ cCall set_sel_limit,<es> ; to destroy following descriptors.
+ pop bx
+
+ jmp short gz_doit
+
+next_64k:
+ push es
+ cCall get_physical_address,<es> ;update selector to next
+ inc dl ; 64k block
+ cCall set_physical_address,<es>
+ pop es ;reload it with new base
+
+gz_doit:
+ mov cx,1000h ; 1000h paras = 64k bytes
+ cmp bx,cx
+ jae @f
+ mov cx,bx ; less than 64k left
+@@:
+ sub bx,cx ; bx = # paras left to do
+ shl cx,3 ; cx = # words to zero this time
+ xor ax,ax
+ mov di,ax
+ rep stosw
+
+ or bx,bx ; more to do?
+ jnz short next_64k ; go do the next block
+
+gzexit:
+ pop di
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ pop es
+ ret
+
+; The CPU is an 80386 or better, zero the memory a faster way...
+
+its_a_386:
+
+ .386
+
+ push eax
+ push edi
+ push ecx
+
+ movzx ecx, cx
+ shl ecx, 2 ; # dwords to clear
+ mov es, bx
+ xor eax, eax
+ xor edi, edi
+
+ cld
+ rep stos dword ptr es:[edi]
+
+ pop ecx
+ pop edi
+ pop eax
+ pop es
+ ret
+
+ .286p
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmarkfree ;
+; ;
+; Marks a block as free, coalesceing it with any free blocks before ;
+; or after it. This does not free any handles. ;
+; ;
+; Arguments: ;
+; SI = the first free object before this one ;
+; 0 if unknown ;
+; Ring 1 if no free list update wanted ;
+; Ring 0 if free list update required ;
+; ES:DI = block to mark as free. ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; ZF = 1 if freed a fixed block ;
+; SI = 0 ;
+; ZF = 0 if freed a moveable block ;
+; SI = handle table entry ;
+; ES:DI = block freed (may have been coalesced) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DS ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; gjoin ;
+; gadd_free ;
+; ;
+; History: ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Sun Nov 09, 1986 01:35:08p -by- David N. Weise [davidw] ;
+; Made the debugging version fill all free space with CCCC. ;
+; ;
+; Wed Sep 24, 1986 10:27:06p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gmarkfree,<PUBLIC,NEAR>
+cBegin nogen
+
+ call gadd_free
+ mov si,es
+ or si,si
+ jz short gmf_exit
+
+; Mark this block as free by clearing the owner field.
+
+ mov es:[di].ga_sig,GA_SIGNATURE
+ mov es:[di].ga_owner,di ; Mark as free
+ mov es:[di].ga_flags,0 ; For good measure.
+
+; Remember the handle value in DX, before setting to zero.
+
+ push dx
+ xor dx,dx
+ xchg es:[di].ga_handle,dx
+
+; Try to coalesce with next block, if it is free
+
+ push es:[di].ga_prev ; save previous block
+ mov es,es:[di].ga_next ; ES = next block
+ cmp es:[di].ga_owner,di ; Is it free?
+ jne short free2 ; No, continue
+ call gjoin ; Yes, coalesce with block we are freeing
+free2:
+ pop es ; ES = previous block
+ cmp es:[di].ga_owner,di ; Is it free?
+ jne short free3 ; No, continue
+ mov es,es:[di].ga_next ; Yes, coalesce with block we are freeing;
+ call gjoin
+free3:
+ mov si,dx ; Return 0 or handle in SI
+ pop dx ; restore handle
+ cmp es:[di].ga_owner,di ; Point to free block?
+ je short free4 ; Yes, done
+ mov es,es:[di].ga_next ; No, leave ES pointing at free block
+free4:
+if KDEBUG
+ call CCCC
+endif
+gmf_exit:
+ or si,si
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gadd_free ;
+; ;
+; Links in the given partition into the global free list. ;
+; ;
+; Arguments: ;
+; SI = the first free object before this one ;
+; 0 if unknown ;
+; odd if no free list update wanted ;
+; DS:DI = BurgerMaster ;
+; ES:DI = free global object to add ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Nov 09, 1986 02:42:53p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc gadd_free,<PUBLIC,NEAR>
+cBegin nogen
+ test si,1
+ jnz no_update_wanted
+
+ push ax
+ push si
+ push ds
+ mov ax,es
+ or ax,ax ; this happens with gmovebusy
+ jz gaf_exit
+
+ inc [di].gi_free_count
+
+ ;
+ ; For DPMI compliance, we cannot look at addresses of
+ ; selectors in the LDT and DPMI calls would be too slow,
+ ; so we scan forward from the block we are freeing,
+ ; looking for a free block or the sentinal and insert
+ ; the new block before it.
+ ;
+ smov ds, es
+need_a_home_loop:
+ mov ds, ds:[di].ga_next
+ cmp ds:[di].ga_owner, di ; Free?
+ je found_a_home
+ cmp ds:[di].ga_sig, GA_ENDSIG ; Sentinal
+ jne need_a_home_loop
+
+found_a_home:
+ mov si, ds:[di].ga_freeprev ; Fix up block after free block
+ mov ds:[di].ga_freeprev, es
+
+ mov es:[di].ga_freeprev,si ; Fix up free block
+ mov es:[di].ga_freenext,ds
+
+ mov ds,si ; Fix up block before free block
+ mov ds:[di].ga_freenext,es
+
+if KDEBUG
+ call check_free_list
+endif
+
+gaf_exit:
+ pop ds
+ pop si
+ pop ax
+
+no_update_wanted:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gdel_free ;
+; ;
+; Removes a partition from the global free list. ;
+; ;
+; Arguments: ;
+; DS:DI = BurgerMaster ;
+; ES:DI = arena header of partition ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Nov 09, 1986 02:43:26p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc gdel_free,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ push ds
+ push es
+ mov ds,es:[di].ga_freeprev
+ mov es,es:[di].ga_freenext
+ mov ds:[di].ga_freenext,es
+ mov es:[di].ga_freeprev,ds
+ pop es
+ pop ds
+
+ dec [di].gi_free_count
+gfx:
+ pop ax
+
+if KDEBUG
+ call check_free_list
+endif
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------
+; GrowHeap -- this procedure grows the global heap
+;
+; Input:
+; None
+;
+; Output:
+; carry clear for success
+;
+ public GrowHeap
+GrowHeap proc near
+
+ push si
+ push di
+ push bx
+ push es
+
+ xor si,si
+
+ ;
+ ; Request 1 MB
+ ;
+ xor ax,ax
+ call AllocDpmiBlock
+
+ or ax,ax
+ jz gh30
+
+ ;
+ ; Format the block
+ ;
+ or bx,bx
+ jnz gh10
+
+ mov si,1
+gh10: mov dx,ax
+ call FormatHeapBlock
+
+
+ ;
+ ; Add the block to the heap
+ ;
+ call AddBlockToHeap
+
+ clc
+gh20: pop es
+ pop bx
+ pop di
+ pop si
+ ret
+
+gh30: stc
+ jmp gh20
+
+GrowHeap endp
+;-----------------------------------------------------------------------
+; FormatHeapBlock -- this procedure initializes three arenas in a
+; global heap block. The first arena is marked as the heap
+; initial sentinel, the second arena is the heap free block, and
+; the third arena at the very end of the block is marked as
+; 'not there'.
+;
+; In: SI:BX - size of block in paragraphs
+; DX - selector pointing to start of block (descriptor is modified!)
+;
+; Out: AX - selector to ending 'not there' block
+; BX - zero
+; SI - selector to initial sentinel
+; DI - selector to free block arena
+; ES:BX -> initial sentinel arena
+;
+; Uses: CX, DX
+ public FormatHeapBlock
+FormatHeapBlock proc near
+
+; Setup selector to first arena (the new initial sentinel)
+
+ push bx ;save # paragraphs
+ push si
+
+ mov bx,dx ;get physical address of start
+ cCall get_physical_address,<bx>
+
+ push ax ;save unaligned start address
+ push dx
+
+ add ax,GA_ALIGN_BYTES
+ adc dx,0
+ and ax,GA_MASK_BYTES
+
+ cCall set_physical_address,<bx>
+ mov si,bx ;si -> initial sentinel
+
+ mov bx,10h ;set initial selector to
+ xor cx,cx ; be just 1 arena long
+ cCall set_sel_limit,<si>
+
+; Setup selector to second arena (the free block)
+
+ add ax,10h+GA_ALIGN_BYTES
+ adc dx,0
+ and ax,GA_MASK_BYTES
+ cCall alloc_data_sel,<dx,ax,1>
+ mov di,ax ;di -> free block arena
+
+; Setup selector to the third arena ('NOT THERE' at end of heap block)
+
+ pop dx ;recover unaligned start addr
+ pop ax
+
+ pop cx ;recover len in paragraphs
+ pop bx
+
+ sub bx,1
+ sbb cx, 0
+rept 4
+ shl bx,1
+ rcl cx,1 ;cx:bx = len in bytes
+endm
+ add ax,bx
+ adc dx,cx
+ and ax,GA_MASK_BYTES ;dx:ax -> not there arena addr
+
+ push ax ;save not there arena address
+ push dx
+
+ cCall alloc_data_sel,<dx,ax,1>
+
+; Now fill in the arenas
+
+ mov es,ax
+ assumes es,nothing
+
+ xor bx,bx ;es:bx -> not there arena
+
+ mov es:[bx].ga_sig,GA_SIGNATURE
+ mov es:[bx].ga_owner,GA_NOT_THERE
+ mov es:[bx].ga_flags,bl
+ mov es:[bx].ga_size,bx
+ mov es:[bx].ga_prev,di
+ mov es:[bx].ga_handle,bx
+ mov es:[bx].ga_lrunext,bx
+ mov es:[bx].ga_lruprev,bx
+
+ mov es,di ;es:bx -> free block
+
+ mov es:[bx].ga_sig,GA_SIGNATURE
+ mov es:[bx].ga_owner,bx
+ mov es:[bx].ga_flags,bl
+ mov es:[bx].ga_prev,si
+ mov es:[bx].ga_next,ax
+ mov es:[bx].ga_handle,bx
+ mov es:[bx].ga_lrunext,bx
+ mov es:[bx].ga_lruprev,bx
+
+ pop cx ;cx:bx = address of end arena
+ pop bx
+ push ax ;save not there selector
+
+ cCall get_physical_address,<di> ;dx:ax = address of free arena
+ sub bx,ax
+ sbb cx,dx ;cx:bx = length in bytes
+rept 4
+ shr cx,1
+ rcr bx,1
+endm
+ sub bx,1
+ sbb cx,0 ;cx:bx = length in paragraphs
+
+ or cx, cx ; Less than 1024k?
+ jz @F ; yes, set correct size
+ xor bx, bx ; no, set bogus size
+@@:
+ mov cx,bx
+ xor bx,bx
+ mov es:[bx].ga_size,cx ;save free block size (<1024k)
+
+ pop ax ;recover end arena selector
+
+ mov es,si ;es:bx -> initial sentinel
+
+ mov es:[bx].ga_sig,GA_SIGNATURE
+ mov es:[bx].ga_size,bx
+ mov es:[bx].ga_owner,GA_NOT_THERE
+ mov es:[bx].ga_flags,bl
+ mov es:[bx].ga_prev,si ;first.prev = self
+ mov es:[bx].ga_next,di
+ mov es:[bx].ga_handle,bx
+ mov es:[bx].ga_lrunext,bx
+ mov es:[bx].ga_lruprev,bx
+
+ ret
+
+FormatHeapBlock endp
+
+;-----------------------------------------------------------------------
+;
+; In: AX - selector to ending 'not there' block
+; BX - zero
+; SI - selector to initial sentinel
+; DI - selector to free block arena
+; ES:BX -> initial sentinel arena
+ public AddBlockToHeap
+AddBlockToHeap proc near
+
+ pusha
+ push bp
+ mov bp,sp
+ sub sp,8
+SelFirstBlock equ word ptr [bp - 2]
+SelLastBlock equ word ptr [bp - 4]
+SelFreeBlock equ word ptr [bp - 6]
+SelInsertBlock equ word ptr [bp - 8]
+
+ mov SelFirstBlock,si
+ mov SelLastBlock,ax
+ mov SelFreeBlock,di
+
+ ;
+ ; Get the physical address of this block
+ ;
+ cCall get_physical_address, <si>
+ mov bx,ax
+ mov cx,dx
+
+ xor di,di
+ ;
+ ; search for the correct place to insert it.
+ ;
+ mov si,[di].hi_first
+
+abh20: cCall get_physical_address, <si>
+ cmp dx,cx
+ jb abh40
+ ja abh60
+
+ cmp ax,bx
+ jb abh40
+
+ ;
+ ; Found our spot
+ ;
+ jmp abh60
+
+ ;
+ ; Check the next block
+ ;
+abh40: mov es,si
+ ;
+ ; Have we reached the end of the list?
+ ;
+ cmp si,es:[di].ga_next
+ mov si,es:[di].ga_next
+ jne abh20
+
+ ;
+ ; es contains the selector of the block to insert this
+ ; heap partition after
+ ;
+abh60:
+ add [di].hi_count,3 ;three more arenas
+ mov ax,GA_SIGNATURE
+ cmp es:[di].ga_sig,GA_ENDSIG
+ jne abh70
+
+ ;
+ ; New block will be at the end of the heap
+ ;
+ mov es:[di].ga_sig,GA_SIGNATURE
+ mov ax,GA_ENDSIG
+
+ ;
+ ; make this the next block in the heap
+ ;
+abh70: mov dx,SelFirstBlock
+ mov bx,es:[di].ga_next
+ mov es:[di].ga_next,dx
+ mov cx,es
+ mov SelInsertBlock,cx
+ mov es,dx
+ mov es:[di].ga_prev,cx
+
+ ;
+ ; Put the last block last
+ ;
+ mov dx,SelLastBlock
+ mov es,dx
+ mov es:[di].ga_next,bx
+
+ ;
+ ; If this block was last, don't update next.prev
+ ;
+ cmp ax,GA_ENDSIG
+ je abh75
+
+ mov es,bx
+ mov es:[di].ga_prev,dx
+ jmp abh80
+
+ ;
+ ; Fix the old heap end block
+ ;
+abh75: mov es,[di].hi_last
+ mov es:[di].ga_owner,GA_NOT_THERE
+ mov es:[di].ga_sig,GA_SIGNATURE
+ mov es:[di].ga_size,di
+ mov cx,es:[di].ga_freeprev
+ mov es:[di].ga_freeprev,di
+ mov es:[di].ga_freenext,di
+
+ ;
+ ; Turn the new end block into a proper end block
+ ;
+ mov es,SelLastBlock
+ mov es:[di].ga_sig,GA_ENDSIG
+ mov es:[di].ga_owner,-1
+ mov bx,SelFreeBlock
+ mov es:[di].ga_freeprev,bx
+ mov es:[di].ga_freenext,-1
+ mov es:[di].ga_size,GA_ALIGN
+ mov ax,SelLastBlock
+ mov es:[di].ga_next,ax
+
+ ;
+ ; Fix the free list
+ ;
+ mov es,cx
+ mov es:[di].ga_freenext,bx
+ mov es,bx
+ mov es:[di].ga_freeprev,cx
+ mov ax,SelLastBlock
+ mov es:[di].ga_freenext,ax
+
+ ;
+ ; Fix the discardable code fence
+ ;
+ cCall get_physical_address, <[di].hi_last>
+ sub ax,[di].gi_disfence
+ sbb dx,[di].gi_disfence_hi
+
+ mov bx,ax
+ mov cx,dx
+ cCall get_physical_address, <SelLastBlock>
+
+ sub ax,bx
+ sbb dx,cx
+
+ mov [di].gi_disfence,ax
+ mov [di].gi_disfence_hi,dx
+
+ ;
+ ; Increment the free block count
+ ;
+ inc [di].gi_free_count
+
+ ;
+ ; Make this block the last block in the heap
+ ;
+ mov ax,SelLastBlock
+ mov [di].hi_last,ax
+ jmp abh90
+
+ ;
+ ; Add the free block to the free list
+ ;
+abh80: mov es,SelFreeBlock
+ mov si,0
+ cCall gadd_free
+
+abh90: mov sp,bp
+ pop bp
+ popa
+ ret
+
+AddBlockToHeap endp
+
+;-----------------------------------------------------------------------;
+; AllocDpmiBlock ;
+; ;
+; Allocates a block from DPMI and stores the information in ;
+; DpmiMemory. It also allocates a selector for the beginning of ;
+; the block. ;
+; ;
+; Arguments: ;
+; ;
+; AX = size of block to allocate in paragraphs ;
+; ;
+; Returns: ;
+; AX = selector to block if allocated ;
+; BX = size of block in paragraphs ;
+; BX = zero if block is 1 megabyte in size. ;
+; ;
+; Error Returns: ;
+; AX = zero if error ;
+; ;
+;-----------------------------------------------------------------------;
+ public AllocDpmiBlock
+AllocDpmiBlock proc near
+ push es
+ push ds
+ push si
+ push di
+ push cx
+ push bp
+ mov bp,sp
+ sub sp,30h ; space for meminfo structure
+MemInfo equ [bp - 30h]
+ SetKernelDS
+ ;
+ ; Find an unused Dpmi Block
+ ;
+ mov si,0
+ mov cx,NUM_DPMI_BLOCKS - 1
+adb3: cmp DpmiMemory[si].DBSel,0
+ je adb5
+
+ add si,size DpmiBlock
+ loop adb3
+
+ ;
+ ; Did We find one?
+ ;
+ cmp DpmiMemory[si].DBSel,0
+ jne adb140
+
+ ;
+ ; Store expected size
+ ;
+adb5: mov DpmiMemory[si].DBSize, ax
+
+ ;
+ ; Convert paragraphs to bytes (if paragraphs = 0, then alloc a
+ ; megabyte)
+ ;
+ mov cx,ax
+ mov bx,10h
+ or cx,cx
+ jz adb10
+
+ mov bx,ax
+ shr bx,0ch
+ shl cx,04h
+
+ ;
+ ; Attempt to allocate the block
+ ;
+adb10: push si
+ DPMICALL 501h
+ mov dx,si
+ pop si
+ jc adb100
+
+ ;
+ ; put information into dpmi memory list
+ ;
+adb20: mov DpmiMemory[si].DBHandleLow,di
+ mov DpmiMemory[si].DBHandleHigh,dx
+
+ ;
+ ; Allocate a selector for the beginning of the block
+ ;
+ cCall alloc_data_sel,<bx,cx,1>
+
+ ;
+ ; Remember the selector
+ ;
+ mov DpmiMemory[si].DBSel,ax
+
+ ;
+ ; Update the number of dpmi blocks
+ ;
+ inc DpmiBlockCount
+
+ ;
+ ; Return the information
+ ;
+ mov bx,DpmiMemory[si].DBSize
+ adb40: mov sp,bp
+ pop bp
+ pop cx
+ pop di
+ pop si
+ pop ds
+ pop es
+ ret
+
+ ;
+ ; Couldn't allocate a block the size we wanted. Find the largest
+ ; block we can allocate
+ ;
+adb100: mov ax,ss
+ mov es,ax
+ lea di,MemInfo
+ DPMICALL 500h
+ jc adb140
+
+ ;
+ ; Convert block size to paragraphs
+ ;
+ mov ax,es:[di]
+ mov dx,es:[di + 2]
+ mov bx,dx
+ mov cx,ax
+ shl dx,0ch
+ shr ax,4
+ or ax,dx
+
+ ;
+ ; Store expected size
+ ; N.B. We don't jump back into the above code, because this
+ ; could result in an infinite loop if something is seriously
+ ; wrong with DPMI.
+ ;
+ mov DpmiMemory[si].DBSize, ax
+
+ ;
+ ; Attempt to allocate the block
+ ;
+ push si
+ DPMICALL 501h
+ mov dx,si
+ pop si
+ jnc adb20
+
+ ;
+ ; We have failed to allocate the memory
+ ;
+adb140: xor ax,ax
+ jmp adb40
+
+ UnsetKernelDS
+AllocDpmiBlock endp
+if KDEBUG
+
+;-----------------------------------------------------------------------;
+; CCCC ;
+; ;
+; Fills the given area with DBGFILL_FREE ;
+; ;
+; Arguments: ;
+; ES:DI = arena header of free area. ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All. ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sun Nov 09, 1986 01:39:52p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CCCC,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ cmp fCheckFree,0
+ jnz short dont_CCCC ; not while booting
+ test Kernel_flags,kf_check_free
+ jz short dont_CCCC
+ push ax
+ push bx
+ push cx
+ push dx
+ push di
+ push es
+ mov bx,es:[di].ga_size
+ mov ax,es
+ call get_blotto
+ mov es,ax
+
+;;; mov cx,ss ; make sure we're not wiping
+;;; cmp cx,ax ; out the stack
+;;; jb short by_64Kb_loop
+;;; add ax,bx
+;;; cmp cx,ax
+;;; ja short by_64Kb_loop ; yes it wastes debugging bytes
+;;; jmps no_not_the_stack ; but it's readable
+
+ push bx ; Say it ain't so, Joe...
+ xor cx,cx ; force the incoming sel/descriptor to
+ mov bx,cx ; a limit of 64k - it might be higher
+ inc cx ; which would cause set_physical_adr
+ cCall set_sel_limit,<es> ; to destroy following descriptors.
+ pop bx
+
+ jmp short CC_doit
+
+CC_next_64k:
+ push es
+ cCall get_physical_address,<es> ;update selector to next
+ inc dl ; 64k block
+ cCall set_physical_address,<es>
+ pop es ;reload it with new base
+
+CC_doit:
+ mov cx,1000h ; 1000h paras = 64k bytes
+ cmp bx,cx
+ jae @f
+ mov cx,bx ; less than 64k left
+@@:
+ sub bx,cx ; bx = # paras left to do
+ shl cx,3 ; cx = # words to CC this time
+ mov ax,(DBGFILL_FREE or (DBGFILL_FREE SHL 8))
+ xor di, di
+ rep stosw
+
+ or bx,bx ; more to do?
+ jnz short CC_next_64k ; go do the next block
+no_not_the_stack:
+ pop es
+ pop di
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+dont_CCCC:
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; init_free_to_CCCC ;
+; ;
+; Initializes all of the free space to zero. It speeds booting if ;
+; CCCCing is not done during boot time. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; CCCC ;
+; ;
+; History: ;
+; ;
+; Wed Nov 19, 1986 09:41:58a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc init_free_to_CCCC,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ test Kernel_flags,kf_check_free
+ jz short dont_init
+ push cx
+ push di
+ push es
+ xor di,di
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov cx,[di].gi_free_count
+ mov es,[di].hi_first
+ mov es,es:[di].ga_freenext
+CCCC_all_loop:
+ call CCCC
+ mov es,es:[di].ga_freenext
+ loop CCCC_all_loop
+
+; get EMS land if there
+
+ mov cx,[di].gi_alt_free_count
+ jcxz no_alts
+ mov es,[di].gi_alt_first
+ mov es,es:[di].ga_freenext
+CCCC_alt_loop:
+ call CCCC
+ mov es,es:[di].ga_freenext
+ loop CCCC_alt_loop
+no_alts:
+ pop es
+ pop di
+ pop cx
+dont_init:
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; check_this_space ;
+; ;
+; Makes sure the given free space is still filled with DBGFILL_FREE ;
+; ;
+; Arguments: ;
+; ES:DI = arena header of space to check ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Nov 18, 1986 08:26:52p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc check_this_space,<PUBLIC,NEAR>,<ax,bx,cx,dx,di,ds,es>
+cBegin
+ SetKernelDS
+ cmp fCheckFree,0
+ jnz short not_while_boot
+ test Kernel_flags,kf_check_free
+ jnz short cts_check_it_out
+not_while_boot:
+ jmps cts_ret
+cts_check_it_out:
+ mov bx,es:[di].ga_size
+ mov ax,es
+ call get_blotto
+ mov es,ax
+
+ push bx ; Say it ain't so, Joe...
+ xor cx,cx ; force the incoming sel/descriptor to
+ mov bx,cx ; a limit of 64k - it might be higher
+ inc cx ; which would cause set_physical_adr
+ cCall set_sel_limit,<es> ; to destroy following descriptors.
+ pop bx
+
+ jmp short cts_doit
+
+cts_next_64k:
+ push es
+ cCall get_physical_address,<es> ;update selector to next
+ inc dl ; 64k block
+ cCall set_physical_address,<es>
+ pop es ;reload it with new base
+
+cts_doit:
+ mov cx,1000h ; 1000h paras = 64k bytes
+ cmp bx,cx
+ jae @f
+ mov cx,bx ; less than 64k left
+@@:
+ sub bx,cx ; bx = # paras left to do
+ shl cx,3 ; cx = # words to zero this time
+ mov ax,(DBGFILL_FREE or (DBGFILL_FREE shl 8))
+ xor di, di
+ repz scasw ; check it out
+ jz short so_far_so_good
+ kerror 0FFh,<FREE MEMORY OVERWRITE AT >,es,di
+ jmps cts_ret
+so_far_so_good:
+ or bx,bx ; more to do?
+ jnz short cts_next_64k ; go do the next block
+
+cts_ret:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; check_free_list ;
+; ;
+; Checks the global free list for consistency. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Oct 29, 1986 10:13:42a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc check_free_list,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ push bx
+ push cx
+ push ds
+ push es
+ SetKernelDS
+ cmp fCheckFree,0
+ jnz short cfl_outta_here
+ test Kernel_flags,kf_check_free
+ jnz short cfl_check_it_out
+cfl_outta_here:
+ jmp all_done
+cfl_check_it_out:
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov es,[di].hi_first
+ mov cx,[di].gi_free_count
+ or cx,cx
+ jnz short short_relative_jumps
+ jmp all_done
+short_relative_jumps:
+ mov ax,es:[di].ga_freenext
+ mov es,ax
+check_chain_loop:
+ mov ds,es:[di].ga_freeprev
+ mov es,es:[di].ga_freenext
+ cmp ds:[di].ga_freenext,ax
+ jnz short prev_bad
+ mov bx,ds
+ cmp ax,bx
+ jmps prev_okay
+prev_bad:
+ mov bx, ax
+ kerror 0FFh,<free_list: prev bad>,ds,bx
+ mov ax, bx
+prev_okay:
+ cmp es:[di].ga_freeprev,ax
+ jnz short next_bad
+ mov bx,es
+ cmp ax,bx
+ jmps next_okay
+
+next_bad:
+ mov bx, ax
+ kerror 0FFh,<free_list: next bad>,bx,es
+next_okay:
+ mov ax,es
+ loop check_chain_loop
+ SetKernelDS
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ cmp [di].hi_last,ax
+ jz short all_done
+ mov bx, ax
+ kerror 0FFh,<free_list: count bad>,[di].hi_last,bx
+all_done:
+ pop es
+ pop ds
+ pop cx
+ pop bx
+ pop ax
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ValidateFreeSpaces ;
+; ;
+; The global free list is gone through to make sure that all free ;
+; partitions are filled with DBGFILL_FREE ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Nov 18, 1986 09:46:55a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc ValidateFreeSpaces,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ test Kernel_flags,kf_check_free
+ jz short dont_validate
+ push cx
+ push di
+ push es
+ xor di,di
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov cx,[di].gi_free_count
+ mov es,[di].hi_first
+ mov es,es:[di].ga_freenext
+ jcxz empty_list
+check_all_loop:
+ call check_this_space
+ mov es,es:[di].ga_freenext
+ loop check_all_loop
+empty_list:
+ pop es
+ pop di
+ pop cx
+dont_validate:
+ pop ds
+ ret
+cEnd nogen
+
+else
+
+cProc ValidateFreeSpaces,<PUBLIC,FAR>
+cBegin nogen
+ ret
+cEnd nogen
+
+endif
+
+sEnd CODE
+
+end
+
diff --git a/private/mvdm/wow16/kernel31/2gcompac.asm b/private/mvdm/wow16/kernel31/2gcompac.asm
new file mode 100644
index 000000000..433d0b8fb
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2gcompac.asm
@@ -0,0 +1,1452 @@
+ TITLE GCOMPACT - Global memory compactor
+
+.sall
+.xlist
+include kernel.inc
+include protect.inc
+.list
+
+WM_COMPACTING = 041h
+
+.286p
+
+DataBegin
+
+externA __AHINCR
+externB Kernel_Flags
+externW kr2dsc
+;externW WinFlags
+externD gcompact_start
+externD gcompact_timer
+externD pPostMessage
+
+externB DpmiMemory
+externW DpmiBlockCount
+fSwitchStacks DB 0
+fUpDown DB 0
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+;externW gdtdsc
+
+externNP glrudel
+externNP gmarkfree
+externNP gcheckfree
+externNP gdel_free
+externNP gnotify
+externNP Enter_gmove_stack
+externNP Leave_gmove_stack
+
+if KDEBUG
+externFP ValidateFreeSpaces
+endif
+externFP SetSelectorBase
+
+externNP get_arena_pointer
+externNP get_physical_address
+externNP set_physical_address
+externNP set_sel_limit
+externNP get_rover_2
+externNP cmp_sel_address
+externNP get_temp_sel
+externNP alloc_data_sel_above
+externNP alloc_data_sel_below
+externNP free_sel
+externNP PreallocSel
+externNP AssociateSelector
+externNP mark_sel_NP
+if ALIASES
+externNP check_for_alias
+endif
+externNP DPMIProc
+
+
+;-----------------------------------------------------------------------;
+; gcompact ;
+; ;
+; Compacts the global heap. ;
+; ;
+; Arguments: ;
+; DX = minimum #contiguous bytes needed ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; AX = size of largest contiguous free block ;
+; ES:DI = arena header of largest contiguous free block ;
+; DX = minimum #contiguous bytes needed ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; SI ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; gcmpheap ;
+; gcheckfree ;
+; gdiscard ; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:34:32p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gcompact,<PUBLIC,NEAR>
+cBegin nogen
+
+ push si
+ mov ax,40h
+ mov es,ax
+ mov ax,es:[6Ch] ; get the BIOS ticker count
+ SetKernelDS es
+ sub gcompact_timer.lo,ax
+gcompactl:
+if KDEBUG
+ call ValidateFreeSpaces
+endif
+ push dx ; Save requested size
+ cmp [di].gi_reserve,di ; Is there a reserve swap area?
+ je gcompact1 ; No, then dont compact lower heap
+ mov es,[di].hi_first ; Yes, compact lower heap
+ mov bx,ga_next
+ call gcmpheap
+gcompact1:
+ test [di].gi_cmpflags,BOOT_COMPACT
+ jz gcompact1a
+ pop dx
+ jmps gcompactx
+gcompact1a:
+ mov es,[di].hi_last ; Compact upper heap
+ mov bx,ga_prev
+ call gcmpheap
+ pop dx ; Get requested size
+ mov es,ax ; ES points to largest free block
+ or ax,ax ; Did we find a free block?
+ jz gcompact2 ; No, try discarding
+ call gcheckfree ; Yes, see if block big enough
+ jae gcompactx ; Yes, all done
+gcompact2: ; Discarding allowed?
+ test [di].gi_cmpflags,GA_NODISCARD+GA_NOCOMPACT
+ jnz gcompactx ; No, return
+ cmp [di].hi_freeze,di ; Heap frozen?
+ jne gcompactx ; Yes, return
+
+ push es
+ call gdiscard ; No, try discarding
+ pop cx ; Saved ES may be bogus if gdiscard
+ ; discarded anything...
+ jnz gcompactl ; Compact again if anything discarded
+ mov es, cx ; Nothing discarded so ES OK.
+gcompactx:
+ push ax
+ push dx
+ push es
+ mov ax,40h
+ mov es,ax
+ mov ax,es:[6Ch]
+ mov si,ax
+ SetKernelDS es
+ cmp pPostMessage.sel,0 ; is there a USER around yet?
+ jz tock
+ add gcompact_timer.lo,ax
+ sub ax,gcompact_start.lo
+ cmp ax,546 ; 30 secs X 18.2 tics/second
+ jb tock
+ cmp ax,1092 ; 60 secs
+ ja tick
+ mov cx,gcompact_timer.lo ; poor resolution of timer!
+ jcxz tick
+ xchg ax,cx
+ xor dx,dx
+ xchg ah,al ; shl 8 DX:AX
+ xchg dl,al
+ div cx
+ cmp ax,32 ; < 12.5% ?
+ jb tick
+ mov ah,al
+ mov bx,-1 ; broadcast
+ mov cx,WM_COMPACTING
+ xor dx,dx
+ push es
+ cCall pPostMessage,<bx, cx, ax, dx, dx>
+ pop es
+tick: mov gcompact_start.lo,si
+ mov gcompact_timer.lo,0
+tock: pop es
+ pop dx
+ pop ax
+ pop si ; Restore SI
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gcmpheap ;
+; ;
+; ;
+; Arguments: ;
+; BX = ga_prev or ga_next ;
+; DX = minimum #contiguous bytes needed ;
+; DS:DI = address of global heap information ;
+; ES:DI = first arena to start with ;
+; ;
+; Returns: ;
+; AX = largest free block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX,CX ;
+; ;
+; Calls: ;
+; gslide ;
+; gbestfit ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:38:16p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gcmpheap,<PUBLIC,NEAR>
+cBegin nogen
+ mov cx,[di].hi_count
+ xor ax,ax ; Nothing found yet
+ push ax ; Save largest free block so far
+gchloop:
+ cmp es:[di].ga_owner,di
+ je gchfreefnd
+gchnext:
+ mov es,es:[bx]
+ loop gchloop
+ pop ax ; Return largest free block in AX
+ ret
+
+gchfreefnd:
+ test [di].gi_cmpflags,GA_NOCOMPACT
+ jnz gchmaxfree ; No, just compute max free.
+ cmp [di].hi_freeze,di ; Heap frozen?
+ jne gchmaxfree ; Yes, just compute max free.
+ push es
+ cmp bl,ga_prev ; Compacting upper heap?
+ jnz no_hack
+ test [di].gi_cmpflags,GA_DISCCODE
+ jz no_hack
+ cmp dx,es:[ga_size]
+ ja no_hack
+ mov es,es:[di].ga_next
+ test es:[di].ga_flags,GA_DISCCODE
+ jnz hack
+ cmp es:[di].ga_owner,GA_SENTINAL
+ jz hack
+ cmp es:[di].ga_owner,GA_NOT_THERE
+ jnz no_hack
+
+; Check to see if anything is locked above us!
+
+gch_hack_check:
+ test es:[di].ga_flags,GA_DISCCODE
+ jnz hat_check
+ mov ax,es:[di].ga_owner
+ or ax,ax
+ jz hat_check
+ cmp ax,GA_NOT_THERE
+ jz hat_check
+ cmp ax,GA_SENTINAL
+ jz hack
+ jmp short no_hack
+hat_check:
+ mov es,es:[di].ga_next
+ jmp gch_hack_check
+
+hack: pop es
+ pop ax
+ mov ax,es
+ ret
+
+no_hack:
+ pop es
+ call PreallocSel
+ jz gchmaxfree
+ push dx
+ call gslide
+ pop dx
+ jnz gchfreefnd
+best_it:
+ push dx
+ call gbestfit
+ pop dx
+ jnz best_it ; Useless to gslide anymore.
+gchmaxfree:
+ cmp bl,ga_prev ; Compacting upper heap?
+ jne gchnext ; No, dont compute largest free block
+ pop si ; Recover largest free block so far
+ mov ax,es ; AX = current free block
+ cmp si,ax ; Same as current?
+ je gchmf2 ; Yes, no change then
+ cmp es:[di].ga_owner,di ; No, is current free?
+ jne gchmf2 ; No, ignore it then
+ push es
+ cmp ds:[di].gi_reserve,di ; Is there a code reserve area?
+ je gchmf0 ; No, continue
+ test ds:[di].gi_cmpflags,GA_DISCCODE ; If allocating disc
+ jz gchmf0 ; code then only use free block if
+ mov es,es:[di].ga_next
+ test es:[di].ga_flags,GA_DISCCODE
+ jnz gchmf0 ; butted up against disc code
+ cmp es:[di].ga_owner,GA_SENTINAL ; or sentinal.
+ pop es
+ jnz gchmf2
+ push es
+gchmf0:
+ pop es
+ or si,si ; First time?
+ jz gchmf1 ; Yes, special case
+ push es
+ mov es,si
+ mov ax,es:[di].ga_size ; No, get size of largest free block
+ pop es ; Compare with size of this free block
+ cmp es:[di].ga_size,ax ; Is it bigger?
+ jb gchmf2 ; No, do nothing
+gchmf1: mov si,es ; Yes, remember biggest free block
+gchmf2: push si ; Save largest free block so far
+ jmp gchnext ; Go process next block
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gslide ;
+; ;
+; Sees if next/previous block can slide into the passed free block. ;
+; ;
+; Arguments: ;
+; ES:DI = free block ;
+; DS:DI = address of global heap information ;
+; CX = #arena entries left to examine ;
+; BX = ga_next or ga_prev ;
+; ;
+; Returns: ;
+; ZF = 0 if block found and moved into passed free block ;
+; ES:DI points to new free block ;
+; SI:DI points to new free block ;
+; ;
+; ZF = 1 if no block found ;
+; ES:DI points to original free block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX,DX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:58:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gslide,<PUBLIC,NEAR>
+cBegin nogen
+ push es
+ mov es,es:[bx]
+ mov ax,es
+ mov dx,es:[di].ga_size
+ call gmoveable
+ pop es
+ jz gslide_no_move
+ cmp bx,ga_next
+ jnz sliding_up
+ push es:[bx] ; gslide will invalidate this block
+ jmps slide
+sliding_up:
+ push es ; gslide will invalidate this block
+slide: call gslidecommon ; C - calling convention
+ call free_sel ; free the pushed selector
+gslide_no_move:
+ ret
+cEnd nogen
+
+ ; Enter here from gbestfit
+cProc gslidecommon,<PUBLIC,NEAR>
+cBegin nogen
+ ; moving non-contiguous blocks
+ push es:[di].ga_freeprev
+ push es:[di].ga_freenext
+
+ mov si,ax ; Source is busy block
+ inc dx ; DX = busy.ga_size + 1
+ cmp bl,ga_next
+ je gslidedown
+
+; Here to slide moveable block up to high end of free block.
+;
+; Free and busy block adjacent
+; 0000:0 | | | |
+; |-----------| a -> |-----------|
+; | busy | | free ? |
+; |-----------| | |
+; | free | b -> |-----------|
+; | | | ? busy ? |
+; |-----------| c -> |-----------|
+; FFFF:0 | | | ? |
+;
+;
+; a = busy
+; b = free.ga_next - busy.ga_size - 1
+; c = free.ga_next
+; destination = b
+;
+; Free and busy block NOT adjacent
+; 0000:0 | | | |
+; |-----------| |-----------|
+; | busy | | free |
+; |-----------| |-----------|
+; | | | |
+; |-----------| a -> |-----------|
+; | free | | free ? |
+; | | b -> |-----------|
+; | | | ? busy ? |
+; |-----------| c -> |-----------|
+; FFFF:0 | | | ? |
+;
+;
+; a = free
+; b = free.ga_next - busy.ga_size - 1
+; c = free.ga_next
+; destination = b
+;
+gslideup:
+ mov ax,es:[di].ga_next
+ push ax ; Save c
+ cCall alloc_data_sel_below, <ax, dx> ; Bogus arena header
+ push ax ; Save b
+ cmp es:[bx],si ; Are blocks adjacent?
+ je gslideup1
+ push es ; No, a = free
+ jmps gslideup2
+gslideup1:
+ push si ; Yes, a = busy
+gslideup2:
+
+ mov es,ax ; Destination is b
+ xor ax,ax ; a.ga_prev will remain valid
+ jmps gslidemove
+
+; Here to slide moveable block down to low end of free block.
+;
+; Free and busy block adjacent
+; 0000:0 | | | |
+; |-----------| a -> |-----------|
+; | free | | ? busy ? |
+; | | b -> |-----------|
+; |-----------| | ? free ? |
+; | busy | | |
+; |-----------| c -> |-----------|
+; FFFF:0 | | | ? |
+;
+; a = free
+; b = free + busy.ga_size + 1
+; c = busy.ga_next
+; destination = free
+;
+; Free and busy block NOT adjacent
+; 0000:0 | | | |
+; |-----------| a -> |-----------|
+; | free | | ? busy ? |
+; | | b -> |-----------|
+; | | | ? free ? |
+; |-----------| c -> |-----------|
+; | | | ? |
+; |-----------| |-----------|
+; | busy | | free |
+; |-----------| |-----------|
+; FFFF:0 | | | |
+;
+;
+; a = free
+; b = free + busy.ga_size + 1
+; c = free.ga_next
+; destination = free
+;
+
+gslidedown:
+ cmp es:[bx],si ; Are blocks adjacent?
+ je gslidedn1
+ push es:[di].ga_next ; No, c = free.ga_next
+ jmps gslidedn2
+gslidedn1:
+
+ push es
+ mov es,si
+ mov ax,es:[di].ga_next
+ pop es
+ push ax
+gslidedn2:
+ cCall alloc_data_sel_above, <es, dx>
+ push ax ; Save b
+ push es ; Save a
+ mov ax,es:[di].ga_prev ; a.ga_prev must be restored after move
+gslidemove:
+
+ push ax
+ push si ; Source arena
+
+ mov ax, es
+ mov es, si ; Save source arena contents
+
+ push word ptr es:[di]
+ push word ptr es:[di+2]
+ push word ptr es:[di+4]
+ push word ptr es:[di+6]
+ push word ptr es:[di+8]
+ push word ptr es:[di+10]
+ push word ptr es:[di+12]
+ push word ptr es:[di+14]
+ mov es, ax
+
+ call gmove
+
+ pop word ptr es:[di+14] ; "Copy" source arena to destination
+ pop word ptr es:[di+12]
+ pop word ptr es:[di+10]
+ pop word ptr es:[di+8]
+ pop word ptr es:[di+6]
+ pop word ptr es:[di+4]
+ pop word ptr es:[di+2]
+ pop word ptr es:[di]
+
+ pop si
+ pop ax
+
+; update lruentries
+
+ mov dx,es:[di].ga_lruprev
+ or dx,dx
+ jz no_links
+ cmp [di].gi_lruchain,si
+ jnz didnt_slide_head
+ mov [di].gi_lruchain,es
+didnt_slide_head:
+ cmp dx,si ; Did we move the only entry?
+ jnz many_entries
+ mov es:[di].ga_lrunext,es
+ mov es:[di].ga_lruprev,es
+ jmps no_links
+many_entries:
+ push ds
+ mov ds,dx
+ mov ds:[di].ga_lrunext,es
+ mov ds,es:[di].ga_lrunext
+ mov ds:[di].ga_lruprev,es
+ pop ds
+no_links:
+
+ mov si,es ; Save new busy block location
+ pop es ; ES = a
+ or ax,ax ; Does a.prev need to be restored?
+ jz gslide1 ; No, continue
+ mov es:[di].ga_prev,ax ; Yes, do it
+gslide1:
+
+; update arena prev and next pointers
+
+ pop ax
+ mov es:[di].ga_next,ax ; a.ga_next = b
+ mov dx,es
+ mov es,ax
+ mov es:[di].ga_prev,dx ; b.ga_prev = a
+ pop ax
+ mov es:[di].ga_next,ax ; b.ga_next = c
+ mov dx,es
+ mov es,ax
+ mov es:[di].ga_prev,dx ; c.ga_prev = b
+ mov es,si ; ES = new busy block
+ mov si,es:[di].ga_handle ; SI = handle
+ or si,si
+ jz gslide2
+ cCall AssociateSelector,<si,es>
+gslide2:
+ mov es,es:[bx] ; Move to new free block
+ push bx
+ push cx
+ cCall get_physical_address,<es:[di].ga_next>
+ mov bx,ax
+ mov cx,dx
+ cCall get_physical_address,<es>
+ sub bx,ax
+ sbb cx,dx
+ REPT 4
+ shr cx,1
+ rcr bx,1
+ ENDM
+ mov ax,bx
+ pop cx
+ pop bx
+ mov si,es
+ dec ax
+ mov es:[di].ga_size,ax
+ mov es:[di].ga_flags,0
+
+; update the global free list
+
+ pop ax ; ga_freenext
+ pop dx ; ga_freeprev
+ mov es:[di].ga_freeprev,dx
+ mov es:[di].ga_freenext,ax
+ mov es,dx
+ mov es:[di].ga_freenext,si
+ mov es,ax
+ mov es:[di].ga_freeprev,si
+ mov es,si
+if KDEBUG
+ test si, 1 ; make SI odd for gmarkfree
+ jnz ok
+ INT3_WARN
+ok:
+endif
+ call gmarkfree ; Coalesce new free block
+ mov si,es
+ or ax,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmove ;
+; ;
+; Moves a moveable block into the top part of a free block. ;
+; ;
+; Arguments: ;
+; DS:DI = master object ;
+; ES:0 = arena of destination block ;
+; SI:0 = arena of source block ;
+; ;
+; Returns: ;
+; DS:DI = master object (it may have moved) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; gnotify ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 03:31:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gmove,<PUBLIC,NEAR>
+cBegin nogen
+
+ push es
+ pusha
+
+ cCall get_physical_address,<es> ; Destination arena address
+ add ax, 10h ; Destination is one paragraph
+ adc dx, 0 ; past the arena header
+
+ push ax ; Save to update source
+ push dx ; selectors after the move
+
+ push ax ; Scribbled by SetSelectorBase
+ push dx
+ SetKernelDS es
+ cCall SetSelectorBase,<kr2dsc,dx,ax> ; NOTE kr2dsc has SEG_RING set
+
+ ; While we have destination
+ ; address, see if move will
+ ; be up or down
+ pop cx
+ pop bx ; CX:BX has address of dest
+ cCall get_physical_address,<si> ; Source address
+ cmp dx, cx ; cmp src, dest
+ jne @F
+ cmp ax, bx
+@@:
+ mov cx, 0 ; move to preserve CARRY
+ adc ch, 0
+ push cx ; Save fUpDown, CL = 0
+
+ mov es, si ; ES:DI = arena header of source
+ UnSetKernelDS es
+ push es:[di].ga_size ; Save #paragraphs
+ mov bx, es:[di].ga_handle ; BX = handle of source
+ Handle_To_Sel bl
+
+if KDEBUG
+ cCall get_arena_pointer,<bx>
+ cmp ax, si
+ je @F
+ INT3_ANCIENT
+@@:
+endif
+
+ mov si, bx ; SI = client data selector of source
+ mov cx, bx ; CX = client data selector of dest
+
+ mov ax, GN_MOVE
+ call gnotify ; Call global notify procedure
+ pop dx ; DX = #paragraphs to move
+ pop cx ; CH has fUpDown, CL = 0
+
+ pop bx ; Destination address in registers
+ pop di ; in case we switch stacks
+
+ SetKernelDS es
+ mov fUpDown, ch
+ mov ax,ss ; Are we about to move the stack?
+ cmp ax,si
+ jne stack_no_move
+ mov cx, ax ; Selector does not change!
+ call Enter_gmove_stack ; switch to temporary stack
+stack_no_move:
+ mov [fSwitchStacks],cl ; Remember if we switched
+
+; Save DS value AFTER call to gnotify, as the master object might be the
+; block we are moving and thus changed by the global heap notify proc.
+; IRRELEVANT SINCE IT IS A SELECTOR!!!
+
+ push ds
+ push di ; Re-save destination address -
+ push bx ; we may be on different stack
+ push si ; Save source selector
+ mov di, kr2dsc ; DI = Destination selector array
+
+ mov bx, dx ; # paragraphs to copy
+ xor cx, cx
+ ; Calculate length
+rept 4
+ shl bx, 1
+ rcl cx, 1
+endm
+
+ push cx
+ cCall set_sel_limit,<di> ; Set destination selector array
+ pop cx
+
+ sub bx, 1 ; Now turn into limit
+ sbb cl, 0 ; CX has number of selectors - 1
+
+;
+; At this point, DX = # paragraphs to be moved, SI = source selector,
+; DI = dest selector
+;
+ or dx,dx ; just in case...
+ jnz @f
+ jmps all_moved
+@@:
+ mov bx,dx ; bx = total # paras to move
+
+ cld ; assume moving down
+ mov dx,__AHINCR ; dx = selector increment
+
+ cmp fUpDown,0 ; Moving up or down? Need to
+ jz start_move ; adjust start descriptors if up
+
+ assumes es, nothing
+
+ std
+
+ ; Moving data up. Fudge the address so we copy
+ ; from the end of each segment.
+
+ push dx
+ mov ax, dx ; Selector increment
+ mul cx ; * (number of sels - 1)
+ add si, ax ; Get source and destination selecotors
+ add di, ax ; for last piece of copy
+ pop dx
+ neg dx ; Going backwards through the array
+
+ mov ds, si ; Set source and destination segments
+ mov es, di
+
+ mov cx, bx ; See if partial copy first
+ and cx, 0FFFh ; 64k-1 paragraphs
+ jz move_blk ; exact multiple, go for it
+ ; Not exact, set up first copy by hand
+ sub bx, cx ; This many paragraphs less
+ shl cx, 4 ; byte count
+ mov si, cx
+ shr cx, 1 ; word count
+ jmps move_up
+
+start_move:
+ mov ds,si
+ mov es,di
+
+move_blk:
+ mov cx,1000h ; 1000h paras = 64k bytes
+ cmp bx,cx
+ jae @f
+ mov cx,bx ; less than 64k left
+@@:
+ sub bx,cx ; bx = # paras left to do
+ shl cx,3 ; cx = # words to move this time
+
+ xor si,si ; assume going down
+ cmp dl,0 ; really moving down?
+ jg @F ; yes, jmp, (yes, SIGNED!)
+move_up:
+ dec si ; up: point to last word in segment
+ dec si
+@@:
+ mov di,si
+ rep movsw
+
+ or bx,bx ; more to do?
+ jz all_moved
+
+ ; Adjust source/dest selectors up/down by 64k
+
+ mov si,ds
+ add si,dx
+
+ mov di,es
+ add di,dx
+
+ jmps start_move ; go do the next block
+
+all_moved:
+ pop si ; Source selector array
+
+ pop dx ; New address for source selectors
+ pop ax
+if ALIASES
+ cCall check_for_alias,<si,dx,ax>
+endif
+ cCall set_physical_address,<si> ; Update source selector array
+
+ pop ds ; Restore DS (it might be different)
+
+ SetKernelDS es
+ cmp [fSwitchStacks], 0 ; Switch to new stack if any
+ je move_exit
+ call Leave_gmove_stack
+move_exit:
+
+ popa
+ pop es
+ UnSetKernelDS es
+
+ cld ; Protect people like MarkCl from themselves
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gbestfit ;
+; ;
+; Searches for the largest moveable block that will fit in the passed ;
+; free block. ;
+; ;
+; Arguments: ;
+; ES:DI = free block ;
+; DS:DI = address of global heap information ;
+; CX = #arena entries left to examine ;
+; BX = ga_next or ga_prev ;
+; ;
+; Returns: ;
+; ZF = 1 if block found & moved into free block w/ no extra room. ;
+; ES:DI = busy block before/after new busy block. ;
+; ;
+; ZF = 0 if ES:DI points to a free block, either the ;
+; original one or what is left over after moving a block ;
+; into it. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; DX,SI ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:52:12p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gbestfit,<PUBLIC,NEAR>
+cBegin nogen
+ push es
+ push cx
+ xor si,si ; Have not found anything yet
+ xor ax, ax ; largest block so far
+ mov dx,es:[di].ga_size ; Compute max size to look for
+gbfloop:
+ cmp es:[di].ga_owner,di ; Is this block busy?
+ je gbfnext ; No, continue
+ cmp es:[di].ga_size,dx ; Yes, is block bigger than max size?
+ ja gbfnext ; Yes, continue
+ call gmoveable ; Yes, is it moveable
+ jz gbfnext ; No, continue
+ cmp es:[di].ga_size,ax ; Is it bigger than the largest so far?
+ jbe gbfnext ; No, continue
+gbf1st:
+ mov si,es ; Yes, remember biggest block
+ mov ax,es:[di].ga_size ; ...and size
+gbfnext:
+ mov es,es:[bx] ; Skip past this block
+ loop gbfloop
+ pop cx ; All done looking
+ pop es
+ or si,si ; Did we find a block?
+ jz gbestfit1 ; No, return with Z flag
+ call gmovebusy ; Yes, move it into free block
+gbestfit1:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmovebusy ;
+; ;
+; Subroutine to move a busy block to a free block of the same size, ;
+; preserving the appropriate arena header fields, freeing the old ;
+; busy block and updating the handle table entry to point to the ;
+; new location of the block. ;
+; ;
+; Arguments: ;
+; BX = ga_prev or ga_next ;
+; SI = old busy block location ;
+; ES:DI = new busy block location ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; ES:DI = points to new busy block arena header ;
+; SI:DI = points to free block where block used to be ;
+; (may be coalesced) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; BX,CX,DX ;
+; ;
+; Registers Destroyed: ;
+; AX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Jun 22, 1987 11:39:56p -by- David N. Weise [davidw] ;
+; Made it jump off to gslidecommon when appropriate. ;
+; ;
+; Mon Oct 27, 1986 10:17:16p -by- David N. Weise [davidw] ;
+; Made the lru list be linked arenas, so we must keep the list correct ;
+; here. ;
+; ;
+; Thu Sep 25, 1986 05:49:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gmovebusy,<PUBLIC,NEAR>
+cBegin nogen
+ push cx
+ push dx
+ mov ax,es
+ mov cx,es:[di].ga_size ; CX = size of destination
+ cmp es:[di].ga_owner,di ; Is destination busy?
+ mov es,si
+ mov dx,es:[di].ga_size ; DX = size of source
+ jne gmbexactfit ; Yes, then dont create extra block
+ cmp cx,dx ; No, are source and destination same size?
+ je gmbexactfit ; Yes, then dont create extra block
+
+ mov es,ax ; ES = destination
+ cmp es:[di].ga_next,si ; Are the two blocks adjacent?
+ ; If so we want to do a gslide.
+ mov ax,si ; AX = source
+ jnz not_adjacent
+ cmp bx,ga_next
+ jnz gmb_sliding_up
+ push es:[bx] ; gslide will invalidate this block
+ jmps gmb_slide
+gmb_sliding_up:
+ push es ; gslide will invalidate this block
+gmb_slide:
+ call gslidecommon ; C - calling convention
+ call free_sel ; free the pushed selector
+ jmp gmbexit
+not_adjacent:
+ push si ; Save busy block address
+ call gslidecommon ; Call common code to do the move
+ inc [di].hi_count ; Just created a new arena entry
+ mov ax,es ; Save new free block address
+ pop es ; Get old busy block address
+ xor si,si
+ call gmarkfree ; Mark as free and coalesce
+ mov si,es
+ mov es,ax ; Restore new free block address
+ or ax,ax ; Return with Z flag clear.
+ jmps gmbexit
+
+gmbexactfit:
+ mov ch,es:[di].ga_count
+ mov cl,es:[di].ga_flags
+ push es:[di].ga_owner
+ push es:[di].ga_lruprev
+ push es:[di].ga_lrunext
+ mov es,ax
+ jne it_wasnt_free
+ call gdel_free
+it_wasnt_free:
+ pop es:[di].ga_lrunext ; Copy client words to new header
+ pop es:[di].ga_lruprev
+ pop es:[di].ga_owner
+ mov es:[di].ga_flags,cl
+ mov es:[di].ga_count,ch
+ cmp es:[di].ga_lruprev,di
+ jz no_link
+ cmp [di].gi_lruchain,si
+ jnz didnt_move_head
+ mov [di].gi_lruchain,es
+didnt_move_head:
+ push ds
+ mov ds,es:[di].ga_lruprev
+ mov [di].ga_lrunext,ax ; Update the lru list
+ mov ds,es:[di].ga_lrunext
+ mov [di].ga_lruprev,ax ; Update the lru list
+ pop ds
+no_link:
+ mov es, ax ; ES is destination of copy
+
+ call gmove ; Move the client data
+ mov es, si
+ xor si,si
+ call gmarkfree ; Free old block
+ mov cx,es
+ mov es,ax
+ or si,si
+ jz gmb1
+ mov es:[di].ga_handle,si ; Set back link to handle in new block
+ cCall AssociateSelector,<si,es> ; and associate with new arena
+ xor dx,dx ; Set Z flag
+gmb1:
+ mov si,cx
+gmbexit:
+ pop dx
+ pop cx
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmoveable ;
+; ;
+; Tests if an ojbect is moveable. Non moveable blocks are: ;
+; Fixed blocks, moveable blocks that are locked, moveable blocks ;
+; going up, discardable code going down. ;
+; ;
+; Arguments: ;
+; ES:DI = arena header of object ;
+; DS:DI = address of global heap information ;
+; BX = ga_next or ga_prev ;
+; ;
+; Returns: ;
+; ZF = 0 if object moveable ;
+; ZF = 1 if object not moveable ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Thu Sep 25, 1986 05:42:17p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gmoveable,<PUBLIC,NEAR>
+cBegin nogen
+ test es:[di].ga_handle,GA_FIXED ; If no handle then fixed
+ jnz gmfixed
+
+ cmp es:[di].ga_count,bh ; If locked then fixed
+ jne gmfixed
+
+ test [di].gi_cmpflags,BOOT_COMPACT ; If fb_init_EMS then all down
+ jnz gmokay
+ test es:[di].ga_flags,GA_DISCCODE ; If discardable code
+ jz gmnotcode
+ cmp bl,ga_next ; Discardable code can only
+ ret ; move up in memory
+gmnotcode:
+ cmp [di].gi_reserve,di ; If no reserved code area?
+ je gmokay ; Then anything can move up
+ cmp bl,ga_prev ; Otherwise can only move down
+ ret ; in memory
+gmfixed:
+ or bh,bh ; Return with ZF = 1 if
+ ret ; not moveable
+gmokay:
+ or bl,bl
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gdiscard ;
+; ;
+; Subroutine to walk LRU chain, discarding objects until the #paras ;
+; discarded, plus the biggest free block is greater than the #paras ;
+; we are looking for. ;
+; ;
+; Arguments: ;
+; AX = size of largest free block so far ;
+; DX = minimum #paras needed ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; ZF = 0 if one or more objects discarded. ;
+; ZF = 1 if no objects discarded. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; Mon Oct 27, 1986 09:34:45p -by- David N. Weise [davidw] ;
+; The glru list was reworked to link the arenas, not using the handle ;
+; table as a middle man. Because of this change glruprev was moved ;
+; inline and the code shortened up again. ;
+; ;
+; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Thu Sep 25, 1986 05:45:31p -by- David N. Weise [davidw] ;
+; Shortened it up a bit and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gdiscard,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ push dx
+
+ mov [di].hi_ncompact,0 ; Clear compaction flag
+ sub dx,ax ; How much to discard before
+ mov [di].hi_distotal,dx ; compacting again.
+
+ xor bx,bx ; BX = amount of DISCCODE below fence
+ test [di].gi_cmpflags,GA_DISCCODE
+ jnz fence_not_in_effect0
+
+ mov cx,[di].gi_lrucount
+ jcxz fence_not_in_effect0 ; All done if LRU chain empty
+ mov es,[di].gi_lruchain ; ES -> most recently used (ga_lruprev
+ push dx
+gdloop0: ; is the least recently used)
+ mov es,es:[di].ga_lruprev ; Move to next block in LRU chain
+ test es:[di].ga_flags,GA_DISCCODE ; Discardable code?
+ jz gdloop0a ; No, ignore
+ mov ax,es
+ cCall get_physical_address,<ax>
+ cmp word ptr [di].gi_disfence_hi,dx ; Yes, is this code fenced off?
+ ja gdloop0b
+ jb gdloop0a ; No, ignore
+ cmp word ptr [di].gi_disfence_lo,ax ; Yes, is this code fenced off?
+ jbe gdloop0a ; No, ignore
+gdloop0b:
+ add bx,es:[di].ga_size ; Yes, accumulate size of discardable
+gdloop0a: ; code below the fence
+ loop gdloop0
+ pop dx
+
+fence_not_in_effect0:
+ mov es,[di].gi_lruchain
+ cmp [di].gi_lrucount, 0
+ je gdexit
+ push es:[di].ga_lruprev
+ push [di].gi_lrucount
+gdloop:
+ pop cx
+ pop ax
+ jcxz gdexit ; No more see if we discarded anything
+ mov es, ax ; ES on stack may be invalid if count 0
+ dec cx
+ push es:[di].ga_lruprev ; Save next handle from LRU chain
+ push cx
+ cmp es:[di].ga_count,0 ; Is this handle locked?
+ jne gdloop ; Yes, ignore it then
+ test [di].gi_cmpflags,GA_DISCCODE
+ jnz fence_not_in_effect
+ test es:[di].ga_flags,GA_DISCCODE
+ jz fence_not_in_effect
+ or bx,bx ; Discardable code below fence?
+ jz gdloop ; No, cant discard then
+ cmp bx,es:[di].ga_size ; Yes, more than size of this block?
+ jb gdloop ; No, cant discard then
+ sub bx,es:[di].ga_size ; Yes, reduce size of code below fence
+fence_not_in_effect:
+ push bx
+ call DiscardCodeSegment
+ pop bx
+ jnz discarded_something
+ test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
+ jz gdloop
+ jmps enough_discarded
+discarded_something:
+ test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
+ jnz enough_discarded
+ or [di].hi_ncompact,1 ; Remember we discarded something
+ sub [di].hi_distotal,ax ; Have we discarded enough yet?
+ ja gdloop ; No, look at next handle
+enough_discarded:
+ pop cx ; Flush enumeration counter
+ pop cx ; and saved ES
+gdexit:
+ cmp [di].hi_ncompact,0 ; Return with Z flag set or clear
+ pop dx
+ pop ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; DiscardCodeSegment ;
+; ;
+; Discards the given segment. Calls gnotify to fix stacks, entry ;
+; points, thunks, and prologs. Then glrudel removes it from the lru ;
+; list and gmarkfree finally gets rid of it. ;
+; ;
+; Arguments: ;
+; DS:DI => BurgerMaster ;
+; ES = Address of segment to discard ;
+; ;
+; Returns: ;
+; AX = size discarded ;
+; ZF = 0 ok ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX ;
+; ;
+; Calls: ;
+; gnotify ;
+; glrudel ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+; Fri Jun 12, 1987 -by- Bob Matthews [bobm] ;
+; Made FAR. ;
+; ;
+; Sun Apr 19, 1987 12:05:40p -by- David N. Weise [davidw] ;
+; Moved it here from InitTask, so that FirstTime could use it. ;
+;-----------------------------------------------------------------------;
+
+cProc DiscardCodeSegment,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ mov bx,es:[di].ga_handle ; BX = handle
+ mov al,GN_DISCARD ; AX = GN_DISCARD
+ push es
+ call gnotify
+ pop es
+ jz cant_discard ; Skip this handle if not discardable
+ call glrudel ; Delete handle from LRU chain
+ push es:[di].ga_owner ; Save owner field
+ mov ax,es:[di].ga_size ; Save size
+ xor si,si
+ call gmarkfree ; Free the block associated with this handle
+ mov bx,si
+ pop cx ; Owner
+ cCall mark_sel_NP,<bx,cx>
+cant_discard:
+ pop si
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------
+; ShrinkHeap
+;
+; This routine finds free partitions and returns them to DPMI
+;
+; Input:
+; ds:di=>BurgerMaster
+;
+; Output:
+; none
+;
+
+ public ShrinkHeap
+ShrinkHeap proc near
+
+ push si
+ push cx
+ push bx
+ push ax
+ push ds
+ push es
+ push bp
+ mov bp,sp
+ sub sp,8
+SelFirst equ word ptr [bp - 2]
+SelLast equ word ptr [bp - 4]
+SelFree equ word ptr [bp - 6]
+SelBurgerMaster equ word ptr [bp - 8]
+ mov SelBurgerMaster,ds
+
+ SetKernelDS
+ ;
+ ; Iterate over each of the DPMI blocks
+ ; there should be fewer dpmi blocks than blocks on the free list
+ ;
+ mov cx,DpmiBlockCount
+ mov si,offset DpmiMemory
+
+ ;
+ ; If this block doesn't exist, go on to the next one
+ ;
+sh30: mov ax,[si].DBSel
+ cmp ax,di
+ je sh60
+
+ ;
+ ; Found an in use dpmi block
+ ;
+ dec cx
+
+ ;
+ ; Check to see if the next block is free
+ ;
+ mov SelFirst,ax
+ mov es,ax
+ mov bx,es:[di].ga_next
+ mov es,bx
+ mov SelFree,bx
+ cmp es:[di].ga_owner,di
+ jne sh60
+
+ ;
+ ; Check to see if it is followed by a not there block
+ ; (Note: we should check for -1 in the future so we can
+ ; free the last block as well)
+ ;
+ mov bx,es:[di].ga_next
+ mov SelLast,bx
+ mov es,bx
+ cmp es:[di].ga_owner,GA_NOT_THERE
+ jne sh60
+
+ ;
+ ; Found one, so remove the free block
+ ;
+ mov es,SelFree
+ mov ds,SelBurgerMaster
+ UnsetKernelDS
+ call gdel_free
+
+ ;
+ ; Fix up the global information
+ ;
+ sub [di].hi_count,3
+
+ ;
+ ; Unlink from the heap
+ ;
+ mov es,SelFirst
+ mov es,es:[di].ga_prev
+ mov ds,SelLast
+ mov ds,ds:[di].ga_next
+ mov ds:[di].ga_prev,es
+ mov es:[di].ga_next,ds
+
+ ;
+ ; Free all of the selectors
+ ;
+ cCall free_sel,<SelFirst>
+ cCall free_sel,<SelLast>
+ cCall free_sel,<SelFree>
+
+ ;
+ ; Give the block back to Dpmi
+ ;
+ push si
+ push di
+ SetKernelDS
+ mov di,[si].DBHandleLow
+ mov si,[si].DBHandleHigh
+ DPMICALL 502h
+ pop di
+ pop si
+
+ ;
+ ; Decrease the number of dpmi blocks
+ ;
+ dec DpmiBlockCount
+
+ ;
+ ; Forget the block
+ ;
+ mov [si].DBSel,di
+
+ ;
+ ; move on to the next iteration
+ ;
+sh60: add si,size DpmiBlock
+ or cx,cx
+ jz sh70
+
+ jmp sh30
+
+sh70: mov sp,bp
+ pop bp
+ pop es
+ pop ds
+ pop ax
+ pop bx
+ pop cx
+ pop si
+ ret
+ShrinkHeap endp
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/kernel31/2ginterf.asm b/private/mvdm/wow16/kernel31/2ginterf.asm
new file mode 100644
index 000000000..ebae4efbe
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2ginterf.asm
@@ -0,0 +1,2039 @@
+ page ,132
+ TITLE GINTERF - Global Memory Manager interface procedures
+
+.sall
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+include protect.inc
+ifdef WOW
+include wowkrn.inc
+include vint.inc
+endif
+.list
+
+CheckHeap MACRO name
+local a
+if KDEBUG
+ extrn CheckGlobalHeap :near
+ call CheckGlobalHeap
+ jnc a
+ or ax,ERR_GMEM
+ xor bx,bx
+ kerror <>,<&name: Invalid global heap>,dx,bx
+a:
+endif
+ endm
+
+PROFILE MACRO function
+ pushf
+ add word ptr ds:[di.gi_stats][c&function], 1
+ adc word ptr ds:[di.gi_stats][c&function][2], 0
+ popf
+ ENDM
+
+ifdef WOW
+externFP WowCursorIconOp
+externFP WowDdeFreeHandle
+endif
+
+externW pStackTop
+externW pStackMin
+externW pStackBot
+
+DataBegin
+
+externB Kernel_Flags
+externB fBooting
+externW hGlobalHeap
+externW pGlobalHeap
+externW curTDB
+externW loadTDB
+externW hExeHead
+
+GSS_SI dw 0
+GSS_DS dw 0
+GSS_RET dd 0
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+if SDEBUG
+externNP DebugFreeSegment
+endif
+
+externNP galloc
+externNP grealloc
+externNP gfree
+externNP glock
+externNP gunlock
+externNP gfreeall
+externNP galign
+externNP gcompact
+externNP gmovebusy
+externNP gsearch
+externNP genter
+externNP gleave
+externNP gavail
+externNP glrutop
+externNP glrubot
+externNP glrudel
+externNP glruadd
+externNP gmarkfree
+;externNP gdiscard
+
+externNP get_arena_pointer
+externNP pdref
+externNP cmp_sel_address
+externNP get_physical_address
+externNP set_physical_address
+externNP set_sel_limit
+externNP alloc_data_sel
+externFP FreeSelector
+externNP GetAccessWord
+externNP MyGetAppCompatFlags
+if ALIASES
+externNP add_alias
+externNP delete_alias
+externNP get_alias_from_original
+externNP get_original_from_alias
+externNP wipe_out_alias
+endif
+externNP ShrinkHeap
+externNP DpmiProc
+externNP HackCheck
+
+if KDEBUG
+externFP OutputDebugString
+
+ThisIsForTurboPascal:
+ db "A program has attempted an invalid selector-to-handle conversion.",13,10,"Attempting to correct this error.",13,10,0
+endif
+
+if ROM
+externNP GetOwner
+endif
+
+if KDEBUG
+externNP xhandle_norip
+endif
+
+;-----------------------------------------------------------------------;
+; gbtop ;
+; ;
+; Converts a 32-bit byte count to a 16-bit paragraph count. ;
+; ;
+; Arguments: ;
+; AX = allocation flags or -1 if called from GlobalCompact ;
+; BX = stack address of 32-bit unsigned integer ;
+; DX = handle being reallocated or zero ;
+; DS:DI = address of GlobalInfo for global heap ;
+; ;
+; Returns: ;
+; AX = updated allocation flags ;
+; BX = #paragraphs needed to contain that many bytes ;
+; CX = owner value to use ;
+; DX = handle being reallocated or zero ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Dec 03, 1986 10:20:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gbtop,<PUBLIC,NEAR>
+cBegin nogen
+ push dx
+ mov dx,ss:[bx][2]
+ mov bx,ss:[bx]
+ mov cx,4
+ add bx,15
+ adc dx,0
+ jnc gbtop1
+ dec dx
+ dec bx
+gbtop1:
+ shr dx,1
+ rcr bx,1
+ loop gbtop1
+ or dx,dx ; Requesting more than 1 meg?
+ jz gbtop2
+ mov bx,0FFFFh ; Yes, set to bogus value - this can NEVER succeed
+gbtop2:
+ pop dx
+ inc ax
+ jnz gbtop2a
+ ret ; All done if called from GlobalCompact
+gbtop2a:
+ dec ax
+
+ push ax
+if ROM
+ cCall GetOwner,<[bp].savedCS>
+ mov es,ax ; ES has owner exe hdr selector
+else
+ cCall get_arena_pointer,<[bp].savedCS>
+ mov es,ax ; ES has arena of calling CS (if known)
+endif
+ pop ax
+
+ push ds
+ SetKernelDS
+
+ cmp fBooting,0 ; Done booting?
+ jne gbtop3 ; No, must be KERNEL allocating then
+if ROM
+ mov cx,es
+ cmp cx,hExeHead ; Is the KERNEL calling us?
+else
+ mov cx,hExeHead ; CX = KERNEL exe header
+ cmp cx,es:[di].ga_owner ; Is the KERNEL calling us?
+endif
+ je gbtop3 ; Yes, let him party
+
+ and ax,not GA_INTFLAGS ; No, then cant use these flags
+gbtop3:
+ pop ds
+ UnSetKernelDS
+
+ test ah,GA_ALLOC_DOS ; Dos land allocations can never ever
+ jz gbtop3b ; be moved once allocated--make sure
+ and al,not GA_MOVEABLE ; caller isn't confused about this
+gbtop3b:
+
+ mov cl,GA_SEGTYPE ; Isolate segment type bits in CL
+ and cl,al
+ mov [di].gi_cmpflags,al ; Save flags for gcompact
+ and [di].gi_cmpflags,CMP_FLAGS
+
+ push ds
+ SetKernelDS
+
+ test al, GA_MOVEABLE ; Is this fixed?
+ jz gbtop4 ; yes, must go low
+ife ROM
+ cmp fBooting, 1 ; Booting?
+ je @F ; yes, allocate high
+endif
+ test cl, GA_DISCCODE ; no, only discardable code goes high
+ jz gbtop4
+@@:
+ or al, GA_ALLOCHIGH
+gbtop4:
+ pop ds
+ UnSetKernelDS
+
+ push ax ; Under Win1.0x ANY bit in 0Fh meant
+ mov al,HE_DISCARDABLE ; make discardable.
+ and ah,al ; Under Win2.0x ONLY 01h or 0Fh means
+ cmp ah,al ; discardable.
+ pop ax
+ jnz gbtop4a
+ and ah,not HE_DISCARDABLE ; Yes, convert to boolean value
+ or ah,GA_DISCARDABLE
+gbtop4a:
+
+ and ah,NOT GA_SEGTYPE ; Clear any bogus flags
+ or ah,cl ; Copy segment type bits
+ test ah,GA_SHAREABLE ; Shared memory request?
+ jz GetDefOwner ; No, default action
+
+ mov cx, es ; Arena of calling CS
+ jcxz no_owner_yet
+
+ife ROM
+ mov cx,es:[di].ga_owner ; owner of calling code segment
+endif
+no_owner_yet:
+ ret
+cEnd nogen
+
+
+cProc GetDefOwner,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov cx,curTDB
+ jcxz xxxx
+ mov es,cx
+ mov cx,loadTDB
+ jcxz xxx
+ mov es,cx
+xxx: mov cx,es:[TDB_PDB]
+ inc cx
+xxxx: dec cx
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+
+; The remainder of this file implements the exported interface to the
+; global memory manager. A summary follows:
+
+; HANDLE far PASCAL GlobalAlloc( WORD, DWORD );
+; HANDLE far PASCAL GlobalReAlloc( HANDLE, DWORD, WORD );
+; HANDLE far PASCAL GlobalFree( HANDLE );
+; HANDLE far PASCAL GlobalFreeAll( WORD );
+; char far * far PASCAL GlobalLock( HANDLE );
+; BOOL far PASCAL GlobalUnlock( HANDLE );
+; DWORD far PASCAL GlobalSize( HANDLE );
+; DWORD far PASCAL GlobalCompact( DWORD );
+; #define GlobalDiscard( h ) GlobalReAlloc( h, 0L, GMEM_MOVEABLE )
+; HANDLE far PASCAL GlobalHandle( WORD );
+; HANDLE far PASCAL LockSegment( WORD );
+; HANDLE far PASCAL UnlockSegment( WORD );
+
+
+cProc IGlobalAlloc,<PUBLIC,FAR>,<si,di>
+ parmW flags
+ parmD nbytes
+cBegin
+ call genter ; About to modify memory arena
+ PROFILE GLOBALALLOC
+
+ cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
+ test al, GACF_IGNORENODISCARD ; for selected modules
+ mov ax, flags
+ jz @f
+ call IsKernelCalling ; needs caller's CS @ [bp+4]
+ jz @f ; skip hack if kernel calling us
+ and al, NOT GA_NODISCARD
+@@:
+
+ifdef WOW
+ ; compatibility: amipro calls globalallocs some memory for storing one
+ ; of its ini files and accesses the lpstring[byte after the null char].
+ ; This happens to be harmless on most occasions because we roundoff the
+ ; allocation to next 16byte boundary. However if the allocation request
+ ; is for exactly 0x10 bytes we allocate a selector of exactly 0x10 bytes
+ ; and thus amipro GPs when it access the byte seg:0x10
+ ;
+ ; So here is a cheap fix.
+ ; - nanduri
+
+ cmp word ptr nbytes+2, 0
+ jnz @F
+ cmp word ptr nbytes, 010h
+ jne @F
+ inc word ptr nbytes
+@@:
+endif
+
+ xor dx,dx ; No handle
+ lea bx,nbytes ; Convert requested bytes to paragraphs
+ call gbtop ; ... into BX
+ call galloc
+ CheckHeap GlobalAlloc
+ call gleave
+ mov es,di
+cEnd
+
+cProc IGlobalReAlloc,<PUBLIC,FAR>,<si,di>
+ parmW handle
+ parmD nbytes
+ parmW rflags
+cBegin
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test byte ptr handle,7
+ jnz @F
+if KDEBUG
+ Trace_Out "GlobalReAlloc:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ INT3_WARN
+endif
+ dec handle
+@@:
+
+ call genter ; About to modify memory arena
+ PROFILE GLOBALREALLOC
+
+ cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
+ test al, GACF_IGNORENODISCARD ; for selected modules
+ mov ax, rflags
+ jz @f
+ call IsKernelCalling ; needs caller's CS @ [bp+4]
+ jz @f ; skip hack if kernel calling us
+ and al, NOT GA_NODISCARD
+@@:
+ mov dx,handle
+ ;mov ax,rflags
+ lea bx,nbytes ; Convert requested bytes to paragraphs
+ call gbtop ; ... into BX
+ call grealloc
+gr_done:
+ CheckHeap GlobalReAlloc
+ call gleave
+ mov es,di
+cEnd
+
+cProc DiscardTheWorld,<PUBLIC,NEAR>
+cBegin
+ call genter
+ mov [di].gi_cmpflags, GA_DISCCODE
+ mov dx, -1
+ Trace_Out "Discarding the World."
+ call gcompact
+ call gleave
+cEnd
+
+
+; Returns with Z flag set if ss:[bp+4] is a kernel code segment selector.
+; Uses: DX, flags.
+
+cProc IsKernelCalling,<PUBLIC,NEAR>
+cBegin nogen
+ mov dx, [bp+4] ; CS of GlobalAlloc caller
+ cmp dx, IGROUP
+ jz @f
+ cmp dx, _NRESTEXT
+ jz @f
+ cmp dx, _MISCTEXT
+@@:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; GlobalFree ;
+; ;
+; Frees the given object. If the object lives in someone elses banks ;
+; then the argument MUST be a handle entry. ;
+; ;
+; Arguments: ;
+; parmW handle ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
+; Added support for EMS and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalFree,<PUBLIC,FAR>,<si,di>
+ parmW handle
+ifdef WOW
+DsOnStack equ [bp][-2]
+endif
+
+; if you add any local params or make this nogen or something similar,
+; the references to [bp][-2] to access DS on stack will need to change!
+
+cBegin
+ call genter ; About to modify memory arena
+ PROFILE GLOBALFREE
+ xor ax,ax ; In case handle = 0.
+ mov dx,handle
+ or dx,dx
+ jnz @F
+ jmp nothing_to_free
+@@:
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test dl,7
+ jnz @F
+if KDEBUG
+ Trace_Out "GlobalFree:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ INT3_WARN
+endif
+ dec dx
+ mov handle,dx
+@@:
+
+if ALIASES
+ call wipe_out_alias
+endif
+ push dx
+ call pdref ; returns dx=handle, ax=selector
+ pushf ; save pdref Z flag return
+
+ifdef WOW
+;
+; [bp][-2] has been changed to DsOnStack
+;
+endif
+
+ cmp ax,DsOnStack ; Are we about to free the DS on
+ jz short yup ; the stack and GP?
+ cmp dx,DsOnStack
+ jnz short nope
+yup: xor dx,dx ; Yup, zero DS image on stack...
+ mov DsOnStack,dx
+nope:
+ popf ; flags from pdref, Z set if discarded
+ pop dx
+
+ jz @f ; discarded can be freed, but has
+ ; no arena pointer
+ mov bx, es ; Invalid handle if arena ptr = 0
+ or bx, bx
+ jz nothing_to_free
+@@:
+
+if KDEBUG
+ or si,si
+ jz freeo
+ or ch,ch ; Debugging check for count underflow
+ jz freeo
+ pusha
+ xor bx,bx
+ kerror ERR_GMEMUNLOCK,<GlobalFree: freeing locked object>,bx,handle
+ popa
+freeo:
+endif
+
+ifdef WOW
+ test cl, GAH_CURSORICON ; call to pdref above sets cl
+ jz gf_wowdde
+ push ax ; save
+ push bx
+ push dx
+ push es
+
+ push handle
+ push FUN_GLOBALFREE
+ call WowCursorIconOp
+ or ax, ax ; if TRUE 'free' else 'dont free, fake success'
+
+ pop es
+ pop dx
+ pop bx
+ pop ax ; restore
+
+ jnz gf_notglobalicon
+
+ xor ax, ax ; fake success
+ xor cx, cx
+ jmps nothing_to_free
+
+gf_wowdde:
+ test cl, GAH_WOWDDEFREEHANDLE ; call to pdref above sets cl
+ jz gf_noticon
+
+ push ax ; save
+ push bx
+ push dx
+ push es
+
+ push handle
+ call WowDdeFreeHandle
+ or ax, ax ; if TRUE 'free' else 'dont free, fake success'
+
+ pop es
+ pop dx
+ pop bx
+ pop ax ; restore
+
+ jnz gf_notglobalicon
+
+ xor ax, ax ; fake success
+ xor cx, cx
+ jmps nothing_to_free
+
+gf_notglobalicon:
+gf_noticon:
+endif
+
+ xor cx,cx ; Dont check owner field
+ call gfree
+
+
+nothing_to_free:
+ CheckHeap GlobalFree
+ call gleave
+ mov es,di
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalFreeAll ;
+; ;
+; Frees all of the global objects belonging to the given owner. ;
+; ;
+; Arguments: ;
+; parmW id ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
+; Added support for EMS and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc GlobalFreeAll,<PUBLIC,FAR>,<si,di>
+ parmW id
+cBegin
+ call genter ; About to modify memory arena
+ PROFILE GLOBALFREEALL
+ mov cx,1
+ push cx
+ mov dx,id ; Get id to match with
+ or dx,dx ; Is it zero?
+ jnz all1 ; No, continue
+ call GetDefOwner ; Yes, CX = default task owner to free
+ mov dx,cx
+all1:
+if SDEBUG
+ mov es,[di].hi_first ; ES:DI points to first arena entry
+ mov cx,[di].hi_count ; CX = #entries in the arena
+all2:
+ cmp es:[di].ga_owner,dx
+ jne all3
+ mov ax, es:[di].ga_handle
+ Handle_To_Sel al
+ push cx
+ push dx
+ cCall DebugFreeSegment,<ax,0>
+ pop dx
+ pop cx
+all3:
+ mov es,es:[di].ga_next ; Move to next block
+ loop all2 ; Back for more if there (may go extra times
+ ; because of coalescing, but no great whoop)
+endif
+ call gfreeall
+ pop cx
+ CheckHeap GlobalFreeAll
+ call gleave
+ mov es,di
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; xhandle ;
+; ;
+; Returns the handle for a global segment. ;
+; ;
+; Arguments: ;
+; Stack = sp -> near return return address ;
+; sp+2 -> far return return address of caller ;
+; sp+6 -> segment address parameter ;
+; ;
+; Returns: ;
+; Old DS,DI have been pushed on the stack ;
+; ;
+; ZF= 1 if fixed segment. ;
+; AX = handle ;
+; ;
+; ZF = 0 ;
+; AX = handle ;
+; BX = pointer to handle table entry ;
+; CX = flags and count word from handle table ;
+; DX = segment address ;
+; ES:DI = arena header of object ;
+; DS:DI = master object segment address ;
+; ;
+; Error Returns: ;
+; AX = 0 if invalid segment address ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Oct 16, 1986 02:40:08p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc xhandle,<PUBLIC,NEAR>
+cBegin nogen
+ pop dx ; Get near return address
+ mov bx,sp ; Get seg parameter from stack
+ mov ax,ss:[bx+4]
+ cmp ax,-1 ; Is it -1?
+ jnz xh1
+ mov ax,ds ; Yes, use callers DS
+xh1: inc bp
+ push bp
+ mov bp,sp
+ push ds ; Save DS:DI
+ push di
+ call genter
+ push dx
+ mov dx,ax
+ push si
+
+ call pdref
+
+ mov dx,ax ; get seg address in DX
+ jz xhandle_ret ; invalid or discarded handle
+ mov bx,si
+ or si,si
+ jz xhandle_ret
+ mov ax,si
+
+xhandle_ret:
+ pop si
+ ret
+cEnd nogen
+
+
+cProc GlobalHandleNorip,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+if KDEBUG
+ call xhandle_norip
+ jmp xhandlex
+endif
+cEnd nogen
+
+
+cProc IGlobalHandle,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall MyLock,<selector>
+ xchg ax, dx
+cEnd
+
+
+cProc MyLock,<PUBLIC,NEAR>
+; parmW selector
+cBegin nogen
+ mov bx, sp
+ xor ax, ax ; In case LAR fails
+ xor dx, dx
+ lar ax, ss:[bx+2]
+ jnz ML_End ; LAR failed, get out
+ test ah, DSC_PRESENT
+ jz @F
+
+ push ds ; Do quick conversion for present
+ SetKernelDS ; selector
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall get_arena_pointer,<ss:[bx+2]>
+
+ ;** Fix for bugs #9106 and (I think) #9102
+ or ax,ax ;Did get_arena_pointer fail?
+ jnz ml_got_arena ;No, skip this
+ife ROM
+ ;** If we get here, it's only because get_arena_pointer failed.
+ ;** This happens with any non-heap selector.
+ pop ds
+ jmps ML_End ;Return NULL instead of GP faulting
+else
+ ;** get_arena_pointer fails when called with a ROM segment selector
+ ;** so just assume that's what happened and return the selector
+ mov ax,ss:[bx+2] ; Assume that's what happened and
+ jmps ml_ret ; just return the selector
+endif
+ml_got_arena:
+ mov ds, ax
+ mov ax, ds:[ga_handle]
+ml_ret:
+ pop ds
+ mov dx, ax
+ Handle_To_Sel al
+ML_End:
+ ret 2
+
+@@:
+ pop ax ; Convert to far call for xhandle
+ push cs
+ push ax
+ call xhandle ; Go around the houses
+ PROFILE GlobalHandle
+ xchg ax, dx
+ jmp xhandlex
+cEnd nogen
+
+
+cProc ILockSegment,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ PROFILE LOCKSEGMENT
+ jz @F ; Ignore invalid or discarded objects
+ test cl,GA_DISCARDABLE
+ jz @F
+ call glock
+@@:
+ jmp xhandlex
+cEnd nogen
+
+
+cProc IGlobalFix,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ PROFILE GLOBALFIX
+ jnz igf5
+ jmp xhandlex ; Ignore invalid or discarded objects
+igf5:
+ call glock
+ jmp xhandlex
+cEnd nogen
+
+
+cProc IUnlockSegment,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ PROFILE UNLOCKSEGMENT
+ jz xhandlex ; Ignore invalid or discarded objects
+ test cl,GA_DISCARDABLE
+ jz xhandlex
+ call gunlock
+ jmps xhandlex
+cEnd nogen
+
+
+cProc IGlobalUnfix,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ PROFILE GLOBALUNFIX
+ jz xhandlex ; Ignore invalid or discarded objects
+ call gunlock
+ jmps xhandlex
+cEnd nogen
+
+
+cProc IGlobalSize,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ PROFILE GLOBALSIZE
+ jnz gs1 ; Continue if valid handle
+ or dx,dx
+ jnz gs1
+ xor ax,ax ; Return zero if invalid handle
+ jmps xhandlex
+gs1: mov ax, es ; Invalid handle if arena ptr = 0
+ or ax, ax
+ jz gs4
+gs2: mov ax,es:[di].ga_size ; Get size in paragraphs
+gs2a: push ax
+ xor dx,dx ; Returning a long result
+ mov cx,4
+gs3: shl ax,1
+ rcl dx,1
+ loop gs3
+if 0
+ ; This hack should be enabled for Simcity when its other problems
+ ; are fixed on RISC (aka with krnl286).
+ push ds
+ push dx
+ push ax
+ cCall hackcheck,<handle>
+ or ax,ax
+ jz gsN
+ pop ax
+ pop dx
+ mov ax,02000h
+ xor dx,dx
+ push dx
+ push ax
+gsN:
+ pop ax
+ pop dx
+ pop ds
+endif
+ pop cx ; Return number paragraphs in CX
+ jmps xhandlex
+gs4: xor dx, dx
+ jmps xhandlex
+cEnd nogen
+
+cProc IGlobalFlags,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ PROFILE GLOBALFLAGS
+ xchg cl,ch ; Return lock count in low half
+ mov ax,cx ; Let caller do jcxz to test failure
+xhandlex:
+ call gleave
+ mov es,di ; don't return arbitrary selector
+ pop di
+ pop ds
+ pop bp
+ dec bp
+ ret 2
+cEnd nogen
+
+cProc IGlobalLock,<PUBLIC,FAR>
+ parmW handle
+ifdef WOW
+ localW gflags
+ localW accword
+endif
+
+cBegin
+ifdef WOW
+ mov gflags,0
+endif
+ xor dx, dx ; Assume failure
+ cmp handle, -1
+ jne @F
+ mov handle, ds
+@@:
+ cCall GetAccessWord,<handle>
+ifdef WOW
+ mov accword, ax
+endif
+ test al, DSC_PRESENT ; Is it present?
+ jz GL_exit
+ mov dx, handle ; OK, will return something
+ Handle_To_Sel dl ; Turn parameter into a selector
+ifndef WOW
+ test ah, DSC_DISCARDABLE ; Is it discardable
+ jz GL_exit ; no, Lock is a nop
+endif
+
+ cCall get_arena_pointer,<dx> ; Discardable, get its arena
+ or ax, ax
+ jz GL_exit ; No arena, assume an alias
+
+ mov es, ax
+ifdef WOW
+ mov al, es:[ga_flags]
+ mov byte ptr gflags, al
+ test accword, DSC_DISCARDABLE SHL 8
+ jz GL_exit
+endif
+ inc es:[ga_count] ; Finally, do the lock
+;;; jz GL_rip ; Rip if we overflow
+
+GL_exit:
+ifdef WOW
+ test gflags, GAH_CURSORICON
+ jz GL_NotIcon
+ push dx ; save
+ push handle ; arg for CursorIconLockOp
+ push FUN_GLOBALLOCK ; func id
+ call WowCursorIconOp
+ pop dx ; restore
+
+GL_NotIcon:
+endif
+ xor ax, ax
+ mov es, ax ; Clean out ES
+ mov cx, dx ; HISTORY - someone probably does a jcxz
+cEnd
+
+cProc IGlobalUnlock,<PUBLIC,FAR>
+ parmW handle
+ifdef WOW
+ localW gflags
+ localW accword
+endif
+
+cBegin
+ mov gflags,0
+ cmp handle, -1
+ jne @F
+ mov handle, ds
+@@:
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test byte ptr handle,7
+ jnz @F
+if KDEBUG
+ Trace_Out "GlobalUnlock:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ INT3_WARN
+endif
+ dec handle
+@@:
+ xor cx, cx ; Assume zero lock count
+ cCall GetAccessWord,<handle>
+ifdef WOW
+ mov accword, ax
+endif
+ test al, DSC_PRESENT ; Is it present?
+ jz GU_exit ; no, must be discarded, return 0:0
+ifndef WOW
+ test ah, DSC_DISCARDABLE ; Is it discardable
+ jz GU_exit ; no, Lock is a nop
+endif
+
+ cCall get_arena_pointer,<handle> ; Discardable, get its arena
+ or ax, ax
+ jz GU_exit ; No arena, assume an alias
+
+ mov es, ax
+ifdef WOW
+ mov al, es:[ga_flags]
+ mov byte ptr gflags, al
+ test accword, DSC_DISCARDABLE SHL 8
+ jz GU_exit
+endif
+ mov cl, es:[ga_count] ; Get current count
+ dec cl
+ cmp cl, 0FEh
+ jae @F
+ dec es:[ga_count] ; Finally, do the unlock
+ jmps GU_Exit
+@@:
+;;; ; Rip if we underflow
+ xor cx, cx ; Return zero on underflow
+
+GU_exit:
+ifdef WOW
+ test gflags, GAH_CURSORICON
+ jz GUL_NotIcon
+ push cx ; save
+ push handle ; arg for CursorIconLockOp
+ push FUN_GLOBALUNLOCK ; UnLocking
+ call WowCursorIconOp
+ pop cx ; restore
+
+GUL_NotIcon:
+endif
+ xor ax, ax
+ mov es, ax ; Clean out ES
+ mov ax, cx
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalWire ;
+; ;
+; Locks a moveable segment and moves it down as low as possible. ;
+; This is meant for people who are going to be locking an object ;
+; for a while and wish to be polite. It cannot work as a general ;
+; panacea, judgement is still called for in its use! ;
+; ;
+; Arguments: ;
+; WORD object handle ;
+; ;
+; Returns: ;
+; DWORD object address ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; xhandle ;
+; gmovebusy ;
+; ;
+; History: ;
+; ;
+; Wed Dec 03, 1986 01:07:13p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalWire,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ SetKernelDS es
+ or Kernel_Flags[1],kf1_MEMORYMOVED
+ UnSetKernelDS es
+if KDEBUG
+ push ds
+ SetKernelDS
+ cmp [fBooting], 0
+ jnz shutup
+ push bx
+ mov bx, sp
+ mov bx, ss:[bx+8]
+ krDebugOut <DEB_WARN OR DEB_KrMemMan>, "GlobalWire(#BX of %BX2) (try GlobalLock)"
+ pop bx
+shutup:
+ pop ds
+ UnSetKernelDS
+endif
+ call xhandle
+ push si
+ jz gw_done ; Ignore invalid or discarded objects
+ push bx ; Save handle
+ push cx
+ test cl,GA_DISCARDABLE
+ jz @F
+ inc es:[di].ga_count ; don't want to discard if discardable
+@@: xor ax,ax ; Try to get a fixed segment.
+ mov bx,es:[di].ga_size
+ mov cx,es:[di].ga_owner
+ call gsearch ; AX = segment
+ pop cx
+ pop bx ; Object handle.
+ push ax ; Return from gsearch
+ cCall get_arena_pointer,<bx> ; Get arena header, gsearch may
+ mov es,ax ; have moved the global object!
+ test cl,GA_DISCARDABLE
+ jz @F
+ dec es:[di].ga_count ; undo lock
+@@:
+;;; mov es, es:[di].ga_next
+;;; mov ax, es:[di].ga_prev ; REAL arena header
+ mov si,ax
+;;; mov es,ax
+ pop ax
+ or ax,ax
+ push bx ; Handle
+ jz lock_in_place ; Couldn't get memory.
+ push ax ; New Block
+ mov bx,ax
+ cCall cmp_sel_address,<bx,si> ; Flags set as if cmp bx,si
+ ja oh_no_mr_bill ; Let's not move it up in memory!!
+ pop es
+; mov bx,ga_next ; This is always an exact fit.
+ call gmovebusy ; Wire it on down.
+lock_in_place:
+ pop bx ; Handle
+ inc es:[di].ga_count ; Lock it down.
+ test es:[di].ga_flags,GA_DISCCODE
+ jz not_disccode
+ call glrudel
+ and es:[di].ga_flags,NOT GA_DISCCODE
+not_disccode:
+ mov ax,es
+ mov ax, es:[di].ga_handle
+ Handle_To_Sel al
+gw_done:
+ mov dx,ax
+ xor ax,ax ; Make address SEG:OFF.
+ pop si
+gw_ret: jmp xhandlex
+
+oh_no_mr_bill:
+ pop bx ; kill what's on stack
+ push es
+ mov es, ax
+ xor si, si
+ call gmarkfree
+ pop es
+ jmp lock_in_place
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; GlobalUnWire ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Sep 16, 1987 04:28:49p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalUnWire,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle
+ jnz guw_go
+ jmp xhandlex
+guw_go:
+
+ cCall GetAccessWord,<bx>
+ test ah, DSC_DISCARDABLE
+ jz guw_not_disccode
+ test al, DSC_CODE_BIT
+ jz guw_not_disccode
+ or es:[di].ga_flags,GA_DISCCODE
+ call glruadd
+guw_not_disccode:
+
+if KDEBUG
+ cmp ch,00h ; Debugging check for count underflow
+ jne unlock1
+ push bx ; then the count is wrong.
+ push cx
+ push dx
+ xor cx,cx
+ kerror ERR_GMEMUNLOCK,<GlobalUnWire: Object usage count underflow>,cx,bx
+ pop dx
+ pop cx
+ pop bx
+unlock1:
+endif
+ call gunlock
+ mov ax, 0FFFFh ; TRUE
+ jcxz guw_done
+ inc ax ; FALSE
+guw_done:
+ jmp xhandlex
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GlobalCompact ;
+; ;
+; Compacts the global arena until a free block of the requested size ;
+; appears. Contrary to the toolkit it ALWAYS compacts! ;
+; ;
+; Arguments: ;
+; DWORD minimum bytes wanted ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Wed Dec 03, 1986 01:09:02p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalCompact,<PUBLIC,FAR>,<bx,si,di>
+ parmD minBytes
+cBegin
+ call genter ; About to modify memory arena
+ PROFILE GLOBALCOMPACT
+ CheckHeap GlobalCompact
+
+ cCall DpmiFreeSpace
+ cmp dx,seg_minBytes
+ jb GCReallyCompact
+ ja GCWorked
+
+ cmp ax,off_minBytes
+ jnb GCWorked
+
+GCReallyCompact:
+if KDEBUG
+ push ax
+ push bx
+ mov ax, seg_minBytes
+ mov bx, off_minBytes
+ krDebugOut DEB_TRACE, "%SS2 GlobalCompact(#ax#BX), discarding segments"
+ pop bx
+ pop ax
+endif
+ mov ax,-1
+ lea bx,minBytes
+ call gbtop
+ assumes es, nothing
+ clc ; galign should be called with CF = 0
+ call galign
+ call gavail ; Returns paragraphs in DX:AX
+ mov cx,4 ; Convert paragraphs to bytes
+ push ax
+gcsize1:
+ shl ax,1
+ rcl dx,1
+ loop gcsize1
+ pop cx ; Let caller do jcxz to test failure.
+ jmp GCDone
+
+GCWorked:
+ cmp dx,0fh ; make sure return value not too large
+ jb GCAlmostDone
+ ja GCAD1
+
+ cmp ax,0ffb0h
+ jb GCAlmostDone
+
+GCAD1:
+ mov dx,0fh
+ mov ax,0ffb0h
+
+GCAlmostDone:
+ mov cx,dx
+ mov bx,ax
+ shr bx,4
+ shl cx,12
+ or cx,bx
+
+GCDone:
+ call ShrinkHeap
+ call gleave
+ mov es,di
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalNotify ;
+; ;
+; This sets a procedure to call when a discardable segment belonging ;
+; to this task gets discarded. The discardable object must have been ;
+; allocated with the GMEM_DISCARDABLE bit set. ;
+; ;
+; Arguments: ;
+; parmD NotifyProc ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Jun 23, 1987 10:16:32p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalNotify,<PUBLIC,FAR>
+
+ parmD NotifyProc
+cBegin
+ push ds
+ les bx,NotifyProc ; verify pointer
+ SetKernelDS
+ mov ds,curTDB
+ UnsetKernelDS
+ mov word ptr ds:[TDB_GNotifyProc][2],es
+ mov word ptr ds:[TDB_GNotifyProc][0],bx
+ pop ds
+cEnd
+
+
+cProc GlobalMasterHandle,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ax,hGlobalHeap
+ mov dx,pGlobalHeap
+ UnSetKernelDS
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetTaskDS ;
+; ;
+; Gets the segment of the current task's DS. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AX = selector. ;
+; DX = selector. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Thu Jun 25, 1987 10:52:10p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc GetTaskDS,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ds,curTDB
+ UnsetKernelDS
+ mov ax,ds:[TDB_Module]
+ mov dx,ax
+ pop ds
+ ret
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IGlobalLRUOldest,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jz xhandlex2
+ call glrubot
+xhandlex2:
+ jmp xhandlex
+cEnd nogen
+
+
+cProc IGlobalLRUNewest,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jz xhandlex2
+ call glrutop
+ jmp xhandlex
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; SwitchStackTo ;
+; ;
+; Switched to the given stack, and establishes the BP chain. It also ;
+; copies the last stack arguments from the old stack to the new stack. ;
+; ;
+; Arguments: ;
+; parmW new_ss ;
+; parmW new_sp ;
+; parmW stack_top ;
+; ;
+; Returns: ;
+; A new stack! ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 22, 1987 08:42:05p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProcVDO SwitchStackTo,<PUBLIC,FAR>
+; parmW new_ss
+; parmW new_sp
+; parmW stack_top
+cBegin nogen
+
+ SetKernelDS es
+ FCLI
+ mov GSS_SI,si
+ mov GSS_DS,ds
+ pop word ptr GSS_RET[0] ; get the return address
+ pop word ptr GSS_RET[2]
+ assumes es, nothing
+ pop ax ; stack_top
+ pop bx ; new_sp
+ pop dx ; new_ss
+ mov si,bp ; Calculate # of parameters on stack.
+ dec si ; remove DS
+ dec si
+ mov cx,si
+ sub cx,sp
+ shr cx,1
+ push bp ; save BP
+ smov es,ss
+ mov ds,dx ; new_ss
+ mov ds:[2],sp
+ mov ds:[4],ss
+ mov ds:[pStackTop],ax
+ mov ds:[pStackMin],bx
+ mov ds:[pStackBot],bx
+
+; switch stacks
+
+ mov ss,dx
+ mov sp,bx
+ mov bp,bx
+ xor ax,ax
+ push ax ; null terminate bp chain
+ jcxz no_args
+copy_args:
+ dec si
+ dec si
+ push es:[si]
+ loop copy_args
+no_args:
+ SetKernelDS
+ mov es,curTDB
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+ push GSS_RET.sel
+ push GSS_RET.off ; get the return address
+ mov si,GSS_SI
+ mov ds,GSS_DS
+ FSTI
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; SwitchStackBack ;
+; ;
+; Switches to the stack stored at SS:[2], and restores BP. Preserves ;
+; AX and DX so that results can be passed back from the last call. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; The old stack! ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 22, 1987 09:56:32p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SwitchStackBack,<PUBLIC,FAR>
+cBegin nogen
+
+ push ds
+ SetKernelDS
+ FCLI
+ pop GSS_DS
+ pop GSS_RET.off ; get the return address
+ pop GSS_RET.sel
+ xor bx,bx
+ xor cx,cx
+ xchg bx,ss:[4]
+ xchg cx,ss:[2]
+ mov ss,bx
+ mov sp,cx
+ mov es,curTDB
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+ pop bp
+ push GSS_RET.sel
+ push GSS_RET.off ; get the return address
+ mov ds,GSS_DS
+ UnSetKernelDS
+ FSTI
+ ret
+
+cEnd nogen
+
+;
+; GetFreeMemInfo - reports Free and Unlocked pages
+; in paging systems. -1 for non paging system.
+;
+cProc GetFreeMemInfo,<PUBLIC,FAR>
+cBegin nogen
+ mov ax, -1
+ mov dx, ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetFreeSpace ;
+; ;
+; Calculates the current amount of free space ;
+; ;
+; Arguments: ;
+; flags - ignored for non-EMS system ;
+; ;
+; Returns: ;
+; DX:AX Free space in bytes ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IGetFreeSpace,<PUBLIC,FAR>,<si,di>
+ parmW flags
+ localV MemInfo,30h
+cBegin
+ call genter
+ xor si, si
+ xor dx, dx
+
+ mov es, [di].hi_first
+gfs_loop:
+ mov es, es:[di].ga_next
+ cmp es:[di].ga_sig, GA_ENDSIG
+ je gfs_last ; End of heap
+ mov ax, es:[di].ga_owner
+ cmp ax, GA_NOT_THERE
+ je gfs_loop ; Nothing there
+ or ax, ax ; Free?
+ jz gfs_freeblock
+ test flags, 2 ; Ignore discardable?
+ jnz gfs_loop
+ mov bx, es:[di].ga_handle
+ test bl, GA_FIXED
+ jnz gfs_loop ; Fixed block if odd
+ cmp es:[di].ga_sig, 0
+ jne gfs_loop ; skip if locked
+ cCall GetAccessWord,<bx>
+ test ah, DSC_DISCARDABLE
+ jz gfs_loop
+gfs_freeblock:
+ mov ax, es:[di].ga_size
+ inc ax
+ add si, ax
+ adc dx, 0 ; Keep 32 bit total
+ jmps gfs_loop
+
+gfs_last:
+ test flags, 2 ; No fence stuff if ignoring discardable
+ jnz @F
+ sub si, [di].gi_reserve ; Subtract out that above fence
+ sbb dx, 0
+@@:
+ mov ax, si ; Return in DX:AX
+ ; Convert to bytes
+REPT 4
+ shl ax, 1
+ rcl dx, 1
+ENDM
+
+ ;
+ ; Get the ammount of free memory
+ ;
+ push bx
+ push cx
+ push ax
+ push dx
+ call DpmiFreeSpace
+ pop dx
+ pop ax
+ add ax,bx
+ adc dx,cx
+ pop cx
+ pop bx
+@@: call gleave
+ mov es,di
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalDOSAlloc
+;
+; Allocates memory that is accessible by DOS.
+;
+; Entry:
+; parmD nbytes number of bytes to alloc
+;
+; Returns:
+; AX = memory handle
+; DX = DOS segment paragraph address
+;
+; History:
+; Tue 23-May-1989 11:30:57 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalDOSAlloc,<PUBLIC,FAR>,<di,si>
+ parmD nbytes
+cBegin
+ mov ax,GA_ALLOC_DOS shl 8
+ cCall IGlobalAlloc,<ax,nbytes>
+ xor dx,dx ; In case of error return
+ or ax,ax
+ jz short gda_exit
+ push ax
+ cCall get_physical_address,<ax>
+REPT 4
+ shr dx,1
+ rcr ax,1
+ENDM
+ xchg dx,ax
+ pop ax
+gda_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalDOSFree
+;
+; Frees memory allocated by GlobalDOSAlloc.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 17:48:03 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalDOSFree,<PUBLIC,FAR>
+ parmW handle
+cBegin nogen
+ jmp IGlobalFree
+cEnd nogen
+
+if ALIASES
+
+;-----------------------------------------------------------------------;
+; GlobalAllocHuge
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 21-Jan-1990 16:35:10 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalAllocHuge,<PUBLIC,FAR>,<di,si>
+
+ parmW flags
+ parmD nbytes
+ parmW maxsegs ; !!! check for maxsegs = 0
+
+ localW hMem
+ localW hAlias
+cBegin
+ cCall GlobalAlloc,<0,nbytes>
+ or ax,ax
+ jz gah_exit
+ mov hMem,ax
+ cCall get_physical_address,<ax>
+ mov cx,maxsegs
+ cmp cx,0Fh
+ jb @F
+ mov cx,0Fh
+@@: shl cx,12
+ or cx,0FFFh
+ cCall alloc_data_sel,<dx,ax,cx>
+ or ax,ax
+ jz gah_error_return
+ mov hAlias,ax
+ mov bx,hMem
+ call add_alias ; the key point!
+ mov bx,ax
+ mov ax,maxsegs ; the only way to remember
+ call add_alias ; the number of selectors
+ mov cx,nbytes.hi
+ mov bx,nbytes.lo
+ cCall set_sel_limit,<hAlias>
+ mov ax,hAlias
+ jmps gah_exit
+
+gah_error_return:
+ cCall GlobalFree,<hMem>
+ xor ax,ax
+
+gah_exit:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalReAllocHuge
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 21-Jan-1990 16:35:10 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalReAllocHuge,<PUBLIC,FAR>,<si,di>
+
+ parmW handle
+ parmD nbytes
+cBegin
+ mov ax,handle
+ call get_alias_from_original
+ cmp bx,nbytes.hi
+ jb grh_error_exit
+ call get_original_from_alias
+ push es
+ or bx,SEG_RING
+ cCall GlobalRealloc,<bx,nbytes,0>
+ pop es
+ or ax,ax ; did we get the memory?
+ jz grh_exit
+ cmp ax,es:[di].sae_sel ; did the selector change?
+ jz grh_exit
+ mov es:[di].sae_sel,ax
+ cCall get_physical_address,<ax>
+ cCall set_physical_address,<handle>
+ mov ax,handle
+ jmps grh_exit
+
+grh_error_exit:
+ xor ax,ax
+
+grh_exit:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalFreeHuge
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 22-Jan-1990 21:24:02 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalFreeHuge,<PUBLIC,FAR>,<di,si>
+
+ parmW handle
+cBegin
+ mov ax,handle
+ call get_alias_from_original
+ mov es:[di].sae_sel,0
+ mov es:[di].sae_alias,0
+ mov cx,bx
+ mov bx,0FFFFh
+ cCall set_sel_limit,<ax>
+ mov dx,ax
+ mov ax,handle
+ call get_original_from_alias
+ push bx
+ push ax
+ call delete_alias
+ pop ax ; wastes a couple of bytes
+ cCall FreeSelector,<ax>
+ pop ax
+ cCall GlobalFree,<ax>
+cEnd
+
+endif ; ALIASES
+
+;-----------------------------------------------------------------------;
+; GlobalHuge
+;
+; Random place holder of an entry point.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-Jan-1990 00:53:59 -by- David N. Weise [davidw]
+; Stubbed it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalHuge,<PUBLIC,FAR>
+
+cBegin nogen
+ ret 10
+cEnd nogen
+
+cProc DpmiFreeSpace,<PUBLIC,NEAR>,<di,si,es>
+ localV MemInfo,30h
+cBegin
+ ;
+ ; Get Memory Info
+ ;
+ mov ax,ss
+ mov es,ax
+ lea di,MemInfo
+ DPMICALL 500h
+ jc dfs30
+
+ ;
+ ; Convert pages to bytes
+ ;
+ mov bx,MemInfo[14h]
+ mov cx,MemInfo[16h]
+REPT 12
+ shl bx,1
+ rcl cx,1
+ENDM
+ ;
+ ; Get the rest of the info
+ ;
+ mov ax,MemInfo[0]
+ mov dx,MemInfo[2]
+ jmp dfs40
+
+dfs30: xor ax,ax
+ mov bx,ax
+ mov cx,ax
+ mov dx,ax
+
+dfs40:
+cEnd
+
+ifdef WOW
+;--------------------------------------------------------------------------;
+;
+; Similar to GlobalFlags
+;
+;--------------------------------------------------------------------------;
+
+cProc SetCursorIconFlag,<PUBLIC,FAR>
+ parmW handle
+ parmW fSet
+cBegin
+ cCall get_arena_pointer,<handle> ; get the owner
+ mov es,ax
+ or ax,ax
+ jz sf_error
+ mov ax,fSet
+ or ax,ax
+ jz sf_unset
+ or es:[ga_flags], GAH_CURSORICON
+ jmps sf_error
+sf_unset:
+ and es:[ga_flags], NOT GAH_CURSORICON
+sf_error:
+ xor ax,ax
+ mov es,ax
+cEnd
+
+;--------------------------------------------------------------------------;
+;
+; Stamp the 01h in globalarena for DDE handles. This is GAH_PHANTOM flag
+; which is not used any longer.
+;
+;--------------------------------------------------------------------------;
+
+cProc SetDdeHandleFlag,<PUBLIC,FAR>
+ parmW handle
+ parmW fSet
+cBegin
+ cCall get_arena_pointer,<handle> ; get the owner
+ mov es,ax
+ or ax,ax
+ jz sd_error
+
+ mov ax,fSet
+ or ax,ax
+ jz sd_unset
+ or es:[ga_flags], GAH_WOWDDEFREEHANDLE
+ jmps sd_error
+
+sd_unset:
+ and es:[ga_flags], NOT GAH_WOWDDEFREEHANDLE
+
+sd_error:
+ xor ax,ax
+ mov es,ax
+cEnd
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/2glru.asm b/private/mvdm/wow16/kernel31/2glru.asm
new file mode 100644
index 000000000..9053e5c05
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2glru.asm
@@ -0,0 +1,595 @@
+ TITLE GLRU - Primitives for LRU management
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+.list
+
+DataBegin
+
+;externB EMSSwapDepth
+externB Kernel_InDOS
+externB Kernel_flags
+;externW curTDB
+externW loadTDB
+externW pGlobalHeap
+;externW hExeSweep
+
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externW gdtdsc
+externNP GetAccessWord
+externNP DPMIProc
+
+
+;-----------------------------------------------------------------------;
+; lrusweep ;
+; ;
+; Searches all of the exe headers in the system for segments that have ;
+; been accessed since the last time through. For each segment found ;
+; its referenced byte is reset and that segment is moved to the top ;
+; of the lru chain. This routine is called (default) every 4 timer ;
+; ticks from the int 8 handler. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,ES ;
+; ;
+; Calls: ;
+; glrutop ;
+; ;
+; History: ;
+; ;
+; Tue Apr 21, 1987 06:22:41p -by- David N. Weise [davidw] ;
+; Added the check for discarded segments. ;
+; ;
+; Wed Apr 08, 1987 11:00:59a -by- David N. Weise [davidw] ;
+; Made it clear only the curTask's private handle table. ;
+; ;
+; Wed Feb 18, 1987 08:13:35p -by- David N. Weise [davidw] ;
+; Added the sweeping of the private handle tables. ;
+; ;
+; Tue Feb 10, 1987 02:11:40a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lrusweep,<PUBLIC,FAR>
+cBegin nogen
+
+ push dx
+ push di
+ push si
+ push ds
+ xor di,di
+ SetKernelDS
+ cmp kernel_InDOS,0 ; SMARTDrive and EMS may be present
+ jnz dont_do_it ; => disk buffers over the code segs
+ cmp di,loadTDB ; Ignore interrupt if loading task
+ jnz dont_do_it
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ cmp di,ds:[di].gi_lrulock ; Ignore interrupt if inside memory
+ jz do_it ; manager
+dont_do_it:
+ jmps sweepdone
+do_it:
+
+ mov cx, ds:[di].gi_lrucount
+ jcxz stuff_it
+ mov si, ds:[di].gi_lruchain
+
+ push bx
+ push ds
+
+;; For WOW dpmi will update the ACCESSED bits from the real LDT in NT on timer ticks
+;; So it will not be totally accurate but will be accurate enough. mattfe apr16 92
+
+ mov ds, gdtdsc ; Go grab it out of the LDT
+sweep_loop:
+ mov es, si
+ mov si, es:[di].ga_lrunext
+ mov bx, es:[di].ga_handle
+
+ sel_check bl
+
+if KDEBUG
+ test ds:[bx].dsc_hlimit, DSC_DISCARDABLE
+ jnz sweep_ok
+ INT3_WARN
+sweep_ok:
+endif
+ test ds:[bx].dsc_access, DSC_ACCESSED ; Segment accessed?
+ jz sweep_next
+ifdef WOW
+ push cx
+ xor cx,cx
+ mov cl, ds:[bx].dsc_access
+ and cx, not DSC_ACCESSED
+ DPMICALL 0009h
+ pop cx
+ jnc @f
+ INT3_WARN
+@@:
+else
+ and ds:[bx].dsc_access, not DSC_ACCESSED
+endif ; WOW
+
+ pop ds
+ call glrutop
+ push ds
+ mov ds, gdtdsc
+sweep_next:
+ loop sweep_loop
+ pop ds
+ pop bx
+
+stuff_it:
+
+
+
+sweepdone:
+ pop ds
+ pop si
+ pop di
+ pop dx
+ ret
+cEnd nogen
+
+
+
+
+;
+; Entry:
+; DI == 0
+; DS:SI.gi_lruchain -> head of list
+; ES:0 -> arena header of object to insert
+; DX = 0 => insert at head of list
+; !=0 => insert at tail of list
+;
+; Exit:
+; BX,DX destroyed
+;
+cProc LRUInsert,<PUBLIC,NEAR>
+cBegin nogen
+ inc ds:[si].gi_lrucount ; Increment count of LRU entries
+ mov bx,ds:[si].gi_lruchain ; BX = head of list
+ or dx,dx ; Inserting at head of chain?
+ jnz lruins0 ; No, tail so dont update head
+ mov ds:[si].gi_lruchain,es ; Yes, make new one the new head
+lruins0:
+ or bx,bx ; List empty?
+ jnz lruins1
+ mov es:[di].ga_lruprev,es ; Yes, make circular
+ mov es:[di].ga_lrunext,es
+ mov ds:[si].gi_lruchain,es
+ ret
+lruins1:
+ push es ; Save ES
+ push bx ; ES = insertion point
+ mov bx,es ; BX = new
+ mov dx,es ; DX = new
+ pop es
+ xchg es:[di].ga_lruprev,bx
+ mov es,bx
+ xchg es:[di].ga_lrunext,dx
+ pop es
+ mov es:[di].ga_lruprev,bx
+ mov es:[di].ga_lrunext,dx
+ ret
+cEnd nogen
+
+
+
+
+;
+; Entry:
+; DI == 0
+; DS:SI.gi_lruchain -> head of list
+; ES:0 -> arena header of object to insert
+;
+; Exit:
+; BX,DX destroyed
+;
+;
+cProc LRUDelete,<PUBLIC,NEAR>
+cBegin nogen
+
+;
+; This is basically a consistency check, in case we don't fix
+; GlobalRealloc() for 3.1.
+;
+ push ax
+ mov ax,es:[di].ga_lrunext
+ or ax,es:[di].ga_lruprev
+ pop ax
+
+ jz lrudel_ret
+
+ dec ds:[si].gi_lrucount ; Decrement count of LRU entries
+ jnz lrudel0
+ mov ds:[si].gi_lruchain,di ; List empty, zero LRU chain.
+ mov es:[di].ga_lruprev,di ; Zero pointers in deleted object
+ mov es:[di].ga_lrunext,di
+ ret
+lrudel0:
+ mov dx,es
+ cmp ds:[si].gi_lruchain,dx ; Are we deleting the head?
+ jne lrudel1
+ mov dx,es:[di].ga_lrunext
+ mov ds:[si].gi_lruchain,dx ; Yes, make it point to the next one
+lrudel1:
+ xor bx,bx ; Zero pointers in deleted object
+ xchg es:[di].ga_lrunext,bx
+
+ xor dx,dx
+ xchg es:[di].ga_lruprev,dx
+ push es
+ mov es,dx
+ mov es:[di].ga_lrunext,bx
+ mov es,bx
+ mov es:[di].ga_lruprev,dx
+ pop es
+lrudel_ret:
+ ret
+cEnd nogen
+
+;
+; glruSetup
+;
+; INPUT: ES -> arena header
+; DI = 0
+;
+; OUTPUT: ZF set: block is not on LRU list
+; ZF clear:
+; SI = 0
+;
+;
+cProc glruSetup,<PUBLIC,NEAR>
+cBegin nogen
+ mov bx,es:[di].ga_handle
+ or bx,bx
+ jz gsdone
+ push ax
+ cCall GetAccessWord,<bx>
+ test ah, DSC_DISCARDABLE
+ pop ax
+ jz gsdone ; not a discardable object
+ xor si,si
+ or sp,sp
+gsdone:
+ ret
+cEnd nogen
+
+
+
+
+;-----------------------------------------------------------------------;
+; glrutop ;
+; ;
+; Moves a discardable object to the head of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = global arena of moveable object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:20:10p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrutop,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+ call glruSetup
+ jz glrutop1
+
+ call LRUDelete
+ xor dx,dx ; DX == 0 means insert at head
+ call LRUInsert
+glrutop1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glrubot ;
+; ;
+; Moves a discardable object to the tail of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = global arena of moveable object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:20:10p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrubot,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+ call glruSetup
+ jz glrubot1
+
+ call LRUDelete
+ mov dx,sp ; DX != 0 means insert at tail
+ call LRUInsert
+glrubot1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+
+
+;-----------------------------------------------------------------------;
+; glruadd ;
+; ;
+; Adds a discardable object to the head of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = arena header of object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:23:35p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glruadd,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+
+ call glruSetup
+ jz glruadd1
+
+ xor dx,dx ; DX == 0 means insert at head
+ call LRUInsert
+glruadd1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glrudel ;
+; ;
+; Removes a discardable object from the LRU chain. ;
+; ;
+; Arguments: ;
+; ES:DI = arena header of object ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; Nothing. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:36:49p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrudel,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+
+ call glruSetup
+ jz glrudel1
+
+ call LRUDelete
+glrudel1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+if KDEBUG
+
+;-----------------------------------------------------------------------;
+; check_lru_list ;
+; ;
+; Checks the glru list for consistency. ;
+; ;
+; Arguments: ;
+; nothing ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Wed Oct 29, 1986 10:13:42a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc check_lru_list,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ push ds
+ SetKernelDS
+ test Kernel_flags,kf_check_free
+ jnz check_lru_too
+ jmps cll_ret
+check_lru_too:
+ push ax
+ push bx
+ push cx
+ push dx
+ push es
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ xor bx,bx
+do_it_again:
+ mov ax,[bx].gi_lruchain
+ mov cx,[bx].gi_lrucount ; without ems gi_alt_count is 0
+ or cx,cx
+ jnz short_relative_jumps
+ jmps all_done
+short_relative_jumps:
+ push ds
+ push bx
+ mov es,ax
+check_chain_loop:
+ mov ds,es:[di].ga_lruprev
+ mov es,es:[di].ga_lrunext
+ cmp ds:[di].ga_lrunext,ax
+ jz prev_okay
+ mov bx, ax
+ kerror 0FFh,<lru: prev bad>,ds,bx
+ mov ax, bx
+prev_okay:
+ cmp es:[di].ga_lruprev,ax
+ jz next_okay
+ mov bx, ax
+ kerror 0FFh,<lru: next bad>,bx,es
+next_okay:
+ mov ax,es
+ loop check_chain_loop
+ pop bx
+ pop ds
+ cmp [bx].gi_lruchain,ax
+ jz all_done
+ mov cx, ax
+ kerror 0FFh,<lru: count bad>,cx,[bx].gi_lrucount
+all_done:
+ or bx,bx
+ jnz really_done
+ mov bx,gi_alt_lruchain - gi_lruchain
+ jmp do_it_again
+really_done:
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+cll_ret:
+ pop ds
+ ret
+
+cEnd nogen
+
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/2gmem.asm b/private/mvdm/wow16/kernel31/2gmem.asm
new file mode 100644
index 000000000..4049a2ecf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2gmem.asm
@@ -0,0 +1,1321 @@
+ TITLE GMEM - Register interface to global memory allocator
+
+.xlist
+include kernel.inc
+include tdb.inc
+include protect.inc
+.list
+
+externFP SetSelectorLimit
+
+DataBegin
+
+externB fBooting
+;externW curTDB
+;externW pGlobalHeap
+externW SelTableStart
+externW SelTableLen
+
+ifdef WOW
+globalB fInAlloc, 0
+globalW UserSelArray, 0
+globalW SelectorFreeBlock, 0
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP DPMIProc
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+
+;externW gdtdsc
+
+
+externNP gsplice
+externNP gjoin
+externNP gzero
+externNP gsearch
+externNP gmarkfree
+;externNP gcheckfree
+externNP gmovebusy
+externNP gcompact
+externNP glruadd
+externNP glrudel
+externNP glrutop
+externNP gnotify
+externNP henum
+externNP is_there_theoretically_enough_space
+externNP can_we_clear_this_space
+
+externNP get_physical_address
+externNP set_physical_address
+externNP alloc_sel
+externNP alloc_data_sel_above
+externNP pdref
+externNP set_sel_limit
+externNP mark_sel_PRESENT
+externNP mark_sel_NP
+externNP free_sel
+externNP FreeSelArray
+externNP GrowSelArray
+externNP get_arena_pointer
+externNP get_temp_sel
+externNP get_blotto
+;externNP get_sel
+externNP PreallocSel
+externNP AssociateSelector
+externNP GetAccessWord
+externNP SetAccessWord
+externFP set_discarded_sel_owner
+
+if ROM
+externNP IsROMObject
+endif
+
+if KDEBUG
+externNP CheckGAllocBreak
+endif
+
+;-----------------------------------------------------------------------;
+; galign ;
+; ;
+; Aligns the size request for a global item to a valid para boundary. ;
+; ;
+; Arguments: ;
+; BX = #paras ;
+; CF = 1 if #paras overflowed. ;
+; ;
+; Returns: ;
+; DX = #paras aligned, to next higher multiple of 2 ;
+; ;
+; Error Returns: ;
+; DX = FFFFh ;
+; ;
+; Registers Preserved: ;
+; all ;
+; Registers Destroyed: ;
+; none ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Mon Sep 22, 1986 03:14:56p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc galign,<PUBLIC,NEAR>
+cBegin nogen
+
+ jc align_error ; Overflow occur?
+ lea dx,[bx+GA_ALIGN] ; No, add alignment amount
+ and dl,GA_MASK ; ...modulo alignment boundary
+ cmp dx,bx ; Test for overflow
+ jnb align_exit ; Yes, continue
+align_error:
+ mov dx,0FFFFh ; Return impossible size
+align_exit:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; galloc ;
+; ;
+; Allocates global memory. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; BX = #paragraphs ;
+; CX = owner field ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; BX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; DX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; gsearch ;
+; ghalloc ;
+; glruadd ;
+; gmarkfree ;
+; History: ;
+; ;
+; Wed Jun 24, 1987 03:04:32a -by- David N. Weise [davidw] ;
+; Added support for Global Notify. ;
+; ;
+; Mon Sep 22, 1986 02:38:19p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+AccessWord dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_CODE+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+
+cProc galloc,<PUBLIC,NEAR>
+cBegin nogen
+
+if ROM and KDEBUG
+ if 1
+ %out Remove me someday
+ endif
+ or cx,cx ; had trouble with owner == 0
+ jnz @f ; too many times!
+ Debug_Out "ROMKRNL: galloc with owner = 0!"
+@@:
+endif
+
+if KDEBUG
+ test al,GA_DISCCODE ; If discardable code, allow alloc
+ jnz @F
+ call CheckGAllocBreak
+ jnc @F
+ jmp gaerr
+@@:
+endif
+
+ or bx,bx ; Allocating zero size?
+ jnz @F
+ jmp allocate_zero_size
+@@:
+
+ifdef WOW
+ push ds
+ SetKernelDS
+ mov fInAlloc, 1
+ mov SelectorFreeBlock, 0
+ mov UserSelArray, 0
+ UnSetKernelDS
+ pop ds
+endif
+ call gsearch ; Search for block big enough
+ jnz bleech
+ mov cx, ax
+
+ifdef WOW
+ push ds
+ SetKernelDS
+ mov fInAlloc, 0
+ mov SelectorFreeBlock, 0
+ mov UserSelArray, 0
+ UnSetKernelDS
+ pop ds
+endif
+
+ ret ; Done, if couldn't get enough
+bleech:
+ mov es,ax
+ push dx
+
+ifdef WOW
+
+ push ds
+ SetKernelDS
+ mov fInAlloc, 0
+ mov SelectorFreeBlock, 0
+ mov ax, UserSelArray
+ UnSetKernelDS
+ pop ds
+ or ax, ax
+ jnz got_Sel
+ mov ax, es
+
+old_path:
+
+endif
+ mov bx,dx
+ cCall get_physical_address,<ax>
+ add ax,10h ; Calculate address of object
+ adc dx,0
+ mov cx, ax ; in DX:CX
+
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ cCall alloc_sel,<dx,cx,es:[di].ga_size>
+
+got_sel:
+ pop dx
+ or ax, ax
+ jz short gaerr1
+ cCall AssociateSelector,<ax,es>
+ test dl,GA_MOVEABLE ; Is this a moveable object?
+ jnz moveable
+ test dh, GA_DISCARDABLE ; We have a fixed block
+ jnz not_moveable ; Not interested in discardable blocks
+ mov bx, ax
+%out THIS IS WRONG!!!
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ mov ax, 4 ; Lock the WIN386 pages
+ ;bugbugbugbug
+ DPMICALL ax ; int 31h
+ mov ax, bx
+endif
+ jmps not_moveable
+moveable:
+ mov es:[di].ga_count,0 ; Initialize lock count to 0
+ StoH al ; Mark as moveable block
+not_moveable:
+ mov es:[di].ga_handle,ax ; Set handle in arena
+ mov bx, ax ; AX and BX handle
+
+ call glruadd ; Yes, Add to LRU chain
+ mov cx, ax
+ ret
+
+allocate_zero_size:
+ test al,GA_MOVEABLE ; Yes, moveable?
+ jz gaerr ; No, return error (AX = 0)
+
+ mov bx, ax
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh ; Above bits are exclusive
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ and al, NOT DSC_PRESENT ; These are NOT present
+ xor dx, dx ; Base of zero for now
+ cCall alloc_sel,<dx,dx,cx>
+ or ax, ax
+ jz gaerr
+
+ cCall AssociateSelector,<ax,cx>
+ StoH al ; Handles are RING 2
+ mov bx,ax
+ga_exit:
+ mov cx, ax
+ ret
+
+gaerr1:
+ xor si,si
+ call gmarkfree
+gaerr:
+ KernelLogError DBF_WARNING,ERR_GALLOC,"GlobalAlloc failed"
+ xor dx,dx ; DX = 0 means NOT out of memory
+ xor ax,ax ; Return AX = 0 to indicate error
+ jmps ga_exit
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; grealloc ;
+; ;
+; Reallocates the given global memory object. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; BX = #paragraphs for new size ;
+; CX = new owner field value ;
+; DX = existing handle ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; DX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 05-Feb-1990 21:07:33 -by- David N. Weise [davidw] ;
+; Got rid of the spagetti code. ;
+; ;
+; Mon Sep 22, 1986 10:11:48a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc grealloc,<PUBLIC,NEAR>,<si>
+
+ localW rflags
+ localW hMem
+ localW oldhMem
+ localW owner
+ localW rsize
+ localW canmove
+ localB locked
+ localB mflags
+ localW numsels
+cBegin
+ mov rflags,ax
+ mov hMem,dx
+ mov oldhMem,dx
+ mov owner,cx
+ mov rsize,bx
+ call pdref
+ mov dx,bx ; save owner if discarded
+ mov word ptr mflags,cx
+ mov bx,rsize
+ jnz handle_ok
+ jmp racreate ; Do nothing with 0, free or discarded handles
+handle_ok:
+ test byte ptr rflags,GA_MODIFY ; Want to modify table flags?
+ jnz ramodify ; Yes go do it
+ or bx,bx ; Are we reallocing to zero length?
+ jz radiscard
+ jmp ra_shrink_grow ; No, continue
+
+;-----------------------------------------------------------------------;
+; Here to discard object, when reallocating to zero size. This ;
+; feature is only enabled if the caller passes the moveable flag ;
+;-----------------------------------------------------------------------;
+
+radiscard:
+ or ch,ch ; Is handle locked?
+ jnz radiscard_fail
+ test byte ptr rflags,GA_MOVEABLE ; Did they want to discard?
+ jz radiscard_fail ; No, then return failure.
+ mov al,GN_DISCARD ; AL = discard message code
+ xor cx,cx ; CX = means realloc
+ mov bx,hMem ; BX = handle
+ push es
+ call gnotify ; See if okay to discard
+ pop es
+ jz radiscard_fail ; No, do nothing
+ call glrudel ; Yes, Delete handle from LRU chain
+
+ cCall mark_sel_NP,<si,es:[di].ga_owner>
+
+ xor si,si
+ call gmarkfree ; Free client data
+ mov ax,0 ; don't change flags
+ jz @F ; Return NULL if freed a fixed block
+ mov bx, si
+ mov ax,hMem ; Return original handle, except
+@@: jmp raexit ; GlobalLock will now return null.
+
+radiscard_fail:
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ xor dx,dx
+ xor ax,ax
+ jmp raexit
+
+;-----------------------------------------------------------------------;
+; There are 2 attributes that can change: ;
+; 1) Fixed -> moveable - added in 2.x, probably not used by many ;
+; 2) nondiscardable <-> discardable ;
+; 3) non-shared -> shared, i.e., the owner changes ;
+;-----------------------------------------------------------------------;
+
+ramodify:
+if ROM
+ cCall IsROMObject,<hMem> ; If someone is trying to modify a
+ jc ramod_done ; ROM object, just pretend it worked
+endif
+ mov ax,rflags ; Get new flags
+ mov dx,owner ; Get new owner field value
+ or si,si ; Moveable object?
+ jnz is_moveable ; yes, change discardability/owner
+ test al,GA_MOVEABLE ; Make fixed into moveable?
+ jz ra_mod_owner ; Fixed, can ONLY change owner
+
+ push ax
+ push cx
+ mov ax, es:[di].ga_handle ; Turn selector into handle
+ StoH al
+ mov bx, ax
+ mov es:[di].ga_handle, ax
+ mov es:[di].ga_count, 0 ; 0 lock count for new movable obj
+ pop cx
+ pop ax
+ mov si,bx
+
+; fall through to code that makes [non]discardable and may change owner
+
+is_moveable:
+ call glrudel ; Remove from lru chain, even though
+ push bx
+ mov bx, ax
+ cCall GetAccessWord,<si>
+ and ah, not DSC_DISCARDABLE ; Clear discard bit
+ test bh, GA_DISCARDABLE
+ jz ra_notdiscardable
+ or ah, DSC_DISCARDABLE
+ra_notdiscardable:
+ cCall SetAccessWord,<si,ax>
+ mov ax, bx
+ pop bx
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz ramod1 ; No, continue
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz ramod_done
+
+ push bx
+ push es
+ mov bx, si
+ mov es, dx
+ call set_discarded_sel_owner
+ pop es
+ pop bx
+ jmps ramod_done
+
+ramod1: call glruadd ; only adds to list IF object is disc
+
+ra_mod_owner:
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz ramod_done
+ mov es:[di].ga_owner,dx ; Set new owner value
+ramod_done:
+ mov ax,hMem ; Return the same handle
+ jmp raexit ; All done
+
+;-----------------------------------------------------------------------;
+; We are here to grow a 0 sized object up big. ;
+;-----------------------------------------------------------------------;
+
+racreate:
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz racre_fail ; No, return error
+ or bx,bx ; Are we reallocing to zero length?
+ mov ax,hMem
+ jz racre_done ; Yes, return handle as is.
+if KDEBUG
+ test cl,GA_DISCCODE ; if discardable code, allow realloc
+ jnz @F
+ call CheckGAllocBreak
+ jc racre_fail
+@@:
+endif
+ mov ax,GA_MOVEABLE ; Reallocating a moveable object
+ or ax,rflags ; ...plus any flags from the caller
+
+ and cl,GA_SEGTYPE
+ or al,cl
+ mov cx,dx ; get owner
+ push ds
+ SetKernelDS
+ife ROM
+ cmp fBooting, 1 ; Allocate high while booting
+ je @F
+endif
+ test al,GA_DISCCODE ; Discardable code segment?
+ jz ranotcode
+@@:
+ or al,GA_ALLOCHIGH ; Yes, allocate high
+ranotcode:
+ pop ds
+ UnSetKernelDS
+ mov [di].gi_cmpflags,al ; Save flags for gcompact
+ and [di].gi_cmpflags,CMP_FLAGS
+ push si ; save handle
+ call gsearch ; Find block big enough
+ pop si ; restore existing handle
+ jz racre_fail1
+
+ mov bx,ax ; save new block
+ cCall mark_sel_PRESENT,<ax,si> ; sets a new set of sels if necessary
+ or si,si
+ jz racre_worst_case
+ xchg ax,si ; Return original/new handle
+ ; Set back link to handle in new block
+ cCall AssociateSelector,<ax,si>
+ mov es,si
+ mov es:[di].ga_handle,ax
+ mov es:[di].ga_count,0
+ call glruadd ; Add to LRU chain
+ jmps racre_done
+
+racre_worst_case:
+ mov es,bx ; Free block if no handles available.
+ xor si,si
+ call gmarkfree
+
+racre_fail:
+ xor dx,dx
+racre_fail1:
+ push dx
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ pop dx
+ xor ax,ax ; Yes, return failure
+racre_done:
+ jmp raexit
+
+
+;-----------------------------------------------------------------------;
+; This is what most would have thought is the guts of GlobalRealloc. ;
+;-----------------------------------------------------------------------;
+
+ra_shrink_grow:
+
+if KDEBUG
+ test es:[di].ga_flags,GA_DISCCODE
+ jz ok
+ INT3_WARN ; GlobalRealloc of discardable code!
+ok:
+endif
+ cmp bx,es:[di].ga_size
+ jz rasame
+
+ add bx,1 ; add room for header, set carry bit
+ jc ra_s_g_fail
+ call galign ; assuming there is room.
+ dec dx ; Exclude header again
+ mov si,dx
+
+; Here if not trying to realloc this block to zero
+; ES:0 = arena header of current block
+; AX:0 = client address of current block
+; CH = lock count of current block
+; DX = new requested size of block
+; SI = new requested size of block
+
+ mov bx,es:[di].ga_next ; Get address of current next header
+ cmp si,es:[di].ga_size ; Are we growing or shrinking?
+ ja raextend ; We are growing
+
+ call rashrink
+rasame: mov ax,hMem ; Return the same handle
+ jmp raexit ; All done
+
+raextend:
+ test rflags,GA_DISCCODE ; Not allowed to grow a disccode seg
+ jnz ra_s_g_fail
+if KDEBUG
+ call CheckGAllocBreak
+ jc ra_s_g_fail
+endif
+ push ax
+ call GrowSelArray
+ mov numsels, cx ; Save how many to free just in case
+ mov cx, ax
+ pop ax
+ jcxz ra_s_g_fail ; Didn't get selectors
+ mov hMem, cx ; We have a new handle
+ call ragrow
+ jnc rasame
+ test mflags,GA_DISCARDABLE ; if discardable, just stop now
+ jz ramove ; since it might get discarded!
+ra_s_g_fail:
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ xor ax,ax ; Yes, return failure
+ xor dx,dx
+ jmp raexit
+
+
+; Here to try to move the current block
+; AX = client address of current block
+; ES:0 = arena header of current block
+; CH = lock count of current block
+; SI = new requested size of block
+
+ramove: mov canmove, 1
+ mov dx,rflags ; get the passed in flags
+ test dx,GA_MOVEABLE ; Did they say OK to move
+ jnz ramove1 ; Yes, try to move even iflocked or fixed
+ cmp locked, 0 ; Locked?
+ jnz racompact ; Continue if this handle not locked
+ ; yes, try to find space to grow in place
+ or dx,GA_MOVEABLE ; If moveable, make sure bit set.
+ test hMem,GA_FIXED ; Is this a moveable handle?
+ jz ramove2 ; Yes, okay to move
+racompact:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ jmps racantmove
+
+ramove1:
+ test hMem, GA_FIXED
+ jz ramove2
+ and dx, NOT GA_MOVEABLE
+ramove2:
+ mov ax,dx ; AX = allocation flags
+ mov bx,si ; BX = size of new block
+ call PreAllocSel ; for gmovebusy later
+ jz racantmove
+ mov cx,bx ; CX = owner (use size for now)
+ call gsearch ; Find block big enough
+ jz racantmove ; Cant find one, grow in place now?
+ mov cx,hMem
+
+ push ax
+ cCall get_arena_pointer,<cx>
+;;; mov es,ax
+;;; mov es,es:[di].ga_next ; get real arena header
+;;; mov si,es:[di].ga_prev
+ mov si, ax ; SI = source arena
+ pop es ; ES = destination arena
+
+ call gmovebusy ; Call common code to move busy block
+ ; (AX destroyed)
+ push bx
+ push cx
+ mov bx, es:[di].ga_size
+ xor cx,cx
+REPT 4
+ shl bx,1
+ rcl cx,1
+ENDM
+ cCall set_sel_limit, <es:[di].ga_handle>
+
+ pop cx
+ pop bx
+ mov ax,cx ; Return new handle
+raexit:
+ mov cx,ax
+ jcxz ra_done
+ test hMem,GA_FIXED ; Is this a moveable object?
+ jz ra_done ; no, don't lock
+ mov bx, ax
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ mov ax, 4 ; Lock the WIN386 pages
+ ; bugbugbugbug
+ DPMICALL ax ; int 31h
+ mov ax, bx
+endif
+ jmps ra_done
+
+racantmove:
+ mov dx, hMem
+ call pdref
+
+ mov bx,rsize
+ add bx,1 ; add room for header, set carry bit
+ call galign ; assuming there is room.
+ dec dx ; Exclude header again
+ mov si,dx
+
+ mov bx,es:[di].ga_next ; Get address of current next header
+ call ragrow
+ jc racmove3
+ jmp rasame
+
+racmove3:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ mov dx,ax ; DX = size of largest free block
+
+rafailmem:
+ cCall get_arena_pointer,<hMem>
+ mov es,ax
+ mov ax,es:[di].ga_size ; AX = size of current block
+ mov es,es:[di].ga_next ; Check following block
+ cmp es:[di].ga_owner,di ; Is it free?
+ jne rafailmem0 ; No, continue
+ add ax,es:[di].ga_size ; Yes, then include it as well
+ inc ax
+rafailmem0:
+ cmp ax,dx ; Choose the larger of the two
+ jbe rafailmem1
+ mov dx,ax
+rafailmem1:
+ push dx ; Save DX
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ pop dx ; RestoreDX
+ xor ax,ax
+ jmps raexit
+
+ra_done: ; 3 feb 1990, this
+ push ax ; is a last minute hack
+ push bx
+ push cx
+ push dx
+ mov bx,hMem
+ mov cx,oldhMem
+ife RING-1
+ inc bx
+ and bl,NOT 1
+ inc cx
+ and cl,NOT 1
+else
+ or bl, 1
+ or cl, 1
+endif
+ cmp bx,cx ; was a new selector allocated?
+ jz ra_really_done ;
+ or ax,ax ; figure out if we suceeded
+ jz ra_ra
+ cCall FreeSelArray,<cx> ; free the original selector
+ jmps ra_really_done
+
+ra_ra: cCall get_physical_address,<bx>
+ cCall set_physical_address,<oldhMem>
+ cCall get_arena_pointer,<hMem>
+ INT3_ANCIENT
+ cCall AssociateSelector,<cx,es>
+ push ax
+
+ mov cx, numsels
+ mov ax, hMem
+fsloop:
+ cCall free_sel,<ax>
+ add ax, 8
+ loop fsloop
+
+ pop es
+ mov ax,oldhMem
+ mov es:[ga_handle],ax
+ cCall AssociateSelector,<ax,es>
+
+ra_really_done:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; rashrink ;
+; ;
+; Shrinks the given block ;
+; ;
+; Arguments: ;
+; Here to shrink a block ;
+; ES:0 = arena header of current block ;
+; DX = new requested size of block ;
+; SI = new requested size of block ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; gsplice ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+; Tue 06-Feb-1990 01:03:54 -by- David N. Weise [davidw] ;
+; I got no clue what the history of this thing is, all I know is ;
+; that I got to fix it fast to prevent selector leak. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc rashrink,<PUBLIC,NEAR>
+cBegin nogen
+
+ mov bx,si
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+ mov ax,es:[di].ga_handle
+ or ax,ax
+ jz ra_free
+
+; !! the following was added Tue 06-Feb-1990 01:47:12
+; it doesn't belong here really but it is the only way to
+; prevent selector leak.
+
+ push bx
+ push cx
+ push si
+
+ mov si,ax
+ cCall GetAccessWord,<si>
+ mov bl, ah
+ mov ax, si
+ and bl, 0Fh ; Current hlimit
+ inc bl ; number of selectors there now
+ mov cx,dx
+
+ add cx, 0FFFh
+ rcr cx, 1 ; 17 bitdom
+ shr cx, 11
+ sub bl, cl
+ jbe ignore_this_shi
+
+ xor bh,bh ; BX = number of selectors to free
+ shl cx,3
+ .errnz SIZE DscPtr - 8
+ add cx,si ; CX = selector to start to free
+ xchg bx,cx
+@@: cCall free_sel,<bx>
+ add bx,SIZE DscPtr
+ loop @B
+
+ignore_this_shi:
+ pop si
+ pop cx
+ pop bx
+
+; end of shi
+
+ Handle_To_Sel al
+ cCall set_sel_limit,<ax>
+ra_free:
+ inc dx ; Test for small shrinkage
+ inc dx
+ .errnz GA_ALIGN - 1
+
+ cmp dx,es:[di].ga_size ; Enough room from for free block?
+ ja rashrunk ; No, then no change to make
+
+; !! why isn't the PreAllocSel done before the set_sel_limit?
+; Because it belongs with the 'gsplice'.
+
+ call PreallocSel ; Must be able to get selector
+ jz rashrunk
+ ; Yes, ES:DI = cur block, SI=new block
+ inc si ; Include header in size of block
+ call gsplice ; splice new block into the arena
+ mov es,si ; ES:DI = new free block
+ xor si,si
+ call gmarkfree ; Mark it as free
+rashrunk:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ragrow ;
+; ;
+; Tries to grow the given global memory object in place ;
+; ;
+; Arguments: ;
+; AX:0 = client address of current block ;
+; ES:0 = arena header of current block ;
+; BX:0 = arena header of next block ;
+; DX = SI = new requested size of block ;
+; ;
+; Returns: ;
+; CY = 0 Success ;
+; ;
+; CY = 1 Failed ;
+; ES preserved ;
+; DX contains free memory required ;
+; ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; is_there_theoretically_enough_space ;
+; can_we_clear_this_space ;
+; gjoin ;
+; gzero ;
+; rashrink ;
+; ;
+; History: ;
+; ;
+; Mon 05-Sep-1988 20:10:15 -by- David N. Weise [davidw] ;
+; Made ragrow be more intelligent by trying to extend into moveable ;
+; blocks. ;
+;-----------------------------------------------------------------------;
+cProc ragrow,<PUBLIC,NEAR>
+cBegin nogen
+
+ push si
+ push es ; Save current block address
+ sub dx, es:[di].ga_size ; compute amount of free space wanted
+ mov es,bx ; ES = next block address
+ mov cx,[di].hi_count
+ push cx
+ push es
+ call is_there_theoretically_enough_space
+ pop es
+ pop cx
+ cmp ax,dx
+ jb ragx
+ call can_we_clear_this_space
+ jz ragx
+ pop cx ; clear the stack
+ pop si
+ push si
+ call gjoin ; and attach to end of current block
+ pop si ; (will free a selector)
+ test byte ptr rflags,GA_ZEROINIT ; Zero fill extension?
+ jz ranz ; No, continue
+
+ mov bx, dx ; number of paragraphs to fill
+ mov dx, si ; New size of block
+ sub dx, bx ; Old size of block
+ inc dx ; Paragraph offset of where to zero
+ cCall alloc_data_sel_above,<es,dx>
+ push bx
+ push ax ; set the limit really big
+ push es
+ cCall SetSelectorLimit,<ax,0Fh,0FFFFh>
+ pop es
+ pop ax
+ pop cx ; Number of paragraphs to zero
+ mov bx, ax ; Selector to fill
+ call gzero ; zero fill extension
+ cCall free_sel,<bx>
+ranz:
+ mov dx, si
+ mov bx,es:[di].ga_next ; Pick up new next block address
+ call rashrink ; Now shrink block to correct size
+ clc
+ ret
+ragx:
+ pop es ; Recover current block address
+ pop si
+ stc
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfree ;
+; ;
+; Frees a global object. ;
+; ;
+; Arguments: ;
+; DX = global memory object handle ;
+; CX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; CX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; gdref ;
+; free_object ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 11:48:38a -by- David N. Weise [davidw] ;
+; Added this nifty comment block and restructured. ;
+;-----------------------------------------------------------------------;
+
+cProc gfree,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ call pdref
+
+ pop dx
+ jz object_discarded
+ call free_object
+ jmps gfree_exit
+object_discarded:
+
+ cCall AssociateSelector,<si,di>
+ cCall FreeSelArray,<si>
+ xor ax,ax ;!!! just for now force success
+
+gfree_exit:
+ mov cx,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_object ;
+; ;
+; Arguments: ;
+; DX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ES:DI = address of arena header ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrudel ;
+; gmarkfree ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:59:06p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+cProc free_object,<PUBLIC,NEAR>
+cBegin nogen
+ or dx,dx
+ jz free_it
+ cmp es:[di].ga_owner,dx
+ je free_it
+ mov ax,-1
+ jmps free_object_exit
+free_it:
+ call glrudel ; delete object from LRU chain
+ xor si,si
+ call gmarkfree ; free the object
+ cCall AssociateSelector,<si,di>
+ cCall FreeSelArray,<si>
+ xor ax,ax ;!!! just for now force success
+free_object_exit:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_handle ;
+; ;
+; Frees the given handle. ;
+; ;
+; Arguments: ;
+; DS:SI = handle table entry address ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; BX ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:30:32p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+;cProc free_handle,<PUBLIC,NEAR>
+;cBegin nogen
+; xor ax,ax
+; or si,si
+; jz free_handle_exit
+; push bx
+; mov bx,si
+; call hfree
+; pop bx
+;free_handle_exit:
+; ret
+;cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfreeall ;
+; ;
+; Frees all global objects that belong to the given owner. It first ;
+; loops through the global heap freeing objects and then loops through ;
+; the handle table freeing handles of discarded objects. ;
+; ;
+; Arguments: ;
+; DX = owner field value to match ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,ES,SI ;
+; ;
+; Calls: ;
+; free_object ;
+; henum ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:46:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gfreeall,<PUBLIC,NEAR>
+cBegin nogen
+
+ mov es,[di].hi_first ; ES:DI points to first arena entry
+ mov cx,[di].hi_count ; CX = #entries in the arena
+free_all_objects:
+ push cx
+ call free_object ; Free object if matches owner
+ pop cx
+ mov es,es:[di].ga_next ; Move to next block
+ loop free_all_objects
+
+; may go extra times, as CX does not track coalescing done by gfree,
+; but no big whoop
+
+
+ push ax
+ push bx
+ push di
+ SetKernelDS es
+ mov si, SelTableStart
+ mov cx, SelTableLen
+ shr cx, 1
+ mov di, si
+ smov es, ds
+ UnSetKernelDS es
+
+free_all_handles_loop:
+ mov ax, dx
+ repne scas word ptr es:[di] ; Isn't this easy?
+ jne short we_be_done
+ lea bx, [di-2]
+ sub bx, si
+ shl bx, 2
+ or bl, SEG_RING
+
+if KDEBUG
+ lsl ax, bx
+ cmp ax, dx
+ je @F
+ INT3_ANCIENT
+@@:
+endif
+
+ cCall GetAccessWord,<bx>
+ test al,DSC_PRESENT ; segment present?
+ jnz short free_all_handles_loop ; yes, not a handle
+ test ah,DSC_DISCARDABLE ; discardable?
+ jz short free_all_handles_loop ; no, nothing to free
+ cCall free_sel,<bx>
+ mov word ptr [di-2], 0 ; Remove owner from table
+ jcxz we_be_done
+ jmps free_all_handles_loop
+we_be_done:
+ pop di
+ pop bx
+ pop ax
+
+
+gfreeall_done:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glock ;
+; ;
+; Increment the lock count of an object in handle table entry ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; DX = segment address of object ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count ;
+; DX = pointer to client area ;
+; ;
+; Error Returns: ;
+; ZF = 1 if count overflowed. ;
+; ;
+; Registers Preserved: ;
+; AX ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:38:57p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc glock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ inc ch ; Increment lock count
+ jz overflow ; All done if overflow
+ mov es:[di].ga_count,ch ; Update lock count
+glockerror:
+overflow:
+ pop ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gunlock ;
+; ;
+; Decrement the lock count of an object. ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; CX = handle table flags and lock count for moveable objects ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count, no underflow ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrutop ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 04:39:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gunlock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ mov ax,bx
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; ff -> fe, 0 -> ff
+ jae count_zero ; Return if pinned, or was already 0
+ dec es:[di].ga_count ; Non-zero update lock count
+ jnz count_positive ; All done if still non-zero
+ test cl,GA_DISCARDABLE ; Is this a discardable handle?
+ jz count_zero ; No, all done
+ call glrutop ; Yes, bring to top of LRU chain
+count_zero:
+ xor cx,cx
+count_positive:
+ pop ax
+ ret
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/2gmemini.asm b/private/mvdm/wow16/kernel31/2gmemini.asm
new file mode 100644
index 000000000..8a2f5a6d5
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2gmemini.asm
@@ -0,0 +1,830 @@
+ page ,132
+
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+
+.sall
+.xlist
+include kernel.inc
+include protect.inc
+.list
+
+DataBegin
+
+externB Kernel_Flags
+externW hGlobalHeap
+externW pGlobalHeap
+externW sel_alias_array
+externW WinFlags
+externW SelTableLen
+externD SelTableStart
+
+DataEnd
+
+DataBegin INIT
+
+ INITIAL_BLOCK_SIZE equ 0 ; one meg
+ NUM_DPMI_BLOCKS equ 20 ; Impossibly huge number
+
+DPMI_block STRUC
+ blksize dw 0
+ addr_lo dw 0
+ addr_hi dw 0
+DPMI_block ENDS
+
+DPMI_memory DPMI_block NUM_DPMI_BLOCKS DUP (<>)
+
+top_block dw ?
+
+DataEnd INIT
+
+sBegin INITCODE
+assumes CS,CODE
+
+externW gdtdsc
+
+externNP get_physical_address
+externNP set_physical_address
+externNP set_sel_limit
+externNP alloc_data_sel
+externNP get_arena_pointer
+externNP get_rover_2
+externNP AssociateSelector
+externNP AllocDpmiBlock
+externNP FormatHeapBlock
+externNP AddBlockToHeap
+
+externFP GlobalAlloc
+externNP DPMIProc
+
+GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
+GA_MASK_BYTES = NOT GA_ALIGN_BYTES
+
+
+;-----------------------------------------------------------------------;
+; GlobalPigAll ;
+; ;
+; Allocates all the DPMI memory in the system as blocks of 1 Meg. ;
+; or smaller. Stores the addresses and sizes in the DPMI_memory array. ;
+; ;
+;-----------------------------------------------------------------------;
+cProc GlobalPigAll,<NEAR,PUBLIC>,<ds,es,di,si,ax,bx,cx,dx>
+ localV MemInfo,30h
+ localW saveCX
+cBegin
+ smov es, ss
+ SetKernelDS
+ifdef WOW
+; DOSX is not efficient about the way it manages its heap. If we alloc
+; the largest block an then free it - it will do better management
+; when we alloc 1Mbyte chunks. Otherwise it will alloc 3 selectors
+; and 1k of unused memory per megabyte
+ lea di, MemInfo
+ DPMICALL 0500h ; Get Free Memory Info
+ mov cx, es:[di] ; BX:CX gets largest free block
+ mov bx, es:[di+2]
+ or ax,bx
+ jz idb_gotblocks ; None to be had!
+
+ DPMICALL 0501h ; allocate is all
+ DPMICALL 0502h ; Free it all
+endif; WOW
+ mov si,dataOffset DPMI_memory ; DS:SI -> first DPMI_block
+ mov cx,NUM_DPMI_BLOCKS
+idb_getblock:
+ mov word ptr saveCX,cx
+ lea di, MemInfo
+ DPMICALL 0500h ; Get Free Memory Info
+ mov cx, es:[di] ; BX:CX gets largest free block
+ mov bx, es:[di+2]
+ mov ax,cx
+ or ax,bx
+ jz idb_gotblocks ; None to be had!
+
+ cmp bx,0010h ; 1 Meg. or more available?
+ jb @F ; No, use what is available
+ mov bx,0010h
+ xor cx,cx
+@@: ; BX:CX is bytes to allocate
+ mov dx,bx ; copy to DX:AX
+ mov ax,cx
+rept 4
+ shr dx,1
+ rcr ax,1
+endm
+ mov [si].blksize,ax ; Size is #paragraphs we hope to get
+
+;
+; This call returns an address in BX:CX, and a handle in SI:DI. We don't
+; use the handle for anything, but we do use SI here.
+;
+ push si
+ DPMICALL 0501h ; allocate the block
+ pop si
+
+ jc idb_gotblocks
+ mov [si].addr_lo,cx
+ mov [si].addr_hi,bx
+ add si,SIZE DPMI_block
+
+ mov cx,word ptr saveCX
+ loop idb_getblock
+
+idb_gotblocks:
+ mov [top_block],si
+
+ UnsetKernelDS
+cEnd
+
+ ;
+;-----------------------------------------------------------------------;
+; Find_DPMI_block ;
+; ;
+; Allocate a block of memory from DPMI that is 1 megabyte in size, ;
+; or the largest available block if smaller. ;
+; ;
+; RETURNS: AX = selector to block if allocated ;
+; AX = zero if error ;
+; CX = size of block in paragraphs (yech!) ;
+; CX = zero if block is 1 megabyte in size. ;
+;-----------------------------------------------------------------------;
+
+cProc Find_DPMI_block,<PUBLIC,NEAR>,<ds,si,es,di,bx,dx>
+ localV MemInfo,30h
+ localW SizeOfBlock
+cBegin
+ SetKernelDS
+ smov es, ds
+ xor ax,ax ; AX = 0
+ mov si,dataOffset DPMI_memory ; DS:SI -> first DPMI_block
+
+adb_findfirstblock:
+ cmp si,[top_block]
+ jnb adb_ret
+ mov cx,[si].addr_lo
+ mov bx,[si].addr_hi
+ or bx,cx
+ jnz adb_foundfirstblock
+ add si,SIZE DPMI_block ; SI -> next block
+ jmp adb_findfirstblock
+
+adb_foundfirstblock:
+ mov di,si ; SI -> first block
+
+adb_nextblock:
+ add di,SIZE DPMI_block ; DI -> next block
+ cmp di,[top_block]
+ jnb adb_foundblock
+
+ mov dx,[si].addr_lo ; which block is lower?
+ cmp dx,[di].addr_lo
+ mov dx,[si].addr_hi
+ sbb dx,[di].addr_hi
+
+ jb adb_nextblock ; block at si is lower than block at di
+
+ mov dx,[si].addr_lo
+ xchg dx,[di].addr_lo
+ xchg dx,[si].addr_lo
+
+ mov dx,[si].addr_hi
+ xchg dx,[di].addr_hi
+ xchg dx,[si].addr_hi
+
+ mov dx,[si].blksize
+ xchg dx,[di].blksize
+ xchg dx,[si].blksize
+
+ jmp adb_nextblock
+
+adb_foundblock: ; DS:SI -> block to use
+ mov bx,ax
+ mov cx,ax
+ xchg bx,[si].addr_hi
+ xchg cx,[si].addr_lo
+ cCall alloc_data_sel,<bx,cx,1>; Get selector for start of block
+ ; (return result)
+ mov cx,[si].blksize
+adb_ret:
+ UnsetKernelDS
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalInit ;
+; ;
+; Procedure to initialize the global heap. ;
+; ;
+; Arguments: ;
+; parmW hdelta = size (.25k) of master object ;
+; parmW palloc = selector of block to mark allocated ;
+; parmW pstart = selector pointing to first available address ;
+; parmW pend = selector pointing to last available address ;
+; ;
+; Note: for the ROM kernel, palloc is actually the size in bytes ;
+; of the allocated block, not a pointer! ;
+; ;
+; Returns: ;
+; AX = handle for allocated block ;
+; ;
+; Error Returns: ;
+; ;
+; Alters: ;
+; ES ;
+; Calls: ;
+; ginit ;
+; ;
+; History: ;
+; ;
+; Fri May 05, 1989 09:40:00a -by- Jim Mathews [jimmat] ;
+; Dear diary, many things have happened since the last comment entry... ;
+; Added code to allocate a block of conventional memory and link it ;
+; into the Windows global heap when running under the 286 DOS extender. ;
+; ;
+; Sat Jun 20, 1987 05:55:35p -by- David N. Weise [davidw] ;
+; Making real EMS work with the fast boot version. ;
+; ;
+; Sun Mar 15, 1987 06:38:04p -by- David N. Weise [davidw] ;
+; Added support for the linked free list long ago. ;
+; ;
+; Wed Feb 18, 1987 08:09:18p -by- David N. Weise [davidw] ;
+; Added the initialization of the gi_alt entries. ;
+; ;
+; Mon Sep 08, 1986 07:53:41p -by- David N. Weise [davidw ;
+; Changed the return values so that this can be called from other than ;
+; initialization code. ;
+;-----------------------------------------------------------------------;
+
+cProc GlobalInit,<PUBLIC,NEAR>,<ds,si,di>
+ parmW hdelta
+ parmW palloc
+ parmW pstart
+ parmW pend
+ localW hInitMem
+ localW allocated_sel
+ localW next_block
+ localW free_hi
+ localW free_lo
+ localV MemInfo,30h
+
+cBegin
+
+ mov ax,palloc ; AX = block to mark allocated
+ mov bx,pstart ; BX = first available address
+ mov cx,hdelta ; CX = size (.25k) of master object
+ mov dx,pend ; DX = last available address
+ call ginit
+
+ mov allocated_sel,ax
+
+ xor di,di ; Initialize master object
+ mov [di].hi_first,bx ; Fill in pointers to first and
+ mov [di].hi_last,dx ; last blocks
+ mov [di].hi_count,5 ; 5 arena entries
+ or ax,ax
+ jnz allocated_block
+ mov [di].hi_count,4 ; 4 arena entries
+allocated_block:
+ mov [di].gi_lruchain,di ; Nothing in LRU list so far
+ mov [di].gi_lrucount,di
+ mov [di].gi_lrulock,di ; ...and not locked
+ mov [di].gi_reserve,di ; No discardable code reserve area yet
+
+ cCall get_physical_address, <dx>
+ mov word ptr [di].gi_disfence,ax ; gi_disfence = hi_last
+ mov word ptr [di].gi_disfence_hi,dx
+
+ mov [di].hi_hdelta,32
+
+ mov [di].gi_alt_first,-1 ; Fill in pointers to first and
+ mov [di].gi_alt_last,-1 ; last blocks, the -1 is necessary!!
+ mov [di].gi_alt_count,di ; # of arena entries
+ mov [di].gi_alt_lruchain,di
+ mov [di].gi_alt_lrucount,di ; MUST be 0!
+ mov [di].gi_alt_free_count,di
+ mov [di].gi_alt_reserve,di
+ mov [di].gi_alt_disfence,di
+ mov [di].gi_alt_pPhantom,-1 ; MUST be -1!
+
+ mov bx,ds
+ SetKernelDS es
+ mov hGlobalHeap,bx
+ cCall get_arena_pointer,<ds>
+
+ mov es,ax
+ assumes es,nothing
+ mov es:[di].ga_handle,bx ; Point master object to handle
+ mov es:[di].ga_count,0
+ push es:[di].ga_next ; Push free block arena
+
+ife ROM
+ mov es, [di].hi_last
+endif
+ mov es,es:[di].ga_prev ; Point to allocated object before
+ mov bx,allocated_sel
+ StoH bl ; It is moveable
+
+ mov es:[di].ga_handle,bx
+ mov hInitMem,bx
+if ROM ; For ROM Windows, the alloc block is
+ mov es:[di].ga_count,1 ; krnl DS which needs to be locked!
+else
+ mov es:[di].ga_count,0
+endif
+no_allocated_object:
+
+; initialize free list
+
+ mov [di].gi_free_count,1
+ mov ax,[di].hi_first
+ mov cx,[di].hi_last
+ mov es,ax
+ pop bx ; Free block arena
+ mov es:[di].ga_freeprev,-1 ; Fill in first sentinal
+ mov es:[di].ga_freenext,bx
+ mov es,cx
+ mov es:[di].ga_freeprev,bx ; Fill in last sentinal
+ mov es:[di].ga_freenext,-1
+ mov es,bx
+ mov es:[di].ga_freeprev,ax ; Link in free block
+ mov es:[di].ga_freenext,cx
+
+GI_done:
+
+;
+; Allocate a block for the heap
+;
+ mov ax,INITIAL_BLOCK_SIZE
+ xor si,si
+ call AllocDpmiBlock
+ or bx,bx
+ jnz ginom
+ mov si,1
+ginom: mov dx,ax
+ call FormatHeapBlock ;build the arenas in the XMS block
+ assume es:NOTHING
+ call AddBlockToHeap
+
+if ALIASES
+ call init_alias_list
+endif
+
+ mov ax,hInitMem
+ clc
+ jmps @f
+
+GI_fail:
+ xor ax,ax
+ stc
+@@:
+
+cEnd
+
+
+gi_set_size proc near
+
+ cCall get_physical_address, <es:[di].ga_next>
+ mov bx, ax
+ mov cx, dx
+ cCall get_physical_address, <es>
+ sub bx, ax
+ sbb cx, dx
+rept 4
+ shr cx, 1
+ rcr bx, 1
+endm
+ dec bx
+ mov es:[di].ga_size, bx
+ ret
+
+gi_set_size endp
+
+
+;-----------------------------------------------------------------------;
+; ginit ;
+; ;
+; Procedure to initialize the global heap. ;
+; ;
+; The global heap looks as follows after this procedure returns: ;
+; ;
+; BX - first object in arena, alway busy, zero length. ;
+; - free object ;
+; AX - allocated object ;
+; DS - master object ;
+; DX - last object in arena, alway busy, zero length. ;
+; ;
+; ;
+; Arguments: ;
+; AX = address of block to mark allocated. May be zero. ;
+; BX = address of first paragraph in arena ;
+; DX = address of last paragraph in arena ;
+; CX = initial size of master object, in bytes ;
+; ;
+; Note: for the ROM kernel, AX is actually the size in bytes of ;
+; the allocated block, not it's address. ;
+; ;
+; Returns: ;
+; AX = aligned address of block marked allocated. ;
+; BX = aligned address of first object in arena ;
+; CX = size of master object, in bytes ;
+; DX = aligned address of last object in arena ;
+; DS = aligned address of master object ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; DI,SI,ES ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Thu Sep 11, 1986 04:22:02p -by- David N. Weise [davidw] ;
+; Commented it, made it handle the case of no allocated block correctly.;
+;-----------------------------------------------------------------------;
+
+cProc ginit,<PUBLIC,NEAR>
+
+ localW size_free
+ localW size_allocated
+ localW size_master
+ localW allocated_arena
+ localW allocated_sel
+ localW BurgerMaster_arena
+ localW BurgerMaster_sel
+ localW new_last_sel
+ localW size_free_hi
+ localW marker_arena
+
+cBegin
+
+; SI = the first block address (sentinel, always busy)
+
+ CheckKernelDS
+ ReSetKernelDS
+if ROM
+ xchg ax,dx ; want diff stack order if ROM
+ mov allocated_sel, ds ; something of a hack that this
+ ; code 'knows' DS is the alloc
+ ; block
+endif
+ push ax
+ push dx
+
+ cCall get_physical_address,<bx> ; Start of our memory
+
+%OUT Is alignment necessary???
+
+ add ax, GA_ALIGN_BYTES ; Align our start
+ adc dx, 0
+ and ax, GA_MASK_BYTES
+
+ cCall set_physical_address, <bx>
+ mov si, bx ; first sentinal
+ mov bx, 10h ; just an arena
+ xor cx, cx
+ cCall set_sel_limit, <si>
+
+if ROM ;----------------------------------------------------------------
+
+; The allocated block (kernel's data segment) is next, and already in place
+
+ add ax, 10h+GA_ALIGN_BYTES
+ adc dx, 0
+ and al, GA_MASK_BYTES
+ push ax
+ cCall alloc_data_sel,<dx,ax,1> ; Get arena for data seg
+ mov allocated_arena, ax
+ pop ax
+
+if KDEBUG
+ push dx
+ push ax
+ mov cx,ax
+ mov bx,dx
+ add cx,10h
+ adc bx,0 ; BX:CX better -> DS
+ cCall get_physical_address,<ds>
+ cmp ax,cx
+ jne rom_oh_no
+ cmp dx,bx
+ jz @f
+rom_oh_no:
+ Debug_Out "ginit: DS arena in wrong spot!"
+@@:
+ pop ax
+ pop dx
+endif
+ pop bx ; size of alloc block
+ add ax,bx
+ adc dx,0
+
+ add bx,15 ; save size of alloc
+ and bl,NOT 15 ; block in paragraphs
+ shr bx,4
+ mov size_allocated,bx
+
+endif ;ROM ---------------------------------------------------------
+
+
+; CX = where the master object goes (second block)
+
+ add ax, 10h+GA_ALIGN_BYTES ; Skip past sentinal
+ adc dx, 0
+ and al, GA_MASK_BYTES
+ push ax
+ cCall alloc_data_sel,<dx, ax, 1> ; Get arena for BurgerMaster
+ mov BurgerMaster_arena, ax
+
+ mov cx, size GlobalInfo+1
+ and cl, NOT 1 ; Word align selector table -
+ mov word ptr SelTableStart, cx ; it starts after GlobalInfo
+ ;;;mov ax, 8*1024 ; Selector table length
+ mov ax, 8*1024*2 ; Assume 8k sels * 2 bytes each
+ test [WinFlags], WF_ENHANCED ; Slime to allow 286 krnl under
+ jnz @f ; 386enh mode where LDT grows
+ mov bx, gdtdsc
+ or bx, bx
+ jz @f ; If we party on the LDT,
+ lsl ax, bx ; use the LDT limit to size
+ add ax, 1 ; the table
+ rcr ax, 1
+ shr ax, 1 ; ASSUMES LDT DOES NOT GROW!!!
+@@:
+ mov SelTableLen, ax
+ add cx, ax
+ add cx, GA_ALIGN_BYTES+10h ; Include arena header
+ and cl, GA_MASK_BYTES
+
+ pop ax ; DX:AX is address of arena
+ mov bx, cx
+ shr bx, 4 ; length in paras
+ dec bx ; excluding arena header
+ mov size_master, bx
+ push ax ; Save start of master object arena
+ push dx
+ add ax, 10h
+ adc dx, 0
+ cCall alloc_data_sel, <dx, ax, bx>
+ mov BurgerMaster_sel, ax
+ pop dx
+ pop ax
+ add ax, cx ; Move past master object
+ adc dx, 0
+
+; DI = the third block address (initial free block)
+
+ cCall alloc_data_sel,<dx, ax, 1>
+ mov di, ax ; First free block
+
+; DX = the last block address (sentinel, always busy)
+
+if ROM
+ pop dx
+ cCall get_physical_address,<dx> ; End of our world
+else
+ pop ax
+ xor dx, dx
+ REPT 4
+ shl ax, 1
+ rcl dx, 1
+ ENDM
+endif
+ sub ax, 10h
+ sbb dx, 0
+ and ax, GA_MASK_BYTES
+ mov bx, ax ; Save end of allocated block
+ mov cx, dx
+ cCall alloc_data_sel, <dx, ax, 1>
+ mov new_last_sel, ax ; Save it away
+
+ife ROM ;----------------------------------------------------------------
+
+ pop ax ; Allocated Block
+ cCall get_physical_address, <ax>
+ sub ax, 10h ; Make room for arena
+ sbb dx, 0
+ and al, GA_MASK_BYTES ; "Align" it
+
+ sub bx, ax
+ sbb cx, dx ; Length in bytes
+rept 4
+ shr cx, 1
+ rcr bx, 1
+endm
+ dec bx ; Length in paras
+ mov size_allocated, bx
+
+ push ax
+ cCall alloc_data_sel, <dx, ax, 1>
+ mov allocated_arena, ax
+ pop ax
+ add ax, 10h
+ adc dx, 0
+ push ax
+ cCall alloc_data_sel, <dx, ax, 1000h>
+ mov allocated_sel, ax
+ pop ax
+
+ sub ax, 10h
+ sbb dx, 0 ; Back to arena
+ mov bx, ax
+ mov cx, dx ; cx:bx = addr allocated arena
+
+endif ;ROM ---------------------------------------------------------
+
+ cCall get_physical_address, <di>
+ sub bx, ax
+ sbb cx, dx ; Length in bytes of free block
+rept 4
+ shr cx, 1
+ rcr bx, 1
+endm
+ sub bx, 1 ; Length in paras
+ sbb cx, 0
+ mov size_free, bx
+ mov size_free_hi, cx
+
+ mov ax, allocated_arena
+ mov cx, BurgerMaster_arena
+ mov dx, new_last_sel
+
+; Fill in first block
+
+ mov ds,si
+assumes ds, nothing
+ xor bx,bx
+ mov ds:[bx].ga_sig,GA_SIGNATURE
+ mov ds:[bx].ga_size,GA_ALIGN
+ mov ds:[bx].ga_owner,-1
+ mov ds:[bx].ga_flags,bl
+ mov ds:[bx].ga_prev,ds ; first.prev = self
+if ROM
+ mov ds:[bx].ga_next,ax ; Next is the allocated block
+else
+ mov ds:[bx].ga_next,cx ; Next is master object
+endif
+ mov ds:[bx].ga_handle,bx
+ mov ds:[bx].ga_lrunext,bx
+ mov ds:[bx].ga_lruprev,bx
+ push ds ; Save pointer to first block
+
+; Fill in the last block (sentinel block)
+
+ mov ds,dx
+ mov ds:[bx].ga_sig,GA_ENDSIG
+ mov ds:[bx].ga_size,GA_ALIGN
+ mov ds:[bx].ga_owner,-1 ; Always allocated
+ mov ds:[bx].ga_next,ds ; last.next = self
+ mov ds:[bx].ga_flags,bl
+ mov ds:[bx].ga_handle,bx
+ mov ds:[bx].ga_lrunext,bx
+ mov ds:[bx].ga_lruprev,bx
+ push ds ; Save pointer to last block
+if ROM
+ mov ds:[bx].ga_prev,di ; Previous is free block
+else
+ mov ds:[bx].ga_prev,ax ; Previous is allocated block
+endif
+
+; Fill in the allocated block
+
+ mov ds,ax
+if ROM
+ mov ds:[bx].ga_next, cx ; next object is burger master
+else
+ mov ds:[bx].ga_next, dx ; next object is sentinel
+endif
+ mov dx,size_allocated
+ mov ds:[bx].ga_sig,GA_SIGNATURE
+ mov ds:[bx].ga_size,dx
+ mov ds:[bx].ga_owner,-1
+ mov ds:[bx].ga_flags,bl
+ mov ds:[bx].ga_handle,bx
+ mov ds:[bx].ga_lruprev,bx
+ mov ds:[bx].ga_lrunext,bx
+if ROM
+ mov ds:[bx].ga_prev, si ; Previous object is sentinal
+else
+ mov ds:[bx].ga_prev, di ; Previous object is free block
+endif
+
+; Fill in free block
+
+ mov ds,di
+if ROM
+ mov dx,new_last_sel
+ mov ds:[bx].ga_next, dx ; Next ojb is last block
+else
+ mov ds:[bx].ga_next, ax ; Next obj allocated block
+endif
+ mov dx,size_free
+
+ cmp size_free_hi, 0
+ je gi_small
+ xor dx, dx ; BOGUS VALUE!!
+gi_small:
+
+ mov ds:[bx].ga_sig,GA_SIGNATURE
+ mov ds:[bx].ga_owner,bx ; This is a free block
+ mov ds:[bx].ga_flags,bl
+ mov ds:[bx].ga_size,dx
+ mov ds:[bx].ga_prev,cx
+ mov ds:[bx].ga_handle,bx
+ mov ds:[bx].ga_lruprev,bx
+ mov ds:[bx].ga_lrunext,bx
+
+; Fill in the master object
+
+ mov ds,cx
+ mov ds:[bx].ga_next,di
+if ROM
+ mov ds:[bx].ga_prev,ax ; prev obj is allocated block
+else
+ mov ds:[bx].ga_prev,si
+endif
+ mov cx,size_master
+ mov ds:[bx].ga_sig,GA_SIGNATURE
+ mov ds:[bx].ga_size,cx
+ mov ds:[bx].ga_owner,-3
+ mov ds:[bx].ga_flags,bl
+ mov ds:[bx].ga_handle,bx ; No handle table entry for this
+ ; moveable object yet.
+ mov ds:[bx].ga_lruprev,bx
+ mov ds:[bx].ga_lrunext,bx
+
+; Initialize master object
+
+ ; CX = size of master object in paras
+;;; mov dx, ds ; DX = address of master object
+
+ mov dx,BurgerMaster_sel
+
+ shl cx,1 ; Get size of master object in words
+ shl cx,1
+ shl cx,1
+
+ push cx ; save size in words
+
+ SetKernelDS
+ mov pGlobalHeap,dx
+ mov es,dx
+ assumes es,nothing
+ xor ax,ax
+ xor di,di ; Init master object to zero
+ rep stosw
+
+ mov ds,dx ; Switch to master object as our DS
+ UnSetKernelDS
+
+ cCall AssociateSelector,<ds,BurgerMaster_arena>
+
+ pop cx
+ shl cx,1 ; CX = size of master object in bytes
+
+ mov ax, allocated_sel ; AX = address of allocated block
+ cCall AssociateSelector,<ax,allocated_arena>
+ pop dx ; DX = address of last block
+ pop bx ; BX = address of first block
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; init_alias_list
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 15-Jan-1990 23:59:36 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc init_alias_list,<PUBLIC,NEAR>
+
+cBegin nogen
+ push ds
+ SetKernelDS
+ cCall GlobalAlloc,<GA_ZEROINIT,0,256>
+ or ax,ax
+ jz ial_exit
+ mov sel_alias_array,ax
+ mov es,ax
+ xor di,di
+ mov es:[di].sa_size,256 - SIZE SASTRUC
+ mov es:[di].sa_allocated,(256 - (SIZE SASTRUC)) / (SIZE SAENTRY)
+ mov ax,1 ; signify success
+ial_exit:
+ pop ds
+ ret
+cEnd nogen
+
+
+
+sEnd INITCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/2gmoreme.asm b/private/mvdm/wow16/kernel31/2gmoreme.asm
new file mode 100644
index 000000000..8cf963711
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2gmoreme.asm
@@ -0,0 +1,917 @@
+ TITLE GMOREMEM - More Global Memory Manager procedures
+
+.xlist
+include kernel.inc
+include tdb.inc
+include newexe.inc
+include protect.inc
+.list
+
+ .286
+
+DataBegin
+
+externB Kernel_Flags
+;externW hGlobalHeap
+externW pGlobalHeap
+externW curTDB
+externW headTDB
+externW cur_dos_PDB
+externW Win_PDB
+externW MaxCodeSwapArea
+
+DataEnd
+
+externFP CalcMaxNRSeg
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+;externW MyCSDS
+
+if SDEBUG
+externNP DebugMovedSegment
+endif
+
+;if SWAPPRO
+;externNP WriteDiscardRecord
+;endif
+
+externNP real_dos
+externNP gcompact
+externNP get_physical_address
+externNP get_arena_pointer
+externNP GetAccessWord
+externFP CVWBreak
+externNP GrowHeap
+
+if LDCHKSUM
+externNP ZeroSegmentChksum
+endif
+
+
+;-----------------------------------------------------------------------;
+; genter ;
+; ;
+; Enters a critical region for the global heap. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; DS:DI = address of GlobalInfo for global heap ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 29, 1986 03:05:33p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc genter,<PUBLIC,NEAR>
+cBegin nogen
+ SetKernelDS
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ xor di,di
+ inc [di].gi_lrulock
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gleave ;
+; ;
+; Leaves a critical region for the global heap. ;
+; ;
+; Arguments: ;
+; DS:DI = address of GlobalInfo for global heap ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 29, 1986 03:07:53p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gleave,<PUBLIC,NEAR>
+
+cBegin nogen
+ dec ds:[gi_lrulock]
+ jnz gl_ret
+ test ds:[gi_flags],GIF_INT2
+ jz gl_ret
+ and ds:[gi_flags],NOT GIF_INT2
+ pushf
+ call CVWBreak
+gl_ret: ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gavail ;
+; ;
+; Gets the available memory. ;
+; ;
+; Arguments: ;
+; DX = number of paragraphs wanted ;
+; DS:DI = master object ;
+; Returns: ;
+; AX = #paragraphs available for the biggest block ;
+; DX = 0 ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; DI,DS ;
+; Registers Destroyed: ;
+; BX,CX,SI,ES ;
+; Calls: ;
+; gcompact ;
+; ;
+; History: ;
+; Thu Apr 06, 1988 08:00:00a -by- Tim Halvorsen [iris] ;
+; Fix bug in computation of space available when GA_NOT_THERE object ;
+; resides above discard fence. ;
+; ;
+; Wed Oct 15, 1986 05:09:27p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Sat Sep 27, 1986 09:37:27a -by- David N. Weise [davidw] ;
+; Reworked it. ;
+;-----------------------------------------------------------------------;
+
+cProc gavail,<PUBLIC,NEAR>
+cBegin nogen
+ mov byte ptr [di].gi_cmpflags,0
+ call gcompact
+ mov es,[di].hi_first
+ xor dx,dx
+loop_for_beginning:
+ xor ax,ax
+ mov es,es:[di].ga_next ; Next block
+ cmp es:[di].ga_sig,GA_ENDSIG ; End of arena?
+ jnz blecher
+ jmp all_done
+blecher:
+ cmp es:[di].ga_owner,di ; Free?
+ jz how_big_is_it ; Yes
+ mov si,es:[di].ga_handle
+ or si,si ; Fixed?
+ jz loop_for_beginning ; Yes, next block
+ cmp es:[di].ga_count,0 ; Locked?
+ jne loop_for_beginning ; Yes, next block
+ push ax
+ cCall GetAccessWord,<si>
+ test ah, DSC_DISCARDABLE
+ pop ax
+ jz loop_for_beginning ; No, next block
+
+how_big_is_it:
+ mov ax,es:[di].ga_size ; Use this size
+loop_for_bigness:
+ mov es,es:[di].ga_next ; Next block
+ cmp es:[di].ga_owner,di ; Free?
+ jz include_his_size ; Yes, include size
+
+ cmp es:[di].ga_sig,GA_ENDSIG ; End of arena?
+ jz all_done
+ mov si,es:[di].ga_handle
+ or si,si ; Fixed?
+ jz end_of_bigness ; Yes, stop looking
+ cmp es:[di].ga_count,0 ; Locked?
+ jne end_of_bigness ; Yes, stop looking
+ push ax
+ cCall GetAccessWord,<si>
+ test ah, DSC_DISCARDABLE
+ pop ax
+ jz dont_include_him ; No, dont include in count then
+include_his_size: ; Free or Discardable
+ add ax,es:[di].ga_size ; Increase availabe space
+ inc ax ; by size of this block
+dont_include_him: ; Moveable
+ jmp loop_for_bigness
+
+end_of_bigness:
+ mov si,es
+ cmp es:[di].ga_owner,GA_NOT_THERE
+ jnz nothing_not_there
+ push ax
+ push dx
+ cCall get_physical_address,<si>
+ sub ax,word ptr [di].gi_disfence_lo
+ sbb dx,word ptr [di].gi_disfence_hi
+ jae fence_lower
+ pop dx
+ pop ax
+ jmps nothing_not_there
+
+fence_lower:
+ REPT 4
+ shr dx,1
+ rcr ax,1
+ ENDM
+ mov si,ax
+ pop dx
+ pop ax
+ sub ax,si
+ jmps all_done_1
+
+nothing_not_there:
+ cmp ax,dx ; Did we find a bigger block?
+ jbe blech_o_rama ; No, then look again
+ mov dx,ax ; Yes, remember size
+blech_o_rama:
+ jmp loop_for_beginning
+
+all_done:
+ sub ax,[di].gi_reserve ; In case lower_land has little free.
+ jb all_done_2
+all_done_1:
+ cmp ax,dx ; Did we find a bigger block?
+ ja gcsize
+all_done_2:
+ mov ax,dx
+gcsize:
+ inc ax ; Cheap bug fix
+ or ax,ax ; zero mem available?
+ jz gcfinal ; yes, return 0
+ dec ax ; Dont be too exact
+ jz gcfinal
+ dec ax
+ jz gcfinal
+ dec ax
+gcfinal:
+ and al,GA_MASK ; round down to nearest alignment
+ xor dx,dx
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; greserve ;
+; ;
+; Sets the size of the discardable code reserve area. ;
+; If the new size is larger than the old size, it checks to see ;
+; if there is enough room to support the new size. ;
+; ;
+; Arguments: ;
+; AX = new greserve size ;
+; ;
+; Returns: ;
+; CX = the largest greserve we can get ;
+; AX != 0 success ;
+; AX = 0 failure ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,DX,ES ;
+; ;
+; Calls: ;
+; genter ;
+; gcompact ;
+; will_gi_reserve_fit ;
+; gleave ;
+; ;
+; History: ;
+; ;
+; Sun 14-Jan-1990 13:42:59 -by- David N. Weise [davidw] ;
+; The greserve must be twice as big as the largest non-resident ;
+; segment, because restarting a NP fault requires both caller and ;
+; callee to be in memory. ;
+; ;
+; Tue May 19, 1987 00:03:08p -by- David N. Weise [davidw] ;
+; Made it far. ;
+; ;
+; Sat Sep 27, 1986 01:03:08p -by- David N. Weise [davidw] ;
+; Made it perform according to spec and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc greserve,<PUBLIC,FAR>,<si,di> ; FAR because of the gcompact below
+ localW new_size
+cBegin
+ call genter
+ add ax, ax ; Double required so caller & callee
+ add ax,GA_ALIGN ; both fit in memory
+ and al,GA_MASK
+ mov new_size,ax
+ mov si, ax
+
+ mov cx,[di].gi_reserve ; Get old size.
+ jcxz first_time ; Old size equal to zero?
+ call will_gi_reserve_fit
+ jnc new_okay
+
+ call GrowHeap
+ call will_gi_reserve_fit
+ jnc new_okay
+
+try_compacting:
+ mov dx,new_size
+ call gcompact ; Try compacting to get new reserve
+ call will_gi_reserve_fit
+ jnc new_okay
+
+will_not_fit:
+ xor ax,ax
+ jmps gr_exit
+
+first_time: ; Things are strange at first
+ mov bx, ax
+ xor cx, cx
+REPT 4
+ shl bx, 1
+ rcl cx, 1
+ENDM
+ cCall get_physical_address,<[di].hi_last>
+ sub ax, bx
+ sbb dx, cx ; Address of gi_reserve
+
+new_okay:
+ mov word ptr [di].gi_disfence_lo,ax
+ mov word ptr [di].gi_disfence_hi,dx
+ mov dx,new_size
+ mov [di].gi_reserve,dx
+gr_exit:
+ call gleave
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; will_gi_reserve_fit ;
+; ;
+; See if new size okay by scanning arena backwards. ;
+; ;
+; Arguments: ;
+; SI = new greserve size ;
+; DS:DI = master object ;
+; ;
+; Returns: ;
+; DX:AX = gi_disfence ;
+; BX = amount of NOT THERE memory, such as EGA ;
+; CX = the largest greserve we can get ;
+; CF = 0 new size ok ;
+; CF = 1 new size NOT ok ;
+; ES:DI => arena below CODE segments ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; SI,DI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Jul 12, 1987 08:13:23p -by- David N. Weise [davidw] ;
+; Added EMS support. ;
+; ;
+; Sat Sep 27, 1986 01:03:57p -by- David N. Weise [davidw] ;
+; Rewrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc will_gi_reserve_fit,<PUBLIC,NEAR>
+ localB got_half
+ localW second_block
+ localW largest_block
+ localW fence_block
+ localW fence_offset
+cBegin
+
+ xor ax,ax
+ xor bx,bx
+ mov got_half, al
+ mov fence_block, ax
+ mov largest_block, ax
+ mov second_block, ax
+
+ mov es,[di].hi_last
+ mov cx,[di].hi_count
+
+how_much_space_loop:
+ mov es,es:[di].ga_prev
+how_much_space_loop1:
+ cmp di,es:[di].ga_owner ; If free then include.
+ jz include_this_one
+ test es:[di].ga_flags,GA_DISCCODE ; If disccode then include.
+ jz end_block
+include_this_one:
+ add ax, es:[di].ga_size ; Total the size of this block
+ inc ax ; include arena header
+ loop how_much_space_loop
+
+end_block:
+ cmp ax, largest_block ; Track two largest blocks
+ jbe not_largest
+ push largest_block
+ mov largest_block, ax
+ pop second_block
+ jmps not_second
+not_largest:
+ cmp ax, second_block
+ jbe not_second
+ mov second_block, ax
+not_second:
+ cmp fence_block, di
+ jne skip_not_there
+ cmp si, ax ; This block big enough?
+ jbe set_fence
+ cmp got_half, 0
+ jne skip_not_there ; Already split requirement
+ shr si, 1
+ cmp si, ax ; Half fits?
+ ja no_good
+ mov got_half, 1 ; yes, will use this block
+ jmps skip_not_there
+set_fence:
+ sub ax, si
+ mov fence_offset, ax ; Offset from next arena
+ mov ax, es:[di].ga_next
+ mov fence_block, ax
+ jmps skip_not_there
+no_good:
+ shl si, 1 ; no, keep trying for full amount
+skip_not_there:
+ xor ax, ax ; zero count
+ cmp es:[di].ga_owner,GA_NOT_THERE
+ jne thats_all_folks
+skip_not_there_loop:
+ add bx,es:[di].ga_size
+ dec cx
+ mov es, es:[di].ga_prev
+ cmp es:[di].ga_owner, GA_NOT_THERE ; skip all not there blocks
+ je skip_not_there_loop
+ jmps how_much_space_loop1
+
+thats_all_folks:
+ mov cx, second_block ; Return max of twice second
+ shl cx, 1 ; largest block and the largest
+ jnc not_monstrously_huge ; block
+ mov cx, 0FFFDh
+ jmps time_to_go
+not_monstrously_huge:
+ cmp cx, largest_block
+ jae time_to_go
+ mov cx, largest_block
+time_to_go:
+ cmp got_half, 1
+ jne si_ok
+ shl si, 1
+si_ok:
+ cmp cx, si ; Set CARRY for failure
+ jc failed
+ push bx
+ push cx
+ cCall get_physical_address,<fence_block>
+ mov bx, fence_offset
+ xor cx, cx
+REPT 4
+ shl bx, 1
+ rcl cx, 1
+ENDM
+ add ax, bx
+ adc dx, cx ; DX:AX is new fence
+ pop cx
+ pop bx
+ clc ; Success
+failed:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; gnotify ;
+; ;
+; This is where the hard job of updating the stacks and thunks happens. ;
+; We only walk stacks and thunks for code and data (defined by being ;
+; LocalInit'ed), not for resources or task allocated segments. ;
+; ;
+; Arguments: ;
+; AL = message code ;
+; BX = handle ;
+; CX = optional argument ;
+; ES = address of arena header ;
+; ;
+; Returns: ;
+; AX = return value from notify proc or AL ;
+; DS = current DS (i.e. if DATA SEG was moved then DS is updated. ;
+; ZF = 1 if AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Jun 24, 1987 03:08:39a -by- David N. Weise [davidw] ;
+; Adding support for Global Notify. ;
+; ;
+; Wed Dec 03, 1986 01:59:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gnotify,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ push di
+ xor ah,ah
+ mov di,cx
+ mov cx,ax
+ mov si,bx
+ loop notify_discard
+ errnz <GN_MOVE - 1>
+
+;-----------------------------------------------------------------------;
+; Here for a segment that moved. ;
+;-----------------------------------------------------------------------;
+
+why_bother:
+
+ mov cx,ds
+ cmp cx,si ; Did we move DS?
+ jne notify_exit_0 ; No, continue
+notify_exit_0:
+ jmp notify_exit
+
+notify_discard:
+;;;;;; loop notify_exit
+ loop notify_exit_0
+ errnz <GN_DISCARD - 2>
+
+;-----------------------------------------------------------------------;
+; Here for a segment discarded. ;
+;-----------------------------------------------------------------------;
+
+ xor ax,ax
+ test bl,1
+ jnz notify_exit_0 ; SDK is wrong, can't free fixed.
+ push ax
+ cCall GetAccessWord,<bx>
+ test ah, DSC_DISCARDABLE
+ pop ax
+ jz notify_exit_0
+
+ test es:[ga_flags],GAH_NOTIFY
+ jnz @F
+ jmp dont_bother_asking
+@@:
+
+ push bx
+ push cx
+ push dx
+ mov ax,1
+ mov es,es:[ga_owner]
+ cmp es:[ne_magic],NEMAGIC
+ jz dont_ask ; doesn't belong to a particular task
+ mov ax,es
+ SetKernelDS es
+ push HeadTDB ; Look for TDB that owns this block.
+find_TDB:
+ pop cx
+ jcxz dont_ask
+ mov es,cx
+ UnSetKernelDS es
+ push es:[TDB_next]
+ cmp ax,es:[TDB_PDB]
+ jnz find_TDB
+ pop cx ; clear stack in 1 byte
+ mov cx,word ptr es:[TDB_GNotifyProc][0] ; paranoia
+ cmp cx,word ptr es:[TDB_GNotifyProc][2]
+ jz dont_ask
+ push ds
+ SetKernelDS
+
+;;; xor cx, cx ; Hack from hell for Legend
+;;; cmp ax, cur_dos_PDB ; Are we on task's PDB
+;;; je nothing_to_hack ; Yes, fine
+;;; mov cx, cur_dos_PDB ; No, save the PDB to restore
+;;; push ax
+;;; push bx
+;;; mov bx, ax
+;;; mov cur_dos_PDB, bx ; And point us to the task's
+;;; mov Win_PDB, bx
+;;; mov ah, 50h
+;;; call real_dos
+;;; pop bx
+;;; pop ax
+;;;nothing_to_hack:
+;;; push cx ; Save old PDB (if any)
+
+ push Win_PDB ; Save current PDB
+ mov Win_PDB, ax ; Ensure it is the task's
+
+ or Kernel_Flags[1],kf1_GLOBALNOTIFY
+
+ push es:[TDB_GNotifyProc]+2 ; push addr of func to call onto stack
+ push es:[TDB_GNotifyProc]
+
+ push bx ; push arg for notify proc
+
+ mov ax,ss ; Zap segment regs so DS
+ mov ds,ax ; doesn't get diddled by callee
+ mov es,ax
+
+ mov bx,sp
+ call dword ptr ss:[bx]+2
+ add sp,4 ; clean up stack.
+
+ SetKernelDS
+ and Kernel_Flags[1],not kf1_GLOBALNOTIFY
+
+ pop Win_PDB ; Restore PDB
+
+;;; pop bx ; Saved PDB
+;;; or bx, bx ; Was there one?
+;;; jz @F ; Nope.
+;;; push ax
+;;; mov ah, 50h ; Set it back...
+;;; mov cur_dos_PDB, bx
+;;; mov Win_PDB, bx
+;;; call real_dos
+;;; pop ax
+;;;@@:
+
+ pop ds
+ UnSetKernelDS
+
+dont_ask:
+ pop dx
+ pop cx
+ pop bx
+ or ax,ax ; Well, can we?
+ jz notify_exit
+dont_bother_asking:
+
+ cCall get_arena_pointer,<si>
+ mov es,ax
+ mov es,es:[ga_owner]
+ cmp es:[ne_magic],NEMAGIC
+ jnz not_in_exe
+ mov di,es:[ne_segtab]
+ mov cx,es:[ne_cseg]
+ jcxz not_in_exe
+; test es:[ne_flags],NENOTP
+; jnz pt0a
+; inc bx
+pt0a:
+ cmp bx,es:[di].ns_handle
+ jz pt0b
+ add di,SIZE NEW_SEG1
+ loop pt0a
+ jmps not_in_exe
+pt0b:
+ and byte ptr es:[di].ns_flags,not NSLOADED ; Mark as not loaded.
+not_in_exe:
+
+why_bother_again:
+ xor di,di
+if SDEBUG
+ cCall DebugMovedSegment,<si,di>
+endif
+if LDCHKSUM
+ call ZeroSegmentChksum ; SI points to segment
+endif
+ mov ax,1
+notify_exit:
+ or ax,ax
+ pop di
+ pop si
+ ret
+
+gn_error:
+ kerror 0FFh,<gnotify - cant discard segment>,si,si
+ xor ax,ax
+ jmp notify_exit
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; MemoryFreed ;
+; ;
+; This call is apps that have a GlobalNotify procedure. Some apps ;
+; may shrink the segment instead of allowing it to be discarded, or ;
+; they may free other blocks. This call tells the memory manager ;
+; that some memory was freed somewhere. ;
+; ;
+; Arguments: ;
+; WORD = # paragraphs freed ;
+; ;
+; Returns: ;
+; DX:AX = amount of memory that still needs freeing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri 08-Apr-1988 10:25:55 -by- David N. Weise [davidw] ;
+; Wrote it! ;
+;-----------------------------------------------------------------------;
+
+cProc MemoryFreed,<PUBLIC,FAR>
+
+ parmW memory_freed
+cBegin
+ xor ax,ax
+ SetKernelDS
+ test Kernel_Flags[1],kf1_GLOBALNOTIFY
+ jz mf_done
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov ax,memory_freed
+ or ax,ax
+ jz mf_inquire
+ or ds:[hi_ncompact],1 ; Remember we discarded something
+ sub ds:[hi_distotal],ax ; Have we discarded enough yet?
+ ja mf_inquire
+ or ds:[hi_ncompact],10h ; To tell gdiscard that we're done.
+mf_inquire:
+ mov ax,ds:[hi_distotal] ; Have we discarded enough yet?
+mf_done:
+ xor dx,dx
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSwapAreaSize ;
+; ;
+; Sets the current task's code swap area size. ;
+; ;
+; Arguments: ;
+; WORD == 0 then current size is just returned ;
+; != 0 number paragraphs wanted for swap area ;
+; Returns: ;
+; AX = Size actually set ;
+; DX = Max size you can get ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Apr 18, 1988 08:00:00a -by- T.H. SpeedWagon [-????-] ;
+; Move routine into CODE segment, so applications can query the ;
+; code working set value without paging in the NRESCODE segment. ;
+; ;
+; Thu Apr 23, 1987 09:36:00p -by- R.E.O. SpeedWagon [-???-] ;
+; Added ability to get size without setting it. ;
+; ;
+; Wed Dec 03, 1986 10:52:16p -by- David N. Weise [davidw] ;
+; Rewrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc SetSwapAreaSize,<PUBLIC,FAR>
+ parmW nParas
+ localW MxCodeSwapArea
+cBegin
+ SetKernelDS
+ mov ax,nParas
+ xor bx,bx
+ mov cx,MaxCodeSwapArea
+ mov MxCodeSwapArea,cx ; avoid a segment load later
+ cmp ax,cx
+ jbe requested_size_OK
+ mov ax,cx
+requested_size_OK:
+ mov ds,CurTDB
+ UnSetKernelDS
+ mov ds,ds:[bx].TDB_pModule ; Get exe header address
+ or ax,ax ; just a query request?
+ jz got_it ; yes
+ cmp ax,ds:[bx].ne_swaparea
+ jz got_it ; just want what we have?
+ ja calc_it
+
+; To restart a NP fault both caller and callee must be in memory.
+; So we cheat here, and set the minimum to be twice the rmode number.
+; We have to prevent the app from setting the swap area too
+; small. So we recalculate the minimum needed. We should
+; do this is rmode as well, but the chance of screw up is
+; much larger in pmode, where new app writers are apt to
+; be very cavalier with lots of memory.
+; We should keep another NE variable instead of always
+; recalculating the largest ne_seg BUT at this late
+; date this is simpler!
+
+ push ax
+ xor ax,ax ; No max yet.
+ mov cx,ds:[bx].ne_cseg
+ mov bx,ds:[bx].ne_segtab
+ jcxz no_NR_segments
+get_largest_loop:
+ test ds:[bx].ns_flags,NSDATA ; Code segment?
+ jnz not_disc_code
+ .errnz NSCODE
+ test ds:[bx].ns_flags,NSDISCARD ; Discardable?
+ jz not_disc_code ; No, ignore.
+ mov dx,ds:[bx].ns_minalloc ; Yes, get size
+ add dx,0Fh ; in paragraphs
+ shr dx,4
+ cmp ax,dx ; Biggest NR Seg?
+ jae not_disc_code
+ mov ax,dx
+not_disc_code:
+ add bx,SIZE NEW_SEG1
+ loop get_largest_loop
+no_NR_segments:
+ shl ax,1
+ mov cx,ax
+ pop ax
+ cmp ax,cx
+ ja calc_it
+ mov ax,cx
+
+calc_it:
+ xchg ds:[ne_swaparea],ax
+ push ax
+ call CalcMaxNRSeg
+ pop dx
+ or ax,ax
+ jnz got_it
+ mov ds:[ne_swaparea],dx
+got_it:
+ mov ax,ds:[ne_swaparea]
+ mov dx,MxCodeSwapArea
+ cmp cx,dx
+ ja cant_get_that_much
+ mov dx,cx
+cant_get_that_much:
+cEnd
+
+;
+; SetReserve - Sets gi_reserve to the given number of paragraphs
+;
+; Registers Destroyed:
+; AX, BX, DX
+;
+
+cProc SetReserve,<PUBLIC,FAR>,<di>
+ parmW paras
+cBegin
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ xor di,di
+ mov bx, paras
+ mov ds:[di].gi_reserve, bx
+ shl bx, 4
+ cCall get_physical_address,<ds:[di].hi_last>
+ sub ax, bx
+ sbb dx, di
+ mov ds:[di].gi_disfence_lo, ax
+ mov ds:[di].gi_disfence_hi, dx
+cEnd
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/2protect.asm b/private/mvdm/wow16/kernel31/2protect.asm
new file mode 100644
index 000000000..315a668b1
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2protect.asm
@@ -0,0 +1,4141 @@
+ PAGE ,132
+ TITLE Windows Protect Mode Routines
+
+.list
+include kernel.inc
+include protect.inc
+include pdb.inc
+include newexe.inc
+.list
+
+ .286p
+
+ifdef WOW
+
+;
+; the dpmi func 04f1h is idential to function 00h, except that
+; the descriptor base and limit are not initialized to zero.
+;
+
+;
+; the dpmi func 04f2h is identical to 0ch except that it
+; sets 'count' (in cx) LDTs at one time. The first selector is in
+; register bx. The descriptor data is in gdtdsc[bx], gdtdsc[bx+8]
+; etc. This data is shared between dpmi (dosx.exe) and us and thus
+; need not be passed in es:di
+
+WOW_DPMIFUNC_00 equ 04f1h
+WOW_DPMIFUNC_0C equ 04f2h
+endif
+
+MovsDsc Macro ;Move (copy) a descriptor (4 words)
+ cld
+ rept 4
+ movsw
+ endm
+ endm
+
+CheckDS Macro
+ local okDS
+ push ax
+ mov ax, ds
+ cmp ax, pGlobalHeap
+ je okDS
+ int 3
+okDS:
+ pop ax
+ endm
+
+CheckLDT Macro selector
+if KDEBUG
+ test selector,SEL_LDT
+ jnz @F
+ int 3
+@@:
+endif
+ Endm
+
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+
+CHECKSEL MACRO selector
+ ENDM
+
+extrn GlobalHandle:FAR
+extrn GlobalRealloc:FAR
+extrn GlobalFix:FAR
+extrn GlobalUnFix:FAR
+extrn IGlobalFix:FAR ;Far calls in this segment
+extrn IGlobalFlags:FAR
+IF KDEBUG
+extrn GlobalHandleNorip:FAR
+ELSE
+extrn IGlobalHandle:FAR
+ENDIF
+
+DataBegin
+
+ifdef WOW
+externW SelectorFreeBlock
+externW UserSelArray
+endif
+
+externW WinFlags
+
+extrn kr1dsc:WORD
+extrn kr2dsc:WORD
+extrn blotdsc:WORD
+extrn DemandLoadSel:WORD
+extrn temp_sel:WORD
+
+externW MyCSSeg
+externW selWoaPdb
+externW cpLowHeap
+externW selLowHeap
+externW pGlobalHeap
+externW SelTableLen
+
+externW MyCSAlias
+
+extrn SelTableStart:DWORD
+extrn sel_alias_array:WORD
+
+if ROM
+externW selROMTOC
+externW selROMLDT
+externW sel1stAvail
+endif
+
+if ROM
+externD lmaHiROM
+externD cbHiROM
+endif
+
+globalD lpProc,0
+
+DataEnd
+
+
+DataBegin INIT
+
+RModeCallStructure STRUC
+RMCS_DI dw 0
+ dw 0
+RMCS_ESI dd 0
+RMCS_EBP dd 0
+RMCS_Res dd 0
+RMCS_EBX dd 0
+RMCS_EDX dd 0
+RMCS_ECX dd 0
+RMCS_EAX dd 0
+RMCS_Flags dw 0
+RMCS_ES dw 0
+RMCS_DS dw 0
+RMCS_FS dw 0
+RMCS_GS dw 0
+RMCS_IP dw 0
+RMCS_CS dw 0
+RMCS_SP dw 0
+RMCS_SS dw 0
+RModeCallStructure ENDS
+
+MyCallStruc RModeCallStructure <>
+
+public MS_DOS_Name_String
+MS_DOS_Name_String db "MS-DOS", 0
+
+DataEnd INIT
+
+sBegin CODE
+
+externW MyCSDS
+externW gdtdsc
+ifdef WOW
+externD prevInt31proc
+endif
+
+sEnd CODE
+
+sBegin INITCODE
+assumes cs,CODE
+
+;-----------------------------------------------------------------------;
+; SwitchToPMODE ;
+; ;
+; Entry: ;
+; In Real or Virtual Mode ;
+; DS -> Data Segment ;
+; ES -> PSP ;
+; ;
+; Returns: ;
+; In Protect Mode ;
+; BX -> LDT selector ;
+; SI -> Segment of start of available memory ;
+; ES -> PSP ;
+; ;
+; Error Returns: ;
+; Exits via DOS call 4Ch ;
+; ;
+; Registers Preserved: ;
+; ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,DATA
+ assumes es,nothing
+
+ife ROM
+
+cProc SwitchToPMODE,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ push es ; Current PSP
+
+ mov ax, 1687h
+ int 2Fh ; Get PMODE switch entry
+ or ax, ax ; Can we do it?
+ jz @F
+NoPMODEj:
+ jmp NoPMODE
+@@:
+ xor bh, bh ; Set CPU type now
+ mov bl,WF_CPU286
+ cmp cl, 2 ; At least a 286?
+ jb NoPMODEj ; No, Fail
+ je @F ; It is a 286?
+ mov bl,WF_CPU386
+ cmp cl,3 ; No, 386?
+ je @F
+ mov bl,WF_CPU486 ; No, assume 486 for now
+@@:
+ mov WinFlags, bx ; Save away CPU type
+ mov word ptr [lpProc][0], di
+ mov word ptr [lpProc][2], es
+ pop ax ; PSP
+ add ax, 10h ; Skip the PSP
+ mov es, ax ; Give this to the DOS extender
+ add si, ax ; Start of memory available to us
+ mov selWoaPdb, si ; PDB for WOA
+ add si, 10h ; Move start on another 256 bytes
+
+ xor ax, ax ; 16-bit app
+ call [lpProc] ; Switch to PROTECTED mode
+ jc short NoPMODEj ; No, still Real/Virtual mode
+
+ mov ax, cs
+ and al, 7 ; LDT, Ring 3
+ cmp al, 7
+ je @F
+ jmp BadDPMI ; Insist on Ring 3!
+@@:
+
+ mov bx, cs ; Allocate CS Alias
+ DPMICALL 000Ah
+
+ mov MyCSAlias, ax ; Save CS Alias in DS
+
+ mov bx, ds ; Use alias to update code seg var
+ mov ds, ax
+ assumes ds, CODE
+
+ mov MyCSDS, bx ; The DS selector
+
+ mov ds, bx
+ ReSetKernelDS
+
+ push si ; Unlock all of our memory
+ mov bx, si ; Segment address of start of our memory
+ mov di, es:[PDB_block_len] ; End of our memory
+ sub di, bx ; Size of our block in paragraphs
+ mov cpLowHeap, di ; (MAY NEED INCREMENTING!!!)
+ xor si, si ; Calculate # bytes in SI:DI
+ REPT 4
+ shl di, 1
+ rcl si, 1
+ ENDM
+ mov cx, bx ; Convert start of block to linear
+ xor bx, bx ; address
+ REPT 4
+ shl cx, 1
+ rcl bx, 1
+ ENDM
+ mov ax, 0602h
+ ;BUGBUGBUGBUG
+ int 31h ; Mark region as pageable.
+
+ pop bx
+ DPMICALL 0002h ; Convert start of memory to selector
+ mov si, ax
+ mov selLowHeap, ax ; Save for WOA (MAY NEED PARA LESS!!!)
+
+ mov bx, selWoaPdb ; Convert WOA PDB segment to selector
+ DPMICALL 0002h
+ mov selWoaPdb, ax
+
+ push si
+ push es
+ mov ax, 168Ah ; See if we have MS-DOS extensions
+ mov si, dataOffset MS_DOS_Name_String
+ int 2Fh
+ cmp al, 8Ah
+ je short BadDPMI ; No extensions, screwed
+
+ mov word ptr [lpProc][0], di ; Save CallBack address
+ mov word ptr [lpProc][2], es
+
+ mov ax, 0100h ; Get base of LDT
+ call [lpProc]
+ jc short NoLDTParty
+ifndef WOW
+ verw ax ; Writeable?
+else
+ verr ax ; for WOW we can use read access
+endif
+ jnz short NoLDTParty ; nope, don't bother with it
+
+ mov es, MyCSAlias
+ assumes es,CODE
+ mov gdtdsc, ax
+ assumes es,nothing
+
+NoLDTParty: ; Well, we'll just have to use DPMI!
+ pop es
+ pop si
+ xor bx, bx
+ pop cx
+ ret
+
+BadDPMI:
+ ;
+ ; Call real/virtual mode to whine
+ ;
+ xor cx, cx ; Nothing on stack to copy
+ xor bh, bh ; Flags to DPMI
+ mov ax, MyCSSeg
+ mov MyCallStruc.RMCS_DS, ax ; Real mode DS will be parent PDB
+ mov MyCallStruc.RMCS_ES, cx ; Real mode ES will be 0
+ mov MyCallStruc.RMCS_CS, ax ; Real mode CS
+ mov MyCallStruc.RMCS_IP, codeoffset RModeCode ; Real mode IP
+
+ smov es, ds
+ mov di, dataoffset MyCallStruc ; ES:DI points to call structure
+ mov ax, 0301h ; Call Real Mode Procedure
+ int 31h
+ jmps GoodBye
+
+RModeCode:
+ mov dx, codeoffset szInadequate
+ mov ah, 9
+ int 21h
+ retf
+
+;szInadequate:
+; DB 'KRNL286: Inadequate DPMI Server',13,10,'$'
+externB <szNoPMode, szInadequate>
+
+NoPMODE: ; NOTE: stack trashed...
+ifdef WOW
+ ;** Put Up a Dialog Box If we fail to Enter Protect Mode
+ ;** Prepare the dialog box
+ push cs ;In our DS
+ push codeOFFSET szNoPMode ; -> unable to enter Prot Mode
+
+ push ds
+externB <syserr>
+ push dataOffset syserr ;Caption
+
+ push 0 ;No left button
+
+ push SEB_CLOSE + SEB_DEFBUTTON ;Button 1 style
+
+ push 0 ;No right button
+externFP kSYSERRORBOX
+ call kSYSERRORBOX ;Put up the system error message
+externNP ExitKernel
+ jmp ExitKernel
+
+else ; Not WOW
+
+ mov dx, codeoffset szNoPMode
+; call complain
+; DB 'KRNL286: Unable to enter Protected Mode',7,7,7,13,10,'$'
+;complain:
+; pop dx
+ push cs
+ pop ds ; DS:DX -> error message
+ mov ah,9 ; Print error message
+ int 21h
+
+endif ; WOW
+
+
+GoodBye:
+ mov ax, 4CFFh
+ int 21h
+cEnd nogen
+
+endif ;ROM
+
+;-----------------------------------------------------------------------;
+; LDT_Init ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc LDT_Init,<PUBLIC,NEAR>,<ax,bx,cx,di,es>
+cBegin
+
+ ReSetKernelDS
+ mov es, bx ; Selector for LDT if any
+
+ push es ; Get random selectors
+ smov es, ds
+ ReSetKernelDS es
+ assumes ds,nothing
+ mov cx, 1 ; Argument to get_sel
+ call get_sel
+ mov kr1dsc, si
+ call get_sel
+ mov blotdsc, si
+ call get_sel
+ or si, SEG_RING
+ mov DemandLoadSel, si
+
+ mov ax, DSC_DATA+DSC_PRESENT; Get an array of 16 selectors
+ cCall alloc_sel,<0000h,0BADh,0FFFFh> ; This covers 1Mb.
+ mov kr2dsc, ax
+ smov ds, es
+ pop es
+ assumes es,nothing
+cEnd
+
+sEnd INITCODE
+
+sBegin CODE
+assumes cs,CODE
+
+;-----------------------------------------------------------------------;
+; AllocSelector
+;
+;
+; Entry:
+;
+; Returns:
+; AX = New selector
+; = 0 if out of selectors
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc AllocSelectorWOW,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ ; same as allocselector but doesn't set the descriptor
+ cCall inner_alloc_selector,<selector,0ffffh>
+cEnd
+
+cProc AllocSelector,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall inner_alloc_selector,<selector,0>
+cEnd
+
+
+labelFP <PUBLIC, IAllocCStoDSAlias>
+
+;-----------------------------------------------------------------------;
+; AllocAlias
+;
+; This allocates a data alias for the passed in selector, which
+; can be either code or data. The alias will track segment
+; motion.
+;
+; Entry:
+; parmW selector selector to get an alias for
+;
+; Returns:
+; AX = selector
+; = 0 failure
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw]
+; Cleaning up.
+;
+; Fri 02-Dec-1988 11:04:58 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc AllocAlias,<FAR,PUBLIC>
+
+ parmW selector
+cBegin
+ifdef WOW
+ push bx ; Whitewater tool ObjDraw needs this too
+endif
+ cCall inner_alloc_selector,<selector,1>
+ ; WhiteWater Resource Toolkit (shipped with Borland's Turbo
+ ; Pascal) depends on dx being the data selector which was true
+ ; in 3.0 but in 3.1 validation layer destroys it.
+ mov dx,selector
+ifdef WOW
+ pop bx
+endif
+cEnd
+
+;-----------------------------------------------------------------------;
+; AllocDStoCSAlias
+;
+; This allocates a code alias for the passed in selector, which
+; should be data. The alias will track segment motion. The
+; passed in selector must be less than 64K.
+;
+; Entry:
+; parmW selector selector to get an alias for
+;
+; Returns:
+; AX = selector
+; = 0 failure
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw]
+; Cleaning up.
+;
+; Fri 02-Dec-1988 11:04:58 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IAllocDStoCSAlias,<FAR,PUBLIC>, <cx,si,di>
+ parmW data_selector
+cBegin
+ ;** AllocDStoCSAlias has an interesting hack. A fix was made to
+ ;** not allow apps to GlobalAlloc fixed memory. This was done
+ ;** for performance reasons. The only reason we can ascertain
+ ;** for an app needing fixed GlobalAlloc'ed memory is in the case
+ ;** of alias selectors. We assume that all apps needing alias
+ ;** selectors will use this function to make the alias. So, if
+ ;** we see a DStoCS alias being made, we make sure the DS is fixed.
+ mov ax, data_selector ;Get handle
+ push ax
+IF KDEBUG
+ call GlobalHandleNorip ;Make sure it's really a handle
+ELSE
+ call IGlobalHandle ;Make sure it's really a handle
+ENDIF
+ test ax, 1 ;Fixed blocks have low bit set
+ jnz ADCA_Already_Fixed ;It's already a fixed block!
+
+ ;** If the block is not fixed, it may be locked so we must check this.
+ push ax ;Save returned selector
+ push ax ;Use as parameter
+ call IGlobalFlags ;Returns lock count if any
+ or al, al ;Non-zero lock count?
+ pop ax ;Get selector back
+ jnz ADCA_Already_Fixed ;Yes, don't mess with it
+
+ ;** Fix the memory. Note that we're only doing this for bonehead
+ ;** apps that are calling this on non-fixed or -locked memory.
+ ;** This will cause them to rip on the GlobalFree call to this
+ ;** memory, but at least it won't move on them!
+ push ax ;Fix it
+ call IGlobalFix
+ADCA_Already_Fixed:
+
+ cCall inner_alloc_selector,<data_selector,2>
+if ALIASES
+ or ax,ax
+ jz ada_nope
+ mov bx,data_selector
+ call add_alias
+ada_nope:
+endif
+ smov es,0
+
+ ; WhiteWater Resource Toolkit (shipped with Borland's Turbo
+ ; Pascal) depends on dx being the data selector which was
+ ; true in 3.0 but in 3.1 validation layer destroys it.
+ mov dx,data_selector
+cEnd
+
+;-----------------------------------------------------------------------;
+; inner_alloc_selector
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc inner_alloc_selector,<PUBLIC,NEAR>,<di,si>
+
+ parmW selector
+ parmW sel_type
+ localV DscBuf,DSC_LEN
+cBegin
+ mov cx, 1
+ mov di, selector
+ and di, not SEG_RING_MASK
+ jnz as1
+
+ call get_sel
+ jnz short as_exit ; We got it
+ jmps as_exit1
+
+as1:
+ mov bx, selector
+ lea di, DscBuf
+ smov es, ss
+
+ifdef WOW
+ DPMICALL 000Bh ; Get existing descriptor
+else
+ push ds
+ mov ds, gdtdsc
+ push si ; Get Descriptor
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif
+ mov cl, DscBuf.dsc_hlimit
+ and cl, 0Fh
+ inc cl ; # selectors
+
+ call get_sel
+ jz short as_exit1
+ifdef WOW
+ cmp sel_type, 0ffffh ; called from AllocSelectorWOW ?
+ jz as_exit ; yes . dont set descriptor
+endif
+ cmp sel_type,0 ; called from AllocSelector?
+ jz as_fill ; done if so
+ mov al,DSC_PRESENT+DSC_DATA
+ cmp sel_type,1 ; called from AllocAlias?
+ jz @F
+ or al,DSC_CODE_BIT ; called from AllocDStoCSAlias
+@@:
+ mov DscBuf.dsc_access,al
+as_fill:
+ mov bx, si
+ or bl, SEG_RING
+
+ call fill_in_selector_array
+
+as_exit:
+ or si, SEG_RING
+as_exit1:
+ mov ax,si
+ smov es, 0
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_sel ;
+; ;
+; Entry: ;
+; CX = # of selectors required ;
+; ;
+; Returns: ;
+; SI = First Selector ;
+; DS = LDT ;
+; ZF = 0 ;
+; ;
+; Error Returns: ;
+; SI = 0 ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc AllocSelectorArray,<PUBLIC,FAR>,<si>
+ parmW nSels
+cBegin
+ mov cx, nSels
+ call get_sel
+ mov ax, si
+ jz asa_fail
+
+ or si, SEG_RING
+ mov bx, si
+ mov dx, cx
+ mov cx, DSC_DATA+DSC_PRESENT ; Mark all as Data and Present
+ifdef WOW
+fill_in_access:
+ DPMICALL 0009h
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jnz fill_in_access
+else
+ push ds
+ mov ds, gdtdsc
+ push bx
+ and bl, not 7
+fill_in_access:
+ mov word ptr ds:[bx].dsc_access, cx
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jnz fill_in_access
+ pop bx
+ pop ds
+endif; WOW
+ mov ax, si
+
+asa_fail:
+cEnd
+
+
+cProc get_sel,<PUBLIC,NEAR>
+cBegin nogen
+ call SetKernelDSProc ; Must call procedure here
+ ReSetKernelDS
+ push ax
+ push cx
+ xor ax, ax
+ cmp cx, 1 ; One selector only?
+ jne gs_int31
+ cmp temp_sel, ax ; Have one waiting?
+ je gs_int31 ; no, get one
+ xchg temp_sel, ax ; Use the waiting selector
+ jmps gs_got_sel
+gs_int31:
+ DPMICALL 0000h
+ CHECKSEL ax
+
+gs_got_sel:
+ mov si, ax
+ and si, not SEG_RING_MASK
+
+if KDEBUG
+ jnz got_sel
+ push es
+ pusha
+ kerror 0,<Out of selectors>
+ popa
+ pop es
+ jmps gs_exit
+got_sel:
+endif
+
+ mov ax, si
+ shr ax, 2
+ cmp ax, SelTableLen ; Make sure we can associate it
+ jae gs_free_sels
+
+gs_exit:
+ mov ds, gdtdsc ; SIDE EFFECT...
+ UnSetKernelDS
+gs_exit_2:
+ pop cx
+ pop ax
+ or si, si
+ ret
+
+gs_free_sels:
+ ReSetKernelDS
+ cmp SelTableLen, 0
+ je gs_exit ; Not set yet, so we are ok
+
+ mov ds, gdtdsc
+ UnSetKernelDS
+ push bx
+ mov bx, si ; Could not associate, so free them
+ xor si, si
+ or bl, SEG_RING
+as_free:
+ DPMICALL 0001h
+ lea bx, [bx+DSC_LEN]
+ loop as_free
+ pop bx
+ jmps gs_exit_2
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; FreeSelector ;
+; free_sel ;
+; FreeSelArray
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IFreeSelector,<FAR,PUBLIC>,<di,si>
+ parmW selector
+cBegin
+ CheckLDT selector
+if ALIASES
+ mov ax,selector
+ call delete_alias
+endif
+ xor ax, ax
+ mov es, ax ; GRRRRRRRR!
+ cCall FreeSelArray,<selector>
+cEnd
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc free_sel,<PUBLIC,NEAR>,<ax,bx>
+ parmW selector
+cBegin
+ pushf ; !! for the nonce
+ mov bx,selector ; must be careful in gcompact
+ ; to ignore error return
+if KDEBUG
+ or bx, SEG_RING ; Ensure Table bit correct
+endif
+
+ DPMICALL 0001h
+ popf
+cEnd
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FreeSelArray,<PUBLIC,NEAR>,<ax,bx,cx>
+ parmW selector
+cBegin
+ mov bx,selector ; to ignore error return
+
+ cCall GetSelectorCount
+ mov cx, ax
+
+fsa_loop:
+ DPMICALL 0001h
+ lea bx, [bx+DSC_LEN]
+ loop fsa_loop ; Any left to free
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GrowSelArray ;
+; ;
+; This is called from within grealloc. The point is to grow the ;
+; number of contiguous selectors to tile the memory object. ;
+; If we can't get a contiguous set then we attempt to find a set ;
+; anywhere. ;
+; ;
+; Entry: ;
+; ES => arena header ;
+; ;
+; Returns: ;
+; AX => new selector array ;
+; CX => new number of selectors ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; BX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GrowSelArray,<PUBLIC,NEAR>,<bx,si,di,ds>
+ localV DscBuf,DSC_LEN
+ localW oldCount
+cBegin
+ mov bx, es:[ga_handle]
+ mov di, bx
+
+ cCall GetSelectorCount
+ mov word ptr oldCount, ax
+
+ mov cx, si ; New size
+ dec cx ; Paragraph limit
+ shr cx, 12
+ inc cx ; new # selectors
+ cmp al, cl ; Same # of selectors required?
+ je gsa_done ; yes, just return!
+
+ call get_sel ; get a new selector array
+ jz short gsa_nosels
+ xchg si, di ; DI now new array, SI old array
+
+ push es
+ push cx
+ and bx, SEG_RING_MASK ; Ring bits
+ or bx, di ; New handle
+ mov cx, word ptr oldCount
+ push ds ; Copy Descriptor(s)
+ push si
+ mov es, gdtdsc
+ mov ds, gdtdsc
+ and si, not 7
+
+ shl cx, 2 ; CX = 4 * Descriptors = words to copy
+ rep movsw
+
+ pop si
+ pop ds
+ifdef WOW
+ ; set the descriptors
+ push bx
+ mov cx, word ptr oldCount
+ or bx, SEG_RING_MASK ; start selector
+ DPMICALL WOW_DPMIFUNC_0C
+ pop bx
+endif; WOW
+ pop cx
+ pop es
+
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<si,0>
+ mov es:[ga_handle], bx
+ cCall AssociateSelector,<bx,es>
+ jmps gsa_done
+
+gsa_nosels:
+ xor bx, bx ; Indicate failure
+gsa_done:
+ mov ax, bx
+ or ax, ax ; Indicate success
+gsa_ret:
+cEnd
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc PreallocSel,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ push cx
+ push si
+ mov cx, 1
+ call get_sel
+ call SetKernelDSProc
+ ReSetKernelDS
+ mov temp_sel, si
+ or si, si ; Set flags for caller
+ pop si
+ pop cx
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; alloc_sel ;
+; alloc_data_sel
+; ;
+; Entry: ;
+; parmD Address 32 bit address ;
+; parmW Limit limit in paragraphs (limit of 1 meg) ;
+; AX = flags alloc_sel only ;
+; ;
+; Returns: ;
+; AX = new selector ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu 07-Apr-1988 21:33:27 -by- David N. Weise [davidw] ;
+; Added the GlobalNotify check. ;
+; ;
+; Sun Feb 01, 1987 07:48:39p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+ assumes ds, nothing
+ assumes es, nothing
+
+if ROM
+public far_alloc_data_sel16
+far_alloc_data_sel16 equ this far
+endif
+
+cProc far_alloc_data_sel,<PUBLIC,FAR>
+ parmD Address
+ parmW Limit
+cBegin
+ cCall alloc_data_sel,<Address,Limit>
+cEnd
+
+if ROM
+public alloc_data_sel16
+alloc_data_sel16 equ this near
+endif
+
+cProc alloc_data_sel,<PUBLIC,NEAR>
+; parmD Address
+; parmW Limit
+cBegin nogen
+ mov ax, DSC_DATA+DSC_PRESENT
+ errn$ alloc_sel
+cEnd nogen
+
+
+cProc alloc_sel,<PUBLIC,NEAR>,<bx,cx,dx,si,di,ds,es>
+ parmD Address
+ parmW Limit
+ localV DscBuf,DSC_LEN
+cBegin
+ mov cx, 1
+ test al, DSC_PRESENT
+ jz as_oneonly
+
+ mov cx, Limit ; Calculate how many selectors required
+ add cx, 0FFFh
+ rcr cx, 1 ; 17 bitdom
+ shr cx, 11
+
+as_oneonly:
+ call get_sel
+ jz short a_s_exit
+
+ mov bx, si ; Selector in bx for DPMI
+ or bl, SEL_LDT
+ lea di, DscBuf
+ smov es, ss ; es:di points to descriptor buffer
+ push ax ; Save access word
+
+ mov ax, Address.lo ; Set descriptor base
+ mov DscBuf.dsc_lbase, ax
+ mov ax, Address.hi
+ mov DscBuf.dsc_mbase, al
+ mov DscBuf.dsc_hbase, ah
+
+ pop ax ; Access word
+ test al, DSC_PRESENT ; If selector not present, limit is
+ jnz short set_everything ; as passed, not a paragraph count
+
+ mov word ptr DscBuf.dsc_access, ax
+ mov ax, word ptr Limit
+ mov DscBuf.dsc_limit, ax
+ifdef WOW
+ DPMICALL 000Ch ; Fill in our stuff in the descriptor
+else
+ push ds
+ push bx ; Set Descriptor
+ mov ds, gdtdsc
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif; WOW
+ jmps as_done
+
+set_everything:
+ dec cl
+ and ah, not 0Fh ; Zero limit 19:16
+ or ah, cl ; Fill in limit 19:16
+ inc cl
+ mov word ptr DscBuf.dsc_access, ax
+ mov ax, Limit
+ shl ax, 4 ; Convert paragraphs to byte limit
+ dec ax
+ mov DscBuf.dsc_limit, ax
+
+ call fill_in_selector_array
+
+as_done:
+ or si, SEG_RING
+a_s_exit:
+ mov ax, si
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; fill_in_selector_array ;
+; ;
+; Entry: ;
+; AX = size of object in paragraphs ;
+; DH = Discard bit for descriptors ;
+; DL = Access bits ;
+; CX:BX = 32 bit base address of object ;
+; SI = index into LDT ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; SI, DI, DS, ES ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc fill_in_selector_array,<PUBLIC,NEAR>
+cBegin nogen
+ CheckLDT bl
+
+ push ds
+ push es:[di].dsc_limit ; Save limit for last selector
+ SetKernelDS
+ test WinFlags, WF_CPU286 ; protect mode on a 286?
+ jz next_sel
+ mov es:[di].dsc_limit, 0FFFFh ; Others get 64k limit on 286
+
+next_sel:
+ cmp cx, 1 ; Last selector?
+ jne fsa_not_last
+ pop es:[di].dsc_limit ; yes, get its limit
+fsa_not_last:
+ DPMICALL 000Ch ; Set this descriptor
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ add es:[di].dsc_mbase, 1 ; Add 64kb to address
+ adc es:[di].dsc_hbase, 0
+ dec es:[di].dsc_hlimit ; subtract 64kb from limit
+ loop next_sel
+
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetSelectorBase
+; get_physical_address
+;
+;
+; Entry:
+;
+; Returns:
+; DX:AX 32 bit physical address
+; Registers Destroyed:
+; none
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetSelectorBase,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall get_physical_address,<selector>
+cEnd
+
+cProc get_physical_address,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ push bx
+ push cx
+ mov bx, selector
+ CheckLDT bl
+ifdef WOWJUNK
+ DPMICALL 0006h
+ mov ax, dx
+ mov dx, cx
+else
+ push ds ; Get Segment Base Address
+ mov ds, gdtdsc
+ and bl, not 7
+ mov ax, ds:[bx].dsc_lbase
+ mov dl, ds:[bx].dsc_mbase
+ mov dh, ds:[bx].dsc_hbase
+ pop ds
+endif; WOW
+ pop cx
+ pop bx
+cEnd
+
+;-----------------------------------------------------------------------;
+; set_physical_address
+;
+;
+; Entry:
+; DX:AX 32 bit physical address
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_physical_address,<PUBLIC,NEAR>,<ax,bx,cx,dx>
+ parmW selector
+cBegin
+ CheckLDT selector
+
+ push di
+
+ push ax ; save low bits of address
+ mov bx, selector
+ call GetSelectorCount
+ mov di, ax
+ mov cx, dx ; CX:DX has new address
+ pop dx
+
+set_bases:
+ DPMICALL 0007h ; Set selector base
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ inc cx ; Add 64k to base
+ dec di
+ jnz set_bases
+
+ pop di
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_selector_length16
+;
+;
+; Entry:
+;
+; Returns:
+; AX 16 bit segment length
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_selector_length16,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ mov ax, -1
+ lsl ax, selector
+ inc ax ; length is one bigger!
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_sel_limit
+; SIDE EFFECT: descriptor bases and access are set based
+; on the first in the array
+;
+; Entry:
+; CX:BX = length of segment
+; Returns:
+;
+; Registers Destroyed:
+; CX
+;
+; History:
+; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_sel_limit,<PUBLIC,NEAR>,<ax,bx,dx>
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+
+ push es
+ push di
+
+ push bx ; Get existing descriptor
+ smov es, ss
+ lea di, DscBuf
+ mov bx, selector
+ CheckLDT bl
+ifdef WOW
+ DPMICALL 000Bh
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif; WOW
+ pop bx
+
+ mov dx, word ptr [DscBuf.dsc_access]
+ and dh, 0F0h ; Zap old hlimit bits
+
+ sub bx, 1 ; Turn length into linit
+ sbb cx, 0
+ and cx, 0Fh ; Get bits 19:16 of new limit
+ or dh, cl ; Set new hlimit bits
+
+ mov word ptr DscBuf.dsc_access, dx
+ mov DscBuf.dsc_limit, bx
+ mov bx, Selector
+
+ jcxz ssl_set_limit1 ; Only one, fast out
+
+ inc cx ; Turn CX into selector count
+ call fill_in_selector_array
+ jmps ssl_done
+
+ssl_set_limit1: ; Fast out for one only
+ifdef WOW
+ DPMICALL 000Ch
+else
+ push ds
+ push bx ; Set Descriptor
+ mov ds, gdtdsc
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif; WOW
+ssl_done:
+ pop di
+ pop es
+
+ smov ss,ss ; It might be SS we're changing
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; mark_sel_NP
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc mark_sel_NP,<PUBLIC,NEAR>
+ parmW selector
+ parmW owner
+ localV DscBuf,DSC_LEN
+cBegin
+ push es
+ push ax
+ push bx
+ push di
+ifdef WOW
+ lea di, DscBuf
+ smov es, ss
+ mov bx, selector
+ DPMICALL 000Bh
+ and DscBuf.dsc_access, not DSC_PRESENT
+ or DscBuf.dsc_hlimit, DSC_DISCARDABLE
+ mov ax, owner
+ mov DscBuf.dsc_owner, ax
+ DPMICALL 000Ch
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ mov bx, selector
+ and bl, not 7
+ and [bx].dsc_access, not DSC_PRESENT
+ or [bx].dsc_hlimit, DSC_DISCARDABLE
+ mov ax, owner
+ mov [bx].dsc_owner, ax
+ pop ds
+endif; WOW
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<bx,owner>
+ pop di
+ pop bx
+ pop ax
+ pop es
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; mark_sel_PRESENT
+;
+; This little routine is called from grealloc, specifically
+; racreate.
+;
+; Entry:
+; parmW arena_sel
+; parmW selector
+;
+; Returns:
+; SI = selector to client area (may have changed)
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 06-Feb-1990 00:29:56 -by- David N. Weise [davidw]
+; Cleaning up tony's int 1's way too late.
+;
+; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc mark_sel_PRESENT,<PUBLIC,NEAR>,<ax,bx,cx,dx,di,ds>
+ parmW arena_sel
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+ push es
+ smov es, ss
+ lea di, DscBuf ; ES:DI -> descriptor buffer
+ mov bx, selector
+ifdef WOW
+ DPMICALL 000Bh ; Get old descriptor
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif; WOW
+ or DscBuf.dsc_access, DSC_PRESENT
+
+ mov ds, arena_sel
+ mov bl, DscBuf.dsc_hlimit
+ and bl, 0Fh ; Current number of selectors - 1
+ inc bl
+ mov ax, ds:[ga_size]
+ mov cx, ax
+ dec cx
+ shr cx, 12 ; New number of selectors - 1
+ inc cl
+ sub bl, cl
+ jz go_ahead ; Same number, just fill in array
+ jb get_big ; More, must get more
+
+; here to get small
+
+ and DscBuf.dsc_hlimit, NOT 0Fh
+ dec cl
+ or DscBuf.dsc_hlimit, cl ; Put new number of selectors in limit
+ inc cl
+ push cx
+ xor bh,bh ; BX = number of selectors to free
+ shl cx,3
+ .errnz DSC_LEN - 8
+ add cx,selector ; CX = selector to start to free
+ xchg bx,cx
+@@: cCall free_sel,<bx>
+ lea bx, [bx+DSC_LEN]
+ loop @B
+ pop cx
+ jmps go_ahead ; And fill in remaining selectors
+
+get_big:
+ push ax ; # paragraphs
+ mov bx, ds
+ DPMICALL 0006h ; Get base address of arena
+ add dx, 10h ; Move on to block
+ adc cx, 0
+ pop bx ; # paragraphs
+ mov ax, word ptr DscBuf.dsc_access ; Access bits in ax
+ cCall alloc_sel,<cx,dx,bx>
+ mov si, ax
+ or ax,ax ; did we get a set?
+ jz return_new_handle
+ or si, SEG_RING
+ test selector, IS_SELECTOR
+ jnz @F
+ StoH si
+ HtoS selector
+@@:
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<selector,0>
+ cCall FreeSelArray,<selector> ; Zap old handle
+ jmps return_new_handle
+
+go_ahead:
+ shl ax, 4 ; AX had length in paras
+ dec ax ; now limit in bytes
+ mov DscBuf.dsc_limit, ax ; Put in descriptor
+ push cx
+ mov bx, ds
+ DPMICALL 0006h ; Get base address of arena
+ add dx, 10h ; Move on to block
+ adc cx, 0
+ mov DscBuf.dsc_lbase, dx
+ mov DscBuf.dsc_mbase, cl
+ mov DscBuf.dsc_hbase, ch
+ pop cx ; # selectors
+ mov bx, selector
+
+ call fill_in_selector_array
+ mov si, selector ; return old selector in SI
+return_new_handle:
+ pop es
+cEnd
+
+;-----------------------------------------------------------------------;
+; alloc_data_sel_below
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc alloc_data_sel_below,<PUBLIC,NEAR>,<bx,cx,dx>
+ parmW selector
+ parmW paras
+cBegin
+ mov bx, paras
+ xor cx, cx
+rept 4
+ shl bx, 1
+ rcl cx, 1
+endm
+ cCall get_physical_address,<selector>
+ sub ax, bx
+ sbb dx, cx
+ cCall alloc_data_sel,<dx, ax, 1>
+cEnd
+
+;-----------------------------------------------------------------------;
+; alloc_data_sel_above
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc alloc_data_sel_above,<PUBLIC,NEAR>,<bx,cx,dx>
+ parmW selector
+ parmW paras
+cBegin
+ mov bx, paras
+ xor cx, cx
+rept 4
+ shl bx, 1
+ rcl cx, 1
+endm
+ cCall get_physical_address,<selector>
+ add ax, bx
+ adc dx, cx
+ cCall alloc_data_sel,<dx, ax, 1>
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; cmp_sel_address
+;
+; Compares the physical addresses corresponding to two selectors
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc cmp_sel_address,<PUBLIC,NEAR>,<ax,bx,cx,dx>
+ parmW sel1
+ parmW sel2
+cBegin
+ cCall get_physical_address,<sel1>
+ mov cx, dx
+ mov bx, ax
+ cCall get_physical_address,<sel2>
+ cmp cx, dx
+ jne csa_done
+ cmp bx, ax
+csa_done:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_arena_pointer
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 20:11:27 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc far_get_arena_pointer,<FAR,PUBLIC>
+ parmW selector
+cBegin
+ cCall get_arena_pointer,<selector>
+cEnd
+
+cProc get_arena_pointer,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ push bx
+ push ds
+ push es
+
+ mov bx, selector
+ cCall get_selector_association
+ ReSetKernelDS es
+
+if ROM
+ test al,1 ; If the low bit isn't set
+ jnz @f ; then it's either 0 or the
+ xor ax,ax ; special ROM owner selector
+ jmps gap_exit ; (see Get/SetROMOwner)
+@@:
+endif
+
+if KDEBUG
+ or ax, ax
+ jz gap_exit
+ mov ds, ax ; Sanity checks:
+
+ cmp ds:[ne_magic], NEMAGIC
+ je gap_exit
+ cmp ds:[0], 020CDh ; PSP - not a very good check,
+ je gap_exit ; but OK for DEBUG
+ push si
+ mov si, ds:[ga_handle] ; Make sure handle matches
+ sel_check si
+ or si, si
+ jz short gap_match ; Boot time...
+ sub bx, word ptr SelTableStart
+ shl bx, 2
+ cmp bx, si
+ je short gap_match
+ xor ax, ax ; put back in 5 feb 90, alias avoided
+;;; xor ax, ax ; Removed - may be an alias!
+gap_match:
+ pop si
+endif ; KDEBUG
+gap_exit:
+ pop es
+ pop ds
+ pop bx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; AssociateSelector
+;
+; Put the arena pointer or owner in the selector table slot
+; corresponding to the given selector.
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+; flags
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FarAssociateSelector,<PUBLIC,FAR>
+ parmW Selector
+ parmW ArenaSel
+cBegin
+ cCall AssociateSelector,<Selector,ArenaSel>
+cEnd
+
+cProc AssociateSelector,<PUBLIC,NEAR>,<ax,bx,es>
+ parmW selector
+ parmW ArenaSel
+cBegin
+ SetKernelDS es
+
+ CheckDS ; DS must bp pGlobalHeap
+ mov bx, selector
+ and bl, NOT SEG_RING_MASK
+ shr bx, 2 ; 2 bytes per selector: divide by 4
+if KDEBUG
+ cmp bx, SelTableLen ; More sanity
+ jb @F
+ INT3_WARN
+ jmps bad
+@@:
+endif
+
+ add bx, word ptr SelTableStart
+ mov ax, ArenaSel
+
+if KDEBUG
+ or ax, ax ; Zero means deleting entry
+ jz okay
+ CheckLDT al ; Ensure we won't GP fault later
+okay:
+endif
+
+ mov ds:[bx], ax ; Finally fill in table entry
+bad:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_selector_association
+;
+; Returns the arena pointer or owner field from the selector table that
+; was set by AssociateSelector.
+;
+;
+; Entry:
+; BX = selector to get associated arena pointer/owner
+;
+; Returns:
+; AX = arena pointer/owner or 0
+; DS = pGlobalHeap
+; ES = Kernel DS
+;
+; Registers Destroyed:
+; BX, flags
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_selector_association,<PUBLIC,NEAR>
+cBegin nogen
+
+ SetKernelDS es
+ mov ds, pGlobalHeap
+
+ and bl, NOT SEG_RING_MASK
+ shr bx, 2 ; 2 bytes per selector: divide by 4
+
+if ROM ;-------------------------------
+
+ cmp bx, SelTableLen ; Selector in range? Make this check
+ jb gsa_in_range ; even if not debug kernel.
+ xor ax,ax ; No, just fail
+ jmps gsa_exit
+gsa_in_range:
+
+else ;ROM ------------------------
+
+if KDEBUG
+ cmp bx, SelTableLen ; Selector in range?
+ jb @F
+ INT3_WARN
+ xor ax, ax ; No, just fail
+ jmps gsa_exit
+@@:
+endif
+endif ;ROM ------------------------
+
+ add bx, word ptr SelTableStart
+ mov ax, ds:[bx] ; Get associated value
+
+gsa_exit:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; pdref ;
+; ;
+; Dereferences the given global handle, i.e. gives back abs. address. ;
+; ;
+; Arguments: ;
+; DX = selector ;
+; DS:DI = BURGERMASTER ;
+; ;
+; Returns: ;
+; ES:DI = address of arena header ;
+; AX = address of client data ;
+; CH = lock count or 0 for fixed objects ;
+; CL = flags ;
+; SI = handle, 0 for fixed objects ;
+; ;
+; Error Returns: ;
+; ZF = 1 if invalid or discarded ;
+; AX = 0 ;
+; BX = owner of discarded object ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ghdref ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc pdref,<PUBLIC,NEAR>
+
+cBegin nogen
+ mov si, dx
+ sel_check si
+
+ or si, si ; Null handle?
+ mov ax, si
+ jz pd_exit ; yes, return 0
+
+ cCall GetAccessWord,<dx> ; Get the access bits
+ or ax, ax
+ jz pd_totally_bogus
+
+; We should beef up the check for a valid discarded sel.
+
+ xor cx,cx
+ test ah, DSC_DISCARDABLE
+ jz pd_not_discardable
+ or cl,GA_DISCARDABLE
+ ; Discardable, is it code?
+ test al,DSC_CODE_BIT
+ jz pd_not_code
+ or cl,GA_DISCCODE
+pd_not_code:
+
+pd_not_discardable:
+ test al,DSC_PRESENT
+ jnz pd_not_discarded
+
+; object discarded
+
+ or cl,HE_DISCARDED
+ife RING-1
+ or si, SEG_RING+1 ; Handles are RING 2
+else
+ or si, SEG_RING-1 ; Handles are RING 2
+endif
+ cCall get_arena_pointer,<si> ; get the owner
+ mov bx, ax
+ xor ax,ax
+ jmps pd_exit
+
+pd_not_discarded:
+if KDEBUG
+ or si, SEG_RING ; For the sel_check later
+endif
+ cCall get_arena_pointer,<si>
+ or ax, ax
+ jz pd_nomatch
+ mov es, ax
+ mov ax, es:[ga_handle] ; The real thing
+ mov si, ax
+ cmp ax, dx ; Quick check - handle in header
+ je pd_match ; matches what we were given?
+
+ test dl, IS_SELECTOR ; NOW, we MUST have been given
+ jz pd_totally_bogus ; a selector!!
+ test al, GA_FIXED ; Fixed segment?
+ jnz pd_nomatch ; Doesn't match arena header...
+ push ax
+ HtoS al
+ cmp ax, dx ; Selector must match
+ pop ax
+ jne pd_nomatch
+pd_match:
+ or cl, es:[ga_flags]
+ and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!!
+ test al, GA_FIXED
+ jnz pd_fixed
+ mov ch, es:[ga_count]
+ HtoS al ; Back to ring 1
+
+pd_exit:
+ or ax,ax
+ ret
+
+pd_totally_bogus:
+if KDEBUG
+ or dx,dx
+ jnz dref_invalid
+pd_null_passed:
+endif
+ xor dx,dx
+
+pd_nomatch: ; Handle did not match...
+ mov ax, dx ; Must be an alias...
+pd_fixed:
+ xor si, si
+ xor dx, dx
+ jmps pd_exit
+
+if KDEBUG
+dref_invalid:
+ push ax
+ kerror ERR_GMEMHANDLE,<gdref: invalid handle>,0,dx
+ pop ax
+ jmps pd_null_passed
+endif
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; get_rover_2 ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_rover_2,<PUBLIC,NEAR>,<ax,bx,di>
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, es
+ lea di, DscBuf
+ smov es, ss
+ifdef WOW
+ DPMICALL 000Bh ; Get source descriptor
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif; WOW
+ SetKernelDS es
+ mov bx, kr2dsc ; Will set kr2 to point there
+ or bl, SEG_RING
+ mov word ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA
+ mov DscBuf.dsc_limit, 0FFFFh
+ smov es, ss
+ UnSetKernelDS es
+ifdef WOW
+ DPMICALL 000Ch
+else
+ push ds
+ mov ds, gdtdsc
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif; WOW
+ mov es, bx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_blotto
+;
+;
+; Entry:
+; AX = arena header
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 31-Jul-1988 16:20:53 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_blotto,<PUBLIC,NEAR>,<bx,di,es>
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, ax
+ lea di, DscBuf
+ smov es, ss
+ifdef WOW
+ DPMICALL 000Bh ; Get source descriptor
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif
+ SetKernelDS es
+ mov bx, blotdsc ; Will set kr2 to point there
+ or bl, SEG_RING
+ mov word ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA
+ mov DscBuf.dsc_limit, 0FFFFh
+ mov DscBuf.dsc_hlimit, 0Fh
+ add DscBuf.dsc_lbase, 10h ; Move on to object from arena
+ adc DscBuf.dsc_mbase, 0
+ adc DscBuf.dsc_hbase, 0
+ smov es, ss
+ UnSetKernelDS es
+ifdef WOW
+ DPMICALL 000Ch ; Set new descriptor
+else
+ push ds
+ mov ds, gdtdsc
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif ;WOW
+ mov ax, bx ; Return new selector
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_temp_sel
+; far_get_temp_sel
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 08-Aug-1988 19:14:45 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc far_get_temp_sel,<FAR,PUBLIC>
+cBegin nogen
+ cCall get_temp_sel
+ ret
+cEnd nogen
+
+cProc get_temp_sel,<PUBLIC,NEAR>,<ax,bx,cx,di,si,ds>
+ localV DscBuf,DSC_LEN
+cBegin
+ mov cx, 1
+ call get_sel
+ mov ax, si
+ jz gts_exit
+
+ mov bx, es
+ smov es, ss
+ lea di, DscBuf
+ifdef WOW
+ DPMICALL 000Bh ; Get existing descriptor
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif ; WOW
+
+ mov DscBuf.dsc_access,DSC_PRESENT+DSC_DATA
+ mov DscBuf.dsc_limit,0ffffh
+IFNDEF WOW
+ or DscBuf.dsc_hlimit, 0Fh ; Max length ; bugbug daveh
+ENDIF
+ mov bx, si
+ or bl, SEG_RING
+ifdef WOW
+ DPMICALL 000Ch ; Set new descriptor
+else
+ push ds
+ mov ds, gdtdsc
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif ; WOW
+ mov es, bx ; and return selector in ES
+gts_exit:
+cEnd
+
+cProc far_free_temp_sel,<FAR,PUBLIC>
+ parmW selector
+cBegin
+ cCall free_sel,<selector>
+cEnd
+
+;-----------------------------------------------------------------------;
+; PrestoChangoSel
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IPrestoChangoSelector,<PUBLIC,FAR>,<di,si>
+ parmW sourcesel
+ parmW destsel
+ localV DscBuf,DSC_LEN
+cBegin
+ smov es, ss
+ lea di, DscBuf
+ mov bx, sourcesel
+ifdef WOW
+ DPMICALL 000Bh
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif ; WOW
+ xor DscBuf.dsc_access, DSC_CODE_BIT
+ mov bx, destsel
+ifdef WOW
+ DPMICALL 000Ch
+else
+ push ds
+ mov ds, gdtdsc
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+endif; WOW
+ mov ax, bx
+ smov es, 0
+cEnd
+
+
+if 0
+;-----------------------------------------------------------------------;
+; pmnum ;
+; ;
+; Enumerates the allocated selectors in the GDT with the ;
+; specified discard level. ;
+; ;
+; Arguments: ;
+; SI = zero first time called. Otherwise contains a pointer ;
+; to the last handle returned. ;
+; CX = #handles remaining. Zero first time called. ;
+; DI = address of local arena information structure. ;
+; ;
+; Returns: ;
+; SI = address of handle table entry ;
+; CX = #handles remaining, including the one returned. ;
+; ZF = 1 if SI = 0 and no more handle table entries. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 04:19:15p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc pmnum,<PUBLIC,NEAR>
+cBegin nogen
+ or si,si ; Beginning of enumeration?
+ jnz lcdhenext ; No, return next handle
+ mov ax,[di].hi_htable ; Yes, start with last handle table block
+
+lcdhtloop:
+ mov si,ax ; SI = address of handle table block
+ or si,si ; Any more handle table blocks?
+ jz lcdheall ; No, return zero
+ lodsw ; Get # handles in this block
+ errnz ht_count
+ mov cx,ax ; into CX
+lcdheloop: ; Loop to process each handle table entry
+ mov ax,word ptr [si].lhe_flags
+ errnz <lhe_flags - he_flags>
+ errnz <2-lhe_flags>
+ errnz <3-lhe_count>
+
+ inc ax ; Free handle?
+ jz lcdhenext ; Yes, skip this handle
+ errnz <LHE_FREEHANDLE - 0FFFFh>
+ errnz <LHE_FREEHANDLE - HE_FREEHANDLE >
+ dec ax
+
+ cmp [di].hi_dislevel,0 ; Enumerating all allocated handles?
+ je lcdheall ; Yes, return this handle
+
+ test al,LHE_DISCARDED ; No, handle already discarded?
+ jnz lcdhenext ; Yes, skip this handle
+
+ and al,LHE_DISCARDABLE ; Test if DISCARDABLE
+ cmp [di].hi_dislevel,al ; at the current discard level
+ jne lcdhenext ; No, skip this handle
+
+ or ah,ah ; Is handle locked?
+ jnz lcdhenext ; Yes, skip this handle
+
+lcdheall:
+ or si,si ; No, then return handle to caller
+ ret ; with Z flag clear
+
+lcdhenext:
+ lea si,[si].SIZE LocalHandleEntry ; Point to next handle table entry
+ errnz <LocalHandleEntry - HandleEntry>
+ loop lcdheloop ; Process next handle table entry
+ lodsw ; end of this block, go to next
+ jmp lcdhtloop
+cEnd nogen
+endif
+
+
+;-----------------------------------------------------------------------;
+; LongPtrAdd
+;
+; Performs segment arithmetic on a long pointer and a DWORD offset
+; The resulting pointer is normalized to a paragraph boundary.
+; The offset cannot be greater than a megabyte.
+;
+; Entry:
+;
+; Returns:
+; DX:AX new segment:offset
+;
+; Error returns:
+; DX:AX = 0
+;
+; Registers Destroyed:
+; BX,CX
+;
+; History:
+; Mon 19-Dec-1988 18:37:23 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifdef WOW
+
+LPTRADDWOW_SETBASE equ 01h
+
+;cProc LongPtrAddWOW,<PUBLIC,FAR>,<si,di>
+; parmD long_ptr
+; parmD delta
+; parmW RefSelector
+; parmW flBaseSetting
+;
+; effectively pops RefSelector and flBaseSetting into dx and ax.
+; and jumps to longptrAddWorker.
+;
+; RefSelector is used only if the descriptor needs to be set.
+;
+
+labelFP <PUBLIC,LongPtrAddWOW>
+ pop ax
+ pop dx ; far return address
+ mov bx,sp
+ xchg ax, ss:[bx] ; replace the 'dword' with the return address
+ xchg dx, ss:[bx+2]
+ jmps LongPtrAddWorker ; ax = flags; dx = reference selector
+
+labelFP <PUBLIC,LongPtrAdd>
+ mov ax, LPTRADDWOW_SETBASE
+ xor dx, dx
+ ; fall through
+
+cProc LongPtrAddWorker,<PUBLIC,FAR>,<si,di>
+ parmD long_ptr
+ parmD delta
+ localV DscBuf,DSC_LEN
+ localW flBaseSetting
+ localW RefSelector
+cBegin
+ mov flBaseSetting, ax ; save in localvariables
+ mov RefSelector, dx
+ or dx, dx ; if RefSelector is nonzero
+ jz @F ; use it for querying descriptor info.
+ xchg dx, word ptr long_ptr[2] ; and store the selector to be set in
+ mov RefSelector, dx ; the localvariable
+@@:
+else
+
+cProc LongPtrAdd,<PUBLIC,FAR>,<si,di>
+ parmD long_ptr
+ parmD delta
+ localV DscBuf,DSC_LEN
+cBegin
+
+endif
+ mov bx,word ptr long_ptr[2]
+ lea di, DscBuf
+ smov es, ss
+ifdef WOW
+ DPMICALL 000Bh ; Pick up old descriptor
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+endif ; WOW
+ mov ax,word ptr long_ptr[0] ; get the pointer into SI:AX
+ and ax,0FFF0h
+
+ mov si, DscBuf.dsc_lbase ; DX:SI gets old base
+ mov dl, DscBuf.dsc_mbase
+ mov dh, DscBuf.dsc_hbase
+
+ add si, ax ; Add in old pointer offset
+ adc dx, 0
+
+ mov cx, word ptr delta[2] ; add the segment and MSW
+ test cx, 0FFF0h
+ifdef WOW
+ jz @F
+ test flBaseSetting, LPTRADDWOW_SETBASE
+ jnz lptr_mustset
+ jmp short lpa_too_big
+@@:
+else
+ jnz short lpa_too_big
+endif
+
+ add si, word ptr delta[0]
+ adc dx, cx
+
+ifdef WOW
+lptr_mustset:
+endif
+
+ mov cl, DscBuf.dsc_hlimit ; Calculate # selectors now in array
+ and cl, 0Fh
+ xor ch, ch
+ inc cx
+
+ifdef WOW
+ test flBaseSetting, LPTRADDWOW_SETBASE
+ jz lptr_dontset
+ cmp RefSelector, 0
+ jz @F
+ mov bx, RefSelector
+ mov word ptr long_ptr[2], bx
+@@:
+endif
+ mov DscBuf.dsc_lbase, si ; Put new base back in descriptor
+ mov DscBuf.dsc_mbase, dl
+ mov DscBuf.dsc_hbase, dh
+
+ call fill_in_selector_array
+
+ifdef WOW
+lptr_dontset:
+ test word ptr delta[2], 0fff0h
+ jz @F
+ mov cx, word ptr delta[2]
+ jmps lpa_too_big
+@@:
+endif
+ mov dx,word ptr long_ptr[2]
+ mov ax,word ptr long_ptr[0]
+ and ax, 0Fh
+ jmps lpa_exit
+
+lpa_too_big:
+ xor ax,ax
+ xor dx,dx
+lpa_exit:
+ smov es,0
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSelectorBase
+;
+; Sets the base and limit of the given selector.
+;
+; Entry:
+; parmW selector
+; parmD selbase
+;
+; Returns:
+; AX = selector
+;
+; Error Returns:
+; AX = 0
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetSelectorBase,<PUBLIC,FAR>
+ parmW selector
+ parmD selbase
+cBegin
+ mov bx, selector
+ mov dx, selbase.lo
+ mov cx, selbase.hi
+ifdef WOW
+ DPMICALL 0007h
+else
+ push ds
+ mov ds, gdtdsc
+ push bx
+ and bl, not 7
+ mov ds:[bx].dsc_lbase, dx
+ mov ds:[bx].dsc_mbase, cl
+ mov ds:[bx].dsc_hbase, ch
+ pop bx
+ pop ds
+endif ; WOW
+ mov ax, 0
+ jc ssb_exit
+ mov ax, selector ; Return selector
+ssb_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; GetSelectorLimit
+;
+; Gets the limit of the given selector.
+;
+; Entry:
+; parmW selector
+;
+; Returns:
+; DX:AX = limit of selector
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetSelectorLimit,<PUBLIC,FAR>
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, selector
+ifdef WOW
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh
+ xor dx, dx
+ mov ax, DscBuf.dsc_limit
+ mov dl, DscBuf.dsc_hlimit
+ and dx, 0Fh ; AND out flags
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ and bl, not 7
+ mov ax, [bx].dsc_limit
+ mov dl, [bx].dsc_hlimit
+ and dx, 0Fh ; AND out flags
+ pop ds
+endif ; WOW
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSelectorLimit
+;
+; Sets the limit of the given selector.
+;
+; Entry:
+; parmW selector
+; parmD sellimit
+;
+; Returns:
+; AX = 0 success
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetSelectorLimit,<PUBLIC,FAR>
+ parmW selector
+ parmD sellimit
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, selector
+ifdef WOW
+ push di
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh
+ mov ax, word ptr sellimit[0]
+ mov DscBuf.dsc_limit, ax
+ mov al, byte ptr sellimit[2]
+ and al, 0Fh
+ and DscBuf.dsc_hlimit, 0F0h
+ or DscBuf.dsc_hlimit, al
+ DPMICALL 000Ch
+ pop di
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push si
+ mov si, bx
+ and si, not 7
+ mov ax, sellimit.lo
+ mov [si].dsc_limit, ax
+ mov ax, sellimit.hi
+ and al, 0Fh
+ and [si].dsc_hlimit, 0F0h
+ or [si].dsc_hlimit, al
+ pop si
+ pop ds
+endif ;WOW
+ xor ax,ax ; for now always return success
+cEnd
+
+;-----------------------------------------------------------------------;
+; SelectorAccessRights
+;
+; Sets the access and other bytes of the given selector.
+;
+; Entry:
+; parmW selector
+; parmW getsetflag
+; parmD selrights
+;
+; Returns:
+; AX = 0 success
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SelectorAccessRights,<PUBLIC,FAR>
+
+ parmW selector
+ parmW getsetflag
+ parmW selrights
+ localV DscBuf,DSC_LEN
+cBegin
+
+ cCall GetAccessWord,<selector>
+ cmp getsetflag,0
+ jnz short sar_set
+
+ and ax, 0D01Eh ; Hide bits they can't play with
+ jmps sar_exit
+
+sar_set:
+ mov cx, selrights
+ and cx, 0D01Eh ; Zap bits they can't set and
+ and ax, NOT 0D01Eh ; get them from existing access rights
+ or cx, ax
+ mov bx, selector
+ifdef WOW
+ push di
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh ; Set new access rights
+ mov word ptr DscBuf.dsc_access, cx
+ DPMICALL 000Ch
+ pop di
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ and bx, not 7
+ mov word ptr [bx].dsc_access, cx
+ pop ds
+endif ;WOW
+ xor ax,ax ; for now always return success
+
+sar_exit:
+
+cEnd
+
+;
+; Direct GDT access is really helpful here - you are supposed
+; to use LAR to get the high access bits, but this
+; cannot be done on a 286 where we are STILL using
+; these bits in a 386 compatible manner
+;
+
+cProc GetAccessWord,<PUBLIC,NEAR>
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+ push bx
+ push es
+ cmp gdtdsc, 0 ; Do we have LDT access?
+ je do_it_the_really_slow_way ; no, must make DPMI call
+
+ mov es, gdtdsc ; Go grab it out of the LDT
+ mov bx, selector
+ sel_check bl
+ mov ax, word ptr es:[bx].dsc_access
+ jmps gaw_exit
+
+do_it_the_really_slow_way:
+ push di
+ lea di, DscBuf
+ smov es, ss
+ mov bx, selector
+ DPMICALL 000Bh
+ mov ax, word ptr DscBuf.dsc_access
+ pop di
+gaw_exit:
+ pop es
+ pop bx
+gaw_exit1:
+cEnd
+
+;
+; Setting it is WORSE....
+;
+cProc SetAccessWord,<PUBLIC,NEAR>,<ax,bx,es>
+ parmW selector
+ parmW access
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, selector
+ifndef WOW ; For WOW we have to call DMPI, LATER for mips this should party directly
+ cmp gdtdsc, 0
+ je slow_again
+
+ mov es, gdtdsc ; Go stuff it in the LDT
+ sel_check bl
+ mov ax, access
+ mov word ptr es:[bx].dsc_access, ax
+ jmps saw_exit
+
+endif ; WOW
+slow_again:
+;
+; The DPMI guys changed their mind, NOW call 9h
+; WILL set the AVL bit in the descriptor on
+; all implementations.
+;
+ sel_check bl
+ push cx
+ mov cx, access
+ DPMICALL 0009h
+ pop cx
+saw_exit:
+cEnd
+
+;
+; Selector in BX
+;
+cProc GetSelectorCount,<PUBLIC,NEAR>
+cBegin nogen
+ cmp gdtdsc, 0
+ je @F
+ push ds
+ push bx
+ mov ds, gdtdsc
+ sel_check bl
+ mov al, ds:[bx].dsc_hlimit
+ pop bx
+ pop ds
+ and ax, 0Fh
+ inc al
+ ret
+@@:
+ push es
+ push di
+ sub sp, DSC_LEN
+ mov di, sp
+ smov es, ss
+ DPMICALL 000Bh
+ mov al, es:[di].dsc_hlimit
+ add sp, DSC_LEN
+ pop di
+ pop es
+ and ax, 0Fh
+ inc al
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GlobalPageLock
+;
+; Page locks the memory associated with the Handle.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+; AX = new lock count
+;
+; History:
+; Fri 16-Feb-1990 02:13:09 -by- David N. Weise [davidw]
+; Should it or shouldn't it? At the very least it must lock
+; the object to be consitent with 386pmode.
+;
+; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalPageLock,<PUBLIC,FAR>,<si,di>
+
+ parmW handle
+cBegin
+ cCall GlobalFix,<handle>
+ cCall GetSelectorLimit,<handle>
+ mov si, dx
+ mov di, ax
+ cCall get_physical_address,<handle>
+ mov bx, dx
+ mov cx, ax
+ DPMICALL 0600h
+ mov ax, 1
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalPageUnlock
+;
+; Page unlocks the memory associated with the Handle.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+; AX = new lock count
+;
+; History:
+; Fri 16-Feb-1990 02:13:09 -by- David N. Weise [davidw]
+; Should it or shouldn't it? At the very least it must unlock
+; the object to be consitent with 386pmode.
+;
+; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalPageUnlock,<PUBLIC,FAR>,<si,di>
+
+ parmW handle
+cBegin
+ cCall GlobalUnFix,<handle>
+ cCall GetSelectorLimit,<handle>
+ mov si, dx
+ mov di, ax
+ cCall get_physical_address,<handle>
+ mov bx, dx
+ mov cx, ax
+ DPMICALL 0601h
+ xor ax,ax ; page lock count is zero
+cEnd
+
+
+if ROM ;----------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; ChangeROMHandle
+;
+; Changes the handle of an allocated memory block. Used when loading
+; segments from ROM to RAM so RAM copy can use the handle expected by
+; other ROM code.
+;
+; Entry:
+; parmW hOld
+; parmW hNew
+;
+; Returns:
+; AX = hNew if successful, 0 if not
+;
+; History:
+;
+;-----------------------------------------------------------------------
+
+ assumes ds,nothing
+ assumes es,nothing
+
+
+cProc ChangeROMHandle,<PUBLIC,FAR>,<bx,si,di,ds,es>
+ parmW hOld
+ parmW hNew
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx,hOld ; Get arena pointer for old handle
+ cCall get_arena_pointer,<bx>
+ or ax,ax
+if KDEBUG
+ jnz @f
+ INT3_WARN
+ jmps ch_ret
+@@:
+else
+ jz ch_ret
+endif
+ push ax
+ mov si, bx
+ and bx, SEG_RING_MASK ; Ring bits
+ or bx, hNew ; New handle
+ smov es, ss
+ lea di, DscBuf
+ xchg bx ,si
+ DPMICALL 000Bh ; Get old descriptor
+ xchg bx, si
+ DPMICALL 000Ch ; Set new descriptor
+ pop es ; es -> arena (or owner)
+
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<si,0> ; Old sel has not association
+
+ test DscBuf.dsc_access,DSC_PRESENT ; Change handle in arena
+ jz crh_np ; if selector is present
+ mov es:[ga_handle], bx
+crh_np:
+ cCall AssociateSelector,<bx,es> ; New sel associated with this
+ ; arena or owner
+ cCall FreeSelArray,<hOld> ; Free old selector
+
+ mov ax,bx
+ch_ret:
+cEnd
+
+;-----------------------------------------------------------------------
+; CloneROMSelector
+;
+; Changes the base and limit of the clone selector to point to the
+; ROM selector's original ROM segment. ROM segment selectors may be
+; changed when loading a ROM segment to RAM.
+;
+; Entry:
+; parmW selROM
+; parmW selClone
+;
+; Returns:
+;
+; History:
+;
+;-----------------------------------------------------------------------
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CloneROMSelector,<PUBLIC,NEAR>,<bx, si, di, ds, es>
+ parmW selROM
+ parmW selClone
+ localV DscBuf,DSC_LEN
+cBegin
+ SetKernelDS es
+ mov ax,selROMLDT
+ mov es,selROMToc
+ assumes es,nothing
+
+ mov bx,selROM
+
+if KDEBUG
+ cmp bx,es:[FirstROMsel] ; sanity checks to make sure
+ jae @f ; selector is within ROM range
+ INT3_WARN
+@@:
+ push bx
+ and bl,not SEG_RING_MASK
+ sub bx,es:[FirstROMsel]
+ shr bx,3
+ cmp bx,es:[cROMsels]
+ jbe @f
+ INT3_WARN
+@@:
+ pop bx
+endif
+ mov si, bx
+ and si, NOT SEG_RING_MASK
+ sub si, es:[FirstROMsel] ; si = offset in ROM LDT of descriptor
+
+ mov ds, ax ; copy ROM desciptor to stack buffer
+ smov es, ss
+ lea di, DscBuf
+
+ errnz <8 - DSC_LEN>
+ movsw
+ movsw
+ movsw
+ movsw
+
+ mov bx, selClone ; clone descriptor to orig ROM contents
+ lea di, DscBuf
+ DPMICALL 000Ch
+
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<bx,0> ; no arena/owner currently
+
+ mov ax,bx ; return with selClone in AX
+cEnd
+
+endif ;ROM ---------------------------------------------------------
+
+
+cProc SetKernelCSDwordProc,<PUBLIC,NEAR>,<ax,bx,ds>
+ parmw addr
+ parmw hiword
+ parmw loword
+cBegin
+ SetKernelDS
+ mov ds, MyCSAlias
+ UnSetKernelDS
+ mov bx, addr
+ mov ax, loword
+ mov [bx], ax
+ mov ax, hiword
+ mov [bx+2], ax
+cEnd
+
+cProc GetKernelDataSeg,<PUBLIC,NEAR>
+cBegin nogen
+ mov ax, cs:MyCSDS
+ ret
+cEnd nogen
+
+cProc SetKernelDSProc,<PUBLIC,NEAR>
+cBegin nogen
+ mov ds, cs:MyCSDS
+ ret
+cEnd nogen
+
+cProc SetKernelESProc,<PUBLIC,NEAR>
+cBegin nogen
+ mov es, cs:MyCSDS
+ ret
+cEnd nogen
+
+cProc CheckKernelDSProc,<PUBLIC,NEAR>
+cBegin nogen
+if KDEBUG
+ cmp ax, cs:MyCSDS
+ je dsok
+ INT3_WARN
+dsok:
+endif
+ ret
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarGetOwner,<PUBLIC,FAR>,<bx>
+ parmW Selector
+cBegin
+ cCall GetOwner,<Selector>
+cEnd
+
+cProc GetOwner,<PUBLIC,NEAR>,<es>
+ parmW Selector
+cBegin
+ cCall get_arena_pointer,<Selector>
+if ROM
+ or ax,ax ; get_arena_pointer fails on
+ jnz go_got_it ; ROM segments so give it
+ cCall GetROMOwner,<Selector> ; another try
+ jmps go_end
+go_got_it:
+else
+ or ax, ax
+ jz go_end
+endif
+ mov es, ax
+ mov ax, es:[ga_owner]
+go_end:
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarSetOwner,<PUBLIC,FAR>
+ parmW Selector
+ parmW owner
+cBegin
+ cCall SetOwner,<Selector,owner>
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SetOwner,<PUBLIC,NEAR>,<ax,es>
+ parmW Selector
+ parmW owner
+cBegin
+ cCall get_arena_pointer,<Selector>
+ mov es, ax
+ push owner
+ pop es:[ga_owner]
+cEnd
+
+
+if ROM ;----------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; Set/GetROMOwner
+;
+; The Get/SetROMOwner routines use AssociateSelector and the inverse
+; get_selector_association routines to track the owner of an object
+; in ROM. ROM objects (like code segments and resources) don't have
+; a global heap arena to store the owner's ID in.
+;
+; NOTE: THIS CODE DEPENDS ON WINDOWS RUNNING IN RING 1 OR 3!! The low
+; bit of the associated value is set to zero to indicate the object is
+; in ROM. SetROMOwner expects the owner selector to have the low bit
+; set, and GetROMOwner returns the owner field with the low bit set.
+;
+;-----------------------------------------------------------------------
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarSetROMOwner,<PUBLIC,FAR>
+ parmW Selector
+ parmW Owner
+cBegin
+ cCall SetROMOwner,<Selector,Owner>
+cEnd
+
+cProc SetROMOwner,<PUBLIC,NEAR>,<ds>
+ parmW Selector
+ parmW Owner
+cBegin
+ mov ax,Owner
+ and al,NOT 1 ; mark this as a ROM selector
+ SetKernelDS
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<Selector,ax>
+cEnd
+
+
+cProc GetROMOwner,<PUBLIC,NEAR>,<bx,es,ds>
+ parmW Selector
+cBegin
+ mov bx,Selector
+ cCall get_selector_association
+ or ax,ax
+ jz gro_exit
+
+ test al,1 ; low bit off if ROM owner
+ jnz gro_not_rom_owner
+
+ or al,1 ; restore bit cleared by SetROMOwner
+ jmps gro_exit
+
+gro_not_rom_owner:
+ xor ax,ax
+
+gro_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; IsROMObject
+;
+; Determines if a given selector points into the ROM area.
+;
+; Entry:
+; selector selector to check
+;
+; Returns:
+; AX != 0 & CY set if selector points to ROM
+; AX = 0 & CY clr if selector does not point to ROM
+;
+; Registers Destroyed:
+; none
+;
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FarIsROMObject, <PUBLIC, FAR>
+ parmW selector
+cBegin
+ cCall IsROMObject, <selector>
+cEnd
+
+cProc IsROMObject,<PUBLIC,NEAR>,<bx,di,es>
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+
+ push ds
+ SetKernelDS
+
+if KDEBUG
+ mov ax,selector
+ sel_check ax
+endif
+ mov bx,selector
+ smov es,ss
+ lea di,DscBuf
+ DPMICALL 000Bh ; Get current descriptor
+
+ mov bh,DscBuf.dsc_hbase ; is descriptor base at or
+ mov bl,DscBuf.dsc_mbase ; above start of ROM?
+ mov ax,DscBuf.dsc_lbase
+ sub ax,lmaHiROM.off
+ sbb bx,lmaHiROM.sel
+ jc iro_not_rom
+
+ sub ax,cbHiROM.off ; make sure it's not above
+ sbb bx,cbHiROM.sel ; the end of the ROM
+ jnc iro_not_rom
+
+ mov al,1 ; in ROM range, ret AX != 0 & CY set
+ jmps iro_exit
+
+iro_not_rom:
+ xor ax,ax ; not in ROM, AX = 0 & CY clear
+
+iro_exit:
+ pop ds
+ assumes ds,nothing
+cEnd
+
+
+endif ;ROM ---------------------------------------------------------
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarValidatePointer,<PUBLIC,FAR>
+ parmD p
+cBegin
+ cCall ValidatePointer,<p>
+cEnd
+
+cProc ValidatePointer,<PUBLIC,NEAR>
+ parmD p
+cBegin
+ lsl ax, seg_p
+ jnz short bad_p ; can we access this selector?
+ cmp ax, off_p ; yes, is the offset valid?
+ jae short good_p
+bad_p:
+ xor ax, ax
+ jmps vp_done
+good_p:
+ mov ax, 1
+vp_done:
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+OneParaBytes dw 10h
+
+cProc SelToSeg,<PUBLIC,NEAR>,<dx>
+ parmW selector
+cBegin
+ cCall get_physical_address,<selector>
+ div OneParaBytes ; Smaller than rotates
+cEnd
+
+
+
+cProc SegToSelector,<PUBLIC,NEAR>,<bx>
+ parmW smegma
+cBegin
+ mov bx, smegma
+ DPMICALL 0002h
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_discarded_sel_owner
+;
+; Sets the owner of a selector that points to a discarded object,
+; which lives in the limit field.
+;
+; Entry:
+; BX = selector to mark
+; ES = owner
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+; BX
+;
+; History:
+; Sun 03-Dec-1989 21:02:24 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_discarded_sel_owner,<PUBLIC,FAR>,<ds,di>
+ localV DscBuf,DSC_LEN
+cBegin
+ mov cx, es
+ifdef WOW
+ push ax
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh
+ mov DscBuf.dsc_owner, cx
+ DPMICALL 000Ch
+ pop ax
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push di
+ mov di, bx
+ and di, not 7
+ mov [di].dsc_owner, cx
+ pop di
+ pop ds
+endif ; WOW
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<bx,cx>
+ mov es, cx ; Restore ES
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetResourceOwner
+;
+; Sets the owner of a selector that points to a not present resource
+;
+; Entry:
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+;
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetResourceOwner,<PUBLIC,NEAR>,<ax,bx,cx,di,ds,es>
+ parmW selector
+ parmW owner
+ parmW selCount
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, selector
+ mov cx, owner
+ifdef WOW
+
+ smov es, ss
+ lea di, DscBuf
+ DPMICALL 000Bh ; Get current descriptor
+ mov DscBuf.dsc_owner, cx
+ mov DscBuf.dsc_access, DSC_DATA
+ mov cx,selCount
+ dec cl
+ and cl,00001111b
+ or cl,DSC_DISCARDABLE
+ mov DscBuf.dsc_hlimit, cl ; Save number of selectors here
+ DPMICALL 000Ch ; Set it with new owner
+else
+ push ds ; Get Descriptor
+ mov ds, gdtdsc
+ push bx
+ and bx, not 7
+ mov [bx].dsc_owner, cx
+ mov [bx].dsc_access, DSC_DATA
+ mov cx,selCount
+ dec cl
+ and cl,00001111b
+ or cl,DSC_DISCARDABLE
+ mov [bx].dsc_hlimit, cl ; Save number of selectors here
+ pop bx
+ pop ds
+endif ; WOW
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector,<bx,owner> ; And save in selector table
+cEnd
+
+
+;-----------------------------------------------------------------------;
+;
+; Alias stuff moved out due to gross bloating of this file
+;
+;-----------------------------------------------------------------------;
+if ALIASES
+include aliases.asm
+endif
+
+
+;-----------------------------------------------------------------------;
+; DPMIProc
+;
+; Called NEAR by the DPMICALL macro -
+; this is better than intercepting int 31h
+;
+; By sheer fluke, all intercepts return with
+; Carry clear ie no error.
+;
+;-----------------------------------------------------------------------;
+cProc DPMIProc,<PUBLIC,NEAR>
+cBegin nogen
+ or ah, ah
+ jz @F
+CallServer:
+ifndef WOW
+ int 31h ; Nope, call DPMI server
+ ret
+else
+ test word ptr [prevInt31Proc + 2],0FFFFh
+ jz dp30
+dp20: pushf
+ call [prevInt31Proc]
+ ret
+endif
+@@:
+if ROM
+ cmp al, 01h ; Free selector?
+ jne @f
+ push ds
+ SetKernelDS
+ cmp bx,sel1stAvail ; Yes, don't free selectors in
+ pop ds ; the preallocated ROM range
+ UnSetKernelDS
+ jae CallServer
+ ret
+@@:
+endif ;ROM
+ifdef WOW
+ cmp gdtdsc, 0 ; Can we party?
+ jz CallServer ; Nope
+endif
+ push ds
+ mov ds, gdtdsc
+ifdef WOW
+
+ or al, al
+ jnz @F
+ mov ax, WOW_DPMIFUNC_00
+ pop ds
+ jmps CallServer
+@@:
+endif
+ cmp al, 0Bh
+ jne @F
+
+ test bx,4
+ jnz xx1
+
+ ; On MIPS if Win87EM is processing an NPX exception the selector
+ ; to Dosx's stack is being looked up here. Since it is a global
+ ; selector the normal lookup will not find it and Win87EM will
+ ; fault. This is solved by calling Dosx since it knows about the
+ ; global selectors that we don't. - MarkRi [6/93]
+ ;
+ pop ds
+ jmps CallServer
+
+xx1: push si ; Get Descriptor - used very often!
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+ ret
+
+ifndef WOW
+@@:
+ cmp al, 0Ch
+ jne @F
+
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+ ret
+
+@@:
+ cmp al, 07h ; Set Segment Base Address
+ jne @F
+ push bx
+ and bl, not 7
+ mov ds:[bx].dsc_lbase, dx
+ mov ds:[bx].dsc_mbase, cl
+ mov ds:[bx].dsc_hbase, ch
+ pop bx
+ pop ds
+ ret
+endif
+@@:
+ cmp al, 06h ; Get Segment Base Address
+ jne @F
+ push bx
+ and bl, not 7
+ mov dx, ds:[bx].dsc_lbase
+ mov cl, ds:[bx].dsc_mbase
+ mov ch, ds:[bx].dsc_hbase
+ pop bx
+ pop ds
+ ret
+ifndef WOW
+@@:
+ cmp al, 09h ; Set Descriptor Access Rights
+ jne @F
+ push bx
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, cx
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+ ret
+endif
+@@:
+ pop ds
+ jmp CallServer
+
+ifdef WOW
+dp30: int 31h
+ ret
+endif
+cEnd nogen
+
+
+if ROM
+if1
+%out CheckROMSelector -- fix me!! (what exactly is wrong?)
+endif
+endif
+
+if 0 ;;ROM and KDEBUG
+
+;------------------------------------------------------------------------
+; CheckROMSelector
+;
+; ROM Windows debug hack to ensure that Windows code doesn't try writing
+; to the ROM image. It does this by making any data selector to the
+; ROM read only.
+;
+; Entry:
+; DS:BX -> descriptor to check
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+; none
+;
+;------------------------------------------------------------------------
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CheckROMSelector,<PUBLIC,NEAR>
+cBegin nogen
+
+ test ds:[bx].dsc_access,DSC_CODEDATA ; code or data dsc?
+ jz crs_exit ; no, skip it
+
+ test ds:[bx].dsc_access,DSC_CODE_BIT ; code?
+ jnz crs_exit ; yes, skip it
+
+ push ax
+ push dx
+ mov dh,ds:[bx].dsc_hbase ; is descriptor base at or
+ mov dl,ds:[bx].dsc_mbase ; above start of ROM?
+ mov ax,ds:[bx].dsc_lbase
+ sub ax,lmaHiROM.off
+ sbb dx,lmaHiROM.sel
+ jc crs_exit1
+
+ sub ax,cbHiROM.off ; make sure it's not above
+ sbb dx,cbHiROM.sel ; the end of the ROM
+ jnc crs_exit1
+
+ and ds:[bx].dsc_access,NOT DSC_RW_BIT ; make it read only
+
+crs_exit1:
+ pop dx
+ pop ax
+
+crs_exit:
+ ret
+
+cEnd nogen
+
+endif ;ROM and KDEBUG
+
+ifdef WOW
+
+
+cProc alloc_special_sel,<PUBLIC,NEAR>,<bx,cx,dx,si,di,ds>
+ parmW AllocFlags
+ parmW SelFreeBlock
+ parmW SizeFreeBlock
+ parmW SizeNewFreeBlock
+ parmW AdjustedSize
+ parmB fBaseAddressToUse
+
+ localD AddressNewFreeBlock
+ localD Address
+ localW Limit
+ localW cFreeBlock
+ localW cTotalSelectors
+ localW EachSelectorLimit
+cBegin
+
+ ;
+ ; this will be our ds
+ ;
+
+ mov ds, gdtdsc
+
+ ;
+ ; replace allocflags with accessword
+ ;
+
+ mov bx, AllocFlags
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:SelAccessWord[bx] ; Pick up access rights for selector
+ mov AllocFlags, ax ; allocflags = access rights
+
+ ;
+ ; Limit for data selectors
+ ;
+
+ mov ax, AdjustedSize
+ dec ax
+ mov Limit, ax
+
+ ;
+ ; compute base address for new freeblock and the first selector
+ ; the base address is dependent on fBaseAddressToUse flag
+ ;
+
+ cCall get_physical_address,<SelFreeBlock>
+
+ cmp fBaseAddressToUse, ga_prev
+ jne @F
+
+ mov bx, SizeNewFreeBlock
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+
+ add ax, bx
+ adc dx, cx
+
+ mov AddressNewFreeBlock.lo, ax
+ mov AddressNewFreeBlock.hi, dx
+
+ ;
+ ; compute base address for first selector
+ ;
+
+ add ax, 10h
+ adc dx, 00h
+
+ mov Address.lo, ax
+ mov Address.hi, dx
+
+ jmps alloc_checkforfreeblock
+@@:
+
+ push ax ; save base address of freeblock
+ push dx
+
+ add ax, 10h
+ adc dx, 00h
+
+ mov Address.lo, ax ; address of first selector
+ mov Address.hi, dx
+
+ pop dx
+ pop ax
+
+ mov bx, AdjustedSize
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+
+ add ax, bx
+ adc dx, cx
+
+ mov AddressNewFreeBlock.lo, ax
+ mov AddressNewFreeBlock.hi, dx
+
+alloc_checkforfreeblock:
+
+ ;
+ ; check if a 'new' free block needs to be created.
+ ; cFreeBlock = (SizeNewFreeBlock) ? 1 : 0;
+ ;
+
+ mov cFreeBlock, 0
+ mov cx, SizeNewFreeBlock
+ jcxz alloc_nofreeblock
+ mov cFreeBlock, 1
+
+alloc_nofreeblock:
+
+
+ ;
+ ; start of processing
+ ;
+
+ mov cx, 1
+ mov ax, AllocFlags
+ test al, DSC_PRESENT
+ jz allocspecial_oneonly
+ ; limit in paras
+ mov cx, Limit ; Calculate how many selectors required
+ add cx, 0FFFh
+ rcr cx, 1 ; 17 bitdom
+ shr cx, 11
+
+allocspecial_oneonly:
+ push cx
+ add cx, cFreeBlock ; cFreeBlock is zero or one
+ mov cTotalSelectors, cx
+
+ ;
+ ; the dpmi func is 04f1h. This is idential to function 00h, except that
+ ; the descriptor base and limit are not initialized to zero.
+ ;
+
+ DPMICALL WOW_DPMIFUNC_00
+ pop cx
+ jnz allocspecial_continue
+ jmp allocspecial_exit
+
+allocspecial_continue:
+
+ push ax ; save the first selector
+ and ax, not SEG_RING
+
+ mov bx, ax ; Selector in bx for DPMI
+
+ mov ax, Address.lo ; Set descriptor base
+ mov [bx].dsc_lbase, ax
+ mov di, ax ; used later
+ mov ax, Address.hi
+ mov [bx].dsc_mbase, al
+ mov [bx].dsc_hbase, ah
+
+ mov ax, AllocFlags
+ test al, DSC_PRESENT ; If selector not present, limit is
+ jnz short allocspecial_present ; as passed, not a paragraph count
+
+allocspecial_not_present:
+
+ mov word ptr [bx].dsc_access, ax
+ mov ax, word ptr Limit
+ mov [bx].dsc_limit, ax
+
+ jmps allocspecial_done
+
+allocspecial_present:
+
+ dec cl
+ and ah, not 0Fh ; Zero limit 19:16
+ or ah, cl ; Fill in limit 19:16
+ inc cl
+ mov word ptr [bx].dsc_access, ax
+ mov si, ax ; save for later use
+ mov ax, Limit
+ shl ax, 4 ; Convert paragraphs to byte limit
+ dec ax
+ mov [bx].dsc_limit, ax
+
+ dec cx
+ jcxz allocspecial_done ; if sel=1 done.
+
+ mov EachSelectorLimit, ax ; ax the limit from above
+ mov al, [bx].dsc_mbase ;
+ mov ah, [bx].dsc_hbase
+ mov dl, [bx].dsc_hlimit
+
+ push ds
+ SetKernelDS
+ test WinFlags, WF_CPU286 ; protect mode on a 286?
+ pop ds
+
+
+ push [bx].dsc_limit ; Save limit for last selector
+ jz allocspecial_next_sel ; the result of the test above
+ mov EachSelectorLimit, 0FFFFh ; Others get 64k limit on 286
+
+allocspecial_next_sel:
+ push ax
+ mov ax, EachSelectorLimit
+ mov [bx].dsc_limit, ax ; limit for current selector
+ pop ax
+
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ cmp cx, 1 ; Last selector?
+ jne allocspecial_fsa_not_last
+ pop [bx].dsc_limit ; yes, get its limit
+
+allocspecial_fsa_not_last:
+ mov [bx].dsc_lbase, di
+ mov word ptr [bx].dsc_access, si
+ inc ax
+ mov [bx].dsc_mbase, al ; Add 64kb to address
+ mov [bx].dsc_hbase, ah
+ dec dl
+ mov [bx].dsc_hlimit, dl ; subtract 64kb from limit
+ loop allocspecial_next_sel
+
+allocspecial_done:
+ cmp cFreeBlock, 1
+ jne allocspecial_nofreeblock
+
+allocspecial_freeblock:
+
+ mov ax, AddressNewFreeBlock.lo ; the base for freeblock
+ mov dx, AddressNewFreeBlock.hi
+
+
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ mov [bx].dsc_limit, 0fh ; = 1 para
+ mov [bx].dsc_lbase, ax
+ mov [bx].dsc_mbase, dl
+ mov [bx].dsc_hbase, dh
+
+ mov ax, DSC_DATA+DSC_PRESENT
+ and ah, not 0Fh ; Zero limit 19:16
+ mov word ptr [bx].dsc_access, ax
+
+allocspecial_nofreeblock:
+
+ pop si ; restore the first selector
+
+ push bx
+ mov cx, cTotalSelectors
+ mov bx, si
+
+ ;
+ ; the dpmi func is 04f2h. This is identical to 0ch except that it
+ ; sets 'count' (in cx) LDTs at one time. The first selector is in
+ ; register bx. The descriptor data is in gdtdsc[bx], gdtdsc[bx+8]
+ ; etc. This data is shared between dpmi (dosx.exe) and us and thus
+ ; need not be passed in es:di
+
+ DPMICALL WOW_DPMIFUNC_0C
+ pop bx
+
+ SetKernelDS
+
+ ;
+ ; sanity check. done so late because if this check was done
+ ; somewhere eariler, we would have had to Save and Restor DS. Since
+ ; this check would be successful most of the time, it is quite Ok
+ ; to do it now and we would avoid unneccessary loading of DS.
+
+ mov ax, bx
+ shr ax, 2
+ cmp ax, SelTableLen ; Make sure we can associate it
+ jb @F
+ xor ax, ax ; set zero flag
+ jmps allocspecial_exit
+
+@@:
+ mov UserSelArray, si ; the selector for user data
+ mov ax, bx
+ or ax, SEG_RING ; selector of new freeblock, if one is
+ ; created. sets nz flag.
+ mov SelectorFreeBlock, ax ;
+allocspecial_exit:
+cEnd
+
+
+;----------------------------------------------------------------------------
+; grabbed from 2gmem.asm
+;
+;----------------------------------------------------------------------------
+
+SelAccessWord dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_CODE+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+
+
+
+;-----------------------------------------------------------------------------
+; Grab the selector 0x47 so that we dont need to special case the biosdata
+; selector (0x40) while converting seg:off address to flat 32bit address
+;
+; This, however should not be part of Krnl286 heap.
+;
+; - Nanduri Ramakrishna
+;-----------------------------------------------------------------------------
+cProc AllocSelector_0x47,<PUBLIC,FAR>, <ax, bx, cx, ds>
+cBegin
+
+ ; alloc the specific selector
+
+ mov bx, 047h
+ DPMICALL 0dh
+ jc as47_exit
+
+ ; initialize the LDT
+
+ and bx, not SEG_RING
+ mov ds, gdtdsc
+ mov [bx].dsc_limit, 00h ; = 1 byte
+ mov [bx].dsc_lbase, 0400h
+ mov [bx].dsc_mbase, 00h
+ mov [bx].dsc_hbase, 00h
+
+ mov ax, DSC_DATA+DSC_PRESENT
+ and ah, not 0Fh ; Zero limit 19:16
+ mov word ptr [bx].dsc_access, ax
+
+ ; set the LDT
+
+ mov cx,1
+ mov bx, 047h
+ DPMICALL WOW_DPMIFUNC_0C
+
+as47_exit:
+cEnd
+sEnd CODE
+
+sBegin NRESCODE
+
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+cProc get_sel_flags,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ ; Not used in krnl286
+ xor ax,ax
+ xor dx,dx
+cEnd
+
+cProc set_sel_for_dib,<PUBLIC,NEAR>
+ parmW selector
+ parmW flags
+ parmD address
+ parmW csel
+cBegin
+ ; Not used in krnl286
+ xor ax,ax
+ xor dx,dx
+cEnd
+
+cProc RestoreDib,<PUBLIC,NEAR>
+ parmW selector
+ parmW flags
+ parmD address
+cBegin
+ ; Not used in krnl286
+ xor ax,ax
+ xor dx,dx
+cEnd
+
+cProc DibRealloc,<PUBLIC,FAR>
+ parmW Selector
+ parmW NewSize
+cBegin
+cEnd
+
+endif
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3gacheck.asm b/private/mvdm/wow16/kernel31/3gacheck.asm
new file mode 100644
index 000000000..66d5c173a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3gacheck.asm
@@ -0,0 +1,199 @@
+
+.xlist
+include kernel.inc
+include protect.inc
+.list
+
+ .386p
+
+DataBegin
+
+externB fBooting
+externW pGlobalHeap
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+
+if KDEBUG
+
+externNP check_lru_list
+externNP check_free_list
+
+externFP ValidateFreeSpaces
+
+
+;-----------------------------------------------------------------------;
+; CheckGlobalHeap ;
+; ;
+; The Global Heap is checked for consistency. First the forward links ;
+; are examined to make sure they lead from the hi_first to the hi_last. ;
+; Then the backward links are checked to make sure they lead from the ;
+; hi_last to the hi_first. Then the arenas are sequentially checked ;
+; to see that the moveable entries point to allocated handles and that ;
+; said handles point back. The handle table is then checked to see ;
+; that the number of used handles match the number of referenced ;
+; handles, and that the number of total handles matches the sum of the ;
+; free, discarded, and used handles. Finally the free list of handles ;
+; is checked. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; CF = 0 everything is just fine ;
+; all registers preserved ;
+; ;
+; Error Returns: ;
+; CF = 1 ;
+; DX = offending arena header ;
+; AX = 01h Forward links invalid ;
+; 02h Backward links invalid ;
+; 04h ga_handle points to free handle ;
+; 08h arena points to handle but not vice versa ;
+; 80h ga_sig is bad ;
+; DX = 0 ;
+; AX = 10h allocated handles don't match used handles ;
+; 20h total number of handles don't match up ;
+; 40h total number of free handles don't match up ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Nov 01, 1986 02:16:46p -by- David N. Weise [davidw] ;
+; Rewrote it from C into assembly. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CheckGlobalHeap,<PUBLIC,NEAR>
+cBegin nogen
+ push eax
+ push edx
+ push ebx
+ push ecx
+ push edi
+ push esi
+ push ds
+ push es
+ push fs
+ push gs
+
+ xor eax,eax
+ xor edx,edx
+ xor edi,edi
+ SetKernelDS es
+ cmp pGlobalHeap,di
+ jnz short there_is_a_GlobalHeap
+ jmp all_done
+there_is_a_GlobalHeap:
+;;; cmp fBooting, 1
+;;; jz no_check
+ mov ds,pGlobalHeap
+;;; UnSetKernelDS
+ cmp [di].hi_check,di
+ jnz short checking_enabled
+no_check:
+;;; jmp all_done
+checking_enabled:
+ mov cx,[di].hi_count
+ mov esi,[di].phi_first
+;;; mov es, dx
+forward_ho:
+
+ push cx
+ mov eax, ds:[esi].pga_address
+ mov ecx, ds:[esi].pga_size
+ cmp ds:[esi].pga_owner, GA_NOT_THERE
+ je short no_limit_check
+ cmp ds:[esi].pga_owner, GA_BURGERMASTER
+ je short no_limit_check
+ cmp ds:[esi].pga_owner, di
+ je short no_limit_check
+ cmp ds:[esi].pga_handle, di
+ je short no_limit_check
+ cmp fBooting, 1
+ je short no_limit_check
+ mov bx, ds:[esi].pga_handle
+ dec ecx
+ Handle_To_Sel bl
+ lsl ebx, ebx
+ jnz short bad_limit
+ cmp ecx, ebx
+ je short ok_limit
+bad_limit:
+int 3
+ok_limit:
+no_limit_check:
+ add eax, ds:[esi].pga_size
+ mov ebx, ds:[esi].pga_next
+ mov edx, ds:[ebx].pga_address
+ cmp eax, edx
+ pop cx
+ xchg esi, ebx
+ jne short forward_size_mismatch
+ cmp ebx, ds:[esi].pga_prev
+ jz short size_and_next_match
+forward_size_mismatch:
+ cmp ds:[esi].pga_owner, GA_NOT_THERE
+ je short size_and_next_match
+ cmp cx,1
+ jnz short forward_links_invalid
+size_and_next_match:
+ loop xxxx
+ cmp ebx,[di].phi_last
+ jz short forward_links_okay
+forward_links_invalid:
+int 3
+ mov edx,ebx
+ mov ax,1
+ jmps all_done
+xxxx:
+ jmp forward_ho
+
+ UnSetKernelDS es
+
+forward_links_okay:
+
+ xor ax, ax
+ call check_lru_list
+ call check_free_list
+; push cs
+; call near ptr ValidateFreeSpaces
+clear_dx_all_done:
+ xor dx,dx
+all_done:
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop esi
+ pop edi
+ pop ecx
+ pop ebx
+ or ax,ax
+ jnz short cgh_error
+ pop edx
+ pop eax
+ ret
+cgh_error:
+ int 3
+ add sp,8
+ stc
+ ret
+cEnd nogen
+
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3galloc.asm b/private/mvdm/wow16/kernel31/3galloc.asm
new file mode 100644
index 000000000..3b93c902a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3galloc.asm
@@ -0,0 +1,1678 @@
+ PAGE ,132
+ TITLE GALLOC - Global memory allocator
+
+.sall
+.xlist
+include kernel.inc
+include protect.inc
+include wowcmpat.inc
+.list
+
+.386
+
+DataBegin
+
+externB Kernel_flags
+externB fCheckFree
+externW pGlobalHeap
+externW Win386_Blocks
+externW FreeArenaCount
+
+gsearch_state_machine dw 0
+gsearch_compact_first dw 0
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP gcompact
+externNP gmovebusy
+externNP gslide
+externNP galign
+ifdef WOW
+externFP MyGetAppWOWCompatFlagsEx
+ ; WOW doesn't decommit pages this way
+else
+externNP gwin386discard
+endif
+externNP GetDPMIFreeSpace
+externNP InnerShrinkHeap
+
+externNP get_physical_address
+externNP set_physical_address
+externNP alloc_arena_header
+externNP free_arena_header
+ifndef WOW_x86
+externNP get_blotto
+endif
+externNP PreallocArena
+externNP DPMIProc
+
+;-----------------------------------------------------------------------;
+; gsearch ;
+; ;
+; Searches from start to finish for a free global object to allocate ;
+; space from. For a fixed request it tries to get the space as low as ;
+; possible, moving movable out of the way if neccessary. For movable ;
+; requests it also starts at the bottom. For discardable code it ;
+; starts from the top, only using the first free block it finds. ;
+; If at first blush it can't find a block it compacts memory and tries ;
+; again. ;
+; When it finally finds a block it gsplices it in, makes sure the ;
+; arena headers are fine, and returns the allocated block. ;
+; Called from within the global memory manager's critical section. ;
+; ;
+; Arguments: ;
+; AX = allocations flags ;
+; EBX = #bytes ;
+; CX = owner field value ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; AX = data address of block allocated or NULL ;
+; BX = ga_prev or ga_next ;
+; DX = allocation flags ;
+; ;
+; Error Returns: ;
+; ZF = 1 ;
+; AX = 0 ;
+; BX = ga_prev or ga_next ;
+; DX = size of largest free block ;
+; ;
+; Registers Preserved: ;
+; DI,DS ;
+; ;
+; Registers Destroyed: ;
+; CX,SI,ES ;
+; ;
+; Calls: ;
+; galign ;
+; gfindfree ;
+; fmovebusy ;
+; gcheckfree ;
+; gcompact ;
+; gsplice ;
+; gzero ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+; ;
+; 19-Aug-95 davehart: Win 3.1 tries to grow the heap before ;
+; compacting it, for WOW we want to compact first to be a good ;
+; multitasking neighbor. ;
+; ;
+; Wed Jul 22, 1987 11:15:19p -by- David N. Weise [davidw] ;
+; Fixed BOGUS BLOCK freeing yet again. ;
+; ;
+; Sun May 10, 1987 11:29:38p -by- David N. Weise [davidw] ;
+; Added the state machine to handle the case of wanting to search ;
+; both global arenas. ;
+; ;
+; Sat Feb 28, 1987 06:31:11p -by- David N. Weise [davidw] ;
+; Putting in support for allocating discardable code from EEMS land. ;
+; ;
+; Tue Dec 30, 1986 01:54:50p -by- David N. Weise [davidw] ;
+; Made sure it freed any bogus blocks created. ;
+; ;
+; Thu Nov 20, 1986 04:00:06p -by- David N. Weise [davidw] ;
+; Rewrote it use the global free list. Also made it put fixed requests ;
+; as low as possible and to search again after a compact. ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Tue Sep 23, 1986 04:35:39p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gsearch,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS fs
+ ReSetKernelDS fs
+
+ cmp word ptr [di].gi_free_count, 96
+ jae short compact_first
+ mov gsearch_compact_first, 0
+ mov gsearch_state_machine,codeOFFSET grow_heap
+ jmp short look_again
+
+compact_first:
+ mov gsearch_compact_first, 1
+ mov gsearch_state_machine,codeOFFSET do_compact_nodiscard
+
+look_again:
+ push ebx ; Save requested size
+ push cx ; Save owner
+ push ax ; Save flags
+ clc ; Instead of add
+ call galign ; Get requested size in EDX
+ push edx ; Save adjusted requested size
+
+; see if there is any one free space large enough for the request first
+
+ mov cx,[di].gi_free_count
+ jcxz were_hosed_from_start
+ mov esi,[di].phi_first
+is_there_one:
+ mov esi,ds:[esi].pga_freenext
+ cmp edx,ds:[esi].pga_size
+ jbe short got_one
+ loop is_there_one
+were_hosed_from_start:
+ jmp space_not_found
+
+got_one:
+ mov ebx,pga_prev ; search backwards
+ test al,GA_ALLOCHIGH
+ jz short alloc_low
+
+;------ allocate disc code -------
+
+ public alloc_high
+alloc_high:
+ mov cx,[di].gi_free_count
+ mov esi,[di].phi_last ; Start with last entry.
+alloc_high_loop:
+ mov esi,ds:[esi].pga_freeprev
+ cmp edx,ds:[esi].pga_size
+ jbe afound ; Yes, exit search loop
+ loop alloc_high_loop
+ jmp space_not_found
+
+
+;------ allocate moveable ---------
+
+ public alloc_low
+alloc_low:
+ mov ebx,pga_next ; Search forwards.
+ test al,GA_MOVEABLE
+ jz short alloc_fixed
+ call gcheckfree ; Room for requested size?
+ jb short space_not_found
+ jmp afound
+
+;------ allocate fixed ------------
+
+ public alloc_fixed
+alloc_fixed:
+ mov esi,[di].phi_first ; Start with first entry.
+ mov cx,[di].hi_count
+ mov esi,ds:[esi+ebx] ; Skip first sentinel
+alloc_fixed_loop:
+ push cx
+ push esi
+ call is_there_theoretically_enough_space
+ cmp eax,edx
+ jb short nope
+ pop esi
+ pop cx
+ call can_we_clear_this_space
+ jz short anext1
+ call gcheckfree ; Yes, room for requested size?
+ jb short anext1
+ ; Now we have enough free space,
+ ; slide it back as far as possible.
+ push eax ; This is to prevent us blocking
+ push edx ; the growth of moveable blocks.
+ push ebx ; AND to keep pagelocked code together
+ call PreallocArena
+ jz short no_sliding
+
+ mov ebx, pga_prev ; Sliding backwards
+keep_sliding:
+ call gslide
+ jnz keep_sliding
+
+no_sliding:
+ pop ebx
+ pop edx
+ pop eax
+
+ pop edx
+ pop cx
+ test ch, GA_ALLOC_DOS
+ push cx
+ push edx
+ jz afound
+ cmp ds:[esi].pga_address, 100000h ; > 1Mb?
+ jb afound
+ jmp gsearch_fail
+
+nope:
+ or eax,eax
+ jz short hosed_again
+anext:
+ add sp, 6 ; get rid of CX, ESI on the stack
+anext1:
+ mov esi,ds:[esi+ebx]
+ loop alloc_fixed_loop
+ jmps and_again
+
+hosed_again:
+ pop esi
+ pop cx
+and_again:
+
+; no one space big enough, try compacting
+
+ public space_not_found
+space_not_found:
+ pop edx ; get adjusted size
+ pop ax ; get flags
+ push ax
+ push edx
+; test al,GA_ALLOCHIGH
+; jnz short ask_for_what_we_need
+; add edx,0400h ; ask for 1k more
+; jnc short ask_for_what_we_need ; no overflow
+; mov edx,-1
+ask_for_what_we_need:
+
+ jmp gsearch_state_machine
+
+;------------------------------
+
+public do_compact_nodiscard ; for debugging
+
+do_compact_nodiscard:
+ mov gsearch_state_machine,codeOFFSET grow_heap
+
+ ;
+ ; Before growing the heap try compacting without
+ ; discarding. This step isn't executed unless there
+ ; were 96 or more free blocks at entry to gsearch.
+ ;
+
+ test ds:[di].gi_cmpflags, GA_NODISCARD
+ jnz short dcn_nodiscard
+
+ or ds:[di].gi_cmpflags, GA_NODISCARD
+ call gcompact
+ and ds:[di].gi_cmpflags, NOT GA_NODISCARD
+ jmp short over_compact
+
+dcn_nodiscard:
+ call gcompact
+ jmp short over_compact
+
+
+public do_compact ; for debugging
+
+do_compact:
+ mov gsearch_state_machine,codeOFFSET gsearch_fail
+
+ ;
+ ; If we tried compacting before and GA_NODISCARD was set,
+ ; there is no need to compact again, since we already
+ ; compacted with GA_NODISCARD before attempting to
+ ; grow the heap. If GA_NODISCARD was not set, our earlier
+ ; compact forced it on, so it's worth trying again since
+ ; we may be able to discard enough to satisfy the request.
+ ;
+
+ cmp gsearch_compact_first, 0
+ je short @f
+ test ds:[di].gi_cmpflags, GA_NODISCARD
+ jnz short gsearch_fail
+
+@@:
+ call gcompact
+
+over_compact:
+ pop edx
+ pop ax
+ pop cx
+ pop ebx
+ jmp look_again
+
+public grow_heap ; for debugging
+
+grow_heap:
+ mov gsearch_state_machine,codeOFFSET do_compact
+
+ push edx ; can we get the space from DPMI?
+ call GrowHeap
+ pop edx
+ jnc short over_compact ; heap grew, go look again
+
+ call InnerShrinkHeap ; try to give back DPMI blocks so DPMI
+ ; mmgr can defragment its memory
+ jz short do_compact ; heap did not shrink
+
+ push edx ; gave some back, try to get it again
+ call GrowHeap
+ pop edx
+ jnc short over_compact ; heap grew, go look again
+doomed:
+
+;------------------------------
+
+public gsearch_fail ; for debugging
+
+gsearch_fail: ; get size of largest free block
+ .errnz doomed-gsearch_fail
+ xor edx,edx
+ mov cx,[di].gi_free_count
+ jcxz gs_failure
+ mov esi,[di].phi_first
+largest_loop:
+ mov esi,ds:[esi].pga_freenext
+ mov eax,ds:[esi].pga_size
+ cmp edx,eax
+ jae short new_smaller
+ mov edx,eax
+new_smaller:
+ loop largest_loop
+gs_failure:
+ pop eax ; adjusted requested size
+ pop ax ; AX = flags
+
+ pop cx ; CX = owner field
+ pop eax ; waste requested size
+ xor eax,eax ; Return zero, with ZF = 1
+ ret
+
+; Here when we have a block big enough.
+; ES:DI = address of block
+; AX = size of block, including header
+; DX = requested size, including header
+; BX = ga_prev if backwards search and ga_next if forwards search
+
+afound:
+ mov ecx,ds:[esi].pga_size ; Use actual size of free block
+ sub ecx,edx ; (found size - requested size)
+ jecxz no_arena_needed
+ call PreallocArena
+ jnz short no_arena_needed
+
+;
+; Detect infinite loop here. If we are out of arenas, and
+; the compact failed once, then another one isn't going to do much
+; good.
+;
+ cmp gsearch_state_machine,codeOFFSET gsearch_fail
+ je gsearch_fail
+
+ pop edx ; get adjusted size
+ pop ax ; get flags
+ push ax
+ push edx
+ and ds:[di].gi_cmpflags, NOT (GA_NODISCARD+GA_NOCOMPACT)
+ or ds:[di].gi_cmpflags, COMPACT_ALLOC
+ mov edx, -1 ; Discard the world!
+ jmp do_compact
+
+no_arena_needed:
+ mov eax,ds:[esi].pga_freeprev
+ call gdel_free ; remove the alloc block from freelist
+ jecxz aexitx
+ cmp bl,pga_prev ; Yes, scanning forwards or backwards?
+ je short abackward ; Backwards.
+ call gsplice ; FS:ESI = block we are allocating
+ jmps aexit ; EDX = block to mark as free
+abackward:
+ neg edx
+ add edx,ds:[esi].pga_size ; Scanning backwards. Put extra space
+ call gsplice
+ xchg edx, esi
+ jmps aexit
+
+; Here with allocated block
+; AX = data address or zero if nothing allocated
+; ES:DI = address of block to mark as busy and zero init if requested
+; EDX = address of block to mark as free
+
+aexitx:
+ xor edx,edx ; Assume nothing extra to free
+aexit:
+ pop ecx ; waste adjusted requested size
+ pop cx ; Restore flags
+ pop ds:[esi].pga_owner ; Mark block as busy with owner field value
+ add sp, 4 ; waste requested size
+ mov ds:[esi].pga_lruprev,edi
+ mov ds:[esi].pga_lrunext,edi
+
+ push esi
+ mov esi, edx ; Free any extra space
+ mov edx, eax ; Previous free block
+ call gmarkfree
+ pop esi
+
+ mov dx, cx
+ mov al,GA_SEGTYPE
+ and al,dl
+ test dh,GAH_NOTIFY
+ jz short no_notify
+ or al,GAH_NOTIFY
+no_notify:
+ mov ds:[esi].pga_flags,al ; Store segment type bits
+ mov eax,esi ; AX = address of client data
+
+ test cl,GA_ZEROINIT ; Want it zeroed?
+ jz short aexit1 ; No, all done
+
+ push eax
+ifdef WOW_x86
+;; On NT we try never to set selectors when we don't need to since it is a
+;; slow operation - a system call. In this case we can use selector 23h
+;; which points to all flat vdm memory as data
+ push es
+ push bx
+ push edi
+
+ mov bx,FLAT_SEL
+ mov es,bx
+
+ mov ecx,ds:[esi].pga_size ; Yes, zero paragraphs
+ push ecx
+
+ shr ecx, 2 ; # dwords to clear
+ mov edi, ds:[esi].pga_address
+ xor eax, eax
+
+ cld
+ rep stos dword ptr es:[edi]
+
+ pop ecx
+ pop edi
+ pop bx
+ pop es
+else
+ cCall get_blotto
+ mov ecx,ds:[esi].pga_size ; Yes, zero paragraphs
+ push bx
+ mov bx,ax ; from beginning of client data
+ call gzero ; zero them
+ pop bx
+endif; WOW_x86
+ pop eax
+aexit1:
+
+ or eax,eax
+ ret ; Return AX points to client portion
+ UnSetKernelDS FS ; of block allocated.
+cEnd nogen
+
+cProc GrowHeap,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS FS
+ ReSetKernelDS fs
+ cmp FreeArenaCount, 4 ; 3 for below, 1 for a gsplice later
+ jb short gh_fail
+
+ pushad
+ push edx ; Save requested size
+ ; If they want more than 64k, assume they
+ ; want a big block and just allocate that amount.
+ cmp edx, 64*1024 ; Want more than 64k?
+ jae short ask_for_it ; yes, just round up
+ mov edx, 128*1024 ; no, try for 128k
+ask_for_it:
+ mov ebx, edx
+ add ebx, 4096-1 ; Round up to 4k multiple
+ and bx, NOT (4096-1)
+
+ cCall MyGetAppWOWCompatFlagsEx ; check if we need to pad it
+ test ax, WOWCFEX_BROKENFLATPOINTER
+ jz short @f
+ add ebx, 4096*4 ; make it a bit bigger
+@@:
+
+ push ebx ; Length we will ask for
+ mov cx, bx
+ shr ebx, 16
+ DPMICALL 0501h ; Allocate Memory Block
+ ; Get our memory
+ jnc short got_more_memory
+ pop ebx ; Toss length we asked for
+
+ ; Couldn't get our 1st choice, how
+ call GetDPMIFreeSpace ; much is available
+ mov ebx, eax ; ebx = largest available
+
+ pop edx ; Requested size
+ cmp ebx, edx ; Enough for request?
+ jbe SHORT gh_fail_pop
+
+ push edx ; Expected on stack below
+ push ebx ; Length we will ask for
+ mov cx, bx
+ shr ebx, 16
+ DPMICALL 0501h ; Allocate Memory Block
+ ; Get our memory
+ jnc short got_more_memory
+ add sp, 8 ; Toss requested size & len asked for
+
+gh_fail_pop:
+ popad
+gh_fail:
+ stc ; No chance mate!
+ ret
+ ; Now we have a new block
+ ; Sort it in to the heap
+ ; Create NOT THERE blocks to
+got_more_memory: ; bracket the new block
+ inc Win386_Blocks
+ pop edx ; Length of block allocated
+if KDEBUG
+ mov eax, edx
+ shr eax, 16
+ krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "GrowHeap: #ax#DX allocated"
+endif
+ shl ebx, 16
+ mov bx, cx ; EBX has linear address
+ pop ecx ; Toss original length
+ shl esi, 16
+ mov si, di ; ESI has WIN386 handle
+ xor edi, edi
+ cCall alloc_arena_header,<ebx>
+ mov ecx, eax ; First not there arena
+ mov [ecx].pga_size, edi
+ mov [ecx].pga_sig, GA_SIGNATURE
+ mov [ecx].pga_owner, GA_NOT_THERE
+ mov [ecx].pga_handle, di
+ mov [ecx].pga_flags, di
+ mov [ecx].pga_lrunext, esi ; Save WIN386 handle here
+ mov [ecx].pga_lruprev, edi
+ cCall alloc_arena_header,<ebx>
+ mov [eax].pga_size, edx ; Free block
+ push ebx ; Save address
+ add edx, ebx ; Address of end of block
+ mov ebx, eax
+ mov [ecx].pga_next, ebx
+ mov [ebx].pga_prev, ecx
+ mov [ebx].pga_owner, di
+ cCall alloc_arena_header,<edx>
+ mov edx, eax
+ mov [ebx].pga_next, edx
+ mov [edx].pga_prev, ebx
+ mov [edx].pga_size, edi
+ mov [edx].pga_owner, GA_NOT_THERE
+ mov [edx].pga_handle, di
+ mov [edx].pga_flags, di
+ mov [edx].pga_sig, GA_SIGNATURE
+ mov [edx].pga_lrunext, edi
+ mov [edx].pga_lruprev, edi
+
+ pop eax ; Address of block
+sort_it:
+ mov esi, [edi].phi_first
+ cmp eax, [esi].pga_address ; Below start of heap?
+ ja short sort_loop ; no, sort it in
+; int 3 ; [this code never reached]
+ mov [esi].pga_address, eax ; yes, adjust sentinel
+ jmps link_it_in ; Sentinel now points to new block
+
+sort_loop:
+ mov esi, [esi].pga_next
+ cmp [esi].pga_next, esi ; At end?
+ je short sort_found ; yes, put here
+ cmp [esi].pga_owner, GA_NOT_THERE
+ jne short sort_loop
+ mov esi, [esi].pga_prev ; Will go after previous block.
+
+sort_found: ; Block will go after ESI
+ cmp [esi].pga_next, esi ; This the sentinel?
+ jne short link_it_in ; no, link it in
+ mov eax, [edx].pga_address ; yes, adjust sentinel
+ mov [esi].pga_address, eax
+ sub eax, [di].gi_reserve ; Adjust fence
+ mov [di].gi_disfence_lo, ax
+ shr eax, 16
+ mov [di].gi_disfence_hi, ax
+ mov esi, [esi].pga_prev ; New block goes before sentinel
+
+link_it_in: ; Link it in after ESI
+ mov [ecx].pga_prev, esi
+ xchg [esi].pga_next, ecx
+ mov [edx].pga_next, ecx
+ mov [ecx].pga_prev, edx
+
+ add [di].hi_count, 3 ; Three more entries in heap
+ mov esi, ebx
+ xor edx, edx
+ call gmarkfree ; To be picked up next time around
+ popad
+ clc
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+
+; Input - DWORD - Old Arena offset from burgermaster
+;
+; Output - None
+
+cProc FreeHeapDib,<PUBLIC,FAR>
+ parmD OldArena
+cBegin
+ CheckKernelDS FS
+ ReSetKernelDS fs
+
+ ; Make sure arena before and after are GA_NOT_THERE
+ mov ebx,OldArena
+ mov edx,ds:[ebx].pga_prev
+ cmp ds:[edx].pga_owner,GA_NOT_THERE
+ jne short fhd5
+ mov ecx,ds:[ebx].pga_next
+ cmp ds:[ecx].pga_owner,GA_NOT_THERE
+ je short fhd7
+fhd5:
+if KDEBUG
+ krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "FreeHeapDIB: Corrupt DIB Block"
+endif
+fhd7:
+ ;Free all the three arenas. First fixup the arena list.
+ ; edx - First GA_NOT_THERE arena
+ ; ebx - Actual DIB arean
+ ; ecx - Last GA_NOT_THERE arena
+
+ mov eax,ds:[edx].pga_prev
+ mov ebx,ds:[ecx].pga_next
+ mov ds:[eax].pga_next,ebx
+ mov ds:[ebx].pga_prev,eax
+
+
+ mov ds:[edx].pga_handle,0
+ cCall free_arena_header,<edx>
+
+ mov ds:[ecx].pga_handle,0
+ cCall free_arena_header,<ecx>
+
+ mov edx,OldArena
+ mov ds:[edx].pga_handle,0
+ cCall free_arena_header,<edx>
+
+ xor di,di
+ sub [di].hi_count, 3 ; Three less entries in heap
+ dec Win386_Blocks
+ UnSetKernelDS FS
+cEnd
+
+; Input - DWORD - Dib Address
+; DWORD - Old Arena offset from burgermaster
+;
+; Output - eax = new arena if operation successful
+; eax = NULL if operation failed
+
+cProc GrowHeapDib,<PUBLIC,FAR>
+ parmD OldArena
+ parmD NewAddress
+cBegin
+ CheckKernelDS FS
+ ReSetKernelDS fs
+ cmp FreeArenaCount, 4 ; 3 for below, 1 for a gsplice later
+ jae short ghd_start
+ xor eax,eax
+ ret
+
+ ; Now we have a new block. Sort it in to the heap. Create
+ ; NOT THERE blocks as well.
+
+ghd_start:
+ inc Win386_Blocks
+ mov ebx,OldArena
+ mov edx,ds:[ebx].pga_size ; Length of block
+if KDEBUG
+ mov eax, edx
+ shr eax, 16
+ krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "GrowHeapDIB: #ax#DX allocated"
+endif
+ mov ebx,NewAddress ; Ebx is the address of new block
+ mov esi, ebx ; ESI has WIN386 handle
+ xor edi, edi
+ cCall alloc_arena_header,<ebx>
+ mov ecx, eax ; First not there arena
+ mov [ecx].pga_size, edi
+ mov [ecx].pga_sig, GA_SIGNATURE
+ mov [ecx].pga_owner, GA_NOT_THERE
+ mov [ecx].pga_handle, di
+ mov [ecx].pga_flags, di
+ mov [ecx].pga_lrunext, esi ; Save WIN386 handle here
+ mov [ecx].pga_lruprev, edi
+ cCall alloc_arena_header,<ebx>
+ mov [eax].pga_size, edx ; DIB block
+ push ebx ; Save address
+ add edx, ebx ; Address of end of block
+ mov ebx, eax
+ mov [ecx].pga_next, ebx
+ mov [ebx].pga_prev, ecx
+ push ecx
+ mov ecx,OldArena
+ mov ax, [ecx].pga_handle
+ mov [ebx].pga_handle,ax
+ mov ax, [ecx].pga_owner
+ mov [ebx].pga_owner,ax
+ mov al, [ecx].pga_count
+ mov [ebx].pga_count,al
+ inc [ebx].pga_count ; make sure it doesn't move
+ mov al, [ecx].pga_pglock
+ mov [ebx].pga_pglock,al
+ mov al, [ecx].pga_flags
+ mov [ebx].pga_flags,al
+ mov al, [ecx].pga_selcount
+ mov [ebx].pga_selcount,al
+ mov [ebx].pga_lrunext, edi
+ mov [ebx].pga_lruprev, edi
+ pop ecx
+ cCall alloc_arena_header,<edx>
+ mov edx, eax
+ mov [ebx].pga_next, edx
+ mov [edx].pga_prev, ebx
+ mov [edx].pga_size, edi
+ mov [edx].pga_owner, GA_NOT_THERE
+ mov [edx].pga_handle, di
+ mov [edx].pga_flags, di
+ mov [edx].pga_sig, GA_SIGNATURE
+ mov [edx].pga_lrunext, edi
+ mov [edx].pga_lruprev, edi
+
+ pop eax ; Address of block
+ mov esi, [edi].phi_first
+ cmp eax, [esi].pga_address ; Below start of heap?
+ ja short ghd_sort_loop ; no, sort it in
+; int 3 ; [this code never reached]
+ mov [esi].pga_address, eax ; yes, adjust sentinel
+ jmps ghd_link_it_in ; Sentinel now points to new block
+
+ghd_sort_loop:
+ mov esi, [esi].pga_next
+ cmp [esi].pga_next, esi ; At end?
+ je short ghd_sort_found ; yes, put here
+ cmp [esi].pga_owner, GA_NOT_THERE
+ jne short ghd_sort_loop
+ mov esi, [esi].pga_prev ; Will go after previous block.
+
+ghd_sort_found: ; Block will go after ESI
+ cmp [esi].pga_next, esi ; This the sentinel?
+ jne short ghd_link_it_in ; no, link it in
+ mov eax, [edx].pga_address ; yes, adjust sentinel
+ mov [esi].pga_address, eax
+ sub eax, [di].gi_reserve ; Adjust fence
+ mov [di].gi_disfence_lo, ax
+ shr eax, 16
+ mov [di].gi_disfence_hi, ax
+ mov esi, [esi].pga_prev ; New block goes before sentinel
+
+ghd_link_it_in: ; Link it in after ESI
+ mov [ecx].pga_prev, esi
+ xchg [esi].pga_next, ecx
+ mov [edx].pga_next, ecx
+ mov [ecx].pga_prev, edx
+
+ add [di].hi_count, 3 ; Three more entries in heap
+ mov eax,ebx
+ UnSetKernelDS FS
+cEnd
+
+;-----------------------------------------------------------------------;
+; is_there_theoretically_enough_space
+;
+; Starting at the given arena checks to see if there are enough
+; continuous free and unlocked moveable blocks.
+;
+; Entry:
+; CX = arenas to search
+; EDX = size requested
+; DS = BurgerMaster
+; FS:ESI = arena to start from
+;
+; Returns:
+; EAX = 0 => not enough space and no more memory left to search
+; EAX = 1 => not enough space in this block, but maybe....
+; otherwise
+; EAX = size of block
+;
+; Registers Destroyed:
+; CX,ESI
+;
+; Registers Preserved:
+; BX,DX,DI,ES
+;
+; History:
+; Mon 05-Sep-1988 15:21:14 -by- David N. Weise [davidw]
+; Moved it here from gsearch so that grealloc could use it as well.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc is_there_theoretically_enough_space,<PUBLIC,NEAR>
+cBegin nogen
+
+ xor eax,eax
+ittes:
+ cmp ds:[esi].pga_owner,di
+ jne short is_it_moveable
+ add eax,ds:[esi].pga_size
+ push ebx
+ push eax
+ mov bx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
+ shl ebx, 16
+ mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
+ mov eax, ds:[esi].pga_address
+ add eax, ds:[esi].pga_size ; Address of end of free block
+ sub eax,ebx
+ ja short ittes_above_fence ; All below fence?
+ittes_below_fence:
+ pop eax ; yes, we can use it
+ pop ebx
+ jmps this_ones_free
+
+ittes_above_fence:
+ cmp eax, ds:[di].gi_reserve
+ jae ittes_below_fence
+ mov ebx, eax ; portion above the fence
+ pop eax ; Total size so far
+ sub eax,ebx ; No, Reduce apparent size of free block
+ pop ebx
+ cmp eax,edx
+ jae short theoretically_enough
+ jmps absolutely_not
+
+is_it_moveable:
+ cmp ds:[esi].pga_owner,GA_NOT_THERE ; Against end of heap partition?
+ je short theoretically_not ; no room here.
+ test ds:[esi].pga_handle,GA_FIXED ; See if movable.
+ jnz short theoretically_not
+ cmp ds:[esi].pga_count,0
+ jne short theoretically_not ; See if locked.
+ add eax,ds:[esi].pga_size
+this_ones_free:
+ cmp eax,edx
+ jae short theoretically_enough
+ mov esi,ds:[esi].pga_next
+ loop ittes
+
+; For the case of gsearch we should never get here for two reasons.
+; 1) It should be impossible to have no discardable code loaded, in
+; this case we would have failed in the above loop. 2) We checked
+; at the very start for a free block somewhere that could have
+; satisfied the request. In our mucking around to load as low as
+; possible we destroyed this free block and we did not produce a free
+; block we could use. However we know from debugging code in 2.03
+; that this happens extremely rarely. Because of the rareness of
+; this event we will not try to recover, instead we simply fail the call.
+
+absolutely_not:
+ mov eax,-1 ; return EAX = 0
+theoretically_not:
+ inc eax ; DX is even, => cmp the same.
+theoretically_enough:
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; can_we_clear_this_space
+;
+; Attempts to make a free space starting at the address moved in.
+; To do this it moves moveable out of the area. The only subtlety
+; involves a free block that stradles the end of wanted area. This
+; may get broken into two pieces, the lower piece gets temporary marked
+; as allocated and BOGUS, the upper piece will remain free.
+;
+; Entry:
+; CX = max number of blocks to look at
+; EDX = size wanted in bytes
+; DS = BurgerMaster
+; FS:ESI = beginning arena
+;
+; Returns:
+; ZF = 0
+; FS:ESI points to free space
+; ZF = 1
+; couldn't free the space up
+;
+; Registers Destroyed:
+; AX,SI
+;
+; History:
+; Mon 05-Sep-1988 16:48:31 -by- David N. Weise [davidw]
+; Moved it out of gsearch so that grealloc could use it.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc can_we_clear_this_space,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS FS
+ ReSetKernelDS FS
+
+ push ecx
+ push esi
+ cmp di,[di].gi_free_count ; any free blocks?
+ jz short cwcts_fail
+ mov eax, esi ; Beginning of space we want.
+ cmp di,ds:[esi].pga_owner ; Is it free?
+ jnz short can_we_move_it
+ mov ecx,edx
+ cmp ecx,ds:[esi].pga_size
+ ja short asdf
+ or eax,eax ; return ZF = 0
+cwcts_fail:
+ pop esi
+ pop ecx
+ ret
+
+asdf: mov esi,ds:[esi].pga_next
+
+ public can_we_move_it
+can_we_move_it:
+ push ebx
+ push ecx
+ push edx
+ push esi
+ cmp ds:[esi].pga_owner,GA_BOGUS_BLOCK
+ jnz short not_bogus
+ xor edx,edx
+ call gmarkfree
+ jmp restart
+not_bogus:
+ mov ebx, ds:[eax].pga_address
+ add ebx, edx ; EBX is the end of the space we want
+ mov cx,[di].gi_free_count
+ mov edx,ds:[esi].pga_size ; Yes, try to find a place for the
+ mov esi,[di].phi_first ; moveable block
+look_loop:
+ call PreAllocArena ; Needed for gmovebusy or gsplice
+ jz couldnt_clear_it
+ mov esi,ds:[esi].pga_freenext
+ push esi
+ mov esi, ds:[esi].pga_address
+ cmp esi, ds:[eax].pga_address ; It defeats our purpose to move the
+ jb short check_this_out ; block to a free space we want.
+ cmp esi, ebx
+ jb short is_there_hope
+check_this_out:
+ pop esi
+ push eax
+ call gcheckfree
+ push ecx
+ jb short inopportune_free_space
+ pop ecx
+ pop eax
+
+ pop edx ; EDX = moveable block for gmovebusy
+ mov ebx,pga_next
+ call gmovebusy ; Move moveable block out of the way
+ mov esi,edx ; Replace the ESI on the stack,
+ ; the free block may have grown
+ ; downward with the gmovebusy.
+ pop edx
+ pop ecx
+ pop ebx
+ pop ecx ; WAS pop esi but esi set above now
+ pop ecx
+ jmp can_we_clear_this_space
+
+inopportune_free_space:
+ pop ecx
+ pop eax
+ loop look_loop
+ jmps couldnt_clear_it
+
+ public is_there_hope
+is_there_hope:
+ pop esi
+ push eax
+ push ecx
+
+ mov ecx, ds:[esi].pga_address
+ add ecx, ds:[esi].pga_size ; ECX end of block
+
+ mov ax, [di].gi_disfence_hi
+ shl eax, 16
+ mov ax, [di].gi_disfence_lo ; EAX == fence
+
+ sub eax, ecx ; Fence - End
+ jae short below_reserved ; Block is below fence
+ neg eax ; End - Fence
+ cmp eax, ds:[di].gi_reserve
+ jae short below_reserved ; Block is above reserved
+ sub ecx, eax ; End - (End - Fence)
+ ; Gives Fence in ECX
+below_reserved:
+ sub ecx, ebx ; Adjust size of free block
+ jbe inopportune_free_space ; No room here
+
+overlap:
+ cmp ecx,edx ; Is it big enough?
+ jbe short inopportune_free_space
+
+ mov edx, ebx
+ sub edx, ds:[esi].pga_address ; Calculate overlap
+
+ pop ecx
+ pop eax
+
+; cut off the first piece for the original alloc
+
+ push ds:[esi].pga_freeprev
+ call gdel_free
+ call gsplice
+
+; DS:ESI = addr of block to mark as busy, FS:EDX = addr of block to mark as free
+
+ mov ds:[esi].pga_owner,GA_BOGUS_BLOCK
+ mov ds:[esi].pga_lruprev,edi
+ mov ds:[esi].pga_lrunext,edi
+ mov esi, edx
+ pop edx ; previous free block
+ call gmarkfree ; Free any extra space
+restart:
+ pop edx ; WAS pop es
+ pop edx
+ pop ecx
+ pop ebx
+ pop esi
+ pop ecx
+ jmp can_we_clear_this_space
+
+; If here then failure! see if we made a bogus block!
+
+couldnt_clear_it:
+ pop esi ; recover block we wanted moved
+check_again:
+ mov edx,ds:[esi].pga_next
+ cmp edx, ds:[edx].pga_next ; At end of arenas?
+ je short no_bogus_block ; Yes, let's go
+ cmp ds:[edx].pga_address, ebx ; EBX points to where bogus block
+ ja short no_bogus_block ; would be.
+ je short is_it_bogus
+ mov esi,edx
+ jmps check_again
+is_it_bogus:
+ cmp ds:[esi].pga_owner,GA_BOGUS_BLOCK
+ jnz short no_bogus_block
+ xor edx,edx
+ call gmarkfree
+no_bogus_block:
+
+if KDEBUG
+ mov cx,[di].hi_count
+ mov esi,[di].phi_first
+bogus_all:
+ cmp ds:[esi].pga_owner,GA_BOGUS_BLOCK
+ jnz short not_me
+ int 3
+not_me: mov esi,ds:[esi].pga_next
+ loop bogus_all
+endif
+ pop edx
+ pop ecx
+ pop ebx
+ pop esi
+ pop ecx
+ xor eax,eax ; return ZF = 1
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; gcheckfree ;
+; ;
+; Checks the size of the passed free block against the passed desired ;
+; size, making sure that the limitations of the code reserve area are ;
+; not violated for objects other than discardable code. It also checks ;
+; for Phantoms. ;
+; ;
+; Arguments: ;
+; FS:ESI = address of free block ;
+; DX = #bytes needed ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; CF = 0 block big enough ;
+; EAX = apparent size of free block ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Thu 27-Apr-1989 10:38:05 -by- David N. Weise [davidw] ;
+; Fixed this to work in pmode. ;
+; ;
+; Thu Apr 02, 1987 10:45:22p -by- David N. Weise [davidw] ;
+; Added Phantom support. ;
+; ;
+; Tue Sep 23, 1986 05:54:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gcheckfree,<PUBLIC,NEAR>
+cBegin nogen
+ mov eax,ds:[esi].pga_size ; Compute size of free block
+ test byte ptr [di].gi_cmpflags,GA_DISCCODE
+ jnz short gcftest ; Discardable code not restricted
+
+ push ebx
+ mov ebx, [di].phi_last ; Last sentinel
+ mov ebx, ds:[ebx].pga_address
+ cmp ebx, ds:[esi].pga_address ; Above sentinel?
+ jbe short gcftest1 ; yes, not in reserved area!
+
+ push eax
+ mov bx,word ptr [di].gi_disfence_hi ; See if begin of reserve area
+ shl ebx, 16
+ mov bx,word ptr [di].gi_disfence_lo ; is above end of free block
+ add eax, ds:[esi].pga_address ; EAX address of end of block
+ sub ebx, eax
+ pop eax
+ jae short gcftest1 ; Yes, return actual size of free block
+ neg ebx
+ sub eax,ebx ; No, Reduce apparent size of free block
+ ja short gcftest1 ; Is it more than what is free?
+
+ xor eax,eax ; Yes, then apparent size is zero
+ ; Nothing left, set apparent size to 0
+gcftest1:
+ pop ebx
+ jmps gcftest
+gcfrsrv1: ; Yes, then apparent size is zero
+ xor eax,eax ; Nothing left, set apparent size to 0
+gcftest:
+ cmp eax,edx ; Return results of the comparison
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gsplice [should be named gslice, ;
+; since splice means combine two into one - donc] ;
+; ;
+; Splits one block into two. ;
+; ;
+; Arguments: ;
+; EDX = size in bytes of new block to make ;
+; DS:ESI = address of existing block ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; EDX = address of new block
+; ;
+; Error Returns: ;
+; nothing ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,DI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Tue Sep 23, 1986 03:50:30p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gsplice,<PUBLIC,NEAR>,<EAX,EBX>
+cBegin
+
+ mov ebx,ds:[esi].pga_size
+ sub ebx,edx ; get size of 2nd new block made
+ mov eax, ds:[esi].pga_address
+ add eax, edx
+ cCall alloc_arena_header,<eax>
+
+ inc [di].hi_count ; Adding new arena entry
+ mov ecx, eax
+ xchg ds:[esi].pga_next,ecx ; and old.next = new
+ mov ds:[ecx].pga_prev,eax ; [old old.next].prev = new
+
+ mov ds:[eax].pga_next,ecx ; new.next = old old.next
+ mov ds:[eax].pga_prev,esi
+
+ mov ds:[eax].pga_size,ebx
+ mov ds:[eax].pga_sig,GA_SIGNATURE
+ mov ds:[eax].pga_owner,di ; Zero owner & handle fields
+ mov ds:[eax].pga_flags,0 ; For good measure.
+ mov ds:[eax].pga_handle,di
+
+ mov ds:[esi].pga_size,edx
+
+ mov edx, eax
+gsplice_ret:
+cEnd
+
+;-----------------------------------------------------------------------;
+; gjoin ;
+; ;
+; Merges a block into his previous neighbor. ;
+; ;
+; Arguments: ;
+; FS:ESI = address of block to remove ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; nothing ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; gdel_free ;
+; ;
+; History: ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Tue Sep 23, 1986 03:58:00p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gjoin,<PUBLIC,NEAR>
+cBegin nogen
+if KDEBUG
+ cmp esi, ds:[esi].pga_prev
+ jne short ok
+int 3
+int 3
+ok:
+endif
+ push eax ; assumes one is on freelist
+ push edx
+ dec [di].hi_count
+ call gdel_free
+ mov eax,ds:[esi].pga_size
+ mov edx,ds:[esi].pga_next ; Get address of block after
+ mov esi,ds:[esi].pga_prev ; Get address of block before
+ cCall free_arena_header,<ds:[edx].pga_prev> ; Free arena being removed
+ mov ds:[edx].pga_prev,esi ; Fix up block after
+ mov ds:[esi].pga_next, edx ; and the one before
+ add ds:[esi].pga_size,eax ; Recompute size of block
+ pop edx
+ pop eax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gzero ;
+; ;
+; Fills the given area with zeros. ;
+; ;
+; Arguments: ;
+; BX = address of first paragraph ;
+; ECX = Bytes to clear ;
+; ;
+; Returns: ;
+; BX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 23, 1986 04:08:55p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gzero,<PUBLIC,NEAR>
+cBegin nogen
+
+; Assumptions: on entry, BX contains selector to start of block, and is
+; for a scratch descriptor that can be modified. ECX contains the # of
+; bytes to be zeroed.
+
+
+ push es
+ push eax
+ push edi
+ push ecx
+
+ shr ecx, 2 ; # dwords to clear
+ mov es, bx
+ xor eax, eax
+ xor edi, edi
+
+ cld
+ rep stos dword ptr es:[edi]
+
+ pop ecx
+ pop edi
+ pop eax
+ pop es
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmarkfree ;
+; ;
+; Marks a block as free, coalesceing it with any free blocks before ;
+; or after it. This does not free any handles. ;
+; ;
+; Arguments: ;
+; EDX = the first free object before this one ;
+; 0 if unknown ;
+; Ring 1 if no free list update wanted ;
+; Ring 0 if free list update required ;
+; FS:ESI = block to mark as free. ;
+; DS:DI = address of global arena information structure ;
+; ;
+; Returns: ;
+; ZF = 1 if freed a fixed block ;
+; DX = 0 ;
+; ZF = 0 if freed a moveable block ;
+; DX = handle table entry ;
+; FS:ESI = block freed (may have been coalesced) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DS ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; gjoin ;
+; gadd_free ;
+; ;
+; History: ;
+; ;
+; Mon Nov 17, 1986 11:41:49a -by- David N. Weise [davidw] ;
+; Added support for the free list of global partitions. ;
+; ;
+; Sun Nov 09, 1986 01:35:08p -by- David N. Weise [davidw] ;
+; Made the debugging version fill all free space with CCCC. ;
+; ;
+; Wed Sep 24, 1986 10:27:06p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gmarkfree,<PUBLIC,NEAR>
+cBegin nogen
+
+ call gadd_free
+ or esi,esi
+ jz short gmf_exit
+
+; Mark this block as free by clearing the owner field.
+
+ mov ds:[esi].pga_sig,GA_SIGNATURE
+ mov ds:[esi].pga_owner,di ; Mark as free
+ mov ds:[esi].pga_flags,0 ; For good measure.
+
+; Remember the handle value in DX, before setting to zero.
+
+ xor dx,dx
+ xchg ds:[esi].pga_handle,dx
+
+; Try to coalesce with next block, if it is free
+
+ push ds:[esi].pga_prev ; save previous block
+ mov esi,ds:[esi].pga_next ; ESI = next block
+ cmp ds:[esi].pga_owner,di ; Is it free?
+ jne short free2 ; No, continue
+ call gjoin ; Yes, coalesce with block we are freeing
+free2:
+ pop esi ; ESI = previous block
+ cmp ds:[esi].pga_owner,di ; Is it free?
+ jne short free3 ; No, continue
+ mov esi,ds:[esi].pga_next ; Yes, coalesce with block we are freeing;
+ call gjoin
+free3:
+ cmp ds:[esi].pga_owner,di ; Point to free block?
+ je short free4 ; Yes, done
+ mov esi,ds:[esi].pga_next ; No, leave ES pointing at free block
+free4:
+ifdef WOW
+ ; WOW doesn't decommit pages this way
+else
+ call gwin386discard
+endif
+gmf_exit:
+ or dx,dx
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gadd_free ;
+; ;
+; Links in the given partition into the global free list. ;
+; ;
+; Arguments: ;
+; EDX = the first free object before this one ;
+; 0 if unknown ;
+; odd if no free list update wanted ;
+; DS:DI = BurgerMaster ;
+; FS:ESI = free global object to add ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Nov 09, 1986 02:42:53p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc gadd_free,<PUBLIC,NEAR>
+cBegin nogen
+ push eax
+ push edx
+
+ test dl,1
+ jnz short no_update_wanted
+
+ or esi,esi ; this happens with gmovebusy
+ jz short no_update_wanted
+
+ inc [di].gi_free_count
+ mov edx, esi
+
+need_a_home_loop:
+ mov edx, ds:[edx].pga_prev
+ cmp ds:[edx].pga_owner, di ; Found a free block?
+ je short found_a_home
+ cmp ds:[edx].pga_prev, edx ; Sentinel?
+ jne short need_a_home_loop
+
+found_a_home:
+ mov eax, ds:[edx].pga_freenext
+ mov ds:[esi].pga_freenext, eax
+ mov ds:[esi].pga_freeprev, edx
+ mov ds:[edx].pga_freenext, esi
+ mov ds:[eax].pga_freeprev, esi
+
+if KDEBUG
+ call check_free_list
+endif
+gaf_exit:
+no_update_wanted:
+ pop edx
+ pop eax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gdel_free ;
+; ;
+; Removes a partition from the global free list. ;
+; ;
+; Arguments: ;
+; DS:DI = BurgerMaster ;
+; FS:ESI = arena header of partition ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Nov 09, 1986 02:43:26p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc gdel_free,<PUBLIC,NEAR>
+cBegin nogen
+
+ push edi
+ push esi
+ mov edi,ds:[esi].pga_freeprev
+ mov esi,ds:[esi].pga_freenext
+ mov ds:[edi].pga_freenext,esi
+ mov ds:[esi].pga_freeprev,edi
+ pop esi
+ pop edi
+
+ dec [di].gi_free_count
+if KDEBUG
+ call check_free_list
+endif
+ ret
+cEnd nogen
+
+
+if KDEBUG
+;-----------------------------------------------------------------------;
+; check_free_list ;
+; ;
+; Checks the global free list for consistency. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Oct 29, 1986 10:13:42a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc check_free_list,<PUBLIC,NEAR>
+cBegin nogen
+ push eax
+ push ebx
+ push cx
+ push esi
+ push ds
+ SetKernelDS
+ cmp fCheckFree,0
+ jnz short cfl_outta_here
+ test Kernel_flags,kf_check_free
+ jnz short cfl_check_it_out
+cfl_outta_here:
+ jmp all_done
+cfl_check_it_out:
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov esi,[di].phi_first
+ mov cx,[di].gi_free_count
+ or cx,cx
+ jz all_done
+ mov eax, ds:[esi].pga_freenext
+ mov esi, eax
+check_chain_loop:
+ mov ebx,ds:[esi].pga_freeprev
+ mov esi,ds:[esi].pga_freenext
+ cmp ds:[ebx].pga_freenext,eax
+ jz short prev_okay
+prev_bad:
+ push esi
+ mov esi, eax
+ kerror 0FFh,<free_list: prev bad>,bx,si
+ mov eax, esi
+ pop esi
+prev_okay:
+ cmp ds:[esi].pga_freeprev,eax
+ jnz short next_bad
+ mov ebx,esi
+ jmps next_okay
+next_bad:
+ mov bx, ax
+ kerror 0FFh,<free_list: next bad>,bx,es
+next_okay:
+ mov eax,esi
+ loop check_chain_loop
+ SetKernelDS
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ cmp [di].phi_last,eax
+ jz short all_done
+ mov bx, ax
+ kerror 0FFh,<free_list: count bad>,[di].phi_last,bx
+all_done:
+ pop ds
+ pop esi
+ pop cx
+ pop ebx
+ pop eax
+ ret
+cEnd nogen
+
+endif
+
+cProc ValidateFreeSpaces,<PUBLIC,FAR>
+cBegin nogen
+ ret
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3gcompac.asm b/private/mvdm/wow16/kernel31/3gcompac.asm
new file mode 100644
index 000000000..a8039d429
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3gcompac.asm
@@ -0,0 +1,1583 @@
+ TITLE GCOMPACT - Global memory compactor
+
+.sall
+.xlist
+include kernel.inc
+.list
+
+WM_COMPACTING = 041h
+
+.386p
+
+include protect.inc
+
+DataBegin
+
+externB Kernel_Flags
+externW WinFlags
+externW Win386_Blocks
+externW PagingFlags
+externD gcompact_start
+externD gcompact_timer
+externD pPostMessage
+externD NextCandidate
+
+fSwitchStacks DB 0
+fUpDown DB 0
+
+DataEnd
+
+externFP GlobalCompact
+
+sBegin CODE
+assumes CS,CODE
+assumes fs, nothing
+
+externNP glrudel
+externNP gmarkfree
+externNP gcheckfree
+externNP gdel_free
+externNP gsplice
+externNP gnotify
+externNP genter
+externNP gleave
+externNP Enter_gmove_stack
+externNP Leave_gmove_stack
+
+if KDEBUG
+externFP ValidateFreeSpaces
+endif
+
+externNP set_selector_address32
+ifndef WOW_x86
+externNP get_rover_232
+endif
+externNP AssociateSelector32
+externNP alloc_arena_header
+externNP free_arena_header
+externNP mark_sel_NP
+externNP PreAllocArena
+externNP DPMIProc
+externNP get_physical_address
+externFP VirtualFree
+
+if KDEBUG
+externNP CheckGlobalHeap
+endif
+
+;-----------------------------------------------------------------------;
+; gcompact ;
+; ;
+; Compacts the global heap. ;
+; ;
+; Arguments: ;
+; DX = minimum #contiguous bytes needed ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; AX = size of largest contiguous free block ;
+; ES:DI = arena header of largest contiguous free block ;
+; DX = minimum #contiguous bytes needed ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; SI ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; gcmpheap ;
+; gcheckfree ;
+; gdiscard ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:34:32p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gcompact,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS fs
+ ReSetKernelDS fs
+ push esi
+ smov es,40h
+ mov ax,es:[6Ch] ; get the BIOS ticker count
+ sub gcompact_timer.lo,ax
+ or Kernel_Flags[1],kf1_MEMORYMOVED
+
+ mov si, [di].gi_cmpflags
+ push si
+ push si
+ test WinFlags[1], WF1_PAGING
+ jz short @F
+ ; First time:
+ or [di].gi_cmpflags, GA_NOCOMPACT ; No movement
+@@:
+gcompactl:
+if KDEBUG
+ call ValidateFreeSpaces
+endif
+ push edx ; Save requested size
+ife ROM
+ cmp [di].gi_reserve,edi ; Is there a reserve swap area?
+ je short gcompact1 ; No, then dont compact lower heap
+endif
+ mov esi,[di].phi_first ; Yes, compact lower heap
+ mov ebx,pga_next
+ call gcmpheap
+gcompact1:
+ mov esi,[di].phi_last ; Compact upper heap
+ mov ebx,pga_prev
+ call gcmpheap
+ pop edx ; Get requested size
+ mov esi,eax ; ES points to largest free block
+ or eax,eax ; Did we find a free block?
+ jz short gcompact2 ; No, try discarding
+ call gcheckfree ; Yes, see if block big enough
+ jae short gcompactxx ; Yes, all done
+gcompact2: ; Discarding allowed?
+ cmp [di].hi_freeze,di ; Heap frozen?
+ jne short gcompactxx ; Yes, return
+ test [di].gi_cmpflags,GA_NODISCARD
+ jnz short gcompactx ; No, return
+ test WinFlags[1], WF1_PAGING
+ jnz short @F
+ test [di].gi_cmpflags, GA_NOCOMPACT ; Ignore flag if paging
+ jnz short gcompactx
+@@:
+ push esi
+ call gdiscard ; No, try discarding
+ pop ecx ; Saved ESI may be bogus if gdiscard
+ ; discarded anything...
+ jnz short gcompactl ; Compact again if anything discarded
+ mov esi, ecx ; Nothing discarded so ES OK.
+
+gcompactx:
+ test WinFlags[1], WF1_PAGING
+ jz short gcompactxx
+ pop si ; Original flags
+ mov [di].gi_cmpflags, si
+ or si, GA_NOCOMPACT+GA_NODISCARD
+ push si ; Abort next time
+ test [di].gi_cmpflags, GA_NOCOMPACT
+ jz short gcompactl
+
+gcompactxx:
+ add sp,2 ; Toss working flags
+ push ax
+ push dx
+ push es
+ mov ax,40h
+ mov es,ax
+ mov ax,es:[6Ch]
+ mov si,ax
+ cmp pPostMessage.sel,0 ; is there a USER around yet?
+ jz short tock
+ add gcompact_timer.lo,ax
+ sub ax,gcompact_start.lo
+ cmp ax,546 ; 30 secs X 18.2 tics/second
+ jb short tock
+ cmp ax,1092 ; 60 secs
+ ja short tick
+ mov cx,gcompact_timer.lo ; poor resolution of timer!
+ jcxz short tick
+ xchg ax,cx
+ xor dx,dx
+ xchg ah,al ; shl 8 DX:AX
+ xchg dl,al
+ div cx
+ cmp ax,32 ; < 12.5% ?
+ jb short tick
+ mov ah,al
+ mov bx,-1 ; broadcast
+ mov cx,WM_COMPACTING
+ xor dx,dx
+ cCall pPostMessage,<bx, cx, ax, dx, dx>
+tick: mov gcompact_start.lo,si
+ mov gcompact_timer.lo,0
+tock: pop es
+ pop dx
+ pop ax
+ pop [di].gi_cmpflags
+ pop esi ; Restore SI
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gcmpheap ;
+; ;
+; ;
+; Arguments: ;
+; EBX = pga_prev or pga_next ;
+; EDX = minimum #contiguous bytes needed ;
+; DS:DI = address of global heap information ;
+; FS = Kernel DATA ;
+; ;
+; Returns: ;
+; EAX = largest free block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX,CX ;
+; ;
+; Calls: ;
+; gslide ;
+; gbestfit ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:38:16p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gcmpheap,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS fs
+ ReSetKernelDS fs
+ mov NextCandidate, -1
+ xor eax,eax ; Nothing found yet
+ push eax ; Save largest free block so far
+gchloop:
+ cmp ds:[esi].pga_owner,di
+ je short gchfreefnd
+ cmp ds:[esi].pga_owner, GA_NOT_THERE
+ jne short gchnext
+ mov NextCandidate, -1
+gchnext:
+ mov esi, ds:[esi+ebx]
+ cmp esi, ds:[esi+ebx] ; Sentinel?
+ jne short gchloop ; no, continue
+
+gchexit:
+ pop eax ; Return largest free block in AX
+ ret
+
+gchfreefnd:
+ test [di].gi_cmpflags,GA_NOCOMPACT
+ jnz short gchmaxfree ; No, just compute max free.
+ cmp [di].hi_freeze,di ; Heap frozen?
+ jne short gchmaxfree ; Yes, just compute max free.
+ push esi
+ test [di].gi_cmpflags,COMPACT_ALLOC
+ jz short no_hack
+ call gcheckfree ; Allocating, this big enough?
+ jb short no_hack ; yes, STOP NOW!
+ cmp bl,pga_prev ; Compacting upper heap?
+ jnz short no_hack
+ test [di].gi_cmpflags,GA_DISCCODE
+ jz short no_hack
+ cmp edx,ds:[esi].pga_size
+ ja short no_hack
+ mov esi,ds:[esi].pga_next
+ test ds:[esi].pga_flags,GA_DISCCODE
+ jnz short hack
+ cmp ds:[esi].pga_owner,GA_SENTINAL
+ jz short hack
+ cmp ds:[esi].pga_owner,GA_NOT_THERE
+ jnz short no_hack
+hack:
+ pop esi
+ pop eax
+ mov eax,esi
+ ret
+
+no_hack:
+ pop esi
+ test byte ptr WinFlags[1], WF1_PAGING ; Paging?
+ jnz short best_it ; yes, don't slide
+ call PreAllocArena
+ jz short gchmaxfree
+ push edx
+ call gslide
+ pop edx
+ jnz short gchfreefnd
+best_it:
+ push edx
+ call gfirstfit
+ pop edx
+gchmaxfree:
+ cmp bl,pga_prev ; Compacting upper heap?
+ jne short gchnext ; No, dont compute largest free block
+ cmp ds:[esi].pga_owner,di ; Is current free?
+ jne gchnext ; No, ignore it then
+ pop eax ; Recover largest free block so far
+ push edx
+ cmp esi,eax ; Same as current?
+ je short gchmf2 ; Yes, no change then
+ push eax
+ cmp ds:[di].gi_reserve,edi ; Is there a code reserve area?
+ je short gchmf0 ; No, continue
+ test ds:[di].gi_cmpflags,GA_DISCCODE ; If allocating disc
+ jnz short gchmf0 ; code ignore the fence
+ mov ax, [di].gi_disfence_hi
+ shl eax, 16
+ mov ax, [di].gi_disfence_lo
+ mov edx, ds:[esi].pga_size ; Size of this block
+ add edx, ds:[esi].pga_address ; End of this block
+ sub eax, edx ; Fence above it?
+ jae short gchmf0 ; yes, use the whole block
+ neg eax ; Amount above the fence
+ cmp eax, ds:[di].gi_reserve ; Above reserve?
+ jae short gchmf0 ; yes, use all of it
+ sub edx, eax ; Subtract off that above fence
+ ja short gchmf00 ; Use as size of block
+ pop eax
+ jmps gchmf2
+
+gchmf0:
+ mov edx, ds:[esi].pga_size ; Size of this block
+gchmf00:
+ pop eax
+ or eax,eax ; First time?
+ jz short gchmf1 ; Yes, special case
+ cmp edx, ds:[eax].pga_size ; Is it bigger?
+ jb short gchmf2 ; No, do nothing
+gchmf1:
+ mov eax,esi ; Yes, remember biggest free block
+gchmf2:
+ pop edx
+ push eax ; Save largest free block so far
+ test PagingFlags, 2 ; Idle time compaction!
+ jnz gchexit
+ jmp gchnext ; Go process next block
+ UnSetKernelDS fs
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gslide ;
+; ;
+; Sees if next/previous block can slide into the passed free block. ;
+; ;
+; Arguments: ;
+; FS:ESI = free block ;
+; DS:DI = address of global heap information ;
+; CX = #arena entries left to examine ;
+; EBX = pga_next or pga_prev ;
+; ;
+; Returns: ;
+; ZF = 0 if block found and moved into passed free block ;
+; FS:ESI points to new free block ;
+; FS:EDX points to new free block ;
+; ;
+; ZF = 1 if no block found ;
+; FS:ESI points to original free block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; EAX,EDX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:58:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gslide,<PUBLIC,NEAR>
+cBegin nogen
+ push esi
+ mov esi,ds:[ebx+esi]
+ mov edx,esi ; Source of move in EDX
+ call gmoveable
+ pop esi
+ jz short gslide_no_move
+ call gmovebusy ; Handle exact fits etc!!
+ call gpagingcandidate
+if KDEBUG
+ cmp edx, ds:[esi+ebx] ; Are we adjacent?
+ je short gslide_adjacent
+ int 3
+ int 3
+gslide_adjacent:
+endif
+ mov esi, edx
+ or esi, esi ; ZF = 0
+gslide_no_move:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmove ;
+; ;
+; Moves a moveable block into the top part of a free block. The low ;
+; order bit of the source and destination may be either set or reset. ;
+; If set, then this routine does NOT move the arena header paragraph. ;
+; If the bit is reset, then the arena header is moved. Only the low ;
+; order bit of EDX is examined, and the low order bit of ESI is assumed ;
+; to the same. ;
+; ;
+; Arguments: ;
+; DS:DI = master object ;
+; ES:0 = address of destination block ;
+; FS:ESI = arena of destination block ;
+; FS:EDX = arena of source block ;
+; ECX = # bytes to move ;
+; ;
+; Returns: ;
+; DS:DI = master object (it may have moved) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; gnotify ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 03:31:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gmove,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS fs
+ ReSetKernelDS fs
+
+ push es
+ pushad
+
+ mov eax, edx
+ push esi ; Save destination
+ mov edx, ecx ; # bytes passed in in ECX
+ mov bx, ds:[eax].pga_handle ; BX = handle of source
+ Handle_To_Sel bl
+ mov cx, bx ; CX = client data address of dest.
+
+ push eax
+ push edx ; Save #paragraphs
+
+ mov ax, GN_MOVE
+ push cx ; Save client data address
+ call gnotify ; Call global notify procedure
+ pop cx
+
+ pop edx ; EDX = #paragraphs to move
+ pop esi ; ESI = source arena
+ pop edi ; EDI = destination arena
+
+; Save DS value AFTER call to gnotify, as the master object might be the
+; block we are moving and thus changed by the global heap notify proc.
+
+ push gs
+ smov gs, ds
+ mov ax,ss ; Are we about to move the stack?
+ cmp ax,cx
+ mov cx,0 ; ...assume no
+ jne short stack_no_move
+ mov cx, ax ; Selector does not change!
+ call Enter_gmove_stack ; switch to temporary stack
+stack_no_move:
+ mov fSwitchStacks,cl ; Remember if we switched
+
+ xor cx, cx ; Ready for result of compare
+ mov eax, gs:[edi].pga_address
+ cmp gs:[esi].pga_address, eax
+ adc ch, 0
+ mov fUpDown,ch
+
+ mov ecx, edx ; # bytes to move
+ shr ecx, 2 ; # dwords to move
+ jecxz all_done
+ cmp fUpDown, 0
+ jnz short move_it_up
+
+; MOVE IT DOWN
+
+ cld
+ xor esi, esi
+ jmps move_it
+
+move_it_up:
+ std
+ mov esi, ecx
+ dec esi
+ shl esi,2
+
+move_it:
+ mov ds, bx ; DS:SI = first word in source block
+ mov edi, esi
+ifdef WOW_x86
+ smov es,FLAT_SEL ; 23:EAX => pga_address or taget
+ add edi,eax
+endif; WOW_x86
+ rep movs dword ptr [edi], dword ptr [esi]
+ ; 386 BUG, ECX, ESI, EDI ARE NOW TRASHED
+
+all_done:
+ smov ds, gs
+ cCall set_selector_address32,<bx,eax> ; Update source selector
+
+ cmp fSwitchStacks,cl ; Switch to new stack if any
+ je short move_exit
+ call Leave_gmove_stack
+move_exit:
+ pop gs
+
+ popad
+ pop es
+ cld ; Protect people like MarkCl from themselves
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gbestfit ;
+; ;
+; Searches for the largest moveable block that will fit in the passed ;
+; free block. ;
+; ;
+; Arguments: ;
+; DS:ESI = free block ;
+; DS:DI = address of global heap information ;
+; CX = #arena entries left to examine ;
+; EBX = pga_next or pga_prev ;
+; ;
+; Returns: ;
+; ZF = 1 if block found & moved into free block w/ no extra room. ;
+; DS:ESI = busy block before/after new busy block. ;
+; ;
+; ZF = 0 if DS:ESI points to a free block, either the ;
+; original one or what is left over after moving a block ;
+; into it. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; DX,SI ;
+; ;
+; Calls: ;
+; gmoveable ;
+; gmovebusy ;
+; ;
+; History: ;
+; ;
+; Thu Sep 25, 1986 05:52:12p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gfirstfit,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS fs
+ ReSetKernelDS fs
+ push ecx
+ mov edx, esi ; Save free block
+
+gbfrestart:
+ call PreAllocArena ; Abort if no free arenas
+ jz short gbfabort
+ mov eax,ds:[edx].pga_size ; Compute max size to look for
+ jmps gbfnext
+
+gbfloop:
+ cmp ds:[esi].pga_owner,di ; Is this block busy?
+ je short gbfnext ; No, continue
+ cmp ds:[esi].pga_size,eax ; Yes, is block bigger than max size?
+ ja short gbfnext ; Yes, continue
+ cmp ds:[esi].pga_owner,GA_NOT_THERE ; Is this even here?
+ je short gbfnext ; No, continue
+ call gmoveable ; Yes, is it moveable
+ jnz short gbffound
+gbfnext: ; No, continue
+ mov esi, ds:[esi+ebx] ; Skip past this block
+ cmp esi, ds:[esi+ebx] ; Sentinel?
+ jne gbfloop
+
+gbfabort:
+ mov esi, edx ; Return original free block in ESI
+ jmps gbestfit1 ; Nothing found!
+
+gbffound:
+ xchg edx, esi ; Source of move
+ call gmovebusy ; Yes, move it into free block
+ mov NextCandidate, -1
+ call gpagingcandidate
+ mov NextCandidate, -1
+ifndef WOW
+ xchg esi, edx ; Put free block in esi
+ call gwin386discard
+ xchg esi, edx
+endif
+
+ cmp edx, ds:[esi+ebx] ; Blocks adjacent?
+ je short gbestfit1 ; Yes, may have coalesced.
+ ; Return busy block in ESI
+
+ mov esi, ds:[esi+ebx] ; Get block after busy block
+ cmp ds:[esi].pga_owner,di ; Is this block busy?
+ jne short gbestfit1 ; Yes, fit was exact
+ xchg edx, esi ; EDX is new free block
+ jmps gbfrestart ; Start search from old busy block
+
+gbestfit1:
+ pop ecx
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gmovebusy ;
+; ;
+; Subroutine to move a busy block to a free block of the same size, ;
+; preserving the appropriate arena header fields, freeing the old ;
+; busy block and updating the handle table entry to point to the ;
+; new location of the block. ;
+; ;
+; [tonyg] ;
+; The above has been inaccurate for a while - the destination is NOT ;
+; necessarily free, NOR is it always the same size! ;
+; ;
+; It will now handle everything gslidecommon used to do! ;
+; ;
+; Arguments: ;
+; BX = ga_prev or ga_next ;
+; DS:EDX = old busy block location ;
+; DS:ESI = new busy block location ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; DS:ESI = points to new busy block arena header ;
+; DS:EDX = points to free block where block used to be ;
+; (may be coalesced) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; EBX,ECX ;
+; ;
+; Registers Destroyed: ;
+; EAX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Jun 22, 1987 11:39:56p -by- David N. Weise [davidw] ;
+; Made it jump off to gslidecommon when appropriate. ;
+; ;
+; Mon Oct 27, 1986 10:17:16p -by- David N. Weise [davidw] ;
+; Made the lru list be linked arenas, so we must keep the list correct ;
+; here. ;
+; ;
+; Thu Sep 25, 1986 05:49:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gmovebusy,<PUBLIC,NEAR>
+cBegin nogen
+if KDEBUG
+ cmp ds:[esi].pga_owner, GA_NOT_THERE
+ jne short @F
+AAARRRGGGHHH:
+ int 3
+ int 3
+@@:
+ cmp ds:[edx].pga_owner, GA_NOT_THERE
+ je AAARRRGGGHHH
+endif
+
+ push ecx
+ mov ecx,ds:[edx].pga_size ; ECX = size of source
+ cmp ds:[esi].pga_owner,di ; Is destination busy?
+ jne gmbexactfit ; Yes, then don't create extra block
+ mov eax, ds:[esi].pga_freeprev
+ call gdel_free ; Take off free list now!
+ cmp ecx,ds:[esi].pga_size ; No, source and destination same size?
+ je short gmbexactfit ; Yes, then don't create extra block
+ jb short gmbsplice ; Destination is larger, split it
+
+if KDEBUG
+ ; MUST BE ADJACENT IF DESTINATION
+ cmp ds:[esi+ebx], edx ; SMALLER THAN SOURCE!!!
+ je short gmb_adjust
+ int 3
+ int 3
+gmb_adjust:
+endif
+ push ecx ; source length
+ push ds:[esi].pga_size ; destination length
+ cmp bl, pga_next
+ je short gmb_down
+ ; Moving busy block up
+ mov eax, ds:[edx].pga_address ; Correct destination address
+ add eax, ds:[esi].pga_size
+ mov ds:[esi].pga_address, eax
+ call gmb_gmove
+ jmps gmb_adjusted
+
+gmb_down: ; Moving busy block down
+ call gmb_gmove
+ mov ecx, ds:[esi].pga_address ; Correct new free block address
+ add ecx, ds:[edx].pga_size
+ mov ds:[edx].pga_address, ecx
+
+gmb_adjusted:
+ pop ds:[edx].pga_size ; Swap sizes
+ pop ds:[esi].pga_size
+ jmps gmb_moved
+
+gmbsplice:
+ push ecx
+ push edx
+ mov edx, ecx ; # bytes in block to make
+ cmp bl, pga_prev
+ je short gmb_backward
+ call gsplice ; Split the block
+ jmps gmb_spliced
+
+gmb_backward:
+ neg edx
+ add edx, ds:[esi].pga_size ; Second block will be used
+ call gsplice
+ xchg esi, edx
+
+gmb_spliced:
+ mov ds:[esi].pga_owner,1 ; Mark new block busy
+ push esi ; New free block
+ mov esi, edx ; Block to free
+ mov edx, eax
+ call gmarkfree
+ pop esi ; New free block
+ pop edx ; Source for copy
+ pop ecx
+
+gmbexactfit:
+ call gmb_gmove
+
+gmb_moved:
+ mov eax, esi
+ mov esi, edx
+ xor edx, edx
+ call gmarkfree ; Free old block
+ mov ecx,esi ; New free block
+ mov esi,eax ; New block
+ or dx,dx
+ jz short gmb1
+ mov ds:[esi].pga_handle,dx ; Set back link to handle in new block
+ cCall AssociateSelector32,<dx,esi> ; Associate with new arena
+ xor dx,dx ; Set Z flag
+gmb1:
+ mov edx,ecx
+gmbexit:
+ pop ecx
+ ret
+cEnd nogen
+
+;
+; Common code for gmovebusy
+;
+cProc gmb_gmove,<PUBLIC,NEAR>
+
+cBegin nogen
+ push ecx ; # bytes to move
+ push dword ptr ds:[edx].pga_count
+ push ds:[edx].pga_owner
+ push ds:[edx].pga_lruprev
+ push ds:[edx].pga_lrunext
+
+ pop ds:[esi].pga_lrunext ; Copy client words to new header
+ pop ds:[esi].pga_lruprev
+ pop ds:[esi].pga_owner
+ pop dword ptr ds:[esi].pga_count
+ cmp ds:[esi].pga_lruprev,edi
+ jz short no_link
+ cmp [di].gi_lruchain,edx
+ jnz short didnt_move_head
+ mov [di].gi_lruchain,esi
+didnt_move_head:
+ mov ecx,ds:[edx].pga_lruprev
+ mov ds:[ecx].pga_lrunext,esi ; Update the lru list
+ mov ecx,ds:[edx].pga_lrunext
+ mov ds:[ecx].pga_lruprev,esi ; Update the lru list
+no_link:
+ pop ecx
+ifndef WOW_x86
+ call get_rover_232
+endif
+ jmp gmove ; Move the client data
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; gmoveable ;
+; ;
+; Tests if an ojbect is moveable. Non moveable blocks are: ;
+; Fixed blocks, moveable blocks that are locked, moveable blocks ;
+; going up, discardable code going down. ;
+; ;
+; Arguments: ;
+; FS:ESI = arena header of object ;
+; DS:DI = address of global heap information ;
+; BX = ga_next or ga_prev ;
+; ;
+; Returns: ;
+; ZF = 0 if object moveable ;
+; ZF = 1 if object not moveable ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Thu Sep 25, 1986 05:42:17p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gmoveable,<PUBLIC,NEAR>
+cBegin nogen
+ test ds:[esi].pga_handle,GA_FIXED ; If no handle then fixed
+ jnz short gmfixed
+
+ cmp ds:[esi].pga_count,bh ; If locked then fixed
+ jne short gmfixed
+
+ test ds:[esi].pga_flags,GA_DISCCODE ; If discardable code
+ jz short gmnotcode
+ cmp bl,pga_next ; Discardable code can only
+ ret ; move up in memory
+gmnotcode:
+ cmp [di].gi_reserve,edi ; If no reserved code area?
+ je short gmokay ; Then anything can move up
+ cmp bl,pga_prev ; Otherwise can only move down
+ ret ; in memory
+gmfixed:
+ or bh,bh ; Return with ZF = 1 if
+ ret ; not moveable
+gmokay:
+ or esi,esi
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gdiscard ;
+; ;
+; Subroutine to walk LRU chain, discarding objects until the #paras ;
+; discarded, plus the biggest free block is greater than the #paras ;
+; we are looking for. ;
+; ;
+; Arguments: ;
+; EAX = size of largest free block so far ;
+; EDX = minimum #bytes needed ;
+; DS:DI = address of global heap information ;
+; ;
+; Returns: ;
+; ZF = 0 if one or more objects discarded. ;
+; ZF = 1 if no objects discarded. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; Mon Oct 27, 1986 09:34:45p -by- David N. Weise [davidw] ;
+; The glru list was reworked to link the arenas, not using the handle ;
+; table as a middle man. Because of this change glruprev was moved ;
+; inline and the code shortened up again. ;
+; ;
+; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Thu Sep 25, 1986 05:45:31p -by- David N. Weise [davidw] ;
+; Shortened it up a bit and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc gdiscard,<PUBLIC,NEAR>
+cBegin nogen
+ push eax
+ push edx
+
+ mov [di].hi_ncompact,0 ; Clear compaction flag
+ sub edx,eax ; How much to discard before
+ mov [di].hi_distotal,edx ; compacting again.
+
+ xor ebx,ebx ; EBX = amount of DISCCODE below fence
+ test [di].gi_cmpflags,GA_DISCCODE
+ jnz short fence_not_in_effect0
+
+ mov cx,[di].gi_lrucount
+ jcxz fence_not_in_effect0 ; All done if LRU chain empty
+
+ mov ax, [di].gi_disfence_hi
+ shl eax, 16
+ mov ax, [di].gi_disfence_lo
+ push edx
+ mov edx, eax
+ add edx, ds:[edi].gi_reserve
+ mov esi,[di].gi_lruchain ; ESI -> most recently used (ga_lruprev
+gdloop0: ; is the least recently used)
+ mov esi,ds:[esi].pga_lruprev ; Move to next block in LRU chain
+ test ds:[esi].pga_flags,GA_DISCCODE ; Discardable code?
+ jz short gdloop0a ; No, ignore
+ cmp edx, ds:[esi].pga_address
+ jbe short gdinclude
+ cmp eax, ds:[esi].pga_address ; Yes, is this code fenced off?
+ jbe short gdloop0a ; No, ignore
+gdinclude:
+ add ebx,ds:[esi].pga_size ; Yes, accumulate size of discardable
+gdloop0a: ; code below the fence
+ loop gdloop0
+ pop edx
+
+fence_not_in_effect0:
+ mov esi,[di].gi_lruchain
+ cmp [di].gi_lrucount, 0
+ je short gdexit
+ push ds:[esi].pga_lruprev
+ push [di].gi_lrucount
+gdloop:
+ pop cx
+ pop eax
+ jcxz gdexit ; No more see if we discarded anything
+ mov esi, eax ; ES on stack may be invalid if count 0
+ dec cx
+ push ds:[esi].pga_lruprev ; Save next handle from LRU chain
+ push cx
+ cmp ds:[esi].pga_count,0 ; Is this handle locked?
+ jne short gdloop ; Yes, ignore it then
+ test [di].gi_cmpflags,GA_DISCCODE
+ jnz short fence_not_in_effect
+ test ds:[esi].pga_flags,GA_DISCCODE
+ jz short fence_not_in_effect
+ or ebx,ebx ; Discardable code below fence?
+ jz short gdloop ; No, cant discard then
+ cmp ebx,ds:[esi].pga_size ; Yes, more than size of this block?
+ jb short gdloop ; No, cant discard then
+ sub ebx,ds:[esi].pga_size ; Yes, reduce size of code below fence
+fence_not_in_effect:
+ push ebx
+ call DiscardCodeSegment
+ pop ebx
+ jnz short discarded_something
+ test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
+ jz short gdloop
+ jmps enough_discarded
+discarded_something:
+ test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
+ jnz short enough_discarded
+ or [di].hi_ncompact,1 ; Remember we discarded something
+ sub [di].hi_distotal,eax ; Have we discarded enough yet?
+ ja short gdloop ; No, look at next handle
+enough_discarded:
+ pop cx ; Flush enumeration counter
+ pop ecx ; and saved ESI
+gdexit:
+ cmp [di].hi_ncompact,0 ; Return with Z flag set or clear
+ pop edx
+ pop eax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; DiscardCodeSegment ;
+; ;
+; Discards the given segment. Calls gnotify to fix stacks, entry ;
+; points, thunks, and prologs. Then glrudel removes it from the lru ;
+; list and gmarkfree finally gets rid of it. ;
+; ;
+; Arguments: ;
+; DS:DI => BurgerMaster ;
+; ES = Address of segment to discard ;
+; ;
+; Returns: ;
+; AX = size discarded ;
+; ZF = 0 ok ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX ;
+; ;
+; Calls: ;
+; gnotify ;
+; glrudel ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+; Fri Jun 12, 1987 -by- Bob Matthews [bobm] ;
+; Made FAR. ;
+; ;
+; Sun Apr 19, 1987 12:05:40p -by- David N. Weise [davidw] ;
+; Moved it here from InitTask, so that FirstTime could use it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DiscardCodeSegment,<PUBLIC,NEAR>
+cBegin nogen
+ push esi
+ mov bx,ds:[esi].pga_handle ; BX = handle
+ mov al,GN_DISCARD ; AX = GN_DISCARD
+ call gnotify
+ jz short cant_discard ; Skip this handle if not discardable
+ call glrudel ; Delete handle from LRU chain
+ push ds:[esi].pga_owner ; Save owner field
+ mov eax,ds:[esi].pga_size ; Save size
+ xor edx,edx
+ call gmarkfree ; Free the block associated with this handle
+ mov bx,dx
+ pop cx ; Owner
+ cCall mark_sel_NP,<bx,cx>
+cant_discard:
+ pop esi
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ShrinkHeap ;
+; ;
+; Tries to return DPMI memory blocks to DPMI memory manager. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; InnerShrinkHeap ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ShrinkHeap,<PUBLIC,NEAR>
+cBegin nogen
+
+ push ds
+
+ GENTER32
+ ReSetKernelDS FS
+
+ cCall InnerShrinkHeap
+ jnz short sh_maybe_more
+
+ and PagingFlags, NOT 8 ; Don't call back if # win386
+ ; didn't change
+sh_maybe_more:
+
+ GLEAVE32
+ UnSetKernelDS FS
+ pop ds
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; InnerShrinkHeap ;
+; ;
+; Checks heap to see if there are any blocks to return to Win386 ;
+; Compacts if there are Win386 blocks around AND there is more ;
+; than 512k free. ;
+; Returns any completely free Win386 block to Win386. ;
+; ;
+; Arguments: ;
+; FS = Kernel's DS ;
+; EDI = 0 ;
+; ;
+; Returns: ;
+; Z flag set if no blocks returned, Z clear if 1 or more returned.;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; UnlinkWin386Block ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc InnerShrinkHeap,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS FS
+ ReSetKernelDS FS
+ pushad
+
+ push Win386_Blocks
+
+ cmp Win386_Blocks, 0
+ je short sh_done
+ ; First count up free blocks
+ mov esi, [edi].phi_first
+scan_loop:
+ mov esi, [esi].pga_freenext
+scan_next:
+ cmp esi, [esi].pga_next ; Sentinel?
+ je short sh_done ; yes, all done
+
+ mov ebx, [esi].pga_prev
+ cmp [ebx].pga_owner, GA_NOT_THERE
+ jne short scan_loop
+ mov ecx, [esi].pga_next
+ cmp [ecx].pga_owner, GA_NOT_THERE
+ jne short scan_loop
+ mov eax, [ecx].pga_next ; Block after NOT_THERE block
+ cmp eax, [eax].pga_next ; Sentinel?
+ je short sh_done ; yes, don't try to unlink
+ ; Have block to return
+ push [esi].pga_freeprev ; Current block will be freed
+
+ cCall UnlinkWin386Block
+
+ pop esi ; Continue before block freed
+ jmps scan_loop
+
+sh_done:
+ pop ax ; Starting value of Win386_Blocks
+ cmp ax, Win386_Blocks ; Set Z flag if heap didn't shrink
+
+ popad
+ UnSetKernelDS FS
+ ret
+cEnd
+
+;-----------------------------------------------------------------------;
+; UnlinkWin386Block ;
+; ;
+; Returns a block to Win386 and unlinks it from the heap. ;
+; ;
+; Arguments: ;
+; EBX Block previous to block to be unlinked ;
+; ESI Block to be unlinked ;
+; ECX Block after to block to be unlinked ;
+; ;
+; Returns: ;
+; ESI Block previous to EBX ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ECX, DX, EDI, DS, ES ;
+; ;
+; Registers Destroyed: ;
+; EAX, EBX, EDX ;
+; ;
+; Calls: ;
+; GlobalCompact ;
+; UnlinkWin386Block ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc UnlinkWin386Block,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS FS
+ ReSetKernelDS FS
+ push dx
+
+ mov edx, [ecx].pga_next ; Block after all this
+ cmp edx, [edx].pga_next ; Last sentinel?
+ je RSHORT dont_do_it ; Never free last block
+
+if KDEBUG
+ push edx
+ mov eax, [esi].pga_size
+ mov edx, eax
+ shr edx, 16
+ krDebugOut <DEB_TRACE OR DEB_krMemMan>, "UnlinkWin386Block: releasing #dx#AX bytes"
+ pop edx
+endif
+ push esi
+ call gdel_free ; Remove from free list
+ifdef WOW
+ push edx
+ push ebx
+ push ecx
+ mov eax,MEM_RELEASE
+ xor edi,edi
+ cCall VirtualFree,<[ebx].pga_lrunext,edi,eax>
+ pop ecx
+ pop ebx
+ pop edx
+else
+ mov esi, [ebx].pga_lrunext ; Saved WIN386 handle
+ mov di, si
+ shr esi, 16 ; Put in SI:DI
+ DPMICALL 0502h ; Free Memory Block
+endif; WOW
+ xor edi, edi
+ pop esi
+
+ dec Win386_Blocks
+
+ mov eax, [ebx].pga_prev ; Block before all this
+ mov [eax].pga_next, edx ; Unlink them.
+ mov [edx].pga_prev, eax
+
+ cCall free_arena_header,<ebx> ; Free the arena headers
+ cCall free_arena_header,<esi>
+ cCall free_arena_header,<ecx>
+
+ mov esi, eax ; For gfreeall
+
+ sub [edi].hi_count, 3
+
+if KDEBUG
+ call CheckGlobalHeap
+endif
+
+dont_do_it:
+ pop dx
+ ret
+ UnSetKernelDS FS
+
+cEnd nogen
+
+cProc gpagingcandidate,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS FS
+ ReSetKernelDS FS
+ test byte ptr WinFlags[1], WF1_PAGING ; Paging?
+ jz short gpc_not_paging
+ pushad
+ mov ebx, ds:[esi].pga_address
+ mov esi, ds:[esi].pga_size
+ add esi, ebx ; End of region
+ shr ebx, 12
+ shr esi, 12
+ cmp ebx, NextCandidate
+ jb short gpc_use_this_page
+ mov ebx, NextCandidate ; Start the region here
+gpc_use_this_page:
+ cmp esi, ebx
+ jne short call_win386
+ mov NextCandidate, ebx
+ jmps gpc_done
+call_win386:
+ mov NextCandidate, -1
+ sub esi, ebx ; number of pages
+ mov di, si
+ shr esi, 16
+ mov cx, bx
+ shr ebx, 16
+ifndef WOW ; NT doesn't have the concept
+ DPMICALL 0700h ; Page Candidate
+endif
+gpc_done:
+ popad
+gpc_not_paging:
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+ifndef WOW
+cProc gwin386discard,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS FS
+ ReSetKernelDS FS
+ cmp ds:[esi].pga_size, 4096
+ jb short not_a_chance ; Quick exit
+ cmp ds:[esi].pga_size, 16*1024
+ jb short inform_later
+
+ pushad
+ mov ebx, ds:[esi].pga_address
+ mov esi, ds:[esi].pga_size
+
+ mov di, si
+ shr esi, 16 ; SI:DI is # bytes to discard
+ mov cx, bx
+ shr ebx, 16 ; BX:CX is first bytes to discard
+ifndef WOW
+ DPMICALL 0703h
+endif
+ popad
+ jmps not_a_chance
+
+inform_later:
+ or PagingFlags, 1
+not_a_chance:
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+endif
+
+
+ifndef WOW
+cProc DiscardFreeBlocks,<PUBLIC,NEAR>
+cBegin nogen
+ push es
+ push ds
+ GENTER32
+ ReSetKernelDS FS
+ and PagingFlags, NOT 1
+
+ mov esi, ds:[di].phi_first
+ mov esi, ds:[esi].pga_freenext
+dfb_next:
+ cmp esi, ds:[esi].pga_next ; Sentinel?
+ je short dfb_done ; yes, all done
+
+ push esi
+ push edi
+ cmp ds:[esi].pga_size, 4096
+ jb short no_win386discard ; Quick exit
+
+ mov ebx, ds:[esi].pga_address
+ mov esi, ds:[esi].pga_size
+ add esi, ebx ; First byte past block
+ shr esi, 12 ; Page of this byte
+ add ebx, 0fffh
+ shr ebx, 12 ; First page we can discard
+ sub esi, ebx ; # pages we can discard
+ jbe short no_win386discard ; none to discard
+
+ mov di, si
+ shr esi, 16 ; SI:DI is # pages to discard
+ mov cx, bx
+ shr ebx, 16 ; BX:CX is first page to discard
+ifndef WOW
+ DPMICALL 0701h ; Say goodbye, pages
+endif
+
+no_win386discard:
+ pop edi
+ pop esi
+
+ mov esi, ds:[esi].pga_freenext
+ jmps dfb_next
+
+dfb_done:
+ GLEAVE32
+ UnSetKernelDS FS
+ pop ds
+ pop es
+ ret
+cEnd nogen
+endif
+
+;---------------------------------------------------------------------------
+;
+; guc_findfree
+;
+; helper function for guncompact
+;
+; finds the next free block below the address
+; in ECX into which the block pointed to by ESI will fit.
+;
+; Entry:
+; ECX = maximum address (desired swap area)
+; DS:DI = global heap info
+; ESI = arena of block to move
+;
+; Exit:
+; Carry clear if block found, set if not
+; EDX = free block arena
+;
+; Uses:
+; EAX, EDX
+;
+; Preserves:
+; EBX, ECX, ESI, EDI
+;
+; History:
+; Fri Jun 7, 1991 9:38 -by- Craig Critchley [craigc]
+; Wrote it...
+;
+;--------------------------------------------------------------------------
+
+cProc guc_findfree, <NEAR, PUBLIC>
+cBegin nogen
+
+ mov edx, ds:[di].phi_last
+ mov edx, ds:[edx].pga_freeprev
+
+gucff_check:
+ cmp edx, ds:[edx].pga_prev ; if at start, not found
+ jz short gucff_notfound
+
+ mov eax, ds:[edx].pga_address ; is it out of swap area
+ add eax, ds:[edx].pga_size
+ cmp eax, ecx
+ jae short gucff_nextblock
+
+ mov eax, ds:[esi].pga_size ; does it fit
+ cmp ds:[edx].pga_size, eax
+ jb short gucff_nextblock
+
+ clc ; return it in EDX
+ ret
+
+gucff_nextblock:
+ mov edx, ds:[edx].pga_freeprev ; previous free block
+ jmp short gucff_check
+
+gucff_notfound:
+ stc ; return error
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------------
+;
+; guncompact -
+;
+; this function moves segments that are not free or discardable code
+; out of the intended swap area. don't take the name too seriously.
+;
+; Entry:
+; ECX = size of intended swap area
+; DS:DI = global heap info
+; FS = global heap
+;
+; Exit:
+; Carry clear if space could be cleared, set if not
+;
+; Registers used:
+; EAX, EBX, ECX, EDX, ESI
+;
+; Called by:
+; greserve
+;
+; Calls:
+; gmoveable
+; gmovebusy
+;
+; History:
+; Fri Jun 7, 1991 9:38 -by- Craig Critchley [craigc]
+; Wrote it...
+;
+;-----------------------------------------------------------------------------
+
+cProc guncompact, <NEAR, PUBLIC>
+
+cBegin <nogen>
+
+ mov edx, [di].phi_last ; point to last block
+ mov ebx, pga_prev
+
+ sub ecx, ds:[edx].pga_address ; find desired code fence
+ neg ecx
+
+guc_trymovingblock:
+ mov esi, ds:[edx+ebx] ; block under current one...
+ cmp ds:[esi].pga_owner, 0 ; don't move free blocks
+ jz short guc_skipblock
+ test ds:[esi].pga_flags, GA_DISCCODE ; don't move discardable code
+ jnz short guc_skipblock
+ cmp ds:[esi].pga_owner, GA_NOT_THERE ; ignore not-there's
+ jz short guc_skipblock
+
+ call gmoveable ; can this block be moved?
+ jz short guc_error ; if not, swap area toast
+ push edx
+ call guc_findfree ; find a block to move it into
+ pop eax
+ jc short guc_error ; error if didn't find one
+ push eax
+ xchg edx, esi
+ call gmovebusy ; move it
+ xchg edx, esi
+ pop edx
+
+ ;;; can we just fall thru the block ought to be free now...
+ jmp short guc_trymovingblock ; move what's there now
+
+guc_skipblock:
+ mov edx, esi ; this block now first cleared
+ cmp ds:[edx].pga_address, ecx ; big enough?
+ ja short guc_trymovingblock
+
+guc_done:
+ clc ; success-o-mundo!!
+ ret
+
+guc_error:
+ stc ; if not, we could not
+ ret ; clear swap area
+
+cEnd <nogen>
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3ginterf.asm b/private/mvdm/wow16/kernel31/3ginterf.asm
new file mode 100644
index 000000000..6d5e19a9e
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3ginterf.asm
@@ -0,0 +1,2274 @@
+ TITLE GINTERF - Global Memory Manager interface procedures
+
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+ifdef WOW
+include wow.inc
+include wowkrn.inc
+include vint.inc
+include wowcmpat.inc
+
+GMEMSTATUS_block STRUC
+dwLength dd ? ;/* size in bytes of MEMORYSTATUS structure */
+dwMemoryLoad dd ? ;/* percent of memory being used */
+dwTotalPhys dd ? ;/* total bytes of physical memory */
+dwAvailPhys dd ? ;/* unallocated bytes of physical memory */
+dwTotalPageFile dd ? ;/* total bytes of paging file */
+dwAvailPageFile dd ? ;/* unallocated bytes of paging file */
+dwTotalVirtual dd ? ;/* total user bytes of virtual address space */
+dwAvailVirtual dd ? ;/* unallocated user bytes of virtual address space */
+GMEMSTATUS_block ENDS
+
+endif
+.list
+
+.386p
+include protect.inc
+
+CheckHeap MACRO name
+local a
+if KDEBUG
+ extrn CheckGlobalHeap :near
+ call CheckGlobalHeap
+ jnc short a
+ or ax,ERR_GMEM
+ xor bx,bx
+ kerror <>,<&name: Invalid global heap>,dx,bx
+a:
+endif
+ endm
+
+ifdef WOW
+externFP WowCursorIconOp
+externFP GlobalMemoryStatus
+externFP WowDdeFreeHandle
+
+externFP FindAndReleaseDib
+externNP MyGetAppWOWCompatFlags
+endif
+
+externW pStackTop
+externW pStackMin
+externW pStackBot
+
+DataBegin
+
+externB Kernel_Flags
+externB fBooting
+externW hGlobalHeap
+externW pGlobalHeap
+externW curTDB
+externW loadTDB
+externW hExeHead
+externW WinFlags
+
+GSS_SI dw 0
+GSS_DS dw 0
+GSS_RET dd 0
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+
+if SDEBUG
+externNP DebugFreeSegment
+endif
+
+externNP galloc
+externNP grealloc
+externNP gfree
+externNP glock
+externNP gunlock
+externNP gfreeall
+externNP galign
+externNP gcompact
+externNP gmovebusy
+externNP gsearch
+externNP genter
+externNP gleave
+externNP gavail
+externNP glrutop
+externNP glrubot
+externNP glrudel
+externNP glruadd
+externNP gmarkfree
+externNP ShrinkHeap
+externNP HackCheck
+
+externNP get_arena_pointer32
+externNP get_physical_address
+externNP pdref
+externNP alloc_arena_header
+externNP free_arena_header
+externNP PreAllocArena
+externNP MyGetAppCompatFlags
+externNP DPMIProc
+externW gdtdsc
+
+if ROM
+externNP GetOwner
+endif
+
+if KDEBUG
+externFP OutputDebugString
+
+ThisIsForTurboPascal:
+ db "A program has attempted an invalid selector-to-handle conversion.",13,10,"Attempting to correct this error.",13,10,0
+endif
+
+if KDEBUG
+externNP xhandle_norip
+
+ifdef ?CHECKMEM
+cProc CheckMem,<PUBLIC,NEAR>
+cBegin nogen
+ or ax,ax
+ jnz short cm_okay
+ cmp [di].hi_check,di
+ je short cm_okay
+ kerror ERR_GMEM,<GlobalAlloc or ReAlloc failed>,di,cx
+ xor ax,ax
+ xor cx,cx
+ xor dx,dx
+cm_okay:
+ ret
+cEnd nogen
+endif
+endif
+
+cProc GetDefOwner,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS fs
+ ReSetKernelDS fs
+ mov cx,curTDB
+ jcxz xxxx
+ mov es,cx
+ mov cx,loadTDB
+ jcxz xxx
+ mov es,cx
+xxx: mov cx,es:[TDB_PDB]
+ inc cx
+xxxx: dec cx
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gbtop ;
+; ;
+; Converts a 32-bit byte count to a 16-bit paragraph count. ;
+; ;
+; Arguments: ;
+; AX = allocation flags or -1 if called from GlobalCompact ;
+; BX = stack address of 32-bit unsigned integer ;
+; DX = handle being reallocated or zero ;
+; DS:DI = address of GlobalInfo for global heap ;
+; ;
+; Returns: ;
+; AX = updated allocation flags ;
+; EBX = #bytes needed to contain that many bytes ;
+; CX = owner value to use ;
+; DX = handle being reallocated or zero ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Dec 03, 1986 10:20:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc gbtop,<PUBLIC,NEAR>
+cBegin nogen
+ CheckKernelDS fs
+ ReSetKernelDS fs
+ mov ebx, dword ptr ss:[bx]
+ add ebx, 15
+ jc short gbtop1
+ and bl, not 15 ; Round to 16 byte boundary
+ cmp ebx, (16*1020*1024) ; Too big?
+ jbe short gbtop2 ; no.
+gbtop1:
+ mov ebx, 07FFFFFFFh ; Make it a ridiculous value
+gbtop2:
+ inc ax
+ jnz short gbtop2a
+ jmp gbtopx ; All done if called from GlobalCompact
+gbtop2a:
+ dec ax
+
+ mov cx, [bp].savedCS
+ push eax
+if ROM
+ push fs ; dammit! trashes registers!
+ push ebx
+ cCall GetOwner, <cx>
+ pop ebx
+ pop fs
+ mov si, ax
+else
+ cCall get_arena_pointer32,<cx>
+ mov esi,eax
+endif
+ pop eax
+
+ mov cx,hExeHead ; CX = KERNEL exe header
+ cmp fBooting,0 ; Done booting?
+ jne short gbtop3 ; No, must be KERNEL allocating then
+if ROM
+ cmp cx, si
+else
+ cmp cx,ds:[esi].pga_owner ; Is the KERNEL calling us?
+endif
+ je short gbtop3 ; Yes, let him party
+
+ and ax,not GA_INTFLAGS ; No, then cant use these flags
+ and al, NOT GA_ALLOCHIGH
+
+if ROM
+ mov es, si
+else
+ mov es,ds:[esi].pga_owner ; ES -> module database
+endif
+ cmp es:[di].ne_magic,NEMAGIC; Valid?
+ jne short gbtop2b ; No, must have brains to screw this up
+
+ test es:[di].ne_flags,NENOTP ; Yes, is it an app?
+ jnz short gbtop3 ; No, don't force it moveable
+gbtop2b:
+ or al, GA_MOVEABLE ; Force it moveable
+
+gbtop3:
+ mov cl,GA_SEGTYPE ; Isolate segment type bits in CL
+ and cl,al
+ mov [di].gi_cmpflags,al ; Save flags for gcompact
+ and [di].gi_cmpflags,CMP_FLAGS
+ or [di].gi_cmpflags, COMPACT_ALLOC ; Not a call from GlobalCompact
+
+ or dx, dx ; ReAllocating?
+ jnz short gbtop4 ; Yes, allow low
+ test al,GA_MOVEABLE ; Is this a moveable request?
+ jz short gbtop4 ; No, then go allocate low
+
+ test cl,GA_DISCCODE ; Yes, is this discardable code?
+ jz short gbtop4 ; Yes, then allocate high
+ or al,GA_ALLOCHIGH ; No, then allocate low
+ or [di].gi_cmpflags,GA_ALLOCHIGH
+
+gbtop4:
+ push ax ; Under Win1.0x ANY bit in 0Fh meant
+ mov al,HE_DISCARDABLE ; make discardable.
+ and ah,al ; Under Win2.0x ONLY 01h or 0Fh means
+ cmp ah,al ; discardable.
+ pop ax
+ jnz short gbtop4a
+ and ah,not HE_DISCARDABLE ; Yes, convert to boolean value
+ or ah,GA_DISCARDABLE
+gbtop4a:
+gbtop4b:
+ and ah,NOT GA_SEGTYPE ; Clear any bogus flags
+ or ah,cl ; Copy segment type bits
+ test ah,GA_SHAREABLE ; Shared memory request?
+ jz GetDefOwner ; No, default action
+
+if ROM
+ mov cx, si ; the code below confuses me a little
+else
+ mov cx,[bp].savedCS ; Yes, make owner same as
+ push eax
+ cCall get_arena_pointer32,<cx>
+ cmp esi,eax
+ je short @F
+ int 3
+@@:
+ pop eax
+ mov cx,ds:[esi].pga_owner ; owner of calling code segment
+endif
+gbtopx:
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+; The remainder of this file implements the exported interface to the
+; global memory manager. A summary follows:
+
+; HANDLE far PASCAL GlobalAlloc( WORD, DWORD );
+; HANDLE far PASCAL GlobalReAlloc( HANDLE, DWORD, WORD );
+; HANDLE far PASCAL GlobalFree( HANDLE );
+; HANDLE far PASCAL GlobalFreeAll( WORD );
+; char far * far PASCAL GlobalLock( HANDLE );
+; BOOL far PASCAL GlobalUnlock( HANDLE );
+; DWORD far PASCAL GlobalSize( HANDLE );
+; DWORD far PASCAL GlobalCompact( DWORD );
+; #define GlobalDiscard( h ) GlobalReAlloc( h, 0L, GMEM_MOVEABLE )
+; HANDLE far PASCAL GlobalHandle( WORD );
+; HANDLE far PASCAL LockSegment( WORD );
+; HANDLE far PASCAL UnlockSegment( WORD );
+
+
+cProc IGlobalAlloc,<PUBLIC,FAR>
+ parmW flags
+ parmD nbytes
+cBegin
+ GENTER32 ; About to modify memory arena
+
+ cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
+ test al, GACF_IGNORENODISCARD ; for selected modules
+ mov ax, flags
+ jz short @f
+ call IsKernelCalling ; needs caller's CS @ [bp+4]
+ jz short @f ; skip hack if kernel calling us
+ and al, NOT GA_NODISCARD
+@@:
+ xor dx,dx ; No handle
+ lea bx,nbytes ; Convert requested bytes to paragraphs
+ call gbtop ; ... into BX
+ call galloc
+ifdef ?CHECKMEM
+if KDEBUG
+ call CheckMem
+endif
+endif
+ CheckHeap GlobalAlloc
+ GLEAVE32
+if kdebug
+ or ax, ax
+ jnz @F
+ push ax
+ push bx
+ mov bx, seg_nbytes
+ mov ax, off_nbytes
+ krDebugOut <DEB_TRACE or DEB_krMemMan>, "GlobalAlloc(#bx#AX) failed for %ss2"
+ pop bx
+ pop ax
+@@:
+endif
+cEnd
+
+cProc IGlobalReAlloc,<PUBLIC,FAR>
+ parmW handle
+ parmD nbytes
+ parmW rflags
+cBegin
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test byte ptr handle,7
+ jnz SHORT @F
+if KDEBUG
+ Trace_Out "GlobalReAlloc:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ int 3
+endif
+ dec handle
+@@:
+
+ GENTER32 ; About to modify memory arena
+
+ cCall MyGetAppCompatFlags ; Ignore the NODISCARD flag
+ test al, GACF_IGNORENODISCARD ; for selected modules
+ mov ax, rflags
+ jz short @f
+ call IsKernelCalling ; needs caller's CS @ [bp+4]
+ jz short @f ; skip hack if kernel calling us
+ and al, NOT GA_NODISCARD
+@@:
+
+#ifdef WOW
+ push ax
+
+ ; check for suspicious dib memory
+ mov dx, handle
+ call pdref
+
+ ; check if the obj is locked
+ or ch,ch
+ jz short gr_proceed
+
+
+ ; here, check for phantom flag... this might mean
+ ; it's dib sec
+ test cl, GAH_PHANTOM
+ jz short gr_proceed
+
+ ; if we are here - mem object is locked and boogie flag is set
+ ; sufficient reason to check with wow32 to see if this is
+ ; pesky dib section
+
+ cCall FindAndReleaseDib, <handle, FUN_GLOBALREALLOC>
+
+gr_proceed:
+
+ pop ax
+#endif
+ mov dx,handle
+ ; mov ax,rflags
+ lea bx,nbytes ; Convert requested bytes to paragraphs
+ call gbtop ; ... into BX
+
+ call grealloc
+
+gr_done:
+ CheckHeap GlobalReAlloc
+ GLEAVE32
+cEnd
+
+
+cProc DiscardTheWorld,<PUBLIC,NEAR>
+cBegin
+ GENTER32
+ mov [di].gi_cmpflags, GA_DISCCODE+COMPACT_ALLOC
+ mov edx, -1
+ call gcompact
+ GLEAVE32
+cEnd
+
+
+; Returns with Z flag set if ss:[bp+4] is a kernel code segment selector.
+; Uses: DX, flags.
+
+cProc IsKernelCalling,<PUBLIC,NEAR>
+cBegin nogen
+ mov dx, [bp+4] ; CS of GlobalAlloc caller
+ cmp dx, IGROUP
+ jz @f
+ cmp dx, _NRESTEXT
+ jz @f
+ cmp dx, _MISCTEXT
+@@:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GlobalFree ;
+; ;
+; Frees the given object. If the object lives in someone elses banks ;
+; then the argument MUST be a handle entry. ;
+; ;
+; Arguments: ;
+; parmW handle ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
+; Added support for EMS and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalFree,<PUBLIC,FAR>
+ parmW handle
+ifdef WOW
+DsOnStack equ [bp][-2]
+endif
+
+; if you add any local params or make this nogen or something similar,
+; the references to [bp][-2] to access DS on stack will need to change!
+
+cBegin
+ GENTER32 ; About to modify memory arena
+ mov es, di ; We may be freeing what is in ES
+ xor ax,ax ; In case handle = 0.
+ mov dx,handle
+ or dx,dx
+ jnz @F
+ jmp nothing_to_free
+@@:
+
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test dl,7
+ jnz SHORT @F
+if KDEBUG
+ Trace_Out "GlobalFree:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ int 3
+endif
+ dec dx
+@@:
+
+ push dx
+ call pdref ; returns dx=handle, ax=selector
+ pushf ; save pdref Z flag return
+
+ifdef WOW
+;
+; [bp][-2] has been changed to DsOnStack
+;
+endif
+
+ cmp ax,DsOnStack ; Are we about to free the DS on
+ jz short yup ; the stack and GP?
+ cmp dx,DsOnStack
+ jnz short nope
+yup: xor dx,dx ; Yup, zero DS image on stack...
+ mov DsOnStack,dx
+nope:
+ popf ; flags from pdref, Z set if discarded
+ pop dx
+
+ jz @f ; discarded can be freed, but has
+ ; no arena pointer
+ or esi, esi ; Handle invalid if arena ptr = 0
+ jz nothing_to_free
+@@:
+
+ifdef WOW
+ or ch,ch
+ jz short gf_checkgicon
+
+ ; here, check for phantom flag...
+ test cl, GAH_PHANTOM
+ jz gf_checkgicon
+
+ ; sufficient reason to check with wow32 to see if this is
+ ; pesky dib section
+ push dx ; dx is the only one that needs saving
+ cCall FindAndReleaseDib, <dx, FUN_GLOBALFREE>
+ or ax, ax ; if true, then just bail out, else free...
+ pop dx
+
+ jz gf_checkgicon
+
+ ; now call the pdref again... as dx is set to selector
+ call pdref ; ret handle - also ok
+ jmps gf_notdib ; not a dib anymore...
+
+gf_checkgicon:
+
+endif
+
+if KDEBUG
+ test dl, GA_FIXED
+ jnz short freeo
+ or ch,ch ; Debugging check for count underflow
+ jz short freeo
+ pushad
+ xor bx,bx
+ kerror ERR_GMEMUNLOCK,<GlobalFree: freeing locked object>,bx,handle
+ popad
+freeo:
+endif
+
+ifdef WOW
+ test cl, GAH_CURSORICON ; call to pdref above sets cl
+ ; Note: GAH_CURSORICON is also used for Free'ing
+ ; Accelerators - a-craigj
+ jz gf_wowdde
+ push ax ; save
+ push bx
+ push dx
+ push es
+ push fs ; fs needs saving
+
+ push handle
+ push FUN_GLOBALFREE
+ call WowCursorIconOp
+ or ax, ax ; if TRUE 'free' else 'dont free, fake success'
+
+ pop fs
+ pop es
+ pop dx
+ pop bx
+ pop ax ; restore
+
+ jnz gf_notglobalicon
+
+ xor ax, ax ; fake success
+ xor cx, cx
+ jmps nothing_to_free
+
+gf_wowdde:
+ test cl, GAH_WOWDDEFREEHANDLE
+ jz gf_noticon
+ push ax
+ push bx
+ push dx
+ push es ; save these
+ push fs
+
+ push handle
+ call WowDdeFreeHandle
+ or ax, ax ; if TRUE 'free' else 'dont free, fake success'
+
+ pop fs
+ pop es
+ pop dx
+ pop bx
+ pop ax
+
+ jnz gf_notglobalicon
+
+ xor ax, ax ; fake success
+ xor cx, cx
+ jmps nothing_to_free
+
+gf_notdib:
+gf_notglobalicon:
+gf_noticon:
+endif
+ xor cx,cx ; Dont check owner field
+ call gfree
+
+nothing_to_free:
+ CheckHeap GlobalFree
+ GLEAVE32
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalFreeAll ;
+; ;
+; Frees all of the global objects belonging to the given owner. ;
+; ;
+; Arguments: ;
+; parmW id ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Sat Apr 25, 1987 10:23:13p -by- David N. Weise [davidw] ;
+; Added support for EMS and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc GlobalFreeAll,<PUBLIC,FAR>
+ parmW id
+cBegin
+ GENTER32 ; About to modify memory arena
+ mov es, di ; We may be freeing what is in ES
+ mov dx,id ; Get id to match with
+ or dx,dx ; Is it zero?
+ jnz short all1 ; No, continue
+ call GetDefOwner ; Yes, CX = default task owner to free
+ mov dx,cx
+all1:
+if SDEBUG
+ mov esi,[di].phi_first ; ES:DI points to first arena entry
+ mov cx,[di].hi_count ; CX = #entries in the arena
+all2:
+ cmp ds:[esi].pga_owner,dx
+ jne short all3
+ mov ax, ds:[esi].pga_handle
+ Handle_To_Sel al
+ push cx
+ push dx
+ cCall DebugFreeSegment,<ax,0>
+ pop dx
+ pop cx
+all3:
+ mov esi,ds:[esi].pga_next ; Move to next block
+ loop all2 ; Back for more if there (may go extra times
+ ; because of coalescing, but no great whoop)
+endif
+ call gfreeall
+
+ ; REALLY free the id selector. MSTEST setup depends on this.
+
+ pushf
+ push ax
+ push bx
+ push es
+ push di
+ mov di,id
+ and di,0FFF8h
+ mov es,gdtdsc
+ push es:[di]
+ push es:[di + 2]
+ push es:[di + 4]
+ push es:[di + 6]
+ mov word ptr es:[di],0
+ mov word ptr es:[di + 2],0
+ mov word ptr es:[di + 4],0
+ mov word ptr es:[di + 6],0
+ mov bx,id
+ DPMICALL 000Ch
+ pop es:[di + 6]
+ pop es:[di + 4]
+ pop es:[di + 2]
+ pop es:[di]
+ pop di
+ pop es
+ pop bx
+ pop ax
+ popf
+
+gf_done:
+ CheckHeap GlobalFreeAll
+ GLEAVE32
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; xhandle ;
+; ;
+; Returns the handle for a global segment. ;
+; ;
+; Arguments: ;
+; Stack = sp -> near return return address ;
+; sp+2 -> far return return address of caller ;
+; sp+6 -> segment address parameter ;
+; ;
+; Returns: ;
+; Old DS,DI have been pushed on the stack ;
+; ;
+; ZF= 1 if fixed segment. ;
+; AX = handle ;
+; ;
+; ZF = 0 ;
+; AX = handle ;
+; BX = pointer to handle table entry ;
+; CX = flags and count word from handle table ;
+; DX = segment address ;
+; ES:DI = arena header of object ;
+; DS:DI = master object segment address ;
+; ;
+; Error Returns: ;
+; AX = 0 if invalid segment address ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Oct 16, 1986 02:40:08p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc xhandle,<PUBLIC,NEAR>
+cBegin nogen
+ pop dx ; Get near return address
+ mov bx,sp ; Get seg parameter from stack
+ mov ax,ss:[bx+4]
+ cmp ax,-1 ; Is it -1?
+ jnz short xh1
+ mov ax,ds ; Yes, use callers DS
+xh1: inc bp
+ push bp
+ mov bp,sp
+ push ds ; Save DS:DI
+ push edi
+ push esi
+ SetKernelDS FS
+ mov ds,pGlobalHeap ; Point to master object
+ xor edi,edi
+ inc [di].gi_lrulock
+ push dx
+ mov dx,ax
+ call pdref
+ xchg dx,ax ; get seg address in DX
+ jz short xhandle_ret ; invalid or discarded handle
+ test al, GA_FIXED
+ jnz short xhandle_fixed
+ or ax, ax
+ jmps xhandle_ret
+xhandle_fixed:
+ xor bx, bx ; Set ZF
+xhandle_ret:
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+
+
+cProc GlobalHandleNorip,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+if KDEBUG
+ call xhandle_norip
+else
+ call xhandle
+endif
+ mov ebx, esi
+ jmp xhandlex
+cEnd nogen
+
+
+cProc IGlobalHandle,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall MyLock,<selector>
+ xchg ax, dx
+cEnd
+
+
+cProc MyLock,<PUBLIC,NEAR>
+; parmW seg
+cBegin nogen
+ mov bx, sp
+ xor ax, ax ; In case LAR fails
+ xor dx, dx
+ lar ax, ss:[bx+2]
+ jnz SHORT ML_End ; LAR failed, get out
+ test ah, DSC_PRESENT
+ jz short @F
+
+ push ds ; Do quick conversion for present
+ SetKernelDS ; selector
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall get_arena_pointer32,<ss:[bx+2]>
+ or eax, eax
+ jnz SHORT got_arena_pointer
+
+ ;** Fix for bug #9106 and (I think) #9102
+ife ROM
+ ;** If we get here, it's only because get_arena_pointer failed.
+ ;** This happens with any non-heap selector.
+ pop ds
+ jmp SHORT ML_End ;Return NULL instead of GP faulting
+else
+ ; in ROM, get-arena fails for ROM segments which do not have
+ ; arena headers, so just assume this is the case and return the
+ ; selector.
+ ;
+ mov ax, ss:[bx+2]
+ jmps ml_ret
+endif
+got_arena_pointer:
+
+ mov ax, ds:[eax].pga_handle
+ml_ret:
+ pop ds
+ mov dx, ax
+ Handle_To_Sel al
+ML_End:
+ ret 2
+
+@@:
+ pop ax ; Convert to far call for xhandle
+ push cs
+ push ax
+ call xhandle
+ xchg ax, dx
+ jmp xhandlex
+
+cEnd nogen
+
+cProc ILockSegment,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ jnz ls5 ; Ignore invalid or discarded objects
+ jmp xhandlex
+ls5:
+ test cl,GA_DISCARDABLE
+ jz short xhandlex
+ call glock
+ jmps xhandlex
+cEnd nogen
+
+
+cProc IGlobalFix,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ jz short xhandlex ; Ignore invalid or discarded objects
+ call glock
+ jmps xhandlex
+cEnd nogen
+
+
+cProc IUnlockSegment,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ jz short xhandlex ; Ignore invalid or discarded objects
+ test cl,GA_DISCARDABLE
+ jz short xhandlex
+ call gunlock
+ jmps xhandlex
+cEnd nogen
+
+cProc IGlobalUnfix,<PUBLIC,FAR>
+; parmW seg
+cBegin nogen
+ call xhandle ; Get handle
+ jz short xhandlex ; Ignore invalid or discarded objects
+ call gunlock
+ jmps xhandlex
+cEnd nogen
+
+cProc IGlobalSize,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jnz short gs1 ; Continue if valid handle
+ or dx,dx
+ jnz short gs1
+ xor ax,ax ; Return zero if invalid handle
+ jmps xhandlex
+
+gs1:
+ or esi, esi ; Can't be valid if arena ptr == 0
+ jz gs2
+ push eax
+ mov eax, ds:[esi].pga_size
+ shr eax, 4
+ mov cx, ax ; Return number paragraphs in CX
+ shr eax, 12
+ mov dx, ax
+ pop eax
+ mov ax, word ptr ds:[esi].pga_size
+ push ds
+ push dx
+ push ax
+ cCall hackcheck,<handle>
+ or ax,ax
+ jz gsN
+ pop ax
+ pop dx
+ mov ax,04000h
+ xor dx,dx
+ push dx
+ push ax
+gsN:
+ pop ax
+ pop dx
+ pop ds
+ jmps xhandlex
+gs2:
+ xor ax, ax
+ xor dx, dx
+ jmps xhandlex
+cEnd nogen
+
+cProc IGlobalFlags,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ xchg cl,ch ; Return lock count in low half
+ mov ax,cx ; Let caller do jcxz to test failure
+xhandlex:
+ call gleave
+ mov es, di ; don't return arbitrary selector
+ mov fs, di
+ pop esi
+ pop edi
+ pop ds
+ pop bp
+ dec bp
+ ret 2
+cEnd nogen
+
+if 0
+
+cProc IGlobalLock,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jz short lock1 ; Ignore invalid or discarded objects
+if KDEBUG
+ cmp ch,0FFh ; Debugging check for count overflow
+ jne short lock0
+ push bx
+ push cx
+ push dx
+ xor cx,cx
+ kerror ERR_GMEMLOCK,<GlobalLock: Object usage count overflow>,cx,bx
+ pop dx
+ pop cx
+ pop bx
+lock0:
+endif
+ test cl,GA_DISCARDABLE
+ jz short lock1
+ call glock ; Increment lock count
+lock1:
+ xor ax,ax
+ mov cx,dx
+xhandlex1:
+ jmp short xhandlex
+cEnd nogen
+
+else
+
+cProc IGlobalLock,<PUBLIC,FAR>,<ds>
+ parmW handle
+ifdef WOW
+ localW gflags
+ localW accword
+endif
+
+cBegin
+ifdef WOW
+ mov gflags,0
+endif
+ xor dx, dx ; Assume failure
+ cmp handle, -1
+ jne short @F
+ mov handle, ds
+@@:
+ lar eax, dword ptr handle
+ shr eax, 8
+ifdef WOW
+ mov accword, ax
+endif
+ test al, DSC_PRESENT ; Is it present?
+ jz short GL_exit
+ mov dx, handle ; OK, will return something
+ Handle_To_Sel dl ; Turn parameter into a selector
+ifndef WOW
+ test ah, DSC_DISCARDABLE ; Is it discardable
+ jz short GL_exit ; no, Lock is a nop
+endif
+ SetKernelDS es
+ mov ds, pGlobalHeap
+ cCall get_arena_pointer32,<dx> ; Discardable, get its arena
+ or eax, eax
+ jz short GL_exit ; No arena, assume an alias
+ifdef WOW
+ mov cl, ds:[eax].pga_flags
+ mov byte ptr gflags, cl
+ test accword, DSC_DISCARDABLE SHL 8
+ jz GL_exit
+endif
+ inc ds:[eax].pga_count ; Finally, do the lock
+if KDEBUG
+ jnz short GL_exit ; Rip if we overflow
+ push bx
+ mov bx, handle
+ xor cx,cx
+ kerror ERR_GMEMLOCK,<GlobalLock: Object usage count overflow>,cx,bx
+ pop bx
+endif
+ UnSetKernelDS es
+
+GL_exit:
+ifdef WOW
+ test gflags, GAH_CURSORICON
+ jz GL_NotIcon
+ push dx ; save
+ push handle ; arg for CursorIconLockOp
+ push FUN_GLOBALLOCK ; func id
+ call WowCursorIconOp
+ pop dx ; restore
+
+GL_NotIcon:
+endif
+ xor ax, ax
+ mov es, ax ; Clean out ES
+ mov cx, dx ; HISTORY - someone probably does a jcxz
+cEnd
+endif
+
+cProc IGlobalUnlock,<PUBLIC,FAR>,<ds>
+ parmW handle
+ifdef WOW
+ localW gflags
+ localW accword
+endif
+
+cBegin
+ mov gflags,0
+ cmp handle, -1
+ jne short @F
+ mov handle, ds
+@@:
+;
+; Does this thing have any ring bits or LDT bit? If not, then it
+; could be a selector incorrectly converted to a handle.
+;
+ test byte ptr handle,7
+ jnz SHORT @F
+if KDEBUG
+ Trace_Out "GlobalUnlock:"
+ push seg ThisIsForTurboPascal
+ push offset ThisIsForTurboPascal
+ cCall OutputDebugString
+ int 3
+endif
+ dec handle
+@@:
+ xor cx, cx ; Assume zero lock count
+ lar eax, dword ptr handle
+ shr eax, 8
+ifdef WOW
+ mov accword, ax
+endif
+ test al, DSC_PRESENT ; Is it present?
+ jz short GU_exit ; no, must be discarded, return 0:0
+ifndef WOW
+ test ah, DSC_DISCARDABLE ; Is it discardable
+ jz short GU_exit ; no, Lock is a nop
+endif
+ SetKernelDS es
+ mov ds, pGlobalHeap
+ cCall get_arena_pointer32,<handle> ; Discardable, get its arena
+ or eax, eax
+ jz short GU_exit ; No arena, assume an alias
+ifdef WOW
+ push cx
+ mov cl,ds:[eax].pga_flags
+ mov byte ptr gflags, cl
+ pop cx
+ test accword, DSC_DISCARDABLE SHL 8
+ jz GU_exit
+endif
+ mov cl, ds:[eax].pga_count ; Get current count
+ dec cl
+ cmp cl, 0FEh
+ jae short @F
+ dec ds:[eax].pga_count ; Finally, do the unlock
+ jmps GU_Exit
+@@:
+if KDEBUG
+ push bx ; then the count is wrong.
+ push dx
+ mov bx, handle
+ xor cx,cx
+ kerror ERR_GMEMUNLOCK,<GlobalUnlock: Object usage count underflow>,cx,bx
+ pop dx
+ pop bx
+endif
+ xor cx, cx
+ UnSetKernelDS es
+
+GU_exit:
+ifdef WOW
+ test gflags, GAH_CURSORICON
+ jz GUL_NotIcon
+ push cx ; save
+ push handle ; arg for CursorIconLockOp
+ push FUN_GLOBALUNLOCK ; UnLocking
+ call WowCursorIconOp
+ pop cx ; restore
+
+GUL_NotIcon:
+endif
+ xor ax, ax
+ mov es, ax ; Clean out ES
+ mov ax, cx
+
+ ; Smalltalk V version 1.1 has a bug where they depend on dx containing
+ ; the handle as it did in 3.0. Sinc STalk is a 386 only app, this is
+ ; only put into the 386 kernel
+ mov dx, handle
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalWire ;
+; ;
+; Locks a moveable segment and moves it down as low as possible. ;
+; This is meant for people who are going to be locking an object ;
+; for a while and wish to be polite. It cannot work as a general ;
+; panacea, judgement is still called for in its use! ;
+; ;
+; Arguments: ;
+; WORD object handle ;
+; ;
+; Returns: ;
+; DWORD object address ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; xhandle ;
+; gmovebusy ;
+; ;
+; History: ;
+; ;
+; Wed Dec 03, 1986 01:07:13p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalWire,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+
+if KDEBUG
+ push ds
+ SetKernelDS
+ cmp [fBooting], 0
+ jnz shutup
+ push bx
+ mov bx, sp
+ mov bx, ss:[bx+8]
+ krDebugOut <DEB_WARN OR DEB_KrMemMan>, "GlobalWire(#BX of %BX2) (try GlobalLock)"
+ pop bx
+shutup:
+ pop ds
+ UnSetKernelDS
+endif
+ call xhandle
+ jz short gw_done ; Ignore invalid or discarded objects
+ call gwire ; Copy it low if possible
+ inc ds:[esi].pga_count ; Lock it down.
+ test ds:[esi].pga_flags,GA_DISCCODE
+ jz short not_disccode
+ call glrudel
+ and ds:[esi].pga_flags,NOT GA_DISCCODE
+not_disccode:
+ mov ax, ds:[esi].pga_handle
+ Handle_To_Sel al ; Return address.
+gw_done:
+ mov dx,ax
+ xor ax,ax ; Make address SEG:OFF.
+ jmp xhandlex
+cEnd nogen
+
+
+
+cProc gwire,<PUBLIC,NEAR>
+cBegin nogen
+ ReSetKernelDS fs
+ or Kernel_Flags[1],kf1_MEMORYMOVED
+ push ax ; Save handle
+ push cx
+ test cl,GA_DISCARDABLE
+ jz short @F
+ inc ds:[esi].pga_count ; don't want to discard if discardable
+@@: xor ax,ax ; Try to get a fixed segment.
+ mov ebx,ds:[esi].pga_size
+ mov cx,ds:[esi].pga_owner
+
+ call gsearch ; AX = segment
+ pop cx
+ pop bx ; Object handle.
+ push eax ; Return from gsearch
+ cCall get_arena_pointer32,<bx> ; Get arena header, gsearch may
+ ; have moved the global object!
+ mov esi,eax ; ESI is old block
+ test cl,GA_DISCARDABLE
+ jz short @F
+ dec ds:[esi].pga_count ; undo lock
+@@:
+ pop eax ; EAX is new block
+ or eax,eax
+ push bx ; Handle
+ jz short lock_in_place ; Couldn't get memory.
+ mov ebx, ds:[eax].pga_address
+ cmp ebx, ds:[esi].pga_address
+ jbe short ok_to_move ; Let's not move it up in memory!!
+ cCall PreAllocArena
+ jz short lock_in_place
+
+ push esi
+ mov esi, eax
+ xor edx, edx
+ call gmarkfree
+ pop esi
+ jmp short lock_in_place
+
+ok_to_move:
+ mov edx, esi
+ mov esi, eax
+ mov ebx,ga_next ; This is always an exact fit.
+ call gmovebusy ; Wire it on down.
+
+lock_in_place:
+ pop bx ; Handle
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; GlobalUnWire ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Sep 16, 1987 04:28:49p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalUnWire,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle
+ jz short guw_done
+if 0
+ mov bx, ax
+ sel_check bx
+ SetKernelDS es
+ mov es, gdtdsc
+ UnSetKernelDS es
+ test byte ptr es:[bx+6], 10h
+ jz short guw_not_disccode
+ test byte ptr es:[bx+5], 8 ; Is it code?
+ jz short guw_not_disccode ; nope, no point setting it
+else
+ lar ebx, eax
+ shr ebx, 8
+ test bh, DSC_DISCARDABLE
+ jz short guw_not_disccode
+ test bl, DSC_CODE_BIT ; Is it code?
+ jz short guw_not_disccode ; nope, no point setting it
+endif
+ or ds:[esi].pga_flags,GA_DISCCODE
+ call glruadd
+guw_not_disccode:
+if KDEBUG
+ cmp ch,00h ; Debugging check for count underflow
+ jne short unlock1
+ push bx ; then the count is wrong.
+ push cx
+ push dx
+ xor cx,cx
+ kerror ERR_GMEMUNLOCK,<GlobalUnWire: Object usage count underflow>,cx,bx
+ pop dx
+ pop cx
+ pop bx
+unlock1:
+endif
+ call gunlock
+ mov ax, 0FFFFh ; TRUE
+ jcxz guw_done
+ inc ax ; FALSE
+guw_done:
+ jmp xhandlex
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GlobalCompact ;
+; ;
+; Compacts the global arena until a free block of the requested size ;
+; appears. Contrary to the toolkit it ALWAYS compacts! ;
+; ;
+; Arguments: ;
+; DWORD minimum bytes wanted ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+; Wed Dec 03, 1986 01:09:02p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc GlobalCompact,<PUBLIC,FAR>
+ parmD minBytes
+ localD DPMIbytes
+cBegin
+ GENTER32 ; About to modify memory arena
+ CheckHeap GlobalCompact
+
+ call GetDPMIFreeSpace ; EAX = largest free DPMI block
+ and ax, GA_MASK_BYTES
+ mov ebx, eax
+ clc
+ call galign ; align size
+ mov eax, edx ; EAX = aligned DPMI block
+ mov DPMIbytes, eax
+ cmp eax, minBytes ; Q: Enough to satisfy request?
+ jb SHORT GCReallyCompact ; N: Really compact heap
+ cmp eax, 512*1024 ; Q: Less than 1/2 Mb of DPMI mem?
+ jnb SHORT GCWorked
+
+GCReallyCompact:
+if KDEBUG
+ push ax
+ push bx
+ mov ax, seg_minBytes
+ mov bx, off_minBytes
+ krDebugOut DEB_WARN, "%SS2 GlobalCompact(#ax#BX), discarding segments"
+ pop bx
+ pop ax
+endif
+ mov ax,-1
+ lea bx,minBytes
+ call gbtop
+ assumes es, nothing
+ clc ; galign should be called with CF = 0
+ call galign
+ call gavail ; Returns paragraphs in DX:AX
+
+ cmp eax, DPMIbytes ; Return max of gavail or DMPI free
+ jae SHORT GCWorked ; space
+ mov eax, DPMIbytes
+
+GCWorked:
+ mov edx, eax
+ shr edx, 16
+ mov cx, ax
+ or cx, dx
+
+ GLEAVE32
+
+ pushad
+ call ShrinkHeap
+ popad
+
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalNotify ;
+; ;
+; This sets a procedure to call when a discardable segment belonging ;
+; to this task gets discarded. The discardable object must have been ;
+; allocated with the GMEM_DISCARDABLE bit set. ;
+; ;
+; Arguments: ;
+; parmD NotifyProc ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Jun 23, 1987 10:16:32p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc IGlobalNotify,<PUBLIC,FAR>
+
+ parmD NotifyProc
+cBegin
+ push ds
+ les bx,NotifyProc ; verify pointer
+ SetKernelDS
+ mov ds,curTDB
+ UnSetKernelDS
+ mov word ptr ds:[TDB_GNotifyProc][2],es
+ mov word ptr ds:[TDB_GNotifyProc][0],bx
+ pop ds
+cEnd
+
+cProc GlobalMasterHandle,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ax,hGlobalHeap
+ mov dx,pGlobalHeap
+ UnSetKernelDS
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetTaskDS ;
+; ;
+; Gets the segment of the current task's DS. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AX = selector. ;
+; DX = selector. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Thu Jun 25, 1987 10:52:10p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc GetTaskDS,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ds,curTDB
+ UnsetKernelDS
+ mov ax,ds:[TDB_Module]
+ mov dx,ax
+ pop ds
+ ret
+cEnd nogen
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalLRUOldest,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jz short xhandlex2
+ call glrubot
+xhandlex2:
+ jmp xhandlex
+cEnd nogen
+
+
+cProc IGlobalLRUNewest,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle ; Call ghandle with handle in DX
+ jz short xhandlex2
+ call glrutop
+ jmp xhandlex
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; SwitchStackTo ;
+; ;
+; Switched to the given stack, and establishes the BP chain. It also ;
+; copies the last stack arguments from the old stack to the new stack. ;
+; ;
+; Arguments: ;
+; parmW new_ss ;
+; parmW new_sp ;
+; parmW stack_top ;
+; ;
+; Returns: ;
+; A new stack! ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 22, 1987 08:42:05p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProcVDO SwitchStackTo,<PUBLIC,FAR>
+; parmW new_ss
+; parmW new_sp
+; parmW stack_top
+cBegin nogen
+
+ SetKernelDS es
+ FCLI
+ mov GSS_SI,si
+ mov GSS_DS,ds
+ pop word ptr GSS_RET[0] ; get the return address
+ pop word ptr GSS_RET[2]
+ assumes es, nothing
+ pop ax ; stack_top
+ pop bx ; new_sp
+ pop dx ; new_ss
+ mov si,bp ; Calculate # of parameters on stack.
+ dec si ; remove DS
+ dec si
+ mov cx,si
+ sub cx,sp
+ shr cx,1
+ push bp ; save BP
+ smov es,ss
+ mov ds,dx ; new_ss
+ mov ds:[2],sp
+ mov ds:[4],ss
+ mov ds:[pStackTop],ax
+ mov ds:[pStackMin],bx
+ mov ds:[pStackBot],bx
+
+; switch stacks
+
+ mov ss,dx
+ mov sp,bx
+ mov bp,bx
+ xor ax,ax
+ push ax ; null terminate bp chain
+ jcxz no_args
+copy_args:
+ dec si
+ dec si
+ push es:[si]
+ loop copy_args
+no_args:
+ SetKernelDS
+ mov es,curTDB
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+ push GSS_RET.sel
+ push GSS_RET.off ; get the return address
+ mov si,GSS_SI
+ mov ds,GSS_DS
+ FSTI
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; SwitchStackBack ;
+; ;
+; Switches to the stack stored at SS:[2], and restores BP. Preserves ;
+; AX and DX so that results can be passed back from the last call. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; The old stack! ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Sep 22, 1987 09:56:32p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SwitchStackBack,<PUBLIC,FAR>
+cBegin nogen
+
+ push ds
+ SetKernelDS
+ FCLI
+ pop GSS_DS
+ pop GSS_RET.off ; get the return address
+ pop GSS_RET.sel
+ xor bx,bx
+ xor cx,cx
+ xchg bx,ss:[4]
+ xchg cx,ss:[2]
+ mov ss,bx
+ mov sp,cx
+ mov es,curTDB
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+ pop bp
+ push GSS_RET.sel
+ push GSS_RET.off ; get the return address
+ mov ds,GSS_DS
+ UnSetKernelDS
+ FSTI
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; GetFreeMemInfo ;
+; ;
+; Get free and unlocked pages in paging system ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; DX Free pages ;
+; AX Unlocked pages ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetFreeMemInfo,<PUBLIC,FAR>,<di>
+ localV mem_info,30h
+cBegin
+ mov ax, -1
+ mov dx, ax
+ SetKernelDS es
+ test byte ptr WinFlags[1], WF1_PAGING
+ jz short gfmi_no_info
+ lea di, mem_info
+ smov es, ss
+ UnSetKernelDS es
+ DPMICALL 0500h ; Get Free Memory Information
+ jc short gfmi_no_info
+ mov ax, es:[di][10h]
+ mov dx, es:[di][14h]
+gfmi_no_info:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GetFreeSpace ;
+; ;
+; Calculates the current amount of free space ;
+; ;
+; Arguments: ;
+; flags - ignored for non-EMS system ;
+; ;
+; Returns: ;
+; DX:AX Free space in bytes ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed 26-Apr-1989 15:33:18 -by- David N. Weise [davidw] ;
+; Added the zero'ing of ES on exit. ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IGetFreeSpace,<PUBLIC,FAR>
+ parmW flags
+cBegin
+ GENTER32
+
+ call GetDPMIFreeSpace ; EDX = Free DPMI heap space
+
+ mov esi, [di].phi_first
+gfs_loop:
+ mov esi, ds:[esi].pga_next
+ cmp ds:[esi].pga_sig, GA_ENDSIG
+ je short gfs_last ; End of heap
+ mov ax, ds:[esi].pga_owner
+ cmp ax, GA_NOT_THERE
+ je short gfs_loop ; Nothing there
+ or ax, ax ; Free?
+ jz short gfs_include ; yes, include
+ test flags, 2 ; Ignore discardable?
+ jnz short gfs_loop ; yes.
+ mov bx, ds:[esi].pga_handle
+ test bl, GA_FIXED
+ jnz short gfs_loop ; Fixed block if odd
+ cmp ds:[esi].pga_sig, 0
+ jne short gfs_loop ; skip if locked
+ lar ebx, ebx
+ shr ebx, 8
+ test bh, DSC_DISCARDABLE ; include if discardable
+ jz short gfs_loop
+gfs_include:
+ add edx, ds:[esi].pga_size
+ jmps gfs_loop
+
+gfs_last:
+ test flags, 2 ; Ignoring discardable?
+ jnz short @F ; yes, then ignore fence
+ sub edx, [di].gi_reserve ; Subtract out that above fence
+@@:
+ sub edx, 10000h ; Lose 64k of it for fun
+ jns short gfs_positive ; Return zero if we
+ xor edx, edx ; went negative!
+gfs_positive:
+
+;
+; Now check to see if this app has troubles if the value gets too huge.
+; 61a8000h is 100MB
+;
+WOW_FREE_SPACE_CAP equ 61a8000h
+
+ push edx
+ cCall MyGetAppWOWCompatFlags ; check if we need to cap it
+ test dx, WOWCF_LIMIT_MEM_FREE_SPACE SHR 16
+ pop edx
+ jz short @f
+
+ cmp edx, WOW_FREE_SPACE_CAP
+ jb short @f
+ mov edx, WOW_FREE_SPACE_CAP
+@@:
+
+ mov eax, edx ; Return in DX:AX
+ shr edx, 16
+
+ GLEAVE32
+cEnd
+
+
+
+;-----------------------------------------------------------------------;
+; GetDPMIFreeSpace ;
+; ;
+; Calculates the current amount of DPMI free space ;
+; ;
+; Arguments: ;
+; None ;
+; ;
+; Returns: ;
+; EAX = Size of largest free block in bytes ;
+; EDX = Free DPMI space in bytes ;
+; DI = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+ifdef WOW
+cProc GetDPMIFreeSpace,<PUBLIC,NEAR>,<edi,esi,cx>
+cBegin
+ push bp
+ mov cx, sp
+ and cx, 3 ;prepare to align on dword
+ add cx, SIZE GMEMSTATUS_block ;length to adjust sp
+ sub sp, cx
+ mov bp, sp ;base pointer to structure
+
+ mov dwLength[bp], SIZE GMEMSTATUS_block
+ cCall GlobalMemoryStatus,<ss,bp> ;Call NT To get Memory Info
+ mov edx,dwAvailPhys[bp] ; if (dwAvailVirtual < dwAvailPhys +dwAvailPagefile)
+ add edx,dwAvailPageFile[bp] ; return(dwAvailVirtual
+ cmp dwAvailVirtual[bp],edx ; else
+ ja @f ; return(dwAvailPhys +dwAvailPagefile)
+
+ mov edx,dwAvailVirtual[bp]
+@@:
+ mov eax,dwAvailPhys[bp] ; Not entirely accurate equivalent
+ ; of Windows, should be OK
+ add sp, cx ;restore stack pointer
+ pop bp
+else; NOT WOW
+cProc GetDPMIFreeSpace,<PUBLIC,NEAR>
+ localV mem_info,30h
+cBegin
+ xor edx, edx ; In case of DPMI failure
+ lea di, mem_info
+ smov es, ss
+ DPMICALL 0500h ; Get Free Memory Information
+ jc short xoredxedx
+
+ mov edx, dword ptr mem_info[14h] ; Number of free pages (if not paging)
+
+ mov eax, dword ptr mem_info[20h] ; Paging file size
+ inc eax
+ cmp eax, 1 ; 0 or -1?
+ jbe short not_paging ; yes, no paging
+ lea edx, [eax-1] ; no, paging file size in edx
+;
+; Calculation is:
+; (Paging file size + Total physical pages)
+; - (Total linear space - Free linear space)
+;
+
+; Actually, there are two limits to total swap area. (Since Win386
+; isn't a planned product, it first allocates data structures for
+; linear memory, then discovers how big the page file is.)
+; First, find out how many pages we have - this is the sum of
+; physical pages owned by DPMI, and pages in the disk swap file.
+; Next, find out how many pages are allowed for in the linear
+; address data structure. The lesser of these two values is
+; the limit. Next, subtract the already allocated pages. This
+; is found as the difference between total linear, and free linear
+; space. The final result is close to the amount of allocatable
+; virtual memory.
+
+ add edx, dword ptr mem_info[18h] ; Total physical pages
+ cmp edx, dword ptr mem_info[0ch] ; Allocatable linear memory
+ jl short @F
+ mov edx, dword ptr mem_info[0ch] ; take the smaller
+@@:
+
+ add edx, dword ptr mem_info[1Ch] ; Free linear space
+ sub edx, dword ptr mem_info[0Ch] ; Total linear space
+
+not_paging:
+
+ mov eax, dword ptr mem_info ; size of largest free block
+
+ shl edx, 12 ; Convert to bytes
+ jns short no_info ; Went negative?
+ xor edx, edx
+endif: WOW
+no_info:
+;
+; !!! HACK ALERT !!!
+; We don't actually want to grab all the memory from DPMI, because then
+; we won't be able to allocate DPMI memory for arena tables, if we
+; need them, and WIN386 won't be able to grow the LDT.
+;
+ sub edx,10000h
+ ja @F
+xoredxedx:
+ xor edx,edx
+@@:
+ cmp eax,edx
+ jb @F
+ mov eax,edx
+@@:
+ xor di, di
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GlobalDOSAlloc
+;
+; Allocates memory that is accessible by DOS.
+;
+; Entry:
+; parmD nbytes number of bytes to alloc
+;
+; Returns:
+; AX = memory handle
+; DX = DOS segment paragraph address
+;
+; History:
+; Tue 23-May-1989 11:30:57 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalDOSAlloc,<PUBLIC,FAR>,<di,si>
+ parmD nbytes
+cBegin
+ mov ax,GA_ALLOC_DOS shl 8
+ cCall IGlobalAlloc,<ax,nbytes>
+ xor dx, dx ; In case of error return
+ or ax, ax
+ jz short gda_exit
+ push ax
+ cCall get_physical_address,<ax>
+REPT 4
+ shr dx, 1
+ rcr ax, 1
+ENDM
+ mov dx, ax
+ pop ax
+gda_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalDOSFree
+;
+; Frees memory allocated by GlobalDOSAlloc.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 17:48:03 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GlobalDOSFree,<PUBLIC,FAR>,<di,si>
+
+ parmW handle
+cBegin
+ cCall IGlobalFree,<handle>
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalPageLock
+;
+; Page locks the memory associated with the Handle.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+; AX = new lock count
+;
+; History:
+; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalPageLock,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle
+ or ax,ax
+ jz short gpl_fail ; Ignore invalid or discarded objects
+
+ cmp [esi].pga_pglock, 0FFh ; About to overflow?
+ je short gpl_over
+
+ push dx
+ call gwire ; Move it LOW!
+ pop bx
+
+ DPMICALL 4 ; Page Lock it
+ jc short gpl_fail
+
+ inc [esi].pga_count
+ inc [esi].pga_pglock
+ movzx ax, [esi].pga_pglock
+ jmp xhandlex
+
+gpl_over:
+
+if KDEBUG
+ push bx
+ push cx
+ push dx
+ xor cx,cx
+ kerror ERR_GMEMLOCK,<GlobalPageLock: Lock count overflow>,cx,bx
+ pop dx
+ pop cx
+ pop bx
+endif
+
+gpl_fail:
+ xor ax,ax
+ jmp xhandlex
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GlobalPageUnlock
+;
+; Page unlocks the memory associated with the Handle.
+;
+; Entry:
+; parmW handle
+;
+; Returns:
+; AX = new lock count
+;
+; History:
+; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGlobalPageUnlock,<PUBLIC,FAR>
+; parmW handle
+cBegin nogen
+ call xhandle
+ or ax,ax
+ jz short gpu_fail ; Ignore invalid or discarded objects
+
+ cmp [esi].pga_pglock, 0 ; About to underflow?
+ je short gpu_under
+
+ mov bx, dx
+ DPMICALL 5
+ jc short gpu_fail
+
+ dec [esi].pga_count
+ dec [esi].pga_pglock
+ movzx ax, [esi].pga_pglock
+ jmp xhandlex
+
+gpu_under:
+
+if KDEBUG
+ xor ax,ax
+ push bx
+ push cx
+ push dx
+ xor cx,cx
+ kerror ERR_GMEMUNLOCK,<GlobalPageUnlock: Lock count underflow>,cx,bx
+ pop dx
+ pop cx
+ pop bx
+endif
+
+gpu_fail:
+ xor ax, ax
+ jmp xhandlex
+
+cEnd nogen
+
+ifdef WOW
+;--------------------------------------------------------------------------;
+;
+; Similar to GlobalFlags
+;
+;--------------------------------------------------------------------------;
+
+cProc SetCursorIconFlag,<PUBLIC,FAR>,<ds,es,esi>
+ parmW handle
+ parmW fSet
+cBegin
+ SetKernelDS es
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall get_arena_pointer32,<handle> ; get the owner
+ or eax,eax
+ jz sf_error
+
+ mov esi,eax
+ mov ax,fSet
+ or ax,ax
+ jz sf_unset
+ or ds:[esi].pga_flags, GAH_CURSORICON ;cursor, icon, or accelerator
+ jmps sf_error
+sf_unset:
+ and ds:[esi].pga_flags, NOT GAH_CURSORICON
+sf_error:
+ xor ax,ax
+cEnd
+
+
+
+;--------------------------------------------------------------------------;
+;
+; Stamp the 01h in globalarena for DDE handles. This is GAH_PHANTOM flag
+; which is not used any longer.
+;
+;--------------------------------------------------------------------------;
+
+cProc SetDdeHandleFlag,<PUBLIC,FAR>,<ds,es,esi>
+ parmW handle
+ parmW fSet
+cBegin
+ SetKernelDS es
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall get_arena_pointer32,<handle> ; get the owner
+ or eax,eax
+ jz sd_error
+
+ mov esi,eax
+ mov ax,fSet
+ or ax,ax
+ jz sd_unset
+ or ds:[esi].pga_flags, GAH_WOWDDEFREEHANDLE
+ jmps sd_error
+
+sd_unset:
+ and ds:[esi].pga_flags, NOT GAH_WOWDDEFREEHANDLE
+
+sd_error:
+ xor ax,ax
+cEnd
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3glru.asm b/private/mvdm/wow16/kernel31/3glru.asm
new file mode 100644
index 000000000..17cfd9c2a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3glru.asm
@@ -0,0 +1,593 @@
+ TITLE GLRU - Primitives for LRU management
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+.list
+
+.386p
+
+DataBegin
+
+externB Kernel_InDOS
+externB Kernel_flags
+;externW curTDB
+externW loadTDB
+externW pGlobalHeap
+;externW hExeSweep
+;externW WinFlags
+
+if ROM
+externW gdtdsc
+endif
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+
+externNP DPMIProc
+
+ife ROM
+externW gdtdsc
+endif
+
+;-----------------------------------------------------------------------;
+; lrusweep ;
+; ;
+; Searches all of the exe headers in the system for segments that have ;
+; been accessed since the last time through. For each segment found ;
+; its referenced byte is reset and that segment is moved to the top ;
+; of the lru chain. This routine is called (default) every 4 timer ;
+; ticks from the int 8 handler. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,ES ;
+; ;
+; Calls: ;
+; glrutop ;
+; ;
+; History: ;
+; ;
+; Tue Apr 21, 1987 06:22:41p -by- David N. Weise [davidw] ;
+; Added the check for discarded segments. ;
+; ;
+; Wed Apr 08, 1987 11:00:59a -by- David N. Weise [davidw] ;
+; Made it clear only the curTask's private handle table. ;
+; ;
+; Wed Feb 18, 1987 08:13:35p -by- David N. Weise [davidw] ;
+; Added the sweeping of the private handle tables. ;
+; ;
+; Tue Feb 10, 1987 02:11:40a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lrusweep,<PUBLIC,FAR>
+cBegin nogen
+
+ push edx
+ push edi
+ push esi
+ push ds
+ push es
+ push fs
+ xor edx,edx
+ xor edi,edi
+ SetKernelDS fs
+
+; [notes from code review 4/91, added by donc 4/16/91
+; 1) should check WinFlags1 for WF_PAGING,
+; 2) insist on direct LDT access
+; 3) try assembling without DPMI
+; 4) have LRUSweepFreq= setting in .ini file to control update rate
+; ]
+ ; Excuses not to do the sweep:
+ cmp kernel_InDOS,0 ; SMARTDrive and EMS may be present
+ jnz short dont_do_it ; => disk buffers over the code segs
+ cmp di,loadTDB ; Ignore interrupt if loading task
+ jnz short dont_do_it
+ mov ds,pGlobalHeap
+ cmp di,ds:[di].gi_lrulock ; Ignore interrupt if inside memory
+ jz short do_it ; manager
+
+dont_do_it:
+ jmp sweepdone
+
+do_it:
+ mov cx, ds:[di].gi_lrucount
+ jcxz dont_do_it
+ mov esi, ds:[di].gi_lruchain
+
+ mov bx, gdtdsc
+ or bx, bx ; See if we can poke at the LDT
+ jz short sweep_loop_dpmi ; no, must use DPMI calls
+ mov es, bx ; yes, ES points to the LDT
+
+
+ ; Direct LDT access loop
+sweep_loop:
+ mov esi, [esi].pga_lrunext
+ mov bx, [esi].pga_handle
+
+ sel_check bx
+
+if KDEBUG
+ test es:[bx].dsc_hlimit, DSC_DISCARDABLE ; Ensure it really is discardable
+ jnz short sweep_ok
+ Debug_Out "lrusweep: Bad lru entry"
+sweep_ok:
+endif
+
+ btr word ptr es:[bx].dsc_access, 0 ; Test and reset accessed bit
+.errnz DSC_ACCESSED-1
+ jnc short sweep_next
+
+ call glrutop ; Accessed objects are most recently used
+
+sweep_next:
+ loop sweep_loop
+ jmps sweepdone
+
+
+ ; DPMI loop
+sweep_loop_dpmi:
+ mov esi, [esi].pga_lrunext
+ mov bx, [esi].pga_handle
+ lar edx, ebx
+ shr edx, 8 ; Access bits in DX
+
+if KDEBUG
+ test dh, DSC_DISCARDABLE ; Ensure it really is discardable
+ jnz short sweep_ok_dpmi
+ Debug_Out "lrusweep: Bad lru entry"
+sweep_ok_dpmi:
+endif
+
+ btr dx, 0 ; Segment accessed?
+.errnz DSC_ACCESSED-1
+ jnc short sweep_next_dpmi ; no, leave it where it is on LRU list
+
+ push cx
+ mov cx, dx
+ DPMICALL 0009h ; Set access word
+ pop cx
+
+ call glrutop ; Accessed objects are most recently used
+
+sweep_next_dpmi:
+ loop sweep_loop_dpmi
+
+sweepdone:
+ pop fs
+ pop es
+ pop ds
+ pop esi
+ pop edi
+ pop edx
+ ret
+ UnSetKernelDS fs
+cEnd nogen
+
+
+
+
+;
+; Entry:
+; DI == 0
+; DS:SI.gi_lruchain -> head of list
+; ES:0 -> arena header of object to insert
+; DX = 0 => insert at head of list
+; !=0 => insert at tail of list
+;
+; Exit:
+; BX,DX destroyed
+;
+cProc LRUInsert,<PUBLIC,NEAR>
+cBegin nogen
+ inc ds:[di].gi_lrucount ; Increment count of LRU entries
+ mov ebx,ds:[di].gi_lruchain ; BX = head of list
+ or dx,dx ; Inserting at head of chain?
+ jnz short lruins0 ; No, tail so dont update head
+ mov ds:[di].gi_lruchain,esi ; Yes, make new one the new head
+lruins0:
+ or ebx,ebx ; List empty?
+ jnz short lruins1
+ mov ds:[esi].pga_lruprev,esi; Yes, make circular
+ mov ds:[esi].pga_lrunext,esi
+ mov ds:[di].gi_lruchain,esi
+ ret
+lruins1:
+ mov edx,esi ; DX = new
+ xchg ds:[ebx].pga_lruprev,edx
+ mov ds:[edx].pga_lrunext,esi
+
+ mov ds:[esi].pga_lruprev,edx
+ mov ds:[esi].pga_lrunext,ebx
+
+ ret
+cEnd nogen
+
+
+
+
+;
+; Entry:
+; DI == 0
+; DS:DI.gi_lruchain -> head of list
+; DS_ESI -> arena header of object to delete
+;
+; Exit:
+; EBX,EDX destroyed
+;
+;
+cProc LRUDelete,<PUBLIC,NEAR>
+cBegin nogen
+
+;
+; This is basically a consistency check, in case we don't fix
+; GlobalRealloc() for 3.1.
+;
+ push eax
+ mov eax,ds:[esi].pga_lrunext
+ or eax,ds:[esi].pga_lruprev
+ pop eax
+ jz lrudel_ret
+
+ dec ds:[di].gi_lrucount ; Decrement count of LRU entries
+ jnz short lrudel0
+ mov ds:[di].gi_lruchain,edi ; List empty, zero LRU chain.
+ mov ds:[esi].pga_lruprev,edi; Zero pointers in deleted object
+ mov ds:[esi].pga_lrunext,edi
+ ret
+lrudel0:
+ mov edx,esi
+ cmp ds:[di].gi_lruchain,edx ; Are we deleting the head?
+ jne short lrudel1
+ mov edx,ds:[esi].pga_lrunext
+ mov ds:[di].gi_lruchain,edx ; Yes, make it point to the next one
+lrudel1:
+ xor ebx,ebx ; Zero pointers in deleted object
+ xchg ds:[esi].pga_lrunext,ebx
+
+ xor edx,edx
+ xchg ds:[esi].pga_lruprev,edx
+ mov ds:[edx].pga_lrunext,ebx
+ mov ds:[ebx].pga_lruprev,edx
+lrudel_ret:
+ ret
+cEnd nogen
+
+
+
+
+
+cProc glruSetup,<PUBLIC,NEAR>
+cBegin nogen
+ mov bx,ds:[esi].pga_handle
+ test bl, GA_FIXED
+ jz short gsmoveable
+ xor bx, bx ; Set ZF
+ jmps gsdone
+gsmoveable:
+ push ebx
+ lar ebx, ebx
+ test ebx, DSC_DISCARDABLE SHL 16
+ pop ebx
+ jz short gsdone
+ or sp,sp
+gsdone:
+ ret
+cEnd nogen
+
+
+
+
+;-----------------------------------------------------------------------;
+; glrutop ;
+; ;
+; Moves a discardable object to the head of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = global arena of moveable object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:20:10p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrutop,<PUBLIC,NEAR>
+cBegin nogen
+ push ebx
+ push edx
+ push esi
+ call glruSetup
+ jz short glrutop1
+
+ call LRUDelete
+ xor dx,dx ; DX == 0 means insert at head
+ call LRUInsert
+glrutop1:
+ pop esi
+ pop edx
+ pop ebx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glrubot ;
+; ;
+; Moves a discardable object to the tail of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = global arena of moveable object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:20:10p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrubot,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+ call glruSetup
+ jz short glrubot1
+
+ call LRUDelete
+ mov dx,sp ; DX != 0 means insert at tail
+ call LRUInsert
+glrubot1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+
+
+;-----------------------------------------------------------------------;
+; glruadd ;
+; ;
+; Adds a discardable object to the head of the LRU chain. ;
+; ;
+; Arguments: ;
+; DS:DI = address of global heap info ;
+; ES:DI = arena header of object ;
+; ;
+; Returns: ;
+; Updated LRU chain ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:23:35p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glruadd,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+
+ call glruSetup
+ jz short glruadd1
+
+ xor dx,dx ; DX == 0 means insert at head
+ call LRUInsert
+glruadd1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glrudel ;
+; ;
+; Removes a discardable object from the LRU chain. ;
+; ;
+; Arguments: ;
+; ES:DI = arena header of object ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; Nothing. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Mon Oct 27, 1986 04:36:49p -by- David N. Weise [davidw] ;
+; Rewrote it to eliminate the handle table as intermediary. ;
+;-----------------------------------------------------------------------;
+
+cProc glrudel,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push dx
+ push si
+
+ call glruSetup
+ jz short glrudel1
+
+ call LRUDelete
+glrudel1:
+ pop si
+ pop dx
+ pop bx
+if KDEBUG
+ call check_lru_list
+endif
+ ret
+cEnd nogen
+
+
+if KDEBUG
+
+;-----------------------------------------------------------------------;
+; check_lru_list ;
+; ;
+; Checks the glru list for consistency. ;
+; ;
+; Arguments: ;
+; EDI 0 ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Feb 18, 1987 08:30:45p -by- David N. Weise [davidw] ;
+; Added support for EMS. ;
+; ;
+; Wed Oct 29, 1986 10:13:42a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc check_lru_list,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ test Kernel_flags,kf_check_free
+ jz cll_ret
+
+ push ax
+ push ebx
+ push cx
+ push edx
+ push esi
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+do_it_again:
+ mov ebx,[di].gi_lruchain
+ mov cx,[di].gi_lrucount ; without ems gi_alt_count is 0
+ or cx,cx
+ jz all_done
+
+ mov esi,ebx
+check_chain_loop:
+ mov edx,ds:[esi].pga_lruprev
+ mov esi,ds:[esi].pga_lrunext
+ cmp ds:[edx].pga_lrunext,ebx
+ jz short prev_okay
+ kerror 0FFh,<lru: prev bad>,dx,bx
+prev_okay:
+ cmp ds:[esi].pga_lruprev,ebx
+ jz short next_okay
+ kerror 0FFh,<lru: next bad>,bx,si
+next_okay:
+ mov ebx,esi
+ loop check_chain_loop
+ cmp [di].gi_lruchain,ebx
+ jz short all_done
+ kerror 0FFh,<lru: count bad>,bx,[di].gi_lrucount
+all_done:
+ pop esi
+ pop edx
+ pop cx
+ pop ebx
+ pop ax
+cll_ret:
+ pop ds
+ ret
+cEnd nogen
+
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3gmem.asm b/private/mvdm/wow16/kernel31/3gmem.asm
new file mode 100644
index 000000000..317d9c9ff
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3gmem.asm
@@ -0,0 +1,1375 @@
+ TITLE GMEM - Register interface to global memory allocator
+
+.xlist
+include kernel.inc
+include tdb.inc
+.list
+
+.386p
+include protect.inc
+
+DataBegin
+
+;externW curTDB
+;externW pGlobalHeap
+externW Win386_Blocks
+externW SelTableLen
+externD SelTableStart
+
+ifdef WOW
+globalB fInAlloc, 0
+globalW UserSelArray, 0
+globalW SelectorFreeBlock, 0
+endif
+
+if ROM
+externW gdtdsc
+endif
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+externNP DPMIProc
+ife ROM
+externW gdtdsc
+endif
+
+externNP gsplice
+externNP gjoin
+externNP gzero
+externNP gsearch
+externNP gmarkfree
+;externNP gdel_free
+;externNP gcheckfree
+externNP gmovebusy
+externNP gcompact
+externNP glruadd
+externNP glrudel
+externNP glrutop
+externNP gnotify
+externNP is_there_theoretically_enough_space
+externNP can_we_clear_this_space
+
+if ROM
+externNP IsROMObject
+endif
+
+externNP get_physical_address
+externNP alloc_sel
+externNP alloc_data_sel
+externFP IAllocCStoDSAlias
+externNP pdref
+externNP set_sel_limit
+externNP set_selector_limit32
+externNP set_selector_address32
+externNP mark_sel_PRESENT
+externNP mark_sel_NP
+externNP free_sel
+externNP FreeSelArray
+externNP GrowSelArray
+externNP get_arena_pointer32
+externNP get_temp_sel
+externNP AssociateSelector32
+externNP free_arena_header
+externNP PageLockLinear
+externNP UnlinkWin386Block
+ifdef WOW
+ ; WOW doesn't decommit pages this way
+else
+externNP gwin386discard
+endif
+externNP PreAllocArena
+
+if KDEBUG
+externNP CheckGAllocBreak ; LINTERF.ASM
+endif
+
+;-----------------------------------------------------------------------;
+; galign ;
+; ;
+; Aligns the size request for a global item to a valid para boundary. ;
+; ;
+; Arguments: ;
+; EBX = #bytes ;
+; CF = 1 if #paras overflowed. ;
+; ;
+; Returns: ;
+; EDX = #bytes aligned, to next higher multiple of 32 ;
+; ;
+; Error Returns: ;
+; EDX = 0100000h ;
+; ;
+; Registers Preserved: ;
+; all ;
+; Registers Destroyed: ;
+; none ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Mon Sep 22, 1986 03:14:56p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc galign,<PUBLIC,NEAR>
+cBegin nogen
+
+ jc short align_error ; Overflow occur?
+ lea edx,[ebx+GA_ALIGN_BYTES]; No, add alignment amount
+ and dl,GA_MASK_BYTES ; ...modulo alignment boundary
+ cmp edx,ebx ; Test for overflow
+ jnb short align_exit ; OK, continue
+align_error:
+ mov edx,0FF0000h ; Return largest possible size
+ jmps align_exit1 ; 255*64k since max # selectors is 255
+align_exit:
+ cmp edx, 100000h ; Greater than 1Mb?
+ jbe short align_exit1 ; no, done
+ add edx, 0FFFh ; yes, page align
+ jc align_error
+ and dx, not 0FFFh
+ cmp edx, 0FF0000h ; Too big?
+ ja short align_error ; yep, hard luck
+align_exit1:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; galloc ;
+; ;
+; Allocates global memory. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; BX = #paragraphs ;
+; CX = owner field ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; BX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; DX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; gsearch ;
+; ghalloc ;
+; glruadd ;
+; gmarkfree ;
+; History: ;
+; ;
+; Wed Jun 24, 1987 03:04:32a -by- David N. Weise [davidw] ;
+; Added support for Global Notify. ;
+; ;
+; Mon Sep 22, 1986 02:38:19p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+AccessWord dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_CODE+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+
+cProc galloc,<PUBLIC,NEAR>
+cBegin nogen
+
+if KDEBUG
+ test al,GA_DISCCODE ; if discardable code, allow alloc
+ jnz @F
+ call CheckGAllocBreak
+ jc gaerr ; time to fail...
+@@:
+endif
+ cmp ebx, (16*1024*1020) ; Too big?
+ ja gaerr ; yes.
+
+ or ebx,ebx ; Allocating zero size?
+ jz allocate_zero_size
+
+ call gsearch ; Search for block big enough
+ jz ga_exit ; Done, if couldn't get enough
+
+ mov esi,eax
+ push dx
+ mov bx,dx
+ mov edx, ds:[esi].pga_address
+ mov ecx, ds:[esi].pga_size
+
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ cCall alloc_sel,<edx,ecx>
+ pop dx
+ or ax, ax ; Did we get the selectors?
+ jz short gaerr2 ; no, free block and return
+
+ add ecx, 0FFFFh ; Calculate # selectors we got
+ shr ecx, 16
+ mov ds:[esi].pga_selcount, cl
+ cCall AssociateSelector32,<ax,esi>
+ test dl,GA_MOVEABLE ; Is this a moveable object?
+ jnz short moveable
+ test dh, GA_DISCARDABLE ; We have a fixed block
+ jnz short not_moveable ; Not interested in discardable blocks
+ mov bx, ax
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ DPMICALL 0004H
+ jc short gaerr1
+endif
+ inc [esi].pga_pglock ; Mark it locked
+ mov ax, bx
+ jmps not_moveable
+
+moveable:
+ mov ds:[esi].pga_count,0 ; Initialize lock count to 0
+ StoH ax ; Mark as moveable block
+not_moveable:
+ mov ds:[esi].pga_handle,ax ; Set handle in arena
+ mov bx, ax ; AX and BX handle
+
+ call glruadd ; Yes, Add to LRU chain
+ mov cx,ax
+ ret
+
+allocate_zero_size:
+ test al,GA_MOVEABLE ; Yes, moveable?
+ jz short gaerr ; No, return error (AX = 0)
+
+ mov bx, ax
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh ; Above bits are exclusive
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ and al, NOT DSC_PRESENT ; These are NOT present
+ xor edx, edx ; Base of zero for now
+ cCall alloc_sel,<edx,dx,cx>
+ or ax, ax
+ jz short gaerr
+
+ cCall AssociateSelector32,<ax,0,cx> ; Save owner in selector table
+
+ StoH al ; Handles are RING 2
+ mov bx,ax
+ga_exit:
+ mov cx,ax
+ ret
+
+gaerr1: ; Failed to page lock, free up everthing
+ cCall FreeSelArray,<bx>
+gaerr2: ; Failed to get selectors
+ xor edx,edx
+ call gmarkfree
+gaerr:
+ KernelLogError DBF_WARNING,ERR_GALLOC,"GlobalAlloc failed"
+ xor dx,dx ; DX = 0 means NOT out of memory
+ xor ax,ax ; Return AX = 0 to indicate error
+ jmps ga_exit
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; grealloc ;
+; ;
+; Reallocates the given global memory object. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; EBX = #bytes for new size ;
+; CX = new owner field value ;
+; DX = existing handle ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; DX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 22, 1986 10:11:48a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc grealloc,<PUBLIC,NEAR>
+cBegin nogen
+
+ push bp
+ mov bp,sp
+ push ax
+rflags EQU word ptr [bp-2]
+ push dx
+h EQU word ptr [bp-4]
+ push cx
+owner EQU word ptr [bp-6]
+ push ebx
+rsize EQU dword ptr [bp-10]
+ sub sp, 6
+canmove EQU byte ptr [bp-12]
+locked EQU byte ptr [bp-13]
+mflags EQU byte ptr [bp-14]
+pgLockSel EQU word ptr [bp-16]
+ push dx
+oldh EQU word ptr [bp-18]
+
+ mov pgLockSel, 0 ; No selector to free yet
+
+ call pdref
+ mov dx, bx ; save owner if discarded
+ mov word ptr (mflags), cx
+ mov ebx,rsize
+ jz racreate ; Do nothing with 0, free or discarded handles
+handle_ok:
+ test byte ptr rflags,GA_MODIFY ; Want to modify table flags?
+ jnz short ramodify ; Yes go do it
+ or ebx,ebx ; Are we reallocing to zero length?
+ jz short to_0
+ jmp raokay ; No, continue
+to_0: or ch,ch ; Is handle locked?
+ jz short radiscard
+rafail:
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ xor ax,ax ; Yes, return failure
+ xor dx,dx
+ jmp raexit
+
+radiscard: ; No, then try to discard the object
+
+; Here to discard object, when reallocating to zero size. This
+; feature is only enabled if the caller passes the moveable flag
+
+ test byte ptr rflags,GA_MOVEABLE ; Did they want to discard?
+ jz short rafail ; No, then return failure.
+
+ mov al,GN_DISCARD ; AL = discard message code
+ xor cx,cx ; CX = means realloc
+ mov bx, ds:[esi].pga_handle ; BX = handle
+ push es
+ call gnotify ; See if okay to discard
+ pop es
+ jz short rafail ; No, do nothing
+ call glrudel ; Yes, Delete handle from LRU chain
+
+ cCall mark_sel_NP,<ds:[esi].pga_handle,ds:[esi].pga_owner>
+ xor edx,edx
+ call gmarkfree ; Free client data
+ jz short rafixed ; Return NULL if freed a fixed block
+ jmp rasame ; Return original handle, except
+ ; GlobalLock will now return null.
+rafixed:
+ xor ax,ax
+ jmp raexit
+
+ramodify:
+if ROM
+ cCall IsROMObject, <h>
+ or ax, ax
+ jnz rasame1
+endif
+ mov ax,rflags ; Get new flags
+ mov dx,owner ; Get new owner field value
+ mov bx, ds:[esi].pga_handle
+ test bl, GA_FIXED ; Moveable object?
+ jz short is_moveable
+ test al,GA_MOVEABLE ; Make fixed into moveable?
+ jz short ramod2 ; No, change owner only
+
+ StoH bx ; Turn selector into handle
+ mov ds:[esi].pga_handle, bx
+ mov ds:[esi].pga_count, 0 ; 0 lock count for new movable obj
+
+is_moveable:
+ call glrudel ; Yes, remove from lru chain
+ push ax
+ push ecx
+ lar ecx, ebx ; Get existing access rights
+ shr ecx, 8
+ test ah, GA_DISCARDABLE ; Do we want it to be discardable?
+ jnz short ra_want_discardable
+.errnz DSC_DISCARDABLE-10h
+ btr cx, 12 ; Ensure DSC_DISCARDABLE is off
+ jnc short ra_ok_disc_bit ; it was
+ jmps ra_set_access ; nope, must reset it
+ra_want_discardable:
+ bts cx, 12 ; Ensure DSC_DISCARDABLE is on
+ jc short ra_ok_disc_bit
+ra_set_access:
+ DPMICALL 0009h
+ra_ok_disc_bit:
+ pop ecx
+ pop ax
+ra_notdiscardable:
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz short ramod1 ; No, continue
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz short rasame1
+int 3
+ push ax
+ push ecx
+ lsl ecx, ebx ; Use existing high limit bits
+ shr ecx, 16
+ DPMICALL 0008h ; Set segment limit (to CX:DX)
+ pop ecx
+ pop ax
+ jmps rasame1
+ramod1:
+ call glruadd ; Add to lru chain if now discardable
+ramod2:
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz short rasame1
+ mov ds:[esi].pga_owner,dx ; Set new owner value
+rasame1:
+ jmp rasame
+
+rafail0:
+ jmp rafail
+racreate:
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz short rafail0 ; No, return error
+ or ebx,ebx ; Are we reallocing to zero length?
+ jz short rasame1 ; Yes, return handle as is.
+
+if KDEBUG
+ test cl,GA_DISCCODE ; if discardable code, allow realloc
+ jnz @F
+ call CheckGAllocBreak
+ jc rafail0
+@@:
+endif
+ mov ax,GA_MOVEABLE ; Reallocating a moveable object
+ or ax,rflags ; ...plus any flags from the caller
+ ; DO NOT CHANGE: flag conflict
+ ; GA_DISCARDABLE == GA_ALLOCHIGH.
+ and cl,not (HE_DISCARDED + GA_ALLOCHIGH)
+ or al,cl
+ mov cx,dx ; get owner
+
+ test al,GA_DISCCODE ; Discardable code segment?
+ jz short ranotcode
+ or al,GA_ALLOCHIGH ; Yes, allocate high
+ranotcode:
+ or al, COMPACT_ALLOC ; Allow discarding
+ mov [di].gi_cmpflags,al ; Save flags for gcompact
+ and [di].gi_cmpflags,CMP_FLAGS or GA_ALLOCHIGH
+ push si ; save handle
+ call gsearch ; Find block big enough
+ pop si ; restore existing handle
+ jz rafailmem1
+
+ cCall mark_sel_PRESENT,<eax,si>
+ or si,si ; Might have failed to grow selector array
+ jz short racre_worst_case
+
+ xchg eax,esi ; Return original handle
+ ; Set back link to handle in new block
+ cCall AssociateSelector32,<ax,esi>
+ mov ds:[esi].pga_handle,ax
+ mov ds:[esi].pga_count,0
+; and ch,GA_SEGTYPE ; OPTIMIZE superfluous??
+; and es:[di].ga_flags,GAH_NOTIFY
+; or es:[di].ga_flags,ch ; Copy segment type flags to ga_flags
+ call glruadd ; Add to LRU chain
+ jmp raexit
+
+racre_worst_case:
+ mov esi, eax ; Free block if selectors not available
+ xor edx, edx
+ call gmarkfree
+
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+
+ xor dx, dx
+ xor ax, ax
+ jmp raexit
+
+raokay:
+
+if KDEBUG
+ test ds:[esi].pga_flags,GA_DISCCODE
+ jz short ok
+ Debug_Out "GlobalReAlloc of Discardable Code"
+ok:
+endif
+ cmp ebx,ds:[esi].pga_size
+ jz short rasame
+
+ clc
+ call galign ; assuming there is room.
+
+; Here if not trying to realloc this block to zero
+; FS:ESI = arena header of current block
+; AX:0 = client address of current block
+; CH = lock count of current block
+; EDX = new requested size
+
+ cmp ds:[esi].pga_pglock, 0 ; Are we page locked?
+ je short ranolock
+ push ax
+ push dx
+ push es
+ cCall IAllocCStoDSAlias,<h> ; Get an alias selector (type doesn't
+ pop es
+ pop dx
+ mov pgLockSel, ax ; matter)
+ or ax, ax ; Got selector?
+ pop ax
+ jz rafail ; no, goodbye
+ranolock:
+ mov ebx,ds:[esi].pga_next ; Get address of current next header
+ cmp edx,ds:[esi].pga_size ; Are we growing or shrinking?
+ ja short raextend ; We are growing
+
+ call rashrink
+
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ mov bx, h
+ mov ax, pgLockSel ; Were we page locked?
+ or ax, ax
+ jz short rasame ; no, nothing to do
+ Handle_To_Sel bl
+ DPMICALL 0004h
+endif
+
+rasame_pglock:
+ifdef WOW
+ ; avoid the call altogether.
+else
+ mov bx, pgLockSel ; Were we page locked?
+ or bx, bx
+ jz short rasame
+ DPMICALL 0005h
+endif
+
+rasame:
+ mov ax,h ; Return the same handle
+ jmp raexit ; All done
+
+raextend:
+ test rflags,GA_DISCCODE ; Not allowed to grow a disccode seg
+ jnz short rafail1
+if KDEBUG
+ call CheckGAllocBreak
+ jc rafail1
+endif
+ push ax
+ call GrowSelArray
+ mov cx, ax
+ pop ax ; Did we get the selectors?
+ jcxz rafail1 ; no, fail
+ mov h, cx ; Update handle
+ call ragrow
+ jnc short rasame_pglock ; Success
+ test mflags,GA_DISCARDABLE ; if discardable, just stop now
+ jz short ramove ; since it might get discarded!
+rafail1:
+ jmp rafail
+
+; Here to try to move the current block
+; AX = client address of current block
+; ES:0 = arena header of current block
+; CH = lock count of current block
+; EDX = new requested size of block
+
+ramove:
+ mov ebx, edx ; Size now in EBX
+ mov canmove, 1
+ mov dx,rflags ; get the passed in flags
+ test dx,GA_MOVEABLE ; Did they say OK to move
+ jnz short ramove1 ; Yes, try to move even iflocked or fixed
+ cmp locked, 0 ; Locked?
+ ; Continue if this handle not locked
+ jnz short racompact ; yes, try to find space to grow in place
+ or dx,GA_MOVEABLE ; If moveable, make sure bit set.
+ test h,GA_FIXED ; Is this a moveable handle?
+ jz short ramove2 ; Yes, okay to move
+
+racompact:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ jmp racantmove
+
+ramove1:
+ test h, GA_FIXED
+ jz short ramove2
+ and dx, NOT GA_MOVEABLE
+ramove2:
+ mov ax,dx ; AX = allocation flags
+;;; mov bx,si ; EBX = size of new block
+ mov cx,1 ; CX = owner (use size for now)
+ call gsearch ; Find block big enough
+ jz short racantmove ; Cant find one, grow in place now?
+ mov esi, eax ; ESI = destination arena
+ call PreAllocArena ; Required for gmovebusy
+ jz short ramove2a
+ mov cx, pgLockSel ; Do we have to page lock it?
+ jcxz ramove3
+ cCall PageLockLinear,<ds:[esi].pga_address,ds:[esi].pga_size>
+ jnc short ramove3 ; Locked it?
+ramove2a:
+ xor edx, edx ; no, free memory block
+ call gmarkfree
+ jmps racantmove
+ramove3:
+ mov cx,h
+
+ cCall get_arena_pointer32,<cx>
+ mov edx,eax
+
+ call gmovebusy ; Call common code to move busy block
+ ; (AX destroyed)
+
+ push ebx
+ push esi
+ mov esi, edx ; free block just emptied
+ mov ebx, ds:[esi].pga_prev ; See if block can be
+ cmp ds:[ebx].pga_owner, GA_NOT_THERE; returned to win386
+ jne short ra_no_unlink
+ push ecx
+ mov ecx, ds:[esi].pga_next
+ cmp ds:[ecx].pga_owner, GA_NOT_THERE
+ jne short ra_no_unlink_ecx
+ mov eax, ds:[ecx].pga_next
+ cmp eax, ds:[eax].pga_next ; Sentinel?
+ je short ra_no_unlink_ecx ; yes, keep this block
+
+ push edx
+ push edi
+ cCall UnlinkWin386Block
+ pop edi
+ pop edx
+
+ra_no_unlink_ecx:
+ pop ecx
+ra_no_unlink:
+ pop esi
+ pop ebx
+
+ cCall set_selector_limit32,<ds:[esi].pga_handle,ds:[esi].pga_size>
+ jmp rasame_pglock
+
+racantmove:
+ mov dx, h
+ call pdref
+
+ mov ebx,rsize
+ clc
+ call galign ; assuming there is room.
+
+ mov ebx,ds:[esi].pga_next ; Get address of current next header
+ call ragrow
+ jc short racmove3
+ jmp rasame_pglock
+
+racmove3:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ mov dx,ax ; DX = size of largest free block
+
+rafailmem:
+
+ mov eax,ds:[esi].pga_size ; AX = size of current block
+ mov esi,ds:[esi].pga_next ; Check following block
+ cmp ds:[esi].pga_owner,di ; Is it free?
+ jne short rafailmem0 ; No, continue
+ add eax,ds:[esi].pga_size ; Yes, then include it as well
+;;; inc ax
+rafailmem0:
+ cmp ax,dx ; Choose the larger of the two
+ jbe short rafailmem1
+ mov dx,ax
+rafailmem1:
+ push dx ; Save DX
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ pop dx ; Restore DX
+
+ xor ax,ax
+
+raexit:
+ push ax
+ push bx
+ push dx
+
+ mov bx, pgLockSel
+ or bx, bx ; Have alias selector?
+ jz short noSel ; nope, all ok
+ cCall free_sel,<bx>
+noSel:
+ mov bx, h
+;;; inc bl
+ and bl, NOT 1
+ mov cx, oldh
+;;; inc cl
+ and cl, NOT 1
+ cmp bx, cx ; Did we get new selector array?
+ je short no_new_handle ; nope.
+ or ax, ax ; Did we succeed?
+ jz short free_new
+ HtoS cl
+ cCall FreeSelArray,<cx> ; Free old selector array
+ jmps no_new_handle
+ ; Update old selector array
+free_new:
+ HtoS bl
+ cCall get_arena_pointer32,<bx> ; Get new arena (may have moved)
+ mov esi,eax
+ HtoS cl
+ cCall AssociateSelector32,<cx,esi> ; Set up old sel array
+ cCall set_selector_address32,<cx,ds:[esi].pga_address>
+ lsl ecx, ecx ; Get old length
+if KDEBUG
+ jz short @F
+ int 3
+@@:
+endif
+ add ecx, 10000h
+ shr ecx, 16 ; CL has old # selectors
+ xchg ds:[esi].pga_selcount, cl
+ mov ax, oldh
+ xchg ds:[esi].pga_handle, ax ; Reset handle
+ cCall AssociateSelector32,<ax,0,0> ; Disassociate new array
+fsloop:
+ cCall free_sel,<ax> ; Free new selector array
+ add ax, 8
+ loop fsloop
+
+no_new_handle:
+ pop dx
+ pop bx
+ pop ax
+ mov cx, ax
+
+ mov sp,bp
+ pop bp
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; rashrink ;
+; ;
+; Shrinks the given block ;
+; ;
+; Arguments: ;
+; Here to shrink a block ;
+; DS:ESI = arena header of current block ;
+; DS:EBX = arena header of next block ;
+; EDX = new requested size ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; gsplice ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+cProc rashrink,<PUBLIC,NEAR>
+cBegin nogen
+
+ call PreAllocArena ; Make sure we can do it
+ jz short rashrunk
+
+ mov ax,ds:[esi].pga_handle
+ or ax,ax
+ jz short ra_free
+ Handle_To_Sel al
+ push ecx
+ push edx
+ lsl ecx, eax
+ Limit_To_Selectors ecx ; Old # selectors
+ dec edx
+ Limit_To_Selectors edx ; New # selectors
+ sub cx, dx
+ jbe short none_to_free
+
+ mov ds:[esi].pga_selcount, dl
+ push ax
+ .errnz SIZE DscPtr-8
+ shl dx, 3
+ add ax, dx ; First selector to free
+ras_loop:
+ cCall free_sel,<ax>
+ add ax, SIZE DscPtr
+ loop ras_loop
+ pop ax
+
+none_to_free:
+ pop edx
+ pop ecx
+
+ cCall set_selector_limit32,<ax,edx>
+ra_free:
+ cmp edx,ds:[esi].pga_size ; Enough room from for free block?
+ jae short rashrunk ; No, then no change to make
+
+ call gsplice ; splice new block into the arena
+ mov esi, edx
+ xor edx, edx
+ call gmarkfree ; Mark it as free
+rashrunk:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ragrow ;
+; ;
+; Tries to grow the given global memory object in place ;
+; ;
+; Arguments: ;
+; AX:0 = client address of current block ;
+; FS:ESI = arena header of current block ;
+; FS:EBX = arena header of next block ;
+; EDX = new requested size of block ;
+; ;
+; Returns: ;
+; CY = 0 Success ;
+; ;
+; CY = 1 Failed ;
+; ESI preserved ;
+; EDX contains free memory required ;
+; ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; is_there_theoretically_enough_space ;
+; can_we_clear_this_space ;
+; gjoin ;
+; gzero ;
+; rashrink ;
+; ;
+; History: ;
+; ;
+; Mon 05-Sep-1988 20:10:15 -by- David N. Weise [davidw] ;
+; Made ragrow be more intelligent by trying to extend into moveable ;
+; blocks. ;
+;-----------------------------------------------------------------------;
+cProc ragrow,<PUBLIC,NEAR>
+cBegin nogen
+
+ push ds:[esi].pga_size ; Save in case we have to back out
+ push edx
+ push esi ; Save current block address
+ sub edx, ds:[esi].pga_size ; compute amount of free space wanted
+ xchg esi,ebx ; ESI = next block address
+ mov cx,[di].hi_count
+ push ax
+ push cx
+ push esi
+ call is_there_theoretically_enough_space
+ pop esi
+ pop cx
+ cmp eax,edx
+ jb short ragx
+ call can_we_clear_this_space
+ jz short ragx
+ cCall alloc_data_sel,<ds:[esi].pga_address, edx>
+
+ or ax, ax ; Did we get a selector?
+ jnz short okk ; yes, continue
+ jmps ragx
+okk:
+ mov cx, ax
+ pop ax
+ push cx ; Parameter to free_sel (below)
+ push edx
+ call gjoin ; and attach to end of current block
+ pop edx
+ test byte ptr rflags,GA_ZEROINIT ; Zero fill extension?
+ jz short ranz ; No, continue
+ mov bx,cx ; Yes, BX = first paragraph to fill
+ mov ecx,edx ; compute last paragraph to fill
+ call gzero ; zero fill extension
+ranz:
+ call FreeSelArray
+ pop edx ; clear the stack
+ pop edx ; New length of block
+ mov bx, ds:[esi].pga_handle
+ Handle_To_Sel bl
+ cCall set_selector_limit32,<bx,edx>
+
+ifndef WOW ; WOW doesn't lock pages
+ cmp ds:[esi].pga_pglock, 0
+ je short rag1
+
+ mov ax, 4 ; Page lock the whole thing
+ int 31h
+ mov ax, bx
+ jc short rag2
+endif; WOW
+
+rag1:
+ mov ebx,ds:[esi].pga_next ; Pick up new next block address
+ call rashrink ; Now shrink block to correct size
+ add sp, 4
+ clc
+ ret
+ragx:
+ pop ax
+ pop esi ; Recover current block address
+ pop edx
+ add sp, 4 ; toss original size
+ stc
+ ret
+rag2:
+if KDEBUG
+int 3
+endif
+ pop edx ; Shrink back to orignal size
+ mov ebx, ds:[esi].pga_next
+ call rashrink
+ stc ; and fail
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfree ;
+; ;
+; Frees a global object. ;
+; ;
+; Arguments: ;
+; DX = global memory object handle ;
+; CX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; CX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; gdref ;
+; free_object ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 11:48:38a -by- David N. Weise [davidw] ;
+; Added this nifty comment block and restructured. ;
+;-----------------------------------------------------------------------;
+
+cProc gfree,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ call pdref
+ pop dx
+ jz short object_discarded
+ call free_object
+ jmps gfree_exit
+
+ ;** When the object is discarded, we have to remove the sel table
+ ;* pointer to the object (this points to the >owner< of the
+ ;** block for discardable objects)
+object_discarded:
+ PUBLIC object_discarded
+ xor eax,eax
+ cCall AssociateSelector32, <si,eax> ;Remove in the sel table
+ cCall FreeSelArray,<si>
+ xor ax,ax ;Force success
+
+gfree_exit:
+ mov cx,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_object ;
+; ;
+; Arguments: ;
+; DX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ES:ESI = address of arena header ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrudel ;
+; gmarkfree ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:59:06p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+cProc free_object,<PUBLIC,NEAR>
+cBegin nogen
+ or dx,dx
+ jz short free_it
+ cmp ds:[esi].pga_owner,dx
+ je short free_it
+ mov ax,-1
+ jmps free_object_exit
+free_it:
+ call glrudel ; delete object from LRU chain
+ifdef WOW
+ ; No need to call DPMI to unpagelock
+else
+ movzx cx, ds:[esi].pga_pglock
+ jcxz fo_notpglocked
+ mov bx, ds:[esi].pga_handle
+unpagelock:
+ DPMICALL 0005h
+ loop unpagelock
+endif
+ mov ds:[esi].pga_pglock, 0
+fo_notpglocked:
+ push dx
+ xor edx,edx
+ call gmarkfree ; free the object
+
+ mov ebx, ds:[esi].pga_prev ; See if block can be
+ cmp ds:[ebx].pga_owner, GA_NOT_THERE; returned to win386
+ jne short fo_no_return
+ mov ecx, ds:[esi].pga_next
+ cmp ds:[ecx].pga_owner, GA_NOT_THERE
+ jne short fo_no_return
+ push ecx
+ mov ecx, ds:[ecx].pga_next
+ cmp ecx, ds:[ecx].pga_next ; Sentinel?
+ pop ecx
+ je short fo_no_return ; yes, keep this block
+
+ cCall UnlinkWin386Block
+ jmps fo_no_discard
+
+fo_no_return:
+ifdef WOW
+ ; WOW doesn't decommit pages this way
+else
+ call gwin386discard
+endif
+fo_no_discard:
+ Handle_To_Sel dl
+ cCall AssociateSelector32,<dx,edi> ; Trash sel table entry
+ cCall FreeSelArray,<dx>
+ pop dx
+ xor ax,ax ;!!! just for now force success
+free_object_exit:
+ ret
+cEnd nogen
+
+
+cProc free_object2,<PUBLIC,FAR>
+cBegin nogen
+ call glrudel ; delete object from LRU chain
+ifdef WOW
+ ; No need to call DPMI to unpagelock
+else
+ movzx cx, ds:[esi].pga_pglock
+ jcxz fo2_notpglocked
+ mov bx, ds:[esi].pga_handle
+unpagelock2:
+ DPMICALL 0005h
+ loop unpagelock2
+endif
+ mov ds:[esi].pga_pglock, 0
+fo2_notpglocked:
+ xor edx,edx
+ call gmarkfree ; free the object
+
+ mov ebx, ds:[esi].pga_prev ; See if block can be
+ cmp ds:[ebx].pga_owner, GA_NOT_THERE; returned to win386
+ jne short fo2_no_return
+ mov ecx, ds:[esi].pga_next
+ cmp ds:[ecx].pga_owner, GA_NOT_THERE
+ jne short fo2_no_return
+ push ecx
+ mov ecx, ds:[ecx].pga_next
+ cmp ecx, ds:[ecx].pga_next ; Sentinel?
+ pop ecx
+ je short fo2_no_return ; yes, keep this block
+
+ cCall UnlinkWin386Block
+ jmps fo2_no_discard
+
+fo2_no_return:
+ifdef WOW
+ ; WOW doesn't decommit pages this way
+else
+ call gwin386discard
+endif
+fo2_no_discard:
+ xor ax,ax ;!!! just for now force success
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_handle ;
+; ;
+; Frees the given handle. ;
+; ;
+; Arguments: ;
+; DS:SI = handle table entry address ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; BX ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:30:32p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+;cProc free_handle,<PUBLIC,NEAR>
+;cBegin nogen
+; xor ax,ax
+; or si,si
+; jz short free_handle_exit
+; push bx
+; mov bx,si
+; call hfree
+; pop bx
+;free_handle_exit:
+; ret
+;cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfreeall ;
+; ;
+; Frees all global objects that belong to the given owner. It first ;
+; loops through the global heap freeing objects and then loops through ;
+; the handle table freeing handles of discarded objects. ;
+; ;
+; Arguments: ;
+; DX = owner field value to match ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,ES,SI ;
+; ;
+; Calls: ;
+; free_object ;
+; henum ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:46:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gfreeall,<PUBLIC,NEAR>
+cBegin nogen
+
+ mov esi,[di].phi_first ; ES:DI points to first arena entry
+ mov cx,[di].hi_count ; CX = #entries in the arena
+free_all_objects:
+ push cx
+ call free_object ; Free object if matches owner
+ pop cx
+ mov esi,ds:[esi].pga_next ; Move to next block
+ loop free_all_objects
+
+; may go extra times, as CX does not track coalescing done by gfree,
+; but no big whoop
+
+
+ push ax
+ push ebx
+ push edi
+ CheckKernelDS FS
+ ReSetKernelDS FS
+ movzx ecx, SelTableLen
+ shr ecx, 2
+ mov edi, SelTableStart
+ mov esi, edi
+ smov es, ds
+ UnSetKernelDS FS
+free_all_handles_loop:
+ movzx eax, dx
+ repne scas dword ptr es:[edi] ; Isn't this easy?
+ jne short we_be_done
+ lea eax, [edi-4]
+ sub eax, esi
+ shl ax, 1
+ or al, SEG_RING
+
+ lar ebx, eax
+ test bh,DSC_PRESENT ; segment present?
+ jnz short free_all_handles_loop ; yes, not a handle
+ test ebx,DSC_DISCARDABLE SHL 16 ; discardable?
+ jz short free_all_handles_loop ; no, nothing to free
+ cCall FreeSelArray,<ax>
+ mov dword ptr [edi-4], 0 ; Remove owner from table
+ jmps free_all_handles_loop
+we_be_done:
+ pop edi
+ pop ebx
+ pop ax
+
+gfreeall_done:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glock ;
+; ;
+; Increment the lock count of an object in handle table entry ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; DX = segment address of object ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count ;
+; DX = pointer to client area ;
+; ;
+; Error Returns: ;
+; ZF = 1 if count overflowed. ;
+; ;
+; Registers Preserved: ;
+; AX ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:38:57p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc glock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ inc ch ; Increment lock count
+ jz short overflow ; All done if overflow
+ mov ds:[esi].pga_count,ch ; Update lock count
+glockerror:
+overflow:
+ pop ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gunlock ;
+; ;
+; Decrement the lock count of an object. ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; CX = handle table flags and lock count for moveable objects ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count, no underflow ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrutop ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 04:39:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gunlock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ mov ax,bx
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; ff -> fe, 0 -> ff
+ jae short count_zero ; Return if pinned, or was already 0
+ dec ds:[esi].pga_count ; Non-zero update lock count
+ jnz short count_positive ; All done if still non-zero
+ test cl,GA_DISCARDABLE ; Is this a discardable handle?
+ jz short count_zero ; No, all done
+ call glrutop ; Yes, bring to top of LRU chain
+count_zero:
+ xor cx,cx
+count_positive:
+ pop ax
+ ret
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3gmemini.asm b/private/mvdm/wow16/kernel31/3gmemini.asm
new file mode 100644
index 000000000..1d315521a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3gmemini.asm
@@ -0,0 +1,636 @@
+
+include kernel.inc
+include protect.inc
+.list
+
+.386p
+
+DataBegin
+
+externB WinFlags
+externW hGlobalHeap
+externW pGlobalHeap
+externW ArenaSel
+externD hBmDPMI
+externD FreeArenaList
+externD FreeArenaCount
+externD SelTableStart
+externW SelTableLen
+externW InitialPages
+
+DataEnd
+
+
+sBegin INITCODE
+assumes CS,CODE
+
+externNP get_physical_address
+externNP set_physical_address
+externNP set_selector_address32
+externNP set_selector_limit32
+externNP alloc_arena_header
+externNP AssociateSelector32
+externNP alloc_data_sel
+externNP alloc_data_sel32
+externNP GrowHeap
+externNP DPMIProc
+
+GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
+GA_MASK_BYTES = NOT GA_ALIGN_BYTES
+
+;-----------------------------------------------------------------------;
+; get_selector_address32 ;
+; ;
+; Function to translate return of get_physical_address (DX:AX) into EAX ;
+; ;
+;-----------------------------------------------------------------------;
+cProc get_selector_address32,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ push dx
+ cCall get_physical_address,<selector>
+ shl eax, 16
+ mov ax, dx
+ ror eax, 16
+ pop dx
+cEnd
+
+;-----------------------------------------------------------------------;
+; GlobalInit ;
+; ;
+; Procedure to initialize the global heap. Called with the starting ;
+; and ending paragraph addresses. ;
+; ;
+; Arguments: ;
+; parmW hdelta = size (.25k) of master object ;
+; parmW palloc = block to mark allocated ;
+; = (ROM) Size of DS == allocated block ;
+; parmW pstart = first available address ;
+; parmW pend = last available address ;
+; ;
+; Returns: ;
+; AX = handle for allocated block ;
+; ;
+; Error Returns: ;
+; ;
+; Alters: ;
+; ES ;
+; Calls: ;
+; ginit ;
+; hthread ;
+; ghalloc ;
+; History: ;
+; ;
+; Sat Jun 20, 1987 05:55:35p -by- David N. Weise [davidw] ;
+; Making real EMS work with the fast boot version. ;
+; ;
+; Sun Mar 15, 1987 06:38:04p -by- David N. Weise [davidw] ;
+; Added support for the linked free list long ago. ;
+; ;
+; Wed Feb 18, 1987 08:09:18p -by- David N. Weise [davidw] ;
+; Added the initialization of the gi_alt entries. ;
+; ;
+; Mon Sep 08, 1986 07:53:41p -by- David N. Weise [davidw ;
+; Changed the return values so that this can be called from other than ;
+; initialization code. ;
+;-----------------------------------------------------------------------;
+
+cProc GlobalInit,<PUBLIC,NEAR>,<ds,si,di>
+ parmW hdelta
+ parmW palloc
+ parmW pstart
+ parmW pend
+ localW emspalloc
+ localW hInitMem
+ localD allocated_arena
+ localW next_block
+ localW free_hi
+ localW free_lo
+
+cBegin
+ mov ax,palloc ; AX = block to mark allocated
+ mov bx,pstart ; BX = first available address
+ mov cx,hdelta ; CX = size (.25k) of master object
+ mov dx,pend ; DX = last available address
+ call ginit
+ jc FailGlobalInit
+
+ SetKernelDS es
+ mov allocated_arena,eax
+ xor edi,edi ; Initialize master object
+ mov [di].phi_first,ebx ; Fill in pointers to first and
+ mov [di].phi_last,edx ; last blocks
+ mov [di].hi_count,4 ; 4 arena entries
+ or eax,eax
+ jnz short allocated_block
+ mov [di].hi_count,3 ; 3 arena entries
+allocated_block:
+ mov [di].gi_lruchain,edi ; Nothing in LRU list so far
+ mov [di].gi_lrucount,di
+ mov [di].gi_lrulock,di ; ...and not locked
+ mov [di].gi_reserve,edi ; No discardable code reserve area yet
+ push eax
+ mov eax, ds:[edx.pga_address]
+ mov word ptr [di].gi_disfence,ax ; gi_disfence = hi_last
+ shr eax, 16
+ mov word ptr [di].gi_disfence_hi,ax
+ pop eax
+
+ mov [di].gi_alt_first,-1 ; Fill in pointers to first and
+ mov [di].gi_alt_last,-1 ; last blocks, the -1 is necessary!!
+ mov [di].gi_alt_count,di ; # of arena entries
+ mov [di].gi_alt_lruchain,di
+ mov [di].gi_alt_lrucount,di ; MUST be 0!
+ mov [di].gi_alt_free_count,di
+ mov [di].gi_alt_reserve,di
+ mov [di].gi_alt_disfence,di
+ mov [di].gi_alt_pPhantom,-1 ; MUST be -1!
+
+ mov ax, ds:[esi.pga_handle] ; Pick up master objects selector
+ mov hGlobalHeap,ax
+ mov ds:[esi].pga_count,0
+ mov ds:[esi].pga_selcount,1
+
+if ROM
+ mov esi,ds:[ebx].pga_next ; in ROM, alloced == first.next
+else
+ mov esi,ds:[edx].pga_prev ; Point to allocated object before
+endif
+ mov bx,ds:[esi.pga_handle]
+ StoH bx ; It is moveable
+ mov ds:[esi].pga_handle,bx
+ mov hInitMem,bx
+if ROM
+ mov ds:[esi].pga_count,1 ; LOCKED in ROM
+else
+ mov ds:[esi].pga_count,0
+endif
+no_allocated_object:
+
+; initialize free list
+
+ mov [di].gi_free_count,1
+ mov eax,[di].phi_first
+ mov ecx,[di].phi_last
+
+if ROM
+ mov ebx,ds:[ecx].pga_prev
+else
+ mov ebx,ds:[eax].pga_next
+endif
+ mov ds:[eax].pga_freeprev,-1 ; Fill in first sentinal
+ mov ds:[eax].pga_freenext,ebx
+
+ mov ds:[ecx].pga_freeprev,ebx ; Fill in last sentinal
+ mov ds:[ecx].pga_freenext,-1
+
+ mov ds:[ebx].pga_freeprev,eax ; Link in free block
+ mov ds:[ebx].pga_freenext,ecx
+ pushad
+ SetKernelDS fs
+ mov edx, 060000h ; Enough to boot quickly in
+ call GrowHeap
+ jnc short @F
+ mov edx, 020000h ; Insist on enough for fence
+ call GrowHeap
+@@:
+ UnSetKernelDS fs
+ popad
+ jc short FailGlobalInit
+ mov ax,hInitMem
+ clc
+FailGlobalInit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; ginit ;
+; ;
+; Procedure to initialize the global heap. ;
+; ;
+; The global heap looks as follows after this procedure returns: ;
+; ;
+; BX - first object in arena, alway busy, zero length. ;
+; - free object ;
+; AX - allocated object ;
+; DS - master object ;
+; DX - last object in arena, alway busy, zero length. ;
+; ;
+; ;
+; Arguments: ;
+; AX = address of block to mark allocated. May be zero. ;
+; = (ROM) length of allocated block (which is DS) ;
+; BX = address of first paragraph in arena ;
+; DX = address of last paragraph in arena ;
+; CX = initial size of master object, in bytes ;
+; ;
+; Returns: ;
+; AX = aligned address of block marked allocated. ;
+; BX = aligned address of first object in arena ;
+; CX = size of master object, in bytes ;
+; DX = aligned address of last object in arena ;
+; DS = aligned address of master object ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; DI,SI,ES ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Thu Sep 11, 1986 04:22:02p -by- David N. Weise [davidw] ;
+; Commented it, made it handle the case of no allocated block correctly.;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ginit,<PUBLIC,NEAR>
+
+ localD size_free
+ localD size_allocated
+ localD size_master
+ localD allocated_arena
+ localW allocated_sel
+ localD BurgerMaster_arena
+ localW BurgerMaster_sel
+ localD new_last_arena
+
+cBegin
+
+; ESI = the first block address (sentinel, always busy)
+
+ SetKernelDS es
+ push ax
+
+ cCall get_selector_address32,<bx> ; Start of our memory
+ add eax, GA_ALIGN_BYTES ; Align our start
+ and al, GA_MASK_BYTES
+ push eax ; Save the start address
+ cCall set_selector_address32,<bx,eax> ; This will be our arena list
+ mov ArenaSel, bx
+ mov BurgerMaster_sel, bx
+ mov si, bx
+
+ push bx
+ push di
+ xor bx, bx ; # physical pages available
+ sub sp, 30h
+ mov di, sp
+ push es
+ smov es, ss
+ DPMICALL 0500h
+ pop es
+ mov eax, 16*1024 ; Size of selector table
+ jc short default_sel_table
+ mov bx, word ptr ss:[di][10h]
+ cmp bx, 256
+ jb short default_sel_table
+ ;;;mov eax, 31*1024
+ mov eax, 32*1024
+default_sel_table:
+ mov [InitialPages], bx
+; For WOW we assume 386 Kernel is running on paging System
+; So always set WF1_PAGING
+ifndef WOW
+ mov ecx, ss:[di][20h] ; Paging file size
+ inc ecx
+ cmp ecx, 1 ; 0 or -1?
+ jbe short @F
+endif
+ or byte ptr WinFlags[1], WF1_PAGING
+@@:
+ mov ecx, ss:[di][0]
+ shr ecx, 7 ; Bytes reserved for arenas
+ add sp, 30h
+ pop di
+ pop bx
+
+ add ecx, GA_ALIGN_BYTES ; Align length of arena table
+ and cl, GA_MASK_BYTES
+ add eax, GA_ALIGN_BYTES ; Align length of selector table
+ and al, GA_MASK_BYTES
+ mov SelTableLen, ax
+ cmp ecx, DEFAULT_ARENA_SIZE ; Number of bytes of arenas
+ jae short @F
+ mov ecx, DEFAULT_ARENA_SIZE
+@@:
+ mov ebx, Size GlobalInfo+GA_ALIGN_BYTES
+ and bl, GA_MASK_BYTES ; EBX start of arenas
+ mov size_master, ebx
+ add ecx, ebx
+ mov SelTableStart, ecx
+ add eax, ecx ; EAX total length of segment
+
+ push ecx
+ push ebx
+ push eax
+ push si
+ mov cx, ax ; Make BX:CX required
+ mov ebx, eax ; length of Burgermaster
+ shr ebx, 16
+ push bx ; Save length
+ push cx
+ DPMICALL 0501h
+ mov hBmDPMI[0], di ; Save DPMI handle
+ mov hBmDPMI[2], si
+ pop di ; SI:DI now length
+ pop si
+ jc Failginit
+if 0
+ mov di, 4096 ; Lock first page
+ xor si, si
+ DPMICALL 0600h ; Now page lock it
+ push bx
+ push cx
+ add cx, word ptr SelTableStart
+ adc bx, 0
+ and cx, not 4095
+ DPMICALL 0600h
+ pop cx
+ pop bx
+endif
+
+ shl ebx, 16
+ mov bx, cx ; Address in EBX
+ pop si
+ pop eax
+ cCall set_selector_address32,<si,ebx>
+ mov edi, ebx
+;;; cCall set_selector_limit32, <si,eax>
+ push eax
+ push dx
+ dec eax
+ mov ecx, eax ; Limit in CX:DX
+ shr ecx, 16
+ mov dx, ax
+ test cx,0fff0h ; bits 20-31 set?
+ jz @F ; No.
+ or dx,0fffh ; Yes, page align limit.
+@@:
+ mov bx, si ; Selector in BX
+ DPMICALL 8
+ pop dx
+ pop eax
+ pop ebx
+ pop ecx
+ jc Failginit
+
+ mov ds, si
+ sub ecx, ebx ; Subtract out BurgerMaster
+ cCall InitialiseArenas,<ebx,ecx>
+ mov ecx, eax
+ pop esi ; Sentinel address
+ cCall alloc_arena_header,<esi> ; Sentinel
+ mov esi, eax
+ cCall alloc_arena_header,<edi> ; BurgerMaster
+ mov BurgerMaster_arena, eax
+ mov ds:[eax].pga_handle, ds ; Save selector in handle field
+ mov ds:[eax].pga_size, ecx
+
+ push edi
+ push ecx
+ movzx ecx, SelTableLen
+ mov edi, SelTableStart
+ push es
+ smov es, ds ; Zero this area
+ UnSetKernelDS es
+ shr ecx, 2
+ xor eax, eax
+ rep stos dword ptr es:[edi]
+ pop es
+ ReSetKernelDS es
+ pop ecx
+ pop edi
+ cCall AssociateSelector32,<ds,BurgerMaster_Arena> ; Set back link
+
+; EDI = the Free block address (initial free block)
+
+ife ROM
+
+ mov eax, ds:[esi].pga_address
+;;; add eax, ecx
+ cCall alloc_arena_header,<eax>
+ mov edi, eax ; Free block arena in EDI
+
+ movzx eax, dx ; Get linear address
+ shl eax, 4
+else
+ cCall get_selector_address32, <dx>
+endif
+
+; EDX = the last block address (sentinel, always busy)
+
+ and al, GA_MASK_BYTES
+ push eax
+ cCall alloc_arena_header,<eax>
+ mov new_last_arena, eax ; Save it away
+ pop ebx
+
+if ROM
+ ; in ROM, the alloced segment is the data segment, and we are
+ ; passed the length, not the address
+ ;
+ ; the length (a word) is on the stack from that very first push way
+ ; up there, and we want the base in eax and the length in ebx
+ ;
+ CheckKernelDS ES
+ cCall get_selector_address32, <es>
+ and al, GA_MASK_BYTES
+ xor ebx, ebx ; clear hi word of length
+ pop bx
+ add ebx, GA_ALIGN_BYTES
+ and bl, GA_MASK_BYTES
+
+ cCall set_selector_limit32, <es, ebx>
+else
+ pop ax ; Allocated Block
+ cCall get_selector_address32, <ax>
+ and al, GA_MASK_BYTES ; "Align" it
+
+ sub ebx, eax ; Length in bytes
+endif
+
+ife ROM
+ push eax
+endif
+ push eax
+ cCall alloc_arena_header, <eax>
+ mov ds:[eax].pga_size, ebx ; Record size
+ mov allocated_arena, eax
+ mov ebx, eax
+ pop eax
+if ROM
+ CheckKernelDS ES
+ mov allocated_sel, es
+ mov ds:[ebx.pga_handle], es
+ cCall AssociateSelector32,<es, ebx>
+else
+ cCall alloc_data_sel32, <eax, ds:[ebx].pga_size>
+ mov allocated_sel, ax
+ mov ds:[ebx.pga_handle], ax ; Save selector
+ cCall AssociateSelector32,<ax,ebx> ; Set back link
+endif
+
+if ROM
+ ; now deal with the free sucker
+ mov eax, ds:[ebx].pga_address
+ add eax, ds:[ebx].pga_size
+ add eax, GA_ALIGN_BYTES
+ and al, GA_MASK_BYTES
+ cCall alloc_arena_header, <eax>
+ mov edi, eax
+
+ cCall get_selector_address32, <dx>
+ mov ebx, eax
+else
+ pop ebx
+endif
+ sub ebx, ds:[edi].pga_address ; Length in bytes
+ mov ds:[edi].pga_size, ebx
+
+ mov eax, allocated_arena
+ mov ecx, BurgerMaster_arena
+ mov edx, new_last_arena
+
+; Fill in first block
+
+ xor ebx, ebx
+ mov ds:[esi].pga_sig,GA_SIGNATURE
+ mov ds:[esi].pga_size,ebx
+ mov ds:[esi].pga_owner,-1
+ mov ds:[esi].pga_flags,bx
+ mov ds:[esi].pga_prev,esi ; first.prev = self
+if ROM
+ mov ds:[esi].pga_next,eax ; first.next = alloced (ds)
+else
+ mov ds:[esi].pga_next,edi ; first.next = free
+endif
+ mov ds:[esi].pga_handle,bx
+ mov ds:[esi].pga_lrunext,ebx
+ mov ds:[esi].pga_lruprev,ebx
+
+; Fill in the last block (sentinel block)
+
+ mov ds:[edx].pga_sig,GA_ENDSIG
+ mov ds:[edx].pga_size,ebx
+ mov ds:[edx].pga_owner,-1 ; Always allocated
+ mov ds:[edx].pga_next,edx ; last.next = self
+if ROM
+ mov ds:[edx].pga_prev,edi ; last.prev = free
+else
+ mov ds:[edx].pga_prev,eax ; last.prev = alloced
+endif
+ mov ds:[edx].pga_flags,bx
+ mov ds:[edx].pga_handle, bx
+ mov ds:[edx].pga_lrunext,ebx
+ mov ds:[edx].pga_lruprev,ebx
+
+; Fill in the master object
+
+ mov ds:[ecx].pga_next,ecx
+ mov ds:[ecx].pga_prev,ecx
+ mov ds:[ecx].pga_sig,GA_SIGNATURE
+ mov ds:[ecx].pga_owner,-3
+ mov ds:[ecx].pga_flags,bx
+ mov ds:[ecx].pga_lruprev,ebx
+ mov ds:[ecx].pga_lrunext,ebx
+
+; Fill in the allocated block
+
+if ROM
+ mov ds:[eax].pga_next,edi ; next = free
+ mov ds:[eax].pga_prev,esi ; prev = first
+else
+ mov ds:[eax].pga_next,edx ; next object is Sentinel
+ mov ds:[eax].pga_prev,edi ; Previous object is second block
+endif
+ mov ds:[eax].pga_sig,GA_SIGNATURE
+ mov ds:[eax].pga_owner,-1
+ mov ds:[eax].pga_flags,bx
+ mov ds:[eax].pga_lruprev,ebx
+ mov ds:[eax].pga_lrunext,ebx
+
+; Fill in free block
+
+ mov ds:[edi].pga_sig,GA_SIGNATURE
+ mov ds:[edi].pga_owner,bx ; This is a free block
+ mov ds:[edi].pga_flags,bx
+if ROM
+ mov ds:[edi].pga_next,edx ; next = last
+ mov ds:[edi].pga_prev,eax ; prev = alloced
+else
+ mov ds:[edi].pga_next,eax ; Next obj allocated block
+ mov ds:[edi].pga_prev,esi
+endif
+ mov ds:[edi].pga_handle,bx
+ mov ds:[edi].pga_lruprev,ebx
+ mov ds:[edi].pga_lrunext,ebx
+
+; Initialize master object
+
+
+ mov ecx, size_master
+ mov dx,BurgerMaster_sel
+ shr ecx, 1
+
+ push ecx ; save size in words
+
+ mov pGlobalHeap,dx
+ mov es,dx
+ UnSetKernelDS es
+ xor eax,eax
+ xor di,di ; Init master object to zero
+ shr ecx, 1
+ rep stosd
+
+ mov ds,dx ; Switch to master object as our DS
+
+ pop ecx
+ shl ecx,1 ; ECX = size of master object in bytes
+
+ mov eax, allocated_arena ; EAX = address of allocated block
+ mov edx, new_last_arena ; EDX = address of last block
+ mov ebx, esi ; EBX = address of first block
+ mov esi, BurgerMaster_arena ; ESI = arena of BurgerMaster
+ clc
+Failginit:
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc InitialiseArenas,<PUBLIC,NEAR>
+ parmD StartOffset
+ parmD BytesAllocated
+cBegin
+ push ecx
+ push esi
+ push edi
+ CheckKernelDS es
+ ReSetKernelDS es
+ mov esi, StartOffset
+ mov ecx, BytesAllocated
+ add ecx, esi
+ mov FreeArenaList, esi ; Point to list
+ lea edi, [esi+size GlobalArena32]
+IA_loop:
+ cmp edi, ecx
+ jae short IA_done
+ mov [esi.pga_next], edi
+ add esi, size GlobalArena32
+ add edi, size GlobalArena32
+ inc FreeArenaCount
+ jmps IA_loop
+IA_done:
+ mov ds:[esi.pga_next], -1 ; Terminate list
+ UnSetKernelDS es
+ pop edi
+ pop esi
+ pop ecx
+cEnd
+
+sEnd INITCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3gmoreme.asm b/private/mvdm/wow16/kernel31/3gmoreme.asm
new file mode 100644
index 000000000..030a54092
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3gmoreme.asm
@@ -0,0 +1,723 @@
+ TITLE GMOREMEM - More Global Memory Manager procedures
+
+.xlist
+include kernel.inc
+include tdb.inc
+include newexe.inc
+.list
+
+include protect.inc
+
+.386p
+
+DataBegin
+
+externB Kernel_Flags
+externW pGlobalHeap
+externW curTDB
+externW headTDB
+externW Win_PDB
+externW MaxCodeSwapArea
+
+DataEnd
+
+
+externFP CalcMaxNRSeg
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+if SDEBUG
+externNP DebugMovedSegment
+endif
+
+
+externNP gcompact
+
+
+externNP get_physical_address
+externNP GrowHeap
+
+externNP guncompact
+
+;-----------------------------------------------------------------------;
+; genter ;
+; ;
+; Enters a critical region for the global heap. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; DS:DI = address of GlobalInfo for global heap ;
+; FS = Kernel Data segment ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 29, 1986 03:05:33p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc genter,<PUBLIC,NEAR>
+cBegin nogen
+ SetKernelDS FS
+ mov ds,pGlobalHeap
+ xor edi,edi
+ inc [di].gi_lrulock
+ ret
+ UnSetKernelDS FS
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gleave ;
+; ;
+; Leaves a critical region for the global heap. ;
+; ;
+; Arguments: ;
+; DS:DI = address of GlobalInfo for global heap ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 29, 1986 03:07:53p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gleave,<PUBLIC,NEAR>
+cBegin nogen
+ dec ds:[gi_lrulock]
+ jnz short gl_ret
+ test ds:[gi_flags],GIF_INT2
+ jz short gl_ret
+ and ds:[gi_flags],NOT GIF_INT2
+ int 02h
+gl_ret: ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gavail ;
+; ;
+; Gets the available memory. ;
+; ;
+; Arguments: ;
+; DX = number of paragraphs wanted ;
+; DS:DI = master object ;
+; Returns: ;
+; AX = #paragraphs available for the biggest block ;
+; DX = 0 ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; DI,DS ;
+; Registers Destroyed: ;
+; BX,CX,SI,ES ;
+; Calls: ;
+; gcompact ;
+; ;
+; History: ;
+; Thu Apr 06, 1988 08:00:00a -by- Tim Halvorsen [iris] ;
+; Fix bug in computation of space available when GA_NOT_THERE object ;
+; resides above discard fence. ;
+; ;
+; Wed Oct 15, 1986 05:09:27p -by- David N. Weise [davidw] ;
+; Moved he_count to ga_count. ;
+; ;
+; Sat Sep 27, 1986 09:37:27a -by- David N. Weise [davidw] ;
+; Reworked it. ;
+;-----------------------------------------------------------------------;
+
+cProc gavail,<PUBLIC,NEAR>
+cBegin nogen
+ push esi
+ push ecx
+ mov byte ptr [di].gi_cmpflags,0
+ call gcompact
+
+ mov cx,word ptr [di].gi_disfence_hi ; ECX has address of fence
+ shl ecx, 16
+ mov cx,word ptr [di].gi_disfence_lo
+ mov esi,[di].phi_first
+ xor edx,edx
+loop_for_beginning:
+ xor eax,eax
+ mov esi,ds:[esi].pga_next ; Next block
+ cmp ds:[esi].pga_sig,GA_ENDSIG ; End of arena?
+ je all_done
+ mov ebx, ds:[esi].pga_address
+ add ebx, ds:[esi].pga_size ; End of block
+ sub ebx, ecx ; Below fence?
+ jbe short include_it ; yes, use it
+ cmp ebx, ds:[di].gi_reserve ; Difference > reserve?
+ jb all_done ; no, can't use it
+include_it:
+ cmp ds:[esi].pga_owner,di ; Free?
+ jz short how_big_is_it ; Yes calculate length
+ cmp ds:[esi].pga_owner,GA_NOT_THERE ; Marker arena?
+ jz short loop_for_beginning ; Yes, next block
+ mov bx,ds:[esi].pga_handle
+ test bl, GA_FIXED ; Fixed?
+ jnz short loop_for_beginning ; Yes, next block
+ cmp ds:[esi].pga_count,0 ; Locked?
+ jne short loop_for_beginning ; Yes, next block
+ lar ebx, ebx ; See lar docs and protect.inc
+ test ebx, DSC_DISCARDABLE SHL 16 ; bit is in third byte of EBX
+ jz short loop_for_beginning ; Not discardable, next block
+
+how_big_is_it:
+ mov eax,ds:[esi].pga_size ; Use this size
+loop_for_bigness:
+ mov esi,ds:[esi].pga_next ; Next block
+ cmp ds:[esi].pga_owner,di ; Free?
+ jz short include_his_size ; Yes, include size
+ cmp ds:[esi].pga_owner,GA_NOT_THERE ; Marker arena?
+ jz short end_of_bigness ; Yes
+
+ cmp ds:[esi].pga_sig,GA_ENDSIG ; End of arena?
+ jz short end_of_bigness
+ mov bx,ds:[esi].pga_handle
+ test bx,GA_FIXED ; Fixed?
+ jnz short end_of_bigness ; Yes, stop looking
+ cmp ds:[esi].pga_count,0 ; Locked?
+ jne short end_of_bigness ; Yes, stop looking
+ lar ebx, ebx ; See lar docs and protect.inc
+ test ebx, DSC_DISCARDABLE SHL 16 ; bit is in third byte of EBX
+ jz short loop_for_bigness ; No, dont include in count then
+include_his_size: ; Free or Discardable
+ add eax,ds:[esi].pga_size ; Increase available space
+ jmp loop_for_bigness
+
+end_of_bigness:
+ mov esi, ds:[esi].pga_prev ; Get end of useable block
+ mov ebx, ds:[esi].pga_address
+ add ebx, ds:[esi].pga_size
+ mov esi, ds:[esi].pga_next
+ sub ebx, ecx ; Subtract fence
+ jbe short all_below_fence
+ cmp ebx, ds:[di].gi_reserve
+ jae short all_below_fence
+
+ sub eax,ebx ; We are above the fence, subtract
+ ; that above the fence and say goodbye
+all_below_fence:
+ cmp eax,edx ; Did we find a bigger block?
+ jbe short blech_o_rama ; No, then look again
+ mov edx,eax ; Yes, remember size
+blech_o_rama:
+ jmp loop_for_beginning
+
+all_done:
+ mov eax,edx
+ sub eax, 20h ; Dont be too exact
+ or eax,eax ; See if negative
+ jns short gcfinal
+ xor eax, eax ; Disallow negative returns
+gcfinal:
+ and al,NOT 1Fh ; round down to nearest alignment
+ xor dx,dx
+ pop ecx
+ pop esi
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; greserve ;
+; ;
+; Sets the size of the discardable code reserve area. ;
+; If the new size is larger than the old size, it checks to see ;
+; if there is enough room to support the new size. ;
+; ;
+; Arguments: ;
+; AX = new greserve size ;
+; ;
+; Returns: ;
+; CX = the largest greserve we can get ;
+; AX != 0 success ;
+; AX = 0 failure ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,DX,ES ;
+; ;
+; Calls: ;
+; genter ;
+; gcompact ;
+; will_gi_reserve_fit ;
+; gleave ;
+; ;
+; History: ;
+; Fri Jun 14, 1991 -by- Craig A. Critchley [craigc] ;
+; Lots has happened since 1987 - undo change to get 128K always in ;
+; enhanced mode, added call to guncompact for ROM ;
+; ;
+; Tue May 19, 1987 00:03:08p -by- David N. Weise [davidw] ;
+; Made it far. ;
+; ;
+; Sat Sep 27, 1986 01:03:08p -by- David N. Weise [davidw] ;
+; Made it perform according to spec and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc greserve,<PUBLIC,FAR> ; FAR because of the gcompact below
+ localD new_size
+cBegin
+ GENTER32
+ ReSetKernelDS FS
+
+ movzx eax, ax
+ shl eax, 5 ; convert to bytes and double
+ cmp eax, 020000h ; if >= 128k, THAT'S ENOUGH!
+ jb short no_extra ; So there, Mr EXCEL!
+ mov eax, 020000h
+
+no_extra:
+ add eax,GA_ALIGN_BYTES
+ and al,GA_MASK_BYTES
+
+ mov new_size,eax
+ mov ebx,eax
+ mov eax, ds:[di].phi_last
+ mov eax, ds:[eax].pga_address
+ sub eax,ebx ; Address of new gi_reserve
+ cmp ebx, [di].gi_reserve ; New value <= old?
+ ja short @F
+ jmp new_okay
+@@:
+if KDEBUG
+ mov ecx, ebx
+ shr ecx, 16
+ krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "greserve: #cx#BX bytes"
+endif
+
+ call will_gi_reserve_fit
+ jnc short new_okay
+
+ mov edx, new_size
+ call GrowHeap
+ jc short try_compacting
+ mov eax, ds:[di].phi_last
+ mov eax, ds:[eax].pga_address
+ sub eax, new_size
+ call will_gi_reserve_fit
+ jnc short new_okay
+
+try_compacting:
+ push eax ; Must be junk in the way!
+ push edx
+ mov edx,new_size
+ call gcompact ; Try compacting to get new reserve
+ mov ecx, new_size
+ call guncompact ; slide stuff down after compact
+ pop edx
+ pop eax
+ call will_gi_reserve_fit
+ jnc short new_okay
+
+will_not_fit:
+if KDEBUG
+ krDebugOut DEB_ERROR, "greserve doesn't fit"
+endif
+ xor ax,ax
+ jmps gr_exit
+
+new_okay:
+ mov word ptr [di].gi_disfence_lo,ax
+ shr eax, 16
+ mov word ptr [di].gi_disfence_hi,ax
+ mov edx,new_size
+ mov [di].gi_reserve,edx
+gr_exit:
+ GLEAVE32
+ UnSetKernelDS FS
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; will_gi_reserve_fit ;
+; ;
+; See if new size okay by scanning arena backwards. If not under EMS ;
+; this is trivial. With EMS we take into consideration the disjoint ;
+; areas and the WRAITHS. ;
+; ;
+; Arguments: ;
+; EAX = gi_disfence ;
+; DS:DI = master object ;
+; ;
+; Returns: ;
+; CF = 0 new size ok ;
+; CF = 1 new size NOT ok ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; none ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Jul 12, 1987 08:13:23p -by- David N. Weise [davidw] ;
+; Added EMS support. ;
+; ;
+; Sat Sep 27, 1986 01:03:57p -by- David N. Weise [davidw] ;
+; Rewrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc will_gi_reserve_fit,<PUBLIC,NEAR>
+cBegin nogen
+
+ push esi
+
+ mov esi, [di].phi_last
+ mov esi, [esi].pga_prev ; skip sentinal
+
+does_it_fit:
+ mov esi, [esi].pga_prev ; do first to skip nothere
+ cmp [esi].pga_owner, di ; is it free?
+ je short ok_thisll_fit
+ test [esi].pga_flags, GA_DISCCODE ; is it code?
+ jz short nope_wont_fit
+ok_thisll_fit:
+ cmp eax, [esi].pga_address ; do we have enough
+ jb short does_it_fit
+
+it_all_fits:
+ clc ; return excellent!
+ pop esi
+ ret
+
+nope_wont_fit:
+ stc ; return heinous!
+ pop esi
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gnotify ;
+; ;
+; This is where the hard job of updating the stacks and thunks happens. ;
+; We only walk stacks and thunks for code and data (defined by being ;
+; LocalInit'ed), not for resources or task allocated segments. ;
+; ;
+; Arguments: ;
+; AL = message code ;
+; BX = handle ;
+; CX = optional argument ;
+; ESI = address of arena header ;
+; ;
+; Returns: ;
+; AX = return value from notify proc or AL ;
+; DS = current DS (i.e. if DATA SEG was moved then DS is updated. ;
+; ZF = 1 if AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Jun 24, 1987 03:08:39a -by- David N. Weise [davidw] ;
+; Adding support for Global Notify. ;
+; ;
+; Wed Dec 03, 1986 01:59:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gnotify,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ push di
+ xor ah,ah
+ mov di,cx
+ mov cx,ax
+ loop notify_discard
+ errnz <GN_MOVE - 1>
+
+ mov cx,ds
+ cmp cx,bx ; Did we move DS?
+ jne short notify_exit_0 ; No, continue
+notify_exit_0:
+ jmp notify_exit
+
+notify_discard:
+ loop notify_exit_0
+ errnz <GN_DISCARD - 2>
+
+;-----------------------------------------------------------------------;
+; Here for a segment discarded. ;
+;-----------------------------------------------------------------------;
+
+ xor ax,ax
+ test bl,1
+ jnz short notify_exit_0 ; SDK is wrong, can't free fixed.
+ push ebx
+ lar ebx, ebx ; See lar docs and protect.inc
+ test ebx, DSC_DISCARDABLE SHL 16 ; bit is in third byte of EBX
+ pop ebx
+ jz short notify_exit_0
+
+ test ds:[esi].pga_flags,GAH_NOTIFY
+ jnz @F
+ jmp dont_bother_asking
+@@:
+ push bx
+ push cx
+ push dx
+ mov ax,1
+ mov es,ds:[esi].pga_owner
+ cmp es:[ne_magic],NEMAGIC
+ jz short dont_ask ; doesn't belong to a particular task
+ mov ax,es
+ SetKernelDS es
+ push HeadTDB ; Look for TDB that owns this block.
+ UnSetKernelDS es
+find_TDB:
+ pop cx
+ jcxz dont_ask
+ mov es,cx
+ push es:[TDB_next]
+ cmp ax,es:[TDB_PDB]
+ jnz short find_TDB
+ pop cx ; clear stack in 1 byte
+ mov cx,word ptr es:[TDB_GNotifyProc][0] ; paranoia
+ or cx,word ptr es:[TDB_GNotifyProc][2]
+ jz short dont_ask
+ push ds
+ SetKernelDS
+ or Kernel_Flags[1],kf1_GLOBALNOTIFY
+
+ push Win_PDB ; Save current PDB
+ mov Win_PDB, ax ; Ensure it is the task's
+ push fs
+
+ push dword ptr es:[TDB_GNotifyProc]
+
+ push bx ; push arg for notify proc
+
+ mov ax,ss ; Zap segment regs so DS
+ mov ds,ax ; doesn't get diddled by callee
+ mov es,ax
+
+ mov bx,sp
+ call dword ptr ss:[bx]+2
+ add sp,4 ; clean up stack.
+
+ SetKernelDS
+ and Kernel_Flags[1],not kf1_GLOBALNOTIFY
+
+ pop fs
+ pop Win_PDB ; Restore PDB
+
+ pop ds
+ UnSetKernelDS
+dont_ask:
+ pop dx
+ pop cx
+ pop bx
+ or ax,ax ; Well, can we?
+ jz short notify_exit
+dont_bother_asking:
+
+ mov es,ds:[esi].pga_owner
+ cmp es:[ne_magic],NEMAGIC
+ jnz short not_in_exe
+ mov di,es:[ne_segtab]
+ mov cx,es:[ne_cseg]
+ jcxz not_in_exe
+pt0a:
+ cmp bx,es:[di].ns_handle
+ jz short pt0b
+ add di,SIZE NEW_SEG1
+ loop pt0a
+ jmps not_in_exe
+pt0b:
+ and byte ptr es:[di].ns_flags,not NSLOADED ; Mark as not loaded.
+not_in_exe:
+
+why_bother_again:
+ xor di,di
+if SDEBUG
+ cCall DebugMovedSegment,<si,di>
+endif
+ mov ax,1
+notify_exit:
+ or ax,ax
+ pop di
+ pop si
+ ret
+
+gn_error:
+ kerror 0FFh,<gnotify - cant discard segment>,si,si
+ xor ax,ax
+ jmp notify_exit
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; MemoryFreed ;
+; ;
+; This call is apps that have a GlobalNotify procedure. Some apps ;
+; may shrink the segment instead of allowing it to be discarded, or ;
+; they may free other blocks. This call tells the memory manager ;
+; that some memory was freed somewhere. ;
+; ;
+; Arguments: ;
+; WORD = # paragraphs freed ;
+; ;
+; Returns: ;
+; DX:AX = amount of memory that still needs freeing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri 08-Apr-1988 10:25:55 -by- David N. Weise [davidw] ;
+; Wrote it! ;
+;-----------------------------------------------------------------------;
+
+cProc MemoryFreed,<PUBLIC,FAR>
+
+ parmW memory_freed
+cBegin
+ xor ax,ax
+ SetKernelDS
+ test Kernel_Flags[1],kf1_GLOBALNOTIFY
+ jz short mf_done
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ mov ax,memory_freed
+ or ax,ax
+ jz short mf_inquire
+ or ds:[hi_ncompact],1 ; Remember we discarded something
+ sub ds:[hi_distotal],ax ; Have we discarded enough yet?
+ ja short mf_inquire
+ or ds:[hi_ncompact],10h ; To tell gdiscard that we're done.
+mf_inquire:
+ mov ax,ds:[hi_distotal] ; Have we discarded enough yet?
+mf_done:
+ xor dx,dx
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSwapAreaSize ;
+; ;
+; Sets the current task's code swap area size. ;
+; ;
+; Arguments: ;
+; WORD == 0 then current size is just returned ;
+; != 0 number paragraphs wanted for swap area ;
+; Returns: ;
+; AX = Size actually set ;
+; DX = Max size you can get ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Apr 18, 1988 08:00:00a -by- Tim Halvorsen [iris] ;
+; Move routine into CODE segment, so applications can query the ;
+; code working set value without paging in the NRESCODE segment. ;
+; ;
+; Thu Apr 23, 1987 09:36:00p -by- Raymond E. Ozzie [-iris-] ;
+; Added ability to get size without setting it. ;
+; ;
+; Wed Dec 03, 1986 10:52:16p -by- David N. Weise [davidw] ;
+; Rewrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc SetSwapAreaSize,<PUBLIC,FAR>
+ parmW nParas
+ localW MxCodeSwapArea
+cBegin
+ SetKernelDS
+ mov ax,nParas
+ mov cx,MaxCodeSwapArea
+ mov MxCodeSwapArea,cx ; avoid a segment load later
+ cmp ax,cx
+ jbe short requested_size_OK
+ mov ax,cx
+requested_size_OK:
+ mov ds,CurTDB
+ UnSetKernelDS
+ mov ds,ds:[TDB_pModule] ; Get exe header address
+ or ax,ax ; just a query request?
+ jz short got_it ; yes
+ xchg ds:[ne_swaparea],ax
+ push ax
+ call CalcMaxNRSeg
+ pop dx
+ or ax,ax
+ jnz short got_it
+ mov ds:[ne_swaparea],dx
+got_it:
+ mov ax,ds:[ne_swaparea]
+ mov dx,MxCodeSwapArea
+ cmp cx,dx
+ ja short cant_get_that_much
+ mov dx,cx
+cant_get_that_much:
+cEnd
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/3protect.asm b/private/mvdm/wow16/kernel31/3protect.asm
new file mode 100644
index 000000000..dcd950ab8
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/3protect.asm
@@ -0,0 +1,4653 @@
+ PAGE ,132
+ TITLE Windows Protect Mode Routines
+
+.xlist
+include kernel.inc
+
+ .386p
+
+include protect.inc
+include pdb.inc
+.list
+
+ifdef WOW
+
+;
+; the dpmi func 04f1h is idential to function 00h, except that
+; the descriptor base and limit are not initialized to zero.
+;
+
+;
+; the dpmi func 04f2h is identical to 0ch except that it
+; sets 'count' (in cx) LDTs at one time. The first selector is in
+; register bx. The descriptor data is in gdtdsc[bx], gdtdsc[bx+8]
+; etc. This data is shared between dpmi (dosx.exe) and us and thus
+; need not be passed in es:di
+
+WOW_DPMIFUNC_00 equ 04f1h
+WOW_DPMIFUNC_0C equ 04f2h
+
+
+endif
+
+
+MovsDsc Macro ;Move (copy) a descriptor (4 words)
+ cld
+ movsd
+ movsd
+ endm
+
+CheckDS Macro
+ local okds
+if KDEBUG
+ push ax
+ mov ax, ds
+ SetKernelDS
+ cmp ax, ArenaSel
+ mov ds, ax
+ UnSetKernelDS
+ je short okds
+ int 3
+ int 3
+okds:
+ pop ax
+endif
+ endm
+
+CheckLDT Macro selector
+if KDEBUG
+ test selector,SEL_LDT
+ jnz short @F
+ int 3
+@@:
+endif
+ Endm
+
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+
+
+MY_SEL equ 0F00h ; Access word to indicate selector owned by kernel
+
+externW pLocalHeap
+
+DataBegin
+
+ifdef WOW
+externW SelectorFreeBlock
+externW UserSelArray
+externB fBooting
+globalW high0c,0
+globalD FlatAddressArray,0
+endif
+
+
+externW MyCSSeg
+externW WinFlags
+externW ArenaSel
+externW pGlobalHeap
+
+externW MyCSAlias
+
+extrn kr1dsc:WORD
+extrn kr2dsc:WORD
+extrn blotdsc:WORD
+extrn DemandLoadSel:WORD
+extrn FreeArenaList:DWORD
+extrn FreeArenaCount:DWORD
+extrn HighestArena:DWORD
+extrn temp_arena:DWORD
+extrn SelTableLen:word
+extrn SelTableStart:DWORD
+extrn temp_sel:WORD
+extrn FirstFreeSel:WORD
+extrn CountFreeSel:WORD
+
+if ROM
+externW selROMTOC
+externW selROMLDT
+externW sel1stAvail
+endif
+
+if ROM
+externD lmaHiROM
+externD cbHiROM
+externD linHiROM
+endif
+
+DataEnd
+
+DataBegin INIT
+
+RModeCallStructure STRUC
+RMCS_EDI dd 0
+RMCS_ESI dd 0
+RMCS_EBP dd 0
+RMCS_Res dd 0
+RMCS_EBX dd 0
+RMCS_EDX dd 0
+RMCS_ECX dd 0
+RMCS_EAX dd 0
+RMCS_Flags dw 0
+RMCS_ES dw 0
+RMCS_DS dw 0
+RMCS_FS dw 0
+RMCS_GS dw 0
+RMCS_IP dw 0
+RMCS_CS dw 0
+RMCS_SP dw 0
+RMCS_SS dw 0
+RModeCallStructure ENDS
+
+MyCallStruc RModeCallStructure <>
+
+globalD lpProc,0
+
+if ROM
+externW gdtdsc
+endif
+
+public MS_DOS_Name_String
+MS_DOS_Name_String db "MS-DOS", 0
+
+DataEnd INIT
+
+externFP IGlobalFree
+externFP IGlobalAlloc
+
+sBegin CODE
+assumes cs,CODE
+assumes ds,nothing
+
+
+externNP genter
+extrn GrowHeapDib: FAR
+extrn LocalNotifyDib: FAR
+extrn LocalNotifyDefault: FAR
+extrn FreeHeapDib: FAR
+externNP gleave
+extrn IGlobalFix:FAR ;Far calls in this segment
+extrn GlobalHandleNorip:FAR
+extrn IGlobalFlags:FAR
+extrn IGlobalHandle: FAR
+extrn Free_Object2: FAR
+
+extrn mycsds:WORD
+
+ife ROM
+extrn gdtdsc:WORD
+endif
+
+ifdef WOW
+externD prevInt31proc
+externFP VirtualAlloc
+endif
+
+
+sEnd CODE
+
+sBegin INITCODE
+assumes cs,CODE
+assumes ds,nothing
+
+;=======================================================================;
+; ;
+; 386 PROTECTED MODE INITIALISATION ROUTINES ;
+; ;
+;=======================================================================;
+
+ife ROM
+
+; this function is not used in ROM since DOSX switches to Pmode before
+; jumping to kernel. this means the enhanced mode loader will have
+; to do something similar...
+
+;-----------------------------------------------------------------------;
+; SwitchToPMODE ;
+; ;
+; Entry: ;
+; In Real or Virtual Mode ;
+; ES -> PSP ;
+; ;
+; Returns: ;
+; In Protect Mode ;
+; BX -> LDT selector ;
+; SI -> Segment of start of available memory ;
+; ES -> PSP ;
+; ;
+; Error Returns: ;
+; Exits via DOS call 4Ch ;
+; ;
+; Registers Preserved: ;
+; ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,DATA
+ assumes es,nothing
+
+
+cProc SwitchToPMODE,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ push es ; Current PSP
+
+ mov ax, 1687h
+ int 2Fh ; Get PMODE switch entry
+ or ax, ax ; Can we do it?
+ jnz NoPMODE
+
+ xor bh, bh ; Set CPU type now
+ cmp cl, 3 ; At least a 386?
+ jb NoPMODE
+
+ mov bl,WF_CPU386
+ je short @F ; If 386
+ mov bl,WF_CPU486 ; No, assume 486 for now
+@@:
+ mov WinFlags, bx ; Save away CPU type
+ mov word ptr [lpProc][0], di
+ mov word ptr [lpProc][2], es
+ pop ax ; PSP
+ add ax, 10h ; Skip the PSP
+ mov es, ax ; Give this to the DOS extender
+ add si, ax ; Start of memory available to us
+
+ ; THIS IS IT FOLKS!
+ xor ax, ax ; 16-bit app
+ call [lpProc] ; Switch to PROTECTED mode
+ jc NoPMODE ; No, still Real/Virtual mode
+
+ mov ax, cs
+ and al, 7 ; LDT, Ring 3
+ cmp al, 7
+ jne short BadDPMI ; Insist on Ring 3!
+
+ mov bx, cs ; Allocate CS Alias
+ DPMICALL 000Ah
+
+ mov MyCSAlias, ax ; Save CS Alias in DS
+
+ mov bx, ds ; Use alias to update code seg var
+ mov ds, ax
+ assumes ds, CODE
+
+ mov MyCSDS, bx ; The DS selector
+
+ mov ds, bx
+ ReSetKernelDS
+
+ push es
+ push si
+ mov ax, 168Ah ; See if we have MS-DOS extensions
+ mov si, dataoffset MS_DOS_Name_String
+ int 2Fh ; DS:SI -> MS-DOS string
+ cmp al, 8Ah ; Have extensions?
+ je short BadDPMI ; no extensions, screwed
+
+ mov [lpProc][0], di ; Save CallBack address
+ mov [lpProc][2], es
+
+ mov ax, 0100h ; Get base of LDT
+ call [lpProc]
+ jc short NoLDTParty
+ verw ax ; Writeable?
+ jnz short NoLDTParty ; nope, don't bother with it yet
+
+ mov es, MyCSAlias
+ assumes es,CODE
+ mov gdtdsc, ax
+ assumes es,nothing
+
+NoLDTParty:
+ pop si
+ pop es
+
+ push si ; Unlock all of our memory
+ifndef WOW ; For WOW its all pageable
+ movzx ebx, si
+ shl ebx, 4 ; Linear address of start of our memory
+ movzx esi, es:[PDB_block_len] ; End of our memory
+ shl esi, 4
+ sub esi, ebx ; Size of our block
+ mov di, si
+ shr esi, 10h
+ mov cx, bx
+ shr ebx, 10h
+ mov ax, 0602h
+ int 31h ; Mark region as pageable.
+endif
+ pop bx
+ mov ax, 2 ; Convert start of memory to selector
+ int 31h
+ mov si, ax
+
+ xor bx, bx
+ pop cx
+ ret
+
+BadDPMI:
+ ;
+ ; Call real/virtual mode to whine
+ ;
+ xor cx, cx ; Nothing on stack to copy
+ xor bh, bh ; Flags to DPMI
+ mov ax, MyCSSeg
+ mov MyCallStruc.RMCS_DS, ax ; Real mode DS will be parent PDB
+ mov MyCallStruc.RMCS_ES, cx ; Real mode ES will be 0
+ mov MyCallStruc.RMCS_CS, ax ; Real mode CS
+ mov MyCallStruc.RMCS_IP, codeoffset RModeCode ; Real mode IP
+
+ smov es, ds
+ mov di, dataOffset MyCallStruc ; ES:DI points to call structure
+ mov ax, 0301h ; Call Real Mode Procedure
+ int 31h
+ jmps GoodBye
+
+RModeCode:
+ mov dx, codeoffset szInadequate
+ mov ah, 9
+ int 21h
+ retf
+
+;Inadequate:
+; DB 'KRNL386: Inadequate DPMI Server',13,10,'$'
+externB <szNoPMode, szInadequate>
+
+NoPMODE: ; NOTE: stack trashed...
+ifdef WOW
+ ;** Put Up a Dialog Box If we fail to Enter Protect Mode
+ ;** Prepare the dialog box
+ push cs ;In our DS
+ push codeOFFSET szNoPMode ; -> unable to enter Prot Mode
+
+ push ds
+externB <syserr>
+ push dataOffset syserr ;Caption
+
+ push 0 ;No left button
+
+ push SEB_CLOSE + SEB_DEFBUTTON ;Button 1 style
+
+ push 0 ;No right button
+externFP kSYSERRORBOX
+ call kSYSERRORBOX ;Put up the system error message
+externNP ExitKernel
+ jmp ExitKernel
+
+else ; Not WOW
+
+ mov dx, codeoffset szNoPMode
+; call complain
+; DB 'KRNL386: Unable to enter Protected Mode',13,10,'$'
+;complain:
+; pop dx
+ push cs
+ pop ds ; DS:DX -> error message
+ mov ah,9 ; Print error message
+ int 21h
+
+endif; WOW
+
+GoodBye:
+ mov ax, 4CFFh
+ int 21h
+cEnd nogen
+
+endif
+
+;-----------------------------------------------------------------------;
+; LDT_Init ;
+; ;
+; Entry: ;
+; DS -> CS ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+cProc LDT_Init,<PUBLIC,NEAR>,<ax,bx,cx,di,es>
+cBegin
+ ReSetKernelDS
+
+ cmp gdtdsc, 0
+ jz short SlowAllocation
+;
+; Scan LDT for free selectors and
+; put on a linked list
+;
+ mov es, gdtdsc
+ mov cx, 1
+ DPMICALL 0000h ; Get selector from win386
+ and al, NOT SEG_RING_MASK
+ mov FirstFreeSel, ax ; Set up header
+ mov si, ax
+ mov word ptr es:[si], -1
+ mov word ptr es:[si].dsc_access, MY_SEL ; MINE!
+
+ mov cx, es
+ lsl ecx, ecx ; limit of LDT
+ xor eax, eax
+
+steal_sels:
+ mov di, si ; prev selector in list
+not_this_one:
+ add si, DSC_LEN ; use add for flags
+ jz short end_ldt
+ cmp si, cx
+ ja short end_ldt
+
+ cmp dword ptr es:[si], eax
+ jne not_this_one
+ cmp dword ptr es:[si][4], eax
+ jne not_this_one
+
+ mov word ptr es:[di], si ; Link into list
+ mov word ptr es:[si].dsc_access, MY_SEL ; MINE!
+ inc CountFreeSel
+ jmps steal_sels
+
+end_ldt:
+ mov word ptr es:[di], -1
+SlowAllocation:
+
+ push es ; Get random selectors
+ smov es, ds
+ ReSetKernelDS es
+ UnSetKernelDS
+ ; Could get 3 selectors at once here,
+ ; but get_sel is more efficient for just 1
+ mov cx, 1 ; Argument to get_sel
+ call get_sel
+ or si, SEG_RING
+ mov kr1dsc, si
+ call get_sel
+ mov kr2dsc, si
+ call get_sel
+ mov blotdsc, si
+ call get_sel
+ or si, SEG_RING
+ mov DemandLoadSel, si ; for demand loading segments
+ smov ds, es
+ pop es
+ UnSetKernelDS es
+cEnd
+
+sEnd INITCODE
+
+sBegin CODE
+assumes cs,CODE
+assumes ds,nothing
+
+
+;=======================================================================;
+; ;
+; SELECTOR ALLOCATION/DEALLOCATION ROUTINES ;
+; ;
+;=======================================================================;
+
+
+;-----------------------------------------------------------------------;
+; AllocSelector
+;
+;
+; Entry:
+;
+; Returns:
+; AX = 0 if out of selectors
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifdef WOW
+labelFP <PUBLIC,AllocSelectorWOW>
+ mov ax, 1
+ jmps AllocSelectorWorker
+
+labelFP <PUBLIC,AllocSelector>
+ xor ax, ax
+ ; fall through
+
+cProc AllocSelectorWorker,<PUBLIC,FAR>,<di,si,es>
+ parmW selector
+ localV OldDsc,DSC_LEN
+ localW fDontSetDescriptor
+cBegin
+ mov fDontSetDescriptor, ax
+else
+cProc AllocSelector,<PUBLIC,FAR>,<di,si,es>
+ parmW selector
+ localV OldDsc,DSC_LEN
+cBegin
+
+endif
+
+ mov cx, 1
+ lsl ecx, dword ptr selector
+ jz short as_present
+
+ call get_sel ; He passed in some junk, give him
+ifdef WOW ; just one selector...
+ ; If we have a good selector, use DPMI to write it through to the
+ ; system LDT before giving it to an application to use.
+ jz short as_exit1
+ mov ax, [bp+4] ; Get caller CS.
+ cmp ax, IGROUP ; Don't write thru if it's KRNL386 calling.
+ je short as_exit
+ cmp ax, _NRESTEXT
+ je short as_exit
+ cmp ax, _MISCTEXT
+ je short as_exit
+
+ ;Set shadow LDT entry to known state.
+ push bx
+ push ds
+ mov ds, gdtdsc ; Get shadow LDT in DS
+ UnSetKernelDS
+ mov bx, si
+
+ mov [bx].dsc_limit, 00h ; Set entry to: BASE = 0, LIMIT = 0, BYTES,
+ mov [bx].dsc_lbase, 00h ; DPL = 3, PRESENT, DATA
+ mov [bx].dsc_mbase, 00h
+ mov [bx].dsc_hbase, 00h
+ mov ax, DSC_DATA+DSC_PRESENT
+ mov word ptr [bx].dsc_access, ax
+ pop ds
+
+ DPMICALL WOW_DPMIFUNC_0C ; Write shadow LDT entry thru to system LDT.
+ pop bx
+ jmps as_exit
+else
+ jnz short as_exit ; just one selector...
+ jmps as_exit1
+endif
+
+as_present:
+ Limit_To_Selectors ecx
+
+ call get_sel
+ jz short as_exit1
+ifdef WOW
+ test fDontSetDescriptor, 1
+ jnz as_exit
+endif
+ smov es, ss
+ lea di, OldDsc ; ES:DI points to descriptor
+ mov bx, selector ; BX gets old selector
+
+ push ds
+if ROM
+ SetKernelDS
+endif
+ mov ds, gdtdsc
+if ROM
+ assumes ds,nothing
+endif
+ push si ; Get Descriptor
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+ mov bx, si ; BX gets new selector
+ or bl, SEG_RING
+
+ call fill_in_selector_array ; and set new array to match
+
+as_exit:
+ or si, SEG_RING
+as_exit1:
+ mov ax,si
+cEnd
+
+;-----------------------------------------------------------------------;
+; AllocResSelArray - Allocate a resource Selector array (see resaux) ;
+; Combination of AllocSelectorArray + SetResourceOwner;
+; Entry: ;
+; nSels = # selectors required ;
+; parmW owner ;
+; ;
+; ;
+; ;
+; get_sel - get an array of selectors ;
+; ;
+; Entry: ;
+; CX = # selectors required ;
+; ;
+; Returns: ;
+; SI = First Selector ;
+; DS = LDT ;
+; ZF = 0 ;
+; ;
+; Error Returns: ;
+; SI = 0 ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; DI,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; mattfe March 30th 1993 - WOW Specific Routine, by combining the two ;
+; routines I can reduce the number of DPMI calls by 40/1 for loading ;
+; a typical app. ;
+;-----------------------------------------------------------------------;
+ifdef WOW
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc AllocResSelArray,<PUBLIC,NEAR>,<cx,si,di,es,ds>
+ parmW nSels
+ parmW owner
+cBegin
+ mov cx, nSels
+ call get_sel
+ mov ax, si
+ jz short ARSA_fail
+
+ or si, SEG_RING
+ mov bx, si
+
+ mov dx, cx
+
+ push ds
+ mov ds, gdtdsc
+ push bx
+ and bl, not 7
+
+;; For the first selector mark it with the resource owner
+
+ mov cx, owner
+ mov ds:[bx].dsc_owner, cx
+ mov word ptr ds:[bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
+ mov cx,nSels
+ mov ds:[bx].dsc_hbase, cl ; Save number of selectors here
+
+ mov cx, DSC_DATA+DSC_PRESENT
+
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jz ASRA_CallNT
+
+ARSA_fill_in_access:
+ mov word ptr ds:[bx].dsc_access, cx
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jnz ARSA_fill_in_access
+
+ASRA_CallNT:
+ mov bx,si ; First Selector
+ mov cx,nSels ; Count
+ DPMICALL WOW_DPMIFUNC_0C
+
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector32,<si,0,owner> ; And save in selector table
+ pop ax ; Return first sel
+ pop ds
+
+ARSA_fail:
+cEnd
+endif ; WOW
+
+
+;-----------------------------------------------------------------------;
+; AllocSelectorArray - external entry for get_sel ;
+; Entry: ;
+; nSels = # selectors required ;
+; ;
+; get_sel - get an array of selectors ;
+; ;
+; Entry: ;
+; CX = # selectors required ;
+; ;
+; Returns: ;
+; SI = First Selector ;
+; DS = LDT ;
+; ZF = 0 ;
+; ;
+; Error Returns: ;
+; SI = 0 ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; DI,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc AllocSelectorArray,<PUBLIC,FAR>,<si>
+ parmW nSels
+cBegin
+ mov cx, nSels
+ call get_sel
+ mov ax, si
+ jz short asa_fail
+
+ or si, SEG_RING
+ mov bx, si
+ mov dx, cx
+ mov cx, DSC_DATA+DSC_PRESENT
+ifdef WOW ; LATER should use single op to update
+fill_in_access: ; complete LDT with one call.
+ DPMICALL 0009h
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jnz fill_in_access
+else
+ push ds
+ mov ds, gdtdsc
+ push bx
+ and bl, not 7
+fill_in_access:
+ mov word ptr ds:[bx].dsc_access, cx
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ lea bx, [bx+DSC_LEN]
+ dec dx
+ jnz fill_in_access
+ pop bx
+ pop ds
+endif; WOW
+ mov ax, si
+
+
+asa_fail:
+cEnd
+
+if KDEBUG
+cProc check_free_sel_list,<PUBLIC,NEAR>
+cBegin
+ pushf
+ pusha
+ push ds
+
+ call SetKernelDSProc ; Must call direct in this file
+ ReSetKernelDS
+
+ mov cx, CountFreeSel
+ cmp cx, 2 ; Only check list with more than 1 entry.
+ jb cfl_ok
+ inc cx ; Count dummy entry.
+ mov si, FirstFreeSel ; Pointer to head of list
+ mov ds, gdtdsc ; Get shadow LDT in DS
+ UnSetKernelDS
+
+cfl_loop:
+ mov ax, word ptr [si] ; Get next.
+ cmp ax, 0FFFFH ; -1 is sentinal
+ je short cfl_trashed
+ mov di, si ; Save prev. for debugging.
+ mov si, ax
+ loop cfl_loop
+ mov ax, word ptr [si] ; Get sentinal.
+
+cfl_done:
+ cmp ax, 0FFFFH ; -1 is sentinal
+ je short cfl_ok ; Must have sentinal and
+cfl_trashed:
+ kerror 0, <Free sel list is trashed>
+
+cfl_ok:
+ pop ds
+ popa
+ popf
+cEnd
+endif
+
+cProc get_sel,<PUBLIC,NEAR>
+ localW MySel
+cBegin
+ pusha
+gs_retry_get_sel:
+ call SetKernelDSProc ; Must call direct in this file
+ ReSetKernelDS
+
+ mov si, FirstFreeSel ; Pointer to head of list
+ mov ds, gdtdsc
+ UnSetKernelDS
+ mov dx, cx ; Sels wanted
+
+ mov ax, word ptr [si]
+ inc ax ; -1 teminated
+ jz short gs_searchfailed
+
+if KDEBUG
+ call check_free_sel_list
+endif
+
+ cmp cx, 1 ; One selector only?
+ jne short gs_selblock
+
+ dec ax
+ mov di, ax
+ mov word ptr [di].dsc_access, DSC_USED ; Mark it used
+ mov di, word ptr [di] ; Unlink it
+ mov word ptr [si], di
+ mov si, ax
+ jmp got_my_sel
+
+gs_selblock: ; Following stolen from DOSX
+ mov bx, si ; Start of list of free sels
+ lea si, [si+DSC_LEN] ; Start search here!
+ mov di, ds
+ lsl di, di ; limit of LDT
+ and di, NOT 7
+gs_jail:
+ mov ax, si ; Starting selector
+ mov cx, dx ; number to check
+gs_sb0:
+ cmp word ptr ds:[si].dsc_access, MY_SEL ; This one free?
+ jnz short gs_sb1 ; nope, keep looking
+
+ lea si, [si+DSC_LEN]
+ cmp si, di ; Falling off the end?
+ jae short gs_searchfailed
+ loop gs_sb0 ; All we wanted?
+ jmps gs_gotblock
+
+gs_sb1:
+ lea si, [si+DSC_LEN] ; Restart scan after this selector
+ cmp si, di
+ jb short gs_jail
+ jmps gs_searchfailed
+ ; Got our block, now blast them out
+gs_gotblock: ; of the free list
+ mov cx, dx ; # selectors
+ push cx
+ shl dx, 3 ; Length of our array of selectors
+ add dx, ax ; First selector after our array
+ mov si, [bx] ; Next selector in free list
+gs_blast:
+ inc si
+ jz short gs_blasted ; Gone thru whole list
+ dec si
+ cmp si, ax ; See if in range
+ jb short gs_noblast
+ cmp si, dx
+ jb short gs_unlink
+gs_noblast:
+ mov bx, si
+ mov si, [si] ; Follow the link
+ jmps gs_blast
+
+gs_unlink: ; This one is in range
+ mov si, [si] ; Unlink it
+ mov [bx], si
+ loop gs_blast ; Stop search when unlinked them all
+
+gs_blasted:
+ pop cx
+ mov si, ax
+ lea si, [si].dsc_access ; Now mark them used
+gs_markused:
+ mov byte ptr [si], DSC_USED
+ lea si, [si+DSC_LEN]
+ cmp si, dx
+ jb short gs_markused
+
+ mov si, ax
+ jmps got_my_sel
+
+gs_searchfailed: ; Failed from our list, try WIN386
+ mov cx, dx
+
+;;;%out Take me out later
+;;; mov ds, gdtdsc
+;;; UnSetKernelDS
+
+gs_slow:
+ifdef WOW
+;; Calling DPMI to do anything is very slow, so lets grab at minimum 256
+;; selectors at a time, that way we don't have to call again for a while
+
+ call SetKernelDSProc ; Must call direct in this file
+ ReSetKernelDS
+
+ push cx
+ cmp fbooting,1 ; Don't do optimization during boot
+ ; since free_Sel will return them to
+ ; DPMI.
+ jz gs_0100
+
+ add cx,256 ; get more than we need
+
+ DPMICALL 0000h
+ jc gs_0100 ; Failed, then just grab the required
+ mov bx, ax ; number.
+gs_free_loop:
+ cCall free_sel,<bx> ; Got the selectors, put them on
+ lea bx, [bx+DSC_LEN] ; our free list the easy way...
+ loop gs_free_loop
+ pop cx
+ jmp gs_retry_get_sel
+
+gs_0100:
+ pop cx
+endif; WOW
+ DPMICALL 0000h ; Call DPMI to get one
+ and al, NOT SEG_RING_MASK
+ mov si, ax
+
+ or si, si ; Did we get it?
+ jnz short got_dpmi_sel
+if KDEBUG
+ push es
+ pusha
+ kerror 0,<Out of selectors>
+ popa
+ pop es
+ jmp gs_exit
+else
+ jmps gs_exit
+endif
+
+; Try to avoid running out of selectors under Enhanced mode by keeping
+; 256 selectors free. This will hopefully allow win386 to grow the
+; LDT while there is still memory to do so.
+
+got_my_sel:
+ SetKernelDS
+ sub CountFreeSel, cx
+ifndef WOW
+;; See above WOW code which grabs chunks of 256 selectors from DOSX
+;; we don't need to do this.
+ test byte ptr WinFlags, WF_ENHANCED ; Standard mode can't grow the
+ jz got_either_sel ; LDT so don't bother
+ cmp CountFreeSel, 256
+ jae got_either_sel
+ lsl bx, gdtdsc ; LDT already full size?
+ cmp bx, 0F000h
+ ja got_either_sel
+ push ax
+ push cx
+ mov cx, 256
+ DPMICALL 0000h
+ jc gs_after_free
+ mov bx, ax
+gs_free_it:
+ cCall free_sel,<bx> ; Got the selectors, put them on
+ lea bx, [bx+DSC_LEN] ; our free list the easy way...
+ loop gs_free_it
+gs_after_free:
+ pop cx
+ pop ax
+endif; NOT WOW
+ jmps got_either_sel
+
+got_dpmi_sel:
+ SetKernelDS
+
+got_either_sel:
+ cmp SelTableLen, 0
+ je short gs_exit ; Not set yet
+ push eax
+ .ERRNZ DSC_LEN-8
+ lea eax, [esi+ecx*DSC_LEN][-DSC_LEN] ; AX has last selector
+ shr ax, 1 ; ignore high word...
+ cmp ax, SelTableLen
+ pop eax
+ jb short gs_exit ; Can associate this selector
+
+if KDEBUG
+ int 3
+endif
+ mov bx, si
+ xor si, si
+ or bl, SEG_RING
+as_free:
+ DPMICALL 0001h ; Free selector
+ ; Give to WIN386 since we can't use it
+ lea bx, [bx+DSC_LEN]
+ loop as_free
+
+gs_exit:
+ mov ds, gdtdsc
+ UnSetKernelDS
+
+ mov MySel, si
+ popa
+ mov si, MySel
+ or si, si ; Set ZF for caller
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; alloc_disc_data_sel
+; alloc_data_sel
+; alloc_data_sel32
+; alloc_disc_CS_sel
+; alloc_CS_sel
+; alloc_NP_data_sel
+; alloc_NP_CS_sel
+;
+; Set appropriate access rights flags then use
+; alloc_sel to get a selector.
+;
+; Entry:
+; Base address and Limit OR Owner
+;
+; Returns:
+; Selector in AX
+;
+; Registers Destroyed:
+; AX
+;
+; History:
+; Fri 15-Jul-1988 21:05:19 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+if ROM
+;
+; there is a bunch of selector allocating in the ROM initialization
+; so have a couple functions for 16 bit limits...
+;
+
+cProc far_alloc_data_sel16, <PUBLIC,FAR>
+
+ parmD base
+ parmW limit
+
+cBegin
+
+ movzx eax, limit
+ shl eax, 4
+ mov edx, base
+ cCall alloc_data_sel, <edx, eax>
+
+cEnd
+
+cProc alloc_data_sel16, <PUBLIC, NEAR>
+
+ parmD base
+ parmW limit
+
+cBegin
+ movzx eax, limit
+ shl eax, 4 ;; this is is paragraphs...
+ mov edx, base
+ cCall alloc_data_sel, <edx, eax>
+cEnd
+
+endif
+
+
+public alloc_data_sel32
+alloc_data_sel32 label near
+cProc alloc_data_sel,<PUBLIC,NEAR>
+; parmD Address
+; parmD Limit
+cBegin nogen
+ mov ax,DSC_PRESENT+DSC_DATA
+ jmps alloc_sel
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; alloc_sel ;
+; ;
+; Entry: ;
+; AL = flags ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu 07-Apr-1988 21:33:27 -by- David N. Weise [davidw] ;
+; Added the GlobalNotify check. ;
+; ;
+; Sun Feb 01, 1987 07:48:39p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc alloc_sel,<PUBLIC,NEAR>,<bx,dx,si,di,ds,es>
+ parmD Address
+ parmD Limit
+ localV DscBuf,DSC_LEN
+cBegin
+ push ecx
+ mov cx, 1
+ test al, DSC_PRESENT
+ jz short as_oneonly
+
+ mov ecx, Limit ; Calculate how many selectors required
+ cmp ecx, 100000h ; More than 1Mb?
+ jb short as_byte
+
+ add ecx, 0FFFh ; Round to 4K pages
+ and cx, not 0FFFh
+ mov Limit, ecx
+ shr Limit, 12 ; # 4K pages
+ or ah, DSC_GRANULARITY ; 4K granularity!
+as_byte:
+ dec Limit ; Came in as length, now limit
+ add ecx, 0FFFFh
+ shr ecx, 16 ; # selectors in array
+
+as_oneonly:
+ call get_sel
+ jz short a_s_exit ; No selectors left
+
+
+ mov bx, si ; Selector in bx for DPMI
+ or bl, SEL_LDT
+ lea di, DscBuf
+ smov es, ss ; es:di points to descriptor buffer
+ test al, DSC_PRESENT
+ jnz short set_everything
+
+ push ax
+
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ assumes ds,nothing
+else
+ mov ds, gdtdsc
+endif
+ and bl, not 7
+ pop word ptr [bx].dsc_access
+ mov ax, word ptr Limit
+ mov [bx].dsc_limit, ax
+ mov [bx].dsc_hbase, cl ; Number of selectors here
+ifdef WOW
+ smov es, ds ; es:di -> descriptor
+ mov di, bx
+ or bl, SEG_RING ; bx selector #
+ DPMICALL 000Ch ; Set descriptor
+endif; WOW
+ jmps as_done
+
+set_everything:
+ and ah, not 0Fh ; Zero limit 19:16
+ or ah, byte ptr Limit+2 ; Fill in limit 19:16
+ mov word ptr DscBuf.dsc_access, ax
+ mov ax, Limit.lo
+ mov DscBuf.dsc_limit, ax
+ mov ax, Address.lo
+ mov DscBuf.dsc_lbase, ax
+ mov ax, Address.hi
+ mov DscBuf.dsc_mbase, al
+ mov DscBuf.dsc_hbase, ah
+
+ call fill_in_selector_array
+
+as_done:
+ or si, SEG_RING
+a_s_exit:
+ mov ax, si
+ pop ecx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; free_sel ;
+; FreeSelector ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IFreeSelector,<FAR,PUBLIC>
+ parmW selector
+cBegin
+ xor ax, ax
+ mov es, ax
+ cCall FreeSelArray,<selector>
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+ifdef WOW
+; save cx too.
+
+cProc free_sel,<PUBLIC,NEAR>,<ax,bx,si,ds,cx>
+else
+cProc free_sel,<PUBLIC,NEAR>,<ax,bx,si,ds>
+endif
+ parmW selector
+cBegin
+ pushf ; !!! for the nonce
+ mov bx,selector ; must be careful in gcompact
+ ; to ignore error return
+ call SetKernelDSProc ; Must call direct in this file
+ ReSetKernelDS
+
+if ROM
+ ; don't free ROM selectors...
+ cmp bx, sel1stAvail
+ jb sel_freed
+endif
+
+ cmp gdtdsc, 0
+ je short give_to_win386
+
+ sel_check bx
+ mov si, bx
+ shr si, 1
+ cmp si, SelTableLen
+if 0
+ mov si, SelTableLen
+ shl si, 1
+ cmp bx, si
+endif
+ jae short give_to_win386
+
+ mov si, FirstFreeSel
+ inc CountFreeSel
+ mov ds, gdtdsc
+ UnSetKernelDS
+ifdef WOW
+ mov cx, word ptr [bx+4]
+endif
+
+ ; Link into list
+ mov ax, [si] ; ax := head.next
+ mov [si], bx ; head.next := new
+ mov [bx], ax ; new.next := ax
+ mov word ptr [bx][2], 0
+ mov dword ptr [bx][4], MY_SEL SHL 8 ; Make it free
+
+ifdef WOW
+ cmp cx, MY_SEL
+ jz sel_freed
+ or bl, SEG_RING ; Ensure Table bit correct
+ mov cx, 1
+ DPMICALL WOW_DPMIFUNC_0C
+endif
+ jmps sel_freed
+
+
+give_to_win386:
+ or bl, SEG_RING ; Ensure Table bit correct
+ DPMICALL 0001H
+sel_freed:
+ popf
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FreeSelArray ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FreeSelArray,<PUBLIC,NEAR>,<ax,bx>
+
+ parmW selector
+cBegin
+ push ecx
+
+ mov cx, 1 ; In case lar, lsl fail, one sel to free
+ mov bx, selector
+ Handle_To_Sel bl
+
+ifdef WOW
+ if KDEBUG
+ push ds
+ SetKernelDS
+ cmp DemandLoadSel, 0 ; Skip the test if we're freeing DemandLoadSel
+ UnSetKernelDS
+ pop ds
+ je short fsa_no_test
+ push bx
+ push ds
+ mov ds, gdtdsc
+ and bl, not 7
+ mov ch, [bx].dsc_access
+ pop ds
+ pop bx
+
+ lar ax, bx
+ and ah, 0feh ;ignore access bit
+ and ch, 0feh ;ignore access bit
+ cmp ah, ch
+ je short LDTs_match
+
+ kerror 0, <System LDT does not match Shadow LDT>
+LDTs_match:
+ xor ch, ch
+fsa_no_test:
+ endif
+endif
+
+ lar ax, bx
+ jnz short just_free_it ; I'm completely confused...
+
+ test ah, DSC_CODEDATA ; Code or data?
+ jz short just_free_it ; No, assume only one selector
+
+ test ah, DSC_PRESENT ; Present?
+ jnz short use_limit ; yes, calculate # sels from limit
+
+ifdef WOW
+; MarkSelNotPresent Saves Number of selectors in the dsc_hbase entry to get
+; it back directly from our copy of the LDT.
+
+ push bx
+ push ds
+
+ mov ds, gdtdsc
+ and bl, not 7
+ xor cx,cx
+ mov cl,[bx].dsc_hbase ; Get Saved # selectors
+
+ pop ds
+ pop bx
+else
+ push dx ; DPMI call 6 returns CX:DX
+ DPMICALL 0006h ; Get physical address
+ shr cx, 8 ; number of selectors
+ pop dx
+endif; WOW
+ jmps just_free_it
+
+use_limit:
+ lsl ecx, ebx
+ jnz short just_free_it ; Not present
+ Limit_To_Selectors ecx
+
+just_free_it:
+if KDEBUG
+ cmp cl,ch
+ jnz short skip_zero_inc
+ kerror 0, <Looping on cx=0 in FreeSelArray>
+ inc cl
+skip_zero_inc:
+endif
+just_free_it2:
+ cCall free_sel,<bx> ; (preserves cx)
+ lea bx, [bx+DSC_LEN]
+ loop just_free_it2 ; Any left to free
+
+ pop ecx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GrowSelArray ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GrowSelArray,<PUBLIC,NEAR>,<bx,di>
+ localV DscBuf,DSC_LEN
+cBegin
+ push ecx
+ mov di, ds:[esi].pga_handle
+ mov bx, di
+ Handle_To_Sel di
+ lsl eax, edi
+ Limit_To_Selectors eax
+if KDEBUG
+ cmp al, ds:[esi].pga_selcount
+ je short gsa_count_ok
+ int 3
+ int 3
+gsa_count_ok:
+endif
+ mov ecx, edx ; New size
+ add ecx, 0FFFFh
+ shr ecx, 16 ; new # selectors
+ cmp ax, cx ; Same # of selectors required?
+ je short gsa_done ; yes, just return!
+
+ push si
+ push es
+ push ds
+ push di ; Argument to FreeSelArray
+
+ cmp cx, 255 ; Max array is 255.
+ jae short gsa_nosels
+
+ call get_sel ; get a new selector array
+ jz short gsa_nosels
+
+ push bx
+ mov bx, di ; DI had original selector
+
+ push ds
+if ROM
+ SetKernelDS
+ mov es,gdtdsc
+ mov ds,gdtdsc
+ assumes ds,nothing
+else
+ mov ds,gdtdsc
+ mov es,gdtdsc
+endif
+ push si
+ mov di,si
+ and di, not 7
+ mov si,bx
+ and si, not 7
+ MovsDsc
+ pop si
+ pop ds
+ifdef WOW
+ push cx
+ push bx
+ mov cx, 1
+ mov bx, si
+ or bx, SEG_RING_MASK
+ DPMICALL WOW_DPMIFUNC_0C
+ pop bx
+ pop cx
+endif
+
+ mov di, si ; New selector in DI
+ pop bx
+ pop si
+ pop ds
+ cCall AssociateSelector32,<si,0,0>
+ pop es
+ pop si
+ mov ax, bx
+ and ax, SEG_RING_MASK ; Ring bits
+ or ax, di ; New handle
+ mov ds:[esi].pga_handle, ax
+ mov ds:[esi].pga_selcount, cl
+ cCall AssociateSelector32,<ax,esi>
+ jmps gsa_done
+
+gsa_nosels:
+ pop di
+ pop ds
+ pop es
+ pop si
+ xor ax, ax ; Indicate failure
+ jmps gsa_ret
+
+gsa_done:
+ mov ax, ds:[esi].pga_handle
+ or ax, ax ; Success
+gsa_ret:
+ pop ecx
+cEnd
+
+
+;=======================================================================;
+; ;
+; SELECTOR ALIAS ROUTINES ;
+; ;
+;=======================================================================;
+
+
+;-----------------------------------------------------------------------;
+; PrestoChangoSel
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IPrestoChangoSelector,<PUBLIC,FAR>,<di,si>
+ parmW sourcesel
+ parmW destsel
+ localV DscBuf,DSC_LEN
+cBegin
+ifdef WOW
+ smov es, ss
+ lea di, DscBuf
+ mov bx, sourcesel
+ DPMICALL 000Bh ; LATER change this to a single
+ xor DscBuf.dsc_access, DSC_CODE_BIT ; DPMI call, read from gdtdsc
+ mov bx, destsel
+ DPMICALL 000Ch
+ mov ax, bx
+else
+ push bx
+
+ push ds
+if ROM
+ SetKernelDS
+ mov es, gdtdsc
+ mov ds, gdtdsc
+ assumes ds, nothing
+else
+ mov ds, gdtdsc
+ mov es, gdtdsc
+endif
+ mov si, sourcesel
+ and si, not 7
+ mov di, destsel
+ and di, not 7
+ MovsDsc
+ lea bx,[di-DSC_LEN]
+ xor ds:[bx].dsc_access,DSC_CODE_BIT ; Toggle CODE/DATA
+ pop ds
+ or bl, SEG_RING
+ mov ax, bx
+ pop bx
+endif; WOW
+ smov es,0
+cEnd
+
+
+
+;-----------------------------------------------------------------------;
+; AllocAlias ;
+; AllocCStoDSAlias ;
+; AllocDStoCSAlias ;
+; All these routines return an alias selector for the ;
+; given selector. ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; AX is alias selector ;
+; DX is original selector (compatibility thing) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; BX,CX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ES destroyed ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+labelFP <PUBLIC,IAllocDStoCSAlias>
+ ;** AllocDStoCSAlias has an interesting hack. A fix was made to
+ ;** not allow apps to GlobalAlloc fixed memory. This was done
+ ;** for performance reasons. The only reason we can ascertain
+ ;** for an app needing fixed GlobalAlloc'ed memory is in the case
+ ;** of alias selectors. We assume that all apps needing alias
+ ;** selectors will use this function to make the alias. So, if
+ ;** we see a DStoCS alias being made, we make sure the DS is fixed.
+ push bp
+ mov bp, sp ;Create the stack frame
+ push WORD PTR [bp + 6] ;Get handle/selector
+IF KDEBUG
+ call GlobalHandleNorip ;Make sure it's really a handle
+ELSE
+ call IGlobalHandle ;Make sure it's really a handle
+ENDIF
+ test ax, 1 ;Fixed blocks have low bit set
+ jnz SHORT ADCA_Already_Fixed ;It's already a fixed block!
+
+ ;** If the block is not fixed, it may be locked so we must check this.
+ push ax ;Save returned selector
+ push ax ;Use as parameter
+ call IGlobalFlags ;Returns lock count if any
+ or al, al ;Non-zero lock count?
+ pop ax ;Get selector back
+ jnz SHORT ADCA_Already_Fixed ;Yes, don't mess with it
+
+ ;** Fix the memory. Note that we're only doing this for bonehead
+ ;** apps that are calling this on non-fixed or -locked memory.
+ ;** This will cause them to rip on the GlobalFree call to this
+ ;** memory, but at least it won't move on them!
+ push ax ;Fix it
+ call IGlobalFix
+ADCA_Already_Fixed:
+ pop bp ;Clear our stack frame
+
+ ;** Flag which type of alias to make and jump to common routine
+ mov dl, 1
+ jmps aka
+
+labelFP <PUBLIC,IAllocCStoDSAlias>
+ xor dl, dl
+
+cProc aka,<FAR,PUBLIC>, <bx,cx,si,di,ds>
+ parmW sourceSel
+ localV DscBuf,DSC_LEN
+ localB flag ; 0 for data, !0 for code
+cBegin
+ mov flag, dl
+
+ mov cx, 1
+ call get_sel
+ mov ax, si ; in case it failed
+ jz short aka_nope
+ or si, SEG_RING
+
+ifdef WOW ; LATER Single DPMI call
+ push si ; save Target Selector
+ smov es,ss
+ lea di,DscBuf
+ mov bx,sourceSel
+ DPMICALL 000Bh ; Read the Selector into DscBuf
+ and es:[di].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA
+ cmp flag, 0
+ jz @F
+ or es:[di].dsc_access,DSC_CODE_BIT
+@@:
+ pop bx ; restore Target Selector
+ DPMICALL 0000Ch
+else
+if ROM
+ SetKernelDS
+ mov es, gdtdsc
+ mov ds, gdtdsc
+ assumes ds, nothing
+else
+ mov ds, gdtdsc
+ mov es, gdtdsc
+endif
+ mov bx, si
+ mov di, si
+ and di, not 7
+ mov si, sourceSel
+ and si, not 7
+ MovsDsc
+ and es:[di][-DSC_LEN].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA
+ cmp flag, 0
+ jz @F
+ or es:[di][-DSC_LEN].dsc_access,DSC_CODE_BIT
+@@:
+endif; WOW
+ mov ax, bx
+ smov es,0
+aka_nope:
+ mov dx,sourceSel
+cEnd
+
+
+cProc AllocAlias,<FAR,PUBLIC>, <bx,cx,si,di,ds>
+ parmW selector
+cBegin
+ifdef WOW
+ push bx ; Whitewater tool ObjDraw needs this too
+endif
+ mov cx, 1
+ call get_sel
+ jz short aca_nope
+ or si, SEG_RING
+ cCall IPrestoChangoSelector,<selector,si>
+aca_nope:
+ ; WhiteWater Resource Toolkit (shipped with Borland's Turbo
+ ; Pascal) depends on dx being the data selector which was true
+ ; in 3.0 but in 3.1 validation layer destroys it.
+ mov dx,selector
+ifdef WOW
+ pop bx
+endif
+cEnd
+
+;=======================================================================;
+; ;
+; SELECTOR MANPULATION ROUTINES ;
+; ;
+;=======================================================================;
+
+
+;-----------------------------------------------------------------------;
+; fill_in_selector_array ;
+; ;
+; Entry: ;
+; AX = Limit for object ;
+; DH = Discard bit for descriptors ;
+; DL = Access bits ;
+; BX:DI = 32 bit base address of object ;
+; SI = index into LDT ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; SI, DI, DS, ES ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc fill_in_selector_array,<PUBLIC,NEAR>
+cBegin nogen
+
+ push ds
+ mov ds, gdtdsc
+ push bx
+ push cx
+
+ mov dh, es:[di].dsc_hlimit ; For granularity
+next_sel:
+
+;; DPMICALL 000Ch ; Set this descriptor
+
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+ pop bx
+
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ add es:[di].dsc_mbase, 1 ; Add 64kb to address
+ adc es:[di].dsc_hbase, 0
+
+ test dh, DSC_GRANULARITY ; Page granular?
+ jz short byte_granular
+
+ sub es:[di].dsc_limit, 16 ; 64K is 16 4K pages
+ sbb es:[di].dsc_hlimit, 0 ; Carry into hlimit
+ loop next_sel
+
+ jmps fisa_ret
+
+byte_granular:
+ dec es:[di].dsc_hlimit ; subtract 64kb from limit
+ loop next_sel
+
+fisa_ret:
+ pop cx
+ pop bx
+ DPMICALL WOW_DPMIFUNC_0C
+ pop ds
+
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetSelectorBase
+; get_physical_address
+;
+;
+; Entry:
+;
+; Returns:
+; DX:AX 32 bit physical address
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetSelectorBase,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall get_physical_address, <selector>
+cEnd
+
+cProc get_physical_address,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ push bx
+ push cx
+ mov bx, selector
+
+ push ds ; Get Segment Base Address
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ assumes ds, nothing
+else
+ mov ds, gdtdsc
+endif
+ and bl, not 7
+ mov ax, ds:[bx].dsc_lbase
+ mov dl, ds:[bx].dsc_mbase
+ mov dh, ds:[bx].dsc_hbase
+ pop ds
+ pop cx
+ pop bx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_selector_length16
+;
+;
+; Entry:
+;
+; Returns:
+; AX 16 bit segment length
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_selector_length16,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ mov ax, -1
+ lsl ax, selector
+ inc ax ; length is one bigger!
+cEnd
+
+;-----------------------------------------------------------------------;
+; set_physical_address
+;
+;
+; Entry:
+; DX:AX 32 bit physical address
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc far_set_physical_address,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall set_physical_address,<selector>
+cEnd
+
+cProc set_physical_address,<PUBLIC,NEAR>,<bx,di>
+ parmW selector
+cBegin
+ push ecx
+ mov bx, selector
+ CheckLDT bl
+ lsl ecx, ebx
+if KDEBUG
+ jz short spa_ok
+ int 3
+spa_ok:
+endif
+ Limit_To_Selectors ecx
+
+ mov di, cx
+ mov cx, dx ; CX:DX has new address
+ mov dx, ax
+
+ push ds
+ push bx
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ assumes ds, nothing
+else
+ifdef WOW
+set_bases:
+ DPMICALL 0007h ; Set selector base
+else
+ mov ds, gdtdsc
+set_bases:
+ and bl, not 7
+ mov ds:[bx].dsc_lbase, dx
+ mov ds:[bx].dsc_mbase, cl
+ mov ds:[bx].dsc_hbase, ch
+endif; WOW
+ lea bx, [bx+DSC_LEN] ; On to next selector
+ inc cx ; Add 64k to base
+ dec di
+ jnz set_bases
+
+ pop bx
+ pop ds
+endif; ROM
+ mov ax, dx ; Restore AX and DX
+ mov dx, cx
+ pop ecx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_selector_address32
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_selector_address32,<PUBLIC,NEAR>,<ax,dx>
+ parmW selector
+ parmD addr
+cBegin
+ mov dx, addr.sel
+ mov ax, addr.off
+ cCall set_physical_address,<selector>
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_sel_limit
+;
+;
+; Entry:
+; CX:BX = length of segment
+; Returns:
+;
+; Registers Destroyed:
+; CX
+;
+; History:
+; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_sel_limit,<PUBLIC,NEAR>,<ax,dx,si,di,es,ds>
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+ push ebx
+ push ecx
+
+ push bx ; Get existing descriptor
+ smov es, ss
+ lea di, DscBuf
+ mov bx, selector
+
+ push ds ; Get Descriptor
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ assumes ds,nothing
+else
+ mov ds, gdtdsc
+endif
+ push si
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+ pop bx
+ mov dx, word ptr [DscBuf.dsc_access]
+ and dh, 0F0h ; Zap hlimit bits
+ test dl, DSC_PRESENT
+ jz short ssl_set_limit1 ; Not present, just one to set
+
+ and dh, NOT DSC_GRANULARITY ; Byte granularity
+ shl ecx, 16
+ mov cx, bx ; DWORD length
+ mov ebx, ecx
+ cmp ecx, 100000h ; More than 1Mb?
+ jb short ssl_byte
+
+ add ecx, 0FFFh ; Round to 4k pages
+ and cx, not 0FFFh
+ mov ebx, ecx
+ shr ebx, 12 ; # 4k pages
+ or dh, DSC_GRANULARITY ; Set 4k granularity
+ssl_byte:
+ add ecx, 0FFFFh
+ shr ecx, 16 ; # selectors in array
+ cmp cx, 1
+ je short ssl_set_limit1
+
+ dec ebx ; length to limit
+ mov ax, bx ; low 16 bits of limit
+ shr ebx, 16
+ or dh, bl ; Bits 19:16 of limit
+
+ mov word ptr DscBuf.dsc_access, dx
+ mov DscBuf.dsc_limit, ax
+ mov bx, Selector
+
+ call fill_in_selector_array
+ jmps ssl_done
+
+ssl_set_limit1: ; Fast out for one only
+ dec bx ; Came in as length
+ mov DscBuf.dsc_limit, bx ; and limit
+ mov word ptr DscBuf.dsc_access, dx ; Access, Discard and hlimit
+ mov bx, Selector
+ DPMICALL 000Ch
+
+ssl_done:
+ smov ss,ss ; It may be SS we're changing
+ pop ecx
+ pop ebx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_selector_limit32
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_selector_limit32,<PUBLIC,NEAR>,<cx,bx>
+ parmW selector
+ parmD sel_len
+cBegin
+ mov cx, sel_len.hi
+ mov bx, sel_len.lo
+ cCall set_sel_limit,<selector>
+cEnd
+
+;-----------------------------------------------------------------------;
+; mark_sel_NP
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+; BX
+;
+; History:
+; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc mark_sel_NP,<PUBLIC,NEAR>,<ds>
+ parmW selector
+ parmW owner
+ localV DscBuf,DSC_LEN
+cBegin
+ push ecx
+ mov bx, selector
+ Handle_To_Sel bl
+ lsl ecx, ebx ; How many selectors do we have now?
+ Limit_To_Selectors ecx
+
+ push ax
+ push es
+ push di
+
+ push ds
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ assumes ds, nothing
+else
+ mov ds, gdtdsc
+endif
+ push bx
+ and bl, not 7
+ mov [bx].dsc_hbase, cl ; Save # selectors
+ mov [bx].dsc_hlimit, DSC_DISCARDABLE
+ and [bx].dsc_access, NOT DSC_PRESENT
+ mov cx, owner
+ mov [bx].dsc_owner, cx ; Set owner in descriptor
+
+ifdef WOW
+;
+; Now the copy of the LDT has the correct info set VIA DPMI the real NT
+; LDT Entry
+
+ smov es,ds
+ mov di,bx ; es:di->selector
+ or bx, SEG_RING ; BX = selector
+ DPMICALL 000Ch
+
+endif; WOW
+ pop bx
+ pop ds
+
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector32,<bx,0,cx> ; Save owner in selector table
+ pop di
+ pop es
+ pop ax
+ pop ecx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; mark_sel_PRESENT
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc mark_sel_PRESENT,<PUBLIC,NEAR>,<dx,di,es>
+ parmD arena_ptr
+ parmW selector
+ localV DscBuf,DSC_LEN
+cBegin
+ push eax
+ push ebx
+ push ecx
+
+ smov es, ss
+ lea di, DscBuf
+ mov bx, selector
+ DPMICALL 000Bh ; Get existing descriptor
+ mov ax, word ptr DscBuf.dsc_access ; Access and hlimit
+ or al, DSC_PRESENT ; Mark it present
+ and ah, NOT DSC_GRANULARITY ; Assume byte granular
+
+ mov esi, arena_ptr
+ CheckDS
+ mov ecx, ds:[esi].pga_size
+ mov ebx, ecx
+ cmp ecx, 100000h ; New size more than 1Mb?
+ jb short msp_byte
+
+ add ebx, 0FFFh ; Round to 4k pages
+ and bx, not 0FFFh
+ shr ebx, 12 ; # 4k pages
+ or ah, DSC_GRANULARITY ; Set 4k granularity
+msp_byte:
+ dec ebx
+ mov DscBuf.dsc_limit, bx ; Fill in new limit fields
+ shr ebx, 16
+ and bl, 0Fh
+ and ah, NOT 0Fh
+ or ah, bl
+ mov word ptr DscBuf.dsc_access, ax ; Fill in new hlimit and access
+
+ dec ecx
+ Limit_To_Selectors ecx ; New number of selectors
+ mov ds:[esi].pga_selcount, cl
+ mov bl, DscBuf.dsc_hbase ; Old number of selectors
+ sub bl, cl
+ je short go_ahead ; Same number, just fill in array
+ jb short get_big
+
+; here to get small
+
+ xor bh, bh
+ xchg bx, cx
+ shl bx, 3 ; Offset of first selector
+ .errnz DSC_LEN - 8
+ add bx, selector ; First selector to free
+@@: cCall free_sel,<bx>
+ lea bx, [bx+DSC_LEN]
+ loop @B
+ jmps go_ahead ; And fill in remaining selectors
+
+get_big:
+ mov ax, word ptr DscBuf.dsc_access ; Access bits in ax
+ mov ebx, ds:[esi].pga_address ; Get base address
+ mov ecx, ds:[esi].pga_size
+ cCall alloc_sel,<ebx,ecx> ; Access bits in ax
+ mov si, ax
+ or ax, ax ; did we get a set?
+ jz short return_new_handle
+ or si, SEG_RING ; Set ring bits like old selector
+ test selector, IS_SELECTOR
+ jnz short @F
+ StoH si
+ HtoS selector
+@@:
+ cCall AssociateSelector32,<selector,0,0>
+ cCall FreeSelArray,<selector> ; Zap old handle
+ jmps return_new_handle
+
+go_ahead:
+ mov ebx, ds:[esi].pga_address ; Fill in selector array with
+ mov DscBuf.dsc_lbase, bx ; new base and limit
+ shr ebx, 16
+ mov DscBuf.dsc_mbase, bl
+ mov DscBuf.dsc_hbase, bh
+ mov bx, selector
+ movzx cx, ds:[esi].pga_selcount
+
+ call fill_in_selector_array
+ mov si, selector ; return old selector in SI
+return_new_handle:
+
+ pop ecx
+ pop ebx
+ pop eax
+cEnd
+
+;-----------------------------------------------------------------------;
+; cmp_sel_address
+;
+; Compares the physical addresses corresponding to two selectors
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc cmp_sel_address,<PUBLIC,NEAR>
+ parmW sel1
+ parmW sel2
+cBegin
+ push ax
+ push ebx
+ push edx
+ cCall get_physical_address,<sel1>
+ mov bx, dx
+ shl ebx, 16
+ mov bx, ax ; First address in EBX
+ cCall get_physical_address,<sel2>
+ shl edx, 16
+ mov dx, ax ; Second address in EDX
+ cmp ebx, edx
+ pop edx
+ pop ebx
+ pop ax
+;;; mov ds,gdtdsc
+;;; mov si,sel1
+;;; mov di,sel2
+;;; sel_check si
+;;; sel_check di
+;;; mov al,[si].dsc_hbase
+;;; cmp al,[di].dsc_hbase
+;;; jne short csa_done
+;;; mov al,[si].dsc_mbase
+;;; cmp al,[di].dsc_mbase
+;;; jne short csa_done
+;;; mov ax,[si].dsc_lbase
+;;; cmp ax,[di].dsc_lbase
+;;;csa_done:
+cEnd
+
+;-----------------------------------------------------------------------;
+; pdref ;
+; ;
+; Dereferences the given global handle, i.e. gives back abs. address. ;
+; ;
+; Arguments: ;
+; DX = selector ;
+; DS:DI = BURGERMASTER ;
+; ;
+; Returns: ;
+; ESI = address of arena header ;
+; AX = address of client data ;
+; CH = lock count or 0 for fixed objects ;
+; CL = flags ;
+; DX = handle, 0 for fixed objects ;
+; ;
+; Error Returns: ;
+; ZF = 1 if invalid or discarded ;
+; AX = 0 ;
+; BX = owner of discarded object ;
+; SI = handle of discarded object ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc pdref,<PUBLIC,NEAR>
+
+cBegin nogen
+ mov si, dx
+ sel_check si
+ or si, si ; Null handle?
+ mov ax, si
+ jz short pd_exit ; yes, return 0
+
+ lar eax, edx
+ jnz short pd_totally_bogus
+ shr eax, 8
+
+; We should beef up the check for a valid discarded sel.
+
+ xor cx,cx
+ test ah, DSC_DISCARDABLE
+ jz short pd_not_discardable
+ or cl, GA_DISCARDABLE
+ ; Discardable, is it code?
+ test al, DSC_CODE_BIT
+ jz short pd_not_code
+ or cl,GA_DISCCODE
+pd_not_code:
+
+pd_not_discardable:
+ test al, DSC_PRESENT
+ jnz short pd_not_discarded
+
+; object discarded
+
+ or cl,HE_DISCARDED
+ifdef WOW
+; On WOW we don't copy the owner to the real LDT since it is slow to call
+; the NT Kernel, so we read our copy of it directly.
+; see set_discarded_sel_owner mattfe mar 23 93
+
+ move ax,es ; save es
+ mov bx,dx
+ mov es,cs:gdtdsc
+ and bl, not 7
+ mov bx,es:[bx].dsc_owner
+ mov es,ax ; restore
+else
+ lsl bx, dx ; get the owner
+endif
+ or si, SEG_RING-1 ; Handles are RING 2
+ xor ax,ax
+ jmps pd_exit
+
+pd_not_discarded:
+ cCall get_arena_pointer32,<dx>
+ mov esi, eax
+ mov ax, dx
+ or esi, esi ; Unknown selector
+ jz short pd_maybe_alias
+ mov dx, ds:[esi].pga_handle
+ cmp dx, ax ; Quick check - handle in header
+ je short pd_match ; matches what we were given?
+
+ test al, IS_SELECTOR ; NOW, we MUST have been given
+ jz short pd_totally_bogus ; a selector address.
+ push ax
+ StoH al ; Turn into handle
+ cmp dx, ax
+ pop ax
+ jne short pd_nomatch
+pd_match:
+ or cl, ds:[esi].pga_flags
+ and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!!
+ mov ax, dx ; Get address in AX
+ test dl, GA_FIXED ; DX contains handle
+ jnz short pd_fixed ; Does handle need derefencing?
+ mov ch, ds:[esi].pga_count
+ HtoS al ; Dereference moveable handle
+ jmps pd_exit
+pd_totally_bogus:
+ xor ax,ax
+pd_maybe_alias:
+ife ROM
+if KDEBUG
+ or dx,dx
+ jnz short dref_invalid
+endif
+endif
+pd_nomatch: ; Handle did not match...
+ xor dx, dx
+;;; mov dx, ax ; Must be an alias...
+pd_fixed:
+;;; xor si, si
+;;; xor dx, dx
+pd_exit:
+ or ax,ax
+ ret
+if KDEBUG
+dref_invalid:
+ push ax
+ kerror ERR_GMEMHANDLE,<gdref: invalid handle>,0,dx
+ pop ax
+ jmps pd_nomatch
+endif
+cEnd nogen
+
+cProc Far_pdref,<PUBLIC,FAR>
+cBegin nogen
+ call pdref
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; get_rover_2 ;
+; ;
+; Entry: ;
+; ES Selector to get rover for ;
+; Returns: ;
+; ES (kr2dsc) is rover DATA and PRESENT ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_rover_2,<PUBLIC,NEAR>,<di>
+ localV DscBuf,DSC_LEN
+cBegin
+ push ax
+ push bx
+ mov bx, es ; Selector to get rover for
+ push ds
+ SetKernelDS ds
+ifdef WOW
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh ; Get source descriptor
+ mov byte ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA
+ mov bx, kr2dsc ; kr2dsc is target
+ or bl, SEG_RING
+ DPMICALL 000Ch
+else
+ push ds
+ SetKernelDS ds
+ mov di, kr2dsc
+ mov es, gdtdsc
+ mov ds, gdtdsc
+ UnSetKernelDS ds
+ push si
+ mov si, bx
+ and si, not 7
+ and di, not 7
+ MovsDsc
+ lea bx, [di-DSC_LEN]
+ mov es:[bx].dsc_access, DSC_PRESENT+DSC_DATA
+ or bl, SEG_RING
+ pop si
+endif; WOW
+ pop ds
+ mov es, bx ; Return with ES containing rover
+ pop bx
+ pop ax
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_rover_232 ;
+; ;
+; Entry: ;
+; ds:esi ;
+; Returns: ;
+; ES:0 ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+ifndef WOW_x86
+ assumes ds,nothing
+ assumes es,nothing
+cProc get_rover_232,<PUBLIC,NEAR>,<di>
+ localV DscBuf,DSC_LEN
+cBegin
+ push eax
+ push bx
+ SetKernelDS es
+ mov bx, kr2dsc
+ or bl, SEG_RING
+ smov es, ss
+ UnSetKernelDS es
+ lea di, DscBuf ; ES:DI -> descriptor
+ mov eax, ds:[esi].pga_address
+ mov [DscBuf].dsc_lbase, ax ; Fill in base address
+ shr eax, 16
+ mov [DscBuf].dsc_mbase, al
+ mov [DscBuf].dsc_hbase, ah
+ mov [DscBuf].dsc_limit, 1000h ; Real big limit
+ mov [DscBuf].dsc_hlimit, DSC_GRANULARITY
+ mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA
+ DPMICALL 000Ch ; Set descriptor
+ mov es, bx
+ pop bx
+ pop eax
+cEnd
+endif; WOW
+
+cProc far_get_temp_sel,<FAR,PUBLIC>
+cBegin
+ cCall get_temp_sel
+cEnd
+
+cProc get_temp_sel,<PUBLIC,NEAR>,<ax,cx,di,si>
+ localV DscBuf,DSC_LEN
+cBegin
+ mov cx, 1
+ DPMICALL 0000h ; Get us a selector
+ push bx
+ mov si, ax ; New selector
+ mov bx, es ; Old selector
+
+ifdef WOW ; LATER Make single dpmicall
+ smov es, ss
+ lea di, DscBuf
+
+ DPMICALL 000Bh ; Get existing descriptor
+
+ mov DscBuf.dsc_access,DSC_PRESENT+DSC_DATA
+ mov DscBuf.dsc_limit,0ffffh
+ or DscBuf.dsc_hlimit, 0Fh ; Max length
+
+ mov bx, si
+ or bl, SEG_RING
+
+ DPMICALL 000Ch ; Set new descriptor
+else
+ push ds
+if ROM
+ SetKernelDS
+ mov es, gdtdsc
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+ mov es, gdtdsc
+endif
+ mov di, si
+ and di, not 7
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea bx, [di-DSC_LEN]
+ mov [bx].dsc_access,DSC_PRESENT+DSC_DATA
+ mov [bx].dsc_limit,0ffffh
+ or [bx].dsc_hlimit, 0Fh ; Max length
+ or bl, SEG_RING
+ pop ds
+endif; WOW
+ mov es, bx
+ pop bx
+cEnd
+
+cProc far_free_temp_sel,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ cCall free_sel,<selector>
+cEnd
+
+;-----------------------------------------------------------------------;
+; get_blotto
+;
+;
+; Entry:
+; EAX = arena header
+;
+; Returns:
+; BX = Selector points to pga_address (size pga_arena)
+; Registers Destroyed:
+;
+; History:
+; Sun 31-Jul-1988 16:20:53 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifndef WOW_x86
+;; On WOW_x86 we try to avoid setting selectors since it is slow, we use selector
+;; 23h to write to anywhere in VDM memory.
+
+
+cProc get_blotto,<PUBLIC,NEAR>,<di>
+ localV DscBuf,DSC_LEN
+cBegin
+ push es
+ push bx
+ lea di, DscBuf
+ SetKernelDS es
+ mov bx, blotdsc
+ smov es, ss
+ UnSetKernelDS es
+ or bl, SEG_RING
+ push eax
+ mov eax, ds:[eax].pga_address
+ mov [DscBuf].dsc_lbase,ax
+ shr eax, 16
+ mov [DscBuf].dsc_mbase,al
+ mov [DscBuf].dsc_hbase,ah
+
+ ; Convert pga_size to limit in page granularity
+
+ pop eax
+ mov eax, ds:[eax].pga_size ; Get Size in Bytes
+ add eax, 4096-1 ; Round up to 4k multiple
+ shr eax, 3*4
+ mov [DscBuf].dsc_limit,ax
+ shr eax,16
+ or al, DSC_GRANULARITY
+
+ mov [DscBuf].dsc_hlimit, al
+ mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA
+ DPMICALL 000Ch ; Set up the descriptor
+ mov ax, bx
+ pop bx
+ pop es
+cEnd
+endif;
+
+
+;-----------------------------------------------------------------------;
+; LongPtrAdd
+;
+; Performs segment arithmetic on a long pointer and a DWORD offset
+; The resulting pointer is normalized to a paragraph boundary.
+; The offset cannot be greater than 16 megabytes (current Enh Mode
+; limit on size of an object).
+;
+; Entry:
+;
+; Returns:
+; DX:AX new segment:offset
+;
+; Error returns:
+; DX:AX = 0
+;
+; Registers Destroyed:
+; BX,CX
+;
+; History:
+; Mon 19-Dec-1988 18:37:23 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifdef WOW
+
+LPTRADDWOW_SETBASE equ 01h
+
+;cProc LongPtrAddWOW,<PUBLIC,FAR>,<si,di>
+; parmD long_ptr
+; parmD delta
+; parmW RefSelector
+; parmW flBaseSetting
+;
+; effectively pops RefSelector and flBaseSetting into dx and ax.
+; and jumps to longptrAddWorker.
+;
+; RefSelector is used only if the descriptor needs to be set.
+;
+
+labelFP <PUBLIC,LongPtrAddWOW>
+ pop ax
+ pop dx ; far return address
+ mov bx,sp
+ xchg ax, ss:[bx] ; replace the 'dword' with the return address
+ xchg dx, ss:[bx+2]
+ jmps LongPtrAddWorker ; ax = flags; dx = reference selector
+
+labelFP <PUBLIC,LongPtrAdd>
+ mov ax, LPTRADDWOW_SETBASE
+ xor dx, dx
+ ; fall through
+
+cProc LongPtrAddWorker,<PUBLIC,FAR>,<si,di>
+ parmD long_ptr
+ parmD delta
+ localV DscBuf,DSC_LEN
+ localW flBaseSetting
+ localW RefSelector
+cBegin
+ mov flBaseSetting, ax ; save in localvariables
+ mov RefSelector, dx
+ or dx, dx ; if RefSelector is nonzero
+ jz @F ; use it for querying descriptor info.
+ xchg dx, word ptr long_ptr[2] ; and store the selector to be set in
+ mov RefSelector, dx ; the localvariable
+@@:
+else
+
+cProc LongPtrAdd,<PUBLIC,FAR>,<si,di>
+ parmD long_ptr
+ parmD delta
+ localV DscBuf,DSC_LEN
+cBegin
+
+endif
+ mov bx,word ptr long_ptr[2]
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh ; Pick up old descriptor
+ mov ax,word ptr long_ptr[0] ; get the pointer into SI:AX
+ and ax,0FFF0h
+
+ mov si, DscBuf.dsc_lbase ; DX:SI gets old base
+ mov dl, DscBuf.dsc_mbase
+ mov dh, DscBuf.dsc_hbase
+
+ add si, ax ; Add in old pointer offset
+ adc dx, 0
+
+ mov cx, word ptr delta[2] ; add the segment and MSW
+ test cx, 0FF00h ; bigger than 16Meg?
+ifdef WOW
+ jz @F
+ test flBaseSetting, LPTRADDWOW_SETBASE
+ jnz lptr_mustset
+ jmp short lpa_too_big
+@@:
+else
+ jnz short lpa_too_big
+endif
+
+ add si, word ptr delta[0] ; add the offset and LSW
+ adc dx, cx
+
+ifdef WOW
+lptr_mustset:
+endif
+
+ mov cx, 1 ; Calculate # selectors now in array
+ lsl ecx, dword ptr long_ptr[2]
+ jnz short trash
+ Limit_to_Selectors ecx
+trash:
+ifdef WOW
+ test flBaseSetting, LPTRADDWOW_SETBASE
+ jz lptr_dontset
+ cmp RefSelector, 0
+ jz @F
+ mov bx, RefSelector ; get the actual selector to be set
+ mov word ptr long_ptr[2], bx
+@@:
+endif
+ mov DscBuf.dsc_lbase, si ; Put new base back in descriptor
+ mov DscBuf.dsc_mbase, dl
+ mov DscBuf.dsc_hbase, dh
+
+ call fill_in_selector_array
+ifdef WOW
+lptr_dontset:
+ test word ptr delta[2], 0ff00h
+ jz @F
+ mov cx, word ptr delta[2]
+ jmps lpa_too_big
+@@:
+endif
+ mov dx,word ptr long_ptr[2]
+ mov ax,word ptr long_ptr[0]
+ and ax, 0Fh
+ jnc short lpa_exit
+
+lpa_too_big:
+ xor ax,ax
+ xor dx,dx
+lpa_exit:
+ smov es,0
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSelectorBase
+;
+; Sets the base and limit of the given selector.
+;
+; Entry:
+; parmW selector
+; parmD selbase
+;
+; Returns:
+; AX = selector
+;
+; Error Returns:
+; AX = 0
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetSelectorBase,<PUBLIC,FAR>
+ parmW selector
+ parmD selbase
+cBegin
+ push bx
+ push cx
+ push dx
+ mov cx, selbase.hi
+ mov dx, selbase.lo
+ mov bx, selector
+ifdef WOW
+ DPMICALL 0007h ; Set Segment Base Address
+else
+ push ds
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ push bx
+ and bl, not 7
+ mov ds:[bx].dsc_lbase, dx
+ mov ds:[bx].dsc_mbase, cl
+ mov ds:[bx].dsc_hbase, ch
+ pop bx
+ pop ds
+endif; WOW
+ pop dx
+ pop cx
+ pop bx
+ mov ax,selector
+cEnd
+
+;-----------------------------------------------------------------------;
+; GetSelectorLimit
+;
+; Sets the limit of the given selector.
+;
+; Entry:
+; parmW selector
+;
+; Returns:
+; DX:AX = limit of selector
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetSelectorLimit,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ xor eax, eax ; In case lsl fails
+ lsl eax, dword ptr selector
+ mov edx, eax
+ shr edx, 16
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetSelectorLimit
+;
+; Sets the limit of the given selector.
+;
+; Entry:
+; parmW selector
+; parmD sellimit
+;
+; Returns:
+; AX = 0 success
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetSelectorLimit,<PUBLIC,FAR>
+ parmW selector
+ parmD sellimit
+ localV DscBuf,DSC_LEN
+cBegin
+
+ifdef WOW
+ mov bx, selector
+ mov dx, word ptr sellimit[0]
+ mov cx, word ptr sellimit[2]
+ DPMICALL 0008h
+else
+ push es
+ push di
+ mov bx,selector
+
+ push ds
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ and bl, not 7
+ mov ax,sellimit.lo
+ mov [bx].dsc_limit,ax
+ mov ax,sellimit.hi
+ and al,0Fh ; AND out flags
+ and [bx].dsc_hlimit,0F0h ; AND out hi limit
+ or [bx].dsc_hlimit,al
+ pop ds
+ pop di
+ pop es
+endif; WOW
+ xor ax,ax ; for now always return success
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SelectorAccessRights
+;
+; Sets the access and other bytes of the given selector.
+;
+; Entry:
+; parmW selector
+; parmW getsetflag
+; parmD selrights
+;
+; Returns:
+; AX = 0 success
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SelectorAccessRights,<PUBLIC,FAR>
+
+ parmW selector
+ parmW getsetflag
+ parmW selrights
+cBegin
+
+ mov bx, selector
+ lar eax, ebx ; Get current access rights
+ shr eax, 8 ; in AX
+
+ cmp getsetflag,0
+ jnz short sar_set
+
+ and ax, 0D01Eh ; Hide bits they can't play with
+ jmps sar_exit
+
+sar_set:
+ mov cx, selrights
+ and cx, 0D01Eh ; Zap bits they can't set and
+ and ax, NOT 0D01Eh ; get them from existing access rights
+ or cx, ax
+ DPMICALL 0009h ; Set new access rights
+ xor ax,ax ; for now always return success
+
+sar_exit:
+
+cEnd
+
+
+cProc SetKernelCSDwordProc,<PUBLIC,NEAR>,<ax,bx,ds>
+ parmw addr
+ parmw hiword
+ parmw loword
+cBegin
+ SetKernelDS
+ mov ds, MyCSAlias
+ UnSetKernelDS
+ mov bx, addr
+ mov ax, loword
+ mov [bx], ax
+ mov ax, hiword
+ mov [bx+2], ax
+cEnd
+
+cProc GetKernelDataSeg,<PUBLIC,NEAR>
+cBegin nogen
+ mov ax, cs:MyCSDS
+ ret
+cEnd nogen
+
+cProc SetKernelDSProc,<PUBLIC,NEAR>
+cBegin nogen
+ mov ds, cs:MyCSDS
+ ret
+cEnd nogen
+
+cProc SetKernelESProc,<PUBLIC,NEAR>
+cBegin nogen
+ mov es, cs:MyCSDS
+ ret
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc PreallocArena,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ push eax
+ cCall alloc_arena_header,<eax>
+ call SetKernelDSProc
+ ReSetKernelDS
+ mov temp_arena, eax
+ or eax, eax ; Set flags for caller
+ pop eax
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc alloc_arena_header,<PUBLIC,NEAR>,<es>
+ parmD Address
+ localV DscBuf,DSC_LEN
+cBegin
+ SetKernelDS es
+ push ebx
+
+ xor eax, eax
+ cmp temp_arena, eax ; Have one waiting?
+ je short aah_look ; no, get one
+ xchg temp_arena, eax ; Use the waiting selector
+ jmp aah_found
+
+aah_look:
+ cmp FreeArenaCount, 0
+ jnz aah_ok
+ ; Out of arenas, try to get
+ push ecx
+ push si
+ push di
+ xor bx, bx
+ mov cx, ARENA_INCR_BYTES
+ DPMICALL 0501h
+ jc short aah_no_memory
+
+if 0
+ push si
+ push di
+ mov ax, 0600h ; Page lock it
+ mov di, ARENA_INCR_BYTES
+ xor si, si
+ int 31h
+ pop di
+ pop si
+ jnc short aah_got_memory
+
+give_it_back:
+ DPMICALL 0502h ; No good, give it back
+else
+ jmp short aah_got_memory
+endif
+
+aah_no_memory:
+ pop di
+ pop si
+ pop ecx
+ xor eax, eax ; We are REALLY out of arenas!
+ jmp aah_exit
+
+aah_got_memory:
+ shl ebx, 16
+ mov bx, cx ; Address of our new arenas
+ cCall get_arena_pointer32,<ds>; Arena of burgermaster
+ sub ebx, [eax].pga_address ; Above present arenas?
+
+ lea ecx, [ebx+ARENA_INCR_BYTES+0FFFh]
+ shr ecx, 12 ; #pages selector must cover
+ dec ecx ; limit with page granularity
+ cmp ecx, HighestArena
+ jbe short aah_limitOK
+
+
+ mov HighestArena, ecx
+ push es
+ push bx
+ mov bx, ds
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh ; Get DS descriptor
+ mov [DscBuf].dsc_limit, cx ; Set the new limit in the descriptor
+ shr ecx, 16
+ and cl, 0fh ; hlimit bits
+ and [DscBuf].dsc_hlimit, not 0fh; Zap old ones
+ or cl, DSC_GRANULARITY ; Granularity bit
+ or [DscBuf].dsc_hlimit, cl
+ DPMICALL 000Ch ; Set new limit
+ pop bx
+ pop es
+
+aah_limitOK:
+ mov cx, ARENA_INCR_BYTES
+ shr cx, 5 ; # arenas to add
+aah_loop:
+ cCall free_arena_header,<ebx> ; Free up all our new arenas
+ add ebx, size GlobalArena32
+ loop aah_loop
+
+ pop di
+ pop si
+ pop ecx
+
+aah_ok:
+ mov eax, FreeArenaList
+if KDEBUG
+ inc eax
+ jnz short aah_ook
+ int 3
+ int 3
+aah_ook:
+ dec eax
+endif
+ mov ebx, ds:[eax.pga_next]
+ mov FreeArenaList, ebx
+ dec FreeArenaCount
+aah_found:
+ mov ebx, Address
+ mov ds:[eax.pga_address], ebx
+ mov dword ptr ds:[eax.pga_count], 0
+aah_exit:
+ pop ebx
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc free_arena_header,<PUBLIC,NEAR>,<es>
+ parmD arena
+cBegin
+ push eax
+ push ebx
+ SetKernelDS es
+ CheckDS
+
+ mov ebx, arena
+ mov eax, FreeArenaList
+ mov ds:[ebx.pga_next], eax
+ mov FreeArenaList, ebx
+ inc FreeArenaCount
+ pop ebx
+ pop eax
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarAssociateSelector32,<PUBLIC,FAR>
+ parmW Selector
+ parmD ArenaPtr
+cBegin
+ cCall AssociateSelector32,<Selector,ArenaPtr>
+cEnd
+
+cProc AssociateSelector32,<PUBLIC,NEAR>,<ds,es>
+ parmW Selector
+ parmD ArenaPtr
+cBegin
+ CheckDS
+ SetKernelDS es
+ push eax
+ push ebx
+ movzx ebx, Selector
+ and bl, NOT SEG_RING_MASK
+ shr bx, 1
+if KDEBUG
+ cmp bx, SelTableLen
+ jb short as_ok
+ INT3_NEVER
+ INT3_NEVER
+as_ok:
+endif
+ add ebx, SelTableStart
+ mov eax, ArenaPtr
+ mov ds:[ebx], eax
+ pop ebx
+ pop eax
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc far_get_arena_pointer32,<PUBLIC,FAR>
+ parmW Selector
+cBegin
+ cCall get_arena_pointer32,<Selector>
+cEnd
+
+cProc get_arena_pointer32,<PUBLIC,NEAR>
+ parmW Selector
+cBegin
+ CheckDS
+ push es
+ SetKernelDS es
+ push ebx
+ movzx ebx, Selector
+ and bl, not SEG_RING_MASK
+ shr bx, 1
+ cmp bx, SelTableLen
+ jb short gap_ok
+ xor eax, eax ; Bogus, return null
+ jmps gap_exit
+gap_ok:
+ add ebx, SelTableStart
+ mov eax, ds:[ebx]
+
+if ROM
+ ; hack for ROM-owned selectors. these do not have arenas
+ ; but the owner is stored in the low word. ack ack ack!!
+ ;
+ cmp eax, 0FFFF0000h
+ jb short @F
+ xor eax, eax
+@@:
+endif
+
+if KDEBUG
+ or eax, eax
+ jz short gap_exit ; Bogus, return null
+ push si
+ mov si, ds:[eax].pga_handle
+ sel_check si
+ or si, si
+ jz short gap32_match ; Boot time...
+ sub ebx, SelTableStart
+ shl bx, 1
+ cmp bx, si
+ je short gap32_match
+ xor eax, eax ; put back in 5 feb 90, alias avoided
+;;; xor eax, eax ; Removed - may be an alias!
+gap32_match:
+ pop si
+endif
+
+gap_exit:
+ pop ebx
+ pop es
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarGetOwner,<PUBLIC,FAR>,<bx>
+ parmW Selector
+cBegin
+ cCall GetOwner,<Selector>
+cEnd
+
+cProc GetOwner,<PUBLIC,NEAR>,<bx,es>
+ parmW Selector
+cBegin
+ GENTER32
+ ;;;push eax ;; why??? ax gets trashed anyway.
+ cCall get_arena_pointer32,<Selector>
+if ROM
+ or eax, eax
+ jnz short @F
+ cCall GetROMOwner,<selector>
+ jmp short go_solong
+@@:
+endif
+ or eax, eax
+ jz go_solong
+ mov bx, ds:[eax].pga_owner
+ ;;;pop eax
+ mov ax, bx
+go_solong:
+ GLEAVE32
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarSetOwner,<PUBLIC,FAR>
+ parmW Selector
+ parmW owner
+cBegin
+ cCall SetOwner,<Selector,owner>
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SetOwner,<PUBLIC,NEAR>,<ds,es>
+ parmW Selector
+ parmW owner
+cBegin
+ GENTER32 ; Assume ds not set!
+ push eax
+ cCall get_arena_pointer32,<Selector>
+ push owner
+ pop ds:[eax].pga_owner
+ pop eax
+ GLEAVE32
+cEnd
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc PageLockLinear,<PUBLIC,NEAR>,<ax,bx,cx,si,di>
+ parmD address
+ parmD len
+cBegin
+ mov bx, word ptr address+2
+ mov cx, word ptr address
+ mov si, word ptr len+2
+ mov di, word ptr len
+ DPMICALL 0600h
+ ; Let it return with carry flag from int 31h
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarValidatePointer,<PUBLIC,FAR>
+ parmD lpointer
+cBegin
+ cCall ValidatePointer,<lpointer>
+cEnd
+
+cProc ValidatePointer,<PUBLIC,NEAR>
+ parmD lpointer
+cBegin
+ lar ax, lpointer.sel
+ jnz short bad_p ; Really bad selector
+ test ah, DSC_PRESENT ; Must be present
+ jz short bad_p
+ lsl eax, dword ptr lpointer.sel
+ movzx ecx, lpointer.off
+ cmp eax, ecx ; Is the offset valid?
+ jae short good_p
+bad_p:
+ xor ax, ax
+ jmps vp_done
+good_p:
+ mov ax, 1
+vp_done:
+cEnd
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+OneParaBytes dw 10h
+
+
+cProc SelToSeg,<PUBLIC,NEAR>,<dx>
+ parmW selector
+cBegin
+ cCall get_physical_address,<selector>
+ div cs:OneParaBytes ; Smaller than rotates
+cEnd
+
+
+cProc SegToSelector,<PUBLIC,NEAR>,<bx,cx,di,ds>
+ parmW smegma
+cBegin
+ mov bx, smegma
+ DPMICALL 0002h ; Make win386 do it
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; set_discarded_sel_owner
+;
+; Sets the owner of a selector that points to a discarded object,
+; which lives in the limit field.
+;
+; Entry:
+; BX = selector to mark
+; ES = owner
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+; BX
+;
+; History:
+; Sun 03-Dec-1989 21:02:24 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc set_discarded_sel_owner,<PUBLIC,FAR>
+ localV DscBuf,DSC_LEN
+cBegin
+ push cx
+ push di
+ mov cx, es
+
+if KDEBUG
+ifdef WOW
+ lea di, DscBuf
+ smov es, ss
+ DPMICALL 000Bh
+ push cx
+ xor cx,cx ; For debug build write 0 to LDT
+ mov DscBuf.dsc_owner, cx
+ DPMICALL 000Ch
+ pop cx
+endif
+endif
+ push ds
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ push bx
+ and bl, not 7
+ mov [bx].dsc_owner, cx
+ pop bx
+ pop ds
+ push ds
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector32,<bx,0,cx> ; And save in selector table
+ pop ds
+ mov es, cx
+ pop di
+ pop cx
+cEnd
+
+;-----------------------------------------------------------------------;
+; SetResourceOwner
+;
+; Sets the owner of a selector that points to a not present resource
+;
+; Entry:
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+;
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetResourceOwner,<PUBLIC,NEAR>,<ax,bx,cx,di,ds,es>
+ parmW selector
+ parmW owner
+ parmW selCount
+ localV DscBuf,DSC_LEN
+cBegin
+ mov bx, selector
+ mov cx, owner
+ifdef WOW
+ smov es, ss
+ lea di, DscBuf
+ DPMICALL 000Bh ; Get current descriptor
+ mov DscBuf.dsc_owner, cx
+ mov word ptr DscBuf.dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
+ mov cx,selCount
+ mov DscBuf.dsc_hbase, cl ; Save number of selectors here
+ DPMICALL 000Ch ; Set it with new owner
+else
+ push ds
+if ROM
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ push bx
+ and bl, not 7
+ mov [bx].dsc_owner, cx
+ mov word ptr [bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA
+ mov cx, selCount
+ mov [bx].dsc_hbase, cl ; Save number of selectors here
+ pop bx
+ pop ds
+endif; WOW
+ SetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall AssociateSelector32,<bx,0,owner> ; And save in selector table
+cEnd
+
+cProc GetAccessWord,<PUBLIC,NEAR>
+ parmW selector
+cBegin
+ lar eax, dword ptr selector ; 386 or better, can use LAR
+ shr eax, 8
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DPMIProc
+;
+; Called NEAR by the DPMICALL macro -
+; this is better than intercepting int 31h
+;
+; By sheer fluke, all intercepts return with
+; Carry clear ie no error.
+;
+;-----------------------------------------------------------------------;
+cProc DPMIProc,<PUBLIC,NEAR>
+cBegin nogen
+if 0
+ cmp ax,WOW_DPMIFUNC_0C
+ jne @f
+
+ INT3_TEST
+ push ds
+ SetKernelDS ds
+ cmp high0c,cx
+ ja popit
+
+ mov high0c,cx
+popit:
+ pop ds
+@@:
+endif
+
+ifdef WOW
+ cmp ax,501h
+ jne normal
+
+ push eax
+ push edx
+
+ shl ebx,16 ; ebx = bx:cx
+ mov bx,cx
+
+ xor eax,eax
+ mov ecx,PAGE_READWRITE
+ mov edx,MEM_COMMIT_RESERVE
+ cCall VirtualAlloc,<eax,ebx,edx,ecx>
+
+ mov bx,dx ; DPMI returns BX:CX - linear Address
+ mov cx,ax
+
+ mov si,dx ; FAKE dpmi "handle" - linear Address
+ mov di,ax
+
+ or ax,dx ; NULL is Error
+ pop edx
+ pop eax
+
+ clc
+ jnz @f ; OK Jump
+ stc ; else set error
+@@:
+ ret
+
+normal:
+endif ; WOW
+
+ or ah, ah
+
+ jz @F
+ife KDEBUG
+ifdef WOW_x86
+
+ ;
+ ; If it is the wow set selector call we will just set the selector
+ ; directly using int 2a (only for the single selector case)
+ ;
+ cmp ax,WOW_DPMIFUNC_0C
+ jne CallServer
+
+ cmp cx,1
+ jne CallServer
+
+ call WowSetSelector
+ jc CallServer
+ ret
+endif
+endif
+CallServer:
+ifndef WOW
+ int 31h ; Nope, call DPMI server
+ ret
+else
+ test word ptr [prevInt31Proc + 2],0FFFFh
+ jz dp30
+dp20:
+ pushf
+ call [prevInt31Proc]
+ ret
+endif
+@@:
+ifdef WOW
+ cmp gdtdsc, 0 ; Can we party?
+ jz CallServer ; Nope
+endif
+ push ds
+ mov ds, gdtdsc
+ifdef WOW
+
+ or al, al
+ jnz @F
+ mov ax, WOW_DPMIFUNC_00
+ pop ds
+ jmp CallServer
+@@:
+endif
+ cmp al, 0Bh
+ jne short @F
+
+ push si ; Get Descriptor - used very often!
+ mov si, bx
+ and si, not 7
+ MovsDsc
+ lea di, [di-DSC_LEN] ; Restore DI
+ pop si
+ pop ds
+ ret
+ifndef WOW
+@@:
+ cmp al, 0Ch
+ jne @F
+
+ push bx ; Set Descriptor
+ and bl, not 7
+ mov ax, es:[di] ; This looks slow but it isn't...
+ mov ds:[bx], ax
+ mov ax, es:[di][2]
+ mov ds:[bx][2], ax
+ mov ax, es:[di][4]
+ mov ds:[bx][4], ax
+ mov ax, es:[di][6]
+ mov ds:[bx][6], ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+ ret
+
+@@:
+ cmp al, 07h ; Set Segment Base Address
+ jne @F
+ push bx
+ and bl, not 7
+ mov ds:[bx].dsc_lbase, dx
+ mov ds:[bx].dsc_mbase, cl
+ mov ds:[bx].dsc_hbase, ch
+ pop bx
+ pop ds
+ ret
+endif
+@@:
+ cmp al, 06h ; Get Segment Base Address
+ jne @F
+ push bx
+ and bl, not 7
+ mov dx, ds:[bx].dsc_lbase
+ mov cl, ds:[bx].dsc_mbase
+ mov ch, ds:[bx].dsc_hbase
+ pop bx
+ pop ds
+ ret
+ifndef WOW
+@@:
+ cmp al, 09h ; Set Descriptor Access Rights
+ jne @F
+ push bx
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, cx
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop bx
+ pop ds
+ ret
+endif
+@@:
+ pop ds
+ jmp CallServer
+
+ifdef WOW
+dp30: int 31h
+ ret
+endif
+cEnd nogen
+
+ife KDEBUG
+ifdef WOW_x86
+;-----------------------------------------------------------------------;
+; WowSetSelector
+;
+; Entry
+; BX contains selector #
+;
+; Exit
+; CY clear for success
+;
+;
+;-----------------------------------------------------------------------;
+cProc WowSetSelector,<PUBLIC,NEAR>
+cBegin nogen
+
+ push ds
+ push es
+ push eax
+ push ecx
+ push edx
+ push ebx
+ push ebp
+
+ SetKernelDS ds
+ ;
+ ; Check to see if we can do this
+ ;
+ mov edx, FlatAddressArray
+ or edx, edx
+ stc
+ jz wss50
+
+ ;
+ ; put the base of the selector in the flat address array
+ ;
+ mov es,gdtdsc
+ and bx, NOT SEG_RING
+ mov ax, FLAT_SEL
+ mov ds, ax
+ mov ah, es:[bx].dsc_hbase
+ mov al, es:[bx].dsc_mbase
+ shl eax,16
+ mov ax, es:[bx].dsc_lbase
+ movzx ecx,bx
+ shr ecx,1 ; dword index from selector index
+ add ecx, edx ; point to proper spot in array
+ mov [ecx], eax
+
+ ;
+ ; Form the limit of the selector
+ ;
+ movzx dx, byte ptr es:[bx].dsc_hlimit
+ and dx,0fh ; remove gran etc.
+ shl edx, 16
+ mov dx, es:[bx].dsc_limit
+
+ ;
+ ; Adjust for granularity
+ ;
+ test es:[bx].dsc_hlimit, DSC_GRANULARITY
+ jz wss10
+
+ shl edx,12
+ or edx,0fffh
+
+ ;
+ ; Verify that the base/limit combination is allowed
+ ; duplicate of code in dpmi32/i386/dpmi386.c <DpmiSetDescriptorEntry>
+ ;
+wss10: cmp edx,07ffeffffh
+ ja wss30
+
+ mov ecx,eax
+ add ecx,edx
+ cmp ecx,07ffeffffh
+ jb wss40
+
+ ;
+ ; Limit is too high, so adjust it downward
+ ;
+wss30: mov edx,07ffeffffh
+ sub edx,eax
+ sub edx,0fffh
+
+ ;
+ ; fix for granularity
+ ;
+ test es:[bx].dsc_hlimit, DSC_GRANULARITY
+ jz wss35
+
+ shr edx,12
+
+ ;
+ ; store the new limit in the descriptor table
+ ;
+wss35: mov es:[bx].dsc_limit,dx
+ shr edx,16
+ movzx ax,es:[bx].dsc_hlimit
+ and ax,0f0h ; mask for gran etc
+ and dx,00fh ; mask for limit bits
+ or dx,ax ; put back gran etc
+ mov es:[bx].dsc_hlimit,dl
+
+ ;
+ ; Call the system to set the selector
+ ;
+ ; int 2a special case for wow:
+ ;
+ ; eax = 0xf0f0f0f1
+ ; ebp = 0xf0f0f0f1
+ ; ebx = selector
+ ; ecx = first dword of the descriptor (LODWORD)
+ ; edx = second dword of the descriptor (HIDWORD)
+
+wss40: mov eax, 0f0f0f0f1h
+ mov ebp, 0f0f0f0f1h
+ mov ecx, dword ptr es:[bx]
+ mov edx, dword ptr es:[bx+4]
+ movzx ebx,bx
+ or bl, 3
+ int 02ah
+
+wss50:
+ pop ebp
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax
+ pop es
+ pop ds
+ ret
+cEnd nogen
+endif ; WOW_x86
+endif
+if ROM
+
+;-----------------------------------------------------------------------------
+;
+; Functions for ROM Windows
+;
+;
+
+;-----------------------------------------------------------------------------
+;
+; HocusROMBase
+;
+;-----------------------------------------------------------------------------
+
+assumes ds,nothing
+assumes es,nothing
+assumes fs,nothing
+assumes gs,nothing
+
+cProc HocusROMBase, <PUBLIC, FAR>
+
+ parmW selector
+
+cBegin
+ push bx
+ push cx
+ push dx
+ push ds
+ SetKernelDS
+ mov bx, selector
+ DPMICALL 0006h
+ mov ax, cx
+ shl eax, 16
+ mov ax, dx
+ sub eax, lmaHiROM
+ jb not_in_hi_rom
+ cmp eax, cbHiROM
+ jae not_in_hi_rom
+ add eax, linHiROM
+ mov dx, ax
+ shr eax, 16
+ mov cx, ax
+ DPMICALL 0007h
+not_in_hi_rom:
+ mov ax, bx
+ pop ds
+ UnsetKernelDS
+ pop dx
+ pop cx
+ pop bx
+cEnd
+
+
+;-----------------------------------------------------------------------------
+;
+; ChangeROMHandle
+;
+;-----------------------------------------------------------------------------
+
+assumes ds,nothing
+assumes es,nothing
+assumes fs,nothing
+assumes gs,nothing
+
+cProc ChangeROMHandle, <FAR, PUBLIC>, <si, bx, es, di, ds>
+
+ parmW hold
+ parmW hnew
+
+ localV dscbuf, DSC_LEN
+
+cBegin
+
+ SetKernelDS
+ mov ds, ArenaSel
+ UnsetKernelDS
+
+ mov bx, hold
+ cCall get_arena_pointer32, <bx>
+ or eax, eax
+ jz short crh_bummer_dude
+
+ push eax
+
+ mov si, bx
+ and si, SEG_RING_MASK
+ or si, hnew
+ smov es, ss
+ lea di, dscbuf
+ DPMICALL 000Bh
+ xchg bx, si
+ DPMICALL 000Ch
+
+ cCall AssociateSelector32, <si, 0, 0>
+
+ pop eax
+
+ test dscbuf.dsc_access, DSC_PRESENT
+ jz short @F
+ mov ds:[eax].pga_handle, bx
+@@:
+ cCall AssociateSelector32, <bx, eax>
+ cCall FreeSelArray, <hold>
+
+ mov ax, bx
+
+crh_bummer_dude:
+
+cEnd
+
+
+;-----------------------------------------------------------------------------
+;
+; CloneROMSelector
+;
+;-----------------------------------------------------------------------------
+
+assumes ds,nothing
+assumes es,nothing
+assumes fs,nothing
+assumes gs,nothing
+
+cProc CloneROMSelector, <NEAR, PUBLIC>, <es, di, bx, ds>
+
+ parmW selROM
+ parmW selClone
+
+cBegin
+
+ SetKernelDS
+ mov di, selROM
+ mov es, selROMTOC
+ assumes es, nothing
+ and di, NOT SEG_RING_MASK
+ sub di, es:[FirstROMSel]
+ mov es, selROMLDT
+ mov bx, selClone
+ DPMICALL 000Ch
+
+ cCall HocusROMBase, <bx>
+
+ mov ds, ArenaSel
+ cCall AssociateSelector32, <bx, 0, 0>
+
+ mov ax, bx
+
+cEnd
+
+;-----------------------------------------------------------------------------
+;
+; Get/SetROMOwner
+;
+;-----------------------------------------------------------------------------
+
+assumes ds,nothing
+assumes es,nothing
+assumes fs,nothing
+assumes gs,nothing
+
+cProc SetROMOwner, <NEAR, PUBLIC>, <ds, ebx, es>
+
+ parmW selector
+ parmW owner
+
+cBegin
+ GENTER32
+ cCall AssociateSelector32, <selector, 0FFFFh, owner>
+ GLEAVE32
+cEnd
+
+cProc FarSetROMOwner, <FAR, PUBLIC>
+
+ parmW selector
+ parmW owner
+
+cBegin
+ cCall SetROMOwner, <selector, owner>
+cEnd
+
+cProc GetROMOwner, <NEAR, PUBLIC>, <ds, es, ebx>
+
+ parmW selector
+
+cBegin
+ UnsetKernelDS
+ SetKernelDS es
+ mov ds, ArenaSel
+ movzx ebx, selector
+ and bl, not SEG_RING_MASK
+ shr bx, 1
+ cmp bx, SelTableLen
+ jae short gro_nope
+ add ebx, SelTableStart
+ mov eax, ds:[ebx]
+ cmp eax, 0FFFF0000h
+ jae short gro_ok
+gro_nope:
+ xor eax, eax
+gro_ok:
+cEnd
+
+;-----------------------------------------------------------------------------
+;
+; IsROMObject
+;
+;-----------------------------------------------------------------------------
+
+assumes ds,nothing
+assumes es,nothing
+assumes fs,nothing
+assumes gs,nothing
+
+cProc IsROMObject, <NEAR, PUBLIC>, <bx, di, es>
+
+ parmW selector
+ localV DscBuf, DSC_LEN
+
+cBegin
+
+if KDEBUG
+ mov ax, selector
+ sel_check ax
+endif
+
+ mov bx, selector
+ smov es, ss
+ lea di, DscBuf
+ DPMICALL 000Bh
+
+ SetKernelDS ES
+
+ mov ah, DscBuf.dsc_hbase
+ mov al, DscBuf.dsc_mbase
+ shl eax, 16
+ mov ax, DscBuf.dsc_lbase
+ sub eax, linHiROM
+ jc short iro_not_rom
+ sub eax, cbHiROM
+ jnc short iro_not_rom
+ mov al, 1
+ jmps iro_exit
+
+iro_not_rom:
+ xor eax, eax
+
+iro_exit:
+cEnd
+
+cProc FarIsROMObject, <FAR, PUBLIC>
+
+ parmW selector
+
+cBegin
+ cCall IsROMObject, <selector>
+cEnd
+
+endif
+
+ifdef WOW
+
+;-----------------------------------------------------------------------------
+; Grab the selector 0x47 so that we dont need to special case the biosdata
+; selector (0x40) while converting seg:off address to flat 32bit address
+;
+; This, however should not be part of Krnl286 heap.
+;
+; - Nanduri Ramakrishna
+;-----------------------------------------------------------------------------
+cProc AllocSelector_0x47,<PUBLIC,FAR>, <ax, bx, cx, ds>
+cBegin
+
+ ; alloc the specific selector
+
+ mov bx, 047h
+ DPMICALL 0dh
+ jc as47_exit
+
+ ; initialize the LDT
+
+ and bx, not SEG_RING
+ mov ds, gdtdsc
+ mov [bx].dsc_limit, 00h ; = 1 byte
+ mov [bx].dsc_lbase, 0400h
+ mov [bx].dsc_mbase, 00h
+ mov [bx].dsc_hbase, 00h
+
+ mov ax, DSC_DATA+DSC_PRESENT
+ and ah, not 0Fh ; Zero limit 19:16
+ mov word ptr [bx].dsc_access, ax
+
+ ; set the LDT
+
+ mov cx,1
+ mov bx, 047h
+ DPMICALL WOW_DPMIFUNC_0C
+
+as47_exit:
+cEnd
+
+endif
+
+sEnd CODE
+
+sBegin NRESCODE
+
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+; All the code below is to support DIB.DRV and WING.
+
+cProc get_sel_flags,<PUBLIC,FAR>
+ parmW selector
+cBegin
+ SetKernelDSNRes
+ mov ds,pGlobalHeap
+ cCall far_get_arena_pointer32,<selector>
+ or eax,eax
+ jz gsf5
+ movzx ax, byte ptr ds:[eax].pga_flags
+gsf5:
+ xor dx,dx
+cEnd
+
+cProc set_sel_for_dib,<PUBLIC,FAR>
+ parmW selector
+ parmW flags
+ parmW addressLo
+ parmW addressHi
+ parmW csel
+cBegin
+ SetKernelDSNRes
+ push ecx
+ push ebx
+ push fs
+ push es
+
+ ; if the selector has a value of -1, it means we either need to allocate
+ ; or deallocate an array of selectors. If we are allocating, csel will have
+ ; a count of 64k selectors. If csel is 0, we need to deallocate the selector
+ ; array pointed to by address.
+
+ cmp selector,-1
+ jne ssfSetDIB
+
+ ; see if we are actually deleting the selector array
+
+ cmp csel,0
+ jne ssfAllocSel
+
+ ; free selector array at addressHi
+
+ cCall IFreeSelector,<addressHi>
+
+ mov ax,1
+ mov dx,0
+ jmp ssf5
+
+ssfAllocSel:
+ ; we need to have the selector array created
+
+ cCall AllocSelectorArray,<csel>
+ mov selector,ax
+
+ xor dx,dx
+ cmp ax,0
+ je ssf5
+
+ ; we must set the limits in the selectors. Each selector
+ ; must have a limit in bytes for the remainder of the buffer. If there are
+ ; 3 selectors, the first will be 0x0002ffff, the second 0x0001ffff, the
+ ; third 0x0000ffff.
+
+ mov cx,csel
+ mov bx,selector
+
+ssfSetLimit:
+ sub cx,1 ; 1 less each time
+ cCall SetSelectorLimit,<bx,cx,-1>
+ add bx,DSC_LEN ; advance to the next selector
+ cmp cx,0 ; see if we have any more selector to set
+ jne ssfSetLimit
+
+
+ mov dx,addressHi
+ mov ax,addressLo
+ push selector
+ call far_set_physical_address
+
+ mov ax,0 ; return the first selector
+ mov dx,selector
+ jmp ssf5
+
+ssfSetDIB:
+ push ds
+ mov ds,pGlobalHeap
+ cCall far_get_arena_pointer32,<selector>
+ or eax,eax
+ jz ssf5
+ pop fs
+ push eax ; save arena ptr
+ cCall GrowHeapDib,<eax,addressHi,addressLo>
+ or eax,eax
+ jnz ssf0
+ pop eax
+ xor eax,eax
+ jmp ssf5
+ssf0:
+ pop esi ; ds:esi is arena ptr
+ push eax ; save the new arena
+ xor edi,edi ; ds:edi is global heap info
+ cCall Free_Object2
+ mov dx,addressHi
+ mov ax,addressLo
+ cCall far_set_physical_address,<selector>
+ pop eax
+ push eax
+ cCall FarAssociateSelector32, <selector, eax>
+
+ ; now see that the GAH_PHANTOM flag is set in the arena
+ pop edx
+ or ds:[edx].pga_flags, GAH_PHANTOM
+
+ ; Now check if we are operating on a local heap. If so we change the
+ ; LocalNotifyDefault to LocalNotifyDib.
+ push es
+ push selector
+ pop es
+ xor edi,edi
+ mov di,word ptr es:[pLocalHeap]
+ or di,di
+ jz ssf4 ; Its not a local heap
+ cmp edi,ds:[edx].pga_size
+ jae ssf4 ; Its not a local heap
+ cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH
+ jne ssf4
+if KDEBUG
+ cmp word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault
+ jne ssf2
+ cmp word ptr es:[di].li_notify+2,codeBase
+ je ssf3
+ssf2:
+ krDebugOut <DEB_TRACE OR DEB_KrMemMan>, "Set_Sel_For_Dib: App has hooked LocalNotifyDefault"
+ssf3:
+endif
+ mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDib
+ mov word ptr es:[di].li_notify+2,codeBase
+ssf4:
+ pop es
+ mov eax,1
+ssf5:
+ pop es
+ pop fs
+ pop ebx
+ pop ecx
+cEnd
+
+cProc RestoreDib,<PUBLIC,FAR>
+ parmW selector
+ parmW flags
+ parmD address
+ localw hNewDib
+ localw cSel
+ localD DibSize
+ localD NewArena
+ localD OldArena
+cBegin
+ SetKernelDSNRes
+ push ecx
+ push ebx
+ push fs
+ push es
+
+ ;; Allocate a new global block
+ xor eax, eax ; In case lsl fails
+ lsl eax, dword ptr selector
+ or eax,eax
+ jz rd_fail
+
+ inc eax
+ mov DibSize,eax
+ cCall IGlobalAlloc,<flags,eax>
+ or ax,ax
+ jz rd_fail
+
+ mov hNewDib,ax
+
+ push ds
+ pop fs
+ mov ds,pGlobalHeap
+ cCall far_get_arena_pointer32,<selector>
+ mov OldArena,eax
+ or eax,eax
+ jz rd2
+ movzx ax, word ptr [eax].pga_selcount
+ mov cSel,ax
+ cCall far_get_arena_pointer32,<hNewDib>
+ or eax,eax
+ jnz rd5
+rd2:
+ cCall IGlobalFree,<hNewDib>
+ jmp rd_fail
+rd5:
+ mov NewArena,eax
+ cld
+
+ push ds
+ mov ecx,DibSize
+ mov ax, hNewDib
+ or ax, 1
+ mov es, ax
+ mov ds, selector
+ xor esi, esi
+ xor edi, edi
+ mov eax,ecx
+ shr ecx,2 ; dwords
+ rep movs dword ptr es:[edi], dword ptr ds:[esi]
+ and eax,3
+ mov ecx,eax
+ rep movs byte ptr es:[edi], byte ptr ds:[esi]
+
+ pop ds
+
+ ;; free the selector that came back with GlobalAlloc
+ xor eax,eax
+ cCall farAssociateSelector32, <hNewDib,eax>
+ cCall IFreeSelector, <hNewDib>
+
+ ;; Map the original selector to this new block
+ mov eax,NewArena
+ mov edx,[eax].pga_address
+ mov ebx,[eax].pga_size
+ dec ebx
+ mov ax,dx
+ shr edx,16
+ cCall far_set_physical_address,<selector>
+ mov eax,NewArena
+ cCall farAssociateSelector32, <selector,eax>
+ mov cx,cSel
+ mov dx,selector
+rd13:
+ dec cx
+ push bx
+ push cx
+ push dx
+ cCall SetSelectorLimit,<dx,cx,bx>
+ pop dx
+ pop cx
+ pop bx
+ add dx,DSC_LEN ; advance to the next selector
+ jcxz rd14
+ jmp short rd13
+rd14:
+
+ ;; Fix some values in the new arena from old arena
+ mov eax,NewArena
+ mov ebx,OldArena
+
+ mov ecx,dword ptr [ebx].pga_handle
+ mov dword ptr [eax].pga_handle,ecx
+ mov ecx,dword ptr [ebx].pga_count
+ dec ecx
+ mov dword ptr [eax].pga_count,ecx
+
+ and byte ptr [eax].pga_flags, NOT GAH_PHANTOM
+
+ ;; Free the dib
+ cCall FreeHeapDib, <OldArena>
+
+ ; Now check if we are operating on a local heap. If we so change the
+ ; LocalNotifyDiB to LocalNotify.
+
+ mov edx, NewArena
+ push selector
+ pop es
+ xor edi,edi
+ mov di,word ptr es:[pLocalHeap]
+ or di,di
+ jz rd_15
+ cmp edi,ds:[edx].pga_size
+ jae rd_15 ; Its not a local heap
+ cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH
+ jne rd_15
+ mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault
+ mov word ptr es:[di].li_notify+2,codeBase
+
+rd_15:
+ mov eax,1
+ jmp short rd_exit
+
+rd_fail:
+ xor eax,eax
+
+rd_exit:
+ pop es
+ pop fs
+ pop ebx
+ pop ecx
+cEnd
+
+cProc DibRealloc,<PUBLIC,FAR>
+ parmW Selector
+ parmW NewSize
+cBegin
+ SetKernelDSNRes
+
+ push ebx
+ mov ds,pGlobalHeap
+ cCall far_get_arena_pointer32,<Selector>
+ or eax,eax
+ jz dr20
+
+ movzx ebx,NewSize
+ mov ds:[eax].pga_size,bx
+ add ebx,ds:[eax].pga_address
+ mov eax,ds:[eax].pga_next
+ mov dword ptr ds:[eax].pga_address,ebx
+ mov bx,NewSize
+ dec bx
+ cCall SetSelectorLimit,<Selector,0,bx>
+ mov ax,Selector
+ jmp short drexit
+dr20:
+ xor ax,ax
+drexit:
+ pop ebx
+cEnd
+
+
+sEnd NRESCODE
+
+
+end
+
diff --git a/private/mvdm/wow16/kernel31/aliases.asm b/private/mvdm/wow16/kernel31/aliases.asm
new file mode 100644
index 000000000..f2ad8b915
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/aliases.asm
@@ -0,0 +1,302 @@
+
+;-----------------------------------------------------------------------;
+; add_alias
+;
+;
+; Entry:
+; AX = alias
+; BX = base
+;
+; Returns:
+; AX = 1 success
+;
+; Error Returns:
+; AX = 0
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-May-1989 09:16:09 -by- David N. Weise [davidw]
+; Stole it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc add_alias,<PUBLIC,NEAR>,<ax>
+
+cBegin
+ SetKernelDS ES
+ mov dx,ax
+ mov es,sel_alias_array
+ UnSetKernelDS ES
+aa_look:
+ mov cx,es:[sa_size]
+ shr cx,1
+ mov di, SIZE SASTRUC
+ xor ax,ax
+ repnz scasw
+ jcxz aa_grow
+ and bl,NOT 07h ; remove RPL bits
+ and dl,NOT 07h ; remove RPL bits
+ mov es:[di][-2].sae_sel,bx
+ mov es:[di][-2].sae_alias,dx
+ mov ax,1 ; return success
+ jmps aa_exit
+
+aa_grow:
+ xor di,di
+ mov ax,es:[di].sa_size
+ add ax,SIZE SASTRUC + ((SIZE SAENTRY) * 8)
+ push ax
+ push bx
+ push dx
+ push es
+ cCall GlobalRealloc,<es,di,ax,GA_MOVEABLE>
+ pop es
+ pop dx
+ pop bx
+ or ax,ax ; did we get the memory?
+ pop ax
+ jz aa_exit
+ sub ax,SIZE SASTRUC
+ mov es:[di].sa_size,ax ; reset the size
+ jmps aa_look
+
+aa_exit:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; delete_alias
+;
+; Checks to see if the passed selector is an alias, if
+; so it frees the entry in the array.
+;
+; Entry:
+; AX = selector to free
+; Returns:
+; ES:DI => alias struct
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-May-1989 09:16:09 -by- David N. Weise [davidw]
+; Stole it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc delete_alias,<PUBLIC,NEAR>
+cBegin
+; int 3
+ SetKernelDS ES
+ mov es,sel_alias_array
+ xor di,di
+ mov cx,es:[di].sa_size
+ shr cx,1
+ mov di, SIZE SASTRUC
+ and al,NOT 07h ; remove RPL bits
+da_keep_looking:
+ repnz scasw
+ jcxz da_exit
+ .errnz sae_sel - 0
+ .errnz sae_alias - 2
+ .errnz (SIZE SASTRUC) - 4
+ test di,2 ; we avoid problems this way
+ jnz da_keep_looking
+ sub di,4
+ xor ax,ax
+ mov es:[di].sae_alias,ax
+ mov es:[di].sae_sel,ax
+da_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; get_alias_from_original
+;
+;
+; Entry:
+; AX = original selector
+;
+; Returns:
+; BX = alias
+; = 0 if no alias
+; ES:DI => alias struct
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-May-1989 09:16:09 -by- David N. Weise [davidw]
+; Stole it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_alias_from_original,<PUBLIC,NEAR>
+
+cBegin nogen
+; int 3
+ SetKernelDS ES
+ mov es,sel_alias_array
+ UnsetKernelDS ES
+ xor di,di
+ mov cx,es:[di].sa_size
+ mov di,SIZE SASTRUC
+ shr cx,1
+ and al,NOT 07h ; remove RPL bits
+gafo_keep_looking:
+ cld
+ repnz scasw
+ xor bx,bx
+ jcxz gafo_exit
+ .errnz sae_sel - 0
+ .errnz sae_alias - 2
+ .errnz (SIZE SASTRUC) - 4
+ test di,2 ; we avoid problems this way
+ jz gafo_keep_looking
+ sub di,2
+; int 3
+ mov bx,es:[di].sae_alias
+gafo_exit:
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; get_original_from_alias
+;
+;
+; Entry:
+; AX = alias selector
+;
+; Returns:
+; BX = original selector
+; = 0 if no alias
+; ES:DI => alias struct
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-May-1989 09:16:09 -by- David N. Weise [davidw]
+; Stole it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_original_from_alias,<PUBLIC,NEAR>
+
+cBegin nogen
+; int 3
+ SetKernelDS ES
+ mov es,sel_alias_array
+ xor di,di
+ mov cx,es:[di].sa_size
+ mov di,SIZE SASTRUC
+ shr cx,1
+ and al,NOT 07h ; remove RPL bits
+gofa_keep_looking:
+ cld
+ repnz scasw
+ xor bx,bx
+ jcxz gofa_exit
+ .errnz sae_sel - 0
+ .errnz sae_alias - 2
+ .errnz (SIZE SASTRUC) - 4
+ test di,2 ; we avoid problems this way
+ jnz gofa_keep_looking
+ sub di,4
+; int 3
+ mov bx,es:[di].sae_sel
+gofa_exit:
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; check_for_alias
+;
+;
+; Entry:
+; parmW selector that moved
+; parmD new address
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Wed 17-Jan-1990 02:07:41 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc check_for_alias,<PUBLIC,NEAR>,<ds,es>
+
+ parmW selector
+ parmD new_address
+cBegin
+; int 3
+ pusha
+ pushf
+ mov ax,selector
+ call get_alias_from_original
+ or bx,bx
+ jz cfa_exit
+; int 3
+ mov dx,new_address.hi
+ mov ax,new_address.lo
+ cCall set_physical_address,<bx>
+cfa_exit:
+ popf
+ popa
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; wipe_out_alias
+;
+; This little routine is called when a global memory object
+; is being freed. We search for an alias, if one is found
+; then it is freed.
+;
+; Entry:
+; DX = handle that might have an alias associated with it
+;
+; Returns:
+; nothing
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 18-Jan-1990 00:43:13 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc wipe_out_alias,<PUBLIC,NEAR>,<dx,di>
+cBegin
+; int 3
+ mov ax,dx
+ call get_alias_from_original
+ or bx,bx
+ jz woa_exit
+; int 3
+ xor ax,ax
+ mov es:[di].sae_sel,ax
+ xchg es:[di].sae_alias,ax
+ cCall FreeSelector,<ax>
+woa_exit:
+
+cEnd
+
diff --git a/private/mvdm/wow16/kernel31/appl.inc b/private/mvdm/wow16/kernel31/appl.inc
new file mode 100644
index 000000000..be9baee91
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/appl.inc
@@ -0,0 +1,49 @@
+;*****************************************************************************
+;* * AppL.inc : Windows Application Fast Loader APPL structure
+;*****************************************************************************
+
+magicApplCur EQU '0A' ;* apploader version ("A0")
+
+APPL STRUC
+ ;* Magic value
+ magicAppl DW ?
+
+;* * Information filled in by Munge
+ ;* start of RLB info
+ ;* prlbCodeAppl is patched by MUNGE to point to first address
+ ;* will be 0 if not MUNGEd
+ prlbCodeAppl DW ?
+
+;* * Information filled in by Apploader
+ ;* address of Boot Procedure (first instance only)
+ pfnBootAppl DD ?
+ ;* address of Reload Procedure
+ pfnReloadAppl DD ?
+
+;* * Information filled in by Kernel
+ ;* address of pGlobalHeap
+ lppsMob DD ?
+ ;* address of MyAlloc() far alias
+ pfnKernelAlloc DD ?
+ ;* address of EntProcAddress() far alias
+ pfnEntProcAddress DD ?
+
+;* * THE FOLLOWING ADDITIONS WERE ADDED AFTER THE Win386 release (9/15/87)
+
+;* * filled in by AppLoader
+ pfnExitAppl DD ? ;* exit application
+ ;* (i.e. last instance)
+
+;* * filled in by MUNGE
+ cparaFixedAppl DW ? ;* size of fixed block
+ cparaPreloadAppl DW ? ;* size of preload block
+ cbDgroupNonzAppl DW ? ;* real non-zero data size
+ cwRlbCodeAppl DW ? ;* size of rlbCode
+
+;* * THE FOLLOWING ADDITIONS WERE ADDED FOR Windows 3.0
+ ;* address of SetOwner() far alias
+ pfnSetOwner DD ?
+
+APPL ENDS
+
+;*****************************************************************************
diff --git a/private/mvdm/wow16/kernel31/atom.asm b/private/mvdm/wow16/kernel31/atom.asm
new file mode 100644
index 000000000..3972124c3
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/atom.asm
@@ -0,0 +1,452 @@
+ title ATOM - atom package
+
+include kernel.inc
+include gpfix.inc
+
+MAXINTATOM = 0C000h
+
+PRIME = 37
+
+ACTION_FIND = 0
+ACTION_ADD = 1
+ACTION_DEL = 2
+
+ATOMTABLE STRUC
+at_prime DW ? ; Hash modulus
+at_hashTable DW ? ; variable length array
+ATOMTABLE ENDS
+
+ATOM STRUC
+a_chain DW ?
+a_usage DW ?
+a_len DB ?
+a_name DB ?
+ATOM ENDS
+
+
+externW <pAtomTable>
+
+
+externFP <LocalAlloc,LocalFree,GlobalHandle>
+externNP <MyUpper>
+ifdef DBCS
+externNP MyIsDBCSLeadByte
+endif
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+;
+; This procedure should be called once by each new client program. It
+; will initialize the atom table for the caller's DS and store a pointer
+; to the atom table in a reserve location in the caller's DS.
+; We expect return value to be in CX as well as AX. (jcxz!)
+;
+cProc InitAtomTable,<PUBLIC,FAR>
+ parmW tblSize
+cBegin
+ mov ax,ds:[pAtomTable] ; Don't create if already exists
+ or ax,ax
+ jnz initdone
+ mov bx,tblSize
+ or bx,bx
+ jnz gotsize
+ mov bl,PRIME
+gotsize:
+ push bx
+ inc bx ; space for table size
+ shl bx,1
+ mov ax,LA_ZEROINIT
+ cCall LocalAlloc,<ax,bx>
+ pop dx
+ jcxz initDone ; Failure
+ mov ds:[pAtomTable],ax
+ mov bx,ax
+ mov ds:[bx].at_prime,dx ; First word in hash is hash modulus
+initDone:
+ mov cx,ax
+cEnd
+
+sEnd MISCCODE
+
+
+sBegin CODE
+
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+labelFP <PUBLIC,DelAtom>
+ mov cl,ACTION_DEL
+ db 0BBh ; mov bx,
+
+labelVDO AddAtom
+ mov cl,ACTION_ADD
+ db 0BBh ; mov bx,
+
+labelVDO FindAtom
+ mov cl,ACTION_FIND
+ errn$ LookupAtom
+;
+; Common procedure to add, find or delete an atom table entry. Called
+; with a far pointer to the name string and an action code in CL register
+; Works in an SS != DS environment.
+;
+cProc LookupAtom,<PUBLIC,FAR>,<ds,si,di>
+ parmD pName
+ localW hName
+ localB action
+cBegin
+ beg_fault_trap la_trap
+
+ mov [action],cl
+
+ mov cx,SEG_pName ; If segment value is zero
+ifdef DBCS
+ or cx,cx
+ jne @F
+ jmp haveIntAtom
+@@:
+else
+ jcxz haveIntAtom ; ...then integer atom
+endif
+ mov hName,cx
+ les si,pName ; ES:SI = pName
+ cmp byte ptr es:[si],'#' ; Check for integer atom
+ je parseIntAtom
+ xor ax,ax
+ cmp ds:[pAtomTable],ax ; Make sure we have an atom table
+ jne tblokay
+ cCall InitAtomTable,<ax>
+ jcxz fail1
+notIntAtom:
+ les si,pName ; ES:SI = pName
+tblokay:
+ xor ax,ax ; c = 0
+ xor cx,cx ; size = 0
+ xor dx,dx ; hash = 0
+ cld
+loop1: ; while {
+ lods byte ptr es:[si] ; c = *pName++
+ or al,al ; if (!c) break;
+ jz xloop1
+ inc cl ; size++
+ jz fail1 ; if (size > 255) fail
+ifdef DBCS
+ call MyIsDBCSLeadByte ; Is first of 2byte DBCS char ?
+ jnc loop1ax ; Yes.
+endif
+ call MyUpper
+ifdef DBCS
+ jmp short loop1a ; go normal
+loop1ax:
+ mov bx, dx ; caluculate hash value
+ rol bx, 1
+ add bx, dx
+ add bx, ax
+ ror dx, 1
+ add dx, bx
+ lods byte ptr es:[si] ; Get Next char
+ or al, al ; end of strings ?
+ jz xloop1 ; yes, break;
+ inc cl ;
+ jz fail1 ; (size > 255) error
+endif
+loop1a:
+ mov bx,dx ; hash =
+ rol bx,1 ; + hash << 1
+ add bx,dx ; + hash
+ add bx,ax ; + c
+ ror dx,1 ; + hash >> 1
+ add dx,bx
+ jmp loop1 ; } end of while loop
+
+; Here if pName points to string of the form: #nnnn
+parseIntAtom:
+ inc si ; pName++
+ xor cx,cx ; sum = 0
+ xor ax,ax
+loop3:
+ lods byte ptr es:[si] ; c = *pName++
+ or al,al ; if (!c) break;
+ jz xloop3
+ sub al,'0' ; if (!isdigit(c))
+ cmp al,9
+ ja notIntAtom ;
+ imul cx, cx, 10 ; sum = (sum * 10) + (c - '0')
+ add cx, ax
+ jmp loop3
+haveIntAtom:
+ mov cx,OFF_pName ; Get integer atom
+xloop3:
+ jcxz fail1
+ cmp cx,MAXINTATOM
+ jae fail1
+ mov ax,cx ; return sum
+ jmp do_exit
+
+fail1:
+ xor ax,ax ; Fail, return NULL
+ jmp do_exit
+
+xloop1:
+ jcxz fail1 ; if (size == 0) fail
+ xchg ax,dx ; DX:AX = hash
+ mov bx,ds:[pAtomTable]
+ div ds:[bx].at_prime
+ lea bx,ds:[bx].at_hashTable ; pp = &hashTable[ hash % PRIME ]
+ shl dx,1
+ add bx,dx
+ mov dx,cx ; size
+ mov ax,ss ; Setup for cmpsb
+ mov es,ax
+loop2: ; while {
+ mov si,[bx] ; p = *pp
+ or si,si ; if (!p) break
+ jz xloop2
+
+ cmp [si].a_len,dl ; if (p->len != size)
+ jne loop2a ; continue
+ les di,pName ; s2 = pName
+ lea si,[si].a_name ; s1 = &p->name
+ mov cx,dx ; size
+loop4:
+ jcxz loop4x
+ dec cx
+ lodsb ; c1 = *s1++
+ifdef DBCS
+ call MyIsDBCSLeadByte ; first byte of 2byte ?
+ jc loop4a ; No, go normal
+ mov ah, al ; save char
+ mov al, es:[di] ; get *s2
+ inc di ; s2++
+ cmp ah, al ; compare *s1, *s2
+ jne loop4x ; not same, do next strings
+ jcxz loop4x ; not necessary but case of bad strings
+ dec cx
+ lodsb ; get next char ( this must be second
+ mov ah, al ; of 2byte )
+ mov al, es:[di]
+ inc di
+ cmp ah, al
+ je loop4 ; same, go next char
+ jmp loop4x ; not same, go next strings
+loop4a:
+endif
+ call MyUpper
+ mov ah,al
+ mov al,es:[di]
+ call MyUpper
+ inc di ; c2 = *s2++
+ cmp ah,al
+ je loop4
+loop4x:
+ mov si,[bx] ; p = *pp
+ je xloop2
+loop2a:
+ lea bx,[si].a_chain ; pp = &p->chain
+ jmp short loop2 ; } end of while loop
+
+xloop2:
+ ; Dispatch on command.
+ xor cx,cx
+ mov cl,[action]
+ jcxz do_find
+ errnz ACTION_FIND
+ loop do_delete
+ errnz ACTION_ADD-1
+
+do_add:
+ or si,si ; NULL?
+ jz do_insert
+
+ inc [si].a_usage ; Already in list. Increment reference count.
+ jmp short do_find
+
+
+do_delete:
+ or si,si ; NULL?
+ jz short do_exit ; Return NULL for internal errors
+ dec [si].a_usage
+ jg do_delete1
+ xor di,di
+ xchg [si].a_chain,di ; *pp = p->chain, p->chain = 0;
+ mov [bx],di
+ cCall LocalFree,<si> ; LocalFree( p )
+
+do_delete1:
+ xor si,si ; p = NULL
+ jmp short do_find
+
+do_insert:
+ mov di,bx ; save pp
+ push dx ; save size
+ add dx,size ATOM ; p = LocalAlloc( sizeof( ATOM )+size )
+ mov bx,LA_ZEROINIT
+ cCall LocalAlloc,<bx,dx> ; LocalAlloc( ZEROINIT, size )
+ pop cx ; restore size
+ mov si,ax
+ or si,si
+ jz do_find
+ mov [di],si ; *pp = p
+ inc [si].a_usage ; p->usage = 1
+ mov [si].a_len,cl ; p->len = size
+ mov bx,si
+ push ds ; ES = DS
+ pop es
+ lea di,[si].a_name ; strcpy( &p->name, pName )
+ xor cx,cx
+ mov cl,[si].a_len ; CX = #bytes to move
+ inc cx ; include terminating null
+ lds si,pName
+ cld
+ rep movsb
+ push es
+ pop ds ; Restore DS
+ mov si,bx
+do_find:
+ mov ax,si ; return p
+ shr ax,1
+ shr ax,1
+ jz do_exit
+ or ax,MAXINTATOM
+ end_fault_trap
+do_exit:
+cEnd
+la_trap:
+ fault_fix_stack
+ xor ax,ax ; return NULL/FALSE
+ jmp do_exit
+
+cProc IDeleteAtom,<PUBLIC,FAR>
+ parmW atom1
+ regPtr lpName,ds,bx
+cBegin
+ mov bx,atom1
+ cmp bx,MAXINTATOM
+ jb freeExit
+ shl bx,2
+ lea bx,[bx].a_name
+ cCall DelAtom,<lpName>
+ jmp short freeDone
+freeExit:
+ xor ax,ax
+freeDone:
+cEnd
+
+
+cProc IGetAtomHandle,<PUBLIC,FAR>
+ parmW atom2
+cBegin
+ mov ax,atom2
+ cmp ax,MAXINTATOM
+ jae @F
+ xor ax, ax
+@@: shl ax,2
+cEnd
+
+cProc IGetAtomName,<PUBLIC,FAR>,<si,di>
+ parmW atom3
+ parmD pString
+ parmW maxChars
+cBegin
+ beg_fault_trap getn_trap
+ cld
+ les di,pString
+ cmp maxChars,0
+ je getnFail
+ xor cx,cx
+ mov byte ptr es:[di],cl
+ mov bx,atom3
+ cmp bx,MAXINTATOM
+ jb getIntAtom
+ shl bx,2
+
+; Parameter validation - is this a pointer to a valid local allocation
+; block, and is the block in use?
+nfd = la_next - la_fixedsize ; given pointer to data, get
+ mov si, [bx.nfd] ; pointer to 'next' allocation
+ mov si, [si] ; p = p->prev
+ and si, not (LA_BUSY + LA_MOVEABLE)
+ sub si, bx
+ cmp si, -la_fixedsize
+ jnz getnFail
+ test word ptr [bx-la_fixedsize], LA_BUSY
+ jz getnFail
+
+; The usage count must be >0
+ cmp [bx].a_usage,cx
+ je getnFail
+; Len must be >0
+ mov cl,[bx].a_len
+ jcxz getnFail
+ cmp maxChars,cx
+ jg getnOkay
+ mov cx,maxChars
+ dec cx
+getnOkay:
+ lea si,[bx].a_name
+ mov ax,cx
+ rep movsb
+ mov byte ptr es:[di],0
+ jmps getnDone
+
+getn_trap:
+ fault_fix_stack ; Yes, fault handler can be within range
+getnFail:
+ mov ax, atom3
+ krDebugOut DEB_WARN, "GetAtomName(#AX,...) Can't find atom"
+ xor ax, ax
+ jmps getnDone
+
+getIntAtom:
+ ; When a buffer of length "n" is passed, we must reserve space for
+ ; the '#' character and a null terminator;
+ ; Fixed Bug #6143 --SANKAR-- 11-9-89
+ mov cx, maxChars
+ cmp cx, 2 ; one '#' and one '\0' are a must!
+ jl getnFail ; If it is less we fail;
+ sub cx, 2 ; Allow two char spaces for '#' and '\0'
+ mov maxChars, cx
+
+ or bx,bx
+ jz getnFail
+ mov al,'#'
+ stosb
+ mov ax,bx
+ mov bx,10
+ mov cx, maxChars
+ jcxz getIntDone
+getIntLoop:
+ xor dx,dx
+ div bx
+ push dx
+ dec cx
+ or ax,ax
+ jz gotIntAtom
+ jcxz gotIntAtom
+ jmp getIntLoop
+gotIntAtom:
+ sub maxChars,cx
+ mov cx,maxChars
+getIntChar:
+ pop ax
+ add al,'0'
+ stosb
+ loop getIntChar
+getIntDone:
+ xor al,al
+ stosb
+ mov ax,maxChars
+ inc ax ; For the '#' Character
+ end_fault_trap
+getnDone:
+cEnd
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/context.asm b/private/mvdm/wow16/kernel31/context.asm
new file mode 100644
index 000000000..617bf95d4
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/context.asm
@@ -0,0 +1,1393 @@
+ page ,132
+ title CONTEXT - task event procedures.
+
+.xlist
+include gpfix.inc
+include kernel.inc
+include tdb.inc
+include pdb.inc
+include eems.inc
+ifdef WOW
+include vint.inc
+include wowcmpat.inc
+endif
+.list
+
+externFP CloseCachedFiles
+externFP Int21Handler
+externFP Far_real_dos
+
+externFP GlobalAlloc
+externFP GlobalFree
+externFP GlobalLock
+externFP GlobalUnlock
+externFP GetAppCompatFlags
+
+ifdef DBCS
+externFP FarMyIsDBCSLeadByte
+endif
+
+ifdef WOW
+externFP WowShouldWeSayWin95
+externFP IGetModuleFileName
+endif
+
+DataBegin
+
+externB Kernel_Flags
+externW cpLowHeap
+externW selLowHeap
+externW selHighHeap
+externW selWoaPdb
+externB InScheduler
+externB DOS_version
+externB DOS_revision
+externB lpszFileName
+;externW pGlobalHeap
+externW winVer
+externW topPDB
+externW cur_dos_PDB
+externW Win_PDB
+externW curTDB
+externW WinFlags
+externW FileEntrySize
+externW shell_file_TDB
+externD shell_file_proc
+if ROM
+externD pYieldProc
+endif
+externD ptrace_DLL_entry
+externD ptrace_app_entry
+externD lpfnToolHelpProc
+externD dressed_for_success
+IF PMODE32
+externB fTaskSwitchCalled
+externW LockTDB
+ENDIF
+DataEnd
+
+sBegin CODE
+assumes ds,NOTHING
+assumes cs,CODE
+
+ife ROM
+externD pYieldProc
+endif
+ifndef WOW
+externNP Reschedule
+externNP DeleteTask
+externNP InsertTask
+endif ; WOW
+
+ifdef WOW
+externFP MyGetAppWOWCompatFlagsEx
+endif
+
+ifndef WOW
+;-----------------------------------------------------------------------;
+; WaitEvent ;
+; ;
+; If an event is waiting on taskID, suspend the current task until ;
+; an event is ready. Returns if an event was ready and no reschedule ;
+; occured. Otherwise returns true to indicate a reschedule has occured.;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Mar 28, 1987 05:13:50p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc WaitEvent,<PUBLIC,FAR>,<bx,ds>
+ parmW taskID
+cBegin
+
+IF PMODE32
+ push ds
+ SetKernelDS
+ cmp LockTDB, 0 ;Do we have a locked task
+ jne @F ;Yes, we want to be able to reboot
+ mov fTaskSwitchCalled, 1 ;Tell Reboot VxD that we're scheduling
+@@:
+ pop ds
+ENDIF
+
+ mov ax,taskID
+ call GetTaskHandle0
+ mov ds,ax
+ xor ax,ax
+wait_test:
+ pushf
+ FCLI
+ dec ds:[TDB_nEvents]
+ jge wait_exit
+ mov ds:[TDB_nEvents],0
+
+; go uncritical
+
+ pop bx
+ test bh,02 ; the interrupt flag
+ jz leave_int_off
+ FSTI
+leave_int_off:
+
+ smov es, 0
+if PMODE32
+ .386
+ smov fs, 0
+ smov gs, 0
+ .286
+endif
+ push cs
+ call Reschedule
+ mov al,-1
+ jmp wait_test
+
+wait_exit:
+ pop bx
+ test bh,02 ; the interrupt flag
+ jz leave_ints_off
+ FSTI
+leave_ints_off:
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; DirectedYield ;
+; ;
+; This does a yield and attempts to yield to the specific yo-yo. ;
+; In reschedule is checked the event count of the target task, if ;
+; non-zero then that task is started. Else the task queue is searched ;
+; as normal. ;
+; ;
+; Arguments: ;
+; parmW yield_to ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Mar 28, 1987 06:14:17p -by- David N. Weise [davidw] ;
+; Fixed it for aaronr. ;
+; ;
+; Fri Feb 06, 1987 00:00:11a -by- David N. Weise [davidw] ;
+; Wrote it for aaronr. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DirectedYield,<PUBLIC,FAR>
+; parmW yield_to
+cBegin nogen
+
+ push bp
+ mov bp,sp
+ push ax
+ push ds
+
+; get rid of the argument on the stack
+
+ mov ax,[bp][2] ; move IP up
+ xchg [bp][4],ax
+ xchg [bp][6],ax ; move CS up
+ SetKernelDS
+
+if ROM ;----------------------------------------------------------------
+
+ push pYieldProc.sel ; safe assumption we're going to
+ push pYieldProc.off ; USER's yield proc
+
+ mov ds,curTDB
+ assumes ds,nothing
+ mov ds:[TDB_Yield_to],ax
+
+ifdef DISABLE
+ cmp ds:[TDB_QUEUE],0
+ jnz dy_away
+endif
+dy_OldYield:
+ mov word ptr [bp][-8],codeOffset OldYield ; assumption incorrect
+ mov [bp][-6],cs
+dy_away:
+ mov ds,[bp][-4] ; 'pop' ds
+ mov ax,[bp][-2] ; .. ax ..
+ mov bp,[bp] ; .. bp ..
+ retf 8 ; 'jmp' to yield proc & clear stack
+
+else ;ROM ---------------------------------------------------------
+
+ mov ds,curTDB
+ assumes ds,nothing
+ mov ds:[TDB_Yield_to],ax
+;
+; Since this function is used by SendMessage() to switch directly
+; to and from the destination app, we don't want to call USER to recieve
+; any messages, since that causes unnecessary and inefficient recursion.
+;
+ifdef DISABLE
+ cmp ds:[TDB_QUEUE],0
+ pop ds
+ pop ax
+ pop bp
+ jz dy_OldYield
+ add sp,2 ; waste the space
+ jmp cs:pYieldProc ; Jump through CS VARIABLE
+else
+ pop ds
+ pop ax
+ pop bp
+endif
+
+dy_OldYield:
+ add sp,2 ; waste the space
+ jmps OldYield ; If no task queue, do OLD Yield.
+
+endif ;ROM ---------------------------------------------------------
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Yield ;
+; ;
+; Does what it says. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat May 09, 1987 12:21:13p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+; ;
+; Wed Apr 15, 1987 12:13:00p -by- Raymond E. Ozzie [-iris-] ;
+; Changed Yield to work for tasks that don't ever do an INITAPP, and ;
+; thus don't have a task queue. These are presumably tasks that do ;
+; some sort of background computational activity that don't have a ;
+; window associated with them. ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Yield,<PUBLIC,FAR>
+cBegin nogen
+
+if ROM ;----------------------------------------------------------------
+
+ push bp
+ mov bp,sp
+ push ds
+ SetKernelDS
+
+ push pYieldProc.sel ; safe assumption we're going to
+ push pYieldProc.off ; USER's yield proc
+
+ mov ds,curTDB
+ assumes ds, nothing
+ mov ds:[TDB_Yield_to],0
+ cmp ds:[TDB_QUEUE],0
+ jz y_oldyield
+y_away:
+ mov ds,[bp][-2] ; 'pop' ds
+ mov bp,[bp] ; .. and bp ..
+ retf 4 ; off to yield proc & clean stack
+
+y_oldyield:
+ mov word ptr [bp][-6],codeOffset OldYield ; bad assumption
+ mov [bp][-4],cs
+ jmps y_away
+
+else ;ROM ---------------------------------------------------------
+
+ push ds
+ SetKernelDS
+ mov ds,curTDB
+ assumes ds, nothing
+ mov ds:[TDB_Yield_to],0
+ cmp ds:[TDB_QUEUE],0
+ pop ds
+ jz OldYield ; If no task queue, do OLD Yield.
+ jmp cs:pYieldProc ; Pass to USER Jump through CS VARIABLE
+
+endif ;ROM ---------------------------------------------------------
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc OldYield,<PUBLIC,FAR>,<ds>
+cBegin
+ SetKernelDS
+ xor ax,ax
+ cmp InScheduler,al ; can't yield if inside scheduler
+ jnz yld3 ; just return false
+ cmp CurTDB,0 ; did it kill itself?
+ jz @F
+ mov ds,CurTDB
+ assumes ds, nothing
+ inc ds:[TDB_nEvents]
+
+@@: smov es, ax
+if PMODE32
+ .386
+ smov fs, ax
+ smov gs, ax
+ .286
+endif
+ push cs
+ call Reschedule
+ dec ds:[TDB_nEvents]
+ mov ax,-1 ; TRUE
+yld3:
+cEnd
+
+endif ; !WOW
+
+ assumes ds, nothing
+ assumes es, nothing
+
+GetTaskHandle2:
+ mov bx,sp
+ mov ax,ss:[bx+8]
+ mov bx,ss:[bx+6]
+ jmps GetTaskHandle0
+GetTaskHandle1:
+ mov bx,sp
+ mov ax,ss:[bx+6]
+GetTaskHandle0:
+ or ax,ax
+ jnz gt1
+ SetKernelDS es
+ mov ax,curTDB
+gt1: mov es,ax
+ assumes es, nothing
+; cmp es:[TDB_sig],TDB_SIGNATURE
+; jne gt2
+ ret
+;gt2: kerror ERR_TASKID,<GetTaskHandle: Invalid task handle>
+; ret
+
+ifndef WOW
+
+;;
+;; PostEvent( taskID ) - increment the event counter for a task. Return
+;; false if invalid task handle passed. Otherwise return true, after
+;; setting the scheduler flag that says a new task might be ready to
+;; run.
+;;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc PostEvent,<PUBLIC,FAR>
+; parmW taskID
+cBegin nogen
+ call GetTaskHandle1
+ inc es:[TDB_nEvents] ; indicate one more event
+ ret 2
+cEnd nogen
+
+endif ; !WOW
+
+;-------------------------------------------------------
+;
+; Get the Task pull model event queue handle
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetTaskQueue,<PUBLIC,FAR>
+; parmW taskID
+cBegin nogen
+ call GetTaskHandle1
+ mov ax,es:[TDB_queue]
+ ret 2
+cEnd nogen
+
+;-------------------------------------------------------
+;
+; Get the Task pull model event queue handle into DS
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetTaskQueueDS,<PUBLIC,FAR>
+cBegin nogen
+ SetKernelDS
+ mov ds,curTDB
+ assumes ds, nothing
+ mov ds,ds:[TDB_queue]
+ ret
+cEnd nogen
+
+;-------------------------------------------------------
+;
+; Get the Task pull model event queue handle into ES
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetTaskQueueES,<PUBLIC,FAR>
+cBegin nogen
+ SetKernelDS es
+ mov es,curTDB
+ assumes es,nothing
+ mov es,es:[TDB_queue]
+ ret
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SetTaskSignalProc,<PUBLIC,FAR>
+; parmW taskID
+; parmD signalProc
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+8]
+ call GetTaskHandle0
+ mov ax,ss:[bx+4]
+ mov dx,ss:[bx+6]
+ xchg ax,es:[TDB_USignalProc].off
+ xchg dx,es:[TDB_USignalProc].sel
+ ret 6
+cEnd nogen
+
+;--------------------------------------------------------
+;
+; Set (and Get) the Task pull model event queue handle
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SetTaskQueue,<PUBLIC,FAR>
+; parmW taskID
+; parmW hQueue
+cBegin nogen
+ call GetTaskHandle2
+ mov ax,bx
+ xchg ax,es:[TDB_queue]
+ ret 4
+cEnd nogen
+
+ifndef WOW
+
+;--------------------------------------------------------
+;
+; Set (and Get) Task Priority
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SetPriority,<PUBLIC,FAR>
+; parmW taskID
+; parmW newPri
+cBegin nogen
+ call GetTaskHandle2
+ add bl,es:[TDB_priority]
+ cmp bl,-32
+ jge stp1
+ mov bl,-32
+stp1: cmp bl,15
+ jle stp2
+ mov bl,15
+stp2: push bx
+ mov bh,1 ; put at back of priority queue
+ cmp es:[TDB_priority],bl ; SetPriority( 0 )?
+ jne stp3 ; No, continue
+ mov ax,es ; Yes, is this the current task?
+ push ds
+ SetKernelDS
+ cmp ax,curTDB
+ pop ds
+ assumes ds, nothing
+ je stp4 ; Yes, exit without doing anything
+ mov bh,0 ; No, put at front of priority queue
+stp3:
+ add bl,bh
+ mov es:[TDB_priority],bl
+ push bx
+ push es
+ cCall DeleteTask,<es>
+ cCall InsertTask,<ax>
+ pop es
+ pop ax
+ sub es:[TDB_priority],ah
+stp4:
+ pop ax
+ cbw
+ ret 4
+cEnd nogen
+
+endif ; WOW - the above code is not required in WOW
+
+;;
+;; Aaron Reynolds 7/20/87 - Added so folks like USER can ask if this is Winoldap
+;;
+;; IsWinoldapTask( taskID ) - Is this a Winoldap Task?
+;; false if not a Winoldap task, else true
+;; This works by returning the low bit in the Global Heap pointer of the task's
+;; PDB. Nobody in KERNEL sets this bit (it is always initialized to 0). It is
+;; up to WINOLDAP to mark its tasks by setting the low bit itself.
+;;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IsWinoldapTask,<PUBLIC,FAR>
+; parmW taskID
+cBegin nogen
+ifdef WOW
+ xor ax, ax ; always return false
+else
+ call GetTaskHandle1
+ mov es,es:[TDB_PDB] ; Get PDB pointer from task handle
+ mov ax,word ptr es:[PDB_GlobalHeap] ; Get low word of Global heap ptr
+ and ax,0000000000000001B ; Mask to low bit
+endif
+ ret 2
+cEnd nogen
+
+
+;----------------------------------------------------------------------------;
+; IsTask
+;
+; OLE 1.0 DLLs check whether the task they are talking to is a genuine one
+; or not. This they do by calling IsTask(). So, I look for -1 as the hTask,
+; which was returned from GetWindowTask() as BOGUSGDT for the 32 bit tasks
+; and for the 16 bit tasks a correct value was returned.
+;
+; So, if we find hTask on this function as -1, we should return TRUE to
+; keep OLE DLLs happy.
+;
+; ChandanC Feb 9th 1993.
+;
+;----------------------------------------------------------------------------;
+
+
+; Validate a task handle
+; davidds
+cProc IsTask,<PUBLIC, FAR>
+; parmW taskID
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+4]
+
+ or ax,ax
+ jz IT_err
+
+ifdef WOW
+ test al, 0100b ; Check for task aliases (see WOLE2.C) or BOGUSGDT
+ jnz task_check
+
+task_ok:
+ mov ax, 1
+ jmp SHORT IT_exit
+
+task_check:
+endif
+
+.286p
+ lsl bx,ax
+ jnz IT_err
+ cmp bx,size TDB
+ jl IT_err
+ mov es,ax
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jne IT_err
+ jmp short IT_exit
+
+IT_err:
+ xor ax,ax
+
+IT_exit:
+ ret 2
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; CVW_Hack
+;
+; This is a little hack for the next rev of CVW. This is a cheap
+; way to break into an app just before it really starts up. We
+; call off to the ptrace DLL and then jump off to the real entry
+; point.
+;
+; Entry:
+; none
+;
+; Returns:
+; none
+;
+; Registers Preserved:
+; all
+;
+; Registers Destroyed:
+;
+; History:
+;
+; Mon 27-Feb-1989 20:22:06 -by- David N. Weise [davidw]
+; Wrote it.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CVW_Hack,<PUBLIC,FAR>
+
+cBegin nogen
+ sub sp, 4
+ ;** See if we should call the TOOLHELP hook first
+ push ds
+ SetKernelDS
+ test Kernel_Flags[2],KF2_TOOLHELP ;TOOLHELP.DLL?
+ jz st_NoToolHelp ;Nope
+ push ax ;Save regs we use
+ push cx
+ push bx
+
+ push Win_PDB ; Preserve Win_TDB across ToolHelp call
+ cmp curTDB,0
+ jz @F
+ push es
+ mov es,curTDB
+ push es:[TDB_PDB]
+ pop ds:Win_PDB
+ pop es
+@@:
+ mov ax,SDM_LOADTASK
+ mov bx,WORD PTR ptrace_app_entry[0] ;Task start address in CX:DX
+ mov cx,WORD PTR ptrace_app_entry[2]
+
+ call lpfnToolHelpProc ;Do it
+
+ pop Win_PDB
+
+ pop bx
+ pop cx
+ pop ax
+
+ ;** Since we got here, we know that at least one of the two
+ ;** (WINDEBUG, TOOLHELP) or both are here. Since we know
+ ;** TOOLHELP is here, we still need to check for WINDEBUG.
+ ;** If it's here, act as if TOOLHELP were not
+ cmp WORD PTR ptrace_DLL_entry[2],0 ;WINDEBUG present?
+ jnz st_NoToolHelp ;Yes, give it a turn
+
+ ;** Since we have no one else to call, simply start the task
+ ;** Stack: AX[-2] BP[0] DS[2] RETFIP[4] RETFCS[6]
+ push bp
+ mov bp,sp
+ push ax
+ mov ax,WORD PTR ptrace_app_entry[0] ;Get the IP value
+ mov [bp + 4],ax ;Put in place of RETFIP
+ mov ax,WORD PTR ptrace_app_entry[2] ;Get the CS value
+ mov [bp + 6],ax ;Put in place of RETFCS
+ pop ax ;Clean up and start up the task
+ pop bp
+ pop ds
+ retf
+
+st_NoToolHelp:
+ pop ds
+ add sp, 4
+
+ ;** Now call CVW's hook (WINDEBUG.DLL)
+ push ax
+ push bx
+ push cx
+ push ds
+ mov bx,ds
+ SetKernelDS
+ push ptrace_app_entry.sel ; push real app entry point
+ push ptrace_app_entry.off
+
+ push cs ; push return to return
+ push codeOffset cvwh_clever
+
+
+
+ push ptrace_DLL_entry.sel ; push call into ptrace
+ push ptrace_DLL_entry.off
+
+ push ptrace_app_entry.sel
+ push ptrace_app_entry.off
+ mov ds,bx
+ UnsetKernelDS
+ mov ax,59h
+ pop bx
+ pop cx
+ retf ; 'call' ptrace
+cvwh_clever:
+ mov bx,sp
+ mov ax,ss:[bx].10
+ mov cx,ss:[bx].06
+ mov bx,ss:[bx].08
+ retf 8 ; return to real entry point
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; FileCDR_notify
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 08-Jun-1989 17:04:49 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FileCDR_notify,<PUBLIC,FAR>,<ax,bx,cx,dx,si,di,ds,es>
+ localW hHunkOMemory
+ localD lpDestFile
+cBegin
+ mov hHunkOMemory, 0 ; Handle/flag for RENAME
+ mov SEG_lpDestFile, es
+ mov OFF_lpDestFile, di
+ mov si,dx ; DS:SI points to [source] file
+ SetKernelDS es
+ cmp word ptr shell_file_proc[2],0
+ jnz @F
+fcdr_no_exitj:
+ jmp fcdr_no_exit
+@@:
+ mov di,dataOffset lpszFileName ; Where we will copy filename
+ cmp ah, 56h ; RENAME?
+ jne fcdr_no_alloc
+
+ mov ax, 256 ; Get enough for two filenames
+ xor bx, bx
+ mov cx, (GA_SHAREABLE SHL 8)+GA_MOVEABLE+GA_NOCOMPACT+GA_NODISCARD
+ cCall GlobalAlloc,<cx, bx, ax>
+ or ax, ax
+ jz fcdr_no_exitj
+ mov hHunkOMemory, ax
+ cCall GlobalLock,<ax>
+ mov es, dx
+ UnSetKernelDS es
+ mov di, ax
+ mov ah, 56h
+fcdr_no_alloc:
+
+ cld
+ push ax ; push arguments to call
+ push es
+ push di
+ cmp byte ptr ds:[si][1],':'
+ jnz nodrive
+ifdef DBCS
+ mov al, byte ptr ds:[si][0]
+ call FarMyIsDBCSLeadByte
+ jnc nodrive
+endif
+ lodsb
+ inc si
+ or al,20h ; convert to lower case
+ sub al,'a' ; convert to number
+ jmps gotdrive
+nodrive:
+ mov ah,19h
+ DOSCALL
+gotdrive:
+ mov dl,al
+ inc dl
+ add al,'A' ; convert to ascii
+ mov ah,':'
+ stosw
+ mov bx,'/' shl 8 + '\'
+ mov al,ds:[si]
+
+ cmp al,bh
+ jz getpath
+ cmp al,bl
+ jz getpath
+ mov al,bl
+ stosb
+ mov cx,ds
+ xchg si,di
+ smov ds,es
+ mov ah,47h
+ DOSCALL
+ mov ds,cx
+ xchg si,di
+ xor al,al
+ifdef DBCS
+; seek pointer to final byte of path.
+ xor ah,ah ; flag to indicate last char is dbc
+bsl_1:
+ mov al,es:[di]
+ test al,al ; end of string?
+ jz bsl_2 ; jump if so
+ inc di
+ xor ah,ah
+ call FarMyIsDBCSLeadByte ; DBC?
+ jc bsl_1 ; jump if not
+ inc ah ; indicate 'DBC'
+ jmp bsl_1
+bsl_2:
+ test ah,ah ; last char is DBC?
+ jnz getpath ; yes - don't test '\/'
+else
+ mov cx,-1
+ repnz scasb
+ dec di
+endif
+ mov al,es:[di-1]
+ cmp al,bh
+ je getpath
+ cmp al,bl
+ je getpath
+ mov al,bl
+ stosb
+getpath:
+
+@@: lodsb
+ or al,al
+ stosb
+ jnz @B
+
+ cmp hHunkOMemory, 0
+ jz no_second_file
+
+ lds si, lpDestFile ; Tack destination file name
+copy_second: ; after source file name
+ lodsb
+ stosb
+ or al, al
+ jnz copy_second
+
+no_second_file:
+ SetKernelDS es
+
+if KDEBUG
+
+ call shell_file_proc
+
+else ; KDEBUG
+;
+; The call to shell_file_proc can blow up if the variable has not
+; been updated properly, and we generate an invalid call fault.
+;
+ beg_fault_trap bad_shell_file_proc
+
+ call shell_file_proc
+
+ jmps good_shell_file_proc
+
+bad_shell_file_proc:
+
+ fault_fix_stack
+;
+; If shell_file_proc has a bad non-zero value, then zero it out
+; so USER doesn't get confused.
+;
+ xor si,si
+ mov word ptr [shell_file_proc],si
+ mov word ptr [shell_file_proc+2],si
+
+ end_fault_trap
+
+good_shell_file_proc:
+
+endif ; KDEBUG
+
+ mov si, hHunkOMemory ; Free up memory if necessary
+ or si, si
+ jz fcdr_no_exit
+ cCall GlobalUnlock,<si>
+ cCall GlobalFree,<si>
+
+fcdr_no_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; InitTask1
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 04-Feb-1990 23:47:37 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitTask1,<PUBLIC,FAR>
+
+; parmD callback
+cBegin nogen
+ mov bx,sp
+ push ds
+ SetKernelDS
+ mov ax,ss:[bx].4
+ mov dressed_for_success.off,ax
+ mov ax,ss:[bx].6
+ mov dressed_for_success.sel,ax
+ pop ds
+ ret 4
+cEnd nogen
+
+ifdef WOW
+;-----------------------------------------------------------------------;
+; IsTaskLocked ;
+; ;
+; Another hack procedure to determine if the current task is locked. ;
+; A non-NULL value is returned if the task is locked and NULL is ;
+; returned is the task is not locked. ;
+; ;
+; This will always return null, because we will always have more than ;
+; one WOW app. (wowexec is always running ;
+; ;
+; This api is used by QuickC ;
+; - Nanduri ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IsTaskLocked,<PUBLIC,FAR>
+cBegin nogen
+ xor ax,ax
+ ret
+cEnd nogen
+
+endif ; WOW
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetVersion,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ifdef WOW
+ call MyGetAppWOWCompatFlagsEx
+ test dx, word ptr cs:[gv_GACFEX_GETVERSIONHACK+2]
+ jz gv_nohack
+
+ ;
+ ; Call WOW32 to ask if we should lie about the version.
+ ; WowShouldWeSayWin95 will return zero if we should
+ ; return the "real" windows version (3.1), or will
+ ; return the word we should return in AX. For
+ ; InstallShield versions less than 3.00.088.0 it
+ ; will return 5f03, e.g. 3.95, since they don't work
+ ; on the newshell otherwise.
+ ;
+
+ pop cx ; CX = caller DS
+ push cx
+ sub sp, 256 ; make room for module path
+ mov dx, 256
+ mov bx, sp
+ push cx ; save caller DS
+ cCall IGetModuleFileName, <cx, ss, bx, dx>
+ pop cx
+ mov bx, sp
+ cCall WowShouldWeSayWin95, <ss, bx, cx>
+ add sp, 256
+ test ax,ax ; Did WOW32 provide a version?
+ jz gv_nohack ; Nope
+ jmp short gv_setdosversion
+
+gv_GACFEX_GETVERSIONHACK:
+ DD WOWCFEX_GETVERSIONHACK
+endif
+
+gv_nohack:
+ mov ax,winVer
+ xchg ah,al
+gv_setdosversion:
+ mov dh,DOS_version
+ mov dl,DOS_revision
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+
+sEnd CODE
+
+
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+ExternNP MISCMapDStoDATA
+
+;-----------------------------------------------------------------------;
+;
+; SetErrorMode - set the current task's error mode
+;
+; Entry:
+; parmW errMode 0001h = fail critical errors to app
+; 0002h = don't put up pmode fault message
+; 8000h = don't promt for file in OpenFile
+;
+; Returns:
+; AX = old flags
+;
+; History:
+; Sun 11-Feb-1990 19:01:12 -by- David N. Weise [davidw]
+; Added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ISetErrorMode,<PUBLIC,FAR>
+ parmW errMode
+cBegin
+ cCall MISCMapDStoDATA
+ ResetKernelDS
+ mov ax,errMode
+ mov ds,CurTDB
+ UnSetKernelDS
+ xchg ds:[TDB_ErrMode],ax
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GetWinFlags
+;
+; Gets the WinFlags for those wimps that can't import
+; __WinFlags properly!
+;
+; Entry:
+; none
+;
+; Returns:
+; AX = WinFlags
+;
+; History:
+; Wed 05-Jul-1989 20:19:46 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetWinFlags,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ cCall MISCMapDStoDATA
+ ResetKernelDS
+ xor ax, ax
+ push ax ; NULL => current task
+ cCall GetAppCompatFlags
+ test ax, GACF_HACKWINFLAGS
+ mov ax,WinFlags
+ jz @f
+ifdef WOW
+ ; fixes toolbook for WOW -BobDay
+ and ah, not ( WF1_WINNT or WF1_PAGING )
+else
+ and ah, not WF1_PAGING ; fixes toolbook
+endif
+
+@@:
+ xor dx,dx
+ pop ds
+ ret
+cEnd nogen
+
+
+;--------------------------------------------------------
+;
+; GetExeVersion - return the current task's expected Windows version
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetExeVersion,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov ds, CurTDB
+ UnSetKernelDS
+ mov ax, ds:[TDB_ExpWinVer]
+ pop ds
+ ret
+cEnd nogen
+
+ifndef WOW
+;-----------------------------------------------------------------------;
+; WinOldApCall ;
+; ;
+; This gives WinOldAp the information it needs to run in Expanded ;
+; Memory. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; (Real Mode) ;
+; BX = XMS Handle of segment cache block ;
+; CX = Size (in K bytes) of segment cache block ;
+; DS:SI = pointer to original Int 21h handler ;
+; DI = DOS System File Table Entry size ;
+; ;
+; (Protected Mode) ;
+; AX = Selector to low (lower 640k) heap block ;
+; BX = paragraph count of low heap block ;
+; CX = Selector to high (above 1024k & HMA) heap block ;
+; DX = Selector to fixed low PDB block for WOA use ;
+; DS:SI = pointer to original Int 21h handler ;
+; DI = DOS System File Table Entry size ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Mar 25, 1987 03:03:57p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc WinOldApCall,<PUBLIC,FAR>
+; parmW func
+cBegin nogen
+
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov bx,sp ; check function code
+ cmp word ptr ss:[bx+6],0 ; 0 - get WOA info call
+ jz get_info ; !0 - close cached files call
+
+ push Win_PDB ; Save current PDB
+ cCall CloseCachedFiles,<topPDB> ; close the cached files--really
+ pop Win_PDB ; 'Set' it back
+;;; mov bx, Win_PDB
+;;; mov ah, 50h ; Reset the PDB
+;;; call far_real_DOS
+;;; mov cur_dos_PDB, bx ; Keep variables in sync
+ jmps woa_exit ; closes them when passed topPDB
+
+get_info:
+
+ mov ax,selLowHeap
+ mov bx,cpLowHeap
+ mov cx,selHighHeap
+ mov dx,selWoaPdb
+
+ mov di,FileEntrySize ;DOS version specific SFT entry size
+
+woa_exit:
+ pop ds
+ ret 2
+
+cEnd nogen
+endif
+
+
+;-----------------------------------------------------------------------;
+; RegisterPtrace
+;
+; The ptrace engine DLL gets calls on behalf of the KERNEL.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Fri 02-Feb-1990 23:41:54 -by- David N. Weise [davidw]
+; We'll get this right one of these days.
+;
+; Mon 27-Feb-1989 20:22:06 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc RegisterPtrace,<PUBLIC,FAR>
+
+; parmD ptrace_proc
+
+cBegin nogen
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov bx,sp
+ or Kernel_flags[2],KF2_PTRACE
+ mov ax,ss:[bx][6]
+ mov ptrace_DLL_entry.off,ax
+ or ax,ss:[bx][8] ; is there one?
+ mov ax,ss:[bx][8]
+ mov ptrace_DLL_entry.sel,ax
+
+ jnz rp_done
+
+ ;** If TOOLHELP's still installed, we don't really want to clear the
+ ;** flag. If it's unhooked, clear the flag
+ test Kernel_flags[2], KF2_TOOLHELP
+ jnz rp_done
+ and Kernel_flags[2],NOT KF2_PTRACE
+rp_done:
+ pop ds
+ ret 4
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ToolHelpHook
+;
+; Allows TOOLHELP.DLL to get PTrace notifications BEFORE the
+; normal PTrace hook used by WINDEBUG.DLL. The WINDEBUG.DLL
+; hook is now obsolete and is maintained only for backward
+; compatibility.
+;
+; TOOLHELP calls this function with a valid lpfn or with NULL
+; when it is ready to unhook.
+;
+; July 25, 1991 [jont]
+;-----------------------------------------------------------------------;
+
+cProc ToolHelpHook,<PUBLIC,FAR>, <ds,si,di>
+ parmD lpfn
+cBegin
+ SetKernelDSMisc
+
+ ;** Set/clear the ToolHelp hook installed flag + we also set the
+ ;* PTrace flag because the ToolHelp hook is just a new
+ ;* PTrace hook. We can only clear it, though, if BOTH PTrace
+ ;** hooks are now clear.
+ or Kernel_Flags[2],KF2_TOOLHELP OR KF2_PTRACE ;Set the flags
+ mov ax,WORD PTR lpfn[0] ;Get the offset
+ mov dx,WORD PTR lpfn[2] ; and the selector
+ mov bx,ax ;Get a copy to trash
+ or bx,dx ;NULL?
+ jnz THH_Installed ;No
+ and Kernel_Flags[2],NOT KF2_TOOLHELP ;Clear the flag
+ cmp WORD PTR ptrace_dll_entry[2],0 ;WINDEBUG.DLL lurking?
+ jnz THH_Installed ;Yes, don't clear PTrace flag
+ and Kernel_Flags[2],NOT KF2_PTRACE ;Clear the flag
+THH_Installed:
+
+ ;** Install the hook and return the old one
+ xchg ax,WORD PTR lpfnToolHelpProc[0]
+ xchg dx,WORD PTR lpfnToolHelpProc[2]
+cEnd
+
+;-----------------------------------------------------------------------;
+; FileCDR
+;
+; Allows the shell to set a procedure that gets called when
+; a file or directory is created, moved, or destroyed.
+;
+; Entry:
+; parmD lpNotifyProc call back function
+;
+; Returns:
+; AX != 0 success
+;
+; History:
+; Mon 05-Jun-1989 22:59:33 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FileCDR,<PUBLIC,FAR>
+; parmD lpNotifyProc
+cBegin nogen
+ mov bx,sp
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov ax,ss:[bx][6]
+ cmp ax,-1 ; is sel == -1, return current
+ jne @F ; proc
+ mov ax,shell_file_proc.off
+ mov dx,shell_file_proc.sel
+ jmps fcdr_exit
+
+@@:
+ xchg shell_file_proc.sel,ax
+ or ax,ax
+ jz @F
+ mov cx,curTDB
+ cmp cx,shell_file_TDB
+ jnz fcdr_error
+@@: mov ax,ss:[bx][4]
+ mov shell_file_proc.off,ax
+ mov ax,curTDB
+ mov shell_file_TDB,ax
+ mov ax,1
+ jmps fcdr_exit
+
+fcdr_error:
+ xchg shell_file_proc.sel,ax ; replace what was there
+ xor ax,ax
+
+fcdr_exit:
+ pop ds
+ UnSetKernelDS
+ retf 4
+cEnd nogen
+
+
+sEnd MISCCODE
+end
diff --git a/private/mvdm/wow16/kernel31/diag.asm b/private/mvdm/wow16/kernel31/diag.asm
new file mode 100644
index 000000000..8a0e335a4
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/diag.asm
@@ -0,0 +1,225 @@
+;***************************************************************************
+;* DIAG.ASM
+;*
+;* Diagnostic-mode routines used to log interesting output to a log
+;* file. Diagnostic mode is enabled/disabled through a command line
+;* switch.
+;*
+;* Created by JonT starting 19 July 1991
+;*
+;***************************************************************************
+
+ TITLE LOG - Diagnostic mode logging routines
+
+.xlist
+include kernel.inc
+.list
+
+.386p
+
+
+DataBegin
+
+externD lpWindowsDir
+externW cBytesWinDir
+externB szDiagStart
+externB szCRLF
+
+globalW fDiagMode,0 ;Set in LDBOOT.ASM
+szLogFileName DB 'BOOTLOG.TXT', 0
+szPath DB 128 DUP(0) ;Entire pathname to file
+IF KDEBUG
+externB szInitSpew
+ENDIF
+
+DataEnd
+
+externFP Int21Handler
+externFP OutputDebugString
+
+;** Note that this goes in the fixed code segment
+sBegin CODE
+assumes CS,CODE
+
+; DiagQuery
+;
+; Exported entry point that can be called to determine if in
+; diagnostic mode. Returns TRUE iff in diagnostic mode.
+
+cProc DiagQuery, <FAR,PUBLIC>, <si,di,ds>
+cBegin
+ SetKernelDS
+
+ mov ax,fDiagMode ;Return the flag
+cEnd
+
+
+; DiagOutput
+;
+; Exported entry point to allow a string to be written to the
+; log file. The file is flushed after writing the string
+; guaranteeing that it always gets in there in case we abort
+; immediately after the call.
+
+cProc DiagOutput, <FAR,PUBLIC>, <si,di,ds>
+ parmD lpstr
+ localW wHandle
+cBegin
+ SetKernelDS
+
+ ;** Check for diag mode
+ cmp fDiagMode,1 ;Diag mode?
+ jne SHORT DO_End ;Nope, get out
+
+ ;** Reopen the log file
+ mov ah,3dh ;Create file call
+ mov al,22h ;R/W, Deny W to others
+ mov dx,dataOFFSET szPath ;File name pointer
+ DOSCALL
+ jc SHORT DO_Error ;Error, get out
+ mov wHandle,ax ;Save the handle
+
+ ;** Seek to the end
+ mov ax,4202h ;Seek to end of file call
+ mov bx,wHandle ;Get the file handle
+ xor cx,cx ;0 bytes before end of file
+ xor dx,dx
+ DOSCALL
+ jc SHORT DO_Error ;Error, get out
+
+ ;** Get the length of the string
+ xor cx,cx ;Get max length
+ dec cx ; (0xffff)
+ les di,lpstr ;Point to the string
+ xor al,al ;Zero byte
+ repnz scasb ;Find the zero byte
+ neg cx ;Get the length
+ dec cx
+ dec cx
+
+IF KDEBUG
+ ;** Spit to debug terminal in debug KERNEL
+ push cx
+ push WORD PTR lpstr[2]
+ push WORD PTR lpstr[0]
+ call OutputDebugString
+ pop cx
+ENDIF
+
+ ;** Write the string
+ push ds ;Save our DS
+ mov ah,40h ;Write file call
+ mov bx,wHandle ;Get the handle
+ lds dx,lpstr ;Get the buffer pointer
+ UnsetKernelDS
+ DOSCALL
+ pop ds
+ ResetKernelDS
+ jnc SHORT DO_Close ;No problem
+
+DO_Error:
+ mov fDiagMode,0 ;Clear diagnostic mode and close file
+
+ ;** Close the file
+DO_Close:
+ mov bx,wHandle ;Handle in BX
+ or bx,bx ;File open?
+ jz SHORT DO_End ;Nope, just get out
+ mov ah,3eh ;Close file call
+ DOSCALL
+DO_End:
+
+cEnd
+
+
+; DiagInit
+;
+; Called from Bootstap (LDBOOT.ASM) and is used to create the log file
+; and write the startup message to it.
+
+cProc DiagInit, <FAR,PUBLIC>, <ds,si,di>
+ localW wHandle
+cBegin
+ SetKernelDS
+ smov es,ds ;Point to kernel DS with ES
+
+ ;** Get the full path name
+ mov di,dataOFFSET szPath ;Point to destination path
+ mov cx,cBytesWinDir ;Get the length of the directory
+ lds si,lpWindowsDir ;Point to the Windows directory
+ UnsetKernelDS
+ rep movsb ;Copy it
+ smov ds,es ;Get DS back to kernel DS
+ ResetKernelDS
+ mov si,dataOFFSET szLogFileName ;Point to log file name
+ cmp BYTE PTR [di - 1],'/' ;Check for trailing separator
+ je SHORT DI_NoSeparator ;No separator needed
+ mov al,'\' ;Get the other separator
+ cmp [di - 1],al ;Check for other separator
+ je SHORT DI_NoSeparator ;None needed
+ stosb ;Put a '\' in
+DI_NoSeparator:
+ lodsb ;Get the char
+ stosb ;Write it
+ or al,al ;Zero byte?
+ jnz DI_NoSeparator ;No, loop for next char
+
+IF KDEBUG
+ ;** Spit to debug terminal in debug KERNEL
+ push ds
+ push dataOFFSET szInitSpew
+ call OutputDebugString ;Spit out the message
+ push ds
+ push dataOFFSET szPath ;Spit out log filename
+ call OutputDebugString
+ push ds
+ push dataOFFSET szCRLF ;Write a CR/LF
+ call OutputDebugString
+ENDIF
+
+ ;** Try to open the file. If it exists, we use it as it
+ mov ah,3dh ;Open file call
+ xor cx,cx ;Normal file
+ mov al,22h ;R/W, Deny W to others
+ mov dx,dataOFFSET szPath ;File name pointer
+ DOSCALL
+ jc SHORT DI_Create ;Error, need to create file
+ mov wHandle,ax ;Save the handle
+
+ ;** Seek to the end
+ mov ax,4202h ;Seek to end of file call
+ mov bx,wHandle ;Get the file handle
+ xor cx,cx ;0 bytes before end of file
+ xor dx,dx
+ DOSCALL
+ jmps DI_CloseIt ;Close file now
+
+ ;** Create the log file
+DI_Create:
+ mov ah,3ch ;Create file call
+ xor cx,cx ;Normal file
+ mov dx,dataOFFSET szPath ;File name pointer
+ DOSCALL
+ mov wHandle,ax ;Save the handle
+
+ ;** On error, disable logging
+ jc SHORT DI_End ;Error, get out without enabling
+DI_CloseIt:
+ mov fDiagMode,1 ;We're in diag mode now
+
+ ;** Close the file (we reopen it on each call to DiagOutput)
+ mov bx,wHandle ;Handle in BX
+ mov ah,3eh ;Close file call
+ DOSCALL
+
+ ;** Now start the log file
+ mov ax,dataOFFSET szDiagStart ;Point to the string
+ cCall DiagOutput, <ds,ax> ;Start the file
+
+DI_End:
+cEnd
+
+sEnd
+
+END
+
diff --git a/private/mvdm/wow16/kernel31/disasm.c b/private/mvdm/wow16/kernel31/disasm.c
new file mode 100644
index 000000000..1fdb5e8cc
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/disasm.c
@@ -0,0 +1,737 @@
+/* disasm.c
+ Future Features -
+
+ Current bugs -
+ Data32 for
+ (callf fword ptr [mem]), (jmpf fword ptr [mem])
+ Floating point insns
+ Call not tested
+ jecxz disassembled as large_address, not large_data
+ lidt/lgdt are 6-byte operands
+ segload doesn't set memXxxxx vars
+ some 0x0f opcodes should set gpSafe flag
+ bt, bts, btr, btc
+ SetBcc [mem]
+ SHD[l,r]
+
+Usage:
+ Call DisAsm86(code ptr)
+
+ gpRegs = 0
+ gpSafe = 0
+ If we can continue,
+ set gpSafe = 1
+ if instruction is POP SEGREG
+ gpRegs |= POPSEG
+ else
+ gpInsLen = length of instruction
+ gpRegs |= regs modified (SegLoad or String)
+ endif
+ endif
+*/
+
+/* #include <string.h> */
+#include <windows.h> /* wsprintf() */
+/* Disasm.h - definitions for Don's Tiny Disassembler */
+
+typedef unsigned long dword;
+typedef unsigned short word;
+typedef unsigned char byte;
+
+
+extern word memOp; /* actual operation performed */
+extern char *memName[]; /* name corresponding to memOp */
+enum { memNOP, memRead, memWrite, memRMW, memSegReg, memSegMem};
+
+extern word memSeg; /* value of segment of memory address */
+extern dword memLinear, /* offset of operand */
+ memLinear2;
+extern word memSeg2, /* duplicate of above if dual mem op */
+ memSize2, memOp2,
+ memDouble; /* true if two-mem-operand instruction */
+
+extern word memSize; /* bytes of memory of operation */
+enum { MemByte=1, MemWord=2, MemDWord=4, MemQWord=8, MemTword=10,
+ Adr4, Adr6=6};
+
+enum { memNoSeg, memES, memCS, memSS, memDS, memFS, memGS};
+
+enum {strCX=1, strSI=2, strDI=4, segDS=8, segES=16, segFS=32, segGS=64};
+extern word gpSafe, /* 1 if may continue instruction */
+ gpRegs, /* regs which instruction modifies as side effect */
+ gpStack; /* amount stack is changed by */
+
+#ifdef PM386
+#define SHERLOCK 1
+#else
+#define SHERLOCK 0
+#endif
+
+
+#if SHERLOCK
+
+#define STATIC /*static*/
+#define NO_MEM
+
+/* int gpTrying = 0, gpEnable = 1, gpInsLen = 0; */
+extern int gpTrying, gpEnable, gpInsLen;
+extern word gpSafe, gpRegs, gpStack; /* indicate side effects of instruction */
+
+STATIC byte lookup[256] = {0}; /* lookup table for first byte of opcode */
+
+STATIC int dataSize=0, adrSize=0, /* flag to indicate 32 bit data/code */
+ segSize=0; /* flag if 32 bit code segment */
+
+
+enum { /* operand decoding classes */
+ UNK, /*NOOP, BREG, VREG, SREG, */ BWI, /*BRI, WRI,*/
+ SMOV, IMOV, /*IBYTE, IWORD, JMPW, JMPB, LEA, JCond,
+ GrpF,*/ Grp1, Grp2, Grp3, Grp4, Grp5, /*IADR, */ MOVABS,
+ RRM, RRMW, /*IMUL,*/ POPMEM, /*TEST, ENTER, FLOP, ARPL,
+ INOUT, IWORD1, ASCII, */ XLAT,
+};
+
+
+#define opBase 0
+STATIC struct {
+/* char *name; /* opcode mnemonic */
+ byte base, count; /* first table entry, number of entries */
+ byte operand; /* operand class */
+} ops[] = {
+#define NoText(n, b, c, o) b, c, o
+ NoText("?UNKNOWN", 0, 0, UNK),
+ NoText("add", 0x00, 6, BWI),
+ NoText("or", 0x08, 6, BWI),
+/* NoText("FGrp", 0x0f, 1, GrpF), */
+ NoText("adc", 0x10, 6, BWI),
+ NoText("sbb", 0x18, 6, BWI),
+ NoText("and", 0x20, 6, BWI),
+ NoText("sub", 0x28, 6, BWI),
+ NoText("xor", 0x30, 6, BWI),
+ NoText("cmp", 0x38, 6, BWI),
+/* NoText("inc", 0x40, 8, VREG), */
+/* "dec", 0x48, 8, VREG, */
+/* NoText("push", 0x50, 8, VREG), */
+/* "pop", 0x58, 8, VREG, */
+ NoText("bound", 0x62, 1, RRMW),
+/* "arpl", 0x63, 1, ARPL, */
+/* NoText("push", 0x68, 1, IWORD), */
+/* "imul", 0x69, 3, IMUL, */
+/* NoText("push", 0x6a, 1, IBYTE), */
+/* "jcond", 0x70, 16, JCond, */
+ NoText("Grp1", 0x80, 4, Grp1),
+ NoText("test", 0x84, 2, RRM),
+ NoText("xchg", 0x86, 2, RRM),
+ NoText("mov", 0x88, 4, BWI),
+ NoText("mov", 0x8c, 3, SMOV),
+/* NoText("lea", 0x8d, 1, LEA), */
+ NoText("pop", 0x8f, 1, POPMEM),
+/* NoText("xchg", 0x90, 8, VREG), */
+/* NoText("callf", 0x9a, 1, IADR), */
+ NoText("mov", 0xa0, 4, MOVABS),
+/* NoText("test", 0xa8, 2, TEST), */
+/* NoText("mov", 0xb0, 8, BRI), */
+/* NoText("mov", 0xb8, 8, WRI), */
+ NoText("Grp2", 0xc0, 2, Grp2),
+/* NoText("retn", 0xc2, 1, IWORD1), */
+ NoText("les", 0xc4, 1, RRMW),
+ NoText("lds", 0xc5, 1, RRMW),
+ NoText("mov", 0xc6, 2, IMOV),
+/* NoText("enter", 0xc8, 1, ENTER), */
+/* NoText("retf", 0xca, 1, IWORD1), */
+/* NoText("int", 0xcd, 1, IBYTE), */
+ NoText("Grp2", 0xd0, 4, Grp2),
+/* NoText("aam", 0xd4, 1, ASCII), */
+/* NoText("aad", 0xd5, 1, ASCII), */
+ NoText("xlat", 0xd7, 1, XLAT),
+/* NoText("float", 0xd8, 8, FLOP), */
+/* NoText("loopne", 0xe0, 1, JMPB), */
+/* NoText("loope", 0xe1, 1, JMPB), */
+/* NoText("loop", 0xe2, 1, JMPB), */
+/* NoText("jcxz", 0xe3, 1, JMPB), */
+/* NoText("in", 0xe4, 2, INOUT), */
+/* NoText("out", 0xe6, 2, INOUT), */
+/* NoText("call", 0xe8, 1, JMPW), */
+/* NoText("jmp", 0xe9, 1, JMPW), */
+/* NoText("jmpf", 0xea, 1, IADR), */
+/* NoText("jmp", 0xeb, 1, JMPB), */
+ NoText("Grp3", 0xf6, 2, Grp3),
+ NoText("Grp4", 0xfe, 1, Grp4),
+ NoText("Grp5", 0xff, 1, Grp5),
+};
+#define opCnt (sizeof(ops)/sizeof(ops[0]))
+
+#define simpleBase (opBase + opCnt)
+STATIC struct { /* these are single byte opcodes, no decode */
+ byte val;
+ /* char *name; */
+} simple[] = {
+#define NoText2(v, n) v
+/* NoText2(0x06, "push es"), */
+ NoText2(0x07, "pop es"),
+/* NoText2(0x0e, "push cs"), */
+/* NoText2(0x16, "push ss"), */
+/* NoText2(0x17, "pop ss"), */
+/* NoText2(0x1e, "push ds"), */
+ NoText2(0x1f, "pop ds"),
+/* NoText2(0x27, "daa"), */
+/* NoText2(0x2f, "das"), */
+/* NoText2(0x37, "aaa"), */
+/* NoText2(0x3f, "aas"), */
+/* NoText2(0x90, "nop"), */
+/* NoText2(0x9b, "wait"), */
+/* NoText2(0x9e, "sahf"), */
+/* NoText2(0x9f, "lahf"), */
+/* NoText2(0xc3, "retn"), */
+/* NoText2(0xc9, "leave"), */
+/* NoText2(0xcb, "retf"), */
+/* NoText2(0xcc, "int 3"), */
+/* NoText2(0xce, "into"), */
+/* NoText2(0xec, "in al), dx", */
+/* NoText2(0xee, "out dx), al", */
+/* NoText2(0xf0, "lock"), */
+/* NoText2(0xf2, "repne"), */
+/* NoText2(0xf3, "rep/repe"), */
+/* NoText2(0xf4, "hlt"), */
+/* NoText2(0xf5, "cmc"), */
+/* NoText2(0xf8, "clc"), */
+/* NoText2(0xf9, "stc"), */
+/* NoText2(0xfa, "cli"), */
+/* NoText2(0xfb, "sti"), */
+/* NoText2(0xfc, "cld"), */
+/* NoText2(0xfd, "std"), */
+};
+#define simpleCnt (sizeof(simple)/sizeof(simple[0]))
+
+#define dSimpleBase (simpleBase + simpleCnt)
+#if 0
+STATIC struct { /* these are simple opcodes that change */
+ byte val; /* based on current data size */
+ char *name, *name32;
+} dsimple[] = {
+/* 0x60, "pusha", "pushad", */
+/* 0x61, "popa", "popad", */
+/* 0x98, "cbw", "cwde", */
+/* 0x99, "cwd", "cdq", */
+/* 0x9c, "pushf", "pushfd", */
+/* 0x9d, "popf", "popfd", */
+/* 0xcf, "iret", "iretd", */
+/* 0xed, "in ax, dx", "in eax, dx", */
+/* 0xef, "out dx, ax", "out dx, eax", */
+};
+#define dSimpleCnt (sizeof(dsimple)/sizeof(dsimple[0]))
+#endif
+#define dSimpleCnt 0
+
+#define STR_S 1 /* string op, source regs */
+#define STR_D 2 /* string op, dest regs */
+#define STR_D_Read 4 /* string op, reads from dest regs */
+#define STR_NO_COND 8 /* rep ignores flags */
+#define stringOpBase (dSimpleBase+ dSimpleCnt)
+STATIC struct {
+ byte val;
+ /* char *name; */
+ byte flag; /* should be 'next' to op, to pack nicely */
+} stringOp[] = {
+#define NoText3(v, n, f) v, f
+ NoText3(0x6c, "ins", STR_D | STR_NO_COND),
+ NoText3(0x6e, "outs", STR_S | STR_NO_COND),
+ NoText3(0xa4, "movs", STR_S | STR_D | STR_NO_COND),
+ NoText3(0xa6, "cmps", STR_S | STR_D | STR_D_Read),
+ NoText3(0xaa, "stos", STR_D | STR_NO_COND),
+ NoText3(0xac, "lods", STR_S | STR_NO_COND),
+ NoText3(0xae, "scas", STR_D | STR_D_Read),
+};
+#define stringOpCnt (sizeof(stringOp)/sizeof(stringOp[0]))
+
+STATIC void InitDisAsm86(void) {
+ int i, j;
+ for (i=0; i<opCnt; i++) { /* Init complex entries */
+ for (j=0; j<(int)ops[i].count; j++)
+ lookup[ops[i].base+j] = (byte)i + opBase;
+ }
+
+ for (i=0; i<simpleCnt; i++) /* Init simple entries */
+ lookup[simple[i].val] = (byte)(i + simpleBase);
+
+ for (i=0; i<stringOpCnt; i++) { /* Init string op table */
+ lookup[stringOp[i].val] = (byte)(i + stringOpBase);
+ lookup[stringOp[i].val+1] = (byte)(i + stringOpBase);
+ }
+} /* InitDisAsm86 */
+
+STATIC byte far *code = 0; /* this is ugly - it saves passing current */
+ /* code position to all the GetByte() funcs */
+
+#define Mid(v) (((v) >> 3) & 7) /* extract middle 3 bits from a byte */
+
+
+ /* If you don't want to return memory access info, #def NO_MEM */
+#if !defined(NO_MEM)
+ /* global vars set by DisAsm() to indicate current instruction's memory */
+ /* access type. */
+word memSeg, memSize, memOp; /* segment value, operand size, operation */
+word memSeg2, memSize2, memOp2, /* instruction may have two memory accesses */
+ memDouble;
+dword memLinear, memLinear2; /* offset from segment of access */
+
+STATIC dword memReg, memDisp; /* used to pass information from GetReg()... */
+char *memName[] = { /* used to convert 'enum memOp' to ascii */
+ "NOP",
+ "Read",
+ "Write",
+ "RMW",
+ "MovStr",
+};
+
+#define SetMemSize(s) memSize = s
+#define SetMemSeg(s) memSeg = regs[s+9]
+#define SetMemOp(o) memOp = o
+#define SetMemLinear(l) memLinear = l
+#define SetMemSeg2(s) memSeg2 = regs[s+9]
+#define SetMemOp2(o) memOp2 = o
+#define SetMemLinear2(l) memLinear2 = l
+#define ModMemLinear(l) memLinear += l
+#define SetMemReg(r) memReg = r
+#define SetMemDisp(d) memDisp = d
+#define Read_RMW(o) ((o) ? memRead : memRMW)
+
+#else
+
+#define SetMemSeg(s)
+#define SetMemSize(s)
+#define StMemOp(o)
+#define SetMemLinear(l)
+#define SetMemSeg2(s)
+#define StMemOp2(o)
+#define SetMemLinear2(l)
+#define ModMemLinear(l)
+#define SetMemReg(r)
+#define SetMemDisp(d)
+#define Read_RMW(o) 0
+
+#endif
+
+/******************** Register Decode *******************************/
+/* These helper functions return char pointers to register names.
+ They are safe to call multiple times, as the return values are not
+ stored in a single buffer. The ?Reg() functions are passed a register
+ number. They mask this with 7, so you can pass in the raw opcode.
+ The ?Mid() functions extract the register field from e.g. a ModRM byte.
+ The Vxxx() functions look at dataSize to choose between 16 and 32 bit
+ registers. The Xxxx() functions look at the passed in W bit, and then
+ the dataSize global, do decide between 8, 16, and 32 bit registers.
+*/
+
+/************************* Opcode Fetch ***************************/
+ /* GetByte(), GetWord(), and GetDWord() read from the code segment */
+ /* and increment the pointer appropriately. They also add the current */
+ /* value to the hexData display, and set the MemDisp global in case the */
+ /* value fetched was a memory displacement */
+
+STATIC byte GetByte(void) { /* Read one byte from code segment */
+ return *code++;
+} /* GetByte */
+
+STATIC word GetWord(void) { /* Read two bytes from code seg */
+ word w = *(word far *)code;
+ code += 2;
+ return w;
+} /* GetWord */
+
+STATIC long GetDWord(void) { /* Read four bytes from code seg */
+ unsigned long l = *(long far *)code;
+ code += 4;
+ return l;
+} /* GetDWord */
+
+#define GetImmByte() GetByte()
+#define GetImmWord() GetWord()
+#define GetImmDWord() GetDWord()
+
+STATIC int GetImmAdr(int w) { /* Get an immediate address value */
+ if (!w) return GetImmByte();
+ else if (!adrSize) return GetImmWord();
+ return (int)GetImmDWord();
+} /* GetImmAdr */
+
+STATIC int GetImmData(int w) { /* Get an immediate data value */
+ if (!w) return GetImmByte();
+ else if (!dataSize) return GetImmWord();
+ return (int)GetImmDWord();
+} /* GetImmData */
+
+/************************* Helper Functions **************************/
+
+void PopSeg(int seg) {
+ gpSafe = 1;
+ gpRegs = seg;
+ gpStack = 1;
+} /* PopSeg */
+
+enum {
+ RegAX, RegCX, RegDX, RegBX, RegSP, RegBP, RegSI, RegDI
+};
+
+ /* Based on the second byte of opcode, width flag, adrSize and dataSize, */
+ /* determine the disassembly of the current instruction, and what */
+ /* memory address was referenced */
+ /* needinfo indicates that we need a size override on a memory operand */
+ /* for example, "mov [bx], ax" is obviously a 16 bit move, while */
+ /* "mov [bx], 0" could be 8, 16, or 32 bit. We add the proper */
+ /* "mov word ptr [bx], 0" information. */
+ /* The 'mem' parameter indicates the kind of operation, Read, Write, RMW */
+
+ /* don't bother trying to understand this code without an Intel manual */
+ /* and assembler nearby. :-) */
+STATIC void ModRMGeneral(byte op) {
+ int mod = op >> 6;
+ int rm = op & 7;
+
+ if (adrSize) { /* do 32 bit addressing */
+ if (mod == 3) return; /*XReg(w, rm); /* register operand */
+
+ if (rm == 4) /* [esp+?] is special S-I-B style */
+ GetByte();
+
+ if (mod==1) GetImmAdr(0);
+ else if (mod == 2) GetImmAdr(1);
+ } else { /* do 16 bit addressing */
+ if (mod == 3) return;/* XReg(w, rm); /* register operand */
+ if (mod == 0 && rm == 6) /* [bp] becomes [mem16] */
+ GetImmAdr(1);
+ else if (mod) /* (mod3 already returned) */
+ GetImmAdr(mod-1); /* mod==1 is byte, mod==2 is (d)word */
+ }
+} /* ModRMGeneral */
+
+#define ModRMInfo(op, w, mem) ModRMGeneral(op)
+#define ModRM(op, w, mem) ModRMGeneral(op)
+
+STATIC void F(void) {
+ ModRMGeneral(GetByte());
+ gpSafe = 1;
+} /* F */
+
+#define ModRMF(m) F()
+
+ /* Disassemble the 386 instructions whose first opcode is 0x0f */
+ /* Sorry, but this is just too ugly to comment */
+STATIC void DisAsmF(void) {
+ byte op0;
+
+ op0 = GetByte();
+ switch (op0 >> 4) { /* switch on top 4 bits of opcode */
+ case 0:
+#if 0
+ switch (op0 & 0xf) {
+ case 0: /* grp6 - scary */
+ case 1: /* grp7 - scary */
+ case 2: /* lar */
+ case 3: /* lsl */
+ default:
+ }
+#endif
+ break;
+
+ case 9: /* byte set on condition */
+ ModRMF(memWrite);
+ return;
+
+ case 0xa:
+ switch (op0 & 0xf) {
+ case 0: return; /* "push fs"; */
+ case 1:
+ PopSeg(segFS);
+ return; /* "pop fs"; */
+ case 3: case 0xb: /* bts, bt */
+ ModRMF(memRMW);
+ return;
+
+ case 4: case 0xc: /* shrd, shld */
+ ModRMF(memRMW);
+ GetImmData(0);
+ return;
+ case 5: case 0xd: /* shrd, shld */
+ ModRMF(memRMW);
+ return;
+ case 6: /* cmpxchg */
+ gpSafe = 1;
+ ModRM(GetByte(), 0, memRMW);
+ return;
+ case 7: /* cmpxchg */
+ ModRMF(memRMW);
+ return;
+ case 8: return; /*"push gs";*/
+ case 9:
+ PopSeg(segGS);
+ return; /*"pop gs";*/
+ case 0xf: /* imul */
+ ModRMF(memRead);
+ return;
+ }
+ break;
+
+ case 0xb:
+ switch (op0 & 0xf) {
+ case 2: case 4: case 5:
+ if (op0 & 2) {
+ /* "lss"*/
+ } else { /* : (op0 &1) ? "lgs" : "lfs"; */
+ ModRMF(memRead);
+ }
+ return;
+ case 3: case 0xb: /* btc, btr */
+ ModRMF(memRMW);
+ return;
+ case 6: case 7: case 0xe: case 0xf: /* movsx, movzx */
+ dataSize = 0;
+ ModRMF(memRead);
+ return;
+ case 0xa:
+ ModRMF(memRMW);
+ GetImmData(0);
+ return;
+ case 0xc: case 0xd: /* bsr, bsf */
+ ModRMF(memRead);
+ return;
+ }
+ break;
+
+ case 0xc:
+ if (op0 > 0xc7) { /* bswap */
+ return;
+ }
+ if (op0 < 0xc2) { /* xadd */
+ ModRMF(memRMW);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+} /* DisAsmF */
+
+int IsPrefix(byte op0) {
+ switch (op0) { /* check for prefix bytes */
+
+#define CSEG 0x2e
+#define DSEG 0x3e
+#define ESEG 0x26
+#define SSEG 0x36
+#define FSEG 0x64
+#define GSEG 0x65
+#define REP 0xf3
+#define REPNE 0xf2
+#define DATA32 0x66
+#define ADR32 0x67
+
+ case CSEG: SetMemSeg(memCS); break;
+ case DSEG: SetMemSeg(memDS); break;
+ case ESEG: SetMemSeg(memES); break;
+ case SSEG: SetMemSeg(memSS); break;
+ case FSEG: SetMemSeg(memFS); break;
+ case GSEG: SetMemSeg(memGS); break;
+ case REP: gpRegs |= strCX; break;
+ case REPNE: gpRegs |= strCX; break;
+ case ADR32: adrSize = !adrSize; break;
+ case DATA32:dataSize = !dataSize; break;
+ default:
+ return 0;
+ }
+ return 1;
+} /* IsPrefix */
+
+ /* like, call this with a pointer to the instruction, it will return */
+ /* the opcode bytes used in *len, and a pointer to the disassembled insn */
+int near DisAsm86(byte far *codeParm) {
+ byte far *oldcode;
+ byte op0, op1;
+ byte opclass;
+ static int init =0;
+
+ if (!init) {
+ InitDisAsm86();
+ init = 1;
+ }
+ adrSize = dataSize = segSize;
+ gpSafe = gpRegs = gpStack = 0;
+ code = oldcode = codeParm;
+ do {
+ op0 = GetByte();
+ } while (IsPrefix(op0));
+ opclass = lookup[op0];
+
+ StMemOp(memNOP);
+
+ if (opclass >= simpleBase) { /* is it special */
+ if (opclass >= stringOpBase) { /* string operations? */
+ char cmd;
+
+ opclass -= stringOpBase;
+ cmd = stringOp[opclass].flag;
+ if (cmd & STR_S) {
+ gpRegs |= strSI;
+ StMemOp(memRead);
+ /* DS already set */
+ SetMemLinear(memReg);
+ if (cmd & STR_D) {
+ gpRegs |= strDI;
+ StMemOp2(cmd & STR_D_Read ? memRead : memWrite);
+ SetMemSeg2(memES);
+ SetMemLinear2(memReg);
+ /* memDouble = 1; */
+ }
+ } else {
+ gpRegs |= strDI;
+ StMemOp(cmd & STR_D_Read ? memRead : memWrite);
+ SetMemSeg(memES);
+ SetMemLinear(memReg);
+ }
+
+ if (op0 & 1) {
+ if (dataSize) SetMemSize(4);
+ else SetMemSize(2);
+ } else SetMemSize(1);
+
+ } else if (opclass >= dSimpleBase) {
+ opclass -= dSimpleBase;
+ } else {
+ if (op0 == 7)
+ PopSeg(segES); /* pop ES */
+ else if (op0 == 0x1f)
+ PopSeg(segDS); /* pop DS */
+ }
+ goto DisAsmDone;
+ }
+
+ if (op0 == 0x0f) { /* is it an extended opcode? */
+ DisAsmF();
+ goto DisAsmDone;
+ }
+
+ switch (ops[opclass].operand) {
+ case BWI: /* byte/word/immediate */
+ gpSafe = 1;
+ if (op0 & 4) {
+ GetImmData(op0&1);
+ } else {
+ int i;
+ op1 = GetByte();
+ /* if ((op0 & 0xf8) == 0x38) i = memRead;
+ else if ((op0 & 0xfe) == 0x88) i = memWrite;
+ else Read_RMW(op0 & 2); */
+ ModRM(op1, op0&1, i);
+ }
+ break;
+
+ case Grp1: /* group 1 instructions */
+ gpSafe = 1;
+ op1 = GetByte();
+ ModRMInfo(op1, op0&1, Mid(op1) == 7 ? memRead : memRMW);
+ GetImmData((op0&3)==1);
+ break;
+
+ case Grp2: /* group 2 instructions */
+ gpSafe = 1;
+ op1 = GetByte();
+ ModRMInfo(op1, op0&1, memRMW);
+ if (!(op0 & 0x10)) GetImmData(0);
+ break;
+
+ case Grp3: /* group 3 instructions */
+ gpSafe = 1;
+ op1 = GetByte();
+ ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) <2 || Mid(op1) >3));
+ if (Mid(op1) < 2) GetImmData(op0&1);
+ break;
+
+ case Grp4: /* group 4 instructions */
+ op1 = GetByte();
+ if (Mid(op1) > 1) ;
+ else {
+ ModRMInfo(op1, op0&1, memRMW);
+ gpSafe = 1;
+ }
+ break;
+
+ case Grp5: /* group 5 instructions */
+ op1 = GetByte();
+ if (Mid(op1) < 3) {
+ gpSafe = 1;
+ if (Mid(op1) == 2) {
+ gpStack = -1 << dataSize;
+ }
+ }
+ ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) >= 2));
+ break;
+
+ case SMOV: /* segment move */
+ gpSafe = 1;
+ op1 = GetByte();
+ dataSize = 0;
+ ModRM(op1, 1, Read_RMW(op0&2));
+ if (op0 & 2) { /* if moving _to_ SREG */
+ switch (Mid(op1)) {
+ case 0: gpRegs = segES; break;
+ case 3: gpRegs = segDS; break;
+ case 4: gpRegs = segFS; break;
+ case 5: gpRegs = segGS; break;
+ default: gpSafe = 0;
+ }
+ }
+ break;
+
+ case IMOV: /* immediate move to reg/mem */
+ gpSafe = 1;
+ op1 = GetByte();
+ ModRMInfo(op1, op0&1, memWrite);
+ GetImmData(op0&1);
+ break;
+
+ case MOVABS: /* move between accum and abs mem address */
+ gpSafe = 1;
+ GetImmAdr(1);
+ StMemOp(op0&2 ? memWrite : memRead);
+ break;
+
+ case POPMEM:
+ gpSafe = 1;
+ gpStack = 1 << dataSize;
+ ModRMInfo(GetByte(), 1, memWrite);
+ break;
+
+ case RRM: /* test and xchg */
+ gpSafe = 1;
+ op1 = GetByte();
+ ModRM(op1, op0&1, memRMW);
+ break;
+
+ case RRMW: /* bound, les, lds */
+ op1 = GetByte();
+ switch (op0) {
+ case 0xc4: /* les reg, [mem] */
+ gpRegs = segES;
+ gpSafe = 1;
+ break;
+ case 0xc5: /* lds reg, [mem] */
+ gpRegs = segDS;
+ gpSafe = 1;
+ break;
+ }
+ ModRM(op1, 1, memRead);
+ break;
+
+ case XLAT:
+ gpSafe = 1;
+ StMemOp(memRead);
+ break;
+
+ default: ;
+ }
+DisAsmDone:
+ return (int)(code - oldcode);
+} /* DisAsm86 */
+
+#endif /* SHERLOCK */
diff --git a/private/mvdm/wow16/kernel31/diskio.asm b/private/mvdm/wow16/kernel31/diskio.asm
new file mode 100644
index 000000000..c15a41208
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/diskio.asm
@@ -0,0 +1,126 @@
+ TITLE DISKIO
+
+include kernel.inc
+
+externFP Int21Handler
+
+sBegin CODE
+
+ASSUMES CS,CODE
+
+externNP MyAnsiToOem
+
+cProc I_lopen,<PUBLIC,FAR>
+; parmD lpFilename
+; parmW mode
+; localV OemBuffer,128
+cBegin nogen
+ mov ch,3Dh ; Open File
+ jmps loccommon
+cEnd nogen
+
+cProc I_lcreat,<PUBLIC,FAR>
+; parmD lpFilename
+; parmW attributes
+; localV OemBuffer,128
+cBegin nogen
+ mov ch,3Ch ; Create File
+cEnd nogen
+
+ errn$ loccommon
+
+cProc loccommon,<PUBLIC,FAR>
+ parmD lpFilename
+ parmW attributes
+ localV OemBuffer,128
+cBegin
+
+; Common code for open and creat functions. CH = function code
+
+ push cx
+ lea bx, OemBuffer
+ cCall MyAnsiToOem,<lpFilename,ss,bx>
+ pop cx
+ mov cl, byte ptr attributes
+ mov ax,cx
+ xor ch,ch
+ smov ds, ss
+ lea dx, OemBuffer
+ DOSCALL
+ jnc lopen_ok
+ mov ax,-1
+lopen_ok:
+cEnd
+
+
+cProc I_lclose,<PUBLIC,FAR>
+; parmW fd
+cBegin nogen
+ mov bx,sp
+ mov bx,ss:[bx+4]
+ mov ah,3Eh ; DOS file close function
+ DOSCALL
+ mov ax,-1
+ jc lclose_end
+ inc ax
+lclose_end:
+ ret 2
+cEnd nogen
+
+cProc I_llseek,<PUBLIC,FAR>
+; parmW fh
+; parmD fileOffset
+; parmW mode
+cBegin nogen
+ mov bx,sp
+ mov dx,ss:[bx+6]
+ mov cx,ss:[bx+8]
+ mov ax,ss:[bx+4]
+ mov bx,ss:[bx+10]
+ mov ah,42h
+ DOSCALL
+ jnc lseek_ok
+ mov ax,-1
+ cwd ; must return a long
+lseek_ok:
+ ret 8
+cEnd nogen
+
+cProc I_lwrite,<PUBLIC,FAR>
+; parmW fh
+; parmD lpBuf
+; parmW bufsize
+cBegin nogen
+ mov cl,40h
+ jmp short _lrw
+cEnd nogen
+
+cProc I_lread,<PUBLIC,FAR>
+; parmW fh
+; parmD lpBuf
+; parmW bufsize
+cBegin nogen
+ mov cl,3fh
+ errn$ _lrw
+cEnd nogen
+
+; Common code for read and write functions. CL = function code
+cProc _lrw,<PUBLIC,FAR>
+cBegin nogen
+ mov bx,sp
+ push ds
+ mov ah,cl ; read or write operation
+ mov cx,ss:[bx+4] ; bufSize
+ lds dx,DWORD PTR ss:[bx+6] ; lpBuf
+ mov bx,ss:[bx+10] ; fh
+ DOSCALL
+ pop ds
+ jnc lwrite_ok
+ mov ax,-1
+lwrite_ok:
+ ret 8
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/dosinit.asm b/private/mvdm/wow16/kernel31/dosinit.asm
new file mode 100644
index 000000000..d303c73e6
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/dosinit.asm
@@ -0,0 +1,1363 @@
+title DOSINIT - Initialize dos specific static data.
+
+.xlist
+include kernel.inc
+include pdb.inc
+.list
+
+externFP GetModuleHandle
+externFP GetProcAddress
+externFP Int21Handler
+externFP GlobalDOSAlloc
+externFP GetFreeSpace
+ifdef WOW
+externNP ExitKernel
+endif
+
+DataBegin
+
+externB graphics
+externB Kernel_flags
+externB DOS_version
+externB DOS_revision
+externB KeyInfo
+externB fFarEast
+ifdef DBCS
+externB fDBCSLeadTable
+endif
+externB fBreak
+externB fNovell
+externB CurDOSDrive
+externB DOSDrives
+externW cur_dos_PDB
+externW Win_PDB
+externW f8087
+externW FileEntrySize
+externW topPDB
+externW headPDB
+externW hExeHead
+externW MyCSDS
+externW hGDI
+externW hUser
+externD pTimerProc
+externD pSftLink
+externD pFileTable
+externD myInt2F
+externD pMBoxProc
+externD pSysProc
+externD pGetFreeSystemResources
+ifdef JAPAN
+externD pJpnSysProc
+endif
+externD pKeyProc
+externD pKeyProc1
+externD pSErrProc
+externD pDisableProc
+externD pExitProc
+
+externD pMouseTermProc
+externD pKeyboardTermProc
+externD pKeyboardSysReq
+externD pSystemTermProc
+externD pDisplayCritSec
+externD pUserInitDone
+externD pPostMessage
+externD pSignalProc
+externD pIsUserIdle
+externD pUserGetFocus
+externD pUserGetWinTask
+externD pUserIsWindow
+externD curDTA
+externD InDOS
+
+if ROM
+externD pYieldProc
+externD pStringFunc
+externD prevInt21Proc
+externD prevInt00proc
+externD prevInt24Proc
+externD prevInt2FProc
+externD prevInt02proc
+externD prevInt04proc
+externD prevInt06proc
+externD prevInt07proc
+externD prevInt3Eproc
+externD prevInt75proc
+endif
+
+ifdef JAPAN
+; Need this variable in order to make Kernel to hardware independent
+externW WinFlags
+endif
+
+DataEnd
+
+DataBegin INIT
+
+; Win.com does version check, so this does not need to be internationalized.
+
+externB szDosVer
+;msg0 DB 'Incorrect DOS version: DOS 3.1 or greater required.',13,10,'$'
+
+handles dw 10 dup(0)
+
+find_string db 'CON '
+name_string db 'CON',0
+
+DataEnd INIT
+
+
+sBegin CODE
+assumes cs,CODE
+
+ife ROM
+externD pYieldProc
+externD pStringFunc
+externD prevInt21Proc
+externD prevInt00proc
+externD prevInt24Proc
+externD prevInt2FProc
+externD prevInt02proc
+externD prevInt04proc
+externD prevInt06proc
+externD prevInt07proc
+externD prevInt3Eproc
+externD prevInt75proc
+ifdef WOW
+externD prevInt31proc
+endif
+endif
+
+sEnd CODE
+
+externNP DebugSysReq
+externNP SetOwner
+
+;----------------------------------------------------------------------------;
+; define any constans used in the file. ;
+;----------------------------------------------------------------------------;
+
+SFT_GROW_LIM_IN_64K equ 8 ;if memory < 8*64k, grow to 100 handles
+ ;else grow upto 127 handles
+SFT_HIGH_LIM equ 127 ;grow upto 127 when enough memory
+SFT_LOW_LIM equ 100 ;grow upto 100 when low in memory
+
+
+;----------------------------------------------------------------------------;
+; define any macros used in the file. ;
+;----------------------------------------------------------------------------;
+
+SaveVec MACRO vec
+ mov ax,35&vec&h
+ pushf
+ call prevInt21proc
+if ROM
+ mov prevInt&vec&proc.off,bx
+ mov prevInt&vec&proc.sel,es
+else
+ mov ax,codeOffset prevInt&vec&proc
+ SetKernelCSDword ax,es,bx
+endif
+ ENDM
+
+;----------------------------------------------------------------------------;
+
+DataBegin INIT
+
+sysmodstr DB 'SYSTEM',0
+keymodstr DB 'KEYBOARD',0
+displaymodstr DB 'DISPLAY',0
+mousemodstr DB 'MOUSE',0
+gdimodstr DB 'GDI',0
+usermodstr DB 'USER',0
+
+inqprocstr label byte
+msgprocstr label byte ; MessageBox in USER
+sysprocstr DB '#1',0 ; sysprocstr = InquireSystem
+timerprocstr DB '#2',0 ; timerprocstr = CreateSystemTimer
+keydisstr label byte ; keydisstr = DisableKeyboard
+mousedisstr DB '#3',0 ; mouseprocstr = DisableMouse
+disprocstr DB '#4',0 ; DisableOEMLayer in USER
+extprocstr label byte ; ExitWindows in USER
+coprocessor DB '#7',0 ; Get80x87SaveSize in system
+kbdfocus DB '#23',0 ; GetFocus in USER
+wintask DB '#224',0 ; GetWindowTask in USER
+iswindow DB '#47',0 ; IsWindow in USER
+signalproc DB '#314',0 ; SignalProc in user
+isuseridle DB '#333',0 ; IsUserIdle in user
+getfreesysrsc DB '#284',0 ; GetFreeSystemResources in user
+stringfunc DB '#470',0 ; StringFunc in User.
+
+sysdisstr DB '#5',0 ; sysdisstr = DisableSystemTimers
+pmprocstr DB '#110',0 ; pmprocstr = PostMessage
+keysysreq DB '#136',0 ; keysysreq = EnableKBSysReq
+syserrorstr DB '#320',0 ; syserrorstr = SysErrorBox in USER
+yldprocstr DB '#332',0 ; yldprocstr = UserYield in USER
+udnprocstr DB '#400',0 ; tell user that initialization done
+displaycrit DB '#500',0 ; win386 interaction craziness
+ifdef JAPAN
+jpnsysprocstr db 'JapanInquireSystem',0 ; Kernel.JapanInquireSystem entry
+endif
+
+DataEnd INIT
+
+sBegin INITCODE
+assumes CS,CODE
+;-----------------------------------------------------------------------;
+; InitFwdRef ;
+; ;
+; Initializes the far call pointers to SYSTEM, USER, KEYBOARD. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Jan 06, 1987 04:21:13p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitFwdRef,<PUBLIC,NEAR>,<si,di>
+cBegin
+ SetKernelDS
+
+ mov ax,352Fh
+ pushf
+ call prevInt21proc
+ mov myInt2F.sel,es
+ mov myInt2F.off,bx
+
+; Save current Int 00h, 21h, 24h, and 2Fh.
+
+ SaveVec 00
+;;; SaveVec 21
+ SaveVec 24
+
+; Get address of procedures in USER and SYSTEM modules that we will need.
+
+ regptr pStr,ds,bx
+
+ mov bx,dataOffset sysmodstr
+ cCall GetModuleHandle,<pStr>
+ mov si,ax
+
+ mov bx,dataOffset sysprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov pSysProc.off,ax
+ mov pSysProc.sel,dx
+
+ifdef JAPAN
+ mov bx,dataOffset jpnsysprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov pJpnSysProc.off,ax
+ mov pJpnSysProc.sel,dx
+endif
+
+ mov bx,codeOffset ifr4
+ push cs ; push return address
+ push bx
+ mov bx,dataOffset coprocessor
+ cCall GetProcAddress,<si,pStr>
+ push dx
+ push ax ; push address to call
+ ret_far ; call 8087 info
+ifr4:
+ mov f8087,ax
+ifdef JAPAN
+;;; int 1 ; debugging purpose only
+ ; Since Japanese OEMs have non-IBM clone machines, Windows
+ ; cannot use standard Bios interrupt to get system informations.
+ ; In BootStrap (see LDBOOT.ASM), it uses Int 11h to obtain MCP's
+ ; availability. However, Windows cannot use Int 11h (becase of
+ ; IBM-dependant), MSKK has removed Int 11h from BootStrap.
+ ;
+ ; At this point, AX register contains MCP's availability, i.e.
+ ; if AX has value zero, no MCP is installd. if AX has value except
+ ; zero, MCP is installed. The following codes will update WinFlags
+ ; and its exported variables by using AX register.
+
+ test ax,ax ; MCP is installed?
+ jz @F ; jump if not
+ mov ax,WF1_80x87 shl 8 ; set MCP present bit
+@@:
+ or WinFlags,ax ; update internal variable
+ xor ax,ax
+ mov dx,178 ; #178 is __WinFlags location for public use
+ cCall GetProcAddress,<hExeHead,ax,dx>
+ mov ax,WinFlags
+ mov es:[bx],ax
+endif
+
+ mov bx,dataOffset timerprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov pTimerProc.off,ax
+ mov pTimerProc.sel,dx
+
+ mov bx,dataOffset sysdisstr
+ cCall GetProcAddress,<si,pStr>
+ mov pSystemTermProc.off,ax
+ mov pSystemTermProc.sel,dx
+
+ cmp graphics,0 ; Graphics?
+ jne grp
+ jmp nographics
+
+grp:
+ifndef WOW
+ mov bx,dataOffset displaymodstr ; display stuff
+ cCall GetModuleHandle,<pStr>
+ mov bx,dataOffset displaycrit
+
+ cCall GetProcAddress,<ax,pStr>
+ mov pDisplayCritSec.off,ax
+ mov pDisplayCritSec.sel,dx
+
+ mov bx,dataOffset mousemodstr ; mouse stuff
+ cCall GetModuleHandle,<pStr>
+ mov si,ax
+
+ mov bx,dataOffset mousedisstr
+ cCall GetProcAddress,<si,pStr>
+ mov pMouseTermProc.off,ax
+ mov pMouseTermProc.sel,dx
+endif
+ mov bx,dataOffset gdimodstr
+ cCall GetModuleHandle,<pStr>
+ mov hGDI,ax
+
+ mov bx,dataOffset usermodstr ; user stuff
+ cCall GetModuleHandle,<pStr>
+ mov hUser,ax
+ mov si,ax
+
+ mov bx,dataOffset msgprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov pMBoxProc.off,ax
+ mov pMBoxProc.sel,dx
+
+ mov bx,dataOffset syserrorstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pSErrProc[0],ax
+ mov word ptr pSErrProc[2],dx
+
+ mov bx,dataOffset extprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pExitProc[0],ax
+ mov word ptr pExitProc[2],dx
+
+ mov bx,dataOffset disprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pDisableProc[0],ax
+ mov word ptr pDisableProc[2],dx
+
+ mov bx,dataOffset yldprocstr
+ cCall GetProcAddress,<si,pStr>
+ife ROM
+ mov bx, codeOFFSET pYieldProc
+ SetKernelCSDword bx,dx,ax
+else
+ mov pYieldProc.off,ax
+ mov pYieldProc.sel,dx
+endif
+
+ mov bx,dataOffset udnprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pUserInitDone[0],ax
+ mov word ptr pUserInitDone[2],dx
+
+ mov bx,dataOffset pmprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pPostMessage[0],ax
+ mov word ptr pPostMessage[2],dx
+
+ mov bx,dataOffset signalproc
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pSignalProc[0],ax
+ mov word ptr pSignalProc[2],dx
+
+ ; These are never called in WOW
+
+ifndef WOW
+ mov bx,dataOffset isuseridle
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pIsUserIdle[0],ax
+ mov word ptr pIsUserIdle[2],dx
+
+ mov bx,dataOffset getfreesysrsc
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pGetFreeSystemResources[0],ax
+ mov word ptr pGetFreeSystemResources[2],dx
+endif
+ mov bx,dataOffset stringfunc
+ cCall GetProcAddress,<si,pStr>
+if ROM
+ mov pStringFunc.off,ax
+ mov pStringFunc.sel,dx
+else
+ mov bx, codeOFFSET pStringFunc
+ SetKernelCSDword bx,dx,ax
+endif
+
+ mov bx,dataOffset kbdfocus
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pUserGetFocus[0],ax
+ mov word ptr pUserGetFocus[2],dx
+
+ mov bx,dataOffset wintask
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pUserGetWinTask[0],ax
+ mov word ptr pUserGetWinTask[2],dx
+
+ mov bx,dataOffset iswindow
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr pUserIsWindow[0],ax
+ mov word ptr pUserISWindow[2],dx
+
+ mov bx,dataOffset keymodstr
+ cCall GetModuleHandle,<pStr>
+ mov si,ax
+
+ mov bx,dataOffset keydisstr
+ cCall GetProcAddress,<si,pStr>
+ mov word ptr [pKeyboardTermProc],ax
+ mov word ptr [pKeyboardTermProc+2],dx
+
+ mov bx,dataOffset keysysreq
+ cCall GetProcAddress,<si,pStr>
+ mov pKeyboardSysReq.off,ax
+ mov pKeyboardSysReq.sel,dx
+
+ mov ax,4
+ cCall pKeyboardSysReq,<ax> ; tell kbd to pass SysReq to CVWBreak
+
+ mov bx,dataOffset KeyInfo
+ push ds
+ push bx ; push argument to keyboard.inquire
+ mov bx,codeOffset ifr1
+ push cs ; push return address
+ push bx
+ mov bx,dataOffset inqprocstr
+ cCall GetProcAddress,<si,pStr>
+ push dx
+ push ax ; push address to call
+ ret_far ; call keyboard inquire
+ifr1:
+ifndef JAPAN
+; This is DBCS kernel. So do not get information from keyboard
+; driver. This K/B spec is old one and should be ignored.
+; We use DOS DBCS vector instead of K/B table.
+; 071191 Yukini
+;
+;ifndef KOREA ;Korea might want to remove this too.
+
+;!!!! Note to Taiwan developers !!!
+; The following code fragment is necessary for those countries
+; who want to run DBCS Windows on top of SBCS MS-DOS.
+; For example, Taiwan might need this feature.
+; Japan and Korea are safe to remove this fragment as Japanese
+; and Hangeul Windows all assume DBCS MS-DOS.
+
+ mov si,dataOffset KeyInfo+KbRanges
+ lodsw
+ cmp al,ah
+ jbe ifr2
+ lodsw
+ cmp al,ah
+ ja ifr3
+ifr2: inc fFarEast
+ifdef DBCS
+;
+; setup DBCS lead byte flag table after keyboard driver is loaded
+;
+ mov di, dataOffset fDBCSLeadTable ; clear table before begin...
+ mov cx, 128
+ xor ax, ax
+ push es
+ push ds
+ pop es
+ cld
+ rep stosw
+ pop es
+ mov si, dataOffset KeyInfo+KbRanges
+ mov cx, 2
+idr1:
+ lodsw ; fetch a DBCS lead byte range
+ cmp al, ah ; end of range info?
+ ja idr3 ; jump if so.
+ call SetDBCSVector
+ loop idr1 ; try another range
+idr3:
+endif ;DBCS
+endif ;NOT JAPAN
+ jmps ifr3
+
+;
+; Substitute dummy procs if user/gdi/keyboard/display not present
+;
+if 0
+externFP <DummyKeyboardOEMToAnsi>
+endif
+externFP <OldYield>
+nographics:
+ife ROM
+ push di
+ push bx
+if 0
+ mov bx, codeOffset pKeyProc
+ mov di, codeOffset DummyKeyboardOEMToAnsi
+; SetKernelCSDword bx,cs,di
+endif
+ mov bx, codeOffset pYieldProc
+ mov di, codeOffset OldYield
+ SetKernelCSDword bx,cs,di
+ pop bx
+ pop di
+else
+ mov pYieldProc.off,codeOffset OldYield
+ mov pYieldProc.sel,cs
+endif
+ifr3:
+ call DebugSysReq
+cEnd
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+; InitDosVarP ;
+; ;
+; Records for future use various DOS variables. ;
+; ;
+; Arguments: ;
+; ES = PDB of Kernel ;
+; ;
+; Returns: ;
+; AX != 0 if successful ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:50:20 -by- David N. Weise [davidw] ;
+; Removed more dicking around by removing WinOldApp support. ;
+; ;
+; Tue Feb 03, 1987 10:45:31p -by- David N. Weise [davidw] ;
+; Removed most of the dicking around the inside of DOS for variable ;
+; locations. Variables are now got and set the right way: through DOS ;
+; calls. This should allow Windows to run in the DOS 5 compatibility ;
+; box as well as under future versions of real mode DOS. ;
+; ;
+; Tue Jan 06, 1987 04:33:16p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitDosVarP,<PUBLIC,NEAR>,<bx,cx,dx,si,di,es>
+cBegin
+
+ ReSetKernelDS
+
+; Save our PDB pointer in the code segment
+
+ mov ax,es
+ mov topPDB,ax
+ mov headPDB,ax
+ mov es:[PDB_Chain],0 ; the buck stops here
+
+; record current PDB
+
+ mov cur_dos_PDB,ax
+ mov Win_PDB,ax
+
+; record current DTA
+
+ mov curDTA.sel,ax
+ mov curDTA.off,80h
+
+; disable ^C checking as fast as possible
+
+ mov ax,3300h ; remember ^C state
+ int 21h
+ mov fBreak,dl
+
+ mov ax,3301h ; disable ^C checking
+ mov dl,0
+ int 21h
+
+; record in_dos pointer
+
+ mov ah,34h
+ int 21h
+ mov InDOS.sel,es
+ mov InDOS.off,bx
+
+ mov ah, 19h
+ int 21h
+ mov CurDOSDrive, al ; Initialize current drive tracking
+ mov dl, al
+ mov ah, 0Eh
+ int 21h
+ mov DOSDrives, al ; For returning from Select Disk calls
+
+; To avoid beaucoup thought, let's init prevInt21Proc right now!
+;
+; This was done as a last minute hack to 2.10. I forget the
+; motivation for it, other than it fixed a couple of bugs
+; having to do with error recovery. It did introduce one
+; bug with one error path having to do with Iris, but I don't
+; remember that either. Interested parties can grep for
+; prevInt21Proc and think hard and long.
+;
+; Since we now call through prevInt21Proc in many places rather
+; than use int 21h (saves ring transitions), this had better stay here!
+; See the DOSCALL macro.
+;
+
+ mov ax, 3521h
+ int 21h
+if ROM
+ mov prevInt21Proc.off,bx
+ mov prevInt21Proc.sel,es
+else
+ mov ax,codeOffset prevInt21Proc
+ SetKernelCSDword ax,es,bx
+endif
+
+ifdef WOW
+;
+; We save the int 31 vector here to avoid emulation of int 31 instructions.
+; THIS WILL BREAK INT 31 HOOKERS. Currently we don't beleive that any
+; windows apps hook int 31.
+ mov ax, 3531h
+ int 21h
+
+ mov ax,codeOffset prevInt31Proc
+ SetKernelCSDword ax,es,bx
+endif
+
+ ; moved here 8 feb 1990 from InitFwdRef, no good reason for
+ ; leaving 0 behind, except that's the way we did it in 2.x.
+
+; Save current Int 02h, 04h, 06h, 07h, 3Eh, and 75h.
+
+ SaveVec 02
+ SaveVec 04
+ SaveVec 06
+ SaveVec 07
+ SaveVec 3E
+ SaveVec 75
+
+; get the 2F
+ ; this slime is an old novell hack
+ SaveVec 2F ; and can probably be removed!
+
+; See if we are under NOVELL
+
+ mov ah, 0DCh
+ int 21h
+ mov fNovell, al
+
+; Get MSDOS version number
+
+ mov ah,30h
+ int 21h
+ifdef TAKEN_OUT_FOR_NT
+ cmp al,10 ; is it the DOS 5 compatibility box?
+ jae got_ver
+ cmp al,4 ; > 4.xx?
+ jae got_ver
+ cmp al,3 ; < 3.0 ?
+ jb dos_version_bad
+ cmp ah,10
+ jae got_ver ; < 3.1 ?
+dos_version_bad:
+ jmps fail
+endif
+
+got_ver:
+
+ mov DOS_version,al
+ mov DOS_revision,ah
+
+; Remember where the end of the SFT table is, so if we decide to
+; add file handles we can remove them on exit
+;
+; DOS 3.10 =< version =< DOS 3.21 => FileEntrySize = 53
+; DOS 3.21 < version < DOS 4.00 => unknown
+; DOS 4.00 =< version =< DOS 4.10 => FileEntrySize = 58
+; DOS 4.10 < version => unknown
+; version = DOS 10 => FileEntrySize = 00
+
+; OS|2
+ xor bx,bx
+ifdef TAKEN_OUT_FOR_NT
+ cmp al,10 ; OS|2 can't dick with SFTs
+ jae have_file_size
+
+; DOS 3
+ cmp al,3
+ ja DOS_4
+
+ mov bx,56
+ cmp ah,0
+ jz have_file_size
+ mov bx,53
+ cmp ah,31
+ jbe have_file_size
+ jmps unknown_DOS
+
+DOS_4: ; REMOVED FOLLOWING! DOS 3.4 will be
+ ; called 4.0 so we don't know the size!
+;;; mov bx,58
+;;; cmp ah,1 ; DOS 4
+;;; jbe have_file_size
+
+unknown_DOS:
+ push ax
+ call GetFileSize
+ mov bx,ax
+ pop ax
+ cmp bx,-1
+ jz fail
+endif
+
+have_file_size:
+ mov FileEntrySize,bx
+
+ mov al,10 ; don't want to dick with SFT's!
+
+ifdef DBCS
+; During boot, use DOS DBCS Vector table for file handling. Under DOS 3.2,
+; use Hard Coded Vector table because they don't have Vector table.
+ifdef TAKEN_OUT_FOR_NT
+ cmp DOS_version,3 ; DOS 3.xx?
+ jnz dbDOS_1
+ cmp DOS_revision,20 ; DOS 3.20?
+ jc dbDOS_HC ; use hard coded if below DOS 3.20
+ jmps dbDOS_VC
+
+fail:
+ jmps fail_1
+
+dbDOS_1:
+ cmp DOS_version,6 ; DOS 4.xx or 5.xx?
+ jnc dbDOS_HC ; jump if not - Hard coded
+dbDOS_VC:
+ push ds
+ mov ax, 6300h
+ int 21h ; get DOS DBCS Vector
+ jnc dbDOS_2 ; jump if OK
+ pop ds
+ jmps dbDOS_HC ; use Hard coded if failed
+dbDOS_2:
+ push ds
+ pop es ; ES:SI -> points vector table
+ pop ds
+dbDOS_3:
+ mov ax,es:[si]
+ test ax,ax ; end of table?
+ jz dbDOS_x ; jump if so
+ call SetDBCSVector
+ add si,2
+ jmp dbDOS_3
+endif
+dbDOS_HC:
+ mov ax,3800h ; get DOS country code
+ sub sp, 40 ; enough space for country data
+ mov dx, sp
+ push ds
+ push ss
+ pop ds
+ int 21h
+ pop ds
+ add sp, 40
+ cmp bx,81 ; JAPAN?
+ jnz dbDOS_NoJapan
+ mov ax,9f81h ; set DBCS Range 0x81-0x9f
+ call SetDBCSVector
+ mov ax,0fce0h ; set DBCS Range 0xe0-0xfc
+ call SetDBCSVector
+ jmps dbDOS_x
+dbDOS_NoJapan:
+ cmp bx,82 ; KOREA?
+ jnz dbDOS_NoKorea
+ mov ax,0fd81h ; set DBCS Range 0x81-0xfd
+ call SetDBCSVector
+ jmps dbDOS_x
+dbDOS_NoKorea:
+ cmp bx,88 ; TAIWAN?
+ jnz dbDOS_x ; jump if unknown country code
+;TCA code range
+;; mov ax,0fd81h ; set DBCS Range 0x81-0xfd
+;Big-5 code range
+ mov ax,0fe81h
+ call SetDBCSVector
+dbDOS_x:
+ mov ax, -1
+ jmps initdone
+fail_1:
+else
+ mov ax,-1
+ jmps initdone
+fail:
+endif
+ mov dx,dataOffset szDosVer ;msg0
+ mov ah,09
+ int 21h
+ xor ax,ax
+initdone:
+cEnd
+
+ifdef DBCS
+;-----------------------------------------------------------------------;
+; SetDBCSVector ;
+; ;
+; Setup fDBCSLeadTable ;
+; ;
+; Arguments: ;
+; BL = First DBCS lead byte ;
+; BH = Final DBCS lead byte ;
+; ;
+; Returns: ;
+; NONE ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; Calls: ;
+; NONE ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc SetDBCSVector,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ mov bl, al ;
+ xor bh, bh ;
+idr2:
+ mov byte ptr fDBCSLeadTable[bx], 1 ; set "DBCS lead byte"
+ inc bl
+ cmp bl, ah ; end of range?
+ jle idr2 ; jump if not
+ifdef JAPAN
+;ifdef KOREA
+ mov fFarEast,1 ; I am in DBCS world. 071191 Yukini.
+endif
+ ret
+
+cEnd nogen
+
+endif
+
+;-----------------------------------------------------------------------;
+; GetFileSize ;
+; ;
+; Measures the SFT entry size for DOS versions we don't know about. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AX = SFT size ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Aug 03, 1987 02:42:15p -by- David N. Weise [davidw] ;
+; Rickz wrote it. ;
+; ;
+; Modifications: ;
+; -by- Amit Chatterjee. ;
+; ;
+; The original method of opening 5 files and looking for 3 consecutive ;
+; ones would not succeed always. IRMALAN when run as a TSR from standar-;
+; -d mode Windows would leave a file open (it probably opens 3 files ;
+; when pooped into the host and leaves the third one open). Next time ;
+; on starting windows, the index of the above 5 files that this routine ;
+; would open would be 3,4,5,6 & 8 (SFT entry no). Of these the first ;
+; 2 would be in one node so this woutine would not find 3 consecutive ;
+; entries and Windows would not start up. ;
+; ;
+; To work around this, we try to open 5 at first. If we fail, then we ;
+; leave the 5 open and open another 5. ;
+; ;
+; !!! At some point we should try to figure out why IRMALAN leaves a ;
+; file open. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetFileSize,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ CheckKernelDS
+ ReSetKernelDS
+
+ mov si,dataOffset handles
+ cCall GetFileSize1
+ cmp ax,-1 ;did it succeed ?
+ jnz @f ;yes.
+ mov si,dataOffset handles+10;place for another five
+ cCall GetFileSize1 ;try to get it
+@@:
+ push ax ;save return value
+
+; close files that were opened
+
+ mov si,dataOffset handles
+ mov cx,10
+
+close_file_loop: ; close the file for each handle
+
+ mov ax,3E00h
+ mov bx,[si]
+ or bx,bx ; no more open ?
+ jz close_file_done
+ int 21h
+ add si,2
+ loop close_file_loop
+
+close_file_done:
+
+ pop ax ;get back return value
+ ret
+
+cEnd nogen
+
+
+
+cProc GetFileSize1,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ mov dx,dataOffset name_string
+ mov cx,5
+open_file_loop: ; open the console four times
+ mov ax,3D00H
+ int 21h
+ mov [si],ax ; save the handle
+ add si,2
+ loop open_file_loop
+
+ xor di,di ; start searching from 0:0
+
+
+; get a selector for searching from 0:0
+
+ mov ax,0 ;get a free slector
+ mov cx,1 ;only 1 selector to allocate
+ int 31h ;ax has selector
+ xor cx,cx ;hiword of initial base
+ push dx
+ xor dx,dx ;loword of initial base
+ mov bx,ax ;get the selector
+ call SetSelectorBaseLim64k ;base is at 0:0
+ pop dx
+ mov es,bx
+
+get_first:
+ call find_con ; find first 'CON\0'
+ cmp ax,-1
+ jz no_table
+
+ cmp ax,-2
+ jnz get_second
+search_again:
+
+ push bx
+ mov bx,es ;get the slector
+
+; add FFD paragraphs to the base to get to next segment
+
+ mov ax,0FFDh ;paragraphs to offset base by
+ push dx
+ call AddParaToBase ;update base
+ pop dx
+ mov es,bx ;have the updated selector
+ pop bx
+ xor di,di
+ jmp get_first
+
+get_second:
+
+ mov bx,ax ; bx is location of first 'CON\0'
+ and bx,000Fh
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ push bx ;save
+ mov bx,es ;get the base
+ push dx
+ call AddParaToBase ;add AX paras to base
+ pop dx
+ mov es,bx ;have the updated base
+ pop bx ;restore
+ mov di,bx
+ add di, 3 ; kludge for the size of desired string
+ call find_con ; find second 'CON\0'
+ cmp ax,-1
+ jz no_table
+ cmp ax,-2
+ jz search_again
+
+ mov dx,ax ; dx is location of second 'CON\0'
+ sub dx,bx
+ cmp dx,100h ; file entries are within 100h bytes of another
+ ja get_second
+ mov bx,dx ; bx is distance between the first two
+ mov dx,ax ; dx is location of second 'CON\0'
+get_third:
+ call find_con
+ cmp ax,-1
+ jz no_table
+ cmp ax,-2
+ jz search_again
+ mov cx,ax ; ax & cx = location of third 'CON\0'
+ sub cx,dx ; cx is distance between the 2nd & 3rd
+ sub bx,cx ; bx = the difference in distances
+ jz found
+ cmp cx,100h ; file entries are within 100h bytes of another
+ ja get_second
+ mov bx,cx ; bx is distance between the two
+ mov dx,ax ; dx is location of the last 'CON\0'
+ jmp get_third
+
+found:
+ mov ax,cx ; store file table entry size in ax
+
+no_table:
+
+; if the temp selector had been allocated free it.
+
+ push bx
+ push ax
+ mov bx,es
+ xor ax,ax
+ mov es,ax
+ or bx,bx ;allocated ?
+ jz @f ;no.
+ mov ax,1 ;free selector
+ int 31h ;free it
+@@:
+ pop ax
+ pop bx ;restore
+ ret
+
+find_con:
+ mov ax,es
+ push dx ;save
+ push bx
+ mov bx,ax ;get the slector
+ call GetSelectorSegment ;DX returns segment value
+ mov ax,dx ;get the segment value
+ pop bx
+ pop dx ;restore
+ cmp ax,8000h
+ ja not_found
+ xor ax,ax
+ mov al, byte ptr [find_string]
+try_again:
+ mov cx,0FFF0h
+ sub cx,di
+ repnz scasb ; search for the first letter ('C')
+ jz continue
+ mov ax,-2
+ jmps temp_ret
+; ret
+continue:
+ mov cx,3
+ mov si, dataOffset find_string+1
+ repz cmpsb ; search for the next three letters
+ jnz find_con
+ lea ax,[di-4] ; return the string's location in ax
+temp_ret:
+ ret
+
+not_found:
+
+ mov ax,-1
+ ret
+
+cEnd nogen
+;----------------------------------------------------------------------------;
+; AddParaToBase: ;
+; ;
+; Given a selector in BX and a para value in AX, it updates the base of the ;
+; selector by AX paras. In real mode, it just adds AX to BX. The modified ;
+; selector/segment is returned in BX. ;
+;----------------------------------------------------------------------------;
+
+AddParaToBase proc near
+ push ax ;save
+ mov ax,6 ;get base address code
+ int 31h ;cx:dx has current base address
+ pop ax ;get back the offset in para
+ push bx ;use as work register
+ xor bx,bx ;zero out
+ shl ax,1 ;shift out a bit
+ rcl bx,1 ;gather into bx
+ shl ax,1 ;shift out a bit
+ rcl bx,1 ;gather into bx
+ shl ax,1 ;shift out a bit
+ rcl bx,1 ;gather into bx
+ shl ax,1 ;shift out a bit
+ rcl bx,1 ;gather into bx
+ add dx,ax ;add low word of offset
+ adc cx,0 ;update hiword
+ add cx,bx ;update hiword of offset
+ pop bx ;get back selector
+ mov ax,7 ;set selector base code
+ int 31h ;the base of the selector has been set
+ inc ax ;set selector limit code
+ mov dx,-1 ;64-1k limit
+ xor cx,cx ;cx:dx=64-1k
+ int 31h ;limit set to 64-1k
+ ret
+
+AddParaToBase endp
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; GrowSFTToMax: ;
+; ;
+; This routine is invoked only in protected mode and grows the SFT to its max;
+; size by linking in one more tanle entry. ;
+;----------------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GrowSFTToMax,<NEAR,PUBLIC,PASCAL>,<es,ax,di>
+
+ localW NewHandles ;# of extra handles being allocated
+ localW NewTableSize ;size of newtable
+ localB GrowLimit ;size to grow sft to
+
+cBegin
+ ReSetKernelDS
+
+; get the amount of free space and decide on the number of handle entries that
+; we want to add. If the memory space is more than 8*64K, make the total number
+; of handle entries 256 else make it 100.
+
+ mov GrowLimit,SFT_HIGH_LIM ;assume we will grow upto 255
+ xor bx,bx ;dummy parameter
+ cCall GetFreeSpace,<bx> ;dx:ax returns free area size
+ cmp dx,SFT_GROW_LIM_IN_64K ;is it more than or equal (in 64k incs)
+ jae @f ;yes
+ mov GrowLimit,SFT_LOW_LIM ;low on memory, grow till 100
+@@:
+
+; allocate a free selector.
+
+ xor ax,ax ;allocate selector function code
+ mov cx,1 ;need to get 1 selector
+ int 31h ;ax has the selector
+
+; get the address of the first in the SFT chain.
+
+ push ax ;save the slector
+ mov ah,52h ;get SYSVARS call
+ int 21h ;es:bx points to DOS SYSVAR structure
+ lea bx,[bx+sftHead] ;es:bx points to the start of the sft
+ mov cx,es:[bx][2] ;get the segment
+ mov dx,es:[bx] ;get the offset
+ pop ax ;get back the free selector
+
+; modify the base of the free selector to point to the first link in the system
+; file table list.
+
+ mov bx,ax ;get the selector here
+ call SetSelectorBaseLim64k ;set selector base and limit.
+
+; now get into a loop, to find out the number of file handles that the system
+; currently.
+
+ xor ah,ah ;will count handles here.
+ mov es,bx ;es points to the first entry
+
+CountNumHandles:
+
+ xor bx,bx ;es:bx points to first table
+ mov cx,es:[bx].sftCount ;get the number of handles
+ add ah,cl ;accumulate no of handles here
+ cmp word ptr es:[bx],-1 ;end of chain ?
+ jz AddOneMoreSFTLink ;end of current list reached
+ mov cx,word ptr es:[bx].sftLink[2];get the segment of next node
+ mov dx,word ptr es:[bx].sftLink[0];get the offset of the next node
+ mov bx,es ;get the selector
+ call SetSelectorBaseLim64k ;modify sel to point to next node
+ jmp short CountNumHandles ;continue
+
+AddOneMoreSFTLink:
+
+; find out the number of extra handles for which we will allocate space
+
+ mov al,GrowLimit ;max number of handles
+ cmp ah,al ;is it already more than limit ?
+ jae GrowSFTToMaxRet ;no need to grow any more.
+
+ifdef WOW
+ xchg ah,al
+ xor ah,ah
+ Debug_Out "GrowSFTToMax: At least 128 files handles required in CONFIG.SYS only specified #AX"
+ jmp ExitKernel
+else
+ sub al,ah ;al has the no of extra handles
+ xor ah,ah ;ax has no of extra handles
+ mov NewHandles,ax ;save it.
+ mul FileEntrySize ;dx:ax has size of table
+ add ax,(SIZE SFT) - 1 ;size of the initial header
+ mov NewTableSize,ax ;save size
+ regptr dxax,dx,ax
+
+ save <es,bx>
+ cCall GlobalDOSAlloc,<dxax> ;allocate the block
+ jcxz GrowSFTToMaxRet ;no memory to allocate
+
+ cCall SetOwner,<ax,hExeHead>
+
+; store the pointer to the new link in the current link.
+
+ push bx ;save
+ mov bx,ax ;get the new selector
+ call GetSelectorSegment ;returns segment of sel in ax, in dx
+ pop bx ;restore
+ mov word ptr es:[bx].sftLink[2],dx
+ mov word ptr es:[bx].sftLink[0],0
+
+; we have to save the address of this last original link so that it can be
+; restored to be the last at DisableKernel time. We will save the current
+; selector and delete it at disable time
+
+ mov word ptr [pSftLink],bx ;save
+ mov word ptr [pSftLink+2],es
+
+ mov bx,es ;get the selector
+ mov es,ax ;es points to new link
+
+; initialize memory tp all zeros
+
+ xor di,di ;es:di points to new buffer
+ mov cx,NewTableSize ;size of buffer
+ xor al,al ;want to initialize to 0's
+ rep stosb ;initialized
+
+; prepare the header for the new table.
+
+ xor bx,bx ;es:bx points to the new table
+ mov cx,-1 ;link terminator code
+ mov word ptr es:[bx].sftLink[2],cx
+ mov word ptr es:[bx].sftLink[0],cx
+ mov cx,NewHandles ;# of handles in this node
+ mov es:[bx].sftCount,cx
+endif; WOW
+
+GrowSFTToMaxRet:
+
+cEnd
+;----------------------------------------------------------------------------;
+; SetSelectorBaseLim64k: ;
+; ;
+; Given a selector value in bx and a real mode lptr in cx:dx, it sets the ba-;
+; -se of the selector to that value and sets it to be a 64k data segment. AX ;
+; is preserved. ;
+; ;
+;----------------------------------------------------------------------------;
+
+SetSelectorBaseLim64k proc near
+
+ push ax ;save
+
+; calculate the linear base address.
+
+ xor ax,ax ;will have high nibble of shift
+ shl cx,1 ;shift by 1
+ rcl ax,1 ;gather in
+ shl cx,1 ;shift by 1
+ rcl ax,1 ;gather in
+ shl cx,1 ;shift by 1
+ rcl ax,1 ;gather in
+ shl cx,1 ;shift by 1
+ rcl ax,1 ;gather in
+ add cx,dx ;add in the offset
+ adc ax,0 ;ax:cx has the base
+ mov dx,cx ;get into proper registers
+ mov cx,ax ;cx:dx has the base
+ mov ax,7 ;set selector base code
+ int 31h ;the base of the selector has been set
+ inc ax ;set selector limit code
+ mov dx,-1 ;64-1k limit
+ xor cx,cx ;cx:dx=64-1k
+ int 31h ;limit set to 64-1k
+
+ pop ax ;restore ax
+ ret
+
+SetSelectorBaseLim64k endp
+;----------------------------------------------------------------------------;
+; GetSelectorSegment: ;
+; ;
+; Given a slector in bx pointing to DOS memory, this function returns the ;
+; real mode segment value in DX. AX,BX is preserved. ;
+;----------------------------------------------------------------------------;
+
+GetSelectorSegment proc near
+
+ push ax ;save
+ push bx ;save
+ mov ax,6 ;get selector base
+ int 31h ;cx:dx has base
+ shr cx,1 ;shift by 1
+ rcr dx,1 ;gather into dx
+ shr cx,1 ;shift by 1
+ rcr dx,1 ;gather into dx
+ shr cx,1 ;shift by 1
+ rcr dx,1 ;gather into dx
+ shr cx,1 ;shift by 1
+ rcr dx,1 ;gather into dx
+ pop bx ;restore
+ pop ax ;dx has segment value
+ ret
+
+GetSelectorSegment endp
+;----------------------------------------------------------------------------;
+
+
+sEnd INITCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/eems.inc b/private/mvdm/wow16/kernel31/eems.inc
new file mode 100644
index 000000000..b11aa9d75
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/eems.inc
@@ -0,0 +1,15 @@
+; some useful constants for EEMS
+
+KBYTES equ 1024
+PARAGRAPH equ 16
+LOG2_KBYTES equ 10
+LOG2_PARAGRAPH equ 4
+
+EMSPageShift equ 10 ; Insist on 16k pages
+EMSPageSize equ (1 shl EMSPageShift) ; Insist on 16k pages
+
+; parameters for EEMS
+
+LOWEST_SWAP_AREA equ 384
+EEMS_DEBUG equ 1
+
diff --git a/private/mvdm/wow16/kernel31/emsmisc.asm b/private/mvdm/wow16/kernel31/emsmisc.asm
new file mode 100644
index 000000000..e836336d9
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/emsmisc.asm
@@ -0,0 +1,172 @@
+
+.xlist
+include kernel.inc
+include tdb.inc
+include eems.inc
+include newexe.inc
+.list
+
+sBegin EMSCODE
+assumes cs,CODE
+assumes ds,NOTHING
+assumes es,NOTHING
+
+;-----------------------------------------------------------------------;
+; EMSCopy ;
+; ;
+; This routine is the continuation of ems_glock. It is intended ;
+; to be called from the clipboard (in C) or from ems_glock ;
+; ;
+; Arguments: ;
+; SourcePID = The EMS PID of the source banks. ;
+; RegSet = EMS register set of source object ;
+; handle = handle to global object ;
+; segaddr = address of object ;
+; EmsSavAddr = address of ems save area (TDB_EEMSSave) ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon July 20, 1987 15:10:23 -by- Rick N. Zucker [rickz] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc EMSCopy,<PUBLIC,FAR>,<di,si>
+ parmW SourcePID
+ parmW RegSet
+ parmW handle
+ parmD segaddr
+ parmD EmsSavAddr
+cBegin
+
+cEnd
+
+sEnd EMSCODE
+
+sBegin CODE
+assumes cs,CODE
+
+;-----------------------------------------------------------------------;
+; LimitEmsPages ;
+; ;
+; Limits the total number of EMS pages a task may have. ;
+; ;
+; Arguments: ;
+; Maximum amount of memory in Kbytes that this task wants. ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Jun 26, 1987 01:53:15a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc LimitEmsPages,<PUBLIC,FAR>
+; parmD amount
+cBegin nogen
+ xor ax,ax
+
+ cwd
+ ret 4
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; KbdReset ;
+; ;
+; Keyboard driver calls here when Ctl+Alt+Del is happening. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc KbdRst,<PUBLIC,FAR>
+cBegin nogen
+
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetCurPID ;
+; A utility routine for EMS functions needed from user routines ;
+; ;
+; function = ;
+; 0 - return the current PID in ax ;
+; 1 - copy the TDB_EEMSSave area into a new block and return ;
+; the new block's handle in ax ;
+; 2 - do not free the banks of the current app ;
+; 3 - free the given PID's banks ;
+; 4 - do an HFree on the given handle ;
+; 5 - get expanded memory sizes ;
+; 6 - ;
+; 7 - do an EMS_save ;
+; 8 - do an EMS_restore ;
+; ;
+; ;
+; Arguments: ;
+; None ;
+; ;
+; Returns: ;
+; see above ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ax,bx,cx,di,si,ds,es ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Jul 17, 1987 11:02:23a -by- Rick N. Zucker [rickz] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc GetCurPID,<PUBLIC,FAR>,<di,si>
+ parmW function
+ parmW gcpArg
+cBegin
+ xor ax,ax
+ xor dx,dx
+
+cEnd
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/enable.asm b/private/mvdm/wow16/kernel31/enable.asm
new file mode 100644
index 000000000..22a031e02
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/enable.asm
@@ -0,0 +1,652 @@
+
+
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+include eems.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+externFP KillLibraries
+ifndef WOW
+externFP WriteOutProfiles
+endif
+
+DataBegin
+
+externB PhantArray
+externB kernel_flags
+externB fBreak
+externB fInt21
+ifndef WOW
+externB fProfileMaybeStale
+endif
+externW curTDB
+externW headPDB
+externW topPDB
+ife PMODE32
+externW hXMMHeap
+endif
+externD lpInt21
+externD pSftLink
+externD lpWinSftLink
+externD pSysProc
+externD pMouseTermProc
+externD pKeyboardTermProc
+externD pSystemTermProc
+externW MyCSAlias
+
+externD myInt2F
+
+if ROM
+externD prevInt00Proc
+externD prevInt21Proc
+externD prevInt24Proc
+externD prevInt2FProc
+externD prevInt3FProc
+externD prevInt67Proc
+externD prevInt02Proc
+externD prevInt04Proc
+externD prevInt06Proc
+externD prevInt07Proc
+externD prevInt3EProc
+externD prevInt75Proc
+externD prevInt0CProc
+externD prevInt0DProc
+externD prevIntx6Proc
+externD prevInt0EProc
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes ds, nothing
+assumes es, nothing
+
+ife ROM
+externD prevInt00Proc
+externD prevInt21Proc
+externD prevInt24Proc
+externD prevInt2FProc
+externD prevInt3FProc
+externD prevInt67Proc
+externD prevInt02Proc
+externD prevInt04Proc
+externD prevInt06Proc
+externD prevInt07Proc
+externD prevInt3EProc
+externD prevInt75Proc
+externD prevInt0CProc
+externD prevInt0DProc
+externD prevIntx6Proc
+externD prevInt0EProc
+ifdef WOW
+externD prevInt01proc
+externD prevInt03proc
+externD oldInt00proc
+endif
+endif
+
+
+if ROM
+externFP PrevROMInt21Proc
+endif
+
+externNP real_DOS
+externNP Enter_gmove_stack
+externNP TerminatePDB
+
+;-----------------------------------------------------------------------;
+; InternalEnableDOS
+;
+;
+; Entry:
+; none
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 21-Sep-1989 20:44:48 -by- David N. Weise [davidw]
+; Added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+SetWinVec MACRO vec
+ externFP Int&vec&Handler
+ mov dx, codeoffset Int&vec&Handler
+ mov ax, 25&vec&h
+ pushf
+if ROM
+ call PrevROMInt21Proc
+else
+ call prevInt21Proc
+endif
+ endm
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc InternalEnableDOS,<PUBLIC,FAR>
+cBegin nogen
+
+ push si
+ push ds
+ SetKernelDS
+
+ mov al,1
+ xchg al,fInt21 ; set hook count to 1
+ or al,al ; was it zero?
+ jz @f
+ jmp ena21 ; no, just leave
+@@:
+
+; now link back nodes to SFT if kernel had done it before. InternalDisableDOS
+; saves the link in the DWORD variable lpWinSftLink. If this variable is NULL
+; then either this is the first time InternalEnableDOS is being called or
+; else the SFT had not been grown.
+
+ cmp lpWinSftLink.sel,0 ;was it allocated ?
+ jz @f ;no.
+ push ds ;save
+ mov cx,lpWinSftLink.sel ;get the selector
+ mov dx,lpWinSftLink.off ;get the offset
+ lds bx,[pSftLink] ;place where we hooked new entry
+ mov word ptr ds:[bx][0],dx ;restore offset
+ mov word ptr ds:[bx][2],cx ;restore segment
+ pop ds ;restore data segment
+@@:
+
+
+; WARNING!! The ^C setting diddle MUST BE FIRST IN HERE......
+; If you do some other INT 21 call before this you will have
+; a "^C window", so don't do it....
+
+ mov ax,3301h ; disable ^C checking
+ mov dl,0
+ call real_DOS
+
+ mov bx,TopPDB
+ mov ah,50h
+ call real_DOS ; This way, or TDB_PDB gets set wrong
+
+ifndef WOW
+ends1: mov ah,6 ; clean out any pending keys
+ mov dl,0FFh
+ call real_DOS
+ jnz ends1
+endif
+
+ mov es,curTDB
+ mov bx,es:[TDB_PDB]
+ mov ah,50h
+ int 21h
+
+ push ds
+ lds dx,myInt2F
+ mov ax,252Fh
+ int 21h
+
+ smov ds,cs ; Pick up executable sel/seg
+ UnSetKernelDS
+ SetWinVec 24
+ SetWinVec 00
+ SetWinVec 02
+ SetWinVec 04
+ SetWinVec 06
+ SetWinVec 07
+ SetWinVec 3E
+ SetWinVec 75
+ pop ds
+ ReSetKernelDS
+
+ mov bx,2 ; 2 = Enable/Disable one drive logic
+ xor ax,ax ; FALSE = Disable
+ cCall [pSysProc],<bx,ax> ; NOTE: destroys ES if DOS < 3.20
+
+; Set up the PhantArray by calling inquire system for each drive letter
+
+ mov bx,dataOffset PhantArray + 25 ; Array index
+ mov cx,26 ; Drive #
+SetPhant:
+ dec cx
+ push cx
+ push bx
+ mov dx,1 ; InquireSystem
+ cCall [pSysProc],<dx,cx>
+ pop bx
+ pop cx
+ mov byte ptr [bx],0 ; Assume not Phantom
+ cmp ax,2
+ jae NotPhant ; Assumption correct
+; or dx,dx ; Drive just invalid?
+; jz NotPhant ; Yes, assumption correct
+ mov byte ptr [bx],dl ; Drive is phantom
+NotPhant:
+ dec bx ; Next array element
+ jcxz phant_done
+ jmp SetPhant
+phant_done:
+
+ lds dx,lpInt21
+ UnSetKernelDS
+ mov ax,2521h
+ int 21h
+ena21:
+ pop ds
+ pop si
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; InternalDisableDOS ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Oct 16, 1989 11:04:50 -by- Amit Chatterjee [amitc] ;
+; InternalDisableDOS now takes away any nodes that kernel would have ;
+; added to the SFT. InternalEnableDOS puts the nodes backs. Previously ;
+; the delinking was done by DisableKernel, but no one linked it back! ;
+; ;
+; Sat May 09, 1987 02:00:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+; ;
+; Thu Apr 16, 1987 11:32:00p -by- Raymond E. Ozzie [-iris-] ;
+; Changed InternalDisableDOS to use real dos for 52h function, since ;
+; DosTrap3 doesn't have 52h defined and PassOnThrough will croak if the ;
+; current TDB's signature is 0, as it is during exit after the last ;
+; task has been deleted. ;
+;-----------------------------------------------------------------------;
+
+ReSetDOSVec MACRO vec
+ lds dx,PrevInt&vec&proc
+ mov ax,25&vec&h
+ int 21h
+ endm
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc InternalDisableDOS,<PUBLIC,FAR>
+cBegin
+ SetKernelDS es
+ xor ax,ax
+ xchg al,fInt21 ; set hook count to zero
+ or al,al ; was it non zero?
+ jnz @F
+ jmp dis21 ; no, just leave
+@@:
+ mov bx,2 ; 2 = Enable/Disable one drive logic
+ mov ax,1 ; TRUE = Enable
+ push es
+ cCall pSysProc,<bx,ax>
+ pop es
+
+ mov ax,3301h ; disable ^C checking
+ mov dl,0
+ pushf
+ife PMODE32
+ FCLI
+endif
+ call [prevInt21Proc]
+
+ mov ax,2521h
+ lds dx,prevInt21Proc
+ pushf
+ife PMODE32
+ FCLI
+endif
+ call [prevInt21Proc]
+
+ push es
+ mov ax,352Fh
+ int 21h
+ mov ax,es
+ pop es
+ mov myInt2F.sel,ax
+ mov myInt2F.off,bx
+
+ ReSetDOSVec 00 ; as a favor in win2 we restored this
+ ReSetDOSVec 24
+ ReSetDOSVec 2F
+ ReSetDOSVec 02
+ ReSetDOSVec 04
+ ReSetDOSVec 06
+ ReSetDOSVec 07
+ ReSetDOSVec 3E
+ ReSetDOSVec 75
+
+ mov dl,fBreak ; return state of ^C checking
+ mov ax,3301h
+ int 21h
+
+dis21:
+cEnd
+
+;------------------------------------------------------------------
+;
+; Ancient WinOldAp hook.
+;
+;------------------------------------------------------------------
+ public EnableDOS
+
+EnableDOS Label Byte
+if kdebug
+ krDebugOut DEB_WARN, "Don't call EnableDOS"
+endif
+ retf
+
+;------------------------------------------------------------------
+;
+; Ancient WinOldAp hook.
+;
+;------------------------------------------------------------------
+ public DisableDOS
+
+DisableDOS Label Byte
+if kdebug
+ krDebugOut DEB_WARN, "Don't call DisableDOS"
+endif
+ retf
+
+;------------------------------------------------------------------
+;
+; Ancient WinOldAp hook.
+;
+;------------------------------------------------------------------
+ public EnableKernel
+
+EnableKernel Label Byte
+if kdebug
+ krDebugOut DEB_WARN, "Don't call EnableKernel"
+endif
+ retf
+
+
+;-----------------------------------------------------------------------;
+; DisableKernel ;
+; ;
+; This call is provided as a Kernel service to applications that ;
+; wish to totally unhook Windows in order to do something radical ;
+; such as save the state of the world and restore it at a later ;
+; time. This is similar in many ways to the way OLDAPP support ;
+; works, with the addition that it also unhooks the kernel. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat May 09, 1987 02:34:35p -by- David N. Weise [davidw] ;
+; Merged changes in. Most of this came from ExitKernel. ;
+; ;
+; Tue Apr 28, 1987 11:12:00a -by- R.E.O. SpeedWagon [-????-] ;
+; Changed to indirect thru PDB to get JFN under DOS 3.x. ;
+; ;
+; Mon Apr 20, 1987 11:34:00p -by- R.E.O. SpeedWagon [-????-] ;
+; Set PDB to topPDB before final int 21/4C; we were sometimes exiting ;
+; with a task's PDB, and thus we came back to ExitCall2 instead of ;
+; going back to DOS! ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DisableKernel,<PUBLIC,FAR>,<si,di>
+cBegin
+
+ SetKernelDS
+ or Kernel_flags[2],KF2_WIN_EXIT ; prevent int 24h dialogs
+ cmp prevInt21Proc.sel,0
+ je nodisable
+ call InternalDisableDOS
+nodisable:
+
+ SetKernelDS
+ mov ax,0203h ; Reset not present fault.
+ mov bl,0Bh
+ mov cx,prevInt3Fproc.sel
+ mov dx,prevInt3Fproc.off
+ int 31h
+
+ mov ax,0203h ; Reset stack fault.
+ mov bl,0Ch
+ mov cx,prevInt0Cproc.sel
+ mov dx,prevInt0Cproc.off
+ int 31h
+
+ mov ax,0203h ; Reset GP fault.
+ mov bl,0Dh
+ mov cx,prevInt0Dproc.sel
+ mov dx,prevInt0Dproc.off
+ int 31h
+
+ mov ax,0203h ; Reset invalid op-code exception.
+ mov bl,06h
+ mov cx,prevIntx6proc.sel
+ mov dx,prevIntx6proc.off
+ int 31h
+
+ mov ax,0203h ; Reset page fault.
+ mov bl,0Eh
+ mov cx,prevInt0Eproc.sel
+ mov dx,prevInt0Eproc.off
+ int 31h
+
+ifdef WOW
+ mov ax,0203h ; Reset divide overflow traps
+ mov bl,00h
+ mov cx,oldInt00proc.sel
+ mov dx,oldInt00proc.off
+ int 31h
+
+ mov ax,0203h ; Reset single step traps
+ mov bl,01h
+ mov cx,prevInt01proc.sel
+ mov dx,prevInt01proc.off
+ int 31h
+
+ mov ax,0203h ; Reset breakpoint traps
+ mov bl,03h
+ mov cx,prevInt03proc.sel
+ mov dx,prevInt03proc.off
+ int 31h
+endif
+
+ mov dx, [HeadPDB]
+ SetKernelDS es
+ UnSetKernelDS
+exk1:
+ mov ds,dx
+ cmp dx, [topPDB] ; Skip KERNEL, he is about to get
+ je exk3 ; a 4C stuffed down his throat
+
+ push ds
+ call TerminatePDB
+ pop ds
+
+exk3:
+ mov dx,ds:[PDB_Chain] ; move to next PDB in chain
+ or dx,dx
+ jnz exk1
+
+ mov bx,[topPDB] ; set to initial DOS task PDB
+ mov ah,50h ; set PDB function
+ int 21h
+ and Kernel_flags[2],NOT KF2_WIN_EXIT ; prevent int 24h dialogs
+;
+; Close all files on Kernel's PSP, 'cause we're gonna shrink the SFT and
+; quit ourselves afterwards.
+;
+ mov ds,[topPDB]
+ mov cx,ds:[PDB_JFN_Length]
+exk4: mov bx,cx ; close all file handles
+ dec bx
+ cmp bx,5 ; console-related handle?
+ jb exk5 ; yup, don't close it (AUX, etc.)
+ mov ah,3eh
+ int 21h
+exk5: loop exk4
+
+; kernel could have added some nodes to the SFT. Delink them by removing
+; the link from the last DOS link in the chain. We need to remember the
+; current pointer there so that InternalEnableDOS can put it back.
+
+ lds bx,[pSftLink] ;place where we hooked new entry
+ assumes ds,nothing
+ mov cx,ds ;this could have been unitialized too
+ jcxz exk6 ;if unitialized, nothing to do
+ mov dx,ds:[bx].off ;get the current offset
+ mov cx,ds:[bx].sel ;get the current segment
+ mov ds:[bx].off,-1 ;remove windows SFT link
+ mov ds:[bx].sel, 0 ;remove windows SFT link
+ mov lpWinSftLink.off,dx ;save the offset
+ mov lpWinSftLink.sel,cx ;save the segment
+exk6:
+
+ UnSetKernelDS es
+cEnd
+
+;------------------------------------------------------------------
+;
+; ExitKernel -- Bye, bye.
+;
+;------------------------------------------------------------------
+ifndef WOW ; If we are closing down WOW then we don't want to go back to the DOS Prompt
+ ; We want to kill the NTVDM WOW Process - so we don't need/want this code.
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ExitKernel,<PUBLIC,FAR>
+; parmW exitcode
+cBegin nogen
+ SetKernelDS
+ or Kernel_flags[2],KF2_WIN_EXIT ; prevent int 24h dialogs
+ call KillLibraries ; Tell DLLs that the system is exiting
+
+ mov si,sp
+ mov si,ss:[si+4] ; get exit code
+
+; Call driver termination procs, just to make sure that they have removed
+; their interrupt vectors.
+
+ push si
+ mov ax,word ptr [pMouseTermProc]
+ or ax,word ptr [pMouseTermProc+2]
+ jz trm0
+ call [pMouseTermProc]
+ CheckKernelDS
+trm0: mov ax,word ptr [pKeyboardTermProc]
+ or ax,word ptr [pKeyboardTermProc+2]
+ jz trm1
+ call [pKeyboardTermProc]
+ CheckKernelDS
+trm1: mov ax,word ptr [pSystemTermProc]
+ or ax,word ptr [pSystemTermProc+2]
+ jz trm2
+ call [pSystemTermProc]
+ CheckKernelDS
+trm2: pop si
+
+ call WriteOutProfiles
+ mov fProfileMaybeStale,1 ; Make sure we check the
+ ; INI file next time around
+;;; cCall CloseCachedFiles,<topPDB>
+
+; Close open files and unhook kernel hooks
+
+; get on a stack that's not in EMS land
+
+ call Enter_gmove_stack
+
+ cCall DisableKernel
+ CheckKernelDS
+
+ cmp si,EW_REBOOTSYSTEM ; Reboot windows?
+ jnz exitToDos
+
+ifndef WOW
+if PMODE32
+ mov ax,1600h
+ int 2Fh
+ test al,7Fh
+ jz NotRunningEnhancedMode
+ cmp al,1
+ je exitToDos ;RunningWindows3862x
+ cmp al,-1
+ je exitToDos ;RunningWindows3862x
+ xor di,di ; Zero return regs
+ mov es,di
+ mov bx,0009h ; Reboot device ID
+ mov ax,1684h ; Get device API entry point
+ int 2Fh
+ mov ax,es
+ or ax,di
+ jz exitToDos ; Reboot vxd not loaded. Exit to dos
+
+ ; Call the reboot function
+ mov ax,0100h
+ push es
+ push di
+ mov bx,sp
+ call DWORD PTR ss:[bx]
+
+ jmp short exitToDos ; Reboot didn't work just exit to dos
+
+NotRunningEnhancedMode:
+endif
+endif ; WOW
+
+ mov ah, 0Dh ; Disk Reset so that Smartdrv etc buffers
+ int 21h ; are written to disk
+
+ mov ax, 0FE03h ; Flush Norton NCache
+ mov si, "CF"
+ mov di, "NU"
+ stc ; Yes! Really set carry too!
+ int 2Fh
+
+ int 19h ; Reboot via int 19h
+
+
+exitToDos:
+ mov ax,si
+ mov ah,4Ch ; Leave Windows.
+ int 21h
+cEnd nogen
+
+endif ; NOT WOW
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/error.c b/private/mvdm/wow16/kernel31/error.c
new file mode 100644
index 000000000..e322f7dac
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/error.c
@@ -0,0 +1,405 @@
+#include "kernel.h"
+
+#define WINAPI _far _pascal _loadds
+typedef unsigned int UINT;
+typedef const char _far* LPCSTR;
+typedef HANDLE HTASK;
+
+#include "logerror.h"
+
+int WINAPI FatalExitC(WORD);
+void WINAPI OutputDebugString(LPCSTR);
+
+void DebugLogParamError(VOID FAR* param, FARPROC lpfn, WORD err);
+void DebugLogError(WORD err, VOID FAR* lpInfo);
+int WINAPI GetOwnerName(WORD sel, char far *buf, WORD buflen);
+int WINAPI FarGetOwner(WORD sel);
+
+#define CODESEG _based(_segname("_CODE"))
+
+#define SELECTOROF(lp) HIWORD(lp)
+#define OFFSETOF(lp) LOWORD((DWORD)lp)
+#define MAKELONG(a, b) ((LONG)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
+#define MAKELP(sel, off) ((VOID FAR *)MAKELONG(off, sel))
+
+#if KDEBUG
+
+UINT DebugOptions = 0;
+UINT DebugFilter = 0;
+
+#define FMT_WORD 0
+#define FMT_DWORD 1
+#define FMT_LP 2
+
+struct TYPEMAP
+{
+ UINT err;
+ char* szType; // Compiler bug: this can't be _based
+ char CODESEG* szFmt;
+};
+
+static char CODESEG szParam[] = "parameter";
+static char CODESEG szD16[] = "%s: Invalid %s: %d\r\n";
+static char CODESEG szD32[] = "%s: Invalid %s: %ld\r\n";
+static char CODESEG szX16[] = "%s: Invalid %s: %#04x\r\n";
+static char CODESEG szX32[] = "%s: Invalid %s: %#08lx\r\n";
+static char CODESEG szLP[] = "%s: Invalid %s: %#04x:%#04x\r\n";
+
+#define DEFMAP(err, type, fmt) \
+ { err, type, fmt }
+struct TYPEMAP CODESEG typemap[] =
+{
+ DEFMAP(ERR_BAD_VALUE, "value", szD16),
+ DEFMAP(ERR_BAD_INDEX, "index", szD16),
+ DEFMAP(ERR_BAD_FLAGS, "flags", szX16),
+ DEFMAP(ERR_BAD_SELECTOR, "selector", szX16),
+ DEFMAP(ERR_BAD_DFLAGS, "flags", szX32),
+ DEFMAP(ERR_BAD_DVALUE, "value", szD32),
+ DEFMAP(ERR_BAD_DINDEX, "index", szD32),
+ DEFMAP(ERR_BAD_PTR, "pointer", szLP),
+ DEFMAP(ERR_BAD_FUNC_PTR, "function pointer", szLP),
+ DEFMAP(ERR_BAD_STRING_PTR, "string pointer", szLP),
+ DEFMAP(ERR_BAD_HINSTANCE, "HINSTANCE", szX16),
+ DEFMAP(ERR_BAD_HMODULE, "HMODULE", szX16),
+ DEFMAP(ERR_BAD_GLOBAL_HANDLE,"global handle", szX16),
+ DEFMAP(ERR_BAD_LOCAL_HANDLE, "local handle", szX16),
+ DEFMAP(ERR_BAD_ATOM, "atom", szX16),
+ DEFMAP(ERR_BAD_HWND, "HWND", szX16),
+ DEFMAP(ERR_BAD_HMENU, "HMENU", szX16),
+ DEFMAP(ERR_BAD_HCURSOR, "HCURSOR", szX16),
+ DEFMAP(ERR_BAD_HICON, "HICON", szX16),
+ DEFMAP(ERR_BAD_GDI_OBJECT, "HGDIOBJ", szX16),
+ DEFMAP(ERR_BAD_HDC, "HDC", szX16),
+ DEFMAP(ERR_BAD_HPEN, "HPEN", szX16),
+ DEFMAP(ERR_BAD_HFONT, "HFONT", szX16),
+ DEFMAP(ERR_BAD_HBRUSH, "HBRUSH", szX16),
+ DEFMAP(ERR_BAD_HBITMAP, "HBITMAP", szX16),
+ DEFMAP(ERR_BAD_HRGN, "HRGN", szX16),
+ DEFMAP(ERR_BAD_HPALETTE, "HPALETTE", szX16),
+ DEFMAP(ERR_BAD_HANDLE, "HANDLE", szX16),
+ DEFMAP(ERR_BAD_HFILE, "HFILE", szX16),
+ DEFMAP(ERR_BAD_HMETAFILE, "HMETAFILE", szX16),
+ DEFMAP(ERR_BAD_CID, "CID", szX16),
+ DEFMAP(ERR_BAD_HDRVR, "HDRVR", szX16),
+ DEFMAP(ERR_BAD_HDWP, "HDWP", szX16)
+};
+
+int (_cdecl _far *wsprintf)(LPSTR, LPCSTR, ...) = NULL;
+int (WINAPI *wvsprintf)(LPSTR lpszOut, LPCSTR lpszFmt, const void FAR* lpParams) = NULL;
+
+#define ORD_WSPRINTF 420
+#define ORD_WVSPRINTF 421
+
+BOOL _fastcall LoadWsprintf(void)
+{
+ static char CODESEG rgchUSER[] = "USER";
+
+ HANDLE hmod;
+
+ hmod = GetModuleHandle(rgchUSER);
+
+ if (!hmod)
+ return FALSE;
+
+ (FARPROC)wsprintf = GetProcAddress(hmod, MAKELP(NULL, ORD_WSPRINTF));
+ (FARPROC)wvsprintf = GetProcAddress(hmod, MAKELP(NULL, ORD_WVSPRINTF));
+
+ if (!SELECTOROF(wsprintf))
+ {
+ static char CODESEG rgch[] = "KERNEL: Can't call wsprintf: USER not initialized\r\n";
+ OutputDebugString(rgch);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+typedef struct
+{
+ UINT flags;
+ LPCSTR lpszFmt;
+ WORD args[1];
+} DOPARAMS;
+
+#define BUFFERSLOP 32
+
+BOOL DebugOutput2(DOPARAMS FAR* pparams)
+{
+ UINT flags = pparams->flags;
+ BOOL fBreak = FALSE;
+ BOOL fPrint = TRUE;
+ char rgch[80*2 + BUFFERSLOP]; // max 2 lines (don't want to hog too much stack space)
+ static char CODESEG szCRLF[] = "\r\n";
+ char far *prefix, far *prefix1;
+
+ switch (flags & DBF_SEVMASK)
+ {
+ case DBF_TRACE:
+ // If the flags don't match the debug filter,
+ // don't print the trace message.
+ // If the trace matches the filter, check for TRACEBREAK.
+ //
+ prefix = "t ";
+ if (!((flags & DBF_FILTERMASK) & DebugFilter))
+ fPrint = FALSE;
+ else if (DebugOptions & DBO_TRACEBREAK)
+ fBreak = TRUE;
+ break;
+
+ case DBF_WARNING:
+ prefix = "wn ";
+ if (DebugOptions & DBO_WARNINGBREAK)
+ fBreak = TRUE;
+ break;
+
+ case DBF_ERROR:
+ prefix = "err ";
+ if (!(DebugOptions & DBO_NOERRORBREAK))
+ fBreak = TRUE;
+ break;
+
+ case DBF_FATAL:
+ prefix = "fatl ";
+ if (!(DebugOptions & DBO_NOFATALBREAK))
+ fBreak = TRUE;
+ break;
+ }
+
+ // If DBO_SILENT is specified, don't print anything.
+ //
+ if (DebugOptions & DBO_SILENT)
+ fPrint = FALSE;
+
+ if ((lstrlen((LPSTR)pparams->lpszFmt) <= sizeof(rgch) - BUFFERSLOP) &&
+ (SELECTOROF(wsprintf) || LoadWsprintf()) && (fPrint || fBreak))
+ {
+ int hinst = HIWORD(pparams);
+
+ for (prefix1 = rgch; *prefix; ) *prefix1++ = *prefix++;
+ prefix1 += GetOwnerName(hinst, prefix1, 16);
+ *prefix1++ = ' ';
+ wvsprintf(prefix1, pparams->lpszFmt, (void FAR*)pparams->args);
+ OutputDebugString(rgch);
+ OutputDebugString(szCRLF);
+ }
+
+ if (fBreak)
+ {
+ // If we are supposed to break with an int 3, then return TRUE.
+ //
+ if (DebugOptions & DBO_INT3BREAK)
+ return TRUE;
+
+ return FatalExitC(flags);
+ }
+ return FALSE;
+}
+
+BOOL LogParamError2(WORD err, FARPROC lpfn, VOID FAR* param, WORD caller)
+{
+ BOOL fBreak;
+
+ fBreak = FALSE;
+ if (err & ERR_WARNING)
+ {
+ if (DebugOptions & DBO_WARNINGBREAK)
+ fBreak = TRUE;
+ }
+ else
+ {
+ if (!(DebugOptions & DBO_NOERRORBREAK))
+ fBreak = TRUE;
+ }
+
+ // If we're not breaking and SILENT is specified, just return.
+ //
+ if (!fBreak && (DebugOptions & DBO_SILENT))
+ return FALSE;
+
+ if (SELECTOROF(wsprintf) || LoadWsprintf())
+ {
+ char rgch[128];
+ char rgchProcName[50], far *rpn;
+ char* pszType; // compiler bug: see above
+ char CODESEG* pszFmt;
+ int i, hinst;
+ WORD errT;
+ void FAR GetProcName(FARPROC lpfn, LPSTR lpch, int cch);
+ char far *prefix1;
+
+ GetProcName(lpfn, rgchProcName, sizeof(rgchProcName));
+ /* if we got a real proc name, then copy just the proc name */
+ for (rpn = rgchProcName; *rpn && (*rpn != '(') && (*rpn != ':'); rpn++)
+ ;
+ if (*rpn == ':') {
+ lstrcpy(rgchProcName, rpn+1);
+ }
+
+ pszFmt = szX32;
+ pszType = szParam;
+ errT = (err & ~ERR_WARNING);
+ for (i = 0; i < (sizeof(typemap) / sizeof(struct TYPEMAP)); i++)
+ {
+ if (typemap[i].err == errT)
+ {
+ pszFmt = typemap[i].szFmt;
+ pszType = typemap[i].szType;
+ break;
+ }
+ }
+ if (err & ERR_WARNING) {
+ lstrcpy(rgch, "wn ");
+ prefix1 = rgch+3;
+ } else {
+ lstrcpy(rgch, "err ");
+ prefix1 = rgch+4;
+ }
+ hinst = HIWORD(prefix1);
+ prefix1 += GetOwnerName(hinst, prefix1, 16);
+ if (FarGetOwner(hinst) != FarGetOwner(caller)) {
+ *prefix1++ = '-';
+ *prefix1++ = '>';
+ prefix1 += GetOwnerName(caller, prefix1, 16);
+ }
+ *prefix1++ = ' ';
+
+ if (pszFmt == szLP)
+ wsprintf(prefix1, pszFmt, (LPSTR)rgchProcName, (LPSTR)pszType, SELECTOROF(param), OFFSETOF(param));
+ else if (pszFmt == szD32 || pszFmt == szX32)
+ wsprintf(prefix1, pszFmt, (LPSTR)rgchProcName, (LPSTR)pszType, (DWORD)param);
+ else
+ wsprintf(prefix1, pszFmt, (LPSTR)rgchProcName, (LPSTR)pszType, (WORD)(DWORD)param);
+
+ OutputDebugString(rgch);
+ }
+
+ if (fBreak)
+ {
+ // If we are supposed to break with an int 3, then return TRUE.
+ //
+ if (DebugOptions & DBO_INT3BREAK)
+ return TRUE;
+
+ return FatalExitC(err);
+ }
+ return FALSE;
+}
+
+extern HTASK allocTask;
+extern DWORD allocCount;
+extern DWORD allocBreak;
+extern char allocModName[8];
+
+void FAR _loadds SetupAllocBreak(HTASK htask);
+char far* GetTaskModNamePtr(HTASK htask);
+
+BOOL WINAPI IGetWinDebugInfo(WINDEBUGINFO FAR* lpwdi, UINT flags)
+{
+ int i;
+
+ lpwdi->flags = flags;
+
+ if (flags & WDI_OPTIONS)
+ lpwdi->dwOptions = DebugOptions;
+
+ if (flags & WDI_FILTER)
+ lpwdi->dwFilter = DebugFilter;
+
+ if (flags & WDI_ALLOCBREAK)
+ {
+ lpwdi->dwAllocBreak = allocBreak;
+ lpwdi->dwAllocCount = allocCount;
+ for (i = 0; i < 8; i++)
+ lpwdi->achAllocModule[i] = allocModName[i];
+ }
+ return TRUE;
+}
+
+BOOL WINAPI ISetWinDebugInfo(const WINDEBUGINFO FAR* lpwdi)
+{
+ int i;
+
+ if (lpwdi->flags & WDI_OPTIONS)
+ DebugOptions = (UINT)lpwdi->dwOptions;
+
+ if (lpwdi->flags & WDI_FILTER)
+ DebugFilter = (UINT)lpwdi->dwFilter;
+
+ if (lpwdi->flags & WDI_ALLOCBREAK)
+ {
+ allocTask = NULL;
+ allocBreak = lpwdi->dwAllocBreak;
+ allocCount = 0; // Always reset count to 0.
+
+ for (i = 0; i < 8; i++)
+ allocModName[i] = lpwdi->achAllocModule[i];
+
+ {
+ extern HTASK headTDB;
+ HTASK htask;
+
+ // Enumerate all current tasks to see if any match
+ //
+ #define TDB_next 0
+ for (htask = headTDB; htask; htask = *((HTASK FAR*)MAKELP(htask, TDB_next)))
+ SetupAllocBreak(htask);
+ }
+ }
+ return TRUE;
+}
+
+void FAR _loadds SetupAllocBreak(HTASK htask)
+{
+ int i;
+ char far* pchAlloc;
+ char far* pchTask;
+
+ // If alloc break task already set up, exit.
+ //
+ if (allocTask)
+ return;
+
+ // If no alloc break in effect, nothing to do.
+ //
+ if (allocModName[0] == 0)
+ return;
+
+ pchAlloc = allocModName;
+ pchTask = GetTaskModNamePtr(htask);
+
+ for (i = 8; --i != 0; pchAlloc++, pchTask++)
+ {
+ char ch1 = *pchAlloc;
+ char ch2 = *pchTask;
+
+ if (ch1 >= 'a' && ch1 <= 'z')
+ ch1 -= ('a' - 'A');
+
+ if (ch2 >= 'a' && ch2 <= 'z')
+ ch2 -= ('a' - 'A');
+
+ if (ch1 != ch2)
+ return;
+
+ if (ch1 == 0 || ch2 == 0)
+ break;
+ }
+
+ // Set the alloc break task, and init the count to 0.
+ //
+ allocTask = htask;
+ allocCount = 0;
+}
+
+#else // !KDEBUG
+
+BOOL WINAPI GetWinDebugInfo(WINDEBUGINFO FAR* lpwdi, UINT flags)
+{
+ return FALSE;
+}
+
+BOOL WINAPI SetWinDebugInfo(const WINDEBUGINFO FAR* lpwdi)
+{
+ return FALSE;
+}
+
+#endif // !KDEBUG
diff --git a/private/mvdm/wow16/kernel31/fixexe.c b/private/mvdm/wow16/kernel31/fixexe.c
new file mode 100644
index 000000000..81ff8b414
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/fixexe.c
@@ -0,0 +1,66 @@
+/*** FIXEXE.C
+ *
+ * Copyright (c) 1991 Microsoft Corporation
+ *
+ * DESCRIPTION
+ * Patches specified .EXE file as required to load Windows KERNEL.EXE
+ * Removes requirement for LINK4 from Build
+ * It also produces same effect as EXEMOD file /MAX 0
+ *
+ * Set DOS .EXE size to size of file +512
+ * Set MAX alloc to Zero
+ *
+ *
+ * MODIFICATION HISTORY
+ * 03/18/91 Matt Felton
+ */
+
+#define TRUE 1
+
+#include <stdio.h>
+
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ FILE *hFile;
+ long lFilesize;
+ int iLengthMod512;
+ int iSizeInPages;
+ int iZero;
+
+ iZero= 0;
+
+ if (argc == 1)
+ fprintf(stderr, "Usage: fixexe [file]\n");
+
+ while (++argv,--argc) {
+ hFile = fopen(*argv, "rb+");
+ if (!hFile) {
+ fprintf(stderr, "cannot open %s\n", *argv);
+ continue;
+ }
+ printf("Processing %s\n", *argv);
+
+ /* calculate the .EXE file size in bytes */
+
+ fseek(hFile, 0L, SEEK_END);
+ lFilesize = ftell(hFile);
+ iSizeInPages = (lFilesize + 511) / 512;
+ iLengthMod512 = lFilesize % 512;
+
+ printf("Filesize is %lu bytes, %i pages, %i mod\n",lFilesize,iSizeInPages,iLengthMod512);
+
+ /* set DOS EXE File size to size of file + 512 */
+ fseek(hFile, 2L, SEEK_SET);
+ fwrite( &iLengthMod512, sizeof(iLengthMod512), 1, hFile );
+ fwrite( &iSizeInPages, sizeof(iSizeInPages), 1, hFile );
+
+ /* Now perform EXEMOD file /MAX 0 equivalent */
+ fseek(hFile, 12L, SEEK_SET);
+ fwrite( &iZero, sizeof(iZero), 1, hFile);
+
+ fclose(hFile);
+ }
+}
diff --git a/private/mvdm/wow16/kernel31/gacheck.asm b/private/mvdm/wow16/kernel31/gacheck.asm
new file mode 100644
index 000000000..5ab9d3db9
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/gacheck.asm
@@ -0,0 +1,215 @@
+
+.xlist
+include kernel.inc
+.list
+
+if KDEBUG
+
+DataBegin
+
+externB fBooting
+externW pGlobalHeap
+;externW hGlobalHeap
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externW gdtdsc
+
+externNP check_lru_list
+externNP check_free_list
+externNP get_physical_address
+
+;externFP ValidateFreeSpaces
+
+
+;-----------------------------------------------------------------------;
+; CheckGlobalHeap ;
+; ;
+; The Global Heap is checked for consistency. First the forward links ;
+; are examined to make sure they lead from the hi_first to the hi_last. ;
+; Then the backward links are checked to make sure they lead from the ;
+; hi_last to the hi_first. Then the arenas are sequentially checked ;
+; to see that the moveable entries point to allocated handles and that ;
+; said handles point back. The handle table is then checked to see ;
+; that the number of used handles match the number of referenced ;
+; handles, and that the number of total handles matches the sum of the ;
+; free, discarded, and used handles. Finally the free list of handles ;
+; is checked. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; CF = 0 everything is just fine ;
+; all registers preserved ;
+; ;
+; Error Returns: ;
+; CF = 1 ;
+; DX = offending arena header ;
+; AX = 01h Forward links invalid ;
+; 02h Backward links invalid ;
+; 04h ga_handle points to free handle ;
+; 08h arena points to handle but not vice versa ;
+; 80h ga_sig is bad ;
+; DX = 0 ;
+; AX = 10h allocated handles don't match used handles ;
+; 20h total number of handles don't match up ;
+; 40h total number of free handles don't match up ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Nov 01, 1986 02:16:46p -by- David N. Weise [davidw] ;
+; Rewrote it from C into assembly. ;
+;-----------------------------------------------------------------------;
+
+cProc CheckGlobalHeap,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ push dx
+ push bx
+ push cx
+ push di
+ push si
+ push ds
+ push es
+
+ xor ax,ax
+ xor dx,dx
+ xor di,di
+ SetKernelDS
+ cmp pGlobalHeap,di
+ jnz there_is_a_GlobalHeap
+ jmp all_done
+there_is_a_GlobalHeap:
+ cmp fBooting, 1
+ jz no_check
+ mov ds,pGlobalHeap
+ UnSetKernelDS
+ cmp [di].hi_check,di
+ jnz checking_enabled
+no_check:
+ jmp all_done
+checking_enabled:
+ mov cx,[di].hi_count
+ mov dx,[di].hi_first
+ mov es, dx
+forward_ho:
+ push cx
+ cCall get_physical_address, <es>
+ add ax, 10h
+ adc dx, 0
+ mov bx, es:[di].ga_size
+ xor cx, cx
+rept 4
+ shl bx, 1
+ rcl cx, 1
+endm
+ cmp es:[di].ga_owner, di
+ je no_limit_check
+ cmp es:[di].ga_handle, di
+ je no_limit_check
+ push bx
+ push cx
+ push si
+ push ds
+ smov ds, gdtdsc
+ mov si, es:[di].ga_handle
+ sel_check si
+ sub bx, 1
+ sbb cx, 0
+ or cx, cx ; More than 1 selector?
+ jz @F
+ mov bx, -1
+@@:
+ cmp [si], bx
+ jne bad_limit
+ mov ch, [si+6]
+ and cx, 0F0Fh
+ cmp ch, cl
+ je ok_limit
+bad_limit:
+ Debug_Out "gacheck: Bad limit for #SI"
+ok_limit:
+ pop ds
+ pop si
+ pop cx
+ pop bx
+no_limit_check:
+
+ cmp es:[di].ga_owner,GA_NOT_THERE ;286pmode has some of these
+ jnz check_size ; with 0 size
+ pop cx
+ jmp short size_ok
+
+check_size:
+ add bx, ax
+ adc cx, dx
+ cCall get_physical_address, <es:[di].ga_next>
+ cmp cx, dx
+ pop cx
+ mov dx, es
+ xchg ax, dx
+ jne forward_size_mismatch
+ cmp dx, bx
+ jne forward_size_mismatch
+
+size_ok:
+ mov ax, es
+ mov dx, es:[di].ga_next
+ mov es, dx
+ cmp ax, es:[di].ga_prev
+ jz size_and_next_match
+forward_size_mismatch:
+ cmp cx,1
+ jnz forward_links_invalid
+size_and_next_match:
+ loop xxxx
+ cmp ax,[di].hi_last
+ jz forward_links_okay
+forward_links_invalid:
+ Debug_Out "gacheck: Forward links invalid"
+ mov dx,ax
+ mov ax,1
+ jmp all_done
+xxxx:
+ jmp forward_ho
+
+forward_links_okay:
+
+ xor ax, ax
+clear_dx_all_done:
+ xor dx,dx
+all_done:
+ pop es
+ pop ds
+ pop si
+ pop di
+ pop cx
+ pop bx
+ or ax,ax
+ jnz cgh_error
+ pop dx
+ pop ax
+ ret
+cgh_error:
+ int 3
+ add sp,4
+ stc
+ ret
+cEnd nogen
+
+sEnd CODE
+
+endif
+
+end
diff --git a/private/mvdm/wow16/kernel31/gpcont.asm b/private/mvdm/wow16/kernel31/gpcont.asm
new file mode 100644
index 000000000..c8eb9556d
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/gpcont.asm
@@ -0,0 +1,272 @@
+; GPCont.asm - code to allow continuation after GP faults
+
+.xlist
+include kernel.inc
+include newexe.inc ; ne_restab
+include gpcont.inc
+.list
+
+if SHERLOCK
+
+FAULTSTACKFRAME struc
+
+fsf_BP dw ? ; Saved BP
+fsf_msg dw ? ; Near pointer to message describing fault
+fsf_prev_IP dw ? ; IP of previous fault handler
+fsf_prev_CS dw ? ; CS of previous fault handler
+fsf_ret_IP dw ? ; DPMI fault handler frame follows
+fsf_ret_CS dw ?
+fsf_err_code dw ?
+fsf_faulting_IP dw ?
+fsf_faulting_CS dw ?
+fsf_flags dw ?
+fsf_SP dw ?
+fsf_SS dw ?
+
+FAULTSTACKFRAME ends
+
+fsf_DS equ word ptr -10
+fsf_ES equ word ptr -10
+fsf_FS equ word ptr -10
+fsf_GS equ word ptr -10
+
+;flag bits set in gpRegs
+strCX = 1
+strSI = 2
+strDI = 4
+segDS = 8
+segES = 16
+segFS = 32
+segGS = 64
+
+DataBegin
+externB szGPCont
+szKernel db 6,'KERNEL'
+szUser db 4,'USER'
+szDrWatson db 'DRWATSON'
+
+
+externW gpTrying ; retrying current operation
+externW gpEnable ; user has enabled GP continue
+externW gpSafe ; current instruction is safe
+externW gpInsLen ; length of faulting instruction
+externW gpRegs ; bit field of modified regs
+externD pSErrProc ; pointer to SysErrBox in USER
+DataEnd
+
+externFP IsBadCodePtr
+externFP FarFindExeInfo
+
+sBegin CODE
+assumes CS,CODE
+
+externNP DisAsm86
+externNP GetOwner
+
+;extern int far pascal SysErrorBox(char far *text, char far *caption,
+; int b1, int b2, int b3);
+SEB_OK = 1 ; Button with "OK".
+SEB_CANCEL = 2 ; Button with "Cancel"
+SEB_YES = 3 ; Button with "&Yes"
+SEB_NO = 4 ; Button with "&No"
+SEB_RETRY = 5 ; Button with "&Retry"
+SEB_ABORT = 6 ; Button with "&Abort"
+SEB_IGNORE = 7 ; Button with "&Ignore"
+SEB_CLOSE = 8 ; Button with "Close"
+SEB_DEFBUTTON = 8000h ; Mask to make this button default
+
+SEB_BTN1 = 1 ; Button 1 was selected
+SEB_BTN2 = 2 ; Button 1 was selected
+SEB_BTN3 = 3 ; Button 1 was selected
+
+;Name: int PrepareToParty(char *modName)
+;Desc: Checks whether we can continue the current app by skipping an
+; instruction. If so, it performs the side effects of the
+; instruction. This must be called after a call to DisAsm86() has
+; set the gpXxxx global vars.
+;Bugs: Should do more checking, should check for within a device driver,
+
+cProc PrepareToParty,<PUBLIC,NEAR>,<si,di>
+ parmD modName
+ parmD appName
+cBegin
+ ReSetKernelDS
+
+ mov ax, [gpEnable] ; User enabled continue
+ test ax, 1 ; We know how to continue
+ jz ptp_poop
+
+ cld
+ dec [modName.off] ; include length byte in compare
+ les di, [modName]
+
+ test ax, 4 ; can continue in KERNEL?
+ jnz @F
+ lea si, szKernel
+ mov cx, 7
+ repe cmpsb
+ jz ptp_poop ; fault in Kernel is fatal
+
+@@: test ax, 8 ; can continue in USER?
+ jnz @F
+ mov di, modName.off
+ lea si, szUser
+ mov cx, 5
+ repe cmpsb
+ jz ptp_poop ; fault in User is fatal
+
+@@: cmp [gpTrying], 0
+ jne ptp_exit ; AX != 0 - do it again
+
+ cmp pSErrProc.sel, 0 ; Is USER loaded?
+ je ptp_poop
+
+ mov ax, dataoffset szGPCont
+ mov bx, SEB_CLOSE or SEB_DEFBUTTON ; dumb cmacros
+ cCall [pSErrProc],<ds, ax, appName, bx, 0, SEB_IGNORE>
+ cmp ax, SEB_BTN3
+ jne ptp_poop
+; mov [gpTrying], 100
+ jmps ptp_exit ; AX != 0
+
+ptp_poop: ; every party needs a pooper
+ xor ax, ax
+ptp_exit:
+cEnd
+ UnSetKernelDS
+
+
+cProc SafeDisAsm86,<NEAR,PUBLIC>
+ parmD cp
+cBegin
+ ReSetKernelDS
+ mov [gpSafe], 0 ; assume unsafe
+
+ mov bx, cp.off ; make sure we can disassemble
+ add bx, 10 ; at least a 10-byte instruction
+ jc sda_exit ; offset wrap-around - failed
+
+ cCall IsBadCodePtr,<seg_cp, bx>
+ or ax, ax
+ jnz sda_exit
+
+ cCall DisAsm86,<cp>
+ mov [gpInsLen], ax
+sda_exit:
+cEnd
+
+
+; return value in DX:AX and ES:AX (your choice), sets Z flag if failure
+cProc FindSegName,<NEAR,PUBLIC>,<ds>
+ parmW segval
+cBegin
+ cCall GetOwner,<segval>
+ mov dx, ax
+ or ax, ax
+ jz fsn_exit
+ mov es, ax
+ mov ax, es:[ne_restab]
+ inc ax
+fsn_exit:
+cEnd
+
+ public GPContinue
+GPContinue proc near
+ push si ; instruction length
+ test [gpEnable], 1
+ jz s_fail
+
+ cCall SafeDisAsm86,<[bp].fsf_faulting_CS,[bp].fsf_faulting_IP>
+ test [gpSafe], 1
+ jz s_fail
+
+ push ds
+ push dataoffset szDrWatson
+ push 8
+ Call FarFindExeInfo
+ or ax, ax
+ jnz s_fail
+
+ cCall FindSegName,<[bp].fsf_faulting_CS>
+ jz s_fail
+ push dx
+ push ax
+
+ cCall FindSegName,<[bp].fsf_SS>
+ jz s_fail4
+ push dx
+ push ax
+
+ cCall PrepareToParty
+ or ax, ax
+ jz s_fail
+
+; Perform side-effects
+
+ mov ax, [gpRegs] ; Invalid value to DS?
+ test ax, segDS
+ jz @F
+ mov [bp].fsf_DS, 0
+
+@@: test ax, segES ; Invalid value to ES?
+ jz @F
+ mov [bp].fsf_ES, 0
+
+if PMODE32
+ .386p
+@@: xor bx, bx ; Invalid value to FS?
+ test ax, segFS
+ jz short @F
+ mov fs, bx
+
+@@: test ax, segGS ; Invalid value to GS?
+ jz short @F
+ mov gs, bx
+ .286p
+endif
+@@:
+ test ax, 0
+; check other reg side effects
+ mov bx, [gpInsLen] ; Fixup IP for instruction length
+ add [bp].fsf_faulting_IP, bx
+ mov ax, 1
+ jmps s_end
+
+s_fail4:
+ add sp, 4
+s_fail:
+ xor ax, ax
+s_end:
+ pop si
+ ret
+GPContinue endp
+
+sEnd CODE
+endif ; SHERLOCK
+ end
+
+ regs.ip += faultlen; /* set at top of func - don't reuse
+ if ((int)gpStack < 0) {
+ for (i=0; i<8; i++) stack[i+gpStack] = stack[i];
+ } else if (gpStack) {
+ for (i=7; i>=0; i--) stack[i+gpStack] = stack[i];
+ }
+ regs.sp += gpStack << 1;
+ if (gpRegs & strCX) {
+ len = regs.cx * memSize;
+ regs.cx = 0;
+ } else len = memSize;
+ if (gpRegs & strSI) { /* doesn't handle 32 bit regs
+ regs.si += len;
+ if (regs.si < (word)len) /* if overflow, set to big value
+ regs.si = 0xfff0; /* so global vars in heap don't get
+ } /* trashed when we continue
+ if (gpRegs & strDI) {
+ regs.di += len;
+ if (regs.di < (word)len) regs.di = 0xfff0;
+ }
+ }
+
+ return party;
+} /* Sherlock
+
diff --git a/private/mvdm/wow16/kernel31/gpcont.inc b/private/mvdm/wow16/kernel31/gpcont.inc
new file mode 100644
index 000000000..5a7daea3c
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/gpcont.inc
@@ -0,0 +1,9 @@
+ ifndef PM386
+ SHERLOCK = 0
+ else
+ SHERLOCK = 1
+ endif
+
+
+
+; SHERLOCK = PM386 ; GPContinue only on Krnl386
diff --git a/private/mvdm/wow16/kernel31/gpfix.asm b/private/mvdm/wow16/kernel31/gpfix.asm
new file mode 100644
index 000000000..3a2dd323b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/gpfix.asm
@@ -0,0 +1,436 @@
+; gpfix.asm - pointer validation routines
+
+ include gpfix.inc
+ include kernel.inc
+ include tdb.inc
+ include newexe.inc
+
+
+sBegin GPFIX0
+__GP label word
+;gpbeg dw 0, 0, 0, 0 ; for use in handler
+public __GP
+sEnd GPFIX0
+
+sBegin GPFIX1
+gpend dw 0
+sEnd GPFIX1
+
+sBegin DATA
+;this segment is page locked and will be accessible during a GP fault
+;has the names of modules that are allowed to use our funky GP fault handling
+; mechanism. Format: length byte, module name. The table is zero-terminated.
+gp_valid_modules label byte
+db 3, "GDI"
+db 4, "USER"
+db 6, "KERNEL"
+db 6, "PENWIN"
+db 7, "DISPLAY"
+db 8, "MMSYSTEM"
+db 0 ;end of table
+sEnd DATA
+
+ifdef DISABLE
+sBegin DATA
+;ExternW wErrorOpts
+sEnd DATA
+endif
+
+
+;public gpbeg, gpend
+
+
+sBegin CODE
+assumes CS,CODE
+
+externA __AHINCR
+
+externNP GetOwner
+externNP EntProcAddress
+externFP GetExePtr
+
+;===============================================================
+;
+;
+cProc IsBadReadPtr,<PUBLIC,FAR,NONWIN>
+ParmD lp
+ParmW cb
+cBegin
+beg_fault_trap BadRead1
+ les bx,lp ; check selector
+ mov cx,cb
+ jcxz ReadDone1
+ dec cx
+ add bx,cx
+ jc BadRead ; check 16 bit overflow
+ mov al,es:[bx] ; check read permission, limit
+end_fault_trap
+ReadDone1:
+ xor ax,ax
+ReadDone:
+cEnd
+
+BadRead1:
+ fault_fix_stack
+BadRead:
+ mov ax,1
+ jmp short ReadDone
+
+;===============================================================
+;
+;
+cProc IsBadWritePtr,<PUBLIC,FAR,NONWIN>
+ParmD lp
+ParmW cb
+cBegin
+beg_fault_trap BadWrite1
+ les bx,lp ; check selector
+ mov cx,cb
+ jcxz WriteDone1
+ dec cx
+ add bx,cx
+ jc BadWrite ; check 16 bit overflow
+ or es:byte ptr [bx],0 ; check write permission, limit
+end_fault_trap
+WriteDone1:
+ xor ax, ax
+WriteDone:
+cEnd
+
+BadWrite1:
+ fault_fix_stack
+BadWrite:
+ mov ax,1
+ jmp short WriteDone
+
+;===============================================================
+; BOOL IsBadHugeReadPtr(VOID HUGE*lp, DWORD cb)
+;
+cProc IsBadHugeReadPtr,<PUBLIC,FAR,NONWIN>
+ParmD lp
+ParmD cb
+cBegin
+beg_fault_trap hrp_trap
+ les bx,lp ; check selector
+
+ mov ax,off_cb
+ mov cx,seg_cb
+
+ mov dx,ax ; if cb == 0, then all done.
+ or dx,cx
+ jz hrp_ok
+
+ sub ax,1 ; decrement the count
+ sbb cx,0
+
+ add bx,ax ; adjust cx:bx by pointer offset
+ adc cx,0
+ jc hrp_bad ; (bug #10446, pass in -1L as count)
+
+ jcxz hrplast ; deal with leftover
+hrploop:
+ mov al,es:[0ffffh] ; touch complete segments.
+ mov dx,es
+ add dx,__AHINCR
+ mov es,dx
+ loop hrploop
+hrplast:
+ mov al,es:[bx]
+hrp_ok:
+ xor ax,ax
+end_fault_trap
+hrp_exit:
+cEnd
+
+hrp_trap:
+ fault_fix_stack
+hrp_bad:
+ mov ax,1
+ jmp hrp_exit
+
+;===============================================================
+; BOOL IsBadHugeWritePtr(VOID HUGE*lp, DWORD cb)
+;
+cProc IsBadHugeWritePtr,<PUBLIC,FAR,NONWIN>
+ParmD lp
+ParmD cb
+cBegin
+beg_fault_trap hwp_trap
+ les bx,lp ; check selector
+
+ mov ax,off_cb
+ mov cx,seg_cb
+
+ mov dx,ax ; if cb == 0, then all done.
+ or dx,cx
+ jz hwp_ok
+
+ sub ax,1 ; decrement the count
+ sbb cx,0
+
+ add bx,ax ; adjust cx:bx by pointer offset
+ adc cx,0
+ jc hwp_bad ; (bug #10446, pass in -1L as count)
+
+ jcxz hwplast ; deal with leftover
+hwploop:
+ or byte ptr es:[0ffffh],0 ; touch complete segments.
+ mov dx,es
+ add dx,__AHINCR
+ mov es,dx
+ loop hwploop
+hwplast:
+ or byte ptr es:[bx],0
+hwp_ok:
+ xor ax,ax
+end_fault_trap
+hwp_exit:
+cEnd
+
+hwp_trap:
+ fault_fix_stack
+hwp_bad:
+ mov ax,1
+ jmp hwp_exit
+
+;===============================================================
+;
+;
+cProc IsBadCodePtr,<PUBLIC,FAR,NONWIN>
+ParmD lpfn
+cBegin
+beg_fault_trap BadCode1
+ mov cx,seg_lpfn
+ lar ax,cx
+ jnz BadCode ; Oh no, this isn't a selector!
+
+ test ah, 8
+ jz BadCode ; Oh no, this isn't code!
+
+ mov es,cx ; Validate the pointer
+ mov bx,off_lpfn
+ mov al,es:[bx]
+
+end_fault_trap
+ xor ax, ax
+CodeDone:
+cEnd
+
+BadCode1:
+ fault_fix_stack
+BadCode:
+ mov ax,1
+ jmp short CodeDone
+
+
+;========================================================
+;
+; BOOL IsBadStringPtr(LPSTR lpsz, UINT cch);
+;
+cProc IsBadStringPtr,<PUBLIC,FAR,NONWIN>,<DI>
+ParmD lpsz
+ParmW cchMax
+cBegin
+beg_fault_trap BadStr1
+ les di,lpsz ; Scan the string.
+ xor ax,ax
+ mov cx,-1
+ cld
+ repnz scasb
+end_fault_trap
+ neg cx ; cx = string length + 1
+ dec cx
+ cmp cx,cchMax
+ ja BadStr ; if string length > cchMax, then bad string.
+bspexit:
+cEnd
+
+BadStr1:
+ fault_fix_stack
+BadStr:
+ mov ax,1
+ jmp bspexit
+
+;-----------------------------------------------------------------------;
+; HasGPHandler ;
+; ;
+; See if GP fault handler is registered for faulting address. ;
+; ;
+; This scheme can only be used by registered modules. You register ;
+; a module by adding an entry containing a length byte followed by ;
+; the module name in the gp_valid_modules table defined above. ;
+; ;
+; Arguments: ;
+; parmD lpFaultAdr ;
+; ;
+; Returns: ;
+; AX = New IP of handler ;
+; AX = 0 if no handler registered ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; GetOwner ;
+; EntProcAddress ;
+; ;
+; The __GP table has the format of 4 words per entry, plus a ;
+; zero word to terminate the table. The 'seg' value should be ;
+; the actual selector (it must be fixed up by the linker), ;
+; and the offset values should be relative to the start of the ;
+; segment or group. The handler must be in the same code segment ;
+; as the fault range (this ensures that the handler is present ;
+; at GP fault time). ;
+; ;
+; __GP label word ;
+; public __GP ;
+; seg, offset begin, offset end, handler ;
+; ... ;
+; 0 ;
+; ;
+; The symbol '__GP' needs to be in the resident name table, so ;
+; it should be added to the DEF file like this (with an ;
+; appropriate ordinal value): ;
+; ;
+; EXPORTS ;
+; __GP @??? RESIDENTNAME ;
+; ;
+; ;
+; History: ;
+; ?? Jun 91 Don Corbitt [donc] Wrote it ;
+; 30 Jul 91 Don Corbitt [donc] Added support for __GP table ;
+;-----------------------------------------------------------------------;
+
+
+cProc HasGPHandler,<PUBLIC,FAR,NONWIN>,<ds,si,di>
+ParmD lpfn
+cBegin
+ cCall GetOwner, <SEG_lpfn> ; find owner of faulting code
+ or ax, ax
+ jz to_fail ;HH_fail
+
+ lar bx, ax ; make sure segment is present
+ jnz to_fail ;HH_fail
+ test bx, 8000h
+ jz to_fail ;HH_fail
+
+ mov es, ax
+ cmp es:[ne_magic], NEMAGIC
+ jz @f
+to_fail:
+ jmp HH_fail
+@@:
+
+ ; check if the faulting module is allowed to use this scheme
+ SetKernelDS
+ mov di, es:[ne_restab]
+ mov bx, di
+ inc bx ; save ptr to module name
+ xor cx,cx
+ xor ax,ax
+ mov si, offset gp_valid_modules
+ mov al, es:[di]
+ cld
+friend_or_fiend:
+ mov cl, [si]
+ jcxz HH_fail
+ cmp al,cl
+ jnz next_friend
+ mov di, bx ; need to keep restoring di
+ inc si ; skip len byte
+ repe cmpsb
+ jz we_know_this_chap
+ dec si ; point to the mismatch
+next_friend:
+ add si, cx
+ inc si
+ jmp short friend_or_fiend
+we_know_this_chap:
+
+ xor cx, cx
+ mov si, es:[ne_restab] ; restore si
+ jmp short @F ; start in middle of code
+
+HH_nextSym:
+ add si, cx ; skip name
+ add si, 3 ; and entry point
+@@: mov cl, es:[si] ; get length of symbol
+ jcxz HH_fail ; end of table - not found
+ cmp cl, 4 ; name length
+ jnz HH_nextSym
+ cmp es:[si+1], '__' ; look for '__GP'
+ jnz HH_nextSym
+ cmp es:[si+3], 'PG'
+ jnz HH_nextSym
+ mov ax, es:[si+5] ; get ordinal for '__GP'
+if KDEBUG
+ cCall EntProcAddress,<es,ax,1>
+else
+ cCall EntProcAddress,<es,ax> ; I hate conditional assembly....
+endif
+ mov cx, ax
+ or cx, dx
+ jz HH_fail ; This shouldn't ever fail, but...
+
+ lar bx, dx ; make sure segment is present
+ jnz HH_fail
+ test bx, 8000h
+ jz HH_fail
+
+ mov ds, dx
+ mov si, ax
+ mov ax, SEG_lpfn
+ mov dx, OFF_lpfn
+next_fault_val:
+ mov cx, [si]
+ jcxz HH_fail
+ cmp cx, ax ; does segment match?
+ jnz gp_mismatch
+ cmp [si+2], dx ; block start
+ ja gp_mismatch
+ cmp [si+4], dx ; block end
+ jbe gp_mismatch
+ mov ax, [si+6] ; get new IP
+ jmp short HH_done
+
+gp_mismatch:
+ add si, 8
+ jmp short next_fault_val
+
+HH_fail:
+ xor ax, ax
+HH_done:
+cEnd
+
+;========================================================================
+;
+; BOOL IsSharedSelector(HGLOBAL h);
+;
+; Makes sure the given selector is shareable. Currently, we just check
+; if it is owned by a DLL. We also need to check GMEM_SHARE bit but
+; this isn't saved...
+;
+cProc IsSharedSelector,<PUBLIC,FAR,NOWIN>
+ParmW sharedsel
+cBegin
+ push sharedsel
+ call GetExePtr
+ or ax,ax ; bogus handle: exit.
+ jz ISS_Done
+ mov es,ax
+ xor ax,ax
+ test es:[ne_flags],NENOTP
+ jz ISS_Done ; Not a DLL
+ inc ax ; Yup a DLL
+
+ISS_Done:
+cEnd
+
+sEnd CODE
+
+ end
diff --git a/private/mvdm/wow16/kernel31/handle.asm b/private/mvdm/wow16/kernel31/handle.asm
new file mode 100644
index 000000000..bd3499792
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/handle.asm
@@ -0,0 +1,75 @@
+ TITLE HANDLE - Handle Table Manager
+
+
+
+.xlist
+include kernel.inc
+.list
+
+sBegin CODE
+assumes CS,CODE
+;-----------------------------------------------------------------------;
+; hthread ;
+; ;
+; Threads together a list of free handles. ;
+; ;
+; Arguments: ;
+; DI = start of chain ;
+; CX = #handle entries in chain ;
+; ;
+; Returns: ;
+; AX = address of first handle entry on free list ;
+; CX = 0 ;
+; DI = address of first word after handle block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Oct 27, 1986 10:09:23a -by- David N. Weise [davidw] ;
+; Restructured as a result of separating handle.asm and lhandle.asm. ;
+; ;
+; Tue Oct 14, 1986 04:11:46p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+; ;
+; Wed Jul 8, 1987 14:36 -by- Rick N. Zucker [rickz] ;
+; changed to hthread from ghthead to be used by local handle entries ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc hthread,<PUBLIC,NEAR>
+cBegin nogen
+ push di ; Save first free handle entry
+ smov es,ds
+ cld
+ht1: ; Chain entries together via he_link
+ errnz <he_link>
+ errnz <he_link - lhe_link>
+ lea ax,[di].SIZE HandleEntry
+ stosw
+ mov ax,HE_FREEHANDLE
+ errnz <2 - he_flags>
+ errnz <he_flags - lhe_flags>
+ stosw
+ errnz <4 - SIZE HandleEntry>
+ errnz <SIZE HandleEntry - SIZE LocalHandleEntry>
+ loop ht1
+ ; Null terminate free list
+ mov [di-SIZE HandleEntry].he_link,cx
+ pop ax ; Return free handle address
+ ret
+cEnd nogen
+
+sEnd CODE
+
+
+end
diff --git a/private/mvdm/wow16/kernel31/hmem.asm b/private/mvdm/wow16/kernel31/hmem.asm
new file mode 100644
index 000000000..3b3a1f6da
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/hmem.asm
@@ -0,0 +1,273 @@
+ title HMem
+;HMem.asm - huge memory functions HMemCpy, etc
+
+include gpfix.inc
+include kernel.inc
+
+externFP Int21Handler
+
+DataBegin
+externW WinFlags
+ifdef WOW
+externD pFileTable
+externW cur_dos_PDB
+externW Win_PDB
+endif
+DataEnd
+
+sBegin CODE
+assumes cs,CODE
+
+ifdef WOW
+externFP WOWFileRead
+externFP WOWFileWrite
+externD prevInt21proc
+endif
+
+
+externA __AHINCR
+
+
+cProc hMemCpy,<PUBLIC,FAR>,<ds, si, di>
+ parmD dest ; to ES:DI
+ parmD src ; to DS:SI
+ parmD cnt ; to DX:AX
+ localW flags
+cBegin
+ SetKernelDS
+ mov bx, WinFlags
+ mov flags, bx
+ mov dx, seg_cnt ; DX:AX is 32 bit length
+ mov ax, off_cnt
+ xor cx, cx ; 0 if fault loading operands
+beg_fault_trap hmc_trap
+ lds si, src
+ les di, dest
+ cld
+hmc_loop:
+ mov cx, 8000h ; try to copy 32K
+
+ cmp cx, si ; space left in source?
+ jae @F
+ mov cx, si
+
+@@: cmp cx, di ; space left in dest?
+ jae @F
+ mov cx, di
+
+@@: neg cx ; convert bytes left to positive
+
+ or dx, dx ; >64K left to copy?
+ jnz @F
+
+ cmp cx, ax ; At least this much left?
+ jbe @F
+ mov cx, ax
+
+@@: sub ax, cx ; Decrement count while we're here
+ sbb dx, 0
+
+ test flags, WF_CPU386 + WF_CPU486 + WF_ENHANCED
+ jnz hmc_do32
+
+ shr cx, 1 ; Copy 32KB
+ rep movsw
+ adc cx, 0
+ rep movsb
+ jmps hmc_copied
+
+hmc_do32:
+ .386p
+ push cx
+ shr cx, 2
+ rep movsd
+ pop cx
+ and cx, 3
+ rep movsb
+ .286p
+
+hmc_copied:
+ mov cx, ax ; At end of copy?
+ or cx, dx
+ jz hmc_done
+
+ or si, si ; Source wrap-around?
+ jnz @F
+ mov bx, ds
+ add bx, __AHINCR
+ mov ds, bx
+
+@@: or di, di ; Dest wrap-around?
+ jnz @F
+ mov bx, es
+ add bx, __AHINCR
+ mov es, bx
+end_fault_trap
+@@: jmps hmc_loop
+
+hmc_trap:
+ fault_fix_stack ; DX:AX = bytes left if failure
+ krDebugOut DEB_ERROR, "hMemCopy: Copy past end of segment"
+ add ax, cx
+ adc dx, 0
+hmc_done: ; DX:AX = 0 if success
+
+cEnd
+
+ifdef W_Q21
+cProc _HREAD, <PUBLIC, FAR, NODATA>, <ds>
+ parmW h
+ parmD lpData
+ parmD dwCnt
+cBegin
+ SetKernelDS ds
+ push bx
+ mov bx, Win_PDB
+ cmp bx, cur_dos_PDB
+ je HR_PDB_ok
+
+ push ax
+ mov cur_dos_PDB,bx
+ mov ah,50h
+ pushf
+ call cs:prevInt21Proc ; JUMP THROUGH CS VARIABLE
+ pop ax
+HR_PDB_OK:
+ pop bx
+
+ cCall WowFileRead,<h,lpData,dwCnt,cur_dos_PDB,0,pFileTable>
+
+; DX:AX = Number Bytes Read
+; DX = FFFF, AX = Error Code
+
+ inc dx
+ jnz @f
+
+ xor dx,dx
+ or ax, -1
+@@:
+ dec dx
+cEnd
+
+cProc _HWRITE, <PUBLIC, FAR, NODATA>, <ds>
+ parmW h
+ parmD lpData
+ parmD dwCnt
+cBegin
+ SetKernelDS ds
+
+ push bx ; Setting the DOS PDB can probably
+ mov bx, Win_PDB ; be removed just pass Win_PDB to
+ cmp bx, cur_dos_PDB ; the WOW thunk
+ je HW_PDB_ok
+
+ push ax
+ mov cur_dos_PDB,bx
+ mov ah,50h
+ pushf
+ call cs:prevInt21Proc ; JUMP THROUGH CS VARIABLE
+ pop ax
+HW_PDB_OK:
+ pop bx
+
+ cCall WowFileWrite,<h,lpData,dwCnt,cur_dos_PDB,0,pFileTable>
+
+; DX:AX = Number Bytes Read
+; DX = FFFF, AX = Error Code
+
+ inc dx
+ jnz @f
+
+ xor dx,dx
+ or ax, -1
+@@:
+ dec dx
+cEnd
+
+else
+public _HREAD, _HWRITE
+
+_HREAD:
+ mov bx, 3f00h
+ jmps hugeIO
+
+_HWRITE:
+ mov bx, 4000h
+
+cProc hugeIO, <FAR, NODATA>, <ds, si, di, cx>
+ parmW h
+ parmD lpData
+ parmD dwCnt
+ localD dwTot
+ localW func
+cBegin
+ mov func, bx ; read from a file
+ mov bx, h
+ xor cx, cx
+ mov seg_dwTot, cx
+ mov off_dwTot, cx
+beg_fault_trap hr_fault
+ lds dx, lpData
+ mov si, seg_dwCnt
+ mov di, off_dwCnt
+
+hr_loop:
+ mov cx, 8000h ; try to do 32KB
+
+ cmp cx, dx ; space left in data buffer
+ jae @F
+ mov cx, dx
+ neg cx
+
+@@: or si, si ; at least 64K left
+ jnz @F
+ cmp cx, di
+ jbe @F
+ mov cx, di
+
+@@: mov ax, func ; talk to DOS
+ DOSCALL
+ jc hr_oops
+
+ add off_dwTot, ax ; update transfer count
+ adc seg_dwTot, 0
+
+ cmp ax, cx ; end of file?
+ jnz hr_done
+
+ sub di, ax ; decrement count
+ sbb si, 0
+
+ mov cx, si ; end of count
+ or cx, di
+ jz hr_done
+
+ add dx, ax ; update pointer to data
+ jnz @F ; wrapped to next segment
+ mov ax, ds
+ add ax, __AHINCR
+ mov ds, ax
+end_fault_trap
+@@: jmps hr_loop
+
+hr_fault:
+ pop dx
+ pop ax
+; krDebugOut DEB_ERROR, "File I/O past end of memory block"
+ krDebugOut DEB_ERROR, "GP fault in _hread/_hwrite at #DX #AX"
+; fault_fix_stack
+
+hr_oops:
+ or dx, -1
+ mov seg_dwTot, dx
+ mov off_dwTot, dx
+
+hr_done:
+ mov dx, seg_dwTot
+ mov ax, off_dwTot
+cEnd
+endif ; WOW
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/kernel31/i21entry.asm b/private/mvdm/wow16/kernel31/i21entry.asm
new file mode 100644
index 000000000..4c768b3dc
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/i21entry.asm
@@ -0,0 +1,1677 @@
+
+
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+include eems.inc
+include protect.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+ifdef WOW
+;
+; Int 21 tracing control. If TraceInt21 is defined, ifdef's cause
+; extra debugging output before/after the DOS call.
+;
+; TraceInt21 equ 1 ; uncomment this line to log Int 21 operations.
+endif
+
+
+DataBegin
+
+externB PhantArray
+externB kernel_flags
+externB Kernel_InDOS
+externB Kernel_InINT24
+externB fInt21
+externB InScheduler
+externB CurDOSDrive
+externB DOSDrives
+externW curTDB
+externW curDTA
+;externW headPDB
+;externW topPDB
+externW Win_PDB
+externW cur_dos_PDB
+externW cur_drive_owner
+externW LastExtendedError
+ifndef WOW
+externB WinIniInfo
+externB PrivateProInfo
+externB fProfileMaybeStale
+externB fWriteOutProfilesReenter
+endif
+externB fBooting
+;externD lpWinSftLink
+
+if ROM
+externD prevInt21Proc
+endif
+
+ifdef WOW
+externD pPMDosCURDRV
+externD pPMDosPDB
+
+externD pFileTable
+externW WinFlags
+externW fLMdepth
+externW WOWLastError
+externB WOWErrClass
+externB WOWErrAction
+externB WOWErrLocation
+endif
+
+DataEnd
+
+externFP WriteOutProfiles
+
+sBegin CODE
+assumes CS,CODE
+assumes ds, nothing
+assumes es, nothing
+
+ife ROM
+externD prevInt21Proc
+endif
+
+ifdef WOW
+externFP WOWFileRead
+externFP WOWFileWrite
+externFP WOWFileLSeek
+externFP WOWFileCreate
+externFP WOWFileOpen
+externFP WOWFileClose
+externFP WOWFileGetAttributes
+externFP WOWFileSetAttributes
+externFP WOWFileGetDateTime
+externFP WOWFileSetDateTime
+externFP WOWFileLock
+externFP WOWDelFile
+externFP WOWFindFirst
+externFP WOWFindNext
+externFP WOWSetDefaultDrive
+externFP WOWGetCurrentDirectory
+externFP WOWSetCurrentDirectory
+externFP WOWGetCurrentDate
+externFP WOWDeviceIOCTL
+
+externNP DPMIProc
+endif
+
+
+;***********************************************************************;
+; ;
+; WINDOWS mediated system calls. ;
+; ;
+; Windows mediates certain system calls. Several matters complicate ;
+; the mediation: ;
+; ;
+; a. MSDOS uses registers to pass arguments. Thus, registers AND ;
+; ANY RETURN VALUES in registers must be preserved across tasks. ;
+; ;
+; b. MSDOS stores global state information that must be preserved ;
+; on a task by task basis. ;
+; ;
+; c. To handle multiple exec calls, the notion of a "parent" task ;
+; is introduced. ;
+; ;
+; ;
+;***********************************************************************;
+
+entry macro fred
+if1
+ dw 0
+else
+ifndef fred
+ extrn fred:near
+endif
+ dw CODEOffset fred
+endif
+ endm
+
+ public DosTrap1
+DosTrap1:
+;;; entry not_supported ; 00 abort call
+;;; entry not_supported ; 01 read keyboard and echo
+;;; entry not_supported ; 02 display character
+;;; entry not_supported ; 03 aux input
+;;; entry not_supported ; 04 aux output
+;;; entry not_supported ; 05 printer output
+;;; entry not_supported ; 06 direct console IO
+;;; entry not_supported ; 07 direct console input
+;;; entry not_supported ; 08 read keyboard
+;;; entry not_supported ; 09 display string
+;;; entry not_supported ; 0A buffered keyboard input
+;;; entry not_supported ; 0B check keyboard status
+;;; entry not_supported ; 0C flush keyboard buffer
+;;; entry PassOnThrough ; 0D disk reset
+ entry Select_Disk ; 0E
+ entry not_supported ; 0F open file FCB
+ entry not_supported ; 10 close file FCB
+ entry FCBCall ; 11 search first FCB
+ entry not_supported ; 12 search next FCB
+ entry not_supported ; 13 delete file FCB
+ entry not_supported ; 14 read FCB
+ entry not_supported ; 15 write FCB
+ entry not_supported ; 16 create file FCB
+ entry not_supported ; 17 rename file FCB
+ entry not_supported ; 18 ???
+ entry PassOnThrough ; 19 current disk
+ entry Set_DTA ; 1A
+ entry not_supported ; 1B allocation table info
+ entry not_supported ; 1C allocation table info
+ entry not_supported ; 1D ???
+ entry not_supported ; 1E ???
+ entry not_supported ; 1F ???
+ entry not_supported ; 20 ???
+ entry not_supported ; 21 read FCB
+ entry not_supported ; 22 write FCB
+ entry not_supported ; 23 file size FCB
+ entry not_supported ; 24 set record field FCB
+ entry Set_Vector ; 25
+ entry not_supported ; 26
+ entry not_supported ; 27 random read FCB
+ entry not_supported ; 28 random write FCB
+ entry not_supported ; 29 parse filename FCB
+ entry PassOnThrough ; 2A get date
+ entry PassOnThrough ; 2B set date
+ entry PassOnThrough ; 2C get time
+ entry PassOnThrough ; 2D set time
+ entry PassOnThrough ; 2E set verify
+ entry PassOnThrough ; 2F get DTA
+ entry PassOnThrough ; 30 get DOS version
+ entry not_supported ; 31 TSR
+ entry DLDriveCall1 ; 32
+ entry not_supported ; 33 break state
+ entry not_supported ; 34 ???
+ entry Get_Vector ; 35
+ entry DLDriveCall1 ; 36
+ entry not_supported ; 37 ???
+ entry not_supported ; 38 country info
+ entry PathDSDXCall ; 39
+ entry PathDSDXCall ; 3A
+ entry Change_Dir ; 3B
+ entry PathDSDXCall ; 3C
+ entry PathDSDXCall ; 3D
+ entry FileHandleCall ; 3E
+ entry PassOnThrough ; 3F
+ entry PassOnThrough ; 40
+ entry PathDSDXCall ; 41
+ entry FileHandleCall ; 42
+ entry PathDSDXCall ; 43
+ entry Xenix_Status ; 44
+ entry FileHandleCall ; 45
+ entry FileHandleCall ; 46
+ entry DLDriveCall2 ; 47
+ entry not_supported ; 48 allocate memory
+ entry not_supported ; 49 free memory
+ entry not_supported ; 4A reallocate memory
+ entry ExecCall ; 4B
+ entry ExitCall ; 4C
+ entry not_supported ; 4D get return code
+ entry PathDSDXCall ; 4E
+ entry PassOnThrough ; 4F find next
+ entry set_PDB ; 50
+ entry get_PDB ; 51
+ entry not_supported ; 52 ???
+ entry not_supported ; 53 ???
+ entry PassOnThrough ; 54 get verify
+ entry not_supported ; 55 ???
+ entry XenixRename ; 56
+ entry FileHandleCall ; 57
+ entry not_supported ; 58 ???
+ entry PassOnThrough ; 59 extended error
+ entry PathDSDXCall ; 5A create unique file
+ entry PathDSDXCall ; 5B create new file
+ entry FileHandleCall ; 5C lock/unlock file access
+ entry not_supported ; 5D ???
+ entry PassOnThrough ; 5E network stuff
+ entry AssignCall ; 5F network stuff
+ entry NameTrans ; 60
+ entry not_supported ; 61 ???
+ entry get_PDB ; 62
+ entry PassOnThrough ; 63
+ entry PassOnThrough ; 64
+ entry PassOnThrough ; 65
+ entry PassOnThrough ; 66
+ entry SetMaxHandleCount ; 67
+ entry PassOnThrough ; 68
+ entry PassOnThrough ; 69
+ entry PassOnThrough ; 6a
+ entry PassOnThrough ; 6b
+ entry PathDSSICall ; 6c Extended File Open
+TableEnd = 6ch
+
+
+ifdef W_Q21
+QuickDispatchTable label word
+QD_FIRST equ 0eh
+ dw offset QuickSetDefaultDrive ;0e
+ dw offset Not_WOW_Handled ;0f
+ dw offset Not_WOW_Handled ;10
+ dw offset Not_WOW_Handled ;11
+ dw offset Not_WOW_Handled ;12
+ dw offset Not_WOW_Handled ;13
+ dw offset Not_WOW_Handled ;14
+ dw offset Not_WOW_Handled ;15
+ dw offset Not_WOW_Handled ;16
+ dw offset Not_WOW_Handled ;17
+ dw offset Not_WOW_Handled ;18
+ dw offset QuickGetDefaultDrive ;19
+ dw offset Not_WOW_Handled ;1a
+ dw offset Not_WOW_Handled ;1b
+ dw offset Not_WOW_Handled ;1c
+ dw offset Not_WOW_Handled ;1d
+ dw offset Not_WOW_Handled ;1e
+ dw offset Not_WOW_Handled ;1f
+ dw offset Not_WOW_Handled ;20
+ dw offset Not_WOW_Handled ;21
+ dw offset Not_WOW_Handled ;22
+ dw offset Not_WOW_Handled ;23
+ dw offset Not_WOW_Handled ;24
+ dw offset Not_WOW_Handled ;25
+ dw offset Not_WOW_Handled ;26
+ dw offset Not_WOW_Handled ;27
+ dw offset Not_WOW_Handled ;28
+ dw offset Not_WOW_Handled ;29
+ dw offset QuickGetDate ;2a
+ dw offset Not_WOW_Handled ;2b
+ dw offset Not_WOW_Handled ;2c
+ dw offset Not_WOW_Handled ;2d
+ dw offset Not_WOW_Handled ;2e
+ dw offset Not_WOW_Handled ;2f
+ dw offset Not_WOW_Handled ;30
+ dw offset Not_WOW_Handled ;31
+ dw offset Not_WOW_Handled ;32
+ dw offset Not_WOW_Handled ;33
+ dw offset Not_WOW_Handled ;34
+ dw offset Not_WOW_Handled ;35
+ dw offset Not_WOW_Handled ;36
+ dw offset Not_WOW_Handled ;37
+ dw offset Not_WOW_Handled ;38
+ dw offset Not_WOW_Handled ;39
+ dw offset Not_WOW_Handled ;3a
+ dw offset QuickSetCurrentDirectory ;3b
+ dw offset QuickCreate ;3c
+ dw offset QuickOpen ;3d
+ dw offset QuickClose ;3e
+ dw offset QuickRead ;3f
+ dw offset Quickwrite ;40
+ dw offset QuickDelete ;41
+ dw offset QuickLSeek ;42
+ dw offset QuickGetSetAttributes ;43
+ dw offset QuickDeviceIOCTL ;44
+ dw offset Not_WOW_Handled ;45
+ dw offset Not_WOW_Handled ;46
+ dw offset QuickGetCurrentDirectory ;47
+ dw offset Not_WOW_Handled ;48
+ dw offset Not_WOW_Handled ;49
+ dw offset Not_WOW_Handled ;4a
+ dw offset Not_WOW_Handled ;4b
+ dw offset Not_WOW_Handled ;4c
+ dw offset Not_WOW_Handled ;4d
+ dw offset QuickFindFirstFile ;4e
+ dw offset QuickFindNextFile ;4f
+ dw offset Not_WOW_Handled ;50
+ dw offset Not_WOW_Handled ;51
+ dw offset Not_WOW_Handled ;52
+ dw offset Not_WOW_Handled ;53
+ dw offset Not_WOW_Handled ;54
+ dw offset Not_WOW_Handled ;55
+ dw offset Not_WOW_Handled ;56
+ dw offset QuickFileDateTime ;57
+ dw offset Not_WOW_Handled ;58
+ dw offset QuickExtendedError ;59
+ dw offset Not_WOW_Handled ;5a
+ dw offset Not_WOW_Handled ;5b
+ dw offset QuickLock ;5c
+QD_LAST equ 5ch
+
+sEnd CODE
+
+sBegin DATA
+QuickDispatchAddr dw ?
+sEnd DATA
+
+sBegin CODE
+endif
+
+;-----------------------------------------------------------------------;
+; ;
+; Interrupt 21h handler. ;
+; ;
+;-----------------------------------------------------------------------;
+
+labelFP <PUBLIC,Int21Handler>
+
+;-----------------------------------------------------------------------;
+; Int21Entry ;
+; ;
+; The is the dispatcher for our INT 21h handler. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:48:06 -by- David N. Weise [davidw] ;
+; Made it use a jump table!! ;
+; ;
+; Thu Apr 16, 1987 07:44:19p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Int21Entry,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ cmp fInt21, 0
+ je not_me
+ pop ds
+ UnSetKernelDS
+ inc bp
+ push bp
+ mov bp, sp
+ push ds
+ push bx ; Will be exchanged later
+ SetKernelDS
+ cmp ah,12h
+ jbe dont_reset_InDOS
+ mov Kernel_InDOS,0
+ mov Kernel_InINT24,0
+dont_reset_InDOS:
+ cmp Kernel_InDOS,0
+ jz not_in_INT24
+ mov kernel_InINT24,1
+not_in_INT24:
+ifndef WOW ; FOR WOW All the Profile Stuff is handled by Win 32
+ ;** On every DOS call, the profile string buffers may become stale
+ ;** in case the app does a DOS call on the INI file.
+ ;** We set the stale profile file and on the next profile read
+ ;** or write, we will check to see if the file is dirty.
+ ;** 27-Nov-1991 [JonT]
+ mov ds:[fProfileMaybeStale], 1
+
+ ;** In a similar situation to the above, DOS calls done after
+ ;** profile string calls but before task switches may depend on
+ ;** the data being flushed to the INI file from the buffer.
+ ;** So, here we do a fast check to see if the profile buffers
+ ;** have unflushed information. If they do, we flush them.
+ ;** Note that 2 is PROUNCLEAN taken from UP.C
+ ;** 27-Nov-1991 [JonT]
+ test WinIniInfo.ProFlags, 2 ;Win.INI dirty?
+ jnz I21_Flush_It ;Yes, flush it
+ test PrivateProInfo.ProFlags, 2 ;Private profile dirty?
+ jz I21_Done_Flushing ;No. Neither.
+
+ ;** When writing out profiles we trash pretty much all the registers
+ ;** and since we can't do this for a DOS call, we save everything
+I21_Flush_It:
+ cmp fWriteOutProfilesReenter, 0 ;Ignore if reentering
+ jne I21_Done_Flushing ; because of profile strings
+ pusha
+ push es
+if PMODE32
+ .386
+ push fs
+ push gs
+endif
+ cCall WriteOutProfiles
+if PMODE32
+ pop gs
+ pop fs
+ .286p
+endif
+ pop es
+ popa
+endif ; NOT WOW
+I21_Done_Flushing:
+
+ mov bx, CODEOffset PassOnThrough
+ cmp ah,TableEnd ; Table is for call 0Eh to 6ch
+ ja let_it_go
+ cmp ah, 0Eh
+ jb let_it_go
+ mov bh, 0
+ mov bl, ah
+ add bx, bx ; Word index in bx
+ mov bx, word ptr DosTrap1[bx][-0Eh*2]
+let_it_go:
+ xchg bx, [bp-4] ; 'pop bx' and push proc addr
+ mov ds, [bp-2] ; Restore DS
+ UnSetKernelDS
+if 1 ; PMODE32 - always want to avoid sti in WOW
+ push ax
+ pushf
+ pop ax
+ test ah, 2
+ pop ax
+ jnz short ints_are_enabled
+endif ; WOW
+ FSTI
+ints_are_enabled:
+ ret
+not_me:
+ pop ds
+;;; jmp prevInt21Proc
+ call real_dos
+ retf 2
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; not_supported
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 06-Aug-1989 13:26:19 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc not_supported,<PUBLIC,NEAR>
+cBegin nogen
+ jmps PassOnThrough
+;;; cmp ah,55h
+;;; jnz @F
+;;; jmp PassOnThrough
+;;;@@: int 3
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; PassOnThrough ;
+; ;
+; This doesn't quite pass on through anymore. It calls down to DOS. ;
+; In this fashion we know when we are in DOS. In addition this routine ;
+; does the delayed binding of DOS variables after task switches. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sun 25-Mar-1990 15:31:49 -by- David N. Weise [davidw] ;
+; added the check for 2Fh, GetDTA, so that the correct one is gotten! ;
+; ;
+; Tue Feb 03, 1987 10:32:25p -by- David N. Weise [davidw] ;
+; Put in the delayed binding of DOS variables. ;
+; ;
+; Tue Feb 03, 1987 10:26:01p -by- David N. Weise [davidw] ;
+; Rewrote it and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+f_iret:
+ FIRET
+
+cProc PassOnThrough,<PUBLIC,NEAR>
+cBegin nogen
+
+ SetKernelDS
+ test Kernel_Flags,KF_restore_disk
+ jnz maybe_restore_disk
+
+PUBLIC final_call_for_DOS
+final_call_for_DOS:
+ pop ds
+ UnSetKernelDS
+ push [bp][6]
+ and [bp][-2],NOT CPUF_TRAP
+ popf ; Correct input flags back in flags
+ pop bp
+ dec bp
+ call real_DOS
+ push bp ; pass back the correct flags
+ mov bp,sp
+ pushf
+ pop [bp][6]
+if 1 ; PMODE32 - always for WOW
+ test [bp][6], 200h ; Interrupts on?
+ pop bp
+ jnz short no_sti
+else
+ pop bp
+endif
+ FSTI
+no_sti:
+ jmp f_iret
+
+maybe_restore_disk:
+
+; Note, caller's DS is on stack, current DS == kernel DS
+
+ cmp ah,2Fh ; get DTA, don't hit disk but
+ jz OnThrough ; DTA must be set correctly!
+
+ cmp ah,29h ; for system calls 29h -> 30h ....
+ jb OnThrough
+ cmp ah,30h ; don't restore directory...
+ jbe final_call_for_DOS ; ...they don't hit disk
+
+ cmp ah,3Fh ; file handle read
+ jz final_call_for_DOS
+ cmp ah,40h ; file handle write
+ jz final_call_for_DOS
+ cmp ah,50h ; for system calls 50h -> 51h ....
+ jz final_call_for_DOS
+ cmp ah,51h ; don't restore directory...
+ jz final_call_for_DOS ; ...they don't hit disk
+
+; restore the DOS environment
+
+OnThrough:
+ push ax
+ push bx
+ push dx
+ push es
+
+ SetKernelDS es
+ cmp [CurTDB], 0
+ je DeadTDB
+ and Kernel_Flags,NOT KF_restore_disk
+ mov ds,[CurTDB]
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jz @F
+DeadTDB:
+ jmp done_restoring_dos
+@@:
+
+; restore DTA
+
+ mov ax,ds:[TDB_DTA].sel
+ mov dx,ds:[TDB_DTA].off
+ cmp dx,curDTA.off
+ jnz restore_DTA
+ cmp ax,curDTA.sel
+ jz dont_restore_DTA
+restore_DTA:
+ mov curDTA.sel,ax
+ mov curDTA.off,dx
+ push ds
+ mov ds,ax
+ mov ah,1Ah
+ call real_DOS
+ pop ds
+dont_restore_DTA:
+
+
+; restore drive and directory
+
+;-----------------------------------------------------------------------;
+; We now need to perform a little check. ;
+; On DOS >= 3.20 it is possible that the phantom drive state ;
+; has changed since we stored this tasks current drive and current ;
+; directory in his task header. UNDER NO CIRCUMSTANCES do we want ;
+; to SetDrive or CHDIR on a phantom drive if the first level of hooks ;
+; are in (to allow this results in the "Please Insert Disk..." message) ;
+; so we check out the SetDrive drive number. ;
+; If it is phantom we will NOT restore drive or directory. ;
+;-----------------------------------------------------------------------;
+
+ xor dx,dx
+ mov dl,ds:[TDB_Drive]
+ and dl,01111111b
+ mov bx,dx ; Index into PhantArray
+ CheckKernelDS es
+ cmp byte ptr PhantArray[bx],0
+ jnz done_restoring_dos
+no_drive_check:
+
+ mov ax,ds
+ cmp ax,cur_drive_owner
+ jz hasnt_been_changed
+
+ inc InScheduler ; prevent Int 24h dialog boxes
+
+ lar ax, cur_drive_owner ; Ensure we have valid TDB
+ jnz restore_dos ; in cur_drive_owner
+ test ah, DSC_PRESENT
+ jz restore_dos
+ lsl ax, cur_drive_owner
+ cmp ax, TDBsize-1
+ jb restore_dos
+ push es
+ mov es, cur_drive_owner
+ UnsetKernelDS es
+ cmp es:[TDB_sig], TDB_SIGNATURE
+ jne restore_dos0 ; Dead TDB, can't compare
+ mov al, es:[TDB_Drive]
+ and al,01111111b
+ cmp al, dl
+ jne restore_dos0 ; Drive the same?
+
+ push cx ; Compare directories
+ push si
+ push di
+ mov si, TDB_LFNDirectory
+ mov di, si
+ xor al, al ; Scan for end of string
+ mov cx, size TDB_LFNDirectory
+ cld
+ repne scasb
+ mov cx, di ; Calculate length
+ sub cx, si
+
+ mov di, si
+ rep cmpsb
+ pop di
+ pop si
+ pop cx
+ pop es
+ ResetKernelDS es
+ jnz restore_directory ; We know the drive is the same
+ jmps have_new_owner
+
+
+restore_dos0:
+ pop es
+restore_dos:
+ mov ah,0Eh
+ call real_DOS ; select the disk
+
+restore_directory:
+ mov dx,TDB_LFNDirectory
+ mov ah,3Bh
+ call real_DOS ; change directory
+
+have_new_owner:
+ dec InScheduler ; allow int 24's
+ mov cur_drive_owner,ds
+hasnt_been_changed:
+
+done_restoring_dos:
+ pop es
+ UnSetKernelDS es
+ pop dx
+ pop bx
+ pop ax
+ jmp final_call_for_DOS
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; real_DOS ;
+; ;
+; Calls the real DOS. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:45:48 -by- David N. Weise [davidw] ;
+; Removed WinOldApp support. ;
+; ;
+; Mon Apr 20, 1987 07:59:00p -by- R. O. [ ] ;
+; Set cur_dos_PDB when we call DOS to change it, for efficiency. ;
+; ;
+; Sun Jan 11, 1987 07:18:19p -by- David N. Weise [davidw] ;
+; Put the per task maintenance of ^C here instead of in the switcher. ;
+; ;
+; Sun Jan 04, 1987 01:19:16p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc far_real_dos,<PUBLIC,FAR>
+cBegin nogen
+ call real_dos
+ ret
+cEnd nogen
+
+cProc real_dos,<PUBLIC,NEAR>
+cBegin nogen
+ pushf
+ push ds
+ SetKernelDS
+ mov Kernel_InDOS,1
+
+ push bx
+if KDEBUG
+ cmp ah, 50h ; SET PSP
+ jne OK_PDB ; No, all's fine
+ cmp bx, Win_PDB ; It is Win_PDB, isn't it?
+ je OK_PDB
+ int 3
+ int 3
+OK_PDB:
+endif
+ mov bx, Win_PDB
+ cmp bx, cur_dos_PDB
+ je PDB_ok
+
+ push ax
+ mov cur_dos_PDB,bx
+ifdef W_Q21
+ call SetPDBForDOS
+else
+
+ mov ah,50h
+ pushf
+ifndef WOW
+ife PMODE32
+ FCLI
+endif
+endif
+if ROM
+ call prevInt21Proc
+else
+ call cs:prevInt21Proc ; JUMP THROUGH CS VARIABLE
+endif
+endif ;WOW
+ pop ax
+
+
+PDB_OK:
+ pop bx
+
+
+ifdef TraceInt21 ; <<< Only Useful when debugging fileio routine >>>
+
+ cmp fBooting,1
+ jz @f
+
+ krDebugOut DEB_WARN, "DOS Call #AX bx #BX cx #CX dx #DX"
+
+ cmp ah,3dh ; Open ?
+ jnz @f
+
+ pop ds ; USERs DS
+ push ds
+ UnSetKernelDS
+
+ krDebugOut DEB_WARN,"Opening File @DS:DX"
+
+ SetKernelDS
+@@:
+
+ cmp ah,3ch ; Create ?
+ jnz @f
+
+ pop ds ; USERs DS
+ push ds
+ UnSetKernelDS
+
+ krDebugOut DEB_WARN,"Creating File @DS:DX"
+
+ SetKernelDS
+@@:
+
+endif
+
+
+ifdef W_Q21
+; If we are the running in protected mode then there is no need to
+; switch to v86 mode and then to call the DOSKrnl for most Int 21
+; operations - since mode switches are slow and DOSX has to read
+; into a buffer in low memory and copy it high. Since we just want
+; to call the Win32 file system we can stay in protected mode.
+; For some DOS calls which don't happen very frequently we don't
+; bother intercepting them.
+
+ cmp ah,59h ; GetExtendedError ?
+ jz short @f
+ mov WOWLastError,0h
+@@:
+
+;-----------------------------------------------------------------------------
+; Dispatch code for WOW quick entry points
+;-----------------------------------------------------------------------------
+
+ cmp ah, QD_FIRST
+ jb really_call_dos
+ cmp ah, QD_LAST
+ ja really_call_dos
+ push bx
+ xor bh, bh
+ mov bl, ah
+ sub bx, QD_FIRST
+ shl bx, 1
+ mov bx, QuickDispatchTable[bx]
+ mov QuickDispatchAddr, bx
+ pop bx
+ jmp word ptr QuickDispatchAddr
+
+really_call_dos:
+ jmp Not_WOW_Handled
+
+;-----------------------------------------------------------------------------
+; WOW quick entry points
+;-----------------------------------------------------------------------------
+
+QuickDelete:
+ push dx
+ push bx
+ push ax
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+
+ cCall WOWDelFile,<BX,DX>
+
+; DX = FFFF, AX = Error Code if failure
+; AX = 0 if success
+
+ inc dx
+ jnz qdf_ok
+
+ jmp DoDos
+
+qdf_ok:
+ pop ax
+ pop bx
+ pop dx
+ jmp QuickDone
+
+ regptr cxdx,cx,dx
+ regptr axdx,ax,dx
+
+QuickExtendedError:
+ cmp WOWLastError,0
+ jnz DoExtendedError
+ jmp Not_WOW_Handled
+
+DoExtendedError:
+ mov ax,WOWLastError ;load values for extended error
+ mov bh,WOWErrClass
+ mov bl,WOWErrAction
+ mov ch,WOWErrLocation ; location
+ jmp QuickDone
+
+QuickGetDate:
+ cCall WowGetCurrentDate
+ push dx ;year
+ mov dl, ah ;monthday
+ mov ah, al ;
+ mov cl, 4 ;shift count
+ shr ah, cl
+ mov dh, ah ;month
+ and al, 0fh ;weekday
+ mov ah, 2ah ;reload ah
+ pop cx ;cx is now the year
+ jmp QuickDone
+
+
+QuickGetDefaultDrive:
+ call GetDefaultDriveFromDOS
+ mov CurDOSDrive, al
+ jmp QuickDone
+
+GetDefaultDriveFromDOS:
+ push di
+ push es
+ les di, pPMDosCURDRV
+ mov al, byte ptr es:[di] ;get drive number from DOS
+ pop es
+ pop di
+ ret
+
+QuickSetPSPAddress:
+ call SetPDBForDOS
+ jmp QuickDone
+
+SetPDBForDOS:
+ push es
+ push di
+ push cx
+ push dx
+ push bx
+
+ DPMICALL 0006h ; Get physical address
+
+ mov bx,cx ; hiword of address
+ mov cx,4 ; shift count
+ shr dx,cl
+ mov cx,12 ; for high nibble
+ shl bx,cl
+ or dx,bx ; now real mode segment
+
+ les di, pPMDosPDB ; get pointer to PDB in DOS
+ mov word ptr es:[di],dx ; set new PDB
+
+ pop bx
+ pop dx
+ pop cx
+ pop di
+ pop es
+ ret
+
+QuickSetDefaultDrive:
+ push dx
+ push ax
+
+ call GetDefaultDriveFromDOS
+ cmp dl, al ;doing a NOP?
+ jz short @f ;yes, skip call to WOW
+
+ cCall WowSetDefaultDrive,<DX>
+
+ mov CurDOSDrive, al ;returned from SetDefaultDrive
+@@:
+ pop ax
+ mov al, 26 ;this is what DOS does
+ pop dx
+ jmp QuickDone
+
+QuickGetCurrentDirectory:
+ push ax
+ push dx
+ push bx
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+
+ cCall WowGetCurrentDirectory,<DX,BX,SI>
+
+ pop bx
+ inc dx ;DX=FFFF on error
+ pop dx
+ jz short qgcd_err ;jif error
+ pop ax
+ mov al, 0 ;this is what DOS does
+ jmp QuickDone
+
+QuickSetCurrentDirectory:
+ push ax
+ push dx
+ push bx
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+
+ cCall WowSetCurrentDirectory,<BX,DX>
+
+ pop bx
+ inc dx ;DX=FFFF on error
+ pop dx
+ jz short qgcd_err ;jif error
+ pop ax
+ mov al, 0 ;BUGBUG is this what DOS does?
+ jmp QuickDone
+
+qgcd_err:
+ add sp, 2 ;leave error code in AX
+ mov WOWLastError,ax ;use this for filefind errors
+ mov WOWErrClass,1 ;this is what DOS seems to do
+ mov WOWErrAction,1ch
+ mov WOWErrLocation,9
+ jmp QErrRet
+
+QuickDeviceIOCTL:
+ cmp al, 8 ;removeable media only
+ jz short @f
+ jmp Not_WOW_Handled
+@@:
+ push dx
+
+ cCall WowDeviceIOCTL,<BX,AX>
+
+ inc dx
+ pop dx
+ jnz short @f
+ jmp QErrRet
+@@:
+ jmp QuickDone
+
+
+QuickFindFirstFile:
+ push dx
+ push bx
+ push si
+ push di
+ mov si, curDTA.sel
+ mov di, curDTA.off
+ mov bx,sp
+ mov bx,ss:[bx + 8] ; BX = USER DS
+
+ifdef TraceInt21 ; <<< Only Useful when debugging fileio routine >>>
+
+ cmp fBooting,1
+ jz @f
+
+ mov ds,bx ; USERs DS
+ UnSetKernelDS
+ krDebugOut DEB_WARN, "QuickFindFirstFile looking for @DS:DX"
+ SetKernelDS
+@@:
+endif
+
+ cCall WowFindFirst,<CX,BX,DX,SI,DI>
+
+ifdef TraceInt21 ; <<< Only Useful when debugging fileio routine >>>
+
+ or ax, ax
+ jnz @f
+ mov bx, curDTA.off
+ mov si, curDTA.sel
+ mov ds, si
+ UnSetKernelDS
+ mov si, bx
+ mov bx, 18h
+ mov di, [si+bx]
+ mov bx, 16h
+ mov dx, [si+bx]
+ mov bx, 1Eh
+ add bx, si
+ krDebugOut DEB_WARN, "QuickFindFirstFile found @DS:BX, date #DI, time #DX"
+ mov bx, 1Ah
+ mov di, [si+bx]
+ mov bx, 1Ch
+ mov dx, [si+bx]
+ mov bx, 15h
+ mov bl, [si+bx]
+ xor bh, bh
+ krDebugOut DEB_WARN, " attribute #BX size #DX:#DI"
+ SetKernelDS
+@@:
+endif
+
+ pop di
+ pop si
+ pop bx
+ pop dx
+ or ax, ax
+ jnz qfErr
+ jmp QuickDone
+
+QuickFindNextFile:
+ push si
+ push di
+
+ mov si, curDTA.sel
+ mov di, curDTA.off
+ cCall WowFindNext,<SI,DI>
+ pop di
+ pop si
+ or ax, ax
+ jnz qfErr
+ jmp QuickDone
+qfErr:
+ mov WOWLastError,ax ;use this for filefind errors
+ mov WOWErrClass,8
+ mov WOWErrAction,3 ; file or item not found, prompt user
+ mov WOWErrLocation,2 ; location is block device
+ jmp QErrRet
+
+QuickLSeek:
+ push dx
+ push bx
+ push ax
+
+ xor ah,ah
+ cCall WowFileLSeek,<BX,CXDX,AX,cur_dos_PDB,0,pFileTable>
+
+; DX:AX = File Position if success
+; DX = FFFF, AX = Error Code if failure
+
+ inc dx
+ jnz LSeekFinish
+ jmp DoDos
+LSeekFinish:
+ dec dx
+ add sp,6
+ jmp QuickDone
+
+QuickCreate:
+ push dx
+ push bx
+ push ax
+
+ test cx, 8 ; ATTR_VOLUME?
+ jz short @f ; no, ok
+ jmp DoDos ; yes, not supported in wow32
+@@:
+
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+ cCall WowFileCreate,<CX,BX,DX,cur_dos_PDB,0,pFileTable>
+
+; AX = FileHandle if success
+; AX = FFFF if path was a device
+; DX = FFFF, AX = Error Code if failure
+
+ cmp ax,0FFFFh
+ jnz short @f ;
+ jmp DoDos ; Device case, just go through DOS
+@@:
+ inc dx ; Set the zero flag on error.
+ jz QOpenError ; Error occured
+ add sp,2 ; discard AX
+ pop bx
+ pop dx
+ifdef TraceInt21
+ jmp QuickDone ; Success
+else
+ jmps QuickDone ; Success
+endif
+
+QuickOpen:
+ push dx
+ push bx
+ push ax
+
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+ xor ah,ah ; clear AH leaving file-access in AX
+ cCall WowFileOpen,<BX,DX,AX,cur_dos_PDB,0,pFileTable>
+
+; AX = FileHandle if success
+; AX = FFFF if path was a device
+; DX = FFFF, AX = Error Code if failure
+
+ cmp ax,0FFFFh
+ifdef TraceInt21
+ jnz @f
+ jmp DoDos
+@@:
+else
+ jz DoDos ; Device case, just go through DOS
+endif
+ inc dx ; Set the zero flag on error.
+ jz QOpenError ; Error occured
+ add sp,2 ; discard AX
+ pop bx
+ pop dx
+ jmps QuickDone ; Success
+
+QOpenError:
+ cmp ax, 3 ; If the error is not file_not_found or path_not_found
+ifdef TraceInt21
+ jbe @f
+ jmp DoDos
+@@:
+else
+ ja DoDos ; then go through DOS again for the open.
+endif
+ cmp ax, 2
+ jb DoDos
+
+ mov WOWLastError,ax
+ mov WOWErrClass,8
+ mov WOWErrAction,3 ; file or item not found, prompt user
+ mov WOWErrLocation,2 ; location is block device
+
+ add sp,2 ; discard saved AX, since AX = Error Code
+ pop bx
+ pop dx
+QErrRet:
+ifdef TraceInt21
+ krDebugOut DEB_WARN, "Q21 fails AX #AX bx #BX cx #CX dx #DX (t)"
+endif
+ pop ds
+ popf
+ stc ; Set Carry = ERROR
+ ret
+
+QuickRead:
+ pop ax ; AX = USER DS
+ push ax
+ push dx ; save user pointer
+ cCall WowFileRead,<BX,AXDX,0,CX,cur_dos_PDB,0,pFileTable>
+
+; AX = Number Bytes Read
+; DX = FFFF, AX = Error Code
+
+ inc dx
+ pop dx ; restore user pointer
+ jz QRError
+QuickDone:
+ifdef TraceInt21
+ krDebugOut DEB_WARN, "Q21 succeeds AX #AX bx #BX cx #CX dx #DX (t)"
+endif
+ pop ds
+ popf
+ clc ; Clear Carry - OK Read
+ ret
+
+QuickClose:
+ push dx
+ push bx
+ push ax
+ cCall WowFileClose,<BX,cur_dos_PDB,0,pFileTable>
+
+; DX = FFFF, AX = Error Code if failure
+; AX = FFFF if path was a device
+
+ cmp ax,0FFFFh
+ jz DoDos ; Device opens go through DOS
+ inc dx ; Sets zero flag on error.
+ jz DoDos ; Let DOS Handle Close Errors
+ pop bx ; Throw old AX out
+ pop bx
+ pop dx
+ mov ah,3Eh ; bogus multiplan fix
+ jmps QuickDone ; Success
+
+DoDos:
+ pop ax
+ pop bx
+ pop dx
+ jmp Not_WOW_Handled
+
+QRError:
+ mov ah,3Fh ; On Error Retry Operation Via DOEem
+ jmp Not_WOW_Handled
+
+QuickGetSetAttributes:
+ cmp al, 0
+ jz short qget_attr
+ cmp al, 1
+ jz short qset_attr
+ jmp Not_WOW_Handled
+
+qget_attr:
+ push dx
+ push bx
+ push ax
+
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+ cCall WowFileGetAttributes,<BX,DX>
+
+; AX = Attributes if success
+; DX = FFFF, AX = Error Code if failure
+
+ inc dx
+ jz DoDos ; if failure retry through DOS
+ mov cx,ax ; move result into CX
+ pop ax
+ pop bx
+ pop dx
+ jmp QuickDone
+
+qset_attr:
+ push dx
+ push bx
+ push ax
+
+ mov bx,sp
+ mov bx,ss:[bx + 6] ; BX = USER DS
+ cCall WowFileSetAttributes,<CX,BX,DX>
+
+; DX = FFFF, AX = Error Code if failure
+
+ inc dx
+ jz DoDos ; if failure retry through DOS
+ pop ax
+ pop bx
+ pop dx
+ jmp QuickDone
+
+
+QuickFileDateTime:
+ cmp al, 0
+ jz short qget_datetime
+ cmp al, 1
+ jz short qset_datetime
+ jmp Not_WOW_Handled
+
+qget_datetime:
+ push dx
+ push bx
+ push ax
+ cCall WowFileGetDateTime,<BX,cur_dos_PDB,0,pFileTable>
+
+; AX = Time, DX = Date if success
+; AX = FFFF if failure
+
+ cmp ax,0FFFFh
+ jz DoDos
+ mov cx,ax
+ pop ax
+ pop bx
+ add sp,2 ; throw away saved DX
+ jmp QuickDone
+
+qset_datetime:
+ push dx
+ push bx
+ push ax
+ cCall WowFileSetDateTime,<BX,CX,DX,cur_dos_PDB,0,pFileTable>
+
+; AX = 0 if success
+; AX = FFFF if failure
+
+ cmp ax,0FFFFh
+ jnz short @f
+ jmp DoDos
+@@:
+ pop ax
+ pop bx
+ pop dx
+ jmp QuickDone
+
+QuickLock:
+ push dx
+ push bx
+ push ax
+ cCall WowFileLock,<AX,BX,CX,DX,SI,DI,cur_dos_PDB,0,pFileTable>
+
+; DX = FFFF, AX = Error Code if failure
+; AX = 0 if success
+
+ inc dx
+ jnz FinishLock
+ cmp ax, 21h ;is this lock violation?
+ jz short @f ;yes, give it back to app
+ jmp DoDos
+@@:
+ add sp,2 ; discard saved AX, since AX = Error Code
+ pop bx
+ pop dx
+ mov WOWLastError,ax
+ mov WOWErrClass,10 ;ext. err info for lock violation
+ mov WOWErrAction,2
+ mov WOWErrLocation,2
+ jmp QErrRet
+
+FinishLock:
+ add sp,2 ; throw out old AX
+ pop bx
+ pop dx
+ jmp QuickDone
+
+QuickWrite:
+ pop ax ; AX = USER DS
+ push ax
+ push dx
+ cCall WowFileWrite,<BX,AXDX,0,CX,cur_dos_PDB,0,pFileTable>
+
+; AX = Number Bytes Read
+; DX = FFFF, AX = Error Code
+
+ inc dx
+ pop dx ; restore user pointer
+ jz RetryWrite
+ jmp QuickDone
+
+RetryWrite:
+ mov ah,40h ; On Error Retry Operation Via DOEem
+
+;-----------------------------------------------------------------------------
+; END OF WOW quick entry points
+;-----------------------------------------------------------------------------
+
+Not_WOW_Handled:
+endif ; W_Q21
+
+;
+; Intercept Select Disk and Get Current Disk
+;
+ cmp ah, 0Eh
+ je rd_Select
+ cmp ah, 19h
+ je rd_Get
+rd_no_intercept:
+
+;;; test Kernel_flags,kf_restore_CtrlC
+;;; jz no_need_to_set_CtrlC
+;;; and Kernel_flags,not kf_restore_CtrlC
+;;;
+;;; push ax
+;;; push bx
+;;; push es
+;;; mov es,curTDB
+;;; cmp es:[TDB_sig],TDB_SIGNATURE
+;;; jne PDB_okay
+;;;
+; restore PDB
+;;;
+;;; mov bx,Win_PDB
+;;; cmp bx,cur_dos_PDB
+;;; jz PDB_okay
+;;;if KDEBUG
+;;; cmp bx,es:[TDB_PDB]
+;;; jz @F
+;;; int 1
+;;;@@:
+;;;endif
+;;; mov cur_dos_PDB,bx
+;;; mov ah,50h
+;;; pushf
+;;;ife PMODE32
+;;; cli
+;;;endif
+;;; call cs:prevInt21Proc ; JUMP THROUGH CS VARIABLE
+;;;PDB_okay:
+;;;
+;;; pop es
+;;; pop bx
+;;; pop ax
+;;;no_need_to_set_CtrlC:
+
+ pop ds
+ UnSetKernelDS
+ifndef WOW
+ife PMODE32
+ FCLI
+endif
+endif
+if ROM
+ cCall <far ptr PrevROMInt21Proc>
+else
+ call cs:prevInt21Proc ; JUMP THROUGH CS VARIABLE
+ifdef TraceInt21
+ pushf
+ jc rd_Trace_CarrySet
+ krDebugOut DEB_WARN, "DOS succeeds AX #AX bx #BX cx #CX dx #DX"
+ jmp @f
+rd_Trace_CarrySet:
+ krDebugOut DEB_WARN, "DOS fails AX #AX bx #BX cx #CX dx #DX"
+@@:
+ popf
+endif
+endif
+rd_after_DOS:
+ push ds
+ SetKernelDS
+rd_after_DOS1:
+ push ax
+ mov al,kernel_inINT24
+ mov Kernel_InDOS,al ; dont change flags!
+ pushf
+ or al, al ; If in int 24h, don't
+ jnz @F ; reset extended error yet
+ cmp LastExtendedError[2],-1 ; Flag to indicate saved status
+ je @F
+
+ push dx
+ lea dx, LastExtendedError
+ mov ax, 5D0Ah
+ pushf
+if ROM
+ call prevInt21Proc
+else
+ call cs:prevInt21Proc
+endif
+ mov LastExtendedError[2], -1 ; Forget the status
+ pop dx
+@@:
+ popf
+ pop ax
+ pop ds
+ UnSetKernelDS
+ ret
+
+rd_Select:
+ ReSetKernelDS
+ cmp dl, CurDOSDrive ; Setting to current drive?
+ jne rd_invalidate ; no, invalidate saved value
+
+ mov al, DOSDrives ; yes, emulate call
+
+rd_intercepted:
+ pop ds ; Return from the DOS call
+ UnSetKernelDS
+ popf
+ jmps rd_after_DOS
+
+rd_invalidate:
+ ReSetKernelDS
+ mov CurDOSDrive, 0FFh ; Invalidate saved drive
+ jmps rd_no_intercept
+
+rd_Get:
+ ReSetKernelDS
+ cmp CurDOSDrive, 0FFh ; Saved drive invalid?
+ jne rd_have_drive ; no, return it
+
+ pop ds ; yes, call DOS to get it
+ UnSetKernelDS
+ifndef WOW
+ife PMODE32
+ FCLI
+endif
+endif
+if ROM
+ cCall <far ptr PrevROMInt21Proc>
+else
+ call cs:prevInt21Proc
+endif
+ push ds
+ SetKernelDS
+ mov CurDOSDrive, al ; And save it
+ jmps rd_after_DOS1
+
+rd_have_drive:
+ ReSetKernelDS
+ mov al, CurDOSDrive ; We have the drive, emulate call
+ jmps rd_intercepted ; and return
+
+cEnd nogen
+
+if ROM ;----------------------------------------------------------------
+
+
+;-----------------------------------------------------------------------;
+; PrevROMInt21Proc ;
+; ;
+; Calls the routine pointed to by the PrevInt21Proc DWORD. Used by ;
+; ROM Windows kernel to when PrevInt21Proc is not a CS variable, and ;
+; kernel's DS is not addressable. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc PrevROMInt21Proc,<PUBLIC,FAR>
+cBegin nogen
+
+ push ds
+ SetKernelDS
+
+ push bp
+ mov bp,sp
+
+ push PrevInt21Proc.sel
+ push PrevInt21Proc.off
+
+ mov ds,[bp][2]
+ UnSetKernelDS
+ mov bp,[bp]
+ retf 4
+
+cEnd nogen
+
+
+endif ;ROM ---------------------------------------------------------
+
+
+;**
+;
+; NoHookDOSCall -- Issue an INT 21 circumventing all Windows Hooks
+;
+; This call is provided as a Kernel service to Core routines
+; which wish to issue DOS INT 21h calls WITHOUT the intervention
+; of the Windows INT 21h hooks.
+;
+; ENTRY:
+; All registers as for INT 21h
+;
+; EXIT:
+; All registers as for particular INT 21h call
+;
+; USES:
+; As per INT 21h call
+;
+;
+cProc NoHookDOSCall,<PUBLIC,FAR>
+cBegin
+ call real_DOS
+cEnd
+
+
+;**
+;
+; DOS3CALL -- Issue an INT 21 for caller
+;
+; This call is provided as a Kernel service to applications that
+; wish to issue DOS INT 21h calls WITHOUT coding an INT 21h, which
+; is incompatible with protected mode.
+;
+; ENTRY:
+; All registers as for INT 21h
+;
+; EXIT:
+; All registers as for particular INT 21h call
+;
+; USES:
+; As per INT 21h call
+;
+;
+cProc DOS3CALL,<PUBLIC,FAR>
+cBegin nogen
+ DOSCALL
+ retf
+cEnd nogen
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/i21file.asm b/private/mvdm/wow16/kernel31/i21file.asm
new file mode 100644
index 000000000..c549a0872
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/i21file.asm
@@ -0,0 +1,862 @@
+ title INT21 - INT 21 handler for scheduler
+
+.xlist
+include kernel.inc
+include tdb.inc
+include pdb.inc
+include eems.inc
+include kdos.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+externFP FileCDR_notify
+
+DataBegin
+
+externB PhantArray
+externB DOSDrives
+externB CurDOSDrive
+externW curTDB
+
+DataEnd
+
+assumes DS,NOTHING
+sBegin CODE
+assumes CS,CODE
+
+;externNP GrowSFT
+externNP PassOnThrough
+externNP final_call_for_DOS
+externNP real_DOS
+externNP MyUpper
+externNP Int21Handler
+
+ifdef DBCS
+externNP MyIsDBCSLeadByte ;near call is fine
+endif
+
+externFP ResidentFindExeFile
+externFP GetModuleHandle
+externFP FlushCachedFileHandle
+externFP WOWDelFile
+
+public ASSIGNCALL
+public NAMETRANS
+public DLDRIVECALL1
+public DLDRIVECALL2
+public XENIXRENAME
+public FCBCALL
+public PATHDSDXCALL
+public PATHDSSICALL
+public SetCarryRet
+public SetErrorDrvDSDX
+
+
+;-----------------------------------------------------------------------;
+; Select_Disk (DOS Call 0Eh) ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Jan 28, 1987 00:40:48a -by- David N. Weise [dnw] ;
+; Rewrote it. It used to save and restore the current disk inside of ;
+; DOS on task swaps. Now it will restore on demand. ;
+; ;
+; Sat Jan 17, 1987 08:19:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Select_Disk,<PUBLIC,NEAR>
+cBegin nogen
+ SetKernelDS
+ cmp dl, CurDOSDrive ; Must set if not this!
+ jne MustSetIt
+ ; See if it matches saved drive for TDB
+ cmp [CurTDB], 0 ; See if we have a TDB
+ je MustSetIt
+ push es
+ mov es, [CurTDB]
+ cmp es:[TDB_sig], TDB_SIGNATURE
+ jne DeadTDB
+ push ax
+ mov al, es:[TDB_Drive]
+ and al, 7Fh ; Zap save drive flag
+ cmp al, dl ; Drive the same?
+ pop ax
+ pop es
+ jne MustSetIt ; no, set it
+ mov al, DOSDrives ; Return number of logical drives
+ jmp DriveErrorRet ; Well, it really just returns!
+DeadTDB:
+ pop es
+MustSetIt:
+ push dx
+ inc dx ; A=1
+ call CheckDriveDL
+ pop dx
+ jnc cd_no_drive_check
+ call SetErrorDLDrv
+ jmp DriveErrorRet
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Change_Dir (DOS Call 3Bh) ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Jan 28, 1987 00:40:48a -by- David N. Weise [dnw] ;
+; Rewrote it. It used to save and restore the current directory ;
+; on task swaps. Now it will restore on demand. ;
+; ;
+; Sat Jan 17, 1987 08:21:13p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Change_Dir,<PUBLIC,NEAR>
+cBegin nogen
+ call PathDrvDSDX
+ jnc cd_no_drive_check ; Drive OK
+ call SetErrorDrvDSDX
+ jmp SetCarryRet
+cd_no_drive_check:
+ SetKernelDS
+ mov ds,CurTDB
+ UnSetKernelDS
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jne Change_Dir1
+ and ds:[TDB_Drive],01111111b ; indicate save needed
+Change_Dir1:
+ jmp PassOnThrough
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; FileHandleCall (DOS Calls 3Eh,42h,45h,46h,57h,5Ch) ;
+; ;
+; Checks to see if the token in the PDB is 80h. 80h represents a ;
+; file that was closed on a floppy by us in order to prompt for a ;
+; file (see CloseOpenFiles). If the token is 80h then it is set ;
+; to FFh. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Sep 29, 1987 03:30:46p -by- David N. Weise [davidw] ;
+; Changed the special token from FEh to 80h to avoid conflict with ;
+; Novell netware that starts with SFT FEh and counts down. ;
+; ;
+; Tue Apr 28, 1987 11:12:00a -by- Raymond E. Ozzie [-iris-] ;
+; Changed to indirect thru PDB to get JFN under DOS 3.x. ;
+; ;
+; Sat Jan 17, 1987 01:54:54a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FileHandleCall,<PUBLIC,NEAR>
+cBegin nogen
+if1
+; %OUT FileHandleCall DISABLED
+endif
+ jmp final_call_for_DOS
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Xenix_Status (DOS Call 44h) ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; FileHandleCall ;
+; PassOnThrough ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:45:48 -by- David N. Weise [davidw] ;
+; Removed WinOldApp support. ;
+; ;
+; Sat Jan 17, 1987 10:17:31p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Xenix_Status,<PUBLIC,NEAR>
+cBegin nogen
+ cmp al,4
+ jb xs1
+ cmp al,7
+ jz xs1
+ cmp al,10
+ jz xs1
+ jmp PassOnThrough
+
+xs1: jmp FileHandleCall
+cEnd nogen
+
+
+;********************************************************************
+;
+; Phantom drive Traps
+;
+;********************************************************************
+
+;**
+;
+; AssignCall -- Trap for Define Macro Call 5F03h
+;
+; ENTRY:
+; Regs for 5F03h except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected
+; USES:
+; Flags and via DOS if error
+;
+AssignCall:
+ cmp ax,5F03h ; Only care about 03 call
+ jnz AssignCall_OK
+ cmp bl,4 ; With BL = 4 (assign block)
+ jnz AssignCall_OK
+ cmp byte ptr [si],0 ; Ignore this special case
+ jz AssignCall_OK
+ push dx
+ mov dx,si
+ call PathDrvDSDX
+ pop dx
+ jc AssignCall_bad
+AssignCall_OK:
+ jmp PassOnThrough
+
+AssignCall_bad:
+ push word ptr [si]
+ mov byte ptr [si],'$' ; Bogus drive letter
+ call real_DOS ; Set error
+ pop word ptr [si] ; reset string
+ jmp SetCarryRet
+
+
+;**
+;
+; NameTrans -- Trap for NameTrans Call 60h
+;
+; ENTRY:
+; Regs for 60h except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected
+; USES:
+; Flags and via DOS if error
+;
+NameTrans:
+ push dx
+ mov dx,si ; Point with DS:DX to call PathDrvDSDX
+ call PathDrvDSDX
+ pop dx
+ jc @F
+ jmp POTJ1 ; Drive OK
+@@:
+ push word ptr [si]
+ mov byte ptr [si],'$' ; Bogus drive letter
+ call real_DOS ; DOS sets error
+ pop word ptr [si] ; Restore users drive
+ jmp SetCarryRet ; Error
+
+si_no_good:
+ call SetErrorDrvDSDX ; Set error
+ pop dx
+ jmp SetCarryRet ; Error
+
+PathDSSICall: ; Simple clone of PathDSDXCall
+ push dx ; but start with offset in SI,
+ mov dx, si ; and we know this is a file open
+ call PathDrvDSDX ; call.
+ jc si_no_good
+ pop dx
+ pop ds
+ push ax
+ push [bp][6] ; Original flags
+ push cs
+ mov ax, codeoffset si_back_here ; Now have IRET frame
+ push ax
+ push [bp] ; Original bp+1
+ mov bp, sp
+ mov ax, [bp][8]
+ push ds
+ jmp PassOnThrough ; Do the DOS call
+si_back_here:
+ pushf
+ inc bp
+ push bp ; pass back the correct flags
+ mov bp,sp
+ xchg ax, [bp][4]
+ jc @F
+ push dx
+ mov dx, si
+ call FileCDR_notify
+ pop dx
+@@:
+ push [bp]
+ pop [bp][6]
+ add sp, 2
+ pop [bp][12]
+ pop ax
+ pop bp
+ dec bp
+ jmp f_iret
+
+
+;**
+;
+; PathDSDXCall -- Trap for Calls which point to a path with DS:DX
+;
+; ENTRY:
+; Regs for call except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected
+; USES:
+; Flags and via DOS if error
+;
+PathDSDXCall:
+ call PathDrvDSDX
+ jnc @f
+ jmp pd_drive_no_good ; Drive not OK
+@@:
+ ; If OPEN with SHARING, check to see if this could be a file in
+ ; the file handle cache. GetModuleHandle is fairly quick as
+ ; opposed to fully qualifying the path involved, but that would
+ ; mean two DOS calls in addition to the open. Kernel opens modules
+ ; in compatibility mode, so sharing bits will barf if the file
+ ; is in the cache. why is this a problem? CVW opens modules
+ ; with sharing modes and we broke em when we fixed the fh cache.
+ ; won't worry about other DOS calls like create or delete since
+ ; they will damage things anyway.
+ ;
+ife SHARE_AWARE
+ cmp ah,3Dh ; open call?
+ jnz maybe_notify
+ test al, 01110000b ; sharing bits?
+ jz maybe_notify
+
+ call DealWithCachedModule
+
+endif
+
+maybe_notify:
+ifdef WOW
+ cmp ah,41h ; Delete call?
+ jnz not_delete
+
+ call DealWithCachedModule ; Yes Flush it out of our cache
+
+not_delete:
+endif; WOW
+ cmp ah,5Bh
+ ja no_notify_jmp ; DOS call we don't know
+ cmp ah,3Dh
+ jnz nd_101
+ jmp diddle_share_bits ; Don't notify on open file.
+nd_101:
+ cmp ah,4Eh
+ jz no_notify_jmp ; Don't notify on find first.
+ cmp ah,56h
+ jz no_notify_jmp ; Handle rename specially.
+ cmp ax, 4300h ; Get File Attributes
+ jz no_notify_jmp
+ pop ds
+ push ax
+ push [bp][6] ; Original flags
+ push cs
+ mov ax, codeoffset back_here ; Now have IRET frame
+ push ax
+ push [bp] ; Original bp+1
+ mov bp, sp
+ mov ax, [bp][8]
+ push ds
+POTJ1:
+ jmp PassOnThrough ; Do the DOS call
+
+no_notify_jmp:
+ jmps no_notify
+
+
+back_here:
+ pushf
+ inc bp
+ push bp ; pass back the correct flags
+ mov bp,sp
+ xchg ax, [bp][4]
+ jc call_failed
+ call FileCDR_notify
+call_failed:
+ push [bp]
+ pop [bp][6]
+ add sp, 2
+ pop [bp][12]
+ pop ax
+ pop bp
+ dec bp
+ jmp f_iret
+
+diddle_share_bits: ; Make ALL opens use SHARE bits
+if SHARE_AWARE
+ test al, 70h ; Any share bits now?
+ jnz no_notify ; yes, fine.
+
+ or al, OF_SHARE_DENY_NONE ; For Read access
+ test al, 3 ; Write or Read/Write access?
+ jz no_notify ; no, SHARE_DENY_NONE is fine
+ ; yes, want SHARE_DENY_WRITE
+ xor al, OF_SHARE_DENY_WRITE OR OF_SHARE_DENY_NONE
+endif
+no_notify:
+ jmps POTJ ; Drive OK
+
+pd_drive_no_good:
+ call SetErrorDrvDSDX ; Set error
+ jmps SetCarryRet ; Error
+
+;**
+;
+; DLDriveCall1 -- Trap for Calls which have a drive number (A = 1) in DL
+; and carry NOT set if error.
+;
+; ENTRY:
+; Regs for call except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected CARRY not
+; diddled
+; USES:
+; Flags and via DOS if error
+;
+DLDriveCall1:
+ call CheckDriveDL
+ jnc POTJ ; Drive OK
+ call SetErrorDLDrv ; Set error
+ jmps DriveErrorRet ; Error
+
+;**
+;
+; DLDriveCall2 -- Trap for Calls which have a drive number (A = 1) in DL
+; and carry set if error.
+;
+; ENTRY:
+; Regs for call except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected CARRY set
+; USES:
+; Flags and via DOS if error
+;
+DLDriveCall2:
+ call CheckDriveDL
+ jnc POTJ ; Drive OK
+ call SetErrorDLDrv ; Set error
+ jmps SetCarryRet ; Error
+
+;**
+;
+; FCBCall -- Trap for Calls which point to an FCB with DS:DX
+;
+; ENTRY:
+; Regs for call except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected
+; USES:
+; Flags and via DOS if error
+;
+FCBCall:
+ push dx
+ push si
+ mov si,dx
+ cmp byte ptr [si],0FFh ; Extended FCB?
+ jnz NotExt ; No
+ add si,7 ; Point to drive
+NotExt:
+ mov dl,byte ptr [si] ; Get drive
+ or dl,dl
+ jz FCBOK ; default drive
+ call CheckDriveDL
+ jc FCBBad
+FCBOK:
+ pop si
+ pop dx
+POTJ:
+ jmp PassOnThrough
+
+FCBBad:
+ push dx ; Save drive
+ mov dx,si ; Point to standard FCB
+ mov byte ptr [si],0F0h ; Known bogus drive
+ call real_DOS
+ pop dx
+ mov byte ptr [si],dl ; Restore user drive
+ pop si
+ pop dx
+ jmps DriveErrorRet
+
+
+SetCarryRet:
+ or User_FL,00000001b ; Set carry
+ jmps DriveErrorRet
+
+
+DriveErrorRet:
+ pop ds
+ pop bp
+ dec bp
+ FSTI
+ jmp f_iret
+
+
+;**
+;
+; XenixRename -- Trap for Call 56h
+;
+; ENTRY:
+; Regs for call except BP is standard INT 21h frame ptr
+; EXIT:
+; Through PassOnThrough or Error path if phantom drive detected CARRY set
+; USES:
+; Flags and via DOS if error
+;
+XenixRename:
+
+; On rename we MUST deal with BOTH strings to prevent access to any
+; phantom drives.
+
+ call PathDrvDSDX ; Check DS:DX drive
+ xchg di,dx ; ES:DI <-> DS:DX
+ push ds
+ push es
+ pop ds
+ pop es
+ jnc XR_010
+ jmp RenameError ; bad
+XR_010:
+ call PathDrvDSDX ; Check ES:DI drive
+ jnc XR_020
+ jmp RenameError
+XR_020:
+ xchg di,dx ; ES:DI <-> DS:DX
+ push ds
+ push es
+ pop ds
+ pop es
+
+ pop ds
+ push ax
+ push [bp][6] ; Original flags
+ push cs
+ mov ax, codeoffset back_here1 ; Now have FIRET frame
+ push ax
+ push [bp] ; Original bp+1
+ mov bp, sp
+ mov ax, [bp][8]
+ push ds
+ jmp PassOnThrough ; Do the DOS call
+back_here1:
+ pushf
+ inc bp
+ push bp ; pass back the correct flags
+ mov bp,sp
+ xchg [bp][4], ax
+ jc call_failed1
+
+;;; mov ah,41h ; delete file
+ call FileCDR_notify
+;;; push ds
+;;; push es
+;;; pop ds
+;;; pop es
+;;; xchg di,dx
+;;; mov ah,5Bh ; create new file
+;;; call FileCDR_notify
+;;; push ds
+;;; push es
+;;; pop ds
+;;; pop es
+;;; xchg di,dx
+
+call_failed1:
+ push [bp]
+ pop [bp][6]
+ add sp, 2
+ pop [bp][12]
+ pop ax
+ pop bp
+ dec bp
+ jmp f_iret
+
+RenameError:
+ xchg di,dx ; DS:DX <-> ES:DI
+ push ds
+ push es
+ pop ds
+ pop es
+
+; We patch the ES:DI drive letter even if it isn't there.
+; Since we are setting an error anyway this is OK.
+
+ push word ptr ES:[di]
+ mov byte ptr ES:[di],'$' ; Bogus drive letter
+ call SetErrorDrvDSDX ; Set error
+ pop word ptr ES:[di]
+ jmp SetCarryRet ; Error
+
+;**
+;
+; PathDrvDSDX -- Check a path pointed to by DS:DX for phantom drives
+;
+; ENTRY:
+; DS:DX points to path
+; EXIT:
+; Carry set if phantom drive detected
+; Carry clear if no phantom drives detected
+; USES:
+; Flags
+;
+ public PathDrvDSDX
+PathDrvDSDX:
+ push si
+ mov si,dx ; Point with SI
+ mov dx,word ptr [si]; Get first two chars
+ or dl,dl ; NUL in first byte?
+ jz PDROK ; yes, OK
+ifdef DBCS
+ push ax
+ mov al,dl
+ call MyIsDBCSLeadByte ; see if char is DBC.
+ pop ax
+ jnc PDROK ; jump if char is a DBC
+endif
+ or dh,dh ; NUL in second byte?
+ jz PDROK ; yes, OK
+ cmp dh,':' ; Drive given?
+ jnz PDROK ; No, OK
+ or dl,20h ; to lower case
+ sub dl,60h ; DL is drive #, A=1
+ call CheckDriveDL ; Check it out
+ jmps PDPPRET
+
+PDROK:
+ clc
+PDPPRET:
+ mov dx,si
+ pop si
+ ret
+
+;**
+;
+; SetErrorDrvDSDX -- Set an error on a DS:DX call by calling the DOS
+;
+; ENTRY:
+; DS:DX points to path with phantom drive
+; All other regs approp for INT 21 CALL
+; EXIT:
+; DOS called to set up error
+; USES:
+; Flags
+; Regs as for INT 21 CALL
+;
+SetErrorDrvDSDX:
+ push si
+ mov si,dx
+ push word ptr [si]
+ mov byte ptr [si],'$' ; Bogus drive letter
+ call real_DOS ; DOS sets error
+ pop word ptr [si] ; Restore users drive
+ pop si
+ ret
+
+;**
+;
+; SetErrorDLDrv -- Set an error on a DL call by calling the DOS
+;
+; ENTRY:
+; DL is drive # (A=1) of a phantom drive.
+; All other regs approp for INT 21 CALL
+; EXIT:
+; DOS called to set up error
+; USES:
+; Flags
+; Regs as for INT 21 CALL
+;
+SetErrorDLDrv:
+ push dx
+ mov dl,0F0h ; Bogus drive letter
+ call real_DOS ; DOS sets error
+ pop dx ; Restore users drive
+ret43: ret
+
+;**
+;
+; CheckDriveDL -- Check DL drive (A = 1)
+;
+; ENTRY:
+; DL is drive # (A=1)
+; EXIT:
+; Carry Set if phantom drive
+; Carry Clear if NOT phantom drive
+; USES:
+; Flags
+;
+CheckDriveDL:
+ push bx
+ mov bx,dx
+ dec bl ; A = 0
+ cmp bl,26 ; 0 >= DL < 26?
+ jae OKDRV ; No, cant be phantom then
+ xor bh,bh
+ add bx,dataOffset PhantArray; Index into PhantArray
+ push ds
+ SetKernelDS
+ cmp byte ptr ds:[bx],0 ; Non-zero entry means phantom
+ pop ds
+ UnSetKernelDS
+ stc
+ jnz BadDrv
+OKDRV:
+ clc
+BadDrv:
+ pop bx
+ ret
+
+
+ife SHARE_AWARE
+
+;**
+;
+; DealWithCachedModule -- closes a cached module if it looks like a filename
+;
+; ENTRY:
+; Same as PathDSDXCall
+;
+; EXIT:
+; Unchanged
+;
+; USES:
+; None
+;
+; SIDE EFFECT:
+; Closes entry in file handle cache if it has the same base name
+;
+public DealWithCachedModule
+DealWithCachedModule:
+ pusha
+ push ds
+ push es ; save all registers
+
+ mov si, dx ; point ds:si to string
+ sub sp, 130 ; big number for paranoia
+ mov di, sp
+ push ss
+ pop es ; es:di to string
+ cld ; forwards
+
+copy_name_loop:
+ lodsb ; get a char
+ cmp al, 0 ; end of string?
+ jz end_of_name
+ cmp al, ':' ; path seperator?
+ jz path_sep
+ cmp al, '\'
+ jz path_sep
+ cmp al, '/'
+ jz path_sep
+ call MyUpper ; upcase the char
+ stosb
+
+ifdef DBCS
+ call MyIsDBCSLeadByte
+ jc copy_name_loop ; copy second byte in east
+ movsb
+endif
+
+ jmp short copy_name_loop
+path_sep:
+ mov di, sp ; point back to beginning
+ jmp short copy_name_loop
+end_of_name:
+ stosb
+ mov di, sp ; point back to beginning
+
+ SetKernelDS
+
+ cCall ResidentFindExeFile, <ss,di> ; find it
+ or ax, ax
+ jz @F
+
+ cCall FlushCachedFileHandle, <ax> ; flush it
+@@:
+ add sp, 130
+
+ pop es
+ pop ds ; restore registers
+ popa
+ UnsetKernelDS
+ ret
+
+endif
+
+f_iret:
+ FIRET
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/i21task.asm b/private/mvdm/wow16/kernel31/i21task.asm
new file mode 100644
index 000000000..3cb19aa95
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/i21task.asm
@@ -0,0 +1,1378 @@
+
+.xlist
+include kernel.inc
+include tdb.inc
+include pdb.inc
+include kdos.inc
+include eems.inc
+include protect.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+externFP LoadLibrary
+externFP LoadModule
+externFP GlobalFree,
+externFP GlobalFreeAll
+externFP GlobalCompact
+externFP FreeModule
+externFP GlobalDOSFree
+externFP FreeSelector
+externFP GetProcAddress ; WIN32S
+externFP ISetErrorMode ; WIN32S
+externFP ISetHandleCount
+
+externFP ExitKernelThunk
+externNP DPMIProc
+
+extrn BUNNY_351:FAR
+
+ifdef WOW
+DRIVE_REMOTE equ 4
+externW headTDB
+externFP lstrlen
+externFP WOWSetIdleHook
+externFP GetDriveType
+endif
+
+externW pStackBot
+;externW pStackMin
+externW pStackTop
+
+DataBegin
+
+externB Kernel_flags
+externB num_tasks
+externB Kernel_InDOS
+externB Kernel_InINT24
+
+externB WOAName
+externB grab_name
+externB fBooting
+externB graphics
+externB fExitOnLastApp
+
+externW cur_dos_PDB
+externW Win_PDB
+externW headPDB
+externW topPDB
+externW curTDB
+externW curDTA
+externW PHTcount
+externW gmove_stack
+externW MyCSSeg
+externW wExitingTDB
+externD lpSystemDir
+
+if KDEBUG
+externW allocTask
+endif
+
+if ROM
+externD prevInt21Proc
+endif
+
+externD lpint21
+externD pExitProc
+if PMODE32
+externD pDisplayCritSec
+externW PagingFlags
+externD lpReboot
+endif
+
+ifdef JAPAN
+externD pJpnSysProc
+endif
+
+DataEnd
+
+sBegin DATA
+externW gmove_stack
+
+
+ifdef PMODE32
+ifndef WOW
+WIN32S = 1 ; enable code for Win32S support
+endif
+endif
+
+ifdef WIN32S
+; Win32S support
+selExecPE DW 0
+offExecPE DW 0
+endif
+
+sEnd DATA
+
+assumes DS,NOTHING
+sBegin CODE
+assumes CS,CODE
+
+ife ROM
+externD prevInt21Proc
+endif
+
+externNP Real_DOS
+externNP PathDrvDSDX
+externNP SetErrorDrvDSDX
+externNP SetCarryRet
+externNP ExitSchedule
+externNP UnlinkObject
+externNP final_call_for_DOS
+
+externNP cmp_sel_address
+externNP free_sel
+externNP SegToSelector
+
+if SDEBUG
+externNP DebugExitCall
+endif
+externNP DeleteTask
+
+
+;-----------------------------------------------------------------------;
+; Set_DTA (DOS Call 1Ah) ;
+; ;
+; Simply records on a task basis the DTA. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Jan 10, 1987 09:19:36p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Set_DTA,<PUBLIC,NEAR>
+cBegin nogen
+ push es
+ SetKernelDS es
+ mov curDTA.off,dx
+ mov curDTA.sel,ds
+ mov es,curTDB
+ UnSetKernelDS es
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jne Set_DTA_noTDB
+ mov es:[TDB_DTA].off,dx
+ mov es:[TDB_DTA].sel,ds
+Set_DTA_noTDB:
+ pop es
+ jmp final_call_for_DOS
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; SaveRegs ;
+; ;
+; Does what it says. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Jan 16, 1987 09:57:49p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SaveRegs,<PUBLIC,NEAR>
+cBegin nogen
+
+ xchg dx, user_DX ; Return address in DX
+ push es
+ push bx
+ push ax
+ push cx
+ push si
+ push di
+ and USER_FL,11111110b ; clc flag
+ push dx
+ mov dx, user_DX ; Rescue DX for what it's worth
+ cld
+
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; RestoreRegs ;
+; ;
+; Does what it says and (used to cli). ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Jan 16, 1987 10:00:41p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc RestoreRegs,<PUBLIC,NEAR>
+cBegin nogen
+
+ pop di ; Return address
+ xchg di, user_BP ; Insert for ret later, get saved BP
+ mov bp, di
+ dec bp
+ pop di
+ pop si
+ pop cx
+ pop ax
+ pop bx
+ pop es
+ pop dx
+ pop ds
+ ret ; SP points to user_BP
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ;
+; Handle the Int21 func 67 call "Set Maximum Handle Count" ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc SetMaxHandleCount,<PUBLIC,NEAR>
+cBegin nogen
+ pop ds
+ pop bp ; clean up stack
+ dec bp
+
+ cmp bx, 255
+ ja smhc_err1
+
+ push bx
+ push cx
+ push dx
+
+ cCall ISetHandleCount,<bx>
+ pop dx
+ pop cx
+ pop bx
+
+ cmp ax, bx ; did we get everything?
+ jne smhc_err2
+ clc
+ jmp smhcexit
+
+smhc_err1:
+ mov ax,4 ; too many open files
+ stc ; set carry flag
+ jmp smhcexit
+
+smhc_err2:
+ mov ax,8 ; not enough memory
+ stc ; set carry flag
+smhcexit:
+ STIRET
+ ret
+
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Set_Vector (DOS Call 25h) ;
+; Get_Vector (DOS Call 35h) ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Jan 17, 1987 01:48:29a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Set_Vector,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ push es
+ call IsItIntercepted
+ jnz notintercepted
+ SetKernelDS es
+ mov es, CurTDB ; We intercepted it, change
+ UnSetKernelDS es ; vector in the TDB
+ mov es:[di].off, dx
+ mov es:[di].sel, ds
+ jmps sv_done ; And just return
+notintercepted:
+ SetKernelDS es
+ cmp fBooting,1
+ jz sv_no_restrictions
+ cmp graphics,0 ; in the stand alone OS/2 box?
+ jz @F
+ifdef JAPAN
+ push ax
+ push bx ; 04/23/91 -yukini
+ mov bx,0
+ cCall [pJpnSysProc], <bx,ax> ; call System.JapanInquireSystem to
+ ; get vector can be modified or not.
+ test ax,ax
+ pop bx
+ pop ax
+ jz sv_done ; jump if cannot be modified
+else
+ cmp al,1Bh
+ jz sv_done
+ cmp al,1Ch
+ jz sv_done
+endif
+@@: cmp al,21h ; trying to reset our traps?
+ jz sv_done
+ cmp al,24h ; trying to reset our traps?
+ jz sv_done
+ cmp al,2fh ; setting idle detect vector?
+ jnz sv_no_restrictions ; no, proceed normally
+ push ax
+ push dx
+ push ds
+ cCall WOWSetIdleHook ; set the real hook back in Win32
+ pop ds
+ pop dx
+ pop ax
+ jmp bodacious_cowboys
+sv_no_restrictions:
+ cmp al,21h
+ jnz bodacious_cowboys
+ mov lpint21.off,dx
+ mov lpint21.sel,ds
+bodacious_cowboys:
+ call real_DOS
+
+sv_done:
+ pop es
+ pop di
+ pop ds
+ pop bp ; clean up stack
+ dec bp
+ STIRET
+
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Get_Vector,<PUBLIC,NEAR>
+cBegin nogen
+ pop ds
+ pop bp ; clean up stack
+ dec bp
+ push di
+ call IsItIntercepted
+ jnz notintercepted1
+ push ds ; We intercepted it, get the
+ SetKernelDS ; vector from the TDB
+ mov ds, CurTDB
+ UnSetKernelDS
+ mov bx, [di]
+ mov es, [di+2]
+ pop ds
+ pop di
+ jmps gv_done
+notintercepted1:
+ pop di
+ call real_DOS
+gv_done:
+ STIRET
+
+cEnd nogen
+
+
+
+cProc IsItIntercepted,<PUBLIC,NEAR>
+cBegin nogen
+ mov di, TDB_INTVECS
+ cmp al, 00h
+ je yes_intercepted
+ add di, 4
+ cmp al, 02h
+ je yes_intercepted
+ add di, 4
+ cmp al, 04h
+ je yes_intercepted
+ add di, 4
+ cmp al, 06h
+ je yes_intercepted
+ add di, 4
+ cmp al, 07h
+ je yes_intercepted
+ add di, 4
+ cmp al, 3Eh
+ je yes_intercepted
+ add di, 4
+ cmp al, 75h
+yes_intercepted:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ExecCall (DOS Call 4Bh) ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:39:59 -by- David N. Weise [davidw] ;
+; Added support for long command lines to WinOldApp. ;
+; ;
+; Sat Jan 17, 1987 01:39:44a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ExecCall,<PUBLIC,NEAR>
+cBegin nogen
+ call PathDrvDSDX ; Check drive
+ jnc EC1 ; Drive OK
+ call SetErrorDrvDSDX ; Set up errors
+ jmp SetCarryRet ; Error
+
+EC1: call SaveRegs
+ call far ptr FarExecCall
+ call RestoreRegs
+ STIRET
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; TerminatePDB ;
+; ;
+; It calls DOS to terminate the current task. ;
+; ;
+; Arguments: ;
+; DI = exit code ;
+; Returns: ;
+; nothing ;
+; Error Returns: ;
+; nothing ;
+; Registers Preserved: ;
+; none ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc TerminatePDB,<PUBLIC,NEAR>
+cBegin nogen
+
+ SetKernelDS ES
+ mov bx, ds ; DS is PDB being terminated
+ cmp cur_dos_PDB, bx ; Ensure DOS/anyone on the
+ je short @F ; int 21h chain has correct PDB
+ mov ah, 50h
+ pushf
+ call prevInt21Proc
+@@:
+ mov ax, ds:[PDB_Parent_PID] ; Parent PDB
+ mov Win_PDB, ax ; These will be changed by DOS
+ mov cur_dos_PDB, ax
+
+ or Kernel_Flags[2],KF2_WIN_EXIT
+ mov ax,di ; AL = exit code
+ mov ah, 0 ; Alternative exit for PMODE which returns
+ call real_DOS ; let DOS clean up
+ UnSetKernelDS es
+
+ errn$ DosExitReturn
+
+cEnd nogen
+
+;
+; The DOS terminate call above will return to
+; the following label, DosExitReturn. This is
+; a separate procedure in order to be declared FAR.
+;
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DosExitReturn,<PUBLIC,FAR>
+cBegin nogen
+
+ SetKernelDS ES
+ mov Kernel_InDOS,0
+ mov Kernel_InINT24,0
+ and Kernel_Flags[2],NOT KF2_WIN_EXIT
+ retn
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ExitCall (DOS Call 4Ch) ;
+; ;
+; It terminates the current task. ;
+; ;
+; Arguments: ;
+; AL = exit code ;
+; Returns: ;
+; nothing ;
+; Error Returns: ;
+; nothing ;
+; Registers Preserved: ;
+; none ;
+; Registers Destroyed: ;
+; none ;
+; Calls: ;
+; TerminatePDB ;
+; GlobalFreeAll ;
+; UnlinkObject ;
+; DeleteTask ;
+; GlobalFree ;
+; FreeModule ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 23:39:59 -by- David N. Weise [davidw] ;
+; Removed WinOldApp support. ;
+; ;
+; Sun Apr 26, 1987 03:20:05p -by- David N. Weise [davidw] ;
+; Made it switch stacks to the temp_stack because of EMS. ;
+; ;
+; Mon Sep 29, 1986 04:06:08p -by- Charles Whitmer [chuckwh] ;
+; Made it kill all threads in the current process. ;
+; ;
+; Mon Sep 29, 1986 03:27:12p -by- Charles Whitmer [chuckwh] ;
+; Made it call UnlinkObject rather than do the work inline. ;
+; ;
+; Mon Sep 29, 1986 09:22:08a -by- Charles Whitmer [chuckwh] ;
+; Documented it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ExitCall,<PUBLIC,NEAR>
+cBegin nogen
+
+ifdef WOW
+ ; Set to a Known DIR so that if an app was running over the network
+ ; the user can disconnect once the app terminates.
+ ; This also allows a subdirectory to be removed after a Win16 app
+ ; had that dir as the current dir, but was terminated.
+
+ SetKernelDS
+
+ push ax
+ push si
+ push dx
+ push ds
+
+ lds si,lpSystemDir ; ds:si points to system directory
+ mov dl,[si] ; put drive letter into AL
+ add dl,-65 ; subtract 'A' to get drive number
+ mov ah,0Eh
+ call real_DOS ; select disk
+
+ add si,2 ; let SI point to the first '\' past d:
+
+ mov al,[si + 1] ; save first character after '\'
+ push ax
+
+ mov byte ptr [si + 1],0 ; null-terminate string after root dir
+ mov dx,si
+ mov ah,3Bh
+ call real_DOS ; select directory
+
+ pop ax
+ mov [si + 1],al ; restore string to its original state
+
+ pop ds
+ pop dx
+ pop si
+ pop ax
+endif
+
+
+if SDEBUG
+ ;** Save the TDB of the currently exiting task. We check for this
+ ;** in DebugWrite so that we don't get recursive
+ ;** debug strings at task exit time. This is a gross hack
+ ;** for QCWin and their numerous param validation errors.
+ mov bx,curTDB ;Get current task handle
+ mov wExitingTDB,bx ;Save as exiting TDB
+ cCall DebugExitCall ;Passes exit code in AL
+endif ; SDEBUG
+
+if PMODE32
+ .386
+ smov fs, 0
+ smov gs, 0
+ .286p
+
+ xchg di,ax ; DI = exit code
+
+ cmp graphics,1 ; is there a display driver around?
+ jnz @F
+ mov ax,1
+ifndef WOW ; WOW doesn't have a display dirver to call
+ cCall pDisplayCritSec,<ax> ; tell display driver to shut up
+endif
+ or Kernel_Flags[2],KF2_WIN386CRAZINESS
+@@: mov ds,curTDB ; DS = current TDB
+ assumes ds,nothing
+else
+ xchg di,ax ; DI = exit code
+ mov ds,curTDB ; DS = current TDB
+ UnSetKernelDS
+endif
+
+; We may have gotten here due to stack checking. Let's make sure
+; that we are on a stack we can deal with.
+
+ test ds:[TDB_flags],TDBF_OS2APP
+ jz @F
+ mov ax,sp
+ mov ss:[pStackBot],ax
+@@: xor ax,ax
+ mov ss:[pStackTop],ax
+
+; remove the PDB from the chain
+
+ mov es,ds:[TDB_PDB]
+ mov dx,PDB_Chain
+ mov bx,dataOffset HeadPDB
+ call UnlinkObject
+
+ xor si,si ; source of zero
+
+; Dec total # of tasks, if last task in system, then quit Windows completely.
+
+ smov es,ds
+ assumes es,nothing
+ SetKernelDS
+ifdef WOW
+ cmp fExitOnLastApp,0 ; Quit WOW when the last app dies ?
+ jz @f
+
+ cmp num_tasks,2 ; Last Task (ingnoring WOWEXEC) ?
+ jz last_task
+@@:
+endif
+ dec num_tasks
+ jnz not_the_last_task
+
+last_task:
+IF PMODE32
+ ;** Unhook local reboot VxD stuff
+ cmp WORD PTR lpReboot[2], 0 ;Reboot handler installed?
+ je @F ;No
+ push es
+ mov ax, 0201h ;Reboot VxD #201: Set callback addr
+ xor di, di ;Zero CS means no SYS VM local
+ mov es, di
+ call [lpReboot] ; reboot handler
+ pop es
+@@:
+ENDIF
+
+ call BUNNY_351
+
+ifndef WOW ; For WOW ex just want to get out of here - no need to call USER16 or GDI16
+ cCall pExitProc,<si,si> ; this does not return
+endif
+ cCall ExitKernelThunk,<si>
+
+ assumes es, nothing
+not_the_last_task:
+
+; Signal( hTask, SG_EXIT, ExitCode, 0, Queue ) if we have a user signal proc
+
+ push es
+ cmp es:[si].TDB_USignalProc.sel,si
+ jz no_signal_proc
+ mov bx,SG_EXIT
+ cCall es:[si].TDB_USignalProc,<es,bx,di,es:[si].TDB_Module,es:[si].TDB_Queue>
+no_signal_proc:
+
+ pop es
+
+ mov bl,6
+ DPMICALL 0202h ; DPMI get exception handler vector
+ push cx
+ push dx
+
+ mov cx,cs
+ lea dx,exit_call_guts
+ mov bl,6
+ DPMICALL 0203h ; DPMI set exception handler vector
+
+ pop dx
+ pop cx
+;
+; Generate an invalid opcode exception fault. This causes DPMI to call
+; our "exception handler."
+;
+ db 0fh,0ffh
+exit_call_guts:
+ FSTI ; we're called with ints disabled
+ mov bp,sp ; BP -> RETIP RETCS EC IP CS FL SP SS
+;
+; Restore the previous invalid exception handler vector.
+;
+ mov bl,6
+ DPMICALL 0203h
+;
+; Point the return stack at Kernel's temporary stack.
+;
+ mov ax,dataOffset gmove_stack
+ mov [bp+12],ax
+ mov ax,seg gmove_stack
+ mov [bp+14],ax
+;
+; Replace the return address on the DPMI fault handler routine with
+; our exit code.
+;
+ lea ax,ExitSchedule
+ mov [bp+6],ax
+ mov [bp+8],cs
+
+ push es
+
+ cCall GlobalFreeAll,<si> ; free up all task data
+ pop es
+
+; Remove from queue.
+
+ push es
+ cCall DeleteTask,<es>
+ pop es
+ mov ds,es:[TDB_PDB] ; DS = current PDB
+
+ UnsetKernelDS ; DS is PDB to terminate
+
+ call TerminatePDB ; Call DOS to close down files etc.
+
+ ReSetKernelDS ES ; TerminatePDB returned with ES set
+
+ xor bp,bp ; set up valid frame
+ mov ds,curTDB
+
+; If this task has a PHT, decrement the PHT count and clear the pointer
+; and zap the PHT pointer so we don't look at it anymore.
+; NOTE - BP contains a convenient zero.
+
+ mov ax,ds:[TDB_PHT].sel
+ or ax,ds:[TDB_PHT].off
+ jz no_PHT
+ mov ds:[TDB_PHT].sel,bp
+ mov ds:[TDB_PHT].off,bp
+ dec PHTcount ; dec # tasks with PHT's
+no_PHT:
+ UnSetKernelDS es
+ cCall FreeModule,<ds:[TDB_Module]> ; Free the module for this task
+ xor ax,ax
+ mov ds:[TDB_sig],ax ; Mark TDB as invalid
+
+ ;** Nuke any JFN that is outside the PDB. We can tell that the
+ ;** JFN points outside the PDB if the offset is zero. PDB
+ ;** JFN's never have a zero offset and outside ones always do.
+ push ds
+ mov ds, ds:[TDB_PDB]
+ cmp WORD PTR ds:[PDB_JFN_Pointer][0], 0 ;JFN pointer into PDB?
+ jne EC_NoFreeJFN ;Yes, don't free anything
+ push WORD PTR ds:[PDB_JFN_Table] ;Get our selector
+ call GlobalDOSFree
+EC_NoFreeJFN:
+
+ SetKernelDS
+
+ cmp num_tasks,1 ; Last task? (except wowexec)
+ jne @f
+
+ cCall GlobalCompact,<-1, -1> ; free up as many pages as possible
+@@:
+ mov bx, topPDB
+ mov Win_PDB, bx
+ mov cur_dos_PDB, bx
+ mov ah, 50h
+ pushf
+ call prevInt21Proc ; Set PDB to KERNEL's
+ pop ds
+ UnSetKernelDS
+ xchg bx, ds:[TDB_PDB]
+ cCall free_sel,<bx> ; Free the PDB selector
+
+ call far ptr FreeTDB ; Tosses PDB's memory
+ SetKernelDS
+ifndef WOW
+ mov curTDB,0 ; We can use this, setting curTDB = 0
+else
+ ;; We do this a little later - see tasking.asm exitschedule
+endif
+ if PMODE32 ; in rmode as well in the next rev
+ or PagingFlags, 8 ; to save a few bytes.
+ endif
+
+ ;** Task has been nuked. Clear the DebugWrite task exiting flag
+ mov wExitingTDB,0
+
+ retf ; To ExitSchedule
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FreeTDB, <PUBLIC,FAR>
+cBegin nogen
+
+ cCall FreeSelector,<ds:[TDB_MPI_Sel]>
+ mov ax,ds
+if KDEBUG
+;
+; If we're freeing the alloc break task, zero out the global.
+;
+ SetKernelDS
+ cmp ax,allocTask
+ jnz @F
+ mov allocTask,0
+@@:
+ UnSetKernelDS
+endif
+ smov ds,0
+ cCall GlobalDOSFree,<ax>
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; set_PDB (DOS Call 50h) ;
+; ;
+; This is an undocumented DOS call to set the current PDB. ;
+; DOS does not check for ^C's on this call, in fact it never turns ;
+; on the interrupts. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Jan 23, 1987 07:07:14p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc set_PDB,<PUBLIC,NEAR>
+cBegin nogen
+ SetKernelDS
+ mov cur_dos_PDB,bx
+ mov Win_PDB,bx
+ mov ds,curTDB
+ assumes ds,nothing
+ mov ds:[TDB_PDB],bx
+ call real_DOS
+ pop ds
+ pop bp ; clean up stack
+ dec bp
+ STIRET
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; get_PDB ;
+; ;
+; This is an undocumented DOS call to set the current PDB. ;
+; DOS does not check for ^C's on this call, in fact it never turns ;
+; on the interrupts. ;
+; Trapping this is superfluous is real mode but necessary in protect ;
+; mode since the DOS extender may not be doing the segment ;
+; translation properly. ;
+; ;
+; Entry: ;
+; ;
+; Returns: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; History: ;
+; Tue 13-Jun-1989 18:22:16 -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc get_PDB,<PUBLIC,NEAR>
+cBegin nogen
+ SetKernelDS
+ call real_DOS
+ mov bx,cur_dos_PDB
+ pop ds
+ pop bp ; clean up stack
+ dec bp
+ STIRET
+cEnd nogen
+
+sEnd code
+
+sBegin NRESCODE
+assumes cs, NRESCODE
+assumes ds, nothing
+assumes es, nothing
+
+externNP MapDStoDATA
+
+
+;-----------------------------------------------------------------------;
+; BuildPDB ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu 04-Jan-1990 20:15:27 -by- David N. Weise [davidw] ;
+; Made it avoid closing cached files if the PDB being copied is not ;
+; the topPDB. This is for supporting inheriting a parents files. ;
+; ;
+; Mon 11-Sep-1989 19:13:52 -by- David N. Weise [davidw] ;
+; Removed returning validity in AX, and removed copying of FCBs. ;
+; ;
+; Mon 07-Aug-1989 23:39:59 -by- David N. Weise [davidw] ;
+; Added support for long command lines to WinOldApp. ;
+; ;
+; Sun Jan 18, 1987 00:27:52a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc BuildPDB,<PUBLIC,FAR>,<si,di>
+ ParmW oldPDB
+ ParmW newPDB
+ ParmD ParmBlock
+ ParmW newSize
+ ParmW fWOA
+cBegin
+ call MapDStoDATA
+ ReSetKernelDS
+
+ push Win_PDB ; Save current PDB
+
+ mov bx,oldPDB ; set current PDB for copy
+ mov Win_PDB, bx
+
+ mov dx,newPDB
+ mov si,newSize
+ mov ah,55h ; duplicate PDB
+ int 21h
+
+ mov bx, oldPDB
+ mov dx, newPDB
+ mov cur_dos_PDB, dx ; DOS call 55h sets the PDB to this
+
+nothing_to_close:
+
+ pop Win_PDB ; restore former PDB
+
+ xor di,di
+
+ mov cx, MyCSSeg
+ mov ds,dx
+ UnSetKernelDS
+ mov es,dx
+ add si,dx
+ mov ax,oldPDB
+ mov [di].PDB_Parent_PID,ax ; parent = OldPDB
+ mov [di].PDB_Block_Len,si
+
+ mov [di].PDB_Exit.off,codeOffset DosExitReturn
+ mov [di].PDB_Exit.sel, cx
+
+; No private global heap yet.
+
+ mov [di].PDB_GlobalHeap.lo,di
+ mov [di].PDB_GlobalHeap.hi,di
+
+; Set up proper command line stuff.
+
+ lds si,ParmBlock
+ lds si,ds:[si].lpcmdline ; command line
+ mov di,PDB_DEF_DTA
+ mov cx,di
+ cmp fWOA,0
+ jz @F ; Winoldap can have long command line
+ mov cx,ds:[si] ; get byte count
+ cld
+ movsb ; copy count byte
+ inc cx
+ inc si
+@@: rep movsb ; Store command line.
+
+cEnd
+
+
+cProc FarExecCall,<PUBLIC,FAR>
+cBegin nogen
+
+; Check if file extension is .COM, .BAT, .PIF, if so it needs emulation...
+
+ cld
+ les di,User_DSDX
+
+
+ifdef WOW
+;
+; Wow LoadModule handles all forms of exec including
+; pe images, com, bat, pif files etc.
+;
+ lds si,User_ESBX
+ regptr esdx,es,dx
+ regptr dssi,ds,si
+ cCall LoadModule,<esdx,dssi>
+ cmp ax, LME_MAXERR ; check for error...
+ jae ex8
+ jmp short ex7 ; no, return error
+
+else
+
+ mov cx,-1
+ xor al,al
+ repnz scasb ; scan to end of string
+ neg cx
+ dec cx ; cx has length (including null)
+ mov ax,es:[di-5]
+ or ah,20h
+ mov bx,es:[di-3] ; complete check for .COM
+ or bx,2020h ; convert to lower case
+
+ cmp ax,'c.' ; check for .COM file extension
+ jnz ex1b ; no match...attempt load module
+ cmp bx,'mo'
+ jz ex4 ; yes! go immediatly to GO
+
+ex1b: cmp ax,'b.' ; check for .BAT extension...
+ jnz ex1c
+ cmp bx,'ta'
+ jz ex4
+
+ex1c: cmp ax,'p.' ; check for .PIF extension...
+ jnz ex2
+ cmp bx,'fi'
+ jz ex4
+
+ex2: lds si,User_ESBX
+ regptr esdx,es,dx
+ regptr dssi,ds,si
+ push cx ; save length of string
+ cCall LoadModule,<esdx,dssi>
+ pop cx
+ cmp ax, LME_MAXERR ; check for error...
+ jb ex3
+ jmp ex8
+ex3: cmp ax, LME_INVEXE ; wrong format?
+ jz ex4
+ cmp ax, LME_EXETYPE ; quick basic app
+ jz ex4
+
+ cmp ax, LME_PE ; Win32 PE format
+ jz @F
+ jmp ex7 ; no, return error
+@@:
+
+
+ifdef WIN32S
+ push cx
+; Win32S support - (AviN) 11-19-91
+
+ lds si,User_DSDX
+ push ds
+ push si
+ lds si,User_ESBX
+ push ds:[si+4] ; CmdLine sel
+ push ds:[si+2] ; offset
+
+ les bx, ds:[si+6] ; FCB1
+ push es:[bx+2] ; nCmdShow
+
+ call FAR PTR ExecPE
+ pop cx
+
+ cmp ax, 32
+ jbe @F
+ jmp ex8
+@@:
+ cmp ax, 11 ; NOT PE
+ je @F
+ jmp ex7
+
+@@:
+
+; end of Win32S support
+endif
+
+ex4:
+
+; Run an old application
+;
+; If we are running in the OS/2 3x box, we do not support running old
+; apps. If someone trys this, put up a nasty message and return with
+; an error. (Thu 12-Nov-1987 : bobgu)
+
+
+ mov dx,cx ; save length of file name
+ sub sp,256 ; make room for command line
+ smov es,ss
+ mov di,sp
+ lds si,User_ESBX
+ lds si,ds:[si].lpcmdline
+ xor ax,ax
+ xor cx,cx
+ mov cl,ds:[si]
+ inc cx
+ movsb
+ stosb
+ rep movsb
+ mov cx,dx
+ lds si,User_DSDX
+ rep movsb
+ mov byte ptr es:[di][-1],10 ; terminate with line feed
+ mov di,sp
+ add es:[di],dx
+
+ mov bx,es
+ push ds
+ call MapDStoDATA
+ smov es, ds
+ pop ds
+ ReSetKernelDS es
+
+ test Kernel_flags[2],KF2_DOSX ; DOSX winoldap doesn't need special
+ jnz @F ; special handling
+ mov ax,dataOffset grab_name
+ push bx
+ push dx
+ push es
+ cCall LoadLibrary,<es,ax>
+ pop es
+ pop dx
+ pop bx
+ cmp ax,32
+ jae @F
+ add sp, 256 ; undo damage to stack
+ jmps ex7
+@@:
+
+ or Kernel_flags[1],KF1_WINOLDAP
+ lds si,User_ESBX
+ mov ds:[si].lpcmdline.off,di
+ mov ds:[si].lpcmdline.sel,bx
+ mov dx,dataOffset WOAName
+ regptr esdx,es,dx
+ regptr dssi,ds,si
+ cCall LoadModule,<esdx,dssi>
+ assumes es, nothing
+ add sp,256
+ cmp ax,32 ; check for error...
+ jae ex8
+ cmp ax,2 ; file not found?
+ jnz ex7 ; no, return error
+ mov al,23 ; flag WINOLDAP error
+
+;; ndef wow
+endif
+
+ex7: or User_FL,1 ; set carry flag
+ or ax,ax ; out of memory?
+ jnz ex8
+ mov ax,8h ; yes, return proper error code
+ex8: mov User_AX,ax ; return AX value
+
+ ret
+cEnd nogen
+
+
+ifdef WIN32S
+SZW32SYS db "W32SYS.DLL", 0
+ExecPEOrd equ 3
+
+;-----------------------------------------------------------------------;
+; ExecPE
+; Get ExecPE address in W32SYS.DLL, and call it
+; 11-13-91 AviN created
+;-----------------------------------------------------------------------;
+
+cProc ExecPE,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ mov ax, SEG selExecPE
+ mov ds, ax
+
+assumes DS, DATA
+
+ mov dx, selExecPE ; check for a valid address
+ or dx, dx
+ jnz ep_x
+
+ mov ax, offExecPE
+ or ax, ax
+ jnz ep_err ; already failed, don't try again
+
+
+ cCall ISetErrorMode, <8000h>
+ push ax
+
+ lea ax, SZW32SYS
+ cCall LoadLibrary,<cs, ax>
+
+ pop dx
+ push ax
+ cCall ISetErrorMode,<dx> ; restore original error mode
+ pop ax
+
+ cmp ax, 32
+ jbe ep_err
+
+ push ax
+ push 0
+ push ExecPEOrd
+ cCall GetProcAddress
+ or dx,dx
+ jz ep_err
+ mov selExecPE, dx
+ mov offExecPE, ax
+ep_x:
+
+ pop ax ; saved DS
+ push selExecPE ; jmp to ExecPE
+ push offExecPE
+ mov ds, ax
+ retf
+
+ep_err:
+ ; if w32sys support no available return
+ mov ax, 11 ; invalid module format
+ mov offExecPE, ax ; and record for next time
+
+ pop ds
+ retf 10 ; pop ExecPE parameters
+
+
+assumes DS,NOTHING
+cEnd nogen
+endif
+
+
+sEnd NRESCODE
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+externNP MISCMapDStoDATA
+
+;-----------------------------------------------------------------------;
+; ;
+; Get the Current PDB without doing a DOS call. ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc GetCurrentPDB,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov dx,TopPDB
+ mov ds,curTDB
+ UnSetKernelDS
+ mov ax,ds:[TDB_PDB]
+ pop ds
+ ret
+cEnd nogen
+
+
+sEnd MISCCODE
+
+end
+
diff --git a/private/mvdm/wow16/kernel31/ikernel.h b/private/mvdm/wow16/kernel31/ikernel.h
new file mode 100644
index 000000000..3ebcc30b0
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ikernel.h
@@ -0,0 +1,73 @@
+#define API _far _pascal _loadds
+
+HANDLE API IGlobalAlloc(WORD, DWORD);
+DWORD API IGlobalCompact(DWORD);
+HANDLE API IGlobalFree(HANDLE);
+DWORD API IGlobalHandle(WORD);
+LPSTR API IGlobalLock(HANDLE);
+HANDLE API IGlobalReAlloc(HANDLE, DWORD, WORD);
+DWORD API IGlobalSize(HANDLE);
+BOOL API IGlobalUnlock(HANDLE);
+WORD API IGlobalFlags(HANDLE);
+LPSTR API IGlobalWire(HANDLE);
+BOOL API IGlobalUnWire(HANDLE);
+HANDLE API IGlobalLRUNewest(HANDLE);
+HANDLE API IGlobalLRUOldest(HANDLE);
+VOID API IGlobalNotify(FARPROC);
+WORD API IGlobalPageLock(HANDLE);
+WORD API IGlobalPageUnlock(HANDLE);
+VOID API IGlobalFix(HANDLE);
+BOOL API IGlobalUnfix(HANDLE);
+DWORD API IGlobalDosAlloc(DWORD);
+WORD API IGlobalDosFree(WORD);
+HANDLE API IGetModuleHandle(LPSTR);
+int API IGetModuleUsage(HANDLE);
+int API IGetModuleFileName(HANDLE, LPSTR, int);
+FARPROC API IGetProcAddress(HANDLE, LPSTR);
+FARPROC API IMakeProcInstance(FARPROC, HANDLE);
+void API IFreeProcInstance(FARPROC);
+void API IOutputDebugString(LPSTR);
+//LPSTR API Ilstrcpy( LPSTR, LPSTR );
+//LPSTR API Ilstrcat( LPSTR, LPSTR );
+//int API IlstrOriginal( LPSTR, LPSTR );
+//int API Ilstrlen( LPSTR );
+int API I_lopen( LPSTR, int );
+int API I_lclose( int );
+int API I_lcreat( LPSTR, int );
+LONG API I_llseek( int, long, int );
+WORD API I_lread( int, LPSTR, int );
+WORD API I_lwrite( int, LPSTR, int );
+
+#define GlobalAlloc IGlobalAlloc
+#define GlobalFree IGlobalFree
+#define GlobalHandle IGlobalHandle
+#define GlobalLock IGlobalLock
+#define GlobalReAlloc IGlobalReAlloc
+#define GlobalSize IGlobalSize
+#define GlobalUnlock IGlobalUnlock
+#define GlobalFlags IGlobalFlags
+#define GlobalWire IGlobalWire
+#define GlobalUnWire IGlobalUnWire
+#define GlobalLRUNewest IGlobalLRUNewest
+#define GlobalLRUOldest IGlobalLRUOldest
+#define GlobalNotify IGlobalNotify
+#define GlobalPageLock IGlobalPageLock
+#define GlobalPageUnlock IGlobalPageUnlock
+#define GlobalFix IGlobalFix
+#define GlobalUnfix IGlobalUnfix
+#define GetProcAddress IGetProcAddress
+#define GetModuleHandle IGetModuleHandle
+#define GetModuleUsage IGetModuleUsage
+#define GetModuleFileName IGetModuleFileName
+#define GetFreeSpace IGetFreeSpace
+#define GetTempFileName IGetTempFileName
+//#define lstrcpy Ilstrcpy
+//#define lstrcat Ilstrcat
+//#define lstrOriginal IlstrOriginal
+//#define lstrlen Ilstrlen
+#define _lopen I_lopen
+#define _lclose I_lclose
+#define _lcreat I_lcreat
+#define _llseek I_llseek
+#define _lread I_lread
+#define _lwrite I_lwrite
diff --git a/private/mvdm/wow16/kernel31/ikernel.inc b/private/mvdm/wow16/kernel31/ikernel.inc
new file mode 100644
index 000000000..f01235c27
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ikernel.inc
@@ -0,0 +1,88 @@
+AllocCStoDSAlias equ <IAllocCStoDSAlias>
+AllocDStoCSAlias equ <IAllocDStoCSAlias>
+FreeSelector equ <IFreeSelector>
+ChangeSelector equ <IChangeSelector>
+LoadResource equ <ILoadResource>
+AccessResource equ <IAccessResource>
+FindResource equ <IFindResource>
+AllocResource equ <IAllocResource>
+FreeResource equ <IFreeResource>
+LockResource equ <ILockResource>
+SetResourceHandler equ <ISetResourceHandler>
+SizeofResource equ <ISizeofResource>
+;AddAtom equ <IAddAtom>
+DeleteAtom equ <IDeleteAtom>
+;FindAtom equ <IFindAtom>
+GetAtomName equ <IGetAtomName>
+GetAtomHandle equ <IGetAtomHandle>
+;Catch equ <ICatch>
+;Throw equ <IThrow>
+FreeModule equ <IFreeModule>
+FreeLibrary equ <IFreeLibrary>
+FatalAppExit equ <IFatalAppExit>
+GlobalAlloc equ <IGlobalAlloc>
+GlobalFree equ <IGlobalFree>
+GlobalHandle equ <IGlobalHandle>
+GlobalLock equ <IGlobalLock>
+GlobalReAlloc equ <IGlobalReAlloc>
+GlobalSize equ <IGlobalSize>
+GlobalUnlock equ <IGlobalUnlock>
+GlobalFlags equ <IGlobalFlags>
+GlobalWire equ <IGlobalWire>
+GlobalUnWire equ <IGlobalUnWire>
+GlobalLRUNewest equ <IGlobalLRUNewest>
+GlobalLRUOldest equ <IGlobalLRUOldest>
+GlobalNotify equ <IGlobalNotify>
+GlobalPageLock equ <IGlobalPageLock>
+GlobalPageUnlock equ <IGlobalPageUnlock>
+GlobalFix equ <IGlobalFix>
+GlobalUnfix equ <IGlobalUnfix>
+LockSegment equ <ILockSegment>
+UnlockSegment equ <IUnlockSegment>
+GetWindowsDirectory equ <IGetWindowsDirectory>
+GetSystemDirectory equ <IGetSystemDirectory>
+MakeProcInstance equ <IMakeProcInstance>
+FreeProcInstance equ <IFreeProcInstance>
+GetCodeInfo equ <IGetCodeInfo>
+GetProcAddress equ <IGetProcAddress>
+GetModuleHandle equ <IGetModuleHandle>
+GetModuleUsage equ <IGetModuleUsage>
+GetModuleFileName equ <IGetModuleFileName>
+GetInstanceData equ <IGetInstanceData>
+GetFreeSpace equ <IGetFreeSpace>
+GetTempFileName equ <IGetTempFileName>
+;lstrcpy equ <Ilstrcpy>
+;lstrcat equ <Ilstrcat>
+;lstrlen equ <Ilstrlen>
+_lopen equ <I_lopen>
+_lclose equ <I_lclose>
+_lcreat equ <I_lcreat>
+_llseek equ <I_llseek>
+_lread equ <I_lread>
+_lwrite equ <I_lwrite>
+LoadLibrary equ <ILoadLibrary>
+;LoadModule equ <ILoadModule> ;;; ATM: Can't call internal function
+LocalAlloc equ <ILocalAlloc>
+LocalFree equ <ILocalFree>
+LocalLock equ <ILocalLock>
+LocalReAlloc equ <ILocalReAlloc>
+LocalSize equ <ILocalSize>
+LocalUnlock equ <ILocalUnlock>
+LocalFlags equ <ILocalFlags>
+LocalNotify equ <ILocalNotify>
+OpenFile equ <IOpenFile>
+;SwitchStackTo equ <ISwitchStackTo>
+SetHandleCount equ <ISetHandleCount>
+SetErrorMode equ <ISetErrorMode>
+SwapRecording equ <ISwapRecording>
+WinExec equ <IWinExec>
+GetProfileInt equ <IGetProfileInt>
+GetProfileString equ <IGetProfileString>
+GetPrivateProfileInt equ <IGetPrivateProfileInt>
+GetPrivateProfileString equ <IGetPrivateProfileString>
+RegEnumKey32 equ <IRegEnumKey32>
+RegOpenKey32 equ <IRegOpenKey32>
+RegCloseKey32 equ <IRegCloseKey32>
+RegEnumValue32 equ <IRegEnumValue32>
+WriteProfileString equ <IWriteProfileString>
+WritePrivateProfileString equ <IWritePrivateProfileString>
diff --git a/private/mvdm/wow16/kernel31/int24.asm b/private/mvdm/wow16/kernel31/int24.asm
new file mode 100644
index 000000000..7801feac9
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/int24.asm
@@ -0,0 +1,558 @@
+
+;-----------------------------------------------------------------------;
+; ;
+; Windows Critical Error Handler ;
+; ;
+;-----------------------------------------------------------------------;
+
+.xlist
+include kernel.inc
+include tdb.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+DEVSTRC struc
+devLink dd ?
+devAttr dw ?
+devPtr1 dw ?
+devPtr2 dw ?
+devName db 8 dup (?)
+DEVSTRC ends
+
+IDABORT = 3
+IDRETRY = 4
+IDIGNORE = 5
+
+;-----------------------------------------------------------------------;
+; ;
+; XENIX calls all return error codes through AX. If an error occurred ;
+; then the carry bit will be set and the error code is in AX. ;
+; If no error occurred then the carry bit is reset and AX contains ;
+; returned info. ;
+; ;
+; Since the set of error codes is being extended as we extend the ;
+; operating system, we have provided a means for applications to ask ;
+; the system for a recommended course of action when they receive an ;
+; error. ;
+; ;
+; The GetExtendedError system call returns a universal error, an error ;
+; location and a recommended course of action. The universal error ;
+; code is a symptom of the error REGARDLESS of the context in which ;
+; GetExtendedError is issued. ;
+; ;
+; These are the universal int 24h mappings for the old INT 24 set of ;
+; errors. ;
+; ;
+;-----------------------------------------------------------------------;
+
+error_write_protect EQU 19
+error_bad_unit EQU 20
+error_not_ready EQU 21
+error_bad_command EQU 22
+error_CRC EQU 23
+error_bad_length EQU 24
+error_Seek EQU 25
+error_not_DOS_disk EQU 26
+error_sector_not_found EQU 27
+error_out_of_paper EQU 28
+error_write_fault EQU 29
+error_read_fault EQU 30
+error_gen_failure EQU 31
+
+; These are the new 3.0 error codes reported through INT 24h
+
+error_sharing_violation EQU 32
+error_lock_violation EQU 33
+error_wrong_disk EQU 34
+error_FCB_unavailable EQU 35
+
+; New OEM network-related errors are 50-79
+
+error_not_supported EQU 50
+
+; End of INT 24h reportable errors
+
+error_file_exists EQU 80
+error_DUP_FCB EQU 81 ; *****
+error_cannot_make EQU 82
+error_FAIL_I24 EQU 83
+
+; New 3.0 network related error codes
+
+error_out_of_structures EQU 84
+error_Already_assigned EQU 85
+error_invalid_password EQU 86
+error_invalid_parameter EQU 87
+error_NET_write_fault EQU 88
+
+error_I24_write_protect EQU 0
+error_I24_bad_unit EQU 1
+error_I24_not_ready EQU 2
+error_I24_bad_command EQU 3
+error_I24_CRC EQU 4
+error_I24_bad_length EQU 5
+error_I24_Seek EQU 6
+error_I24_not_DOS_disk EQU 7
+error_I24_sector_not_found EQU 8
+error_I24_out_of_paper EQU 9
+error_I24_write_fault EQU 0Ah
+error_I24_read_fault EQU 0Bh
+error_I24_gen_failure EQU 0Ch
+; NOTE: Code 0Dh is used by MT-DOS.
+error_I24_wrong_disk EQU 0Fh
+
+; THE FOLLOWING ARE MASKS FOR THE AH REGISTER ON Int 24h
+
+Allowed_FAIL EQU 00001000b
+Allowed_RETRY EQU 00010000b
+Allowed_IGNORE EQU 00100000b
+
+;NOTE: ABORT is ALWAYS allowed
+
+I24_operation EQU 00000001b ;Z if READ,NZ if Write
+I24_area EQU 00000110b ; 00 if DOS
+ ; 01 if FAT
+ ; 10 if root DIR
+DataBegin
+
+externB SysErr
+externB msgWriteProtect
+externB drvlet1
+externB msgCannotReadDrv
+externB drvlet2
+externB msgCannotWriteDrv
+externB drvlet3
+externB msgShare
+externB drvlet4
+externB msgNetError
+externB drvlet5
+externB msgCannotReadDev
+externB devenam1
+externB msgCannotWriteDev
+externB devenam2
+externB devenam3
+externB msgNetErrorDev
+externB msgNoPrinter
+externB OutBuf
+externB Kernel_Flags
+externB Kernel_InDOS
+externB Kernel_InINT24
+externB InScheduler
+externB cdevat
+externB errcap
+externB fNovell
+externB fDW_Int21h
+externW pGlobalHeap
+externW CurTDB
+;externW MyCSDS
+externW LastExtendedError
+if 0; EarleH
+externW LastCriticalError
+endif ; 0
+externD pSErrProc
+externD InDOS
+
+fDialogShown db 0 ; NZ if end user sees dialog box
+
+if ROM
+externD prevInt21Proc
+endif
+
+DataEnd
+
+INT24STACK STRUC
+Int24_IP dw ?
+Int24_CS dw ?
+Int24_FG dw ?
+Int24_AX dw ?
+Int24_BX dw ?
+Int24_CX dw ?
+Int24_DX dw ?
+Int24_SI dw ?
+Int24_DI dw ?
+Int24_BP dw ?
+Int24_DS dw ?
+Int24_ES dw ?
+INT24STACK ENDS
+
+
+sBegin code
+ assumes cs,code
+ assumes ds,nothing
+ assumes es,nothing
+
+ife ROM
+externD prevInt21Proc
+endif
+
+externNP AppendFirst
+externNP GetKernelDataSeg
+
+;-----------------------------------------------------------------------;
+; Int24Handler ;
+; ;
+; This is the default disk error handling code available to all ;
+; users if they do not try to intercept interrupt 24h. ;
+; The two options given the user are RETRY and FAIL. Retry goes back ;
+; to DOS. If FAIL is chosen then for DOS 3.XX we return to DOS, but ;
+; for DOS 2.XX we do the fail ourselves and return to the APP. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Feb 03, 1987 10:10:09p -by- David N. Weise [davidw] ;
+; Removed the poking around in DOS by using Kernel_InDOS. ;
+; ;
+; Tue Jan 27, 1987 07:58:56p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Int24Handler,<PUBLIC,NEAR>
+cBegin nogen
+
+ push ds
+ SetKernelDS
+ mov fDialogShown, 0 ; Assume no dialog box
+ inc InScheduler ; Prevent recursion
+ cmp InScheduler,1 ; Well are we?
+ jz NotInSched ; No, then handle this one
+ jmp ReturnError ; Yes, return abort
+
+NotInSched:
+ mov Kernel_InINT24,1
+ FSTI
+ cld
+ push es
+ push dx
+ push cx
+ push bx
+
+; Save away the return capabilities mask.
+
+ mov errcap,ah ; save the capabilities mask
+ push di
+ mov ds,bp
+ UnSetKernelDS
+ SetKernelDS es
+ mov cx,[si].devAttr
+ mov cdevat,ch
+ mov di,dataOffset devenam1
+ mov cx,8
+ add si,devName ; suck up device name (even on block)
+ push si
+ rep movsb
+ pop si
+ mov di,dataOffset devenam2
+ mov cl,8
+ push si
+ rep movsb
+ pop si
+ mov di,dataOffset devenam3
+ mov cl,8
+ rep movsb
+ pop di
+
+ SetKernelDS
+ UnSetKernelDS es
+if 0; EarleH
+ mov LastCriticalError, di
+endif
+
+ add al,'A' ; compute drive letter (even on character)
+ mov drvlet1,al
+ mov drvlet2,al
+ mov drvlet3,al
+ mov drvlet4,al
+ mov drvlet5,al
+
+; At app exit time we will Ignore any critical errors. This is
+; because errors that usually occur at app exit time are generally
+; due to the network beeping death. Trying to put up the dialog
+; hangs Windows because USER doesn't think the task exists any more.
+; THIS IS AN INCREADABLE HACK!! We don'r really know if we can
+; ignore all critical errors, but hey, nobodies complained yet.
+
+ test Kernel_flags[2],KF2_WIN_EXIT ; prevent int 24h dialogs
+ jz SetMsg
+ xor ax,ax
+ jmp eexit
+
+SetMsg: test ah,1
+ jz ReadMes
+
+WriteMes:
+ mov si,dataOffset msgCannotWriteDev
+ test cdevat,10000000b
+ jnz Gotmes
+ mov si,dataOffset msgCannotWriteDrv
+ jmps Gotmes
+
+ReadMes:
+ mov si,dataOffset msgCannotReadDev
+ test cdevat,10000000b
+ jnz Gotmes
+ mov si,dataOffset msgCannotReadDrv
+Gotmes:
+
+; reach into DOS to get the extended error code
+
+;;; les bx,InDOS
+;;; mov ax,es:[bx].3
+
+ push es ; DOS may trash these...
+ push ds
+ push si
+ push di
+ xor bx, bx
+ mov ah, 59h
+ pushf
+ call prevInt21Proc
+ mov LastExtendedError, ax
+ mov LastExtendedError[2], bx
+ mov LastExtendedError[4], cx
+ pop di
+ pop si
+ pop ds
+ pop es
+
+ mov dx,dataOffset msgWriteProtect
+ cmp ax,error_write_protect
+ jz prmes ; Yes
+ mov dx,dataOffset msgNoPrinter
+ cmp al,error_out_of_paper
+ jz prmes ; Yes
+ mov dx,dataOffset msgShare
+ cmp al,error_sharing_violation
+ jz prmes ; Yes
+ cmp al,error_lock_violation
+ jz prmes ; Yes
+ mov dx,dataOffset msgNetError
+ test cdevat,10000000b
+ jz check_net_error
+ mov dx,dataOffset msgNetErrorDev
+check_net_error:
+ cmp al,50
+ jb not_net_error
+ cmp al,80
+ ja not_net_error
+ test Kernel_Flags[2],KF2_APP_EXIT
+ jz prmes
+ jmps ReturnError
+
+not_net_error:
+
+ mov dx,si ; Message in SI is correct
+
+prmes: call AppendFirst ; print error type
+
+ mov es,curTDB ; Point to current task
+ mov ax,es:[TDB_errMode] ; See if wants default error processing
+ test al,1 ; Low-order bit = zero means
+ jz ask ; ...put up dialog box
+ mov al,2
+ jmps eexit ; <> 0 means return error from call
+
+ask: mov es,pGlobalHeap
+ inc es:[hi_freeze] ; freeze global heap
+ call ShowDialogBox
+ mov fDialogShown, dl ; will be 0 if dialog box NOT shown
+ mov es,pGlobalHeap
+ dec es:[hi_freeze] ; thaw global heap
+
+eexit: pop bx
+ pop cx
+ pop dx
+ pop es
+ cmp al,2 ; retry, ignore?
+ jb aexit ; yes, return to dos
+
+ cmp fNovell, 0
+ je ReturnError ; Not NOVELL
+ test errcap, Allowed_FAIL
+ jnz ReturnError ; We CAN fail, so we do.
+ push ax
+ mov ax, di
+ cmp al, 0Ch ; General failure
+ pop ax
+ jne ReturnError
+ cmp word ptr devenam1[0], 'EN'
+ jne ReturnError
+ cmp word ptr devenam1[2], 'WT'
+ jne ReturnError
+ cmp word ptr devenam1[4], 'RO'
+ jne ReturnError
+ cmp word ptr devenam1[6], 'K'
+ jne ReturnError
+ mov al, 2 ; ABORT because NOVELL doesn't like FAIL
+ jmps aexit
+
+ReturnError:
+ mov al,3 ; change to return error code
+
+; If the user canceled an error generated by the Int 21h to AUX: in kernel's
+; DebugWrite routine, set a flag telling DebugWrite not to do that anymore.
+
+ cmp fDialogShown, 0 ; Did end user see dialog box?
+ jz not_krnl
+ cmp fDW_Int21h, 0 ; fDW_Int21h will == 0 if caused by
+ jnz not_krnl ; Int 21h/Write to AUX: in DebugWrite.
+ mov fDW_Int21h, 2 ; Prevent DebugWrite from trying again
+not_krnl: ; (any value >= 2, <= 0FEh works)
+
+aexit: mov Kernel_InINT24,0
+ dec InScheduler
+ pop ds
+ UnSetKernelDS ds
+ FSTI
+ iret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ShowDialogBox
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 02-Dec-1989 15:28:51 -by- David N. Weise [davidw]
+; Removed the stack switching because of the new WinOldAp support,
+; and added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc ShowDialogBox,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ CheckKernelDS
+ ReSetKernelDS
+
+ mov ax,3 ; assume no USER therefor CANCEL
+ xor dx, dx
+ cmp pSErrProc.sel,0 ; is there a USER yet?
+ jz sdb_exit
+
+ push bp
+ xor bp,bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,dataOffset OutBuf ; lpText
+ push ax
+ push ds
+ mov ax,dataOffset SysErr ; lpCaption
+ push ax
+
+; Set up the buttons based on the capabilities mask. Cancel is always
+; availible. Retry and Ignore are not always available.
+
+ mov ax,SEB_CANCEL+SEB_DEFBUTTON ; cancel is always allowed
+ push ax
+ xor ax,ax ; assume no second button
+if 0 ; 05 feb 1990, ignoring is not user friendly, win 2.x did not allow it
+ test errcap,20h ; is ignore allowed?
+ jz button_2
+ mov ax,SEB_IGNORE ; ignore is the second button
+endif
+
+button_2:
+ push ax
+
+ xor ax,ax ; assume no third button
+ test errcap,10h ; is retry allowed?
+ jz button_3
+ mov ax,SEB_RETRY ; retry is the third button
+button_3:
+ push ax
+dobox:
+ call [pSErrProc] ; USER.SysErrorBox()
+ mov dx, ax
+
+; We need to map the return as follows:
+; button 1 (Cancel) => 3 3
+; button 2 (Retry) => 1 0
+; button 3 (Ignore) => 0 1
+
+ sub al,2
+ jnb codeok
+ mov al,3
+codeok:
+ pop bp
+ pop bp
+sdb_exit:
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; GetLPErrMode ;
+; ;
+; This routine returns a long pointer to the Kernel_InDOS and ;
+; Kernel_InINT24 bytes inside the KERNEL. It is used by 386 WINOLDAP ;
+; to prevent switching while inside INT 24 errors from other VMs. ;
+; ;
+; NOTE: Do not change this call without talking to the WIN/386 group. ;
+; NOTE: USER also uses this call to determine whether PostMessage ;
+; can call FatalExit. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; DX:AX = pointer to Kernel_InDOS followed by Kernel_InINT24 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Jan 27, 1987 07:13:27p -by- David N. Weise [davidw] ;
+; Rewrote it and added this nifty comment block. ;
+; ;
+; 7/23/87 -by- Arron Reynolds [aaronr], updated comments to desired ;
+; state. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetLPErrMode,<PUBLIC,FAR>
+cBegin nogen
+ call GetKernelDataSeg
+ mov dx, ax
+ mov ax,dataOffset Kernel_InDOS
+ ret
+cEnd nogen
+
+sEnd code
+
+end
diff --git a/private/mvdm/wow16/kernel31/intnn.asm b/private/mvdm/wow16/kernel31/intnn.asm
new file mode 100644
index 000000000..f7d9830b8
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/intnn.asm
@@ -0,0 +1,133 @@
+
+
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+.list
+
+DataBegin
+
+externW curTDB
+
+DataEnd
+
+sBegin CODE
+externD prevInt10proc
+assumes CS,CODE
+assumes ds, nothing
+assumes es, nothing
+
+;-----------------------------------------------------------------------;
+; IntnnHandlers - Handlers for int 0, 2, 4, 6, 7, 10, 3E, 75 ;
+; ;
+; Slimed in here for lack of a better place. ;
+; Merely jump through the vector saved in the TDB ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc Int00Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS
+IntnnCommon:
+ sub sp, 2 ; Make room for dword (saved bx is
+ push bp ; other word)
+ mov bp, sp
+ push ds
+
+ SetKernelDS
+ mov ds, CurTDB
+ UnSetKernelDS
+ push [bx] ; Fill in dword with vector contents
+ pop [bp+2]
+ mov bx, [bx+2]
+ xchg bx, [bp+4] ; Fill in segment, recover bx
+ pop ds
+ pop bp
+ retf
+cEnd nogen
+
+cProc Int02Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+4
+ jmps IntnnCommon
+cEnd nogen
+
+cProc Int04Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+8
+ jmps IntnnCommon
+cEnd nogen
+
+cProc Int06Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+12
+ jmps IntnnCommon
+cEnd nogen
+
+cProc Int07Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+16
+ jmps IntnnCommon
+cEnd nogen
+
+cProc Int3EHandler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+20
+ jmps IntnnCommon
+cEnd nogen
+
+cProc Int75Handler,<PUBLIC,FAR>
+cBegin nogen
+ push bx
+ mov bx, TDB_INTVECS+24
+ jmps IntnnCommon
+cEnd nogen
+
+ifdef WOW
+
+cProc Int10Handler,<PUBLIC,FAR>
+
+;; QuattroPro for windows does direct VGA programming if they detect
+;; that the monitor they are running on is a VGA. On NT if they program
+;; the VGA we trap all the operations in NTVDM - but it makes QuattroPro
+;; look very slow. So we lie to them here bl = 0 No monitor. That way
+;; they don't do direct VGA programming and run fast.
+;; - mattfe june 93
+;;
+;; if function == 1h (get monitor type)
+;; then return 0 - No monitor
+;; else
+;; chain into real int10 handler
+
+cBegin nogen
+ cmp ah,1ah
+ jne int10h_dontbother
+
+ mov bl,00h
+ IRET
+
+int10h_dontbother:
+ jmp cs:prevInt10proc
+cEnd nogen
+
+endif; WOW
+
+;-----------------------------------------------------------------------;
+; FOR INT HANDLER SEE ;
+; ;
+; 21h i21entry.asm ;
+; 3Fh ldint.asm ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/kdata.asm b/private/mvdm/wow16/kernel31/kdata.asm
new file mode 100644
index 000000000..26d4850f4
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kdata.asm
@@ -0,0 +1,540 @@
+ TITLE KDATA - Kernel data area
+
+win3debdata=1
+include gpfix.inc ; include first to define segment order
+include kernel.inc
+include gpcont.inc ; do we alloc Sherlock data items?
+
+extrn __ahshift:ABS ; Pull in LDBOOT.ASM next from KERNOBJ.LIB
+
+sBegin CODE
+externFP Int21Handler
+sEnd CODE
+
+public __acrtused
+ __acrtused = 9697
+
+;------------------------------------------------------------------------
+; Segment definations to define labels at the segment start. Don't put
+; any code or data here.
+;------------------------------------------------------------------------
+
+sBegin EMSCODE
+labelB <PUBLIC,beg_emscode>
+sEnd EMSCODE
+
+sBegin INITCODE
+labelB <PUBLIC,initcode>
+sEnd INITCODE
+
+DataBegin INIT
+labelB <PUBLIC,initdata>
+DataEnd INIT
+
+DataBegin EMS
+labelB <PUBLIC,beg_emsdata>
+DataEnd EMS
+
+
+;------------------------------------------------------------------------
+; D A T A S E G M E N T V A R I A B L E S
+;------------------------------------------------------------------------
+
+DataBegin
+
+; The following items must remain in the same location and order. These
+; items also appear in the initial paragraph of each application's DS.
+
+ ORG 0
+
+ DW 0
+ globalW oOldSP,0
+ globalW hOldSS,5
+ globalW pLocalHeap,0
+ globalW pAtomTable,0
+ globalW pStackTop,<dataOffset gmove_stack_top>
+ globalW pStackMin,<dataOffset gmove_stack>
+ globalW pStackBot,<dataOffset gmove_stack>
+
+;------------------------------------------------------------------------
+if KDEBUG
+; If this word gets trashed, then we overflowed our stack
+
+globalW gmove_stack_sig,STACK_SIGNATURE,16
+endif
+
+labelB <PUBLIC,lpszFileName> ; Used in FileCDR_notify
+ gmove_stack_top label byte
+
+ EVEN
+
+ DW 256 DUP (0) ; gmove requires at least 64 words
+
+globalW gmove_stack,0
+
+globalW prev_gmove_SP,0
+globalW prev_gmove_SS,0
+globalW ss_sel,0
+
+;------------------------------------------------------------------
+
+; The debugger requires that the following items remain in the same
+; relative order.
+
+ labelW <PUBLIC,THHOOK> ; So ToolHelp can find this stuff, too.
+ globalW hGlobalHeap,0 ; Handle to master object
+ globalW pGlobalHeap,0 ; Current physical address of master object
+ globalW hExeHead,0 ; Head of module list maintained by Load/Free Module
+ globalW hExeSweep,0 ; ... 1st module for LRU sweep to examine
+
+ globalW topPDB,0 ; DOS PDB on entry
+ globalW headPDB,0 ; link list of PDBs
+ globalW topsizePDB,0 ; DOS PDB size upon entry
+ globalW headTDB,0 ; head of task queue
+ globalW curTDB,0 ; handle for currently running task
+ globalW loadTDB,0 ; handle for currently loading task
+ globalW LockTDB,0 ; handle of super task
+ globalW SelTableLen,0 ; DONT MOVE THIS
+ globalD SelTableStart,0 ; DONT MOVE THIS
+ if PMODE32
+ globalD hBmDPMI,0 ; DPMI handle to BurgerMaster
+ endif
+
+;------------------------------------------------------------------------
+globalW winVer,30Ah ; Windows version number for KERNEL.EXE header
+globalW fWinx,0 ; Flag from ldboot.asm
+globalW f8087,0 ; non zero if 8087 installed
+globalW PHTcount,0 ; Count of tasks with a PHT
+globalW hGDI,0 ; module handle of GDI
+globalW hUser,0 ; module handle of User
+globalW hShell,0 ; module handle of Shell
+globalW fLMdepth,0 ; # of recursive LoadModules
+globalW wDefRIP,0 ; Value to return from RIP in Debug
+globalB num_Tasks,0 ; number of tasks (i.e. TDB's) in system
+globalB InScheduler,0 ; True if inside scheduler
+globalB graphics,1 ; True if user/keyboard/gdi/display loaded
+ DB 0
+globalB fastfp,1 ; True if suppress FWAIT before FOp
+
+;globalW PID_for_fake,0 ; the PID allocated for the fake task
+;globalW EMS_calc_swap_line,0 ; The calculated swap line
+;globalW EMSCurPID,0 ; The current PID.
+
+globalW MaxCodeSwapArea,0 ; The max paragraphs SetSwapAreaSize can set.
+
+globalW selLowHeap,0 ; selector to Windows Low ( < 640k) heap block
+globalW cpLowHeap,0 ; count of paragraphs of Low heap block
+globalW selHighHeap,0 ; selector to Windows High ( >640k) heap block
+globalW selWoaPdb,0 ; selector to fixed low PDB for WinOldApp
+globalW sel_alias_array,0 ; the selector alias array (286 only)
+globalW temp_sel,0 ; Single pre-allocated selector
+globalD dressed_for_success,0 ; callback into OS/2 mapping layer at app start
+ife PMODE32
+globalW hXMMHeap,0 ; XMS handle to secondary extended heap block
+endif
+
+
+globalD InDOS,0 ; -> in dos flags and stuff
+globalD pSftLink,0 ; -> end of Sft chain when we started
+globalD lpWinSftLink,0 ; -> first node in chain that windows adds
+
+ifdef WOW
+globalD pDosWowData,0 ; -> rmode pointer to DosWowData in DOSDATA
+globalD pPMDosCDSCNT,0 ; -> DOS CDS Count variable
+globalD pPMDosCURDRV,0 ; -> DOS CurDrv variable
+globalD pPMDosPDB,0 ; -> pointer to PDB in DOSDATA
+endif
+
+globalD pFileTable,0 ; -> beginning of Sft chain
+globalW FileEntrySize,0 ; size of one sft entry
+globalD curDTA,0 ; what DOS thinks is the current DTA
+globalW cur_dos_PDB,0 ; what DOS thinks is the current PDB
+globalW Win_PDB,0 ; what we want the PDB to be
+globalW cur_drive_owner,0 ; last TDB to change the disk or directory
+globalB fBreak,0 ; state of dos break flag between e&d dos
+globalB LastDriveSwapped,0 ; drive letter of last drive where disk swap
+globalB DOS_version,0 ; DOS major version number
+globalB DOS_revision,0 ; DOS minor version number
+globalB fInt21,0 ; Flag indicating INT 21 hooks are installed
+globalB fNovell,0 ; Have Novell network
+globalB fPadCode,0 ; Pad code segments for 286 chip bug
+globalB CurDOSDrive,0FFh ; Current drive according to DOS
+globalB DOSDrives,26 ; number of logical drives from DOS
+
+;----------------------------------------------------------------------
+
+; PhantArray is a byte array indexed by zero based drive number.
+; A non-zero value indicates the drive is phantom.
+
+globalB PhantArray,0,26
+
+
+; Keyboard inquire structure
+globalB fFarEast,0 ; non zero means far eastern keyboard
+ifdef DBCS
+globalB fDBCSLeadTable,0,256 ; DBCS lead byte index table
+endif
+globalB KeyInfo,0,%(SIZE KBINFO)
+
+; Procedure addresses initialized by InitFwdRef
+
+ ALIGN 4
+
+globalD pSysProc,0 ; -> SYSTEM.InquireSystem
+globalD pTimerProc,0 ; -> SYSTEM.CreateTimer
+globalD pSystemTermProc,0 ; -> SYSTEM.Disable
+globalD pKeyProc,0 ; -> KEYBOARD.AnsiToOem
+globalD pKeyProc1,0 ; -> KEYBOARD.OemToAnsi
+globalD pKeyboardTermProc,0 ; -> KEYBOARD.Disable
+globalD pKeyboardSysReq,0 ; -> KEYBOARD.EnableKBSysReq
+globalD pDisplayCritSec,0 ; -> DISPLAY.500
+globalD pMouseTermProc,0 ; -> MOUSE.Disable
+globalD pMBoxProc,0 ; -> USER.MessageBox
+globalD pSErrProc,0 ; -> USER.SysErrorBox
+globalD pExitProc,0 ; -> USER.ExitWindows
+globalD pDisableProc,0 ; -> USER.DisableOEMLayer
+globalD pUserInitDone,0 ; -> USER.routine to call when init is done
+globalD pPostMessage,0 ; -> USER.PostMessage function
+globalD pSignalProc,0 ; -> USER.SignalProc function
+globalD pIsUserIdle,0 ; -> USER.IsUserIdle function
+globalD pUserGetFocus,0 ; -> USER.GetFocus function
+globalD pUserGetWinTask,0 ; -> USER.GetWindowTask function
+globalD pUserIsWindow,0 ; -> USER.IsWindow function
+globalD pGetFreeSystemResources,0 ; -> USER.GetFreeSystemResources function
+
+if ROM
+ globalD pYieldProc,0 ; -> USER.UserYield
+ globalD pStringFunc,0 ; -> USER.StringFunc function
+
+ globalD prevInt21proc,0 ; -> previous INT 21h handler
+ globalD prevInt24proc,0 ; -> previous Int 24h handler
+ globalD prevInt2Fproc,0 ; -> previous Int 24h handler
+ globalD prevInt3Fproc,0 ; -> previous Int 3Fh handler
+ globalD prevInt67proc,0 ; -> previous Int 67h handler
+ globalD prevInt00proc,0 ; -> previous INT 00h handler !! don't move
+ ; !! don't move
+ globalD prevInt02proc,0 ; -> previous INT 02h handler !! don't move
+ globalD prevInt04proc,0 ; -> previous INT 04h handler !! don't move
+ globalD prevInt06proc,0 ; -> previous INT 06h handler !! don't move
+ globalD prevInt07proc,0 ; -> previous INT 07h handler !! don't move
+ globalD prevInt3Eproc,0 ; -> previous INT 3Eh handler !! don't move
+ globalD prevInt75proc,0 ; -> previous INT 75h handler !! don't move
+ globalD prevIntx6proc,0 ; -> previous invalid op-code Fault handler
+ globalD prevInt0Cproc,0 ; -> previous stack fault handler
+ globalD prevInt0Dproc,0 ; -> previous GP Fault handler
+ globalD prevInt0Eproc,0 ; -> previous Page Fault handler
+endif
+
+globalD lpInt21,0 ; support for NOVELL stealing int 21h
+globalD myInt2F,0 ; support for NOVELL swapping with DOS apps
+globalD FatalExitProc,0 ; Intercept for FatalExit()
+
+globalD ptrace_dll_entry,0 ; -> ptrace engine DLL entry
+globalD ptrace_app_entry,0 ; -> real entry point for app
+globalD lpfnToolHelpProc,0 ; TOOLHELP.DLL PTrace function
+globalW wExitingTDB,0 ; Flag for DebugWrite--no debug strings at exit
+globalD shell_file_proc,0 ; -> shell for file create/del notify
+globalW shell_file_TDB,0 ; shell TDB
+if SWAPPRO
+ globalD prevIntF0proc,0 ; -> previous Int F0h handler
+ globalW hSwapPro,-1 ; file handle for swap profiler
+ globalB fSwappro,0 ; 0 = no swap info, 1 = swaps, 2 = all
+ DB 0
+endif
+
+globalD gcompact_start,0 ; start to measure swapping
+globalD gcompact_timer,0 ; time spent in gcompact to measure swapping
+
+ifdef JAPAN
+ globalD pJpnSysProc,0 ; -> SYSTEM.JapanInquireSystem
+endif
+
+globalW WinFlags,0 ; see kernel.inc for defs of these
+
+globalB Kernel_Flags,0,4 ; see kernel.inc for defs of these
+;
+; WARNING!! Do not disturb the order of the next two variables....
+; See GetLPErrormode in INT24.ASM ARR 7/23/87
+;
+globalB Kernel_InDOS,0 ; set when we call the REAL DOS
+globalB Kernel_InINT24,0 ; set when Int 24h calls DOS funcs < 13
+
+globalB fBooting,1 ; Set to zero by bootdone
+globalB fChkSum,0 ; Flag set if segment checksumming enabled
+globalB fCheckFree,1 ; Set to zero by slowboot
+globalB cdevat,0 ; Int 24 state
+globalB errcap,0 ; Int 24 error capabilities mask
+ifndef WOW
+; profile APIs are thunked
+globalB fProfileDirty,0 ; Profiles need writing
+globalB fProfileMaybeStale,0 ; Profiles MAY need to be reread
+globalB fWriteOutProfilesReenter,0 ; Are we currently in WriteOutProfiles?
+endif
+globalB fPokeAtSegments,1 ; Idle time load of segments
+globalB fTaskSwitchCalled, 0 ; Local Reboot only works when task switching
+globalD WinAppHooks,0 ; winapps can hook this for std winoldap.
+
+public WOAName
+WOAName DB 'WINOLDAP.MOD',0
+globalB grab_name,0,128
+
+ALIGN 4
+
+globalD lpWindowsDir,0 ; -> to WFP of where win.ini lives
+globalD lpSystemDir,0 ; -> to WFP of where kernel lives
+globalW cBytesWinDir,0 ; length of WFP for windows dir
+globalW cBytesSysDir,0 ; length of WFP for system dir
+ifdef WOW
+globalD lpSystemRootDir,0 ; -> value of SystemRoot environment var
+globalD lpSystem16Dir,0 ; -> to WFP of \windows\system
+globalD lpSystemWx86Dir,0 ; \windows\system32\Wx86
+globalW cBytesSystemRootDir,0 ; length of SystemrootEnvironment var
+globalW cBytesSys16Dir,0 ; in WOW lpSystemDir points to \windows\system32
+globalW cBytesSysWx86Dir,0 ; in WOW Windows\system32\Wx86
+public Sys16Suffix
+Sys16Suffix DB '\system' ; append to WinDir to get lpSystem16Dir
+public cBytesSys16Suffix
+cBytesSys16Suffix DW ($ - dataoffset Sys16Suffix)
+public SysWx86Suffix
+SysWx86Suffix DB '\Wx86' ; append to SystemDir to get lpSystemWx86Dir
+public cBytesSysWx86Suffix
+cBytesSysWx86Suffix DW ($ - dataoffset SysWx86Suffix)
+
+endif
+
+
+globalD lpGPChain,0 ; GP fault hack for WEPs - chain to this addr
+
+if SHERLOCK
+ globalW gpTrying,0 ; Trying to continue after a GP fault
+ globalW gpEnable, 1 ; Enable GP continuation
+ globalW gpInsLen, 0 ; Length of faulting instruction
+ globalW gpSafe, 0 ; OK to skip current instruction
+ globalW gpRegs, 0 ; Regs modified by faulting insn
+ globalW gpStack, 0 ; movement of stack by faulting insn
+endif
+
+ifndef WOW
+; The profile APIs are thunked for WOW
+globalB WinIniInfo,0,%(size PROINFO)
+globalB PrivateProInfo,0,%(size PROINFO)
+public szUserPro
+szUserPro DB 'WIN.INI',0
+ DB 72 dup (0) ; Room for a long path
+;;;globalB fUserPro,0 ; Current Profile is WIN.INI
+;;;globalD lpszUserPro,0
+endif
+; ndef WOW
+
+globalW BufPos,0 ; buffer pointer with OutBuf
+globalB OutBuf,0,70 ; 70 character out buffer
+
+EVEN
+globalW MyCSAlias,0 ; Kernel's CS/DS Alias
+globalW MyCSSeg,0 ; Kernel's CS as a segment
+globalW MyDSSeg,0 ; Kernel's DS as a segment
+globalW hLoadBlock,0 ; Handle that points to in memory file image
+globalW segLoadBlock,0 ; Segment address of file image
+globalW wMyOpenFileReent, 0 ; Reentrant flag for MyOpenFile
+
+ife ROM
+ globalW cpShrink,0
+ globalW cpShrunk,0 ; Delta from beginning of file to hLoadBlock
+endif
+
+if ROM
+ externD <lmaExtMemROM,cbExtMemROM>
+ globalD lmaHiROM,lmaExtMemROM
+ globalD cbHiROM,cbExtMemROM
+ globalW selROMTOC,0
+ globalW selROMLDT,0
+ globalW sel1stAvail,0
+ globalD linHiROM, 0
+endif
+
+if PMODE32
+ globalW PagingFlags,0
+ globalW ArenaSel,0
+ globalW FirstFreeSel,0
+ globalW CountFreeSel,0
+ globalD FreeArenaList,0
+ globalD FreeArenaCount,0
+ globalD HighestArena,0
+ globalD temp_arena,0
+ globalD NextCandidate,-1
+ globalW Win386_Blocks,0
+ globalW InitialPages,0
+ globalD lpReboot,0 ; Reboot VxD address
+endif
+
+globalW BaseDsc,0
+globalW kr1dsc,0
+globalW kr2dsc,0
+globalW blotdsc,0
+globalW DemandLoadSel,0
+
+globalW fhcStealNext,<(MAXFHCACHELEN-1)*size fhCacheStruc+dataOffset fhCache> ; Next fhCache entry to use
+globalW fhCacheEnd,<MAXFHCACHELEN*size fhCacheStruc+dataOffset fhCache> ; End of the cache
+globalW fhCacheLen,MINFHCACHELEN
+globalB fhCache,0,%(MAXFHCACHELEN*size fhCacheStruc)
+
+if KDEBUG
+ globalB fLoadTrace, 0
+ globalB fPreloadSeg, 0
+ globalB fKTraceOut, 0 ; Used by DebugWrite to ignore traces
+ ; to be sent to PTrace
+endif
+globalB fDW_Int21h, 0FFh ; FF if okay for DebugWrite to use Int 21h
+
+if ROM and PMODE32
+ globalW gdtdsc,0
+endif
+
+ ALIGN 2
+
+if 0; EarleH
+globalW LastCriticalError,-1
+endif
+globalW LastExtendedError,-1,3 ; Don't move this
+globalW Reserved,0,8 ; Don't move this
+
+ifdef WOW
+;------------------------------------------------------------------------
+; W O W G L O B A L D A T A
+;------------------------------------------------------------------------
+globalW wCurTaskSS,0 ; Currently Running Task SS
+globalW wCurTaskBP,0 ; Currently Running Task BP
+globalD Dem16to32handle,0 ; -> DOS Emulation 16 to 32 bit handle convertion
+globalD FastBop,0 ; eip value for fast bop entry point
+globalW FastBopCS,0 ; CS value for fast bop entry point
+globalD FastWOW,0 ; eip for fast WOW32 entry point when doing thunk call
+globalW FastWOWCS,0 ; CS value for fast wow entry point
+globalD FastWOWCbRet,0 ; eip for fast WOW32 entrypoint to return from callback
+globalW FastWOWCbRetCS,0; cs for above
+globalW WOWFastBopping,0; non-zero if fast call to WOW32 enabled
+ ; Jmp indirect through here for faster bops
+globalB fExitOnLastApp,0 ; Close WOW when the last app exits (not WOWEXEC)
+
+;; do not rearrange these or stick anything in the middle!
+;;
+;;
+wowtablemodstart label byte
+globalW MOD_KERNEL ,0 ; kernel must be first!
+globalW MOD_DKERNEL ,0
+globalW MOD_USER ,0
+globalW MOD_DUSER ,0
+globalW MOD_GDI ,0
+globalW MOD_DGDI ,0
+globalW MOD_KEYBOARD ,0
+globalW MOD_SOUND ,0
+globalW MOD_SHELL ,0
+globalW MOD_WINSOCK ,0
+globalW MOD_TOOLHELP ,0
+globalW MOD_MMEDIA ,0
+globalW MOD_COMMDLG ,0
+globalW ModCount ,<($ - dataoffset wowtablemodstart) / 2>
+;;
+;;
+;; do not rearrange these or stick anything in the middle!
+
+globalW DebugWOW,1 ; bit 0 = 1 WOW is being debugged, 0 = WOW is not
+globalW TraceOff,0 ; bit 0 = 1 turn off trace interrupts during apis
+
+globalW WOWLastError,0 ; Last error returned by int 21
+globalB WOWErrClass, 0
+globalB WOWErrAction, 0
+globalB WOWErrLocation, 0
+
+endif
+DataEnd
+
+
+;------------------------------------------------------------------------
+; C O D E S E G M E N T V A R I A B L E S
+;------------------------------------------------------------------------
+
+sBegin CODE
+assumes cs,CODE
+
+ EVEN
+
+ dw 18h dup(0F4CCh) ; Catch them jmps, calls & rets to 0
+ ; and offset segment for putting in HMA
+if ROM
+
+globalW MyCSDS,<seg _DATA> ; Kernel's DS
+ife PMODE32
+externW selLDTAlias
+globalW gdtdsc,selLDTAlias ; Data alias to LDT
+endif
+else
+globalW MyCSDS,0 ; Kernel's DS
+globalW gdtdsc,0
+endif
+
+ ALIGN 4
+
+ife ROM
+globalD pYieldProc,0 ; -> USER.UserYield
+globalD pStringFunc,0 ; -> USER.StringFunc function
+
+globalD prevInt21proc,0 ; -> previous INT 21h handler
+globalD prevInt24proc,0 ; -> previous Int 24h handler
+globalD prevInt2Fproc,0 ; -> previous Int 24h handler
+globalD prevInt3Fproc,0 ; -> previous Int 3Fh handler
+globalD prevInt67proc,0 ; -> previous Int 67h handler
+globalD prevInt00proc,0 ; -> previous INT 00h handler !! don't move
+ ; !! don't move
+globalD prevInt02proc,0 ; -> previous INT 02h handler !! don't move
+globalD prevInt04proc,0 ; -> previous INT 04h handler !! don't move
+globalD prevInt06proc,0 ; -> previous INT 06h handler !! don't move
+globalD prevInt07proc,0 ; -> previous INT 07h handler !! don't move
+globalD prevInt3Eproc,0 ; -> previous INT 3Eh handler !! don't move
+globalD prevInt75proc,0 ; -> previous INT 75h handler !! don't move
+globalD prevIntx6proc,0 ; -> previous invalid op-code Fault handler
+globalD prevInt0Cproc,0 ; -> previous stack fault handler
+globalD prevInt0Dproc,0 ; -> previous GP Fault handler
+globalD prevInt0Eproc,0 ; -> previous Page Fault handler
+ifdef WOW
+globalD prevInt31proc,0 ; used to speed dpmi calls
+globalD oldInt00proc,0 ; for debugging traps
+globalD prevInt01proc,0 ; for debugging traps
+globalD prevInt03proc,0 ; for debugging traps
+globalD prevInt10proc,0 ; -> previous INT 10 handler
+endif
+endif ;!ROM
+
+if 0
+ PUBLIC DummyKeyboardOEMToAnsi
+DummyKeyboardOEMToAnsi proc far
+ ret ; used for non-graphics version
+DummyKeyboardOEMToAnsi endp
+endif
+
+sEnd CODE
+
+
+;------------------------------------------------------------------------
+; I N I T D A T A S E G M E N T V A R I A B L E S
+;------------------------------------------------------------------------
+
+DataBegin INIT
+
+globalW oNRSeg,0
+globalW oMSeg,0
+globalD lpBootApp,0 ; Long pointer to app to run after booting
+ifndef WOW
+; WOW doesn't muck with WOAName buffer, we leave it as WINOLDAP.MOD
+labelB <PUBLIC,woa_286>
+ db 'WINOLDAP.MOD'
+labelB <PUBLIC,woa_386>
+ db 'WINOA386.MOD'
+endif
+labelB <PUBLIC,bootExecBlock>
+ EXECBLOCK <0,0,0,0>
+globalW win_show,2
+ dw 1 ; show open window
+
+DataEnd INIT
+
+end
diff --git a/private/mvdm/wow16/kernel31/kdataend.asm b/private/mvdm/wow16/kernel31/kdataend.asm
new file mode 100644
index 000000000..8eb91849d
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kdataend.asm
@@ -0,0 +1,22 @@
+ TITLE KDATAEND - Kernel ending data area
+
+
+; This file contains the kernel data items that must be at the end of
+; their respective segments. This file is last in the link order.
+
+include kernel.inc
+
+
+; The PADDATA segment performs two functions: it provides ginit with
+; space to create the ending global heap sentinel, and it forces the
+; linker to fully expand DGROUP in the .EXE file. Kernel uses DGROUP
+; before it's actually loaded by LoadSegment, so it needs to be fully
+; expanded when loaded by the DOS EXEC call of kernel.
+
+sBegin PADDATA
+
+ DB 32 DUP (0FFh) ; Room for final arena entry
+
+sEnd PADDATA
+
+end
diff --git a/private/mvdm/wow16/kernel31/kdos.inc b/private/mvdm/wow16/kernel31/kdos.inc
new file mode 100644
index 000000000..0bfe50fce
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kdos.inc
@@ -0,0 +1,39 @@
+
+SG_EXIT = 20H
+
+TASKREG STRUC
+TASKDX DW ?
+TASKBX DW ?
+TASKES DW ?
+TASKCX DW ?
+TASKAX DW ?
+TASKDI DW ?
+TASKSI DW ?
+TASKDS DW ?
+TASKBP DW ?
+TASKREG ENDS
+
+; Exit codes in upper byte
+
+Exit_terminate EQU 0
+Exit_abort EQU 0
+Exit_Ctrl_C EQU 1
+Exit_Hard_Error EQU 2
+Exit_Keep_process EQU 3
+
+user_FG equ word ptr [bp+6]
+user_FL equ byte ptr [bp+6]
+user_CS equ word ptr [bp+4]
+user_IP equ word ptr [bp+2]
+user_BP equ word ptr [bp]
+user_DS equ word ptr [bp-2]
+user_DX equ word ptr [bp-4]
+user_DSDX equ dword ptr [bp-4]
+user_ES equ word ptr [bp-6]
+user_BX equ word ptr [bp-8]
+user_ESBX equ dword ptr [bp-8]
+user_AX equ word ptr [bp-10]
+user_AL equ byte ptr [bp-10]
+user_CX equ word ptr [bp-12]
+user_SI equ word ptr [bp-14]
+user_DI equ word ptr [bp-16]
diff --git a/private/mvdm/wow16/kernel31/kernel.api b/private/mvdm/wow16/kernel31/kernel.api
new file mode 100644
index 000000000..dd4b651f1
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.api
@@ -0,0 +1,1217 @@
+;===========================================================================
+;
+; WinError.H constants
+;
+ERROR_INVALID_PARAMETER EQU 87
+
+;===========================================================================
+;
+; Validation constants
+;
+GMEM_VALID equ 07372h ; include old GMEM_CODE_DATA
+GMEM_REALLOC_VALID equ 063f2h ; include GMEM_MODIFY and old GMEM_CODE_DATA
+
+GETFREESPACE_VALID equ 01002h ; undocumented "2" bit.
+
+OF_VALID equ 0fff7h
+LOPEN_VALID equ 000f7h
+
+LMEM_VALID equ 00f72h
+LMEM_REALLOC_VALID equ 00ff2h ; includes LMEM_MODIFY
+
+ATTR_MAX equ 3 ; _lcreat max
+ORIGIN_MAX equ 2 ; _lseek origin
+HANDLE_MAX equ 255
+
+SW_MAX equ 9 ; ShowWindow() SW_* max
+
+ERRMODE_VALID equ 08003h ; SetErrorMode
+
+SWAP_MAX equ 2 ; SwapRecording()
+
+; Local heap structures and definitions
+; (FROM WINKERN.INC)
+;
+LocalHandleEntry STRUC
+lhe_address DW ? ; actual address of object
+lhe_flags DB ? ; flags and priority level
+lhe_count DB ? ; lock count
+LocalHandleEntry ENDS
+
+LHE_DISCARDED EQU 040h ; Marks objects that have been discarded.
+
+; Local arena objects are kept in a doubly linked list.
+
+LocalArena STRUC
+la_prev DW ? ; previous arena entry (first entry points to self)
+la_next DW ? ; next arena entry (last entry points to self)
+la_handle DW ? ; back link to handle table entry
+LocalArena ENDS
+la_fixedsize = la_handle ; Fixed arena headers stop here
+
+LA_ALIGN = 4-1
+LA_MASK = NOT LA_ALIGN
+LA_FREE = 00h
+LA_BUSY = 01h ; Saved in la_prev field of header
+LA_MOVEABLE EQU 02h ; Saved in la_prev field of header
+
+;==========================================================================
+;
+; Per-segment helper subroutine definitions
+;
+EXTRA_EXPAND macro lseg
+
+ifdef genHLOCAL&lseg
+
+public HLOCAL0&lseg
+HLOCAL0&lseg:
+ or bx,bx ; accept NULL
+ jz LV_OK&lseg
+
+public HLOCAL&lseg
+HLOCAL&lseg:
+ mov dx,si ; preserve SI in DX
+ mov cx,bx ; cx = handle value
+
+beg_fault_trap LV_trap&lseg
+ test bl,LA_MOVEABLE ; moveable block?
+ jz LV_fixed&lseg
+
+ mov bx,[bx].lhe_address ; deref moveable object
+ or bx,bx ; if address is 0, ensure discarded.
+ jnz @F ; not null addr: continue.
+
+ mov bx,cx
+ test [bx].lhe_flags,LHE_DISCARDED
+ jnz LV_OK&lseg
+ jmp short LV_Error&lseg
+@@:
+ test [bx]-(SIZE LocalArena)+la_prev,LA_MOVEABLE ; make sure LA_MOVEABLE is set.
+ jz LV_Error&lseg
+
+ sub bx,(SIZE LocalArena)-la_fixedsize
+LV_fixed&lseg:
+ sub bx,la_fixedsize ; Point to arena block
+
+ifdef DISABLE ; disabled for speed.
+;** Make sure we're at least past the first heap block. We can
+;** do this because heap blocks are always linked into the list
+;** in order. We can get away with using WORD PTR hi_first
+;** for both the 286 and 386 KERNELs because the pointer is
+;** stored in the low WORD of this structure member in the
+;** 386 KERNEL and the structures are identical in 286 and 386
+;** up to this point. Members AFTER hi_first do NOT match
+;** up and we'd have to make special case code for the KERNELs.
+
+ mov si,[pLocalHeap] ;Points to HEAPINFO + LOCALINFO
+ cmp bx,WORD PTR [si].hi_first ;Beyond first block?
+ jl LV_Error&lseg ;Nope, can't be a local block
+endif
+
+;** Check that this is really a local block
+
+ mov ax,[bx].la_prev ;Point to previous arena
+ test al,LA_BUSY
+ jz LV_Error&lseg
+ and al,LA_MASK ; strip off LA_BUSY and LA_MOVEABLE
+
+; Assume that LA_BUSY bit is set (i.e., we're not a free block)
+
+ xchg ax,si
+ cmp [si].la_next,bx ;Does it chain to this block?
+ jne LV_Error&lseg ;No, bail
+ mov si,[bx].la_next ;Point to next arena
+ mov ax,[si].la_prev
+ and al,LA_MASK
+ cmp ax,bx ;Does it chain back to our block?
+ jne LV_Error&lseg ;Nope: error.
+end_fault_trap
+
+LV_OK&lseg:
+ mov si,dx ; restore SI
+ ret ; and return.
+
+LV_trap&lseg:
+ fault_fix_stack
+LV_Error&lseg:
+ mov si,dx ; restore SI
+ xchg ax,cx ; ax = handle value
+ mov bx,ERR_BAD_LOCAL_HANDLE
+ jmp Short Inval_Param_&lseg
+
+endif ;genHLOCAL&lseg
+
+endm
+
+;===========================================================================
+;
+; Argument types
+;
+P_HLOCAL0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov bx,_P_&h
+ lcall HLOCAL0
+ _gensub HLOCAL
+ endif
+endm
+
+P_HLOCAL macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov bx,_P_&h
+ lcall HLOCAL
+ _gensub HLOCAL
+ endif
+endm
+
+;
+; Special case for GlobalReAlloc, GlobalFree, GlobalUnlock because
+; of Turbo Pascal setup program. It turns out it dereferences a handle
+; by doing an inc, which worked on 3.0 but not any more.
+;
+; What happens in 3.1 is that the 3 low bits of a selector will be 1,
+; so an inc will set them all to 0 and carry to the next bit. We check
+; for this by checking for the 3 low bits == 0.
+;
+P_GHANDLETP macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ mov ax,_P_&h
+ or ax,ax ; Don't dec if == NULL!
+ jz @F
+ test al,0111b ; if GDT and ring 0 selector, it could be
+ jnz @F ; that turbo pascal did a dec.
+ dec ax
+ @@:
+ lcall GHANDLE
+ endif
+endm
+
+P_SEL equ <P_H>
+P_SEL0 equ <P_H0>
+P_SELM1 equ <P_H>
+
+P_HRESINFO equ <P_H>
+
+STRUCT <CATCHBUF>
+F_RGW reserved,9
+ENDSTRUCT
+
+_GenLP <P_LPCATCHBUF>,<LP>,%VLcbsCATCHBUF
+_GenLP <P_CLPCATCHBUF>,<LP>,%VLcbsCATCHBUF
+
+P_NPTR equ <P_2>
+
+STRUCT <SEGINFO> ; NOTE: this should be defined in windows.h
+F_WORD offSegment
+F_WORD cbSegment
+F_WORD flags
+F_WORD cbAlloc
+F_RGW reserved,4
+ENDSTRUCT
+
+_GenLP <P_LPSEGINFO>,<LP>,%VLcbsSEGINFO
+
+P_NPBUFFER macro pb, cb, opts
+ P_NPTR <pb>,<opts>
+ P_int <cb>,<opts>
+
+endm
+
+; special case for gettempfilename
+; cannot be used as is for anything else
+; will validate selector of buffer
+P_LPFILENAMEBUF macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov cx,_P_&name+2
+ mov ax,_P_&name
+ mov bx, 127 ; 128-char filename buffer
+beg_fault_trap LPFbad
+ mov es,cx
+LPFgood_es:
+ add bx, ax ; offset + 127
+ jc LPFbad1 ; check 16 bit overflow
+ or byte ptr es:[bx],0 ; check write permission, limit
+end_fault_trap
+ jmp short LPFexit
+LPFbad:
+ pop bx ; fault ip
+ add sp,2 ; fix flt stk (fault)
+ cmp bx, offset LPFgood_es
+ jb LPFbad1 ; bad selector, no excuse
+ mov bx, ERR_BAD_PTR or ERR_WARNING
+ jmp short LPFcallerr
+LPFbad1:
+ mov bx,ERR_BAD_PTR
+LPFcallerr:
+ call HandleParamError
+LPFexit:
+ endif
+
+endm
+
+P_CLPSTRORD equ <P_CLPSTRATOM>
+P_CLPSZMODNAME equ <P_CLPSTRATOM>
+
+P_DRIVECHAR equ <P_2>
+P_DRIVE equ <P_2>
+
+P_HFILE macro name, opts
+ _GenParm <name>,2,<opts>
+ if VLgen
+ mov ax,_P_&name ; Don't allow -1 for file handles
+ cmp ax,0FFFFh ; 0 is a valid file handle
+ jne @F
+;
+; We only want to warn here: this will let DOS return the appropriate error.
+;
+ mov bx,ERR_BAD_HFILE or ERR_WARNING ; only warn!
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+
+; Huge buffer pointers, that allow accessing beyond the
+; 64k segment limit. For now, we just ensure that there
+; is at least one valid byte in the buffer.
+;
+P_LPHUGEBUFFER macro pb, cb, opts
+ _DefParm <pb>,4,<opts>
+ _DefParm <cb>,2,<opts>
+ if VLgen
+ mov cx,_P_&cb ;; if cb == 0, don't validate
+ jcxz @F
+ mov ax,_P_&pb
+ mov cx,_P_&pb+2
+ mov bx,1
+ lcall LP
+ _gensub LP
+ @@:
+ endif
+endm
+
+P_CLPHUGEBUFFER macro pb, cb, opts
+ _DefParm <pb>,4,<opts>
+ _DefParm <cb>,2,<opts>
+ if VLgen
+ mov cx,_P_&cb ;; if cb == 0, don't validate
+ jcxz @F
+ mov ax,_P_&pb
+ mov cx,_P_&pb+2
+ mov bx,1
+ lcall CLP
+ _gensub LP
+ @@:
+ endif
+endm
+
+STRUCT <LOADPARAMS> ; Should be defined in windows.h
+F_WORD segEnv
+F_LPSTR lpCmdLine
+F_LPVOID lpCmdShow ; far pointer to rgw[2] = { 2, cmdShow };
+F_DWORDMBZ dwReserved
+ENDSTRUCT
+
+P_CLPLOADPARAMS0M1 macro name,opts
+ _DefParm <name>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ mov bx,ax
+ or bx,cx
+ jz @F ;; allow NULL for ATM
+ mov bx,ax
+ and bx,cx ;; if ax:cx == -1, accept parameter.
+ inc bx
+ jz @F
+ mov bx,VLcbsLOADPARAMS
+ lcall CLP
+ _gensub LP
+ @@:
+ endif
+endm
+
+STRUCT <OFSTRUCT>
+F_BYTE cBytes ;** BYTE. Size of OFSTRUCT
+F_BYTE fFixedDisk
+F_WORD nErrCode
+F_RGB reserved,4 ;** 4 reserved bytes
+F_RGCH szPathName,128 ;** null-terminated name of length
+ ;not > 128. Field length is 128
+ ;Wrongly documented as 120.
+ENDSTRUCT
+
+; We need this special code for openfile because the ofstruct was
+; wrongly documented as having a szPathName of 120 bytes instead of 128.
+; What we do is validate for 120 bytes, if that fails then issue error.
+; If that succeeds then validate for 128, if that fails then issue a warning
+; but continue the call.
+
+P_LPOFSTRUCT macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov cx,_P_&name+2
+ mov ax,_P_&name
+ mov bx,VLcbsOFSTRUCT-1 ; last addressible byte
+ sub bx,8 ; start by validating path=120 bytes
+
+beg_fault_trap LPOFbad
+ mov es,cx
+ add bx, ax
+ jc LPOFbad1 ; check 16 bit overflow
+ or byte ptr es:[bx],0 ; check write limit for path=120
+LPOFpath120:
+ add bx,8
+ jc LPOFwarn ; check 16 bit overflow
+ or byte ptr es:[bx],0 ; check write limit for path=128
+end_fault_trap
+ jmp short LPOFexit
+
+LPOFbad:
+ pop bx ; fault ip
+ add sp,2 ; fix flt stk (fault)
+ cmp bx, offset LPOFpath120
+ jb LPOFbad1 ; bad selector, or path < 120 => error
+LPOFwarn:
+ mov bx, ERR_BAD_PTR or ERR_WARNING
+ jmp short LPOFcallerr
+LPOFbad1:
+ mov bx,ERR_BAD_PTR
+LPOFcallerr:
+ call HandleParamError
+
+LPOFexit:
+ endif
+endm
+
+P_NPHTABLE equ <P_NPTR>
+
+P_LPFNRHANDLER equ <P_LPFN>
+P_LPFNGNOTIFY0 equ <P_LPFN0>
+P_LPFNLNOTIFY0 equ <P_LPFN0>
+
+P_HKEY equ <P_4>
+
+;===========================================================================
+;
+; API Descriptions
+;
+; in 3PROTECT.ASM
+API WORD, AllocCStoDSAlias, TEXT, <ASM>
+P_SEL sel ;** code selector
+
+; in 3PROTECT.ASM
+API WORD, AllocDStoCSAlias, TEXT, <ASM>
+P_SEL sel ;** data selector
+
+; in 3PROTECT.ASM
+API WORD, AllocSelector, TEXT, <ASM, NOGEN>
+P_SEL0 sel ;can be 0 (nogen)
+
+; in 3PROTECT.ASM
+API WORD, FreeSelector, TEXT, <ASM>
+P_SEL sel
+
+; in 3PROTECT.ASM
+API WORD, PrestoChangoSelector, TEXT, <ASM>
+P_SEL selSrc
+P_SEL selDst
+
+; in RESAUX.ASM
+API GHANDLE,LoadResource, TEXT, <ASM>
+P_HINSTANCE hInstance
+P_HRESINFO hResInfo
+
+; in RESAUX.ASM
+API int, AccessResource, TEXT, <ASM>
+P_HINSTANCE hInstance
+P_HRESINFO hRes
+APIERR
+ mov ax, -1 ;cannot get file handle
+APIEND
+
+; in RESAUX.ASM
+API HRESINFO, FindResource, MISCTEXT, <ASM>
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpName
+P_CLPSTRRSRC lpType
+
+; in RESAUX.ASM
+API GHANDLE,AllocResource, TEXT, <ASM>
+P_HINSTANCE hInstance
+P_HRESINFO hRes
+P_DWORD cbRes
+
+; in RESAUX.ASM
+API BOOL, FreeResource, TEXT, <ASM>
+P_GHANDLE hData
+
+; in RESAUX.ASM
+API LPSTR, LockResource, TEXT, <ASM>
+P_GHANDLE hResData
+
+; in RESAUX.ASM
+API LPFNRHANDLER, SetResourceHandler, MISCTEXT, <ASM>
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpType
+P_LPFNRHANDLER lpLoadFunc
+
+; in RESAUX.ASM
+API DWORD, SizeofResource, TEXT, <ASM>
+P_HINSTANCE hInstance
+P_HRESINFO hResInfo
+
+; in ATOM.ASM
+API BOOL, InitAtomTable, MISCTEXT, <ASM, NOGEN>
+P_int size
+
+; in ATOM.ASM
+API ATOM, AddAtom, TEXT, <ASM,FUNNYFRAME,DEBUGONLY>
+P_CLPSTRATOM lpString
+
+; in ATOM.ASM
+API ATOM, DeleteAtom, TEXT, <ASM>
+P_ATOM atom
+
+; in ATOM.ASM
+API ATOM, FindAtom, TEXT, <ASM,FUNNYFRAME, DEBUGONLY>
+P_CLPSTRATOM lpAtomName
+
+; in ATOM.ASM
+API WORD, GetAtomName, TEXT, <ASM>
+P_ATOM atom
+P_LPBUFFER lpBuffer, cchBuffer
+APIERR
+E_SETEMPTY lpBuffer, cchBuffer
+APIEND
+
+; in ATOM.ASM
+API HANDLE, GetAtomHandle, TEXT, <ASM>
+P_ATOM atom
+
+; in LDSTACK.ASM
+API int, Catch, MISCTEXT, <ASM, DEBUGONLY>
+P_LPCATCHBUF lpCatchBuf
+
+; in LDSTACK.ASM
+API void, Throw, MISCTEXT, <ASM, FUNNYFRAME,DEBUGONLY>
+P_CLPCATCHBUF lpCatchBuf
+P_int catchReturn
+
+; in RIPAUX.ASM
+API void, DebugBreak, TEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in MODULE.ASM
+API BOOL, FreeModule, NRESTEXT, <ASM>
+P_HMODULE hModule
+
+; in MODULE.ASM
+API void, FreeLibrary, NRESTEXT, <ASM> ;Falls into FreeModule
+P_HMODULE hLibModule
+
+; in RIPAUX.ASM (debug version) and RIP.C (retail version) ??
+API void, FatalExit, TEXT, <ASM, NOGEN, FUNNYFRAME>
+P_int code
+
+; in LDINT.ASM
+API void, FatalAppExit, TEXT, <ASM>
+P_WORDMBZ reserved ; ** must be 0
+P_CLPSTR0 lpMsgText
+
+; The 286 kernel has GlobalAlloc/ReAlloc size limits of 1meg - 16 bytes.
+;
+ ifdef PM386
+P_GHCB equ <P_DWORD>
+ else
+P_GHCB macro cb,opts
+ _GenParm <cb>,4,<opts>
+ if VLgen
+ mov ax,_P_&cb ; Error if cb > 0x000ffff0
+ mov cx,_P_&cb+2
+ cmp ax,0fff0h
+ sbb cx,0000fh
+ jbe @f
+ mov cx,_P_&cb+2 ; we trashed cx.
+ mov bx,ERR_BAD_DVALUE
+ lcall Inval_Param_
+@@:
+ endif
+endm
+ endif
+
+; in 3GINTERF.ASM
+API GHANDLE,GlobalAlloc, TEXT, <ASM>
+P_FLAGS flags,GMEM_VALID
+P_GHCB cb
+
+; The 286 kernel has a GlobalCompact size limit of 1meg-16 bytes
+; (but we also have to allow -1L, too).
+;;
+ ifdef PM386
+P_GCCB equ <P_DWORD>
+ else
+P_GCCB macro cb,opts
+ local noerr
+ _GenParm <cb>,4,<opts>
+ if VLgen
+ mov ax,_P_&cb ; Error if cb > 0x000ffff0
+ mov cx,_P_&cb+2
+ cmp ax,0ffffh ; if ax == -1 && ax == cx, then ok.
+ jnz @F
+ cmp ax,cx
+ jz noerr
+@@:
+ cmp ax,0fff0h
+ sbb cx,0000fh
+ jbe noerr
+ mov cx,_P_&cb+2 ; we trashed dx.
+ mov bx,ERR_BAD_DVALUE
+ lcall Inval_Param_
+noerr:
+ endif
+endm
+ endif
+
+; in 3GINTERF.ASM
+API DWORD, GlobalCompact, TEXT, <ASM, NOGEN>
+P_GCCB cbMinFree
+
+; in 3GINTERF.ASM
+API GHANDLE,GlobalFree, TEXT, <ASM>
+P_GHANDLETP h
+
+; in 3GINTERF.ASM
+API DWORD, GlobalHandle, TEXT, <ASM>
+P_SEL sel
+
+; in 3GINTERF.ASM
+API LPSTR, GlobalLock, TEXT, <ASM>
+P_GHANDLE h
+
+; The 286 kernel has GlobalReAlloc size limits of 1meg - 16 bytes.
+; However, if GMEM_MODIFY bit is set, we will completely ignore the size
+; field for 3.0 compatability instead of failing the call.
+ ifdef PM386
+P_GRAPARMS macro cb,flags,opts
+ P_DWORD <cb>,<opts>
+ P_FLAGS <flags>,GMEM_REALLOC_VALID,<opts>
+endm
+
+ else
+
+GMEM_MODIFY = 0080h
+
+P_GRAPARMS macro cb,flags,opts
+ _GenParm <cb>,4,<opts>
+ _GenParm <flags>,2,<opts>
+ if VLgen
+ errnz high(GMEM_MODIFY)
+ test byte ptr _P_&flags,low(GMEM_MODIFY)
+ jnz @F ; Ignore byte count if GMEM_MODIFY is set
+ mov ax,_P_&cb ; Error if cb > 0x000ffff0
+ mov cx,_P_&cb+2
+ cmp ax,0fff0h
+ sbb cx,0000fh
+ jbe @f
+ mov cx,_P_&cb+2 ; we trashed cx.
+ mov bx,ERR_BAD_DVALUE
+ lcall Inval_Param_
+@@:
+ifdef DEBUG
+ mov ax,_P_&flags
+ test ax,not(GMEM_REALLOC_VALID)
+ jz @F
+ mov bx,ERR_BAD_FLAGS or ERR_WARNING
+ lcall Inval_Param_
+@@:
+endif
+ endif
+endm
+ endif
+
+; in 3GINTERF.ASM
+API GHANDLE,GlobalReAlloc, TEXT, <ASM>
+P_GHANDLETP h
+P_GRAPARMS cb,flags
+
+; in 3GINTERF.ASM
+API DWORD, GlobalSize, TEXT, <ASM,FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API BOOL, GlobalUnlock, TEXT, <ASM>
+P_GHANDLETP h
+
+; in 3GINTERF.ASM
+API WORD, GlobalFlags, TEXT, <ASM,FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API LPSTR, GlobalWire, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API BOOL, GlobalUnWire, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API GHANDLE,GlobalLRUNewest, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API GHANDLE,GlobalLRUOldest, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API VOID, GlobalNotify, TEXT, <ASM>
+P_LPFNGNOTIFY0 lpNotifyProc ;** fn. to reside in fixed CS
+
+; in 3GINTERF.ASM
+API WORD, GlobalPageLock, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API WORD, GlobalPageUnlock, TEXT, <ASM,FUNNYFRAME> ;nogen
+P_SEL sel
+
+; in 3GINTERF.ASM
+API VOID, GlobalFix, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API BOOL, GlobalUnfix, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_GHANDLE h
+
+; in 3GINTERF.ASM
+API DWORD, GlobalDosAlloc, TEXT, <ASM, NOGEN>
+P_GHCB cb
+
+; in 3GINTERF.ASM
+API WORD, GlobalDosFree, TEXT, <ASM,NOGEN> ;calls GlobalFree
+P_SEL sel
+
+; in 3GINTERF.ASM
+API GHANDLE,LockSegment, TEXT, <ASM, FUNNYFRAME>
+P_SELM1 sel ;** can be -1
+
+; in 3GINTERF.ASM
+API GHANDLE,UnlockSegment, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_SELM1 sel ;can be -1
+
+; in TASK.ASM
+API HTASK, GetCurrentTask, TEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in USERPRO.ASM
+API WORD, GetWindowsDirectory, MISCTEXT, <ASM>
+P_LPBUFFER lpBuffer, cb
+APIERR
+E_SETEMPTY lpBuffer, cb
+APIEND
+
+; in USERPRO.ASM
+API WORD, GetSystemDirectory, MISCTEXT, <ASM>
+P_LPBUFFER lpBuffer, cb
+APIERR
+E_SETEMPTY lpBuffer, cb
+APIEND
+
+; in CONTEXT.ASM
+API LONG, GetWinFlags, MISCTEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in TASK.ASM
+API LPSTR, GetDOSEnvironment, MISCTEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+ ;calls GetCurrentTask
+
+; in CONTEXT.ASM
+API DWORD, GetVersion, MISCTEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in TASK.ASM
+API WORD, GetNumTasks, MISCTEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in LDAUX.ASM
+API BOOL, DefineHandleTable, MISCTEXT, <ASM, NOGEN>
+P_NPHTABLE pTable ; offset from start of caller's DS
+
+; in LDAUX.ASM
+API LPFN, MakeProcInstance, MISCTEXT, <ASM>
+P_LPFN lpProc
+P_HINSTANCE0 hInstance ; NULL => use caller's DS (not documemnted)
+
+; in LDAUX.ASM
+API void, FreeProcInstance, MISCTEXT, <ASM>
+P_LPFN lpProc
+
+; in LDAUX.ASM
+API GHANDLE,GetCodeHandle, TEXT, <ASM, NOGEN>
+P_DWORD lpProc ;;;; SHOULD BE P_CLP
+
+;
+; GetCodeInfo lpProc parameter can be either a proc addr
+; or module handle:segment number. So, we just validate
+; that the hi order word is a valid selector.
+;
+P_LPFNGCI macro name,opts
+ _DefParm <name>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov cx,_P_&name+2
+ inc cx ;; Allow 0xffff to pass...
+ jz @F
+ dec cx
+ xor ax,ax
+ mov bx,1
+ lcall CLP
+ _gensub LP
+ @@:
+ endif
+endm
+
+P_CLPLOADPARAMS0M1 macro name,opts
+ _DefParm <name>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ mov bx,ax
+ or bx,cx
+ jz @F ;; allow NULL for ATM
+ mov bx,ax
+ and bx,cx ;; if ax:cx == -1, accept parameter.
+ inc bx
+ jz @F
+ mov bx,VLcbsLOADPARAMS
+ lcall CLP
+ _gensub LP
+ @@:
+ endif
+endm
+
+; in LDAUX.ASM
+API void, GetCodeInfo, TEXT, <ASM>
+P_LPFNGCI lpProc ; LPFN or HMODULE:SegNum allowed
+P_LPSEGINFO lpSegInfo ; points to buffer of four 32-bit values
+
+; in LDAUX.ASM
+API LPFN, GetProcAddress, NRESTEXT, <ASM>
+P_HMODULE0 hModule
+P_CLPSTRORD lpProcName
+
+; in LDAUX.ASM
+API HMODULE,GetModuleHandle, NRESTEXT, <ASM>
+P_CLPSZMODNAME lpModuleName
+
+; in LDAUX.ASM
+API int, GetModuleUsage, NRESTEXT, <ASM>
+P_HMODULE hModule
+
+; in LDAUX.ASM
+API int, GetModuleFileName, NRESTEXT, <ASM, SAVEBX>
+P_HMODULE32 hModule
+P_LPBUFFER lpszName, cchName
+APIERR
+E_SETEMPTY lpszName, cchName
+APIEND
+
+; in LDAUX.ASM
+API int, GetInstanceData, NRESTEXT, <ASM>
+P_HINSTANCE hInstance
+P_NPBUFFER pb, cb ;** points to area in current DS of caller
+
+; in 3GINTERF.ASM Relevant only in case of EMS
+API DWORD, GetFreeSpace, TEXT, <ASM>
+P_FLAGS flags,GETFREESPACE_VALID
+
+; in I21TASK.ASM
+API WORD, GetCurrentPDB, MISCTEXT, <VOID, ASM, FUNNYFRAME>
+
+; in LDOPEN.ASM
+API DRIVECHAR, GetTempDrive, MISCTEXT, <ASM, FUNNYFRAME, NOGEN>
+P_DRIVECHAR chDrive ;** BYTE drive letter or 0
+
+; in LDOPEN.ASM
+API int, GetTempFileName, MISCTEXT, <ASM>
+P_DRIVECHAR chDrive
+P_CLPSTR lpPrefix
+P_WORD wUnique
+P_LPFILENAMEBUF lpTmpFileName ; at least 144(sic) 128 chars
+APIERR
+E_SETEMPTYNC lpTmpFileName
+APIEND
+
+; in LDOPEN.ASM
+API WORD, GetDriveType, MISCTEXT, <ASM, FUNNYFRAME, NOGEN>
+P_DRIVE drive ;** int. drive number (0, 1, ...)
+
+; in LSTRING.ASM
+API LPSTR, lstrcpy, TEXT, <ASM, FUNNYFRAME,DEBUGONLY> ;nogen
+P_LPSTR lpDst
+P_CLPSTR lpSrc
+APIERR
+E_SETEMPTYNC lpDst
+APIEND
+
+; in LSTRING.ASM
+API LPSTR, lstrcat, TEXT, <ASM, FUNNYFRAME,DEBUGONLY> ;nogen
+P_LPSTR lpDst
+P_CLPSTR lpSrc
+APIERR
+E_SETEMPTYNC lpDst
+APIEND
+
+; in LSTRING.ASM
+API int, lstrOriginal, TEXT, <ASM, FUNNYFRAME,DEBUGONLY> ;nogen
+P_CLPSTR lpSrc1
+P_CLPSTR lpSrc2
+APIERR
+ mov ax,-1 ; return -1 on error
+APIEND
+
+; in LSTRING.ASM
+API int, lstrlen, TEXT, <ASM, FUNNYFRAME,DEBUGONLY> ;nogen
+P_CLPSTR lpString
+
+; in DISKIO.ASM
+API int, _lopen, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_CLPSTR lpPathName
+P_FLAGS iReadWrite, LOPEN_VALID
+APIERR
+ mov ax,-1 ; return -1 on error
+APIEND
+
+; in DISKIO.ASM
+API int, _lclose, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HFILE fh
+APIERR
+ mov ax,-1 ; return -1 on error
+APIEND
+
+; in DISKIO.ASM
+API int, _lcreat, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_CLPSTR lpPathName
+P_VALUE attrs, ATTR_MAX
+APIERR
+ mov ax,-1 ; return -1 on error
+APIEND
+
+; in DISKIO.ASM
+API LONG, _llseek, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HFILE fh
+P_long offset
+P_VALUE origin, ORIGIN_MAX
+APIERR
+ mov ax,-1 ; return -1 on error
+ cwd
+APIEND
+
+; BACKWARD COMPATIBILITY HACK
+; Special case for _lread and _lwrite parameter errors
+;
+; If we have an invalid buffer pointer, we must return 0, not -1
+; for 3.0 compatibility. This is because some apps call these functions
+; with bogus pointers at EOF, in which case DOS ignores the pointer and count.
+; The P_HFILE parameter checking just warns about bogus values, which is
+; later caught by DOS and returned as a -1 error.
+;
+; in DISKIO.ASM
+API WORD, _lread, TEXT, <ASM, FUNNYFRAME, SAVEES> ;nogen
+P_HFILE fh
+P_LPHUGEBUFFER lpBuffer, cb
+APIERR
+; return 0 on a validation error (see above)
+;;;;;;;;mov ax,-1 ; return 0 on error
+APIEND
+
+; in DISKIO.ASM
+API WORD, _lwrite, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HFILE fh
+P_CLPHUGEBUFFER lpBuffer, cb
+APIERR
+; Return 0 if we get an error (see above)
+;;;;;;;;mov ax,-1 ; return -1 on error
+APIEND
+
+; in LD.ASM
+API HINSTANCE, LoadLibrary, NRESTEXT, <ASM> ;calls LoadModule directly
+P_CLPSZMODNAME lpLibName
+
+; in LD.ASM
+API HINSTANCE, LoadModule, NRESTEXT, <ASM, ATMFRAME>
+P_CLPSZMODNAME lpModuleMame
+P_CLPLOADPARAMS0M1 lpLoadParams ; -1L and NULL allowed
+
+; in LINTERF.ASM
+API HLOCAL, LocalAlloc, TEXT, <ASM>
+P_FLAGS flags, LMEM_VALID ;** LMEM_DISCARDABLE, LMEM_FIXED, LMEM_MODIFY,
+ ;LMEM_MOVEABLE, LMEM_NOCOMPACT, LMEM_NODISCARD
+ ;LMEM_ZEROINIT
+P_WORD cb
+
+; in LINTERF.ASM
+API WORD, LocalCompact, TEXT, <ASM,NOGEN>
+P_WORD cbMinFree
+
+; in LINTERF.ASM
+API HLOCAL, LocalFree, TEXT, <ASM>
+P_HLOCAL h ;** handle cannot be locked
+ ;DEBUG version checks if handle is locked
+
+; in LINTERF.ASM
+API HLOCAL, LocalHandle, TEXT, <ASM, FUNNYFRAME, NOGEN>
+P_NPTR pmem
+
+; in LINTERF.ASM
+API BOOL, LocalInit, NRESTEXT, <ASM, NOGEN>
+P_SEL0 sel ; 0 => current DS. This is not documented
+P_NPTR pStart ; start of heap in segment
+P_NPTR pEnd ; end of heap in segment
+
+; in LINTERF.ASM
+ifdef DEBUG
+API NPSTR, LocalLock, TEXT, <ASM>
+else
+API NPSTR, LocalLock, TEXT, <ASM, FUNNYFRAME> ;nogen
+endif
+P_HLOCAL h ;DEBUG checks for lock count overflow
+
+; in LINTERF.ASM
+API HLOCAL, LocalReAlloc, TEXT, <ASM>
+P_HLOCAL h
+P_WORD cb
+P_FLAGS flags, LMEM_REALLOC_VALID ;** LMEM_DISCARDABLE, LMEM_MODIFY,
+ ;LMEM_MOVEABLE, LMEM_NOCOMPACT,
+ ;LMEM_NODISCARD, LMEM_ZEROINIT
+
+; in LINTERF.ASM
+API WORD, LocalSize, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HLOCAL h
+
+; in LINTERF.ASM
+API BOOL, LocalUnlock, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HLOCAL h
+
+; in LINTERF.ASM
+API WORD, LocalFlags, TEXT, <ASM, FUNNYFRAME> ;nogen
+P_HLOCAL h
+
+; in LINTERF.ASM
+API WORD, LocalShrink, TEXT, <ASM, NOGEN>
+P_SEL0 sel ; segment containing heap
+P_WORD cb
+
+; in LINTERF.ASM
+API LPFNLNOTIFY, LocalNotify, NRESTEXT, <ASM, FUNNYFRAME>
+P_LPFNLNOTIFY0 lpfnNotifyProc
+
+; in EMSMISC.ASM (Relevant only if EMS present)
+API VOID, LimitEmsPages, EMS, <ASM, FUNNYFRAME, NOGEN> ;nogen
+P_DWORD cKiloBytes
+
+; in LSTRING.ASM
+API BOOL, IsDBCSLeadByte, TEXT, <ASM, FUNNYFRAME, NOGEN> ;nogen
+P_WORD ch
+
+; in 3LDDEBUG.ASM
+API void, OutputDebugString, TEXT, <ASM, FUNNYFRAME, NOGEN> ; preserves all regs
+P_CLPSTR lpString
+
+; in LDOPEN.ASM
+API int, OpenFile, TEXT, <ASM>
+P_CLPSTR0 lpFileName ; can be NULL if OF_REOPEN is set.
+P_LPOFSTRUCT lpOF ;** ptr. to OFSTRUCT
+P_FLAGS flags, OF_VALID ;** OF_ flags
+APIERR
+ mov ax,-1 ; return -1 on error
+APIEND
+
+; in 3GINTERF.ASM
+API void, SwitchStackBack, TEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in 3GINTERF.ASM
+API void, SwitchStackTo, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;nogen
+P_SEL sel
+P_NPTR pStack
+P_NPTR pStackTop
+
+; in MISCAPI.ASM
+API WORD, SetHandleCount, TEXT, <ASM>
+P_UVALUEW wNumber, HANDLE_MAX ;** upto 255 allowed
+
+; in 3GMOREME.ASM
+API LONG, SetSwapAreaSize, TEXT, <ASM, NOGEN>
+P_WORD cParagraphs
+
+; in CONTEXT.ASM
+API BOOL, SetErrorMode, MISCTEXT, <ASM>
+P_FLAGS flags, ERRMODE_VALID
+
+; in LDINT.ASM
+API void, SwapRecording, MISCTEXT, <ASM, FUNNYFRAME> ;nogen
+P_UVALUE action, SWAP_MAX ;** range 0-2
+
+; in 3GALLOC.ASM
+API VOID, ValidateFreeSpaces, TEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in CHECKSUM.ASM
+API VOID, ValidateCodeSegments, TEXT, <VOID, ASM>
+
+API WORD, WinExec, NRESTEXT, <ASM>
+P_CLPSTR lpFileName,256 ; path max = 128 + arg max = 128
+P_UVALUE wShow, SW_MAX ;** ShowWindow SW_ IDs
+
+; in UP.C
+API WORD, GetProfileInt, TEXT, <DATA>
+P_CLPSTR lpAppName
+P_CLPSTR lpKeyname
+P_int default
+
+; in UP.C
+API int, GetProfileString, TEXT, <DATA>
+P_CLPSTR lpAppName
+P_CLPSTR0 lpKeyName
+P_CLPSTR0 lpDefault
+P_LPBUFFER lpReturnedString, cchBuffer
+APIERR
+E_SETEMPTY lpReturnedString, cchBuffer
+APIEND
+
+; in UP.C
+API WORD, GetPrivateProfileInt, TEXT, <DATA>
+P_CLPSTR lpAppName
+P_CLPSTR lpKeyname
+P_int default
+P_CLPSTR lpFileName
+
+; in UP.C
+API int, GetPrivateProfileString, TEXT, <DATA>
+P_CLPSTR lpAppName
+P_CLPSTR0 lpKeyName
+P_CLPSTR0 lpDefault
+P_LPBUFFER lpReturnedString, cchBuffer
+P_CLPSTR lpFileName
+APIERR
+E_SETEMPTY lpReturnedString, cchBuffer
+APIEND
+
+; in UP.C
+API BOOL, WriteProfileString, TEXT, <DATA>
+P_CLPSTR0 lpAppName
+P_CLPSTR0 lpKeyName
+P_CLPSTR0 lpString
+
+; in UP.C
+API BOOL, WritePrivateProfileString, TEXT, <DATA>
+P_CLPSTR0 lpAppName
+P_CLPSTR0 lpKeyName
+P_CLPSTR0 lpString
+P_CLPSTR lpFileName
+
+; BUGBUG
+; For Win95, the k16 Reg* APIs get only the weakest validation.
+; This is because they were added without _any_ validation,
+; and validation is being added after the final beta.
+; The purpose of this weak validation is to touch each pointer
+; param if non-zero. We need to do this because the real work of
+; the APIs is done at ring0, where we cannot fault in the segment.
+;
+; Stronger validation should be implemented for the next release.
+;
+; These 32-bit kernel API's are thunked to WK32* functions in WOW32\wkernel.c
+
+API LONG, RegEnumKey32, TEXT, <DATA>
+;(HKEY lhKey, DWORD dwIndex, LPSTR lpValue, DWORD dwMax)
+P_HKEY hKey
+P_DWORD dwIndex
+P_CLPVOID0 lpValue
+P_DWORD dwMax
+APIERR
+ mov ax,ERROR_INVALID_PARAMETER
+APIEND
+
+API LONG, RegOpenKey32, TEXT, <DATA>
+;(HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult)
+P_HKEY hKey
+P_CLPVOID0 lpSubKey
+P_CLPVOID0 phkResult
+APIERR
+ mov ax,ERROR_INVALID_PARAMETER
+APIEND
+
+API LONG, RegCloseKey32, TEXT, <DATA>
+;(HKEY hkey)
+P_HKEY hKey
+APIERR
+ mov ax,ERROR_INVALID_PARAMETER
+APIEND
+
+API LONG, RegEnumValue32, TEXT, <DATA>
+;(HKEY hkey, DWORD dwValue, LPCSTR lpValue, LONG FAR * lpcbValue,DWORD dwReserved,LONG FAR *lpdwType, LPBYTE lpbData, LONG FAR *lpcbData)
+P_HKEY hKey
+P_DWORD dwValue
+P_CLPVOID0 lpValue
+P_CLPVOID0 lpcbValue
+P_DWORD dwReserved
+P_CLPVOID0 lpdwType
+P_CLPVOID0 lpbData
+P_CLPVOID0 lpcbData
+APIERR
+ mov ax,ERROR_INVALID_PARAMETER
+APIEND
+
+; in CONTEXT.ASM
+API void, Yield, TEXT, <VOID, ASM, FUNNYFRAME> ;nogen
+
+; in ERROR.C
+API void, LogError, TEXT, <VOID, NOGEN>
+P_WORD err
+P_int iParam
+P_LPVOID pParam
+
+; in ERROR.C
+API void, LogParamError, TEXT, <VOID, NOGEN>
+P_WORD err
+
+; in ERROR.C
+
+WDI_VALID equ 0007h
+
+_DefSimpleF F_MODNAME,8
+
+STRUCT <WINDEBUGINFO>
+F_FLAGS flags, WDI_VALID
+F_DWORD dwOptions
+F_DWORD dwFilter
+F_MODNAME achAllocModule
+F_DWORD dwAllocBreak
+F_DWORD dwAllocCount
+ENDSTRUCT
+
+_GenLP <P_LPWINDEBUGINFO>,<LP>,%VLcbsWINDEBUGINFO
+
+P_CLPWINDEBUGINFO macro lpwdi,opts
+ _GenParm <lpwdi>,4,<opts>
+ if VLgen
+ mov ax,_P_&lpwdi
+ mov cx,_P_&lpwdi+2
+ mov bx,VLcbsWINDEBUGINFO
+ lcall CLP
+ _gensub CLP
+ mov es,cx
+ mov bx,ax
+ test word ptr es:[bx]._F_flags,not WDI_VALID
+ jz @F
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+API void, SetWinDebugInfo, TEXT, <DEBUGONLY>
+P_CLPWINDEBUGINFO lpwdi
+
+API void, GetWinDebugInfo, TEXT, <DEBUGONLY>
+P_LPWINDEBUGINFO lpwdi
+P_FLAGS flags, WDI_VALID
diff --git a/private/mvdm/wow16/kernel31/kernel.def b/private/mvdm/wow16/kernel31/kernel.def
new file mode 100644
index 000000000..818bdaee7
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.def
@@ -0,0 +1,472 @@
+LIBRARY KERNEL
+
+DESCRIPTION 'Microsoft Windows Kernel Interface Version 3.10'
+EXETYPE WINDOWS
+PROTMODE
+STUB 'KERNSTUB.EXE'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA SINGLE
+
+SEGMENTS
+ _TEXT CLASS 'CODE' PRELOAD FIXED
+ _STRS CLASS 'CODE' PRELOAD FIXED
+ _GPFIX0 CLASS 'CODE' PRELOAD FIXED
+ _GPFIX CLASS 'CODE' PRELOAD FIXED
+ _GPFIX1 CLASS 'CODE' PRELOAD FIXED
+ _EMS CLASS 'CODE' PRELOAD FIXED
+ _INITTEXT CLASS 'CODE' PRELOAD FIXED
+ _DATA CLASS 'DATA' PRELOAD FIXED
+ _EMSDATA CLASS 'DATA' PRELOAD FIXED
+ _INITDATA CLASS 'DATA' PRELOAD FIXED
+ STACK CLASS 'DATA' PRELOAD FIXED
+ _PADDATA CLASS 'DATA' PRELOAD FIXED
+ _NRESTEXT CLASS 'CODE' PRELOAD MOVEABLE DISCARDABLE
+ _MISCTEXT CLASS 'CODE' PRELOAD MOVEABLE DISCARDABLE
+
+HEAPSIZE 512 ; This used to be the initial size of the
+ ; global handle table.
+
+EXPORTS
+
+; General procedures
+
+ FATALEXIT @ 1
+ EXITKERNEL @ 2 NODATA ;Internal
+ GETVERSION @ 3 NODATA
+
+; Local memory manager procedures
+
+ LOCALINIT @ 4 NODATA
+ LOCALALLOC @ 5 NODATA
+ LOCALREALLOC @ 6 NODATA
+ LOCALFREE @ 7 NODATA
+ LOCALLOCK @ 8 NODATA
+ LOCALUNLOCK @ 9 NODATA
+ LOCALSIZE @ 10 NODATA
+ LOCALHANDLE @ 11 NODATA
+ LOCALFLAGS @ 12 NODATA
+ LOCALCOMPACT @ 13 NODATA
+ LOCALNOTIFY @ 14 NODATA ;Internal
+
+; Global memory manager procedures
+
+ GLOBALALLOC @ 15 NODATA
+ GLOBALREALLOC @ 16 NODATA
+ GLOBALFREE @ 17 NODATA
+ GLOBALLOCK @ 18 NODATA
+ GLOBALUNLOCK @ 19 NODATA
+ GLOBALSIZE @ 20 NODATA
+ GLOBALHANDLE @ 21 NODATA
+ GLOBALFLAGS @ 22 NODATA
+ LOCKSEGMENT @ 23 NODATA
+ UNLOCKSEGMENT @ 24 NODATA
+ GLOBALCOMPACT @ 25 NODATA
+ GLOBALFREEALL @ 26 NODATA ;Internal
+; SETSWAPHOOK @ 27 NODATA
+ GLOBALMASTERHANDLE @ 28 NODATA ;Internal
+
+; Multitasking procedures
+
+ YIELD @ 29 NODATA
+ WAITEVENT @ 30 NODATA
+ POSTEVENT @ 31 NODATA ;Internal
+ SETPRIORITY @ 32 NODATA ;Internal
+ LOCKCURRENTTASK @ 33 NODATA ;Internal
+ SETTASKQUEUE @ 34 NODATA ;Internal
+ GETTASKQUEUE @ 35 NODATA ;Internal
+ GETCURRENTTASK @ 36 NODATA
+ GETCURRENTPDB @ 37 NODATA
+ SETTASKSIGNALPROC @ 38 NODATA ;Internal
+; SETTASKSWITCHPROC @ 39 NODATA
+; SETTASKINTERCHANGE @ 40 NODATA
+ ENABLEDOS @ 41 NODATA ;Internal
+ DISABLEDOS @ 42 NODATA ;Internal
+; ISSCREENGRAB @ 43 NODATA
+; BUILDPDB @ 44 NODATA
+
+; Dynamic loader
+
+ LOADMODULE @ 45 NODATA
+ FREEMODULE @ 46 NODATA
+ GETMODULEHANDLE @ 47 NODATA
+ GETMODULEUSAGE @ 48 NODATA
+ GETMODULEFILENAME @ 49 NODATA
+ GETPROCADDRESS @ 50 NODATA
+ MAKEPROCINSTANCE @ 51 NODATA
+ FREEPROCINSTANCE @ 52 NODATA
+ CALLPROCINSTANCE @ 53 NODATA ;Internal
+ GETINSTANCEDATA @ 54 NODATA
+ CATCH @ 55 NODATA
+ THROW @ 56 NODATA
+
+; WIN.INI interface procedures
+
+ GETPROFILEINT @ 57
+ GETPROFILESTRING @ 58
+ WRITEPROFILESTRING @ 59
+
+; Resource manager procedures
+
+ FINDRESOURCE @ 60 NODATA
+ LOADRESOURCE @ 61 NODATA
+ LOCKRESOURCE @ 62 NODATA
+ FREERESOURCE @ 63 NODATA
+ ACCESSRESOURCE @ 64 NODATA
+ SIZEOFRESOURCE @ 65 NODATA
+ ALLOCRESOURCE @ 66 NODATA
+ SETRESOURCEHANDLER @ 67 NODATA
+
+; Atom manager procedures
+
+ INITATOMTABLE @ 68 NODATA
+ FINDATOM @ 69 NODATA
+ ADDATOM @ 70 NODATA
+ DELETEATOM @ 71 NODATA
+ GETATOMNAME @ 72 NODATA
+ GETATOMHANDLE @ 73 NODATA
+
+; File name procedures
+
+ OPENFILE @ 74 NODATA
+ OPENPATHNAME @ 75 NODATA ;Internal
+ DELETEPATHNAME @ 76 NODATA ;Internal
+
+; ANSI character set procedures
+; The following 4 functions are now in USER. The ordinal numbers are
+; preserved for compatability with 2.X apps
+
+ RESERVED1 = ANSINEXT @ 77 NODATA
+ RESERVED2 = ANSIPREV @ 78 NODATA
+ RESERVED3 = ANSIUPPER @ 79 NODATA
+ RESERVED4 = ANSILOWER @ 80 NODATA
+
+; Internally used file I/O procedures
+
+ _LCLOSE @ 81 NODATA
+ _LREAD @ 82 NODATA
+ _LCREAT @ 83 NODATA
+ _LLSEEK @ 84 NODATA
+ _LOPEN @ 85 NODATA
+ _LWRITE @ 86 NODATA
+
+; Internally used string procedures that take far pointers
+; The following LSTRORIGINAL function is the old 2.X lstrcmp()
+; The ordinal number is preserved for compatability with 2.X apps
+; All 3.X apps will use the lstrcmp() and lstrcmpi() of USER.
+
+ RESERVED5 = LSTRORIGINAL @ 87 NODATA
+ LSTRCPY @ 88 NODATA
+ LSTRCAT @ 89 NODATA
+ LSTRLEN @ 90 NODATA
+
+; Stuff added after last release
+
+ INITTASK @ 91 NODATA
+ GETTEMPDRIVE @ 92 NODATA
+ GETCODEHANDLE @ 93 NODATA
+ DEFINEHANDLETABLE @ 94 NODATA
+ LOADLIBRARY @ 95 NODATA
+ FREELIBRARY @ 96 NODATA
+ GETTEMPFILENAME @ 97 NODATA
+ GETLASTDISKCHANGE @ 98 NODATA ;Internal
+ GETLPERRMODE @ 99 NODATA ;Internal
+ VALIDATECODESEGMENTS @100 NODATA
+
+; Stuff added for 1.02 release
+
+ NOHOOKDOSCALL @101 NODATA ;Internal
+
+; Stuff added for 1.03 release
+
+ DOS3CALL @102 NODATA
+ NETBIOSCALL @103 NODATA
+
+; Stuff added for 2.00 release
+
+ GETCODEINFO @104 NODATA
+ GETEXEVERSION @105 NODATA ;Internal
+ SETSWAPAREASIZE @106 NODATA
+ SETERRORMODE @107 NODATA
+ SWITCHSTACKTO @108 NODATA
+ SWITCHSTACKBACK @109 NODATA
+ PATCHCODEHANDLE @110 NODATA
+ GLOBALWIRE @111 NODATA
+ GLOBALUNWIRE @112 NODATA
+ __AHSHIFT @113 NODATA
+ __AHINCR @114 NODATA
+ OUTPUTDEBUGSTRING @115 NODATA
+ INITLIB @116 NODATA ;Internal
+ OLDYIELD @117 NODATA ;Internal
+ GETTASKQUEUEDS @118 NODATA ;Internal
+ GETTASKQUEUEES @119 NODATA ;Internal
+ UNDEFDYNLINK @120 NODATA ;Internal
+ LOCALSHRINK @121 NODATA
+ ISTASKLOCKED @122 NODATA ;Internal
+ KBDRST @123 NODATA ;Internal
+
+; Stuff added for REO SpeedWagon
+
+ ENABLEKERNEL @124 NODATA ;Internal
+ DISABLEKERNEL @125 NODATA ;Internal
+
+; Stuff added for 2.03c release.
+
+ MEMORYFREED @126 NODATA ;Internal
+
+; New 3.0 Goodies
+
+ GETPRIVATEPROFILEINT @127
+ GETPRIVATEPROFILESTRING @128
+ WRITEPRIVATEPROFILESTRING @129
+ FILECDR @130 NODATA ;Internal
+ GETDOSENVIRONMENT @131 NODATA
+ GETWINFLAGS @132 NODATA
+ GETEXEPTR @133 NODATA ;Internal
+ GETWINDOWSDIRECTORY @134 NODATA
+ GETSYSTEMDIRECTORY @135 NODATA
+ GETDRIVETYPE @136 NODATA
+ FATALAPPEXIT @137 NODATA
+ GETHEAPSPACES @138 NODATA ;Internal
+ DOSIGNAL @139 NODATA ;Internal
+ SETSIGHANDLER @140 NODATA ;Internal
+ INITTASK1 @141 NODATA ;Internal
+
+; From Win95:
+
+ GETVERSIONEX @149 NODATA
+
+; Stuff below was in 2.03
+
+ DIRECTEDYIELD @150 NODATA
+; WINOLDAPCALL @151 NODATA ;Removed by davehart -- WOW doesn't use
+ GETNUMTASKS @152 NODATA
+; DISCARDCODESEGMENT @153 NODATA
+ GLOBALNOTIFY @154 NODATA
+ GETTASKDS @155 NODATA ;Internal
+ LIMITEMSPAGES @156 NODATA
+ GETCURPID @157 NODATA ;Internal
+ ISWINOLDAPTASK @158 NODATA ;Internal
+ GLOBALHANDLENORIP @159 NODATA ;Internal
+ EMSCOPY @160 NODATA ;Internal
+ LOCALCOUNTFREE @161 NODATA ;Internal
+ LOCALHEAPSIZE @162 NODATA ;Internal
+ GLOBALLRUOLDEST @163 NODATA
+ GLOBALLRUNEWEST @164 NODATA
+ A20PROC @165 NODATA ;Internal
+
+ WINEXEC @166 NODATA
+ GETEXPWINVER @167 NODATA ;Internal
+ DIRECTRESALLOC @168 NODATA ;Internal
+ GETFREESPACE @169 NODATA
+
+; Protect Mode stuff
+
+ ALLOCCSTODSALIAS @170 NODATA
+ ALLOCDSTOCSALIAS @171 NODATA
+ ALLOCALIAS @172 NODATA
+ __ROMBIOS @173 NODATA
+ __A000h @174 NODATA
+ ALLOCSELECTOR @175 NODATA
+ FREESELECTOR @176 NODATA
+ PRESTOCHANGOSELECTOR @177 NODATA
+ __WINFLAGS @178 NODATA
+ __D000h @179 NODATA
+ LONGPTRADD @180 NODATA
+ __B000h @181 NODATA
+ __B800h @182 NODATA
+ __0000h @183 NODATA
+ GLOBALDOSALLOC @184 NODATA
+ GLOBALDOSFREE @185 NODATA
+ GETSELECTORBASE @186 NODATA
+ SETSELECTORBASE @187 NODATA
+ GETSELECTORLIMIT @188 NODATA
+ SETSELECTORLIMIT @189 NODATA
+ __E000h @190 NODATA
+ GLOBALPAGELOCK @191 NODATA
+ GLOBALPAGEUNLOCK @192 NODATA
+ __0040h @193 NODATA
+ __F000h @194 NODATA
+ __C000h @195 NODATA
+ SELECTORACCESSRIGHTS @196 NODATA
+ GLOBALFIX @197 NODATA
+ GLOBALUNFIX @198 NODATA
+
+ SETHANDLECOUNT @199 NODATA
+
+; Debugging aids
+
+ VALIDATEFREESPACES @200 NODATA
+ REPLACEINST @201 NODATA ;Internal
+ REGISTERPTRACE @202 NODATA ;Internal
+ DEBUGBREAK @203 NODATA
+ SWAPRECORDING @204 NODATA
+ CVWBREAK @205 NODATA
+
+ALLOCSELECTORARRAY @206 NODATA ;Internal
+
+; DBCS Supporting Stuff
+
+ ISDBCSLEADBYTE @207 NODATA
+
+ WOWSHOULDWESAYWIN95 @215 NODATA ;Internal
+
+; 32-bit Registry APIs
+ REGENUMKEY = REGENUMKEY32 @216 NODATA
+ REGOPENKEY = REGOPENKEY32 @217 NODATA
+; REGCREATEKEY = REGCREATEKEY32 @218 NODATA
+; REGDELETEKEY = REGDELETEKEY32 @219 NODATA
+ REGCLOSEKEY = REGCLOSEKEY32 @220 NODATA
+; REGSETVALUE = REGSETVALUE32 @221 NODATA
+; REGDELETEVALUE = REGDELETEVALUE32 @222 NODATA
+ REGENUMVALUE = REGENUMVALUE32 @223 NODATA
+; REGQUERYVALUE = REGQUERYVALUE32 @224 NODATA
+; REGQUERYVALUEEX = REGQUERYVALUEEX32 @225 NODATA
+; REGSETVALUEEX = REGSETVALUEEX32 @226 NODATA
+; REGFLUSHKEY = REGFLUSHKEY32 @227 NODATA
+
+;;;;; JAPANESE VERSION ONLY
+;;;;; GETINTERNALVERSION NODATA ;Internal
+
+; all you wanted to know about these ROMRESERVEDs but were afraid to ask:
+; these act like ifdef ROM
+; rom.def is produced by passing kernel.def thru SED.
+
+; ROM Windows Uncompression routine
+;ROM_RESERVED LZDECODE @286 NODATA ;Internal
+
+; New stuff for 3.1
+
+ LOCALHANDLEDELTA @310 NODATA
+ GETSETKERNELDOSPROC @311 NODATA ;Internal
+; FARVALIDATEPOINTER @312 NODATA ;Internal removed davidds
+; GETLASTCRITICALERROR @313 NODATA ; removed EarleH
+ DEBUGDEFINESEGMENT @314 NODATA ;Internal
+ WRITEOUTPROFILES @315 ;Internal
+ GETFREEMEMINFO @316 NODATA
+ FATALEXITHOOK @318 NODATA ;Internal
+ FLUSHCACHEDFILEHANDLE @319 NODATA ;Internal
+ ISTASK @320 NODATA
+; RESERVED @321 NODATA
+ ISROMMODULE @323 NODATA ;Internal
+ LOGERROR @324
+ LOGPARAMERROR @325
+ ISROMFILE @326 NODATA ;Internal
+ K327=HANDLEPARAMERROR @327 NODATA ;Internal
+ _DebugOutput @328 NODATA ;Internal
+ K329=DEBUGFILLBUFFER @329 NODATA ;Internal
+
+ THHOOK @332 NODATA ;Internal
+;OPENSYSTEMFILE @333 NODATA ;Removed 3-Oct-91 by JonT
+
+ ; Pointer validation routines (donc)
+ ISBADREADPTR @334 NODATA
+ ISBADWRITEPTR @335 NODATA
+ ISBADCODEPTR @336 NODATA
+ ISBADSTRINGPTR @337 NODATA
+ HASGPHANDLER @338 NODATA ;Internal
+
+ ; Diagnostic mode exports
+ DIAGQUERY @339 NODATA
+ DIAGOUTPUT @340 NODATA
+
+ TOOLHELPHOOK @341 NODATA ;Internal
+ ; GP handler table
+ __GP @342 RESIDENTNAME ;Internal
+
+ ; Winoldap hooks
+ REGISTERWINOLDAPHOOK @343 NODATA
+ GETWINOLDAPHOOKS @344 NODATA
+
+ ISSHAREDSELECTOR @345 NODATA ;Internal
+
+ ; More pointer validation and huge routines (donc)
+ ISBADHUGEREADPTR @346 NODATA
+ ISBADHUGEWRITEPTR @347 NODATA
+ HMEMCPY @348 NODATA
+ _HREAD @349 NODATA
+ _HWRITE @350 NODATA
+
+; USER's private exit notify callback.
+
+ BUNNY_351 @351 NODATA ;Internal
+
+ LSTRCPYN @353 NODATA
+
+ GETAPPCOMPATFLAGS @354 NODATA ;Internal
+
+ GETWINDEBUGINFO @355
+ SETWINDEBUGINFO @356
+
+ K403 = FARSETOWNER @403 NODATA ;Internal Win32S support
+ K404 = FARGETOWNER @404 NODATA ;Internal Win32S support
+
+;
+; ADD NEW EXPORTS HERE SO YOU DON'T BREAK ROM WINDOWS
+;
+
+; WOW Stuff for NT
+
+ WOW16CALL @500 NODATA ;Internal
+ KDDBGOUT @501 NODATA ;Internal
+ WOWGETNEXTVDMCOMMAND @502 NODATA ;Internal
+ WOWREGISTERSHELLWINDOWHANDLE @503 NODATA ;Internal
+ WOWLOADMODULE @504 NODATA ;Internal
+ WOWQUERYPERFORMANCECOUNTER @505 NODATA ;Internal
+
+; in wowkrn.h there is a struct of k506. so not using ordinal 506.
+
+ WOWCURSORICONOP @507 NODATA ;Internal
+ WOWFAILEDEXEC @508 NODATA ;Internal
+ WOWCLOSECOMPORT @509 NODATA ;Internal
+
+ WOWKILLREMOTETASK @511 NODATA ;Internal
+ WOWQUERYDEBUG @512 NODATA ;Internal
+
+; Generic Thunk Interface
+
+ LOADLIBRARYEX32W @513 NODATA
+ FREELIBRARY32W @514 NODATA
+ GETPROCADDRESS32W @515 NODATA
+ GETVDMPOINTER32W @516 NODATA
+ CALLPROC32W @517 NODATA
+ _CallProcEx32W @518 NODATA
+ EXITKERNELTHUNK @519 NODATA
+
+ __MOD_KERNEL @520 NODATA
+ __MOD_DKERNEL @521 NODATA
+ __MOD_USER @522 NODATA
+ __MOD_DUSER @523 NODATA
+ __MOD_GDI @524 NODATA
+ __MOD_DGDI @525 NODATA
+ __MOD_KEYBOARD @526 NODATA
+ __MOD_SOUND @527 NODATA
+ __MOD_SHELL @528 NODATA
+ __MOD_WINSOCK @529 NODATA
+ __MOD_TOOLHELP @530 NODATA
+ __MOD_MMEDIA @531 NODATA
+ __MOD_COMMDLG @532 NODATA
+
+ WOWSETEXITONLASTAPP @541 NODATA ;Internal
+ WOWWAITFORMSGANDEVENT @262 NODATA ;Internal
+ WOWMSGBOX @263 NODATA ;Internal
+ K273 = WOWPARTYBYNUMBER @273 NODATA ;Internal
+ GetShortPathName @274 NODATA
+
+ WOWSETCOMPATHANDLE @544 NODATA ;for user thunk
+
+
+; all you wanted to know about these ROMRESERVEDs but were afraid to ask:
+; these act like ifdef ROM
+; rom.def is produced by passing kernel.def thru SED.
+
+;ROM_RESERVED IMPORTS
+
+ ;ROM_RESERVED lmaROMTOC = ROMWIN.1
+ ;ROM_RESERVED selLDTAlias = ROMWIN.3
+ ;ROM_RESERVED lmaExtMemROM = ROMWIN.4
+ ;ROM_RESERVED cbExtMemROM = ROMWIN.5
+
+;
+; DON'T ADD EXPORTS HERE BECAUSE THIS IS THE IMPORTS SECTION FOR ROM
+;
diff --git a/private/mvdm/wow16/kernel31/kernel.h b/private/mvdm/wow16/kernel31/kernel.h
new file mode 100644
index 000000000..7ec797256
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.h
@@ -0,0 +1,654 @@
+/*
+ * KERNEL.H - C header file for all C kernel files
+ *
+ */
+
+/*
+ * The following is defined as the null string as the kernel is compiled
+ * with the -PLM switch
+ */
+#ifndef PASCAL
+#define PASCAL
+#endif
+
+#define BUILDDLL 1
+#define PMODE 1
+/*
+ * Define the following non-zero and the debugging support in the kernel
+ * is enabled
+ */
+#ifndef WINDEBUG
+#define KDEBUG 0
+#else
+#define KDEBUG 1
+#endif
+
+#ifdef ROMWIN
+#define ROM 1
+#else
+#define ROM 0
+#endif
+
+/* Register definition. */
+#define REG
+#define LONG long
+#define NULL 0
+
+/* Define common constants. */
+#define TRUE 1
+#define FALSE 0
+
+/* Far and Near dummy pointer attributes. */
+#define FAR far
+#define NEAR near
+typedef char far *FARP;
+typedef char *NEARP;
+typedef char far *LPSTR;
+typedef char *PSTR;
+typedef int ( far PASCAL * FARPROC )();
+typedef int ( near PASCAL * NEARPROC )();
+/* Standard types. */
+typedef unsigned long DWORD;
+typedef unsigned short int WORD;
+typedef WORD *pWORD;
+typedef unsigned char BYTE;
+typedef int BOOL;
+#define VOID void
+
+typedef WORD HANDLE;
+
+typedef struct {
+ WORD Offset;
+ WORD Segment;
+ } FARADDR;
+typedef FARADDR *pFARADDR;
+
+/*
+ * Internel near kernel procedures
+ */
+
+FARPROC StartProcAddress( HANDLE, int );
+HANDLE StartTask( HANDLE, HANDLE, HANDLE, FARPROC );
+HANDLE StartLibrary( HANDLE, FARP, FARPROC );
+HANDLE FindExeInfo( FARP, WORD );
+FARP GetStringPtr( HANDLE, int, WORD );
+HANDLE AddModule( HANDLE );
+HANDLE DelModule( HANDLE );
+void IncExeUsage( HANDLE );
+void DecExeUsage( HANDLE );
+void PreloadResources( HANDLE, int );
+HANDLE GetExePtr( HANDLE );
+DWORD GetStackPtr( HANDLE );
+WORD GetInstance( HANDLE );
+HANDLE LoadExeHeader( int, int, FARP );
+HANDLE TrimExeHeader( HANDLE );
+int AllocAllSegs( HANDLE );
+HANDLE LoadSegment( HANDLE, WORD, int, int );
+WORD MyLock( HANDLE );
+HANDLE MyFree( HANDLE );
+HANDLE MyResAlloc( HANDLE, WORD, WORD, WORD );
+
+
+/*
+ * Undocumented, exported kernel procedures
+ */
+
+#if KDEBUG
+LPSTR GetDebugString( int );
+BOOL far PASCAL GlobalInit( WORD, WORD, WORD, WORD );
+WORD far * PASCAL GlobalInfoPtr( void );
+#define GlobalFreeze( dummy ) ( *(GlobalInfoPtr()+1) += 1 )
+#define GlobalMelt( dummy ) ( *(GlobalInfoPtr()+1) -= 1 )
+#endif
+
+void PASCAL PatchStack( WORD far *, WORD, WORD );
+WORD far * PASCAL SearchStack( WORD far *, WORD );
+
+int far PASCAL SetPriority( HANDLE, int );
+HANDLE far PASCAL LockCurrentTask( BOOL );
+HANDLE far PASCAL GetTaskQueue( HANDLE );
+HANDLE far PASCAL SetTaskQueue( HANDLE, HANDLE );
+WORD far PASCAL GetCurrentPDB( void );
+WORD far PASCAL BuildPDB( WORD, WORD, FARP, WORD );
+void far PASCAL EnableDOS( void );
+void far PASCAL DisableDOS( void );
+BOOL far PASCAL IsScreenGrab( void );
+
+HANDLE far PASCAL CreateTask( DWORD, FARP, HANDLE);
+HANDLE far PASCAL GetDSModule( WORD );
+HANDLE far PASCAL GetDSInstance( WORD );
+void far PASCAL CallProcInstance( void );
+FARPROC far PASCAL SetTaskSignalProc( HANDLE, FARPROC );
+FARPROC far PASCAL SetTaskSwitchProc( HANDLE, FARPROC );
+FARPROC far PASCAL SetTaskInterchange( HANDLE, FARPROC );
+void far PASCAL ExitKernel( int );
+
+
+/*
+ * Exported procedures for KERNEL module
+ */
+
+/*
+ * Interface to FatalExit procedure
+ */
+
+void far PASCAL FatalExit( int );
+void far PASCAL ValidateCodeSegments();
+
+/* Interface to Catch and Throw procedures */
+
+typedef int CATCHBUF[ 9 ];
+typedef int FAR *LPCATCHBUF;
+int FAR PASCAL Catch( LPCATCHBUF );
+void FAR PASCAL Throw( LPCATCHBUF, int );
+
+
+/*
+ * Interface to local memory manager
+ */
+
+#define LMEM_FIXED 0x0000
+#define LMEM_MOVEABLE 0x0002
+#define LMEM_NOCOMPACT 0x0010
+#define LMEM_NODISCARD 0x0020
+#define LMEM_ZEROINIT 0x0040
+#define LMEM_MODIFY 0x0080
+#define LMEM_DISCARDABLE 0x0F00
+
+#define LNOTIFY_OUTOFMEM 0
+#define LNOTIFY_MOVE 1
+#define LNOTIFY_DISCARD 2
+
+BOOL far PASCAL LocalInit( WORD, char *, char * );
+HANDLE far PASCAL LocalAlloc( WORD, WORD );
+HANDLE far PASCAL LocalReAlloc( HANDLE, WORD, WORD );
+HANDLE far PASCAL LocalFree( HANDLE );
+char * far PASCAL LocalLock( HANDLE );
+BOOL far PASCAL LocalUnlock( HANDLE );
+WORD far PASCAL LocalSize( HANDLE );
+HANDLE far PASCAL LocalHandle( WORD );
+WORD far PASCAL LocalCompact( WORD );
+FARPROC far PASCAL LocalNotify( FARPROC );
+int far PASCAL LocalNotifyDefault( int, HANDLE, WORD );
+#define LocalDiscard( h ) LocalReAlloc( h, 0, LMEM_MOVEABLE )
+
+extern WORD * PASCAL pLocalHeap;
+
+#define dummy 0
+#define LocalFreeze( dummy ) ( *(pLocalHeap+1) += 1 )
+#define LocalMelt( dummy ) ( *(pLocalHeap+1) -= 1 )
+#define LocalHandleDelta( delta ) ( (delta) ? (*(pLocalHeap+9) = (delta)) : *(pLocalHeap+9))
+
+#define calloc( n,size ) LocalAlloc( LMEM_ZEROINIT, n*(size) )
+#define malloc( size ) LocalAlloc( 0, size )
+#define free( p ) LocalFree( p )
+#define realloc( p, size ) LocalReAlloc( p, size, LMEM_ZEROINIT )
+
+/*
+ * Interface to global memory manager
+ */
+
+#define GMEM_FIXED 0x0000
+#define GMEM_ALLOCHIGH 0x0001 /* Kernel use only */
+#define GMEM_MOVEABLE 0x0002
+#define GMEM_DISCCODE 0x0004
+#define GMEM_NOCOMPACT 0x0010
+#define GMEM_NODISCARD 0x0020
+#define GMEM_ZEROINIT 0x0040
+#define GMEM_MODIFY 0x0080
+#define GMEM_DISCARDABLE 0x0100
+#define GMEM_SHARE 0x1000
+#define GMEM_SHAREALL 0x2000
+
+#define GNOTIFY_OUTOFMEM 0
+#define GNOTIFY_MOVE 1
+#define GNOTIFY_DISCARD 2
+
+#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
+#define LOWORD(l) ((WORD)(DWORD)(l))
+
+HANDLE far PASCAL GlobalAlloc( WORD, DWORD );
+HANDLE far PASCAL GlobalReAlloc( HANDLE, DWORD, WORD );
+HANDLE far PASCAL GlobalFree( HANDLE );
+HANDLE far PASCAL GlobalFreeAll( WORD );
+char far * far PASCAL GlobalLock( HANDLE );
+BOOL far PASCAL GlobalUnlock( HANDLE );
+DWORD far PASCAL GlobalSize( HANDLE );
+DWORD far PASCAL GlobalHandle( WORD );
+DWORD far PASCAL GlobalHandleNoRIP( WORD );
+HANDLE far PASCAL LockSegment( WORD );
+HANDLE far PASCAL UnlockSegment( WORD );
+DWORD far PASCAL GlobalCompact( DWORD );
+#define LockData( dummy ) LockSegment( 0xFFFF )
+#define UnlockData( dummy ) UnlockSegment( 0xFFFF )
+#define GlobalDiscard( h ) GlobalReAlloc( h, 0L, GMEM_MOVEABLE )
+
+
+/*
+ * Interface to the task scheduler
+ */
+
+BOOL far PASCAL Yield( void );
+BOOL far PASCAL WaitEvent( HANDLE );
+BOOL far PASCAL PostEvent( HANDLE );
+HANDLE far PASCAL GetCurrentTask( void );
+BOOL far PASCAL KillTask( HANDLE );
+
+
+/*
+ * Interface to the dynamic loader/linker
+ */
+
+HANDLE far PASCAL LoadModule( LPSTR, LPSTR );
+void far PASCAL FreeModule( HANDLE );
+HANDLE far PASCAL GetModuleHandle( LPSTR );
+FARPROC far PASCAL GetProcAddress( HANDLE, LPSTR );
+FARPROC far PASCAL MakeProcInstance( FARPROC, HANDLE );
+void far PASCAL FreeProcInstance( FARPROC );
+int far PASCAL GetInstanceData( HANDLE, PSTR, int );
+int far PASCAL GetModuleUsage( HANDLE );
+int far PASCAL GetModuleFileName( HANDLE, LPSTR, int );
+
+
+/*
+ * Interface to the resource manager
+ */
+
+HANDLE far PASCAL FindResource( HANDLE, LPSTR, LPSTR );
+HANDLE far PASCAL LoadResource( HANDLE, HANDLE );
+BOOL far PASCAL FreeResource( HANDLE );
+
+char far * far PASCAL LockResource( HANDLE );
+
+FARPROC far PASCAL SetResourceHandler( HANDLE, LPSTR, FARPROC );
+HANDLE far PASCAL AllocResource( HANDLE, HANDLE, DWORD );
+WORD far PASCAL SizeofResource( HANDLE, HANDLE );
+int far PASCAL AccessResource( HANDLE, HANDLE );
+
+#define MAKEINTRESOURCE(i) (LPSTR)((unsigned long)((WORD)i))
+
+/* Predefined resource types */
+#define RT_CURSOR MAKEINTRESOURCE( 1 )
+#define RT_BITMAP MAKEINTRESOURCE( 2 )
+#define RT_ICON MAKEINTRESOURCE( 3 )
+#define RT_MENU MAKEINTRESOURCE( 4 )
+#define RT_DIALOG MAKEINTRESOURCE( 5 )
+#define RT_STRING MAKEINTRESOURCE( 6 )
+#define RT_FONTDIR MAKEINTRESOURCE( 7 )
+#define RT_FONT MAKEINTRESOURCE( 8 )
+
+
+/*
+ * Interface to the user profile
+
+int far PASCAL GetProfileInt( LPSTR, LPSTR, int );
+int far PASCAL GetProfileString( LPSTR, LPSTR, LPSTR, LPSTR, int );
+void far PASCAL WriteProfileString( LPSTR, LPSTR, LPSTR );
+ */
+
+
+/*
+ * Interface to the atom manager
+ */
+
+typedef WORD ATOM;
+
+BOOL far PASCAL InitAtomTable( int );
+ATOM far PASCAL FindAtom( LPSTR );
+ATOM far PASCAL AddAtom( LPSTR );
+ATOM far PASCAL DeleteAtom( ATOM );
+WORD far PASCAL GetAtomName( ATOM, LPSTR, int );
+HANDLE far PASCAL GetAtomHandle( ATOM );
+
+#define MAKEINTATOM(i) (LPSTR)((unsigned long)((WORD)i))
+
+#define ATOMSTRUC struct atomstruct
+typedef ATOMSTRUC *PATOM;
+typedef ATOMSTRUC {
+ PATOM chain;
+ WORD usage; /* Atoms are usage counted. */
+ BYTE len; /* length of ASCIZ name string */
+ BYTE name; /* beginning of ASCIZ name string */
+} ATOMENTRY;
+
+typedef struct {
+ int numEntries;
+ PATOM pAtom[ 1 ];
+} ATOMTABLE;
+
+extern ATOMTABLE * PASCAL pAtomTable;
+
+
+/*
+ * Interface to the string functions
+ */
+
+int far PASCAL lstrcmp( LPSTR, LPSTR );
+LPSTR far PASCAL lstrcpy( LPSTR, LPSTR );
+LPSTR far PASCAL lstrcat( LPSTR, LPSTR );
+int far PASCAL lstrlen( LPSTR );
+LPSTR far PASCAL lstrbscan( LPSTR, LPSTR );
+LPSTR far PASCAL lstrbskip( LPSTR, LPSTR );
+
+/*
+ * Interface to the file I/O functions
+ */
+
+int far PASCAL OpenPathname( LPSTR, int );
+int far PASCAL DeletePathname( LPSTR );
+int far PASCAL _lopen( LPSTR, int );
+void far PASCAL _lclose( int );
+int far PASCAL _lcreat( LPSTR, int );
+LONG far PASCAL _llseek( int, long, int );
+WORD far PASCAL _lread( int, LPSTR, int );
+WORD far PASCAL _lwrite( int, LPSTR, int );
+BOOL FAR PASCAL AnsiToOem( LPSTR, LPSTR );
+BOOL FAR PASCAL OemToAnsi( LPSTR, LPSTR );
+BYTE FAR PASCAL AnsiUpper( LPSTR );
+BYTE FAR PASCAL AnsiLower( LPSTR );
+LPSTR FAR PASCAL AnsiNext( LPSTR );
+LPSTR FAR PASCAL AnsiPrev( LPSTR, LPSTR );
+
+typedef struct {
+ BYTE cBytes; /* length of structure */
+ BYTE fFixedDisk; /* non-zero if file located on non- */
+ /* removeable media */
+ WORD nErrCode; /* DOS error code if OpenFile fails */
+ BYTE reserved[ 4 ];
+ BYTE szPathName[ 128 ];
+} OFSTRUCT;
+typedef OFSTRUCT *POFSTRUCT;
+typedef OFSTRUCT NEAR *NPOFSTRUCT;
+typedef OFSTRUCT FAR *LPOFSTRUCT;
+
+int FAR PASCAL GetTempFileName( BYTE, LPSTR, WORD, LPSTR );
+int FAR PASCAL OpenFile( LPSTR, LPOFSTRUCT, WORD );
+int NEAR PASCAL MyOpenFile( LPSTR, LPOFSTRUCT, WORD );
+
+/* Flags for GetTempFileName */
+
+#define TF_FORCEDRIVE (BYTE)0x80 /* Forces use of current dir of passed */
+ /* drive */
+/* Flags for OpenFile */
+
+#define OF_REOPEN 0x8000
+#define OF_EXIST 0x4000
+#define OF_PROMPT 0x2000
+#define OF_CREATE 0x1000
+#define OF_CANCEL 0x0800
+#define OF_VERIFY 0x0400
+#define OF_DELETE 0x0200
+/* Can use these with _lopen too */
+#define OF_SHARE_COMPAT 0x00
+#define OF_SHARE_EXCLUSIVE 0x10
+#define OF_SHARE_DENY_WRITE 0x20
+#define OF_SHARE_DENY_READ 0x30
+#define OF_SHARE_DENY_NONE 0x40
+#define OF_NO_INHERIT 0x80
+
+#define READ 0 /* Flags for _lopen */
+#define WRITE 1
+#define READ_WRITE 2
+
+#if KDEBUG
+int PASCAL KernelError( int, LPSTR, LPSTR );
+void far PASCAL FarKernelError( int, LPSTR, LPSTR );
+#else
+#define FarKernelError( a, b, c ) FatalExit( a )
+#endif
+
+/* See KERNEL.INC for parallel definitions */
+
+#define ERR_LMEM 0x0100 /* Local memory manager errors */
+#define ERR_GMEM 0x0200 /* Global memory manager errors */
+#define ERR_TASK 0x0300 /* Task scheduler errors */
+
+#define ERR_LD 0x0400 /* Dynamic loader/linker errors */
+#define ERR_LDBOOT 0x0401 /* Error booting */
+#define ERR_LDLOAD 0x0401 /* Unable to load a file */
+
+#define ERR_RESMAN 0x0500 /* Resource manager errors */
+#define ERR_MISSRES 0x0501 /* Missing resource table */
+#define ERR_BADRESTYPE 0x0502 /* Bad resource type */
+#define ERR_BADRESNAME 0x0503 /* Bad resource name */
+#define ERR_BADRESFILE 0x0504 /* Bad resource file */
+#define ERR_BADDEFAULT 0x0506 /* Bad parameter to profile routine */
+
+#define ERR_ATOM 0x0600 /* Atom manager errors */
+#define ERR_IO 0x0700 /* I/O package errors */
+
+#define ERR_PARAMETER 0x0800 /* Parameter checking RIP */
+
+#define HE_DISCARDED 0x40
+#define HE_SHAREALL 0x20
+#define HE_SHARE 0x10
+#define HE_DISCARDABLE 0x0F
+
+#define HE_FREEHANDLE 0xFFFF
+
+#define LHE_DISCARDED 0x40
+#define LHE_SHAREALL 0x20
+#define LHE_SHARE 0x10
+#define LHE_DISCARDABLE 0x0F
+
+#define LHE_FREEHANDLE 0xFFFF
+
+#define HANDLEENTRY struct handleentry
+#define HANDLETABLE struct handletable
+#define LOCALHANDLEENTRY struct localhandleentry
+#define LOCALHANDLETABLE struct localhandletable
+#define FREEHANDLEENTRY struct freehandleentry
+#define LOCALFREEHANDLEENTRY struct localfreehandleentry
+
+HANDLEENTRY {
+ WORD he_address;
+ BYTE he_flags;
+ BYTE he_seg_no;
+};
+typedef HANDLEENTRY *PHANDLEENTRY;
+
+HANDLETABLE {
+ WORD ht_count;
+ HANDLEENTRY ht_entry[ 1 ];
+};
+typedef HANDLETABLE *PHANDLETABLE;
+
+LOCALHANDLEENTRY {
+ WORD lhe_address;
+ BYTE lhe_flags;
+ BYTE lhe_count;
+};
+typedef LOCALHANDLEENTRY *PLOCALHANDLEENTRY;
+
+LOCALHANDLETABLE {
+ WORD ht_count;
+ LOCALHANDLEENTRY ht_entry[ 1 ];
+};
+typedef LOCALHANDLETABLE *PLOCALHANDLETABLE;
+
+FREEHANDLEENTRY {
+ WORD he_link;
+ WORD he_free;
+};
+typedef FREEHANDLEENTRY *PFREEHANDLEENTRY;
+
+LOCALFREEHANDLEENTRY {
+ WORD lhe_link;
+ WORD lhe_free;
+};
+typedef LOCALFREEHANDLEENTRY *PLOCALFREEHANDLEENTRY;
+
+#define LOCALARENA struct localarena
+
+LOCALARENA {
+ LOCALARENA *la_prev;
+ LOCALARENA *la_next;
+ LOCALHANDLEENTRY *la_handle;
+};
+typedef LOCALARENA *PLOCALARENA;
+
+#define LOCALARENAFREE struct localarenafree
+
+LOCALARENAFREE {
+ LOCALARENAFREE *la_prev; /* previous block */
+ LOCALARENAFREE *la_next; /* next block */
+ int la_size; /* size of block (includes header) */
+ LOCALARENAFREE *ls_free_prev; /* previous free entry */
+ LOCALARENAFREE *la_free_next; /* next free entry */
+};
+typedef LOCALARENAFREE *PLOCALARENAFREE;
+
+#define LOCALSTATS struct localstats
+
+LOCALSTATS {
+ WORD ls_ljoin;
+ WORD ls_falloc;
+ WORD ls_fexamine;
+ WORD ls_fcompact;
+ WORD ls_ffound;
+ WORD ls_ffoundne;
+ WORD ls_malloc;
+ WORD ls_mexamine;
+ WORD ls_mcompact;
+ WORD ls_mfound;
+ WORD ls_mfoundne;
+ WORD ls_fail;
+ WORD ls_lcompact;
+ WORD ls_cloop;
+ WORD ls_cexamine;
+ WORD ls_cfree;
+ WORD ls_cmove;
+};
+
+typedef struct {
+ WORD hi_check;
+ WORD hi_freeze;
+ WORD hi_count;
+ PLOCALARENA hi_first;
+ PLOCALARENA hi_last;
+ BYTE hi_ncompact;
+ BYTE hi_dislevel;
+ WORD hi_distotal;
+ LOCALHANDLETABLE *hi_htable;
+ LOCALHANDLEENTRY *hi_hfree;
+ WORD hi_hdelta;
+ NEARPROC hi_hexpand;
+ LOCALSTATS *hi_pstats;
+
+ FARPROC li_notify;
+ WORD li_lock;
+ WORD li_extra;
+ WORD li_minsize;
+} LOCALINFO;
+
+typedef LOCALINFO *PLOCALINFO;
+
+#define LA_BUSY 1
+#define LA_MOVEABLE 2
+#define LA_ALIGN (LA_MOVEABLE+LA_BUSY)
+#define LA_MASK (~ LA_ALIGN)
+
+typedef HANDLEENTRY far *LPHANDLEENTRY;
+typedef HANDLETABLE far *LPHANDLETABLE;
+typedef FREEHANDLEENTRY far *LPFREEHANDLEENTRY;
+
+typedef LOCALHANDLEENTRY far *LPLOCALHANDLEENTRY;
+typedef LOCALHANDLETABLE far *LPLOCALHANDLETABLE;
+typedef LOCALFREEHANDLEENTRY far *LPLOCALFREEHANDLEENTRY;
+
+#define GLOBALARENA struct globalarena
+
+GLOBALARENA {
+ BYTE ga_count;
+ WORD ga_owner;
+ WORD ga_size;
+ BYTE ga_flags;
+ WORD ga_prev;
+ WORD ga_next;
+ HANDLEENTRY *ga_handle;
+ HANDLEENTRY *ga_lruprev;
+ HANDLEENTRY *ga_lrunext;
+};
+
+#define ga_sig ga_count
+
+typedef GLOBALARENA far *LPGLOBALARENA;
+
+typedef struct {
+ WORD hi_check;
+ WORD hi_freeze;
+ WORD hi_count;
+ WORD hi_first;
+ WORD hi_last;
+ BYTE hi_ncompact;
+ BYTE hi_dislevel;
+ WORD hi_distotal;
+ HANDLETABLE *hi_htable;
+ HANDLEENTRY *hi_hfree;
+ WORD hi_hdelta;
+ NEARPROC hi_hexpand;
+ WORD *hi_pstats;
+
+ WORD gi_lrulock;
+ HANDLEENTRY *gi_lruchain;
+ WORD gi_lrucount;
+ WORD gi_reserve;
+ WORD gi_disfence;
+ WORD gi_alt_first;
+ WORD gi_alt_last;
+ WORD gi_alt_count;
+ HANDLEENTRY *gi_alt_lruchain;
+ WORD gi_alt_lrucount;
+ WORD gi_alt_reserve;
+ WORD gi_alt_disfence;
+} GLOBALINFO;
+
+typedef GLOBALINFO far *LPGLOBALINFO;
+
+#define GA_SIGNATURE 0x4D
+#define GA_ENDSIG 0x5A
+
+#define GA_FIXED 1
+#define GA_ALIGN GA_FIXED
+#define GA_MASK (~ GA_ALIGN)
+
+#define lpGlobalArena( w ) (LPGLOBALARENA)((DWORD)(w) << 16)
+#define lpHandleEntry( w ) (LPHANDLEENTRY)(pMaster | (WORD)(w))
+#define lpHandleTable( w ) (LPHANDLETABLE)(pMaster | (WORD)(w))
+
+/*
+ * Structure passed between user profile routines
+ */
+typedef struct {
+ LPSTR lpProFile; /* Pointer to INI filename */
+ LPSTR lpBuffer; /* Pointer to buffer containing file */
+ int hBuffer; /* Handle of buffer */
+ unsigned BufferLen; /* Length of buffer */
+ int FileHandle; /* File handle - -1 if not open */
+ int ProFlags; /* Open, writing etc */
+ WORD wClusterSize; /* Cluster size on this drive */
+ OFSTRUCT ProBuf; /* OpenFile info */
+} PROINFO;
+
+/* WinFlags[0] */
+
+#define WF_PMODE 0x01 /* Windows is running in Protected Mode */
+#define WF_CPU286 0x02 /* Windows is running on an 80286 cpu */
+#define WF_CPU386 0x04 /* " " " " " 80386 cpu */
+#define WF_CPU486 0x08 /* Windows is running on an 80486 cpu */
+#define WF_STANDARD 0x10 /* Running Windows/286 */
+#define WF_ENHANCED 0x20 /* Running Windows/386 */
+#define WF_CPU086 0x40 /* Windows is running on an 8086 cpu */
+#define WF_CPU186 0x80 /* Windows is running on an 80186 cpu */
+
+/* WinFlags[1] */
+
+#define WF1_LARGEFRAME 0x01 /* Running in EMS small frame */
+#define WF1_SMALLFRAME 0x02 /* Running in EMS large frame */
+#define WF1_80x87 0x04 /* There is a co-processor present */
+
+#ifndef WINDEBUG
+
+#include "ikernel.h"
+
+#endif
diff --git a/private/mvdm/wow16/kernel31/kernel.inc b/private/mvdm/wow16/kernel31/kernel.inc
new file mode 100644
index 000000000..e01663cf6
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.inc
@@ -0,0 +1,1259 @@
+
+; Include file for kernel assembler source files.
+
+?PLM = 1
+?WIN = 1
+?NODATA = 1
+?DF = 1
+?386regs = 1
+ifndef WINDEBUG
+ KDEBUG = 0
+ WDEBUG = 0
+ DOS5 = 1 ; Do not mark far stack frames.
+else
+ KDEBUG = 1
+ WDEBUG = 1
+endif
+
+SHARE_AWARE = 0
+
+BUILDDLL equ 1
+PMODE equ 1
+
+include cmacros.inc
+include logerror.inc
+include vint.inc
+
+DEB_ERROR equ DBF_ERROR
+DEB_WARN equ DBF_WARNING
+DEB_TRACE equ DBF_TRACE
+DEB_FERROR equ DBF_FATAL
+DEB_krMemMan equ DBF_KRN_MEMMAN
+DEB_krLoadMod equ DBF_KRN_LOADMODULE
+DEB_krLoadSeg equ DBF_KRN_SEGMENTLOAD
+DEB_IERROR equ DBF_ERROR
+DEB_IWARN equ DBF_WARNING
+DEB_ITRACE equ DBF_TRACE
+DEB_IFERROR equ DBF_FATAL
+
+;DEB_ERROR = 1
+;DEB_WARN = 2
+;DEB_TRACE = 4
+;DEB_FERROR = 8 ;; fatal error - terminate app
+;DEB_IERROR = 10h
+;DEB_IWARN = 20h
+;DEB_ITRACE = 40h
+;DEB_IFERROR = 80h ;; fatal error - terminate app
+;DEB_FERRORS = DEB_FERROR or DEB_IFERROR
+;DEB_ERRORS = DEB_ERROR OR DEB_IERROR OR DEB_FERRORS
+;DEB_WARNS = DEB_WARN OR DEB_IWARN
+;DEB_TRACES = DEB_TRACE OR DEB_ITRACE
+;DEB_NOCRLF = 8000h ;; No CR/LF in string
+DEB_BREAKLEVEL = 099h
+DEB_INFOLEVEL = 099h or 022h
+
+if KDEBUG
+ ;include win3deb.inc
+ ;declare_debug kr
+ ;declare_areas Kernel, kr, <MemMan, LoadMod, LoadSeg>
+
+ifndef win3deb
+externFP _krDebugTest
+endif
+
+BegData macro
+ _DATA SEGMENT PARA PUBLIC 'DATA'
+endm
+
+EndData macro
+ _DATA ENDS
+endm
+
+krDebugOut macro flags,msg
+ local a, b
+ BegData
+a label byte
+ife ((flags and DBF_SEVMASK) - DBF_FATAL)
+ db "fatl"
+elseife ((flags and DBF_SEVMASK) - DBF_ERROR)
+ db "err"
+elseife ((flags and DBF_SEVMASK) - DBF_WARNING)
+ db "wn"
+else
+ db "t"
+endif
+ifdef WOW
+ db " W16Kernel: "
+else
+ db " Kernel: "
+endif
+ db msg
+ db 0ah
+ db 0
+ EndData
+ push flags or DBF_KERNEL
+ push offset a
+ call _krDebugTest
+endm
+
+else
+ krDebugOut macro flag, str, vals
+ endm
+endif
+
+if1
+ifndef ?DFSTACK
+ ?DFSTACK1 = 0
+else
+ ?DFSTACK1 = 1
+endif
+endif
+
+; Define IGROUP segments
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE,IGROUP
+createSeg _GPFIX0,GPFIX0,WORD,PUBLIC,CODE,IGROUP ; GP fault trapping
+createSeg _GPFIX,GPFIX,WORD,PUBLIC,CODE,IGROUP
+createSeg _GPFIX1,GPFIX1,WORD,PUBLIC,CODE,IGROUP
+createSeg _EMS,EMSCODE,PARA,PUBLIC,CODE,IGROUP
+createSeg _INITTEXT,INITCODE,BYTE,PUBLIC,CODE,IGROUP
+
+defGrp IGROUP,CODE
+
+
+; Define Non-resident segments (after "defGrp IGROUP")
+
+createSeg _NRESTEXT,NRESCODE,WORD,PUBLIC,CODE
+createSeg _MISCTEXT,MISCCODE,WORD,PUBLIC,CODE
+
+; Define DGROUP segments
+
+createSeg _DATA,DATA,PARA,PUBLIC,DATA,DGROUP
+createSeg _EMSDATA,EMSDATA,WORD,PUBLIC,DATA,DGROUP
+createSeg _INITDATA,INITDATA,WORD,PUBLIC,DATA,DGROUP
+if ?DFSTACK1
+ createSeg STACK,STACK,PARA,PUBLIC,DATA,DGROUP
+endif
+createSeg _PADDATA,PADDATA,BYTE,PUBLIC,DATA,DGROUP
+
+defGrp DGROUP,DATA
+
+
+if ?CHKSTK1
+externP <chkstk>
+endif
+
+
+DISCARD_HIGH = 1
+TONYS_EMS_STUFF = 0
+
+if KDEBUG
+RSHORT equ <>
+else
+RSHORT equ short
+endif
+
+.286
+
+ .286p
+ INTBASE = 90h
+ RNTBASE = 45h
+
+ ifndef PM386
+ PMODE32 = 0
+ else
+ PMODE32 = 1
+ endif
+
+ ifndef ALIASTRACKING
+ ALIASES = 0
+ else
+ ALIASES = 1
+ endif
+
+
+if1
+
+ifdef DBCS
+ FFDBCS = 1
+else
+ FFDBCS = 0
+endif
+
+KRNLDS EQU <DATA>
+
+ifdef ROMWIN
+ ROM = 1
+ if PMODE
+ %OUT ROM Kernel requires Protect Mode
+ .err
+ endif
+else
+ ROM = 0
+endif
+
+outif ROM,0,<ROM Windows kernel>
+
+outif KDEBUG,0,<Debug Kernel.>
+
+outif FFDBCS,0,<DBCS code enabled>
+
+; The following three are obsolete, but they need to have the
+; proper values so dead code doesn't get assembled, and live
+; code does.
+
+SDEBUG equ 1
+
+LDCHKSUM equ 0
+
+SWAPPRO equ 0
+
+endif
+
+ ERR_LMEM = 00100h ; Local memory errors
+ ERR_LMEMCRIT = 00140h ; Local heap is busy
+ ERR_LMEMHANDLE = 00180h ; Invalid local handle
+ ERR_LMEMLOCK = 001C0h ; LocalLock count overflow
+ ERR_LMEMUNLOCK = 001F0h ; LocalUnlock count underflow
+
+ ERR_GMEM = 00200h ; global memory errors
+;ERR_GMEMCRIT = 00240h ; Critical section problems
+ ERR_GMEMHANDLE = 00280h ; Invalid global handle
+ ERR_GMEMLOCK = 002C0h ; globalLock count overflow
+ ERR_GMEMUNLOCK = 002F0h ; globalUnlock count underflow
+
+;ERR_TASK = 00300h ; task schedule errors
+;ERR_TASKID = 00301h ; Invalid task ID
+;ERR_TASKEXIT = 00302h ; Invalid exit system call
+;ERR_TASKFRAME = 00303h ; Invalid BP chain
+
+;ERR_LD = 00400h ; dynamic loader/linker errors
+;ERR_LDBOOT = 00401h ; Error during boot process
+;ERR_LDLOAD = 00402h ; Error loading a module
+;ERR_LDORD = 00403h ; Invalid ordinal reference
+;ERR_LDNAME = 00404h ; Invalid entry name reference
+;ERR_LDPROC = 00405h ; Invalid start proc
+ERR_LDMODULE = 00406h ; Invalid module handle
+;ERR_LDRELOC = 00407h ; Invalid relocation record
+;ERR_LDFWDREF = 00408h ; Error saving forward reference
+;ERR_LDREADSEG = 00409h ; Error reading segment contents
+;ERR_LDREADREL = 00410h ; Error reading segment contents
+;ERR_LDDISK = 00411h ; Insert disk for specified file
+ERR_LDNRTABLE = 00412h ; Error reading non-resident table
+;ERR_LDFILES = 00413h ; Out of files
+;ERR_LDINT3F = 004FFh ; INT 3F handler unable to load segment
+
+;ERR_RESMAN = 00500h ; resource manager/user profile errors
+;ERR_MISSRES = 00501h ; Missing resource table
+;ERR_BADRESTYPE = 00502h ; Bad resource type
+;ERR_BADRESNAME = 00503h ; Bad resource name
+ERR_BADRESFILE = 00504h ; Bad resource file
+ERR_BADRESREAD = 00505h ; Error reading resource
+ERR_BADDEFAULT = 00506h ; Bad default pointer for profile routine
+
+;ERR_ATOM = 00600h ; atom manager errors
+
+;ERR_IO = 00700h ; I/O package errors
+
+ERR_PARAMETER = 00800h ; Internal KERNEL parameter validation
+
+;** PTrace notification indexes. See 2lddebug and 3lddebug
+SDM_RIN = 9
+SDM_BANKLINE = 10
+SDM_NEWTASK = 11
+SDM_FLUSHTASK = 12
+SDM_SWITCHOUT = 13
+SDM_SWITCHIN = 14
+SDM_KEYBOARD = 15
+SDM_MAXFUNC = 15
+SDM_LOADSEG = 50h
+SDM_MOVESEG = 51h
+SDM_FREESEG = 52h
+SDM_RELEASESEG = 5Ch
+SDM_GLOBALHEAP = 3
+SDM_CONWRITE = 12h
+SDM_CONREAD = 1
+SDM_DGH = 56h
+SDM_DFL = 57h
+SDM_DLL = 58h
+SDM_LOADTASK = 59h
+SDM_POSTLOAD = 60h
+SDM_EXITCALL = 62h
+SDM_INT2 = 63h
+SDM_LOADDLL = 64h
+SDM_DELMODULE = 65h
+; New notifications
+SDM_LOGERROR = 66h ; cx = error code, dx:bx = ptr to optional info
+SDM_LOGPARAMERROR = 67h ; es:bx = ptr to struct { err, lpfn, param };
+
+if1
+outif ?RIPAUX,0
+endif
+
+; DataBegin/End macros are used to bracket data items. Examples:
+;
+; DataBegin ; in segment DATA
+; globalD flarp,0
+; DataEnd
+;
+; DataBegin INIT ; in segment INITDATA
+; globalW who_cares,1022
+; DataEnd INIT
+
+DataBegin macro type
+% sBegin &type&%KRNLDS
+assumes ds, %KRNLDS
+ endm
+
+DataEnd macro type
+assumes ds,nothing
+sEnd &type&%KRNLDS
+ endm
+
+;-----------------------------------------------------------------------
+; cProcVDO - cProc "Validate Debug Only"
+;
+; Same as cProc, except used for "Validate in Debug Only" entry points.
+; Declares Iname if debug, name if retail.
+;
+cProcVDO macro name,opts,savelist
+ if KDEBUG
+ cProc <I&name>,<opts>,<savelist>
+ else
+ LabelFP <PUBLIC, I&name>
+ cProc <name>,<opts>,<savelist>
+ endif
+endm
+
+
+;-----------------------------------------------------------------------
+; LabelVDO
+;
+; Similar to LabelFP, except used for "validate in debug only" entry points.
+; Declares Iname if debug, name if
+;
+LabelVDO macro name
+ if KDEBUG
+ LabelFP <PUBLIC, I&name>
+ else
+ LabelFP <PUBLIC, I&name>
+ LabelFP <PUBLIC, name>
+ endif
+endm
+if KDEBUG
+
+ife ?RIPAUX
+externFP FarKernelError
+externNP NearKernelError
+externFP KOutDSStr
+endif
+
+externNP <KernelError>
+
+DataBegin
+externB szFKE ; "**** Fatal Kernel Error ****" - Only define the string once
+DataEnd
+
+kerror macro errcode,msg,segarg,offarg
+ local a
+ ifnb <errcode> ;; Push either AX or errcode
+ push errcode ;; Don't trash AX anymore!
+ else
+ push ax
+ endif
+
+ ifnb <msg> ;; Put strings in DGROUP so jcond
+ _DATA SEGMENT PARA PUBLIC 'DATA' ;; can be short (not jump around)
+ a label byte
+ db '&msg',0
+ _DATA ENDS
+ push dataOffset a
+ else
+ push dataOffset szFKE
+ endif
+
+ ifnb <segarg> ;; Push seg:offset or NULLPTR
+ push segarg
+ push offarg
+ else
+ push 0
+ push 0
+ endif
+
+ call NearKernelError ;; Call Kernel Error
+endm
+
+fkerror macro errcode,msg,segarg,offarg
+ local a
+ ifnb <errcode> ;; Push either AX or errcode
+ push errcode ;; Don't trash AX anymore!
+ else
+ push ax
+ endif
+
+ ifnb <msg> ;; Put strings in DGROUP so jcond
+ _DATA SEGMENT PARA PUBLIC 'DATA' ;; can be short (not jump around)
+ a label byte
+ db '&msg',0
+ _DATA ENDS
+ push dataOffset a
+ else
+ push dataOffset szFKE
+ endif
+
+ ifnb <segarg> ;; Push seg:offset or NULLPTR
+ push segarg
+ push offarg
+ else
+ push 0
+ push 0
+ endif
+
+ call FarKernelError ;; Call Kernel Error
+ endm
+
+mkerror macro errcode,msg,segarg,offarg
+ local a
+ ifnb <errcode> ;; Push either AX or errcode
+ push errcode ;; Don't trash AX anymore!
+ else
+ push ax
+ endif
+
+ ifnb <msg> ;; Put strings in DGROUP so jcond
+ _DATA SEGMENT PARA PUBLIC 'DATA' ;; can be short (not jump around)
+ a label byte
+ db '&msg',0
+ _DATA ENDS
+ push dataOffset a
+ else
+ push dataOffset szFKE
+ endif
+
+ ifnb <segarg> ;; Push seg:offset or NULLPTR
+ push segarg
+ push offarg
+ else
+ push 0
+ push 0
+ endif
+
+ call FarKernelError ;; Call Kernel Error
+ endm
+else
+
+ifdef WOW ; For WOW we call FatalExitC which thunks to WK32FatalExit.
+externFP <FatalExitC>
+kerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitC,<errcode>
+ endm
+
+fkerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitC,<errcode>
+ endm
+
+mkerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitC,<errcode>
+ endm
+else
+ife ?RIPAUX ; Dont declare external in RIPAUX.ASM
+externFP <FatalExitDeath>
+endif
+kerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitDeath,<errcode>
+ endm
+
+fkerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitDeath,<errcode>
+ endm
+
+mkerror macro errcode,msg,segarg,offarg ;; Non-Debug version
+ cCall FatalExitDeath,<errcode>
+ endm
+endif
+endif
+
+; define misc. register pairs
+;
+regptr esax,es,ax
+regptr esbx,es,bx
+regptr essi,es,si
+regptr esdi,es,di
+regptr dsax,ds,ax
+regptr dsbx,ds,bx
+regptr dsdx,ds,dx
+regptr dssi,ds,si
+regptr dsdi,ds,di
+regptr csbx,cs,bx
+regptr csdx,cs,dx
+regptr cssi,cs,si
+regptr csdi,cs,di
+regptr dxax,dx,ax
+regptr ssbx,ss,bx
+regptr ssdi,ss,di
+
+; The jmpnext macro and associated symbols are used to generate
+; the fall-through chain and generate the labels required for
+; error checking.
+
+??ji = 0 ;;Initial index value
+
+jmpnext macro e
+jn %??ji,%(??ji+1),e ;;Set next label
+endm
+
+jn macro i,j,e
+.sall
+??ji&i:
+.xall
+ifb <e> ;;If not the end of the chain
+ db 03Dh ;;cmp ax, next two bytes
+errn$ ??ji&j,+2 ;;next label must be two bytes away
+endif
+??ji=j ;;increment counter
+endm
+
+smov macro segreg1,segreg2
+ push segreg2
+ pop segreg1
+endm
+
+jmps macro n
+ jmp short n
+endm
+
+ret_far macro add_2_stack
+ifnb <add_2_stack>
+ db 0CAh
+ dw add_2_stack
+else
+ db 0CBh
+endif
+ endm
+
+
+entry macro routine
+ extrn routine :near
+ dw Offset IGROUP:routine
+ endm
+
+
+STACK_SIGNATURE equ 'WD'
+MPIT_SIGNATURE equ 'TP'
+
+INT21 macro
+ int 21h ; Force an actual int 21h
+ endm
+
+DOSCALL macro
+ pushf
+ push cs
+ call near ptr Int21Handler ; Call our handler directly!
+ endm
+
+DOSFCALL macro
+ pushf
+ call far ptr Int21Handler ; Call our handler directly!
+ endm
+
+SetKernelDSNRes macro segreg ; usable in kernel NRES segment
+ifndef KDataSeg
+externW KDataSeg
+endif
+ifnb <segreg>
+ifdifi <segreg>,<es>
+ mov segreg, cs:KDataSeg
+else
+ mov es, cs:KDataSeg
+endif
+ assumes <segreg>, %KRNLDS
+else
+ mov ds, cs:KDataSeg
+ assumes ds, %KRNLDS
+endif
+ endm
+
+SetKernelDSMisc macro segreg ; usable in kernel MISC segment
+ifndef MKDataSeg
+externW MKDataSeg
+endif
+ifnb <segreg>
+ifdifi <segreg>,<es>
+ mov segreg, cs:MKDataSeg
+else
+ mov es, cs:MKDataSeg
+endif
+ assumes <segreg>, %KRNLDS
+else
+ mov ds, cs:MKDataSeg
+ assumes ds, %KRNLDS
+endif
+ endm
+
+SetKernelDS macro segreg
+ifndef MyCSDS
+externW MyCSDS
+endif
+ifnb <segreg>
+ifdifi <segreg>,<es>
+ mov segreg, cs:MyCSDS
+else
+ mov es, cs:MyCSDS
+endif
+ assumes <segreg>, %KRNLDS
+else
+ mov ds, cs:MyCSDS
+ assumes ds, %KRNLDS
+endif
+ endm
+
+UnSetKernelDS macro segreg
+ifnb <segreg>
+ assumes <segreg>, nothing
+else
+ assumes ds, nothing
+endif
+ endm
+
+ReSetKernelDS macro segreg
+ifnb <segreg>
+ assumes <segreg>, %KRNLDS
+else
+ assumes ds, %KRNLDS
+endif
+ endm
+
+CheckKernelDS macro segreg
+ local ok
+if KDEBUG
+ifndef MyCSDS
+externW MyCSDS
+endif
+ push ax
+ifnb <segreg>
+ mov ax, segreg
+else
+ mov ax, ds
+endif
+ cmp ax, cs:MyCSDS
+ je short ok
+ int 3
+ok:
+ pop ax
+endif
+ endm
+
+SetKernelCSDword macro pdw, dwseg, dwoff
+ifndef SetKernelCSDwordProc
+externNP SetKernelCSDwordProc
+endif
+ cCall SetKernelCSDwordProc,<pdw,dwseg,dwoff>
+ endm
+
+Critical_check macro
+ local hey_dude
+if KDEBUG
+ push ds
+ mov ds,pGlobalHeap
+ cmp ds:[gi_lrulock],0 ; Make sure we're critical!
+ jnz short hey_dude
+ int 3
+hey_dude:
+ pop ds
+endif
+endm
+
+TDB_check_ES macro
+ local hey_dude
+if KDEBUG
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jz short hey_dude
+ int 3
+hey_dude:
+endif
+endm
+
+TDB_check_DS macro
+ local hey_dude
+if KDEBUG
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jz short hey_dude
+ int 3
+hey_dude:
+endif
+endm
+
+NE_check_ES macro
+ local hey_dude
+if KDEBUG
+ cmp es:[ne_magic],NEMAGIC
+ jz short hey_dude
+ int 3
+hey_dude:
+endif
+endm
+
+NE_check_DS macro
+ local hey_dude
+if KDEBUG
+ cmp ds:[ne_magic],NEMAGIC
+ jz short hey_dude
+ int 3
+hey_dude:
+endif
+endm
+
+ife 3-3
+sel_check macro reg
+ local hey_dude, aaarrrggghhh
+if KDEBUG
+ or reg, reg
+ jz short hey_dude
+ test reg, 4h ; Must be LDT
+ jz short aaarrrggghhh
+ test reg,2h ; Must be ring 2 or 3
+ jnz short hey_dude ; yes, fine
+aaarrrggghhh:
+ int 3
+ xor reg, reg ; HACK!! bug 5896
+hey_dude:
+endif
+ and reg, not 7
+endm
+
+else
+
+sel_check macro reg
+ local hey_dude, aaarrrggghhh
+if KDEBUG
+ or reg, reg
+ jz short hey_dude
+ test reg, 4h ; Must be LDT
+ jnz short hey_dude
+ int 3
+hey_dude:
+endif
+ and reg, not 7
+endm
+
+endif
+
+KBINFO STRUC
+kbRanges DB 4 dup (0) ; Far East ranges for KANJI
+kbStateSize DW 0 ; #bytes of state info maintained by TOASCII
+KBINFO ENDS
+
+
+EXECBLOCK struc
+envseg dw ? ; seg addr of environment
+lpcmdline dd ? ; pointer to asciz command line
+lpfcb1 dd ? ; default fcb at 5C
+lpfcb2 dd ? ; default fcb at 6C
+EXECBLOCK ends
+
+SYSINITVAR STRUC
+dpbhead DD ? ; Head of DPB-FAT list
+sfthead DD ? ; Head of SFT table list
+pclockdev DD ? ; pointer to clock device
+pcondev DD ? ; pointer to console device
+SYSI_MAXSEC DW ? ; maximum sector size
+SYSI_BUF DD ? ; points to Hashinitvar
+SYSI_CDS DD ? ; CDS list
+SYSI_FCB DD ? ; FCB chain
+SYSI_Keep DW ? ; keep count
+SYSI_NUMIO DB ? ; Number of block devices
+SYSI_NCDS DB ? ; number of CDS's
+SYSI_DEV DD ? ; device list
+SYSI_ATTR DW ? ; null device attribute word
+SYSI_STRAT DW ? ; null device strategy entry point
+SYSI_INTER DW ? ; null device interrupt entry point
+SYSI_NAME DB 8 DUP(?) ; null device name
+SYSI_SPLICE DB 0 ; TRUE -> splicees being done
+SYSI_IBMDOS_SIZE DW ? ; DOS size in paragraphs
+SYSI_IFS_DOSCALL@ DD ? ; IFS DOS service rountine entry
+SYSI_IFS DD ? ; IFS header chain
+SYSI_BUFFERS DW ?,0 ; BUFFERS= values (m,n)
+SYSI_BOOT_DRIVE DB ? ; boot drive A=1 B=2,..
+SYSI_DWMOVE DB 0 ; 1 if 386 machine
+SYSI_EXT_MEM DW 0 ; Extended memory size in KB.
+SYSINITVAR ENDS
+;
+; system file table
+;
+SFT STRUC
+sftLink DD ?
+sftCount DW ? ; number of entries
+sftFile DB ?
+SFT ENDS
+
+SFT_ENTRY3 STRUC
+sf_ref_count3 DW ? ; number of processes sharing fcb
+sf_mode3 DW ? ; mode of access
+sf_attr3 DB ? ; attribute of file
+sf_flags DW ?
+sf_devptr DD ?
+ DB 21 dup (?) ; this is 21 for DOS 3.1
+sf_name DB ?
+SFT_ENTRY3 ENDS
+
+DPB STRUC
+dpb_drive DB ? ; Logical drive # assoc with DPB (A=0,B=1,...)
+DPB ENDS
+
+devid_device EQU 0080H ; true if a device
+sf_isnet EQU 8000H ; true if network drive
+
+
+ INTVECTOR = 00Bh
+ INTSIZE = 8
+
+
+HILO STRUC
+lo DW ?
+hi DW ?
+HILO ENDS
+
+SEGOFF STRUC
+off DW ?
+sel DW ?
+SEGOFF ENDS
+
+
+; CPU flags
+
+CPUF_CARRY = 0000000000000001b
+; = 0000000000000010b
+CPUF_PARITY = 0000000000000100b
+; = 0000000000001000b
+CPUF_AUXCARRY = 0000000000010000b
+; = 0000000000100000b
+CPUF_ZERO = 0000000001000000b
+CPUF_SIGN = 0000000010000000b
+CPUF_TRAP = 0000000100000000b
+CPUF_INTERRUPT = 0000001000000000b
+CPUF_DIRECTION = 0000010000000000b
+CPUF_OVERFLOW = 0000100000000000b
+CPUF_IOPL = 0011000000000000b
+CPUF_NESTEDTASK = 0100000000000000b
+; = 1000000000000000b
+
+; WM_FILESYSCHANGE message wParam value
+
+WM_FILESYSCHANGE = 0034h
+
+FSC_CREATE = 0
+FSC_DELETE = 1
+FSC_RENAME = 2
+FSC_ATTRIBUTES = 3
+FSC_NETCONNECT = 4
+FSC_NETDISCONNECT = 5
+FSC_REFRESH = 6
+FSC_MKDIR = 7
+FSC_RMDIR = 8
+
+; MessageBox type flags
+
+MB_OK = 0000H
+MB_OKCANCEL = 0001H
+MB_ABORTRETRYIGNORE = 0002H
+MB_YESNOCANCEL = 0003H
+MB_RETRYCANCEL = 0005H
+MB_ICONHAND = 0010H
+MB_ICONQUESTION = 0020H
+MB_ICONEXCLAMATION = 0030H
+MB_ICONASTERISK = 0040H
+MB_DEFBUTTON1 = 0000H
+MB_DEFBUTTON2 = 0100H
+MB_DEFBUTTON3 = 0200H
+MB_SYSTEMMODAL = 1000H
+MB_TASKMODAL = 2000H
+
+; Conventional dialog box and message box command IDs
+
+IDOK = 1
+IDCANCEL = 2
+IDABORT = 3
+IDRETRY = 4
+IDIGNORE = 5
+IDYES = 6
+IDNO = 7
+
+; SysErrorBox type flags
+
+SEB_OK = 0001h ; Button with "OK".
+SEB_CANCEL = 0002h ; Button with "Cancel"
+SEB_YES = 0003h ; Button with "&Yes"
+SEB_NO = 0004h ; Button with "&No"
+SEB_RETRY = 0005h ; Button with "&Retry"
+SEB_ABORT = 0006h ; Button with "&Abort"
+SEB_IGNORE = 0007h ; Button with "&Ignore"
+SEB_CLOSE = 0008h ; Button with "Close"
+SEB_DEFBUTTON = 8000h ; Mask to make this button default
+
+; ExitKernel/ExitWindows flags
+EW_REBOOTSYSTEM = 43h
+
+; Kernel Flags[0]
+
+kf_restore_CtrlC EQU 01h ; A task switch has occured.
+kf_restore_disk EQU 02h ; A task switch has occured.
+kf_mondrian EQU 04h ; Windows was started under Mondrian.
+kf_check_free EQU 08h ; Free memory checking requested.
+kf_pUID EQU 10h ; Time to call pUserInitDone.
+kf_EMS_debug EQU 20h ; Tell symdeb about pseudo discards.
+kf_search_inst_stacks EQU 40h ; In patchstack search module stacks.
+kf_useslim32 EQU 80h ; Uses LIM 3.2 API (Intel Above Board)
+
+; Kernel Flags[1]
+
+kf1_WIN386 EQU 01h ; we are running under Windows/386
+kf1_WINOLDAP EQU 02h ; the app being loaded is WinOldAp
+kf1_ABORTION EQU 04h ; loading the automatic data segment?
+kf1_HAVEHMA EQU 08h ; High Memory Area is available
+kf1_GLOBALNOTIFY EQU 10h ; We're calling the app's notify proc.
+kf1_MEMORYMOVED EQU 20h ; global memory was moved by gmove
+;
+kf1_A20ON EQU 80h ; We have A20 on
+
+; Kernel Flags[2]
+
+KF2_GH_NORIP EQU 01h ; don't rip in gdref if invalid handle
+KF2_WIN_EXIT EQU 02h ; we're past ExitKernel
+KF2_APP_EXIT EQU 04h ; we're in DOS 4C quitting an app
+KF2_SYMDEB EQU 08h ; symdeb or somesuch in installed
+KF2_PTRACE EQU 10h ; ptrace.dll is installed
+KF2_DOSX EQU 20h ; running under 286 DOS extender
+KF2_WIN386CRAZINESS EQU 40h ; i hate async notification!
+KF2_TOOLHELP EQU 80h ; TOOLHELP.DLL callback installed
+
+; WinFlags[0]
+
+WF_PMODE EQU 01h ; Windows is running in Protected Mode
+WF_CPU286 EQU 02h ; Windows is running on an 80286 cpu
+WF_CPU386 EQU 04h ; " " " " " 80386 cpu
+WF_CPU486 EQU 08h ; Windows is running on an 80486 cpu
+WF_STANDARD EQU 10h ; Running Windows/286
+WF_ENHANCED EQU 20h ; Running Windows/386
+WF_CPU086 EQU 40h ; Windows is running on an 8086 cpu
+WF_CPU186 EQU 80h ; Windows is running on an 80186 cpu
+
+; WinFlags[1]
+
+WF1_LARGEFRAME EQU 01h ; Running in EMS small frame
+WF1_SMALLFRAME EQU 02h ; Running in EMS large frame
+WF1_80x87 EQU 04h ; There is a co-processor present
+WF1_PAGING EQU 08h ; Paging is enabled
+ifdef WOW
+WF1_WINNT EQU 40h ; Running on Windows NT WOW layer
+endif
+
+ifdef WOW
+; DebugWOW
+DW_DEBUG EQU 0001h ; 32-bit Debugger debugging wow
+endif
+
+; Note, WF_WIN286 + WF_PMODE indicates running under the 286 DOS extender
+
+; Flags for OpenFile
+
+OF_READ = 0000H
+OF_WRITE = 0001H
+OF_READWRITE = 0002H
+OF_SHARE_COMPAT = 0000H
+OF_SHARE_EXCLUSIVE = 0010H
+OF_SHARE_DENY_WRITE = 0020H
+OF_SHARE_DENY_READ = 0030H
+OF_SHARE_DENY_NONE = 0040H
+OF_NO_INHERIT = 0080H
+OF_PARSE = 0100H
+OF_DELETE = 0200H
+OF_VERIFY = 0400H
+OF_CANCEL = 0800H
+OF_CREATE = 1000H
+OF_PROMPT = 2000H
+OF_EXIST = 4000H
+OF_REOPEN = 8000H
+
+TF_FORCEDRIVE = 80H
+
+MaxFileLen equ 128
+
+OPENSTRUC STRUC
+opLen db ?
+opDisk db ?
+opXtra dw ?
+opDate dw ?
+opTime dw ?
+opFile db ?
+OPENSTRUC ENDS
+
+; GetAppCompatFlags/TDB_CompatFlags flag values
+
+GACF_IGNORENODISCARD EQU 0001h ; Ignore GA_NODISCARD on GlobalAlloc
+GACF_HACKWINFLAGS EQU 0400h ; mask out new win31 flags ie. WF_PAGING
+
+; Look for module in Module Compatibilty section of win.ini
+MCF_FIXEDSEGLOW = 00001h ; Win31 behaviour for FIXED segs
+MCF_MODPATCH = 00002h ; Look for module patches in the registry
+MCF_NODISCARD = 00004h ; Make all segments in the module not discardable
+MCF_MODPATCH_X86 = 08000h ; Apply this module patch on x86 only
+MCF_MODPATCH_RISC = 04000h ; Apply this module patch on RISC only
+
+ifdef JAPAN
+;
+; INT 41H SIGNATURE
+; Some Japanese OEM want to use interrupt vector other than 41h for
+; debugger hook since this vector already used by system hardware.
+; We won't disclose sources for Kernel, OEM should change vector
+; number by 'patch'ing. The following macro appears below the 'INT 41H'
+; instruction so that OEM can find the patch position by searching this
+; signature string.
+INT41SIGNATURE macro
+ jmp short @F
+ db 'DEB41PATCH'
+@@:
+ endm
+endif ;JAPAN
+
+DebInt macro val
+ ifnb <val>
+ mov ax, val
+ endif
+ int 41h
+ ifdef JAPAN
+ jmp short @F
+ db 'DEB41PATCH'
+ @@:
+ endif
+endm
+
+
+;
+; Structure passed between user profile routines
+;
+PROINFO struc
+ lpProFile dd ? ; Pointer to INI filename
+ lpBuffer dd ? ; Pointer to buffer containing file
+ hBuffer dw ? ; Handle of buffer
+ BufferLen dw ? ; Length of buffer
+ FileHandle dw ? ; File handle - -1 if not open
+ ProFlags dw ? ; Open, writing etc
+ wClusterSize dw ? ; Bytes/cluster on current disk
+ ProBuf db (SIZE OPENSTRUC + MaxFileLen - 1) dup(?)
+PROINFO ends
+
+; -------------------------------------------------------
+; This macro displays a string if DEBUG
+;
+
+Trace_Out MACRO String, nocrlf
+ LOCAL a
+IF KDEBUG
+ _DATA SEGMENT PARA PUBLIC 'DATA' ;; (not jump around)
+ a label byte
+ifdef WOW
+ db "W16KERNEL: "
+endif
+ db String
+ IFB <nocrlf>
+ db 0dh, 0ah
+ ENDIF
+ db 0
+ _DATA ENDS
+ push dataOffset a
+ call KOutDSStr
+ENDIF
+ ENDM
+
+move MACRO reg,var
+ mov reg,var
+ endm
+
+WOWTrace MACRO String,args
+ LOCAL String_Offset, Skip
+IFDEF WOWDEBUGTRACE
+ irp arg,<args>
+ move arg
+ endm
+
+ jmps Skip
+String_Offset db "W16KERNEL:",String,0Dh,0Ah,0
+Skip:
+ push ds
+ pushf
+ pusha
+
+ mov ax,cs ; make sure string is addressable
+ mov ds,ax
+
+ lea si, String_Offset ; LEA to stop link whining
+
+ifndef KOutDebugStr
+externFP KOutDebugStr
+endif
+
+ call KOutDebugStr
+
+ popa
+ popf
+ pop ds
+ENDIF
+ ENDM
+
+; -------------------------------------------------------
+; This macro displays a string and breaks if DEBUG
+;
+
+Debug_Out MACRO String
+IF KDEBUG
+ Trace_Out <String>
+ int 3
+ENDIF
+ ENDM
+
+;
+; Error reporting constants (from windows.h)
+;
+; Error option flags (set by [kernel] ErrorOptions win.ini variable)
+
+ERO_PARAM_ERROR_BREAK equ 0001h
+ERO_BUFFER_FILL equ 0002h
+
+; Debug fill constants
+
+DBGFILL_ALLOC equ 0fdh
+DBGFILL_FREE equ 0fbh
+DBGFILL_BUFFER equ 0f9h
+DBGFILL_STACK equ 0f7h
+
+include winkern.inc
+
+if ROM
+include krom.inc
+endif
+
+ifndef WINDEBUG
+include ikernel.inc
+endif
+
+ifdef WOW
+STIRET MACRO
+ LOCAL Dont_Do_STI
+ push ax
+ pushf
+ pop ax
+ test ah, 2
+ pop ax
+ jnz SHORT Dont_Do_STI
+ FSTI
+Dont_Do_STI:
+ FIRET
+ ENDM
+else
+STIRET MACRO
+ LOCAL Dont_Do_STI
+if PMODE32
+ push ax
+ pushf
+ pop ax
+ test ah, 2
+ pop ax
+ jnz SHORT Dont_Do_STI
+ FSTI
+Dont_Do_STI:
+endif
+ FIRET
+ ENDM
+endif; WOW
+
+
+ife ?RIPAUX
+externFP LogError
+endif
+
+KernelLogError macro flags, errcode, msg
+ krDebugOut <flags>,<msg>
+ push errcode
+ push 0
+ push 0
+ call LogError
+endm
+
+; Load Module error return codes
+; Used by LD.asm, LDHEADER.asm, etc.
+LME_MEM = 0 ; Out of memory ;
+LME_FNF = 2 ; File not found
+LME_LINKTASK = 5 ; can't link to task ;
+LME_LIBMDS = 6 ; lib can't have multiple data segments ;
+LME_VERS = 10 ; Wrong windows version ;
+LME_INVEXE = 11 ; Invalid exe ;
+LME_OS2 = 12 ; OS/2 app ;
+LME_DOS4 = 13 ; DOS 4 app ;
+LME_EXETYPE = 14 ; unknown exe type ;
+LME_RMODE = 15 ; not a pmode windows app ;
+LME_APPMDS = 16 ; multiple data segments in app ;
+LME_EMS = 17 ; scum app in l-frame EMS ;
+LME_PMODE = 18 ; not an rmode windows app ;
+LME_COMP = 19 ; compressed EXE file ;
+LME_INVCOMP = 20 ; invalid DLL (component) caused EXE load fail ;
+LME_PE = 21 ; Windows Portable EXE app - let them load it ;
+LME_MAXERR = 32 ; for comparisons ;
+
+LME_WOAWOW32 = 23 ; For wow special handling of WOA
+
+PEMAGIC = 4550h ; 'PE'
+
+
+;
+; Use these macros instead of a raw "int 3" and maybe we can tell
+; later what is happening when we hit one!
+;
+
+; Put there by davidw or tonyg or even earlier. Nobody knows
+; what this is.
+;
+INT3_ANCIENT macro
+ int 3
+endm
+
+
+;
+; Used find out what happens when a code path is executed.
+; Should be ignoreable, but call a developer to make sure.
+;
+INT3_TEST macro
+ int 3
+endm
+
+
+;
+; This code path should "never" be executed.
+;
+INT3_NEVER macro
+ int 3
+endm
+
+
+;
+; Something strange, but not fatal. Should be changed to output
+; a message.
+;
+INT3_WARN macro
+ int 3
+endm
+
+
+;
+; This is bad, real bad.
+;
+INT3_FATAL macro
+ int 3
+endm
+
+
+;
+; Break in to debugger
+;
+INT3_DEBUG macro
+ int 3
+endm
diff --git a/private/mvdm/wow16/kernel31/kernel.rcv b/private/mvdm/wow16/kernel31/kernel.rcv
new file mode 100644
index 000000000..ca919b655
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* KERNEL.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Kernel"
+#define VER_INTERNALNAME_STR "KERNEL"
+
+/* VER_ORIGINALFILENAME_STR is #defined before this is #included */
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/kernel31/kernel.sed b/private/mvdm/wow16/kernel31/kernel.sed
new file mode 100644
index 000000000..0dcfc8410
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernel.sed
@@ -0,0 +1,9 @@
+/\\$/N
+/\\$/N
+/\\$/N
+h
+/./s/^./$(DEST)\\&/
+/./p
+g
+s/\..*//
+/./s/.*/ $(ASM) &,$(DEST)\\;/
diff --git a/private/mvdm/wow16/kernel31/kernstub.asm b/private/mvdm/wow16/kernel31/kernstub.asm
new file mode 100644
index 000000000..ed8079db0
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kernstub.asm
@@ -0,0 +1,118 @@
+ TITLE KERNSTUB - Assembly stub program for KERNEL.EXE
+
+.xlist
+?DF = 1
+SWAPPRO = 0
+
+include cmacros.inc
+
+; NOTE: This code is always assembled in real mode, so it'll run on any machine.
+;
+PMODE32=0
+
+include newexe.inc
+include protect.inc
+ifdef WOW
+include vint.inc
+endif
+.list
+
+createSeg _TEXT,CODE,PARA,PUBLIC,CODE
+createSeg STACK,STACK,PARA,STACK,STACK
+
+sBegin STACK
+ DB 128 DUP (?)
+stacktop LABEL BYTE
+sEnd STACK
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,CODE
+
+
+KERNSTUB PROC FAR
+ push cs
+ pop ds
+ mov si,codeOFFSET stacktop
+ add si,1FFh
+ and si,not 1FFh
+ cmp cs:[si].ne_magic,NEMAGIC
+ je @F
+ jmp ksfail
+@@:
+
+ mov ax,ds
+
+ cli
+ mov ss,ax
+ mov sp,si
+ sti
+
+ mov bx,ds:[si].ne_autodata ; Get number of automatic DS
+ dec bx
+ jl ksg11 ; Continue if no DS
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ .errnz 8 - SIZE new_seg
+ add bx,ds:[si].ne_segtab ; DS:BX -> seg. tab. entry for DS
+ mov ax,ds:[si+bx].ns_sector ; Compute paragraph address of DS
+ cmp ds:[si].ne_align,0
+ jne ksg10
+ mov ds:[si].ne_align,NSALIGN ; in DI
+ksg10:
+ mov cx,ds:[si].ne_align ; Convert sectors to paragraphs
+ sub cx,4
+ shl ax,cl
+ mov di,cs ; Add to paragraph address of old
+ sub di,20h ; exe header
+ add di,ax
+ksg11:
+ push cx
+ mov bx,word ptr cs:[si].ne_csip+2 ; Get number of CS
+ dec bx
+ jl ksfail ; Error if no CS
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ .errnz 8 - SIZE new_seg
+ add bx,cs:[si].ne_segtab ; DS:BX -> seg. tab. entry for CS
+ mov ax,cs:[si+bx].ns_sector ; Compute paragraph address of CS
+ mov cx,cs:[si].ne_align ; Convert sectors to paragraphs
+ sub cx,4
+ shl ax,cl
+ pop bx
+
+ mov dx,cs ; Add to paragraph address of old
+ sub dx,20h ; exe header
+ add dx,ax
+ push dx ; Push far address of start proc
+ push word ptr cs:[si].ne_csip
+ mov ds,di ; DS:0 points to automatic DS
+ mov cx,si ; CX = file offset of new header
+ add cx,200h
+ jmp short ksgo
+ org 0A0h
+ksgo:
+
+;!!! The old CS selector should be freed up at some point!
+
+ mov ax, "KO"
+ ret ; FAR return to start proc
+
+ksfail:
+ call ks1
+ DB 'KERNSTUB: Error during boot',13,10,'$'
+ks1: pop dx
+ push cs
+ pop ds ; DS:DX -> error message
+ mov ah,9 ; Print error message
+ int 21h
+ mov ax,4C01h ; Terminate program, exit code = 1
+ int 21h
+
+KERNSTUB ENDP
+
+sEnd CODE
+
+END KERNSTUB
diff --git a/private/mvdm/wow16/kernel31/krnl286.lnk b/private/mvdm/wow16/kernel31/krnl286.lnk
new file mode 100644
index 000000000..5e0da418a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/krnl286.lnk
@@ -0,0 +1,13 @@
+kdata strings stack mapdata layer ldboot dosinit +
+ldfastb 2gmemini ldself int24 diskio 2ginterf +
+intnn i21file i21task i21entry 2protect 2gmoreme +
+2gcompac lhandle 2galloc 2glru 2gmem handle emsmisc +
+winexec ldfile ldaux atom gpfix hmem ldutil module +
+ldheader ld ldcache ldopen ldint userpro ldreloc +
+ldappl ldseg context tasking lstring task ldstack +
+resaux linterf lcompact lalloc ripaux rip gacheck +
+lacheck lddebug rom enable miscapi lzexp error +
+diag wow16cal kthunks wowdeb kdataend
+kernel.exe/align:16/warnfixup/farcall/nopackcode
+kernel.map/map
+/NOD/NOE
diff --git a/private/mvdm/wow16/kernel31/krnl286.rc b/private/mvdm/wow16/kernel31/krnl286.rc
new file mode 100644
index 000000000..779128baf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/krnl286.rc
@@ -0,0 +1,7 @@
+/****************************************************************************/
+/* KRNL286.RC */
+/****************************************************************************/
+
+#define VER_ORIGINALFILENAME_STR "KRNL286.EXE"
+
+#include "kernel.rcv"
diff --git a/private/mvdm/wow16/kernel31/krnl386.lnk b/private/mvdm/wow16/kernel31/krnl386.lnk
new file mode 100644
index 000000000..3fda6c0cf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/krnl386.lnk
@@ -0,0 +1,14 @@
+kdata strings stack mapdata layer ldboot dosinit +
+ldfastb 3gmemini ldself int24 diskio 3ginterf +
+intnn i21file i21task i21entry 3protect 3gmoreme +
+3gcompac lhandle 3galloc 3glru 3gmem handle emsmisc +
+winexec ldfile ldaux atom gpfix hmem ldutil module +
+ldheader ld ldcache ldopen ldint userpro ldreloc +
+ldappl ldseg context tasking lstring task ldstack +
+resaux linterf lcompact lalloc ripaux rip 3gacheck +
+lacheck lddebug rom enable miscapi lzexp error +
+gpcont disasm patch reboot diag wow16cal kthunks +
+wowdeb kdataend
+kernel.exe/align:16/warnfixup/farcall/nopackcode
+kernel.map/map
+/NOD/NOE
diff --git a/private/mvdm/wow16/kernel31/krnl386.rc b/private/mvdm/wow16/kernel31/krnl386.rc
new file mode 100644
index 000000000..e7f943584
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/krnl386.rc
@@ -0,0 +1,7 @@
+/****************************************************************************/
+/* KRNL386.RC */
+/****************************************************************************/
+
+#define VER_ORIGINALFILENAME_STR "KRNL386.EXE"
+
+#include "kernel.rcv"
diff --git a/private/mvdm/wow16/kernel31/krom.inc b/private/mvdm/wow16/kernel31/krom.inc
new file mode 100644
index 000000000..25fa2ac2b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/krom.inc
@@ -0,0 +1,6 @@
+; Kernel / ROM Windows specific include file
+
+
+ROMEXTRASTACKSZ = 2048 ; Extra stack space for kernel
+
+include ..\inc\rom.inc
diff --git a/private/mvdm/wow16/kernel31/ksource.txt b/private/mvdm/wow16/kernel31/ksource.txt
new file mode 100644
index 000000000..57d04e637
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ksource.txt
@@ -0,0 +1,187 @@
+ 3.1 Kernel Directory
+ ====================
+
+ Directorys
+
+[debug2] krnl286.exe debug is built here
+[debug3] krnl386.exe debug is built here
+[debug] kernel.exe debug is built here
+[history] Some dead files
+[reckern] Recording (or swap) kernel is built here
+[retail2] krnl286.exe retail is built here
+[retail3] krnl386.exe retail is built here
+[retail] kernel.exe retail is built here
+
+ Include files
+
+..\inc\cmacros.inc Such a wonderful(!) macro package
+appl.inc* Include file for application loader routines
+pdb.inc* aka PSP definitions
+tdb.inc* Task data block defintions
+eems.inc*
+kernel.inc Half of kernel's definitions
+winkern.inc* The other half.
+..\inc\newexe.inc New exe file, ASM definitions
+newexe.h* New exe file, C definitions
+protect.inc* Protect mode definitions
+kdos.inc*
+krom.inc*
+kernel.h* C version of kernel's definitions
+ Expect this to be out of date!
+
+ Real mode memory manager
+
+gacheck.asm* g*.asm are the real mode memory management
+galloc.asm* files. gacheck.asm and glru.asm are shared
+gcompact.asm* with krnl286.exe.
+ginterf.asm*
+glru.asm*
+gmem.asm*
+gmeminit.asm*
+gmoremem.asm*
+handle.asm* Real mode handle table routines
+protect.asm* Real mode stubs
+
+ 286pmode memory manager
+
+2galloc.asm* 2*.asm are krnl286 memory management files
+2gcompac.asm* the name matches the real mode file with
+2ginterf.asm* '2' prepended.
+2gmem.asm*
+2gmemini.asm*
+2gmoreme.asm*
+2protect.asm*
+
+ 386pmode memory manager
+
+3gacheck.asm* 3*.asm are krnl386 memory management files.
+3galloc.asm*
+3gcompac.asm*
+3ginterf.asm*
+3glru.asm*
+3gmem.asm*
+3gmemini.asm*
+3gmoreme.asm*
+3protect.asm*
+
+ Debugger glue routines
+
+2lddebug.asm* Interface files for the debugger. Also
+3lddebug.asm* include debug output routines.
+lddebug.asm*
+
+
+ EMS support. Mostly dead code here.
+
+emm.asm*
+emmsched.asm*
+emshead.asm*
+emsinit.asm*
+emsmisc.asm*
+newems.asm*
+smartdrv.asm*
+
+
+ Kernel's interrupt hooks
+
+i21entry.asm* i21*.asm are the kernel's DOS call
+i21file.asm* intercept routines.
+i21task.asm*
+int24.asm* The Windows critical error handler
+intnn.asm* Miscallaneous interrupts trapped by kernel
+
+
+ Data and data segment routines
+
+kdata.asm* Kernel's data
+strings.asm Kernel's strings
+kdataend.asm*
+mapdata.asm* DS loading stubs
+
+
+ Linker definitions
+
+kernel.def* Kernel's link definitions
+rom.def*
+kernel.lnk*
+
+
+ Initialisation/Exit code
+
+kernstub.asm* DOS stub to jump to the new exe file
+ldboot.asm Kernel's bootstrap code
+ldfastb.asm* Mostly dead, some ldboot support
+ldself.asm* Loader for Kernel's exe header
+dosinit.asm* Initialisation routines dealing with DOS
+enable.asm Routines to Enable/Disable kernel
+
+
+ Local memory manager files
+
+lacheck.asm*
+lalloc.asm*
+linterf.asm*
+lcompact.asm*
+lhandle.asm*
+
+
+ EXE loader and support
+
+ld.asm* Mostly LoadModule
+ldheader.asm* LoadExeHeader - loads a new exe header
+ldappl.asm* Private loader (Excel 2.x, WinWord) routines
+ldcache.asm* File handle cache and real mode
+ XMS segment cache
+ldaux.asm* Loader support
+ldutil.asm* More loader support
+module.asm* Yet more loader support
+ldfile.asm* LoadNRTable - loader support
+ldseg.asm* LoadSegment and segment allocation routines
+ldreloc.asm* Segment relocation
+checksum.asm* Segment checksum routines
+ldint.asm Segment not present handler and
+ other fault handlers
+resaux.asm* Resource loader
+ldstack.asm* Real mode stack patching routines
+
+
+ Build files
+
+mk.bat* Front end for makefile
+makefile* THE makefile
+
+
+ Miscellaneous Kernel entry points
+
+atom.asm* Atom manager
+diskio.asm* _lopen, _lread etc.
+ldopen.asm* OpenFile
+miscapi.asm* Miscellaneous kernel entry points
+lstring.asm* lstrlen etc.. half dead
+winexec.asm* WinExec()
+
+ Rips
+rip.c* Those lovely beeps and stack traces
+ripaux.asm Support for rips
+
+
+ Scheduler and task management
+
+schedule.asm* Scheduler
+context.asm* Scheduler support
+task.asm* Task management
+
+
+ Really miscellanous routines
+
+rom.asm* ROM stuff
+sft.asm* SFT handling
+stack.asm* Kernel's temporary stack routines
+
+
+ Profile routines
+
+up.c* INI file routines
+userpro.asm* Old INI file routines, mostly dead code
+
+
diff --git a/private/mvdm/wow16/kernel31/kthunks.asm b/private/mvdm/wow16/kernel31/kthunks.asm
new file mode 100644
index 000000000..4462d6994
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/kthunks.asm
@@ -0,0 +1,460 @@
+ TITLE KTHUNKS.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; KTHUNKS.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 02-Apr-1991 Matt Felton (mattfe)
+; Created.
+;
+
+ifndef WINDEBUG
+ KDEBUG = 0
+ WDEBUG = 0
+else
+ KDEBUG = 1
+ WDEBUG = 1
+endif
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ include wow.inc
+ include wowkrn.inc
+ .list
+
+externNP WowFixWin32CurDir
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+; Kernel API thunks
+
+ DKernelThunk Yield,0
+ KernelThunk GetProfileString
+ KernelThunk GetProfileInt
+ KernelThunk GetPrivateProfileString
+ KernelThunk GetPrivateProfileInt
+ KernelThunk RegEnumKey32
+ KernelThunk RegOpenKey32
+ KernelThunk RegCloseKey32
+ KernelThunk RegEnumValue32
+ KernelThunk WriteProfileString
+ KernelThunk WritePrivateProfileString
+ DKernelThunk GetVersionEx
+
+
+
+; Internal WOW Thunks
+
+ DKernelThunk WowInitTask ; Task Creation
+ DKernelThunk WowKillTask,0 ; Task Destruction
+ DKernelThunk WOWFreeResource, %(size FREERESOURCE16)
+ DKernelThunk WowFileRead,%(size FILEIOREAD16)
+ DKernelThunk WowFileWrite,%(size FILEIOWRITE16)
+ DKernelThunk WowFileLSeek,%(size FILEIOLSEEK16)
+ DKernelThunk WowKernelTrace,%(size KERNELTRACE16)
+ DKernelThunk WOWOutputDebugString, %(size OUTPUTDEBUGSTRING16)
+ DKernelThunk WowCursorIconOp
+ DKernelThunk WowFailedExec,0
+ DKernelThunk WowCloseComPort
+ DKernelThunk WowFileOpen,%(size FILEIOOPEN16)
+ DKernelThunk WowFileClose,%(size FILEIOCLOSE16)
+ DKernelThunk WowIsKnownDLL, %(size WOWISKNOWNDLL16)
+ DKernelThunk WowDdeFreeHandle
+ DKernelThunk WowFileGetAttributes,%(size FILEIOGETATTRIBUTES16)
+ DKernelThunk WowFileGetDateTime,%(size FILEIOGETDATETIME16)
+ DKernelThunk WowFileLock,%(size FILEIOLOCK16)
+ DKernelThunk WowFindFirst,%(size WOWFINDFIRST16)
+ DKernelThunk WowFindNext,%(size WOWFINDNEXT16)
+ DKernelThunk WowSetDefaultDrive
+ DKernelThunk WowGetCurrentDirectory
+ DKernelThunk WowSetCurrentDirectory
+ DKernelThunk WowWaitForMsgAndEvent
+ DKernelThunk WowMsgBox
+ DKernelThunk WowGetCurrentDate,0
+ DKernelThunk WowDeviceIOCTL
+ DKernelThunk WowFileSetAttributes
+ DKernelThunk WowFileSetDateTime
+ DKernelThunk WowFileCreate
+ DKernelThunk WowDosWowInit
+ DKernelThunk WowCheckUserGdi
+ DKernelThunk WowPartyByNumber
+ DKernelThunk WowShouldWeSayWin95
+ DKernelThunk GetShortPathName
+ DKernelThunk FindAndReleaseDib
+ DKernelThunk WowReserveHtask
+
+;-----------------------------------------------------------------------;
+; WOWGetNexVdmCommand
+;
+; Returns the Next App Name for the Requested 32 Bit Exec
+;
+; Arguments:
+; FARP lpReturnedString = LPSTR points to the buffer that receives the character strin
+; int nSize = Size of the lpReturnedString buffer
+;
+; Returns:
+; DX:AX = TRUE Success, sting is present
+; DX:AX = NULL, buffer size was not large enough
+;
+; Error Returns:
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Sun Jan 19, 1992 11:00:06a -by- Matthew Felton [MattFe]
+; New API for Multi Tasking Exec by 32 bit app of 16 bit app
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WowGetNextVdmCommand
+
+;-----------------------------------------------------------------------;
+; WowRegisterShellWindowHandle
+;
+; Tells WOW the Windows Handle To Post Messages to For Execing 16 bit
+; apps. (see WOWEXEC and WK32NotifyThread)
+;
+; Arguments:
+; hwndShell = Shell Window Handle
+;
+; Returns:
+; nothing
+;
+; Error Returns:
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; thu mar 19, 1992 11:11:06a -by- Matthew Felton [MattFe]
+; New API for Multi Tasking Exec by 32 bit app of 16 bit app
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WowRegisterShellWindowHandle
+
+;-----------------------------------------------------------------------;
+; WOWLoadModule32
+;
+; Loads a module or creates a new instance of an existing module.
+;
+; Arguments:
+; FARP p = name of module or handle of existing module
+; FARP lpPBlock = Parameter Block to pass to CreateTask
+; HWND hwndWinOldAp = hwnd to send WM_USER to when app exits.
+;
+; Returns:
+; AX = 32 if Successful
+;
+; Error Returns:
+; AX = Error from Win32 LoadModule
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 16-Mar-1991 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWLoadModule
+
+;-----------------------------------------------------------------------;
+; WOWSetIdleHook
+;
+; Calls WK32SetIdleHook For 16 Bit App
+;
+; Arguments:
+; none
+;
+; Returns:
+; AX = 32 if Successful
+;
+; Error Returns:
+; AX = Error from Win32 LoadModule
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 01-Dec-1992 16:30:00 -by- Russ Blake [russbl}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWSetIdleHook,0
+
+;-----------------------------------------------------------------------;
+; WOWQueryPerformanceCounter
+;
+; Calls NTQueryPerformanceCounter For 16 Bit App
+;
+; Arguments:
+; FARP p = name of module or handle of existing module
+; FARP lpPBlock = Parameter Block to pass to CreateTask
+;
+; Returns:
+; AX = 32 if Successful
+;
+; Error Returns:
+; AX = Error from Win32 LoadModule
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 16-Mar-1991 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWQueryPerformanceCounter
+
+;-----------------------------------------------------------------------;
+; WOWGetFastAddress
+;
+; Calls into WOW32 to determine the address of WOWBopEntry on the 32-bit side.
+;
+; Arguments:
+; none
+;
+; Returns:
+; AX = LOWORD of address
+; DX = HIWORD of address
+;
+; Error Returns:
+; AX = 0
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 16-Mar-1991 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWGetFastAddress, 0
+
+ DKernelThunk WOWGetFastCbRetAddress, 0
+ DKernelThunk WOWGetTableOffsets
+
+;-----------------------------------------------------------------------;
+; WOWKillRemoteTask
+;
+; Tells the 32-bit thread to die and save its context so that later remote
+; threads can be created to use this context.
+;
+; Arguments:
+; none
+;
+; Returns:
+; Nothing
+;
+; Error Returns:
+; AX = 0
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 16-Mar-1991 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWKillRemoteTask
+
+;-----------------------------------------------------------------------;
+; WOWNotifyWOW32
+;
+; Tells the 32-bit world some cool stuff about the 16-bit world.
+;
+; Arguments:
+; none
+;
+; Returns:
+; Nothing
+;
+; Error Returns:
+; AX = 0
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; Calls:
+;
+; History:
+; Mon 16-Mar-1991 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+
+ DKernelThunk WOWNotifyWOW32
+
+ DKernelThunk KSYSERRORBOX
+
+ DKernelThunk WOWDelFile, %(size WOWDelFile16)
+ DKernelThunk VirtualAlloc
+ DKernelThunk VirtualFree
+; DKernelThunk VirtualLock Unused
+; DKernelThunk VirtualUnlock Unused
+ DKernelThunk GlobalMemoryStatus
+ DKernelThunk GetDriveType
+ DKernelThunk LoadLibraryEx32W, %(size LOADLIBRARYEX32)
+ DKernelThunk FreeLibrary32W, %(size FREELIBRARY32)
+ DKernelThunk GetProcAddress32W,%(size GETPROCADDRESS32)
+ DKernelThunk GetVDMPointer32W, %(size GETVDMPOINTER32)
+ DKernelThunk ICallProc32W,0
+
+; These Thunks Shouldn't be Called - They are Thunked to Trap Them.
+
+; DKernelThunk GetTaskQueueES
+; DKernelThunk GetTaskQueueDS
+ DKernelThunk PostEvent
+; DKernelThunk IsTaskLocked
+; DKernelThunk IsWinOldApTask
+ DKernelThunk WaitEvent
+ DKernelThunk OldYield,0
+; DKernelThunk GetTaskQueue
+ DKernelThunk SetPriority
+; DKernelThunk SetTaskQueue
+ DKernelThunk DirectedYield
+ DKernelThunk LockCurrentTask
+ DKernelThunk WriteOutProfiles,0
+
+;
+; ExitKernel is small wrapper which takes exit status in AX and pushes it
+; for the convenience of ExitKernelThunk, a regular WOW stack-based thunk.
+; The FUN_ aliasing below allows us to generate the thunk with the name
+; ExitKernelThunk while using the arguments and thunk table entry already
+; set up for ExitKernel.
+;
+
+ FUN_ExitKernelThunk equ FUN_ExitKernel
+ DKernelThunk ExitKernelThunk, %(size EXITKERNEL16)
+
+; FatalExitC is called by FatalExit and takes the same one word parameter
+; indicating fatalexit code.
+
+ FUN_FatalExitC equ FUN_FatalExit
+ DKernelThunk FatalExitC, %(size FATALEXIT16)
+
+; Thunk for WowGetModuleFileName reuses the GetModuleFileName slot.
+
+ FUN_WowGetModuleFileName equ FUN_GetModuleFileName
+ DKernelThunk WowGetModuleFileName, %(size GetModuleFileName16)
+
+; Thunk for WowGetModuleHandle reuses the GetModuleHandle slot.
+
+ FUN_WowGetModuleHandle equ FUN_GetModuleHandle
+ DKernelThunk WowGetModuleHandle
+
+
+
+
+
+;-----------------------------------------------------------------------;
+; CallProc32W
+;
+; Generic Thunk Routine
+; Transitions to 32 bits and calls specified routine
+;
+; Arguments:
+; Variable number of Parameters for function they want to call
+; up to 32.
+;
+; DWORD fAddressConvert - Bit Field, for 16:16 address Convertion
+; eg (bit 1 means convert parameter 1 from 16:16
+; to flat address before calling routine)
+; DWORD cParams - Number of DWORD parameters (so we can clean the stack
+; and so 32 bit land know how many params to copy to
+; 32 bit stack before call.
+; DWORD lpProcAddress - 32 bit native address to call (use LoadLibraryEx32W
+; and GetProcAddress32W to figure this out).
+;
+; Returns:
+; What ever the API returned on 32 bit side in AX:DX
+;
+; Error Returns:
+; AX = 0, more than 32 parameters.
+;
+; Registers Preserved:
+; Registers Destroyed:
+;
+; History:
+; Mon 12-Mar-1993 14:19:04 -by- Matthew Felton [mattfe}
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CallProc32W,<PUBLIC,FAR>
+; PARMD cParams
+cBegin nogen
+ push bp
+ mov bp,sp
+
+ ; Disable CDECL source bit
+ and word ptr [bp+8],NOT CPEX32_SOURCE_CDECL
+
+ cCall ICallProc32W
+
+; Clean Up Callers Stack to remove Parameters Passed
+
+ mov bx, WORD PTR [bp+6] ; get the # of DWORDS this API took
+ shl bx, 2 ; convert it to offset into aRets table
+ add bx, codeoffset aRets
+ pop bp
+ jmp bx ; dispatch to the right RETF n
+
+CRETENTRIES equ 020h
+; generate the retf n codetable
+
+ bytes = 0
+ REPT CRETENTRIES
+ IFE bytes
+aRets:
+ ENDIF
+ retf bytes + 4*3 ; 4*3 - Always
+ nop
+ bytes = bytes + 4
+ ENDM
+
+cEnd
+
+ public _CallProcEx32W
+
+_CallProcEx32W PROC FAR
+ push bp
+ mov bp,sp
+
+ ; Enable CDECL source bit
+ or word ptr [bp+8],CPEX32_SOURCE_CDECL
+
+ cCall ICallProc32W
+
+ pop bp
+ ret
+_CallProcEx32W ENDP
+
+ ; get the address of the array containing the selector bases
+ DKernelThunk WOWGetFlatAddressArray, 0
+
+sEnd CODE
+
+end
+
diff --git a/private/mvdm/wow16/kernel31/lacheck.asm b/private/mvdm/wow16/kernel31/lacheck.asm
new file mode 100644
index 000000000..d448623a1
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lacheck.asm
@@ -0,0 +1,258 @@
+
+
+.xlist
+include kernel.inc
+include gpfix.inc
+.list
+
+externW pLocalHeap
+
+DataBegin
+
+externB kernel_flags
+;externW MyCSDS
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+if KDEBUG
+
+;-----------------------------------------------------------------------;
+; CheckLocalHeap ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Jan 01, 1980 10:58:28p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly. ;
+;-----------------------------------------------------------------------;
+
+cProc CheckLocalHeap,<PUBLIC,NEAR>,<di,si>
+
+ localW nrefhandles
+ localW nhandles
+ localW nfreehandles
+ localW nusedhandles
+ localW ndishandles
+ localW pbottom
+
+cBegin
+ beg_fault_trap clh_trap
+ xor di,di
+ xor dx,dx ; For error codes.
+ mov bx,[di].pLocalHeap
+ or bx,bx
+ jnz have_a_heap
+ jmp clh_ret
+have_a_heap:
+
+ cmp di,[bx].hi_check
+ jnz do_heap_check
+ jmp clh_ret
+do_heap_check:
+
+ mov cx,[bx].hi_count
+ mov si,[bx].hi_first
+ test [si].la_prev,LA_BUSY
+ jnz first_should_be_busy
+ or dx,1 ; Forward links invalid.
+first_should_be_busy:
+
+check_forward_links:
+ mov ax,[si].la_next
+ cmp ax,si
+ jbe end_of_line
+ mov si,ax
+ loop check_forward_links
+end_of_line:
+
+ cmp ax,[bx].hi_last
+ jnz forward_bad
+ cmp cx,1
+ jz forward_good
+; jcxz forward_good
+forward_bad:
+ or dx,1 ; Forward links invalid.
+forward_good:
+
+ mov cx,[bx].hi_count
+ mov si,[bx].hi_last
+ test [si].la_prev,LA_BUSY
+ jnz last_should_be_busy
+ or dx,2 ; Backward links invalid.
+last_should_be_busy:
+
+check_backward_links:
+ mov ax,[si].la_prev
+ and ax,0FFFCh
+ cmp ax,si
+ jae begin_of_line
+ mov si,ax
+ loop check_backward_links
+begin_of_line:
+
+ cmp ax,[bx].hi_first
+ jnz backward_bad
+ cmp cx,1
+ jz backward_good
+; jcxz backward_good
+backward_bad:
+ or dx,2 ; Backward links invalid.
+backward_good:
+
+ mov cx,[bx].hi_count
+ mov si,[bx].hi_first
+ mov nrefhandles,0
+count_referenced_handles:
+ test [si].la_prev,LA_BUSY
+ jz no_handle
+ test [si].la_prev,LA_MOVEABLE
+ jz no_handle
+ mov di,[si].la_handle
+ cmp [di].lhe_free,LHE_FREEHANDLE
+ jnz handle_not_free
+ or dx,4 ; Block points to free handle.
+ jmps no_handle
+handle_not_free:
+ mov ax,si
+ add ax,SIZE LocalArena
+ cmp ax,[di].lhe_address
+ jz handle_points_back
+ or dx,8 ; Block -> handle but not vice versa
+ jmps no_handle
+handle_points_back:
+ inc nrefhandles
+no_handle:
+ mov si,[si].la_next
+ loop count_referenced_handles
+
+ mov di,[bx].hi_htable
+ mov nhandles,0
+ mov ndishandles,0
+ mov nusedhandles,0
+ mov nfreehandles,0
+
+handle_block_loop:
+ or di,di
+ jz no_more_handle_blocks
+ lea si,[di].ht_entry[0]
+ mov cx,[di].ht_count
+ add nhandles,cx
+
+handle_entry_loop:
+ jcxz next_handle_block
+ dec cx
+ cmp [si].lhe_free,LHE_FREEHANDLE
+ jnz not_free
+ inc nfreehandles
+ jmps next_handle_entry
+not_free:
+ test [si].lhe_flags,LHE_DISCARDED
+ jz not_discarded
+ inc ndishandles
+ jmps next_handle_entry
+not_discarded:
+ inc nusedhandles
+next_handle_entry:
+ add si,SIZE LocalHandleEntry
+ jmp handle_entry_loop
+next_handle_block:
+ mov di,[si].lhe_address
+ jmp handle_block_loop
+
+no_more_handle_blocks:
+
+ mov ax,nusedhandles
+ cmp ax,nrefhandles
+ jz handles_match
+ or dx,10h ; allocated handles != used handles
+handles_match:
+ add ax,nfreehandles
+ add ax,ndishandles
+ cmp ax,nhandles
+ jz total_number_okay
+ or dx,20h ; total number of handles dont add up
+total_number_okay:
+
+ xor cx,cx
+ mov si,[bx].hi_hfree
+count_free:
+ or si,si
+ jz counted_free
+ inc cx
+ mov si,[si].lhe_link
+ jmp count_free
+counted_free:
+ cmp cx,nfreehandles
+ jz free_add_up
+ or dx,40h ; total # of free handles dont add up
+free_add_up:
+
+; now check the free block list
+
+ mov si,[bx].hi_first
+ mov si,[si].la_free_next ; Sentinals not free.
+ mov ax,[bx].hi_last
+ mov pbottom,ax
+
+check_free_list:
+ cmp si,[si].la_free_next
+ jz check_free_list_done
+ mov ax,[si].la_next
+ sub ax,si
+ cmp ax,[si].la_size
+ jnz free_list_corrupted ; invalid block size
+
+ cmp [bx].hi_check,2 ; if hi_check >= 2, check free.
+ jb dont_check_free
+
+ mov di,si
+ add di,SIZE LocalArenaFree
+ mov cx,[si].la_next
+ sub cx,di
+ mov al,DBGFILL_FREE
+ smov es,ds
+ repz scasb
+ jnz free_list_corrupted ; free block corrupted
+dont_check_free:
+ mov ax,[si].la_free_next
+ cmp ax,si
+ jbe free_list_corrupted
+ mov si,ax
+ cmp ax,pbottom
+ jbe check_free_list
+
+free_list_corrupted:
+ krDebugOut DEB_FERROR, "Local free memory overwritten at #ES:#DI"
+ or dx,80h
+
+ end_fault_trap
+
+check_free_list_done:
+clh_ret:
+ mov ax,dx
+cEnd
+clh_trap:
+ fault_fix_stack
+ mov dx, 80h
+ jmp clh_ret
+
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/lalloc.asm b/private/mvdm/wow16/kernel31/lalloc.asm
new file mode 100644
index 000000000..1e4040d77
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lalloc.asm
@@ -0,0 +1,835 @@
+ TITLE LALLOC - Local memory allocator
+
+include kernel.inc
+
+.errnz la_prev ; This code assumes la_prev = 0
+
+externW pLocalHeap
+
+DataBegin
+
+externB Kernel_flags
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP lalign ; LINTERF.ASM
+externNP lnotify ; LINTERF.ASM
+externNP lcompact ; LCOMPACT.ASM
+
+if KDEBUG
+externNP CheckLAllocBreak ; LINTERF.ASM
+endif
+
+;-----------------------------------------------------------------------;
+; ljoin ;
+; ;
+; Join two blocks together, by removing one. ;
+; ;
+; Arguments: ;
+; BX = address of block to remove ;
+; SI = address of block that points to the one to remove ;
+; ;
+; Returns: ;
+; BX = address of block following [SI], after join ;
+; Updated hi_count field in the local arena info structure ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+; Added free list stuff. ;
+; ;
+; Tue Oct 14, 1986 05:20:56p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ljoin,<PUBLIC,NEAR>
+cBegin nogen
+
+ IncLocalStat ls_ljoin
+
+ push di
+ dec [di].hi_count ; remove free block from arena
+ mov di,bx ; save ptr to block removing
+ mov bx,[bx].la_next ; Get address of block after
+ and [bx].la_prev,LA_ALIGN ; one we are removing.
+ or [bx].la_prev,si ; Change it's back link
+ mov [si].la_next,bx ; and change the forward link
+
+; If it is free, remove the block at [DI] from the free list
+
+ test [di].la_prev,LA_BUSY
+ jnz join1
+ xchg bx,di
+ call lfreedelete ; delete from free list
+ xchg bx,di
+join1:
+
+; if the block at [SI] is free, set its new larger free block
+; size. If not free, then block at [DI] is about to become part
+; of the previous busy block.
+
+ test [si].la_prev,LA_BUSY ; is it busy?
+ jnz joinexit ; yes
+
+ push ax
+ mov ax,bx
+ sub ax,si ; length of new free block
+ mov [si].la_size,ax
+ pop ax
+
+if KDEBUG
+
+; Fill new free block with DBGFILL_ALLOC
+
+ xchg si,bx
+ call lfillCC
+ xchg si,bx
+endif
+
+joinexit:
+ pop di
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lrepsetup ;
+; ;
+; Sets up for a block store or move of words. ;
+; ;
+; Arguments: ;
+; CX = #bytes ;
+; ;
+; Returns: ;
+; CX = #words ;
+; ES = DS ;
+; DF = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 05:23:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lrepsetup,<PUBLIC,NEAR>
+cBegin nogen
+ shr cx,1
+ push ds
+ pop es
+ cld
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lzero ;
+; ;
+; Fills a block with zeros. ;
+; ;
+; Arguments: ;
+; BX = address of last word +1 to zero ;
+; CX = address of first word to zero ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 05:25:30p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lzero,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ mov di,cx ; DI = destination
+ sub cx,bx ; CX = - #bytes
+ jae zero1 ; Do nothing if BX less than or equal to CX
+ push ax
+ neg cx
+ xor ax,ax
+ call lrepsetup ; Setup for stosw
+ rep stosw ; Zero it out
+ pop ax
+zero1:
+ pop di
+ ret
+cEnd nogen
+
+
+if KDEBUG
+;-----------------------------------------------------------------------;
+; lallocfill ;
+; ;
+; Fills a block with DBGFILL_ALLOC ;
+; ;
+; Arguments: ;
+; BX = address of last word +1 to zero ;
+; CX = address of first word to zero ;
+; ;
+; Registers Destroyed: ;
+; CX,ES ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc lallocfill,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ mov di,cx ; DI = destination
+ sub cx,bx ; CX = - #bytes
+ jae @F ; Do nothing if BX less than or equal to CX
+ push ax
+ neg cx
+ mov ax,(DBGFILL_ALLOC or (DBGFILL_ALLOC shl 8))
+ call lrepsetup ; Setup for stosw
+ rep stosw ; Zero it out
+ pop ax
+@@:
+ pop di
+ ret
+cEnd nogen
+
+endif ;KDEBUG
+
+;-----------------------------------------------------------------------;
+; lalloc ;
+; ;
+; Actually allocates a local object. Called from within the local ;
+; memory manager's critical section. ;
+; ;
+; Arguments: ;
+; AX = allocations flags ;
+; BX = #bytes ;
+; DI = address of local arena information structure ;
+; ;
+; Returns: ;
+; AX = data address of block allocated or NULL ;
+; DX = allocation flags or size of largest free block ;
+; if AX = 0 ;
+; ZF = 1 if AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1986 -by- Bob Gunderson (bobgu) ;
+; Changed the search algorithm to use the free list and added calls ;
+; to add/remove blocks from the free list ;
+; ;
+; Tue Oct 14, 1986 05:27:40p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lalloc,<PUBLIC,NEAR>
+cBegin nogen
+
+if KDEBUG
+ call CheckLAllocBreak
+ jnc @F
+ xor ax,ax
+ ret
+@@:
+endif
+
+ push si
+ push ax
+ push bx
+ test al,LA_MOVEABLE ; Moveable?
+; jnz scanbwd ; Yes, search backwards
+ jz @F
+ jmp scanbwd
+@@:
+ IncLocalStat ls_falloc
+ add bx,la_fixedsize ; Room for fixed header
+ call lalign ; Get requested size in DX
+ mov bx,[di].hi_first ; No, start with first entry
+
+; use free list to find a block to allocate
+afwdloop:
+ mov ax,[bx].la_free_next ; get next free block
+ cmp ax,bx ; are we at end of arena ?
+ jz afwdcmp ; yes try to compact....
+
+ IncLocalStat ls_fexamine
+ mov bx,ax
+ cmp dx,[bx].la_size ; is it big enough?
+ ja afwdloop ; no, loop for next
+
+; Here when we have a block big enough.
+; BX = address of block
+; DX = requested size, including fixed header
+
+afwdfound:
+
+if KDEBUG
+
+; verify the block is filled with DBGFILL_FREE
+
+ call lcheckCC
+ jz afwdfound1 ; all OK
+ kerror ERR_LMEM,<LocalAlloc: Local free memory overwritten>
+afwdfound1:
+
+endif
+
+ IncLocalStat ls_ffound
+ mov ax,la_fixedsize
+ mov cx,[bx].la_next ; mov cx,[bx].la_next
+ sub cx,LA_MINBLOCKSIZE ; CX = as low as we will go for free
+ mov si,bx ; Calculate address of new block
+ add si,dx ; (current block + requested size)
+ cmp si,cx ; Is it past the current next block
+;;;;;;; jae aexit1 ; yes, use the whole block
+ jb afwdfound2
+ jmp aexit1
+afwdfound2:
+
+; Here with two blocks.
+; BX = address of existing block
+; SI = address of new block to add to arena as free space
+
+ IncLocalStat ls_ffoundne
+ push bx
+ jmp aexit
+
+
+afwdcmp:
+ IncLocalStat ls_fcompact
+ call lcompact ; End of arena. Try compacting.
+ cmp ax,dx ; Room for requested size?
+ jae afwdfound ; Yes, exit search loop
+afail: ; No, fail.
+ push ax ; Remember size of largest free block
+ xor bx,bx
+ .errnz LN_OUTOFMEM ; Notify client procedure
+ xchg ax,bx ; BX = size of largest free block
+ mov cx,dx ; CX = size we are looking for
+ call lnotify
+ pop dx ; DX = size of largest free block
+ pop bx ; BX = requested size
+ pop ax ; AX = flags
+ pop si ; Restore SI
+; jnz lalloc ; Try again if notify procedure said to
+ jz @F
+ jmp lalloc
+@@:
+ IncLocalStat ls_fail
+ xor ax,ax ; O.W. return zero, with Z flag set
+ ret
+
+
+scanbwd:
+ IncLocalStat ls_malloc
+ add bx,SIZE LocalArena ; Room for moveable header
+ call lalign ; Get requested size in DX
+ mov bx,[di].hi_last
+
+; use free chain to find a block to aloocate
+
+abwdloop:
+ IncLocalStat ls_mexamine
+ mov ax,[bx].la_free_prev ; previous free block
+ cmp ax,bx ; are we at beginning of arena ?
+ jz abwdcmp ; yes try to compact....
+
+ mov bx,ax
+ cmp dx,[bx].la_size ; Room for requested size?
+ ja abwdloop ; no, loop to previous free block
+ jmps abwdfound ; yes, alloocate the memory
+
+; Beginning of arena. Try compacting. If that fails then too bad
+
+abwdcmp:
+ IncLocalStat ls_mcompact
+ call lcompact
+ cmp ax,dx ; Room for requested size?
+ jb afail ; No, fail
+ mov si,ax ; Yes, get free size in SI
+
+abwdfound:
+
+if KDEBUG
+
+; verify the block is filled with DBGFILL_FREE
+
+ call lcheckCC
+ jz abwdfound1 ; all OK
+ kerror ERR_LMEM,<LocalAlloc: Local free memory overwritten>
+abwdfound1:
+endif
+
+ IncLocalStat ls_mfound
+ mov ax,SIZE LocalArena
+ mov si,[bx].la_size ; size of block found
+ sub si,dx ; SI = size of free block = total size
+ ; less requested size (includes header)
+ mov cx,si ; save what's left over
+ add si,bx ; SI = address of new block
+ cmp cx,LA_MINBLOCKSIZE ; enough room for another?
+ jb aexit1 ; no, use entire block
+ push si
+
+ IncLocalStat ls_mfoundne
+
+; Here with two blocks, in following order
+; BX = address of existing free block to make smaller
+; SI = address of new block to add to arena as busy
+; CX = address of block after new block
+
+aexit:
+ mov cx,si
+ xchg [bx].la_next,cx
+ mov [si].la_prev,bx
+ mov [si].la_next,cx
+
+; Here with allocated block
+; BX = address of found block
+; SI = address of new block after found block
+; CX = address of block after new block
+
+ xchg si,cx ; SI = block after new block
+ and [si].la_prev,LA_ALIGN ; CX = new block
+ or [si].la_prev,cx ; Point to new block
+ inc [di].hi_count ; We added an arena entry
+ mov si,bx ; SI = previous free block
+ mov bx,cx ; BX = new block after found block
+ call lfreeadd ; add this new block to free list
+ sub bx,si
+ mov [si].la_size,bx ; set new free block size
+ pop bx ; BX = block we are allocating
+
+aexit1:
+ call lfreedelete ; remove this block from free list
+ add ax,bx
+ or byte ptr [bx].la_prev,LA_BUSY ; Mark block as busy
+ pop dx ; Flush requested size
+ pop dx ; Restore flags
+if KDEBUG
+ test dl,LA_ZEROINIT
+ jnz @F
+ mov cx,ax
+ mov bx,[bx].la_next
+ call lallocfill
+ jmp short aexit2
+@@:
+endif
+ test dl,LA_ZEROINIT ; Want it zeroed?
+ jz aexit2 ; No, all done
+ mov cx,ax ; Yes, CX = 1st word to zero
+ mov bx,[bx].la_next ; BX = last word+1 to zero
+ call lzero ; Zero them
+aexit2:
+ pop si
+ or ax,ax ; Return AX points to client portion
+ ret ; of block allocated or zero
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lfree ;
+; ;
+; Marks a block as free, coalescing it with any free blocks before ;
+; or after it. ;
+; ;
+; Arguments: ;
+; BX = block to mark as free. ;
+; DI = address of local arena information structure ;
+; ;
+; Returns: ;
+; SI = 0 if freed a fixed block. ;
+; SI = handle table entry, for moveable blocks. ;
+; ZF =1 if SI = 0 ;
+; Updated hi_count field in local arena information structure ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+; Freed blocks are placed back on the free list ;
+; ;
+; Tue Oct 14, 1986 05:31:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lfree,<PUBLIC,NEAR>
+cBegin nogen
+ mov si,bx
+ or si,si
+ jz free4
+ push dx
+
+ push [bx].la_handle ; push possible handle
+
+; Add block to free list
+
+ push si
+ xor si,si
+ call lfreeadd ; add this block to free list
+ pop si
+
+; Clear any existing LA_BUSY and LA_MOVEABLE bits
+
+ mov dx,LA_BUSY + LA_MOVEABLE
+ and dx,[bx].la_prev
+ xor [bx].la_prev,dx
+ and dl,LA_MOVEABLE ; Moveable?
+ pop dx ; restore handle
+ jnz free1 ; Yes, return handle in DX
+ xor dx,dx ; No, return 0 in DX
+free1:
+ mov si,[bx].la_next ; SI = next block
+ test byte ptr [si].la_prev,LA_BUSY ; Is it free?
+ jnz free2 ; No, continue
+ xchg bx,si
+ call ljoin ; Yes, coelesce with block in BX
+ mov bx,si
+free2:
+ mov si,[bx].la_prev ; SI = previous block
+ test byte ptr [si].la_prev,LA_BUSY ; Is it free?
+ jnz free3 ; No, continue
+ call ljoin ; Yes, coelesce with block in BX
+free3:
+ mov si,dx ; Return 0 or handle in BX
+ pop dx ; restore DX
+free4:
+ or si,si ; Set Z flag if SI = zero
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; lfreeadd ;
+; ;
+; Links a block onto the free block chain. This routine assumes that ;
+; the block to add already has the la_next and la_prev fields set ;
+; to their proper values. An extended free block header is written ;
+; into the block. ;
+; ;
+; Arguments: ;
+; BX = Address of block to add to free list ;
+; SI = 0 to search for insertion point, else contins the address ;
+; of the previous free block. ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All are preserved ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+;Initail version ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lfreeadd,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ push di
+ push ax
+ push cx
+
+ or si,si ; need to search for insertion point?
+ jnz lfa1 ; no
+
+; We first need to find the previous free block so that we can insert this
+; block into the proper place.
+
+ mov si,ds:pLocalHeap ; get local arena info block address
+
+if KDEBUG
+
+; Range check the insertion point
+
+ cmp bx,[si].hi_first
+ jb lfadie
+ cmp bx,[si].hi_last
+ jb lfaok
+lfadie:
+ kerror ERR_LMEM,<lfreeadd : Invalid local heap>
+lfaok:
+endif
+
+ mov si,[si].hi_first ; get first block address (free list header)
+lfaloop:
+ mov ax,[si].la_free_next ; get address of next free block
+ cmp bx,ax ; will next block be past new block?
+ jb lfa1 ; yes, DI contains block to insert AFTER
+ mov si,ax
+ jmp lfaloop ; loop on next block
+
+; At this point, BX = block to insert, SI = block to insert after
+
+lfa1:
+ mov di,[si].la_free_next ; get next free block
+ mov [bx].la_free_next,di ;
+ mov [si].la_free_next,bx ; set new next block
+
+ mov [bx].la_free_prev,si ; set new previous block
+ mov [di].la_free_prev,bx ; ditto
+
+ mov ax,[bx].la_next ; next block (not necessarily free)
+ sub ax,bx
+ mov [bx].la_size,ax ; set the size of this block
+
+if KDEBUG
+
+; now fill the new free block with DBGFILL_ALLOC
+
+ call lfillCC
+endif
+
+ pop cx
+ pop ax
+ pop di
+ pop si
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; lfreedelete ;
+; ;
+; Removes a specified block from the free list. This routine assums ;
+; that the specified block is indeed on the free list ;
+; ;
+; Arguments: ;
+; BX = Address of block to remove from the free list ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All are preserved ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+;Initail version ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lfreedelete,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ push si
+
+ mov di,[bx].la_free_prev
+ mov si,[bx].la_free_next
+
+ mov [di].la_free_next,si
+ mov [si].la_free_prev,di
+
+ pop si
+ pop di
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; lfillCC ;
+; ;
+; Fills all the bytes in the specified block with DBGFILL_FREE ;
+; ;
+; Arguments: ;
+; BX = Address of block to fill ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All are preserved ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+;Initail version ;
+;-----------------------------------------------------------------------;
+
+if KDEBUG
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lfillCC,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ push cx
+ push ax
+
+; if heap free checking is off, don't fill the block.
+
+ mov di,pLocalHeap
+ cmp [di].hi_check,2 ; 2 -> checkfree
+ jb fillexit
+
+ lea di,[bx].la_freefixedsize
+ mov cx,[bx].la_next
+ cmp cx,bx ; marker block ?
+ jz fillexit
+ sub cx,di
+ mov al,DBGFILL_FREE
+ push ds
+ pop es
+ cld
+ rep stosb
+
+fillexit:
+ pop ax
+ pop cx
+ pop di
+ ret
+cEnd nogen
+
+endif
+
+
+;-----------------------------------------------------------------------;
+; lcheckCC ;
+; ;
+; checks all bytes in the specified block for the value DBGFILL_FREE ;
+; ;
+; Arguments: ;
+; BX = Address of block to check ;
+; ;
+; Returns: ;
+; ZF = 0 if block does not contain all 0CCh values, else ZF = 1 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All are preserved ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon March 9, 1987 -by- Bob Gunderson (bobgu) ;
+;Initail version ;
+;-----------------------------------------------------------------------;
+
+if KDEBUG
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc lcheckCC,<PUBLIC,NEAR>
+cBegin nogen
+ push si
+ push cx
+ push ax
+
+; if heap checking is off, don't check the block
+
+ mov si,pLocalHeap
+ xor cx,cx ; cx == 0 for ok return
+ cmp [si].hi_check,2
+ jb testexit
+
+ lea si,[bx].la_freefixedsize
+ mov cx,[bx].la_next
+ cmp cx,bx ; sentinel block ?
+ jz testexit2 ; yes: return ZF = 1 for success
+ sub cx,si
+ push ds
+ pop es
+ cld
+testloop:
+ lodsb
+ cmp al,DBGFILL_FREE
+ loope testloop
+
+testexit:
+ or cx,cx ; ZF = 1 if ok, ZF = 0 if failed test
+testexit2:
+ pop ax
+ pop cx
+ pop si
+ ret
+cEnd nogen
+
+endif
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/layer.asm b/private/mvdm/wow16/kernel31/layer.asm
new file mode 100644
index 000000000..b3532b5a9
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/layer.asm
@@ -0,0 +1,28 @@
+ title LAYER.ASM - Parameter validation layer
+
+.xlist
+
+ifdef WINDEBUG
+DEBUG equ <1>
+endif
+
+PMODE equ <1>
+
+include gpfix.inc
+include klayer.inc
+
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+
+.list
+
+LAYER_START
+
+include kernel.api
+
+LAYER_END
+
+LAYER_EXPAND TEXT
+LAYER_EXPAND NRESTEXT
+LAYER_EXPAND MISCTEXT
+
+end
diff --git a/private/mvdm/wow16/kernel31/lcompact.asm b/private/mvdm/wow16/kernel31/lcompact.asm
new file mode 100644
index 000000000..221a3076d
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lcompact.asm
@@ -0,0 +1,851 @@
+ TITLE LCOMPACT - Local memory allocator, compaction procedures
+
+include kernel.inc
+
+errnz la_prev ; This code assumes la_prev = 0
+
+sBegin CODE
+assumes CS,CODE
+
+; These are all the external subroutines needed by this source file.
+;
+externNP <henum> ; HANDLE.ASM
+externNP <ljoin,lfree,lfreeadd,lfreedelete> ; LALLOC.ASM
+externNP <lnotify,lalign> ; LINTERF.ASM
+externFP <GlobalHandle, GlobalRealloc>
+;externFP <LocalHeapSize>
+
+; These are all of the internal subroutines defined in this source file.
+;
+ PUBLIC lmove, lbestfit, lcompact
+
+;-----------------------------------------------------------------------;
+; lmove ;
+; ;
+; Moves a moveable block into the top part of a free block. ;
+; ;
+; Arguments: ;
+; BX = address of free block ;
+; SI = address of busy block to move ;
+; ;
+; Returns: ;
+; SI = old busy address (new free block) ;
+; DI = new busy address ;
+; BX = old free block ;
+; AX = block after old free block ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 06:22:28p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lmove,<PUBLIC,NEAR>
+cBegin nogen
+ mov cx,[si].la_next ; Calculate #bytes in busy block
+ sub cx,si
+
+ add si,cx ; SI = bottom of busy block
+ mov di,[bx].la_next ; DI = bottom of free block
+ cmp si,bx ; Are the busy and free blocks adjacent?
+ je move1 ; Yes, always room for free header
+ mov ax,di ; Calculate the new busy block location
+ sub ax,cx
+ sub ax,LA_MINBLOCKSIZE ; See if there is room for two blocks
+ cmp ax,bx ; in this free block
+ jae move1 ; Yes, continue
+ mov ax,di ; No, AX = block after free block
+ mov di,bx ; New busy block will replace free block
+ add di,cx ; with some extra slop at end
+ jmp short move2
+move1:
+ mov ax,di ; AX = block after free block
+move2:
+ dec si ; Predecrement for moving backwards
+ dec si ; on bogus Intel hardware
+ dec di
+ dec di
+ shr cx,1 ; Move words
+ push ds ; Initialize for rep movsw
+ pop es
+ std ; Move down as may overlap
+ rep movsw
+ cld ; Don't hose careless ones
+ inc si ; More bogosity.
+ inc si ; SI = old busy address (new free block)
+ inc di ; DI = new busy address
+ inc di ; BX = old free block
+movex: ; AX = block after old free block
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lbestfit ;
+; ;
+; Searches backwards for the largest moveable block that will fit ;
+; in the passed free block. ;
+; ;
+; Arguments: ;
+; BX = free block ;
+; CX = #arena entries left to examine ;
+; ;
+; Returns: ;
+; SI = address of moveable block or zero ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 06:25:46p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc lbestfit,<PUBLIC,NEAR>
+cBegin nogen
+ push bx
+ push cx
+ push dx
+ xor si,si ; Have not found anything yet
+ push si
+ mov dx,[bx].la_next ; Compute max size to look for
+ sub dx,bx
+bfloop:
+ mov ax,[bx].la_prev ; Get previous block pointer
+ test al,LA_BUSY ; Is this block busy?
+ jz bfnext ; No, continue
+ test al,LA_MOVEABLE ; Is this block moveable?
+ jz bfnext ; No, continue
+ mov si,[bx].la_handle ; Yes, is this block locked?
+ cmp [si].lhe_count,0
+ jne bfnext ; No, continue
+ mov ax,[bx].la_next ; Yes, compute size of this moveable block
+ sub ax,bx ; Compare to size of free block
+ cmp ax,dx ; Is it bigger?
+ ja bf2 ; Yes, continue
+ pop si ; No, Recover largest block so far
+ or si,si ; First time?
+ jz bf0 ; Yes, special case
+ add ax,si ; No, is this block better than
+ cmp ax,[si].la_next ; ...the best so far?
+ jbe bf1 ; No, continue
+bf0: mov si,bx ; Yes, remember biggest block
+bf1: push si ; Save largest block so far
+bf2: mov ax,[bx].la_prev ; Skip past this block
+bfnext:
+ and al,LA_MASK
+ mov bx,ax
+ loop bfloop
+bfexit:
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lcompact ;
+; ;
+; Compacts the local heap. ;
+; ;
+; Arguments: ;
+; DX = minimum #contiguous bytes needed ;
+; DI = address of local heap information ;
+; ;
+; Returns: ;
+; AX = size of largest contiguous free block ;
+; BX = arena header of largest contiguous free block ;
+; DX = minimum #contiguous bytes needed ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,SI,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed March 11, 1987 -by- Bob Gunderson [bobgu] ;
+; Added code to maintain free list while compacting. ;
+; ;
+; Tue Oct 14, 1986 06:27:37p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lcompact,<PUBLIC,NEAR>
+cBegin nogen
+x = LHE_DISCARDABLE+1
+x = x shl 8
+x = x or 1
+ IncLocalStat ls_lcompact
+ push si
+ mov word ptr [di].hi_ncompact,x
+ errnz <hi_ncompact-hi_dislevel+1>
+ cmp [di].hi_freeze,0 ; Is the heap frozen?
+ je compact1 ; No, continue
+ dec [di].hi_ncompact ; Yes, prevent discarding
+compact1:
+ IncLocalStat ls_cloop
+ push dx ; Save what we are looking for
+ xor ax,ax ; Haven't found a free block yet
+ push ax ; Remember what we have found here
+ mov bx,[di].hi_last ; Start at end of arena
+ mov cx,[di].hi_count
+; Loop to find the next free block
+;
+cfreeloop:
+ IncLocalStat ls_cexamine
+ mov ax,[bx].la_prev
+ test al,LA_BUSY
+ jz cfreefound
+ and al,LA_MASK
+ mov bx,ax
+cflnext:
+ loop cfreeloop
+
+compact2:
+ pop bx ; Recover largest free block so far
+ pop dx ; Recover size needed
+ mov ax,bx ; Compute size in AX
+ or ax,ax ; Did we find a free block?
+ jz cexit1 ; No, done
+ sub ax,[bx].la_next ; Yes, compute size of largest free block
+ neg ax
+ dec [di].hi_ncompact ; Any other possibilities?
+ jl cexit ; No, get out now
+ cmp ax,dx ; Yes, Did we get size we needed?
+ jb compact3 ; No, try next possibility
+cexit:
+cexit1:
+ pop si
+ ret ; Yes, return to caller
+
+compact3:
+ push dx
+ push bx
+
+ dec [di].hi_dislevel ; Down to next discard level
+ jz compact2 ; Ooops, no more, try next step
+ inc [di].hi_ncompact ; Still discarding
+ xor si,si ; Start enumerating handle table entries
+cdloop:
+ call henum ; Get next discardable handle
+ jz cdexit ; No, more see if we discarded anything
+ push cx ; Got one, see if okay to discard
+ mov cl,LN_DISCARD ; AX = LN_DISCARD
+ xchg ax,cx ; CX = discardable flags
+ mov bx,si ; BX = handle
+ call lnotify
+ pop cx
+ or ax,ax ; Is it still discardable?
+ jz cdloop ; No, skip this handle
+ mov bx,[si].lhe_address ; Get true address of a block
+ sub bx,SIZE LocalArena ; BX = address of block to free
+ call lfree ; Free the block associated with this handle
+ xor ax,ax ; Zero the true address field in the
+ mov [si].lhe_address,ax
+ or [si].lhe_flags,LHE_DISCARDED ; and mark as discarded
+ or [di].hi_ncompact,80h ; Remember we discarded something
+ jmp cdloop
+cdexit:
+ test [di].hi_ncompact,80h ; No, did we discarded something?
+ jz compact2
+ xor [di].hi_ncompact,80h ; Yes, clear flag
+ pop bx
+ pop dx
+ jmp compact1 ; and try compacting again
+
+; Here when we have a free block. While the preceeding block is
+; moveable, then move it down and put the free space in it place.
+; When the preceeding block is not moveable, then search backwards
+; for one or more moveable blocks that are small enough to fit
+; in the remaining free space. Advance to previous block when
+; no more blocks to examine.
+cfreefound:
+ IncLocalStat ls_cfree
+ cmp [di].hi_freeze,0 ; Is the heap frozen?
+ jne cffexit ; No, continue
+
+; and al,LA_MASK ; Already clear for free blocks
+ mov si,ax ; SI = previous block
+ test byte ptr [si].la_prev,LA_MOVEABLE
+ jz cfreefill ; Skip if not moveable
+ mov si,[si].la_handle ; Point to handle table entry
+ cmp [si].lhe_count,0 ; Is it locked?
+ jne cfreefill ; Yes, skip this block
+
+; Here if previous block is moveable. Slide it up to the top of the
+; free block and make the old busy block free. This is easy as
+; we are not really adding or taking anything away from the arena
+;
+ push cx ; Save loop state regs
+ push di
+ mov si,ax ; SI = busy block before free block
+ call lfreedelete ; remove [BX] from free list
+ call lmove ; Move busy block down
+ mov [di].la_prev,si ; Link in new busy block
+ or byte ptr [di].la_prev,LA_MOVEABLE+LA_BUSY
+ mov bx,ax
+ mov [di].la_next,bx ; la_next field from old free block
+ and [bx].la_prev,LA_ALIGN
+ or [bx].la_prev,di
+
+ mov [si].la_next,di ; Link in old busy block (new free block)
+ and byte ptr [si].la_prev,LA_MASK ; mark it free
+
+ push si
+ push bx
+ mov bx,si
+ xor si,si
+ call lfreeadd ; add new free block to free list
+ pop bx
+ pop si
+
+ mov bx,[di].la_handle ; Modify handle table entry to point
+ lea ax,[di].SIZE LocalArena
+ mov [bx].lhe_address,ax ; to new location of client data
+
+ pop di ; Restore arena info pointer
+ IncLocalStat ls_cmove
+ mov al,LN_MOVE ; Tell client we moved it
+ lea cx,[si].SIZE LocalArena ; CX = old client data
+ call lnotify ; BX = handle
+
+ pop cx ; restore #arena entries left
+ mov bx,si ; BX = address of free block
+ mov si,[bx].la_prev ; SI = previous block
+ test byte ptr [si].la_prev,LA_BUSY ; Is it free?
+ jnz cffnext ; No, continue
+ call ljoin ; Yes, coelesce with block in BX
+;;; DO NOT change cx, ljoin leaves BX pointing after the free block
+;;; dec cx ; ...keep CX in sync
+cffnext:
+ jmp cflnext ; Go process next free block
+
+; Here when done with a free block. Keep track of the largest free block
+; seen so far.
+;
+cffexit:
+ pop si ; Recover largest free block so far
+ cmp si,bx ; Same as current?
+ je cff1 ; Yes, no change then
+ test [bx].la_prev,LA_BUSY ; No, is current free?
+ jnz cff1 ; No, ignore it then
+ or si,si ; Yes, First time?
+ jz cff0 ; Yes, special case
+ mov ax,[si].la_next ; No, compute size of largest free block
+ sub ax,si
+ add ax,bx ; Compare to size of this free block
+ cmp [bx].la_next,ax ; Is it bigger?
+ jbe cff1 ; No, do nothing
+cff0: mov si,bx ; Yes, remember biggest free block
+cff1: push si ; Save largest free block so far
+cff2: mov bx,[bx].la_prev ; Skip past this free block
+ and bl,LA_MASK ; (it might not be a free block)
+ jmp cffnext
+
+; Here if previous block is NOT moveable. Search backwards for the
+; largest moveable block that will fit in this free block. As long
+; as a block is found, move it to the top of the free block, free it
+; from it's old location and shrink the current free block to accomodate
+; the change.
+;
+cfreefill:
+ call lbestfit ; Search for best fit
+ or si,si ; Find one?
+ jz cffexit ; No, all done with this free block
+ push cx ; Save loop state regs
+ push di
+ push [bx].la_prev ; Save busy block before free block
+ call lfreedelete ; remove [BX] from free list
+ call lmove ; Move it down
+ ; SI = old busy address (new free block)
+ ; DI = new busy address
+ ; BX = old free block
+ ; AX = block after old free block
+ pop cx ; Recover la_prev field of old free block
+ cmp bx,di ; Did we consume the free block?
+ je cff ; Yes, then CX has what we want
+ mov cx,bx ; No, then busy block will point to what
+ mov [bx].la_next,di ; is left of the free block and vs.
+cff:
+ mov [di].la_prev,cx ; Link in new busy block
+ or byte ptr [di].la_prev,LA_MOVEABLE+LA_BUSY
+ mov [di].la_next,ax ; la_next field from old free block
+ xchg di,ax
+ and [di].la_prev,LA_ALIGN
+ or [di].la_prev,ax
+ xchg di,ax
+
+ lea cx,[di].SIZE LocalArena
+
+ cmp bx,di ; Did we create a free block?
+ je cffff
+ push si
+ xor si,si
+ call lfreeadd ; Add [BX] to free list
+ pop si
+cffff:
+
+ cmp bx,di ; Did we create a free block?
+
+ mov bx,di ; Current block is busy block
+ mov di,[di].la_handle ; Modify handle table entry to point
+ xchg [di].lhe_address,cx ; to new location of client data
+ pop di ; Restore arena info pointer
+ pop ax ; restore #arena entries left
+ je cfff ; No, arena count okay
+ inc ax ; Keep arena count on target
+ inc [di].hi_count
+cfff:
+ push bx ; Save current block pointer
+ push ax ; Save #arena entries left
+ mov al,LN_MOVE ; Tell client we moved it (CX = old addr)
+ mov bx,[bx].la_handle ; BX = handle
+ call lnotify
+ pop cx ; restore #arena entries left
+ and byte ptr [si].la_prev,not LA_MOVEABLE ; Clear moveable bit
+ mov bx,si ; BX = address of old busy block to free
+ push [di].hi_count
+ call lfree ; Mark it as free
+ pop si
+ sub si,[di].hi_count
+ sub cx,si ; Keep arena count on target
+ pop bx ; BX = current block
+ jmp cff2 ; Move to previous block.
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lshrink ;
+; ;
+; Shrinks the local heap. ;
+; ;
+; Arguments: ;
+; DS:DI = address of local heap information block ;
+; BX = Minimum size to shrink heap ;
+; ;
+; Returns: ;
+; AX = New size of local heap ;
+; ;
+; Error Returns: ;
+; None. ;
+; ;
+; Registers Preserved: ;
+; None ;
+; Registers Destroyed: ;
+; All ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri July 17, 1987 -by- Bob Gunderson [bobgu] ;
+; Changed logic so we don't call lcompact every time we move ;
+; a block, just call it whenever we can't find room. ;
+; ;
+; Fri June 12, 1987 -by- Bob Gunderson [bobgu] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc lshrink,<PUBLIC,NEAR>
+cBegin nogen
+
+ ; Bound the minimum size to the size specified at LocalInit() time.
+ mov ax,[di].li_minsize
+ cmp ax,bx ; specified smaller than min ?
+ jbe lshr_around ; no - use what's specified
+ mov bx,ax ; yes - use real min.
+lshr_around:
+ push bx ; Save minimum heap size
+ mov ax,[di].hi_last
+ add ax,SIZE LocalArenaFree
+ sub ax,[di].hi_first ; ax = current heap size
+ cmp ax,bx ; already small enough ?
+ ja lshr_around1
+ jmp lshr_exit ; yes - that was quick...
+lshr_around1:
+
+ ; local compact to get as much contiguous free space as possible.
+ stc
+ call lalign
+ call lcompact ; compact everything
+ xor dx,dx ; start with null flag
+
+ ; Start with last block in heap.
+ mov si,[di].hi_last
+
+loop1:
+
+ ; SI = address of block just moved.
+
+ ; This section moves moveable blocks (one at a time) up
+ ; into free blocks below (higher addresses) all fixed blocks.
+ ; The blocks they vacate are freed. The sentenal block is then
+ ; moved, the heap is re-compacted. Then a test is made to see if
+ ; the heap has shrunk enough, if not
+ ; we start this loop again. We continue this until we can't
+ ; move anything or we have moved enough to satisfy the minimum
+ ; size specified by BX when called.
+
+ mov si,[si].la_prev ; get next block to move
+ and si,LA_MASK ; zap the flag bits
+ mov ax,[si].la_prev ; get this blocks flags
+ test ax,LA_BUSY ; is this block free?
+ jz lshr_gobblefree ; yes - gobble this free block
+ test ax,LA_MOVEABLE ; is it moveable ?
+ jz lshr_cantmove ; no - exit
+ mov bx,[si].la_handle ; get its handle
+ cmp [bx].lhe_count,0 ; is it locked ?
+ jnz lshr_cantmove ; yes - exit
+
+ mov cx,[si].la_next
+ sub cx,si ; get block size in cx
+
+ ; Find the first free block (after fixed blocks) that is big
+ ; enough for this block
+loop2:
+ call lfirstfit
+ jnc lshr_gotblock ; got one - continue
+
+ ; If we have already tried compacting, nothing more to do
+ or dx,dx
+ jnz lshr_cantmove ; nothing more to do...
+
+ ; Not enough room found, recompact the local heap and test again
+ push si
+ push cx
+ stc
+ call lalign
+ call lcompact ; compact everything
+ pop cx
+ pop si
+ mov dx,1 ; flag to say we have done this
+ jmp loop2 ; try again
+
+ ; DI = local arena info block address
+ ; SI = block we didn't move (next is last block moved)
+lshr_cantmove:
+ mov si,[si].la_next ; get last block moved
+ jmp lshr_alldone ; cleanup and exit
+
+lshr_gobblefree:
+ ; SI = address of free block
+ ; Block to move is already free, remove it from the free list and mark
+ ; it a busy.
+ mov bx,si
+ call lfreedelete
+ or [bx].la_prev,LA_BUSY
+ jmps lshr_shiftup
+
+lshr_gotblock:
+ ; DI - Arena info block address
+ ; SI - Address of block to move
+ ; BX - Address of free block to use
+ ; CX - Size of block to move
+
+ call lfreedelete ; remove it from the free list
+ xchg di,bx
+ mov ax,[di].la_next
+ sub ax,cx
+ sub ax,LA_MINBLOCKSIZE ; Room to split free block into
+ cmp ax,di ; two blocks ?
+ jb lshr_nosplit ; no - don't split the block
+ push bx
+ push si
+ mov bx,cx
+ lea bx,[bx+di] ; bx = address of new free block to add
+ ; link this new block in
+ mov [bx].la_prev,di
+ mov ax,[di].la_next
+ mov [bx].la_next,ax
+ mov [di].la_next,bx
+ xchg ax,bx
+ and [bx].la_prev,LA_ALIGN ; Zap only high bits
+ or [bx].la_prev,ax ; and set new previous pointer
+ mov bx,ax
+ mov si,[di].la_free_prev ; previous free block
+ call lfreeadd ; add the new smaller free block
+ pop si
+ pop bx
+ inc [bx].hi_count ; bump the block count (we added
+ ; a block)
+lshr_nosplit:
+ ; BX - Arena info block address
+ ; SI - Address of block to move
+ ; DI - Address of free block to use
+ ; CX - Size of block to move
+
+ ; copy the flags from the old block
+ mov ax,[si].la_prev
+ and ax,LA_ALIGN
+ or [di].la_prev,ax
+
+ push si
+ push di
+ ; don't copy the block headers (but do copy the handle)
+ add si,la_fixedsize
+ add di,la_fixedsize
+ sub cx,la_fixedsize
+ ; We can take # bytes/2 as # words to move because all blocks
+ ; start on even 4 byte boundary.
+ shr cx,1 ; bytes / 2 = words
+ push ds
+ pop es ; same segment
+ cld ; auto-increment
+ rep movsw ; Head 'em up! Move 'em out!
+ pop di
+ pop si
+ ; BX - Arena info block address
+ ; SI - Address of block to move
+ ; DI - Address of free block to use
+
+ ; Fixup the handle table pointer
+ push bx
+ mov bx,[si].la_handle
+ lea ax,[di].SIZE LocalArena
+ mov [bx].lhe_address,ax
+ pop di ; DI = info block address
+
+ ; Mark the old block as busy fixed
+ and [si].la_prev,LA_MASK ; clear old bits
+ or [si].la_prev,LA_BUSY ; put in busy fixed bit
+ jmps lshr_shiftup
+
+ ; Time to shift the setenal block up, recompact and look for more
+ ; space...
+ ; DI = local arena info block address
+ ; SI = block just freed
+ public foo
+foo:
+lshr_shiftup:
+ mov ax,[di].hi_last
+ mov bx,ax
+ sub bx,si ; less what is already removed
+ sub ax,bx
+ add ax,SIZE LocalArenaFree ; size of sentenal block
+ sub ax,[di].hi_first ; ax = current heap size
+ pop bx ; get min size
+ push bx ; and put it back on stack
+ cmp ax,bx ; already small enough ?
+ jbe lshr_alldone ; yes - exit
+ xor dx,dx ; localcompact flag
+ jmp loop1 ; and back for more
+
+lshr_alldone:
+ ; DI = local arena info block address
+ ; SI = last block moved
+
+ ; Time to shift the sentenal block up and realloc our heap
+ pop bx ; Minimum size of the heap
+ push bx
+ call slide_sentenal ; slide the sentenal block up
+
+ ; get our data segment handle
+ push ds
+ call GlobalHandle ; ax = handle of DS
+ or ax,ax
+ jz lshr_exit ; this can't happen.....
+ push ax ; hMem
+
+ ; determine how big we should be
+ mov ax,[di].hi_last
+ add ax,SIZE LocalArenaFree
+ xor cx,cx
+ push cx
+ push ax ; # bytes in DS
+ push cx ; no wFlags
+ call GlobalRealloc
+
+ ; local compact to get as much contiguous free space as possible.
+lshr_exit:
+ stc
+ call lalign
+ call lcompact ; compact everything
+ pop ax ; clean the stack
+ mov ax,[di].hi_last
+ add ax,SIZE LocalArenaFree
+ sub ax,[di].hi_first ; ax = current heap size
+ ret
+cEnd nogen
+
+;-------------------------------------------------------------------------
+; Find first free block after last fixed block. We do this by scanning
+; through the free list looking for a free block with the next physical
+; block being moveable (remember we just did a compact...). Then, starting
+; with this free block, find the first free block that is at least
+; CX bytes long.
+;
+; Entry:
+; DI = local arena header info block address
+; CX = # bytes needed
+;
+; Exit:
+; BX = Address of free block to use
+;
+; Error Return:
+; Carry set if no free block big enough
+;
+; History:
+;
+; Fri June 12, 1987 -by- Bob Gunderson [bobgu]
+; Wrote it.
+;-------------------------------------------------------------------------
+
+cProc lfirstfit,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+
+ mov bx,[di].hi_last
+ mov bx,[bx].la_free_prev
+; mov bx,[di].hi_first
+; mov bx,[bx].la_free_next
+lffloop:
+ cmp bx,[bx].la_free_prev
+; cmp bx,[bx].la_free_next
+ jz lff_err_exit
+ cmp cx,[bx].la_size
+ jbe lff_exit
+ mov bx,[bx].la_free_prev
+; mov bx,[bx].la_free_next
+ jmp lffloop
+lff_err_exit:
+ stc
+ jmps lff_done
+lff_exit:
+ clc ; good return
+lff_done:
+ pop ax
+ ret
+cEnd nogen
+
+
+;-------------------------------------------------------------------------
+; slide_sentenal
+; This routine is called during the LocalShrink() operation.
+; Make all the blocks between the one at SI and the sentenal go
+; away. Then check to see if we have shrunk the heap too much. If
+; so, then add a free block at SI big enough to bump the size up (this
+; will be moved later by LocalCompact). Now move the sentenal block
+; up after the last block.
+;
+; Entry:
+; BX = requested minimum size of the heap
+; SI = last block actually moved (put sentenal here)
+; DI = local arena info block address
+;
+; Exit:
+;
+; Error Return:
+;
+; History:
+;
+; Fri Aug 14, 1987 -by- Bob Gunderson [bobgu]
+; Changed things again to insure we don't shrink to heap too much.
+;
+; Fri July 17, 1987 -by- Bob Gunderson [bobgu]
+; Was too slow, so changed the logic.
+;
+; Fri June 12, 1987 -by- Bob Gunderson [bobgu]
+; Wrote it.
+;-------------------------------------------------------------------------
+
+cProc slide_sentenal,<PUBLIC,NEAR>
+cBegin nogen
+
+ push bx
+
+ ; Get sentenal block
+ mov bx,[di].hi_last
+
+ ; Insure that we aren't trying to move to ourselves
+ cmp si,bx
+ jz slide_exit ; nothing to do....
+
+ ; count the number of block we are removing so that we can update
+ ; the block count in the arena header.
+ push si
+ xor cx,cx
+slide_loop:
+ cmp si,bx
+ jz slide_loop_exit
+ inc cx
+ mov si,[si].la_next
+ jmp slide_loop
+slide_loop_exit:
+ pop si
+
+ sub [di].hi_count,cx ; decrement the count of blocks
+
+ ; Would the heap be too small if the sentenal were moved to the block
+ ; pointed to by si? If so, add a free block at SI to make up the
+ ; difference.
+ mov ax,si
+ sub ax,[di].hi_first
+ add ax,la_freefixedsize ; size of heap in ax
+ pop bx ; minimum in bx
+ cmp ax,bx
+ ja slide_ok ; everything is ok...
+ sub bx,ax ; bx = size to grow
+ cmp bx,LA_MINBLOCKSIZE
+ jbe slide_ok ; not enough for a block
+ clc
+ call lalign ; make it even 4 byte boundary
+ mov bx,dx
+ ; add a free block of bx bytes
+ lea ax,[si+bx] ; address of new "next" block
+ mov [si].la_next,ax ; make block point at "next"
+ and [si].la_prev,LA_MASK ; make it a free block
+ xor bx,bx
+ xchg si,bx ; bx = block to add, si = 0
+ call lfreeadd ; preserves ax
+ inc [di].hi_count ; bump block count
+ mov si,ax ; and bump si to "next" block
+ mov [si].la_prev,bx ; set new block's previous pointer
+
+slide_ok:
+ ; move the sentenal block up by copying the words.
+ mov bx,[di].hi_last ; old sentenal block
+ mov [si].la_next,si ; new sentenal points to self
+ and [si].la_prev,LA_MASK ; remove any old flags
+ or [si].la_prev,LA_BUSY ; make it busy
+ mov ax,[bx].la_size
+ mov [si].la_size,ax ; move in the size
+ mov bx,[bx].la_free_prev
+ mov [si].la_free_prev,bx ; move in previous free block
+ mov [bx].la_free_next,si ; point prev free block to this one
+ mov [si].la_free_next,si ; point to itself
+
+ ; Now fixup the arena header block to point to the new setenal
+ ; position.
+
+ mov [di].hi_last,si
+
+ ; And we are done...
+ jmps slide_exit1
+
+slide_exit:
+ pop bx
+slide_exit1:
+ ret
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ld.asm b/private/mvdm/wow16/kernel31/ld.asm
new file mode 100644
index 000000000..510d756dc
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ld.asm
@@ -0,0 +1,3699 @@
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include pdb.inc
+include eems.inc
+include protect.inc
+.list
+
+NEWEPME = NEPRIVLIB ; flag saying Call WEP on exit
+
+externW pLocalHeap
+externW pStackTop
+
+DataBegin
+
+externB num_tasks
+externB graphics
+externB fBooting
+externB Kernel_flags
+externB WOAName
+externW fLMdepth
+externW headPDB
+externW curTDB
+externW loadTDB
+externW Win_PDB
+externW topPDB
+externW hExeHead
+;externW EMS_calc_swap_line
+externW WinFlags
+externW hGDI
+externW hUser
+ifdef WOW
+externW OFContinueSearch
+endif
+externD pMBoxProc
+externD pGetFreeSystemResources
+externD dressed_for_success
+externD lpGPChain
+
+;** Diagnostic mode stuff
+externW fDiagMode
+externB szLoadStart
+externB szCRLF
+externB szLoadSuccess
+externB szLoadFail
+externB szFailCode
+externB szCodeString
+
+if ROM
+externW selROMTOC
+endif
+
+; Look for module in Module Compatibilty section of win.ini
+szModuleCompatibility DB 'ModuleCompatibility',0
+DataEnd
+
+if ROM and PMODE32
+externFP HocusROMBase
+endif
+
+externFP Yield
+externFP CreateTask
+externFP GlobalAlloc
+externFP GlobalSize
+externFP GlobalLock
+externFP GlobalUnlock
+externFP GlobalFree
+externFP LocalAlloc
+externFP LocalFree
+externFP LocalCountFree
+externFP LoadModule
+externFP lstrlen
+externFP _lclose
+externFP FreeModule
+externFP GetModuleHandle
+externFP LoadExeHeader
+externFP GetExePtr
+externFP GetProcAddress
+externFP MyOpenFile
+externFP FarGetCachedFileHandle
+externFP FarEntProcAddress
+externFP FlushCachedFileHandle
+externFP FarMyLock
+externFP FarMyFree
+externFP FarMyUpper
+externFP FarLoadSegment
+externFP FarDeleteTask
+externFP FarUnlinkObject
+externFP Far_genter
+externFP AllocSelector
+externFP FreeSelector
+externFP LongPtrAdd
+externFP GetProfileInt
+
+if ROM
+externFP ChangeROMHandle
+externFP UndefDynLink
+externFP GetProcAddress
+externFP IPrestoChangoSelector
+externFP far_alloc_data_sel16
+externFP far_free_temp_sel
+endif
+
+ifdef WOW
+externFP StartWOWTask
+externFP WowIsKnownDLL
+externFP LongPtrAddWOW
+externFP AllocSelectorWOW
+externFP WOWLoadModule
+endif
+
+ifdef DBCS
+externFP FarMyIsDBCSLeadByte
+endif
+
+externFP FreeTDB
+
+;** Diagnostic mode
+externFP DiagOutput
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+sEnd CODE
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externB szProtectCap
+externB msgRealModeApp1
+externB msgRealModeApp2
+
+externNP MapDStoDATA
+externNP FindExeFile
+externNP FindExeInfo
+externNP AddModule
+externNP DelModule
+externNP GetInstance
+externNP IncExeUsage
+externNP DecExeUsage
+externNP AllocAllSegs
+externNP PreloadResources
+externNP StartProcAddress
+externNP StartLibrary
+externNP GetStackPtr
+externNP StartTask
+
+IFNDEF NO_APPLOADER
+externNP BootAppl
+ENDIF ;!NO_APPLOADER
+
+
+;-----------------------------------------------------------------------;
+; OpenApplEnv ;
+; Calls CreateTask ;
+; Allocates temporary stack ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ax = selector of load-time stack ;
+; Error Returns: ;
+; ax = 0 ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue 16-Jan-1990 21:13:51 -by- David N. Weise [davidw] ;
+; Ya know, it seems to me that most of the below ain't necessary ;
+; for small frame EMS. But it's too late to change it now. ;
+; ;
+; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
+; Added support for task ExeHeaders above The Line in Large ;
+; Frame EMS. ;
+; ;
+; Tue Oct 20, 1987 07:48:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+LOADSTACKSIZE = 2048
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc OpenApplEnv,<PUBLIC,NEAR>,<ds,si,di>
+ parmD lpPBlock
+ parmW pExe
+ parmW fWOA
+; localW myCodeDS
+; localW myCurTDB
+; localW myLoadTDB
+cBegin
+ ReSetKernelDS ; Assume DS:KRNLDS
+
+ cCall CreateTask,<lpPBlock,pExe,fWOA>
+ or ax,ax
+ jz oae_done
+
+ test kernel_flags,KF_pUID ; All done booting?
+ jz oae_done
+
+ xor ax,ax
+ mov bx,LOADSTACKSIZE
+ mov cx,(GA_ALLOC_LOW or GA_SHAREABLE) shl 8 or GA_ZEROINIT or GA_MOVEABLE
+ cCall GlobalAlloc,<cx,ax,bx>
+ or ax,ax
+ jz oae_done
+ cCall GlobalLock,<ax>
+ mov ax,dx
+ push es ; added 13 feb 1990
+ mov es,loadTDB
+ mov es:[TDB_LibInitSeg],ax
+ mov es:[TDB_LibInitOff],10h
+ mov es,dx
+ mov es:[pStackTop],12h
+ pop es
+oae_done:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; CloseApplEnv ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; AX = hExe ;
+; BX = ? ;
+; DX = TDB ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ..., ES, ... ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
+; Added support for task ExeHeaders above The Line in Large ;
+; Frame EMS. ;
+; ;
+; Tue Oct 20, 1987 07:48:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CloseApplEnv,<PUBLIC,NEAR>,<ds,si,di>
+ parmW hResult
+ parmW hExe
+ localW myCurTDB
+ localW cae_temp
+ localW myLoadTDB
+cBegin
+
+ ReSetKernelDS
+
+; Copy DS variables to stack, since we may need DS
+ mov cx,curTDB
+ mov myCurTDB,cx
+ mov cx,loadTDB
+ mov myLoadTDB,cx
+ mov cae_temp, si
+
+ mov ax, myLoadTDB
+ or ax, ax ; Not set if LMCheckHeap failed
+ jz cae_done
+ mov ds, ax
+ mov ax, ds:[TDB_LibInitSeg]
+ or ax, ax
+ jz cae_free_stack1
+ mov ds, ax
+ cmp ds:[pStackTop], 12h
+ jne cae_free_stack1
+ mov ds,myLoadTDB
+ push ax
+ cCall GlobalUnlock,<ax>
+ call GlobalFree ; parameter pushed above
+cae_free_stack1:
+ mov ds,myLoadTDB
+ mov ds:[TDB_LibInitSeg],ax
+ mov ds:[TDB_LibInitOff],10h
+
+; Copy correct return address
+
+cae_done:
+ SetKernelDSNRES
+ xor dx,dx
+ xchg loadTDB,dx ; Done loading this guy
+
+ mov ax,hResult ; if hResult < 32, it's not a real
+ cmp ax,LME_MAXERR ; handle, and in fact is the invalid
+ jb cae_cleanup ; format return code. (11).
+
+ mov es,dx
+
+; Start this guy up! TDB_nEvents must be set here, and not before
+; because message boxes may be put up if we can't find libraries,
+; which would have caused this app to prematurely start.
+
+ push es
+ mov es:[TDB_nEvents],1
+ inc num_tasks ; Do this here or get it wrong.
+
+ test es:[TDB_flags],TDBF_OS2APP
+ jz @F
+ cmp dressed_for_success.sel,0
+ jz @F
+ call dressed_for_success
+
+ifdef WOW
+ ; Start Up the New Task
+@@: cCall StartWOWTask,<es,es:[TDB_taskSS],es:[TDB_taskSP]>
+ or ax,ax ; Success ?
+ jnz @f ; Yes
+
+ mov hResult,ax ; No - Fake Out of Memory Error 0
+ ; No error matches failed to create thread
+ pop dx ; restore TDB
+ dec num_tasks ;
+ jmps cae_cleanup ;
+
+endif; WOW
+
+@@: test kernel_flags,KF_pUID ; All done booting?
+ jz @F ; If booting then don't yield.
+ cCall Yield
+
+@@:
+ assumes ds,nothing
+ pop dx ; return TDB
+ jmps cae_exit
+
+; Failure case - undo the damage
+cae_cleanup:
+ or dx,dx ; Did we even get a TDB?
+ jz cae_exit ; No.
+ mov ds,dx
+ assumes ds,nothing
+ mov ds:[TDB_sig],ax ; mark TDB as invalid
+ cCall FarDeleteTask,<ds>
+ mov es,ds:[TDB_PDB]
+ mov dx,PDB_Chain
+ mov bx,dataOffset HeadPDB ; Kernel PDB
+ cCall FarUnlinkObject
+ cCall FreeTDB
+
+cae_exit:
+ xor ax,ax
+ mov es,ax ; to avoid GP faults in pmode
+if PMODE32
+.386
+ mov fs, ax
+ mov gs, ax
+.286
+endif
+ mov ax,hResult
+ mov bx, cae_temp
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; StartModule ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; AX = hExe or StartLibrary ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; BX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; FarLoadSegment ;
+; StartProcAddress ;
+; StartLibrary ;
+; ;
+; History: ;
+; ;
+; Tue Jan 01, 1980 03:04:49p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc StartModule,<PUBLIC,NEAR>,<di,si>
+ parmW hPrev
+ parmD lpPBlock
+ parmW hExe
+ parmW fh
+ localD pf
+cBegin
+ mov ax,hExe
+ mov es,ax
+ assumes es,nothing
+ cmp es:[ne_csip].sel,0
+ jz start_it_up
+
+; Make sure DGROUP loaded before we need to load the start segment.
+
+ mov cx,es:[ne_autodata]
+ jcxz start_it_up ; no automatic data segment
+ cCall FarLoadSegment,<es,cx,fh,fh>
+ or ax,ax
+ jnz start_it_up ; auto DS loaded OK
+ mov ax,fh
+ inc ax
+ jz sm_ret1 ; return NULL
+ dec ax
+ cCall _lclose,<ax>
+ xor ax,ax
+sm_ret1:
+ jmps sm_ret ; return NULL
+
+start_it_up:
+ cCall StartProcAddress,<hExe,fh> ; just because it's preloaded
+ mov pf.sel,dx ; doesn't mean it's still around!
+ mov pf.off,ax
+ or dx,ax
+ push dx
+ mov ax,fh
+ cmp ax,-1
+ jz sm_nothing_to_close
+ cCall _lclose,<ax>
+sm_nothing_to_close:
+ pop dx
+ mov es,hExe
+ assumes es,nothing
+ test es:[ne_flags],NENOTP
+ jnz start_library
+ or dx,dx
+ jz nothing_to_start
+ cCall GetStackPtr,<es>
+ cCall StartTask,<hPrev,hExe,dx,ax,pf>
+ jmps sm_ret
+
+start_library:
+ mov es, hExe
+ or es:[ne_flags], NEWEPME ; Need to call my WEP on exit
+ cCall StartLibrary,<hExe,lpPBlock,pf>
+ jmps sm_ret
+
+nothing_to_start:
+ mov ax,hExe
+ test es:[ne_flags],NENOTP
+ jnz sm_ret
+ xor ax,ax
+sm_ret:
+cEnd
+
+if 0 ; too late to include in 3.1, add for next Windows release (donc)
+cProc GetProcAddressRes, <PUBLIC, FAR>, <ds, si, di>
+parmW hExe
+parmD pname ; pass in Pascal string
+cBegin
+ les di, [pname] ; ES:DI = name to find
+
+ mov cx, 255 ; CH = 0
+ xor ax, ax
+ push di
+ repne scasb
+ pop di
+ jnz GPAR_fail
+ not cl
+ dec cl
+ mov al, cl ; AX = length of name
+
+ mov ds, [hExe] ; DS:SI = res name table
+ mov bx, ds:[ne_restab] ; (actually DS:BX first time through)
+
+GPAR_nextsym:
+ mov si, bx ; next entry to check
+ mov cl, [si] ; string length
+ jcxz GPAR_fail
+ lea bx, [si+3]
+ add bx, cx ; BX points to next (last + len + 3)
+ cmp cx, ax
+ jnz GPAR_nextsym ; length diff - no match
+ inc si ; skip length byte
+ push di
+ rep cmpsb
+ pop di
+ jnz GPAR_nextsym
+ lodsw ; get ordinal number
+;if KDEBUG
+; cCall FarEntProcAddress,<ds,ax,1>
+;else
+ cCall FarEntProcAddress,<ds,ax> ; I hate conditional assembly....
+;endif
+ mov cx, ax
+ or cx, dx
+ jmps GPAR_exit
+
+GPAR_fail:
+ xor ax, ax
+ cwd
+GPAR_exit:
+cEnd
+endif
+
+;-----------------------------------------------------------------------;
+; CallWEP ;
+; ;
+; Call WEP of DLL if appropriate ;
+; ;
+; Arguments: ;
+; HANDLE hExe = HEXE of module about to close ;
+; WORD WEPVal = 0, 1 pass to WEP, 2 check for WEP ;
+; ;
+; Returns: ;
+; AX = status ;
+; ;
+; Error Returns: ;
+; AX = Not a DLL ;
+; AX = No WEP ;
+; AX = Module not started ;
+;-----------------------------------------------------------------------;
+
+cProc CallWEP, <PUBLIC,FAR>, <ds>
+ parmW hExe
+ parmW WEPVal
+ localV szExitProc,4
+ localD pExitProc
+ localW bogusIBMAppSp
+cBegin
+ mov ds, hExe ; Robustify this!
+
+ CWErr = 1
+ mov ax, 1 ; exit code
+ cmp ds:[ne_expver], 300h ; 3.0 libraries only
+ jb CW_noWEP
+
+ CWErr = CWErr+1
+ inc ax
+ test ds:[ne_flags], NENOTP ; is it a DLL?
+ jz CW_noWEP
+
+ CWErr = CWErr+1
+ inc ax ; Font, etc
+ cmp ds:[ne_cseg],0
+ jz CW_noWEP
+
+ CWErr = CWErr+1
+ inc ax
+ mov bx, ds:[ne_pautodata] ; Make sure auto data loaded
+ or bx, bx
+ jz @F
+ test ds:[bx].ns_flags, NSLOADED
+ jz CW_noWEP
+@@:
+
+ CWErr = CWErr+1
+ inc ax
+ NoWepErr = CWErr
+ mov [szExitProc].lo, 'EW' ; If the module has a procedure
+ mov [szExitProc].hi, 'P' ; named 'WEP', call it.
+ lea bx, szExitProc
+ push ax
+ cCall GetProcAddress, <ds, ss, bx>
+ mov [pExitProc].off, ax
+ mov [pExitProc].sel, dx
+ or ax, dx
+ pop ax
+ jnz CW_WEP
+CW_noWEP:
+ jmps CW_noWEP1
+
+CW_WEP:
+ cmp WEPVAL,2 ; If I'm just looking for WEP
+ jz CW_OK ; return 0
+
+ inc ax
+ test ds:[ne_flags], NEWEPME ; don't call wep if libmain
+ jz CW_noWEP ; wasn't called
+
+ and ds:[ne_flags], NOT NEWEPME ; only call WEP once
+
+ SetKernelDSNRES ; Save old GP chaine
+ pusha
+ push lpGPChain.sel
+ push lpGPChain.off
+ push cs
+ push offset cw_BlowChunks
+ mov lpGPChain.sel, ss ; and insert self in the chain
+ mov lpGPChain.off, sp
+ UnSetKernelDS
+
+ mov ax, ss
+ mov ds, ax
+ mov es, ax
+ mov bogusIBMAppSP,sp ; Save sp cause some apps (Hollywood)
+ ; don't retf 2 correctly when we
+ ; call their wep
+ cCall pExitProc, <WEPVal> ; fSystemExit
+
+ mov sp,bogusIBMAppSp
+
+ add sp, 4 ; remove the CS:IP for error handler
+cw_BlowChunks:
+ SetKernelDSNRES
+ pop lpGPChain.off ; restore GPChain
+ pop lpGPChain.sel
+ popa
+ UnSetKernelDS
+CW_OK:
+ xor ax, ax
+
+CW_noWEP1:
+ cmp WEPVAL, 2 ; if we checked for whining
+ jnz CW_done
+ or ax, ax ; if we found, then OK
+ jz CW_done
+ cmp ax, NoWepErr ; anything other than NoWep is OK
+ jz CW_done
+ xor ax, ax
+
+CW_done:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; LoadModule ;
+; ;
+; Loads a module or creates a new instance of an existing module. ;
+; ;
+; Arguments: ;
+; FARP p = name of module or handle of existing module ;
+; FARP lpPBlock = Parameter Block to pass to CreateTask ;
+; ;
+; Returns: ;
+; AX = instance handle or module handle ;
+; ;
+; Error Returns: ;
+;LME_MEM = 0 ; Out of memory ;
+;LME_FNF = 2 ; File not found
+;LME_LINKTASK = 5 ; can't link to task ;
+;LME_LIBMDS = 6 ; lib can't have multiple data segments ;
+;LME_VERS = 10 ; Wrong windows version ;
+;LME_INVEXE = 11 ; Invalid exe ;
+;LME_OS2 = 12 ; OS/2 app ;
+;LME_DOS4 = 13 ; DOS 4 app ;
+;LME_EXETYPE = 14 ; unknown exe type ;
+;LME_RMODE = 15 ; not a pmode windows app ;
+;LME_APPMDS = 16 ; multiple data segments in app ;
+;LME_EMS = 17 ; scum app in l-frame EMS ;
+;LME_PMODE = 18 ; not an rmode windows app ;
+;LME_INVCOMP = 20 ; invalid DLL caused fail of EXE load ;
+;LME_PE32 = 21 ; Windows Portable EXE app - let them load it ;
+;LME_MAXERR = 32 ; for comparisons ;
+; ;
+; Registers Preserved: ;
+; DI, SI, DS ;
+; Registers Destroyed: ;
+; BX, CX, DX, ES ;
+; ;
+; Calls: ;
+; AllocAllSegs ;
+; CreateInsider ;
+; DecExeUsage ;
+; DelModule ;
+; FindExeFile ;
+; FindExeInfo ;
+; FreeModule ;
+; GetExePtr ;
+; GetInstance ;
+; GetStringPtr ;
+; IncExeUsage ;
+; LoadExeHeader ;
+; LoadModule ;
+; FarLoadSegment ;
+; lstrlen ;
+; FarMyFree ;
+; MyOpenFile ;
+; PreloadResources ;
+; StartModule ;
+; _lclose ;
+; ;
+; History: ;
+; Sun 12-Nov-1989 14:19:04 -by- David N. Weise [davidw] ;
+; Added the check for win87em. ;
+; ;
+; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
+; Added support for task ExeHeaders above The Line in Large ;
+; Frame EMS. ;
+; ;
+; Tue Oct 13, 1987 05:00:00p -by- David J. Habib [davidhab] ;
+; Added check for FAPI applications. ;
+; ;
+; Sat Jul 18, 1987 12:04:15p -by- David N. Weise [davidw] ;
+; Added support for multiple instances in different EMS banks. ;
+; ;
+; Tue Jan 01, 1980 06:57:01p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly. ;
+; ;
+; Wed Sep 17, 1986 03:31:06p -by- Charles Whitmer [chuckwh] ;
+; Modified the original LoadModule code to only allow INSIDERs to ;
+; allocate segments for a new process. An INSIDER is a new process ;
+; stub which bootstraps up a new instance of an application. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc ILoadLibrary,<PUBLIC,FAR>
+ parmD pLibName
+ localV szExitProc,4
+cBegin
+ mov ax,-1
+ cCall <far ptr LoadModule>,<pLibName,ax,ax>
+ cmp ax, LME_INVEXE ; Invalid format?
+ jnz @F
+ mov ax, LME_INVCOMP ; Invalid component
+@@:
+if KDEBUG
+ SetKernelDSNRes
+ cmp fBooting, 0
+ jne ll_fail ; No check while booting
+ cmp ax, LME_MAXERR
+ jb ll_fail ; No library, so no WEP()
+
+ push ax ; Now check for WEP
+ cCall GetExePtr,<ax>
+ mov es, ax
+ test es:[ne_flags],NEPROT ; ignore for OS/2 apps
+ jnz ll_noWhine
+ cmp es:[ne_usage], 0
+ jne ll_noWhine ; Only check on first load!
+ push dx
+ push ax
+ cCall CallWEP,<ax,2> ; Just check for WEP, don't call it
+ or ax, ax
+ pop ax
+ pop dx
+ jz ll_noWhine
+ trace_out "No WEP in library - > %AX0 %AX1"
+; fkerror 0,<No WEP in library - >,ax,dx
+ll_noWhine:
+ pop ax ; return value of LoadModule
+
+ll_fail:
+endif ; KDEBUG
+cEnd
+
+
+
+os2calls DB 'DOSCALLS' ; Used for FAPI detection
+mgxlib DB 'MGXLIB' ; Used for lib large entry table detection
+win87em DB 'WIN87EM.DLL',0 ; Used for win87em.exe detection
+
+ assumes ds,nothing
+ assumes es,nothing
+
+?SAV5 = ?DOS5 ; Adobe Type Manager check the LoadModule
+?DOS5 = 0 ; prolog and expects to see INC BP there...
+
+public LMAlreadyLoaded, LMLoadExeFile, LMCheckHeader, LMRamNMods
+public LMImports, LMSegs, LMLetsGo, LMPrevInstance, LMCleanUp
+
+cProc ILoadModule,<PUBLIC,FAR>,<di,si>
+ parmD lpModuleName
+ parmD lpPBlock
+ localW fh ; close if failed
+ localW pExe ; point to NE header in RAM
+; localW hExe ; prev module if already loaded
+ localW hResult ; temp return value
+ localW hDepFail ; return of implicit link loads
+ localW abortresult ; temp return value
+ localW ffont ; flag if loading a *.fon
+ localW fexe ; flag if loading a *.exe
+ifdef notyet
+ localW dll ; flag if loading a *.dll
+endif
+ localW hBlock ; fastload block from LoadExeHeader
+ localW AllocAllSegsRet
+ localW exe_type ; from LoadExeHeader
+ localW hTDB ; dx from CloseApplEnv
+ localW SavePDB ; save caller's pdb, switch to krnl's
+ localW fWOA ; save flag if we're loading WOA
+if ROM
+ localW selROMHdr
+ localW fLoadFromDisk
+ localW fReplaceModule
+endif
+ifdef WOW
+ LocalD pszKnownDLLPath
+ LocalW fKnownDLLOverride
+ localW RefSelector
+ localW LMHadPEDLL
+endif
+ localD FileOffset ; offset to start of ExeHdr
+ localW OnHardDisk ; don't cache FH if on floppy
+ localV namebuf,136 ; SIZE OPENSTRUC + 127
+ localW fModCompatFlags ; used by LMRamNMods
+
+
+cBegin
+ SetKernelDSNRES
+
+ mov al,Kernel_Flags[1] ; solve re-entrancy #10759
+ and ax,KF1_WINOLDAP
+ mov fWOA,ax
+ and Kernel_Flags[1],NOT KF1_WINOLDAP
+
+ inc fLMdepth ; # current invocations
+
+ ;** Log this entry only if in diagnostic mode
+ mov ax, fDiagMode ; Only log if booting and diag mode
+ and al, fBooting
+ jz @F
+
+ ;** Write out the string
+ mov ax,dataOFFSET szLoadStart ; Write the string
+ cCall DiagOutput, <ds,ax>
+ push WORD PTR lpModuleName[2]
+ push WORD PTR lpModuleName[0]
+ cCall DiagOutput
+ mov ax,dataOFFSET szCRLF
+ cCall DiagOutput, <ds,ax>
+
+; Zero out flags and handles
+@@:
+ifdef WOW
+ mov LMHadPEDLL,0
+lm_restart:
+endif
+ xor ax,ax
+; mov hExe,ax
+ mov pExe,ax
+ mov abortresult,ax ; default 0 == out of memory
+ mov ffont,ax
+ mov fexe,ax
+ifdef notyet
+ mov dll,ax
+endif
+ mov hBlock,ax
+ mov hTDB,ax
+if ROM
+ mov selROMHdr,ax
+ mov fLoadFromDisk, ax ; PATCHING
+ mov fReplaceModule, ax
+endif
+
+; Some flags are default -1
+ dec ax
+ mov fh, ax
+ mov SavePDB, ax
+
+; First, see if we were passed in a handle in the filename
+ les si,lpModuleName ; point to the file name
+ mov ax,es
+ or ax,ax ; Was a handle passed in low word?
+ jnz @F
+ cCall GetExePtr,<si> ; Valid handle?
+ or ax, ax
+ jnz prev_instance
+ mov al, LME_FNF ; call this file not found??
+ jmp ilm_ret
+
+; No handle, see if filename is already loaded
+@@: call LMAlreadyLoaded ; es:si -> modname on stack
+ cmp ax, LME_MAXERR
+ jb @F ; Not found, try to load it
+prev_instance:
+ call LMPrevInstance
+ jmp ilm_ret
+
+; Wasn't loaded, see if we can load it
+@@: call LMLoadExeFile ; fh in DI, AX = 0 or error code
+ or ax, ax
+ jz @F
+ jmp ilm_ret ; can't find it - return error
+@@:
+
+if ROM
+ mov ax, di
+ cmp di, -1
+ jnz lm_disk_exe_header
+ mov ax, selROMHdr
+lm_disk_exe_header:
+
+; Here to deal with a new library or task module.
+; We found the file, now load and scan the header
+@@: lea si,namebuf
+ cCall LoadExeHeader,<ax,di,ss,si>
+ cmp ax,LME_MAXERR
+ jb ilm_ret
+
+ cmp di, -1
+ jnz lm_disk_header_loaded
+
+ or es:[ne_flags], NEMODINROM
+lm_disk_header_loaded:
+else
+
+; Here to deal with a new library or task module.
+; We found the file, now load and scan the header
+@@: lea si,namebuf
+ cCall LoadExeHeader,<di,di,ss,si>
+ifdef WOW
+ cmp ax,LME_PE
+ jne @F
+; If we find the module is a Win32 binary (PE), check to see
+; if we're trying to load a task or DLL. If it's a DLL
+; we will continue searching for a Win16 copy of this DLL
+; on the path. If we're unsuccessful we'll eventually
+; munge the file not found error code back to LME_PE.
+
+ mov ax,lpPBlock.off
+ and ax,lpPBlock.sel
+ inc ax
+ mov ax,LME_PE
+ jnz @F ; have a PBlock, must be doing LoadModule
+ cmp LMHadPEDLL,0
+ je lm_retry_pe
+ mov LMHadPEDLL,0
+ mov OFContinueSearch,0
+ KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Found Win32 DLL again after continuing search."
+ jmps ilm_ret
+@@: jmps @F
+lm_retry_pe:
+; Tell OpenFile to restart last search at next search location.
+ mov OFContinueSearch,1
+ mov LMHadPEDLL,1
+ KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Found Win32 DLL, continuing search for Win16 copy."
+; Close open Win32 DLL file handle
+ cCall My_lclose,<fh>
+; Switch back to caller's PDB
+ mov si, -1
+ xchg si, SavePDB
+ mov Win_PDB, si
+ or fh, -1
+ jmp lm_restart
+@@:
+endif
+ cmp ax,LME_MAXERR
+ jb ilm_ret
+
+endif
+
+; Header is loaded, now see if valid for Windows
+@@: call LMCheckHeader
+ cmp ax, LME_MAXERR
+ jb ilm_ret
+
+; Now allocate segs, check for special modules, etc
+@@: call LMRamNMods
+ cmp ax, LME_MAXERR
+ jb ilm_ret
+
+; Load import libraries (scary code here)
+@@: call LMImports
+ cmp ax, LME_MAXERR
+ jb ilm_ret
+
+; Load and relocate segments
+@@: call LMSegs
+ cmp ax, LME_MAXERR
+ jb ilm_ret
+
+; Load resources, schedule execution
+@@: call LMLetsGo
+
+; Everyone comes through ILM_RET - we free the fastload block, etc
+ilm_ret:
+ call LMCleanUp
+ jmp LoadModuleEnd
+
+
+abort_load0:
+ pop fLMdepth
+abort_load:
+ cmp fLMdepth, 1 ; If a recursive call, nothing
+ jne abort_load_A ; has been incremented!
+ cCall DecExeUsage,<pExe>
+abort_load_A:
+ cCall My_lclose,<fh>
+ mov es,pExe
+ push es:[ne_flags]
+ cCall DelModule,<es>
+ mov pExe, 0
+ pop bx
+abort_load_B: ; If app, close environment
+ test bx,NENOTP
+ jnz lm_ab
+ mov si, -1
+ xchg si, SavePDB ; Saved PDB?
+ inc si
+ jz @F ; nope.
+ dec si
+ mov Win_PDB, si ; yes, restore it
+@@:
+ mov si, fLMdepth
+ mov fLMdepth, 0
+ cCall CloseApplEnv,<abortresult,es>
+ mov fLMdepth, bx
+lm_ab: mov ax, abortresult
+ retn
+; add sp, 2
+; jmps ilm_ret ; ax = abortresult. (0 normal, 11 fapi)
+
+
+ifdef WOW
+winspool db "WINSPOOL.EXE" ; Trying to Load Winspool ?
+size_winspool equ $-winspool
+ db 0h ; NULL Terminate
+
+endif ;WOW
+
+;----------------------------------------------------------------------
+;
+; LMAlreadyLoaded - internal routine for LoadModule
+; See if a module is already loaded by looking for the file name
+; or the module name.
+; Entry:
+; ES:SI points to filename
+; Exit:
+; AX = handle of previous instance
+; SS:SI -> uppercase filename
+; Error:
+; AX = error value < LME_MAXERR
+;
+;-----------------------------------------------------------------------
+LMAlreadyLoaded:
+; We check if this Module is already loaded. To do so we get the
+; name off of the end of the string, omitting the extension.
+
+ krDebugOut <DEB_TRACE OR DEB_KrLoadMod>, "Loading @ES:SI"
+ cCall lstrlen,<es,si> ; Get the length of the string.
+ or ax,ax ; NULL string?
+ jnz @F
+ mov al,LME_FNF ; return file not found error
+ retn
+
+ifdef DBCS
+;
+; Backword search '\' or ':' is prohibited for DBCS version of
+; Windows. Some DBCS 2nd byte may have '\' or ':'. So we search
+; these characters from beginning of string.
+;
+@@:
+ cld
+ mov bx,si
+delinator_loop_DBC:
+ lods byte ptr es:[si] ; fetch a character
+ test al,al
+ jz found_end_DBC
+ cmp al,"\"
+ jz found_delinator_DBC
+ cmp al,'/'
+ jz found_delinator_DBC
+ cmp al,":"
+ jz found_delinator_DBC
+ call FarMyIsDBCSLeadByte ; see if char is DBC...
+ jc delinator_loop_DBC
+ inc si ; skip 2nd byte of DBC
+ jmp delinator_loop_DBC
+
+found_delinator_DBC:
+ mov bx,si ; update delinator pointer
+if ROM
+ inc fLoadFromDisk ; PATCHING
+endif
+ jmp delinator_loop_DBC
+found_end_DBC:
+ mov si, bx ; ES:SI -> beginning of name..
+else
+@@: mov cx,ax
+ add si,ax
+ dec si ; ES:SI -> end of string
+ std
+delineator_loop: ; look for beginning of name
+ lods byte ptr es:[si]
+ cmp al,"\"
+ jz found_delineator
+ cmp al,'/'
+ jz found_delineator
+ cmp al,":"
+ jz found_delineator
+ loop delineator_loop
+ dec si
+if ROM
+ dec fLoadFromDisk ;PATCHING
+endif
+found_delineator: ; ES:SI -> before name
+if ROM
+ inc fLoadFromDisk ;PATCHING
+endif
+ cld
+ inc si
+ inc si ; ES:SI -> beginning of name
+endif
+ xor di,di
+ xor bx,bx
+copy_name_loop:
+ lods byte ptr es:[si] ; Copy and capitalize to temp buffer.
+ or al,al
+ jz got_EXE_name
+ cmp al,"."
+ jne @F
+ lea bx,namebuf[di]
+ifdef notyet
+ cmp dll, 0 ; Was it .DLL and failed to open it?
+ jz @F ; no, no hacking
+ mov byte ptr es:[si], 'E' ; yes, change it to .EXE
+ mov word ptr es:[si+1],'EX'
+ mov dll, 0
+endif
+@@:
+ifdef DBCS
+;
+; Do not capitalize if a character is DBC.
+;
+ call FarMyIsDBCSLeadByte
+ jnc @F
+ call FarMyUpper ; capitalize if SBC..
+ jmps is_a_SBC
+@@:
+ mov namebuf[di],al
+ inc di
+ lods byte ptr es:[si] ; copy 2nd byte also
+is_a_SBC:
+ mov namebuf[di],al
+else
+ call FarMyUpper
+ mov namebuf[di],al
+endif
+ inc di
+ jmps copy_name_loop
+
+; Finally call FindExeInfo to see if it's already loaded!
+
+got_EXE_name:
+ cmp namebuf[di][-2],'NO' ; .fons are allowed to be
+ jnz @F ; non protect mode
+ cmp namebuf[di][-4],'F.'
+ jnz @F
+ mov ffont,bp ; make non-zero
+@@:
+ cmp namebuf[di][-2],'EX' ; .exes will not get
+ jnz @F ; prompted
+ cmp namebuf[di][-4],'E.'
+ jnz @F
+ mov fexe,bp ; make non-zero
+@@:
+ifdef NOTYET
+ cmp namebuf[di][-2],'LL'
+ jne @F
+ cmp namebuf[di][-4],'D.'
+ jne @F
+ mov dll, di
+@@:
+endif
+ifdef WOW
+
+; apps will expect to find WINSPOOL.DRV, which is a 32-bit driver.
+; we need to intercept this and change it WINSPOOL.EXE, which is our 16-bit
+; stub that contains a few entrypoints.
+
+if 0
+ ; Bitstreams's MakeUp extracts the printer driver from the [devices]
+ ; section of win.ini the line looks like this:
+ ; HP Laserjet Series II=winspool,FILE:
+ ; and then it calls LoadLibrary(drivername) ie LoadLibrary("winspool")
+ ; so we need to allow no extension when checking for "winspool"
+endif
+
+ cmp namebuf[di][-2],'VR'
+ jne checkfornoext
+ cmp namebuf[di][-4],'D.'
+ jne @f
+
+ jmp short gotadrv
+
+checkfornoext:
+ ; int 3
+ cmp di,8
+ jc @f
+ cmp namebuf[di][-2],'LO'
+ jne @f
+ cmp namebuf[di][-4],'OP'
+ jne @f
+ cmp namebuf[di][-6],'SN'
+ jne @f
+ cmp namebuf[di][-8],'IW'
+ jne @f
+
+ ; the last 8 characters are 'WINSPOOL'. tack on '.EXE' and proceed.
+
+ add di,4
+ mov namebuf[di][-2],'EX' ; Changed Uppercased String
+ mov namebuf[di][-4],'E.'
+
+ push cx
+ mov lpModuleName.hi,cs
+ lea cx,winspool ;
+ mov lpModuleName.lo,cx
+ pop cx
+ jmp short @f
+
+gotadrv:
+ push es
+ push ds
+ push si
+ push cx
+ push di
+
+ smov es,ss
+ lea di,namebuf[di][-(size_winspool)]
+ smov ds,cs
+ lea si,winspool
+ mov cx,size_winspool-4 ; match WINSPOOL?
+ rep cmpsb
+
+ pop di
+ jnz not_winspool
+
+ mov namebuf[di][-2],'EX' ; Changed Uppercased String
+ mov namebuf[di][-4],'E.'
+
+ mov lpModuleName.hi,cs ; Used by Myopenfile below
+ lea cx,winspool ;
+ mov lpModuleName.lo,cx
+
+not_winspool:
+ pop cx
+ pop si
+ pop ds
+ pop es
+@@:
+endif; WOW
+ mov namebuf[di],al ; Null terminate file name
+ lea si,namebuf
+ push bx
+ cCall FindExeFile,<ss,si>
+ pop bx
+ or ax,ax
+ jnz al_end
+ or bx,bx ; extension specified?
+ jz @F ; No, DI correct then
+ sub bx,si ; DI = length of name portion
+ mov di,bx
+@@:
+ cCall FindExeInfo,<ss,si,di>
+al_end:
+ retn
+
+;----------------------------------------------------------------------
+;
+; LMLoadExeFile - internal routine for LoadModule
+; Try to open an EXE file
+; Enter:
+; SS:SI -> uppercase filename
+; Exit:
+; AX=0
+; DI = fh = handle of open EXE file
+; Error:
+; AX = error code
+; Effects:
+; Set Win_PDB to kernel PDB to open the file
+;
+;-----------------------------------------------------------------------
+; if here then not yet loaded, see if we can open the file
+LMLoadExeFile:
+if ROM
+ cCall <far ptr FindROMExe>,<ss,si> ; Module exist in ROM?
+ mov selROMHdr,ax ; selector mapping ROM
+ or ax,ax ; copy of EXE header if yes
+ jz @F
+ ; PATCHING
+ cmp fLoadFromDisk, 0 ; Loading this from disk? If so, go
+ jz in_rom
+@@: jmp not_in_rom ; do it, but remember selROMHdr
+ ; cause that's what we're patching
+in_rom:
+ smov es,ss ; LoadExeHeader expects an OPENSTRUC
+ cCall lstrlen,<es,si> ; containing the module file name.
+ add si,ax ; namebuf (ss:si) already contains
+ .erre opFile ; a capitalized name string, shift
+ lea di,[si].opFile ; it down to make room for the other
+ mov bx,di ; OPENSTRUC fields.
+ mov cx,ax
+ inc cx
+ std
+ rep movs byte ptr es:[di],es:[si] ; I don't think this is safe!
+
+ .errnz opLen
+ lea si,namebuf ; Now set the length field, doesn't
+ sub bx,si ; include terminating null
+ mov es:[si].opLen,bl
+
+ .erre opFile-1
+ lea di,[si.opLen+1] ; Zero out fields between length and
+ mov cx,opFile-1 ; the file name
+ xor al,al
+ cld
+ rep stosb
+
+ mov di,-1 ; no file handle in di
+ sub ax, ax ; 0 => success
+
+ retn
+
+not_in_rom:
+endif
+ mov ax, topPDB
+ xchg Win_PDB, ax ; Switch to Kernel's PDB,
+ mov SavePDB, ax ; saving current PDB
+ xor ax,ax
+ifdef notyet
+ cmp dll, ax ; Don't prompt for .DLL, if it fails we
+ jnz @F ; try for .EXE which we will prompt for
+endif
+ cmp fexe,ax ; Don't prompt for EXE file
+ jnz @F
+ mov ax,OF_CANCEL ; If DLL, let them cancel
+ mov es,curTDB
+ test es:[TDB_ErrMode],08000h ; did app say not to prompt??
+ jnz @F
+ mov ax,OF_CANCEL or OF_PROMPT
+@@:
+if SHARE_AWARE
+ or ax, OF_NO_INHERIT or OF_SHARE_DENY_WRITE
+else
+ or ax, OF_NO_INHERIT
+endif
+ifdef WOW
+ ; Ask WOW32 to check the filename to see if it is
+ ; a Known DLL,
+ ;
+ ; If it is, WowIsKnownDLL will point pszKnownDLLPath
+ ; at a just-allocated buffer with the full path to
+ ; the DLL in the system32 directory and return with
+ ; AX nonzero. This buffer must be freed with a
+ ; call to WowIsKnownDLL with the filename pointer
+ ; zero, and pszKnownDLLPath as it was left by the
+ ; first call to WowIsKnownDLL.
+ ;
+ ; If it's not a known DLL, pszKnownDLLPath will be
+ ; NULL and AX will be zero.
+
+ push ax
+ cmp fBooting,0 ; Known DLLs take effect
+ je lef_look_for_known_dll ; after booting is complete.
+
+ mov fKnownDLLOverride,0 ; We're booting, make sure
+ jmps lef_dll_not_known ; we know not to call
+ ; WowIsKnownDLL the second time.
+
+lef_look_for_known_dll:
+ push si
+ smov es,ss
+ lea bx,pszKnownDLLPath
+ cCall WowIsKnownDLL,<lpModuleName,esbx>
+ mov fKnownDLLOverride,ax
+ cmp ax,0
+ pop si
+ je lef_dll_not_known
+
+ pop ax
+ cCall MyOpenFile,<pszKnownDLLPath,ss,si,ax>
+ jmps @f
+
+lef_dll_not_known:
+ pop ax
+ cCall MyOpenFile,<lpModuleName,ss,si,ax>
+@@:
+else
+ cCall MyOpenFile,<lpModuleName,ss,si,ax>
+endif
+
+ifdef notyet
+ mov di, dll
+ or di, di
+ jz no_second_chance
+ cmp ax, -1
+ jne no_second_chance ; open succeeded
+ xchg ax, SavePDB ; Restore original PDB (AX == -1)
+ mov Win_PDB, ax
+ les si, lpModuleName
+ pop ax
+ jmp pointer_to_name ; Start again!
+no_second_chance:
+endif
+ xor dh, dh
+ mov dl, ss:[si].opDisk
+ mov OnHardDisk, dx
+ mov fh,ax
+ mov di,ax ; DI gets preserved, AX doesn't!
+ inc ax ; -1 means error or invalid parsed file
+ mov ax, 0
+ jnz @F ; OK, return 0
+ ; MyOpenFile failed
+ mov ax,ss:[si].[opXtra] ; SI = &namebuf
+ or ax,ax ; What is the error value?
+ jnz @F
+ mov ax,LME_FNF ; unknown, call it file not found
+@@:
+ifdef WOW
+ push ax
+ mov ax,fKnownDLLOverride
+ cmp ax,0
+ je lef_no_need_to_free
+
+ push bx
+ push dx
+ push di
+
+ smov es,ss
+ lea bx,pszKnownDLLPath
+ cCall WowIsKnownDLL, <0,0,esbx>
+
+ pop di
+ pop dx
+ pop bx
+lef_no_need_to_free:
+ pop ax
+endif
+ retn
+
+;----------------------------------------------------------------------
+;
+; LMCheckHeader - internal routine for LoadModule
+; Loading new module - see if header values are OK
+; Enter:
+; ax = exeheader in RAM
+; bx = 0 or FastLoad ram block selector
+; cx = file offset of header
+; dx = exe_type
+; Exit:
+;
+;
+;-----------------------------------------------------------------------
+LMCheckHeader:
+ mov exe_type,dx
+ mov hBlock,bx ; fast-load block
+ mov pExe,ax ; exeheader in RAM
+ mov es,ax
+ mov ax, cx ; file offset of header
+ mov cx, es:[ne_align]
+ mov bx, ax ; BX:AX <= AX shl CL
+ shl ax, cl
+ neg cl
+ add cl, 16
+ shr bx, cl
+
+ mov FileOffset.sel, bx
+ mov FileOffset.off, ax
+if ROM
+ test es:[ne_flags], NEMODINROM
+ jnz @F
+ cmp selROMHdr, 0
+ jnz ch_patch_file
+@@: jmp ch_not_patch_file
+
+ch_patch_file:
+ test es:[ne_flagsothers], NEGANGLOAD
+ jnz ch_replace_mod
+if 0
+ ; ack: loadexeheader trashes this...
+ mov ax, es:[ne_cseg]
+ mov ah, 2
+ cmp ax, es:[ne_gang_start]
+endif
+ jz ch_check_rom_header
+
+ ; here for a replacement file with matching file name
+ch_replace_mod:
+ inc fReplaceModule
+ jmp ch_not_patch_file
+
+ch_check_rom_header:
+ push ds
+ push si
+
+ mov cx, es:[ne_cseg]
+ mov ds, selROMHdr
+
+ ; make sure that the various patching flags match up to
+ ; what they are supposed to be
+
+ ; RIB clears this bit, check
+ test ds:[ne_flagsothers], NEGANGLOAD
+ jnz ch_patch_error
+
+ ; does it have a patch table
+ test byte ptr ds:[ne_gang_start+1], 1
+ jnz ch_is_patchable
+
+ ; if no one links to this file, its ok, don't need to patch
+ test byte ptr ds:[ne_gang_start+1], 4
+ jnz ch_patch_error
+
+ch_not_really_a_patch_file:
+ pop si
+ pop ds
+ jmp ch_not_patch_file
+
+ch_patch_error:
+ pop si
+ pop ds
+ mov ax, LME_INVEXE
+ retn
+
+ch_is_patchable:
+ ; must be the right segment
+ mov ax, ds:[ne_cseg]
+ cmp al, byte ptr ds:[ne_gang_start]
+ jnz ch_patch_error
+
+ch_whack_segment_table:
+ mov si, ds:[ne_segtab]
+ mov bx, es:[ne_segtab]
+
+ch_ps_patch_loop:
+ test es:[bx].ns_flags, NSINROM
+ jz ch_patch_loop_pass
+ mov ax, ds:[si].ns_flags
+ and ax, NSCOMPR or NSRELOC or NSLOADED or NSALLOCED
+ or es:[bx].ns_flags, ax
+
+ mov ax, ds:[si].ns_cbseg
+ mov es:[bx].ns_cbseg, ax
+
+ mov ax, ds:[si].ns_minalloc
+ mov es:[bx].ns_minalloc, ax
+
+ mov ax, ds:[si].ns_sector
+ mov es:[bx].ns_sector, ax
+ test es:[bx].ns_flags, NSLOADED
+ jz ch_patch_loop_pass
+ cmp es:[bx].ns_handle, 0
+ jnz ch_patch_loop_pass
+ mov es:[bx].ns_handle, ax
+ch_patch_loop_pass:
+ add si, size new_seg
+ add bx, size new_seg1
+ loop ch_ps_patch_loop
+
+ pop si
+ pop ds
+ch_not_patch_file:
+endif
+
+; Is this module PMode-compatible?
+ cmp es:[ne_expver],300h ; by definition
+ jae @F
+ test dh,NEINPROT ; by flag
+ jnz @F
+ cmp ffont,0 ; are we loading a font?
+ jnz @F
+ mov cx,ss
+ lea bx,namebuf
+ call WarnRealMode
+ cmp ax,IDCANCEL
+ jnz @F ; yes, user says so
+ mov ax, LME_RMODE ; no, die you pig
+ retn
+
+ifdef WOW
+@@:
+ ;
+ ; if WOA invoked by app (not fWOA) fail it
+ ;
+ cmp fWOA,0 ; fWOA
+ jnz @F
+
+ cld
+ push si
+ push di
+ mov di, es:[ne_restab]
+ inc di
+ mov si, dataOffset WOAName
+ mov cx, 4
+ repe cmpsw
+ pop di
+ pop si
+ jnz @F
+ mov ax, LME_WOAWOW32
+ retn
+endif
+
+; Are we dynalinking to a task?
+@@:
+
+
+ test es:[ne_flags],NENOTP
+ jnz ch_not_a_process
+ or es:[ne_flags],NEINST ; for safety sake
+ mov ax,lpPBlock.off
+ and ax,lpPBlock.sel
+ inc ax
+ jnz ch_new_application ; not linking
+ mov ax, LME_LINKTASK
+ retn
+
+; Error if multiple instance EXE is a library module.
+ch_not_a_process:
+ mov ax, 33 ; Any value > 32
+ test es:[ne_flags],NEPROT ; is it an OS/2 exe?
+ jnz ch_ok ; windows doesn't do this right
+ test es:[ne_flags],NEINST
+ jz ch_ok
+ mov ax, LME_LIBMDS ; I think this error code is wrong
+ch_ok:
+ retn
+
+; Create environment for new application task.
+ch_new_application:
+ call LMCheckHeap
+ or ax,ax
+ jz @F
+ cCall OpenApplEnv,<lpPBlock,pExe,fWOA>
+ mov es,pExe
+ or ax,ax ; AX is a selector, therefor > 32
+ jnz ch_ok
+@@:
+ jmp abort_load_A
+
+
+;----------------------------------------------------------------------
+;
+; LMRamNMods - internal routine for LoadModule
+; Load segments, check for special modules
+; Enter:
+; EX = pexe
+
+
+; Exit:
+; CX = number of import modules
+; AX = status
+;
+;
+;-----------------------------------------------------------------------
+LMRamNMods:
+ push es
+ cCall AddModule,<pExe>
+ pop es
+ or ax,ax
+ jnz @F
+ push es:[ne_flags] ; AddModule failed - out of memory
+ mov dx,ne_pnextexe
+ mov bx,dataOffset hExeHead
+ call FarUnlinkObject
+ pop bx
+ jmp abort_load_B ; clean this up
+
+@@:
+ cmp es:[ne_expver],400h
+ jae rm_skip_modulecompat
+
+ ; Look for Module in ModuleCompatibilty section
+ ; and get its compat flags
+ push es ; save es
+ push ds
+ push dataoffset szModuleCompatibility
+ push es
+ mov bx,es:[ne_restab] ; module name is 1st rsrc
+ inc bx ; Skip length byte
+ push bx
+ xor ax, ax
+ push ax ; default = 0
+ call GetProfileInt
+@@:
+ pop es ; restore es
+ ; Set the module's patch bit if the INI file says to.
+if KDEBUG
+ test es:[ne_flagsothers], NEHASPATCH
+ jz @F
+ push ax
+ mov ax, es:[ne_restab]
+ inc ax
+ krDebugOut DEB_TRACE,"ILoadModule: module patch bit for @es:ax already set, clearing it"
+ pop ax
+@@:
+endif
+ and es:[ne_flagsothers], not NEHASPATCH ; clear module patch bit
+ifdef WOW_x86
+ test ax, MCF_MODPATCH + MCF_MODPATCH_X86
+else
+ test ax, MCF_MODPATCH + MCF_MODPATCH_RISC
+endif
+ jz rm_after_modpatch
+if KDEBUG
+ push ax
+ mov ax, es:[ne_restab]
+ inc ax
+ krDebugOut DEB_WARN,"ILoadModule: setting module patch bit for @es:ax"
+ pop ax
+endif
+ or es:[ne_flagsothers], NEHASPATCH
+rm_after_modpatch:
+
+ ; See if we need to make the module's segments not discardable
+ test ax, MCF_NODISCARD
+ jz rm_after_nodiscard
+
+ mov cx, es:[ne_cseg] ; cx = number of segs
+ jcxz rm_after_nodiscard
+ mov bx, es:[ne_segtab] ; es:bx = seg table start
+rm_loop:
+ and es:[bx].ns_flags, not NSDISCARD ; clear the discard flag
+ add bx, SIZE NEW_SEG1 ; es:bx = seg table next entry
+ loop rm_loop
+rm_after_nodiscard:
+
+rm_skip_modulecompat:
+
+ mov bx, -1
+if ROM
+ cmp bx,fh
+ jz @F
+endif
+ cCall FarGetCachedFileHandle,<es,bx,fh> ; Set file handle cache up
+ mov fh, bx ; Use cached file handle from now
+ xchg SavePDB, bx ; Back to original PDB (BX == -1)
+ mov Win_PDB, bx
+@@: xor bx,bx
+ mov hDepFail,-1 ; Assume success
+ mov cx,es:[bx].ne_cmod
+ jcxz @F
+ test kernel_flags,KF_pUID ; All done booting?
+ jnz @F ; Yes
+ or es:[bx].ne_flags,NEALLOCHIGH ; No, GDI and USER are party
+ ; dynlinks that can alloc high
+@@: xor ax,ax
+IFNDEF NO_APPLOADER
+ test es:[ne_flags],NEAPPLOADER
+ jnz rm_no_segs_to_alloc
+ENDIF
+ cmp ax,es:[ne_cseg]
+ jz rm_no_segs_to_alloc
+ push es
+ mov es:[ne_usage],1
+ cCall AllocAllSegs,<es> ; AX is count of segs
+ pop es
+ mov es:[ne_usage],8000h
+ inc ax
+ jnz @F
+ jmp abort_load
+@@:
+ dec ax
+rm_no_segs_to_alloc:
+ mov AllocAllSegsRet, ax
+
+ xor bx, bx
+ mov di,es:[bx].ne_modtab ; ES:DI = pModIdx
+ mov cx,es:[bx].ne_cmod
+ or cx,cx
+ jz lm_ret_ok
+
+; this small chunk of code goes thru the imported names table
+; and looks for DOSCALLS. if DOSCALLS is found, then the app
+; is an FAPI "bound" application and not a windows app, and
+; loadmodule should return an error for "invalid format".
+; This will force it to run in a DOS box
+; coming in:
+; cx = cmod
+; di = modtab
+
+ test es:[bx].ne_flags,NENOTP ; only test apps, not libraries.
+ jnz lm_ret_ok
+ mov ax,exe_type ; UNKNOWN may be OS/2 in disguise.
+ cmp al,NE_UNKNOWN
+ jnz @F
+ push ds
+ smov ds,cs
+ mov ax,8
+ mov si,NRESCODEoffset os2calls ; DS:SI = "DOSCALLS"
+ call search_mod_dep_list
+ pop ds
+ jnc @F
+ mov abortresult,LME_INVEXE ; store invalid format code for return
+ jmp abort_load
+
+; In order to make it easier on our ISV to migrate to pmode
+; we must deal with win87em specially because the win 2.x
+; version gp faults. Since we have never shipped them a clean
+; one to ship with their apps we must compensate here.
+; If we are loading a win 2.x app in pmode we force the load
+; of win87em.dll. For compatibility in real mode we just load
+; the one they would have gotten anyway.
+
+@@: cmp es:[bx].ne_expver,300h ; no special casing win3.0 apps
+ jae rm_no_win87em_here
+
+ push ds
+ smov ds,cs
+ mov ax,7
+ mov si,NRESCODEoffset win87em ; DS:SI = "WIN87EM"
+ call search_mod_dep_list
+ pop ds
+ jnc rm_no_win87em_here
+ push bx ; Load Win87em.dll
+ push es
+ cCall ILoadLibrary,<cs,si>
+ cmp ax,LME_MAXERR
+ jae @F
+ mov hDepFail,ax
+@@: pop es
+ pop bx
+rm_no_win87em_here:
+lm_ret_ok:
+ mov di,es:[bx].ne_modtab ; ES:DI = pModIdx
+ mov cx,es:[bx].ne_cmod ; What is AX?
+ mov ax, es
+ retn
+
+;----------------------------------------------------------------------
+;
+; LMImports - internal routine for LoadModule
+;
+;-----------------------------------------------------------------------
+LMImports:
+ or cx, cx
+ jnz im_inc_dependencies_loop
+ jmp im_end_dependency_loop
+im_inc_dependencies_loop:
+ push cx
+ mov si,es:[di]
+ push es
+ or si,si
+ jz im_next_dependencyj
+ add si,es:[ne_imptab] ; ES:SI = pname
+ xor ax,ax
+ mov al,es:[si] ; get length of name
+ inc si
+ mov cx, ax
+ mov bx, es ; pExe
+
+;;;; Load the imported library.
+
+ push ds ; Copy the name and .EXE to namebuf
+ push di
+ smov es,ss
+ mov ds,bx
+ UnSetKernelDS
+ lea di,namebuf
+ mov bx,di
+ cld
+ rep movsb
+ mov byte ptr es:[di], 0 ; Null terminate
+ push bx
+ push es
+ cCall GetModuleHandle,<es,bx>
+ pop es
+ pop bx
+ or ax, ax
+ jz @F
+ pop di
+ pop ds
+ jmps im_imported_exe_already_loaded
+
+@@: cmp ds:[ne_expver], 300h ; USE .DLL for 3.0, .EXE for lower
+ jae im_use_dll
+
+ mov es:[di][0],"E."
+ mov es:[di][2],"EX"
+ jmps im_done_extension
+im_use_dll:
+ mov word ptr ss:[di][0],"D."
+ mov word ptr ss:[di][2],"LL"
+im_done_extension:
+ mov byte ptr es:[di][4],0
+
+ pop di
+ pop ds
+ ResetKernelDS
+ cCall ILoadLibrary,<ss,bx>
+ cmp ax,LME_MAXERR
+ jae im_imported_exe_loaded
+ mov hDepFail,ax
+ xor ax,ax
+im_next_dependencyj:
+ jmps im_next_dependency
+
+im_imported_exe_already_loaded:
+;;; push ax
+;;; cCall IncExeUsage,<ax>
+;;; pop ax
+
+im_imported_exe_loaded:
+ cCall GetExePtr,<ax>
+ mov es,ax
+ assumes es,nothing ; assume that dep libraries
+ or es:[ne_flags],NEALLOCHIGH ; are smart
+
+im_next_dependency:
+ pop es
+ assumes es,nothing
+ mov es:[di],ax
+ inc di
+ inc di
+ pop cx
+ dec cx
+ jz im_end_dependency_loop
+ jmp im_inc_dependencies_loop
+
+im_end_dependency_loop:
+ mov es:[ne_usage], 0
+ cmp fLMdepth, 1
+ jne @F
+ push es ; Now set usage count of this
+ cCall IncExeUsage,<es> ; module and dependants
+ pop es
+@@:
+ mov cx,hDepFail
+ inc cx
+ jz im_libs_ok
+ dec cx
+ mov abortresult,cx
+im_abort_loadj:
+ jmp abort_load
+im_libs_ok:
+ retn
+
+;----------------------------------------------------------------------
+;
+; LMSegs - internal routine for LoadModule
+;
+;-----------------------------------------------------------------------
+LMSegs:
+; Do something about all those segments in the module.
+
+IFNDEF NO_APPLOADER
+ test es:[ne_flags],NEAPPLOADER
+ jz @F
+;* * special boot for AppLoader
+ push Win_PDB
+ push fLMdepth
+ mov fLMdepth, 0
+ mov ax, -1
+ cCall FarGetCachedFileHandle,<es,ax,ax>
+ Save <es>
+ cCall BootAppl,<es, ax> ;* returns BOOL
+ cCall FlushCachedFileHandle,<es>
+ pop fLMdepth
+ pop Win_PDB
+ or ax,ax
+ jnz lms_done
+ jmp abort_load
+; retn
+@@:
+ENDIF ;!NO_APPLOADER
+
+ mov cx, AllocAllSegsRet
+ jcxz lms_done
+
+lms_preload_segments:
+
+ mov si,es:[ne_segtab] ; ES:SI = pSeg
+ mov cx,es:[ne_cseg]
+ xor di,di
+lms_ps_loop:
+ inc di
+if ROM
+ mov bx,es:[si].ns_flags ; Load the segment now if it's execute
+ and bx,NSINROM OR NSLOADED ; in place in the ROM.
+ cmp bx,NSINROM OR NSLOADED
+ je lms_ReadFromRom
+endif
+ test es:[si].ns_flags,NSPRELOAD
+ jz lms_next_segment
+if ROM
+ test byte ptr es:[si].ns_flags+1,(NSINROM SHR 8)
+ jnz lms_ReadFromRom
+endif
+ cmp es:[ne_align], 4 ; Must be at least paragraph aligned
+ jb lms_ReadFromFile
+ cmp hBlock, 0
+ jne lms_ReadFromMemory
+ jmps lms_ReadFromFile
+
+lms_next_segment:
+ add si,SIZE new_seg1
+ loop lms_ps_loop
+lms_done:
+ retn
+
+if ROM
+lms_ReadFromRom:
+ push cx
+ push es
+ cCall FarLoadSegment,<es,di,0,-1>
+ jmps lms_DoneLoad
+endif
+
+lms_ReadFromFile:
+ push cx
+ push es
+ cCall FarLoadSegment,<es,di,fh,fh>
+ jmps lms_DoneLoad
+
+lms_ReadFromMemory:
+ push cx
+ push es
+ cCall GlobalLock,<hBlock>
+ or dx, dx
+ jnz lms_still_here
+ cCall GlobalFree,<hBlock>
+ mov hBlock, 0
+ pop es
+ pop cx
+ jmps lms_ReadFromFile
+
+lms_still_here:
+ifdef WOW
+ cCall AllocSelectorWOW,<dx> ; same as allocselector. but the
+ mov RefSelector, dx ; new descriptor is not set.
+else
+ cCall AllocSelector,<dx>
+endif
+ pop es
+ mov bx, es:[si].ns_sector
+ xor dx, dx
+ mov cx, es:[ne_align]
+ push es
+@@:
+ shl bx, 1
+ rcl dx, 1
+ loop @B
+
+ sub bx, off_FileOffset
+ sbb dx, seg_FileOffset
+ push ax
+ push es
+ifdef WOW
+ ; same as longptradd. but the descriptor 'RefSelector' is used
+ ; to set the descriptor of 'ax'
+ cCall LongPtrAddWOW,<ax,cx,dx,bx, RefSelector, 1> ; (cx is 0)
+else
+ cCall LongPtrAdd,<ax,cx,dx,bx> ; (cx is 0)
+endif
+ pop es
+ dec cx
+ cCall FarLoadSegment,<es,di,dx,cx>
+ pop cx
+ push ax
+ cCall FreeSelector,<cx>
+ cCall GlobalUnlock,<hBlock>
+ pop ax
+lms_DoneLoad:
+ pop es
+ pop cx
+ or ax,ax
+ jz lms_abort_load1
+ jmp lms_next_segment
+lms_abort_load1:
+ jmp abort_load
+
+;-----------------------------------------------------------------------
+;
+; LMLetsGo -
+;
+;-----------------------------------------------------------------------
+LMLetsGo:
+ push es
+ push Win_PDB ; Save current PDB
+ push topPDB ; Set it to Kernel's
+ pop Win_PDB
+if ROM
+ ;
+ ; the cases are:
+ ;
+ ; 1 loading a ROM module:
+ ; selROMHdr <> 0, fLoadFromDisk == fReplaceModule == 0
+ ;
+ ; 2 loading a patch module:
+ ; selROMHdr, fLoadFromDisk <> 0, fReplaceModule == 0
+ ;
+ ; 3 loading an override module with same name:
+ ; selROMHdr <> 0, fReplaceModule <> 0, fLoadFromDisk == ?
+ ;
+ ; 4 loading an override module with a different name:
+ ; selROMHdr == fReplaceModule == 0
+ ;
+ ; 5 loading a module not in rom at all
+ ; selROMhdr == fReplaceModule == 0
+
+ ; is it case 4 or 5
+
+ mov ax, selROMHdr
+ or ax, fReplaceModule
+ jnz lg_no_rom_header
+
+ ; never replace a process
+ test es:[ne_flags],NENOTP
+ jz lg_file_load_res
+
+ push es
+ cCall <far ptr FindROMModule>, <es>
+ pop es
+
+ ; is it case 5
+ inc ax ; -1 = not found
+ jz lg_file_load_res
+ dec ax ; 0 = couldn't alloc selector
+ jnz lg_found_rom_same_name
+
+ ; ax == 0 => out of memory
+ mov ax, LME_MEM
+ retn
+
+lg_found_rom_same_name:
+ mov selROMHdr, ax
+ mov fReplaceModule, ax
+
+lg_no_rom_header:
+ ; is it case 3 or 4
+ cmp fReplaceModule, 0
+ jz @F
+
+ push es
+ cCall <near ptr ReplacePatchTable>, <es,selROMHdr>
+ pop es
+ or ax, ax
+ jmp lg_file_load_res
+
+ ; is it case 1 or 2?
+ sub cx, cx
+@@: cmp fLoadFromDisk, 0
+ jz lg_resFromFile
+
+ ; loading a patch file; set the patch table selector, then
+ ; fall through to load resources
+ push ds
+ mov ds, selROMHdr
+ mov si, ds:[ne_cseg]
+ dec si
+ shl si, 3
+ add si, ds:[ne_segtab]
+ mov bx, ds:[si].ns_sector
+ pop ds
+
+ .errnz 2 + size new_seg - size new_seg1
+ ; also assumes both exehdrs have same ne_segtab!!!!
+
+ add si, es:[ne_cseg]
+ add si, es:[ne_cseg]
+ sub si, 2
+ mov ax, es:[si].ns_handle
+ Sel_To_Handle ax
+
+ cCall ChangeROMHandle, <ax,bx>
+ mov es:[si].ns_handle, bx
+
+lg_file_load_res:
+endif
+ mov ax, -1
+ cCall FarGetCachedFileHandle,<es,ax,ax>
+if ROM
+ mov cx, selROMHdr
+endif
+ cmp hBlock,0
+ je lg_resFromFile
+
+if ROM
+ cCall PreloadResources,<es,ax,hBlock,FileOffset,0>
+else
+ cCall PreloadResources,<es,ax,hBlock,FileOffset>
+endif
+ jmps lg_gotRes
+
+lg_resFromFile:
+ xor dx, dx
+if ROM
+ cCall PreloadResources,<es,ax,dx,dx,dx,cx>
+else
+ cCall PreloadResources,<es,ax,dx,dx,dx>
+endif
+lg_gotRes:
+ pop Win_PDB ; Restore PDB
+ pop es
+ mov ax,lpPBlock.off
+ mov dx,lpPBlock.sel
+ and ax,dx
+ inc ax
+ jnz lg_huh
+ mov lpPBlock.off,ax
+ mov lpPBlock.sel,ax
+lg_huh: xor ax,ax ; free 0
+ push fLMdepth
+ mov fLMdepth, 0
+ push es
+ cCall StartModule,<ax,lpPBlock,es,fh>
+ pop es
+ mov hResult,ax
+ or ax,ax
+ jnz @F
+ jmp abort_load0
+
+@@: test es:[ne_flags],NENOTP
+ jnz lg_not_a_process2
+
+ pop si
+ cCall CloseApplEnv,<hResult,pExe>
+ push bx
+ mov hResult,ax
+ mov hTDB,dx
+lg_not_a_process2:
+ pop fLMdepth
+ retn
+
+
+;----------------------------------------------------------------------
+;
+; LMPrevInstance - internal routine for LoadModule
+; Load an app/dll if a previous instance in memory
+; Entry:
+; ax = handle of previous instance
+; Exit:
+; ax = status to return
+; dx = hTDB = TDB
+; Error:
+; ax < LME_MAXERR
+;
+;-----------------------------------------------------------------------
+LMPrevInstance:
+ mov es,ax
+ mov dx,es:[ne_flags]
+ mov si,ax
+ mov pExe,ax ; why store in pExe and hExe?
+ mov hResult,0
+
+if ROM
+; Error if multiple instance of ROM app with instance or auto data
+; (actually this might be okay if there are no entry points that need
+; to be patched--would require checks like in PatchCodeHandle).
+
+ test dh,(NENOTP SHR 8) ; okay if not a process
+ jnz @F
+ test dl,NEMODINROM ; module in rom?
+ jz @F
+
+ test dl,NEINST ; app have instance data?
+ jnz pi_mds
+ cmp es:[ne_autodata],0 ; how about an autodata segment?
+ jnz pi_mds ; can't patch the ROM code so can't
+ ; run the 2nd instance
+@@:
+endif
+
+; Error if dynamically linking to non-library module.
+ mov ax,lpPBlock.off
+ and ax,lpPBlock.sel
+ inc ax
+ jnz pi_app
+ test dx,NENOTP
+ jnz @F
+ mov ax, LME_LINKTASK ; can't dynalink to a task
+ retn
+
+@@: mov lpPBlock.off,ax ; AX == 0
+ mov lpPBlock.sel,ax
+pi_app:
+ test dx,NEINST
+ jnz @F
+ jmp pi_not_inst
+@@: call LMCheckHeap
+ or ax, ax
+ jnz @F
+ mov ax, LME_MEM ; Out of (gdi/user) memory
+ retn
+@@:
+
+ifdef WOW
+ ;
+ ; if WOA invoked by app (not fWOA) fail it
+ ;
+ cmp fWOA,0 ; fWOA
+ jnz pi_not_multiple_data
+
+ cld
+ push si
+ push di
+ mov di, es:[ne_restab]
+ inc di
+ mov si, dataOffset WOAName
+ mov cx, 4
+ repe cmpsw
+ pop di
+ pop si
+ jnz @F
+ mov ax, LME_WOAWOW32
+ retn
+@@:
+endif
+
+
+
+; We refuse to load multiple instances of apps that have
+; multiple data segments. This is because we cannot do
+; fixups to these other data segments. What happens is
+; that the second copy of the app gets fixed up to the
+; data segments of the first application. For the case
+; of read-only data segments we make an exception since
+; what does it matter who the segments belong to?
+
+ mov ax, 2 ; if we have >= 2 dsegs we die
+ mov es,si
+ mov cx,es:[ne_cseg]
+ mov bx,es:[ne_segtab]
+pi_next_seg:
+ test es:[bx].ns_flags,NSDATA ; scum! this barely works!
+ jz @F
+ test es:[bx].ns_flags,NSERONLY
+ jnz @F
+ dec ax
+ jnz @F ; two data segments is one too many!
+pi_mds: mov ax, LME_APPMDS
+ retn
+
+@@: add bx,SIZE NEW_SEG1
+ loop pi_next_seg
+
+pi_not_multiple_data: ; Prepare the application
+ cCall OpenApplEnv,<lpPBlock,si,fWOA>
+ cCall GetInstance,<si> ; Why do we call this?
+ mov di,ax
+ cCall IncExeUsage,<si>
+ cCall AllocAllSegs,<si> ; Can we get memory?
+ inc ax
+ jnz @F
+ cCall DecExeUsage,<si> ; AllocAllSegs failed, Dec Usage
+ jmps pi_mem ; Must have failed from no memory
+
+@@: mov ax,-1
+ cCall StartModule,<di,lpPBlock,si,ax>
+; mov hResult,ax
+ or ax,ax
+ jnz @F
+ mov es,si ; StartModule failed, FreeModule
+ mov si,es:[ne_pautodata]
+ cCall FreeModule,<es:[si].ns_handle>
+pi_mem: mov ax, LME_MEM
+ retn
+
+@@: mov si, fLMdepth
+ mov fLMdepth, 0
+ cCall CloseApplEnv,<ax,pExe>
+ mov fLMdepth, bx
+ mov hTDB,dx
+ retn
+
+pi_not_inst:
+ mov ax,es:[ne_autodata] ; Make sure data segment is loaded.
+ or ax,ax
+ jz @F
+ or bx,-1
+ push es
+ cCall FarLoadSegment,<es,ax,bx,bx>
+ pop es
+ or ax,ax
+ jz pi_end ; yes, AX is already 0, but ...
+@@:
+ push es ; for GetInstance
+ cCall IncExeUsage,<es>
+ cCall GetInstance ; ,<pExe>
+pi_end:
+ retn
+
+;----------------------------------------------------------------------
+;
+; LMCleanUp - internal routine for LoadModule
+;
+;-----------------------------------------------------------------------
+LMCleanUp:
+ifdef WOW
+ cmp LMHadPEDLL,0
+ je @F
+ cmp ax, LME_MAXERR
+ jae @F
+ mov ax,LME_PE ; Reflect real error we tried to mask
+ KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Could not find Win16 copy of Win32 DLL, returning LME_PE."
+@@:
+endif
+ push ax ; save status for future
+ cmp ax, LME_MAXERR
+ jae @F
+ cCall my_lclose,<fh>
+ or fh, -1
+
+; Restore PDB if needed
+@@: mov ax, -1
+ xchg SavePDB, ax
+ inc ax
+ jz @F
+ dec ax
+ mov Win_PDB, ax
+
+; Free FastLoad block if allocated
+@@: cmp hBlock,0
+ je @F
+ cCall GlobalFree,<hBlock>
+ mov hBlock,0
+
+if ROM
+; Free ROM selector if allocated
+@@:
+ mov ax,selROMHdr ; FindROMExe allocates a selector
+ or ax,ax ; to the ROM Exe Header if found.
+ jz @F ; Free it here.
+ cCall far_free_temp_sel,<ax>
+endif
+
+; Free app environment if failure and this was an app
+@@:
+ pop ax
+ cmp ax,LME_MAXERR
+ jae @F
+if KDEBUG
+ cmp ax, LME_INVEXE ; invalid format (WinOldAp)
+ jz cu_fred
+ cmp ax, LME_PE ; Win32 Portable Exe - try to load it
+ jz cu_fred
+ push ax
+ push bx
+ push es
+ les bx, lpModuleName
+ KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Error 0x#ax loading @ES:BX"
+ pop es
+ pop bx
+ pop ax
+endif
+cu_fred:
+ cmp loadTDB,0
+ je @F
+ mov bx,pExe
+ cmp bx,LME_MAXERR ; Did we load an ExeHeader?
+ jbe @F
+ mov es,bx
+ test es:[ne_flags],NENOTP
+ jnz @F
+ mov si, fLMdepth
+ mov fLMdepth, 0
+ cCall CloseApplEnv,<ax,es>
+ mov fLMdepth, bx
+
+; shouldn't cache file handles on removable devices cause it
+; makes share barf when the user swaps disks. this kills some
+; install apps. CraigC 8/8/91
+@@:
+ push ax
+ cmp ax, LME_MAXERR ; real?
+ jbe @F
+ cmp OnHardDisk, 0 ; is it on a removable device?
+ jne @F
+ cCall GetExePtr, <ax> ; get module handle
+ cCall FlushCachedFileHandle, <ax> ; blow that sucker off
+
+;** Log this entry only if in diagnostic mode
+@@:
+ cmp fDiagMode,0 ; Only log if in diag mode
+ je LM_NoDiagExit
+ cmp fBooting,0 ; Only log if booting
+ je LM_NoDiagExit
+
+ pop ax ; Get the return code early
+ push ax
+
+ pusha ; Save all the registers
+ push ds
+ push es
+
+ ;** Write out the appropriate string
+ mov si,ax ; Save the return value
+ cmp ax,LME_MAXERR
+ jae LM_DiagSuccess
+ mov ax,dataOFFSET szLoadFail ; Write the string
+ jmp SHORT LM_DiagOutput
+LM_DiagSuccess:
+ mov ax,dataOFFSET szLoadSuccess ; Write the string
+LM_DiagOutput:
+ cCall DiagOutput, <ds,ax>
+ cCall DiagOutput, <lpModuleName>
+ cmp si,LME_MAXERR ; Don't do this on success
+ jae SHORT LM_DiagSuccessSkip
+
+ ;** Log a message complete with the failure code
+ mov ax,si ; Get the failure code
+ shr al, 4
+ mov bx,dataOFFSET szCodeString ; Point to the second digit
+ push NREScodeOffset afterHex
+ call toHex
+ mov ax, si
+ inc bx
+toHex:
+ and al,0fh ; Get low hex digit
+ add al,'0' ; Convert to ASCII
+ cmp al,'9' ; Letter?
+ jbe @F ; Yes
+ add al,'A' - '0' ; Make it a letter
+@@: mov [bx],al ; Save the digit
+ retn
+afterHex:
+ mov ax,dataOFFSET szFailCode ; Get the string 'Failure code is '
+ cCall DiagOutput, <ds,ax>
+LM_DiagSuccessSkip:
+ mov ax,dataOFFSET szCRLF
+ cCall DiagOutput, <ds,ax>
+
+ pop es
+ pop ds
+ popa
+
+LM_NoDiagExit:
+ pop ax
+ dec fLMdepth
+ mov dx,hTDB
+ retn
+
+;@@end
+
+;shl_ax16: ; shift AX into DX:AX by cl bits
+; mov dx, ax
+; shl ax, cl
+; neg cl
+; add cl, 16 ; cl = 16 - cl
+; shr dx, cl
+; retn
+
+LoadModuleEnd: ; jmp here to clean up stack and RET
+
+ifdef WOW
+ cmp ax, LME_MAXERR
+ jb @F
+lmntex:
+ jmp LoadModuleExit
+@@:
+
+;
+; Exec For Non 16 Bit Windows Apps
+;
+ ;
+ ; WIN 32S App ? yes -> let NT load it
+ ;
+ cmp ax,LME_PE
+ je LM_NTLoadModule
+
+
+ ;
+ ; if an app is spawning WOA (NOT our internal load-fWOA),
+ ; Patch lpModuleName to -1 let NT load it
+ ;
+ cmp ax,LME_WOAWOW32
+ jne @F
+ mov word ptr lpModuleName[2], -1 ; patch lpModuleName
+ mov word ptr lpModuleName[0], -1
+ jmp short LM_NTLoadModule
+@@:
+
+ ; Errors 11-15 -> let NT load it
+ cmp ax,LME_RMODE
+ jae lmntex
+
+ cmp ax,LME_VERS
+ jbe lmntex
+
+
+ public LM_NTLoadModule
+LM_NTLoadModule:
+;
+; WOW Execs non-windows apps using WINOLDAP.
+;
+
+; First check for loading of a 32bit DLL. lpPBlock will be -1
+; in such a case.
+
+ push ax
+ mov ax,lpPBlock.off
+ and ax,lpPBlock.sel
+ inc ax
+ pop ax
+ jz LoadModuleExit
+
+;
+; This is an EXE, but the LME_PE failure code might have come from
+; an implicitly linked DLL. If so, we don't want to try having
+; Win32 lauch the win16 EXE, as it will just come back to us.
+;
+ cmp ax,LME_PE
+ jne @F
+ cmp ax,hDepFail
+ je short LoadModuleExit
+@@:
+ sub sp, 80 ; alloc space for cmdline
+ mov di, sp
+ smov es, ss
+ mov word ptr es:[di], 0 ; set WindOldApp CmdLine to NULL
+ regptr esdi,es,di
+ cCall WowLoadModule,<lpModuleName, lpPBlock, esdi>
+
+ ;
+ ; if ax < 33 an error occurred
+ ;
+ cmp ax, 33
+ jb ex8
+
+ or Kernel_flags[1],KF1_WINOLDAP
+ mov ax, ss
+ les si,lpPBlock
+ mov es:[si].lpcmdline.off,di
+ mov es:[si].lpcmdline.sel,ax
+ mov si,dataOffset WOAName
+ regptr dssi,ds,si
+ cCall LoadModule,<dssi, lpPBlock>
+ cmp ax,32 ; check for error...
+ jae ex8
+
+ ;
+ ; LoadModule of WinOldApp failed
+ ; Call WowLoadModule to clean up process handle
+ ;
+ push ax
+ mov ax, ss
+ regptr axdi,ax,di
+ cCall WowLoadModule,<0, lpPBlock, axdi>
+ pop ax
+
+ cmp ax,2 ; file not found?
+ jnz ex7 ; no, return error
+ mov al, LME_WOAWOW32 ; flag WINOLDAP error
+ex7:
+ or ax,ax ; out of memory?
+ jnz ex8
+ mov ax,8h ; yes, return proper error code
+ex8:
+ add sp,80 ; free space for cmdline
+endif; WOW
+
+LoadModuleExit:
+
+cEnd
+
+?DOS5 = ?SAV5
+
+;-----------------------------------------------------------------------;
+; My_lclose
+;
+; Close file handle if it isn't -1.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc My_lclose,<PUBLIC,NEAR>
+ parmW fh
+cBegin
+ mov ax,fh
+ inc ax
+ jz mlc_exit
+
+ cCall _lclose,<fh>
+mlc_exit:
+cEnd
+
+
+if ROM
+
+;-----------------------------------------------------------------------;
+; FindROMExe
+;
+; Locates the ROM EXE header for a module in ROM.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FindROMExe,<PUBLIC,FAR>,<ds,es,di,si>
+ parmD lpFileName
+cBegin
+ xor ax,ax ; calculate length of
+ mov cx,-1 ; file name, include
+ les di,lpFileName ; terminating null in count
+ cld
+ repne scasb
+ not cx
+ jcxz fre_exit
+
+ cmp cx,File_Name_Len ; can't be in rom if name
+ ja fre_exit ; is too long
+
+ call MapDStoDATA
+ ReSetKernelDS
+
+ mov ds,selROMTOC ; search ROM TOC for matching
+ UnSetKernelDS ; module name
+ mov bx,ds:[cModules] ; # modules in ROM TOC
+ mov ax,ModEntries+FileNameStr ; offset in ROM TOC of 1st name
+
+ les di,lpFileName
+ mov dx,cx
+
+fre_next:
+ mov si,ax ; search ROM TOC, entry by entry
+ push ax
+next_chr:
+ mov al, es:[di]
+ call FarMyUpper ; case insensitive
+ cmp al, ds:[si]
+ jne @f
+ inc si
+ inc di
+ loop next_chr
+ pop ax
+ jmps fre_got_it
+@@:
+ pop ax
+ dec bx
+ jz fre_failed
+ mov cx,dx
+ add ax,size MODENT
+ mov di,lpFileName.off
+ jmps fre_next
+
+fre_failed:
+ xor ax,ax ; no matching module, return 0
+ jmps fre_exit
+
+fre_got_it:
+ mov si,ax ; return selector pointing
+ sub si,FileNameStr
+ mov ax,word ptr [si.lmaExeHdr] ; to ROM copy of module
+ mov dx,word ptr [si.lmaExeHdr+2] ; EXE header
+ cCall far_alloc_data_sel16,<dx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+
+fre_exit:
+
+cEnd
+
+endif ;ROM
+
+
+
+if ROM
+
+;-----------------------------------------------------------------------;
+; FindROMFile
+;
+; Locates the start of a file in ROM ( for true-type files esp.)
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; adapted from FindROMExe -- 8/8/91 -- vatsanp
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FindROMFile,<PUBLIC,FAR>,<ds,es,di,si>
+ parmD lpFileName
+ parmD lpfsize
+cBegin
+ xor ax,ax ; calculate length of
+ mov cx,-1 ; file name, include
+ les di,lpFileName ; terminating null in count
+ cld
+ repne scasb
+ not cx
+ jcxz frf_failed ; to frf_exit
+
+ cmp cx,File_Name_Len ; can't be in rom if name
+ ja frf_exit ; is too long
+
+ call MapDStoDATA
+ ReSetKernelDS
+
+ mov ds,selROMTOC ; search ROM TOC for matching
+ UnSetKernelDS ; file name
+ mov bx,ds:[cModules] ; # modules in ROM TOC
+ mov ax, SIZE MODENT
+ mul bx
+ mov bx,ModEntries+fname ; offset in ROM TOC of 1st name
+ add ax, bx
+ mov bx,ds:[cFiles] ; # Files in ROM TOC
+
+ les di,lpFileName
+ mov dx,cx
+
+frf_next:
+ mov si,ax ; search ROM TOC, entry by entry
+ cld
+ repe cmpsb
+ je frf_got_it
+ dec bx
+ jz frf_failed
+ mov cx,dx
+ add ax,size FILENT
+ mov di,lpFileName.off
+ jmps frf_next
+
+frf_failed:
+ xor ax,ax ; no matching module, return 0
+ jmps frf_exit
+
+frf_got_it:
+ mov si,ax ; return selector pointing
+ sub si,fname
+ les di,lpfsize
+ mov cx, word ptr [si.fsize] ; massage fsize into paras
+ mov word ptr es:[di], cx
+ mov ax, word ptr [si.fsize+2]
+ mov word ptr es:[di+2], ax
+ shl ax, 12
+ add cx, 15 ; round off
+ shr cx, 4
+ or cx, ax
+ mov ax,word ptr [si.lma] ; to ROM copy of file
+ mov dx,word ptr [si.lma+2]
+ cCall far_alloc_data_sel16,<dx,ax,cx>
+if PMODE32
+ add cx, 0FFFh ; compute #sels allocated
+ rcr cx, 1
+ shr cx, 11 ; cx = # of sels allocated
+ mov dx, ax ; save
+anudder_sel:
+ cCall HocusROMBase, <ax> ; for each of those sels
+ add ax, 8 ; next sel
+ loop anudder_sel
+ mov ax, dx ; restore
+endif
+
+frf_exit:
+
+cEnd
+
+endif ;ROM
+;-----------------------------------------------------------------------;
+; WarnRealMode
+;
+; Trayf for files in the form "Insert WIN.EXE disk in drive A:"
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 07-Oct-1989 17:12:43 -by- David N. Weise [davidw]
+; Wrote it! A month or so ago.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WarnRealMode,<PUBLIC,NEAR>
+cBegin nogen
+ ReSetKernelDS
+ push Win_PDB
+ push fLMDepth
+ cld
+ mov ax,IDCANCEL ; assume booting
+ test fBooting,1
+ jnz promptly_done
+ cmp pMBoxProc.sel,0 ; is there a USER around yet?
+ jz promptly_done
+ push di
+ push si
+ push es
+ mov es,cx
+ifdef DBCS
+;Japan and Korea declare that they need more space for DBCS msg.
+;It sounds like this is one of common requirement for DBCS enabling
+;although Taiwan doesn't claim she has the same requirement.
+;I enclosed this code fragment under DBCS and it can be removed
+;if somebody thinks it is not necessary.
+ sub sp, 530
+else
+ sub sp,512
+endif
+ mov di,sp
+ mov si,offset msgRealModeApp1
+ push ds
+ smov ds,cs
+ UnSetKernelDS
+ call StartString
+ smov ds,cs
+ mov si,offset msgRealModeApp2
+ call Append
+ pop ds
+ ReSetKernelDS
+
+ mov bx,sp
+ xor ax,ax
+ push ax ; Null hwnd
+ push ss
+ push bx ; (lpstr)text
+ push cs
+ mov ax,offset szProtectCap
+ push ax ; (lpstr)caption
+ mov ax,MB_OKCANCEL or MB_ICONEXCLAMATION or MB_DEFBUTTON2 or MB_SYSTEMMODAL
+ push ax ; wType
+ call [pMBoxProc] ; Call USER.MessageBox
+ifdef DBCS
+ add sp, 530
+else
+ add sp,512
+endif
+ pop es
+ pop si
+ pop di
+
+promptly_done:
+ pop fLMDepth
+ pop Win_PDB
+ ret
+
+cEnd nogen
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+StartString:
+ call Append ; append first string
+
+; Now append the file name
+
+ push di
+ lea di,[bx].opFile ; skip past length, date, time
+
+ call NResGetPureName ; strip off drive and directory
+ smov ds,es
+ mov si,di
+ pop di
+
+; Append ASCIIZ string to output buffer, DS:DX points to string
+
+ assumes ds,nothing
+ assumes es,nothing
+
+Append: lodsb
+ stosb
+ or al,al
+ jnz Append
+ dec di
+ ret
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+; NResGetPureName
+;
+; Returns a pointer the the filename off the end of a path
+;
+; Entry:
+; ES:DI => path\filename
+; Returns:
+; ES:DI => filename
+; Registers Destroyed:
+;
+; History:
+; Wed 18-Oct-1989 20:01:25 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc NResGetPureName,<PUBLIC,NEAR>
+cBegin nogen
+
+ifdef DBCS
+;
+; It is not possible to search filename delimiter by backword search
+; in case of DBCS version. so we use forword search instead.
+;
+ mov bx,di
+iup0:
+ mov al,es:[di]
+ test al,al ; end of string?
+ jz iup2 ; jump if so
+ inc di
+ cmp al,'\'
+ jz iup1
+ cmp al,'/'
+ jz iup1
+ cmp al,':'
+ jz iup1
+ call FarMyIsDBCSLeadByte ; see if char is DBC
+ jc iup0 ; jump if not a DBC
+ inc di ; skip to detemine 2nd byte of DBC
+ jmp iup0
+iup1:
+ mov bx,di ; update purename candidate
+ jmp iup0
+iup2:
+ mov di,bx ; di points purename pointer
+ ret
+else
+ cld
+ xor al,al
+ mov cx,-1
+ mov bx,di
+ repne scasb
+ inc cx
+ inc cx
+ neg cx
+iup0: cmp bx,di ; back to beginning of string?
+ jz iup1 ; yes, di points to name
+ mov al,es:[di-1] ; get next char
+ cmp al,'\' ; next char a '\'?
+ jz iup1 ; yes, di points to name
+ cmp al,'/' ; next char a '/'
+ jz iup1
+ cmp al,':' ; next char a ':'
+ jz iup1 ; yes, di points to name
+ dec di ; back up one
+ jmp iup0
+iup1: ret
+endif
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; search_mod_dep_list
+;
+; Searches the dependent module list for the passed in name.
+;
+; Entry:
+; AX = length of name to search for
+; CX = count of modules
+; DS:SI => module name to search for
+; ES:DI => module table
+; Returns:
+;
+; Registers Preserved:
+; AX,BX,CX,DI,SI,ES
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 07-Oct-1989 17:12:43 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc search_mod_dep_list,<PUBLIC,NEAR>
+cBegin nogen
+
+ push bx
+ push cx
+ push di
+ mov bx,di
+
+search_mod_loop:
+ mov di,es:[bx] ; es:di = offset into imptable
+ add di,es:[ne_imptab]
+ cmp es:[di],al ; does len of entry = sizeof(doscalls)
+ jnz get_next_entry
+
+ push cx ; cx holds count of module entries.
+ push si
+ inc di ; es:di = import module name
+ mov cx,ax
+ rep cmpsb
+ pop si
+ pop cx
+ stc
+ jz got_it
+
+get_next_entry:
+ inc bx
+ inc bx
+ loop search_mod_loop
+ clc
+got_it: pop di
+ pop cx
+ pop bx
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; LMCheckHeap
+;
+; This checks for 4K free space in both USER's and GDI's data
+; segments. If this space does not exist then we will not load
+; the app. This is better than the hose-bag way we did things
+; under win 1 and 2.
+;
+; Entry:
+; nothing
+;
+; Returns:
+; AX != 0 lots o'space
+;
+; Registers Destroyed:
+; BX,CX
+;
+; History:
+; Sat 28-Oct-1989 17:49:09 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+MIN_RSC = 10
+cProc LMCheckHeap,<PUBLIC,NEAR>,<ds>
+cBegin
+ SetKernelDSNRES
+ifdef WOW
+ ; USER32 and GDI32 can deal with memory alloc no need check heaps on WOW
+ mov ax,-1 ; WOW doesn't have GDI or User heaps
+else ; so don't check them.
+ mov ax, MIN_RSC
+ cmp word ptr pGetFreeSystemResources[2],0
+ jz @F
+ cCall pGetFreeSystemResources,<0>
+ cmp ax, MIN_RSC
+ jae @F
+if kdebug ; test low memory code if DEBUG
+ krDebugOut DEB_WARN, "Resources #ax% - this tests your error handling code"
+ or al, 1
+else
+ xor ax, ax ; you failed - g'bye
+endif
+@@:
+endif ; WOW
+ ReSetKernelDS
+cEnd
+
+if 0
+cProc check_gdi_user_heap_space,<PUBLIC,NEAR>
+cBegin nogen
+
+ ReSetKernelDS
+
+ifdef WOW
+ ; USER32 and GDI32 can deal with memory alloc no need check heaps on WOW
+ mov ax,-1 ; WOW doesn't have GDI or User heaps
+else ; so don't check them.
+ cmp graphics,0
+ jz c_ret
+ push dx
+ push es
+ push ds
+ mov ds,hGDI
+ UnSetKernelDS
+ call checkit_bvakasha
+ or ax,ax
+ jz c_exit
+ pop ds
+ ReSetKernelDS
+ push ds
+ mov ds,hUser
+ UnSetKernelDS
+ call checkit_bvakasha
+c_exit: pop ds
+ pop es
+ pop dx
+c_ret: ret
+
+ public checkit_bvakasha
+checkit_bvakasha:
+ mov bx,ds:[ne_pautodata]
+ cCall FarMyLock,<ds:[bx].ns_handle>
+ mov ds,ax
+ call LocalCountFree
+ sub ax,4095
+ ja cguhs_exit
+ neg ax
+ mov bx,LA_MOVEABLE
+ cCall LocalAlloc,<bx,ax>
+ or ax,ax
+ jz cguhs_exit
+free_User_piece:
+ cCall LocalFree,<ax>
+ mov ax,sp ; return non-zero
+cguhs_exit:
+endif ;WOW
+ ret
+cEnd nogen
+endif
+
+;-----------------------------------------------------------------------;
+; GetHeapSpaces
+;
+;
+; Entry:
+; nothing
+;
+; Returns:
+; AX = free space (bytes) of User heap assuming heap can grow to 64K
+; DX = free space (bytes) of GDI heap assuming heap can grow to 64K
+; Registers Destroyed:
+;
+; History:
+; Wed 10-Jan-1990 22:27:38 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetHeapSpaces,<PUBLIC,FAR>,<di,si>
+
+ parmW hInstance
+cBegin
+ call MapDStoDATA
+ ReSetKernelDS
+ cCall FarMyLock,<hInstance>
+ or ax,ax
+ jz ghs_exit
+ mov ds,ax
+ cmp ds:[ne_magic],NEMAGIC
+ jnz ghs_must_be_data
+ mov bx,ds:[ne_pautodata]
+ cCall FarMyLock,<ds:[bx].ns_handle>
+ mov ds,ax
+ghs_must_be_data:
+ call LocalCountFree
+ mov si,ax
+ cCall GlobalSize,<ds>
+ neg ax
+ add ax,si ; AX = size of free assuming 64K
+ mov cx,si ; CX = size of free
+ mov dx,-1
+ sub dx,ds:[pLocalHeap] ; DX = size of heap
+
+ghs_exit:
+
+cEnd
+
+if ROM
+
+;-----------------------------------------------------------------------;
+; FindROMModule
+;
+; search through the the exehdr's listed in the ROM TOC for a specific
+; module name
+;
+; Entry:
+; Returns:
+; Registers Destroyed:
+;
+; History:
+; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+cProc FindROMModule, <PUBLIC,FAR>, <si, di>
+ parmW hExe
+cBegin
+ push ds
+ call MapDSToData
+ ResetKernelDS
+ mov es, selROMTOC
+ mov ds, hExe
+ UnsetKernelDS
+ mov cx, es:[cModules] ; get number of modules
+ lea bx, es:[ModEntries] ; point to first module
+
+frm_loop:
+ push cx ; save count
+ lea di, [bx].ModNameStr ; point to module name string
+ mov si, ds:[ne_restab] ; point to res name table
+ sub cx, cx
+ lodsb ; get count in name table
+ mov cl, al
+ repe cmpsb ; compare up to that length
+ jnz frm_pass ; if mismatch, next
+ cmp es:[di], cl ; make sure there's a zero term
+ jnz frm_pass
+ pop cx
+ mov ax, word ptr es:lmaExeHdr[bx][0]
+ mov dx, word ptr es:lmaExeHdr[bx][2]
+ cCall far_alloc_data_sel16, <dx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+ jmp short frm_ret
+
+frm_pass:
+ add bx, size MODENT
+ pop cx
+ loop frm_loop
+
+ mov ax, -1
+
+frm_ret:
+ pop ds
+cEnd
+
+;-----------------------------------------------------------------------;
+; ReplacePatchTable
+;
+; this function generates a new patch table when a module is loaded
+; from disk to replace the one in RAM.
+;
+; we do this by walking the entry table in the rom module, finding all
+; exported entry points, finding the corresponding entry point in the
+; new exe, and placing a far jump at that offset in the new segment.
+;
+; Entry:
+; Returns:
+; Registers Destroyed:
+;
+; History:
+; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+OP_FARJUMP equ 0EAh
+
+public enter_patch
+enter_patch proc near
+ push ax
+ push bx
+ push cx
+ push dx
+ push es
+ cCall GetProcAddress,<dx,0,cx>
+ pop es
+ or dx, dx
+ jz @F
+ mov es:[di+1],ax
+ mov es:[di+3],dx
+@@: pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+enter_patch endp
+
+cProc ReplacePatchTable, <PUBLIC>, <si, di>
+ parmW hExe
+ parmW selROMHdr
+
+ localW hCodeSeg
+cBegin
+ sub ax, ax
+ mov es, selROMHdr
+ test es:[ne_flagsothers], NEGANGLOAD
+ jnz rpt_ok ; one of these bits is set
+ifdef PATCHCHECK
+ test byte ptr es:[ne_gang_start+1], 4
+ jz rpt_ok
+endif
+ mov ax, es:[ne_cseg]
+ cmp al, byte ptr es:[ne_gang_start]
+ jz rpt_has_table
+ifdef PATCHCHECK
+ sub ax, ax
+ jmp short rpt_not_ok
+endif
+rpt_ok:
+ mov ax, 1 ; doesn't have patch table
+rpt_not_ok:
+ jmp rpt_exit
+
+rpt_has_table: ; allocate memory for the
+ mov si, es:[ne_cseg] ; segment
+ dec si
+ shl si, 3
+ .errnz size new_seg - 8
+ add si, es:[ne_segtab]
+ mov ax, es:[si].ns_minalloc
+ xor dx, dx
+ push ax
+ cCall GlobalAlloc, <GA_MOVEABLE,dx,ax>
+ pop si
+ or ax, ax
+ jnz @F
+ jmp rpt_exit
+
+@@: cCall GlobalLock, <ax> ; lock it
+ mov hCodeSeg, dx
+ mov es, dx
+ sub di, di ; initialize it to JMP UNDEFDYNLINK
+ cld
+ sub si, 4 ; don't overrun segment
+rpt_initloop:
+ mov al, OP_FARJUMP
+ stosb
+ mov ax, offset UndefDynLink
+ stosw
+ mov ax, seg UndefDynLink
+ stosw
+ cmp di, si
+ jb rpt_initloop
+
+ push ds ; set up for entry table
+ mov ds, selROMHdr
+ mov si, ds:[ne_enttab]
+ mov bx, ds:[ne_cseg]
+
+ mov cx, 1 ; first export = 1
+ mov dx, hExe
+
+rpt_ent_loop:
+ lodsw ; get count and segment
+ or al, al
+ jz rpt_ent_done ; if count 0, done
+
+ inc ah ; is seg == 0xFF
+ jnz rpt_not_moveable_entries
+
+rpt_mov_ent_loop:
+ test byte ptr [si], ENT_PUBLIC
+ jz rpt_mov_ent_loop_pass
+ cmp bl, 3[si]
+ jnz rpt_mov_ent_loop_pass ; must be patch segment
+
+ mov di, 4[si]
+
+ call enter_patch
+
+rpt_mov_ent_loop_pass:
+ inc cx
+ add si, 6
+ dec al
+ jnz rpt_mov_ent_loop
+ jmp rpt_ent_loop
+
+rpt_not_moveable_entries:
+ dec ah ; is seg == 0
+ jnz rpt_fixed_entries
+
+ add cx, ax ; seg=0 = unused entries
+ jmp short rpt_ent_loop
+
+rpt_fixed_entries:
+ cmp bl, ah ; must be in patch segment
+ jz rpt_fixed_ent_loop
+ sub ah, ah
+ add cx, ax ; update the ordinal count
+ add si, ax
+ add si, ax ; skip over entries in table
+ add si, ax
+ jmp rpt_ent_loop
+
+rpt_fixed_ent_loop:
+ test byte ptr [si], ENT_PUBLIC
+ jz rpt_fixed_loop_pass
+ mov di, 1[si]
+ call enter_patch
+
+rpt_fixed_loop_pass:
+ inc cx
+ add si, 3
+ dec al
+ jnz rpt_fixed_ent_loop
+ jmp rpt_ent_loop
+
+rpt_ent_done:
+ pop ds
+ cCall IPrestoChangoSelector, <hCodeSeg,hCodeSeg>
+ mov es, selROMHdr
+ mov bx, es:[ne_cseg]
+ dec bx
+ shl bx, 3
+ add bx, es:[ne_segtab]
+ cCall ChangeROMHandle, <hCodeSeg,es:[bx].ns_sector>
+rpt_exit:
+cEnd
+
+endif
+
+;-----------------------------------------------------------------------;
+; IsROMModule
+;
+; Determines if an app with a given name is a ROM application
+;
+; Entry:
+; Returns:
+; Registers Destroyed:
+;
+; History:
+; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+if ROM
+
+cProc IsROMModule, <FAR, PUBLIC>, <si, di>
+ parmD lpModule
+ parmW fSelector
+
+ localV szName, 18
+cBegin
+ cld
+ mov cx, 13
+ push ds
+ push ss
+ pop es
+ lea di, szName
+ assumes ds,nothing
+ lds si, lpModule
+
+skip_space: ; skip leading spaces
+ cmp byte ptr [si], ' '
+ jnz find_it
+ inc si
+ jmp short skip_space
+
+path_char:
+ pop ds
+ xor ax, ax
+ jmp short IRM_Exit
+
+find_it: ; if : / or \, not in ROM
+ lodsb
+ cmp al, ':'
+ jz path_char
+ cmp al, '\'
+ jz path_char
+ cmp al, '/'
+ jz path_char
+ cmp al, ' ' ; if illegal character, end of path
+ jbe end_char
+ cmp al, '<'
+ jz end_char
+ cmp al, '>'
+ jz end_char
+ cmp al, '|'
+ jz end_char
+ stosb ; store up to 13 chars
+ loop find_it
+
+end_char:
+ mov byte ptr es:[di], 0 ; 0 terminate...
+ pop ds ; get DS back
+ lea ax, szName ; find exe header in ROMTOC
+ cCall FindROMExe, <ss, ax>
+ or ax, ax
+ jz IRM_Exit
+
+IRM_Found:
+ cmp fSelector,0
+ jnz IRM_Exit
+
+ cCall FreeSelector, <ax> ; free the selector we got...
+ mov ax, 1 ; return success
+
+IRM_Exit:
+cEnd
+
+else
+
+cProc IsROMModule, <FAR, PUBLIC>
+cBegin <nogen>
+ xor ax, ax
+ retf 6
+cEnd <nogen>
+
+endif
+
+
+if ROM
+
+;-----------------------------------------------------------------------;
+; IsROMFile
+;
+; Determines if a file is in ROM
+;
+; Entry:
+; Returns:
+; Registers Destroyed:
+;
+; History:
+; 8/8/91 -- vatsanp -- adapted this for true-type files in ROM
+; from IsROMModule [ craigc]
+; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+cProc IsROMFile, <FAR, PUBLIC>, <si, di>
+ parmD lpFile
+ parmD lpfsize
+ parmW fSelector
+
+ localV szName, 18
+cBegin
+
+ cld
+ mov cx, 13
+ push ds
+ push ss
+ pop es
+ lea di, szName
+ assumes ds,nothing
+ lds si, lpFile
+
+skip_spc: ; skip leading spaces
+ cmp byte ptr [si], ' '
+ jnz fnd_it
+ inc si
+ jmp short skip_spc
+
+path_chr:
+ pop ds
+ xor ax, ax
+ jmp short IRF_Exit
+
+fnd_it: ; if : / or \, not in ROM
+ lodsb
+ cmp al, ':'
+ jz path_chr
+ cmp al, '\'
+ jz path_chr
+ cmp al, '/'
+ jz path_chr
+ cmp al, ' ' ; if illegal character, end of path
+ jbe end_chr
+ cmp al, '<'
+ jz end_chr
+ cmp al, '>'
+ jz end_chr
+ cmp al, '|'
+ jz end_chr
+ stosb ; store up to 13 chars
+ loop fnd_it
+
+end_chr:
+ mov byte ptr es:[di], 0 ; 0 terminate...
+ pop ds ; get DS back
+ lea ax, szName ; find file start in ROMTOC
+ cCall FindROMFile, <ss, ax, lpfsize>
+ or ax, ax
+ jz IRF_Exit
+
+IRF_Found:
+ cmp fSelector,0
+ jnz IRF_Exit
+
+ cCall FreeSelector, <ax> ; free the selector we got...
+ mov ax, 1 ; return success
+
+IRF_Exit:
+cEnd
+
+else
+
+cProc IsROMFile, <FAR, PUBLIC>
+cBegin <nogen>
+ xor ax, ax
+ retf 6
+cEnd <nogen>
+
+endif
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldappl.asm b/private/mvdm/wow16/kernel31/ldappl.asm
new file mode 100644
index 000000000..6cc574a34
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldappl.asm
@@ -0,0 +1,385 @@
+ TITLE LDAPPL - AppLoader Interface
+
+IFNDEF NO_APPLOADER ;* entire file for AppLoader
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include appl.inc
+include protect.inc
+.list
+
+DataBegin
+
+externW pGlobalHeap
+
+DataEnd
+
+sBegin CODE
+externNP SetOwner
+externFP set_discarded_sel_owner
+sEnd CODE
+
+externFP MyOpenFile
+externFP FarLoadSegment
+externFP FarMyAlloc
+externNP Int21Handler
+IF KDEBUG ;See comment below where this function is used
+externFP AppLoaderEntProcAddress
+ELSE
+externFP FarEntProcAddress
+ENDIF
+externFP GlobalHandle
+externFP Far_get_temp_sel
+externFP Far_free_temp_sel
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MapDSToDATA
+
+;-----------------------------------------------------------------------;
+; BootAppl ;
+; ;
+; Boots (i.e. starts) an AppLoader application ;
+; Loads (and relocates) first segment (must be CODE/FIXED/PRELOAD) ;
+; Validates the APPL magic word ;
+; Calls APPL boot procedure ;
+; ;
+; Arguments: ;
+; parmW hexe (handle to exe header) ;
+; parmW fh (file handle) ;
+; ;
+; Returns: ;
+; AX != 0 => ok ;
+; ;
+; Error Returns: ;
+; AX == 0 => error ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; various ;
+; ;
+; History: ;
+; ;
+; Thu Oct 01, 1987 11:10:06a -by- David N. Weise [davidw] ;
+; Changed the return values to NOT return ZF. ;
+; ;
+; Thu Jul 30, 1987 11:56:34a -by- Scott A. Randell [scottra] ;
+; Created it. ;
+;-----------------------------------------------------------------------;
+
+cProc BootAppl,<NEAR,PUBLIC>,<si>
+ parmW hexe
+ parmW fh
+cBegin BootAppl
+
+ mov es,hexe
+ mov si,es:[ne_segtab] ;* es:si => segtab
+ mov ax,es:[si].ns_flags ;* first segment
+ test ax,NSMOVE
+ jnz @f ;* PMode loader will set the
+ jmp bal_error ;* moveable flag for us
+@@:
+
+ test ax,NSPRELOAD
+ jz bal_error ;* must be preload
+
+;* * load in first segment (turn off Alloced/Loaded, and DS requirement)
+ and ax,not NSALLOCED+NSLOADED+NSUSESDATA
+ mov es:[si].ns_flags,ax ;* update flags
+ mov ax,1 ;* first segment
+ cCall FarLoadSegment,<es,ax,fh,fh>
+ jcxz bal_fail ;* not enough memory
+
+;* * now validate APPL header
+ mov es,ax
+ push es
+ cCall Far_get_temp_sel
+ xor bx,bx ;* es:bx => first segment
+ cmp es:[bx].magicAppl,magicApplCur ;* current version ?
+ ;* (no backward compatibility)
+ jne bal_error_popes
+
+;* * fill in global information
+ mov word ptr es:[bx].lppsMob,dataOffset pGlobalHeap
+ mov ax,codeBase ;* segment address of FIXED KERNEL
+
+ push ds
+ call MapDStoData
+ mov word ptr es:[bx].lppsMob+2,ds ;* segment address of krnl data
+ pop ds
+
+ mov word ptr es:[bx].pfnKernelAlloc,codeOffset FarMyAlloc
+ mov word ptr es:[bx].pfnKernelAlloc+2,ax
+
+ ; In DEBUG, we really want RIPs to be able to happen when we don't
+ ; find ordinals. This saves an enormous amount of debugging
+ ; time!! The entry point AppLoaderEntProcAddress only exists
+ ; in debug and allows RIPs to happen (unlike FarEntProcAddress
+ ; which is the same entry point used for GetProcAddress which
+ ; should not RIP).
+IF KDEBUG
+ mov word ptr es:[bx].pfnEntProcAddress,codeOffset AppLoaderEntProcAddress
+ELSE
+ mov word ptr es:[bx].pfnEntProcAddress,codeOffset FarEntProcAddress
+ENDIF
+ mov word ptr es:[bx].pfnEntProcAddress+2,ax
+;* * extra entry for Protect Mode only
+ mov word ptr es:[bx].pfnSetOwner,codeOffset MySetOwner
+ mov word ptr es:[bx].pfnSetOwner+2,ax
+
+ mov ax,es
+ pop es
+ cCall Far_free_temp_sel,<ax>
+;* * call the start procedure
+ cCall es:[pfnBootAppl], <hexe, fh> ;* returns BOOL
+
+bal_end: ;* ax
+cEnd BootAppl
+
+
+bal_error_popes: ;* an error occured (pop es if in PMODE)
+ mov ax,es
+ pop es
+ cCall Far_free_temp_sel,<ax>
+bal_error: ;* an error occured
+if KDEBUG
+ int 3
+endif
+bal_fail: ;* Boot failed (not enough memory)
+ xor ax,ax
+ jmps bal_end
+
+
+;-----------------------------------------------------------------------;
+; ExitAppl ;
+; ;
+; Exit last instance of an APPLOADER application ;
+; ;
+; Arguments: ;
+; parmW hexe (handle to exe header) ;
+; ;
+; Returns: ;
+; N/A ;
+; ;
+; History: ;
+; ;
+; Sat Sep 19, 1987 15:55:19 -by- Scott A. Randell [scottra] ;
+; Created it ;
+;-----------------------------------------------------------------------;
+
+cProc ExitAppl,<NEAR,PUBLIC>
+ parmW hexe
+cBegin ExitAppl
+
+; The apps with loaders don't do anything in their exit code except try
+; to close a bogus file handle, so we just will not make this call
+; anymore. This call runs on the kernel PSP, so if the app picked a valid
+; kernel file handle, that file got closed. 0 seems to be a popular
+; handle to inadvertently close. Newer apps do/will not have their own
+; loaders.
+
+ifdef DEAD_CODE ;--------------------------------------------------------
+
+ mov es,hexe
+ mov bx,es:[ne_segtab] ;* es:si => segtab
+
+;* * first segment is the AppLoader
+ mov ax,es:[bx].ns_handle ;* handle
+ or ax, ax ; Out of memory, couldn't load segment?
+ jz exa_error
+ HtoS ax ;* back to ring 1
+
+ push bx
+ lar bx, ax
+ test bh, DSC_PRESENT ; Fix a WinWord bug
+ pop bx
+ jz exa_error
+
+ mov es,ax
+;* * test to make sure that an APPL is there
+ cmp es:[magicAppl],magicApplCur
+ jne exa_error
+
+; The following hack sets up SS to have a 64k limit before calling the
+; app's exit procedure. Added 12/18/90 to work around a bug in the
+; Excel & WinWord app loader that references a bogus offset from SS. In
+; the past the stack segment at this point already had a large limit, but
+; when the data segment was moved out of the kernel's code segment and
+; the limit decreased to the actual DS size, the Excel/WinWord offset
+; is now beyond the segment limit.
+
+ push ss ;save current SS
+ push es ;seg 1 handle
+ smov es,ss ;get temp selector takes
+ cCall far_get_temp_sel ; and returns selector in ES
+ smov ss,es ;SS now has max limit
+ pop es ;seg 1 handle
+ cCall es:[pfnExitAppl], <hexe>
+
+ mov ax,ss ;return to original SS and
+ pop ss ; free temp selector
+ cCall far_free_temp_sel,<ax>
+exa_error:
+
+endif ;DEAD_CODE -------------------------------------------------
+
+cEnd ExitAppl
+
+sEnd NRESCODE
+
+
+sBegin CODE
+assumes CS,CODE
+;-----------------------------------------------------------------------;
+; LoadApplSegment ;
+; ;
+; Load an APPL segment ;
+; open file if not already open ;
+; tests to make sure 1st segment is an APPL loader ;
+; call the Apploader requesting segment be loaded ;
+; NOTE : never call for first segment ;
+; ;
+; Arguments: ;
+; parmW hexe (handle to exe header) ;
+; parmW fh (file handle (may be -1)) ;
+; parmW segno (segment #) ;
+; ;
+; Returns: ;
+; NZ, AX != 0 => ok, AX = segment where loaded, DX = handle of seg;
+; ;
+; Error Returns: ;
+; Z, AX == 0 => error ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; various ;
+; ;
+; History: ;
+; ;
+; Thu Jul 30, 1987 11:56:34a -by- Scott A. Randell [scottra] ;
+; Created it ;
+;-----------------------------------------------------------------------;
+
+cProc LoadApplSegment,<NEAR,PUBLIC>,<si>
+ parmW hexe
+ parmW fh
+ parmW segno
+ localW myfh ;* private file handle
+ ;* (if one shot open/close)
+cBegin LoadApplSegment
+
+ mov es,hexe
+ mov myfh,-1 ;* try with what is open first
+ mov ax,fh
+
+las_retry: ;* ax = file handle
+ mov si,es:[ne_segtab] ;* es:si => segtab
+;* * first segment is the AppLoader
+ mov si,es:[si].ns_handle ;* handle
+ HtoS si ;* back to ring 1
+ mov es,si
+;* * test to make sure that an APPL is there
+ cmp es:[magicAppl],magicApplCur ;* current version ?
+ ;* (no backward compatibility)
+ jne las_error
+
+;* * Try to reload with the handle Windows has (may be -1)
+ cCall es:[pfnReloadAppl], <hexe, ax, segno>
+ ;* returns AX = segment
+ or ax,ax
+ jnz las_end ;* return AX != 0
+;* * if the file handle was -1, open the file and try again
+ cmp myfh,-1
+ jne las_error ;* could not load with a file
+;* * file is not open, open up temporary file (put handle in myfh)
+ mov es,hexe
+ mov dx,es:[ne_pfileinfo]
+ regptr esdx,es,dx
+if SHARE_AWARE
+ mov bx,OF_REOPEN or OF_PROMPT or OF_CANCEL or OF_VERIFY + OF_SHARE_DENY_WRITE
+else
+ mov bx,OF_REOPEN or OF_PROMPT or OF_CANCEL or OF_VERIFY
+endif
+ push dx
+ Save <es>
+ cCall MyOpenFile,<esdx,esdx,bx>
+ pop dx
+ mov myfh,ax
+ cmp ax,-1
+ jne las_retry
+
+las_error: ;* an error occured
+;* * close file (if myfh != -1), then return error
+ debug_out "LoadApplSegment failed - better find out why!"
+ xor ax,ax
+
+las_end: ;* ax = return value
+ mov bx,myfh
+ inc bx
+ jz las_no_temp_file
+ dec bx
+ push ax
+ mov ah,3Eh ;* close file handle
+ DOSCALL
+ pop ax
+las_no_temp_file: ;* ax = return code
+ or ax,ax
+cEnd LoadApplSegment
+
+;-----------------------------------------------------------------------;
+
+
+
+;-----------------------------------------------------------------------;
+; MySetOwner ;
+; ;
+; Private version of SetOwner for present/non-present selectors ;
+; ;
+; Arguments: ;
+; selector = selector (present or non-present) ;
+; owner = new owner field ;
+; ;
+; History: ;
+; ;
+; Mon 04-Dec-1989 10:03:25 -by- David N. Weise [davidw] ;
+; Made it call set_discarded_sel_owner instead of set_sel_limit. ;
+; ;
+; Mon Jul 03 20:37:22 1989 created -by- Scott A. Randell [scottra] ;
+;-----------------------------------------------------------------------;
+
+cProc MySetOwner,<PUBLIC,FAR>, <SI, DI>
+ parmW selector
+ parmW owner
+cBegin
+ cCall GlobalHandle,<selector>
+ or dx,dx ;* 0 => not present
+ jz set_owner_NP
+;* * set owner for present selectors
+ cCall SetOwner,<selector, owner>
+ jmp short end_set_owner
+
+set_owner_NP:
+ ;* NP selectors store the owner in the segment limit
+ mov bx,selector
+ mov es,owner
+ call set_discarded_sel_owner
+
+end_set_owner:
+cEnd
+
+sEnd CODE
+
+endif ;!NO_APPLOADER (entire file)
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldaux.asm b/private/mvdm/wow16/kernel31/ldaux.asm
new file mode 100644
index 000000000..4c53aa403
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldaux.asm
@@ -0,0 +1,880 @@
+ TITLE LDAUX - Assembler side of LD.C
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+.list
+
+DataBegin
+
+externB fChksum
+externW hExeHead
+externW curTDB
+externW PHTcount
+externW kr1dsc
+szFake32BitModuleName DB 128 DUP(0)
+cFake32BitModuleName DW SIZE szFake32BitModuleName
+DataEnd
+
+externFP GlobalAlloc
+externFP GlobalFree
+externFP GlobalHandle
+externFP GetExePtr
+externFP FarMyUpper
+externFP FarFindOrdinal
+externFP FarEntProcAddress
+externFP FarMyLock
+
+externFP FarGetOwner
+externFP AllocSelector
+externFP IPrestoChangoSelector
+externFP FreeSelector
+ifdef WOW
+externFP WowGetModuleFileName
+externFP HandleAbortProc
+externFP WowGetModuleHandle
+endif
+
+ifdef DBCS
+externFP FarMyIsDBCSLeadByte
+endif
+
+sBegin CODE
+assumes CS,CODE
+
+externNP LoadSegment
+externNP MyLock
+
+externNP GetOwner
+
+if LDCHKSUM
+externNP GetChksumAddr
+endif
+
+;-----------------------------------------------------------------------;
+; GetSegPtr ;
+; ;
+; ;
+; Arguments: ;
+; DS:SI = FARPROC or DS = hModule and SI = segment# ;
+; ;
+; Returns: ;
+; BX = 0 ;
+; CX = segment# or zero if input invalid ;
+; DS:SI -> segment table entry ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sun 24-Dec-1989 22:49:50 -by- David N. Weise [davidw] ;
+; Added check for MPI thunk. ;
+; ;
+; Wed Oct 07, 1987 12:59:54p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetSegPtr,<PUBLIC,NEAR>
+cBegin nogen
+
+ xor bx,bx ; For cheap indexed addressing
+ cmp ds:[bx].ne_magic,NEMAGIC; Is this a thunk address?
+ jne gspFixed ; No, must be fixed procedure
+ dec si ; No, see if valid segment #
+ cmp si,ds:[bx].ne_cseg
+ jb @F
+ jmps gspfail ; No, fail
+@@: mov cx,si ; Yes, load that segment
+ inc cx
+ jmps gspSegNo
+
+; CX = segment number. Convert to segment info pointer.
+
+gspSegNo:
+ push cx
+ dec cx
+ shl cx,1
+ mov si,cx
+ shl cx,1
+ shl cx,1
+ add si,cx
+ .errnz 10 - SIZE NEW_SEG1
+ add si,ds:[bx].ne_segtab
+ pop cx
+ jmps gspExit ; DS:SI -> segment info block
+
+gspFixed: ; DS = code segment address
+
+; check for MakeProcInstance thunk first because GetOwner in 386pmode
+; ain't robust enough
+
+ cmp byte ptr ds:[si].0,0B8h ; Maybe, is this a mov ax,XXXX inst?
+ jnz gsp_not_mpit
+ cmp byte ptr ds:[si].3,0EAh ; Followed by far jump inst?
+ jnz gsp_not_mpit
+ cmp ds:[2],MPIT_SIGNATURE ; Is it in a mpi table?
+ jz gsp_yes_mpit
+ cmp ds:[TDB_MPI_THUNKS].2,MPIT_SIGNATURE
+ jnz gsp_not_mpit
+gsp_yes_mpit:
+ lds si,ds:[si].4 ; get real procedure address
+ jmp GetSegPtr
+gsp_not_mpit:
+
+ push ax
+ mov dx, ds ; Handle in dx
+ StoH dl ; Assume not fixed
+ cCall GetOwner,<ds>
+ or ax,ax
+ mov ds, ax
+ pop ax
+ jz gspfail
+
+gspf1:
+ cmp ds:[bx].ne_magic,NEMAGIC; Is it a module DB?
+ jnz gspfail ; Nope, fail.
+
+getting_closer:
+ mov si,ds:[bx].ne_segtab ; Yes, point to segment table
+ mov cx,ds:[bx].ne_cseg
+gspLoop:
+ cmp dx,ds:[si].ns_handle ; Scan stmen
+ jz gspFound
+ HtoS dx ; May be fixed seg???
+ cmp dx,ds:[si].ns_handle ; Scan stmen
+ jz gspFound
+ StoH dx
+ add si,SIZE NEW_SEG1
+ loop gspLoop
+gspfail:
+ xor cx,cx
+ jmps gspExit
+gspFound:
+ sub cx,ds:[bx].ne_cseg ; Compute segment# from remainder
+ neg cx ; of loop count
+ inc cx ; 1-based segment#
+gspExit:
+ ret
+
+cEnd nogen
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IGetCodeInfo,<PUBLIC,FAR>,<si,di>
+ parmD lpProc
+ parmD lpSegInfo
+cBegin
+ lds si,lpProc
+ call getsegptr
+ mov ax,cx
+ jcxz gciExit
+ les di,lpSegInfo
+ mov cx,SIZE NEW_SEG1
+ cld
+ rep movsb
+ mov ax,ds:[bx].ne_align ; Return segment aligment
+ stosw
+ sub si,SIZE NEW_SEG1
+ sub di,SIZE NEW_SEG1+2
+ cmp si,ds:[bx].ne_pautodata
+ jne gciExit
+ mov ax,ds:[bx].ne_stack
+ add ax,ds:[bx].ne_heap
+ add es:[di].ns_minalloc,ax
+gciExit:
+ smov es,ds ; put module handle (returned from getsegptr) into es
+ ; user depends on this
+ mov cx,ax ; WHY IS THIS HERE?
+;
+; NOTE: USER assumes that AX == BOOL fSuccess and ES == hModule upon return
+;
+cEnd
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetCodeHandle,<PUBLIC,FAR>,<si,di>
+ parmD lpProc
+cBegin
+ lds si,lpProc
+ call getsegptr
+ mov dx,cx
+ jcxz gchExit
+ mov ax,ds:[si].ns_handle
+; test ds:[si].ns_flags,NSLOADED
+; jnz gchExit
+ mov dx,-1
+ cCall LoadSegment,<ds,cx,dx,dx>
+ cCall MyLock,<ax>
+ xchg ax,dx
+ cmp ax,dx
+ je gchExit
+; %OUT Need pmode lru stuff here
+gchExit:
+cEnd
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CallProcInstance,<PUBLIC,FAR>
+cBegin nogen
+ mov ax,ds ; AX = caller's DS
+ mov cx,es:[bx] ; CX = hInstance
+ jcxz cpx ; If zero, then use caller's DS
+ xchg ax,cx ; AX = hInstance, CX = caller's DS
+ test al,GA_FIXED ; Fixed?
+ jnz cpx ; Yes, all set
+ xchg bx,ax ; No, BX = hInstance, ES:AX ->
+labelFP <PUBLIC,CallMoveableInstanceProc> ; procedure address.
+ HtoS bx ; Get selector
+ xchg bx,ax ; AX = segment address
+ mov ds,cx ; Restore DS
+cpx: jmp dword ptr es:[bx][2] ; Jump to far procedure
+cEnd nogen
+
+
+sEnd CODE
+
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+
+externNP MapDStoDATA
+externNP FindExeInfo
+externNP FindExeFile
+externNP NResGetPureName
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CopyName,<PUBLIC,NEAR>,<si>
+ parmD pname
+ parmW pdst
+ parmW fUpper
+cBegin
+ les si,pname
+ mov bx,pdst
+ mov cx,127
+ mov dx,fUpper
+cn0:
+ lods byte ptr es:[si]
+ or al,al
+ jz cn1
+ or dx,dx
+ jz cn0a
+ifdef DBCS
+ call FarMyIsDBCSLeadByte ; test if a char is lead byte of DBC
+ jc @F ; jump if not a DBC
+ inc bx
+ mov ss:[bx],al ; store first byte of DBC
+ dec cx
+ jcxz cn1 ; pay attention for counter exhaust...
+ lods byte ptr es:[si] ; fetch a 2nd byte of DBC
+ jmps cn0a
+@@:
+endif
+ call FarMyUpper
+cn0a:
+ inc bx
+ mov ss:[bx],al
+ loop cn0
+cn1:
+ mov byte ptr ss:[bx+1],0
+ mov ax,bx
+ mov bx,pdst
+ sub ax,bx
+ mov ss:[bx],al
+cEnd
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetProcAddress,<PUBLIC,FAR>,<ds,si>
+ parmW hinstance
+ parmD pname
+ localV namebuf,130
+cBegin
+ mov cx,hinstance
+ jcxz use_current_module
+ cCall GetExePtr,<cx>
+ xor dx,dx
+ jcxz gpdone1
+ mov si,ax
+ mov es,ax
+ test es:[ne_flags],NENOTP
+ jnz have_module_address
+ xor bx,bx
+if KDEBUG
+ fkerror 00FFh,<Can not GetProcAddress a task.>,es,bx
+endif
+ xor ax,ax
+ xor dx,dx
+gpdone1:
+ jmps gpdone
+use_current_module:
+ cCall MapDStoDATA
+ ReSetKernelDS
+ mov es,curTDB
+ UnSetKernelDS
+ mov si,es:[TDB_pModule]
+have_module_address:
+ cmp seg_pname,0
+ jne gp0
+ mov ax,off_pname
+ jmps gpaddr
+gp0:
+ lea bx,namebuf
+ xor dx,dx
+ cCall CopyName,<pname,bx,dx>
+ lea bx,namebuf
+ mov dx,-1
+ cCall FarFindOrdinal,<si,ssbx,dx>
+
+ cwd ; set DX to 0 if no ordinal
+ or ax,ax
+ jz gpdone ; if no ordinal, leave with 0:0
+
+gpaddr:
+ cCall FarEntProcAddress,<si,ax>
+gpdone:
+ mov cx,ax
+ or cx,dx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GetModuleHandle
+;
+; Returns the module handle, AKA segment address, of the named
+; module. The pname should be a pointer to a name, however
+; because we want FreeFontResource to take a file name we check
+; for that one special case for file names.
+;
+; Entry:
+; parmW pname
+; or 0:instance handle
+; Returns:
+; AX = handle if loaded
+; = 0 if not loaded
+;
+; Registers Destroyed:
+; BX,CX,DX,ES
+;
+; History:
+; Sat 18-Nov-1989 21:57:24 -by- David N. Weise [davidw]
+; Adding the handling of exeheaders above the line by calling
+; off to EMS_GetModuleHandle. A little while ago is when
+; the checking for filenames was added.
+;
+; Tue 04-Apr-1989 01:42:12 -by- David N. Weise [davidw]
+; This used to return DX = ExeHead, this is now returned in CX.
+;
+; Tue 28-Mar-1989 17:28:34 -by- David N. Weise [davidw]
+; Put in the Excel hack and added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetModuleHandle,<PUBLIC,FAR>,<di,si>
+ parmD pname
+ localV nameBuf,130
+cBegin
+ cCall MapDStoDATA
+ ReSetKernelDS
+ cmp pname.sel,0
+ jz gm1
+
+ lea di,namebuf
+ xor dx,dx ; Try as is first
+ cCall CopyName,<pname,di,dx>
+ inc di ; point past count
+ push ax
+ cCall FindExeInfo,<ss,di,ax>
+ pop bx
+ or ax,ax
+ jnz gmexit
+
+ lea di,namebuf
+ mov dx,-1 ; Now force upper case
+ cCall CopyName,<pname,di,dx>
+ inc di ; point past count
+ push ax
+ cCall FindExeInfo,<ss,di,ax>
+ pop bx
+ or ax,ax
+ jnz gmexit
+
+ smov es,ss
+ call NResGetPureName
+ cCall FindExeFile,<ss,di>
+ jmps gmexit
+
+gm1: cCall GetExePtr,<OFF_pname>
+gmexit:
+
+ifdef WOW
+;
+; If we didn't find a matching module, call WOW32 to see if
+; the module name matches the module name of a child app
+; spawned via WinOldAp. If it does, WOW32 will return
+; that WinOldAp's hmodule. If not, WOW32 will return zero.
+;
+ or ax,ax
+ jnz @F
+ lea di,namebuf[1]
+ cCall WowGetModuleHandle, <ss,di>
+@@:
+endif
+
+ mov dx,hExeHead ; return this as a freebie
+cEnd
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;
+;NOTE: BX preserved because Actor 4.0 depends on this (bug 9078 - neilk)
+;
+cProc IGetModuleFileName,<PUBLIC,FAR>,<si,di,bx>
+ parmW hinstance
+ parmD lpname
+ parmW nbytes
+cBegin
+ifdef WOW
+ ; take care of 32bit hInstance. 32bit hInstance has GDT/LDT bit clear
+ ; the validation layer will pass such handles as valid so that we can
+ ; thunk to 32bit GetModuleFileName if needed.
+ ;
+ ; in win32 hInstances are not global. therefore fake success by
+ ; returning a valid module name for compatibility sake. Naturally,
+ ; we will use our module name.
+
+ mov ax, hInstance
+ test al, 0100b ; Check for task aliases (see WOLE2.C) or BOGUSGDT
+ jnz GMFName_Normal
+ or ax, ax
+ jz GMFName_Normal
+ cCall MapDStoDATA
+assumes DS, DATA
+ mov cx, cFake32BitModuleName
+ lea si, szFake32BitModuleName
+ cCall WowGetModuleFileName, <ax, ds, si, cx>
+ mov cx,ax
+ jmps GMF_CopyName32
+
+GMFName_Normal:
+endif
+ mov ax, nbytes
+ or ax, ax
+ jz gfx
+ cCall GetExePtr,<hinstance>
+ or ax,ax
+ jz gfx
+ mov ds,ax
+ mov si,ds:[ne_pfileinfo]
+ xor cx,cx
+ mov cl,ds:[si].opLen
+ sub cx,opFile
+ lea si,[si].opFile
+ifdef WOW
+GMF_CopyName32:
+endif
+ les di,lpname
+ cmp cx,nbytes
+ jl gf1
+ mov cx,nbytes
+ dec cx
+gf1:
+ cld
+ mov ax,cx
+ rep movsb
+ mov es:[di],cl
+gfx:
+ mov cx,ax
+
+ ;** Nasty hack to support QuickWin libs (Fortran, QCWin)
+ ;** The startup code assumes DX will be the segment of the
+ ;** lpname parameter
+ mov dx,WORD PTR lpname[2]
+cEnd
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetModuleUsage,<PUBLIC,FAR>
+ parmW hinstance
+cBegin
+ cCall GetExePtr,<hinstance>
+ or ax,ax
+ jz gux
+got_one:
+ mov es,ax
+ mov ax,es:[ne_usage]
+gux: mov cx,ax
+cEnd
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetInstanceData,<PUBLIC,FAR>,<si,di>
+ parmW hinstance
+ parmW psrcdst
+ parmW nbytes
+cBegin
+ push ds
+ cCall GlobalHandle,<hinstance>
+ pop es ; Get caller's DS as destination
+ or dx,dx
+ jz gidone
+ mov ds,dx ; Source is passed instance
+ mov si,psrcdst ; Offsets are the same
+ mov di,si
+ mov ax,nbytes
+ mov cx,ax
+ jcxz gidone
+ cld
+ rep movsb
+ push es
+ pop ds
+gidone: mov cx,ax
+cEnd
+
+sEnd NRESCODE
+
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+externNP MISCMapDStoDATA
+
+;-----------------------------------------------------------------------;
+; MakeProcInstance ;
+; ;
+; Cons together a far procedure address with a data segment address, ;
+; in the form ;
+; ;
+; mov ax,DGROUP ;
+; jmp far pproc ;
+; ;
+; This procedure allocates a fixed segment for a set of thunks and ;
+; threads the thunks together on a free list within the segment. ;
+; When a thunk segment is full, a new one is allocated and pushed ;
+; onto the head of the list of thunk segments pointed to by ;
+; TDB_MPI_Thunks. ;
+; ;
+; Arguments: ;
+; parmD pproc ;
+; parmW hinstance ;
+; ;
+; Returns: ;
+; DX:AX = ProcInstance ;
+; CX != 0 ;
+; ;
+; Error Returns: ;
+; DX:AX = NULL ;
+; CX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,ES ;
+; ;
+; Calls: ;
+; MapDStoDATA ;
+; GlobalAlloc ;
+; FarMyLock ;
+; ;
+; History: ;
+; ;
+; Sat Sep 26, 1987 12:53:58p -by- David N. Weise [davidw] ;
+; ReWrote it a while ago to work with EMS. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IMakeProcInstance,<PUBLIC,FAR>,<si,di>
+ parmD pproc
+ parmW hinstance
+cBegin
+ SetKernelDSMisc
+
+; We try to prohibit tasks from calling into each other.
+; One way to do this is to not allow one app to MPI for
+; another.
+
+ mov bx,[bp-2] ; Warning - assume DS pushed here!
+ mov ax,hinstance ; if hInstance == NULL,
+ or ax,ax ; use caller's DS
+ jz mpi1
+ push bx
+ cCall GlobalHandle,<ax>
+ pop bx
+ cmp dx,bx
+ jz mpi1
+ xor cx,cx
+ krDebugOut DEB_FERROR, "%dx2 MakeProcInstance only for current instance. "
+mpi1: mov hinstance,bx
+
+; If this is a library DS then it makes absolutely no sense to make a
+; ProcInstance because library prologs setup DS already! In addition
+; it is assumed in TestDSAX that only task DS's are in ProcInstances.
+
+ cCall FarGetOwner,<bx>
+ mov es, ax
+ NE_check_ES
+ mov dx,pproc.sel
+ mov ax,pproc.off
+ test es:[ne_flags],NENOTP
+ jz @F
+ jmp mpexit ; It's a library - return its address
+@@:
+
+; now try to get a thunklet
+
+ mov ax,curTDB
+ mov si,TDB_MPI_Thunks
+ mov es,ax
+ mov ax,es:[TDB_MPI_Sel]
+mp2: mov es,ax
+ mov bx,es:[si].THUNKSIZE-2
+ or bx,bx
+ jz @F
+ jmp got_a_thunk
+@@: mov ax,es:[si] ; Is there another block linked in?
+ xor si,si
+ or ax,ax
+ jnz mp2 ; Yes, look at it.
+
+; No thunks available, make a block.
+
+ mov bx,THUNKSIZE * THUNKELEM
+ mov cx,GA_ZEROINIT
+ cCall GlobalAlloc,<cx,ax,bx>
+ or ax,ax
+; jnz mpx
+; cwd
+ jz mpfail
+;mpx:
+ mov bx,ax
+ mov es,curTDB
+ xchg es:[TDB_MPI_Thunks],bx ; Link the new block in.
+ mov es,ax
+
+; Initialize the new block.
+
+ mov es:[0],bx
+ mov es:[2],MPIT_SIGNATURE
+ mov bx,THUNKSIZE-2
+ mov cx,THUNKELEM-1
+mp1: lea dx,[bx+THUNKSIZE]
+ .errnz THUNKELEM and 0FF00h
+ mov es:[bx],dx
+ mov bx,dx
+ loop mp1
+ mov es:[bx],cx
+ push es ; make the block into a code segment
+ cCall AllocSelector,<es>
+ pop es
+ or ax, ax
+ jnz @F
+ ; AllocSelector Failed! Back out.
+ mov bx, es:[0] ; this is the old thunk val
+ mov ax, es ; this is the segment just allocated
+ mov es, curTDB
+ mov es:[TDB_MPI_Thunks], bx ; restore old value
+ cCall GlobalFree,<ax>
+mpfail:
+ krDebugOut DEB_IERROR, "MakeProcInstance failed. Did you check return values?"
+ xor ax, ax
+ cwd
+ jmps mpexit
+
+@@: mov di,ax
+ push es
+ cCall IPrestoChangoSelector,<di,es>
+ cCall FreeSelector,<di>
+ pop ax
+ xor bx,bx
+ jmp mp2
+
+got_a_thunk:
+
+ push es
+
+; we need a data alias so we can write into this thing
+
+ push bx
+ mov bx, kr1dsc
+ or bl, SEG_RING
+ cCall IPrestoChangoSelector,<es,bx>
+ mov es,ax
+ pop bx
+ mov ax,es:[bx]
+ mov es:[si].THUNKSIZE-2,ax
+ lea di,[bx-THUNKSIZE+2]
+
+ cld
+ mov dx,di ; save offset of thunk
+ mov al,0B8h ; mov ax,#
+ stosb
+ mov ax,hInstance
+ stosw
+ mov al,0EAh ; jmp far seg:off
+ stosb
+ mov ax,pproc.off
+ stosw
+ mov ax,pproc.sel
+ stosw
+ mov ax,dx ; recover offset of thunk
+ pop dx ; recover sel of thunk
+mpexit:
+ mov cx,ax
+ or cx,dx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FreeProcInstance ;
+; ;
+; Frees the given ProcInstance. ;
+; ;
+; Arguments: ;
+; parmD pproc ;
+; ;
+; Returns: ;
+; AX != 0 Success ;
+; CX != 0 Success ;
+; ;
+; Error Returns: ;
+; AX == 0 ProcInstance not found. ;
+; CX == 0 ProcInstance not found. ;
+; ;
+; Registers Preserved: ;
+; DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sat Sep 26, 1987 12:25:42p -by- David N. Weise [davidw] ;
+; ReWrote it a while ago to work with EMS. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IFreeProcInstance,<PUBLIC,FAR>,<di>
+ parmD pproc
+cBegin
+
+ cCall MISCMapDStoDATA
+ ReSetKernelDS
+ mov ax,curTDB
+ mov es,ax
+ mov ax,es:[TDB_MPI_Sel]
+ mov bx,TDB_MPI_Thunks ; Point to start of first table.
+
+fp0: or ax,ax ; Loop through linked tables.
+ jz fpdone
+ mov es,ax ; Point to table.
+ cmp ax,pproc.sel ; This the right ProcInstance table?
+ jz fp1
+ mov ax,es:[bx] ; No, get next table.
+ xor bx,bx
+ jmp fp0
+fp1:
+
+ push bx
+ mov ax, kr1dsc
+ or al, SEG_RING
+ cCall IPrestoChangoSelector,<es,ax>
+ mov es,ax
+ pop bx
+ mov di,pproc.off ; Pick off the specific Proc.
+ xor ax,ax
+ cld
+ stosw ; Clear it out!
+ stosw
+ stosw
+ mov ax,di
+ xchg es:[bx].THUNKSIZE-2,ax ; Update free list.
+ stosw
+ mov ax,-1 ; Return success.
+
+ cCall HandleAbortProc, <pproc>
+fpdone:
+ mov cx,ax
+ UnSetKernelDS
+
+cEnd
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DefineHandleTable,<PUBLIC,FAR>,<di>
+ parmW tblOffset
+cBegin
+ cCall FarMyLock,<ds>
+ or ax,ax
+ jz dhtx
+ mov di,tblOffset
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ push ds
+ mov ds,curTDB
+ UnSetKernelDS
+ or di,di ; resetting PHT?
+ jnz @F
+ mov dx,di
+@@: mov word ptr ds:[TDB_PHT][2],dx
+ mov word ptr ds:[TDB_PHT][0],di
+ pop ds
+ ReSetKernelDS
+ or di,di ; Is the app removing the PHT?
+ jnz @F ; setting new
+ dec PHTcount ; resetting
+ jmps dhtx
+
+@@: inc PHTcount ; bump the count of tasks with PHT's
+ assumes ds, nothing
+ mov es,ax
+ mov cx,es:[di] ; Get word count
+ add di,2 ; Point to first word
+
+ xor ax,ax
+ inc cx ; new handle table format (skip cwClear)
+ cld
+ rep stosw ; Zero words in private handle table
+ inc ax
+dhtx:
+cEnd
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldboot.asm b/private/mvdm/wow16/kernel31/ldboot.asm
new file mode 100644
index 000000000..bd9b9c79d
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldboot.asm
@@ -0,0 +1,3313 @@
+ PAGE ,132
+ TITLE LDBOOT - BootStrap procedure
+?DFSTACK = 1
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include pdb.inc
+include eems.inc
+include protect.inc
+include gpcont.inc
+ifdef WOW
+include vint.inc
+include doswow.inc
+endif
+.list
+
+if 0; KDEBUG
+ifdef WOW
+ BootTraceOn = 1
+ BootTrace macro char
+ push ax
+ mov ax,char
+ int 3
+ pop ax
+ endm
+else
+ BootTraceOn = 1
+ BootTrace macro char
+ push char
+ call BootTraceChar
+ endm
+endif
+else
+ BootTrace macro char
+ endm
+ BootTraceOn = 0
+endif
+
+; Note that the following public constants require special handling
+; for ROM Windows. If you add, delete, or change this list of constants,
+; you must also check the ROM Image Builder.
+
+public __ahshift
+public __ahincr
+public __0000h
+public __0040h
+public __A000h
+public __B000h
+public __B800h
+public __C000h
+public __D000h
+public __E000h
+public __F000h
+public __ROMBIOS
+public __WinFlags
+
+public __MOD_KERNEL
+public __MOD_DKERNEL
+public __MOD_USER
+public __MOD_DUSER
+public __MOD_GDI
+public __MOD_DGDI
+public __MOD_KEYBOARD
+public __MOD_SOUND
+public __MOD_SHELL
+public __MOD_WINSOCK
+public __MOD_TOOLHELP
+public __MOD_MMEDIA
+public __MOD_COMMDLG
+
+ __ahshift = 3
+ __ahincr = 1 shl __ahshift
+ __0000h = 00000h
+ __0040h = 00040h
+ __A000h = 0A000h
+ __B000h = 0B000h
+ __B800h = 0B800h
+ __C000h = 0C000h
+ __D000h = 0D000h
+ __E000h = 0E000h
+ __F000h = 0F000h
+ __ROMBIOS = 0F000h
+ __WinFlags = 1
+
+ __MOD_KERNEL = 0h
+ __MOD_DKERNEL = 0h
+ __MOD_USER = 0h
+ __MOD_DUSER = 0h
+ __MOD_GDI = 0h
+ __MOD_DGDI = 0h
+ __MOD_KEYBOARD = 0h
+ __MOD_SOUND = 0h
+ __MOD_SHELL = 0h
+ __MOD_WINSOCK = 0h
+ __MOD_TOOLHELP = 0h
+ __MOD_MMEDIA = 0h
+ __MOD_COMMDLG = 0h
+
+BOOTSTACKSIZE = 512
+EXTRASTACKSIZE = (4096-BOOTSTACKSIZE)
+
+MultWIN386 EQU 16h ; Reserved to Win386
+MW3_ReqInstall EQU 00h ; Installation check
+MW3_ReqInstall_Ret_1 EQU 0FFh ; Return number 1
+MW3_ReqInstall_Ret_2 EQU 01h ; Return number 2
+MW3_ReqInstall_Ret_3 EQU 02h ; Return number 3
+MW3_ReqInstall_Ret_4 EQU 03h ; Return number 4
+
+externFP lstrlen
+externFP IGlobalAlloc
+externFP IGlobalFree
+externFP IGlobalRealloc
+externFP LoadModule
+externFP IOpenFile
+externFP lrusweep
+externFP GetExePtr
+externFP GetProfileInt
+externFP GetPrivateProfileString
+externFP GetPrivateProfileInt
+externFP GetProcAddress
+externFP GetTempDrive
+externFP ExitKernel
+externFP InternalEnableDOS
+externFP FlushCachedFileHandle
+externFP SetHandleCount
+externFP IPrestoChangoSelector
+externFP GPFault
+externFP StackFault
+externFP invalid_op_code_exception
+externFP page_fault
+ifdef WOW
+externFP divide_overflow
+externFP single_step
+externFP breakpoint
+endif
+externFP DiagInit
+
+ifdef WOW
+externFP StartWOWTask
+externFP AllocSelector_0x47
+externW MOD_KERNEL
+externW ModCount
+externFP WOWGetTableOffsets
+externFP WOWDosWowInit
+externFP GetShortPathName
+endif
+
+if KDEBUG
+externFP ValidateCodeSegments
+endif
+
+externW pStackBot
+externW pStackMin
+externW pStackTop
+
+sBegin CODE
+externFP Int21Handler
+externFP Int10Handler
+externD prevInt10proc
+sEnd CODE
+
+;------------------------------------------------------------------------
+; Data Segment Variables
+;------------------------------------------------------------------------
+
+DataBegin
+if SHERLOCK
+ externW gpEnable
+endif
+
+externB graphics
+externB fBooting
+externB Kernel_flags
+externB fChkSum
+externB fCheckFree
+externB WOAName
+externB grab_name
+ifndef WOW
+externB szUserPro
+endif
+externB szBootLoad
+externB szCRLF
+externB fPadCode
+;externW EMScurPID
+;externW PID_for_fake
+externW cBytesWinDir
+externW cBytesSysDir
+externW pGlobalHeap
+externW hExeHead
+externW MaxCodeSwapArea
+externW curTDB
+externW f8087
+externB fastFP
+externW topPDB
+externW headTDB
+externW winVer
+ifndef WOW
+externB WinIniInfo
+externB PrivateProInfo
+endif
+externW gmove_stack
+externW prev_gmove_SS
+externW BaseDsc
+externW WinFlags
+externW hUser
+externW hShell
+externW MyCSSeg
+externW MyDSSeg
+externW MyCSAlias
+externB fhCache
+externW fhCacheEnd
+externW fhCacheLen
+externB fPokeAtSegments
+externB fExitOnLastApp
+externW segLoadBlock
+externD pKeyProc
+externD pKeyProc1
+externW wDefRIP
+
+ife ROM
+externW cpShrunk
+externW cpShrink
+externW hLoadBlock
+endif
+
+if ROM
+externW selROMTOC
+externW selROMLDT
+externW sel1stAvail
+endif
+
+externD pTimerProc
+externD pExitProc
+externD pDisableProc
+externD lpWindowsDir
+externD lpSystemDir
+
+if ROM
+externD prevIntx6proc
+externD prevInt0Cproc
+externD prevInt0Dproc
+externD prevInt0Eproc
+externD prevInt21proc
+externD prevInt3Fproc
+endif
+
+;if KDEBUG and SWAPPRO
+;externD prevIntF0proc
+;endif
+
+externD lpInt21 ; support for NOVELL stealing int 21h
+
+ifdef WOW
+externD pFileTable
+externW cBytesSys16Dir
+externD lpSystem16Dir
+externB Sys16Suffix
+externW cBytesSys16Suffix
+externW cBytesSysWx86Dir
+externD lpSystemWx86Dir
+externB SysWx86Suffix
+externW cBytesSysWx86Suffix
+externD pPMDosCURDRV
+externD pPMDosCDSCNT
+externD pPMDosPDB
+externD pDosWowData
+
+globalW cbRealWindowsDir,0
+
+WINDIR_BUFSIZE equ 121
+
+achWindowsDir DB WINDIR_BUFSIZE DUP(?)
+achRealWindowsDir DB WINDIR_BUFSIZE DUP(?)
+achSystem16Dir DB 128 DUP(?)
+achSystemWx86Dir DB 128 DUP(?)
+
+public cbRealWindowsDir, achRealWindowsDir, achWindowsDir, achSystem16Dir
+
+endif
+
+DataEnd
+
+
+;------------------------------------------------------------------------
+; INITDATA Variables
+;------------------------------------------------------------------------
+
+DataBegin INIT
+
+ifndef WOW
+; WOW doesn't muck with the WOAName buffer -- we just leave it
+; as WINOLDAP.MOD
+externB woa_286
+externB woa_386
+endif
+externB bootExecBlock
+externW oNRSeg
+externW oMSeg
+externW win_show
+externD lpBootApp
+
+if ROM
+externD lmaROMTOC
+staticD MyLmaROMTOC,lmaROMTOC
+
+ .errnz opLen
+ .errnz 8 - opFile
+ROMKRNL db 19 ; mocked up open file structure
+ db 7 dup (0) ; for ROM Kernel
+ db 'ROMKRNL.EXE',0
+endif
+
+staticW initTDBbias,0
+staticW initSP,0
+staticW initSSbias,0
+staticW segNewCS,0
+
+app_name db 68 dup(0)
+
+DataEnd INIT
+
+
+;------------------------------------------------------------------------
+; EMSDATA Variables
+;------------------------------------------------------------------------
+
+DataBegin EMS
+
+externB beg_emsdata
+
+DataEnd EMS
+
+
+;------------------------------------------------------------------------
+
+externNP LoadSegment
+externNP genter
+externNP gleave
+externNP GlobalInit
+externNP DeleteTask
+externNP BootSchedule
+externNP InitFwdRef
+
+externNP SaveState
+externNP LKExeHeader
+externNP GetPureName
+externNP SegmentNotPresentFault
+
+externNP LDT_Init
+externNP alloc_data_sel
+externNP get_physical_address
+externNP set_physical_address
+externNP set_sel_limit
+externNP free_sel
+externFP set_discarded_sel_owner
+externNP SelToSeg
+externNP DebugDefineSegment
+externNP DebugFreeSegment
+
+ife ROM
+externNP SwitchToPMODE
+externNP LKAllocSegs
+endif
+
+if ROM and PMODE32
+externFP HocusROMBase
+endif
+
+ifdef WOW
+externFP WOWFastBopInit
+endif
+
+
+if KDEBUG
+ife PMODE32
+externNP init_free_to_CCCC
+endif
+
+if SWAPPRO
+externB fSwapPro
+externW hSwapPro
+externW cur_dos_pdb
+endif
+endif
+
+ifdef DBCS
+externFP FarMyIsDBCSTrailByte
+endif
+
+externP beg_emscode
+
+
+;------------------------------------------------------------------------
+
+sBegin INITCODE
+assumes cs,CODE
+
+
+ife ROM
+externD prevIntx6proc
+externD prevInt0Cproc
+externD prevInt0Dproc
+externD prevInt0Eproc
+externD prevInt21proc
+externD prevInt3Fproc
+ifdef WOW
+externD prevInt01proc
+externD prevInt03proc
+externD oldInt00proc
+externFP GlobalDosAlloc
+externFP GlobalDosFree
+endif
+endif
+
+externNP TextMode
+externNP InitDosVarP
+externNP GrowSFTToMax
+ifndef WOW
+externNP SetUserPro
+endif
+externNP MyLock
+externNP Shrink
+externNP DebugDebug
+externNP NoOpenFile
+externNP NoLoadHeader
+
+if SDEBUG
+externNP DebugInit
+endif
+
+;if SWAPPRO
+;externNP INTF0Handler
+;endif
+
+
+if SDEBUG
+szModName db 'KERNEL',0
+endif
+
+if ROM
+externNP ROMInit
+externNP SetOwner
+externNP SetROMOwner
+externNP alloc_data_sel16
+if KDEBUG
+externNP CheckGlobalHeap
+endif
+endif
+
+ifdef WOW
+externNP SetOwner
+endif
+
+;-----------------------------------------------------------------------;
+; Bootstrap ;
+; ;
+; Determines whether we should initialize in a smaller amount of ;
+; memory, leaving room for an EEMS swap area. If so, we rep-move the ;
+; code to a lower address, and bugger the PSP to report less memory ;
+; available. It then does lots more of stuff. ;
+; ;
+; Arguments: ;
+; DS:0 = new EXE header ;
+; ES:0 = Program Segment Prefix block (PSP) ;
+; SS:SP = new EXE header ;
+; CX = file offset of new EXE header (set by KernStub) ;
+; DS = automatic data segment if there is one ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Jun 20, 1987 06:00:00p -by- David N. Weise [davidw] ;
+; Made fast booting work with real EMS. ;
+; ;
+; Tue Apr 21, 1987 06:31:42p -by- David N. Weise [davidw] ;
+; Added some more EMS support. ;
+; ;
+; Thu Apr 09, 1987 02:52:37p -by- David N. Weise [davidw] ;
+; Put back in the movement down if EMS. ;
+; ;
+; Sat Mar 14, 1987 05:55:29p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,DATA
+ assumes es,nothing
+ assumes ss,nothing
+
+
+cProc BootStrap,<PUBLIC,NEAR>
+cBegin nogen
+if KDEBUG
+ jmp short Hello_WDEB_End
+Hello_WDEB:
+ db 'Windows Kernel Entry',13,10,0
+Hello_WDEB_End:
+ push ax
+ push es
+ push si
+ xor ax, ax
+ mov es, ax
+ mov ax, es:[68h*4]
+ or ax, es:[68h*4+2]
+ jz @F
+ mov ax,cs
+ mov es,ax
+ lea si,Hello_WDEB
+ mov ah,47h
+ int 68h
+@@:
+ pop si
+ pop es
+ pop ax
+endif
+ BootTrace 'a'
+
+if ROM
+ call ROMInit ; BX -> LDT, DS -> RAM DGROUP, SI -> start mem
+
+else
+
+ cmp ax, "KO" ; OK to boot; set by kernstub.asm
+ je @F
+ xor ax, ax
+ retf
+@@:
+
+; Set up addressibility to our code & data segments
+
+ mov MyCSSeg, cs
+ mov MyDSSeg, ds
+
+endif ;ROM
+
+ifdef WOW
+; Get pointer to sft so that I can find do direct protect mode
+; file IO operations
+
+ mov CS:MyCSDS, ds
+
+ push es
+ mov ah,52h ; get pointer to internal vars
+ int 21h
+
+;
+; Retrieve some pointers from the DosWowData structure in DOS.
+;
+ push di
+ push dx
+ mov di, es:[bx+6ah] ;kernel data pointer
+
+ mov pDosWowData.off, di
+ mov pDosWowData.sel, es
+
+ mov ax, word ptr es:[di].DWD_lpCurPDB
+ mov dx, word ptr es:[di].DWD_lpCurPDB+2
+ mov pPMDosPDB.off,ax
+ mov pPMDosPDB.sel,0 ;to force gpfault if not ready
+
+ mov ax, word ptr es:[di].DWD_lpCurDrv
+ mov dx, word ptr es:[di].DWD_lpCurDrv+2
+ mov pPMDosCURDRV.off,ax
+ mov pPMDosCURDRV.sel,0 ;to force gpfault if not ready
+
+ mov ax, word ptr es:[di].DWD_lpCDSCount
+ mov dx, word ptr es:[di].DWD_lpCDSCount+2
+ mov pPMDosCDSCNT.off,ax
+ mov pPMDosCDSCNT.sel,0 ;to force gpfault if not ready
+
+ pop dx
+ pop di
+
+ lea bx,[bx+sftHead]
+ mov pFileTable.off,bx
+ mov pFileTable.sel,es
+ pop es
+
+endif ; WOW
+
+ife ROM
+ BootTrace 'b'
+ call SwitchToPMODE ; BX -> LDT, DS -> CS(DS), SI start of memory
+ BootTrace 'c'
+endif
+ ReSetKernelDS
+
+ mov BaseDsc,si
+ call LDT_Init
+ BootTrace 'd'
+
+ifdef WOW
+ call AllocSelector_0x47
+ call WOWFastBopInit
+endif
+
+if SDEBUG
+
+; In protected mode, initialize the debugger interface NOW. Only real mode
+; needs to wait until the global heap is initialized.
+
+ cCall DebugInit
+
+; In protected mode, define where our temp Code & Data segments are
+
+ mov ax,codeOffset szModName
+ cCall DebugDefineSegment,<cs,ax,0,cs,0,0>
+
+ mov ax,codeOffset szModName
+ cCall DebugDefineSegment,<cs,ax,3,ds,0,1>
+endif
+ BootTrace 'e'
+
+if ROM
+
+; In the ROM version, the DS selector doesn't change from now on, so we
+; can tell the debugger where the special kernel data is now.
+
+ cCall DebugDebug
+endif
+
+ BootTrace 'f'
+
+ifdef WOW
+ push ax
+ push bx
+ mov bx, pDosWowData.sel ;use this segment
+ mov ax, 2
+ int 31h
+ mov pPMDosPDB.sel,ax ;make this a PM pointer
+ mov pPMDosCURDRV.sel,ax ;make this a PM pointer
+ mov pPMDosCDSCNT.sel,ax ;make this a PM pointer
+ pop bx
+ pop ax
+
+ push pDosWowData.sel
+ push pDosWowData.off
+ call WOWDosWowInit
+endif
+
+; InitDosVarP just records a few variables, it does no hooking.
+; It does dos version checking and other fun stuff that
+; must be done as soon as possible.
+
+ call InitDosVarP
+ or ax,ax
+ jnz inited_ok
+ Debug_Out "KERNEL: InitDosVarP failed"
+ mov ax,4CFFh ; Goodbye!
+ INT21
+inited_ok:
+ BootTrace 'g'
+
+ push bx
+
+ mov bx, WinFlags
+ifndef JAPAN ; should be removed because of IBM dependent code.
+ ; InitFwdRef routine will set 80x87 status bit in WinFlags
+ ; and exported location #178.
+
+; Determine if there is a co-processor present.
+
+ int 11h ; get equipment word
+ test al,2 ; this is the IBM approved method
+ jz no_80x87 ; to check for an 8087
+ or bh,WF1_80x87
+no_80x87:
+endif ;NOT JAPAN
+
+ifdef WOW
+ or bh,WF1_WINNT ; Set NT flag ON
+endif
+
+ mov WinFlags,bx
+
+ pop bx
+
+; Determine if running under Windows/386 or the 286 DOS Extender
+
+ push bx
+ mov ax,(MultWin386 SHL 8) OR MW3_ReqInstall ; Win/386 install check
+ int 2Fh
+ BootTrace 'h'
+ cmp al,MW3_ReqInstall_Ret_4 ; Under WIN386 in pmode?
+ifdef WOW ; For WOW Enhanced Mode on 386
+ife PMODE32
+ jnz NotUnderWin386
+endif
+endif
+ or Kernel_flags[1],kf1_Win386
+ or byte ptr WinFlags,WF_PMODE or WF_ENHANCED
+ jmps InstallChkDone
+
+NotUnderWin386:
+ or Kernel_flags[2],KF2_DOSX
+ or byte ptr WinFlags,WF_PMODE or WF_STANDARD
+
+InstallChkDone:
+ BootTrace 'i'
+ pop bx
+
+ifndef WOW
+ ; WOW doesn't muck with the WOAName buffer -- we just leave it
+ ; as WINOLDAP.MOD
+
+ push cx
+ push di
+ push si
+ cld
+ mov cx,8
+ smov es,ds
+ mov di,dataOffset WOAName
+ mov si,dataOffset woa_286
+ test Kernel_flags[2],KF2_DOSX
+ jnz @F
+ mov si,dataOffset woa_386
+@@: rep movsb
+ pop si
+ pop di
+ pop cx
+endif
+ BootTrace 'j'
+
+ife ROM ;--------------------------------------------------------
+
+ mov ax,cx
+ mov cl,4
+ shr ax,cl
+ mov cpShrunk,ax
+
+; Compute paragraph address of new EXE header from SS:SP
+
+ mov bx,sp ; SS:SP -> new EXE header
+
+ cCall get_physical_address,<ss>
+ add ax,bx
+ adc dx,0
+ BootTrace 'k'
+ if PMODE32
+ cCall alloc_data_sel,<dx,ax,0,0FFFFh>
+ else
+ cCall alloc_data_sel,<dx,ax,1000h>
+ endif
+ BootTrace 'l'
+
+else ; ROM ---------------------------------------------------------
+
+; Setup selector to ROM Table of Contents
+
+ mov ax,word ptr [MyLmaROMTOC]
+ mov dx,word ptr [MyLmaROMTOC+2]
+ cCall alloc_data_sel16,<dx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+ mov selROMTOC,ax
+
+; Setup another selector to the ROM prototype LDT
+
+ mov es,ax
+ assumes es,nothing
+
+ mov ax,word ptr es:[lmaROMLDT]
+ mov dx,word ptr es:[lmaROMLDT+2]
+ cCall alloc_data_sel16,<dx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+ mov selROMLDT,ax
+
+ mov ax,es:[FirstROMsel]
+ shr ax,3
+ add ax,es:[cROMsels]
+ shl ax,3 ; ax = 1st non-ROM selector
+ mov sel1stAvail,ax
+
+; Setup selector to KERNEL EXE header in ROM. **ASSUMES KERNEL is 1st
+; module in ROM TOC**
+
+ mov ax,word ptr es:[ModEntries+lmaExeHdr]
+ mov dx,word ptr es:[ModEntries+lmaExeHdr+2]
+ cCall alloc_data_sel16,<dx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+
+endif ; ROM ---------------------------------------------------------
+
+ mov segLoadBlock,ax ; hinitexe:0 -> new EXE header
+
+; calculate the TDB bias
+
+ mov bx,dataOffset boottdb
+ mov initTDBbias,bx
+
+; calculate the SS bias
+
+ mov bx,dataOffset stackbottom
+ mov initSSbias,bx
+
+; calculate the initial SP
+
+ mov si,dataOffset stacktop
+ sub si,dataOffset stackbottom
+ mov initSP,si
+
+ cCall get_physical_address,<ds>
+ add ax,bx
+ adc dx,0
+ BootTrace 'm'
+if ROM
+ cCall alloc_data_sel16,<dx,ax,1000h>
+ FCLI
+else
+ FCLI
+ mov prev_gmove_SS, ss ; Switch stack while we set up new SS
+ smov ss, ds
+ mov sp, dataOFFSET gmove_stack
+ cCall set_physical_address,<prev_gmove_SS>
+ xor ax, ax
+ xchg ax, prev_gmove_SS
+endif
+ BootTrace 'n'
+ mov ss,ax ; switch to new stack
+ mov sp,si
+ FSTI
+
+ xor bp,bp ; zero terminate BP chain.
+ sub si,BOOTSTACKSIZE
+ mov ss:[pStackBot],sp
+ mov ss:[pStackMin],sp
+ mov ss:[pStackTop],si
+
+ cld
+ mov es,topPDB
+
+externB szNoGlobalInit
+if ROM ;----------------------------------------------------------------
+
+; In the ROM Windows version, the "allocated" block in the global heap is
+; the kernel data segment, not the code segments
+
+ mov bx,ds ; kernel DS is first busy block
+ lsl bx,bx ; pass its size to GlobalInit
+ inc bx
+
+ cCall GlobalInit,<MASTER_OBJECT_SIZE,bx,BaseDsc,es:[PDB_block_len]>
+ jnc mem_init_ok
+
+if KDEBUG
+ Debug_Out "GlobalInit failed!"
+else
+ mov dx, codeoffset szNoGlobalInit
+ smov ds, cs
+ mov ah, 9
+ int 21h ; Whine
+ mov ax, 4CFFh
+ int 21h ; And exit
+;NoGlobalInit db "KERNEL: Unable to initialise heap",13,10,'$'
+endif
+
+mem_init_ok:
+
+if KDEBUG
+ cCall CheckGlobalHeap
+endif
+
+else ;ROM ---------------------------------------------------------
+
+ BootTrace 'o'
+ mov ax, BaseDsc ; Free memory starts after this
+ mov bx,segLoadBlock ; Make boot image be first busy block
+ mov cx,es:[PDB_block_len] ; cx is end of memory
+ mov dx,MASTER_OBJECT_SIZE
+ cCall GlobalInit,<dx,bx,ax,cx>
+
+ jc @F ; passed through from ginit
+ or ax,ax
+ jnz mem_init_ok
+@@:
+ mov dx, codeoffset szNoGlobalInit
+ smov ds, cs
+ mov ah, 9
+ int 21h ; Whine
+ mov ax, 4CFFh
+ int 21h ; And exit
+;NoGlobalInit db "KERNEL: Unable to initialise heap",13,10,'$'
+
+mem_init_ok:
+ mov hLoadBlock,ax ; Save handle to first busy block
+
+endif ;ROM ---------------------------------------------------------
+ BootTrace 'p'
+
+ mov pExitProc.sel,cs
+ mov pExitProc.off,codeOffset ExitKernel
+
+; Find out where we live, and where win.com lives.
+
+ mov ds,topPDB
+ UnSetKernelDS
+ mov bx,ds
+ mov ds,ds:[PDB_environ]
+ xor si,si
+ cld
+envloop1:
+ lodsb
+ or al,al ; end of item?
+ jnz envloop1
+ lodsb
+ or al,al ; end of environment?
+ jnz envloop1
+ lodsw ; ignore argc, DS:SI -> kernel path
+
+ifdef WOW
+ smov es, ds ; now ES:SI -> kernel path
+else
+ call get_windir ; on return, DS:DI -> windir= value
+
+ smov es,ds
+
+; Record where to find the 'windows' directory.
+ BootTrace 'q'
+
+ SetKernelDS
+ or di,di
+ jz no_win_dir_yet
+ mov lpWindowsDir.sel,es
+ mov lpWindowsDir.off,di
+ mov cBytesWinDir,cx
+
+ ; Now set pointer to WIN.INI to be
+ ; in the Windows directory
+ push si
+ push es
+ smov es, ds
+ mov si, dataoffset szUserPro+6
+ mov di, si
+ inc cx
+ add di, cx ; Move up the string WIN.INI
+ std
+ mov cx, 4
+ rep movsw
+ ; Now copy Windows directory
+ cld
+ mov cx, cBytesWinDir
+ mov di, dataoffset szUserPro
+ lds si, lpWindowsDir
+ UnSetKernelDS
+ rep movsb
+ mov byte ptr es:[di], '\'
+ pop es
+ pop si
+endif
+ SetKernelDS
+ BootTrace 'r'
+no_win_dir_yet:
+
+if ROM ;----------------------------------------------------------------
+
+; 'Load' the kernel exe header from ROM.
+
+ mov si,dataOffset ROMKRNL
+ cCall LKExeHeader,<segLoadBlock,ds,si>
+ or ax,ax
+ jnz hdr_ok
+ jmp bootfail
+hdr_ok:
+
+else ;ROM ---------------------------------------------------------
+
+ sub sp,SIZE OPENSTRUC + 127
+ mov di,sp
+ regptr ssdi,ss,di
+ mov bx,OF_EXIST
+ cCall IOpenFile,<essi,ssdi,bx>
+ BootTrace 's'
+ inc ax ; Test for -1
+ jnz opn1 ; Continue if success
+ mov dx, codeoffset NoOpenFile
+fail1:
+ push dx ; Save string pointer
+ call textmode ; Switch to text mode
+ pop dx
+ smov ds, cs
+ mov ah, 9
+ int 21h ; Tell user why we're bailing out
+ mov ax,4CFFh ; Goodbye!
+ INT21
+opn1:
+
+; Now simulate loading ourselves from memory
+
+; Load new EXE header for KERNEL.EXE from memory
+
+ cCall LKExeHeader,<segLoadBlock,ssdi>
+ BootTrace 't'
+ add sp,SIZE OPENSTRUC + 127
+ or ax,ax
+ jnz @F
+ mov dx, codeoffset NoLoadHeader
+ jmp SHORT fail1
+@@:
+
+endif ;ROM ---------------------------------------------------------
+
+ mov hExeHead,ax
+ mov es,ax
+
+ifndef WOW
+; Record where to find the 'system' directory.
+
+if ROM ;----------------------------------------------------------------
+
+ push es
+ mov es,selROMTOC ; ROM system dir @ selROMTOC:offSysDir
+ mov di,es:offSysDir
+ mov lpSystemDir.sel,es
+ mov lpSystemDir.off,di
+ xor ax,ax
+ mov cx,-1
+ cld
+ repne scasb
+ not cx
+ dec cx
+ mov cBytesSysDir,cx
+ pop es
+
+else ;ROM ---------------------------------------------------------
+
+ mov di,es:[ne_pfileinfo]
+ lea di,es:[di].opFile
+ mov lpSystemDir.sel,es
+ mov lpSystemDir.off,di
+ mov dx,di
+ call GetPureName
+ sub di,dx
+ dec di
+ mov cBytesSysDir,di
+
+endif ;ROM ---------------------------------------------------------
+ BootTrace 'u'
+endif
+ ; ndef WOW
+
+
+; Make room at end of kernel data segment for stack--NOTE: DGROUP is
+; assumed to be segment 4!
+
+ mov bx,es:[ne_segtab]
+ife ROM
+ add es:[bx+(3*size NEW_SEG1)].ns_minalloc,EXTRASTACKSIZE
+endif
+
+
+; Determine size of kernel's largest discardable code segment
+
+ xor ax,ax ; No max yet.
+ mov cx,es:[ne_cseg]
+get_largest_loop:
+ test es:[bx].ns_flags,NSDATA ; Code segment?
+ jnz not_disc_code
+ .errnz NSCODE
+ test es:[bx].ns_flags,NSDISCARD ; Discardable?
+ jz not_disc_code ; No, ignore.
+ mov dx,es:[bx].ns_minalloc ; Yes, get size
+ add dx,0Fh ; in paragraphs
+ shr dx,1
+ shr dx,1
+ shr dx,1
+ shr dx,1
+ cmp ax,dx ; Biggest NR Seg?
+ jae not_disc_code
+ mov ax,dx
+not_disc_code:
+ add bx,SIZE NEW_SEG1
+ loop get_largest_loop
+no_NR_segments:
+ cmp ax,es:[ne_swaparea]
+ jbe leave_it_be
+ mov es:[ne_swaparea],ax
+leave_it_be:
+ BootTrace 'v'
+
+
+ife ROM ;----------------------------------------------------------------
+
+; Allocate memory for kernel segments
+
+ cCall LKAllocSegs,<es>
+ mov oNRSeg,ax
+ mov oMSeg, bx ; Misc segment
+ mov es,hExeHead
+
+
+; If this is a pMode debug version, the code and data segments have already
+; been defined to the debugger once. We're about to LoadSegment and define
+; these segments again in their final location. Use a special form of
+; DebugFreeSegment to force the debugger to pull out any breakpoints in these
+; segments. If we don't do this, any existing breakpoints become INT 3's
+; in the new copy of the segment and the code has to be patched by hand.
+; If only the debugger was smart enough to 'move' the breakpoints when it
+; saw a second define for an already loaded segment...
+
+if SDEBUG
+
+ cCall DebugFreeSegment,<cs,-1>
+ cCall DebugFreeSegment,<MyCSDS,-1>
+endif
+
+; Load kernel code segment 1 (resident code)
+
+ mov si,1
+ mov ax,-1 ; Indicate loading from memory
+ cCall LoadSegment,<es,si,cs,ax>
+ or ax,ax
+ jnz ll1
+fail2: jmp bootfail
+ll1:
+ mov segNewCS,ax ; Save new CS value
+
+
+; Load kernel data segment (segment 4)
+
+ mov si,4
+ mov ax,-1
+ cCall LoadSegment,<hExeHead,si,ds,ax>
+ or ax,ax
+ jz fail2
+
+ BootTrace 'w'
+
+
+; locate the stack in the new segment
+
+ mov bx,ax
+ mov si,initSP
+ add si,EXTRASTACKSIZE
+
+else ;ROM ---------------------------------------------------------
+
+ cCall SetOwner,<ds,hExeHead> ;Who owns ya baby?
+ cCall SetROMOwner,<cs,hExeHead> ;IGROUP isn't loaded, but needs owner
+
+; locate the stack at the end of the data segment
+
+ mov ax, ds
+ mov bx, ax
+ mov si, initSP
+ add si, ROMEXTRASTACKSZ
+
+endif ;ROM ---------------------------------------------------------
+
+
+ cCall get_physical_address,<ax>
+ add ax,initSSbias
+ adc dx,0
+ sub ax,10h
+ sbb dx,0
+ or ax,10h
+ FCLI
+ mov prev_gmove_SS, ss ; Switch stack while we set up new SS
+ smov ss, ds
+ mov sp, OFFSET gmove_stack
+ cCall set_physical_address,<prev_gmove_SS>
+ push bx
+ mov bx, si
+ xor cx, cx ; cx:bx=stack len (for set_sel_limit)
+ cCall set_sel_limit,<prev_gmove_SS>
+ pop bx
+ xor ax, ax
+ xchg ax, prev_gmove_SS
+ mov ss,ax ; Switch to new stack location
+ mov sp,si
+ FSTI
+ mov ax,bx
+
+
+; zero the new TDB
+
+ push ax
+
+ cCall get_physical_address,<ax>
+ add ax,initTDBbias
+ adc dx,0
+ if PMODE32
+YAH_WELL = (SIZE TDB+15) and NOT 15
+ cCall alloc_data_sel,<dx,ax,0,YAH_WELL>
+ else
+YAH_WELL = (SIZE TDB+15)/16
+ cCall alloc_data_sel,<dx,ax,YAH_WELL>
+ endif
+ mov es,ax
+ xor ax,ax
+ mov di,ax
+ mov cx,SIZE TDB
+ cld
+ rep stosb
+ pop ax
+
+; put the limits in the stack
+
+ xor bp,bp ; zero terminate BP chain.
+ mov ss:[pStackBot],sp
+ mov ss:[pStackMin],sp
+ mov ss:[pStackTop],10h
+ mov ss:[0],bp ; To mark this stack as NOT linked
+ mov ss:[2],bp ; to another, see PatchStack.
+ mov ss:[4],bp
+
+; initialize the new TDB
+
+ sub sp,SIZE TASK_REGS
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+ mov cx,topPDB
+ mov es:[TDB_PDB],cx ; save new PDB
+ mov es:[TDB_DTA].off,80h ; set initial DTA
+ mov es:[TDB_DTA].sel,cx
+ mov bx,1 ; BX = 1
+ mov es:[TDB_nEvents],bx ; Start this guy up!
+ mov es:[TDB_pModule],-1 ; EMS requires -1
+ mov bx,winVer
+ mov es:[TDB_ExpWinVer],bx ; Windows Version #
+ mov es:[TDB_sig],TDB_SIGNATURE ; Set signature word.
+
+; initialize the task BP and DS
+
+ push es
+ les bx,dword ptr es:[TDB_taskSP]
+ mov es:[bx].TASK_BP,bp ; initial BP = 0
+ mov es:[bx].TASK_DS,bp ; initial DS = 0
+ pop es
+
+ife ROM ;---------------------------------------------------------------
+
+ mov ds,ax ; switch to new DS segment
+ mov ax,segNewCS ; recover new CS value
+
+ push cs ; to free the selector
+
+; do a far return to the new code segment
+
+ push ax
+ mov ax,codeOffset new_code
+ push ax
+ ret_far ; FAR return to new code segment
+
+ public new_code
+new_code:
+
+ pop ax
+ push es
+ cCall free_sel,<ax> ; Free old CS selector
+ cCall IPrestoChangoSelector,<cs,MyCSAlias> ; Change our CS Alias
+
+ mov es,MyCSAlias ; Change MyCSDS to new DS
+ assumes es,CODE
+ mov ax,ds
+ xchg ax,es:MyCSDS
+ assumes es,nothing
+ cCall free_sel,<ax> ; Free old DS selector
+
+ call DebugDebug ; do after MyCSDS changes
+
+ mov pExitProc.sel,cs ; reset this!!
+
+;;; pusha
+;;; cCall get_physical_address,<cs>
+;;; add ax, codeOffset end_page_locked
+;;; adc dx, 0
+;;; mov bx, dx
+;;; mov cx, ax
+;;; mov di, cs
+;;; lsl di, di
+;;; sub di, codeOffset end_page_locked
+;;; xor si, si
+;;; mov ax, 0601h
+;;; int 31h ; Unlock some of Kernel!
+;;; popa
+
+ cCall SelToSeg,<ds> ; Save DS segment value
+ mov MyDSSeg,ax
+
+ cCall SelToSeg,<cs> ; Set segment equivalent
+ mov MyCSSeg, ax
+
+; calculate the maximum amount that we will allow SetSwapAreaSize to set
+
+ mov ax,-1 ; They can only harm themselves.
+
+
+else ;ROM ---------------------------------------------------------
+
+ push es ; code below expects this on stack
+
+ mov ax,-1 ; They can only harm themselves.
+
+endif ;ROM ---------------------------------------------------------
+
+ mov MaxCodeSwapArea,ax
+
+ifndef WOW ; WOW uses 32 bit profile api's
+
+; Allocate a handle for WIN.INI
+
+ xor ax,ax
+ mov bx,GA_SHAREABLE shl 8 OR GA_MOVEABLE
+ cCall IGlobalAlloc,<bx,ax,ax>
+ mov [WinIniInfo.hBuffer], ax
+ or ax,ax
+ jz nowinini
+ mov bx,ax ; put handle into base register
+ mov ax,hExeHead
+ mov es,ax
+ call set_discarded_sel_owner
+ ; Set up the filename
+ mov word ptr [WinIniInfo.lpProFile], dataoffset szUserPro
+ mov word ptr [WinIniInfo.lpProFile][2], ds
+nowinini:
+
+; Allocate a handle for Private Profiles
+
+ xor ax,ax
+ mov bx,GA_SHAREABLE shl 8 OR GA_MOVEABLE
+ cCall IGlobalAlloc,<bx,ax,ax>
+ mov [PrivateProInfo.hBuffer],ax
+ or ax,ax
+ jz noprivate
+ mov bx,ax ; put handle into base register
+ mov ax,hExeHead
+ mov es,ax
+ call set_discarded_sel_owner
+noprivate:
+endif; WOW
+
+ifdef WOW
+ ; Allocate a ~128K discardable code selector to hide the
+ ; GrowHeap - heap not sorted bugs, also present in Win 3.1.
+ ;
+ ; Since our system DLLs (like krnl386, user, gdi etc) contain a few
+ ; discardable codesgements (of approx 40K), we need not be precise
+ ;
+ push es
+ mov ax, 0C000H ; hiword is 01h , totalsize 0x1c000 bytes
+ mov bx, GA_MOVEABLE OR GA_DISCCODE
+ cCall IGlobalAlloc,<bx,01h,ax>
+ or ax,ax
+ jz short nogrowheap
+ cCall SetOwner, <ax, hExeHead>
+nogrowheap:
+ pop es
+endif; WOW
+
+ife ROM ;----------------------------------------------------------------
+
+; Now shrink off exe header and segment 1 of KERNEL.EXE
+
+ mov si,2 ; Segment number
+ xor ax,ax
+ xchg oNRSeg,ax
+nofastboot:
+ sub ax,cpShrunk
+ mov cpShrink,ax ; Amount to shrink by
+ cCall MyLock,<hLoadBlock>
+ mov bx,ax
+ xchg segLoadBlock,ax
+ cCall get_physical_address,<ax>
+ mov cx,dx
+ xchg bx,ax
+ cCall get_physical_address,<ax>
+ sub bx,ax
+ sbb cx,dx
+ REPT 4
+ shr cx,1
+ rcr bx,1
+ ENDM
+ mov ax,bx
+ add cpShrink,ax
+ push ax
+ cCall Shrink
+ pop ax
+ sub cpShrunk,ax
+
+; Load kernel code segment 2 (non-resident code)
+
+ cCall MyLock,<hLoadBlock>
+ mov bx,-1 ; Indicate loading from memory
+ cCall LoadSegment,<hExeHead,si,ax,bx>
+ or ax,ax
+ jnz ll2
+ pop es
+ jmp bootfail
+ll2:
+
+ inc si ; On to segment 3
+ xor ax, ax
+ xchg ax, oMSeg ; Once back only!
+ or ax, ax
+ jnz nofastboot
+
+else ;ROM ---------------------------------------------------------
+
+; The ROM kernel 'loads' the other two kernel segments now. Currently
+; LoadSegment does little more than define the segment to the debugger
+; which has already been done for the primary code & data segments.
+
+ cCall LoadSegment,<hExeHead,2,0,-1>
+ cCall SetROMOwner,<ax,hExeHead>
+
+ cCall LoadSegment,<hExeHead,3,0,-1>
+ cCall SetROMOwner,<ax,hExeHead>
+
+endif ;ROM ---------------------------------------------------------
+
+
+ pop es
+
+
+ call genter
+ smov ds, es
+ UnSetKernelDS
+ SetKernelDS es
+ ;;;mov ax,EMScurPID ; In case an EMS fast boot is going down.
+ ;;;mov ds:[TDB_EMSPID],ax
+
+ ;;;mov ax,ds:[TDB_EMSPID]
+ ;;;mov PID_for_fake,ax
+ ;;;mov EMScurPID,ax
+ mov curTDB,ds
+ mov headTDB,ds
+ push es
+
+ ; vectors
+SaveVec MACRO vec
+ mov ax, 35&vec
+ DOSCALL
+ mov [di.off], bx
+ mov [di.sel], es
+ add di, 4
+ ENDM
+
+ push di
+ mov di, TDB_INTVECS
+ SaveVec 00h
+ SaveVec 02h
+ SaveVec 04h
+ SaveVec 06h
+ SaveVec 07h
+ SaveVec 3Eh
+ SaveVec 75h
+
+ifdef WOW
+;; Hook Int10 so we can filter calls in WOW (see intnn.asm)
+ push es
+ push ds
+ mov ax,3510h
+ INT21
+ mov ax,codeOffset prevInt10proc
+ SetKernelCSDword ax,es,bx
+ mov ax,2510h
+ smov ds,cs
+ mov dx,codeOFFSET Int10Handler
+ INT21
+ pop ds
+ pop es
+endif
+
+ pop di
+
+ cCall SaveState,<ds>
+ pop es
+ mov ds,pGlobalHeap
+ call gleave
+ UnSetKernelDS es
+
+ mov ax, 32 ; Kernel wants a big handle table
+ cCall SetHandleCount,<ax>
+
+ SetKernelDS
+
+;
+; The following variable initialization is done here to avoid having
+; relocations in Kernel's data segment.
+;
+ mov lpInt21.off,codeOFFSET Int21Handler
+ mov lpInt21.sel,cs
+
+;
+; Before we hook exception handlers, make sure the DPMI exception
+; handler stack is set up the way Windows likes it.
+;
+ mov bl,6
+ mov ax,0202h ; DPMI get exception handler vector
+ int 31h
+ push cx
+ push dx
+
+ mov cx,cs
+ lea dx,fixing_stack
+ mov bl,6
+ mov ax,0203h ; DPMI set exception handler vector
+ int 31h
+
+ pop dx
+ pop cx
+;
+; Generate an invalid opcode exception fault. This causes DPMI to call
+; our "exception handler."
+;
+ db 0fh,0ffh
+fixing_stack:
+ push bp
+ mov bp,sp ; BP -> BP RETIP RETCS EC IP CS FL SP SS
+;
+; Restore the previous invalid exception handler vector.
+;
+ mov bl,6
+ mov ax,0203h
+ int 31h
+;
+; Replace the return address on the DPMI fault handler routine with
+; our exit code.
+;
+ lea ax,done_fixing_stack
+ mov [bp+8],ax
+ mov [bp+10],cs
+
+ lea ax,[bp+16]
+ mov ss:[pStackBot],ax
+ mov ss:[pStackMin],sp
+ mov ss:[pStackTop],offset pStackBot + 150
+
+ mov sp,bp
+ pop bp
+ retf
+
+done_fixing_stack:
+
+ife ROM
+ mov es, MyCSAlias
+ assumes es, CODE
+endif
+
+
+; Hook not present fault for segment reloader.
+
+ mov ax,0202h ; Record old not present fault.
+ mov bl,0Bh
+ int 31h
+ mov prevInt3Fproc.off,dx
+ mov prevInt3Fproc.sel,cx
+
+ mov ax,0203h ; Hook not present fault.
+ mov cx,cs
+ mov dx,codeOffset SegmentNotPresentFault
+ int 31h
+
+; Hook GP fault in order to terminate app.
+
+ mov bl, 0Dh ; GP Fault
+ mov ax, 0202h
+ int 31h
+ mov prevInt0Dproc.off, dx
+ mov prevInt0Dproc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset GPFault
+ int 31h
+
+; Hook invalid op-code in order to terminate app.
+
+ mov bl, 06h ; invalid op-code
+ mov ax, 0202h
+ int 31h
+ mov prevIntx6proc.off, dx
+ mov prevIntx6proc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset invalid_op_code_exception
+ int 31h
+
+; Hook stack fault in order to terminate app.
+
+ mov bl, 0Ch ; stack fault
+ mov ax, 0202h
+ int 31h
+ mov prevInt0Cproc.off, dx
+ mov prevInt0Cproc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset StackFault
+ int 31h
+
+; Hook bad page fault in order to terminate app.
+
+ mov bl, 0Eh ; page fault
+ mov ax, 0202h
+ int 31h
+ mov prevInt0Eproc.off, dx
+ mov prevInt0Eproc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset page_fault
+ int 31h
+
+ifdef WOW
+
+; Hook divide overflow trap in order to get better WOW debugging.
+
+ mov bl, 00h ; divide overflow
+ mov ax, 0202h
+ int 31h
+ mov oldInt00proc.off, dx
+ mov oldInt00proc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset divide_overflow
+ int 31h
+
+; Hook single step trap in order to get better WOW debugging.
+
+ mov bl, 01h ; single step
+ mov ax, 0202h
+ int 31h
+ mov prevInt01proc.off, dx
+ mov prevInt01proc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset single_step
+ int 31h
+
+; Hook breakpoint trap in order to get better WOW debugging.
+
+ mov bl, 03h ; page fault
+ mov ax, 0202h
+ int 31h
+ mov prevInt03proc.off, dx
+ mov prevInt03proc.sel, cx
+
+ mov ax, 0203h
+ mov cx, cs
+ mov dx, codeOffset breakpoint
+ int 31h
+
+endif
+
+ assumes es, nothing
+
+; Do a slimy fix-up of __WinFlags containing processor and protect mode flags
+
+ xor ax,ax
+ mov dx,178
+ cCall GetProcAddress,<hExeHead,ax,dx>
+ mov ax,WinFlags
+ mov es:[bx],ax
+
+ifdef WOW
+ ; get WOW32 thunk table offsets and do fixups
+
+ ; WARNING: WOW32 has a dependency on this being called after
+ ; kernel is done booting and addresses are fixed
+ push ds
+ push dataoffset MOD_KERNEL
+ call far ptr WOWGetTableOffsets
+
+ mov si, dataoffset MOD_KERNEL
+ mov cx, ModCount ; # fixups to do
+ mov di, 520 ; first ordinal of the group
+
+Mexico:
+ push si
+ push di
+ push cx
+
+ push hExeHead
+ push 0
+ push di
+ call GetProcAddress
+
+ pop cx
+ pop di
+ pop si
+ mov ax,[si]
+ mov es:[bx],ax
+
+ inc si ; point to next word
+ inc si
+ inc di ; get next ordinal
+
+ loop Mexico
+endif
+
+ife ROM ;--------------------------------
+
+; Can't do slimy fix-ups in ROM--already done by ROM Image Builder
+
+; Do a very slimy fix-up of the runtime constant __0000h
+
+ cCall GetProcAddress,<hExeHead,0,183>
+ mov si,bx
+ mov bx,00000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __0040h
+
+ cCall GetProcAddress,<hExeHead,0,193>
+ mov si,bx
+ mov bx,00040h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __ROMBIOS
+
+ cCall GetProcAddress,<hExeHead,0,173>
+ mov si,bx
+ mov bx,0F000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __F000h
+
+ cCall GetProcAddress,<hExeHead,0,194>
+ mov si,bx
+ mov bx,0F000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __A000h
+
+ cCall GetProcAddress,<hExeHead,0,174>
+ mov si,bx
+ mov bx,0A000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __B000h
+
+ cCall GetProcAddress,<hExeHead,0,181>
+ mov si,bx
+ mov bx,0B000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __B800h
+
+ cCall GetProcAddress,<hExeHead,0,182>
+ mov si,bx
+ mov bx,0B800h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __C000h
+
+ cCall GetProcAddress,<hExeHead,0,195>
+ mov si,bx
+ mov bx,0C000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __D000h
+
+ cCall GetProcAddress,<hExeHead,0,179>
+ mov si,bx
+ mov bx,0D000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+; Do a very slimy fix-up of the runtime constant __E000h
+
+ cCall GetProcAddress,<hExeHead,0,190>
+ mov si,bx
+ mov bx,0E000h
+ mov ax,2
+ int 31h
+ mov es:[si],ax
+
+endif ;ROM -------------------------
+
+ifndef WOW
+ cCall SetUserPro ; Get WIN.INI filename from environment
+endif
+
+ CheckKernelDS
+
+; Free high memory copy of KERNEL.EXE
+
+ife ROM
+ cCall IGlobalFree,<hLoadBlock>
+ mov hLoadBlock,ax
+else
+ xor ax, ax
+endif
+
+if PMODE32
+ .386
+ mov fs, ax
+ mov gs, ax
+ .286p
+endif
+
+ifndef WOW
+ cmp lpWindowsDir.sel,ax
+ jnz got_win_dir
+ mov si,dataOffset szUserPro
+ mov di,dataOffset [WinIniInfo.ProBuf]
+ cCall IOpenFile,<dssi,dsdi,OF_PARSE>
+ lea di,[di].opfile
+ mov lpWindowsDir.sel,ds
+ mov lpWindowsDir.off,di
+ mov dx,di
+ call GetPureName
+ sub di,dx
+ dec di
+ mov cBytesWinDir,di
+got_win_dir:
+endif
+
+ifdef WOW
+; Regular Windows kernel sets up the Windows directory very early in
+; boot, before WOW kernel loads WOW32.DLL.
+;
+; It turns out we can delay setting up the 16-bit copy of the
+; windows directory (referred by lpWindowsDir) until here, where
+; we're in protected mode and about to set up the system directories
+; as well. This allows us to call a GetShortPathName thunk in
+; WOW32.
+;
+
+ mov ds,topPDB
+ UnSetKernelDS
+ mov ds,ds:[PDB_environ]
+
+ call get_windir ; on return, DS:DI -> windows dir
+
+ smov es,ds
+ SetKernelDS
+
+; Record where to find the 'windows' directory.
+ BootTrace 'q'
+
+ mov lpWindowsDir.sel,es
+ mov lpWindowsDir.off,di
+ mov cBytesWinDir,cx
+
+; Record where to find the 'system32' directory.
+
+ mov ax,hExeHead
+ mov es,ax
+ mov di,es:[ne_pfileinfo]
+ lea di,es:[di].opFile
+ mov lpSystemDir.sel,es
+ mov lpSystemDir.off,di
+ mov dx,di
+ call GetPureName
+ sub di,dx
+ dec di
+ mov cBytesSysDir,di
+
+ BootTrace 'u'
+
+;
+; Under WOW there are two system directories: \nt\system and \nt\system32.
+; lpSystemDir points to \nt\system32, while lpSystem16Dir points to
+; \nt\system. We return the latter from GetSystemDirectory, since we want
+; applications to install their shared stuff in \nt\system, but we want
+; to search \nt\system32 before \nt\system when loading modules.
+; Set up lpSystem16Dir using the Windows dir + \system.
+; Note that the string pointed to by lpSystem16Dir is not null terminated!
+
+ mov lpSystem16Dir.sel,ds
+ mov lpSystem16Dir.off,dataoffset achSystem16Dir
+
+ cld
+ mov si,dataoffset achRealWindowsDir
+ mov es,lpSystem16Dir.sel
+ mov di,lpSystem16Dir.off
+ mov cx,cbRealWindowsDir
+ rep movsb ; copy Windows dir
+
+ mov si,dataoffset Sys16Suffix
+ mov cx,cBytesSys16Suffix
+ rep movsb ; tack on "\system"
+
+ mov cx,cbRealWindowsDir
+ add cx,cBytesSys16Suffix
+ mov cBytesSys16Dir,cx
+
+
+;
+; build the Wx86 system directory "Windir\System32\Wx86"
+;
+ mov lpSystemWx86Dir.sel,ds
+ mov lpSystemWx86Dir.off,dataoffset achSystemWx86Dir
+
+ mov es,lpSystemWx86Dir.sel
+ mov di,lpSystemWx86Dir.off
+ mov cx,cBytesSysDir
+ mov si,lpSystemDir.off
+ push ds
+ mov ds,lpSystemDir.sel
+ rep movsb ; copy System dir (Windows\System32)
+ pop ds
+
+ mov si,dataoffset SysWx86Suffix
+ mov cx,cBytesSysWx86Suffix
+ rep movsb ; tack on "\Wx86"
+
+ mov cx,cBytesSysDir
+ add cx,cBytesSysWx86Suffix
+ mov cBytesSysWx86Dir,cx
+
+
+@@:
+; WOW DPMI Supports wants to call GlobalDosAlloc and GlobalDosFree so that
+; We don't have to write the same code for DPMI support. So we call DPMI
+; Here with the addresses of those routines so he can call us back.
+
+ mov bx,cs
+ mov si,bx
+
+ mov dx,codeOffset GlobalDosAlloc
+ mov di,codeOffset GlobalDosFree
+
+ mov ax,4f3h
+ int 31h
+endif
+
+
+; Under win 2.11 we allowed the ":" syntax to replace the shell.
+; We no longer allow this, however to avoid messing up people
+; with batch files that have ":" in them we will strip the
+; ":" out of the command line. But we retain the :: syntax
+; for the OS/2 VM!!
+
+; We also do the check for the /b switch here. This puts us in "diagnostic
+; mode and we set a flag to say this. Later, we will call the DiagInit()
+; function to open the log file, etc.
+
+ push ds
+ cld
+ mov ds,topPDB
+ UnSetKernelDS
+ push ds
+ pop es
+ mov si,80h
+ xor ax,ax
+ lodsb
+ or al,al
+ jz no_colon
+ mov cx,ax
+@@: lodsb
+ cmp al,' '
+ loopz @B
+ cmp al,':'
+ jnz no_colon
+ cmp byte ptr [si],':'
+ jz no_colon
+ mov byte ptr [si][-1],' '
+no_colon:
+ cmp al,'/' ;Switch character?
+ je CheckSwitch ;Yes
+ cmp al,'-' ;Other switch character?
+ jne NoSwitch ;Nope.
+CheckSwitch:
+ lodsb ;Get next char
+ or al,32 ;Convert to lowercase if necessary
+ cmp al,'b' ;Diagnostic mode?
+ jnz NoSwitch ;Nope
+ cCall DiagInit ;Initialize diagnostic mode
+ mov WORD PTR [si-2],2020h ;Blank out the switch
+NoSwitch:
+ pop ds
+ ReSetKernelDS
+
+ ;** We want to grow the SFT *before* loading the modules,
+ ;** not after, like was the case previous to win3.1
+ call GrowSFTToMax ;add to SFT chain in p mode
+
+if 1
+; old ldinit.c
+
+ cld
+ push ds
+ smov es,ds
+ xor ax,ax
+ xor cx,cx
+ mov ds,topPDB
+ UnSetKernelDS
+ mov si,80h
+ lodsb
+ or al,al
+ jz gwaphics_done
+ mov cl,al
+ lodsb
+ cmp al,' '
+ mov al,ah
+ jnz gwaphics_done
+ lodsb
+ cmp al,':'
+ mov al,ah
+ jnz gwaphics_done
+ lodsb
+ cmp al,':'
+ mov al,ah
+ jnz gwaphics_done
+
+ mov di,dataOffset app_name
+
+find_delineator:
+ lodsb
+ stosb
+ cmp al,' '
+ ja find_delineator
+ mov es:[di][-1],ah
+ mov ds:[80h],ah ; assume no arguments
+ jnz gwaphics_done
+
+ add cx,82h
+ sub cx,si
+ smov es,ds
+ mov di,80h
+ mov al,cl
+ stosb
+ rep movsb
+
+gwaphics_done:
+ pop ds
+ ReSetKernelDS
+ or ax,ax
+ jz @F
+ mov graphics,0
+@@:
+else
+ cld
+ xor ax,ax
+ xor bx,bx
+endif
+ jmps SlowBoot
+
+
+bootfail:
+ mov al,1
+ cCall ExitKernel,<ax>
+cEnd nogen
+
+sEnd INITCODE
+
+;-----------------------------------------------------------------------;
+; SlowBoot ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Mar 14, 1987 05:52:22p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+DataBegin INIT
+
+BootSect db 'BOOT',0
+BootFile db 'SYSTEM.INI',0
+FilesCached db 'CACHEDFILEHANDLES',0
+IdleSegLoad db 'LOADSEGMENTSATIDLE',0
+ifdef WOW
+ExitLastApp db 'CLOSEONLASTAPPEXIT',0
+endif
+
+if SHERLOCK
+ szGPC db 'GPCONTINUE',0
+endif
+
+szDebugSect db 'DEBUG',0
+szOutputTo db 'OUTPUTTO', 0
+szAux db 0 ;'AUX', 0 ; don't return a default
+
+if KDEBUG
+szKRInfo db 'KERNELINFO', 0
+szKRBreak db 'KERNELBREAK', 0
+szWin3Info db 'WIN3INFO', 0
+szWin3Break db 'WIN3BREAK', 0
+endif
+
+ife PMODE32
+Standard db 'STANDARD',0
+PadCodeStr db 'PADCODESEGMENTS',0
+endif
+
+BootBufLen equ 80
+BootBuf db BootBufLen dup (?)
+
+bootmods label byte
+ DB 'SYSTEM.DRV',0
+winmods label byte
+ifdef WOW
+ DB 'KEYBOARD.DRV',0
+szAfterKeyboardDriver label byte ;Used so we can tell key driver loaded
+ DB 'MOUSE.DRV',0
+
+ifdef DBCS_WIFE
+ DB 'WIFEMAN.DLL', 0 ;WIFE manager has to be loaded before display driver
+endif
+ DB 'VGA.DRV',0
+ DB 'SOUND.DRV',0
+ DB 'COMM.DRV',0
+ DB 'USER.EXE',0
+ DB 'GDI.EXE',0
+else
+ DB 'KEYBOARD.DRV',0
+szAfterKeyboardDriver label byte ;Used so we can tell key driver loaded
+ DB 'MOUSE.DRV',0
+ifdef DBCS_WIFE
+ DB 'WIFEMAN.DLL', 0 ;WIFE manager has to be loaded before
+ ;display driver
+endif
+ DB 'DISPLAY.DRV',0
+ DB 'SOUND.DRV',0
+ DB 'COMM.DRV',0
+ DB 'FONTS.FON',0
+ DB 'OEMFONTS.FON',0 ; For Internationals use.
+ DB 'GDI.EXE',0
+ DB 'USER.EXE',0
+endif
+
+ifdef WOW
+defapp label byte
+ DB 'WOWEXEC.EXE',0
+else
+defapp label byte
+ DB 'PROGMAN.EXE',0
+endif
+
+Shell label byte
+ DB 'WOWSHELL',0
+
+;** Ordinal strings for two of the Keyboard driver exports
+keymodstr DB 'KEYBOARD',0
+keyprocstr DB '#5',0 ; keyprocstr = AnsiToOem
+keyprocstr1 DB '#6',0 ; keyprocstr = OemToAnsi
+
+DataEnd INIT
+
+sBegin INITCODE
+assumes cs,CODE
+assumes ds,nothing
+assumes es,nothing
+
+if BootTraceOn
+cProc BootTraceChar,<PUBLIC,NEAR,NODATA>, <ax, dx>
+ parmW char
+cBegin
+ mov dx, 3fdh
+@@: in al, dx
+ test al, 20h
+ jz @B
+ mov ax, char
+ mov dx, 3f8h
+ out dx, al
+cEnd
+
+endif ; BootTraceOn
+
+
+
+cProc ttywrite,<PUBLIC,NEAR,NODATA>, <ds, si>
+ parmD s
+cBegin
+; cCall lstrlen,<s>
+; mov cx, ax
+; lds bx, s
+; mov bx,1
+; mov ah,40h
+; int 21h
+ lds si, s
+ cld
+ mov ah, 2
+tty1:
+ lodsb
+ mov dl, al
+ or dl, dl
+ jz tty2
+ int 21h
+ jmps tty1
+tty2:
+cEnd
+
+cProc LoadFail,<PUBLIC,NEAR,NODATA>, <ds>
+ parmD s
+cBegin
+ SetKernelDS
+ cCall TextMode
+ mov bx, dataoffset szCRLF
+ cCall ttywrite, dsbx
+ mov bx, dataoffset szCRLF
+ cCall ttywrite, dsbx
+ mov bx, dataoffset szBootLoad
+ cCall ttywrite, dsbx
+ cCall ttywrite, s
+ mov bx, dataoffset szCRLF
+ cCall ttywrite, dsbx
+cEnd
+
+cProc SlowBoot,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS
+ ReSetKernelDS
+
+GPPI macro sect, key, defval, file, storeit
+ push ds
+ push dataoffset sect
+
+ push ds
+ push dataoffset key
+
+ push defval
+
+ push ds
+ push dataoffset file
+
+ call GetPrivateProfileInt
+ifb <storeit>
+ mov defval, ax
+endif
+endm
+
+
+GPPS macro sect, key, defval, here, hereLen, file
+ push ds
+ push dataoffset sect
+
+ push ds
+ push dataoffset key
+
+ push ds
+ push dataoffset defval
+
+ push ds
+ push dataoffset here
+
+ push hereLen
+
+ push ds
+ push dataoffset file
+
+ call GetPrivateProfileString
+endm
+
+GPPS1 macro sect, key, defval, here, hereLen, file
+ push ds
+ push dataoffset sect
+
+ push ds
+ push key
+
+ push ds
+ push defval
+
+ push ds
+ push dataoffset here
+
+ push hereLen
+
+ push ds
+ push dataoffset file
+
+ call GetPrivateProfileString
+endm
+
+GPI macro sect, key, defval, storeit
+ push ds
+ push dataoffset sect
+
+ push ds
+ push dataoffset key
+
+ push defval
+
+ call GetProfileInt
+ifb <storeit>
+ mov defval, ax
+endif
+endm
+
+ife PMODE32
+ xor ax,ax
+ mov al,fPadCode
+ GPPI Standard, PadCodeStr, ax, BootFile, nostore
+ or al,ah
+ mov fPadCode,al
+endif
+
+if SHERLOCK
+ GPI szKernel, szGPC, gpEnable
+endif
+
+if KDEBUG
+ifdef DISABLE
+ GPPI szDebugSect, szKRInfo, _krInfoLevel, BootFile
+
+ GPPI szDebugSect, szKRBreak, _krBreakLevel, BootFile
+
+ GPPI szDebugSect, szWin3Info, _Win3InfoLevel, Bootfile
+
+ GPPI szDebugSect, szWin3Break, _Win3BreakLevel, Bootfile
+endif
+endif ;KDEBUG
+
+ GPPS szDebugSect, szOutputTo, szAux, BootBuf, BootBufLen, BootFile
+ or ax, ax
+ jz @F
+ cmp ax, BootBufLen-2
+ jz @F
+
+ mov ah, 3ch ; creat file (zero length)
+ xor cx, cx
+ mov dx, dataOffset BootBuf
+ DOSCALL
+ jc @F
+
+ mov bx, ax
+ mov ah, 3eh ; now close it
+ DOSCALL
+ jc @F
+
+ mov ax, 3d42h ; open inherit, deny none, read/write
+ DOSCALL
+ jc @F
+
+ mov bx, ax ; dup handle
+ mov cx, 3 ; force AUX to be this file
+ mov ah, 46h
+ DOSCALL
+
+ mov ah, 3eh ; close temp file
+ DOSCALL
+ mov wDefRIP, 'i' ; since AUX is redirected, assume Ignore RIP
+@@:
+
+ GPPI BootSect, FilesCached, MAXFHCACHELEN, BootFile, nostore
+ cmp ax, MINFHCACHELEN ; Validate length
+ jae @F
+ mov ax, MINFHCACHELEN
+@@: cmp ax, MAXFHCACHELEN
+ jbe @F
+ mov ax, MAXFHCACHELEN
+@@: mov fhCacheLen, ax ; Adjust # of cached file handles
+ shl ax, 1
+ shl ax, 1
+ add ax, dataoffset fhCache
+ mov fhCacheEnd, ax
+
+ GPPI BootSect, IdleSegLoad, 1, BootFile, nostore
+ mov fPokeAtSegments, al
+
+ifdef WOW
+ GPPI BootSect, ExitLastApp, 0, BootFile, nostore
+ mov fExitOnLastApp, al
+endif
+
+ mov bootExecBlock.lpfcb1.off,dataOffset win_show
+ mov bootExecBlock.lpfcb1.sel,ds
+ mov es,topPDB
+
+ mov bootExecBlock.lpcmdline.off,80h
+ mov bootExecBlock.lpcmdline.sel,es
+
+ mov lpBootApp.off,dataOffset app_name
+ mov lpBootApp.sel,ds
+ cmp graphics,1
+ jnz sb1
+
+ mov lpBootApp.off,dataOffset defapp
+ mov lpBootApp.sel,ds
+
+sb1: mov di,dataOffset bootMods
+
+sbloop1:
+ cCall LoadNewExe,<di>
+ SetKernelDS es
+ mov cx,-1
+ xor ax,ax
+ cld
+ repnz scasb
+ cmp di,dataOffset winmods
+ jb sbloop1
+
+ cmp graphics,1
+ jz sbloop2
+; cCall InitFwdRef
+ jmps sb4
+ UnSetKernelDS es
+
+sbloop2: ; load USER.EXE, GDI.EXE
+ cCall LoadNewExe,<di>
+ push ax ; Save hInst return value
+ SetKernelDS es
+ mov cx,-1
+ xor ax,ax
+ cld
+ repnz scasb
+ pop si ; Get hInst of latest module in SI
+
+ ;** If we just loaded the keyboard driver, we want to
+ ;** point our explicit link variables to the AnsiToOem and
+ ;** OemToAnsi functions so OpenFile can use them for the
+ ;** remaining boot modules
+ cmp di,dataOffset szAfterKeyboardDriver
+ jne SB_NotKeyboardDriver
+
+ push ds ; Save regs we care about
+ push di
+ regptr pStr,ds,bx
+
+ mov bx,dataOffset keyprocstr
+ cCall GetProcAddress,<si,pStr>
+ mov pKeyProc.off,ax
+ mov pKeyProc.sel,dx
+
+ mov bx,dataOffset keyprocstr1
+ cCall GetProcAddress,<si,pStr>
+ mov pKeyProc1.off,ax
+ mov pKeyProc1.sel,dx
+
+ pop di
+ pop ds
+
+SB_NotKeyboardDriver:
+ cmp di,dataOffset defapp
+ jb sbloop2
+
+; OPTIMIZE BEGIN
+
+; OPTIMIZE END
+
+sb4:
+ cCall InitFwdRef ; Gets stuff we can't dynalink to
+ cCall InternalEnableDOS ; Enable int21 hooks
+;sb4:
+ call check_TEMP
+
+; Get the shell name from SYSTEM.INI
+
+ mov ax,dataoffset Shell
+ GPPS1 BootSect, ax, lpBootApp.off, BootBuf, BootBufLen, BootFile
+
+ ;** Here we need to convert the command line to ANSI
+ cmp WORD PTR pKeyProc1[2],0 ; Paranoia...
+ jz @F
+
+ ;** Zero terminate the string before passing to OemToAnsi
+ mov es,bootExecBlock.lpcmdline.sel
+ mov bl,es:[80h] ; Get length byte
+ xor bh,bh
+ xchg BYTE PTR es:[bx+81h],bh ; Replace terminator char with zero
+
+ ;** Call the keyboard driver
+ push es ; Save the seg reg
+ push bx ; Save offset and char saved
+ push es
+ push 81h ; Always starts here (fixed offset)
+ push es
+ push 81h
+ cCall [pKeyProc1] ; Call OemToAnsi in keyboard driver
+ pop bx ; Get saved info
+ pop es
+ mov al,bh ; Saved char from string
+ xor bh,bh
+ mov BYTE PTR es:[bx+81h],al ; Replace the character
+@@:
+
+ mov ax,dataOffset bootExecBlock
+ regptr dsax,ds,ax
+ cmp graphics,1
+ jz @F
+
+ cCall LoadModule,<lpBootApp,dsax>
+ or kernel_flags,KF_pUID
+ mov fBooting,0
+ jmps asdf
+
+@@: cCall FlushCachedFileHandle,<hUser> ; in case 100 fonts are loaded
+ farptr lpBootBuf,ds,di
+ mov di, dataoffset BootBuf
+ cCall LoadModule,<lpBootBuf,dsax>
+
+asdf:
+ cmp ax,32
+ jbe sb6
+
+ cCall GetExePtr,<ax>
+ mov hShell, ax
+ jmp bootdone
+
+sb6:
+ ReSetKernelDS
+ les bx, lpBootApp
+ krDebugOut DEB_ERROR, "BOOT: unable to load @ES:BX"
+ cCall LoadFail,<lpBootApp>
+
+; cmp pDisableProc.sel,0 ; Is there a USER around yet?
+; jz @F
+; cCall pDisableProc
+;@@:
+ jmp bootfail
+ UnSetKernelDS
+cEnd nogen
+
+
+;------------------------------------------------------------------------
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc LoadNewExe,<PUBLIC,NEAR>,<si,di>
+ parmW pname
+cBegin
+ farptr lpparm,ax,ax
+ farptr lpBootBuf,ds,di
+ mov di, dataoffset BootBuf
+
+ CheckKernelDS
+ ReSetKernelDS
+ifdef WOW
+; ATM Alters system.ini registry boot section to load its own SYSTEM.DRV
+; However on WOW this causes us to fail to load correctly. Also we
+; would be hard pushed to support the current 16 bit ATM since it relies
+; on internals of 16 bit GDI which are not present in WOW.
+; For this Beta I'm going to ignore the bootsection of the registry
+; when loading drivers and thus ATM will not get installed.
+; At least the user will be protected from not being able to boot WOW
+; BUGBUG - Consider
+; MattFe Oct9 92
+
+ mov di,pname
+else
+ GPPS1 BootSect, pname, pname, BootBuf, BootBufLen, BootFile
+endif
+ xor ax,ax
+ cCall LoadModule,<lpBootBuf,lpparm>
+ cmp ax,2
+ jne lne1
+ krDebugOut DEB_ERROR, "Can't find @DS:DI"
+; kerror ERR_LDBOOT,<BOOT: Unable to find file - >,ds,di
+ jmps lne4
+lne1:
+ cmp ax,11
+ jne lne2
+ krDebugOut DEB_ERROR, "Invalid EXE file @DS:DI"
+; kerror ERR_LDBOOT,<BOOT: Invalid .EXE file - >,ds,di
+ jmps lne4
+lne2:
+ cmp ax,15
+ jnz lne3
+ krDebugOut DEB_ERROR, "Invalid protect mode EXE file @DS:DI"
+; kerror ERR_LDBOOT,<BOOT: Invalid protect mode .EXE file - >,ds,di
+ jmps lne4
+
+lne3:
+ cmp ax, 4
+ jne lne3a
+ krDebugOut DEB_ERROR, "Out of files (set FILES=30 in CONFIG.SYS) @DS:DI"
+; kerror ERR_LDFILES,<BOOT: Out of files, (set FILES=30 in CONFIG.SYS) loading - >,ds,di
+ jmps lne4
+
+lne3a:
+ cmp ax, 32
+ jae lnex
+
+NoLoadIt:
+; kerror ERR_LDBOOT,<BOOT: Unable to load - >,ds,pname
+ krDebugOut DEB_ERROR, "Unable to load @DS:DI (#ax)"
+lne4:
+ cCall LoadFail,dsdi
+ mov ax,1
+ cCall ExitKernel,<ax>
+lnex:
+ UnSetKernelDS
+cEnd
+
+sEnd INITCODE
+
+;-----------------------------------------------------------------------;
+; BootDone ;
+; ;
+; Boot is done when all of modules are loaded. Here we do a bit of ;
+; clean up, such as validating code segments, initing free memory to ;
+; CCCC, freeing up the fake TDB, and finally reallocating the init ;
+; code away. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; nothing ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; all ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Wed Apr 15, 1987 08:53:23p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+
+DataBegin INIT
+
+szKernel DB 'KERNEL',0
+szWindows DB 'WINDOWS',0
+
+if KDEBUG
+szDebugOptions DB 'DebugOptions',0
+szDebugFilter DB 'DebugFilter',0
+
+szChecksum DB 'EnableSegmentChecksum',0
+szSweepFreak DB 'LRUSweepFrequency',0
+sz80x87 DB 'NoUse80x87',0
+szFastFP DB 'FastFP', 0
+
+externW DebugOptions
+externW DebugFilter
+
+ifdef DISABLE
+externB fLoadTrace
+endif
+
+endif ; KDEBUG
+
+ifdef SDEBUG
+szEMSDebug DB 'EnableEMSDebug',0
+endif
+szgrab_386 DB '386GRABBER',0
+
+if SWAPPRO
+szSwapPro DB 'SwapProfile',0
+szSwapFile DB 'SWAPPRO.DAT',0
+endif
+
+DataEnd INIT
+
+
+sBegin INITCODE
+assumes cs,CODE
+assumes ds,nothing
+assumes es,nothing
+
+
+cProc BootDone,<PUBLIC,NEAR>
+cBegin nogen
+
+ SetKernelDS
+
+if KDEBUG
+
+; Get win.ini [Windows] DebugOptions
+ GPI szWindows, szDebugOptions, DebugOptions
+; Get win.ini [Windows] DebugFilter
+ GPI szWindows, szDebugFilter, DebugFilter
+
+; Now set various internal flags based on DebugOptions
+
+ xor ax,ax
+ test DebugOptions,DBO_CHECKHEAP
+ jz @F
+ inc ax
+@@:
+ mov es,pGlobalHeap
+ mov es:[hi_check],ax
+
+ test DebugOptions,DBO_CHECKFREE
+ jz @F
+ or Kernel_flags,kf_check_free
+@@:
+ifdef DISABLE
+ xor ax,ax
+ test DebugOptions,DBO_LOADTRACE
+ jz @F
+ mov fLoadTrace, al
+@@:
+endif ; DISABLE
+ test DebugOptions,DBO_DISABLEGPTRAPPING
+ jz wants_trapping
+
+ mov ax,0203h ; Reset GP fault.
+ mov bl,0Dh
+ mov cx,prevInt0Dproc.sel
+ mov dx,prevInt0Dproc.off
+ int 31h
+
+ mov ax,0203h ; Reset invalid op-code exception.
+ mov bl,06h
+ mov cx,prevIntx6proc.sel
+ mov dx,prevIntx6proc.off
+ int 31h
+
+ mov ax,0203h ; Reset page fault.
+ mov bl,0Eh
+ mov cx,prevInt0Eproc.sel
+ mov dx,prevInt0Eproc.off
+ int 31h
+wants_trapping:
+
+if SWAPPRO
+ GPI szKernel, szSwapPro, 1, nostore
+ mov fSwapPro, al
+
+ mov bx,TopPDB
+ mov ah,50h
+ pushf
+ FCLI
+ call prevInt21Proc
+
+ lea dx,szSwapFile
+ xor cx,cx
+ mov ah,3Ch
+ pushf
+ FCLI
+ call prevInt21Proc
+ mov hSwapPro,ax
+
+ mov bx,cur_dos_pdb
+ mov ah,50h
+ pushf
+ FCLI
+ call prevInt21Proc
+endif
+ GPI szKernel, szChecksum, 1, nostore
+ mov fChkSum,al
+
+ GPI szKernel, sz80x87, 0, nostore
+ or ax,ax
+ jz wants_8087
+ mov f8087,0
+ and WinFlags,NOT WF1_80x87 ;Turn off corresponding WinFlags bit
+wants_8087:
+ GPI szKernel, szFastFP, 1, nostore
+ mov fastFP, al
+
+ GPI szKernel, szSweepFreak, 500, nostore
+else
+ mov ax, 500
+endif ; KDEBUG
+
+ifdef WOW
+ xor ax,ax
+endif
+
+ or ax,ax
+ jz nolrusweep
+
+ test WinFlags[1], WF1_PAGING
+ jnz short nolrusweep
+
+ mov bx,codeOffset lrusweep
+ regptr csbx,cs,bx
+ xor dx,dx
+ cCall pTimerProc,<dx,ax,csbx>
+nolrusweep:
+
+if SDEBUG
+ GPI szKernel, szEMSDebug, 0, nostore
+ or ax,ax
+ jz no_EMS_debug_wanted
+ or Kernel_flags,kf_EMS_debug
+no_EMS_debug_wanted:
+endif
+
+if LDCHKSUM
+ cCall ValidateCodeSegments
+endif
+
+if KDEBUG
+ mov fCheckFree,0
+
+ife PMODE32
+ call init_free_to_CCCC
+endif
+
+endif
+
+; Get the shell name from SYSTEM.INI
+
+ GPPS BootSect, szgrab_386, szgrab_386, grab_name, 128, BootFile
+
+ mov es,curTDB ; ES = TDB of fake task
+ push es
+ cCall DeleteTask,<es> ; Flush bogus task
+ pop es
+ xor dx,dx
+ mov es:[TDB_sig],dx ; Clear signature word.
+ mov curTDB,dx ; Let someone else be current task
+
+; switch to the temp stack since we're about to Realloc the present one away
+
+ mov ax, ss
+
+ FCLI
+ SetKernelDS ss
+ mov sp,dataOffset gmove_stack
+ FSTI
+
+ cCall free_sel,<ax>
+
+
+; Shrink DGROUP down to its post initialization size
+
+ mov cx,dataOFFSET beg_emsdata ; don't need EMS data
+need_EMS_data:
+
+ cCall IGlobalReAlloc,<ds,dx,cx,dx> ; Realloc DGROUP
+
+ xor dx,dx
+
+
+; Now shrink the resident CODE segment
+
+ife ROM
+ mov cx,codeOFFSET beg_emscode ; dont need EMS code
+need_EMS_code:
+
+; cCall IGlobalReAlloc,<cs,dxcx,dx>
+; jmps BootSchedule ; Jump to schedule first app
+
+ push cs ; Arguments to GlobalReAlloc
+ push dx
+ push cx
+ push dx
+ push cs ; Where GlobalReAlloc will eventually return
+ mov ax,codeOFFSET BootSchedule
+ push ax
+ jmp near ptr IGlobalReAlloc ; Jump to GlobalReAlloc
+
+else ;ROM
+
+ jmp BootSchedule
+endif
+ UnSetKernelDS ss
+ UnSetKernelDS
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; check_TEMP
+;
+; If the environment variable TEMP points to garbage then GetTempFile
+; screws up. We fix it by wiping out the TEMP string if it points
+; to garbage.
+;
+; Entry:
+; none
+;
+; Returns:
+;
+; Registers Preserved:
+; all
+;
+; History:
+; Thu 11-May-1989 16:39:34 -by- David N. Weise [davidw]
+; Wrote it.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc check_TEMP,<PUBLIC,NEAR>,<ds,es>
+ifdef DBCS
+ localW pMyBuf
+endif
+cBegin
+ pusha
+ SetKernelDS
+ sub sp,130
+ mov di,sp
+ CheckKernelDS
+ mov ds,TopPDB
+ UnSetKernelDS
+ mov ds,ds:[PDB_environ]
+ xor si, si ; assume DS:SI points to environment
+ cCall GetTempDrive,<si>
+ smov es,ss
+ cld
+ stosw
+ifdef DBCS
+ mov pMyBuf,di ; save string offset(exclude D:)
+endif
+stmp2:
+ lodsw
+ or al,al ; no more enviroment
+ifdef DBCS
+ jnz @F ; I hate this
+ jmp stmpNo1
+@@:
+else
+ jz stmpNo1
+endif
+ cmp ax,'ET' ; Look for TEMP=
+ jne stmp3
+ lodsw
+ cmp ax,'PM'
+ jne stmp3
+ lodsb
+ cmp al,'='
+ je stmpYes
+stmp3: lodsb
+ or al,al
+ jnz stmp3
+ jmp stmp2
+stmpYes:
+ push si ; save pointer to TEMP
+ push ds
+
+ push si ; spaces are legal, but they
+lookForSpace: ; confuse too many apps, so
+ lodsb ; we treat them as illegal
+ cmp al, ' '
+ jz stmpFoundSpace
+ or al, al
+ jnz lookForSpace
+ pop si
+ cmp byte ptr [si+1],':'
+ jne stmpnodrive
+ and byte ptr [si],NOT 20h ; springboard needs this!
+ dec di
+ dec di
+stmpnodrive:
+ lodsb
+ or al,al
+ jz stmpNo
+ stosb
+ jmp stmpnodrive
+
+stmpNo:
+ mov ax,'~\'
+ cmp es:[di-1],al ; does it already end in \
+ jnz stmpNoF ; no, just store it
+ dec di ; override it
+ifdef DBCS
+ push si
+ mov si,pMyBuf
+ call FarMyIsDBCSTrailByte ;is that '\' a DBCS trailing byte?
+ cmc
+ adc di,0 ;skip it if yes.
+ pop si
+endif
+stmpNoF:
+ stosw
+ xor ax,ax
+ stosb ; zero terminate the sucker
+ pop es ; recover pointer to TEMP
+ pop di
+ smov ds,ss
+ mov dx,sp
+ mov ax,5B00h
+ xor cx,cx
+ DOSCALL
+ jnc stmpClose
+ cmp al,80 ; Did we fail because the file
+ jz stmpNo1 ; already exists?
+stmpNukeIt:
+ sub di,5 ; Get the TEMP= part.
+@@: mov al,'x'
+ xchg al,es:[di]
+ inc di
+ or al,al
+ jnz @B
+ mov byte ptr es:[di-1],0
+ jmps stmpNo1
+
+stmpClose:
+ mov bx,ax
+ mov ah,3Eh
+ DOSCALL
+ mov ah,41h
+ DOSCALL
+
+stmpNo1:
+ add sp,130
+ popa
+cEnd
+stmpFoundSpace:
+ pop si
+ pop es
+ pop di
+ jmps stmpNukeIt
+
+
+;-----------------------------------------------------------------------;
+; get_windir
+;
+; Get a pointer to the 'windows' directory.
+;
+; Entry:
+; DS => environment string
+;
+; Returns:
+; CX = length of string
+; DI => WFP of 'windows' directory
+;
+; Registers Preserved:
+; all
+;
+; History:
+; Mon 16-Oct-1989 23:17:23 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifdef WOW
+;-----------------------------------------------------------------------;
+; original get_windir looks for the environment variable 'windir' (all
+; lowercase) to set the 'windows' directory.
+;
+; On NT the equivalent environment variable is 'SystemRoot' (all
+; uppercase). Hence the code is different.
+;
+; - nanduri
+;
+; There are some customers that used the undocumented trick on win31
+; of moving windir to some network location by putting win.com there.
+; The result would be that the "Windows Directory" would point
+; to the network location, and the system directory would be local.
+; Currently, the way WINDIR is supported involves hacks in a couple
+; of different places. What would be best is if you could do a
+; "set windir=xxxx" in your autoexec.nt and we would look for windir
+; here and we would code it to emulate win31 behavior. However, that's
+; broken right now, and windir is only regenerated after krnlx86.exe
+; has finished booting. So the approach taken here is to look for
+; a new environment variable called win16dir, and if it exists, make
+; the windows directory point to it. Systemroot is still used to
+; generate the system directory.
+;
+; We want to allow NT to be installed into a directory with a long
+; name, so we use GetShortPathName on the directory we get from
+; either SystemRoot or Win16Dir variables.
+; -- DaveHart 9-Feb-96
+;-----------------------------------------------------------------------;
+
+szSystemRoot DB 'SYSTEMROOT=',0
+szWin16Dir DB 'WIN16DIR=',0
+
+cProc get_windir,<PUBLIC,NEAR>
+cBegin nogen
+
+ push es
+ mov ax, cs ; the string is in 'cs', see above
+ mov es, ax
+ mov di, codeoffset szSystemRoot
+ call get_env_var_ptr
+
+ push dx
+ mov dx, ds
+ mov es, dx
+ SetKernelDS
+ mov si, dataoffset achRealWindowsDir
+ regptr esdi,es,di
+ regptr dssi,ds,si
+ mov cx, WINDIR_BUFSIZE
+ push dx
+ cCall GetShortPathName, <esdi, dssi, cx>
+ pop dx
+ mov cbRealWindowsDir,ax
+ mov ds, dx ;restore ds
+ pop dx
+ assumes ds,nothing
+
+ push cx
+ push di
+
+ mov ax, cs ; the string is in 'cs', see above
+ mov es, ax
+ mov di, codeoffset szWin16Dir
+ call get_env_var_ptr
+ or di, di ;does win16dir exist?
+ jz gw_not
+ add sp, 4 ;throw away systemroot
+ jmp short gw_cont
+
+gw_not:
+ pop di
+ pop cx
+
+gw_cont:
+ ; Now ds:di points to the Windows directory string in
+ ; the environment block. It may be a long pathname,
+ ; so fix it up.
+ smov es, ds
+ SetKernelDS
+ mov si, dataoffset achWindowsDir
+ regptr esdi,es,di
+ regptr dssi,ds,si
+ mov cx, WINDIR_BUFSIZE
+ cCall GetShortPathName, <esdi, dssi, cx>
+ mov cx, ax
+ smov ds, es
+ assumes ds,nothing
+
+ pop es
+ ret
+
+cEnd nogen
+
+cProc get_env_var_ptr,<PUBLIC,NEAR>
+cBegin nogen
+ cld
+ push si
+ xor si,si
+
+ push di
+ mov cx,-1
+ xor ax,ax
+ repnz scasb
+ not cx
+ dec cx ; length of szSystemRoot
+ pop di
+
+gw_cmp:
+ mov al, [si]
+ or al, al
+ jz gw_exit
+
+ push di
+ push cx
+ repz cmpsb ; compare the inputstring with szSystemRoot
+ pop cx
+ pop di
+
+ jnz gw_next ; not szSystemRoot
+ xor cx,cx ; yes szSystemRoot, cx=0 indicates so
+ mov di,si
+
+gw_next:
+ lodsb
+ or al,al
+ jnz gw_next ; skip to the terminating NULL.
+ or cx,cx ; cx==0 implies... found szSystemRoot
+ jnz gw_cmp ; compare with the next environment string
+ mov cx,si ; here if found szSystemRoot.
+ sub cx,di
+ mov ax,di
+ dec cx
+
+
+gw_exit:
+ mov di,ax
+ pop si
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; original get_windir is within the 'else' 'endif' block
+;
+;-----------------------------------------------------------------------;
+
+else
+
+cProc get_windir,<PUBLIC,NEAR>
+cBegin nogen
+ cld
+ push si
+ xor di,di
+ xor si,si
+gw: lodsw
+ or al,al ; no more enviroment
+ jz gw_exit
+if ROM
+ if1
+ %out Take this out!
+ endif
+ ;;;!!!only until loader builds proper environment block
+ or ax,2020h ; ignore case of ENV string
+endif
+ cmp ax,'iw' ; Look for windir=
+ jne @F
+ lodsw
+if ROM
+ ;;;!!!only until loader builds proper environment block
+ or ax,2020h ; ignore case of ENV string
+endif
+ cmp ax,'dn'
+ jne @F
+ lodsw
+if ROM
+ ;;;!!!only until loader builds proper environment block
+ or ax,2020h ; ignore case of ENV string
+endif
+ cmp ax,'ri'
+ jne @F
+ lodsb
+ cmp al,'='
+ je gw_got_it
+@@: lodsb
+ or al,al
+ jnz @B
+ jmp gw
+gw_got_it:
+ mov di,si
+@@: lodsb
+ or al,al
+ jnz @B
+ mov cx,si
+ sub cx,di
+ dec cx
+gw_exit:
+ pop si
+ ret
+cEnd nogen
+
+endif
+
+
+sEnd INITCODE
+
+;------------------------------------------------------------------------
+
+sBegin STACK
+
+; Boot TDB
+
+boottdb equ this byte
+ DB SIZE TDB dup (0)
+
+if 0
+ ;0123456789012345
+; Boot EEMS context save area
+
+NUMBER_OF_BANKS = 4 * (0FFFFh - (LOWEST_SWAP_AREA * 64) + 1)/400h
+
+boottdb_EEMSsave equ this byte
+ DB NUMBER_OF_BANKS + 100h DUP (0)
+endif
+
+; do a clumsy paragraph alignment
+
+ rept 16
+if ($ - boottdb) and 0Fh
+ db 0
+endif
+ endm
+
+; Dummy arena entry so boot SS looks like a valid object
+
+ DB 'M'
+ DW -1
+ DW (BOOTSTACKSIZE + 31)/16
+ DB 0
+ DW 5 DUP (0)
+
+; Another in case we have to tweek the low order bit of SS
+
+ DB 'M'
+ DW -1
+ DW (BOOTSTACKSIZE + 15)/16
+ DB 0
+ DW 5 DUP (0)
+
+; Boot stack
+
+stackbottom equ this word
+ DB BOOTSTACKSIZE DUP (0)
+stacktop equ this word
+
+ DW -1
+
+sEnd STACK
+
+end BootStrap
diff --git a/private/mvdm/wow16/kernel31/ldcache.asm b/private/mvdm/wow16/kernel31/ldcache.asm
new file mode 100644
index 000000000..b38ccf88b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldcache.asm
@@ -0,0 +1,384 @@
+ TITLE LDCACHE - Segment and File Handle Caching procedures
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+
+.list
+
+DataBegin
+
+externW hExeHead
+
+externW topPDB
+externW Win_PDB
+externW curTDB
+externW cur_dos_PDB
+externB fhCache
+externW fhCacheLen
+externW fhCacheEnd
+externW fhcStealNext
+
+DataEnd
+
+externFP MyOpenFile
+externFP Int21Handler
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP real_DOS
+
+;-----------------------------------------------------------------------;
+; GetCachedFileHandle ;
+; ;
+; Look for the file handle for an EXE file in the cache of file ;
+; handles. Sets current PDB to that of KERNEL to access the file. ;
+; A handle NOT to free in order to satisfy the request can also ;
+; be given. ;
+; ;
+; Arguments: ;
+; parmW hExe handle of EXE file ;
+; parmW keepfh file handle not to change ;
+; parmW fh file handle if file already open ;
+; ;
+; Returns: ;
+; AX == file handle ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; real_DOS ;
+; ;
+; History: ;
+; Wed 18-Oct-1989 20:40:51 -by- David N. Weise [davidw] ;
+; Added the feature of not closing a specified handle. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+ifdef WOW
+ .286
+else
+endif
+
+cProc FarGetCachedFileHandle,<PUBLIC,FAR>
+ parmW hExe
+ parmW keepfh
+ parmW fh
+cBegin
+ cCall GetCachedFileHandle,<hExe,keepfh,fh>
+cEnd
+
+
+cProc GetCachedFileHandle,<PUBLIC,NEAR>,<bx,di,ds,es>
+ parmW hExe
+ parmW keepfh
+ parmW fh ; -1 if file not open
+ localW fhcFreeEntry
+cBegin
+ SetKernelDS
+ mov fhcFreeEntry, 0
+
+ mov bx, topPDB
+
+;;; cmp bx, Win_PDB
+;;; je gcfh_okPDB ; Don't bother setting if already this
+;;; mov cur_dos_PDB, bx
+;;; mov Win_PDB, bx ; Run on kernel's PDB for a while
+;;; mov ah, 50h ; set PDB
+;;; call real_DOS
+;;;gcfh_okPDB:
+
+ mov Win_PDB, bx ; Run on kernel's PDB for a while
+
+ mov ax, hExe ; look for this EXE in the file
+ mov es, ax ; handle cache
+ mov cx, fhCacheLen
+ mov di, dataOffset fhCache
+gcfh_searchfh:
+ mov bx, [di.CacheExe]
+ cmp ax, bx
+ jne @F
+ jmps gcfh_found
+@@:
+ or bx, bx ; Free entry?
+ jnz gcfh_searchnext
+ cmp fhcFreeEntry, bx ; already have a free entry?
+ jne gcfh_searchnext
+ mov fhcFreeEntry, di ; Save index for free entry
+gcfh_searchnext:
+ add di, size fhCacheStruc
+ loop gcfh_searchfh
+ ; EXE not already in the cache
+ mov di, fhcFreeEntry ; Did we find a free entry?
+ or di, di
+ jz gcfh_stealone ; no, steal one
+ mov fhcFreeEntry, -1 ; Flag to steal one if the open fails
+ jmps gcfh_openit ; (due to out of file handles)
+
+gcfh_stealone: ; No free entry, pick one on first come,
+ mov cx, fhcStealNext ; first served basis
+gcfh_stealnext:
+ mov di, cx
+ add cx, 4 ; Calculate next index in CX
+ cmp cx, fhCacheEnd
+ jb gcfh_oknext
+ mov cx, dataoffset fhCache ; Start back at the beginning
+gcfh_oknext:
+ mov bx, [di.Cachefh]
+ or bx, bx ; If no file handle,
+ jz gcfh_stealnext ; on to next cache entry
+ cmp bx, keepfh ; If handle not to free
+ jz gcfh_stealnext ; on to next cache entry
+ mov fhcStealNext, cx
+
+ mov ah, 3Eh
+ DOSCALL ; Close this file handle
+ mov fhcFreeEntry, di
+
+gcfh_openit:
+ push ds
+ mov ax, fh
+ cmp ax, -1 ; File already open?
+ jne gcfh_opened ; yes, just put in cache
+
+ mov dx,es:[ne_pfileinfo]
+ regptr esdx,es,dx
+; mov bx,OF_SHARE_DENY_WRITE or OF_REOPEN or OF_PROMPT or OF_VERIFY or OF_CANCEL
+;;; mov bx,OF_REOPEN or OF_PROMPT or OF_VERIFY or OF_CANCEL
+if 1
+ smov ds,es
+ add dx, opFile
+;;; test es:[ne_flags],NEAPPLOADER
+;;; jnz @F
+if SHARE_AWARE
+ mov ax, 3DA0h ; open for read, deny write, no inherit
+else
+ mov ax, 3D80h ; open for read, no inherit
+endif
+ DOSCALL
+ jnc gcfh_opened
+;;;@@:
+ mov ax, 3DC0h ; try share deny none
+ DOSCALL
+ jnc gcfh_opened
+else
+ mov bx,OF_REOPEN or OF_VERIFY
+ push es
+ cCall MyOpenFile,<esdx,esdx,bx>
+ pop es
+ cmp ax, -1
+ jne gcfh_opened
+endif
+ pop ds
+ cmp fhcFreeEntry, -1 ; This was a free cache entry?
+ je gcfh_stealone ; yes, have run out of file handles
+ mov ax, -1 ; fix bug #6774 donc
+ jmps gcfh_exit ; no, a real failure
+gcfh_found:
+ mov ax, [di.Cachefh]
+ jmps gcfh_exit
+gcfh_opened:
+ pop ds
+ mov [di.Cachefh], ax
+ mov [di.CacheExe], es
+
+gcfh_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; CloseCachedFileHandle ;
+; ;
+; Close the EXE file with the given file handle. ;
+; Actually does delays closing the file until the handle is needed. ;
+; Resets the current PDB to that of the current task. ;
+; ;
+; Arguments: ;
+; parmW fh file handle being 'closed' ;
+; ;
+; Returns: ;
+; none ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX ;
+; ;
+; Calls: ;
+; real_DOS ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CloseCachedFileHandle,<PUBLIC,NEAR>,<bx,ds,es>
+ parmW fh
+cBegin
+;;; SetKernelDS
+;;; mov es, curTDB
+;;; mov bx, es:[TDB_PDB]
+;;; cmp bx, Win_PDB
+;;; je ccfh_okPDB
+;;; mov Win_PDB, bx
+;;; mov cur_dos_PDB, bx
+;;; mov ah, 50h
+;;; call real_DOS
+;;;ccfh_okPDB:
+cEnd
+
+;-----------------------------------------------------------------------;
+; FlushCachedFileHandle ;
+; ;
+; Look for the file handle for an EXE file in the cache of file handles ;
+; If it is found, close the file. ;
+; ;
+; Arguments: ;
+; parmW hExe handle of EXE file ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; real_DOS ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FlushCachedFileHandle,<PUBLIC,FAR>,<ax,bx,cx,di>
+ parmW hExe
+cBegin
+ SetKernelDS
+ mov ax, hExe
+ or ax, ax ; make sure we really
+ jz fcfh_exit ; have a hExe
+ mov cx, fhCacheLen
+ mov di, dataOffset fhCache
+fcfh_search:
+ cmp ax, [di.CacheExe]
+ je fcfh_found
+ add di, size fhCacheStruc
+ loop fcfh_search
+ jmps fcfh_exit ; Not cached, nothing to do
+fcfh_found:
+
+;;; mov bx, topPDB
+;;; cmp bx, cur_dos_PDB
+;;; je fcfh_okPDB
+;;; mov cur_dos_PDB, bx
+;;; mov ah, 50h ; set PDB
+;;; call real_DOS
+;;;fcfh_okPDB:
+
+ push Win_PDB ; Save 'current' PDB
+
+ mov bx, topPDB
+ mov Win_PDB, bx ; Run on kernel's PDB for a while
+
+ mov bx, [di.Cachefh]
+ mov ah, 3Eh ; Close the file
+ DOSCALL
+ xor ax, ax
+ mov [di.Cachefh], ax ; mark cache entry free
+ mov [di.CacheExe], ax
+
+;;; push es
+;;; mov es, curTDB ; and reset the PDB
+;;; mov bx, es:[TDB_PDB]
+;;; pop es
+;;; cmp bx, Win_PDB
+;;; je fcfh_exit
+;;; mov Win_PDB, bx
+;;; mov cur_dos_PDB, bx
+;;; mov ah, 50h
+;;; call real_DOS
+
+ pop Win_PDB ; Restore original PDB
+
+fcfh_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; CloseCachedFiles ;
+; ;
+; Close all the cached files on a duplicate PDB ;
+; Leaves PDB set to new PDB ;
+; ;
+; Arguments: ;
+; parmW pdb new PDB ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; real_DOS ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc CloseCachedFiles,<PUBLIC,FAR>,<ax,bx,cx,di,ds>
+ parmW pdb
+cBegin
+ SetKernelDS
+ mov bx, pdb
+ mov Win_PDB, bx
+;;; mov ah, 50h
+;;; call real_DOS ; Run on the new guy
+
+ mov dx, bx
+ mov cx, fhCacheLen
+ mov di, dataOffset fhCache
+ccf_search:
+ mov bx, [di.Cachefh]
+ or bx, bx
+ je ccf_next
+ mov ah, 3Eh ; Close the file
+ call real_DOS
+
+ cmp dx,topPDB ; If closing cached files on
+ jne ccf_next ; the kernel's PDB, mark the
+ xor ax,ax ; cache entry as free
+ mov [di.Cachefh], ax
+ mov [di.CacheExe], ax
+
+ccf_next:
+ add di, size fhCacheStruc
+ loop ccf_search
+
+cEnd
+
+sEnd CODE
+
+ end
diff --git a/private/mvdm/wow16/kernel31/lddebug.asm b/private/mvdm/wow16/kernel31/lddebug.asm
new file mode 100644
index 000000000..974e9f793
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lddebug.asm
@@ -0,0 +1,2230 @@
+ TITLE LDDEBUG - Debugger interface procedures
+
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+include wow.inc
+include dbgsvc.inc
+include bop.inc
+ifdef WOW
+include vint.inc
+endif
+
+;.386p
+
+HEAPDUMP = 0
+
+DEBUGOFFSET equ 000FBH
+INTOFFSET equ 4*3+2
+
+DEBUGCALL MACRO
+ call MyDebugCall
+ ENDM
+
+DataBegin
+
+externW winVer
+externW wDefRip
+externB Kernel_Flags
+externB Kernel_InDOS
+externB fDW_Int21h
+externW pGlobalHeap
+externW hGlobalHeap
+externD ptrace_dll_entry
+externD lpfnToolHelpProc
+externD pKeyboardSysReq
+externW curTDB
+externW wExitingTDB
+externW <Win_PDB, topPDB>
+
+ifdef WOW
+externD FastBop
+externW DebugWOW
+if PMODE32
+externW gdtdsc
+endif; PMODE32
+endif; WOW
+
+debugseg dw 0
+
+IF KDEBUG
+externB fKTraceOut
+ENDIF
+
+DataEnd
+
+ifdef WOW
+externFP GetModuleFileName
+externFP GetModuleHandle
+externFP WOWOutputDebugString
+externFP WOWNotifyTHHOOK
+endif
+
+sBegin CODE
+assumes CS,CODE
+
+if pmode32
+externNP get_arena_pointer32
+else
+externNP get_arena_pointer
+endif
+
+
+externNP GetOwner
+externNP genter
+externNP get_physical_address
+externNP ValidatePointer
+
+sEnd CODE
+
+
+sBegin INITCODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+;-----------------------------------------------------------------------;
+; debuginit ;
+; ;
+; Returns a non zero value in AX if debugger is resident. ;
+; If the debugger is present a distinquished string of "SEGDEBUG",0 ;
+; will be found at 100H off of the interrupt vector segment (int 3). ;
+; ;
+; Arguments: ;
+; None. ;
+; ;
+; Returns: ;
+; AX =! 0 if debugger resident. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:03:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugInit,<PUBLIC,NEAR>,<es,si,di>
+cBegin
+
+ CheckKernelDS
+ ReSetKernelDS
+
+ DebInt 4fh
+
+ cmp ax, 0F386h
+ jne short no_debugger
+ inc debugseg
+ or Kernel_flags[2],KF2_SYMDEB
+no_debugger:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DebugDebug
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 21-Jun-1988 13:10:41 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugDebug,<PUBLIC,NEAR>
+
+cBegin nogen
+
+ push ds
+ SetKernelDS
+
+ifdef WOW
+ call WOWNotifyTHHOOK
+endif
+
+ test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
+ jz short dd_done
+
+; Tell the debugger where it can poke around for kernel data structure info
+
+ push ax
+ push bx
+ push cx
+ push dx
+ mov bx,winVer
+ mov cx,dataOffset hGlobalHeap
+ mov dx,ds
+ DebInt 5ah
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ UnSetKernelDS
+dd_done:
+ pop ds
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; DebugSysReq
+;
+; tell the keyboard driver to pass sys req through
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 19-Sep-1989 21:42:02 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugSysReq,<PUBLIC,NEAR>
+cBegin nogen
+
+ CheckKernelDS
+ ReSetKernelDS
+ mov ax,debugseg
+ or ax,ax
+ jz short dwr_ret
+ cmp pKeyboardSysReq.sel,0 ; is there a keyboard driver?
+ jz short dwr_ret
+ mov ax,1 ; use int 2
+ cCall pKeyboardSysReq,<ax>
+dwr_ret:
+ ret
+
+cEnd nogen
+
+
+sEnd INITCODE
+
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+; Copyright (c) Microsoft Coropration 1989-1990. All Rights Reserved.
+
+;
+; Stolen from DOSX\DXBUG.ASM
+;
+
+
+; -------------------------------------------------------
+; GENERAL SYMBOL DEFINITIONS
+; -------------------------------------------------------
+
+Debug_Serv_Int equ 41h ;WDEB386 service codes
+DS_Out_Char equ 0
+DS_Out_Symbol equ 0fh
+
+
+; Find owner of 'sel', copy name to buffer, zero terminate name
+; return count of chars copied, or 0.
+
+cProc GetOwnerName,<PUBLIC,FAR>,<ds, si, di>
+ parmW obj
+ parmD buf
+ parmW buflen
+cBegin
+ push [obj]
+ call GetOwner
+ or ax, ax
+ jz gon_exit
+
+ mov ds, ax ; DS:SI points to name
+ xor ax, ax
+ cmp word ptr ds:[0], NEMAGIC
+ jnz gon_exit
+ mov si, ds:[ne_restab]
+ lodsb ; get length
+ cmp ax, [buflen] ; name must be smaller than buf
+ jb @F
+ mov ax, [buflen]
+ dec ax
+@@: mov cx, ax
+ cld
+ les di, [buf]
+ rep movsb
+ mov byte ptr es:[di], 0
+gon_exit:
+cEnd
+
+
+;******************************************************************************
+;
+; KOutputDebugStr
+;
+; Basically stolen from Windows/386 code by Ralph Lipe -- hacked up for
+; 286 instead of 386. Here in RalphL's own words is the description:
+;
+; DESCRIPTION:
+; The following code is not pretty but it does what it needs to. It will
+; only be included in DEBUG versions of Kernel. It accepts an ASCIIZ
+; string which it will output to the COM1 serial port. If the string
+; contains #(Register) (for example #AX) then the value of that register
+; will be output. It will not work for segment registers.
+;
+; If the string contains ?(Register)[:(Register)] (for example ?AX or
+; ?AX:BX) then the value of the register(s) is passed to the debugger
+; to display the label nearest to the given address. (It, also, will
+; not work with segment registers. If ?AX is given, then the segment is
+; assumed to be the DS data segment.
+;
+; Lower case register forces skip leading zeros.
+;
+; ENTRY:
+; DS:SI -> ASCIIZ string
+;
+; EXIT:
+; All registers and flags trashed
+;
+; ASSUMES:
+; This procedure was called by the Trace_Out macro. It assumes that
+; the stack is a pusha followed by a FAR call to this procedure.
+;
+;------------------------------------------------------------------------------
+
+
+Reg_Offset_Table LABEL WORD ; Order of PUSHA
+ dw "DI"
+ dw "SI"
+ dw "BP"
+ dw "SP"
+ dw "BX"
+ dw "DX"
+ dw "CX"
+ dw "AX"
+ dw "SS"
+ dw "ES"
+ dw "DS"
+ dw "CS"
+
+OSC1_ModName:
+ pop ax
+OSC1_ModName1:
+ push es
+ mov es, ax
+ cmp word ptr es:[0], NEMAGIC
+ jz @F
+ pop es
+ jmps is_pdb
+@@: mov cx, es:[ne_restab]
+ inc cx ; skip length byte
+ pop es
+ jmp Show_String ; AX:CX -> string to print
+
+OSC1_FileName:
+ pop ax
+ push es
+ mov es, ax
+ mov cx, word ptr es:[ne_crc+2]
+ add cx, 8
+ pop es
+ jmp Show_String
+
+szUnk db 'Unknown',0
+
+OSC1_OwnerName:
+ pop ax
+ push ds
+ push ax
+ cCall GetOwner ; seg value already on stack
+ pop ds
+ or ax, ax
+ jnz OSC1_ModName1
+is_pdb: mov ax, cs
+ mov cx, CodeOffset szUnk
+ jmp Show_String
+
+OSC1_Custom:
+ call Get_Register
+ jnc short OSC1_not_special
+ or ax, ax
+ jz short OSC1_not_special
+ push ax
+ lodsb
+ cmp al, '0'
+ jz short OSC1_ModName
+ cmp al, '1'
+ jz short OSC1_FileName
+ cmp al, '2'
+ jz short OSC1_OwnerName
+ pop ax
+ jmps OSC1_not_special
+
+
+
+ public KOutDebugStr
+
+KOutDebugStr proc far
+ push bp
+ mov bp, sp ; Assumes BP+6 = Pusha
+ sub sp, 84 ; local 80 char line + count
+odslen equ word ptr [bp-2]
+odsbuf equ byte ptr [bp-82]
+odszero equ word ptr [bp-84] ; flag - true if skip leading zero
+odsflag equ word ptr [bp-86] ; last local var - from pushf
+ mov odslen, 0
+ pushf
+ push es
+
+ push cs ; Address our own data seg
+ pop es
+ assumes ds,NOTHING
+ assumes es,code
+
+ cld
+ FCLI
+
+OSC1_Loop:
+ lodsb ; Get the next character
+ test al, al ; Q: End of string?
+ jz short OSC1_Done ; Y: Return
+ push codeoffset OSC1_Loop
+ cmp al, "#" ; N: Q: Special register out?
+ je SHORT OSC1_Hex ; Y: Find out which one
+ cmp al, "?" ; Q: special label out?
+ je short OSC1_Label ; Y: find out which one
+ cmp al, "@" ; Q: special string out?
+ je short OSC1_Str
+ cmp al, "%" ; Custom value?
+ je short OSC1_Custom
+OSC1_out:
+ xor ah, ah ; N: Send char to COM
+ jmp Out_Debug_Chr
+
+OSC1_Hex:
+ call Get_Register
+ jnc short OSC1_not_special
+
+ or bh, bh ; Q: Word output?
+ jz SHORT OSC1_Out_Byte ; N: display byte
+OSC1_Out_Word:
+ jmp Out_Hex_4_test ; Display AX in hex
+
+OSC1_Out_Byte:
+ xchg al, ah ; swap bytes to print just
+ jmp Out_Hex_2_test ; the low one!
+
+OSC1_Label:
+ call Get_Register
+ jc short show_label
+OSC1_not_special:
+ lodsb ; Get special char again
+ jmp OSC1_out ; display it, and continue
+
+show_label:
+ mov cx, ax ; save first value
+ cmp byte ptr [si], ':' ;Q: selector separator?
+ jne short flat_offset ; N:
+ lodsb ; Y: eat the ':'
+ call Get_Register ; and attempt to get the selector
+ jc short sel_offset
+flat_offset:
+ mov ax, cs ; default selector value
+sel_offset:
+ jmp Show_Near_Label
+
+OSC1_Str:
+ call Get_Register
+ jnc short OSC1_not_special
+ mov cx,ax
+ cmp byte ptr [si],':'
+ jne short no_selector
+ lodsb
+ push cx
+ call Get_Register
+ pop cx
+ xchg ax,cx
+ jc short got_sel_off
+ mov cx,ax
+no_selector:
+ mov ax,ds ; default selector for strings
+got_sel_off:
+ jmp Show_String
+
+OSC1_Done: ; The end
+ xor ax, ax ; flush buffer
+ call Out_Debug_Chr
+ pop es
+if pmode32
+ test odsflag, 200h
+ jz short @F
+ FSTI
+@@:
+endif
+ popf
+ leave
+ ret
+
+KOutDebugStr endp
+
+
+;******************************************************************************
+;
+; Get_Register
+;
+; DESCRIPTION:
+;
+; ENTRY:
+;
+; EXIT: Carry set if register value found
+; AX = register value
+; BL = value size (1, 2, 4) (no longer true - donc)
+;
+; USES:
+;
+;==============================================================================
+
+
+Get_Register proc near
+ lodsw ; get next pair of letters
+ mov bx, ax
+ and bx, 2020h
+ mov [odszero], bx
+ and ax, 0dfdfh ; to upper case
+ xchg ah, al ; normal order (or change table?)
+ or bx, -1 ; BH = -1
+ cmp al, 'L' ; Q: "L" (ie AL, BL, etc)?
+ jne short @F ; N: word reg
+ mov al, 'X' ; Y: change to X for pos match
+ inc bh ; BH now 0 - will clear AH below
+@@:
+ xor di, di ; DI = 0
+ mov cx, 12 ; Size of a pusha + 4 seg regs
+
+OSC1_Special_Loop:
+ cmp ax, Reg_Offset_Table[di] ; Q: Is this the register?
+ je SHORT OSC1_Out_Reg ; Y: Output it
+ add di, 2 ; N: Try the next one
+ loop OSC1_Special_Loop ; until CX = 0
+ sub si, 3 ; restore pointer, clear carry
+ ret
+
+OSC1_Out_Reg:
+ mov ax, SS:[bp.6][di] ; AX = Value to output
+ and ah, bh ; if xL, zero out high byte
+ stc
+ ret
+
+Get_Register endp
+
+
+;******************************************************************************
+;
+; Out_Hex_Word
+;
+; Outputs the value in AX to the COM port in hexadecimal.
+;
+;------------------------------------------------------------------------------
+
+Out_Hex_2_test: ; Write two chars
+ xor ah, ah
+ cmp [odszero], 0 ; skip leading 0's?
+ je Out_Hex_2 ; no, show 2 chars
+ ; yes, fall through
+Out_Hex_4_test:
+ cmp [odszero], 0
+ je Out_Hex_4
+ test ax, 0fff0h
+ jz Out_Hex_1
+ test ah, 0f0h
+ jnz Out_Hex_4
+ test ah, 0fh
+ jz Out_Hex_2
+Out_Hex_3:
+ xchg al, ah
+ call Out_Hex_1
+ xchg al, ah
+ jmps Out_Hex_2
+
+Out_Hex_4:
+ xchg al, ah
+ call Out_Hex_2
+ xchg al, ah
+Out_Hex_2:
+ push ax
+ shr ax, 4
+ call Out_Hex_1
+ pop ax
+Out_Hex_1:
+ push ax
+ and al, 0fh
+ cmp al, 10
+ jb @F
+ add al, '@'-'9'
+@@: add al, '0'
+ call Out_Debug_Chr
+ pop ax
+ ret
+
+;******************************************************************************
+;
+; Out_Debug_Chr
+;
+; DESCRIPTION:
+;
+; ENTRY:
+; AL contains character to output
+;
+; EXIT:
+;
+; USES:
+; Nothing
+;
+;==============================================================================
+
+Out_Debug_Chr proc near
+
+ push di
+ mov di, odslen
+ mov odsbuf[di], al ; store in buffer (in stack)
+ or al, al
+ jz short odc_flushit ; if null, flush buffer
+ inc odslen
+ cmp di, 79 ; if full, flush buffer
+ jnz short odc_ret
+
+odc_flushit:
+ mov odsbuf[di], 0 ; null terminate string
+ lea di, odsbuf
+ cCall DebugWrite,<ssdi,odslen>
+ mov odslen, 0
+odc_ret:
+ pop di
+ ret
+
+Out_Debug_Chr endp
+
+
+;******************************************************************************
+;
+; Show_Near_Label
+;
+; DESCRIPTION: call the debugger to display a label less than or equal
+; to the given address
+;
+; ENTRY: AX is selector, CX is offset of address to try to find
+; a symbol for
+; ES selector to DOSX data segment
+; EXIT:
+;
+; USES:
+;
+;==============================================================================
+
+Show_Near_Label proc near
+
+ push ax ;on a 286, use 16 bit regs
+ push bx
+ push cx
+ mov bx,cx
+ mov cx,ax
+ mov ax,DS_Out_Symbol
+ int Debug_Serv_Int
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+Show_Near_Label endp
+
+
+;******************************************************************************
+;
+; Show_String
+;
+; DESCRIPTION: Display an asciiz string
+;
+; ENTRY: AX is selector, CX is offset of address to find string
+;
+; EXIT:
+;
+; USES:
+;
+;==============================================================================
+
+Show_String proc near
+
+ push ax
+ push ds
+ push si
+
+ mov ds,ax
+ mov si,cx
+ xor ax,ax
+ cmp byte ptr ds:[si], ' '
+ jbe pascal_show_string
+@@:
+ lodsb
+ or al,al
+ jz short @f
+ call Out_Debug_Chr
+ jmp short @b
+@@:
+ pop si
+ pop ds
+ pop ax
+
+ ret
+
+pascal_show_string:
+ push cx
+ lodsb
+ mov cl, al
+ xor ch, ch
+pss_1: lodsb
+ call Out_Debug_Chr
+ loop pss_1
+ pop cx
+ jmps @B
+
+Show_String endp
+
+; END OF DXBUG STUFF
+
+
+
+;-----------------------------------------------------------------------;
+; CVWBreak
+;
+; This is part of the tortuous path from a Ctrl-Alt-SysReq to
+; CVW. In RegisterPtrace we tell the keyboard driver to jump
+; here if Ctrl-Alt_SysReq is done.
+;
+; Entry:
+; none
+;
+; Returns:
+;
+; Registers Destroyed:
+; none
+;
+; History:
+; Mon 17-Jul-1989 14:34:21 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CVWBreak,<PUBLIC,FAR>
+cBegin nogen
+
+ push ax
+ push di
+ push ds
+ SetKernelDS
+ test Kernel_flags[2],KF2_PTRACE
+ jz short call_WDEB
+ cmp Kernel_InDOS,0 ; not in DOS we don't
+ jnz short TVC15_exit
+if pmode32
+ .386p
+ push fs ; save current FS for debuggers
+ .286p
+endif
+ call genter ; sets FS to kernel data seg
+ UnSetKernelDS
+if pmode32
+ .386p
+ pop fs
+ .286p
+endif
+ dec [di].gi_lrulock
+ jz short call_PTrace
+ or [di].gi_flags,GIF_INT2
+ jmps TVC15_exit
+
+call_PTrace:
+ SetKernelDS
+ cmp ptrace_DLL_entry.sel,0
+ jnz short yes_CVW
+
+ ;** This is the only case where WINDEBUG gets first dibs something.
+ ;* Since we have no way of knowing if TOOLHELP wants the
+ ;** CtlAltSysRq, we always give it to CVW if it's there.
+ test Kernel_Flags[2],KF2_TOOLHELP
+ jz SHORT call_WDEB
+ mov ax,SDM_INT2 ;Notification number
+ call lpfnToolHelpProc ;Give it to TOOLHELP
+ jmp SHORT TVC15_exit
+
+ ;** Give it to the kernel debugger
+call_WDEB:
+ pop ds
+ UnSetKernelDS
+ pop di
+ pop ax
+
+ int 1
+ iret
+
+ ;** Give it to CVW
+yes_CVW:
+ ReSetKernelDS
+ mov ax,SDM_INT2
+ call ptrace_DLL_entry
+TVC15_exit:
+ pop ds
+ UnSetKernelDS
+ pop di
+ pop ax
+ iret
+
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; DebugDefineSegment ;
+; ;
+; Informs debugger of physical address and type of a segment for the ;
+; named module, that is informed of segment index and corresponding ;
+; name and physical segment. ;
+; ;
+; Arguments: ;
+; ModName - Long pointer to module name. ;
+; SegNumber - zero based segment index ;
+; LoadedSeg - Physical seg address assigned by user to index. ;
+; InstanceNumber - Windows instance number bound to physical seg.;
+; DataOrCodeFlag - Whether segment is code or data. ;
+; ;
+; Returns: ;
+; None. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:20:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+default_buf_size equ 130
+
+cProc DebugDefineSegment,<PUBLIC,NEAR>,<es>
+ Parmd ModName
+ Parmw SegNumber
+ Parmw LoadedSeg
+ Parmw InstanceNumber
+ Parmw DataOrCodeFlag
+ localV modBuf,default_buf_size
+ localV nameBuf,default_buf_size
+cBegin
+ SetKernelDS es
+ test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
+ jz short setdone
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ les di, ModName
+ UnSetKernelDS es
+ mov bx, SegNumber
+ mov cx, LoadedSeg
+ mov dx, InstanceNumber
+ mov si, DataOrCodeFlag
+ mov ax,SDM_LOADSEG
+ DEBUGCALL
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+setdone:
+
+ifdef WOW
+
+ SetKernelDS es
+ test es:DebugWOW,DW_DEBUG
+ jnz @f
+ jmp dd_no_wdebug
+ UnSetKernelDS es
+@@:
+
+ push ds
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+
+ lds si, ModName
+ mov cx,ds:[ne_magic]
+ cmp cx,NEMAGIC
+ jz @f
+ jmp not_yet
+
+@@: mov cx,ss
+ mov es,cx
+ lea di,modBuf
+ xor cx,cx
+ mov cl,byte ptr [si-1] ; Get length byte
+ cmp cx,default_buf_size
+ jl @f
+ mov cx,default_buf_size-1
+@@:
+ rep movsb ; Copy the string
+
+ xor ax,ax
+
+ stosb
+
+ mov si,ds:[ne_pfileinfo]
+ mov cl,ds:[si].opLen
+ sub cx,opFile
+ lea si,[si].opFile
+ lea di,nameBuf
+ cmp cx,default_buf_size
+ jl @f
+ mov cx,default_buf_size-1
+@@:
+ rep movsb ; Copy the string
+
+ stosb
+
+ SetKernelDS es
+
+ push DataOrCodeFlag
+ lea si,nameBuf
+ push ss
+ push si
+ lea si,modBuf
+ push ss
+ push si
+ push SegNumber
+ push LoadedSeg
+ push DBG_SEGLOAD
+ IFE PMODE
+ BOP BOP_DEBUGGER
+ ELSE
+ FBOP BOP_DEBUGGER,,FastBop
+ ENDIF
+ add sp,+16
+
+not_yet:
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ds
+ UnSetKernelDS
+
+dd_no_wdebug:
+
+endif
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; DebugMovedSegment ;
+; ;
+; Informs debugger of the old and new values for a physical segment. ;
+; ;
+; Arguments: ;
+; SourceSeg - Original segment value. ;
+; DestSeg - New segment value. ;
+; ;
+; Returns: ;
+; None. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:29:15p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+cProc DebugMovedSegment,<PUBLIC,NEAR>
+ ParmW SourceSeg
+ ParmW DestSeg
+cBegin
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DebugFreeSegment ;
+; ;
+; Informs debugger that a segment is being returned to the global ;
+; memory pool and is no longer code or data. ;
+; ;
+; Arguments: ;
+; SegAddr - segment being freed ;
+; fRelBP - flag indicating if breakpoints should be released, ;
+; -1 means yes ;
+; ;
+; Returns: ;
+; None. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:34:13p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc DebugFreeSegment,<PUBLIC,NEAR>,<es>
+ Parmw SegAddr
+ parmW fRelBP
+cBegin
+ push ds
+ SetKernelDS
+ifdef WOW
+ test DebugWOW,DW_DEBUG
+ jz df_no_wdebug
+
+ push SegAddr ; Notify the Win32 debugger that
+ push fRelBP
+ mov ax,DBG_SEGFREE ; the selector number needs to be freed
+ push ax
+ IFE PMODE
+ BOP BOP_DEBUGGER
+ ELSE
+ FBOP BOP_DEBUGGER,,FastBop
+ ENDIF
+ add sp,+6
+
+df_no_wdebug:
+endif
+ test Kernel_Flags[2],KF2_SYMDEB or KF2_PTRACE
+ pop ds
+ UnSetKernelDS
+ jz short killdone
+ mov bx, SegAddr
+ mov ax, SDM_FREESEG
+ inc fRelBP
+ jnz short @f
+ mov ax, SDM_RELEASESEG ;free but pulls out breakpoints 1st
+@@:
+ DEBUGCALL
+killdone:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DebugWrite ;
+; ;
+; Prints the given string of the given length. If a debugger is ;
+; present tells the debugger to print the message. Otherwise uses ;
+; DOS Function 40h to the con device. ;
+; ;
+; Arguments: ;
+; lpBuf long pointer to string to write ;
+; nBytes # of bytes in string ;
+; ;
+; Returns: ;
+; None. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:53:08p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc DebugWrite,<PUBLIC,NEAR>,<ds,si>
+ parmD lpBuf
+ parmW nBytes
+ localW wHandled
+ localW SavePDB
+
+cBegin
+ ;** Validate the pointer and number of bytes
+
+ mov ax,WORD PTR lpBuf[0]
+ add ax,nBytes
+ jnc SHORT @F
+ jmp DW_End ;Overflow: error
+@@:
+if pmode32
+ .386
+ push eax ; 32 bit ValidatePointer destroys top half
+ push ecx ; of eax, ecx which isn't nice in debug outs
+ .286
+endif
+ push WORD PTR lpBuf[2]
+ push ax
+ call ValidatePointer ;Make sure pointer is OK
+ or ax,ax
+if pmode32
+ .386
+ pop ecx
+ pop eax
+ .286
+endif
+ jnz SHORT @F
+ jmp DW_End ;Bogus pointer: just return.
+@@: mov cx,nBytes
+ lds dx,lpBuf ;DS:DX points to string
+ or cx,cx ;Zero length requires computing
+ jnz SHORT DW_GoodLen
+
+ ;** Compute string length if a valid length not passed in
+ mov si,dx
+ cld
+DW_LenLoop:
+ lodsb
+ or al,al
+ jnz short DW_LenLoop
+ mov cx,si
+ sub cx,dx
+ dec cx
+DW_GoodLen:
+
+ ;** Set up for the Int 41h, PTrace, and TOOLHELP interfaces
+ mov wHandled,0 ;Flag that we haven't handled yet
+ mov si,dx ;Point to string with DS:SI
+ push ds ; and ES:SI
+ pop es
+
+ ;** Decide which debugger (if any) to send string to
+
+ push ds
+ SetKernelDS
+ test Kernel_Flags[2],KF2_SYMDEB ;WDEB386 loaded?
+ pop ds
+ UnSetKernelDS
+ jz SHORT DW_TryToolHelp ;No, now try TOOLHELP
+
+ ;** Send to WDEB386
+ push si
+ DebInt SDM_CONWRITE
+ pop si
+ mov wHandled,1 ;Assume that WDEB386 handled it
+
+ ;** Send it to TOOLHELP if it is there
+DW_TryToolHelp:
+ push ds
+ SetKernelDS
+ test Kernel_Flags[2],KF2_TOOLHELP ;ToolHelp around?
+ pop ds
+ UnSetKernelDS
+ jz SHORT DW_TryPTrace ;Nope, now try PTrace
+
+ push ds
+ SetKernelDS
+
+ push Win_PDB ;Save current PDB
+ cmp curTDB,0
+ jz @F
+ push es ; and set to current task's PDB
+ mov es,curTDB ; for toolhelp call.
+ push es:[TDB_PDB]
+ pop ds:Win_PDB
+ pop es
+@@:
+ mov ax,SDM_CONWRITE ;Notification ID
+ call lpfnToolHelpProc ;String in ES:SI for TOOLHELP
+
+ pop Win_PDB ;Restore current PDB
+
+ or ax,ax ;TOOLHELP client say to pass it on?
+
+ pop ds
+ UnSetKernelDS
+ jnz SHORT DW_End ;No, we're done
+
+ ;** Handle PTrace
+DW_TryPTrace:
+ SetKernelDS es
+ cmp WORD PTR es:ptrace_dll_entry[2],0 ;WINDEBUG.DLL lurking around?
+ jz SHORT DW_WriteToCOM ;No, try COM port
+
+ ;** If we're exiting a task, don't send the debug write to PTrace.
+ ;** This is a gross hack for QCWin who chokes on these. These
+ ;** were being sent because of parameter validation errors.
+ push ax ;Temp reg
+ mov ax,es:curTDB
+ cmp ax,es:wExitingTDB
+ pop ax
+ je DW_WriteToCOM ;Write out directly
+
+IF KDEBUG
+ ;** If we're sending a KERNEL trace out, we don't want to send this
+ ;** to PTrace, either
+ cmp fKTraceOut, 0 ;Are we doing a KERNEL trace out?
+ jne DW_WriteToCOM ;Yes, don't call PTrace
+ENDIF
+
+ ;** Now send to PTrace
+ mov wHandled,1 ;Assume WINDEBUG handles if present
+ push ax ;Save regs PTrace might trash
+ push si
+ push dx
+ push ds
+ push es
+ mov ax,SDM_CONWRITE ;Notification ID
+ call es:ptrace_DLL_entry ;Do the PTrace thing
+ pop es
+ pop ds
+ pop dx
+ pop si
+ pop ax
+
+ ;** Write string to debug terminal
+DW_WriteToCOM:
+ cmp wHandled,0 ;Handled?
+ jnz SHORT DW_End ;Yes
+
+ inc es:fDW_Int21h ; Skip it if user has canceled
+ jnz SHORT DW_Skip_Write ; a crit error on this before
+
+ mov ax, es:topPDB
+ xchg es:Win_PDB, ax ; Switch to Kernel's PDB,
+ mov SavePDB, ax ; saving current PDB
+
+ifdef WOW
+ cCall WOWOutputDebugString,<lpBuf>
+else
+ mov bx,3 ;Send to DOS AUX port
+ mov ah,40h
+ int 21h
+endif; WOW
+
+ mov ax, SavePDB
+ mov es:Win_PDB, ax ; restore app pdb
+
+DW_Skip_Write:
+ dec es:fDW_Int21h
+DW_End:
+ UnSetKernelDS
+ UnSetKernelDS es
+cEnd
+
+;-----------------------------------------------------------------------;
+; OutputDebugString ;
+; ;
+; A routine callable from anywhere since it is exported. It calls ;
+; DebugWrite to do its dirty work. ;
+; ;
+; Arguments: ;
+; lpStr long pointer to null terminated string ;
+; ;
+; Returns: ;
+; none ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue June 28, 1988 -by- Ken Shirriff [t-kens] ;
+; Made it save all the registers. ;
+; ;
+; Thu Nov 13, 1986 02:54:36p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc OutputDebugString,<PUBLIC,FAR,NODATA>,<es>
+ parmD lpStr
+cBegin
+ pusha
+ cCall DebugWrite,<lpStr, 0>
+ popa
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DebugRead ;
+; ;
+; Gets a character from either the debugger (if one is present) or ;
+; from the AUX. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AL = character ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Nov 13, 1986 02:55:09p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc DebugRead,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+
+ ;** Send it to the debugger(s) FIRST
+ mov ax,SDM_CONREAD ;Get the notification ID
+
+
+ ; This sure is weird! Goal is to ask if WDEB386 has a char
+ ; available. If so, return.
+ ; We do the check here because MyDebugCall assumes INT41
+ ; doesn't modify registers, but the CONREAD call does.
+ ; This was hosing TOOLHELP, since we were passing a different
+ ; function to TOOLHELP based on what char a user was pressing.
+
+ test Kernel_Flags[2],KF2_SYMDEB ; WDEB386 loaded?
+ jz short dr_symdeb ; no - MyDebugCall
+ DebInt ; Yes - read CON
+ cmp ax, SDM_CONREAD
+ jnz @F ; got a response - continue.
+
+dr_symdeb:
+ DEBUGCALL
+@@:
+ ;** See if we should still hand it to the AUX port
+ cmp al,SDM_CONREAD ;If not changed, we didn't get a character
+ jne SHORT DR_End
+
+ mov ax, wDefRIP ;Do we have a default value to use?
+ or ax, ax
+ jnz DR_End
+
+ xor cx,cx ;Allocate WORD to read into
+ push cx
+ mov dx,sp ;Point with DS:DX
+ push ss
+ pop ds
+ inc cx ;Get one byte
+DR_ConLoop:
+ifdef WOW
+ int 3 ; BUGBUG mattfe 29-mar-92, should be thunked to 32 bit side.
+endif
+ mov bx,3 ;Use AUX
+ mov ah,3fh ;Read device
+ int 21h ;Call DOS
+ cmp ax,cx ;Did we get a byte?
+ jne SHORT DR_ConLoop ;No, try again
+ pop ax ;Get the byte read
+
+DR_End:
+ pop ds
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; DebugDefineLine ;
+; ;
+; Notifies debugger of the location of The Line. ;
+; ;
+; Arguments: ;
+; None ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Registers Destroyed: ;
+; ;
+; History: ;
+; Mon 20-Jun-1988 13:17:41 -by- David N. Weise [davidw] ;
+; Moved it here. ;
+;-----------------------------------------------------------------------;
+;
+; assumes ds,nothing
+; assumes es,nothing
+;
+;cProc DebugDefineLine,<PUBLIC,NEAR>
+;
+;cBegin nogen
+; ret
+;cEnd nogen
+;
+;cProc FarDebugNewTask,<PUBLIC,FAR>
+;
+;cBegin nogen
+; call DebugNewTask
+; ret
+;cEnd nogen
+;
+;
+;-----------------------------------------------------------------------;
+; DebugNewTask ;
+; ;
+; ;
+; Arguments: ;
+; AX = EMS PID ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+;
+;cProc DebugNewTask,<PUBLIC,NEAR>
+;
+;cBegin nogen
+; ret
+;cEnd nogen
+;
+;cProc FarDebugFlushTask,<PUBLIC,FAR>
+;
+;cBegin nogen
+; call DebugFlushTask
+; ret
+;cEnd nogen
+;
+;-----------------------------------------------------------------------;
+; DebugFlushTask ;
+; ;
+; ;
+; Arguments: ;
+; AX = EMS PID ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+;
+;cProc DebugFlushTask,<PUBLIC,NEAR>
+;
+;cBegin nogen
+; ret
+;cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; DebugSwitchOut ;
+; ;
+; ;
+; Arguments: ;
+; DS = TDB ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc DebugSwitchOut,<PUBLIC,NEAR>
+
+cBegin nogen
+ push ds
+ SetKernelDS
+ test Kernel_Flags[2],KF2_PTRACE
+ pop ds
+ UnSetKernelDS
+ jz short dso_done
+
+ push ax
+ mov ax,SDM_SWITCHOUT
+ DEBUGCALL
+ pop ax
+dso_done:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; DebugSwitchIn ;
+; ;
+; ;
+; Arguments: ;
+; DS = TDB ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc DebugSwitchIn,<PUBLIC,NEAR>
+
+cBegin nogen
+ push ds
+ SetKernelDS
+ test Kernel_Flags[2],KF2_PTRACE
+ pop ds
+ UnSetKernelDS
+ jz short dsi_done
+
+ push ax
+ mov ax,SDM_SWITCHIN
+ DEBUGCALL
+ pop ax
+dsi_done:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; DebugExitCall
+;
+; Notifies the debugger than an app is quitting. This gets
+; called at the top of ExitCall.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Preserved:
+; all
+;
+; History:
+; Thu 11-May-1989 08:58:40 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugExitCall,<PUBLIC,NEAR>
+cBegin nogen
+;
+; Windebug knows where this is. See MyDebugCall() comment.
+;
+ifdef WOW
+ push ds
+ SetKernelDS
+ test DebugWOW,DW_DEBUG
+ jz de_no_wdebug
+
+ push ax
+ push es
+ mov es,bx ; Get the current TDB
+ push es ; hTask
+ mov ax,es:[TDB_pModule] ; Get the module handle
+ mov es,ax
+
+ push es ; hModule
+
+ push es ; Pointer to module name
+ push es:ne_restab
+ push es ; Pointer to module path
+ push word ptr es:ne_crc+2
+
+ mov ax,DBG_TASKSTOP ; the selector number needs to be freed
+ push ax
+ FBOP BOP_DEBUGGER,,FastBop
+ add sp,+14
+
+ pop es ; Restore original ES
+ pop ax
+
+de_no_wdebug:
+ pop ds
+ UnSetKernelDS
+endif
+
+ push ax
+ mov bl,al ;Exit code in BL
+ mov ax,SDM_EXITCALL
+ DEBUGCALL
+ pop ax
+
+
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; FarDebugDelModule
+;
+; Notifies the debugger than a module is being deleted. This gets
+; called at the top of ExitCall.
+;
+; Entry:
+; ES = module handle
+;
+; Returns:
+;
+; Registers Reserved:
+; all
+;
+; History:
+; Mon 11-Sep-1989 18:34:06 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc FarDebugDelModule,<PUBLIC,FAR>
+ifdef WOW
+ localV nameBuf,130
+ localV ModName,64
+endif
+cBegin nogen
+ push es
+ifdef WOW
+ push ds
+ push es
+
+ SetKernelDS
+
+ test DebugWOW,DW_DEBUG
+ jnz @f
+ jmp fdd_no_wdebug
+
+@@: push di
+ push si
+ push cx
+ xor cx,cx
+ mov ax,es
+ mov ds,ax
+ mov si,es:[ne_restab]
+ mov cl,[si]
+ inc si
+ cmp cl,64
+ jb @f
+ mov cl,63
+@@:
+ mov ax,ss
+ mov es,ax
+ lea di,ModName
+ rep movsb ; Copy module name from resource
+ mov byte ptr es:[di],0 ; table and null terminate it
+ mov ax,ds
+ mov es,ax
+
+ lea di,nameBuf
+ push ax
+ push ss
+ push di
+ mov ax, 130
+ push ax
+ call GetModuleFileName
+
+ SetKernelDS
+ lea di,nameBuf
+ push ss
+ push di
+ lea di,ModName
+ push ss
+ push di
+ push DBG_MODFREE
+ IFE PMODE
+ BOP BOP_DEBUGGER
+ ELSE
+ FBOP BOP_DEBUGGER,,FastBop
+ ENDIF
+ add sp,+10
+ pop cx
+ pop si
+ pop di
+fdd_no_wdebug:
+ pop es
+ pop ds
+ UnSetKernelDS
+endif; WOW
+ mov ax,SDM_DELMODULE
+ DEBUGCALL
+ add sp,2
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; void DebugLogError(WORD err, VOID FAR* lpInfo);
+;
+; Notifies debugger of a LogError() call.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugLogError,<PUBLIC,NEAR>
+;ParmW err
+cBegin nogen
+ pop ax
+
+ pop bx ; dx:bx = lpInfo
+ pop dx
+
+ pop cx ; cx = error code
+
+ push ax
+ mov ax,SDM_LOGERROR
+ jmp short MyDebugCall
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; void DebugLogParamError(VOID FAR* param, FARPROC lpfn, WORD err);
+;
+; Notifies debugger of a LogParamError() call.
+;
+; NOTE: the parameters are passed in the REVERSE order than expected,
+; so that the stack layout is natural when we do the DebugCall.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DebugLogParamError,<PUBLIC,NEAR>
+;ParmD param
+;ParmD lpfn
+;ParmW err
+cBegin nogen
+;
+; es:bx = pointer to struct containing args
+;
+ mov bx,sp
+ add bx,2 ; point past return addr.
+ push ss
+ pop es
+ mov ax,SDM_LOGPARAMERROR
+ call MyDebugCall
+ ret 2+4+4
+cEnd nogen
+
+;------------------------------------------------------------------------
+;
+; MyDebugCall
+;
+; Call the debugger interface. Created to reduce references to kernel
+; data segment.
+;
+;------------------------------------------------------------------------
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc MyFarDebugCall, <FAR,PUBLIC>
+cBegin nogen
+ cCall MyDebugCall
+ retf
+cEnd nogen
+
+cProc MyDebugCall,<NEAR,PUBLIC>
+cBegin nogen
+
+ push ds
+ SetKernelDS
+
+ test Kernel_Flags[2],KF2_SYMDEB
+ jz short no_symdeb
+
+ cmp ax,SDM_SWITCHOUT ; Don't give these to WDEB.
+ je no_symdeb
+ cmp ax,SDM_SWITCHIN
+ je no_symdeb
+
+ pop ds ; Too bad some Int 41h services
+ UnSetKernelDS ; require segment reg params
+
+ DebInt
+
+ push ds
+ SetKernelDS
+
+no_symdeb:
+
+ ;** Check for TOOLHELP's hook. We always send it here first
+ ;** This callback does NOT depend on what's on the stack.
+ test Kernel_Flags[2],KF2_TOOLHELP ;TOOLHELP hook?
+ jz SHORT MDC_NoToolHelp ;No
+
+ push ax
+
+ push Win_PDB ; Preserve Win_TDB across ToolHelp call
+ cmp curTDB,0
+ jz @F
+ push es
+ mov es,curTDB
+ push es:[TDB_PDB]
+ pop ds:Win_PDB
+ pop es
+@@:
+
+ ;** Just call the TOOLHELP callback. It preserves all registers
+ ;** except AX where it returns nonzero if the notification
+ ;** was handled.
+ call lpfnToolHelpProc ;Do it
+
+ pop Win_PDB ; Restore Win_TDB
+
+ or ax,ax ;Did the TOOLHELP client say to
+ ; pass it on?
+ jz SHORT @F ;Yes
+ add sp,2 ;No, so return TOOLHELP's return value
+ jmp SHORT no_ptrace
+@@: pop ax ;Restore notification ID
+
+MDC_NoToolHelp:
+
+ ;** Make sure we don't have a new notification. If it's newer than
+ ;* CVW, CVW chokes on it so we can't send new notifications
+ ;** through PTrace.
+ cmp ax,SDM_DELMODULE ;Last old notification
+ ja short no_ptrace ;Don't send new notification
+MDC_PTraceOk:
+ cmp WORD PTR ptrace_dll_entry[2],0 ;WINDEBUG.DLL lurking around?
+ jz SHORT no_ptrace
+
+; !!!!!!!!!!!!!! HACK ALERT !!!!!!!!!!!!!!
+;
+; Windebug.DLL for Windows 3.0 knows exactly what is on the stack
+; when Kernel makes a PTrace callout. For this reason, we cannot
+; change what is on the stack when we make one of these calls.
+; This stuff below fakes a FAR return to our NEAR caller, and jumps
+; to the PTrace DLL entry with all registers intact.
+;
+ ; SP -> DS RET
+
+ sub sp,8
+ push bp
+ mov bp,sp
+
+ ; BP -> BP xx xx xx xx DS KERNEL_RET
+
+ mov [bp+2],ax ; save AX
+
+ mov ax,[bp+10] ; move saved DS
+ mov [bp+4],ax
+
+ mov ax,[bp+12] ; convert near RET to far
+ mov [bp+10],ax
+ mov [bp+12],cs
+
+ mov ax,word ptr ptrace_dll_entry[2] ; CS of Routine to invoke
+ mov [bp+8],ax
+ mov ax,word ptr ptrace_dll_entry ; IP of Routine to invoke
+ mov [bp+6],ax
+
+ ; SP -> BP AX DS PTRACE_IP PTRACE_CS KERNEL_RET KERNEL_CS
+
+ pop bp
+ pop ax
+ pop ds
+ UnSetKernelDS
+ retf
+
+no_ptrace:
+ pop ds
+ UnSetKernelDS
+
+ ret
+cEnd nogen
+
+
+if KDEBUG
+
+dout macro var
+ mov byte ptr ss:[si],var
+ inc si
+ endm
+
+
+;-----------------------------------------------------------------------;
+; hex ;
+; ;
+; Outputs byte in AL as two hex digits. ;
+; ;
+; Arguments: ;
+; AL = 8-bit value to be output ;
+; SS:SI = where it's to be put ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Nov 14, 1986 02:32:15p -by- David N. Weise [davidw] ;
+; Modified it from symdeb\debug.asm. ;
+;-----------------------------------------------------------------------;
+
+cProc hex,<NEAR>
+cBegin nogen
+
+ mov ah,al ; save for second digit
+
+; shift high digit into low 4 bits
+
+ mov cl,4
+ shr al,cl
+
+ and al,0Fh ; mask to 4 bits
+ add al,90h
+ daa
+ adc al,40h
+ daa
+ dout al
+
+ mov al,ah ; now do digit saved in ah
+ and al,0Fh ; mask to 4 bits
+ add al,90h
+ daa
+ adc al,40h
+ daa
+ dout al
+ ret
+cEnd nogen
+
+
+
+
+;-----------------------------------------------------------------------;
+; pdref_norip ;
+; ;
+; Dereferences the given global handle, i.e. gives back abs. address. ;
+; ;
+; Arguments: ;
+; DX = selector ;
+; DS:DI = BURGERMASTER ;
+; ;
+; Returns: ;
+; FS:ESI = address of arena header ;
+; AX = address of client data ;
+; CH = lock count or 0 for fixed objects ;
+; CL = flags ;
+; DX = handle, 0 for fixed objects ;
+; ;
+; Error Returns: ;
+; ZF = 1 if invalid or discarded ;
+; AX = 0 ;
+; BX = owner of discarded object ;
+; SI = handle of discarded object ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ghdref ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+if pmode32
+ .386p
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc pdref_norip,<PUBLIC,NEAR>
+
+cBegin nogen
+ ; DPMI - no LDT access
+ mov si, dx
+ sel_check si
+ or si, si ; Null handle?
+ jnz short OK1
+ mov ax, si ; yes, return 0
+ jmps pd_exit
+OK1:
+ lar eax, edx
+ jnz short pd_totally_bogus
+ shr eax, 8
+
+; We should beef up the check for a valid discarded sel.
+
+ xor cx,cx
+ test ah, DSC_DISCARDABLE
+ jz short pd_not_discardable
+ or cl, GA_DISCARDABLE
+ ; Discardable, is it code?
+ test al, DSC_CODE_BIT
+ jz short pd_not_code
+ or cl,GA_DISCCODE
+pd_not_code:
+
+pd_not_discardable:
+ test al, DSC_PRESENT
+ jnz short pd_not_discarded
+
+; object discarded
+
+ or cl,HE_DISCARDED
+if PMODE32
+; On WOW we don't copy the owner to the real LDT since it is slow to call
+; the NT Kernel, so we read our copy of it directly.
+; see set_discarded_sel_owner mattfe mar 23 93
+
+ mov ax,es ; save es
+ mov bx,dx
+ mov es,cs:gdtdsc
+ and bl, not 7
+ mov bx,es:[bx].dsc_owner
+ mov es,ax ; restore
+else
+ lsl bx, dx ; get the owner
+endif
+ or si, SEG_RING-1 ; Handles are RING 2
+ xor ax,ax
+ jmps pd_exit
+
+pd_not_discarded:
+ cCall get_arena_pointer32,<dx>
+ mov esi, eax
+ mov ax, dx
+ or esi, esi ; Unknown selector
+ jz short pd_maybe_alias
+ mov dx, ds:[esi].pga_handle
+ cmp dx, ax ; Quick check - handle in header
+ je short pd_match ; matches what we were given?
+
+ test al, 1 ; NOW, we MUST have been given
+ jz short pd_totally_bogus ; a selector address.
+ push ax
+ StoH ax ; Turn into handle
+ cmp dx, ax
+ pop ax
+ jne short pd_nomatch
+pd_match:
+ or cl, ds:[esi].pga_flags
+ and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!!
+ mov ax, dx ; Get address in AX
+ test dl, GA_FIXED ; DX contains handle
+ jnz short pd_fixed ; Does handle need derefencing?
+ mov ch, ds:[esi].pga_count
+ HtoS ax ; Dereference moveable handle
+ jmps pd_exit
+pd_totally_bogus:
+ xor ax,ax
+pd_maybe_alias:
+pd_nomatch: ; Handle did not match...
+ xor dx, dx
+pd_fixed:
+pd_exit:
+ or ax,ax
+ ret
+cEnd nogen
+ .286p
+endif
+
+;-----------------------------------------------------------------------;
+; xhandle_norip ;
+; ;
+; Returns the handle for a global segment. ;
+; ;
+; Arguments: ;
+; Stack = sp -> near return return address ;
+; sp+2 -> far return return address of caller ;
+; sp+6 -> segment address parameter ;
+; ;
+; Returns: ;
+; Old DS,DI have been pushed on the stack ;
+; ;
+; ZF= 1 if fixed segment. ;
+; AX = handle ;
+; ;
+; ZF = 0 ;
+; AX = handle ;
+; BX = pointer to handle table entry ;
+; CX = flags and count word from handle table ;
+; DX = segment address ;
+; ES:DI = arena header of object ;
+; DS:DI = master object segment address ;
+; ;
+; Error Returns: ;
+; AX = 0 if invalid segment address ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Oct 16, 1986 02:40:08p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+if pmode32
+ .386p
+cProc xhandle_norip,<PUBLIC,NEAR>
+cBegin nogen
+ pop dx ; Get near return address
+ mov bx,sp ; Get seg parameter from stack
+ mov ax,ss:[bx+4]
+ cmp ax,-1 ; Is it -1?
+ jnz short xh1
+ mov ax,ds ; Yes, use callers DS
+xh1: inc bp
+ push bp
+ mov bp,sp
+ push ds ; Save DS:DI
+ push edi
+ push esi
+ SetKernelDS
+ mov ds, pGlobalHeap ; Point to master object
+ UnSetKernelDS
+ xor edi,edi
+ inc [di].gi_lrulock
+ push dx
+ mov dx,ax
+ call pdref_norip
+
+ xchg dx,ax ; get seg address in DX
+ jz short xhandle_ret ; invalid or discarded handle
+ test al, GA_FIXED
+ jnz short xhandle_fixed
+ or ax, ax
+ jmps xhandle_ret
+xhandle_fixed:
+ xor bx, bx ; Set ZF
+xhandle_ret:
+ ret
+cEnd nogen
+ .286p
+
+else
+
+cProc xhandle_norip,<PUBLIC,NEAR>
+cBegin nogen
+ pop dx ; Get near return address
+ mov bx,sp ; Get seg parameter from stack
+ mov ax,ss:[bx+4]
+ cmp ax,-1 ; Is it -1?
+ jnz xh1
+ mov ax,ds ; Yes, use callers DS
+xh1: inc bp
+ push bp
+ mov bp,sp
+ push ds ; Save DS:DI
+ push di
+ call genter
+ push dx
+ mov dx,ax
+ push si
+externNP pdref
+ call pdref
+ xchg dx,ax ; get seg address in DX
+ jz xhandle_ret ; invalid or discarded handle
+ mov bx,si
+ or si,si
+ jz xhandle_ret
+ mov ax,si
+xhandle_ret:
+ pop si
+ ret
+cEnd nogen
+
+
+
+endif
+
+endif ;KDEBUG
+
+cProc ReplaceInst,<PUBLIC,FAR>
+
+;; parmD bpaddress
+;; parmW instruct
+
+cBegin nogen
+ ret 6
+cEnd nogen
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldfastb.asm b/private/mvdm/wow16/kernel31/ldfastb.asm
new file mode 100644
index 000000000..c57fc871a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldfastb.asm
@@ -0,0 +1,274 @@
+ TITLE LDFASTB - FastBoot procedure
+
+.xlist
+include kernel.inc
+include newexe.inc
+include pdb.inc
+include tdb.inc
+include eems.inc
+.list
+
+if PMODE32
+ .386
+endif
+
+externA __ahincr
+
+externFP GlobalReAlloc
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+sEnd NRESCODE
+
+DataBegin
+
+externB Kernel_flags
+externW pGlobalHeap
+externW win_show
+externW hLoadBlock
+externW segLoadBlock
+externD lpBootApp
+
+ife ROM
+externW cpShrink
+externW cpShrunk
+endif
+
+DataEnd
+
+sBegin INITCODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MyLock
+
+if PMODE32
+externNP get_arena_pointer32
+else
+externNP get_arena_pointer
+endif
+externNP get_physical_address
+externNP set_physical_address
+externNP get_rover_2
+
+;-----------------------------------------------------------------------;
+; Shrink ;
+; ;
+; This shrinks what's left of win.bin. The part at the front of win.bin;
+; that has been loaded already is expendable. The part of win.bin ;
+; that has not been loaded yet is moved down over the expended part. ;
+; This does not change the segment that win.bin starts at. The ;
+; partition is then realloced down in size. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX ;
+; ;
+; Calls: ;
+; BigMove ;
+; GlobalReAlloc ;
+; MyLock ;
+; ;
+; History: ;
+; ;
+; Fri Feb 27, 1987 01:20:57p -by- David N. Weise [davidw] ;
+; Documented it and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Shrink,<PUBLIC,NEAR>
+cBegin nogen
+
+ife ROM
+ CheckKernelDS
+ ReSetKernelDS
+ push es
+ push si
+ push di
+ mov ax,[segLoadBlock] ; Get current address
+ mov bx, ax
+if PMODE32
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ cCall get_arena_pointer32,<ax>
+ mov edx, ds:[eax].pga_size
+ shr edx, 4
+ SetKernelDS
+else
+ cCall get_arena_pointer,<ax>
+ mov es,ax
+ mov dx,es:[ga_size] ; get size of whole block
+endif
+ mov ax,bx
+ mov es,ax ; es is destination
+ xor bx,bx
+ xchg [cpShrink],bx ; Get amount to shrink by
+ add [cpShrunk],bx ; Keep track of how much we have shrunk
+
+ sub dx,bx ; get new size
+ push dx ; save new size
+ push ds ; save kernel ds
+
+if PMODE32
+ mov ds, ax
+ movzx esi, bx
+ shl esi, 4 ; Start of new block
+ xor edi, edi ; Where it will go
+ movzx ecx, dx
+ shl ecx, 2 ; Dwords
+ cld ; Move it down.
+ rep movs dword ptr es:[edi], dword ptr ds:[esi]
+ db 67h ; 386 BUG, DO NOT REMOVE
+ nop ; 386 BUG, DO NOT REMOVE
+else
+
+ push dx
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+ cCall get_physical_address,<es>
+ add ax,bx
+ adc dx,cx
+ push es
+ call get_rover_2
+ smov ds,es
+ assumes ds, nothing
+ pop es
+ cCall set_physical_address,<ds>
+ pop dx
+ call BigMove ; move it on down
+
+endif ; PMODE32
+
+ pop ds
+ CheckKernelDS
+ ReSetKernelDS
+ pop ax ; get back size in paragraphs
+ mov cx,4
+ xor dx,dx ; convert to bytes
+il3e:
+ shl ax,1
+ rcl dx,1
+ loop il3e
+ cCall GlobalReAlloc,<hLoadBlock,dxax,cx>
+ cCall MyLock,<hLoadBlock>
+ mov [segLoadBlock],ax
+ pop di
+ pop si
+ pop es
+
+endif ;ROM
+
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; BigMove ;
+; ;
+; Moves a large partition down in memory. ;
+; ;
+; Arguments: ;
+; DX = paragraph count to move ;
+; ES = destination segment ;
+; DS = source segment ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; None ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,DI,SI,DS,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Fri Feb 27, 1987 01:08:43p -by- David N. Weise [davidw] ;
+; Documented it and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+ife ROM
+ife PMODE32
+
+cProc BigMove,<PUBLIC,NEAR>
+cBegin nogen
+if PMODE32
+ movzx ecx, dx
+ shl ecx, 2
+ xor esi, esi
+ xor edi, edi
+ cld
+ rep movsd
+ ret
+else
+ mov bx,dx
+ mov cl,12
+ add bx,0FFFh
+ shr bx,cl ; count +1 of 10000h byte moves
+ xor si,si ; ds:0 is source
+ xor di,di ; es:0 is dest
+ cld
+ jmps BM2
+BM1:
+ int 3 ; IF WE HIT THIS, KRNL286.EXE IS
+ int 3 ; TOO BIG, FIX THE FOLLOWING!!!
+ sub dx,1000h
+;;;ife PMODE32
+ mov cx,8000h
+ rep movsw ; si,di are 0
+;;;else
+;;; mov cx, 4000h
+;;; rep movsd
+;;;endif
+ mov ax,ds
+ add ax,__ahincr
+ mov ds,ax
+ mov ax,es
+ add ax,__ahincr
+ mov es,ax
+BM2: dec bx
+ jnz BM1
+;;;ife PMODE32
+ mov cl,3 ; convert to words
+ shl dx,cl
+ mov cx,dx
+ rep movsw ; si,di are 0
+;;;else
+;;; shl dx, 2 ; dwords
+;;; mov cx, dx
+;;; rep movsd
+;;;endif
+endif
+ ret
+cEnd nogen
+
+endif ; PMODE32
+endif ; ROM
+
+sEnd INITCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldfile.asm b/private/mvdm/wow16/kernel31/ldfile.asm
new file mode 100644
index 000000000..172822c08
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldfile.asm
@@ -0,0 +1,329 @@
+ TITLE LDFILE - Loader file I/O procedures
+
+.xlist
+include kernel.inc
+include newexe.inc
+.list
+
+externFP GlobalAlloc
+externFP GlobalFree
+externFP MyOpenFile
+externFP Int21Handler
+
+sBegin CODE
+assumes CS,CODE
+
+externNP MyLock
+
+;-----------------------------------------------------------------------;
+; LoadNRTable ;
+; ;
+; Returns the segment address of the non-resident name table. ;
+; ;
+; Arguments: ;
+; parmW hexe exeheader to load NRTable from ;
+; parmW fh file handle, -1 if none ;
+; parmD oNRTable if batching, this is where we left off ;
+; parmD lpNRbuffer if batching, this is buffer to use ;
+; parmW cbNRbuffer if batching, this is size of buffer ;
+; ;
+; Returns: ;
+; DX:AX = pointer to non-resident table ;
+; CX:BX = if batching this is where to pick up from ;
+; ;
+; Error Returns: ;
+; DX:AX = NULL ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; MyOpenFile ;
+; GlobalAlloc ;
+; MyLock ;
+; ;
+; History: ;
+; ;
+; Tue 09-May-1989 18:38:04 -by- David N. Weise [davidw] ;
+; Added the batching if out of memory. ;
+; ;
+; Thu Oct 08, 1987 10:11:42p -by- David N. Weise [davidw] ;
+; Added this nifty comment block and fixed it for fastboot. ;
+;-----------------------------------------------------------------------;
+
+cProc LoadNRTable,<PUBLIC,NEAR>,<si,di>
+ parmW hexe
+ parmW fh
+ parmD oNRTable
+ parmD lpNRbuffer
+ parmW cbNRbuffer
+
+ localD lt_ExeoNRTable ; the real offset in the Exe
+ localD lt_oNRTable
+ localB fBatching
+ localB fFirstTime
+ localW cbnrestab
+ localW pfileinfo ; used for debugging only
+cBegin
+ mov cx,oNRTable.hi ; Are we batching?
+ or cx,oNRTable.lo
+ or cl,ch
+ mov fBatching,cl
+ xor di,di
+ mov fFirstTime,0
+
+if KDEBUG
+ mov pfileinfo,di
+endif
+ mov es,hexe
+ mov si,ne_nrestab
+ mov bx,fh
+ mov dx,es:[si][2] ; Get potential segment address
+ mov ax,es:[si][0]
+ inc bx ; Were we passed a file handle
+ jnz ltopen ; Yes, go read then
+ mov dx,es:[di].ne_pfileinfo ; No, then open the file
+if SHARE_AWARE
+ mov bx,OF_REOPEN or OF_PROMPT or OF_CANCEL or OF_VERIFY or OF_NO_INHERIT or OF_SHARE_DENY_WRITE
+else
+ mov bx,OF_REOPEN or OF_PROMPT or OF_CANCEL or OF_VERIFY or OF_NO_INHERIT
+endif
+if KDEBUG
+ mov pfileinfo,dx
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "Non-Res name table of @ES:DX"
+endif
+ regptr esdx,es,dx
+ push dx
+ push es
+ cCall MyOpenFile,<esdx,esdx,bx>
+ pop es
+ pop dx
+;;; cmp ax, -1
+;;; jne @F
+;;;
+;;; mov bx,OF_REOPEN or OF_VERIFY or OF_NO_INHERIT
+;;; cCall MyOpenFile,<esdx,esdx,bx>
+;;;
+;;;@@:
+ mov es,hexe
+ inc bx
+ jnz ltopen
+ jmp ltfail
+ltopen:
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "Loading %es2 Nonresident name table"
+ dec bx
+ mov dx,es:[si][0] ; AX:DX = file address of table
+ mov ax,es:[si][2]
+ cmp es:[di].ne_pfileinfo,di ; Is the NRTable in WIN200.OVL?
+ jnz lt_seek
+ mov cx,4 ; Shift left AX:DX by 4.
+lt_winovl:
+ shl dx,1
+ rcl ax,1
+ loop lt_winovl
+lt_seek:
+ mov lt_ExeoNRTable.hi,ax
+ mov lt_ExeoNRTable.lo,dx
+ cmp fBatching,0 ; Are we batching?
+ jz lt_not_batching
+ mov ax,oNRTable.hi
+ mov dx,oNRTable.lo
+lt_not_batching:
+ mov lt_oNRTable.hi,ax
+ mov lt_oNRTable.lo,dx
+ mov cx,ax ; CX:DX = file address of table
+ mov ax,4200h ; Seek to beginning of the table
+ DOSCALL
+ jnc @F
+ jmp ltfail
+@@: push es
+ push bx
+ cmp fBatching,0
+ jz lt_first_time
+lt_got_no_space:
+ mov es,hexe
+ mov dx,oNRTable.hi
+ mov ax,oNRTable.lo
+ sub ax,lt_ExeoNRTable.lo ; compute the bytes read so far
+ sbb dx,lt_ExeoNRTable.hi
+ sub ax,es:[di].ne_cbnrestab
+ neg ax
+ cmp ax,cbNRbuffer
+ jbe @F
+ mov ax,cbNRbuffer
+@@: mov cbnrestab,ax
+
+ les di,lpNRbuffer
+ mov ax,es
+ mov dx,ax
+ jmps lt_share_your_space
+
+lt_first_time:
+ mov fFirstTime,1 ; make non-zero
+ mov ax,es:[ne_cbnrestab] ; first time through
+ mov cbnrestab,ax
+ add ax,4
+ mov bx,GA_MOVEABLE or GA_NODISCARD
+ xor cx,cx
+
+ cCall GlobalAlloc,<bx,cx,ax>
+ xor dx,dx
+ or ax,ax
+ jnz lt_got_space
+
+ mov ax,lt_oNRTable.hi
+ mov oNRTable.hi,ax
+ mov ax,lt_oNRTable.lo
+ mov oNRTable.lo,ax
+ mov fBatching,1
+ jmp lt_got_no_space
+
+lt_got_space:
+ cCall MyLock,<ax>
+ xor di,di
+lt_share_your_space:
+ pop bx
+ mov cx,ds ; Save DS
+ pop ds
+ push cx ; after alloc
+ mov es,ax
+ cmp fBatching,0
+ jnz @F
+ xor ax,ax ; Set table loaded indicator
+ xchg ds:[si],ax
+ cld
+ stosw ; Save file offset
+ mov ax,dx
+ xchg ds:[si+2],ax ; Set segment handle
+ stosw ; Save file offset
+@@: mov cx,cbnrestab
+ smov ds,es
+ push dx
+ mov dx,di
+ mov ah,3Fh ; Read in the table
+ DOSCALL
+ pop dx
+ pop ds
+ jc ltfail ; did the DOS call fail?
+ cmp ax,cx ; did we get all the bytes?
+ jne ltfail
+
+ cmp fBatching,0 ; are we batching?
+ jz ltdone
+ std ; truncate to whole strings
+ push bx
+ xor ax,ax
+ xor bx,bx
+ mov dx,cbNRbuffer
+ dec dx
+@@: cmp byte ptr es:[di][bx],0 ; are we at end of NRTable?
+ jnz lt_not_buffer_end
+ xor ax,ax
+ mov oNRTable.hi,ax
+ mov oNRTable.lo,ax
+ jmps lt_return_buffer
+lt_not_buffer_end:
+ mov cx,bx
+ mov al,byte ptr es:[di][bx]
+ add bx,ax
+ add bx,3
+ cmp bx,dx
+ jb @B
+ mov bx,cx
+ mov byte ptr es:[di][bx],0
+ add oNRTable.lo,bx
+ adc oNRTable.hi,0
+lt_return_buffer:
+ pop bx
+ les ax,lpNRbuffer
+ mov dx,es
+ cmp fFirstTime,0
+ jnz ltdone_0
+ jmps ltexit
+
+ltdone:
+ push bx
+ cCall MyLock,<dx>
+ pop bx
+ mov dx,ax
+ mov ax,4
+ltdone_0:
+ mov es,dx
+ mov si,ax
+ xor ax,ax
+ mov al,es:[si]
+ add ax,si
+ add ax,3
+ jmps ltexit
+ltfail:
+if KDEBUG
+ push bx
+ kerror ERR_LDNRTABLE,<Unable to load non-resident name table from >,hexe,pfileinfo
+;;; kerror ERR_LDNRTABLE,<(TRY FILES=30 to fix this) Unable to load non-resident name table from >,hexe,pfileinfo
+ pop bx
+endif
+ xor ax,ax
+ xor dx,dx
+
+ltexit: cmp bx,fh
+ je ltx1
+ push ax
+ mov ah,3Eh
+ DOSCALL
+ pop ax
+ltx1:
+ mov cx,oNRTable.hi
+ mov bx,oNRTable.lo
+ cld ; we'll be polite
+cEnd
+
+
+;
+; GetStringPtr( hExe, offset ) - Procedure to return the far address of a
+; string in the passed new EXE file's string table
+;
+cProc GetStringPtr,<PUBLIC,NEAR>,<si,di>
+ parmW hExe
+ parmW fh
+ parmW soffset
+cBegin
+ mov es,hExe
+ mov dx,es
+ mov ax,es:[ne_imptab]
+ add ax,soffset
+cEnd
+
+
+; FreeNRTable( lptable ) - Procedure to free table allocated by LoadNRTable
+; and restore the new EXE header information.
+
+cProc FreeNRTable,<PUBLIC,FAR>,<si,di>
+ parmW hexe
+ parmW tblid
+cBegin
+ mov es,hexe
+ mov di,tblid
+ xor ax,ax
+ mov cx,es:[di+2]
+ cmp word ptr es:[di],0
+ jne lfexit
+ jcxz lfexit
+ push cx
+ cCall MyLock,<cx>
+ pop cx
+ mov es,hexe
+ push ds
+ mov ds,ax
+ xor si,si
+ cld
+ movsw
+ movsw
+ pop ds
+ cCall GlobalFree,<cx>
+lfexit:
+cEnd
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldheader.asm b/private/mvdm/wow16/kernel31/ldheader.asm
new file mode 100644
index 000000000..3a3832543
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldheader.asm
@@ -0,0 +1,853 @@
+ TITLE LDHEADER - Load Exe Header procedure
+
+.xlist
+include gpfix.inc
+include kernel.inc
+include newexe.inc
+.list
+
+externA __AHINCR
+
+externFP IGlobalAlloc
+externFP IGlobalFree
+externFP FarSetOwner
+externFP Int21Handler
+externFP FarMyUpper
+externFP IsBadStringPtr
+externFP _hread
+
+DataBegin
+
+externB fBooting
+externB szBozo
+externW winVer
+externD pSErrProc
+
+DataEnd
+
+externFP IGlobalLock
+externFP IGlobalUnLock
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+
+externNP NResGetPureName
+
+
+;-----------------------------------------------------------------------;
+; LoadExeHeader ;
+; ;
+; Routine to read an EXE header and check for a new format EXE file. ;
+; Returns NULL if not a new format EXE. Otherwise reads the resident ;
+; portion of the new EXE header into allocated storage and returns ;
+; the segment address of the new EXE header. ;
+; ;
+; Arguments: ;
+; parmW fh ;
+; parmW isfh ;
+; parmD pfilename ;
+; ;
+; Returns: ;
+; AX = segment of exe header ;
+; DL = ne_exetyp ;
+; DH = ne_flagsothers ;
+; ;
+; Error Returns: ;
+;LME_MEM = 0 ; Out of memory ;
+;LME_VERS = 10 ; Wrong windows version ;
+;LME_INVEXE = 11 ; Invalid exe ;
+;LME_OS2 = 12 ; OS/2 app ;
+;LME_DOS4 = 13 ; DOS 4 app ;
+;LME_EXETYPE = 14 ; unknown exe type ;
+;LME_COMP = 19 ; Compressed EXE file ;
+;LME_PE = 21 ; Portable EXE ;
+; ;
+; Registers Preserved: ;
+; DI,SI ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DS,ES ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Mar 19, 1987 08:35:32p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc LoadExeHeader,<PUBLIC,FAR>,<si,di>
+ parmW fh
+ parmW isfh
+ parmD pfilename
+ localW pnewexe
+ localW exetype
+ localW nchars
+ localW pseg
+ localW psegsrc
+ localW hBlock
+ localW pBlock
+ localW NEFileOffset
+ localD PreloadLen
+ localW NEBase
+ localW exeflags
+ localW expver
+ localW saveSP
+ localB fast_fail ; 1 if we can't use fastload block
+ localV hdrbuf,<SIZE EXE_HDR>
+
+.errnz SIZE EXE_HDR - SIZE NEW_EXE
+
+cBegin
+ xor ax,ax
+ mov pseg,ax
+ mov hBlock, ax
+ mov fast_fail, al
+ cmp SEG_pfilename,ax
+ je re0
+
+IF KDEBUG ; LoadExeHeader is internal
+ cCall IsBadStringPtr, <pfilename, 128> ; so we assume file pointer is OK
+ or ax, ax
+ jnz refailj
+ENDIF
+ lds si,pfilename
+ mov al,ds:[si].opLen
+ inc ax ; include null byte
+re0:
+ mov nchars,ax
+ mov bx,fh ; No, seek backwards over what
+ cmp isfh,bx
+ je refile
+ mov ds,bx
+ xor si,si
+ jmp remem
+
+refile: ; Here to load from a file
+ push ss ; DS:SI points to I/O buffer
+ pop ds
+ lea si,hdrbuf ; Read beginning of file
+ mov dx,si
+ mov cx,SIZE EXE_HDR
+ mov bx,fh
+ mov ah,3Fh
+ DOSFCALL
+ jnc @F
+refailj:
+ jmps refail
+@@:
+ cmp ax,cx ; Old EXE file, look for offset
+ jb refailj ; to new exe header
+ cmp ds:[si].e_magic,EMAGIC ; Check for old exe file
+ je @F
+ cmp ds:[si], 'ZS' ; Is it compressed?
+ jne refail
+ cmp ds:[si][2],'DD'
+ jne refail
+ cmp ds:[si][4],0F088h
+ jne refail
+ cmp ds:[si][6],03327h
+ jne refail
+ mov ax, LME_COMP ; Compressed EXE
+ jmp reexit
+@@:
+ mov ax,ds:[si].e_lfanew.hi
+ mov dx,ds:[si].e_lfanew.lo
+ mov pnewexe,dx ; To check for bound OS/2 apps.
+ or ax,dx
+ jz refail ; Fail if not there.
+
+ mov cx,ds:[si].e_lfanew.hi
+ mov dx,ds:[si].e_lfanew.lo
+ mov bx, fh
+ mov ax,4200h
+ DOSFCALL
+ jc refail
+ mov cx,SIZE NEW_EXE
+ mov dx,si
+ mov ah,3Fh
+ DOSFCALL
+ jc refail
+ cmp ax,cx
+ jne refail
+ cmp ds:[si].ne_magic,NEMAGIC ; Did we get a valid new EXE header?
+ je remem
+ cmp ds:[si].ne_magic,PEMAGIC ; Did we find a Portable EXE (WIN32)
+ jne refail
+ mov ax, LME_PE
+ jmps rej
+refail:
+ mov ax, LME_INVEXE ; invalid NEW EXE file format
+rej: jmp reexit
+
+remem:
+ mov psegsrc,bx ; bx has either fh or seg address
+ mov di,ds:[si].ne_enttab ; Compute size of resident new header
+ add di,ds:[si].ne_cbenttab
+ add di, 6 ; null entry space (bug #8414)
+
+ mov cx, ds:[si].ne_cbenttab
+ mov bx, ds:[si].ne_cmovent
+ shl bx, 1
+ sub cx, bx
+ shl bx, 1
+ sub cx, bx ; Number of bytes not moveable entries
+ shl cx, 1 ; Allow triple these bytes
+ add di, cx
+
+ mov cx,ds:[si].ne_cseg ; + 3 * #segments
+
+; Reserve space for ns_handle field in segment table
+
+ shl cx,1
+ add di,cx
+
+ .errnz 10 - SIZE NEW_SEG1
+
+; Reserve space for file info block at end
+
+ add di,nchars ; + size of file info block
+
+ xor ax,ax ; Allocate a fixed block for header
+ mov bx,GA_ZEROINIT or GA_MOVEABLE
+ cCall IGlobalAlloc,<bx,ax,di> ; that isn't code or data.
+ or ax,ax
+ jnz @F
+ jmps badformat
+@@:
+ push ax
+ cCall IGlobalLock,<ax>
+ pop ax
+ push dx
+ cCall IGlobalUnlock,<ax>
+ pop ax
+ sub di,nchars
+ mov pseg,ax
+ mov es,ax ; ES:0 -> new header location
+ cld ; DS:SI -> old header
+ mov bx,psegsrc
+ cmp isfh,bx ; Is header in memory?
+ jne remem1 ; Yes, continue
+ mov ax,ds:[si].ne_enttab ; No, read into high end
+ add ax,ds:[si].ne_cbenttab ; of allocated block
+ sub di,ax
+ mov cx,SIZE NEW_EXE ; Copy part read so far
+ sub ax,cx
+ rep movsb
+ mov cx,ax
+ smov ds,es ; Read rest of header from file
+ mov dx,di
+ mov ah,3fh
+ DOSFCALL
+ mov bx,ax
+ jc refail1
+ lea si,[di-SIZE NEW_EXE] ; DS:SI -> old header
+ cmp bx,cx
+ je remem1
+badformat:
+ mov ax, LME_INVEXE ; don't change flags
+refail1: ; Here if error reading header
+ push ax
+ SetKernelDSNRes ; DS may be = pseg, prevent
+ cCall IGlobalFree,<pseg> ; GP faults in pmode.
+ pop ax
+ jmp reexit
+
+remem1:
+ UnsetKernelDS
+ test ds:[si].ne_flags,NEIERR ; Errors in EXE image?
+ jnz badformat ; Yes, fail
+
+ cmp ds:[si].ne_ver,4 ; No, built by LINK4 or above?
+ jl badformat ; No, error
+ mov bx,ds:[si].ne_flags ; Make local copies of ne_flags &
+ and bl,NOT NEPROT ; ne_expver which can be modified
+ mov exeflags,bx ; (can't change ROM exe headers).
+ mov bx,ds:[si].ne_expver
+ mov expver,bx
+ mov bx,word ptr ds:[si].ne_exetyp ; get exetyp and flagsothers
+ mov exetype,bx
+
+ cmp bl,NE_UNKNOWN
+ jz windows_exe
+ cmp bl,NE_WINDOWS ; is it a Windows exe?
+ jz windows_exe
+ mov ax,LME_OS2
+ cmp bl,NE_OS2 ; is it an OS|2 exe?
+ jnz not_os2
+ test bh,NEINPROT ; can it be run under Windows?
+ jz @F
+ and exeflags,NOT NEAPPLOADER
+ or exeflags,NEPROT
+ mov expver,0300h
+ jmps windows_exe
+@@:
+ cmp pnewexe,0800h ; is it a bound
+ jb refail1
+ jmp badformat
+not_os2:
+ inc ax ; AX = 13 - LME_DOS4
+ cmp bl,NE_DOS4 ; is it a DOS 4 exe?
+ jz refail1
+ inc ax ; AX = 14 - LME_EXETYPE
+ jmp refail1
+
+mgxlib DB 'MGXLIB'
+
+windows_exe:
+
+ mov NEBase, si ; Offset of Source header
+ xor di,di ; ES:DI -> new header location
+ mov cx,SIZE NEW_EXE ; Copy fixed portion of header
+ cld
+ rep movsb
+ mov ax,exeflags
+if ROM
+ and al,NOT NEMODINROM ; Assume module not in ROM
+endif
+ mov es:[ne_flags],ax
+ mov ax,expver
+ mov es:[ne_expver],ax
+ mov si, NEBase
+ add si, es:[ne_segtab] ; Real location of segment table
+ mov cx,es:[ne_cseg] ; Copy segment table, adding
+ mov es:[ne_segtab],di
+ jcxz recopysegx
+recopyseg:
+
+if ROM
+
+; If this is a module from ROM, the ROM ns_sector field contains the selector
+; pointing to the ROM segment--this will become the RAM ns_handle value.
+
+ .errnz ns_sector
+ mov dx,ds:[si].ns_flags ; do while si->start of seg info
+ lodsw ; ns_sector
+ xor bx,bx ; ns_handle if not in ROM
+ test dh,(NSINROM SHR 8)
+ jz store_sector
+ mov bx,ax ; will be ns_handle
+store_sector:
+ stosw ; ns_sector
+else
+ movsw ; ns_sector
+endif
+ movsw ; ns_cbseg
+ lodsw ; ns_flags
+
+ .errnz 4 - ns_flags
+
+if ROM
+ mov dl,al
+ and dl,NSLOADED
+ and ax,not (NS286DOS XOR (NSGETHIGH OR NSINROM))
+else
+ and ax,not (NS286DOS XOR NSGETHIGH) ; Clear 286DOS bits
+endif
+; record in the segment flags if this module is a process, this is for EMS
+
+ test ax,NSTYPE ; NSCODE
+ jnz not_code
+ or ax,NSWINCODE
+not_code:
+ or ax,NSNOTP
+ test es:[ne_flags],NSNOTP
+ jnz not_a_process
+ xor ax,NSNOTP
+ or ax,NSMOVE
+not_a_process:
+if ROM
+ test ah,(NSINROM SHR 8) ; if sector is in ROM, preserve
+ jz @f ; NSLOADED flag from ROM builder
+ or al,dl
+@@:
+endif
+ stosw ; ns_flags
+ movsw ; ns_minalloc
+ .errnz 8 - SIZE NEW_SEG
+if ROM
+ mov ax,bx ; bx set to selector or 0 above
+else
+ xor ax,ax
+endif
+ stosw ; one word for ns_handle field
+ .errnz 10 - SIZE NEW_SEG1
+ loop recopyseg
+
+recopysegx:
+ test es:[ne_flagsothers], NEGANGLOAD
+ jz no_gang_loadj
+ mov bx, fh
+ cmp bx, isfh
+ jne no_gang_loadj
+
+ mov ax, es:[ne_gang_start]
+ or ax, ax
+ jz no_gang_loadj
+ mov NEFileOffset, ax ; file offset of gang load area
+ mov ax, es:[ne_gang_length]
+ or ax, ax
+ jz no_gang_loadj
+ mov cx, es:[ne_align]
+ xor dx, dx
+gl_len: ; find length of Gang Load area
+ shl ax, 1
+ adc dx, dx
+ loop gl_len
+
+ cmp dx, 10h ; Greater than 1Mb, forget it!!
+ jb alloc_it ; PS: NEVER go bigger than 1Mb
+no_gang_loadj:
+ jmp no_gang_load ; since LongPtrAdd is limited...
+
+alloc_it:
+ mov word ptr PreloadLen[0], ax
+ mov word ptr PreloadLen[2], dx
+ mov ch, GA_DISCARDABLE
+ mov cl, GA_MOVEABLE+GA_NODISCARD+GA_NOCOMPACT
+ push es
+ cCall IGlobalAlloc,<cx,dx,ax> ; Allocate this much memory
+ pop es
+ or ax, ax
+ jz no_gang_loadj
+ mov hBlock, ax ; Have memory to read file into
+ push es
+ cCall IGlobalLock,<ax>
+ pop es
+ mov pBlock, dx
+ mov dx, NEFileOffset
+ mov cx, es:[ne_align]
+ xor bx, bx
+gl_pos: ; find pos of Gang Load start
+ shl dx, 1
+ adc bx, bx
+ loop gl_pos
+
+ mov cx, bx
+
+ mov bx, fh
+ mov ax,4200h
+ DOSFCALL ; Seek to new exe header
+ jc refailgang
+
+ mov ax, pBlock
+ xor bx, bx
+ farptr memadr,ax,bx
+ cCall _hread, <fh, memadr, PreloadLen>
+ cmp dx, word ptr PreloadLen[2]
+ jnz refailgang
+ cmp ax, word ptr PreloadLen[0]
+ jz no_gang_load ; We're OK now
+; push ds
+; xor dx, dx
+; mov ax, pBlock
+
+; push si
+; push di
+; mov si, word ptr PreloadLen[2]
+; mov di, word ptr PreloadLen[0]
+;read_file:
+; mov cx, 08000h ; Must be factor 64k DON'T CHANGE THIS
+; or si, si
+; jnz big_read
+; cmp cx, di
+; jbe big_read
+; mov cx, di ; all that's left
+; jcxz done_read ; Nothing left, quit.
+;big_read:
+; mov ds, ax
+; mov ah, 3Fh
+; DOSFCALL ; Read chunk from file
+; jc refailgang
+; cmp ax, cx ; All we asked for?
+; jne refailgang ; no, file corrupted
+; sub di, cx
+; sbb si, 0
+; mov ax, ds
+; add dx, cx ; On to next block
+; jnc read_file
+; add ax, __AHINCR
+; jmps read_file
+;
+refailgang:
+; pop di
+; pop si
+; pop ds
+ cCall IGlobalUnlock,<hBlock>
+ cCall IGlobalFree,<hBlock>
+ mov hBlock, 0
+ jmps no_gang_load
+
+BadExeHeader: ; GP fault handler!!!
+ mov sp, saveSP
+; fix_fault_stack
+ jmp refail1 ; corrupt exe header (or our bug)
+
+
+;done_read:
+; pop di
+; pop si
+; pop ds
+
+no_gang_load:
+ mov saveSP, sp
+beg_fault_trap BadExeHeader
+ mov cx,es:[ne_restab] ; Copy resource table
+ sub cx,es:[ne_rsrctab]
+ mov si, NEBase ; Get correct source address
+ add si, es:[ne_rsrctab]
+ mov es:[ne_rsrctab],di
+ rep movsb
+
+rerestab:
+ mov cx,es:[ne_modtab] ; Copy resident name table
+ sub cx,es:[ne_restab]
+ mov es:[ne_restab],di
+ rep movsb
+
+ push di
+ mov di, es:[ne_restab] ; Make the module name Upper Case
+ xor ch, ch
+ mov cl, es:[di]
+ inc di
+uppercaseit:
+ mov al, es:[di]
+ call farMyUpper
+ stosb
+ loop uppercaseit
+ pop di
+
+ mov cx,es:[ne_imptab] ; Copy module xref table
+ sub cx,es:[ne_modtab]
+ mov es:[ne_modtab],di
+ rep movsb
+
+ mov es:[ne_psegrefbytes],di ; Insert segment reference byte table
+ mov es:[ne_pretthunks],di ; Setup return thunks
+ mov cx,es:[ne_enttab] ; Copy imported name table
+ sub cx,es:[ne_imptab]
+ mov es:[ne_imptab],di
+ jcxz reenttab
+ rep movsb
+
+reenttab:
+ mov es:[ne_enttab],di
+ ; Scan current entry table
+ xor ax, ax ; First entry in block
+ mov bx, di ; Pointer to info for this block
+ stosw ; Starts at 0
+ stosw ; Ends at 0
+ stosw ; And is not even here!
+
+copy_next_block:
+ lodsw ; Get # entries and type
+ xor cx, cx
+ mov cl, al
+ jcxz copy_ent_done
+
+ mov al, ah
+ cmp al, ENT_UNUSED
+ jne copy_used_block
+
+ mov ax, es:[bx+2] ; Last entry in current block
+ cmp ax, es:[bx] ; No current block?
+ jne end_used_block
+
+ add es:[bx], cx
+ add es:[bx+2], cx
+ jmps copy_next_block
+
+end_used_block:
+ mov es:[bx+4], di ; Pointer to next block
+ mov bx, di
+ add ax, cx ; Skip unused entries
+ stosw ; First in new block
+ stosw ; Last in new block
+ xor ax, ax
+ stosw ; End of list
+ jmps copy_next_block
+
+copy_used_block:
+ add es:[bx+2], cx ; Add entries in this block
+ cmp al, ENT_MOVEABLE
+ je copy_moveable_block
+
+; absolutes end up here as well
+
+copy_fixed_block:
+ stosb ; Segno
+ movsb ; Flag byte
+ stosb ; segno again to match structure
+ movsw ; Offset
+ loop copy_fixed_block
+ jmps copy_next_block
+
+copy_moveable_block:
+ stosb ; ENT_MOVEABLE
+ movsb ; Flag byte
+ add si, 2 ; Toss int 3Fh
+ movsb ; Copy segment #
+ movsw ; and offset
+ loop copy_moveable_block
+ jmps copy_next_block
+
+copy_ent_done:
+ xor bx,bx
+ cmp es:[bx].ne_ver,5 ; Produced by version 5.0 LINK4
+ jae remem2a ; or above?
+ mov es:[bx].ne_expver,bx ; No, clear uninitialized fields
+ mov es:[bx].ne_swaparea,bx
+
+; TEMPORARY BEGIN
+
+ push ax
+ push cx
+ push di
+ push si
+ mov si,es:[bx].ne_rsrctab
+ cmp si,es:[bx].ne_restab
+ jz prdone
+ mov di,es:[si].rs_align
+ add si,SIZE new_rsrc
+prtype:
+ cmp es:[si].rt_id,0
+ je prdone
+ mov cx,es:[si].rt_nres
+ add si,SIZE rsrc_typeinfo
+prname:
+ push cx
+ mov ax,es:[si].rn_flags
+ test ah,0F0h ; Is old discard field set?
+ jz @F
+ or ax,RNDISCARD ; Yes, convert to bit
+@@:
+ and ax,not RNUNUSED ; Clear unused bits in 4.0 LINK files
+ mov es:[si].rn_flags,ax
+ pop cx
+ add si,SIZE rsrc_nameinfo
+ loop prname
+
+ jmp prtype
+
+prdone: pop si
+ pop di
+ pop cx
+ pop ax
+
+; TEMPORARY END
+
+FixFlags: ; label for debugging
+public FixFlags, leh_slow
+public leh_code, leh_patchnext, leh_code_fixed, leh_patchdone, leh_data
+remem2a: ; (bx == 0)
+ mov es:[bx].ne_usage,bx
+ mov es:[bx].ne_pnextexe,bx
+ mov es:[bx].ne_pfileinfo,bx
+ cmp es:[bx].ne_align,bx
+ jne @F
+ mov es:[bx].ne_align,NSALIGN
+@@:
+ mov cx,nchars
+ jcxz @F
+ mov es:[bx].ne_pfileinfo,di
+ lds si,pfilename
+ rep movsb
+@@: ; Save pointer to seginfo record
+ mov bx,es:[bx].ne_autodata ; of automatic data segment
+ or bx,bx
+ jz @F
+ dec bx
+ shl bx,1
+ mov cx,bx
+ shl bx,1
+ shl bx,1
+ add bx,cx
+ .errnz 10 - SIZE NEW_SEG1
+ add bx,es:[ne_segtab]
+@@:
+ mov es:[ne_pautodata],bx
+
+ SetKernelDSNRes
+
+; Scan seg table, marking nonautomatic DATA segments fixed, preload
+
+ mov ax,es:[ne_expver] ; Default expected version to
+ or ax,ax
+ jnz @F
+ mov ax,201h
+ mov es:[ne_expver],ax ; 2.01
+@@:
+ cmp ax,winVer
+ jbe @F
+ cCall IGlobalFree,<pseg>
+ mov ax, LME_VERS
+ jmp reexit
+@@:
+ mov bx,es:[ne_segtab]
+ xor cx,cx
+ sub bx,SIZE NEW_SEG1
+ jmps leh_patchnext
+
+leh_test_preload:
+ test byte ptr es:[bx].ns_flags, NSPRELOAD
+ jnz leh_patchnext
+
+ or byte ptr es:[bx].ns_flags, NSPRELOAD
+
+ cmp es:[bx].ns_sector, 0 ; don't whine about empty segments
+ je leh_patchnext
+
+ krDebugOut DEB_WARN, "Segment #CX of %ES0 must be preload"
+ mov fast_fail, 1
+
+leh_patchnext:
+ add bx,SIZE NEW_SEG1
+ inc cx
+ cmp cx,es:[ne_cseg]
+ ja leh_patchdone
+ test byte ptr es:[bx].ns_flags,NSDATA ; Is it a code segment?
+ jz leh_code ; Yes, next segment
+ .errnz NSCODE
+leh_data: ; Data must be non-discardable, preload
+if KDEBUG
+ test es:[bx].ns_flags, NSDISCARD
+ jz @F
+ krDebugOut DEB_WARN, "Data Segment #CX of %ES0 can't be discardable"
+@@:
+endif
+ and es:[bx].ns_flags,not NSDISCARD ; Data segments not discardable
+ jmps leh_test_preload
+
+leh_code:
+ test byte ptr es:[bx].ns_flags,NSMOVE; Moveable code?
+ jz leh_code_fixed
+
+ ; moveable code must be discardable, or must be preload
+if KDEBUG
+ test es:[ne_flags],NENOTP ; for 3.0 libraries can't have
+ jz @F ; moveable only code
+ cmp fBooting,0 ; If not booting
+ jne @F
+ test es:[bx].ns_flags,NSDISCARD
+ jnz @F
+ krDebugOut DEB_WARN, "Segment #CX of %ES0 was discardable under Win 3.0"
+@@:
+endif
+ test es:[bx].ns_flags,NSDISCARD ; Is it discardable?
+ jnz leh_patchnext
+ jmp leh_test_preload
+
+leh_code_fixed: ; fixed code must be preload
+ cmp fBooting,0 ; If not booting
+ jne leh_patchnext
+ jmp leh_test_preload
+
+leh_patchdone:
+ mov bx,word ptr es:[ne_csip+2] ; Is there a start segment?
+ or bx,bx
+ jz @F ; No, continue
+ dec bx
+ shl bx,1
+ mov si,bx
+ shl si,1
+ shl si,1
+ add si,bx
+ .errnz 10 - SIZE NEW_SEG1
+ add si,es:[ne_segtab] ; Mark start segment as preload
+if kdebug
+ test byte ptr es:[si].ns_flags,NSPRELOAD
+ jnz scs_pre
+ krDebugOut DEB_WARN, "Starting Code Segment of %ES0 must be preload"
+ mov fast_fail, 1
+scs_pre:
+endif
+ or byte ptr es:[si].ns_flags,NSPRELOAD
+
+ cmp es:[ne_autodata],0 ; Is there a data segment?
+ je @F
+ or es:[si].ns_flags,NSUSESDATA ; Yes, then it needs it
+ mov si,es:[ne_pautodata]
+if kdebug
+ test byte ptr es:[si].ns_flags,NSPRELOAD
+ jnz sds_pre
+ cmp es:[bx].ns_sector, 0 ; don't whine about empty segments
+ je sds_pre
+ krDebugOut DEB_WARN, "Default Data Segment of %ES0 must be preload"
+ mov fast_fail, 1
+sds_pre:
+endif
+ or byte ptr es:[si].ns_flags,NSPRELOAD ; Mark DS as preload
+@@:
+ test es:[ne_flags],NENOTP ; No stack if not a process
+ jnz @F
+ cmp es:[ne_stack],4096+1024
+ jae @F
+ mov es:[ne_stack],4096+1024 ; 4k stack is not enough (raor)
+@@:
+ mov cx, es:[ne_heap] ; If the module wants a heap
+ jcxz @f ; make sure it's big enough
+if KDEBUG ; not to cause LocalInit
+ mov ax, 100 + SIZE LocalStats ; to fail when called from
+else ; InitTask or the user will
+ mov ax, 100 ; be left wondering why the
+endif ; task doesn't run and there
+ cmp cx, ax ; is no error msg.
+ jae @f
+ mov es:[ne_heap], ax
+@@:
+ mov ax,es ; Set owner to be itself
+ cCall FarSetOwner,<ax,ax>
+
+ mov dx,exetype
+ test dh,NEINFONT ; save the font bit in exehdr
+ jz reexit ; somewhere
+ or es:[ne_flags],NEWINPROT
+end_fault_trap
+
+reexit:
+; cmp ax, 20h ; translate error messages for ret
+; jae @F
+; mov bx, ax
+; xor ax, ax
+; cmp bl, 1 ; bx is 0, 1, 2, 19, other
+; jz @F ; 1 -> 0 (out of memory)
+; mov al, 11
+; jb @F ; 0 -> 11 (invalid format)
+; cmp bl, 3 ;
+; mov al, 10
+; jb @F ; 2 -> 10 (windows version)
+; mov al, 19 ; 3 -> 19 (compressed EXE)
+; jz @F ; others left alone
+; mov al, bl
+;@@:
+ push dx
+ mov bx, hBlock
+ or bx, bx
+ je noUnlock ; No block to unlock
+ push ax
+ cCall IGlobalUnlock,<bx>
+ push ss
+ pop ds ; might be freeing DS
+ cmp fast_fail, 1 ; is fastload area invalid?
+ jne @F
+leh_slow:
+ krDebugOut DEB_WARN, "FastLoad area ignored due to incorrect segment flags"
+ cCall IGlobalFree,<hBlock> ; yes - free it, force slow-load
+ mov hBlock, 0
+@@:
+ pop ax
+ cmp ax, LME_MAXERR
+ jae noFree ; Success, return memory block in bx
+ push ax
+ cCall IGlobalFree,<hBlock>
+ pop ax
+noFree:
+ mov cx, NEFileOffset ; Return offset of header in CX
+ mov bx, hBlock
+noUnlock:
+ pop dx
+ UnSetKernelDS
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldint.asm b/private/mvdm/wow16/kernel31/ldint.asm
new file mode 100644
index 000000000..8357e7d68
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldint.asm
@@ -0,0 +1,1490 @@
+TITLE LDINT - Loader interrupt procedure
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+include dbgsvc.inc
+include bop.inc
+include kdos.inc
+include gpcont.inc ; SHERLOCK
+ifdef WOW
+include vint.inc
+include softpc.inc
+endif
+
+NOTEXT = 1
+NOGDICAPMASKS = 1
+NOMB = 1
+NOVK = 1
+NOWH = 1
+NOMST = 1
+NORASTOPS = 1
+NOMETAFILE = 1
+NOMDI = 1
+NOWINMESSAGES = 1
+NOSYSMETRICS = 1
+NOCOLOR = 1
+NOCOMM = 1
+NOKERNEL = 1
+
+include windows.inc ; YIKES!!!
+
+.list
+
+FAULTSTACKFRAME struc
+
+fsf_BP dw ? ; Saved BP
+fsf_msg dw ? ; Near pointer to message describing fault
+fsf_prev_IP dw ? ; IP of previous fault handler
+fsf_prev_CS dw ? ; CS of previous fault handler
+fsf_ret_IP dw ? ; DPMI fault handler frame follows
+fsf_ret_CS dw ?
+fsf_err_code dw ?
+fsf_faulting_IP dw ?
+fsf_faulting_CS dw ?
+fsf_flags dw ?
+fsf_SP dw ?
+fsf_SS dw ?
+
+FAULTSTACKFRAME ends
+
+fsf_OFFSET = fsf_ret_IP - fsf_msg
+
+UAE_STRING_LEN equ 192d
+MIN_SP equ 256d
+
+externFP ExitKernel
+
+DataBegin
+
+;externB syserr
+externB szAbort
+externB szAbortCaption
+externB szNukeApp
+externB szWillClose
+externB szBlame
+externB szSnoozer
+externB szInModule
+externB szAt
+externB szII
+externB szGP
+externB szSF
+externB szNP
+externB szLoad
+;externB szDiscard
+externB szPF
+externB Kernel_Flags
+externB fBooting
+externW curTDB
+;externW pGlobalHeap
+externW DemandLoadSel
+externD pSErrProc
+externD pUserGetFocus
+externD pUserGetWinTask
+externD pUserIsWindow
+externD lpGPChain
+
+if kdebug
+globalw wFaultSegNo,0
+endif
+
+if ROM
+externD prevIntx6proc
+externD prevInt0Cproc
+externD prevInt0Dproc
+externD prevInt0Eproc
+externD prevInt3Fproc
+endif
+
+if KDEBUG
+staticW INT3Fcs,0
+endif
+
+globalW FaultHandler,<codeOffset HandleFault>
+
+externD pPostMessage
+
+ifdef WOW
+externD FastBop
+externD prevInt01proc
+externD prevInt03proc
+externD oldInt00proc
+externW DebugWOW
+externW gdtdsc
+
+endif
+
+DataEnd
+
+sBegin DATA
+externW gmove_stack
+externW TraceOff
+sEnd DATA
+
+sBegin CODE
+assumes CS,CODE
+
+if SHERLOCK
+externNP GPContinue
+endif
+
+ife ROM
+externD prevIntx6proc
+externD prevInt0Cproc
+externD prevInt0Dproc
+externD prevInt0Eproc
+externD prevInt3Fproc
+endif
+
+externNP LoadSegment
+;externNP MyLock
+externNP htoa
+externNP GetOwner
+externNP GetPureName
+externNP TextMode
+externNP Int21Handler
+
+;externNP DebugPostLoadMessage
+externFP GlobalLRUNewest
+externFP GlobalHandleNorip
+externFP HasGPHandler
+externFP AllocSelector
+externFP IFreeSelector
+
+ assumes ds, nothing
+ assumes es, nothing
+
+ifdef WOW
+Entry macro name
+ public name
+ align 2
+ name&:
+ endm
+endif
+
+;-----------------------------------------------------------------------;
+; Display_Box_of_Doom -- Display the Unrecoverable Application Error
+; box that everyone seems to dislike so much.
+;
+; Entry:
+; Action Reserved, must be zero
+; lpText String to display, NULL for default
+;
+; Returns:
+; AX = 1 Cancel
+; AX = 2 OK
+;
+; Registers Destroyed:
+; AX, BX, CX, DX, SI, DI
+;
+; History:
+; Thu 16-May-1991 -by- Earle R. Horton
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Display_Box_of_Doom,<PUBLIC,NEAR>
+
+ parmW action
+ parmD lpText
+cBegin
+ SetKernelDS
+if KDEBUG
+ xor bx,bx
+ or action,bx
+ jz @F
+ kerror 00FFh,<Action not 0 in FatalAppExit>,bx,bx
+@@:
+endif
+ push es ; added 10 feb 1990
+ mov es,curTDB ; did app disable exception
+ test es:[TDB_ErrMode],02h ; message box?
+ pop es
+ jnz nf_dont_ask
+
+ cmp pSErrProc.sel, 0 ; Can we put up message box?
+ jnz short nf_ask ; yes, do it
+ ; no, have debugger?
+nf_dont_ask:
+ mov ax,1
+ test Kernel_Flags[2],KF2_SYMDEB
+ jnz nf_ret ; yes, call debugger
+ inc ax
+ jmps nf_ret ; no, have to nuke the app
+
+nf_ask:
+ push es
+ mov ax,lpText.sel
+ or ax,ax
+ jz nf_default_string
+ push ax
+ push lpText.off
+ jmps nf_pushed_string
+
+nf_default_string:
+ push ds
+ mov ax,dataOffset szAbort ; lpText
+ push ax
+
+nf_pushed_string:
+ push ds ; lpCaption
+ mov ax, dataOffset szAbortCaption
+ push ax
+
+ xor ax,ax ; Assume no debugger, blank first button
+ mov cx,ax
+ test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
+ jz @F ; No
+ mov cx,SEB_CANCEL ; Yes, use Cancel button
+@@:
+ push cx
+; push SEB_OK+SEB_DEFBUTTON
+ push SEB_CLOSE + SEB_DEFBUTTON
+ push ax
+
+ call ds:[pSErrProc] ; Put up the system error message
+ pop es
+
+nf_ret:
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; FatalAppExit -- Called by apps. to request an application error
+; message box.
+;
+; Entry:
+; Action Reserved, must be zero
+; lpText String to display, NULL for default
+;
+; Returns:
+; Returns to caller if Cancel button pressed
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 22-Oct-1989 15:18:57 -by- David N. Weise [davidw]
+; Tonyg wrote it!
+; Fri 24-May-1991 EarleH totally rewrote it, so there!
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IFatalAppExit,<PUBLIC,FAR>
+
+ parmW action
+ parmD lpText
+cBegin
+
+ cmp seg_lpText,0
+ jne fae_string
+ mov off_lpText,offset szAbort
+ mov seg_lpText,seg szAbort
+fae_string:
+ cCall Display_Box_of_Doom,<action,lpText>
+ cmp ax,1 ; Cancel pressed?
+ je fae_ret
+ jmp KillApp
+fae_ret:
+cEnd
+
+; ------------------------------------------------------------------
+;
+; FormatFaultString -- Special purpose "sprintf()"
+; Only used for the Box of Doom
+;
+; ------------------------------------------------------------------
+
+cProc FormatFaultString,<PUBLIC,NEAR>,<si,di,ds,es>
+ parmD lpstr
+ parmW pStr ; Assumed in Kernel's DS
+ parmD csip
+cBegin
+ SetKernelDS
+ cld
+ les di, lpstr ; Form string in ES:DI
+ call CurApName
+ lea si, szSnoozer ; " has caused an error in Windows"
+ call strcpy
+ mov si, pStr ; Copy the fault string
+ call strcpy
+ lea si, szInModule ; "in Module: <unknown>"
+ call strcpy
+
+ push es
+ push di
+
+ cCall GetOwner,<seg_csip> ; Can we find a module to blame?
+ or ax, ax
+ jz NoOwner
+ mov es, ax
+ cmp es:[ne_magic], NEMAGIC
+ jne NoOwner
+
+ mov bx, seg_csip ; Have the module, can we get the
+ and bl, not SEG_RING ; segment number?
+ mov di,es:[ne_segtab]
+ mov ax,1
+ mov cx, es:[ne_cseg]
+getsegno:
+ mov dx, es:[di].ns_handle
+ and dl, not SEG_RING
+ cmp dx, bx
+ jz gotsegno
+ add di,SIZE NEW_SEG1
+ inc ax
+ loop getsegno
+ jmps nosegno ; No, report the selector instead
+gotsegno:
+ mov seg_csip, ax ; Print Segment #
+nosegno:
+
+ mov di, es:[ne_pfileinfo] ; Now blame the module
+ add di, opFile
+ call GetPureName
+ mov si, di
+ smov ds, es
+ UnSetKernelDS
+ pop di
+ pop es
+ sub di, 9 ; Get rid of <unknown>
+
+ call strcpy
+ SetKernelDS
+ jmps GotOwner
+
+NoOwner:
+ pop di
+ pop es
+GotOwner:
+ lea si, szAt
+ call strcpy
+ cCall htoa,<es,di,seg_csip>
+ mov di, ax
+ mov es, dx
+ mov byte ptr es:[di], ':'
+ inc di
+ cCall htoa,<es,di,off_csip>
+ mov es, dx
+ mov di, ax
+ lea si, szNukeApp
+ call strcpy
+ call CurApName
+ lea si, szWillClose
+ call strcpy
+cEnd
+
+CurApName proc near
+ SetKernelDS
+ lea si, szBlame ; Default task to blame
+ cmp curTDB, 0 ; Have a task to blame?
+ je DefaultCaption ; nope, use default
+ mov ds, curTDB
+ UnSetKernelDS
+ mov si, TDB_ModName
+DefaultCaption:
+ mov cx, 8
+copy_appname:
+ lodsb
+ stosb
+ or al, al ; Null padded in TDB
+ loopne copy_appname
+ jne no_null
+ dec di ; Toss extra space
+no_null:
+
+ SetKernelDS
+ ret
+CurApName endp
+
+ public strcpy
+strcpy proc near
+ lodsb
+ stosb
+ or al, al
+ jnz strcpy
+ dec di ; Ignore Null
+ ret
+strcpy endp
+
+;-----------------------------------------------------------------------;
+;
+; KillApp -- Calls USER to tell it that the application is going away,
+; then tells DOS to kill it.
+;
+; ENTRY: None
+; EXIT: None, doesn't
+;
+; Registers modified: Huh?
+;
+;-----------------------------------------------------------------------;
+
+KillApp proc near
+
+ SetKernelDS
+
+ cmp fBooting, 1
+ jne @F
+ mov ax, 1
+ cCall ExitKernel,<ax>
+
+@@: mov ax,4CFFH ; They said OK to Nuke app.
+ DOSCALL
+
+ UnSetKernelDS
+KillApp endp
+
+;-----------------------------------------------------------------------;
+; FaultFilter -- Called by HandleFault, NestedFault, and routines that
+; use the same stack frame. Look at the faulting CS:IP on the exception
+; handler frame, and make sure that CS is Ring 3, LDT. If it is not
+; pop the near return address from the stack and chain the exception
+; to the next handler. This will be the DPMI server, which will crash
+; Windows back to DOS. We ought to try to close up a few things first.
+;-----------------------------------------------------------------------;
+ ReSetKernelDS
+
+ public FaultFilter
+FaultFilter proc near
+
+
+ mov al,byte ptr [bp].fsf_faulting_CS
+ and al, SEG_RING_MASK ; Check it was Ring 3, LDT
+ cmp al, SEG_RING
+
+ je @F
+;
+; The faulting CS's ring bits do not match up. We will not handle
+; this fault, because we assume it happened in the DPMI provider,
+; and is a Real Bad one. Since the default handler is going to
+; abort here, it would be nice to let the user down real easy.
+; Restoring the display to text mode would be nice, at the very
+; minimum.
+;
+ cCall TextMode
+ ret ; Hypocrite!
+@@:
+;
+; Check for faults on POP FS and POP GS. If found, fix them up. We need to
+; fix up faults in the register restoration of both KRNL386 (WOW16Return) and
+; MMSYSTEM (MULTI_MEDIA_ISR386). Monty Pythons Complete Waste of Time is an app
+; which frees selectors in FS across message boundries.
+;
+ifdef WOW
+ push ds
+ mov ax, word ptr [bp].fsf_faulting_CS
+ mov ds, ax
+ mov si, word ptr [bp].fsf_faulting_IP
+ cmp word ptr [si], 0A10Fh ; pop fs
+ je HandFSGSflt
+ cmp word ptr [si], 0A90Fh ; pop gs
+ je HandFSGSflt
+ jmp short NoFSGSflt
+HandFSGSflt:
+if KDEBUG
+ Trace_Out "POP GS/FS fault fixed up!"
+endif
+ mov ds, [bp].fsf_SS
+ mov si, [bp].fsf_SP
+ mov word ptr [si], 0
+ pop ds ; restore kernel DS
+ pop ax ; don't do EH_Chain
+ push codeOffset EH_ret ; use "handled it" return instead
+ ret
+NoFSGSflt:
+ pop ds
+endif
+
+ pop ax ; toss chain return
+ push codeOffset EH_ret ; use "handled it" return
+
+ mov si,word ptr FaultHandler ; SI = Handler
+ push si
+ mov word ptr FaultHandler,codeOffset NestedFault
+
+if KDEBUG
+ test byte ptr [bp].fsf_flags+1,2 ; IF set in faulting frame?
+ jnz @F
+ Trace_Out "Fault with interrupts disabled!"
+@@:
+endif
+ cmp [bp].fsf_SP,128d
+ jb ff_stack
+
+ cCall HasGPHandler, <[bp].fsf_faulting_CS, [bp].fsf_faulting_IP>
+ or ax, ax
+ jz ff_real_fault
+ mov ds, [bp].fsf_SS
+ mov bx, [bp].fsf_SP
+ sub [bp].fsf_SP, 4
+ mov cx, [bp].fsf_err_code ; put error code on stack
+ mov [bx-2],cx
+ mov dx, [bp].fsf_faulting_IP
+ mov [bx-4],dx ; and faulting IP
+ mov [bp].fsf_faulting_IP, ax ; continue at gp fault handler
+ jmps ff_ret
+
+ff_real_fault:
+
+ifdef WOW
+ test DebugWOW,DW_DEBUG
+ jz ff_no_wdebug
+
+ xor ax,ax ; 0 in AX defaults to not handled
+ push DBG_GPFAULT
+
+ FBOP BOP_DEBUGGER,,FastBop
+
+ add sp,+2
+ or ax, ax
+
+ jnz ff_ret ; Alright! they handled the exception!
+ ; Get us back to the app please!
+
+ ; Otherwise, they chose to continue the exception
+
+ff_no_wdebug:
+
+endif
+
+if SHERLOCK
+ cCall GPContinue ; We know BP points to
+ or ax, ax ; the fault frame!
+ jnz ff_ret
+endif
+
+ff_stack:
+ call si ; call our fault handler
+
+ff_ret:
+ SetKernelDS
+ pop FaultHandler
+ ret
+FaultFilter endp
+
+ifdef WOW
+;-----------------------------------------------------------------------;
+;
+; single_step
+;
+;-----------------------------------------------------------------------;
+Entry single_step
+ push ds
+ SetKernelDS ds
+
+ push ax
+
+; QCWIN traces through code which it has no source code for. This means
+; its ends up tracing through the 16-bit to 32-bit transition code and
+; when it traces on the call fword instruction, it cause 32-bit trace
+; interrupt which breaks into the kd> On a retail build with no
+; debugger attached, it might work.
+; To work around the problem we turn off the TraceFlag here if wow16cal
+; has requested it.
+
+ test TraceOff,1h
+ jnz ss_turn_off_trace_flag
+
+ test DebugWOW,DW_DEBUG
+ jz ss_no_wdebug
+
+ xor ax,ax ; 0 in AX defaults to not handled
+ push DBG_SINGLESTEP
+
+ FBOP BOP_DEBUGGER,,FastBop
+
+ add sp,+2
+ or ax, ax
+
+ jnz ss_ret ; Alright! they handled the exception!
+ ; Get us back to the app please!
+
+ss_no_wdebug:
+
+ ; Otherwise, they chose to continue the exception
+ pop ax
+ pop ds
+ jmp cs:[prevInt01proc]
+
+
+; Tell api code (wow16cal) to turn on trace flag at end of next api
+
+ss_turn_off_trace_flag:
+ sub sp,2 ; Make it look like "normalized" fault frame
+ push bp
+ mov bp,sp
+ or TraceOff,2h
+ and [bp].fsf_flags,NOT FLG_TRAP ; turn off the trap flag
+ pop bp
+ add sp,2
+ss_ret:
+ pop ax
+ pop ds
+ UnSetKernelDS ds
+ retf
+
+
+
+
+
+
+
+;-----------------------------------------------------------------------;
+;
+; breakpoint
+;
+;-----------------------------------------------------------------------;
+Entry breakpoint
+ push ds
+ SetKernelDS ds
+ push ax
+
+ test DebugWOW,DW_DEBUG
+ jz br_no_wdebug
+
+ xor ax,ax ; 0 in AX defaults to not handled
+ push DBG_BREAK
+
+ FBOP BOP_DEBUGGER,,FastBop
+
+ add sp,+2
+ or ax, ax
+
+ jnz bp_ret ; Alright! they handled the exception!
+ ; Get us back to the app please!
+
+br_no_wdebug:
+
+ ; Otherwise, they chose to continue the exception
+ pop ax
+ pop ds
+ jmp cs:[prevInt03proc]
+
+bp_ret:
+ pop ax
+ pop ds
+ UnSetKernelDS ds
+ retf
+
+;-----------------------------------------------------------------------;
+;
+; divide_overflow
+;
+;-----------------------------------------------------------------------;
+Entry divide_overflow
+ push ds
+ SetKernelDS ds
+ push ax
+
+ test DebugWOW,DW_DEBUG
+ jz di_no_wdebug
+
+ xor ax,ax ; 0 in AX defaults to not handled
+ push DBG_DIVOVERFLOW
+
+
+ FBOP BOP_DEBUGGER,,FastBop
+.286p
+ add sp,+2
+ or ax, ax
+
+ jnz do_ret ; Alright! they handled the exception!
+ ; Get us back to the app please!
+
+di_no_wdebug:
+
+ ; Otherwise, they chose to continue the exception
+ pop ax
+ pop ds
+ jmp cs:[oldInt00proc]
+
+do_ret:
+ pop ax
+ pop ds
+ UnSetKernelDS ds
+ retf
+
+
+endif
+
+;-----------------------------------------------------------------------;
+;
+; Set_GO_BP
+;
+;-----------------------------------------------------------------------;
+ public Set_GO_BP
+Set_GO_BP proc near
+ mov cx, [bp].fsf_faulting_CS ; Faulting CS
+ mov bx, [bp].fsf_faulting_IP ; Faulting IP
+ DebInt 40h
+; mov ax, 40h ; 16 bit forced go command
+; int 41h ; Call debugger
+;ifdef JAPAN
+; INT41SIGNATURE
+;endif
+ ret
+Set_GO_BP endp
+
+;-----------------------------------------------------------------------;
+;
+; ExitFault -- Fault at Exit Time!!!
+;
+; ENTRY: BP points to fault frame described above
+;
+; EXIT: Returns to DPMI.
+;
+; Registers Modified: None
+;
+;-----------------------------------------------------------------------;
+ ReSetKernelDS
+
+ public ExitFault
+ExitFault proc near
+if KDEBUG
+ Trace_Out "Fault at Exit Time!!!"
+endif
+;
+; If a kernel debugger is loaded, pop out at the nested fault, and
+; take no prisoners.
+;
+ test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
+ jz @F
+ jmp Set_GO_BP
+@@:
+ jmps HandleFault
+ExitFault endp
+
+ public BUNNY_351
+BUNNY_351 proc far
+ push ds
+ SetKernelDS
+ mov FaultHandler,codeOffset ExitFault
+ pop ds
+ ret
+BUNNY_351 endp
+
+;-----------------------------------------------------------------------;
+;
+; MY_RETF -- Executes a far return.
+;
+;-----------------------------------------------------------------------;
+
+MY_RETF proc near
+ retf
+MY_RETF endp
+
+;-----------------------------------------------------------------------;
+;
+; NestedFault -- Called when a fault handler Faults!!!
+;
+; ENTRY: BP points to fault frame described above
+;
+; EXIT: Returns to DPMI.
+;
+; Registers Modified: None
+;
+;-----------------------------------------------------------------------;
+ ReSetKernelDS
+
+ public NestedFault
+NestedFault proc near
+if KDEBUG
+ Trace_Out "Nested Fault!!!"
+endif
+;
+; If a kernel debugger is loaded, pop out at the nested fault, and
+; take no prisoners.
+;
+ test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
+ jz @F
+ jmp Set_GO_BP
+@@:
+ jmps HandleFault
+NestedFault endp
+
+;-----------------------------------------------------------------------;
+;
+; HandleFault -- Puts up the System Error box for a Fault. Terminates
+; the application or enters the debugger.
+;
+; ENTRY: BP points to fault frame described above
+;
+; EXIT: Returns to DPMI. If Cancel is pressed, we tell
+; WDEB to set a GO breakpoint at the faulting instruction
+; first. If OK is pressed, then the CS:IP on the DPMI
+; fault frame is modified to point to KillApp, and the
+; SS:SP points to a temp. stack owned by Kernel.
+;
+; Registers Modified: None
+;
+;-----------------------------------------------------------------------;
+ ReSetKernelDS
+
+ public HandleFault
+HandleFault proc near
+
+ mov ax, lpGPChain.sel ; Do we have a private GP handler?
+ mov lpGPChain.sel, 0 ; Prevent re-entrancy
+ cmp ax, [bp].fsf_SS
+ jnz We_Can_Handle_It
+
+ test Kernel_Flags[2],KF2_SYMDEB ; Debugger?
+ jz @F
+ mov lpGPChain.sel,ax
+
+ jmp Set_GO_BP
+@@:
+ ; If we want to chain back for any
+ mov bx, lpGPChain.off ; faults, then set up the stack of
+ mov [bp].fsf_SP, bx ; the handler, and continue execution
+ mov [bp].fsf_faulting_CS, cs ; at a RETF in Kernel
+ mov [bp].fsf_faulting_IP, offset MY_RETF
+
+ cmp [pPostMessage.sel],0 ; is there a USER around yet?
+ je @F
+ pusha
+ push es
+ cCall [pPostMessage],<-1,WM_SYSTEMERROR,1,0,0>
+ pop es
+ popa
+@@:
+
+if kdebug
+ mov es, ax
+ mov ax, es:[bx+2]
+ mov bx, es:[bx]
+ krDebugOut DEB_ERROR, "Fault detected - handled by %AX2 #AX:#BX"
+endif
+
+ jmp HandleFault_Exit
+
+We_Can_Handle_It:
+ sub sp, UAE_STRING_LEN ; Room for string
+ mov si, sp
+
+ cCall FormatFaultString,<ss,si,[bp].fsf_msg,[bp].fsf_faulting_CS,[bp].fsf_faulting_IP>
+
+ push bp
+ xor bp,bp ; Some people are picky...
+ cCall Display_Box_of_Doom,<0,ss,si>
+ pop bp
+
+ add sp, UAE_STRING_LEN
+
+ or ax, ax
+ jne @F
+ INT3_DEBUG ; Failed call - no USER
+@@:
+ cmp ax, 1 ; Button 1 (Cancel) pressed?
+ jne @F
+ jmp Set_GO_BP
+@@:
+
+ cmp fBooting, 1 ; No, they said to Nuke app.
+ je no_signal_proc
+
+ mov ds, curTDB
+
+ UnSetKernelDS
+
+ cmp ds:[TDB_USignalProc].sel,0
+ jz no_signal_proc
+ mov bx,0666h
+ mov di, -1
+
+ cCall ds:[TDB_USignalProc],<ds,bx,di,ds:[TDB_Module],ds:[TDB_Queue]>
+
+;
+; Since we are on a nice big fat juicy fault handler stack now, we can call
+; Windows to clean up after the task.
+;
+ mov bx,SG_EXIT
+ cCall ds:[TDB_USignalProc],<ds,bx,di,ds:[TDB_Module],ds:[TDB_Queue]>
+ mov ds:[TDB_USignalProc].sel,0
+
+no_signal_proc:
+
+ mov [bp].fsf_SP,dataOffset gmove_stack
+ mov [bp].fsf_SS,seg gmove_stack
+ mov [bp].fsf_faulting_CS,cs
+
+ lea ax,KillApp
+ mov [bp].fsf_faulting_IP,ax
+HandleFault_Exit:
+ ret
+
+HandleFault endp
+
+; ------------------------------------------------------------------
+;
+; ExceptionHandlerProc -- Common entry point for exception handlers
+;
+; ------------------------------------------------------------------
+ public ExceptionHandlerProc
+ExceptionHandlerProc proc far
+
+ push bp
+ mov bp,sp
+ pusha
+ push ds
+ SetKernelDS
+ push es
+EH_Popup:
+ call FaultFilter
+EH_Chain:
+ pop es
+ pop ds
+ UnsetKernelDS
+ popa
+ pop bp
+ add sp,2 ; remove message from stack
+ retf ; chain to prev handler
+EH_ret:
+ pop es
+ pop ds
+ popa
+ pop bp
+ add sp,fsf_OFFSET
+ retf
+
+ExceptionHandlerProc endp
+
+
+; ------------------------------------------------------------------
+;
+; This macro sets up the stack frame for entry to the generic
+; exception handler.
+;
+; ------------------------------------------------------------------
+ExceptionHandlerPrologue macro name,msg,chain
+ public name
+name:
+if ROM
+ sub sp,6
+ push bp
+ push ds
+ push ax
+ mov bp,sp
+ SetKernelDS
+ mov word ptr [bp+6],offset msg
+ mov ax, word ptr [chain][0]
+ mov [bp+8],ax
+ mov ax, word ptr [chain][2]
+ mov [bp+10],ax
+ UnsetKernelDS
+ pop ax
+ pop ds
+ pop bp
+else
+ push word ptr chain + 2
+ push word ptr chain
+ push offset msg
+endif
+endm
+
+; ------------------------------------------------------------------
+;
+; This macro sets up the stack frame, then jumps to the generic
+; exception handler.
+;
+; ------------------------------------------------------------------
+ExceptionHandler macro name,msg,chain
+ ExceptionHandlerPrologue name,msg,chain
+ jmp ExceptionHandlerProc
+ assumes ds, nothing
+ assumes es, nothing
+endm
+
+; ------------------------------------------------------------------
+;
+; Four fatal ones.
+;
+; ------------------------------------------------------------------
+ ExceptionHandler StackFault,szSF,prevInt0Cproc
+ ExceptionHandler GPFault,szGP,prevInt0Dproc
+ ExceptionHandler invalid_op_code_exception,szII,prevIntx6proc
+ ExceptionHandler page_fault,szPF,prevInt0Eproc
+ ExceptionHandler LoadSegFailed,szLoad,prevInt3Fproc
+
+; ------------------------------------------------------------------
+;
+; The not present fault is used to demand-load segments from newexe
+; files. If we find out that something bogus has happened, then
+; we just jump into the fault handler.
+;
+; ------------------------------------------------------------------
+ ExceptionHandlerPrologue SegmentNotPresentFault,szNP,prevInt3Fproc
+
+ push bp
+ mov bp,sp
+ pusha
+ push ds
+ SetKernelDS
+ push es
+
+ mov al,byte ptr [bp].fsf_faulting_CS
+ and al, SEG_RING_MASK ; Check it was Ring 1, LDT
+ cmp al, SEG_RING
+
+ je @F
+ jmp EH_Chain
+@@:
+ mov al,byte ptr [bp].fsf_err_code
+ test al, SEL_LDT ; Check it was LDT
+
+ jne @F
+ jmp EH_Chain
+@@:
+
+if KDEBUG
+ test byte ptr [bp].fsf_flags+1,2 ; IF set in faulting frame?
+ jnz @F
+ Trace_Out "Segment not present fault with interrupts disabled!"
+@@:
+endif
+ FSTI
+;
+; Don't discard the segment that we have to return to!!!
+;
+ cCall GlobalHandleNorip,<[bp].fsf_faulting_CS>
+ test cl,GA_DISCARDABLE
+ jz @F
+ cCall GlobalLRUNewest,<ax>
+@@:
+
+ mov bx,[bp].fsf_err_code
+seg_reload:
+ and bx, NOT 7h ; get the not present selector
+ or bl, SEG_RING ; Correct RING bits
+if KDEBUG
+ mov INT3Fcs, bx ; Save in case of error
+endif
+
+if PMODE32
+; On WOW we don't copy the owner to the real LDT since it is slow to call
+; the NT Kernel, so we read our copy of it directly.
+; see set_discarded_sel_owner mattfe mar 23 93
+
+ mov es,cs:gdtdsc
+ mov cx,bx ; save bx
+ and bl, not 7
+ mov es,es:[bx].dsc_owner
+ mov bx,cx ; restore
+else
+ lsl cx, bx ; mov es,[bx].he_owner
+ mov es, cx
+endif
+ StoH bl ; Need handle
+
+ cmp es:[ne_magic],NEMAGIC ; If owner is not a module
+ jnz bad_seg_load ; (i.e., an instance or garbage)
+ ; get out of here.
+ mov di,es:[ne_segtab]
+ mov ax,1
+ mov cx, es:[ne_cseg]
+ jcxz bad_seg_load
+dorten:
+ cmp es:[di].ns_handle,bx
+ jz got_seg_no
+ add di,SIZE NEW_SEG1
+ inc ax
+ loop dorten
+
+; Stupid program has referenced garbage...
+
+bad_seg_load:
+ jmp EH_Popup
+
+got_seg_no:
+
+;
+; If we already are on the exception handler stack, then we want to make
+; sure that we don't overwrite the original stack frame. Copy our
+; stack frame variables down by the difference between SP and SP before
+; we got called.
+;
+ push ax
+ mov ax,ss
+ cmp ax,word ptr [bp].fsf_SS
+ pop ax
+ jne stack_OK
+ push ax
+ push bx
+ push bp
+ lea bp,word ptr [bp].fsf_SS
+ mov ax,sp
+ dec ax
+ dec ax
+@@:
+ push word ptr [bp]
+ dec bp
+ dec bp
+ cmp bp,ax
+ jne @B
+ pop bp
+ pop bx
+ pop ax
+;
+; Figured out what this was supposed to be by tracing up to here
+; in the debugger.
+;
+ sub bp,32h
+
+stack_OK:
+ push es
+ mov bx,ax
+ UnsetKernelDS
+ mov ax,ss
+ mov ds,ax
+ les di,dword ptr [bp].fsf_SP
+ dec di
+ dec di
+ std
+;
+; Push an IRET frame on the faulting stack.
+;
+ lea si,[bp].fsf_flags
+ mov cx,3
+ rep movsw
+;
+; Push our saved registers on the faulting stack.
+;
+ lea si,[bp]
+ mov cx,11 ; BP + PUSHA + ES + DS
+ rep movsw
+
+ pop ax
+;
+; Push arguments to LoadSegment on the faulting stack.
+;
+ stosw ; hExe
+ mov ax,bx
+ stosw ; segno
+ mov ax,-1
+ stosw
+ stosw
+ inc di
+ inc di
+;
+; Point the faulting stack at the new location.
+;
+ mov [bp].fsf_SP,di
+;
+; Tell DPMI to return to us instead of the faulting code.
+;
+ mov [bp].fsf_faulting_CS,cs
+ mov [bp].fsf_faulting_IP,offset let_them_do_it
+ lea sp,[bp].fsf_ret_IP
+
+if kdebug
+ SetKernelDS
+ mov wFaultSegNo, bx
+ UnSetKernelDS
+endif
+ retf
+let_them_do_it:
+ SetKernelDS
+
+ xor cx, cx ; we try to keep a selector reserved
+ xchg cx, DemandLoadSel ; for scratch use while demand
+ jcxz @f ; loading segments--free it to make
+ cCall IFreeSelector,<cx> ; it available now
+@@:
+ cCall LoadSegment
+
+ push ax ; reserve a selector for the next
+ cCall AllocSelector,<0> ; time we demand load a segment
+ mov DemandLoadSel, ax
+ pop cx ; LoadSegment result
+ jcxz SegLoaderFailure
+
+if kdebug
+ push bx
+ mov bx, wFaultSegNo
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "Demand load %CX2(#bx) on %SS2"
+ pop bx
+endif
+ pop es
+ pop ds
+ UnsetKernelDS
+ popa
+ pop bp
+
+ ;** Check to see if we're about to restart an instruction in
+ ;** a not present segment. This would only occur if the
+ ;** segment was discarded because of the segment load we
+ ;** just did.
+IF KDEBUG
+ push bp ;Make a stack frame
+ mov bp,sp
+ push ax
+ mov bp,[bp + 4] ;Get the CS
+ lar ax,bp ;See if the CS is valid
+ test ax,8000h ;Is it present?
+ jnz @F ;Yes, don't complain
+ mov ax,bp
+ Trace_Out <'LDINT: Trying to restart discarded caller (#AX)'>
+@@:
+ pop ax
+ pop bp
+ENDIF
+ iret
+
+ public SegLoaderFailure
+SegLoaderFailure proc near
+;
+; Stupid segment loader was unable to load the segment!!!
+; Restore all the registers, create a fake DPMI frame, then
+; complain about the problem. Lets the user break into the
+; debugger, if installed, on Cancel. Creating and destroying
+; the fake DPMI frame is inconvenient and messy, but it lets
+; us handle the problem in common fault code.
+;
+ pop es
+ pop ds
+ UnsetKernelDS
+ popa
+
+ sub sp,4
+ mov bp,sp ; BP -> xx xx BP IP CS FL
+ push word ptr [bp+4] ; push app's BP
+ push ax ; get a temporary register
+ mov ax,[bp+6] ; IP
+ mov [bp+2],ax
+ mov ax,[bp+8] ; CS
+ mov [bp+4],ax
+ mov ax,[bp+10] ; Flags
+ mov [bp+6],ax
+ mov [bp+10],ss
+ lea ax,[bp+12]
+ mov [bp+8],ax
+ pop ax
+ pop bp
+
+ call far ptr LoadSegFailed ; BP -> RETIP RETCS EC IP CS FL SP SS
+
+ push bp
+ mov bp,sp ; BP -> BP EC IP CS FL SP SS
+ mov [bp+2],ax
+ mov ax,[bp+8] ; Flags
+ mov [bp+12],ax
+ mov ax,[bp+6] ; CS
+ mov [bp+10],ax
+ mov ax,[bp+4] ; IP
+ mov [bp+8],ax
+ pop bp
+ pop ax
+ add sp,4
+ iret
+
+SegLoaderFailure endp
+
+;ENDIF
+
+;-----------------------------------------------------------------------;
+; default_sig_handler
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Wed 10-Jan-1990 22:32:34 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc default_sig_handler,<PUBLIC,FAR>
+
+cBegin nogen
+
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+;
+; Panic -- Called by ToolHelp when it gets a bad stack fault or any
+; other fault with SP suspiciously low.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Panic,<PUBLIC,NEAR>
+cBegin
+if KDEBUG
+ Trace_Out "KERNEL: Panic called!!!"
+endif
+ int 1
+ jmp KillApp
+cEnd
+
+;-----------------------------------------------------------------------;
+; DoSignal
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Wed 10-Jan-1990 22:52:52 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DoSignal,<PUBLIC,FAR>,<ax,bx,cx,dx,di,si,es>
+cBegin
+ SetKernelDS
+ cmp pUserGetFocus.sel,0 ; is there a USER yet?
+ jz ds_exit
+ call pUserGetFocus
+ or ax,ax
+ jz ds_exit
+ mov si,ax
+ cCall pUserIsWindow,<ax>
+ or ax,ax
+ jz ds_exit
+ cCall pUserGetWinTask,<si>
+ mov ds,ax
+ TDB_check_DS
+ cmp ds:[TDB_SigAction],2 ; send it on?
+ jnz ds_exit
+ mov ax,1
+ xor bx,bx
+ cCall ds:[bx].TDB_ASignalProc,<bx,ax>
+ds_exit:
+
+cEnd
+
+
+
+sEnd CODE
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+externNP MISCMapDStoDATA
+
+
+;-----------------------------------------------------------------------;
+; SetSigHandler
+;
+; SetSigHandler notifies Windows of a handler for a signal.
+; It may also be used to ignore a signal or install a default
+; action for a signal.
+;
+; Entry:
+; parmD lpprocRoutine Signal handler
+; parmD lpDPrevAddress Previous handler (returned)
+; parmD lpWPrevAction Previous action (returned)
+; parmW Action Indicate request type
+; parmW SigNumber Signal number of interest
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 25-Dec-1989 00:36:01 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SetSigHandler,<PUBLIC,FAR>,<di,si,ds>
+
+ parmD lpprocRoutine
+ parmD lpDPrevAddress
+ parmD lpWPrevAction
+ parmW Action
+ parmW SigNumber
+cBegin
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ cmp SigNumber,1 ; is it SIGINTR?
+ jnz dssh_return_success ; ignore if not
+
+ cmp Action,4 ; is it reset Signal?
+ jz @F
+
+ push ds
+ mov ds,curTDB
+ assumes ds,nothing
+ mov ax,Action
+ xchg ax,ds:[TDB_SigAction]
+ les bx,lpWPrevAction
+ mov cx,es
+ or cx,bx
+ jz @F
+ mov es:[bx],ax
+@@:
+ mov dx,lpprocRoutine.sel
+ mov ax,lpprocRoutine.off
+ cmp Action,0 ; put in default handler?
+ jnz ssg_stick_it_in
+ mov dx,SEG default_sig_handler
+ mov ax,codeOffset default_sig_handler
+ssg_stick_it_in:
+ xchg dx,ds:[TDB_ASignalProc].sel
+ xchg ax,ds:[TDB_ASignalProc].off
+ cmp Action,4 ; is it reset Signal?
+ jz @F
+ les bx,lpDPrevAddress
+ mov cx,es
+ or cx,bx
+ jz @F
+ mov es:[bx].sel,dx
+ mov es:[bx].off,ax
+ pop ds
+@@:
+
+dssh_return_success:
+ xor ax,ax ; return success
+
+dssh_exit:
+
+cEnd
+
+;----------------------------------------------------------------------------
+;
+; SwapRecording(Flag)
+;
+; Flag = 0 => Stop recording
+; = 1 => Start recording only Swaps, Discards and Returns
+; = 2 => Start recording Calls in addition to Swaps, Discards and
+; returns.
+; Destroys AL register
+;----------------------------------------------------------------------------
+
+; Retail Version
+
+cProc ISwapRecording,<PUBLIC, FAR>
+; parmW Flag
+cBegin nogen
+ retf 2
+cEnd nogen
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldopen.asm b/private/mvdm/wow16/kernel31/ldopen.asm
new file mode 100644
index 000000000..fad2f9216
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldopen.asm
@@ -0,0 +1,2298 @@
+ TITLE LDOPEN - Open and Delete Pathname primitives
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include pdb.inc
+.list
+
+externFP AnsiUpper
+externFP Int21Handler
+externFP <lstrcpy>
+ifdef DBCS
+externFP FarMyIsDBCSLeadByte
+externFP FarMyIsDBCSTrailByte
+endif
+ifdef WOW
+externFP GetDriveType
+endif
+
+;** Equates for the Directory Table code
+DT_CURDIR EQU 1
+DT_WINDIR EQU 2
+ifndef WOW
+DT_SYSDIR EQU 3
+DT_APPDIR EQU 4
+MAX_SEARCH EQU 4
+else
+DT_SYS16DIR EQU 3
+DT_SYSDIR EQU 4
+DT_SYSWX86DIR EQU 5
+DT_APPDIR EQU 6
+MAX_SEARCH EQU 6
+endif
+
+
+DataBegin
+
+externB fInt21
+externB OutBuf
+externB szCannotFind1
+externB szCannotFind2
+externB szDiskCap
+externB LastDriveSwapped
+externB fNovell
+externB fBooting
+externW bufpos
+externW cBytesWinDir
+externW cBytesSysDir
+externW TopPDB
+externW curTDB
+externD lpWindowsDir
+externD lpSystemDir
+externD pSysProc
+externD pKeyProc
+externD pKeyProc1
+externD pSErrProc
+externW wMyOpenFileReent
+
+;** These variables needed to implement the app dir searching
+externW loadTDB
+externW fLMDepth
+
+staticW myofint24,0
+
+ifdef WOW
+externD lpSystem16Dir
+externW cBytesSys16Dir
+externD lpSystemWx86Dir
+externW cBytesSysWx86Dir
+endif
+
+;** Directory table for different search orders. Pgm Management-aware!!
+
+; DIRTABLE struc holds pointers to previously searched paths so we don't
+; repeat the path searches
+DIRTABLE STRUC
+dt_lpstr DD ?
+dt_wLen DW ?
+DIRTABLE ENDS
+
+dtDirTable LABEL DWORD
+ public dtDirTable
+
+ DB (SIZE DIRTABLE) * MAX_SEARCH DUP (0)
+
+; These tables drive the search order loops, determining which paths
+; to search in which order. The DOS/Novell path is always searched
+; last.
+
+BootOrder LABEL BYTE
+ DB DT_SYSDIR
+ DB DT_WINDIR
+ DB 0
+DefaultOrder LABEL BYTE
+ DB DT_CURDIR
+ DB DT_WINDIR
+ifdef WOW ; Search 16-bit system dir (\windir\system)
+ DB DT_SYS16DIR
+endif
+ DB DT_SYSDIR
+ifdef WOW ; Search Wx86 system dir (\windir\system32\Wx86)
+ DB DT_SYSWX86DIR
+endif
+ DB DT_APPDIR
+ DB 0
+ public BootOrder, DefaultOrder
+
+ ;** Static variables
+szCurDir DB 128 DUP (0) ;Points to fully qualified current dir
+pCurDirName DW 0 ;Points to 8.3 filename
+wCurDirLen DW 0 ;Length of path minus 8.3 filename
+ public pCurDirName, wCurDirLen, szCurDir
+
+ifdef WOW
+LastOFSearchEntry DW 0 ;Addr of last search table entry used
+ ;for continuing the search.
+OFContinueSearch DW 0 ;1 means continue last search
+ public LastOFSearchEntry, OFContinueSearch
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MyUpper
+externNP PathDrvDSDX
+externNP real_DOS
+
+ifdef DBCS
+externNP MyIsDBCSLeadByte
+externNP MyIsDBCSTrailByte
+endif
+
+; These constants are the same as the OF_* values, but are a single byte
+; for efficiency
+fReOpen equ 10000000b
+fExist equ 01000000b
+fPrompt equ 00100000b
+fCreate equ 00010000b
+fCancel equ 00001000b
+fVerify equ 00000100b
+fSearch equ 00000100b
+fDelete equ 00000010b
+fParse equ 00000001b
+
+;** Flags to InternalOpenFile
+IOF_SYSTEM EQU 1
+
+;!!!!!! Everything from here to the next !!!!! rewritten Aug 2-5 1991 [jont]
+
+;-----------------------------------------------------------------------;
+; OpenFile
+; ;
+; OpenFile: Opens the given file (with LOTS of options) ;
+; The search order is defined above in the data section and is ;
+; table-driven. ;
+; ;
+; Arguments: ;
+; ParmD lpstrSourceName ;
+; ParmD lpOFStruct ;
+; ParmW Command ;
+; ;
+; Returns: ;
+; AX = file handle ;
+; ;
+; Error Returns: ;
+; AX = error code ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Oct 12, 1987 09:06:05p -by- David N. Weise [davidw] ;
+; Added this nifty coment block. ;
+; ;
+; August 5, 1991 -by- Jon Thomason [jont] ;
+; Rewrote large sections. Made it table-driven to allow ;
+; changing search paths. Made it return extended error codes ;
+; for all file not found errors. Generally made it into a ;
+; humanly-readable module. ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+cProc IOpenFile, <PUBLIC,FAR>, <si,di,ds>
+ parmD lpSrcFile ;String pointing to filename
+ parmD lpOFStruct ;Points to OFSTRUCT
+ parmW wFlags ;LowB is DOS flags, High is OF flags
+ localD lpDestDir ;Points to dest dir in OFSTRUCT
+cBegin
+ SetKernelDS
+
+ ;** If the file is to be reopened, do it
+ test BYTE PTR wFlags[1],fReopen ;Reopen file?
+ jz IOF_NoReopen ;No
+ les di,lpOFStruct ;Point to structure
+ cCall ReOpenFile, <es,di,wFlags> ;Reopen the file
+ jmp IOF_End ;Done
+IOF_NoReopen:
+
+ifdef WOW
+ ; Reset LastOFSearchEntry if we're not continuing an earlier search
+ cmp OFContinueSearch,0
+ jne @F
+ mov LastOFSearchEntry,0
+@@:
+endif
+
+ ;** Get a pointer into the OFSTRUCT
+ mov di,WORD PTR lpOFStruct[0] ;Point to structure
+ lea di,[di].opFile ;Point to string
+ mov WORD PTR lpDestDir[0],di ;Save in temp variable
+ mov di,WORD PTR lpOFStruct[2] ;Get the selector
+ mov WORD PTR lpDestDir[2],di
+
+
+ ;** Parse the filename and prepare for searching
+ mov bx,dataOFFSET szCurDir ;Point to dest string
+ les si,lpSrcFile ;Point to source string
+if 0
+ krDebugOut DEB_WARN,"WOW16 IOpenFile:Filename @ES:SI"
+endif
+ cCall ParseFileName, <es,si,ds,bx,wFlags>
+
+ ;** Check for error
+ or ax,ax ;Error?
+ jnz @F ;No
+
+ mov ax,0 ;Flag that this is a parse error
+ mov bx,dataOFFSET szCurDir ;pass lpSrcFile as error string
+ cCall ErrorReturn, <lpOFStruct,ds,bx,lpSrcFile,wFlags,ax>
+ jmp IOF_End ;Get out
+@@:
+ ;** If they just wanted to parse, fill in the structure and return
+ test BYTE PTR wFlags[1],fParse ;Parse only?
+ jz @F ;No, skip this
+ mov bx,dataOFFSET szCurDir ;Point to full pathname with DX:BX
+ mov dx,ds
+ xor ax,ax ;No file handle
+ jmp IOF_DoCopy ;Mimic successful file open
+@@:
+ ;** Save return values for future use
+ mov pCurDirName,bx ;Points to 8.3 name
+ mov wCurDirLen,cx ;Length of path portion
+
+ ;** See if we should path search (flag returned in DX)
+ or dx,dx
+ jz IOF_InitSearch ;Do the search
+
+ ;** Try to open the file without searching any other dirs
+ les bx,lpDestDir ;Point to dest dir
+ mov di,dataOFFSET dtDirTable ;Point to the start of the DirTable
+ cCall GetPath, <DT_CURDIR,di,es,bx> ;Dest dir returned in ES:BX
+ cCall OpenCall, <es,bx,wFlags> ;Try to open it
+ jc @F
+ jmp IOF_Success
+@@: jmp IOF_Error ;File found but problem opening
+
+ ;** Point to the proper search order
+IOF_InitSearch:
+ SetKernelDS
+ifdef WOW
+ cmp OFContinueSearch,0
+ je @F
+ mov OFContinueSearch,0 ;consumed the flag, reset it
+ mov si,LastOFSearchEntry
+ or si,si ;Were we searching at all?
+ jnz IOF_WereSearching ;Yes
+ jmp short IOF_FileNotFound ;No searching, so give up now.
+IOF_WereSearching:
+ cmp si,-1 ;Already tried SearchPath?
+ jne IOF_RestartSearch ;No, pick up where we left off in order
+IOF_FileNotFound:
+ mov ax,2 ;SearchPath found it last time, so
+ jmp IOF_Error ;it won't find a different one this
+ ;time, se we return File not found
+IOF_RestartSearch:
+ inc si
+ mov LastOFSearchEntry,si
+ mov al,[si]
+ cbw
+ or al,al
+ mov di,dataOFFSET dtDirTable;Point to the start of the DirTable
+ jnz IOF_SearchLoop ;Pick up with next in search order
+ jmp short IOF_SearchPath ;Restarting after last in search
+ ;order, so try DOS/Novell path.
+@@:
+endif
+ mov si,dataOFFSET DefaultOrder
+ cmp fBooting,0 ;Booting?
+ jz IOF_DoSearch ;No
+ mov si,dataOFFSET BootOrder
+IOF_DoSearch:
+ifdef WOW
+ mov LastOFSearchEntry,si
+endif
+ mov al,[si] ;Get the first search code
+ cbw
+ mov di,dataOFFSET dtDirTable ;Point to the start of the DirTable
+
+ ;** Loop through until we have no more directories to search or
+ ;** until the file is found
+IOF_SearchLoop:
+
+ ;** Get the path and filename for this index entry
+ les bx,lpDestDir ;Point to dest dir
+ cCall GetPath, <ax,di,es,bx> ;Returns pointer to dest dir in ES:BX
+ or bx,bx ;Duplicate dir?
+ jz IOF_Continue ;Yes, skip this
+
+ ;** Try to open the file
+ cCall OpenCall, <es,bx,wFlags> ;Try to open it
+ jnc IOF_Success ;File was found
+ cmp ax,3 ;Errors 3 or less mean file not found
+ ja IOF_Error ;File found but problem opening
+
+ ;** File not found, so try next path if any
+IOF_Continue:
+ add di,SIZE DIRTABLE ;Bump to next DirTable entry
+ inc si ;Bump to next code in list
+ifdef WOW
+ mov LastOFSearchEntry,si
+endif
+ mov al,[si] ;Get this code
+ cbw ;Make it a WORD
+ or al,al ;Done?
+ jnz IOF_SearchLoop ;No
+
+ ;** Try the DOS/Novell path next
+ifdef WOW
+IOF_SearchPath:
+ xor si,si
+ dec si
+ mov LastOFSearchEntry,si
+endif
+ les di,lpDestDir ;Point to the dest dir
+ mov si,pCurDirName ;Point to the 8.3 name
+ cCall SearchFullPath, <ds,si,es,di,wFlags>
+ jc IOF_Error ;Not found here either
+
+ ;** On SUCCESS, we come here. Delete the file and close if
+ ;** necessary
+IOF_Success:
+ mov bx,WORD PTR lpDestDir[0] ;Point to filename with DX:BX
+ mov dx,WORD PTR lpDestDir[2]
+IOF_DoCopy:
+ les si,lpOFStruct ;Point to OFSTRUCT
+ cCall SuccessCleanup, <dx,bx,es,si,wFlags,ax> ;Finish up
+ jmp SHORT IOF_End
+
+ ;** On ERROR, complete the structure and return the error code
+IOF_Error:
+ les si,lpOFStruct
+ mov bx,dataOFFSET szCurDir ;Point to current dir
+ cCall ErrorReturn, <es,si,ds,bx,ds,pCurDirName,wFlags,ax>
+IOF_End:
+
+cEnd
+
+
+;---------------------------------------------------------------------------
+; ReOpenFile
+;
+; Does a fast reopen of a file that has already been opened.
+; Returns proper value in AX for return from OpenFile
+;
+; Trashes everything but si,di,ds
+;
+;---------------------------------------------------------------------------
+
+cProc ReOpenFile, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpStruct ;LPOFSTRUCT parameter
+ parmW wFlags ;OpenFile flags
+ localW hFile
+cBegin
+ ;** Set up for the reopen
+ lds si,lpStruct ;Point to the OFSTRUCT
+ lea dx,[si].opFile ;DS:DX -> path
+ call PathDrvDSDX ;Make sure DRV letter is valid
+ jc ROF_SetDrvErr
+
+ ;** Set up for either an OPEN or a CREATE
+ mov al,BYTE PTR wFlags[0] ;Get the access bits
+ test BYTE PTR wFlags[1],fCreate ;Create file or open
+ jnz ROF_CreateIt ;In create case, we just do it
+ mov ah,3dh ;Open file call
+ jmp SHORT @F
+ROF_CreateIt:
+ mov ah,3ch ;Create file call
+@@: xor cx,cx ;Default file attributes
+ call real_DOS ;Skip overhead of Int21Handler
+ jnc ROF_10 ;Continue on no error
+ jmp SHORT ROF_GetError ;Get out on error
+
+ROF_SetDrvErr:
+ lds si,lpStruct ;Point to the OFSTRUCT
+ mov [si].opXtra,ax ;In OFSTRUCT, this is the error code
+ mov ax,-1 ;Error return
+ jmp ROF_End ;Error
+
+ROF_10: mov bx,ax ;Get handle
+ mov hFile,ax ;Save handle for later
+ifdef WOW
+ xor cx,cx
+ xor dx,dx
+ push ds
+ SetKernelDS ds
+ cmp fLMdepth,cx ; Called From Loader ?
+ pop ds
+ UnSetKernelDS ds
+ jnz @f ; Yes -> Ignore Date/Time
+endif
+ mov ax,5700h ;Get time and date of file
+ DOSCALL
+@@:
+ mov ax,bx ;Put file handle back in ax
+ test BYTE PTR wFlags[1],fVerify ;Should we test time/date?
+ jz ROF_VerifyOK
+ cmp [si].opDate,dx ;Same date as original?
+ jnz ROF_ErrorClose ;No
+ cmp [si].opTime,cx ;Same time as original?
+ jnz ROF_ErrorClose ;No
+ROF_VerifyOK:
+ mov es:[si].opTime,cx ;Save the date and time
+ mov es:[si].opDate,dx
+
+ ;** See if we were supposed to just get the name, or find file
+ test BYTE PTR wFlags[1],fDelete or fExist
+ jz ROF_Done ;Nope, we're done
+
+ ;** If the user specified OF_DELETE, we don't want
+ ;** the file open, so close it here.
+ ;** NOTE: THIS CODE IS DUPLICATED IN FillOFStruct()!!!!
+ mov bx,hFile ;Get handle
+ mov ah,3Eh ;Close the file
+ DOSCALL
+
+ ;** See if we should delete the file
+ test BYTE PTR wFlags[1],fDelete
+ jz ROF_Done ;Nope, we're done
+ smov ds,es ;DS:DX points to full pathname
+ UnSetKernelDS
+ lea dx,[si].opFile
+ mov ah,41h ;Delete the file
+ DOSCALL
+ jnc ROF_Done ;Return the file handle for compat.
+
+ ;** Get extended error always
+ROF_GetError:
+ mov ah,59h ;See if there is an extended error
+ xor bx,bx
+ push bp ;GetExtendedError trashes regs
+ push si
+ push es
+ DOSCALL
+ pop es
+ pop si
+ pop bp
+ mov [si].opXtra,ax ;In OFSTRUCT, this is the error code
+ mov ax,-1 ;Error return
+ jmp SHORT ROF_End
+
+ROF_ErrorClose:
+ mov bx,hFile ;Get the file handle
+ mov ah,3Eh ;Close the bogus file
+ DOSCALL
+ mov ax,-1 ;Error return value
+ lds si,lpStruct ;Point to the OFSTRUCT
+ mov [si].opXtra,0 ;Non-DOS error
+ jmp SHORT ROF_End ;Get out
+
+ROF_Done:
+ mov ax,hFile ;Proper return value for OpenFile
+ROF_End:
+cEnd
+
+
+;----------------------------------------------------------------------------
+; ParseFileName
+;
+; Prepares to do the various file searches by returning a pointer
+; to the fully qualified path and to the "pure" filename
+; (just the 8.3 name).
+;
+; Returns:
+; AX = TRUE/FALSE function successful (if F, nothing else valid)
+; BX points to start of 8.3 filename
+; CX = Length of path portion of filename
+; DX = TRUE/FALSE: Indicates whether path should be searched
+;
+;----------------------------------------------------------------------------
+
+cProc ParseFileName, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpSrcName ;Passed in pathname
+ parmD lpDestName ;String to receive pathname
+ parmW wFlags ;Command WORD to OpenFile
+ localW wPathLen ;Length of path portion of filename
+cBegin
+ ;** Get the fully qualified pathname in lpDestName
+ lds si,lpSrcName ;DS:SI points to source file
+ les di,lpDestName ;ES:DI points to file buffer
+ call ParseFile ;Form a complete name in buffer
+ ; Returns dir len in CX when failing
+ or ax,ax ;Successful?
+ jz PFN_End ;No, get out
+ mov wPathLen,dx ;Save length of path (no 8.3)
+
+ ;** This section handles the fSearch flag. This flag is used to
+ ;** do a path search even when we have a path in front of
+ ;** the filename.
+ test BYTE PTR wFlags[1],fSearch ;Do search even with path?
+ jz PF_NoSearch ;No.
+ xor di,di ;Indicate no slashes
+PF_NoSearch:
+
+ ;** Convert the filename to OEM
+ lds si,lpDestName ;Point to full path
+ cCall MyAnsiToOem,<ds,si,ds,si>
+
+ ;** Return arguments
+ mov ax,1 ;Success
+ mov bx,WORD PTR lpDestName[0] ;Get the offset of the string
+ mov cx,wPathLen ;Length of path portion of name
+ add bx,cx ;Point to start of string
+ inc bx ;Skip slash
+ mov dx,di ;Slashes/path search flag
+
+PFN_End:
+cEnd
+
+
+;----------------------------------------------------------------------------
+; GetPointer
+;
+; Given an index number, returns a pointer to the path associated
+; with this index and its length
+;
+; Returns the lpstr in ES:BX, length in CX
+;
+; Depends on the order of the DT_* indices
+; Depends on Kernel's DS being set, does not trash it
+;
+;----------------------------------------------------------------------------
+
+cProc GetPointer, <PUBLIC,NEAR>, <si,di>
+ parmW wIndex ;Index is from search order table
+cBegin
+ CheckKernelDS
+ ReSetKernelDS
+
+ ;** Decode the index numbers
+ mov ax,wIndex ;Get the index
+ dec ax ;DT_CURDIR?
+ jz GT_CURDIR
+ dec ax ;DT_WINDIR?
+ jz GT_WINDIR
+ifndef WOW
+ dec ax ;DT_SYSDIR?
+ jz GT_SYSDIR
+else
+ dec ax ;DT_SYS16DIR?
+ jz GT_SYS16DIR
+ dec ax ;DT_SYSDIR?
+ jz GT_SYSDIR
+ dec ax ;DT_SYSWX86DIR?
+ jz GT_SYSWX86DIR
+endif
+ ; Must be DT_APPDIR
+
+ ;** Find the app's dir
+IF KDEBUG
+ cmp fBooting,0 ;Booting?
+ jz @F ;No, whew!
+ int 1 ;No app dir during boot process
+ int 1
+@@:
+ENDIF
+ ;** Figure out if we should use curTDB or loadTDB. This is
+ ;** determined by the number of times LoadModule has recursed.
+ ;** We only use the loadTDB pointer if we're in LoadModule the
+ ;** second time and the pointer is not zero. Otherwise, we
+ ;** use the curTDB pointer. If we don't do this check, we
+ ;** end up getting the path of the app calling LoadModule
+ cmp fLMDepth,2 ;In LoadModule 2 times?
+ jb GT_UseCurTDB ;Yes, use curTDB
+ mov ax,LoadTDB ;Get loadTDB
+ or ax,ax ;NULL?
+ jnz GT_UseLoadTDB ;No, assume it's OK
+
+ ;** Get a pointer to the path stored in the module database
+GT_UseCurTDB:
+ mov ax,curTDB ;Get the TDB pointer
+GT_UseLoadTDB:
+ mov es,ax ;Point with DS
+ mov es,es:[TDB_pModule] ;Point to the module database
+IFDEF ROM
+ ; if this is in ROM, then return 0 in CX
+ ; makes no sense to get the app's dir, if app is in ROM
+ test es:[ne_flags], NEMODINROM
+ jz @f
+ xor cx, cx
+ jmp SHORT GT_Done
+@@:
+ENDIF
+ mov di,es:[0ah] ;Points to EXE path string (sort of)
+ ; (High word of CRC in exe hdr)
+ ;** Copy the entire string into the buffer
+ add di,8 ;Move past data garbage
+ push di ;Save start of string
+ cCall GetPureName ;ES:DI points just after the '\'
+ dec di ;ES:DI points to '\'
+ pop bx ;ES:BX points to start of string
+ mov cx,di ;Compute length of path, not filename
+ sub cx,bx ; (not including \)
+ jmp SHORT GT_Done
+
+ ;** Get the current directory pointer and length
+GT_CURDIR:
+ smov es,ds ;ES:BX points to szCurDir
+ mov bx,dataOFFSET szCurDir
+ mov cx,wCurDirLen ;Get path length
+ jmp SHORT GT_Done
+
+GT_WINDIR:
+ les bx,lpWindowsDir ;Point to windir
+ mov cx,cBytesWinDir
+ jmp SHORT GT_Done
+
+GT_SYSDIR:
+ les bx,lpSystemDir ;Point to sysdir
+ mov cx,cBytesSysDir
+ifdef WOW
+ jmp SHORT GT_Done
+
+GT_SYS16DIR:
+ les bx,lpSystem16Dir ;Point to sys16dir
+ mov cx,cBytesSys16Dir
+ jmp SHORT GT_Done
+
+GT_SYSWX86DIR:
+ les bx,lpSystemWx86Dir
+ mov cx,cBytesSysWx86Dir
+ ;jmp SHORT GT_Done
+endif ;WOW
+
+GT_Done:
+
+cEnd
+
+
+;----------------------------------------------------------------------------
+; GetPath
+;
+; Gets the path associated with the given index. The 8.3 filename
+; is appended to the end of the path and this is copied into the
+; destination directory. A pointer to this directory is returned
+; in ES:BX or BX is NULL if the directory to be searched would be
+; a duplicate.
+;
+; Assumes (and does not trash) kernel's DS
+;
+; Calls: GetPointer
+;
+;----------------------------------------------------------------------------
+
+cProc GetPath, <PUBLIC,NEAR>, <si,di>
+ parmW wIndex ;Index from search order table
+ parmW pDirTable ;Points to current DIRTABLE entry
+ parmD lpDest ;Place to copy filename
+cBegin
+ CheckKernelDS
+
+ ;** Gets the pointer and length of the requested string
+ cCall GetPointer, <wIndex> ;lpstr in ES:BX, len in CX
+IFDEF ROM
+ or cx, cx ; if in ROM && APPDIR
+ jnz @f
+ xor bx, bx
+ jmp SHORT GP_End
+@@:
+ENDIF
+ ;** Save it in the table
+ mov di,pDirTable ;Point to the table entry
+ mov WORD PTR [di].dt_lpstr[0],bx
+ mov WORD PTR [di].dt_lpstr[2],es
+ mov [di].dt_wLen,cx
+
+ ;** Check for duplicates
+ mov si,bx ;Point to string with SI
+ mov bx,dataOFFSET dtDirTable ;Point to the start of the table
+GP_Loop:
+ cmp bx,di ;Checked everything before us yet?
+ je GP_Done ;Yes
+
+ ;** Compare the strings
+ cmp cx,[bx].dt_wLen ;Compare lengths
+ jne GP_Continue ;No dup here
+ mov dx,cx ;Save len in DX
+ push si
+ push di
+ push ds
+ les di,ds:[di].dt_lpstr ;Point to the strings to be compared
+ lds si,ds:[bx].dt_lpstr
+ repe cmpsb ;Compare the strings
+ pop ds
+ pop di
+ pop si
+ or cx,cx ;At end of string?
+ jz GP_FoundMatch ;Yes, we matched so ignore this string
+ mov cx,dx ;Get len back in CX
+GP_Continue:
+ add bx,SIZE DIRTABLE ;Bump to next table entry
+ jmp GP_Loop
+
+GP_FoundMatch:
+ mov WORD PTR [di].dt_lpstr[0],0 ;Null out this entry
+ mov WORD PTR [di].dt_lpstr[2],0
+ mov [di].dt_wLen,0
+ xor bx,bx ;Return NULL
+ jmp SHORT GP_End
+
+GP_Done:
+ ;** Copy the string in
+ push ds ;Save DS around this
+ lds si,[di].dt_lpstr ;Return ES:BX pointing to string
+ les di,lpDest ;Point to buffer to copy string to
+ mov bx,di ;Point with BX to struct
+ rep movsb ;Copy the strings
+ pop ds ;Restore KERNEL's DS
+
+ ;** Put a '\' only if needed
+IFDEF DBCS
+ push si
+ push di
+ mov si,word ptr lpDest[0] ;es:si -> string address
+ dec di ;di points to the last valid byte
+ call MyIsDBCSTrailByte ;the last byts a DBCS trailing byte?
+ pop di
+ pop si
+ jnc GP_DoSlash ;yes, go ahead to append a '\'
+ ;no, fall through
+ENDIF
+ cmp BYTE PTR es:[di - 1],'\';Terminating slash?
+ je GP_SkipSlash ;Yes
+ cmp BYTE PTR es:[di - 1],'/';Terminating slash?
+ je GP_SkipSlash ;Yes
+GP_DoSlash:
+ mov al,'\' ;Get the slash
+ stosb ; and write it
+GP_SkipSlash:
+
+ ;** Copy the filename
+ mov si,pCurDirName ;Point to the 8.3 filename
+ call strcpyreg
+;GP_83Loop:
+; lodsb ;Get the char
+; stosb ; and write it
+; or al,al ;Done?
+; jnz GP_83Loop ;Nope
+ ;Returns ES:BX points to filename
+GP_End:
+cEnd
+
+
+;----------------------------------------------------------------------------
+; OpenCall
+;
+; Does the open/create file call. The file is either opened
+; or created. The handle or the error code is returned.
+; The extended error code is returned only if the error was not
+; that the file or path was not found (errors 2 & 3).
+; Carry is set on error.
+;
+;----------------------------------------------------------------------------
+
+cProc OpenCall, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpString ;String to open
+ parmW wFlags ;OpenFile flags
+ localW wInt21AX ;Int 21 AX value
+cBegin
+ ;** HACK to allow SearchPath to use this call.
+ ;** If wFlags is -1, look for flags preset in AX
+ cmp wFlags,-1 ;wFlags?
+ jnz OC_Normal ;Yes, proceed normally
+ mov wInt21AX,ax ;Save these flags
+ jmp SHORT OC_10 ; and go on
+
+ ;** Set up for either an OPEN or a CREATE
+OC_Normal:
+ mov al,BYTE PTR wFlags[0] ;Get the access bits
+ test BYTE PTR wFlags[1],fCreate ;Create file or open
+ jnz OC_CreateIt ;In create case, we just do it
+ mov ah,3dh ;Open file call
+ mov wInt21AX,ax ;Save in temp var
+ jmp SHORT OC_10
+OC_CreateIt:
+ mov ah,3ch ;Create file call
+ and al,3 ;Strip incompatbile share bits, etc.
+ mov wInt21AX,ax ;Save it
+ jmp SHORT OC_DoDOSCall ;Just do it in create case
+
+OC_10: SetKernelDS
+ cmp fNovell,0 ;On Novell?
+ je OC_DoDOSCall ;No, just do normal stuff
+
+ ;** We do a Get Attribute call instead of trying to open the file
+ ;** because doing a normal file open on Novell causes them
+ ;** to search their entire path.
+ lds dx,lpString ;Get the pathname
+ mov ax,4300h ;Get file attributes
+ DOSCALL ;Does the file exist?
+ jc OC_NotThere ;No
+
+ ;** Try to open the file here. In case of Novell, we already know
+ ;** it's here, so now open it
+OC_DoDOSCall:
+ xor cx,cx ;Normal files ONLY!!
+ mov ax,wInt21AX ;Get function code + access flags
+ lds dx,lpString ;Get the pathname
+ DOSCALL ;Try to open the file
+ jc OC_NotThere ;File can't be opened
+ jmp SHORT OC_FileOpened ;Success
+
+OC_NotThere:
+ cmp ax,3 ;Errors 2 & 3 are file not found
+ jbe OC_NoExtError ;No extended error for file not found
+ SetKernelDS
+ cmp wMyOpenFileReent, 0 ;No ext err for MyOpenFile
+ jnz OC_NoExtError
+ mov ah,59h ;See if there is an extended error
+ xor bx,bx
+ push bp ;GetExtendedError trashes bp
+ DOSCALL
+ pop bp
+OC_NoExtError:
+ stc ;Return error
+
+OC_FileOpened: ;CY must be clear here on success
+
+cEnd
+
+
+;----------------------------------------------------------------------------
+; SearchFullPath
+;
+; Searches the full DOS/Novell path for the file
+;
+; Returns the file handle on success or the error code on failure
+; Carry set on error
+;
+;----------------------------------------------------------------------------
+
+cProc SearchFullPath, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpSource ;8.3 filename
+ parmD lpDest ;Place to copy pathname
+ parmW wFlags ;OpenFile flags
+ localW wInt21AX
+cBegin
+ ;** Get the AX WORD for the DOS call
+ mov al,BYTE PTR wFlags[0] ;Get the access bits
+ test BYTE PTR wFlags[1],fCreate ;Create file or open?
+ mov ah,3dh ;Default to open
+ jz @F
+ mov ah,3ch ;Create call
+@@: mov wInt21AX,ax ;Save it for later
+
+ ;** Use SearchPath() to find the file for us
+ push ds ;Save DS across this
+ les di,lpDest ;Point to usable dest buffer
+ lds si,lpSource ;Point to source string
+ UnsetKernelDS
+ cCall <FAR PTR SearchPath>,<ds,si,es,di,ax>
+ pop ds
+ ResetKernelDS
+ cmp ax,-1
+ jne SFP_FoundIt ;Found the file
+ mov ax,bx ;Get error code from SearchPath
+ cmp ax,3 ;Not found?
+ ja SFP_Error ;Found but error
+
+ ;** Now try the Novell path if it's there
+ cmp fNovell,0 ;On Novell?
+ je SFP_Error ;Nope. Nothing more to try so error
+ lds dx,lpSource ;Point to 8.3 filename
+ UnsetKernelDS
+ xor cx,cx ;Normal file type
+ mov ax,wInt21AX ;Get open or create call plus attrs
+ DOSCALL ;Do it
+ jc SFP_Error ;Didn't find it
+
+SFP_FoundIt:
+ clc
+ jmp SHORT SFP_End
+
+SFP_Error:
+ stc
+
+SFP_End: ;Carry should be set/clear correctly
+cEnd
+
+
+;----------------------------------------------------------------------------
+; SuccessCleanup
+;
+; Builds the OFSTRUCT structure on a successful open.
+; Closes and deletes file if requested.
+;
+;----------------------------------------------------------------------------
+
+cProc SuccessCleanup, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpGoodPathName ;Successful path name
+ parmD lpOFStruct ;OFSTRUCT param to OpenFile
+ parmW wFlags ;OpenFile flags
+ parmW hFile ;File handle
+cBegin
+ ;** Compute the length of the string and OFSTRUCT
+ les di,lpGoodPathName ;Point to the new pathname
+ xor al,al ;Get a zero byte
+ xor cx,cx ;Up to 64K
+ dec cx
+ repne scasb ;Search for the zero byte
+ neg cx
+ mov ax,cx ;Get a copy in AX
+ add ax,(SIZE OPENSTRUC) - 3 ;Length of structure including string
+
+ ;** Copy the successful pathname into the OFSTRUCT if necessary
+ dec cx ;This now is string + zero byte len
+ les di,lpOFStruct ;Point to dest buffer
+ lea di,[di].opFile
+ cmp di,WORD PTR lpGoodPathName[0] ;Offsets the same?
+ jne FOF_DoCopy ;No, do it
+ mov dx,es ;Compare sels
+ cmp dx,WORD PTR lpGoodPathName[2] ;Same?
+ je FOF_NoCopy ;Yes, no copy needed
+FOF_DoCopy:
+ lds si,lpGoodPathName ;Point to successful path again
+ UnSetKernelDS
+ rep movsb ;Copy it
+FOF_NoCopy:
+
+ ;** Fill out remainder of OFSTRUCT
+ les si,lpOFStruct ;Point to OFSTRUCT with ES:SI
+ lea di,[si].opFile ; and to the pathname with ES:DI
+ mov es:[si].opXtra,0 ;Zero the error
+ mov es:[si].opLen,al ;Save structure length
+ call AreBooting ;AreBooting checks Int21 hooks inst
+ mov ah,1 ;Always booting from hard drive
+ jz FO_NoCheckDrive ;Int 21 hooks NOT installed yet
+ mov al,es:[di] ;ES:DI points to string
+ or al,20H ;Force it lowercase
+ sub al,'a' ;Drive number, zero based
+ cbw
+ mov di,ax ;Drive number in DI
+ call IsFloppy ;Returns floppy status in ZF
+ mov ah,0 ;Zero in case it's a floppy
+ jz FO_NoCheckDrive ;Must be a floppy disk
+ inc ah ;Non-removable media
+FO_NoCheckDrive:
+ mov es:[si].opDisk,ah ;Tell 'em the type of disk
+ ;** Get the current file date and time
+ mov bx,hFile ;Get file handle
+ mov ax,5700h ;Get date and time
+ifdef WOW
+ xor cx,cx
+ xor dx,dx
+ push ds
+ SetKernelDS ds
+ cmp fLMdepth,cx ; Called From Loader ?
+ pop ds
+ UnSetKernelDS ds
+ jnz @f ; Yes -> Ignore Date/Time
+endif
+ DOSCALL
+@@:
+ mov es:[si].opTime,cx ;Save the date and time
+ mov es:[si].opDate,dx
+
+ ;** See if we were supposed to just get the name, or find file
+ test BYTE PTR wFlags[1],fExist OR fDelete
+ jz FO_Done ;Nope, we're done
+
+ ;** If the user specified OF_EXIST or OF_DELETE, we don't want
+ ;** the file open, so close it here
+ ;** NOTE: THIS CODE IS DUPLICATED IN ReopenFile()!!!!
+ mov bx,hFile ;Get the handle
+ mov ah,3Eh ;Close the file
+ DOSCALL
+ ;We leave the bogus value in hFile
+ ; for 3.0 compatibility
+
+ ;** If OF_DELETE is set, we simply delete the file
+ test BYTE PTR wFlags[1],fDelete
+ jz FO_Done
+ smov ds,es ;DS:DX points to full pathname
+ UnSetKernelDS
+ lea dx,[si].opFile
+ mov ah,41h ;Delete the file
+ DOSCALL
+ mov ax,1 ;TRUE return value
+ jnc FO_Done ;For 3.0 compatiblity
+
+ mov ah,59h ;See if there is an extended error
+ xor bx,bx
+ push bp ;GetExtendedError trashes regs
+ push si
+ DOSCALL
+ pop si
+ pop bp
+ mov [si].opXtra,ax ;In OFSTRUCT, this is the error code
+ mov ax,-1 ;Error return
+ jmp SHORT FO_END
+
+FO_Done:
+ mov ax,hFile ;Proper return value for OpenFile
+
+FO_End:
+cEnd
+
+
+;----------------------------------------------------------------------------
+; ErrorReturn
+;
+; Fills in the return information for error conditions.
+; Returns the proper return value for OpenFile
+;
+;----------------------------------------------------------------------------
+
+cProc ErrorReturn, <NEAR,PUBLIC>,<si,di,ds>
+ parmD lpOFStruct ;OFSTRUCT given to OpenFile
+ parmD lpPath ;Path returned, even when invalid
+ parmD lpError ;Text for error box
+ parmW wFlags ;OpenFile flags
+ parmW wErrCode ;Error code already computed
+cBegin
+ UnSetKernelDS
+ cmp wErrCode,0 ;Parse error?
+ jnz @F ;No
+ mov wErrCode,2 ;Mimic "File not found" error
+ jmp SHORT ER_ReturnError ;Never prompt on parse error
+@@: test BYTE PTR wFlags[1],fPrompt ;Should we do the dialog?
+ jz ER_ReturnError ;No, return error code
+ call AreBooting ;if we're still booting, don't prompt
+ jz ER_ReturnError
+ lds di,lpError
+ cmp BYTE PTR ds:[di],0 ;Don't prompt with NULL string.
+ je ER_ReturnError
+
+ cCall Prompt, <ds,di> ;Prompt with error string.
+
+ER_ReturnError:
+ SetKernelDS
+ les si,lpOFStruct ;Point to structure again
+ mov ax,wErrCode ;Get the error code
+ mov es:[si].opXtra,ax ;In OFSTRUCT, this is the error code
+ lea di,[si].opFile ;Point to dest string
+ lds si,lpPath ;Point to the path
+ call strcpyreg
+;ER_Copy:
+; lodsb ;Copy the sz string for PowerPoint
+; stosb
+; or al,al ;Done?
+; jnz ER_Copy ;No
+ UnSetKernelDS
+ mov ax,-1
+cEnd
+
+
+;!!!!!!!!!!!!!! Everything after this is old
+
+
+;---------------------------------------------------------------------------
+; AreBooting
+;
+; Check to see if DOS hook available
+;
+;---------------------------------------------------------------------------
+AreBooting PROC NEAR
+ push ds
+ SetKernelDS
+ cmp fInt21,0
+ pop ds
+ UnSetKernelDS
+ ret
+AreBooting ENDP
+
+;---------------------------------------------------------------------------
+; FarGetEnv
+;
+; Gets the correct environment, boot time or no
+;
+;---------------------------------------------------------------------------
+
+FarGetEnv PROC FAR
+ SetKernelDS
+ mov si,curTDB
+ or si,si
+ jz boot_time
+ mov ds,si
+ UnSetKernelDS
+ mov ds,ds:[TDB_PDB]
+not_boot_time:
+ mov ds,ds:[PDB_environ]
+ xor si,si
+ ret
+boot_time:
+ ReSetKernelDS
+ mov ds,TopPDB
+ UnSetKernelDS
+ jmps not_boot_time
+FarGetEnv ENDP
+
+
+;-----------------------------------------------------------------------;
+; SearchPath ;
+; ;
+; Searches the PATH as defined in the environment for the given file. ;
+; ; ;
+; Arguments: ;
+; ParmD pName Pointer to name ;
+; ParmD pBuffer Pointer to temporary buffer ;
+; ParmW Attr AX paramter for DOS (Open, etc.) ;
+; ;
+; Returns: ;
+; AX != 0 ;
+; ;
+; Error Returns: ;
+; AX = -1, BX is error code ;
+; ;
+; Registers Preserved: ;
+; DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,DI,SI,ES ;
+; ;
+; Calls: ;
+; GetPureName ;
+; GetFarEnv ;
+; ;
+; History: ;
+; ;
+; Mon Oct 12, 1987 08:57:48p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc SearchPath,<PUBLIC,FAR>
+ ParmD pName ; Pointer to name
+ ParmD pBuffer ; Pointer to temporary buffer
+ ParmW Attr ; AX paramter for DOS (Open, etc.)
+
+ LocalD pPureName ; pointer to stripped name
+cBegin
+ les di,pName
+ call GetPureName
+ mov pPureName.off,di
+ mov pPureName.sel,es
+
+ push cs
+ call near ptr FarGetEnv
+ mov bx, 3 ; preset error to "path not found"
+spth2: cmp byte ptr [si],0 ; no more enviroment
+ jz spthNo
+
+ lodsw
+ cmp ax,'AP' ; Look for PATH=
+ jnz spth3
+ lodsw
+ cmp ax,'HT'
+ jnz spth3
+ lodsb
+ cmp al,'='
+ jz spth4
+spth3: lodsb
+ or al,al
+ jnz spth3
+ jmp spth2
+
+spth4: les di,pBuffer
+spth5: lodsb
+ stosb
+ cmp al,";"
+ jz spth6
+ or al,al
+ jnz spth5
+ dec si
+
+spth6: mov al,'\'
+ifdef DBCS
+ push si
+ push di
+ mov si,word ptr pBuffer ; buffer address
+ dec di ; point di to the byte before ';'
+ call MyIsDBCSTrailByte ; is it a DBCS trailing byte?
+ pop di
+ pop si
+ jnc spth6a ;yes, overwrite ';' with '\'
+endif
+ cmp es:[di-2],al ; path terminated with '\'
+ jnz spth6a
+ dec di
+spth6a: mov es:[di-1],al
+ push ds
+ push si
+ cCall MyAnsiToOem,<pPureName,es,di>
+
+ ;** Call the OpenCall function to search for the file. It calls
+ ;** the extended error function on failure
+ les si,pBuffer ;Point to buffer
+ mov ax,Attr ;Get the AX word here and flag
+ cCall OpenCall, <es,si,-1> ; OpenCall with -1
+ mov bx,ax ;Save the error code if any
+ pop si
+ pop ds
+ jnc spthYes
+ cmp byte ptr [si],0 ;At end of path?
+ jnz spth4
+
+spthNo: mov ax,-1
+ ;** Bug 14960: If the last error code was path not found, the user
+ ;** has a bogus directory in their path. Since we were unable
+ ;** to find the file, return file not found instead of path not
+ ;** found. 2 November 1991 Clark R. Cyr
+ cmp bx, 3 ;Path Not Found?
+ jne spthYes
+ mov bx, 2 ;Make it File Not Found
+spthYes:
+cEnd
+
+
+; MyAnsiToOem
+; Used to do ANSI to OEM conversions. This function allows routines
+; here to call freely without worrying if the keyboard driver can
+; be called with this yet. At boot time, we can't call the
+; keyboard driver where these functions reside, so no translation
+; is done.
+
+cProc MyAnsiToOem, <PUBLIC,NEAR>, <si,di,ds>
+ parmD pSrc
+ parmD pDst
+cBegin
+ SetKernelDS
+ cmp pKeyProc.sel,0 ; is there a keyboard yet?
+ jnz mao1 ; Yes, so do translation
+ lds si, pSrc ; No, so just copy the strings
+ UnSetKernelDS
+ les di, pDst
+ call strcpyreg
+;mao0:
+; lodsb
+; stosb
+; or al, al
+; jnz mao0
+ jmps mao2
+ ; Not booting, we can call the
+mao1: ; translation routine
+ ReSetKernelDS
+ cCall [pKeyProc],<pSrc,pDst> ; convert string from AnsiToOem
+mao2:
+cEnd
+
+
+; MyOemToAnsi
+; Matching function for MyAnsiToOem. See comments above
+
+cProc MyOemToAnsi,<PUBLIC,NEAR>,<si,di,ds>
+ parmD pSrc
+ parmD pDst
+cBegin
+ SetKernelDS
+ cmp pKeyProc.sel,0 ; is there a keyboard yet?
+ jnz moa1 ; Yes, do normal conversion
+ lds si, pSrc ; No, so just copy the string
+ UnSetKernelDS
+ les di, pDst
+ call strcpyreg
+;moa0:
+; lodsb
+; stosb
+; or al, al
+; jnz moa0
+ jmps moa2
+
+moa1: ; Call the translation routine
+ ReSetKernelDS
+ cCall [pKeyProc1],<pSrc,pDst> ; convert string from AnsiToOem
+moa2:
+cEnd
+
+
+;---------------------------------------------------------------------
+;
+; Is Drive number in DI a floppy? A=0, etc. ZF = yes, it is a floppy
+;
+ public IsFloppy
+IsFloppy:
+ifdef WOW
+ push dx
+ cCall GetDriveType,<di>
+ pop dx
+else
+ mov bx,1 ; 1 = Get Drive Info from InquireSystem
+ push es
+ push ds
+ SetKernelDS
+ cCall [pSysProc],<bx,di>
+ pop ds
+ UnSetKernelDS
+ pop es
+endif
+ cmp al,2 ; 2 = removable media
+ ret
+
+FarIsFloppy PROC FAR
+ call IsFloppy
+ ret
+FarIsFloppy ENDP
+
+
+;----------------------------------------------------------------------------
+; Prompt
+;
+; Puts up the system error box telling the user the file can't be found
+;
+;----------------------------------------------------------------------------
+
+cProc Prompt, <NEAR,PUBLIC>, <si,di,ds>
+ parmD lpstr
+cBegin
+ SetKernelDS
+ mov ax,3 ;Assume CANCEL
+ cmp pSErrProc.sel,0 ;Is there a USER yet?
+ jz P_End ;No
+
+ ;** Format the string <szCannotFind1><lpstr><szCannotFind2>
+ push ds
+ pop es
+ mov di, dataOffset OutBuf ; ES:DI points to dest
+ mov si, dataOffset szCannotFind1
+ call strcpyreg
+
+ lds si, [lpstr]
+ mov al, byte ptr ds:[si]
+ UnSetKernelDS
+ mov es:[LastDriveSwapped], al
+ call strcpyreg
+
+ push es
+ pop ds
+ ReSetKernelDS
+ mov si, dataOffset szCannotFind2
+ call strcpyreg
+
+ ;** Prepare the dialog box
+ push ds ;In our DS
+ push dataOFFSET OutBuf ;Point to "Cannot find" string
+
+ push ds
+ push dataOffset szDiskCap ;Caption
+
+ push 0 ;No left button
+
+ push SEB_CLOSE + SEB_DEFBUTTON ;Button 1 style
+
+ push 0 ;No right button
+
+ call [pSErrProc] ;Put up the system error message
+
+P_End:
+ xor ax,ax
+cEnd
+
+
+;----------------------------------------------------------------------------
+; StartString
+;
+; Prepares the start of the string for the sys error box
+;
+; ES:BX is the pointer to the full pathname
+; DS:DX is the string "Can't find file X:"
+;
+;----------------------------------------------------------------------------
+
+cProc strcpyreg, <NEAR,PUBLIC>
+cBegin nogen
+ cld
+@@: lodsb ; copy from DS:SI
+ stosb ; to ES:DI
+ or al, al
+ jnz @B ; including 0
+ dec di ; point to trailing 0
+ ret
+cEnd nogen
+
+
+;cProc StartString, <NEAR,PUBLIC>
+;cBegin NOGEN
+; CheckKernelDS
+; ReSetKernelDS
+;
+; ;** Copy the first part of the string
+; cld
+; push es ;Save the parameter
+; push bx
+; mov dx,dataOffset szCannotFind1 ;Point to Can't Find string
+; call AppendFirst ;Put in OutBuf
+; pop bx
+; pop es
+;
+; ;** Save the drive letter for compatibility with ancient disk swaps
+; mov al,es:[bx] ;Get drive letter
+; mov [LastDriveSwapped],al ;Save it for GetLastDiskChange
+;
+; ;** Append the filename portion
+; smov ds,es
+; mov dx,bx
+; jmps Append
+;
+;cEnd NOGEN
+
+
+; AppendFirst & Append
+; Append ASCIIZ string to the static string OutBuf
+;
+; ENTRY: DS:DX points to a string to append to the static buffer
+;
+; AppendFirst clears the static string and appends the new string
+; as the first part of the string.
+; Append just appends the new string on the end of the current string.
+
+cProc AppendFirst, <PUBLIC,NEAR>
+cBegin NOGEN
+ CheckKernelDS
+ ReSetKernelDS
+ mov [BufPos],dataOffset OutBuf
+ UnSetKernelDS
+
+;Append:
+ push si ;Save some registers
+ push di
+ SetKernelDS es
+ mov di,[BufPos]
+ mov si,dx
+ call strcpyreg
+;ap1: lodsb
+; stosb
+; or al,al
+; jnz ap1
+ dec di
+ mov [BufPos],di
+ pop di
+ pop si
+ ret
+cEnd NOGEN
+ UnSetKernelDS es
+
+
+; GetPureName
+; Strips the drive and directory portions of a pathname off.
+; ENTRY: ES:DI points to pathname
+; EXIT: ES:DI points to "pure" name in same string
+
+cProc GetPureName, <NEAR,PUBLIC>
+cBegin
+
+ ;** Do DBCS version:
+ ;* It is not possible to search filename delimiter by backward
+ ;** search in case of DBCS version, so we use forward search.
+IFDEF DBCS
+ mov bx,di
+iup0:
+ mov al,es:[di]
+ test al,al ; end of string?
+ jz iup2 ; jump if so
+ inc di
+ cmp al,'\'
+ jz iup1
+ cmp al,'/'
+ jz iup1
+ cmp al,':'
+ jz iup1
+ call MyIsDBCSLeadByte ; see if char is DBC
+ jc iup0 ; jump if not a DBC
+ inc di ; skip to detemine 2nd byte of DBC
+ jmp iup0
+iup1:
+ mov bx,di ; update purename candidate
+ jmp iup0
+iup2:
+ mov di,bx ; di points purename pointer
+
+ ;** Do normal version:
+ ;** Here we can just back up until we find the proper char
+ELSE
+ cld
+ xor al,al
+ mov cx,-1
+ mov bx,di
+ repne scasb
+ inc cx
+ inc cx
+ neg cx
+iup0: cmp bx,di ; back to beginning of string?
+ jz iup1 ; yes, di points to name
+ mov al,es:[di-1] ; get next char
+ cmp al,'\' ; next char a '\'?
+ jz iup1 ; yes, di points to name
+ cmp al,'/' ; next char a '/'
+ jz iup1
+ cmp al,':' ; next char a ':'
+ jz iup1 ; yes, di points to name
+ dec di ; back up one
+ jmp iup0
+iup1:
+ENDIF
+
+cEnd
+
+
+; ParseFile
+;
+; ENTRY: DS:SI points to unqualified pathname
+; ES:DI points to buffer to be used for qualified name
+; EXIT: Buffer previously pointed to by ES:DI now has full
+; unambiguous pathname
+; DX is length of path portion of entered pathname
+; AX is total length of pathname
+; DI is number of slashes
+; CX is length of path ON ERROR ONLY!!! (for PowerPoint)
+
+LONG_UNC_NAMES equ 1
+
+cProc ParseFile, <NEAR,PUBLIC>
+ localW cSlash ;Word ptr [bp][-2]
+ localW cchPath ;Word ptr [bp][-4]
+ localW fUNC ;Flag for UNC name (\\foo\bar)
+if LONG_UNC_NAMES
+ localW fCountUNC ;Indicates we are parsing UNC name
+else
+ localW fFirstUNC ;Indicates we are parsing UNC name
+endif
+
+cBegin
+ mov cSlash,0 ;Zero the local variables
+ mov cchPath,0
+ mov fUNC,0 ;Assume it's not UNC
+ cld
+
+ ;** If a drive is on the path, parse it. Otherwise, get the current
+ ;** drive.
+ cmp byte ptr ds:[si+1],':'
+ jne nodrive
+ lodsb
+ inc si
+ or al,20h ; convert to lower case
+ sub al,'a' ; convert to number
+ jb @F ;Not valid, so return error
+ cmp al,'z'-'a'
+ jbe gotdrive
+@@: jmp gpFail2
+nodrive:
+ mov ah,19h
+ DOSCALL
+gotdrive:
+ mov dl,al
+ inc dl
+ add al,'A' ; convert to ascii
+ mov ah,':'
+
+ ;** If this is a UNC name, we don't want to copy the drive letter
+ ;** as it is legal but unnecessary for a full path
+ mov fUNC, 1
+if LONG_UNC_NAMES
+ mov fCountUNC, 2
+else
+ mov fFirstUNC, 1
+endif
+ cmp WORD PTR ds:[si], '\\' ;Is this a UNC? (\\foo\bar)
+ je PF_DriveOK ;Yes, don't insert drive
+ cmp WORD PTR ds:[si], '//' ;Is this a UNC? (//foo/bar)
+ je PF_DriveOK ;Yes, don't insert drive
+ mov fUNC, 0 ;Nope, not UNC
+if LONG_UNC_NAMES
+ mov fCountUNC, 0
+else
+ mov fFirstUNC, 0
+endif
+
+ stosw ;Write drive letter and colon
+ add cchPath,2 ;Add two chars to path len
+PF_DriveOK:
+ push di ; Save beginning of path
+
+ ;** If we start with a slash, we have a qualified path here
+ ;* so we don't have to search to find the current path.
+ ;** Otherwise, we have to find where we are and make the path.
+ mov bx,'/' shl 8 + '\' ;Separator characters
+ mov al,ds:[si] ;Get first character
+ cmp al,bh ;If it's either one, we have a
+ je getpath0 ; full path, so don't search
+ cmp al,bl
+ je getpath0
+ mov al,bl ;Get a '\'
+ stosb ; and put in the buffer
+ inc cchPath ;Bump path count
+ mov cx,ds ;Prepare for DOS call: Save DS
+ xchg si,di ;DS:SI needs to point to buffer
+ mov ax,es
+ mov ds,ax
+ mov ah,47h ;DOS #47: Get Current Directory
+ DOSCALL
+ jnc @F
+ jmp gpfail
+@@:
+ push cx ;DOS returns OEM characters
+ push bx ; so convert to ANSI
+ cCall MyOemToAnsi,<ds,si,ds,si>
+ pop bx
+ pop ds
+ xchg si,di ;Get pointer back
+ xor al,al
+ mov cx,-1
+ repnz scasb ;Find the end of the string
+ neg cx
+ dec cx ;Don't count the terminator
+ dec cx
+ add cchPath,cx ;Add into path count
+ dec di ;Don't leave DI past the zero byte
+ifdef DBCS ;Check for trailing slash, DBCS-style
+ push si
+ push di
+ mov si,di
+ sub si,cx ;es:si->string address
+ dec di ;es:di->last byte
+ call MyIsDBCSTrailByte ;is the last byte a DBCS trailing byte?
+ pop di
+ pop si
+ jnc loopGD3 ;yes, append a '\'
+ ;no, fall through
+endif
+ mov al,es:[di-1] ;Check for trailing slash. Non-DBCS
+ cmp al,bh ;If there is one, we're done here
+ je getpath0
+ cmp al,bl
+ je getpath0
+IFDEF DBCS
+loopGD3:
+ENDIF
+ mov al,bl ;Put a trailing slash on
+ stosb
+ inc cchPath
+
+ ;** Parse the pathname the user gave us
+getpath0:
+PF_GetPath label NEAR
+ public PF_GetPath
+ xor cx,cx ;CL=# of chars, CH=# of '.'
+ mov dx,di ;DX points to start of user chars
+gp0:
+ lodsb ;Get a character
+ cmp al,bl ;Slash?
+ je gp1 ;Yes
+ cmp al,bh
+ jne gp2 ;No, skip this
+gp1: ;Character is a slash
+
+ ;** If we have a UNC name, two slashes are OK
+ ;** (just at the start of the filename)
+ cmp cchPath, 0 ;Start of path?
+ jne PF_NotUNC ;No, even if UNC, not valid here
+ cmp fUNC, 0 ;UNC pathname?
+ je PF_NotUNC ;No, handle normally
+ stosb ;Store the first slash
+ lodsb ;Get the second slash
+ inc cchPath ;Another character in string
+ jmp SHORT gp1f ;Skip double slash failure
+PF_NotUNC:
+
+ cmp ds:[si],bl ; if double slash, bad file name
+ jz gpFail
+ cmp ds:[si],bh
+ jz gpFail
+
+if LONG_UNC_NAMES
+ dec fCountUNC ; Move to next portion of path
+ jns @f
+ mov fCountUNC,0
+@@:
+else
+ ;** When we get here, we will be on the first slash AFTER the
+ ;** UNC slashes: (\\foo\bar) (or any succeeding slash)
+ ;** ^
+ ;** So, we want clear the fFirstUNC flag so we don't allow
+ ;** more than 8 characters before a dot.
+ mov fFirstUNC, 0
+endif
+gp1f:
+ inc cSlash ; we found a slash
+ cmp cl,ch ; number of chars = number of '.'
+ jne gp1b ; nope....
+
+ or cx,cx
+ jnz gp001
+ifdef DBCS
+ jmp gp2b ; We need 16 bits branch
+else
+ jmp SHORT gp2b
+endif
+gp001:
+
+ cmp cl,2 ; if more than 2 '.'
+ ja gpFail ; then we are bogus
+
+ dec di
+ifdef DBCS
+ dec cchPath ; adjust path string length
+endif
+ dec cl
+ jz getpath0
+ifdef DBCS
+ dec di
+ dec di
+ mov dx, di
+ sub di, cchPath
+ add di, 4
+ cmp di, dx
+ jnc gpfail ; illegal path such as "c:.." or "c:\.."
+ mov cchPath, 3
+gp1a:
+ xor cx, cx
+gp1bb:
+ inc di
+ inc cx
+ mov al, es:[di]
+ cmp al, bl
+ jz gp1c
+ call MyIsDBCSLeadByte
+ jc gp1bb
+ inc di
+ inc cx
+ jmp gp1bb
+gp1c:
+ cmp di, dx
+ jz gp1d
+ add cchPath, cx
+ jmp gp1a
+gp1d:
+ sub di, cx
+ inc di ; new di points previous '\'+1
+ jmp getpath0
+else
+ mov di,dx
+gp1a:
+ dec di
+ mov al,es:[di-1]
+ cmp al,bl
+ je getpath0
+ cmp al,':'
+ jne gp1a
+endif
+gpfail:
+ pop ax
+gpFail2:
+ xor ax,ax
+ jmp gpexit
+gp1b:
+ mov al,bl
+ stosb
+ inc cchPath
+ jmp getpath0
+gp2:
+ or al,al
+ jnz gp002
+ jmp short gpx
+
+gp002:
+ cmp al,' '
+ jb gpFail
+ ja gp20
+
+gp2x: lodsb ; if space encountered continue scanning...
+ or al,al ; if end of string, all ok
+ifdef DBCS
+ jz gp2x_01
+ jmp gpx
+gp2x_01:
+else
+ jz gpx
+endif
+ cmp al,' ' ; if space, keep looking...
+ jz gp2x
+ jmps gpFail ; otherwise error
+
+gp20: cmp al,';'
+ jz gpFail
+ cmp al,':'
+ jz gpFail
+ cmp al,','
+ jz gpFail
+ cmp al,'|'
+ jz gpFail
+ cmp al,'+'
+ jz gpFail
+ cmp al,'<'
+ jz gpFail
+ cmp al,'>'
+ jz gpFail
+ cmp al,'"'
+ jz gpFail
+ cmp al,'['
+ jz gpFail
+ cmp al,']'
+ jz gpFail
+ cmp al,'='
+ jz gpFail
+
+ inc cl ; one more char
+ifdef DBCS
+ call MyIsDBCSLeadByte ; First byte of 2 byte character?
+ jc gp2a ; No, convert to upper case
+ stosb ; Yes, copy 1st byte
+ inc cchPath
+ lodsb ; Fetch second byte
+ inc cl
+ jmps gp2a1 ; with no case conversion
+gp2a:
+endif
+ call MyUpper
+gp2a1:
+ cmp cchPath,127 ; DOS pathmax is 128, room for null.
+ ja gpFail
+gp2b:
+ stosb
+ inc cchPath
+ cmp al,'.'
+ jne gp2c
+ inc ch
+ mov ah,cl
+ dec ah
+gp2c:
+if LONG_UNC_NAMES
+ ;** If this is a UNC name, don't bother checking lengths
+ cmp fCountUNC,0 ; Past \\foo\bar yet?
+ je PF_NotUNCPart
+else
+ cmp fFirstUNC, 0 ;First UNC name?
+ je PF_NotFirstUNC ;Nope
+ or ch,ch ;'.' encountered yet?
+ jnz PF_NotFirstUNC ;Yes, treat like normal name
+ cmp cl, 11 ;11 chars allowed with no '.'
+ ja gpFv ;Too many
+endif
+ jmp gp0 ;Ok
+
+if LONG_UNC_NAMES
+PF_NotUNCPart:
+else
+PF_NotFirstUNC:
+endif
+
+ ;** Check other lengths
+ cmp ch,0 ; did we find a . yet?
+ jz gpT1 ; no, max count is 8
+ cmp cl,12 ; otherwise check for 12 chars
+ ja gpFv ; if more, no good
+ mov al,cl
+ sub al,ah
+ cmp al,3+1 ; more than 3 chars in extension?
+ ja gpFv
+ jmp gp0 ; continue
+
+gpT1: cmp cl,8 ; did we find 8 chars between / and .
+ ja gpFv ; if more, we fail
+ jmp gp0
+gpx:
+ ;** UNC names are invalid if they are SHORTER than the following:
+ ;** \\server\share\f
+ cmp fUNC,0 ;UNC name?
+ jz PF_EnoughSlashes ;No
+ cmp cSlash,3 ;We count \\ as one slash
+ jb gpFv ;Not enough, so fail it
+PF_EnoughSlashes:
+
+ cmp ch,1
+ je gpx1
+ ja gpFv ; if more than 1 we fail
+ mov ah,cl ; No extension given
+gpx1:
+ mov es:[di],al ; Zero terminate destination
+ xchg al,ah ; Get length of name in CX
+
+ or ax,ax
+ jnz gpx2
+gpFv: jmp gpFail
+gpx2:
+ cmp ax,8 ; but no more than 8
+ ja gpFv
+
+ pop ax
+ sub dx,ax ;Get length of path in DX
+ inc dx ;Add drive letter and :, less one
+
+ ;** Never a drive letter or colon for the UNC name case
+ cmp fUNC,0 ;UNC name?
+ jz @F ;Yes, don't do this
+ dec dx ;UNC names ALWAYS have >=3 slashes
+ dec dx
+@@: mov ax,dx ;AX = length of entire path
+ xor ch,ch ;Clear high byte for 16 bit add
+ add ax,cx
+ cmp dx,1 ;If length is one, we have C:\ case
+ jne @F ;Nope
+ inc dx ;Bump it
+@@:
+gpexit:
+ mov di,cSlash ;DI retured as cSlash
+cEnd
+
+;---------------------------------------------------------------
+;
+; Return the drive letter of last drive a disk was swapped in
+;
+cProc GetLastDiskChange, <PUBLIC,FAR>
+cBegin nogen
+ xor ax,ax
+ push ds
+ SetKernelDS
+ xchg al,[LastDriveSwapped]
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc MyOpenFile,<PUBLIC,FAR>,<si,di>
+ ParmD srcFile
+ ParmD dstFile
+ ParmW Command
+cBegin
+ SetKernelDS
+ xor ax,ax
+ cmp [wMyOpenFileReent], ax ; Prevent reentering this procedure
+ jne myoffail
+
+ifdef WOW
+ and Command, NOT OF_VERIFY ; Don't Bother with verify for internal
+ ; It slows us down
+endif
+ mov es,[CurTDB]
+ mov ax,es:[TDB_ErrMode] ; Enable INT 24h processing
+ and es:[TDB_ErrMode],NOT 1
+ mov [myofint24],ax ; Save old INT 24h flag
+ mov [wMyOpenFileReent],1
+
+ cCall IOpenFile,<srcFile,dstFile,Command>
+
+ mov es,[CurTDB] ; Restore old INT 24h processing flag
+ mov dx,[myofint24]
+ mov es:[TDB_ErrMode],dx
+
+ mov [wMyOpenFileReent],0
+ jmps mof_ret
+
+myoffail:
+ krDebugOut DEB_ERROR, "MyOpenFile not reentrant"
+ dec ax
+mof_ret:
+ UnSetKernelDS
+cEnd
+
+sEnd CODE
+
+sBegin MISCCODE
+assumes CS,MISCCODE
+assumes ds,nothing
+assumes es,nothing
+
+externNP MISCMapDStoDATA
+externFP GetWindowsDirectory
+
+cProc DeletePathname,<PUBLIC,FAR>
+; ParmD path
+cBegin nogen
+ pop bx
+ pop cx
+ mov ax,4100h ; dos delete file function
+ push ax
+ push cx
+ push bx
+ errn$ OpenPathname
+cEnd nogen
+
+cProc OpenPathname,<PUBLIC,FAR>,<ds,si,di>
+ ParmD path
+ ParmW attr
+
+ LocalV Buffer,MaxFileLen
+cBegin
+ mov ax,attr ; get attribute
+ or ah,ah ; function code already set...
+ jnz opn0 ; ...yes, otherwise...
+ mov ah,3dh ; ...default to open
+opn0: mov di,ax
+
+; We don't use open test for existance, rather we use get
+; file attributes. This is because if we are using Novell
+; netware, opening a file causes Novell to execute its
+; own path searching logic, but we want our code to do it.
+
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ cmp fNovell, 0
+ lds dx,path ; get pointer to pathname
+ UnSetKernelDS
+ je opnNoNovell
+ mov ax,4300h ; Get file attributes
+ DOSFCALL ; Does the file exist?
+ jc opnnov ; No, then dont do the operation
+opnNoNovell:
+ mov ax,di ; Yes, restore operation to AX
+ DOSFCALL
+ jnc opn2
+opnnov:
+ lea ax,Buffer
+ regptr dsdx,ds,dx
+ regptr ssax,ss,ax
+ cCall SearchPath,<dsdx,ssax,di>
+opn2: mov bx,ax
+cEnd
+
+;---------------------------------------------------------------
+;
+; Return the drive letter of a good disk to put a temp file on
+;
+;
+cProc GetTempDrive,<PUBLIC,FAR>
+; ParmB Drive
+cBegin nogen
+ mov bx,sp
+ push si
+ push di
+ mov ax,ss:[bx+4]
+ and al,not TF_FORCEDRIVE
+ jnz gtd1
+ mov ah,19h ; get the current disk
+ DOSFCALL
+ add al,'A'
+gtd1: and al,01011111b ; convert to upper case (always a-z)
+ test byte ptr ss:[bx+4],TF_FORCEDRIVE ; Forcing drive letter?
+ jnz gtdz ; Yes, all done
+ sub al,'A' ; A: = 0, etc.
+ cbw
+ mov si,ax ; SI = drive to return if no hard disk
+ xor di,di ; start with drive A
+gtd2: call FarIsFloppy ; while drive = floppy, keep looking
+ cmp al,3 ; did we find a hard disk?
+ mov dx,1 ; return we have a hard disk
+ jz gtdx ; yes, return it
+ inc di
+ cmp di,"Z"-"A"
+ jbe gtd2
+ xor dx,dx ; indicate its a floppy
+ mov di,si ; return default disk
+
+gtdx: mov ax,di
+ add al,"A"
+
+gtdz: mov ah,":"
+ pop di
+ pop si
+ ret 2
+cEnd nogen
+
+cProc hextoa,<PUBLIC,NEAR>
+cBegin nogen
+ mov ah,al
+ mov cl,4
+ shr al,cl
+ and ah,0Fh
+ add ax,3030h
+ cmp al,39h
+ jbe hextoa1
+ add al,7
+hextoa1:
+ cmp ah,39h
+ jbe hextoa2
+ add ah,7
+hextoa2:
+ ret
+cEnd nogen
+
+;---------------------------------------------------------------
+;
+cProc IGetTempFileName,<PUBLIC,FAR>,<si,di>
+ parmW drive
+ parmD lpPrefix
+ parmW nUnique
+ parmD lpBuf
+ localW myUnique
+ localW mydx
+ localW mybuf
+cBegin
+ sub sp, 128 ; local buffer for buiding lpBuf
+ mov di, sp
+ mov mybuf, sp ; save
+ cCall GetTempDrive,<drive>
+ mov mydx,dx
+ ;les di,lpBuf
+ smov es, ss
+ stosw ; AX = 'drive:'
+ mov ax,drive
+ test al,TF_FORCEDRIVE
+ jnz stmpForce
+ call FarGetEnv ; look for environ TEMP=
+stmp2:
+ lodsw
+ or al,al ; no more enviroment
+ jz stmpNo
+
+ cmp ax,'ET' ; Look for TEMP=
+ jne stmp3
+ lodsw
+ cmp ax,'PM'
+ jne stmp3
+ lodsb
+ cmp al,'='
+ je stmpYes
+stmp3: lodsb ; find end of string
+ or al,al
+ jnz stmp3
+ jmp stmp2
+
+stmpYes:
+ifdef DBCS
+ mov al,[si]
+ mov ah,0
+ call FarMyIsDBCSLeadByte
+ jnc stmpnodrive
+endif
+ cmp byte ptr [si+1],':' ; TEMP has drive?
+ jne stmpnodrive
+ dec di
+ dec di
+stmpnodrive: ; copy path to ES:DI
+ lodsb
+ or al,al
+ jz stmpPath
+ stosb
+ jmp stmpnodrive
+
+stmpForce:
+ mov al,'~'
+ stosb
+ jmps stmpNo1
+
+stmpNo: ; ES:DI points to "drive:"
+ dec di
+ dec di
+ cCall GetWindowsDirectory, <esdi, 144>
+ add di, ax
+
+stmpPath: ; ES:DI points to "drive:path"
+ mov ax,'~\'
+ cmp es:[di-1],al ; does it already end in \
+ jnz stmpNoF ; no, just store it
+ dec di ; override it
+stmpNoF:
+ stosw
+stmpNo1:
+ lds si,lpPrefix
+ mov cx,3
+stmpPfx:
+ lodsb
+ or al,al
+ jz stmpPfx1
+ stosb
+ loop stmpPfx
+stmpPfx1:
+ mov dx,nUnique
+ or dx,dx
+ jnz stmpNum
+ mov ah,2Ch
+ DOSFCALL
+ xor dx,cx
+stmpNum:
+ mov myUnique,dx
+ jnz stmpNum1
+ inc dx ; Dont ever use 0 as the unique num.
+ jmp stmpNum
+stmpNum1:
+ mov al,dh
+ call hextoa
+ stosw
+ mov al,dl
+ call hextoa
+ stosw
+ mov ax,'T.'
+ stosw
+ mov ax,'PM'
+ stosw
+ xor ax,ax
+ stosb
+
+; Don't call AnsiUpper on this string because it has OEM characters
+; in it (from the app and the temp environment variable).
+
+ cmp nUnique,0
+ jne stmpDone
+ ;lds dx,lpBuf
+ mov dx, mybuf
+ smov ds, ss
+ mov ax,5B00h
+ xor cx,cx
+ DOSFCALL
+ jnc stmpClose
+ cmp al,80 ; Did we fail because the file
+ jnz stmpfail ; already exists?
+ sub di,9
+ mov dx,myUnique
+ inc dx
+ jmp stmpNum
+
+stmpClose:
+ mov bx,ax
+ mov ah,3Eh
+ DOSFCALL
+ jmps stmpdone
+
+stmpfail:
+ xor ax,ax
+ mov myunique,ax
+stmpdone:
+ mov di, mybuf ; robustness crap
+ smov es, ss ; bug #15493 ami pro
+ RegPtr esdi, es, di
+ cCall lstrcpy <lpBuf,esdi> ; now copy to user spc
+ mov ax,myunique
+ mov dx,mydx
+ add sp, 128
+cEnd
+
+;-----------------------------------------------------------------------;
+; GetDriveType
+;
+; Entry:
+; parmW drive Disk Drive Information (Drive A = 0)
+;
+; Returns:
+; ax = 0 means the drive does not exist. if dx != 0 then the drive
+; maps to the drive in dx instead (A = 1) AND the drive is
+; REMOVEABLE.
+; ax = 1 means the drive does not exist. if dx != 0 then the drive
+; maps to the drive in dx instead (A = 1) AND the drive is
+; FIXED.
+; ax = 2 means the drive is removable media
+; ax = 3 means the drive is fixed media
+; ax = 4 means the drive is fixed media and remote
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 16-Oct-1989 21:14:27 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ifndef WOW - We thunk this API its too slow
+
+cProc GetDriveType,<PUBLIC,FAR>
+; parmW drive
+cBegin nogen
+ mov bx,sp
+ push ds
+ call MISCMapDStoDATA
+ ResetKernelDS
+ mov ax,1 ; 1 = Get Drive Info from InquireSystem
+ mov bx,ss:[bx+4]
+ cCall pSysProc,<ax,bx>
+ pop ds
+ ret 2
+cEnd nogen
+endif; WOW
+
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldreloc.asm b/private/mvdm/wow16/kernel31/ldreloc.asm
new file mode 100644
index 000000000..8a3fd7b04
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldreloc.asm
@@ -0,0 +1,759 @@
+ PAGE ,132
+ TITLE LDRELOC - SegReloc procedure
+
+.xlist
+include gpfix.inc
+include kernel.inc
+include newexe.inc
+include protect.inc
+.list
+
+;externFP FatalExit
+externFP GlobalLock
+externFP GlobalUnLock
+externFP Int21Handler
+externFP IFatalAppExit
+
+DataBegin
+
+if PMODE32 and ROM
+externW gdtdsc
+endif
+
+externW f8087
+externB fastFP
+;externW WinFlags
+ifndef WINDEBUG
+externB szUndefDyn
+endif
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP GetStringPtr
+externNP FindOrdinal
+externNP EntProcAddress
+externNP LoadSegment
+externNP GetOwner
+
+ife ROM and PMODE32
+externW gdtdsc
+endif
+
+externNP GetAccessWord
+externNP DPMIProc
+
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+
+ifdef WOW_x86
+externNP get_physical_address
+endif
+
+
+
+;-----------------------------------------------------------------------;
+; UndefDynlink
+;
+; If an application has a dynamic link to a loaded library that
+; we can't find we fix up to this think. This way the app
+; will blow up only if it tries to call the entry point.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Wed 10-May-1989 19:28:50 -by- David N. Weise [davidw]
+; Added this nifty comment block!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc UndefDynlink,<PUBLIC,FAR>,<ds>
+ localW foo ; force stack frame
+cBegin
+ SetKernelDS
+if KDEBUG
+ cCall GetOwner,<[bp].savedCS>
+ mov es,[bp].savedCS
+ mov bx,[bp].savedIP
+ sub bx,5
+ krDebugOut DEB_FERROR, "%AX1 #ES:#BX called undefined dynalink"
+; kerror ERR_LDNAME,<Call to undefined dynlink entry point at >,es,bx
+else
+ push 0
+ push ds
+ push dataOffset szUndefDyn
+ cCall IFatalAppExit ;,<0, ds, dataOffset szUndefDyn>
+endif
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SegReloc
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Thu 25-May-1989 20:16:09 -by- David N. Weise [davidw]
+; Removed the special case code for version 1.01 (linker or windows?) that
+; If BASE fixup for moveable code segment within a DATA segment (V1.01 only)
+; Then force to be PTR fixup.
+;
+; Wed 10-May-1989 19:28:50 -by- David N. Weise [davidw]
+; Added this nifty comment block!
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+ifdef WOW_x86
+.386
+cProc SegReloc,<NEAR,PUBLIC>,<si,edi,ds>
+else
+cProc SegReloc,<NEAR,PUBLIC>,<si,di,ds>
+endif
+ parmW hexe
+ parmD prleinfo
+ parmW creloc
+ parmD pseginfo
+ parmW fdataseg
+ parmW fh
+ localW himpexe
+ localW hseg
+ localW pseg
+ localW hifileoff
+ localW lofileoff
+ localV rlerec,<SIZE NEW_RLC>
+ localW fOsfixup ;bool set if a floating-pt osfixup.
+ localW old_access
+ifdef WOW_x86
+ localD rover_2
+endif
+cBegin
+ les si, pseginfo
+ mov dx, es:[si].ns_handle ; Get handle to segment
+ mov hseg, dx
+ test dl, GA_FIXED
+ jnz sr_nolock
+ cCall GlobalLock,<dx>
+sr_nolock:
+
+ mov pseg, dx
+
+;; WOW - refer to original win 3.1 code on \\pucus, there were too many ifdefs
+;; in the code. It would have become unreadable to add any more. mattfe
+;; mar 29 93
+;;; Restored the "too many ifdef's" because this code doesn't just
+;;; assemble right for all our platform permutations. I also tried to make it
+;;; readable by adding comments. -neilsa
+
+;; For 386 version of WOW we use selector 23h to write to vdm memory without
+;; worrying about setting up a selector.
+
+ifndef WOW
+;------------------Original win31 source--------------------------------
+ife PMODE32
+ cCall GetAccessWord,<dx>
+else
+.386p
+ lar eax, edx
+ shr eax, 8
+.286
+endif
+ mov old_access, ax
+ test al, DSC_CODE_BIT
+ jz short access_ok
+ mov al, DSC_PRESENT+DSC_DATA
+ mov bx, dx
+
+ push ds
+if ROM and PMODE32
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, ax
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop ds
+
+else ; ******** WOW ADDED SOURCE
+
+ifdef WOW_x86
+;------------------WOW source for X86 platforms-------------------------
+ife PMODE32
+ cCall GetAccessWord,<dx>
+ mov old_access, ax
+ test al, DSC_CODE_BIT
+ jz short access_ok
+ mov al, DSC_PRESENT+DSC_DATA
+ mov bx, dx
+ mov cx,ax
+ DPMICALL 0009h
+endif; PMODE32
+
+else; WOW_x86
+;------------------WOW source for NON-X86 platforms---------------------
+ife PMODE32
+ cCall GetAccessWord,<dx>
+else
+.386p
+ lar eax, edx
+ shr eax, 8
+.286
+endif
+ mov old_access, ax
+ test al, DSC_CODE_BIT
+ jz short access_ok
+ mov al, DSC_PRESENT+DSC_DATA
+ mov bx, dx
+ife PMODE32
+ mov cx,ax
+ DPMICALL 0009h
+else
+ push ds
+ mov ds, gdtdsc
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, ax
+ pop ds
+endif; PMODE32
+endif; WOW_x86
+endif; ******** WOW ADDED SOURCE
+;----------------------End of WOW changes-------------------------------
+
+access_ok:
+
+ mov fOsfixup,0 ; set flag initially to false.
+ mov si,OFF_prleinfo
+ mov ax,SEG_prleinfo
+ or ax,ax
+ jz @F
+ jmp srloop1
+@@:
+
+ xor dx,dx
+ xor cx,cx
+ mov bx,fh
+ mov ax,4201h
+ DOSCALL ; Get current file offset
+ jnc @F
+ krDebugOut <DEB_ERROR or DEB_krLoadSeg>, "Get file offset failed"
+; Debug_Out "Get file offset failed."
+ jmps srbadrle1
+@@:
+ mov hifileoff,dx
+ mov lofileoff,ax
+srloop:
+ mov ax,SEG_prleinfo
+ or ax,ax ; Did we get a handle to RLE?
+ jnz srloop1 ; No, continue
+
+
+ mov cx,hifileoff ; OPTIMIZE this to read in more
+ mov dx,lofileoff ; than one record at a time!!
+ mov bx,fh
+ mov ax,4200h
+ DOSCALL ; Seek to current offset
+ jnc @F
+ krDebugOut DEB_ERROR, "Seek failed."
+; Debug_Out "Seek failed."
+srbadrle1:
+ jmp srbadrle
+@@:
+ push ss
+ pop ds
+ lea dx,rlerec
+ mov cx,SIZE NEW_RLC
+ add lofileoff,cx
+ adc hifileoff,0
+ mov ah,3Fh
+ DOSCALL ; Read next record
+ jnc @F
+ krDebugOut DEB_ERROR, "Read record failed"
+; Debug_Out "Read record failed"
+ jmps srbadrle1
+@@:
+ cmp ax,cx
+ je @F
+ krDebugOut DEB_ERROR, "Read #AX bytes, expecting #CX."
+ jmp srbadrle
+
+srosfijmp:
+ jmp srosfixup
+
+@@:
+ mov ax,ss
+ mov si,dx
+
+srloop1:
+ mov ds,ax
+ mov ax,ds:[si].nr_proc
+ mov cx,NRRTYP
+ and cl,ds:[si].nr_flags
+ or cx,cx
+ jz srint ; Internal Reference
+ cmp cl,OSFIXUP
+ je srosfijmp
+ .errnz NRRINT
+ mov bx,ds:[si].nr_mod ; Here if Import Ordinal/Name
+ sub bx,1
+ jnc @F
+ krDebugOut DEB_ERROR, "Zero import module."
+ jmps srbadrle
+@@:
+ shl bx,1
+ mov es,hexe
+ add bx,es:[ne_modtab]
+ mov bx,es:[bx]
+ mov himpexe,bx
+ or bx,bx
+ jz srbadimp
+ dec cx ; (sleaze) if cx == 2, then Import Name
+ jz srrord ; else Import Ordinal
+ .errnz NRRORD - 1
+ .errnz NRRNAM - 2
+
+srrnam: ; Convert name to ordinal
+ cCall GetStringPtr,<hexe,fh,ax>
+ cCall FindOrdinal,<himpexe,dxax,fh>
+ mov bx,himpexe
+ or ax,ax
+ jz srbadimp
+srrord:
+if KDEBUG
+ cCall EntProcAddress,<bx,ax,0>; we do want to RIP for failure
+else
+ cCall EntProcAddress,<bx,ax>
+endif
+ jcxz srbadimp
+ jmp dorle
+
+srbadimp:
+if kdebug
+ mov dx, hExe
+ mov ax, himpexe
+ krDebugOut <DEB_WARN or DEB_krLoadSeg>, "%dx1 failed implicit link to %ax0"
+endif
+ mov dx,cs
+ mov ax,codeOFFSET UndefDynlink
+ jmp dorle
+
+srbadrle:
+ jmp srfail
+
+srdone1:
+ jmp srdone
+
+srint:
+ mov dl,NRSTYP ; DL = fixup type
+ and dl,ds:[si].nr_stype
+ mov cl,ds:[si].nr_segno
+ or cx,cx
+ jnz @F
+ krDebugOut DEB_ERROR, "NULL segment in fixup."
+ jmp srbadrle
+@@:
+ mov bx,hexe
+ cmp cl,ENT_MOVEABLE
+ je srrord
+ mov es,bx
+ mov bx,cx
+ dec bx
+ cmp es:[ne_cseg],bx
+ jnbe @F
+ krDebugOut DEB_ERROR, "Invalid segment in fixup."
+ jmp srbadrle ; Error if invalid segno
+@@:
+ push ax ; Save offset
+ shl bx,1
+ mov ax,bx
+ shl bx,1
+ shl bx,1
+ add bx,ax ; BX *= 10
+ .errnz 10 - SIZE NEW_SEG1
+ add bx,es:[ne_segtab]
+ cmp dl,NRSOFF ; Offset only fixup?
+ je srint2 ; Yes, go do it then (DX ignored then)
+if ROM
+ test byte ptr es:[bx].ns_flags, NSALLOCED OR NSLOADED
+else
+ test byte ptr es:[bx].ns_flags, NSALLOCED
+endif
+ jz srint1
+ mov ax, es:[bx].ns_handle
+ or ax,ax
+ jnz @F
+ krDebugOut DEB_ERROR, "NULL handle."
+ jmp srbadrle
+@@:
+
+ test al,GA_FIXED
+ jnz srint2
+ HtoS ax
+ mov cx,ax ; for the jcxz below
+ jmps srint2
+
+srbadrlej:
+ jmp srbadrle
+
+srint1:
+int 3
+int 3
+ cCall LoadSegment,<es,cx,fh,fh>
+srint2:
+ mov dx,ax
+ pop ax
+ or cx,cx
+ jnz @F
+ krDebugOut DEB_ERROR, "Can't load segment."
+ jmp srbadrlej
+
+@@:
+dorle:
+ push ax
+ push dx
+ mov ax,SEG_prleinfo
+ or ax,ax ; Did we get a handle to RLE?
+ jnz @F ; No, continue
+ mov ax,ss ; Assume reading from stack
+@@:
+ mov ds,ax
+ mov bl,NRSTYP
+ and bl,ds:[si].nr_stype
+ mov cx,NRADD
+ and cl,ds:[si].nr_flags
+ mov di,ds:[si].nr_soff
+
+ifdef WOW_x86
+.386
+;; WOW selector optimiaztion
+ cCall get_physical_address,<pseg>
+ shl edx,16
+ mov dx,ax
+ mov rover_2,edx
+
+ mov ax,FLAT_SEL
+ mov ds,ax
+
+ movzx edi,di
+ add edi,edx ; es:edi -> pseg:0
+else
+ mov ds, pseg
+endif
+ pop dx
+ pop ax
+ cmp bl,NRSSEG
+ je srsseg
+ cmp bl,NRSPTR
+ je srsptr
+ cmp bl,NRSOFF
+ je srsoff
+ cmp bl,NRSBYTE
+ je srsbyte
+
+ krDebugOut DEB_ERROR, "Unknown fixup #BX"
+ife KDEBUG
+ jmps nextrle
+endif
+
+nextrlenz: ; if NZ at this point, something broke
+ jz nextrle
+; jnz srfail
+ jmp srfail
+
+nextrle:
+ mov ax,1
+ add si,SIZE NEW_RLC
+ dec creloc
+ jle srdone2
+ jmp srloop
+
+srdone2:jmp srdone
+
+; Lo-byte fixup chain (always additive)
+
+
+
+beg_fault_trap srfailGP
+srsbyte:
+ifdef WOW_x86
+ add ds:[edi],al
+else
+ add ds:[di],al
+endif
+ jmp nextrle
+
+; Offset fixup chain
+srsoff:
+ cmp fOsfixup,0 ; is it a floating-pt. osfixup?
+ jnz srsosfixup ; yes, goto special case code.
+
+ mov dx, ax ; fall through into segment fixup
+
+; Segment fixup chain
+srsseg:
+ jcxz srsseg1
+ifdef WOW_x86
+ add ds:[edi],dx
+else
+ add ds:[di],dx
+endif
+ jmp nextrle
+
+srsseg1:
+ or cx, -1
+srsseg2:
+ mov bx,dx
+ifdef WOW_x86
+ xchg word ptr ds:[edi],bx
+ movzx edi,bx
+ add edi,rover_2
+else
+ xchg ds:[di],bx
+ mov di,bx
+endif
+ inc bx
+ loopnz srsseg2 ; if CX == 0, we're broken
+ jmp nextrlenz
+
+; Segment:Offset fixup chain
+srsptr:
+ jcxz srsptr1
+ifdef WOW_x86
+ add word ptr ds:[edi],ax
+ add word ptr ds:[edi+2],dx
+else
+ add ds:[di],ax
+ add ds:[di+2],dx
+endif
+ jmp nextrle
+
+srsptr1:
+ or cx, -1
+srsptr2:
+ mov bx,ax
+ifdef WOW_x86
+ xchg word ptr ds:[edi],bx
+ mov word ptr ds:[edi+2],dx
+ movzx edi,bx
+ add edi,rover_2
+else
+ xchg ds:[di],bx
+ mov ds:[di+2],dx
+ mov di,bx
+endif
+ inc bx
+ loopnz srsptr2
+ jmp nextrlenz
+
+; osfixup for floating-point instructions
+
+fINT EQU 0CDH
+fFWAIT EQU 09BH
+fESCAPE EQU 0D8H
+fFNOP EQU 090H
+fES EQU 026H
+fCS EQU 02Eh
+fSS EQU 036h
+fDS EQU 03Eh
+BEGINT EQU 034h
+
+FIARQQ EQU (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fDS)
+FISRQQ EQU (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fSS)
+FICRQQ EQU (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fCS)
+FIERQQ EQU (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fES)
+FIDRQQ EQU (fINT + 256*(BEGINT + 0)) - (fFWAIT + 256*fESCAPE)
+FIWRQQ EQU (fINT + 256*(BEGINT + 9)) - (fFNOP + 256*fFWAIT)
+FJARQQ EQU 256*(((0 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+FJSRQQ EQU 256*(((1 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+FJCRQQ EQU 256*(((2 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+
+osfixuptbl label word ; table has 12 entries - six for int
+ DW FIARQQ, FJARQQ
+ DW FISRQQ, FJSRQQ
+ DW FICRQQ, FJCRQQ
+ DW FIERQQ, 0h
+ DW FIDRQQ, 0h
+ DW FIWRQQ, 0h
+osfixuptbllen = $-osfixuptbl ; six to convert FWAIT to NOP
+ DW fFNOP - fFWAIT, 0
+ DW fFNOP - fFWAIT, 0
+ DW fFNOP - fFWAIT, 0
+ DW fFNOP - fFWAIT, 0
+ DW fFNOP - fFWAIT, 0
+ DW FIWRQQ, 0h ; leave this one in for emulator
+
+srsosfixup:
+ifdef WOW_x86
+ add word ptr ds:[edi][0],ax
+ add word ptr ds:[edi][1],dx
+else
+ add ds:[di][0],ax
+ add ds:[di][1],dx
+endif
+ mov fOsfixup,0 ; clear flag for next record.
+ jmp nextrle
+end_fault_trap
+
+srfailGP:
+; fault_fix_stack
+ pop ax
+ pop dx
+ krDebugOut DEB_ERROR, "Fault in SegReloc #AX #DX"
+srfail:
+if KDEBUG
+ mov bx,hexe
+; xor bx,bx
+ krDebugOut DEB_ERROR, "%BX1 has invalid relocation record"
+; kerror ERR_LDRELOC,<Invalid relocation record in >,es,bx
+endif
+ xor ax,ax
+ jmps srdone
+
+
+; OSFIXUPs for floating-point instructions.
+;
+; The fixup is applied by adding the first word (ax) to the
+; coprocessor intruction, and for fixups 1-3 also adding the
+; second word (dx) to the instruction+1. Generalize, by having
+; dx=0 for fixups 4-6 and always adding dx to instruction+1.
+;
+; Note: the relocation type is marked NRSOFF by the linker,
+; but we must apply these fixups differently. Here we know
+; it is an osfixup, so set the flag fOsfixup so that later
+; when we test the type, we can apply the fixup correctly.
+;
+; 06-Oct-1987. davidhab.
+
+; Wed 10-May-1989 19:28:50 -by- David N. Weise [davidw]
+;
+; Actually, due to the way the emulator does fwait polling
+; of exceptions we must send the NOP FWAIT pairs to the
+; emulator even if a math coprocessor is available.
+
+srosfixup:
+ mov es,hexe
+ test es:[ne_flags],NEPROT ; OS/2 app
+ jnz srosf_skip ; then never fix up!
+ SetKernelDS es
+ mov bx,ds:[si].nr_mod ; get OSFIXUP id
+ cmp bx,6 ; is it NOP, FWAIT?
+ jz srosfixup1 ; if so always fix up!
+ cmp f8087,94 ; 8087 installed?
+ jnz srosfixup1 ; No, do OSFIXUP processing
+ cmp fastFP,0
+ je srosf_skip
+ dec bx
+ shl bx, 2
+ cmp bx, osfixuptbllen
+ jae srosfixup2
+ add bx, osfixuptbllen
+ jmps fast
+
+
+srosf_skip:
+ jmp nextrle ; Yes, skip OSFIXUP processing
+
+srosfixup1:
+ dec bx ; offset into table is (n-1) * 4
+ shl bx,1
+ shl bx,1
+ cmp bx,osfixuptbllen ; Make sure it is within table bounds
+ jae srosfixup2 ; No, bad relocation
+fast: mov ax,osfixuptbl[bx+0] ; Yes, get relocation value from table
+ mov dx,osfixuptbl[bx+2] ; get second part of fixup
+ mov fOsfixup,1 ; set flag to mark our special type.
+ jmp dorle ; Go apply relocation
+
+srosfixup2:
+ jmp srbadrle
+ UnSetKernelDS es
+
+srdone:
+ push ax
+
+ifndef WOW
+;------------------Original win31 source--------------------------------
+ mov cx, old_access
+ test cl, DSC_CODE_BIT
+ jz short no_reset_access
+ mov bx, pseg
+
+ push ds
+if ROM and PMODE32
+ SetKernelDS
+ mov ds, gdtdsc
+ UnsetKernelDS
+else
+ mov ds, gdtdsc
+endif
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, cx
+if 0 ;;ROM and KDEBUG
+ call CheckROMSelector
+endif
+ pop ds
+
+else ; ******** WOW ADDED SOURCE
+
+ifdef WOW_x86
+;------------------WOW source for X86 platforms-------------------------
+ife PMODE32
+ mov cx, old_access
+ test cl, DSC_CODE_BIT
+ jz short no_reset_access
+ mov bx, pseg
+ DPMICALL 0009h
+endif; PMODE32
+
+else; WOW_x86
+;------------------WOW source for NON-X86 platforms---------------------
+ mov cx, old_access
+ test cl, DSC_CODE_BIT
+ jz short no_reset_access
+ mov bx, pseg
+
+ife PMODE32
+ DPMICALL 0009h
+else
+ push ds
+ mov ds, gdtdsc
+ and bl, not 7
+ mov word ptr ds:[bx].dsc_access, cx
+ pop ds
+
+endif; PMODE32
+endif; WOW_x86
+endif; ******** WOW ADDED SOURCE
+;----------------------End of WOW changes-------------------------------
+
+no_reset_access:
+ mov ax, hseg
+ test al, 1
+ jnz srdone_nounlock
+ cCall GlobalUnLock,<ax>
+srdone_nounlock:
+ pop ax
+cEnd
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldseg.asm b/private/mvdm/wow16/kernel31/ldseg.asm
new file mode 100644
index 000000000..7e37680ab
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldseg.asm
@@ -0,0 +1,1813 @@
+ TITLE LDSEG - SegAlloc procedure
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc ; Handle_To_Sel
+.list
+
+NSHUGESEG = NSKCACHED ; not first seg of huge segment
+; A huge segment (data object larger than 64K) requires more than one
+; selector, but is part of a single memory allocation block. The first
+; selector is a handle, like any other segment. Subsequent selectors of
+; the huge memory block are _not_ handles, so we can't call MyLock() on
+; them, as the consistency check will fail. We mark these selectors with
+; the NSHUGESEG bit in the flags word. TonyG suggested this.
+; Note that data segments are already loaded, locked, etc, so the call to
+; MyLock is redundant anyway.
+; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ;
+
+
+
+externFP IGlobalFree
+externFP IGlobalAlloc
+externFP IGlobalReAlloc
+externFP IGlobalLock
+externFP MyOpenFile
+externFP FlushCachedFileHandle
+externFP Int21Handler
+externFP set_discarded_sel_owner
+externFP GetPatchAppRegKey
+externFP PatchAppSeg
+
+if KDEBUG
+externFP OutputDebugString
+endif
+
+if ROM
+;externNP SetROMOwner
+externFP FarSetROMOwner
+externFP ChangeROMHandle
+externFP AllocSelector
+externFP IFreeSelector
+externNP CloneROMSelector
+externFP LZDecode
+endif
+
+DataBegin
+
+externB Kernel_flags
+;externB fBooting
+externB fPadCode
+;externW pGlobalHeap
+;externW MyCSDS
+externW Win_PDB
+
+if KDEBUG
+externB fLoadTrace
+externB fPreloadSeg
+endif
+
+if PMODE32
+externD FreeArenaCount
+extrn CountFreeSel:WORD
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+;externNP MyFree
+externNP SegReloc
+externNP MyAlloc
+externNP MyAllocLinear ; MyAlloc with useful parameters
+externNP MyLock
+externNP GetCachedFileHandle
+externNP CloseCachedFileHandle
+externNP GetOwner
+externNP SetOwner
+externNP get_selector_length16
+
+externNP get_rover_2
+externNP DiscardTheWorld
+
+IFNDEF NO_APPLOADER
+externNP LoadApplSegment
+endif ;!NO_APPLOADER
+
+if LDCHKSUM
+;externNP GetChksumAddr
+externNP CheckSegChksum
+externNP ZeroSegmentChksum
+endif
+
+if SDEBUG
+externNP DebugDefineSegment
+endif
+
+ifdef WOW_x86
+externNP get_physical_address
+endif
+
+;-----------------------------------------------------------------------;
+; AllocSeg ;
+; ;
+; Allocates memory for a segment. Does not load the segment. Puts ;
+; the handle of the segment into the segment descriptor structure ;
+; in the module database, and updates the flags there to mark the ;
+; segment as allocated but not loaded. Put the segment number into ;
+; the BurgerMaster handle entry. It also changes the .ga_owner to be ;
+; the module database. ;
+; ;
+; Arguments: ;
+; parmD pSegInfo ;
+; ;
+; Returns: ;
+; AX = handle for segment ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ZF = 1 ;
+; ;
+; Registers Preserved: ;
+; SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX ;
+; ;
+; Calls: ;
+; MyAlloc ;
+; ;
+; History: ;
+; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ;
+; Handle 64K (big/huge) data segments ;
+; ; ;
+; Mon Feb 09, 1987 10:29:16p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc AllocSeg,<PUBLIC,NEAR>,<si,es>
+ parmD pSegInfo
+cBegin
+ SetKernelDS
+ les si,pSegInfo
+
+; Get size into AX (max of file size and minimum allocation).
+
+ mov bx,es:[si].ns_flags
+
+ test bl,NSALLOCED ; Already allocated?
+ jz as0 ; No, allocate it
+ jmp SHORT as3
+as0: mov ax,es:[si].ns_minalloc
+ xor dx, dx ; if AX == 0
+ cmp ax, 1 ; then it is really 64K
+ adc dx, dx
+ add ax, 2 ; We may have a 1 byte entry point at the
+ adc dx, 0 ; very end of a segment. PatchCodeHandle
+ ; will GP trying to decipher the prolog.
+ ; Also allow space for reading relocation word
+
+ cmp si,es:[ne_pautodata]
+ jne as1
+ add ax,es:[ne_stack] ; Include stack and heap for data.
+ jc asfail ; Don't need to handle big auto segs
+ add ax,es:[ne_heap]
+ jnc as1
+asfail:
+ krDebugOut DEB_ERROR, "%es2 Automatic Data Segment larger than 64K."
+ xor ax,ax
+asxj: jmp SHORT asx
+as1:
+
+; Allocate space for segment
+ push bx
+ push es
+ cCall MyAllocLinear,<bx,dxax>
+ pop es
+ pop bx
+ or ax,ax
+ jz asxj
+
+
+as2:
+if ROM
+
+; If this segment gets loaded from ROM, change the segment handle
+; to be the one that was used to fix-up the ROM code segments. This
+; is the value of ns_sector in the segment table.
+
+ test byte ptr es:[si].ns_flags+1,(NSINROM SHR 8)
+ jz as_not_a_rom_seg
+ mov bx,es:[si].ns_sector
+ test dl,GA_FIXED
+ jnz as_fixed
+ StoH bx
+as_fixed:
+ cCall ChangeROMHandle,<dx,bx>
+ mov dx,bx
+as_not_a_rom_seg:
+endif
+ mov es:[si].ns_handle,dx ; Handle into seg table
+ and byte ptr es:[si].ns_flags,not NSLOADED
+ or byte ptr es:[si].ns_flags,NSALLOCED
+
+ mov bx,dx
+ cCall SetOwner,<ax,es>
+
+as3: mov ax,es:[si].ns_handle
+asx:
+ or ax,ax
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; LoadSegment ;
+; ;
+; Loads a segment and performs any necessary relocations. ;
+; ;
+; Arguments: ;
+; parmW hExe ;
+; parmW segno ;
+; parmW fh ;
+; parmW isfh ;
+; ;
+; Returns: ;
+; AX = handle of segment ;
+; CX = handle of segment ;
+; DX = handle of segment ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; CX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,ES ;
+; ;
+; Calls: ;
+; LoadSegment ;
+; AllocSeg ;
+; LoadApplSegment ;
+; MyOpenFile ;
+; SegLoad ;
+; GlobalAlloc ;
+; MyLock ;
+; SegReloc ;
+; GlobalFree ;
+; ZeroSegmentChksum ;
+; CheckSegChksum ;
+; ;
+; History: ;
+; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ;
+; ;
+; Tue Oct 27, 1987 06:10:31p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc LoadSegment,<PUBLIC,NEAR>,<si,di>
+ parmW hExe
+ parmW segno
+ parmW fh
+ parmW isfh
+ localW myfh
+ localW hrleseg
+ localD pseginfo
+ localW creloc
+ localW hseg
+ localW fdataseg
+ localW retries
+ localW SavePDB
+ localB fReload
+if ROM
+ localW selROMrle
+endif
+ localW pleaseNoLock ; 1 if shouldn't lock seg
+cBegin
+ mov retries, 2
+ xor ax,ax
+ mov hrleseg,ax
+ mov hseg,ax
+ mov SavePDB, ax
+ mov pleaseNoLock, ax
+ mov fReload, al
+if ROM
+ mov selROMrle,ax
+endif
+ not ax
+ mov myfh,ax
+ mov es,hexe
+ mov si,segno
+ dec si
+ cmp es:[ne_cseg],si
+ jg ls_not_done ; wish we had auto jump sizing...
+ jmp lsdone
+ls_not_done:
+ shl si,1
+ mov bx,si
+ shl si,1
+ shl si,1
+ add si,bx
+ .errnz 10 - SIZE NEW_SEG1
+ add si,es:[ne_segtab]
+ mov SEG_pseginfo, es ; Save segment info pointer
+ mov OFF_pseginfo, si
+
+IFNDEF NO_APPLOADER
+ test es:[ne_flags],NEAPPLOADER
+ jnz ls_special_load
+ls_not_special_load:
+ENDIF ;!NO_APPLOADER
+
+ mov bx,es:[si].ns_flags
+ mov ax, bx
+ and ax, NSHUGESEG
+ mov pleaseNoLock, ax
+
+if ROM
+ test bh,(NSINROM SHR 8) ; Segment in ROM?
+ jz ls0b ; no, go load it normally
+
+ test bl,NSLOADED ; Alread 'loaded' in ROM?
+ jnz chk_rom_seg
+ push es
+ cCall AllocSelector,<0>
+ pop es
+ cCall CloneROMSelector,<es:[si].ns_sector,ax>
+ mov selROMrle,ax
+ mov fh,ax ; Fake parmas to indicate loading
+ mov isfh,-1 ; from memory and go load it
+ jmps ls1b
+
+chk_rom_seg:
+ test bl,NSALLOCED ; ROM seg allocated & loaded into RAM?
+ jnz ls0b ; yes, treat normally
+
+ mov ax,es:[si].ns_handle ; later code expects this
+ jmp DefineSeg ; define seg to debugger (maybe)
+ls0b:
+endif ;ROM
+
+ test bl,NSALLOCED
+ jnz ls1
+ push bx
+ cCall AllocSeg,<essi> ; No, so try allocating the segment
+ pop bx
+ or ax,ax
+ jnz ls1b
+ls1: mov ax,es:[si].ns_handle
+ mov hseg,ax
+ test bl,NSLOADED
+ jz ls1b
+ mov fReload,1
+ jmp lsexit ; so MyLock at lsexit can swap them in
+
+IFNDEF NO_APPLOADER
+ls_special_load:
+ mov ax,segno
+ cmp ax,1
+ je ls_not_special_load ;* first segment normal load
+ test es:[si].ns_flags,NSLOADED
+ jnz ls_already_loaded
+ cCall LoadApplSegment, <hExe, fh, ax>
+ jmp lsx
+
+ls_already_loaded:
+ mov ax,es:[si].ns_handle
+ mov hseg,ax
+ mov fReload,1
+ jmp lsexit
+endif ;!NO_APPLOADER
+
+ls1b:
+ mov ax,fh
+ inc ax ; Already have file handle?
+ jz ls2 ; No, then get one and load segment
+ dec ax
+ cmp isfh,ax ; Yes, loading from memory?
+ jne lsdoit ; Yes, load it now
+ jmps ls2b ; No, load it now
+ls2:
+ SetKernelDS
+ mov ax, Win_PDB ; Save what PDB is supposed to be
+ mov SavePDB, ax ; since we will set it to kernel's PDB
+ mov ax,-1
+ cCall GetCachedFileHandle,<hExe,ax,ax> ; Get file handle from cache
+ls2b:
+ mov myfh,ax
+ mov isfh,ax
+ inc ax
+ jnz lsdoit0
+ cmp SavePDB, ax ; If we saved the PDB, (ax=0)
+ je @F
+ push SavePDB ; better restore it!
+ pop Win_PDB
+@@:
+ jmp lsdone
+lsdoit0:
+ dec ax
+lsdoit:
+ push es
+ cCall SegLoad,<essi,segno,ax,isfh>
+ pop es
+ mov hseg,0
+ or ax,ax
+ jz lsexit1
+
+ inc ax ; Did we get a file error?
+ jnz lsloaded
+ mov bx, myfh
+ inc bx ; Reading from memory?
+ jz lsexit1 ; no, fail
+ dec bx
+ cmp bx, fh ; We opened the file?
+ je lsexit1 ; no, fail
+;;; cCall CloseCachedFileHandle,<bx>
+ mov bx, SavePDB
+ mov Win_PDB, bx
+ cCall FlushCachedFileHandle,<hExe> ; Close it
+ dec retries
+ jz lsbadfile
+ jmps ls2 ; and try to re-open it.
+ UnSetKernelDS
+lsbadfile:
+ krDebugOut DEB_ERROR, "%ES2 I/O error reading segment"
+lsexit1:
+ jmp lsexit
+
+lsloaded:
+ mov hseg,bx
+ mov bx,es:[si].ns_flags
+ test bx,NSRELOC
+ jnz lm1x
+ jmp lschksum
+lm1x:
+ and bx,NSDATA
+ mov fdataseg,bx
+ mov bx,myfh ; Loading from memory?
+ inc bx
+ jnz lm1 ; No, continue
+ mov es,dx ; Yes, point to relocation info
+ mov si,cx
+ cld
+ lods word ptr es:[si]
+ mov creloc,ax
+ jmps lm2
+lm1:
+ dec bx
+ mov creloc,cx
+ shl cx,1
+ shl cx,1
+ shl cx,1
+ .errnz 8 - SIZE new_rlc
+ push bx
+ push cx
+ mov ax,GA_MOVEABLE+GA_NODISCARD ; DO NOT WANT FIXED!!
+ xor bx,bx
+ regptr xsize,bx,cx
+if PMODE32
+.386
+; We don't really want to cause an attempt to grow the global arena
+; table or the LDT here!
+ push ds
+ SetKernelDS
+ cmp FreeArenaCount,0 ; free arena?
+ jz NoFreeArenas ; No
+ cmp CountFreeSel,0 ; free selector?
+NoFreeArenas:
+ pop ds
+ UnsetKernelDS
+ jz lm1a ; No, then read one at a time
+.286
+endif
+ cCall IGlobalAlloc,<ax,xsize>
+ mov hrleseg,ax ; Save handle
+ or ax,ax ; Did we get the memory
+ jz lm1a ; No, then read one at a time
+
+ cCall IGlobalLock,<ax> ; Get the address of the relocation info
+ mov si, ax
+ mov es, dx
+ pop cx ; Restore byte count
+ pop bx ; Restore file handle
+ push ds
+ mov ds,dx
+ assumes ds,nothing
+ xor dx,dx
+ mov ah,3Fh ; Read in relocation information
+ DOSCALL
+ pop ds
+ assumes ds,nothing
+ jc lserr2
+ cmp ax,cx
+ jne lserr2
+ jmps lm2
+
+lm1a:
+ pop cx ; Restore byte count
+ pop bx ; Restore file handle
+ xor si,si
+ mov es,si ; Signal no records read
+lm2:
+ ; Pass pseginfo, not hseg
+ cCall SegReloc,<hexe,essi,creloc,pseginfo,fdataseg,myfh>
+lm2a:
+ mov cx,hrleseg
+ jcxz no_hrleseg
+ push ax
+ cCall IGlobalFree,<hrleseg>
+ pop ax
+no_hrleseg:
+ les si,pseginfo
+ or ax,ax
+ jnz lschksum
+lsdone2:
+ jmps lsdone
+
+lserr2:
+ krDebugOut DEB_ERROR, "Error reading relocation records from %es2"
+ xor ax,ax
+ jmp lm2a
+
+lschksum:
+ mov ax, hseg ; in case we aren't locking
+ Handle_To_Sel al
+ cmp pleaseNoLock, 0
+ jnz lschksum1
+ cCall MyLock,<hseg>
+lschksum1:
+
+if LDCHKSUM
+ push ax
+ push si
+ mov si,ax
+ cCall ZeroSegmentChksum
+ pop si
+ cCall CheckSegChksum ; destroys ax, bx, cx, dx, es
+ pop ax
+endif
+
+ les si, pseginfo
+
+if ROM
+
+DefineSeg:
+if SDEBUG
+ push ax ; save segment selector
+endif
+endif
+
+if SDEBUG ; Tell debugger about new segment
+ cmp pleaseNoLock, 0
+ jnz keep_secrets
+ mov bx,es:[ne_restab]
+ inc bx
+ mov dx,es:[si].ns_flags
+ mov si, ax
+ xor ax, ax
+ test dx,NSDATA ; test to pass NSKCACHED too
+ jz sa8
+ test byte ptr es:[ne_flags],NEINST
+ jz sa8
+ mov ax,es:[ne_usage]
+ dec ax
+sa8:
+ mov cx,segno
+ dec cx
+
+ cCall DebugDefineSegment,<esbx,cx,si,ax,dx>
+keep_secrets:
+endif
+
+if ROM
+if SDEBUG
+ pop ax ; recover segment selector
+endif
+ mov dx,ax ; in case this is a ROM code seg,
+ ; MyLock doesn't get called, but we
+ ; want to return AX & DX = selector
+endif
+
+lsexit:
+ mov cx,hseg
+ jcxz lsdone
+ mov ax, cx ; in case we don't lock
+ mov dx, ax
+ Handle_To_Sel al
+ cmp pleaseNoLock, 0
+ jnz lsdone
+ cCall MyLock,<cx>
+lsdone:
+if ROM
+ mov cx,selROMrle ; If a segment was loaded from ROM,
+ jcxz @f ; an extra selector was allocated
+ push ax ; to point to reloc info--free that
+ cCall IFreeSelector,<cx> ; now.
+ pop ax
+@@:
+endif
+ mov cx,myfh
+ inc cx
+ jz lsx
+ dec cx
+ cmp fh,cx
+ je lsx
+ push ax
+ SetKernelDS
+;;; cCall CloseCachedFileHandle,<cx>
+ mov ax, SavePDB
+if KDEBUG
+ or ax, ax
+ jnz @F
+ int 3
+@@:
+endif
+ mov Win_PDB, ax
+ UnSetKernelDS
+ pop ax
+public lsx
+lsx:
+ mov es, hExe
+ test es:[ne_flagsothers], NEHASPATCH
+ jz ls_exeunt
+ cmp fReload, 0
+ jne ls_exeunt
+
+ push dx
+ push ax
+
+ cCall GetPatchAppRegKey,<hExe>
+ mov cx, dx
+ or cx, ax
+ jnz @F
+
+ ; MCF_MODPATCH is set, but there are no patches
+ ; in the registry for this module. Turn off the patch flag.
+ and es:[ne_flagsothers], not NEHASPATCH
+ jmp short ls_after_patch
+@@:
+ ; reg key in dx:ax
+ cCall PatchAppSeg,<dx,ax,segno,hseg>
+ test ax, ax
+ jz ls_after_patch
+
+ ; One or more patches applied, so mark the segment not discardable.
+ ; PatchAppSeg already cleared GA_DISCARDABLE or GA_DISCCODE in the
+ ; global arena record.
+ mov si, pseginfo.off
+ and es:[si].ns_flags, not NSDISCARD ; mark not discardable
+ls_after_patch:
+ pop ax
+ pop dx
+ls_exeunt:
+ mov cx,ax
+cEnd
+
+
+GETSEGLEN macro segval
+ local not_huge_386
+if PMODE32
+.386p
+ xor eax, eax ; since we now have huge segments,
+ mov ax, segval ; we need to be able to handle limit
+ lsl eax, eax ; values > 64K. On a 386 we just
+ inc eax ; execute the lsl instruction.
+ test eax, 0ffff0000h
+.286
+ jz not_huge_386
+ mov ax, 0 ; 0 == 64K
+not_huge_386:
+else
+ cCall get_selector_length16,<segval> ; Get size of segment
+endif
+endm
+
+;-----------------------------------------------------------------------;
+; SegLoad ;
+; ;
+; Reads in the data portion of a code or data segment. ;
+; ;
+; It can be confusing decoding how various values of ns_cbseg, ;
+; ns_minalloc, and ns_sector define the size of disk files. I hope ;
+; this table is accurate for all combinations.... ;
+; ;
+; sector cbseg minalloc- Sector in memory is ... ;
+; 0 0 0 - 64K segment, all 0's ;
+; 0 0 m - 'm' bytes, all 0's ;
+; 0 c 0 - illegal (sector = 0 when cbseg != 0) ;
+; 0 c m - illegal (sector = 0 when cbseg != 0) ;
+; s 0 0 - 64K segment on disk at given sector ;
+; s 0 m - illegal (cbseg > minalloc) ;
+; s c 0 - 64K, 'c' from file, 64K-'c' 0's ;
+; s c m - 'm' bytes, 'c' from file, 'm-c' 0's ;
+; ;
+; In other words, cbseg == 0 means 64K when a sector value is given, ;
+; else it means 0 bytes from the file ;
+; ;
+; Arguments: ;
+; parmD pseginfo ;
+; parmW segno ;
+; parmW psegsrc ;
+; parmW isfh ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; Thu Feb 28, 1991 01:39:00p -by- Don A. Corbitt [donc] ;
+; Add support for big/huge segments ;
+; ;
+; Tue Oct 27, 1987 06:17:07p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc SegLoad,<NEAR,PUBLIC>,<si,di>
+ parmD pseginfo
+ parmW segno
+ parmW psegsrc
+ parmW isfh
+ localW hseg
+ localW pseg
+ localW psegdest
+ localD prleinfo
+ localW retry
+ localW segoffset
+ localW pleaseNoLock ;1 if segment is 64K
+ localW allocTwice ;if first alloc fails, FreeTheWorld
+ifdef WOW_x86
+ localD rover_2
+endif
+cBegin
+ mov retry,1
+ mov segoffset, 0
+ mov allocTwice, 1
+ les si,pseginfo
+ mov ax,es:[si].ns_handle
+ mov hseg,ax
+ Handle_To_Sel al ; in case we don't lock
+ mov pleaseNoLock, 1
+ test es:[si].ns_flags, NSHUGESEG
+ jnz dont_touch ;big segs are always locked and present
+ mov pleaseNoLock, 0
+ push es
+ cCall MyLock,<ax>
+ pop es
+ or ax,ax
+ jz try_alloc ; wish I could "jnz saalloced"
+dont_touch:
+ jmps saalloced
+
+try_alloc:
+ push es
+ xor ax,ax
+ mov bx, es:[si].ns_minalloc
+ xor dx, dx
+ cmp bx, 1
+ adc dx, dx
+ add bx, 2 ; We may have a 1 byte entry point at the
+ adc dx, 0 ; very end of a segment. PatchCodeHandle
+ ; will GP trying to decipher the prolog.
+ ; Allow room to read relocation word
+ife PMODE32
+ push ds
+ SetKernelDS
+
+ cmp fPadCode, 0
+ je @F
+ add bx, 14
+ adc dx, 0
+@@:
+ pop ds
+ UnSetKernelDS
+endif
+ cCall IGlobalReAlloc,<hseg,dx,bx,ax>
+ pop es
+ cmp hseg,ax
+ jz sarealloced
+saerr2:
+ test es:[si].ns_flags,NSDISCARD
+ jz dont_scream
+ push es
+ cCall DiscardTheWorld ; Maybe if we try again
+ pop es
+ dec allocTwice
+ jz try_alloc
+ krDebugOut DEB_ERROR, "Out of mem loading seg %es2"
+dont_scream:
+ jmp saerr1
+
+sarealloced: ; ax == handle
+ Handle_To_Sel al
+ cmp pleaseNoLock, 0
+ jnz saalloced
+ push es
+ cCall MyLock,<hseg>
+ pop es
+ or ax,ax
+ jz saerr2
+
+saalloced:
+ mov pseg,ax
+ mov psegdest,ax
+
+sareread:
+ push es
+ push si
+ push ds ; We are going to trash this
+
+ cld
+ cmp es:[si].ns_sector,0 ; if sector == 0, then just init
+ jnz sa_read_from_disk ; segment to all 0's
+; mov cx, es:[si].ns_minalloc ; convert minalloc == 0 to 64K
+ GETSEGLEN pseg
+ mov cx, ax
+ifdef WOW_x86 ;
+.386
+;; WOW we can use the magic flat selector 23h to write to any segment
+;; This saves us calling get_rover_2 which makes an NT system call to set
+;; a temp selector
+ cCall get_physical_address,<pseg>
+ shl edx,16
+ mov dx,ax
+ mov ax,FLAT_SEL
+ mov es,ax
+
+ xor eax, eax
+ mov edi,edx ; es:edi -> pseg:0
+
+ cmp cx, 1 ; Need to handle case where CX == 0
+ mov dx, cx
+ rcr cx, 1
+ shr cx, 1
+ movzx ecx,cx
+ rep stos dword ptr [edi]
+ mov cx, dx
+ and cx, 3
+ rep stos byte ptr [edi]
+ jmp sa_after_read
+
+else ; 286
+ cmp cx, 1 ; set CF if 0000
+ rcr cx, 1 ; this sets CF for odd byte of size
+ xor ax, ax
+ xor di, di
+ mov es, pseg ; start at pseg:0000
+ call get_rover_2
+ rep stosw
+ adc cx, cx
+ rep stosb ; this case now handled
+ jmp sa_after_read
+endif;
+
+sa_read_from_disk:
+ mov di,es:[si].ns_cbseg ; #bytes in segment to read
+
+; If source segment address given then copy segment contents
+
+ mov bx,psegsrc ; Get source handle
+ cmp isfh,bx ; Is source a file handle?
+ je sa_read_file ; Yes, go read segment from file
+
+; We are reading from preload buffer, bx == src seg address, di == len
+ push di ; No, set up for fast copy
+ mov OFF_prleinfo,di
+ mov SEG_prleinfo,bx
+ pop cx
+
+if ROM
+ mov al,byte ptr es:[si].ns_flags+1 ; Compressed seg in ROM?
+ and al,(NSINROM OR NSCOMPR) SHR 8
+ cmp al,(NSINROM OR NSCOMPR) SHR 8 ; Both NSINROM & NSCOMPR must
+ jnz @f ; be set
+ jmp sa_exp_seg
+@@:
+endif
+ mov ds,bx
+ifdef WOW_x86 ;
+.386
+;; For WOW on NT we don't want to set the selector unesssarily
+ cCall get_physical_address,<pseg>
+ shl edx,16
+ mov dx,ax
+ mov rover_2,edx
+
+ mov ax,FLAT_SEL
+ mov es,ax
+
+ mov edi,edx ; es:edi -> pseg:0
+ xor esi,esi
+
+ cmp cx, 1 ; set carry if 0 for big/huge segs
+ mov ax, cx
+ rcr cx, 1
+ shr cx, 1
+ movzx ecx,cx
+ rep movs dword ptr [edi], dword ptr [esi]
+ mov cx, ax
+ and cx, 3
+ rep movs byte ptr [edi], dword ptr [esi]
+
+ sub edi,edx ; make di correct for rest of code
+else
+ mov es,pseg ; Writing to pseg
+ call get_rover_2
+ xor si,si
+ xor di,di
+
+IF ROM
+ clc ; HACK: 64K segs not allowed in ROM
+ ; because ns_sector always != 0
+ELSE
+ ; need to handle case where seg size is 64K (cx == 0)
+ cmp cx, 1 ; set carry if 0 for big/huge segs
+ENDIF
+ife PMODE32
+ rcr cx, 1 ; set bit 15 if carry was set
+ rep movsw
+ adc cx, cx
+ rep movsb
+else
+.386
+ mov ax, cx
+ rcr cx, 1
+ shr cx, 1
+ rep movsd
+ mov cx, ax
+ and cx, 3
+ rep movsb
+.286
+endif
+endif; WOW_x86
+
+
+ ; we have now read 'cbseg' bytes from preload buffer, di == cbseg
+ jmp sa_zero_fill_rest
+
+saerr1:
+ xor ax,ax
+ jmp sax
+
+sa_read_file:
+ ; read segment contents from disk file, bx == file handle
+ ; ax = disk file sector
+
+if 0 ;KDEBUG
+ push ax
+ push ds
+ SetKernelDS
+
+ cmp fPreloadSeg, 0
+ jne SHORT SkipDebugTrace
+
+ mov ax, segno
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "%ES0: reading segment #ax"
+SkipDebugTrace:
+ pop ds
+ UnSetKernelDS
+ pop ax
+endif
+
+; Get offset to data portion of segment in DX:AX
+ mov ax, es:[si].ns_sector
+ xor dx,dx
+ mov cx,es:[ne_align]
+sa4a:
+ shl ax,1
+ adc dx, dx
+ loop sa4a ; DX:AX = file offset to segment
+
+ mov cx,dx ; Seek to beginning of segment data
+ mov dx,ax
+ mov ax,4200h ; lseek(bx, sector << align, SEEK_SET)
+ DOSCALL
+ jc saerr
+ mov cx,di ; Get #bytes to read
+ test es:[si].ns_flags,NSRELOC
+ jz no_read_extra_word
+ add cx, 2 ; Relocation word
+no_read_extra_word:
+ mov ds,pseg ; Read segment from file
+ xor dx,dx
+ mov ah,3Fh
+ test es:[si].ns_flags,NSITER
+ jz @F
+ call iterated_data_seg
+ jmps sa_iter_done
+@@:
+ or cx, cx ; if cx == 0 at this point, it is 64K
+ jnz not_huge_read
+
+ cmp es:[si].ns_minalloc,0 ; If minalloc isn't zero too, then the
+ jnz not_huge_read ; segment is too small. Case should't
+ ; happen but does for dbwindow, mimic Win 3.0.
+
+ mov cx, 8000h
+ DOSCALL ; read first 32K from disk
+ jc saerr
+ add dx, cx ; update destination address
+ mov ah, 3fh ; restore AX (doscall trashes it)
+ DOSCALL ; read second 32K
+ jc saerr
+ cmp ax, cx
+ jnz saerr
+ jmp short sa_zero_fill_rest
+
+not_huge_read:
+ DOSCALL
+sa_iter_done:
+ jc saerr ; Continue if no errors
+ cmp ax,cx ; Read ok, did we get what we asked for?
+ jne saerr ; No, fail
+ test es:[si].ns_flags,NSRELOC ; Relocation records?
+ jz sa_zero_fill_rest ; No, continue
+ mov ax, ds:[di] ; Extra word was read here
+ mov OFF_prleinfo, ax
+ jmps sa_zero_fill_rest
+saerr:
+ pop ds
+ pop si
+ pop es
+ mov ax, -1 ; File error
+ jmp sax
+
+if ROM
+sa_exp_seg:
+ xor si,si
+ mov es,pseg
+
+;; NOT Compiled for WOW
+ call get_rover_2
+
+ cCall LZDecode,<es,bx,si,si>
+ mov di,ax
+ or ax,ax
+ jnz sa_zero_fill_rest
+
+if KDEBUG
+ Debug_Out "LZDecode of segment failed!"
+endif
+ pop ds
+ pop si
+ pop es
+ jmp sax
+endif
+
+sa_zero_fill_rest: ; di == bytes written so far
+ GETSEGLEN pseg ; seg len to ax, 0 == 64K
+
+ sub ax,di ; Any uninitialized portion?
+ jz sa_after_read ; No, continue
+ifdef WOW_x86;
+.386
+;; WOW we don't want to call NT to set the selector
+ push ax
+ cCall get_physical_address,<psegdest>
+ shl edx,16
+ mov dx,ax
+ mov ax,FLAT_SEL
+ mov es,ax
+
+ and edi,0000ffffh
+ add edi,edx ; es:edi -> pseg:0
+ pop cx
+
+ push edx
+
+ xor eax,eax
+ cld
+ mov dx,cx
+ shr cx, 2
+ movzx ecx,cx
+ rep stos dword ptr [edi]
+ mov cx, dx
+ and cx, 3
+ rep stos byte ptr [edi]
+
+ pop edx
+ sub edi,edx
+
+else
+ mov es,psegdest ; Yes, set it to zero
+ call get_rover_2
+ mov cx,ax
+ xor ax,ax
+ cld
+ shr cx, 1
+ rep stosw
+ adc cx, cx
+ rep stosb
+endif
+
+sa_after_read:
+ les si, pseginfo
+
+if LDCHKSUM
+ mov ds,psegdest
+ xor si,si
+ mov cx,di
+ shr cx,1
+ xor dx,dx
+ cld
+sa5b:
+ lodsw
+ xor dx,ax
+ loop sa5b
+endif
+ cmp pleaseNoLock, 0
+ jnz dont_patch
+ push dx
+ cCall <far ptr PatchCodeHandle>,<hseg>
+ pop dx
+dont_patch:
+ pop ds ; Restore DS
+ pop si ; segment info pointer
+ pop es
+ mov ax,es:[si].ns_flags ; Are we loading a code segment?
+ and ax,NSDATA
+ .errnz NSCODE
+ jnz sa9
+
+; Here when loading a code segment
+
+if LDCHKSUM
+ mov cx,segno
+ dec cx
+ shl cx,1
+ shl cx,1
+ mov di,es:[ne_psegcsum]
+ add di,cx
+ mov cx,dx
+ xchg es:[di],cx
+ jcxz sa6a0
+ cmp cx,dx
+ je sa6a0
+ dec retry
+ jl sa6a1
+ public badsegread
+badsegread:
+ mov ah,0Dh ; Disk Reset
+ DOSCALL
+ jmp sareread
+sa6a1:
+ krDebugOut DEB_ERROR, "Segment contents invalid %es2"
+ xor ax,ax
+ jmps sax
+sa6a0:
+ mov word ptr es:[di+2],0
+endif
+
+sa9:
+ mov dx,SEG_prleinfo
+ mov cx,OFF_prleinfo
+ mov bx,hseg
+ mov ax,pseg
+sax: or ax,ax
+cEnd
+
+
+
+.286
+
+;-----------------------------------------------------------------------;
+; iterated_data_seg
+;
+; This expands out iterated data segments (specifically for the
+; OS/2 m.exe). Due to the late date this is being sleazed in
+; instead of being done right. To be done right, the read would
+; go into the last part of the present block, and expanded in place,
+; the stack used for the next record count because the last record
+; never fits.
+;
+; Entry:
+; CX = number of bytes to read
+; DS:DX = place to put them
+; DS:DI = place where #relocs will magically appear
+; ES:SI = module exe header:seg info
+;
+; Returns:
+; CF = 1
+; DS:DI = updated magic place where #relocs will magically appear
+;
+; Error Return:
+; CX = 0
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 28-Jan-1990 12:25:02 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc iterated_data_seg,<PUBLIC,NEAR>,<bx,dx,si,ds,es>
+
+ localW temp_buf
+ localW freloc
+cBegin
+
+; deal with that extra relocation word!
+
+ xor ax,ax
+ test es:[si].ns_flags,NSRELOC ; Relocation records?
+ jz @F
+ inc ax
+@@: mov freloc,ax
+
+; first get a temp buffer
+
+ push bx
+ push cx
+ cCall IGlobalAlloc,<0,0,cx>
+ mov temp_buf,ax
+ pop cx
+ pop bx
+ or ax,ax
+ stc ; assume failure
+ jz ids_exit
+ push dx
+ push ds
+
+; read into the temp buffer
+
+ mov ds,ax
+ xor dx,dx
+ mov ah,3Fh
+ DOSCALL
+ pop ds
+ pop dx
+ jc ids_exit1
+ cmp ax,cx
+ jnz ids_exit1
+
+; expand the buffer, yes we should special case strings of length 1
+
+ cmp freloc,0 ; was an extra word read?
+ jz @F
+ sub cx,2
+@@: mov dx,cx
+ smov es,ds
+ xor di,di
+ mov ds,temp_buf
+ xor si,si
+ cld
+ids_next_group:
+ lodsw ; get the # interations
+ mov cx,ax
+ lodsw ; get the # bytes
+@@: push cx
+ push si
+ mov cx,ax
+ rep movsb
+ pop si
+ pop cx
+ loop @B
+ add si,ax ; get past group
+ cmp si,dx
+ jb ids_next_group
+
+; data segment now processed, deal with reloc word
+
+ cmp freloc,0 ; was an extra word read?
+ jz @F
+ movsw
+ sub di,2
+ add dx,2
+@@: mov ax,dx
+ mov cx,dx
+ clc
+
+ids_exit1:
+ pushf ; preserve the carry flag
+ push ax
+ push cx
+ smov ds,0
+ cCall IGlobalFree,<temp_buf>
+ pop cx
+ pop ax
+ popf
+
+ids_exit:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; PatchCodeHandle ;
+; ;
+; Patches the prologs of the procedures in the given code segment. ;
+; ;
+; Arguments: ;
+; parmW hseg ;
+; ;
+; Returns: ;
+; AX = hseg ;
+; DX = pseg ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; MyLock ;
+; ;
+; History: ;
+; ;
+; Sun 17-Sep-1989 10:45:24 -by- David N. Weise [davidw] ;
+; Added support for symdeb to understand segments in himem. ;
+; ;
+; Tue Oct 27, 1987 06:19:12p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+cProc PatchCodeHandle,<PUBLIC,FAR>,<si,di>
+ parmW hseg
+ localW pseg
+ localW hexe
+ localW segno
+ localW segoffset
+ifdef WOW_x86
+.386
+ localD rover_2
+endif
+cBegin
+ SetKernelDS
+ cCall MyLock,<hseg>
+ mov pseg,ax ; Save physical addresss
+ or ax,ax ; All done if discarded
+ jz pcsDone1
+
+ xor si,si
+ mov segoffset, si
+
+ push ax
+ cCall GetOwner,<pseg>
+ mov es, ax
+ pop ax
+
+
+ cmp es:[si].ne_magic,NEMAGIC
+if KDEBUG
+ jz good_boy
+bad_boy:
+ krDebugOut DEB_ERROR "PatchCodeHandle, owner not NewExe %es2"
+ jmps pcsDone1
+good_boy:
+endif
+ jne pcsDone1
+ mov hexe,es
+ mov cx,es:[si].ne_cseg ; We need si to point to entry
+ mov si,es:[si].ne_segtab ; anyway so do it the slow way
+pcsLoop:
+ cmp es:[si].ns_handle,dx ; Scan table for handle
+ je pcsFound
+ add si,SIZE NEW_SEG1
+ loop pcsLoop
+pcsDone1:
+ jmp pcsDone
+pcsExit1:
+ jmp pcsExit
+pcsFound:
+ sub cx,es:[ne_cseg] ; Compute segment# from remainder
+ neg cx ; of loop count
+ inc cx ; 1-based segment#
+ mov segno,cx
+
+ test es:[si].ns_flags,NSDATA
+ jnz pcsExit1
+ .errnz NSCODE
+
+ push si
+ mov di,es:[ne_pautodata]
+ or di,di
+ jz sa6a
+ cCall MyLock,<es:[di].ns_handle>
+ mov di,ax
+sa6a: ; DI:0 points to data segment (or 0)
+ifdef WOW_x86
+;; For WOW we use the NT Magic data selector, since all 16 bit code is DATA
+ cCall get_physical_address,<pseg>
+ assumes es,nothing
+ shl edx,16
+ mov dx,ax ; ES:EDX -> pseg:0
+ mov rover_2,edx
+
+ mov ax,FLAT_SEL
+ mov es,ax
+else
+ mov es,pseg ; ES:0 points to code segment
+ call get_rover_2
+endif
+ mov ds,hexe ; DS:SI points to entry table
+ assumes ds,nothing
+ mov si,ds:[ne_enttab]
+ cld
+
+ or di, di ; Anything to do?
+ jz sa6x
+sa6b:
+ lods word ptr ds:[si]
+ mov dx, ax
+ lods word ptr ds:[si]
+ sub ax, dx ; Get # entries in this block
+ or ax,ax
+ jz sa6x ; Done if zero
+ push word ptr ds:[si] ; Next block
+ add si, 2 ; Skip Next
+ mov cx,ax
+
+sa6c:
+ mov al,ds:[si].pentsegno ; Get segment# from int instruction
+ cmp byte ptr segno,al ; Does this moveable segment match ES?
+ jne sa6e ; No, advance to next entry
+
+ifdef WOW_x86
+
+ movzx ebx, word ptr ds:[si].pentoffset ; Get entry point offset
+ add ebx,rover_2
+ mov al, ds:[si].pentflags ; Get entry point flags
+
+ cmp byte ptr es:[ebx+2],90h ; Yes, followed by nop?
+ jne sa6e ; No, can;t patch prolog then
+ cmp word ptr es:[ebx],0581Eh ; Is it a push ds, pop ax?
+ jne @F ; Yes, take care of prolog
+
+ mov word ptr es:[ebx],0D88Ch
+ jmps sa6d1
+@@:
+ cmp word ptr es:[ebx],0D88Ch ; Is it a mov ax,ds?
+ jne sa6e ; No, can't patch prolog then
+sa6d1:
+ test al,ENT_DATA ; Valid prolog. shared data?
+ jnz sa6d2 ; Yes, patch mov ax,DGROUP into prolog
+ test byte ptr ds:[ne_flags],NEINST ; No, multiple instances?
+ jz sa6e ; No, do nothing
+ test al,ENT_PUBLIC ; Public entry point?
+ jz sa6e ; No, do nothing
+ mov word ptr es:[ebx],09090h ; Yes, set nop, nop in prolog
+ jmps sa6e
+sa6d2:
+ mov byte ptr es:[ebx],0B8h ; Set mov ax,
+ mov es:[ebx+1],di ; DGROUP
+
+else ; NOT WOW_x86
+
+ mov bx, ds:[si].pentoffset ; Get entry point offset
+ mov al, ds:[si].pentflags ; Get entry point flags
+
+ cmp byte ptr es:[bx+2],90h ; Yes, followed by nop?
+ jne sa6e ; No, can;t patch prolog then
+ cmp word ptr es:[bx],0581Eh ; Is it a push ds, pop ax?
+ jne @F ; Yes, take care of prolog
+
+ mov word ptr es:[bx],0D88Ch
+ jmps sa6d1
+@@:
+ cmp word ptr es:[bx],0D88Ch ; Is it a mov ax,ds?
+ jne sa6e ; No, can't patch prolog then
+sa6d1:
+ test al,ENT_DATA ; Valid prolog. shared data?
+ jnz sa6d2 ; Yes, patch mov ax,DGROUP into prolog
+ test byte ptr ds:[ne_flags],NEINST ; No, multiple instances?
+ jz sa6e ; No, do nothing
+ test al,ENT_PUBLIC ; Public entry point?
+ jz sa6e ; No, do nothing
+ mov word ptr es:[bx],09090h ; Yes, set nop, nop in prolog
+ jmps sa6e
+sa6d2:
+ mov byte ptr es:[bx],0B8h ; Set mov ax,
+ mov es:[bx+1],di ; DGROUP
+endif; WOW_x86
+sa6e:
+ add si,SIZE PENT ; Advance to next entry in
+ loop sa6c ; this block
+ pop si
+ or si, si
+ jnz sa6b
+sa6x:
+ mov es,hexe
+ pop si
+pcsExit:
+ or byte ptr es:[si].ns_flags,NSLOADED ; Mark segment as loaded
+
+
+;;;if SDEBUG ; Tell debugger about new segment
+;;; mov bx,es:[ne_restab]
+;;; inc bx
+;;; mov dx,es:[si].ns_flags
+;;; mov ax,segoffset ; tell symdeb how to fixup symbols
+;;; test dx,NSDATA ; test to pass NSKCACHED too
+;;; jz sa8
+;;; test byte ptr es:[ne_flags],NEINST
+;;; jz sa8
+;;; mov ax,es:[ne_usage]
+;;; dec ax
+;;;sa8:
+;;; mov cx,segno
+;;; dec cx
+;;; cCall DebugDefineSegment,<esbx,cx,pseg,ax,dx>
+;;;endif
+pcsDone:
+ mov ax,hseg
+ mov dx,pseg
+cEnd
+
+sEnd CODE
+
+externFP FarAllocSeg
+externFP FarMyAlloc
+externFP FarMyAllocLinear
+externFP FarMyFree
+externFP FarSetOwner
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MapDStoDATA
+
+externA __AHINCR
+
+;-----------------------------------------------------------------------;
+; AllocAllSegs ;
+; ;
+; "Allocates" for all segments of the module being loaded and stores ;
+; the addresses in the segment table. By allocate we mean: ;
+; ;
+; AUTOMATIC DATA gets space, but not yet loaded, ;
+; PRELOAD FIXED get global mem allocated , but not yet loaded, ;
+; MOVEABLE get a handle for later use, ;
+; FIXED get nothing. ;
+; ;
+; If this is not the first instance, then just allocate space for ;
+; the new instance of the automatic data segment. ;
+; ;
+; Arguments: ;
+; parmW hexe ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX =-1 not enough memory ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; FarAllocSeg ;
+; FarMyAlloc ;
+; FarMyFree ;
+; ;
+; History: ;
+; ;
+; Tue Feb 24, 1987 01:04:12p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc AllocAllSegs,<NEAR,PUBLIC>,<si,di,ds>
+ parmW hexe
+ localW cSegs
+ localD hugeLen ; cum length of huge segment
+ localW hugeIndex ; index of first segment of huge
+ localW hugeOffs ; offset of first segment desc of huge
+ localW hugeCnt ; segments making up huge seg
+ localW hugeFlags ; flags of huge segment (needed?)
+
+cBegin
+ call MapDStoDATA
+ ReSetKernelDS
+ mov es,hexe
+ mov si,es:[ne_segtab]
+ xor di,di
+ mov cSegs,di
+ inc di
+ cmp es:[ne_usage],di
+ je paloop
+ mov si,es:[ne_pautodata]
+ and byte ptr es:[si].ns_flags,not NSALLOCED+NSLOADED
+ mov di,es:[si].ns_handle
+ cCall FarAllocSeg,<essi>
+ or ax,ax
+ jz aa_nomem
+ inc cSegs
+outahere:
+ jmp pagood
+
+aa_nomem:
+ mov es,hexe
+ or byte ptr es:[si].ns_flags,NSALLOCED+NSLOADED
+ mov es:[si].ns_handle,di
+ jmp pafail3
+
+paloop:
+ cmp di,es:[ne_cseg]
+ jbe more_to_go
+ jmp pagood
+
+more_to_go:
+
+ mov bx,es:[si].ns_flags
+ test bl,NSPRELOAD ; Are we preloading?
+ jz not_preload
+ test bl,NSDATA ; Preload data although moveable
+ jnz paalloc
+if ROM
+ test bh,(NSINROM SHR 8) ; Segment in ROM?
+ jz @f
+ test bl,NSLOADED ; Yes, is it already 'loaded'?
+ jnz set_rom_owner ; Yes, just need to set owner
+@@:
+endif
+ test bl,NSMOVE ; Fixed segment?
+ jz paalloc ; Yes, allocate segment
+not_preload:
+
+if ROM
+ test bh,(NSINROM SHR 8) ; Segment in ROM?
+ jz @f
+if KDEBUG
+ test bl,NSDATA ; (non-preload data segments in ROM
+ jz not_rom_data ; haven't been tested)
+int 3
+not_rom_data:
+endif
+ test bl,NSLOADED ; Yes, already 'loaded'?
+ jnz set_rom_owner ; Yes, just need to set owner
+@@:
+endif
+ test bl,NSALLOCED ; Already allocated?
+ jnz panext ; Yes, then nothing to do
+ test bl,NSMOVE ; Fixed segment?
+ jz panext ; Yes, then nothing to do
+
+ xor cx,cx ; No, allocate zero length
+ push es ; object so that we guarantee
+ cCall FarMyAlloc,<bx,cx,cx> ; we will have a handle.
+ pop es
+ or dx,dx ; Fail if we cant get a handle
+ jz pafail
+if ROM
+
+; If this segment gets loaded from ROM, change the segment handle
+; to be the one that was used to fix-up the ROM code segments. This
+; is the value of ns_sector in the segment table.
+
+ test byte ptr es:[si].ns_flags+1,(NSINROM SHR 8)
+ jz not_a_rom_seg
+ mov bx,es:[si].ns_sector
+ test dl,GA_FIXED
+ jnz sa_fixed
+ StoH bx
+sa_fixed:
+ cCall ChangeROMHandle,<dx,bx>
+ mov dx,bx
+not_a_rom_seg:
+endif
+ mov es:[si].ns_handle,dx ; Handle into seg table
+ and byte ptr es:[si].ns_flags,not NSLOADED
+ or byte ptr es:[si].ns_flags,NSALLOCED
+
+ mov bx,dx ; put handle into base register
+ call set_discarded_sel_owner
+ jmps panext
+
+if ROM
+set_rom_owner:
+ cCall FarSetROMOwner,<es:[si].ns_handle,es>
+ jmps panext
+endif
+
+paalloc:
+
+ cmp es:[si].ns_minalloc, 0
+ jnz paalloc_fer_shure
+ jmps PAHugeAlloc
+
+paalloc_fer_shure:
+ cCall FarAllocSeg,<essi>
+ or ax,ax
+ jz pafail
+ inc cSegs
+panext:
+ add si,size NEW_SEG1
+ inc di
+ jmp paloop
+
+; only gets here if not enough memory, free up all previous segments
+
+pafail:
+ mov si,es:[ne_segtab]
+ mov cx,es:[ne_cseg]
+pafail1:
+ push cx
+ mov cx,es:[si].ns_handle
+ jcxz pafail2
+ push es
+ ;Need to handle freeing huge segments!!!
+ cCall FarMyFree,<cx>
+ pop es
+ mov es:[si].ns_handle, 0 ; Necessary for EntProcAddress
+pafail2:
+ and byte ptr es:[si].ns_flags,not (NSALLOCED+NSLOADED)
+ add si,size NEW_SEG1
+ pop cx
+ loop pafail1
+pafail3:
+ mov cSegs,-1
+ jmp pagood
+
+PAHugeAlloc:
+ ; at this point, es:si -> current seg record
+ ; di is segment index (range from 1 to es:[ne_cseg])
+ mov off_hugeLen, 0
+ mov seg_hugeLen, 0 ; init length to 0K
+
+ mov hugeOffs, si
+ mov hugeCnt, 1
+ mov ax, es:[si].ns_flags
+ or ax, NSHUGESEG
+ mov hugeFlags, ax
+PAHugeLoop:
+ mov ax, es:[si].ns_minalloc ; add current segment to group
+ cmp ax, 1
+ sbb dx, dx
+ neg dx
+ add off_hugeLen, ax
+ adc seg_hugeLen, dx
+ or es:[si].ns_flags, NSHUGESEG
+
+ cmp es:[si].ns_minalloc, 0 ;
+ jnz PAHugeEndLoop
+
+ cmp di, es:[ne_cseg]
+ jae PAHugeEndLoop
+
+ mov ax, si
+ add ax, size NEW_SEG1
+ cmp ax, es:[ne_pautodata]
+ jz PAHugeEndLoop
+
+ mov ax, hugeFlags ; do flags have to be identical?
+ cmp ax, es:[si].ns_flags
+ jnz PAHugeEndLoop
+
+ inc hugeCnt
+ inc di
+ add si, size NEW_SEG1
+ jmp PAHugeLoop
+
+PAHugeEndLoop:
+ inc di
+ push es
+ or hugeFlags, NSMOVE
+ cCall FarMyAllocLinear, <hugeFlags, hugeLen>
+ pop es
+ or ax, ax ; check for error
+ jnz Not_pafail
+ jmp pafail
+Not_pafail:
+
+ mov si, hugeOffs ; fix up segment(s)
+ and es:[si].ns_flags, NOT NSHUGESEG
+PAHugeSegLoop:
+ mov es:[si].ns_handle, dx
+ and byte ptr es:[si].ns_flags, not NSLOADED
+ or byte ptr es:[si].ns_flags, NSALLOCED
+ cCall FarSetOwner, <ax, es>
+ add si, size NEW_SEG1
+ add dx, __AHINCR
+ dec hugeCnt
+ jnz PAHugeSegLoop
+
+ ; continue with rest of allocations
+
+ jmp paloop
+
+pagood:
+ mov ax,cSegs
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldself.asm b/private/mvdm/wow16/kernel31/ldself.asm
new file mode 100644
index 000000000..c5b6805e3
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldself.asm
@@ -0,0 +1,566 @@
+
+ TITLE LDSELF - BootStrap procedure for KERNEL.EXE
+
+.xlist
+?NODATA=1
+?TF=1
+include kernel.inc
+include newexe.inc
+include tdb.inc
+.list
+
+externFP IGlobalAlloc
+externFP IGlobalLock
+externFP IGlobalUnlock
+
+DataBegin
+
+externW winVer
+;externW pGlobalHeap
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+;externW MyCSDS
+
+externNP SetOwner
+
+externFP set_discarded_sel_owner
+
+; extra debugging parameter for EntProcAddress to avoid RIPing if all
+; we are doing is a GetProcAddress to something that isn't there.
+externNP EntProcAddress
+cProc FarEntProcAddress,<PUBLIC,FAR,NODATA>
+ parmW hExe
+ parmW entno
+cBegin
+if KDEBUG
+ mov cx,1
+ cCall EntProcAddress,<hExe,entno,cx>
+else
+ cCall EntProcAddress,<hExe,entno>
+endif
+cEnd
+
+if KDEBUG
+
+; AppLoaderEntProcAddress
+; This call added for the app loader. The above call (FarEntProcAddress)
+; forces no RIPs. When we're using the app loader, we really want
+; RIPs, so in debug we add this entry point.
+; This call ONLY exists in debug.
+
+cProc AppLoaderEntProcAddress,<PUBLIC,FAR,NODATA>
+ parmW hExe
+ parmW entno
+cBegin
+ xor cx,cx ;Force RIPs on this one
+ cCall EntProcAddress,<hExe,entno,cx>
+cEnd
+
+endif ; KDEBUG
+
+
+externNP FindOrdinal
+cProc FarFindOrdinal,<PUBLIC,FAR,NODATA>
+ parmW hExe
+ parmD lpname
+ parmW fh
+cBegin
+ cCall FindOrdinal,<hExe,lpName,fh>
+cEnd
+
+
+externNP LoadSegment
+cProc FarLoadSegment,<PUBLIC,FAR,NODATA>
+ parmW hExe
+ parmW segno
+ parmW fh
+ parmW isfh
+cBegin
+ cCall LoadSegment,<hExe,segno,fh,isfh>
+cEnd
+
+
+externNP AllocSeg
+cProc FarAllocSeg,<PUBLIC,FAR,NODATA>
+ parmD pSegInfo
+cBegin
+ cCall AllocSeg,<pSegInfo>
+cEnd
+
+
+externNP DeleteTask
+cProc FarDeleteTask,<PUBLIC,FAR,NODATA,ATOMIC>
+ parmW taskID
+cBegin
+ cCall DeleteTask,<taskID>
+cEnd
+
+
+externNP UnlinkObject
+cProc FarUnlinkObject,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall UnlinkObject
+cEnd
+
+
+externNP MyLower
+cProc FarMyLower,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall MyLower
+cEnd
+
+
+externNP MyUpper
+cProc FarMyUpper,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall MyUpper
+cEnd
+
+
+externNP MyAlloc
+cProc FarMyAlloc,<PUBLIC,FAR,NODATA>
+ parmW aflags
+ parmW nsize
+ parmW nelem
+cBegin
+ cCall MyAlloc,<aflags,nsize,nelem>
+cEnd
+
+
+externNP MyAllocLinear
+cProc FarMyAllocLinear,<PUBLIC,FAR,NODATA>
+ parmW aflags
+ parmD dwBytes
+cBegin
+ cCall MyAllocLinear,<aflags,dwBytes>
+cEnd
+
+
+externNP MyLock
+cProc FarMyLock,<PUBLIC,FAR,NODATA>
+ parmW h1
+cBegin
+ cCall MyLock,<h1>
+cEnd
+
+
+externNP MyFree
+cProc FarMyFree,<PUBLIC,FAR,NODATA>
+ parmW h2
+cBegin
+ cCall MyFree,<h2>
+cEnd
+
+externNP genter
+cProc Far_genter,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall genter
+cEnd
+
+externNP gleave
+cProc Far_gleave,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall gleave
+cEnd
+
+externNP lalign
+cProc Far_lalign,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall lalign
+cEnd
+
+
+externNP lrepsetup
+cProc Far_lrepsetup,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall lrepsetup
+cEnd
+
+
+if KDEBUG
+
+externNP lfillCC
+cProc Far_lfillCC,<PUBLIC,FAR,NODATA,ATOMIC>
+cBegin
+ cCall lfillCC
+cEnd
+endif
+
+sEnd CODE
+
+
+
+
+sBegin INITCODE
+
+;-----------------------------------------------------------------------;
+; LKExeHeader ;
+; ;
+; Copy of LoadExeHeader (from LDHEADER.ASM) that has been stripped ;
+; down to the minimum needed to load the new format .EXE header for ;
+; KERNEL.EXE. ;
+; ;
+; Arguments: ;
+; parmW pMem ;
+; parmD pfilename ;
+; ;
+; Returns: ;
+; AX = segment of exe header ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Mar 19, 1987 08:35:32p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc LKExeHeader,<PUBLIC,NEAR>,<si,di,ds>
+ parmW pMem
+ parmD pfilename
+ localW nchars
+cBegin
+ lds si,pfilename
+ xor ax,ax
+ mov al,ds:[si].opLen
+ inc ax ; include null byte
+ mov nchars,ax
+
+ mov ds,pMem
+ xor si,si
+ mov di,ds:[si].ne_enttab ; Compute size of resident new header
+ add di, 6 ; Room for one block of entries
+ push si
+ mov si, ds:[si].ne_enttab ; Scan current entry table
+
+calc_next_block:
+ lodsw
+ xor cx, cx
+ mov cl, al
+ jcxz calc_ent_sized
+
+ cmp ah, ENT_UNUSED ; 6 bytes per unused block
+ jne calc_used_block
+ add di, 6
+ jmps calc_next_block
+
+calc_used_block:
+ errnz <5-SIZE PENT>
+ mov bx, cx
+ shl bx, 1
+ add di, bx
+ add di, bx ; 5 bytes per entry
+ add di, cx
+
+ add si, bx
+ add si, cx ; Skip the block
+ cmp ah, ENT_MOVEABLE
+ jne calc_next_block
+
+calc_moveable_block:
+ add si, bx
+ add si, cx ; Skip the block
+ jmps calc_next_block
+
+calc_ent_sized:
+ pop si
+ mov cx,ds:[si].ne_cseg ; + 3 * #segments
+
+; Reserve space for segment reference bytes
+
+ add di,cx
+ shl cx,1
+
+; Reserve space for ns_handle field in segment table
+
+ add di,cx
+ errnz <10-SIZE NEW_SEG1>
+
+if LDCHKSUM
+
+; Reserve space for segment chksum table (2 words per segment)
+
+ add di,cx
+ add di,cx
+endif
+
+
+; Reserve space for file info block at end
+
+ add di,16 ; 16 bytes of slop
+ add di,nchars ; + size of file info block
+
+ xor ax,ax ; Allocate a block for header
+ cCall IGlobalAlloc,<GA_MOVEABLE,ax,di>
+ push ax
+ cCall IGlobalLock,<ax>
+ pop ax
+ push dx
+ cCall IGlobalUnlock,<ax>
+ pop ax
+ mov es,ax ; ES:DI -> new header location
+ xor di,di
+ cld ; DS:SI -> old header
+ mov cx,SIZE NEW_EXE ; Copy fixed portion of header
+ cld
+ rep movsb
+ mov cx,es:[ne_cseg] ; Copy segment table
+ mov es:[ne_segtab],di
+recopyseg:
+
+if ROM
+
+; This code assumes kernel segments will not need to be reloaded from ROM
+; and so doesn't set the ns_sector field like LoadExeHeader().
+
+ lodsw ; ns_sector has segment selector in ROM
+ mov bx,ax
+ stosw
+else
+ movsw ; ns_sector
+endif
+ movsw ; ns_cbseg
+ lodsw ; ns_flags
+ errnz <4-ns_flags>
+ and ax,not NS286DOS ; Clear 286DOS bits
+if ROM
+ or ax,NENOTP+4000h+NSINROM+NSLOADED ; library code in ROM
+else
+ or ax,NENOTP+4000h ; Mark library code segments
+endif
+ stosw
+ movsw ; ns_minalloc
+ errnz <8-SIZE NEW_SEG>
+if ROM
+ mov ax,bx
+else
+ xor ax,ax
+endif
+ stosw ; one word for ns_handle field
+ errnz <10-SIZE NEW_SEG1>
+ loop recopyseg
+
+recopysegx:
+ mov cx,es:[ne_restab] ; Copy resource table
+ sub cx,es:[ne_rsrctab]
+ mov es:[ne_rsrctab],di
+ rep movsb
+rerestab:
+ mov cx,es:[ne_modtab] ; Copy resident name table
+ sub cx,es:[ne_restab]
+ mov es:[ne_restab],di
+ rep movsb
+
+ mov cx,es:[ne_imptab] ; Copy module xref table
+ sub cx,es:[ne_modtab]
+ mov es:[ne_modtab],di
+ rep movsb
+
+ mov es:[ne_psegrefbytes],di ; Insert segment reference byte table
+ mov cx,es:[ne_cseg]
+ mov al,0FFh
+ rep stosb ; initialize to not-loaded condition
+
+ mov es:[ne_pretthunks],di ; Setup return thunks
+
+if LDCHKSUM
+ mov es:[ne_psegcsum],di ; Setup segment chksum table
+ mov cx,es:[ne_cseg]
+ jcxz resetsegcsumexit
+ xor ax,ax
+ shl cx,1 ; Two words per segment
+ rep stosw
+resetsegcsumexit:
+endif
+ mov cx,es:[ne_enttab] ; Copy imported name table
+ sub cx,es:[ne_imptab]
+ mov es:[ne_imptab],di
+ jcxz reenttab
+ rep movsb
+
+reenttab:
+ mov es:[ne_enttab],di
+ ; Scan current entry table
+ xor ax, ax ; First entry in block
+ mov bx, di ; Pointer to info for this block
+ stosw ; Starts at 0
+ stosw ; Ends at 0
+ stosw ; And is not even here!
+
+copy_next_block:
+ lodsw ; Get # entries and type
+ xor cx, cx
+ mov cl, al
+ jcxz copy_ent_done
+
+ mov al, ah
+ cmp al, ENT_UNUSED
+ jne copy_used_block
+
+ mov ax, es:[bx].PM_EntEnd ; Last entry in current block
+ cmp ax, es:[bx].PM_EntStart ; No current block?
+ jne end_used_block
+
+int 3
+ add es:[bx].PM_EntStart, cx
+ add es:[bx].PM_EntEnd, cx
+ jmps copy_next_block
+
+end_used_block:
+ mov es:[bx].PM_EntNext, di ; Pointer to next block
+ mov bx, di
+ add ax, cx ; Skip unused entries
+ stosw ; First in new block
+ stosw ; Last in new block
+ xor ax, ax
+ stosw ; End of list
+ jmps copy_next_block
+
+copy_used_block:
+ add es:[bx].PM_EntEnd, cx ; Add entries in this block
+ cmp al, ENT_MOVEABLE
+ je copy_moveable_block
+
+copy_fixed_block:
+ stosb ; Segno
+ movsb ; Flag byte
+ stosb ; segno again to match structure
+ movsw ; Offset
+ loop copy_fixed_block
+ jmps copy_next_block
+
+copy_moveable_block:
+ stosb ; ENT_MOVEABLE
+ movsb ; Flag byte
+ add si, 2 ; Toss int 3Fh
+ movsb ; Copy segment #
+ movsw ; and offset
+ loop copy_moveable_block
+ jmps copy_next_block
+
+copy_ent_done:
+
+
+ xor bx,bx
+ mov es:[bx].ne_usage,1
+ mov es:[bx].ne_pnextexe,bx
+ mov es:[bx].ne_pautodata,bx
+
+ mov cx,nchars
+ mov es:[bx].ne_pfileinfo,di
+ lds si,pfilename
+ rep movsb
+
+ SetKernelDS
+ mov ax,winVer
+ mov es:[bx].ne_expver,ax
+if ROM
+ or es:[bx].ne_flags,NENONRES OR NEMODINROM ;have disc code & in ROM
+else
+ or es:[bx].ne_flags,NENONRES ; Remember that we have
+ ; discardable code
+endif
+ UnSetKernelDS
+ cCall SetOwner,<es,es>
+ mov ax,es
+reexit:
+cEnd
+
+ife ROM ;----------------------------------------------------------------
+
+cProc LKAllocSegs,<PUBLIC,NEAR>,<si,di,ds>
+ parmW hExe
+
+ localW fixed_seg
+ localW SegCount
+cBegin
+ mov ds,hExe
+ mov si,ds:[ne_segtab]
+ mov di,ds:[si].ns_minalloc
+ xor ax,ax
+ mov bx,(GA_ALLOC_LOW or GA_CODE_DATA) shl 8
+ cCall IGlobalAlloc,<bx,ax,di>
+ or ax,ax
+ jz lkallocfail
+ mov fixed_seg,ax
+ mov ds:[si].ns_handle,ax
+ and byte ptr ds:[si].ns_flags,not NSLOADED
+ or byte ptr ds:[si].ns_flags,NSALLOCED
+
+ cCall SetOwner,<ax,ds>
+
+ add si,SIZE NEW_SEG1 ; NRES segment
+ mov di,ds:[si].ns_sector
+ mov SegCount, 0 ; NRES and MISC segments
+
+;; SetKernelDS es
+;; cmp fWinX,0
+;; UnSetKernelDS es
+;; je lk1
+;; mov di,ds:[si].ns_cbseg
+;; xchg ds:[si].ns_minalloc,di
+;; xchg ds:[si].ns_sector,di
+;;lk1:
+
+SegLoop:
+ inc SegCount
+ xor ax,ax
+ mov bh,GA_DISCARDABLE + GA_SHAREABLE + GA_CODE_DATA
+ mov bl,GA_MOVEABLE + GA_DISCCODE
+ cCall IGlobalAlloc,<bx,ax,ax>
+ or ax,ax
+ jz lkallocfail
+ mov ds:[si].ns_handle,ax ; Handle into seg table
+ and byte ptr ds:[si].ns_flags,not NSLOADED
+ or byte ptr ds:[si].ns_flags,NSALLOCED
+ mov bx,ax ; put handle into base register
+ smov es,ds
+ call set_discarded_sel_owner
+ smov es,0
+ mov bx,ds:[si].ns_sector ; Save MiscCode sector
+ add si,SIZE NEW_SEG1 ; Next segment
+ cmp SegCount, 2
+ jnz SegLoop
+
+
+; Allocate fixed block for kernel's data segment
+
+ push bx ; Save MisCode sector
+ mov bx,ds:[si].ns_minalloc
+ xor ax,ax
+ cCall IGlobalAlloc,<ax,ax,bx>
+ pop bx
+ or ax,ax
+ jz lkallocfail
+ mov ds:[ne_pautodata], si
+ mov ds:[si].ns_handle,ax
+ and byte ptr ds:[si].ns_flags,not NSLOADED
+ or byte ptr ds:[si].ns_flags,NSALLOCED
+
+ cCall SetOwner,<ax,ds>
+
+ mov ax,di ; Return offset to NR segment
+lkallocfail:
+cEnd
+
+endif ;ROM ---------------------------------------------------------
+
+ nop ; Stop linker from padding segment
+
+sEnd INITCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldstack.asm b/private/mvdm/wow16/kernel31/ldstack.asm
new file mode 100644
index 000000000..d54e315f0
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldstack.asm
@@ -0,0 +1,106 @@
+
+ TITLE LDSTACK - stack walking procedure
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include eems.inc
+.list
+
+;externFP GlobalHandle
+;externFP FarLoadSegment
+
+;externW pStackTop
+;externW pStackBot
+
+DataBegin
+
+;externB Kernel_flags
+;externW segSwapArea
+;externW oOldSP
+;externW hOldSS
+;externW fEEMS
+;externW pGlobalHeap
+;externW curTDB
+;externW headTDB
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+;externNP MyLock
+;externNP LoadSegment
+
+sEnd CODE
+
+sBegin MISCCODE
+assumes cs, MISCCODE
+assumes ds, nothing
+assumes es, nothing
+
+jmpbuf struc
+jb_ret DD ?
+jb_sp DW ?
+jb_bp DW ?
+jb_si DW ?
+jb_di DW ?
+jb_hds DW ?
+jb_ip DW ?
+jb_hss DW ?
+jmpbuf ends
+
+savedSI = -4
+savedDI = -6
+
+cProcVDO Catch,<PUBLIC,FAR>,<ds,si,di>
+ parmD lpJmpBuf
+cBegin
+ push [bp].savedCS
+ push [bp].savedIP
+ push [bp].savedBP
+ les bx,lpJmpBuf
+ mov es:[bx].jb_hss,ss
+ mov es:[bx].jb_hds,ds
+ mov es:[bx].jb_di,di
+ mov es:[bx].jb_si,si
+ pop es:[bx].jb_bp
+ pop word ptr es:[bx].jb_ret[0]
+ pop word ptr es:[bx].jb_ret[2]
+ mov es:[bx].jb_sp,sp
+ xor ax,ax
+CatchRet:
+cEnd
+
+cProcVDO Throw,<PUBLIC,FAR>
+; parmD lpJmpBuf
+; parmW AXvalue
+cBegin nogen
+ mov bx,sp
+ mov di,ss:[bx+4]
+ lds si,ss:[bx+6]
+
+ mov ss,ds:[si].jb_hss
+ mov sp,ds:[si].jb_sp
+ mov bp,sp
+ add bp,-savedDI
+ push ds:[si].jb_bp
+ pop ss:[bp].savedBP
+ push ds:[si].jb_si
+ pop ss:[bp].savedSI
+ push ds:[si].jb_di
+ pop ss:[bp].savedDI
+ push ds:[si].jb_hds
+ pop ss:[bp].savedDS
+ mov ax,word ptr ds:[si].jb_ret[2]
+ mov ss:[bp].savedCS,ax
+ mov ax,word ptr ds:[si].jb_ret[0]
+ mov ss:[bp].savedIP,ax
+ mov ax,di
+ jmp CatchRet
+cEnd nogen
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/ldutil.asm b/private/mvdm/wow16/kernel31/ldutil.asm
new file mode 100644
index 000000000..d2b5e8e14
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ldutil.asm
@@ -0,0 +1,1322 @@
+ TITLE LDUTIL - Loader support procedures
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+.list
+
+;externFP GetCurrentPDB
+
+if ROM and PMODE32
+externFP HocusROMBase
+endif
+
+DataBegin
+
+;externB Kernel_Flags
+;externW AltfEEMS
+externW headTDB
+externW hExeHead
+;externW pGlobalHeap
+;externW MyCSDS
+externW topPDB
+externW cur_dos_pdb
+externW Win_PDB
+externW curTDB
+;externW segSwapArea
+
+DataEnd
+
+externFP CallWEP
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MyUpper
+externNP MyLock
+externNP LoadNRTable
+externNP LoadSegment
+externNP GetOwner
+externNP GetCachedFileHandle
+
+if SDEBUG
+externNP DebugFreeSegment
+endif
+
+externFP IGlobalAlloc
+externFP IGlobalFree
+;externFP IGlobalLock
+externFP IGlobalUnfix
+externFP IGlobalHandle
+externFP GlobalFlags
+externFP FreeNRTable
+externFP Int21Handler
+
+ifdef DBCS ;declare it.
+externNP MyIsDBCSLeadByte ;Use near one as we are in the same seg
+endif
+
+if ROM
+externFP FreeSelector
+externNP alloc_data_sel16
+endif
+
+cProc SafeCall,<PUBLIC,FAR>
+ parmD Addr
+cBegin
+ call Addr
+cEnd
+
+;-----------------------------------------------------------------------;
+; GetExePtr ;
+; ;
+; Returns the exe header pointer for the passed handle. ;
+; ;
+; Arguments: ;
+; parmW hinstance ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Aug 03, 1987 04:40:45p -by- David N. Weise [davidw] ;
+; Rewrote it to work with expanded memory. Note that if the handle ;
+; passed is truly bogus we could still catch a page fault under ;
+; Win386. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetExePtr,<PUBLIC,FAR>
+ parmW hinstance
+cBegin
+ mov ax,hinstance
+ test ax,GA_FIXED ; Passed a segment address?
+ jz not_module
+ mov es,ax
+ cmp es:[ne_magic],NEMAGIC ; Yes, does it point to a Module?
+ jz gxdone
+
+not_module:
+ SetKernelDS es
+ mov cx,headTDB
+ assumes es, nothing
+find_TDB:
+ jcxz last_chance
+ mov es,cx
+ cmp ax,es:[TDB_module]
+ jz found_it
+ mov cx,es:[TDB_next]
+ jmp find_TDB
+found_it:
+ mov ax,es:[TDB_pModule]
+ jmps gxdone
+
+last_chance: ; The problem here is that USER
+ cCall MyLock,<ax> ; KNOWS that hinstance is but
+ or ax,ax ; the handle to his data segment.
+ jz gxdone
+ mov es,ax
+ cmp es:[ne_magic],NEMAGIC
+ je gxdone
+
+ cCall GetOwner,<ax>
+ or ax,ax
+ jz gxfail
+ mov es,ax
+ cmp es:[ne_magic],NEMAGIC
+ je gxdone
+
+ ; The owner,ax, is now a PDB. We gotta find the TDB
+ SetKernelDS es
+ mov cx,headTDB
+ assumes es, nothing
+find_PDB:
+ jcxz gxfail
+ mov es,cx
+ cmp ax,es:[TDB_PDB]
+ jz found_PDB
+ mov cx,es:[TDB_next]
+ jmp find_PDB
+found_PDB:
+ mov ax,es:[TDB_pModule]
+ jmps gxdone
+
+
+gxfail:
+if KDEBUG
+ xor cx,cx
+ kerror ERR_LDMODULE,<Invalid module handle>,cx,hinstance
+endif
+ xor ax,ax
+gxdone: mov cx,ax
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; ;
+; GetExpWinVer - return the expected Windows version for a given ;
+; module handle ;
+; ;
+; Arguments: ;
+; parmW hinstance ;
+; ;
+; Returns: ;
+; AX = expected windows version ;
+; DX = BOOL proportional font flag ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri 06 Jan 1989 -- Written by Sankar. ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetExpWinVer,<PUBLIC,FAR>, <si,di>
+ parmW hInstance
+cBegin
+ cCall GetExePtr,<hInstance>
+ or ax,ax
+ jz err_GetExpWinVer
+ mov es,ax
+ mov ax,es:[ne_expver]
+ mov dx,es:[ne_flags]
+ and dx,NEWINPROT
+; error if offsets don't match our defines - In which case find the right
+; offsets and changes the defines in mvdm\inc\tdb16.h
+
+.erre (NE_LOWINVER_OFFSET EQ ne_expver)
+.erre (NE_HIWINVER_OFFSET EQ ne_flags)
+
+err_GetExpWinVer:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; MyAlloc ;
+; ;
+; Private interface to memory manager ;
+; ;
+; Arguments: ;
+; parmW aflags ;
+; parmW nsize ;
+; parmW nelem ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX = Handle ;
+; DX = Seg Address ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,ES ;
+; ;
+; Calls: ;
+; GlobalAlloc ;
+; MyLock ;
+; ;
+; History: ;
+; ;
+; Wed Apr 08, 1987 06:22:57a -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+ assumes ds, nothing
+ assumes es, nothing
+
+
+cProc MyAllocLinear,<PUBLIC,NEAR>
+ ; Same as MyAlloc, except for non-brain-dead size parameter
+ parmW aflags
+ parmD dwBytes
+cBegin
+ jmps MyAllocNotBrainDead
+cEnd
+
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc MyAlloc,<PUBLIC,NEAR>
+ parmW aflags
+ parmD dwBytes
+; parmW nsize
+; parmW nelem
+cBegin
+ xor dx,dx
+ mov ax,seg_dwBytes ;nsize
+ mov cx,off_dwBytes ;nelem
+ jcxz ma3
+ma2:
+ shl ax,1
+ rcl dx,1
+ loop ma2
+ma3:
+ mov seg_dwBytes, dx
+ mov off_dwBytes, ax
+MyAllocNotBrainDead:
+ SetKernelDS es
+ mov cx,aflags
+ mov al,NSTYPE
+ and al,cl ; al has SEGTYPE
+ mov bx,NSDISCARD
+ and bx,cx
+ jz @F
+ shr bx,1
+ shr bx,1
+ shr bx,1
+ shr bx,1 ; BX has GA_DISCARDABLE
+ cmp al,NSCODE
+ jne @F
+ or bl,GA_DISCCODE ; Allocating discardable code
+@@:
+
+ cmp al,NSDATA
+ jne @F
+ and cx,NOT NSWINCODE ; undo Excel bogusness
+ or bl,GA_DGROUP ; Allocating automatic data segment
+@@:
+
+ test cl,NSMOVE
+ jz @F
+ or bl,GA_MOVEABLE
+@@:
+
+ cmp al,NSTYPE
+ jz @F
+ or bh,GA_CODE_DATA
+@@:
+
+ cCall IGlobalAlloc,<bx,dwBytes> ;dxax>
+
+ assumes es, nothing
+ push ax
+ test al,GA_FIXED
+ jnz @F
+ cCall MyLock,<ax>
+@@:
+ pop dx
+cEnd
+
+
+;
+; MyLock( hseg ) - Procedure to return the physical segment address of
+; the passed handle.
+;
+;;;cProc MyLock,<PUBLIC,NEAR>
+;;; parmW hseg
+;;;cBegin
+;;; cCall IGlobalHandle,<hseg>
+;;; xchg dx,ax
+;;;cEnd
+
+
+;-----------------------------------------------------------------------;
+; MyFree ;
+; ;
+; Frees a segment allocated by MyAlloc. ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Dec 09, 1986 12:48:43p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc MyFree,<PUBLIC,NEAR>
+ parmW hseg
+ localW pseg
+cBegin
+ mov bx,hseg
+ or bx,bx
+ jz mf3
+ mov ax,bx
+ xor cx,cx
+ test bl,GA_FIXED
+ jnz mf0a
+
+ push bx
+ cCall GlobalFlags,<bx>
+ mov cx, ax
+ xor ax, ax
+ pop bx
+ xchg ch, cl
+ test cl, HE_DISCARDED
+ jnz mf0a
+ mov ax, bx
+ HtoS ax
+
+mf0a:
+if KDEBUG
+ push cx
+endif
+ mov pseg,ax
+ or ax,ax
+ jz mf1
+mf0:
+if SDEBUG
+ cCall DebugFreeSegment,<pseg,0>
+endif
+mf1:
+if KDEBUG
+ pop cx
+ or ch,ch
+ jz mf2
+mf1a:
+ push cx
+ cCall IGlobalUnfix,<hseg> ; Prevent RIP if freeing locked DS
+ pop cx
+ dec ch
+ or ch,ch ; If still lock, do it again
+ jnz mf1a
+endif
+mf2:
+ cCall IGlobalFree,<hseg>
+mf3:
+cEnd
+
+;-----------------------------------------------------------------------;
+; EntProcAddress
+;
+; Returns the fixed address of a procedure.
+;
+; Entry:
+;
+; Returns:
+; DX:AX = thunk for moveable
+; DX:AX = procedure for fixed
+; AX = constant, ES:BX => constant for absolutes
+; Registers Destroyed:
+;
+; History:
+; Wed 30-Nov-1988 19:39:05 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc EntProcAddress,<PUBLIC,NEAR>,<si,di>
+ parmW hExe
+ parmW entno
+if KDEBUG
+ parmW bNoRip ; if 1 don't RIP for error, 0 -> do the RIP
+endif
+
+cBegin
+ mov es,hExe
+ mov cx,entno
+ and cx,7fffh ; clear ResidentName bit (#5108 donc)
+ jcxz entfail
+ dec cx
+ mov si,es:[ne_enttab]
+
+entloop:
+ mov ax, es:[si.PM_entstart]
+ cmp cx, ax ; Below this block?
+ jb entfail ; yes, must be invalid!
+ cmp cx, es:[si.PM_entend] ; Above this block?
+ jae entnext ; yes, go to next block
+ sub cx, ax ; Found the right block, get offset
+ mov bx, cx
+ shl cx, 1
+ add bx, cx
+ add bx, cx ; bx = cx*5
+ lea si, [si+bx+size PM_entstruc]
+ mov bx, si
+ jmps gotent
+entnext:
+ mov si, es:[si.PM_entnext] ; Next block
+ or si, si
+ jnz entloop
+ jmps entfail
+
+entfail:
+if KDEBUG
+ cmp bNoRip,0
+ jnz dont_rip_here
+ mov bx,entno
+ krDebugOut <DEB_WARN or DEB_krLoadSeg>, "Invalid ordinal reference (##BX) to %ES1"
+; kerror ERR_LDORD,<Invalid ordinal reference to >,es,bx
+dont_rip_here:
+endif
+ xor dx,dx
+ xor ax,ax
+ jmps entdone
+
+; Here if the current block has the entry we want
+
+gotabs:
+ add bx,pentoffset ; make ES:BX point to constant (SLIME!)
+ mov dx,-1 ; make != 0 since abs might be!
+ jmps gotent1 ; Offset is symbol value
+
+gotent:
+ xor ax, ax
+ mov al, es:[bx].penttype ; Get segno/type field
+ mov si,es:[bx].pentoffset
+ cmp al,ENT_ABSSEG ; If segno field absoulute segment
+ je gotabs ; Yes, have absolute symbol
+
+ cmp al, ENT_MOVEABLE
+ je gotmoveable
+
+ .errnz 10 - SIZE NEW_SEG1
+ ; ax = segno
+ push bx
+ mov bx, es:[ne_segtab] ; see if really fixed
+ mov cx, ax ; look up in seg table
+ dec cx
+ shl cx, 1 ; get segtable + (segno-1)*10
+ add bx, cx
+ shl cx, 2
+ add bx, cx
+ test es:[bx].ns_flags, NSMOVE + NSALLOCED
+ pop bx
+ jnz gotmoveable
+
+ mov cx,-1 ; Fixed, make sure it's loaded
+ cCall LoadSegment,<es,ax,cx,cx>
+ or ax,ax
+ mov dx,ax
+ jnz gotent1
+ jmp entfail
+
+gotmoveable:
+ xor ax,ax
+ mov al,es:[bx].pentsegno ; Segment number
+ dec ax
+ shl ax,1
+ mov di,ax
+ shl ax,2
+ add di,ax
+ .errnz 10 - SIZE NEW_SEG1
+ add di,es:[ne_segtab]
+
+ mov dx,es:[di].ns_handle
+ or dx, dx
+ jnz ok
+ mov ax, dx ; No handle, probably from an aborted
+ jmps entdone ; LoadModule - just return 0:0
+ok:
+
+ Handle_To_Sel dl
+
+gotent1:
+ mov ax,si
+
+entdone:
+ mov cx,ax
+ or cx,dx
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FindOrdinal ;
+; ;
+; Searches the resident and non-resident name tables for a procedure ;
+; name and return its corresponding entry ordinal. ;
+; ;
+; Arguments: ;
+; parmW hExe ;
+; parmD lpname pointer name, strings starts with length ;
+; parmW fh file handle NOT to be discarded from cache ;
+; ;
+; Returns: ;
+; AX = ordinal number ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; MyUpper ;
+; LoadNRTable ;
+; FreeNRTable ;
+; ;
+; History: ;
+; ;
+; Tue 09-May-1989 18:38:04 -by- David N. Weise [davidw] ;
+; Added the batching if out of memory. ;
+; ;
+; Thu Sep 17, 1987 08:55:05p -by- David N. Weise [davidw] ;
+; Added this nifty comment block and fixed it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+CLNRBUFFER equ 150
+
+cProc FindOrdinal,<PUBLIC,NEAR>,<si,di>
+ parmW hExe
+ parmD lpname
+ parmW fh
+
+if ROM
+ localW fInROM
+endif
+ localD oNRTable ; if batching, continue here
+ localV LoadNRbuffer,CLNRBUFFER ; if batching this is temp buffer
+cBegin
+ xor ax,ax
+ mov oNRTable.hi,ax
+ mov oNRTable.lo,ax
+if ROM
+ mov fInROM,ax ; assume module not in ROM
+endif
+ les si,lpname
+ cmp byte ptr es:[si+1],'#'
+ je foint
+
+fonorm: push ds
+ mov ds,hExe
+if ROM
+ test ds:[ne_flags],NEMODINROM ; is module actually in ROM?
+ jz @f
+ inc fInROM
+@@:
+endif
+ mov si,ds:[ne_restab]
+ cld
+
+foinit: xor ax,ax ; Skip module name or description
+ lodsb
+ add si,ax
+ inc si
+ inc si
+
+foloop: lodsb ; get length of entry
+ les di,lpname
+ mov cx,ax
+ jcxz fodone ; no more entries?
+ cmp es:[di],al ; do lengths match?
+ jne noteq
+ inc di
+fo_find:
+ mov al,es:[di]
+ call MyUpper
+ mov bl,ds:[si]
+ inc si
+ inc di
+ cmp al,bl
+ jne noteq1
+ loop fo_find
+; repe cmpsb
+; jne noteq
+ lodsw ; get ordinal number!
+ mov bx,ds
+ pop ds
+ cmp hExe,bx ; did we load the nrtable?
+ jnz foexit_j
+ jmp foexit1
+foexit_j:
+ jmp foexit
+
+noteq1: dec cx
+noteq: add si,cx
+ inc si
+ inc si
+ jmps foloop
+
+; Here if pName points to string of the form: #nnnn
+
+foint: lods byte ptr es:[si] ; nbytes = *pName++
+ mov cl,al
+ xor ch,ch
+
+ dec cx ; ignore #
+ inc si
+
+ xor ax,ax ; sum = 0
+foint0: mov dx,ax
+ lods byte ptr es:[si] ; c = *pName++
+ sub al,'0' ; if (!isdigit(c))
+ cmp al,9
+ ja fonorm ; treat like normal
+ xor ah,ah
+ mov bx,ax ; sum = (sum * 10) + (c - '0')
+ mov al,10
+ mul dx
+ add ax,bx
+ loop foint0
+ jmp foexit1
+
+fodone: mov bx,ds
+ pop ds
+;%out help me ; what was this line for?
+ mov cx,oNRTable.hi
+ cmp cx,oNRTable.lo
+ jnz fo_batching
+ cmp hExe,bx ; have we looked at NRTable yet?
+if ROM
+ jne foexit_j
+else
+ jne foexit
+endif
+
+if ROM
+ cmp fInROM,0 ; this module in ROM?
+ jz fo_nr_not_in_rom
+ cCall FindROMNRTable,<hExe> ; yes, get selector to ROM NR Table
+ mov fInROM,ax
+ push ds
+ mov ds,ax ; ds -> ROM NR table
+ xor bx,bx
+ mov bl,ds:[0] ; skip over first NR table entry
+ lea si,[bx+3] ; (the module description string)
+ xor ax,ax
+ jmp foloop
+fo_nr_not_in_ROM:
+endif
+
+fo_batching:
+ xor bx,bx
+ mov ax,fh
+;;; cmp ax,-1
+;;; jz no_file_handle
+
+ SetKernelDS ES
+;;; mov dx, topPDB
+;;; mov es, curTDB
+;;; UnSetKernelDS es
+;;; mov ax, es:[TDB_PDB]
+;;;
+;;; cmp dx, cur_dos_pdb
+;;; jz @F
+;;; mov bx,ax
+;;;@@:
+ mov bx, Win_PDB
+ UnSetKernelDS
+
+ mov dx, -1
+ cCall GetCachedFileHandle,<hexe,ax,dx>
+no_file_handle:
+ push bx
+ lea cx,LoadNRbuffer
+ mov dx,CLNRBUFFER
+ cCall LoadNRTable,<hexe,ax,oNRTable,ss,cx,dx>
+if KDEBUG
+ push es
+ push di
+ les di, [lpName]
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, " looking for @ES:DI"
+ pop di
+ pop es
+endif
+ pop si
+ or si,si
+ jz @F
+;;; push ax
+;;; push bx
+;;; mov bx,si
+;;; mov ah,50h
+;;; DOSCALL
+;;; pop bx
+;;; pop ax
+ push es
+ SetKernelDS ES
+ mov Win_PDB, si
+ pop es
+ UnSetKernelDS ES
+@@: mov oNRTable.hi,cx
+ mov oNRTable.lo,bx
+ push ds
+ mov ds,dx
+ mov si,ax
+ or ax,dx ; did we get a table?
+ jz @F
+ xor ax,ax
+ jmp foloop
+@@: pop ds
+foexit: push ax
+if ROM
+ cmp fInROM,0 ; this module in ROM
+ jz @f
+ cCall FreeSelector,<fInROM> ; yes, free ROM NR table selector
+ jmps foexit0
+@@:
+endif
+ mov ax,ne_nrestab
+ cCall FreeNRTable,<hExe,ax>
+foexit0:
+ pop ax
+foexit1:
+
+;??? commented out 3/7/88 by rong
+;??? we should put this back in once everyone has the new keyboard driver
+;if KDEBUG
+; or ax,ax
+; jnz foexit2
+; les bx,lpname
+; inc bx
+; kerror ERR_LDNAME,<Invalid procedure name >,es,bx
+; xor ax,ax
+;foexit2:
+;endif
+cEnd
+
+
+if ROM ;----------------------------------------------------------------
+
+;-----------------------------------------------------------------------
+; FindROMNRTable
+;
+; Returns a selector to the ROM copy of the Non-Resident name table for
+; a module stored in ROM.
+;
+; Arguments:
+; parmW hExe
+;
+; Returns:
+; AX = selector mapping NR table
+;
+;-----------------------------------------------------------------------
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FindROMNRTable,<PUBLIC,NEAR>,<ds>
+ parmW hExe
+cBegin
+ mov ds,hExe
+ mov ax,word ptr ds:[ne_nrestab]
+ mov bx,word ptr ds:[ne_nrestab+2]
+ cCall alloc_data_sel16,<bx,ax,1000h>
+if PMODE32
+ cCall HocusROMBase, <ax>
+endif
+if KDEBUG
+ or ax,ax
+ jnz @f
+ int 3
+@@:
+endif
+cEnd
+
+endif ;ROM ---------------------------------------------------------
+
+; Search the list of new EXE headers for the passed executable file name
+; (no path)
+;
+; this must be resident so we can search for modules in the file handle
+; cache from the int 21 handler -- craigc
+;
+
+cProc ResidentFindExeFile,<PUBLIC,FAR>,<ds,si,di>
+ parmD pname
+cBegin
+ SetKernelDS
+
+ mov ax,hExeHead
+ffloop:
+ or ax,ax
+ jz ffdone
+ mov es,ax
+ mov di,es:[ne_pfileinfo]
+ or di,di
+ jz ffnext
+
+;
+; Double Byte Character is not able to search from the end of string,
+; so this function must search from the top of string.
+;
+ifdef DBCS
+ lea si,[di.opFile] ; get address of file name
+ mov cl,es:[di.opLen] ; get structure length
+ xor ch,ch
+ add cx,di
+ mov di,cx ; save end address
+ sub cx,si ; get length of file name
+ mov bx,si ; save top address of file name
+ cld
+delineator_loop:
+ lods byte ptr es:[si]
+ call MyIsDBCSLeadByte
+ jc delineator_notlead ; if not DBCS lead byte
+ dec cx
+ jcxz delineator_next
+ inc si
+ loop delineator_loop
+ jmp delineator_next
+delineator_notlead:
+ cmp al,"\"
+ jz found_delineator
+ cmp al,":"
+ jz found_delineator
+ loop delineator_loop
+ jmp delineator_next
+found_delineator:
+ mov bx,si ; save delineator address
+ loop delineator_loop
+delineator_next:
+ xchg bx,di ; set address of file name to di
+ sub bx,di ; get lenfth of file name
+else
+ mov si,di
+ xor cx,cx
+ mov cl,es:[di]
+ add si,cx
+ dec si
+ std
+ xor bx,bx
+delineator_loop: ; look for beginning of name
+ lods byte ptr es:[si]
+ cmp al,"\"
+ jz found_delineator
+ cmp al,":"
+ jz found_delineator
+ inc bx
+ loop delineator_loop
+ dec si
+found_delineator: ; ES:SI -> before name
+ mov di,si
+ inc di
+ inc di
+endif
+
+ lds si,pname
+ UnSetKernelDS
+ mov cx,bx
+ cld
+ repe cmpsb
+ mov ax,es
+ je ffdone
+ffnext:
+ mov ax,word ptr es:[ne_pnextexe]
+ jmp ffloop
+ffdone:
+cEnd
+
+sEnd CODE
+
+externFP FarLoadSegment
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP DelModule
+externNP MapDStoDATA
+
+cProc FindExeFile,<PUBLIC,NEAR>
+ parmD pFile
+cBegin
+ cCall ResidentFindExeFile, <pFile>
+cEnd
+
+
+; Search the list of new EXE headers for the passed executable name
+
+cProc FindExeInfo,<PUBLIC,NEAR>,<ds,si,di>
+ parmD pname
+ parmW nchars
+cBegin
+
+ cCall MapDStoDATA
+ ReSetKernelDS
+
+ mov bx,nchars
+ mov ax,hExeHead
+feloop:
+ or ax,ax
+ jz fedone
+ mov es,ax
+ mov di,es:[ne_restab]
+ cmp es:[di],bl
+ jne fenext
+ inc di
+ lds si,pname
+ UnSetKernelDS
+ mov cx,bx
+ repe cmpsb
+ je fedone
+fenext:
+ mov ax,word ptr es:[ne_pnextexe]
+ jmp feloop
+fedone:
+cEnd
+
+cProc FarFindExeInfo,<PUBLIC,FAR>
+ parmD pname
+ parmW nchars
+cBegin
+ cCall FindExeInfo,<pname,nchars>
+cEnd
+
+
+;
+; IncExeUsage( hExe ) - procedure to increment the usage count of this
+; EXE header. Indirectly increments the usage count of all the EXE
+; headers it points to.
+;
+cProc IncExeUsage,<PUBLIC,NEAR>,<ax,di>
+ parmW hexe
+cBegin
+ mov cx,hexe
+ jcxz iexj
+ mov es,cx
+ cmp es:[ne_magic],NEMAGIC
+ jne iexj
+ test es:[ne_usage],8000h
+ jz iego
+iexj:
+ krDebugOut <DEB_ERROR or DEB_KRLOADMOD>, "IncExeUsage(#ES) not DLL"
+ jmp iex
+iego:
+
+ cmp es:[ne_usage], 4000h
+ jb OKusage
+ krDebugOut DEB_FERROR, "IncExeUsage: ne_usage overflow"
+OKusage:
+
+ ;
+ ; Save time and space by saving stuff on stack
+ ; rather than recursing.
+ ;
+
+ or es:[ne_usage], 8000h
+NextExe0:
+ or es:[ne_usage], 4000h ; Mark node visited
+ inc es:[ne_usage]
+;if kdebug
+; push ax
+; mov ax, es:[ne_usage]
+; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "IncExeUsage(%ES0) #ax"
+; pop ax
+;endif
+ mov cx,es:[ne_cmod]
+ jcxz NoDeps0
+ mov di,es:[ne_modtab]
+ieloop:
+ push es
+ cmp word ptr es:[di], 0
+ je ieloop1
+ lar ax, es:[di] ; Make sure valid selector
+ jnz ieloop1
+ mov es, es:[di]
+ cmp es:[ne_magic],NEMAGIC
+ jne ieloop1
+ test es:[ne_usage], 0C000h
+ jnz ieloop1
+ push cx
+ push di ; Fake recursion
+ jmp NextExe0
+NextExeDone0: ; Return from fake recursion
+ pop di
+ pop cx
+ieloop1:
+ pop es
+ add di,2
+ loop ieloop
+
+NoDeps0:
+ mov cx, es
+ cmp cx, hExe
+ jne NextExeDone0
+
+NextExe1:
+ and es:[ne_usage], NOT 4000h ; Mark node visited
+ mov cx,es:[ne_cmod]
+ jcxz NoDeps1
+ mov di,es:[ne_modtab]
+UnMarkLoop:
+ push es
+ cmp word ptr es:[di], 0
+ je UnMarkLoop1
+ lar ax, es:[di] ; Make sure valid selector
+ jnz UnMarkLoop1
+ mov es, es:[di]
+ cmp es:[ne_magic],NEMAGIC
+ jne UnMarkLoop1
+ test es:[ne_usage], 08000h
+ jnz UnMarkLoop1
+ test es:[ne_usage], 04000h
+ jz UnMarkLoop1
+ push cx
+ push di ; Fake recursion
+ jmp NextExe1
+NextExeDone1: ; Return from fake recursion
+ pop di
+ pop cx
+UnMarkLoop1:
+ pop es
+ add di,2
+ loop UnMarkLoop
+
+NoDeps1:
+ mov cx, es
+ cmp cx, hExe
+ jne NextExeDone1
+
+ xor es:[ne_usage], 8000h
+iex:
+cEnd
+
+;-----------------------------------------------------------------------;
+; DecExeUsage ;
+; ;
+; Decrements the usage count of the given EXE header. Indirectly ;
+; decrements the usage count of all the EXE headers it points to. ;
+; ;
+; Arguments: ;
+; parmW hexe ;
+; ;
+; Returns: ;
+; ZF = 1 if usage count is now zero. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; DecExeUsage ;
+; DelModule ;
+; ;
+; History: ;
+; ;
+; Mon Sep 21, 1987 01:21:00p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc DecExeUsage,<PUBLIC,NEAR>,<ds,di,si>
+ parmW hexe
+cBegin
+ call MapDStoDATA
+ ReSetKernelDS
+
+ xor si,si
+ mov cx,hexe
+ xor ax,ax
+ jcxz dexj
+ mov es,cx
+ cmp es:[si].ne_magic,NEMAGIC
+ jne dexj
+ test es:[si].ne_usage,8000h
+ jz dego
+dexj:
+ krDebugOut <DEB_ERROR or DEB_KRLOADMOD>, "DecExeUsage(#ES) not DLL"
+ jmp dex
+dego:
+
+ ;
+ ; Save time and space by saving stuff on stack
+ ; rather than recursing.
+ ;
+
+ dec es:[si].ne_usage
+ or es:[si].ne_usage, 8000h
+;if kdebug
+; push ax
+; mov ax, es:[si].ne_usage
+; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage(%ES0) #ax"
+; pop ax
+;endif
+NextExe2:
+ or es:[si].ne_usage, 4000h ; Mark node visited
+ mov cx,es:[si].ne_cmod
+ jcxz NoDeps2
+ mov di,es:[si].ne_modtab
+MarkLoop2:
+ push es
+ cmp si, es:[di]
+ je MarkLoop3
+ lar ax, es:[di] ; Make sure valid selector
+ jnz MarkLoop3
+ mov es, es:[di]
+ cmp es:[si].ne_magic,NEMAGIC
+ jne MarkLoop3
+ test es:[si].ne_usage, 0C000h
+ jnz MarkLoop3
+ push cx
+ push di ; Fake recursion
+ jmp NextExe2
+NextExeDone2: ; Return from fake recursion
+ pop di
+ pop cx
+MarkLoop3:
+ pop es
+ add di,2
+ loop MarkLoop2
+
+NoDeps2:
+ mov cx, es
+ cmp cx, hExe
+ jne NextExeDone2
+
+ xor cx, cx
+ push cx ; End of list of Exes to delete
+ mov di, hExeHead ; Scan Exes once to dec them
+scan_exes:
+ or di, di
+ jz de_done
+ mov es, di
+ mov di, es:[si].ne_pnextexe
+ test es:[si].ne_usage, 4000h
+ jz scan_exes
+ and es:[si].ne_usage, NOT 4000h ; Remove the mark
+ test es:[si].ne_usage, 8000h ; Skip this one?
+ jnz scan_exes
+; krDebugOut <DEB_TRACE or DEB_krLoadMod>, "DecExeUsage dependent %ES0"
+ dec es:[si].ne_usage
+ jnz scan_exes
+ push es ; We will delete this one
+ jmps scan_exes
+
+
+de_done: ; Call WEP each module before
+ mov bx, sp ; we free any modules
+de_done0:
+ mov cx, ss:[bx]
+ add bx, 2
+ jcxz de_done1
+ push bx
+ cCall CallWEP, <cx, 0>
+ pop bx
+ jmps de_done0
+
+
+de_done1:
+ pop cx ; Get next module to delete
+ jcxz all_deleted
+ cCall DelModule,<cx> ; Delete him
+ jmps de_done1
+
+all_deleted:
+ mov es, hExe
+ and es:[si].ne_usage,NOT 0C000h
+dex:
+cEnd
+
+
+;
+; StartProcAddress( hExe ) - procedure to return the fixed address of
+; a new EXE start procedure
+;
+cProc StartProcAddress,<PUBLIC,NEAR>,<di>
+ parmW hexe
+ parmW fh
+cBegin
+ mov es,hexe
+ mov di,ne_csip
+ xor dx,dx
+ mov ax,es:[di+2]
+ or ax,ax
+ jz sp1
+ mov di,es:[di]
+ cCall FarLoadSegment,<es,ax,fh,fh>
+ jcxz sp1
+ mov ax,di ; DX:AX is start address of module
+sp1: ; (DX is really a handle)
+ mov cx,ax
+ or cx,dx
+cEnd
+
+
+
+; GetStackPtr - returns the initial SS:SP for a module.
+;
+cProc GetStackPtr,<PUBLIC,NEAR>,<si>
+ parmW hExe
+cBegin
+ mov es,hExe
+if KDEBUG
+ cmp es:[ne_sssp].sel,0
+ jnz @F
+ mov cx,ne_sssp
+ fkerror 0,<Invalid stack segment>,es,cx
+@@:
+endif
+ cmp es:[ne_sssp].off,0
+ jne re3
+ mov dx,es:[ne_stack]
+ mov bx,es:[ne_pautodata]
+ or bx,bx
+ jz re2
+ add dx,es:[bx].ns_minalloc
+re2: and dx,0FFFEh ; Word aligned stack
+ mov word ptr es:[ne_sssp],dx
+
+re3: mov dx,es:[ne_sssp].sel
+ mov ax,es:[ne_sssp].off
+ push ax
+ mov cx,-1
+ cCall FarLoadSegment,<es,dx,cx,cx>
+ pop ax ; Handle in DX and offset in AX
+cEnd
+
+
+
+
+;
+; GetInstance( hExe ) - Procedure to return the instance handle for
+; the current automatic data segment associated with the passed exe
+;
+cProc GetInstance,<PUBLIC,NEAR>
+ parmW hexe
+cBegin
+ mov es,hexe
+ mov ax,es:[ne_flags]
+ test ax,NEINST+NESOLO
+ mov ax,es
+ jz gidone
+ mov bx,es:[ne_pautodata]
+ or bx,bx
+ jz gidone
+ mov ax,es:[bx].ns_handle
+gidone:
+ mov cx,ax
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/lhandle.asm b/private/mvdm/wow16/kernel31/lhandle.asm
new file mode 100644
index 000000000..098e8a9f6
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lhandle.asm
@@ -0,0 +1,274 @@
+ TITLE HANDLE - Handle Table Manager
+
+include kernel.inc
+
+; This code assumes the following conditions
+;
+errnz <lhe_address>
+
+DataBegin
+
+;externW <pGlobalHeap,hGlobalHeap>
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+; These are all of the internal subroutines defined in this source file.
+;
+; PUBLIC halloc, lhdref, henum
+
+
+;-----------------------------------------------------------------------;
+; halloc ;
+; ;
+; Allocates a local handle for a block. ;
+; ;
+; Arguments: ;
+; AX = block that needs a handle ;
+; DS:DI = address of local arena infomation structure ;
+; ;
+; Returns: ;
+; AX,BX,CX = handle for that block ;
+; DX preserved ;
+; ;
+; Error Returns: ;
+; AX = 0 if no handles available ;
+; DX = original AX ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Wed Oct 01, 1986 05:44:44p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc halloc,<PUBLIC,NEAR>
+cBegin nogen
+ mov bx,[di].hi_hfree
+ or bx,bx
+ jnz have_a_handle
+ push ax
+ push dx
+ mov cx,[di].hi_hdelta
+ jcxz hafail
+ push si
+ push es
+ call [di].hi_hexpand
+ pop es
+ pop si
+ jcxz hafail
+ mov bx,ax
+ pop dx
+ pop ax
+have_a_handle:
+ xor cx,cx
+ errnz <lhe_flags - he_flags>
+ mov word ptr [bx].lhe_flags,cx ; Zero lock count and flags
+ errnz <lhe_count-lhe_flags-1>
+ errnz <lhe_link - he_link>
+ xchg [bx].lhe_link,ax ; Remove handle from head of chain
+ errnz <lhe_address-lhe_link> ; and store true address of object
+ mov [di].hi_hfree,ax ; Update head of handle free list
+ mov ax,bx ; Return handle to caller
+ mov cx,ax
+ ret
+
+hafail:
+ xor ax,ax
+ pop dx ; Flush stack
+ pop dx ; Return original AX in DX
+ ret ; return error
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lhfree ;
+; ;
+; Frees the given local handle and returns a handle to the freelist. ;
+; ;
+; Arguments: ;
+; SI = handle to free ;
+; ;
+; Returns: ;
+; AX = 0 if valid handle ;
+; ;
+; Error Returns: ;
+; AX = -1 if handle already free ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 04:14:25p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lhfree,<PUBLIC,NEAR>
+cBegin nogen
+ or si,si ; Ignore zero handles
+ jz hf1
+ mov ax,HE_FREEHANDLE ; Mark handle as free
+ xchg word ptr [si].lhe_flags,ax
+ errnz <2-lhe_flags>
+ inc ax ; Already free?
+ jz hf2 ; Yes, return error
+ errnz <1+HE_FREEHANDLE>
+ mov ax,si ; Push handle on head of freelist
+ xchg [di].hi_hfree,ax
+ mov [si].lhe_link,ax
+hf1:
+ xor ax,ax ; Return zero
+ ret
+hf2:
+ dec ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lhdref ;
+; ;
+; Dereferences a local handle. ;
+; ;
+; Arguments: ;
+; SI = handle ;
+; ;
+; Returns: ;
+; AX = address of client data or zero for discarded objects ;
+; CH = lock count ;
+; CL = zero or LHE_DISCARDED flag ;
+; ZF = 1 AX = 0 and CL != 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 04:16:49p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lhdref,<PUBLIC,NEAR>
+cBegin nogen
+ xor ax,ax
+ mov cx,word ptr [si].lhe_flags
+ errnz <2-lhe_flags>
+ errnz <3-lhe_count>
+ inc cx
+ jz lhdref1
+ errnz <1+LHE_FREEHANDLE>
+ dec cx
+ and cl,LHE_DISCARDED
+ jnz lhdref1
+ mov ax,[si].lhe_address
+lhdref1:
+ or ax,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; henum ;
+; ;
+; Enumerates the allocated handles in the local handle table with the ;
+; specified discard level. ;
+; ;
+; Arguments: ;
+; SI = zero first time called. Otherwise contains a pointer ;
+; to the last handle returned. ;
+; CX = #handles remaining. Zero first time called. ;
+; DI = address of local arena information structure. ;
+; ;
+; Returns: ;
+; SI = address of handle table entry ;
+; CX = #handles remaining, including the one returned. ;
+; ZF = 1 if SI = 0 and no more handle table entries. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; AX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 04:19:15p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc henum,<PUBLIC,NEAR>
+cBegin nogen
+ or si,si ; Beginning of enumeration?
+ jnz lcdhenext ; No, return next handle
+ mov ax,[di].hi_htable ; Yes, start with last handle table block
+
+lcdhtloop:
+ mov si,ax ; SI = address of handle table block
+ or si,si ; Any more handle table blocks?
+ jz lcdheall ; No, return zero
+ lodsw ; Get # handles in this block
+ errnz ht_count
+ mov cx,ax ; into CX
+lcdheloop: ; Loop to process each handle table entry
+ mov ax,word ptr [si].lhe_flags
+ errnz <lhe_flags - he_flags>
+ errnz <2-lhe_flags>
+ errnz <3-lhe_count>
+
+ inc ax ; Free handle?
+ jz lcdhenext ; Yes, skip this handle
+ errnz <1+LHE_FREEHANDLE>
+ errnz <LHE_FREEHANDLE - HE_FREEHANDLE >
+ dec ax
+
+ cmp [di].hi_dislevel,0 ; Enumerating all allocated handles?
+ je lcdheall ; Yes, return this handle
+
+ test al,LHE_DISCARDED ; No, handle already discarded?
+ jnz lcdhenext ; Yes, skip this handle
+
+ and al,LHE_DISCARDABLE ; Test if DISCARDABLE
+ cmp [di].hi_dislevel,al ; at the current discard level
+ jne lcdhenext ; No, skip this handle
+
+ or ah,ah ; Is handle locked?
+ jnz lcdhenext ; Yes, skip this handle
+
+lcdheall:
+ or si,si ; No, then return handle to caller
+ ret ; with Z flag clear
+
+lcdhenext:
+ lea si,[si].SIZE LocalHandleEntry ; Point to next handle table entry
+ errnz <LocalHandleEntry - HandleEntry>
+ loop lcdheloop ; Process next handle table entry
+ lodsw ; end of this block, go to next
+ jmp lcdhtloop
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/linterf.asm b/private/mvdm/wow16/kernel31/linterf.asm
new file mode 100644
index 000000000..50a06fdc3
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/linterf.asm
@@ -0,0 +1,1572 @@
+ TITLE LINTERF - Local memory allocator, interface procedures
+
+.xlist
+include tdb.inc
+include kernel.inc
+.list
+
+.errnz la_prev ; This code assumes la_prev = 0
+
+if KDEBUG
+CheckHeap MACRO n
+local a
+ extrn CheckLocalHeap:NEAR
+ cCall CheckLocalHeap
+ or ax,ax
+ jz a
+ or ax,ERR_LMEM
+ kerror <>,<&n: Invalid local heap>
+a:
+ endm
+else
+CheckHeap MACRO n
+ endm
+endif
+
+externW pLocalHeap
+
+externFP <GlobalHandle,GlobalReAlloc,GlobalSize,GlobalCompact,GlobalFlags>
+externFP <GlobalLock,GlobalUnlock>
+externFP <GlobalMasterHandle,GetCurrentTask>
+externFP FarValidatePointer
+externFP DibRealloc
+
+DataBegin
+
+externW curTDB
+;externW MyCSDS
+
+if KDEBUG
+externW DebugOptions
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP <halloc,lhfree,lhdref,hthread> ; LHANDLE.ASM
+externNP <ljoin,lrepsetup,lzero> ; LALLOC.ASM
+externNP <lalloc,lfree,lfreeadd,lfreedelete> ; LALLOC.ASM
+externNP <lcompact,lshrink> ; LCOMPACT.ASM
+
+if KDEBUG
+externNP <CheckLAllocBreak>
+endif ;KDEBUG
+
+;-----------------------------------------------------------------------;
+; lenter ;
+; ;
+; Enters a critical region for the local heap. ;
+; ;
+; Arguments: ;
+; DS = automatic data segment containing local heap ;
+; ;
+; Returns: ;
+; DS:DI = address of LocalInfo for local heap ;
+; (li_lock field has been incremented) ;
+; ;
+; Error Returns: ;
+; CX == 1 if heap is busy ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Oct 13, 2086 09:27:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lenter,<PUBLIC,NEAR>
+cBegin nogen
+ mov di,pLocalHeap
+ mov cx,1
+ xchg [di].li_lock,cx
+ jcxz enter1
+
+; Should really do a WaitEvent
+
+if KDEBUG
+ xor bx,bx
+ kerror ERR_LMEMCRIT,<lenter: local heap is busy>,bx,cx
+endif
+
+enter1: ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lleave ;
+; ;
+; Leaves a critical region for the local heap. ;
+; ;
+; Arguments: ;
+; DS = automatic data segment containing local heap ;
+; ;
+; Returns: ;
+; DS:DI = address of LocalInfo for local heap ;
+; (li_lock field has been cleared) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Oct 13, 2086 09:30:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lleave,<PUBLIC,NEAR>
+cBegin nogen
+ mov di,pLocalHeap
+ xor cx,cx
+ xchg ds:[di].li_lock,cx
+ jcxz leave1
+ ret
+leave1:
+
+; Should really do a PostEvent
+if KDEBUG
+ kerror ERR_LMEMCRIT,<lleave: local heap was not busy>
+endif
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lhexpand ;
+; ;
+; Expands a local handle table. ;
+; ;
+; Arguments: ;
+; CX = #handle entries to allocate ;
+; DS:DI = local info structure ;
+; ;
+; Returns: ;
+; AX = address of handle table block of requested size ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; lalloc ;
+; hthread ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 01:48:21p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lhexpand,<PUBLIC,NEAR>
+cBegin nogen
+ xor ax,ax ; Allocate fixed local block
+ mov bx,cx
+ inc bx ; plus 1 for word at beginning & end
+ shl bx,1
+ shl bx,1
+ errnz <4-SIZE LocalHandleEntry>
+ push cx
+ call lalloc
+ pop cx
+ or ax,ax
+ jz lhfail
+ mov bx,ax
+ xchg [di].hi_htable,bx
+ push di ; Save DI
+ mov di,ax
+ mov ds:[di],cx
+ inc di
+ inc di
+ call hthread
+ mov ds:[di],bx ; Store pointer to next block
+ pop di ; Restore DI
+lhfail: mov cx,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lalign ;
+; ;
+; Aligns the size request for a local item to a multiple of 4 bytes. ;
+; ;
+; Arguments: ;
+; CF = 0 ;
+; BX = #bytes ;
+; CF = 1 get max amount ;
+; ;
+; Returns: ;
+; DX = #bytes aligned to next higher multiple of 4 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue March 10, 1987 -by- Bob Gunderson [bobgu] ;
+; To accomidate free list, must impose a minimum block size to prevent ;
+; allocating a block on top of the extended header of previous block. ;
+; ;
+; Tue Oct 14, 1986 01:56:42p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lalign,<PUBLIC,NEAR>
+cBegin nogen
+ jnc align0
+ mov bx,LA_MASK
+align0: cmp bx,SIZE LocalArenaFree
+ jae align2
+ mov bx,SIZE LocalArenaFree ; Must impose a minimum size
+align2: lea dx,[bx+LA_ALIGN]
+ and dl,LA_MASK
+ cmp dx,bx ; Test for overflow
+ jae align1 ; No, continue
+ mov dx,LA_MASK ; Yes, return largest possible size
+align1: ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ldref ;
+; ;
+; Dereferences a local handle. ;
+; ;
+; Arguments: ;
+; SI = handle ;
+; ;
+; Returns: ;
+; AX = address of client data ;
+; BX = address of arena header ;
+; CH = lock count or zero for fixed objects ;
+; SI = handle table entry address or zero for fixed objects ;
+; ZF = 1 if NULL handle passed in ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CL ;
+; ;
+; Calls: ;
+; lhdref ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 01:58:58p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc ldref,<PUBLIC,NEAR>
+cBegin nogen
+ xor cx,cx ; Zero lock count
+ mov ax,si ; Return handle if fixed object
+ test al,LA_MOVEABLE ; Is it moveable?
+ jnz dref3 ; Yes, go dereference handle
+ xor si,si ; Set SI to zero for fixed objects
+ or ax,ax ; No, were we passed NULL?
+ jz dref2 ; Yes, then all done
+dref1: mov bx,ax ; No, return BX pointing
+ and bl,LA_MASK ; ...to arena header
+ sub bx,la_fixedsize ; Leaving ZF = 0
+dref2: ret
+
+dref3: call lhdref ; Get true address in AX
+ ; and lock count in CH
+ife KDEBUG
+ jz done ; Compute arena header if valid true address
+ mov bx,ax ; See if arena header points to
+ sub bx,SIZE LocalArena
+done: ret ; No, return with ZF = 1
+else
+ test cl,LHE_DISCARDED ; Discarded?
+ jnz dref5 ; Yes, all done
+ or ax,ax ; Is there a true address?
+ jz dref4 ; No, then must be error
+ mov bx,ax ; See if arena header points to
+ sub bx,SIZE LocalArena
+ cmp [bx].la_handle,si ; handle table entry?
+ je dref5 ; Yes, continue
+dref4: xor bx,bx
+ kerror ERR_LMEMHANDLE,<LDREF: Invalid local handle>,bx,si
+ xor ax,ax
+dref5: or ax,ax
+ ret
+endif
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lnotify ;
+; ;
+; Calls the local heap's notify proc (if any). ;
+; ;
+; Arguments: ;
+; AL = message code ;
+; BX = handle or largest free block ;
+; CX = optional argument ;
+; ;
+; Returns: ;
+; AX = return value from notify proc or AL ;
+; ZF = 1 if AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 02:03:14p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lnotify,<PUBLIC,NEAR>
+cBegin nogen
+ cmp word ptr [di+2].li_notify,0
+ je notify1
+ xor ah,ah
+ cCall [di].li_notify,<ax,bx,cx>
+notify1:
+ or ax,ax
+ ret
+cEnd nogen
+
+
+; The remainder of this file implements the exported interface to the
+; local memory manager. A summary follows:
+;
+; HANDLE far PASCAL LocalAlloc( WORD, WORD );
+; HANDLE far PASCAL LocalReAlloc( HANDLE, WORD, WORD );
+; HANDLE far PASCAL LocalFree( HANDLE );
+; WORD far PASCAL LocalSize( HANDLE );
+; char * far PASCAL LocalLock( HANDLE );
+; BOOL far PASCAL LocalUnlock( HANDLE );
+; WORD far PASCAL LocalCompact( WORD );
+; WORD far PASCAL LocalShrink( HANDLE , WORD );
+; FARPROC far PASCAL LocalNotify( FARPROC );
+; #define LocalDiscard( h ) LocalReAlloc( h, 0, LMEM_MOVEABLE )
+; BOOL far PASCAL LocalInit( char *, char * );
+;
+; extern WORD * PASCAL pLocalHeap;
+;
+; #define dummy 0
+; #define LocalFreeze( dummy ) ( *(pLocalHeap+1) += 1 )
+; #define LocalThaw( dummy ) ( *(pLocalHeap+1) -= 1 )
+;
+
+cProc ILocalAlloc,<PUBLIC,FAR>,<si,di>
+ parmW flags
+ parmW nbytes
+cBegin
+ WOWTrace "LocalAlloc(#AX,#BX)",<<ax,flags>,<bx,nbytes>>
+ CheckHeap LocalAlloc
+ call lenter ; About to modify memory arena
+ jcxz la_ok
+ xor ax, ax
+ jmp la_crit
+la_ok:
+ mov ax,flags ; Allocate space for object
+ test al,LA_NOCOMPACT
+ jz all0
+ inc [di].hi_freeze
+all0: mov bx,nbytes
+ or bx,bx ; Zero length?
+ jnz alloc0 ; No, continue
+ and ax,LA_MOVEABLE ; Yes, moveable?
+ jz alloc1 ; No, return error
+ call halloc ; Yes, allocate handle
+ or ax,ax ; failure??
+ jz alloc1 ; yep... return a NULL
+ xor byte ptr [bx].lhe_address,LA_MOVEABLE ; and zero address field
+ or byte ptr [bx].lhe_flags,LHE_DISCARDED ; and mark as discarded
+ jmps alloc1 ; all done
+
+alloc0: test al,LA_MOVEABLE ; Is this a moveable object?
+ jz dont_need_handle
+ push ax
+ push bx
+ call halloc ; Allocate handle first.
+
+ or ax,ax
+ jnz all2 ; error?
+ pop bx ; yes, DON'T destroy the NULL in AX
+ pop bx
+ jmps alloc1
+all2:
+ pop bx
+ pop ax
+
+; pop bx
+; pop ax
+; jcxz alloc1
+
+ push cx ; this is handle
+ call lalloc
+ pop si ; get handle in index register
+ jnz got_space
+ call lhfree ; free the allocated handle
+ jmps alloc1
+
+got_space:
+ mov [si].lhe_address,ax ; Store address away.
+ mov bx,ax ; Store back link to handle in header
+ mov [bx-SIZE LocalArena].la_handle,si ; Mark as moveable block
+ or byte ptr [bx-SIZE LocalArena].la_prev,LA_MOVEABLE
+ mov ax,si ; return the handle
+ and dh,LHE_DISCARDABLE ; Discardable object?
+ jz alloc1 ; No, continue
+ mov [si].lhe_flags,dh ; Yes, save discard level in handle
+ jmps alloc1 ; table entry
+
+dont_need_handle:
+ call lalloc
+alloc1: test byte ptr flags,LA_NOCOMPACT
+ jz all1
+ dec [di].hi_freeze
+all1: call lleave ; Arena is consistent now
+la_crit:
+ or ax,ax
+ jnz @F
+ KernelLogError DBF_WARNING,ERR_LALLOC,"LocalAlloc failed" ; LocalAlloc failure
+ xor ax, ax ; preserve the return value
+@@:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalAlloc: #AX"
+cEnd
+
+
+cProc ILocalReAlloc,<PUBLIC,FAR>,<si,di>
+ parmW h
+ parmW nbytes
+ parmW rflags
+cBegin
+ WOWTrace "LocalReAlloc(#AX,#BX,#CX)",<<ax,h>,<bx,nbytes>,<cx,rflags>>
+ CheckHeap LocalReAlloc
+ call lenter ; About to modify memory arena
+ jcxz lr_ok
+ xor ax, ax
+ jmp lr_crit
+lr_ok:
+ test byte ptr rflags,LA_NOCOMPACT
+ jz rel0
+ inc [di].hi_freeze
+rel0:
+ mov si,h ; Dereference handle
+ call ldref
+ jz racreate ; If zero handle, check for re-creation.
+ test byte ptr rflags,LA_MODIFY ; Want to modify handle table flags
+ jnz ramodify ; Yes, go do it
+ mov si,bx ; SI = arena header
+ mov bx,ax ; Compute address of new next header
+ mov dx,nbytes ; assuming there is room.
+ cmp dx,SIZE LocalArenaFree ; Minimum size must be large enough
+ jae @F ; to a hold free header.
+ mov dx,SIZE LocalArenaFree
+@@: add bx,dx
+ call lalign
+ mov bx,[si].la_next ; Get address of current next header
+ cmp nbytes,0 ; Are we reallocing to zero length?
+ jne raokay ; No, continue
+ jcxz radiscard ; Yes, discard if not locked
+rafail:
+ KernelLogError DBF_WARNING,ERR_LREALLOC,"LocalReAlloc failed"
+ xor ax,ax
+ jmp raexit
+
+radiscard:
+
+; Here to discard object, when reallocating to zero size. This
+; feature is only enabled if the caller passes the moveable flag
+
+ test byte ptr rflags,LA_MOVEABLE ; Did they want to discard?
+ jz rafail ; No, then return failure.
+ mov al,LN_DISCARD ; AL = discard message code
+ xor cx,cx ; CX = disc level of 0 (means realloc)
+ mov bx,h ; BX = handle
+ call lnotify ; See if okay to discard
+ jz rafail ; No, do nothing
+ xor ax,ax ; Yes, free client data
+ mov bx,si
+ call lfree
+ jz rax ; Return NULL if freed a fixed block
+ mov [si].lhe_address,ax ; No, zero addr in handle table entry
+ or [si].lhe_flags,LHE_DISCARDED ; and mark as discarded
+ jmps rasame ; Return original handle, except
+ ; LocalLock will now return null.
+
+ramodify:
+ mov ax,rflags ; Get new flags
+ or si,si ; Moveable object?
+ jz rasame ; No, all done
+ and [si].lhe_flags,not LHE_USERFLAGS ; Clear old flags
+ and ah,LHE_USERFLAGS; Get new flags
+ or [si].lhe_flags,ah ; Store new flags in handle table entry
+ jmps rasame
+
+racreate:
+ test cl,LHE_DISCARDED ; Is this a discarded handle?
+ jz rasame ; No, return original value
+ mov bx,nbytes ; BX = new requested size
+ push si ; save handle
+ mov ax,LA_MOVEABLE ; Reallocating a moveable object
+ or ax,rflags ; ...plus any flags from the caller
+ call lalloc ; Allocate a new block
+ pop si ; restore existing handle
+ jz rafail
+ xor [si].lhe_flags,LHE_DISCARDED ; and mark as not discarded
+ jmp ram2
+
+raokay:
+; Here if not trying to realloc this block to zero
+; SI = arena header of current block
+; AX = client address of current block
+; BX = arena header of next block
+; CH = lock count of current block
+; DX = new next block, based on new requested size
+ cmp dx,bx ; Are we growing or shrinking?
+ ja ragrow ; We are growing
+rashrink: ; We are shrinking
+; Here to shrink a block
+; SI = arena header of current block
+; BX = arena header of next block
+; DX = new next block, based on new requested size
+ push si
+ mov si,dx ; SI = new next block
+ add dx,LA_MINBLOCKSIZE ; Test for small shrinkage
+ jnc @F ; No overflow
+ pop bx ; Overflowed, obviously no room!
+ jmp rasame ; Clear stack and return same handle
+@@: cmp dx,bx ; Is there room from for free block?
+ pop bx ; BX = current block
+ jae rasame ; No, then no change to make
+ ; Splice extra free space into arena
+ mov cx,si ; [si].la_next = [bx].la_next
+ xchg [bx].la_next,cx ; [bx].la_next = si
+ mov [si].la_prev,bx ; [si].la_prev = bx
+ xchg si,cx
+ and [si].la_prev,LA_ALIGN
+ jz splice1 ; If free then coelesce
+ inc [di].hi_count ; No, adding new arena entry
+ jmps splice2
+splice1:
+
+; next block is free, must make the new block a larger free block
+
+; first remove the current free block [SI] from the free list
+
+ xchg bx,si
+ call lfreedelete
+ xchg bx,si
+ mov si,[si].la_next
+ and [si].la_prev,LA_ALIGN
+
+splice2:
+ or [si].la_prev,cx ; [[si].la_next].la_prev = si
+ xchg si,cx
+ mov [si].la_next,cx
+ mov bx,si ; BX = new block
+ xor si,si ; don't know where to insert
+ call lfreeadd ; add to free list
+rasame:
+ mov ax,h ; Return the same handle
+rax: jmps raexit ; All done
+
+; Here to try to grow the current block
+; AX = client address of current block
+; SI = arena header of current block
+; BX = arena header of next block
+; DX = new next block, based on new requested size
+ragrow:
+if KDEBUG
+ call CheckLAllocBreak
+ jc rafail1
+endif
+
+ test byte ptr [bx].la_prev,LA_BUSY ; Is next block free?
+ jnz ramove ; No, try to move the current block
+ cmp dx,[bx].la_next ; Yes, is free block big enough?
+ ja ramove ; No, try to move the current block
+ mov cx,bx ; Yes, save free block address in CX
+ call ljoin ; and attach to end of current block
+ test rflags,LA_ZEROINIT ; Zero fill extension?
+ jz ranz ; No, continue
+ call lzero ; Yes, zero fill
+ranz:
+ jmp rashrink ; Now shrink block to correct size
+
+; Here to try to move the current block
+; AX = client address of current block
+; SI = arena header of current block
+; CH = lock count of current block
+ramove:
+ mov dx,rflags ; get the passed in flags
+ mov bx,LA_MOVEABLE ; Determine if okay to move this guy
+ jcxz ramove1 ; Continue if this handle not locked
+ test dx,bx ; Locked. Did they say move anyway?
+ jnz ramove1 ; Yes, go do it
+rafail1:jmp rafail
+ramove1:
+ or dx,bx ; make sure moveable bit set
+ test h,bx ; Is it a moveable handle?
+ jnz ram1 ; Yes, okay to move
+ test rflags,bx ; No, did they say it's okay to move?
+ jz rafail1 ; No, then fail
+ xor dx,bx ; turn off moveable bit
+ram1:
+; We do this because the lalloc can move the old block to a
+; block that is larger than the requested new block. This can
+; happen if we LocalCompact durring the lalloc call. (bobgu 8/27/87)
+ mov bx,[si].la_next
+ sub bx,ax ; # client bytes in current block
+ push bx ; save it for later
+
+ mov ax,dx ; AX = allocation flags
+ mov bx,nbytes ; BX = new requested size
+ call lalloc ; Allocate a new block
+
+ pop cx ; CX = client size of old block
+ jz rafail1
+ push cx ; save it away again
+
+ push ax ; Call notify proc
+ mov cx,ax ; with new location
+ mov bx,h ; handle
+ mov al,LN_MOVE
+ call lnotify ; Notify client of new location
+ mov si,h
+ call ldref ; BX = old arena header address
+ mov si,ax ; SI = old client address
+ pop ax ; AX = new client address
+
+ pop cx ; get back size of old client
+; mov cx,[bx].la_next ; Compute length of old client data
+; sub cx,si
+ call lrepsetup ; Setup for copy of words
+ push di
+ mov di,ax ; DI = new client data address
+ rep movsw ; Copy old client data to new area
+ pop di ; Restore DI
+ call lfree ; Free old block
+ jz raexit
+ram2:
+ mov [si].lhe_address,ax ; Set new client data address
+ xchg ax,si ; Return original handle
+ ; Set back link to handle in new block
+ or byte ptr [si-SIZE LocalArena].la_prev,LA_MOVEABLE
+ mov [si-SIZE LocalArena].la_handle,ax
+raexit:
+ test byte ptr rflags,LA_NOCOMPACT
+ jz rel1
+ dec [di].hi_freeze
+rel1:
+ call lleave ; Arena is consistent now
+lr_crit:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalReAlloc: #AX"
+cEnd
+
+
+cProc ILocalFree,<PUBLIC,FAR>,<si,di>
+ parmW h
+cBegin
+ WOWTrace "LocalFree(#AX)",<<ax,h>>
+ call lenter ; About to modify memory arena
+ jcxz lf_ok
+ xor ax, ax
+ jmp lf_crit
+lf_ok:
+ CheckHeap LocalFree
+ mov si,h ; Dereference handle
+ call ldref
+ jz free1 ; Free handle if object discarded
+if KDEBUG
+ push ds
+ SetKernelDS
+ mov ds,curTDB
+ assumes ds, nothing
+ cmp ds:[TDB_ExpWinVer],201h
+ pop ds
+ jb dont_do_error_checking
+
+ or ch,ch ; No, is the handle locked?
+ jz freeo ; Yes, then don't free
+ xor bx,bx
+ kerror ERR_LMEMUNLOCK,<LocalFree: freeing locked object>,bx,h
+ mov si,h ; Dereference handle again
+ call ldref
+freeo:
+dont_do_error_checking:
+endif
+ call lfree ; No, free the object
+free1: call lhfree ; and any handle
+freex: call lleave ; Arena is consistent now
+lf_crit:
+ WOWTrace "LocalFree: #AX"
+cEnd
+
+cProc ILocalSize,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+; CheckHeap LocalSize
+ push si
+ mov si,sp
+ mov si,ss:[si+6] ; Dereference handle
+ call ldref ; into BX
+ jz size1 ; Done if AX = zero
+ sub ax,[bx].la_next ; Otherwise size =
+ neg ax ; - (client address - next block address)
+size1: mov cx,ax ; Let caller do jcxz to test failure
+ pop si
+ ret 2
+cEnd nogen
+
+
+cProc ILocalFlags,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+; CheckHeap LocalFlags
+ push si
+ mov si,sp
+ mov si,ss:[si+6] ; Dereference handle
+ call ldref ; into BX
+ mov cx,si
+ jcxz flags1 ; Done if not moveable
+ mov cx,word ptr [si].lhe_flags ; Return flags and lock count
+flags1:
+ xchg cl,ch ; Return lock count in low half
+ mov ax,cx ; Let caller do jcxz to test failure
+ pop si
+ ret 2
+cEnd nogen
+
+
+
+if KDEBUG
+cProc ILocalLock,<PUBLIC,FAR>,<si>
+ parmW h
+cBegin
+ WOWTrace "LocalLock(#AX)",<<ax,h>>
+; CheckHeap LocalLock
+ mov si,h
+ call ldref ; SI = handle table entry
+ jz lock2 ; Done if invalid handle or discarded
+ or si,si
+ jz lock2 ; or if not moveable
+
+ inc [si].lhe_count ; Increment usage count
+ jnz lock1
+ xor cx,cx
+ kerror ERR_LMEMLOCK,<LocalLock: Object usage count overflow>,cx,h
+ dec [si].lhe_count ; Keep pinned at max value
+lock1: mov ax,[si].lhe_address ; Return true address in AX
+lock2:
+ or ax, ax
+ jnz @F
+ KernelLogError DBF_WARNING,ERR_LLOCK,"LocalLock failed"
+ xor ax,ax ; Get back the NULL value in ax
+@@: mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalLock: #AX"
+cEnd
+
+else
+cProc ILocalLock,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp ; Get handle parameter from stack
+ mov bx,SS:[bx+4]
+ mov ax,bx ; Return in AX
+ test bl,LA_MOVEABLE ; Test for moveable (also null)
+ jz lock2 ; Return if not moveable or null
+ test [bx].lhe_flags,LHE_DISCARDED ; Return zero if discarded
+ jnz lock1
+ inc [bx].lhe_count ; Increment usage count
+ jz lock3 ; Special case if overflow
+lock1:
+ mov ax,[bx].lhe_address ; Return true address in AX or zero
+lock2: mov cx,ax ; Let caller do jcxz to test failure
+ ret 2
+lock3:
+ dec [bx].lhe_count ; Ooops, keep pinned at max value
+ jmp lock1
+
+cEnd nogen
+endif
+
+
+if KDEBUG
+cProc ILocalUnlock,<PUBLIC,FAR>,<si>
+ parmW h
+cBegin
+ WOWTrace "LocalUnlock(#AX)",<<ax,h>>
+; CheckHeap LocalUnlock
+ mov si,h
+ call ldref ; SI = handle table entry
+ jz unlock1 ; Done if invalid handle or discarded
+ xor ax,ax
+ or si,si
+ jz unlock1 ; or if not moveable
+
+ or ch, ch
+ jz unlockerr
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; 0 -> ff, ff -> fe
+ jae unlock1 ; Return if pinned or already unlocked
+ mov [si].lhe_count,ch
+; mov ax,bx
+ mov al,ch
+ cbw
+ jmps unlock1
+unlockerr:
+ xor cx,cx
+ kerror ERR_LMEMUNLOCK,<LocalUnlock: Object usage count underflow>,cx,h
+ xor ax,ax
+unlock1:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalUnlock: #AX"
+cEnd
+
+else
+cProc ILocalUnlock,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp ; Get handle parameter from stack
+ mov bx,SS:[bx+4]
+ xor ax,ax
+ test bl,LA_MOVEABLE ; Test for moveable (also null)
+ jz unlock1 ; Return if not moveable or null
+ mov cx,word ptr [bx].lhe_flags
+ errnz <2-lhe_flags>
+ errnz <3-lhe_count>
+ and cl,LHE_DISCARDED
+ jnz unlock1 ; Return if discarded
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; 0 -> ff, ff -> fe
+ jae unlock1 ; Return if pinned or already unlocked
+ mov [bx].lhe_count,ch
+; mov ax,bx
+ mov al,ch
+ cbw
+unlock1:
+ mov cx,ax ; Let caller do jcxz to test failure
+ ret 2
+cEnd nogen
+endif
+
+
+
+cProc LocalHandle,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp
+ mov bx,SS:[bx+4]
+ test bl,LA_MOVEABLE
+ jz lh1
+ mov ax,bx
+ mov bx,[bx-SIZE LocalArena].la_handle
+ cmp [bx].lhe_address,ax
+ je lh1
+ xor bx,bx
+lh1:
+ mov ax,bx
+ ret 2
+cEnd nogen
+
+
+cProc LocalCompact,<PUBLIC,FAR>,<si,di>
+ parmW minBytes
+cBegin
+ CheckHeap LocalCompact
+ call lenter ; About to modify memory arena
+ jcxz lc_ok
+ xor ax, ax
+ jmp lc_crit
+lc_ok:
+ mov bx,minBytes
+ clc
+ call lalign
+ call lcompact
+ or ax,ax
+ jz compact1
+ sub ax,SIZE LocalArena ; Reduce available size by header size
+compact1:
+ call lleave ; Arena is consistent now
+lc_crit:
+cEnd
+
+
+cProc LocalShrink,<PUBLIC,FAR>,<si,di>
+ parmW hseg
+ parmW wsize
+cBegin
+ mov ax,hseg
+ or ax,ax ; use heap in current DS ?
+ jz ls_useds ; yes
+
+; Use the segment handle passed
+ push ax
+ call GlobalHandle
+ or ax,ax ; valid handle ?
+ jz ls_errexit ; no....
+ mov ds,dx ; set the proper DS
+ls_useds:
+; check the heap and lock it
+ CheckHeap LocalShrink
+ call lenter ; About to modify memory arena
+ jcxz ls_ok
+ xor ax, ax
+ jmp short ls_crit
+ls_ok:
+
+ mov bx,wsize ; get requested min size
+ call lshrink ; Let's get small
+; AX = new local heap size
+ call lleave ; Arena is consistent now
+ls_crit:
+ls_errexit:
+
+cEnd
+
+
+cProc LocalNotifyDefault,<PUBLIC,FAR>,<si,di>
+ parmW msg
+ parmW handle ; or largest free block
+ parmW arg1
+cBegin
+ mov ax,msg
+ or ax,ax
+ jnz dlnexit1
+ cCall GlobalHandle,<ds>
+ or ax,ax
+ jz dlnexit1
+ ; Fix for FORMBASE who uses a fixed
+ ; segment for a local heap. This blows
+ ; up if we cause the calling segment
+ ; to be discarded since the DS saved by
+ ; Local???? is a fixed segment which
+ ; SearchStack can't handle. Confused?
+ ; This was not a problem in 2.x because
+ ; 2.x failed to grow a fixed object.
+ ; Using a fixed segment for a local heap
+ ; is not valid and this is really a problem
+ ; with FORMBASE.
+ mov si,ax
+ cCall GlobalFlags,<si> ; Get flags
+ xchg ah, al
+ push ax
+ cCall GlobalSize,<si>
+ sub ax, handle ; Temorarily subtract out largest free
+ pop bx ; Get flags in BX
+ xor cx,cx
+ add ax,arg1
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz dln_too_large ; beyond 64k.
+ add ax,18h ; since li_extra isn't guaranteed
+ adc dx,cx
+ jnz dln_too_large
+ add ax,[di].li_extra
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz @F ; beyond 64k.
+ add ax, handle ; add back largest free
+ adc dx, cx
+ jnz @F
+ cmp ax,0FFF0h
+ jbe dln0
+@@: mov ax,0FFF0h
+ xor dx,dx
+ jmps dln0
+dln_too_large:
+ xor ax,ax
+dlnexit1:
+ jmp dlnexit
+dln0:
+ test si,GA_FIXED ; Is DS fixed?
+ jnz dln1 ; Yes, must grow in place
+ cmp bh,1 ; No, is lock count 1?
+ jne dln1 ; No must grow in place if locked
+ or cl,GA_MOVEABLE ; Yes, okay to move even though locked
+dln1:
+ push bx
+grow_DS:
+ cCall GlobalReAlloc,<si,dxax,cx>
+ pop bx
+ jcxz dlnexit
+ push bx
+ cCall GlobalSize,<ax>
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz @F ; No, OK
+ mov ax,0FFFFh ; This only happens under 386pmode
+@@:
+ mov bx,ax
+ sub bx,la_freefixedsize
+ and bl,LA_MASK
+ mov di,ds:[pLocalHeap]
+ mov si,[di].hi_last
+ mov [bx].la_next,bx
+ mov [bx].la_prev,si
+ or byte ptr [bx].la_prev,LA_BUSY
+ mov [si].la_next,bx
+
+; Maintain the free list.
+
+ mov ax,[si].la_free_prev
+ mov [bx].la_free_prev,ax
+ mov [bx].la_free_next,bx
+ mov [bx].la_size,WORD PTR la_freefixedsize
+ push si
+ mov si,ax
+ mov [si].la_free_next,bx
+ pop si
+
+ mov [di].hi_last,bx
+ inc [di].hi_count
+ mov bx,si
+ call lfree
+
+; Don't do this... (bobgu 8/4/87)
+; stc
+; call lalign
+; call lcompact
+
+ mov ax,1
+ pop bx
+ mov ax,1
+dlnexit:
+cEnd
+
+cProc LocalNotifyDib,<PUBLIC,FAR>,<si,di>
+ parmW msg
+ parmW handle ; or largest free block
+ parmW arg1
+cBegin
+ mov ax,msg
+ or ax,ax
+ jnz dlnexit1dib
+ cCall GlobalHandle,<ds>
+ or ax,ax
+ jz dlnexit1dib
+ ; Fix for FORMBASE who uses a fixed
+ ; segment for a local heap. This blows
+ ; up if we cause the calling segment
+ ; to be discarded since the DS saved by
+ ; Local???? is a fixed segment which
+ ; SearchStack can't handle. Confused?
+ ; This was not a problem in 2.x because
+ ; 2.x failed to grow a fixed object.
+ ; Using a fixed segment for a local heap
+ ; is not valid and this is really a problem
+ ; with FORMBASE.
+ mov si,ax
+ cCall GlobalFlags,<si> ; Get flags
+ xchg ah, al
+ push ax
+ cCall GlobalSize,<si>
+ sub ax, handle ; Temorarily subtract out largest free
+ pop bx ; Get flags in BX
+ xor cx,cx
+ add ax,arg1
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz dib_too_large ; beyond 64k.
+ add ax,18h ; since li_extra isn't guaranteed
+ adc dx,cx
+ jnz dib_too_large
+ add ax,[di].li_extra
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz @F ; beyond 64k.
+ add ax, handle ; add back largest free
+ adc dx, cx
+ jnz @F
+ cmp ax,0FFF0h
+ jbe dln0dib
+@@: mov ax,0FFF0h
+ xor dx,dx
+ jmps dln0dib
+dib_too_large:
+ xor ax,ax
+dlnexit1Dib:
+ jmp dlnexitdib
+dln0dib:
+ test si,GA_FIXED ; Is DS fixed?
+ jnz dln1dib ; Yes, must grow in place
+ cmp bh,1 ; No, is lock count 1?
+ jne dln1dib ; No must grow in place if locked
+ or cl,GA_MOVEABLE ; Yes, okay to move even though locked
+dln1dib:
+ push bx
+ cCall DibReAlloc,<ds,ax>
+ or ax,ax
+ jz dlnexitdib0
+ cCall GlobalSize,<si>
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz @F ; No, OK
+ mov ax,0FFFFh ; This only happens under 386pmode
+@@:
+ mov bx,ax
+ sub bx,la_freefixedsize
+ and bl,LA_MASK
+ mov di,ds:[pLocalHeap]
+ mov si,[di].hi_last
+ mov [bx].la_next,bx
+ mov [bx].la_prev,si
+ or byte ptr [bx].la_prev,LA_BUSY
+ mov [si].la_next,bx
+
+; Maintain the free list.
+
+ mov ax,[si].la_free_prev
+ mov [bx].la_free_prev,ax
+ mov [bx].la_free_next,bx
+ mov [bx].la_size,WORD PTR la_freefixedsize
+ push si
+ mov si,ax
+ mov [si].la_free_next,bx
+ pop si
+
+ mov [di].hi_last,bx
+ inc [di].hi_count
+ mov bx,si
+ call lfree
+
+; Don't do this... (bobgu 8/4/87)
+; stc
+; call lalign
+; call lcompact
+
+
+ mov ax,1
+dlnexitdib0:
+ pop bx
+dlnexitdib:
+cEnd
+
+sEnd CODE
+
+externFP Far_lalign
+externFP Far_lrepsetup
+if KDEBUG
+externFP Far_lfillCC
+endif
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+cProc ILocalNotify,<PUBLIC,FAR>
+; parmD lpProc
+cBegin nogen
+ mov bx,sp
+ mov ax,SS:[bx+4]
+ mov dx,SS:[bx+6]
+ mov bx,ds:[pLocalHeap]
+ xchg word ptr [bx].li_notify,ax
+ xchg word ptr [bx].li_notify+2,dx
+ ret 4
+cEnd nogen
+
+
+cProc LocalInit,<PUBLIC,FAR>,<ds,si,di>
+ parmW pseg
+ parmW pstart
+ parmW pend
+cBegin
+
+; Init current DS if none passed.
+
+ mov cx,pseg
+ jcxz li1
+ mov ds,cx
+li1:
+
+; Place local arena info at the beginning
+
+ mov bx,pstart
+ or bx,bx
+ jnz li2
+ cCall GlobalSize,<ds>
+
+; Here we must do a little checking... The global memory manager may have
+; rounded up the size on us so that the DS is >=64K! If this has happened,
+; we can simply ignore the extra (since app can't look at it anyway) and
+; pretend the DS is actually 0000FFFFH bytes big.
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz li1a ; No, OK
+ mov ax,0FFFFH ; Pretend heap is 64K-1
+li1a:
+ mov bx,ax
+ dec bx
+ xchg pend,bx
+ sub bx,pend
+ neg bx ; BX = first byte in arena
+li2:
+ clc
+ call Far_lalign
+ mov bx,dx ; DX = addr of first block to use
+
+; OK, so here's how it works... In order to keep a free block list, there
+; are 4 blocks allocated initially. First is a dummy marker block that is
+; free but marked busy. Second is the local arena information block which
+; is a standard busy block. Third is the really big free block. And lastly
+; is another busy type free block. All free blocks have an extended header
+; in order to keep a free block list.
+
+; Reserve room for the first free busy block.
+
+ lea bx,[bx].la_freefixedsize ; move over first free block
+ push dx ; preserve first free block address
+ clc
+ call Far_lalign
+ mov bx,dx ; BX = arena info block address
+ pop dx ; DX = first block address
+ push dx ; * Save the address of the first
+ push bx ; * two block on the stack for later
+
+; DI = client address of info block.
+
+ lea di,[bx].la_fixedsize
+ xor ax,ax ; Zero local arena info
+ mov cx,pend
+ cmp bx,cx ; start > end?
+
+;;;;;;; jae lix
+ jb li21
+ pop dx ; clean up the stack first
+ pop dx
+ jmp lix
+li21:
+ sub cx,di
+ call Far_lrepsetup
+ push di
+ rep stosw
+ pop di
+ lea bx,[di].SIZE LocalInfo
+if KDEBUG
+ mov [di].hi_pstats,bx
+ add bx,SIZE LocalStats
+
+ifdef DISABLE
+
+; Set the heap checking flag.
+
+ push es
+ push dx
+ cCall GlobalMasterHandle
+ mov es,dx
+ mov ax,es:[hi_check]
+ pop dx
+ pop es
+else
+ push es
+ push _DATA
+ pop es
+assumes es,DATA
+;
+; hi_check = 0;
+; if (DebugOptions & DBO_CHECKHEAP)
+; {
+; hi_check = 1
+; if (DebugOptions & DBO_CHECKFREE)
+; hi_check = 2;
+; }
+;
+ xor ax,ax
+ test es:DebugOptions,DBO_CHECKHEAP
+ jz @F
+ inc ax
+ test es:DebugOptions,DBO_CHECKFREE
+ jz @F
+ inc ax
+@@:
+assumes es,NOTHING
+ pop es
+endif
+ mov [di].hi_check,ax
+endif
+
+; set the rest of the heap info
+
+ mov byte ptr [di].hi_hdelta,32
+ mov byte ptr [di].hi_count,4
+ mov [di].hi_first,dx
+ mov word ptr [di].li_notify,codeOFFSET LocalNotifyDefault
+ mov word ptr [di].li_notify+2,codeBASE
+ mov word ptr [di].hi_hexpand,codeOFFSET lhexpand
+ mov [di].li_extra,512
+ mov [di].li_sig,LOCALHEAP_SIG
+
+; Move SI to first aligned block after info record
+
+ clc
+ call Far_lalign
+ mov si,dx
+
+; Move BX to last aligned block at end of local heap
+
+ mov bx,pend ; BX = end address
+ sub bx,la_freefixedsize ; Make room for an arena header
+ and bl,LA_MASK ; Align downwards to 4 byte boundary
+
+ cmp bx, si ; If heap is too small, the
+ ja @f ; supposed free block could be
+ xor ax, ax ; beyond the end block
+ jmp lix
+@@:
+
+; Setup reserved pointer in DS to point to LocalInfo
+
+ mov [di].hi_last,bx
+ mov ds:[pLocalHeap],di
+
+; Finish linking entries in the local heap.
+;
+; DX = address of the first arena block. Free busy marker.
+; DI = address of the element which contains the local heap
+; information struc.
+; SI = address of large free block that is the initial heap.
+; BX = address of a zero length arena element that is used to
+; mark the end of the local heap.
+;
+;
+; This last arena element is always busy, with a length of
+; zero. This allows us to always calculate the length of an
+; arena entry by subtracting the address of the arena element
+; from the hi_next field of the arena element (see lsize subr)
+
+ pop di ; Get the address of the first two
+ pop dx ; ... blocks off the stack
+
+; Setup first block in arena, busy free block.
+
+ xchg bx,dx ;bx = first block (temporarily)
+ lea ax,[bx+LA_BUSY] ; ...as a busy block
+ mov [bx].la_prev,ax ; point to self
+ mov [bx].la_next,di ; point to next
+ mov [bx].la_free_prev,bx ; previous free block is self
+ mov [bx].la_free_next,si ; next free is large block
+ mov [bx].la_size,WORD PTR la_freefixedsize ; set the block size
+ xchg bx,dx ; back to normal
+
+; Setup block that contains info structure.
+
+ xchg dx,bx
+ lea ax,[bx+LA_BUSY] ; ...as a busy block
+ xchg dx,bx
+ mov [di].la_prev,ax ; point to previous block
+ mov [di].la_next,si ; point to next block
+
+; Setup large free block with extended free block header.
+
+ mov [si].la_prev,di ; Point middle block to first and
+ mov [si].la_next,bx ; last blocks
+ mov [si].la_free_prev,dx ; previous free block
+ mov [si].la_free_next,bx ; next free block
+ mov ax,bx
+ sub ax,si
+ mov [si].la_size,ax ; length of free block
+
+if KDEBUG
+ xchg si,bx ; BX = large free block
+ call Far_lfillCC ; Fill with 0CCh
+ xchg si,bx
+endif
+
+; Setup last free block with extended header.
+
+ mov [bx].la_next,bx ; Point last block to middle and itself
+ lea ax,[si+LA_BUSY] ; ...as a busy block
+ mov [bx].la_prev,ax
+ mov [bx].la_free_prev,si ; previous free block
+ mov [bx].la_free_next,bx ; next free block is self
+ mov [bx].la_size,WORD PTR la_freefixedsize ; set the block size
+
+; Set the minimum size in arena header.
+
+ mov bx,ds:[pLocalHeap]
+ mov ax,[bx].hi_last
+ add ax,SIZE LocalArenaFree
+ sub ax,[bx].hi_first
+ mov [bx].li_minsize,ax
+
+ cCall GlobalLock,<ds> ; Make moveable DS initially locked.
+ ; (see LocalNotifyDefault)
+ mov al,1
+lix:
+ mov cx,ax
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; LocalCountFree ;
+; ;
+; Return the count of free bytes in the local heap. This was motivated ;
+; by the InitApp routines that want at least 4K available to continue ;
+; the app running. ;
+; ;
+; Arguments: ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = free bytes in local heap ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Aug 15, 1987 04:35:55p -by- Bob Gunderson [bobgu] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalCountFree,<PUBLIC,FAR>
+cBegin nogen
+ push di
+ push si
+ mov di,pLocalHeap
+ lea si, [di].li_sig
+ cCall FarValidatePointer,<ds,si>
+ or ax, ax ; OK pointer?
+ jz countexit ; no, just exit
+ xor ax,ax ; start with 0 bytes free
+ cmp [di].li_sig, LOCALHEAP_SIG
+ jne countexit ; No local heap!!
+ mov si,[di].hi_last ; sentenal block
+ mov di,[di].hi_first ; arena header
+ mov di,[di].la_free_next ; first free block
+countloop:
+ cmp di,si
+ jz countexit
+ add ax,[di].la_size ; count size of this block
+ sub ax,SIZE LocalArenaFree ; less block overhead
+ mov di,[di].la_free_next ; next free block
+ jmp countloop
+countexit:
+ pop si
+ pop di
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; LocalHeapSize ;
+; ;
+; Return the # bytes allocated to the local heap. ;
+; ;
+; Arguments: ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = size of local heap ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Aug 15, 1987 04:35:55p -by- Bob Gunderson [bobgu] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalHeapSize,<PUBLIC,FAR>
+cBegin nogen
+ mov bx,pLocalHeap
+ mov ax,[bx].hi_last
+ sub ax,[bx].hi_first
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; LocalHandleDelta ;
+; ;
+; Change the number of handles to allocate each time ;
+; ;
+; Arguments: ;
+; delta = new # of handles or 0 ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = new number of handles ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalHandleDelta,<PUBLIC,FAR>
+ parmW delta
+cBegin
+ mov bx,pLocalHeap
+ mov ax, delta
+ or ax, ax ; Zero means return present value
+ jz return_present_value
+ mov ax, delta
+ mov [bx].hi_hdelta, ax ; Set new value
+return_present_value:
+ mov ax, [bx].hi_hdelta
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/log.slm b/private/mvdm/wow16/kernel31/log.slm
new file mode 100644
index 000000000..92d71d259
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/log.slm
@@ -0,0 +1,1005 @@
+509838581;MARLINE;addproj;//ISG/TEST/WINDOWS/KERNEL;;;;
+509838585;MARLINE;enlist;//ISG/TEST/WINDOWS/KERNEL;;;;
+509838597;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RETAIL;;
+509838602;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;HEAPWALK;;
+509838608;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;EI;;
+509838613;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0410.LOG;;
+509838614;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;MISC.CCS;;
+509838617;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;INT21.ASM;;
+509838622;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0608.LOG;;
+509838626;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0424.LOG;;
+509838628;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LACHECK.OBJ;;
+509838632;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0118.LOG;;
+509838636;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0106.LOG;;
+509838642;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS1022.LOG;;
+509838647;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0523.LOG;;
+509838651;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0731.LOG;;
+509838656;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0205.LOG;;
+509838657;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LADEBUG.H;;
+509838659;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LALLOC.OBJ;;
+509838660;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LCOMPACT.OBJ;;
+509838664;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0505.LOG;;
+509838666;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;PDB.INC;;
+509838667;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNSTUB;;
+509838669;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL.DEF;;
+509838671;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KDATA.ASM;;
+509838673;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;INT24.ASM;;
+509838675;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCHEDULE.ASM;;
+509838677;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDOPEN.ASM;;
+509838679;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LSTRING.ASM;;
+509838681;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;I21EXEC.INC;;
+509838682;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;I21EXIT.INC;;
+509838684;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KDATA.OBJ;;
+509838687;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0310.LOG;;
+509838689;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WINSTUB;;
+509838693;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0326.LOG;;
+509838694;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDOPEN.OBJ;;
+509838696;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCHEDULE.OBJ;;
+509838697;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;INT21.OBJ;;
+509838699;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;INT24.OBJ;;
+509838701;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LALLOC.ASM;;
+509838703;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDBOOT.ASM;;
+509838707;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GWINTERF.INC;;
+509838708;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WIN.CNF;;
+509838711;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WIN.ASM;;
+509838712;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;HANDLE.H;;
+509838714;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LINTERF.OBJ;;
+509838716;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDAUX.ASM;;
+509838718;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GWMEM.INC;;
+509838719;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDAUX.OBJ;;
+509838724;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0623.LOG;;
+509838726;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;CONTEXT.OBJ;;
+509838729;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GMEM.ASM;;
+509838731;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDBOOT.OBJ;;
+509838732;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDINT.ASM;;
+509838734;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDINT.OBJ;;
+509838736;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL.H;;
+509838738;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RESAUX.ASM;;
+509838741;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDUTIL.ASM;;
+509838742;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS.CHK;;
+509838744;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LACHECK.C;;
+509838745;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL.LNK;;
+509838747;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;MEM.CCS;;
+509838748;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNSTUB.EXE;;
+509838751;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GALLOC.ASM;;
+509838752;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GALLOC.OBJ;;
+509838754;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LD.CCS;;
+509838756;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;NEWEXE.INC;;
+509838757;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WINSTUB.ASM;;
+509838759;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RIPAUX.ASM;;
+509838761;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GADUMP.C;;
+509838766;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS0820.LOG;;
+509838768;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDRELOC.ASM;;
+509838769;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDFILE.OBJ;;
+509838771;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDRELOC.OBJ;;
+509838772;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDINIT.OBJ;;
+509838774;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LD.OBJ;;
+509838775;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDDEBUG.OBJ;;
+509838776;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KPR.BAT;;
+509838778;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RESMAN.OBJ;;
+509838779;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RESAUX.OBJ;;
+509838781;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GLRU.ASM;;
+509838783;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RIP.OBJ;;
+509838785;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RIPAUX.OBJ;;
+509838787;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LCOMPACT.ASM;;
+509838788;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;ATOM.OBJ;;
+509838790;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GALLOC.INC;;
+509838792;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCHED.INC;;
+509838794;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;USERPRO.ASM;;
+509838796;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;DISKIO.OBJ;;
+509838797;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LSTRING.OBJ;;
+509838799;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GACHECK.OBJ;;
+509838801;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GINTERF.OBJ;;
+509838802;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GLRU.OBJ;;
+509838804;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LALLOC.INC;;
+509838805;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GMEM.OBJ;;
+509838807;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LD.C;;
+509838809;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GCOMPACT.OBJ;;
+509838810;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;HANDLE.OBJ;;
+509838811;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;TASK.OBJ;;
+509838842;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS1220.DIF;;
+509838843;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL.INC;;
+509838845;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;USERPRO.OBJ;;
+509838847;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;ATOM.ASM;;
+509838850;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDHEADER.ASM;;
+509838852;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDHEADER.OBJ;;
+509838854;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDSTACK.ASM;;
+509838855;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDSTACK.OBJ;;
+509838858;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDFASTB.ASM;;
+509838860;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDFASTB.OBJ;;
+509838863;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDSEG.ASM;;
+509838865;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDSEG.OBJ;;
+509838866;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KDEBUG.INC;;
+509838868;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;MKKERNEL.BAT;;
+509838870;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;DISKIO.ASM;;
+509838871;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;HANDLE.INC;;
+509838873;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GADEBUG.H;;
+509838875;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;CONTEXT.ASM;;
+509838877;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;TASK.ASM;;
+509838878;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RELKERN.BAT;;
+509838881;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;NEWEXE.DOC;;
+509838882;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL.CCS;;
+509838884;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCHED.CCS;;
+509838885;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDUTIL.OBJ;;
+509838887;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNSTUB.ASM;;
+509838890;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;DOSINIT.ASM;;
+509838892;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;DOSINIT.OBJ;;
+509838893;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WIN;;
+509838895;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDDEBUG.ASM;;
+509838897;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;HANDLE.ASM;;
+509838899;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GACHECK.C;;
+509838900;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LADUMP.C;;
+509838904;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LINTERF.ASM;;
+509838905;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;TDB.INC;;
+509838907;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;NULOBJ.ASM;;
+509838909;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDFILE.ASM;;
+509838910;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WIN.CCS;;
+509838912;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;WINOBJ.CCS;;
+509838915;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GCOMPACT.ASM;;
+509838917;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GMEM.INC;;
+509838918;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;GINTERF.ASM;;
+509838920;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;I21MEM.INC;;
+509838925;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;SCCS1205.LOG;;
+509838926;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;KERNEL;;
+509838929;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;NEWEXE.H;;
+509838930;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;LDINIT.C;;
+509838932;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RESMAN.C;;
+509838934;MARLINE;addfile;//ISG/TEST/WINDOWS/KERNEL;;RIP.C;;
+509839201;MARLINE;defect;//ISG/TEST/WINDOWS/KERNEL;;;;
+510536783;AARONR;enlist;//C:AARONR/WIN/DEVEL/KERNEL;;;;
+510537224;AARONR;defect;//C:AARONR/WIN/DEVEL/KERNEL;;;;
+511252539;BILLAN;enlist;//ISG/TEST/BILLAN;;;;
+511253858;BILLAN;delfile;//ISG/TEST/BILLAN;;ATOM.OBJ;;
+511253858;BILLAN;delfile;//ISG/TEST/BILLAN;;CONTEXT.OBJ;;
+511253858;BILLAN;delfile;//ISG/TEST/BILLAN;;DISKIO.OBJ;;
+511253859;BILLAN;delfile;//ISG/TEST/BILLAN;;DOSINIT.OBJ;;
+511253859;BILLAN;delfile;//ISG/TEST/BILLAN;;GACHECK.OBJ;;
+511253860;BILLAN;delfile;//ISG/TEST/BILLAN;;GALLOC.OBJ;;
+511253860;BILLAN;delfile;//ISG/TEST/BILLAN;;GCOMPACT.OBJ;;
+511253860;BILLAN;delfile;//ISG/TEST/BILLAN;;GINTERF.OBJ;;
+511253861;BILLAN;delfile;//ISG/TEST/BILLAN;;GLRU.OBJ;;
+511253861;BILLAN;delfile;//ISG/TEST/BILLAN;;GMEM.OBJ;;
+511253862;BILLAN;delfile;//ISG/TEST/BILLAN;;HANDLE.OBJ;;
+511253862;BILLAN;delfile;//ISG/TEST/BILLAN;;INT21.OBJ;;
+511253863;BILLAN;delfile;//ISG/TEST/BILLAN;;INT24.OBJ;;
+511253863;BILLAN;delfile;//ISG/TEST/BILLAN;;KDATA.OBJ;;
+511253863;BILLAN;delfile;//ISG/TEST/BILLAN;;LACHECK.OBJ;;
+511253864;BILLAN;delfile;//ISG/TEST/BILLAN;;LALLOC.OBJ;;
+511253864;BILLAN;delfile;//ISG/TEST/BILLAN;;LCOMPACT.OBJ;;
+511253865;BILLAN;delfile;//ISG/TEST/BILLAN;;LD.OBJ;;
+511253865;BILLAN;delfile;//ISG/TEST/BILLAN;;LDAUX.OBJ;;
+511253865;BILLAN;delfile;//ISG/TEST/BILLAN;;LDBOOT.OBJ;;
+511253866;BILLAN;delfile;//ISG/TEST/BILLAN;;LDDEBUG.OBJ;;
+511253866;BILLAN;delfile;//ISG/TEST/BILLAN;;LDFASTB.OBJ;;
+511253867;BILLAN;delfile;//ISG/TEST/BILLAN;;LDFILE.OBJ;;
+511253867;BILLAN;delfile;//ISG/TEST/BILLAN;;LDHEADER.OBJ;;
+511253868;BILLAN;delfile;//ISG/TEST/BILLAN;;LDINIT.OBJ;;
+511253868;BILLAN;delfile;//ISG/TEST/BILLAN;;LDINT.OBJ;;
+511253869;BILLAN;delfile;//ISG/TEST/BILLAN;;LDOPEN.OBJ;;
+511253869;BILLAN;delfile;//ISG/TEST/BILLAN;;LDRELOC.OBJ;;
+511253869;BILLAN;delfile;//ISG/TEST/BILLAN;;LDSEG.OBJ;;
+511253870;BILLAN;delfile;//ISG/TEST/BILLAN;;LDSTACK.OBJ;;
+511253870;BILLAN;delfile;//ISG/TEST/BILLAN;;LDUTIL.OBJ;;
+511253870;BILLAN;delfile;//ISG/TEST/BILLAN;;LINTERF.OBJ;;
+511253871;BILLAN;delfile;//ISG/TEST/BILLAN;;LSTRING.OBJ;;
+511253871;BILLAN;delfile;//ISG/TEST/BILLAN;;RESAUX.OBJ;;
+511253872;BILLAN;delfile;//ISG/TEST/BILLAN;;RESMAN.OBJ;;
+511253872;BILLAN;delfile;//ISG/TEST/BILLAN;;RIP.OBJ;;
+511253873;BILLAN;delfile;//ISG/TEST/BILLAN;;RIPAUX.OBJ;;
+511253873;BILLAN;delfile;//ISG/TEST/BILLAN;;SCHEDULE.OBJ;;
+511253874;BILLAN;delfile;//ISG/TEST/BILLAN;;TASK.OBJ;;
+511253874;BILLAN;delfile;//ISG/TEST/BILLAN;;USERPRO.OBJ;;
+511253957;BILLAN;delfile;//ISG/TEST/BILLAN;;KERNSTUB.EXE;;
+511254201;BILLAN;addfile;//ISG/TEST/BILLAN;;ATOM.OBJ;;
+511254203;BILLAN;addfile;//ISG/TEST/BILLAN;;CONTEXT.OBJ;;
+511254204;BILLAN;addfile;//ISG/TEST/BILLAN;;DISKIO.OBJ;;
+511254207;BILLAN;addfile;//ISG/TEST/BILLAN;;DOSINIT.OBJ;;
+511254209;BILLAN;addfile;//ISG/TEST/BILLAN;;GACHECK.OBJ;;
+511254211;BILLAN;addfile;//ISG/TEST/BILLAN;;GALLOC.OBJ;;
+511254213;BILLAN;addfile;//ISG/TEST/BILLAN;;GCOMPACT.OBJ;;
+511254216;BILLAN;addfile;//ISG/TEST/BILLAN;;GINTERF.OBJ;;
+511254217;BILLAN;addfile;//ISG/TEST/BILLAN;;GLRU.OBJ;;
+511254220;BILLAN;addfile;//ISG/TEST/BILLAN;;GMEM.OBJ;;
+511254221;BILLAN;addfile;//ISG/TEST/BILLAN;;HANDLE.OBJ;;
+511254225;BILLAN;addfile;//ISG/TEST/BILLAN;;INT21.OBJ;;
+511254228;BILLAN;addfile;//ISG/TEST/BILLAN;;INT24.OBJ;;
+511254230;BILLAN;addfile;//ISG/TEST/BILLAN;;KDATA.OBJ;;
+511254232;BILLAN;addfile;//ISG/TEST/BILLAN;;LACHECK.OBJ;;
+511254234;BILLAN;addfile;//ISG/TEST/BILLAN;;LALLOC.OBJ;;
+511254236;BILLAN;addfile;//ISG/TEST/BILLAN;;LCOMPACT.OBJ;;
+511254238;BILLAN;addfile;//ISG/TEST/BILLAN;;LD.OBJ;;
+511254241;BILLAN;addfile;//ISG/TEST/BILLAN;;LDAUX.OBJ;;
+511254244;BILLAN;addfile;//ISG/TEST/BILLAN;;LDBOOT.OBJ;;
+511254245;BILLAN;addfile;//ISG/TEST/BILLAN;;LDDEBUG.OBJ;;
+511254249;BILLAN;addfile;//ISG/TEST/BILLAN;;LDFASTB.OBJ;;
+511254250;BILLAN;addfile;//ISG/TEST/BILLAN;;LDFILE.OBJ;;
+511254253;BILLAN;addfile;//ISG/TEST/BILLAN;;LDHEADER.OBJ;;
+511254255;BILLAN;addfile;//ISG/TEST/BILLAN;;LDINIT.OBJ;;
+511254257;BILLAN;addfile;//ISG/TEST/BILLAN;;LDINT.OBJ;;
+511254259;BILLAN;addfile;//ISG/TEST/BILLAN;;LDOPEN.OBJ;;
+511254262;BILLAN;addfile;//ISG/TEST/BILLAN;;LDRELOC.OBJ;;
+511254265;BILLAN;addfile;//ISG/TEST/BILLAN;;LDSEG.OBJ;;
+511254267;BILLAN;addfile;//ISG/TEST/BILLAN;;LDSTACK.OBJ;;
+511254269;BILLAN;addfile;//ISG/TEST/BILLAN;;LDUTIL.OBJ;;
+511254272;BILLAN;addfile;//ISG/TEST/BILLAN;;LINTERF.OBJ;;
+511254274;BILLAN;addfile;//ISG/TEST/BILLAN;;LSTRING.OBJ;;
+511254277;BILLAN;addfile;//ISG/TEST/BILLAN;;RESAUX.OBJ;;
+511254279;BILLAN;addfile;//ISG/TEST/BILLAN;;RESMAN.OBJ;;
+511254282;BILLAN;addfile;//ISG/TEST/BILLAN;;RIP.OBJ;;
+511254284;BILLAN;addfile;//ISG/TEST/BILLAN;;RIPAUX.OBJ;;
+511254286;BILLAN;addfile;//ISG/TEST/BILLAN;;SCHEDULE.OBJ;;
+511254288;BILLAN;addfile;//ISG/TEST/BILLAN;;TASK.OBJ;;
+511254291;BILLAN;addfile;//ISG/TEST/BILLAN;;USERPRO.OBJ;;
+511254360;BILLAN;addfile;//ISG/TEST/BILLAN;;KERNSTUB.EXE;;
+511254586;BILLAN;defect;//ISG/TEST/BILLAN;;;;
+511254609;BILLAN;enlist;//ISG/TEST/BILLAN;;;;
+511255531;BILLAN;defect;//ISG/TEST/BILLAN;;;;
+511255556;BILLAN;enlist;//ISG/TEST/BILLAN;;;;
+511256272;BILLAN;defect;//ISG/TEST/BILLAN;;;;
+511256296;BILLAN;enlist;//ISG/TEST/BILLAN;;;;
+511256859;BILLAN;defect;//ISG/TEST/BILLAN;;;;
+315595952;MACHROOM;enlist;//ISG/TEST/BILLAN;;;;
+512069564;BILLAN;defect;//ISG/TEST/BILLAN;;;;
+512069698;BILLAN;enlist;//ISG/TEST/TRANSFER;;;;
+512077368;BILLAN;in;//ISG/TEST/TRANSFER;;ATOM.ASM;D0;
+512077370;BILLAN;in;//ISG/TEST/TRANSFER;;ATOM.OBJ;;
+512077388;BILLAN;in;//ISG/TEST/TRANSFER;;CONTEXT.ASM;D1;
+512077390;BILLAN;in;//ISG/TEST/TRANSFER;;CONTEXT.OBJ;;
+512077404;BILLAN;in;//ISG/TEST/TRANSFER;;DISKIO.ASM;D2;
+512077405;BILLAN;in;//ISG/TEST/TRANSFER;;DISKIO.OBJ;;
+512077444;BILLAN;in;//ISG/TEST/TRANSFER;;DOSINIT.ASM;D3;
+512077447;BILLAN;in;//ISG/TEST/TRANSFER;;DOSINIT.OBJ;;
+512077463;BILLAN;in;//ISG/TEST/TRANSFER;;GACHECK.C;D4;
+512077465;BILLAN;in;//ISG/TEST/TRANSFER;;GACHECK.OBJ;;
+512077476;BILLAN;in;//ISG/TEST/TRANSFER;;GADEBUG.H;D5;
+512077490;BILLAN;in;//ISG/TEST/TRANSFER;;GADUMP.C;D6;
+512077533;BILLAN;in;//ISG/TEST/TRANSFER;;GALLOC.ASM;D7;
+512077548;BILLAN;in;//ISG/TEST/TRANSFER;;GALLOC.INC;D8;
+512077550;BILLAN;in;//ISG/TEST/TRANSFER;;GALLOC.OBJ;;
+512077609;BILLAN;in;//ISG/TEST/TRANSFER;;GCOMPACT.ASM;D9;
+512077611;BILLAN;in;//ISG/TEST/TRANSFER;;GCOMPACT.OBJ;;
+512077620;BILLAN;in;//ISG/TEST/TRANSFER;;GINTERF.ASM;D10;
+512077623;BILLAN;in;//ISG/TEST/TRANSFER;;GINTERF.OBJ;;
+512077643;BILLAN;in;//ISG/TEST/TRANSFER;;GLRU.ASM;D11;
+512077644;BILLAN;in;//ISG/TEST/TRANSFER;;GLRU.OBJ;;
+512077711;BILLAN;in;//ISG/TEST/TRANSFER;;GMEM.ASM;D12;
+512077721;BILLAN;in;//ISG/TEST/TRANSFER;;GMEM.INC;D13;
+512077723;BILLAN;in;//ISG/TEST/TRANSFER;;GMEM.OBJ;;
+512077786;BILLAN;in;//ISG/TEST/TRANSFER;;GWINTERF.INC;D14;
+512077795;BILLAN;in;//ISG/TEST/TRANSFER;;GWMEM.INC;D15;
+512077816;BILLAN;in;//ISG/TEST/TRANSFER;;HANDLE.ASM;D16;
+512077826;BILLAN;in;//ISG/TEST/TRANSFER;;HANDLE.H;D17;
+512077840;BILLAN;in;//ISG/TEST/TRANSFER;;HANDLE.INC;D18;
+512077842;BILLAN;in;//ISG/TEST/TRANSFER;;HANDLE.OBJ;;
+512077856;BILLAN;in;//ISG/TEST/TRANSFER;;I21EXEC.INC;D19;
+512077870;BILLAN;in;//ISG/TEST/TRANSFER;;I21EXIT.INC;D20;
+512077882;BILLAN;in;//ISG/TEST/TRANSFER;;I21MEM.INC;D21;
+512077944;BILLAN;in;//ISG/TEST/TRANSFER;;INT21.ASM;D22;
+512077949;BILLAN;in;//ISG/TEST/TRANSFER;;INT21.OBJ;;
+512077972;BILLAN;in;//ISG/TEST/TRANSFER;;INT24.ASM;D23;
+512077973;BILLAN;in;//ISG/TEST/TRANSFER;;INT24.OBJ;;
+512077994;BILLAN;in;//ISG/TEST/TRANSFER;;KDATA.ASM;D24;
+512077997;BILLAN;in;//ISG/TEST/TRANSFER;;KDATA.OBJ;;
+512078012;BILLAN;in;//ISG/TEST/TRANSFER;;KDEBUG.INC;D25;
+512078032;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL;D26;
+512078041;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL.CCS;D27;
+512078056;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL.DEF;D28;
+512078087;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL.H;D29;
+512078101;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL.INC;D30;
+512078111;BILLAN;in;//ISG/TEST/TRANSFER;;KERNEL.LNK;D31;
+512078120;BILLAN;in;//ISG/TEST/TRANSFER;;KERNSTUB;D32;
+512078134;BILLAN;in;//ISG/TEST/TRANSFER;;KERNSTUB.ASM;D33;
+512078135;BILLAN;in;//ISG/TEST/TRANSFER;;KERNSTUB.EXE;;
+512078146;BILLAN;in;//ISG/TEST/TRANSFER;;KPR.BAT;D34;
+512078160;BILLAN;in;//ISG/TEST/TRANSFER;;LACHECK.C;D35;
+512078162;BILLAN;in;//ISG/TEST/TRANSFER;;LACHECK.OBJ;;
+512078172;BILLAN;in;//ISG/TEST/TRANSFER;;LADEBUG.H;D36;
+512078186;BILLAN;in;//ISG/TEST/TRANSFER;;LADUMP.C;D37;
+512078215;BILLAN;in;//ISG/TEST/TRANSFER;;LALLOC.ASM;D38;
+512078228;BILLAN;in;//ISG/TEST/TRANSFER;;LALLOC.INC;D39;
+512078229;BILLAN;in;//ISG/TEST/TRANSFER;;LALLOC.OBJ;;
+512078266;BILLAN;in;//ISG/TEST/TRANSFER;;LCOMPACT.ASM;D40;
+512078268;BILLAN;in;//ISG/TEST/TRANSFER;;LCOMPACT.OBJ;;
+512078285;BILLAN;in;//ISG/TEST/TRANSFER;;LD.C;D41;
+512078297;BILLAN;in;//ISG/TEST/TRANSFER;;LD.CCS;D42;
+512078299;BILLAN;in;//ISG/TEST/TRANSFER;;LD.OBJ;;
+512078343;BILLAN;in;//ISG/TEST/TRANSFER;;LDAUX.ASM;D43;
+512078345;BILLAN;in;//ISG/TEST/TRANSFER;;LDAUX.OBJ;;
+512078385;BILLAN;in;//ISG/TEST/TRANSFER;;LDBOOT.ASM;D44;
+512078388;BILLAN;in;//ISG/TEST/TRANSFER;;LDBOOT.OBJ;;
+512078408;BILLAN;in;//ISG/TEST/TRANSFER;;LDDEBUG.ASM;D45;
+512078410;BILLAN;in;//ISG/TEST/TRANSFER;;LDDEBUG.OBJ;;
+512078456;BILLAN;in;//ISG/TEST/TRANSFER;;LDFASTB.ASM;D46;
+512078459;BILLAN;in;//ISG/TEST/TRANSFER;;LDFASTB.OBJ;;
+512078476;BILLAN;in;//ISG/TEST/TRANSFER;;LDFILE.ASM;D47;
+512078477;BILLAN;in;//ISG/TEST/TRANSFER;;LDFILE.OBJ;;
+512078528;BILLAN;in;//ISG/TEST/TRANSFER;;LDHEADER.ASM;D48;
+512078530;BILLAN;in;//ISG/TEST/TRANSFER;;LDHEADER.OBJ;;
+512078540;BILLAN;in;//ISG/TEST/TRANSFER;;LDINIT.C;D49;
+512078542;BILLAN;in;//ISG/TEST/TRANSFER;;LDINIT.OBJ;;
+512078563;BILLAN;in;//ISG/TEST/TRANSFER;;LDINT.ASM;D50;
+512078565;BILLAN;in;//ISG/TEST/TRANSFER;;LDINT.OBJ;;
+512078607;BILLAN;in;//ISG/TEST/TRANSFER;;LDOPEN.ASM;D51;
+512078610;BILLAN;in;//ISG/TEST/TRANSFER;;LDOPEN.OBJ;;
+512078632;BILLAN;in;//ISG/TEST/TRANSFER;;LDRELOC.ASM;D52;
+512078634;BILLAN;in;//ISG/TEST/TRANSFER;;LDRELOC.OBJ;;
+512078688;BILLAN;in;//ISG/TEST/TRANSFER;;LDSEG.ASM;D53;
+512078692;BILLAN;in;//ISG/TEST/TRANSFER;;LDSEG.OBJ;;
+512078721;BILLAN;in;//ISG/TEST/TRANSFER;;LDSTACK.ASM;D54;
+512078724;BILLAN;in;//ISG/TEST/TRANSFER;;LDSTACK.OBJ;;
+512078756;BILLAN;in;//ISG/TEST/TRANSFER;;LDUTIL.ASM;D55;
+512078758;BILLAN;in;//ISG/TEST/TRANSFER;;LDUTIL.OBJ;;
+512078820;BILLAN;in;//ISG/TEST/TRANSFER;;LINTERF.ASM;D56;
+512078823;BILLAN;in;//ISG/TEST/TRANSFER;;LINTERF.OBJ;;
+512078847;BILLAN;in;//ISG/TEST/TRANSFER;;LSTRING.ASM;D57;
+512078850;BILLAN;in;//ISG/TEST/TRANSFER;;LSTRING.OBJ;;
+512078860;BILLAN;in;//ISG/TEST/TRANSFER;;MEM.CCS;D58;
+512078870;BILLAN;in;//ISG/TEST/TRANSFER;;MISC.CCS;D59;
+512078880;BILLAN;in;//ISG/TEST/TRANSFER;;MKKERNEL.BAT;D60;
+512078918;BILLAN;in;//ISG/TEST/TRANSFER;;NEWEXE.DOC;D61;
+512078948;BILLAN;in;//ISG/TEST/TRANSFER;;NEWEXE.H;D62;
+512078969;BILLAN;in;//ISG/TEST/TRANSFER;;NEWEXE.INC;D63;
+512078979;BILLAN;in;//ISG/TEST/TRANSFER;;NULOBJ.ASM;D64;
+512078990;BILLAN;in;//ISG/TEST/TRANSFER;;PDB.INC;D65;
+512079000;BILLAN;in;//ISG/TEST/TRANSFER;;RELKERN.BAT;D66;
+512079037;BILLAN;in;//ISG/TEST/TRANSFER;;RESAUX.ASM;D67;
+512079039;BILLAN;in;//ISG/TEST/TRANSFER;;RESAUX.OBJ;;
+512079057;BILLAN;in;//ISG/TEST/TRANSFER;;RESMAN.C;D68;
+512079059;BILLAN;in;//ISG/TEST/TRANSFER;;RESMAN.OBJ;;
+512079088;BILLAN;in;//ISG/TEST/TRANSFER;;RIP.C;D69;
+512079091;BILLAN;in;//ISG/TEST/TRANSFER;;RIP.OBJ;;
+512079105;BILLAN;in;//ISG/TEST/TRANSFER;;RIPAUX.ASM;D70;
+512079107;BILLAN;in;//ISG/TEST/TRANSFER;;RIPAUX.OBJ;;
+512079129;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS.CHK;D71;
+512079219;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0106.LOG;D72;
+512079312;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0118.LOG;D73;
+512079408;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0205.LOG;D74;
+512079478;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0310.LOG;D75;
+512079563;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0326.LOG;D76;
+512079669;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0410.LOG;D77;
+512079771;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0424.LOG;D78;
+512079861;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0505.LOG;D79;
+512079968;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0523.LOG;D80;
+512080064;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0608.LOG;D81;
+512080167;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0623.LOG;D82;
+512080274;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0731.LOG;D83;
+512080384;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS0820.LOG;D84;
+512080517;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS1022.LOG;D85;
+512080626;BILLAN;in;//ISG/TEST/TRANSFER;;SCCS1205.LOG;D86;
+512083239;BILLAN;in;//ISG/TEST/TRANSFER;;WIN;D87;
+512083288;BILLAN;in;//ISG/TEST/TRANSFER;;WIN.ASM;D88;
+512083298;BILLAN;in;//ISG/TEST/TRANSFER;;WIN.CCS;D89;
+512083310;BILLAN;in;//ISG/TEST/TRANSFER;;WIN.CNF;D90;
+512083320;BILLAN;in;//ISG/TEST/TRANSFER;;WINOBJ.CCS;D91;
+512083330;BILLAN;in;//ISG/TEST/TRANSFER;;WINSTUB;D92;
+512083340;BILLAN;in;//ISG/TEST/TRANSFER;;WINSTUB.ASM;D93;
+512083675;BILLAN;in;//ISG/TEST/TRANSFER;;TASK.ASM;D94;
+512083677;BILLAN;in;//ISG/TEST/TRANSFER;;TASK.OBJ;;
+512083693;BILLAN;in;//ISG/TEST/TRANSFER;;TDB.INC;D95;
+512084228;BILLAN;in;//ISG/TEST/TRANSFER;;USERPRO.ASM;D96;
+512084231;BILLAN;in;//ISG/TEST/TRANSFER;;USERPRO.OBJ;;
+512084299;BILLAN;in;//ISG/TEST/TRANSFER;;SCHED.CCS;D97;
+512084315;BILLAN;in;//ISG/TEST/TRANSFER;;SCHED.INC;D98;
+512084336;BILLAN;in;//ISG/TEST/TRANSFER;;SCHEDULE.ASM;D99;
+512084338;BILLAN;in;//ISG/TEST/TRANSFER;;SCHEDULE.OBJ;;
+512087683;BILLAN;defect;//ISG/TEST/TRANSFER;;;;
+512087783;BILLAN;enlist;//ISG/TEST/TRANSFER;;;;
+512087888;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNEL.EXE;;
+512087893;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNEL.OLD;;
+512087900;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNEL.LIB;;
+512087918;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNEL.MAP;;
+512087923;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNEL.SYM;;
+512087995;BILLAN;addfile;//ISG/TEST/TRANSFER;;FLOPBACK.BAT;;
+512087997;BILLAN;addfile;//ISG/TEST/TRANSFER;;KERNSTUB.OLD;;
+512087998;BILLAN;addfile;//ISG/TEST/TRANSFER;;WINSTUB.EXE;;
+512088000;BILLAN;addfile;//ISG/TEST/TRANSFER;;WINSTUB.OLD;;
+512088002;BILLAN;addfile;//ISG/TEST/TRANSFER;;CHKOUT.BAK;;
+512088004;BILLAN;addfile;//ISG/TEST/TRANSFER;;CHKOUT.BAT;;
+512088052;BILLAN;delfile;//ISG/TEST/TRANSFER;;FLOPBACK.BAT;;
+512088095;BILLAN;delfile;//ISG/TEST/TRANSFER;;CHKOUT.BAK;;
+512088095;BILLAN;delfile;//ISG/TEST/TRANSFER;;CHKOUT.BAT;;
+512088151;BILLAN;defect;//ISG/TEST/TRANSFER;;;;
+513323211;STEVEWO;enlist;//C:STEVEWO/WIN/KERNEL;;;;
+513324483;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;EI;;
+513324929;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;HEAPWALK;;
+513325756;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS.CHK;D100;
+513325817;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0106.LOG;D101;
+513325879;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0118.LOG;D102;
+513325944;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0205.LOG;D103;
+513325989;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0310.LOG;D104;
+513326040;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0326.LOG;D105;
+513326112;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0410.LOG;D106;
+513326181;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0424.LOG;D107;
+513326240;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0505.LOG;D108;
+513326313;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0523.LOG;D109;
+513326377;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0608.LOG;D110;
+513326447;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0623.LOG;D111;
+513326520;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0731.LOG;D112;
+513326593;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS0820.LOG;D113;
+513326686;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS1022.LOG;D114;
+513326761;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS1205.LOG;D115;
+513328182;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCCS1220.DIF;D116;
+513328274;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.OLD;D117;
+513328277;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNSTUB.OLD;D118;
+513328279;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WINSTUB.OLD;D119;
+513328312;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KPR.BAT;D120;
+513328314;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;MKKERNEL.BAT;D121;
+513328317;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RELKERN.BAT;D122;
+513328328;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.CCS;D123;
+513328332;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LD.CCS;D124;
+513328335;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;MEM.CCS;D125;
+513328337;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;MISC.CCS;D126;
+513328340;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCHED.CCS;D127;
+513328343;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WIN.CCS;D128;
+513328345;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WINOBJ.CCS;D129;
+513328647;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RETAIL;;
+513328672;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;rkernel;;
+513330545;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.EXE;D130;
+513330582;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.MAP;D131;
+513330591;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.SYM;D132;
+513330592;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNSTUB.EXE;;
+513330595;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WINSTUB.EXE;D133;
+513367911;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KERNEL.LIB;D134;
+517554185;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;ATOM.OBJ;;
+517554185;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;CONTEXT.OBJ;;
+517554186;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;DISKIO.OBJ;;
+517554186;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;DOSINIT.OBJ;;
+517554187;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GACHECK.OBJ;;
+517554187;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GALLOC.OBJ;;
+517554188;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GCOMPACT.OBJ;;
+517554188;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GINTERF.OBJ;;
+517554189;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GLRU.OBJ;;
+517554189;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GMEM.OBJ;;
+517554189;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;HANDLE.OBJ;;
+517554190;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;INT21.OBJ;;
+517554190;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;INT24.OBJ;;
+517554191;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KDATA.OBJ;;
+517554191;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LACHECK.OBJ;;
+517554192;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LALLOC.OBJ;;
+517554192;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LCOMPACT.OBJ;;
+517554193;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LD.OBJ;;
+517554193;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDAUX.OBJ;;
+517554194;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDBOOT.OBJ;;
+517554194;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDDEBUG.OBJ;;
+517554194;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDFASTB.OBJ;;
+517554195;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDFILE.OBJ;;
+517554195;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDHEADER.OBJ;;
+517554196;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDINIT.OBJ;;
+517554196;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDINT.OBJ;;
+517554197;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDOPEN.OBJ;;
+517554197;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDRELOC.OBJ;;
+517554198;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDSEG.OBJ;;
+517554198;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDSTACK.OBJ;;
+517554198;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LDUTIL.OBJ;;
+517554199;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LINTERF.OBJ;;
+517554200;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LSTRING.OBJ;;
+517554200;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RESAUX.OBJ;;
+517554200;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RESMAN.OBJ;;
+517554201;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RIP.OBJ;;
+517554201;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;RIPAUX.OBJ;;
+517554202;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;SCHEDULE.OBJ;;
+517554202;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;TASK.OBJ;;
+517554203;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;USERPRO.OBJ;;
+517593300;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LADUMP.C;D135;
+517706801;SEANS;enlist;//C:SEANS/WINDOWS/KERNEL;;;;
+517734071;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WIN.CNF;D136;
+518299490;BUILD400;enlist;//C:BUILD400/WINDOWS/KERNEL;;;;
+518463394;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GADEBUG.H;D137;
+518463445;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GADUMP.C;D138;
+518463491;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GALLOC.INC;D139;
+518463506;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GMEM.INC;D140;
+518464068;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GWINTERF.INC;D141;
+518464079;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;GWMEM.INC;D142;
+518464094;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;HANDLE.H;D143;
+518464140;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;HANDLE.INC;D144;
+518464210;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;I21EXEC.INC;D145;
+518464274;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;I21EXIT.INC;D146;
+518464319;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;I21MEM.INC;D147;
+518464429;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;KDEBUG.INC;D148;
+518464449;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LADEBUG.H;D149;
+518464488;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;LALLOC.INC;D150;
+518465017;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;i21exec.asm;;replaces i21exec.inc
+518465072;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;i21exit.asm;;replaces i21exit.inc
+518465095;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;i21mem.asm;;replaces i21mem.inc
+518465107;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;kernobj;;make file for KERNOBJ.LIB
+518465136;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;kernobj.lnk;;LIB script for KERNOBJ.LIB
+518465182;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;strings.asm;;Separate file for internationalization
+518465204;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;winkern.inc;;replaces handle.inc lalloc.inc galloc.inc kdebug.inc
+518465241;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;mkoem.bat;;File to build KERNEL from STRINGS.ASM and KERNOBJ.LIB
+518465261;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;reloem.bat;;File to build a disk for internationalization of KERNEL
+518465357;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;ATOM.ASM;D151;Version 1.20 changes
+518465378;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;CONTEXT.ASM;D152;Version 1.20 changes
+518465390;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;DISKIO.ASM;D153;Version 1.20 changes
+518465414;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;DOSINIT.ASM;D154;Version 1.20 changes
+518465426;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GACHECK.C;D155;Version 1.20 changes
+518465452;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GALLOC.ASM;D156;Version 1.20 changes
+518465491;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GCOMPACT.ASM;D157;Version 1.20 changes
+518465536;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GINTERF.ASM;D158;Version 1.20 changes
+518465555;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GLRU.ASM;D159;Version 1.20 changes
+518465611;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GMEM.ASM;D160;Version 1.20 changes
+518465624;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;HANDLE.ASM;D161;Version 1.20 changes
+518466377;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;INT21.ASM;D162;Version 1.20 changes
+518466529;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;INT24.ASM;D163;Version 1.20 changes
+518466635;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KDATA.ASM;D164;Version 1.20 changes
+518466703;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL;D165;Version 1.20 changes
+518466782;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.DEF;D166;Version 1.20 changes
+518466815;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.H;D167;Version 1.20 changes
+518466849;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D168;Version 1.20 changes
+518466856;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.LNK;D169;Version 1.20 changes
+518466863;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNSTUB;D170;Version 1.20 changes
+518466871;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNSTUB.ASM;D171;Version 1.20 changes
+518466881;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LACHECK.C;D172;Version 1.20 changes
+518466909;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LALLOC.ASM;D173;Version 1.20 changes
+518466947;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LCOMPACT.ASM;D174;Version 1.20 changes
+518467065;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LD.C;D175;Version 1.20 changes
+518467136;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDAUX.ASM;D176;Version 1.20 changes
+518467177;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDBOOT.ASM;D177;Version 1.20 changes
+518467242;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDDEBUG.ASM;D178;Version 1.20 changes
+518467280;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDFASTB.ASM;D179;Version 1.20 changes
+518467294;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDFILE.ASM;D180;Version 1.20 changes
+518467350;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDHEADER.ASM;D181;Version 1.20 changes
+518467355;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDINIT.C;D182;Version 1.20 changes
+518467373;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDINT.ASM;D183;Version 1.20 changes
+518467931;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDOPEN.ASM;D184;Version 1.20 changes
+518467949;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDRELOC.ASM;D185;Version 1.20 changes
+518468052;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDSEG.ASM;D186;Version 1.20 changes
+518468068;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDSTACK.ASM;D187;Version 1.20 changes
+518468091;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDUTIL.ASM;D188;Version 1.20 changes
+518468134;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LINTERF.ASM;D189;Version 1.20 changes
+518468151;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LSTRING.ASM;D190;Version 1.20 changes
+518468297;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.H;D191;Version 1.20 changes
+518468314;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.INC;D192;Version 1.20 changes
+518468319;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NULOBJ.ASM;D193;Version 1.20 changes
+518468324;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;PDB.INC;D194;Version 1.20 changes
+518468344;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESAUX.ASM;D195;Version 1.20 changes
+518468352;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESMAN.C;D196;Version 1.20 changes
+518468481;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIP.C;D197;Version 1.20 changes
+518468492;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D198;Version 1.20 changes
+518468504;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHED.INC;D199;Version 1.20 changes
+518468635;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHEDULE.ASM;D200;Version 1.20 changes
+518468654;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;TASK.ASM;D201;Version 1.20 changes
+518468663;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;TDB.INC;D202;Version 1.20 changes
+518469017;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;USERPRO.ASM;D203;Version 1.20 changes
+518469020;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;WIN;D204;Version 1.20 changes
+518469045;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;WIN.ASM;D205;Version 1.20 changes
+518469049;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;WINSTUB;D206;Version 1.20 changes
+518469054;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;WINSTUB.ASM;D207;Version 1.20 changes
+518472843;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;;
+518472845;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286PDB.INC;;
+518472854;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286MEM.ASM;;
+518472856;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286;;
+518472860;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;;
+518472862;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286KERN.DEF;;
+518472867;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;;
+518472868;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286KERN.LNK;;
+518472871;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;;
+518683493;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDOPEN.ASM;D208;Move TF_FORCEDRIVE to winkern.inc
+518683515;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;winkern.inc;D209;Added TF_FORCEDRIVE
+518683793;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WIN;D210;
+518683795;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;WINSTUB;D211;
+518683818;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL;D212;Merged in WIN. and WINSTUB. make files
+518733291;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GINTERF.ASM;D213;Fixed to handle request for more than 1 meg
+518768186;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDSEG.ASM;D214;Added better error reporting to SegLoad
+518892418;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDBOOT.ASM;D215;Removed bogus code for switching to CGA monitor
+518987250;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;USERPRO.ASM;D216;Fixed bug with WriteProfileString
+518987277;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;winkern.inc;D217;Made shareable with WINOLDAP
+520205977;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286;D218;More 286DOS changes
+520205988;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;D219;More 286DOS changes
+520206009;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D220;More 286DOS changes
+520206013;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286KERN.LNK;D221;More 286DOS changes
+520206025;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D222;More 286DOS changes
+520206052;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286MEM.ASM;D223;More 286DOS changes
+520206070;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D224;More 286DOS changes
+520206118;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;DISKIO.ASM;D225;More 286DOS changes
+520206168;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;INT24.ASM;D226;More 286DOS changes
+520206193;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.H;D227;More 286DOS changes
+520206214;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D228;More 286DOS changes
+520206238;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDBOOT.ASM;D229;More 286DOS changes
+520206324;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDOPEN.ASM;D230;More 286DOS changes
+520206346;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LSTRING.ASM;D231;More 286DOS changes
+520206382;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESAUX.ASM;D232;More 286DOS changes
+520206391;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESMAN.C;D233;More 286DOS changes
+520206407;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIP.C;D234;More 286DOS changes
+520206426;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D235;More 286DOS changes
+520206444;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHED.INC;D236;More 286DOS changes
+520206454;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;strings.asm;D237;More 286DOS changes
+520206506;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;USERPRO.ASM;D238;More 286DOS changes
+521959817;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286;D239;More 286DOS changes and fix to LDHEADER.ASM
+521959824;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;D240;More 286DOS changes and fix to LDHEADER.ASM
+521959839;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D241;More 286DOS changes and fix to LDHEADER.ASM
+521959847;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286KERN.DEF;D242;More 286DOS changes and fix to LDHEADER.ASM
+521959851;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286KERN.LNK;D243;More 286DOS changes and fix to LDHEADER.ASM
+521959871;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D244;More 286DOS changes and fix to LDHEADER.ASM
+521959883;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286MEM.ASM;D245;More 286DOS changes and fix to LDHEADER.ASM
+521959895;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D246;More 286DOS changes and fix to LDHEADER.ASM
+521959906;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;DOSINIT.ASM;D247;More 286DOS changes and fix to LDHEADER.ASM
+521959912;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.DEF;D248;More 286DOS changes and fix to LDHEADER.ASM
+521959919;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D249;More 286DOS changes and fix to LDHEADER.ASM
+521959925;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDDEBUG.ASM;D250;More 286DOS changes and fix to LDHEADER.ASM
+521959936;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDFASTB.ASM;D251;More 286DOS changes and fix to LDHEADER.ASM
+521959948;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDHEADER.ASM;D252;More 286DOS changes and fix to LDHEADER.ASM
+521959957;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.H;D253;More 286DOS changes and fix to LDHEADER.ASM
+521959964;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.INC;D254;More 286DOS changes and fix to LDHEADER.ASM
+521959973;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESAUX.ASM;D255;More 286DOS changes and fix to LDHEADER.ASM
+521959982;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIP.C;D256;More 286DOS changes and fix to LDHEADER.ASM
+521959989;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D257;More 286DOS changes and fix to LDHEADER.ASM
+521959995;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHED.INC;D258;More 286DOS changes and fix to LDHEADER.ASM
+521960429;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286win.asm;;
+521960431;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286ld.c;;
+521960433;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286lh.asm;;
+521960436;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286int21.asm;;
+521960477;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286win.def;;
+522703702;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;D259;
+522703720;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D260;
+522703736;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286int21.asm;D261;
+522703760;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286ld.c;D262;
+522703789;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286lh.asm;D263;
+522703862;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D264;
+522703870;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286win.asm;D265;
+522703877;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286win.def;D266;
+522703886;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;CONTEXT.ASM;D267;
+522703898;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D268;
+522703913;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D269;
+522703923;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHEDULE.ASM;D270;
+522703981;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;TASK.ASM;D271;
+522714373;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D272;
+523673767;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D273;More 286DOS fixes
+523673773;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286KERN.DEF;D274;More 286DOS fixes
+523673782;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D275;More 286DOS fixes
+523673788;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286win.asm;D276;More 286DOS fixes
+523673793;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286win.def;D277;More 286DOS fixes
+523673798;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.DEF;D278;More 286DOS fixes
+523673806;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LD.C;D279;More 286DOS fixes
+523673816;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDBOOT.ASM;D280;More 286DOS fixes
+523673827;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDHEADER.ASM;D281;More 286DOS fixes
+523673835;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDRELOC.ASM;D282;More 286DOS fixes
+523673845;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDUTIL.ASM;D283;More 286DOS fixes
+523673855;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;USERPRO.ASM;D284;More 286DOS fixes
+523911795;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D285;More 286DOS fixes
+523911810;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286int21.asm;D286;More 286DOS fixes
+523911817;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286KERN.DEF;D287;More 286DOS fixes
+523911824;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286lh.asm;D288;More 286DOS fixes
+523911835;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D289;More 286DOS fixes
+523911847;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286MEM.ASM;D290;More 286DOS fixes
+523911864;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D291;More 286DOS fixes
+523911882;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;INT21.ASM;D292;More 286DOS fixes
+523911889;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.DEF;D293;More 286DOS fixes
+523911906;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDOPEN.ASM;D294;More 286DOS fixes
+523911913;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LSTRING.ASM;D295;More 286DOS fixes
+523911920;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.INC;D296;More 286DOS fixes
+523911931;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RESAUX.ASM;D297;More 286DOS fixes
+524182168;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D298;oops
+524252672;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDDEBUG.ASM;D299;Fix RET in OutputDebugString
+524254820;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KDATA.ASM;D300;Updated version to 2.0
+524272432;CHUCKWH;enlist;//D:CHUCKWHII/KERNEL;;;;
+524275786;DAVIDW;enlist;//C:DAVIDW/WINKERN;;;;
+524367061;DAVIDW;defect;//C:DAVIDW/WINKERN;;;;
+524367209;DAVIDW;enlist;//D:DWEISE/KERNEL;;;;
+524875815;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;D301;More 286 stuff
+524875823;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D302;More 286 stuff
+524875835;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D303;More 286 stuff
+524875843;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D304;More 286 stuff
+524875854;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;LDBOOT.ASM;D305;More 286 stuff
+524875864;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIP.C;D306;More 286 stuff
+524875871;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D307;More 286 stuff
+525032571;CHUCKWH;defect;//D:CHUCKWHII/KERNEL;;;;
+525110379;STEVEWO;delfile;//C:STEVEWO/WIN/KERNEL;;286PDB.INC;D308;
+525110393;STEVEWO;addfile;//C:STEVEWO/WIN/KERNEL;;286.inc;;replaces 286pdb.inc
+525553319;CHUCKWH;enlist;//D:CHUCKWH/KERNEL;;;;
+525649248;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286.inc;D309;More 286DOS hacks
+525649254;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286DATA.ASM;D310;More 286DOS hacks
+525649260;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286INIT.ASM;D311;More 286DOS hacks
+525649268;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286lh.asm;D312;More 286DOS hacks
+525649278;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286LM.ASM;D313;More 286DOS hacks
+525649290;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286TASK.ASM;D314;More 286DOS hacks
+525649294;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;286win.def;D315;More 286DOS hacks
+525649302;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;KERNEL.INC;D316;More 286DOS hacks
+525649309;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;SCHED.INC;D317;More 286DOS hacks
+525821488;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D318;Added checks for EEMS in PreBootStrap
+525823372;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KDATA.ASM;D319;Added EEMS variables
+525823377;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D320;Added EEMS variables
+525830126;DAVIDW;enlist;//D:DAVIDW/KERNEL;;;;
+525845931;CHUCKWH;in;//D:CHUCKWH/KERNEL;;DOSINIT.ASM;D321;Added more initialization for EEMS
+525845934;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KDATA.ASM;D322;Added more initialization for EEMS
+525845939;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D323;Added more initialization for EEMS
+525845942;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHED.INC;D324;Added more initialization for EEMS
+525908412;CHUCKWH;addfile;//D:CHUCKWH/KERNEL;;eems.inc;;defines constants for EEMS
+525912221;CHUCKWH;in;//D:CHUCKWH/KERNEL;;DOSINIT.ASM;D325;Put all EEMS definitions in EEMS.INC
+525912225;CHUCKWH;in;//D:CHUCKWH/KERNEL;;eems.inc;D326;Put all EEMS definitions in EEMS.INC
+525912229;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D327;Put all EEMS definitions in EEMS.INC
+525912233;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHED.INC;D328;Put all EEMS definitions in EEMS.INC
+525912237;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D329;Put all EEMS definitions in EEMS.INC
+525912241;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TASK.ASM;D330;Put all EEMS definitions in EEMS.INC
+525913236;CHUCKWH;in;//D:CHUCKWH/KERNEL;;eems.inc;D331;Defined all EMM commands
+525921231;DAVIDW;in;//D:DAVIDW/KERNEL;;eems.inc;D332;Added EMMBitArraySize.
+525921284;DAVIDW;in;//D:DAVIDW/KERNEL;;KDATA.ASM;D333;Added EMMBitArraySize.
+525922165;DAVIDW;in;//D:DAVIDW/KERNEL;;TDB.INC;D334;Put in variables for EEMS support.
+526065469;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D335;Just a test of SLM.
+526065522;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D336;Just a test of SLM.
+526065775;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D337;Just a test of SLM.
+526065914;DAVIDW;enlist;//D:DAVIDW/TEST;;;;
+526066070;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D338;Just a test of SLM.
+526066306;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D339;just a test
+526066339;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D340;just a test
+526066368;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D341;just a test
+526066393;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D342;just a test
+526066460;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D343;just a test
+526066530;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D344;test
+526066606;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D345;cdd'd
+526066645;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D346;test
+526066690;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D347;test
+526066988;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D348;test
+526067019;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D349;test
+526067057;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D350;test
+526067328;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D351;test
+526067372;DAVIDW;in;//D:DAVIDW/TEST;;TASK.ASM;D352;test
+526068238;DAVIDW;defect;//D:DAVIDW/TEST;;;;
+526072649;DAVIDW;in;//D:DAVIDW/KERNEL;;DOSINIT.ASM;D353;Made it initialize EMMBitArraySize.
+526073792;DANL;enlist;//C:DANL/KERNTMP;;;;
+526073838;DANL;in;//C:DANL/KERNTMP;;TASK.ASM;D354;test
+526074529;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TDB.INC;D355;No change really
+526074772;DANL;defect;//C:DANL/KERNTMP;;;;
+526077537;SEANS;defect;//C:SEANS/WINDOWS/KERNEL;;;;
+526083495;DAVIDW;in;//D:DAVIDW/KERNEL;;DOSINIT.ASM;D356;Removed a spurious int 3.
+526111447;CHUCKWH;in;//D:CHUCKWH/KERNEL;;DOSINIT.ASM;D357;Changed EEMS function numbers
+526111450;CHUCKWH;in;//D:CHUCKWH/KERNEL;;eems.inc;D358;Changed EEMS function numbers
+526111454;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL;D359;Changed EEMS function numbers
+526287489;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;DOSINIT.ASM;D361;Removed INT 3 from testemm procedure
+526287514;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GINTERF.ASM;D362;Fixed bug with GlobalSize and discarded handles
+526287539;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;i21exit.asm;D363;Removed bogus exit fix
+526287554;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;RIPAUX.ASM;D364;Fixed assumes in GetExeHead
+526599787;DAVIDW;in;//D:DAVIDW/KERNEL;;TDB.INC;D366;Test.
+526600977;DAVIDW;in;//D:DAVIDW/KERNEL;;TDB.INC;D367;Test.
+526606220;DAVIDW;in;//D:DAVIDW/KERNEL;;PDB.INC;D368;Added PDB_EMMHeap.
+526610548;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D369;Moved ginit from INITCODE to CODE.
+526672436;DAVIDW;in;//D:DAVIDW/KERNEL;;PDB.INC;D370;Added PDB_EMMhHeap.
+526686425;DAVIDW;in;//D:DAVIDW/KERNEL;;eems.inc;D372;Set EEMS_DEBUG = 0.
+526687055;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D373;Added MASTER_OBJECT_SIZE
+526687151;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D374;Changed a comment.
+526864644;DAVIDW;in;//D:DAVIDW/KERNEL;;PDB.INC;D377;Took out PDB_EMMpHeap and PDB_EMMhHeap.
+526867015;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL.INC;D378;added alternate heap info variables
+526867024;CHUCKWH;in;//D:CHUCKWH/KERNEL;;winkern.inc;D379;added alternate heap info variables
+526935828;CHUCKWH;in;//D:CHUCKWH/KERNEL;;GCOMPACT.ASM;D380;Publicized a temporary stack
+526935836;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL.INC;D381;Publicized a temporary stack
+526935844;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D382;Publicized a temporary stack
+526949499;DAVIDW;addfile;//D:DAVIDW/KERNEL;;emm.asm;;For better EEMS support.
+526949651;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D376;Put GlobalInit back into INITCODE, made it handle the case of no allocated block correctly.
+526949712;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D375;Put ginit back into INITCODE, ade it handle the case of no allocated block correctly.
+526949732;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D383;Added emm.asm.
+526949749;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D384;Added emm.asm.
+526949869;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D360;Adding support for EEMS into CreateTask. Added EMMInit.
+526950338;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D365;Padded the fake static task to have a large emm swap area.
+526950449;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D385;Took out a random int 3.
+526950508;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D386;Took out a random int 3.
+527030904;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D387;added EEMSDiscard and EEMSUnDiscard
+527033552;DAVIDW;in;//D:DAVIDW/KERNEL;;emm.asm;D389;Make EMMGlobalInit link together disjoint blocks.
+527033586;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D388;Moved a couple of procs to emm.asm
+527035026;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D390;Added dependencies for emm.obj.
+527042039;DAVIDW;in;//D:DAVIDW/KERNEL;;emm.asm;D391;Fixed a small bug.
+527190543;DAVIDW;in;//D:DAVIDW/KERNEL;;INT21.ASM;D392;Added dependency on eems.inc.
+527190587;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D393;Added dependency on eems.inc.
+527199310;DAVIDW;in;//D:DAVIDW/KERNEL;;i21exit.asm;D371;Made it free a EEMS_PID when it frees a task.
+527373721;CHUCKWH;in;//D:CHUCKWH/KERNEL;;emm.asm;D394;removed an int 3
+527373727;CHUCKWH;in;//D:CHUCKWH/KERNEL;;i21exit.asm;D395;removed an int 3
+527441580;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LD.C;D396;Started INSIDER mods for LoadModule
+527463179;DAVIDW;in;//D:DAVIDW/KERNEL;;TASK.ASM;D398;Made CreateTask pass the correct ax to the task it's creating.
+527463200;DAVIDW;in;//D:DAVIDW/KERNEL;;TDB.INC;D399;Added TDB_Validity.
+527629056;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LD.C;D400;Made new tasks load their own modules
+527629079;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDHEADER.ASM;D401;Made new tasks load their own modules
+527629088;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D402;Made new tasks load their own modules
+527633671;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D403;Fixed a small bug in initializing the fake TDB.
+527871957;CHUCKWH;addfile;//D:CHUCKWH/KERNEL;;mtask.asm;;Will contain new multitasking calls
+527871984;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL;D404;Support for new file mtask.asm
+527871990;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL.DEF;D405;Support for new file mtask.asm
+527871996;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL.LNK;D406;Support for new file mtask.asm
+527893105;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;GINTERF.ASM;D407;Fixed bug with GlobalSize and FIXED segments
+527903038;CHUCKWH;in;//D:CHUCKWH/KERNEL;;mtask.asm;D408;Added support for NULL pointers in DosSetVec
+527963485;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D409;Fixed two small bugs, restructured a bit, and added comment blocks.
+527967337;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL;D410;Fixed dependences on tdb.inc
+527967379;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TDB.INC;D411;Save only vectors 0,4,6,7 on per task basis
+527967419;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D412;Deleted redundant register setting
+527970879;DAVIDW;in;//D:DAVIDW/KERNEL;;emm.asm;D413;Made EMMGlobalInit set gi_alt_reserve.
+528057308;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D414;Removed the assumption that SS = TDB in initialization
+528057319;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TASK.ASM;D415;Removed the assumption that SS = TDB in initialization
+528076706;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D416;Put thread support in TDBs
+528076723;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDHEADER.ASM;D417;Put thread support in TDBs
+528076733;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDSTACK.ASM;D418;Put thread support in TDBs
+528076744;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TASK.ASM;D419;Put thread support in TDBs
+528076752;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TDB.INC;D420;Put thread support in TDBs
+528082211;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D421;Added thread initialization
+528082223;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TASK.ASM;D422;Added thread initialization
+528082230;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TDB.INC;D423;Added thread initialization
+528099205;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.H;D424;
+528099213;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;NEWEXE.INC;D425;
+528406819;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D426;Commented and restructured.
+528406914;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D427;Added comment blocks, reworked gdiscard.
+528406995;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D428;Added comment blocks, reworked gavail, and moved ?lrusweep to glru.asm.
+528407024;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D429;Moved ?glrusweep here from ginterf.asm.
+528496870;CHUCKWH;in;//D:CHUCKWH/KERNEL;;CONTEXT.ASM;D430;Completed thread handling
+528496878;CHUCKWH;in;//D:CHUCKWH/KERNEL;;emm.asm;D431;Completed thread handling
+528496883;CHUCKWH;in;//D:CHUCKWH/KERNEL;;i21exec.asm;D432;Completed thread handling
+528496901;CHUCKWH;in;//D:CHUCKWH/KERNEL;;i21exit.asm;D433;Completed thread handling
+528496923;CHUCKWH;in;//D:CHUCKWH/KERNEL;;INT21.ASM;D434;Completed thread handling
+528496932;CHUCKWH;in;//D:CHUCKWH/KERNEL;;INT24.ASM;D435;Completed thread handling
+528496940;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KDATA.ASM;D436;Completed thread handling
+528496955;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDBOOT.ASM;D437;Completed thread handling
+528496973;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDHEADER.ASM;D438;Completed thread handling
+528496991;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDOPEN.ASM;D439;Completed thread handling
+528497010;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDSEG.ASM;D440;Completed thread handling
+528497019;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDSTACK.ASM;D441;Completed thread handling
+528497026;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHED.INC;D442;Completed thread handling
+528497048;CHUCKWH;in;//D:CHUCKWH/KERNEL;;SCHEDULE.ASM;D443;Completed thread handling
+528497065;CHUCKWH;in;//D:CHUCKWH/KERNEL;;TASK.ASM;D444;Completed thread handling
+528568690;DAVIDW;addfile;//D:DAVIDW/KERNEL;;dinterf.asm;;The new DOS5 memory manager interface.
+528568715;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D445;Put in some comment blocks.
+528568735;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D446;Added dinterf.asm.
+528568741;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D447;Added dinterf.asm.
+528574862;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LD.C;D449;generalized QuickStartTask
+528574885;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LDHEADER.ASM;D450;generalized QuickStartTask
+528657009;DAVIDW;in;//D:DAVIDW/KERNEL;;i21mem.asm;D451;Changed "M" and "Z" to GA_... .
+528661288;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D452;Added initialization for gi_disfence.
+528662203;DAVIDW;in;//D:DAVIDW/KERNEL;;LDFASTB.ASM;D453;Deleted an extern.
+528786287;CHUCKWH;in;//D:CHUCKWH/KERNEL;;LD.C;D454;Allocated more stack space for INSIDER
+528786312;CHUCKWH;in;//D:CHUCKWH/KERNEL;;KERNEL.DEF;D455;Added DosCreateThread
+528786325;CHUCKWH;in;//D:CHUCKWH/KERNEL;;mtask.asm;D456;Added DosCreateThread
+529087138;CHUCKWH;in;//D:CHUCKWH/KERNEL;;mtask.asm;D458;Fixed stack underflow in DosCreateThread
+529261998;DAVIDW;in;//D:DAVIDW/KERNEL;;emm.asm;D459;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262006;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D460;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262010;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D457;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262013;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D462;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262020;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D463;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262031;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D464;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262041;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.H;D471;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262045;DAVIDW;in;//D:DAVIDW/KERNEL;;LDAUX.ASM;D465;Temporarily added to NEW_SEG1 and HandleEntry for change to new DOS5 memory manager interface.
+529262055;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D466;
+529262058;DAVIDW;in;//D:DAVIDW/KERNEL;;LDHEADER.ASM;D467;
+529262061;DAVIDW;in;//D:DAVIDW/KERNEL;;LDRELOC.ASM;D468;
+529262108;DAVIDW;in;//D:DAVIDW/KERNEL;;LDSEG.ASM;D469;Temporarily add to New_Seg1 and HandleEntry for change to new DOS5 memory manager interface.
+529262113;DAVIDW;in;//D:DAVIDW/KERNEL;;LINTERF.ASM;D470;Temporarily add to New_Seg1 and HandleEntry for change to new DOS5 memory manager interface.
+529262124;DAVIDW;in;//D:DAVIDW/KERNEL;;NEWEXE.H;D472;Temporarily add to New_Seg1 and HandleEntry for change to new DOS5 memory manager interface.
+529262132;DAVIDW;in;//D:DAVIDW/KERNEL;;NEWEXE.INC;D473;Temporarily add to New_Seg1 and HandleEntry for change to new DOS5 memory manager interface.
+529262141;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D474;Temporarily add to New_Seg1 and HandleEntry for change to new DOS5 memory manager interface.
+529612999;DAVIDW;in;//D:DAVIDW/KERNEL;;CONTEXT.ASM;D476;Made the code supportable.
+529613115;DAVIDW;in;//D:DAVIDW/KERNEL;;DISKIO.ASM;D475;Made the code supportable.
+529613409;DAVIDW;in;//D:DAVIDW/KERNEL;;i21mem.asm;D478;Remove a check for a partition signature of 'Z'.
+529615309;DAVIDW;in;//D:DAVIDW/KERNEL;;LDINT.ASM;D479;In testDSAX took out a check for the partition signature.
+529619743;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D481;Took out checks for partition signatures for moveable objects.
+529703641;DAVIDW;addfile;//D:DAVIDW/KERNEL;;lhandle.asm;;Just a stub for now.
+529704149;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D486;Added lhandle.asm.
+529704157;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D487;Added lhandle.asm.
+529721184;DAVIDW;in;//D:DAVIDW/KERNEL;;LCOMPACT.ASM;D489;Entabbed.
+529776534;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D490;Added LocalHandleEntry which is the same as it always was.
+529786212;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D484;Separated global handles from local handles.
+529786216;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D483;Separated global handles from local handles.
+529786229;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D485;Separated global handles from local handles.
+529786244;DAVIDW;in;//D:DAVIDW/KERNEL;;LALLOC.ASM;D492;Separated global handles from local handles.
+529786257;DAVIDW;in;//D:DAVIDW/KERNEL;;LCOMPACT.ASM;D493;Separated global handles from local handles.
+529786267;DAVIDW;in;//D:DAVIDW/KERNEL;;lhandle.asm;D494;Separated global handles from local handles.
+529786295;DAVIDW;in;//D:DAVIDW/KERNEL;;LINTERF.ASM;D488;Separated global handles from local handles.
+529804363;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D495;Entabbed.
+529804998;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D496;Added a comment block.
+529980987;WINBUILD;defect;//C:BUILD400/WINDOWS/KERNEL;;;;
+530225106;WINBUILD;enlist;//C:WINBUILD/WIN200/KERNEL;;;;
+530497931;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D498;Made the boot stack properly aligned again.
+530580595;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D499;Mushed ldinit.c into it.
+530580618;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D500;Took out ldinit.c
+530580624;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D501;Took out ldinit.c.
+530741275;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D502;Took ldinit.obj out of the dependencies for kernel.exe.
+530741295;DAVIDW;delfile;//D:DAVIDW/KERNEL;;LDINIT.C;D503;
+530819287;DAVIDW;in;//D:DAVIDW/KERNEL;;GACHECK.C;D504;Moved he_count to ga_count, added he_paddress.
+530819591;DAVIDW;unlock;//D:DAVIDW/KERNEL;;;;slm
+530819616;DAVIDW;in;//D:DAVIDW/KERNEL;;GACHECK.C;D504;Added support for he_paddress.
+530819665;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D505;Moved he_count to ga_count.
+530819786;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D506;Moved he_count to ga_count.
+530819966;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D507;Moved he_count to ga_count.
+530820135;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D508;Moved he_count to ga_count.
+530820243;DAVIDW;addfile;//D:DAVIDW/KERNEL;;gmeminit.asm;;Moved initialization code here from gmem.asm and ginterf.asm.
+530820976;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D509;Moved he_count to ga_count.
+530821015;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D510;Added gmeminit.asm
+530821231;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.H;D511;Added more support for lhandle structures.
+530821262;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D512;Added gmeminit.asm.
+530821388;DAVIDW;in;//D:DAVIDW/KERNEL;;LACHECK.C;D513;Changing the names of things only.
+530821420;DAVIDW;in;//D:DAVIDW/KERNEL;;LCOMPACT.ASM;D514;Changing the names of things only.
+530821510;DAVIDW;in;//D:DAVIDW/KERNEL;;LDSEG.ASM;D516;Changing the names of things only.
+530821589;DAVIDW;in;//D:DAVIDW/KERNEL;;LDSTACK.ASM;D497;Added support for he_paddress.
+530821633;DAVIDW;in;//D:DAVIDW/KERNEL;;lhandle.asm;D517;Changing the names of things only.
+530821692;DAVIDW;in;//D:DAVIDW/KERNEL;;LINTERF.ASM;D518;Changing the names of things only.
+530821740;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D519;Changing the names of things only.
+530821932;DAVIDW;in;//D:DAVIDW/KERNEL;;SCHEDULE.ASM;D520;Changing the names of things only.
+530999562;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D521;Deleted SETSWAPHOOK.
+530999583;DAVIDW;in;//D:DAVIDW/KERNEL;;286LM.ASM;D522;Deleted SETSWAPHOOK.
+530999622;DAVIDW;in;//D:DAVIDW/KERNEL;;286MEM.ASM;D523;Changed names only.
+530999671;DAVIDW;in;//D:DAVIDW/KERNEL;;INT21.ASM;D524;Removed all references to Swapping.
+530999697;DAVIDW;in;//D:DAVIDW/KERNEL;;LDAUX.ASM;D525;Removed all references to Swapping.
+530999724;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D526;Removed all references to Swapping.
+530999742;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.H;D527;Removed all references to Swapping.
+531000287;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D528;Changed the glru links from handles to addresses.
+531000324;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D529;Changed the glru links from handles to addresses.
+531000339;DAVIDW;in;//D:DAVIDW/KERNEL;;gmeminit.asm;D530;Changed the glru links from handles to addresses.
+531000363;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D531;Changed the glru links from handles to addresses.
+531000402;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D532;Changed the glru links from handles to addresses, and removed SetSwapHook.
+531000449;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D533;Changed the glru links from handles to addresses, and removed SetSwapHook.
+531615186;DAVIDW;delfile;//D:DAVIDW/KERNEL;;GACHECK.C;D535;
+531615242;DAVIDW;addfile;//D:DAVIDW/KERNEL;;gacheck.asm;;Rewrote from C into assembly.
+531615315;DAVIDW;addfile;//D:DAVIDW/KERNEL;;kdebug.mac;;Macros for debugging. I'm not sure of the half-life of this file.
+531615384;DAVIDW;in;//D:DAVIDW/KERNEL;;dinterf.asm;D536;Adding more of the DOS 5 mem. management.
+531615512;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D537;Making changes for the new global HandleEntry structure.
+531615558;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D538;Making changes for the new global HandleEntry structure.
+531615606;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D539;Making changes for the new global HandleEntry structure.
+531615663;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D540;Making changes for the new global HandleEntry structure.
+531615717;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D541;Making changes for the new global HandleEntry structure.
+531615827;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D542;Making changes for the new global HandleEntry structure. Cleaned up and shortened some of the routines.
+531615865;DAVIDW;in;//D:DAVIDW/KERNEL;;gmeminit.asm;D543;Making changes for the new global HandleEntry structure.
+531615906;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D544;in kernel.def
+531615943;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D545;Adding 286DOS memory management interface.
+531616033;DAVIDW;in;//D:DAVIDW/KERNEL;;SCHEDULE.ASM;D546;Commented out emm_discard and emm_undiscard. They need work, but can be ignored for now.
+531617201;DAVIDW;in;//D:DAVIDW/KERNEL;;RESAUX.ASM;D547;Making changes for the DOS5 mem. management interface.
+531617298;DAVIDW;in;//D:DAVIDW/KERNEL;;LDUTIL.ASM;D548;Making changes for the DOS5 mem. management interface.
+531617345;DAVIDW;in;//D:DAVIDW/KERNEL;;LDAUX.ASM;D549;Making changes for the DOS5 mem. management interface.
+531617428;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D550;Making changes for the DOS5 mem. management interface.
+531617751;DAVIDW;in;//D:DAVIDW/KERNEL;;LDFASTB.ASM;D551;Making changes for the DOS5 mem. management interface.
+531617803;DAVIDW;in;//D:DAVIDW/KERNEL;;LDSTACK.ASM;D552;Making changes for the DOS5 mem. management interface.
+531618407;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D553;Making changes for the DOS5 mem. management interface.
+531728424;DAVIDW;in;//D:DAVIDW/KERNEL;;dinterf.asm;D554;Adding DosLockSeg and DosUnlockSeg
+531728452;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D555;Made gdref more robust.
+531728471;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D556;Fixed a small bug in set_handle_paddress.
+531728506;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D558;Added more 286DOS mem man interface.
+531789548;SEANS;defect;//D:DWEISE/KERNEL;;;;
+532578761;DAVIDW;in;//D:DAVIDW/KERNEL;;emm.asm;D561;Got rid of gi_alt_rover.
+532578890;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D562;Replaced the nonfunctional gi_rover idea by linking the free partitions together instead.
+532578933;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D563;Made the kernel.exe dependencies correct.
+532579027;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.INC;D565;Added the macros smov and jmps.
+532639857;DAVIDW;in;//D:DAVIDW/KERNEL;;DOSINIT.ASM;D560;Feeble attempts at making Windows work under Mondrian.
+532639960;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D567;Fixed a small bug.
+532640167;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D568;Adding the linked free list of global partitions.
+532640221;DAVIDW;in;//D:DAVIDW/KERNEL;;gmeminit.asm;D569;Adding the linked free list of global partitions.
+532640308;DAVIDW;in;//D:DAVIDW/KERNEL;;GMEM.ASM;D570;Adding the linked free list of global partitions.
+532640380;DAVIDW;in;//D:DAVIDW/KERNEL;;RIP.C;D564;Cosmetic changes.
+532758071;DAVIDW;in;//D:DAVIDW/KERNEL;;gmeminit.asm;D571;Fixed a small bug.
+532818054;WINBUILD;enlist;//C:WINBUILD/WIN104/KERNEL;;;;
+532823300;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D572;Added the debugging aid CheckFreeSpaces.
+532823354;DAVIDW;in;//D:DAVIDW/KERNEL;;KDATA.ASM;D573;Added fCheckFree. This allows after booting the
+532823415;DAVIDW;in;//D:DAVIDW/KERNEL;;GLRU.ASM;D574;Turned int 3's into kerrors.
+532823465;DAVIDW;in;//D:DAVIDW/KERNEL;;gacheck.asm;D575;Added more checking, check_lru_list and check_free_list.
+532823530;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D576;Put in CheckFreeSpaces before any global compactions.
+532823602;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D577;Added the initialiazation of free memory to being filled with CCCC.
+532823990;DAVIDW;unlock;//D:DAVIDW/KERNEL;;;;
+532824208;DAVIDW;in;//D:DAVIDW/KERNEL;;LDDEBUG.ASM;D578;Added comment blocks. Also added dump_free_list and dump_lru_list.
+532824626;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D566;Added the debugging tools check_this_space, and CHECKFREESPACES.
+533432648;RONM;enlist;//C:RON_MURRAY/KERNEL;;;;
+534027733;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D581;Corrected a few comment blocks.
+534027811;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D579;Added the flag GA_COMPACTED.
+534062916;DAVIDW;addfile;//D:DAVIDW/KERNEL;;gmoremem.asm;;The files ginterf.asm, gmem.asm, galloc.asm, and gcompact were getting too big so this contains overflow.
+534491499;DAVIDW;in;//D:DAVIDW/KERNEL;;LDFASTB.ASM;D586;Made fastbooting work again.
+534494578;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D582;Fixed a small bug for fastbooting.
+534494933;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D587;Fixed a small bug for fastbooting.
+534547027;DAVIDW;in;//D:DAVIDW/KERNEL;;LDUTIL.ASM;D588;Fixed a small ga_count bug in MyFree.
+534710985;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL;D589;Added the file gmoremem.asm
+534711081;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.DEF;D590;Changed CheckFreeSpaces to VALIDATEFREESPACES.
+534711137;DAVIDW;in;//D:DAVIDW/KERNEL;;KDATA.ASM;D591;Added globalW MaxCodeSwapArea.
+534711257;DAVIDW;in;//D:DAVIDW/KERNEL;;CONTEXT.ASM;D592;Moved SetSwapAreaSize to gmoremem.asm.
+534711313;DAVIDW;in;//D:DAVIDW/KERNEL;;gacheck.asm;D593;Changed the proc CheckFreeSpaces to ValidateFreeSpaces.
+534712331;DAVIDW;in;//D:DAVIDW/KERNEL;;LDBOOT.ASM;D595;Put in support for SetSwapAreaSize. Made a few cosmetic changes.
+534713686;DAVIDW;in;//D:DAVIDW/KERNEL;;LDHEADER.ASM;D596;Reworked CalcMaxNRSeg. Made some cosmetic changes.
+534713657;CHUCKWH;defect;//D:CHUCKWH/KERNEL;;;;
+534715641;DAVIDW;in;//D:DAVIDW/KERNEL;;LDHEADER.ASM;D597;Removed superfluous MaxCalcNRSeg's from the StartTasks.
+534715683;DAVIDW;in;//D:DAVIDW/KERNEL;;KERNEL.LNK;D598;Added gmoremem.asm
+534715732;DAVIDW;in;//D:DAVIDW/KERNEL;;HANDLE.ASM;D585;Moved ghexpand here.
+534716333;DAVIDW;in;//D:DAVIDW/KERNEL;;LDSEG.ASM;D599;Made AddModule calculate and set ne_swaparea
+534716538;DAVIDW;in;//D:DAVIDW/KERNEL;;GINTERF.ASM;D600;Reworked Global(Un)Wire. Moved genter, gleave, gavail, greserve, etc. to gmoremem. Moved ghexpand to handle.asm.
+534716613;DAVIDW;in;//D:DAVIDW/KERNEL;;gmoremem.asm;D601;Moved SetSwapAreaSize to here and made it do the right thing.
+534716663;DAVIDW;in;//D:DAVIDW/KERNEL;;GCOMPACT.ASM;D602;Cosmetic changes.
+534716926;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D603;Reworked gsearch to use the new free list, and to allocate fixed segments as "low as possible".
+534718441;DAVIDW;in;//D:DAVIDW/KERNEL;;LDFASTB.ASM;D604;This should now work!
+534735735;STEVEWO;in;//C:STEVEWO/WIN/KERNEL;;INT24.ASM;D605;Added check for ? drive letter
+534735783;STEVEWO;defect;//C:STEVEWO/WIN/KERNEL;;;;
+534736371;STEVEWO;enlist;//C:STEVEWO/WIN/KERNEL;;;;
+534975760;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D606;Small bug fix.
+534975859;DAVIDW;in;//D:DAVIDW/KERNEL;;winkern.inc;D609;Redefined GA_COMPACTED equ 02h.
+535104265;DAVIDW;in;//D:DAVIDW/KERNEL;;GALLOC.ASM;D610;Fixed a small bug in allocating fixed objects.
+535104314;DAVIDW;in;//D:DAVIDW/KERNEL;;i21exec.asm;D611;Cosmetic changes.
+535104320;DAVIDW;in;//D:DAVIDW/KERNEL;;i21exit.asm;D612;Cosmetic changes.
+535104324;DAVIDW;in;//D:DAVIDW/KERNEL;;i21mem.asm;D613;Cosmetic changes.
+535104346;DAVIDW;in;//D:DAVIDW/KERNEL;;INT21.ASM;D614;Cosmetic changes.
+535104354;DAVIDW;in;//D:DAVIDW/KERNEL;;SCHED.INC;D615;Cosmetic changes.
+535104390;DAVIDW;defect;//D:DAVIDW/KERNEL;;;;
diff --git a/private/mvdm/wow16/kernel31/lstring.asm b/private/mvdm/wow16/kernel31/lstring.asm
new file mode 100644
index 000000000..a1cad5318
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lstring.asm
@@ -0,0 +1,688 @@
+ TITLE LSTRING
+
+include kernel.inc
+include gpfix.inc
+include wowcmpat.inc
+
+DataBegin
+
+externB fFarEast ; non zero if far eastern keyboard
+externB KeyInfo ; Info returned by KEYBOARD.Inquire
+ifdef DBCS
+externB fDBCSLeadTable ; DBCS Lead byte flag array
+endif
+
+if ROM
+externD pStringFunc ; Entry point of string functions in USER.
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+ifdef WOW
+externNP MyGetAppWOWCompatFlags
+endif
+ife ROM
+externD pStringFunc ; Entry point of string functions in USER.
+endif
+
+
+; Function codes for all the string functions in USER
+;
+ANSINEXT_ID equ 1
+ANSIPREV_ID equ 2
+ANSIUPPER_ID equ 3
+ANSILOWER_ID equ 4
+
+;
+; lstrlen: Same as strlen except for taking long ptrs
+;
+
+cProcVDO lstrlen,<PUBLIC,FAR>
+; parmD pStr
+cBegin nogen
+ mov bx,sp
+ push di
+beg_fault_trap sl_trap
+ les di,ss:[bx+4]
+ cld
+ xor ax,ax ; get zero in ax
+ mov cx,-1 ; at most 64 k to move
+ repnz scasb ; look for end
+ mov ax,cx
+ neg ax
+ dec ax
+ dec ax
+end_fault_trap
+sl_exit:
+ pop di
+ ret 4
+cEnd nogen
+
+sl_trap:
+ fault_fix_stack
+ xor ax,ax
+ jmp sl_exit
+
+lstr_trap:
+ fault_fix_stack
+
+lstrfinish proc far
+ pop di
+ pop si
+ pop ds
+ ret 8
+lstrfinish endp
+
+
+; lstrcpy_n - not the same as lstr_n_cpy. This version doesn't
+; null-pad, but does null-terminate in all cases.
+cProc lstrcpyn,<PUBLIC,FAR>,<ds,si,di>
+ parmD pDst
+ parmD pSrc
+ parmW wLen
+cBegin
+ cld
+beg_fault_trap lscn_err
+ les di, [pSrc] ; Find length of source string
+ mov cx, -1
+ xor ax, ax
+ repnz scasb
+ not cx ; length now in CX (incl null term)
+
+ cmp cx, [wlen] ; Check destination length
+ jbe @F
+ mov cx, [wLen]
+@@:
+ lds si, [pSrc] ; Copy the string
+ les di, [pDst]
+ dec cx ; save space for null
+ shr cx, 1
+ rep movsw
+ adc cx, cx
+ rep movsb
+
+ stosb ; null terminate string
+
+end_fault_trap
+ mov ax, [OFF_pDst] ; ptr to dest in DX:AX
+ mov dx, es
+lscn_exit:
+cEnd
+
+lscn_err:
+ fault_fix_stack
+ krDebugOut DEB_ERROR, "GP fault in LStrNCpy"
+ xor ax, ax
+ cwd
+ jmps lscn_exit
+
+if 0 ; we don't have a use for lstr_n_cpy at this time
+cProc lstrncpy,<PUBLIC,FAR>,<ds,si,di>
+ parmD pDst
+ parmD pSrc
+ parmW wLen
+cBegin
+ cld
+beg_fault_trap lsnc_err
+ les di, [pSrc] ; Find length of source string
+ mov cx, -1
+ xor ax, ax
+ repnz scasb
+ not cx ; length now in CX (incl null term)
+
+ mov bx, [wlen] ; Check destination length
+ sub bx, cx ; find bytes to null pad
+ jnc @F
+ mov cx, [wLen]
+ xor bx, bx
+@@:
+ lds si, [pSrc] ; Copy the string
+ les di, [pDst]
+ rep movsb
+
+ mov cx, bx ; Pad string with 0's
+ rep stosb
+
+end_fault_trap
+ mov ax, [OFF_pDst] ; ptr to dest in DX:AX
+ mov dx, es
+lsnc_exit:
+cEnd
+
+lsnc_err:
+ fault_fix_stack
+ krDebugOut DEB_ERROR, "GP fault in LStrNCpy"
+ xor ax, ax
+ cwd
+ jmps lsnc_exit
+endif
+
+lstrsetup:
+ pop dx
+ mov bx,sp
+
+ push ds
+ push si
+ push di
+
+beg_fault_trap lstr_trap
+ lds si,ss:[bx+4]
+ les di,ss:[bx+8]
+ cld
+ jmp dx
+;
+;lstrcpy: strcpy with long pointers
+;
+cProcVDO lstrcpy,<PUBLIC,FAR>
+; parmD pDst ; [bx+8]
+; parmD pSrc ; [bx+4]
+
+cBegin nogen
+ call lstrsetup
+ mov dx,di ; save for return
+
+lcp1: lodsb
+ stosb
+ or al,al
+ jnz lcp1
+
+ xchg ax,dx ; return ds:ax = original dest
+ mov dx,es
+ jmp lstrfinish
+cEnd nogen
+
+
+;
+;lstrcat: Same as strcat except with long ptrs.
+;
+cProcVDO lstrcat,<PUBLIC,FAR>
+; parmD pDst
+; parmD pSrc
+
+cBegin nogen
+ call lstrsetup
+ mov dx,di ; save original dest for return
+ xor ax,ax ; get zero in ax
+ mov cx,-1 ; at most 64 k to look
+ repnz scasb ; look for end
+ dec di ; Point at null byte
+ifndef WOW
+ jmp lcp1 ; jump to lstrcpy loop
+else
+lcp1_wow: lodsb
+ stosb
+ or al,al
+ jnz lcp1_wow
+
+ ; normal lstrcat is now complete.
+ ;
+ ; Now begins a GROSS HACK HACK HACK for fixing wordperfect
+ ; For compatibility reasons we want to check if the function call
+ ; was of type lstrcat(lpsz, ".WRS");
+ ;
+ ; the checks are:
+ ; let lpDest = ".WRS"
+ ; if (lstrlen(lpDest)+NULLCHAR == 5) &&
+ ; !lstrcmp(lpDest, ".WRS")) {
+ ; if (wordperfect) {
+ ; remove all backslashes in lpsz
+ ; }
+ ; }
+ ;
+ ; we do these checks after the concatenation 'cause it means that
+ ; source string is valid and we wont GP fault while accessing the
+ ; source string
+ ; - Nanduri
+
+ sub si, 5
+ cmp si, ss:[bx+4]
+ jnz @F
+ cmp [si], 'W.' ; ".W"
+ jnz @F
+ cmp [si+2], 'SR' ; "RS"
+ jnz @F
+
+lscat_DOTWRS:
+ ; here if lstrcat (lpString, ".WRS")
+ ; now make sure that it is wordperfect. this is a gross hack so
+ ; why care for efficiency.
+
+ push dx
+ call MyGetAppWOWCompatFlags
+ test dx, word ptr cs:[gacf_dotwrs+2]
+ pop dx
+ jz @F
+ jmp short replace_slashes
+
+gacf_dotwrs:
+ DD WOWCF_SANITIZEDOTWRSFILES
+
+replace_slashes:
+
+ ; yes it is. strip backslashes if any.
+ ; if there are any backslashes the lpString would be of the form
+ ; \\blahblah or \\blah\blah. note that 'blah' is not important, the
+ ; backslashes are.
+ ;
+
+ push es
+ pop ds
+ mov si, dx
+ mov di, dx
+slash_a_slash:
+ lodsb
+ cmp al, '\'
+ je slash_a_slash
+ stosb
+ or al, al
+ jnz slash_a_slash
+@@:
+ xchg ax,dx ; return ds:ax = original dest
+ mov dx,es
+ jmp lstrfinish
+endif
+
+
+cEnd nogen
+
+;
+;lstrOriginal: This is language independent version of lstrcmp
+; specially made for kernel.
+; (i made it case insensitive...chrisp)
+;
+cProcVDO lstrOriginal,<PUBLIC,FAR>
+; parmD ps1
+; parmD ps2
+cBegin nogen
+ call lstrsetup
+lcmploop:
+ xor ax,ax
+ cmp es:byte ptr [di],al
+ jz ldidone ; left hand side finished <=
+ cmp byte ptr [si],al
+ jz lsismall ; right hand side finished, >
+ lodsb
+ifdef DBCS
+ call MyIsDBCSLeadByte
+ jc cmp1
+ mov ah,ds:[si]
+ inc si
+ jmp short cmp2
+endif
+cmp1: call MyLower
+ xor ah,ah
+
+cmp2: mov bx,ax
+ mov al,es:[di]
+ inc di
+ifdef DBCS
+ call MyIsDBCSLeadByte
+ jc cmp3
+ mov ah,es:[di]
+ inc di
+ jmp short cmp4
+endif
+cmp3: call MyLower
+ xor ah,ah
+
+cmp4: cmp ax,bx ; effectlively es:[di],ds:[si]
+ jz lcmploop ; still equal
+ mov ax,0 ; preverve flags
+ jb ldismall ; di is less than si
+lsismall:
+ inc ax
+ jmp short lstrcmpend
+ldidone:
+ cmp byte ptr ds:[si],0
+ jz lequal
+ldismall:
+ dec ax
+lequal:
+lstrcmpend:
+ jmp lstrfinish
+cEnd nogen
+
+end_fault_trap
+
+;--------------------------------------------------------
+;
+; ANSI compatible string routines
+;
+
+ public AnsiUpper, AnsiLower, AnsiPrev, AnsiNext
+
+AnsiUpper:
+ mov cl,ANSIUPPER_ID
+ jmpnext
+AnsiLower:
+ mov cl,ANSILOWER_ID
+ jmpnext
+AnsiPrev:
+ mov cl,ANSIPREV_ID
+ jmpnext
+AnsiNext:
+ mov cl,ANSINEXT_ID
+ jmpnext end
+
+ xor ch,ch
+if ROM
+ push ds
+ SetKernelDS
+endif
+ cmp pStringFunc.sel,0 ; Is there a USER around?
+ jz no_user_function
+if ROM
+ push bp
+ mov bp,sp
+ push pStringFunc.sel
+ push pStringFunc.off
+ mov ds,[bp][2]
+ UnSetKernelDS
+ mov bp,[bp]
+ retf 4
+else
+ jmp pStringFunc
+endif
+
+no_user_function:
+if KDEBUG
+ int 3
+endif
+if ROM
+ pop ds
+ UnSetKernelDS
+endif
+ cmp cl,ANSIPREV_ID
+ jz @F
+ retf 4
+@@: retf 8
+
+;----------------------------------------------------------------------------
+; MyUpper: Called from LDSelf.ASM
+; convert lower case to upper, must preserve es,di,cx
+;---------------------------------------------------------------------------
+
+ public MyUpper
+MyUpper:
+ cmp al,'a'
+ jb myu2
+ cmp al,'z'
+ jbe myu1
+ifdef DBCS
+ push ds
+ SetKernelDS
+ cmp [fFarEast],1 ; Far east ?
+ pop ds
+ UnSetKernelDS
+ jge myu2 ; yes do nothing to the Microsoft fonts.
+endif
+ cmp al,0E0H ; this is lower case a with a back slash
+ jb myu2
+ cmp al, 0F7H ; This is division mark in Microsoft fonts; So, don't
+ je myu2 ; convert this; Fix for Bug #1356 -SANKAR-08-28-89;
+ cmp al,0FEH
+ ja myu2
+myu1: sub al,'a'-'A'
+myu2: ret
+
+;----------------------------------------------------------------------------
+; MyLower: Called from Atom.asm, LdOpen.asm, ldUtil.asm, ldself.asm
+; convert upper case to lower, must preserve es,di,cx
+;----------------------------------------------------------------------------
+ public MyLower
+MyLower:
+ cmp al,'A'
+ jb myl2
+ cmp al,'Z'
+ jbe myl1
+
+ push ds
+ SetKernelDS
+ cmp [fFarEast],1 ; this is a far east kbd 1/12/87 linsh
+ pop ds
+ UnSetKernelDS
+ jge myl2 ; yes do nothing to the 0C0H - 0DEH range
+
+ cmp al,0C0H ; this is lower case a with a back slash
+ jb myl2
+
+ cmp al, 0D7H ; This is multiply mark in Microsoft fonts; So, don't
+ je myl2 ; translate this; Fix for Bug #1356;-SANKAR-08-28-89;
+
+ cmp al,0DEH
+ ja myl2
+myl1: add al,'a'-'A'
+myl2: ret
+
+
+;-----------------------------------------------------------------------;
+; IsDBCSLeadByte ;
+;
+; This Function will be exist on US Windows, but it
+; returns FALSE always.
+;
+;-----------------------------------------------------------------------;
+
+cProc IsDBCSLeadByte,<PUBLIC,FAR>
+; parmW char ss:[bx+04]
+cBegin nogen
+ifdef DBCS
+ mov bx,sp
+ push ds
+ SetKernelDS
+;; push di
+;;
+;; mov ax,ss:[bx+04]
+;; call MyIsDBCSLeadByte
+;; jnc id1
+;; xor ax,ax
+;; jmp idx
+;;id1: mov ax,1
+;;idx:
+;;
+;; pop di
+ mov al, byte ptr ss:[bx+4]
+ mov bx, offset fDBCSLeadTable
+ xlat
+ xor ah,ah
+ pop ds
+ UnSetKernelDS
+else
+ xor ax,ax
+endif
+ ret 2
+cEnd nogen
+
+
+ifdef DBCS
+
+; This API returns DBCS lead byte table for applications which
+; in turn can speed up DBCS checking without making calls to
+; IsDBCSLeadByte.
+;-----------------------------------------------------------------------;
+; GetDBCSEnv ;
+;
+; int GetDBCSEnv(LPSTR lpsz, int cbMax)
+; lpsz: long ptr points to buffer to receive DBCS lead byte table
+; cbMax: how many bytes the buffer pointed to by lpsz.
+; 0 if inquire buffer size required to receive the table
+; return (ax) 0 if failed else the size of the table.
+; use: AX, BX, CX, DX
+;
+;
+;-----------------------------------------------------------------------;
+
+;
+cProc GetDBCSEnv,<PUBLIC,FAR>
+; parmD ss:[bx+6] ;lpsz
+; parmW ss:[bx+4] ;cbMax
+cBegin nogen
+ mov bx,sp ;frame ptr
+ push es
+ push di
+ push si
+;;; 12 bytes should be enough to accumulate our result.
+;;; However, if fDBCSLeadTable corrupt then we are dead!!!!
+ sub sp,12 ;temp private storage
+ mov si,sp ;
+ SetKernelDS es ;
+ mov di, offset fDBCSLeadTable ;
+ cld
+ mov al,1 ;
+ mov cx,256 ;256 bytes in table
+GDE_loop:
+ xor al,1 ;toggle the match pattern (0/1)
+ repe scasb ;
+ jz GDE_done ;not found then CX must be 0
+ mov ah,cl ;calc the index
+ sub ah,255
+ neg ah
+ sub ah,al ;
+ mov ss:[si],ah ;save it
+ inc si
+ jmps GDE_loop
+GDE_done:
+ mov word ptr ss:[si],0 ;terminated with 0,0
+ mov ax,si
+ sub ax,sp ;how many bytes we got?
+ jz GDE_Exit ;none, return
+ add ax,2 ;count the terminated bytes
+ inc si ;and advance ptr to the last 0
+ mov cx,ss:[bx+4] ;get cbMax
+ jcxz GDE_Exit ;return if inquire buffer size
+ cmp cx,ax ;enough buffer provided ?
+ jge @F
+ xor ax,ax ;no, return error
+ jmps GDE_Exit
+
+@@:
+beg_fault_trap GDE_gp
+ les di, ss:[bx+6] ;lpsz
+ mov cx,ax ;how many bytes to copy
+ add di,ax
+ dec di ;offset started from 0
+ std
+rep movs byte ptr [di],ss:[si]
+
+end_fault_trap
+
+GDE_Exit:
+ cld
+ UnSetKernelDS es
+ add sp, 12
+ pop si
+ pop di
+ pop es
+ ret 6
+cEnd nogen
+
+GDE_gp:
+ fault_fix_stack
+ xor ax, ax ;invalide lpsz, return ax=0
+ jmps GDE_Exit
+
+
+;--------------------------------------------------------------------------
+;
+; return carry clear if character in AL is first byte of DBCS
+;
+;--------------------------------------------------------------------------
+ public MyIsDBCSLeadByte
+MyIsDBCSLeadByte:
+ push ds
+ SetKernelDS
+ push ax ; Save AX for caller
+ push bx ; Save BX for caller
+ mov bx, offset fDBCSLeadTable
+ xlat
+ shr al,1 ; refrect to carry flag
+ cmc
+ pop bx
+ pop ax
+;; cmp [fFarEast],1 ; not in far east?
+;; jb ikx ; carry set if not far east keyboard
+;; mov cx,[KeyInfo].kbRanges.lo
+;; cmp cl,ch
+;; ja iknk ; lower range invalid, not kanji
+;; cmp al,cl
+;; jb ik1 ; below lower range, try second range
+;; cmp al,ch
+;; jbe ikgk ; inside lower range, valid kanji char
+;;
+;;ik1: mov cx,[KeyInfo].kbRanges.hi
+;; cmp cl,ch ; valid upper range?
+;; ja iknk ; no, not kanji
+;; cmp al,cl ; is it within range?
+;; jb ikx ; trick...carry already set
+;; cmp al,ch
+;; ja iknk
+;;ikgk: clc ; within range...valid kanji char
+;; jmp short ikx
+;;
+;;iknk: stc
+;;ikx:
+;; pop cx
+ pop ds
+ UnSetKernelDS
+ ret
+
+ public FarMyIsDBCSLeadByte
+FarMyIsDBCSLeadByte proc far
+ call MyIsDBCSLeadByte
+ ret
+FarMyIsDBCSLeadByte endp
+
+
+ public MyIsDBCSTrailByte
+MyIsDBCSTrailByte proc near
+;----------------------------------------------------------
+; IsDBCSTrailByte
+; Check if the indexed byte is a DBCS char trailing byte.
+;
+; Input:
+; ES:SI = char *ach[]
+; ES:DI -> position of character of interested.
+;
+; Output:
+; Carry flag clear if it is a DBCS trailing byte
+; Carry flag set if it is a SBCS or DBCS leading byte
+;
+; Use:
+; flags
+;
+;----------------------------------------------------------
+ cmp si,di ;if beginning >= index?
+ jae IDTB_Exit ;yes, SBCS or DBCS 1st (CF=1)
+
+ push si
+ push ax
+ cld ;no chance
+@@:
+ lods byte ptr es:[si] ;
+ call MyIsDBCSLeadByte
+ cmc
+ adc si,0 ;si++ if DBCS
+ cmp di,si ;hit the target yet?
+ ja @B ;go to loop if not yet
+ pop ax ;di=si, we have a SBCS or DBCS 1st
+ pop si ;di < si, we have a DBCS 2nd
+IDTB_Exit:
+ cmc
+ ret
+MyIsDBCSTrailByte endp
+
+;---------------------------------------------------------------
+ public FarMyIsDBCSTrailByte
+FarMyIsDBCSTrailByte proc far
+ call MyIsDBCSTrailByte
+ ret
+FarMyIsDBCSTrailByte endp
+endif ; DBCS
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/kernel31/lzexp.c b/private/mvdm/wow16/kernel31/lzexp.c
new file mode 100644
index 000000000..176515231
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/lzexp.c
@@ -0,0 +1,174 @@
+/*
+ * LZEXP.C
+ *
+ * Routines used in Lempel-Ziv expansion.
+ *
+ */
+
+#include "kernel.h"
+
+#if ROM //--------------------------------------------------------------
+
+
+#define API _far _pascal _loadds
+
+#define RING_BUF_LEN 4096 // size of ring buffer
+#define MAX_RING_BUF_LEN 4224 // size of ring buffer - from LZFile
+ // struct declaration in lzexpand.h
+
+#define BUF_CLEAR_BYTE ((BYTE) ' ') // rgbyteRingBuf[] initializer
+
+#define MAX_LITERAL_LEN 2 // encode string into position and
+ // length if match length greater than
+ // this value (== # of bytes required
+ // to encode position and length)
+
+#define LZ_MAX_MATCH_LEN (0x10 + MAX_LITERAL_LEN)
+ // upper limit for match length
+ // (n.b., assume length field implies
+ // length += 3)
+
+#define END_OF_INPUT 500 // EOF flag for input file
+
+#define FOREVER for(;;)
+
+#define ReadByte(byte) ((byte = (BYTE)(cbSrc ? *pSrc++ : 0)), \
+ (cbSrc ? (cbSrc--, TRUE) : END_OF_INPUT))
+#define WriteByte(byte) ((*pDst++ = byte), cblOutSize++)
+
+typedef struct COMPHEAD _far * LPCOMPHEAD;
+
+struct COMPHEAD { // Compressed segment/resource header
+ BYTE Sig; // signature
+ BYTE Method; // compression method
+ DWORD cbSize; // # compressed bytes following
+};
+
+#define CMP_SIG ('C')
+#define CMP_LZ ('L')
+
+
+/*
+ * LZDecode
+ *
+ * Parameters:
+ * selDst Selector pointing to destination buffer
+ * selSrc Selector pointing to compressed data
+ * lpBuf Pointer to optional ring buffer
+ *
+ * Returns:
+ * count (in bytes) of uncompressed data written to selDst buffer
+ *
+ * Note: This routine does not use any static or external data.
+ * This allows it to be used to uncompress Kernel's own
+ * data segment.
+ */
+
+DWORD FAR API
+LZDecode(WORD selDst, WORD selSrc, LPSTR lpBuf) {
+
+ int i,
+ cb, // number of bytes to unpack
+ f; // holds ReadByte() return values
+ int oStart; // buffer offset for unpacking
+ BYTE byte1, byte2; // input byte holders
+ unsigned uFlags; // LZ decoding description byte
+ int iCurRingBufPos; // ring buffer offset
+ int cbMaxMatchLen;
+ LPSTR rgbyteRingBuf;
+ HANDLE hRingBuf;
+ LPCOMPHEAD lpHead;
+ DWORD cblOutSize, cbSrc;
+ char _based((_segment)selDst) *pDst = NULL;
+ char _based((_segment)selSrc) *pSrc = NULL;
+ struct COMPHEAD _based((_segment)selSrc) *pHead = NULL;
+
+ pSrc += sizeof(struct COMPHEAD);
+
+ cblOutSize = 0;
+ cbSrc = pHead->cbSize;
+ cbMaxMatchLen = LZ_MAX_MATCH_LEN;
+
+ // Make sure we know how to expand this object
+
+ if (pHead->Sig != CMP_SIG || pHead->Method != CMP_LZ)
+ return(0);
+
+ // Set up a fresh buffer state.
+ if (lpBuf) {
+ hRingBuf = NULL;
+ rgbyteRingBuf = lpBuf;
+ } else {
+ if (!(hRingBuf = GlobalAlloc(GMEM_MOVEABLE,MAX_RING_BUF_LEN)))
+ return(0);
+ rgbyteRingBuf = GlobalLock(hRingBuf);
+ }
+
+ // Initialize ring buffer.
+ for (i = 0; i < RING_BUF_LEN - cbMaxMatchLen; i++)
+ rgbyteRingBuf[i] = BUF_CLEAR_BYTE;
+
+ // Initialize decoding globals.
+ uFlags = 0U;
+ iCurRingBufPos = RING_BUF_LEN - cbMaxMatchLen;
+
+ f = ReadByte(byte1);
+
+ // Decode one encoded unit at a time.
+ FOREVER
+ {
+ if (f == END_OF_INPUT) // EOF reached
+ break;
+
+ // High order byte counts the number of bits used in the low order
+ // byte.
+ if (((uFlags >>= 1) & 0x100) == 0)
+ {
+ // Set bit mask describing the next 8 bytes.
+ uFlags = ((unsigned)byte1) | 0xff00;
+
+ if ((f = ReadByte(byte1)) != TRUE)
+ break;
+ }
+
+ if (uFlags & 1)
+ {
+ // Just store the literal byte in the buffer.
+ WriteByte(byte1);
+
+ rgbyteRingBuf[iCurRingBufPos++] = byte1;
+ iCurRingBufPos &= RING_BUF_LEN - 1;
+ }
+ else
+ {
+ // Extract the offset and count to copy from the ring buffer.
+ if ((f = ReadByte(byte2)) != TRUE)
+ break;
+
+ cb = (int)byte2;
+ oStart = (cb & 0xf0) << 4 | (int)byte1;
+ cb = (cb & 0x0f) + MAX_LITERAL_LEN;
+
+ for (i = 0; i <= cb; i++)
+ {
+ byte1 = rgbyteRingBuf[(oStart + i) & (RING_BUF_LEN - 1)];
+
+ WriteByte(byte1);
+
+ rgbyteRingBuf[iCurRingBufPos++] = byte1;
+ iCurRingBufPos &= RING_BUF_LEN - 1;
+ }
+ }
+
+ f = ReadByte(byte1);
+ }
+
+ if (hRingBuf) {
+ GlobalUnlock(hRingBuf);
+ GlobalFree(hRingBuf);
+ }
+
+ return(cblOutSize);
+}
+
+#endif //ROM -------------------------------------------------------
diff --git a/private/mvdm/wow16/kernel31/m.msg b/private/mvdm/wow16/kernel31/m.msg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/m.msg
diff --git a/private/mvdm/wow16/kernel31/makefile b/private/mvdm/wow16/kernel31/makefile
new file mode 100644
index 000000000..31a697f67
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/makefile
@@ -0,0 +1,836 @@
+#
+# Kernel Make file
+#
+# Macros defined on command line:
+# DEST - Destination of obj's.
+# CFLAGS - DOS version dependent C compiler flags
+# AFLAGS - DOS version dependent assembler flags
+
+# For DOS.
+MAKE=NMAKE
+
+# Uncomment one of the two following lines. The first disables our
+# protected-mode-only Int 21 handlers for testing. The second is
+# the way we ship.
+#WOW_QUICK_INT21=
+WOW_QUICK_INT21=-DW_Q21
+
+!ifndef DEST
+
+#####################################################################
+# #
+# The command lines in this section MUST AGREE with their parallels #
+# in the master CORE makefile. #
+# #
+#####################################################################
+
+# the first target specified is the default. Set this based on
+# NTDEBUG free (empty or "retail) vs checked (everything else).
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+finaltarget: debug
+
+# 386 debug kernel
+
+d386:
+ $(MAKE) 386P=1 DEST=DEBUG3
+
+# 286 debug
+
+d286:
+ $(MAKE) 286P=1 DEST=DEBUG2
+
+# 386 debug and 286 debug
+# debug: d286 d386
+# NT doesn't use krnl286 any more
+
+debug: d386
+
+r386:
+
+r286:
+
+!else
+finaltarget: retail
+
+# 386 retail
+
+r386:
+ $(MAKE) 386P=1 DEST=RETAIL3
+
+# 286 retail
+
+r286:
+ $(MAKE) 286P=1 DEST=RETAIL2
+
+# 386 retail and 286 retail
+# retail: r286 r386
+# NT doesn't use krnl286 any more
+
+retail: r386
+
+d386:
+
+d286:
+
+!endif
+
+# 286 retail and 286 debug
+
+286: r286 d286
+
+# 386 retail and 386 debug
+
+386: r386 d386
+
+# all RAM-based kernels
+
+RAM: 286 386
+
+!else
+
+!if "$(286P)"=="1"
+! if "$(DEST)"=="DEBUG2"
+A1FLAGS=-DWOW $(WOW_QUICK_INT21) -DWINDEBUG -DWOW_$(PROCESSOR_ARCHITECTURE)
+CFLAGS=-DWINDEBUG
+! else
+A1FLAGS=-DWOW $(WOW_QUICK_INT21) -DWOW_$(PROCESSOR_ARCHITECTURE)
+CFLAGS=
+! endif
+!else
+! if "$(DEST)"=="DEBUG3"
+A1FLAGS=-DWOW $(WOW_QUICK_INT21) -DWINDEBUG -DPM386 -DWOW_$(PROCESSOR_ARCHITECTURE)
+CFLAGS=-DWINDEBUG -DPM386
+! else
+A1FLAGS=-DWOW $(WOW_QUICK_INT21) -DPM386 -DWOW_$(PROCESSOR_ARCHITECTURE)
+CFLAGS=-DPM386
+! endif
+!endif
+
+!endif
+
+# Turn on the PMODE and BUILDDLL flags
+
+MAP=map/li/warnfixup
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .obj .lst .def .lnk .exe .com .imt .inc .h
+
+WOWINC = ..\..\inc
+AINC = -I..\inc -I$(WOWINC)
+CINC = -I..\inc -I$(WOWINC)
+
+#
+# 286 protect mode kernels use the 286 memory manager
+#
+
+!ifdef 286P
+286MMGR = 1
+!endif
+
+# international mode
+
+!ifndef LANG
+RES_DIR=.\messages\usa
+!IFDEF COUNTRY
+RES_DIR=.\messages\$(COUNTRY)
+!ENDIF
+!ifdef DBCS
+RES_DIR=.\messages\$(DBCS)
+!endif
+!else
+RES_DIR=$(INTL_SRC)\$(LANG)\core\kernel
+EXE_DIR=$(INTL_EXE)
+!endif
+
+#
+# Standard command line definitions
+#
+
+#
+# Note: The SED program "kernel.sed" is used to generate the commands
+# to build .obj files from .asm files. This is because having the .obj
+# files in different directories makes it difficult to format a default
+# rule. This is done by "nmake depend."
+#
+
+AFLAGS = $(A1FLAGS) -s -t -P -W0
+
+# flags for kernstub.asm compiles (no protect mode)
+KSAFLAGS = -I. -I..\..\inc -I..\..\..\inc $(A1FLAGS) -DPMODE=0 -DBUILDDLL -s -t -P -W2
+
+
+#
+# -Zi gives exes larger than 600K, so use -Zd
+#
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AFLAGS = $(AFLAGS) -Zd
+CFLAGS = $(CFLAGS) -Od -Oi -Zd
+LDEBUG = /LI
+!endif
+
+LINK = link16
+CVPACK = cvpack
+
+
+ASM = MASM $(AINC) $(AFLAGS)
+
+CP = cl16 -c -Asnw -G2sc -Oase -Zpe -W2 -Fo$*.obj $(CFLAGS) $(CINC)
+
+!ifndef DEF
+DEF = kernel.def
+!endif
+
+
+##############################################################################
+
+
+# (leave a blank line above this one)
+#
+# The Assembler File List
+#
+
+!ifdef 286P
+all: $(DEST)\kernel.exe $(DEST)\krnl286.sym
+ -binplace $(DEST)\krnl286.exe
+ -binplace $(DEST)\krnl286.sym
+ -binplace $(DEST)\krnl286.map
+!endif
+
+!ifdef 386P
+all: $(DEST)\kernel.exe $(DEST)\krnl386.sym
+ -binplace $(DEST)\krnl386.exe $(DEST)\krnl386.sym $(DEST)\krnl386.map
+!endif
+
+clean: cleanup all
+
+cleanup:
+ if exist $(DEST)\*.obj del $(DEST)\*.obj
+ if exist $(DEST)\*.exe del $(DEST)\*.exe
+ if exist $(DEST)\*.map del $(DEST)\*.map
+ if exist $(DEST)\*.sym del $(DEST)\*.sym
+
+
+OBJ = $(DEST)\winexec.obj \
+ $(DEST)\kdata.obj \
+ $(DEST)\ldboot.obj \
+ $(DEST)\ldutil.obj \
+ $(DEST)\ldfile.obj \
+ $(DEST)\ldseg.obj \
+ $(DEST)\ldreloc.obj \
+ $(DEST)\ldint.obj \
+ $(DEST)\gpfix.obj \
+ $(DEST)\ldopen.obj \
+ $(DEST)\ld.obj \
+ $(DEST)\ldaux.obj \
+ $(DEST)\ldcache.obj \
+ $(DEST)\lddebug.obj \
+ $(DEST)\ldfastb.obj \
+ $(DEST)\stack.obj \
+ $(DEST)\mapdata.obj \
+ $(DEST)\kdataend.obj \
+ $(DEST)\ldstack.obj \
+ $(DEST)\ldheader.obj \
+ $(DEST)\resaux.obj \
+ $(DEST)\strings.obj \
+ $(DEST)\emsmisc.obj \
+ $(DEST)\ripaux.obj \
+ $(DEST)\module.obj \
+ $(DEST)\task.obj \
+ $(DEST)\context.obj \
+ $(DEST)\i21file.obj \
+ $(DEST)\int24.obj \
+ $(DEST)\dosinit.obj \
+ $(DEST)\atom.obj \
+ $(DEST)\diskio.obj \
+ $(DEST)\lstring.obj \
+ $(DEST)\hmem.obj \
+ $(DEST)\userpro.obj \
+ $(DEST)\handle.obj \
+ $(DEST)\lacheck.obj \
+ $(DEST)\lalloc.obj \
+ $(DEST)\lcompact.obj \
+ $(DEST)\linterf.obj \
+ $(DEST)\lhandle.obj \
+ $(DEST)\i21entry.obj \
+ $(DEST)\i21task.obj \
+ $(DEST)\ldappl.obj \
+ $(DEST)\ldself.obj \
+ $(DEST)\rip.obj \
+ $(DEST)\intnn.obj \
+ $(DEST)\enable.obj \
+ $(DEST)\miscapi.obj \
+ $(DEST)\lzexp.obj \
+ $(DEST)\rom.obj \
+ $(DEST)\layer.obj \
+ $(DEST)\error.obj \
+ $(DEST)\diag.obj \
+ $(DEST)\wow16cal.obj \
+ $(DEST)\kthunks.obj \
+ $(DEST)\wowdeb.obj \
+ $(DEST)\tasking.obj \
+
+OBJ2 = $(DEST)\2glru.obj \
+ $(DEST)\2gmemini.obj \
+ $(DEST)\2gmoreme.obj \
+ $(DEST)\2protect.obj \
+ $(DEST)\gacheck.obj \
+ $(DEST)\2galloc.obj \
+ $(DEST)\2gcompac.obj \
+ $(DEST)\2ginterf.obj \
+ $(DEST)\2gmem.obj
+
+OBJ3 = $(DEST)\3glru.obj \
+ $(DEST)\3gmemini.obj \
+ $(DEST)\3gmoreme.obj \
+ $(DEST)\3protect.obj \
+ $(DEST)\3gacheck.obj \
+ $(DEST)\3galloc.obj \
+ $(DEST)\3gcompac.obj \
+ $(DEST)\3ginterf.obj \
+ $(DEST)\3gmem.obj \
+ $(DEST)\gpcont.obj \
+ $(DEST)\disasm.obj \
+ $(DEST)\patch.obj \
+ $(DEST)\reboot.obj
+
+
+
+!ifdef 286P
+
+
+# international mode
+
+!ifndef LANG
+target: $(DEST)\kernel.exe $(DEST)\krnl286.sym
+!else
+target: $(DEST)\krnl286.$(LANG)
+!endif
+
+$(DEST)\kernel.exe: krnl286.lnk $(DEF) $(DEST)\kernstub.exe $(OBJ) $(OBJ2)
+ cd $(DEST)
+ $(LINK) $(LDEBUG) @..\krnl286.lnk,..\$(DEF)
+ fixexe kernel.exe
+ cd ..
+
+
+$(DEST)\krnl286.$(LANG): iclean krnl286.lnk $(DEF) $(DEST)\kernstub.exe \
+ $(OBJ) $(OBJ2)
+ cd $(DEST)
+ $(LINK) $(LDEBUG) @..\krnl286.lnk,..\$(DEF)
+ fixexe kernel.exe
+ copy kernel.exe krnl286.$(LANG)
+ -erase kernel.exe
+ cd ..
+
+!endif
+
+
+!ifdef 386P
+
+# international mode
+
+!ifndef LANG
+target: $(DEST)\kernel.exe $(DEST)\krnl386.sym
+!else
+target: $(DEST)\krnl386.$(LANG)
+!endif
+
+$(DEST)\kernel.exe: krnl386.lnk $(DEF) $(DEST)\kernstub.exe $(OBJ) $(OBJ3) \
+ krnl386.res
+ cd $(DEST)
+ $(LINK) $(LDEBUG) @..\krnl386.lnk,..\$(DEF)
+ rc16 -t ..\krnl386.res kernel.exe
+ fixexe kernel.exe
+ cd ..
+
+$(DEST)\krnl386.$(LANG): iclean krnl386.lnk $(DEF) $(DEST)\kernstub.exe \
+ $(OBJ) $(OBJ3) krnl386.res
+ cd $(DEST)
+ rc16 -r $(CINC) ..\krnl386.rc -fo krnl386.res
+ $(LINK) $(LDEBUG) @..\krnl386.lnk,..\$(DEF)
+ rc16 -t ..\krnl386.res kernel.exe
+ fixexe kernel.exe
+ copy kernel.exe krnl386.$(LANG)
+ -erase kernel.exe
+ cd ..
+
+!endif
+
+
+# international mode
+
+strings.asm: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+iclean:
+ erase $(DEST)\strings.obj
+ erase strings.asm
+
+$(DEST)\kernstub.exe: kernstub.asm
+ cd $(DEST)
+ masm $(KSAFLAGS) ..\kernstub;
+ link16 kernstub;
+ -erase kernstub.obj
+ cd ..
+
+
+$(DEST)\kernel.map: $(DEST)\kernel.exe
+
+
+$(DEST)\kernel.sym: $(DEST)\kernel.map qgrep.grp
+ cd $(DEST)
+ mapsym /n kernel
+ cd ..
+
+krnl386.res: krnl386.rc kernel.rcv ..\inc\common.ver
+ rc16 -r $(CINC) $*.rc -fo $@
+
+$(DEST)\krnl286.sym: $(DEST)\kernel.map qgrep.grp
+ cd $(DEST)
+ mapsym /n kernel
+ copy kernel.sym krnl286.sym
+ copy kernel.map krnl286.map
+ copy kernel.exe krnl286.exe
+ copy kernel.sym krnl286.sym
+ -erase kernel.exe
+ cd ..
+
+
+$(DEST)\krnl386.sym: $(DEST)\kernel.map qgrep.grp
+ cd $(DEST)
+ mapsym /n kernel
+ copy kernel.sym krnl386.sym
+ copy kernel.map krnl386.map
+ copy kernel.exe krnl386.exe
+ copy kernel.sym krnl386.sym
+ -erase kernel.exe
+ cd ..
+
+depend: strings.asm
+ copy makefile makefile.old
+ sed "/^# Dependencies follow/,/^# see depend: above/D" makefile.old > makefile
+ echo # Dependencies follow >> makefile
+ includes $(AINC) -A=api *.asm | sed -f kernel.sed>> makefile
+ includes $(CINC) *.c | sed s/:/::/ >> makefile
+ echo # IF YOU PUT STUFF HERE IT WILL GET BLASTED >> makefile
+ echo # see depend: above >> makefile
+
+#
+# The C File List
+#
+# Do not put dependencies here. Dependencies are created by
+# "nmake depend."
+#
+
+$(DEST)\rip.obj:: rip.c
+ $(CP) rip.c
+
+$(DEST)\lzexp.obj:: lzexp.c
+ $(CP) -NT _TEXT lzexp.c
+
+$(DEST)\error.obj:: error.c
+ $(CP) -NT _TEXT error.c
+
+$(DEST)\disasm.obj:: disasm.c
+ $(CP) disasm.c
+
+# DO NOT DELETE THE FOLLOWING LINE
+# Dependencies follow
+$(DEST)\2galloc.obj 2galloc.lst: 2galloc.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc protect.inc \
+ winkern.inc
+ $(ASM) 2galloc,$(DEST)\;
+
+$(DEST)\2gcompac.obj 2gcompac.lst: 2gcompac.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc winkern.inc
+ $(ASM) 2gcompac,$(DEST)\;
+
+$(DEST)\2ginterf.obj 2ginterf.lst: 2ginterf.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc pdb.inc protect.inc tdb.inc winkern.inc \
+ $(WOWINC)\tdb16.inc $(WOWINC)\wowkrn.inc
+ $(ASM) 2ginterf,$(DEST)\;
+
+$(DEST)\2glru.obj 2glru.lst: 2glru.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) 2glru,$(DEST)\;
+
+$(DEST)\2gmem.obj 2gmem.lst: 2gmem.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc
+ $(ASM) 2gmem,$(DEST)\;
+
+$(DEST)\2gmemini.obj 2gmemini.lst: 2gmemini.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc winkern.inc
+ $(ASM) 2gmemini,$(DEST)\;
+
+$(DEST)\2gmoreme.obj 2gmoreme.lst: 2gmoreme.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) 2gmoreme,$(DEST)\;
+
+$(DEST)\2protect.obj 2protect.lst: 2protect.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc aliases.asm \
+ ikernel.inc kernel.inc krom.inc pdb.inc protect.inc winkern.inc
+ $(ASM) 2protect,$(DEST)\;
+
+$(DEST)\3gacheck.obj 3gacheck.lst: 3gacheck.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc winkern.inc
+ $(ASM) 3gacheck,$(DEST)\;
+
+$(DEST)\3galloc.obj 3galloc.lst: 3galloc.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc protect.inc \
+ winkern.inc
+ $(ASM) 3galloc,$(DEST)\;
+
+$(DEST)\3gcompac.obj 3gcompac.lst: 3gcompac.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc winkern.inc
+ $(ASM) 3gcompac,$(DEST)\;
+
+$(DEST)\3ginterf.obj 3ginterf.lst: 3ginterf.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc pdb.inc protect.inc tdb.inc winkern.inc \
+ $(WOWINC)\tdb16.inc $(WOWINC)\wow.inc $(WOWINC)\wowkrn.inc
+ $(ASM) 3ginterf,$(DEST)\;
+
+$(DEST)\3glru.obj 3glru.lst: 3glru.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) 3glru,$(DEST)\;
+
+$(DEST)\3gmem.obj 3gmem.lst: 3gmem.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc
+ $(ASM) 3gmem,$(DEST)\;
+
+$(DEST)\3gmemini.obj 3gmemini.lst: 3gmemini.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc winkern.inc
+ $(ASM) 3gmemini,$(DEST)\;
+
+$(DEST)\3gmoreme.obj 3gmoreme.lst: 3gmoreme.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) 3gmoreme,$(DEST)\;
+
+$(DEST)\3protect.obj 3protect.lst: 3protect.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ pdb.inc protect.inc winkern.inc
+ $(ASM) 3protect,$(DEST)\;
+
+$(DEST)\aliases.obj aliases.lst: aliases.asm
+ $(ASM) aliases,$(DEST)\;
+
+$(DEST)\atom.obj atom.lst: atom.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) atom,$(DEST)\;
+
+$(DEST)\context.obj context.lst: context.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc $(WOWINC)\wowcmpat.inc
+ $(ASM) context,$(DEST)\;
+
+$(DEST)\diag.obj diag.lst: diag.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) diag,$(DEST)\;
+
+$(DEST)\diskio.obj diskio.lst: diskio.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) diskio,$(DEST)\;
+
+$(DEST)\dosinit.obj dosinit.lst: dosinit.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc pdb.inc winkern.inc
+ $(ASM) dosinit,$(DEST)\;
+
+$(DEST)\emsmisc.obj emsmisc.lst: emsmisc.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) emsmisc,$(DEST)\;
+
+$(DEST)\enable.obj enable.lst: enable.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) enable,$(DEST)\;
+
+$(DEST)\gacheck.obj gacheck.lst: gacheck.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) gacheck,$(DEST)\;
+
+$(DEST)\gpcont.obj gpcont.lst: gpcont.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc gpcont.inc ikernel.inc kernel.inc \
+ krom.inc winkern.inc
+ $(ASM) gpcont,$(DEST)\;
+
+$(DEST)\gpfix.obj gpfix.lst: gpfix.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) gpfix,$(DEST)\;
+
+$(DEST)\handle.obj handle.lst: handle.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) handle,$(DEST)\;
+
+$(DEST)\hmem.obj hmem.lst: hmem.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) hmem,$(DEST)\;
+
+$(DEST)\i21entry.obj i21entry.lst: i21entry.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc eems.inc \
+ ikernel.inc kernel.inc krom.inc pdb.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc
+ $(ASM) i21entry,$(DEST)\;
+
+$(DEST)\i21file.obj i21file.lst: i21file.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc eems.inc ikernel.inc kdos.inc kernel.inc krom.inc \
+ pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) i21file,$(DEST)\;
+
+$(DEST)\i21task.obj i21task.lst: i21task.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc eems.inc ikernel.inc kdos.inc kernel.inc krom.inc \
+ pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) i21task,$(DEST)\;
+
+
+$(DEST)\int24.obj int24.lst: int24.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) int24,$(DEST)\;
+
+$(DEST)\intnn.obj intnn.lst: intnn.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc
+ $(ASM) intnn,$(DEST)\;
+
+$(DEST)\kdata.obj kdata.lst: kdata.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/rom.inc gpcont.inc ikernel.inc kernel.inc \
+ krom.inc winkern.inc
+ $(ASM) kdata,$(DEST)\;
+
+$(DEST)\kdataend.obj kdataend.lst: kdataend.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) kdataend,$(DEST)\;
+
+$(DEST)\kernstub.obj kernstub.lst: kernstub.asm ../inc/cmacros.inc \
+ ../inc/newexe.inc protect.inc
+ $(ASM) kernstub,$(DEST)\;
+
+$(DEST)\kthunks.obj kthunks.lst: kthunks.asm ../inc/cmacros.inc \
+ $(WOWINC)\wow.inc $(WOWINC)\wowkrn.inc
+ $(ASM) kthunks,$(DEST)\;
+
+$(DEST)\lacheck.obj lacheck.lst: lacheck.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) lacheck,$(DEST)\;
+
+$(DEST)\lalloc.obj lalloc.lst: lalloc.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) lalloc,$(DEST)\;
+
+$(DEST)\layer.obj layer.lst: layer.asm ../inc/gpfix.inc ../inc/klayer.inc \
+ ../inc/logerror.inc kernel.api
+ $(ASM) layer,$(DEST)\;
+
+$(DEST)\lcompact.obj lcompact.lst: lcompact.asm ../inc/cmacros.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) lcompact,$(DEST)\;
+
+$(DEST)\ld.obj ld.lst: ld.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ld,$(DEST)\;
+
+$(DEST)\ldappl.obj ldappl.lst: ldappl.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc appl.inc ikernel.inc kernel.inc \
+ krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldappl,$(DEST)\;
+
+$(DEST)\ldaux.obj ldaux.lst: ldaux.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldaux,$(DEST)\;
+
+$(DEST)\ldboot.obj ldboot.lst: ldboot.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc gpcont.inc ikernel.inc \
+ kernel.inc krom.inc pdb.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc $(WOWINC)\doswow.inc
+ $(ASM) ldboot,$(DEST)\;
+
+$(DEST)\ldcache.obj ldcache.lst: ldcache.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldcache,$(DEST)\;
+
+$(DEST)\lddebug.obj lddebug.lst: lddebug.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc $(WOWINC)\tdb16.inc \
+ $(WOWINC)\bop.inc $(WOWINC)\wow.inc $(WOWINC)\dbgsvc.inc
+ $(ASM) lddebug,$(DEST)\;
+
+$(DEST)\ldfastb.obj ldfastb.lst: ldfastb.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldfastb,$(DEST)\;
+
+$(DEST)\ldfile.obj ldfile.lst: ldfile.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) ldfile,$(DEST)\;
+
+$(DEST)\ldheader.obj ldheader.lst: ldheader.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc winkern.inc
+ $(ASM) ldheader,$(DEST)\;
+
+$(DEST)\ldint.obj ldint.lst: ldint.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ../inc/windows.inc gpcont.inc \
+ ikernel.inc kdos.inc kernel.inc krom.inc protect.inc tdb.inc $(WOWINC)\tdb16.inc \
+ winkern.inc $(WOWINC)\bop.inc
+ $(ASM) ldint,$(DEST)\;
+
+$(DEST)\ldopen.obj ldopen.lst: ldopen.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldopen,$(DEST)\;
+
+$(DEST)\ldreloc.obj ldreloc.lst: ldreloc.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/newexe.inc ../inc/rom.inc ikernel.inc \
+ kernel.inc krom.inc protect.inc winkern.inc
+ $(ASM) ldreloc,$(DEST)\;
+
+$(DEST)\ldseg.obj ldseg.lst: ldseg.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldseg,$(DEST)\;
+
+$(DEST)\ldself.obj ldself.lst: ldself.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldself,$(DEST)\;
+
+$(DEST)\ldstack.obj ldstack.lst: ldstack.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldstack,$(DEST)\;
+
+$(DEST)\ldutil.obj ldutil.lst: ldutil.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) ldutil,$(DEST)\;
+
+$(DEST)\lhandle.obj lhandle.lst: lhandle.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) lhandle,$(DEST)\;
+
+$(DEST)\linterf.obj linterf.lst: linterf.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) linterf,$(DEST)\;
+
+$(DEST)\lstring.obj lstring.lst: lstring.asm ../inc/cmacros.inc ../inc/gpfix.inc \
+ ../inc/logerror.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc $(WOWINC)\wowcmpat.inc
+ $(ASM) lstring,$(DEST)\;
+
+$(DEST)\mapdata.obj mapdata.lst: mapdata.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) mapdata,$(DEST)\;
+
+$(DEST)\miscapi.obj miscapi.lst: miscapi.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) miscapi,$(DEST)\;
+
+$(DEST)\module.obj module.lst: module.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) module,$(DEST)\;
+
+$(DEST)\patch.obj patch.lst: patch.asm ../inc/cmacros.inc kernel.inc \
+ ../inc/gpfix.inc pdb.inc tdb.inc ../inc/newexe.inc protect.inc
+ $(ASM) patch,$(DEST)\;
+
+$(DEST)\reboot.obj reboot.lst: reboot.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) reboot,$(DEST)\;
+
+$(DEST)\resaux.obj resaux.lst: resaux.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ protect.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) resaux,$(DEST)\;
+
+$(DEST)\ripaux.obj ripaux.lst: ripaux.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc ikernel.inc kernel.inc krom.inc \
+ winkern.inc
+ $(ASM) ripaux,$(DEST)\;
+
+$(DEST)\rom.obj rom.lst: rom.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc pdb.inc protect.inc \
+ winkern.inc
+ $(ASM) rom,$(DEST)\;
+
+$(DEST)\stack.obj stack.lst: stack.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc
+ $(ASM) stack,$(DEST)\;
+
+$(DEST)\strings.obj strings.lst: strings.asm gpcont.inc
+ $(ASM) strings,$(DEST)\;
+
+$(DEST)\task.obj task.lst: task.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/newexe.inc ../inc/rom.inc eems.inc ikernel.inc kernel.inc \
+ krom.inc pdb.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc \
+ $(WOWINC)\bop.inc
+ $(ASM) task,$(DEST)\;
+
+$(DEST)\tasking.obj tasking.lst: tasking.asm ../inc/cmacros.inc \
+ tdb.inc $(WOWINC)\tdb16.inc $(WOWINC)\wow.inc
+ $(ASM) tasking,$(DEST)\;
+
+$(DEST)\userpro.obj userpro.lst: userpro.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc pdb.inc winkern.inc
+ $(ASM) userpro,$(DEST)\;
+
+$(DEST)\w32sys.obj w32sys.lst: w32sys.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc tdb.inc $(WOWINC)\tdb16.inc winkern.inc
+ $(ASM) w32sys,$(DEST)\;
+
+$(DEST)\winexec.obj winexec.lst: winexec.asm ../inc/cmacros.inc ../inc/logerror.inc \
+ ../inc/rom.inc ikernel.inc kernel.inc krom.inc winkern.inc $(WOWINC)\wowcmpat.inc
+ $(ASM) winexec,$(DEST)\;
+
+$(DEST)\wowdeb.obj wowdeb.lst: wowdeb.asm ../inc/cmacros.inc \
+ kernel.inc $(WOWINC)\wow.inc
+ $(ASM) wowdeb,$(DEST)\;
+
+$(DEST)\wow16cal.obj wow16cal.lst: wow16cal.asm ../inc/cmacros.inc \
+ $(WOWINC)\wow.inc $(WOWINC)\dpmi.inc tdb.inc $(WOWINC)\tdb16.inc
+ $(ASM) wow16cal,$(DEST)\;
+
+
+disasm.obj disasm.lst:: disasm.c ../inc/windows.h ../inc/windowsx.h
+
+error.obj error.lst:: error.c ../inc/logerror.h ikernel.h kernel.h
+
+fixexe.obj fixexe.lst:: fixexe.c
+
+lzexp.obj lzexp.lst:: lzexp.c ikernel.h kernel.h
+
+rip.obj rip.lst:: rip.c ikernel.h kernel.h newexe.h
+
+# IF YOU PUT STUFF HERE IT WILL GET BLASTED
+# see depend: above
diff --git a/private/mvdm/wow16/kernel31/mapdata.asm b/private/mvdm/wow16/kernel31/mapdata.asm
new file mode 100644
index 000000000..b34c3be92
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/mapdata.asm
@@ -0,0 +1,66 @@
+ TITLE MAPDATA - Map DS to kernel's data segment
+
+include kernel.inc
+
+
+; This code could go almost anywhere, but didn't really belong in kdata.asm
+
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+assumes SS,NOTHING
+
+KDataSeg dw seg _DATA
+public KDataSeg
+
+cProc MapDStoDATA,<PUBLIC,NEAR>
+cBegin nogen
+;;; push ax
+;;; mov ax,seg _DATA
+;;; mov ds,ax
+;;; pop ax
+ mov ds, cs:KDataSeg
+ ret
+cEnd nogen
+
+sEnd NRESCODE
+
+
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+assumes ss, nothing
+
+MKDataSeg dw seg _DATA
+public MKDataSeg
+
+cProc MISCMapDStoDATA,<PUBLIC,NEAR>
+cBegin nogen
+;;; push ax
+;;; mov ax,seg _DATA
+;;; mov ds,ax
+;;; pop ax
+ mov ds, cs:MKDataSeg
+ ret
+cEnd nogen
+
+
+if 0 ;----------------------------------------------------------------
+cProc MISCMapEStoDATA,<PUBLIC,NEAR>
+cBegin nogen
+;;; push ax
+;;; mov ax,seg _DATA
+;;; mov es,ax
+;;; pop ax
+ mov es, cs:MKDataSeg
+ ret
+cEnd nogen
+endif ;----------------------------------------------------------------
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/messages/usa/strings.asm b/private/mvdm/wow16/kernel31/messages/usa/strings.asm
new file mode 100644
index 000000000..01fdf84ff
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/messages/usa/strings.asm
@@ -0,0 +1,258 @@
+ TITLE STRINGS - OEM dependent strings used by KERNEL
+include gpcont.inc ; SHERLOCK
+
+_DATA SEGMENT PARA PUBLIC 'DATA'
+_DATA ENDS
+
+DGROUP GROUP _DATA
+
+_INITTEXT SEGMENT WORD PUBLIC 'CODE'
+_INITTEXT ENDS
+
+_NRESTEXT SEGMENT WORD PUBLIC 'CODE'
+_NRESTEXT ENDS
+
+ASSUME DS:DGROUP
+
+
+_DATA SEGMENT PARA PUBLIC 'DATA'
+
+; This is the caption string for the dialog box.
+
+public szDiskCap
+IF 0
+szDiskCap db 'Change Disk',0
+ELSE
+szDiskCap db 'File Error',0
+ENDIF
+
+
+; This is the text for the "Cannot find xxxxxx" dialog box.
+; It is printed:
+;
+; <szCannotFind1>filename<szCannotFind2>
+
+public szCannotFind1,szCannotFind2
+szCannotFind1 db "Cannot find ", 0
+szCannotFind2 db 0
+
+; This is the text for fatal errors at boot time
+; <szBootLoad>filename
+public szBootLoad
+szBootLoad db "Error loading ",0
+
+; The following group of strings is used for the "Please insert disk with XXXX
+; in drive X:" dialog box.
+;
+; These two strings form the dialog message it is:
+;
+; <szCannotFind1>filename<szInsert>
+
+IF 0
+public szInsert
+szInsert db ', Please insert in drive '
+ENDIF
+;public drvlet
+;drvlet db "X.",0
+
+if SHERLOCK
+public szGPCont ; GP fault continuation message
+szGPCont db "An error has occurred in your application.",10
+ db "If you choose Ignore, you should save your work in a new file.",10
+ db "If you choose Close, your application will terminate.",0
+endif
+
+public szDosVer
+szDosVer DB 'Incorrect MS-DOS version. MS-DOS 3.1 or greater required.',13,10,'$'
+; Text for exceptions and faults lead to app termination.
+
+public szAbortCaption,szInModule,szAt
+public szNukeApp,szSnoozer,szGP,szSF,szII,szPF,szNP,szBlame,szLoad,szWillClose
+public szOutofSelectors
+szAbortCaption db "Application Error"
+ db 0
+szBlame db "BOOT "
+ db 0
+szSnoozer db " caused "
+ db 0
+szInModule db " in", 10, "module <unknown>"
+ db 0
+szAt db " at "
+ db 0
+szNukeApp db ".", 10, 10, "Choose close. "
+ db 0
+szWillClose db " will close."
+ db 0
+szGP db "a General Protection Fault"
+ db 0
+szD0 db "a Divide by Zero" ; not yet used
+ db 0
+szSF db "a Stack Fault" ; not spec'ed
+ db 0
+szII db "an Illegal Instruction" ; "Fault" ???
+ db 0
+szPF db "a Page Fault"
+ db 0
+szNP db "a Not Present Fault"
+ db 0
+szAF db "an Application Fault" ; not yet used
+ db 0
+szLoad db "Segment Load Failure"
+ db 0
+szOutofSelectors db "Out of Selectors"
+ db 0
+
+; Text for dialog box when terminating an application
+
+public szAbort
+szAbort db "Closing current application.",0
+
+; Text for dialog box when trying to run a compressed file
+
+public szBozo
+szBozo db "Cannot load compressed files",0
+
+; This is the caption string for system error dialog boxes
+
+public syserr
+syserr db "System Error",0
+
+; The following group of messages forms all of the messages used
+; in the INT 24 dialog box.
+;
+; There are 7 messages which can be translated individually. The
+; location of drvlet? and devenam? can be moved to any location
+; within the string.
+
+public msgWriteProtect,drvlet1
+public msgCannotReadDrv,drvlet2
+public msgCannotWriteDrv,drvlet3
+public msgShare,drvlet4
+public msgNetError,drvlet5
+public msgCannotReadDev,devenam1
+public msgCannotWriteDev,devenam2
+public msgNoPrinter
+public msgNetErrorDev,devenam3
+
+msgWriteProtect db "Write-protected disk in drive "
+drvlet1 db "X.",0
+
+msgCannotReadDrv db "Cannot read from drive "
+drvlet2 db "X.",0
+
+msgCannotWriteDrv db "Cannot write to drive "
+drvlet3 db "X.",0
+
+msgShare db "Sharing violation on drive "
+drvlet4 db "X.",0
+
+msgNetError db "Network error on drive "
+drvlet5 db "X.",0
+
+msgCannotReadDev db "Cannot read from device "
+devenam1 db 8 dup (?)
+ db 0
+
+msgCannotWriteDev db "Cannot write to device "
+devenam2 db 8 dup (?)
+ db 0
+
+msgNetErrorDev db "Network error on device "
+devenam3 db 8 dup (?)
+ db 0
+
+msgNoPrinter db "Printer not ready",0
+
+
+ifndef WINDEBUG
+public szExitStr1,szExitStr2
+szExitStr1 DB 7,13,10,'FatalExit code = ',0
+szExitStr2 DB ' stack overflow',13,10,0
+public szUndefDyn
+szUndefDyn db "Call to Undefined Dynalink",0
+public szFatalExit
+szFatalExit db "Application requested abnormal termination",0
+else
+public szDebugStr
+szDebugStr DB 'KERNEL: Failed loading - ',0 ; 0
+ DB 'KERNEL: Failed loading new instance of - ',0 ; 1
+ DB 'Error loading from resource file - ',0 ; 2
+ DB 13,10,0 ; 3
+ DB 7,13,10,'FatalExit code = ',0 ; 4
+ DB ' stack overflow',0 ; 5
+ DB 13,10,'Stack trace:',13,10,0 ; 6
+ DB 7,13,10,'Abort, Break, Exit or Ignore? ',0 ; 7
+ DB 'Invalid BP chain',7,13,10,0 ; 8
+ DB ': ',0 ; 9
+ DB 'Reentered FatalExit',7,13,10,0 ; 10
+ DB 0
+public szFKE
+szFKE DB '*** Fatal Kernel Error ***',0
+endif
+
+;** Diagnostic mode messages
+ public szDiagStart, szCRLF, szLoadStart, szLoadSuccess, szLoadFail
+ public szFailCode, szCodeString
+szDiagStart db '[boot]' ;lpCRLF must follow
+szCRLF db 0dh, 0ah, 0
+szLoadStart db 'LoadStart = ',0
+szLoadSuccess db 'LoadSuccess = ', 0
+szLoadFail db 'LoadFail = ', 0
+szFailCode db ' Failure code is ' ;szCodeString must follow
+szCodeString db '00', 0dh, 0ah, 0
+ifdef WINDEBUG
+ public szInitSpew
+szInitSpew DB 'Diagnostic mode startup. Log file is: ', 0
+endif
+
+_DATA ENDS
+
+
+_INITTEXT SEGMENT WORD PUBLIC 'CODE'
+public szInadequate, szNoPMode, szNoGlobalInit
+public NoOpenFile, NoLoadHeader
+
+ifdef WOW
+public szGenBootFail
+szNoPMode db "The Win16 Subsystem was unable to enter Protected Mode, DOSX.EXE must be in your AUTOEXEC.NT and present in your PATH.",0
+szInadequate db "KERNEL: Inadequate DPMI Server",0
+szNoGlobalInit db "KERNEL: Unable to initialize heap",0
+NoOpenFile db "KERNEL: Unable to open KERNEL executable",0
+NoLoadHeader db "KERNEL: Unable to load KERNEL EXE header",0
+szGenBootFail db "KERNEL: Win16 Subsystem Initialization Failure",0
+else
+szInadequate db 'KERNEL: Inadequate DPMI Server',13,10,'$'
+szNoPMode db 'KERNEL: Unable to enter Protected Mode',13,10,'$'
+szNoGlobalInit db "KERNEL: Unable to initialize heap",13,10,'$'
+NoOpenFile db "KERNEL: Unable to open KERNEL executable"
+ db 13, 10, '$'
+NoLoadHeader db "KERNEL: Unable to load KERNEL EXE header"
+ db 13, 10, '$'
+endif
+
+_INITTEXT ENDS
+
+
+
+
+_NRESTEXT SEGMENT WORD PUBLIC 'CODE'
+
+; This is the caption string for the protect mode dialog box.
+;
+; DO NOT CHANGE THE LENGTH OF THIS MESSAGE
+;
+
+public szProtectCap,msgRealModeApp1,msgRealModeApp2
+
+szProtectCap db "Application Compatibility Warning",0
+
+msgRealModeApp1 db "The application you are about to run, ",0
+msgRealModeApp2 db ", was designed for a previous version of Windows.",0Dh,0Dh
+ db "Obtain an updated version of the application that is compatible "
+ db "with Windows version 3.0 and later.",13,13
+ db "If you choose the OK button and start the application, compatibility "
+ db "problems could cause the application or Windows to close unexpectedly.",0
+
+_NRESTEXT ENDS
+
+end
diff --git a/private/mvdm/wow16/kernel31/miscapi.asm b/private/mvdm/wow16/kernel31/miscapi.asm
new file mode 100644
index 000000000..d96dfdf2a
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/miscapi.asm
@@ -0,0 +1,569 @@
+
+
+.xlist
+include kernel.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+include eems.inc
+.list
+
+externFP GlobalDOSAlloc
+externFP GlobalDOSFree
+externFP GetProfileString
+
+DataBegin
+
+externB kernel_flags
+externW MyCSAlias
+externW curTDB
+externW headTDB
+if 0 ; EarleH
+externW LastCriticalError
+endif
+externW LastExtendedError
+
+externD FatalExitProc
+
+if ROM
+externD PrevInt21Proc
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes ds, nothing
+assumes es, nothing
+
+ife ROM
+externD PrevInt21Proc
+endif
+
+externNP SetOwner
+
+;-----------------------------------------------------------------------;
+; A20Proc ;
+; Enable / Disable the A20 line by calling an XMS driver ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Mar 31, 1988 -by- Tony Gosling ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc A20Proc,<PUBLIC,FAR>,<si,di>
+ parmW enable
+cBegin
+cEnd
+
+
+;**
+;
+; NETBIOSCALL -- Issue an INT 5C for caller
+;
+; This call is provided as a Kernel service to applications that
+; wish to issue NETBIOS INT 5Ch calls WITHOUT coding an INT 5Ch, which
+; is incompatible with protected mode.
+;
+; ENTRY:
+; All registers as for INT 5Ch
+;
+; EXIT:
+; All registers as for particular INT 5Ch call
+;
+; USES:
+; As per INT 5Ch call
+;
+;
+cProc NETBIOSCALL,<PUBLIC,FAR>
+cBegin
+ int 5Ch
+cEnd
+
+
+;**
+;
+; SetHandleCount -- Set the handle count in the PDB
+;
+; Sets the per process handle count to a new value
+; and allocates space for these file handles
+;
+; ENTRY:
+; nFiles - new number of file handles required
+;
+; EXIT:
+; returns new number of file handles
+;
+; USES:
+; C call
+;
+;
+cProc ISetHandleCount,<PUBLIC,FAR>,<di,si>
+ parmW nFiles
+cBegin
+ SetKernelDS
+ mov si, CurTDB
+ mov ds, si
+ UnSetKernelDS
+ mov ds, ds:[TDB_PDB]
+
+ ;** We allow no more than 255. Also, if something smaller than what
+ ;** we have, we just do nothing and respond with the number we
+ ;** already have.
+ mov ax, ds:[PDB_JFN_Length] ; How many now
+ cmp nFiles,255 ;Validate the parameter
+ jbe SHC_OK ;Parm OK
+
+IF KDEBUG
+ push ax
+ kerror ERR_PARAMETER,<SetHandleCount: Too many files requested:>,nFiles,0
+ pop ax
+ENDIF
+ mov nFiles,255 ;Force it to do no more than 255
+SHC_OK: mov bx, nFiles
+ cmp ax, bx ; Don't want more?
+ jae no_change
+
+ ;** Allocate memory for a new file handle table
+ add bx, 2
+ cCall GlobalDOSAlloc, <0, bx>
+ or ax, ax
+ jnz ok_we_got_it
+ mov ax, ds:[PDB_JFN_Length] ; Return original number
+ jmp SHORT no_change
+ok_we_got_it:
+
+ ;** Prepare the new table and update the PDB for the new table
+ cCall SetOwner,<ax,si> ;Hide it from GlobalFreeAll
+ mov es, ax ;Point to new table with ES
+ mov WORD PTR ds:[PDB_JFN_Pointer][2], dx ;Save seg address
+ xor di, di
+ mov si, word ptr ds:[PDB_JFN_Pointer] ;Offset of old table
+ mov cx, ds:[PDB_JFN_Length] ;Bytes to copy (one byte per handle)
+ mov WORD PTR ds:[PDB_JFN_Pointer][0], di ;Save new offset
+ mov bx, nFiles ;Save new number of files
+ mov ds:[PDB_JFN_Length], bx
+ push ds ;Save PDB selector for later
+
+ ;** We use the PDB selector to copy if we're copying the original
+ ;** table which is always in the PDB. Note that we only have a
+ ;** non-zero offset if the table is in the PDB. We can't save
+ ;** the selector in the table in this case until AFTER
+ or si, si ;Table in PDB?
+ jnz @F ;Yes
+ mov ds, WORD PTR ds:[PDB_JFN_Table] ;Get old selector to copy from
+@@:
+
+ ;** Copy the existing table into the new one
+ cld
+ rep movsb ;Copy existing files
+ mov al, -1
+ mov cx, nFiles
+ sub cx, di
+ rep stosb ;Pad new files with -1
+ mov ax, ds
+ pop bx ;Retrieve PDB selector
+ mov ds, bx
+ mov WORD PTR ds:[PDB_JFN_Table], es ;Save new selector
+
+ ;** We only free the old table if it wasn't in the PDB
+ cmp ax, bx ;Were we using the PDB selector?
+ je SHC_OldTableInPDB ;Yes. Don't free it
+ cCall GlobalDOSFree, <ax> ;Free old table
+SHC_OldTableInPDB:
+
+ mov ax, nFiles
+no_change:
+cEnd
+
+;-----------------------------------------------------------------------;
+; GetSetKernelDOSProc ;
+; Set the address kernel calls for DOS ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Dec 31, 1990 -by- Tony Gosling ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetSetKernelDOSProc,<PUBLIC,FAR>
+ parmD NewProc
+cBegin
+ SetKernelDS
+ife ROM
+ mov ds, MyCSAlias
+ assumes ds, CODE
+endif
+ mov ax, word ptr NewProc[0]
+ xchg ax, word ptr PrevInt21Proc[0]
+ mov dx, word ptr NewProc[2]
+ xchg dx, word ptr PrevInt21Proc[2]
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FatalExitHook ;
+; Hooks FatalExit ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Dec 31, 1990 -by- Tony Gosling ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FatalExitHook,<PUBLIC,FAR>
+ parmD NewProc
+cBegin
+ SetKernelDS
+ mov ax, word ptr NewProc[0]
+ xchg ax, word ptr FatalExitProc[0]
+ mov dx, word ptr NewProc[2]
+ xchg dx, word ptr FatalExitProc[2]
+cEnd
+
+if 0 ; EarleH
+
+;-----------------------------------------------------------------------;
+; GetLastCriticalError ;
+; Get the last int 24h error and extended error code ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri Dec 31, 1990 -by- Tony Gosling ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetLastCriticalError,<PUBLIC,FAR>
+cBegin
+ SetKernelDS
+ mov ax, -1
+ mov dx, ax
+ xchg ax, LastExtendedError
+ xchg dx, LastCriticalError
+cEnd
+endif ;0
+
+;-----------------------------------------------------------------------;
+; DWORD GetAppCompatFlags(HTASK hTask) ;
+; ;
+; Returns win.ini [Compatibility] flags for hTask (or current task ;
+; if hTask is NULL). ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; All but DX:AX ;
+; ;
+; Registers Destroyed: ;
+; ;
+; DX, AX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetAppCompatFlags,<PUBLIC,FAR>,<DS>
+parmW hTask
+cBegin
+ SetKernelDS
+ mov ax,hTask
+ or ax,ax
+ jnz got_tdb
+ mov ax,curTDB ; If no current task (e.g., during boot)
+ cwd ; just return 0L.
+ or ax,ax
+ jz gacf_exit
+got_tdb:
+ mov ds,ax
+ UnSetKernelDS
+ mov ax,ds:[TDB_CompatFlags]
+ mov dx,ds:[TDB_CompatFlags2]
+gacf_exit:
+ UnSetKernelDS
+cEnd
+
+; Simpler (faster) NEAR version for Kernel -- only works for current task!
+;
+; Preserves all regs except dx:ax
+;
+cProc MyGetAppCompatFlags,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+
+ mov ax, curTDB
+ cwd
+ or ax, ax ; No current task while booting
+ jz mygacf_exit
+
+ mov ds, ax
+ UnSetKernelDS
+ mov ax, ds:[TDB_CompatFlags]
+ mov dx, ds:[TDB_CompatFlags2]
+
+mygacf_exit:
+ pop ds
+ UnSetKernelDS
+ ret
+
+cEnd nogen
+
+ifdef WOW
+cProc MyGetAppWOWCompatFlags,<PUBLIC,NEAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+
+ mov ax, curTDB
+ cwd
+ or ax, ax ; No current task while booting
+ jz wow_mygacf_exit
+
+ mov ds, ax
+ UnSetKernelDS
+ mov ax, ds:[TDB_WOWCompatFlags]
+ mov dx, ds:[TDB_WOWCompatFlags2]
+
+wow_mygacf_exit:
+ pop ds
+ UnSetKernelDS
+ ret
+
+cEnd nogen
+
+;
+; Returns WOW extended compatiblity flags
+;
+; Preserves all regs except dx:ax
+;
+cProc MyGetAppWOWCompatFlagsEx,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+
+ mov ax, curTDB
+ cwd
+ or ax, ax ; No current task while booting
+ jz wow_mygacfex_exit
+
+ mov ds, ax
+ UnSetKernelDS
+ mov ax, ds:[TDB_WOWCompatFlagsEx]
+ mov dx, ds:[TDB_WOWCompatFlagsEx2]
+
+wow_mygacfex_exit:
+ pop ds
+ UnSetKernelDS
+ retf
+
+cEnd nogen
+
+
+;---------------------------------------------------------------------------
+; This gets called from FreeProcInstance. If the proc being freed is an
+; AbortProc that was set by the app, we reset it to NULL. This way we dont
+; callback to a proc that's garbage.
+;
+; This case happens with Aldus Pagemaker ver 5.0 when one prints to EPS file.
+; The app sets the AbortProc and then later calls freeprocinstance.
+; Subsequently when it make the call Escape(..OPENCHANNEL..) the callback
+; occurs and we die randomly.
+;
+; This solution is a general solution.
+; - Nanduri
+;---------------------------------------------------------------------------
+
+cProc HandleAbortProc, <PUBLIC,FAR>, <ds, ax>
+ ParmD pproc
+cBegin
+ SetKernelDS
+
+ mov ax, curTDB
+ or ax, ax ; No current task while booting
+ jz wow_aproc_exit
+
+ mov ds, ax
+ UnSetKernelDS
+ mov ax, ds:[TDB_vpfnAbortProc+2]
+ or ax, ax
+ je wow_aproc_exit ; sel = 0 - no abort proc. done
+ cmp ax, word ptr [pproc+2]
+ jnz wow_aproc_exit ; selectors don't match
+ mov ax, ds:[TDB_vpfnAbortProc]
+ cmp ax, word ptr [pproc]
+ jnz wow_aproc_exit ; offsets don't match
+
+ mov ds:[TDB_vpfnAbortProc], 0 ; set abort proc to NULL.
+ mov ds:[TDB_vpfnAbortProc+2], 0
+wow_aproc_exit:
+ UnSetKernelDS
+cEnd
+
+endif ; WOW
+
+sEnd CODE
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+
+CompatSection DB 'Compatibility'
+DefVal DB 0
+
+cProc SetAppCompatFlags, <PUBLIC, NEAR>, <ds, es, si, di>
+ localV szHex,12 ; read string to here
+ localV key, <SIZE TDB_Modname + 2> ; ModName of loading app
+cBegin
+ xor ax, ax
+ cwd
+ cmp es:[TDB_ExpWinVer], 30Ah ; Hacks don't apply to 3.1 or above
+ jae sa_exit
+
+ push es ; Copy ModName to zero-terminate it
+ pop ds
+ lea si, es:[TDB_ModName]
+ push ss
+ pop es
+ lea di, key
+ mov cx, SIZE TDB_Modname
+ cld
+ rep movsb
+ stosb
+
+ push cs
+ push NREScodeoffset CompatSection
+
+ push ss
+ lea ax, key
+ push ax
+
+ push cs
+ push NREScodeoffset DefVal
+
+ push ss
+ lea ax, szHex
+ push ax
+
+ push 12
+
+ call GetProfileString
+ cwd
+ or ax, ax
+ jz sa_exit
+ xor dx,dx ; zero our value in dx:bx
+ xor bx,bx
+ push ss
+ pop ds
+ lea si, szHex
+
+ lodsw ; String starts with '0x'
+ and ah, not 20h
+ cmp ax, 'X0'
+ jnz sa_done
+sa_again:
+ lodsb
+ sub al, '0'
+ jc sa_done
+ cmp al, '9'-'0'
+ jbe @F
+ add al, '0'-'A'+10 ; map 'A'..F' to 10..15
+ ; (lower case guys are 0x20 apart!)
+@@:
+ add bx,bx ; value << 4;
+ adc dx,dx
+ add bx,bx
+ adc dx,dx
+ add bx,bx
+ adc dx,dx
+ add bx,bx
+ adc dx,dx
+
+ and al,0fh ; value |= (al & 0x0f);
+ or bl,al
+ jmps sa_again
+
+sa_done: ; DX:BX contains flags
+ mov ax, bx
+
+sa_exit: ; DX:AX contains flags, or 0x00000000
+cEnd
+
+
+cProc ValidateCodeSegments,<PUBLIC,FAR>
+cBegin nogen
+ ret
+cEnd nogen
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/module.asm b/private/mvdm/wow16/kernel31/module.asm
new file mode 100644
index 000000000..4173532b1
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/module.asm
@@ -0,0 +1,599 @@
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+.list
+
+;externFP GlobalCompact
+externFP GlobalFreeAll
+externFP greserve
+externFP GetExePtr
+externFP FarMyFree
+externFP Far_genter
+externFP FlushCachedFileHandle
+externFP GetProcAddress
+externFP FarUnlinkObject
+externFP CallWEP
+
+
+if SDEBUG
+externFP FarDebugDelModule
+endif
+
+DataBegin
+
+externB fBooting
+;externW EMScurPID
+externW curTDB
+externW loadTDB
+externW headTDB
+externW hExeHead
+externW pGlobalHeap
+externW MyCSDS
+externD pSignalProc
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+;-----------------------------------------------------------------------;
+; UnlinkObject ;
+; ;
+; Removes an object from a singly linked list of objects. ;
+; ;
+; Arguments: ;
+; CS:BX = head of chain ;
+; ES = object to delete ;
+; DX = offset of next pointer in object ;
+; ;
+; Returns: ;
+; AX = deleted object ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; BX,DI,SI,BP,DS ;
+; ;
+; Registers Destroyed: ;
+; CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon Sep 29, 1986 11:29:32a -by- Charles Whitmer [chuckwh] ;
+; Wrote it to remove this code from the three different places where ;
+; it was included inline. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc UnlinkObject,<PUBLIC,NEAR>
+cBegin nogen
+ push di
+ mov di,dx
+
+; keep DX = next object
+
+ mov dx,es:[di]
+
+; see if the object is at the head
+
+ push ds
+ SetKernelDS
+ mov cx,ds:[bx] ; start CX at head
+ mov ax,es ; AX = object to delete
+ cmp ax,cx
+ jnz not_at_head
+ mov ds:[bx],dx
+ pop ds
+ UnSetKernelDS
+ jmp short unlink_done
+not_at_head:
+ pop ds
+ UnSetKernelDS
+
+; run down the chain looking for the object
+
+unlink_loop:
+ jcxz unlink_done
+ mov es,cx
+ mov cx,es:[di]
+ cmp ax,cx
+ jnz unlink_loop
+ mov es:[di],dx
+unlink_done:
+ pop di
+ ret
+cEnd nogen
+
+
+sEnd CODE
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MapDStoDATA
+externNP DecExeUsage
+externNP FlushPatchAppCache
+IFNDEF NO_APPLOADER
+externNP ExitAppl
+ENDIF ;!NO_APPLOADER
+
+
+;-----------------------------------------------------------------------;
+; KillLibraries ;
+; ;
+; Scans the list of EXEs looking for Libraries. For all Libraries ;
+; it looks for a procedure called 'WEP'. If found, WEP is called with ;
+; fSystemExit set. ;
+; ;
+; Arguments: ;
+; None ;
+; ;
+; Returns: ;
+; None ;
+; ;
+; Error Returns: ;
+; none ;
+; ;
+; Registers Preserved: ;
+; DI,SI,BP,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; GetProcAddress ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc KillLibraries,<PUBLIC,FAR>,<DS>
+ localW hExe
+cBegin
+ SetKernelDSNRes
+ mov cx, hExeHead
+kl_NextExe:
+ UnSetKernelDS
+ mov ds, cx ; This skips first module (kernel)
+ mov cx, ds:[ne_pnextexe]
+ jcxz kl_done
+ push cx
+ cCall CallWEP, <cx, 1> ; Call for any module (call is fast)
+ pop cx
+ jmp kl_NextExe
+kl_done:
+cEnd
+
+;-----------------------------------------------------------------------;
+; AddModule ;
+; ;
+; Adds a module to the end of the list of modules. ;
+; ;
+; Arguments: ;
+; parmW hExe seg of module to add ;
+; ;
+; Returns: ;
+; AX != 0 if successful ;
+; ;
+; Error Returns: ;
+; AX == 0 if error detected ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; GlobalCompact ;
+; CalcMaxNRSeg ;
+; FarRedo_library_entries ;
+; ;
+; History: ;
+; Wed 24-Jul-1991 -by- Don Corbitt [donc] ;
+; Finish removal of Real mode code, dead code. Remove module from ;
+; list if insufficient memory. Directly set DS on entry. ;
+; ;
+; Thu 23-Mar-1989 23:00:40 -by- David N. Weise [davidw] ;
+; Made tasks and libraries be separate on the module chain. ;
+; ;
+; Thu Feb 25, 1988 08:00:00a -by- Tim Halvorsen [iris] ;
+; Check new error return from Redo_library_entries, returned when ;
+; we totally run out of space for another library's entry table ;
+; in EMS (the entry table is for ALL tasks, not just this task). ;
+; Fix comments above to reflect correct returns from this routine. ;
+; ;
+; Wed May 06, 1987 00:07:20a -by- David N. Weise [davidw] ;
+; Added support for EMS and library entrys. ;
+; ;
+; Thu Dec 11, 1986 12:10:26p -by- David N. Weise [davidw] ;
+; Added this nifty comment block, and made it set calculate and set ;
+; ne_swaparea. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc AddModule,<PUBLIC,NEAR>,<ds>
+ parmW hExe
+ localW hLast ; last module in current list
+cBegin
+ SetKernelDSNRes
+ xor bx,bx
+ mov cx,hExeHead
+
+am0: mov es,cx ; find end of linked list of exe's
+ mov cx,es:[bx].ne_pnextexe
+ or cx, cx
+ jnz am0
+
+; Here to add a module to the end of the chain. BX == 0.
+
+ mov hLast, es ; so we can remove hExe on failure
+ mov ax,hExe
+ mov es:[bx].ne_pnextexe,ax
+ mov es,ax
+ mov es:[bx].ne_pnextexe,bx
+
+; calculate and set the largest NR segment size
+
+ xor ax,ax ; No max yet.
+ mov cx,es:[bx].ne_cseg
+ mov bx,es:[bx].ne_segtab
+ jcxz no_NR_segments
+get_largest_loop:
+ test es:[bx].ns_flags,NSDATA ; Code segment?
+ jnz not_disc_code
+ errnz <NSCODE>
+ test es:[bx].ns_flags,NSDISCARD ; Discardable?
+ jz not_disc_code ; No, ignore.
+ mov dx,es:[bx].ns_minalloc ; Yes, get size
+ add dx,0Fh ; in paragraphs
+ jnc @F
+ mov dx, -1 ; overflow - was near 64K
+@@:
+ shr dx,4
+ cmp ax,dx ; Biggest NR Seg?
+ jae not_disc_code
+ mov ax,dx
+not_disc_code:
+ add bx,SIZE NEW_SEG1
+ loop get_largest_loop
+
+no_NR_segments: ; store largest segment if bigger
+ cmp ax,es:[ne_swaparea]
+ jbe leave_it_be
+ mov es:[ne_swaparea],ax
+leave_it_be:
+
+ xor bx,bx
+ cmp fBooting,bl
+ jne am_done
+ call far ptr CalcMaxNRSeg ; do we have room for this one?
+ or ax,ax
+ jnz am_done
+ mov es, hLast ; no, remove from module list
+ mov es:[ne_pnextexe],ax
+ jmp short am_exit ; note - ax == 0
+am_done:
+ mov ax,hExe
+am_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DelModule ;
+; ;
+; Deletes a module from the list of modules. ;
+; ;
+; Arguments: ;
+; parmW hExe seg of module to delete ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; FarUnlinkObject ;
+; GlobalFreeAll ;
+; CalcMaxNRSeg ;
+; EMSDelModule ;
+; ;
+; History: ;
+; ;
+; Wed May 06, 1987 00:07:20a -by- David N. Weise [davidw] ;
+; Added support for EMS and library entrys. ;
+; ;
+; Tue May 05, 1987 10:36:29p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DelModule,<PUBLIC,NEAR>,<ds,di>
+ parmW pExe
+cBegin
+ SetKernelDSNRes
+
+if SDEBUG
+ mov es, pExe
+ call FarDebugDelModule ; is ES preserved?
+endif
+
+ cCall CallWEP,<pExe,0>
+
+ mov es, pExe
+ test es:[ne_flags],NENOTP
+ jz dm_not_a_lib
+
+
+; call user to clean up any stuff
+ test es:[ne_flags],NEPROT ; OS/2 app? is this necessary???
+ jnz no_user_yet
+ cmp pSignalProc.sel,0
+ jz no_user_yet
+ xor ax,ax
+ mov bx,80h
+ mov es:[ne_usage],1
+ push es
+ cCall pSignalProc,<pExe,bx,ax,ax,ax>
+ pop es
+ mov es:[ne_usage],0
+no_user_yet:
+
+dm_not_a_lib:
+ ; Following code moved here
+ ; from FreeModule 1/18/89
+ mov es,pExe
+ mov bx,es:[ne_pautodata]
+ or bx,bx
+ jz fm00
+ cCall FarMyFree,<es:[bx].ns_handle> ; Free DS separately to free thunks
+fm00:
+IFNDEF NO_APPLOADER
+ mov es,pExe
+ test es:[ne_flags],NEAPPLOADER
+ jz normal_unload
+;* * special unload for AppLoader
+ cCall ExitAppl,<es>
+normal_unload:
+ENDIF ;!NO_APPLOADER ; END code from FreeModule
+ cCall FlushPatchAppCache, <pExe> ; Flush out Module Patch cache
+ cCall FlushCachedFileHandle,<pExe> ; Flush out of file handle cache
+ cCall Far_genter ; so we don't interfere with lrusweep
+ SetKernelDSNRes
+ mov es,pExe
+ mov dx,ne_pnextexe
+ mov bx,dataOffset hExeHead
+ call FarUnlinkObject
+ mov es,pGlobalHeap
+ xor di,di
+ dec es:[di].gi_lrulock
+
+ mov es,pExe ; Make sure no one mistakes this for
+ mov es:[di].ne_magic,di ; an exe header anymore.
+ cCall GlobalFreeAll,<pExe>
+ Call far ptr CalcMaxNRSeg
+ xor ax,ax
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FreeModule ;
+; ;
+; Deletes the given module from the system. First it decs the usage ;
+; count checking to see if this is the last instance, ( this may ;
+; indirectly free other modules). If this is the last instance then ;
+; it frees the automatic data segment to free any thunks associated ;
+; with this module. Then the module is deleted. If this was not the ;
+; last instance then the ns_handle for the automatic data seg may have ;
+; to be updated. ;
+; ;
+; Arguments: ;
+; parmW hInstance ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 03-Apr-1989 22:22:01 -by- David N. Weise [davidw] ;
+; Removed the GlobalCompact at the end of this routine. ;
+; ;
+; Fri Jul 10, 1987 11:54:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+labelFP <PUBLIC, IFreeLibrary>
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IFreeModule,<PUBLIC,FAR>,<si,di>
+ parmW hInstance
+cBegin
+ cCall GetExePtr,<hInstance> ; Get exe header address
+ or ax,ax
+ jz fmexit1
+ mov si,ax
+ cCall DecExeUsage,<si> ; Decrement usage count
+ jnz fmfree ; If non-zero, then just free inst.
+ifdef WOW
+ ; Word Perfect v5.2 needs DX to contain a number >= 0x17 inorder
+ ; to print properly. Since on Win 3.1, the DX value came from
+ ; this point, lets save it for them. (On Win 3,1, the printer
+ ; driver was being free'd here, but not deleted, GDI or spooler
+ ; still has it open).
+ push dx
+endif
+ cCall DelModule,<si> ; If zero, free entire module
+ifdef WOW
+ pop dx
+endif
+
+fmexit1:
+ jmps fmexit
+fmfree:
+ mov es,si
+ test byte ptr es:[ne_flags],NEINST
+ jz fmexit ; All done if not a multiple inst
+ mov bx,es:[ne_pautodata]
+ push es:[bx].ns_handle
+ cCall FarMyFree,<hInstance> ; Free instance
+ pop dx
+ cmp dx,hInstance ; Did we free current instance?
+ jne fmexit ; No, then continue
+
+ cCall MapDStoDATA
+ ReSetKernelDS
+ xor ax,ax
+ xor bx,bx
+ mov cx,headTDB ; Yes, search TDBs looking for
+ UnSetKernelDS
+fm0: jcxz fm1 ; another instance handle
+ mov es,cx
+ cmp si,es:[bx].TDB_pModule
+ mov cx,es:[bx].TDB_next
+ jnz fm0
+
+ mov ax,es:[bx].TDB_module
+ cmp ax,hInstance ; Is this the instance we're quitting?
+ jz fm0
+
+fm1: mov es,si
+ mov bx,es:[bx].ne_pautodata
+ mov es:[bx].ns_handle,ax ; Remember handle of data seg
+fmexit:
+
+cEnd
+
+sEnd NRESCODE
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+externNP MISCMapDStoDATA
+
+;-----------------------------------------------------------------------;
+; CalcMaxNRSeg ;
+; ;
+; Checks all of the EXE headers in the system to get the size of the ;
+; largest non-resident code segment and sets the size of the ;
+; discardable code reserve area. If the new size is larger than the ;
+; old size, it checks to see if there is enough room to support the ;
+; new size. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; CX = the largest greserve we can get ;
+; AX != 0 success ;
+; AX = 0 failure ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,DX,ES ;
+; ;
+; Calls: ;
+; greserve ;
+; ;
+; History: ;
+; ;
+; Thu Oct 08, 1987 07:53:30p -by- David N. Weise [davidw] ;
+; Made the fix for multiple apps in the same EMS bank. ;
+; ;
+; Sat Jul 11, 1987 01:42:42p -by- David N. Weise [davidw] ;
+; Added EMS support. ;
+; ;
+; Thu Dec 11, 1986 11:14:05a -by- David N. Weise [davidw] ;
+; Rewrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CalcMaxNRSeg,<PUBLIC,FAR>, <ds>
+cBegin
+ SetKernelDSMISC
+ xor ax,ax ; No max yet.
+ cmp fBooting,al
+ jnz not_while_booting
+
+ mov cx,hExeHead
+get_largest_NR_segment:
+ jcxz no_more_EXEs
+ mov es,cx
+ NE_check_ES
+ test es:[ne_flags],NENOTP ; Library module?
+ jz lib_still_largest ; Yes, include its segments.
+ mov bx,es:[ne_swaparea]
+ cmp ax,bx
+ jae lib_still_largest
+ mov ax,bx
+lib_still_largest:
+ mov cx,es:[ne_pnextexe]
+ jmp get_largest_NR_segment
+no_more_EXEs:
+
+ mov cx,headTDB
+get_task_largest:
+ jcxz no_more_tasks
+ mov es,cx
+ TDB_check_ES
+ mov cx,es:[TDB_next]
+ lsl bx, es:[TDB_pModule]
+ jnz get_task_largest
+ mov es,es:[TDB_pModule]
+ cmp es:[ne_magic],NEMAGIC
+ jnz get_task_largest ; dead task or boot time
+ mov bx,es:[ne_swaparea]
+ cmp ax,bx
+ jae get_task_largest
+ mov ax,bx
+ jmp get_task_largest
+
+no_more_tasks:
+ call greserve
+
+not_while_booting:
+cEnd
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/newexe.doc b/private/mvdm/wow16/kernel31/newexe.doc
new file mode 100644
index 000000000..9b09d6428
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/newexe.doc
@@ -0,0 +1,391 @@
+ New Executable Format
+
+DOS 2.0 Windows will define a new executable format for .EXE files
+that is a superset of the current DOS 2.0 .EXE format. The purpose
+of this new format is to provide the additional information needed
+to support the new dynamic linking and segmentation facilities provided
+by DOS 2.0 Windows and DOS 4.0. In order for Windows and DOS 4.0
+to recognize the new executable format, the existing .EXE format
+will be used with a slight modification:
+
+ - the word at offset 18h in the existing .EXE file contains the
+ relative byte offset to the relocation table. If this offset
+ is 40h, then that identifies this as a new format .EXE file and
+ The word at offset 24h is the relative byte offset from the
+ beginning of the file to the beginning of the new format
+ executable header. The remainder of the old format header will
+ describe a small program that will either print an error message
+ or bring in a loader that can handle the job. See the picture
+ below for the actual file layout.
+
+ - this format will only be used for .EXE files that use the new
+ memory model supported by DOS 2.0 Windows and DOS 4.0. Old .EXE
+ files will continue with the DOS 2.0 file format, as modified
+ by the DOS 4.0 group. In that format, the DOS 4.0 behavior bits
+ (2 bytes) are stored at offset 20h.
+
+The format of the new .EXE file format looks like:
+
+ 00h -------------------
+ | |
+ | Old EXE Header |
+ | |
+ -------------------
+ 20h | DOS 4.0 bbits |
+ 22h | unused bbits |
+ 3eh | offset to new | ----
+ | EXE header | |
+ 40h ------------------- |
+ | DOS 2.0 Stub | |
+ | Program & | |
+ | Reloc. Table | |
+ xxh ------------------- <---
+ | |
+ | New EXE Header |\
+ | | \
+ ------------------- \
+ | | |
+ | Segment Table | |
+ | | |
+ ------------------- |
+ | Resource | | DOS4 and Windows keep this
+ | Table | |-----------part as part of their
+ ------------------- | MODULE table, currently
+ | Resident | |
+ | Name | |
+ | Table | |
+ ------------------- /
+ | Module Ref | /
+ | Table |/
+ -------------------
+ | Imported |
+ | Names |
+ | Table |
+ -------------------
+* | Entry |
+* | Table |
+ -------------------
+ | Non-Resident |
+ | Name |
+ | Table |
+ -------------------
+ | Seg #1 Data |
+ | Seg #1 Info |
+ -------------------
+ .
+ .
+ .
+ -------------------
+ | Seg #n Data |
+ | Seg #n Info |
+ -------------------
+
+ 20h - DW DOS 4.0 behavior bits
+* 22h - 3ch - reserved for more behavior info
+* 3eh - DW offset to new executable header
+
+ Program that DOS 2.0 header points to, that will either print out an
+ error message or load in a new-EXE loader.
+
+ xxh - Beginning of new executable header
+ DW signature word - can never be too careful
+ "N" is low order byte
+ "E" is high order byte
+ DB version# of LINK that produced this executable
+ DB revision# of LINK that produced this executable
+
+ DW Entry Table file offset relative to beginning of new EXE header
+ DW #bytes in Entry Table
+
+ DD CRC-32 of entire contents of file (with these words taken
+ as 00 during the calculation)
+
+ DW flag word
+ 0000h = NOAUTODATA
+ 0001h = SINGLEDATA (SOLO)
+ 0002h = MULTIPLEDATA (INSTANCE)
+ 0004h = runs in real mode
+ 0008h = runs in protected mode (if 0Ch set, runs in either)
+ 4000h = non-conforming program (a valid stack is not maintained)
+ 8000h = Library module (SS:SP info is invalid, CS:IP points
+ to initialization procedure that is called with AX
+ = the module handle. The procedure must execute a
+ far return to the caller, with AX != 0 to indicate
+ success and AX = 0 to indicate failure to
+ initialize. DS = the library's data segment if the
+ SINGLEDATA flag is set and the caller's DS
+ otherwise.
+
+ A program can only contain dynamic links to
+ executables that have this flag set. If this flag
+ is set, the MULTIPLEDATA flag must be reset. The
+ SINGLEDATA flag may be set or reset.
+
+ DW segment# of automatic data segment (index into segment table)
+ set to zero if SINGLEDATA and MULTIPLEDATA flag bits are reset
+
+ DW initial size (bytes) of dynamic heap added to data segment
+ (0 if no local alloc)
+ DW initial size (bytes) of stack added to data segment
+ (0 if SS!=DS)
+ DD segment#:offset of CS:IP
+ DD segment#:offset of SS:SP
+ Segment# is an index into the module's segment table.
+ The first entry in the segment table is segment number 1.
+ If SS = automatic data segment and SP = 0,
+ the stack pointer is set to the top of the automatic
+ data segment just below the additional heap area.
+
+ +-------------------------+
+ | additional dynamic heap |
+ +-------------------------+ <- SP
+ | additional stack |
+ +-------------------------+
+ | loaded data segment |
+ +-------------------------+ <- DS, SS
+
+ DW #of entries in Segment Table
+ DW #of entries in Module Ref Table
+ DW #bytes in Non-Resident Name Table
+
+ DW Segment Table file offset relative to beginning of new EXE header
+ DW Resource Table file offset relative to beginning of new EXE header
+ DW Resident Name Table file offset relative to beginning of new EXE header
+ DW Module Ref Table file offset relative to beginning of new EXE header
+ DW Imported Names Table file offset relative to beginning of new EXE header
+ DD Non-Resident Name Table offset relative to beginning of file
+
+* DW #moveable entry points
+* DW alignment shift count for segment data. Value of zero means
+* use the default value of 9 for 512 byte alignment.
+* DB 12 DUP (?) - room for growth here
+
+ Segment Table
+ =============
+
+ "N" segment table entries:
+
+ The first entry in the segment table is segment number 1.
+* DW logical sector offset to contents of the segment data
+* relative to beginning of file (zero means no file data)
+* The alignment field in the header determines the units
+* of this offset.
+ DW length of segment in file (bytes) (zero means 64k bytes)
+ DW flag word
+ TYPE_MASK = 0007h ; segment type field
+ CODE = 0000h ; code segment type
+ DATA = 0001h ; data segment type
+ ITERATED = 0008h ; segment data is iterated
+ MOVABLE = 0010h ; segment is not fixed
+ PURE = 0020h ; segment can be shared
+ PRELOAD = 0040h ; segment is not demand loaded
+ ERONLY = 0080h ; execute only if code segment
+ ; read only if data segment
+ RELOCINFO = 0100h ; set if segment has reloc records
+ DEBUGINFO = 0200h ; set if segment has debug info
+ SEGDPL = 0C00h ; reserved for 286 DPL bits
+ DISCARDABLE = F000h ; static discard priority level
+ DW minimum allocation size (bytes)
+ Total size of the segment (0 means 65536)
+
+ Resource Table
+ ==============
+
+ DW alignment shift count for resource data
+
+ "N" iterations of record:
+ | DW type ID - integer type if high order bit is set (8000h)
+ | otherwise offset to type string, relative to
+ | beginning of the resource table
+ | = 0 marks end of resource records
+ |
+ | DW #resources for this type
+ | DD reserved for runtime use
+ | |
+ | | "#resources" copies of Resource Entry (8 bytes)
+ | |
+ | | DW file offset to contents of the resource data relative
+ | | to beginning of file. Offset is in terms of alignment
+ | | units specified at beginning of resource table.
+ | | DW length of resource in file (bytes)
+ | | DW flag word
+ | | MOVEABLE = 0010h ; resource is not fixed
+ | | PURE = 0020h ; resource can be shared
+ | | PRELOAD = 0040h ; resource is not demand loaded
+ | | DW resource ID - integer type if high order bit is set (8000h)
+ | | otherwise offset to resource string, relative to beginning
+ | | of the resource table
+ | | DD reserved for runtime use
+ \ \
+
+ Resource type and name strings stored at end of resource table
+ Note that these strings are NOT null terminated
+
+ DB length of type or name ; = 0 if end of resource table
+ DB ASCII text of type or name ; Case sensitive
+
+
+
+ Module Reference Table
+ ======================
+
+ "N" entries of the form: (1-based)
+
+ DW offset within Imported Names Table to module name string
+
+
+
+ Entry Table (1 based)
+ ===========
+
+ "N" bundles of entry definitions. The ordinal value of an entry
+ | point is its ordinal within the entry table, counting the
+ | first entry as ordinal #1. The loader must scan over the
+ | bundles until it finds the bundle containing the entry point;
+ | the loader can then multiply by entry size to index the
+ | proper entry.
+ |
+ | The linker forms bundles in the densest manner it can, given
+ | the restriction that it cannot reorder entry points to improve
+ | bundling because other EXE files may refer to entry points within
+ | this one by their ordinal in this table.
+ |
+ | DB #entries in this bundle. All records in one bundle are
+ | either movabe or refer to the same fixed segment.
+ | =0 if no more bundles in Entry Table
+ |
+ | DB segment indicator for this bundle
+ | | 000 - Unused
+ | | 0FF - Movable segment, # is in entry
+ | | otherwise is segment # of fixed segment
+ | |
+ | | If fixed segment, entries are 3 bytes:
+ | | DB flags
+ | | 0000 0001 - set if entry is exported
+ | | 0000 0010 - set if entry uses global (shared) data segment
+ | | "mov ax,#ds-value" must be the 1st
+ | | instruction in the prolog of this
+ | | entry. This flag may only be set
+ | | for SINGLEDATA library modules.
+ | | nnnn n--- - # of parameter words
+ | | DW offset
+ | | Else movable segment, entries are 6 bytes:
+ | | DB flags
+ | | 0000 0001 - set if entry is exported
+ | | 0000 0010 - set if segment uses global (shared) data segment
+ | | nnnn n--- - # of parameter words
+ | | int 3Fh
+ | | DB segment#
+ \ \ DW offset
+
+
+
+ Resident or Non-resident Name Table Entry (3 + n bytes)
+ =========================================
+
+ The strings are CASE SENSITIVE and NOT NULL TERMINATED. If the
+* .EXE was produced with the /IGNORECASE switch, then all strings
+* will be UPPERCASE
+
+ DB Length of string ; =0 if no more strings in table
+ DB ASCII text of string
+ DW ordinal# (index into entry table)
+
+ First string in resident name table is the module name.
+
+ First string in non-resident name table is the module description.
+
+
+ Imported Names Table Entry (1 + n bytes)
+ ==========================
+
+ The strings are CASE SENSITIVE and NOT NULL TERMINATED. If the
+* .EXE was produced with the /IGNORECASE switch, then all strings
+* will be UPPERCASE
+
+ DB Length of name ; =0 if no more strings in Table
+ DB ASCII text of name
+
+
+
+ Per segment data:
+ ================
+
+ If ITERATED
+ DW #iterations
+ DW #bytes of data
+ DB data bytes
+ else
+ DB data bytes
+
+
+ If RELOCINFO
+ DW #relocation items
+ |
+ | Relocation Item: (8 bytes)
+ |
+ | DB source type (32 bit address, 16 bit segment, 16 bit offset)
+ | NRSTYP = 07h ; source type mask
+ | NRSBYTE = 00h
+ | NRSSEG = 02h ; 16-bit segment
+ | NRSPTR = 03h ; 32-bit pointer
+ | NRSOFF = 05h ; 16-bit offset
+ | DB flags
+ | TARGET_MASK = 03h
+ | INTERNALREF = 00h
+ | IMPORTORDINAL = 01h
+ | IMPORTNAME = 02h
+ | ADDITIVE = 04h
+ | DW offset within this segment of source chain
+ | If ADDITIVE flag set, then add target value to source contents,
+ | instead of replacing source and following the chain.
+ | The source chain is a 0xFFFF terminated linked list within
+ | this segment of all references to the target.
+ | Target
+ | INTERNALREF
+ | DB segment# for fixed segment or FF if movable
+ | DB 0
+ | DW if moveable segment
+* | ordinal# (index into entry table of this module)
+ | if fixed segment
+ | offset into segment if fixed
+ |
+ | IMPORTNAME
+ | DW index into module ref table
+ | DW offset within Imported Names Table to proc. name string
+ |
+ | IMPORTORDINAL
+ | DW index into module ref table
+ | DW procedure ordinal#
+ |
+ | OSFIXUP
+ | DW Operating system fixup type
+ |
+ | floating-point fixups
+ | 0001h = FIARQQ, FJARQQ
+ | 0002h = FISRQQ, FJSRQQ
+ | 0003h = FICRQQ, FJCRQQ
+ | 0004h = FIERQQ
+ | 0005h = FIDRQQ
+ | 0006h = FIWRQQ
+ | applied by adding the fixup to the coprocessor instr.
+ | for 1-3, apply the first fixup at the offset, and
+ | the second fixup at the offset+1. for 4-6, just add
+ | the fixup at the offset.
+ |
+ | NOTE: the linker marks these relocations as NRSOFF, but
+ | they must be applied differently. in ldreloc.asm, we
+ | use a flag to discern this case.
+ |
+ \ DW 0
+
+
+ If DEBUGINFO
+ DW # of bytes of debug info
+ <debug info - not yet defined>
+
+
+
+
+
+NOTE: this document does not totally agree with version 1.7, dated 5/05/87.
diff --git a/private/mvdm/wow16/kernel31/newexe.h b/private/mvdm/wow16/kernel31/newexe.h
new file mode 100644
index 000000000..653fac7cf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/newexe.h
@@ -0,0 +1,380 @@
+/*static char *SCCSID = "@(#)newexe.h:2.9";*/
+/*
+ * Title
+ *
+ * newexe.h
+ * Pete Stewart
+ * (C) Copyright Microsoft Corp 1984
+ * 17 August 1984
+ *
+ * Description
+ *
+ * Data structure definitions for the DOS 4.0/Windows 2.0
+ * executable file format.
+ *
+ * Modification History
+ *
+ * 84/08/17 Pete Stewart Initial version
+ * 84/10/17 Pete Stewart Changed some constants to match OMF
+ * 84/10/23 Pete Stewart Updates to match .EXE format revision
+ * 84/11/20 Pete Stewart Substantial .EXE format revision
+ * 85/01/09 Pete Stewart Added constants ENEWEXE and ENEWHDR
+ * 85/01/10 Steve Wood Added resource definitions
+ * 85/03/04 Vic Heller Reconciled Windows and DOS 4.0 versions
+ * 85/03/07 Pete Stewart Added movable entry count
+ * 85/04/01 Pete Stewart Segment alignment field, error bit
+ */
+
+#define EMAGIC 0x5A4D /* Old magic number */
+#define ENEWEXE sizeof(struct exe_hdr)
+ /* Value of E_LFARLC for new .EXEs */
+#define ENEWHDR 0x003C /* Offset in old hdr. of ptr. to new */
+#define ERESWDS 0x0010 /* No. of reserved words in header */
+#define ECP 0x0004 /* Offset in struct of E_CP */
+#define ECBLP 0x0002 /* Offset in struct of E_CBLP */
+#define EMINALLOC 0x000A /* Offset in struct of E_MINALLOC */
+
+struct exe_hdr /* DOS 1, 2, 3 .EXE header */
+ {
+ unsigned short e_magic; /* Magic number */
+ unsigned short e_cblp; /* Bytes on last page of file */
+ unsigned short e_cp; /* Pages in file */
+ unsigned short e_crlc; /* Relocations */
+ unsigned short e_cparhdr; /* Size of header in paragraphs */
+ unsigned short e_minalloc; /* Minimum extra paragraphs needed */
+ unsigned short e_maxalloc; /* Maximum extra paragraphs needed */
+ unsigned short e_ss; /* Initial (relative) SS value */
+ unsigned short e_sp; /* Initial SP value */
+ unsigned short e_csum; /* Checksum */
+ unsigned short e_ip; /* Initial IP value */
+ unsigned short e_cs; /* Initial (relative) CS value */
+ unsigned short e_lfarlc; /* File address of relocation table */
+ unsigned short e_ovno; /* Overlay number */
+ unsigned short e_res[ERESWDS]; /* Reserved words */
+ long e_lfanew; /* File address of new exe header */
+ };
+
+#define E_MAGIC(x) (x).e_magic
+#define E_CBLP(x) (x).e_cblp
+#define E_CP(x) (x).e_cp
+#define E_CRLC(x) (x).e_crlc
+#define E_CPARHDR(x) (x).e_cparhdr
+#define E_MINALLOC(x) (x).e_minalloc
+#define E_MAXALLOC(x) (x).e_maxalloc
+#define E_SS(x) (x).e_ss
+#define E_SP(x) (x).e_sp
+#define E_CSUM(x) (x).e_csum
+#define E_IP(x) (x).e_ip
+#define E_CS(x) (x).e_cs
+#define E_LFARLC(x) (x).e_lfarlc
+#define E_OVNO(x) (x).e_ovno
+#define E_RES(x) (x).e_res
+#define E_LFANEW(x) (x).e_lfanew
+
+#define NEMAGIC 0x454E /* New magic number */
+#define NERESBYTES 0
+
+struct new_exe /* New .EXE header */
+ {
+ unsigned short int ne_magic; /* Magic number NE_MAGIC */
+ char ne_ver; /* Version number */
+ char ne_rev; /* Revision number */
+ unsigned short int ne_enttab; /* Offset of Entry Table */
+ unsigned short int ne_cbenttab; /* Number of bytes in Entry Table */
+ long ne_crc; /* Checksum of whole file */
+ unsigned short int ne_flags; /* Flag word */
+ unsigned short int ne_autodata; /* Automatic data segment number */
+ unsigned short int ne_heap; /* Initial heap allocation */
+ unsigned short int ne_stack; /* Initial stack allocation */
+ long ne_csip; /* Initial CS:IP setting */
+ long ne_sssp; /* Initial SS:SP setting */
+ unsigned short int ne_cseg; /* Count of file segments */
+ unsigned short int ne_cmod; /* Entries in Module Reference Table */
+ unsigned short int ne_cbnrestab; /* Size of non-resident name table */
+ unsigned short int ne_segtab; /* Offset of Segment Table */
+ unsigned short int ne_rsrctab; /* Offset of Resource Table */
+ unsigned short int ne_restab; /* Offset of resident name table */
+ unsigned short int ne_modtab; /* Offset of Module Reference Table */
+ unsigned short int ne_imptab; /* Offset of Imported Names Table */
+ long ne_nrestab; /* Offset of Non-resident Names Table */
+ unsigned short int ne_cmovent; /* Count of movable entries */
+ unsigned short int ne_align; /* Segment alignment shift count */
+ unsigned short int ne_cres; /* Count of resource segments */
+
+#ifdef NEVER
+ unsigned short int ne_psegcsum; /* offset to segment chksums */
+#else
+ unsigned char ne_exetyp; /* Target Operating system */
+ unsigned char ne_flagsothers; /* Other .EXE flags */
+#endif
+ unsigned short int ne_pretthunks; /* offset to return thunks */
+ unsigned short int ne_psegrefbytes;/* offset to segment ref. bytes */
+ unsigned short int ne_swaparea; /* Minimum code swap area size */
+ unsigned short int ne_expver; /* Expected Windows version number */
+ };
+
+#define NE_MAGIC(x) (x).ne_magic
+#define NE_VER(x) (x).ne_ver
+#define NE_REV(x) (x).ne_rev
+#define NE_ENTTAB(x) (x).ne_enttab
+#define NE_CBENTTAB(x) (x).ne_cbenttab
+#define NE_CRC(x) (x).ne_crc
+#define NE_FLAGS(x) (x).ne_flags
+#define NE_AUTODATA(x) (x).ne_autodata
+#define NE_HEAP(x) (x).ne_heap
+#define NE_STACK(x) (x).ne_stack
+#define NE_CSIP(x) (x).ne_csip
+#define NE_SSSP(x) (x).ne_sssp
+#define NE_CSEG(x) (x).ne_cseg
+#define NE_CMOD(x) (x).ne_cmod
+#define NE_CBNRESTAB(x) (x).ne_cbnrestab
+#define NE_SEGTAB(x) (x).ne_segtab
+#define NE_RSRCTAB(x) (x).ne_rsrctab
+#define NE_RESTAB(x) (x).ne_restab
+#define NE_MODTAB(x) (x).ne_modtab
+#define NE_IMPTAB(x) (x).ne_imptab
+#define NE_NRESTAB(x) (x).ne_nrestab
+#define NE_CMOVENT(x) (x).ne_cmovent
+#define NE_ALIGN(x) (x).ne_align
+#define NE_RES(x) (x).ne_res
+#define NE_EXETYPE(x) (x).ne_exetyp
+
+#define NE_USAGE(x) (WORD)*((WORD FAR *)(x)+1)
+#define NE_PNEXTEXE(x) (WORD)(x).ne_cbenttab
+#define NE_PAUTODATA(x) (WORD)(x).ne_crc
+#define NE_PFILEINFO(x) (WORD)((DWORD)(x).ne_crc >> 16)
+
+#ifdef DOS5
+#define NE_MTE(x) (x).ne_psegcsum /* DOS 5 MTE handle for this module */
+#endif
+
+
+/*
+ * Format of NE_FLAGS(x):
+ *
+ * p Not-a-process
+ * c Non-conforming
+ * e Errors in image
+ * xxxxxxxxx Unused
+ * P Runs in protected mode
+ * r Runs in real mode
+ * i Instance data
+ * s Solo data
+ */
+#define NENOTP 0x8000 /* Not a process */
+#define NENONC 0x4000 /* Non-conforming program */
+#define NEIERR 0x2000 /* Errors in image */
+#define NEPROT 0x0008 /* Runs in protected mode */
+#define NEREAL 0x0004 /* Runs in real mode */
+#define NEINST 0x0002 /* Instance data */
+#define NESOLO 0x0001 /* Solo data */
+
+struct new_seg /* New .EXE segment table entry */
+ {
+ unsigned short ns_sector; /* File sector of start of segment */
+ unsigned short ns_cbseg; /* Number of bytes in file */
+ unsigned short ns_flags; /* Attribute flags */
+ unsigned short ns_minalloc; /* Minimum allocation in bytes */
+ };
+
+struct new_seg1 /* New .EXE segment table entry */
+ {
+ unsigned short ns_sector; /* File sector of start of segment */
+ unsigned short ns_cbseg; /* Number of bytes in file */
+ unsigned short ns_flags; /* Attribute flags */
+ unsigned short ns_minalloc; /* Minimum allocation in bytes */
+ unsigned short ns_handle; /* Handle of segment */
+ };
+
+#define NS_SECTOR(x) (x).ns_sector
+#define NS_CBSEG(x) (x).ns_cbseg
+#define NS_FLAGS(x) (x).ns_flags
+#define NS_MINALLOC(x) (x).ns_minalloc
+
+/*
+ * Format of NS_FLAGS(x):
+ *
+ * xxxx Unused
+ * DD 286 DPL bits
+ * d Segment has debug info
+ * r Segment has relocations
+ * e Execute/read only
+ * p Preload segment
+ * P Pure segment
+ * m Movable segment
+ * i Iterated segment
+ * ttt Segment type
+ */
+#define NSTYPE 0x0007 /* Segment type mask */
+#define NSCODE 0x0000 /* Code segment */
+#define NSDATA 0x0001 /* Data segment */
+#define NSITER 0x0008 /* Iterated segment flag */
+#define NSMOVE 0x0010 /* Movable segment flag */
+#define NSPURE 0x0020 /* Pure segment flag */
+#define NSPRELOAD 0x0040 /* Preload segment flag */
+#define NSEXRD 0x0080 /* Execute-only (code segment), or
+ * read-only (data segment)
+ */
+#define NSRELOC 0x0100 /* Segment has relocations */
+#define NSDEBUG 0x0200 /* Segment has debug info */
+#define NSDPL 0x0C00 /* 286 DPL bits */
+#define NSDISCARD 0x1000 /* Discard bit for segment */
+
+#define NSALIGN 9 /* Segment data aligned on 512 byte boundaries */
+
+struct new_segdata /* Segment data */
+ {
+ union
+ {
+ struct
+ {
+ unsigned short ns_niter; /* number of iterations */
+ unsigned short ns_nbytes; /* number of bytes */
+ char ns_iterdata; /* iterated data bytes */
+ } ns_iter;
+ struct
+ {
+ char ns_data; /* data bytes */
+ } ns_noniter;
+ } ns_union;
+ };
+
+struct new_rlcinfo /* Relocation info */
+ {
+ unsigned short nr_nreloc; /* number of relocation items that */
+ }; /* follow */
+
+struct new_rlc /* Relocation item */
+ {
+ char nr_stype; /* Source type */
+ char nr_flags; /* Flag byte */
+ unsigned short nr_soff; /* Source offset */
+ union
+ {
+ struct
+ {
+ char nr_segno; /* Target segment number */
+ char nr_res; /* Reserved */
+ unsigned short nr_entry; /* Target Entry Table offset */
+ } nr_intref; /* Internal reference */
+ struct
+ {
+ unsigned short nr_mod; /* Index into Module Reference Table */
+ unsigned short nr_proc; /* Procedure ordinal or name offset */
+ } nr_import; /* Import */
+ } nr_union; /* Union */
+ };
+
+#define NR_STYPE(x) (x).nr_stype
+#define NR_FLAGS(x) (x).nr_flags
+#define NR_SOFF(x) (x).nr_soff
+#define NR_SEGNO(x) (x).nr_union.nr_intref.nr_segno
+#define NR_RES(x) (x).nr_union.nr_intref.nr_res
+#define NR_ENTRY(x) (x).nr_union.nr_intref.nr_entry
+#define NR_MOD(x) (x).nr_union.nr_import.nr_mod
+#define NR_PROC(x) (x).nr_union.nr_import.nr_proc
+
+/*
+ * Format of NR_STYPE(x):
+ *
+ * xxxxx Unused
+ * sss Source type
+ */
+#define NRSTYP 0x07 /* Source type mask */
+#define NRSSEG 0x02 /* 16-bit segment */
+#define NRSPTR 0x03 /* 32-bit pointer */
+#define NRSOFF 0x05 /* 16-bit offset */
+
+/*
+ * Format of NR_FLAGS(x):
+ *
+ * xxxxx Unused
+ * a Additive fixup
+ * rr Reference type
+ */
+#define NRADD 0x04 /* Additive fixup */
+#define NRRTYP 0x03 /* Reference type mask */
+#define NRRINT 0x00 /* Internal reference */
+#define NRRORD 0x01 /* Import by ordinal */
+#define NRRNAM 0x02 /* Import by name */
+#define OSFIXUP 0x03 /* Floating point fixup */
+
+
+/* Resource type or name string */
+struct rsrc_string
+ {
+ char rs_len; /* number of bytes in string */
+ char rs_string[ 1 ]; /* text of string */
+ };
+
+#define RS_LEN( x ) (x).rs_len
+#define RS_STRING( x ) (x).rs_string
+
+/* Resource type information block */
+struct rsrc_typeinfo
+ {
+ unsigned short rt_id;
+ unsigned short rt_nres;
+ long rt_proc;
+ };
+
+#define RT_ID( x ) (x).rt_id
+#define RT_NRES( x ) (x).rt_nres
+#define RT_PROC( x ) (x).rt_proc
+
+/* Resource name information block */
+struct rsrc_nameinfo
+ {
+ /* The following two fields must be shifted left by the value of */
+ /* the rs_align field to compute their actual value. This allows */
+ /* resources to be larger than 64k, but they do not need to be */
+ /* aligned on 512 byte boundaries, the way segments are */
+ unsigned short rn_offset; /* file offset to resource data */
+ unsigned short rn_length; /* length of resource data */
+ unsigned short rn_flags; /* resource flags */
+ unsigned short rn_id; /* resource name id */
+ unsigned short rn_handle; /* If loaded, then global handle */
+ unsigned short rn_usage; /* Initially zero. Number of times */
+ /* the handle for this resource has */
+ /* been given out */
+ };
+
+#define RN_OFFSET( x ) (x).rn_offset
+#define RN_LENGTH( x ) (x).rn_length
+#define RN_FLAGS( x ) (x).rn_flags
+#define RN_ID( x ) (x).rn_id
+#define RN_HANDLE( x ) (x).rn_handle
+#define RN_USAGE( x ) (x).rn_usage
+
+#define RSORDID 0x8000 /* if high bit of ID set then integer id */
+ /* otherwise ID is offset of string from
+ the beginning of the resource table */
+
+ /* Ideally these are the same as the */
+ /* corresponding segment flags */
+#define RNMOVE 0x0010 /* Moveable resource */
+#define RNPURE 0x0020 /* Pure (read-only) resource */
+#define RNPRELOAD 0x0040 /* Preloaded resource */
+#define RNDISCARD 0x1000 /* Discard bit for resource */
+
+#define RNLOADED 0x0004 /* True if handler proc return handle */
+
+#define RNCOMPR 0x0200 /* Resource is compressed in ROM */
+
+/* Resource table */
+struct new_rsrc
+ {
+ unsigned short rs_align; /* alignment shift count for resources */
+ struct rsrc_typeinfo rs_typeinfo;
+ };
+
+#define RS_ALIGN( x ) (x).rs_align
+
+/* Target operating systems: Possible values of ne_exetyp field */
+
+#define NE_UNKNOWN 0 /* Unknown (any "new-format" OS) */
+#define NE_OS2 1 /* Microsoft/IBM OS/2 (default) */
+#define NE_WINDOWS 2 /* Microsoft Windows */
+#define NE_DOS4 3 /* Microsoft MS-DOS 4.x */
+#define NE_DEV386 4 /* Microsoft Windows 386 */
+
diff --git a/private/mvdm/wow16/kernel31/patch.asm b/private/mvdm/wow16/kernel31/patch.asm
new file mode 100644
index 000000000..93da98df0
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/patch.asm
@@ -0,0 +1,1502 @@
+.xlist
+include kernel.inc
+include gpfix.inc
+include pdb.inc
+include tdb.inc
+include newexe.inc
+include protect.inc
+.list
+
+.386
+
+ERROR_NO_MORE_ITEMS EQU 259
+
+;-----------------------------------------------------------------------
+;-----------------------------------------------------------------------
+; App patching defines
+
+
+externFP RegCloseKey32
+externFP RegOpenKey32
+externFP RegEnumKey32
+externFP RegEnumValue32
+
+externFP FarGetCachedFileHandle
+externFP GlobalRealloc
+externFP GlobalSize
+externFP Far_genter
+externFP Far_gleave
+externFP Far_htoa0
+externFP Far_pdref
+externFP FreeSelector
+
+; MultiThreading version of change PDB
+;externFP GetCurPDB
+;externFP SetCurPDB
+;externFP TopPDB
+; MultiThreading version of change PDB
+
+externW topPDB
+externW Win_PDB
+externW gdtdsc
+
+REG_BINARY equ 3
+
+HKEY_LOCAL_MACHINE equ 80000002h
+HKEY_LOCAL_MACHINE_HI equ 8000h
+HKEY_LOCAL_MACHINE_LO equ 0002h
+
+; Under HKEY_LOCAL_MACHINE
+REGSTR_PATH_APPPATCH equ <"System\CurrentControlSet\Control\Session Manager\AppPatches">
+; There is one value for each modification to a given segment.
+; The values for a segment are stored under the key
+; REGSTR_PATH_APPPATCH\<AppName>\<AppVersion>\<signature>
+; where <signature> lists bytes in the module to match.
+
+
+BY_HANDLE_FILE_INFORMATION STRUC
+bhfi_dwFileAttributes DD ?
+bhfi_ftCreationTime DD 2 dup (?)
+bhfi_ftLastAccessTime DD 2 dup (?)
+bhfi_ftLastWriteTime DD 2 dup (?)
+bhfi_dwVolumeSerialNumber DD ?
+bhfi_nFileSizeHigh DD ?
+bhfi_nFileSizeLow DD ?
+bhfi_nNumberOfLinks DD ?
+bhfi_nFileIndexHigh DD ?
+bhfi_nFileIndexLow DD ?
+BY_HANDLE_FILE_INFORMATION ENDS
+
+
+;-----------------------------------------------------------------------
+; Signature definitions
+;
+AP_SIG STRUC
+sig_format DB ? ; formatType for the struc
+; rest of the data depends on the value in the sig_format field
+AP_SIG ENDS
+
+; Supported values for the sig_format field
+AP_SIG_FORMAT_HEXE equ 01h ; match hExe bytes, 1B offset
+AP_SIG_FORMAT_HEXE2 equ 02h ; match hExe bytes, 2B offset
+AP_SIG_FORMAT_FILE2 equ 03h ; match file bytes, 2B offset
+AP_SIG_FORMAT_FILE3 equ 04h ; match file bytes, 3B offset
+AP_SIG_FORMAT_FILE4 equ 05h ; match file bytes, 4B offset
+AP_SIG_FORMAT_FILESIZE2 equ 06h ; match file size, 2B size
+AP_SIG_FORMAT_FILESIZE3 equ 07h ; match file size, 3B size
+AP_SIG_FORMAT_FILESIZE4 equ 08h ; match file size, 4B size
+AP_SIG_FORMAT_META equ 0ffh ; contains other signatures
+
+;AP_SIG_FORMAT_HEXE
+AP_SIG_HEXE STRUC
+es_format DB ? ; AP_SIG_FORMAT_HEXE
+; There can be multiple signature strings, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+es_cb DB ? ; number of bytes to compare
+es_offset DB ? ; offset to begin signature compare
+es_abSignature DB ? ; cb DUP (?) ; signature bytes
+AP_SIG_HEXE ENDS
+
+;AP_SIG_FORMAT_HEXE2
+AP_SIG_HEXE2 STRUC
+es2_format DB ? ; AP_SIG_FORMAT_HEXE2
+; There can be multiple signature strings, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+es2_cb DB ? ; number of bytes to compare
+es2_offset DW ? ; offset to begin signature compare
+es2_abSignature DB ? ; cb DUP (?) ; signature bytes
+AP_SIG_HEXE2 ENDS
+
+;AP_SIG_FORMAT_FILE2
+AP_SIG_FILE2 STRUC
+fs2_format DB ? ; AP_SIG_FORMAT_FILE2
+; There can be multiple signature strings, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+fs2_cb DB ? ; number of bytes to compare
+fs2_offset DB 2 DUP (?) ; offset to begin signature compare
+fs2_abSignature DB ? ; cb DUP (?) ; bytes to match
+AP_SIG_FILE2 ENDS
+
+;AP_SIG_FORMAT_FILE3
+AP_SIG_FILE3 STRUC
+fs3_format DB ? ; AP_SIG_FORMAT_FILE3
+; There can be multiple signature strings, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+fs3_cb DB ? ; number of bytes to compare
+fs3_offset DB 3 DUP (?) ; offset to begin signature compare
+fs3_abSignature DB ? ; cb DUP (?) ; bytes to match
+AP_SIG_FILE3 ENDS
+
+;AP_SIG_FORMAT_FILE4
+AP_SIG_FILE4 STRUC
+fs4_format DB ? ; AP_SIG_FORMAT_FILE4
+; There can be multiple signature strings, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+fs4_cb DB ? ; number of bytes to compare
+fs4_offset DB 4 DUP (?) ; offset to begin signature compare
+fs4_abSignature DB ? ; cb DUP (?) ; bytes to match
+AP_SIG_FILE4 ENDS
+
+;AP_SIG_FORMAT_FILESIZE
+AP_SIG_FILESIZE STRUC
+fss_format DB ? ; AP_SIG_FORMAT_FILESIZE[2,3,4]
+fss_cbFile DB ? ; file size in bytes
+AP_SIG_FILESIZE ENDS
+
+;AP_SIG_FORMAT_FILESIZE2
+AP_SIG_FILESIZE2 STRUC
+fss2_format DB ? ; AP_SIG_FORMAT_FILESIZE2
+fss2_cbFile DB 2 DUP (?) ; file size in bytes
+AP_SIG_FILESIZE2 ENDS
+
+;AP_SIG_FORMAT_FILESIZE3
+AP_SIG_FILESIZE3 STRUC
+fss3_format DB ? ; AP_SIG_FORMAT_FILESIZE3
+fss3_cbFile DB 3 DUP (?) ; file size in bytes
+AP_SIG_FILESIZE3 ENDS
+
+;AP_SIG_FORMAT_FILESIZE4
+AP_SIG_FILESIZE4 STRUC
+fss4_format DB ? ; AP_SIG_FORMAT_FILESIZE4
+fss4_cbFile DB 4 DUP (?) ; file size in bytes
+AP_SIG_FILESIZE4 ENDS
+
+;AP_SIG_FORMAT_META
+AP_SIG_META STRUC
+ms_format DB ? ; AP_SIG_FORMAT_META
+; There can be multiple sub-signatures, packed one after the other.
+; All must match to give a match.
+; cb==0 signals the end.
+ms_cb DB ? ; number of bytes in the sub-signature
+ms_abSubSignature DB ? ; the sub-signature
+AP_SIG_META ENDS
+
+;-----------------------------------------------------------------------
+; Patch definitions
+;
+AP_COMMON STRUC
+ap_format DB ? ; formatType for the struc
+ap_cbSize DB ? ; number of bytes in the whole struct
+; rest of the data depends on the value in the ap_format field
+AP_COMMON ENDS
+
+; Supported values for the ap_format field:
+AP_FORMAT_REPLACE equ 1
+AP_FORMAT_ADD equ 2
+
+;AP_FORMAT_REPLACE
+AP_REPLACE STRUC
+apr_format DB ? ; AP_FORMAT_REPLACE
+apr_cbSize DB ? ; number of bytes in the whole struct
+apr_offset DW ? ; offset within the segment
+apr_cb DB ? ; number of bytes to replace
+apr_abOld DB ? ; cb DUP (?) ; old bytes
+apr_abNew DB ? ; cb DUP (?) ; new bytes
+AP_REPLACE ENDS
+
+;AP_FORMAT_ADD
+AP_ADD STRUC
+apa_format DB ? ; AP_FORMAT_ADD
+apa_cbSize DB ? ; number of bytes in the whole struct
+apa_offset DW ? ; offset within the segment
+apa_cb DB ? ; number of bytes to replace
+apa_abNew DB ? ; cb DUP (?) ; new bytes
+AP_ADD ENDS
+
+
+
+DataBegin
+
+szREGSTR_PATH_APPPATCH db REGSTR_PATH_APPPATCH, "\", 0
+
+; app-patching cache
+globalW hExePatchAppCache 0
+globalD hkeyPatchAppCache 0
+
+
+DataEnd
+
+
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+
+; GetPatchAppCache
+;
+; Gets an hkeyReg from the PatchApp cache if hExe in cache.
+;
+; Arguments:
+; hExe
+;
+; Returns:
+; dx:ax -1 if cache miss
+; registry key associated with hExe if cache hit
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;HKEY
+cProc GetPatchAppCache, <PUBLIC, NEAR>, <ds>
+ parmW hExe
+cBegin
+ SetKernelDSNRes
+
+ ; Set up dx==ax==-1 (indicates cache miss)
+ sub ax, ax
+ dec ax
+ mov dx, ax
+
+ mov cx, hExe
+ cmp cx, hExePatchAppCache
+ jne short gpac_exeunt
+
+ mov dx, hkeyPatchAppCache.hi
+ mov ax, hkeyPatchAppCache.lo
+ krDebugOut DEB_WARN,"GetPatchAppCache: hit (#cx, #dx#ax)"
+gpac_exeunt:
+ UnSetKernelDS
+cEnd
+
+
+; AddPatchAppCache
+;
+; Adds an (hExe,hkeyReg) pair to the PatchApp cache.
+;
+; Arguments:
+; hExe
+; hkeyReg
+;
+; Returns:
+;
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;VOID
+cProc AddPatchAppCache, <PUBLIC, NEAR>, <ds>
+ parmW hExe
+ parmD hkeyReg
+cBegin
+ SetKernelDSNRes
+
+ mov ax, hExe
+ mov hExePatchAppCache, ax
+
+ mov edx, hkeyReg
+ mov hkeyPatchAppCache, edx
+if KDEBUG
+ push cx
+ mov cx, hkeyPatchAppCache.hi
+ krDebugOut DEB_WARN,"AddPatchAppCache: (#ax, #cx#dx)"
+ pop cx
+endif
+
+ UnSetKernelDS
+cEnd
+
+
+; FlushPatchAppCache
+;
+; Flushes an hExe from the PatchApp cache.
+; If the cache has a reg key for the hExe, closes the key.
+;
+; Arguments:
+; hExe
+;
+; Returns:
+;
+; Remarks:
+; called by DelModule
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;VOID
+cProc FlushPatchAppCache, <PUBLIC, NEAR>, <>
+ parmW hExe
+cBegin
+; CheckKernelDS
+ ReSetKernelDS
+
+ mov ax, hExe
+ krDebugOut DEB_TRACE,"FlushPatchAppCache: (hExe #ax)"
+ cmp ax, hExePatchAppCache
+ jne short fpac_exeunt
+
+ sub eax, eax
+ cmp eax, hkeyPatchAppCache
+ je short fpac_after_close_key
+ cCall RegCloseKey32, <hkeyPatchAppCache>
+if KDEBUG
+ mov cx, hExe
+ mov bx, hkeyPatchAppCache.lo
+ mov dx, hkeyPatchAppCache.hi
+ krDebugOut DEB_WARN,"FlushPatchAppCache: flushing (hExe #cx) (hkey #dx#bx)"
+endif
+
+fpac_after_close_key:
+ mov hExePatchAppCache, ax
+if KDEBUG
+ mov hkeyPatchAppCache, eax ; a little extra for debug
+endif
+
+fpac_exeunt:
+ UnSetKernelDS
+cEnd
+
+
+; PatchGetFileSize
+;
+; Get the size of a file, given the DOS file handle.
+;
+; Arguments:
+; dfh - DOS file handle
+;
+; Returns:
+; DWORD file size
+;
+; Remarks:
+; Since these patches are only for old (<4.0) apps, only support
+; DWORD file size.
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;DWORD
+cProc PatchGetFileSize, <PUBLIC, NEAR>, <ds,si,di>
+ parmW dfh
+
+ localV FileInformation,<SIZE BY_HANDLE_FILE_INFORMATION>
+ localW HiPosition
+ localW LoPosition
+
+ localW SavePDB
+
+cBegin
+; MultiThreading version of change PDB
+; cCall GetCurPDB
+; mov SavePDB, ax
+; SetKernelDSNRes
+; cCall SetCurPDB,<topPDB> ; kernel's PSP
+; UnSetKernelDS
+; MultiThreading version of change PDB
+ SetKernelDSNRes ; ds is a scratch reg -> no need restore
+ mov ax, topPDB
+ xchg Win_PDB, ax ; Switch to Kernel's PDB,
+ UnSetKernelDS
+ mov SavePDB, ax ; saving current PDB
+
+ mov bx, dfh
+ smov ds, ss
+ lea dx, FileInformation
+ stc ; Real-mode drivers don't set CY on error
+ mov ax, 71a6h
+ int 21h
+ jc short gfs_try_offsets
+
+ mov dx, FileInformation.bhfi_nFileSizeLow.hi
+ mov ax, FileInformation.bhfi_nFileSizeLow.lo
+ jmp short gfs_exeunt
+
+gfs_try_offsets:
+ ; Real-mode drivers don't support 71a6, so we do it the hard way.
+ ; Move from current by 0 to get the current postion
+ mov bx, dfh
+ sub cx, cx
+ mov dx, cx
+ mov ax, 4201h
+ int 21h
+ jc short gfs_fail
+
+ ; Save current position
+ mov HiPosition, dx
+ mov LoPosition, ax
+
+ ; Get file size by moving from end by 0
+ sub cx, cx
+ mov dx, cx
+ mov ax, 4202h
+ int 21h
+ jc short gfs_fail
+
+ push dx
+ push ax
+
+ ; Restore current position
+ mov cx, HiPosition
+ mov dx, LoPosition
+ mov ax, 4200h
+ int 21h
+ ; Don't check for error, since we can't recover any more anyway...
+
+ pop ax
+ pop dx
+ jmp short gfs_exeunt
+
+gfs_fail:
+ sub ax, ax
+ mov dx, ax
+gfs_exeunt:
+; MultiThreading version of change PDB
+ push ax
+ mov ax, SavePDB
+ SetKernelDSNRes ; ds restored on proc exit
+ mov Win_PDB, ax
+ UnSetKernelDS
+; cCall SetCurPDB,<SavePDB> ; preserves dx
+ pop ax
+; MultiThreading version of change PDB
+
+cEnd
+
+
+; CompareFileBytes
+;
+; Compares a sequence of bytes with those at a given offset in a file.
+;
+; Arguments:
+; dfh
+; lpBytes
+; cb
+; dwFileOffset
+;
+; Returns:
+; WORD, zero iff match
+;
+; Remarks:
+; The caller is responsible for preserving the offset in the file.
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;WORD
+cProc CompareFileBytes, <PUBLIC, NEAR>, <si,di,ds>
+ parmW dfh
+ parmD lpBytes
+ parmW cb
+ parmD dwFileOffset
+cBegin
+ ; Seek to dwFileOffset.
+ mov bx, dfh
+ mov cx, dwFileOffset.hi
+ mov dx, dwFileOffset.lo
+ mov ax, 4200h
+ int 21h
+ jc short cfb_fail
+
+if KDEBUG
+ ; The high byte of cb _must_ be 0.
+ mov cx, cb
+ cmp ch, 0
+ je short @F
+ krDebugOut DEB_FERROR,"CompareFileBytes: cb (#cx) > 0ffh"
+@@:
+endif
+ mov byte ptr [cb].1, 0 ; force cb < 100h
+
+ ; Read from file.
+ mov cx, cb
+ smov ds, ss
+ sub sp, cx
+ mov dx, sp ; ds:dx = read buffer
+ mov ah, 3fh
+ int 21h
+ jc short cps_fail_restore_stack
+
+ ; Make sure we filled the buffer.
+ cmp ax, cx
+ jne short cps_fail_restore_stack
+
+ ; Compare the bytes.
+ les di, lpBytes ; es:di = signature bytes
+ smov ds, ss
+ mov si, sp ; ds:si = read buffer
+ rep cmpsb
+ jne short cps_fail_restore_stack
+
+ sub ax, ax
+ add sp, cb
+ jmp short cfb_exit
+
+cps_fail_restore_stack:
+ add sp, cb
+cfb_fail:
+ or al, 1
+cfb_exit:
+cEnd
+
+
+; ComparePatchSignature
+;
+; Tests a patch signature against an hExe.
+;
+; Arguments:
+; hExe
+; lpPatchSignature
+;
+; Returns:
+; WORD, zero iff match
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;WORD
+cProc ComparePatchSignature, <PUBLIC, NEAR>, <si,di,ds>
+ parmW hExe
+ parmD lpPatchSignature
+
+ localW SavePDB
+ localW dfh
+ localW cbNonZero
+ localD dwFileOffset
+cBegin
+beg_fault_trap cps_fault
+ mov es, hExe
+ lds si, lpPatchSignature
+
+ cld
+ .errnz AP_SIG.sig_format
+ lodsb
+;---------------------------------------------------
+ cmp al, AP_SIG_FORMAT_META
+ jne short cps_maybe_hexe
+
+ .errnz (AP_SIG_HEXE.ms_cb - AP_SIG_HEXE.ms_format) - 1
+cps_loop_meta:
+ lodsb
+ mov ah, 0
+ mov cx, ax ; cx = size of sub-signature
+ jcxz cps_meta_exeunt ; end of list. must be match.
+
+ mov di, si
+ add di, cx ; ds:di = next sub-signature
+ cCall ComparePatchSignature,<hExe,ds,si>
+ test ax, ax
+ jnz cps_fail
+ ; Got a match. Try the next one.
+ mov si, di ; ds:si = next sub-signature
+ jmp cps_loop_meta
+
+cps_meta_exeunt:
+ jmp cps_exeunt
+
+;---------------------------------------------------
+; AP_SIG_FORMAT_HEXE
+; AP_SIG_FORMAT_HEXE2
+cps_maybe_hexe:
+ .errnz (AP_SIG_FORMAT_HEXE2-AP_SIG_FORMAT_HEXE)-1
+ cmp al, AP_SIG_FORMAT_HEXE
+ jb short cps_maybe_filesize
+ cmp al, AP_SIG_FORMAT_HEXE2
+ ja short cps_maybe_filesize
+
+ ; Compute number of bytes in offset after first byte.
+ mov dl, al
+ sub dl, AP_SIG_FORMAT_HEXE
+
+ .errnz (AP_SIG_HEXE.es_cb - AP_SIG_HEXE.es_format) - 1
+ mov ah, 0
+cps_hexe_loop:
+ lodsb
+ mov cx, ax ; cx = size of signature block
+ jcxz cps_hexe_match ; end of list. must be match.
+
+ ; Set up bx with the offset in the hExe
+ sub bx, bx ; bx = default offset (0)
+ lodsb
+ mov bl, al ; bl = low byte of offset
+ test dl, dl ; more bytes?
+ jz short @F
+ lodsb
+ mov bh, al ; bh = high byte of offset
+@@:
+ mov di, bx ; es:di points to bytes in hExe
+ rep cmpsb
+ jne cps_fail
+ jmp cps_hexe_loop
+
+cps_hexe_match:
+ ; ax already 0
+ jmp cps_exeunt
+
+;---------------------------------------------------
+; AP_SIG_FORMAT_FILESIZE2
+; AP_SIG_FORMAT_FILESIZE3
+; AP_SIG_FORMAT_FILESIZE4
+cps_maybe_filesize:
+ .errnz (AP_SIG_FORMAT_FILESIZE3-AP_SIG_FORMAT_FILESIZE2)-1
+ .errnz (AP_SIG_FORMAT_FILESIZE4-AP_SIG_FORMAT_FILESIZE3)-1
+ cmp al, AP_SIG_FORMAT_FILESIZE2
+ jb short cps_maybe_file
+ cmp al, AP_SIG_FORMAT_FILESIZE4
+ ja short cps_maybe_file
+
+ ; Compute number of non-zero bytes in file size high word
+ mov cl, al
+ sub cl, AP_SIG_FORMAT_FILESIZE2
+ push cx
+
+; MultiThreading version of change PDB
+; cCall GetCurPDB
+; mov SavePDB, ax
+; SetKernelDSNRes es
+; cCall SetCurPDB,<topPDB> ; kernel's PSP
+; UnSetKernelDS es
+; MultiThreading version of change PDB
+ push ds
+ SetKernelDSNRes
+ mov ax, topPDB
+ xchg Win_PDB, ax ; Switch to Kernel's PDB,
+ UnSetKernelDS
+ pop ds
+ mov SavePDB, ax ; saving current PDB
+
+ ; Since these patches are only for old (<4.0) apps, only support
+ ; DWORD file size.
+ or ax, -1
+ cCall FarGetCachedFileHandle,<hExe,ax,ax>
+ cmp ax, -1
+ je short cps_filesize_fh_cache_miss
+
+ cCall PatchGetFileSize,<ax>
+ pop cx ; cl = non-zero bytes in file size high word
+
+ ; Low word of file size must match.
+ ; [si] = low byte of signature file size
+ cmp ax, [si]
+ jne short cps_filesize_fail
+
+ mov ch, 0
+ sub bx, bx ; bx = default high word of file size (0)
+ jcxz cps_filesize_compare_high
+
+ ; [si] = low word of signature file size
+ inc si
+ inc si
+ ; [si] = low byte of high word of signature file size (if exists)
+ ; bx = 0
+ ; cx = [1|2], non-zero bytes in file size high word
+ lodsb
+ mov bl, al
+ dec cl
+ jcxz cps_filesize_compare_high
+ lodsb
+ mov bh, al
+cps_filesize_compare_high:
+ cmp bx, dx
+ jne short cps_filesize_fail
+
+cps_filesize_match:
+ ; File size matches.
+; MultiThreading version of change PDB
+; cCall SetCurPDB,<SavePDB>
+; MultiThreading version of change PDB
+ mov ax, SavePDB
+ push ds
+ SetKernelDSNRes
+ mov Win_PDB, ax
+ UnSetKernelDS
+ pop ds
+
+ sub ax, ax
+ jmp cps_exeunt
+
+cps_filesize_fh_cache_miss:
+ krDebugOut DEB_ERROR,"ComparePatchSignature: filesize fh cache miss"
+
+cps_filesize_fail:
+; MultiThreading version of change PDB
+; cCall SetCurPDB,<SavePDB>
+; MultiThreading version of change PDB
+ mov ax, SavePDB
+ push ds
+ SetKernelDSNRes
+ mov Win_PDB, ax
+ UnSetKernelDS
+ pop ds
+
+ jmp cps_fail
+
+;---------------------------------------------------
+; AP_SIG_FORMAT_FILE2
+; AP_SIG_FORMAT_FILE3
+; AP_SIG_FORMAT_FILE4
+cps_maybe_file:
+ .errnz (AP_SIG_FORMAT_FILE3-AP_SIG_FORMAT_FILE2)-1
+ .errnz (AP_SIG_FORMAT_FILE4-AP_SIG_FORMAT_FILE3)-1
+ cmp al, AP_SIG_FORMAT_FILE2
+ jb cps_bad_format
+ cmp al, AP_SIG_FORMAT_FILE4
+ ja cps_bad_format
+
+ ; Compute number of non-zero bytes in file offset high word
+ mov cl, al
+ sub cl, AP_SIG_FORMAT_FILE2
+ mov ch, 0
+ mov cbNonZero, cx
+
+; MultiThreading version of change PDB
+; cCall GetCurPDB
+; mov SavePDB, ax
+; SetKernelDSNRes es
+; cCall SetCurPDB,<topPDB> ; kernel's PSP
+; UnSetKernelDS es
+; MultiThreading version of change PDB
+ push ds
+ SetKernelDSNRes
+ mov ax, topPDB
+ xchg Win_PDB, ax ; Switch to Kernel's PDB,
+ UnSetKernelDS
+ pop ds
+ mov SavePDB, ax ; saving current PDB
+
+ mov es, hExe
+
+ or ax, -1
+ push es
+ cCall FarGetCachedFileHandle,<es,ax,ax>
+ pop es
+ cmp ax, -1
+ je short cps_file_fh_cache_miss
+
+ mov bx, ax ; bx = dos file handle
+ mov dfh, ax
+ sub cx, cx
+ mov dx, cx
+ mov ax, 4201h
+ int 21h
+ jc cps_fail
+
+ mov dwFileOffset.hi, dx
+ mov dwFileOffset.lo, ax
+
+cps_file_loop:
+ lodsb
+ mov ah, 0
+ mov cx, ax ; cx = size of signature block
+ jcxz cps_file_match ; end of list. must be match.
+
+ mov di, cx ; di = number of bytes to match
+
+ ; Get the file offset into dx:bx
+ ; First get the low word.
+ lodsw
+ mov bx, ax ; bx = low word of file offset
+
+ ; Get one or both bytes of the high word.
+ sub dx, dx ; dx = default high word of file offset (0)
+ mov cx, cbNonZero
+ jcxz cps_file_compare
+ ; [si] = low byte of high word of file offset
+ ; dx = 0
+ ; cx = [1|2], non-zero bytes in file offset high word
+ lodsb
+ mov dl, al
+ dec cl
+ jcxz cps_file_compare
+ lodsb
+ mov dh, al
+
+cps_file_compare:
+ ; ds:[si] = bytes to match in file
+ ; di = byte count
+ ; dx:bx = offset in file
+ cCall CompareFileBytes,<dfh,ds,si,di,dx,bx>
+ test ax, ax
+ jnz short cps_file_fail
+
+ add si, di ; ds:si = next signature block
+ jmp cps_file_loop
+
+cps_file_fh_cache_miss:
+ krDebugOut DEB_ERROR,"ComparePatchSignature: file fh cache miss"
+
+cps_file_fail:
+ or al, 1
+ jmp short cps_file_exit
+
+cps_file_match:
+ sub ax, ax
+
+cps_file_exit:
+ mov si, ax ; si = return value
+
+ ; Restore file position
+ mov bx, dfh ; bx = dos file handle
+ mov cx, dwFileOffset.hi
+ mov dx, dwFileOffset.lo
+ mov ax, 4200h
+ int 21h
+ ; Don't check error, since we can't do anything anyway.
+if KDEBUG
+ jnc short @F
+ krDebugOut DEB_ERROR,"ComparePatchSignature: failure restoring file position"
+@@:
+endif
+; MultiThreading version of change PDB
+; cCall SetCurPDB,<SavePDB>
+; MultiThreading version of change PDB
+ mov ax, SavePDB
+ push ds
+ SetKernelDSNRes
+ mov Win_PDB, ax
+ UnSetKernelDS
+ pop ds
+
+ mov ax, si
+ jmp short cps_exeunt
+
+;---------------------------------------------------
+end_fault_trap
+cps_fault:
+ fault_fix_stack
+ krDebugOut DEB_ERROR,"ComparePatchSignature: trapped fault"
+
+cps_bad_format:
+ krDebugOut DEB_ERROR,"ComparePatchSignature: invalid format"
+cps_fail:
+ or al, 1 ; ensure we return "no_match"
+cps_exeunt:
+cEnd
+
+
+; GetPatchAppRegKey
+;
+; Determines if we patch an app at load time, gets reg key if so.
+;
+; Arguments:
+; hExe
+;
+; Returns:
+; HKEY, non-zero iff we segment-patch info in the registry for this app.
+;
+; Registers Preserved:
+; DI, SI, DS, ES
+
+ assumes ds,nothing
+ assumes es,nothing
+
+;HKEY
+cProc GetPatchAppRegKey, <PUBLIC, FAR>, <si,di,ds,es>
+ parmW hExe
+
+szKey_size = 200
+abPatchSignature_size = 100
+
+ localD hkeyModule
+ localD hkeySignature
+ localD dwIndex
+ localV szKey,szKey_size ; BUGBUG need a better size
+ localV abPatchSignature,abPatchSignature_size ; BUGBUG need a better size
+
+cBegin
+ ; We must refuse to patch system modules.
+ ; Should be ok because of version check (in caller).
+if KDEBUG
+ mov es, hExe
+ cmp es:[ne_expver], 400h ; Hacks don't apply to 4.0 or above
+ jb short @F
+ ; Should never get here since the caller should have already checked.
+ krDebugOut DEB_ERROR,"GetPatchAppRegKey: (#es) version later than 4.0"
+@@:
+endif
+ cCall GetPatchAppCache,<hExe>
+ ; ffff:ffff means a cache miss
+ or cx, -1
+ cmp cx, dx
+ jne gpark_exeunt
+ cmp cx, ax
+ jne gpark_exeunt
+
+ ; Not in the cache. Get it from the registry and add to the cache.
+
+ ; Copy the subkey prefix to the buffer.
+ lea di, szKey
+ smov es, ss
+ SetKernelDSNRes
+ lea si, szREGSTR_PATH_APPPATCH
+ mov cx, szKey_size
+@@:
+ lodsb
+ stosb
+ test al, al
+ loopnz @B
+if KDEBUG
+ jz short @F
+ krDebugOut DEB_ERROR,"GetPatchAppRegKey: len(szREGSTR_PATH_APPPATCH) > szKey_size"
+@@:
+endif
+ dec di
+ UnSetKernelDS
+
+ ; Append the module's base name (pascal format).
+ mov ds, hExe
+ mov si, ds:[ne_restab]
+ lodsb
+if KDEBUG
+ mov ah, 0
+ cmp cx, ax
+ ja short @F
+ krDebugOut DEB_ERROR,"GetPatchAppRegKey: len(reg path) > szKey_size"
+@@:
+endif
+ movzx cx, al
+ rep movsb
+ sub al, al
+ stosb ; NULL terminator
+
+ ; Get the key for this module.
+ mov hkeySignature, 0 ; In case we fail.
+ mov eax, HKEY_LOCAL_MACHINE
+ lea si, szKey
+ lea di, hkeyModule
+ ccall RegOpenKey32, <eax, ss, si, ss, di>
+ or ax,dx
+ jnz gpark_fail2
+
+ or dwIndex, -1 ; == mov dwIndex,-1 (but smaller)
+gpark_loop:
+ inc dwIndex
+ lea si, szKey
+ ccall RegEnumKey32, <hkeyModule, dwIndex, ss, si, 0, szKey_size>
+ or ax, dx
+ jnz short gpark_loop_done
+
+ ; First, convert string to binary.
+ ; Reuse szKey since we don't need path any more (we have hKeyModule).
+ lea si, abPatchSignature
+ lea di, szKey
+ krDebugOut DEB_WARN,"GetPatchAppRegKey: checking signature (@ss:di)"
+ cCall ConvertPatchStringToBinary,<ss,si,abPatchSignature_size,ss,di>
+ ; Skip a badly formatted patch signature.
+ test ax, ax
+if KDEBUG
+ jnz short @F
+ lea cx, szKey
+ krDebugOut DEB_ERROR,"PatchAppSeg: bad patch signature in registry, @ss:cx"
+@@:
+endif
+ jz gpark_loop
+
+ cCall ComparePatchSignature,<hExe,ss,si>
+ test ax, ax
+ jne gpark_loop
+
+if KDEBUG
+ mov ax, hExe
+ krDebugOut DEB_WARN,"GetPatchAppRegKey: (#ax) sig matches (@ss:di)"
+endif
+ ; We have a match. Get the corresponding key.
+ lea si, szKey
+ lea di, hkeySignature
+ ccall RegOpenKey32, <hkeyModule, ss, si, ss, di>
+ or ax,dx
+ jz short gpark_add
+
+ krDebugOut DEB_ERROR,"GetPatchAppRegKey: RegOpenKey failed, #dx#ax"
+ jmp short gpark_fail
+
+gpark_loop_done:
+
+if KDEBUG
+ test dx, dx
+ jnz short @F
+ cmp ax, ERROR_NO_MORE_ITEMS
+ je short gpark_after_loop_done_err
+@@:
+ krDebugOut DEB_ERROR,"GetPatchAppRegKey: unexpected error #dx#ax"
+gpark_after_loop_done_err:
+endif
+
+gpark_fail:
+ ; Mark that there are no patches in the registry.
+ mov hkeySignature, 0
+gpark_add:
+ ; Close the reg key for the path to the end of the module name
+ cCall RegCloseKey32, <hkeyModule>
+
+gpark_fail2:
+ ; Add hkeySignature to the cache and set up return regs.
+ cCall AddPatchAppCache,<hExe, hkeySignature>
+
+ mov ax, hkeySignature.lo
+ mov dx, hkeySignature.hi
+gpark_exeunt:
+cEnd
+
+; ConvertPatchStringToBinary
+;
+; Convert a string of [0-9,A-F] with nibble-swapped bytes to binary.
+;
+; Arguments:
+; lpBinary - output buffer
+; cbBinary - size of output buffer in bytes
+; lpString - input NULL-terminated string
+;
+; Returns:
+; Boolean, TRUE iff we convert the entire string.
+;
+; Registers Preserved:
+; DI, SI, DS, ES
+
+ assumes ds, nothing
+ assumes es, nothing
+
+;BOOL
+cProc ConvertPatchStringToBinary, <PUBLIC, NEAR>,<di,si,ds>
+ parmD lpBinary
+ parmW cbBinary
+ parmD lpString
+cBegin
+ krDebugOut DEB_WARN,"ConvertPatchStringToBinary: enter"
+ mov cx, cbBinary
+ jcxz cpstb_bad
+
+ les di, lpBinary
+ lds si, lpString
+ sub ah, ah
+
+cpstb_loop:
+ lodsb
+ cmp al, 0
+ je short cpstb_maybe_good
+ cmp al, ' '
+ je cpstb_loop
+ cmp al, ','
+ je cpstb_loop
+ cmp al, '0'
+ jb short cpstb_bad
+ cmp al, '9'
+ ja short cpstb_maybe_lower
+
+ ; digit
+ sub al, '0'
+ jmp short cpstb_have_nibble
+
+cpstb_maybe_lower:
+ or al, 20h ; map upper-case to lower-case
+ cmp al, 'f'
+ ja short cpstb_bad
+ cmp al, 'a'
+ jb short cpstb_bad
+
+ ; lower-case
+ sub al, 'a'-10
+
+cpstb_have_nibble:
+ cmp ah, 0
+ jne short cpstb_store_byte
+ mov ah, al
+ or ah, 80h
+ jmp cpstb_loop
+
+cpstb_store_byte:
+ shl ah, 4
+ or al, ah
+ stosb
+ sub ah, ah
+ loop cpstb_loop
+cpstb_bad:
+ krDebugOut DEB_ERROR, "ConvertPatchStringToBinary: bad char #al, or bad buffer size"
+ sub ax, ax
+ jmp short cpstb_end
+cpstb_maybe_good:
+ cmp ah, 0 ; odd-length input string ?
+ jne cpstb_bad
+cpstb_good:
+ or al, 1
+cpstb_end:
+cEnd
+
+
+; PatchAppSegWorker
+;
+; Do the work of patching an app segment.
+;
+; Arguments:
+; wSeg - the segment we are about to patch
+; wPartySeg - a data aliase of the segment we are about to patch
+; cbOriginalSeg - the value returned by GlobalSize(wSeg)
+; lpcbCurrentSeg - ptr to the current size of the segment
+; lpBinaryPatch - the APPPATCH struct to apply to wSeg
+;
+; Returns:
+; VOID
+;
+; Registers Preserved:
+; DI, SI, DS
+
+ assumes ds, nothing
+ assumes es, nothing
+
+;VOID
+cProc PatchAppSegWorker, <PUBLIC, NEAR>,<si,di,ds>
+ parmW wSeg
+ parmW wPartySeg
+ parmW cbOriginalSeg
+ parmD lpcbCurrentSeg
+ parmD lpBinaryPatch
+
+ localW wAddPartySeg
+
+cBegin
+ lds si, lpBinaryPatch
+ mov es, wPartySeg
+ krDebugOut DEB_WARN,"PatchAppSegWorker: applying patch to party seg #es"
+
+ mov al, [si].AP_COMMON.ap_format
+ cmp al, AP_FORMAT_REPLACE
+ jne short pasw_maybe_add
+
+ ; Replace some code in a segment.
+ krDebugOut DEB_WARN,"PatchAppSegWorker: type==replace"
+
+ ; Check size
+ mov ch, 0
+ mov cl, [si].AP_REPLACE.apr_cb
+ mov al, (AP_REPLACE.apr_abOld - AP_REPLACE.apr_format)
+ add al, cl
+ add al, cl
+ cmp al, [si].AP_REPLACE.apr_cbSize
+
+if KDEBUG
+ je short @F
+ mov ah, ch
+ mov dh, ch
+ mov dl, [si].AP_REPLACE.apr_cbSize
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: actual size (#ax) != apa_cbSize (#dx)"
+@@:
+endif
+ jne pasw_end
+ mov di, [si].AP_REPLACE.apr_offset
+ add di, cx
+ cmp di, cbOriginalSeg
+ ja pasw_replace_offset_too_large
+
+ sub di, cx
+ add si, (AP_REPLACE.apr_abOld - AP_REPLACE.apr_format)
+ repe cmpsb ; compare old bytes to hExe bytes
+ jne pasw_repl_no_match
+
+ mov si, lpBinaryPatch.lo
+ mov ch, 0
+ mov cl, [si].AP_REPLACE.apr_cb
+ add si, (AP_REPLACE.apr_abOld - AP_REPLACE.apr_format)
+ add si, cx ; skip over the old bytes
+ sub di, cx ; rewind to the patch area start
+ rep movsb ; replace the bytes
+ jmp pasw_end
+pasw_maybe_add:
+ cmp al, AP_FORMAT_ADD
+ jne pasw_bad_format
+
+ ; Add some code to the segment.
+ krDebugOut DEB_WARN,"PatchAppSegWorker: type==add"
+
+ ; Check size
+ mov ch, 0
+ mov cl, [si].AP_ADD.apr_cb
+ mov al, (AP_ADD.apa_abNew - AP_ADD.apa_format)
+ add al, cl
+ cmp al, [si].AP_ADD.apa_cbSize
+if KDEBUG
+ je short @F
+ mov ah, ch
+ mov dh, ch
+ mov dl, [si].AP_ADD.apa_cbSize
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: actual size (#ax) != apa_cbSize (#dx)"
+@@:
+endif
+ jne pasw_end
+
+ ; Make sure the add is beyond the original segment.
+ mov di, [si].AP_ADD.apa_offset
+ cmp di, cbOriginalSeg
+ jb short pasw_offset_too_small
+
+ ; Grow the segment if necessary.
+ mov ah, 0
+ mov al, [si].AP_ADD.apa_cb
+ add di, ax
+
+ ; See if the segment is already big enough.
+ les bx, lpcbCurrentSeg
+ cmp di, es:[bx]
+ jbe short pasw_do_add
+
+ ; Segment too small. Grow it.
+ cCall GlobalRealloc,<wSeg,0,di,0>
+ ; Make sure we got the same sel back.
+ mov cx, wSeg
+ and al, not 1
+ and cl, not 1
+ cmp ax, cx
+ jne short pasw_repl_realloc_failed
+
+ ; Save the new size of the segment.
+ les bx, lpcbCurrentSeg
+ mov es:[bx], di
+
+pasw_do_add:
+ mov ch, 0
+ mov cl, [si].AP_ADD.apa_cb
+
+ ;Since wSeg may have grown, create a new party seg.
+ mov bx, wSeg
+ mov ax, 000Ah ;DPMI, Create Code Segment Alias
+ int 031h
+ mov es, ax
+
+ sub di, cx
+ add si, (AP_ADD.apa_abNew - AP_ADD.apa_format)
+ rep movsb ; add the bytes
+ cCall FreeSelector, <es>
+
+if KDEBUG
+ jmp short pasw_end
+endif
+
+pasw_bad_format:
+if KDEBUG
+ sub ah, ah
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: unknown format #ax"
+ jmp short pasw_end
+endif
+pasw_repl_realloc_failed:
+if KDEBUG
+ mov ax, wSeg
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: realloc failed on seg #ax"
+ jmp short pasw_end
+endif
+pasw_repl_no_match:
+if KDEBUG
+ krDebugOut DEB_WARN,"PatchAppSegWorker: replace failed in seg #es"
+ jmp short pasw_end
+endif
+pasw_offset_too_small:
+if KDEBUG
+ mov cx, cbOriginalSeg
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: add offset (#di) < size (#cx)"
+ jmp short pasw_end
+endif
+pasw_replace_offset_too_large:
+if KDEBUG
+ mov cx, cbOriginalSeg
+ krDebugOut DEB_ERROR,"PatchAppSegWorker: replace offset (#di) > size (#cx)"
+endif
+pasw_end:
+
+cEnd
+
+
+; PatchAppSeg
+;
+; Apply any patches for the given segment.
+;
+; Arguments:
+; hkeyPatchApp - reg key containing patches for this app
+; wSegNo - number of the segment in the module
+; wSeg - selector of the segment
+;
+; Returns:
+; BOOL - ax!=0 iff one or more patches applied
+;
+; Registers Preserved:
+; CX, DI, SI, DS, ES
+
+ assumes ds, nothing
+ assumes es, nothing
+
+;BOOL
+cProc PatchAppSeg, <PUBLIC, FAR>,<cx,si,di,ds,es>
+ parmD hkeyPatchApp
+ parmW wSegNo
+ parmW wSeg
+
+szKey_size = 5
+szValString_size = 32
+abValData_size = 100
+abBinaryPatch_size = 100
+
+ localD hkey
+ localV szKey,szKey_size ; BUGBUG need a better size
+ localV szValString,szValString_size ; BUGBUG need a better size
+ localV abValData,abValData_size ; BUGBUG need a better size
+ localV abBinaryPatch,abBinaryPatch_size ; BUGBUG need a better size
+ localD cbValString
+ localD cbValData
+ localD dwType
+ localD dwIndex
+ localW cbOriginalSeg
+ localW cbCurrentSeg
+ localW wPartySeg
+
+cBegin
+if KDEBUG
+ mov ax, wSegNo
+ mov bx, wSeg
+ krDebugOut DEB_WARN,"PatchAppSeg: enter, (wSegNo #ax) (wSeg #bx)"
+endif
+ push wSeg
+ call GlobalSize
+ mov cbOriginalSeg,ax
+ mov cbCurrentSeg,ax
+
+ ; Segment number is the subkey.
+
+ lea si, szKey
+ cCall Far_htoa0, <ss, si, wSegNo>
+ mov bx, ax
+ mov byte ptr ss:[bx], 0 ; NULL terminator
+
+ ; Get the key for this module/seg pair.
+ lea si, szKey
+ lea di, hKey
+ cCall RegOpenKey32, <hkeyPatchApp, ss, si, ss, di>
+ or ax,dx
+ jnz pas_no_patches
+
+ ; Turn off the code bit for the seg to make it writeable.
+ ; NB - Bail if this is a data segment.
+
+
+
+ mov bx, seg gdtdsc
+ mov ds, bx
+ assume ds:nothing
+ mov ds, ds:gdtdsc
+ mov bx, wSeg
+ and bl, not 7
+ test byte ptr ds:[bx+5], DSC_CODE_BIT
+ jz pas_no_patches ; bail if data seg
+
+ mov bx, wSeg
+ mov ax, 000Ah ;DPMI, Create Code Segment Alias
+ int 031h
+ mov wPartySeg, ax
+
+ ; Mark this code segment not discardable so we don't have to deal
+ ; with patching it again.
+ call Far_genter
+ mov dx, wSeg
+ call Far_pdref
+ ; ds:esi = arena record
+ and ds:[esi].pga_flags, not (GA_DISCARDABLE or GA_DISCCODE)
+ call Far_gleave
+
+ or dwIndex, -1
+pas_loop:
+ sub ecx, ecx
+ inc dwIndex
+
+ push dword ptr hkey
+ push dword ptr dwIndex
+ mov cbValString, szValString_size
+ mov cbValData, abValData_size
+ push ss
+ lea ax, szValString
+ push ax
+ push ss
+ lea ax, cbValString
+ push ax
+ push ecx
+ push ss
+ lea ax, dwType
+ push ax
+ push ss
+ lea ax, abValData
+ push ax
+ push ss
+ lea ax, cbValData
+ push ax
+ cCall RegEnumValue32
+ or ax, dx
+ jnz pas_loop_done
+if KDEBUG
+ lea bx, szValString
+ krDebugOut DEB_WARN,"PatchAppSeg: found patch @ss:bx"
+endif
+
+ cmp dwType, REG_BINARY
+ jne short pas_bad_type
+
+ lea bx, abValData ; ss:bx points to patch
+ movzx ecx, ss:[bx].AP_COMMON.ap_cbSize
+ cmp cbValData, ecx
+if KDEBUG
+ je short @F
+ push bx
+ mov eax, cbValData
+ mov edx, eax
+ ror edx, 16
+ mov ebx, ecx
+ ror ebx, 16
+ krDebugOut DEB_ERROR,"PatchAppSeg: actual size (#dx:#ax) != ap_cbSize (#bx:#cx)"
+ pop bx
+@@:
+endif
+ jne pas_loop
+
+pas_apply_patch:
+ lea ax, cbCurrentSeg ; ss:ax points to curr seg size
+ ; Now apply the patch.
+
+ cCall PatchAppSegWorker,<wSeg,wPartySeg,cbOriginalSeg,ss,ax,ss,bx>
+ jmp pas_loop
+
+pas_bad_type:
+if KDEBUG
+ mov eax, dwType
+ mov edx, eax
+ ror edx, 16
+ krDebugOut DEB_WARN,"PatchAppSeg: unimplemented type #dx:#ax"
+endif
+ jmp pas_loop
+
+pas_no_patches:
+ sub ax, ax
+ jmp short pas_end
+
+pas_loop_done:
+if KDEBUG
+ test dx, dx
+ jnz short @F
+ cmp ax, ERROR_NO_MORE_ITEMS
+ je short pas_cleanup
+@@:
+ krDebugOut DEB_WARN,"PatchAppSeg: unexpected error #dx#ax"
+endif
+pas_cleanup:
+ cCall FreeSelector, <wPartySeg>
+
+ cCall RegCloseKey32, <hkey>
+ or al, 1 ; ax!=0 marks patch found in reg
+pas_end:
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/patch.txt b/private/mvdm/wow16/kernel31/patch.txt
new file mode 100644
index 000000000..f44e50daf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/patch.txt
@@ -0,0 +1,233 @@
+This is an overview document describing how to create module patches
+in Windows 95.
+
+Legal aspects:
+--------------
+While we are obviously using this module-patching technology to
+make already-shipping apps run or run better, it is possible
+for us to make a mistake and wrongly patch a module. For example,
+there might be two similar versions of an app which need to be
+patched differently, but we only know about one of them. Due to the
+obvious liability concerns, we need to obtain authorization from
+the app vendor for each module patch we put into the registry.
+The letter must specify the name of the module, the number of the
+segment taking the patch, the bytes being replaced, and the new
+bytes taking their place. The letter can be from any responsible
+person at the vendor, eg. an engineer who is familiar with the code.
+At the same time, talking to the vendor will help us find out how
+many different versions there are of an app, so we can figure out
+how to patch each one.
+
+See brianrey if you have a module patch you want to check in.
+It would be a good idea to get the ball rolling on getting the
+letter as soon as possible after you know what the patch is, since
+it can sometimes take a while to get these things taken care of.
+We already get similar letters for app-hack bits.
+
+
+How to check in a patch:
+------------------------
+Since the patch values go in the registry, and since the initial registry
+contents are owned by setup, you must work with Andy Hill to get your
+module patches checked in.
+
+A common mistake when adding app-patches to msbase.inx is to leave out
+field 4 (field 3 if you are a computer), which are flags. The reason
+for the confusion is the flag that means "This is a binary regkey" is 01,
+and the opcode for "Change" is also 01, so everything just shifts down
+one step and nobody gets hurt. Except that the patch doesn't work.
+eg: If you want to add a key whose value is <01,09,70,00,02,ff,76,eb,15>
+WRONG
+ HKLM,"SYSTEM\...",Change,01,09,70,00,02,ff,76,eb,15
+BETTER
+ HKLM,"SYSTEM\...",Change,1,01,09,70,00,02,ff,76,eb,15
+
+
+How to make a patch:
+--------------------
+All definitions of the structures used below are in core\kernel\patch.asm.
+
+The loader knows to look in the registry for patch data if the MCF_MODPATCH
+bit is set in the [ModuleCompatibility] section in win.ini.
+eg.
+[ModuleCompatibility]
+GENERIC=0x0002
+
+All registry keys and values for module-patching are stored
+under HKEY_LOCAL_MACHINE under REGSTR_PATH_APPPATCH:
+(from dev\sdk\inc\regstr.h)
+#define REGSTR_PATH_APPPATCH "System\\CurrentControlSet\\Control\\SessionManager\\AppPatches"
+
+The actual patches are values stored in the registry under
+REGSTR_PATH_APPPATCH\<mod_name>\<signature>\<segment_number>
+where
+ mod_name = the module name
+ signature = a signature string identifying the module version
+ segment_number = the hex number of the segment receiving the patches
+
+
+Signatures:
+-----------
+Signatures are strings of ANSI characters representing hex numbers
+in nibble-swapped byte format (what you see in wdeb386 if you type
+db). Blanks and commas are ignored, and may be included for readability.
+
+The easiest way to create a signature is to run dev\tools\binw\gensig.
+eg. If you want to patch segment 3 in foo.dll, run "gensig foo.exe 3"
+and a tight signature will be written to stdout.
+
+type-1 and -2 signatures:
+A type-1 signature specifies a list of byte sequences with byte offsets
+(type-2 has word offsets) which must all match for the signature to match.
+A 0 byte-count marks the end of the list.
+A match-any-file signature is "0100".
+eg. signature = "01 02,00,4e,45 02,3e,0a,03 00" is a type-1 signature which
+ || || || || || || || || || ||
+ type --------++ || || || || || || || || ||
+ || || || || || || || || ||
+ byte count------++ || || || || || || || ||
+ offset-------------++ || || || || || || ||
+ match bytes-----------++-++ || || || || ||
+ || || || || ||
+ byte count------------------++ || || || ||
+ offset-------------------------++ || || ||
+ match bytes-----------------------++-++ ||
+ ||
+ terminating byte count------------------++
+matches if the 2 bytes starting at offset 0 in the exe header match
+4e,45 ("NE") and if the 2 bytes starting at offset 3e match 0a,03.
+Note- DO NOT include a match on NE in your signature. This is just
+for illustrative purposes. The windows version and size(s) of the
+segment(s) being patched are good candidates.
+
+
+type-3, -4 and -5 signatures:
+Type-3, -4 and -5 signatures are similar to type-1 and -2 signatures,
+except that the offsets are offsets in the module file. Type-3 takes
+word offsets, type-4 takes 3-byte offsets, and type-5 takes dword offsets.
+eg. signature = "03,03,67,05,c2,0a,00,00"
+ || || || || || || || ||
+ type---------++ || || || || || || ||
+ || || || || || || ||
+ byte count------++ || || || || || ||
+ file offset--------++-++ || || || ||
+ match bytes--------------++-++-++ ||
+ ||
+ terminating byte count------------++
+matches if the 3 bytes at offset 567h in the file match c2,0a,00.
+
+
+type-6, -7 and -8 signatures:
+Type-6, -7 and -8 signatures specify the file size of the matching
+module. The number of bytes used to specify the matching file size
+is 2, 3 or 4 respectively.
+eg. signature = "06,d0,0c"
+ || || ||
+ type---------++ || ||
+ file size-------++-++
+matches if the file size is 0cd0h.
+
+
+type-ff signatures:
+Type-ff signatures are meta-signatures and consist of a list of the
+other types of signatures. Each list element consists of a byte count
+and a sub-signature. A 0 byte-count ends the list.
+eg. signature = "ff 06,01,02,3e,0a,03,00 03,06,d0,0c 00"
+ || || || || || || || || || || || || ||
+ type---------++ || || || || || || || || || || || ||
+ || || || || || || || || || || || ||
+ byte count------++ || || || || || || || || || || ||
+ sub-type-----------++ || || || || || || || || || ||
+ sub-byte-count--------++ || || || || || || || || ||
+ hExe offset--------------++ || || || || || || || ||
+ match bytes-----------------++-++ || || || || || ||
+ sub-type terminator---------------++ || || || || ||
+ || || || || ||
+ byte count---------------------------++ || || || ||
+ sub-type--------------------------------++ || || ||
+ file size----------------------------------++-++ ||
+ ||
+ terminating byte count---------------------------++
+matches if the 2 bytes at offset 3eh in the exe header match 0a,03
+and the file size is 0cd0h.
+
+
+Criteria for selecting a signature:
+-----------------------------------
+In terms of time required to validate a signature, the hExe types are
+the fastest, the file size types are next-fastest, and the file data
+types are the slowest. A signature specifying the expected Windows
+version (hExe offset 3e) and the file size is probably sufficient
+for most cases, since almost any code change changes the file size.
+A signature which also requires a file match on the bytes being replaced
+(if they are not fixed up and they are in a segment, they must be
+somewhere in the file!) is very good, but might be overkill.
+Since file match signatures hit the disk, they might noticeably increase
+the load time of the module.
+
+DO NOT match on the NE signature in the module header. This is
+just a waste of bytes, since it always matches.
+DO match on the file size unless you have a very good reason not to.
+If going through the ifs, this is a very cheap test.
+DO match on something, since we don't want to rely on just the
+name of the module. We have signatures. Use them. If you have
+no better idea (eg. there is only one version), match on the
+windows version, the size(s) of the segment(s) being patched, and
+the file size.
+
+
+Patch data:
+-----------
+The patch values specify sequences of bytes to add or replace.
+Add's must be placed after the end of the unpatched segment.
+The segment is GlobalReAlloc'd as necessary to contain the new code.
+Replace's must be within the limits of the unpatched segment,
+and they must match the sequence of old bytes in the patch value.
+Obviously, replaced bytes cannot contain fixups.
+The contents of the value string are not used, except to be sent
+to the debugger as a debugging aid when the value is loaded from
+the registry. The contents of the value data must be in REG_BINARY
+format.
+
+Example:
+--------
+Note: The registry key show below will not work as shown, since it
+has been broken into multiple lines for legibility. Join the lines
+together and it works.
+
+==================================================================
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\SessionManager
+\AppPatches\GENERIC
+\ff 06,01,02,3e,0a,03,00 03,06,d0,0c 08,03,03,67,05,c2,0a,00,00 00
+\1]
+"Add"=hex:02,08,f0,03,03,c2,0a,00
+"Replace"=hex:01,0b,67,00,03,c2,0a,00,e9,86,03
+==================================================================
+
+The Add value has data with a size of 8 bytes, saying that at offset
+3f0h that the 3 bytes c2,0a,00 should be added.
+ "Add"=hex:02,08,f0,03,03,c2,0a,00
+ || || || || || || || ||
+ type=Add--++ || || || || || || ||
+ total bytes--++ || || || || || ||
+ offset----------++-++ || || || ||
+ byte count------------++ || || ||
+ bytes to add-------------++-++-++
+
+The Replace value has data with a size of 0bh bytes, saying that at
+offset 67h that the 3 bytes c2,0a,00 should be replaced with e9,86,03.
+ "Replace"=hex:01,0b,67,00,03,c2,0a,00,e9,86,03
+ || || || || || || || || || || ||
+ type=Replace--++ || || || || || || || || || ||
+ total bytes------++ || || || || || || || || ||
+ offset--------------++-++ || || || || || || ||
+ byte count----------------++ || || || || || ||
+ old bytes--------------------++-++-++ || || ||
+ new bytes-----------------------------++-++-++
+
+The combined effect of these two changes is to replace a "retn a" at 67
+with "jmp 3f0" and, at 3f0 to add "retn a". The app runs exactly as
+before in this case, except for a small detour. When it reaches ip=67,
+instead of doing "retn a", it does a "jmp 3f0" and then the "retn a".
diff --git a/private/mvdm/wow16/kernel31/pdb.inc b/private/mvdm/wow16/kernel31/pdb.inc
new file mode 100644
index 000000000..636a121e8
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/pdb.inc
@@ -0,0 +1,41 @@
+;
+; MSDOS 2.xx Process Data Block
+;
+; Contains all DOS specific data.
+;
+
+FilPerProc EQU 20
+
+; Process Data located in the Program Segment Prefix, just before the
+; code and data for the loaded program.
+;
+PDB STRUC
+PDB_Exit_Call DW ?
+PDB_block_len DW ?
+ DB ?
+PDB_CPM_Call DB 5 DUP (?)
+PDB_Exit DD ?
+PDB_Ctrl_C DD ?
+PDB_Fatal_Abort DD ?
+PDB_Parent_PID DW ?
+PDB_JFN_Table DB FilPerProc DUP (?)
+PDB_environ DW ?
+PDB_User_stack DD ?
+PDB_JFN_Length DW ? ; DOS 3.x only
+PDB_JFN_Pointer DD ? ; DOS 3.x only
+PDB_Next_PDB DD ? ; DOS 3.x only
+PDB_InterCon DB ? ; DOS 4.x only
+PDB_Append DB ? ; DOS 4.x only
+PDB_Novell_Used DB 02h DUP (?)
+PDB_Version DW ? ; DOS 5.x only
+PDB_Chain DW ? ; Windows only
+PDB_Partition DW ? ; Windows only
+PDB_NextPDB DW ? ; Windows only
+PDB_GlobalHeap DD ? ; Windows only
+PDB_Entry_stack DD ? ; Windows only
+PDB_Call_system DB 5h DUP (?)
+PDB_PAD2 DB 7h DUP (?)
+PDB_5C_FCB DB 10h DUP (?)
+PDB_6C_FCB DB 14h DUP (?)
+PDB_DEF_DTA DB 80h DUP (?)
+PDB ENDS
diff --git a/private/mvdm/wow16/kernel31/protect.inc b/private/mvdm/wow16/kernel31/protect.inc
new file mode 100644
index 000000000..f4184f698
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/protect.inc
@@ -0,0 +1,181 @@
+ifdef WOW
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+else
+DPMICALL MACRO func
+ mov ax, func
+ int 31h
+ ENDM
+endif; WOW
+
+
+RING equ 3 ; RING 1 we be
+
+SEL_LDT equ 4
+SEG_RING equ (RING+SEL_LDT)
+SEG_RING_MASK equ 7
+
+IS_SELECTOR equ 1 ; Selectors are odd, handles even
+
+ ; Bits in dsc_access
+DSC_PRESENT equ 80h
+DSC_CODEDATA equ 10h ; Code or data descriptor
+DSC_RING equ (RING SHL 5)
+DSC_CODE equ (1Bh+DSC_RING) ; Code, readable, accessed
+DSC_CODE_BIT equ 08h ; Identifies code
+DSC_RW_BIT equ 02h ; Code readable, data writable bit
+DSC_DATA equ (13h+DSC_RING) ; Data, writable, accessed
+DSC_ACCESSED equ 01h ; Segment was accessed
+
+DSC_USED equ 0Fh ; Access rights to mark descriptor used
+
+ ; Bits in dsc_hlimit
+DSC_GRANULARITY equ 80h ; Page granularity segment
+DSC_DEFAULT equ 40h ; Default word size
+DSC_DISCARDABLE equ 10h ; Available bit in descriptor
+ ; (using access as a word)
+
+GDT_FREEDSC equ -1
+GDT_NPDSC equ 07FFFh
+
+if PMODE
+if PMODE32
+GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
+GA_MASK_BYTES = (NOT GA_ALIGN_BYTES)
+endif
+endif
+
+DscPtr struc ;Descriptor
+dsc_limit dw ? ;Descriptor max length
+dsc_lbase dw ? ;Descriptor base bits 15-0
+dsc_mbase db ? ;Descriptor base bits 23-16
+dsc_access db ? ;Descriptor access byte
+dsc_hlimit db ? ;High limit, granularity and 2 custom bits
+dsc_hbase db ? ;Descriptor base bits 31-24
+DscPtr ends
+
+
+DSC_LEN equ (size DscPtr)
+.ERRNZ DSC_LEN-8 ; Paranoia
+
+dsc386 equ word ptr dsc_hlimit
+dsc_owner equ word ptr dsc_limit
+
+if PMODE
+if PMODE32
+GENTER32 MACRO
+
+ push esi
+ push edi
+ call genter
+ mov gs, di
+
+ ENDM
+
+
+GLEAVE32 MACRO
+
+ mov es, di ; Zero ES for now
+ mov fs, di ; And FS
+ call gleave
+ pop edi
+ pop esi
+
+ ENDM
+
+MIN_FREE_ARENAS equ 30h ; Minimum number of free arenas desired
+ARENA_INCR_BYTES equ 8192 ; Space for more arenas
+endif
+endif
+
+if PMODE
+ife RING-3
+
+;
+; Change selector or handle to a handle
+; Handles are RING 2
+; Selectors are RING 3
+;
+Sel_To_Handle MACRO xsel
+ and xsel, NOT 1
+ ENDM
+
+;
+; Change handle or selector to a selector
+;
+Handle_To_Sel MACRO xsel
+ or xsel, 1
+ ENDM
+
+;
+; Change known selector into corresponding handle
+;
+StoH MACRO sel
+ dec sel
+ ENDM
+
+;
+; Change known handle into corresponding selector
+;
+HtoS MACRO h
+ inc h
+ ENDM
+
+;
+; Given a segment limit, calculate the
+; number of selectors in the array
+;
+Limit_To_Selectors MACRO reg
+ shr reg, 16 ; Now divide by 64k to get # of selectors - 1
+ inc reg
+ ENDM
+
+endif
+
+ife RING-1
+;
+; Change selector or handle to a handle
+; Handles are RING 2
+; Selectors are RING 1
+;
+Sel_To_Handle MACRO xsel
+ test xsel, 1
+ jz short @F
+ inc xsel
+@@:
+ ENDM
+
+;
+; Change handle or selector to a selector
+;
+Handle_To_Sel MACRO xsel
+ test xsel, 1
+ jnz short @F
+ dec xsel
+@@:
+ ENDM
+
+;
+; Change known selector into corresponding handle
+;
+StoH MACRO sel
+ inc sel
+ ENDM
+
+;
+; Change known handle into corresponding selector
+;
+HtoS MACRO h
+ dec h
+ ENDM
+
+endif
+
+
+IsFixed MACRO xh
+ test xh, 1
+ ENDM
+
+endif ; PMODE
diff --git a/private/mvdm/wow16/kernel31/qgrep.grp b/private/mvdm/wow16/kernel31/qgrep.grp
new file mode 100644
index 000000000..6deae0cb5
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/qgrep.grp
@@ -0,0 +1,269 @@
+Don't edit this file with "m" or any other editor that does
+perverse things with TAB characters.
+
+Start Length
+
+Address Export
+ CODE
+ DATA
+
+Origin Group
+ DGROUP
+ IGROUP
+
+Publics by Name
+Publics by Value
+
+Program entry point
+ HEADTDB$
+ CURTDB$
+ HEXEHEAD$
+ ACCESSRESOURCE$
+ ADDATOM$
+ ALLOCALIAS$
+ ALLOCSELECTORARRAY$
+ ALLOCCSTODSALIAS$
+ ALLOCDSTOCSALIAS$
+ ALLOCRESOURCE$
+ ALLOCSELECTOR$
+ CATCH$
+ CHANGESELECTOR$
+ DEBUGBREAK$
+ DEBUGDEFINESEGMENT$
+ DEFINEHANDLETABLE$
+ DELETEATOM$
+ DIAGOUTPUT$
+ DIAGQUERY$
+ DIRECTEDYIELD$
+ DOS3CALL$
+ FATALAPPEXIT$
+ FATALEXIT$
+ FINDATOM$
+ FINDRESOURCE$
+ FREELIBRARY$
+ FREEMODULE$
+ FREEPROCINSTANCE$
+ FREERESOURCE$
+ FREESELECTOR$
+ GETATOMHANDLE$
+ GETATOMNAME$
+ GETCODEHANDLE$
+ GETCODEINFO$
+ GETCURRENTTASK$
+ GETDOSENVIRONMENT$
+ GETDRIVETYPE$
+ GETFREESPACE$
+ GETHEAPSPACES$
+ GETINSTANCEDATA$
+ GETMODULEFILENAME$
+ GETMODULEHANDLE$
+ GETMODULEUSAGE$
+ GETNUMTASKS$
+ GETPRIVATEPROFILEINT$
+ GETPRIVATEPROFILESTRING$
+ GETPROCADDRESS$
+ GETPROFILEINT$
+ GETPROFILESTRING$
+ GETSELECTORBASE$
+ GETSELECTORLIMIT$
+ GETSYSTEMDIRECTORY$
+ GETTEMPDRIVE$
+ GETTEMPFILENAME$
+ GETVERSION$
+ GETWINDOWSDIRECTORY$
+ GETWINFLAGS$
+ GLOBALALLOC$
+ GLOBALCOMPACT$
+ GLOBALDOSALLOC$
+ GLOBALDOSFREE$
+ GLOBALFLAGS$
+ GLOBALFIX$
+ GLOBALFREE$
+ GLOBALHANDLE$
+ GLOBALLOCK$
+ GLOBALLRUNEWEST$
+ GLOBALLRUOLDEST$
+ GLOBALNOTIFY$
+ GLOBALPAGELOCK$
+ GLOBALPAGEUNLOCK$
+ GLOBALREALLOC$
+ GLOBALSIZE$
+ GLOBALUNFIX$
+ GLOBALUNLOCK$
+ GLOBALUNWIRE$
+ GLOBALWIRE$
+ HMEMCPY$
+ _HREAD$
+ _HWRITE$
+ INITATOMTABLE$
+ INITLIB$
+ INITTASK$
+ ISBADCODEPTR$
+ ISBADHUGEREADPTR$
+ ISBADHUGEWRITEPTR$
+ ISBADREADPTR$
+ ISBADSTRINGPTR$
+ ISBADWRITEPTR$
+ ISDBCSLEADBYTE$
+ ISTASK$
+ _LCLOSE$
+ _LCREAT$
+ LIMITEMSPAGES$
+ _LLSEEK$
+ LOADLIBRARY$
+ LOADMODULE$
+ LOADRESOURCE$
+ LOCALALLOC$
+ LOCALCOMPACT$
+ LOCALFLAGS$
+ LOCALFREE$
+ LOCALHANDLE$
+ LOCALHANDLEDELTA$
+ LOCALINIT$
+ LOCALLOCK$
+ LOCALREALLOC$
+ LOCALSHRINK$
+ LOCALSIZE$
+ LOCALUNLOCK$
+ LOCKRESOURCE$
+ LOCKSEGMENT$
+ LOGERROR$
+ LOGPARAMERROR$
+ LONGPTRADD$
+ _LOPEN$
+ _LREAD$
+ LSTRCAT$
+ LSTRORIGINAL$
+ LSTRCPY$
+ LSTRLEN$
+ _LWRITE$
+ MAKEPROCINSTANCE$
+ NETBIOSCALL$
+ OPENFILE$
+ OPENSYSTEMFILE$
+ OUTPUTDEBUGSTRING$
+ PATCHCODEHANDLE$
+ SELECTORACCESSRIGHTS$
+ SETERRORMODE$
+ SETSELECTORBASE$
+ SETSELECTORLIMIT$
+ SETHANDLECOUNT$
+ SETRESOURCEHANDLER$
+ SETSWAPAREASIZE$
+ SIZEOFRESOURCE$
+ SWAPRECORDING$
+ SWITCHSTACKBACK$
+ SWITCHSTACKTO$
+ THROW$
+ UNDEFDYNLINK$
+ UNLOCKSEGMENT$
+ VALIDATECODESEGMENTS$
+ VALIDATEFREESPACES$
+ WAITEVENT$
+ WINEXEC$
+ WRITEPRIVATEPROFILESTRING$
+ WRITEPROFILESTRING$
+ YIELD$
+ __AHSHIFT$
+ __AHINCR$
+ __0000h$
+ __0040h$
+ __A000h$
+ __B000h$
+ __B800h$
+ __C000h$
+ __D000h$
+ __E000h$
+ __F000h$
+ __ROMBIOS$
+ __WINFLAGS$
+ IACCESSRESOURCE$
+ IADDATOM$
+ IALLOCCSTODSALIAS$
+ IALLOCDSTOCSALIAS$
+ IALLOCRESOURCE$
+ IALLOCSELECTOR$
+ ICATCH$
+ ICHANGESELECTOR$
+ IDEFINEHANDLETABLE$
+ IDELETEATOM$
+ IFATALAPPEXIT$
+ IFINDATOM$
+ IFINDRESOURCE$
+ IFREELIBRARY$
+ IFREEMODULE$
+ IFREEPROCINSTANCE$
+ IFREERESOURCE$
+ IFREESELECTOR$
+ IGETATOMHANDLE$
+ IGETATOMNAME$
+ IGETCODEHANDLE$
+ IGETCODEINFO$
+ IGETDRIVETYPE$
+ IGETFREESPACE$
+ IGETINSTANCEDATA$
+ IGETMODULEFILENAME$
+ IGETMODULEHANDLE$
+ IGETMODULEUSAGE$
+ IGETPRIVATEPROFILEINT$
+ IGETPRIVATEPROFILESTRING$
+ IGETPROCADDRESS$
+ IGETPROFILEINT$
+ IGETPROFILESTRING$
+ IGETSYSTEMDIRECTORY$
+ IGETTEMPDRIVE$
+ IGETTEMPFILENAME$
+ IGETWINDOWSDIRECTORY$
+ IGLOBALALLOC$
+ IGLOBALFIX$
+ IGLOBALFREE$
+ IGLOBALHANDLE$
+ IGLOBALLOCK$
+ IGLOBALLRUNEWEST$
+ IGLOBALLRUOLDEST$
+ IGLOBALNOTIFY$
+ IGLOBALPAGELOCK$
+ IGLOBALPAGEUNLOCK$
+ IGLOBALREALLOC$
+ IGLOBALSIZE$
+ IGLOBALUNFIX$
+ IGLOBALUNLOCK$
+ IGLOBALUNWIRE$
+ IGLOBALWIRE$
+ ILOADLIBRARY$
+ ILOADMODULE$
+ ILOADRESOURCE$
+ ILOCALALLOC$
+ ILOCALFLAGS$
+ ILOCALFREE$
+ ILOCALHANDLE$
+ ILOCALINIT$
+ ILOCALLOCK$
+ ILOCALREALLOC$
+ ILOCALSHRINK$
+ ILOCALSIZE$
+ ILOCALUNLOCK$
+ ILOCKRESOURCE$
+ ILOCKSEGMENT$
+ ILSTRCAT$
+ ILSTRCPY$
+ ILSTRLEN$
+ ILSTRORIGINAL$
+ IMAKEPROCINSTANCE$
+ IOPENFILE$
+ ISETERRORMODE$
+ ISETHANDLECOUNT$
+ ISETRESOURCEHANDLER$
+ ISIZEOFRESOURCE$
+ ISWAPRECORDING$
+ ISWITCHSTACKTO$
+ ITHROW$
+ IUNLOCKSEGMENT$
+ IWINEXEC$
+ IWRITEPRIVATEPROFILESTRING$
+ IWRITEPROFILESTRING$
+ I_LCLOSE$
+ I_LCREAT$
+ I_LLSEEK$
+ I_LOPEN$
+ I_LREAD$ \ No newline at end of file
diff --git a/private/mvdm/wow16/kernel31/reboot.asm b/private/mvdm/wow16/kernel31/reboot.asm
new file mode 100644
index 000000000..d400f396b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/reboot.asm
@@ -0,0 +1,375 @@
+;***************************************************************************
+;* REBOOT.ASM
+;*
+;* Contains routines used to support a local reboot in the Sys
+;* VM. To do this, we interact with USER and the Reboot VxD.
+;*
+;* This functionality is only present in the 386 KERNEL.
+;*
+;* The KRebootInit function is called just after USER is loaded.
+;*
+;* The Reboot VxD calls the local reboot proc to terminate an app.
+;* The local reboot proc may fail and cause the VxD to trace until
+;* it is able to kill the task. See comments in the local reboot
+;* proc for more details.
+;*
+;* This code must be located in KERNEL due to the internal KERNEL
+;* information it must access.
+;*
+;* Created by JonT starting 12 July 1991
+;*
+;***************************************************************************
+
+ TITLE REBOOT - Local Reboot Routines
+
+.xlist
+include kernel.inc
+include tdb.inc
+include protect.inc
+include newexe.inc
+.list
+
+.386p
+
+MAX_TRACE EQU 5000h
+
+HookInt1 MACRO
+ mov ax,0204h ;;Tell VxD to hook/unhook Int 1
+ mov cx,cs ;;Point to ISR
+ mov dx,codeOFFSET TraceOut
+ movzx edx,dx
+ call [lpReboot] ;;Call the VxD API
+ENDM
+
+UnhookInt1 MACRO
+ mov ax,0204h ;;Tell VxD to hook/unhook Int 1
+ xor cx,cx ;;Pass a zero in CX to unhook
+ call [lpReboot] ;;Call the VxD API
+ENDM
+
+DataBegin
+
+externD lpReboot
+externW curTDB
+externW hExeHead
+externW hUser
+externB Kernel_Flags
+externB fTaskSwitchCalled
+externW wMyOpenFileReent
+externB OutBuf
+externW pGlobalHeap
+
+EVEN
+globalW wLastSeg, 0
+globalW wTraceCount, 0
+lpOldInt1 DD 0
+szUser DB 'USER'
+
+DataEnd
+
+externFP Int21Handler
+externFP GetPrivateProfileInt
+IFDEF DBCS
+externFP FarMyIsDBCSLeadByte
+ENDIF
+
+;** Note that this goes in the fixed code segment
+sBegin CODE
+assumes CS,CODE
+
+; KRebootInit
+; Initializes the KERNEL Local Reboot functionality and talks with
+; the Reboot VxD.
+
+cProc KRebootInit, <FAR,PUBLIC>, <si,di,ds>
+cBegin
+ SetKernelDS
+
+ ;** Get the reboot device entry point if it exists
+ xor di,di ;Get a NULL pointer
+ mov es,di ; in case there's no reboot device
+ mov bx,0009h
+ mov ax,1684h ;Get device entry point
+ int 2fh
+ mov ax,es
+ or ax,di
+ jz SHORT RI_NoRebootDev
+ mov WORD PTR lpReboot[0],di
+ mov WORD PTR lpReboot[2],es
+
+ ;** Set the reboot device call back
+ mov ax, 0201h ;Reboot VxD #201: Set callback addr
+ mov di,cs
+ mov es,di
+ lea di,KRebootProc
+ lea si, fTaskSwitchCalled ;DS:SI points to task switch flag
+ call [lpReboot]
+
+RI_NoRebootDev:
+
+cEnd
+
+
+; LocalRebootProc
+;
+; Called by the Reboot VxD to cause the current Windows app to be
+; terminated.
+
+cProc KRebootProc, <FAR,PUBLIC>
+cBegin nogen
+
+ ;** Save all the registers so we can restart if necessary
+ pusha ;16 bytes
+ push ds ;2 bytes
+ push es ;2 bytes
+ SetKernelDS
+ mov bp,sp ;Point with BP
+
+ ;** If the KERNEL debugger is installed, DON'T trace!
+ test Kernel_Flags[2],KF2_SYMDEB ;Debugger installed
+IF KDEBUG
+ jz SHORT RP_CheckSeg ;No debugger, try to trace
+ Trace_Out <'LocalReboot: Debugger installed, nuking app without tracing'>
+ jmp SHORT RP_NukeIt ;Just try to nuke it here!
+ELSE
+ jnz SHORT RP_NukeIt ;Just try to nuke it here!
+ENDIF
+
+ ;** Get the code segment we were executing in
+RP_CheckSeg:
+ mov ax,[bp + 22] ;Get CS from stack (IRET frame)
+
+ ;** See if the owner of the code segment was loaded before USER
+ cCall IsBootSeg ;Returns TRUE if owned by boot mod
+ or ax,ax ;Ok to nuke?
+ jnz RP_TraceOut ;No, must trace out
+
+RP_NukeIt:
+
+ ;** First, we need to get the filename of the .EXE we're about to
+ ;** nuke. We do this by getting the name out of the module
+ ;** database. Module databases are not page locked and also
+ ;** have the fully qualified pathname. So, we copy just the
+ ;** module name into a buffer in our pagelocked data segment
+ cld
+ push ds
+ pop es
+ mov di, dataOFFSET OutBuf ;Point to start of buffer
+ mov ds, curTDB ;Get the current TDB
+ UnSetKernelDS
+ mov ds, ds:[TDB_pModule] ;Point to the module database
+ mov si, WORD PTR ds:[ne_crc + 2] ;Points to length byte of module EXE
+ mov cl, [si] ;Get length byte
+ xor ch, ch
+ sub cl, 8 ;8 bytes of garbage
+ add si, 8
+ mov bx, si ;In case we don't find a slash (bad)
+RP_SlashLoop:
+ lodsb ;Get this char
+IFDEF DBCS
+ call FarMyIsDBCSLeadByte
+ jc SHORT RP_NoDBCSChar
+ lodsb
+ dec cx
+ jmp SHORT RP_NoSlash ;It is, can't be a slash
+RP_NoDBCSChar:
+ENDIF
+ cmp al, '\' ;Is this a slash?
+ je SHORT RP_Slash ;Yes
+ cmp al, '/'
+ jne SHORT RP_NoSlash
+RP_Slash:
+ mov bx, si ;BX points after last slash
+RP_NoSlash:
+ loop RP_SlashLoop
+ mov cx, si ;Compute count of characters in 8.3 name
+ sub cx, bx
+ mov si, bx ;Point to 8.3 name
+ rep movsb ;Copy the string into OutBuf
+ xor al, al ;Zero byte
+ stosb
+
+ ;** Call the VxD to put up the app name
+ push es ;ES points to kernel DS
+ pop ds
+ ReSetKernelDS
+ mov di, dataOFFSET OutBuf ;Point to module name with ES:DI
+ mov ax, 203h ;Display message through VxD
+ call [lpReboot]
+ or ax, ax ;If non-zero, we nuke it
+ jz SHORT RP_NoNuke
+
+IF KDEBUG
+ krDebugOut DEB_WARN, <'LocalReboot: Trying to nuke @ES:DI'>
+ENDIF
+
+ ;** Clean out some static info
+ mov wMyOpenFileReent, 0 ;Clear reentrant flag for MyOpenFile
+
+ ;** Call USER's signal proc for the task
+ mov es,curTDB ;Get the current TDB
+ cmp WORD PTR es:[TDB_USignalProc] + 2,0 ;USER signal proc?
+ jz SHORT @F ;No
+ mov bx,0666h ;Death knell
+ mov di,-1
+ cCall es:[TDB_USignalProc],<es,bx,di,es:[TDB_Module],es:[TDB_Queue]>
+@@:
+
+ ;** Nuke the app. Does not return
+ mov ax,4c00h
+ DOSCALL
+
+ ;** We're somewhere in a boot module. Try to trace out by telling
+ ;** VxD to do another instruction
+RP_TraceOut:
+ mov ax,[bp + 22] ;Get CS from stack (IRET frame)
+IF KDEBUG
+ krDebugOut DEB_WARN, <'LocalReboot: Tracing out of boot module %AX2'>
+ENDIF
+ mov wLastSeg,ax ;Save for next time
+ mov wTraceCount,0 ;Clear the trace count
+ HookInt1
+
+ ;** Set the trace flag
+ or WORD PTR [bp + 24],0100h
+ jmp SHORT RP_SetFlag
+
+ ;** Force the trap flag clear on the no nuke case
+RP_NoNuke:
+ and WORD PTR [bp + 24],NOT 0100h
+
+RP_SetFlag:
+ pop es
+ pop ds
+ popa
+ STIRET ;VxD calls as an interrupt
+cEnd nogen
+
+
+; TraceOut
+;
+; This routine continues to trace until it traces out of a boot module
+; or until the trace count is up. If it needs to nuke the app,
+; it jumps to RP_NukeIt which depends only on DS being set. This
+; call returns via an IRET since it is called as an INT 1 handler.
+
+cProc TraceOut, <FAR,PUBLIC>
+cBegin nogen
+
+ ;** Save all the registers so we can restart if necessary
+ pusha ;16 bytes
+ push ds ;2 bytes
+ push es ;2 bytes
+ SetKernelDS
+ mov bp,sp ;Point with BP
+
+ ;** We keep tracing forever if the heap is locked
+ push es
+ mov es, pGlobalHeap ;Point to GlobalInfo structure
+ cmp es:[gi_lrulock], 0 ;Is the global heap busy
+ pop es
+ jne SHORT TO_10 ;Force the trace out
+
+ ;** See if the CS is the same as last time
+ inc wTraceCount ;Bump the count
+ cmp wTraceCount,MAX_TRACE ;Too many instructions?
+IF KDEBUG
+ jb SHORT TO_10 ;Count not exceeded
+ mov cx,MAX_TRACE ;Get trace count
+ Trace_Out <'LocalReboot: Trace count (#CXh instructions) exceeded'>
+ jmp SHORT TO_Reboot
+ELSE
+ jae SHORT TO_Reboot ;Yes, too many, nuke it
+ENDIF
+
+TO_10: mov ax,[bp + 22] ;Get the CS from the IRET frame
+ cmp ax,wLastSeg ;Same as last time?
+ je SHORT TO_StillBad ;Yes, don't bother looking up
+ mov wLastSeg,ax ;Save as last executed segment
+ mov bx,cs ;Get our CS
+ cmp ax,bx ;Our segment?
+ je SHORT TO_StillBad ;Yes, can't nuke here!
+ cCall IsBootSeg ;Returns TRUE if owned by boot mod
+ or ax,ax ;Ok to nuke?
+ jnz SHORT TO_StillBad ;No, must continue tracing
+IF KDEBUG
+ mov cx,wTraceCount ;Get trace count
+ Trace_Out <'LocalReboot: Traced out after #CXh instructions'>
+ENDIF
+
+ ;** Unhook the interrupt handler and kill the app now
+TO_Reboot:
+ UnhookInt1
+ jmp RP_NukeIt ;Try to nuke the app
+
+ ;** Restore the registers and restart
+TO_StillBad:
+ or WORD PTR [bp + 24],0100h ;Set the trace flag
+ pop es
+ pop ds
+ popa
+ iret ;VxD calls as an interrupt
+
+cEnd nogen
+
+
+; IsBootSeg
+;
+; Tries to find a code segment somewhere in the initial segments
+; loaded before USER. The CS value is passed in AX. Returns
+; TRUE iff the CS was found in a boot module.
+
+cProc IsBootSeg, <NEAR,PUBLIC>
+cBegin nogen
+ SetKernelDS
+ mov dx,ax ;Put CS in DX for call
+ mov es,hExeHead ;Get the first module on chain
+
+IBS_Loop:
+ cCall IsModuleOwner ;See if we can find the owner
+ or ax,ax ;Found?
+ jnz SHORT IBS_End ;Yes, return TRUE
+ mov ax,es ;Get the module handle
+ cmp ax,hUser ;If we just tried USER, we're done
+ je SHORT IBS_NotFound ;Not found
+ mov es,es:[6] ;Nope, get next module to try
+ jmp IBS_Loop
+
+IBS_NotFound:
+ xor ax,ax ;Return FALSE
+
+IBS_End:
+cEnd
+
+
+; IsModuleOwner
+;
+; Checks in the EXE header to see if the given segment is in this
+; module.
+; DX is the segment, ES points to the module database
+; Returns TRUE/FALSE in AX. Doesn't trash DX.
+
+cProc IsModuleOwner, <NEAR,PUBLIC>
+cBegin nogen
+ xor ax,ax ;Get a FALSE just in case
+ mov cx,es:[ne_cseg] ;Get max number of segments
+ jcxz SHORT IMO_End ;No segments
+ mov di,es:[ne_segtab] ;Point to the segment table
+IMO_SegLoop:
+ cmp dx,es:[di].ns_handle ;Is this the correct segment entry?
+ jz SHORT IMO_FoundIt ;Yes, get out
+ add di,SIZE new_seg1 ;Bump to next entry
+ loop IMO_SegLoop ;Loop back to check next entry
+ jmp SHORT IMO_End ;Didn't find it
+
+IMO_FoundIt:
+ mov ax,1 ;Return that we found it here
+
+IMO_End:
+
+cEnd
+
+sEnd
+
+END
+
diff --git a/private/mvdm/wow16/kernel31/resaux.asm b/private/mvdm/wow16/kernel31/resaux.asm
new file mode 100644
index 000000000..51d80caa3
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/resaux.asm
@@ -0,0 +1,1852 @@
+ TITLE RESAUX - support routines for resource manager
+
+.xlist
+include kernel.inc
+include newexe.inc
+include tdb.inc
+include protect.inc
+.list
+
+ifdef WOW
+ WOW_OPTIMIZE_PRELOADRESOURCE = 1
+endif
+
+externA __AHINCR
+externFP _lclose
+externFP GlobalFree
+externFP GlobalLock
+externFP GlobalUnlock
+externFP GlobalFlags
+externFP GlobalReAlloc
+externFP GlobalHandle
+externFP GetExePtr
+externFP MyOpenFile
+externFP FarMyUpper
+;externFP GlobalAlloc
+externFP lstrlen
+externFP lstrOriginal
+externFP Int21Handler
+
+externFP AllocSelector
+externFP FreeSelector
+externFP LongPtrAdd
+ifdef WOW
+externFP WOWFreeResource
+endif
+
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+externFP LongPtrAddWOW
+externFP AllocSelectorWOW
+endif
+
+if KDEBUG
+externFP OutputDebugString
+endif
+
+if ROM
+externFP LZDecode
+externFP FindROMModule
+externNP SetROMOwner
+externNP GetROMOwner
+endif
+
+
+DataBegin
+
+externW Win_PDB
+
+if KDEBUG
+externB fLoadTrace
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MyAlloc
+externNP MyLock
+externNP GetOwner
+externNP SetOwner
+externNP GetCachedFileHandle
+externNP CloseCachedFileHandle
+
+externFP AllocSelectorArray
+externFP set_discarded_sel_owner
+externNP SetResourceOwner
+if PMODE32
+externNP AllocResSelArray
+endif
+ifdef WOW
+externFP hMemCpy
+externFP _HREAD
+externW gdtdsc
+endif
+
+if ROM
+externFP <FreeSelector,GetSelectorBase,SetSelectorBase,SetSelectorLimit>
+endif
+
+
+;-----------------------------------------------------------------------;
+; ;
+; DirectResAlloc - This allocates memory for creating cursors and icons;
+; "on the fly". ;
+; ;
+; Arguments: ;
+; parmW hinstance ; Identifies the instance that allocates ;
+; parmW resFlags ; Flags to be used in memory allocation ;
+; parmW nBytes ; The size of the memory to be allocated ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Fri 06 Jan 1989 -- Written by Sankar. ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc DirectResAlloc, <PUBLIC, FAR>, <si,di>
+ parmW hInstance
+ parmW resFlags
+ parmW nBytes
+
+cBegin
+ cCall GetExePtr, <hInstance>
+ or ax, ax
+ jz err_end
+ push ax ; Save ptr to EXE header
+
+ xor bx, bx
+ cCall MyResAlloc, <ax, resFlags, nBytes, bx>
+ xchg ax,dx
+ pop cx ; restore exe header address
+ or ax,ax
+ jz err_end
+ cCall SetOwner,<ax,cx>
+ xchg ax,dx
+ err_end:
+cEnd
+
+
+cProc MyResAlloc,<PUBLIC,NEAR>
+ parmW hExe
+ parmW resFlags
+ parmW nBytes
+ parmW nAlign
+cBegin
+ mov bx,resFlags ; Allocate memory for
+ or bl,NSTYPE or RNMOVE ; non-code, non-data segment
+ cCall MyAlloc,<bx,nBytes,nAlign>
+ test dl,GA_FIXED
+ jnz mysox
+ mov bx,dx
+
+ HtoS bx ; Make it ring 1
+ lar cx, bx
+ jnz mysox
+ test ch, 80h ; Present?
+ jnz mysox
+int 3
+ mov es, hExe ; Set limit to the owner ie. hExe.
+ cCall set_discarded_sel_owner
+
+mysox:
+ xchg ax,dx
+cEnd
+
+cProc IAllocResource,<PUBLIC,FAR>,<si>
+ parmW hResFile
+ parmW hResInfo
+ parmD newSize
+cBegin
+ cCall GetExePtr,<hResFile>
+ or ax,ax
+ jz arx
+ mov es,ax
+ push es ; Save exe header address
+ mov si,hResInfo
+ push es ; push hexe
+ mov bx,es:[si].rn_flags
+ or bl,NSTYPE ; non-code, non-data segment
+ push bx ; push flags
+ push es:[si].rn_length ; push default size
+ mov bx,es:[ne_rsrctab]
+ mov cx,es:[bx].rs_align
+ mov dx,OFF_newSize
+ or dx,SEG_newSize ; Want a different size?
+ jz ar1 ; No, continue
+ pop dx ; Yes discard default size
+ push cx ; Save alignment shift
+ mov dx,newSize.hi ; Round up new size by alignment
+ xor ax,ax
+ not ax
+ shl ax,cl
+ not ax
+ add ax,newSize.lo
+ adc dx, 0
+ar0:
+ shr dx,1 ; convert to alignment units
+ rcr ax,1
+ loop ar0
+ pop cx ; Restore alignment shift
+ push ax ; Push new size
+ar1:
+ cmp es:[si].rn_handle,0 ; Already a handle?
+ je ar2 ; No, continue
+ pop ax ; AX = length
+ add sp,4 ; ignore flags and hExe
+ xor dx,dx
+ jcxz ma3
+ma2:
+ shl ax,1
+ rcl dx,1
+ loop ma2
+ma3:
+ xor cx,cx
+ cCall GlobalReAlloc,<es:[si].rn_handle,dxax,cx>
+ cwd ; zero dx (may not be needed)
+ or ax,ax ; did it fail?
+ jz ar3
+
+ cCall GlobalHandle,<ax>
+ jmps ar3
+ar2:
+ push cx ; push alignment shift count
+ cCall MyResAlloc ; rn_flags, rn_length, rs_align
+ar3:
+ xchg ax,dx
+ pop cx ; restore exe header address
+ or ax,ax
+ jz arx
+ cCall SetOwner,<ax,cx>
+ xchg ax,dx
+arx:
+ or ax, ax
+ jnz @F
+ KernelLogError DBF_WARNING,ERR_ALLOCRES,"AllocResource failed"
+ xor ax, ax ; Restore the NULL value in ax
+@@:
+ mov cx,ax
+cEnd
+
+
+cProc ResAlloc,<PUBLIC,FAR>,<si,di>
+ parmD pResInfo
+ parmW fh
+ parmW isfh
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ parmW hiResOffset
+ parmW loResOffset
+endif
+ localW hres
+cBegin
+ xor ax,ax
+ cCall IAllocResource,<pResInfo,ax,ax>
+ les si,pResInfo
+ mov hres,ax ; Returns handle in AX
+ mov ax,dx ; Segment address in DX
+ mov bx,es:[ne_rsrctab]
+ mov cx,es:[bx].rs_align
+ mov dx,es:[si].rn_length
+ xor bx,bx
+ cmp hres,bx
+; jnz ra1
+ jz rax
+
+ra1: shl dx,1
+ rcl bx,1
+ loop ra1
+if ROM
+ test es:[si].rn_flags,RNCOMPR ; is this a compressed ROM res?
+ jz not_rom_comp
+ xor si,si
+ cCall LZDecode,<ax,fh,si,si> ; ax=dest, fh=src
+ or ax,ax
+ jz rafail2
+ jmps ra4
+not_rom_comp:
+endif
+ push ds
+ mov cx,dx
+ mov si, bx ; Save hi word of length
+ mov bx,fh
+ cmp isfh,bx ; is bx a file handle?
+ je ra2 ; if so, load from file
+ifdef WOW
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ cmp hiResOffset, 0
+ jz @F
+ push ax
+ mov al, __AHINCR
+ mul byte ptr hiResOffset
+ add bx,ax
+ pop ax
+@@:
+ cCall hMemCpy,<ax,0,bx,loResOffset,si,cx>
+else
+ cCall hMemCpy,<ax,0,bx,0,si,cx>
+endif
+ jmps ra3
+ra2:
+ cCall _hRead,<bx,ax,0,si,cx>
+ cmp dx, si ; If we didn't read what we wanted
+ jnz rafail ; then fail
+ cmp ax, cx
+ jnz rafail
+else ; NOT WOW
+ cCall CopyResource,<ax,bx,si,cx>
+ jmps ra3
+ra2:
+ cCall ReadResource,<ax,bx,si,cx>
+ jc rafail
+endif ; WOW
+ra3:
+ pop ds
+ra4:
+ mov ax,hres
+ jmps rax
+rafail:
+ mov bx,ds
+ pop ds
+rafail2:
+ cCall GlobalFree,<hres>
+if KDEBUG
+ push es
+ mov bx,SEG_pResInfo
+ mov es,bx
+ xor bx,bx
+ KernelLogError <DBF_WARNING>,ERR_BADRESREAD,"Unable to read resource from @ES:BX"
+ pop es
+endif
+ xor ax,ax
+rax:
+cEnd
+
+cProc CopyResource,<PUBLIC,NEAR>
+ parmW DestSeg
+ parmW SrcSeg
+ parmD nBytes
+cBegin
+ push es
+ mov ds, SrcSeg ; bx is segment of resource
+ mov es, DestSeg
+ xor si, si
+ xor di, di
+ cld
+rc_next:
+ mov cx, 8000h
+ cmp word ptr [nBytes+2], 0
+ clc ; No odd byte to copy
+ jne big_copy
+ mov cx, word ptr [nBytes]
+ shr cx, 1 ; Word count
+big_copy:
+ rep movsw
+ rcl cx, 1 ; Rescue low bit
+ rep movsb ; Any odd byte
+
+ dec word ptr [nBytes+2]
+ js rc_done
+
+ mov ax, ds
+ add ax, __AHINCR
+ mov ds, ax
+ mov ax, es
+ add ax, __AHINCR
+ mov es, ax
+ jmp rc_next
+
+rc_done:
+ pop es
+cEnd
+
+cProc ReadResource,<PUBLIC,NEAR>
+ parmW DestSeg
+ parmW fh
+ parmD nBytes
+cBegin
+ mov bx, fh
+ xor dx, dx
+ mov ds, DestSeg
+ mov di, word ptr nBytes
+ mov si, word ptr [nBytes+2]
+around_again:
+ mov cx, 8000h
+ or si, si
+ jnz big_xfer
+ cmp di, cx
+ jae big_xfer
+ mov cx, di
+big_xfer:
+ mov ah, 3Fh
+ DOSCALL
+ jc rrfail
+ cmp ax, cx
+ jne rrfail
+
+ sub di, cx
+ sbb si, 0
+ jnz incr_address
+ or di, di
+ jz rrdone
+incr_address:
+ add dx, cx
+ jnc around_again
+ mov ax, ds
+ add ax, __AHINCR
+ mov ds, ax
+ jmp around_again
+
+rrfail:
+ stc
+ jmps rrx
+rrdone:
+ clc
+rrx:
+cEnd
+
+cProc IAccessResource,<PUBLIC,FAR>
+ parmW hResFile
+ parmW hResInfo
+cBegin
+ xor ax, ax
+ cCall InternalAccessResource,<hResFile,hResInfo,ax>
+cEnd
+
+cProc InternalAccessResource,<PUBLIC>
+ parmW hResFile
+ parmW hResInfo
+ parmW CachedFile
+cBegin
+ cCall GetExePtr,<hResFile>
+ mov es,ax
+ mov bx, hResInfo
+ mov ax,es:[bx].rn_flags
+if ROM
+ test es:[ne_flags],NEMODINROM
+ jnz @f
+ test ax, RNINROM or RNCOMPR
+ jz iar_ok
+@@:
+if KDEBUG
+ Debug_Out "InternalAccessResource called for ROM resource!"
+endif
+ jmps ra2b
+iar_ok:
+endif
+ push es:[bx].rn_length
+ push es:[bx].rn_offset
+ mov dx,es:[ne_pfileinfo]
+ mov bx,es:[ne_rsrctab]
+ mov cx,es:[bx].rs_align
+ push cx
+ push es
+ cmp CachedFile, 0
+ je open_it
+ mov cx, -1
+ cCall GetCachedFileHandle,<es,cx,cx>
+ mov bx, ax
+ jmps got_fh
+open_it:
+if SHARE_AWARE
+ mov bx,OF_REOPEN or OF_VERIFY or OF_NO_INHERIT or OF_SHARE_DENY_WRITE
+else
+ mov bx,OF_REOPEN or OF_VERIFY or OF_NO_INHERIT
+endif
+ regptr esdx,es,dx
+ push es
+ push dx
+ cCall MyOpenFile,<esdx,esdx,bx> ; returns handle in ax & bx
+ pop dx
+ pop es
+;;; cmp ax, -1 ; Success?
+;;; jne got_fh ; yes.
+;;; ; no, try compatibility mode
+;;; mov bx,OF_REOPEN or OF_VERIFY or OF_NO_INHERIT
+;;; regptr esdx,es,dx
+;;; cCall MyOpenFile,<esdx,esdx,bx> ; returns handle in ax & bx
+got_fh:
+ pop es
+ pop cx
+ pop dx
+ inc ax
+ jnz ra2c
+ pop dx
+ra2b:
+ mov bx,-1
+ jmps ra2x
+ra2c:
+ xor ax,ax
+ push cx
+AR_shift:
+ shl dx,1
+ rcl ax,1
+ loop AR_shift
+ mov cx,ax
+ mov ax,4200h
+ DOSCALL
+ pop cx
+ pop dx
+ jc ra2b
+ xor ax,ax
+AR_shift1:
+ shl dx,1
+ rcl ax,1
+ loop AR_shift1
+ mov cx,ax ; CX:DX is size of resource
+ra2x:
+ mov ax,bx ; AX and BX are file handle
+cEnd
+
+cProc ILockResource,<PUBLIC,FAR>,<si>
+ parmW hres
+ localD lpfn
+cBegin
+ mov ax,hres ; Get object handle
+ or ax,ax
+ jnz short_rel
+lrfail0:
+ jmp lrfail
+short_rel:
+
+ifdef WOW
+ test ax, GA_WOWHANDLE ; should we call WOW32 FreeResource?
+ jnz @f
+ jmp lrfail
+
+@@:
+endif; WOW
+
+ cCall GlobalLock,<ax> ; Attempt to lock it
+ jcxz yawn
+ jmp lrx
+yawn:
+if ROM
+ cCall GetROMOwner,<hres> ; GlobalLock failed, is it in ROM?
+ or ax,ax
+ jz not_in_rom
+ mov dx,hres ; It's in ROM so just return
+ xor ax,ax ; the pointer to it
+ jmp lrx
+not_in_rom:
+endif
+ mov bx,hres ; Failed, is it fixed?
+ test bl,GA_FIXED
+ jnz lrfail0 ; Yes, fail all the way
+
+ HtoS bx
+if PMODE32
+; On WOW we don't copy the owner to the real LDT since it is slow to call
+; the NT Kernel, so we read our copy of it directly.
+; see set_discarded_sel_owner mattfe mar 23 93
+
+ push cx
+ lar cx, bx
+ pop cx
+ jnz lrfail0 ; NZ -> LAR failed
+ mov es,cs:gdtdsc
+ and bl, not 7
+ mov bx,es:[bx].dsc_owner
+else
+ lsl bx, bx ; No, get the owner
+ jnz lrfail0
+endif
+ mov es,bx
+ assumes es,nothing
+ cmp es:[ne_magic],NEMAGIC ; Does owner point to EXE header?
+ jne lrfail ; No, fail.
+ mov bx,es:[ne_rsrctab] ; Yes, scan resource table
+ cmp es:[ne_restab],bx ; Is there a resource table?
+ je lrfail ; No, just free the global object
+ push ds
+ SetKernelDS
+ pop ds
+ assumes ds, nothing
+ mov dx,hres ; Yes, look for this handle
+ add bx,SIZE NEW_RSRC ; Point to first resource type
+lrloop0:
+ cmp es:[bx].rt_id,ax ; End of table?
+ je lrfail ; Yes, just return failure
+ lea si,[bx].rt_proc ; Remember address of type proc.
+ mov cx,es:[bx].rt_nres
+ add bx,SIZE RSRC_TYPEINFO ; Point to first resource of this type
+lrloop:
+ cmp es:[bx].rn_handle,dx ; Is this the one?
+ je lr3 ; Yes, go see if type proc to call
+ add bx,SIZE RSRC_NAMEINFO ; No, point to next resource
+ loop lrloop ; Any more resources for this type?
+ jmps lrloop0 ; No, advance to next type
+lr3:
+ cmp word ptr es:[si+2],0 ; Was there a proc defined for this type
+ je lrfail ; No, return failure.
+
+if KDEBUG
+ jmp PrintInfo
+PrintedInfo:
+endif
+ push ds ; preserve these registers across call
+ push es
+ push bx
+
+ mov ax,word ptr es:[si] ; set up proc addr to call on stack
+ mov word ptr lpfn,ax
+ mov ax,word ptr es:[si]+2
+ mov word ptr lpfn+2,ax
+
+ mov cx,es ; cx = es for later push
+
+ mov ax,ss ; Zap segment registers so he can't
+ mov es,ax ; diddle DS
+ mov ds,ax
+
+ cCall lpfn,<dx,cx,bx> ; Yes, call proc to reload
+
+ xchg ax,cx ; cx = result
+ jcxz @F ; skip lock if NULL
+
+ cCall GlobalLock,<cx> ; Attempt to lock result
+@@:
+ pop bx
+ pop es
+ pop ds
+ jcxz lrfail
+ or byte ptr es:[bx].rn_flags,RNLOADED ; Mark loaded
+ jmps lrx
+lrfail: ; Here to return failure.
+ KernelLogError DBF_WARNING,ERR_LOCKRES,"LockResource failed"
+ xor ax,ax
+ cwd
+lrx:
+cEnd
+
+if KDEBUG
+RCTypes:
+ db 'Custom', 0
+ db 'Cursor', 0
+ db 'Bitmap', 0
+ db 'Icon', 0
+ db 'Menu', 0
+ db 'Dialog', 0
+ db 'String', 0
+ db 'FontDir', 0
+ db 'Font', 0
+ db 'Accelerator', 0
+ db 'RCData', 0
+ db 'Type11', 0
+ db 'GroupCursor', 0
+ db 'Type13', 0
+ db 'GroupIcon', 0
+ db 0
+PrintInfo:
+ pusha
+ mov cx, word ptr es:[si][rt_id-rt_proc]
+ and ch, not 80h
+ mov si, offset RCTypes
+pi_1: inc si
+pi_2: cmp byte ptr cs:[si], 0
+ jnz pi_1
+ inc si
+ cmp byte ptr cs:[si], 0
+ loopnz pi_2
+ jnz @F
+ mov si, offset RCTypes
+@@:
+ mov ax, es:[bx].rn_id
+; test ah, 80h
+; jz pi_name
+ and ah, not 80h
+ krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "%es0: reading resource @CS:SI.#ax"
+; jmps pi_done
+;pi_name:
+; int 3
+; krDebugOut <DEB_TRACE or DEB_krLoadSeg>, "%es0: reading resource @CS:SI.@ES:AX"
+;pi_done:
+ popa
+ jmp PrintedInfo
+endif
+
+
+cProc IFreeResource,<PUBLIC,FAR>,<ds,si>
+ parmW hres
+cBegin
+ mov ax,hres ; Get segment address of resource
+ or ax,ax
+ jz frxj
+ifdef WOW
+ test ax, GA_WOWHANDLE ; should we call WOW32 FreeResource?
+ jnz @f
+ cCall WOWFreeResource,<ax> ; you bet !
+ xor ax, ax
+ jmp frxx
+
+@@:
+endif; WOW
+ cCall MyLock,<ax>
+ or ax,ax ; Discarded or invalid handle?
+ jnz fr0a ; No, continue
+ mov bx,hres
+
+ test bl,GA_FIXED
+ jnz fr2 ; Return NULL
+ HtoS bx ; Fix RPL so we can do LAR
+ lar cx, bx
+ jnz fr2 ; LAR failed, return NULL
+ test ch, 80h ; Present?
+ jnz fr2 ; yes, return NULL
+if PMODE32
+; On WOW we don't copy the owner to the real LDT since it is slow to call
+; the NT Kernel, so we read our copy of it directly.
+; see set_discarded_sel_owner mattfe mar 23 93
+
+ mov ds,cs:gdtdsc
+ and bl, not 7
+ mov cx,ds:[bx].dsc_owner
+ mov ds,cx
+else
+ lsl cx, bx ; Get owner
+ mov ds, cx
+endif
+ jmps fr0b
+frxj:
+ jmps frx
+
+fr0a:
+ cCall GetOwner,<ax>
+ mov ds,ax
+ xor ax,ax
+
+fr0b:
+ cmp ds:[ne_magic],NEMAGIC ; Is it an exe header?
+ jne fr1 ; No, just free the handle
+ mov bx,ds:[ne_rsrctab]
+ cmp ds:[ne_restab],bx ; Is there a resource table?
+ je fr1 ; No, just free the handle
+ mov dx,hres
+ add bx,SIZE NEW_RSRC ; Point to first resource type
+frloop0:
+ cmp ds:[bx].rt_id,ax ; End of table?
+ je fr1 ; Yes, just free the handle
+ mov cx,ds:[bx].rt_nres
+ add bx,SIZE RSRC_TYPEINFO ; Point to first resource of this type
+frloop:
+ cmp ds:[bx].rn_handle,dx ; Is this the one?
+ je fr0 ; Yes, go decrement usage count
+ add bx,SIZE RSRC_NAMEINFO ; No, point to next resource
+ loop frloop ; Any more resources for this type?
+ jmps frloop0 ; No, advance to next type
+fr0:
+ cmp ds:[bx].rn_usage,ax ; Already zero?
+ je fr1a ; Yes, then free this resource now
+ dec ds:[bx].rn_usage ; Decrement use count
+ jg frx ; Positive means still in use
+ test ds:[bx].rn_flags,RNDISCARD ; Discardable?
+ jnz fr2 ; Yes, let discard logic toss it
+fr1a:
+ mov ds:[bx].rn_handle,ax ; o.w. free memory now
+ and byte ptr ds:[bx].rn_flags,not RNLOADED ; Mark not loaded
+if ROM
+ mov ax,ds:[bx].rn_flags ; If the resource is in ROM,
+ and ax,RNINROM OR RNPURE OR RNCOMPR ; uncompressed, and pure,
+ cmp ax,RNINROM OR RNPURE ; only it's selector needs
+ jnz fr1 ; to be freed
+ cCall FreeSelector,<hres>
+ jmps frxx
+endif
+fr1:
+ cCall GlobalFree,<hres> ; Free global object
+fr2:
+ mov hres,ax
+frx:
+ mov ax,hres ; Return zero if freed, hres o.w.
+frxx:
+cEnd
+
+
+cProc ISizeofResource,<PUBLIC,FAR>
+ parmW hResFile
+ parmW hResInfo
+cBegin
+ cCall GetExePtr,<hResFile>
+ mov es,ax
+ mov bx,hResInfo
+ mov ax,es:[bx].rn_length
+ xor dx,dx
+ mov bx,es:[ne_rsrctab]
+ mov cx,es:[bx].rs_align
+sr0: shl ax,1
+ rcl dx,1
+ loop sr0
+cEnd
+
+
+cProc DefaultResourceHandler,<PUBLIC,FAR>,<si,di>
+ parmW hRes
+ parmW hResFile
+ parmW hResInfo
+ localW SavePDB
+cBegin
+ cCall GetExePtr,<hResFile>
+ or ax,ax
+ jz drhx
+ mov si,ax
+ mov cx,hRes ; if hRes == NULL, we need to allocate.
+ jcxz @F
+ cCall GlobalHandle,<cx>
+ or dx,dx ; Nothing to do for allocated resources
+ jnz drhx
+@@:
+if ROM
+ mov es,si
+ mov bx, hResInfo
+ test es:[bx].rn_flags, RNINROM or RNCOMPR
+ jz drh_file
+ cCall DefROMResHandler,<si,hResInfo>
+ jmps drhx
+drh_file:
+endif
+ SetKernelDS
+ mov ax, Win_PDB ; Save current PDB
+ mov SavePDB, ax
+ mov ax, 1
+ cCall InternalAccessResource,<si,hResInfo,ax>
+ mov di,ax
+ inc ax
+ jz drhx
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ cCall ResAlloc,<si,hResInfo,di,di, 0, 0>
+else
+ cCall ResAlloc,<si,hResInfo,di,di>
+endif
+ push ax
+;;; cCall _lclose,<di>
+ push bx
+ cCall CloseCachedFileHandle,<di>
+ mov bx, SavePDB
+ mov Win_PDB, bx ; Restore PDB
+ pop bx
+ pop ax
+drhx:
+cEnd
+
+if ROM
+
+cProc DefROMResHandler,<PUBLIC,NEAR>
+ parmW hExe
+ parmW hResInfo
+ localW selTemp
+cBegin
+ cCall FindROMModule,<hExe> ; allocates a selector to ROM EXE header
+ mov selTemp,ax ; returns 0 if not in ROM
+ inc ax
+ jz @F
+ dec ax
+ jz @F
+@@:
+ jmp short drr_gotsel
+if KDEBUG ;shouldn't happen except out of sels...
+ int 3 ;*******************************
+endif
+ jmp drrx
+
+drr_gotsel:
+ mov es, hExe
+ mov si,hResInfo
+ mov bx,es:[ne_rsrctab]
+ mov cx,es:[bx].rs_align
+ mov ax,es:[si].rn_offset
+ xor bx,bx
+@@: shl ax,1
+ rcl bx,1
+ loop @b
+ mov cx,ax ; bx:cx = offset of resource from hdr
+
+ cCall GetSelectorBase,<selTemp>
+ add ax,cx
+ adc dx,bx ; dx:ax = lma of resource
+
+ if1
+ %out Doesn't work if resource > 64k!
+ endif
+
+ cCall SetSelectorBase,<selTemp,dx,ax>
+
+ ; Pure uncompressed resources can be used as is in ROM.
+
+ mov es,hExe
+ test byte ptr es:[si].rn_flags+1,(RNCOMPR SHR 8)
+ jnz res_to_ram
+ test byte ptr es:[si].rn_flags,RNPURE
+ jz res_to_ram
+
+ mov si,hResInfo ; set selector limit for
+ mov bx,es:[ne_rsrctab] ; this resource
+ mov cx,es:[bx].rs_align
+ mov ax,es:[si].rn_length
+ xor bx,bx
+@@: shl ax,1
+ rcl bx,1
+ loop @b
+
+ sub ax,1 ; limit is len - 1
+ sbb bx,0
+
+ cCall SetSelectorLimit,<selTemp,bx,ax>
+
+ cCall SetROMOwner,<selTemp,hExe> ; this EXE owns the resource
+ mov ax,selTemp
+ jmps drrx
+
+res_to_ram:
+
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ cCall ResAlloc,<es,hResInfo,ax,-1, 0, 0> ; has to be loaded into ram...
+else
+ cCall ResAlloc,<es,hResInfo,ax,-1> ; has to be loaded into ram...
+endif
+
+ push ax
+ cCall FreeSelector,<selTemp> ; don't need sel in this case
+ pop ax
+drrx:
+cEnd
+
+endif ;ROM
+
+;-----------------------------------------------------------------------;
+; LoadResource ;
+; ;
+; Called by each task ONCE to load a resource. ;
+; If this is the VERY FIRST time this resource is loaded ;
+; AND it is fixed, then the resource handler proc is called. ;
+; AND it is discardable then only a handle is allocated. We wait ;
+; until LockResource to actually load the resource. ;
+; ;
+; If the resource had been loaded by a previous task ;
+; then we load it if it has been discarded. ;
+; ;
+; Arguments: ;
+; HANDLE hResFile ;
+; HANDLE hResInfo ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Jan 01, 1980 07:23:34p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc ILoadResource,<PUBLIC,FAR>,<di,si>
+
+ parmW hResFile
+ parmW hResInfo
+ localV DscBuf,DSC_LEN
+ localD lpfn
+cBegin
+ mov di,hResInfo ; DI = pName
+ or di,di
+ jnz got_a_hResInfo
+ jmp lr_error_ret
+got_a_hResInfo:
+
+ cCall GetExePtr,<hResFile>
+ or ax,ax
+ jnz got_a_resource_file
+ jmp lr_error_ret
+got_a_resource_file:
+
+ mov ds,ax ; DS = pExe
+ mov si,ds:[ne_rsrctab] ; DS:SI = pRes
+ cmp si,ds:[ne_restab]
+ jnz got_a_resource_table
+ jmp lr_error_ret
+got_a_resource_table:
+
+; If first LoadResource on resource, then call resource handler proc
+; associated with resource type.
+
+ mov ax,[di].rn_usage
+ or ax,ax
+ jz maybe_load_it
+got_it: inc [di].rn_usage
+ mov ax,[di].rn_handle
+ jmp lr_ret
+
+; IF
+; 1) the resource is discardable
+; 2) and has been loaded before
+; 3) and has been FreeResource'd
+; 4) but not yet discarded (See FreeResource for this madness!)
+; THEN
+; 1) the usage count is zero
+; 2) it's still marked loaded
+; 3) it's still in memory
+
+maybe_load_it:
+ cmp ax,[di].rn_handle ; we know that ax == rn_usage == 0
+ jz not_loaded_before
+ test [di].rn_flags,RNLOADED
+ jz load_it
+ cCall GlobalFlags,<[di].rn_handle>
+ test ah,HE_DISCARDED
+ jz got_it
+ jmps load_it
+
+not_loaded_before:
+ test [di].rn_flags,RNDISCARD
+ jz load_it
+
+; Allocate a zero length object to get a handle.
+
+ push si
+ mov ax, [di].rn_length
+ xor dx, dx
+ mov bx, ds:ne_rsrctab
+ mov cx, [bx].rs_align
+fred:
+ shl ax, 1
+ rcl dx, 1
+ loop fred
+
+ add ax, 15
+ adc dx, 0
+ mov cx, dx
+ inc cx ; # selectors
+if PMODE32
+;; WOW x86 only
+ cCall AllocResSelArray,<cx,ds>
+ jz no_sel
+else
+ push cx
+ cCall AllocSelectorArray,<cx>
+ pop cx
+ or ax, ax
+ jz no_sel ; got selectors?
+ or al, SEG_RING
+ cCall SetResourceOwner,<ax,ds,cx>
+endif; WOW
+ StoH al
+no_sel:
+ pop si
+ mov [di].rn_handle,ax
+ jmp got_it
+load_it:
+ lea si,[si].SIZE new_rsrc ; DS:SI = pType
+lr_type_loop:
+ cmp [si].rt_id,0
+ jz lr_error_ret
+ lea bx,[si].SIZE rsrc_typeinfo ; BX =pName1
+ mov ax,word ptr [si].rt_proc[0]
+ or ax,word ptr [si].rt_proc[2]
+ jz lr_skip_name
+ mov cx,[si].rt_nres
+ jcxz lr_next_type
+lr_name_loop:
+ cmp bx,di
+ jnz lr_next_name
+
+ push ds ; Zap segment registers to prevent
+
+ mov ax,word ptr [si].rt_proc
+ mov word ptr lpfn,ax
+ mov ax,word ptr [si].rt_proc+2
+ mov word ptr lpfn+2,ax
+
+ push [di].rn_handle
+ push hResFile
+ push hResInfo
+
+ mov ax,ss ; callee from trashing our DS.
+ mov ds,ax
+ mov es,ax
+
+ call lpfn
+
+ pop ds
+
+ or ax,ax
+ jz lr_ret
+ mov [di].rn_handle,ax
+ or [di].rn_flags,RNLOADED
+ jmp got_it
+
+lr_next_name:
+ add bx,SIZE rsrc_nameinfo
+ loop lr_name_loop
+ jmps lr_next_type
+
+lr_skip_name:
+ mov ax,[si].rt_nres
+ mov cx,SIZE rsrc_nameinfo
+ mul cx
+ add bx,ax
+
+lr_next_type:
+ mov si,bx
+ jmp lr_type_loop
+
+
+lr_error_ret:
+if KDEBUG
+ xor bx,bx
+ kerror ERR_BADRESFILE,<Error loading from resource file - >,ds,bx
+endif
+ xor ax,ax
+lr_ret:
+
+cEnd
+
+sEnd CODE
+
+
+sBegin MISCCODE
+assumes CS,MISCCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MISCMapDStoDATA
+
+cProc GetResOrd,<PUBLIC,NEAR>,<si,di>
+ parmW hResFile
+ parmD lpszType
+ parmD lpszName
+ localW hRes
+cBegin
+ cCall OrdinalOrString, <lpszType>
+ mov si,ax
+ cCall OrdinalOrString, <lpszName>
+ mov di,ax
+
+gro_maybe_search_nametable:
+;
+; First see if we need to search the name table at all (if we have ordinals
+; already, we don't need to do the search).
+;
+ xor ax,ax
+ cmp si,ax
+ jz gro_do_search_nametable
+ or ax,di
+ jnz gro_exit1 ; Both are ordinals - just exit
+ or ax,seg_lpszName ; If lpszName is NULL, exit because
+ jnz gro_do_search_nametable ; we have the type ordinal.
+
+gro_exit1:
+ jmp gro_exit
+
+gro_do_search_nametable:
+ cCall GetExePtr,<hResFile>
+ mov es,ax
+ mov bx,es:[ne_rsrctab]
+ cmp bx,es:[ne_restab]
+ jz gro_exit1
+
+ add bx,SIZE new_rsrc
+
+gro_check_resource_type:
+ cmp es:[bx].rt_id,0
+ jz gro_exit1
+ cmp es:[bx].rt_id,(RT_NAMETABLE OR RSORDID)
+ jz gro_found_resource_table_entry
+
+ mov cx,es:[bx].rt_nres
+ add bx,SIZE RSRC_TYPEINFO
+
+ ; add 12*nres to bx (12*size of resource)
+
+ .errnz ((SIZE RSRC_NAMEINFO) - 12)
+
+ shl cx,1
+ shl cx,1
+ add bx,cx
+ shl cx,1
+ add bx,cx
+ jmps gro_check_resource_type
+
+
+gro_found_resource_table_entry:
+ add bx,SIZE RSRC_TYPEINFO
+ mov ax,es:[bx].rn_handle
+ or ax,ax
+ jnz gro_have_handle_nametable
+
+ xor ax,ax
+ mov dx,1
+ mov bx,RT_NAMETABLE
+ cCall <far ptr IFindResource>,<hResFile,ax,dx,ax,bx>
+ or ax,ax
+ jz gro_exit1
+
+ push ds ; DS not even really used probably
+ cCall MISCMapDStoDATA ; Hack, need DS pointing to something
+ cCall ILoadResource,<hResFile,ax> ; with a handle
+ pop ds
+ or ax,ax
+ jnz gro_have_handle_nametable
+gro_exit2:
+ jmp gro_exit
+
+gro_have_handle_nametable:
+
+ mov hRes,ax
+ push ds ; DS not even really used probably
+ cCall MISCMapDStoDATA ; Hack, need DS pointing to something
+ cCall ILockResource,<ax> ; with a handle
+ pop ds
+
+ mov cx,ax
+ or cx,dx
+ jcxz gro_exit2
+
+ mov es,dx ; es:bx is a pointer to resource
+ mov bx,ax
+
+;
+; Now we have a pointer to the resource. Scan through the name table and
+; find a match in the table with the passed type/name.
+; SI = type ordinal, 0 if string type
+; DI = name ordinal, 0 if string name
+;
+gro_nametable_loop:
+
+ or si,si
+ jz gro_do_type_string_match
+
+ cmp si,es:[bx].ntbl_idType
+ jnz gro_next_nametable_entry
+ jmps gro_do_name_match
+
+gro_do_type_string_match:
+
+ push es ; Save pntbl
+ push bx
+
+ lea ax,es:[bx].ntbl_achTypeName
+ push es
+ push ax
+ push seg_lpszType
+ push off_lpszType
+ call lstrOriginal ; compare against type name
+
+ pop bx ; Restore pntbl
+ pop es
+
+ or ax,ax
+ jnz gro_next_nametable_entry
+
+gro_do_name_match:
+
+ or di,di
+ jz gro_do_name_string_match
+
+ cmp di,es:[bx].ntbl_idName
+ jnz gro_next_nametable_entry
+ jmps gro_found_nametable_match
+
+gro_do_name_string_match:
+
+ cmp seg_lpszName, 0
+ jne want_name
+ mov si,es:[bx].ntbl_idType ; Hey man, can't check name!
+ jmps gro_unlock_resource
+
+want_name:
+ push es ; push pntbl for later restoration
+ push bx
+
+ push es ; push pntbl for later strcmp
+ push bx
+ lea ax,es:[bx].ntbl_achTypeName
+
+ push es
+ push ax
+ call lstrlen ; get string length
+
+ mov bx,sp ; Adjust pointer on stack to point
+ add ss:[bx],ax ; past first string
+ add word ptr ss:[bx],ntbl_achTypeName + 1
+ push seg_lpszName
+ push off_lpszName
+ call lstrOriginal
+
+ pop bx
+ pop es
+
+ or ax,ax
+ jz gro_found_nametable_match
+
+gro_next_nametable_entry:
+
+ add bx,es:[bx].ntbl_cbEntry
+ cmp es:[bx].ntbl_cbEntry,0
+ jnz gro_nametable_loop
+ jmps gro_unlock_resource
+
+gro_found_nametable_match:
+
+ mov ax,es:[bx].ntbl_idType
+ test ax,RSORDID
+ jz gro_try_replace_name
+ mov si,ax
+
+gro_try_replace_name:
+
+ mov ax,es:[bx].ntbl_idName
+ test ax,RSORDID
+ jz gro_unlock_resource
+ mov di,ax
+
+gro_unlock_resource:
+
+ push hRes
+ call GlobalUnlock
+
+gro_exit:
+ xor ax,ax
+ cwd
+ or ax,si
+ jz gro_test_name_ordinal
+ or ax,RSORDID
+
+gro_test_name_ordinal:
+ or dx,di
+ jz gro_leave
+ or dx,RSORDID
+
+gro_leave:
+cEnd
+
+cProc OrdinalOrString, <PUBLIC, NEAR>, <si>
+ parmD s
+cBegin
+ les si,s
+ mov cx,si
+ mov ax,es
+ or ax,ax
+ jz codone
+ xor cx,cx ; sum = zero
+ cld
+ lods byte ptr es:[si] ; c = *pName++
+ cmp al,'#'
+ jne codone
+coloop:
+ lods byte ptr es:[si] ; c = *pName++
+ or al,al ; if (!c) break;
+ jz codone
+ sub al,'0' ; if (!isdigit(c))
+ cmp al,9
+ ja codone ;
+ xor ah,ah
+ mov bx,ax ; sum = (sum * 10) + (c - '0')
+ mov al,10
+ mul cx
+ add ax,bx
+ mov cx,ax
+ jmp coloop
+codone:
+ mov ax,cx
+coexit:
+cEnd
+
+cProc CmpResStr,<PUBLIC,NEAR>,<ds,si>
+ parmD pRes
+ parmW id
+ parmD s
+cBegin
+ mov ax,id
+ test ax,RSORDID
+ jnz crsneq
+ lds si,pRes
+ add si,ax
+ xor ax,ax
+ cld
+ lodsb
+ mov cx,ax
+ les bx,s
+crsloop:
+ mov al,es:[bx]
+ inc bx
+ or al,al
+ jz crsneq
+ call FarMyUpper
+ mov ah,al
+ lodsb
+ cmp ah,al
+ jne crsneq
+ loop crsloop
+ xor ax,ax
+ cmp es:[bx],al
+ jne crsneq
+ not ax
+ jmps crsexit
+crsneq:
+ xor ax,ax
+crsexit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; SetResourceHandler ;
+; ;
+; Sets the resource handler for the given type. ;
+; ;
+; Note that the string pointed to can be the resource ID. In this ;
+; case the string should have the form #ID. ;
+; ;
+; If the seg of pointer = 0, then the offset is taken as the ID. ;
+; ;
+; Arguments: ;
+; HANDLE hResFile ;
+; char far *lpszType ;
+; FARPROC lpHandler ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; GetExePtr ;
+; GetResOrd ;
+; CmpResStr ;
+; ;
+; History: ;
+; ;
+; Tue Jan 01, 1980 04:13:03p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly and added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc ISetResourceHandler,<PUBLIC,FAR>,<di,si>
+
+ parmW hResFile
+ parmD lpszType
+ parmD lpHandler
+cBegin
+ cCall GetExePtr,<hResFile>
+ mov ds,ax ; DS = pExe
+ mov si,ds:[ne_rsrctab] ; DS:SI = pRes
+ cmp si,ds:[ne_restab]
+ jz srh_type_not_found ; No resources in this module!
+
+;
+; Pass the type string and NULL for the name string. AX = type ordinal, 0
+; if it doesn't exist.
+;
+ push hResFile
+ push seg_lpszType
+ push off_lpszType
+ xor ax,ax
+ push ax
+ push ax
+ call GetResOrd
+
+ lea di,[si].SIZE new_rsrc ; DS:DI = pType
+srh_type_loop:
+ mov cx,[di].rt_id
+ jcxz srh_type_not_found
+ push ax ; typeord
+ or ax,ax
+ jz srh_compare_string
+ cmp ax,cx
+ jz srh_type_found
+ jmps srh_next_type
+srh_compare_string:
+ cCall CmpResStr,<ds,si,cx,lpszType>
+ or ax,ax
+ jnz srh_type_found
+srh_next_type:
+ mov ax,[di].rt_nres
+ mov cx,SIZE rsrc_nameinfo
+ mul cx
+ add ax, SIZE rsrc_typeinfo
+ add di,ax
+ pop ax
+ jmp srh_type_loop
+
+srh_type_found:
+ pop ax ; clean stack
+ mov dx,word ptr lpHandler[2]
+ mov ax,word ptr lpHandler[0]
+ xchg dx,word ptr [di].rt_proc[2]
+ xchg ax,word ptr [di].rt_proc[0]
+ jmps srh_ret
+
+srh_type_not_found:
+ xor ax,ax
+ xor dx,dx
+srh_ret:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; FindResource ;
+; ;
+; Returns a near pointer (into the module database) to the resource ;
+; description structure. ;
+; ;
+; Note that the string pointed to can be the resource ID. In this ;
+; case the string should have the form #ID. ;
+; ;
+; If the seg of pointer = 0, then the offset is taken as the ID. ;
+; ;
+; Arguments: ;
+; HANDLE hResFile ;
+; char far *lpszName ;
+; char far *lpszType ;
+; ;
+; Returns: ;
+; AX = near pointer to resource description structure. ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; GetExePtr ;
+; GetResOrd ;
+; CmpResStr ;
+; ;
+; History: ;
+; ;
+; Tue Jan 01, 1980 10:00:15p -by- David N. Weise [davidw] ;
+; ReWrote it from C into assembly and added this nifty comment block. ;
+; Wed May 31, 1989 09:17:00a -by- Scott R. Ludwig [scottlu]
+; Rewrote so that string identifiers map to ordinals through an indirection
+; table called a 'name table'. For OS/2 .EXE Compatibility.
+;-----------------------------------------------------------------------;
+
+cProc IFindResource,<PUBLIC,FAR>,<di,si>
+
+ parmW hResFile
+ parmD lpszName
+ parmD lpszType
+ localW typeord
+ localW nameord
+cBegin
+ cCall GetExePtr,<hResFile>
+ mov ds,ax ; DS = pExe
+ mov si,ds:[ne_rsrctab] ; DS:SI = pRes
+ cmp si,ds:[ne_restab]
+ jz fr_error_ret
+
+;
+; Get resource ordinals. ax = type ordinal, dx = name ordinal. (0 if not
+; ordinals).
+;
+ cCall GetResOrd,<hResFile, lpszType, lpszName>
+ mov typeord,ax
+ mov nameord,dx
+
+; First find the resource type.
+
+ lea di,[si].SIZE new_rsrc ; DS:DI = pType
+fr_type_loop:
+ mov cx,[di].rt_id
+ jcxz fr_error_ret
+ mov ax,typeord
+ or ax,ax
+ jz fr_compare_type_string
+ cmp ax,cx
+ jz fr_found_type
+ jmps fr_next_type
+fr_compare_type_string:
+ cCall CmpResStr,<ds,si,cx,lpszType>
+ or ax,ax
+ jnz fr_found_type
+fr_next_type:
+ mov ax,[di].rt_nres
+ mov cx,SIZE rsrc_nameinfo
+ mul cx
+ add ax,SIZE rsrc_typeinfo
+ add di,ax
+ jmp fr_type_loop
+fr_found_type:
+
+; Now find the resource name.
+
+ mov cx,[di].rt_nres
+ lea di,[di].SIZE rsrc_typeinfo ; DS:DI = pName
+fr_name_loop:
+ mov bx,nameord
+ or bx,bx
+ mov ax,[di].rn_id
+ jz fr_compare_name_string
+ cmp ax,bx
+ jz fr_found_name
+ jmps fr_next_name
+fr_compare_name_string:
+ push cx
+ cCall CmpResStr,<ds,si,ax,lpszName>
+ pop cx
+ or ax,ax
+ jnz fr_found_name
+fr_next_name:
+ add di,SIZE rsrc_nameinfo
+ loop fr_name_loop
+fr_error_ret:
+ xor ax,ax
+ jmps fr_ret
+
+fr_found_name:
+ mov ax,di
+fr_ret:
+cEnd
+
+sEnd MISCCODE
+
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+cProc PreloadResources,<PUBLIC,NEAR>,<si,di>
+ parmW hExe
+ parmW fh
+ parmW hBlock
+ parmD FileOffset
+if ROM
+ parmW selROMHdr
+
+ localW rtid
+endif
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ localW hiResOffset
+ localW loResOffset
+endif
+
+cBegin
+ mov es,hExe
+ xor bx,bx
+ mov si,es:[bx].ne_rsrctab
+ cmp es:[bx].ne_restab,si
+ jne prnotdone
+prdonej:
+ jmp prdone
+ife ROM
+prnextj:
+ jmp prnext
+endif
+
+prnotdone:
+ mov di,es:[si].rs_align
+ add si,SIZE new_rsrc
+prtype:
+ cmp es:[si].rt_id,0
+ je prdonej
+ mov cx,es:[si].rt_nres
+ mov word ptr es:[si].rt_proc[0],codeOffset DefaultResourceHandler
+ mov word ptr es:[si].rt_proc[2],codeBase
+if ROM
+ mov ax, es:[si].rt_id
+ mov rtid, ax
+endif
+ add si,SIZE rsrc_typeinfo
+prname:
+ push cx
+ mov ax,es:[si].rn_flags
+; cmp word ptr es:[ne_ver],4 ; Produced by version 4.0 LINK?
+; ja prname2
+; test ah,0Fh ; Is old discard field set?
+; jz prname1
+; or ax,RNDISCARD ; Yes, convert to bit
+;prname1:
+; and ax,not RNUNUSED ; Clear unused bits in 4.0 LINK files
+prname2:
+ or ax,NENOTP
+ errnz <NENOTP - 8000h>
+ test es:[ne_flags],NENOTP
+ jnz prname4 ; Mark as EMSable if resource belongs
+ xor ax,NENOTP ; to a task.
+prname4:
+if ROM
+ ; don't preload yet if ROM, but make sure that if its a patch
+ ; file using a resource in ROM, the resource table gets patched...
+ ;
+
+ test es:[si].rn_flags, RNINROM or RNCOMPR
+ jz PL_not_rom_res
+
+ cmp selROMHdr, 0
+ jz PL_no_patch
+
+ mov ax, es:[si].rn_id
+ push es
+ mov es, selROMHdr
+
+ mov bx, es:[ne_rsrctab]
+ add bx, size NEW_RSRC
+PL_patch_loop1:
+ cmp es:[bx].rt_id, 0
+ jz PL_patch_fubar
+ mov cx, es:[bx].rt_nres
+ mov dx, es:[bx].rt_id
+ add bx, size RSRC_TYPEINFO
+ cmp dx, rtid
+ jz PL_right_type
+ .errnz size RSRC_NAMEINFO - 12
+ shl cx, 2
+ add bx, cx ; nres*4
+ shl cx, 1
+ add bx, cx ; + nres*8 = nres*12
+ jmp short PL_patch_loop1
+PL_right_type:
+PL_patch_loop2:
+ cmp es:[bx].rn_id, ax
+ jz PL_patch_foundit
+ add bx, size RSRC_NAMEINFO
+ loop PL_patch_loop2
+
+PL_patch_fubar:
+if KDEBUG
+ int 3
+endif
+ sub dx, dx
+ sub ax, ax
+ jmp short PL_patch_resource
+
+PL_patch_foundit:
+ mov ax, es:[bx].rn_flags
+ mov dx, es:[bx].rn_offset
+
+PL_patch_resource:
+ pop es
+ mov es:[si].rn_offset, dx
+ mov es:[si].rn_flags, ax
+
+PL_no_patch:
+prnextj:
+ jmp prnext
+PL_not_rom_res:
+endif
+ mov es:[si].rn_flags,ax
+ test al,RNPRELOAD
+ jz prnextj
+
+ mov cx, seg_FileOffset
+ or cx, off_FileOffset
+ jcxz PL_file
+
+ cmp di, 4 ; Must be at least paragraph aligned
+ jb PL_file
+
+ push es
+ cCall GlobalLock,<hBlock>
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ mov ax,dx ; no need to alloc a selector. we will use the
+ ; the current one.
+if KDEBUG
+ or ax, ax
+ jnz @F
+ int 3 ; // should never happen
+@@:
+endif
+
+else
+ cCall AllocSelector,<dx>
+endif
+
+ pop es
+ mov bx,es:[si].rn_offset
+ xor dx,dx
+ mov cx,di
+PL_shift:
+ shl bx,1
+ rcl dx,1
+ loop PL_shift
+
+ sub bx, off_FileOffset
+ sbb dx, seg_FileOffset
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ ; call to longptraddwow basically is a nop. it doesn't set the
+ ; descriptor. it is called 'cause it sets some registers.
+
+ mov hiResOffset, dx
+ mov loResOffset, bx
+ push ax
+ push es
+ cCall LongPtrAddWOW,<ax,cx,dx,bx, 0, 0> ; (cx is 0)
+ pop es
+ dec cx
+ cCall ResAlloc,<essi,dx,cx, hiResOffset, loResOffset>
+ pop cx
+ push ax
+else
+ push ax
+ push es
+ cCall LongPtrAdd,<ax,cx,dx,bx> ; (cx is 0)
+ pop es
+ dec cx
+ cCall ResAlloc,<essi,dx,cx, 0, 0>
+ pop cx
+ push ax
+ cCall FreeSelector,<cx>
+endif
+ cCall GlobalUnlock,<hBlock>
+ pop ax
+ jmps PL_loaded
+
+PL_file:
+ mov dx,es:[si].rn_offset
+ xor ax,ax
+ mov cx,di
+PL_shift1:
+ shl dx,1
+ rcl ax,1
+ loop PL_shift1
+ mov cx,ax
+ mov ax,4200h
+ mov bx,fh
+ DOSFCALL
+ifdef WOW_OPTIMIZE_PRELOADRESOURCE
+ cCall ResAlloc,<essi,bx,bx, 0, 0>
+else
+ cCall ResAlloc,<essi,bx,bx>
+endif
+
+PL_loaded:
+ mov es,hExe
+ mov es:[si].rn_handle,ax
+prnext:
+ pop cx
+ add si,SIZE rsrc_nameinfo
+ dec cx
+ jz prtypej
+ jmp prname
+prtypej:
+ jmp prtype
+prdone:
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/rip.c b/private/mvdm/wow16/kernel31/rip.c
new file mode 100644
index 000000000..9c9d5bea9
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/rip.c
@@ -0,0 +1,698 @@
+/****************************************************************************/
+/* */
+/* RIP.C - */
+/* */
+/* Debugging Support Routines */
+/* */
+/****************************************************************************/
+
+#include "kernel.h"
+#include "newexe.h"
+
+#if KDEBUG
+
+#include "logerror.h"
+#define API _far _pascal _loadds
+
+extern unsigned int DebugOptions;
+
+/* Defines for debug strings in STRINGS.ASM. */
+#define DS_LOADFAIL 0
+#define DS_NEWINSTLOADFAIL 1
+#define DS_RESLOADERR 2
+#define DS_CRLF 3
+#define DS_FATALEXITCODE 4
+#define DS_STACKOVERFLOW 5
+#define DS_STACKTRACE 6
+#define DS_ABORTBREAKIGNORE 7
+#define DS_INVALIDBPCHAIN 8
+#define DS_COLON 9
+#define DS_REENTERFATALEXIT 10
+
+LPSTR htoa(LPSTR, WORD);
+LPSTR htoa0(LPSTR, WORD);
+LONG PASCAL LSHL(WORD, int);
+char DebugRead(void);
+int DebugWrite(LPSTR, int);
+void DoAbort(void);
+void EnterBreak(int);
+HANDLE GetExeHead(void);
+int OpenSymFile(LPSTR);
+void GetSymFileName(HANDLE, LPSTR);
+int ValidatePointer(LPSTR);
+WORD (far PASCAL *FatalExitProc)(WORD, WORD);
+BOOL PASCAL IsCodeSelector(WORD);
+int FAR FatalExitC(WORD);
+void FAR FatalAppExit(WORD, LPSTR);
+
+/* Debug Symbol Table Structures:
+ *
+ * For each symbol table (map): (MAPDEF)
+ * -------------------------------------------------------------------------------------------------
+ * | map_ptr | lsa | pgm_ent | abs_cnt | abs_ptr | seg_cnt | seg_ptr | nam_max | nam_len | name... |
+ * -------------------------------------------------------------------------------------------------
+ */
+
+typedef struct tagMAPDEF
+{
+ unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */
+ unsigned lsa ; /* 16 bit Load Segment address */
+ unsigned pgm_ent; /* 16 bit entry point segment value */
+ int abs_cnt; /* 16 bit count of constants in map */
+ unsigned abs_ptr; /* 16 bit ptr to constant chain */
+ int seg_cnt; /* 16 bit count of segments in map */
+ unsigned seg_ptr; /* 16 bit ptr to segment chain */
+ char nam_max; /* 8 bit Maximum Symbol name length */
+ char nam_len; /* 8 bit Symbol table name length */
+}
+MAPDEF;
+
+typedef struct tagMAPEND
+{
+ unsigned chnend; /* end of map chain (0) */
+ char rel; /* release */
+ char ver; /* version */
+}
+MAPEND;
+
+
+/* For each segment/group within a symbol table: (SEGDEF)
+ * --------------------------------------------------------------
+ * | nxt_seg | sym_cnt | sym_ptr | seg_lsa | name_len | name... |
+ * --------------------------------------------------------------
+ */
+
+typedef struct tagSEGDEF
+{
+ unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */
+ int sym_cnt; /* 16 bit count of symbols in sym list */
+ unsigned sym_ptr; /* 16 bit ptr to symbol list */
+ unsigned seg_lsa; /* 16 bit Load Segment address */
+ unsigned seg_in0; /* 16 bit instance 0 physical address */
+ unsigned seg_in1; /* 16 bit instance 1 physical address */
+ unsigned seg_in2; /* 16 bit instance 2 physical address */
+ unsigned seg_in3; /* 16 bit instance 3 physical address */
+ unsigned seg_lin; /* 16 bit ptr to line number record */
+ char seg_ldd; /* 8 bit boolean 0 if seg not loaded */
+ char seg_cin; /* 8 bit current instance */
+ char nam_len; /* 8 bit Segment name length */
+}
+SEGDEF;
+typedef SEGDEF FAR *LPSEGDEF;
+
+
+/* Followed by a list of SYMDEF's..
+ * for each symbol within a segment/group: (SYMDEF)
+ * -------------------------------
+ * | sym_val | nam_len | name... |
+ * -------------------------------
+ */
+
+typedef struct tagSYMDEF
+{
+ unsigned sym_val; /* 16 bit symbol addr or const */
+ char nam_len; /* 8 bit symbol name length */
+}
+SYMDEF;
+
+
+typedef struct tagRIPINFO
+{
+ char symName[128];
+ LPSTR pSymName;
+ DWORD symFPos;
+ int symFH;
+}
+RIPINFO;
+typedef RIPINFO FAR *LPRIPINFO;
+
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* KernelError() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Print out the module name, the message which 'lpmsg1' points to, and the
+ * value of 'lpmsg2' in hex. Then call FatalExit.
+ */
+
+int KernelError(int errCode, LPSTR lpmsg1, LPSTR lpmsg2) {
+ int n;
+ char buf[16];
+ LPSTR pbuf;
+ WORD hExe;
+ WORD pfileinfo;
+
+ struct new_exe far *pExe;
+
+ /* Write out 'lpmsg1'. */
+ if (lpmsg1)
+ DebugWrite(lpmsg1, 0);
+
+ /* Is the second pointer non-NULL? */
+ if (lpmsg2)
+ {
+ /* Is the segment value non-NULL? */
+ if ( (hExe = (WORD)((DWORD)lpmsg2 >> 16))
+ && ValidatePointer(lpmsg2) )
+ {
+ /* Does it point anywhere inside a New EXE Header? */
+ pExe = (struct new_exe far *)((DWORD)hExe << 16);
+ if (pExe->ne_magic == NEMAGIC)
+ {
+ /* Write out the module name (1st in the resident names table).*/
+ pbuf = (LPSTR)(((DWORD)hExe << 16) | pExe->ne_restab);
+ if (n = (int)((BYTE)*pbuf++))
+ {
+ DebugWrite(pbuf, n);
+ DebugWrite(GetDebugString(DS_COLON), 0);
+ }
+
+ /* Is the offset NULL? */
+ if (!LOWORD(lpmsg2))
+ {
+ /* Get the pointer to the full-path name which we stuck in
+ * the checksum a long time ago.
+ */
+ if (pfileinfo = NE_PFILEINFO(*pExe))
+ (DWORD)lpmsg2 |= (DWORD)pfileinfo;
+ else
+ {
+ pExe = (struct new_exe far *)((DWORD)GetExeHead() << 16);
+ pfileinfo = NE_PFILEINFO(*pExe);
+ lpmsg2 = (LPSTR)(((DWORD)hExe << 16) | pfileinfo);
+ }
+ lpmsg2 += 8; /* HERE???? */
+ }
+ }
+
+ /* Write out the full-path name. */
+ pbuf = lpmsg2;
+ n = 0;
+ while ((BYTE)*pbuf++ >= ' ')
+ n++;
+
+ if (n && n < 64)
+ DebugWrite(lpmsg2, n);
+ }
+
+ /* Write out the second pointer in hex. */
+ pbuf = (LPSTR)buf;
+ *pbuf++ = ' ';
+ pbuf = htoa(pbuf, HIWORD(lpmsg2));
+ *pbuf++ = ':';
+ pbuf = htoa(pbuf, LOWORD(lpmsg2));
+ *pbuf++ = '\r';
+ *pbuf++ = '\n';
+ *pbuf++ = 0;
+ DebugWrite((LPSTR)buf, 0);
+ }
+
+ /* Print errCode and dump the stack. */
+ return FatalExitC(errCode);
+}
+
+
+static char far *GetModName(char far *exeName) {
+ int delim, dot, len, i;
+ delim = 0;
+ dot = 0;
+ for (i=0; i<80 && exeName[i]; i++) {
+ if (exeName[i] == '.')
+ dot = i;
+ if (exeName[i] == ':' || exeName[i] == '\\')
+ delim = i+1;
+ }
+ if (!dot) dot = i;
+ len = dot - delim;
+ for (i=0; i<len; i++)
+ exeName[i] = exeName[i+delim];
+ exeName[len] = 0;
+ return exeName+len;
+} /* GetModName */
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FindSegSyms() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int FindSegSyms(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD CSvalue) {
+ HANDLE hExe;
+ struct new_exe far *pExe;
+ struct new_seg1 far *pSeg;
+ MAPDEF MapDef;
+ MAPEND MapEnd;
+ LPSTR pFileName;
+ BYTE c;
+ int i;
+ int j;
+ WORD seg_ptr;
+
+ if (lpRipInfo->symFH != -1)
+ {
+ _lclose(lpRipInfo->symFH);
+ lpRipInfo->symFH = -1;
+ }
+
+ hExe = GetExeHead();
+ while (hExe)
+ {
+ pExe = (struct new_exe far *)((DWORD)hExe << 16);
+ pSeg = (struct new_seg1 far *)(((DWORD)hExe << 16) | pExe->ne_segtab);
+
+ for (i=0; i < pExe->ne_cseg; i++, pSeg++)
+ {
+#if 1
+ if (HIWORD(GlobalHandleNoRIP((HANDLE)pSeg->ns_handle)) == CSvalue)
+#else
+ if (MyLock((HANDLE)pSeg->ns_handle) == CSvalue)
+#endif
+ {
+ lpRipInfo->pSymName = (LPSTR)lpRipInfo->symName;
+ GetSymFileName(hExe, lpRipInfo->pSymName);
+ if ((lpRipInfo->symFH = OpenSymFile(lpRipInfo->pSymName)) != -1)
+ {
+ _lread(lpRipInfo->symFH, (LPSTR)&MapDef, sizeof(MAPDEF));
+ _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)MapDef.nam_len));
+
+ if (i > MapDef.seg_cnt) /* Too much assembly */
+ goto ModName;
+
+ lpRipInfo->pSymName += MapDef.nam_len;
+ *lpRipInfo->pSymName++ = '!';
+ *lpRipInfo->pSymName = 0;
+ seg_ptr = (WORD)MapDef.seg_ptr;
+ _llseek(lpRipInfo->symFH, -(long)sizeof(MAPEND), 2);
+ _lread(lpRipInfo->symFH, (LPSTR)&MapEnd, sizeof(MAPEND));
+ if (MapEnd.ver != 3) goto ModName;
+
+ j = i + 1;
+ while (j--)
+ {
+ if (MapEnd.rel >= 10)
+ _llseek(lpRipInfo->symFH, LSHL(seg_ptr, 4), 0);
+ else
+ _llseek(lpRipInfo->symFH, (long)seg_ptr, 0);
+ _lread( lpRipInfo->symFH, (LPSTR)lpSegDef, sizeof(*lpSegDef));
+ seg_ptr = (WORD)lpSegDef->nxt_seg;
+ }
+
+ _lread(lpRipInfo->symFH, lpRipInfo->pSymName, (int)((BYTE)lpSegDef->nam_len));
+ lpRipInfo->pSymName += lpSegDef->nam_len;
+ *lpRipInfo->pSymName++ = ':';
+ *lpRipInfo->pSymName = 0;
+ lpRipInfo->symFPos = (DWORD)_llseek(lpRipInfo->symFH, 0L, 1);
+
+ return(TRUE);
+ } /* if opened file */
+ModName:
+ /* Put Module on line: USER(0033)XXXX:XXXX */
+ GetSymFileName(hExe, lpRipInfo->symName);
+ lpRipInfo->pSymName = GetModName(lpRipInfo->symName);
+ *lpRipInfo->pSymName++ = '(';
+ lpRipInfo->pSymName = htoa0(lpRipInfo->pSymName, i+1);
+ *lpRipInfo->pSymName++ = ')';
+ *lpRipInfo->pSymName = 0;
+ goto TermName;
+ }
+ }
+ hExe = (HANDLE)NE_PNEXTEXE(*pExe);
+ }
+ lpRipInfo->pSymName = lpRipInfo->symName;
+TermName: /* Add segment:offset to line */
+ lpRipInfo->pSymName = htoa((LPSTR)lpRipInfo->pSymName, CSvalue);
+ *lpRipInfo->pSymName++ = ':';
+ *lpRipInfo->pSymName = 0;
+ if (lpRipInfo->symFH != -1) {
+ _lclose(lpRipInfo->symFH);
+ lpRipInfo->symFH = -1;
+ }
+ return(FALSE);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FindSymbol() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int FindSymbol(LPRIPINFO lpRipInfo, LPSEGDEF lpSegDef, WORD offset) {
+ WORD i;
+ DWORD symPos, curPos;
+ LPSTR s;
+ SYMDEF SymDef;
+
+ if (lpRipInfo->symFH != -1)
+ {
+ curPos = symPos = (DWORD)_llseek(lpRipInfo->symFH, (long)lpRipInfo->symFPos, 0);
+ i = (WORD)lpSegDef->sym_cnt;
+ while (i--)
+ {
+ _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF));
+ if ((WORD)SymDef.sym_val > offset)
+ break;
+
+ symPos = curPos;
+
+ curPos = _llseek(lpRipInfo->symFH, (long)SymDef.nam_len, 1);
+ }
+ _llseek(lpRipInfo->symFH, (long)symPos, 0);
+ _lread(lpRipInfo->symFH, (LPSTR)&SymDef, sizeof(SYMDEF));
+ s = lpRipInfo->pSymName;
+ _lread(lpRipInfo->symFH, s, (int)((BYTE)SymDef.nam_len));
+ s += SymDef.nam_len;
+ if ((WORD)SymDef.sym_val < offset)
+ {
+ *s++ = '+';
+ s = htoa0(s, offset - SymDef.sym_val);
+ }
+ *s = 0;
+ return(TRUE);
+ }
+
+ s = htoa(lpRipInfo->pSymName, offset);
+ *s = 0;
+ return(FALSE);
+}
+
+void API GetProcName(FARPROC lpfn, LPSTR lpch, int cch)
+{
+ RIPINFO RipInfo;
+ SEGDEF SegDef;
+ static char lastName[128] = "test";
+ static FARPROC lastfn = 0;
+
+ if (lastfn == lpfn) { /* cache last symbol name looked up */
+ lstrcpy(RipInfo.symName, lastName);
+ } else {
+ RipInfo.pSymName = 0L;
+ RipInfo.symFH = -1;
+
+ FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, HIWORD(lpfn));
+ FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, LOWORD(lpfn));
+
+ if (RipInfo.symFH != -1) {
+ _lclose(RipInfo.symFH);
+ RipInfo.symFH = -1;
+ }
+ lstrcpy(lastName, RipInfo.symName);
+ lastfn = lpfn;
+ }
+
+ if (cch > 1)
+ {
+ if (cch > sizeof(RipInfo.symName))
+ cch = sizeof(RipInfo.symName);
+
+ RipInfo.symName[cch-1] = 0;
+ lstrcpy(lpch, RipInfo.symName);
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* NextFrame() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD far *NextFrame(WORD far *lpFrame) {
+ WORD w;
+
+ /* Force BP even. */
+ w = *lpFrame & 0xFFFE;
+
+ /* Are we at the end of the BP chain? */
+ if (w)
+ {
+ /* BPs should decrease as we move down the chain. */
+ if (w <= LOWORD(lpFrame))
+ goto BadBP;
+
+ /* Are we above the top of the stack (SS:000A contains pStackTop)? */
+ lpFrame = (WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | 0x0A);
+
+ if (w < *lpFrame++)
+ goto BadBP;
+
+ /* Are we below the bottom of the stack (SS:000C contains pStackMin)? */
+ if (w > *++lpFrame)
+ goto BadBP;
+
+ /* Return the address of the next BP. */
+ return((WORD far *)(((DWORD)lpFrame & 0xFFFF0000L) | w));
+ }
+ else
+ return((WORD far *)0L);
+
+BadBP:
+ DebugWrite(GetDebugString(DS_INVALIDBPCHAIN), 0);
+ return((WORD far *)0L);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* StackWalk() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void StackWalk(WORD arg) {
+
+/* WORD arg; /* NOTE: 'arg' is only used as a pointer into the frame. */
+/* If we subtract 2 words from 'arg's location, we */
+/* get the address of the previous frame's BP!!! */
+ WORD far *lpFrame;
+ WORD wCurBP;
+ WORD wCurRetOffset;
+ WORD curCS;
+ RIPINFO RipInfo;
+ SEGDEF SegDef;
+
+ RipInfo.pSymName = 0L;
+ RipInfo.symFH = -1;
+
+ /* Have 'lpFrame' point to the previous frame's BP. */
+ lpFrame = &arg - 2;
+
+ curCS = 0;
+ while (lpFrame = NextFrame(lpFrame))
+ {
+ /* Get the next BP. Stop if it is zero. */
+ wCurBP = *lpFrame;
+ if (!wCurBP)
+ break;
+
+ /* Get the current frame's return address offset. */
+ wCurRetOffset = lpFrame[1];
+
+ /* Have we changed code segments (Far call && Different CS)? */
+ if (((wCurBP & 1) || IsCodeSelector(lpFrame[2])) && (curCS != lpFrame[2]))
+ {
+ /* Yes, get the new segment's name. */
+ curCS = lpFrame[2];
+ FindSegSyms((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, curCS);
+ }
+
+ /* Move back to the address of the actual call instruction. */
+ if ((wCurBP & 1) || IsCodeSelector(lpFrame[2]))
+ /* Near or Far call? */
+ wCurRetOffset -= 5;
+ else
+ wCurRetOffset -= 3;
+
+ FindSymbol((LPRIPINFO)&RipInfo, (LPSEGDEF)&SegDef, wCurRetOffset);
+
+ DebugWrite((LPSTR)RipInfo.symName, 0);
+
+ DebugWrite(GetDebugString(DS_CRLF), 0);
+ }
+ if (RipInfo.symFH != -1)
+ _lclose(RipInfo.symFH);
+}
+
+// #ifndef WOW // can't pass -DWOW without blowing out command-line-length limit
+#if 0 // can't pass -DWOW without blowing out command-line-length limit
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FatalExit() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Debugging version. Retail version in RIPAUX.ASM. */
+/* Kernel DS setup by prolog code */
+
+int FAR FatalExitC(WORD errCode) { /* return 1 to break execution */
+ char c;
+ char buf[7];
+ LPSTR pbuf;
+ int rep=0;
+
+ /* This calls the TOOLHELP RIP hook */
+ if ( FatalExitProc )
+ {
+ _asm
+ {
+ push errCode
+ push bp
+ call DWORD PTR FatalExitProc
+ or ax,ax
+ jz NoReturn
+ }
+ return 0;
+
+ _asm NoReturn:;
+ }
+
+#if 0
+ static BOOL fInsideFatalExit = FALSE;
+
+ if (fInsideFatalExit)
+ {
+ DebugWrite(GetDebugString(DS_REENTERFATALEXIT), 0);
+ return 0;
+ }
+
+ fInsideFatalExit = TRUE;
+#endif
+
+ReRip:
+ /* Display "FatalExit Code =" */
+ DebugWrite(GetDebugString(DS_FATALEXITCODE), 0);
+
+ /* Did the stack overflow? */
+ if (errCode == -1)
+ DebugWrite(GetDebugString(DS_STACKOVERFLOW), 0);
+ else
+ {
+ /* Display the error code in hex. */
+ pbuf = (LPSTR)buf;
+ *pbuf++ = '0';
+ *pbuf++ = 'x';
+ pbuf = htoa(pbuf, (WORD)errCode);
+ *pbuf++ = 0;
+ DebugWrite((LPSTR)buf, 0);
+ }
+
+ /* Display the Stack Trace. */
+ if (rep /* || (DebugOptions & DBO_RIP_STACK) */) {
+ DebugWrite(GetDebugString(DS_STACKTRACE), 0);
+ StackWalk(0);
+ }
+
+ while (TRUE)
+ {
+ /* Display "Abort, Break, Ignore" */
+ DebugWrite(GetDebugString(DS_ABORTBREAKIGNORE), 0);
+
+ /* Get and process the user's response. */
+ c = DebugRead();
+
+ DebugWrite(GetDebugString(DS_CRLF), 0);
+
+ if (c >= 'a' && c <= 'z')
+ c += 'A' - 'a';
+
+ switch (c)
+ {
+ case 'A':
+ DoAbort();
+
+ case 'B':
+ /* fInsideFatalExit = FALSE; */
+ /* EnterBreak(2); */
+ return 1;
+
+ case 0 :
+ case 'I':
+ /* fInsideFatalExit = FALSE; */
+ return 0;
+
+ case 'X':
+ case 'E':
+ FatalAppExit(0, "Terminating Application");
+ break;
+
+ case ' ':
+ case 13:
+ rep = 1;
+ goto ReRip;
+ default:
+ ;
+ }
+ }
+
+}
+
+#endif // ifndef WOW
+
+#endif // if KDEBUG
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* htoa() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Converts 'w' into a hex string in 's'. */
+
+LPSTR htoa(s, w)
+
+LPSTR s;
+WORD w;
+
+{
+ int i;
+ char c;
+
+ i = 4;
+ s += i;
+ while (i--)
+ {
+ c = (char)(w & (WORD)0x000F);
+ w >>= 4;
+ if (c > 9)
+ c += 'A' - 10;
+ else
+ c += '0';
+ *--s = c;
+ }
+
+ return(s+4);
+}
+
+/* skip leading 0's */
+LPSTR htoa0(LPSTR s, WORD w)
+{
+ int i;
+ char c;
+ int flag = 0;
+
+ i = 4;
+ while (i--)
+ {
+ c = (char)((w>>12) & (WORD)0x000F);
+ w <<= 4;
+ if (c > 9)
+ c += 'A' - 10;
+ else
+ c += '0';
+ if (c > '0' || flag || !i) {
+ *s++ = c;
+ flag = 1;
+ }
+ }
+
+ return s;
+}
+
+LPSTR FAR far_htoa0( LPSTR s, WORD w)
+{
+ return htoa0( s, w);
+}
diff --git a/private/mvdm/wow16/kernel31/ripaux.asm b/private/mvdm/wow16/kernel31/ripaux.asm
new file mode 100644
index 000000000..eae3223d8
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/ripaux.asm
@@ -0,0 +1,1083 @@
+;-----------------------------------------------------------------------;
+; ;
+; RIPAUX.ASM - ;
+; ;
+; Debugging Support Routines ;
+; ;
+;-----------------------------------------------------------------------;
+
+ TITLE RIPAUX.ASM - Debugging Support Routines
+
+;-----------------------------------------------------------------------;
+; INCLUDES ;
+;-----------------------------------------------------------------------;
+
+?RIPAUX = 1
+.xlist
+win3deb = 1
+include kernel.inc
+include newexe.inc
+.list
+
+;-----------------------------------------------------------------------;
+; DATA SEGMENT DEFINITION ;
+;-----------------------------------------------------------------------;
+
+DataBegin
+
+externD pDisableProc
+
+if ROM
+externD prevInt21Proc
+endif
+
+
+if KDEBUG
+
+externW fWinX
+externW hExeHead
+externB szDebugStr
+
+externW DebugOptions
+externW DebugFilter
+externB fKTraceOut ; Used by DebugWrite to ignore traces
+else
+
+externB szExitStr1
+externB szExitStr2
+externB szFatalExit
+
+endif
+
+DataEnd
+
+;-----------------------------------------------------------------------;
+; CODE SEGMENT DEFINITION ;
+;-----------------------------------------------------------------------;
+
+sBegin CODE
+
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+;-----------------------------------------------------------------------;
+; EXTERNS ;
+;-----------------------------------------------------------------------;
+
+externFP ExitKernel
+externFP FatalAppExit
+externFP FatalExitC
+
+if KDEBUG
+
+externFP KOutDebugStr
+externNP DebugOutput2
+externNP LogParamError2
+
+else
+
+ife ROM
+externD prevInt21Proc
+endif
+externFP InternalDisableDOS
+
+endif
+
+externNP DebugLogError
+externNP DebugLogParamError
+
+
+; SAVEREGS - Preserve all registers
+;
+SAVEREGS macro
+if PMODE32
+.386
+ push ds ; preserve all registers
+ push es
+ push fs
+ push gs
+ pushad
+.286p
+else
+ push ds
+ push es
+ pusha
+endif; PMODE32
+endm
+
+; RESTOREREGS - Restore registeres preserved with SAVEREGS
+;
+RESTOREREGS macro
+if PMODE32
+.386
+ popad
+ pop gs
+ pop fs
+ pop es
+ pop ds
+.286p
+else
+ popa
+ pop es
+ pop ds
+endif; PMODE32
+endm
+
+; In Win3.1, different code is used for FatalExit on retail
+; and debug builds. WOW uses the code below derived from the
+; debug wrapper for FatalExitC. FatalExitC is a thunk to
+; WOW32's WK32FatalExit thunk.
+
+
+cProc FatalExit,<PUBLIC,FAR>
+ parmW errCode
+cBegin nogen
+ push bp
+ mov bp, sp
+ push ds
+ pusha
+ setkernelds
+ push [bp+6]
+ cCall FatalExitC
+ popa
+ pop ds
+ INT3_DEBUG ; Stop here so WDEB386 can generate same stack trace.
+ pop bp
+ ret 2
+cEnd nogen
+
+if KDEBUG
+
+BegData
+szCRLF db 13,10,0
+EndData
+
+; trashes ES - but caller saves it
+cProc KOutDSStr,<PUBLIC,FAR>,<ds>
+ parmW string
+cBegin
+
+if PMODE32
+.386p
+ pushad ; save upper 16 bits of EAX, etc
+ push fs
+ push gs
+.286p
+endif
+ pushf
+ push cs
+ push ds
+ push es
+ push ss
+ pusha
+ SetKernelDS
+
+ mov si,string
+ call KOutDebugStr ; expects pusha right before call
+ popa
+ add sp, 8 ; don't need to restore seg regs
+ popf
+if PMODE32
+.386p
+ pop gs
+ pop fs
+ popad
+.286p
+endif
+cEnd
+
+cProc _krDebugTest,<PUBLIC, FAR, NONWIN>,<DS>
+ ParmW flags
+ ParmW psz
+ LocalW axSave
+ LocalW bxSave
+ LocalW esSave
+ LocalB fBreakPrint
+cBegin
+ assumes ds,NOTHING
+ mov axSave,ax ; save these regs before they're trashed
+ mov bxSave,bx
+ mov esSave,es
+
+;
+; If this .exe hasn't been relocated yet, just call FatalExit.
+;
+ mov ax,cs:MyCSDS
+ cmp ax,1000h ;; DATA should be selector, not addr
+ jc @F
+ jmp kdtnobreak
+@@:
+ mov es,ax
+assumes es,DATA
+;
+; First use DebugOptions to determine whether we should print anything
+; and/or break with a fatalexit.
+;
+ errnz low(DBF_SEVMASK)
+ errnz low(DBF_TRACE)
+ errnz low(DBF_WARNING)
+ errnz low(DBF_ERROR)
+ errnz low(DBF_FATAL)
+
+ mov bx,es:DebugOptions
+ mov ax,flags
+ and ah,high(DBF_SEVMASK)
+ mov al,2 ; fBreak = FALSE, fPrint = TRUE
+ cmp ah,high(DBF_TRACE)
+ jnz notrace
+
+ push ax
+ mov es:fKTraceOut, 1 ; Set flag for DebugWrite
+ mov ax,flags ; if (!((flags & DBF_FILTERMASK) & DebugFilter))
+ and ax,DBF_FILTERMASK
+ test ax,es:DebugFilter
+ pop ax
+ jnz @F
+ and al,not 2 ; fPrint = FALSE
+ jmp short kdtnobreak
+@@:
+ test bx,DBO_TRACEBREAK ; else if (DebugOptions & DBO_TRACEBREAK)
+ jnz kdtbreak ; fBreak = TRUE
+ jmp short kdtnobreak
+
+notrace:
+ cmp ah,high(DBF_WARNING)
+ jnz nowarn
+ test bx,DBO_WARNINGBREAK
+ jnz kdtbreak
+ jmp short kdtnobreak
+nowarn:
+ cmp ah,high(DBF_ERROR)
+ jnz dofatal
+ test bx,DBO_NOERRORBREAK
+ jnz kdtnobreak
+ jmp short kdtbreak
+dofatal:
+ test bx,DBO_NOFATALBREAK
+ jnz kdtnobreak
+ errn$ kdtbreak
+kdtbreak:
+ or al,1 ; fBreak = TRUE
+kdtnobreak:
+;
+; If DBO_SILENT, then fPrint = FALSE
+;
+ test bx,DBO_SILENT
+ jz @F
+ and al,not 2
+@@:
+ mov fBreakPrint,al
+;
+; if (fBreak || fPrint)
+; print out the string
+;
+ or al,al ; if !(fBreak | fPrint)
+ jz kdtnoprint
+
+assumes es,NOTHING
+ mov es,esSave ; restore registers
+ mov ax,axSave
+ mov bx,bxSave
+ push psz
+ call KOutDSStr ; output the string
+
+ifndef WOW
+ push offset szCRLF
+ call KOutDSStr
+endif
+
+kdtnoprint:
+ test fBreakPrint,1 ; if fBreak, then FatalExit
+ jz kdtexit
+kdtdobreak:
+ cCall FatalExit,<flags>
+kdtexit:
+ SetKernelDS es
+ mov es:fKTraceOut,0 ; Clear DebugWrite flag
+
+ mov ax, axSave
+ mov bx, bxSave
+ mov es, esSave
+cEnd
+
+ifdef DISABLE
+
+flags equ word ptr [bp+6]
+msg equ word ptr [bp+8]
+appDS equ word ptr [bp-2]
+appAX equ word ptr [bp-4]
+;myDS equ word ptr [bp-6]
+_krDebugTest proc far ;Per-component - check right flags
+public _krDebugTest
+ push bp
+ mov bp, sp
+ push ds ; at BP-2
+ push ax ; at BP-4
+ mov ax, _DATA
+ cmp ax, 1000h ;; DATA should be selector, not addr
+ jnc skip
+ mov ds, ax
+ assume ds:_DATA
+
+ mov ax, [flags] ; See if component enabled
+ and ax, [_krInfoLevel]
+ and al, byte ptr [_Win3InfoLevel] ; See if system enabled
+ cmp ax, [flags]
+ jnz skip
+
+ push bx ; Print it, so format message
+ test al, DEB_ERRORS
+ mov bx, dataoffset STR_krError
+ jnz @F
+ test al, DEB_WARNS
+ mov bx, dataoffset STR_krWarn
+ jnz @F
+ test al, DEB_TRACES
+ mov bx, dataoffset STR_krTrace
+ jz short deb_no_msg_type
+
+@@: push bx
+ call KOutDSStr
+
+deb_no_msg_type:
+ mov bx, dataoffset STR_krTable
+ or ah, ah
+ jz deb_show_it
+@@: add bx, 2 ; get next string table entry
+ shr ah, 1 ; find which category
+ jnz @B
+
+deb_show_it:
+ push [bx] ;; push parameter
+ call KOutDSStr
+ pop bx ;; restore reg
+
+ mov ax, [appAX] ; print message passed in
+ push ds
+ mov ds, appDS ; restore App ds for error strings
+ push [msg]
+ call KOutDSStr
+ pop ds ; restore kernel DS
+
+ mov ax, [flags] ; shall we have a breakpoint?
+ and ax, [_krBreakLevel]
+ and al, byte ptr _Win3BreakLevel
+ cmp ax, [flags]
+ jnz skip
+
+ INT3_DEBUG
+skip:
+ test byte ptr [flags], DEB_FERRORS
+ jz @F
+
+ push 0
+ push cs:MyCSDS
+ push word ptr [bp+8]
+ cCall FatalAppExit ;,<0,DGROUP,[bp+8]>
+@@:
+ pop ax
+ pop ds
+ pop bp
+ retf
+_krDebugTest endp
+endif; DISABLE
+
+endif; KDEBUG
+
+ife KDEBUG ; RETAIL ONLY SECTION STARTS HERE!
+
+ifndef WOW ; WOW uses only the "debug" version
+ ; of FatalExit which calls FatalExitC.
+ ; FatalExitC is thunked in WOW, the
+ ; version in rip.c is disabled.
+
+;-----------------------------------------------------------------------;
+; ;
+; FatalExit() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+; Retail version. The Debug version is in RIP.C.
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FatalExit,<PUBLIC,FAR>
+ parmW errCode
+cBegin
+ SetKernelDS
+ push 0
+ push ds
+ push dataOffset szFatalExit
+ cCall IFatalAppExit ;,<0, ds, dataOffset szUndefDyn>
+cEnd
+
+cProc FatalExitDeath,<PUBLIC,FAR>
+
+ parmW errCode
+
+ localD pbuf
+ localV buf,6
+cBegin
+
+if 0
+ mov ax,4CFFh
+ int 21h
+else
+ SetKernelDS
+ cCall TextMode ; Is USER started?
+
+; cmp pDisableProc.sel,0
+; je fex1
+; cCall pDisableProc ; Yes, Call USER's DisableOEMLayer()
+; ; to get to the text screen
+; jmps fex1a
+;fex1:
+; mov ax, 6 ; set text mode
+; int 10h
+;fex1a:
+
+; Is Int 21h hooked?
+
+ cmp prevInt21Proc.sel,0
+ je fex2
+ cCall InternalDisableDOS ; Yes, disable Int 21h
+
+fex2:
+ mov cx,errCode ; No output if error code is zero
+ jcxz fe4
+
+; Write "FatalExit = " message to STDOUT.
+
+ mov bx,1
+ mov dx,dataOffset szExitStr1
+ mov cx,20
+ mov ah,40h
+ int 21h
+
+; Error code of FFFF means Stack Overflow.
+
+ mov dx,errCode
+ inc dx
+ jnz fe1
+ mov dx,dataOffset szExitStr2 ; "Stack Overflow" message
+ mov cx,17
+ mov ah,40h
+ int 21h
+ jmps fe4
+
+ UnSetKernelDS
+fe1:
+
+; Write out error code in Hex.
+
+ dec dx
+ push ss
+ pop es
+ lea di,buf
+ mov ax,'x' shl 8 OR '0'
+ stosw
+ mov cx,4
+ rol dx,cl ; Rotate most significant into view
+fe2:
+ mov ax,dx
+ and ax,0Fh
+ push cx
+ mov cl,4
+ rol dx,cl ; Rotate next byte into view
+ pop cx
+ add al,'0'
+ cmp al,'9'
+ jbe fe3
+ add al,'A'-':'
+fe3:
+ stosb
+ loop fe2
+ mov ax,10 shl 8 OR 13
+ stosw
+ xor ax,ax
+ stosb
+ lea dx,buf
+ push ss
+ pop ds
+ mov cx,8
+ mov bx,1
+ mov ah,40h
+ int 21h ; Write it out
+fe4:
+ mov ax,errcode
+ cCall ExitKernel,<ax>
+endif
+cEnd
+
+endif ; ifndef WOW
+
+else ; DEBUG ONLY SECTION STARTS HERE!
+
+;-----------------------------------------------------------------------;
+; ;
+; GetSymFileName() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetSymFileName,<PUBLIC,NEAR>,<ds,si,di>
+
+ParmW hExe
+ParmD lpName
+
+cBegin
+ cld
+ les di,lpName
+ SetKernelDS
+;; cmp fWinX,0
+;; je slowboot
+;; mov ax,hExe
+;; cmp hExeHead,ax
+;; mov ds,ax
+;; UnSetKernelDS
+;; je makename
+;; mov si,ds:[ne_pfileinfo]
+;; or si,si
+;; jnz havename
+;;makename:
+;; mov si,ds:[ne_restab]
+;; xor ax,ax
+;; lodsb
+;; mov cx,ax
+;; rep movsb
+;;appendext:
+;; mov ax,'S.'
+;; stosw
+;; mov ax,'MY'
+;; stosw
+;; xor ax,ax
+;; stosb
+;; jmps namedone
+;;
+;;slowboot:
+ mov ds,hExe
+ mov si,ds:[ne_pfileinfo]
+havename:
+ add si,opFile
+nameloop:
+ lodsb
+ cmp al,'.'
+ je appendext
+ stosb
+ jmp nameloop
+appendext:
+ mov ax,'S.'
+ stosw
+ mov ax,'MY'
+ stosw
+ xor ax,ax
+ stosb
+ les ax,lpName
+ mov dx,es
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; ;
+; OpenSymFile() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc OpenSymFile,<PUBLIC,NEAR>,<ds,si,di>
+
+ParmD path
+
+LocalV Buffer,MaxFileLen
+
+cBegin
+ lds dx,path ; get pointer to pathname
+ mov di,3D40h ; open file function code (SHARE_DENY_NONE)
+
+ ; We don't use open test for existance, rather we use get
+ ; file attributes. This is because if we are using Novell
+ ; netware, opening a file causes Novell to execute its
+ ; own path searching logic, but we want our code to do it.
+
+ mov ax,4300h ; Get file attributes
+ int 21h ; Does the file exist?
+ jc opnnov ; No, then don't do the operation
+ mov ax,di ; Yes, open the file then
+ int 21h
+ jnc opn2
+opnnov:
+ mov ax, -1
+opn2: mov bx,ax
+cEnd
+
+
+
+
+;-----------------------------------------------------------------------;
+; ;
+; GetDebugString() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+; Finds the 'strIndex'-th string in 'szDebugStr'. The strings are defined
+; in STRINGS.ASM.
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetDebugString,<PUBLIC,NEAR>,<di>
+
+parmW strIndex
+
+cBegin
+ SetKernelDS es
+ mov di,dataOffset szDebugStr
+ mov bx,strIndex
+ cld
+gds1:
+ dec bx
+ jl gdsx
+ xor ax,ax
+ mov cx,-1
+ repne scasb
+ cmp es:[di],al
+ jne gds1
+ xor di,di
+ mov es,di
+gdsx:
+ mov ax,di
+ mov dx,es
+ UnSetKernelDS es
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; ;
+; GetExeHead() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc GetExeHead,<PUBLIC,NEAR>
+
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ax,[hExeHead]
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ;
+; LSHL() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc LSHL,<PUBLIC,NEAR>
+
+cBegin nogen
+ pop bx
+ pop cx
+ pop ax
+ xor dx,dx
+lshl1:
+ shl ax,1
+ rcl dx,1
+ loop lshl1
+ jmp bx
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ;
+; FarKernelError() - ;
+; ;
+; 05-09-91 EarleH modified to save and restore all registers. ;
+; ;
+;-----------------------------------------------------------------------;
+
+; Far entry point for KernelError(). Allows the multitude of calls to
+; KernelError() be made as near calls.
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc FarKernelError,<PUBLIC,FAR,NODATA>
+
+cBegin nogen
+ push bp
+ mov bp,sp
+
+ SAVEREGS
+ mov ax, _DATA
+ mov ds, ax
+; push [bp+14]
+ push [bp+12]
+ push ds ; seg of string
+ push [bp+10]
+ push [bp+8]
+ push [bp+6]
+ mov bp,[bp]
+ call KernelError
+ or ax, ax
+ RESTOREREGS
+ pop bp
+ jz @F
+ INT3_DEBUG
+@@:
+ ret 10
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ;
+; NearKernelError() - ;
+; ;
+; 05-09-91 EarleH modified to save and restore all registers. ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc NearKernelError,<PUBLIC,NEAR,NODATA>
+
+cBegin nogen
+ push bp
+ mov bp,sp
+
+ SAVEREGS
+ mov ax, _DATA
+ mov ds, ax
+
+; push [bp+12] ; only pass 4 words now
+ push [bp+10] ; err code
+ push ds ; seg of string
+ push [bp+8] ; offset of string
+ push [bp+6]
+ push [bp+4]
+ mov bp,[bp] ; hide this stack frame
+ call KernelError
+ or ax, ax
+ RESTOREREGS
+ pop bp
+ jz @F
+ INT3_DEBUG
+@@:
+ ret 8
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ;
+; IsCodeSelector() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc IsCodeSelector,<PUBLIC,NEAR>
+
+parmW Candidate
+
+cBegin
+ mov ax,Candidate
+ lar dx,ax
+ jz lar_passed
+ xor ax,ax
+ jmp ics_ret
+lar_passed:
+ xor ax,ax
+ test dh,00001000b ; Executable segment descriptor?
+ jz ics_ret ; No
+ push cs ; Yes
+ pop dx
+ and dx,3
+ and Candidate,3 ; RPL matches that of CS?
+ cmp dx,Candidate
+ jne ics_ret ; No
+ inc ax ; Yes
+ics_ret:
+cEnd
+
+endif; DEBUG ; DEBUG ONLY SECTION ENDS HERE
+
+
+;-----------------------------------------------------------------------;
+; ;
+; DebugBreak() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+if KDEBUG
+db_tab dw db_t, db_w, db_e, db_f, db_k, db_3
+db_len equ ($ - db_tab) / 2
+endif
+
+cProc DebugBreak,<PUBLIC,FAR>
+
+cBegin nogen
+if KDEBUG
+ cmp ax, 0DACh
+ jnz db_3
+ cmp bx, db_len
+ jae db_3
+ shl bx, 1
+ jmp db_tab[bx]
+db_t: krDebugOut DEB_TRACE, "Test trace"
+ jmps db_end
+db_w: krDebugOut DEB_WARN, "Test warning"
+ jmps db_end
+db_e: krDebugOut DEB_ERROR, "Test error"
+ jmps db_end
+db_f: krDebugOut DEB_FERROR, "Test fatal error"
+ jmps db_end
+db_k: kerror 0, "This is a kernel error"
+ jmps db_end
+db_3:
+endif
+
+ INT3_DEBUG ; Jump to debugger if installed
+db_end:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ;
+; TextMode() - Enter text mode for debugging load failure ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc TextMode,<PUBLIC,NEAR,NODATA>,<ds>
+cBegin
+ SetKernelDS
+ cmp word ptr [pDisableProc+2],0
+ je tm1
+ cCall [pDisableProc]
+ jmps tm2
+tm1:
+ mov ax, 3
+ int 10h
+tm2:
+cEnd
+
+
+
+
+;-----------------------------------------------------------------------;
+; ;
+; DoAbort() - ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DoAbort,<PUBLIC,NEAR>
+
+cBegin nogen
+ SetKernelDS
+ cCall TextMode
+; cmp word ptr [pDisableProc+2],0
+; je doa1
+; cCall [pDisableProc]
+;doa1:
+ mov ax,1
+ cCall ExitKernel,<ax>
+ UnSetKernelDS
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+;
+; HandleParamError
+;
+; This entry point is jumped to by the parameter validation code of
+; USER and GDI (and KERNEL). Its job is to parse the error code
+; and, if necessary, RIP or jmp to the error handler routine
+;
+; Stack on entry: Far return addr to validation code
+; Saved error handler offset
+; Saved BP
+; API far ret addr
+;
+;-----------------------------------------------------------------------;
+
+ERR_WARNING equ 08000h ; from error.h/windows.h/layer.inc
+
+LabelFP <PUBLIC, HandleParamError>
+ push bp
+ mov bp,sp
+ push bx ; save err code
+
+ push bx ; push err code
+
+ push [bp+4] ; push err return addr as place where error occured
+ push [bp+2]
+
+ push cx ; push parameter
+ push ax
+ call far ptr LogParamError ; yell at the guy
+
+ pop bx
+ pop bp
+
+ test bh,high(ERR_WARNING) ; warn or fail?
+ errnz low(ERR_WARNING)
+ jnz @F
+
+ pop bx
+ pop ax ; pop far return addr
+
+ pop bx ; get error handler address
+
+ pop bp ; restore BP
+ and bp,not 1 ; Make even in case "inc bp" for ATM
+
+ push ax
+ push bx ; far return to handler
+
+ xor ax,ax ; set dx:ax == 0 for default return value
+ cwd
+ xor cx,cx ; set cx == 0 too, for kernel error returns
+
+ mov es,ax ; clear ES just in case it contains
+ ; a Windows DLL's DS...
+@@:
+ retf
+
+cProc DebugFillBuffer,<PUBLIC, FAR, PASCAL, NONWIN>,<DI>
+ParmD lpb
+ParmW cb
+cBegin
+if KDEBUG
+assumes ES,data
+ mov ax,_DATA
+ mov es,ax
+ test es:DebugOptions,DBO_BUFFERFILL
+assumes ES,nothing
+ jz dfbexit
+ les di,lpb
+ mov cx,cb
+ mov ax,(DBGFILL_BUFFER or (DBGFILL_BUFFER shl 8))
+ cld
+ shr cx,1
+ rep stosw
+ rcl cx,1
+ rep stosb
+dfbexit:
+endif; KDEBUG
+cEnd
+
+;========================================================================
+;
+; void FAR _cdecl DebugOutput(UINT flags, LPCSTR lpszFmt, ...);
+;
+; NOTE: there is a CMACROS bug with C that causes the parameter offsets
+; to be calculated incorrectly. Offsets calculated by hand here.
+;
+cProc DebugOutput,<PUBLIC, FAR, C, NONWIN>
+flags equ <[bp+2+4]> ; parmW flags point past ret addr & saved bp
+lpszFmt equ <[bp+2+4+2]> ; parmD lpszFmt
+cBegin
+if KDEBUG
+ push bp ; generate a stack frame
+ mov bp,sp
+
+ SAVEREGS ; save all registers
+
+ push ds
+ SetKernelDS
+
+ lea ax,flags ; point at flags, lpszFmt, and rest of arguments
+ push ss
+ push ax
+ call DebugOutput2
+
+ UnsetKernelDS
+ pop ds
+ or ax,ax ; test break flag
+ RESTOREREGS
+
+ pop bp
+
+ jz @F ; break if needed
+ INT3_DEBUG
+@@:
+endif
+cEnd
+
+;========================================================================
+;
+; void WINAPI LogError(UINT err, void FAR* lpInfo);
+;
+cProc LogError,<PUBLIC, FAR, PASCAL, NONWIN>
+ParmD err
+ParmW lpInfo
+cBegin
+ SAVEREGS
+assumes ds,NOTHING
+
+ cCall DebugLogError,<err, lpInfo>
+
+ RESTOREREGS
+cEnd
+
+;========================================================================
+;
+; void WINAPI LogParamError(UINT err, FARPROC lpfn, void FAR* param);
+;
+cProc LogParamError,<PUBLIC, FAR, PASCAL, NONWIN>
+ParmW err
+ParmD lpfn
+ParmD param
+cBegin
+assumes ds,NOTHING
+ SAVEREGS
+
+ ; Call debugger hook (note the reversed parameter order)
+ ;
+ cCall DebugLogParamError,<param, lpfn, err>
+
+if KDEBUG
+ push ds
+ SetKernelDS
+assumes ds,DATA
+ mov bx, [bp+0] ; address of faulting code
+ mov bx, ss:[bx+0]
+; mov bx, ss:[bx+0]
+ mov bx, ss:[bx+4]
+ cCall LogParamError2,<err, lpfn, param, bx>
+ UnsetKernelDS
+ pop ds
+assumes ds,NOTHING
+ or ax,ax ; test break flag
+endif
+ RESTOREREGS
+if KDEBUG
+ jz @F ; break if needed
+ INT3_DEBUG
+@@:
+endif
+cEnd
+
+
+;-----------------------------------------------------------------------
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/rom.asm b/private/mvdm/wow16/kernel31/rom.asm
new file mode 100644
index 000000000..0fa5f59df
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/rom.asm
@@ -0,0 +1,283 @@
+ PAGE ,132
+ TITLE ROM - Kernel ROM specific code
+
+.xlist
+include kernel.inc
+include protect.inc
+include pdb.inc
+.list
+
+if ROM ;----------------------------------------------------------------
+
+;------------------------------------------------------------------------
+; Local Macros & Equates
+;------------------------------------------------------------------------
+
+DPMICALL MACRO callno
+ ifnb <callno>
+ mov ax,callno
+ endif
+ int 31h
+ ENDM
+
+GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
+GA_MASK_BYTES = NOT GA_ALIGN_BYTES
+
+
+;------------------------------------------------------------------------
+; External Routines
+;------------------------------------------------------------------------
+
+externFP LZDecode
+
+;------------------------------------------------------------------------
+; Data Segment Variables
+;------------------------------------------------------------------------
+
+DataBegin
+
+if PMODE32
+externW gdtdsc
+externB MS_DOS_Name_String
+endif
+
+externW MyDSSeg
+externW WinFlags
+externD linHiROM
+externD lmaHiROM
+
+DataEnd
+
+
+;------------------------------------------------------------------------
+; INITDATA Variables
+;------------------------------------------------------------------------
+
+DataBegin INIT
+
+DataEnd INIT
+
+
+;------------------------------------------------------------------------
+
+
+sBegin INITCODE
+assumes cs,CODE
+
+
+;-----------------------------------------------------------------------;
+; ROMInit ;
+; ;
+; Performs ROM specific initialization. ;
+; ;
+; Arguments: ;
+; DS = ES = SS = selector to conventional RAM mem block & PSP ;
+; for kernel use. ;
+; SP = offset in conventional RAM block ;
+; SS:SP = [near ret to ldboot] [far ret to invoker] ;
+; CX:DX = linear address of hi rom (as opposed to physical) ;
+; set by DOSX or the fake KRNL386 which enh exec's ;
+; ;
+; Returns: ;
+; BX = 0 ;
+; DS:0 = Kernel's RAM Data segment ;
+; ES:0 = Kernel's PSP ;
+; ;
+; Regs Used: ;
+; AX, CX, DX, DI ;
+; ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+ assumes ss,nothing
+
+
+cProc ROMInit,<PUBLIC,NEAR>,<es>
+ localW selNewDS
+ localW selBaseMem
+ localD lpProc
+if PMODE32
+ localD romhilinear
+ localD linDOSBlock
+ localD cbDOSBlock
+endif
+cBegin
+if PMODE32
+ mov word ptr romhilinear[0], dx
+ mov word ptr romhilinear[2], cx
+endif
+
+; On entry we do not have a RAM copy of our data segment, set up a
+; selector for on in the conventional memory block. This will become
+; the first block in the global heap...
+
+ mov cx,1 ;allocate 1 selector to use for DS
+ DPMICall 0000h
+;;; jc RIFailed ; worry about this?
+
+ mov selNewDS,ax ;save new selector
+
+ DPMICall 0000h ;and another for base memory ptr
+;;; jc RIFailed ; worry about this?
+
+ mov selBaseMem,ax
+
+ mov bx,ds ;get base of conventional memory blk
+ DPMICall 0006h ; and PSP
+
+if PMODE32
+ mov word ptr linDOSBlock[0], dx
+ mov word ptr linDOSBlock[2], cx
+endif
+
+ add dx,100h+GA_ALIGN_BYTES ;point selBaseMem past PSP and
+ adc cx,0 ; align for initial heap sentinal
+ and dl,GA_MASK_BYTES
+ mov bx,selBaseMem
+ DPMICall 0007h
+
+ife PMODE32
+ add dx,10h+GA_ALIGN_BYTES ;align DS selector and leave room
+ adc cx,0 ; for heap sentinel & arena
+ and dl,GA_MASK_BYTES ; (where DS arena goes)
+ add dx,10h
+ adc cx,0 ; (where DS goes)
+endif
+
+ push cx ;save RAM DS base on stack
+ push dx
+
+ mov bx,selNewDS ;set base of new DS selector
+ DPMICall 0007h
+
+ xor cx,cx ;set limit of new DS selector
+ xor dx,dx ; to 64k for now
+ dec dx
+ DPMICall 0008h
+
+
+ xor ax,ax
+ mov si,seg _DATA
+ mov dx,0E000h ;ASSUMES kernel ds < E000 & uncompress
+ ; buffer < 2000 bytes
+ push es
+ cCall LZDecode,<bx,si,bx,dx> ; uncompress our DS
+ pop es
+
+ mov dx,ax ;ax = # expanded bytes, make this
+ dec dx ; the new limit for selNewDS
+ xor cx,cx
+ mov bx,selNewDS
+ DPMICall 0008h
+
+ mov ds,bx
+ ReSetKernelDS
+
+
+; Update the original data selector to point to the RAM copy
+
+ mov bx,seg _DATA ;orig DS selector
+ pop dx ;base of RAM data seg
+ pop cx
+ DPMICall 0007h
+
+ push cx
+ push dx
+ mov cx,ds
+ lsl dx,cx ;increase limit of DS selector
+ add dx,ROMEXTRASTACKSZ ; to include extra stack space
+ xor cx,cx
+ DPMICall 0008h
+
+ mov cl,DSC_PRESENT OR DSC_DATA ; and make sure it's writable
+ DPMICall 0009h
+
+ pop dx
+ pop cx
+
+ mov ds,bx ;use orig DS selector and free temp
+ ReSetKernelDS
+
+ mov bx,selNewDS
+ DPMICall 0001h
+
+ mov bx,cx ;convert RAM DS base to segment & save
+ mov cx,4
+@@: shr bx,1
+ rcr dx,1
+ loop @b
+
+ mov MyDSSeg,dx
+
+if PMODE32
+.386p
+ ; now that we're looking at our ds, set the linear address of the
+ ; high ROM
+ mov eax, romhilinear
+ or eax, eax
+ jnz @F
+ mov eax, lmaHiROM
+@@: mov linHiROM, eax
+endif
+
+; Set WinFlags to have the CPU type
+
+ DPMICall 0400h ;returns CPU type in CL
+
+ mov ax,WF_CPU286
+ cmp cl,2
+ jbe @f
+ mov al,WF_CPU386
+ cmp cl,3
+ je @f
+ mov al,WF_CPU486
+@@:
+ mov WinFlags,ax
+
+if PMODE32
+ push es
+ mov ax, 168Ah ; See if we have MS-DOS extensions
+ mov si, dataoffset MS_DOS_Name_String
+ int 2Fh ; DS:SI -> MS-DOS string
+ cmp al, 8Ah ; Have extensions?
+ je short NoLDTParty ; no extensions, screwed
+
+ mov word ptr [lpProc][0], di ; Save CallBack address
+ mov word ptr [lpProc][2], es
+
+ mov ax, 0100h ; Get base of LDT
+ call [lpProc]
+ jc short NoLDTParty
+ verw ax ; Writeable?
+ jnz short NoLDTParty ; nope, don't bother with it yet
+
+ mov gdtdsc, ax
+
+NoLDTParty:
+ pop es
+
+ ;; now page-unlock the DOS block
+ ;;
+ mov bx, es:[PDB_Block_Len]
+ DPMICALL 0006h
+ mov si, cx
+ mov di, dx
+ mov cx, word ptr linDOSBlock[0]
+ mov bx, word ptr linDOSBlock[2]
+ sub di, cx
+ sbb si, bx
+ DPMICALL 0602h
+endif
+
+ xor bx,bx ;return 0 in BX (for LDT_Init)
+ mov si,selBaseMem ;return selector to memory base in SI
+
+cEnd
+
+sEnd INITCODE
+
+endif ;ROM ---------------------------------------------------------
+
+end
diff --git a/private/mvdm/wow16/kernel31/schedule.asm b/private/mvdm/wow16/kernel31/schedule.asm
new file mode 100644
index 000000000..cf7d27fc5
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/schedule.asm
@@ -0,0 +1,674 @@
+ title SCHEDULE - task scheduler
+
+.xlist
+include kernel.inc
+include tdb.inc
+include eems.inc
+include newexe.inc
+.list
+
+if PMODE32
+.386
+endif
+
+externFP WriteOutProfiles
+externFP GlobalCompact
+externFP GetFreeSpace
+
+;if KDEBUG
+;externFP OutputDebugString
+;endif
+
+DataBegin
+
+externB Kernel_InDOS
+externB Kernel_flags
+externB InScheduler
+externB fProfileDirty
+externB fProfileMaybeStale
+externB fPokeAtSegments
+externW WinFlags
+;externW EMSCurPID
+;externW cur_drive_owner
+externW curTDB
+externW Win_PDB
+externW LockTDB
+externW headTDB
+externW hShell
+externW pGlobalHeap
+externW hExeHead
+externW f8087
+externW
+if PMODE32
+externW PagingFlags
+externD pDisplayCritSec
+endif
+externD pIsUserIdle
+
+if KDEBUG
+externB fPreloadSeg
+endif
+
+staticW PokeCount,0
+
+DataEnd
+
+sBegin CODE
+assumes cs,CODE
+assumes ds,NOTHING
+assumes es,NOTHING
+
+externNP LoadSegment
+externNP DeleteTask
+externNP InsertTask
+if PMODE32
+externNP DiscardFreeBlocks
+externNP ShrinkHeap
+endif
+
+if SDEBUG
+externNP DebugSwitchOut
+externNP DebugSwitchIn
+endif
+
+;-----------------------------------------------------------------------;
+; Reschedule ;
+; ;
+; This routine does the task switching. ;
+; ;
+; Arguments: ;
+; none ;
+; Returns: ;
+; nothing ;
+; Error Returns: ;
+; nothnig ;
+; Registers Preserved: ;
+; AX,BX,CX,DX,DI,SI,BP,DS,ES ;
+; Registers Destroyed: ;
+; none ;
+; Calls: ;
+; DeleteTask ;
+; InsertTask ;
+; SaveState ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
+; Removed the WinOldApp support and DEC rainbow support. ;
+; ;
+; Fri 07-Apr-1989 22:16:02 -by- David N. Weise [davidw] ;
+; Added support for task ExeHeaders above The Line in Large ;
+; Frame EMS. ;
+; ;
+; Sat Aug 15, 1987 11:41:35p -by- David N. Weise [davidw] ;
+; Commented out the cli and sti around the swapping of states. ;
+; Sweet Lord, what will this break? ;
+; ;
+; Fri Feb 06, 1987 00:09:20a -by- David N. Weise [davidw] ;
+; Put in support for DirectedYield. ;
+; ;
+; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
+; Got rid of going inside of DOS for InDOS and ErrorMode. Task ;
+; switching should be much better under Windows386 now. ;
+; ;
+; Mon Sep 29, 1986 05:27:29p -by- Charles Whitmer [chuckwh] ;
+; Made it recognize threads. It now does a fast context switch if ;
+; just switching between two threads in the same process. ;
+; ;
+; Mon Sep 29, 1986 05:24:16p -by- Charles Whitmer [chuckwh] ;
+; Documented it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc Reschedule,<PUBLIC,FAR>
+cBegin nogen
+
+; get all the registers up on the stack
+
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ push si
+ push di
+ push ax
+ push cx
+ push es
+ push bx
+ push dx
+
+ public BootSchedule
+BootSchedule:
+ call TaskSwitchProfileUpdate ;Update profile information
+
+ public ExitSchedule
+ExitSchedule:
+
+; see if we're supposed to do a directed yield
+
+ SetKernelDS es
+ mov cx,curTDB
+ jcxz search_the_queue ; this happens first after boot time!
+ mov ds,cx
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jnz short search_the_queue ; task may have suicided
+ xor cx,cx
+ xchg ds:[TDB_Yield_to],cx
+ jcxz search_the_queue ; nope
+ mov ds,cx
+ cmp ds:[TDB_nevents],0 ; anything for this guy?
+ jnz found_one
+
+; run down the task queue looking for someone with events
+
+search_the_queue:
+ CheckKernelDS es
+ mov ax,HeadTDB
+keep_searching:
+ or ax,ax ; Anyone to schedule?
+ jnz short try_this_one ; Yes, go do it
+
+; if no one is dispatchable, do an idle interrupt
+
+if PMODE32
+ xor PagingFlags, 4
+ test PagingFlags, 4
+ jnz short NoDiscarding ; Every other time through!
+
+ test PagingFlags, 8 ; An app has exited?
+ jz short NoShrink
+ push es
+ call ShrinkHeap
+ pop es
+NoShrink:
+
+;;; or PagingFlags, 2 ; Causes early exit from GlobalCompact
+;;; mov ax, -1
+;;; push es
+;;; cCall GlobalCompact,<ax,ax>
+;;; pop es
+;;; and PagingFlags, not 2
+
+ test byte ptr WinFlags[1], WF1_PAGING
+ jz short NoDiscarding
+ test PagingFlags, 1
+ jz short NoDiscarding
+ call DiscardFreeBlocks
+ jmps search_the_queue
+NoDiscarding:
+endif
+
+ mov ax, 1 ; Assume User is idle
+ cmp word ptr pIsUserIdle[2], 0
+ je short go_idle
+ call pIsUserIdle
+ SetKernelDS es
+go_idle:
+
+ cmp fPokeAtSegments, 0 ; Disabled?
+ je short @F ; yep, skip
+ or ax, ax ; Only if USER is idle
+ jz short @F
+ inc PokeCount
+ test PokeCount, 1Fh ; Only every 32 times through
+ jnz short @F
+ call PokeAtSegments
+ jc search_the_queue
+@@:
+ push ax ; Ralph's paranoia
+ int 28h ; No, generate DOS idle int
+ pop ax
+ xor bx, bx
+ or ax, ax
+ jnz short tell_ralph
+ or bl, 1
+tell_ralph:
+ mov ax,1689h ; Do an idle to Win386.
+ int 2fh
+ jmp search_the_queue
+
+get_out_fast:
+ jmp reschedule_done
+
+; see if the given task has events
+
+try_this_one:
+ mov ds,ax
+ mov ax,ds:[TDB_next]
+ cmp ds:[TDB_nevents],0 ; anything for this guy?
+ jz keep_searching
+
+; is this the guy we're already running?
+
+found_one:
+ mov di,ds ; DI = handle of new task
+ cmp di,curTDB
+ jz short get_out_fast
+
+; is there a locked task?
+
+ mov cx,LockTDB ; are any tasks super priority?
+ jcxz no_locked_task
+ cmp cx,di ; are we it?
+ jnz short get_out_fast ; No => don't switch
+no_locked_task:
+
+; don't switch if in DOS or int 24 handler
+
+ cmp Kernel_InDOS,0 ; if inside INT2[0,4] handler
+ jnz keep_searching ; ...don't reschedule
+
+ inc InScheduler ; set flag for INT 24...
+
+ inc ds:[TDB_priority] ; lower task priority
+ push es
+ UnSetKernelDS es
+ cCall DeleteTask,<ds> ; remove him from queue
+ cCall InsertTask,<ds> ; put him back further down
+ dec ds:[TDB_priority] ; restore former priority
+ pop es
+ ReSetKernelDS es
+
+; Around saving state and restoring state go critical on memory
+; heap access because of EMS.
+
+ push es
+ mov es,pGlobalHeap
+ UnSetKernelDS es
+ inc es:[gi_lrulock]
+ pop es
+ ReSetKernelDS es
+
+; Signature is trashed when we suicide so we dont save state
+; for the non-existant task.
+
+ mov di,ds ; DI = destination task
+ xor si,si ; SI is an argument to RestoreState
+ mov es,curTDB ; ES = current TDB
+ UnSetKernelDS es
+ mov ax,es
+ or ax,ax
+ jz short dont_save_stack
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jnz short dont_save_stack
+ mov si,es ; SI = current task
+
+; save the present stack
+
+ mov es:[TDB_taskSS],ss
+ mov es:[TDB_taskSP],sp
+dont_save_stack:
+
+; get onto a temporary stack while we switch the EEMS memory
+
+ mov ax,es
+ or ax,ax
+ jz short dont_save_state
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jnz short dont_save_state
+
+ cCall SaveState,<si>
+ push ds
+ mov ds,ax
+if SDEBUG
+ call DebugSwitchOut
+endif
+ pop ds
+dont_save_state:
+ SetKernelDS es
+ mov curTDB,di
+
+ mov ax, ds:[TDB_PDB] ; Set our idea of the PDB
+ mov Win_PDB, ax
+ ;;;mov ax,ds:[TDB_EMSPID]
+ ;;;mov EMSCurPID,ax
+ cmp f8087, 0
+ je short no_fldcw
+ .8087
+ fnclex
+ fldcw ds:[TDB_FCW]
+no_fldcw:
+
+ or Kernel_flags,kf_restore_CtrlC OR kf_restore_disk
+if SDEBUG
+ call DebugSwitchIn
+endif
+
+fast_switch:
+ mov cx,ds:[TDB_taskSS] ; Switch to new task stack.
+ mov ax,ds:[TDB_taskSP]
+ mov ss,cx
+ mov sp,ax
+ mov curTDB,di
+ dec InScheduler ; reset flag for INT 24
+
+if PMODE32
+ mov al,Kernel_Flags[2]
+ and Kernel_Flags[2],NOT KF2_WIN386CRAZINESS
+
+; Tell the display driver to speak its mind. added 20 feb 1990
+
+ test al,KF2_WIN386CRAZINESS
+ jz short @F
+ xor ax,ax
+ push es ; preserve es
+ cCall pDisplayCritSec,<ax>
+ pop es
+@@:
+endif
+
+; Around saving state and restoring state go critical on memory
+; arena access because of EMS.
+
+ mov es,pGlobalHeap
+ UnSetKernelDS es
+ dec es:[gi_lrulock]
+
+; pop the task's registers off the stack
+
+reschedule_done:
+ pop dx
+ pop bx
+ pop es
+ pop cx
+ pop ax
+ pop di
+ pop si
+ pop ds
+ pop bp
+ dec bp
+ public dispatch
+dispatch:
+ ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; LockCurrentTask ;
+; ;
+; Hack procedure to make the current task god if the passed boolean ;
+; is true. ;
+; If false, then demotes the current god to a mere mortal. Self ;
+; inflicted by definition. ;
+; ;
+; DavidDS: Note, the USER function, LockMyTask should be called for ;
+; Windows apps instead of this if you expect the input queue to work ;
+; properly. ;
+; ;
+; Arguments: ;
+; ParmW lock ; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,DI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; AX,BX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sun Jan 04, 1987 04:37:11p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc LockCurrentTask,<PUBLIC,FAR>
+; ParmW lock
+cBegin nogen ; Crock to save space
+ mov bx,sp
+ mov ax,ss:[bx][4] ; get the argument
+ push ds
+ SetKernelDS
+ or ax,ax
+ jz short lct1
+ mov ax,curTDB
+lct1:
+ mov LockTDB,ax
+ pop ds
+ UnSetKernelDS
+ ret 2
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; IsTaskLocked ;
+; ;
+; Another hack procedure to determine if the current task is locked. ;
+; A non-NULL value is returned if the task is locked and NULL is ;
+; returned is the task is not locked. ;
+; ;
+; Arguments: ;
+; ; ;
+; Returns: ;
+; The value of LockTDB ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; All but AX ;
+; ;
+; Registers Destroyed: ;
+; AX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; (Tue 20-Oct-1987 : bobgu) Created this thing. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc IsTaskLocked,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ SetKernelDS
+ mov ax,LockTDB
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; SaveState ;
+; ;
+; Saves the state of the current MS-DOS process. This means the per ;
+; task interrupt vectors, the drive and directory, EEMS land if any, ;
+; and old app stuff if any. ;
+; ;
+; Arguments: ;
+; parmW destination ;
+; ;
+; Returns: ;
+; DS returned in AX. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
+; Removed the WinOldApp support. ;
+; ;
+; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
+; Got rid of the rest of the DOS version dependencies. ;
+; ;
+; Thu Jan 22, 1987 03:15:15a -by- David N. Weise [davidw] ;
+; Took out the saving of the ^C state, DTA address, and ErrorMode. ;
+; ;
+; Sun Jan 04, 1987 04:40:44p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SaveState,<PUBLIC,NEAR>,<si,di,ds>
+ parmW destination
+cBegin
+ cld
+ SetKernelDS
+ mov ax,f8087
+ UnSetKernelDS
+ mov ds,destination
+ or ax,ax
+ jz short no_fstcw
+ .8087
+ fstcw ds:[TDB_FCW]
+no_fstcw:
+ test ds:[TDB_Drive],10000000b; if hi bit set....
+ jnz short ss_ret ; ...no need to get dir
+ mov ah,19h
+ int 21h
+ mov dl,al
+ inc dl
+ or al,10000000b
+ mov ds:[TDB_Drive],al ; save it (A=0, B=1, etc.)
+ mov si,TDB_Directory
+ mov byte ptr [si],'\' ; set "\"
+ inc si
+ mov ah,47h ; get current directory...
+ int 21h
+ jnc short ss_ret
+ mov byte ptr [si-1],0 ; indicate error with null byte
+ss_ret: mov ax,ds
+cEnd
+
+
+cProc TaskSwitchProfileUpdate,<PUBLIC,NEAR>
+cBegin
+ SetKernelDS es
+
+ ;** See if we need to write out the profile string cache. We
+ ;** do this at task switch time.
+ cmp es:fProfileDirty, 0
+ je short PU_NoFlushProfiles
+ push es
+ call WriteOutProfiles
+ pop es
+PU_NoFlushProfiles:
+
+ ;** Set the flag saying that the profile cache MAY be invalid.
+ ;** If a task switch occurs, on the next Get/SetProfileXXX() we
+ ;** will have to see if the file has been modified by this
+ ;** (or any other) task
+ mov es:fProfileMaybeStale,1
+cEnd
+
+assumes ds, nothing
+assumes es, nothing
+
+if PMODE32
+.386
+else
+.286
+endif
+
+cProc PokeAtSegments,<PUBLIC,NEAR>
+cBegin
+ push ds
+ push es
+ pusha
+
+ cCall GetFreeSpace,<2> ; Ignore discardable
+ or dx, dx ; Insist on > 64k free
+if KDEBUG
+ jz never_again
+else
+ jz short never_again
+endif
+
+if PMODE32
+ SetKernelDS
+
+ test WinFlags[1], WF1_PAGING
+ jz short have_room
+
+ sub sp, 30h ; Room for info
+ smov es, ss
+ mov di, sp
+ mov ax, 0500h ; Get Paging Info
+ int 31h
+ mov eax, es:[di][14h] ; Free pages
+ add sp, 30h
+ cmp eax, 16 ; Insist on 64k
+ jb short never_again
+
+have_room:
+ smov es, ds
+ ResetKernelDS es
+else
+ SetKernelDS es
+endif
+
+ mov ds, hExehead
+ UnsetKernelDS
+
+next_exe:
+ mov cx, ds:[ne_cseg] ; Module has segments?
+ jcxz no_segs ; no, on to next module
+ mov di, 1 ; Segment number
+ mov si, ds:[ne_segtab] ; Pointer to segment table
+
+next_seg:
+ test ds:[si].ns_flags, NSLOADED ; This segment in memory?
+ jnz short seg_here ; yes, look at next one
+ test ds:[si].ns_flags, NSDISCARD ; Only load if discardable
+ jz short seg_here ; Skip this one
+if KDEBUG
+ push ds
+ SetKernelDS
+ mov fPreloadSeg, 1
+ pop ds
+ UnsetKernelDS
+endif
+ cCall LoadSegment,<ds,di,-1,-1>
+if KDEBUG
+ push ds
+ SetKernelDS
+ mov fPreloadSeg, 0
+ pop ds
+ UnsetKernelDS
+endif
+ stc ; We loaded something!
+ jmps all_done
+
+seg_here:
+ lea si, [si + size NEW_SEG1] ; On to next segment
+ inc di
+ loop next_seg ; looked at all in this module?
+
+no_segs:
+ mov cx, ds:[ne_pnextexe] ; On to next module
+ jcxz all_done ; End of list?
+ mov ax, ds
+ mov ds, cx
+ cmp ax, hShell ; Only boot time modules
+ jne short next_exe
+ UnSetKernelDS es
+never_again:
+ SetKernelDS
+ mov fPokeAtSegments, 0 ; That's all folks
+ clc
+all_done:
+ popa
+ pop es
+ pop ds
+cEnd
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/kernel31/stack.asm b/private/mvdm/wow16/kernel31/stack.asm
new file mode 100644
index 000000000..749e30e30
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/stack.asm
@@ -0,0 +1,126 @@
+ TITLE STACK - Kernel stack switching code
+
+
+include kernel.inc
+ifdef WOW
+include vint.inc
+endif
+
+
+;------------------------------------------------------------------------
+; T M P S T A C K S E G M E N T V A R I A B L E S
+;------------------------------------------------------------------------
+
+sBegin DATA
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+assumes SS,NOTHING
+
+ EVEN
+
+if KDEBUG
+externW gmove_stack_sig
+endif
+
+externW gmove_stack
+
+externW prev_gmove_SP
+externW prev_gmove_SS
+externW ss_sel
+
+sEnd DATA
+
+
+;------------------------------------------------------------------------
+
+sBegin CODE
+assumes CS,CODE
+assumes SS,NOTHING
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Enter_gmove_stack,<PUBLIC,NEAR>
+cBegin nogen
+ mov ax,ds
+ SetKernelDS
+ cmp prev_gmove_SS,0
+ jne gs_fail
+ FCLI
+ pop gmove_stack
+;;;if PMODE
+;;; mov ss_sel,ss
+;;;endif
+ mov prev_gmove_SS,cx
+ mov prev_gmove_SP,sp
+if KDEBUG
+ mov gmove_stack_sig,STACK_SIGNATURE
+endif
+ smov ss,ds
+ mov sp,dataOffset gmove_stack
+ FSTI
+ mov ds,ax
+ ret
+cEnd nogen
+
+gs_fail:
+ kerror ERR_GMEM,<gmove_stack usage error>,prev_gmove_SS,prev_gmove_SP
+ jmp gs_fail
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Leave_gmove_stack,<PUBLIC,NEAR>
+cBegin nogen
+ mov ax,ds
+ SetKernelDS
+ cmp prev_gmove_SS,0
+ je gs_fail
+if KDEBUG
+ push ax
+ push cx
+ push es
+ push di
+ lea di, gmove_stack_sig
+ smov es, ss
+ mov ax, STACK_SIGNATURE
+ mov cx, 16
+ cld
+ repe scasw
+ pop di
+ pop es
+ pop cx
+ pop ax
+ jne gs_fail
+ cmp sp,dataOffset gmove_stack
+ jne gs_fail
+endif
+
+;;;if PMODE
+;;;externNP get_physical_address
+;;;externNP set_physical_address
+;;; push ax
+;;; push dx
+;;; cCall get_physical_address,<prev_gmove_SS>
+;;; cCall set_physical_address,<ss_sel>
+;;; pop dx
+;;; pop ax
+;;; FCLI
+;;; mov ss,ss_sel
+;;;else
+
+ FCLI
+ mov ss,prev_gmove_SS
+;;;endif
+ mov sp,prev_gmove_SP
+ push gmove_stack
+ mov prev_gmove_SS,0
+ FSTI
+ mov ds,ax
+ ret
+cEnd nogen
+
+sEND CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/state.rst b/private/mvdm/wow16/kernel31/state.rst
new file mode 100644
index 000000000..bc8121748
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/state.rst
@@ -0,0 +1,7 @@
+1 1 0 1 0
+ptrace
+
+
+[FILES]
+e:\src\core\kernel\lddebug.asm
+1657 1
diff --git a/private/mvdm/wow16/kernel31/swappro/makefile b/private/mvdm/wow16/kernel31/swappro/makefile
new file mode 100644
index 000000000..702f71e7b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/swappro/makefile
@@ -0,0 +1,15 @@
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+swap: swap.exe
+
+swap.obj: swap.c
+ cl16 -c -AL -Ox -G2 -Zp swap.c
+
+swap.exe: swap.obj
+ link16 /nod swap,swap,,llibcep doscalls;
+ bind16 swap.exe apilmr.obj api.lib doscalls.lib
diff --git a/private/mvdm/wow16/kernel31/swappro/swap.c b/private/mvdm/wow16/kernel31/swappro/swap.c
new file mode 100644
index 000000000..005137833
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/swappro/swap.c
@@ -0,0 +1,757 @@
+/* Chris Peters
+ * CHANGED: Fritz Knabe, 7/28/87
+ * mikedr, 8/8/88 - read offset bytes after 0xff seg no on swap
+ * allow specification of data file location
+ * c-chrisc [Christine Comaford], 10/31/89 - added "-i" flag to
+ * allow symbol file path spec on command line, added "-m"
+ * flag to precede module spec, rewrote module parser,
+ * added usage display, misc other enhancements.
+ *
+ * Copyright Microsoft Corporation, 1985-1990
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <memory.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+/* standard stuff */
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+
+BOOL FModuleMatch(BYTE *, BYTE);
+int GetSymbolString(BYTE *, BYTE *, WORD, WORD);
+int GetSegNum(char *, char *);
+BYTE *htoa(BYTE *, WORD);
+char *ProcessArguments(int, char **);
+
+/* Debug Symbol Table Structures
+ -----------------------------
+For each symbol table (map): (MAPDEF)
+-------------------------------------------------------------------------------------------------
+| map_ptr | lsa | pgm_ent | abs_cnt | abs_ptr | seg_cnt | seg_ptr | nam_max | nam_len | name... |
+------------------------------------------------------------------------------------------------- */
+struct mapdef
+{
+ unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */
+ unsigned lsa ; /* 16 bit Load Segment address */
+ unsigned pgm_ent; /* 16 bit entry point segment value */
+ int abs_cnt; /* 16 bit count of constants in map */
+ unsigned abs_ptr; /* 16 bit ptr to constant chain */
+ int seg_cnt; /* 16 bit count of segments in map */
+ unsigned seg_ptr; /* 16 bit ptr to segment chain */
+ char nam_max; /* 8 bit Maximum Symbol name length */
+ char nam_len; /* 8 bit Symbol table name length */
+};
+
+struct mapend
+{
+ unsigned chnend; /* end of map chain (0) */
+ char rel; /* release */
+ char ver; /* version */
+};
+
+/* For each segment/group within a symbol table: (SEGDEF)
+--------------------------------------------------------------
+| nxt_seg | sym_cnt | sym_ptr | seg_lsa | name_len | name... |
+-------------------------------------------------------------- */
+struct segdef
+{
+ unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */
+ int sym_cnt; /* 16 bit count of symbols in sym list */
+ unsigned sym_ptr; /* 16 bit ptr to symbol list */
+ unsigned seg_lsa; /* 16 bit Load Segment address */
+ unsigned seg_in0; /* 16 bit instance 0 physical address */
+ unsigned seg_in1; /* 16 bit instance 1 physical address */
+ unsigned seg_in2; /* 16 bit instance 2 physical address */
+ unsigned seg_in3; /* 16 bit instance 3 physical address */
+ unsigned seg_lin; /* 16 bit ptr to line number record */
+ char seg_ldd; /* 8 bit boolean 0 if seg not loaded */
+ char seg_cin; /* 8 bit current instance */
+ char nam_len; /* 8 bit Segment name length */
+};
+
+/* Followed by a list of SYMDEF's..
+ for each symbol within a segment/group: (SYMDEF)
+-------------------------------
+| sym_val | nam_len | name... |
+------------------------------- */
+struct symdef
+{
+ unsigned sym_val; /* 16 bit symbol addr or const */
+ char nam_len; /* 8 bit symbol name length */
+};
+
+typedef struct tagMODSEG /* Structure for saving information */
+{ /* about cmd line arguments */
+ int segno; /* Special values:
+ -1 information about all segments in the module
+ is supplied
+ -2 an invalid segment name was supplied, i.e.
+ nothing matches this record/argument
+ >=0 valid segment number
+ */
+ char szModule[32]; /* Name of module */
+} MODSEG, *PMODSEG;
+
+
+/*----------------------------------------------------------------------------
+| Global Variables
+|
+----------------------------------------------------------------------------*/
+
+#define MAX_ARGS 34 /* arbitrary (but reasonable) values */
+#define MAX_PATHS 16
+
+char curpath_buffer[65]; /* buffer holding current sym file path */
+char path_buffer[132]; /* buffer holding cmd line sym path string */
+char *path_table[MAX_PATHS]; /* table of sym file buffers */
+
+int num_paths = 0; /* index into path_table[] */
+int nNumArgs; /* Number of command line arguments */
+
+char *ModSegTab[MAX_ARGS]; /* Table of MODSEG records */
+
+BOOL bModule = FALSE; /* is module specified on command line? */
+BOOL bSymPath = FALSE; /* is symbol file path specified on command line? */
+
+int num_mods = 0; /* index into module table */
+
+
+char usage[] = "\nUSAGE: SWAP [-Ipath1;path2;...] [-Fswapfile] [-Mmod1[:seg];mod2[:seg];...]\n\n"
+ " -Ipath1;path2;... -- Path list for .SYM files.\n\n"
+ " -Fswapfile -- Name and path of swap file,\n"
+ " default: swappro.dat.\n\n"
+ " -Mmod1[:seg];mod2[:seg];... -- Name of module or module:segment\n"
+ " pairs to return swap data for.\n";
+
+
+/*----------------------------------------------------------------------------
+| Main Program
+|
+|
+----------------------------------------------------------------------------*/
+
+/* Structure of swappro.dat records:
+ BYTE type; 0 = Call, 1 = Swap, 2 = Discard, 3 = Return
+ WORD time;
+ BYTE nam_len; Length of following name (not null terminated)
+ BYTE name[];
+ BYTE segno; This is the end of the record for DISCARD records
+ or resources (segno == 0xFF)
+ WORD offset; This is the end of the record for types 2 and 3
+ BYTE nam2_len; If 0, the next field missing, and the name is the
+ same as the previous one
+ BYTE name2[];
+ BYTE segno2;
+ BYTE offset2;
+*/
+
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ register FILE *pfIn;
+ BYTE rgch1[256];
+ BYTE rgch2[256];
+ register BYTE stModule[32], stModule2[32];
+ BYTE rt;
+ BYTE cch;
+ WORD t;
+ WORD segno = 0, segno2 = 0;
+ WORD offset, offset2;
+ BOOL fFirst = TRUE;
+ long time, timePrev, timeBase;
+ char *filepath;
+
+
+ /* sign on */
+
+ printf("Microsoft (R) Swap File Analyzer Version 3.00\n");
+ printf("Copyright (C) Microsoft Corp 1990. All rights reserved.\n\n");
+
+ filepath = ProcessArguments(argc, argv);
+ if (filepath == NULL)
+ filepath = "swappro.dat";
+
+ pfIn = fopen(filepath,"rb");
+ if (pfIn == NULL)
+ {
+ printf("\nFile %s not found.\n",filepath);
+ exit(2);
+ }
+
+ printf("\nType\tTime\tSegment\tOffset\tSegment\tOffset");
+ printf("\n----\t----\t-------\t------\t-------\t------");
+
+ while(!feof(pfIn))
+ {
+ fread(&rt, 1, 1, pfIn); /* Get the record type */
+
+ timePrev = time;
+ fread(&t, 2, 1, pfIn); /* Get the time */
+ time = t;
+ if (fFirst)
+ {
+ timePrev = 0;
+ timeBase = time;
+ fFirst = FALSE;
+ }
+ time -= timeBase;
+ if (time < timePrev)
+ {
+ time += 65536;
+ timeBase -= 65536;
+ }
+
+ switch (rt)
+ {
+ default:
+ printf("\n **** Invalid swap record ****");
+ break;
+
+ case 0: /* Call */
+ case 1: /* Swap */
+ fread(stModule, 1, 1, pfIn);
+ fread(stModule+1, 1, stModule[0], pfIn);
+ fread(&segno, 1, 1, pfIn);
+ if (segno != 0xFF)
+ fread(&offset, 2, 1, pfIn);
+
+ else /* We have a RESOURCE, so we don't fread */
+ offset = 0xFFFF;
+
+ fread(stModule2, 1, 1, pfIn);
+ /* Check if this module name is the same as
+ stModule */
+ if (stModule2[0])
+ fread(stModule2+1, 1, stModule2[0], pfIn);
+ else
+ memcpy(stModule2, stModule, 1 + stModule[0]);
+
+ /* read segment and offset */
+ fread(&segno2, 1, 1, pfIn);
+ fread(&offset2, 2, 1, pfIn);
+ if (segno2 == 0xFF)
+ offset2 = 0xFFFF;
+
+ if (bModule)
+ {
+
+ if (!FModuleMatch(stModule, segno) &&
+ !FModuleMatch(stModule2, segno2))
+ break;
+ }
+
+ GetSymbolString(rgch1, stModule, segno, offset);
+ GetSymbolString(rgch2, stModule2, segno2, offset2);
+
+ if (rt == 1)
+ printf("\nSwap");
+ else
+ printf("\nCall");
+ printf("\t%ld\t%s\t%s",time, rgch1, rgch2);
+ break;
+
+ case 2: /* Discard */
+ case 3: /* Return */
+ fread(stModule, 1, 1, pfIn);
+ fread(stModule+1, 1, stModule[0], pfIn);
+ fread(&segno, 1, 1, pfIn);
+ if (rt == 2 || segno == 0xFF)
+ offset = 0xFFFF;
+ else
+ /* Only read offset if not a DISCARD
+ record or a resource */
+ fread(&offset, 2, 1, pfIn);
+
+
+ if (bModule)
+ {
+
+ if (!FModuleMatch(stModule, segno))
+ break;
+
+ }
+
+ GetSymbolString(rgch1, stModule, segno, offset);
+ if (rt == 2)
+ printf("\nDiscard");
+ else
+ printf("\nReturn");
+ printf("\t%ld\t%s",time,rgch1);
+ break;
+ }
+ }
+}
+
+
+/* returns pointer to swap data file name, NULL if none given */
+char *ProcessArguments(argc, argv)
+int argc;
+char *argv[];
+{
+ PMODSEG pms;
+ int i,j;
+ int nArgSep = 0;
+ int n = 0;
+ char *filepath = NULL;
+ char *curpath;
+ char ch;
+ char *opt;
+ char module_buffer[132];
+ char *curmodule;
+
+ #define MAX_MODULES 20
+ char *module_table[MAX_MODULES];
+
+
+ nNumArgs = (int) min(argc,MAX_ARGS);
+
+ if (nNumArgs < 2) /* No arguments */
+ return(filepath);
+
+ for (i = 1; i < argc; i++)
+ {
+ if ((*argv[i] == '-' || *argv[i] == '/'))
+ {
+ ch = tolower(argv[i][1]);
+
+ switch (ch) {
+
+ case 'f':
+ /* create swap data file spec */
+ filepath = &argv[i][2]; /* first char past flag */
+ if (!*filepath) /* skip white space */
+ {
+ i++; /* adjust command line variables */
+ nNumArgs--;
+ filepath = argv[i]; /* get file name from next arg */
+ }
+
+ nNumArgs--;
+ break;
+
+ case 'i':
+ bSymPath = TRUE;
+
+ /* place the current directory at the head of the symbol
+ table path */
+ getcwd(curpath_buffer, 132);
+ path_table[num_paths++] = curpath_buffer;
+
+ /* create symbol file spec */
+ strcpy(path_buffer, &argv[i][2]);
+
+ if (!*path_buffer)
+ {
+ /* space after flag, so increment index */
+ i++;
+
+ /* adjust command line arg count */
+ nNumArgs--;
+
+ /* get all symbol file path names from next arg */
+ strcpy (path_buffer, argv[i]);
+ }
+
+ strcat(path_buffer, ";");
+
+ curpath = strtok(path_buffer, ";");
+
+ do {
+ path_table[num_paths++] = curpath;
+ } while (curpath = strtok(NULL, ";"));
+
+ break;
+
+
+ case 'm':
+
+ /* create module and/or module:_segment file spec */
+
+ bModule = TRUE;
+
+ strcpy(module_buffer, &argv[i][2]);
+
+ if (!*module_buffer)
+ {
+ i++;
+ nNumArgs--;
+ strcpy(module_buffer, argv[i]);
+
+ }
+
+ strcat(module_buffer, ";");
+
+ /* fill module table with mod names */
+ curmodule = strtok(module_buffer, ";");
+
+ do {
+ module_table[num_mods++] = curmodule;
+ } while (curmodule = strtok(NULL, ";"));
+
+
+ /* for each module, assign segno if applicable */
+ for (j = 0; j < num_mods; j++)
+ {
+ if (!(pms = (PMODSEG) malloc(sizeof(MODSEG))))
+ {
+ printf ("MEMORY ALLOCATION FAILED!!!!");
+ exit (1);
+ }
+
+ /* determine whether a segment has been specified
+ (i.e., GDI:_FONTRES), look for a ':' */
+
+ nArgSep = strcspn(module_table[j], ":");
+ strncpy(pms->szModule, module_table[j], nArgSep);
+
+ pms->szModule[nArgSep] = '\0';
+
+ /* Get segment number */
+
+ /* First case: no segment specified; e.g. format of
+ arg would be "user" */
+ if (nArgSep == strlen(module_table[j]) ||
+ module_table[j][nArgSep+1] == '\0')
+ pms->segno = -1;
+
+ /* Second case: decimal segment number supplied; e.g.
+ "user:10" */
+ else if (isdigit(module_table[j][nArgSep+1]))
+ pms->segno = atoi(module_table[j]+nArgSep+1);
+
+ /* Third case: the segment name is "resource" */
+ else if (strcmpi(module_table[j]+nArgSep+1, "RESOURCE") == 0)
+ pms->segno = 0xFF;
+
+ /* Fourth case: a segment name is supplied; get
+ it's number */
+ else
+ {
+ pms->segno = GetSegNum(pms->szModule,
+ module_table[j]+nArgSep+1);
+
+ }
+
+ ModSegTab[n++] = (char *) pms;
+
+ }
+ break;
+
+ default:
+
+ /* Display cmd line args and quit */
+ fprintf(stderr, usage);
+ exit(1);
+ }
+
+ }
+
+ }
+
+ return(filepath);
+}
+
+
+
+/* Determines whether module specified on command line is equal to
+current module read in. No called if no mod, mod/seg is specified on
+command line. If false is returned, record won't be displayed. */
+
+BOOL FModuleMatch(stModule, segno)
+register BYTE stModule[];
+BYTE segno;
+{
+ register int i;
+ PMODSEG pms;
+
+
+ if (nNumArgs < 2)
+ return TRUE;
+
+ stModule[stModule[0]+1] = '\0';
+
+ for (i = 0; i < num_mods; i++)
+ {
+ pms = (PMODSEG) ModSegTab[i];
+
+ if (strcmpi(stModule+1, pms->szModule) == 0 &&
+ (pms->segno == -1 || pms->segno == segno))
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+int GetSegNum(szModule, szSegment)
+char *szModule;
+char *szSegment;
+{
+/* Gets the number of the named segment in the named module, if it exists.
+ This is a "stripped" version of GetSymbolString. */
+
+ char buf[50];
+ FILE *pfSym;
+ struct mapdef MAPDEF;
+ struct mapend MAPEND;
+ struct segdef SEGDEF;
+ WORD seg_ptr, fstseg_ptr;
+ int i;
+ register int pathcnt;
+ char symfile[65];
+
+
+ strcpy(symfile, szModule);
+ strcat(symfile, ".SYM");
+
+
+ if (bSymPath)
+ {
+ /* Loop through all symbol file paths until file is found */
+
+ for (pathcnt=0; pathcnt <num_paths; pathcnt++)
+ {
+ strcpy(buf, path_table[pathcnt]);
+ strcat(buf, "\\");
+ strcat(buf, symfile);
+
+ if (pfSym = fopen(buf, "rb"))
+ break;
+ }
+ }
+ else
+ pfSym = fopen(symfile, "rb");
+
+ if (!pfSym)
+ return -1;
+
+ fread(&MAPDEF, 1, sizeof(MAPDEF), pfSym);
+ fstseg_ptr = seg_ptr = (WORD)MAPDEF.seg_ptr;
+ fseek(pfSym, (long)-sizeof(MAPEND), 2);
+ fread(&MAPEND, 1, sizeof(MAPEND), pfSym);
+ if (MAPEND.ver != 3)
+ {
+ fclose(pfSym);
+ return -1;
+ }
+ i = 0;
+ do
+ {
+ if (MAPEND.rel >= 10)
+ fseek(pfSym, (long)(seg_ptr * 16), 0);
+ else
+ fseek(pfSym, (long)seg_ptr, 0);
+ fread(&SEGDEF, 1, sizeof(SEGDEF), pfSym);
+ seg_ptr = (WORD)SEGDEF.nxt_seg;
+ fread(buf, 1, SEGDEF.nam_len, pfSym);
+ buf[SEGDEF.nam_len] = '\0';
+ if (strcmpi(buf, szSegment) == 0)
+ {
+ fclose(pfSym);
+ return i;
+ }
+ i++;
+ }
+ while (seg_ptr && seg_ptr != fstseg_ptr);
+ fclose(pfSym);
+ return -2;
+}
+
+
+int GetSymbolString(pchOut, stModule, segno, offset)
+BYTE *pchOut; /* output buffer */
+BYTE stModule[]; /* module name */
+WORD segno; /* segment number */
+WORD offset; /* offset into segment */
+{
+ int cch;
+ register int i;
+ register BYTE *pch;
+ FILE *pfSym;
+ WORD seg_ptr;
+ long symPos1, symPos2;
+ struct mapdef MAPDEF;
+ struct mapend MAPEND;
+ struct segdef SEGDEF;
+ struct symdef SYMDEF;
+ BYTE *htoa();
+ register int pathcnt;
+ char symfile[65];
+ int len;
+
+
+ pch = stModule;
+
+ cch = *pch++;
+ pch = (BYTE *) memcpy(pchOut, pch, cch) + cch;
+
+ if((len = strlen(pchOut)) < 2)
+ return (-1);
+
+
+ pch[0] = '.';
+ pch[1] = 'S';
+ pch[2] = 'Y';
+ pch[3] = 'M';
+ pch[4] = 0;
+
+ if (bSymPath)
+ {
+ for (pathcnt=0; pathcnt <num_paths; pathcnt++)
+ {
+ strcpy(symfile, path_table[pathcnt]);
+ strcat(symfile, "\\");
+ strcat(symfile, pchOut);
+
+ if (pfSym = fopen(symfile, "rb"))
+ break;
+ }
+ }
+ else
+ pfSym = fopen(pchOut, "rb");
+
+
+ /* If symbol file not found, insert/append () around name */
+ if (pfSym == NULL)
+ {
+ pch = stModule;
+ cch = *pch++;
+ pch = (BYTE *) memcpy(pchOut+1, pch, cch) + cch;
+ *pchOut = '(';
+ *pch++ = ')';
+ if (offset != 0xFFFF)
+ *pch++ = '\t';
+ *pch = 0;
+ return(-1);
+ }
+
+ fread(&MAPDEF, 1, sizeof(MAPDEF), pfSym);
+
+ *pch++ = '!';
+ if (segno == 0xFF)
+ {
+ *pch++ = 'R';
+ *pch++ = 'E';
+ *pch++ = 'S';
+ *pch++ = 'O';
+ *pch++ = 'U';
+ *pch++ = 'R';
+ *pch++ = 'C';
+ *pch++ = 'E';
+ *pch = 0;
+ fclose(pfSym);
+ return(1);
+ }
+
+ if (segno >= MAPDEF.seg_cnt)
+ goto lbNoSeg;
+
+ seg_ptr = (WORD)MAPDEF.seg_ptr;
+ fseek(pfSym, (long)-sizeof(MAPEND), 2);
+ fread(&MAPEND, 1, sizeof(MAPEND), pfSym);
+ if (MAPEND.ver != 3)
+ {
+
+lbNoSeg:
+ pch = htoa(pch, segno);
+ *pch = 0;
+ if (offset != 0xFFFF)
+ {
+ *pch++ = '\t';
+ pch = htoa(pch, offset);
+ *pch = 0;
+ }
+ fclose(pfSym);
+ return(-2);
+ }
+ i = segno+1;
+ while (i--)
+ {
+ if (MAPEND.rel >= 10)
+ fseek(pfSym, (long)(seg_ptr * 16), 0);
+ else
+ fseek(pfSym, (long)seg_ptr, 0);
+ fread(&SEGDEF, 1, sizeof(SEGDEF), pfSym);
+ seg_ptr = (WORD)SEGDEF.nxt_seg;
+ }
+ fread(pch, 1, (int)((BYTE)SEGDEF.nam_len), pfSym);
+
+ pch += SEGDEF.nam_len;
+ *pch = 0;
+ if (offset == 0xFFFF)
+ {
+ fclose(pfSym);
+ return(1);
+ }
+ *pch++ = '\t';
+
+ i = (WORD)SEGDEF.sym_cnt;
+ if (i == 0)
+ goto lbNoSym;
+ symPos1 = 0;
+ while (i--)
+ {
+ symPos2 = symPos1;
+ symPos1 = ftell(pfSym);
+ fread(&SYMDEF, 1, sizeof(SYMDEF), pfSym);
+ if (i == 0 || (WORD)SYMDEF.sym_val > offset)
+ {
+ if ((WORD)SYMDEF.sym_val > offset)
+ {
+ if (symPos2 == 0)
+ goto lbNoSym;
+ fseek(pfSym, (long)symPos2, 0);
+ fread(&SYMDEF, 1, sizeof(SYMDEF), pfSym);
+ }
+ fread(pch, 1, (int)((BYTE)SYMDEF.nam_len), pfSym);
+ pch += SYMDEF.nam_len;
+ if ((WORD)SYMDEF.sym_val < offset)
+ {
+ *pch++ = '+';
+ pch = htoa(pch, offset - SYMDEF.sym_val);
+ }
+ *pch = 0;
+ fclose(pfSym);
+ return(1);
+ }
+ fseek(pfSym, (long)((BYTE)SYMDEF.nam_len), 1);
+ }
+lbNoSym:
+ pch = htoa(pch, offset);
+ *pch = 0;
+ fclose(pfSym);
+ return(0);
+}
+
+BYTE *htoa( s, w ) /* Hexadecimal to ASCII */
+register BYTE *s;
+WORD w;
+{
+ register int i;
+ char c;
+
+ i = 4;
+ s += i;
+ while (i--)
+ {
+ c = (char)(w & (WORD)0xF);
+ w >>= 4;
+ if (c > 9)
+ c += 'A' - 10;
+ else
+ c += '0';
+ *--s = c;
+ }
+
+ return s+4;
+}
diff --git a/private/mvdm/wow16/kernel31/swappro/swap.doc b/private/mvdm/wow16/kernel31/swappro/swap.doc
new file mode 100644
index 000000000..dbfc5b70e
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/swappro/swap.doc
Binary files differ
diff --git a/private/mvdm/wow16/kernel31/task.asm b/private/mvdm/wow16/kernel31/task.asm
new file mode 100644
index 000000000..6f460b529
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/task.asm
@@ -0,0 +1,1954 @@
+ page ,132
+ title TASK - task create/destroy procedures
+.xlist
+include kernel.inc
+include tdb.inc
+include pdb.inc
+include eems.inc
+include newexe.inc
+include dbgsvc.inc
+include bop.inc
+.list
+
+outd macro msg,n
+%out msg n
+endm
+if2
+; outd <TDBsize =>,%TDBsize
+endif
+
+externW pStackBot
+externW pStackMin
+externW pStackTop
+
+if ROM
+externFP FarIsROMObject
+endif
+
+externFP SafeCall
+externFP BuildPDB
+externFP LockSegment
+externFP UnlockSegment
+;externFP Yield
+externFP LocalInit
+externFP GlobalAlloc
+externFP GlobalFree
+;externFP GlobalLock
+externFP GlobalUnLock
+externFP GlobalCompact
+externFP IGlobalHandle
+externFP GlobalLRUOldest
+externFP AllocDStoCSAlias
+;;;externFP FarMyLock
+externFP FarSetOwner
+externFP default_sig_handler
+externFP CVW_Hack
+externFP GlobalDOSAlloc
+externFP GlobalDOSFree
+externFP AllocSelector
+externFP LongPtrAdd
+externFP MyFarDebugCall
+externFP Int21Handler
+if PMODE32
+externFP far_get_arena_pointer32
+externFP FarAssociateSelector32
+externFP KRebootInit
+else
+externFP far_get_arena_pointer
+externFP FarAssociateSelector
+endif
+
+if KDEBUG
+externFP SetupAllocBreak
+endif
+
+ifdef WOW
+externFP WowReserveHtask
+externFP FreeSelector
+endif
+
+DataBegin
+
+;externB fEMM
+externB fBooting
+externB kernel_flags
+externB num_tasks
+;externW hexehead
+externW pGlobalHeap
+externW curTDB
+externW loadTDB
+externW headTDB
+externW headPDB
+externW topPDB
+externW cur_DOS_PDB
+;if PMODE32
+;externW ArenaSel
+;endif
+externW MyCSAlias
+externD pUserInitDone
+externD ptrace_app_entry
+externD ptrace_DLL_entry
+externD pSignalProc
+
+if KDEBUG
+globalW allocTask,0
+globalD allocCount,0
+globalD allocBreak,0
+globalB allocModName,0,8
+endif ;KDEBUG
+
+if ROM
+externD prevInt00proc
+endif
+
+ifdef WOW
+externD FastBop
+externW DebugWOW
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+ife ROM
+externD prevInt00proc
+endif
+
+externNP SaveState
+externNP UnlinkObject
+externNP genter
+externNP gleave
+
+nullcomline DB 0,0Dh
+
+;-----------------------------------------------------------------------;
+; GetCurrentTask ;
+; ;
+; Returns the current task. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AX = curTDB ;
+; DX = headTDB ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Feb 01, 1987 07:45:40p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetCurrentTask,<PUBLIC,FAR>
+cBegin nogen
+ push es
+ SetKernelDS ES
+ mov ax,curTDB
+ mov dx,headTDB
+; mov bx,codeOffset headTDB
+; mov cx,codeOffset curTDB
+ pop es
+ ret
+ assumes es,nothing
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; InsertTask ;
+; ;
+; Inserts a task into the task list. ;
+; ;
+; Arguments: ;
+; parmW hTask ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,ES ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Feb 01, 1987 09:41:24p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InsertTask,<PUBLIC,NEAR>,<ds>
+ parmW hTask
+cBegin
+ mov es,hTask ; get task handle
+ SetKernelDS
+ mov ax,headTDB ; get head of task list
+ UnSetKernelDS
+ or ax,ax ; anybody here?
+ jz ins1 ; no, just do trivial case
+
+ins0: mov ds,ax ; point to head TDB
+ mov bl,es:[TDB_priority] ; get insert priority
+ cmp bl,ds:[TDB_priority] ; is it less than head task?
+ jg ins2 ; no, insert elsewhere
+ mov es:[TDB_next],ax
+ins1: SetKernelDS
+ mov headTDB,es
+ UnSetKernelDS
+ jmps ins4
+
+ins2: mov ds,ax ; save segment of previous TDB
+ mov ax,ds:[TDB_next] ; get segment of next tdb
+ or ax,ax ; if zero, insert now
+ jz ins3
+ mov es,ax ; point to new TDB
+ cmp bl,es:[TDB_priority]
+ jg ins2
+ins3: mov es,hTask
+ mov ds:[TDB_next],es
+ mov es:[TDB_next],ax
+ins4:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; DeleteTask ;
+; ;
+; Deletes a task from the task list. ;
+; ;
+; Arguments: ;
+; parmW hTask ;
+; ;
+; Returns: ;
+; AX = hTask ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; UnlinkObject ;
+; ;
+; History: ;
+; ;
+; Sun Feb 01, 1987 09:41:24p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DeleteTask,<PUBLIC,NEAR>
+ parmW hTask
+cBegin
+ mov es,hTask
+ mov bx,dataOffset headTDB
+ mov dx,TDB_next
+ call UnlinkObject ; returns AX = hTask
+cEnd
+
+
+cProc FarCreateTask,<PUBLIC,FAR> ; Called from CreateTask
+; parmW fPrev ; Calls several 'near' CODE funcs
+cBegin
+ cCall SaveState,<ds>
+ SetKernelDS es
+ mov loadTDB,ds
+ cCall InsertTask,<ds>
+ clc
+cEnd
+
+if KDEBUG
+
+;-----------------------------------------------------------------------
+;
+; CheckGAllocBreak
+;
+; Checks to see if the allocation break count has been reached.
+; Returns CARRY SET if the allocation should fail, CLEAR otherwise.
+; Increments the allocation count.
+;
+;-----------------------------------------------------------------------
+
+LabelNP <PUBLIC, CheckGAllocBreak>
+ errn$ CheckLAllocBreak
+
+cProc CheckLAllocBreak,<PUBLIC,NEAR>,<DS,AX>
+cBegin
+ SetKernelDS
+assumes ds,DATA
+
+ mov ax,allocTask ; if allocTask != curTDB, exit.
+ or ax,ax ; curTDB may be NULL during boot.
+ jz cab_nofail
+ cmp ax,curTDB
+ jnz cab_nofail
+
+ mov ax,word ptr allocBreak
+ cmp ax,word ptr allocCount ; if allocBreak != allocCount
+ jnz cab_increment ; inc allocCount
+ mov ax,word ptr allocBreak+2
+ cmp ax,word ptr allocCount+2
+ jnz cab_increment
+
+ or ax,word ptr allocBreak ; if allocBreak is 0L, just inc.
+ jz cab_increment
+
+ krDebugOut <DEB_ERROR>, "Alloc break: Failing allocation"
+
+ stc ; return carry set
+ jmp short cab_exit
+
+cab_increment:
+ inc word ptr allocCount ; increment allocCount
+ jnz cab_nofail
+ inc word ptr allocCount+2
+cab_nofail:
+ clc
+cab_exit:
+assumes ds,NOTHING
+cEnd
+
+endif ;KDEBUG
+
+sEnd CODE
+
+externFP CalcMaxNRSeg
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MapDStoDATA
+externNP GetInstance
+externNP StartProcAddress
+externNP SetAppCompatFlags
+
+;-----------------------------------------------------------------------;
+; CreateTask ;
+; ;
+; "Creates" a new task. It allocates the memory for the TDB+PDB struc, ;
+; builds the PDB, constructs the TDB, initializes the EEMS memory ;
+; arena, and sets the signature word in the TDB. TDB actually added ;
+; to task queue by StartTask. ;
+; ;
+; Arguments: ;
+; parmD pParmBlk ;
+; parmW pExe ;
+; parmW hPrev instance ;
+; parmW fWOA ;
+; ;
+; Returns: ;
+; AX = segment of TDB ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu 04-Jan-1990 21:18:25 -by- David N. Weise [davidw] ;
+; Added support for OS/2 apps. ;
+; ;
+; Mon 07-Aug-1989 23:28:15 -by- David N. Weise [davidw] ;
+; Added support for long command lines to winoldap. ;
+; ;
+; Thu Apr 09, 1987 03:53:16p -by- David N. Weise [davidw] ;
+; Added the initialization for EMS a while ago, recently added the ;
+; switching of stacks to do it. ;
+; ;
+; Sun Feb 01, 1987 07:46:53p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CreateTask,<PUBLIC,FAR>,<si,di>
+ parmD pParmBlk
+ parmW pExe
+; parmW fPrev
+ parmW fWOA
+
+ localW env_seg
+ localW comline_start
+cBegin
+ call MapDStoDATA
+ ReSetKernelDS
+ cld
+ xor si,si
+ mov env_seg,si
+ mov comline_start,si
+ cmp si,pParmBlk.sel
+ jz parm_block_considered
+ cCall pass_environment,<pExe,pParmBlk>
+ inc ax
+ jnz @F
+ jmp ats6
+@@: dec ax
+ mov env_seg,ax
+ mov comline_start,dx
+ mov si,size PDB ; start with size of PDB
+ cmp fWOA,0
+ jz parm_block_considered
+ les di,pParmBlk
+ les di,es:[di].lpcmdline
+ mov cx,es:[di]
+ sub cx,127 ; account for terminating 0Dh
+ jbe parm_block_considered
+ add si,cx
+ add si,15
+ and si,NOT 15
+parm_block_considered:
+ add si,TDBsize+15 ; Room for task data and paragraph aligned.
+; xor ax,ax ; Room for EMM save area if needed.
+; mov al,fEMM
+; add si,ax
+ and si,0FFF0h
+ mov di,si
+ mov cl,4
+ shr si,cl
+ifdef WOW
+; We need to ensure task handles are unique across multiple WOW VDMs
+; on Windows NT, so that for example the undocumented feature of
+; passing a 16-bit htask to Win32 Post(App|Thread)Message instead
+; of a thread ID will work reliably with multiple WOW VDMs.
+;
+; To accomplish this we call WowReserveHtask, which will return
+; the htask if the htask (ptdb) was previously unused and has
+; been reserved for us. If it returns 0 another VDM is already
+; using that value and so we need to allocate another and try again.
+; To avoid risking exhausting low memory, we allocate memory for the
+; TDB once using GlobalDOSAlloc, then clone it using AllocSelector.
+; We test this cloned selector value using WowReserveHtask, if it
+; fails we get another clone until one works. Then we free all but
+; the clone we'll return, and magically swap things around so that
+; the cloned selector owns the TDB memory and then free the original
+; selector from GlobalDOSAlloc
+;
+
+ xor dx,dx ; Make size of allocation a dword
+ regptr xsize,dx,di
+ cCall GlobalDOSAlloc,<xsize>
+ or ax,ax
+ jnz @f
+ jmp ats6 ; Return zero for failure.
+
+@@: push di ; save TDB size on stack
+ push ax ; save GlobalDOSAlloc selector on stack
+ mov di,ax ; and in DI
+ cCall WowReserveHtask,<ax> ; returns htask or 0
+ or ax,ax ; Is this selector value avail as htask?
+ jz MustClone ; no, start cloning loop
+ pop ax ; htask to return
+ pop di ; TDB size
+ jmps NoClone
+MustClone:
+ xor cx,cx ; count of clone selectors
+ xor si,si ; no selector to return yet
+AnotherHtask:
+ push cx
+ cCall AllocSelector,<di> ; clone the selector
+ pop cx
+ or ax,ax
+ jz FreeAnyHtasks ; Out of selectors cleanup and exit
+ push ax ; save cloned selector on stack
+ inc cx
+ push cx
+ cCall WowReserveHtask,<ax> ; returns htask or 0
+ pop cx
+ or ax,ax
+ jz AnotherHtask ; conflict
+ mov si,ax ; SI = selector to return
+ pop bx ; pop the selector we're returning
+ dec cx
+ jcxz @f
+FreeLoop:
+ pop bx ; pop an allocated selector from stack
+ push cx
+ cCall FreeSelector,<bx>
+ pop cx
+ dec cx
+FreeAnyHtasks:
+ jcxz @f ; have we popped all the allocated selectors? Yes
+ jmps FreeLoop ; No
+
+@@: mov ax,si
+ or si,si
+ jnz @f
+ pop ax ; original selector from GlobalDOSAlloc
+ cCall GlobalDOSFree,<ax>
+ pop di
+ jmp ats6
+
+@@:
+ ; SI is selector to return, top of stack is original GlobalDOSAlloc
+ ; selector. We need to free the original selector and make the clone
+ ; selector "own" the memory so it will be freed properly by GlobalDOSFree
+ ; during task cleanup.
+
+ pop di ; DI = original GlobalDOSAlloc selector
+ push ds
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+ .386
+ cCall far_get_arena_pointer32,<di>
+ push eax
+ cCall FarAssociateSelector32,<di,0,0>
+ pop eax
+ mov ds:[eax].pga_handle, si
+ cCall FarAssociateSelector32,<si,eax>
+ .286p
+ pop ds
+ ReSetKernelDS
+ cCall FreeSelector,<di>
+ mov ax,si ; AX is the final TDB selector/handle.
+ pop di ; TDB size
+NoClone:
+
+else
+ xor dx,dx ; Make size of allocation a dword
+ regptr xsize,dx,di
+ cCall GlobalDOSAlloc,<xsize>
+ or ax,ax
+ jnz @f
+ jmp ats6 ; Return zero for failure.
+@@:
+endif
+ mov es, ax
+ xor ax, ax ; zero allocated block
+ mov cx, di
+ shr cx, 1
+ xor di, di
+ rep stosw
+
+ mov ax, es
+
+ats2a:
+ cCall FarSetOwner,<ax,ax> ; Set TDB owner to be itself
+ cmp fWOA,0 ; Is this WinOldApp?
+ mov ds,ax
+ UnSetKernelDS
+ jz no_it_isnt
+ or ds:[TDB_flags],TDBF_WINOLDAP
+no_it_isnt:
+
+; Initialize the task stack.
+
+ mov si,1 ; 1 for show means open window
+ les di,pParmBlk
+ mov ax,es
+ or ax,di
+ jnz @F
+ jmp ats4 ; AX = DI = 0 if no parmblock
+
+@@: xor ax,ax ; Skip past EMM save area and
+ push ds
+ xor dx, dx
+ push es
+ mov es,pExe
+ mov dx,es:[ne_flags]
+ pop es
+ test dx,NEPROT
+ jz @F
+ or ds:[TDB_flags],TDBF_OS2APP
+ or ds:[TDB_ErrMode],08000h ; don't prompt for .DLL's
+@@:
+ call MapDStoDATA
+ ReSetKernelDS
+ test dx,NEPROT ; OS/2 app?
+ mov dx,TopPDB ; DX has segment of parent PDB
+ jz use_kernel_TDB
+; %OUT This should probably be Win_PDB
+ mov dx,cur_DOS_PDB ; inherit parent's stuff
+use_kernel_TDB:
+ pop ds
+ UnSetKernelDS
+
+ push dx ; yes, get address of PDB
+ push es
+ mov si,(TDBsize+15) and not 15 ; Round up TDB size
+
+ cCall AllocSelector,<ds> ; Get us an alias selector
+ or ax, ax ; did we get it?
+ jnz ats_gotsel
+ mov bx, ds ; No, tidy up
+ mov ds, ax ; We will current ds, so zero it
+ cCall GlobalDOSFree,<bx> ; Free the memory
+ pop es
+ pop dx
+ xor ax, ax
+ jmp ats6
+
+ats_gotsel:
+ xor dx, dx
+ cCall LongPtrAdd,<ax,dx,dx,si>
+ mov si, dx ; SI = selector of new PDB
+ pop es
+ pop dx
+ regptr esbx,es,bx ; es:bx points at parm block
+ mov bx,di
+ mov cx,256 ; just include enough room for PDB
+ cCall BuildPDB,<dx,si,esbx,cx,fWOA>; go build it
+ mov ax,si ; link on another PDB
+ push ds
+ call MapDStoDATA
+ ReSetKernelDS
+ xchg HeadPDB,ax
+ mov es,si
+ mov es:[PDB_Chain],ax
+
+ les di,pParmBlk
+ push si
+ lds si,es:[di].lpfcb1
+ UnSetKernelDS
+ mov di,PDB_5C_FCB
+ pop es
+ mov cx,ds
+ or cx,si
+ jz ats3b
+ mov cx,ds:[si]
+ inc cx
+ inc cx
+ cmp cx,24h
+ jbe ats3a
+ mov cx,24h
+ats3a: rep movsb
+ats3b: mov si,es
+ pop ds
+
+ mov ax,env_seg
+ or ax,ax
+ jz no_new_env
+ mov es:[PDB_environ],ax
+no_new_env:
+
+ats4: mov es,pExe
+ mov ds:[TDB_pModule],es ; Do this before InitTaskEMS
+
+ mov ax,comline_start ;!!! just for now os2
+ mov ds:[TDB_Validity],ax
+
+ push si
+ push ds
+ push ds
+ push es
+ pop ds
+ pop es
+
+ mov di,TDB_ModName
+ mov si,ds:[ne_restab]
+ lodsb ; get no of bytes in name
+ cbw
+ cmp ax,8
+ jbe @F
+ mov ax, ds
+ krDebugOut <DEB_WARN or DEB_krLoadMod>, "Module Name %AX0 (%AX1) too long"
+ mov ax,8
+@@: mov cx,ax
+ cld
+ rep movsb
+
+; initialize the interrupt vectors
+
+ mov di,TDB_INTVECS
+ call MapDStoDATA
+ ReSetKernelDS
+ife ROM
+ mov ds,MyCSAlias
+ assumes ds,CODE
+ mov si,codeOffset prevInt00proc
+else
+ mov si,dataOffset prevInt00proc
+endif
+ mov cx,(4 * numTaskInts)/2
+ rep movsw
+ assumes ds,nothing
+ pop ds
+ pop si
+
+ cCall FarCreateTask ;,<fPrev>
+ jnc @F
+ jmp ats6
+@@:
+ push ds
+ call MapDStoDATA
+ ReSetKernelDS
+ mov es,curTDB ; inherit the parents
+ pop ds
+ UnSetKernelDS
+
+ mov ds:[TDB_PDB],si ; save new PDB
+ or si,si ; do we have a new PDB?
+ jnz @F ; zero means no
+ mov si,es:[TDB_PDB]
+ mov ds:[TDB_PDB],si
+@@: mov ds:[TDB_Parent],es
+;
+; Inherit parent's wow compatibiltiy flags
+; Special code is required in wkman.c to exploit this
+ mov ax,es:[TDB_WOWCompatFlags]
+ mov ds:[TDB_WOWCompatFlags],ax
+ mov ax,es:[TDB_WOWCompatFlags2]
+ mov ds:[TDB_WOWCompatFlags2],ax
+ mov ax,es:[TDB_WOWCompatFlagsEx]
+ mov ds:[TDB_WOWCompatFlagsEx],ax
+ mov ax,es:[TDB_WOWCompatFlagsEx2]
+ mov ds:[TDB_WOWCompatFlagsEx2],ax
+
+ mov ds:[TDB_thread_tdb],ds
+ mov ds:[TDB_DTA].off,80h ; set initial DTA
+ mov ds:[TDB_DTA].sel,si
+ mov ds:[TDB_sig],TDB_SIGNATURE ; Set signature word.
+
+ mov ax,SEG default_sig_handler
+ mov ds:[TDB_ASignalProc].sel,ax
+ mov ax,codeOffset default_sig_handler
+ mov ds:[TDB_ASignalProc].off,ax
+
+; Initialize the MakeProcInstance Thunks.
+
+ cCall AllocDStoCSAlias,<ds>
+ mov ds:[TDB_MPI_Sel],ax
+ mov ds:[TDB_MPI_Thunks],0
+ mov ds:[TDB_MPI_Thunks].2,MPIT_SIGNATURE
+ mov bx,TDB_MPI_Thunks + THUNKSIZE-2
+ mov cx,THUNKELEM-1
+ mov dx,bx
+mp1: add dx,THUNKSIZE
+ .errnz THUNKELEM and 0FF00h
+ mov ds:[bx],dx
+ mov bx,dx
+ loop mp1
+ mov ds:[bx],cx
+
+ mov si, ds
+ mov di, ax
+ call MapDStoDATA
+ ReSetKernelDS
+ mov ds, pGlobalHeap
+ UnSetKernelDS
+if PMODE32
+ .386
+ cCall far_get_arena_pointer32,<si>
+ cCall FarAssociateSelector32,<di, eax>
+ .286p
+else
+ cCall far_get_arena_pointer,<si>
+ cCall FarAssociateSelector,<di, ax>
+endif
+ mov ax, si
+ mov ds, si
+ats6:
+cEnd
+
+;-----------------------------------------------------------------------;
+; pass_environment
+;
+;
+; Entry:
+;
+; Returns:
+; AX = seg of new env if any
+; DX = start of comline
+;
+; Error Return:
+; AX = -1
+;
+; Registers Destroyed:
+;
+; History:
+; Wed 27-Dec-1989 23:36:25 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc pass_environment,<PUBLIC,NEAR>,<di,si,ds>
+
+ parmW pExe
+ parmD pParmBlk
+
+ localW myEnv
+cBegin
+
+ ReSetKernelDS
+
+ cld
+ cmp fBooting,1
+ jnz @F
+ xor ax,ax
+ jmp pe_exit
+@@:
+ mov es,curTDB
+ mov bl,es:[TDB_flags]
+
+; THIS IS JUST A TEST TO SEE IF IT FIXES THE PROBLEM WITH APPS NOT GETTING
+; ARGV[0] IN THE RIGHT MANNER. SEE ME IF YOU HAVE ANY PROBLEMS WITH THIS
+; CODE PATH -BOBDAY
+;
+; mov es,pExe
+; test es:[ne_flags],NEPROT
+; jnz @F
+; jmp just_copy
+@@:
+
+; massage environment
+
+ les di,pParmBlk
+ mov ax,es:[di].envseg
+ or ax,ax
+ jnz pe_given_env
+; %OUT This should probably be Win_PDB
+ mov ds,cur_DOS_PDB
+ UnsetKernelDS
+ mov ax,ds:[PDB_environ]
+
+pe_given_env:
+ mov myEnv,ax
+ mov es,ax ; ES => environment
+ xor ax,ax
+ mov cx,-1
+ xor di,di
+@@: repnz scasb
+ cmp es:[di],al
+ jnz @B
+ neg cx
+; dec cx ; include space for extra 0
+ push cx ; length of environment
+ mov dx,cx
+
+; MORE TEST CODE TO SEE IF IT FIXES THE PROBLEM.
+ mov es,pExe
+ test es:[ne_flags],NEPROT
+ jnz @f
+
+ mov cx,3 ; Save room for magic word and nul
+ add dx,cx
+ push 8000h ; No command line after the env.
+
+ jmps pe_got_com_len
+
+@@:
+ les di,pParmBlk
+ test bl,TDBF_OS2APP ; execer an OS/2 app?
+ jz pe_execer_dos_app
+ les di,es:[di].lpCmdLine
+ mov cx,-1
+ repnz scasb
+ repnz scasb ; get both strings
+ neg cx
+ add dx,cx
+ dec cx ; length of command line
+ or ch,80h ; mark special
+ push cx
+ jmps pe_got_com_len
+
+pe_execer_dos_app:
+ inc es:[di].lpCmdLine.off
+ les di,es:[di].lpCmdLine
+ xor cx,cx
+ mov cl,es:[di][-1] ; length of command line
+ add dx,cx
+ inc dx ; We add a '\0' when we move it anyway
+ push cx
+
+pe_got_com_len:
+ mov es,pExe
+ mov di,es:[ne_pfileinfo]
+ lea di,[di].opfile
+ mov cx,-1
+ repnz scasb
+ neg cx
+ dec cx
+ push cx ; length of file name
+ shl cx,1 ; for program pointer and arg 1
+ add dx,cx
+
+ cCall GlobalAlloc,<ax,ax,dx>
+ or ax,ax
+ jz @f
+ push ax
+ cCall FarSetOwner,<ax,pExe> ; Make this new guy the owner
+ pop ax
+@@:
+ mov es,ax
+ pop dx ; length of filename
+ pop bx ; length of command line
+ pop cx ; length of environment
+ or ax,ax
+ jz pe_error_exit2
+
+ mov ds,myEnv
+ xor di,di
+ xor si,si
+ rep movsb
+
+ mov ds,pExe
+
+; MORE TEST CODE TO SEE IF IT FIXED THE PROBLEM
+
+ test ds:[ne_flags],NEPROT
+ jnz @f
+
+ mov ax,1
+ stosw
+
+@@:
+ mov si,ds:[ne_pfileinfo]
+ lea si,[si].opfile
+ mov cx,dx ; length of filename
+ rep movsb
+ mov ax,di ; save position of comline start
+
+ test bh,80h ; if OS/2 execer comline is correct
+ jnz @F
+ mov si,ds:[ne_pfileinfo]
+ lea si,[si].opfile
+ mov cx,dx ; length of filename
+ rep movsb
+
+@@: and bh,NOT 80h
+ lds si,pParmBlk
+ lds si,ds:[si].lpCmdLine
+ mov cx,bx
+ rep movsb
+ mov byte ptr es:[di],0 ; zero terminate
+ mov dx,ax ; comline start
+ mov ax,es
+ jmps pe_exit
+
+pe_error_exit2:
+ jmps pe_error_exit
+
+just_copy:
+ les di,pParmBlk
+ mov ax,es:[di].envseg
+ or ax,ax
+ jz pe_exit
+ mov cx,-1
+ mov es, ax ; fix #7771 donc
+ xor ax,ax
+ xor di,di
+ push di
+ push es
+@@: repnz scasb
+ cmp es:[di],al
+ jnz @B
+ neg cx
+; dec cx ; include space for extra 0
+ push cx
+ cCall GlobalAlloc,<ax,ax,cx>
+ pop cx
+ pop ds
+ pop si
+ or ax,ax
+ jz pe_error_exit
+ mov es,ax
+ xor di,di
+ cld
+ rep movsb
+ jmps pe_exit
+
+pe_error_exit:
+ mov ax,-1
+
+pe_exit:
+
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; StartLibrary ;
+; ;
+; Initialize library registers. ;
+; ;
+; Arguments: ;
+; parmW hExe ;
+; parmD lpParms ;
+; parmD startAddr ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; AX = 0 ;
+; DS = data segment ;
+; ;
+; Registers Preserved: ;
+; DI,SI ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; GetInstance ;
+; FarMyLock ;
+; ;
+; History: ;
+; ;
+; Thu 04-Jan-1990 22:48:25 -by- David N. Weise [davidw] ;
+; Added support for OS/2 apps. ;
+; ;
+; Sat Apr 18, 1987 08:54:50p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc StartLibrary,<PUBLIC,NEAR>,<ds,si,di>
+ parmW hExe
+ parmD lpParms
+ parmD startAddr
+ localW hStartSeg
+cBegin
+ cCall MapDStoDATA
+ ReSetKernelDS
+ cmp loadTDB,0
+ je notloading
+ test kernel_flags,KF_pUID ; All done booting?
+ jz notloading
+ mov es,loadTDB
+ test es:[TDB_Flags],TDBF_OS2APP
+ jnz notloading
+ mov ax,hExe
+ mov es,es:[TDB_LibInitSeg]
+ mov bx,es:[pStackTop]
+ xchg es:[bx-2],ax
+ mov es:[bx],ax
+ add es:[pStackTop],2
+ mov ax,hExe
+ jmp slxx
+
+notloading:
+ mov si,hExe
+ mov es,si
+ test es:[ne_flags],NEPROT
+ jnz no_user_yet
+ cmp pSignalProc.sel,0
+ jz no_user_yet
+ xor ax,ax
+ mov bx,40h
+ cCall pSignalProc,<hExe,bx,ax,ax,ax> ; SignalProc(hModule,40h,wParam,lParam)
+no_user_yet:
+ cCall GetInstance,<si>
+ mov di,ax
+if ROM
+ cCall FarIsROMObject, <SEG_startAddr>
+ or ax, ax
+ jz not_rom_code_segment
+ mov hStartSeg, 0
+ jmp sl_got_handle
+not_rom_code_segment:
+endif
+ cCall IGlobalHandle,<SEG_startAddr>
+ xchg startAddr.sel,dx
+ mov hStartSeg,ax
+
+if ROM
+sl_got_handle:
+endif
+
+ ;** Send the SDM_LOADDLL notification
+ mov bx,startAddr.off
+ mov cx,startAddr.sel
+ mov ax,SDM_LOADDLL
+ cCall MyFarDebugCall
+
+ cmp SEG_startAddr, 0
+ jnz HaveStart
+ mov ax, di
+ jmps slxx
+HaveStart:
+ cCall IGlobalHandle,<di>
+ mov ds,si
+ UnSetKernelDS
+ mov cx,ds:[ne_heap]
+ mov ds,dx
+ les si,lpParms
+ mov ax,es
+ or ax,ax
+ jz dont_fault
+ les si,es:[si].lpcmdline
+dont_fault:
+ mov ax,1 ; An Arts & Letters lib init doesn't
+ push di ; touch AX!!
+ifdef WOW
+ push cs
+ push offset RetAddr
+ pushf
+ push startAddr.sel
+ push startAddr.off
+
+ push ax
+
+ push ds
+
+ push ax
+ mov ax,hExe
+ mov ds,ax
+ pop ax
+
+ push 0 ; hTask (meaningless for a DLL)
+
+ push ds ; hModule
+
+ push ds ; Pointer to module name
+ push ds:ne_restab
+ push ds ; Pointer to module path
+ push word ptr ds:ne_crc+2
+
+ cCall MapDStoDATA
+ ReSetKernelDS ds
+ push DBG_DLLSTART
+
+ test DebugWOW,DW_DEBUG
+ jz skip_bop
+
+ FBOP BOP_DEBUGGER,,FastBop
+.286p
+
+skip_bop:
+ add sp,+14
+
+ pop ds
+ UnSetKernelDS ds
+ pop ax
+ iret
+
+RetAddr equ $
+
+else
+ cCall SafeCall,<startAddr>
+endif
+ pop di ; USER.EXE didn't save DI, maybe others
+ or ax,ax
+ jz slx
+ mov ax,di
+slx:
+ push ax
+if ROM
+ cmp hStartSeg, 0
+ jz @F
+ cCall GlobalLRUOldest,<hStartSeg>
+@@:
+endif
+ pop ax
+slxx:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; StartTask ;
+; ;
+; Sets up the standard register values for a Windows task. ;
+; ;
+; Arguments: ;
+; HANDLE hPrev = a previous instance ;
+; HANDLE hExe = the EXE header ;
+; FARP stackAddr = the normal task stack address (initial SS:SP) ;
+; FARP startAddr = the normal task start address (initial CS:IP) ;
+; ;
+; Returns: ;
+; AX = HANDLE ;
+; ;
+; Error Returns: ;
+; AX = NULL ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; GetInstance ;
+; FarMyLock ;
+; ;
+; History: ;
+; ;
+; Tue Apr 21, 1987 06:41:05p -by- David N. Weise [davidw] ;
+; Added the EMS initialization of the entry tables in page 0. ;
+; ;
+; Thu Dec 11, 1986 11:38:53a -by- David N. Weise [dnw] ;
+; Removed the superfluous call to calculate the largesr NR seg. ;
+; ;
+; Fri Sep 19, 1986 12:08:23p -by- Charles Whitmer [cxw] ;
+; Made it return 0000 on error rather than terminate. ;
+; ;
+; Thu Sep 18, 1986 02:33:39p -by- Charles Whitmer [cxw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc StartTask,<PUBLIC,NEAR>,<si,di>
+ parmW hPrev
+ parmW hExe
+ parmD stackAddr
+ parmD startAddr
+cBegin
+ cCall MapDStoDATA
+ ReSetKernelDS
+ xor di,di
+ cmp loadTDB,di
+ jnz st1
+ jmp stx
+
+stfail0:
+ xor ax,ax
+ pop ds
+ jmp stfail
+
+st1: push ds
+ cmp stackAddr.sel,di
+ jz stfail0
+
+ cmp startAddr.sel,di
+ jz stfail0
+
+ mov ds,loadTDB
+ UnSetKernelDS
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jnz stfail0
+
+; Get new task stack
+
+ cCall IGlobalHandle,<SEG_stackAddr>
+ mov ds:[TDB_taskSS],dx
+ mov ax,stackAddr.off
+ sub ax,(SIZE TASK_REGS)
+ mov ds:[TDB_taskSP],ax
+
+; get my instance
+
+ cCall GetInstance,<hExe>
+ mov di,ax
+ mov ds:[TDB_Module],ax
+
+; find my real code segment
+
+ cCall IGlobalHandle,<SEG_startAddr>
+ or dx,dx
+ jz stfail0
+ mov startAddr.sel,dx
+
+; find my real data segment
+
+ cCall IGlobalHandle,<di> ; DI = handle of DGROUP
+ mov si,dx ; SI = address of DGROUP
+
+if KDEBUG
+
+; Set up the allocBreak globals if needed
+
+ cCall SetupAllocBreak,<ds>
+
+endif ;KDEBUG
+
+; copy junk from hExe -> TDB
+
+ mov es,hExe
+ mov cx,es:[ne_expver]
+ mov ds:[TDB_ExpWinVer],cx
+ mov cx,es:[ne_stack] ; CX = STACKSIZE
+ mov dx,es:[ne_heap] ; DX = HEAPSIZE
+
+
+
+; set up the task registers
+
+ test es:[ne_flags],NEPROT
+ jnz st_OS2_binary
+
+ les bx,dword ptr ds:[TDB_TaskSP]
+ mov es:[bx].TASK_AX,0 ; Task AX = NULL
+ mov ax,ds:[TDB_PDB]
+ mov es:[bx].TASK_ES,ax ; Task ES = PDB
+ mov es:[bx].TASK_DI,di ; Task DI = hInstance or hExe
+ mov es:[bx].TASK_DS,si ; Task DS = data segment
+ mov ax,hPrev
+ mov es:[bx].TASK_SI,ax ; Task SI = previous instance
+ mov es:[bx].TASK_BX,cx ; Task BX = STACKSIZE
+ mov es:[bx].TASK_CX,dx ; Task CX = HEAPSIZE
+ mov es:[bx].TASK_BP,1 ; Task BP = 1 (far frame)
+ jmps st_regs_set
+
+st_OS2_binary:
+ push di
+ mov es,ds:[TDB_PDB]
+ mov di,es:[PDB_environ]
+ les bx,dword ptr ds:[TDB_TaskSP]
+ mov es:[bx].TASK_AX,di ; Task AX = environment
+ mov es:[bx].TASK_DX,cx ; Task DX = STACKSIZE
+ lsl cx,si
+ inc cx
+ mov es:[bx].TASK_CX,cx ; Task CX = Length of data segment
+ mov ax,ds:[TDB_pModule]
+ mov es:[bx].TASK_DI,ax ; Task DI = hExe
+ mov es:[bx].TASK_SI,dx ; Task SI = HEAPSIZE
+ mov es:[bx].TASK_DS,si ; Task DS = data segment
+ mov es:[bx].TASK_ES,0 ; Task ES = 0
+ mov es:[bx].TASK_BP,1 ; Task BP = 1 (far frame)
+ xor ax,ax
+ xchg ax,ds:[TDB_Validity]
+ mov es:[bx].TASK_BX,ax ; Task BX = offset in env of comline
+ pop di
+
+st_regs_set:
+
+ pop ds
+ push ds
+ ReSetKernelDS
+
+ test Kernel_Flags[2],KF2_PTRACE ;TOOLHELP.DLL and/or WINDEBUG.DLL?
+ jz st_NoPTrace
+
+ mov ax,startAddr.sel
+ mov ptrace_app_entry.sel,ax
+ mov ax,startAddr.off
+ mov ptrace_app_entry.off,ax
+
+ mov ax,SEG CVW_HACK
+ mov ds,ax
+ UnSetKernelDS
+ mov ax,codeOffset CVW_Hack
+ jmps st_PTraceHere
+
+st_NoPTrace:
+ lds ax,startAddr ; Task CS:IP = start address
+ UnSetKernelDS
+st_PTraceHere:
+ mov es:[bx].TASK_CS,ds
+ mov es:[bx].TASK_IP,ax
+ pop ds
+ ReSetKernelDS
+
+stx: mov ax,di
+stfail:
+cEnd
+
+;-----------------------------------------------------------------------;
+; InitTask ;
+; ;
+; This should be the first thing called by app when first started. ;
+; It massages the registers, massages the command line and inits ;
+; the heap. ;
+; ;
+; Arguments: ;
+; ;
+; When a windows application starts up the registers look ;
+; like this: ;
+; ;
+; AX = 0 ;
+; BX = stack size ;
+; CX = heap size ;
+; DX = ? ;
+; DI = hInstance ;
+; SI = hPrevInstance ;
+; BP = 0 ;
+; ES = Segment of Program Segment Prefix (see page E-8) ;
+; DS = Applications DS ;
+; SS = DS ;
+; SP = stack area ;
+; ;
+; FCB1 field at PSP:5CH contains up to 24h bytes of binary data. ;
+; Windows apps get their ShowWindow parameter in the first word of ;
+; of this data. ;
+; ;
+; Returns: ;
+; AX = PSP address ;
+; CX = stack limit ;
+; DX = command show ;
+; ES:BX = command line ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; LocalInit ;
+; FarEMS_FirstTime ;
+; ;
+; History: ;
+; ;
+; Mon 11-Sep-1989 19:13:52 -by- David N. Weise [davidw] ;
+; Remove entry of AX = validity check. ;
+; ;
+; Wed Mar 16, 1988 22:45:00a -by- T.H. [ ] ;
+; Fix bug in exit path. It was not popping the saved DS from the ;
+; far call frame properly. Normally, this is not a problem (since ;
+; it does indeed save the DS register across the entire routine), ;
+; but if the RET has to go through a RetThunk, the saved DS is not ;
+; really the original DS value, but a special value needed by the ;
+; INT3F RetThunk code. This causes a crash when something in this ;
+; routine (like the call to UserInitDone) causes our calling code ;
+; segment to be discarded. ;
+; ;
+; Sat Apr 18, 1987 08:43:54p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+STACKSLOP equ 150 ; stack slop for interrupt overhead
+
+ assumes ds,nothing
+ assumes es,nothing
+
+; ES = TDB
+
+ public do_libinit
+do_libinit proc near
+ push si
+ push es
+ mov si,es:[TDB_LibInitOff]
+ mov es,cx
+libinit_loop:
+ cld
+ lods word ptr es:[si]
+ or ax,ax
+ jz libinit_done
+ push es
+ mov es,ax
+ cmp es:[ne_magic],NEMAGIC
+ jne libinit_loop1
+ mov ax,-1
+ push es
+ cCall StartProcAddress,<es,ax>
+ pop es
+;;; jcxz libinit_loop1
+ xor cx,cx
+ cCall StartLibrary,<es,cx,cx,dx,ax>
+ or ax,ax
+ jnz libinit_loop1
+ mov ax,4CF0h
+ DOSFCALL
+libinit_loop1:
+ pop es
+ jmp libinit_loop
+libinit_done:
+
+ mov si,es
+ cCall GlobalUnlock,<si>
+ cCall GlobalFree,<si>
+ pop es
+ mov es:[TDB_LibInitSeg],0
+ mov es:[TDB_LibInitOff],0
+ pop si
+ ret
+do_libinit endp
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitTask,<PUBLIC,FAR>
+cBegin nogen
+ pop ax ; Get return address
+ pop dx
+ mov ss:[pStackMin],sp ; Save bottom of stack
+ mov ss:[pStackBot],sp
+ sub bx,sp ; Compute top of stack
+ neg bx
+ add bx,STACKSLOP
+ mov ss:[pStackTop],bx ; Setup for chkstk
+
+ xor bp,bp ; Initial stack frame
+ push bp ; is not a far frame as there
+ mov bp,sp ; is no return address
+ push dx ; Push return address back on
+ push ax
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ jcxz noheap ; Initialize local heap if any
+ xor ax,ax
+ push es
+ cCall LocalInit,<ax,ax,cx>
+ pop es
+ or ax,ax
+ jnz noheap
+ push ds
+ jmp noinit
+noheap:
+ push es
+ cCall GetCurrentTask
+ mov es,ax
+ mov cx,es:[TDB_LibInitSeg]
+ jcxz no_libinit
+ call do_libinit
+no_libinit:
+ call SetAppCompatFlags
+ mov es:[TDB_CompatFlags], ax
+ mov es:[TDB_CompatFlags2], dx
+if KDEBUG
+ mov bx, ax
+ or bx, dx
+ jz @F
+ krDebugOut DEB_WARN, "Backward compatibility hack enabled: #dx#AX"
+@@:
+endif
+ pop es
+
+ push ds
+ cCall MapDStoDATA
+ ReSetKernelDS
+ test kernel_flags,KF_pUID ; All done booting?
+ jnz noboot ; Yes, continue
+ or kernel_flags,KF_pUID
+ mov fBooting,0
+ mov cx,ds
+
+ pop ds ; DS = caller's data segment
+ UnSetKernelDS
+ push es ; Save ES
+ push ax
+ push cx
+ cCall IGlobalHandle,<ds>
+ push ax
+ cCall UnlockSegment,<ds>
+ cCall CalcMaxNRSeg ; Yes, Enable code swap area
+ xor dx,dx
+ cCall GlobalCompact,<dx,dx> ; Compact memory
+ xor dx,dx
+ cCall GlobalCompact,<dx,dx> ; Once more for completeness
+ cCall IGlobalHandle ; ,<ax> from above
+ mov ds,dx
+ cCall LockSegment,<ds>
+
+ pop cx
+ push ds
+ mov ds,cx
+ ReSetKernelDS
+ cmp pUserInitDone.sel,0 ; for Iris's server
+ jz no_User_to_call
+ call pUserInitDone ; Let USER lock down stuff.
+no_USER_to_call:
+ pop ds
+ UnSetKernelDS
+ pop ax
+ pop es
+ push ds
+
+IF PMODE32
+ ;** Initialize the reboot stuff here
+ push es ; Save across call
+ cCall KRebootInit ; Local reboot init code
+ pop es
+ENDIF
+
+
+noboot:
+ mov bx,PDB_DEF_DTA ; point at command line
+ mov cx,bx ; save copy in cx
+ cmp bh,es:[bx] ; any chars in command line?
+ je ws3a ; no - exit
+ws1: inc bx ; point to next char
+ mov al,es:[bx] ; get the char
+ cmp al,' ' ; SPACE?
+ je ws1
+ cmp al,9 ; TAB?
+ je ws1
+ mov cx,bx ; save pointer to beginning
+ dec bx ; compensate for next inc
+ws2: inc bl ; move to next char
+ jz ws3a ; bailout if wrapped past 0FFh
+ cmp byte ptr es:[bx],13 ; end of line?
+ jne ws2
+ws3:
+ mov byte ptr es:[bx],0 ; null terminate the line
+ws3a:
+ mov bx,cx ; ES:BX = command line
+ mov cx,ss:[pStackTop] ; CX = stack limit
+ mov dx,1 ; DX = default cmdshow
+ cmp word ptr es:[PDB_5C_FCB],2 ; Valid byte count?
+ jne wsa4 ; No, use default
+ mov dx,word ptr es:[PDB_5C_FCB][2] ; Yes, DX = passed cmdshow
+wsa4:
+ mov ax,es ; AX = PSP address
+noinit:
+ pop ds
+
+; THIS is correct way to pop the call frame. Must pop the saved
+; DS properly from stack (might have been plugged with a RetThunk).
+
+ sub bp,2
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; InitLib ;
+; ;
+; Does what it says. ;
+; ;
+; Arguments: ;
+; CX = # bytes wanted for heap ;
+; ;
+; Returns: ;
+; ES:SI => null command line ;
+; ;
+; Error Returns: ;
+; CX = 0 ;
+; ;
+; Registers Preserved: ;
+; DI,DS ;
+; ;
+; Registers Destroyed: ;
+; AX,BX,DX ;
+; ;
+; Calls: ;
+; LocalInit ;
+; ;
+; History: ;
+; ;
+; Sat Apr 18, 1987 08:31:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitLib,<PUBLIC,FAR>
+cBegin nogen
+ xor ax,ax
+ jcxz noheap1 ; Done if no heap
+ mov si,cx
+ cCall LocalInit,<ax,ax,cx>
+ jcxz noheap1 ; Done if no heap
+ mov cx,si
+noheap1:
+ push ds
+ cCall MapDStoDATA
+ push ds
+ pop es
+ pop ds
+ mov si,codeOFFSET nullcomline
+ ret
+cEnd nogen
+
+if KDEBUG
+
+if 0
+;-----------------------------------------------------------------------
+; SetupAllocBreak
+;
+; Initializes the allocation break globals
+; from the ALLOCBRK environment variable.
+;
+; ALLOCBRK=MODULE,0x12345678
+;
+; Assumes:
+; DS = loadTDB
+;
+; Trashes:
+; ES, SI, AX, BX, CX, DX
+;
+szALLOCBRK db "ALLOCBRK="
+cchALLOCBRK equ $-szALLOCBRK
+
+cProc SetupAllocBreak,<NEAR, PUBLIC>,<SI>
+cBegin
+ mov es,ds:[TDB_PDB]
+ mov es,es:[PDB_environ]
+
+ lea bx,szALLOCBRK
+ mov dx,cchALLOCBRK
+ call LookupEnvString
+ or bx,bx
+ jz nomatch
+;
+; See if TDB_ModName is the same as the ALLOCBRK= module.
+;
+ mov si,TDB_ModName
+modloop:
+ mov al,es:[bx] ; get next environment char
+ or al,al
+ jz nomatch ; if at end of environment, no match
+ cmp al,','
+ jz match ; if at comma, then they might match
+ cmp al,ds:[si]
+ jnz nomatch
+ inc bx ; advance ptrs and try next char
+ inc si
+ jmp modloop
+match:
+ cmp byte ptr ds:[si],0 ; at end of module name string?
+ jnz nomatch
+
+ inc bx ; skip past comma.
+ call ParseHex ; parse hex constant into dx:ax
+
+ SetKernelDSNRes es
+ mov word ptr es:allocBreak,ax
+ mov word ptr es:allocBreak+2,dx
+
+ or ax,dx ; if allocBreak is 0, clear allocTask
+ jz @F
+ mov ax,ds ; otherwise allocTask = loadTDB.
+@@:
+ mov es:allocTask,ax
+
+ xor ax,ax ; reset allocCount
+ mov word ptr es:allocCount,ax
+ mov word ptr es:allocCount+2,ax
+nomatch:
+cEnd
+
+;-----------------------------------------------------------------------
+; LookupEnvString
+;
+; ES -> environment segment
+; CS:BX -> string to search for (which must include trailing '=')
+; DX -> length of string to search for
+;
+; returns:
+; es:bx = pointer to environment string past '='
+;
+cProc LookupEnvString,<NEAR, PUBLIC>,<SI,DI,DS>
+cBegin
+ push cs ; ds = cs
+ pop ds
+
+ cld
+ xor di,di ;start at beginning of environment seg
+lenv_nextstring:
+ mov si,bx ;si = start of compare string
+ mov cx,dx ;cx = string length
+ mov ax,di ;Save current position in env seg
+ repe cmpsb
+ je lenv_foundit
+
+ mov di,ax ; start at beginning again
+ xor ax,ax ; and skip to end.
+ xor cx,cx
+ dec cx ; cx = -1
+ repne scasb
+ cmp es:[di],al ;End of environment?
+ jne lenv_nextstring ;No, try next string
+ xor bx,bx ; BX == NULL == not found.
+ jmp short lenv_exit
+
+lenv_foundit:
+ mov bx,di
+lenv_exit:
+cEnd
+
+;---------------------------------------------------------------------------
+;
+; ParseHex
+;
+; Assumes:
+; es:bx - pointer to hex string of form 0x12345678
+;
+; Returns:
+; Hex value in dx:ax, es:bx pointing to char past constant.
+;
+; Trashes:
+; cx
+;
+cProc ParseHex,<NEAR, PUBLIC>
+cBegin
+ xor dx,dx ; zero break count
+ xor ax,ax
+ xor cx,cx ; clear hi byte of char
+hexloop:
+ mov cl,es:[bx] ; get first digit
+ jcxz parse_exit
+ inc bx
+ cmp cl,' ' ; skip spaces
+ jz hexloop
+ cmp cl,'x' ; skip 'x' or 'X'
+ jz hexloop
+ cmp cl,'X'
+ jz hexloop
+
+ cmp cl,'0' ; '0'..'9'?
+ jb parse_exit
+ cmp cl,'9'
+ jbe hexdigit
+
+ or cl,'a'-'A' ; convert to lower case
+
+ cmp cl,'a' ; 'a'..'f'?
+ jb parse_exit
+ cmp cl,'f'
+ ja parse_exit
+
+ sub cl,'a'-'0'-10
+hexdigit:
+ sub cl,'0'
+
+ add ax,ax ; dx:ax *= 16
+ adc dx,dx
+ add ax,ax
+ adc dx,dx
+ add ax,ax
+ adc dx,dx
+ add ax,ax
+ adc dx,dx
+
+ add ax,cx ; add in the new digit
+ adc dx,0
+
+ jmp hexloop
+parse_exit:
+cEnd
+endif; 0
+
+endif ;KDEBUG
+
+sEnd NRESCODE
+
+
+if KDEBUG
+
+sBegin CODE
+assumes cs,CODE
+;------------------------------------------------------------------------
+;
+; char FAR* GetTaskModNamePtr(HTASK htask)
+;
+; Returns a far pointer to a task's module name
+; Used by SetupAllocBreak to access the task module name.
+;
+; Coded in assembly because no C header file that describes
+; the TDB exists (and it's a little late to create one now)
+;
+cProc GetTaskModNamePtr,<NEAR, PUBLIC>
+ParmW htask
+cBegin
+ mov dx,htask
+ mov ax,TDB_ModName
+cEnd
+
+sEnd CODE
+endif; KDEBUG
+
+
+sBegin MISCCODE
+assumes cs, misccode
+assumes ds, nothing
+assumes es, nothing
+
+externNP MISCMapDStoDATA
+
+;-----------------------------------------------------------------------;
+; GetDOSEnvironment
+;
+; Gets a pointer to the current task's starting environment string.
+; Basically used by DLL's to find the environment.
+;
+; Entry:
+; none
+;
+; Returns:
+; DX:AX = pointer to current task's starting environment string
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 13-Jun-1989 20:52:58 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetDOSEnvironment,<PUBLIC,FAR>
+cBegin nogen
+
+ push ds
+ call GetCurrentTask
+ mov ds,ax
+ mov ds,ds:[TDB_PDB]
+ mov dx,ds:[PDB_environ]
+ xor ax,ax
+ pop ds
+ ret
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetNumTasks ;
+; ;
+; Gets the number of tasks (AKA TDB) in the system. ;
+; ;
+; Arguments: ;
+; none ;
+; ;
+; Returns: ;
+; AX = number of tasks ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Thu Apr 09, 1987 11:34:30p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetNumTasks,<PUBLIC,FAR>
+cBegin nogen
+ xor ax,ax
+ push ds
+ call MISCMapDStoDATA
+ ReSetKernelDS
+ mov al,num_tasks
+ pop ds
+ UnSetKernelDS
+ ret
+cEnd nogen
+
+sEnd MISCCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/tasking.asm b/private/mvdm/wow16/kernel31/tasking.asm
new file mode 100644
index 000000000..91696477f
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/tasking.asm
@@ -0,0 +1,590 @@
+ TITLE TASKING.ASM - WOW Tasking Support
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; TASKING.ASM
+; WOW Tasking Support on 16 bit side - also see wkman.c
+;
+; History:
+; 23-May-91 Matt Felton (mattfe) Created
+; 12-FEB-92 Cleanup
+;
+
+.xlist
+include kernel.inc
+include tdb.inc
+include newexe.inc
+include wow.inc
+include vint.inc
+.list
+
+if PMODE32
+.386
+else
+.286
+endif
+
+
+if KDEBUG
+externFP OutputDebugString
+endif
+
+DataBegin
+
+externB Kernel_InDOS
+externB Kernel_flags
+externB InScheduler
+ifndef WOW
+externB fProfileDirty
+endif
+externW WinFlags
+externW cur_drive_owner
+externW curTDB
+externW Win_PDB
+externW LockTDB
+externW headTDB
+externW hShell
+externW pGlobalHeap
+externW hExeHead
+externW f8087
+externD pIsUserIdle
+externW wCurTaskSS
+externW wCurTaskBP
+
+globalw gwHackpTDB,0
+globalw gwHackTaskSS,0
+globalw gwHackTaskSP,0
+
+if PMODE32
+externW PagingFlags
+endif
+
+DataEnd
+
+sBegin CODE
+assumes cs,CODE
+assumes ds,NOTHING
+assumes es,NOTHING
+
+ife PMODE
+externNP patch_cached_p
+endif
+externNP LoadSegment
+externNP DeleteTask
+externNP InsertTask
+if PMODE32
+externNP ShrinkHeap
+endif
+
+ifdef WOW
+externFP ExitKernelThunk
+externFP WowInitTask
+externFP Yield
+externFP WOW16CallNewTaskRet
+externFP WowKillTask
+externFP WOW16DoneBoot
+externNP Int21Handler
+externFP GlobalCompact
+externFP WOWGetCurrentDirectory
+endif
+
+if SDEBUG
+externNP DebugSwitchOut
+externNP DebugSwitchIn
+endif
+
+;-----------------------------------------------------------------------;
+; StartWOWTask ;
+; ;
+; Start a WOW 32 Task ;
+; ;
+; Arguments: ;
+; Parmw1 -> TDB Of New Task ;
+; Parmw2 New Task SS ;
+; Parmw3 New Task SP ;
+; Returns: ;
+; AX - TRUE/FALSE if we we able to create a new WOW task ;
+; Error Returns: ;
+; none ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX ;
+; Calls: ;
+; See Notes ;
+; History: ;
+; ;
+; Fre 24-May-1991 14:30 -by- Matthew A. Felton [mattfe] ;
+; Created ;
+;-----------------------------------------------------------------------;
+
+; The 16-Bit Kernel has created the new task and its ready to go
+; 1. Temporarily Switch to New Task Stack S2
+; 2. Fake Far Return from Thunk to point to StartW16Task
+; 3. Thunk to WOW32 - This will create a new Thread and call Win32 InitTask()
+; Note InitTask() will not return from the non-preemptive scheduler until
+; This thread does a Yield.
+; 4. When the thunk returns is jmps to WOW16TaskStarted on S2 leaving
+; S2 ready for the new task when it returns
+; 5. Restore S1 - Original Task Stack
+; 6. Return Back to LoadModule who will Yield and start T2 going.
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc StartWOWTask,<PUBLIC,FAR>
+ parmW pTDB
+ parmW wTaskSS
+ parmW wTaskSP
+
+cBegin
+ SetKernelDS ds
+
+ mov es,pTDB ; Get New Task TDB, will use later
+ push curTDB ; Save our TDB
+ push bp ; save BP (we don't exit wow16cal directly)
+ mov di,ss ; Save Current Task Stack
+ mov cx,sp ; di=ss cx=sp
+
+; switch to new task stack temporarily
+
+ FCLI ; Disable Ints Till We get Back
+ ; To presever new fram
+ mov si,wTaskSP ; Grab this before SS goes away
+ mov ss,wTaskSS ; Switch to new task stack.
+ mov sp,si ;
+
+ mov curTDB,es ; Set curTDB to new task
+ ;
+ pushf
+ pop ax
+ or ax,0200h ; Re-enable interrupts
+ push ax
+
+ push es ; hTask
+
+ mov es, es:[TDB_pModule] ; exehdr
+
+ mov ax, es:[ne_expver]
+ mov dx, es:[ne_flags]
+ and dx, NEWINPROT ; prop. font bit
+
+ push es ; hModule
+ push es ; Pointer to module name
+ push es:ne_restab
+ push es ; Pointer to module path
+ push word ptr es:ne_crc+2
+
+ push dx ; expwinver. argument for WOWINITTASK
+ push ax
+
+ mov es, curTDB ; resotre es, just being safe
+
+
+; thunk to wow32 to create a thread and task
+
+ push cs ; Fake Out FAR Return to StartW16Task
+ push offset StartW16Task
+
+ jmp WowInitTask ; Start Up the W32 Thread
+
+ public WOW16TaskStarted
+WOW16TaskStarted:
+ mov ss,di ; Restore Calling Task Stack
+ mov sp,cx
+ pop bp
+ pop curTDB ; Restore real CurTDB
+ FSTI ; OK we look like old task
+
+cEnd
+
+
+;
+; First code executed By New Task - Setup Registers and Go
+;
+
+StartW16Task:
+ add sp,+12
+ pop ax ; Flags
+ mov bp,sp
+ xchg ax,[bp+20] ; Put flags down & pick up cs
+ xchg ax,[bp+18] ; Put cs down & pick up ip
+ xchg ax,[bp+16] ; Put ip down & pick up bp
+ mov bp,ax
+ dec bp
+ pop dx
+ pop bx
+ pop es
+ pop cx
+ pop ax
+ pop di
+ pop si
+ pop ds
+ iret ; App Code Starts From Here
+
+
+; ExitKernel
+;
+; Enter When the 16 bit Kernel is going away -- never returns.
+; In WOW this is a register-args wrapper for the stack-args
+; thunk ExitKernelThunk.
+
+ public ExitKernel
+ ExitKernel:
+
+ cCall ExitKernelThunk, <ax>
+
+ INT3_NEVER ; ExitKernel never returns.
+
+
+; BootSchedule
+;
+; Entered When Bogus Boot Task goes Away - treated same as task exit.
+
+ public BootSchedule
+BootSchedule:
+ CheckKernelDS DS ; Make Sure we Address Kernel DS
+ mov [curTDB],0 ; Make No Task the Current Task
+ jmp WOW16DONEBOOT
+
+; ExitSchedule
+;
+; We get here when a 16 bit task has exited - go kill this task
+; Win32 non-preemptive scheduler will wake someone else to run.
+
+ public ExitSchedule
+ExitSchedule:
+ CheckKernelDS DS ; Make Sure we Address Kernel DS
+
+ mov ax,[LockTDB] ; If I am the locked TDB then clear flag
+ cmp ax,[curTDB]
+ jnz @f
+ mov [LockTDB],0
+@@:
+ mov [curTDB],0 ; Make No Task the Current Task
+if PMODE32
+ call ShrinkHeap
+endif; PMODE32
+ jmp WowKillTask ; Go Kill Myself (NEVER RETURNS)
+
+
+
+;-----------------------------------------------------------------------;
+; SwitchTask - This is NOT a subroutine DO NOT CALL IT
+;
+; This routine does a Win 3.1 compatible task switch.
+;
+; Arguments:
+; AX == Next Tasks TDB pointer
+; Returns:
+; nothing
+; Error Returns:
+; nothing
+; Registers Preserved:
+;
+; Registers Destroyed:
+;
+; Calls:
+; SaveState
+; RestoreState
+;
+; History:
+; 22-May-91 Matt Felton (MattFe) Created
+; Using idea's from Win 3.1 Schedule.Asm
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+ public SwitchTask
+SwitchTask:
+ CheckKernelDS ds
+ ReSetKernelDS ds
+
+ inc InScheduler ; set flag for INT 24...
+
+ cmp curTDB,0 ; Previous Task Gone Away ?
+ jnz @f ; No ->
+
+ ; Yes
+ mov di,ax ; DI = New TDB
+ mov ds,ax ; DS = New TDB
+ jmps dont_save_state ; Get Set for this new guy
+
+@@:
+ push ax ; Save Next Tasks TDB pointer
+
+; COMPAT 22-May-91 Mattfe, Idle callout for funky screen drivers is done by
+; the Windows scheduler - that will not happen either from WOW. INT 28
+; and Win386 1689 int2f call
+
+; There was PokeAtSegments code which during idle time brought back segments !
+
+; Do Debuggers Care that the stack frame of registers looks like a Windows stack frame
+; when we do the debugger callout ? - check with someone in CVW land.
+
+ mov es,curTDB ; ES = Previous Task TDB
+
+ mov ax,es ; Don't SS,SP For DEAD Task
+ or ax,ax
+ jz @F
+
+ mov ax,wCurTaskSS ; FAKE Out TDB_taskSS,SP so that
+ mov es:[TDB_taskSS],ax ; The Old Task Task_BP looks right
+ mov ax,wCurTaskBP
+ sub ax,(Task_BP-Task_DX)
+ mov es:[TDB_taskSP],ax
+
+@@:
+ pop ds ; DS = Next Task TDB
+ UnSetKernelDS ds
+
+if KDEBUG
+
+; Assertion Check TDB_taskSS == SS for current Task
+
+ mov ax,ds:[TDB_taskSS]
+ mov di,ss
+ cmp di,ax
+ jz @F
+
+; int 3
+@@:
+endif; KDEBUG
+
+ mov di,ds ; DI = destination task
+ xor si,si ; SI is an argument to RestoreState
+
+ mov ax,es ; NOTE TDB_SS,SP Are note Correct
+ or ax,ax ; might affect debugger compatability.
+ jz short dont_save_state
+
+ cmp es:[TDB_sig],TDB_SIGNATURE
+ jnz short dont_save_state
+ mov si,es ; SI = Old Task
+
+
+ cCall SaveState,<si>
+if SDEBUG
+ push ds
+ mov ds,ax
+ call DebugSwitchOut ; Note Stack Frame is not Compatible
+ pop ds ; Do we care ?
+endif
+dont_save_state:
+ SetKernelDS es
+ mov curTDB,di
+
+ mov ax, ds:[TDB_PDB] ; Set our idea of the PDB
+ mov Win_PDB, ax
+
+ SetKernelDS es
+
+ cmp di,0 ; the first task, will never get 0
+ jz dont_restore_state
+
+ife PMODE
+ call RestoreState
+endif
+ or Kernel_flags,kf_restore_CtrlC OR kf_restore_disk
+if SDEBUG
+ call DebugSwitchIn
+endif
+
+dont_restore_state:
+ ; Switch to new task stack.
+ mov curTDB,di
+ dec InScheduler ; reset flag for INT 24
+
+ SetKernelDS ds ; Set the Kernel DS again
+
+;the word at [vf_wES] is a selector that's about to be popped into
+;the ES in WOW16CallNewTaskRet. this selector could be the TDB of
+;a task that just died, in which case it's invalid. so let's
+;shove something in there that won't cause a GP when we do the POP ES.
+;
+; In some cases we are switching tasks while returning to a callback.
+; When this happens our stack is a CBVDMFRAME instead of a VDMFRAME.
+; We only want to shove a safe ES,FS,GS value when it's a VDMFRAME and
+; we're returning from an API call rather than calling back to
+; 16-bit code.
+;
+; Regardless of which frame we're using, ss:sp points to wRetID.
+
+
+ mov bx, sp
+ cmp WORD PTR ss:[bx], RET_DEBUGRETURN ; if (wRetID > RET_DEBUGRETURN)
+ ja dont_stuff_regs ; goto dont_stuff_regs
+
+ sub bx,vf_wTDB + 2 ;bx is now start of VDMFRAME struct
+ mov ss:[bx+vf_wES],es ;put something safe in there
+;Win31 does not save fs, gs over task switches, so we zero them out here
+ mov word ptr ss:[bx+vf_wFS],0 ;put something safe in there
+ mov word ptr ss:[bx+vf_wGS],0 ;put something safe in there
+dont_stuff_regs:
+
+
+if KDEBUG
+ mov bx, sp
+ cmp WORD PTR ss:[bx], RET_TASKSTARTED
+ jne @f
+ INT3_NEVER ; We need to stuff ES for RET_TASKSTARTED
+ ; if we hit this breakpoint.
+@@:
+endif
+
+; Hung App Support
+; If the new task is the one we want to kill then force it to exit
+
+ mov bx,curTDB ; if ( curTDB == LockTDB )
+ cmp bx,LockTDB
+ jnz SW_DontKillIt
+
+ mov ax,4CFFH ; YES -> Exit
+ DOSCALL
+ INT3_NEVER
+
+SW_DontKillIt:
+ jmp WOW16CallNewTaskRet ; Continue with the new task.
+
+
+;-----------------------------------------------------------------------;
+; SaveState ;
+; ;
+; Saves the state of the current MS-DOS process. This means the per ;
+; task interrupt vectors, the drive and directory, EEMS land if any, ;
+; and old app stuff if any. ;
+; ;
+; Arguments: ;
+; parmW destination ;
+; ;
+; Returns: ;
+; DS returned in AX. ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
+; Removed the WinOldApp support. ;
+; ;
+; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
+; Got rid of the rest of the DOS version dependencies. ;
+; ;
+; Thu Jan 22, 1987 03:15:15a -by- David N. Weise [davidw] ;
+; Took out the saving of the ^C state, DTA address, and ErrorMode. ;
+; ;
+; Sun Jan 04, 1987 04:40:44p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc SaveState,<PUBLIC,NEAR>,<si,di,ds>
+ parmW destination
+cBegin
+ cld
+ife PMODE
+ SaveTaskInts destination
+endif
+ SetKernelDS
+ mov ax,f8087
+ UnSetKernelDS
+ mov ds,destination
+ or ax,ax
+if 0
+ jz short no_fstcw
+ .8087
+ fstcw ds:[TDB_FCW]
+endif
+no_fstcw:
+ test ds:[TDB_Drive],10000000b; if hi bit set....
+ jnz short ss_ret ; ...no need to get dir
+ mov ah,19h
+ DOSCALL
+ mov dl,al
+ inc dl
+ or al,10000000b
+ mov ds:[TDB_Drive],al ; save it (A=0, B=1, etc.)
+
+ mov si,TDB_LFNDirectory
+ mov byte ptr [si],'\' ; set "\"
+ inc si
+ ; get Long path
+ cCall WowGetCurrentDirectory,<80h, ds, si>
+ or dx, dx
+ jz short ss_ret
+ mov byte ptr [si-1],0 ; indicate error with null byte
+ss_ret: mov ax,ds
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; RestoreState ;
+; ;
+; Restores the MS-DOS interrupt vectors in real mode. ;
+; ;
+; Arguments: ;
+; none ;
+; Returns: ;
+; none ;
+; Error Returns: ;
+; none ;
+; Registers Preserved: ;
+; BX,CX,DX,DI,SI,DS,ES ;
+; Registers Destroyed: ;
+; AX ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
+; Removed the WinOldApp support. ;
+; ;
+; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
+; Got rid of the rest of the DOS version dependencies. ;
+; ;
+; Thu Jan 22, 1987 03:15:15a -by- David N. Weise [davidw] ;
+; Took out the restoring of the ^C state, DTA address, and ErrorMode. ;
+; ;
+; Sun Jan 04, 1987 04:45:31p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ife PMODE
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc RestoreState,<PUBLIC,NEAR>
+
+cBegin nogen
+ push di
+ push si
+ push ds
+ push es
+ cld
+ RestTaskInts di ; restore DOS interrupts
+ pop es
+ pop ds
+ pop si
+ pop di
+ ret
+cEnd nogen
+
+endif ; PMODE
+
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/kernel31/tdb.inc b/private/mvdm/wow16/kernel31/tdb.inc
new file mode 100644
index 000000000..aa5ae32a2
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/tdb.inc
@@ -0,0 +1,235 @@
+;
+; Task Data Block
+;
+; Contains all task specific data.
+;
+
+;
+; The following macros allow saving and restoring hardware interrupt
+; vectors inline.
+
+numTaskInts = 0
+?hinum = 0
+
+?higen macro x,i,r,t
+
+if r LE 3
+
+ ?hisav&x &macro
+ ife t
+ mov si,4*i
+ else
+ mov si,i
+ endif
+ rept 2*r
+ movsw
+ endm
+ &endm
+
+ ?hires&x &macro
+ ife t
+ mov di,4*i
+ else
+ mov di,i
+ endif
+ rept 2*r
+ movsw
+ endm
+ &endm
+
+else
+
+ ?hisav&x &macro
+ ife t
+ mov si,4*i
+ else
+ mov si,i
+ endif
+ mov cx,2*r
+ rep movsw
+ &endm
+
+ ?hires&x &macro
+ ife t
+ mov di,4*i
+ else
+ mov di,i
+ endif
+ mov cx,2*r
+ rep movsw
+ &endm
+
+endif
+endm
+
+DefTaskIntGroup macro i,r,t
+?higen %?hinum,i,r,t
+?hinum = ?hinum + 1
+numTaskInts = numTaskInts + r
+endm
+
+?hiexp macro n,x
+ n&x
+endm
+
+
+SaveTaskInts macro destination
+mov es,destination
+xor ax,ax
+mov ds,ax
+mov di,TDB_INTVECS
+?hicnt = 0
+rept ?hinum
+?hiexp &?hisav,%?hicnt
+?hicnt = ?hicnt + 1
+endm
+endm
+
+RestTaskInts macro source
+mov ds,source
+mov si,TDB_INTVECS
+xor ax,ax
+mov es,ax
+?hicnt = 0
+rept ?hinum
+?hiexp &?hires,%?hicnt
+?hicnt = ?hicnt + 1
+endm
+endm
+
+; Define the hardware interrupts we will keep on a task specific basis.
+; We only save on a per task basis those interrupts related to arithmetic.
+; So we save 0, 2, 4, 6, 7, 10h, 3Eh, and 75h.
+; Int 0 is divide by 0
+; Int 2 is Coprocessor Error
+; Int 4 is overflow
+; Int 6 is invalid op-code
+; Int 7 is no coprocessor,
+; Int 3Eh is use by the C compiler for 8087 emulation.
+; Int 75h is use by the C compiler for 8087 emulation.
+; In Windows 1.03 we saved 0h, 1h, 2h, 3Eh.
+; For DOS5 compatibility we should save 0, 4, 6, and 7.
+
+
+DefTaskIntGroup (00h),1,0
+DefTaskIntGroup (02h),1,0
+DefTaskIntGroup (04h),1,0
+DefTaskIntGroup (06h),2,0
+DefTaskIntGroup (3Eh),1,0
+DefTaskIntGroup (75h),1,0
+
+ifdef WOW
+ include tdb16.inc
+else ; original TDB
+
+THUNKELEM EQU 8 ; (62*8) = 512-16 (low arena overhead)
+THUNKSIZE EQU 8
+
+; Task data structure
+
+
+;
+; DON'T YOU DARE CHANGE ANYTHING IN HERE
+; OR RAOR WILL KILL YOU
+; OLE DEPENDS ON THIS 3/25/91
+;
+
+TDB STRUC
+
+TDB_next DW ? ; next task in dispatch queue
+TDB_taskSP DW ? ; Saved SS:SP for this task
+TDB_taskSS DW ? ;
+TDB_nEvents DW ? ; Task event counter
+TDB_priority DB ? ; Task priority (0 is highest)
+
+TDB_thread_ordinal DB ? ; ordinal number of this thread
+TDB_thread_next DW ? ; next thread
+TDB_thread_tdb DW ? ; the real TDB for this task
+
+TDB_thread_list DW ? ; list of allocated thread structures
+TDB_thread_free DW ? ; free list of availble thread structures
+TDB_thread_count DW ? ; total count of tread structures
+
+TDB_FCW DW ? ; Floating point control word
+
+TDB_flags DB ? ; Task flags
+TDB_filler DB ? ; keep word aligned
+
+TDB_ErrMode DW ? ; Error mode for this task
+TDB_ExpWinVer DW ? ; Expected Windows version for this task
+TDB_Module DW ? ; Task module handle to free in killtask
+TDB_pModule DW ? ; Pointer to the module database.
+TDB_Queue DW ? ; Task Event Queue pointer
+TDB_Parent DW ? ; TDB of the task that started this up
+
+TDB_SigAction DW ? ; Action for app task signal
+TDB_ASignalProc DD ? ; App's Task Signal procedure address
+TDB_USignalProc DD ? ; User's Task Signal procedure address
+TDB_GNotifyProc DD ? ; Task global discard notify proc.
+
+TDB_INTVECS DD numTaskInts DUP (?) ; Task specfic hardware interrupts
+
+if 0
+ ; EMS fields are OBSOLETE!
+
+TDB_LIMSave DW ? ; Offset within TDB of LIM save area
+TDB_EMSPID DW ? ; EMS PID for this task
+TDB_EEMSSave DD ? ; LPTR to EEMS save area (in a TDB)
+TDB_EMSBCnt DW ? ; number of EMS banks allocated so far
+TDB_EMSMaxBCnt DW ? ; Maximum # banks this task wants.
+TDB_EMSRegSet DB ? ; The register set this TDB lives in.
+
+else
+
+TDB_CompatFlags DW ? ; Compatibility flags
+TDB_CompatFlags2 DW ? ; Upper 16 bits
+ DB 9 DUP (?) ; Filler to keep TDB size unchanged
+endif
+
+TDB_cLibrary DB ? ; tracks add/del of ALL libs in system EMS
+TDB_PHT DD ? ; (HANDLE:OFFSET) to private handle table
+TDB_PDB DW ? ; MSDOS Process Data Block (PDB)
+TDB_DTA DD ? ; MSDOS Disk Transfer Address
+TDB_Drive DB ? ; MSDOS current drive
+TDB_Directory DB 65 DUP (?) ; MSDOS current directory
+TDB_Validity DW ? ; initial AX to be passed to a task
+TDB_Yield_to DW ? ; DirectedYield arg stored here
+TDB_LibInitSeg DW ? ; segment address of libraries to init
+TDB_LibInitOff DW ?
+ ; MakeProcInstance thunks live here.
+TDB_MPI_Sel DW ? ; Code selector for thunks
+TDB_MPI_Thunks DW ((THUNKELEM*THUNKSIZE)/2) dup (?)
+
+TDB_ModName DB 8 DUP (?) ; Name of Module.
+TDB_sig DW ? ; Signature word to detect bogus code
+TDB ENDS
+endif ; original TDB_
+
+TDBsize = SIZE TDB
+
+
+; signature word used to check validity of a TDB
+
+TDB_SIGNATURE equ 'DT'
+
+; TDB flags
+
+TDBF_WINOLDAP EQU 01h ; This app is WinOldAp.
+TDBF_EMSSHARE EQU 02h ; This app shares EMS banks with MSDOS EXEC.
+TDBF_CACHECHECK EQU 04h ; Used in CacheCompact to prevent revisitation.
+TDBF_OS2APP EQU 08h ; This is an OS/2 app.
+TDBF_WIN32S EQU 10h ; This is Win32S app.
+
+Task_Regs struc
+Task_DX dw ?
+Task_BX dw ?
+Task_ES dw ?
+Task_CX dw ?
+Task_AX dw ?
+Task_DI dw ?
+Task_SI dw ?
+Task_DS dw ?
+Task_BP dw ?
+Task_IP dw ?
+Task_CS dw ?
+Task_Regs ends
diff --git a/private/mvdm/wow16/kernel31/up.c b/private/mvdm/wow16/kernel31/up.c
new file mode 100644
index 000000000..8a839b181
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/up.c
@@ -0,0 +1,2390 @@
+
+/*
+ * UP.C
+ *
+ * User Profile routines
+ *
+ * These are the routines which read and write INI files.
+ *
+ * Exported routines:
+ *
+ * GetProfileString
+ * GetPrivateProfileString
+ * GetProfileInt
+ * GetPrivateProfileInt
+ * WriteProfileString
+ * WritePrivateProfileString
+ *
+ * Note the parameter "lpSection" used to be known as "lpApplicationName".
+ * The code always referred to sections, so the parameter has been changed.
+ *
+ * Rewritten 6/90 for C 6.0.
+ */
+
+#include "kernel.h"
+
+ /*
+ * Required definitions for exported routines:
+ */
+
+#define API _far _pascal _loadds
+
+HANDLE API IGlobalAlloc(WORD, DWORD);
+HANDLE API IGlobalFree(HANDLE);
+LPSTR API IGlobalLock(HANDLE);
+HANDLE API IGlobalReAlloc(HANDLE, DWORD, WORD);
+BOOL API IGlobalUnlock(HANDLE);
+
+/* #pragma optimize("t", off) */
+
+ /* This ensures that only one selector is required in PMODE */
+#define MAXBUFLEN 0xFFE0L
+
+#define SPACE ' '
+#define TAB '\t'
+#define LINEFEED '\n'
+#define CR '\r'
+#define SECT_LEFT '['
+#define SECT_RIGHT ']'
+#define CTRLZ ('Z'-'@')
+
+ /* Constants for WriteProfileString - DON'T CHANGE THESE */
+#define NOSECTION 0
+#define NOKEY 1
+#define NEWRESULT 2
+#define REMOVESECTION 3
+#define REMOVEKEY 4
+
+ /* Flags about a file kept in ProInfo
+ * If the PROUNCLEAN label is changed, its value must also be
+ * changed in I21ENTRY.ASM, where it is assumed to be 2.
+ */
+#define PROCOMMENTS 1 /* contains comments */
+#define PROUNCLEAN 2 /* has not been written */
+#define PROMATCHES 4 /* buffer matches disk copy */
+#define PROREADONLY 8 /* Read only file */
+#define PRO_CREATED 16 /* File was just created */
+
+ /* Sharing violation. */
+#define SHARINGVIOLATION 0x0020
+
+ /* For forcing variables into the current code segment */
+#define CODESEG _based(_segname("_CODE"))
+ /* Hide disgusting _based syntax */
+#define BASED_ON_LP(x) _based((_segment)x)
+#define BASED_ON_SEG(x) _based(x)
+#define SEGMENT _segment
+
+ /* Externals assumed to be in DGROUP */
+extern PROINFO WinIniInfo;
+extern PROINFO PrivateProInfo;
+extern LPSTR lpWindowsDir;
+extern int cBytesWinDir;
+extern int WinFlags;
+extern char fBooting;
+extern char fProfileDirty;
+extern char fProfileMaybeStale;
+extern char fAnnoyEarle;
+extern char fBooting;
+extern LPSTR curDTA;
+extern BYTE fWriteOutProfilesReenter;
+
+ /* Forward definitions to keep compiler happy */
+ /* _fastcall may save some space on internal routines */
+LPSTR _fastcall BufferInit(PROINFO *, int);
+LPSTR _fastcall LockBuffer(PROINFO *);
+void _fastcall UnlockBuffer(PROINFO *);
+LPSTR _fastcall FreeBuffer(PROINFO *);
+LPSTR _fastcall PackBuffer(PROINFO *, int, int);
+void _fastcall FlushDirtyFile(PROINFO *);
+int GetInt(PROINFO *, LPSTR, LPSTR, int);
+int GetString(PROINFO *, LPSTR, LPSTR, LPSTR, LPSTR, int);
+LPSTR FindString(PROINFO *, LPSTR, LPSTR);
+LPSTR FindSection(LPSTR, LPSTR);
+LPSTR FindKey(LPSTR, LPSTR);
+int WriteString(PROINFO *, LPSTR, LPSTR, LPSTR);
+void strcmpi(void);
+int MyStrlen(void);
+void API WriteOutProfiles(void);
+PROINFO * SetPrivateProInfo(LPSTR,LPSTR);
+int GetSection(PROINFO*, LPSTR, LPSTR, int);
+int IsItTheSame(LPSTR, LPSTR);
+int Cstrlen(LPSTR);
+int MakeRoom(LPSTR, int, int*);
+int InsertSection(LPSTR, LPSTR, short);
+int InsertKey(LPSTR, LPSTR, short);
+int InsertResult(LPSTR, LPSTR, short);
+int DeleteSection(LPSTR, PROINFO*);
+int DeleteKey(LPSTR, PROINFO*);
+
+ /* External KERNEL routines */
+void _far _pascal FarMyLower();
+
+int API lstrOriginal(LPSTR,LPSTR); /* lstrcmp in disguise */
+
+#ifdef DBCS
+// Delacred in kernel.h already
+// void _far _pascal AnsiPrev(LPSTR,LPSTR);
+void _far _pascal FarMyIsDBCSLeadByte();
+#endif
+
+char CODESEG WinIniStr[] = "WIN.INI";
+
+/* DOS FindFirst/FindNext structure (43h, 44h) */
+typedef struct tagFILEINFO
+{
+ BYTE fiReserved[21];
+ BYTE fiAttribute;
+ WORD fiFileTime;
+ WORD fiFileDate;
+ DWORD fiSize;
+ BYTE fiFileName[13];
+} FILEINFO;
+
+/*
+ * Get[Private]ProfileInt
+ *
+ * Parameters:
+ * lpSection Pointer to section to match in INI file
+ * lpKeyName Pointer to key string to match in file
+ * nDefault Default value to return if not found
+ * [lpFile File to use for Private INI]
+ *
+ * Returns:
+ * nDefault section/keyname not found
+ * number found in file if section/keyname found
+ */
+int API
+IGetProfileInt(lpSection, lpKeyName, nDefault)
+LPSTR lpSection;
+LPSTR lpKeyName;
+int nDefault;
+{
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(&WinIniInfo);
+
+ nReturn = GetInt(&WinIniInfo, lpSection, lpKeyName, nDefault);
+
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+int API
+IGetPrivateProfileInt(lpSection, lpKeyName, nDefault, lpFile)
+LPSTR lpSection;
+LPSTR lpKeyName;
+int nDefault;
+LPSTR lpFile;
+{
+ PROINFO *pProInfo;
+ char Buffer[128];
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(pProInfo);
+
+ nReturn = GetInt(pProInfo, lpSection, lpKeyName, nDefault);
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+/*
+ * Get[Private]ProfileString
+ *
+ * Parameters:
+ * lpSection Pointer to section to match in INI file
+ * lpKeyName Pointer to key string to match in file
+ * lpDefault Default string to return if not found
+ * lpResult String to fill in
+ * nSize Max number of characters to copy
+ * [lpFile] File to use for Private INI
+ *
+ * Returns:
+ * string from file or lpDefault copied to lpResult
+ * < nSize - 2 Number of characters copied to lpResult
+ * nSize - 2 lpResult was not big enough
+ */
+int API
+IGetProfileString(lpSection, lpKeyName, lpDefault, lpResult, nSize)
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpDefault;
+LPSTR lpResult;
+int nSize;
+{
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(&WinIniInfo);
+
+ nReturn = GetString(&WinIniInfo, lpSection, lpKeyName, lpDefault,
+ lpResult, nSize);
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+int API
+IGetPrivateProfileString(lpSection, lpKeyName, lpDefault, lpResult, nSize, lpFile)
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpDefault;
+LPSTR lpResult;
+int nSize;
+LPSTR lpFile;
+{
+ PROINFO *pProInfo;
+ char Buffer[128];
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(pProInfo);
+
+ nReturn = GetString(pProInfo, lpSection, lpKeyName, lpDefault,
+ lpResult, nSize);
+
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+/*
+ * Write[Private]ProfileString
+ *
+ * Parameters:
+ * lpSection Pointer to section to match/add to INI file
+ * lpKeyName Pointer to key string to match/add to file
+ * lpString String to add to file
+ * [lpFile] File to use for Private INI
+ *
+ * Returns:
+ * 0 Failed
+ * 1 Success
+ */
+int API
+IWriteProfileString(lpSection, lpKeyName, lpString)
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpString;
+{
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(&WinIniInfo);
+
+ nReturn = WriteString(&WinIniInfo, lpSection, lpKeyName, lpString);
+
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+int API
+IWritePrivateProfileString(lpSection, lpKeyName, lpString, lpFile)
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpString;
+LPSTR lpFile;
+{
+ PROINFO *pProInfo;
+ char Buffer[128];
+ int nReturn;
+
+ /* Make sure we don't try to flush INI files on DOS calls */
+ ++fWriteOutProfilesReenter;
+
+ pProInfo = SetPrivateProInfo(lpFile, (LPSTR)Buffer);
+
+ /* Reread INI file first if necessary */
+ FlushDirtyFile(pProInfo);
+
+ nReturn = WriteString(pProInfo, lpSection, lpKeyName, lpString);
+
+ --fWriteOutProfilesReenter;
+
+ return nReturn;
+}
+
+
+/* FlushDirtyFile
+ * Rereads a file if it has been "dirtied" by another task. To
+ * see if the file has been dirtied, we check the time/date
+ * stamp.
+ */
+
+void _fastcall FlushDirtyFile(PROINFO *pProInfo)
+{
+ FILEINFO FileInfo;
+ DWORD dwSaveDTA;
+
+ /* We only have to do this if the file COULD have changed and
+ * that we already have something cached. Also, there's
+ * no need to do this at boot time because this is a
+ * safeguard against the USER doing something bad!
+ */
+ if (fBooting || !fProfileMaybeStale || !pProInfo->lpBuffer)
+ return;
+
+ /* The OFSTRUCT in the PROINFO buffer should have the most recent
+ * date and time when the file was opened. We just compare the
+ * current date and time to this.
+ */
+ _asm
+ {
+ ;** Save old DTA and point to our structure
+ mov ah,2fh ;Get DTA. Int21 code calls DOS only
+ int 21h ; if necessary. DTA in ES:BX
+ jc RDF_FlushIt ;Problem, so better flush it
+ mov WORD PTR dwSaveDTA[2],es ;Save for later
+ mov WORD PTR dwSaveDTA[0],bx
+ mov ah,1ah ;Set DTA
+ push ds ;Can't do a SetKernelDS so push/pop
+ push ss ;Get SS=DS
+ pop ds
+ lea dx,FileInfo ;Point DTA to our structure
+ int 21h ;Set the DTA
+ pop ds
+ jc RDF_FlushIt ;Problem, so just flush it
+
+ ;** Do a FindFirst on the file to get date and time reliably
+ xor cx,cx ;Normal file
+ mov si,pProInfo ;Point to pathname with DS:DX
+ lea dx,[si].ProBuf
+ add dx,8 ;(offset of szPathName)
+ mov ah,4eh ;Find first
+ int 21h ;Call DOS
+ jc RDF_FlushIt ;Can't find, so better flush it
+
+ ;** Put DTA back
+ push ds
+ lds dx,dwSaveDTA ;DS:DX points to old DTA
+ mov ah,1ah
+ int 21h
+ pop ds
+
+ ;** Compare the date and time
+ lea bx,FileInfo ;Point to FILEINFO
+ mov dx,ss:[bx + 24] ;Date in FILEINFO structure
+ mov cx,ss:[bx + 22] ;Tile in FILEINFO structure
+ mov si,pProInfo ;Point to OFSTRUCT with DS:SI
+ lea si,[si].ProBuf
+ cmp [si + 4],dx ;Same date as original?
+ jne RDF_FlushIt ;No
+ cmp [si + 6],cx ;Same time as original?
+ je RDF_NoFlush ;No
+ }
+
+ /* Force a file reread */
+RDF_FlushIt:
+ FreeBuffer(pProInfo);
+RDF_NoFlush:
+
+ /* Clear the dirty flag */
+ fProfileMaybeStale = 0;
+}
+
+
+/*
+ * SetPrivateProInfo
+ *
+ * Force a private profile into the windows directory if necessary.
+ * Check if it is the same file as is currently cached.
+ * If not, discard the cached file.
+ * Sets up the PrivateProInfo data structure.
+ *
+ * Parameters:
+ * lpFile Pointer to filename to be used as a profile
+ * Buffer Buffer to parse filename into
+ *
+ * Returns:
+ * PROINFO * Pointer to information about ini file
+ */
+PROINFO *
+SetPrivateProInfo(lpFile, Buffer)
+LPSTR lpFile;
+LPSTR Buffer;
+{
+ OFSTRUCT NewFileBuf;
+ char c;
+ char fQualified = 0;
+ char BASED_ON_LP(lpFile) *psrc;
+ int Count = 0;
+
+ /* Get rid of annoying warnings with this ugly cast */
+ psrc = (char BASED_ON_LP(lpFile)*)(WORD)(DWORD)lpFile;
+
+ /* For those who insist on using private routines for WIN.INI */
+ if ( lstrOriginal(lpFile, (LPSTR)WinIniStr) == 0
+ || lstrOriginal(lpFile, WinIniInfo.ProBuf.szPathName) == 0 ) {
+ return(&WinIniInfo);
+ }
+
+ /*
+ * Following code is from ForcePrivatePro
+ *
+ * If the filename given is not qualified, we force
+ * it into the windows directory.
+ */
+#ifdef DBCS
+_asm {
+ ;Apr.26,1990 by AkiraK
+ cld
+ push ds ;save kernel DS
+ xor ax,ax
+ mov bx,'/' shl 8 + '\\' ; '/' or '\'
+ xor dx,dx
+ lds si,lpFile ; first get length of string
+ mov cx,si
+ mov al,ds:[si]
+ call FarMyIsDBCSLeadByte
+ jnc fpp_s1
+ cmp byte ptr ds:[si+1],':' ;
+ jnz fpp_s1
+ inc dx
+fpp_s1:
+
+fpp_l1:
+ lodsb
+ or al,al
+ jz fpp_got_length
+ cmp al,bh
+ jz fpp_qualified
+ cmp al,bl
+ jz fpp_qualified
+fpp_s2:
+ call FarMyIsDBCSLeadByte
+ jc fpp_l1
+ inc si
+ jmp fpp_l1
+
+fpp_qualified:
+ inc dx
+ jmp fpp_s2
+fpp_got_length:
+;; mov fQualified, dx
+ mov fQualified, dl ; a byte variable
+ sub si, cx
+ mov Count, si
+ pop ds ;recover kernel DS
+}
+#else
+ /* Drive specified? */
+ if ( *(psrc+1) == ':' )
+ fQualified++;
+ while ( c = *psrc++ ) {
+ /* Look for path separators */
+ if ( c == '/' || c == '\\' )
+ fQualified++;
+ Count++;
+ }
+#endif
+
+ /*
+ * Now copy filename to buffer.
+ * Prepend Windows directory if not qualified.
+ */
+ _asm {
+ cld
+ push ds
+ les di, Buffer ; Destination is Buffer
+ cmp fQualified, 0
+ jnz Qualified
+ mov cx, cBytesWinDir ; Pick up Windows directory
+ lds si, lpWindowsDir
+ rep movsb ; Copy it
+ mov al, '\\'
+ cmp es:[di-1], al ; BUG FIX: if in root, don't
+ je Qualified ; add separator
+ stosb ; Add path separator
+ Qualified:
+ lds si, lpFile ; Now add Filename we were given
+ mov cx, Count
+ inc cx ; Allow for NULL
+ rep movsb
+ pop ds
+ }
+#ifdef NOTNOW
+ if ( !fBooting && fQualified ) {
+ /*
+ * Use OpenFile to generate pathname for
+ * comparison with the cached pathname.
+ * OF_EXIST ensures we get a complete pathname
+ * We cannot use OF_PARSE, it does not search the path.
+ * We only do this if the pathname we were given was
+ * qualified since in other cases we force the file
+ * into the windows directory and therefore know
+ * that Buffer contains the complete pathname.
+ */
+ NewFileBuf.szPathName[0] = 0;
+ OpenFile(Buffer, &NewFileBuf, OF_EXIST);
+ }
+#endif
+ /* Now see if the filename matches the cached filename */
+ _asm {
+ cld
+ xor cx, cx
+ lea si, word ptr [PrivateProInfo.ProBuf] ; Cached INI OFSTRUCT
+ mov cl, [si].cBytes
+ lea si, word ptr [si].szPathName ; Cached filename
+ sub cx, 8 ; Get its length
+ UseOriginal: ; Use the filename they gave us
+ les di, Buffer ; while booting
+ xor bl, bl
+ call strcmpi ; Ignore case while booting
+ jmp short DoWeDiscardIt
+ JustCompare:
+ ; Not booting, compare OFSTRUCTS
+ ; Note OpenFile forced upper case
+ push ss
+ pop es ; NewFileBuf is on SS
+ lea di, word ptr NewFileBuf.szPathName[0];
+ rep cmpsb ; Compare filenames
+ DoWeDiscardIt:
+ jz WeHaveItCached ; Don't discard if names match
+ }
+ /*
+ * The cached file is not the right one,
+ * so we discard the saved file.
+ */
+ FreeBuffer(&PrivateProInfo);
+
+WeHaveItCached:
+ /* Save pointer to FileName - buffer may have been discarded */
+ PrivateProInfo.lpProFile = Buffer;
+ return(&PrivateProInfo);
+}
+
+
+/*
+ * GetInt - search file and return an integer
+ *
+ * Parameters:
+ * pProInfo Pointer to information on the INI file
+ * lpSection Pointer to section to match in INI file
+ * lpKeyName Pointer to key string to match in file
+ * nDefault Default value to return if not found
+ *
+ * Returns:
+ * see GetProfileInt
+ */
+int
+GetInt(pProInfo, lpSection, lpKeyName, nDefault)
+PROINFO *pProInfo;
+LPSTR lpSection;
+LPSTR lpKeyName;
+int nDefault;
+{
+ LPSTR lpResult;
+
+ lpResult = FindString(pProInfo, lpSection, lpKeyName);
+ if (lpResult) {
+ /* We found a string, convert to int */
+ register int c;
+ int radix = 10;
+ BOOL fNeg = FALSE;
+
+ // Skip spaces
+ while (*lpResult == ' ' || *lpResult == '\t')
+ ++lpResult;
+
+ nDefault = 0;
+
+ while ((c = *lpResult++) != 0) {
+
+ // Watch for change in sign
+ //
+ if (c == '-') {
+ fNeg = !fNeg;
+ continue;
+ }
+
+ // Lower case the character if it's a letter.
+ //
+ if (c >= 'A' && c <= 'Z')
+ c += ('a' - 'A');
+
+ // deal with hex constants
+ //
+ if (c == 'x') {
+ radix = 16;
+ continue;
+ }
+
+ c -= '0';
+ if (c > 9)
+ c += '0' - 'a' + 10;
+
+ if (c < 0 || c >= radix)
+ break;
+
+ nDefault = nDefault * radix + c;
+ }
+ if (fNeg)
+ nDefault = -nDefault;
+ }
+ UnlockBuffer(pProInfo);
+ return(nDefault);
+}
+
+
+/*
+ * GetString - Search file for a specific Section and KeyName
+ *
+ * Parameters:
+ * pProInfo Pointer to information on the INI file
+ * lpSection Pointer to section to match in INI file
+ * lpKeyName Pointer to key string to match in file
+ * lpDefault Default string to return if not found
+ * lpResult String to fill in
+ * nSize Max number of characters to copy
+ *
+ * Returns:
+ * see GetProfileString
+ */
+GetString(pProInfo, lpSection, lpKeyName, lpDefault, lpResult, nSize)
+PROINFO *pProInfo;
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpDefault;
+LPSTR lpResult;
+int nSize;
+{
+ int nFound;
+ LPSTR lpFound;
+
+ if ( !lpKeyName ) {
+ nFound = GetSection(pProInfo, lpSection, lpResult, nSize);
+ if ( nFound == -1 )
+ goto CopyDefault; /* Yes, I know! */
+ } else {
+ lpFound = FindString(pProInfo, lpSection, lpKeyName);
+ if ( lpFound )
+ lpDefault = lpFound;
+ CopyDefault:
+ _asm {
+ xor ax, ax ; Return value
+ cmp word ptr lpDefault[2], 0 ; Check for null default
+ je SavedMe
+ les di, lpDefault
+ call MyStrlen ; Returns length in CX
+
+ ; Fix for #10907 -- Used to GP fault on zero length str.
+ or cx,cx ; No characters in string?
+ je strdone
+
+#ifdef DBCS
+ ; Get last character behind terminator
+ push si
+ les si, lpDefault ; SI = front of string
+ gps_dbcs_l1:
+ mov al, es:[si]
+ call FarMyIsDBCSLeadByte
+ cmc
+ adc si, 1
+ cmp si, di
+ jb gps_dbcs_l1
+ pop si
+#else
+ add di, cx
+ mov al, es:[di-1] ; Final character in string
+#endif
+ les di, lpDefault
+ cmp cx, 2 ; strlen > 2
+ jb strdone
+ ; Strip off single and double quotes
+ mov ah, es:[di]
+ cmp ah, al ; First character == last character?
+ jne strdone
+ cmp al, '\''
+ je strq
+ cmp al, '"'
+ jne strdone
+ strq:
+ sub cx, 2 ; Lose those quotes
+ inc di
+ strdone:
+ ; CX has length of string
+ mov dx, nSize
+ dec dx ; Allow for null
+ cmp cx, dx ; See if enough room
+ jbe HaveRoom
+ mov cx, dx
+ HaveRoom:
+ cld
+ push ds
+ push es
+ pop ds
+ mov si, di ; DS:SI has string to return
+ les di, lpResult
+ mov ax, cx ; Save length of string
+ rep movsb ; Copy the string
+ mov byte ptr es:[di], 0 ; Null terminate the string
+ pop ds
+ SavedMe:
+ mov nFound, ax ; We will return this
+ }
+ }
+
+ UnlockBuffer(pProInfo);
+ return(nFound);
+}
+
+
+/*
+ * GetSection - find a section and copy all KeyNames to lpResult
+ *
+ * Parameters:
+ * pProInfo pointer to info on the file
+ * lpSection pointer to the section name we want
+ * lpResult where the KeyNames will go
+ * nSize size of lpResult buffer
+ *
+ * Returns:
+ * int Number of characters copied, -1 for failure
+ */
+int
+GetSection(pProInfo, lpSection, lpResult, nSize)
+PROINFO *pProInfo;
+LPSTR lpSection;
+LPSTR lpResult;
+int nSize;
+{
+ LPSTR lp;
+
+ lp = BufferInit(pProInfo, READ);
+ if ( !lp )
+ return(-1); /* No buffer, (no file, no memory etc.) */
+
+ nSize--; /* Room for terminating NULL */
+
+ lp = FindSection(lp, lpSection);
+ if ( !lp )
+ return(-1);
+
+ _asm {
+ push ds
+ lds si, lpResult ; DS:SI is where we store the result
+ les di, lp ; ES:DI points to the section in buffer
+ xor dx, dx ; Count of characters in the result
+ KeyNameLoop:
+ mov bx, di ; Save start of line
+ cmp es:[di], ';' ; Is this a comment line?
+ jne KeyNameNextCh ; no, check this line out
+ cld
+ mov cx, -1
+ mov al, LINEFEED
+ repne scasb ; Skip to end of the line
+ jmp KeyNameLoop
+ KeyNameNextCh:
+ mov al, es:[di] ; Get next character
+#ifdef DBCS
+ call FarMyIsDBCSLeadByte
+ cmc ; if the char is lead byte of DBCS,
+ adc di, 1 ; then di += 2, else di += 1
+#else
+ inc di
+#endif
+ cmp al, '='
+ je FoundEquals
+ cmp al, LINEFEED
+ je KeyNameLoop ; Ignore lines without an '='
+ cmp al, SECT_LEFT
+ je EndSection ; Done if end of section
+ or al, al ; or if end of buffer (NULL)
+ jne KeyNameNextCh ; On to the next character
+ jmp EndSection
+ FoundEquals:
+ mov di, bx ; Back to the start of the line
+ CopyLoop:
+ mov al, es:[di] ; Pick up next character in line
+ inc di
+ cmp al, '=' ; Is it the '='?
+ jne LeaveItAlone
+ xor al, al ; yes, replace with NULL
+ LeaveItAlone:
+ mov [si], al ; Put it in the result string
+ inc dx ; Number of characters in the result
+ inc si
+ cmp dx, nSize ; Overflowed?
+ jb NoProblem
+ dec dx ; yes, ignore this character
+ dec si
+ NoProblem:
+#ifdef DBCS
+ call FarMyIsDBCSLeadByte
+ jc NoProblem1
+ mov al, es:[di]
+ inc di
+ mov [si], al
+ inc dx
+ inc si
+ cmp dx, nSize
+ jb NoProblem1
+ dec si
+ dec dx
+ NoProblem1:
+#endif
+ or al, al ; Was this the '='
+ jne CopyLoop
+ SkipLine:
+ mov al, es:[di] ; Skip the rest of the line
+ inc di
+ cmp al, LINEFEED
+ jne SkipLine
+ jmp KeyNameLoop
+
+ EndSection:
+ mov byte ptr [si], 0 ; Terminate with NULL
+ or dx, dx ; Did we copy anything?
+ jz NothingFound ; no, no hack
+#ifdef DBCS
+;AnsiPrev API has been moved to USER and it is not the
+;right time to invoke any USER's APIs as we might be called
+;while USER is still on the bed.
+; push dx
+; push word ptr lpResult[2]
+; push word ptr lpResult[0]
+; push ds
+; push si
+; call AnsiPrev
+; mov si, ax
+; mov byte ptr [si], 0
+; mov byte ptr [si+1], 0
+; pop dx
+;-----------------------------------------------------------
+ push es
+ push di
+ push bx
+ les di,lpResult ;string head
+ScanLoop:
+ mov bx,di ;"prev" char position
+ mov al,es:[di]
+ call FarMyIsDBCSLeadByte
+ cmc
+ adc di, 1 ;+2 if DBCS, +1 if not
+ cmp di,si ;have we hit the point yet?
+ jb ScanLoop ;nope,
+;The output of this routine looks like:
+;<name 1>,0,<name2>,0,.... <name n>,0,0
+; the very last 0 tells the end of story.
+ mov es:[bx],0 ;this is safe
+ mov es:[bx+1],0 ;Hmmmmm
+ pop bx
+ pop di
+ pop es
+#else
+ mov byte ptr [si-1], 0 ; Hack - if we hit nSize, we
+#endif
+ ; and extra NULL
+ NothingFound:
+ pop ds
+ mov nSize, dx
+ }
+ return(nSize);
+}
+
+
+/*
+ * FindString - look for section name and key name
+ *
+ * Parameters:
+ * pProInfo Pointer to info on the file
+ * lp Pointer to the buffer containing the file
+ * lpSection Pointer to the section name we are looking for
+ * lpKeyName Pointer the the KeyName we want
+ *
+ * Returns:
+ * LPSTR Pointer to the start of the result string
+ * NULL for failure
+ */
+LPSTR
+FindString(pProInfo, lpSection, lpKeyName)
+PROINFO *pProInfo;
+LPSTR lpSection;
+LPSTR lpKeyName;
+{
+ LPSTR lp;
+
+ if ( lp = BufferInit(pProInfo, READ) )
+ if ( lp = FindSection(lp, lpSection) )
+ lp = FindKey(lp, lpKeyName);
+ return(lp);
+}
+
+
+/*
+ * FindSection - look for a section name enclosed in '[' and ']'
+ *
+ * Parameters:
+ * lp Pointer to the buffer containing the file
+ * lpSection Pointer to the section name we are looking for
+ *
+ * Returns:
+ * LPSTR Pointer to the start of the section for success
+ * NULL for failure
+ */
+LPSTR
+FindSection(lp, lpSection)
+LPSTR lp;
+LPSTR lpSection;
+{
+ WORD wCount;
+ WORD wTrailCount;
+ WORD fLead;
+ LPSTR lpstr;
+ WORD wSegLen;
+
+ /* Remove leading whitespace from section names and compute
+ * a length count that doesn't include trailing whitespace.
+ * We use this below to force a TRUE compare even though
+ * the stupid program put garbage on the end.
+ */
+ for (lpstr = lpSection, fLead = 1, wCount = wTrailCount = 0 ;
+ *lpstr ; ++lpstr)
+ {
+ /* If we haven't passed leading space yet... */
+ if (fLead)
+ {
+ if (*lpstr == SPACE || *lpstr == TAB)
+ ++lpSection;
+ else
+ {
+ fLead = 0;
+ ++wCount;
+ ++wTrailCount;
+ }
+ }
+
+ /* Otherwise this might be trailing space... */
+ else
+ {
+ /* wCount always has correct count, wTrailCount
+ * never counts whitespace until another
+ * character is encountered. This allows
+ * a count of characters excluding trailing
+ * whitespace.
+ */
+ ++wCount;
+ if (*lpstr != SPACE && *lpstr != TAB)
+ wTrailCount = wCount;
+ }
+ }
+ wCount = wTrailCount;
+
+ _asm {
+ lsl cx,WORD PTR lp[2] ; Get max possible search len
+ mov wSegLen,cx ; Save for quick access later
+ push ds
+ les di, lp
+ SectionLoop:
+ cmp byte ptr es:[di], SECT_LEFT ; ie '['
+ jne NotThisLine
+ inc di ; Skip the '['
+
+ ;** Check the length of the string
+ push di ; Save because we're going to trash
+ mov cx,wSegLen ; Get segment length
+ sub cx,di ; Subtract off the distance into seg
+ mov dx,cx ; Save in DX
+ mov al,SECT_RIGHT ; Stop when we encouter this
+#ifdef DBCS
+;SECT_RIGHT is a legal DBCS second byte
+;and we have to emulate DBCS "repne scasb" here.
+ fsScanSectRight:
+ dec cx ;
+ jz fsScanFinish ; reach to end of segment
+ scasb ;
+ je fsScanFinish ; find it!
+ call FarMyIsDBCSLeadByte
+ jc fsScanSectRight
+ inc di ; skip DBCS 2nd byte
+ dec cx
+ jnz short fsScanSectRight
+ fsScanFinish:
+
+#else
+ repne scasb ; Compare until we find it
+#endif
+ sub dx,cx ; Get true string len
+ dec dx
+ pop di
+ cmp dx,wCount ; Same length?
+ jne NotThisLine
+
+ ;** Now compare the strings. Note that strcmpi returns a
+ ;** pointer just past the failed char
+ lds si, lpSection
+ mov bl, SECT_RIGHT ; Compare up to '['
+ call strcmpi
+ je HereItIs
+
+ ;** Even if we failed, it might match less trailing whitespace
+ sub ax,di ; Get length at first mismatch
+ cmp ax,wCount ; Make sure we mismatched at end
+ jne NotThisLine ; We didn't so get out
+ add di,ax ; Bump pointers to end
+ add si,ax
+ mov al,es:[di - 1] ; Compare last chars
+ cmp al,ds:[si - 1] ; Do they match?
+ jne NotThisLine ; Yes
+
+ HereItIs:
+ mov al, LINEFEED ; Skip the rest of the line
+ mov cx, -1
+ repne scasb ; Scans ES:[DI]
+
+ mov ax, di
+ mov dx, es ; Return pointer to section
+ jmp FoundIt
+
+ NotThisLine:
+ mov al, LINEFEED ; Skip the rest of the line
+ mov cx, -1 ; Scans ES:[DI]
+ repne scasb
+
+ cmp byte ptr es:[di], 0 ; End of the file?
+ jne SectionLoop ; nope, continue
+ xor ax, ax
+ xor dx, dx ; Return 0
+ FoundIt:
+ pop ds
+ }
+}
+
+
+/*
+ * FindKey - Find a KeyName given a pointer to the start of a section
+ *
+ * Parameters:
+ * lp Pointer to start of a section
+ * lpKeyName Pointer the the KeyName we want
+ *
+ * Returns:
+ * LPSTR Pointer to the string following the KeyName
+ * NULL if KeyName not found
+ */
+LPSTR
+FindKey(lp, lpKeyName)
+LPSTR lp;
+LPSTR lpKeyName;
+{
+ WORD wCount;
+ WORD wTrailCount;
+ WORD fLead;
+ LPSTR lpstr;
+ WORD wSegLen;
+
+ /* Remove leading whitespace from key names and compute
+ * a length count that doesn't include trailing whitespace.
+ * We use this below to force a TRUE compare even though
+ * the stupid program put garbage on the end.
+ */
+ for (lpstr = lpKeyName, fLead = 1, wCount = wTrailCount = 0 ;
+ *lpstr ; ++lpstr)
+ {
+ /* If we haven't passed leading space yet... */
+ if (fLead)
+ {
+ if (*lpstr == SPACE || *lpstr == TAB)
+ ++lpKeyName;
+ else
+ {
+ fLead = 0;
+ ++wCount;
+ ++wTrailCount;
+ }
+ }
+
+ /* Otherwise this might be trailing space... */
+ else
+ {
+ /* wCount always has correct count, wTrailCount
+ * never counts whitespace until another
+ * character is encountered. This allows
+ * a count of characters excluding trailing
+ * whitespace.
+ */
+ ++wCount;
+ if (*lpstr != SPACE && *lpstr != TAB)
+ wTrailCount = wCount;
+ }
+ }
+ wCount = wTrailCount;
+
+ _asm {
+ push ds
+ mov ax, word ptr lpKeyName
+ or ax, word ptr lpKeyName[2]
+ jz NoMatch ; Return zero if lpKeyName is 0
+ lsl cx,WORD PTR lp[2] ; Get max possible search len
+ mov wSegLen,cx ; Save for quick access later
+ les di, lp
+
+ ;** See if we're at the end of the section
+ FindKeyNext:
+ mov al,es:[di] ; Get next character
+ or al,al
+ jz NoMatch ; End of the file
+ cmp al,SECT_LEFT
+ je NoMatch ; End of the section
+ cmp al,CR ; Blank line?
+ je NotThisKey ; Yes, skip this one
+
+ ;** Check the length of the string
+ push di ; Save because we're going to trash
+ mov cx,wSegLen ; Get segment length
+ sub cx,di ; Subtract off the distance into seg
+ mov dx,cx ; Save in DX
+ mov al,'=' ; Stop when we encouter this
+ repne scasb ; Compare until we find it
+ sub dx,cx ; Get true string len
+ dec dx
+ pop di
+ cmp dx,wCount ; Same length?
+ jne NotThisKey
+
+ ;** Now compare the strings. Note that strcmpi returns a
+ ;** pointer just past the failed char.
+ mov bl,'=' ; Compare until we hit this
+ lds si,lpKeyName
+ call strcmpi
+ mov bx,di ; Save DI value for below
+ mov di,ax
+ je FoundKey
+
+ ;** Even if we failed, it might match less trailing whitespace
+ sub ax,bx ; Get length at first mismatch
+ cmp ax,wCount ; Make sure we mismatched at end
+ jne NotThisKey ; Lengths at mismatch must match
+ add bx,ax ; Bump pointers to end
+ add si,ax
+ mov al,es:[bx - 1] ; Get last char that should match
+ cmp al,ds:[si - 1] ; Does it match?
+ je FoundKey ; Yes
+
+ NotThisKey:
+ mov al, LINEFEED
+ mov cx, -1
+ repne scasb ; Scan to the end of the line
+ jmp FindKeyNext
+
+ NoMatch:
+ xor ax, ax
+ xor dx, dx
+ jmp AndReturn
+ FoundKey:
+ inc di ; Skip the '='
+ mov ax, di ; Return the pointer
+ mov dx, es
+ AndReturn:
+ pop ds
+ }
+}
+
+
+/*
+ * MyStrlen - returns length of a string excluding trailing spaces and CR
+ *
+ * Paremeters:
+ * ES:DI pointer to string
+ *
+ * Returns:
+ * CX number of characters in string
+ *
+ */
+int
+MyStrlen()
+{
+_asm {
+; SPACE, CR, NULL never in DBCS lead byte, so we are safe here
+ push ax
+ mov cx, di ; CX = start of string
+ dec di
+str1:
+ inc di
+ mov al, es:[di] ; Get next character
+ cmp al, CR
+ ja str1 ; Not CR or NULL
+str2:
+ cmp di, cx ; Back at the start?
+ jbe str3 ; yes
+ dec di ; Previous character
+ cmp byte ptr es:[di], SPACE
+ je str2 ; skip spaces
+ inc di ; Back to CR or NULL
+str3:
+ cmp es:[di], al
+ je maybe_in_code ; PMODE hack
+ mov es:[di], al ; Zap trailing spaces
+maybe_in_code:
+ neg cx ; Calculate length
+ add cx, di
+ pop ax
+ }
+}
+
+
+/*
+ * Cstrlen - returns length of a string excluding trailing spaces and CR
+ * This is a C callable interface to MyStrLen
+ *
+ * Paremeters:
+ * lp pointer to string
+ *
+ * Returns:
+ * number of characters in string
+ *
+ */
+int
+Cstrlen(lp)
+LPSTR lp;
+{
+_asm {
+ xor di, di ; Persuade compiler to save DI
+ les di, lp
+ call MyStrlen
+ mov ax, cx
+ }
+}
+
+
+/*
+ * strcmpi - internal case insensitive string compare
+ *
+ * Parameters:
+ * ES:DI & DS:SI Strings to be compared
+ * BL Character to terminate on
+ * DS:SI is null terminated
+ *
+ * Returns:
+ * ZF indicates strings equal
+ * AX pointer to next character in ES:DI string
+ * or failed character in case of mismatch
+ */
+void
+strcmpi()
+{
+_asm {
+#ifdef DBCS
+ ;Apr.26,1990 by AkiraK
+ ; Copied directly from USERPRO.ASM
+sti_l1:
+ mov al,es:[di]
+ cmp al,bl
+ jz sti_s1
+
+ call FarMyLower
+ mov cl,al
+
+ mov al,ds:[si]
+ call FarMyLower
+
+ inc si
+ inc di
+
+ cmp al,cl
+ jnz sti_exit
+
+ call FarMyIsDBCSLeadByte
+ jc sti_l1
+
+ mov al,es:[di]
+ cmp al,ds:[si]
+ jnz sti_exit
+
+ inc si
+ inc di
+ jmp short sti_l1
+
+sti_s1:
+ mov al,ds:[si]
+ or al,al
+sti_exit:
+ mov ax, di
+#else
+stci10:
+ mov al,es:[di] ; Get next character
+ cmp al,bl ; Character to terminate on?
+ jnz stci15 ; no, compare it
+ mov al,[si] ; yes, strings equal if at end
+ or al,al
+ jmp stciex
+stci15:
+ call FarMyLower ; Ensure both characters lower case
+ mov cl,[si]
+ xchg al,cl
+ call FarMyLower
+ inc si
+ inc di
+ cmp al,cl ; Still matching chars?
+ jz stci10 ; Yes, go try the next char.
+stciex:
+ mov ax,di ; Return pointer to next character
+#endif
+ }
+}
+
+
+/*
+ * BufferInit
+ *
+ * Parameters:
+ * pProInfo Pointer to structure describing an INI file
+ * OpenFlags READ_WRITE if we are writing to the file
+ *
+ * Returns:
+ * Pointer to start of buffer on success
+ * (LPSTR)0 Failure
+ *
+ * Open or create the INI file as necessary
+ * Get a buffer in memory for the file
+ * Read the INI file into the buffer
+ * Strip unwanted spaces comments and ^Zs from the buffer
+ */
+LPSTR _fastcall
+BufferInit(pProInfo, OpenFlags)
+PROINFO *pProInfo;
+int OpenFlags;
+{
+ LPSTR BufAddr;
+ long llen;
+ unsigned short len;
+ int fh;
+ int hNew;
+ BYTE byLastDrive; /* Cache last drive read from */
+
+ /* Ensure we have a handle for the buffer */
+ if ( pProInfo->hBuffer == 0 )
+ return(0L);
+ /* If the buffer is already filled, return */
+ if ( (BufAddr = LockBuffer(pProInfo)) != (LPSTR)NULL )
+ return(BufAddr);
+
+ pProInfo->ProFlags = 0;
+
+ /* Remember the last drive read from to see if we have to reread
+ * the cluster size.
+ */
+ byLastDrive = *pProInfo->ProBuf.szPathName;
+
+ if ( pProInfo == &PrivateProInfo ) {
+ /* Open a PRIVATE profile */
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ_WRITE+OF_SHARE_DENY_WRITE);
+ if ( fh == -1 ) {
+ /* Attempt to open for read. */
+ if ( !OpenFlags ){
+ pProInfo->ProFlags |= PROREADONLY;
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ+OF_SHARE_DENY_WRITE);
+ /* If this fails, try compatibility mode. */
+ if ( (fh == -1) && (pProInfo->ProBuf.nErrCode == SHARINGVIOLATION) ){
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, READ);
+ }
+ }else{
+ /* If the open failed and we are writing, silently create the file.
+ * If the open failed because of sharing violation, try compatibility mode instead.
+ */
+ if ( pProInfo->ProBuf.nErrCode != SHARINGVIOLATION ){
+ OpenFlags |= OF_CREATE;
+ }
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags);
+ }
+ }
+ } else {
+ /* Open WIN.INI */
+ if ( OpenFlags )
+ OpenFlags |= OF_CREATE;
+ if ( pProInfo->ProBuf.cBytes ) {
+ /* If previously found, reopen, don't create */
+ OpenFlags |= OF_REOPEN+OF_PROMPT|OF_CANCEL|OF_SHARE_DENY_WRITE;
+ OpenFlags &= ~OF_CREATE;
+ }
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags|READ_WRITE);
+ if ( (fh == -1) && !(OpenFlags & (READ_WRITE|OF_CREATE)) ) {
+ pProInfo->ProFlags |= PROREADONLY;
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags+OF_SHARE_DENY_WRITE);
+ }
+ /* Sharing violation. Let's try compatibility mode. */
+ if ( (fh == -1) && ( pProInfo->ProBuf.nErrCode == SHARINGVIOLATION ) ){
+ OpenFlags &= ~OF_SHARE_DENY_WRITE;
+ fh = OpenFile(pProInfo->lpProFile, &pProInfo->ProBuf, OpenFlags);
+ }
+ }
+ pProInfo->FileHandle = fh;
+
+ /* If we are using a different drive than the last call or this is
+ * the first time, clear cluster size so we reread it on next
+ * call to WriteString.
+ */
+ if (byLastDrive != *pProInfo->ProBuf.szPathName)
+ pProInfo->wClusterSize = 0;
+
+ if ( fh == -1 )
+ goto ReturnNull;
+
+ /* Seek to end of file, allow for CR, LF and NULL */
+ llen = _llseek(fh, 0L, 2);
+ if (!llen)
+ pProInfo->ProFlags |= PRO_CREATED;
+ llen += 3;
+ if ( llen > MAXBUFLEN )
+ llen = MAXBUFLEN; /* Limit to plenty less than 64k */
+
+ /* Now get a buffer */
+ hNew = IGlobalReAlloc(pProInfo->hBuffer, llen, GMEM_ZEROINIT);
+ if ( !hNew ) {
+ ReturnNull:
+ return( pProInfo->lpBuffer = (LPSTR)0 );
+ }
+
+ /* And now read in the file */
+ pProInfo->hBuffer = hNew;
+ LockBuffer(pProInfo);
+ _llseek(fh, 0L, 0); /* Seek to beginning of file */
+ *(int _far *)pProInfo->lpBuffer = 0x2020; /* Bogus spaces */
+
+ len = _lread(fh, pProInfo->lpBuffer, (short)llen-3);
+ if ( len == -1 ) {
+ UnlockBuffer(pProInfo);
+ return( FreeBuffer(pProInfo) );
+ }
+ if ( len < 2 )
+ len = 2; /* Prevent faults in PackBuffer */
+ return( PackBuffer(pProInfo, len, OpenFlags & READ_WRITE) );
+}
+
+
+/*
+ * LockBuffer - Lock the buffer containing the file. Make it
+ * moveable and non-discardable.
+ * Instead of locking the buffer, we're just going to make it
+ * non-discardable and moveable. This is preferable to locking it
+ * because all we really care about is that it doesn't get discarded.
+ *
+ * Parameter:
+ * pProInfo Pointer to info describing INI file
+ *
+ * Returns:
+ * LPSTR Pointer to buffer containing file
+ */
+LPSTR _fastcall
+LockBuffer(pProInfo)
+PROINFO *pProInfo;
+{
+ /* We only have to lock the block if it's marked dirty. Otherwise
+ * it's already unlocked.
+ */
+ if (!(pProInfo->ProFlags & PROUNCLEAN))
+ {
+ /* Make the block non-discardable */
+ IGlobalReAlloc(pProInfo->hBuffer, 0L,
+ GMEM_MODIFY + GMEM_MOVEABLE);
+
+ /* All we need here is to dereference the handle. Since
+ * this block is now non-discardable, this is all that
+ * IGlobalLock() really does.
+ */
+ pProInfo->lpBuffer = IGlobalLock(pProInfo->hBuffer);
+ IGlobalUnlock(pProInfo->hBuffer);
+ }
+
+ return pProInfo->lpBuffer;
+}
+
+
+/*
+ * UnlockBuffer - unlock the buffer, make it discardable and close the file.
+ * We don't really have to unlock the buffer (we weren't before anyway
+ * even though the comment says so)
+ *
+ * Parameter:
+ * pProInfo Pointer to info describing INI file
+ *
+ * Returns:
+ * nothing
+ */
+void _fastcall
+UnlockBuffer(pProInfo)
+PROINFO *pProInfo;
+{
+ int fh;
+
+ if (!(pProInfo->ProFlags & PROUNCLEAN))
+ IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_DISCARDABLE+GMEM_MODIFY);
+ fh = pProInfo->FileHandle;
+ pProInfo->FileHandle = -1;
+ if (fh != -1)
+ _lclose(fh);
+}
+
+
+/*
+ * FreeBuffer - discards the CONTENTS of a buffer containing an INI file
+ *
+ * Parameter:
+ * pProInfo Pointer to info describing INI file
+ *
+ * Returns:
+ * (LPSTR)0
+ */
+LPSTR _fastcall
+FreeBuffer(pProInfo)
+PROINFO *pProInfo;
+{
+ if ( pProInfo->ProFlags & PROUNCLEAN )
+ WriteOutProfiles();
+ /* Make the buffer discardable */
+ IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_DISCARDABLE+GMEM_MODIFY);
+
+ /* Make it zero length, shared, moveable and below the line */
+ IGlobalReAlloc(pProInfo->hBuffer, 0L, GMEM_MOVEABLE);
+
+ pProInfo->ProFlags = 0;
+ return( pProInfo->lpBuffer = (LPSTR)0 );
+}
+
+
+/*
+ * PackBuffer - strip blanks comments and ^Zs from an INI file
+ *
+ * Parameters:
+ * pProInfo Pointer to info describing INI file
+ * Count Number of characters in the buffer
+ * writing Flag indicating we are writing to the file
+ *
+ * Returns:
+ * LPSTR Pointer to the packed buffer
+ *
+ * NOTE: The use of Count here is DUMB. We should stick a NULL
+ * at the end, check for it and toss all the checks on Count.
+ */
+LPSTR _fastcall
+PackBuffer(pProInfo, Count, fKeepComments)
+PROINFO *pProInfo;
+int Count;
+int fKeepComments;
+{
+ LPSTR Buffer;
+ char BASED_ON_LP(Buffer) *psrc;
+ char BASED_ON_LP(Buffer) *pdst;
+ char BASED_ON_LP(Buffer) *LastValid;
+ char nextc;
+
+ Buffer = pProInfo->lpBuffer;
+ psrc = pdst = (char BASED_ON_LP(Buffer)*)(WORD)(DWORD)Buffer;
+
+ if ( WinFlags & WF_PMODE )
+ fKeepComments = 1;
+
+ if ( fKeepComments )
+ pProInfo->ProFlags |= PROCOMMENTS;
+
+ while ( Count ) {
+ /* Strip leading spaces and tabs */
+ nextc = *psrc;
+ if ( nextc == SPACE || nextc == TAB ) {
+/* TAB or SPACE never in lead byte of DBCS, so loop is safe */
+ Count--;
+ psrc++;
+ continue;
+ }
+
+ /* Process non-blanks */
+ LastValid = pdst;
+ do {
+ nextc = *psrc++;
+ Count--;
+ /* Strip comments if real mode and not writing */
+ if ( nextc == ';' && !fKeepComments ) {
+ while ( Count && nextc != LINEFEED ) {
+/* LINEFEED never in lead byte of DBCS, so loop is safe */
+ nextc = *psrc++;
+ Count--;
+ }
+ break;
+ }
+ /* Copy this character */
+ *pdst++ = nextc;
+#ifdef DBCS
+ if ( Count && CIsDBCSLeadByte(nextc) ) {
+ *pdst++ = *psrc++;
+ Count--;
+ }
+#endif
+ if ( nextc == '=' ) {
+ /* Skip preceeding spaces and tabs */
+ pdst = LastValid;
+ /* New home for the '=' */
+ *pdst++ = nextc;
+ /* Skip spaces and tabs again */
+ while ( Count ) {
+ nextc = *psrc;
+ if ( nextc != SPACE && nextc != TAB )
+ break;
+ Count--;
+ psrc++;
+ }
+ /* Copy remainder of line */
+ while ( Count ) {
+ Count--;
+/* LINEFEED never in lead byte of DBCS, so loop is safe */
+ if ( (*pdst++ = *psrc++) == LINEFEED )
+ break;
+ }
+ break;
+ }
+
+ /* End of file or line? */
+ if ( Count == 0 || nextc == LINEFEED )
+ break;
+
+ /* Strip trailing spaces */
+ if ( nextc == SPACE || nextc == TAB )
+ continue;
+
+ LastValid = pdst;
+ } while ( Count );
+ /* Here if end of line or file */
+ }
+ /* Here if end of file; skip trailing ^Zs */
+ for ( ; ; ) {
+ if ( pdst == Buffer )
+ break;
+ if ( *--pdst != CTRLZ ) {
+ pdst++;
+ break;
+ }
+ }
+
+ *pdst++ = CR;
+ *pdst++ = LINEFEED;
+ *pdst++ = 0;
+
+ IGlobalUnlock(pProInfo->hBuffer);
+ IGlobalReAlloc(pProInfo->hBuffer, (long)((LPSTR)pdst - Buffer), 0);
+ Buffer = LockBuffer(pProInfo);
+ pProInfo->BufferLen = (unsigned)pdst;
+ return(Buffer);
+}
+
+
+#ifdef DBCS
+/*
+ * C interface to FarMyIsDBCSLeadByte
+ *
+ * Parameter:
+ * c character to be tested
+ *
+ * Returns:
+ * 1 It is a lead byte
+ * 0 It isn't a lead byte
+ */
+CIsDBCSLeadByte(c)
+char c;
+{
+_asm {
+ mov al, c
+ call FarMyIsDBCSLeadByte
+ cmc ; Set carry if lead byte
+ mov ax, 0 ; Set return value to 0, preserve flags
+ adc al, 0 ; Set to one if carry set
+}
+}
+#endif
+
+
+/*
+ * WriteString
+ *
+ * Adds/deletes sections/lines in an INI file
+ *
+ * Parameters:
+ * pProInfo pointer to info on the file
+ * lpSection pointer to the section name we want
+ * lpKeyName key name to change or add
+ * NULL means delete section
+ * lpString string to add to file
+ * NULL means delete line
+ *
+ * Returns:
+ * bResult Success/Fail
+ */
+WriteString(pProInfo, lpSection, lpKeyName, lpString)
+PROINFO *pProInfo;
+LPSTR lpSection;
+LPSTR lpKeyName;
+LPSTR lpString;
+{
+ LPSTR ptrTmp;
+ short WhatIsMissing;
+ short nchars;
+ short fh;
+ long fp;
+ short SectLen = 0;
+ short KeyLen = 0;
+ short ResultLen = 0;
+ SEGMENT BufferSeg;
+ register char BASED_ON_SEG(BufferSeg) *bp;
+
+ /* Debugging noise */
+ /* Assert that we have something to do! */
+ if ( (SEGMENT)lpSection == NULL && (SEGMENT)lpKeyName == NULL
+ && (SEGMENT)lpString == NULL ) {
+ FreeBuffer(pProInfo); /* FEATURE! */
+ return(0);
+ }
+
+ /* If buffer does not already contain comments, free it */
+ if ( !(pProInfo->ProFlags & PROCOMMENTS) )
+ FreeBuffer(pProInfo);
+
+ /* Read the file into a buffer, preserving comments */
+ ptrTmp = BufferInit(pProInfo, READ_WRITE);
+ if ( !ptrTmp )
+ return(0);
+
+ /* Abort now if read only file */
+ if ( pProInfo->ProFlags & PROREADONLY )
+ goto GrodyError;
+
+ /* Set bp to point in buffer where we will add stuff */
+ BufferSeg = (SEGMENT)ptrTmp;
+ bp = pProInfo->BufferLen + (char BASED_ON_SEG(BufferSeg)*)
+ (WORD)(DWORD)ptrTmp - 1;
+
+ /*
+ * Now see what we have to do to the file by
+ * searching for section and keyname.
+ */
+ nchars = 0;
+
+ /* See if section exists */
+ if ( !(ptrTmp = FindSection(ptrTmp, lpSection)) ) {
+ /* No Section. If deleting anything, stop now */
+ if ( !lpKeyName || !lpString )
+ goto NothingToDo;
+ /* Need to add section and keyname */
+ WhatIsMissing = NOSECTION;
+ } else {
+ /* Found the section, save pointer to it */
+ bp = (char BASED_ON_SEG(BufferSeg)*)(WORD)(DWORD)ptrTmp;
+ /* If lpKeyName NULL, delete the section */
+ if ( !lpKeyName ) {
+ WhatIsMissing = REMOVESECTION;
+ } else {
+ /* Look for the keyname in the section */
+ if ( !(ptrTmp = FindKey(bp, lpKeyName)) ) {
+ /* No KeyName, stop if deleting it */
+ if ( !lpString )
+ goto NothingToDo;
+ WhatIsMissing = NOKEY;
+ /* Insert new keyname
+ at the end of the section */
+ while ( *bp && (*bp != SECT_LEFT || *(bp-1) != LINEFEED) )
+ bp++;
+ } else {
+ /* Found the keyname, save pointer */
+ bp = (char BASED_ON_SEG(BufferSeg)*)
+ (WORD)(DWORD)ptrTmp;
+ /* NULL lpString means delete it */
+ if ( !lpString )
+ WhatIsMissing = REMOVEKEY;
+ else {
+ /*
+ * Compare the existing string with the
+ * string we are supposed to replace it
+ * with. If they are the same, there
+ * is no need to rewrite the file, so
+ * we abort now.
+ */
+ if ( !IsItTheSame((LPSTR)bp, lpString) )
+ goto NothingToDo;
+
+ /*
+ * Count characters in old result.
+ * The file will be shrinking by
+ * this many characters.
+ */
+ while ( *bp++ != CR )
+ nchars--;
+ bp = (char BASED_ON_SEG(BufferSeg)*)
+ (WORD)(DWORD)ptrTmp;
+ WhatIsMissing = NEWRESULT;
+ }
+ }
+ }
+ }
+
+ /*
+ * If we will be adding to the file, grow the buffer
+ * to the size we will need, then make an appropriate
+ * sized hole in the buffer.
+ */
+ switch ( WhatIsMissing ) {
+
+ case NOSECTION:
+ /* Need to add section */
+ SectLen = Cstrlen(lpSection);
+ nchars = SectLen + 4; /* for []<CR><LF> */
+ /* Fall through for KeyName and result */
+
+ case NOKEY:
+ /* Need to add key name */
+ KeyLen = Cstrlen(lpKeyName);
+ nchars += KeyLen + 3; /* for =<CR><LF> */
+
+ /* For new key or section, skip back to previous line */
+ while ( bp > pProInfo->lpBuffer ) {
+ bp--;
+ if ( *bp != CR && *bp != LINEFEED )
+ break;
+ }
+ if ( bp != pProInfo->lpBuffer )
+ bp += 3;
+ /* Fall through for result */
+
+ /* If not at start of buffer, add room for extra CR/LF */
+ if ((WORD)bp && WhatIsMissing == NOSECTION)
+ nchars += 2;
+
+ case NEWRESULT:
+ /* Need to change/add result */
+ /* nchars may be -<current length of result> */
+ ResultLen = Cstrlen(lpString);
+ nchars += ResultLen;
+
+ /* Grow the buffer if necessary */
+ if ( nchars > 0 ) {
+ IGlobalUnlock(pProInfo->hBuffer);
+
+ fp = nchars + (long)pProInfo->BufferLen;
+ /* Ensure buffer will be plenty less than 64k */
+ /* and grow to new size */
+ if ( fp > MAXBUFLEN || !IGlobalReAlloc(pProInfo->hBuffer, fp, 0) ) {
+ /* Undo above Unlock */
+ IGlobalLock(pProInfo->hBuffer);
+ goto GrodyError;
+ }
+ pProInfo->lpBuffer = IGlobalLock(pProInfo->hBuffer);
+ BufferSeg = (SEGMENT)pProInfo->lpBuffer;
+ }
+
+ /* In order to fix bug #4672 and other ugly things
+ * that happen when we run out of disk space,
+ * we want to see if there is room to write the
+ * buffer. We know that the file can actually only
+ * grow on cluster boundaries, but rather than get
+ * the cluster size. If we don't have the cluster
+ * size yet, we have to get it from DOS.
+ */
+ if (!pProInfo->wClusterSize)
+ {
+ WORD wTemp;
+
+ /* Get drive letter */
+ wTemp = *pProInfo->ProBuf.szPathName - 'A' + 1;
+ _asm
+ {
+ mov ah,1ch ;Drive parameters
+ mov dl,BYTE PTR wTemp
+ push ds
+ int 21h
+ pop ds
+ cmp al,0ffh ;Error?
+ jnz DPOk ;No
+ mov al,1
+ mov cx,512 ;Default
+ DPOk: cbw ;Secs per cluster WORD
+ mul cx ;AX = bytes/cluster
+ mov wTemp,ax
+ }
+ if (!wTemp)
+ pProInfo->wClusterSize = 512;
+ else
+ pProInfo->wClusterSize = wTemp;
+ }
+
+ /* Now see if we're going past a cluster length */
+ if ((pProInfo->ProFlags & PRO_CREATED) ||
+ (((pProInfo->BufferLen + nchars) ^ pProInfo->BufferLen)
+ & ~(pProInfo->wClusterSize - 1)))
+ {
+ int fh;
+
+ /* Make sure that we only do this once for a newly-
+ * created file because this will handle the
+ * growing to one cluster case.
+ */
+ pProInfo->ProFlags &= ~PRO_CREATED;
+ fh = pProInfo->FileHandle;
+
+ /* Make sure the file is open and exists. If not,
+ * we have to open the file. We are guaranteed
+ * at least that the file exists in this case.
+ * Note that UnlockBuffer closes the file
+ * that we open here.
+ */
+ if (fh == -1)
+ {
+ fh = OpenFile(pProInfo->lpProFile,&pProInfo->ProBuf,OF_REOPEN+READ_WRITE+OF_SHARE_DENY_WRITE);
+ /* Sharing violation. Let's try compabitility mode. */
+ if ( (fh == -1) && (pProInfo->ProBuf.nErrCode == SHARINGVIOLATION ) ){
+ fh = OpenFile(pProInfo->lpProFile,&pProInfo->ProBuf,OF_REOPEN+READ_WRITE);
+ }
+ pProInfo->FileHandle = fh;
+ }
+
+ /* Try to grow the file to the right length */
+ if(_llseek(fh, pProInfo->BufferLen + nchars, 0) !=
+ pProInfo->BufferLen + nchars ||
+ _lwrite(fh, " ", 1) != 1)
+ goto GrodyError;
+ }
+
+ /* Now, make room in the buffer for this new stuff */
+ if ( nchars )
+ MakeRoom((LPSTR)bp, nchars, &pProInfo->BufferLen);
+
+ /* Now copy in the new info */
+ switch ( WhatIsMissing ) {
+ case NOSECTION:
+ /* Create the new section */
+ (int)bp = InsertSection((LPSTR)bp, lpSection, SectLen);
+ /* FALL THROUGH */
+
+ case NOKEY:
+ (int)bp = InsertKey((LPSTR)bp, lpKeyName, KeyLen);
+ /* FALL THROUGH */
+
+ case NEWRESULT:
+ (int) bp = InsertResult((LPSTR)bp, lpString, ResultLen);
+ }
+ break;
+
+ /* Handle deleting sections or KeyNames */
+ case REMOVESECTION:
+ DeleteSection((LPSTR)bp, pProInfo);
+ break;
+
+ case REMOVEKEY:
+ DeleteKey((LPSTR)bp, pProInfo);
+ break;
+ }
+
+ pProInfo->ProFlags |= PROUNCLEAN;
+ fProfileDirty = 1;
+
+NothingToDo:
+ UnlockBuffer(pProInfo);
+ return(1);
+
+ /* I really hate the GOTO, but in order to clean up, this is much
+ * more efficient...
+ */
+GrodyError:
+ UnlockBuffer(pProInfo);
+ return 0;
+}
+
+
+/*
+ * WriteOutProfiles
+ *
+ * Called on a task switch or at exit time
+ *
+ * If we have a dirty profile buffer, write it.
+ */
+void API
+WriteOutProfiles(void)
+{
+ LPSTR ptrTmp;
+ int fh;
+ PROINFO *pProInfo;
+ int nwritten;
+
+ /* Make sure that we don't get called through a DOS call. This
+ * flag is tested in I21ENTRY.ASM in the Int 21h hook to see
+ * if the profiles should be flushed.
+ */
+ ++fWriteOutProfilesReenter;
+
+ for ( pProInfo = &WinIniInfo; ; pProInfo = &PrivateProInfo ) {
+ if ( !(pProInfo->ProFlags & PROUNCLEAN) )
+ goto NoWrite;
+ if (
+/* Try read/write with sharing flags, then try compabitility mode, then try to create the sucker. */
+ ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | READ_WRITE | OF_SHARE_DENY_WRITE)) == -1)
+ && ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | READ_WRITE)) == -1)
+ && ( (fh = OpenFile(NULL, &pProInfo->ProBuf, OF_REOPEN | OF_CREATE)) == -1) ){
+ goto NoWrite;
+ }
+ pProInfo->FileHandle = fh;
+
+ /* Finally write the file */
+ ptrTmp = pProInfo->lpBuffer;
+ nwritten = _lwrite(fh, ptrTmp, pProInfo->BufferLen-3);
+ if ( nwritten == pProInfo->BufferLen-3 ) {
+ _lwrite(fh, ptrTmp, 0); /* Mark end of file */
+ pProInfo->ProFlags &= ~(PROUNCLEAN | PRO_CREATED);
+ UnlockBuffer(pProInfo);
+ } else {
+ _lclose(fh);
+ }
+ NoWrite:
+ if ( pProInfo == &PrivateProInfo )
+ break;
+ }
+ fProfileDirty = 0;
+
+ --fWriteOutProfilesReenter;
+}
+
+
+/*
+ * See if two character strings are the same.
+ * Special routine since one is terminated with <CR>.
+ * Returns zero if the strings match.
+ */
+IsItTheSame(CRstring, NullString)
+LPSTR CRstring;
+LPSTR NullString;
+{
+_asm {
+ push ds
+ les di, CRstring ; CR terminated string
+ lds si, NullString ; Null terminated string
+ xor ah, ah ; High byte of return value
+stci10:
+ mov al,es:[di] ; Get next character
+ cmp al,0Dh ; CR?
+ jnz stci15 ; no, compare it
+ mov al,[si] ; yes, strings equal if at end
+ jmp stciex
+stci15:
+ mov cl,[si]
+ inc si
+ inc di
+ cmp al,cl ; Still matching chars?
+ jz stci10 ; Yes, go try the next char.
+ mov al, 1 ; Didn't match
+stciex:
+ pop ds
+}
+}
+
+
+/*
+ * Create or close a hole in the buffer.
+ * Used to create room for a new section,
+ * keyname or result and to remove unwanted
+ * sections, keynames or results.
+ *
+ * Parameters:
+ * lp position in buffer to add/remove characters
+ * nchars number of characters to add/remove
+ * pAdjust pointer to variable containing current
+ * size of the buffer
+ *
+ * Side effects:
+ * *pAdjust is changed by nchars
+ *
+ * Returns:
+ * nothing
+ */
+MakeRoom(lp, nChars, pAdjust)
+LPSTR lp;
+short nChars;
+int *pAdjust;
+{
+ short BufLen = *pAdjust;
+
+ if ( nChars < 0 )
+ _asm {
+ push ds
+ les di, lp ; Where characters will be taken
+ push es
+ pop ds
+ mov si, di ; End of area
+ sub si, nChars ; Remember nChars is negative
+ mov cx, BufLen
+ sub cx, si ; Calculate # characters to move
+ cld
+ rep movsb ; Copy characters down
+ pop ds
+ } else _asm {
+ push ds
+ mov es, word ptr lp[2] ; Get segment to copy in
+ mov ds, word ptr lp[2]
+ mov si, BufLen ; We will be moving backwards
+ mov cx, si
+ dec si ; Adjust pointer for move
+ mov di, si ; so start at end of the buffer
+ sub cx, word ptr lp ; Number of characters to move
+ add di, nChars
+ std ; Backwards move
+ rep movsb ; Copy characters up
+ cld
+ pop ds
+ }
+ *pAdjust += nChars;
+}
+
+
+/*
+ * Delete a section from the buffer,
+ * preserving comments since they may
+ * relate to the next section
+ *
+ * Parameters:
+ * lp pointer to section returned by FindSection
+ * pProInfo pointer to INI file info
+ *
+ * Returns:
+ * nothing
+ */
+DeleteSection(lp, pProInfo)
+LPSTR lp;
+PROINFO *pProInfo;
+{
+ int nRemoved;
+ char BASED_ON_LP(lp) *SectEnd;
+
+ _asm {
+ cld
+ push ds
+ lds si, lp
+ BackToStart:
+ dec si ; Skip backwards to start of the section
+ cmp ds:[si], SECT_LEFT
+ jne BackToStart
+
+ mov di, si
+ push ds
+ pop es ; ES:DI points to start of section
+ inc si ; DS:SI points to the '[', skip it
+ RemoveLoop:
+ lodsb ; Get next character in section
+ cmp al, ';' ; Is it a comment
+ jne NotComment
+
+ CopyComment:
+ stosb ; Save this character
+ cmp al, LINEFEED ; Copy to end of the line
+ je RemoveLoop
+ lodsb ; And get the next one
+ jmp CopyComment
+
+ NotComment:
+ cmp al, SECT_LEFT ; So is it the next section?
+ je EndSection
+ or al, al ; or the end of the buffer?
+ jne SkipLine
+ sub si, 2 ; Extra CR & LF at end of buffer
+ jmp short EndSection
+
+ SkipLine:
+ cmp al, LINEFEED ; Nothing interesting, so skip line
+ je RemoveLoop
+ lodsb
+ jmp SkipLine
+
+ EndSection:
+ dec si ; Back to the character
+ mov SectEnd, si ; where the search stopped
+ mov word ptr lp, di ; End of copied comments (if any)
+ sub si, di
+ mov nRemoved, si ; Number of characters removed
+ pop ds
+ }
+
+ MakeRoom(lp, -nRemoved, &pProInfo->BufferLen);
+}
+
+
+/*
+ * Delete a keyname from the buffer
+ *
+ * Parameters:
+ * lp pointer to keyname returned by FindKey
+ * pProInfo pointer to INI file info
+ *
+ * Returns:
+ * nothing
+ */
+DeleteKey(lp, pProInfo)
+LPSTR lp;
+PROINFO *pProInfo;
+{
+ int nRemoved;
+ char BASED_ON_LP(lp) *KeyEnd;
+
+ _asm {
+ cld
+ les di, lp
+ BackToStart:
+ dec di ; Skip backwards to start of the line
+ cmp es:[di], LINEFEED
+ jne BackToStart
+ inc di
+ mov word ptr lp, di ; Save start of the line
+
+ mov cx, -1
+ mov al, LINEFEED
+ repne scasb ; Scan to end of the line
+ sub di, word ptr lp
+ mov nRemoved, di ; Length of line
+ }
+ MakeRoom(lp, -nRemoved, &pProInfo->BufferLen);
+}
+
+
+/*
+ * Insert a new section in the buffer.
+ * A hole has already been created for it.
+ * This merely copies the string, places
+ * '[]'s around it and a CR, LF after it.
+ * Returns a pointer to immediately
+ * after the section header in the buffer.
+ *
+ * Parameters:
+ * lpDest pointer to where to add the section
+ * lpSrc pointer to the section name
+ * count length of lpSrc
+ */
+InsertSection(lpDest, lpSrc, count)
+LPSTR lpDest;
+LPSTR lpSrc;
+short count;
+{
+_asm {
+ cld
+ push ds
+ les di, lpDest
+ lds si, lpSrc
+ or di,di ; If at start of buffer, no prefix
+ jz IS_SkipPrefix
+ mov ax, LINEFEED SHL 8 + CR ; Prefix with CR/LF
+ stosw
+IS_SkipPrefix:
+ mov al, SECT_LEFT ; '[' first
+ stosb
+ mov cx, count ; Now the section name
+ rep movsb
+ mov al, SECT_RIGHT ; and the ']'
+ stosb
+ mov ax, LINEFEED SHL 8 + CR ; finally, CR, LF
+ stosw
+ pop ds
+ mov ax, di ; Return pointer to char after header
+}
+}
+
+
+/*
+ * Insert a new keyname in the buffer.
+ * This copies the keyname and adds
+ * an '='. It is assumed that InsertResult()
+ * will terminate the line.
+ * A pointer to the buffer immediately after
+ * the '=' is returned.
+ *
+ * Parameters:
+ * lpDest pointer to where to add the keyname
+ * lpSrc pointer to the keyname
+ * count length of lpSrc
+ */
+InsertKey(lpDest, lpSrc, count)
+LPSTR lpDest;
+LPSTR lpSrc;
+short count;
+{
+_asm {
+ cld
+ push ds
+ les di, lpDest
+ lds si, lpSrc
+ mov cx, count ; Copy the KeyName
+ rep movsb
+ mov al, '=' ; add the '='
+ stosb
+ mov ax, di ; Pointer to char after the '='
+ pop ds
+}
+}
+
+
+/*
+ * Add a new result string to the buffer.
+ * It assumes that the keyname and '=' are
+ * already there. This routine may be
+ * overwriting an existing result. The result
+ * is terminated with a CR, LR.
+ *
+ * Parameters:
+ * lpDest pointer to where to add the result
+ * lpSrc pointer to the result
+ * count length of lpSrc
+ */
+InsertResult(lpDest, lpSrc, count)
+LPSTR lpDest;
+LPSTR lpSrc;
+short count;
+{
+_asm {
+ cld
+ push ds
+ les di, lpDest
+ lds si, lpSrc
+ mov cx, count ; Copy the result
+ rep movsb
+ mov ax, LINEFEED SHL 8 + CR ; finally, CR, LF
+ stosw ; This may overwrite existing CR, LF
+ mov ax, di
+ pop ds
+}
+}
+
+/*
+ * GetFileAttr
+ *
+ * DOS call to Get file attributes
+GetFileAttr(szFile)
+LPSTR szFile;
+{
+_asm {
+ int 3
+ xor cx, cx ; In case of failure
+ lds dx, szFile
+ mov ax, 4300h
+ int 21h
+ mov ax, cx
+}
+}
+*/
diff --git a/private/mvdm/wow16/kernel31/userpro.asm b/private/mvdm/wow16/kernel31/userpro.asm
new file mode 100644
index 000000000..f9d375edc
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/userpro.asm
@@ -0,0 +1,1872 @@
+ TITLE USERPRO - interface to WIN.INI file
+
+include kernel.inc
+include pdb.inc
+
+externFP GlobalFree
+externFP GlobalAlloc
+externFP GlobalLock
+externFP GlobalUnlock
+externFP GlobalReAlloc
+externFP GlobalSize
+externFP OpenFile
+externFP FarMyLower
+;externFP _lopen
+externFP _lcreat
+externFP _lclose
+externFP _lread
+externFP _lwrite
+externFP _llseek
+
+ifdef DBCS ;Apr.26,1990 by AkiraK
+externFP AnsiPrev
+externFP FarMyIsDBCSLeadByte
+endif
+
+ifdef WOW
+externFP FarMyUpper
+endif
+
+DataBegin
+
+ifndef WOW
+externB szUserPro
+endif
+externB fBooting
+externW cBytesWinDir
+externD lpWindowsDir
+ifndef WOW
+externW cBytesSysDir
+externD lpSystemDir
+else
+externW cBytesSys16Dir
+externD lpSystem16Dir
+endif
+if 0
+externB fUserPro
+externB UserProBuf
+externB PrivateProBuf
+externW hBuffer
+ifndef PHILISAWEENIE
+externW hWBuffer
+externW hPBuffer
+endif
+externW hFile
+externD BufAddr
+externD lpszUserPro
+endif
+externW TopPDB
+;externW MyCSDS
+
+LeftSect DB '['
+; these next two must stay together
+RightSect DB ']'
+CarRetLF DB 13,10
+EquStr DB '='
+
+DataEnd
+
+sBegin MISCCODE
+assumes CS,MISCCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP MISCMapDStoDATA
+
+; WOW thunks most of these APIs.
+ifndef WOW
+
+SECT_LEFT equ byte ptr '['
+SECT_RIGHT equ byte ptr ']'
+CARRETURN equ byte ptr 13
+LINEFEED equ byte ptr 10
+SPACE equ byte ptr ' '
+TAB equ byte ptr 09
+CRLF equ 0A0Dh
+NEWRESULT equ 1
+NOSECTION equ 2
+NOKEY equ 4
+REMOVESECTION equ 5
+REMOVEKEY equ 6
+
+PROUNKN EQU 0 ; Profile unknown
+PROWININI EQU 1 ; Profile WIN.INI
+PROPRIVATE EQU 2 ; Profile specified by app
+PROWASPRIVATE EQU 3 ; Buffer contains private profile data
+
+ScanTo MACRO StopAt
+ mov al, StopAt
+ mov cx, -1
+ repne scasb
+ENDM
+
+ScanBack MACRO StopAt
+ std
+ mov al, StopAt
+ mov cx, di
+ inc cx
+ repne scasb
+ inc di ; Leave pointing to StopAt
+ cld
+ENDM
+
+
+;-----------------------------------------------------------------------;
+; SetDefaultPro ;
+; ;
+; Set lpszUserPro to point to WIN.INI if it is not already set ;
+; to point to a private file ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,code
+ assumes es,nothing
+
+cProc SetDefaultPro,<PUBLIC,NEAR>
+cBegin nogen
+ cmp fUserPro, PROWASPRIVATE
+ je SDF_SetIt
+ cmp fUserPro, PROUNKN ; No file specified
+ jne SDF_Done
+SDF_SetIt:
+ mov ax, dataOffset szUserPro
+ mov word ptr [lpszUserPro], ax
+ mov word ptr [lpszUserPro+2], ds
+ mov fUserPro, PROWININI
+ifndef PHILISAWEENIE
+ mov si,[hWBuffer]
+ mov [hBuffer],si
+else
+ mov si,[hBuffer]
+ call FreeBuffer ; free up any buffer we may have
+endif
+SDF_Done:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; SetPrivatePro ;
+; ;
+; Sets lpszUserPro to point to a private file ;
+; ;
+; Arguments: ;
+; parmD lpFile ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,code
+ assumes es,nothing
+
+cProc SetPrivatePro,<PUBLIC,NEAR>,<di>
+ parmD lpszProfile
+ localV NewFileBuf, 80h
+cBegin
+ifndef PHILISAWEENIE
+ mov si, [hPBuffer]
+ mov [hBuffer], si
+else
+ cmp fUserPro, PROWASPRIVATE
+ jne SPP_SetIt
+endif
+ les di,lpszProfile
+ test fBooting,1
+ jnz spr_booting
+ smov es, ss
+ lea di, NewFileBuf
+ mov byte ptr es:[di.opFile], 0 ; Zap junk on stack
+ mov ax,OF_EXIST ; OF_EXIST searches path!
+ cCall OpenFile,<lpszProfile,es,di,ax>
+ lea di, [di.opFile]
+spr_booting:
+ lea si, [PrivateProBuf]
+ xor cx, cx
+ mov cl, [si.opLen]
+ lea si, [si.opFile]
+ sub cx, 8
+ cld
+ifndef PHILISAWEENIE
+ test fBooting, 1
+ jz @F
+ xor bl, bl ; Terminate on null
+ call strcmpi
+ je SPP_KeepBuffer
+ jmps SPP_SetIt
+@@:
+endif
+ rep cmpsb
+ je SPP_KeepBuffer
+SPP_SetIt:
+ mov si,[hBuffer]
+ call FreeBuffer ; free up any buffer we may have
+SPP_KeepBuffer:
+ mov fUserPro, PROPRIVATE
+ mov ax, lpszProfile.off
+ mov [lpszUserPro].off, ax
+ mov ax, lpszProfile.sel
+ mov [lpszUserPro].sel, ax
+cEnd
+
+;-----------------------------------------------------------------------;
+; ResetPrivatePro ;
+; ;
+; Sets lpszUserPro to point to nothing ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,code
+ assumes es,nothing
+
+cProc ResetPrivatePro,<PUBLIC,NEAR>
+cBegin nogen
+ mov fUserPro, PROWASPRIVATE
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; GetProfileInt ;
+; ;
+; Gets the integer value for the keyword field. ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmW nDefault ;
+; ;
+; Returns: ;
+; AX = nKeyValue ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 04:32:04p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetProfileInt,<PUBLIC,FAR>,<si,di>
+ parmD section
+ parmD keyword
+ parmW defint
+cBegin
+ cCall MISCMapDStoDATA ; point at data segment
+ ReSetKernelDS
+
+ cCall SetDefaultPro
+
+ cCall GetString, <section,keyword>
+
+; DX:AX contains pointer to return string
+; CX is the length of the string, -1 if none
+
+ mov si,ax ; save pointer offset
+ mov ax,defint ; if so, return default integer
+ cmp cx,-1 ; was there no string?
+ jz intdone ; if none, use default
+ push ds ; save DS
+ mov ds,dx ; DS:SI has string
+
+; AtoI function, CX has count of characters, AX is result, DS:SI is string.
+
+ xor ax,ax
+AtoI: mov dx,10
+ mov bl,[si]
+ sub bl,'0'
+ jc AtoIDone
+ cmp bl,10
+ jnc AtoIDone
+ inc si
+ mul dx
+ xor bh,bh
+ add ax,bx
+ loop AtoI
+AtoIdone:
+ pop ds ; restore DS
+intdone:
+ push ax
+ call UnlockBuffer
+ pop ax ; get result to return
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GetProfileString ;
+; ;
+; Returns the string for the keyword field. ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmD lpDefault ;
+; parmD lpReturnedString ;
+; parmW nSize ;
+; ;
+; Returns: ;
+; AX = nLength ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 04:45:20p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetProfileString,<PUBLIC,FAR>,<si,di>
+ parmD section
+ parmD keyword
+ parmD defString
+ parmD resString
+ parmW cchMax
+cBegin
+ cCall MISCMapDStoDATA ; point at data segment
+ ReSetKernelDS
+
+ cCall SetDefaultPro
+
+if KDEBUG
+ mov dx, off_defString
+ or dx, seg_defString ; Catch those NULL pointers
+ jnz ok_def
+ mkerror ERR_BADDEFAULT,<GetProfileString: NULL lpDefault>,dx,dx
+ok_def:
+endif
+ mov ax,off_keyword
+ mov dx,seg_keyword
+ or ax,dx
+ jnz GPS_Normal
+ cCall GetKeys,<section,resString,cchMax>
+
+; Carry if the section not found, AX has length of "string".
+
+ jnc GPS_End
+ jmps GPS_DefString
+
+GPS_Normal:
+ cCall GetString,<section,keyword>
+
+; DX:AX contains pointer to return string
+; CX has length, -1 if string not found
+
+ cmp cx,-1 ; see if there is any string
+ jz GPS_DefString
+ mov SEG_defstring,dx
+ mov OFF_defstring,ax
+GPS_DefString:
+ xor ax, ax ; Stupid bug fixed.
+ cmp SEG_defstring, 0
+ je GPS_End ; Save us from the GP fault
+ les di,defString ; DI = front of string
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ call strlen ; CX = strlen, di = end of string
+ ;get last character behind terminater
+ push si
+ les si,defString ; SI = front of string
+gps_dbcs_l1:
+ mov al,es:[si]
+ call FarMyIsDBCSLeadByte
+ cmc
+ adc si,1
+ cmp si,di
+ jb gps_dbcs_l1
+ pop si
+else
+ call strlen ; CX = strlen, di = end of string
+ mov al,es:[di-1] ; AL = last character of string
+endif
+ les di,defString ; DI = front of string
+
+ ; Strip off single and double quotes
+ cmp cx,2 ; strlen < 2?
+ jb strdone ; yes, skip
+ mov ah,es:[di] ; AH = first character in the string
+ cmp ah,al ; first char = last char?
+ jnz strdone ; if no match, then no quotes
+ cmp al,"'"
+ jz strq
+ cmp al,'"'
+ jnz strdone
+strq: sub cx,2 ; string is really two smaller
+ inc di ; and starts here
+strdone:
+
+; CX now has length of return string, use it for copying.
+
+ mov dx,cchMax
+ dec dx
+ cmp cx,dx
+ jbe GPS1
+ mov cx,dx
+GPS1:
+ push ds ; save DS
+ push es
+ pop ds
+ mov si,di ; ds:si has string
+ push cx ; save length for return
+ les di,ResString
+ rep movsb ; copy string
+ mov byte ptr es:[di], 0 ; null terminate
+ pop ax
+ pop ds ; restore DS
+GPS_End:
+ push ax
+ call UnlockBuffer
+ pop ax ; get length of returned string
+cEnd
+
+cProc GetKeys,<PUBLIC,NEAR>,<si,di,ds>
+ parmD section
+ parmD resstr
+ parmW cchMax
+cBegin
+
+ xor di,di ; make sure buffer is ready
+ call BufferInit
+
+; DX:AX has buffer address, NULL if it didn't work.
+
+ mov di,ax ; save offset
+ or ax,dx ; see if no address
+ifdef DBCS
+ jnz skip1
+ jmp GetKeysNone ; if no address, done
+skip1:
+else
+ jz GetKeysNone ; if no address, done
+endif
+ dec cchMax ; Leave room for terminating null byte
+ mov es,dx
+
+ cCall FindSection, <section>
+ jc GetKeysNone
+
+ lds si,resstr
+ xor dx,dx
+GK3: ; Key name loop
+ mov bx,di
+GK3a:
+ mov al,es:[di]
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ call FarMyIsDBCSLeadByte
+ cmc ;if the char is lead byte of DBCS,
+ adc di,1 ; then di += 2 else di += 1
+else
+ inc di
+endif
+ cmp al,'='
+ je GK3c
+ cmp al,LINEFEED ; Ignore lines without =
+ je GK3
+ cmp al,SECT_LEFT ; Done if it's a section header
+ je GK4
+ or al,al ; or null.
+ jnz GK3a
+ jmps GK4
+GK3c:
+ mov di,bx
+GK3d:
+ mov al,es:[di]
+ inc di
+ cmp al,'='
+ jne GK3e
+ xor al,al
+GK3e:
+ mov [si],al
+ inc dx
+ inc si
+ cmp dx,cchMax
+ jb GK3f
+ dec si
+ dec dx
+GK3f:
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ call FarMyIsDBCSLeadByte
+ jc GK3_s1
+ mov al,es:[di]
+ inc di
+
+ mov [si],al
+ inc dx
+ inc si
+ cmp dx,cchMax
+ jb GK3f2
+ dec si
+ dec dx
+GK3f2:
+
+GK3_s1:
+endif
+ or al,al
+ jnz GK3d
+ ScanTo LINEFEED
+ jmp GK3
+
+GetKeysNone:
+ stc
+ jmps GetKeysDone
+
+GK4:
+ mov byte ptr [si], 0 ; Terminating null
+ or dx, dx ; No extra zapping if nothing found
+ jz GK4x
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ push dx
+
+ cCall AnsiPrev,<resstr,ds,si>
+ mov si,ax
+ mov byte ptr [si], 0
+ mov byte ptr [si+1], 0
+
+ pop dx
+else
+ mov byte ptr [si-1], 0 ; [si-1] already zero unless we hit
+ ; cchMax above in which case, we must
+ ; zap the previous character.
+endif
+GK4x:
+ mov ax,dx
+ clc
+
+GetKeysDone:
+cEnd
+
+
+; Scan through buffer, looking for section.
+
+cProc FindSection, <PUBLIC, NEAR>
+ parmD section
+cBegin
+
+SS1:
+ cmp byte ptr es:[di],SECT_LEFT ; see if it's a section header
+ jne SS2
+ inc di
+ lds si,section
+ mov bl,SECT_RIGHT
+ call strcmpi ; case insensitive compare
+ je SSfound ; terminate on SECT_RIGHT
+SS2:
+ ScanTo LINEFEED
+ cmp byte ptr es:[di], 0
+ jne SS1
+
+; If it gets here, there wasn't a match.
+
+ stc ; Fail
+ jmps SSdone
+
+SSfound:
+ ScanTo LINEFEED ; read to beginning of first keyline
+ clc ; Success
+
+SSdone:
+cEnd
+
+cProc FindKey, <PUBLIC, NEAR>
+ parmD keyword
+cBegin
+
+ mov ax, SEG_keyword
+ or ax, OFF_keyword ; Do we have something to look for?
+ jz FK_NoMatch
+FK_Next:
+ mov al,es:[di]
+ or al,al
+ jz FK_NoMatch
+ cmp al,SECT_LEFT
+ jz FK_NoMatch
+
+ lds si,keyword
+ mov bl,'=' ; term on =.
+ call strcmpi ; case insensitive compare, term on 0
+ je FK_Found ; es:di has result string
+
+ ScanTo LINEFEED
+ jmp FK_Next
+
+FK_NoMatch:
+ stc
+ jmps FK_Done
+FK_Found:
+ clc
+FK_Done:
+
+cEnd
+
+cProc GetString,<PUBLIC,NEAR>,<si,di,ds>
+ parmD section
+ parmD key
+cBegin
+ xor di,di ; make sure buffer is ready
+ call BufferInit
+
+; DX:AX has buffer address, NULL if it didn't work.
+
+ mov di,ax ; save offset
+ or ax,dx ; see if no address
+ jz NoMatch ; no address, nothing to match against
+
+ mov es,dx
+
+; DX:DI now has the buffer address, buffer is locked down.
+
+ cCall FindSection, <section> ; Look for the section
+ jc NoMatch
+ cCall FindKey, <key>
+ jnc HaveKey
+
+NoMatch:
+ mov cx,-1 ; string was not found
+ jmps GetStrDone
+
+; if it gets here, it matched
+
+HaveKey:
+ inc di ; pointing at =
+ mov dx,es
+ mov bx,di
+ ScanTo CARRETURN ; traverse string until reach end
+ inc cx
+ inc cx
+ neg cx ; will now contain string length
+ mov ax,bx
+GetStrDone:
+cEnd
+
+; make sure the buffer has been filled
+
+
+ public BufferInit ; this is for the debugger
+BufferInit:
+assumes DS,CODE
+ mov ax,[hBuffer]
+ or ax,ax
+ jnz bf0
+ xor dx,dx
+ ret
+bf0:
+ call LockBuffer
+ mov bx,ax
+ or bx,dx
+ jz bf1
+ ret
+bf1:
+ mov bx,GA_MODIFY ; make block not discardable
+ cCall GlobalReAlloc,<hBuffer,ax,ax,bx>
+ mov ax,di
+ les dx, lpszUserPro
+ cmp fUserPro, PROPRIVATE
+ jne bf1a1
+ mov bx,codeOffset PrivateProBuf ; Private ie not WIN.INI
+ cCall OpenFile,<es,dx,dsbx,ax>
+ cmp ax, -1 ; File not found?
+ jne bf1a2
+ or di, di
+ jz bf1a2 ; Don't create if we want to read it.
+ mov ax, di
+ or ax, OF_CREATE ; Writing it, create it silently.
+ les dx, lpszUserPro
+ mov bx,codeOffset PrivateProBuf
+ jmps bf1a
+bf1a1:
+ or di,di
+ jz bf1a0
+ or ax,OF_CREATE
+bf1a0:
+ mov bx,codeOffset UserProBuf
+ cmp byte ptr [bx],0
+ jz bf1a
+ mov dx,dataOffset szUserPro
+ and ax,NOT OF_CREATE
+ or ax,OF_REOPEN or OF_PROMPT
+bf1a:
+ cCall OpenFile,<es,dx,dsbx,ax>
+bf1a2:
+ mov [hFile],ax
+ inc ax
+ jnz @F
+ jmp bf3 ; if file not found, return 0:0
+@@: mov ax,0002h
+ call Rewind2 ; seek to end of file
+ add ax,3 ; tack on room for cr,lf and 0
+ adc dx,0
+ jz bf1aa ; ok if less than 64k
+ mov ax, -1 ; Limit memory used
+ xor dx, dx
+bf1aa:
+ push ax ; Length to read
+ mov bx,GA_ZEROINIT
+ regptr LONGINT,DX,AX
+ cCall GlobalReAlloc,<hBuffer,LONGINT,bx> ; global block
+ pop bx ; Stand on our head to preserve length
+ or ax,ax
+ jz bf3
+ mov hBuffer, ax
+ push bx
+ call LockBuffer
+ call Rewind ; rewind to beginning of file
+ les bx,[BufAddr]
+ mov es:[bx],2020h ; space space
+ pop cx ; read in the whole file
+ sub cx, 3 ; don't fill extra space in the buffer
+ jcxz bf1zz ; Don't bother if nothing to read
+ cCall _lread,<hFile,esbx,cx>
+ inc ax
+ jz bf2
+ dec ax
+ mov cx,ax ; cx has file size
+bf1zz:
+ cmp cx,2
+ jae bf1z
+ mov cx,2
+bf1z:
+ jmps PackBuffer
+bf2: call UnlockBuffer
+FreeBuffer:
+ xor ax,ax
+ mov dx,GA_DISCARDABLE shl 8 OR GA_MODIFY
+ cCall GlobalReAlloc,<si,ax,ax,dx>
+ xor ax,ax
+ mov dx,(GA_SHAREABLE) shl 8 OR GA_MOVEABLE
+ cCall GlobalReAlloc,<si,ax,ax,dx>
+
+bf3: xor ax,ax
+ xor dx,dx
+ mov word ptr [BufAddr][0],ax
+ mov word ptr [BufAddr][2],dx
+ ret
+
+ public packbuffer
+PackBuffer:
+ push ds
+ mov dx,di
+ les di,[BufAddr]
+ lds si,[BufAddr]
+
+pb1:
+ifdef DBCS ;Apr.26,1990 by AkiraK
+;TAB or SPACE are never found in lead byte of DBCS.
+;so, this loop is safe in DBCS.
+endif
+ jcxz pb9 ; while leading space or tab
+ mov bx, di ; Initialize first valid character
+
+ lodsb
+ dec cx
+ cmp al, SPACE ; remove leading spaces
+ jz pb1
+ cmp al, TAB ; and tabs
+ jz pb1
+
+ dec si ; refetch last character
+ inc cx
+pb2:
+ lodsb
+ dec cx
+ or dx,dx ; Are we writing?
+ jnz pb20 ; Yes, leave comments in
+ cmp al,';' ; No, is this a comment?
+ jne pb20 ; No, continue
+ jcxz pb9 ; if done
+pb2loop:
+ifdef DBCS ;Apr.26,1990 by AkiraK
+;LINEFEED is never found in lead byte of DBCS.
+;so, this loop is safe in DBCS.
+endif
+ lodsb
+ dec cx
+ jz pb9 ; if done
+ cmp al, LINEFEED ; if end of line, go on
+ jz pb1
+ jmps pb2loop
+pb20:
+ stosb ; first character of line
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ call FarMyIsDBCSLeadByte
+ jc pb_dbcs_s1
+ movsb
+ dec cx
+ jz pb9
+pb_dbcs_s1:
+endif
+ cmp al,'=' ; if '=', then end of left hand side
+ jz pb2a
+ jcxz pb9
+ cmp al, SPACE ; if space, might be trailing space
+ jz pb2
+ cmp al, TAB
+ jz pb2
+ cmp al, LINEFEED ; if end of line, go on
+ jz pb1
+ mov bx,di ; ow save last valid character+1
+ jmp pb2
+
+pb2a:
+ mov di,bx ; remove trailing spaces on left
+ stosb ; resave '='
+pb3: ; now work on right hand side
+ jcxz pb9 ; while leading space or tab
+ lodsb ; remove leading spaces
+ dec cx
+ cmp al, SPACE
+ jz pb3 ; and tabs
+ cmp al, TAB
+ jz pb3
+
+ dec si ; refetch last character
+ inc cx
+pb5:
+ifdef DBCS ;Apr.26,1990 by AkiraK
+;LINEFEED is never found in lead byte of DBCS.
+;so, this loop is safe in DBCS.
+endif
+ lodsb
+ stosb ; store character
+ dec cx
+ jz pb9
+ cmp al, LINEFEED ; at end of line?
+ jz pb1 ; yes, go on
+ jmp pb5
+
+pb9:
+ or di, di
+ jz pb9a ; NOTHING THERE!!
+ dec di ; remove trailing ^Z's
+ cmp byte ptr es:[di],"Z"-"@"
+ jz pb9
+ inc di
+pb9a:
+
+ mov ax,CRLF
+ stosw ; make sure there is a final
+ xor ax,ax ; CARRETURN and NULL
+ stosb
+ pop ds ; restore DS
+ mov si,[hBuffer]
+ cCall GlobalUnlock,<si>
+
+ xor ax,ax
+ regptr xsize,ax,di
+ cCall GlobalReAlloc,<si,xsize,ax>
+
+ public lockbuffer
+LockBuffer:
+ mov si,ax
+ cCall GlobalLock,<ax>
+ mov word ptr BufAddr[0],ax
+ mov word ptr BufAddr[2],dx
+ ret
+
+ public unlockbuffer
+UnlockBuffer:
+ mov si,hBuffer
+ cCall GlobalUnlock,<si>
+ xor ax,ax
+ mov dx,(GA_MODIFY + (GA_DISCARDABLE SHL 8)) ; make block discardable
+ cCall GlobalReAlloc,<si,ax,ax,dx>
+ mov bx,-1
+ xchg bx,[hFile]
+ inc bx
+ jz ulbdone
+ dec bx
+ cCall _lclose,<bx> ; close file
+ulbdone:
+ ret
+
+Rewind:
+ xor ax,ax ; rewind the tape
+Rewind2:
+ xor cx,cx
+ cCall _llseek,<hFile,cx,cx,ax>
+ ret
+
+
+; this proc calculates the length of the string pointed to by es:di
+; and returns it in cx. It searches for a CR and then backs thru any
+; trailing spaces.
+; it uses cx, es, and di
+
+ public strlen
+strlen PROC NEAR
+ifdef DBCS ;Apr.26,1990 by AkiraK
+; Space, Carridge Return, NULL are never in lead byte of DBCS.
+; So, we don't need to enable here.
+endif
+ push ax ; Save ax
+ mov cx,di ; cx = start of string
+ dec di
+str1: inc di ; Search for CR or NULL
+ mov al,es:[di] ; AL has CR or NULL
+ cmp al,CARRETURN
+ ja str1
+str2: dec di ; Remove trailing blanks
+ cmp di,cx ; Check for start of string
+ jb str3
+ cmp byte ptr es:[di],SPACE
+ jz str2
+str3: inc di ; Restore CR or NULL
+ cmp es:[di],al
+ jz maybe_in_code
+ mov es:[di],al
+maybe_in_code:
+ neg cx
+ add cx,di
+ pop ax ; Restore ax
+ ret
+strlen ENDP
+
+ public strcmpi
+strcmpi PROC NEAR
+; es:di and ds:si have strings
+; es:di should be terminated by the char in bl
+; ds:si is null terminated
+ifdef DBCS ;Apr.26,1990 by AkiraK
+sti_l1:
+ mov al,es:[di]
+ cmp al,bl
+ jz sti_s1
+
+ call FarMyLower
+ mov cl,al
+
+ mov al,ds:[si]
+ call FarMyLower
+
+ inc si
+ inc di
+
+ cmp al,cl
+ jnz sti_exit
+
+ call FarMyIsDBCSLeadByte
+ jc sti_l1
+
+ mov al,es:[di]
+ cmp al,ds:[si]
+ jnz sti_exit
+
+ inc si
+ inc di
+ jmp short sti_l1
+
+
+sti_exit:
+ ret
+
+sti_s1:
+ mov al,ds:[si]
+ or al,al
+ ret
+else
+stci10:
+ mov al,es:[di]
+ cmp al,bl ; At the end?
+ jnz stci15 ; yes, get out of here.
+ mov al,[si] ; are we at the end of the string
+ or al,al
+ jmps stciex
+stci15:
+ call FarMyLower
+stci30:
+ mov cl,[si]
+ xchg al,cl
+ call FarMyLower
+ xchg cl,al
+stci40:
+ inc si
+ inc di
+ cmp al,cl ; Still matching chars?
+ jz stci10 ; Yes, go try the next char.
+stciex:
+ ret
+endif
+strcmpi ENDP
+
+
+;-----------------------------------------------------------------------;
+; WriteProfileString ;
+; ;
+; Copies the given character string to WIN.INI. ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmD lpString ;
+; ;
+; Returns: ;
+; AX = bResult ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 05:12:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WriteProfileString,<PUBLIC,FAR>,<si,di,ds>
+ parmD section
+ parmD keyword
+ parmD result
+
+ localD ptrTmp
+ localW WhatIsMissing
+ localW nBytes
+ localW fh
+cBegin
+ cCall MISCMapDStoDATA ; point at data segment
+ ReSetKernelDS
+
+ cCall SetDefaultPro
+
+;make sure buffer is ready
+
+ mov si,[hBuffer]
+ call FreeBuffer ; free up any buffer we may have
+ cmp ax,SEG_section
+ jne WPS0
+ cmp ax,SEG_keyword
+ jne WPS0
+ cmp ax,SEG_result
+ jne WPS0
+ jmp WriteDone
+WPS0:
+ mov di,2 ; write
+ call BufferInit ; read in a fresh copy
+
+; DX:AX has buffer address, NULL if it didn't work
+
+ mov di,ax
+ or ax,dx
+ jnz WPS1
+ jmp WriteDone
+
+WPS1: push dx ; save buffer selector
+
+ cCall GlobalSize, <hBuffer> ; how big is he?
+ or dx, dx ; more than 64k, icky
+ jnz WPS_TooBig
+ cmp ax, 0FF00h ; more than 64K-256, icky
+ jb WPS_SmallEnough
+
+WPS_TooBig:
+ pop ax ; throw away saved buffer selector
+ xor ax, ax ; return FALSE if file too big
+ jmp WriteDone
+
+WPS_SmallEnough:
+
+ pop es ; selector of buffer popped into es
+ push ds
+ call Rewind
+
+; ES:DI now has the buffer address, buffer is locked down
+; scan through buffer, looking for section
+
+ cCall FindSection, <section>
+ jc WPS5
+
+ mov ax, SEG_keyword
+ or ax, OFF_keyword
+ jnz WPS2
+ mov WhatIsMissing, REMOVESECTION
+ ScanBack SECT_LEFT
+ jmps WPS9
+WPS2:
+ cCall FindKey, <keyword>
+ jnc WPS7
+
+; if it gets here, there wasn't a match
+
+ mov WhatIsMissing,NOKEY
+ jmps WPS8
+
+; if it gets here, there wasn't a match
+
+WPS5:
+ mov WhatIsMissing,NOSECTION
+ jmps WPS8
+
+WPS7:
+ inc di ; di now points to result
+ mov WhatIsMissing,NEWRESULT
+ mov ax, SEG_result
+ or ax, OFF_result
+ jnz WPS9 ; NEWRESULT
+
+ ScanBack LINEFEED
+ inc di ; Now points to the keyword
+ jmps WPS9
+WPS8:
+
+ cmp WhatIsMissing,NEWRESULT
+ jz WPS9
+WPS14: ; get rid of extra CRLF
+ or di, di
+ jz WPS9
+ dec di
+ mov al,es:[di]
+ cmp al,CARRETURN
+ jz WPS14
+ cmp al,LINEFEED
+ jz WPS14
+ add di,3
+WPS9:
+
+; write out up to here in file
+
+ pop ds
+ push ds
+ mov bx,[hFile]
+ cmp bx,-1
+ jnz WPS10
+
+ lds dx,lpszUserPro ; create win.ini
+ xor cx,cx ; no special attributes
+ cCall _lcreat,<ds,dx,cx> ; create the file
+ pop ds
+ push ds
+ mov [hFile],ax
+ mov bx,ax ; bx has file handle
+ inc ax
+ jz WPSError ; -1 means didn't work
+ xor dx,dx
+ cCall _lwrite,<bx,dsdx,dx> ; Zero length write to reset file
+ or ax,ax
+ jz WPS10 ; size on a network file (3.0 bug)
+WPSError:
+ pop ds
+ call UnlockBuffer
+ xor ax,ax
+ jmp WriteDone
+WPS10:
+ mov bx,[hFile]
+ mov fh,bx ; save file handle in local variable
+ xor cx,cx
+ mov nBytes,cx
+; write file
+ mov off_ptrTmp,di
+ mov seg_ptrTmp,es
+ mov cx,di ; cx has file size
+ push es
+ pop ds
+ xor dx,dx
+ call WriteCheck ; write and check the write
+
+ cmp WhatIsMissing,NOSECTION
+ jnz WPS11
+ mov ax, SEG_keyword ; Wanted to delete it?
+ or ax, OFF_keyword
+ jnz WPS10a
+ jmp WPS13 ; Yes, don't do anything
+WPS10a:
+ pop ds
+ push ds
+ mov dx,codeOffset CarRetLF
+ mov cx,2
+ call WriteCheck
+ mov dx,codeOffset LeftSect
+ mov cx,1
+ call WriteCheck
+ les di,section
+ call strlen
+ lds dx,section
+ call WriteCheck
+ pop ds
+ push ds
+ mov dx,codeOffset RightSect
+ mov cx,3
+ call WriteCheck
+WPS11:
+ cmp WHatIsMissing, REMOVESECTION
+ jne WPS11a
+
+WPS11b:
+ ScanTo LINEFEED ; Skip Current Line
+WPS11c:
+ mov al, es:[di]
+ or al, al
+ jz WPS13
+ cmp al, SECT_LEFT
+ je WPS13
+ cmp al, ';'
+ jne WPS11b ; Skip this line
+ ; Preserve Comment lines
+ smov ds, es ; Write from ds:dx
+ mov dx, di
+ ScanTo LINEFEED
+ mov cx, di
+ sub cx, dx
+ call WriteCheck
+ jmps WPS11c
+
+WPS11a:
+ cmp WhatIsMissing,NEWRESULT
+ jz WPS15
+ ; WhatIsMissing == NOKEY
+ mov ax, SEG_result ; Delete keyword?
+ or ax, OFF_result
+ jz WPS13 ; Yes, do nothing since not there!
+
+ les di,keyword
+ call strlen
+ lds dx,keyword
+ call WriteCheck
+ pop ds
+ push ds
+ mov dx,codeOffset EquStr
+ mov cx,1
+ call WriteCheck
+ jmps WPS15a ; and write out result
+
+WPS15: ; Found keyword, have new result
+ mov ax, SEG_result
+ or ax, OFF_result ; Have result to set?
+ jnz WPS15a
+ ScanTo LINEFEED ; No result, delete line
+ jmps WPS13
+WPS15a:
+ les di,result
+ call strlen
+ lds dx,result
+ call WriteCheck
+ pop ds
+ push ds
+ mov dx,codeOffset CarRetLF
+ mov cx,2
+ call WriteCheck
+WPS12:
+ les di,ptrTmp
+ cmp WhatIsMissing,NEWRESULT
+ jnz WPS13
+ ; get rid of old result
+ ScanTo LINEFEED
+WPS13:
+ mov dx,di
+ xor al,al
+ mov cx,-1
+ repne scasb
+ sub di,3 ; one past end, plus extra CRLF
+ sub di,dx
+if 1
+ jbe WPS23 ; if di points before dx blow it off
+endif
+ mov cx,di
+if 0
+ or cx,cx ; if <= 0 then nothing to write
+ jle WPS23
+endif
+ mov si,dx
+ mov dx,cx ; We are growing the file. Seek
+ add dx,nBytes
+ xor cx,cx ; to new EOF and set file size
+ cCall _llseek,<fh,cx,dx,cx>
+ ; with zero length write (DOS 2.X
+ ; BIOS bug with writes past current
+ xor cx,cx ; EOF with DTA near end of memory)
+ call WriteCheck
+ mov dx,nBytes ; Now backup to write rest of file
+ xor cx,cx
+ cCall _llseek,<fh,cx,dx,cx>
+ push es
+ pop ds
+ mov cx,di
+ mov dx,si
+ call WriteCheck
+WPS23:
+ xor cx,cx
+ call WriteCheck
+ pop ds
+
+ call UnlockBuffer
+ call FreeBuffer
+ mov ax,1
+WriteDone:
+cEnd
+
+ public WriteCheck
+WriteCheck:
+ cCall _lwrite,<fh,dsdx,cx>
+ mov cx,ax
+ inc ax
+ jz WC1
+ dec ax
+ add [nBytes],cx
+ ret
+WC1:
+ pop ax ; return address
+ jmp WPSError
+
+
+;-----------------------------------------------------------------------;
+; GetPrivateProfileInt ;
+; ;
+; Gets the integer value for the keyword field from a private file ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmW nDefault ;
+; parmD lpFile ;
+; ;
+; Returns: ;
+; AX = nKeyValue ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 04:32:04p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetPrivateProfileInt,<PUBLIC,FAR>,<si>
+ parmD Section
+ parmD keyword
+ parmW defint
+ parmD lpFile
+ localV Buffer,80h
+cBegin
+ cCall MISCMapDStoDATA ; Safety
+ lea si,Buffer
+ cCall ForcePrivatePro,<ss,si,lpFile>
+ cCall SetPrivatePro,<ss,si>
+ cCall GetProfileInt,<section, keyword, defint>
+ cCall ResetPrivatePro
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; GetPrivateProfileString ;
+; ;
+; Returns the string for the keyword field from a private file ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmD lpDefault ;
+; parmD lpReturnedString ;
+; parmW nSize ;
+; parmD lpFile ;
+; ;
+; Returns: ;
+; AX = nLength ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 04:45:20p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc GetPrivateProfileString,<PUBLIC,FAR>,<si>
+ parmD section
+ parmD keyword
+ parmD defString
+ parmD resString
+ parmW cchMax
+ parmD lpFile
+ localV Buffer,80h
+cBegin
+ cCall MISCMapDStoDATA ; Safety
+ lea si,Buffer
+ cCall ForcePrivatePro,<ss,si,lpFile>
+ cCall SetPrivatePro,<ss,si>
+ cCall GetProfileString,<section,keyword,defString,resString,cchMax>
+ cCall ResetPrivatePro
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; WritePrivateProfileString ;
+; ;
+; Copies the given character string to a private file ;
+; ;
+; Arguments: ;
+; parmD lpApplicationName ;
+; parmD lpKeyName ;
+; parmD lpString ;
+; parmD lpFile ;
+; ;
+; Returns: ;
+; AX = bResult ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; DI,SI,DS ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Oct 10, 1987 05:12:51p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WritePrivateProfileString,<PUBLIC,FAR>,<si>
+ parmD section
+ parmD keyword
+ parmD result
+ parmD lpFile
+ localV Buffer,80h
+cBegin
+ cCall MISCMapDStoDATA ; Safety
+ lea si,Buffer
+ cCall ForcePrivatePro,<ss,si,lpFile>
+ cCall SetPrivatePro,<ss,si>
+ cCall WriteProfileString,<section, keyword, result>
+ cCall ResetPrivatePro
+cEnd
+
+;-----------------------------------------------------------------------;
+; ForcePrivatePro
+;
+; If the file pointed to is not qualified then we force
+; the file into the Windows directory.
+;
+; Entry:
+; BX = buffer on stack
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Tue 14-Nov-1989 20:30:48 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc ForcePrivatePro,<PUBLIC,NEAR>,<di,si,ds>
+ parmD lpDest
+ parmD lpSource
+cBegin
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ cld
+ xor ax,ax
+ mov bx,'/' shl 8 + '\'
+ xor dx,dx
+ lds si,lpSource ; first get length of string
+ mov cx,si
+ mov al,ds:[si]
+ call FarMyIsDBCSLeadByte
+ jnc fpp_s1
+ cmp byte ptr ds:[si].1,':' ; is it qualified with a drive?
+ jnz fpp_s1
+ inc dx
+fpp_s1:
+
+fpp_l1:
+ lodsb
+ or al,al
+ jz fpp_got_length
+ cmp al,bh
+ jz fpp_qualified
+ cmp al,bl
+ jz fpp_qualified
+fpp_s2:
+ call FarMyIsDBCSLeadByte
+ jc fpp_l1
+ inc si
+ jmp fpp_l1
+
+fpp_qualified:
+ inc dx
+ jmp fpp_s2
+else
+ cld
+ xor ax,ax
+ mov bx,'/' shl 8 + '\'
+ xor dx,dx
+ lds si,lpSource ; first get length of string
+ mov cx,si
+ cmp byte ptr ds:[si].1,':' ; is it qualified with a drive?
+ jnz @F
+ inc dx
+@@: lodsb
+ or al,al
+ jz fpp_got_length
+ cmp al,bh
+ jz fpp_qualified
+ cmp al,bl
+ jnz @B
+fpp_qualified:
+ inc dx
+ jmp @B
+endif
+
+fpp_got_length:
+ sub si,cx
+ xchg si,cx
+ les di,lpDest
+ or dx,dx
+ jnz fpp_copy_name
+ push cx
+ cCall MISCMapDStoDATA
+ ResetKernelDS
+ mov cx,cBytesWinDir
+ lds si,lpWindowsDir
+ rep movsb
+ mov al,'\'
+ stosb
+ pop cx
+ lds si,lpSource
+fpp_copy_name:
+ rep movsb
+cEnd
+
+endif
+; ndef WOW
+
+;-----------------------------------------------------------------------;
+; GetWindowsDirectory
+;
+;
+; Entry:
+; parmD lpBuffer pointer to buffer
+; parmW cbBuffer size of buffer
+;
+; Returns:
+; AX = size of string copied
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 24-Sep-1989 16:18:46 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetWindowsDirectory,<PUBLIC,FAR>,<di,si>
+ parmD lpBuf
+ parmW cbBuffer
+cBegin
+ cCall MISCMapDStoDATA ; point at data segment
+ ResetKernelDS
+ mov cx,cBytesWinDir
+ lds si,lpWindowsDir
+ inc cx ; Room for NULL
+ mov ax, cx
+ cmp cx, 3 ; Just 3 bytes implies <drive>:
+ jne gwd_notroot
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ mov al,ds:[si+0] ;Make sure the 1st byte is not
+ call FarMyIsDBCSLeadByte ; DBCS lead byte.
+ jnc gwd_notroot
+endif
+ cmp byte ptr ds:[si+1], ':' ; Make sure
+ jne gwd_notroot
+ inc ax ; Allow for \
+gwd_notroot:
+ cmp ax,cbBuffer ; is there enough room in buffer?
+ ja gwd_exit
+ dec cx ; don't copy null
+ les di,lpBuf
+ cld
+ifdef WOW
+;; For WOW we might be running on a file system that supports lower case
+;; however some apps can't cope with lowercase names so we uppercase it here
+ push ax
+gwd_loop:
+ lodsb
+ call FarMyUpper ; Convert char to UpperCase
+ stosb
+ifdef DBCS
+ call MyIsDBCSLeadByte
+ jc gwd_loop ; copy second byte in east
+ movsb
+endif
+ loop gwd_loop
+ pop ax
+else ; WOW
+ rep movsb
+endif; WOW
+ mov es:[di],cl
+ dec ax
+ cmp ax, 3
+ jne gwd_exit
+ mov di, word ptr lpBuf ; Get pointer to dest again
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ mov al,ds:[di+0] ;Make sure the 1st byte is not
+ call FarMyIsDBCSLeadByte ; DBCS lead byte.
+ jnc gwd_exit
+endif
+ cmp byte ptr es:[di+1], ':'
+ jne gwd_exit
+ mov byte ptr es:[di+2], '\'
+ mov byte ptr es:[di+3], cl
+gwd_exit:
+cEnd
+;-----------------------------------------------------------------------;
+; GetSystemDirectory
+;
+; Entry:
+; parmD lpBuf pointer to buffer
+; parmW cbBuffer size of buffer
+;
+; Returns:
+; AX = size of string copied
+;
+; Registers Destroyed:
+;
+; History:
+; Sun 24-Sep-1989 16:18:46 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc IGetSystemDirectory,<PUBLIC,FAR>,<di,si>
+ parmD lpBuf
+ parmW cbBuffer
+cBegin
+ cCall MISCMapDStoDATA ; point at data segment
+ ResetKernelDS
+ifndef WOW
+ mov cx,cBytesSysDir
+ lds si,lpSystemDir
+else
+ mov cx,cBytesSys16Dir
+ lds si,lpSystem16Dir
+endif
+ inc cx ; Room for NULL
+ mov ax, cx
+ cmp cx, 3 ; Just 3 bytes implies <drive>:
+ jne gsd_notroot
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ mov al,ds:[si+0] ;Make sure the 1st byte is not
+ call FarMyIsDBCSLeadByte ; DBCS lead byte.
+ jnc gsd_notroot
+endif
+ cmp byte ptr ds:[si+1], ':' ; Make sure
+ jne gsd_notroot
+ inc ax ; Allow for \
+gsd_notroot:
+ cmp ax,cbBuffer ; is there enough room in buffer?
+ ja gsd_exit
+ dec cx ; don't copy null
+ les di,lpBuf
+ cld
+ifdef WOW
+;; For WOW we might be running on a file system that supports lower case
+;; however some apps can't cope with lowercase names so we uppercase it here
+ push ax
+gsd_loop:
+ lodsb
+ call FarMyUpper ; Convert char to UpperCase
+ stosb
+ifdef DBCS
+ call MyIsDBCSLeadByte
+ jc gsd_loop ; copy second byte in east
+ movsb
+endif
+ loop gsd_loop
+ pop ax
+else ; WOW
+ rep movsb
+endif; WOW
+ mov es:[di],cl
+ dec ax ; return number of bytes in string
+ cmp ax, 3
+ jne gsd_exit
+ mov di, word ptr lpBuf ; Get pointer to dest again
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ mov al,ds:[di+0] ;Make sure the 1st byte is not
+ call FarMyIsDBCSLeadByte ; DBCS lead byte.
+ jnc gsd_exit
+endif
+ cmp byte ptr es:[di+1], ':'
+ jne gsd_exit
+ mov byte ptr es:[di+2], '\'
+ mov byte ptr es:[di+3], cl
+gsd_exit:
+cEnd
+
+sEnd MISCCODE
+
+
+ifndef WOW
+
+sBegin INITCODE
+assumes cs, CODE
+assumes ds, nothing
+assumes es, nothing
+
+szWININI db 'WININI='
+lenWININI equ $-codeoffset szWININI
+
+;-----------------------------------------------------------------------;
+; SetUserPro ;
+; ;
+; Set szUserPro to the string given in the environment variable WININI ;
+; The default is WIN.INI ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+cProc SetUserPro,<PUBLIC,NEAR>,<ax,cx,si,di,ds,es>
+cBegin
+ SetKernelDS es
+ mov ds, TopPDB
+ mov ds, ds:[PDB_environ]
+ cld
+ xor si, si
+
+ smov es,cs
+ assumes es,CODE
+
+FindWinIni:
+ cmp byte ptr ds:[si], 0
+ je EndEnv
+ mov di, codeoffset szWININI
+ mov cx, lenWININI
+ rep cmpsb
+ je FoundEntry
+ dec si
+SkipEntry:
+ lodsb
+ or al, al
+ jnz SkipEntry
+ jmps FindWinIni
+FoundEntry:
+
+ SetKernelDS es
+
+ mov di, dataoffset szUserPro
+CopyEntry:
+ lodsb
+ stosb
+ or al, al
+ jnz CopyEntry
+EndEnv:
+ assumes es, nothing
+cEnd
+
+sEnd INITCODE
+
+endif
+; ndef WOW
+
+end
diff --git a/private/mvdm/wow16/kernel31/w32sys.asm b/private/mvdm/wow16/kernel31/w32sys.asm
new file mode 100644
index 000000000..67dcbf6f2
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/w32sys.asm
@@ -0,0 +1,39 @@
+ TITLE w32sys - Win32S support
+
+.xlist
+include kernel.inc
+include tdb.inc
+.list
+
+DataBegin
+
+externW curTDB
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ public GetW32SysInfo
+
+cProc GetW32SysInfo,<PUBLIC,FAR>
+cBegin nogen
+if PMODE32
+ SetKernelDS ES
+
+ mov dx, es
+ lea ax, curTDB
+
+endif
+ ret
+ assumes es,nothing
+cEnd nogen
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/winexec.asm b/private/mvdm/wow16/kernel31/winexec.asm
new file mode 100644
index 000000000..71953548b
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/winexec.asm
@@ -0,0 +1,331 @@
+;-----------------------------------------------------------------------;
+;
+; WINEXEC.ASM -
+;
+; Windows Exec Function
+;
+;-----------------------------------------------------------------------;
+
+include kernel.inc
+ifdef WOW
+include wowcmpat.inc
+;The following defines come from winerror.inc, which is new in the
+;win95 source tree, but hasn't been merged into wow
+ERROR_FILE_NOT_FOUND equ 2
+ERROR_BAD_LENGTH equ 24
+endif
+
+
+ifdef DBCS
+externFP FarMyIsDBCSLeadByte
+endif
+
+ifdef WOW
+externFP MyGetAppWOWCompatFlagsEx
+endif
+
+ externW WinFlags ; (kdata.asm)
+ externD WinAppHooks ; (kdata.asm)
+
+sBegin NRESCODE
+
+assumes cs,NRESCODE
+
+
+;-----------------------------------------------------------------------;
+;
+; WinExec() -
+;
+;-----------------------------------------------------------------------;
+
+; HANDLE PASCAL WinExec(lpszFile,wShow)
+
+cProc IWinExec, <FAR,PUBLIC>,<si,di>
+
+ parmD lpszFile ; Pathname ptr
+ parmW wShow ; Mode flag
+;
+; szCmdLine buffer must be big enough for passed in path & parms, plus
+; .EXE, null terminator, and newline terminator.
+; So we add a little room for good measure here.
+;
+ LocalV szCmdLine,260+256+8 ; Path and command line (to account for .exe)
+ LocalW pszParm ; Ptr to start of parameters
+
+ LocalB bDotFound ; Non-zero if a period is in the string
+ LocalB bDblQFound ; Non-zero if the string starts with "
+
+ LocalV loadparams, %(SIZE EXECBLOCK)
+ LocalD FCB1
+cBegin
+
+; Copy first part of line into szCmdLine.
+
+ lds si,lpszFile
+ smov es,ss
+ lea di,szCmdLine
+ mov cx,260 ; MAX_PATH
+
+ xor al,al
+ mov bDotFound,al
+ mov bDblQFound,al
+ ; The Dbl-quote is used as a delimiter for cmdname as in
+ ; winexec("\"c:\fldr with spaces\" cmd line", ..);
+ mov al, ds:[si] ; get Ist char
+ cmp al,'"' ; is it a "
+ jne WELoop1 ; N:
+ mov bDblQFound,al ; Y: remember that
+ lodsb ; skip the dblQ
+
+; Loop until a blank or NULL is found.
+WELoop1:
+ lodsb
+ cmp bDblQFound, 0 ; If str didn't start with dblQ
+ je WESpaceCheck ; then SPACE is a delimiter
+ ; otherwise " is the delimiter
+ cmp al,'"' ; look for second DblQ
+ jne WESkipSpaceCheck
+ and bDblQFound,0 ; reset this, so space is the delimiter
+ lodsb ; skip past the dbl Q
+WESpaceCheck:
+ cmp al,' ' ; Exit loop if blank or NULL
+ je WECont1
+WESkipSpaceCheck:
+ cmp al,9
+ je WECont1
+ or al,al
+ je WECont1
+ cmp al,'.'
+ jne WELoopCont
+ mov bDotFound,al
+WELoopCont:
+ ;** We have to check to see if the dot we found was actually in
+ ;** a directory name, not in the filename itself.
+ cmp al, '\' ; Separator?
+ je WE_Separator
+ cmp al, '/'
+ jne WE_Not_Separator
+WE_Separator:
+ mov bDotFound,0 ; No dots count yet
+WE_Not_Separator:
+ stosb
+ dec cx
+ jz WE_filename_too_long
+ifdef DBCS ;Apr.26,1990 by AkiraK
+ push cx
+ call FarMyIsDBCSLeadByte
+ pop cx
+ jc WELoop1
+ movsb
+ dec cx
+ jz WE_filename_too_long
+endif
+ jmp short WELoop1
+
+WE_filename_too_long:
+ krDebugOut DEB_TRACE, "WinExecEnv: filename too long, > 259"
+ mov ax,ERROR_FILE_NOT_FOUND
+ jmp WinExecEnvExit
+
+WECont1:
+ mov dx,ax ; Store final char in DX
+
+; Does the command have an extention?
+
+ cmp bDotFound,0
+ jne WEHasExt
+
+ mov ax,0452Eh ;'.E'
+ stosw
+ mov ax,04558h ;'XE'
+ stosw
+
+WEHasExt:
+ xor ax,ax ; NULL terminate string
+ stosb
+
+ mov pszParm,di ; Store pointer to parm string
+ stosb ; length = 0
+ mov al,0dh ; line feed terminator
+ stosb
+ dec di ; back up
+
+ or dl,dl ; Exec if lpszFile was null terminated
+ jz WEExec
+
+; Copy everything else into szParm.
+
+ mov cx,255 ; Max length of cmd tail +1
+WELoop2:
+ lodsb
+ or al,al
+ifdef WOW
+ jz WEDoneParm
+else
+ jz WECont2
+endif
+ stosb
+ dec cx
+ jnz WELoop2
+
+ifdef WOW
+ jmps @F
+
+;
+; On NT we have a compatibility flag, WOWCFEX_LONGWINEXECTAIL which is
+; set for applications such as TSSETUP, the setup program for Intergraph's
+; NT-only Transcend app. This app uses a command tail on the order of
+; 143 bytes for a Win32 worker app, and it worked on 3.5 and 3.51,
+; so we need to continue to let at least this app cheat.
+;
+
+WEDoneParm:
+ sub cx, 128
+ ja WECont2
+
+; tail was longer than 126 characters
+
+ call MyGetAppWOWCompatFlagsEx
+ test dx, word ptr cs:[WE_GACFEX_LONGWINEXECTAIL+2]
+ jz @F
+ jmps WECont2
+
+WE_GACFEX_LONGWINEXECTAIL:
+ DD WOWCFEX_LONGWINEXECTAIL
+
+@@:
+endif
+
+; Cmd tail too long to fit in PSP !!!
+; Fail the call.
+; We _could_ alloc some memory to hold the cmd tail and make its
+; owner be the new hTask. However InitTask is documented to return
+; es=PSP, es:bx=cmd_tail. So we're screwed. Could truncate the cmd line.
+; Cleaner to fail the exec.
+; Could grow the PSP and tack the big cmd tail on at the end. Scary!
+; Unfortunately, kernel32.ExecWin16Program maps ERROR_BAD_LENGTH to
+; ERROR_GEN_FAILURE.
+ krDebugOut DEB_TRACE, "WinExecEnv: command tail too long, > 126"
+ mov ax,ERROR_BAD_LENGTH
+ jmps WinExecEnvExit
+
+WECont2:
+
+; Terminate it with a carriage return.
+
+ mov al,0Dh
+ stosb
+
+; Prefix the parameter string with its length.
+
+ mov bx,pszParm ; ax = length + 2
+ mov ax,di
+ sub ax,bx
+ dec ax ; don't include line feed char or length
+ dec ax
+ mov ss:[bx],al
+
+; Set up the FCBs.
+
+WEExec:
+ mov word ptr FCB1[0],2 ; FCB1[0] = 2;
+ mov ax,wShow ; FCB1[1] = wShow;
+ mov word ptr FCB1[2],ax
+ xor ax,ax
+ mov loadparams.envseg,ax ; loadparms.segEnv = 0;
+ mov loadparams.lpfcb2.lo,ax ; loadparms.lpFCB2 = (LPSTR)NULL;
+ mov loadparams.lpfcb2.hi,ax
+ mov ax,pszParm ; loadparms.lpCmdLine = (LPSTR)pszParm;
+ mov loadparams.lpCmdLine.lo,ax
+ mov loadparams.lpCmdLine.hi,ss
+ lea ax,FCB1 ; loadparms.lpFCB1 = (LPSTR)fcb1buf;
+ mov loadparams.lpfcb1.lo,ax
+ mov loadparams.lpfcb1.hi,ss
+
+; Exec the progam.
+
+ smov ds,ss
+ lea dx,szCmdLine ; ds:ax == ptr to file to exec
+ lea bx,loadparams ; es:bx == ptr to param block
+ mov ax,4B00h ; dos exec
+ int 21h
+
+WinExecEnvExit:
+cEnd
+
+;**************************************************************************
+; RegisterWinoldapHook(Addr,Opcode):
+;
+; Description: (Opcode == 1) => hook, (Opcode == 0) => unhook.
+; Addr is a ptr to struct of the form WinoldapHookList
+; struct WinoldapHookList { struct WinoldapHookList *ptr; DWORD Hook;};
+;**************************************************************************
+
+cProc RegisterWinoldapHook,<FAR,PUBLIC,PASCAL>,<ds,es,di,si,dx>
+ parmD Address
+ parmB Opcode
+cBegin
+ SetKernelDSNRes ; set kernel's DS
+ mov ax, WinFlags
+ test ax, WF_STANDARD
+ mov ax,0
+ jz RWH_Call
+ lea si,WinAppHooks
+ les di,Address
+ cmp Opcode,0 ; unhook ?
+ jz RWH_Unhook
+RWH_Exchange:
+ mov ax,ds:[si] ; old
+ mov es:[di],ax ; next of new
+ mov ax,ds:[si+2]
+ mov es:[di+2],ax ; next set
+ mov ds:[si],di
+ mov di,es
+ mov ds:[si+2],di ; new one becomes first
+ mov ax,1
+ jmp SHORT RWH_Call
+
+RWH_Unhook:
+ mov dx,es
+RWH_Compare:
+ cmp di,ds:[si]
+ jnz RWH_Nexthook
+ cmp dx,ds:[si+2]
+ jnz RWH_NextHook
+ mov ax,es:[di]
+ mov ds:[si],ax
+ mov ax,es:[di+2]
+ mov ds:[si+2],ax
+ mov ax,1
+ jmp SHORT RWH_Call
+RWH_NextHook:
+ lds si,ds:[si]
+ mov ax,ds
+ or ax,si
+ jnz short RWH_Compare
+RWH_Call:
+ UnSetKernelDS ; unset it
+cEnd
+
+;**********************************************************************
+;
+; GetWinoldapHooks:
+; Description: Called exclusively by winoldap to get a pointer to a list
+; of WinoldapHookList.
+; Entry: None
+; EXIT: DX:AX -> WinoldapHookList...
+; USES: Flags.
+;**********************************************************************
+
+cProc GetWinoldapHooks,<FAR,PUBLIC,PASCAL>,<ds,si>
+cBegin
+ SetKernelDSNRes ; set kernel DS
+ lea si,WinAppHooks
+ mov ax, word ptr ds:[si]
+ mov dx, word ptr ds:[si+2]
+ UnSetKernelDS ; unset it
+cEnd
+
+sEnd NRESCODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/winkern.inc b/private/mvdm/wow16/kernel31/winkern.inc
new file mode 100644
index 000000000..e1783be94
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/winkern.inc
@@ -0,0 +1,489 @@
+MASTER_OBJECT_SIZE equ 512
+
+LOCALHEAP_SIG EQU 'HL'
+GLOBALHEAP_SIG EQU 'HG'
+
+; Debug fill constants
+
+DBGFILL_ALLOC equ 0fdh
+DBGFILL_FREE equ 0fbh
+DBGFILL_BUFFER equ 0f9h
+DBGFILL_STACK equ 0f7h
+
+ife PMODE32
+
+; Data structure that describes an allocation arena. Both the local
+; and global allocators use this structure at the beginning of their
+; information structures.
+;
+HeapInfo STRUC
+hi_check DW ? ; arena check word (non-zero enables heap checking)
+hi_freeze DW ? ; arena frozen word (non-zero prevents compaction)
+hi_count DW ? ; #entries in arena
+hi_first DW ? ; first arena entry (sentinel, always busy)
+hi_last DW ? ; last arena entry (sentinel, always busy)
+hi_ncompact DB ? ; #compactions done so far (max of 3)
+hi_dislevel DB ? ; current discard level
+hi_distotal DW ? ; total amount discarded so far
+hi_htable DW ? ; head of handle table list
+hi_hfree DW ? ; head of free handle table list
+hi_hdelta DW ? ; #handles to allocate each time
+hi_hexpand DW ? ; address of near procedure to expand handles for
+ ; this arena
+hi_pstats DW ? ; address of statistics table or zero
+HeapInfo ENDS
+
+else ; PMODE32
+
+; Data structure that describes an allocation arena. Both the local
+; and global allocators use this structure at the beginning of their
+; information structures.
+;
+HeapInfo STRUC
+hi_check DW ? ; arena check word (non-zero enables heap checking)
+hi_freeze DW ? ; arena frozen word (non-zero prevents compaction)
+hi_count DW ? ; #entries in arena
+hi_first DW ? ; first arena entry (sentinel, always busy)
+ DW ?
+hi_last DW ? ; last arena entry (sentinel, always busy)
+ DW ?
+hi_ncompact DB ? ; #compactions done so far (max of 3)
+hi_dislevel DB ? ; current discard level
+hi_distotal DD ? ; total amount discarded so far
+hi_htable DW ? ; head of handle table list
+hi_hfree DW ? ; head of free handle table list
+hi_hdelta DW ? ; #handles to allocate each time
+hi_hexpand DW ? ; address of near procedure to expand handles for
+ ; this arena
+hi_pstats DW ? ; address of statistics table or zero
+HeapInfo ENDS
+
+phi_first equ dword ptr hi_first
+phi_last equ dword ptr hi_last
+
+endif ; PMODE32
+
+; Handle table entry.
+
+HandleEntry STRUC
+he_address DW ? ; actual address of object
+he_flags DB ? ; flags and priority level
+he_seg_no DB ? ; 0-based segment number for discardable code
+HandleEntry ENDS
+he_EMSPID_no equ byte ptr he_seg_no
+
+FreeHandleEntry STRUC
+he_link DW ?
+he_free DW ?
+FreeHandleEntry ENDS
+
+LocalHandleEntry STRUC
+lhe_address DW ? ; actual address of object
+lhe_flags DB ? ; flags and priority level
+lhe_count DB ? ; lock count
+LocalHandleEntry ENDS
+
+LocalFreeHandleEntry STRUC
+lhe_link DW ?
+lhe_free DW ?
+LocalFreeHandleEntry ENDS
+
+he_owner EQU he_address ; Discarded objects contain owner field
+ ; here so we know when to free handle
+ ; table entries of discarded objects.
+
+HE_DISCARDABLE EQU 00Fh ; Discard level of this object
+HE_DISCARDED EQU 040h ; Marks objects that have been discarded.
+
+HE_FREEHANDLE EQU 0FFFFh ; Use -1 to mark free handle table entries
+
+
+LHE_DISCARDABLE EQU 00Fh ; Discard level of this object
+LHE_DISCARDED EQU 040h ; Marks objects that have been discarded.
+LHE_USERFLAGS EQU 01Fh ; Mask for user setable flags
+
+LHE_FREEHANDLE EQU 0FFFFh ; Use -1 to mark free handle table entries
+
+
+HE_ALIGN = 4-1
+HE_MASK = NOT HE_ALIGN
+
+; Handles are allocated in blocks of N, where N is the hi_hdelta field
+; in the local heap information structure. The last word of each block
+; of handles is used to thread the blocks together, allowing all handles
+; to be enumerated. The first word of every block is the number of
+; handle table entries in the block. Not only does it save us code
+; in henum, but it also has the convenient property of placing all
+; handle entries on 2 byte boundaries (i.e. 2, 6, 10, 14), since the
+; LA_MOVEABLE bit is 02h. Thus the address of the he_address field of
+; a handle table entry is also the address of the handle table entry
+; itself.
+
+HandleTable STRUC
+ht_count DW ? ; # handletable entries in this block
+ht_entry DB SIZE HandleEntry DUP (?)
+HandleTable ENDS
+
+LocalHandleTable STRUC
+lht_count DW ? ; # handletable entries in this block
+lht_entry DB SIZE LocalHandleEntry DUP (?)
+LocalHandleTable ENDS
+
+; Local arena objects are kept in a doubly linked list.
+
+LocalArena STRUC
+la_prev DW ? ; previous arena entry (first entry points to self)
+la_next DW ? ; next arena entry (last entry points to self)
+la_handle DW ? ; back link to handle table entry
+LocalArena ENDS
+la_fixedsize = la_handle ; Fixed arena headers stop here
+
+LA_MINBLOCKSIZE = la_fixedsize*4 ;*** This must be larger than LocalArenaFree
+
+; free blocks have these extra items.
+la_size = la_handle ; size of block (includes header data)
+LocalArenaFree STRUC
+ DB SIZE LocalArena DUP (?)
+la_free_prev DW ? ; previous free entry
+la_free_next DW ? ; next free entry
+LocalArenaFree ENDS
+la_freefixedsize = SIZE LocalArenaFree ; Free block header stops here
+
+; Local arena objects are aligned on 4 byte boundaries, leaving the
+; low order two bits always zero.
+
+LA_ALIGN = 4-1
+LA_MASK = NOT LA_ALIGN
+LA_FREE = 00h
+LA_BUSY = 01h ; Saved in la_prev field of header
+errnz <LA_ALIGN - LA_MOVEABLE - LA_BUSY>
+
+
+; Flags passed to LocalAlloc (zero is the default case)
+
+LA_MOVEABLE EQU 02h ; Saved in la_prev field of header
+LA_NOCOMPACT EQU 10h
+LA_ZEROINIT EQU 40h
+LA_MODIFY EQU 80h
+
+
+; Data structure that describes the local arena. Allocated as the first
+; object in each local heap. _pLocalHeap is a reserved location each
+; automatic data segment that contains the pointer to this structure.
+
+LocalInfo STRUC
+ DB SIZE HeapInfo DUP (?)
+li_notify DD ? ; Far proc to call whenever a local block is moved
+li_lock DW ? ; arena lock word
+li_extra DW ? ; minimum amount to grow DS by
+li_minsize DW ? ; minimum size of heap
+li_sig DW ? ; signature for local heap
+LocalInfo ENDS
+
+; Notify procedure message codes
+
+LN_OUTOFMEM = 0 ; Out of memory - arg1 = #bytes needed
+LN_MOVE = 1 ; Object moved - arg1 = handle arg2 = old location
+LN_DISCARD = 2 ; Object discard? - arg1 = handle, arg2 = discard flags
+ ; Returns new discard flags in AX
+
+LocalStats STRUC
+ls_ljoin DW ? ; #calls to ljoin
+ls_falloc DW ? ; #calls to lalloc with forward search
+ls_fexamine DW ? ; #arena entries examined by ls_falloc calls
+ls_fcompact DW ? ; #calls to lcompact by ls_falloc calls
+ls_ffound DW ? ; #ls_falloc calls that found a block
+ls_ffoundne DW ? ; #ls_falloc calls that failed to find a block
+ls_malloc DW ? ; #calls to lalloc with backward search
+ls_mexamine DW ? ; #arena entries examined by ls_malloc calls
+ls_mcompact DW ? ; #calls to lcompact by ls_malloc calls
+ls_mfound DW ? ; #ls_malloc calls that found a block
+ls_mfoundne DW ? ; #ls_malloc calls that failed to find a block
+ls_fail DW ? ; #times lalloc failed because unable to grow DS
+ls_lcompact DW ? ; #calls to lcompact
+ls_cloop DW ? ; #repeated compacts after discarding
+ls_cexamine DW ? ; #entries examined in compaction loop
+ls_cfree DW ? ; #free entries examined in compaction loop
+ls_cmove DW ? ; #moveable entries moved by compaction
+LocalStats ENDS
+
+
+IncLocalStat MACRO n
+if KDEBUG
+inc ds:[di+SIZE LocalInfo].&n
+endif
+ENDM
+
+; Global arena objects are kept in a doubly linked list.
+;
+ifdef WOWJUNK
+GlobalArena STRUC
+ga_count DB ? ; lock count for movable segments
+ga_flags DB ? ; 1 byte available for flags
+ga_owner DW ? ; DOS 2.x 3.x owner field (current task)
+ga_size DW ? ; DOS 2.x 3.x size, in paragraphs, not incl. header
+ga_prev DW ? ; previous arena entry (first points to self)
+ga_next DW ? ; next arena entry (last points to self)
+ga_handle DW ? ; back link to handle table entry
+ga_lruprev DW ? ; Previous handle in lru chain
+ga_lrunext DW ? ; Next handle in lru chain
+GlobalArena ENDS
+else
+GlobalArena STRUC
+ga_count DB ? ; lock count for movable segments
+ga_owner DW ? ; DOS 2.x 3.x owner field (current task)
+ga_size DW ? ; DOS 2.x 3.x size, in paragraphs, not incl. header
+ga_flags DB ? ; 1 byte available for flags
+ga_prev DW ? ; previous arena entry (first points to self)
+ga_next DW ? ; next arena entry (last points to self)
+ga_handle DW ? ; back link to handle table entry
+ga_lruprev DW ? ; Previous handle in lru chain
+ga_lrunext DW ? ; Next handle in lru chain
+GlobalArena ENDS
+endif; WOW
+ga_sig = byte ptr ga_count ; DOS =< 3.x signature byte for fixed segs
+
+ga_freeprev = word ptr ga_lruprev ; links for free segs
+ga_freenext = word ptr ga_lrunext ; links for free segs
+
+if PMODE32
+
+DEFAULT_ARENA_SIZE equ 8000h ; Initial length of arena array
+;
+; 32 bit Protect Mode Arena
+;
+GlobalArena32 STRUC
+pga_next DD ? ; next arena entry (last points to self)
+pga_prev DD ? ; previous arena entry (first points to self)
+pga_address DD ? ; 32 bit linear address of memory
+pga_size DD ? ; 32 bit size in bytes
+pga_handle DW ? ; back link to handle table entry
+pga_owner DW ? ; Owner field (current task)
+pga_count DB ? ; lock count for movable segments
+pga_pglock DB ? ; # times page locked
+pga_flags DB ? ; 1 word available for flags
+pga_selcount DB ? ; Number of selectors allocated
+pga_lruprev DD ? ; Previous entry in lru chain
+pga_lrunext DD ? ; Next entry in lru chain
+GlobalArena32 ENDS
+
+.ERRNZ 32-size GlobalArena32
+
+pga_sig = word ptr pga_count
+
+pga_freeprev = dword ptr pga_lruprev ; links for free segs
+pga_freenext = dword ptr pga_lrunext ; links for free segs
+
+endif ; PMODE32
+
+GA_SIGNATURE = 04Dh
+GA_ENDSIG = 05Ah
+
+; there are many special kinds of blocks, marked in the owner word
+
+GA_SENTINAL = -1 ; a sentinal block
+GA_BOGUS_BLOCK = -7 ; a block temporary marked allocated
+GA_BURGERMASTER = -3 ; the master object
+GA_NOT_THERE = -4 ; used with EEMS to link out unallocatable
+ ; memory such as the EGA etc.
+GA_PHANTOM = -5 ; A block that has no EMS banks banked in.
+GA_WRAITH = -6 ; A block used to hold up partition headers.
+
+; Global arena objects are aligned on 2 para. boundaries, leaving the
+; low order bit always zero.
+
+GA_ALIGN = 2-1
+GA_MASK = NOT GA_ALIGN
+GA_FIXED = 1
+
+; It is specific to WOW only. This handle was generated by WIN32, ChandanC.
+
+GA_WOWHANDLE = 3
+
+errnz <GA_FIXED-GA_ALIGN>
+
+; Low byte of flags passed to GlobalAlloc (zero is the default case)
+
+GA_ALLOCHIGH EQU 01h ; Flag to indicate allocate high
+GA_MOVEABLE EQU 02h
+GA_SEGTYPE EQU 0Ch ; These 2 bits stored in he_flags field
+GA_DGROUP EQU 04h
+GA_DISCCODE EQU 08h
+GA_NOCOMPACT EQU 10h
+GA_NODISCARD EQU 20h
+GA_ZEROINIT EQU 40h
+GA_MODIFY EQU 80h
+
+GA_NEWEXPANDED EQU 80h ; Use new EMS allocation scheme
+
+; These flags for use by KERNEL only (caller's CS must match)
+
+GA_INTFLAGS = GA_ALLOCHIGH+GA_SEGTYPE or (GA_CODE_DATA+GA_ALLOC_DOS) shl 8
+
+; High byte of flags remembered in handle table (he_flags field)
+
+GA_DISCARDABLE EQU 01h ; Boolean flag for global object, not a level.
+GA_CODE_DATA EQU 02h ; CODE or DATA seg that belongs to a task.
+;GA_DGROUP EQU 04h
+;GA_DISCCODE EQU 08h
+GA_ALLOC_LOW EQU 10h ; Alloc in Lower land, overrides GA_ALLOC_EMS
+GA_SHAREABLE EQU 20h ; Shareable object
+GA_DDESHARE EQU 20h ; A shared memory object used for DDE.
+;HE_DISCARDED EQU 40h ; Marks objects that have been discarded.
+;GAH_NOTIFY EQU 40h
+GA_ALLOC_DOS EQU 80h ; Alloc in DOS land if protected mode
+
+GA_USERFLAGS = GA_SHAREABLE + GA_DISCARDABLE
+
+; Flags stored in the global arena header
+
+GAH_PHANTOM EQU 01h ; This block is either a phantom or a wraith
+GAH_DONT_GROW EQU 02h ; Don't grow this data segment.
+GAH_DGROUP EQU GA_DGROUP
+GAH_DISCCODE EQU GA_DISCCODE
+GAH_NOTIFY EQU 40h
+GAH_FIXED EQU 80h
+
+GAH_CURSORICON EQU 10h ; WOW uses this flag
+
+;
+; GAH_PHANTOM is unused in Win 3.0 and Win 3.1
+; ChandanC
+;
+GAH_WOWDDEFREEHANDLE EQU GAH_PHANTOM ; This is used to mark the DDE handle
+
+;
+; Global Memory Stats definitions
+; Offsets in array
+;
+cGLOBALALLOC EQU 0
+cGLOBALREALLOC EQU 4
+cGLOBALFREE EQU 8
+cGLOBALFREEALL EQU 12
+cGLOBALLOCK EQU 16
+cGLOBALUNLOCK EQU 20
+cGLOBALSIZE EQU 24
+cGLOBALCOMPACT EQU 28
+cLOCKSEGMENT EQU 32
+cUNLOCKSEGMENT EQU 36
+cGLOBALFIX EQU 40
+cGLOBALUNFIX EQU 44
+cGLOBALHANDLE EQU 48
+cGLOBALFLAGS EQU 52
+NGLOBALSTATS EQU (56/4)
+
+; Data structure that describes the global arena. Allocated at the end
+; of the local heap information structure. DO NOT CHANGE THE ORDER OF
+; THE ENTRIES! The alt sequence and normal sequence must match!
+
+GlobalInfo STRUC
+ DB SIZE HeapInfo DUP (?)
+gi_lrulock DW ? ; Lock out access to LRU chain from interrupt level
+ife PMODE32
+gi_lruchain DW ? ; First handle in lru chain (most recently used)
+else
+gi_lruchain DD ? ; First handle in lru chain (most recently used)
+endif
+gi_lrucount DW ? ; #entries in LRU chain
+ife PMODE32
+gi_reserve DW ? ; #paras to reserve for disc code, 0 => not enabled
+gi_disfence DW ? ; Fence for discardable code.
+else
+gi_reserve DD ? ; #paras to reserve for disc code, 0 => not enabled
+gi_disfence DD ? ; Fence for discardable code.
+endif
+gi_free_count DW ? ; Count of all the free partitions.
+
+gi_alt_first DW ? ; first entry in alternate arena
+gi_alt_last DW ? ; last entry in alternate arena
+gi_alt_count DW ? ; count of entries in alternate arena
+gi_alt_lruchain DW ? ; First handle in lru chain (most recently used)
+gi_alt_lrucount DW ? ; #entries in LRU chain
+gi_alt_reserve DW ? ; alternate reserve
+gi_alt_disfence DW ? ; Fence for discardable code.
+gi_alt_free_count DW ? ; Count of all the free partitions.
+gi_alt_pPhantom DW ? ; Pointer to the first pPhantom block.
+gi_disfence_hi DW ? ; High word of fence
+gi_flags DW ? ; some flags! !!! should merge with freeze and check
+gi_stats DD NGLOBALSTATS dup(?)
+GlobalInfo ENDS
+gi_cmpflags = byte ptr hi_dislevel ; Flags to control gcompact
+gi_disfence_lo = word ptr gi_disfence
+
+GIF_INT2 EQU 01h
+
+BOOT_COMPACT EQU 80h
+COMPACT_ALLOC EQU 40h ; Fast abort in gcompact for allocations
+
+CMP_FLAGS EQU GA_NODISCARD or GA_NOCOMPACT or GA_DISCCODE or COMPACT_ALLOC
+
+; Notify procedure message codes
+
+GN_MOVE = 1 ; Object moved - arg1 = handle arg2 = old location
+GN_DISCARD = 2 ; Object discard? - arg1 = handle, arg2 = discard flags
+ ; Returns new discard flags in AX
+
+SASTRUC STRUC
+sa_size dw 0 ; size, in bytes, of the alias list
+sa_allocated dw 0 ; number of allocated entries
+SASTRUC ENDS
+
+SAENTRY STRUC
+sae_sel dw 0 ; selector of the object
+sae_alias dw 0 ; alias of the object
+SAENTRY ENDS
+
+MAXFHCACHELEN = 12 ; Max number of file handles cached
+MINFHCACHELEN = 2 ; Min number of file handles cached
+
+fhCacheStruc struc
+ Cachefh dw ? ; File handle
+ CacheExe dw ? ; Exe handle
+fhCacheStruc ends
+
+; NAMETBL is a structure defining a private resource called a name table.
+; It is a resource that maps string resource types and names into unique
+; ordinal ids - this way all resources identified by name or type with
+; a string can actually be loaded by id. This is for OS/2 compatibility
+; with named resources.
+;
+; typedef struct nametbl { /* ntbl */
+; int cbEntry; /* size of structure */
+; int idType; /* type id or string replc if (idType & RSORDID) */
+; int idName; /* name id or string replc if (idName & RSORDID) */
+; char achTypeName[1]; /* 0 term type followed by 0 term name */
+; } NAMETBL;
+ntbl struc
+ ntbl_cbEntry dw ?
+ ntbl_idType dw ?
+ ntbl_idName dw ?
+ ntbl_achTypeName db ?
+ntbl ends
+
+RT_NAMETABLE equ 15
+
+ifdef WOW
+if PMODE32
+PAGE_READWRITE EQU 0004h
+MEM_COMMIT EQU 1000h
+MEM_RESERVE EQU 2000h
+MEM_RELEASE EQU 8000h
+MEM_COMMIT_RESERVE EQU 3000h
+endif
+endif
+
+ifdef WOW
+ife PMODE32
+DpmiBlock struc
+ DBSize dw 0
+ DBSel dw 0
+ DBHandleLow dw 0
+ DBHandleHigh dw 0
+DpmiBlock ends
+NUM_DPMI_BLOCKS equ 20
+endif
+endif
+
+ifdef WOW_x86
+FLAT_SEL equ 23H
+endif
diff --git a/private/mvdm/wow16/kernel31/wow16cal.asm b/private/mvdm/wow16/kernel31/wow16cal.asm
new file mode 100644
index 000000000..13bcbfbe1
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/wow16cal.asm
@@ -0,0 +1,1418 @@
+ TITLE WOW16CAL.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WOW16CAL.ASM
+; Thunk router in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 25-Jan-1991 Jeff Parsons (jeffpar) Created.
+; 24-Apr-91 Matt Felton (mattfe) Incorporated into Kernel
+; 29-May-91 Matt Felton (mattfe) Added Multi-Tasking
+; 30-Apr-1992 Mike Tricker (MikeTri) Added MultiMedia callbacks
+;
+; .xlist
+ include kernel.inc
+ include tdb.inc
+ include dbgsvc.inc
+ include wow.inc
+ include dpmi.inc
+ include cmacros.inc
+
+; include NEW_SEG1 struc used in GetProcModule
+
+ include newexe.inc
+
+ .list
+
+ HACK16 equ 1 ;enable hacks
+
+.286p
+
+Entry macro name
+ ;align 16
+ public name
+ name&:
+ endm
+
+externFP SETCURSORICONFLAG
+externFP SETDDEHANDLEFLAG
+externFP LOCALALLOC
+externFP LOCALREALLOC
+externFP LOCALLOCK
+externFP LOCALHANDLE
+externFP LOCALUNLOCK
+externFP LOCALSIZE
+externFP LOCALFREE
+externFP LOCALINIT
+externFP LOCKSEGMENT
+externFP UNLOCKSEGMENT
+externFP GLOBALALLOC
+externFP GLOBALLOCK
+externFP GLOBALHANDLE
+externFP GLOBALUNLOCK
+externFP GLOBALSIZE
+externFP GLOBALFREE
+externFP FINDRESOURCE
+externFP LOADRESOURCE
+externFP FREERESOURCE
+externFP LOCKRESOURCE
+externFP SIZEOFRESOURCE
+externFP Int21Handler
+externFP IsBadReadPtr
+externFP GetSelectorLimit
+externFP GetExpWinVer
+externNP SwitchTask
+externNP WOW16TaskStarted
+externFP GetExePtr
+externFP GetModuleUsage
+externFP WOWGetFastAddress
+externFP WOWGetFastCbRetAddress
+externFP WowGetFlatAddressArray
+externFP WOWNotifyWOW32
+externFP GETMODULEHANDLE
+externFP GETPROCADDRESS
+externFP PrestoChangoSelector
+externFP GetModuleFileName
+externFP WinExec
+externW gdtdsc
+externW pLocalHeap
+externNP SetOwner
+externFP WowCheckUserGdi
+externFP GetExePtr
+externFP FatalExit
+
+sBegin NRESCODE
+externFP get_sel_flags
+externFP set_sel_for_dib
+externFP RestoreDib
+sEnd NRESCODE
+
+DataBegin
+externW wCurTaskSS
+externW wCurTaskBP
+externW Win_PDB ;MikeTri - extracting DOS PDB and SFT
+externD pFileTable
+externB fExitOnLastApp
+
+if PMODE
+externW THHOOK
+externD FastBop
+externD FastWOW
+externW FastWOWCS
+externD FastWOWCbRet
+externW FastWOWCbRetCS
+if PMODE32
+externD FlatAddressArray
+endif
+endif
+externW WOWFastBopping
+externW curTDB
+externW cur_drive_owner
+externW LockTDB
+externB num_tasks
+externW DebugWOW
+externW topPDB
+externW TraceOff
+externD pDosWowData
+
+UserModuleName DB 'USER.EXE', 0
+
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+apfnWOW16Func dw WOW16Return ;order MUST match RET_* (wow.h)
+ dw WOW16DebugReturn
+ dw WOW16Debug
+ dw WOW16WndProc
+ dw WOW16EnumFontProc
+ dw WOW16EnumWindowProc
+ dw WOW16LocalAlloc
+ dw WOW16LocalReAlloc
+ dw WOW16LocalLock
+ dw WOW16LocalUnlock
+ dw WOW16LocalSize
+ dw WOW16LocalFree
+ dw WOW16GlobalAllocLock
+ dw WOW16GlobalLock
+ dw WOW16GlobalUnlock
+ dw WOW16GlobalUnlockFree
+ dw WOW16FindResource
+ dw WOW16LoadResource
+ dw WOW16FreeResource
+ dw WOW16LockResource
+ dw WOW16GlobalUnlock ;there is no UnlockResource
+ dw WOW16SizeofResource
+ dw WOW16LockSegment
+ dw WOW16UnlockSegment
+ dw WOW16EnumMetaFileProc
+ dw WOW16TaskStartedTmp ; in Tasking.asm
+ dw WOW16HookProc
+ dw WOW16SubClassProc
+ dw WOW16LineDDAProc
+ dw WOW16GrayStringProc
+ dw WOW16ForceTaskExit
+ dw WOW16SetCurDir
+ dw WOW16EnumObjProc
+ dw WOW16SetCursorIconFlag
+ dw WOW16SetAbortProc
+ dw WOW16EnumPropsProc
+ dw WOW16ForceSegmentFault
+ dw 0 ;FREE
+ dw 0 ;FREE
+ dw 0 ;FREE
+ dw 0 ;FREE
+ dw 0 ;FREE
+ dw WOW16GetExePtr
+ dw 0 ; WOW16GetModuleUsage removed
+ dw WOW16ForceTaskFault
+ dw WOW16GetExpWinVer
+ dw WOW16GetCurDir
+ dw WOW16GetDosPDB
+ dw WOW16GetDosSFT
+ dw WOW16ForegroundIdle
+ dw WOW16WinsockBlockHook
+ dw WOW16SetDdeHandleFlag
+ dw WOW16ChangeSelector
+ dw WOW16GetModuleFilename
+ dw WOW16WordBreakProc
+ dw WOW16WinExec
+ dw WOW16WOWCallback16
+ dw WOW16GetDibSize
+ dw WOW16GetDibFlags
+ dw WOW16SetDibSel
+ dw WOW16FreeDibSel
+functableend equ $
+
+; the aRets table looks like this: ...retf, ...retf 2, ...retf 4, ...
+
+CRETENTRIES equ 020h
+; generate the retf n codetable
+
+ bytes = 0
+ REPT CRETENTRIES
+ align 8
+ IFE bytes
+aRets:
+ ENDIF
+ pop bx ;restore app BX
+ pop bp
+ add sp, 0ah ;pop thunk ret address, wCallID/lpfn, wArgs
+ retf bytes
+ bytes = bytes + 2
+ ENDM
+align 8
+rettableend equ $
+RETFCODESIZE equ (rettableend - aRets) / CRETENTRIES
+.errnz ((rettableend - aRets) AND 01h) ; complain if odd
+.erre (RETFCODESIZE EQ 08h)
+ ; if the size is not 8 bytes need to
+ ; change the code that indexes 'aRets'
+
+;----------------------------------------------------------------------------
+; these comments are a result of hard labour (so called 'fruits'
+; of hard labour)
+;
+; 1. If you make a change in VDMFRAME or similar such change, make sure
+; tasking.asm is in sync. pay attention to the labels wow16doneboot,
+; wow16taskstarted and the resetting of vf_wES (all in tasking.asm)
+;
+; 2. The general purpose registers es, bx, cx which are saved around the
+; the api thunks. LATER these have to be removed with care and caution.
+; If you just remove the push/pop of these, kernel31 won't boot.
+; These registers will have to be saved around certain calls in krnl286/386
+; for it to boot.
+;
+; - nanduri ramakrishna
+;
+;-----------------------------------------------------------------------------
+
+
+;-----------------------------------------------------------------------------
+; NOTES:
+;
+; the frame at time of bop is of type VDMFRAME
+; the frame at the time of a callback is CBVDMFRAME.
+; VDMFRAME and CBVDMFRAME share the first few fields (the order is important)
+; but the structures don't overlap.
+;
+; ie stack looks like this
+;
+; ss:sp = VDMFRAME
+; ... BOP ....
+; if return from BOP:
+; ss:sp = VDMFRAME
+; if from callback16:
+; ss:sp = CBVDMFRAME
+; .....callback function...
+; - nanduri ramakrishna
+;-----------------------------------------------------------------------------
+
+ assumes ds, nothing
+ assumes es, nothing
+
+align 16
+cProc WOW16Call,<PUBLIC,FAR>
+ ; parmW wArgs ; # paramater bytes pushed for this API
+ ; parmW wCallID
+
+
+; note that 'bp' of api thunk and callback differ
+
+ pFrame equ [bp-vf_wBP]
+ wAppBX equ [pFrame].vf_wBX
+ wApiRetID equ [pFrame].vf_wRetID
+ wAX equ [pFrame].vf_wAX
+ wArgs equ [pFrame].vf_cbArgs
+
+; for callback16
+
+ pCBFrame equ [bp-cvf_Parm16];
+ vpfnProc equ [pCBFrame].cvf_vpfnProc
+ hInst equ [pCBFrame+cvf_Parm16].wp_hInst
+ hwnd equ [pCBFrame+cvf_Parm16].wp_hwnd
+ wMsg equ [pCBFrame+cvf_Parm16].wp_wMsg
+ wParam equ [pCBFrame+cvf_Parm16].wp_wParam
+ lParam equ [pCBFrame+cvf_Parm16].wp_lParam
+
+ vpfnWndProc equ [di-cvf_Parm16].cvf_vpfnProc
+
+ cbackAX equ [pCBFrame].cvf_wAX ;
+ cbackDX equ [pCBFrame].cvf_wDX
+ wGenUse1 equ [pCBFrame].cvf_wGenUse1
+ wGenUse2 equ [pCBFrame].cvf_wGenUse2
+ vfSP equ [pCBFrame].cvf_vpStack ; lo word is sp = ptr to vdmframe
+
+; The stack frame here is defined in wow.h make sure they match
+; the order is very important.
+
+cBegin nogen
+
+wc_set_vdmframe:
+ push bp
+ mov bp, sp ; standard frame
+ push bx ; REMOVE LATER APPs BX
+ push es ; REMOVE LATER
+ push cx ; REMOVE LATER
+ifndef PM386
+ ; %OUT building 286
+ push ax ; dummy values for fs,gs in 286
+ push ax
+else
+.386
+ ; %OUT building 386
+ push fs
+ push gs
+.286
+endif
+ push ds
+ sub sp, 4 ; room for api dword return value
+ push si ; standard regs
+ push di
+
+WOW16ApiCall:
+ push bp
+ push RET_RETURN ;push default wRetID (do not move see tasking.asm)
+ SetKernelDS ds
+ push [curTDB] ;save current 16bit task handle (see tasking.asm)
+ mov di,ss
+ mov [wCurTaskSS],di ;save current task SS
+ mov [wCurTaskBP],bp ;save current task BP
+
+; We don't want to allow debuggers to trace into 32 bit land, since they
+; will get lost.
+
+ mov TraceOff,1h
+
+ test [WOWFastBopping], 0ffffh
+ jz WOW16SlowVector
+
+WOW16FastVector:
+
+.386
+ call fword ptr [FastWOW]
+.286
+ jmp short WOW16CallContinue
+
+ public WOW16SlowVector
+Entry WOW16SlowVector
+ BOP BOP_WOW
+
+ public WOW16CallContinue
+WOW16CallContinue: ; don't move this label! see comment below
+
+ SetKernelDS ds
+
+ xor ax,ax
+ xchg TraceOff,ax
+ test ax,2h ; Turn Tracing Back on ?
+ jnz turn_on_trace_bit
+
+W16C_010:
+; Check for Task Switch
+ pop ax ; retrieve current task ID
+ cmp ax, [curTDB] ; Task Switch ?
+ jnz jmpSwitchTask ; Yes -> Perform Task Switch
+
+ public WOW16CallNewTaskRet ; from tasking.asm
+WOW16CallNewTaskRet:
+
+ pop bx ;retrieve wRetID
+ pop bp ;localbp
+ cmp bx, RET_RETURN
+ jnz WOW16_From_CallBack16
+
+ public WOW16Return
+WOW16Return:
+
+ ; we don't want to return to the thunk, that's just going to
+ ; do a RETF n where n is the # of parameters to the API.
+ ; doing this takes about half the time of a RETF on a 486
+ ; according to the clock counts in the book. but RETF also flushes
+ ; the instruction prefetch queue, and we're touching one less page
+ ; (probably a TLB miss if we're coming back from a call with a long
+ ; code path).
+
+wc_restore_regs:
+
+ pop di
+ pop si
+ pop ax ;
+ pop dx
+ pop ds
+ifndef PM386
+ pop cx ; trash cx for two dumy words, as real cx is going
+ pop cx ; to be popped after this.
+else
+.386
+ pop gs
+ pop fs
+.286
+endif
+
+ pop cx ; REMOVE LATER
+ pop es ; REMOVE LATER
+ mov bx,wArgs ; get the # of bytes this API took
+if KDEBUG
+ or bx, bx
+ jz @F
+ test bx, 01h
+ jz @F
+ int 3 ; error. odd #bytes to pop
+@@:
+ cmp bx, CRETENTRIES * 2
+ jl @F
+ int 3 ; error. outside aRets tablerange
+@@:
+endif
+ shl bx, 2 ; convert it to offset into aRets table
+ add bx, codeoffset aRets
+ jmp bx ; dispatch to the right RETF n
+
+
+;
+; If a debugger was tracing the app then reenable on the 16 bit side again
+;
+
+turn_on_trace_bit:
+ pushf
+ pop ax
+ or ax,FLG_TRAP
+ push ax
+ popf
+ jmps W16C_010
+
+
+ public WOW16_From_CallBack16
+WOW16_From_CallBack16: ; exception RET_DEBUGRETURN and RET_TASKSTARTED
+ mov si, bp ; save bp, dont push on stack
+ mov bp, sp ; for convenience.
+
+ mov ax, ss
+ mov es, ax
+ mov ds, ax
+
+ mov ax, cbackAX ; for prolog initialization
+ add bx,bx
+ jmp apfnWOW16Func[bx] ;route to appropriate function handler
+
+
+ public WOW16DebugReturn
+Entry WOW16DebugReturn
+ ; undo the 'callback' munging
+ mov bp, si
+ int 3 ;that's all folks
+ jmps WOW16Return
+
+jmpSwitchTask:
+ jmp SwitchTask ; Go perform a Task Switch
+
+ public WOW16TaskStartedTmp
+Entry WOW16TaskStartedTmp
+ ; undo the 'callback' munging
+ mov bp, si
+
+ pop di
+ pop si
+ pop ax ;
+ pop dx
+ pop ds
+
+ifndef PM386
+ pop cx ; trash cx for two dumy words, as real cx is going
+ pop cx ; to be popped after this.
+else
+.386
+ pop gs
+ pop fs
+.286
+endif
+ pop cx ; REMOVE LATER
+ pop es ; REMOVE LATER
+ pop bx ; pop bx ; REMOVE LATER;
+ mov wApiRetID, RET_RETURN
+ jmp WOW16TaskStarted
+
+;
+; Call Back Routines
+; On entry, SS:SP points to PARM16 structure
+; Assumes PARM16 is followed by vpfn
+;
+
+ public WOW16WOWCallback16
+Entry WOW16WOWCallback16 ; 32-bit generic callback
+
+ call [vpfnProc] ; call the target proc
+ mov si, [wGenUse1] ; si = cbArgs
+ sub sp, si ; undo effect of "RET cbArgs"
+ jmp WOW16Done
+
+ public WOW16WndProc
+Entry WOW16WndProc
+
+; don't expect si and di to be saved by the callback function - so save the
+; critical info elsewhere like on stack.
+
+; we set 'si' to 'hwnd'. this fixes a bug in QuickCase (qcasew.exe) where
+; options.tools.add doesn't bring up a dialog box.
+;
+ mov cx,hwnd ;for later use
+ mov di,bp ;MSAccess debug version walks BP chain. they're
+ mov bp,si ; testing it for us, let's make it easier for them.
+ mov wAX,di ;save current bp in vdmframe.wAX - temporary
+ ;note:
+ ; current 'bp (ie di) = 'sp' ,also vdmFrame can be
+ ; accessed with the new 'bp' (ie 'si').
+ mov si,cx ;si has hwnd
+ call [vpfnWndProc] ;call the window proc (AX already set)
+ mov bp,wAX ;restore pre-callback bp
+ mov sp,bp ;restore pre-callback sp
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16EnumFontProc
+Entry WOW16EnumFontProc
+
+ call [vpfnProc] ;call the font proc
+ sub sp,size PARMEFP ;undo the effect of the proc's RET 0Eh
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16EnumObjProc
+Entry WOW16EnumObjProc
+ call [vpfnProc] ;call the obj proc
+ sub sp,size PARMEOP ;undo the effect of the proc's RET 0Eh
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16EnumWindowProc
+Entry WOW16EnumWindowProc
+ call [vpfnProc] ;call the font proc
+ sub sp,size PARMEWP ;undo the effect of the proc's RET 06h
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16LineDDAProc
+Entry WOW16LineDDAProc
+ call [vpfnProc] ;call the Line DDA proc
+ sub sp,size PARMDDA ;undo the effect of the proc's RET 0Eh
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16GrayStringProc
+Entry WOW16GrayStringProc
+ call [vpfnProc] ;call the Graystring proc
+ sub sp,size PARMGST ;undo the effect of the proc's RET 0Eh
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16EnumPropsProc
+Entry WOW16EnumPropsProc
+ call [vpfnProc] ;call the obj proc
+ sub sp,size PARMEPP ;undo the effect of the proc's RET
+ jmp WOW16Done ;call back to WOW32
+
+ public WOW16WordBreakProc
+Entry WOW16WordBreakProc
+ call [vpfnProc] ;call the wordbreak proc
+ sub sp,size PARMWBP ;undo the effect of the proc's RET
+ jmp WOW16Done ;call back to WOW32
+
+if 0
+;
+; MultiMedia callbacks - MikeTri 30-Apr-1992
+;
+
+Entry WOW16MidiInFunc
+ call [vpfnProc] ;call the MidiIn proc
+ sub sp,size PARMMIF ;undo the effect of the proc's RET 12h
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16MidiOutFunc
+ call [vpfnProc] ;call the MidiOut proc
+ sub sp,size PARMMOF ;undo the effect of the proc's RET 12h
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16IOProc
+ call [vpfnProc] ;call the MMIO proc
+ sub sp,size PARMIOP ;undo the effect of the proc's RET 0Eh
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16TimeFunc
+ call [vpfnProc] ;call the Time proc
+ sub sp,size PARMTIF ;undo the effect of the proc's RET 10h
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16WaveInFunc
+ call [vpfnProc] ;call the WaveIn proc
+ sub sp,size PARMWIF ;undo the effect of the proc's RET 12h
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16WaveOutFunc
+ call [vpfnProc] ;call the WaveOut proc
+ sub sp,size PARMWOF ;undo the effect of the proc's RET 12h
+ jmp WOW16Done ;call back to WOW32
+endif
+
+Entry WOW16LocalAlloc
+ mov ax,wMsg ; set up DS with hInstance
+ mov ds,ax
+
+ cmp ds:[pLocalHeap], 0 ; already have a local heap in this DS?
+ jnz @f ; yes
+
+ ; we need to LocalInit this segment
+ ; note: Win3.1 doesn't check return codes on GlobalSize, LocalInit
+
+ push ds
+ call far ptr GLOBALSIZE
+ sub ax, 64
+
+ push ds
+ push 0
+ push ax
+ call far ptr LOCALINIT
+
+ push ds
+ call far ptr UNLOCKSEGMENT
+
+@@:
+
+ push wParam ;push wFlags
+ push lParam.lo ;push wBytes
+ call far ptr LOCALALLOC ;get hmem in AX
+ mov dx,ds ; return DS in hiword of handle
+ jmp WOW16Done ;
+
+Entry WOW16LocalReAlloc
+ mov ax,lParam.hi ; set up DS with value from alloc
+ mov ds,ax
+
+ push lParam.lo ;push hMem
+ push wMsg ;push wBytes
+ push wParam ;push wFlags
+ call far ptr LOCALREALLOC;get hmem in AX
+ mov dx,ds ;hiword of handle=DS
+ jmp WOW16Done
+
+Entry WOW16LocalLock
+
+if 0
+
+; HACK32 remove this!
+
+ mov ax,lParam.hi ; set up DS with value from alloc
+ mov ds,ax
+
+ push lParam.lo ;push hMem
+ call far ptr LOCALLOCK ;
+ sub dx,dx ;
+ or ax,ax ;
+ jz short lalock_done ;
+ IFDEF HACK16
+ push ax
+ push -1
+ call far ptr LOCKSEGMENT
+ pop ax
+ ENDIF
+ mov dx,ds ;if success, return full address in DX:AX
+lalock_done: ;
+
+endif
+
+ jmp WOW16Done ;
+
+Entry WOW16LocalUnlock
+if 0
+
+; HACK32 remove this!
+
+ mov ax,lParam.hi ; set up DS with value from alloc
+ mov ds,ax
+
+ push lParam.lo ;push hMem
+ call far ptr LOCALUNLOCK ;
+ or ax,ax ;
+ jnz short lufree_done ;
+ IFDEF HACK16
+ push -1
+ call far ptr UNLOCKSEGMENT
+ sub ax,ax ;
+ ENDIF
+lufree_done: ;
+ cwd ;
+
+endif
+
+ jmp WOW16Done ;
+
+Entry WOW16LocalSize
+ mov ax,lParam.hi ; set up DS with value from alloc
+ mov ds,ax
+
+ push lParam.lo ;push hMem
+ call far ptr LOCALSIZE ;
+ sub dx,dx
+ jmp WOW16Done
+
+Entry WOW16LocalFree
+ mov ax,lParam.hi ; get selector of current local heap
+ push ax ; set up for call to IsBadReadPtr
+ push 0
+ push 1
+ call far ptr IsBadReadPtr ; is selector still valid?
+ or ax,ax
+ jnz wlf_done ; ax != 0 -> nope!
+
+ mov ax,lParam.hi ; set up DS with value from alloc
+ mov ds,ax
+
+ push lParam.lo ;push hMem
+ call far ptr LOCALFREE ;
+wlf_done:
+ jmp WOW16Done ;
+
+
+Entry WOW16GlobalAllocLock
+ push wParam ;push wFlags
+ push lParam.hi ;push dwBytes
+ push lParam.lo ;
+ call far ptr GLOBALALLOC ;get hmem in AX
+ sub dx,dx ;
+ or ax,ax ;
+ jz short galock_done ;
+ push ax ;save hmem
+ push ax ;push hmem
+ call far ptr GLOBALLOCK ;get seg:off in DX:AX
+ pop bx ;recover hmem in BX
+galock_done: ;
+ mov wGenUse1, bx
+ jmp WOW16Done ;
+
+Entry WOW16GlobalLock
+ push wParam ;push hMem
+ call far ptr GLOBALLOCK ;
+ push ax ;save return value
+ push dx ;
+ or ax,dx
+ jz glock_exit
+ push wParam ;push hMem
+ call far ptr GLOBALSIZE ;
+glock_exit:
+ mov wGenUse2,ax ;save size
+ mov wGenUse1,dx ;
+ pop dx ;
+ pop ax ;
+ jmp WOW16Done ;
+
+Entry WOW16GlobalUnlock
+ push wParam ;push hMem
+ call far ptr GLOBALUNLOCK;
+ cmp ax,1 ;
+ sbb ax,ax ;
+ cwd ;make return code a full 32-bits
+ jmp WOW16Done ;
+
+Entry WOW16GlobalUnlockFree
+ push lParam.hi ;push segment of address to free
+ call far ptr GLOBALHANDLE;
+ or dx,ax ;valid handle?
+ jz short gufree_done ;no
+ push ax ;save a copy of hmem for the free
+ push ax ;push hmem to unlock
+ call far ptr GLOBALUNLOCK;
+ pop cx ;recover copy of hmem
+ or ax,ax ;is lock count now zero?
+ jnz short gufree_err ;no
+ push cx ;push hmem to free
+ call far ptr GLOBALFREE ;
+gufree_exit: ;
+ or ax,ax ;
+ mov ax,1 ;if success, return TRUE; otherwise, FALSE
+ jz short gufree_done ;
+gufree_err: ;
+ sub ax,ax ;
+gufree_done: ;
+ cwd ;
+ jmp WOW16Done ;
+
+Entry WOW16FindResource
+ push wParam ;push hTask
+ call far ptr GetExpWinVer
+ push ax ;save expwinver
+
+ push wParam ;push hTask
+ push lParam.hi ;push vpName
+ push lParam.lo ;
+ push hwnd ;push vpType
+ push wMsg ;
+ call far ptr FINDRESOURCE;
+; or ax,ax ;
+; jz short findres_done ;
+;findres_done: ;
+ cwd ;make return code a full 32-bits
+ pop cx ; expwinver
+ mov wGenUse1, cx
+ jmp WOW16Done ;
+
+Entry WOW16LoadResource
+ push wParam ;push hTask
+ push lParam.lo ;push hResInfo
+ call far ptr LOADRESOURCE;
+ cwd ;make return code a full 32-bits
+ jmp WOW16Done ;
+
+Entry WOW16FreeResource
+ push wParam ;push hResData
+ call far ptr FREERESOURCE;
+ cmp ax,1
+ sbb ax,ax
+ cwd ;make return code a full 32-bits
+ jmp WOW16Done
+
+Entry WOW16LockResource
+ push wParam ;hResData
+ call far ptr LOCKRESOURCE;
+ push ax ; save res pointer
+ push dx
+ or dx,dx
+ jz lres_exit
+ push wParam ;push hResData
+ call far ptr GLOBALSIZE
+lres_exit:
+ mov wGenUse2,ax ;save size
+ mov wGenUse1,dx ;
+ pop dx
+ pop ax
+ jmp WOW16Done
+
+Entry WOW16SizeofResource
+ push wParam ;push hTask
+ push lParam.lo ;push hResInfo
+ call far ptr SIZEOFRESOURCE ; DX:AX is DWORD size
+ jmp WOW16Done
+
+Entry WOW16LockSegment
+ push wParam ;push wSeg
+ call far ptr LOCKSEGMENT
+ sub dx,dx
+ jmp WOW16Done
+
+Entry WOW16UnlockSegment
+ push wParam ;push wSeg
+ call far ptr UNLOCKSEGMENT
+ cmp ax,1
+ sbb ax,ax
+ cwd ;make return code a full 32-bits
+ jmp WOW16Done
+
+;MikeTri Beginning of temporary hack for testing - 17-Aug-1992
+
+Entry WOW16GetDosPDB
+ push ds ;Save DS
+ SetKernelDS ;Pick up Kernel DS
+ mov dx, Win_PDB ;Copy Windows PDB to DX (selector)
+ mov ax,0 ;Move 0 to AX (offset)
+ UnSetKernelDS ;Get rid of kernel DS
+ pop ds ;Restore callers DS
+ jmp WOW16Done ;Exit
+
+Entry WOW16GetDosSFT
+ push ds ;Save DS
+ SetKernelDS ;Pick up Kernel DS
+ mov dx,pFileTable.sel ;Move SFT selector value to DX
+ mov ax,pFileTable.off ;Move SFT offset value to AX
+ UnSetKernelDS ;Get rid of kernel DS
+ pop ds ;Restore callers DS
+ jmp WOW16Done
+
+;MikeTri End of temporary hack for testing - 17-Aug-1992
+
+Entry WOW16EnumMetaFileProc
+ call [vpfnProc] ;call the apps MetaFile proc
+ sub sp,size PARMEMP ;undo the effect of the proc's RET 0x10h
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16HookProc
+
+ call [vpfnProc] ;call the apps Hook Proc.
+ sub sp,size PARMHKP ;undo the effect of the proc's RET 0x08h
+ jmp WOW16Done ;call back to WOW32
+
+
+Entry WOW16SetAbortProc
+ call [vpfnProc] ;call the apps abort proc
+; sub sp,size PARMSAP ;undo the effect of the proc's RET 0x04h
+;
+; Use 'bp' to restore 'sp' instead of subtracting 4bytes from sp. this is
+; because Wordperfect's Informs doesn't pop the arguments off the stack.
+; However it preserves 'bp'.
+;
+; Here in wow, sp is same as bp . The correct value is in 'bp' - see
+; WOW16_From_CallBack16
+;
+; Similar fix can also be found in win31 - core\gdi, function queryabort()
+;
+; - nandurir
+;
+
+ mov sp, bp
+ jmp WOW16Done ;call back to WOW32
+
+
+Entry WOW16SubClassProc
+
+ push ds
+ SetKernelDS ds
+ push ds
+ push dataoffset UserModuleName
+ call GETMODULEHANDLE
+ pop ds ; restore ds
+ UnSetKernelDS ds
+ pop cx ; cx = the ordinal number
+ push cx ; restore stack pointer
+ push ax ; hModule
+ push 0 ; hiword of ordinal number
+ push cx ; the ordinal
+ call GetProcAddress
+ jmp WOW16Done ;call back to WOW32
+
+Entry WOW16SetCurDir
+ call SetCurrentDrive ; on the stack is drive number;
+ call SetCurrentDirectory ; on the stack is directory name;
+ sub sp,size PARMDIR ; restore stack
+ jmp WOW16Done ;call back to WOW32
+
+
+Entry WOW16SetDdeHandleFlag
+ push wParam ;push hMem
+ push wMsg ;push fSet
+ call far ptr SETDDEHANDLEFLAG
+ jmp WOW16Done ;
+
+
+Entry WOW16SetCursorIconFlag
+ push wParam ;push hMem
+ push wMsg ;push fSet
+ call far ptr SETCURSORICONFLAG
+ jmp WOW16Done ;
+
+
+Entry WOW16GetExePtr
+ push wParam ;push hInstance
+ call GetExePtr
+ jmp WOW16Done
+
+
+Entry WOW16ForceTaskExit
+ mov ax,4CFFH ; Hung App Support Forces Current Task to Exit
+ DOSCALL
+ INT3_NEVER
+
+Entry WOW16GetModuleFilename
+ push wParam ; hInstance
+ push lParam.hi ; selector of filename buffer
+ push lParam.lo ; offset of filename buffer
+ push wMsg ; bytes in filename buffer
+ call far ptr GetModuleFileName
+ jmp WOW16Done ; Just return return value
+
+Entry WOW16WinExec
+ push lParam.hi ; selector of lpszCmdLine
+ push lParam.lo ; offset of lpszCmdLine
+ push wParam ; fuCmdShow
+ call far ptr WinExec
+ jmp WOW16Done ; Just return return value
+
+Entry WOW16GetExpWinVer
+ push wParam ;push hInstance
+ call GetExpWinVer
+ jmps WOW16Done
+
+Entry WOW16GetCurDir
+ call GetCurrentDirectory ;
+ sub sp,size PARMDIR ; restore stack
+ jmps WOW16Done ;call back to WOW32
+
+
+Entry WOW16ForceTaskFault
+ ; %OUT Ignore Impure warning A4100 its required for Forcing a GP Fault
+ mov cs:gdtdsc,0 ; Force a GP Fault - Write to our CS
+ jmp WOW16ForceTaskFault
+
+Entry WOW16ForceSegmentFault
+ push lParam.hi ; selector of lp
+ push lParam.lo ; offset of lp
+ push 1 ; min byte size
+ call far ptr IsBadReadPtr ; force segment fault or handle GPF
+ jmps WOW16Done
+
+Entry WOW16ForegroundIdle
+ mov ax,1689h ;notify application that the foreground
+ int 2fh ;task has gone idle
+ jmps WOW16Done
+
+Entry WOW16WinsockBlockHook
+ call [vpfnProc] ;call the apps Hook Proc.
+ jmps WOW16Done ;call back to WOW32
+
+Entry WOW16ChangeSelector
+ push wParam ;push wSeg
+ push wParam ;push wSeg
+ call far ptr PRESTOCHANGOSELECTOR;
+ cCall SetOwner,<wParam,-1> ; Make this new guy the owner
+ jmps WOW16Done ; Just return return value
+
+Entry WOW16GetDibSize
+ push wParam ; selector for which size is being queryed
+ call far ptr GetSelectorLimit
+ jmps WOW16Done ; Just return return value
+
+Entry WOW16GetDibFlags
+ cCall get_sel_flags,<wParam>
+ jmps WOW16Done ; Just return return value
+
+Entry WOW16SetDibSel
+ cCall set_sel_for_dib,<wParam,wMsg,lParam.lo,lParam.hi,hwnd>
+ jmps WOW16Done ; Just return return value
+
+Entry WOW16FreeDibSel
+ cCall RestoreDib,<wParam,wMsg,lParam.hi,lParam.lo>
+ jmps WOW16Done ; Just return return value
+
+Entry WOW16Debug
+ int 3 ;that's all folks
+ ;fall into WOW16Done
+
+Entry WOW16Done
+ mov cbackAX, ax ; set return value
+ mov cbackDX, dx
+ mov bp, word ptr vfSP
+ mov [bp].vf_wES, es ; update es to avoid GP. A HACK
+ mov bp, [bp].vf_wLocalBP
+
+ ; fall thru. the return values are set for a 'real' callback only
+ ; don't use 'entry' macro for wow16doneboot as it 'align 16s' the label
+ ; thus putting extra instructions between cbackDx, dx and mov bp,si.
+
+ public WOW16DoneBoot ; tasking.asm needs this label
+WOW16DoneBoot: ; tasking.asm needs this label
+ push bp ;rebuild the frame
+ push RET_RETURN ;push default wRetID (do not move see tasking.asm)
+ SetKernelDS ds
+ push [curTDB] ;save current 16bit task handle (see tasking.asm)
+ mov [wCurTaskSS],ss ;save current task SS
+ mov [wCurTaskBP],bp ;save current task BP
+ mov TraceOff,1h ; Don't allow debuggers to trace to 32 bit land
+
+ test [FastWOWCbRetCS], 0ffffh
+ jz WOW16SlowCBReturn
+
+.386
+ call fword ptr [FastWOWCbRet]
+.286
+
+ ; don't put any code here!!!
+ ; when fastbopping, after kernel has booted we return
+ ; directly to WOW16CallContinue
+
+ jmp WOW16CallContinue
+
+
+WOW16SlowCBReturn:
+
+ IFE PMODE
+ BOP BOP_UNSIMULATE ;return from host_simulate
+ ELSE
+ FBOP BOP_UNSIMULATE,,FastBop
+ ENDIF
+
+ jmp WOW16CallContinue
+
+cEnd nogen ; WOW16Call
+
+
+
+;
+; Initialize address of fast Bop entry to monitor.
+;
+cProc WOWFastBopInit,<PUBLIC,FAR>
+cBegin
+IF PMODE
+ push ds
+ push es
+ push bx
+ push dx
+
+ DPMIBOP GetFastBopAddress
+ CheckKernelDS ds ; On debug, check that DS is really kernels
+ ReSetKernelDS ds ; Assume it otherwise.
+ ;
+ ; Set up FastBop address (for DPMI, and WOW without WOW16FastVector)
+
+ mov word ptr [FastBop],bx
+ mov word ptr [FastBop + 2],dx
+ mov word ptr [FastBop + 4],es
+ or bx,dx
+ jz NoFastWow
+
+ call far ptr WOWGetFastAddress
+ mov word ptr [FastWOW],ax
+ mov word ptr [FastWOW+2],dx
+
+ or ax,dx
+ jz NoFastWow
+
+ mov word ptr [FastWOWCS],es
+ mov word ptr [WOWFastBopping],1
+
+ call far ptr WOWGetFastCbRetAddress
+ mov word ptr [FastWOWCbRet],ax
+ mov word ptr [FastWOWCbRet+2],dx
+
+ or ax,dx
+ jz NoFastCb
+
+ mov word ptr [FastWOWCbRetCS],es
+
+if PMODE32
+ call far ptr WowGetFlatAddressArray
+ mov word ptr [FlatAddressArray],ax
+ mov word ptr [FlatAddressArray + 2],dx
+endif
+NoFastCb:
+NoFastWow:
+
+ pop dx
+ pop bx
+ pop es
+ pop ds
+ UnSetKernelDS ds
+ENDIF
+cEnd WOWFastBopInit
+
+cProc WOWNotifyTHHOOK,<PUBLIC,FAR>
+cBegin
+ CheckKernelDS ds
+ ReSetKernelDS ds
+
+ mov DebugWOW,0
+
+if PMODE32
+ push 1
+else
+ push 0
+endif
+ push seg THHOOK
+ push offset THHOOK
+ push DBG_TOOLHELP
+ FBOP BOP_DEBUGGER,,FastBop
+ add sp,+8
+
+ push seg cur_drive_owner
+ push offset cur_drive_owner
+
+ push topPDB
+ push 0
+
+ push seg LockTDB
+ push offset LockTDB
+
+ push seg DebugWOW
+ push offset DebugWOW
+
+ push seg curTDB
+ push offset curTDB
+
+ push seg num_tasks
+ push offset num_tasks
+
+ push codeBase
+ push codeOffset Int21Handler
+
+ call WOWNotifyWOW32
+
+ UnSetKernelDS ds
+cEnd WOWNotifyTHHOOK
+
+cProc WOWQueryDebug,<PUBLIC,FAR>
+cBegin
+ push ds
+
+ SetKernelDS
+
+ mov ax,DebugWOW
+
+ pop ds
+ UnSetKernelDS
+
+cEnd WOWQueryDebug
+
+
+;*--------------------------------------------------------------------------*
+;*
+;* GetCurrentDirectory() -
+;*
+;* - Drive =0 implies 'current' drive.
+;*--------------------------------------------------------------------------*
+cProc GetCurrentDirectory, <NEAR, PUBLIC>, <SI, DI>
+
+ParmD lpDest
+ParmW Drive
+
+cBegin
+ push ds ; Preserve DS
+ les di,lpDest ; ES:DI = lpDest
+ push es
+ pop ds ; DS:DI = lpDest
+ cld
+ mov ax,Drive ; AX = Drive
+ or al,al ; Zero?
+ jnz CDGotDrive ; Yup, skip
+ mov ah,19h ; Get Current Disk
+ DOSCALL
+ inc al ; Convert to logical drive number
+CDGotDrive:
+ mov dl,al ; DL = Logical Drive Number
+ add al, 040h ; drive letter
+ mov ah, 03Ah ; ':'
+ stosw
+ mov al,'\' ; Start string with a backslash
+ stosb
+ mov byte ptr es:[di],0 ; Null terminate in case of error
+ mov si,di ; DS:SI = lpDest[1]
+ mov ah,47h ; Get Current Directory
+ DOSCALL
+ jc CDExit ; Skip if error
+ xor ax,ax ; Return FALSE if no error
+CDExit:
+ pop ds ; Restore DS
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetCurrentDirectory() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc SetCurrentDirectory, <NEAR, PUBLIC>,<si,di>
+
+ParmD lpDirName
+
+cBegin
+ push ds ; Preserve DS
+ lds dx,lpDirName ; DS:DX = lpDirName
+ mov ah,3Bh ; Change Current Directory
+ DOSCALL
+ jc SCDExit ; Skip on error
+ xor ax,ax ; Return FALSE if successful
+SCDExit:
+ pop ds ; Restore DS
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetCurrentDrive() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Returns the number of drives in AX.
+
+cProc SetCurrentDrive, <NEAR, PUBLIC>,<si,di>
+
+ParmW Drive
+
+cBegin
+ mov dx,Drive
+ mov ah,0Eh ; Set Current Drive
+ DOSCALL
+ sub ah,ah ; Zero out AH
+cEnd
+
+
+; --- GetTaskHandle0 ---
+; ripped out piece of GetTaskHandle, taken from CONTEXT.ASM which was not
+; part of WOW's kernel, so we copied this little piece out.
+;
+
+GetTaskHandle0:
+ or ax,ax
+ jnz gt1
+ SetKernelDS es
+ mov ax,curTDB
+gt1: mov es,ax
+ assumes es, nothing
+; cmp es:[TDB_sig],TDB_SIGNATURE
+; jne gt2
+ ret
+;gt2: kerror ERR_TASKID,<GetTaskHandle: Invalid task handle>
+; ret
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* WowSetExitOnLastApp(WORD fExitOnLastApp) *
+;* Sets fExitOnLastApp variable which causes kernel to exit when the *
+;* last app except WowExec exits. Called by WowExec for seperate *
+;* WOW VDMs, which need to exit after the last app closes. *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc WowSetExitOnLastApp, <PUBLIC, FAR>
+
+ParmW fExit
+
+cBegin
+ SetKernelDS
+
+ mov ax, fExit
+ mov fExitOnLastApp, al
+cEnd
+
+;-----------------------------------------------------------------------;
+; WowFixWin32CurDir
+;
+; Called by thunks for PrivateProfile APIs which need Win32 current
+; directory to reflect Win16 current directory (imagine that!)
+;
+; Trashes AX, DX which shouldn't matter
+;
+; History:
+; Mon Dec 20, 1993 -by- Dave Hart [DaveHart]
+; Don't ask me about current directories and WOW! I'll deny it all!
+;-----------------------------------------------------------------------;
+
+Entry WowFixWin32CurDir
+ push ds
+ SetKernelDS
+ mov ax,[CurTDB]
+ or ax,ax
+ jz WFW32CD_Exit
+ mov ds,ax ; DS points to TDB
+ UnSetKernelDS
+ cmp ds:[TDB_sig],TDB_SIGNATURE
+ jne WFW32CD_Exit
+ mov dl,ds:[TDB_Drive]
+ and dl,7fh
+ mov ah,0Eh ; change drive
+ DOSCALL
+ mov dx,TDB_LFNDirectory ; DS:DX points to TDB curdir
+ mov ah,3Bh ; change directory
+ DOSCALL
+if KDEBUG
+ jnc WFW32CD_Exit
+ krDebugOut DEB_WARN, "WowFixWin32CurDir: DOS fn 3B fails error #AX"
+endif
+WFW32CD_Exit:
+ pop ds
+ ret
+
+; sudeepb 11-May-1994
+;
+; This hackcheck is for simcity. Simcity does a GlobalSize on GDI.EXE and
+; USER.EXE to figure out how much free resources are available. WOW's USER
+; GDI have pretty small DGROUP, hence the size returns fails the check of
+; this app. So we need to fake a bigger size.
+;
+
+cProc HackCheck,<PUBLIC,NEAR>
+ parmW handle
+cBegin]
+ push es
+ SetKernelDS es
+ ; first check in the TDB that the currently running app is SCW.
+ mov ax,curtdb
+ mov es,ax
+ xor ax,ax
+ cmp word ptr es:[0f2h],4353h ; SC (mod name in TDB at f2 offset)
+ jne hc5
+ cmp word ptr es:[0f4h],0057h ; W
+ jne hc5
+
+ ; Its SCW. Now get the module table for the given handle and check if its
+ ; for USER.EXE and GDI.EXE
+ cCall GetExePtr,<handle>
+ or ax,ax
+ jz hc5
+ mov ds,ax
+ mov si,ds:[ne_pfileinfo]
+ lea dx,[si].opFile ; DS:DX -> path
+ cCall WowCheckUserGdi,<ds,dx> ; Much easier to check this in 32bit land.
+hc5:
+ pop es
+cEnd
+
+;-----------------------------------------------------------------------;
+; WowSetCompatHandle
+;
+; This routine takes a single parameter and saves it in the TDB. It is
+; used to take care of a bug in dBase where it confuses handle values.
+; This is a private API called by USER.EXE.
+;
+; All registers must be saved. DS is saved automatically by cmacros.
+; History:
+;-----------------------------------------------------------------------;
+
+cProc WowSetCompatHandle, <PUBLIC, FAR>
+ParmW handle
+cBegin
+ push bx
+ SetKernelDS
+ mov bx,[CurTDB]
+ or bx,bx
+ jz @f ;check for zero just in case
+ mov ds,bx ; DS points to TDB
+ UnSetKernelDS
+ mov bx, handle
+ mov ds:[TDB_CompatHandle],bx ;save it here
+@@:
+ pop bx
+cEnd
+
+sEND CODE
+
+end
diff --git a/private/mvdm/wow16/kernel31/wowdeb.asm b/private/mvdm/wow16/kernel31/wowdeb.asm
new file mode 100644
index 000000000..0b0dcfd8d
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/wowdeb.asm
@@ -0,0 +1,114 @@
+ TITLE WOWDEB.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; wowdeb.ASM
+; Debug Routines
+;
+; History:
+; 19-June-91 Matt Felton (mattfe) Created
+;
+ .xlist
+ include kernel.inc
+ include cmacros.inc
+ .list
+
+.286p
+
+externFP WOWKernelTrace
+
+DataBegin
+externW curTDB
+DataEnd
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+;-----------------------------------------------------------------------;
+; KdDbgOut ;
+; ;
+; Cmacros.inc has been modified so in the debug kernel all far public ;
+; routines have a preamble compiled so they call this routine with a ;
+; a count of the number of arguements and a pointer to a charater string;
+; with the name of the routine. ;
+; This routine then thunks to 32 bit WOW to output the paramters to the ;
+; log. ;
+; It assumes that if the callers CS != Our CS then its not the kernel ;
+; Calling this routine ;
+; Cmacros doesn't compile in the preamble for some internal routines ;
+; that are called all the time. ;
+; For retail Kernel the preamble and this routine are omitted. ;
+; ;
+; Arguments: ;
+; lpStr long pointer to null terminated string ;
+; cparms count of parameters ;
+; Returns: ;
+; none ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; WOWKernelTrace Thunk to 32 bits ;
+; ;
+; History: ;
+; ;
+; June 19 1991 Create Matt Felton [mattfe]
+;-----------------------------------------------------------------------;
+
+ifdef KDEBUG
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc KdDbgOut,<PUBLIC,FAR>,<ax,bx,dx>
+ parmW cParms
+ parmD lpRoutineName
+cBegin
+ SetKernelDS DS
+ mov ax,curTDB ; if there is no CurrentTDB forget it.
+ cmp ax,0
+ jz KdDbgOut_Exit
+
+; Get the iLogLevel From ROMBIOS Hard Disk Area
+
+ push 0040h
+ pop ds
+ UnSetKernelDS ds
+
+ iLogLevel equ 0042h ; use fixed disk status area
+ cmp word ptr ds:[iLogLevel],"00" ;No Output if Zero
+ jz KdDbgOut_Exit
+
+; Log Application Calls Only
+
+ mov ax,cs
+ mov bx,word ptr [bp] ; (follow BP chain to user CS)
+ add bx,3
+
+ cmp word ptr ds:[iloglevel],"61" ; LOG IT ALL at Level 16
+ jz @f
+
+ cmp ax,word ptr ss:[bx] ;If Users CS != KERNEL CS
+ jz KdDbgOut_Exit ; then ignore tracing
+
+@@:
+ sub bx,2 ; Point to Callers Return Address IP:CS Args
+ cCall WOWKernelTrace,<lpRoutineName,cParms,SSBX>
+
+KdDbgOut_Exit:
+cEnd
+
+endif
+
+sEND CODE
+
+end
diff --git a/private/mvdm/wow16/killwow/killwow.c b/private/mvdm/wow16/killwow/killwow.c
new file mode 100644
index 000000000..2e3671048
--- /dev/null
+++ b/private/mvdm/wow16/killwow/killwow.c
@@ -0,0 +1,31 @@
+/****************************************************************************
+
+ PROGRAM: KillWOW.c
+
+ PURPOSE: KillWOW Close WOW
+
+ COMMENTS:
+ This app will NUKE WOW if it is able to run
+
+
+****************************************************************************/
+
+#include <windows.h> /* required for all Windows applications */
+
+HANDLE hInst; /* current instance */
+
+/****************************************************************************
+
+ FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
+
+ PURPOSE: calls initialization function, processes message loop
+
+ COMMENTS:
+
+
+****************************************************************************/
+
+int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ ExitKernelThunk(0);
+}
diff --git a/private/mvdm/wow16/killwow/killwow.ico b/private/mvdm/wow16/killwow/killwow.ico
new file mode 100644
index 000000000..1ac14e882
--- /dev/null
+++ b/private/mvdm/wow16/killwow/killwow.ico
Binary files differ
diff --git a/private/mvdm/wow16/killwow/killwow.rc b/private/mvdm/wow16/killwow/killwow.rc
new file mode 100644
index 000000000..88113eae5
--- /dev/null
+++ b/private/mvdm/wow16/killwow/killwow.rc
@@ -0,0 +1,5 @@
+#include "windows.h"
+
+#include "killwow.rcv"
+
+KillWOW ICON killwow.ico
diff --git a/private/mvdm/wow16/killwow/killwow.rcv b/private/mvdm/wow16/killwow/killwow.rcv
new file mode 100644
index 000000000..6d18b54a7
--- /dev/null
+++ b/private/mvdm/wow16/killwow/killwow.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* KILLWOW.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Kills Windows NT Shared WOW VDM"
+#define VER_INTERNALNAME_STR "KILLWOW"
+#define VER_ORIGINALFILENAME_STR "KILLWOW.EXE"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/killwow/makefile b/private/mvdm/wow16/killwow/makefile
new file mode 100644
index 000000000..f9dbfc994
--- /dev/null
+++ b/private/mvdm/wow16/killwow/makefile
@@ -0,0 +1,121 @@
+# KillWOW makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Matt Felton (mattfe)
+# 21-Mar-1992 Matt Felton Code from win 3.1 progman
+# Created.
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+AOBJ = -W2 -DSEGNAME=COMMAND $(INCS)
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+COBJ = -AS -G2s -Os -W2 -Zp -DDEBUG $(INCS)
+!IF "$(OLD_WOW_BUILD)" != ""
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG -DOLD_WOW_BUILD $(INCS)
+!ELSE
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG $(INCS)
+!ENDIF
+!else
+COBJ = -AS -G2s -Os -W2 -Zp $(INCS)
+!IF "$(OLD_WOW_BUILD)" != ""
+CW16 = -AS -G2sw -Os -W2 -Zp -DOLD_WOW_BUILD $(INCS)
+!ELSE
+CW16 = -AS -G2sw -Os -W2 -Zp $(INCS)
+!ENDIF
+!endif
+
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /stack:8192 /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\snocrt.lib ..\lib\libw.lib
+
+
+.h.inc:
+ h2inc -t $*.h -o $*.inc
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+all: KillWOW.exe KillWOW.sym
+ -binplace killwow.exe killwow.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.def del *.def
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+KillWOW.lrf: makefile
+ echo killwow.obj >killwow.lrf
+ echo KillWOW $(LINK)>>KillWOW.lrf
+ echo KillWOW>>KillWOW.lrf
+ echo $(W16LIBS) /nod>>KillWOW.lrf
+ echo KillWOW;>>KillWOW.lrf
+
+KillWOW.def: makefile
+ echo name KillWOW>KillWOW.def
+ echo exetype windows>>KillWOW.def
+ echo stub '..\bin\winstub.exe'>>KillWOW.def
+ echo code preload moveable discardable>>KillWOW.def
+ echo data preload moveable multiple>>KillWOW.def
+ echo heapsize 4096>>KillWOW.def
+ echo imports>>KillWOW.def
+ echo WOWQUERYDEBUG = KERNEL.512>>KillWOW.def
+
+KillWOW.res: $*.rc $*.rcv ..\inc\common.ver
+
+KillWOW.exe: KillWOW.obj KillWOW.lrf KillWOW.def KillWOW.res
+ link16 @KillWOW.lrf;
+ rc16 -t KillWOW.res KillWOW.exe
diff --git a/private/mvdm/wow16/lib/makefile b/private/mvdm/wow16/lib/makefile
new file mode 100644
index 000000000..660e4599b
--- /dev/null
+++ b/private/mvdm/wow16/lib/makefile
@@ -0,0 +1,56 @@
+# Build file for the standard model-independent Windows import lib (libw.lib)
+# and other related modules for the Windows part of c6 libs.- LR
+
+target: kernel.lib user.lib gdi.lib system.lib shell.lib mmsystem.lib
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# Standard (model-independent) import library
+
+libw.lib: ..\kernel31\kernel.def ..\gdi\gdi.def ..\user\user.def \
+ ..\drivers\sound\sound.def ..\drivers\keyboard\keyboard.def \
+ ..\shell\library\shell.def
+ upd /ne ..\drivers\sound . sound.def
+ upd /ne ..\drivers\keyboard . keyboard.def
+ implib libw.lib ..\kernel31\kernel.def ..\gdi\gdi.def ..\user\user.def \
+ sound.def keyboard.def ..\shell\library\shell.def
+ lib16 libw.lib;
+
+
+#
+# Import library build for internal use only
+#
+all: kernel.lib system.lib gdi.lib user.lib shell.lib mmsystem.lib
+
+kernel.lib: ..\kernel31\kernel.def
+ implib kernel.lib ..\kernel31\kernel.def
+
+system.lib: ..\system\system.def
+ implib system.lib ..\system\system.def
+
+gdi.lib: ..\gdi\gdi.def
+ implib gdi.lib ..\gdi\gdi.def
+
+user.lib: ..\user\user.def
+ implib user.lib ..\user\user.def
+
+shell.lib: ..\shell\shell.def
+ implib shell.lib ..\shell\shell.def
+
+mmsystem.lib: ..\$*\$*.def
+ implib $@ ..\$*\$*.def
+
+clean: cleanup all
+
+cleanup:
+ if exist kernel.lib del kernel.lib
+ if exist system.lib del system.lib
+ if exist gdi.lib del gdi.lib
+ if exist user.lib del user.lib
+ if exist shell.lib del shell.lib
+ -del libw.lib 2>NUL
diff --git a/private/mvdm/wow16/makefile b/private/mvdm/wow16/makefile
new file mode 100644
index 000000000..4d461f4bd
--- /dev/null
+++ b/private/mvdm/wow16/makefile
@@ -0,0 +1,134 @@
+# WOW16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 04-Dec-1991 Sudeep Bharati
+# Created.
+# Modified 12-May-1992 Mike Tricker (MikeTri) Added MultiMedia subdirectory
+#
+
+all:
+ cd kernel31
+ $(MAKE) d386
+ $(MAKE) r386
+ cd ..\lib
+ $(MAKE)
+ cd ..\user
+ $(MAKE)
+ cd ..\gdi
+ $(MAKE)
+ cd ..\system
+ $(MAKE)
+ cd ..\shell
+ $(MAKE)
+ cd ..\drivers\keyboard
+ $(MAKE)
+ cd ..\sound
+ $(MAKE)
+ cd ..\comm
+ $(MAKE)
+ cd ..\display
+ $(MAKE)
+ cd ..\mouse
+ $(MAKE)
+ cd ..
+ cd ..\winspool
+ $(MAKE)
+ cd ..\test
+ $(MAKE)
+ cd ..\mmsystem
+ $(MAKE)
+ cd ..\mciole
+ $(MAKE)
+ cd ..\winsock
+ $(MAKE)
+ cd ..\toolhelp
+ $(MAKE)
+ cd ..\timer
+ $(MAKE)
+ cd ..\wowdeb
+ $(MAKE)
+ cd ..\commdlg
+ $(MAKE)
+ cd ..\sherlock
+ $(MAKE)
+ cd ..\rasapi16
+ $(MAKE)
+ cd ..\wfwnet
+ $(MAKE)
+ cd ..\write
+ $(MAKE)
+ cd ..\ddeml
+ $(MAKE)
+ cd ..\winoldap
+ $(MAKE)
+ cd ..\ole\server
+ $(MAKE)
+ cd ..\..\regedit
+ $(MAKE)
+ cd ..\killwow
+ $(MAKE)
+ cd ..
+
+
+clean:
+ cd kernel31
+ $(MAKE) 386P=1 DEST=DEBUG3 clean
+ $(MAKE) 386P=1 DEST=RETAIL3 clean
+ cd ..\lib
+ $(MAKE) clean
+ cd ..\user
+ $(MAKE) clean
+ cd ..\gdi
+ $(MAKE) clean
+ cd ..\system
+ $(MAKE) clean
+ cd ..\shell
+ $(MAKE) clean
+ cd ..\drivers\keyboard
+ $(MAKE) clean
+ cd ..\sound
+ $(MAKE) clean
+ cd ..\comm
+ $(MAKE) clean
+ cd ..\display
+ $(MAKE) clean
+ cd ..\mouse
+ $(MAKE) clean
+ cd ..
+ cd ..\winspool
+ $(MAKE) clean
+ cd ..\test
+ $(MAKE) clean
+ cd ..\mmsystem
+ $(MAKE) clean
+ cd ..\mciole
+ $(MAKE) clean
+ cd ..\winsock
+ $(MAKE) clean
+ cd ..\toolhelp
+ $(MAKE) clean
+ cd ..\timer
+ $(MAKE) clean
+ cd ..\wowdeb
+ $(MAKE) clean
+ cd ..\commdlg
+ $(MAKE) clean
+ cd ..\sherlock
+ $(MAKE) clean
+ cd ..\rasapi16
+ $(MAKE) clean
+ cd ..\wfwnet
+ $(MAKE) clean
+ cd ..\ddeml
+ $(MAKE) clean
+ cd ..\winoldap
+ $(MAKE) clean
+ cd ..\ole\server
+ $(MAKE) clean
+ cd ..\..\regedit
+ $(MAKE) clean
+ cd ..\killwow
+ $(MAKE) clean
+ cd ..
diff --git a/private/mvdm/wow16/mciole/libinit.asm b/private/mvdm/wow16/mciole/libinit.asm
new file mode 100644
index 000000000..ea61a3e0b
--- /dev/null
+++ b/private/mvdm/wow16/mciole/libinit.asm
@@ -0,0 +1,151 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: LIBINIT.ASM
+;
+; library stub to do local init for a Dynamic linked library
+;
+; Created: 06-27-89
+; Author: Todd Laney [ToddLa]
+;
+; Exported Functions: none
+;
+; Public Functions: none
+;
+; Public Data: none
+;
+; General Description:
+;
+; Restrictions:
+;
+; This must be the first object file in the LINK line, this assures
+; that the reserved parameter block is at the *base* of DGROUP
+;
+;-----------------------------------------------------------------------;
+
+?PLM=1 ; PASCAL Calling convention is DEFAULT
+?WIN=1 ; Windows calling convention
+
+ .286p
+ .xlist
+ include cmacros.inc
+; include windows.inc
+ .list
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+;-----------------------------------------------------------------------;
+; external functions
+;
+ externFP LocalInit ; in KERNEL
+ externP LibMain ; C code to do DLL init
+
+;-----------------------------------------------------------------------;
+;
+; Stuff needed to avoid the C runtime coming in, and init the windows
+; reserved parameter block at the base of DGROUP
+;
+%out link me first!!
+sBegin Data
+assumes DS,Data
+ org 0 ; base of DATA segment!
+
+ DD 0 ; So null pointers get 0
+maxRsrvPtrs = 5
+ DW maxRsrvPtrs
+usedRsrvPtrs = 0
+labelDP <PUBLIC,rsrvptrs>
+
+DefRsrvPtr MACRO name
+globalW name,0
+usedRsrvPtrs = usedRsrvPtrs + 1
+ENDM
+
+DefRsrvPtr pLocalHeap ; Local heap pointer
+DefRsrvPtr pAtomTable ; Atom table pointer
+DefRsrvPtr pStackTop ; top of stack
+DefRsrvPtr pStackMin ; minimum value of SP
+DefRsrvPtr pStackBot ; bottom of stack
+
+if maxRsrvPtrs-usedRsrvPtrs
+ DW maxRsrvPtrs-usedRsrvPtrs DUP (0)
+endif
+
+public __acrtused
+ __acrtused = 1
+
+sEnd Data
+
+;-----------------------------------------------------------------------;
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+
+;--------------------------Private-Routine-----------------------------;
+;
+; LibEntry - called when DLL is loaded
+;
+; Entry:
+; CX = size of heap
+; DI = module handle
+; DS = automatic data segment
+; ES:SI = address of command line (not used)
+;
+; Returns:
+; AX = TRUE if success
+; Error Returns:
+; AX = FALSE if error (ie fail load process)
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; Calls:
+; None
+; History:
+;
+; 06-27-89 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+
+cProc LibEntry,<FAR,PUBLIC,NODATA>,<>
+cBegin
+ ;
+ ; Init the local heap (if one is declared in the .def file)
+ ;
+ jcxz no_heap
+
+ cCall LocalInit,<0,0,cx>
+
+no_heap:
+ cCall LibMain, <di>
+cEnd
+
+if 0
+;--------------------------Exported-Routine-----------------------------;
+;
+; WEP()
+;
+; called when the DLL is unloaded, it is passed 1 WORD parameter that
+; is TRUE if the system is going down, or zero if the app is
+;
+; WARNING:
+;
+; This function is basicly useless, you cant can any kernel function
+; that may cause the LoadModule() code to be reentered..
+;
+;-----------------------------------------------------------------------;
+
+cProc WEP,<FAR,PUBLIC,NODATA>,<>
+; ParmW fSystemExit
+cBegin nogen
+ mov ax,1
+ retf 2
+cEnd nogen
+endif
+
+sEnd CodeSeg
+
+ end LibEntry
diff --git a/private/mvdm/wow16/mciole/makefile b/private/mvdm/wow16/mciole/makefile
new file mode 100644
index 000000000..3d7fd8183
--- /dev/null
+++ b/private/mvdm/wow16/mciole/makefile
@@ -0,0 +1,85 @@
+# mciole16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# Created
+# 06-May-1993 Stephen Estrop (StephenE)
+# 24-Jan-1994 Lee Hart (LeeHart) - Added Version Resources
+#
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+INCS = -I. -I..\inc -I..\..\inc
+DEFINES = -DWOW $(MVDMFLAGS)
+AOBJ = -Mx -t -D?QUIET $(DEFINES) $(INCS)
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+LPATH = ..\..\tools.os2
+LINK = /map /nod
+W16LIBS = ..\lib\libw.lib ..\lib\snocrt.lib olecli.lib
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+.def.lib:
+ implib $*.lib $*.def
+
+.rc.res:
+ $(RESCOMP) -r -fo $@ $(INCS) $*.rc
+
+
+OBJ1= libinit.obj mciole.obj
+
+LINKER=link16
+RESCOMP=rc16
+
+all: mciole16.dll
+
+mciole16.dll: $(OBJ1) mciole16.res
+ $(LINKER) $(LINK) @<<
+$(OBJ1)
+mciole16.dll
+mciole16.map
+$(W16LIBS)
+mciole.def
+<<
+ $(RESCOMP) -t mciole16.res mciole16.dll
+ mapsym mciole16.map
+ -binplace mciole16.dll mciole16.map mciole16.sym
+
+mciole16.res: $*.rc $*.rcv ..\inc\common.ver
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
diff --git a/private/mvdm/wow16/mciole/mciole.c b/private/mvdm/wow16/mciole/mciole.c
new file mode 100644
index 000000000..ad925cd57
--- /dev/null
+++ b/private/mvdm/wow16/mciole/mciole.c
@@ -0,0 +1,1553 @@
+//
+// MCIOLE - OLE handler DLL for MCI objects
+//
+//
+// NOTES:
+// The whole reason for this handler DLL is to supply the function
+//
+// OleQueryObjPos()
+//
+// this function gives information to the server application on the
+// location (in the client document) of the activated OLE object.
+// the server can use this information to play the object in place
+// or position the server window correctly
+//
+// IMPLEMENTION:
+//
+// in theory all this DLL (handler) has to do is save the information
+// passed to OleActivate(). But in reality no app correctly calls
+// OleActivate(). They either pass no information or the wrong
+// information.
+//
+// this DLL is a OLE handler, because of global data (vtblDef!) it
+// can only be a handler for one class at a time.
+//
+// the handler intercepts the OleDraw, OleActivate, and all the
+// creation/destuction OLE APIs. for each OLE object a info
+// structure is maintained (a OBJINFO structure) when ever the
+// client draws (using OleDraw...) the drawing position, and the
+// window drawn to is remembered.
+//
+// when the client calls OleActivate, the saved draw location is
+// recalled, or if the app never called OleDraw() (plays
+// the meta-file itself) then the rectangle passed to OleActivate()
+// is used. (if one is supplied)
+//
+// there are many classes of apps:
+//
+// calls OleActivate() with correct info
+// calls OleActivate() with incorrect info
+// calls OleActivate() with no info
+//
+// calls OleDraw()
+// does not call OleDraw()
+//
+// here is a table of known OLE Clients....
+//
+// OleDraw OleActivate()
+// App Y or N Y, N, X
+// (X = wrong info)
+// ------------- ---------- ------------
+// Write Y N
+// CardFile Y N
+// Packager Y N
+//
+// Excel N N (uses DDE)
+// Excel 4.0 N N (uses DDE)
+// PowerPnt 2.0 N N (uses DDE)
+//
+// WinWord N N
+// WinWorks Y X
+// PowerPnt 3.0 N Y
+// MsPublisher N X
+// ClTest Y N
+// Cirus Y X
+// WinProj ? ?
+//
+// AmiPro Y ?
+//
+#include <windows.h>
+#include "ole.h"
+#include "shellapi.h"
+#include "mciole.h"
+
+HANDLE ghInstance;
+
+OLEOBJECTVTBL vtblDll; // these are our functions.
+OLEOBJECTVTBL vtblDef; // these are the default functions.
+HBITMAP hbmStock;
+
+#ifdef DEBUG
+RECT rcNull = {0,0,0,0};
+#define PUSHRC(prc) *((prc) ? (prc) : &rcNull)
+#define CARETPOS() // {POINT pt; GetCaretPos(&pt); DPRINTF(("CaretPos: [%d, %d]", pt.x, pt.y));}
+#endif
+
+/****************************************************************************
+****************************************************************************/
+
+void ReplaceFunctions(LPOLEOBJECT);
+BOOL CanReplace(LPOLEOBJECT);
+
+/****************************************************************************
+
+ FUNCTION: LibMain(HANDLE hInstance)
+
+****************************************************************************/
+
+BOOL NEAR PASCAL LibMain (HANDLE hInstance)
+{
+ HDC hdc;
+ HBITMAP hbm;
+
+ ghInstance = hInstance;
+
+ //
+ // get the stock 1x1 mono bitmap.
+ //
+ hbm = CreateBitmap(1,1,1,1,NULL);
+ hdc = CreateCompatibleDC(NULL);
+ hbmStock = SelectObject(hdc, hbm);
+ SelectObject(hdc, hbmStock);
+ DeleteDC(hdc);
+ DeleteObject(hbm);
+
+// // register clipboard formats.
+// cfObjectLink = RegisterClipboardFormat("ObjectLink");
+// cfOwnerLink = RegisterClipboardFormat("OwnerLink");
+// cfNative = RegisterClipboardFormat("Native");
+
+ return TRUE;
+}
+
+/****************************************************************************
+
+ FUNCTION: WEP(int)
+
+ PURPOSE: Standard exit routine for the DLL
+
+****************************************************************************/
+
+int FAR PASCAL _loadds WEP(nParameter)
+int nParameter;
+{
+ return 1;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+BOOL NEAR PASCAL IsApp(LPSTR szApp)
+{
+ char ach[80];
+ int i;
+ WORD wStack;
+
+ _asm mov wStack,ss
+
+ GetModuleFileName((HINSTANCE)wStack, ach, sizeof(ach));
+
+ for (i = lstrlen(ach);
+ i > 0 && ach[i-1] != '\\' && ach[i-1] != '/' && ach[i] != ':';
+ i--)
+ ;
+
+ return lstrcmpi(ach + i, szApp) == 0;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+BOOL NEAR PASCAL IsDcMemory(HDC hdc)
+{
+ HBITMAP hbmT;
+
+ if (hbmT = SelectObject(hdc, hbmStock))
+ SelectObject(hdc, hbmT);
+
+ return hbmT != NULL;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+typedef struct _OBJINFO {
+
+ struct _OBJINFO*poiNext;
+
+ LPOLEOBJECT lpobj; // client side LPOLEOBJECT
+
+ HWND hwnd; // client window (passed to OleActivate)
+ RECT rcActivate; // activation rectangle (passed to OleActivate)
+
+ HWND hwndDraw; // active window at time of OleDraw
+ RECT rcDraw; // rectangle of draw
+} OBJINFO;
+
+#ifdef DEBUG
+int nObjects = 0;
+#endif
+OBJINFO *poiFirst = NULL;
+
+LPOLEOBJECT lpobjActive;
+BOOL RegSetGetData(OBJINFO *poi, BOOL Write);
+
+OBJINFO *FindObj(LPOLEOBJECT lpobj)
+{
+ OBJINFO *poi;
+
+ for (poi=poiFirst; poi; poi=poi->poiNext)
+ if (poi->lpobj == lpobj)
+ return poi;
+
+ DPRINTF(("FindObj: Unable to find object %lx", lpobj));
+
+ return NULL;
+}
+
+void DelObj(LPOLEOBJECT lpobj)
+{
+ OBJINFO *poi;
+ OBJINFO *poiT;
+
+ for (poiT=NULL,poi=poiFirst; poi; poiT=poi,poi=poi->poiNext)
+ {
+ if (poi->lpobj == lpobj)
+ {
+ if (poiT)
+ poiT->poiNext = poi->poiNext;
+ else
+ poiFirst = poi->poiNext;
+
+ poi->lpobj = NULL;
+ LocalFree((HLOCAL)poi);
+
+ DPRINTF(("DelObj(%lx): %d objects", lpobj, --nObjects));
+ return;
+ }
+ }
+
+ DPRINTF(("DelObj(%lx): Cant find object to delete.", lpobj));
+}
+
+BOOL RegSetGetData(OBJINFO *poi, BOOL Write)
+{
+
+ static char szKey[] = "PlayData";
+ static char szFormat[] = "%ld %ld %d %d %d %d %d %d %d %d";
+
+
+ if (Write) {
+ LONG Rc;
+
+ char Data[100];
+
+ //
+ // Store hwnd, hwnddraw, rcDraw, rcActivate
+ //
+
+#ifdef WIN32
+ wsprintf(Data, szFormat,
+ (LONG)poi->hwnd,
+ (LONG)poi->hwndDraw,
+ poi->rcDraw.left,
+ poi->rcDraw.right,
+ poi->rcDraw.top,
+ poi->rcDraw.bottom,
+ poi->rcActivate.left,
+ poi->rcActivate.right,
+ poi->rcActivate.top,
+ poi->rcActivate.bottom);
+
+#else
+ wsprintf(Data, szFormat,
+ (LONG)(poi->hwnd == NULL ? (LONG)0 : MAKELONG(poi->hwnd, 0xFFFF)),
+ (LONG)(poi->hwndDraw == NULL ? (LONG)0 : MAKELONG(poi->hwndDraw, 0xFFFF)),
+ poi->rcDraw.left,
+ poi->rcDraw.right,
+ poi->rcDraw.top,
+ poi->rcDraw.bottom,
+ poi->rcActivate.left,
+ poi->rcActivate.right,
+ poi->rcActivate.top,
+ poi->rcActivate.bottom);
+#endif
+
+ Rc = RegSetValue(HKEY_CLASSES_ROOT,
+ szKey,
+ REG_SZ,
+ Data,
+ lstrlen(Data));
+
+ return Rc == ERROR_SUCCESS;
+ } else {
+
+#ifdef WIN32
+ LONG Rc;
+ CHAR Data[100];
+ DWORD hwnd, hwndDraw;
+ LONG Length;
+
+ Length = sizeof(Data);
+
+ Rc = RegQueryValue(HKEY_CLASSES_ROOT, szKey,
+ Data, &Length);
+
+ RegSetValue(HKEY_CLASSES_ROOT, szKey, REG_SZ, "", 0);
+
+ //
+ // Extract our data - sscanf doesn't work yet!!!
+ //
+
+ if (Rc == ERROR_SUCCESS) {
+ LONG OurData[10];
+ int i;
+ LPTSTR lpData;
+
+ for (i = 0, lpData = Data; i < 10; i++) {
+ OurData[i] = atol(lpData);
+ while (*lpData != ' ' && *lpData != '\0') {
+ lpData++;
+ }
+
+ if (*lpData == ' ') {
+ lpData++;
+ }
+ }
+
+ poi->hwnd = (HWND)OurData[0];
+ poi->hwndDraw = (HWND)OurData[1];
+ poi->rcDraw.left = OurData[2];
+ poi->rcDraw.right = OurData[3];
+ poi->rcDraw.top = OurData[4];
+ poi->rcDraw.bottom = OurData[5];
+ poi->rcActivate.left = OurData[6];
+ poi->rcActivate.right = OurData[7];
+ poi->rcActivate.top = OurData[8];
+ poi->rcActivate.bottom = OurData[9];
+ }
+
+ return Rc == ERROR_SUCCESS && Length != 0;
+#else
+ return FALSE;
+#endif
+ }
+}
+
+//
+// for some reason we dont get all the OleDelete() calls that we should
+// so lets try to "weed out the bad apples" so we dont choke.
+//
+void CleanObjects()
+{
+ OBJINFO *poi;
+
+again:
+ for (poi=poiFirst; poi; poi=poi->poiNext)
+ {
+ if (IsBadReadPtr(poi->lpobj, 0))
+ {
+ DPRINTF(("Freeing bad object %lx", poi->lpobj));
+ DelObj(poi->lpobj);
+ goto again;
+ }
+ }
+}
+
+OBJINFO *NewObj(LPOLEOBJECT lpobj)
+{
+ OBJINFO *poi;
+
+ CleanObjects();
+
+ if (poi = FindObj(lpobj))
+ {
+ DPRINTF(("NewObj(%lx): Trying to add object twice!", lpobj));
+ return poi;
+ }
+
+ if (poi = (OBJINFO*)LocalAlloc(LPTR, sizeof(OBJINFO)))
+ {
+ poi->lpobj = lpobj;
+ poi->hwnd = NULL;
+ poi->hwndDraw = NULL;
+ SetRectEmpty(&poi->rcDraw);
+ SetRectEmpty(&poi->rcActivate);
+
+ poi->poiNext = poiFirst;
+ poiFirst = poi;
+
+ DPRINTF(("NewObj(%lx): %d objects", lpobj, ++nObjects));
+ }
+ else
+ {
+ DPRINTF(("NewObj(%lx): Out of room in the object table", lpobj));
+ }
+
+ return poi;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+HWND LookForDC(HWND hwndP, HDC hdc)
+{
+ RECT rc;
+ DWORD dw;
+ HWND hwnd;
+
+ if (hwndP == NULL)
+ return NULL;
+
+ dw = GetDCOrg(hdc);
+
+ for (hwnd = hwndP; hwnd; hwnd = GetWindow(hwnd, GW_HWNDNEXT))
+ {
+ GetClientRect(hwnd, &rc);
+ ClientToScreen(hwnd, (LPPOINT)&rc);
+ ClientToScreen(hwnd, (LPPOINT)&rc+1);
+
+ if ((int)LOWORD(dw) == rc.left && (int)HIWORD(dw) == rc.top)
+ return hwnd;
+
+ if (PtInRect(&rc, MAKEPOINT(dw)) && (hwndP = GetWindow(hwnd, GW_CHILD)))
+ if (hwndP = LookForDC(hwndP,hdc))
+ return hwndP;
+ }
+
+ return NULL;
+}
+
+HWND WindowFromDC(HDC hdc)
+{
+ return LookForDC(GetDesktopWindow(), hdc);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+BOOL RectSameSize(LPRECT lprc1, LPRECT lprc2)
+{
+ return lprc1->right - lprc1->left == lprc2->right - lprc2->left &&
+ lprc1->bottom - lprc1->top == lprc2->bottom - lprc2->top;
+}
+
+/****************************************************************************
+
+ OleQueryObjPos - this function retuns the last drawn or activated
+ position of a object
+
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds OleQueryObjPos(
+LPOLEOBJECT lpobj, /* object to query */
+HWND FAR * lphwnd, /* window of the document containing the object */
+LPRECT lprc, /* rect (client cords) of object. */
+LPRECT lprcWBounds)/* rect (client cords) of bounding rect. */
+{
+ OBJINFO *poi;
+
+ //
+ // we dont do this any more
+ //
+ if (lprcWBounds)
+ SetRectEmpty(lprcWBounds);
+
+ //
+ // because the server side calls this API the passed lpobj is
+ // a server side LPOLEOBJECT, we can't search our table for this
+ // object.
+ //
+ // this API is only callable by the server during the DoVerb
+ // server callback
+ //
+ //!!! this only works for the last active object!!!!
+
+ DPRINTF(("OleQueryObjPos(%lx)", lpobj));
+
+ if (lpobjActive != NULL && (poi = FindObj(lpobjActive)))
+ {
+ //
+ // set lpobjActive to NULL so we will never retrive the
+ // wrong info again.
+ //
+ lpobjActive = NULL;
+
+ *lphwnd = poi->hwnd;
+
+// if (IsRectEmpty(&poi->rcActivate))
+ if (!IsRectEmpty(&poi->rcDraw))
+ {
+ DPRINTF(("Using the OleDraw() rectange...."));
+
+ //
+ // use the draw rectangle
+ //
+ *lprc = poi->rcDraw;
+
+ if (poi->hwndDraw)
+ {
+ ClientToScreen(poi->hwndDraw, (LPPOINT)lprc);
+ ClientToScreen(poi->hwndDraw, (LPPOINT)lprc+1);
+ }
+
+ ScreenToClient(poi->hwnd, (LPPOINT)lprc);
+ ScreenToClient(poi->hwnd, (LPPOINT)lprc+1);
+ }
+ else
+ {
+ //
+ // use the activate rectangle
+ //
+ *lprc = poi->rcActivate;
+ }
+
+ if (poi->hwnd && !IsRectEmpty(lprc))
+ return OLE_OK;
+ else
+ return OLE_ERROR_BLANK; // return a error, we dont know about this OBJ
+ }
+ else
+ {
+ *lphwnd = NULL;
+ SetRectEmpty(lprc);
+
+ return OLE_ERROR_BLANK; // return a error, we dont know about this OBJ
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllLoadFromStream (lpstream, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, objType, aClass, cfFormat)
+LPOLESTREAM lpstream;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LONG objType;
+ATOM aClass;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleLoadFromStream(%s,%s)", lpprotocol, lpobjname));
+
+ retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ objType, aClass, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreateFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, objType)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleCreateFromClip(%s,%s)", lpprotocol, lpobjname));
+
+ retVal = DefCreateFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, objType);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+ BOOL bReplace = FALSE;
+
+ DPRINTF(("OleCreateLinkFromClip(%s,%s)", lpprotocol, lpobjname));
+
+ retVal = DefCreateLinkFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreateFromTemplate (lpprotocol, lpclient, lptemplate, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleCreateFromTemplate(%s,%s,%s)", lpprotocol, lptemplate, lpobjname));
+
+ retVal = DefCreateFromTemplate (lpprotocol, lpclient, lptemplate,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreate (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleCreate(%s,%s,%s)", lpprotocol, lpclass, lpobjname));
+
+ retVal = DefCreate (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleCreateFromFile(%s,%s,%s,%s)", lpprotocol, lpclass, lpfile, lpobjname));
+
+ retVal = DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCreateLinkFromFile (lpprotocol, lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LPSTR lpitem;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ DPRINTF(("OleCreateLinkFromFile(%s,%s,%s,%s,%s)", lpprotocol, lpclass, lpfile, lpitem, lpobjname));
+
+ retVal = DefCreateLinkFromFile (lpprotocol, lpclient,
+ lpclass, lpfile, lpitem,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ ReplaceFunctions(*lplpobj);
+
+ return retVal;
+}
+
+
+/****************************************************************************
+****************************************************************************/
+
+void ReplaceFunctions(LPOLEOBJECT lpobj)
+{
+// OBJINFO *poi;
+
+ if (!CanReplace(lpobj))
+ return;
+
+ NewObj(lpobj);
+
+ //
+ // get the default handlers
+ //
+ if (vtblDef.Draw == NULL) // only get the handlers once!
+ vtblDef = *lpobj->lpvtbl; // save default handlers
+
+ //
+ // make the OLE object use our handlers
+ //
+ lpobj->lpvtbl = (LPOLEOBJECTVTBL)&vtblDll;
+
+ //
+ // init our VTBL, ie replace any handlers we want to override.
+ // any handlers we dont replace we set the the default ones.
+ //
+ vtblDll = vtblDef;
+
+////(FARPROC)vtblDll.QueryProtocol = (FARPROC)DllQueryProtocol;
+////(FARPROC)vtblDll.Release = (FARPROC)DllRelease;
+////(FARPROC)vtblDll.Show = (FARPROC)DllShow;
+////(FARPROC)vtblDll.DoVerb = (FARPROC)DllDoVerb;
+////(FARPROC)vtblDll.GetData = (FARPROC)DllGetData;
+////(FARPROC)vtblDll.SetData = (FARPROC)DllSetData;
+////(FARPROC)vtblDll.SetTargetDevice = (FARPROC)DllSetTargetDevice;
+////(FARPROC)vtblDll.SetBounds = (FARPROC)DllSetBounds;
+////(FARPROC)vtblDll.EnumFormats = (FARPROC)DllEnumFormats;
+////(FARPROC)vtblDll.SetColorScheme = (FARPROC)DllSetColorScheme;
+
+ (FARPROC)vtblDll.Delete = (FARPROC)DllDelete;
+////(FARPROC)vtblDll.SetHostNames = (FARPROC)DllSetHostNames;
+////(FARPROC)vtblDll.SaveToStream = (FARPROC)DllSaveToStream;
+ (FARPROC)vtblDll.Clone = (FARPROC)DllClone;
+ (FARPROC)vtblDll.CopyFromLink = (FARPROC)DllCopyFromLink;
+////(FARPROC)vtblDll.Equal = (FARPROC)DllEqual;
+////(FARPROC)vtblDll.CopyToClipboard = (FARPROC)DllCopyToClipboard;
+ (FARPROC)vtblDll.Draw = (FARPROC)DllDraw;
+ (FARPROC)vtblDll.Activate = (FARPROC)DllActivate;
+////(FARPROC)vtblDll.Execute = (FARPROC)DllExecute;
+////(FARPROC)vtblDll.Close = (FARPROC)DllClose;
+////(FARPROC)vtblDll.Update = (FARPROC)DllUpdate;
+////(FARPROC)vtblDll.Reconnect = (FARPROC)DllReconnect;
+ (FARPROC)vtblDll.ObjectConvert = (FARPROC)DllObjectConvert;
+////(FARPROC)vtblDll.GetLinkUpdateOptions = (FARPROC)DllGetLinkUpdateOptions;
+////(FARPROC)vtblDll.SetLinkUpdateOptions = (FARPROC)DllSetLinkUpdateOptions;
+////(FARPROC)vtblDll.Rename = (FARPROC)DllRename;
+////(FARPROC)vtblDll.QueryName = (FARPROC)DllQueryName;
+////(FARPROC)vtblDll.QueryType = (FARPROC)DllQueryType;
+////(FARPROC)vtblDll.QueryBounds = (FARPROC)DllQueryBounds;
+////(FARPROC)vtblDll.QuerySize = (FARPROC)DllQuerySize;
+////(FARPROC)vtblDll.QueryOpen = (FARPROC)DllQueryOpen;
+////(FARPROC)vtblDll.QueryOutOfDate = (FARPROC)DllQueryOutOfDate;
+////(FARPROC)vtblDll.QueryReleaseStatus = (FARPROC)DllQueryReleaseStatus;
+////(FARPROC)vtblDll.QueryReleaseError = (FARPROC)DllQueryReleaseError;
+////(FARPROC)vtblDll.QueryReleaseMethod = (FARPROC)DllQueryReleaseMethod;
+////(FARPROC)vtblDll.RequestData = (FARPROC)DllRequestData;
+////(FARPROC)vtblDll.ObjectLong = (FARPROC)DllObjectLong;
+////(FARPROC)vtblDll.ChangeData = (FARPROC)DllChangeData;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+BOOL CanReplace(LPOLEOBJECT lpobj)
+{
+#if 0 // did not work anyway.
+ //
+ // we dont work on the wierd OLE shipped with PenWindows so don't load
+ //
+#pragma message("Disabling handler because we are on PenWindows...")
+ if (GetSystemMetrics(SM_PENWINDOWS))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+LPVOID GetData(LPOLEOBJECT lpobj, WORD cf)
+{
+ HANDLE h;
+
+ if ( (*vtblDef.GetData)(lpobj, cf, &h) != OLE_OK || h == NULL)
+ return NULL;
+
+ return GlobalLock(h);
+}
+
+/****************************************************************************
+
+these are the actual handlers.....
+
+****************************************************************************/
+
+/****************************************************************************
+****************************************************************************/
+
+LPVOID FAR PASCAL _loadds DllQueryProtocol (
+LPOLEOBJECT lpobj,
+LPSTR lpsz)
+{
+ DPRINTF(("OleQueryProtocol(%ls)", lpsz));
+
+ return vtblDef.QueryProtocol(lpobj, lpsz);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllRelease (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleRelease()"));
+
+ return vtblDef.Release(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllShow (
+LPOLEOBJECT lpobj,
+BOOL fShow)
+{
+ DPRINTF(("OleShow(%d)", fShow));
+
+ return vtblDef.Show(lpobj, fShow);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllDoVerb (
+LPOLEOBJECT lpobj,
+WORD verb,
+BOOL fShow,
+BOOL fActivate)
+{
+ DPRINTF(("OleDoVerb(%d, %d, %d)", verb, fShow, fActivate));
+
+ return vtblDef.DoVerb(lpobj, verb, fShow, fActivate);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllGetData (
+LPOLEOBJECT lpobj,
+OLECLIPFORMAT cf,
+LPHANDLE lph)
+{
+ DPRINTF(("OleGetData(%d)", cf));
+
+ return vtblDef.GetData(lpobj, cf, lph);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetData (
+LPOLEOBJECT lpobj,
+OLECLIPFORMAT cf,
+HANDLE h)
+{
+ DPRINTF(("OleSetData(%d, %d)", cf, h));
+
+ return vtblDef.SetData(lpobj, cf, h);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetTargetDevice (
+LPOLEOBJECT lpobj,
+HANDLE h)
+{
+ DPRINTF(("OleSetTargetDevice()"));
+
+ return vtblDef.SetTargetDevice(lpobj, h);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetBounds (
+LPOLEOBJECT lpobj,
+LPRECT lprc)
+{
+ DPRINTF(("OleSetBounds([%d,%d,%d,%d])", PUSHRC(lprc)));
+
+ return vtblDef.SetBounds(lpobj, lprc);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLECLIPFORMAT FAR PASCAL _loadds DllEnumFormats (
+LPOLEOBJECT lpobj,
+OLECLIPFORMAT cf)
+{
+ DPRINTF(("OleEnumFormats(%d)", cf));
+
+ return vtblDef.EnumFormats(lpobj, cf);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetColorScheme (
+LPOLEOBJECT lpobj,
+LPLOGPALETTE lppal)
+{
+ DPRINTF(("OleSetColorScheme()"));
+
+ return vtblDef.SetColorScheme(lpobj, lppal);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllDelete (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleDelete(%lx)", lpobj));
+
+ DelObj(lpobj);
+ CleanObjects();
+
+ return vtblDef.Delete(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetHostNames (
+LPOLEOBJECT lpobj,
+LPSTR szClientName,
+LPSTR szDocName)
+{
+ DPRINTF(("OleSetHostNames(%ls,%ls)", szClientName, szDocName));
+
+ return vtblDef.SetHostNames(lpobj, szClientName, szDocName);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSaveToStream (
+LPOLEOBJECT lpobj,
+LPOLESTREAM lpstream)
+{
+ DPRINTF(("OleSaveToStream()"));
+
+ return vtblDef.SaveToStream(lpobj, lpstream);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllClone (
+LPOLEOBJECT lpobj,
+LPOLECLIENT lpClient,
+LHCLIENTDOC lhClientDoc,
+LPSTR szObjName,
+LPOLEOBJECT FAR*lplpobj)
+{
+ OLESTATUS err;
+
+ DPRINTF(("OleClone(%ls)", szObjName));
+
+ err = vtblDef.Clone(lpobj, lpClient, lhClientDoc, szObjName, lplpobj);
+
+ //
+ // if the object cloned correctly then clone our object information
+ //
+ if (err <= OLE_WAIT_FOR_RELEASE)
+ {
+ OBJINFO *poi, *poiT;
+
+ if ((poiT = FindObj(lpobj)) && (poi = NewObj(NULL)))
+ {
+ poi->lpobj = *lplpobj;
+ poi->hwnd = poiT->hwnd;
+ poi->rcActivate = poiT->rcActivate;
+ poi->hwndDraw = poiT->hwndDraw;
+ poi->rcDraw = poiT->rcDraw;
+ }
+ }
+
+ return err;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCopyFromLink (
+LPOLEOBJECT lpobj,
+LPOLECLIENT lpClient,
+LHCLIENTDOC lhClientDoc,
+LPSTR szObjName,
+LPOLEOBJECT FAR*lplpobj)
+{
+ OLESTATUS err;
+
+ DPRINTF(("OleCopyFromLink(%ls)", szObjName));
+
+ err = vtblDef.CopyFromLink(lpobj, lpClient, lhClientDoc, szObjName, lplpobj);
+
+ if (err <= OLE_WAIT_FOR_RELEASE)
+ NewObj(*lplpobj);
+
+ return err;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllEqual (
+LPOLEOBJECT lpobj1,
+LPOLEOBJECT lpobj2)
+{
+ DPRINTF(("OleEqual()"));
+
+ return vtblDef.Equal(lpobj1, lpobj2);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllCopyToClipboard (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleCopyToClipboard()"));
+
+ return vtblDef.CopyToClipboard(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllDraw (
+LPOLEOBJECT lpobj,
+HDC hdc,
+LPRECT lprcBounds,
+LPRECT lprcWBounds,
+HDC hdcFormat)
+{
+ OBJINFO *poi;
+ RECT rc;
+ DWORD dw;
+
+ DPRINTF(("OleDraw(%lx,[%d,%d,%d,%d], [%d,%d,%d,%d])", lpobj, PUSHRC(lprcBounds), PUSHRC(lprcWBounds)));
+
+#ifdef DEBUG
+ if (OleIsDcMeta(hdc))
+ DPRINTF(("OleDraw: drawing to a meta-file"));
+ else if (IsDcMemory(hdc))
+ DPRINTF(("OleDraw: drawing to a bitmap"));
+#endif
+
+ if ((poi = FindObj(lpobj)) && !OleIsDcMeta(hdc) && !IsDcMemory(hdc))
+ {
+ //!!!get the window from the HDC!!!
+
+ poi->hwndDraw = WindowFromDC(hdc);
+ DPRINTF(("OleDraw: hwndDraw = %04X", poi->hwndDraw));
+
+ if (lprcBounds && !IsRectEmpty(lprcBounds))
+ {
+ poi->rcDraw = *lprcBounds;
+
+ //
+ // convert the bound rectange into coordinates.
+ // relative to hwndDraw
+ //
+ LPtoDP(hdc, (LPPOINT)&poi->rcDraw, 2);
+
+ if (poi->hwndDraw == NULL)
+ {
+ dw = GetDCOrg(hdc);
+ OffsetRect(&poi->rcDraw, LOWORD(dw), HIWORD(dw));
+ }
+ }
+
+ if (GetClipBox(hdc, &rc) == NULLREGION)
+ return OLE_OK;
+ }
+
+ return vtblDef.Draw(lpobj, hdc, lprcBounds, lprcWBounds, hdcFormat);
+}
+
+/****************************************************************************
+
+ scan WinWords stack and "extract" the info it should have passed to
+ OleActivate() this has been tested with WinWord 2.0 and 2.0a.
+
+ we expect future verisons of WinWord to pass the correct info to
+ OleActivate() so we will never get here.
+
+****************************************************************************/
+
+BOOL NEAR PASCAL GetOpusRect(LPRECT lprcBound)
+{
+ LPRECT lprc;
+ LPVOID lp;
+// int i,dx,dy;
+
+ //
+ // see if the current app is WinWord
+ //
+ if (!IsApp("WINWORD.EXE"))
+ return FALSE;
+
+ //
+ // lets scan the stack looking for a RECT, this is a total
+ // hack to get MSWORD to work.
+ //
+ _asm
+ {
+ mov bx,ss:[bp] ; get saved BP DllActivate()
+ and bx, not 1
+ mov bx,ss:[bx] ; get saved saved BP OleActivate()
+ and bx, not 1
+ mov bx,ss:[bx] ; get saved saved saved BP "winword"
+ and bx, not 1
+
+ mov word ptr lp[0], bx
+ mov word ptr lp[2], ss
+ }
+
+#ifdef DEBUG
+ DPRINTF(("****** SCANING WINWORDs STACK ********"));
+ lprc = lp;
+
+ for (i=0; i<1000; i++)
+ {
+ dx = lprc->right - lprc->left;
+ dy = lprc->bottom - lprc->top;
+
+ if (dx >= 158 && dx <= 162 &&
+ dy >= 118 && dy <= 122)
+ {
+ DPRINTF(("found a RECT at offset %d, [%d, %d, %d, %d]",
+ (LPBYTE)lprc - (LPBYTE)lp, PUSHRC(lprc)));
+ }
+
+ ((LPBYTE)lprc)++;
+ }
+ DPRINTF(("**************************************"));
+#endif
+
+ lprc = (LPRECT)((LPBYTE)lp + 6);
+
+ if (lprc->right - lprc->left > 0 && lprc->bottom - lprc->top > 0)
+ {
+ DPRINTF(("*** HACK FOR WINWORD, [%d, %d, %d, %d]", PUSHRC(lprc)));
+ *lprcBound = *lprc;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllActivate (
+LPOLEOBJECT lpobj,
+WORD verb,
+BOOL fShow,
+BOOL fActivate,
+HWND hwnd,
+LPRECT lprcBound)
+{
+ OBJINFO *poi;
+ RECT rc;
+
+ DPRINTF(("OleActivate(%lx, %d, %d, %d, %04X, [%d,%d,%d,%d])", lpobj, verb, fShow, fActivate, hwnd, PUSHRC(lprcBound)));
+
+ //
+ // hack for Write
+ //
+ if (IsWindow(fActivate))
+ {
+ DPRINTF(("OleActivate: Write pre-realase work around"));
+ hwnd = fActivate;
+ fActivate = TRUE;
+ }
+
+ if (poi = FindObj(lpobj))
+ {
+ lpobjActive = lpobj;
+
+ poi->hwnd = hwnd;
+
+ if (poi->hwnd == NULL)
+ {
+ if (GetFocus())
+ {
+ DPRINTF(("OleActivate: no window specifed, using the focus window"));
+ poi->hwnd = GetFocus();
+ }
+ else
+ {
+ DPRINTF(("OleActivate: no window specifed, using the active window"));
+ poi->hwnd = GetActiveWindow();
+ }
+ }
+
+ if (lprcBound && !IsRectEmpty(lprcBound))
+ {
+ poi->rcActivate = *lprcBound;
+ }
+ else
+ {
+ GetOpusRect(&poi->rcActivate);
+ }
+
+ //
+ // MS-Publisher gives use the *wrong* rectangle in the OleActivate call
+ // and never calls OleDraw() we are hosed!
+ //
+ // so we check if the rect is off in space, and dont use it if so.
+ //
+ if (poi->hwnd)
+ {
+ GetClientRect(poi->hwnd, &rc);
+
+ IntersectRect(&rc,&rc,&poi->rcActivate);
+
+ if (IsRectEmpty(&rc))
+ {
+ DPRINTF(("OleActivate: rectangle specifed is not valid"));
+ SetRectEmpty(&poi->rcActivate);
+ }
+ }
+
+ if (IsRectEmpty(&poi->rcActivate))
+ {
+ DPRINTF(("OleActivate: stupid ole app!!!"));
+ }
+
+ //
+ // Shove it in the registry
+ //
+
+ {
+ RegSetGetData(poi, TRUE);
+ }
+ }
+
+ return vtblDef.Activate(lpobj, verb, fShow, fActivate, hwnd, lprcBound);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllExecute (
+LPOLEOBJECT lpobj,
+HANDLE hCmds,
+WORD reserved)
+{
+ DPRINTF(("OleExecute(%ls)", GlobalLock(hCmds)));
+
+ return vtblDef.Execute(lpobj, hCmds, reserved);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllClose (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleClose(%lx)", lpobj));
+
+////DelObj(lpobj);
+
+ return vtblDef.Close(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllUpdate (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleUpdate()"));
+
+ return vtblDef.Update(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllReconnect (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleReconnect()"));
+
+ return vtblDef.Reconnect(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllObjectConvert (
+LPOLEOBJECT lpobj,
+LPSTR szProtocol,
+LPOLECLIENT lpClient,
+LHCLIENTDOC lhClientDoc,
+LPSTR szObjName,
+LPOLEOBJECT FAR*lplpobj)
+{
+ OLESTATUS err;
+
+ DPRINTF(("OleObjectConvert(%ls,%ls)", szProtocol, szObjName));
+
+ err = vtblDef.ObjectConvert(lpobj, szProtocol, lpClient, lhClientDoc, szObjName, lplpobj);
+
+ if (err <= OLE_WAIT_FOR_RELEASE)
+ NewObj(*lplpobj);
+
+ return err;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllGetLinkUpdateOptions (
+LPOLEOBJECT lpobj,
+OLEOPT_UPDATE FAR *lpoleopt)
+{
+ DPRINTF(("OleGetLinkUpdateOptions()"));
+
+ return vtblDef.GetLinkUpdateOptions(lpobj, lpoleopt);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllSetLinkUpdateOptions (
+LPOLEOBJECT lpobj,
+OLEOPT_UPDATE oleopt)
+{
+ DPRINTF(("OleSetLinkUpdateOptions()"));
+
+ return vtblDef.SetLinkUpdateOptions(lpobj, oleopt);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllRename (
+LPOLEOBJECT lpobj,
+LPSTR szName)
+{
+ DPRINTF(("OleRename(%ls)", szName));
+
+ return vtblDef.Rename(lpobj, szName);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryName (
+LPOLEOBJECT lpobj,
+LPSTR szObjName,
+WORD FAR * lpwSize)
+{
+ DPRINTF(("OleQueryName(%ls)", szObjName));
+
+ return vtblDef.QueryName(lpobj, szObjName, lpwSize);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryType (
+LPOLEOBJECT lpobj,
+LPLONG lpType)
+{
+ DPRINTF(("OleQueryType()"));
+
+ return vtblDef.QueryType(lpobj, lpType);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryBounds (
+LPOLEOBJECT lpobj,
+LPRECT lprc)
+{
+ DPRINTF(("OleQueryBounds()"));
+
+ return vtblDef.QueryBounds(lpobj, lprc);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQuerySize (
+LPOLEOBJECT lpobj,
+DWORD FAR * lpdwSize)
+{
+ DPRINTF(("OleQuerySize()"));
+
+ return vtblDef.QuerySize(lpobj, lpdwSize);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryOpen (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleQueryOpen()"));
+
+ return vtblDef.QueryOpen(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryOutOfDate (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleQueryOutOfDate()"));
+
+ return vtblDef.QueryOutOfDate(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryReleaseStatus (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleQueryReleaseStatus()"));
+
+ return vtblDef.QueryReleaseStatus(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllQueryReleaseError (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleQueryReleaseError()"));
+
+ return vtblDef.QueryReleaseError(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllRequestData (
+LPOLEOBJECT lpobj,
+OLECLIPFORMAT cf)
+{
+ DPRINTF(("OleRequestData(%d)", cf));
+
+ return vtblDef.RequestData(lpobj, cf);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllObjectLong (
+LPOLEOBJECT lpobj,
+WORD w,
+LPLONG lpl)
+{
+ DPRINTF(("OleObjectLong()"));
+
+ return vtblDef.ObjectLong(lpobj, w, lpl);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLE_RELEASE_METHOD FAR PASCAL _loadds DllQueryReleaseMethod (
+LPOLEOBJECT lpobj)
+{
+ DPRINTF(("OleQueryReleaseMethod()"));
+
+ return vtblDef.QueryReleaseMethod(lpobj);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+OLESTATUS FAR PASCAL _loadds DllChangeData (
+LPOLEOBJECT lpobj,
+HANDLE h,
+LPOLECLIENT lpClient,
+BOOL f)
+{
+ DPRINTF(("OleChangeData()"));
+
+ return vtblDef.ChangeData(lpobj, h, lpClient, f);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DEBUG STUFF
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef DEBUG
+
+void FAR cdecl dprintf(LPSTR szFormat, ...)
+{
+ char ach[128];
+
+ extern FAR PASCAL OutputDebugStr(LPSTR);
+
+ lstrcpy(ach, "MCIOLE: ");
+ wvsprintf(ach + 8,szFormat,(LPSTR)(&szFormat+1));
+ lstrcat(ach,"\r\n");
+
+ OutputDebugString(ach);
+}
+
+#endif
diff --git a/private/mvdm/wow16/mciole/mciole.def b/private/mvdm/wow16/mciole/mciole.def
new file mode 100644
index 000000000..1aa5e50c3
--- /dev/null
+++ b/private/mvdm/wow16/mciole/mciole.def
@@ -0,0 +1,43 @@
+LIBRARY MCIOLE16
+EXETYPE WINDOWS
+
+DESCRIPTION 'OLE handler DLL for MCI objects'
+
+;STUB 'WINSTUB.EXE'
+
+;CODE MOVEABLE DISCARDABLE LOADONCALL
+CODE MOVEABLE PRELOAD
+DATA SINGLE MOVEABLE PRELOAD
+
+HEAPSIZE 128
+
+EXPORTS
+ WEP @1 RESIDENTNAME
+
+ ;
+ ; OLICLI.DLL will call these functions when the client calls
+ ; Ole?????(), we then can hook out all the other functions we want.
+ ;
+ DllLoadFromStream @2
+ DllCreateFromClip @3
+ DllCreateLinkFromClip @4
+ DllCreateFromTemplate @5
+ DllCreate @6
+ DllCreateFromFile @7
+ DllCreateLinkFromFile @8
+
+ ;
+ ; this DLL exports this so a server can call it to get the position
+ ; of a object
+ ;
+ OleQueryObjPos @10
+
+IMPORTS
+ OutputDebugStr = MMSYSTEM.OutputDebugStr
+ DefLoadFromStream = OLECLI.DefLoadFromStream
+ DefCreateFromClip = OLECLI.DefCreateFromClip
+ DefCreateLinkFromClip = OLECLI.DefCreateLinkFromClip
+ DefCreateFromTemplate = OLECLI.DefCreateFromTemplate
+ DefCreate = OLECLI.DefCreate
+ DefCreateFromFile = OLECLI.DefCreateFromFile
+ DefCreateLinkFromFile = OLECLI.DefCreateLinkFromFile
diff --git a/private/mvdm/wow16/mciole/mciole.h b/private/mvdm/wow16/mciole/mciole.h
new file mode 100644
index 000000000..335757c14
--- /dev/null
+++ b/private/mvdm/wow16/mciole/mciole.h
@@ -0,0 +1,77 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// these are the default OLE functions (exported from OLECLI.DLL)
+//
+///////////////////////////////////////////////////////////////////////////////
+extern OLESTATUS FAR PASCAL DefLoadFromStream (LPOLESTREAM, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+extern OLESTATUS FAR PASCAL DefCreateFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+extern OLESTATUS FAR PASCAL DefCreateLinkFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+extern OLESTATUS FAR PASCAL DefCreateFromTemplate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+extern OLESTATUS FAR PASCAL DefCreate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+extern OLESTATUS FAR PASCAL DefCreateFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+extern OLESTATUS FAR PASCAL DefCreateLinkFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// these are our OLE handlers (defined in this file)
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Server has to implement only the following methods.
+LPVOID FAR PASCAL _loadds DllQueryProtocol (LPOLEOBJECT, LPSTR);
+OLESTATUS FAR PASCAL _loadds DllRelease (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllShow (LPOLEOBJECT, BOOL);
+OLESTATUS FAR PASCAL _loadds DllDoVerb (LPOLEOBJECT, WORD, BOOL, BOOL);
+OLESTATUS FAR PASCAL _loadds DllGetData (LPOLEOBJECT, OLECLIPFORMAT, LPHANDLE);
+OLESTATUS FAR PASCAL _loadds DllSetData (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS FAR PASCAL _loadds DllSetTargetDevice (LPOLEOBJECT, HANDLE);
+OLESTATUS FAR PASCAL _loadds DllSetBounds (LPOLEOBJECT, LPRECT);
+OLECLIPFORMAT FAR PASCAL _loadds DllEnumFormats (LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS FAR PASCAL _loadds DllSetColorScheme (LPOLEOBJECT, LPLOGPALETTE);
+
+// Extra methods required for client.
+OLESTATUS FAR PASCAL _loadds DllDelete (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllSetHostNames (LPOLEOBJECT, LPSTR, LPSTR);
+OLESTATUS FAR PASCAL _loadds DllSaveToStream (LPOLEOBJECT, LPOLESTREAM);
+OLESTATUS FAR PASCAL _loadds DllClone (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+OLESTATUS FAR PASCAL _loadds DllCopyFromLink (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+OLESTATUS FAR PASCAL _loadds DllEqual (LPOLEOBJECT, LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllCopyToClipboard (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllDraw (LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS FAR PASCAL _loadds DllActivate (LPOLEOBJECT, WORD, BOOL, BOOL, HWND, LPRECT);
+OLESTATUS FAR PASCAL _loadds DllExecute (LPOLEOBJECT, HANDLE, WORD);
+OLESTATUS FAR PASCAL _loadds DllClose (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllUpdate (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllReconnect (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllObjectConvert (LPOLEOBJECT, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+OLESTATUS FAR PASCAL _loadds DllGetLinkUpdateOptions (LPOLEOBJECT, OLEOPT_UPDATE FAR *);
+OLESTATUS FAR PASCAL _loadds DllSetLinkUpdateOptions (LPOLEOBJECT, OLEOPT_UPDATE);
+OLESTATUS FAR PASCAL _loadds DllRename (LPOLEOBJECT, LPSTR);
+OLESTATUS FAR PASCAL _loadds DllQueryName (LPOLEOBJECT, LPSTR, WORD FAR *);
+OLESTATUS FAR PASCAL _loadds DllQueryType (LPOLEOBJECT, LPLONG);
+OLESTATUS FAR PASCAL _loadds DllQueryBounds (LPOLEOBJECT, LPRECT);
+OLESTATUS FAR PASCAL _loadds DllQuerySize (LPOLEOBJECT, DWORD FAR *);
+OLESTATUS FAR PASCAL _loadds DllQueryOpen (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllQueryOutOfDate (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllQueryReleaseStatus (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllQueryReleaseError (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds DllRequestData (LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS FAR PASCAL _loadds DllObjectLong (LPOLEOBJECT, WORD, LPLONG);
+OLE_RELEASE_METHOD FAR PASCAL _loadds DllQueryReleaseMethod(LPOLEOBJECT);
+
+// This method is internal only
+OLESTATUS FAR PASCAL _loadds DllChangeData (LPOLEOBJECT, HANDLE, LPOLECLIENT, BOOL);
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// DEBUG STUFF
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef DEBUG
+ extern void FAR cdecl dprintf(LPSTR, ...);
+
+ #define DPRINTF(x) dprintf x
+#else
+ #define DPRINTF(x)
+#endif
diff --git a/private/mvdm/wow16/mciole/mciole16.rc b/private/mvdm/wow16/mciole/mciole16.rc
new file mode 100644
index 000000000..1f327ad86
--- /dev/null
+++ b/private/mvdm/wow16/mciole/mciole16.rc
@@ -0,0 +1,5 @@
+/********************************************************************/
+/* MCIOLE16.RC */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include "mciole16.rcv"
diff --git a/private/mvdm/wow16/mciole/mciole16.rcv b/private/mvdm/wow16/mciole/mciole16.rcv
new file mode 100644
index 000000000..a99b8edc8
--- /dev/null
+++ b/private/mvdm/wow16/mciole/mciole16.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* MCIOLE16.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "MCIOLE16 - OLE Handler DLL for MCI Objects"
+#define VER_INTERNALNAME_STR "MCIOLE16"
+#define VER_ORIGINALFILENAME_STR "MCIOLE16.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/mciole/ole.h b/private/mvdm/wow16/mciole/ole.h
new file mode 100644
index 000000000..37bcf9cad
--- /dev/null
+++ b/private/mvdm/wow16/mciole/ole.h
@@ -0,0 +1,504 @@
+/*****************************************************************************\
+* *
+* ole.h - Object Linking and Embedding functions, types, and definitions*
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1990-1992, Microsoft Corp. All rights reserved.*
+* *
+\*****************************************************************************/
+
+#ifndef _INC_OLE
+#define _INC_OLE
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef WINAPI /* If not included with 3.1 headers... */
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+#ifdef STRICT
+#define OLE_LPCSTR LPCSTR
+#define OLE_CONST const
+#else /* STRICT */
+#define OLE_LPCSTR LPSTR
+#define OLE_CONST
+#endif /* !STRICT */
+
+
+/* Object types */
+#define OT_LINK 1L
+#define OT_EMBEDDED 2L
+#define OT_STATIC 3L
+
+/* activate verbs */
+#define OLEVERB_PRIMARY 0
+
+/* target device info structure */
+typedef struct _OLETARGETDEVICE
+{
+ UINT otdDeviceNameOffset;
+ UINT otdDriverNameOffset;
+ UINT otdPortNameOffset;
+ UINT otdExtDevmodeOffset;
+ UINT otdExtDevmodeSize;
+ UINT otdEnvironmentOffset;
+ UINT otdEnvironmentSize;
+ BYTE otdData[1];
+} OLETARGETDEVICE;
+typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE;
+
+/* flags used in some methods */
+#define OF_SET 0x0001
+#define OF_GET 0x0002
+#define OF_HANDLER 0x0004
+
+/* return codes for OLE functions */
+typedef enum
+{
+ OLE_OK, /* 0 Function operated correctly */
+
+ OLE_WAIT_FOR_RELEASE, /* 1 Command has been initiated, client */
+ /* must wait for release. keep dispatching */
+ /* messages till OLE_RELESE in callback */
+
+ OLE_BUSY, /* 2 Tried to execute a method while another */
+ /* method is in progress. */
+
+ OLE_ERROR_PROTECT_ONLY, /* 3 Ole APIs are called in real mode */
+ OLE_ERROR_MEMORY, /* 4 Could not alloc or lock memory */
+ OLE_ERROR_STREAM, /* 5 (OLESTREAM) stream error */
+ OLE_ERROR_STATIC, /* 6 Non static object expected */
+ OLE_ERROR_BLANK, /* 7 Critical data missing */
+ OLE_ERROR_DRAW, /* 8 Error while drawing */
+ OLE_ERROR_METAFILE, /* 9 Invalid metafile */
+ OLE_ERROR_ABORT, /* 10 Client chose to abort metafile drawing */
+ OLE_ERROR_CLIPBOARD, /* 11 Failed to get/set clipboard data */
+ OLE_ERROR_FORMAT, /* 12 Requested format is not available */
+ OLE_ERROR_OBJECT, /* 13 Not a valid object */
+ OLE_ERROR_OPTION, /* 14 Invalid option(link update / render) */
+ OLE_ERROR_PROTOCOL, /* 15 Invalid protocol */
+ OLE_ERROR_ADDRESS, /* 16 One of the pointers is invalid */
+ OLE_ERROR_NOT_EQUAL, /* 17 Objects are not equal */
+ OLE_ERROR_HANDLE, /* 18 Invalid handle encountered */
+ OLE_ERROR_GENERIC, /* 19 Some general error */
+ OLE_ERROR_CLASS, /* 20 Invalid class */
+ OLE_ERROR_SYNTAX, /* 21 Command syntax is invalid */
+ OLE_ERROR_DATATYPE, /* 22 Data format is not supported */
+ OLE_ERROR_PALETTE, /* 23 Invalid color palette */
+ OLE_ERROR_NOT_LINK, /* 24 Not a linked object */
+ OLE_ERROR_NOT_EMPTY, /* 25 Client doc contains objects. */
+ OLE_ERROR_SIZE, /* 26 Incorrect buffer size passed to the api */
+ /* that places some string in caller's */
+ /* buffer */
+
+ OLE_ERROR_DRIVE, /* 27 Drive letter in doc name is invalid */
+ OLE_ERROR_NETWORK, /* 28 Failed to establish connection to a */
+ /* network share on which the document */
+ /* is located */
+
+ OLE_ERROR_NAME, /* 29 Invalid name(doc name, object name), */
+ /* etc.. passed to the APIs */
+
+ OLE_ERROR_TEMPLATE, /* 30 Server failed to load template */
+ OLE_ERROR_NEW, /* 31 Server failed to create new doc */
+ OLE_ERROR_EDIT, /* 32 Server failed to create embedded */
+ /* instance */
+ OLE_ERROR_OPEN, /* 33 Server failed to open document, */
+ /* possible invalid link */
+
+ OLE_ERROR_NOT_OPEN, /* 34 Object is not open for editing */
+ OLE_ERROR_LAUNCH, /* 35 Failed to launch server */
+ OLE_ERROR_COMM, /* 36 Failed to communicate with server */
+ OLE_ERROR_TERMINATE, /* 37 Error in termination */
+ OLE_ERROR_COMMAND, /* 38 Error in execute */
+ OLE_ERROR_SHOW, /* 39 Error in show */
+ OLE_ERROR_DOVERB, /* 40 Error in sending do verb, or invalid */
+ /* verb */
+ OLE_ERROR_ADVISE_NATIVE, /* 41 Item could be missing */
+ OLE_ERROR_ADVISE_PICT, /* 42 Item could be missing or server doesn't */
+ /* this format. */
+
+ OLE_ERROR_ADVISE_RENAME, /* 43 Server doesn't support rename */
+ OLE_ERROR_POKE_NATIVE, /* 44 Failure of poking native data to server */
+ OLE_ERROR_REQUEST_NATIVE, /* 45 Server failed to render native data */
+ OLE_ERROR_REQUEST_PICT, /* 46 Server failed to render presentation */
+ /* data */
+ OLE_ERROR_SERVER_BLOCKED, /* 47 Trying to block a blocked server or */
+ /* trying to revoke a blocked server */
+ /* or document */
+
+ OLE_ERROR_REGISTRATION, /* 48 Server is not registered in regestation */
+ /* data base */
+ OLE_ERROR_ALREADY_REGISTERED,/*49 Trying to register same doc multiple */
+ /* times */
+ OLE_ERROR_TASK, /* 50 Server or client task is invalid */
+ OLE_ERROR_OUTOFDATE, /* 51 Object is out of date */
+ OLE_ERROR_CANT_UPDATE_CLIENT,/* 52 Embed doc's client doesn't accept */
+ /* updates */
+ OLE_ERROR_UPDATE, /* 53 erorr while trying to update */
+ OLE_ERROR_SETDATA_FORMAT, /* 54 Server app doesn't understand the */
+ /* format given to its SetData method */
+ OLE_ERROR_STATIC_FROM_OTHER_OS,/* 55 trying to load a static object created */
+ /* on another Operating System */
+
+ /* Following are warnings */
+ OLE_WARN_DELETE_DATA = 1000 /* Caller must delete the data when he is */
+ /* done with it. */
+} OLESTATUS;
+
+
+
+/* Codes for CallBack events */
+typedef enum
+{
+ OLE_CHANGED, /* 0 */
+ OLE_SAVED, /* 1 */
+ OLE_CLOSED, /* 2 */
+ OLE_RENAMED, /* 3 */
+ OLE_QUERY_PAINT, /* 4 Interruptible paint support */
+ OLE_RELEASE, /* 5 Object is released(asynchronous operation */
+ /* is completed) */
+ OLE_QUERY_RETRY /* 6 Query for retry when server sends busy ACK */
+} OLE_NOTIFICATION;
+
+typedef enum
+{
+ OLE_NONE, /* 0 no method active */
+ OLE_DELETE, /* 1 object delete */
+ OLE_LNKPASTE, /* 2 PasteLink(auto reconnect) */
+ OLE_EMBPASTE, /* 3 paste(and update) */
+ OLE_SHOW, /* 4 Show */
+ OLE_RUN, /* 5 Run */
+ OLE_ACTIVATE, /* 6 Activate */
+ OLE_UPDATE, /* 7 Update */
+ OLE_CLOSE, /* 8 Close */
+ OLE_RECONNECT, /* 9 Reconnect */
+ OLE_SETUPDATEOPTIONS, /* 10 setting update options */
+ OLE_SERVERUNLAUNCH, /* 11 server is being unlaunched */
+ OLE_LOADFROMSTREAM, /* 12 LoadFromStream(auto reconnect) */
+ OLE_SETDATA, /* 13 OleSetData */
+ OLE_REQUESTDATA, /* 14 OleRequestData */
+ OLE_OTHER, /* 15 other misc async operations */
+ OLE_CREATE, /* 16 create */
+ OLE_CREATEFROMTEMPLATE, /* 17 CreatefromTemplate */
+ OLE_CREATELINKFROMFILE, /* 18 CreateLinkFromFile */
+ OLE_COPYFROMLNK, /* 19 CopyFromLink(auto reconnect) */
+ OLE_CREATEFROMFILE, /* 20 CreateFromFile */
+ OLE_CREATEINVISIBLE /* 21 CreateInvisible */
+} OLE_RELEASE_METHOD;
+
+/* rendering options */
+typedef enum
+{
+ olerender_none,
+ olerender_draw,
+ olerender_format
+} OLEOPT_RENDER;
+
+/* standard clipboard format type */
+typedef WORD OLECLIPFORMAT;
+
+/* Link update options */
+typedef enum
+{
+ oleupdate_always,
+ oleupdate_onsave,
+#ifndef OLE_INTERNAL
+ oleupdate_oncall
+#else
+ oleupdate_oncall,
+ oleupdate_onclose
+#endif /* OLE_INTERNAL */
+} OLEOPT_UPDATE;
+
+typedef HANDLE HOBJECT;
+typedef LONG LHSERVER;
+typedef LONG LHCLIENTDOC;
+typedef LONG LHSERVERDOC;
+
+typedef struct _OLEOBJECT FAR* LPOLEOBJECT;
+typedef struct _OLESTREAM FAR* LPOLESTREAM;
+typedef struct _OLECLIENT FAR* LPOLECLIENT;
+
+
+#ifndef OLE_INTERNAL
+/* object method table definitions. */
+typedef struct _OLEOBJECTVTBL
+{
+ void FAR* (CALLBACK* QueryProtocol) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* Release) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Show) (LPOLEOBJECT, BOOL);
+ OLESTATUS (CALLBACK* DoVerb) (LPOLEOBJECT, UINT, BOOL, BOOL);
+ OLESTATUS (CALLBACK* GetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+ OLESTATUS (CALLBACK* SetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+ OLESTATUS (CALLBACK* SetTargetDevice) (LPOLEOBJECT, HGLOBAL);
+ OLESTATUS (CALLBACK* SetBounds) (LPOLEOBJECT, OLE_CONST RECT FAR*);
+ OLECLIPFORMAT (CALLBACK* EnumFormats) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* SetColorScheme) (LPOLEOBJECT, OLE_CONST LOGPALETTE FAR*);
+ /* Server has to implement only the above methods. */
+
+#ifndef SERVERONLY
+ /* Extra methods required for client. */
+ OLESTATUS (CALLBACK* Delete) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* SetHostNames) (LPOLEOBJECT, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SaveToStream) (LPOLEOBJECT, LPOLESTREAM);
+ OLESTATUS (CALLBACK* Clone) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* CopyFromLink) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* Equal) (LPOLEOBJECT, LPOLEOBJECT);
+ OLESTATUS (CALLBACK* CopyToClipboard) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Draw) (LPOLEOBJECT, HDC, OLE_CONST RECT FAR*, OLE_CONST RECT FAR*, HDC);
+ OLESTATUS (CALLBACK* Activate) (LPOLEOBJECT, UINT, BOOL, BOOL, HWND, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLEOBJECT, HGLOBAL, UINT);
+ OLESTATUS (CALLBACK* Close) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Update) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Reconnect) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* ObjectConvert) (LPOLEOBJECT, OLE_LPCSTR, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* GetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+ OLESTATUS (CALLBACK* SetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE);
+
+ OLESTATUS (CALLBACK* Rename) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* QueryName) (LPOLEOBJECT, LPSTR, UINT FAR*);
+
+ OLESTATUS (CALLBACK* QueryType) (LPOLEOBJECT, LONG FAR*);
+ OLESTATUS (CALLBACK* QueryBounds) (LPOLEOBJECT, RECT FAR*);
+ OLESTATUS (CALLBACK* QuerySize) (LPOLEOBJECT, DWORD FAR*);
+ OLESTATUS (CALLBACK* QueryOpen) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryOutOfDate) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* QueryReleaseStatus) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryReleaseError) (LPOLEOBJECT);
+ OLE_RELEASE_METHOD (CALLBACK* QueryReleaseMethod)(LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* RequestData) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* ObjectLong) (LPOLEOBJECT, UINT, LONG FAR*);
+
+/* This method is internal only */
+ OLESTATUS (CALLBACK* ChangeData) (LPOLEOBJECT, HANDLE, LPOLECLIENT, BOOL);
+#endif /* !SERVERONLY */
+} OLEOBJECTVTBL;
+typedef OLEOBJECTVTBL FAR* LPOLEOBJECTVTBL;
+
+typedef struct _OLEOBJECT
+{
+ LPOLEOBJECTVTBL lpvtbl;
+} OLEOBJECT;
+#endif /* !OLE_NTERNAL */
+
+/* ole client definitions */
+typedef struct _OLECLIENTVTBL
+{
+ int (CALLBACK* CallBack)(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT);
+} OLECLIENTVTBL;
+
+typedef OLECLIENTVTBL FAR* LPOLECLIENTVTBL;
+
+typedef struct _OLECLIENT
+{
+ LPOLECLIENTVTBL lpvtbl;
+} OLECLIENT;
+
+/* Stream definitions */
+typedef struct _OLESTREAMVTBL
+{
+ DWORD (CALLBACK* Get)(LPOLESTREAM, void FAR*, DWORD);
+ DWORD (CALLBACK* Put)(LPOLESTREAM, OLE_CONST void FAR*, DWORD);
+} OLESTREAMVTBL;
+typedef OLESTREAMVTBL FAR* LPOLESTREAMVTBL;
+
+typedef struct _OLESTREAM
+{
+ LPOLESTREAMVTBL lpstbl;
+} OLESTREAM;
+
+/* Public Function Prototypes */
+OLESTATUS WINAPI OleDelete(LPOLEOBJECT);
+OLESTATUS WINAPI OleRelease(LPOLEOBJECT);
+OLESTATUS WINAPI OleSaveToStream(LPOLEOBJECT, LPOLESTREAM);
+OLESTATUS WINAPI OleEqual(LPOLEOBJECT, LPOLEOBJECT );
+OLESTATUS WINAPI OleCopyToClipboard(LPOLEOBJECT);
+OLESTATUS WINAPI OleSetHostNames(LPOLEOBJECT, LPCSTR, LPCSTR);
+OLESTATUS WINAPI OleSetTargetDevice(LPOLEOBJECT, HGLOBAL);
+OLESTATUS WINAPI OleSetBounds(LPOLEOBJECT, const RECT FAR*);
+OLESTATUS WINAPI OleSetColorScheme(LPOLEOBJECT, const LOGPALETTE FAR*);
+OLESTATUS WINAPI OleQueryBounds(LPOLEOBJECT, RECT FAR*);
+OLESTATUS WINAPI OleQuerySize(LPOLEOBJECT, DWORD FAR*);
+OLESTATUS WINAPI OleDraw(LPOLEOBJECT, HDC, const RECT FAR*, const RECT FAR*, HDC);
+OLESTATUS WINAPI OleQueryOpen(LPOLEOBJECT);
+OLESTATUS WINAPI OleActivate(LPOLEOBJECT, UINT, BOOL, BOOL, HWND, const RECT FAR*);
+OLESTATUS WINAPI OleExecute(LPOLEOBJECT, HGLOBAL, UINT);
+OLESTATUS WINAPI OleClose(LPOLEOBJECT);
+OLESTATUS WINAPI OleUpdate(LPOLEOBJECT);
+OLESTATUS WINAPI OleReconnect(LPOLEOBJECT);
+OLESTATUS WINAPI OleGetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+OLESTATUS WINAPI OleSetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE);
+void FAR* WINAPI OleQueryProtocol(LPOLEOBJECT, LPCSTR);
+
+/* Routines related to asynchronous operations. */
+OLESTATUS WINAPI OleQueryReleaseStatus(LPOLEOBJECT);
+OLESTATUS WINAPI OleQueryReleaseError(LPOLEOBJECT);
+OLE_RELEASE_METHOD WINAPI OleQueryReleaseMethod(LPOLEOBJECT);
+
+OLESTATUS WINAPI OleQueryType(LPOLEOBJECT, LONG FAR*);
+
+/* LOWORD is major version, HIWORD is minor version */
+DWORD WINAPI OleQueryClientVersion(void);
+DWORD WINAPI OleQueryServerVersion(void);
+
+/* Converting to format (as in clipboard): */
+OLECLIPFORMAT WINAPI OleEnumFormats(LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS WINAPI OleGetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+OLESTATUS WINAPI OleSetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS WINAPI OleQueryOutOfDate(LPOLEOBJECT);
+OLESTATUS WINAPI OleRequestData(LPOLEOBJECT, OLECLIPFORMAT);
+
+/* Query apis for creation from clipboard */
+OLESTATUS WINAPI OleQueryLinkFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleQueryCreateFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+
+/* Object creation functions */
+OLESTATUS WINAPI OleCreateFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleLoadFromStream(LPOLESTREAM, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCreate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateInvisible(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+OLESTATUS WINAPI OleCreateFromTemplate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleClone(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCopyFromLink(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleObjectConvert(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleRename(LPOLEOBJECT, LPCSTR);
+OLESTATUS WINAPI OleQueryName(LPOLEOBJECT, LPSTR, UINT FAR*);
+OLESTATUS WINAPI OleRevokeObject(LPOLECLIENT);
+BOOL WINAPI OleIsDcMeta(HDC);
+
+/* client document API */
+OLESTATUS WINAPI OleRegisterClientDoc(LPCSTR, LPCSTR, LONG, LHCLIENTDOC FAR*);
+OLESTATUS WINAPI OleRevokeClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleRenameClientDoc(LHCLIENTDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleSavedClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleEnumObjects(LHCLIENTDOC, LPOLEOBJECT FAR*);
+
+/* server usage definitions */
+typedef enum {
+ OLE_SERVER_MULTI, /* multiple instances */
+ OLE_SERVER_SINGLE /* single instance(multiple document) */
+} OLE_SERVER_USE;
+
+/* Server API */
+typedef struct _OLESERVER FAR* LPOLESERVER;
+
+OLESTATUS WINAPI OleRegisterServer(LPCSTR, LPOLESERVER, LHSERVER FAR*, HINSTANCE, OLE_SERVER_USE);
+OLESTATUS WINAPI OleRevokeServer(LHSERVER);
+OLESTATUS WINAPI OleBlockServer(LHSERVER);
+OLESTATUS WINAPI OleUnblockServer(LHSERVER, BOOL FAR*);
+
+/* APIs to keep server open */
+OLESTATUS WINAPI OleLockServer(LPOLEOBJECT, LHSERVER FAR*);
+OLESTATUS WINAPI OleUnlockServer(LHSERVER);
+
+/* Server document API */
+
+typedef struct _OLESERVERDOC FAR* LPOLESERVERDOC;
+
+OLESTATUS WINAPI OleRegisterServerDoc(LHSERVER, LPCSTR, LPOLESERVERDOC, LHSERVERDOC FAR*);
+OLESTATUS WINAPI OleRevokeServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleRenameServerDoc(LHSERVERDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleSavedServerDoc(LHSERVERDOC);
+
+typedef struct _OLESERVERVTBL
+{
+ OLESTATUS (CALLBACK* Open) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* document name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Create)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* CreateFromTemplate)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* lp template name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Edit) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Exit) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Release) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Execute)(LPOLESERVER, HGLOBAL);
+ /* lp OLESERVER */
+ /* handle to command strings */
+} OLESERVERVTBL;
+typedef OLESERVERVTBL FAR* LPOLESERVERVTBL;
+
+typedef struct _OLESERVER
+{
+ LPOLESERVERVTBL lpvtbl;
+} OLESERVER;
+
+typedef struct _OLESERVERDOCVTBL
+{
+ OLESTATUS (CALLBACK* Save) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* Close) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetHostNames)(LPOLESERVERDOC, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SetDocDimensions)(LPOLESERVERDOC, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* GetObject) (LPOLESERVERDOC, OLE_LPCSTR, LPOLEOBJECT FAR*, LPOLECLIENT);
+ OLESTATUS (CALLBACK* Release) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetColorScheme)(LPOLESERVERDOC, OLE_CONST LOGPALETTE FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLESERVERDOC, HGLOBAL);
+} OLESERVERDOCVTBL;
+typedef OLESERVERDOCVTBL FAR* LPOLESERVERDOCVTBL;
+
+typedef struct _OLESERVERDOC
+{
+ LPOLESERVERDOCVTBL lpvtbl;
+} OLESERVERDOC;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_OLE */
diff --git a/private/mvdm/wow16/mciole/shellapi.h b/private/mvdm/wow16/mciole/shellapi.h
new file mode 100644
index 000000000..af978b924
--- /dev/null
+++ b/private/mvdm/wow16/mciole/shellapi.h
@@ -0,0 +1,88 @@
+/*****************************************************************************\
+* *
+* shellapi.h - SHELL.DLL functions, types, and definitions *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_SHELLAPI
+#define _INC_SHELLAPI
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+/* If included with Windows 3.0 windows.h: define 3.1-compatible types */
+
+#ifndef _INC_WINDOWS
+
+#define HDROP HANDLE
+#define WINAPI FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+
+#else
+
+DECLARE_HANDLE(HDROP);
+
+#endif
+
+/* return codes from Registration functions */
+#define ERROR_SUCCESS 0L
+#define ERROR_BADDB 1L
+#define ERROR_BADKEY 2L
+#define ERROR_CANTOPEN 3L
+#define ERROR_CANTREAD 4L
+#define ERROR_CANTWRITE 5L
+#define ERROR_OUTOFMEMORY 6L
+#define ERROR_INVALID_PARAMETER 7L
+#define ERROR_ACCESS_DENIED 8L
+
+#define REG_SZ 1 /* string type */
+
+#define HKEY_CLASSES_ROOT 1
+
+typedef DWORD HKEY;
+typedef HKEY FAR* PHKEY;
+
+LONG WINAPI RegOpenKey(HKEY, LPCSTR, HKEY FAR*);
+LONG WINAPI RegCreateKey(HKEY, LPCSTR, HKEY FAR*);
+LONG WINAPI RegCloseKey(HKEY);
+LONG WINAPI RegDeleteKey(HKEY, LPCSTR);
+LONG WINAPI RegSetValue(HKEY, LPCSTR, DWORD, LPCSTR, DWORD);
+LONG WINAPI RegQueryValue(HKEY, LPCSTR, LPSTR, LONG FAR*);
+LONG WINAPI RegEnumKey(HKEY, DWORD, LPSTR, DWORD);
+
+UINT WINAPI DragQueryFile(HDROP, UINT, LPSTR, UINT);
+BOOL WINAPI DragQueryPoint(HDROP, POINT FAR*);
+void WINAPI DragFinish(HDROP);
+void WINAPI DragAcceptFiles(HWND, BOOL);
+
+HICON WINAPI ExtractIcon(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex);
+
+/* error values for ShellExecute() beyond the regular WinExec() codes */
+#define SE_ERR_SHARE 26
+#define SE_ERR_ASSOCINCOMPLETE 27
+#define SE_ERR_DDETIMEOUT 28
+#define SE_ERR_DDEFAIL 29
+#define SE_ERR_DDEBUSY 30
+#define SE_ERR_NOASSOC 31
+
+HINSTANCE WINAPI ShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int iShowCmd);
+HINSTANCE WINAPI FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* RC_INVOKED */
+
+#endif /* _INC_SHELLAPI */
diff --git a/private/mvdm/wow16/mmsystem/auxout.c b/private/mvdm/wow16/mmsystem/auxout.c
new file mode 100644
index 000000000..cd0b786f5
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/auxout.c
@@ -0,0 +1,171 @@
+#include <windows.h>
+#define MMNOMCI
+#include "mmsystem.h"
+#define NOMCIDEV
+#include "mmddk.h"
+#include "mmsysi.h"
+
+/* -------------------------------------------------------------------------
+** External globals
+** -------------------------------------------------------------------------
+*/
+extern DWORD mmwow32Lib;
+extern LPSOUNDDEVMSGPROC aux32Message;
+
+
+
+/*****************************************************************************
+ * @doc EXTERNAL AUX
+ *
+ * @api UINT | auxGetNumDevs | This function retrieves the number of auxiliary
+ * output devices present in the system.
+ *
+ * @rdesc Returns the number of auxiliary output devices present in the system.
+ *
+ * @xref auxGetDevCaps
+ ****************************************************************************/
+UINT WINAPI auxGetNumDevs(void)
+{
+ return (UINT)auxOutMessage( 0, AUXDM_GETNUMDEVS, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL AUX
+ *
+ * @api UINT | auxGetDevCaps | This function queries a specified
+ * auxiliary output device to determine its capabilities.
+ *
+ * @parm UINT | wDeviceID | Identifies the auxiliary output device to be
+ * queried. Specify a valid device ID (see the following comments
+ * section), or use the following constant:
+ * @flag AUX_MAPPER | Auxiliary audio mapper. The function will
+ * return an error if no auxiliary audio mapper is installed.
+ *
+ * @parm LPAUXCAPS | lpCaps | Specifies a far pointer to an AUXCAPS
+ * structure. This structure is filled with information about the
+ * capabilities of the device.
+ *
+ * @parm UINT | wSize | Specifies the size of the AUXCAPS structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver failed to install.
+ *
+ * @comm The device ID specified by <p wDeviceID> varies from zero
+ * to one less than the number of devices present. AUX_MAPPER may
+ * also be used. Use <f auxGetNumDevs> to determine the number of
+ * auxiliary devices present in the system.
+ *
+ * @xref auxGetNumDevs
+ ****************************************************************************/
+UINT WINAPI auxGetDevCaps(UINT wDeviceID, LPAUXCAPS lpCaps, UINT wSize)
+{
+ if (!wSize)
+ return MMSYSERR_NOERROR;
+
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+ return (UINT)auxOutMessage(wDeviceID, AUXDM_GETDEVCAPS, (DWORD)lpCaps, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL AUX
+ *
+ * @api UINT | auxGetVolume | This function returns the current volume
+ * setting of an auxiliary output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the auxiliary output device to be
+ * queried.
+ *
+ * @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location
+ * to be filled with the current volume setting. The low-order word of
+ * this location contains the left channel volume setting, and the high-order
+ * word contains the right channel setting. A value of 0xFFFF represents
+ * full volume, and a value of 0x0000 is silence.
+ *
+ * If a device does not support both left and right volume
+ * control, the low-order word of the specified location contains
+ * the volume level.
+ *
+ * The full 16-bit setting(s)
+ * set with <f auxSetVolume> are returned, regardless of whether
+ * the device supports the full 16 bits of volume level control.
+ *
+ * @comm Not all devices support volume control.
+ * To determine whether the device supports volume control, use the
+ * AUXCAPS_VOLUME flag to test the <e AUXCAPS.dwSupport> field of the
+ * <t AUXCAPS> structure (filled by <f auxGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both the
+ * left and right channels, use the AUXCAPS_LRVOLUME flag to test the
+ * <e AUXCAPS.dwSupport> field of the <t AUXCAPS> structure (filled
+ * by <f auxGetDevCaps>).
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver failed to install.
+ *
+ * @xref auxSetVolume
+ ****************************************************************************/
+UINT WINAPI auxGetVolume(UINT wDeviceID, LPDWORD lpdwVolume)
+{
+ V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
+ return (UINT)auxOutMessage(wDeviceID, AUXDM_GETVOLUME, (DWORD)lpdwVolume, 0);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL AUX
+ *
+ * @api UINT | auxSetVolume | This function sets the volume in an
+ * auxiliary output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the auxiliary output device to be
+ * queried. Device IDs are determined implicitly from the number of
+ * devices present in the system. Device ID values range from zero
+ * to one less than the number of devices present. Use <f auxGetNumDevs>
+ * to determine the number of auxiliary devices in the system.
+ *
+ * @parm DWORD | dwVolume | Specifies the new volume setting. The
+ * low-order word specifies the left channel volume setting, and the
+ * high-order word specifies the right channel setting.
+ * A value of 0xFFFF represents full volume, and a value of 0x0000
+ * is silence.
+ *
+ * If a device does not support both left and right volume
+ * control, the low-order word of <p dwVolume> specifies the volume
+ * level, and the high-order word is ignored.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver failed to install.
+ *
+ * @comm Not all devices support volume control.
+ * To determine whether the device supports volume control, use the
+ * AUXCAPS_VOLUME flag to test the <e AUXCAPS.dwSupport> field of the
+ * <t AUXCAPS> structure (filled by <f auxGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both the
+ * left and right channels, use the AUXCAPS_LRVOLUME flag to test the
+ * <e AUXCAPS.dwSupport> field of the <t AUXCAPS> structure (filled
+ * by <f auxGetDevCaps>).
+ *
+ * Most devices do not support the full 16 bits of volume level control
+ * and will use only the high-order bits of the requested volume setting.
+ * For example, for a device that supports 4 bits of volume control,
+ * requested volume level values of 0x4000, 0x4fff, and 0x43be will
+ * all produce the same physical volume setting, 0x4000. The
+ * <f auxGetVolume> function will return the full 16-bit setting set
+ * with <f auxSetVolume>.
+ *
+ * Volume settings are interpreted logarithmically. This means the
+ * perceived volume increase is the same when increasing the
+ * volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
+ *
+ * @xref auxGetVolume
+ ****************************************************************************/
+UINT WINAPI auxSetVolume(UINT wDeviceID, DWORD dwVolume)
+{
+ return (UINT)auxOutMessage(wDeviceID, AUXDM_SETVOLUME, dwVolume, 0);
+}
diff --git a/private/mvdm/wow16/mmsystem/bwinexec.asm b/private/mvdm/wow16/mmsystem/bwinexec.asm
new file mode 100644
index 000000000..2cc62ae8f
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/bwinexec.asm
@@ -0,0 +1,222 @@
+ PAGE 58,132
+;******************************************************************************
+TITLE bwinexec.asm - WinExec with binary command line
+;******************************************************************************
+;
+; Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+;
+; Title: bwinexec.asm - Exec. an app. with a block of binary data.
+;
+; Version: 1.00
+;
+; Date: 14-Mar-1990 (from winexec)
+;
+; Author: ROBWI
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 14-Mar-1990 RJW Modified Toddla's WinExec code to take a binary command
+; block instead of an ascii command line
+;
+;==============================================================================
+
+?PLM=1
+?WIN=0
+PMODE=1
+
+.xlist
+include cmacros.inc
+include windows.inc
+.list
+
+ externFP LoadModule
+
+EXECBLOCK struc
+envseg dw ? ; seg addr of environment
+lpcmdline dd ? ; pointer to command block (normally ascii str)
+lpfcb1 dd ? ; default fcb at 5C
+lpfcb2 dd ? ; default fcb at 6C
+EXECBLOCK ends
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes es,nothing
+ assumes ds,nothing
+
+;****************************************************************************
+;
+; @doc INTERNAL MMSYSTEMS
+;
+; @api HANDLE | BWinExec | This function executes the Windows
+; or non-Windows application identified by the <p lpCmdLine>
+; parameter. The <p nCmdShow> parameter specifies the initial
+; state of the applications main window when it is created.
+;
+; @parm LPSTR | lpModuleName | Far pointer to a null-terminated
+; character string that contains the filename of the
+; application to run. See <f LoadModule> for more info.
+;
+; @parm WORD | nCmdShow | Specifies how the application is shown.
+; See <f ShowWindow> for valid values.
+;
+; @parm LPVOID | lpParameters | Specifies a far pointer to a block
+; of data which will be passed to the application as a cmd
+; tail. The first byte of the block must be the length of the
+; data and must be less than or equal to 120.
+;
+; @rdesc The return value identifies the instance of the loaded module if
+; the function was successful. Otherwise, it is a value less than
+; 32 that specifies the error. See <f LoadModule> for valid
+; error values.
+;
+; @xref LoadModule WinExec
+;
+;============================================================================
+
+cProc BWinExec, <FAR,PUBLIC,NODATA>,<si,di>
+
+ parmD lpszFile ; Pathname ptr
+ parmW wShow ; Mode flag
+ parmD lpParameters ; Cmd Line Data
+
+ LocalV szCommand, 128 ; ASCIIZ Name of program to exec
+
+ LocalV szParm, 128 ; DOS version of parameters
+ LocalB szParmLen ; DOS parm length
+ LocalB bDotFound ; Non-zero if a period is in the string
+
+ LocalV loadparams, %(SIZE EXECBLOCK)
+ LocalV rOF, %(SIZE OPENSTRUC)
+ LocalD FCB1
+
+cBegin
+ mov byte ptr szParm,0Dh
+ mov szParmLen,0 ; Init to zero length, Line feed
+
+; Copy first part of line into szCommand.
+
+ lds si,lpszFile
+ mov ax,ss
+ mov es,ax
+ lea di,szCommand
+
+ xor al,al
+ mov bDotFound,al
+
+; Loop until a blank or NULL is found.
+
+WELoop1:
+ lodsb
+ cmp al,' ' ; Exit loop if blank or NULL
+ je WECont1
+ or al,al
+ je WECont1
+ cmp al,'.'
+ jne WELoopCont
+ mov bDotFound,al
+WELoopCont:
+ stosb
+ jmp short WELoop1
+
+WECont1:
+
+; Does the command have an extension?
+
+ cmp bDotFound,0
+ jne WEHasExt
+
+ mov ax,0452Eh ;'.E'
+ stosw
+ mov ax,04558h ;'XE'
+ stosw
+
+WEHasExt:
+ xor ax,ax ; NULL terminate string
+ stosb
+
+ lds si,lpParameters
+ mov ax, ds
+ or ax, si ; NULL Parameter block?
+ jz WEExec ; Y: exec
+
+; Copy Parameter Block into szParm.
+
+ lea di, szParmLen
+ lodsb
+ xor cx,cx
+ mov cl, al
+ push dx ; truncate to legal length!
+ mov ax, 78h
+ sub ax, cx
+ cwd
+ and ax, dx
+ add cx, ax ; length + 1 in cx
+ pop dx
+ mov al, cl
+ stosb
+ dec cx
+ cld
+ rep movsb
+
+; Terminate it with a linefeed.
+
+ mov al,0Dh
+ stosb
+
+; Set up the FCBs.
+
+WEExec:
+ mov word ptr FCB1[0],2 ; FCB1[0] = 2;
+ mov ax,wShow ; FCB1[1] = wShow;
+ mov word ptr FCB1[2],ax
+ xor ax,ax
+ mov loadparams.envseg,ax ; loadparms.segEnv = 0;
+ mov loadparams.lpfcb2.lo,ax ; loadparms.lpFCB2 = (LPSTR)NULL;
+ mov loadparams.lpfcb2.hi,ax
+ lea ax,szParmLen ; loadparms.lpCmdLine = (LPSTR)ach;
+ mov loadparams.lpCmdLine.lo,ax
+ mov loadparams.lpCmdLine.hi,ss
+ lea ax,FCB1 ; loadparms.lpFCB1 = (LPSTR)fcb1buf;
+ mov loadparams.lpfcb1.lo,ax
+ mov loadparams.lpfcb1.hi,ss
+
+; Exec the progam.
+
+ lea dx,szCommand ; ds:ax == ptr to file to exec
+ lea bx,loadparams ; es:bx == ptr to param block
+if 1
+ cCall LoadModule, <ss,dx, ss,bx> ; return ax=hInstance, dx=hTask
+ cmp ax,32
+ jb @f
+ mov ax,dx ; return hTask
+@@:
+else
+ mov ax,ss
+ mov ds,ax
+ mov ax,4B00h ; dos exec
+ int 21h
+endif
+
+cEnd
+
+sEnd CodeSeg
+
+end
diff --git a/private/mvdm/wow16/mmsystem/comm.asm b/private/mvdm/wow16/mmsystem/comm.asm
new file mode 100644
index 000000000..037fcf2dd
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/comm.asm
@@ -0,0 +1,164 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; COMM.ASM
+;
+; Copyright (c) Microsoft Corporation 1990. All rights reserved.
+;
+; This module contains code to write a string to the COM port
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+
+ .286
+ .xlist
+ include cmacros.inc
+; include windows.inc
+ .list
+
+ WF_CPU286 equ 0002h
+
+ ifdef DEBUG
+ DEBUG_RETAIL equ 1
+ endif
+
+; externA __0040h ; in KERNEL
+; externA __B000h ; in KERNEL
+
+ externFP OutputDebugString ; in KERNEL
+
+ externFP wvsprintf ; in USER
+
+ SCREENWIDTH equ 80
+ SCREENHEIGHT equ 25
+ SCREENBYTES equ (SCREENWIDTH*2)
+ DEFATTR equ 07
+
+ LASTLINE equ ((SCREENHEIGHT-1)*SCREENBYTES)
+
+BUFFER_SIZE = 256
+
+;******************************************************************************
+;
+; SEGMENTS
+;
+;******************************************************************************
+
+createSeg _TEXT, CodeRes, word, public, CODE
+createSeg FIX, CodeFix, word, public, CODE
+createSeg INTDS, DataFix, byte, public, DATA
+
+;******************************************************************************
+;
+; FIXED DATA
+;
+;******************************************************************************
+ifdef DEBUG_RETAIL
+sBegin DataFix
+ globalW fDebugOutput, 0
+sEnd DataFix
+endif
+
+;******************************************************************************
+;
+; NON FIXED DATA
+;
+;******************************************************************************
+ifdef DEBUG
+sBegin Data
+ globalW _fDebug, 0
+sEnd Data
+endif
+
+ifdef DEBUG
+
+sBegin CodeRes
+ assumes cs,CodeRes
+ assumes ds,nothing
+ assumes es,nothing
+
+;******************************************************************************
+;
+; dprintf - output a MMSYSTEM debug string with formatting
+;
+; if the mmsystem global fDebug==0, no ouput will be sent
+;
+;==============================================================================
+ assumes ds,Data
+ assumes es,nothing
+
+?PLM=0
+cProc dprintf, <FAR, C, PUBLIC>, <>
+ ParmD szFormat
+ ParmW Args
+ LocalV szBuffer, BUFFER_SIZE
+cBegin
+ cmp [_fDebug],0
+ jz dprintf_exit
+
+ lea ax,szBuffer
+ lea bx,Args
+ cCall wvsprintf, <ss,ax, szFormat, ss,bx>
+
+ lea ax,szBuffer
+ push ss
+ push ax
+ call far ptr OutputDebugStr
+
+dprintf_exit:
+
+cEnd
+?PLM=1
+
+sEnd
+
+endif
+
+;******************************************************************************
+;
+;******************************************************************************
+sBegin CodeFix
+ assumes cs,CodeFix
+ assumes ds,nothing
+ assumes es,nothing
+
+ externW CodeFixDS ; in STACK.ASM
+ externW CodeFixWinFlags
+
+ifdef DEBUG
+
+;******************************************************************************
+;
+; dout - output a MMSYSTEM debug string
+;
+; if the mmsystem global fDebug==0, no ouput will be sent
+;
+;==============================================================================
+ assumes ds,Data
+ assumes es,nothing
+
+public dout
+dout proc far
+
+ cmp [_fDebug],0
+ jnz OutputDebugStr
+ retf 4
+
+dout endp
+
+endif; DEBUG
+
+
+;
+; in the retail version stub out the OutputDebugStr function
+;
+cProc OutputDebugStr, <FAR, PASCAL, PUBLIC>, <>
+ ParmD szString
+cBegin
+
+ cCall OutputDebugString, <szString>
+cEnd
+
+sEnd
+end
diff --git a/private/mvdm/wow16/mmsystem/debug.asm b/private/mvdm/wow16/mmsystem/debug.asm
new file mode 100644
index 000000000..d75f6f0af
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/debug.asm
@@ -0,0 +1,710 @@
+
+;--------------------------------------------------------------------------
+
+ifdef DEBUG
+ DEBUG_RETAIL equ 1
+endif ; ifdef DEBUG
+
+;--------------------------------------------------------------------------
+ ?PLM = 1
+ ?WIN = 0
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ include mmsystem.inc
+; include logerror.inc
+ include mmddk.inc
+ .list
+
+;--------------------------------------------------------------------------
+
+;/* Error modifier bits */
+
+ERR_WARNING equ 08000h
+ERR_PARAM equ 04000h
+
+;/* Generic parameter values */
+ERR_BAD_VALUE equ 06001h
+ERR_BAD_FLAGS equ 06002h
+ERR_BAD_INDEX equ 06003h
+ERR_BAD_DVALUE equ 07004h
+ERR_BAD_DFLAGS equ 07005h
+ERR_BAD_DINDEX equ 07006h
+ERR_BAD_PTR equ 07007h
+ERR_BAD_FUNC_PTR equ 07008h
+ERR_BAD_SELECTOR equ 06009h
+ERR_BAD_STRING_PTR equ 0700ah
+ERR_BAD_HANDLE equ 0600bh
+
+;/* KERNEL parameter errors */
+ERR_BAD_HINSTANCE equ 06020h
+ERR_BAD_HMODULE equ 06021h
+ERR_BAD_GLOBAL_HANDLE equ 06022h
+ERR_BAD_LOCAL_HANDLE equ 06023h
+ERR_BAD_ATOM equ 06024h
+ERR_BAD_HFILE equ 06025h
+
+;/* USER parameter errors */
+ERR_BAD_HWND equ 06040h
+ERR_BAD_HMENU equ 06041h
+ERR_BAD_HCURSOR equ 06042h
+ERR_BAD_HICON equ 06043h
+ERR_BAD_HDWP equ 06044h
+ERR_BAD_CID equ 06045h
+ERR_BAD_HDRVR equ 06046h
+
+DBF_TRACE equ 00000h
+DBF_WARNING equ 04000h
+DBF_ERROR equ 08000h
+DBF_FATAL equ 0c000h
+
+; [Windows] DebugFilter and flags values
+
+DBF_INTERNAL equ 02000h
+DBF_KERNEL equ 01000h
+DBF_USER equ 00800h
+DBF_GDI equ 00400h
+DBF_COMPAT equ 00200h
+DBF_LOGERROR equ 00100h
+DBF_PARAMERROR equ 00080h
+DBF_MMSYSTEM equ 00040h
+DBF_PENWIN equ 00020h
+
+;--------------------------------------------------------------------------
+
+AssertF macro reg
+ local assert_ok
+ifdef DEBUG
+ or reg,reg
+ jnz assert_ok
+ int 3
+assert_ok:
+endif
+ endm
+
+AssertT macro reg
+ local assert_ok
+ifdef DEBUG
+ or reg,reg
+ jz assert_ok
+ int 3
+assert_ok:
+endif
+ endm
+
+;--------------------------------------------------------------------------
+;
+; DebugErr() macro
+;
+ifdef DEBUG_RETAIL
+
+externFP _DebugOutput
+
+DebugErr macro flags,msg
+ local a,b
+
+ push cs
+ push offset a
+ push flags or DBF_MMSYSTEM
+ call _DebugOutput
+ add sp,6
+ jmp short b
+a:
+ db "MMSYSTEM: "
+ db msg
+ db 13,10,0
+b:
+endm
+
+else ; DEBUG
+
+DebugErr macro flags,msg
+endm
+
+endif ; DEBUG
+
+;--------------------------------------------------------------------------
+
+; Define the return address as a type using the DefD macro in order to
+; be able to pass it as a parameter to the LogParamError function.
+ReturnAddr equ (dword ptr [bp+2])
+DefD ReturnAddr
+
+;--------------------------------------------------------------------------
+
+NSTYPE equ 00007h ; Segment type mask
+NSCODE equ 00000h ; Code segment
+NSDATA equ 00001h ; Data segment
+NSITER equ 00008h ; Iterated segment flag
+NSMOVE equ 00010h ; Movable segment flag
+NSPURE equ 00020h ; Pure segment flag
+NSPRELOAD equ 00040h ; Preload segment flag
+NSRELOC equ 00100h ; Segment has relocations
+NSDEBUG equ 00200h ; Segment has debug info
+NSDPL equ 00C00h ; 286 DPL bits
+NSDISCARD equ 01000h ; Discard bit for segment
+
+CODEINFO struc
+ ns_sector dw ? ; File sector of start of segment
+ ns_cbseg dw ? ; Number of bytes in file
+ ns_flags dw ? ; Attribute flags
+ ns_minalloc dw ? ; Minimum allocation in bytes
+ ns_handle dw ? ; handle to object
+ ns_align dw ? ; file alignment
+CODEINFO ends
+
+DSC_CODE_BIT equ 08h
+
+;--------------------------------------------------------------------------
+
+;**************************************************************************;
+; IF YOU CHANGE THESE TYPES YOU MUST ALSO CHANGE THE ONES IN MMSYSI.H
+;**************************************************************************;
+TYPE_WAVEOUT equ 1
+TYPE_WAVEIN equ 2
+TYPE_MIDIOUT equ 3
+TYPE_MIDIIN equ 4
+TYPE_MMIO equ 5
+TYPE_IOPROC equ 6
+TYPE_MCI equ 7
+TYPE_DRVR equ 8
+TYPE_MIXER equ 9
+;**************************************************************************;
+
+;--------------------------------------------------------------------------
+
+;**************************************************************************;
+; IF YOU CHANGE THIS STRUCTURE YOU MUST ALSO CHANGE THE ONE IN MMSYSI.H
+;**************************************************************************;
+HNDL struc
+ hndlNext dw ? ; link to next handle
+ hndlType dw ? ; type of handle wave, midi, mmio, ...
+ hndlTask dw ? ; task that owns it
+HNDL ends
+;**************************************************************************;
+
+;--------------------------------------------------------------------------
+
+externW _pHandleList
+externA __AHINCR
+externA __WINFLAGS
+externFP LogParamError ;(WORD wError, FARPROC lpfn, DWORD dValue);
+externFP LocalAlloc ;(WORD fwFlags, WORD wSize);
+externFP LocalFree ;(LOCALHANDLE h);
+externFP IsWindow ;(HWND hwnd);
+externFP GetCodeInfo ;(FARPROC lpfnProc, LPVOID lpSegInfo);
+externFP GetCurrentTask ;(void);
+externFP IsTask ;(HANDLE hTask);
+
+; Windows internal pointer validation tools.
+externFP IsBadReadPtr ;(LPVOID lp, WORD cb);
+externFP IsBadWritePtr ;(LPVOID lp, WORD cb);
+externFP IsBadHugeReadPtr ;(LPVOID lp, DWORD cb);
+externFP IsBadHugeWritePtr ;(LPVOID lp, DWORD cb);
+externFP IsBadCodePtr ;(FARPROC lp);
+externFP IsBadStringPtr ;(LPSTR lpsz, WORD wMaxLen);
+externFP IsSharedSelector ;(WORD wSelector);
+
+;--------------------------------------------------------------------------
+sBegin Data
+
+sEnd Data
+
+;--------------------------------------------------------------------------
+
+createSeg _TEXT, CodeRes, word, public, CODE
+createSeg FIX, CodeFix, word, public, CODE
+
+sBegin CodeRes
+ assumes cs, CodeRes
+ assumes ds, Data
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func HANDLE | NewHandle | allocate a fixed handle in MMSYSTEM's local heap
+;
+; @parm WORD | wType | unique id describing handle type
+; @parm WORD | wSize | size in bytes to be allocated
+;
+; @rdesc Returns pointer/handle to memory object
+;
+; @comm a standard handle header (HNDL) will be added to the object,
+; and it will be linked into the list of MMSYSTEM handles.
+;
+cProc NewHandle, <FAR, PUBLIC, PASCAL> <>
+ parmW wType
+ parmW wSize
+cBegin
+ mov ax, wSize ; Attempt to allocate local memory
+ add ax, SIZE HNDL ; Add header to requested size first
+ cCall LocalAlloc, <LPTR, ax>
+ AssertF ax
+ or ax, ax
+ jz NewHandle_Exit ; Return NULL
+ mov bx, ax
+ mov ax, [_pHandleList] ; Put the head of the list as the
+ mov [bx].hndlNext, ax ; next pointer
+ cCall GetCurrentTask, <>
+ mov [bx].hndlTask, ax ; Set task for new handle
+ mov ax, wType ; Set type for new handle
+ mov [bx].hndlType, ax
+ mov [_pHandleList], bx ; Make new handle head of list
+ lea ax, [bx + SIZE HNDL] ; Return data portion of handle
+NewHandle_Exit:
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func HANDLE | FreeHandle | free handle allocated with NewHandle
+;
+; @parm HANDLE | hLocal | handle returned from NewHandle
+;
+; @comm handle will be unlinked from list, and memory will be freed with
+; LocalFree
+;
+cProc FreeHandle, <FAR, PUBLIC, PASCAL> <>
+ parmW hLocal
+cBegin
+ mov ax, hLocal
+ AssertF ax
+ or ax, ax
+ jz FreeHandle_Exit ; NULL handle returns NULL
+ sub ax, SIZE HNDL ; Get real handle from data portion
+ lea bx, [_pHandleList] ; Pointer to first pointer
+ errnz hndlNext ; Assume this is the first element
+
+FreeHandle_Search:
+ mov dx, [bx].hndlNext ; get pointer to next handle
+ cmp dx, ax ; If this is the handle
+ je FreeHandle_Free ; Free it
+
+ mov bx, dx ; advance to next handle.
+ or bx, bx ; Check for end of list
+ jnz FreeHandle_Search
+ AssertF bx ; bx == 0 force a fail
+ jmp FreeHandle_Exit ; Handle not found, so return handle
+
+FreeHandle_Free:
+ xchg ax, bx ; BX --> handle
+ xor dx, dx ; Zero out entries for better debugging
+ mov [bx].hndlType, dx
+ mov [bx].hndlTask, dx
+ xchg [bx].hndlNext, dx ; Get next handle in list
+ xchg ax, bx ; BX --> prev handle
+ mov [bx].hndlNext, dx ; update link
+ cCall LocalFree, <ax> ; Free handle found, returning error
+ AssertT ax
+
+FreeHandle_Exit:
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL WAVE MIDI
+;
+; @func BOOL | ValidateHeader | validates a wave or midi date header
+;
+; @parm LPVOID | lpHeader| pointer to wave/midi header
+; @parm WORD | wSize | size of header passed by app
+; @parm WORD | wType | unique id describing header/handle type
+;
+; @rdesc Returns TRUE if <p> is non NULL and <wSize> is the correct size
+; Returns FALSE otherwise
+;
+; @comm if the header is invalid an error will be generated.
+;
+
+cProc ValidateHeader, <FAR, PUBLIC, PASCAL> <>
+ parmD lpHeader
+ parmW wSize
+ parmW wType
+cBegin
+ cCall IsBadWritePtr, <lpHeader, wSize>
+ or ax, ax ; If fail,
+ jnz vValidateHeader_Fail_Header_Ptr
+
+ mov ax, wType
+ mov dx, SIZE WAVEHDR ; assume WAVEHDR
+ mov cx, not WHDR_VALID
+
+ cmp ax, TYPE_WAVEIN ; If wave out
+ jbe ValidateHeader_Size
+ errnz TYPE_WAVEOUT-1
+ errnz TYPE_WAVEIN-2
+
+ mov dx, SIZE MIDIHDR ; Set MIDIHDR
+ mov cx, not MHDR_VALID
+
+ValidateHeader_Size:
+ cmp dx, wSize ; Compare against given size
+ jne ValidateHeader_Fail_Size; Fail if wrong size, LogParamError
+
+ les bx, lpHeader ; Load lpData pointer
+
+ mov ax,es:[bx].dwWaveFlags.lo
+ test ax,cx
+ jnz ValidateHeader_Fail_Flags
+
+ push es:[bx].lpWaveData.hi ; Validate data pointer
+ push es:[bx].lpWaveData.lo
+ push es:[bx].dwWaveBufferLength.hi
+ push es:[bx].dwWaveBufferLength.lo
+ cCall IsBadHugeWritePtr, <>
+ or ax,ax
+ jnz vValidateHeader_Fail_Buffer_Ptr
+ errn$ ValidateHeader_Exit
+
+ValidateHeader_Exit:
+ not ax
+cEnd
+
+ValidateHeader_Fail_Exit:
+ mov ax, -1 ; Return FALSE
+ jmp short ValidateHeader_Exit
+
+vValidateHeader_Fail_Header_Ptr:
+ jmp ValidateHeader_Fail_Header_Ptr
+
+vValidateHeader_Fail_Buffer_Ptr:
+ jmp ValidateHeader_Fail_Buffer_Ptr
+
+ValidateHeader_Fail_Size:
+ DebugErr DBF_ERROR, "Invalid header size."
+ cCall LogParamError, <ERR_BAD_VALUE, ReturnAddr, 0, wSize>
+ jmp short ValidateHeader_Fail_Exit
+
+ValidateHeader_Fail_Flags:
+ cCall LogParamError, <ERR_BAD_FLAGS, ReturnAddr, 0, ax>
+ jmp short ValidateHeader_Fail_Exit
+
+ValidateHeader_Fail_Header_Ptr:
+ DebugErr DBF_ERROR, "Invalid header pointer."
+ cCall LogParamError, <ERR_BAD_PTR, ReturnAddr, lpHeader>
+ jmp ValidateHeader_Fail_Exit
+
+ValidateHeader_Fail_Buffer_Ptr:
+ DebugErr DBF_ERROR, "Invalid buffer pointer."
+ push ERR_BAD_PTR
+ push ReturnAddr.hi
+ push ReturnAddr.lo
+ les bx,lpHeader
+ push es:[bx].lpWaveData.hi
+ push es:[bx].lpWaveData.lo
+ cCall LogParamError
+ jmp ValidateHeader_Fail_Exit
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateReadPointer | validates that a pointer is valid to
+; read from.
+;
+; @parm LPVOID | lpPoint| pointer to validate
+; @parm DWORD | dLen | supposed length of said pointer
+;
+; @rdesc Returns TRUE if <p> is a valid pointer
+; Returns FALSE if <p> is not a valid pointer
+;
+; @comm will generate error if the pointer is invalid
+;
+cProc ValidateReadPointer, <FAR, PUBLIC, PASCAL> <>
+ parmD lpPoint
+ parmD dLen
+cBegin
+ cCall IsBadHugeReadPtr, <lpPoint, dLen>
+ or ax,ax
+ jz ValidateReadPointer_Exit ; Return TRUE
+
+ cCall LogParamError, <ERR_BAD_PTR, ReturnAddr, lpPoint>
+ mov ax,-1 ; Return FALSE
+
+ValidateReadPointer_Exit:
+ not ax
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateWritePointer | validates that a pointer is valid to
+; write to.
+;
+; @parm LPVOID | lpPoint| pointer to validate
+; @parm DWORD | dLen | supposed length of said pointer
+;
+; @rdesc Returns TRUE if <p> is a valid pointer
+; Returns FALSE if <p> is not a valid pointer
+;
+; @comm will generate error if the pointer is invalid
+;
+cProc ValidateWritePointer, <FAR, PUBLIC, PASCAL> <>
+ parmD lpPoint
+ parmD dLen
+cBegin
+ cCall IsBadHugeWritePtr, <lpPoint, dLen>
+ or ax,ax ; If not fail,
+ jz ValidateWritePointer_Exit ; Return TRUE
+ cCall LogParamError, <ERR_BAD_PTR, ReturnAddr, lpPoint>
+ mov ax,-1 ; Return FALSE
+ValidateWritePointer_Exit:
+ not ax
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func WORD | ValidDriverCallback |
+;
+; validates that a driver callback is valid, to be valid a driver
+; callback must be a valid window, task, or a function in a FIXED DLL
+; code segment.
+;
+; @parm DWORD | dwCallback | callback to validate
+; @parm WORD | wFlags | driver callback flags
+;
+; @rdesc Returns 0 if <dwCallback> is a valid callback
+; Returns error condition if <dwCallback> is not a valid callback
+;
+cProc ValidDriverCallback, <NEAR, PASCAL> <>
+ parmD dCallback
+ parmW wFlags
+ localV ci, %(SIZE CODEINFO)
+cBegin
+ mov ax, wFlags ; switch on callback type
+ and ax, DCB_TYPEMASK
+ errnz <DCB_NULL>
+ jnz ValidDriverCallback_Window ; case DCB_NULL
+ jmp ValidDriverCallback_Exit ; return zero for success
+
+ValidDriverCallback_Window:
+ dec ax
+ errnz <DCB_WINDOW - 1>
+ jnz ValidDriverCallback_Task ; case DCB_WINDOW
+ cmp dCallback.hi, 0 ; HIWORD must be NULL
+ jnz ValidDriverCallback_BadWindow ; Set error
+ push dCallback.lo ; Check for valid HWND
+ cCall IsWindow, <>
+ or ax, ax ; If HWND,
+ jnz ValidDriverCallback_Success ; Set successful return
+
+ValidDriverCallback_BadWindow: ; Else set error return
+ mov ax, ERR_BAD_HWND
+ jmp ValidDriverCallback_Exit ; Return error
+
+ValidDriverCallback_Task:
+ dec ax
+ errnz <DCB_TASK - 2>
+ jnz ValidDriverCallback_Function ; case DCB_TASK
+ cmp dCallback.hi, 0 ; HIWORD must be NULL
+ jnz ValidDriverCallback_BadTask ; Set error
+ push dCallback.lo ; Check for valid Task
+ cCall IsTask, <>
+ or ax, ax ; If Task,
+ jnz ValidDriverCallback_Success ; Set successful return
+
+ValidDriverCallback_BadTask: ; Else set error return
+ mov ax, ERR_BAD_HANDLE
+ jmp ValidDriverCallback_Exit ; Return error
+
+ValidDriverCallback_Function:
+ dec ax
+ errnz <DCB_FUNCTION - 3> ; case DCB_FUNCTION
+ jnz ValidDriverCallback_Default
+ lea ax, ci
+ cCall GetCodeInfo, <dCallback, ss, ax>
+ or ax, ax
+ jz ValidDriverCallback_BadFunction ; Set error return
+ mov ax, ci.ns_flags ; Check for valid flags
+ and ax, NSDATA or NSMOVE or NSDISCARD
+ jz ValidDriverCallback_Exit ; Return zero for success
+ jnz ValidDriverCallback_BadFunction
+
+ValidDriverCallback_Default:
+ mov ax, ERR_BAD_FLAGS ; default to error condition
+ jmp ValidDriverCallback_Exit
+
+ValidDriverCallback_Success:
+ xor ax, ax
+
+ValidDriverCallback_Exit:
+cEnd
+
+ValidDriverCallback_BadFunction: ; Else set error return
+ DebugErr DBF_ERROR, "Driver callbacks MUST be in a FIXED segment of a DLL."
+ mov ax, ERR_BAD_FUNC_PTR
+ jmp ValidDriverCallback_Exit ; Return error
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateDriverCallback |
+;
+; validates that a driver callback is valid, to be valid a driver
+; callback must be a valid window, task, or a function in a FIXED DLL
+; code segment.
+;
+; @parm DWORD | dwCallback | callback to validate
+; @parm WORD | wFlags | driver callback flags
+;
+; @rdesc Returns TRUE if <dwCallback> is a valid callback
+; Returns FALSE if <dwCallback> is not a valid callback
+;
+; @comm will generate error if the callback is invalid
+;
+cProc ValidateDriverCallback, <FAR, PUBLIC, PASCAL> <>
+ parmD dCallback
+ parmW wFlags
+cBegin
+ cCall ValidDriverCallback, <dCallback, wFlags>
+ or ax, ax ; If no error return
+ jz ValidateDriverCallback_Exit ; Return TRUE
+ cCall LogParamError, <ax, ReturnAddr, dCallback>
+ mov ax, -1 ; Return FALSE
+ValidateDriverCallback_Exit:
+ not ax
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateCallback |
+;
+; validates that a callback is valid.
+;
+; @parm FARPROC | dCallback | callback to validate
+;
+; @rdesc Returns TRUE if <lpfnCallback> is a valid callback
+; Returns FALSE if <lpfnCallback> is not a valid callback
+;
+; @comm will generate error if the callback is invalid
+;
+cProc ValidateCallback, <FAR, PUBLIC, PASCAL> <>
+ parmD dCallback
+cBegin
+ cCall IsBadCodePtr, <dCallback>
+ or ax,ax ; If not fail,
+ jz ValidateCallback_Exit ; Return TRUE
+ cCall LogParamError, <ERR_BAD_FUNC_PTR, ReturnAddr, dCallback>
+ mov ax, -1 ; Return FALSE
+ValidateCallback_Exit:
+ not ax
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateString |
+;
+cProc ValidateString, <FAR, PUBLIC, PASCAL> <>
+ parmD lsz
+ parmW max_len
+cBegin
+ cCall IsBadStringPtr, <lsz, max_len> ; Maximum length
+ or ax,ax ; If not fail,
+ jz ValidateString_Exit ; Return TRUE
+ cCall LogParamError, <ERR_BAD_STRING_PTR, ReturnAddr, lsz>
+ mov ax, -1 ; Return FALSE
+ValidateString_Exit:
+ not ax
+cEnd
+
+sEnd
+
+;--------------------------------------------------------------------------
+
+sBegin CodeFix
+ assumes cs, CodeFix
+ assumes ds, nothing
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateHandle | validates a handle created with NewHandle
+;
+; @parm HANDLE | hLocal | handle returned from NewHandle
+; @parm WORD | wType | unique id describing handle type
+;
+; @rdesc Returns TRUE if <h> is a valid handle of type <wType>
+; Returns FALSE if <h> is not a valid handle
+;
+; @comm if the handle is invalid an error will be generated.
+;
+;--------------------------------------------------------------------------
+ assumes ds, Data
+ assumes es, nothing
+
+cProc ValidateHandle, <FAR, PUBLIC, PASCAL> <>
+ parmW hLocal
+ parmW wType
+cBegin
+ mov bx, hLocal
+ sub bx, SIZE HNDL ; Get actual handle
+ jc ValidateHandle_Bad
+
+ mov ax, ds
+ lsl ax, ax ; Get DS limit
+ cmp bx, ax ; Check for out of limit
+ jae ValidateHandle_Bad
+
+ mov ax,[bx].hndlType
+ cmp ax, wType ; Compare handle type
+ je ValidateHandle_Exit ; Types are the same, return TRUE
+
+ValidateHandle_Bad:
+ add bx, SIZE HNDL
+ cCall LogParamError, <ERR_BAD_HANDLE, ReturnAddr, 0, bx>
+ xor ax, ax ; Return FALSE
+
+ValidateHandle_Exit:
+cEnd
+
+;--------------------------------------------------------------------------
+; @doc INTERNAL
+;
+; @func BOOL | ValidateTimerCallback |
+;
+; validates that a timer callback is valid, to be valid a driver
+; callback must be a valid function in a FIXED DLL code segment.
+;
+; @parm LPTIMECALLBACK | lpfn | callback to validate
+;
+; @rdesc Returns TRUE if <lpfn> is a valid callback
+; Returns FALSE if <lpfn> is not a valid callback
+;
+; @comm will generate error if the callback is invalid
+;
+;--------------------------------------------------------------------------
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc ValidateTimerCallback, <FAR, PUBLIC, PASCAL> <>
+ parmD lpfn
+cBegin
+ mov ax, lpfn.hi
+ lar bx, ax
+ jnz ValidateTimerCallback_Fail ; Invalid segment
+ test bh, DSC_CODE_BIT
+ jz ValidateTimerCallback_Fail ; Not executable segment
+ lsl cx, ax ; Get segment limit
+ mov bx, lpfn.lo
+ cmp bx, cx
+ jae ValidateTimerCallback_Fail ; Invalid offset
+ mov es, ax
+ mov bx, es:[bx]+2
+ cmp bx, 0581eH ; push ds, pop ax
+ je ValidateTimerCallback_Fail ; Invalid entry point
+ cmp bx, 0d88cH ; mov ax, ds
+ jne ValidateTimerCallback_Exit ; Return TRUE
+ValidateTimerCallback_Fail:
+ cCall LogParamError, <ERR_BAD_FUNC_PTR, ReturnAddr, lpfn>
+ xor ax, ax ; Return FALSE
+ValidateTimerCallback_Exit:
+cEnd
+
+sEnd CodeFix
+
+;--------------------------------------------------------------------------
+
+END
diff --git a/private/mvdm/wow16/mmsystem/debug.h b/private/mvdm/wow16/mmsystem/debug.h
new file mode 100644
index 000000000..98bc7fb5d
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/debug.h
@@ -0,0 +1,80 @@
+//==========================================================================;
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+// PURPOSE.
+//
+// Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
+//
+//--------------------------------------------------------------------------;
+//
+// debug.h
+//
+// Description:
+//
+//
+//
+//==========================================================================;
+
+#ifndef _INC_DEBUG
+#define _INC_DEBUG
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+//
+//
+//
+//
+#define DEBUG_MODULE_NAME "MSMIXMGR" // key name and prefix for output
+
+#ifdef DEBUG
+ #define DEBUG_SECTION "Debug" // section name for
+ #define DEBUG_MAX_LINE_LEN 255 // max line length (bytes!)
+#endif
+
+
+//
+// based code makes since only in win 16 (to try and keep stuff out of
+// [fixed] data segments, etc)...
+//
+#ifndef BCODE
+#ifdef WIN32
+ #define BCODE
+#else
+ #define BCODE _based(_segname("_CODE"))
+#endif
+#endif
+
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+// #pragma message(REMIND("this is a reminder"))
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifdef DEBUG
+
+ #define D(x) {x;}
+ #define DPF(_x_)
+ #define DPI(sz) {static char BCODE ach[] = sz; OutputDebugStr(ach);}
+
+#else
+
+ #define D(x)
+ #define DPF(_x_)
+ #define DPI(sz)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif // _INC_DEBUG
diff --git a/private/mvdm/wow16/mmsystem/dosa.asm b/private/mvdm/wow16/mmsystem/dosa.asm
new file mode 100644
index 000000000..90082c21d
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/dosa.asm
@@ -0,0 +1,266 @@
+ title dosa.asm
+;
+; ASM routines lifted from WINCOM
+;
+; ToddLa & RussellW
+;
+; DavidLe removed all but current drive/directory functions
+;
+?PLM=1 ; PASCAL Calling convention is DEFAULT
+?WIN=0 ; Windows calling convention
+PMODE=1 ; Enable enter/leave
+
+ .xlist
+ include cmacros.inc
+ .list
+
+; -------------------------------------------------------
+; DATA SEGMENT DECLARATIONS
+; -------------------------------------------------------
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg
+ assumes CS,CodeSeg
+ assumes DS,Data
+ assumes ES,nothing
+
+; ----------------------------------------------------------------
+;
+; @doc INTERNAL
+; @api int | DosChangeDir | This function changes the current drive
+; and directory.
+;
+; @parm LPSTR | lpszPath | Points to the desired drive and directory path.
+; The optional drive identifier must be the first character, followed by
+; a colon. The drive identifier is followed by an optional path
+; specification, which may be relative or absolute.
+;
+; @rdesc Returns one of the following values:
+;
+; @flag 1 The drive and directory were successfully changed.
+; @flag 0 The specified pathname is invalid. The drive and
+; current directory is restored
+; to the default values when the function was called.
+; @flag -1 The specified drive is invalid. The drive and directory
+; current directory is restored to the default values when the
+; function was called.
+;
+; @xref DosGetCurrentDir, DosGetCurrentPath, DosGetCurrentDrive
+;
+szCurDir:
+ db '.',0
+
+cProc DosChangeDir,<PUBLIC, FAR, PASCAL>, <ds>
+ parmD lpszPath
+
+ LocalW fDriveChange
+ LocalW wLastDrive
+ LocalW wReturn
+ LocalV szPoint, 2
+cBegin
+ mov fDriveChange, 0
+
+ lds dx, lpszPath
+ mov bx, dx
+
+ ; Check if a drive was specified. If not, then go direct to ChDir
+ cmp BYTE PTR ds:[bx+1],':' ; no drive allowed
+ jnz chdnodrive
+
+ ; get the current drive to save it in case the drive change/
+ ; dir change fails, so we can restore it.
+ mov ah, 19h
+ int 21h
+ mov wLastDrive, ax
+
+ mov fDriveChange, 1 ; flag the drive change
+
+ ; Now, change the drive to that specified in the input
+ ; string.
+ mov dl, ds:[bx] ; Get the drive letter
+ or dl, 20h ; lower case it
+ sub dl, 'a' ; and adjust so 0 = a:, 1 = b:, etc
+
+ mov ah, 0eh ; set current drive
+ int 21h
+
+ mov ah, 19h ; get current drive
+ int 21h
+
+ cmp al, dl ; check that chDrive succeeded
+ jne chdDriveError
+
+ ; as a further test of whether the drive change took, attempt
+ ; to change to the current directory on the new drive.
+ mov ax, cs
+ mov ds, ax
+ mov dx, CodeSegOFFSET szCurDir
+ mov ah, 3bh
+ int 21h
+ jc chdDriveError
+
+ lds dx, lpszPath
+ add dx, 2 ; skip over the drive identifier
+ mov bx, dx
+ ;; if they passed only drive: without dir path, then end now
+ cmp BYTE PTR ds:[bx], 0 ; if path name is "", we are there
+ jz chdok
+
+chdnodrive:
+ mov ah, 3bh
+ int 21h
+ jc chdPathError
+chdok:
+ mov ax, 1
+chdexit:
+cEnd
+
+chdPathError:
+ mov wReturn, 0
+ jmp short chderror
+
+chdDriveError:
+ mov wReturn, -1
+
+chderror:
+ ; if a drive change occurred, but the CD failed, change
+ ; the drive back to that which was the original drive
+ ; when entered.
+ mov ax, fDriveChange
+ or ax, ax
+ jz chdNoCD
+
+ mov dx, wLastDrive
+ mov ah, 0eh
+ int 21h
+ mov ax, wReturn
+ jmp short chdexit
+chdNoCD:
+ xor ax, ax ; return zero on error
+ jmp short chdexit
+
+
+
+
+; ----------------------------------------------------------------
+;
+; @doc INTERNAL
+; @api WORD | DosGetCurrentDrive | This function returns the drive identifier
+; of the current drive.
+; @rdesc Returns the drive code of the current drive: 0 is drive
+; A:, 1 is drive B:, etc.
+;
+; @comm This function assumes that drive A: is zero. Some
+; other DOS functions assume drive A: is one.
+;
+; @xref DosSetCurrentDrive
+;
+
+cProc DosGetCurrentDrive,<PUBLIC, FAR, PASCAL>
+cBegin
+ mov ah, 19h ; Get Current Drive
+ int 21h
+ sub ah, ah ; Zero out AH
+cEnd
+
+
+; ----------------------------------------------------------------
+;
+; @doc INTERNAL WINCOM
+; @api WORD | DosSetCurrentDrive | This function sets the current DOS
+; drive to be the specified drive.
+;
+; @parm WORD | wDrive | Specifies the drive to be set as the current drive.
+; 0 indicates drive A:, 1 is B:, etc.
+;
+; @rdesc Returns TRUE if the drive change was successful, or FALSE
+; if the current drive was not changed.
+;
+; @comm This is the same range returned by <f DosGetCurrentDrive>.
+; Other functions assume drive A: is 1.
+;
+;
+; @xref DosGetCurrentDrive
+;
+
+cProc DosSetCurrentDrive,<FAR, PUBLIC, PASCAL>
+ParmW Drive
+cBegin
+ mov dx, Drive
+ mov ah, 0Eh ; Set Current Drive
+ int 21h
+
+ ; Check if successful
+ mov ah, 19h ; get current drive
+ int 21h
+
+ cmp al, dl ; check that chDrive succeeded
+ jne SetDriveError
+ mov ax, 1h ; return true on success
+SetDriveExit:
+cEnd
+SetDriveError:
+ xor ax, ax ; return false on error
+ jmp short SetDriveExit
+
+
+
+; ----------------------------------------------------------------
+;
+; @doc INTERNAL WINCOM
+;
+; @api WORD | DosGetCurrentDir | This function copies the current
+; directory of the specified drive into a caller-supplied buffer. This
+; function differs from the <f DosGetCurrentPath> function in that it
+; copies only the current directory of the specified drive, whereas
+; <f DosGetCurrentPath> copies the current drive and its current directory
+; into the caller's buffer.
+;
+; @parm WORD | wCurdrive | Specifies the drive. 0 is the default drive,
+; 1 is drive A, 2 is drive B, etc.
+;
+; @parm LPSTR | lpszBuf | Points to the buffer in which to place the
+; current directory. This buffer must be 66 bytes in length.
+; The returned directory name will always have a leading '\' character.
+;
+; @rdesc Returns NULL if the function succeeded. Otherwise, it returns
+; the DOS error code.
+;
+; @comm The drive identifier value specified by <p wCurdrive>
+; assumes that drive A: is one, whereas the <f DosGetCurrentDrive>
+; function assumes that drive A: is zero.
+;
+; @xref DosGetCurrentDrive, DosChangeDir, DosGetCurrentPath
+;
+
+cProc DosGetCurrentDir,<PUBLIC,FAR,PASCAL>,<si,di,ds>
+ parmW wCurdrive
+ parmD lpDest
+cBegin
+ cld
+ les di, lpDest ; es:di = lpDest
+ mov al, '\'
+ stosb
+ push es
+ pop ds ; ds = es
+ mov si, di ; ds:si = lpDest + 1
+ ; Add NULL char for case of error
+ xor al, al
+ stosb ; null terminate in case of error
+
+ mov ah, 47h ; GetCurrentDirectory
+ mov dx, wCurdrive ; of this drive
+ int 21h
+ jc CWDexit ; return error code for failure
+ xor ax, ax ; return NULL on success
+CWDexit:
+cEnd
+
+sEnd CodeSeg
+
+end
diff --git a/private/mvdm/wow16/mmsystem/dpmipage.asm b/private/mvdm/wow16/mmsystem/dpmipage.asm
new file mode 100644
index 000000000..33171ec69
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/dpmipage.asm
@@ -0,0 +1,384 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: PAGELOCK
+;
+; This module contains functions for page locking memory using DPMI
+;
+; Created: 03-20-90
+; Author: Todd Laney [ToddLa]
+;
+; Copyright (c) 1984-1990 Microsoft Corporation
+;
+; Exported Functions: none
+;
+; Public Functions: DpmiPageLock
+; DpmiPageUnlock
+;
+; Public Data: none
+;
+; General Description:
+;
+; Restrictions:
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ ?NODATA = 1
+
+ .286
+ .xlist
+ include cmacros.inc
+ include int31.inc
+ .list
+
+ externA __AHINCR ; KERNEL
+ externFP GlobalHandle ; KERNEL
+ externFP GlobalHandleNoRip ; KERNEL
+ externFP GlobalFix ; KERNEL
+ externFP GlobalUnFix ; KERNEL
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+Int31_SelMgt_Get_Base EQU ((Int31_Sel_Mgt shl 8) + SelMgt_Get_Base )
+Int31_Lock_Region EQU ((Int31_Page_Lock shl 8) + Lock_Region )
+Int31_Unlock_Region EQU ((Int31_Page_Lock shl 8) + Unlock_Region )
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;---------------------------Public-Routine------------------------------;
+; DpmiPageLock
+;
+; page lock a region using DPMI
+;
+; Entry:
+; lpBase Selector:offset of base of region to lock
+; dwSize size in bytes of region to lock
+;
+; Returns:
+; NZ
+; AX = TRUE if successful
+;
+; Error Returns:
+; Z
+; AX = FALSE if error
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; INT 31h
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DpmiPageLock, <NEAR>, <>
+; parmD lpBase
+; parmD dwSize
+cBegin nogen
+ mov cx,Int31_Lock_Region
+ jmp short DpmiPageLockUnLock
+cEnd nogen
+
+;---------------------------Public-Routine------------------------------;
+; DpmiPageUnlock
+;
+; un-page lock a region using DPMI
+;
+; Entry:
+; lpBase Selector:offset of base of region to unlock
+; dwSize size in bytes of region to unlock
+;
+; Returns:
+; NZ
+; AX = TRUE if successful
+;
+; Error Returns:
+; Z
+; AX = FALSE if error
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; INT 31h
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DpmiPageUnlock, <NEAR>, <>
+; parmD lpBase
+; parmD dwSize
+cBegin nogen
+ mov cx,Int31_Unlock_Region
+ errn$ DpmiPageLockUnLock
+cEnd nogen
+
+cProc DpmiPageLockUnLock, <NEAR>, <si,di>
+ parmD lpBase
+ parmD dwSize
+cBegin
+ mov si,cx ; save lock/unlock flag
+
+ mov ax,Int31_SelMgt_Get_Base
+ mov bx,lpBase.sel
+ int 31h ; returns CX:DX selector base
+ jc dpl_exit
+
+ mov bx,cx ; BX:CX is base
+ mov cx,dx
+
+ add cx,lpBase.off ; add offset into selector base
+ adc bx,0
+
+ mov ax,si ; get lock/unlock flag
+ mov si,dwSize.hi ; SI:DI length
+ mov di,dwSize.lo
+
+ int 31h ; lock or unlock it
+dpl_exit:
+ cmc ; set carry iff success
+ sbb ax,ax ; return TRUE/FALSE
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HugePageLock
+;
+; page lock a range of windows allocated memory
+;
+; Entry:
+; lpBase Selector:offset of base of region to lock
+; dwSize size in bytes of region to lock
+;
+; Returns:
+; AX = TRUE if successful
+;
+; Error Returns:
+; AX = FALSE if error
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; INT 31h
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HugePageLock, <FAR, PUBLIC>, <>
+ parmD lpBase
+ parmD dwSize
+cBegin
+ mov ax,lpBase.sel ; NULL pointer, invalid
+ or ax,ax
+ jz GPageLock_Exit
+
+ call HugeGlobalFix ; fix the memory, then page lock
+ cCall DpmiPageLock,<lpBase, dwSize>
+ jnz GPageLock_Exit
+
+ mov ax,lpBase.sel ; page lock failed, un-fix
+ call HugeGlobalUnFix ; and return failure
+ xor ax,ax
+
+GPageLock_Exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HugePageUnlock
+;
+; un-page lock a range of windows alocated memory, (locked with HugePageLock)
+;
+; Entry:
+; lpBase Selector:offset of base of region to lock
+; dwSize size in bytes of region to lock
+;
+; Returns:
+; none
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; INT 31h
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HugePageUnlock, <FAR, PUBLIC>, <>
+ parmD lpBase
+ parmD dwSize
+cBegin
+ cCall DpmiPageUnlock,<lpBase, dwSize>
+
+ mov ax,lpBase.sel
+ call HugeGlobalUnFix
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HugeGlobalFix
+;
+; fix the global object that represents the passed selector
+;
+; Entry:
+; AX = SELECTOR
+;
+; Returns:
+; none
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; GlobalFix
+; HugeGlobalHandle
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+HugeGlobalFix proc near
+
+ call HugeGlobalHandle
+ jz HugeGlobalFixExit
+
+ cCall GlobalFix,<ax>
+
+HugeGlobalFixExit:
+ ret
+
+HugeGlobalFix endp
+
+;---------------------------Public-Routine------------------------------;
+; HugeGlobalUnFix
+;
+; un-fix the global object that represents the passed selector
+;
+; Entry:
+; AX = SELECTOR
+;
+; Returns:
+; none
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; HugeGlobalHandle
+; GlobalUnFix
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+HugeGlobalUnFix proc near
+
+ call HugeGlobalHandle
+ jz HugeGlobalUnFixExit
+
+ cCall GlobalUnFix,<ax>
+
+HugeGlobalUnFixExit:
+ ret
+
+HugeGlobalUnFix endp
+
+;---------------------------Public-Routine------------------------------;
+; HugeGlobalHandle
+;
+; Entry:
+; AX = SELECTOR to global object
+;
+; Returns:
+; NZ
+; AX = HANDLE of global object
+;
+; Error Returns:
+; Z
+; AX = 0 if error
+;
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; GlobalHandleNoRip
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+HugeGlobalHandle proc near
+
+ push si
+ mov si,ax
+
+ or ax,ax ; test for NULL pointer!
+ jz HugeGlobalHandleExit
+
+HugeGlobalHandleAgain:
+ cCall GlobalHandleNoRip,<si>
+ sub si,__AHINCR
+ or ax,ax
+ jz HugeGlobalHandleAgain
+
+HugeGlobalHandleExit:
+ pop si
+ ret
+
+HugeGlobalHandle endp
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/mmsystem/drvproc.c b/private/mvdm/wow16/mmsystem/drvproc.c
new file mode 100644
index 000000000..6b25743d5
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvproc.c
@@ -0,0 +1,379 @@
+/*
+ drvproc.c
+
+ contains MMSYSTEMs DriverProc
+
+ Copyright (c) Microsoft Corporation 1990. All rights reserved
+
+*/
+
+#include <windows.h>
+#include <mmsysver.h>
+#include "mmsystem.h"
+#include "mmsysi.h"
+#include "drvr.h"
+#include "mmioi.h"
+
+extern IOProcMapEntry NEAR * gIOProcMapHead; // in MMIO.C
+
+/****************************************************************************
+
+ internal prototypes
+
+****************************************************************************/
+
+static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile);
+
+static BYTE fFirstTime=TRUE; // First enable
+
+extern BOOL FAR PASCAL DrvLoad(void); // in init.c
+extern BOOL FAR PASCAL DrvFree(void);
+extern char far szStartupSound[]; // in mmwnd.c
+
+static SZCODE szExitSound[] = "SystemExit";
+
+#ifdef DEBUG_RETAIL
+ extern char far szMMSystem[];
+ extern char far szSystemIni[];
+ extern char far szDebugOutput[];
+ extern char far szMci[];
+
+// extern WORD fDebugOutput;
+ extern int DebugmciSendCommand; // in MCI.C
+#ifdef DEBUG
+ extern char far szDebug[];
+ extern WORD fDebug;
+#endif
+#endif
+
+void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit);
+
+/*****************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api LRESULT | DriverProc | This is the standard DLL entry point. It is
+ * called from user (3.1) or mmsound.drv (3.0) when MMSYSTEM.DLL is
+ * loaded, enabled, or disabled.
+ *
+ ****************************************************************************/
+LRESULT CALLBACK
+DriverProc(
+ DWORD dwDriver,
+ HDRVR hDriver,
+ UINT wMessage,
+ LPARAM lParam1,
+ LPARAM lParam2
+ )
+{
+ switch (wMessage)
+ {
+ case DRV_LOAD:
+ //
+ // first load message, initialize mmsystem.
+ // sent from USER when loading drivers from drivers= line
+ //
+ if (fFirstTime)
+ return (LRESULT)(LONG)DrvLoad();
+
+ //
+ // a normal load message, a app is trying to open us
+ // with OpenDriver()
+ //
+ break; // return success all other times (1L)
+
+ case DRV_FREE:
+ //
+ // a free message, this is send just before the DLL is unloaded
+ // by the driver interface.
+ //
+ // sent by user just before system exit, after sending
+ // the DRV_DISABLE message.
+ //
+ DrvFree();
+ break; // return success (1L)
+
+ case DRV_OPEN: // FALL-THROUGH
+ case DRV_CLOSE:
+ break; // return success (1L)
+
+ case DRV_ENABLE:
+ DOUT("MMSYSTEM: Enable\r\n");
+ fFirstTime = FALSE;
+ break; // return success (1L)
+
+ case DRV_DISABLE:
+ DOUT("MMSYSTEM: Disable\r\n");
+ break; // return success (1L)
+
+ //
+ // sent when a application is terminating
+ //
+ // lParam1:
+ // DRVEA_ABNORMALEXIT
+ // DRVEA_NORMALEXIT
+ //
+ case DRV_EXITAPPLICATION:
+ AppExit(GetCurrentTask(), (BOOL)lParam1 == DRVEA_NORMALEXIT);
+ break;
+
+ case DRV_EXITSESSION:
+ sndPlaySound(szExitSound, SND_SYNC | SND_NODEFAULT);
+ break;
+
+#ifdef DEBUG_RETAIL
+ case MM_GET_DEBUG:
+ break;
+
+ case MM_GET_DEBUGOUT:
+ return (LRESULT)(LONG)fDebugOutput;
+
+ case MM_SET_DEBUGOUT:
+ fDebugOutput = (BYTE)(LONG)lParam1;
+ SetPrivateProfileInt(szMMSystem,szDebugOutput,fDebugOutput,szSystemIni);
+ break;
+
+ case MM_GET_MCI_DEBUG:
+ return (LRESULT)(LONG)DebugmciSendCommand;
+
+ case MM_SET_MCI_DEBUG:
+ DebugmciSendCommand = (WORD)(LONG)lParam1;
+ SetPrivateProfileInt(szMMSystem,szMci,DebugmciSendCommand,szSystemIni);
+ break;
+
+#ifdef DEBUG
+ case MM_GET_MM_DEBUG:
+ return (LRESULT)(LONG)fDebug;
+
+ case MM_SET_MM_DEBUG:
+ fDebug = (BYTE)(LONG)lParam1;
+ SetPrivateProfileInt(szMMSystem,szDebug,fDebug,szSystemIni);
+ break;
+
+#ifdef DEBUG
+ case MM_DRV_RESTART:
+ break;
+#endif
+
+
+ case MM_HINFO_MCI:
+ if ((HLOCAL)(LONG)lParam2 == (HLOCAL)NULL)
+ return (LRESULT)(LONG)MCI_wNextDeviceID;
+ if (MCI_VALID_DEVICE_ID((UINT)(LONG)lParam1))
+ {
+ *(LPMCI_DEVICE_NODE)lParam2 = *MCI_lpDeviceList[(UINT)(LONG)lParam1];
+ break;
+ }
+ return (LRESULT)FALSE;
+
+ case MM_HINFO_NEXT:
+ if ((HLOCAL)(LONG)lParam1 == (HLOCAL)NULL)
+ return (LRESULT)(LONG)(UINT)GetHandleFirst();
+ else
+ return (LRESULT)(LONG)(UINT)GetHandleNext((HLOCAL)(LONG)lParam1);
+
+ case MM_HINFO_TASK:
+ return (LRESULT)(LONG)(UINT)GetHandleOwner((HLOCAL)(LONG)lParam1);
+
+ case MM_HINFO_TYPE:
+ return GetHandleType((HLOCAL)(LONG)lParam1);
+
+#endif // ifdef DEBUG
+#endif // ifdef DEBUG_RETAIL
+
+ default:
+ return DefDriverProc(dwDriver, hDriver, wMessage, lParam1, lParam2);
+ }
+ return (LRESULT)1L;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @func void | AppExit |
+ * a application is exiting, free any MMSYS resources it may own
+ *
+ ****************************************************************************/
+
+void NEAR PASCAL AppExit(HTASK hTask, BOOL fNormalExit)
+{
+ HLOCAL h;
+ HLOCAL hNext;
+ WORD wDebugFlags;
+ UINT wDeviceID;
+ UINT cFree;
+ UINT cHeap;
+ UINT err;
+
+ if (hdrvDestroy != (HLOCAL)-1)
+ {
+ DOUT("MMSYSTEM: Hey! AppExit has been re-entered!\r\n");
+ }
+
+#ifdef DEBUG
+ if (!fNormalExit)
+ ROUT("MMSYSTEM: Abnormal app termination");
+#endif
+
+ //
+ // either log a error or a warning depending on wether it was
+ // a normal exit or not.
+ //
+ if (fNormalExit)
+ wDebugFlags = DBF_MMSYSTEM | DBF_ERROR;
+ else
+ wDebugFlags = DBF_MMSYSTEM | DBF_WARNING; // DBF_TRACE?
+
+ //
+ // now free MCI devices.
+ //
+ for (wDeviceID=1; wDeviceID<MCI_wNextDeviceID; wDeviceID++)
+ {
+ if (MCI_VALID_DEVICE_ID(wDeviceID) && MCI_lpDeviceList[wDeviceID]->hCreatorTask == hTask)
+ {
+ DebugErr2(wDebugFlags, "MCI device %ls (%d) not released.", MCI_lpDeviceList[wDeviceID]->lpstrInstallName, wDeviceID);
+
+ //
+ // clear these to force MCI to close the device
+ //
+ MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISCLOSING;
+ MCI_lpDeviceList[wDeviceID]->dwMCIFlags &= ~MCINODE_ISAUTOCLOSING;
+
+ err = (UINT)mciSendCommand(wDeviceID, MCI_CLOSE, NULL, NULL);
+
+#ifdef DEBUG
+ if (err != 0)
+ DebugErr1(DBF_WARNING, "Unable to close MCI device (err = %04X).", err);
+#endif
+ }
+ }
+
+ //
+ // free all WAVE/MIDI/MMIO handles
+ //
+start_over:
+ for (h=GetHandleFirst(); h; h=hNext)
+ {
+ hNext = GetHandleNext(h);
+
+ if (GetHandleOwner(h) == hTask)
+ {
+ //
+ // hack for the wave/midi mapper, always free handle's backward.
+ //
+ if (hNext && GetHandleOwner(hNext) == hTask)
+ continue;
+
+ //
+ // do this so even if the close fails we will not
+ // find it again.
+ //
+ SetHandleOwner(h, NULL);
+
+ //
+ // set the hdrvDestroy global so DriverCallback will not
+ // do anything for this device
+ //
+ hdrvDestroy = h;
+
+ switch(GetHandleType(h))
+ {
+ case TYPE_WAVEOUT:
+ DebugErr1(wDebugFlags, "WaveOut handle (%04X) was not released.", h);
+ waveOutReset((HWAVEOUT)h);
+ err = waveOutClose((HWAVEOUT)h);
+ break;
+
+ case TYPE_WAVEIN:
+ DebugErr1(wDebugFlags, "WaveIn handle (%04X) was not released.", h);
+ waveInStop((HWAVEIN)h);
+ waveInReset((HWAVEIN)h);
+ err = waveInClose((HWAVEIN)h);
+ break;
+
+ case TYPE_MIDIOUT:
+ DebugErr1(wDebugFlags, "MidiOut handle (%04X) was not released.", h);
+ midiOutReset((HMIDIOUT)h);
+ err = midiOutClose((HMIDIOUT)h);
+ break;
+
+ case TYPE_MIDIIN:
+ DebugErr1(wDebugFlags, "MidiIn handle (%04X) was not released.", h);
+ midiInStop((HMIDIIN)h);
+ midiInReset((HMIDIIN)h);
+ err = midiInClose((HMIDIIN)h);
+ break;
+
+ case TYPE_MMIO:
+ DebugErr1(wDebugFlags, "MMIO handle (%04X) was not released.", h);
+ err = mmioClose((HMMIO)h, 0);
+ break;
+
+ case TYPE_IOPROC:
+ DebugErr1(wDebugFlags, "MMIO handler '%4.4ls' not removed.", (LPSTR)&((IOProcMapEntry*)h)->fccIOProc);
+ err = !mmioInstallIOProc(((IOProcMapEntry*)h)->fccIOProc, NULL, MMIO_REMOVEPROC);
+ break;
+
+ }
+
+#ifdef DEBUG
+ if (err != 0)
+ DebugErr1(DBF_WARNING, "Unable to close handle (err = %04X).", err);
+#endif
+
+ //
+ // unset hdrvDestroy so DriverCallback will work.
+ // some hosebag drivers (like the TIMER driver)
+ // may pass NULL as their driver handle.
+ // so dont set it to NULL.
+ //
+ hdrvDestroy = (HLOCAL)-1;
+
+ //
+ // the reason we start over is because a single free may cause
+ // multiple free's (ie MIDIMAPPER has another HMIDI open, ...)
+ //
+ goto start_over;
+ }
+ }
+
+ //
+ // what about timeSetEvent()!!!???
+ //
+ // any outstanding timer events till be killed by the timer driver
+ // it self.
+ //
+ mciAppExit( hTask );
+
+
+ // shrink our heap, down to minimal size.
+
+ if ((cFree = LocalCountFree()) > 1024)
+ {
+ cHeap = LocalHeapSize() - (cFree - 512);
+ LocalShrink(NULL, cHeap);
+ DPRINTF(("MMSYSTEM: Shrinking the heap (%d)\r\n", cHeap));
+ }
+}
+
+#ifdef DEBUG_RETAIL
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @func void | SetPrivateProfileInt | windows should have this function
+ *
+ * @comm used by DriverProc to set debug state in SYSTEM.INI
+ *
+ ****************************************************************************/
+
+static void FAR PASCAL SetPrivateProfileInt(LPSTR szSection, LPSTR szKey, int i, LPSTR szIniFile)
+{
+ char ach[32] ;
+
+ if (i != (int)GetPrivateProfileInt(szSection, szKey, ~i, szIniFile))
+ {
+ wsprintf(ach, "%d", i);
+ WritePrivateProfileString(szSection, szKey, ach, szIniFile);
+ }
+}
+#endif //ifdef DEBUG_RETAIL
diff --git a/private/mvdm/wow16/mmsystem/drvr.c b/private/mvdm/wow16/mmsystem/drvr.c
new file mode 100644
index 000000000..803899e32
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvr.c
@@ -0,0 +1,213 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: drvr.c - Installable driver code. Common code
+
+ Version: 1.00
+
+ Date: 10-Jun-1990
+
+ Author: DAVIDDS ROBWI
+
+------------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ ----------- ----- -----------------------------------------------------------
+ 10-JUN-1990 ROBWI From windows 3.1 installable driver code by davidds
+
+*****************************************************************************/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "drvr.h"
+
+int cInstalledDrivers = 0; // Count of installed drivers
+HANDLE hInstalledDriverList = 0; // List of installed drivers
+
+typedef LONG (FAR PASCAL *SENDDRIVERMESSAGE31)(HANDLE, WORD, LONG, LONG);
+typedef LONG (FAR PASCAL *DEFDRIVERPROC31)(DWORD, HANDLE, WORD, LONG, LONG);
+
+extern SENDDRIVERMESSAGE31 lpSendDriverMessage;
+extern DEFDRIVERPROC31 lpDefDriverProc;
+extern BOOL fUseWinAPI;
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api LONG | InternalBroadcastDriverMessage | Send a message to a
+ * range of drivers.
+ *
+ * @parm WORD | hDriverStart | index of first driver to send message to
+ *
+ * @parm WORD | message | Message to broadcast.
+ *
+ * @parm LONG | lParam1 | First message parameter.
+ *
+ * @parm LONG | lParam2 | Second message parameter.
+ *
+ * @parm WORD | flags | defines range of drivers as follows:
+ *
+ * @flag IBDM_SENDMESSAGE | Only send message to hDriverStart.
+ *
+ * @flag IBDM_ONEINSTANCEONLY | This flag is ignored if IBDM_SENDMESSAGE is
+ * set. Only send message to single instance of each driver.
+ *
+ * @flag IBDM_REVERSE | This flag is ignored if IBDM_SENDMESSAGE is set.
+ * Send message to drivers with indices between
+ * hDriverStart and 1 instead of hDriverStart and cInstalledDrivers.
+ * If IBDM_REVERSE is set and hDriverStart is 0 then send messages
+ * to drivers with indices between cInstalledDrivers and 1.
+ *
+ * @rdesc returns non-zero if message was broadcast. If the IBDM_SENDMESSAGE
+ * flag is set, returns the return result from the driver proc.
+ *
+ ***************************************************************************/
+
+LONG FAR PASCAL InternalBroadcastDriverMessage(WORD hDriverStart,
+ WORD message,
+ LONG lParam1,
+ LONG lParam2,
+ WORD flags)
+{
+ LPDRIVERTABLE lpdt;
+ LONG result=0;
+ int id;
+ int idEnd;
+
+
+ if (!hInstalledDriverList || hDriverStart > cInstalledDrivers)
+ return(FALSE);
+
+ if (flags & IBDM_SENDMESSAGE)
+ {
+ if (!hDriverStart)
+ return (FALSE);
+ flags &= ~(IBDM_REVERSE | IBDM_ONEINSTANCEONLY);
+ idEnd = hDriverStart;
+ }
+
+ else
+ {
+ if (flags & IBDM_REVERSE)
+ {
+ if (!hDriverStart)
+ hDriverStart = cInstalledDrivers;
+ idEnd = -1;
+ }
+ else
+ {
+ if (!hDriverStart)
+ return (FALSE);
+ idEnd = cInstalledDrivers;
+ }
+ }
+
+ hDriverStart--;
+
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+
+ for (id = hDriverStart; id != idEnd; ((flags & IBDM_REVERSE) ? id-- : id++))
+ {
+ if (lpdt[id].hModule)
+ {
+ if ((flags & IBDM_ONEINSTANCEONLY) &&
+ !lpdt[id].fFirstEntry)
+ continue;
+
+ result =
+ (*lpdt[id].lpDriverEntryPoint)(lpdt[id].dwDriverIdentifier,
+ id+1,
+ message,
+ lParam1,
+ lParam2);
+ }
+ }
+
+ GlobalUnlock(hInstalledDriverList);
+
+ return(result);
+}
+
+
+/***************************************************************************
+ *
+ * @doc DDK
+ *
+ * @api LONG | DrvSendMessage | This function sends a message
+ * to a specified driver.
+ *
+ * @parm HANDLE | hDriver | Specifies the handle of the destination driver.
+ *
+ * @parm WORD | wMessage | Specifies a driver message.
+ *
+ * @parm LONG | lParam1 | Specifies the first message parameter.
+ *
+ * @parm LONG | lParam2 | Specifies the second message parameter.
+ *
+ * @rdesc Returns the results returned from the driver.
+ *
+ ***************************************************************************/
+
+LONG API DrvSendMessage(HANDLE hDriver, WORD message, LONG lParam1, LONG lParam2)
+{
+ if (fUseWinAPI)
+ return (*lpSendDriverMessage)(hDriver, message, lParam1,lParam2);
+
+ return(InternalBroadcastDriverMessage(hDriver,
+ message,
+ lParam1,
+ lParam2,
+ IBDM_SENDMESSAGE));
+}
+
+/**************************************************************************
+ *
+ * @doc DDK
+ *
+ * @api LONG | DefDriverProc | This function provides default
+ * handling of system messages.
+ *
+ * @parm DWORD | dwDriverIdentifier | Specifies the identifier of
+ * the device driver.
+ *
+ * @parm HANDLE | hDriver | Specifies the handle of the device driver.
+ *
+ * @parm WORD | wMessage | Specifies a driver message.
+ *
+ * @parm LONG | lParam1 | Specifies the first message parameter.
+ *
+ * @parm LONG | lParam2 | Specifies the second message parameter.
+ *
+ * @rdesc Returns 1L for DRV_LOAD, DRV_FREE, DRV_ENABLE, and DRV_DISABLE.
+ * It returns 0L for all other messages.
+ *
+***************************************************************************/
+
+
+
+LONG API DefDriverProc(DWORD dwDriverIdentifier,
+ HANDLE hDriver,
+ WORD message,
+ LONG lParam1,
+ LONG lParam2)
+{
+
+ switch (message)
+ {
+ case DRV_LOAD:
+ case DRV_ENABLE:
+ case DRV_DISABLE:
+ case DRV_FREE:
+ return(1L);
+ break;
+ case DRV_INSTALL:
+ return(DRV_OK);
+ break;
+ }
+
+ return(0L);
+}
diff --git a/private/mvdm/wow16/mmsystem/drvr.h b/private/mvdm/wow16/mmsystem/drvr.h
new file mode 100644
index 000000000..52b064f30
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvr.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: drvr.h - Installable driver code internal header file.
+
+ Version: 1.00
+
+ Date: 10-Jun-1990
+
+ Author: DAVIDDS ROBWI
+
+------------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ ----------- ----- -----------------------------------------------------------
+ 10-JUN-1990 ROBWI Based on windows 3.1 installable driver code by davidds
+
+*****************************************************************************/
+
+typedef LRESULT (CALLBACK *DRIVERPROC)
+ (DWORD dwDriverID, HDRVR hDriver, UINT wMessage, LPARAM lParam1, LPARAM lParam2);
+
+typedef struct tagDRIVERTABLE
+{
+ WORD fFirstEntry:1;
+ WORD fBusy:1;
+ DWORD dwDriverIdentifier;
+ WORD hModule;
+ DRIVERPROC lpDriverEntryPoint;
+} DRIVERTABLE;
+typedef DRIVERTABLE FAR *LPDRIVERTABLE;
+
+LONG FAR PASCAL InternalBroadcastDriverMessage(WORD, WORD, LONG, LONG, WORD);
+LONG FAR PASCAL InternalCloseDriver(WORD, LONG, LONG, BOOL);
+LONG FAR PASCAL InternalOpenDriver(LPSTR, LPSTR, LONG, BOOL);
+LONG FAR PASCAL InternalLoadDriver(LPSTR, LPSTR, LPSTR, WORD, BOOL);
+WORD FAR PASCAL InternalFreeDriver(WORD, BOOL);
+void FAR PASCAL InternalInstallDriverChain (void);
+void FAR PASCAL InternalDriverDisable (void);
+void FAR PASCAL InternalDriverEnable (void);
+int FAR PASCAL GetDrvrUsage(HANDLE);
+HANDLE FAR PASCAL LoadAliasedLibrary (LPSTR, LPSTR, LPSTR, LPSTR, WORD);
+void NEAR PASCAL DrvInit(void);
+
+/* Defines for internalbroadcastdrivermessage flags */
+#define IBDM_SENDMESSAGE 0x0001
+#define IBDM_REVERSE 0x0002
+#define IBDM_ONEINSTANCEONLY 0x0004
diff --git a/private/mvdm/wow16/mmsystem/drvr31.asm b/private/mvdm/wow16/mmsystem/drvr31.asm
new file mode 100644
index 000000000..d18862562
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvr31.asm
@@ -0,0 +1,195 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: DRVR31.ASM - Installable driver code.
+;
+; all this code does is pass any installable driver API on to
+; win 3.1 USER.
+;
+; Created: 28-08-91
+; Author: Todd Laney [ToddLa]
+;
+; Copyright (c) 1984-1991 Microsoft Corporation
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ .list
+
+;
+; these are the USER driver interface functions
+;
+ externFP OpenDriver ; USER
+ externFP CloseDriver ; USER
+ externFP GetDriverModuleHandle ; USER
+ externFP SendDriverMessage ; USER
+ externFP DefDriverProc ; USER
+
+ifdef DEBUG
+ externFP GetModuleFileName ; KERNEL
+ externFP _dprintf ; COMM.ASM
+endif
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+ifdef DEBUG
+
+szSuccess:
+ db "MMSYSTEM: DrvOpen(%ls) (%ls)", 13,10,0
+
+szFailed:
+ db "MMSYSTEM: DrvOpen(%ls) *failed*", 13,10,0
+
+cProc DrvOpen, <FAR, PUBLIC, PASCAL, LOADDS>, <>
+ ParmD szDriverName
+ ParmD szSectionName
+ ParmD dw2
+ LocalV ach,128
+cBegin
+ cCall OpenDriver, <szDriverName, szSectionName, dw2>
+ push ax
+
+ lea bx,szFailed
+ or ax,ax
+ jz DrvOpenFailed
+
+ cCall GetDriverModuleHandle, <ax>
+
+ lea bx,ach
+ cCall GetModuleFileName,<ax, ss,bx, 128>
+
+ lea bx,szSuccess
+
+DrvOpenFailed:
+ lea ax,ach
+ push ss ; ach
+ push ax
+
+ push szDriverName.sel ; szDriverName
+ push szDriverName.off
+
+ push cs ; szFormat
+ push bx
+
+ call _dprintf ; dprintf(szFormat, szDriverName, ach)
+ add sp,6*2
+
+DrvOpenExit:
+ pop ax ; return hdrv to caller
+
+DrvOpenExitNow:
+cEnd
+
+else ; DEBUG
+
+cProc DrvOpen, <FAR, PUBLIC, PASCAL>, <>
+; ParmD szDriverName
+; ParmD szSectionName
+; ParmD dw2
+cBegin nogen
+
+ jmp OpenDriver
+
+cEnd nogen
+
+
+
+
+endif ; DEBUG
+
+;-----------------------------------------------------------------------;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DrvClose, <FAR, PUBLIC, PASCAL>, <>
+; ParmW hDriver
+; ParmD dw1
+; ParmD dw2
+cBegin nogen
+
+ jmp CloseDriver
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DrvGetModuleHandle, <FAR, PUBLIC, PASCAL>, <>
+; ParmW hDriver
+cBegin nogen
+
+ jmp GetDriverModuleHandle
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DrvSendMessage, <FAR, PUBLIC, PASCAL>, <>
+; ParmW hDriver
+; ParmW message
+; ParmD dw1
+; ParmD dw2
+cBegin nogen
+
+ jmp SendDriverMessage
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DrvDefDriverProc, <FAR, PUBLIC, PASCAL>, <>
+; ParmD dwDriver
+; ParmW hDriver
+; ParmW message
+; ParmD dw1
+; ParmD dw2
+cBegin nogen
+
+ jmp DefDriverProc
+
+cEnd nogen
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/mmsystem/drvrrare.c b/private/mvdm/wow16/mmsystem/drvrrare.c
new file mode 100644
index 000000000..67b413b41
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvrrare.c
@@ -0,0 +1,873 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: drvrrare.c - Installable driver code. Less common code
+
+ Version: 1.00
+
+ Date: 10-Jun-1990
+
+ Author: DAVIDDS ROBWI
+
+*****************************************************************************/
+
+#include <windows.h>
+#include "drvr.h"
+#define MMNOSOUND
+#define MMNOWAVE
+#define MMNOMIDI
+#define MMNOSEQ
+#define MMNOTIMER
+#define MMNOJOY
+#define MMNOMCI
+#include "mmsystem.h"
+#define NOTIMERDEV
+#define NOJOYDEV
+#define NOMCIDEV
+#define NOSEQDEV
+#define NOWAVEDEV
+#define NOMIDIDEV
+#define NOTASKDEV
+#include "mmddk.h"
+#include "mmsysi.h"
+
+extern HANDLE hInstalledDriverList; // List of installed driver instances
+extern int cInstalledDrivers; // High water count of installed driver instances
+
+extern DWORD FAR PASCAL DriverProc(DWORD dwID, HANDLE hdrv, WORD msg, DWORD dw1, DWORD dw2);
+
+/* Support for using 3.1 APIs if available */
+
+typedef HANDLE (FAR PASCAL *OPENDRIVER31)(LPSTR, LPSTR, LONG);
+typedef LONG (FAR PASCAL *CLOSEDRIVER31)(HANDLE, LONG, LONG);
+typedef HANDLE (FAR PASCAL *GETDRIVERMODULEHANDLE31)(HANDLE);
+typedef LONG (FAR PASCAL *SENDDRIVERMESSAGE31)(HANDLE, WORD, LONG, LONG);
+typedef LONG (FAR PASCAL *DEFDRIVERPROC31)(DWORD, HANDLE, WORD, LONG, LONG);
+
+OPENDRIVER31 lpOpenDriver;
+CLOSEDRIVER31 lpCloseDriver;
+GETDRIVERMODULEHANDLE31 lpGetDriverModuleHandle;
+SENDDRIVERMESSAGE31 lpSendDriverMessage;
+DEFDRIVERPROC31 lpDefDriverProc;
+BOOL fUseWinAPI;
+
+#pragma alloc_text( INIT, DrvInit )
+
+/***************************************************************************
+
+ strings
+
+****************************************************************************/
+
+extern char far szSystemIni[]; // INIT.C
+extern char far szDrivers[];
+extern char far szBoot[];
+extern char far szNull[];
+extern char far szUser[];
+extern char far szOpenDriver[];
+extern char far szCloseDriver[];
+extern char far szDrvModuleHandle[];
+extern char far szSendDriverMessage[];
+extern char far szDefDriverProc[];
+extern char far szDriverProc[];
+
+/***************************************************************************
+ *
+ * @doc DDK
+ *
+ * @api LONG | DrvClose | This function closes an open driver
+ * instance and decrements
+ * the driver's open count. Once the driver's open count becomes zero,
+ * the driver is unloaded.
+ *
+ * @parm HANDLE | hDriver | Specifies the handle of the installable
+ * driver to close.
+ *
+ * @parm LONG | lParam1 | Specifies the first message parameter for
+ * the DRV_CLOSE message. This data is passed directly to the driver.
+ *
+ * @parm LONG | lParam2 | Specifies the second message parameter
+ * for DRV_CLOSE message. This data is passed directly to the driver.
+ *
+ * @rdesc Returns zero if the driver aborted the close;
+ * otherwise, returns the return result from the driver.
+
+ * @xref DrvOpen
+ *
+ ***************************************************************************/
+
+
+LONG API DrvClose(HANDLE hDriver, LONG lParam1, LONG lParam2)
+{
+ /* The driver will receive the following message sequence:
+ *
+ * DRV_CLOSE
+ * if DRV_CLOSE returns non-zero
+ * if driver usage count = 1
+ * DRV_DISABLE
+ * DRV_FREE
+ */
+
+ if (fUseWinAPI)
+ return ((*lpCloseDriver)(hDriver, lParam1, lParam2));
+ else
+ return InternalCloseDriver(hDriver, lParam1, lParam2, TRUE);
+}
+
+/***************************************************************************
+ *
+ * @doc DDK
+ *
+ * @api LONG | DrvOpen | This function opens an installable driver.
+ * The first time a driver is opened it is loaded
+ * and enabled. A driver must be opened before messages are sent
+ * to it.
+ *
+ * @parm LPSTR | szDriverName | Specifies a far pointer to a
+ * null-terminated character string
+ * containing a driver filename or a keyname from a
+ * section of the SYSTEM.INI file.
+ *
+ * @parm LPSTR | szSectionName | Specifies a far pointer to a
+ * null-terminated character string containing the name of
+ * the driver section to search. If <p szSectionName> is
+ * not null, the specified section of the SYSTEM.INI file is
+ * searched instead of the [Drivers] section. If
+ * <p szSectionName> is null, the default [Drivers] section is used.
+ *
+ * @parm LONG | lParam | Specifies a message parameter to
+ * pass to the driver procedure with the <m DRV_OPEN> message.
+ *
+ * @rdesc Returns a handle to the driver.
+ *
+ * @comm Installable drivers must export a <f DriverProc> routine of
+ * the form:
+ *
+ * @cb LONG FAR PASCAL | DriverProc | This entry point receives the
+ * messages sent to an installable driver. This entry will always
+ * handle the system messages as a minimum set of messages.
+ *
+ * @parm DWORD | dwDriverIdentifier | Specifies the device driver
+ * identifier.
+ *
+ * @parm HANDLE | hDriver | Specifies the device driver handle.
+ *
+ * @parm WORD | wMessage | Specifies the message for the device
+ * driver.
+ *
+ * @parm LONG | lParm1 | Specifies message dependent data.
+ *
+ * @parm LONG | lParm2 | Specifies message dependent data.
+ *
+ * @xref DrvClose
+ *
+****************************************************************************/
+
+HANDLE API DrvOpen(LPSTR szDriverName,
+ LPSTR szSectionName,
+ LONG lParam2)
+{
+ /* The driver will receive the following message sequence:
+ *
+ * if driver not loaded and can be found
+ * DRV_LOAD
+ * if DRV_LOAD returns non-zero
+ * DRV_ENABLE
+ * if driver loaded correctly
+ * DRV_OPEN
+ */
+
+ HANDLE hdrv;
+
+ if (fUseWinAPI)
+ hdrv = ((*lpOpenDriver)(szDriverName, szSectionName, lParam2));
+ else
+ hdrv = (HANDLE)InternalOpenDriver(szDriverName, szSectionName, lParam2, TRUE);
+
+#ifdef DEBUG
+ if (hdrv) {
+ char ach[80];
+ static SZCODE szFormat[] = "MMSYSTEM: Opened %ls (%ls)\r\n";
+
+ GetModuleFileName(DrvGetModuleHandle(hdrv), ach, sizeof(ach));
+ DPRINTF((szFormat, (LPSTR)szDriverName, (LPSTR)ach));
+ }
+#endif
+
+ return hdrv;
+}
+
+/***************************************************************************
+ *
+ * @doc DDK
+ *
+ * @api HANDLE | DrvGetModuleHandle | This function returns the library
+ * module handle of the specified installable driver.
+ *
+ * @parm HANDLE | hDriver | Specifies the handle of the installable driver.
+ *
+ * @rdesc Returns the module handle of the driver specified by the
+ * driver handle <p hDriver>.
+ *
+ * @comm A module handle is not the same as an installable driver handle.
+ *
+ ***************************************************************************/
+
+HANDLE API DrvGetModuleHandle(HANDLE hDriver)
+{
+ LPDRIVERTABLE lpdt;
+ HANDLE h = 0;
+
+ if (fUseWinAPI)
+ return ((*lpGetDriverModuleHandle)(hDriver));
+
+ if (hDriver && ((WORD)hDriver <= cInstalledDrivers))
+ {
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+ h = lpdt[hDriver-1].hModule;
+ GlobalUnlock(hInstalledDriverList);
+ }
+
+ return(h);
+}
+
+
+LONG FAR PASCAL InternalCloseDriver(WORD hDriver,
+ LONG lParam1,
+ LONG lParam2,
+ BOOL fSendDisable)
+{
+ LPDRIVERTABLE lpdt;
+ LONG result;
+ HANDLE h;
+ int index;
+ BOOL f;
+
+ // check handle in valid range.
+
+ if (hDriver > cInstalledDrivers)
+ return(FALSE);
+
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+
+ result = DrvSendMessage(hDriver, DRV_CLOSE, lParam1, lParam2);
+
+ if (result)
+ {
+
+ // Driver didn't abort close
+
+ f = lpdt[hDriver-1].fFirstEntry;
+
+ if (InternalFreeDriver(hDriver, fSendDisable) && f)
+ {
+
+ /* Only one entry for the driver in the driver list has the first
+ * instance flag set. This is to make it easier to handle system
+ * messages that only need to be sent to a driver once.
+ *
+ * To maintain the flag, we must set the flag in one of the other
+ * entries if we remove the driver entry with the flag set.
+ *
+ * Note that InternalFreeDriver returns the new usage count of
+ * the driver so if it is zero, we know that there are no other
+ * entries for the driver in the list and so we don't have to
+ * do this loop.
+ */
+
+ for (index=0;index<cInstalledDrivers;index++)
+ if (lpdt[index].hModule == lpdt[hDriver-1].hModule && !lpdt[index].fFirstEntry)
+ {
+ lpdt[index].fFirstEntry = 1;
+ break;
+ }
+ }
+
+ }
+
+ GlobalUnlock(hInstalledDriverList);
+
+ return(result);
+}
+
+
+LONG FAR PASCAL InternalOpenDriver(LPSTR szDriverName,
+ LPSTR szSectionName,
+ LONG lParam2,
+ BOOL fSendEnable)
+{
+ int hDriver;
+ LPDRIVERTABLE lpdt;
+ LONG result;
+ HANDLE h;
+ char sz[128];
+
+ if (hDriver = LOWORD(InternalLoadDriver(szDriverName,
+ szSectionName,
+ sz,
+ sizeof(sz),
+ fSendEnable)))
+ {
+
+
+ /*
+ Set the driver identifier to the DRV_OPEN call to the
+ driver handle. This will let people build helper functions
+ that the driver can call with a unique identifier if they
+ want to.
+ */
+
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+ lpdt[hDriver-1].dwDriverIdentifier = hDriver;
+ GlobalUnlock(hInstalledDriverList);
+
+ result = DrvSendMessage(hDriver,
+ DRV_OPEN,
+ (LONG)(LPSTR)sz,
+ lParam2);
+ if (!result)
+ InternalFreeDriver(hDriver, fSendEnable);
+
+ else
+ {
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+ lpdt[hDriver-1].dwDriverIdentifier = result;
+ GlobalUnlock(hInstalledDriverList);
+ result = hDriver;
+ }
+ }
+ else
+ result = 0L;
+
+ return(result);
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api LONG | InternalLoadDriver | Loads an installable driver. If this is
+ * the first time that the driver is opened, the driver will be loaded
+ * and enabled.
+ *
+ * @parm LPSTR | szDriverName | A null-terminated character string
+ * containing a driver filename or a keyname from the [Drivers]
+ * section of system.ini.
+ *
+ * @parm LPSTR | szSectionName | A null-terminated character string
+ * that specifies a driver section to search. If szSectionName is
+ * not null, the specified section of system.ini is searched instead
+ * of the [Drivers] section. If szSectionName is null, the
+ * default [Drivers] section is used.
+ *
+ * @parm LPSTR | lpstrTail | caller supplied buffer to return the "tail"
+ * of the system.ini line in. The tail is any characters that follow
+ * the filename.
+ *
+ * @parm WORD | cbTail | size of supplied buffer.
+ *
+ * @parm BOOL | fSendEnable | TRUE if driver should be enabled
+ *
+ * @rdesc Returns a long whose loword is the handle to the driver and whose
+ * high word is an error code or the module handle
+ *
+ * @xref InternalOpenDriver
+ *
+ ****************************************************************************/
+
+LONG FAR PASCAL InternalLoadDriver(LPSTR szDriverName,
+ LPSTR szSectionName,
+ LPSTR lpstrTail,
+ WORD cbTail,
+ BOOL fSendEnable)
+{
+ int index;
+ LPDRIVERTABLE lpdt;
+ LONG result;
+ HANDLE h;
+
+
+ /* The driver will receive the following message sequence:
+ *
+ * if driver not loaded and can be found
+ * DRV_LOAD
+ * if DRV_LOAD returns non-zero and fSendEnable
+ * DRV_ENABLE
+ */
+
+ /* Allocate a table entry */
+
+ if (!hInstalledDriverList)
+ h = GlobalAlloc(GHND | GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
+
+ else
+
+ /* Alloc space for the next driver we will install. We may not really
+ * install the driver in the last entry but rather in an intermediate
+ * entry which was freed.
+ */
+
+ h = GlobalReAlloc(hInstalledDriverList,
+ (DWORD)((WORD)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
+ GHND | GMEM_SHARE);
+
+ if (!h)
+ return(0L);
+
+ cInstalledDrivers++;
+ hInstalledDriverList = h;
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+
+ /* find an unused entry in the table */
+
+ for (index=0;index<cInstalledDrivers;index++)
+ {
+ if (lpdt->hModule || lpdt->fBusy)
+ lpdt++;
+ else
+ break;
+ }
+
+ if (index+1 < cInstalledDrivers)
+
+ /* The driver went into an unused entry in the middle somewhere so
+ * restore table size.
+ */
+
+ cInstalledDrivers--;
+
+ /* Protect the entry we just allocated so that OpenDriver
+ * can be called at any point from now on without overriding
+ * the entry
+ */
+
+ lpdt->fBusy = 1;
+
+ h = LoadAliasedLibrary(szDriverName,
+ szSectionName ? szSectionName : szDrivers,
+ szSystemIni,
+ lpstrTail,
+ cbTail);
+
+ if (h < 32)
+ {
+ result = MAKELONG(0,h);
+ goto LoadCleanUp;
+ }
+
+ lpdt->lpDriverEntryPoint = (DRIVERPROC)GetProcAddress(h, szDriverProc);
+ if (!lpdt->lpDriverEntryPoint)
+ {
+ // Driver does not have correct entry point
+ FreeLibrary(h);
+ result = 0L;
+ goto LoadCleanUp;
+ }
+
+ // Set hModule here so that GetDrvrUsage() and DrvSendMessage() work
+
+ lpdt->hModule = h;
+
+ if (GetDrvrUsage(h) == 1)
+ {
+
+ // First instance of the driver.
+
+ if (!DrvSendMessage(index+1, DRV_LOAD, 0L, 0L))
+ {
+ // Driver failed load call.
+ lpdt->lpDriverEntryPoint = NULL;
+ lpdt->hModule = NULL;
+ FreeLibrary(h);
+ result = 0L;
+ goto LoadCleanUp;
+ }
+ lpdt->fFirstEntry = 1;
+ if (fSendEnable)
+ DrvSendMessage(index+1, DRV_ENABLE, 0L, 0L);
+ }
+
+ result = MAKELONG(index+1,h);
+
+LoadCleanUp:
+ lpdt->fBusy = 0;
+ GlobalUnlock(hInstalledDriverList);
+ return(result);
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api WORD | InternalFreeDriver | This function decrements the usage
+ * count of the specified driver. When the driver usage count reaches
+ * 0, the driver is sent a DRV_FREE message and then freed.
+ *
+ * @parm HANDLE | hDriver | Driver handle of the installable driver to be
+ * freed.
+ *
+ * @parm BOOL | fSendDisable | TRUE if a DRV_DISABLE message should be sent
+ * before the DRV_FREE message if the usage count reaches zero.
+ *
+ * @rdesc Returns current driver usage count.
+ *
+ * @comm Using LoadLibrary or FreeLibrary directly on a library installed
+ * with OpenDriver will break this function. A module handle is not
+ * the same as an installable driver handle.
+ *
+ * @xref CloseDriver
+ *
+ ***************************************************************************/
+
+WORD FAR PASCAL InternalFreeDriver(WORD hDriver, BOOL fSendDisable)
+{
+ LPDRIVERTABLE lpdt;
+ HANDLE h;
+ WORD w;
+
+ /* The driver will receive the following message sequence:
+ *
+ * if usage count of driver is 1
+ * DRV_DISABLE (normally)
+ * DRV_FREE
+ */
+
+ if (hDriver > cInstalledDrivers || !hDriver)
+ return(0);
+
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+
+ /*
+ * If the driver usage count is 1, then send
+ * free and disable messages.
+ */
+
+ /*
+ Clear dwDriverIdentifier so that the sendmessage for
+ DRV_OPEN and DRV_ENABLE have dwDriverIdentifier = 0
+ if an entry gets reused and so that the DRV_DISABLE and DRV_FREE
+ messages below also get dwDriverIdentifier = 0.
+ */
+
+ lpdt[hDriver-1].dwDriverIdentifier = 0;
+
+ w = GetDrvrUsage(lpdt[hDriver-1].hModule);
+ if (w == 1)
+ {
+ if (fSendDisable)
+ DrvSendMessage(hDriver, DRV_DISABLE, 0L, 0L);
+ DrvSendMessage(hDriver, DRV_FREE, 0L, 0L);
+ }
+ FreeLibrary(lpdt[hDriver-1].hModule);
+
+ // Clear the rest of the table entry
+
+ lpdt[hDriver-1].hModule = 0; // this indicates free entry
+ lpdt[hDriver-1].fFirstEntry = 0; // this is also just to be tidy
+ lpdt[hDriver-1].lpDriverEntryPoint = 0; // this is also just to be tidy
+
+ GlobalUnlock(hInstalledDriverList);
+ return(w-1);
+}
+
+#ifdef DEBUG
+
+WORD GetWinVer()
+{
+ WORD w = GetVersion();
+
+ return (w>>8) | (w<<8);
+}
+
+#endif
+
+void NEAR PASCAL DrvInit(void)
+{
+HANDLE hlibUser;
+LPDRIVERTABLE lpdt;
+
+ /* If the window's driver interface is present then use it.
+ */
+
+ DOUT("MMSYSTEM: DrvInit");
+
+ hlibUser = GetModuleHandle(szUser);
+
+ if(lpOpenDriver = (OPENDRIVER31)GetProcAddress(hlibUser,szOpenDriver))
+ fUseWinAPI = TRUE;
+ else
+ {
+ fUseWinAPI = FALSE;
+ DOUT(" - No Windows Driver I/F detected. Using MMSYSTEM\r\n");
+
+ //
+ // force MMSYSTEM into the driver table, without enableing it.
+ //
+ cInstalledDrivers = 1;
+ hInstalledDriverList = GlobalAlloc(GHND|GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
+
+#ifdef DEBUG
+ if (hInstalledDriverList == NULL)
+ {
+ DOUT("no memory for driver table\r\n");
+ FatalExit(-1);
+ return;
+ }
+#endif
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+
+ //
+ // NOTE! we are not setting fFirstEntry==TRUE
+ //
+ // because under windows 3.0 MMSOUND will enable/disable us
+ // we *dont* wan't the driver interface doing it!
+ //
+ lpdt->lpDriverEntryPoint = (DRIVERPROC)DriverProc;
+ lpdt->hModule = ghInst;
+ lpdt->fFirstEntry = 0;
+
+ GlobalUnlock(hInstalledDriverList);
+ }
+
+ if (fUseWinAPI)
+ {
+ DOUT(" - Windows Driver I/F detected\r\n");
+
+#ifdef DEBUG
+ if (GetWinVer() < 0x30A)
+ DOUT("MMSYSTEM: WARNING !!! WINDOWS DRIVER I/F BUT VERSION LESS THAN 3.1\r\n");
+#endif
+
+ // link to the relevant user APIs.
+
+ lpCloseDriver = (CLOSEDRIVER31)GetProcAddress(hlibUser, szCloseDriver);
+ lpGetDriverModuleHandle = (GETDRIVERMODULEHANDLE31)GetProcAddress(hlibUser, szDrvModuleHandle);
+ lpSendDriverMessage = (SENDDRIVERMESSAGE31)GetProcAddress(hlibUser, szSendDriverMessage);
+ lpDefDriverProc = (DEFDRIVERPROC31)GetProcAddress(hlibUser, szDefDriverProc);
+ }
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api void | InternalInstallDriverChain | This function loads the
+ * drivers specified on the Drivers= line of the [Boot] section
+ * of system.ini. The Drivers are loaded but not opened.
+ *
+ * @rdesc None
+ *
+ ***************************************************************************/
+
+void FAR PASCAL InternalInstallDriverChain(void)
+{
+ char szBuffer[150];
+ BOOL bFinished;
+ int iStart;
+ int iEnd;
+
+ if (!fUseWinAPI)
+ {
+ /* Load DLL's from DRIVERS section in system.ini
+ */
+ GetPrivateProfileString(szBoot, /* [Boot] section */
+ szDrivers, /* Drivers= */
+ szNull, /* Default if no match */
+ szBuffer, /* Return buffer */
+ sizeof(szBuffer),
+ szSystemIni);
+
+ if (!*szBuffer)
+ return;
+
+ bFinished = FALSE;
+ iStart = 0;
+ while (!bFinished)
+ {
+ iEnd = iStart;
+ while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
+ (szBuffer[iEnd] != ','))
+ iEnd++;
+
+ if (szBuffer[iEnd] == NULL)
+ bFinished = TRUE;
+ else
+ szBuffer[iEnd] = NULL;
+
+ /* Load and enable the driver.
+ */
+ InternalLoadDriver(&(szBuffer[iStart]), NULL, NULL, 0, TRUE);
+
+ iStart = iEnd+1;
+ }
+ }
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api void | InternalDriverEnable | This function enables all the
+ * currently loaded installable drivers. If the user driver i/f
+ * has been detected, this function will do nothing.
+ *
+ * @rdesc None
+ *
+ ***************************************************************************/
+
+void FAR PASCAL InternalDriverEnable(void)
+{
+
+ if (!fUseWinAPI)
+ InternalBroadcastDriverMessage(1, DRV_ENABLE, 0L, 0L, IBDM_ONEINSTANCEONLY);
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api void | InternalDriverDisable | This function disables all the
+ * currently loaded installable drivers. If the user driver I/F
+ * has been detected, this function will do nothing.
+ *
+ *
+ * @rdesc None
+ *
+ ***************************************************************************/
+
+void FAR PASCAL InternalDriverDisable(void)
+{
+
+ if (!fUseWinAPI)
+ InternalBroadcastDriverMessage(0, DRV_DISABLE, 0L, 0L,
+ IBDM_ONEINSTANCEONLY | IBDM_REVERSE);
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api HANDLE | LoadAliasedLibrary | This function loads the library module
+ * contained in the specified file and returns its module handle
+ * unless the specified name matches a keyname in the
+ * specified section section of the specified ini file in which case
+ * the library module in the file specified on the ini line is loaded.
+ *
+ * @parm LPSTR | szLibFileName | points to a null-terminated character
+ * string containing the filename or system.ini keyname.
+ *
+ * @parm LPSTR | szSection | points to a null-terminated character
+ * string containing the section name.
+ *
+ * @parm LPSTR | szIniFile | points to a null-terminated character
+ * string containing the ini filename.
+ *
+ * @parm LPSTR | lpstrTail | caller supplied buffer to return the "tail"
+ * of the system.ini line in. The tail is any characters that follow
+ * the filename.
+ *
+ * @parm WORD | cbTail | size of supplied buffer.
+ *
+ * @rdesc Returns the library's module handle.
+ *
+ * @xref LoadLibrary
+ *
+ ***************************************************************************/
+
+HANDLE FAR PASCAL LoadAliasedLibrary(LPSTR szLibFileName,
+ LPSTR szSection,
+ LPSTR szIniFile,
+ LPSTR lpstrTail,
+ WORD cbTail)
+{
+ HANDLE h;
+ char sz[128];
+ LPSTR pch;
+ OFSTRUCT of;
+
+ if (!szLibFileName || !*szLibFileName)
+ return(2); // File not found
+
+ // read the filename and additional info. into sz
+
+ GetPrivateProfileString(szSection, // ini section
+ szLibFileName, // key name
+ szLibFileName, // default if no match
+ sz, // return buffer
+ sizeof(sz), // return buffer size
+ szIniFile); // ini. file
+
+ sz[sizeof(sz)-1] = 0;
+
+ // strip off the additional info.
+
+ pch = (LPSTR)sz;
+
+ while (*pch)
+ {
+ if (*pch == ' ')
+ {
+ *pch++ = '\0';
+ break;
+ }
+ pch++;
+ }
+
+ // pch pts to ch after first space or null ch
+
+ if (!GetModuleHandle(sz) &&
+ OpenFile(sz, &of, OF_EXIST|OF_READ|OF_SHARE_DENY_NONE) == -1)
+ return(2);
+
+ // copy additional info. to lpstrTail
+
+ if (lpstrTail && cbTail)
+ {
+ while (cbTail-- && (*lpstrTail++ = *pch++))
+ ;
+ *(lpstrTail-1) = 0;
+ }
+
+ return (LoadLibrary(sz));
+}
+
+
+/***************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api int | GetDrvrUsage | Runs through the driver list and figures
+ * out how many instances of this driver module handle we have.
+ * We use this instead of GetModuleUsage so that we can have drivers
+ * loaded as normal DLLs and as installable drivers.
+ *
+ * @parm HANDLE | h | Driver's module handle
+ *
+ * @rdesc Returns the library's driver usage count.
+ *
+ ***************************************************************************/
+
+int FAR PASCAL GetDrvrUsage(HANDLE h)
+{
+ LPDRIVERTABLE lpdt;
+ int index;
+ int count;
+
+ if (!hInstalledDriverList || !cInstalledDrivers)
+ return(0);
+
+ count = 0;
+ lpdt = (LPDRIVERTABLE)GlobalLock(hInstalledDriverList);
+ for (index=0;index<cInstalledDrivers;index++)
+ {
+ if (lpdt->hModule==h)
+ {
+ count++;
+ }
+ lpdt++;
+ }
+ GlobalUnlock(hInstalledDriverList);
+
+ return(count);
+}
diff --git a/private/mvdm/wow16/mmsystem/drvrstr.c b/private/mvdm/wow16/mmsystem/drvrstr.c
new file mode 100644
index 000000000..1f1213ff7
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/drvrstr.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: drvrstr.c - Installable driver code strings
+
+ Version: 1.00
+
+ Date: 10-Jun-1990
+
+ Author: ROBWI
+
+------------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ ----------- ----- -----------------------------------------------------------
+ 10-JUN-1990 ROBWI Based on windows 3.1 installable driver code by davidds
+
+*****************************************************************************/
+
+#include "windows.h"
+
+LPSTR szDriverProc = "DriverProc";
diff --git a/private/mvdm/wow16/mmsystem/gmem.h b/private/mvdm/wow16/mmsystem/gmem.h
new file mode 100644
index 000000000..1a03979b3
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/gmem.h
@@ -0,0 +1,69 @@
+/*
+ * GMEM.H - Macros for windows 3.0 memory management in protected mode
+ *
+ * because windows 3.0 runs in pmode GlobalLock and GlobalUnlock are
+ * unnessary. The "Selector" to a memory object will always be the
+ * same for the life of the memory object.
+ *
+ * these macros take advantage of the following win3 memory "facts"
+ *
+ * a SELECTOR (to a global object) is a HANDLE
+ * a HANDLE is *not* a SELECTOR!!!!!!!!
+ *
+ * GlobalLock() and GlobalUnlock() do *not* keep lock counts
+ *
+ * GlobalLock() is the only way to convert a HANDLE to a SELECTOR
+ *
+ * functions:
+ *
+ * GHandle(sel) convert a SELECTOR to a HANDLE
+ * GSelector(h) convert a HANDLE to a SELECTOR
+ *
+ * GAllocSel(ulBytes) allocate a SELECTOR ulBytes in size
+ * GAllocPtr(ulBytes) allocate a POINTER ulBytes in size
+ *
+ * GReAllocSel(sel,ulBytes) re-alloc a SELECTOR
+ * GReAllocPtr(lp,ulBytes) re-alloc a POINTER
+ *
+ * GSizeSel(sel) return the size in bytes of a SELECTOR
+ *
+ * GLockSel(sel) convert a SELECTOR into a POINTER
+ * GUnlockSel(sel) does nothing
+ *
+ * GFreeSel(sel) free a SELECTOR
+ * GFreePtr(lp) free a POINTER
+ *
+ * 5/31/90 ToddLa
+ *
+ */
+
+HGLOBAL __H;
+
+#define MAKEP(sel,off) ((LPVOID)MAKELONG(off,sel))
+
+#define GHandle(sel) ((HGLOBAL)(sel)) /* GlobalHandle? */
+#define GSelector(h) (HIWORD((DWORD)GlobalLock(h)))
+
+#define GAllocSelF(f,ulBytes) ((__H=GlobalAlloc(f,(LONG)(ulBytes))) ? GSelector(__H) : NULL )
+#define GAllocPtrF(f,ulBytes) MAKEP(GAllocSelF(f,ulBytes),0)
+#define GAllocF(f,ulBytes) GAllocSelF(f,ulBytes)
+
+#define GAllocSel(ulBytes) GAllocSelF(GMEM_MOVEABLE,ulBytes)
+#define GAllocPtr(ulBytes) GAllocPtrF(GMEM_MOVEABLE,ulBytes)
+#define GAlloc(ulBytes) GAllocSelF(GMEM_MOVEABLE,ulBytes)
+
+#define GReAllocSel(sel,ulBytes) ((__H=GlobalReAlloc((HGLOBAL)(sel),(LONG)(ulBytes), GMEM_MOVEABLE | GMEM_ZEROINIT)) ? GSelector(__H) : NULL )
+#define GReAllocPtr(lp,ulBytes) MAKEP(GReAllocSel(HIWORD((DWORD)(lp)),ulBytes),0)
+#define GReAlloc(sel,ulBytes) GReAllocSel(sel,ulBytes)
+
+#define GSizeSel(sel) GlobalSize((HGLOBAL)(sel))
+#define GSize(sel) GSizeSel(sel)
+
+#define GLockSel(sel) MAKEP(sel,0)
+#define GUnlockSel(sel) /* nothing */
+#define GLock(sel) GLockSel(sel)
+#define GUnlock(sel) GUnlockSel(sel)
+
+#define GFreeSel(sel) (GlobalUnlock(GHandle(sel)),GlobalFree(GHandle(sel)))
+#define GFreePtr(lp) GFreeSel(HIWORD((DWORD)(lp)))
+#define GFree(sel) GFreeSel(sel)
diff --git a/private/mvdm/wow16/mmsystem/heap.asm b/private/mvdm/wow16/mmsystem/heap.asm
new file mode 100644
index 000000000..eb35e11ed
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/heap.asm
@@ -0,0 +1,278 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: HEAP.ASM
+;
+; This module contains functions for dealing with external local heaps
+;
+; Created: 09-20-90
+; Author: Todd Laney [ToddLa]
+;
+; Copyright (c) 1984-1990 Microsoft Corporation
+;
+; Exported Functions: none
+;
+; Public Functions: HeapCreate
+; HeapDestroy
+; HeapAlloc
+; HeapFree
+;
+; Public Data: none
+;
+; General Description:
+;
+; Restrictions:
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ ?NODATA = 1
+ .286p
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ .list
+
+ MIN_HEAPSIZE = 128
+ GMEM_SHARE = GMEM_DDESHARE
+
+ externFP LocalInit ; in KERNEL
+ externFP LocalAlloc ; in KERNEL
+ externFP LocalReAlloc ; in KERNEL
+ externFP LocalFree ; in KERNEL
+ externFP LocalCompact ; in KERNEL
+ externFP GlobalAlloc ; in KERNEL
+ externFP GlobalLock ; in KERNEL
+ externFP GlobalUnlock ; in KERNEL
+ externFP GlobalFree ; in KERNEL
+
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+createSeg INIT, InitSeg, word, public, CODE
+
+sBegin InitSeg
+ assumes cs,InitSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;---------------------------Public-Routine------------------------------;
+; HeapCreate
+;
+; Create a external heap
+;
+; Entry:
+; cbSize is the initial size of the heap
+;
+; Returns:
+; AX = handle to heap
+; Error Returns:
+; AX = 0
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; GlobalAlloc, LocalInit
+; History:
+; Fri 21-Sep-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HeapCreate, <FAR,PUBLIC>, <>
+ ParmW cbSize
+cBegin
+ mov ax,cbSize
+ cmp ax,MIN_HEAPSIZE
+ jg hc_alloc
+ mov ax,MIN_HEAPSIZE
+ mov cbSize,ax
+
+hc_alloc:
+ cCall GlobalAlloc, <GHND+GMEM_SHARE,0,ax>
+ or ax,ax
+ jz hc_exit
+
+ cCall GlobalLock, <ax>
+ push dx
+ mov ax,cbSize
+ dec ax
+ cCall LocalInit,<dx,0,ax>
+ pop ax
+hc_exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HeapDestroy
+;
+; Destroys a external heap
+;
+; Entry:
+; hHeap contains heap handle (ie the selector)
+;
+; Returns:
+; none
+; Error Returns:
+; none
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; GlobalUnlock, GlobalFree
+; History:
+; Fri 21-Sep-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HeapDestroy, <FAR,PUBLIC>, <>
+ ParmW hHeap
+cBegin
+ cCall GlobalUnlock, <hHeap> ; !!! only need in REAL mode
+ cCall GlobalFree, <hHeap>
+cEnd
+
+sEnd
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;---------------------------Public-Routine------------------------------;
+; HeapAlloc
+;
+; allocate memory from a external heap
+;
+; Entry:
+; hHeap contains heap handle (ie the selector)
+; cbSize contains the requested size of the allocation
+;
+; Returns:
+; DX:AX = pointer to allocated object
+; Error Returns:
+; DX:AX = NULL
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; LocalAlloc
+; History:
+; Fri 21-Sep-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HeapAlloc, <FAR,PUBLIC>, <ds>
+ ParmW hHeap
+ ParmW cbSize
+cBegin
+ mov ds,hHeap
+ cCall LocalAlloc, <LPTR, cbSize>
+ xor dx,dx
+ or ax,ax
+ jz hal_exit
+ mov dx,ds
+hal_exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HeapReAlloc
+;
+; reallocate memory from a external heap
+;
+; Entry:
+; lpObject contains the pointer to the object to be reallocated
+; cbSize contains the requested size of the reallocation
+;
+; Returns:
+; DX:AX = pointer to allocated object
+; Error Returns:
+; DX:AX = NULL
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; LocalAlloc
+; History:
+; Wed 8-Jan-1991 1: 2: 3 -by- David Levine [DavidLe]
+; Created based on HeapAlloc.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HeapReAlloc, <FAR,PUBLIC>, <ds>
+ ParmD lpObject
+ ParmW cbSize
+cBegin
+ lds ax,lpObject
+
+AllocFlags EQU LMEM_MOVEABLE OR LMEM_ZEROINIT
+
+ cCall LocalReAlloc, <ax, cbSize, AllocFlags>
+ xor dx,dx
+ or ax,ax
+ jz hral_exit
+ mov dx,ds
+hral_exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; HeapFree
+;
+; free memory from a external heap
+;
+; Entry:
+; hObject contains the object to free
+;
+; Returns:
+; none
+; Error Returns:
+; none
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; LocalFree
+; History:
+; Fri 21-Sep-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc HeapFree, <FAR,PUBLIC>, <ds>
+ ParmD lpObject
+cBegin
+ lds ax,lpObject
+ cCall LocalFree, <ax>
+cEnd
+
+sEnd CodeSeg
+ end
diff --git a/private/mvdm/wow16/mmsystem/hmemcpy.asm b/private/mvdm/wow16/mmsystem/hmemcpy.asm
new file mode 100644
index 000000000..dff1be9c5
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/hmemcpy.asm
@@ -0,0 +1,248 @@
+; mem.asm:
+;
+; masm -Mx -Zi -DSEGNAME=????? asm.asm
+;
+ TITLE MEM.ASM
+
+;****************************************************************
+;* MEM.ASM - Assembly mem-copy routines *
+;* for 80286 and 80386 *
+;****************************************************************
+;
+
+?PLM=1 ; PASCAL Calling convention is DEFAULT
+?WIN=0 ; Windows calling convention
+
+.xlist
+include cmacros.inc
+include windows.inc
+.list
+
+ externA __WinFlags ; in KERNEL
+ externA __AHINCR ; in KERNEL
+ externA __AHSHIFT ; in KERNEL
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+; -------------------------------------------------------
+; DATA SEGMENT DECLARATIONS
+; -------------------------------------------------------
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin Data
+sEnd Data
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,DATA
+
+cProc fstrrchr,<NEAR,PASCAL,PUBLIC,NODATA>,<di>
+ ParmD lsz
+ ParmB c
+cBegin
+ les di, lsz
+ xor al, al ; Search for terminating NULL
+ mov cx, -1 ; Search forever
+ cld ; Moving forward
+ repne scasb ; Look for the NULL
+ not cx ; Negative value minus 1 gives length
+ dec cx ; CX is always incremented
+ jcxz fstrrchr_fail ; Zero length string fails
+ dec di ; DI is one past character found
+ dec di ; Back up to last character in string
+ mov al, c ; Get character to search for
+ std ; Moving backwards
+ repne scasb ; Look for the character
+ cld ; Reset direction
+ jne fstrrchr_fail ; Fail if not found
+ inc di ; Back up to actual character found
+ mov ax, di ; Return pointer to that character
+ mov dx, es
+ jmp fstrrchr_exit
+fstrrchr_fail:
+ xor ax, ax ; Return NULL on failure
+ cwd
+fstrrchr_exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; MemCopy
+;
+; copy memory, dons *not* handle overlaped copies.
+;
+; Entry:
+; lpSrc HPSTR to copy from
+; lpDst HPSTR to copy to
+; cbMem DWORD count of bytes to move
+;
+; Returns:
+; destination pointer
+; Error Returns:
+; None
+; Registers Preserved:
+; BP,DS,SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; Calls:
+; nothing
+; History:
+;
+; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
+; Created.
+; Tue 16-Oct-1990 16:41:00 -by- David Maymudes [DavidMay]
+; Modified 286 case to work correctly with cbMem >= 64K.
+; Changed name to hmemcpy.
+; Changed 386 case to copy by longwords
+;-----------------------------------------------------------------------;
+
+cProc MemCopy,<NEAR,PASCAL,PUBLIC,NODATA>,<>
+; ParmD lpDst
+; ParmD lpSrc
+; ParmD cbMem
+cBegin <nogen>
+ mov ax,__WinFlags
+ test ax,WF_CPU286
+ jz MemCopy386
+ jmp NEAR PTR MemCopy286
+cEnd <nogen>
+
+cProc MemCopy386,<NEAR,PASCAL,PUBLIC,NODATA>,<ds>
+ ParmD lpDst
+ ParmD lpSrc
+ ParmD cbMem
+cBegin
+ .386
+ push edi
+ push esi
+ cld
+
+ mov ecx,cbMem
+ jecxz mc386_exit
+
+ movzx edi,di
+ movzx esi,si
+ lds si,lpSrc
+ les di,lpDst
+
+ push ecx
+ shr ecx,2 ; get count in DWORDs
+ rep movs dword ptr es:[edi], dword ptr ds:[esi]
+ db 67H
+ pop ecx
+ and ecx,3
+ rep movs byte ptr es:[edi], byte ptr ds:[esi]
+ db 67H
+ nop
+mc386_exit:
+ cld
+ pop esi
+ pop edi
+ mov dx,lpDst.sel ; return destination address
+ mov ax,lpDst.off
+ .286
+cEnd
+
+cProc MemCopy286,<NEAR,PASCAL,PUBLIC,NODATA>,<ds,si,di>
+ ParmD lpDst
+ ParmD lpSrc
+ ParmD cbMem
+cBegin
+ mov cx,cbMem.lo ; CX holds count
+ or cx,cbMem.hi ; or with high word
+ jnz @f
+ jmp empty_copy
+@@:
+ lds si,lpSrc ; DS:SI = src
+ les di,lpDst ; ES:DI = dst
+
+next:
+ mov ax,cx
+ dec ax
+
+ mov ax,di
+ not ax ; AX = 65535-DI
+
+ mov dx,si
+ not dx ; DX = 65535-SI
+
+ sub ax,dx
+ sbb bx,bx
+ and ax,bx
+ add ax,dx ; AX = MIN(AX,DX) = MIN(65535-SI,65535-DI)
+
+ ; problem: ax might have wrapped to zero
+
+ test cbMem.hi,-1
+ jnz plentytogo ; at least 64k still to copy
+
+ dec cx ; this is ok, since high word is zero
+ sub ax,cx
+ sbb bx,bx
+ and ax,bx
+ add ax,cx ; AX = MIN(AX,CX)
+ inc cx
+
+plentytogo:
+ xor bx,bx
+ add ax,1 ; AX = Num = MIN(count,65536-SI,65536-DI)
+ ; we must check the carry here!
+ adc bx,0 ; BX could be 1 here, if CX==0 indicating
+ ; exactly 64k to copy
+ xchg ax,cx
+ sub ax,cx ; Count -= Num
+ sbb cbMem.hi,bx
+
+ shr bx,1
+ rcr cx,1 ; if bx==1, then cx ends up 0x8000
+ rep movsw
+ jnc @f
+ movsb ; move last byte, if necessary
+@@:
+ mov cx,ax ; put low word of count back in cx
+ or ax,cbMem.hi
+
+ jz done ; If Count == 0 Then BREAK
+
+ or si,si ; if SI wraps, update DS
+ jnz @f
+;
+ mov ax,ds
+ add ax,__AHINCR
+ mov ds,ax ; update DS if appropriate
+@@:
+ or di,di ; if DI wraps, update ES
+ jnz next
+;
+ mov ax,es
+ add ax,__AHINCR
+ mov es,ax ; update ES if appropriate
+ jmp next
+;
+; Restore registers and return
+;
+done:
+empty_copy:
+ mov dx,lpDst.sel ; return destination address
+ mov ax,lpDst.off
+cEnd
+
+sEnd
+
+sEnd CodeSeg
+end
diff --git a/private/mvdm/wow16/mmsystem/idrv.h b/private/mvdm/wow16/mmsystem/idrv.h
new file mode 100644
index 000000000..f22c111cb
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/idrv.h
@@ -0,0 +1,517 @@
+//==========================================================================;
+//
+// idrv.h
+//
+// Description:
+// This header file defines common information needed for compiling
+// the installable driver.
+//
+// History:
+// 11/ 8/92 cjp [curtisp]
+//
+//==========================================================================;
+
+#ifndef _INC_IDRV
+#define _INC_IDRV // #defined if file has been included
+
+#ifndef RC_INVOKED
+#pragma pack(1) // assume byte packing throughout
+#endif
+
+#ifndef EXTERN_C
+#ifdef __cplusplus
+ #define EXTERN_C extern "C"
+#else
+ #define EXTERN_C extern
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" // assume C declarations for C++
+{
+#endif
+
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// Win 32
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifdef WIN32
+ #ifndef FNLOCAL
+ #define FNLOCAL
+ #define FNCLOCAL
+ #define FNGLOBAL
+ #define FNCGLOBAL
+ #define FNWCALLBACK CALLBACK
+ #define FNEXPORT CALLBACK
+ #endif
+
+ //
+ //
+ //
+ #define Edit_GetSelEx(hwndCtl, pnS, pnE) \
+ ((DWORD)SendMessage((hwndCtl), EM_GETSEL, (WPARAM)pnS, (LPARAM)pnE))
+
+ //
+ // for compiling Unicode
+ //
+ #ifdef UNICODE
+ #define SIZEOF(x) (sizeof(x)/sizeof(WCHAR))
+ #else
+ #define SIZEOF(x) sizeof(x)
+ #endif
+
+ //
+ // win32 apps [usually] don't have to worry about 'huge' data
+ //
+ #define hmemcpy memcpy
+#endif // #ifdef WIN32
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// Win 16
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifndef WIN32
+ #ifndef FNLOCAL
+ #ifdef CALLBACK
+ #undef CALLBACK
+ #endif
+ #ifdef _WINDLL
+ #define CALLBACK _far _pascal _loadds
+ #else
+ #define CALLBACK _far _pascal
+ #endif
+
+ #ifdef DEBUG
+ #define FNLOCAL NEAR PASCAL
+ #define FNCLOCAL NEAR _cdecl
+ #else
+ #define FNLOCAL static NEAR PASCAL
+ #define FNCLOCAL static NEAR _cdecl
+ #endif
+ #define FNGLOBAL FAR PASCAL
+ #define FNCGLOBAL FAR _cdecl
+ #define FNWCALLBACK CALLBACK
+ #define FNEXPORT CALLBACK _export
+ #endif
+
+ //
+ // stuff for Unicode in Win 32--make it a noop in Win 16
+ //
+ #ifndef _TCHAR_DEFINED
+ #define _TCHAR_DEFINED
+ typedef char TCHAR, *PTCHAR;
+ typedef unsigned char TBYTE, *PTUCHAR;
+
+ typedef PSTR PTSTR, PTCH;
+ typedef LPSTR LPTSTR, LPTCH;
+ typedef LPCSTR LPCTSTR;
+ #endif
+
+ #define TEXT(a) a
+ #define SIZEOF(x) sizeof(x)
+
+ //
+ //
+ //
+ #define CharNext AnsiNext
+ #define CharPrev AnsiPrev
+
+ //
+ //
+ //
+ #define Edit_GetSelEx(hwndCtl, pnS, pnE) \
+ { \
+ DWORD dw; \
+ dw = (DWORD)SendMessage((hwndCtl), EM_GETSEL, 0, 0L); \
+ *pnE = (int)HIWORD(dw); \
+ *pnS = (int)LOWORD(dw); \
+ }
+
+ //
+ // common message cracker macros available in windowx.h on NT--these
+ // should be added to the Win 16 windowsx.h and probably will be
+ // in the future.
+ //
+ // there is a windowsx.h16 that ships with the NT PDK that defines
+ // these macros. so if that version is being used, don't redefine
+ // message crackers.
+ //
+
+#ifndef WM_CTLCOLORMSGBOX
+ #define WM_CTLCOLORMSGBOX 0x0132
+ #define WM_CTLCOLOREDIT 0x0133
+ #define WM_CTLCOLORLISTBOX 0x0134
+ #define WM_CTLCOLORBTN 0x0135
+ #define WM_CTLCOLORDLG 0x0136
+ #define WM_CTLCOLORSCROLLBAR 0x0137
+ #define WM_CTLCOLORSTATIC 0x0138
+#endif
+
+#ifndef GET_WM_ACTIVATE_STATE
+ #define GET_WM_ACTIVATE_STATE(wp, lp) (wp)
+ #define GET_WM_ACTIVATE_FMINIMIZED(wp, lp) (BOOL)HIWORD(lp)
+ #define GET_WM_ACTIVATE_HWND(wp, lp) (HWND)LOWORD(lp)
+ #define GET_WM_ACTIVATE_MPS(s, fmin, hwnd) (WPARAM)(s), MAKELONG(hwnd, fmin)
+
+ #define GET_WM_CHARTOITEM_CHAR(wp, lp) (CHAR)(wp)
+ #define GET_WM_CHARTOITEM_POS(wp, lp) HIWORD(lp)
+ #define GET_WM_CHARTOITEM_HWND(wp, lp) (HWND)LOWORD(lp)
+ #define GET_WM_CHARTOITEM_MPS(ch, pos, hwnd) (WPARAM)(ch), MAKELONG(hwnd, pos)
+
+ #define GET_WM_COMMAND_ID(wp, lp) (wp)
+ #define GET_WM_COMMAND_HWND(wp, lp) (HWND)LOWORD(lp)
+ #define GET_WM_COMMAND_CMD(wp, lp) HIWORD(lp)
+ #define GET_WM_COMMAND_MPS(id, hwnd, cmd) (WPARAM)(id), MAKELONG(hwnd, cmd)
+
+ #define GET_WM_CTLCOLOR_HDC(wp, lp, msg) (HDC)(wp)
+ #define GET_WM_CTLCOLOR_HWND(wp, lp, msg) (HWND)LOWORD(lp)
+ #define GET_WM_CTLCOLOR_TYPE(wp, lp, msg) HIWORD(lp)
+ #define GET_WM_CTLCOLOR_MPS(hdc, hwnd, type) (WPARAM)(hdc), MAKELONG(hwnd, type)
+
+ #define GET_WM_MENUSELECT_CMD(wp, lp) (wp)
+ #define GET_WM_MENUSELECT_FLAGS(wp, lp) LOWORD(lp)
+ #define GET_WM_MENUSELECT_HMENU(wp, lp) (HMENU)HIWORD(lp)
+ #define GET_WM_MENUSELECT_MPS(cmd, f, hmenu) (WPARAM)(cmd), MAKELONG(f, hmenu)
+
+ // Note: the following are for interpreting MDIclient to MDI child messages.
+ #define GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wp, lp) (BOOL)(wp)
+ #define GET_WM_MDIACTIVATE_HWNDDEACT(wp, lp) (HWND)HIWORD(lp)
+ #define GET_WM_MDIACTIVATE_HWNDACTIVATE(wp, lp) (HWND)LOWORD(lp)
+
+ // Note: the following is for sending to the MDI client window.
+ #define GET_WM_MDIACTIVATE_MPS(f, hwndD, hwndA) (WPARAM)(hwndA), 0
+
+ #define GET_WM_MDISETMENU_MPS(hmenuF, hmenuW) 0, MAKELONG(hmenuF, hmenuW)
+
+ #define GET_WM_MENUCHAR_CHAR(wp, lp) (CHAR)(wp)
+ #define GET_WM_MENUCHAR_HMENU(wp, lp) (HMENU)LOWORD(lp)
+ #define GET_WM_MENUCHAR_FMENU(wp, lp) (BOOL)HIWORD(lp)
+ #define GET_WM_MENUCHAR_MPS(ch, hmenu, f) (WPARAM)(ch), MAKELONG(hmenu, f)
+
+ #define GET_WM_PARENTNOTIFY_MSG(wp, lp) (wp)
+ #define GET_WM_PARENTNOTIFY_ID(wp, lp) HIWORD(lp)
+ #define GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp) (HWND)LOWORD(lp)
+ #define GET_WM_PARENTNOTIFY_X(wp, lp) (INT)LOWORD(lp)
+ #define GET_WM_PARENTNOTIFY_Y(wp, lp) (INT)HIWORD(lp)
+ #define GET_WM_PARENTNOTIFY_MPS(msg, id, hwnd) (WPARAM)(msg), MAKELONG(hwnd, id)
+ #define GET_WM_PARENTNOTIFY2_MPS(msg, x, y) (WPARAM)(msg), MAKELONG(x, y)
+
+ #define GET_WM_VKEYTOITEM_CODE(wp, lp) (wp)
+ #define GET_WM_VKEYTOITEM_ITEM(wp, lp) (INT)HIWORD(lp)
+ #define GET_WM_VKEYTOITEM_HWND(wp, lp) (HWND)LOWORD(lp)
+ #define GET_WM_VKEYTOITEM_MPS(code, item, hwnd) (WPARAM)(code), MAKELONG(hwnd, item)
+
+ #define GET_EM_SETSEL_START(wp, lp) LOWORD(lp)
+ #define GET_EM_SETSEL_END(wp, lp) HIWORD(lp)
+ #define GET_EM_SETSEL_MPS(iStart, iEnd) 0, MAKELONG(iStart, iEnd)
+
+ #define GET_EM_LINESCROLL_MPS(vert, horz) 0, MAKELONG(vert, horz)
+
+ #define GET_WM_CHANGECBCHAIN_HWNDNEXT(wp, lp) (HWND)LOWORD(lp)
+
+ #define GET_WM_HSCROLL_CODE(wp, lp) (wp)
+ #define GET_WM_HSCROLL_POS(wp, lp) LOWORD(lp)
+ #define GET_WM_HSCROLL_HWND(wp, lp) (HWND)HIWORD(lp)
+ #define GET_WM_HSCROLL_MPS(code, pos, hwnd) (WPARAM)(code), MAKELONG(pos, hwnd)
+
+ #define GET_WM_VSCROLL_CODE(wp, lp) (wp)
+ #define GET_WM_VSCROLL_POS(wp, lp) LOWORD(lp)
+ #define GET_WM_VSCROLL_HWND(wp, lp) (HWND)HIWORD(lp)
+ #define GET_WM_VSCROLL_MPS(code, pos, hwnd) (WPARAM)(code), MAKELONG(pos, hwnd)
+#endif
+
+#endif // #ifndef WIN32
+
+
+
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// Installable Driver Version Information:
+//
+//
+//
+// NOTE! all string resources that will be used in app.rcv for the
+// version resource information *MUST* have an explicit \0 terminator!
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#define IDRV_VERSION_MAJOR 3
+#define IDRV_VERSION_MINOR 11
+#define IDRV_VERSION_BUILD 43
+#ifdef UNICODE
+#define IDRV_VERSION_STRING_RC "Version 3.11 (Unicode Enabled)\0"
+#else
+#define IDRV_VERSION_STRING_RC "Version 3.11\0"
+#endif
+
+#define IDRV_VERSION_NAME_RC "msmixmgr.dll\0"
+#define IDRV_VERSION_COMPANYNAME_RC "Microsoft Corporation\0"
+#define IDRV_VERSION_COPYRIGHT_RC "Copyright \251 Microsoft Corp. 1993\0"
+
+#define IDRV_VERSION_PRODUCTNAME_RC "Microsoft Audio Mixer Manager\0"
+
+#ifdef DEBUG
+#define IDRV_VERSION_DESCRIPTION_RC "Microsoft Audio Mixer Manager (debug)\0"
+#else
+#define IDRV_VERSION_DESCRIPTION_RC "Microsoft Audio Mixer Manager\0"
+#endif
+
+
+//
+// Unicode versions (if UNICODE is defined)... the resource compiler
+// cannot deal with the TEXT() macro.
+//
+#define IDRV_VERSION_STRING TEXT(IDRV_VERSION_STRING_RC)
+#define IDRV_VERSION_NAME TEXT(IDRV_VERSION_NAME_RC)
+#define IDRV_VERSION_COMPANYNAME TEXT(IDRV_VERSION_COMPANYNAME_RC)
+#define IDRV_VERSION_COPYRIGHT TEXT(IDRV_VERSION_COPYRIGHT_RC)
+#define IDRV_VERSION_PRODUCTNAME TEXT(IDRV_VERSION_PRODUCTNAME_RC)
+#define IDRV_VERSION_DESCRIPTION TEXT(IDRV_VERSION_DESCRIPTION_RC)
+
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// misc defines for misc sizes and things...
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+//
+// bilingual. this allows the same identifier to be used in resource files
+// and code without having to decorate the id in your code.
+//
+#ifdef RC_INVOKED
+ #define RCID(id) id
+#else
+ #define RCID(id) MAKEINTRESOURCE(id)
+#endif
+
+
+//
+//
+//
+#ifdef WIN32
+ #define BSTACK
+ #define BCODE
+ #define BDATA
+#else
+ #define BSTACK _based(_segname("_STACK"))
+ #define BCODE _based(_segname("_CODE"))
+ #define BDATA _based(_segname("_DATA"))
+#endif
+
+
+//
+//
+//
+//
+#define IDRV_MAX_STRING_RC_CHARS 512
+#define IDRV_MAX_STRING_RC_BYTES (IDRV_MAX_STRING_RC_CHARS * sizeof(TCHAR))
+#define IDRV_MAX_STRING_ERROR_CHARS 512
+#define IDRV_MAX_STRING_ERROR_BYTES (IDRV_MAX_STRING_ERROR_CHARS * sizeof(TCHAR))
+
+
+//
+// resource defines...
+//
+#define ICON_IDRV RCID(10)
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+BOOL FNGLOBAL ProfileWriteUInt
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ UINT uValue
+);
+
+UINT FNGLOBAL ProfileReadUInt
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ UINT uDefault
+);
+
+BOOL FNGLOBAL ProfileWriteString
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ LPCTSTR pszValue
+);
+
+UINT FNGLOBAL ProfileReadString
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ LPCTSTR pszDefault,
+ LPTSTR pszBuffer,
+ UINT cbBuffer
+);
+
+BOOL FNGLOBAL ProfileWriteBytes
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ LPBYTE pbStruct,
+ UINT cbStruct
+);
+
+BOOL FNGLOBAL ProfileReadBytes
+(
+ LPCTSTR pszSection,
+ LPCTSTR pszKey,
+ LPBYTE pbStruct,
+ UINT cbStruct
+);
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+//
+//
+//
+#define BOGUS_DRIVER_ID 1L
+
+
+//
+//
+//
+//
+typedef struct tIDRVINST
+{
+ HDRVR hdrvr; // driver handle we were opened with
+
+} IDRVINST, *PIDRVINST, FAR *LPIDRVINST;
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+LRESULT FNGLOBAL IDrvLoad
+(
+ HDRVR hdrvr
+);
+
+LRESULT FNGLOBAL IDrvFree
+(
+ HDRVR hdrvr
+);
+
+LRESULT FNGLOBAL IDrvEnable
+(
+ HDRVR hdrvr
+);
+
+LRESULT FNGLOBAL IDrvDisable
+(
+ HDRVR hdrvr
+);
+
+LRESULT FNGLOBAL IDrvExitSession
+(
+ PIDRVINST pidi
+);
+
+LRESULT FNGLOBAL IDrvConfigure
+(
+ PIDRVINST pidi,
+ HWND hwnd,
+ LPDRVCONFIGINFO pdci
+);
+
+
+LRESULT FNGLOBAL IDrvInstall
+(
+ PIDRVINST pidi,
+ LPDRVCONFIGINFO pdci
+);
+
+LRESULT FNGLOBAL IDrvRemove
+(
+ PIDRVINST pidi
+);
+
+
+
+//
+// defines for gfuIDrvFlags
+//
+//
+#define IDRVF_FIRSTLOAD 0x0001
+#define IDRVF_ENABLED 0x0002
+
+
+//
+// defines for gfuIDrvOptions
+//
+//
+#define IDRV_OPTF_ZYZSMAG 0x0001
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// global variables
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+extern HINSTANCE ghinstIDrv;
+
+extern UINT gfuIDrvFlags;
+extern UINT gfuIDrvOptions;
+
+extern TCHAR gszIDrvSecConfig[];
+extern TCHAR gszNull[];
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifndef RC_INVOKED
+#pragma pack() // revert to default packing
+#endif
+
+#ifdef __cplusplus
+} // end of extern "C" {
+#endif
+
+#endif // _INC_IDRV
+
+
diff --git a/private/mvdm/wow16/mmsystem/init.c b/private/mvdm/wow16/mmsystem/init.c
new file mode 100644
index 000000000..e357c8edd
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/init.c
@@ -0,0 +1,671 @@
+/*
+ init.c
+
+ Level 1 kitchen sink DLL initialisation
+
+ Copyright (c) Microsoft Corporation 1990. All rights reserved
+
+*/
+#ifdef DEBUG
+#ifndef DEBUG_RETAIL
+#define DEBUG_RETAIL
+#endif
+#endif
+
+#include <windows.h>
+#include <mmsysver.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "drvr.h"
+#include "thunks.h"
+
+
+/****************************************************************************
+
+ global data
+
+****************************************************************************/
+
+HINSTANCE ghInst; // our module handle
+
+
+/* -------------------------------------------------------------------------
+** Thunking stuff
+** -------------------------------------------------------------------------
+*/
+LPCB32 PASCAL cb32;
+LPSOUNDDEVMSGPROC PASCAL wod32Message;
+LPSOUNDDEVMSGPROC PASCAL wid32Message;
+LPSOUNDDEVMSGPROC PASCAL mod32Message;
+LPSOUNDDEVMSGPROC PASCAL mid32Message;
+LPSOUNDDEVMSGPROC PASCAL aux32Message;
+JOYMESSAGEPROC PASCAL joy32Message;
+
+
+UINT FAR PASCAL _loadds ThunkInit(void);
+static BOOL NEAR PASCAL ThunkTerm( void );
+
+LPSOUNDDEVMSGPROC PASCAL wodMapper;
+LPSOUNDDEVMSGPROC PASCAL widMapper;
+
+
+#ifdef DEBUG_RETAIL
+BYTE fIdReverse; // reverse wave/midi id's
+#endif
+
+PHNDL pHandleList;
+
+#ifdef DEBUG_RETAIL
+extern int DebugmciSendCommand; // in MCI.C
+#endif
+
+#ifdef DEBUG
+extern WORD fDebug;
+#endif
+
+/****************************************************************************
+
+ strings
+
+****************************************************************************/
+
+static SZCODE szMMWow32[] = "winmm.dll";
+static SZCODE szNotifyCB[] = "NotifyCallbackData";
+static SZCODE szWodMessage[] = "wod32Message";
+static SZCODE szWidMessage[] = "wid32Message";
+static SZCODE szModMessage[] = "mod32Message";
+static SZCODE szMidMessage[] = "mid32Message";
+static SZCODE szAuxMessage[] = "aux32Message";
+static SZCODE szTidMessage[] = "tid32Message";
+static SZCODE szJoyMessage[] = "joy32Message";
+static SZCODE szWaveMapper[] = "wavemapper";
+static SZCODE szWodMapper[] = "wodMessage";
+static SZCODE szWidMapper[] = "widMessage";
+
+ SZCODE szNull[] = "";
+ SZCODE szSystemIni[] = "system.ini";
+ SZCODE szDrivers[] = "Drivers";
+ SZCODE szBoot[] = "boot";
+ SZCODE szDriverProc[] = "DriverProc";
+ SZCODE szJoystick[] = "joystick";
+ SZCODE szJoystickDrv[] = "joystick.drv";
+ SZCODE szTimerDrv[] = "timer";
+
+#ifdef DEBUG_RETAIL
+ SZCODE szLibMain[] = "MMSYSTEM: Win%dp %ls Version"
+ "%d.%02d MMSystem Version %d.%02d.%03d\r\n";
+ SZCODE szWinDebug[] = "(Debug)";
+ SZCODE szWinRetail[] = "(Retail)";
+#endif
+
+ SZCODE szMMSystem[] = "mmsystem";
+ SZCODE szStackFrames[] = "StackFrames";
+ SZCODE szStackSize[] = "StackSize";
+
+#ifdef DEBUG_RETAIL
+ SZCODE szDebugOutput[] = "DebugOutput";
+ SZCODE szMci[] = "mci";
+#endif
+#ifdef DEBUG
+ SZCODE szDebug[] = "Debug";
+#endif
+
+#ifdef DEBUG_RETAIL
+/*****************************************************************************
+ *
+ * DebugInit() - called from init.c!LibMain() to handle any DLL load time
+ * initialization in the DEBUG version
+ *
+ ****************************************************************************/
+static void NEAR PASCAL
+DebugInit(
+ void
+ )
+{
+ fDebugOutput = GetPrivateProfileInt(szMMSystem,szDebugOutput,0,szSystemIni);
+ DebugmciSendCommand = GetPrivateProfileInt(szMMSystem,szMci,0,szSystemIni);
+
+#ifdef DEBUG
+ fDebug = GetPrivateProfileInt(szMMSystem,szDebug,fDebugOutput,szSystemIni);
+
+ if (fDebug && !fDebugOutput)
+ fDebug = FALSE;
+
+ if (fDebug) {
+ OutputDebugString( "Breaking for debugging\r\n" );
+ _asm int 3
+ }
+#endif
+}
+#endif // ifdef DEBUG_RETAIL
+
+
+
+/****************************************************************************
+
+ Library initialization code
+
+ libentry took care of calling LibMain() and other things....
+
+****************************************************************************/
+int NEAR PASCAL
+LibMain(
+ HINSTANCE hInstance,
+ UINT cbHeap,
+ LPSTR lpCmdLine
+ )
+{
+
+#ifdef DEBUG_RETAIL
+ WORD w;
+#endif
+
+ ghInst = hInstance;
+
+ /*
+ ** Here we do a global alloc of the Callback data array. We then
+ ** Lock and Page Lock the allocated storage and initialize the storage
+ ** to all zeros. We then call WOW32 passing to it the address of the
+ ** Callback data array, which is saved by WOW32.
+ */
+ hGlobal = GlobalAlloc( GHND, sizeof(CALLBACK_DATA) );
+ if ( hGlobal == (HGLOBAL)NULL ) {
+ return FALSE;
+ }
+
+ vpCallbackData = (VPCALLBACK_DATA)GlobalLock( hGlobal );
+ if ( vpCallbackData == NULL ) {
+ return FALSE;
+ }
+
+ if ( !HugePageLock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) ) ) {
+ return FALSE;
+ }
+
+ /*
+ ** Now we create our interrupt callback stacks.
+ */
+ if ( StackInit() == FALSE ) {
+ return FALSE;
+ }
+
+ /*
+ ** Now we install our interrupt service routine. InstallInterruptHandler
+ ** return FALSE if it couldn't set the interrupt vector. If this is the
+ ** case we have to terminate the load of the dll.
+ */
+ if ( InstallInterruptHandler() == FALSE ) {
+ return FALSE;
+ }
+
+
+#ifdef DEBUG_RETAIL
+ DebugInit();
+ w = (WORD)GetVersion();
+#endif
+
+ DPRINTF(( szLibMain, WinFlags & WF_WIN386 ? 386 : 286,
+ (LPSTR)(GetSystemMetrics(SM_DEBUG) ? szWinDebug : szWinRetail),
+ LOBYTE(w), HIBYTE(w),
+ HIBYTE(mmsystemGetVersion()), LOBYTE(mmsystemGetVersion()),
+ MMSYSRELEASE ));
+
+#ifdef DEBUG
+ DPRINTF(("MMSYSTEM: NumTasks: %d\r\n", GetNumTasks()));
+ //
+ // 3.0 - MMSYSTEM must be loaded by MMSOUND (ie at boot time)
+ // check for this and fail to load otherwise.
+ //
+ // the real reason we need loaded at boot time is so we can get
+ // in the enable/disable chain.
+ //
+ if (GetNumTasks() > 1)
+ {
+ DOUT("MMSYSTEM: ***!!! Not correctly installed !!!***\r\n");
+////////return FALSE; -Dont fail loading, just don't Enable()
+ }
+#endif
+
+#ifdef DEBUG_RETAIL
+ //
+ // fIdReverse being TRUE causes mmsystem to reverse all wave/midi
+ // logical device id's.
+ //
+ // this prevents apps/drivers assuming a driver load order.
+ //
+ // see wave.c!MapWaveId() and midi.c!MapId()
+ //
+
+ fIdReverse = LOBYTE(LOWORD(GetCurrentTime())) & (BYTE)0x01;
+
+ if (fIdReverse)
+ ROUT("MMSYSTEM: wave/midi driver id's will be inverted");
+#endif
+
+ //
+ // do a LoadLibrary() on ourself
+ //
+ LoadLibrary(szMMSystem);
+
+ return TRUE;
+}
+
+/****************************************************************************
+
+ DrvFree - Handler for a DRV_FREE driver message
+
+****************************************************************************/
+void FAR PASCAL
+DrvFree(
+ void
+ )
+{
+ MCITerminate(); // mci.c free heap
+ WndTerminate(); // mmwnd.c destroy window, unregister class
+ if ( mmwow32Lib != 0L ) {
+ ThunkTerm();
+ }
+}
+
+
+/****************************************************************************
+
+ DrvLoad - handler for a DRV_LOAD driver message
+
+****************************************************************************/
+BOOL FAR PASCAL DrvLoad(void)
+{
+
+/*
+** The VFW1.1 wave mapper was GP faulting in Daytona when running dangerous
+** creatures videos. Since it was trying to load an invalid selector in
+** its callback routine it's doubtful we can ever enable them.
+**
+*/
+#if 0 // The wave mappers were GP faulting in Daytona so NOOP for now
+
+ HDRVR h;
+
+
+ /* The wave mapper.
+ *
+ * MMSYSTEM allows the user to install a special wave driver which is
+ * not visible to the application as a physical device (it is not
+ * included in the number returned from getnumdevs).
+ *
+ * An application opens the wave mapper when it does not care which
+ * physical device is used to input or output waveform data. Thus
+ * it is the wave mapper's task to select a physical device that can
+ * render the application-specified waveform format or to convert the
+ * data into a format that is renderable by an available physical
+ * device.
+ */
+
+ if (h = mmDrvOpen(szWaveMapper))
+ {
+ mmDrvInstall(h, &wodMapper, MMDRVI_MAPPER|MMDRVI_WAVEOUT|MMDRVI_HDRV);
+ /* open again to get usage count in DLL correct */
+ h = mmDrvOpen(szWaveMapper);
+ mmDrvInstall(h, &widMapper, MMDRVI_MAPPER|MMDRVI_WAVEIN |MMDRVI_HDRV);
+ }
+#endif // NOOP wave mapper
+
+
+ if ( TimeInit() && WndInit() ) {
+ return TRUE;
+ }
+
+ //
+ // something failed, backout the changes
+ //
+ DrvFree();
+ return FALSE;
+}
+
+/******************************Public*Routine******************************\
+* StackInit
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+BOOL FAR PASCAL
+StackInit(
+ void
+ )
+{
+# define GMEM_STACK_FLAGS (GMEM_FIXED | GMEM_SHARE)
+# define DEF_STACK_SIZE 0x600 // 1.5k
+# define DEF_STACK_FRAMES 3
+# define MIN_STACK_SIZE 64
+# define MIN_STACK_FRAMES 1
+
+ DWORD dwStackBytes;
+ WORD wStackFrames;
+
+ //
+ // The original Window 3.1 code didn't create stack frames for the
+ // Windows Enchanced mode. However, WOW only emulates standard mode so
+ // I won't bother with this distinction.
+ //
+ // if (WinFlags & WF_ENHANCED)
+ // return TRUE;
+ //
+
+ /* read stackframes and stacksize from system.ini */
+ gwStackSize = GetPrivateProfileInt( szMMSystem, szStackSize,
+ DEF_STACK_SIZE, szSystemIni );
+
+ /* make sure value isn't something stupid */
+ if ( gwStackSize < DEF_STACK_SIZE ) {
+ gwStackSize = DEF_STACK_SIZE;
+ }
+
+ wStackFrames = GetPrivateProfileInt( szMMSystem, szStackFrames,
+ DEF_STACK_FRAMES, szSystemIni );
+
+ //
+ // Always create at least DEF_STACK_FRAMES stack frames.
+ //
+ if ( wStackFrames < DEF_STACK_FRAMES ) {
+ wStackFrames = DEF_STACK_FRAMES;
+ }
+
+ gwStackFrames = wStackFrames;
+
+ /* round to nearest number of WORDs */
+ gwStackSize = (gwStackSize + 1) & ~1;
+
+ dwStackBytes = (DWORD)gwStackSize * (DWORD)gwStackFrames;
+
+ /* try to alloc memory */
+ if ( dwStackBytes >= 0x10000 ||
+ !(gwStackSelector = GlobalAlloc(GMEM_STACK_FLAGS, dwStackBytes)) )
+ {
+ gwStackFrames = DEF_STACK_FRAMES;
+ gwStackSize = DEF_STACK_SIZE;
+
+ /* do as little at runtime as possible.. */
+ dwStackBytes = (DWORD)(DEF_STACK_FRAMES * DEF_STACK_SIZE);
+
+ /* try allocating defaults--if this fails, we are HOSED! */
+ gwStackSelector = GlobalAlloc( GMEM_STACK_FLAGS, dwStackBytes );
+ }
+
+ /*
+ ** set to first available stack
+ */
+ gwStackUse = (WORD)dwStackBytes;
+
+
+ /*
+ ** did we get memory for stacks??
+ */
+ if ( !gwStackSelector ) {
+
+ /*
+ ** no stacks available... as if we have a chance of survival!
+ */
+
+ gwStackUse = 0;
+ return FALSE;
+ }
+
+ /* looks good... */
+ return TRUE;
+}
+
+
+/*****************************Private*Routine******************************\
+* StackInit
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+BOOL NEAR PASCAL
+StackTerminate(
+ void
+ )
+{
+ if ( gwStackSelector )
+ {
+ DOUT("MMSTACKS: Freeing stacks\r\n");
+
+ gwStackSelector = GlobalFree( gwStackSelector );
+
+ if ( gwStackSelector )
+ DOUT("MMSTACKS: GlobalFree failed!\r\n");
+ }
+
+ /* return the outcome... non-zero is bad */
+ return ( (BOOL)gwStackSelector );
+} /* StackTerminate() */
+
+
+/*****************************************************************************
+ * @doc EXTERNAL MMSYSTEM
+ *
+ * @api WORD | mmsystemGetVersion | This function returns the current
+ * version number of the Multimedia extensions system software.
+ *
+ * @rdesc The return value specifies the major and minor version numbers of
+ * the Multimedia extensions. The high-order byte specifies the major
+ * version number. The low-order byte specifies the minor version number.
+ *
+ ****************************************************************************/
+WORD WINAPI mmsystemGetVersion(void)
+{
+ return(MMSYSTEM_VERSION);
+}
+
+
+/*****************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api BOOL | DrvTerminate | This function cleans up the installable
+ * driver interface.
+ *
+ ****************************************************************************/
+static void NEAR PASCAL DrvTerminate(void)
+{
+// don't know about system exit dll order - so do nothing.
+}
+
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api BOOL | mmDrvInstall | This function installs a WAVE driver
+ *
+ * @parm HANDLE | hDriver | Module handle or driver handle containing driver
+ *
+ * @parm DRIVERMSGPROC | drvMessage | driver message procedure, if NULL
+ * the standard name will be used (looked for with GetProcAddress)
+ *
+ * @parm UINT | wFlags | flags
+ *
+ * @flag MMDRVI_TYPE | driver type mask
+ * @flag MMDRVI_WAVEIN | install driver as a wave input driver
+ * @flag MMDRVI_WAVEOUT | install driver as a wave ouput driver
+ *
+ * @flag MMDRVI_MAPPER | install this driver as the mapper
+ * @flag MMDRVI_HDRV | hDriver is a installable driver
+ *
+ * @rdesc returns NULL if unable to install driver
+ *
+ ****************************************************************************/
+BOOL WINAPI
+mmDrvInstall(
+ HANDLE hDriver,
+ DRIVERMSGPROC *drvMessage,
+ UINT wFlags
+ )
+{
+ DWORD dw;
+ HINSTANCE hModule;
+ UINT msg_num_devs;
+ SZCODE *szMessage;
+
+ hModule = GetDriverModuleHandle((HDRVR)hDriver);
+
+ switch (wFlags & MMDRVI_TYPE)
+ {
+ case MMDRVI_WAVEOUT:
+ msg_num_devs = WODM_GETNUMDEVS;
+ szMessage = szWodMapper;
+ break;
+
+ case MMDRVI_WAVEIN:
+ msg_num_devs = WIDM_GETNUMDEVS;
+ szMessage = szWidMapper;
+ break;
+
+ default:
+ goto error_exit;
+ }
+
+ if (hModule != NULL)
+ *drvMessage = (DRIVERMSGPROC)GetProcAddress(hModule, szMessage);
+
+ if (*drvMessage == NULL)
+ goto error_exit;
+
+ //
+ // send the init message, if the driver returns a error, should we
+ // unload them???
+ //
+ dw = (*(*drvMessage))(0,DRVM_INIT,0L,0L,0L);
+
+ //
+ // call driver to get num-devices it supports
+ //
+ dw = (*(*drvMessage))(0,msg_num_devs,0L,0L,0L);
+
+ //
+ // the device returned a error, or has no devices
+ //
+ if (HIWORD(dw) != 0)
+ goto error_exit;
+
+ return TRUE;
+
+error_exit:
+ if (hDriver)
+ CloseDriver(hDriver, 0, 0);
+
+ return FALSE;
+}
+
+
+/*****************************************************************************
+ *
+ * @doc INTERNAL
+ *
+ * @api HDRVR | mmDrvOpen | This function load's an installable driver, but
+ * first checks weather it exists in the [Drivers] section.
+ *
+ * @parm LPSTR | szAlias | driver alias to load
+ *
+ * @rdesc The return value is return value from OpenDriver or NULL if the alias
+ * was not found in the [Drivers] section.
+ *
+ ****************************************************************************/
+HDRVR NEAR PASCAL
+mmDrvOpen(
+ LPSTR szAlias
+ )
+{
+ char buf[3];
+
+ if (GetPrivateProfileString( szDrivers,szAlias,szNull,buf,
+ sizeof(buf),szSystemIni )) {
+
+ return OpenDriver(szAlias, NULL, 0L);
+ }
+ else {
+ return NULL;
+ }
+}
+
+/*****************************Private*Routine******************************\
+* ThunkInit
+*
+* Tries to setup the thunking system. If this can not be performed
+* it returns an error code of MMSYSERR_NODRIVER. Otherwise it returns
+* MMSYSERR_NOERROR to indicate sucess.
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT FAR PASCAL _loadds
+ThunkInit(
+ void
+ )
+{
+ mmwow32Lib = LoadLibraryEx32W( szMMWow32, NULL, 0L );
+ if ( mmwow32Lib == 0L ) {
+ return MMSYSERR_NODRIVER;
+ }
+ cb32 = (LPCB32)GetProcAddress32W(mmwow32Lib, szNotifyCB );
+
+ /*
+ ** Now we notify WOW32 that all is OK by passing the 16:16 bit pointer
+ ** to the CALLBACK_DATA to it.
+ */
+ Notify_Callback_Data( vpCallbackData );
+
+ /*
+ ** Now initialize the rest of the thuynking system
+ */
+ wod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWodMessage );
+ wid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szWidMessage );
+ mod32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szModMessage );
+ mid32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szMidMessage );
+ aux32Message = (LPSOUNDDEVMSGPROC)GetProcAddress32W( mmwow32Lib, szAuxMessage );
+ mci32Message = (LPMCIMESSAGE)GetProcAddress32W( mmwow32Lib, "mci32Message" );
+ tid32Message = (TIDMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szTidMessage );
+ joy32Message = (JOYMESSAGEPROC)GetProcAddress32W( mmwow32Lib, szJoyMessage );
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************Private*Routine******************************\
+* ThunkTerm
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+static BOOL NEAR PASCAL
+ThunkTerm(
+ void
+ )
+{
+ /*
+ ** Free the interrupt stack frames and uninstall the interrupt handler.
+ */
+ StackTerminate();
+ DeInstallInterruptHandler();
+
+ /*
+ ** Next we notify WOW32 that we are going away by passing NULL to
+ ** Notify_Callback_Data, then free the storage.
+ */
+ Notify_Callback_Data( NULL );
+ HugePageUnlock( vpCallbackData, (DWORD)sizeof(CALLBACK_DATA) );
+ GlobalUnlock( hGlobal );
+ GlobalFree( hGlobal );
+
+ return 1;
+}
+
diff --git a/private/mvdm/wow16/mmsystem/int31.inc b/private/mvdm/wow16/mmsystem/int31.inc
new file mode 100644
index 000000000..3de9a3c7f
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/int31.inc
@@ -0,0 +1,144 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1989-1990
+;
+; Title: INT31.INC - Equates and Structures for Int 31h Interface
+;
+; Version: 3.00
+;
+; Date: 22-May-1989
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 22-May-1989 RAL Original
+;
+;==============================================================================
+
+
+
+Int31_Sel_Mgt EQU 00h
+ SelMgt_Alloc_Sel EQU 00h
+ SelMgt_Free_Sel EQU 01h
+ SelMgt_Seg_To_Sel EQU 02h
+ SelMgt_Get_LDT_Base EQU 03h
+ SelMgt_Lock_Sel EQU 04h
+ SelMgt_Unlock_Sel EQU 05h
+ SelMgt_Get_Base EQU 06h
+ SelMgt_Set_Base EQU 07h
+ SelMgt_Set_Limit EQU 08h
+ SelMgt_Set_Acc_Bits EQU 09h
+ SelMgt_Alias_Sel EQU 0Ah
+ SelMgt_Get_Desc EQU 0Bh
+ SelMgt_Set_Desc EQU 0Ch
+ SelMgt_Get_Spec_Sel EQU 0Dh
+
+Int31_DOS_Mem_Mgt EQU 01h
+ DOSMem_Allocate EQU 00h
+ DOSMem_Free EQU 01h
+ DOSMem_Resize EQU 02h
+
+Int31_Int_Serv EQU 02h
+ Int_Get_Real_Vec EQU 00h
+ Int_Set_Real_Vec EQU 01h
+ Int_Get_Excep_Vec EQU 02h
+ Int_Set_Excep_Vec EQU 03h
+ Int_Get_PMode_Vec EQU 04h
+ Int_Set_PMode_Vec EQU 05h
+
+Int31_Trans_Serv EQU 03h
+ Trans_Sim_Int EQU 00h
+ Trans_Far_Call EQU 01h
+ Trans_Call_Int_Proc EQU 02h
+ Trans_Call_Back EQU 03h
+ Trans_Free_CB EQU 04h
+ Trans_Get_Save_Addr EQU 05h
+ Trans_Get_Sw_Addr EQU 06h
+
+Int31_Get_Version EQU 04h
+
+Int31_Mem_Mgt EQU 05h
+ MemMgt_Get_Info EQU 00h
+ MemMgt_Allocate EQU 01h
+ MemMgt_Free EQU 02h
+ MemMgt_Resize EQU 03h
+
+Int31_Page_Lock EQU 06h
+ Lock_Region EQU 00h
+ Unlock_Region EQU 01h
+ Mark_Pageable EQU 02h
+ Mark_Not_Pageable EQU 03h
+ Get_Page_Size EQU 04h
+
+Int31_Demand_Page_Tune EQU 07h
+ Page_Candidate EQU 00h
+ Page_Discard EQU 01h
+ DPMI_Candidate EQU 02h
+ DPMI_Discard EQU 03h
+
+Int31_Map_Phys_Addr EQU 08h
+
+Int31_Virt_Int_State EQU 09h
+ Get_Clear_Int_State EQU 00h
+ Get_Set_Int_State EQU 01h
+ Get_Int_State EQU 02h
+
+
+Real_Mode_Call_Struc STRUC
+RealMode_EDI dd ?
+RealMode_ESI dd ?
+RealMode_EBP dd ?
+ dd ?
+RealMode_EBX dd ?
+RealMode_EDX dd ?
+RealMode_ECX dd ?
+RealMode_EAX dd ?
+RealMode_Flags dw ?
+RealMode_ES dw ?
+RealMode_DS dw ?
+RealMode_FS dw ?
+RealMode_GS dw ?
+RealMode_IP dw ?
+RealMode_CS dw ?
+RealMode_SP dw ?
+RealMode_SS dw ?
+Real_Mode_Call_Struc ENDS
+
+
+Real_Mode_Word_Regs STRUC
+RealMode_DI dw ?
+ dw ?
+RealMode_SI dw ?
+ dw ?
+RealMode_BP dw ?
+ dw ?
+ dd ?
+RealMode_BX dw ?
+ dw ?
+RealMode_DX dw ?
+ dw ?
+RealMode_CX dw ?
+ dw ?
+RealMode_AX dw ?
+Real_Mode_Word_Regs ENDS
+
+
+Real_Mode_Byte_Regs STRUC
+ dd 4 dup (?)
+RealMode_BL db ?
+RealMode_BH db ?
+ dw ?
+RealMode_DL db ?
+RealMode_DH db ?
+ dw ?
+RealMode_CL db ?
+RealMode_CH db ?
+ dw ?
+RealMode_AL db ?
+RealMode_AH db ?
+Real_Mode_Byte_Regs ENDS
diff --git a/private/mvdm/wow16/mmsystem/isr.asm b/private/mvdm/wow16/mmsystem/isr.asm
new file mode 100644
index 000000000..28f01a720
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/isr.asm
@@ -0,0 +1,225 @@
+TITLE ISR.ASM -- Windows DLL HARDWARE ISR
+;****************************************************************************
+;
+; PROGRAM: isr.asm
+;
+; PURPOSE:
+; Installs an interrupt handler under Windows 3.x
+; This ISR (Interrupt service routine) will then service a requested
+; multi-media callback routine.
+;
+; FUNCTIONS:
+; DoInterrupt: Performs interrupt processing
+; InstallInterruptHandler: Installs the interrupt handler
+; DeInstallInterruptHandler: Removes the interrupt handler
+;
+;****************************************************************************
+
+ .286
+memS EQU 1 ;Small memory model
+
+.xlist
+ include cmacros.inc
+ include windows.inc
+ include wowmmcb.inc
+ include vint.inc
+.list
+
+
+;-------------------------------------------------------------------------;
+;
+; debug support
+;
+;-------------------------------------------------------------------------;
+
+
+externFP OutputDebugString
+externFP DoInterrupt
+
+;-------------------------------------------------------------------------;
+;
+; callback support
+;
+;-------------------------------------------------------------------------;
+externW CodeFixWinFlags
+
+
+
+;--------------------------Private-Macro----------------------------------;
+; DOUT String - send a debug message to the debugger
+;
+; Entry:
+; String String to send to the COM port, does not need a CR,LF
+;
+; Registers Destroyed:
+; none
+;
+; NOTE no code is generated unless the DEBUG symbol is defined
+;
+; History:
+; Sun 31-Jul-1989 -by- ToddLa
+; Wrote it.
+;-------------------------------------------------------------------------;
+
+DOUT macro text
+ local string_buffer
+ifdef MYDEBUG
+ push cs
+ push offset string_buffer
+ call OutputDebugString
+ jmp @F
+string_buffer label byte
+ db "MMSYSTEM: "
+ db "&text&",13,10,0
+@@:
+endif
+ endm
+
+
+;****************************************************************************
+;
+; Create a fixed code segment
+;
+;****************************************************************************
+
+createSeg FIX, CodeFix, word, public, CODE
+createSeg INTDS, DataFix, byte, public, DATA
+
+
+
+DOS_SetVector EQU 2500h
+DOS_GetVector EQU 3500h
+Pic1 EQU 20h
+Pic2 EQU 0a0h
+
+sBegin Data
+staticD dOldVector,0
+sEnd
+
+sBegin CodeFix
+ assumes cs,CodeFix
+ assumes ds,Data
+
+
+
+;****************************************************************************
+; FUNCTION: InstallInterruptHandler()
+;
+; PURPOSE:
+; This routine saves the interrupt vector "MultiMediaVector" in
+; the global variable "dOldVector". Then, it installs a small
+; ISR at that vector which calls the routine "DoInt()" when
+; the interrupt occurs.
+;
+;
+;****************************************************************************
+cProc InstallInterruptHandler, <FAR,PUBLIC>, <si,di>
+cBegin InstallInterruptHandler
+
+ push bx ;Save previous vector
+ push es
+ mov ax,DOS_GetVector + MULTIMEDIA_INTERRUPT
+ int 21h
+ mov WORD PTR dOldVector,bx
+ mov WORD PTR dOldVector+2,es
+ pop es
+ pop bx
+
+
+ push ds ;Install handler
+ push dx ;
+ push cs
+ pop ds
+ mov dx,OFFSET MULTI_MEDIA_ISR286
+ test cs:[CodeFixWinFlags],WF_WIN286
+ jnz @F
+ mov dx,OFFSET MULTI_MEDIA_ISR386
+@@:
+ mov ax,DOS_SetVector + MULTIMEDIA_INTERRUPT
+ int 21h
+ pop dx
+ pop ds
+
+ jmp set_exit
+
+ ; **** Entry point of ISR ****
+MULTI_MEDIA_ISR286: ;Our Multi-Media ISR (286)
+ pusha
+ push ds
+ push es
+
+ cCall DoInterrupt ;Do Interrupt Handling
+
+ mov al,20h
+ out Pic2,al ;EOI on Pic2
+ out Pic1,al ;EOI on Pic1
+ pop es
+ pop ds
+ popa
+ ; FSTI
+ ; iret ;exit MULTI_MEDIA_ISR
+ FIRET
+
+MULTI_MEDIA_ISR386: ;Our Multi-Media ISR (286)
+.386
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+
+ cCall DoInterrupt ;Do Interrupt Handling
+
+ mov al,20h
+ out Pic2,al ;EOI on Pic2
+ out Pic1,al ;EOI on Pic1
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ ; FSTI
+ ; iret ;exit MULTI_MEDIA_ISR
+ FIRET
+.286
+
+set_exit: ;exit InstallHandler
+
+; DOUT <Interupt installed>
+ mov ax,1 ;return TRUE
+
+cEnd InstallInteruptHandler
+
+
+;****************************************************************************
+; FUNCTION: DeInstallInterruptHandler()
+;
+; PURPOSE:
+; Restores the interrupt vector "MultiMediaVector" with the address
+; at "dOldVector".
+;
+;****************************************************************************
+cProc DeInstallInterruptHandler, <FAR,PUBLIC>, <si,di>
+cBegin DeInstallInterruptHandler
+
+ push ds ;
+ push dx ;
+ mov dx,WORD PTR dOldVector
+ mov ax,WORD PTR dOldVector+2
+ cmp dx,0 ;were we installed?
+ jnz dih_go
+ cmp ax,0
+ jz dih_skip
+dih_go:
+ mov ds,ax
+ mov ax,DOS_SetVector + MULTIMEDIA_INTERRUPT
+ int 21h
+
+dih_skip:
+ pop dx ;
+ pop ds ;
+
+cEnd DeInstallHandler
+
+sEnd
+ end
diff --git a/private/mvdm/wow16/mmsystem/joy.c b/private/mvdm/wow16/mmsystem/joy.c
new file mode 100644
index 000000000..fdb303fb2
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/joy.c
@@ -0,0 +1,725 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: joy.c - MMSYSTEM Joystick interface code
+
+ Version: 1.00
+
+ Date: 10-Jun-1990
+
+ Author: GLENNS ROBWI
+
+------------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ -------- ----- -----------------------------------------------------------
+ 2/7/90 Changes to avoid a bug in Windows which won't allow
+ FreeLibrary to be called during WEP.
+
+ 10/11/90 .61 Use windows timer + general cleanup
+
+*****************************************************************************/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "thunks.h"
+
+// Put init and terminate code in correct segment.
+
+static void NEAR PASCAL joyGetCalibration(void);
+
+#pragma alloc_text( INIT, JoyInit )
+#pragma alloc_text( INIT, joyGetCalibration)
+
+/* -------------------------------------------------------------------------
+** Thunking stuff
+** -------------------------------------------------------------------------
+*/
+extern JOYMESSAGEPROC PASCAL joy32Message;
+
+
+
+/****************************************************************************
+
+ strings
+
+****************************************************************************/
+
+extern char far szNull[]; // in INIT.C
+extern char far szSystemIni[];
+extern char far szJoystick[];
+extern char far szJoystickDrv[];
+extern char far szDrivers[];
+
+char szJoyKey[] = "JoyCal ";
+
+/****************************************************************************
+
+ Joystick Capture Internal Structure
+
+****************************************************************************/
+
+typedef struct joycapture_tag {
+ HWND hWnd;
+ UINT wPeriod;
+ BOOL bChanged;
+ UINT wThreshold;
+ UINT wIDEvent;
+} JOYCAPTURE;
+
+#define iJoyMax 2
+#define JOY_UNINITIALIZED 0xFFFF
+
+// !!! Code assumes these constants equal 0 and 1
+
+#if JOYSTICKID1 != 0
+ERROR IN ASSUMMED CONSTANT
+#endif
+#if JOYSTICKID2 != 1
+ERROR IN ASSUMMED CONSTANT
+#endif
+
+
+/****************************************************************************
+
+ Local data
+
+****************************************************************************/
+
+static JOYCAPTURE JoyCapture[iJoyMax];
+static HDRVR hDrvJoy[iJoyMax];
+static UINT wNumDevs = JOY_UNINITIALIZED;
+
+void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT wIDEvent, DWORD dwTime);
+
+/****************************************************************************
+
+ @doc INTERNAL
+
+ @api void | joyGetCalibration | Retrieve and set calibration from
+ [joystick.drv] section of system.ini file.
+
+****************************************************************************/
+
+// !!! need to do clean up of strings in all of mmsystem
+
+static void NEAR PASCAL joyGetCalibration(void)
+{
+ char szKeyName[sizeof(szJoyKey)];
+
+ #define hexval(h) (int)(h>='a'?h-'a'+10:h-'0')
+
+ UINT val[6];
+ UINT wDev,wVal;
+ int hv;
+ char c,sz[80],far *psz;
+
+ lstrcpy(szKeyName, szJoyKey);
+ for (wDev=0; wDev < wNumDevs; wDev++)
+ {
+ szKeyName[sizeof(szKeyName)-2] = (char)(wDev + '0');
+
+ if (GetPrivateProfileString(szJoystickDrv,
+ szKeyName,szNull,sz,sizeof(sz),szSystemIni))
+ {
+ AnsiLower(sz);
+ for (psz=sz,wVal=0; c = *psz, wVal < 6; psz++)
+ {
+ if (c != ' ')
+ {
+ hv=0;
+
+ do {
+ hv = (hv << 4) + hexval(c);
+ } while ((c=*++psz) && (c!=' '));
+
+ val[wVal++] = hv;
+ }
+ }
+ joySetCalibration (wDev,val+0,val+1,val+2,val+3,val+4,val+5);
+ }
+ }
+}
+
+/****************************************************************************
+
+ @doc INTERNAL
+
+ @api BOOL | JoyInit | This function initializes the joystick services.
+
+ @rdesc The return value is TRUE if the services are initialised, FALSE
+ if an error occurs
+
+****************************************************************************/
+
+BOOL FAR PASCAL JoyInit(void)
+{
+ // Only attempt initialization once.
+ if (wNumDevs != JOY_UNINITIALIZED) {
+ return FALSE;
+ }
+ else {
+ wNumDevs = 0;
+ }
+
+ wNumDevs = joyMessage( (HDRVR)1, JDD_GETNUMDEVS, 0L, 0L );
+
+ // Make sure driver was installed.
+ if (joy32Message == NULL) {
+ return FALSE;
+ }
+
+ switch ( wNumDevs ) {
+
+ case 2:
+ hDrvJoy[1] = (HDRVR)2;
+ /* fall thru */
+
+ case 1:
+ hDrvJoy[0] = (HDRVR)1;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ // Initialize joycapture...
+
+ // Code relies on hWnd being NULL or an invalid window handle
+ // if joystick is not captured.
+
+ JoyCapture[0].hWnd = NULL;
+ JoyCapture[1].hWnd = NULL;
+
+ // Code relies on joystick threshold being initialized to a rational
+ // value. 0 essentially turns threshold off - any change in joystick
+ // position will be reported.
+
+ JoyCapture[0].wThreshold= 0;
+ JoyCapture[1].wThreshold= 0;
+
+ JoyCapture[0].wIDEvent= 0;
+ JoyCapture[1].wIDEvent= 0;
+
+ // bChanged, and wPeriod do not need initializing.
+
+ joyGetCalibration ();
+
+ return TRUE;
+
+}
+
+
+/****************************************************************************
+*
+* MMSYSTEM JOYSTICK API'S
+*
+****************************************************************************/
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joyGetDevCaps | This function queries a joystick device to
+ determine its capabilities.
+
+ @parm UINT | wId | Identifies the device to be queried. This value
+ is either JOYSTICKID1 or JOYSTICKID2.
+
+ @parm LPJOYCAPS | lpCaps | Specifies a far pointer to a <t JOYCAPS>
+ data structure. This structure is filled with information about the
+ capabilities of the joystick device.
+
+ @parm UINT | wSize | Specifies the size of the <t JOYCAPS> structure.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
+
+ @comm Use <f joyGetNumDevs> to determine the number of
+ joystick devices supported by the driver.
+
+ @xref joyGetNumDevs
+****************************************************************************/
+
+UINT WINAPI joyGetDevCaps(UINT wId, LPJOYCAPS lpCaps, UINT wSize)
+{
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+
+ if ((!hDrvJoy[0] && !JoyInit()) || (wId >= iJoyMax))
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ return joyMessage( hDrvJoy[wId], JDD_GETDEVCAPS,
+ (DWORD)lpCaps, (DWORD)wSize );
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joyGetNumDevs | This function returns the number of joystick
+ devices supported by the system.
+
+ @rdesc Returns the number of joystick devices supported by the joystick
+ driver. If no driver is present, the function returns zero.
+
+ @comm Use <f joyGetPos> to determine whether a given
+ joystick is actually attached to the system. The <f joyGetPos> function returns
+ a JOYERR_UNPLUGGED error code if the specified joystick is not connected.
+
+ @xref joyGetDevCaps joyGetPos
+
+****************************************************************************/
+
+UINT WINAPI joyGetNumDevs(void)
+{
+ // Return 0 on error (Can't return JOYERR_NODRIVER
+ // since no way to distinguish error code from valid count.)
+
+ if (!hDrvJoy[0] && !JoyInit())
+ return 0;
+
+ return wNumDevs;
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joyGetPos | This function queries for the position and button
+ activity of a joystick device.
+
+ @parm UINT | wId | Identifies the joystick device to be queried.
+ This value is either JOYSTICKID1 or JOYSTICKID2.
+
+ @parm LPJOYINFO | lpInfo | Specifies a far pointer to a <t JOYINFO>
+ data structure. This structure is filled with information about the
+ position and button activity of the joystick device.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
+
+ @flag JOYERR_UNPLUGGED | The specified joystick is not connected to the
+ system.
+
+****************************************************************************/
+
+UINT WINAPI joyGetPos(UINT wId, LPJOYINFO lpInfo)
+{
+ V_WPOINTER(lpInfo, sizeof(JOYINFO), MMSYSERR_INVALPARAM);
+
+ if ((!hDrvJoy[0] && !JoyInit()) || (wId >= iJoyMax))
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ return joyMessage( hDrvJoy[wId], JDD_GETPOS, (DWORD)lpInfo, 0L );
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joyGetThreshold | This function queries the current
+ movement threshold of a joystick device.
+
+ @parm UINT | wId | Identifies the joystick device to be queried.
+ This value is either JOYSTICKID1 or JOYSTICKID2.
+
+ @parm UINT FAR* | lpwThreshold | Specifies a far pointer to a UINT variable
+ that is filled with the movement threshold value.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
+
+ @comm The movement threshold is the distance the joystick must be
+ moved before a WM_JOYMOVE message is sent to a window that has
+ captured the device. The threshold is initially zero.
+
+ @xref joySetThreshold
+
+****************************************************************************/
+
+UINT WINAPI joyGetThreshold(UINT wId, UINT FAR* lpwThreshold)
+{
+ V_WPOINTER(lpwThreshold, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+ if (!hDrvJoy[0] && !JoyInit())
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= iJoyMax)
+ return MMSYSERR_INVALPARAM;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ *lpwThreshold = (JoyCapture[wId].wThreshold);
+
+ return JOYERR_NOERROR;
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joyReleaseCapture | This function releases the capture
+ set by <f joySetCapture> on the specified joystick device.
+
+ @parm UINT | wId | Identifies the joystick device to be released.
+ This value is either JOYSTICKID1 or JOYSTICK2.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
+
+ @xref joySetCapture
+****************************************************************************/
+
+UINT WINAPI joyReleaseCapture(UINT wId)
+{
+ if (!hDrvJoy[0] && !JoyInit())
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= iJoyMax)
+ return MMSYSERR_INVALPARAM;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ if (JoyCapture[wId].hWnd == NULL)
+ return JOYERR_NOERROR;
+
+ KillTimer (NULL, JoyCapture[wId].wIDEvent);
+ JoyCapture[wId].wIDEvent = 0;
+ JoyCapture[wId].hWnd = NULL;
+
+ return JOYERR_NOERROR;
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joySetCapture | This function causes joystick messages to
+ be sent to the specified window.
+
+ @parm HWND | hWnd | Specifies a handle to the window to which messages
+ are to be sent.
+
+ @parm UINT | wId | Identifies the joystick device to be captured.
+ This value is either JOYSTICKID1 or JOYSTICKID2.
+
+ @parm UINT | wPeriod | Specifies the polling rate, in milliseconds.
+
+ @parm BOOL | bChanged | If this parameter is set to TRUE, then messages
+ are sent only when the position changes by a value greater than the
+ joystick movement threshold.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified window handle <p hWnd>
+ or joystick device ID <p wId> is invalid.
+
+ @flag JOYERR_NOCANDO | Cannot capture joystick input because some
+ required service (for example, a Windows timer) is unavailable.
+
+ @flag JOYERR_UNPLUGGED | The specified joystick is not connected to the
+ system.
+
+ @comm This function fails if the specified joystick device is
+ currently captured. You should call the <f joyReleaseCapture> function when
+ the joystick capture is no longer needed. If the window is destroyed,
+ the joystick will be released automatically.
+
+ @xref joyReleaseCapture joySetThreshold joyGetThreshold
+
+****************************************************************************/
+
+UINT WINAPI joySetCapture(HWND hwnd, UINT wId, UINT wPeriod, BOOL bChanged )
+{
+ JOYINFO joyinfo;
+ LPJOYINFO lpinfo = &joyinfo;
+ UINT w;
+ JOYCAPS JoyCaps;
+
+ if (!hwnd || !IsWindow(hwnd))
+ return JOYERR_PARMS;
+
+ if (!hDrvJoy[0] && !JoyInit())
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= iJoyMax)
+ return MMSYSERR_INVALPARAM;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ if (JoyCapture[wId].hWnd)
+ if (IsWindow(JoyCapture[wId].hWnd))
+ return JOYERR_NOCANDO;
+ else
+ joyReleaseCapture(wId);
+
+ if (joyGetDevCaps (wId, &JoyCaps, sizeof(JOYCAPS)) == 0)
+ wPeriod = min(JoyCaps.wPeriodMax,max(JoyCaps.wPeriodMin,wPeriod));
+ else
+ return JOYERR_NOCANDO;
+
+ // ensure that position info. is ok.
+
+ if (w = joyGetPos(wId, lpinfo))
+ return (w);
+
+ JoyCapture[wId].wPeriod = wPeriod;
+ JoyCapture[wId].bChanged = bChanged;
+
+ if (!(JoyCapture[wId].wIDEvent = SetTimer(NULL, 0, wPeriod, joyPollCallback)))
+ {
+ DOUT("MMSYSTEM: Couldn't allocate timer in joy.c\r\n");
+ return JOYERR_NOCANDO;
+ }
+
+ JoyCapture[wId].hWnd = hwnd;
+ return JOYERR_NOERROR;
+}
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | joySetThreshold | This function sets the movement threshold
+ of a joystick device.
+
+ @parm UINT | wId | Identifies the joystick device. This value is either
+ JOYSTICKID1 or JOYSTICKID2.
+
+ @parm UINT | wThreshold | Specifies the new movement threshold.
+
+ @rdesc Returns JOYERR_NOERROR if successful. Otherwise, returns one of the
+ following error codes:
+
+ @flag MMSYSERR_NODRIVER | The joystick driver is not present.
+
+ @flag JOYERR_PARMS | The specified joystick device ID <p wId> is invalid.
+
+ @comm The movement threshold is the distance the joystick must be
+ moved before a MM_JOYMOVE message is sent to a window that has
+ captured the device.
+
+ @xref joyGetThreshold joySetCapture
+
+****************************************************************************/
+
+UINT WINAPI joySetThreshold(UINT wId, UINT wThreshold)
+{
+ if (!hDrvJoy[0] && !JoyInit())
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= iJoyMax)
+ return MMSYSERR_INVALPARAM;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ JoyCapture[wId].wThreshold = wThreshold;
+ return JOYERR_NOERROR;
+}
+
+/****************************************************************************
+
+ @doc INTERNAL
+
+ @api UINT | joySetCalibration | This function sets the values used to
+ convert the values returned by the joystick drivers GetPos function
+ to the range specified in GetDevCaps.
+
+ @parm UINT | wId | Identifies the joystick device
+
+ @parm UINT FAR* | pwXbase | Specifies the base value for the X pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @parm UINT FAR* | pwXdelta | Specifies the delta value for the X pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @parm UINT FAR* | pwYbase | Specifies the base value for the Y pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @parm UINT FAR* | pwYdelta | Specifies the delta value for the Y pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @parm UINT FAR* | pwZbase | Specifies the base value for the Z pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @parm UINT FAR* | pwZdelta | Specifies the delta value for the Z pot. The
+ previous value will be copied back to the variable pointed to here.
+
+ @rdesc The return value is zero if the function was successful, otherwise
+ it is an error number.
+
+ @comm The base represents the lowest value the joystick driver returns,
+ whereas the delta represents the multiplier to use to convert
+ the actual value returned by the driver to the valid range
+ for the joystick API's.
+ i.e. If the driver returns a range of 43-345 for the X pot, and
+ the valid mmsystem API range is 0-65535, the base value will be
+ 43, and the delta will be 65535/(345-43)=217. Thus the base,
+ and delta convert 43-345 to a range of 0-65535 with the formula:
+ ((wXvalue-43)*217) , where wXvalue was given by the joystick driver.
+
+****************************************************************************/
+
+UINT WINAPI joySetCalibration( UINT wId,
+ UINT FAR* pwXbase,
+ UINT FAR* pwXdelta,
+ UINT FAR* pwYbase,
+ UINT FAR* pwYdelta,
+ UINT FAR* pwZbase,
+ UINT FAR* pwZdelta )
+{
+ JOYCALIBRATE oldCal,newCal;
+ UINT w;
+
+ if (!hDrvJoy[0] && !JoyInit())
+ return MMSYSERR_NODRIVER;
+
+ if (wId >= wNumDevs)
+ return JOYERR_PARMS;
+
+ newCal.wXbase = *pwXbase;
+ newCal.wXdelta = *pwXdelta;
+
+ newCal.wYbase = *pwYbase;
+ newCal.wYdelta = *pwYdelta;
+
+ newCal.wZbase = *pwZbase;
+ newCal.wZdelta = *pwZdelta;
+
+ w = joyMessage( hDrvJoy[wId], JDD_SETCALIBRATION, (DWORD)(LPSTR)&newCal,
+ (DWORD)(LPSTR)&oldCal );
+
+ *pwXbase = oldCal.wXbase;
+ *pwXdelta = oldCal.wXdelta;
+
+ *pwYbase = oldCal.wYbase;
+ *pwYdelta = oldCal.wYdelta;
+
+ *pwZbase = oldCal.wZbase;
+ *pwZdelta = oldCal.wZdelta;
+
+ return w;
+}
+
+/****************************************************************************
+
+ @doc INTERNAL
+
+ @api void | joyPollCallback | Function called for joystick
+ timer polling scheme initiated from SetCapture call.
+
+ @parm HWND | hWnd | Identifies the window associated with the timer
+ event.
+
+ @parm UINT | wMsg | Specifies the WM_TIMER message.
+
+ @parm UINT | wIDEvent | Specifies the timer's ID.
+
+ @parm DWORD | dwTime | Specifies the current system time.
+
+
+****************************************************************************/
+
+void CALLBACK joyPollCallback(HWND hWnd, UINT wMsg, UINT wIDEvent, DWORD dwTime)
+{
+ #define diff(w1,w2) (UINT)(w1 > w2 ? w1-w2 : w2-w1)
+
+ static JOYINFO oldInfo[2] = {{ 0, 0, 0, 0 },{ 0, 0, 0, 0 }};
+ JOYINFO Info;
+
+ UINT w ,fBtnMask;
+
+ if (wIDEvent == JoyCapture[0].wIDEvent)
+ wIDEvent = 0;
+ else if (wIDEvent == JoyCapture[1].wIDEvent)
+ wIDEvent = 1;
+
+#ifdef DEBUG
+ else
+ {
+ DOUT("MMSYSTEM: Invalid timer handle in joy.c\r\n");
+ KillTimer (NULL, wIDEvent);
+ }
+#endif
+
+
+ if (!JoyCapture[wIDEvent].hWnd || !IsWindow(JoyCapture[wIDEvent].hWnd))
+ joyReleaseCapture(wIDEvent);
+
+ if (!joyMessage( hDrvJoy[wIDEvent], JDD_GETPOS,
+ (DWORD)(LPJOYINFO)&Info, 0L ))
+ {
+
+ for (w=0,fBtnMask=1; w < 4; w++,fBtnMask <<=1)
+ {
+ if ((Info.wButtons ^ oldInfo[wIDEvent].wButtons) & fBtnMask)
+ {
+ PostMessage(
+ JoyCapture[wIDEvent].hWnd,
+ wIDEvent + ((Info.wButtons & fBtnMask) ?
+ MM_JOY1BUTTONDOWN : MM_JOY1BUTTONUP ),
+ (WPARAM)(Info.wButtons | fBtnMask << 8),
+ MAKELPARAM(Info.wXpos,Info.wYpos));
+ }
+ }
+
+ if (!JoyCapture[wIDEvent].bChanged ||
+ diff(Info.wXpos,oldInfo[wIDEvent].wXpos)>JoyCapture[wIDEvent].wThreshold ||
+ diff(Info.wYpos,oldInfo[wIDEvent].wYpos)>JoyCapture[wIDEvent].wThreshold)
+ {
+ PostMessage(
+ JoyCapture[wIDEvent].hWnd,
+ MM_JOY1MOVE+wIDEvent,
+ (WPARAM)(Info.wButtons),
+ MAKELPARAM(Info.wXpos,Info.wYpos));
+
+ }
+
+ else if (!JoyCapture[wIDEvent].bChanged ||
+ diff(Info.wZpos,oldInfo[wIDEvent].wZpos)>JoyCapture[wIDEvent].wThreshold)
+ {
+ PostMessage(
+ JoyCapture[wIDEvent].hWnd,
+ MM_JOY1ZMOVE+wIDEvent,
+ (WPARAM)Info.wButtons,
+ MAKELPARAM(Info.wZpos,0));
+ }
+
+ oldInfo[wIDEvent] = Info;
+ }
+ #undef diff
+}
diff --git a/private/mvdm/wow16/mmsystem/libentry.asm b/private/mvdm/wow16/mmsystem/libentry.asm
new file mode 100644
index 000000000..cfd06ac76
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/libentry.asm
@@ -0,0 +1,144 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; LIBENTRY.ASM
+;
+; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
+;
+; This module contains the entry point for MMsystem.dll
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ PMODE = 1
+
+ include cmacros.inc
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; extrns
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ externNP LibMain
+ externFP LocalInit
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Code segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+;-----------------------------------------------------------------------;
+;
+; Stuff needed to avoid the C runtime coming in, and init the windows
+; reserved parameter block at the base of DGROUP
+;
+sBegin Data
+assumes DS,Data
+
+ DD 0 ; So null pointers get 0
+maxRsrvPtrs = 5
+ DW maxRsrvPtrs
+usedRsrvPtrs = 0
+labelDP <PUBLIC,rsrvptrs>
+
+DefRsrvPtr MACRO name
+globalW name,0
+usedRsrvPtrs = usedRsrvPtrs + 1
+ENDM
+
+DefRsrvPtr pLocalHeap ; Local heap pointer
+DefRsrvPtr pAtomTable ; Atom table pointer
+DefRsrvPtr pStackTop ; top of stack
+DefRsrvPtr pStackMin ; minimum value of SP
+DefRsrvPtr pStackBot ; bottom of stack
+
+if maxRsrvPtrs-usedRsrvPtrs
+ DW maxRsrvPtrs-usedRsrvPtrs DUP (0)
+endif
+
+public __acrtused
+ __acrtused = 1
+
+sEnd Data
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,Data
+ assumes es,nothing
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Library entry point
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;--------------------------Private-Routine-----------------------------;
+;
+; LibEntry - called when DLL is loaded
+;
+; Entry:
+; CX = size of heap
+; DI = module handle
+; DS = automatic data segment
+; ES:SI = address of command line (not used)
+;
+; Returns:
+; AX = TRUE if success
+; Error Returns:
+; AX = FALSE if error (ie fail load process)
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; Calls:
+; None
+; History:
+;
+; 06-27-89 -by- Todd Laney [ToddLa]
+; Created.
+;-----------------------------------------------------------------------;
+
+cProc LibEntry,<FAR,PUBLIC,NODATA>,<>
+cBegin
+ ;
+ ; Push frame for LibMain (hModule,cbHeap,lpszCmdLine)
+ ;
+ push di
+ push cx
+ push es
+ push si
+
+ ;
+ ; Init the local heap (if one is declared in the .def file)
+ ;
+ jcxz no_heap
+
+ xor ax,ax
+ cCall LocalInit,<ax,ax,cx>
+
+no_heap:
+ cCall LibMain
+cEnd
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WEP, <FAR, PUBLIC, PASCAL>, <>
+; ParmW fSystemExit
+cBegin nogen
+ mov ax, 1
+ retf 2
+cEnd nogen
+
+ sEnd CodeSeg
+
+ end LibEntry
diff --git a/private/mvdm/wow16/mmsystem/makefile b/private/mvdm/wow16/mmsystem/makefile
new file mode 100644
index 000000000..86474dfe8
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/makefile
@@ -0,0 +1,261 @@
+#
+# constructs mmsystem DLL
+#
+# Defines:
+# DEBUG - Enable debug code
+# STRICT - Build a version with STRICT enabled
+#
+
+NAME =mmsystem
+EXT =dll
+OBJFIRST=$Zlibentry.obj
+OBJ1 =$Zinit.obj $Ztime.obj $Zjoy.obj $Zsound.obj $Zwave.obj
+OBJ2 =$Zmidi.obj $Zmci.obj $Zmcisys.obj $Zmciparse.obj $Zdrvproc.obj $ZPlaywav.obj
+OBJ3 =$Zmmwnd.obj $Zauxout.obj $Zdebug.obj $Zdrvr31.obj $Ztaska.obj $Zthunks.obj
+OBJ4 =$Ztask.obj $Zbwinexec.obj $Zcomm.obj $Zstack.obj $Zheap.obj $Zdpmipage.obj
+OBJ5 =$Zmmio.obj $Zmmioriff.obj $Zhmemcpy.obj $Zdosa.obj $Zisr.obj $Zmixer.obj
+
+OBJ =$(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(OBJ5) $(OBJD)
+LIBS =..\lib\libw ..\lib\mdllcew
+INCS = -I. -I..\inc -I..\..\inc
+
+OPT = -Oxws
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+#
+# build a retail build
+#
+!if "$(NTDEBUG)" == "" || "$(NTDEBUG)" == "retail" && "$(NTDEBUG)" != "ntsdnodbg"
+
+CLOPT =-I..\inc -I.\rinc -I..\..\inc
+MASMOPT =-I..\inc -I..\..\inc
+LINKOPT =
+RC =rc16 -i..\inc -i.\rinc
+OBJD =
+Z = .\retail^\
+MMDEBUG =
+
+#
+# build a full debug build
+#
+!else
+
+CDEBUG =-Zd -Odi
+ADEBUG =-Zd
+LDEBUG =/LI
+
+CLOPT =$(CDEBUG) -DDEBUG -I..\inc -I.\rinc -I..\..\inc
+MASMOPT =$(ADEBUG) -DDEBUG -I..\inc -I..\..\inc
+LINKOPT =$(LDEBUG)
+RC =rc16 -DDEBUG -i..\inc -i.\rinc
+OBJD =$Zmmsex.obj
+Z = .\debug^\
+MMDEBUG = DEBUG=1
+
+!endif
+
+
+!if "$(STRICT)" == "YES"
+TYPES =-DSTRICT
+!else
+TYPES =
+!endif
+
+#
+# NOTE
+#
+# this code is compiled *without* windows prolog/epilog (no -Gw)
+# thus all exported routines, must have _loadds
+#
+
+CC = cl16 -c -Alnw -G2s -Zp -W3 $(CLOPT) $(OPT) $(TYPES)
+ASM = masm -Mx -t -D?QUIET $(MASMOPT)
+LINK = link16 /NOD/NOE/MAP/ALIGN:16 $(LINKOPT)
+
+.c{$Z}.obj:
+ $(CC) -Fo$*.obj $(@B).c
+
+.asm{$Z}.obj:
+ $(ASM) -DSEGNAME=_TEXT $(@B).asm, $*.obj;
+
+
+###################################
+
+all: $(NAME).$(EXT) $(NAME).sym mmtask.tsk
+
+$(NAME).$(EXT): $(OBJFIRST) $(OBJ) $(NAME).def $(NAME).res mmtask.tsk
+ @$(LINK) @<<
+$(OBJFIRST) +
+$(OBJ1)+
+$(OBJ2)+
+$(OBJ3)+
+$(OBJ4)+
+$(OBJ5)+
+$(OBJD),
+$(NAME).$(EXT),
+$(NAME),
+$(LIBS),
+$(NAME).def
+<<
+ @$(RC) -t $(NAME).res $(NAME).$(EXT)
+ @mapsym /n $*.map
+ -binplace mmsystem.dll mmsystem.map mmsystem.sym mmtask.tsk mmtask.map mmtask.sym
+
+RES_DIR =.\messages\usa
+
+$(NAME).rc: $(RES_DIR)\$(NAME).rc
+ @copy $(RES_DIR)\$(NAME).rc
+
+mci.rc: $(RES_DIR)\$$(@F)
+ @copy $(RES_DIR)\$@
+
+$(NAME).rcv: $(RES_DIR)\$$(@F) ..\inc\common.ver
+ @copy $(RES_DIR)\$@
+ @touch $@
+
+$(NAME).res: $(NAME).rc mci.rc ..\inc\$(NAME).h $(NAME).rcv mmsysi.h ..\inc\mmddk.h
+ @$(RC) -r $(NAME).rc
+
+############## mmtask #############
+
+mmtask.tsk: mmtask\mmtask.asm mmtask\makefile mmtask\mmtask.def mmtask\mmtask.h
+ @cd mmtask
+ @$(MAKE) $(MMDEBUG)
+ @cd ..
+
+############## includes ##############
+
+#..\inc\$(NAME).h ..\inc\$(NAME).inc ..\inc\mmddk.h ..\inc\mmddk.inc ..\inc\mci.rc : $$(@F)
+# @copy $(@F) $@
+
+############## clean ##############
+
+clean: cleanup all
+
+cleanup:
+ -@del $(NAME).$(EXT)
+ -@del $(NAME).res
+ -@del *.sym
+ -@del *.map
+ -@del *.lib
+ -@del $Z*.cod
+ -@del $Z*.obj
+ -@del *.rcv
+ -@del *.rc
+ -@del *.tsk
+ @cd mmtask
+ @$(MAKE) clean
+ @cd ..
+
+########### segmentation ##########
+#
+# INIT is the init/exit time segment
+# FIXED is the interupt time fixed segment
+# _TEXT is the non-resident "random" segment (was NRES)
+
+SEGC = $(CC) -NT CSEG -Fo$*.obj $(@B).c
+SEGA = $(ASM) -DSEGNAME=CSEG $(@B).asm, $*.obj;
+
+$Zdebug.obj : ; $(SEGA:CSEG=FIX)
+$Zinit.obj : ; $(SEGC:CSEG=INIT)
+$Zlibentry.obj : ; $(SEGA:CSEG=INIT)
+$Zmmwnd.obj : ; $(SEGC:CSEG=INIT)
+$Zplaywav.obj : ; $(SEGC:CSEG=WAVE)
+$Zsound.obj : ; $(SEGC:CSEG=WAVE)
+$Zwave.obj : ; $(SEGC:CSEG=WAVE)
+$Zmidi.obj : ; $(SEGC:CSEG=MIDI)
+$Zdpmipage.obj : ; $(SEGA:CSEG=_TEXT)
+$Zmci.obj : ; $(SEGC:CSEG=MCI)
+$Zmcisys.obj : ; $(SEGC:CSEG=MCI)
+$Zmciparse.obj : ; $(SEGC:CSEG=MCI)
+$Zdosa.obj : ; $(SEGA:CSEG=MCI)
+$Zheap.obj : ; $(SEGA:CSEG=MCI)
+$Ztask.obj : ; $(SEGC:CSEG=_TEXT)
+$Zdrvproc.obj : ; $(SEGC:CSEG=_TEXT)
+$Ztaska.obj : ; $(SEGA:CSEG=_TEXT)
+$Zjoy.obj : ; $(SEGC:CSEG=RARE)
+$Ztime.obj : ; $(SEGC:CSEG=FIX)
+$Zbwinexec.obj : ; $(SEGA:CSEG=_TEXT)
+$Zauxout.obj : ; $(SEGC:CSEG=RARE)
+$Zdrvr31.obj : ; $(SEGA:CSEG=_TEXT)
+$Zcomm.obj : ; $(SEGA:CSEG=FIX)
+$Zstack.obj : ; $(SEGA:CSEG=FIX)
+$Zhmemcpy.obj : ; $(SEGA:CSEG=MMIO)
+$Zmmio.obj : ; $(SEGC:CSEG=MMIO)
+$Zmmioriff.obj : ; $(SEGC:CSEG=MMIO)
+$Zmmsex.obj : ; $(SEGC:CSEG=RARE)
+$Zmixer.obj : ; $(SEGC:CSEG=MIXER)
+
+############# depend ##############
+
+depend:
+ mv makefile makefile.old
+ sed "/^# START Dependencies/,/^# END Dependencies/D" makefile.old > makefile
+ -del makefile.old
+ echo # START Dependencies >> makefile
+ includes -l *.c *.asm >> makefile
+ echo # END Dependencies >> makefile
+
+##################################################################
+# START Dependencies
+$Zauxout.obj: auxout.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zdpmipage.obj: dpmipage.asm int31.inc
+
+$Zcomm.obj: comm.asm
+
+$Zbwinexec.obj: bwinexec.asm
+
+$Zdosa.obj: dosa.asm
+
+$Zinit.obj: init.c drvr.h ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zhmemcpy.obj: hmemcpy.asm
+
+$Zheap.obj: heap.asm
+
+$Zjoy.obj: joy.c drvr.h ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zmci.obj: mci.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zlibentry.obj: libentry.asm
+
+$Zmciparse.obj: mciparse.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zmcisys.obj: mcisys.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zmidi.obj: midi.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zmmio.obj: mmio.c mmioi.h ..\inc\mmsystem.h mmsysi.h
+
+$Zmmioriff.obj: mmioriff.c mmioi.h ..\inc\mmsystem.h
+
+$Zmmwnd.obj: mmwnd.c mmsysi.h ..\inc\mmsystem.h
+
+$Zplaywav.obj: playwav.c mmsysi.h ..\inc\mmsystem.h playwav.h
+
+$Zsound.obj: sound.c mmsysi.h ..\inc\mmsystem.h playwav.h
+
+$Ztask.obj: task.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h mmtask\mmtask.h
+
+$Ztaska.obj: taska.asm ..\inc\mmsystem.inc
+
+$Zstack.obj: stack.asm ..\inc\mmddk.inc ..\inc\mmsystem.inc
+
+$Zisr.obj: isr.asm ..\inc\mmddk.inc ..\inc\mmsystem.inc
+
+$Ztime.obj: time.c drvr.h ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zwave.obj: wave.c ..\inc\mmddk.h mmsysi.h ..\inc\mmsystem.h
+
+$Zdebug.obj: debug.asm ..\inc\mmddk.inc ..\inc\mmsystem.inc
+
+$Zdrvproc.obj: drvproc.c mmsysi.h ..\inc\mmsystem.h mmioi.h
+
+# END Dependencies
diff --git a/private/mvdm/wow16/mmsystem/mci.c b/private/mvdm/wow16/mmsystem/mci.c
new file mode 100644
index 000000000..af61d4838
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mci.c
@@ -0,0 +1,2232 @@
+/******************************************************************************
+* Module Name: mci.c
+*
+* Media Control Architecture Driver Interface
+*
+* Contents: MCI external message API's mciSendString and mciSendCommand
+* Author: DLL (DavidLe)
+* Created: 2/13/90
+*
+* Copyright (c) 1990 Microsoft Corporation
+*
+\******************************************************************************/
+#ifdef DEBUG
+#ifndef DEBUG_RETAIL
+#define DEBUG_RETAIL
+#endif
+#endif
+
+#include <windows.h>
+#include <string.h>
+
+#define MMNOSEQ
+#define MMNOJOY
+#define MMNOWAVE
+#define MMNOMIDI
+#include "mmsystem.h"
+
+#define NOMIDIDEV
+#define NOWAVEDEV
+#define NOTIMERDEV
+#define NOJOYDEV
+#define NOSEQDEV
+#define NOTASKDEV
+#include "mmddk.h"
+
+#include "mmsysi.h"
+#include "thunks.h"
+
+#ifndef STATICFN
+#define STATICFN
+#endif
+
+
+/* -------------------------------------------------------------------------
+** Thunking stuff
+** -------------------------------------------------------------------------
+*/
+LPMCIMESSAGE PASCAL mci32Message;
+DWORD WINAPI mciSendCommand16(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+
+
+//
+// Define the init code for this file.
+//
+#pragma alloc_text( INIT, MCITerminate )
+
+#ifdef DEBUG_RETAIL
+int DebugmciSendCommand;
+#endif
+
+#ifdef DEBUG
+void PASCAL NEAR mciCheckLocks(void);
+#endif
+
+STATICFN UINT PASCAL NEAR
+mciConvertReturnValue(
+ UINT wType,
+ UINT wErr,
+ UINT wDeviceID,
+ LPDWORD dwParams,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength
+ );
+
+STATICFN DWORD NEAR PASCAL
+mciSendStringInternal(
+ LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength,
+ HWND hwndCallback,
+ LPMCI_SYSTEM_MESSAGE lpMessage
+ );
+
+STATICFN DWORD NEAR PASCAL
+mciSendSystemString(
+ LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength
+ );
+
+extern int FAR PASCAL
+mciBreakKeyYieldProc(
+ UINT wDeviceID,
+ DWORD dwYieldData
+ );
+
+
+// From dosa.asm
+extern int FAR PASCAL DosChangeDir(LPCSTR lpszPath);
+extern WORD FAR PASCAL DosGetCurrentDrive(void);
+extern BOOL FAR PASCAL DosSetCurrentDrive(WORD wDrive);
+extern WORD FAR PASCAL DosGetCurrentDir(WORD wCurdrive, LPSTR lpszBuf);
+
+#define MAX_PATHNAME 144
+
+// This macro defines the list of messages for which mciSendString
+// will not try to auto-open
+#define MCI_CANNOT_AUTO_OPEN(wMessage) \
+ (wMessage == MCI_OPEN || wMessage == MCI_SYSINFO \
+ || wMessage == MCI_SOUND || wMessage == MCI_CLOSE \
+ || wMessage == MCI_BREAK)
+
+// This macro devices the list of message which do not require an open
+// device. It is a subset of MCI_CANNOT_AUTO_OPEN
+#define MCI_DO_NOT_NEED_OPEN(wMessage) \
+ (wMessage == MCI_OPEN || wMessage == MCI_SOUND || wMessage == MCI_SYSINFO)
+
+// Strings used in mciAutoOpenDevice
+ SZCODE szOpen[] = "open";
+static SZCODE szClose[] = "close";
+static SZCODE szNotify[] = "notify";
+static SZCODE szWait[] = "wait";
+static SZCODE szCmdFormat[] = "%ls %ls";
+static SZCODE szLongFormat[] = "%ld";
+static SZCODE szRectFormat[] = "%d %d %d %d";
+extern char far szSystemDefault[];
+
+// Special device name
+static SZCODE szNew[] = "new";
+
+/******************************Public*Routine******************************\
+* mciAppExit
+*
+* Notify the 32 bit code that a 16 bit app has died.
+*
+* History:
+* dd-mm-94 - StephenE - Created
+*
+\**************************************************************************/
+DWORD
+mciAppExit(
+ HTASK hTask
+ )
+{
+ return mciMessage( THUNK_APP_EXIT, (DWORD)hTask,
+ 0L, 0L, 0L );
+}
+
+
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api void | MciNotify | called by mmWndProc when it recives a
+ * MM_MCINOTIFY message
+ * @rdesc None.
+ *
+ ****************************************************************************/
+
+void FAR PASCAL
+MciNotify(
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ //
+ // wParam is the notify status
+ // lParam is the MCI device id
+ //
+ if (MCI_VALID_DEVICE_ID(LOWORD(lParam)) &&
+ !(MCI_lpDeviceList[LOWORD(lParam)]->dwMCIFlags & MCINODE_ISCLOSING)) {
+ MCI_lpDeviceList[LOWORD(lParam)]->dwMCIFlags |= MCINODE_ISAUTOCLOSING;
+ mciCloseDevice (LOWORD(lParam), 0L, NULL, TRUE);
+ }
+}
+
+
+
+STATICFN void NEAR PASCAL
+HandleNotify(
+ UINT wErr,
+ UINT wDeviceID,
+ DWORD dwFlags,
+ DWORD dwParam2
+ )
+{
+ LPMCI_GENERIC_PARMS lpGeneric = (LPMCI_GENERIC_PARMS)dwParam2;
+ HWND hwndCallback;
+ if (wErr == 0 && dwFlags & MCI_NOTIFY && lpGeneric != NULL &&
+ (hwndCallback = (HWND)(UINT)lpGeneric->dwCallback) != NULL)
+
+ mciDriverNotify (hwndCallback, wDeviceID, MCI_NOTIFY_SUCCESSFUL);
+}
+
+#ifdef DEBUG_RETAIL
+//
+// Dump the string form of an MCI command
+//
+UINT PASCAL NEAR
+mciDebugOut(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwFlags,
+ DWORD dwParam2,
+ LPMCI_DEVICE_NODE nodeWorking
+ )
+{
+ LPSTR lpCommand, lpFirstParameter, lpPrevious, lszDebugOut;
+ char strTemp[256];
+ UINT wID, wOffset, wOffsetFirstParameter, wReturnType;
+ DWORD dwValue;
+ DWORD dwMask;
+ UINT wTable;
+
+// Find the command table for the given command message ID
+ lpCommand = FindCommandItem( wDeviceID, NULL,
+ (LPSTR)MAKELONG (wMessage, 0),
+ NULL, &wTable);
+
+ if (lpCommand == NULL)
+ {
+ if (wMessage != MCI_OPEN_DRIVER && wMessage != MCI_CLOSE_DRIVER)
+ ROUT ("MMSYSTEM: mciDebugOut: Command table not found");
+ return 0;
+ }
+
+ lszDebugOut = mciAlloc(512);
+ if (!lszDebugOut) {
+ ROUT("MMSYSTEM: Not enough memory to display command");
+ return 0;
+ }
+
+// Dump the command name
+ wsprintf(lszDebugOut, "MMSYSTEM: MCI command: \"%ls", lpCommand);
+
+// Dump the device name
+ if (wDeviceID == MCI_ALL_DEVICE_ID)
+ {
+ lstrcat(lszDebugOut, " all");
+ }
+ else if (nodeWorking != NULL)
+ {
+ if (nodeWorking->dwMCIOpenFlags & MCI_OPEN_ELEMENT_ID)
+ {
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " Element ID:0x%lx", nodeWorking->dwElementID);
+ } else if (nodeWorking->lpstrName != NULL)
+ {
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", nodeWorking->lpstrName);
+ }
+ }
+
+// Skip past command entry
+ lpCommand += mciEatCommandEntry (lpCommand, NULL, NULL);
+
+// Get the next entry
+ lpFirstParameter = lpCommand;
+
+// Skip past the DWORD return value
+ wOffsetFirstParameter = 4;
+
+ lpCommand += mciEatCommandEntry (lpCommand, &dwValue, &wID);
+
+// If it is a return value, skip it
+ if (wID == MCI_RETURN)
+ {
+ wReturnType = (UINT)dwValue;
+ lpFirstParameter = lpCommand;
+ wOffsetFirstParameter += mciGetParamSize (dwValue, wID);
+ lpCommand += mciEatCommandEntry (lpCommand, &dwValue, &wID);
+ }
+ else {
+ wReturnType = (UINT)0;
+ }
+
+// Dump device name parameter to OPEN
+ if (wMessage == MCI_OPEN)
+ {
+ LPCSTR lpstrDeviceType =
+ ((LPMCI_OPEN_PARMS)dwParam2)->lpstrDeviceType;
+ LPCSTR lpstrElementName =
+ ((LPMCI_OPEN_PARMS)dwParam2)->lpstrElementName;
+
+// Tack on device type
+ if (dwFlags & MCI_OPEN_TYPE_ID)
+ {
+ LPMCI_OPEN_PARMS lpOpen = (LPMCI_OPEN_PARMS)dwParam2;
+ DWORD dwOld = (DWORD)lpOpen->lpstrDeviceType;
+ if (mciExtractTypeFromID ((LPMCI_OPEN_PARMS)dwParam2) != 0)
+ strTemp[0] = '\0';
+ lstrcpy (strTemp, lpOpen->lpstrDeviceType);
+ mciFree ((LPSTR)lpOpen->lpstrDeviceType);
+ lpOpen->lpstrDeviceType = (LPSTR)dwOld;
+ } else if (lpstrDeviceType != NULL)
+ lstrcpy (strTemp, lpstrDeviceType);
+ else
+ strTemp[0] = '\0';
+
+ if (dwFlags & MCI_OPEN_ELEMENT_ID)
+ {
+// Tack on element ID
+ lstrcat (strTemp, " Element ID:");
+ wsprintf (strTemp + lstrlen (strTemp), szLongFormat,
+ LOWORD ((DWORD)lpstrDeviceType));
+ } else
+ {
+// Add separator if both type name and element name are present
+ if (lpstrDeviceType != 0 && lpstrElementName != 0)
+ lstrcat (strTemp, "!");
+ if (lpstrElementName != 0 && dwFlags & MCI_OPEN_ELEMENT)
+ lstrcat (strTemp, lpstrElementName);
+ }
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", (LPSTR)strTemp);
+ }
+
+
+// Walk through each flag
+ for (dwMask = 1; dwMask;)
+ {
+// Is this bit set?
+ if ((dwFlags & dwMask) != 0 && !
+// The MCI_OPEN_TYPE and MCI_OPEN_ELEMENT flags are taken care of
+// above
+ (wMessage == MCI_OPEN && (dwMask == MCI_OPEN_TYPE
+ || dwMask == MCI_OPEN_ELEMENT)))
+ {
+ lpPrevious = lpCommand = lpFirstParameter;
+ wOffset = 0;
+ lpCommand += mciEatCommandEntry (lpCommand, &dwValue, &wID);
+
+// What parameter uses this bit?
+ while (wID != MCI_END_COMMAND && dwValue != dwMask)
+ {
+ wOffset += mciGetParamSize (dwValue, wID);
+
+ if (wID == MCI_CONSTANT)
+ while (wID != MCI_END_CONSTANT)
+ lpCommand += mciEatCommandEntry (lpCommand,
+ NULL, &wID);
+
+ lpPrevious = lpCommand;
+ lpCommand += mciEatCommandEntry (lpCommand, &dwValue, &wID);
+ }
+
+ if (wID != MCI_END_COMMAND)
+ {
+// Found the parameter which matches this flag bit
+// Print the parameter name
+ if (*lpPrevious)
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", lpPrevious);
+
+// Print any argument
+ switch (wID)
+ {
+ case MCI_STRING:
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", *(LPSTR FAR *)((LPSTR)dwParam2 + wOffset + wOffsetFirstParameter));
+ break;
+ case MCI_CONSTANT:
+ {
+ DWORD dwConst = *(LPDWORD)((LPSTR)dwParam2 + wOffset +
+ wOffsetFirstParameter);
+ UINT wLen;
+ BOOL bFound;
+
+ for (bFound = FALSE; wID != MCI_END_CONSTANT;)
+ {
+ wLen = mciEatCommandEntry (lpCommand,
+ &dwValue, &wID);
+
+ if (dwValue == dwConst)
+ {
+ bFound = TRUE;
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", lpCommand);
+ }
+
+ lpCommand += wLen;
+ }
+ if (bFound)
+ break;
+// FALL THROUGH
+ }
+ case MCI_INTEGER:
+ wsprintf ((LPSTR)strTemp, szLongFormat,
+ *(LPDWORD)((LPSTR)dwParam2 + wOffset +
+ wOffsetFirstParameter));
+ wsprintf(lszDebugOut + lstrlen(lszDebugOut), " %ls", (LPSTR)strTemp);
+ break;
+ }
+ }
+ }
+// Go the the next flag
+ dwMask <<= 1;
+ }
+ mciUnlockCommandTable (wTable);
+ lstrcat(lszDebugOut, "\"");
+ ROUTS(lszDebugOut);
+ mciFree(lszDebugOut);
+ return wReturnType;
+}
+#endif
+
+STATICFN DWORD PASCAL NEAR
+mciBreak(
+ UINT wDeviceID,
+ DWORD dwFlags,
+ LPMCI_BREAK_PARMS lpBreakon
+ )
+{
+ HWND hwnd;
+
+ if (dwFlags & MCI_BREAK_KEY)
+ {
+ if (dwFlags & MCI_BREAK_OFF)
+ return MCIERR_FLAGS_NOT_COMPATIBLE;
+
+ if (dwFlags & MCI_BREAK_HWND)
+ hwnd = lpBreakon->hwndBreak;
+ else
+ hwnd = 0;
+
+ return mciSetBreakKey (wDeviceID, lpBreakon->nVirtKey,
+ hwnd)
+ ? 0 : MMSYSERR_INVALPARAM;
+
+ } else if (dwFlags & MCI_BREAK_OFF) {
+
+ mciSetYieldProc(wDeviceID, NULL, 0);
+ return 0;
+
+ } else
+ return MCIERR_MISSING_PARAMETER;
+}
+
+// Close the indicated device by sending a message inter-task
+STATICFN DWORD PASCAL NEAR
+mciAutoCloseDevice(
+ LPCSTR lpstrDevice
+ )
+{
+ LPSTR lpstrCommand;
+ DWORD dwRet;
+
+ if ((lpstrCommand =
+ mciAlloc (sizeof (szClose) + 1 +
+ lstrlen (lpstrDevice))) == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+ wsprintf(lpstrCommand, szCmdFormat, (LPCSTR)szClose, lpstrDevice);
+
+ dwRet = mciSendSystemString (lpstrCommand, NULL, 0);
+
+ mciFree (lpstrCommand);
+
+ return dwRet;
+}
+
+//
+// Process a single MCI command
+//
+// Called by mciSendCommandInternal
+//
+STATICFN DWORD PASCAL NEAR
+mciSendSingleCommand(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwParam1,
+ DWORD dwParam2,
+ LPMCI_DEVICE_NODE nodeWorking,
+ BOOL bTaskSwitch,
+ LPMCI_INTERNAL_OPEN_INFO lpOpenInfo
+ )
+{
+ DWORD dwRet;
+#ifdef DEBUG_RETAIL
+ UINT wReturnType;
+ DWORD dwTime;
+#endif
+
+#ifdef DEBUG_RETAIL
+ if (DebugmciSendCommand)
+ wReturnType =
+ mciDebugOut (wDeviceID, wMessage, dwParam1, dwParam2,
+ nodeWorking);
+#endif
+
+ switch (wMessage)
+ {
+ case MCI_OPEN:
+ dwRet = mciOpenDevice (dwParam1,
+ (LPMCI_OPEN_PARMS)dwParam2, lpOpenInfo);
+ break;
+
+ case MCI_CLOSE:
+// If this device was auto opened send the command via a task switch
+ if (bTaskSwitch)
+ {
+ if (dwParam1 & MCI_NOTIFY)
+ return MCIERR_NOTIFY_ON_AUTO_OPEN;
+
+ dwRet = mciAutoCloseDevice (nodeWorking->lpstrName);
+ } else
+ dwRet =
+ mciCloseDevice (wDeviceID,
+ dwParam1,
+ (LPMCI_GENERIC_PARMS)dwParam2, TRUE);
+ break;
+
+ case MCI_SYSINFO:
+ dwRet = mciSysinfo (wDeviceID, dwParam1,
+ (LPMCI_SYSINFO_PARMS)dwParam2);
+ HandleNotify ((UINT)dwRet, 0, dwParam1, dwParam2);
+ break;
+
+ case MCI_BREAK:
+ dwRet = mciBreak (wDeviceID, dwParam1,
+ (LPMCI_BREAK_PARMS)dwParam2);
+ HandleNotify ((UINT)dwRet, wDeviceID, dwParam1, dwParam2);
+ break;
+
+ case MCI_SOUND:
+ {
+ dwRet =
+ sndPlaySound (MCI_SOUND_NAME & dwParam1 ?
+ ((LPMCI_SOUND_PARMS)dwParam2)->lpstrSoundName : szSystemDefault,
+ dwParam1 & MCI_WAIT ?
+ SND_SYNC : SND_ASYNC)
+ ? 0 : MCIERR_HARDWARE;
+ HandleNotify ((UINT)dwRet, wDeviceID, dwParam1, dwParam2);
+ break;
+ }
+ default:
+#ifdef DEBUG_RETAIL
+ if (DebugmciSendCommand)
+ {
+ dwTime = timeGetTime();
+ }
+#endif
+// Initialize GetAsyncKeyState for break key
+ if (dwParam1 & MCI_WAIT &&
+ nodeWorking->fpYieldProc == mciBreakKeyYieldProc)
+ GetAsyncKeyState (LOWORD(nodeWorking->dwYieldData));
+
+ dwRet = (DWORD)SendDriverMessage(nodeWorking->hDrvDriver, wMessage,
+ (LPARAM)dwParam1, (LPARAM)dwParam2);
+#ifdef DEBUG_RETAIL
+ if (DebugmciSendCommand)
+ {
+ dwTime = timeGetTime() - dwTime;
+ }
+#endif
+ break;
+ } // switch
+
+#ifdef DEBUG_RETAIL
+ if (DebugmciSendCommand)
+ {
+ if (dwRet & MCI_INTEGER_RETURNED) {
+ wReturnType = MCI_INTEGER;
+ }
+
+
+ switch (wReturnType)
+ {
+ case MCI_INTEGER:
+ {
+ char strTemp[50];
+
+ if (wMessage == MCI_OPEN) {
+
+ mciConvertReturnValue( wReturnType, HIWORD(dwRet),
+ wDeviceID, (LPDWORD)dwParam2,
+ strTemp, sizeof(strTemp));
+ }
+ else {
+ mciConvertReturnValue( wReturnType, HIWORD(dwRet),
+ wDeviceID, (LPDWORD)dwParam2,
+ strTemp, sizeof(strTemp));
+ }
+
+ RPRINTF2( "MMSYSTEM: time: %lums returns: \"%ls\"",
+ dwTime, (LPSTR)strTemp);
+ break;
+ }
+ case MCI_STRING:
+ RPRINTF2( "MMSYSTEM: time: %lums returns: \"%ls\"",
+ dwTime, (LPSTR)*(((LPDWORD)dwParam2) + 1));
+ break;
+ }
+ }
+#endif
+
+ return dwRet;
+}
+
+// Internal version of mciSendCommand. Differs ONLY in that the return
+// value is a DWORD where the high word has meaning only for mciSendString
+
+STATICFN DWORD NEAR PASCAL
+mciSendCommandInternal(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwParam1,
+ DWORD dwParam2,
+ LPMCI_INTERNAL_OPEN_INFO lpOpenInfo
+ )
+{
+ DWORD dwRetVal;
+ LPMCI_DEVICE_NODE nodeWorking = NULL;
+ BOOL bWalkAll;
+ BOOL bTaskSwitch;
+ DWORD dwAllError = 0;
+ HTASK hCurrentTask;
+
+ hCurrentTask = GetCurrentTask();
+
+// If the device is "all" and the message is *not*
+// "sysinfo" then we must walk all devices
+ if (wDeviceID == MCI_ALL_DEVICE_ID && wMessage != MCI_SYSINFO && wMessage != MCI_SOUND)
+ {
+ if (wMessage == MCI_OPEN)
+ {
+ dwRetVal = MCIERR_CANNOT_USE_ALL;
+ goto exitfn;
+ }
+
+ bWalkAll = TRUE;
+
+// Start at device #1
+ wDeviceID = 1;
+ } else
+ bWalkAll = FALSE;
+
+// Walk through all devices if bWalkAll or just one device if !bWalkAll
+ do
+ {
+// Initialize
+ dwRetVal = 0;
+ bTaskSwitch = FALSE;
+
+// Validate the device ID if single device
+ if (!bWalkAll)
+ {
+ if (!MCI_DO_NOT_NEED_OPEN(wMessage))
+ {
+ if (!MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ dwRetVal = MCIERR_INVALID_DEVICE_ID;
+ goto exitfn;
+ }
+ nodeWorking = MCI_lpDeviceList[wDeviceID];
+ }
+ } else if (wMessage != MCI_SYSINFO)
+ nodeWorking = MCI_lpDeviceList[wDeviceID];
+
+// Skip if walking the device list and the
+// device is not part of the current task
+
+ if (bWalkAll)
+ {
+ if (nodeWorking == NULL ||
+ nodeWorking->hOpeningTask != hCurrentTask)
+ goto no_send;
+ }
+// If the device is in the process of closing and the message
+// is not MCI_CLOSE_DRIVER then return an error
+ if (nodeWorking != NULL &&
+ (nodeWorking->dwMCIFlags & MCINODE_ISCLOSING) &&
+ wMessage != MCI_CLOSE_DRIVER)
+ {
+ dwRetVal = MCIERR_DEVICE_LOCKED;
+ goto exitfn;
+ }
+
+// If this message is being sent from the wrong task (the device was auto-
+// opened) fail all but the MCI_CLOSE message which gets sent inter-task
+ if (nodeWorking != NULL &&
+ nodeWorking->hCreatorTask != hCurrentTask)
+ if (wMessage != MCI_CLOSE)
+ return MCIERR_ILLEGAL_FOR_AUTO_OPEN;
+ else
+ {
+// Don't even allow close from mciSendCommand if auto-open device has a
+// pending close
+ if (nodeWorking->dwMCIFlags & MCINODE_ISAUTOCLOSING)
+ {
+// But at least give the close a chance to take place
+//!! Yield();
+ return MCIERR_DEVICE_LOCKED;
+ } else
+ bTaskSwitch = TRUE;
+ }
+
+ dwRetVal = mciSendSingleCommand (wDeviceID, wMessage, dwParam1,
+ dwParam2, nodeWorking, bTaskSwitch,
+ lpOpenInfo);
+no_send:
+
+// If we are processing multiple devices
+ if (bWalkAll)
+ {
+// If there was an error for this device
+ if (dwRetVal != 0)
+// If this is not the first error
+ if (dwAllError != 0)
+ dwAllError = MCIERR_MULTIPLE;
+// Just one error so far
+ else
+ dwAllError = dwRetVal;
+ }
+ } while (bWalkAll && ++wDeviceID < MCI_wNextDeviceID);
+
+exitfn:
+// Return the accumulated error if multiple devices or just the single error
+ return bWalkAll ? dwAllError : dwRetVal;
+}
+
+
+/*
+ * @doc EXTERNAL MCI
+ *
+ * @api DWORD | mciSendCommand | This function sends a command message to
+ * the specified MCI device.
+ *
+ * @parm UINT | wDeviceID | Specifies the device ID of the MCI device to
+ * receive the command. This parameter is
+ * not used with the <m MCI_OPEN> command.
+ *
+ * @parm UINT | wMessage | Specifies the command message.
+ *
+ * @parm DWORD | dwParam1 | Specifies flags for the command.
+ *
+ * @parm DWORD | dwParam2 | Specifies a pointer to a parameter block
+ * for the command.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * error information. The low-order word
+ * of the returned DWORD is the error return value. If the error is
+ * device-specific, the high-order word contains the driver ID; otherwise
+ * the high-order word is zero.
+ *
+ * To get a textual description of <f mciSendCommand> return values,
+ * pass the return value to <f mciGetErrorString>.
+ *
+ * Error values that are returned when a device is being opened
+ * are listed with the MCI_OPEN message. In addition to the
+ * MCI_OPEN error returns, this function can
+ * return the following values:
+ *
+ * @flag MCIERR_BAD_TIME_FORMAT | Illegal value for time format.
+ *
+ * @flag MCIERR_CANNOT_USE_ALL | The device name "all" is not allowed
+ * for this command.
+ *
+ * @flag MCIERR_CREATEWINDOW | Could not create or use window.
+ *
+ * @flag MCIERR_DEVICE_LOCKED | The device is locked until it is
+ * closed automatically.
+ *
+ * @flag MCIERR_DEVICE_NOT_READY | Device not ready.
+ *
+ * @flag MCIERR_DEVICE_TYPE_REQUIRED | The device name must be a valid
+ * device type.
+ *
+ * @flag MCIERR_DRIVER | Unspecified device error.
+ *
+ * @flag MCIERR_DRIVER_INTERNAL | Internal driver error.
+ *
+ * @flag MCIERR_FILE_NOT_FOUND | Requested file not found.
+ *
+ * @flag MCIERR_FILE_NOT_SAVED | The file was not saved.
+ *
+ * @flag MCIERR_FILE_READ | A read from the file failed.
+ *
+ * @flag MCIERR_FILE_WRITE | A write to the file failed.
+ *
+ * @flag MCIERR_FLAGS_NOT_COMPATIBLE | Incompatible parameters
+ * were specified.
+ *
+ * @flag MCIERR_HARDWARE | Hardware error on media device.
+ *
+ * @flag MCIERR_INTERNAL | mmsystem startup error.
+ *
+ * @flag MCIERR_INVALID_DEVICE_ID | Invalid device ID.
+ *
+ * @flag MCIERR_INVALID_DEVICE_NAME | The device is not open
+ * or is not known.
+ *
+ * @flag MCIERR_INVALID_FILE | Invalid file format.
+ *
+ * @flag MCIERR_MULTIPLE | Errors occurred in more than one device.
+ *
+ * @flag MCIERR_NO_WINDOW | There is no display window.
+ *
+ * @flag MCIERR_NULL_PARAMETER_BLOCK | Parameter block pointer was NULL.
+ *
+ * @flag MCIERR_OUT_OF_MEMORY | Not enough memory for requested operation.
+ *
+ * @flag MCIERR_OUTOFRANGE | Parameter value out of range.
+ *
+ * @flag MCIERR_UNNAMED_RESOURCE | Attempt to save unnamed file.
+ *
+ * @flag MCIERR_UNRECOGNIZED_COMMAND | Unknown command.
+ *
+ * @flag MCIERR_UNSUPPORTED_FUNCTION | Action not available for this
+ * device.
+ *
+ * The following additional return values are defined for MCI sequencers:
+ *
+ * @flag MCIERR_SEQ_DIV_INCOMPATIBLE | Set Song Pointer incompatible
+ * with SMPTE files.
+ *
+ * @flag MCIERR_SEQ_PORT_INUSE | Specified port is in use.
+ *
+ * @flag MCIERR_SEQ_PORT_MAPNODEVICE | Current map uses non-existent
+ * device.
+ *
+ * @flag MCIERR_SEQ_PORT_MISCERROR | Miscellaneous error with
+ * specified port.
+ *
+ * @flag MCIERR_SEQ_PORT_NONEXISTENT | Specified port does not exist.
+ *
+ * @flag MCIERR_SEQ_PORTUNSPECIFIED | No current MIDI port.
+ *
+ * @flag MCIERR_SEQ_NOMIDIPRESENT | No MIDI ports present.
+ *
+ * @flag MCIERR_SEQ_TIMER | Timer error.
+ *
+ * The following additional return values are defined for MCI waveform
+ * audio devices:
+ *
+ * @flag MCIERR_WAVE_INPUTSINUSE | No compatible waveform recording
+ * device is free.
+ *
+ * @flag MCIERR_WAVE_INPUTSUNSUITABLE | No compatible waveform
+ * recording devices.
+ *
+ * @flag MCIERR_WAVE_INPUTUNSPECIFIED | Any compatible waveform
+ * recording device may be used.
+ *
+ * @flag MCIERR_WAVE_OUTPUTSINUSE | No compatible waveform playback
+ * device is free.
+ *
+ * @flag MCIERR_WAVE_OUTPUTSUNSUITABLE | No compatible waveform
+ * playback devices.
+ *
+ * @flag MCIERR_WAVE_OUTPUTUNSPECIFIED | Any compatible waveform
+ * playback device may be used.
+ *
+ * @flag MCIERR_WAVE_SETINPUTINUSE | Set waveform recording device
+ * is in use.
+ *
+ * @flag MCIERR_WAVE_SETINPUTUNSUITABLE | Set waveform recording
+ * device is incompatible with set format.
+ *
+ * @flag MCIERR_WAVE_SETOUTPUTINUSE | Set waveform playback device
+ * is in use.
+ *
+ * @flag MCIERR_WAVE_SETOUTPUTUNSUITABLE | Set waveform playback
+ * device is incompatible with set format.
+ *
+ * @comm Use the <m MCI_OPEN> command to obtain the device ID
+ * specified by <p wDeviceID>.
+ *
+ * @xref mciGetErrorString mciSendString
+ */
+
+ /*
+ * @doc internal
+ *
+ * @api DWORD | mciDriverEntry | Actually a callback. The entry point for MCI drivers.
+ *
+ * @parm UINT | wMessage | Identifies the requested action to be performed.
+ *
+ * @parm DWORD | dwParam1 | Specifies data for this message. Defined separately
+ * for each message.
+ *
+ * @parm DWORD | dwParam2 | Specifies data for this message. Defined separately
+ * for each message.
+ *
+ * @rdesc The return value is defined separately for each message.
+ */
+DWORD WINAPI
+mciSendCommand(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwParam1,
+ DWORD dwParam2
+ )
+{
+ // Initialize the 16-bit device list if needed.
+ if (!MCI_bDeviceListInitialized && !mciInitDeviceList())
+ return MCIERR_OUT_OF_MEMORY;
+
+ // MCI_OPEN_DRIVER & MCI_CLOSE_DRIVER only supported on 16-bit drivers
+ if ( (wMessage == MCI_OPEN_DRIVER) || (wMessage == MCI_CLOSE_DRIVER) ) {
+ return mciSendCommand16( wDeviceID, wMessage, dwParam1, dwParam2 );
+ }
+
+ /*
+ ** If we are opening the device try the 32 bit side first. If this
+ ** worked (hopefully this is the usual case) we return the given
+ ** device ID. Otherwise, we try for a 16 bit device.
+ */
+ if ( wMessage == MCI_OPEN ) {
+
+ DWORD dwErr;
+
+ DPRINTF(("mciSendCommand: Got an MCI_OPEN command... "
+ "trying 32 bits\r\n" ));
+
+ dwErr = mciMessage( THUNK_MCI_SENDCOMMAND, (DWORD)wDeviceID,
+ (DWORD)wMessage, dwParam1, dwParam2 );
+
+ if ( dwErr == MMSYSERR_NOERROR ) {
+
+ LPMCI_OPEN_PARMS lpOpenParms = (LPMCI_OPEN_PARMS)dwParam2;
+
+ DPRINTF(("mciSendCommand: We have a 32 bit driver,"
+ " devID = 0x%X\r\n", lpOpenParms->wDeviceID ));
+
+ return dwErr;
+
+ }
+ else {
+
+ /*
+ ** We could open the device on the 32 bit side so let
+ ** the 16 bit code have a go (ie. just fall thru to the code below).
+ */
+ DPRINTF(("mciSendCommand: Could not find a 32 bit driver, "
+ "trying for a 16 bit driver\r\n" ));
+
+ dwErr = mciSendCommand16( wDeviceID, wMessage, dwParam1, dwParam2 );
+
+ if ( dwErr == MMSYSERR_NOERROR ) {
+
+ LPMCI_OPEN_PARMS lpOpenParms = (LPMCI_OPEN_PARMS)dwParam2;
+
+ DPRINTF(("mciSendCommand: We have a 16 bit driver,"
+ " devID = 0x%X\r\n", lpOpenParms->wDeviceID ));
+ }
+
+ return dwErr;
+ }
+ }
+ else {
+
+ DWORD dwErr16;
+ DWORD dwErr32;
+
+ /*
+ ** If we have been given the MCI_ALL_DEVICE_ID then we have to
+ ** send the command to both the 32 and 16 bit side.
+ **
+ ** Special care needs to be taken with the MCI_ALL_DEVICE_ID.
+ ** The message must be passed on to both 32 and 16 bit devices.
+ */
+
+ if (CouldBe16bitDrv(wDeviceID)) {
+ dwErr16 = mciSendCommand16( wDeviceID, wMessage,
+ dwParam1, dwParam2 );
+
+ if ( wDeviceID != MCI_ALL_DEVICE_ID ) {
+ return dwErr16;
+ }
+ }
+
+ dwErr32 = mciMessage( THUNK_MCI_SENDCOMMAND, (DWORD)wDeviceID,
+ (DWORD)wMessage, dwParam1, dwParam2 );
+
+ /*
+ ** If we have the MCI_ALL_DEVICE_ID device ID we only return
+ ** an error if both the 16 and 32 bit calls failed. In which
+ ** case we return the 32 bit error code.
+ */
+ if ( wDeviceID == MCI_ALL_DEVICE_ID ) {
+
+ if ( (dwErr16 != MMSYSERR_NOERROR)
+ && (dwErr32 != MMSYSERR_NOERROR) ) {
+
+ return dwErr32;
+ }
+ else {
+ return MMSYSERR_NOERROR;
+ }
+ }
+
+ return dwErr32;
+ }
+}
+
+
+/*****************************Private*Routine******************************\
+* mciSendCommand16
+*
+* Here is where we execute the real 16 bit mciSendCommand. Hoefully this
+* will not get called to often.
+*
+* History:
+* dd-mm-94 - StephenE - Created
+*
+\**************************************************************************/
+DWORD WINAPI
+mciSendCommand16(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwParam1,
+ DWORD dwParam2
+ )
+{
+ DWORD dwErr;
+ MCI_INTERNAL_OPEN_INFO OpenInfo;
+
+
+ //
+ // Send the command. This shell is responsible for adding the device ID
+ // to the error code if necessary
+ //
+ OpenInfo.hCallingTask = GetCurrentTask();
+ OpenInfo.lpstrParams = NULL;
+ OpenInfo.lpstrPointerList = NULL;
+ OpenInfo.wParsingError = 0;
+ dwErr = mciSendCommandInternal (wDeviceID, wMessage,
+ dwParam1, dwParam2, &OpenInfo);
+ //
+ // If the return value contains a resource ID then clear
+ // it from clear the high word
+ //
+ if (dwErr & MCI_RESOURCE_RETURNED)
+ ((LPDWORD)dwParam2)[1] &= 0xFFFF;
+ dwErr &= 0xFFFF;
+
+ //
+ // If the error message is in a driver, store the driver ID in the high
+ // word of the error code
+ //
+ if ((UINT)dwErr >= MCIERR_CUSTOM_DRIVER_BASE)
+ dwErr |= ((DWORD)wDeviceID << 16);
+
+#ifdef DEBUG
+ // Dump the error text if any to the debug terminal
+ if (dwErr != 0)
+ {
+ char strTemp[MAXERRORLENGTH];
+
+ if (!mciGetErrorString (dwErr, strTemp, sizeof(strTemp)))
+ LoadString(ghInst, STR_MCISCERRTXT, strTemp, sizeof(strTemp));
+ else
+ DPRINTF(("mciSendCommand: %ls\r\n",(LPSTR)strTemp));
+ }
+#endif
+ return dwErr;
+}
+
+
+
+// Grab colonized digit
+// Return is number of bytes written to output (NOT including NULL)
+// or 0 if out of room in output buffer (but is terminated anyway)
+// If there is room then at least two digits are written, padded with '0'
+// if necessary. The function assumes that the buffer size is non-zero length,
+// as this is checked in the calling function.
+STATICFN UINT PASCAL NEAR
+mciColonizeDigit(
+ LPSTR lpstrOutput,
+ unsigned char cDigit,
+ UINT wSize
+ )
+{
+ UINT wCount;
+
+ wCount = 2;
+
+// If there is room for at least two digits
+ if (wSize >= 3)
+ {
+ if (cDigit >= 100)
+ {
+ wCount = 3;
+ if (wSize < 4)
+ goto terminate;
+ *lpstrOutput++ = (char)((cDigit / 100) % 10 + '0');
+ cDigit = (char)(cDigit % 100);
+ }
+ *lpstrOutput++ = (char)(cDigit / 10 + '0');
+ *lpstrOutput++ = (char)(cDigit % 10 + '0');
+ }
+
+terminate:
+ *lpstrOutput++ = '\0';
+
+// If we ran out of room then return an error
+ return (wCount >= wSize) ? 0 : wCount;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func BOOL | mciColonize | Convert a colonized dword into a string
+ * representation
+ *
+ * @parm LPSTR | lpstrOutput | Output buffer
+ *
+ * @parm UINT | wLength | Size of output buffer
+ *
+ * @parm DWORD | dwData | Value to convert
+ *
+ * @parm UINT | wType | Either MCI_COLONIZED3_RETURN or
+ * MCI_COLONIZED4_RETURN is set (HIWORD portion only!)
+ *
+ * @comm Example: For C4, 0x01020304 is converted to "04:03:02:01"
+ * For C3, 0x01020304 is converted to "04:03:02"
+ *
+ * @rdesc FALSE if there is not enough room in the output buffer
+ *
+ */
+STATICFN BOOL PASCAL NEAR mciColonize(
+ LPSTR lpstrOutput,
+ UINT wLength,
+ DWORD dwData,
+ UINT wType
+ )
+{
+ LPSTR lpstrInput = (LPSTR)&dwData;
+ UINT wSize;
+ int i;
+
+ for (i = 1; i <= (wType & HIWORD(MCI_COLONIZED3_RETURN) ? 3 : 4); ++i)
+ {
+ wSize = mciColonizeDigit (lpstrOutput,
+ *lpstrInput++,
+ wLength);
+ if (wSize == 0)
+ return FALSE;
+ lpstrOutput += wSize;
+ wLength -= wSize;
+ if (i < 3 || i < 4 && wType & HIWORD(MCI_COLONIZED4_RETURN))
+ {
+ --wLength;
+ if (wLength == 0)
+ return FALSE;
+ else
+ *lpstrOutput++ = ':';
+ }
+ }
+ return TRUE;
+}
+
+//
+// Convert the return value to a return string
+//
+STATICFN UINT PASCAL NEAR
+mciConvertReturnValue(
+ UINT wType,
+ UINT wErrCode,
+ UINT wDeviceID,
+ LPDWORD dwParams,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength
+ )
+{
+ UINT wExternalTable;
+
+ if (lpstrReturnString == NULL || wReturnLength == 0)
+ return 0;
+
+ switch (wType)
+ {
+ case MCI_INTEGER:
+// Convert integer or resource return value to string
+ if (wErrCode & HIWORD(MCI_RESOURCE_RETURNED))
+ {
+ int nResId = HIWORD(dwParams[1]);
+ LPMCI_DEVICE_NODE nodeWorking;
+ HINSTANCE hInstance;
+
+ if ((nodeWorking = MCI_lpDeviceList[wDeviceID])
+ == NULL)
+ {
+// Return blank string on memory error
+ DOUT ("mciConvertReturnValue Warning:NULL device node\r\n");
+ break;
+ }
+
+// Return value is a resource
+ if (wErrCode & HIWORD(MCI_RESOURCE_DRIVER))
+ {
+// Return string ID belongs to driver
+ hInstance = nodeWorking->hDriver;
+
+ wExternalTable = nodeWorking->wCustomCommandTable;
+ } else
+ {
+ wExternalTable = nodeWorking->wCommandTable;
+ hInstance = ghInst;
+ }
+
+// Try to get string from custom or device specific external table
+ if (wExternalTable == -1 ||
+ command_tables[wExternalTable].hModule == NULL ||
+ LoadString (command_tables[wExternalTable].hModule,
+ nResId, lpstrReturnString, wReturnLength)
+ == 0)
+ {
+// Try to get string from CORE.MCI if it's not from the driver
+ if (hInstance != ghInst ||
+ command_tables[0].hModule == NULL ||
+ LoadString (command_tables[0].hModule,
+ nResId, lpstrReturnString, wReturnLength)
+ == 0)
+// Get string from custom module or MMSYSTEM.DLL
+ LoadString (hInstance, nResId, lpstrReturnString,
+ wReturnLength);
+ }
+
+ } else if (wErrCode & HIWORD(MCI_COLONIZED3_RETURN) ||
+ wErrCode & HIWORD(MCI_COLONIZED4_RETURN))
+ {
+ if (!mciColonize (lpstrReturnString,
+ wReturnLength, dwParams[1], wErrCode))
+ return MCIERR_PARAM_OVERFLOW;
+ } else
+// Convert integer return value to string
+ {
+ DWORD dwTemp;
+
+// Need room for a sign, up to ten digits and a NULL
+ if (wReturnLength < 12)
+ return MCIERR_PARAM_OVERFLOW;
+
+ if (wType == MCI_STRING ||
+ wErrCode == HIWORD(MCI_INTEGER_RETURNED))
+ dwTemp = *(LPDWORD)dwParams[1];
+ else
+ dwTemp = dwParams[1];
+ wsprintf(lpstrReturnString, szLongFormat, dwTemp);
+ }
+ break;
+ case MCI_RECT:
+// Need from for 4 times (a sign plus 5 digits) plus three spaces and a NULL
+ if (wReturnLength < 4 * 6 + 4)
+ return MCIERR_PARAM_OVERFLOW;
+
+ wsprintf (lpstrReturnString, szRectFormat,
+ ((LPWORD)dwParams)[2], ((LPWORD)dwParams)[3],
+ ((LPWORD)dwParams)[4], ((LPWORD)dwParams)[5]);
+ break;
+ default:
+// Only support INTEGERs & MIXED
+ DOUT ("mciConvertReturnValue Warning: Unknown return type\r\n");
+ return MCIERR_PARSER_INTERNAL;
+ }
+ return 0;
+}
+
+
+//
+// Pull off the command name and device name from the command string,
+// leaving *lplpstrCommand pointing past the device name
+//
+// Returns 0 or an error code on failure. If successful, the caller must
+// free the pstrCommandName and pstrDeviceName
+//
+// If bCompound then check for a '!' separator in the extracted device name
+// and return only the element part. This is done so that inter-task
+// commands to auto-opened devices will include the correct device name
+//
+STATICFN DWORD PASCAL NEAR
+mciSeparateCommandParts(
+ LPSTR FAR *lplpstrCommand,
+ BOOL bCompound,
+ LPSTR FAR *lplpstrCommandName,
+ LPSTR FAR *lplpstrDeviceName
+ )
+{
+ LPSTR lpstrCommand;
+ UINT wErr;
+
+// Localize the input
+ lpstrCommand = *lplpstrCommand;
+
+// Remove leading spaces
+
+ while (*lpstrCommand == ' ')
+ ++lpstrCommand;
+
+ if (*lpstrCommand == '\0')
+ return MCIERR_MISSING_COMMAND_STRING;
+
+// Pull the command name off of the command string
+ if ((wErr = mciEatToken (&lpstrCommand, ' ', lplpstrCommandName, FALSE))
+ != 0)
+ return wErr;
+
+// Skip past spaces
+ while (*lpstrCommand == ' ')
+ ++lpstrCommand;
+
+// If we're looking for compound elements then yank off any leading
+// device type if it is not the open command
+ if (bCompound && lstrcmpi (szOpen, *lplpstrCommandName) != 0)
+ {
+ LPSTR lpstrTemp = lpstrCommand;
+ while (*lpstrTemp != '\0')
+ {
+ if (*lpstrTemp == '!')
+ {
+// A ! was found so skip past it
+ lpstrCommand = lpstrTemp + 1;
+ break;
+ } else
+ ++lpstrTemp;
+ }
+ }
+
+// Pull the device name off of the command string
+ if ((wErr = mciEatToken (&lpstrCommand, ' ', lplpstrDeviceName, FALSE))
+ != 0)
+ {
+ mciFree (*lplpstrCommandName);
+ return wErr;
+
+ }
+
+// Fix up the results
+ *lplpstrCommand = lpstrCommand;
+
+ return 0;
+}
+
+STATICFN DWORD NEAR PASCAL
+mciSendSystemString(
+ LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength
+ )
+{
+ DWORD dwRet;
+ LPMCI_SYSTEM_MESSAGE lpMessage;
+
+ if (!hwndNotify)
+ return MCIERR_INTERNAL;
+ if (lpMessage = mciAlloc (sizeof (MCI_SYSTEM_MESSAGE))) {
+ LPSTR lpstrPath;
+
+ if (lpstrPath = mciAlloc(MAX_PATHNAME)) {
+ if (!(DosGetCurrentDir(0, lpstrPath))) {
+ lpMessage->lpstrCommand = (LPSTR)lpstrCommand;
+ lpMessage->lpstrReturnString = lpstrReturnString;
+ lpMessage->wReturnLength = wReturnLength;
+ lpMessage->hCallingTask = GetCurrentTask();
+ lpMessage->lpstrNewDirectory = lpstrPath;
+ lpMessage->nNewDrive = DosGetCurrentDrive();
+ dwRet = (DWORD)SendMessage(hwndNotify, MM_MCISYSTEM_STRING, (WPARAM)0, (LPARAM)lpMessage);
+ } else {
+ DOUT("mciSendSystemString: cannot get current directory\r\n");
+ dwRet = MCIERR_GET_CD;
+ }
+ mciFree(lpstrPath);
+ } else {
+ DOUT("mciSendSystemString: cannot allocate new path\r\n");
+ dwRet = MCIERR_OUT_OF_MEMORY;
+ }
+ mciFree(lpMessage);
+ } else {
+ DOUT("mciSendSystemString: cannot allocate message block\r\n");
+ dwRet = MCIERR_OUT_OF_MEMORY;
+ }
+ return dwRet;
+}
+
+DWORD FAR PASCAL
+mciRelaySystemString(
+ LPMCI_SYSTEM_MESSAGE lpMessage
+ )
+{
+ DWORD dwRet;
+ LPSTR lpstrOldPath;
+
+ if (lpstrOldPath = mciAlloc(MAX_PATHNAME)) {
+ if (!(DosGetCurrentDir(0, lpstrOldPath))) {
+ int nOldDrive;
+
+ nOldDrive = DosGetCurrentDrive();
+ if (DosSetCurrentDrive(lpMessage->nNewDrive)) {
+ if (DosChangeDir(lpMessage->lpstrNewDirectory) == 1) {
+ dwRet = mciSendStringInternal (NULL, NULL, 0, 0, lpMessage);
+ if (!DosSetCurrentDrive(nOldDrive))
+ DOUT("mciRelaySystemString: WARNING, cannot restore drive\r\n");
+ if (DosChangeDir(lpstrOldPath) != 1)
+ DOUT("mciRelaySystemString: WARNING, cannot restore directory\r\n");
+ } else {
+ DosSetCurrentDrive(nOldDrive);
+ DOUT("mciRelaySystemString: cannot change to new directory\r\n");
+ dwRet = MCIERR_SET_CD;
+ }
+ } else {
+ DOUT("mciRelaySystemString: cannot change to new drive\r\n");
+ dwRet = MCIERR_SET_DRIVE;
+ }
+ } else {
+ DOUT("mciRelaySystemString: cannot get old directory\r\n");
+ dwRet = MCIERR_GET_CD;
+ }
+ mciFree(lpstrOldPath);
+ } else {
+ DOUT("mciRelaySystemString: cannot allocate old path\r\n");
+ dwRet = MCIERR_OUT_OF_MEMORY;
+ }
+ return dwRet;
+}
+
+// Returns TRUE if "notify" is contained in string with leading blank
+// and trailing blank or '\0'
+STATICFN BOOL PASCAL NEAR
+mciFindNotify(
+ LPSTR lpString
+ )
+{
+ while (*lpString != '\0')
+ {
+// "notify" must be preceded by a blank
+ if (*lpString++ == ' ')
+ {
+ LPSTR lpTemp;
+
+ lpTemp = szNotify;
+ while (*lpTemp != '\0' && *lpString != '\0' &&
+ *lpTemp == MCI_TOLOWER(*lpString))
+ {
+ ++lpTemp;
+ ++lpString;
+ }
+// "notify" must be followed by a blank or a null
+ if (*lpTemp == '\0' &&
+ (*lpString == '\0' || *lpString == ' '))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * @doc INTERNAL MCI
+ *
+ * @func UINT | mciAutoOpenDevice | Try to auto-open the given device and
+ * then send the given command with notification sent to the system task
+ * window proc which sends a close command to the device on receipt
+ *
+ * @parm LPSTR | lpstrDeviceName | The device name to open
+ *
+ * @parm LPSTR | lpstrCommand | The full command to send including the
+ * device name which must be the same as lpstrDeviceName
+ *
+ * @parm LPSTR | lpstrReturnString | The caller's return string buffer
+ *
+ * @parm UINT | wReturnLength | Size of the caller's return string buffer
+ *
+ * @rdesc The errorcode to return to the user
+ */
+STATICFN UINT PASCAL NEAR
+mciAutoOpenDevice(
+ LPSTR lpstrDeviceName,
+ LPSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength
+ )
+{
+ LPSTR lpstrTempCommand, lpstrTempReturn = NULL;
+ UINT wErr;
+
+// "notify" not allowed. This will be found by the parser but the wrong
+// error message will be returned.
+ if (mciFindNotify (lpstrCommand))
+ return MCIERR_NOTIFY_ON_AUTO_OPEN;
+
+// Build the command string "open <device name>"
+
+// Must be GMEM_SHARE for system task
+// device name + blank + "open"
+ if ((lpstrTempCommand = mciAlloc (lstrlen (lpstrDeviceName) + 1 +
+ sizeof (szOpen)))
+ == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+ wsprintf(lpstrTempCommand, szCmdFormat, (LPSTR)szOpen, lpstrDeviceName);
+// Get the open string into the system task via a SendMessage() to mmWndProc
+ wErr = (UINT)mciSendSystemString (lpstrTempCommand, NULL, NULL);
+
+ mciFree (lpstrTempCommand);
+
+ if (wErr != 0)
+ return wErr;
+
+ lpstrTempCommand = NULL;
+// Must make a GMEM_SHARE copy of the return string for system task
+ if (lpstrReturnString == NULL ||
+ (lpstrTempReturn = mciAlloc (wReturnLength + 1)) != NULL)
+ {
+// Build a GMEM_SHARE command string "<user command> <notify>
+// command + blank + "notify"
+ if ((lpstrTempCommand = mciAlloc (lstrlen (lpstrCommand) + 1 + sizeof(szNotify))) == NULL)
+ mciFree (lpstrTempReturn);
+ }
+
+ if (lpstrTempCommand == NULL)
+ {
+// Close the device
+ mciDriverNotify (hwndNotify, mciGetDeviceID (lpstrDeviceName), 0);
+ return MCIERR_OUT_OF_MEMORY;
+ }
+
+ wsprintf(lpstrTempCommand, szCmdFormat, lpstrCommand, (LPSTR)szNotify);
+
+// Get the user command string into the system task via a SendMessage()
+// to mmWndProc
+// The notification handle is also mmWndProc
+ wErr = (UINT)mciSendSystemString (lpstrTempCommand, lpstrTempReturn,
+ wReturnLength);
+
+// Copy the return string into the user's buffer
+ if (lpstrReturnString != NULL)
+ {
+ lstrcpy (lpstrReturnString, lpstrTempReturn);
+ mciFree (lpstrTempReturn);
+ }
+
+ mciFree (lpstrTempCommand);
+
+// If there was an error we must close the device
+ if (wErr != 0)
+ mciAutoCloseDevice (lpstrDeviceName);
+
+ return wErr;
+}
+
+//
+// Identical to mciSendString() but the lpMessage parameter is tacked on
+//
+// lpMessage comes from inter-task mciSendString and includes an
+// hCallingTask item which is sent down the the OPEN command
+//
+STATICFN DWORD NEAR PASCAL
+mciSendStringInternal(
+ LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength,
+ HWND hwndCallback,
+ LPMCI_SYSTEM_MESSAGE lpMessage
+ )
+{
+ UINT wID, wConvertReturnValue, wErr, wMessage;
+ UINT wLen;
+ UINT wDeviceID;
+ LPDWORD lpdwParams = NULL;
+ DWORD dwReturn, dwFlags = 0;
+ LPSTR lpCommandItem;
+ DWORD dwErr, dwRetType;
+ UINT wTable = -1;
+ LPSTR lpstrDeviceName = NULL, lpstrCommandName = NULL;
+ LPSTR FAR *lpstrPointerList = NULL;
+ LPSTR lpstrCommandStart;
+ HTASK hCallingTask;
+ UINT wParsingError;
+ BOOL bNewDevice;
+ LPSTR lpstrInputCopy;
+
+ // Did this call come in from another task
+ if (lpMessage != NULL)
+ {
+ // Yes so restore info
+ lpstrCommand = lpMessage->lpstrCommand;
+ lpstrReturnString = lpMessage->lpstrReturnString;
+ wReturnLength = lpMessage->wReturnLength;
+ hwndCallback = hwndNotify;
+ hCallingTask = lpMessage->hCallingTask;
+ lpstrInputCopy = NULL;
+
+ } else
+ {
+ BOOL bInQuotes = FALSE;
+
+ // No so set hCallingTask to current
+ hCallingTask = GetCurrentTask();
+
+ if (lpstrCommand == NULL)
+ return MCIERR_MISSING_COMMAND_STRING;
+
+ // Make a copy of the input string and convert tabs to
+ // spaces except those inside quotes
+ //
+ if ((lpstrInputCopy = mciAlloc (lstrlen (lpstrCommand) + 1)) == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+ lstrcpy (lpstrInputCopy, lpstrCommand);
+ lpstrCommand = lpstrInputCopy;
+ lpstrCommandStart = (LPSTR)lpstrCommand;
+ while (*lpstrCommandStart != '\0')
+ {
+ if (*lpstrCommandStart == '"')
+ bInQuotes = !bInQuotes;
+ else if (!bInQuotes && *lpstrCommandStart == '\t')
+ *lpstrCommandStart = ' ';
+ ++lpstrCommandStart;
+ }
+ }
+ lpstrCommandStart = (LPSTR)lpstrCommand;
+
+ if (lpstrReturnString == NULL) {
+ //
+ // As an additional safeguard against the driver writing into the
+ // output buffer when the return string pointer is NULL, set its
+ // length to 0
+ //
+ wReturnLength = 0;
+ }
+ else {
+ //
+ // Set return to empty string so that it won't print out garbage if not
+ // touched again
+ //
+ *lpstrReturnString = '\0';
+ }
+
+ // Pull the command name and device name off the command string
+ if ((dwReturn = mciSeparateCommandParts (&lpstrCommand, lpMessage != NULL,
+ &lpstrCommandName, &lpstrDeviceName)) != 0)
+ goto exitfn;
+
+ // Get the device id (if any) of the given device name
+ wDeviceID = mciGetDeviceIDInternal(lpstrDeviceName, hCallingTask);
+
+ // Allow "new" for an empty device name
+ if (wDeviceID == 0 && lstrcmpi (lpstrDeviceName, szNew) == 0)
+ {
+ bNewDevice = TRUE;
+ *lpstrDeviceName = '\0';
+ } else {
+ bNewDevice = FALSE;
+ }
+
+
+ // Look up the command name
+ wMessage = mciParseCommand (wDeviceID, lpstrCommandName, lpstrDeviceName,
+ &lpCommandItem, &wTable);
+
+ // If the device has a pending auto-close
+ if (MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ LPMCI_DEVICE_NODE nodeWorking = MCI_lpDeviceList[wDeviceID];
+
+ // Is there a pending auto-close message?
+ if (nodeWorking->dwMCIFlags & MCINODE_ISAUTOCLOSING)
+ {
+ // Let the device close
+ //!! Yield();
+ // Did the device close?
+ //!! wDeviceID = mciGetDeviceIDInternal (lpstrDeviceName, hCallingTask);
+ // If not then fail this command
+ //!! if (wDeviceID == 0)
+ //!! {
+
+ wErr = MCIERR_DEVICE_LOCKED;
+ goto cleanup;
+
+ //!! }
+
+ // If the call does not come from another task and is not owned by this task
+ // and is not the SYSINFO command
+ //
+
+ } else if (lpMessage == NULL &&
+ nodeWorking->hOpeningTask != nodeWorking->hCreatorTask &&
+ wMessage != MCI_SYSINFO)
+ // Send the string inter-task
+ {
+ if (mciFindNotify (lpstrCommandStart))
+ {
+ wErr = MCIERR_NOTIFY_ON_AUTO_OPEN;
+ goto cleanup;
+ } else
+ {
+ LPSTR lpstrReturnStringCopy;
+
+ mciFree(lpstrCommandName);
+ mciFree(lpstrDeviceName);
+ mciUnlockCommandTable (wTable);
+
+ if ((lpstrReturnStringCopy = mciAlloc (wReturnLength + 1)) != NULL)
+ {
+ dwReturn = mciSendSystemString (lpstrCommandStart,
+ lpstrReturnStringCopy,
+ wReturnLength);
+ lstrcpy (lpstrReturnString, lpstrReturnStringCopy);
+ mciFree (lpstrReturnStringCopy);
+ } else
+ dwReturn = MCIERR_OUT_OF_MEMORY;
+ goto exitfn;
+ }
+ }
+ }
+
+ // There must be a device name (except for the MCI_SOUND message)
+ if (*lpstrDeviceName == '\0' && wMessage != MCI_SOUND && !bNewDevice)
+ {
+ wErr = MCIERR_MISSING_DEVICE_NAME;
+ goto cleanup;
+ }
+
+ // The command must appear in the parser tables
+ if (wMessage == 0)
+ {
+ wErr = MCIERR_UNRECOGNIZED_COMMAND;
+ goto cleanup;
+ }
+
+ // The "new" device name is only legal for the open message
+ if (bNewDevice)
+ {
+ if (wMessage != MCI_OPEN)
+ {
+ wErr = MCIERR_INVALID_DEVICE_NAME;
+ goto cleanup;
+ }
+ }
+
+ // If there was no device ID
+ if (wDeviceID == 0)
+ // If auto open is not legal (usually internal commands)
+ if (MCI_CANNOT_AUTO_OPEN (wMessage))
+ {
+ // If the command needs an open device
+ if (!MCI_DO_NOT_NEED_OPEN (wMessage))
+ {
+ wErr = MCIERR_INVALID_DEVICE_NAME;
+ goto cleanup;
+ }
+ } else
+
+ // If auto open is legal try to open the device automatically
+ {
+ wErr = mciAutoOpenDevice (lpstrDeviceName, lpstrCommandStart,
+ lpstrReturnString, wReturnLength);
+ goto cleanup;
+ }
+
+ //
+ // Parse the command parameters
+ //
+ // Allocate command parameter block
+ if ((lpdwParams = (LPDWORD)mciAlloc (sizeof(DWORD) * MCI_MAX_PARAM_SLOTS))
+ == NULL)
+ {
+ wErr = MCIERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ wErr = mciParseParams (lpstrCommand, lpCommandItem,
+ &dwFlags,
+ (LPSTR)lpdwParams,
+ MCI_MAX_PARAM_SLOTS * sizeof(DWORD),
+ &lpstrPointerList, &wParsingError);
+ if (wErr != 0)
+ goto cleanup;
+
+ // The 'new' device keyword requires an alias
+ if (bNewDevice && !(dwFlags & MCI_OPEN_ALIAS))
+ {
+ wErr = MCIERR_NEW_REQUIRES_ALIAS;
+ goto cleanup;
+ }
+
+ // Parsed OK so execute command
+
+ // Special processing for the MCI_OPEN message's parameters
+ if (wMessage == MCI_OPEN)
+ {
+ // Manually reference the device type and device element
+ if (dwFlags & MCI_OPEN_TYPE)
+ {
+ // The type name was specified explicitly as a parameter
+ // so the given device name is the element name
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrElementName
+ = (LPSTR)lpstrDeviceName;
+ dwFlags |= MCI_OPEN_ELEMENT;
+ } else
+ {
+ // A type must be explicitly specified when "new" is used
+ if (bNewDevice)
+ {
+ wErr = MCIERR_INVALID_DEVICE_NAME;
+ goto cleanup;
+ }
+ // The device type is the given device name.
+ // There is no element name
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrDeviceType
+ = (LPSTR)lpstrDeviceName;
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrElementName = NULL;
+ dwFlags |= MCI_OPEN_TYPE;
+ }
+ }
+
+ else if (wMessage == MCI_SOUND && *lpstrDeviceName != '\0')
+ {
+ // Kludge the sound name for SOUND
+ //!! mciToLower (lpstrDeviceName);
+ if (lstrcmpi (lpstrDeviceName, szNotify) == 0)
+ dwFlags |= MCI_NOTIFY;
+ else if (lstrcmpi (lpstrDeviceName, szWait) == 0)
+ dwFlags |= MCI_WAIT;
+ else
+ {
+ ((LPMCI_SOUND_PARMS)lpdwParams)->lpstrSoundName = lpstrDeviceName;
+ dwFlags |= MCI_SOUND_NAME;
+ }
+ }
+
+ // Figure out what kind of return value to expect
+
+ // Initialize flag
+ wConvertReturnValue = 0;
+
+ // Skip past header
+ wLen = mciEatCommandEntry (lpCommandItem, NULL, NULL);
+
+ // Get return value (if any)
+ mciEatCommandEntry (lpCommandItem + wLen, &dwRetType, &wID);
+ if (wID == MCI_RETURN)
+ {
+ // There is a return value
+ if (wDeviceID == MCI_ALL_DEVICE_ID && wMessage != MCI_SYSINFO)
+ {
+ wErr = MCIERR_CANNOT_USE_ALL;
+ goto cleanup;
+ }
+ switch ((UINT)dwRetType)
+ {
+ case MCI_STRING:
+ // The return value is a string, point output
+ // buffer to user's buffer
+ lpdwParams[1] = (DWORD)lpstrReturnString;
+ lpdwParams[2] = (DWORD)wReturnLength;
+ break;
+
+ case MCI_INTEGER:
+ // The return value is an integer, flag to convert it
+ // to a string later
+ wConvertReturnValue = MCI_INTEGER;
+ break;
+
+ case MCI_RECT:
+ // The return value is an rect, flag to
+ // convert it to a string later
+ wConvertReturnValue = MCI_RECT;
+ break;
+#ifdef DEBUG
+ default:
+ DOUT ("mciSendStringInternal: Unknown return type\r\n");
+ break;
+#endif
+ }
+ }
+
+ // We don't need this around anymore
+ mciUnlockCommandTable (wTable);
+ wTable = -1;
+
+ /* Fill the callback entry */
+ lpdwParams[0] = (DWORD)(UINT)hwndCallback;
+
+ // Kludge the type number for SYSINFO
+ if (wMessage == MCI_SYSINFO)
+ ((LPMCI_SYSINFO_PARMS)lpdwParams)->wDeviceType = mciLookUpType(lpstrDeviceName);
+
+ // Now we actually send the command further into the bowels of MCI!
+
+ // The INTERNAL version of mciSendCommand is used in order to get
+ // special return description information encoded in the high word
+ // of the return value and to get back the list of pointers allocated
+ // by any parsing done in the open command
+ {
+ MCI_INTERNAL_OPEN_INFO OpenInfo;
+ OpenInfo.lpstrParams = (LPSTR)lpstrCommand;
+ OpenInfo.lpstrPointerList = lpstrPointerList;
+ OpenInfo.hCallingTask = hCallingTask;
+ OpenInfo.wParsingError = wParsingError;
+ dwErr = mciSendCommandInternal (wDeviceID, wMessage, dwFlags,
+ (DWORD)(LPDWORD)lpdwParams,
+ &OpenInfo);
+ // If the command was reparsed there may be a new pointer list
+ // and the old one was free'd
+ lpstrPointerList = OpenInfo.lpstrPointerList;
+ }
+
+ wErr = (UINT)dwErr;
+
+ if (wErr != 0)
+ // If command execution error
+ goto cleanup;
+
+ // Command executed OK
+ // See if a string return came back with an integer instead
+ if (dwErr & MCI_INTEGER_RETURNED)
+ wConvertReturnValue = MCI_INTEGER;
+
+ // If the return value must be converted
+ if (wConvertReturnValue != 0 && wReturnLength != 0)
+ wErr = mciConvertReturnValue (wConvertReturnValue, HIWORD(dwErr),
+ wDeviceID, lpdwParams,
+ lpstrReturnString, wReturnLength);
+
+cleanup:
+ if (wTable != -1)
+ mciUnlockCommandTable (wTable);
+
+ mciFree(lpstrCommandName);
+ mciFree(lpstrDeviceName);
+ if (lpdwParams != NULL)
+ mciFree (lpdwParams);
+
+ // Free any memory used by string parameters
+ mciParserFree (lpstrPointerList);
+
+ dwReturn = (wErr >= MCIERR_CUSTOM_DRIVER_BASE ?
+ (DWORD)wErr | (DWORD)wDeviceID << 16 :
+ (DWORD)wErr);
+
+#ifdef DEBUG
+ if (dwReturn != 0)
+ {
+ char strTemp[MAXERRORLENGTH];
+
+ if (!mciGetErrorString (dwReturn, strTemp, sizeof(strTemp)))
+ LoadString(ghInst, STR_MCISSERRTXT, strTemp, sizeof(strTemp));
+ else
+ DPRINTF(("mciSendString: %ls\r\n",(LPSTR)strTemp));
+ }
+#endif
+
+exitfn:
+ if (lpstrInputCopy != NULL)
+ mciFree (lpstrInputCopy);
+
+#ifdef DEBUG
+ mciCheckLocks();
+#endif
+
+ return dwReturn;
+}
+
+/*
+ * @doc EXTERNAL MCI
+ *
+ * @api DWORD | mciSendString | This function sends a command string to an
+ * MCI device. The device that the command is sent to is specified in the
+ * command string.
+ *
+ * @parm LPCSTR | lpstrCommand | Specifies an MCI command string.
+ *
+ * @parm LPSTR | lpstrReturnString | Specifies a buffer for return
+ * information. If no return information is needed, you can specify
+ * NUL for this parameter.
+ *
+ * @parm UINT | wReturnLength | Specifies the size of the return buffer
+ * specified by <p lpstrReturnString>.
+ *
+ * @parm HWND | hwndCallback | Specifies a handle to a window to call back
+ * if "notify" was specified in the command string.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * error information. The low-order word
+ * of the returned DWORD contains the error return value.
+ *
+ * To get a textual description of <f mciSendString> return values,
+ * pass the return value to <f mciGetErrorString>.
+ *
+ * The error returns listed for <f mciSendCommand> also apply to
+ * <f mciSendString>. The following error returns are unique to
+ * <f mciSendString>:
+ *
+ * @flag MCIERR_BAD_CONSTANT | Unknown value for parameter.
+ *
+ * @flag MCIERR_BAD_INTEGER | Invalid or missing integer in command.
+ *
+ * @flag MCIERR_DUPLICATE_FLAGS | A flag or value was specified twice.
+ *
+ * @flag MCIERR_MISSING_COMMAND_STRING | No command was specified.
+ *
+ * @flag MCIERR_MISSING_DEVICE_NAME | No device name was specified.
+ *
+ * @flag MCIERR_MISSING_STRING_ARGUMENT | A string value was
+ * missing from the command.
+ *
+ * @flag MCIERR_NEW_REQUIRES_ALIAS | An alias must be used
+ * with the "new" device name.
+ *
+ * @flag MCIERR_NO_CLOSING_QUOTE | A closing quotation mark is missing.
+ *
+ * @flag MCIERR_NOTIFY_ON_AUTO_OPEN | The "notify" flag is illegal
+ * with auto-open.
+ *
+ * @flag MCIERR_PARAM_OVERFLOW | The output string was not long enough.
+ *
+ * @flag MCIERR_PARSER_INTERNAL | Internal parser error.
+ *
+ * @flag MCIERR_UNRECOGNIZED_KEYWORD | Unknown command parameter.
+ *
+ * @xref mciGetErrorString mciSendCommand
+ */
+DWORD WINAPI
+mciSendString(
+ LPCSTR lpstrCommand,
+ LPSTR lpstrReturnString,
+ UINT wReturnLength,
+ HWND hwndCallback
+ )
+{
+ DWORD dwErr32;
+ DWORD dwErr16 = MMSYSERR_NOERROR;
+ LPSTR lpstr;
+ BOOL fHaveAll = FALSE;
+
+ // Initialize the 16-bit device list
+ if (!MCI_bDeviceListInitialized && !mciInitDeviceList()) {
+ return MCIERR_OUT_OF_MEMORY;
+ }
+
+ dwErr32 = mciMessage( THUNK_MCI_SENDSTRING, (DWORD)lpstrCommand,
+ (DWORD)lpstrReturnString, (DWORD)wReturnLength,
+ (DWORD)hwndCallback );
+
+ /*
+ ** Even if the string was processed correctly by the 32 bit side
+ ** we might still have to pass it through to the 16 bit side if it
+ ** contains the string " all\0" or " all ".
+ */
+ lpstr = _fstrstr( lpstrCommand, " all" );
+ if ( lpstr ) {
+
+ lpstr += 4;
+
+ if ( *lpstr == ' ' || *lpstr == '\0' ) {
+ fHaveAll = TRUE;
+ }
+ }
+
+
+ /*
+ ** If we have the all device or an error from the 32 bit side
+ ** we have to try the 16 bit side.
+ */
+
+ if ( !fHaveAll && dwErr32 == MMSYSERR_NOERROR ) {
+ return dwErr32;
+ }
+ else {
+
+ dwErr16 = mciSendStringInternal( lpstrCommand, lpstrReturnString,
+ wReturnLength, hwndCallback, NULL );
+ }
+
+
+ /*
+ ** Special processing of the return code is required if the
+ ** MCI_ALL_DEVICE_ID was specified.
+ */
+ if ( fHaveAll ) {
+ if ( (dwErr16 != MMSYSERR_NOERROR)
+ && (dwErr32 != MMSYSERR_NOERROR) ) {
+
+ return dwErr32;
+ }
+ else {
+ return MMSYSERR_NOERROR;
+ }
+ }
+
+ if ( dwErr32 != MCIERR_INVALID_DEVICE_NAME
+ && dwErr16 != MMSYSERR_NOERROR ) {
+
+ return dwErr32;
+ }
+
+ return dwErr16;
+}
+
+
+/*
+ * @doc INTERNAL MCI
+ *
+ * @api BOOL | mciExecute | This function is a simplified version of the
+ * <f mciSendString> function. It does not take a buffer for
+ * return information, and it displays a message box when errors occur.
+ *
+ * @parm LPCSTR | lpstrCommand | Specifies an MCI command string.
+ *
+ * @rdesc TRUE if successful, FALSE if unsuccessful.
+ *
+ * @comm This function provides a simple interface to MCI from scripting
+ * languages.
+ *
+ * @xref mciSendString
+ */
+BOOL WINAPI
+mciExecute(
+ LPCSTR lpstrCommand
+ )
+{
+ char aszError[MAXERRORLENGTH];
+ DWORD dwErr;
+ LPSTR lpstrName;
+
+ if (LOWORD(dwErr = mciSendString (lpstrCommand, NULL, 0, NULL)) == 0)
+ return TRUE;
+
+ if (!mciGetErrorString (dwErr, aszError, sizeof(aszError)))
+ LoadString(ghInst, STR_MCIUNKNOWN, aszError, sizeof(aszError));
+ else
+
+ if (lpstrCommand != NULL)
+ {
+// Skip initial blanks
+ while (*lpstrCommand == ' ')
+ ++lpstrCommand;
+// Then skip the command
+ while (*lpstrCommand != ' ' && *lpstrCommand != '\0')
+ ++lpstrCommand;
+// Then blanks before the device name
+ while (*lpstrCommand == ' ')
+ ++lpstrCommand;
+
+// Now, get the device name
+ if (lpstrCommand != '\0' &&
+ mciEatToken (&lpstrCommand, ' ', &lpstrName, FALSE) != 0)
+ DOUT ("Could not allocate device name text for error box\r\n");
+ } else
+ lpstrName = NULL;
+
+ MessageBox (NULL, aszError, lpstrName, MB_ICONHAND | MB_OK);
+
+ if (lpstrName != NULL)
+ mciFree(lpstrName);
+
+ return FALSE;
+}
+
+/*
+ * @doc EXTERNAL MCI
+ *
+ * @api BOOL | mciGetErrorString | This function returns a
+ * textual description of the specified MCI error.
+ *
+ * @parm DWORD | dwError | Specifies the error code returned by
+ * <f mciSendCommand> or <f mciSendString>.
+ *
+ * @parm LPSTR | lpstrBuffer | Specifies a pointer to a buffer that is
+ * filled with a textual description of the specified error.
+ *
+ * @parm UINT | wLength | Specifies the length of the buffer pointed to by
+ * <p lpstrBuffer>.
+ *
+ * @rdesc Returns TRUE if successful. Otherwise, the given error code
+ * was not known.
+ */
+BOOL WINAPI
+mciGetErrorString (
+ DWORD dwError,
+ LPSTR lpstrBuffer,
+ UINT wLength
+ )
+{
+ HINSTANCE hInst;
+
+
+ if (lpstrBuffer == NULL)
+ return FALSE;
+
+ if ( mciMessage( THUNK_MCI_GETERRORSTRING, (DWORD)dwError,
+ (DWORD)lpstrBuffer, (DWORD)wLength, 0L ) ) {
+ return TRUE;
+ }
+
+// If the high bit is set then get the error string from the driver
+// else get it from mmsystem.dll
+ if (HIWORD(dwError) != 0)
+ {
+ if (!MCI_VALID_DEVICE_ID (HIWORD (dwError)) || !(hInst = MCI_lpDeviceList[HIWORD (dwError)]->hDriver))
+ {
+ hInst = ghInst;
+ dwError = MCIERR_DRIVER;
+ }
+ } else
+ hInst = ghInst;
+
+ if (LoadString (hInst, LOWORD(dwError), lpstrBuffer, wLength) == 0)
+ {
+// If the string load failed then at least terminate the string
+ if (wLength > 0)
+ *lpstrBuffer = '\0';
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+#if 0
+/* Return non-zero if load successful */
+BOOL NEAR PASCAL MCIInit(void)
+{
+ mci32Message = (LPMCIMESSAGE)GetProcAddress32W( mmwow32Lib,
+ "mci32Message" );
+ return TRUE;
+}
+#endif
+
+
+void NEAR PASCAL
+MCITerminate(
+ void
+ )
+{
+/*
+ We would like to close all open devices here but cannot because of
+ unknown WEP order
+*/
+ if (hMciHeap != NULL)
+ HeapDestroy(hMciHeap);
+
+ hMciHeap = NULL;
+}
diff --git a/private/mvdm/wow16/mmsystem/mciparse.c b/private/mvdm/wow16/mmsystem/mciparse.c
new file mode 100644
index 000000000..392c058eb
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mciparse.c
@@ -0,0 +1,1439 @@
+/*******************************Module*Header*********************************\
+* Module Name: mciparse.c
+*
+* Media Control Architecture Command Parser
+*
+* Created: 3/2/90
+* Author: DLL (DavidLe)
+*
+* History:
+*
+* Copyright (c) 1990 Microsoft Corporation
+*
+\******************************************************************************/
+
+#include <windows.h>
+#define MMNOMIDI
+#define MMNOWAVE
+#define MMNOSOUND
+#define MMNOTIMER
+#define MMNOJOY
+#define MMNOSEQ
+#include "mmsystem.h"
+#define NOMIDIDEV
+#define NOWAVEDEV
+#define NOTIMERDEV
+#define NOJOYDEV
+#define NOSEQDEV
+#define NOTASKDEV
+#include "mmddk.h"
+#include "mmsysi.h"
+
+#ifndef STATICFN
+#define STATICFN
+#endif
+
+#define WCODE UINT _based(_segname("_CODE"))
+
+extern char far szOpen[]; // in MCI.C
+
+#ifdef DEBUG_RETAIL
+extern int DebugmciSendCommand;
+#endif
+
+// Number of command tables registered, including "holes"
+static UINT number_of_command_tables;
+
+// Command table list
+command_table_type command_tables[MAX_COMMAND_TABLES];
+
+static SZCODE szTypeTableExtension[] = ".mci";
+static SZCODE szCoreTable[] = "core";
+
+// Core table is loaded when the first MCI command table is requested
+static BOOL bCoreTableLoaded;
+
+// One element for each device type. Value is the table type to use
+// or 0 if there is no device type specific table.
+static WCODE table_types[] =
+{
+ MCI_DEVTYPE_VCR, // vcr
+ MCI_DEVTYPE_VIDEODISC, // videodisc
+ MCI_DEVTYPE_OVERLAY, // overlay
+ MCI_DEVTYPE_CD_AUDIO, // cdaudio
+ MCI_DEVTYPE_DAT, // dat
+ MCI_DEVTYPE_SCANNER, // scanner
+ MCI_DEVTYPE_ANIMATION, // animation
+ MCI_DEVTYPE_DIGITAL_VIDEO, // digitalvideo
+ MCI_DEVTYPE_OTHER, // other
+ MCI_DEVTYPE_WAVEFORM_AUDIO, // waveaudio
+ MCI_DEVTYPE_SEQUENCER // sequencer
+};
+/*!!
+void PASCAL NEAR mciToLower (LPSTR lpstrString)
+{
+ while (*lpstrString != '\0')
+ {
+ if (*lpstrString >= 'A' && *lpstrString <= 'Z')
+ *lpstrString += 0x20;
+
+ ++lpstrString;
+ }
+}
+*/
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciEatCommandEntry | Read a command resource entry and
+ * return its length and its value and identifier
+ *
+ * @parm LPCSTR | lpEntry | The start of the command resource entry
+ *
+ * @parm LPDWORD | lpValue | The value of the entry, returned to caller
+ * May be NULL
+ *
+ * @parm UINT FAR* | lpID | The identifier of the entry, returned to caller
+ * May be NULL
+ *
+ * @rdesc The total number of bytes in the entry
+ *
+ */
+UINT PASCAL NEAR mciEatCommandEntry (
+LPCSTR lpEntry,
+LPDWORD lpValue,
+UINT FAR* lpID)
+{
+ LPCSTR lpScan = lpEntry;
+
+ while (*lpScan++ != '\0')
+ ;
+ if (lpValue != NULL)
+ *lpValue = *(LPDWORD)lpScan;
+ lpScan += sizeof(DWORD);
+ if (lpID != NULL)
+ *lpID = *(LPWORD)lpScan;
+ lpScan += sizeof(UINT);
+
+ return lpScan - lpEntry;
+}
+
+// Return the size used by this token in the parameter list
+UINT PASCAL NEAR mciGetParamSize (DWORD dwValue, UINT wID)
+{
+ switch (wID)
+ {
+ case MCI_CONSTANT:
+ case MCI_INTEGER:
+ case MCI_STRING:
+ return sizeof(DWORD);
+ case MCI_RECT:
+ return sizeof(RECT);
+ case MCI_RETURN:
+ switch ((UINT)dwValue)
+ {
+ case MCI_INTEGER:
+ return sizeof(DWORD);
+ case MCI_STRING:
+ case MCI_RECT:
+ return sizeof(RECT);
+ default:
+ DOUT ("mciGetParamSize: Unknown return type\r\n");
+ return 0;
+ }
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciRegisterCommandTable | This function adds a new
+ * table for the MCI parser.
+ *
+ * @parm HGLOBAL | hResource | Handle to the RCDATA resource
+ *
+ * @parm UINT FAR* | lpwIndex | Pointer to command table index
+ *
+ * @parm UINT | wType | Specifies the device type for this command table.
+ * Driver tables and the core table are type 0.
+ *
+ * @parm HINSTANCE | hModule | Module instance registering table.
+ *
+ * @rdesc Returns the command table index number that was assigned or -1
+ * on error.
+ *
+ */
+STATICFN UINT PASCAL NEAR
+mciRegisterCommandTable(
+ HGLOBAL hResource,
+ UINT FAR* lpwIndex,
+ UINT wType,
+ HINSTANCE hModule
+ )
+{
+ UINT wID;
+
+/* First check for free slots */
+ for (wID = 0; wID < number_of_command_tables; ++wID)
+ if (command_tables[wID].hResource == NULL)
+ break;
+
+/* If no empty slots then allocate another one */
+ if (wID >= number_of_command_tables)
+ {
+ if (number_of_command_tables == MAX_COMMAND_TABLES)
+ {
+ DOUT ("mciRegisterCommandTable: No more tables\r\n");
+ return -1;
+ }
+ else
+ wID = number_of_command_tables++;
+ }
+
+/* Fill in the slot */
+ command_tables[wID].wType = wType;
+ command_tables[wID].hResource = hResource;
+ command_tables[wID].lpwIndex = lpwIndex;
+ command_tables[wID].hModule = hModule;
+#ifdef DEBUG
+ command_tables[wID].wLockCount = 0;
+#endif
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ {
+ DPRINTF(("mciRegisterCommandTable INFO: assigned slot %u\r\n", wID));
+ DPRINTF(("mciRegisterCommandTable INFO: #tables is %u\r\n",
+ number_of_command_tables));
+ }
+#endif
+ return wID;
+}
+
+/*
+ * @doc DDK MCI
+ * @api UINT | mciLoadCommandResource | Registers the indicated
+ * resource as an MCI command table and builds a command table
+ * index. If a file with the resource name and the extension '.mci' is
+ * found in the path then the resource is taken from that file.
+ *
+ * @parm HINSTANCE | hInstance | The instance of the module whose executable
+ * file contains the resource. This parameter is ignored if an external file
+ * is found.
+ *
+ * @parm LPCSTR | lpResName | The name of the resource
+ *
+ * @parm UINT | wType | The table type. Custom device specific tables MUST
+ * give a table type of 0.
+ *
+ * @rdesc Returns the command table index number that was assigned or -1
+ * on error.
+ *
+ */
+UINT WINAPI mciLoadCommandResource (
+HINSTANCE hInstance,
+LPCSTR lpResName,
+UINT wType)
+{
+ UINT FAR* lpwIndex, FAR* lpwScan;
+ HINSTANCE hExternal;
+ HRSRC hResInfo;
+ HGLOBAL hResource;
+ LPSTR lpResource, lpScan;
+ int nCommands = 0;
+ UINT wID;
+ UINT wLen;
+ // Name + '.' + Extension + '\0'
+ char strFile[8 + 1 + 3 + 1];
+ LPSTR lpstrFile = strFile;
+ LPCSTR lpstrType = lpResName;
+ OFSTRUCT ofs;
+
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ DPRINTF(("mciLoadCommandResource INFO: %s loading\r\n", (LPSTR)lpResName));
+#endif
+
+// Initialize the device list
+ if (!MCI_bDeviceListInitialized && !mciInitDeviceList())
+ return MCIERR_OUT_OF_MEMORY;
+
+// Load the core table if its not already there
+ if (!bCoreTableLoaded)
+ {
+ bCoreTableLoaded = TRUE;
+// If its not the core table being loaded
+ if (lstrcmpi (szCoreTable, lpResName) != 0)
+ if (mciLoadCommandResource (ghInst, szCoreTable, 0) == -1)
+ {
+ DOUT ("mciLoadCommandResource: Cannot load core table\r\n");
+ }
+ }
+
+// Check for a file with the extension ".mci"
+// Copy up to the first eight characters of device type
+ while (lpstrType < lpResName + 8 && *lpstrType != '\0')
+ *lpstrFile++ = *lpstrType++;
+
+// Tack extension onto end
+ lstrcpy (lpstrFile, szTypeTableExtension);
+
+// If the file exists and can be loaded then set flag
+// otherwise load resource from MMSYSTEM.DLL
+ if (OpenFile (strFile, &ofs, OF_EXIST) == HFILE_ERROR ||
+ (hExternal = LoadLibrary(strFile)) < HINSTANCE_ERROR)
+
+ hExternal = NULL;
+
+// Load the given table from the file or from the module if not found
+ if (hExternal != NULL &&
+ (hResInfo = FindResource (hExternal, lpResName, RT_RCDATA)) != NULL)
+
+ hInstance = hExternal;
+ else
+ hResInfo = FindResource (hInstance, lpResName, RT_RCDATA);
+
+ if (hResInfo == NULL)
+ {
+ DOUT ("mciLoadCommandResource: Cannot find command resource\r\n");
+ return -1;
+ }
+ if ((hResource = LoadResource (hInstance, hResInfo)) == NULL)
+ {
+ DOUT ("mciLoadCommandResource: Cannot load command resource\r\n");
+ return -1;
+ }
+ if ((lpResource = LockResource (hResource)) == NULL)
+ {
+ DOUT ("mciLoadCommandResource: Cannot lock resource\r\n");
+ FreeResource (hResource);
+ return -1;
+ }
+
+/* Count the number of commands */
+ lpScan = lpResource;
+ while (TRUE)
+ {
+ lpScan += mciEatCommandEntry(lpScan, NULL, &wID);
+
+// End of command?
+ if (wID == MCI_COMMAND_HEAD)
+ ++nCommands;
+// End of command list?
+ else if (wID == MCI_END_COMMAND_LIST)
+ break;
+ }
+
+// There must be at least on command in the table
+ if (nCommands == 0)
+ {
+ DOUT ("mciLoadCommandResource: No commands in the specified table\r\n");
+ UnlockResource (hResource);
+ FreeResource (hResource);
+ return -1;
+ }
+
+// Allocate storage for the command table index
+// Leave room for a -1 entry to terminate it
+ if ((lpwIndex = (UINT FAR*)
+ mciAlloc ((UINT)sizeof (UINT) * (nCommands + 1)))
+ == NULL)
+ {
+ DOUT ("mciLoadCommandResource: cannot allocate command table index\r\n");
+ UnlockResource (hResource);
+ FreeResource (hResource);
+ return -1;
+ }
+
+/* Build Command Table */
+ lpwScan = lpwIndex;
+ lpScan = lpResource;
+
+ while (TRUE)
+ {
+// Get next command entry
+ wLen = mciEatCommandEntry (lpScan, NULL, &wID);
+
+ if (wID == MCI_COMMAND_HEAD)
+// Add an index to this command
+ *lpwScan++ = lpScan - lpResource;
+
+ else if (wID == MCI_END_COMMAND_LIST)
+ {
+// Mark the end of the table
+ *lpwScan = -1;
+ break;
+ }
+ lpScan += wLen;
+ }
+ UnlockResource (hResource);
+ return mciRegisterCommandTable (hResource, lpwIndex, wType, hExternal);
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciLoadTableType | If the table of the given type
+ * has not been loaded, register it
+ *
+ * @parm UINT | wType | The table type to load
+ *
+ * @rdesc Returns the command table index number that was assigned or -1
+ * on error.
+ */
+UINT PASCAL NEAR mciLoadTableType (
+UINT wType)
+{
+ UINT wID;
+ char buf[MCI_MAX_DEVICE_TYPE_LENGTH];
+ int nTypeLen;
+
+// Check to see if this table type is already loaded
+ for (wID = 0; wID < number_of_command_tables; ++wID)
+ if (command_tables[wID].wType == wType)
+ return wID;
+
+// Must load table
+// First look up what device type specific table to load for this type
+ if (wType < MCI_DEVTYPE_FIRST || wType > MCI_DEVTYPE_LAST)
+ return -1;
+
+// Load string that corresponds to table type
+ LoadString (ghInst, table_types[wType - MCI_DEVTYPE_FIRST],
+ buf, sizeof(buf));
+
+//Must be at least one character in type name
+ if ((nTypeLen = lstrlen (buf)) < 1)
+ return -1;
+
+// Register the table with MCI
+ return mciLoadCommandResource (ghInst, buf, wType);
+}
+
+/*
+ * @doc DDK MCI
+ *
+ * @api BOOL | mciFreeCommandResource | Frees the memory used
+ * by the specified command table.
+ *
+ * @parm UINT | wTable | The table index returned from a previous call to
+ * mciLoadCommandResource.
+ *
+ * @rdesc FALSE if the table index is not valid, TRUE otherwise.
+ *
+ */
+BOOL WINAPI mciFreeCommandResource (
+UINT wTable)
+{
+ UINT wID;
+ HGLOBAL hResource;
+ UINT FAR* lpwIndex;
+
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ {
+ DPRINTF(("mciFreeCommandResource INFO: Free table %d\r\n", wTable));
+ DPRINTF(("mciFreeCommandResource INFO: Lockcount is %d\r\n",
+ command_tables[wTable].wLockCount));
+ }
+#endif
+
+/* Validate input -- do not let the core table be free'd */
+ if (wTable <= 0 || wTable >= number_of_command_tables)
+ {
+#ifdef DEBUG
+// wTable == -1 is OK
+ if (wTable != -1)
+ DOUT ("mciFreeCommandResource: Bad table number\r\n");
+#endif
+ return FALSE;
+ }
+
+// If this table is being used elsewhere then keep it around
+ for (wID = 1; wID < MCI_wNextDeviceID; ++wID)
+ if (MCI_lpDeviceList[wID] != NULL)
+ if (MCI_lpDeviceList[wID]->wCustomCommandTable == wTable ||
+ MCI_lpDeviceList[wID]->wCommandTable == wTable)
+ {
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ DOUT ("mciFreeCommandResource INFO: table in use\r\n");
+#endif
+ return FALSE;
+ }
+
+#if 0
+/* Search the list of tables */
+ for (wID = 0; wID < number_of_command_tables; ++wID)
+
+/* If this resource is still in use, keep it around */
+ if (command_tables[wID].hResource == hResource)
+ {
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ DOUT ("mciFreeCommandResource INFO: resource in use\r\n");
+#endif
+ return FALSE;
+ }
+#endif
+
+ hResource = command_tables[wTable].hResource;
+ command_tables[wTable].hResource = NULL;
+
+ lpwIndex = command_tables[wTable].lpwIndex;
+ command_tables[wTable].lpwIndex = NULL;
+ command_tables[wTable].wType = 0;
+
+
+ FreeResource (hResource);
+ mciFree (lpwIndex);
+
+ if (command_tables[wTable].hModule != NULL)
+ FreeLibrary (command_tables[wTable].hModule);
+
+// Make space at top of list
+ if (wTable == number_of_command_tables - 1)
+ --number_of_command_tables;
+
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ DPRINTF(("mciFreeCommandResource INFO: number_of_command_tables: %u\r\n",
+ number_of_command_tables));
+#endif
+
+ return TRUE;
+}
+
+#ifdef DEBUG
+void PASCAL NEAR mciCheckLocks (void)
+{
+ UINT wTable;
+
+ if (DebugmciSendCommand <= 2)
+ return;
+
+ for (wTable = 0; wTable < number_of_command_tables; ++wTable)
+ {
+ if (command_tables[wTable].hResource == NULL)
+ continue;
+ DPRINTF(("mciCheckLocks INFO: table %u ", wTable));
+ DPRINTF(("user: %x ",
+ GlobalFlags (command_tables[wTable].hResource) & GMEM_LOCKCOUNT));
+ DPRINTF(("mci: %u ", command_tables[wTable].wLockCount));
+ if (GlobalFlags (command_tables[wTable].hResource) & GMEM_DISCARDABLE)
+ DPRINTF(("discardable\r\n"));
+ else
+ DPRINTF(("NOT discardable\r\n"));
+ }
+}
+#endif
+
+/*
+ * @doc INTERNAL MCI
+ * @func BOOL | mciUnlockCommandTable | Unlocks the command table given by
+ * a table index
+ *
+ * @parm UINT | wCommandTable | Table to unlock
+ *
+ * @rdesc TRUE if success, FALSE otherwise
+ *
+ * @comm Used external to this module by mci.c
+ *
+ */
+BOOL PASCAL NEAR mciUnlockCommandTable (
+UINT wCommandTable)
+{
+ UnlockResource(command_tables[wCommandTable].hResource);
+#ifdef DEBUG
+ --command_tables[wCommandTable].wLockCount;
+ if (DebugmciSendCommand > 2)
+ {
+ DPRINTF(("mciUnlockCommandTable INFO: table %d\r\n", wCommandTable));
+ DOUT ("mciUnlockCommandTable INFO: check locks...\r\n");
+ mciCheckLocks();
+ }
+#endif
+ return TRUE;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func LPSTR | FindCommandInTable | Look up the given
+ * command string in the GIVEN parser command table
+ *
+ * @parm UINT | wTable | Command table to use
+ *
+ * @parm LPCSTR | lpstrCommand | The command to look up. It must
+ * be in lower case with no leading or trailing blanks and with at
+ * least one character.
+ *
+ * @parm UINT FAR * | lpwMessage | The message corresponding to the command
+ * Returned to caller.
+ *
+ * @rdesc NULL if the command is unknown or on error, otherwise a pointer to
+ * the command list for the input command string.
+ *
+ * @comm If the command is found, the command resource will be locked on exit.
+ *
+ */
+LPSTR PASCAL NEAR FindCommandInTable (
+UINT wTable,
+LPCSTR lpstrCommand,
+UINT FAR * lpwMessage)
+{
+ UINT FAR* lpwIndex;
+ LPSTR lpResource, lpstrThisCommand;
+ UINT wMessage;
+
+/* Validate table */
+
+ if (wTable >= number_of_command_tables)
+ {
+// Check the core table but its not yet loaded
+ if (wTable == 0)
+ {
+// Try to load it
+ if (mciLoadCommandResource (ghInst, szCoreTable, 0) == -1)
+ {
+ DOUT ("FindCommandInTable: cannot load core table\r\n");
+ return NULL;
+ }
+ } else
+ {
+ DOUT ("MCI FindCommandInTable: invalid table ID\r\n");
+ return NULL;
+ }
+
+ }
+
+ if ((lpResource = LockResource (command_tables[wTable].hResource)) == NULL)
+ {
+ DOUT ("MCI FindCommandInTable: Cannot lock table resource\r\n");
+ return NULL;
+ }
+#ifdef DEBUG
+ ++command_tables[wTable].wLockCount;
+#endif
+
+// Look at each command in the table
+ lpwIndex = command_tables[wTable].lpwIndex;
+ if (lpwIndex == NULL)
+ {
+ DOUT ("MCI FindCommandInTable: null command table index\r\n");
+ return NULL;
+ }
+
+ while (*lpwIndex != -1)
+ {
+ DWORD dwMessage;
+
+ lpstrThisCommand = *lpwIndex++ + lpResource;
+
+// Get message number from the table
+ mciEatCommandEntry (lpstrThisCommand, &dwMessage, NULL);
+ wMessage = (UINT)dwMessage;
+
+// Does this command match the input?
+
+// String case
+ if (HIWORD (lpstrCommand) != 0 &&
+ lstrcmpi (lpstrThisCommand, lpstrCommand) == 0 ||
+
+// Message case
+ HIWORD (lpstrCommand) == 0 &&
+ wMessage == LOWORD ((DWORD)lpstrCommand))
+ {
+// Retain the locked resource pointer
+ command_tables[wTable].lpResource = lpResource;
+
+// Address the message ID which comes after the command name
+ if (lpwMessage != NULL)
+ *lpwMessage = wMessage;
+// Leave table locked on exit
+ return lpstrThisCommand;
+ }
+
+// Strings don't match, go to the next command in the table
+ }
+
+ UnlockResource (command_tables[wTable].hResource);
+#ifdef DEBUG
+ --command_tables[wTable].wLockCount;
+#endif
+
+ return NULL;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func LPSTR | FindCommandItem | Look up the given
+ * command string in the parser command tables
+ *
+ * @parm UINT | wDeviceID | The device ID used for this command.
+ * If 0 then only the system core command table is searched.
+ *
+ * @parm LPCSTR | lpstrType | The type name of the device
+ *
+ * @parm LPCSTR | lpstrCommand | The command to look up. It must
+ * be in lower case with no leading or trailing blanks and with at
+ * least one character. If the HIWORD is 0 then the LOWORD contains
+ * the command message ID instead of a command name and the function is
+ * merely to find the command list pointer.
+ *
+ * If the high word is 0 then the low word is an command ID value instead
+ * of a command name
+ *
+ * @parm UINT FAR* | lpwMessage | The message corresponding to the command
+ * Returned to caller.
+ *
+ * @parm UINT FAR* | lpwTable | The table index in which the command was found
+ * Returned to caller.
+ *
+ * @rdesc NULL if the command is unknown, otherwise a pointer to
+ * the command list for the input command string.
+ */
+LPSTR PASCAL NEAR FindCommandItem (
+UINT wDeviceID,
+LPCSTR lpstrType,
+LPCSTR lpstrCommand,
+UINT FAR* lpwMessage,
+UINT FAR* lpwTable)
+{
+ LPSTR lpCommand;
+ UINT wTable;
+ LPMCI_DEVICE_NODE nodeWorking;
+
+// Only check hiword per comments above
+ if (HIWORD (lpstrCommand) != NULL && *lpstrCommand == '\0')
+ {
+ DOUT ("MCI FindCommandItem: lpstrCommand is NULL or empty string\r\n");
+ return NULL;
+ }
+
+// If a specific device ID was specified then look in any custom table
+// or type table
+ if (wDeviceID != 0 && wDeviceID != MCI_ALL_DEVICE_ID)
+ {
+// If the device ID is valid
+ if (!MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ DOUT ("MCI FindCommandItem: Invalid device ID\r\n");
+ return NULL;
+ }
+ nodeWorking = MCI_lpDeviceList[wDeviceID];
+
+// If there is a custom command table then use it
+ if ((wTable = nodeWorking->wCustomCommandTable) != -1)
+ {
+ lpCommand = FindCommandInTable (wTable, lpstrCommand, lpwMessage);
+ if (lpCommand != NULL)
+ goto exit;
+ }
+// Get the device type table from the existing device
+// Relies on mciReparseCommand in mciLoadDevice to catch all device type
+// tables when device is not yet open.
+ if ((wTable = nodeWorking->wCommandTable) != -1)
+ {
+ lpCommand = FindCommandInTable (wTable, lpstrCommand, lpwMessage);
+ if (lpCommand != NULL)
+ goto exit;
+ }
+ }
+
+// If no match was found in the device or type specific tables
+// Look in the core table
+ wTable = 0;
+ lpCommand = FindCommandInTable (wTable, lpstrCommand, lpwMessage);
+ if (lpCommand == NULL)
+ wTable = -1;
+
+exit:
+ if (lpwTable != NULL)
+ *lpwTable = wTable;
+
+#ifdef DEBUG
+ if (DebugmciSendCommand > 2)
+ {
+ DOUT ("FindCommandItem INFO: check locks...\r\n");
+ mciCheckLocks();
+ }
+#endif
+
+ return lpCommand;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func LPSTR | mciCheckToken | Check to see if the command item matches
+ * the given string, allowing multiple blanks in the input parameter to
+ * match a corresponding single blank in the command token and ignoring
+ * case.
+ *
+ * @parm LPCSTR | lpstrToken | The command token to check
+ *
+ * @parm LPCSTR | lpstrParam | The input parameter
+ *
+ * @rdesc NULL if no match, otherwise points to the first character
+ * after the parameter
+ *
+ */
+STATICFN LPSTR PASCAL NEAR
+mciCheckToken(
+ LPCSTR lpstrToken,
+ LPCSTR lpstrParam
+ )
+{
+/* Check for legal input */
+ if (lpstrToken == NULL || lpstrParam == NULL)
+ return NULL;
+
+ while (*lpstrToken != '\0' && MCI_TOLOWER(*lpstrParam) == *lpstrToken)
+ {
+// If the token contains a blank, allow more than one blank in the
+// parameter
+ if (*lpstrToken == ' ')
+ while (*lpstrParam == ' ')
+ ++lpstrParam;
+ else
+ *lpstrParam++;
+ *lpstrToken++;
+ }
+ if (*lpstrToken != '\0'|| (*lpstrParam != '\0' && *lpstrParam != ' '))
+ return NULL;
+ else
+ return (LPSTR)lpstrParam;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @api BOOL | mciParseInteger | Parse the given integer
+ *
+ * @parm LPSTR FAR * | lplpstrInput | The string containing the argument.
+ * It is updated and returned to the caller pointing to the first character
+ * after the argument or to the first character that is in error.
+ *
+ * @parm LPDWORD | lpdwArgument | The place to put the output
+ *
+ * @rdesc Returns TRUE if not error
+ *
+ * @comm If there are colons in the input (':') the result is "colonized".
+ * This means that each time a colon is read, the current result is written
+ * and any subsequent digits are shifted left one byte. No one "segment"
+ * can be more than 0xFF. For example, "0:1:2:3" is parsed to 0x03020100.
+ *
+ */
+STATICFN BOOL PASCAL NEAR
+mciParseInteger(
+ LPSTR FAR * lplpstrInput,
+ LPDWORD lpdwArgument
+ )
+{
+ LPSTR lpstrInput = *lplpstrInput;
+ BOOL fDigitFound;
+ DWORD dwResult;
+ LPSTR lpstrResult = (LPSTR)lpdwArgument;
+ int nDigitPosition = 0;
+ BOOL bSigned = FALSE;
+
+// Leading blanks have been removed by mciParseParams
+
+ if (*lpstrInput == '-')
+ {
+ ++lpstrInput;
+ bSigned = TRUE;
+ }
+
+// Read digits
+ *lpdwArgument = 0; /* Initialize */
+ dwResult = 0;
+ fDigitFound = FALSE; /* Initialize */
+ while (*lpstrInput >= '0' && *lpstrInput <= '9' || *lpstrInput == ':')
+ {
+// ':' indicates colonized data
+ if (*lpstrInput == ':')
+ {
+// Cannot mix colonized and signed forms
+ if (bSigned)
+ {
+ DOUT ("Bad integer: mixing signed and colonized forms\r\n");
+ return FALSE;
+ }
+// Check for overflow in accumulated colonized byte
+ if (dwResult > 0xFF)
+ return FALSE;
+
+// Copy and move to next byte converted in output
+ *lpstrResult++ = (char)dwResult;
+ ++lpstrInput;
+// Initialize next colonized byte
+ dwResult = 0;
+ ++nDigitPosition;
+// Only allow four colonized components
+ if (nDigitPosition > 3)
+ {
+ DOUT ("Bad integer: Too many colonized components\r\n");
+ return FALSE;
+ }
+ } else
+ {
+ char cDigit = (char)(*lpstrInput++ - '0');
+// Satisfies condition that at least one digit must be read
+ fDigitFound = TRUE;
+
+ if (dwResult > 0xFFFFFFFF / 10)
+// Overflow if multiply was to occur
+ return FALSE;
+ else
+// Multiply for next digit
+ dwResult *= 10;
+
+// Add new digit
+ dwResult += cDigit;
+ }
+ }
+ if (nDigitPosition == 0)
+ {
+// No colonized components
+ if (bSigned)
+ {
+// Check for overflow from negation
+ if (dwResult > 0x7FFFFFFF)
+ return FALSE;
+// Negate result because a '-' sign was parsed
+ dwResult = -dwResult;
+ }
+
+ *lpdwArgument = dwResult;
+ }
+ else
+// Store last colonized component
+ {
+// Check for overflow
+ if (dwResult > 0xFF)
+ return FALSE;
+// Store component
+ *lpstrResult = (char)dwResult;
+ }
+
+ *lplpstrInput = lpstrInput;
+
+/*
+If there were no digits or if the digits were followed by a character
+other than a blank or a '\0', then return a syntax error.
+*/
+ return fDigitFound && (!*lpstrInput || *lpstrInput == ' ');
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func BOOL | mciParseConstant | Parse the given integer
+ *
+ * @parm LPSTR FAR * | lplpstrInput | The string containing the argument.
+ * It is updated and returned to the caller pointing to the first character
+ * after the argument or to the first character that is in error.
+ *
+ * @parm LPDWORD | lpdwArgument | The place to put the output
+ *
+ * @parm LPSTR | lpItem | Pointer into command table.
+ *
+ * @rdesc Returns TRUE if not error
+ *
+ */
+STATICFN BOOL PASCAL NEAR
+mciParseConstant(
+ LPSTR FAR * lplpstrInput,
+ LPDWORD lpdwArgument,
+ LPSTR lpItem
+ )
+{
+ LPSTR lpPrev;
+ DWORD dwValue;
+ UINT wID;
+
+// Skip past constant header
+ lpItem += mciEatCommandEntry (lpItem, &dwValue, &wID);
+
+ while (TRUE)
+ {
+ LPSTR lpstrAfter;
+
+ lpPrev = lpItem;
+
+ lpItem += mciEatCommandEntry (lpItem, &dwValue, &wID);
+
+ if (wID == MCI_END_CONSTANT)
+ break;
+
+ if ((lpstrAfter = mciCheckToken (lpPrev, *lplpstrInput)) != NULL)
+ {
+ *lpdwArgument = dwValue;
+ *lplpstrInput = lpstrAfter;
+ return TRUE;
+ }
+
+ }
+
+ return mciParseInteger (lplpstrInput, lpdwArgument);
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciParseArgument | Parse the given argument
+ *
+ * @parm DWORD | dwValue | The argument value
+ *
+ * @parm UINT | wID | The argument ID
+ *
+ * @parm LPSTR FAR * | lplpstrOutput | The string containing the argument.
+ * It is updated and returned to the caller pointing to the first character
+ * after the argument or to the first character that is in error.
+ *
+ * @parm LPDWORD | lpdwFlags | The output flags
+ *
+ * @parm LPDWORD | lpArgument | The place to put the output
+ *
+ * @rdesc Returns 0 if no error or
+ * @flag MCIERR_BAD_INTEGER | An integer argument could not be parsed
+ * @flag MCIERR_MISSING_STRING_ARGUMENT | An expected string argument
+ * @flag MCIERR_PARM_OVERFLOW | The output buffer was a NULL pointer
+ * was missing
+ *
+ */
+STATICFN UINT PASCAL NEAR
+mciParseArgument(
+ DWORD dwValue,
+ UINT wID,
+ LPSTR FAR * lplpstrOutput,
+ LPDWORD lpdwFlags,
+ LPSTR lpArgument,
+ LPSTR lpCurrentCommandItem
+ )
+{
+LPSTR lpstrInput = *lplpstrOutput;
+UINT wRetval = 0;
+
+/* Switch on the argument type */
+ switch (wID)
+ {
+
+// The parameter is a flag
+ case MCI_FLAG:
+ break; /* switch */
+
+ case MCI_CONSTANT:
+ if (*lpstrInput == '\0')
+ wRetval = MCIERR_NO_INTEGER;
+ else if (!mciParseConstant (&lpstrInput, (LPDWORD)lpArgument,
+ lpCurrentCommandItem))
+ wRetval = MCIERR_BAD_CONSTANT;
+ break;
+
+/* The parameter has an integer argument, try to parse it */
+ case MCI_INTEGER:
+ if (!mciParseInteger (&lpstrInput, (LPDWORD)lpArgument))
+ wRetval = MCIERR_BAD_INTEGER;
+
+ break; /* switch */
+ case MCI_RECT:
+ {
+// Read in four RECT components. Resulting structure is the
+// same as a Windows RECT
+ long lTemp;
+ int n;
+ for (n = 0; n < 4; ++n)
+ {
+ if (!mciParseInteger (&lpstrInput, &lTemp))
+ {
+ wRetval = MCIERR_BAD_INTEGER;
+ break;
+ }
+// Each component is a signed 16 bit number
+ if (lTemp > 32768 || lTemp < -32767)
+ {
+ wRetval = MCIERR_BAD_INTEGER;
+ break;
+ }
+ ((int FAR *)lpArgument)[n] = (int)lTemp;
+// Remove leading blanks before next digit
+ while (*lpstrInput == ' ') ++lpstrInput;
+ }
+ break;
+ }
+
+ case MCI_STRING:
+ {
+ LPSTR lpstrOutput;
+
+/* The parameter has an string argument, read it */
+
+// Leading blanks have been removed by mciParseParams
+
+/* Are there any non-blank characters left in the input? */
+ if (*lpstrInput == '\0')
+ {
+/* Return an error */
+ wRetval = MCIERR_MISSING_STRING_ARGUMENT;
+ break; /* switch */
+ }
+
+ if ((wRetval = mciEatToken (&lpstrInput, ' ', &lpstrOutput, FALSE))
+ != 0)
+ {
+ DOUT ("mciParseArgument: error parsing string\r\n");
+ return wRetval;
+ }
+
+ *(LPDWORD)lpArgument = (DWORD)lpstrOutput;
+
+// NOTE: mciSendString frees the output string after command execution
+// by calling mciParserFree
+
+ break; /* switch */
+ } /* case */
+ } /* switch */
+
+/* Update the output flags if there was no error */
+ if (wRetval == 0)
+ {
+ if (*lpdwFlags & dwValue)
+ {
+ if (wID == MCI_CONSTANT)
+ wRetval = MCIERR_FLAGS_NOT_COMPATIBLE;
+ else
+ wRetval = MCIERR_DUPLICATE_FLAGS;
+ } else
+ *lpdwFlags |= dwValue;
+ }
+/*
+ Return the input pointer pointing at the first character after
+ the argument or to the first character that is in error
+*/
+ *lplpstrOutput = lpstrInput;
+ return wRetval;
+}
+
+/*
+ * @doc MCI INTERNAL
+ * @func UINT | mciParseParams | Parse the command parameters
+ *
+ * @parm LPCSTR | lpstrParams | The parameter string
+ *
+ * @parm LPCSTR | lpCommandList | The command table description
+ * of the command tokens
+ *
+ * @parm LPDWORD | lpdwFlags | Return the parsed flags here
+ *
+ * @parm LPDWORD | lpdwOutputParams | Return the list of parameters here
+ *
+ * @parm UINT | wParamsSize | The size allocated for the parameter list
+ *
+ * @parm LPSTR FAR * FAR * | lpPointerList | A NULL terminated list of
+ * pointers allocated by this function that should be free'd when
+ * no longer needed. The list itself should be free'd also. In both
+ * cases, use mciFree().
+ *
+ * @parm UINT FAR* | lpwParsingError | If not NULL then if the command is
+ * 'open', unrecognized keywords return an error here, and the
+ * function return value is 0 (unless other errors occur). This
+ * is used to allow reparsing of the command by mciLoadDevice
+ *
+ * @rdesc Returns zero if successful or one of the following error codes:
+ * @flag MCIERR_PARM_OVERFLOW | Not enough space for parameters
+ * @flag MCIERR_UNRECOGNIZED_KEYWORD | Unrecognized keyword
+ *
+ * @comm Any syntax error, including missing arguments, will result in
+ * a non-zero error return and invalid output data.
+ *
+ */
+UINT PASCAL NEAR
+mciParseParams(
+ LPCSTR lpstrParams,
+ LPCSTR lpCommandList,
+ LPDWORD lpdwFlags,
+ LPSTR lpOutputParams,
+ UINT wParamsSize,
+ LPSTR FAR * FAR *lpPointerList,
+ UINT FAR* lpwOpenError
+ )
+{
+ LPSTR lpFirstCommandItem, lpCurrentCommandItem;
+ UINT wArgumentPosition, wErr, wLen, wID, wDefaultID;
+ DWORD dwValue, dwDefaultValue;
+ BOOL bOpenCommand;
+ LPSTR FAR *lpstrPointerList;
+ UINT wPointers = 0;
+ UINT wHeaderSize = 0;
+ LPSTR lpDefaultCommandItem = NULL;
+ UINT wDefaultArgumentPosition;
+
+ if (lpwOpenError != NULL)
+ *lpwOpenError = 0;
+
+// If the parameter pointer is NULL, return
+ if (lpstrParams == NULL)
+ {
+ DOUT ("Warning: lpstrParams is null in mciParseParams()\r\n");
+ return 0;
+ }
+
+ if ((lpstrPointerList =
+ mciAlloc ((MCI_MAX_PARAM_SLOTS + 1) * sizeof (LPSTR)))
+ == NULL)
+ {
+ *lpPointerList = NULL;
+ return MCIERR_OUT_OF_MEMORY;
+ }
+
+// If this is the "open" command then allow parameter errors
+ bOpenCommand = lstrcmpi (lpCommandList, szOpen) == 0;
+
+/* Clear all the flags */
+ *lpdwFlags = 0;
+
+/* Initialize the entry for the callback message window handle */
+ wHeaderSize += sizeof (DWORD);
+ if (wHeaderSize > wParamsSize)
+ {
+ wErr = MCIERR_PARAM_OVERFLOW;
+ goto error_exit;
+ }
+
+/* Skip past the header */
+ lpFirstCommandItem = (LPSTR)lpCommandList +
+ mciEatCommandEntry (lpCommandList, NULL, NULL);
+
+ wLen = mciEatCommandEntry (lpFirstCommandItem, &dwValue, &wID);
+/* Make room in lpdwOutputParams for the return arguments if any */
+ if (wID == MCI_RETURN)
+ {
+ lpFirstCommandItem += wLen;
+ wHeaderSize += mciGetParamSize (dwValue, wID);
+ if (wHeaderSize > wParamsSize)
+ {
+ wErr = MCIERR_PARAM_OVERFLOW;
+ goto error_exit;
+ }
+ }
+
+ lpOutputParams += wHeaderSize;
+
+// Scan the parameter string looking up each parameter in the given command
+// list
+
+ while (TRUE)
+ {
+ LPCSTR lpstrArgument = NULL;
+
+/* Remove leading blanks */
+ while (*lpstrParams == ' ') ++lpstrParams;
+
+/* Break at end of parameter string */
+ if (*lpstrParams == '\0') break;
+
+/* Scan for this parameter in the command list */
+ lpCurrentCommandItem = lpFirstCommandItem;
+
+ wLen = mciEatCommandEntry (lpCurrentCommandItem, &dwValue, &wID);
+
+ wArgumentPosition = 0;
+
+/* While there are more tokens in the Command List */
+ while (wID != MCI_END_COMMAND)
+ {
+/* Check for a default argument if not already read */
+ if (lpDefaultCommandItem == NULL &&
+ *lpCurrentCommandItem == '\0')
+ {
+// Remember default argument
+ lpDefaultCommandItem = lpCurrentCommandItem;
+ dwDefaultValue = dwValue;
+ wDefaultID = wID;
+ wDefaultArgumentPosition = wArgumentPosition;
+// break;
+ }
+/* Check to see if this token matches */
+ else if ((lpstrArgument =
+ mciCheckToken (lpCurrentCommandItem, lpstrParams)) != NULL)
+ break;
+
+/* This token did not match the input but advance the argument position */
+ wArgumentPosition += mciGetParamSize (dwValue, wID);
+
+/* Go to next token */
+ lpCurrentCommandItem += wLen;
+
+// Is this command parameter a constant?
+ if (wID == MCI_CONSTANT)
+// Skip constant list
+ do
+ lpCurrentCommandItem +=
+ mciEatCommandEntry (lpCurrentCommandItem, &dwValue, &wID);
+ while (wID != MCI_END_CONSTANT);
+
+ wLen = mciEatCommandEntry (lpCurrentCommandItem, &dwValue, &wID);
+ } /* while */
+
+/* If there were no matches */
+ if (lpstrArgument == NULL)
+ {
+// If a default argument exists then try it
+ if (lpDefaultCommandItem != NULL)
+ {
+ lpstrArgument = lpstrParams;
+ dwValue = dwDefaultValue;
+ wID = wDefaultID;
+ lpCurrentCommandItem = lpDefaultCommandItem;
+ wArgumentPosition = wDefaultArgumentPosition;
+ } else
+ {
+// Allow missing paramters on OPEN command if indicated by a non-null
+// lpwOpenError address
+ if (!bOpenCommand || lpwOpenError == NULL)
+ {
+ wErr = MCIERR_UNRECOGNIZED_KEYWORD;
+ goto error_exit;
+ } else
+ {
+// Skip the parameter if OPEN command
+ while (*lpstrParams != ' ' && *lpstrParams != '\0')
+ ++lpstrParams;
+ if (lpwOpenError != NULL)
+ *lpwOpenError = MCIERR_UNRECOGNIZED_KEYWORD;
+ continue;
+ }
+ }
+ }
+
+/* Is there room in the output buffer for this argument? */
+ if (wArgumentPosition + wHeaderSize + mciGetParamSize (dwValue, wID)
+ > wParamsSize)
+ {
+ DOUT ("mciParseParams: parameter space overflow\r\n");
+ wErr = MCIERR_PARAM_OVERFLOW;
+ goto error_exit;
+ }
+
+// Remove leading blanks
+ while (*lpstrArgument == ' ') ++lpstrArgument;
+
+/* Process this parameter, filling in any flags or arguments */
+ if ((wErr = mciParseArgument (dwValue, wID,
+ &lpstrArgument, lpdwFlags,
+ &lpOutputParams[wArgumentPosition],
+ lpCurrentCommandItem))
+ != 0)
+ goto error_exit;
+
+ lpstrParams = lpstrArgument;
+
+ if (wID == MCI_STRING)
+ {
+ if (wPointers >= MCI_MAX_PARAM_SLOTS)
+ {
+ DOUT ("Warning: Out of pointer list slots in mciParseParams\r\n");
+ break;
+ }
+
+ (DWORD)lpstrPointerList[wPointers++] =
+ *(LPDWORD)&lpOutputParams[wArgumentPosition];
+ }
+
+/* Continue reading the parameter string */
+ } /* while */
+
+// Terminate list
+ lpstrPointerList[wPointers] = NULL;
+// Copy reference for caller
+ *lpPointerList = lpstrPointerList;
+// Return Success
+ return 0;
+
+error_exit:
+ *lpPointerList = NULL;
+// Terminate list
+ lpstrPointerList[wPointers] = NULL;
+ mciParserFree (lpstrPointerList);
+ return wErr;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciParseCommand | This function converts an MCI
+ * control string to an MCI control message suitable for sending to
+ * <f mciSendCommand>. The input string usually comes from <f mciSendString>
+ * and always has the device name stripped off the front.
+ *
+ * @parm UINT | wDeviceID | Identifies the device. First searches the parsing
+ * table belonging to the driver.
+ * Then searches the command tables matching the type
+ * of the given device. Then searches the core command table.
+ *
+ * @parm LPSTR | lpstrCommand | An MCI control command without
+ * a device name prefix. There must be no leading or trailing
+ * blanks.
+ *
+ * @parm LPCSTR | lpstrDeviceName | The device name (second token on the
+ * command line). It is used to identify the device type.
+ *
+ * @parm LPSTR FAR * | lpCommandList | If not NULL then the address of
+ * the command list for the parsed command (if successful) is copied here.
+ * It is used later by mciSendString when parsing arguments
+ *
+ * @parm UINT FAR* | lpwTable | The table resource ID to be unlocked
+ * after parsing. Returned to caller.
+ *
+ * @rdesc Returns the command ID or 0 if not found.
+ *
+ */
+UINT PASCAL NEAR
+mciParseCommand(
+ UINT wDeviceID,
+ LPSTR lpstrCommand,
+ LPCSTR lpstrDeviceName,
+ LPSTR FAR * lpCommandList,
+ UINT FAR* lpwTable)
+{
+ LPSTR lpCommandItem;
+ UINT wMessage;
+
+// Put the command in lower case
+//!! mciToLower (lpstrCommand);
+
+// Look up lpstrCommand in the parser's command tables.
+ if ((lpCommandItem = FindCommandItem (wDeviceID, lpstrDeviceName,
+ lpstrCommand,
+ &wMessage, lpwTable))
+ == NULL)
+ return 0;
+
+/* Return the command list to the caller */
+ if (lpCommandList != NULL)
+ *lpCommandList = lpCommandItem;
+ else
+ DOUT ("Warning: NULL lpCommandList in mciParseCommanad\r\n");
+
+ return wMessage;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func void | mciParserFree | Free any buffers allocated to
+ * receive string arguments.
+ *
+ * @parm LPSTR FAR * | lpstrPointerList | A NULL terminated list of far
+ * pointers to strings to be free'd
+ *
+ */
+void PASCAL NEAR
+mciParserFree(
+ LPSTR FAR *lpstrPointerList
+ )
+{
+ LPSTR FAR *lpstrOriginal = lpstrPointerList;
+
+ if (lpstrPointerList == NULL)
+ return;
+
+ while (*lpstrPointerList != NULL)
+ mciFree (*lpstrPointerList++);
+
+ mciFree (lpstrOriginal);
+}
diff --git a/private/mvdm/wow16/mmsystem/mcisys.c b/private/mvdm/wow16/mmsystem/mcisys.c
new file mode 100644
index 000000000..3b04c020c
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mcisys.c
@@ -0,0 +1,1817 @@
+/*******************************Module*Header*********************************\
+* Module Name: mcisys.c
+*
+* Media Control Architecture System Functions
+*
+* Created: 2/28/90
+* Author: DLL (DavidLe)
+*
+* History:
+*
+* Copyright (c) 1990 Microsoft Corporation
+*
+\******************************************************************************/
+
+#include <windows.h>
+
+#define MMNOMIDI
+#define MMNOWAVE
+#define MMNOSOUND
+#define MMNOTIMER
+#define MMNOJOY
+#define MMNOSEQ
+#include "mmsystem.h"
+#define NOMIDIDEV
+#define NOWAVEDEV
+#define NOTIMERDEV
+#define NOJOYDEV
+#define NOSEQDEV
+#define NOTASKDEV
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "thunks.h"
+
+#ifndef STATICFN
+#define STATICFN
+#endif
+
+extern char far szOpen[]; // in MCI.C
+
+static SZCODE szNull[] = "";
+static SZCODE szMciExtensions[] = "mci extensions";
+
+#define MCI_EXTENSIONS szMciExtensions
+#define MCI_PROFILE_STRING_LENGTH 255
+
+//!!#define TOLOWER(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : c)
+
+// The device list is initialized on the first call to mciSendCommand or
+// to mciSendString
+BOOL MCI_bDeviceListInitialized;
+
+// The next device ID to use for a new device
+UINT MCI_wNextDeviceID = 1;
+
+// The list of MCI devices. This list grows and shrinks as needed.
+// The first offset MCI_lpDeviceList[0] is a placeholder and is unused
+// because device 0 is defined as no device.
+LPMCI_DEVICE_NODE FAR * MCI_lpDeviceList;
+
+// The current size of the list of MCI devices
+UINT MCI_wDeviceListSize;
+
+// The internal mci heap used by mciAlloc and mciFree
+HGLOBAL hMciHeap;
+
+// File containing MCI device profile strings
+extern char far szSystemIni[]; // in INIT.C
+
+// Name of the section contining MCI device profile strings
+static SZCODE szMCISectionName[] = "mci";
+
+static SZCODE szAllDeviceName[] = "all";
+
+static SZCODE szUnsignedFormat[] = "%u";
+
+static void PASCAL NEAR mciFreeDevice(LPMCI_DEVICE_NODE nodeWorking);
+
+BOOL NEAR PASCAL CouldBe16bitDrv(UINT wDeviceID)
+{
+ if (wDeviceID == MCI_ALL_DEVICE_ID) return TRUE;
+
+ if (MCI_VALID_DEVICE_ID(wDeviceID)) {
+ if (MCI_lpDeviceList[wDeviceID]->dwMCIFlags & MCINODE_16BIT_DRIVER) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL NEAR PASCAL Is16bitDrv(UINT wDeviceID)
+{
+ if (wDeviceID == MCI_ALL_DEVICE_ID) return FALSE;
+
+ if (MCI_VALID_DEVICE_ID(wDeviceID)) {
+ if (MCI_lpDeviceList[wDeviceID]->dwMCIFlags & MCINODE_16BIT_DRIVER) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//
+// Initialize device list
+// Called once by mciSendString or mciSendCommand
+// Returns TRUE on success
+BOOL NEAR PASCAL mciInitDeviceList(void)
+{
+
+ if ((hMciHeap = HeapCreate(0)) == 0)
+ {
+ DOUT("Mci heap create failed!\r\n");
+ return FALSE;
+ }
+ if ((MCI_lpDeviceList = mciAlloc (sizeof (LPMCI_DEVICE_NODE) *
+ (MCI_INIT_DEVICE_LIST_SIZE + 1))) != NULL)
+ {
+ MCI_wDeviceListSize = MCI_INIT_DEVICE_LIST_SIZE;
+ MCI_bDeviceListInitialized = TRUE;
+ return TRUE;
+ } else
+ {
+ DOUT ("MCIInit: could not allocate master MCI device list\r\n");
+ return FALSE;
+ }
+}
+
+/*
+ * @doc EXTERNAL MCI
+ * @api UINT | mciGetDeviceIDFromElementID | This function
+ * retrieves the MCI device ID corresponding to and element ID
+ *
+ * @parm DWORD | dwElementID | The element ID
+ *
+ * @parm LPCSTR | lpstrType | The type name this element ID belongs to
+ *
+ * @rdesc Returns the device ID assigned when it was opened and used in the
+ * <f mciSendCommand> function. Returns zero if the device name was not known,
+ * if the device was not open, or if there was not enough memory to complete
+ * the operation or if lpstrType is NULL.
+ *
+ */
+UINT WINAPI mciGetDeviceIDFromElementID (
+DWORD dwElementID,
+LPCSTR lpstrType)
+{
+ UINT wID;
+ LPMCI_DEVICE_NODE nodeWorking, FAR *nodeCounter;
+ char strTemp[MCI_MAX_DEVICE_TYPE_LENGTH];
+
+ if (lpstrType == NULL)
+ return 0;
+
+ wID = (UINT)mciMessage( THUNK_MCI_GETDEVIDFROMELEMID, dwElementID,
+ (DWORD)lpstrType, 0L, 0L );
+ if ( wID == 0 ) {
+
+ nodeCounter = &MCI_lpDeviceList[1];
+
+ for (wID = 1; wID < MCI_wNextDeviceID; ++wID)
+ {
+ nodeWorking = *nodeCounter++;
+
+ if (nodeWorking == NULL)
+ continue;
+
+ if (nodeWorking->dwMCIOpenFlags & MCI_OPEN_ELEMENT_ID &&
+ nodeWorking->dwElementID == dwElementID)
+
+ if (LoadString (ghInst, nodeWorking->wDeviceType, strTemp,
+ sizeof(strTemp)) != 0
+ && lstrcmpi ((LPSTR)strTemp, lpstrType) == 0) {
+
+ return (wID);
+ }
+ }
+ return 0;
+ }
+ return wID;
+}
+
+// Retrieves the device ID corresponding to the name of an opened device
+// matching the given task
+// This fn only looks for 16-bit devices
+// See mciGetDeviceIDInternalEx that looks for all of them
+UINT NEAR PASCAL mciGetDeviceIDInternal (
+LPCSTR lpstrName,
+HTASK hTask)
+{
+ UINT wID;
+ LPMCI_DEVICE_NODE nodeWorking, FAR *nodeCounter;
+
+ if (lstrcmpi (lpstrName, szAllDeviceName) == 0)
+ return MCI_ALL_DEVICE_ID;
+
+ if (MCI_lpDeviceList == NULL)
+ return 0;
+
+// Loop through the MCI device list
+ nodeCounter = &MCI_lpDeviceList[1];
+ for (wID = 1; wID < MCI_wNextDeviceID; ++wID)
+ {
+ nodeWorking = *nodeCounter++;
+
+ if (nodeWorking == NULL)
+ continue;
+
+// If this device does not have a name then skip it
+ if (nodeWorking->dwMCIOpenFlags & MCI_OPEN_ELEMENT_ID)
+ continue;
+
+// If the names match
+ if (lstrcmpi(nodeWorking->lpstrName, lpstrName) == 0)
+
+// If the device belongs to the indicated task
+ if (nodeWorking->hOpeningTask == hTask)
+// Return this device ID
+ return wID;
+ }
+
+ return 0;
+}
+
+/*
+ * @doc EXTERNAL MCI
+ * @api UINT | mciGetDeviceID | This function retrieves the device
+ * ID corresponding to the name of an open MCI device.
+ *
+ * @parm LPCSTR | lpstrName | Specifies the device name used to open the
+ * MCI device.
+ *
+ * @rdesc Returns the device ID assigned when the device was opened.
+ * Returns zero if the device name isn't known,
+ * if the device isn't open, or if there was insufficient memory to complete
+ * the operation. Each compound device element has a unique device ID.
+ * The ID of the "all" device is MCI_ALL_DEVICE_ID.
+ *
+ * @xref MCI_OPEN
+ *
+ */
+UINT WINAPI mciGetDeviceID (
+LPCSTR lpstrName)
+{
+ UINT wDevID;
+
+ /*
+ ** Try the 32 bit side first
+ */
+ wDevID = (UINT)mciMessage( THUNK_MCI_GETDEVICEID, (DWORD)lpstrName,
+ 0L, 0L, 0L );
+ if ( wDevID == 0 ) {
+
+ /*
+ ** The 32 bit call failed so let the 16 bit side have a go.
+ */
+ wDevID = mciGetDeviceIDInternal (lpstrName, GetCurrentTask());
+
+ }
+
+ return wDevID;
+}
+
+//
+// This function is same as mciGetDeviceID but it won't call GetCurrentTask
+// Used when mci needs to verify the dev alias had not been allocated yet
+//
+//
+
+UINT NEAR PASCAL mciGetDeviceIDInternalEx(
+LPCSTR lpstrName,
+HTASK hTask)
+{
+ UINT uiDevID;
+
+ uiDevID = (UINT)mciMessage( THUNK_MCI_GETDEVICEID, (DWORD)lpstrName,
+ 0L, 0L, 0L );
+ if (0 == uiDevID) {
+
+ uiDevID = mciGetDeviceIDInternal(lpstrName, hTask);
+ }
+
+ return uiDevID;
+}
+
+
+/*
+ * @doc EXTERNAL MCI
+ * @api HTASK | mciGetCreatorTask | This function retrieves the creator task
+ * corresponding with the device ID passed.
+ *
+ * @parm UINT | wDeviceID | Specifies the device ID whose creator task is to
+ * be returned.
+ *
+ * @rdesc Returns the creator task responsible for opening the device, else
+ * NULL if the device ID passed is invalid.
+ *
+ */
+HTASK WINAPI mciGetCreatorTask (
+UINT wDeviceID)
+{
+ /*
+ ** Is this a 16 bit device ID
+ */
+ if (Is16bitDrv(wDeviceID)) {
+
+ return MCI_lpDeviceList[wDeviceID]->hCreatorTask;
+ }
+
+ /*
+ ** No, so pass it on to the 32 bit code.
+ */
+
+ return (HTASK)mciMessage( THUNK_MCI_GETCREATORTASK, (DWORD)wDeviceID,
+ 0L, 0L, 0L );
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func BOOL | mciDeviceMatch | Match the first string with the second.
+ * Any single trailing digit on the first string is ignored. Each string
+ * must have at least one character
+ *
+ * @parm LPCSTR | lpstrDeviceName | The device name, possibly
+ * with trailing digits but no blanks.
+ *
+ * @parm LPCSTR | lpstrDeviceType | The device type with no trailing digits
+ * or blanks
+ *
+ * @rdesc TRUE if the strings match the above test, FALSE otherwise
+ *
+ */
+STATICFN BOOL PASCAL NEAR
+mciDeviceMatch(
+ LPCSTR lpstrDeviceName,
+ LPCSTR lpstrDeviceType
+ )
+{
+ BOOL bAtLeastOne;
+
+ for (bAtLeastOne = FALSE;;)
+ if (!*lpstrDeviceType)
+ break;
+ else if (!*lpstrDeviceName || ((BYTE)(WORD)(DWORD)AnsiLower((LPSTR)(DWORD)(WORD)(*lpstrDeviceName++)) != (BYTE)(WORD)(DWORD)AnsiLower((LPSTR)(DWORD)(WORD)(*lpstrDeviceType++))))
+ return FALSE;
+ else
+ bAtLeastOne = TRUE;
+ if (!bAtLeastOne)
+ return FALSE;
+ for (; *lpstrDeviceName; lpstrDeviceName++)
+ if ((*lpstrDeviceName < '0') || (*lpstrDeviceName > '9'))
+ return FALSE;
+ return TRUE;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciLookUpType | Look up the type given a type name
+ *
+ * @parm LPCSTR | lpstrTypeName | The type name to look up. Trailing
+ * digits are ignored.
+ *
+ * @rdesc The MCI type number (MCI_DEVTYPE_<x>) or 0 if not found
+ *
+!! * @comm Converts the input string to lower case as a side effect
+ *
+ */
+UINT PASCAL NEAR mciLookUpType (
+LPCSTR lpstrTypeName)
+{
+ UINT wType;
+ char strType[MCI_MAX_DEVICE_TYPE_LENGTH];
+
+//!! mciToLower (lpstrTypeName);
+
+ for (wType = MCI_DEVTYPE_FIRST; wType <= MCI_DEVTYPE_LAST; ++wType)
+ {
+ if (LoadString (ghInst, wType, strType, sizeof(strType)) == 0)
+ {
+ DOUT ("mciLookUpType: could not load string for type\r\n");
+ continue;
+ }
+
+ if (mciDeviceMatch (lpstrTypeName, strType))
+ return wType;
+ }
+ return 0;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func DWORD | mciSysinfo | Get system information about a device
+ *
+ * @parm UINT | wDeviceID | Device ID, may be 0
+ *
+ * @parm DWORD | dwFlags | SYSINFO flags
+ *
+ * @parm LPMCI_SYSINFO_PARMS | lpSysinfo | SYSINFO parameters
+ *
+ * @rdesc 0 if successful, otherwise error code
+ *
+ */
+DWORD PASCAL NEAR mciSysinfo (
+UINT wDeviceID,
+DWORD dwFlags,
+LPMCI_SYSINFO_PARMS lpSysinfo)
+{
+ UINT wCounted;
+ char strBuffer[MCI_PROFILE_STRING_LENGTH];
+ LPSTR lpstrBuffer = (LPSTR)strBuffer, lpstrStart;
+
+ if (dwFlags & MCI_SYSINFO_NAME && lpSysinfo->dwNumber == 0)
+ return MCIERR_OUTOFRANGE;
+
+ if (lpSysinfo->lpstrReturn == NULL || lpSysinfo->dwRetSize == 0)
+ return MCIERR_PARAM_OVERFLOW;
+
+ if (dwFlags & MCI_SYSINFO_NAME && dwFlags & MCI_SYSINFO_QUANTITY)
+ return MCIERR_FLAGS_NOT_COMPATIBLE;
+
+ if (dwFlags & MCI_SYSINFO_INSTALLNAME)
+ {
+ LPMCI_DEVICE_NODE nodeWorking;
+
+ if (wDeviceID == MCI_ALL_DEVICE_ID)
+ return MCIERR_CANNOT_USE_ALL;
+ if (!MCI_VALID_DEVICE_ID(wDeviceID))
+ return MCIERR_INVALID_DEVICE_NAME;
+
+ nodeWorking = MCI_lpDeviceList[wDeviceID];
+ if ((DWORD)lstrlen (nodeWorking->lpstrInstallName) >= lpSysinfo->dwRetSize)
+ return MCIERR_PARAM_OVERFLOW;
+ lstrcpy (lpSysinfo->lpstrReturn, nodeWorking->lpstrInstallName);
+ return 0;
+ } else if (!(dwFlags & MCI_SYSINFO_OPEN))
+ {
+ if (wDeviceID != MCI_ALL_DEVICE_ID && lpSysinfo->wDeviceType == 0)
+ return MCIERR_DEVICE_TYPE_REQUIRED;
+
+ if ((dwFlags & (MCI_SYSINFO_QUANTITY | MCI_SYSINFO_NAME)) == 0)
+ return MCIERR_MISSING_PARAMETER;
+ GetPrivateProfileString (szMCISectionName, NULL, szNull,
+ lpstrBuffer, MCI_PROFILE_STRING_LENGTH,
+ szSystemIni);
+ wCounted = 0;
+ while (TRUE)
+ {
+ if (dwFlags & MCI_SYSINFO_QUANTITY)
+ {
+ if (*lpstrBuffer == '\0')
+ {
+ *(LPDWORD)lpSysinfo->lpstrReturn = (DWORD)wCounted;
+ return MCI_INTEGER_RETURNED;
+ }
+ if (wDeviceID == MCI_ALL_DEVICE_ID ||
+ mciLookUpType (lpstrBuffer) == lpSysinfo->wDeviceType)
+ ++wCounted;
+// Skip past the terminating '\0'
+ while (*lpstrBuffer != '\0')
+ *lpstrBuffer++;
+ lpstrBuffer++;
+ } else if (dwFlags & MCI_SYSINFO_NAME)
+ {
+ if (wCounted == (UINT)lpSysinfo->dwNumber)
+ {
+ lstrcpy (lpSysinfo->lpstrReturn, lpstrStart);
+ return 0L;
+ } else if (*lpstrBuffer == '\0')
+ return MCIERR_OUTOFRANGE;
+ else
+ {
+ lpstrStart = lpstrBuffer;
+ if (wDeviceID == MCI_ALL_DEVICE_ID ||
+ mciLookUpType (lpstrBuffer) == lpSysinfo->wDeviceType)
+ ++wCounted;
+// Skip past the terminating '\0'
+ while (*lpstrBuffer != '\0')
+ *lpstrBuffer++;
+ lpstrBuffer++;
+ }
+ }
+ }
+ } else
+// Process MCI_SYSINFO_OPEN cases
+ {
+ UINT wID;
+ HTASK hCurrentTask = GetCurrentTask();
+ LPMCI_DEVICE_NODE Node;
+
+ if (wDeviceID != MCI_ALL_DEVICE_ID &&
+ lpSysinfo->wDeviceType == 0)
+ return MCIERR_DEVICE_TYPE_REQUIRED;
+
+ if ((dwFlags & (MCI_SYSINFO_QUANTITY | MCI_SYSINFO_NAME)) == 0)
+ return MCIERR_MISSING_PARAMETER;
+
+ wCounted = 0;
+ for (wID = 1; wID < MCI_wNextDeviceID; ++wID)
+ {
+ if ((Node = MCI_lpDeviceList[wID]) == 0)
+ continue;
+
+ if (wDeviceID == MCI_ALL_DEVICE_ID &&
+ Node->hOpeningTask == hCurrentTask)
+ ++wCounted;
+ else
+ {
+ if (Node->wDeviceType == lpSysinfo->wDeviceType &&
+ Node->hOpeningTask == hCurrentTask)
+ ++wCounted;
+ }
+ if (dwFlags & MCI_SYSINFO_NAME &&
+ wCounted == (UINT)lpSysinfo->dwNumber)
+ {
+ lstrcpy (lpSysinfo->lpstrReturn, Node->lpstrName);
+ return 0L;
+ }
+ }
+ if (dwFlags & MCI_SYSINFO_NAME)
+ {
+ if (lpSysinfo->lpstrReturn != NULL)
+ lpSysinfo->lpstrReturn = '\0';
+ return MCIERR_OUTOFRANGE;
+
+ } else if (dwFlags & MCI_SYSINFO_QUANTITY &&
+ lpSysinfo->lpstrReturn != NULL &&
+ lpSysinfo->dwRetSize >= 4)
+
+ *(LPDWORD)lpSysinfo->lpstrReturn = wCounted;
+ }
+ return MCI_INTEGER_RETURNED;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | wAddDeviceNodeToList | Add the given global handle into the
+ * MCI device table and return that entry's ID#
+ *
+ * @parm LPMCI_DEVICE_NODE | node | device description
+ *
+ * @rdesc The ID value for this device or 0 if there is no memory to expand
+ * the device list
+ *
+ */
+STATICFN UINT PASCAL NEAR
+wAddDeviceNodeToList(
+ LPMCI_DEVICE_NODE node
+ )
+{
+ UINT wDeviceID = node->wDeviceID;
+ LPMCI_DEVICE_NODE FAR *lpTempList;
+ UINT iReallocSize;
+
+ while (wDeviceID >= MCI_wDeviceListSize)
+ {
+ // The list is full so try to grow it
+ iReallocSize = MCI_wDeviceListSize + 1 + MCI_DEVICE_LIST_GROW_SIZE;
+ iReallocSize *= sizeof(LPMCI_DEVICE_NODE);
+ if ((lpTempList = mciReAlloc(MCI_lpDeviceList, iReallocSize)) == NULL)
+ {
+ DOUT ("wReserveDeviceID: cannot grow device list\r\n");
+ return 0;
+ }
+ MCI_lpDeviceList = lpTempList;
+ MCI_wDeviceListSize += MCI_DEVICE_LIST_GROW_SIZE;
+ }
+
+ if (wDeviceID >= MCI_wNextDeviceID) {
+ MCI_wNextDeviceID = wDeviceID + 1;
+ }
+
+ MCI_lpDeviceList[wDeviceID] = node;
+
+ return wDeviceID;
+}
+
+//
+// Allocate space for the given string and assign the name to the given
+// device.
+// Return FALSE if could not allocate memory
+//
+STATICFN BOOL PASCAL NEAR
+mciAddDeviceName(
+ LPMCI_DEVICE_NODE nodeWorking,
+ LPCSTR lpDeviceName
+ )
+{
+ nodeWorking->lpstrName = mciAlloc(lstrlen(lpDeviceName)+1);
+
+ if (nodeWorking->lpstrName == NULL)
+ {
+ DOUT ("mciAddDeviceName: Out of memory allocating device name\r\n");
+ return FALSE;
+ }
+
+ // copy device name to mci node and lowercase it
+
+ lstrcpy(nodeWorking->lpstrName, lpDeviceName);
+//!! mciToLower(nodeWorking->lpstrName);
+
+ return TRUE;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciAllocateNode | Allocate a new driver entry
+ *
+ * @parm DWORD | dwFlags | As sent with MCI_OPEN message
+ * @parm LPCSTR | lpDeviceName | The device name
+ * @parm LPMCI_DEVICE_NODE FAR * | lpnodeNew | new node allocated
+ *
+ * @rdesc The device ID to the new node. 0 on error.
+ *
+ */
+STATICFN UINT PASCAL NEAR mciAllocateNode(
+ DWORD dwFlags,
+ LPCSTR lpDeviceName,
+ LPMCI_DEVICE_NODE FAR *lpnodeNew
+ )
+{
+ LPMCI_DEVICE_NODE nodeWorking;
+ UINT wDeviceID;
+
+ if ((nodeWorking = mciAlloc(sizeof(MCI_DEVICE_NODE))) == NULL)
+ {
+ DOUT("Out of memory in mciAllocateNode\r\n");
+ return 0;
+ }
+
+ // The device ID is a global resource so we fetch it from 32-bit MCI.
+ // A node is also allocated on the 32-bit side, and marked as 16-bit. The
+ // node will be freed during mciFreeDevice, and acts as a place holder for
+ // the device ID.
+
+ wDeviceID = (UINT) mciMessage(THUNK_MCI_ALLOCATE_NODE,
+ dwFlags,
+ (DWORD)lpDeviceName,
+ 0L, 0L);
+
+ // Copy the working node to the device list
+ nodeWorking->wDeviceID = wDeviceID;
+ if (wAddDeviceNodeToList(nodeWorking) == 0)
+ {
+ DOUT ("mciAllocateNode: Cannot allocate new node\r\n");
+ mciFree(nodeWorking);
+ return 0;
+ }
+
+ // Initialize node
+ nodeWorking->hCreatorTask = GetCurrentTask ();
+ nodeWorking->dwMCIFlags |= MCINODE_16BIT_DRIVER;
+
+ if (dwFlags & MCI_OPEN_ELEMENT_ID) {
+ // No device name, just an element ID
+ nodeWorking->dwElementID = (DWORD)lpDeviceName;
+ }
+ else {
+ if (!mciAddDeviceName (nodeWorking, lpDeviceName))
+ {
+ mciFree (nodeWorking);
+ return 0;
+ }
+ }
+ *lpnodeNew = nodeWorking;
+
+ return nodeWorking->wDeviceID;
+}
+
+//
+// Reparse the original command parameters
+// Returns MCIERR code. If the reparse fails the original error code
+// from the first parsing is returned.
+//
+STATICFN UINT PASCAL NEAR
+mciReparseOpen(
+ LPMCI_INTERNAL_OPEN_INFO lpOpenInfo,
+ UINT wCustomTable,
+ UINT wTypeTable,
+ LPDWORD lpdwFlags,
+ LPMCI_OPEN_PARMS FAR *lplpOpen,
+ UINT wDeviceID
+ )
+{
+ LPSTR lpCommand;
+ LPDWORD lpdwParams;
+ UINT wErr;
+ DWORD dwOldFlags = *lpdwFlags;
+
+// If the custom table contains no open command
+ if (wCustomTable == -1 ||
+ (lpCommand = FindCommandInTable (wCustomTable, szOpen, NULL)) == NULL)
+ {
+// Try the type specific table
+ lpCommand = FindCommandInTable (wTypeTable, szOpen, NULL);
+// If it still cannot be parsed
+ if (lpCommand == NULL)
+ return lpOpenInfo->wParsingError;
+ wCustomTable = wTypeTable;
+ }
+// A new version of 'open' was found
+// Free previous set of parameters
+ mciParserFree (lpOpenInfo->lpstrPointerList);
+ *lpdwFlags = 0;
+
+ if ((lpdwParams =
+ (LPDWORD)mciAlloc (sizeof(DWORD) * MCI_MAX_PARAM_SLOTS))
+ == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+ wErr = mciParseParams (lpOpenInfo->lpstrParams, lpCommand,
+ lpdwFlags,
+ (LPSTR)lpdwParams,
+ sizeof(DWORD) * MCI_MAX_PARAM_SLOTS,
+ &lpOpenInfo->lpstrPointerList, NULL);
+// We don't need this around anymore
+ mciUnlockCommandTable (wCustomTable);
+
+// If there was a parsing error
+ if (wErr != 0)
+ {
+// Make sure this does not get free'd by mciSendString
+ lpOpenInfo->lpstrPointerList = NULL;
+
+ mciFree (lpdwParams);
+ return wErr;
+ }
+ if (dwOldFlags & MCI_OPEN_TYPE)
+ {
+// Device type was already extracted so add it manually
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrDeviceType
+ = (*lplpOpen)->lpstrDeviceType;
+ *lpdwFlags |= MCI_OPEN_TYPE;
+ }
+ if (dwOldFlags & MCI_OPEN_ELEMENT)
+ {
+// Element name was already extracted so add it manually
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrElementName
+ = (*lplpOpen)->lpstrElementName;
+ *lpdwFlags |= MCI_OPEN_ELEMENT;
+ }
+ if (dwOldFlags & MCI_OPEN_ALIAS)
+ {
+// Alias name was already extracted so add it manually
+ ((LPMCI_OPEN_PARMS)lpdwParams)->lpstrAlias
+ = (*lplpOpen)->lpstrAlias;
+ *lpdwFlags |= MCI_OPEN_ALIAS;
+ }
+ if (dwOldFlags & MCI_NOTIFY)
+// Notify was already extracted so add it manually
+ ((LPMCI_OPEN_PARMS)lpdwParams)->dwCallback
+ = (*lplpOpen)->dwCallback;
+
+ // Replace old parameter list with new list
+ *lplpOpen = (LPMCI_OPEN_PARMS)lpdwParams;
+
+ return 0;
+}
+
+// See if lpstrDriverName exists in the profile strings of the [mci]
+// section and return the keyname in lpstrDevice and the
+// profile string in lpstrProfString
+// Returns 0 on success or an error code
+STATICFN UINT PASCAL NEAR
+mciFindDriverName(
+ LPCSTR lpstrDriverName,
+ LPSTR lpstrDevice,
+ LPSTR lpstrProfString,
+ UINT wProfLength
+ )
+{
+ LPSTR lpstrEnum, lpstrEnumStart;
+ UINT wEnumLen = 100;
+ UINT wErr;
+ LPSTR lpstrDriverTemp, lpstrProfTemp;
+
+// Enumerate values, trying until they fit into the buffer
+ while (TRUE) {
+ if ((lpstrEnum = mciAlloc (wEnumLen)) == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+ wErr = GetPrivateProfileString ((LPSTR)szMCISectionName,
+ NULL, szNull, lpstrEnum, wEnumLen,
+ szSystemIni);
+
+ if (*lpstrEnum == '\0')
+ {
+ mciFree (lpstrEnum);
+ return MCIERR_DEVICE_NOT_INSTALLED;
+ }
+
+ if (wErr == wEnumLen - 2)
+ {
+ wEnumLen *= 2;
+ mciFree (lpstrEnum);
+ } else
+ break;
+ }
+
+ lpstrEnumStart = lpstrEnum;
+ if (lstrlen(lpstrDriverName) >= MCI_MAX_DEVICE_TYPE_LENGTH) {
+ wErr = MCIERR_DEVICE_LENGTH;
+ goto exit_fn;
+ }
+ lstrcpy(lpstrDevice, lpstrDriverName);
+//!! mciToLower (lpstrDevice);
+
+// Walk through each string
+ while (TRUE) {
+ wErr = GetPrivateProfileString ((LPSTR)szMCISectionName,
+ lpstrEnum, szNull, lpstrProfString,
+ wProfLength,
+ szSystemIni);
+ if (*lpstrProfString == '\0')
+ {
+ DOUT ("mciFindDriverName: cannot load valid keyname\r\n");
+ wErr = MCIERR_CANNOT_LOAD_DRIVER;
+ goto exit_fn;
+ }
+// See if driver pathname matches input
+//!! mciToLower (lpstrProfString);
+ lpstrDriverTemp = lpstrDevice;
+ lpstrProfTemp = lpstrProfString;
+// Find end of file name
+ while (*lpstrProfTemp != '\0' && *lpstrProfTemp != ' ')
+ ++lpstrProfTemp;
+// Find begining of simple file name
+ --lpstrProfTemp;
+ while (*lpstrProfTemp != '\\' && *lpstrProfTemp != '/' &&
+ *lpstrProfTemp != ':')
+ if (--lpstrProfTemp < lpstrProfString)
+ break;
+ ++lpstrProfTemp;
+// Compare to input
+ while (*lpstrDriverTemp != '\0')
+ if (*lpstrDriverTemp++ != *lpstrProfTemp++ ||
+ (UINT)(lpstrProfTemp - lpstrProfString) >= wProfLength)
+ {
+ --lpstrProfTemp;
+ break;
+ }
+// If the input was contained in the profile string and followed by
+// a space or a '.' the we've got it!
+ if (*lpstrDriverTemp == '\0' &&
+ (*lpstrProfTemp == ' ' || *lpstrProfTemp == '.'))
+ {
+ if (lstrlen (lpstrEnum) >= MCI_MAX_DEVICE_TYPE_LENGTH)
+ {
+ DOUT ("mciFindDriverName: device name too long\r\n");
+ wErr = MCIERR_DEVICE_LENGTH;
+ goto exit_fn;
+ }
+ lstrcpy (lpstrDevice, lpstrEnum);
+ wErr = 0;
+ goto exit_fn;
+ }
+// Skip to next keyname
+ while (*lpstrEnum++ != '\0') {}
+// Error if no more left
+ if (*lpstrEnum == 0)
+ {
+ wErr = MCIERR_INVALID_DEVICE_NAME;
+ goto exit_fn;
+ }
+ }
+
+exit_fn:
+ mciFree (lpstrEnumStart);
+ return wErr;
+}
+
+//
+// Identifies the driver name to load
+// Loads the driver
+// Reparses open command if necessary
+// Sets a default break key
+//
+// lpOpenInfo contains various info for reparsing
+//
+// bDefaultAlias indicates that the alias need not be verified because
+// it was internally assigned
+//
+STATICFN UINT PASCAL NEAR
+mciLoadDevice(
+ DWORD dwFlags,
+ LPMCI_OPEN_PARMS lpOpen,
+ LPMCI_INTERNAL_OPEN_INFO lpOpenInfo,
+ BOOL bDefaultAlias
+ )
+{
+ LPMCI_DEVICE_NODE nodeWorking;
+ HINSTANCE hDriver;
+ UINT wID, wErr;
+ char strProfileString[MCI_PROFILE_STRING_LENGTH];
+ MCI_OPEN_DRIVER_PARMS DriverOpen;
+ HDRVR hDrvDriver;
+ LPSTR lpstrParams;
+ LPCSTR lpstrInstallName, lpstrDeviceName;
+ LPSTR lpstrCopy = NULL;
+ LPMCI_OPEN_PARMS lpOriginalOpenParms = lpOpen;
+
+/* Check for the device name in SYSTEM.INI */
+ lpstrInstallName = lpOpen->lpstrDeviceType;
+ wErr = GetPrivateProfileString ((LPSTR)szMCISectionName,
+ lpstrInstallName,
+ szNull, (LPSTR)strProfileString,
+ MCI_PROFILE_STRING_LENGTH,
+ szSystemIni);
+
+// If device name not found
+ if (wErr == 0)
+ {
+ int nLen = lstrlen (lpstrInstallName);
+ int index;
+
+// Try for the device name with a '1' thru a '9' appended to it
+
+ if ((lpstrCopy = (LPSTR)mciAlloc (nLen + 2)) // space for digit too
+ == NULL)
+ {
+ DOUT ("mciLoadDevice: cannot allocate device name copy\r\n");
+ return MCIERR_OUT_OF_MEMORY;
+ }
+ lstrcpy (lpstrCopy, lpstrInstallName);
+
+ lpstrCopy[nLen + 1] = '\0';
+
+ for (index = 1; index <= 9; ++index)
+ {
+ lpstrCopy[nLen] = (char)('0' + index);
+ wErr = GetPrivateProfileString ((LPSTR)szMCISectionName,
+ lpstrCopy,
+ szNull, (LPSTR)strProfileString,
+ MCI_PROFILE_STRING_LENGTH,
+ szSystemIni);
+ if (wErr != 0)
+ break;
+ }
+ if (wErr == 0)
+ {
+ mciFree (lpstrCopy);
+ if ((lpstrCopy = (LPSTR)mciAlloc (MCI_MAX_DEVICE_TYPE_LENGTH))
+ == NULL)
+ {
+ DOUT ("mciLoadDevice: cannot allocate device name copy\r\n");
+ return MCIERR_OUT_OF_MEMORY;
+ }
+ if ((wErr = mciFindDriverName (lpstrInstallName, lpstrCopy,
+ (LPSTR)strProfileString,
+ MCI_PROFILE_STRING_LENGTH)) != 0)
+ goto exit_fn;
+ }
+ lpstrInstallName = lpstrCopy;
+ }
+
+// Break out the device driver pathname and the parameter list
+
+ lpstrParams = strProfileString;
+
+// Eat blanks
+ while (*lpstrParams != ' ' && *lpstrParams != '\0')
+ ++lpstrParams;
+
+// Terminate driver file name
+ if (*lpstrParams == ' ') *lpstrParams++ = '\0';
+
+//Now "strProfileString" is the device driver and "lpstrParams" is
+//the parameter string
+ if (dwFlags & (MCI_OPEN_ELEMENT | MCI_OPEN_ELEMENT_ID))
+ lpstrDeviceName = lpOpen->lpstrElementName;
+ else
+ lpstrDeviceName = lpOpen->lpstrDeviceType;
+
+ if (dwFlags & MCI_OPEN_ALIAS)
+ {
+// If the alias is default then we've already checked its uniqueness
+ if (!bDefaultAlias &&
+ mciGetDeviceIDInternalEx (lpOpen->lpstrAlias,
+ lpOpenInfo->hCallingTask) != 0)
+ {
+ wErr = MCIERR_DUPLICATE_ALIAS;
+ goto exit_fn;
+ }
+ lpstrDeviceName = lpOpen->lpstrAlias;
+ }
+
+ wID = mciAllocateNode (dwFlags, lpstrDeviceName, &nodeWorking);
+
+ if (wID == 0)
+ {
+ wErr = MCIERR_CANNOT_LOAD_DRIVER;
+ goto exit_fn;
+ }
+
+// Identify the task which initiated the open command
+ nodeWorking->hOpeningTask = lpOpenInfo->hCallingTask;
+
+// Initialize the driver
+ DriverOpen.lpstrParams = lpstrParams;
+ DriverOpen.wCustomCommandTable = -1;
+ DriverOpen.wType = 0;
+ DriverOpen.wDeviceID = wID;
+
+// Load the driver
+ hDrvDriver = OpenDriver ((LPSTR)strProfileString, szMCISectionName,
+ (LPARAM)(DWORD)(LPMCI_OPEN_DRIVER_PARMS)&DriverOpen);
+ if (hDrvDriver == NULL)
+ {
+ DOUT ("mciLoadDevice: OpenDriver failed\r\n");
+// Assume driver has free'd any custom command table when it failed the open
+ mciFreeDevice (nodeWorking);
+ wErr = MCIERR_CANNOT_LOAD_DRIVER;
+ goto exit_fn;
+ }
+
+ lpOpen->wDeviceID = wID;
+ lpOpen->wReserved0 = 0;
+
+ hDriver = GetDriverModuleHandle (hDrvDriver);
+
+ nodeWorking->hDrvDriver = hDrvDriver;
+ nodeWorking->hDriver = hDriver;
+
+// Driver provides custom device table and type
+ nodeWorking->wCustomCommandTable = DriverOpen.wCustomCommandTable;
+ nodeWorking->wDeviceType = DriverOpen.wType;
+
+// Load driver's type table
+ if ((nodeWorking->wCommandTable = mciLoadTableType (DriverOpen.wType))
+ == -1)
+// Load from a file if necessary
+ nodeWorking->wCommandTable =
+ mciLoadCommandResource (ghInst, lpOpen->lpstrDeviceType,
+ DriverOpen.wType);
+
+// Record this for 'sysinfo installname'
+ if ((nodeWorking->lpstrInstallName =
+ mciAlloc (lstrlen (lpstrInstallName) + 1))
+ == NULL)
+ {
+ mciCloseDevice (wID, 0L, NULL, FALSE);
+ wErr = MCIERR_OUT_OF_MEMORY;
+ goto exit_fn;
+ } else
+ lstrcpy (nodeWorking->lpstrInstallName, lpstrInstallName);
+
+// Reparse the input command if no type was known the first time or if
+// there was a custom command table
+// and there were any open command parameters
+ if (lpOpenInfo->lpstrParams != NULL)
+ {
+ if ((wErr = mciReparseOpen (lpOpenInfo,
+ nodeWorking->wCustomCommandTable,
+ nodeWorking->wCommandTable,
+ &dwFlags, &lpOpen, wID)) != 0)
+ {
+ mciCloseDevice (wID, 0L, NULL, FALSE);
+ goto exit_fn;
+ }
+// If there is no custom command table but mciSendString had a parsing
+// error then close the device and report the error now
+ } else if (lpOpenInfo->wParsingError != 0)
+ {
+ mciCloseDevice (wID, 0L, NULL, FALSE);
+ wErr = lpOpenInfo->wParsingError;
+ goto exit_fn;
+ }
+
+/* Send MCI_OPEN_DRIVER command to device */
+ wErr = LOWORD(mciSendCommand (wID, MCI_OPEN_DRIVER,
+ dwFlags, (DWORD)lpOpen));
+
+// If the OPEN failed then close the device (don't send a CLOSE though)
+ if (wErr != 0)
+ mciCloseDevice (wID, 0L, NULL, FALSE);
+ else
+// Set default break key
+ mciSetBreakKey (nodeWorking->wDeviceID, VK_CANCEL, NULL);
+
+// If we replaced the open parms here then free them
+ if (lpOriginalOpenParms != lpOpen && lpOpen != NULL)
+ mciFree (lpOpen);
+
+exit_fn:
+ if (lpstrCopy != NULL)
+ mciFree (lpstrCopy);
+
+ return wErr;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func BOOL | mciExtractDeviceType | If the given device name ends with
+ * a file extension (.???) then try to get a typename from the
+ * [mci extensions] section of WIN.INI
+ *
+ * @parm LPCSTR | lpstrDeviceName | The name to get the type from
+ *
+ * @parm LPSTR | lpstrDeviceType | The device type, returned to caller.
+ *
+ * @parm UINT | wBufLen | The length of the output buffer
+ *
+ * @rdesc TRUE if the type was found, FALSE otherwise
+ *
+ */
+BOOL PASCAL NEAR mciExtractDeviceType (
+LPCSTR lpstrDeviceName,
+LPSTR lpstrDeviceType,
+UINT wBufLen)
+{
+ LPCSTR lpstrExt = lpstrDeviceName;
+ int i;
+
+// Goto end of string
+ while (*lpstrExt != '\0')
+ {
+// '!' case is handled elsewhere
+ if (*lpstrExt == '!')
+ return FALSE;
+ ++lpstrExt;
+ }
+
+// Must be at least 2 characters in string
+ if (lpstrExt - lpstrDeviceName < 2)
+ return FALSE;
+
+ lpstrExt -= 1;
+
+// Does not count if last character is '.'
+ if (*lpstrExt == '.')
+ return FALSE;
+
+ lpstrExt -= 1;
+// Now looking at second to the last character. Check this and the two
+// previous characters for a '.'
+
+ for (i=1; i<=3; ++i)
+ {
+// Cannot have path separator here
+ if (*lpstrExt == '/' || *lpstrExt == '\\')
+ return FALSE;
+
+ if (*lpstrExt == '.')
+ {
+ ++lpstrExt;
+ if (GetProfileString (MCI_EXTENSIONS, lpstrExt, szNull,
+ lpstrDeviceType, wBufLen) != 0)
+ return TRUE;
+ }
+ if (lpstrExt == lpstrDeviceName)
+ return FALSE;
+ --lpstrExt;
+ }
+ return FALSE;
+}
+
+// Copy characters up to cSeparater into output which is allocated
+// by this function using mciAlloc. Return the input pointer pointing
+// to the character after cSeparator
+// unless the separator is '\0' in which case it points to the end.
+//
+// Return the allocated pointer
+//
+// If bMustFind then the output string is created only if the token
+// is found and is otherwise NULL. Else the output string is always created.
+//
+// cSeparator is ignored inside matching quotes ("abd"), the quotes
+// are not coppied and doubled
+// quotes inside are compressed to one. There must be a terminating quote.
+// Quotes are treated normally unless the first character is a quote
+//
+// Function return value is 0 or an MCIERR code. A missing separator does
+// not cause an error return.
+UINT PASCAL NEAR mciEatToken (LPCSTR FAR *lplpstrInput, char cSeparater,
+ LPSTR FAR *lplpstrOutput, BOOL bMustFind)
+{
+ LPCSTR lpstrEnd = *lplpstrInput, lpstrCounter;
+ LPSTR lpstrOutput;
+ UINT wLen;
+ BOOL bInQuotes = FALSE, bParseQuotes = TRUE, bQuoted = FALSE;
+
+// Clear output
+ *lplpstrOutput = NULL;
+
+// Scan for token or end of string
+ while ((*lpstrEnd != cSeparater || bInQuotes) && *lpstrEnd != '\0')
+ {
+// If quote
+ if (*lpstrEnd == '"' && bParseQuotes)
+ {
+// If inside quotes
+ if (bInQuotes)
+ {
+// If next character is a quote also
+ if (*(lpstrEnd + 1) == '"')
+// Skip it
+ ++lpstrEnd;
+ else
+ bInQuotes = FALSE;
+ } else
+ {
+ bInQuotes = TRUE;
+ bQuoted = TRUE;
+ }
+ } else if (!bInQuotes)
+ {
+ if (bQuoted)
+ return MCIERR_EXTRA_CHARACTERS;
+// A non-quote was read first so treat any quotes as normal characters
+ bParseQuotes = FALSE;
+ }
+ ++lpstrEnd;
+ }
+
+ if (bInQuotes)
+ return MCIERR_NO_CLOSING_QUOTE;
+
+// Fail if the token was not found and bMustFind is TRUE
+ if (*lpstrEnd != cSeparater && bMustFind)
+ return 0;
+
+// Length of new string (INCLUDES QUOTES NOT COPIED)
+ wLen = lpstrEnd - *lplpstrInput + 1;
+
+ if ((*lplpstrOutput = mciAlloc (wLen)) == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+// Copy into allocated space
+ lpstrCounter = *lplpstrInput;
+ lpstrOutput = *lplpstrOutput;
+ bInQuotes = FALSE;
+
+ while (lpstrCounter != lpstrEnd)
+ {
+ if (*lpstrCounter == '"' && bParseQuotes)
+ {
+ if (bInQuotes)
+ {
+// If this is a doubled quote
+ if (*(lpstrCounter + 1) == '"')
+// Copy it
+ *lpstrOutput++ = *lpstrCounter++;
+ else
+ bInQuotes = FALSE;
+ } else
+ bInQuotes = TRUE;
+// Skip the quote
+ ++lpstrCounter;
+ } else
+ *lpstrOutput++ = *lpstrCounter++;
+ }
+
+ *lpstrOutput = '\0';
+ if (*lpstrEnd == '\0')
+ *lplpstrInput = lpstrEnd;
+ else
+ *lplpstrInput = lpstrEnd + 1;
+
+ return 0;
+}
+
+// Take the type number from the open parameters and return
+// it as a string in lplpstrType which must be free'd with mciFree
+// Returns 0 or an MCI error code
+UINT PASCAL NEAR mciExtractTypeFromID (
+LPMCI_OPEN_PARMS lpOpen)
+{
+ int nSize;
+ LPSTR lpstrType;
+
+ if ((lpstrType = mciAlloc (MCI_MAX_DEVICE_TYPE_LENGTH)) == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+// Load the type string corresponding to the ID
+ if ((nSize = LoadString (ghInst,
+ LOWORD ((DWORD)lpOpen->lpstrDeviceType),
+ lpstrType, MCI_MAX_DEVICE_TYPE_LENGTH)) == 0)
+ return MCIERR_EXTENSION_NOT_FOUND;
+
+// Add ordinal (if any) onto the end of the device type name
+ if (HIWORD (lpOpen->lpstrDeviceType) != 0)
+ {
+ if (nSize > MCI_MAX_DEVICE_TYPE_LENGTH - 11)
+ {
+ DOUT ("mciExtractTypeFromID: type + ordinal too long\r\n");
+ return MCIERR_DEVICE_ORD_LENGTH;
+ }
+
+ wsprintf (lpstrType + nSize, szUnsignedFormat,
+ HIWORD ((DWORD)lpOpen->lpstrDeviceType));
+ }
+ lpOpen->lpstrDeviceType = lpstrType;
+ return 0;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciOpenDevice | Open an MCI device for access.
+ * Used in processing the MCI_OPEN message.
+ *
+ * @parm DWORD | dwFlags | Open Flags
+ * @parm LPMCI_OPEN_PARMS | lpOpen | Description of device
+ *
+ * @rdesc 0 if successful or an error code
+ * @flag MCIERR_INVALID_DEVICE_NAME | Name not known
+ * @flag MCIERR_DEVICE_OPEN | Device is already open and is not sharable
+ *
+ * @comm This function does the following:
+ * 1) Check to see if device is already open. If so, return an error
+ *
+ * 2) Locate the device name in the SYSTEM.INI file and load
+ * the corresponding device driver DLL
+ *
+ * 3) Allocate and initialize a new device description block
+ *
+ */
+UINT NEAR PASCAL mciOpenDevice (
+DWORD dwStartingFlags,
+LPMCI_OPEN_PARMS lpOpen,
+LPMCI_INTERNAL_OPEN_INFO lpOpenInfo)
+{
+ LPSTR lpstrNewType = NULL;
+ UINT wID, wReturn;
+ LPCSTR lpstrDeviceName;
+ LPSTR lpstrNewElement = NULL;
+ BOOL bFromTypeID = FALSE;
+ LPCSTR lpstrOriginalType;
+ LPCSTR lpstrOriginalElement;
+ LPCSTR lpstrOriginalAlias;
+ DWORD dwFlags = dwStartingFlags;
+ BOOL bDefaultAlias = FALSE;
+
+// Initialize
+ if (lpOpen == NULL)
+ return MCIERR_NULL_PARAMETER_BLOCK;
+ lpstrOriginalType = lpOpen->lpstrDeviceType;
+ lpstrOriginalElement = lpOpen->lpstrElementName;
+ lpstrOriginalAlias = lpOpen->lpstrAlias;
+
+// The type number is given explicitly, convert it to a type name
+ if (dwFlags & MCI_OPEN_TYPE_ID)
+ if ((wReturn = mciExtractTypeFromID (lpOpen)) != 0)
+ return wReturn;
+ else
+ bFromTypeID = TRUE;
+
+// The device name is the device type of a simple device or the device
+// element of a compound device
+
+ if (dwFlags & MCI_OPEN_ELEMENT)
+ lpstrDeviceName = lpstrOriginalElement;
+ else if (dwFlags & MCI_OPEN_TYPE)
+ lpstrDeviceName = lpOpen->lpstrDeviceType;
+ else
+ return MCIERR_MISSING_PARAMETER;
+
+ if (lpstrDeviceName == NULL)
+ {
+ DOUT ("mciOpenDevice: Device name is NULL\r\n");
+ return MCIERR_INVALID_DEVICE_NAME;
+ }
+
+// Is the device already open?
+ if (dwFlags & MCI_OPEN_ELEMENT_ID)
+ wID = mciGetDeviceIDFromElementID ((DWORD)lpstrDeviceName,
+ lpOpen->lpstrDeviceType);
+ else
+ wID = mciGetDeviceIDInternalEx ((dwFlags & MCI_OPEN_ALIAS ?
+ lpOpen->lpstrAlias : lpstrDeviceName),
+ lpOpenInfo->hCallingTask);
+
+// If the device is open already then return an error
+ if (wID != 0)
+ return dwFlags & MCI_OPEN_ALIAS ? MCIERR_DUPLICATE_ALIAS :
+ MCIERR_DEVICE_OPEN;
+
+// The device is not already open in that task by the name
+
+// If the type was derived then skip all this crap
+ if (bFromTypeID)
+ goto load_device;
+
+// If an element name is given but no type name (only via mciSendCommand)
+ if (dwFlags & MCI_OPEN_ELEMENT && !(dwFlags & MCI_OPEN_TYPE))
+ {
+ lpstrNewType = mciAlloc (MCI_MAX_DEVICE_TYPE_LENGTH);
+ if (lpstrNewType == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+
+// Try to get the device type from the element name via a file extension
+ if (mciExtractDeviceType (lpstrOriginalElement,
+ lpstrNewType, MCI_MAX_DEVICE_TYPE_LENGTH))
+ {
+ lpOpen->lpstrDeviceType = lpstrNewType;
+ dwFlags |= MCI_OPEN_TYPE;
+ } else
+ {
+ mciFree (lpstrNewType);
+ return MCIERR_EXTENSION_NOT_FOUND;
+ }
+ } else if (dwFlags & MCI_OPEN_TYPE && !(dwFlags & MCI_OPEN_ELEMENT))
+// A type name is given but no element
+ {
+// Try to extract a device type from the given device name via a file extension
+ lpstrNewType = mciAlloc (MCI_MAX_DEVICE_TYPE_LENGTH);
+ if (lpstrNewType == NULL)
+ return MCIERR_OUT_OF_MEMORY;
+ if (mciExtractDeviceType (lpOpen->lpstrDeviceType, lpstrNewType,
+ MCI_MAX_DEVICE_TYPE_LENGTH))
+ {
+// Fix up the type and element names
+ dwFlags |= MCI_OPEN_ELEMENT;
+ lpOpen->lpstrElementName = lpOpen->lpstrDeviceType;
+ lpOpen->lpstrDeviceType = lpstrNewType;
+ } else
+// Failed to extract type so...
+// Try to get a compound element name ('!' separator)
+ {
+ LPCSTR lpstrTemp = lpOpen->lpstrDeviceType;
+
+ mciFree (lpstrNewType);
+ lpstrNewType = NULL;
+
+ if ((wReturn = mciEatToken (&lpstrTemp, '!', &lpstrNewType, TRUE))
+ != 0)
+ goto cleanup;
+ else if (lpstrNewType != NULL)
+ {
+ if ((wReturn = mciEatToken (&lpstrTemp, '\0',
+ &lpstrNewElement, TRUE))
+ != 0)
+ goto cleanup;
+ else if (lpstrNewElement != NULL &&
+ *lpstrNewElement != '\0')
+ {
+// See if this element name is in use
+ if (!(dwFlags & MCI_OPEN_ALIAS))
+ if (mciGetDeviceIDInternalEx (lpstrNewElement,
+ lpOpenInfo->hCallingTask))
+ {
+ wReturn = MCIERR_DEVICE_OPEN;
+ goto cleanup;
+ }
+// Swap type and element for new ones
+ lpOpen->lpstrElementName = lpstrNewElement;
+ lpOpen->lpstrDeviceType = lpstrNewType;
+ dwFlags |= MCI_OPEN_ELEMENT;
+ }
+ }
+ }
+ } else
+ lpstrNewType = NULL;
+
+// Tack on a default alias if none is given
+ if (! (dwFlags & MCI_OPEN_ALIAS))
+ {
+ LPCSTR lpstrAlias;
+
+// If an element name exists then the alias is the element name
+ if (dwFlags & MCI_OPEN_ELEMENT)
+ {
+// If a device ID was specified then there is no alias
+ if (dwFlags & MCI_OPEN_ELEMENT_ID)
+ lpstrAlias = NULL;
+ else
+ lpstrAlias = lpOpen->lpstrElementName;
+// Otherwise the alias is the device type
+ } else
+ lpstrAlias = lpOpen->lpstrDeviceType;
+
+ if (lpstrAlias != NULL)
+ {
+ lpOpen->lpstrAlias = lpstrAlias;
+ dwFlags |= MCI_OPEN_ALIAS;
+ bDefaultAlias = TRUE;
+ }
+ }
+
+load_device:;
+ wReturn = mciLoadDevice (dwFlags, lpOpen, lpOpenInfo, bDefaultAlias);
+
+cleanup:
+ if (lpstrNewElement != NULL)
+ mciFree (lpstrNewElement);
+ if (lpstrNewType != NULL)
+ mciFree (lpstrNewType);
+ if (bFromTypeID)
+ mciFree ((LPSTR)lpOpen->lpstrDeviceType);
+
+// Replace original items
+ lpOpen->lpstrDeviceType = lpstrOriginalType;
+ lpOpen->lpstrElementName = lpstrOriginalElement;
+ lpOpen->lpstrAlias = lpstrOriginalAlias;
+
+ return wReturn;
+}
+
+STATICFN void PASCAL NEAR
+mciFreeDevice(
+ LPMCI_DEVICE_NODE nodeWorking
+ )
+{
+ UINT wID = nodeWorking->wDeviceID;
+
+ mciMessage(THUNK_MCI_FREE_NODE, (DWORD) nodeWorking->wDeviceID, 0L, 0L, 0L);
+
+ if (nodeWorking->lpstrName != NULL)
+ mciFree (nodeWorking->lpstrName);
+
+ if (nodeWorking->lpstrInstallName != NULL)
+ mciFree (nodeWorking->lpstrInstallName);
+
+ mciFree(MCI_lpDeviceList[wID]);
+ MCI_lpDeviceList[wID] = NULL;
+
+/* If this was the last device in the list, decrement next ID value */
+ if (wID + 1 == MCI_wNextDeviceID) {
+ --MCI_wNextDeviceID;
+ }
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciCloseDevice | Close an MCI device. Used in
+ * processing the MCI_CLOSE message.
+ *
+ * @parm UINT | wID | The ID of the device to close
+ * @parm DWORD | dwFlags | Close Flags
+ * @parm LPMCI_GENERIC_PARMS | lpClose | Generic parameters
+ * @parm BOOL | bCloseDriver | TRUE if the CLOSE command should be sent
+ * on to the driver.
+ *
+ * @rdesc 0 if successful or an error code
+ *
+ * @comm This function sends an MCI_CLOSE_DRIVER message to the corresponding
+ * driver if the use count is zero and then unloads the driver DLL
+ *
+ */
+UINT NEAR PASCAL mciCloseDevice (
+UINT wID,
+DWORD dwFlags,
+LPMCI_GENERIC_PARMS lpGeneric,
+BOOL bCloseDriver)
+{
+ LPMCI_DEVICE_NODE nodeWorking;
+ UINT wErr, wTable;
+
+ nodeWorking = MCI_lpDeviceList[wID];
+
+ if (nodeWorking == NULL)
+ {
+ DOUT ("mciCloseDevice: NULL node from device ID--error if not auto-close\r\n");
+ return 0;
+ }
+
+// If a close is in progress (usually this message comes from a Yield
+// after a mciDriverNotify actuated by the active close) then exit
+ if (nodeWorking->dwMCIFlags & MCINODE_ISCLOSING)
+ return 0;
+
+ nodeWorking->dwMCIFlags |= MCINODE_ISCLOSING;
+ if (bCloseDriver)
+ {
+ MCI_GENERIC_PARMS GenericParms;
+// Make fake generic params if close came internally
+ if (lpGeneric == NULL)
+ lpGeneric = &GenericParms;
+
+ wErr = LOWORD(mciSendCommand (wID, MCI_CLOSE_DRIVER, dwFlags,
+ (DWORD)lpGeneric));
+ }
+ else
+ wErr = 0;
+
+// Must zero this to allow the table to be freed by the driver
+ nodeWorking->wCustomCommandTable = 0;
+
+ wTable = nodeWorking->wCommandTable;
+// Must zero this to allow the table to be freed
+ nodeWorking->wCommandTable = 0;
+ mciFreeCommandResource (wTable);
+
+ CloseDriver (nodeWorking->hDrvDriver, 0L, 0L);
+
+ mciFreeDevice (nodeWorking);
+
+ return wErr;
+}
+
+/*
+ * @doc INTERNAL MCI DDK
+ * @api DWORD | mciGetDriverData | Returns a pointer to the instance
+ * data associated with an MCI device
+ *
+ * @parm UINT | wDeviceID | The MCI device ID
+ *
+ * @rdesc The driver instance data. On error, returns 0 but since
+ * the driver data might be zero, this cannot be verified by the caller
+ * unless the instance data is known to be non-zero (e.g. a pointer)
+ *
+ */
+DWORD WINAPI mciGetDriverData (
+UINT wDeviceID)
+{
+ if (!MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ DOUT ("mciGetDriverData: invalid device ID\r\n");
+ return 0;
+ }
+ return MCI_lpDeviceList[wDeviceID]->lpDriverData;
+}
+
+/*
+ * @doc INTERNAL MCI DDK
+ * @func BOOL | mciSetDriverData | Sets the instance
+ * data associated with an MCI device
+ *
+ * @parm UINT | wDeviceID | The MCI device ID
+ *
+ * @parm DWORD | dwData | Driver data to set
+ *
+ * @rdesc FALSE if the device ID is not known or there is insufficient
+ * memory to load the device description, else TRUE.
+ *
+ */
+BOOL WINAPI mciSetDriverData (
+UINT wDeviceID,
+DWORD dwData)
+{
+ if (!MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ DOUT ("mciSetDriverData: invalid device ID\r\n");
+ return FALSE;
+ }
+ MCI_lpDeviceList[wDeviceID]->lpDriverData = dwData;
+ return TRUE;
+}
+
+/*
+ * @doc INTERNAL MCI DDK
+ * @api UINT | mciDriverYield | Used in a driver's idle loop
+ * to yield to Windows
+ *
+ * @parm UINT | wDeviceID | Device ID that is yielding.
+ *
+ * @rdesc Non-zero if the driver should abort the operation.
+ *
+ */
+UINT WINAPI mciDriverYield (
+UINT wDeviceID)
+{
+ if (MCI_VALID_DEVICE_ID(wDeviceID))
+ {
+ LPMCI_DEVICE_NODE node = MCI_lpDeviceList[wDeviceID];
+
+ if (node->fpYieldProc != NULL)
+ return (node->fpYieldProc)(wDeviceID, node->dwYieldData);
+ }
+
+ Yield();
+ return 0;
+}
+
+/*
+ * @doc EXTERNAL MCI
+ * @api BOOL | mciSetYieldProc | This function sets the address
+ * of a callback procedure to be called periodically when an MCI device
+ * is completing a command specified with the WAIT flag.
+ *
+ * @parm UINT | wDeviceID | Specifies the device ID of the MCI device to
+ * which the yield procedure is to be assigned.
+ *
+ * @parm YIELDPROC | fpYieldProc | Specifies the callback procedure
+ * to be called when the given device is yielding. Specify a NULL value
+ * to disable any existing yield procedure.
+ *
+ * @parm DWORD | dwYieldData | Specifies the data sent to the yield procedure
+ * when it is called for the given device.
+ *
+ * @rdesc Returns TRUE if successful. Returns FALSE for an invalid device ID.
+ *
+ * @cb int CALLBACK | YieldProc | <f YieldProc> is a placeholder for
+ * the application-supplied function name. Export the actual name
+ * by including it in the EXPORTS statement in your module-definition
+ * file.
+ *
+ * @parm UINT | wDeviceID | Specifies the device ID of the MCI device.
+ *
+ * @parm DWORD | dwData | Specifies the application-supplied yield data
+ * originally supplied in the <p dwYieldData> parameter.
+ *
+ * @rdesc Return zero to continue the operation. To cancel the operation,
+ * return a nonzero value.
+ *
+ * @comm This call overrides any previous yield procedure for this device.
+ *
+ */
+BOOL WINAPI mciSetYieldProc (
+UINT wDeviceID,
+YIELDPROC fpYieldProc,
+DWORD dwYieldData)
+{
+ V_CALLBACK((FARPROC)fpYieldProc, FALSE);
+
+ if (Is16bitDrv(wDeviceID)) {
+
+ LPMCI_DEVICE_NODE node = MCI_lpDeviceList[wDeviceID];
+
+ node->fpYieldProc = fpYieldProc;
+ node->dwYieldData = dwYieldData;
+ return TRUE;
+ }
+
+ return (BOOL)mciMessage( THUNK_MCI_SETYIELDPROC, (DWORD)wDeviceID,
+ (DWORD)fpYieldProc, dwYieldData, 0L );
+
+}
+
+/*
+ * @doc EXTERNAL MCI
+ * @api YIELDPROC | mciGetYieldProc | This function gets the address
+ * of the callback procedure to be called periodically when an MCI device
+ * is completing a command specified with the WAIT flag.
+ *
+ * @parm UINT | wDeviceID | Specifies the device ID of the MCI device to
+ * which the yield procedure is to be retrieved from.
+ *
+ * @parm LPDWORD | lpdwYieldData | Optionally specifies a buffer to place
+ * the yield data passed to the function in. If the parameter is NULL, it
+ * is ignored.
+ *
+ * @rdesc Returns the current yield proc if any, else returns NULL for an
+ * invalid device ID.
+ *
+ */
+YIELDPROC WINAPI mciGetYieldProc (
+UINT wDeviceID,
+LPDWORD lpdwYieldData)
+{
+ /*
+ ** Is this a 16 bit device ID ?
+ */
+ if (Is16bitDrv(wDeviceID)) {
+
+ if (lpdwYieldData != NULL) {
+ V_WPOINTER(lpdwYieldData, sizeof(DWORD), NULL);
+ *lpdwYieldData = MCI_lpDeviceList[wDeviceID]->dwYieldData;
+ }
+ return MCI_lpDeviceList[wDeviceID]->fpYieldProc;
+ }
+
+ /*
+ ** No, so pass it on to the 32 bit code.
+ */
+ return (YIELDPROC)mciMessage( THUNK_MCI_GETYIELDPROC, (DWORD)wDeviceID,
+ (DWORD)lpdwYieldData, 0L, 0L );
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @api int | mciBreakKeyYieldProc | Procedure called to check a
+ * key state for the given device
+ *
+ * @parm UINT | wDeviceID | Device ID which is yielding
+ *
+ * @parm DWORD | dwYieldData | Data for this device's yield proc
+ *
+ * @rdesc Non-zero if the driver should abort the operation. Currently
+ * always returns 0.
+ *
+ */
+int CALLBACK mciBreakKeyYieldProc (
+UINT wDeviceID,
+DWORD dwYieldData)
+{
+ HWND hwndCheck;
+ int nState;
+
+ hwndCheck = (HWND)HIWORD (dwYieldData);
+ if (hwndCheck == NULL || hwndCheck == GetActiveWindow())
+ {
+ nState = GetAsyncKeyState (LOWORD(dwYieldData));
+
+// Break if key is down or has been down
+ if (nState & 1)
+ {
+ MSG msg;
+
+ while (PeekMessage (&msg, hwndCheck, WM_KEYFIRST, WM_KEYLAST,
+ PM_REMOVE));
+ return -1;
+ }
+ }
+ Yield();
+ return 0;
+}
+
+/*
+ * @doc INTERNAL MCI
+ * @func UINT | mciSetBreakKey | Set a key which will break a wait loop
+ * for a given driver
+ *
+ * @parm UINT | wDeviceID | The device ID to assign a break key to
+ *
+ * @parm int | nVirtKey | Virtual key code to trap
+ *
+ * @parm HWND | hwndTrap | The handle to a window that must be active
+ * for the key to be trapped. If NULL then all windows will be checked
+ *
+ * @rdesc TRUE if successful, FALSE if invalid device ID
+ *
+ */
+UINT PASCAL NEAR mciSetBreakKey (
+UINT wDeviceID,
+int nVirtKey,
+HWND hwndTrap)
+{
+ return mciSetYieldProc (wDeviceID, mciBreakKeyYieldProc,
+ MAKELONG (nVirtKey, hwndTrap));
+}
diff --git a/private/mvdm/wow16/mmsystem/messages/usa/mci.rc b/private/mvdm/wow16/mmsystem/messages/usa/mci.rc
new file mode 100644
index 000000000..5f3660180
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/messages/usa/mci.rc
@@ -0,0 +1,848 @@
+/****************************************************************************
+* Command Lists for the MCI core command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+core RCDATA
+BEGIN
+ "open\0", MCI_OPEN, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "type\0", MCI_OPEN_TYPE, MCI_STRING,
+ "element\0", MCI_OPEN_ELEMENT, MCI_STRING,
+ "alias\0", MCI_OPEN_ALIAS, MCI_STRING,
+ "shareable\0", MCI_OPEN_SHAREABLE, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "close\0", MCI_CLOSE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "play\0", MCI_PLAY, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "from\0", MCI_FROM, MCI_INTEGER,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "record\0", MCI_RECORD, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "from\0", MCI_FROM, MCI_INTEGER,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "insert\0", MCI_RECORD_INSERT, MCI_FLAG,
+ "overwrite\0", MCI_RECORD_OVERWRITE, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "seek\0", MCI_SEEK, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "to start\0", MCI_SEEK_TO_START, MCI_FLAG,
+ "to end\0", MCI_SEEK_TO_END, MCI_FLAG,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "stop\0", MCI_STOP, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "pause\0", MCI_PAUSE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "capability\0", MCI_GETDEVCAPS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", MCI_GETDEVCAPS_ITEM, MCI_CONSTANT
+ "can record\0", MCI_GETDEVCAPS_CAN_RECORD, MCI_INTEGER,
+ "has audio\0", MCI_GETDEVCAPS_HAS_AUDIO, MCI_INTEGER,
+ "has video\0", MCI_GETDEVCAPS_HAS_VIDEO, MCI_INTEGER,
+ "uses files\0", MCI_GETDEVCAPS_USES_FILES, MCI_INTEGER,
+ "compound device\0",MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
+ "device type\0", MCI_GETDEVCAPS_DEVICE_TYPE, MCI_INTEGER,
+ "can eject\0", MCI_GETDEVCAPS_CAN_EJECT, MCI_INTEGER,
+ "can play\0", MCI_GETDEVCAPS_CAN_PLAY, MCI_INTEGER,
+ "can save\0", MCI_GETDEVCAPS_CAN_SAVE, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "info\0", MCI_INFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "product\0", MCI_INFO_PRODUCT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "sysinfo\0", MCI_SYSINFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "quantity\0", MCI_SYSINFO_QUANTITY, MCI_FLAG,
+ "open\0", MCI_SYSINFO_OPEN, MCI_FLAG,
+ "installname\0", MCI_SYSINFO_INSTALLNAME, MCI_FLAG,
+ "name\0", MCI_SYSINFO_NAME, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "break\0", MCI_BREAK, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "on\0", MCI_BREAK_KEY, MCI_INTEGER,
+ "off\0", MCI_BREAK_OFF, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "sound\0", MCI_SOUND, 0 MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "save\0", MCI_SAVE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_SAVE_FILE, MCI_STRING,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "load\0", MCI_LOAD, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_LOAD_FILE, MCI_STRING,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "resume\0", MCI_RESUME, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+END
+
+/****************************************************************************
+* Command Lists for the videodisc command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+videodisc RCDATA
+BEGIN
+ "play\0", MCI_PLAY, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "from\0", MCI_FROM, MCI_INTEGER,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "fast\0", MCI_VD_PLAY_FAST, MCI_FLAG,
+ "slow\0", MCI_VD_PLAY_SLOW, MCI_FLAG,
+ "speed\0", MCI_VD_PLAY_SPEED, MCI_INTEGER,
+ "reverse\0", MCI_VD_PLAY_REVERSE, MCI_FLAG,
+ "scan\0", MCI_VD_PLAY_SCAN, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "seek\0", MCI_SEEK, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "reverse\0", MCI_VD_SEEK_REVERSE, MCI_FLAG,
+ "to start\0", MCI_SEEK_TO_START, MCI_FLAG,
+ "to end\0", MCI_SEEK_TO_END, MCI_FLAG,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "spin\0", MCI_SPIN, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "up\0", MCI_VD_SPIN_UP, MCI_FLAG,
+ "down\0", MCI_VD_SPIN_DOWN, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "step\0", MCI_STEP, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "reverse\0", MCI_VD_STEP_REVERSE, MCI_FLAG,
+ "by\0", MCI_VD_STEP_FRAMES, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "frames\0", MCI_FORMAT_FRAMES, 0, MCI_INTEGER,
+ "hms\0", MCI_FORMAT_HMS, 0 MCI_INTEGER,
+ "track\0", MCI_VD_FORMAT_TRACK, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "media present\0",MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "speed\0", MCI_VD_STATUS_SPEED, MCI_INTEGER,
+ "forward\0", MCI_VD_STATUS_FORWARD, MCI_INTEGER,
+ "media type\0", MCI_VD_STATUS_MEDIA_TYPE, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "side\0", MCI_VD_STATUS_SIDE, MCI_INTEGER,
+ "disc size\0", MCI_VD_STATUS_DISC_SIZE, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+
+ "capability\0", MCI_GETDEVCAPS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "clv\0", MCI_VD_GETDEVCAPS_CLV, MCI_FLAG,
+ "cav\0", MCI_VD_GETDEVCAPS_CAV, MCI_FLAG,
+ "\0", MCI_GETDEVCAPS_ITEM, MCI_CONSTANT,
+ "can record\0", MCI_GETDEVCAPS_CAN_RECORD, MCI_INTEGER,
+ "has audio\0", MCI_GETDEVCAPS_HAS_AUDIO, MCI_INTEGER,
+ "has video\0", MCI_GETDEVCAPS_HAS_VIDEO, MCI_INTEGER,
+ "device type\0", MCI_GETDEVCAPS_DEVICE_TYPE, MCI_INTEGER,
+ "uses files\0", MCI_GETDEVCAPS_USES_FILES, MCI_INTEGER,
+ "compound device\0",MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
+ "can eject\0", MCI_GETDEVCAPS_CAN_EJECT, MCI_INTEGER,
+ "can reverse\0", MCI_VD_GETDEVCAPS_CAN_REVERSE, MCI_INTEGER,
+ "can play\0", MCI_GETDEVCAPS_CAN_PLAY, MCI_INTEGER,
+ "can save\0", MCI_GETDEVCAPS_CAN_SAVE, MCI_INTEGER,
+ "fast play rate\0",MCI_VD_GETDEVCAPS_FAST_RATE, MCI_INTEGER,
+ "slow play rate\0",MCI_VD_GETDEVCAPS_SLOW_RATE, MCI_INTEGER,
+ "normal play rate\0",MCI_VD_GETDEVCAPS_NORMAL_RATE, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "escape\0", MCI_ESCAPE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "\0", MCI_VD_ESCAPE_STRING, MCI_STRING,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+END
+
+
+/****************************************************************************
+* Command Lists for the waveform audio command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+waveaudio RCDATA
+BEGIN
+ "open\0", MCI_OPEN, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "type\0", MCI_OPEN_TYPE, MCI_STRING,
+ "element\0", MCI_OPEN_ELEMENT, MCI_STRING,
+ "alias\0", MCI_OPEN_ALIAS, MCI_STRING,
+ "shareable\0", MCI_OPEN_SHAREABLE, MCI_FLAG,
+ "buffer\0", MCI_WAVE_OPEN_BUFFER, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "media present\0", MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "format tag\0", MCI_WAVE_STATUS_FORMATTAG, MCI_INTEGER,
+ "channels\0", MCI_WAVE_STATUS_CHANNELS, MCI_INTEGER,
+ "samplespersec\0", MCI_WAVE_STATUS_SAMPLESPERSEC, MCI_INTEGER,
+ "bytespersec\0", MCI_WAVE_STATUS_AVGBYTESPERSEC, MCI_INTEGER,
+ "alignment\0", MCI_WAVE_STATUS_BLOCKALIGN, MCI_INTEGER,
+ "bitspersample\0", MCI_WAVE_STATUS_BITSPERSAMPLE, MCI_INTEGER,
+ "input\0", MCI_WAVE_INPUT, MCI_INTEGER,
+ "output\0", MCI_WAVE_OUTPUT, MCI_INTEGER,
+ "level\0", MCI_WAVE_STATUS_LEVEL, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "any input\0", MCI_WAVE_SET_ANYINPUT, MCI_FLAG,
+ "any output\0", MCI_WAVE_SET_ANYOUTPUT, MCI_FLAG,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "bytes\0", MCI_FORMAT_BYTES, 0, MCI_INTEGER,
+ "samples\0", MCI_FORMAT_SAMPLES, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "input\0", MCI_WAVE_INPUT, MCI_INTEGER,
+ "output\0", MCI_WAVE_OUTPUT, MCI_INTEGER,
+ "format tag\0", MCI_WAVE_SET_FORMATTAG, MCI_CONSTANT,
+ "pcm\0", WAVE_FORMAT_PCM, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "channels\0", MCI_WAVE_SET_CHANNELS, MCI_INTEGER,
+ "samplespersec\0", MCI_WAVE_SET_SAMPLESPERSEC, MCI_INTEGER,
+ "bytespersec\0", MCI_WAVE_SET_AVGBYTESPERSEC, MCI_INTEGER,
+ "alignment\0", MCI_WAVE_SET_BLOCKALIGN, MCI_INTEGER,
+ "bitspersample\0", MCI_WAVE_SET_BITSPERSAMPLE, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "capability\0", MCI_GETDEVCAPS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_GETDEVCAPS_ITEM, MCI_CONSTANT,
+ "can record\0", MCI_GETDEVCAPS_CAN_RECORD, MCI_INTEGER,
+ "has audio\0", MCI_GETDEVCAPS_HAS_AUDIO, MCI_INTEGER,
+ "has video\0", MCI_GETDEVCAPS_HAS_VIDEO, MCI_INTEGER,
+ "device type\0", MCI_GETDEVCAPS_DEVICE_TYPE, MCI_INTEGER,
+ "uses files\0", MCI_GETDEVCAPS_USES_FILES, MCI_INTEGER,
+ "compound device\0", MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
+ "can eject\0", MCI_GETDEVCAPS_CAN_EJECT, MCI_INTEGER,
+ "can play\0", MCI_GETDEVCAPS_CAN_PLAY, MCI_INTEGER,
+ "can save\0", MCI_GETDEVCAPS_CAN_SAVE, MCI_INTEGER,
+ "inputs\0", MCI_WAVE_GETDEVCAPS_INPUTS, MCI_INTEGER,
+ "outputs\0", MCI_WAVE_GETDEVCAPS_OUTPUTS, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "info\0", MCI_INFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "product\0", MCI_INFO_PRODUCT, MCI_FLAG,
+ "input\0", MCI_WAVE_INPUT, MCI_FLAG,
+ "output\0", MCI_WAVE_OUTPUT, MCI_FLAG,
+ "file\0", MCI_INFO_FILE, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "cue\0", MCI_CUE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "input\0", MCI_WAVE_INPUT, MCI_FLAG,
+ "output\0", MCI_WAVE_OUTPUT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "delete\0", MCI_DELETE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "from\0", MCI_FROM, MCI_INTEGER,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+END
+
+/****************************************************************************
+* Command Lists for the CD audio command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+cdaudio RCDATA
+BEGIN
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "media present\0",MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "msf\0", MCI_FORMAT_MSF, 0, MCI_INTEGER,
+ "tmsf\0", MCI_FORMAT_TMSF, 0, MCI_INTEGER,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+END
+
+/****************************************************************************
+* Command Lists for the Sequencer command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+sequencer RCDATA
+BEGIN
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "media present\0", MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "tempo\0", MCI_SEQ_STATUS_TEMPO, MCI_INTEGER,
+ "port\0", MCI_SEQ_STATUS_PORT, MCI_INTEGER,
+ "slave\0", MCI_SEQ_STATUS_SLAVE, MCI_INTEGER,
+ "master\0", MCI_SEQ_STATUS_MASTER, MCI_INTEGER,
+ "offset\0", MCI_SEQ_STATUS_OFFSET, MCI_INTEGER,
+ "division type\0", MCI_SEQ_STATUS_DIVTYPE, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG ,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "smpte 30 drop\0", MCI_FORMAT_SMPTE_30DROP, 0, MCI_INTEGER,
+ "smpte 30\0", MCI_FORMAT_SMPTE_30, 0, MCI_INTEGER,
+ "smpte 25\0", MCI_FORMAT_SMPTE_25, 0, MCI_INTEGER,
+ "smpte 24\0", MCI_FORMAT_SMPTE_24, 0, MCI_INTEGER,
+ "song pointer\0", MCI_SEQ_FORMAT_SONGPTR, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "tempo\0", MCI_SEQ_SET_TEMPO, MCI_INTEGER,
+ "port\0", MCI_SEQ_SET_PORT, MCI_CONSTANT,
+ "none\0", MCI_SEQ_NONE, 0, MCI_INTEGER,
+ "mapper\0", MIDIMAPPER, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "slave\0", MCI_SEQ_SET_SLAVE, MCI_CONSTANT,
+ "smpte\0", MCI_SEQ_SMPTE, 0 MCI_INTEGER,
+ "midi\0", MCI_SEQ_MIDI, 0 MCI_INTEGER,
+ "none\0", MCI_SEQ_NONE, 0 MCI_INTEGER,
+ "file\0", MCI_SEQ_FILE, 0 MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "master\0", MCI_SEQ_SET_MASTER, MCI_CONSTANT,
+ "smpte\0", MCI_SEQ_SMPTE, 0, MCI_INTEGER,
+ "midi\0", MCI_SEQ_MIDI, 0, MCI_INTEGER,
+ "none\0", MCI_SEQ_NONE, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "offset\0", MCI_SEQ_SET_OFFSET, MCI_INTEGER,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "info\0", MCI_INFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "product\0", MCI_INFO_PRODUCT, MCI_FLAG,
+ "file\0", MCI_INFO_FILE, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+END
+
+/****************************************************************************
+* Command Lists for the animation command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+animation RCDATA
+BEGIN
+
+ "open\0", MCI_OPEN, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "type\0", MCI_OPEN_TYPE, MCI_STRING,
+ "element\0", MCI_OPEN_ELEMENT, MCI_STRING,
+ "alias\0", MCI_OPEN_ALIAS, MCI_STRING,
+ "shareable\0", MCI_OPEN_SHAREABLE, MCI_FLAG,
+ "style\0", MCI_ANIM_OPEN_WS, MCI_CONSTANT,
+ "overlapped\0", 0x00CF0000L/*WS_OVERLAPPEDWINDOW*/, MCI_INTEGER,
+ "popup\0", 0x80880000L/*WS_POPUPWINDOW*/, MCI_INTEGER,
+ "child\0", WS_CHILD, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "parent\0", MCI_ANIM_OPEN_PARENT, MCI_INTEGER,
+ "nostatic\0", MCI_ANIM_OPEN_NOSTATIC, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "play\0", MCI_PLAY, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "from\0", MCI_FROM, MCI_INTEGER,
+ "to\0", MCI_TO, MCI_INTEGER,
+ "fast\0", MCI_ANIM_PLAY_FAST, MCI_FLAG,
+ "slow\0", MCI_ANIM_PLAY_SLOW, MCI_FLAG,
+ "scan\0", MCI_ANIM_PLAY_SCAN, MCI_FLAG,
+ "reverse\0", MCI_ANIM_PLAY_REVERSE, MCI_FLAG,
+ "speed\0", MCI_ANIM_PLAY_SPEED, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "step\0", MCI_STEP, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "reverse\0", MCI_ANIM_STEP_REVERSE, MCI_FLAG,
+ "by\0", MCI_ANIM_STEP_FRAMES, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "set\0", MCI_SET, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "time format\0", MCI_SET_TIME_FORMAT, MCI_CONSTANT,
+ "milliseconds\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "ms\0", MCI_FORMAT_MILLISECONDS, 0, MCI_INTEGER,
+ "frames\0", MCI_FORMAT_FRAMES, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "audio\0", MCI_SET_AUDIO, MCI_CONSTANT,
+ "all\0", MCI_SET_AUDIO_ALL, MCI_INTEGER,
+ "left\0", MCI_SET_AUDIO_LEFT, MCI_INTEGER,
+ "right\0", MCI_SET_AUDIO_RIGHT, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "video\0", MCI_SET_VIDEO, MCI_FLAG,
+ "on\0", MCI_SET_ON, MCI_FLAG,
+ "off\0", MCI_SET_OFF, MCI_FLAG,
+ "door open\0", MCI_SET_DOOR_OPEN, MCI_FLAG,
+ "door closed\0", MCI_SET_DOOR_CLOSED, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "speed\0", MCI_ANIM_STATUS_SPEED, MCI_INTEGER,
+ "forward\0", MCI_ANIM_STATUS_FORWARD, MCI_INTEGER,
+ "window handle\0", MCI_ANIM_STATUS_HWND, MCI_INTEGER,
+ "palette handle\0", MCI_ANIM_STATUS_HPAL, MCI_INTEGER,
+ "media present\0", MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "time format\0", MCI_STATUS_TIME_FORMAT, MCI_INTEGER,
+ "current track\0", MCI_STATUS_CURRENT_TRACK, MCI_INTEGER,
+ "stretch\0", MCI_ANIM_STATUS_STRETCH, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "info\0", MCI_INFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "product\0", MCI_INFO_PRODUCT, MCI_FLAG,
+ "file\0", MCI_INFO_FILE, MCI_FLAG,
+ "window text\0", MCI_ANIM_INFO_TEXT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "capability\0", MCI_GETDEVCAPS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_GETDEVCAPS_ITEM, MCI_CONSTANT,
+ "can record\0", MCI_GETDEVCAPS_CAN_RECORD, MCI_INTEGER,
+ "has audio\0", MCI_GETDEVCAPS_HAS_AUDIO, MCI_INTEGER,
+ "has video\0", MCI_GETDEVCAPS_HAS_VIDEO, MCI_INTEGER,
+ "device type\0", MCI_GETDEVCAPS_DEVICE_TYPE, MCI_INTEGER,
+ "uses files\0", MCI_GETDEVCAPS_USES_FILES, MCI_INTEGER,
+ "compound device\0", MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
+ "can eject\0", MCI_GETDEVCAPS_CAN_EJECT, MCI_INTEGER,
+ "can play\0", MCI_GETDEVCAPS_CAN_PLAY, MCI_INTEGER,
+ "can save\0", MCI_GETDEVCAPS_CAN_SAVE, MCI_INTEGER,
+ "can reverse\0", MCI_ANIM_GETDEVCAPS_CAN_REVERSE,MCI_INTEGER,
+ "fast play rate\0", MCI_ANIM_GETDEVCAPS_FAST_RATE, MCI_INTEGER,
+ "slow play rate\0", MCI_ANIM_GETDEVCAPS_SLOW_RATE, MCI_INTEGER,
+ "normal play rate\0", MCI_ANIM_GETDEVCAPS_NORMAL_RATE,MCI_INTEGER,
+ "uses palettes\0", MCI_ANIM_GETDEVCAPS_PALETTES, MCI_INTEGER,
+ "can stretch\0", MCI_ANIM_GETDEVCAPS_CAN_STRETCH,MCI_INTEGER,
+ "windows\0", MCI_ANIM_GETDEVCAPS_MAX_WINDOWS,MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "realize\0", MCI_REALIZE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "normal\0", MCI_ANIM_REALIZE_NORM, MCI_FLAG,
+ "background\0", MCI_ANIM_REALIZE_BKGD, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "window\0", MCI_WINDOW, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "handle\0", MCI_ANIM_WINDOW_HWND, MCI_CONSTANT,
+ "default\0", 0L, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "state\0", MCI_ANIM_WINDOW_STATE, MCI_CONSTANT,
+ "hide\0", SW_HIDE, 0, MCI_INTEGER,
+ "minimize\0", SW_MINIMIZE, 0, MCI_INTEGER,
+ "show\0", SW_SHOW, 0, MCI_INTEGER,
+ "maximized\0", SW_SHOWMAXIMIZED, 0, MCI_INTEGER,
+ "minimized\0", SW_SHOWMINIMIZED, 0, MCI_INTEGER,
+ "iconic\0", SW_SHOWMINNOACTIVE, 0, MCI_INTEGER,
+ "no action\0", SW_SHOWNA, 0, MCI_INTEGER,
+ "no activate\0", SW_SHOWNOACTIVATE, 0, MCI_INTEGER,
+ "normal\0", SW_SHOWNORMAL, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "text\0", MCI_ANIM_WINDOW_TEXT, MCI_STRING,
+ "stretch\0", MCI_ANIM_WINDOW_ENABLE_STRETCH, MCI_FLAG,
+ "fixed\0", MCI_ANIM_WINDOW_DISABLE_STRETCH,MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "put\0", MCI_PUT, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "at\0", MCI_ANIM_RECT, MCI_RECT,
+ "source\0", MCI_ANIM_PUT_SOURCE, MCI_FLAG,
+ "destination\0", MCI_ANIM_PUT_DESTINATION, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "where\0", MCI_WHERE, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_RECT, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "source\0", MCI_ANIM_WHERE_SOURCE, MCI_FLAG,
+ "destination\0", MCI_ANIM_WHERE_DESTINATION, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "update\0", MCI_UPDATE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "at\0", MCI_ANIM_RECT, MCI_RECT,
+ "hdc\0", MCI_ANIM_UPDATE_HDC, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+
+END
+
+/****************************************************************************
+* Command Lists for the overlay command set - DO NOT LOCALIZE
+*****************************************************************************/
+
+overlay RCDATA
+BEGIN
+
+ "open\0", MCI_OPEN, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "type\0", MCI_OPEN_TYPE, MCI_STRING,
+ "element\0", MCI_OPEN_ELEMENT, MCI_STRING,
+ "alias\0", MCI_OPEN_ALIAS, MCI_STRING,
+ "shareable\0", MCI_OPEN_SHAREABLE, MCI_FLAG,
+ "style\0", MCI_OVLY_OPEN_WS, MCI_CONSTANT,
+ "overlapped\0", 0x00CF0000L/*WS_OVERLAPPEDWINDOW*/, MCI_INTEGER,
+ "popup\0", 0x80880000L/*WS_POPUPWINDOW*/, MCI_INTEGER,
+ "child\0", WS_CHILD, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "parent\0", MCI_OVLY_OPEN_PARENT, MCI_INTEGER,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "status\0", MCI_STATUS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_STATUS_ITEM, MCI_CONSTANT,
+ "position\0", MCI_STATUS_POSITION, MCI_INTEGER,
+ "length\0", MCI_STATUS_LENGTH, MCI_INTEGER,
+ "number of tracks\0", MCI_STATUS_NUMBER_OF_TRACKS, MCI_INTEGER,
+ "mode\0", MCI_STATUS_MODE, MCI_INTEGER,
+ "ready\0", MCI_STATUS_READY, MCI_INTEGER,
+ "window handle\0", MCI_OVLY_STATUS_HWND, MCI_INTEGER,
+ "media present\0", MCI_STATUS_MEDIA_PRESENT, MCI_INTEGER,
+ "stretch\0", MCI_OVLY_STATUS_STRETCH, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "track\0", MCI_TRACK, MCI_INTEGER,
+ "start\0", MCI_STATUS_START, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "info\0", MCI_INFO, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_STRING, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "product\0", MCI_INFO_PRODUCT, MCI_FLAG,
+ "file\0", MCI_INFO_FILE, MCI_FLAG,
+ "window text\0", MCI_OVLY_INFO_TEXT, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "capability\0", MCI_GETDEVCAPS, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_INTEGER, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_GETDEVCAPS_ITEM, MCI_CONSTANT,
+ "can record\0", MCI_GETDEVCAPS_CAN_RECORD, MCI_INTEGER,
+ "has audio\0", MCI_GETDEVCAPS_HAS_AUDIO, MCI_INTEGER,
+ "has video\0", MCI_GETDEVCAPS_HAS_VIDEO, MCI_INTEGER,
+ "device type\0", MCI_GETDEVCAPS_DEVICE_TYPE, MCI_INTEGER,
+ "uses files\0", MCI_GETDEVCAPS_USES_FILES, MCI_INTEGER,
+ "compound device\0", MCI_GETDEVCAPS_COMPOUND_DEVICE, MCI_INTEGER,
+ "can eject\0", MCI_GETDEVCAPS_CAN_EJECT, MCI_INTEGER,
+ "can play\0", MCI_GETDEVCAPS_CAN_PLAY, MCI_INTEGER,
+ "can save\0", MCI_GETDEVCAPS_CAN_SAVE, MCI_INTEGER,
+ "can stretch\0", MCI_OVLY_GETDEVCAPS_CAN_STRETCH,MCI_INTEGER,
+ "can freeze\0", MCI_OVLY_GETDEVCAPS_CAN_FREEZE, MCI_INTEGER,
+ "windows\0", MCI_OVLY_GETDEVCAPS_MAX_WINDOWS,MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "window\0", MCI_WINDOW, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "handle\0", MCI_OVLY_WINDOW_HWND, MCI_CONSTANT,
+ "default\0", 0L, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "state\0", MCI_OVLY_WINDOW_STATE, MCI_CONSTANT,
+ "hide\0", SW_HIDE, 0, MCI_INTEGER,
+ "minimize\0", SW_MINIMIZE, 0, MCI_INTEGER,
+ "show\0", SW_SHOW, 0, MCI_INTEGER,
+ "maximized\0", SW_SHOWMAXIMIZED, 0, MCI_INTEGER,
+ "minimized\0", SW_SHOWMINIMIZED, 0, MCI_INTEGER,
+ "iconic\0", SW_SHOWMINNOACTIVE, 0, MCI_INTEGER,
+ "no action\0", SW_SHOWNA, 0, MCI_INTEGER,
+ "no activate\0", SW_SHOWNOACTIVATE, 0, MCI_INTEGER,
+ "normal\0", SW_SHOWNORMAL, 0, MCI_INTEGER,
+ "\0", 0L, MCI_END_CONSTANT,
+ "text\0", MCI_OVLY_WINDOW_TEXT, MCI_STRING,
+ "stretch\0", MCI_OVLY_WINDOW_ENABLE_STRETCH, MCI_FLAG,
+ "fixed\0", MCI_OVLY_WINDOW_DISABLE_STRETCH,MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "put\0", MCI_PUT, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "at\0", MCI_OVLY_RECT, MCI_RECT,
+ "source\0", MCI_OVLY_PUT_SOURCE, MCI_FLAG,
+ "destination\0", MCI_OVLY_PUT_DESTINATION, MCI_FLAG,
+ "frame\0", MCI_OVLY_PUT_FRAME, MCI_FLAG,
+ "video\0", MCI_OVLY_PUT_VIDEO, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "where\0", MCI_WHERE, 0, MCI_COMMAND_HEAD,
+ "\0", MCI_RECT, 0, MCI_RETURN,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "source\0", MCI_OVLY_WHERE_SOURCE, MCI_FLAG,
+ "destination\0", MCI_OVLY_WHERE_DESTINATION, MCI_FLAG,
+ "frame\0", MCI_OVLY_WHERE_FRAME, MCI_FLAG,
+ "video\0", MCI_OVLY_WHERE_VIDEO, MCI_FLAG,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "save\0", MCI_SAVE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_SAVE_FILE, MCI_STRING,
+ "at\0", MCI_OVLY_RECT, MCI_RECT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "load\0", MCI_LOAD, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "\0", MCI_LOAD_FILE, MCI_STRING,
+ "at\0", MCI_OVLY_RECT, MCI_RECT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "freeze\0", MCI_FREEZE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "at\0", MCI_OVLY_RECT, MCI_RECT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "unfreeze\0", MCI_UNFREEZE, 0, MCI_COMMAND_HEAD,
+ "notify\0", MCI_NOTIFY, MCI_FLAG,
+ "wait\0", MCI_WAIT, MCI_FLAG,
+ "at\0", MCI_OVLY_RECT, MCI_RECT,
+ "\0", 0L, MCI_END_COMMAND,
+
+ "\0", 0L, MCI_END_COMMAND_LIST
+
+END
diff --git a/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rc b/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rc
new file mode 100644
index 000000000..1fc0566d1
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rc
@@ -0,0 +1,197 @@
+#include <windows.h>
+
+#define MMNOSOUND
+#define MMNOSEQ
+#define MMNOTIMER
+#define MMNOJOY
+#include "mmsystem.h"
+#include "mmsystem.rcv"
+
+#define NOTIMERDEV
+#define NOJOYDEV
+#define NOSEQDEV
+#define NOTASKDEV
+#include "mmddk.h"
+
+#include "mmsysi.h"
+
+STRINGTABLE
+begin
+ 0, "The specified command was carried out."
+
+ STR_MCIUNKNOWN, "Unknown error returned from MCI command"
+// STR_WAVEINPUT, "Wave Input: "
+// STR_WAVEOUTPUT, "Wave Output: "
+// STR_MIDIINPUT, "Midi Input: "
+// STR_MIDIOUTPUT, "Midi Output: "
+#ifdef DEBUG
+ STR_MCISSERRTXT, "Error in mciSendString but could not get text"
+ STR_MCISCERRTXT, "Error in mciSendCommand but could not get text"
+#endif
+ MMSYSERR_ERROR, "Undefined external error."
+ MMSYSERR_BADDEVICEID, "A device ID has been used that is out of range for your system."
+ MMSYSERR_NOTENABLED, "The driver was not enabled."
+ MMSYSERR_ALLOCATED, "The specified device is already in use. Wait until it is free, and then try again."
+ MMSYSERR_INVALHANDLE, "The specified device handle is invalid."
+ MMSYSERR_NODRIVER, "There is no driver installed on your system."
+ MMSYSERR_NOMEM, "Not enough memory available for this task. Quit one or more applications to increase available memory, and then try again."
+ MMSYSERR_NOTSUPPORTED, "This function is not supported. Use the Capabilities function to determine which functions and messages the driver supports."
+ MMSYSERR_BADERRNUM, "An error number was specified that is not defined in the system."
+ MMSYSERR_INVALFLAG, "An invalid flag was passed to a system function."
+ MMSYSERR_INVALPARAM, "An invalid parameter was passed to a system function."
+
+ WAVERR_BADFORMAT, "The specified format is not supported or cannot be translated. Use the Capabilities function to determine the supported formats."
+ WAVERR_UNPREPARED, "The wave header was not prepared. Use the Prepare function to prepare the header, and then try again."
+ WAVERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing."
+ WAVERR_SYNC, "Cannot open the device without using the WAVE_ALLOWSYNC flag. Use the flag, and then try again."
+
+ MIDIERR_UNPREPARED, "The MIDI header was not prepared. Use the Prepare function to prepare the header, and then try again."
+ MIDIERR_STILLPLAYING, "Cannot perform this operation while media data is still playing. Reset the device, or wait until the data is finished playing."
+ MIDIERR_NOMAP, "A MIDI map was not found. There may be a problem with the driver, or the MIDIMAP.CFG file may be corrupt or missing."
+ MIDIERR_NOTREADY, "The port is transmitting data to the device. Wait until the data has been transmitted, and then try again."
+ MIDIERR_NODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup."
+ MIDIERR_INVALIDSETUP, "The current MIDI setup is damaged. Copy the original MIDIMAP.CFG file to the Windows SYSTEM directory, and then try again."
+
+ MCIERR_INVALID_DEVICE_ID, "Invalid MCI device ID. Use the ID returned when opening the MCI device."
+ MCIERR_UNRECOGNIZED_KEYWORD, "The driver cannot recognize the specified command parameter."
+ MCIERR_UNRECOGNIZED_COMMAND, "The driver cannot recognize the specified command."
+ MCIERR_HARDWARE, "There is a problem with your media device. Make sure it is working correctly or contact the device manufacturer."
+ MCIERR_INVALID_DEVICE_NAME, "The specified device is not open or is not recognized by MCI."
+ MCIERR_OUT_OF_MEMORY, "Not enough memory available for this task.\n\nQuit one or more applications to increase available memory, and then try again."
+ MCIERR_DEVICE_OPEN, "The device name is already being used as an alias by this application. Use a unique alias."
+ MCIERR_CANNOT_LOAD_DRIVER, "There is an undetectable problem in loading the specified device driver."
+ MCIERR_MISSING_COMMAND_STRING, "No command was specified."
+ MCIERR_PARAM_OVERFLOW, "The output string was to large to fit in the return buffer. Increase the size of the buffer."
+ MCIERR_MISSING_STRING_ARGUMENT, "The specified command requires a character-string parameter. Please provide one."
+ MCIERR_BAD_INTEGER, "The specified integer is invalid for this command."
+ MCIERR_PARSER_INTERNAL, "The device driver returned an invalid return type. Check with the device manufacturer about obtaining a new driver."
+ MCIERR_DRIVER_INTERNAL, "There is a problem with the device driver. Check with the device manufacturer about obtaining a new driver."
+ MCIERR_MISSING_PARAMETER, "The specified command requires a parameter. Please supply one."
+ MCIERR_UNSUPPORTED_FUNCTION, "The MCI device you are using does not support the specified command."
+ MCIERR_NONAPPLICABLE_FUNCTION, "Cannot carry out the commands in the order specified. Correct the command sequence, and then try again."
+ MCIERR_FILE_NOT_FOUND, "Cannot find the specified file. Make sure the path and filename are correct."
+ MCIERR_DEVICE_NOT_READY, "The device driver is not ready."
+ MCIERR_INTERNAL, "A problem occurred in initializing MCI. Try restarting Windows."
+ MCIERR_DRIVER, "There is a problem with the device driver. The driver has closed. Cannot access error."
+ MCIERR_CANNOT_USE_ALL, "Cannot use 'all' as the device name with the specified command."
+ MCIERR_MULTIPLE, "Errors occurred in more than one device. Specify each command and device separately to determine which devices caused the errors."
+ MCIERR_EXTENSION_NOT_FOUND, "Cannot determine the device type from the given filename extension."
+ MCIERR_OUTOFRANGE, "The specified parameter is out of range for the specified command."
+ MCIERR_FLAGS_NOT_COMPATIBLE, "The specified parameters cannot be used together."
+ MCIERR_FILE_NOT_SAVED, "Cannot save the specified file. Make sure you have enough disk space or are still connected to the network."
+ MCIERR_FILE_READ, "Cannot read the specified file. Make sure the file is still present, or check your disk or network connection."
+ MCIERR_FILE_WRITE, "Cannot write to the specified file. Make sure you have enough disk space or are still connected to the network."
+ MCIERR_DEVICE_LOCKED, "The specified device is now being closed. Wait a few seconds, and then try again."
+ MCIERR_DUPLICATE_ALIAS, "The specified alias is already being used in this application. Use a unique alias."
+ MCIERR_BAD_CONSTANT, "The specified parameter is invalid for this command."
+ MCIERR_MUST_USE_SHAREABLE, "The device driver is already in use. To share it, use the 'shareable' parameter with each 'open' command."
+ MCIERR_MISSING_DEVICE_NAME, "The specified command requires an alias, file, driver, or device name. Please supply one."
+ MCIERR_BAD_TIME_FORMAT, "The specified value for the time format is invalid. Refer to the MCI documentation for valid formats."
+ MCIERR_NO_CLOSING_QUOTE, "A closing double-quotation mark is missing from the parameter value. Please supply one."
+ MCIERR_DUPLICATE_FLAGS, "A parameter or value was specified twice. Only specify it once."
+ MCIERR_INVALID_FILE, "The specified file cannot be played on the specified MCI device. The file may be corrupt, or not in the correct format."
+ MCIERR_NULL_PARAMETER_BLOCK, "A null parameter block was passed to MCI."
+ MCIERR_UNNAMED_RESOURCE, "Cannot save an unnamed file. Supply a filename."
+ MCIERR_NEW_REQUIRES_ALIAS, "You must specify an alias when using the 'new' parameter."
+ MCIERR_NOTIFY_ON_AUTO_OPEN, "Cannot use the 'notify' flag with auto-opened devices."
+ MCIERR_NO_ELEMENT_ALLOWED, "Cannot use a filename with the specified device."
+ MCIERR_ILLEGAL_FOR_AUTO_OPEN, "Cannot carry out the specified command on an auto-opened device. Wait until the device is closed, and then try again."
+ MCIERR_FILENAME_REQUIRED, "The filename is invalid. Make sure the filename is not longer than 8 characters, followed by a period and an extension."
+ MCIERR_EXTRA_CHARACTERS, "Cannot specify extra characters after a string enclosed in quotation marks."
+ MCIERR_DEVICE_NOT_INSTALLED, "The specified device is not installed on the system. Use the Drivers option in Control Panel to install the device."
+ MCIERR_GET_CD, "Cannot access the specified file or MCI device. Try changing directories or restarting your computer."
+ MCIERR_SET_CD, "Cannot access the specified file or MCI device because the application cannot change directories."
+ MCIERR_SET_DRIVE, "Cannot access specified file or MCI device because the application cannot change drives."
+ MCIERR_DEVICE_LENGTH, "Specify a device or driver name that is less than 79 characters."
+ MCIERR_DEVICE_ORD_LENGTH, "Specify a device or driver name that is less than 69 characters."
+ MCIERR_NO_INTEGER, "The specified command requires an integer parameter. Please provide one."
+
+ MCIERR_WAVE_OUTPUTSINUSE, "All wave devices that can play files in the current format are in use. Wait until a wave device is free, and then try again."
+ MCIERR_WAVE_SETOUTPUTINUSE, "Cannot set the current wave device for play back because it is in use. Wait until the device is free, and then try again."
+ MCIERR_WAVE_INPUTSINUSE, "All wave devices that can record files in the current format are in use. Wait until a wave device is free, and then try again."
+ MCIERR_WAVE_SETINPUTINUSE, "Cannot set the current wave device for recording because it is in use. Wait until the device is free, and then try again."
+ MCIERR_WAVE_OUTPUTUNSPECIFIED, "Any compatible waveform playback device may be used."
+ MCIERR_WAVE_INPUTUNSPECIFIED, "Any compatible waveform recording device may be used."
+ MCIERR_WAVE_OUTPUTSUNSUITABLE, "No wave device that can play files in the current format is installed. Use the Drivers option to install the wave device."
+ MCIERR_WAVE_SETOUTPUTUNSUITABLE, "The device you are trying to play to cannot recognize the current file format."
+ MCIERR_WAVE_INPUTSUNSUITABLE, "No wave device that can record files in the current format is installed. Use the Drivers option to install the wave device."
+ MCIERR_WAVE_SETINPUTUNSUITABLE, "The device you are trying to record from cannot recognize the current file format."
+
+ MCIERR_SEQ_DIV_INCOMPATIBLE, "Cannot use the song-pointer time format and the SMPTE time-format together."
+ MCIERR_SEQ_PORT_INUSE, "The specified MIDI device is already in use. Wait until it is free, and then try again."
+ MCIERR_SEQ_PORT_NONEXISTENT, "The specified MIDI device is not installed on the system. Use the Drivers option in Control Panel to install the driver."
+ MCIERR_SEQ_PORT_MAPNODEVICE, "The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use MIDI Mapper to edit the setup."
+ MCIERR_SEQ_PORT_MISCERROR, "An error occurred using the specified port."
+ MCIERR_SEQ_TIMER, "All multimedia timers are being used by other applications. Quit one of these applications, and then try again."
+ MCIERR_SEQ_PORTUNSPECIFIED, "There is no current MIDI port."
+ MCIERR_SEQ_NOMIDIPRESENT, "There are no MIDI devices installed on the system. Use the Drivers option in Control Panel to install the driver."
+
+ MCIERR_NO_WINDOW, "There is no display window."
+ MCIERR_CREATEWINDOW, "Could not create or use window."
+
+ MCIERR_DEVICE_TYPE_REQUIRED, "Cannot find the specified device. Make sure it is installed or that the device name is spelled correctly."
+
+ MCI_FALSE, "false"
+ MCI_TRUE, "true"
+
+ MCI_DEVTYPE_ANIMATION, "animation"
+ MCI_DEVTYPE_CD_AUDIO, "cdaudio"
+ MCI_DEVTYPE_DAT, "dat"
+ MCI_DEVTYPE_DIGITAL_VIDEO, "digitalvideo"
+ MCI_DEVTYPE_OTHER, "other"
+ MCI_DEVTYPE_OVERLAY, "overlay"
+ MCI_DEVTYPE_SCANNER, "scanner"
+ MCI_DEVTYPE_SEQUENCER, "sequencer"
+ MCI_DEVTYPE_VCR, "vcr"
+ MCI_DEVTYPE_VIDEODISC, "videodisc"
+ MCI_DEVTYPE_WAVEFORM_AUDIO, "waveaudio"
+
+ MCI_MODE_NOT_READY, "not ready"
+ MCI_MODE_STOP, "stopped"
+ MCI_MODE_PLAY, "playing"
+ MCI_MODE_RECORD, "recording"
+ MCI_MODE_SEEK, "seeking"
+ MCI_MODE_PAUSE, "paused"
+ MCI_MODE_OPEN, "open"
+
+ MCI_FORMAT_MILLISECONDS_S, "milliseconds"
+ MCI_FORMAT_HMS_S, "hms"
+ MCI_FORMAT_MSF_S, "msf"
+ MCI_FORMAT_FRAMES_S, "frames"
+ MCI_FORMAT_SMPTE_24_S, "smpte 24"
+ MCI_FORMAT_SMPTE_25_S, "smpte 25"
+ MCI_FORMAT_SMPTE_30_S, "smpte 30"
+ MCI_FORMAT_SMPTE_30DROP_S, "smpte 30 drop"
+ MCI_FORMAT_BYTES_S, "bytes"
+ MCI_FORMAT_SAMPLES_S, "samples"
+ MCI_FORMAT_TMSF_S, "tmsf"
+
+ MCI_VD_MODE_PARK, "parked"
+ MCI_VD_MEDIA_CAV, "CAV"
+ MCI_VD_MEDIA_CLV, "CLV"
+ MCI_VD_MEDIA_OTHER, "other"
+ MCI_VD_FORMAT_TRACK_S, "track"
+
+ MCI_SEQ_DIV_PPQN, "PPQN"
+ MCI_SEQ_DIV_SMPTE_24, "SMPTE 24 Frame"
+ MCI_SEQ_DIV_SMPTE_25, "SMPTE 25 Frame"
+ MCI_SEQ_DIV_SMPTE_30DROP, "SMPTE 30 Drop Frame"
+ MCI_SEQ_DIV_SMPTE_30, "SMPTE 30 Frame"
+ MIDIMAPPER_S, "mapper"
+ MCI_SEQ_FILE_S, "file"
+ MCI_SEQ_MIDI_S, "midi"
+ MCI_SEQ_SMPTE_S, "smpte"
+ MCI_SEQ_FORMAT_SONGPTR_S, "song pointer"
+ MCI_SEQ_NONE_S, "none"
+
+ WAVE_FORMAT_PCM_S, "pcm"
+ WAVE_MAPPER_S, "mapper"
+
+ IDS_TASKSTUB, "mmtask.tsk"
+end
+
+#include "mci.rc"
+
+#ifdef DEBUG
+#include "mmsex.dlg"
+#endif
diff --git a/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rcv b/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rcv
new file mode 100644
index 000000000..9761ffaac
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/messages/usa/mmsystem.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* MMSYSTEM.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "System APIs for Multimedia"
+#define VER_INTERNALNAME_STR "mmsystem.dll"
+#define VER_ORIGINALFILENAME_STR "mmsystem.dll"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rc b/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rc
new file mode 100644
index 000000000..0388fff09
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rc
@@ -0,0 +1,2 @@
+#include <windows.h>
+#include "mmtask.rcv"
diff --git a/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rcv b/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rcv
new file mode 100644
index 000000000..7bea4f228
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/messages/usa/mmtask.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* MMTASK.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Multimedia background task support module"
+#define VER_INTERNALNAME_STR "mmtask.tsk"
+#define VER_ORIGINALFILENAME_STR "mmtask.tsk"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/mmsystem/midi.c b/private/mvdm/wow16/mmsystem/midi.c
new file mode 100644
index 000000000..a991848d2
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/midi.c
@@ -0,0 +1,1728 @@
+/*****************************************************************************
+ midi.c
+
+ Level 1 kitchen sink DLL midi support module
+
+ Copyright (c) Microsoft Corporation 1990. All rights reserved
+
+*****************************************************************************/
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "thunks.h"
+
+/* -------------------------------------------------------------------------
+** Local functions
+** -------------------------------------------------------------------------
+*/
+static UINT NEAR PASCAL
+midiGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ );
+
+/* -------------------------------------------------------------------------
+** Local structures
+** -------------------------------------------------------------------------
+*/
+typedef struct mididev_tag {
+ PMIDIDRV mididrv;
+ UINT wDevice;
+ DWORD dwDrvUser;
+ UINT wDeviceID;
+} MIDIDEV;
+typedef MIDIDEV *PMIDIDEV;
+
+
+/* -------------------------------------------------------------------------
+** Segmentation
+**
+** Define the fixed code for this file.
+** -------------------------------------------------------------------------
+*/
+#pragma alloc_text( FIX, midiIMessage)
+#pragma alloc_text( FIX, midiOMessage)
+#pragma alloc_text( FIX, midiOutMessage)
+#pragma alloc_text( FIX, midiOutShortMsg)
+#pragma alloc_text( FIX, midiOutLongMsg)
+#pragma alloc_text( FIX, midiOutReset)
+
+/* -------------------------------------------------------------------------
+** Global data
+** -------------------------------------------------------------------------
+*/
+static int iMidiLockCount = 0;
+
+
+/*****************************************************************************
+ * @doc INTERNAL MIDI
+ *
+ * @api void | midiLockData |
+ *
+ * This function is called every time a new MIDI handle is created, it
+ * makes sure MMSYSTEM's data segment is page-locked. MIDI handles
+ * are useable at interupt time so we must page-lock the data seg.
+ *
+ * in the future we should re-do the MIDI system.
+ *
+ ****************************************************************************/
+BOOL NEAR PASCAL
+midiLockData(
+ void
+ )
+{
+ if (iMidiLockCount == 0) {
+
+ DOUT("MMSYSTEM: Locking data segment\r\n");
+
+ if ( !GlobalPageLock((HGLOBAL)HIWORD((DWORD)(LPVOID)&iMidiLockCount))
+ && (WinFlags & WF_ENHANCED)) {
+
+ return 0;
+ }
+ }
+
+ return ++iMidiLockCount;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL MIDI
+ *
+ * @api void | midiUnlockData |
+ *
+ * This function is called every time a MIDI handle is closed, it
+ * makes sure MMSYSTEM's data segment is un-page-locked. MIDI handles
+ * are useable at interupt time so we must page-lock the data seg.
+ *
+ * in the future we should re-do the MIDI system.
+ *
+ ****************************************************************************/
+void NEAR PASCAL
+midiUnlockData(
+ void
+ )
+{
+
+#ifdef DEBUG
+ if (iMidiLockCount == 0)
+ DOUT("MMSYSTEM: midiUnlockData() underflow!!!!\r\n");
+#endif
+
+ if (--iMidiLockCount == 0) {
+
+ DOUT("MMSYSTEM: Unlocking data segment\r\n");
+ GlobalPageUnlock((HGLOBAL)HIWORD((DWORD)(LPVOID)&iMidiLockCount));
+ }
+}
+
+/*****************************************************************************
+ * @doc INTERNAL MIDI
+ *
+ * @api UINT | midiPrepareHeader | This function prepares the header and data
+ * if the driver returns MMSYSERR_NOTSUPPORTED.
+ *
+ * @rdesc Currently always returns MMSYSERR_NOERROR.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+midiPrepareHeader(
+ LPMIDIHDR lpMidiHdr,
+ UINT wSize
+ )
+{
+ if (!HugePageLock(lpMidiHdr, (DWORD)sizeof(MIDIHDR)))
+ return MMSYSERR_NOMEM;
+
+ if (!HugePageLock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength)) {
+ HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
+ return MMSYSERR_NOMEM;
+ }
+
+// lpMidiHdr->dwFlags |= MHDR_PREPARED;
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL MIDI
+ *
+ * @api UINT | midiUnprepareHeader | This function unprepares the header and
+ * data if the driver returns MMSYSERR_NOTSUPPORTED.
+ *
+ * @rdesc Currently always returns MMSYSERR_NOERROR.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+midiUnprepareHeader(
+ LPMIDIHDR lpMidiHdr,
+ UINT wSize
+ )
+{
+ HugePageUnlock(lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
+ HugePageUnlock(lpMidiHdr, (DWORD)sizeof(MIDIHDR));
+
+// lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
+
+ return MMSYSERR_NOERROR;
+}
+
+
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutGetNumDevs | This function retrieves the number of MIDI
+ * output devices present in the system.
+ *
+ * @rdesc Returns the number of MIDI output devices present in the system.
+ *
+ * @xref midiOutGetDevCaps
+ ****************************************************************************/
+UINT WINAPI midiOutGetNumDevs(void)
+{
+ return midiOIDMessage( 0, MODM_GETNUMDEVS, 0L, 0L, 0L );
+}
+
+/****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api DWORD | midiOutMessage | This function sends messages to the MIDI device
+ * drivers.
+ *
+ * @parm HMIDIOUT | hMidiOut | The handle to the MIDI device.
+ *
+ * @parm UINT | msg | The message to send.
+ *
+ * @parm DWORD | dw1 | Parameter 1.
+ *
+ * @parm DWORD | dw2 | Parameter 2.
+ *
+ * @rdesc Returns the value of the message sent.
+ ***************************************************************************/
+DWORD WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT msg, DWORD dw1, DWORD dw2)
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, 0L);
+
+ return midiOMessage( (HMIDI)hMidiOut, msg, dw1, dw2);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutGetDevCaps | This function queries a specified
+ * MIDI output device to determine its capabilities.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI output device.
+ *
+ * @parm LPMIDIOUTCAPS | lpCaps | Specifies a far pointer to a <t MIDIOUTCAPS>
+ * structure. This structure is filled with information about the
+ * capabilities of the device.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIOUTCAPS> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ * @flag MMSYSERR_NOMEM | Unable load mapper string description.
+ *
+ * @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The MIDI_MAPPER constant may also be used as a device id. Only
+ * <p wSize> bytes (or less) of information is copied to the location
+ * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
+ * and the function returns zero.
+ *
+ * @xref midiOutGetNumDevs
+ ****************************************************************************/
+UINT WINAPI
+midiOutGetDevCaps(
+ UINT wDeviceID,
+ LPMIDIOUTCAPS lpCaps,
+ UINT wSize
+ )
+{
+ if (wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+
+ return midiOIDMessage( wDeviceID,
+ MODM_GETDEVCAPS, 0L, (DWORD)lpCaps, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutGetVolume | This function returns the current volume
+ * setting of a MIDI output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI output device.
+ *
+ * @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location
+ * to be filled with the current volume setting. The low-order word of
+ * this location contains the left channel volume setting, and the high-order
+ * WORD contains the right channel setting. A value of 0xFFFF represents
+ * full volume, and a value of 0x0000 is silence.
+ *
+ * If a device does not support both left and right volume
+ * control, the low-order word of the specified location contains
+ * the mono volume level.
+ *
+ * The full 16-bit setting(s)
+ * set with <f midiOutSetVolume> is returned, regardless of whether
+ * the device supports the full 16 bits of volume level control.
+ *
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Not all devices support volume control. To determine whether the
+ * device supports volume control, use the MIDICAPS_VOLUME
+ * flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
+ * structure (filled by <f midiOutGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both the
+ * left and right channels, use the MIDICAPS_LRVOLUME flag to test
+ * the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
+ * structure (filled by <f midiOutGetDevCaps>).
+ *
+ * @xref midiOutSetVolume
+ ****************************************************************************/
+UINT WINAPI
+midiOutGetVolume(
+ UINT wDeviceID,
+ LPDWORD lpdwVolume
+ )
+{
+ V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ return midiOIDMessage( wDeviceID, MODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0 );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutSetVolume | This function sets the volume of a
+ * MIDI output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI output device.
+ *
+ * @parm DWORD | dwVolume | Specifies the new volume setting.
+ * The low-order word contains the left channel volume setting, and the
+ * high-order word contains the right channel setting. A value of
+ * 0xFFFF represents full volume, and a value of 0x0000 is silence.
+ *
+ * If a device does not support both left and right volume
+ * control, the low-order word of <p dwVolume> specifies the volume
+ * level, and the high-order word is ignored.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Not all devices support volume changes. To determine whether the
+ * device supports volume control, use the MIDICAPS_VOLUME
+ * flag to test the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
+ * structure (filled by <f midiOutGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both the
+ * left and right channels, use the MIDICAPS_LRVOLUME flag to test
+ * the <e MIDIOUTCAPS.dwSupport> field of the <t MIDIOUTCAPS>
+ * structure (filled by <f midiOutGetDevCaps>).
+ *
+ * Most devices do not support the full 16 bits of volume level control
+ * and will use only the high-order bits of the requested volume setting.
+ * For example, for a device that supports 4 bits of volume control,
+ * requested volume level values of 0x4000, 0x4fff, and 0x43be will
+ * all produce the same physical volume setting, 0x4000. The
+ * <f midiOutGetVolume> function will return the full 16-bit setting set
+ * with <f midiOutSetVolume>.
+ *
+ * Volume settings are interpreted logarithmically. This means the
+ * perceived increase in volume is the same when increasing the
+ * volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
+ *
+ * @xref midiOutGetVolume
+ ****************************************************************************/
+UINT WINAPI
+midiOutSetVolume(
+ UINT wDeviceID,
+ DWORD dwVolume
+ )
+{
+ return midiOIDMessage( wDeviceID, MODM_SETVOLUME, 0L, dwVolume, 0);
+}
+
+/*****************************************************************************
+ * @doc INTERNAL MIDI
+ *
+ * @func UINT | midiGetErrorText | This function retrieves a textual
+ * description of the error identified by the specified error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to a buffer which
+ * is filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the length of the buffer pointed to by
+ * <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
+ * is returned.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+midiGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ lpText[0] = 0;
+
+#if MMSYSERR_BASE
+ if ( ((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR))
+ && ((wError < MIDIERR_BASE) || (wError > MIDIERR_LASTERROR))) {
+
+ return MMSYSERR_BADERRNUM;
+ }
+#else
+ if ((wError > MMSYSERR_LASTERROR) && ((wError < MIDIERR_BASE)
+ || (wError > MIDIERR_LASTERROR))) {
+
+ return MMSYSERR_BADERRNUM;
+ }
+#endif
+
+ if (wSize > 1) {
+
+ if (!LoadString(ghInst, wError, lpText, wSize)) {
+ return MMSYSERR_BADERRNUM;
+ }
+ }
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutGetErrorText | This function retrieves a textual
+ * description of the error identified by the specified error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to a buffer to be
+ * filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the length of the buffer pointed to by
+ * <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied, and the
+ * function returns MMSYSERR_NOERROR. All error descriptions are
+ * less than MAXERRORLENGTH characters long.
+ ****************************************************************************/
+UINT WINAPI
+midiOutGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ if(wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
+
+ return midiGetErrorText(wError, lpText, wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutOpen | This function opens a specified MIDI
+ * output device for playback.
+ *
+ * @parm LPHMIDIOUT | lphMidiOut | Specifies a far pointer to an HMIDIOUT
+ * handle. This location is filled with a handle identifying the opened
+ * MIDI output device. Use the handle to identify the device when calling
+ * other MIDI output functions.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI output device that is
+ * to be opened.
+ *
+ * @parm DWORD | dwCallback | Specifies the address of a fixed callback
+ * function or
+ * a handle to a window called during MIDI playback to process
+ * messages related to the progress of the playback. Specify NULL
+ * for this parameter if no callback is desired.
+ *
+ * @parm DWORD | dwCallbackInstance | Specifies user instance data
+ * passed to the callback. This parameter is not used with
+ * window callbacks.
+ *
+ * @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
+ * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
+ * assumed to be a window handle.
+ * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
+ * assumed to be a callback procedure address.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are as follows:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ * @flag MIDIERR_NOMAP | There is no current MIDI map. This occurs only
+ * when opening the mapper.
+ * @flag MIDIERR_NODEVICE | A port in the current MIDI map doesn't exist.
+ * This occurs only when opening the mapper.
+ *
+ * @comm Use <f midiOutGetNumDevs> to determine the number of MIDI output
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * You may also specify MIDI_MAPPER as the device ID to open the MIDI mapper.
+ *
+ * If a window is chosen to receive callback information, the following
+ * messages are sent to the window procedure function to indicate the
+ * progress of MIDI output: <m MM_MOM_OPEN>, <m MM_MOM_CLOSE>,
+ * <m MM_MOM_DONE>.
+ *
+ * If a function is chosen to receive callback information, the following
+ * messages are sent to the function to indicate the progress of MIDI
+ * output: <m MOM_OPEN>, <m MOM_CLOSE>, <m MOM_DONE>. The callback function
+ * must reside in a DLL. You do not have to use <f MakeProcInstance> to
+ * get a procedure-instance address for the callback function.
+ *
+ * @cb void CALLBACK | MidiOutFunc | <f MidiOutFunc> is a placeholder for
+ * the application-supplied function name. The actual name must be
+ * exported by including it in an EXPORTS statement in the DLL's
+ * module-definition file.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI device
+ * associated with the callback.
+ *
+ * @parm UINT | wMsg | Specifies a MIDI output message.
+ *
+ * @parm DWORD | dwInstance | Specifies the instance data
+ * supplied with <f midiOutOpen>.
+ *
+ * @parm DWORD | dwParam1 | Specifies a parameter for the message.
+ *
+ * @parm DWORD | dwParam2 | Specifies a parameter for the message.
+ *
+ * @comm Because the callback is accessed at interrupt time, it must reside
+ * in a DLL and its code segment must be specified as FIXED in the
+ * module-definition file for the DLL. Any data that the callback accesses
+ * must be in a FIXED data segment as well. The callback may not make any
+ * system calls except for <f PostMessage>, <f timeGetSystemTime>,
+ * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
+ * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
+ *
+ * @xref midiOutClose
+ ****************************************************************************/
+UINT WINAPI
+midiOutOpen(
+ LPHMIDIOUT lphMidiOut,
+ UINT wDeviceID,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD dwFlags
+ )
+{
+ MIDIOPENDESC mo;
+ PMIDIDEV pdev;
+ UINT wRet;
+
+ V_WPOINTER(lphMidiOut, sizeof(HMIDIOUT), MMSYSERR_INVALPARAM);
+ V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
+ V_FLAGS(LOWORD(dwFlags), 0, midiOutOpen, MMSYSERR_INVALFLAG);
+
+ /*
+ ** Check for no devices
+ */
+// if (wTotalMidiOutDevs == 0 ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+//
+// /*
+// ** check for device ID being to large
+// */
+// if ( wDeviceID != MIDI_MAPPER ) {
+// if ( wDeviceID >= wTotalMidiOutDevs ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+// }
+
+ *lphMidiOut = NULL;
+
+ if (!midiLockData()) {
+ return MMSYSERR_NOMEM;
+ }
+
+ pdev = (PMIDIDEV)NewHandle(TYPE_MIDIOUT, sizeof(MIDIDEV));
+ if( pdev == NULL) {
+ return MMSYSERR_NOMEM;
+ }
+
+ pdev->wDevice = wDeviceID;
+ pdev->wDeviceID = wDeviceID;
+
+ mo.hMidi = (HMIDI)pdev;
+ mo.dwCallback = dwCallback;
+ mo.dwInstance = dwInstance;
+
+ wRet = midiOIDMessage( wDeviceID, MODM_OPEN,
+ (DWORD)(LPDWORD)&pdev->dwDrvUser,
+ (DWORD)(LPMIDIOPENDESC)&mo, dwFlags );
+
+ if (wRet) {
+ FreeHandle((HMIDIOUT)pdev);
+ midiUnlockData();
+ } else {
+ *lphMidiOut = (HMIDIOUT)pdev;
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutClose | This function closes the specified MIDI
+ * output device.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output device.
+ * If the function is successful, the handle is no longer
+ * valid after this call.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
+ *
+ * @comm If there are output buffers that have been sent with
+ * <f midiOutLongMsg> and haven't been returned to the application,
+ * the close operation will fail. Call <f midiOutReset> to mark all
+ * pending buffers as being done.
+ *
+ * @xref midiOutOpen midiOutReset
+ ****************************************************************************/
+UINT WINAPI
+midiOutClose(
+ HMIDIOUT hMidiOut
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+
+ wRet = (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_CLOSE, 0L,0L);
+ if (!wRet) {
+ FreeHandle(hMidiOut);
+ midiUnlockData();
+ }
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutPrepareHeader | This function prepares a MIDI
+ * system-exclusive data block for output.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
+ * device.
+ *
+ * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
+ * structure that identifies the data block to be prepared.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ *
+ * @comm The <t MIDIHDR> data structure and the data block pointed to by its
+ * <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
+ * GMEM_MOVEABLE and GMEM_SHARE flags and locked with <f GlobalLock>.
+ * Preparing a header that has already been prepared has no effect, and
+ * the function returns zero.
+ *
+ * @xref midiOutUnprepareHeader
+ ****************************************************************************/
+UINT WINAPI
+midiOutPrepareHeader(
+ HMIDIOUT hMidiOut,
+ LPMIDIHDR lpMidiOutHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
+
+ if (lpMidiOutHdr->dwFlags & MHDR_PREPARED) {
+ return MMSYSERR_NOERROR;
+ }
+
+ lpMidiOutHdr->dwFlags = 0;
+
+ wRet = midiPrepareHeader(lpMidiOutHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_PREPARE,
+ (DWORD)lpMidiOutHdr, (DWORD)wSize );
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutUnprepareHeader | This function cleans up the
+ * preparation performed by <f midiOutPrepareHeader>. The
+ * <f midiOutUnprepareHeader> function must be called
+ * after the device driver fills a data buffer and returns it to the
+ * application. You must call this function before freeing the data
+ * buffer.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
+ * device.
+ *
+ * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a pointer to a <t MIDIHDR>
+ * structure identifying the buffer to be cleaned up.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_STILLPLAYING | <p lpMidiOutHdr> is still in the queue.
+ *
+ * @comm This function is the complementary function to
+ * <f midiOutPrepareHeader>.
+ * You must call this function before freeing the data buffer with
+ * <f GlobalFree>.
+ * After passing a buffer to the device driver with <f midiOutLongMsg>, you
+ * must wait until the driver is finished with the buffer before calling
+ * <f midiOutUnprepareHeader>.
+ *
+ * Unpreparing a buffer that has not been
+ * prepared has no effect, and the function returns zero.
+ *
+ * @xref midiOutPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+midiOutUnprepareHeader(
+ HMIDIOUT hMidiOut,
+ LPMIDIHDR lpMidiOutHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
+
+ if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
+ return MMSYSERR_NOERROR;
+ }
+
+ if(lpMidiOutHdr->dwFlags & MHDR_INQUEUE) {
+ DebugErr( DBF_WARNING,
+ "midiOutUnprepareHeader: header still in queue\r\n");
+ return MIDIERR_STILLPLAYING;
+ }
+
+ wRet = midiUnprepareHeader(lpMidiOutHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_UNPREPARE,
+ (DWORD)lpMidiOutHdr, (DWORD)wSize );
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutShortMsg | 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.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
+ * device.
+ *
+ * @parm DWORD | dwMsg | Specifies the MIDI message. The message is packed
+ * into a DWORD with the first byte of the message in the low-order byte.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_NOTREADY | The hardware is busy with other data.
+ *
+ * @comm This function may not return until the message has been sent to the
+ * output device.
+ *
+ * @xref midiOutLongMsg
+ ****************************************************************************/
+UINT WINAPI
+midiOutShortMsg(
+ HMIDIOUT hMidiOut,
+ DWORD dwMsg
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ return (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_DATA, dwMsg, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutLongMsg | This function sends a system-exclusive
+ * MIDI message to the specified MIDI output device.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
+ * device.
+ *
+ * @parm LPMIDIHDR | lpMidiOutHdr | Specifies a far pointer to a <t MIDIHDR>
+ * structure that identifies the MIDI data buffer.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_UNPREPARED | <p lpMidiOutHdr> hasn't been prepared.
+ * @flag MIDIERR_NOTREADY | The hardware is busy with other data.
+ *
+ * @comm The data buffer must be prepared with <f midiOutPrepareHeader>
+ * before it is passed to <f midiOutLongMsg>. The <t MIDIHDR> data
+ * structure and the data buffer pointed to by its <e MIDIHDR.lpData>
+ * field must be allocated with <f GlobalAlloc> using the GMEM_MOVEABLE
+ * and GMEM_SHARE flags, and locked with <f GlobalLock>. The MIDI output
+ * device driver determines whether the data is sent synchronously or
+ * asynchronously.
+ *
+ * @xref midiOutShortMsg midiOutPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+midiOutLongMsg(
+ HMIDIOUT hMidiOut,
+ LPMIDIHDR lpMidiOutHdr,
+ UINT wSize
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+
+//
+// we can't call these at interupt time.
+//
+#pragma message("header not validated for midiOutLongMessage")
+////V_HEADER(lpMidiOutHdr, wSize, TYPE_MIDIOUT, MMSYSERR_INVALPARAM);
+
+ if ( HIWORD(lpMidiOutHdr) == 0 ) {
+ return MMSYSERR_INVALPARAM;
+ }
+
+ if ( wSize != sizeof(MIDIHDR) ) {
+ return MMSYSERR_INVALPARAM;
+ }
+
+ if (LOWORD(lpMidiOutHdr->dwFlags) & ~MHDR_VALID) {
+ return MMSYSERR_INVALFLAG;
+ }
+
+ if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) {
+ return MIDIERR_UNPREPARED;
+ }
+
+ if (lpMidiOutHdr->dwFlags & MHDR_INQUEUE) {
+ return MIDIERR_STILLPLAYING;
+ }
+
+ return (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_LONGDATA,
+ (DWORD)lpMidiOutHdr, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutReset | This function turns off all notes on all MIDI
+ * channels for the specified MIDI output device. Any pending
+ * system-exclusive output buffers are marked as done and
+ * returned to the application.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the MIDI output
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm To turn off all notes, a note-off message for each note for each
+ * channel is sent. In addition, the sustain controller is turned off for
+ * each channel.
+ *
+ * @xref midiOutLongMsg midiOutClose
+ ****************************************************************************/
+UINT WINAPI
+midiOutReset(
+ HMIDIOUT hMidiOut
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ return (UINT)midiOMessage( (HMIDI)hMidiOut, MODM_RESET, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutCachePatches | 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.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
+ * device. This device must be an internal MIDI synthesizer.
+ *
+ * @parm UINT | wBank | Specifies which bank of patches should be used.
+ * This parameter should be set to zero to cache the default patch bank.
+ *
+ * @parm WORD FAR* | lpPatchArray | Specifies a pointer to a <t PATCHARRAY>
+ * array indicating the patches to be cached or uncached.
+ *
+ * @parm UINT | wFlags | Specifies options for the cache operation. Only one
+ * of the following flags can be specified:
+ * @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
+ * can't all be cached, cache none, clear the <t PATCHARRAY> array,
+ * and return MMSYSERR_NOMEM.
+ * @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
+ * If all patches can't be cached, cache as many patches as
+ * possible, change the <t PATCHARRAY> array to reflect which
+ * patches were cached, and return MMSYSERR_NOMEM.
+ * @flag MIDI_CACHE_QUERY | Change the <t PATCHARRAY> array to indicate
+ * which patches are currently cached.
+ * @flag MIDI_UNCACHE | Uncache the specified patches and clear the
+ * <t PATCHARRAY> array.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * one of the following error codes:
+ * @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
+ * patch caching.
+ * @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
+ * all of the requested patches.
+ *
+ * @comm The <t PATCHARRAY> data type is defined as:
+ *
+ * typedef WORD PATCHARRAY[MIDIPATCHSIZE];
+ *
+ * Each element of the array represents one of the 128 patches and
+ * has bits set for
+ * each of the 16 MIDI channels that use that particular patch. The
+ * least-significant bit represents physical channel 0; the
+ * most-significant bit represents physical channel 15 (0x0F). For
+ * example, if patch 0 is used by physical channels 0 and 8, element 0
+ * would be set to 0x0101.
+ *
+ * This function only applies to internal MIDI synthesizer devices.
+ * Not all internal synthesizers support patch caching. Use the
+ * MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
+ * <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
+ * device supports patch caching.
+ *
+ * @xref midiOutCacheDrumPatches
+ ****************************************************************************/
+UINT WINAPI
+midiOutCachePatches(
+ HMIDIOUT hMidiOut,
+ UINT wBank,
+ WORD FAR* lpPatchArray,
+ UINT wFlags
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpPatchArray, sizeof(PATCHARRAY), MMSYSERR_INVALPARAM);
+ V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCachePatches, MMSYSERR_INVALFLAG);
+
+ return (UINT)midiOMessage( (HMIDI)hMidiOut,
+ MODM_CACHEPATCHES, (DWORD)lpPatchArray,
+ MAKELONG(wFlags, wBank) );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutCacheDrumPatches | 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 available.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies a handle to the opened MIDI output
+ * device. This device should be an internal MIDI synthesizer.
+ *
+ * @parm UINT | wPatch | Specifies which drum patch number should be used.
+ * This parameter should be set to zero to cache the default drum patch.
+ *
+ * @parm WORD FAR* | lpKeyArray | Specifies a pointer to a <t KEYARRAY>
+ * array indicating the key numbers of the specified percussion patches
+ * to be cached or uncached.
+ *
+ * @parm UINT | wFlags | Specifies options for the cache operation. Only one
+ * of the following flags can be specified:
+ * @flag MIDI_CACHE_ALL | Cache all of the specified patches. If they
+ * can't all be cached, cache none, clear the <t KEYARRAY> array,
+ * and return MMSYSERR_NOMEM.
+ * @flag MIDI_CACHE_BESTFIT | Cache all of the specified patches.
+ * If all patches can't be cached, cache as many patches as
+ * possible, change the <t KEYARRAY> array to reflect which
+ * patches were cached, and return MMSYSERR_NOMEM.
+ * @flag MIDI_CACHE_QUERY | Change the <t KEYARRAY> array to indicate
+ * which patches are currently cached.
+ * @flag MIDI_UNCACHE | Uncache the specified patches and clear the
+ * <t KEYARRAY> array.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * one of the following error codes:
+ * @flag MMSYSERR_INVALHANDLE | The specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | The specified device does not support
+ * patch caching.
+ * @flag MMSYSERR_NOMEM | The device does not have enough memory to cache
+ * all of the requested patches.
+ *
+ * @comm The <t KEYARRAY> data type is defined as:
+ *
+ * typedef WORD KEYARRAY[MIDIPATCHSIZE];
+ *
+ * Each element of the array represents one of the 128 key-based percussion
+ * patches and has bits set for
+ * each of the 16 MIDI channels that use that particular patch. The
+ * least-significant bit represents physical channel 0; the
+ * most-significant bit represents physical channel 15. For
+ * example, if the patch on key number 60 is used by physical channels 9
+ * and 15, element 60 would be set to 0x8200.
+ *
+ * This function applies only to internal MIDI synthesizer devices.
+ * Not all internal synthesizers support patch caching. Use the
+ * MIDICAPS_CACHE flag to test the <e MIDIOUTCAPS.dwSupport> field of the
+ * <t MIDIOUTCAPS> structure filled by <f midiOutGetDevCaps> to see if the
+ * device supports patch caching.
+ *
+ * @xref midiOutCachePatches
+ ****************************************************************************/
+UINT WINAPI
+midiOutCacheDrumPatches(
+ HMIDIOUT hMidiOut,
+ UINT wPatch,
+ WORD FAR* lpKeyArray,
+ UINT wFlags
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpKeyArray, sizeof(KEYARRAY), MMSYSERR_INVALPARAM);
+ V_FLAGS(wFlags, MIDI_CACHE_VALID, midiOutCacheDrumPatches, MMSYSERR_INVALFLAG);
+
+ return (UINT)midiOMessage( (HMIDI)hMidiOut,
+ MODM_CACHEDRUMPATCHES, (DWORD)lpKeyArray,
+ MAKELONG(wFlags, wPatch) );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInGetNumDevs | This function retrieves the number of MIDI
+ * input devices in the system.
+ *
+ * @rdesc Returns the number of MIDI input devices present in the system.
+ *
+ * @xref midiInGetDevCaps
+ ****************************************************************************/
+UINT WINAPI
+midiInGetNumDevs(
+ void
+ )
+{
+ return midiIIDMessage( 0, MIDM_GETNUMDEVS, 0L, 0L, 0L );
+}
+
+/****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api DWORD | midiInMessage | This function sends messages to the MIDI device
+ * drivers.
+ *
+ * @parm HMIDIIN | hMidiIn | The handle to the MIDI device.
+ *
+ * @parm UINT | msg | The message to send.
+ *
+ * @parm DWORD | dw1 | Parameter 1.
+ *
+ * @parm DWORD | dw2 | Parameter 2.
+ *
+ * @rdesc Returns the value of the message sent.
+ ***************************************************************************/
+DWORD WINAPI
+midiInMessage(
+ HMIDIIN hMidiIn,
+ UINT msg,
+ DWORD dw1,
+ DWORD dw2
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, 0L);
+
+ return midiIMessage( (HMIDI)hMidiIn, msg, dw1, dw2);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInGetDevCaps | This function queries a specified MIDI input
+ * device to determine its capabilities.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI input device.
+ *
+ * @parm LPMIDIINCAPS | lpCaps | Specifies a far pointer to a <t MIDIINCAPS>
+ * data structure. This structure is filled with information about
+ * the capabilities of the device.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIINCAPS> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The MIDI_MAPPER constant may also be used as a device id. Only
+ * <p wSize> bytes (or less) of information is copied to the location
+ * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied,
+ * and the function returns zero.
+ *
+ * @xref midiInGetNumDevs
+ ****************************************************************************/
+UINT WINAPI
+midiInGetDevCaps(
+ UINT wDeviceID,
+ LPMIDIINCAPS lpCaps,
+ UINT wSize
+ )
+{
+ if (wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+
+ return midiIIDMessage( wDeviceID,
+ MIDM_GETDEVCAPS, 0L, (DWORD)lpCaps, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInGetErrorText | This function retrieves a textual
+ * description of the error identified by the specified error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to the buffer to be
+ * filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the length of buffer pointed to by
+ * <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied, and
+ * the function returns zero. All error descriptions are
+ * less than MAXERRORLENGTH characters long.
+ ****************************************************************************/
+UINT WINAPI
+midiInGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ if(wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
+
+ return midiGetErrorText(wError, lpText, wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInOpen | This function opens a specified MIDI input device.
+ *
+ * @parm LPHMIDIIN | lphMidiIn | Specifies a far pointer to an HMIDIIN handle.
+ * This location is filled with a handle identifying the opened MIDI
+ * input device. Use the handle to identify the device when calling
+ * other MIDI input functions.
+ *
+ * @parm UINT | wDeviceID | Identifies the MIDI input device to be
+ * opened.
+ *
+ * @parm DWORD | dwCallback | Specifies the address of a fixed callback
+ * function or a handle to a window called with information
+ * about incoming MIDI messages.
+ *
+ * @parm DWORD | dwCallbackInstance | Specifies user instance data
+ * passed to the callback function. This parameter is not
+ * used with window callbacks.
+ *
+ * @parm DWORD | dwFlags | Specifies a callback flag for opening the device.
+ * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
+ * assumed to be a window handle.
+ * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
+ * assumed to be a callback procedure address.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ *
+ * @comm Use <f midiInGetNumDevs> to determine the number of MIDI input
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The MIDI_MAPPER constant may also be used as a device id.
+ *
+ * If a window is chosen to receive callback information, the following
+ * messages are sent to the window procedure function to indicate the
+ * progress of MIDI input: <m MM_MIM_OPEN>, <m MM_MIM_CLOSE>,
+ * <m MM_MIM_DATA>, <m MM_MIM_LONGDATA>, <m MM_MIM_ERROR>,
+ * <m MM_MIM_LONGERROR>.
+ *
+ * If a function is chosen to receive callback information, the following
+ * messages are sent to the function to indicate the progress of MIDI
+ * input: <m MIM_OPEN>, <m MIM_CLOSE>, <m MIM_DATA>, <m MIM_LONGDATA>,
+ * <m MIM_ERROR>, <m MIM_LONGERROR>. The callback function must reside in
+ * a DLL. You do not have to use <f MakeProcInstance> to get a
+ * procedure-instance address for the callback function.
+ *
+ * @cb void CALLBACK | MidiInFunc | <f MidiInFunc> is a placeholder for
+ * the application-supplied function name. The actual name must be
+ * exported by including it in an EXPORTS statement in the DLL's module
+ * definition file.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ *
+ * @parm UINT | wMsg | Specifies a MIDI input message.
+ *
+ * @parm DWORD | dwInstance | Specifies the instance data supplied
+ * with <f midiInOpen>.
+ *
+ * @parm DWORD | dwParam1 | Specifies a parameter for the message.
+ *
+ * @parm DWORD | dwParam2 | Specifies a parameter for the message.
+ *
+ * @comm Because the callback is accessed at interrupt time, it must reside
+ * in a DLL, and its code segment must be specified as FIXED in the
+ * module-definition file for the DLL. Any data that the callback accesses
+ * must be in a FIXED data segment as well. The callback may not make any
+ * system calls except for <f PostMessage>, <f timeGetSystemTime>,
+ * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
+ * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
+ *
+ * @xref midiInClose
+ ****************************************************************************/
+UINT WINAPI
+midiInOpen(
+ LPHMIDIIN lphMidiIn,
+ UINT wDeviceID,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD dwFlags
+ )
+{
+ MIDIOPENDESC mo;
+ PMIDIDEV pdev;
+ UINT wRet;
+
+ V_WPOINTER(lphMidiIn, sizeof(HMIDIIN), MMSYSERR_INVALPARAM);
+ V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
+ V_FLAGS(LOWORD(dwFlags), 0, midiInOpen, MMSYSERR_INVALFLAG);
+
+ /*
+ ** Check for no devices
+ */
+// if (wTotalMidiInDevs == 0 ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+//
+// /*
+// ** check for device ID being to large
+// */
+// if ( wDeviceID != MIDI_MAPPER ) {
+// if ( wDeviceID >= wTotalMidiInDevs ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+// }
+
+ *lphMidiIn = NULL;
+
+ if (!midiLockData()) {
+ return MMSYSERR_NOMEM;
+ }
+
+ pdev = (PMIDIDEV)NewHandle(TYPE_MIDIIN, sizeof(MIDIDEV));
+ if( pdev == NULL) {
+ return MMSYSERR_NOMEM;
+ }
+
+ pdev->wDevice = wDeviceID;
+ pdev->wDeviceID = wDeviceID;
+
+ mo.hMidi = (HMIDI)pdev;
+ mo.dwCallback = dwCallback;
+ mo.dwInstance = dwInstance;
+
+ wRet = midiIIDMessage( wDeviceID, MIDM_OPEN,
+ (DWORD)(LPDWORD)&pdev->dwDrvUser,
+ (DWORD)(LPMIDIOPENDESC)&mo, dwFlags );
+
+ if (wRet) {
+ FreeHandle((HMIDIIN)pdev);
+ midiUnlockData();
+ } else {
+ *lphMidiIn = (HMIDIIN)pdev;
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInClose | This function closes the specified MIDI input
+ * device.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ * If the function is successful, the handle is no longer
+ * valid after this call.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_STILLPLAYING | There are still buffers in the queue.
+ *
+ * @comm If there are input buffers that have been sent with
+ * <f midiInAddBuffer> and haven't been returned to the application,
+ * the close operation will fail. Call <f midiInReset> to mark all
+ * pending buffers as being done.
+ *
+ * @xref midiInOpen midiInReset
+ ****************************************************************************/
+UINT WINAPI
+midiInClose(
+ HMIDIIN hMidiIn
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+
+ wRet = (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_CLOSE, 0L, 0L);
+
+ if (!wRet) {
+ FreeHandle(hMidiIn);
+ midiUnlockData();
+ }
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInPrepareHeader | This function prepares a buffer for
+ * MIDI input.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
+ * device.
+ *
+ * @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
+ * structure that identifies the buffer to be prepared.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ *
+ * @comm The <t MIDIHDR> data structure and the data block pointed to by its
+ * <e MIDIHDR.lpData> field must be allocated with <f GlobalAlloc> using the
+ * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
+ * Preparing a header that has already been prepared has no effect,
+ * and the function returns zero.
+ *
+ * @xref midiInUnprepareHeader
+ ****************************************************************************/
+UINT WINAPI
+midiInPrepareHeader(
+ HMIDIIN hMidiIn,
+ LPMIDIHDR lpMidiInHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
+
+ if (lpMidiInHdr->dwFlags & MHDR_PREPARED) {
+ return MMSYSERR_NOERROR;
+ }
+
+ lpMidiInHdr->dwFlags = 0;
+
+ wRet = midiPrepareHeader(lpMidiInHdr, wSize);
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_PREPARE,
+ (DWORD)lpMidiInHdr, (DWORD)wSize);
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInUnprepareHeader | This function cleans up the
+ * preparation performed by <f midiInPrepareHeader>. The
+ * <f midiInUnprepareHeader> function must be called
+ * after the device driver fills a data buffer and returns it to the
+ * application. You must call this function before freeing the data
+ * buffer.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input
+ * device.
+ *
+ * @parm LPMIDIHDR | lpMidiInHdr | Specifies a pointer to a <t MIDIHDR>
+ * structure identifying the data buffer to be cleaned up.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_STILLPLAYING | <p lpMidiInHdr> is still in the queue.
+ *
+ * @comm This function is the complementary function to <f midiInPrepareHeader>.
+ * You must call this function before freeing the data buffer with
+ * <f GlobalFree>.
+ * After passing a buffer to the device driver with <f midiInAddBuffer>, you
+ * must wait until the driver is finished with the buffer before calling
+ * <f midiInUnprepareHeader>. Unpreparing a buffer that has not been
+ * prepared has no effect, and the function returns zero.
+ *
+ * @xref midiInPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+midiInUnprepareHeader(
+ HMIDIIN hMidiIn,
+ LPMIDIHDR lpMidiInHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
+
+ if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
+ return MMSYSERR_NOERROR;
+ }
+
+ if(lpMidiInHdr->dwFlags & MHDR_INQUEUE) {
+ DebugErr( DBF_WARNING,
+ "midiInUnprepareHeader: header still in queue\r\n");
+ return MIDIERR_STILLPLAYING;
+ }
+
+
+ wRet = midiUnprepareHeader(lpMidiInHdr, wSize);
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_UNPREPARE,
+ (DWORD)lpMidiInHdr, (DWORD)wSize);
+ }
+ return wRet;
+}
+
+/******************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInAddBuffer | 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.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ *
+ * @parm LPMIDIHDR | lpMidiInHdr | Specifies a far pointer to a <t MIDIHDR>
+ * structure that identifies the buffer.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MIDIHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MIDIERR_UNPREPARED | <p lpMidiInHdr> hasn't been prepared.
+ *
+ * @comm The data buffer must be prepared with <f midiInPrepareHeader> before
+ * it is passed to <f midiInAddBuffer>. The <t MIDIHDR> data structure
+ * and the data buffer pointed to by its <e MIDIHDR.lpData> field must be allocated
+ * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
+ * locked with <f GlobalLock>.
+ *
+ * @xref midiInPrepareHeader
+ *****************************************************************************/
+UINT WINAPI
+midiInAddBuffer(
+ HMIDIIN hMidiIn,
+ LPMIDIHDR lpMidiInHdr,
+ UINT wSize
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpMidiInHdr, wSize, TYPE_MIDIIN, MMSYSERR_INVALPARAM);
+
+ if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) {
+ DebugErr(DBF_WARNING, "midiInAddBuffer: buffer not prepared\r\n");
+ return MIDIERR_UNPREPARED;
+ }
+
+ if (lpMidiInHdr->dwFlags & MHDR_INQUEUE) {
+ DebugErr(DBF_WARNING, "midiInAddBuffer: buffer already in queue\r\n");
+ return MIDIERR_STILLPLAYING;
+ }
+
+ return (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_ADDBUFFER,
+ (DWORD)lpMidiInHdr, (DWORD)wSize );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInStart | This function starts MIDI input on the
+ * specified MIDI input device.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm This function resets the timestamps to zero; timestamp values for
+ * subsequently received messages are relative to the time this
+ * function was called.
+ *
+ * All messages other than system-exclusive messages are sent
+ * directly to the client when received. System-exclusive
+ * messages are placed in the buffers supplied by <f midiInAddBuffer>;
+ * if there are no buffers in the queue,
+ * the data is thrown away without notification to the client, and input
+ * continues.
+ *
+ * Buffers are returned to the client when full, when a
+ * complete system-exclusive message has been received,
+ * or when <f midiInReset> is
+ * called. The <e MIDIHDR.dwBytesRecorded> field in the header will contain the
+ * actual length of data received.
+ *
+ * Calling this function when input is already started has no effect, and
+ * the function returns zero.
+ *
+ * @xref midiInStop midiInReset
+ ****************************************************************************/
+UINT WINAPI
+midiInStart(
+ HMIDIIN hMidiIn
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+ return (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_START, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInStop | This function terminates MIDI input on the
+ * specified MIDI input device.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Current status (running status, parsing state, etc.) is maintained
+ * across calls to <f midiInStop> and <f midiInStart>.
+ * If there are any system-exclusive message buffers in the queue,
+ * the current buffer
+ * is marked as done (the <e MIDIHDR.dwBytesRecorded> field in the header will
+ * contain the actual length of data), but any empty buffers in the queue
+ * remain there. Calling this function when input is not started has no
+ * no effect, and the function returns zero.
+ *
+ * @xref midiInStart midiInReset
+ ****************************************************************************/
+UINT WINAPI
+midiInStop(
+ HMIDIIN hMidiIn
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+
+ return (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_STOP, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInReset | This function stops input on a given MIDI
+ * input device and marks all pending input buffers as done.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies a handle to the MIDI input device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @xref midiInStart midiInStop midiInAddBuffer midiInClose
+ ****************************************************************************/
+UINT WINAPI
+midiInReset(
+ HMIDIIN hMidiIn
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+
+ return (UINT)midiIMessage( (HMIDI)hMidiIn, MIDM_RESET, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiInGetID | This function gets the device ID for a
+ * MIDI input device.
+ *
+ * @parm HMIDIIN | hMidiIn | Specifies the handle to the MIDI input
+ * device.
+ * @parm UINT FAR* | lpwDeviceID | Specifies a pointer to the UINT-sized
+ * memory location to be filled with the device ID.
+ *
+ * @rdesc Returns zero if successful. Otherwise, returns
+ * an error number. Possible error returns are:
+ *
+ * @flag MMSYSERR_INVALHANDLE | The <p hMidiIn> parameter specifies an
+ * invalid handle.
+ *
+ ****************************************************************************/
+UINT WINAPI
+midiInGetID(
+ HMIDIIN hMidiIn,
+ UINT FAR* lpwDeviceID
+ )
+{
+ V_HANDLE(hMidiIn, TYPE_MIDIIN, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpwDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+ *lpwDeviceID = ((PMIDIDEV)hMidiIn)->wDeviceID;
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL MIDI
+ *
+ * @api UINT | midiOutGetID | This function gets the device ID for a
+ * MIDI output device.
+ *
+ * @parm HMIDIOUT | hMidiOut | Specifies the handle to the MIDI output
+ * device.
+ * @parm UINT FAR* | lpwDeviceID | Specifies a pointer to the UINT-sized
+ * memory location to be filled with the device ID.
+ *
+ * @rdesc Returns MMSYSERR_NOERROR if successful. Otherwise, returns
+ * an error number. Possible error returns are:
+ *
+ * @flag MMSYSERR_INVALHANDLE | The <p hMidiOut> parameter specifies an
+ * invalid handle.
+ *
+ ****************************************************************************/
+UINT WINAPI
+midiOutGetID(
+ HMIDIOUT hMidiOut,
+ UINT FAR* lpwDeviceID
+ )
+{
+ V_HANDLE(hMidiOut, TYPE_MIDIOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpwDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+ *lpwDeviceID = ((PMIDIDEV)hMidiOut)->wDeviceID;
+ return MMSYSERR_NOERROR;
+}
+
+#if 0
+/*****************************Private*Routine******************************\
+* midiIDMessage
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT FAR PASCAL
+midiIDMessage(
+ LPSOUNDDEVMSGPROC lpProc,
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+ )
+{
+ return CallProc32W( (DWORD)wDeviceID, (DWORD)wMessage,
+ dwUser, dwParam1, dwParam2, lpProc, 0L, 5L );
+}
+#endif
diff --git a/private/mvdm/wow16/mmsystem/mixer.c b/private/mvdm/wow16/mmsystem/mixer.c
new file mode 100644
index 000000000..36ff0e9f4
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mixer.c
@@ -0,0 +1,1950 @@
+//==========================================================================;
+//
+// mixapi.c
+//
+// Copyright (C) 1992-1993 Microsoft Corporation. All Rights Reserved.
+//
+// Description:
+//
+//
+// History:
+// 6/27/93 cjp [curtisp]
+//
+//==========================================================================;
+#define _WINDLL
+#include <windows.h>
+#include <windowsx.h>
+#include <string.h>
+
+#include <mmsystem.h>
+#include <mmddk.h>
+
+#include "mmreg.h"
+#include "mmsysi.h"
+
+//
+// fix a conflict will a bad define in MMREG.H that shipped with NT
+// the define is bogus for some silly Media Vision crap...
+//
+// why not just build MSMIXMGR with a NEW mmreg.h??
+//
+#ifdef MIXERR_BASE
+#undef MIXERR_BASE
+#endif // MIXERR_BASE
+
+
+#define _INC_MMDDK
+#include "msmixmgr.y"
+
+
+#define WODM_MAPPER_STATUS (0x2000)
+#define WAVEOUT_MAPPER_STATUS_DEVICE 0
+#define WIDM_MAPPER_STATUS (0x2000)
+#define WAVEIN_MAPPER_STATUS_DEVICE 0
+
+#include "idrv.h"
+#include "mixmgri.h"
+#include "debug.h"
+
+UINT FAR PASCAL
+mmCallProc32(
+ DWORD uId,
+ DWORD uMsg,
+ DWORD dwInst,
+ DWORD dwP1,
+ DWORD dwP2,
+ DRIVERMSGPROC fp,
+ DWORD dwDirChange );
+
+/* -------------------------------------------------------------------------
+** thunking global variables
+** -------------------------------------------------------------------------
+*/
+DWORD mix32Lib;
+
+BOOL FAR PASCAL
+InitMixerThunks(
+ void
+ );
+
+DWORD CALLBACK
+mxdMessage(
+ UINT uId,
+ UINT uMsg,
+ DWORD dwInstance,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+
+#define CHECK_AND_INIT_THUNKS( _x_ ) \
+ if ( (_x_) == 0L ) { \
+ if ( InitMixerThunks() == FALSE ) { \
+ return MMSYSERR_NODRIVER; \
+ } \
+ }
+
+UINT guTotalMixerDevs; // total mixer devices
+DRIVERMSGPROC mix32Message;
+typedef MMDRV MIXERDRV, *PMIXERDRV;
+
+
+//
+//
+//
+typedef struct tMIXERDEV {
+ UINT uHandleType; // for parameter validation
+
+ struct tMIXERDEV *pmxdevNext; /* How quaint, a linked list... */
+ PMIXERDRV pmxdrv;
+ UINT wDevice;
+ DWORD dwDrvUser;
+ UINT uDeviceID;
+
+ DWORD fdwSupport; // from the driver's mixercaps
+ DWORD cDestinations; // from the driver's mixercaps
+
+ DWORD dwCallback; // client's callback and inst data
+ DWORD dwInstance;
+
+ DWORD fdwOpen; /* The open flags the caller used */
+} MIXERDEV, *PMIXERDEV;
+
+PMIXERDEV gpMixerDevHeader = NULL; /* A LL of open devices */
+
+//
+// mixer device driver list--add one to accomodate the MIXER_MAPPER. note
+// that even if we are not compiling with mapper support we need to add
+// one because other code relies on it (for other device mappers).
+//
+MIXERDRV mixerdrv[1];
+
+
+
+
+//==========================================================================;
+//
+// Mixer API's
+//
+//
+//==========================================================================;
+
+//--------------------------------------------------------------------------;
+//
+// DWORD IMixerMapId
+//
+// Description:
+// This function maps a logical id to a device driver table index and
+// physical id.
+//
+// Arguments:
+// PMIXERDRV pmxdrv: The array of mixer drivers.
+//
+// UINT uTotalNumDevs: The total number of mixer devices.
+//
+// UINT uId: The logical id to be mapped.
+//
+// Return (DWORD):
+// The return value contains the dev[] array element id in the high word
+// and the driver physical device number in the low word.
+//
+// Out of range values map to FFFF:FFFF
+//
+// History:
+// 03/17/93 cjp [curtisp]
+//
+//--------------------------------------------------------------------------;
+
+DWORD NEAR PASCAL IMixerMapId(
+ PMIXERDRV pmxdrv,
+ UINT uTotalNumDevs,
+ UINT uId
+)
+{
+ UINT u;
+
+#ifdef MIXER_MAPPER
+ //
+ // the mapper is always the last element of the MIXERDEV array.
+ //
+ if (uId == MIXER_MAPPER)
+ return (MAKELONG(0, MAXMIXERDRIVERS));
+#endif
+
+ if (uId >= uTotalNumDevs)
+ return ((DWORD)-1);
+
+#ifdef DEBUG_RETAIL
+ if (fIdReverse)
+ uId = uTotalNumDevs - 1 - uId;
+#endif
+
+ for (u = 0; u < MAXMIXERDRIVERS; u++)
+ {
+ if (pmxdrv[u].bNumDevs > (BYTE)uId)
+ return (MAKELONG(uId, u));
+
+ uId -= pmxdrv[u].bNumDevs;
+ }
+
+ return ((DWORD)-1);
+} // IMixerMapId()
+
+
+//--------------------------------------------------------------------------;
+//
+// DWORD IMixerMessageHandle
+//
+// Description:
+//
+//
+// Arguments:
+// HMIXER hmx:
+//
+// UINT uMsg:
+//
+// DWORD dwP1:
+//
+// DWORD dwP2:
+//
+// Return (DWORD):
+//
+// History:
+// 03/17/93 cjp [curtisp]
+//
+//--------------------------------------------------------------------------;
+
+DWORD NEAR PASCAL IMixerMessageHandle(
+ HMIXER hmx,
+ UINT uMsg,
+ DWORD dwP1,
+ DWORD dwP2
+)
+{
+ PMIXERDEV pmxd;
+ DWORD dwRc;
+
+ pmxd = (PMIXERDEV)hmx;
+
+ dwRc = ((*(pmxd->pmxdrv->drvMessage))
+ (pmxd->wDevice, uMsg, pmxd->dwDrvUser, dwP1, dwP2));
+
+ return dwRc;
+} // IMixerMessageHandle()
+
+
+//--------------------------------------------------------------------------;
+//
+// DWORD IMixerMessageId
+//
+// Description:
+//
+//
+// Arguments:
+// PMIXERDRV pmxdrv:
+//
+// UINT uTotalNumDevs:
+//
+// UINT uDeviceID:
+//
+// UINT uMsg:
+//
+// DWORD dwParam1:
+//
+// DWORD dwParam2:
+//
+// Return (DWORD):
+//
+// History:
+// 03/17/93 cjp [curtisp]
+//
+//--------------------------------------------------------------------------;
+
+DWORD NEAR PASCAL IMixerMessageId(
+ PMIXERDRV pmxdrv,
+ UINT uTotalNumDevs,
+ UINT uDeviceID,
+ UINT uMsg,
+ DWORD dwParam1,
+ DWORD dwParam2
+)
+{
+ DWORD dwMap;
+ DWORD dwRc;
+
+ dwMap = IMixerMapId(pmxdrv, uTotalNumDevs, uDeviceID);
+
+ if (dwMap == (DWORD)-1)
+ return (MMSYSERR_BADDEVICEID);
+
+ pmxdrv = (PMIXERDRV)&pmxdrv[HIWORD(dwMap)];
+ if (!pmxdrv->drvMessage)
+ return (MMSYSERR_NODRIVER);
+
+ dwRc = ((*(pmxdrv->drvMessage))
+ ((UINT)dwMap, uMsg, 0L, dwParam1, dwParam2));
+
+ return dwRc;
+
+} // IMixerMessageId()
+
+/******************************Public*Routine******************************\
+* mixerGetNumDevs
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT MIXAPI mixerGetNumDevs(
+ void
+)
+{
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+
+ return guTotalMixerDevs;
+}
+
+
+
+/******************************Public*Routine******************************\
+* mixerGetDevCaps
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerGetDevCaps(
+ UINT uMxId,
+ LPMIXERCAPS pmxcaps,
+ UINT cbmxcaps
+)
+{
+
+ MMRESULT mmr;
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+
+ if (0 == cbmxcaps)
+ return (MMSYSERR_NOERROR);
+
+ V_WPOINTER(pmxcaps, cbmxcaps, MMSYSERR_INVALPARAM);
+
+ if (uMxId >= MAXMIXERDRIVERS)
+ {
+ V_HANDLE((HMIXER)uMxId, TYPE_MIXER, MMSYSERR_INVALHANDLE);
+
+ mmr = (MMRESULT)IMixerMessageHandle((HMIXER)uMxId,
+ MXDM_GETDEVCAPS,
+ (DWORD)pmxcaps,
+ (DWORD)cbmxcaps);
+ }
+ else
+ {
+ if (uMxId >= guTotalMixerDevs)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetDevCaps: mixer device id is out of range (%u).", uMxId);
+ return (MMSYSERR_BADDEVICEID);
+ }
+
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ uMxId,
+ MXDM_GETDEVCAPS,
+ (DWORD)pmxcaps,
+ (DWORD)cbmxcaps);
+ }
+ return mmr;
+}
+
+
+
+/******************************Public*Routine******************************\
+* mixerGetID
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerGetID(
+ HMIXEROBJ hmxobj,
+ UINT FAR *puMxId,
+ DWORD fdwId
+)
+{
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ return IMixerGetID( hmxobj, puMxId, NULL, fdwId );
+}
+
+
+/*****************************Private*Routine******************************\
+* IMixerGetID
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT FNGLOBAL IMixerGetID(
+ HMIXEROBJ hmxobj,
+ UINT FAR *puMxId,
+ LPMIXERLINE pmxl,
+ DWORD fdwId
+)
+{
+ MMRESULT mmr;
+ MIXERLINE mxl;
+ UINT u;
+
+ V_DFLAGS(fdwId, MIXER_GETIDF_VALID, IMixerGetID, MMSYSERR_INVALFLAG);
+ V_WPOINTER(puMxId, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+
+ //
+ // set to '-1' which would be the mixer mapper (if there was one)
+ // this way we will definitely fail any calls made on this id if
+ // this function fails and the caller doesn't check his return value.
+ //
+ *puMxId = (UINT)-1;
+
+
+ //
+ //
+ //
+ switch (MIXER_OBJECTF_TYPEMASK & fdwId)
+ {
+ case MIXER_OBJECTF_MIXER:
+ case MIXER_OBJECTF_HMIXER:
+ if ((UINT)hmxobj > MAXMIXERDRIVERS)
+ {
+ V_HANDLE(hmxobj, TYPE_MIXER, MMSYSERR_INVALHANDLE);
+
+ *puMxId = ((PMIXERDEV)hmxobj)->uDeviceID;
+ return (MMSYSERR_NOERROR);
+ }
+
+ if ((UINT)hmxobj >= guTotalMixerDevs)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetID: mixer device id is out of range (%u).", hmxobj);
+ return (MMSYSERR_BADDEVICEID);
+ }
+
+ *puMxId = (UINT)hmxobj;
+ return (MMSYSERR_NOERROR);
+
+
+ case MIXER_OBJECTF_HWAVEOUT:
+ {
+ UINT uId;
+ DWORD dwId;
+
+ mmr = waveOutGetID((HWAVEOUT)hmxobj, &uId);
+ if (MMSYSERR_NOERROR != mmr)
+ {
+ return (MMSYSERR_INVALHANDLE);
+ }
+
+ if (WAVE_MAPPER == uId)
+ {
+ mmr = (MMRESULT)waveOutMessage((HWAVEOUT)hmxobj,
+ WODM_MAPPER_STATUS,
+ WAVEOUT_MAPPER_STATUS_DEVICE,
+ (DWORD)(LPVOID)&dwId);
+
+ if (MMSYSERR_NOERROR == mmr)
+ {
+ uId = (UINT)dwId;
+ }
+ }
+
+ hmxobj = (HMIXEROBJ)uId;
+ }
+
+ case MIXER_OBJECTF_WAVEOUT:
+ {
+ WAVEOUTCAPS woc;
+
+ mmr = waveOutGetDevCaps((UINT)hmxobj, &woc, sizeof(woc));
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_BADDEVICEID);
+
+ woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
+
+ mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
+ mxl.Target.dwDeviceID = (UINT)hmxobj;
+ mxl.Target.wMid = woc.wMid;
+ mxl.Target.wPid = woc.wPid;
+ mxl.Target.vDriverVersion = woc.vDriverVersion;
+ lstrcpy(mxl.Target.szPname, woc.szPname);
+ break;
+ }
+
+
+ case MIXER_OBJECTF_HWAVEIN:
+ {
+ UINT uId;
+ DWORD dwId;
+
+ mmr = waveInGetID((HWAVEIN)hmxobj, &uId);
+ if (MMSYSERR_NOERROR != mmr)
+ {
+ return (MMSYSERR_INVALHANDLE);
+ }
+
+ if (WAVE_MAPPER == uId)
+ {
+ mmr = (MMRESULT)waveInMessage((HWAVEIN)hmxobj,
+ WIDM_MAPPER_STATUS,
+ WAVEIN_MAPPER_STATUS_DEVICE,
+ (DWORD)(LPVOID)&dwId);
+
+ if (MMSYSERR_NOERROR == mmr)
+ {
+ uId = (UINT)dwId;
+ }
+ }
+
+ hmxobj = (HMIXEROBJ)uId;
+ }
+
+ case MIXER_OBJECTF_WAVEIN:
+ {
+ WAVEINCAPS wic;
+
+ mmr = waveInGetDevCaps((UINT)hmxobj, &wic, sizeof(wic));
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_BADDEVICEID);
+
+ wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
+
+ mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
+ mxl.Target.dwDeviceID = (UINT)hmxobj;
+ mxl.Target.wMid = wic.wMid;
+ mxl.Target.wPid = wic.wPid;
+ mxl.Target.vDriverVersion = wic.vDriverVersion;
+ lstrcpy(mxl.Target.szPname, wic.szPname);
+ break;
+ }
+
+
+ case MIXER_OBJECTF_HMIDIOUT:
+ mmr = midiOutGetID((HMIDIOUT)hmxobj, (UINT FAR *)&hmxobj);
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_INVALHANDLE);
+
+ case MIXER_OBJECTF_MIDIOUT:
+ {
+ MIDIOUTCAPS moc;
+
+ mmr = midiOutGetDevCaps((UINT)hmxobj, &moc, sizeof(moc));
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_BADDEVICEID);
+
+ moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
+
+ mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT;
+ mxl.Target.dwDeviceID = (UINT)hmxobj;
+ mxl.Target.wMid = moc.wMid;
+ mxl.Target.wPid = moc.wPid;
+ mxl.Target.vDriverVersion = moc.vDriverVersion;
+ lstrcpy(mxl.Target.szPname, moc.szPname);
+ break;
+ }
+
+
+ case MIXER_OBJECTF_HMIDIIN:
+ mmr = midiInGetID((HMIDIIN)hmxobj, (UINT FAR *)&hmxobj);
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_INVALHANDLE);
+
+ case MIXER_OBJECTF_MIDIIN:
+ {
+ MIDIINCAPS mic;
+
+ mmr = midiInGetDevCaps((UINT)hmxobj, &mic, sizeof(mic));
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_BADDEVICEID);
+
+ mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
+
+ mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIIN;
+ mxl.Target.dwDeviceID = (UINT)hmxobj;
+ mxl.Target.wMid = mic.wMid;
+ mxl.Target.wPid = mic.wPid;
+ mxl.Target.vDriverVersion = mic.vDriverVersion;
+ lstrcpy(mxl.Target.szPname, mic.szPname);
+ break;
+ }
+
+
+ case MIXER_OBJECTF_AUX:
+ {
+ AUXCAPS ac;
+
+ mmr = auxGetDevCaps((UINT)hmxobj, &ac, sizeof(ac));
+ if (MMSYSERR_NOERROR != mmr)
+ return (MMSYSERR_BADDEVICEID);
+
+ ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
+
+ mxl.Target.dwType = MIXERLINE_TARGETTYPE_AUX;
+ mxl.Target.dwDeviceID = (UINT)hmxobj;
+ mxl.Target.wMid = ac.wMid;
+ mxl.Target.wPid = ac.wPid;
+ mxl.Target.vDriverVersion = ac.vDriverVersion;
+ lstrcpy(mxl.Target.szPname, ac.szPname);
+ break;
+ }
+
+ default:
+ DebugErr1(DBF_ERROR, "mixerGetID: unknown mixer object flag (%.08lXh).",
+ MIXER_OBJECTF_TYPEMASK & fdwId);
+ return (MMSYSERR_INVALFLAG);
+ }
+
+
+ //
+ //
+ //
+ //
+ mxl.cbStruct = sizeof(mxl);
+ mxl.dwDestination = (DWORD)-1L;
+ mxl.dwSource = (DWORD)-1L;
+ mxl.dwLineID = (DWORD)-1L;
+ mxl.fdwLine = 0;
+ mxl.dwUser = 0;
+ mxl.dwComponentType = (DWORD)-1L;
+ mxl.cChannels = 0;
+ mxl.cConnections = 0;
+ mxl.cControls = 0;
+ mxl.szShortName[0] = '\0';
+ mxl.szName[0] = '\0';
+
+
+ for (u = 0; u < guTotalMixerDevs; u++)
+ {
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ u,
+ MXDM_GETLINEINFO,
+ (DWORD)(LPVOID)&mxl,
+ M_GLINFOF_TARGETTYPE);
+
+ if (MMSYSERR_NOERROR == mmr)
+ {
+ *puMxId = u;
+
+ if (NULL != pmxl)
+ {
+ DWORD cbStruct;
+
+ cbStruct = pmxl->cbStruct;
+
+ _fmemcpy(pmxl, &mxl, (UINT)cbStruct);
+
+ pmxl->cbStruct = cbStruct;
+ }
+
+ return (mmr);
+ }
+ }
+
+ return (MMSYSERR_NODRIVER);
+} // IMixerGetID()
+
+
+/******************************Public*Routine******************************\
+* mixerOpen
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerOpen(
+ LPHMIXER phmx,
+ UINT uMxId,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD fdwOpen
+)
+{
+ MMRESULT mmr;
+ DWORD dwMap;
+ PMIXERDRV pmxdrv;
+ PMIXERDEV pmxdev;
+ MIXEROPENDESC mxod;
+ DWORD dwDrvUser;
+ MIXERCAPS mxcaps;
+
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+
+ //
+ //
+ //
+ V_WPOINTER(phmx, sizeof(HMIXER), MMSYSERR_INVALPARAM);
+
+ *phmx = NULL;
+
+ //
+ // Don't allow callback functions - they're not useful and they
+ // cause headaches. Specifically for Windows NT the only way
+ // to cause an asynchronous callback to 16-bit land from a 32-bit DLL
+ // is to cause an interrupt but we don't want to require mixer stuff
+ // to be locked down to allow for this.
+ //
+
+ if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
+ {
+ DebugErr(DBF_ERROR, "mixerOpen: CALLBACK_FUNCTION is not supported");
+ return MMSYSERR_INVALFLAG;
+ }
+
+ V_DCALLBACK(dwCallback, HIWORD(fdwOpen & CALLBACK_TYPEMASK), MMSYSERR_INVALPARAM);
+ V_DFLAGS(fdwOpen, MIXER_OPENF_VALID, mixerOpen, MMSYSERR_INVALFLAG);
+
+ mmr = IMixerGetID((HMIXEROBJ)uMxId, &uMxId, NULL, (MIXER_OBJECTF_TYPEMASK & fdwOpen));
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+
+ //
+ //
+ //
+ //
+ dwMap = IMixerMapId(mixerdrv, guTotalMixerDevs, uMxId);
+ if ((DWORD)-1 == dwMap)
+ return (MMSYSERR_BADDEVICEID);
+
+ pmxdrv = &mixerdrv[HIWORD(dwMap)];
+
+#ifdef MIXER_MAPPER
+ //
+ // Default Mixer Mapper:
+ //
+ // If a mixer mapper is installed as a separate DLL then all mixer
+ // mapper messages are routed to it. If no mixer mapper is installed,
+ // simply loop through the mixer devices looking for a match.
+ //
+ if ((MIXER_MAPPER == uMxId) && (NULL == pmxdrv->drvMessage))
+ {
+ for (uMxId = 0; uMxId < guTotalMixerDevs; uMxId++)
+ {
+ // try to open it
+ if (MMSYSERR_NOERROR == mmr)
+ break;
+
+ }
+
+ return (mmr);
+ }
+#endif
+
+
+ //
+ // Get some memory for the dev structure
+ //
+ pmxdev = (PMIXERDEV)NewHandle(TYPE_MIXER, sizeof(MIXERDEV));
+ if (NULL == pmxdev)
+ {
+ return (MMSYSERR_NOMEM);
+ }
+
+ //
+ // initialize our open instance struct for the client
+ //
+ pmxdev->uHandleType = TYPE_MIXER;
+ pmxdev->pmxdrv = pmxdrv;
+ pmxdev->wDevice = LOWORD(dwMap);
+ pmxdev->uDeviceID = uMxId;
+
+ //
+ // save the client's callback info
+ //
+ pmxdev->dwCallback = dwCallback;
+ pmxdev->dwInstance = dwInstance;
+ pmxdev->fdwOpen = fdwOpen;
+
+
+ //
+ // this should probably be done when the driver is booted.. can change
+ // this later..
+ //
+ mmr = mixerGetDevCaps(uMxId, &mxcaps, sizeof(mxcaps));
+ if (MMSYSERR_NOERROR != mmr)
+ {
+ DPF((0, "!mixerOpen() failing because mixerGetDevCaps() failed!"));
+
+ FreeHandle((HMIXER)pmxdev);
+ return (mmr);
+ }
+
+ //
+ // cache some stuff for parameter validation
+ //
+ pmxdev->fdwSupport = mxcaps.fdwSupport;
+ pmxdev->cDestinations = mxcaps.cDestinations;
+
+
+ //
+ // If we get here, no one has the device currently open. Let's
+ // go open it, then.
+ //
+
+ //
+ // Load up our local MIXEROPENDESC struct
+ //
+
+ mxod.hmx = (HMIXER)pmxdev;
+ mxod.pReserved0 = (LPVOID)(fdwOpen & ~MIXER_OBJECTF_TYPEMASK);
+ mxod.dwCallback = dwCallback;
+ mxod.dwInstance = dwInstance;
+ mmr = (MMRESULT)((*(pmxdrv->drvMessage))(LOWORD(dwMap),
+ MXDM_OPEN,
+ (DWORD)(LPDWORD)&dwDrvUser,
+ (DWORD)(LPVOID)&mxod,
+ (DWORD)uMxId ));
+
+
+ if (MMSYSERR_NOERROR != mmr)
+ {
+ FreeHandle((HMIXER)pmxdev);
+ }
+ else
+ {
+ pmxdrv->bUsage++;
+ pmxdev->dwDrvUser = dwDrvUser;
+ *phmx = (HMIXER)pmxdev;
+
+ //
+ // Put this new device into the devlist chain.
+ //
+
+ MIXMGR_ENTER;
+
+ pmxdev->pmxdevNext = gpMixerDevHeader;
+ gpMixerDevHeader = pmxdev;
+
+ MIXMGR_LEAVE;
+ }
+ return mmr;
+}
+
+
+/******************************Public*Routine******************************\
+* mixerClose
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerClose(
+ HMIXER hmx
+)
+{
+ MMRESULT mmr;
+ PMIXERDEV pmxdev;
+ PMIXERDEV pmxdevT;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ V_HANDLE(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
+
+
+ //
+ // if last open instance, then close it
+ //
+ mmr = (MMRESULT)IMixerMessageHandle(hmx, MXDM_CLOSE, 0L, 0L);
+
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+
+ //
+ // remove the mixer handle from the linked list
+ //
+
+ MIXMGR_ENTER;
+
+ pmxdev = (PMIXERDEV)hmx;
+ if (pmxdev == gpMixerDevHeader)
+ {
+ gpMixerDevHeader = pmxdev->pmxdevNext;
+ }
+ else
+ {
+ for (pmxdevT = gpMixerDevHeader;
+ pmxdevT && (pmxdevT->pmxdevNext != pmxdev);
+ pmxdevT = pmxdevT->pmxdevNext)
+ ;
+
+ if (NULL == pmxdevT)
+ {
+ DebugErr1(DBF_ERROR, "mixerClose: invalid mixer handle (%.04Xh).", hmx);
+ return (MMSYSERR_INVALHANDLE);
+ }
+
+ pmxdevT->pmxdevNext = pmxdev->pmxdevNext;
+ }
+
+ MIXMGR_LEAVE;
+
+ //
+ // dec usage count
+ //
+ pmxdev->pmxdrv->bUsage--;
+
+
+ //
+ // we're done with the memory block. now free the memory and return.
+ //
+ FreeHandle(hmx);
+ return mmr;
+}
+
+
+/******************************Public*Routine******************************\
+* mixerMessage
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+DWORD MIXAPI mixerMessage(
+ HMIXER hmx,
+ UINT uMsg,
+ DWORD dwParam1,
+ DWORD dwParam2
+)
+{
+ DWORD dw;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ V_HANDLE(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
+
+ //
+ // don't allow any non-user range messages through this API
+ //
+ if (MXDM_USER > uMsg)
+ {
+ DebugErr1(DBF_ERROR, "mixerMessage: message must be in MXDM_USER range--what's this (%u)?", uMsg);
+ return (MMSYSERR_INVALPARAM);
+ }
+
+
+ dw = IMixerMessageHandle(hmx, uMsg, dwParam1, dwParam2);
+ return dw;
+}
+
+
+//--------------------------------------------------------------------------;
+//
+// BOOL IMixerIsValidComponentType
+//
+// Description:
+//
+//
+// Arguments:
+// DWORD dwComponentType:
+//
+// UINT uSrcDst:
+//
+// Return (BOOL):
+//
+// History:
+// 10/06/93 cjp [curtisp]
+//
+//--------------------------------------------------------------------------;
+
+BOOL FNLOCAL IMixerIsValidComponentType(
+ DWORD dwComponentType,
+ DWORD fdwLine
+)
+{
+
+ if (0L == (MIXERLINE_LINEF_SOURCE & fdwLine))
+ {
+ if (dwComponentType > MLCT_DST_LAST)
+ return (FALSE);
+
+ return (TRUE);
+ }
+ else
+ {
+ if (dwComponentType < MLCT_SRC_FIRST)
+ return (FALSE);
+
+ if (dwComponentType > MLCT_SRC_LAST)
+ return (FALSE);
+
+ return (TRUE);
+ }
+
+ return (FALSE);
+} // IMixerIsValidComponentType()
+
+
+
+/******************************Public*Routine******************************\
+* mixerGetLineInfo
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerGetLineInfo(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINE pmxl,
+ DWORD fdwInfo
+)
+{
+ DWORD fdwMxObjType;
+ MMRESULT mmr;
+ PMIXERDEV pmxdev;
+ UINT uMxId;
+ BOOL fSourceLine;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+
+ V_DFLAGS(fdwInfo, M_GLINFOF_VALID, mixerGetLineInfo, MMSYSERR_INVALFLAG);
+ V_WPOINTER(pmxl, sizeof(DWORD), MMSYSERR_INVALPARAM);
+ if (sizeof(MIXERLINE) > (UINT)pmxl->cbStruct)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: structure size too small or cbStruct not initialized (%lu).", pmxl->cbStruct);
+ return (MMSYSERR_INVALPARAM);
+ }
+ V_WPOINTER(pmxl, pmxl->cbStruct, MMSYSERR_INVALPARAM);
+
+
+ //
+ //
+ //
+ fSourceLine = FALSE;
+ switch (fdwInfo & M_GLINFOF_QUERYMASK)
+ {
+ case M_GLINFOF_DESTINATION:
+ pmxl->dwSource = (DWORD)-1L;
+ pmxl->dwLineID = (DWORD)-1L;
+ pmxl->dwComponentType = (DWORD)-1L;
+ break;
+
+ case M_GLINFOF_SOURCE:
+ fSourceLine = TRUE;
+ pmxl->dwLineID = (DWORD)-1L;
+ pmxl->dwComponentType = (DWORD)-1L;
+ break;
+
+ case M_GLINFOF_LINEID:
+ pmxl->dwSource = (DWORD)-1L;
+ pmxl->dwDestination = (DWORD)-1L;
+ pmxl->dwComponentType = (DWORD)-1L;
+ break;
+
+ case M_GLINFOF_COMPONENTTYPE:
+ pmxl->dwSource = (DWORD)-1L;
+ pmxl->dwDestination = (DWORD)-1L;
+ pmxl->dwLineID = (DWORD)-1L;
+
+ if (!IMixerIsValidComponentType(pmxl->dwComponentType, 0) &&
+ !IMixerIsValidComponentType(pmxl->dwComponentType, MIXERLINE_LINEF_SOURCE))
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid dwComponentType (%lu).", pmxl->dwComponentType);
+ return (MMSYSERR_INVALPARAM);
+ }
+ break;
+
+ case M_GLINFOF_TARGETTYPE:
+ pmxl->dwSource = (DWORD)-1L;
+ pmxl->dwDestination = (DWORD)-1L;
+ pmxl->dwLineID = (DWORD)-1L;
+ pmxl->dwComponentType = (DWORD)-1L;
+
+ if ((DWORD)MIXERLINE_TARGETTYPE_AUX < pmxl->Target.dwType)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid Target.dwType (%lu).", pmxl->Target.dwType);
+ return (MMSYSERR_INVALPARAM);
+ }
+ break;
+
+ default:
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid query flag (%.08lXh).",
+ fdwInfo & M_GLINFOF_QUERYMASK);
+ return (MMSYSERR_INVALFLAG);
+ }
+
+
+
+ //
+ //
+ //
+ fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwInfo);
+
+ mmr = IMixerGetID(hmxobj, &uMxId, pmxl, fdwMxObjType);
+ if (MMSYSERR_NOERROR != mmr)
+ {
+ DPF((0, "!IMixerGetLineInfo: IMixerGetID() failed!"));
+ return (mmr);
+ }
+
+ if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
+ (MIXER_OBJECTF_HMIXER == fdwMxObjType))
+ {
+ //
+ // if a mixer device id was passed, then null hmx so we use the
+ // correct message sender below
+ //
+ if ((UINT)hmxobj == uMxId)
+ hmxobj = NULL;
+ }
+ else
+ {
+ return (MMSYSERR_NOERROR);
+ }
+
+
+ //
+ // clear all fields before calling driver
+ //
+ if (NULL != hmxobj)
+ {
+ //
+ //
+ //
+ pmxdev = (PMIXERDEV)hmxobj;
+#if 0
+ if (pmxdev->cDestinations <= pmxl->dwDestination)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid destination index (%lu).", pmxl->dwDestination);
+ return (MMSYSERR_INVALPARAM);
+ }
+#endif
+
+ mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
+ MXDM_GETLINEINFO,
+ (DWORD)(LPVOID)pmxl,
+ fdwInfo);
+ }
+ else
+ {
+#pragma message("----IMixerGetLineInfo: dwDestination not validated for ID's!!")
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ uMxId,
+ MXDM_GETLINEINFO,
+ (DWORD)(LPVOID)pmxl,
+ fdwInfo);
+ }
+
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+#pragma message("----IMixerGetLineInfo: should validate mixer driver didn't hose us!")
+
+
+ //
+ // validate the driver's returned stuff...
+ //
+ //
+ if (sizeof(MIXERLINE) != (UINT)pmxl->cbStruct)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid cbStruct (%lu).", pmxl->cbStruct);
+ pmxl->cbStruct = sizeof(MIXERLINE);
+ }
+
+ if ((DWORD)-1L == pmxl->dwDestination)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwDestination member.");
+ }
+ if (fSourceLine)
+ {
+ if (0L == (MIXERLINE_LINEF_SOURCE & pmxl->fdwLine))
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to set MIXERLINE_LINEF_SOURCE.");
+ pmxl->fdwLine |= MIXERLINE_LINEF_SOURCE;
+ }
+
+ if ((DWORD)-1L == pmxl->dwSource)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwSource member.");
+ }
+ }
+ if ((DWORD)-1L == pmxl->dwLineID)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwLineID member.");
+ }
+ if (pmxl->fdwLine & ~0x80008001L)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver set reserved line flags (%.08lXh)!", pmxl->fdwLine);
+ pmxl->fdwLine &= 0x80008001L;
+ }
+ if (!IMixerIsValidComponentType(pmxl->dwComponentType, pmxl->fdwLine))
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid dwComponentType (%.08lXh).", pmxl->dwComponentType);
+ pmxl->dwComponentType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ }
+ if (0L == pmxl->cChannels)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned zero channels?!?");
+ pmxl->cChannels = 1;
+ }
+ if (fSourceLine)
+ {
+ if (0L != pmxl->cConnections)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned non-zero connections on source?!?");
+ pmxl->cConnections = 0;
+ }
+ }
+
+ pmxl->szShortName[SIZEOF(pmxl->szShortName) - 1] = '\0';
+ pmxl->szName[SIZEOF(pmxl->szName) - 1] = '\0';
+
+
+ //
+ // Does this really need to be done if TARGETTYPE was requested?
+ //
+
+
+ //
+ //
+ //
+ if ((DWORD)MIXERLINE_TARGETTYPE_UNDEFINED != pmxl->Target.dwType)
+ {
+ UINT u;
+
+ pmxl->Target.dwDeviceID = (DWORD)-1L;
+
+
+ //
+ // we have a wMid, wPid and szPname (supposedly) of type dwType
+ // so let's go find it...
+ //
+ switch (pmxl->Target.dwType)
+ {
+ case MIXERLINE_TARGETTYPE_WAVEOUT:
+ u = waveOutGetNumDevs();
+ while (u--)
+ {
+ WAVEOUTCAPS woc;
+
+ mmr = waveOutGetDevCaps(u, &woc, sizeof(woc));
+ if (MMSYSERR_NOERROR != mmr)
+ continue;
+
+ woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
+
+ if (woc.wMid != pmxl->Target.wMid)
+ continue;
+
+ if (woc.wPid != pmxl->Target.wPid)
+ continue;
+
+ if (woc.vDriverVersion != pmxl->Target.vDriverVersion)
+ continue;
+
+ if (lstrcmp(woc.szPname, pmxl->Target.szPname))
+ continue;
+
+ pmxl->Target.dwDeviceID = u;
+ break;
+ }
+ break;
+
+ case MIXERLINE_TARGETTYPE_WAVEIN:
+ u = waveInGetNumDevs();
+ while (u--)
+ {
+ WAVEINCAPS wic;
+
+ mmr = waveInGetDevCaps(u, &wic, sizeof(wic));
+ if (MMSYSERR_NOERROR != mmr)
+ continue;
+
+ wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
+
+ if (wic.wMid != pmxl->Target.wMid)
+ continue;
+
+ if (wic.wPid != pmxl->Target.wPid)
+ continue;
+
+ if (wic.vDriverVersion != pmxl->Target.vDriverVersion)
+ continue;
+
+ if (lstrcmp(wic.szPname, pmxl->Target.szPname))
+ continue;
+
+ pmxl->Target.dwDeviceID = u;
+ break;
+ }
+ break;
+
+ case MIXERLINE_TARGETTYPE_MIDIOUT:
+ u = midiOutGetNumDevs();
+ while (u--)
+ {
+ MIDIOUTCAPS moc;
+
+ mmr = midiOutGetDevCaps(u, &moc, sizeof(moc));
+ if (MMSYSERR_NOERROR != mmr)
+ continue;
+
+ moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
+
+ if (moc.wMid != pmxl->Target.wMid)
+ continue;
+
+ if (moc.wPid != pmxl->Target.wPid)
+ continue;
+
+ if (moc.vDriverVersion != pmxl->Target.vDriverVersion)
+ continue;
+
+ if (lstrcmp(moc.szPname, pmxl->Target.szPname))
+ continue;
+
+ pmxl->Target.dwDeviceID = u;
+ break;
+ }
+ break;
+
+ case MIXERLINE_TARGETTYPE_MIDIIN:
+ u = midiInGetNumDevs();
+ while (u--)
+ {
+ MIDIINCAPS mic;
+
+ mmr = midiInGetDevCaps(u, &mic, sizeof(mic));
+ if (MMSYSERR_NOERROR != mmr)
+ continue;
+
+ mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
+
+ if (mic.wMid != pmxl->Target.wMid)
+ continue;
+
+ if (mic.wPid != pmxl->Target.wPid)
+ continue;
+
+ if (mic.vDriverVersion != pmxl->Target.vDriverVersion)
+ continue;
+
+ if (lstrcmp(mic.szPname, pmxl->Target.szPname))
+ continue;
+
+ pmxl->Target.dwDeviceID = u;
+ break;
+ }
+ break;
+
+ case MIXERLINE_TARGETTYPE_AUX:
+ u = auxGetNumDevs();
+ while (u--)
+ {
+ AUXCAPS ac;
+
+ mmr = auxGetDevCaps(u, &ac, sizeof(ac));
+ if (MMSYSERR_NOERROR != mmr)
+ continue;
+
+ ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
+
+ if (ac.wMid != pmxl->Target.wMid)
+ continue;
+
+ if (ac.wPid != pmxl->Target.wPid)
+ continue;
+
+ if (ac.vDriverVersion != pmxl->Target.vDriverVersion)
+ continue;
+
+ if (lstrcmp(ac.szPname, pmxl->Target.szPname))
+ continue;
+
+ pmxl->Target.dwDeviceID = u;
+ break;
+ }
+ break;
+
+ default:
+ pmxl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
+ break;
+ }
+ }
+
+ return mmr;
+}
+
+
+/******************************Public*Routine******************************\
+* mixerGetLineControls
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerGetLineControls(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINECONTROLS pmxlc,
+ DWORD fdwControls
+)
+{
+ DWORD fdwMxObjType;
+ UINT uMxId;
+ MMRESULT mmr;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ V_DFLAGS(fdwControls, M_GLCONTROLSF_VALID, mixerGetLineControls, MMSYSERR_INVALFLAG);
+ V_WPOINTER(pmxlc, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ //
+ // the structure header for MIXERLINECONTROLS must be at least the
+ // minimum size
+ //
+ if (sizeof(MIXERLINECONTROLS) > (UINT)pmxlc->cbStruct)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbStruct not initialized (%lu).", pmxlc->cbStruct);
+ return (MMSYSERR_INVALPARAM);
+ }
+ V_WPOINTER(pmxlc, pmxlc->cbStruct, MMSYSERR_INVALPARAM);
+
+ if (sizeof(MIXERCONTROL) > (UINT)pmxlc->cbmxctrl)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbmxctrl not initialized (%lu).", pmxlc->cbmxctrl);
+ return (MMSYSERR_INVALPARAM);
+ }
+
+
+ //
+ //
+ //
+ switch (M_GLCONTROLSF_QUERYMASK & fdwControls)
+ {
+ case M_GLCONTROLSF_ALL:
+ if (0L == pmxlc->cControls)
+ {
+ DebugErr(DBF_ERROR, "mixerGetLineControls: cControls cannot be zero.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+
+ pmxlc->dwControlID = (DWORD)-1L;
+ break;
+
+ case M_GLCONTROLSF_ONEBYID:
+ pmxlc->dwLineID = (DWORD)-1L;
+
+ // -- fall through --
+
+ case M_GLCONTROLSF_ONEBYTYPE:
+ pmxlc->cControls = (DWORD)1;
+ break;
+
+ default:
+ DebugErr1(DBF_ERROR, "mixerGetLineControls: invalid query flags (%.08lXh).",
+ M_GLCONTROLSF_QUERYMASK & fdwControls);
+ return (MMSYSERR_INVALFLAG);
+ }
+
+ V_WPOINTER(pmxlc->pamxctrl, pmxlc->cControls * pmxlc->cbmxctrl, MMSYSERR_INVALPARAM);
+
+
+ //
+ //
+ //
+ fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwControls);
+
+ mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+ if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
+ (MIXER_OBJECTF_HMIXER == fdwMxObjType))
+ {
+ //
+ // if a mixer device id was passed, then null hmx so we use the
+ // correct message sender below
+ //
+ if ((UINT)hmxobj == uMxId)
+ hmxobj = NULL;
+ }
+ else
+ {
+ hmxobj = NULL;
+ fdwControls &= ~MIXER_OBJECTF_TYPEMASK;
+ fdwControls |= MIXER_OBJECTF_MIXER;
+ }
+
+
+
+ //
+ //
+ //
+ //
+ if (NULL != hmxobj)
+ {
+ mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
+ MXDM_GETLINECONTROLS,
+ (DWORD)pmxlc,
+ fdwControls);
+ }
+ else
+ {
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ uMxId,
+ MXDM_GETLINECONTROLS,
+ (DWORD)pmxlc,
+ fdwControls);
+ }
+
+ return mmr;
+}
+
+
+/******************************Public*Routine******************************\
+* mixerGetControlDetails
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerGetControlDetails(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+)
+{
+ DWORD fdwMxObjType;
+ MMRESULT mmr;
+ UINT uMxId;
+ UINT cDetails;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ V_DFLAGS(fdwDetails, M_GCDSF_VALID, mixerGetControlDetails, MMSYSERR_INVALFLAG);
+ V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ //
+ // the structure header for MIXERCONTROLDETAILS must be at least the
+ // minimum size
+ //
+ if (sizeof(MIXERCONTROLDETAILS) > (UINT)pmxcd->cbStruct)
+ {
+ DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
+ return (MMSYSERR_INVALPARAM);
+ }
+ V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
+
+
+ switch (M_GCDSF_QUERYMASK & fdwDetails)
+ {
+ case M_GCDSF_VALUE:
+ //
+ // if both cChannels and cMultipleItems are zero, it is a
+ // custom control
+ //
+ if ((0L == pmxcd->cChannels) && (0L == pmxcd->cMultipleItems))
+ {
+ if (0L == pmxcd->cbDetails)
+ {
+ DebugErr(DBF_ERROR, "mixerGetControlDetails: cbDetails cannot be zero.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+
+ }
+ else
+ {
+ if (0L == pmxcd->cChannels)
+ {
+ DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _VALUE cannot be zero.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+
+ if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
+ {
+ DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ //
+ //
+ //
+ cDetails = (UINT)pmxcd->cChannels;
+ if (0L != pmxcd->cMultipleItems)
+ {
+ cDetails *= (UINT)pmxcd->cMultipleItems;
+ }
+
+ V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+ }
+ break;
+
+ case M_GCDSF_LISTTEXT:
+ if (0L == pmxcd->cChannels)
+ {
+ DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _LISTTEXT cannot be zero.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ if (2L > pmxcd->cMultipleItems)
+ {
+ DebugErr(DBF_ERROR, "mixerGetControlDetails: cMultipleItems for _LISTTEXT must be 2 or greater.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_LISTTEXT))
+ {
+ DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ cDetails = (UINT)pmxcd->cChannels * (UINT)pmxcd->cMultipleItems;
+ V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+ break;
+
+ default:
+ DebugErr1(DBF_ERROR, "mixerGetControlDetails: invalid query flags (%.08lXh).",
+ M_GCDSF_QUERYMASK & fdwDetails);
+ return (MMSYSERR_INVALFLAG);
+ }
+
+
+
+ //
+ //
+ //
+ fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
+
+ mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+ if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
+ (MIXER_OBJECTF_HMIXER == fdwMxObjType))
+ {
+ //
+ // if a mixer device id was passed, then null hmx so we use the
+ // correct message sender below
+ //
+ if ((UINT)hmxobj == uMxId)
+ hmxobj = NULL;
+ }
+ else
+ {
+ hmxobj = NULL;
+ fdwDetails &= ~MIXER_OBJECTF_TYPEMASK;
+ fdwDetails |= MIXER_OBJECTF_MIXER;
+ }
+
+ //
+ //
+ //
+ //
+ if (NULL != hmxobj)
+ {
+ mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
+ MXDM_GETCONTROLDETAILS,
+ (DWORD)pmxcd,
+ fdwDetails);
+ }
+ else
+ {
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ uMxId,
+ MXDM_GETCONTROLDETAILS,
+ (DWORD)pmxcd,
+ fdwDetails);
+ }
+
+ return mmr;
+}
+
+
+/******************************Public*Routine******************************\
+* mixerSetControlDetails
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+MMRESULT MIXAPI mixerSetControlDetails(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+)
+{
+ DWORD fdwMxObjType;
+ MMRESULT mmr;
+ UINT uMxId;
+ UINT cDetails;
+
+ CHECK_AND_INIT_THUNKS(mix32Lib);
+ V_DFLAGS(fdwDetails, M_SCDF_VALID, mixerSetControlDetails, MMSYSERR_INVALFLAG);
+ V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ //
+ // the structure header for MIXERCONTROLDETAILS must be at least the
+ // minimum size
+ //
+ if (sizeof(MIXERCONTROLDETAILS) > (UINT)pmxcd->cbStruct)
+ {
+ DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
+ return (MMSYSERR_INVALPARAM);
+ }
+ V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
+
+
+
+ switch (M_SCDF_QUERYMASK & fdwDetails)
+ {
+ case M_SCDF_VALUE:
+ //
+ // cChannels is zero for custom controls
+ //
+ if (0L == pmxcd->cChannels)
+ {
+ if (0L == pmxcd->cbDetails)
+ {
+ DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+
+ //
+ //
+ //
+ if (0L != pmxcd->cMultipleItems)
+ {
+ DebugErr(DBF_ERROR, "mixerSetControlDetails: cMultipleItems must be zero for custom controls.");
+ return (MMSYSERR_INVALPARAM);
+ }
+ }
+ else
+ {
+ if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
+ {
+ DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ cDetails = (UINT)pmxcd->cChannels;
+
+ //
+ //
+ //
+ if (0L != pmxcd->cMultipleItems)
+ {
+ cDetails *= (UINT)(pmxcd->cMultipleItems);
+ }
+
+ V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+ }
+ break;
+
+ case M_SCDF_CUSTOM:
+ if (0L == pmxcd->cbDetails)
+ {
+ DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero for custom controls.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ if (0L != pmxcd->cChannels)
+ {
+ DebugErr(DBF_ERROR, "mixerSetControlDetails: cChannels must be zero for custom controls.");
+ return (MMSYSERR_INVALPARAM);
+ }
+
+ V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
+
+ //
+ //
+ //
+ if ((NULL != pmxcd->hwndOwner) && !IsWindow(pmxcd->hwndOwner))
+ {
+ DebugErr1(DBF_ERROR, "mixerSetControlDetails: hwndOwner must be a valid window handle (%.04Xh).", pmxcd->hwndOwner);
+ return (MMSYSERR_INVALHANDLE);
+ }
+ break;
+
+ default:
+ DebugErr1(DBF_ERROR, "mixerSetControlDetails: invalid query flags (%.08lXh).",
+ M_SCDF_QUERYMASK & fdwDetails);
+ return (MMSYSERR_INVALFLAG);
+ }
+
+
+ //
+ //
+ //
+ fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
+
+ mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
+ if (MMSYSERR_NOERROR != mmr)
+ return (mmr);
+
+ if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
+ (MIXER_OBJECTF_HMIXER == fdwMxObjType))
+ {
+ //
+ // if a mixer device id was passed, then null hmx so we use the
+ // correct message sender below
+ //
+ if ((UINT)hmxobj == uMxId)
+ hmxobj = NULL;
+ }
+ else
+ {
+ fdwDetails &= ~MIXER_OBJECTF_TYPEMASK;
+ fdwDetails |= MIXER_OBJECTF_MIXER;
+ hmxobj = NULL;
+ }
+
+ //
+ //
+ //
+ //
+ if (NULL != hmxobj)
+ {
+ mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
+ MXDM_SETCONTROLDETAILS,
+ (DWORD)pmxcd,
+ fdwDetails);
+ }
+ else
+ {
+ mmr = (MMRESULT)IMixerMessageId(mixerdrv,
+ guTotalMixerDevs,
+ uMxId,
+ MXDM_SETCONTROLDETAILS,
+ (DWORD)pmxcd,
+ fdwDetails);
+ }
+
+ return mmr;
+}
+
+/*****************************Private*Routine******************************\
+* InitMixerThunks
+*
+* Initializes the thunking system.
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+BOOL FAR PASCAL
+InitMixerThunks(
+ void
+ )
+{
+
+ /*
+ ** For WOW we have a fake device driver (that actually lives inside
+ ** this library). When an applications makes an api call to this
+ ** library we check to see is the WOW thunks are loaded. If they are
+ ** not loaded "InitWOWThunks" is called. This function loads the 32
+ ** bit library and determines the total number of mixer devices
+ ** present in the system. It then sets mixerdrv[0].bUsage
+ ** and guTotalMixerDevs to this value. This appears to the 16 bit code
+ ** that we have one 16 bit device driver that supports all the
+ ** 32 bit devices !!. The entry point to this fake driver is
+ ** mxdMessage, which just passes the message through to the 32 bit
+ ** side.
+ */
+
+ mixerdrv[0].hDriver = NULL;
+ mixerdrv[0].bNumDevs = (BYTE)0;
+ mixerdrv[0].bUsage = 0;
+ mixerdrv[0].drvMessage = mxdMessage;
+ guTotalMixerDevs = 0;
+
+
+ /*
+ ** First try winmm.dll
+ */
+ mix32Lib = LoadLibraryEx32W( "winmm.dll", NULL, 0L );
+ if ( mix32Lib ) {
+ mix32Message = (DRIVERMSGPROC)GetProcAddress32W( mix32Lib,
+ "mxd32Message" );
+ if ( mix32Message ) {
+
+ mxdMessage( 0, MXDM_INIT, 0L, 0L, 0L );
+ guTotalMixerDevs = (UINT)mxdMessage( 0, MXDM_GETNUMDEVS,
+ 0L, 0L, 0L );
+
+ mixerdrv[0].bNumDevs = (BYTE)guTotalMixerDevs;
+ return TRUE;
+ }
+ }
+
+ /*
+ ** Then try msmix32.dll
+ */
+ mix32Lib = LoadLibraryEx32W( "msmix32.dll", NULL, 0L );
+ if ( mix32Lib ) {
+
+ mix32Message = (DRIVERMSGPROC)GetProcAddress32W( mix32Lib,
+ "mxd32Message" );
+ if ( mix32Message ) {
+
+ mxdMessage( 0, MXDM_INIT, 0L, 0L, 0L );
+ guTotalMixerDevs = (UINT)mxdMessage( 0, MXDM_GETNUMDEVS,
+ 0L, 0L, 0L );
+
+ mixerdrv[0].bNumDevs = (BYTE)guTotalMixerDevs;
+ return TRUE;
+ }
+ }
+
+ /*
+ ** Give up !!
+ */
+ return FALSE;
+
+}
+
+
+/*****************************Private*Routine******************************\
+* mxdMessage
+*
+* Entry point for the fake WOW device driver.
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+DWORD CALLBACK
+mxdMessage(
+ UINT uId,
+ UINT uMsg,
+ DWORD dwInstance,
+ DWORD dwParam1,
+ DWORD dwParam2
+ )
+{
+ return mmCallProc32( (DWORD)uId, (DWORD)uMsg, dwInstance,
+ dwParam1, dwParam2, mix32Message, 0L );
+}
diff --git a/private/mvdm/wow16/mmsystem/mixmgri.h b/private/mvdm/wow16/mmsystem/mixmgri.h
new file mode 100644
index 000000000..ed840b87a
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mixmgri.h
@@ -0,0 +1,368 @@
+//==========================================================================;
+//
+// mixmgri.h
+//
+// Copyright (C) 1992-1993 Microsoft Corporation. All Rights Reserved.
+//
+// Description:
+// This header file contains INTERNAL Mixer Manager defines and stuff.
+//
+// History:
+// 6/27/93 cjp [curtisp]
+//
+//==========================================================================;
+
+#ifndef _INC_MIXMGRI
+#define _INC_MIXMGRI // #defined if file has been included
+
+#ifndef RC_INVOKED
+#pragma pack(1) // assume byte packing throughout
+#endif
+
+#ifndef EXTERN_C
+#ifdef __cplusplus
+ #define EXTERN_C extern "C"
+#else
+ #define EXTERN_C extern
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" // assume C declarations for C++
+{
+#endif
+
+#ifdef DEBUG
+ #define RDEBUG
+#endif
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+
+//
+//
+//
+//
+#ifndef FIELD_OFFSET
+ #define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
+#endif
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+//
+// WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
+//
+// if you change the order of the following defines, you must also fix
+// gapszMxMgrFunctions[] in idrvinit.c!
+//
+// WARNING DANGER WARNING DANGER WARNING DANGER WARNING DANGER WARNING
+//
+
+enum {
+ MXMGRTHUNK_GETNUMDEVS = 0,
+#ifdef WIN32
+ MXMGRTHUNK_GETDEVCAPSA ,
+ MXMGRTHUNK_GETDEVCAPS ,
+#else
+ MXMGRTHUNK_GETDEVCAPS ,
+#endif // WIN32
+ MXMGRTHUNK_GETID ,
+ MXMGRTHUNK_OPEN ,
+ MXMGRTHUNK_CLOSE ,
+ MXMGRTHUNK_MESSAGE ,
+#ifdef WIN32
+ MXMGRTHUNK_GETLINEINFOA ,
+ MXMGRTHUNK_GETLINEINFO ,
+ MXMGRTHUNK_GETLINECONTROLSA ,
+ MXMGRTHUNK_GETLINECONTROLS ,
+ MXMGRTHUNK_GETCONTROLDETAILSA ,
+ MXMGRTHUNK_GETCONTROLDETAILS ,
+#else
+ MXMGRTHUNK_GETLINEINFO ,
+ MXMGRTHUNK_GETLINECONTROLS ,
+ MXMGRTHUNK_GETCONTROLDETAILS ,
+#endif // WIN32
+ MXMGRTHUNK_SETCONTROLDETAILS ,
+ MXMGRTHUNK_MAX_FUNCTIONS
+};
+
+
+extern FARPROC gafnMxMgrFunctions[];
+
+
+//
+//
+//
+//
+UINT FNGLOBAL IMixerGetNumDevs
+(
+ void
+);
+
+MMRESULT FNGLOBAL IMixerGetDevCaps
+(
+ UINT uMxId,
+ LPMIXERCAPS pmxcaps,
+ UINT cbmxcaps
+);
+
+#ifdef WIN32
+MMRESULT FNGLOBAL IMixerGetDevCapsA
+(
+ UINT uMxId,
+ LPMIXERCAPSA pmxcaps,
+ UINT cbmxcaps
+);
+#endif // WIN32
+
+MMRESULT FNGLOBAL IMixerGetID
+(
+ HMIXEROBJ hmxobj,
+ UINT FAR *puMxId,
+ LPMIXERLINE pmxl,
+ DWORD fdwId
+);
+
+MMRESULT FNGLOBAL IMixerOpen
+(
+ LPHMIXER phmx,
+ UINT uMxId,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD fdwOpen
+);
+
+MMRESULT FNGLOBAL IMixerClose
+(
+ HMIXER hmx
+);
+
+DWORD FNGLOBAL IMixerMessage
+(
+ HMIXER hmx,
+ UINT uMsg,
+ DWORD dwParam1,
+ DWORD dwParam2
+);
+
+MMRESULT FNGLOBAL IMixerGetLineInfo
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINE pmxl,
+ DWORD fdwInfo
+);
+
+MMRESULT FNGLOBAL IMixerGetLineControls
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINECONTROLS pmxlc,
+ DWORD fdwControls
+);
+
+MMRESULT FNGLOBAL IMixerGetControlDetails
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+);
+
+#ifdef WIN32
+MMRESULT FNGLOBAL IMixerGetLineInfoA
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINEA pmxl,
+ DWORD fdwInfo
+);
+
+MMRESULT FNGLOBAL IMixerGetLineControlsA
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINECONTROLSA pmxlc,
+ DWORD fdwControls
+);
+
+MMRESULT FNGLOBAL IMixerGetControlDetailsA
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+);
+#endif // WIN32
+
+MMRESULT FNGLOBAL IMixerSetControlDetails
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+);
+
+
+
+//
+//
+//
+//
+//
+BOOL FNGLOBAL IMixerUnloadDrivers
+(
+ HDRVR hdrvr
+);
+
+BOOL FNGLOBAL IMixerLoadDrivers
+(
+ HDRVR hdrvr
+);
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// -= Handles =-
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// No multi-thread synchronization for 16-bit
+//
+
+#define ENTER_MM_HANDLE(x) TRUE
+#define LEAVE_MM_HANDLE(x)
+
+#define MIXMGR_ENTER
+#define MIXMGR_LEAVE
+
+
+//
+// typedef for mxdMessage
+//
+typedef DWORD (CALLBACK *DRIVERMSGPROC)
+(
+ UINT uId,
+ UINT uMsg,
+ DWORD dwInstance,
+ DWORD dwParam1,
+ DWORD dwParam2
+);
+
+
+EXTERN_C DWORD FNWCALLBACK mxdMessageHack
+(
+ UINT uDevId,
+ UINT uMsg,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+);
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// -= Parameter Validation =-
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+//
+// No error logging for Win32
+//
+
+#ifdef WIN32
+#define LogParamError(a, b, c)
+#endif // WIN32
+//
+//
+//
+BOOL FNGLOBAL ValidateReadPointer(const void FAR* p, DWORD len);
+BOOL FNGLOBAL ValidateWritePointer(const void FAR* p, DWORD len);
+BOOL FNGLOBAL ValidateDriverCallback(DWORD dwCallback, UINT uFlags);
+BOOL FNGLOBAL ValidateCallback(FARPROC lpfnCallback);
+BOOL FNGLOBAL ValidateString(LPCSTR lsz, UINT cbMaxLen);
+
+//
+// unless we decide differently, ALWAYS do parameter validation--even
+// in retail. this is the 'safest' thing we can do. note that we still
+// LOG parameter errors in retail (see prmvalXX).
+//
+#if 1
+
+#define V_HANDLE(h, t, r) { if (!ValidateHandle(h, t)) return (r); }
+#define V_RPOINTER(p, l, r) { if (!ValidateReadPointer((p), (l))) return (r); }
+#define V_WPOINTER(p, l, r) { if (!ValidateWritePointer((p), (l))) return (r); }
+#define V_DCALLBACK(d, w, r) { if (!ValidateDriverCallback((d), (w))) return (r); }
+#define V_CALLBACK(f, r) { if (!ValidateCallback(f)) return (r); }
+#define V_STRING(s, l, r) { if (!ValidateString(s,l)) return (r); }
+#define V_DFLAGS(t, b, f, r) { if ((t) & ~(b)) {LogParamError(ERR_BAD_DFLAGS, (FARPROC)(f), (LPVOID)(DWORD)(t)); return (r); }}
+#define V_FLAGS(t, b, f, r) { if ((t) & ~(b)) {LogParamError(ERR_BAD_FLAGS, (FARPROC)(f), (LPVOID)(DWORD)(t)); return (r); }}
+
+#else
+
+#define V_HANDLE(h, t, r) { if (!(h)) return (r); }
+#define V_RPOINTER(p, l, r) { if (!(p)) return (r); }
+#define V_WPOINTER(p, l, r) { if (!(p)) return (r); }
+#define V_DCALLBACK(d, w, r) 0
+#define V_CALLBACK(f, r) { if (!(f)) return (r); }
+#define V_STRING(s, l, r) { if (!(s)) return (r); }
+#define V_DFLAGS(t, b, f, r) { if ((t) & ~(b)) return (r); }
+#define V_FLAGS(t, b, f, r) { if ((t) & ~(b)) return (r); }
+
+#endif
+
+
+//
+// the DV_xxxx macros are for INTERNAL DEBUG builds--aid to debugging.
+// we do 'loose' parameter validation in retail and retail debug builds.
+//
+#ifdef DEBUG
+
+#define DV_HANDLE(h, t, r) V_HANDLE(h, t, r)
+#define DV_RPOINTER(p, l, r) V_RPOINTER(p, l, r)
+#define DV_WPOINTER(p, l, r) V_WPOINTER(p, l, r)
+#define DV_DCALLBACK(d, w, r) V_DCALLBACK(d, w, r)
+#define DV_CALLBACK(f, r) V_CALLBACK(f, r)
+#define DV_STRING(s, l, r) V_STRING(s, l, r)
+#define DV_DFLAGS(t, b, f, r) V_DFLAGS(t, b, f, r)
+#define DV_FLAGS(t, b, f, r) V_FLAGS(t, b, f, r)
+
+#else
+
+#define DV_HANDLE(h, t, r) { if (!(h)) return (r); }
+#define DV_RPOINTER(p, l, r) { if (!(p)) return (r); }
+#define DV_WPOINTER(p, l, r) { if (!(p)) return (r); }
+#define DV_DCALLBACK(d, w, r) 0
+#define DV_CALLBACK(f, r) { if (!(f)) return (r); }
+#define DV_STRING(s, l, r) { if (!(s)) return (r); }
+#define DV_DFLAGS(t, b, f, r) { if ((t) & ~(b)) return (r); }
+#define DV_FLAGS(t, b, f, r) { if ((t) & ~(b)) return (r); }
+
+#endif
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifndef RC_INVOKED
+#pragma pack() // revert to default packing
+#endif
+
+#ifdef __cplusplus
+} // end of extern "C" {
+#endif
+
+#endif // _INC_MIXMGRI
diff --git a/private/mvdm/wow16/mmsystem/mmio.c b/private/mvdm/wow16/mmsystem/mmio.c
new file mode 100644
index 000000000..a71e7f4f6
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmio.c
@@ -0,0 +1,1961 @@
+/* mmio.c
+ *
+ * Basic MMIO functions.
+ *
+ * Implementation notes:
+ *
+ * The "current disk offset" is the disk offset (i.e. the location
+ * in the disk file) that the next MMIOM_READ or MMIOM_WRITE will
+ * read from or write to. The I/O procedure maintains the
+ * <lDiskOffset> field of the file's MMIO structure so that
+ * <lDiskOffset> is equal to the current disk offset.
+ *
+ * The "current buffered offset" is the disk offset that the next
+ * mmioRead() or mmioWrite() call would read from or write to.
+ * The current buffered offset is defined as
+ *
+ * <lBufOffset> + (<pchNext> - <pchBuffer>)
+ *
+ * since <lBufOffset> is the disk offset of the start of the buffer
+ * and <pchNext> corresponds to the current buffered offset.
+ *
+ * If the file is unbuffered, then <pchBuffer>, <pchNext>,
+ * <pchEndRead> and <pchEndWrite> will always be NULL, and
+ * <lBufOffset> will always be considered the "current buffered
+ * offset", i.e. mmioRead() and mmioWrite() will read/write
+ * at this offset.
+ *
+ *
+ * Except right at the beginning of mmioOpen(), the MMIO_ALLOCBUF
+ * flag is set if and only if the pchBuffer field points to a block
+ * of global memory that MMIO has allocated.
+ */
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmioi.h"
+#include "mmsysi.h"
+
+/* The I/O procedure map is a linked list of IOProcMPEntry structures.
+ * The head of the list, <gIOProcMapHead> is a pointer node to the last
+ * entry registered. The first few elements of the list are the predefined
+ * global IO procedures below -- these all have <hTask> equal to NULL so
+ * that no task can unregister them.
+ */
+static LRESULT CALLBACK mmioDOSIOProc(LPSTR, UINT, LPARAM, LPARAM);
+static LRESULT CALLBACK mmioMEMIOProc(LPSTR, UINT, LPARAM, LPARAM);
+
+static IOProcMapEntry gIOProcMaps[] = {
+ FOURCC_DOS, mmioDOSIOProc, NULL, STATICIOPROC, &gIOProcMaps[1],
+ FOURCC_MEM, mmioMEMIOProc, NULL, STATICIOPROC, NULL,
+};
+IOProcMapEntry NEAR * gIOProcMapHead = gIOProcMaps;
+
+/* private prototypes */
+static LONG NEAR PASCAL mmioDiskIO(PMMIO pmmio, UINT wMsg, HPSTR pch, LONG cch);
+static UINT NEAR PASCAL mmioExpandMemFile(PMMIO pmmio, LONG lExpand);
+
+/* @doc INTERNAL
+
+@func LPMMIOPROC | FindIOProc | This function locates previously installed
+ IO procedure.
+*/
+static LPMMIOPROC PASCAL NEAR
+FindIOProc(FOURCC fccIOProc, HTASK htask)
+{
+ IOProcMapEntry *pEnt; // an entry in linked list
+
+ /* walk through the linked list, first looking for an entry with
+ * identifier <fccIOProc> that was added by the current task, then
+ * looking for global entries.
+ */
+
+ for (pEnt = gIOProcMapHead; pEnt; pEnt = pEnt->pNext)
+ if ((pEnt->fccIOProc == fccIOProc) && (pEnt->hTask == htask))
+ return pEnt->pIOProc;
+
+ for (pEnt = gIOProcMapHead; pEnt; pEnt = pEnt->pNext)
+ if (!pEnt->hTask && (pEnt->fccIOProc == fccIOProc))
+ return pEnt->pIOProc;
+
+ return NULL;
+}
+
+/* @doc INTERNAL
+
+@func LPMMIOPROC | RemoveIOProc | This function removes previously installed
+ IO procedure.
+*/
+static LPMMIOPROC PASCAL NEAR
+RemoveIOProc(FOURCC fccIOProc, HTASK htask)
+{
+ IOProcMapEntry *pEnt; // an entry in linked list
+ IOProcMapEntry *pEntPrev; // the entry before <pEnt>
+
+ /* walk through the linked list, looking for an entry with
+ * identifier <fccIOProc> that was added by the current task
+ */
+ for (pEntPrev = NULL, pEnt = gIOProcMapHead; pEnt; pEntPrev = pEnt, pEnt = pEnt->pNext)
+ if ((pEnt->fccIOProc == fccIOProc) && (pEnt->hTask == htask)) {
+ LPMMIOPROC pIOProc;
+
+ if (pEnt->wFlags & STATICIOPROC)
+ return NULL;
+ pIOProc = pEnt->pIOProc;
+ if (pEntPrev)
+ pEntPrev->pNext = pEnt->pNext;
+ else
+ gIOProcMapHead = pEnt->pNext;
+ FreeHandle((HMMIO) pEnt);
+ return pIOProc;
+ }
+ return NULL;
+}
+
+/* @doc INTERNAL
+
+@func void | SetIOProc | This function sets the physical IO procedure
+ based on either the file name or the parameters within the
+ <p lpmmioinfo> structure passed.
+
+@parm LPCSTR | szFilename | Specifies a far pointer to a string
+containing the filename of the file to open. If no I/O procedure is
+
+@parm LPMMIOINFO | lpmmioinfo | Specifies a far pointer to an
+ <t MMIOINFO> structure containing extra parameters used by
+ <f SetIOProc> in determining the IO procedure to use. The
+ <e MMIOINFO.pIOProc> element is set to the procedure found.
+
+@rdesc Nothing.
+*/
+
+static void NEAR PASCAL
+SetIOProc(LPCSTR szFileName, LPMMIOINFO lpmmio)
+{
+ /* If the IOProc is not given, see if the file name implies that
+ * <szFileName> is either a RIFF compound file or some kind of
+ * other registered storage system -- look for the last CFSEPCHAR in
+ * the name, e.g. '+' in "foo.bnd+bar.hlp+blorg.dib", and figure
+ * that the IOProc ID is the extension of the compound file name,
+ * e.g. the extension of "foo.bnd+bar.hlp", i.e. 'HLP '.
+ *
+ * Alternatively, if <szFileName> is NULL, then assume that
+ * <lpmmio->adwInfo[0]> is a DOS file handle.
+ */
+ if (lpmmio->pIOProc == NULL)
+ {
+ if (lpmmio->fccIOProc == NULL)
+ {
+ if (szFileName != NULL)
+ {
+ LPSTR pch;
+
+ /* see if <szFileName> contains CFSEPCHAR */
+ if ((pch = fstrrchr(szFileName, CFSEPCHAR)) != NULL)
+ {
+ /* find the extension that precedes CFSEPCHAR,
+ * e.g. "hlp" in "foo.bnd+bar.hlp+blorg.dib"
+ */
+ while ((pch > szFileName) && (*pch != '.') && (*pch != ':') && (*pch != '\\'))
+ pch--;
+ if (*pch == '.')
+ {
+ char aszFour[sizeof(FOURCC)+1];
+ int i;
+
+ for (i = 0, pch++; i < sizeof(FOURCC); i++)
+ if (*pch == CFSEPCHAR)
+ aszFour[i] = (char)0;
+ else
+ aszFour[i] = *pch++;
+ aszFour[sizeof(FOURCC)] = (char)0;
+ lpmmio->fccIOProc = mmioStringToFOURCC(aszFour, MMIO_TOUPPER);
+ }
+ }
+ }
+ /* if the caller didn't specify an IOProc, and the code above
+ * didn't determine an IOProc ID, then the default is the DOS
+ * IOProc.
+ */
+ if (lpmmio->fccIOProc == NULL)
+ lpmmio->fccIOProc = FOURCC_DOS;
+ }
+
+ /* unless an IOProc address is specified explicitly, look up the
+ * IOProc in the global IOProc ID-to-address table -- the default
+ * is 'DOS' since we'll assume that custom storage system I/O
+ * procedures would have been installed
+ */
+ lpmmio->pIOProc = FindIOProc(lpmmio->fccIOProc, lpmmio->htask ? lpmmio->htask : GetCurrentTask());
+
+ if (lpmmio->pIOProc == NULL)
+ lpmmio->pIOProc = mmioDOSIOProc;
+ }
+}
+
+/* @doc EXTERNAL
+
+@api UINT | mmioRename | This function renames the specified file.
+
+@parm LPCSTR | szFilename | Specifies a far pointer to a string
+containing the filename of the file to rename.
+
+@parm LPCSTR | szNewFileName | Specifies a far pointer to a string
+containing the new filename.
+
+@parm LPMMIOINFO | lpmmioinfo | Specifies a far pointer to an
+ <t MMIOINFO> structure containing extra parameters used by
+ <f mmioRename>.
+
+ If <p lpmmioinfo> is not NULL, all unused fields of the
+ <t MMIOINFO> structure it references must be set to zero, including the
+ reserved fields.
+
+@parm DWORD | dwRenameFlags | Specifies option flags for the rename
+ operation. This should be set to zero.
+
+@rdesc The return value is zero if the file was renamed. Otherwise, the
+return value is an error code returned from <f mmioRename> or from the I/O
+procedure.
+*/
+UINT WINAPI
+mmioRename(LPCSTR szFileName, LPCSTR szNewFileName, LPMMIOINFO lpmmioinfo, DWORD dwRenameFlags)
+{
+ PMMIO pmmio;
+ UINT uReturn;
+
+ V_FLAGS(dwRenameFlags, 0, mmioRename, MMSYSERR_INVALFLAG);
+ V_RPOINTER0(lpmmioinfo, sizeof(MMIOINFO), MMSYSERR_INVALPARAM);
+
+ if ((pmmio = PH(NewHandle(TYPE_MMIO, sizeof(MMIOINFO)))) == NULL)
+ return MMIOERR_OUTOFMEMORY;
+
+ if (lpmmioinfo) {
+ V_CALLBACK0((FARPROC)lpmmioinfo->pIOProc, MMSYSERR_INVALPARAM);
+ *pmmio = *lpmmioinfo;
+ }
+
+ SetIOProc(szFileName, pmmio);
+ uReturn = (UINT)(DWORD) (pmmio->pIOProc((LPSTR) pmmio, MMIOM_RENAME, (LPARAM) szFileName, (LPARAM) szNewFileName));
+ FreeHandle((HLOCAL)pmmio);
+ return uReturn;
+}
+
+/* @doc EXTERNAL
+
+@api HMMIO | mmioOpen | This function opens a file for unbuffered
+ or buffered I/O. The file can be a DOS file, a memory file, or an
+ element of a custom storage system.
+
+@parm LPSTR | szFilename | Specifies a far pointer to a string
+containing the filename of the file to open. If no I/O procedure is
+specified to open the file, then the filename determines how the file
+is opened, as follows:
+
+ -- If the filename does not contain "+", then it is assumed
+ to be the name of a DOS file.
+
+ -- If the filename is of the form "foo.ext+bar", then the
+ extension "EXT " is assumed to identify an installed I/O procedure
+ which is called to perform I/O on the file (see <f mmioInstallIOProc>).
+
+ -- If the filename is NULL and no I/O procedure is given, then
+ <e MMIOINFO.adwInfo[0]> is assumed to be the DOS file handle
+ of a currently open file.
+
+ The filename should not be longer than 128 bytes, including the
+ terminating NULL.
+
+ When opening a memory file, set <p szFilename> to NULL.
+
+@parm LPMMIOINFO | lpmmioinfo | Specifies a far pointer to an
+ <t MMIOINFO> structure containing extra parameters used by
+ <f mmioOpen>. Unless you are opening a memory file, specifying the
+ size of a buffer for buffered I/O, or specifying an uninstalled I/O
+ procedure to open a file, this parameter should be NULL.
+
+ If <p lpmmioinfo> is not NULL, all unused fields of the
+ <t MMIOINFO> structure it references must be set to zero, including the
+ reserved fields.
+
+@parm DWORD | dwOpenFlags | Specifies option flags for the open
+ operation. The MMIO_READ, MMIO_WRITE, and MMIO_READWRITE flags are
+ mutually exclusive--only one should be specified. The MMIO_COMPAT,
+ MMIO_EXCLUSIVE, MMIO_DENYWRITE, MMIO_DENYREAD, and MMIO_DENYNONE flags
+ are DOS file-sharing flags, and can only be used after the DOS
+ command SHARE has been executed.
+
+ @flag MMIO_READ | Opens the file for reading only. This is the
+ default, if MMIO_WRITE and MMIO_READWRITE are not specified.
+
+ @flag MMIO_WRITE | Opens the file for writing. You should not
+ read from a file opened in this mode.
+
+ @flag MMIO_READWRITE | Opens the file for both reading and writing.
+
+ @flag MMIO_CREATE | Creates a new file.
+ If the file already exists, it is truncated to zero length.
+ For memory files, MMIO_CREATE indicates the end of the file
+ is initially at the start of the buffer.
+
+ @flag MMIO_DELETE | Deletes a file. If this flag is specified,
+ <p szFilename> should not be NULL. The return
+ value will be TRUE (cast to HMMIO) if the file was deleted
+ successfully, FALSE otherwise. Do not call <f mmioClose>
+ for a file that has been deleted. If this flag is specified,
+ all other file opening flags are ignored.
+
+ @flag MMIO_PARSE | Creates a fully qualified filename from the path
+ specified in <p szFileName>. The fully qualified filename is
+ placed back into <p szFileName>. The return value
+ will be TRUE (cast to HMMIO) if the qualification was
+ successful, FALSE otherwise. The file is not opened, and the function
+ does not return a valid MMIO file handle, so do not attempt to
+ close the file. If this flag is specified, all other file
+ opening flags are ignored.
+
+ @flag MMIO_EXIST | Determines whether the specified file exists
+ and creates a fully qualified filename from the path
+ specified in <p szFileName>. The fully qualified filename is
+ placed back into <p szFileName>. The return value
+ will be TRUE (cast to HMMIO) if the qualification was
+ successful and the file exists, FALSE otherwise. The file is
+ not opened, and the function does not return a valid MMIO file
+ handle, so do not attempt to close the file.
+
+ @flag MMIO_ALLOCBUF | Opens a file for buffered I/O.
+ To allocate a buffer larger or smaller than the default
+ buffer size (8K), set the <e MMIOINFO.cchBuffer> field of the
+ <t MMIOINFO> structure to the desired buffer size. If
+ <e MMIOINFO.cchBuffer> is zero, then the default buffer size
+ is used. If you are providing your own I/O buffer, then the
+ MMIO_ALLOCBUF flag should not be used.
+
+ @flag MMIO_COMPAT | Opens the file with compatibility mode,
+ allowing any process on a given machine to open the file
+ any number of times. <f mmioOpen> fails if the file has
+ been opened with any of the other sharing modes.
+
+ @flag MMIO_EXCLUSIVE | Opens the file with exclusive mode,
+ denying other processes both read and write access to the file.
+ <f mmioOpen> fails if the file has been opened in any other
+ mode for read or write access, even by the current process.
+
+ @flag MMIO_DENYWRITE | Opens the file and denies other
+ processes write access to the file. <f mmioOpen> fails
+ if the file has been opened in compatibility or for write
+ access by any other process.
+
+ @flag MMIO_DENYREAD | Opens the file and denies other
+ processes read access to the file. <f mmioOpen> fails if the
+ file has been opened in compatibility mode or for read access
+ by any other process.
+
+ @flag MMIO_DENYNONE | Opens the file without denying other
+ processes read or write access to the file. <f mmioOpen>
+ fails if the file has been opened in compatibility mode
+ by any other process.
+
+ @flag MMIO_GETTEMP | Creates a temporary filename, optionally
+ using the parameters passed in <p szFileName> to determine
+ the temporary name. For example, you can specify "C:F" to
+ create a temporary file residing on drive C, starting with
+ letter "F". The resulting filename is placed in the buffer
+ pointed to by <p szFileName>. The return value will be TRUE
+ (cast to HMMIO) if the temporary filename was created successfully,
+ FALSE otherwise. The file is
+ not opened, and the function does not return a valid MMIO file
+ handle, so do not attempt to close the file.
+ This flag overrides all other flags.
+
+@rdesc The return value is a handle to the opened file. This handle
+ is not a DOS file handle--do not use it with any file I/O functions
+ other than MMIO functions.
+
+ If the file cannot be opened, the return value is NULL. If
+ <p lpmmioinfo> is not NULL, then its <e MMIOINFO.wErrorRet> field
+ will contain extended error information returned by the I/O
+ procedure.
+
+@comm If <p lpmmioinfo> references an <t MMIOINFO> structure, set
+up the fields as described below. All unused fields must be set to
+zero, including reserved fields.
+
+-- To request that a file be opened with an installed I/O
+procedure, set the <e MMIOINFO.fccIOProc> field
+to the four-character code of the I/O procedure,
+and set the <e MMIOINFO.pIOProc> field to NULL.
+
+-- To request that a file be opened with an uninstalled I/O procedure,
+set the <e MMIOINFO.pIOProc> field to
+point to the I/O procedure, and set <e MMIOINFO.fccIOProc> to NULL.
+
+-- To request that <f mmioOpen> determine which I/O procedure to use
+to open the file based on the filename contained in <p szFilename>,
+set both <e MMIOINFO.fccIOProc> and <e MMIOINFO.pIOProc> to NULL.
+This is the default behavior if no <t MMIOINFO> structure is specified.
+
+-- To open a memory file using an internally allocated and managed
+buffer, set the <e MMIOINFO.pchBuffer> field to NULL,
+<e MMIOINFO.fccIOProc> to FOURCC_MEM,
+<e MMIOINFO.cchBuffer> to the initial size of the buffer, and
+<e MMIOINFO.adwInfo[0]> to the incremental expansion size of the
+buffer. This memory file will automatically be expanded in increments of
+<e MMIOINFO.adwInfo[0]> bytes when necessary. Specify the MMIO_CREATE
+flag for the <p dwOpenFlags> parameter to initially set the end of
+the file to be the beginning of the buffer.
+
+-- To open a memory file using a caller-supplied buffer, set
+the <e MMIOINFO.pchBuffer> field to point to the memory buffer,
+<e MMIOINFO.fccIOProc> to FOURCC_MEM,
+<e MMIOINFO.cchBuffer> to the size of the buffer, and
+<e MMIOINFO.adwInfo[0]> to the incremental expansion size of the
+buffer. The expansion size in <e MMIOINFO.adwInfo[0]> should only
+be non-zero if <e MMIOINFO.pchBuffer> is a pointer obtained by calling
+<f GlobalAlloc> and <f GlobalLock>, since <f GlobalReAlloc> will be called to
+expand the buffer. In particular, if <e MMIOINFO.pchBuffer> points to a
+local or global array, a block of memory in the local heap, or a block
+of memory allocated by <f GlobalDosAlloc>, <e MMIOINFO.adwInfo[0]> must
+be zero.
+Specify the MMIO_CREATE flag for the <p dwOpenFlags> parameter to
+initially set the end of the file to be the beginning of the buffer;
+otherwise, the entire block of memory will be considered readable.
+
+-- To use a currently open DOS file handle with MMIO, set the
+<e MMIOINFO.fccIOProc> field to FOURCC_DOS,
+<e MMIOINFO.pchBuffer> to NULL, and <e MMIOINFO.adwInfo[0]> to the
+DOS file handle. Note that offsets within the file will be relative to
+the beginning of the file, and will not depend on the DOS file position
+at the time <f mmioOpen> is called; the initial MMIO offset will be the same
+as the DOS offset when <f mmioOpen> is called.
+Later, to close the MMIO file handle without closing the DOS
+file handle, pass the MMIO_FHOPEN flag to <f mmioClose>.
+
+You must call <f mmioClose> to close a file opened with <f mmioOpen>.
+Open files are not automatically closed when an application exits.
+
+@xref mmioClose
+*/
+
+/* these are the changes to mmioOpen() to support compound files... */
+
+/* @doc CFDOC
+
+@api HMMIO | mmioOpen | ...The file can be a DOS file, a memory file,
+ an element of a RIFF compound file...
+
+@parm LPSTR | szFilename | ...
+
+ -- If <p szFilename> is of the form "foo+bar", then <f mmioOpen>
+ opens the compound file element named "bar" that is stored inside
+ the RIFF compound file named "foo".
+
+ -- If <p szFilename> is of the form "foo.ext+bar", then the
+ extension "ext" is assumed to identify the installed I/O procedure
+ (see <f mmioInstallIOProc>). The extension "bnd", and any extensions
+ that have not been installed, are assumed to refer to a RIFF compound
+ file.
+
+@parm LPMMIOINFO | lpmmioinfo | ...
+
+@parm DWORD | dwOpenFlags | ...
+
+@rdesc ...
+
+@comm ...
+
+ The following I/O procedure identifiers (type FOURCC) are predefined:
+
+ ...
+
+ FOURCC_BND: <p szFilename> is assumed to be the name of
+ a RIFF compound file element, and <p adwInfo[0]> should
+ contain the HMMCF of the compound file. Alternatively,
+ <p szFilename> can include the name of the compound file
+ (e.g. "foo.bnd+bar.dib" as described above), and <p adwInfo[0]>
+ should be NULL, to automatically open the compound file.
+
+ ...
+
+ The easy way to open an element of a RIFF compound file: just
+ include the name of the compound file in <p szFilename> preceded
+ by a "+" as described above. For example, opening
+ "c:\data\bar.bnd+blorg.dib" opens the compound file element
+ named "blorg.dib" in the compound file "c:\data\bar.bnd".
+ <p lpmmioinfo> can be null in this case -- set <p dwOpenFlags>
+ as described above. You can use this same method to open an
+ element of a custom storage system, if the file extension of the
+ compound file ("bnd" in the above example) corresponds to an
+ installed I/O procedure -- see <f mmioInstallIOProc> for details.
+
+ To open an element of a RIFF compound file that was opened using
+ <f mmioCFAccess> or <f mmioCFOpen>: set <p szFilename>
+ to be the name of the compound file element; set <p fccIOProc>
+ to FOURCC_BND; set <p adwInfo[0]> to the HMMCF of the open compound
+ file; set <p dwOpenFlags> and <p cchBuffer> as described above;
+ set all other fields of <p lpmmioinfo> to zero.
+
+ ...
+*/
+HMMIO WINAPI
+mmioOpen(LPSTR szFileName, LPMMIOINFO lpmmioinfo, DWORD dwOpenFlags)
+{
+ PMMIO pmmio; // MMIO status block
+ HPSTR hpBuffer;
+ UINT w;
+
+ V_FLAGS(dwOpenFlags, MMIO_OPEN_VALID, mmioOpen, NULL);
+ V_WPOINTER0(lpmmioinfo, sizeof(MMIOINFO), NULL);
+
+ if (lpmmioinfo) {
+ lpmmioinfo->wErrorRet = 0;
+ V_CALLBACK0((FARPROC)lpmmioinfo->pIOProc, NULL);
+ }
+
+ /* allocate MMIO status information block */
+ if ((pmmio = PH(NewHandle(TYPE_MMIO, sizeof(MMIOINFO)))) == NULL)
+ {
+ if (lpmmioinfo)
+ lpmmioinfo->wErrorRet = MMIOERR_OUTOFMEMORY;
+ return NULL;
+ }
+
+ /* if user supplied <lpmmioinfo>, copy it to <pmmio> */
+ if (lpmmioinfo != NULL)
+ *pmmio = *lpmmioinfo;
+
+ /* <dwOpenFlags> always takes precedence over contents of <pmmio> */
+ pmmio->dwFlags = dwOpenFlags;
+ pmmio->hmmio = HP(pmmio);
+
+ /* MMIO_ALLOCBUF in the flags means that the user wants a buffer
+ * allocated for buffered I/O, but after this point it means that
+ * a buffer *was* allocated, so turn off the flag until the buffer
+ * is actually allocated (which is done by mmioSetBuffer() below)
+ */
+ if (pmmio->dwFlags & MMIO_ALLOCBUF)
+ {
+ /* if a buffer size is not specified, use the default */
+ if (pmmio->cchBuffer == 0)
+ pmmio->cchBuffer = MMIO_DEFAULTBUFFER;
+ pmmio->dwFlags &= ~MMIO_ALLOCBUF;
+ }
+
+ /* Set the pIOProc function as determined by the file name or the
+ * parameters in the pmmio structure.
+ */
+ SetIOProc(szFileName, pmmio);
+
+ /* The pmmio structure hasn't been set up for buffering, so we must
+ * explicitly make sure that pchBuffer is NULL.
+ */
+ hpBuffer = pmmio->pchBuffer;
+ pmmio->pchBuffer = NULL;
+
+ /* set up buffered I/O however the user requested it */
+ if (w = mmioSetBuffer(HP(pmmio), hpBuffer, pmmio->cchBuffer, 0))
+ {
+ if (lpmmioinfo)
+ lpmmioinfo->wErrorRet = w;
+ FreeHandle(HP(pmmio));
+ return NULL;
+ }
+
+ /* let the I/O procedure open/delete/qualify the file */
+ w = (UINT)(DWORD) (pmmio->pIOProc((LPSTR) pmmio, MMIOM_OPEN, (LPARAM) szFileName, (LPARAM) 0));
+
+ /* If this is non-zero, return it to the user */
+ if (w != 0)
+ {
+ if (lpmmioinfo != NULL)
+ lpmmioinfo->wErrorRet = w;
+ FreeHandle(HP(pmmio));
+ return NULL;
+ }
+
+ if (pmmio->dwFlags & (MMIO_DELETE | MMIO_PARSE | MMIO_EXIST | MMIO_GETTEMP))
+ {
+ /* if the file is being deleted/parsed/name gotten, exit
+ * QUICKLY because the file handle (or whatever) in <pmmio>
+ * is not valid.
+ */
+ mmioSetBuffer(HP(pmmio), NULL, 0L, 0);
+ FreeHandle(HP(pmmio));
+ return (HMMIO) TRUE;
+ }
+
+ /* the initial "current buffered offset" will be equal to the initial
+ * "current disk offset"
+ */
+ pmmio->lBufOffset = pmmio->lDiskOffset;
+
+ return HP(pmmio);
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioClose | This function closes a file opened with
+ <f mmioOpen>.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file to
+ close.
+
+@parm UINT | wFlags | Specifies options for the close operation.
+
+ @flag MMIO_FHOPEN | If the file was opened by passing the DOS
+ file handle of an already-opened file to <f mmioOpen>, then
+ using this flag tells <f mmioClose> to close the MMIO file
+ handle, but not the DOS file handle.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value is an error code, either from
+ <f mmioFlush> or from the I/O procedure. The error code can be
+ one of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | The contents of the buffer could
+ not be written to disk.
+
+@xref mmioOpen mmioFlush
+*/
+UINT WINAPI
+mmioClose(HMMIO hmmio, UINT wFlags)
+{
+ UINT w;
+
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+
+ if (mmioFlush(hmmio, 0) != 0) {
+ DebugErr(DBF_WARNING, "MMIO File flush failed during close.\r\n");
+ PH(hmmio)->dwFlags &= ~MMIO_DIRTY;
+ }
+
+ if ((w = (UINT)(DWORD) PH(hmmio)->pIOProc((LPSTR)PH(hmmio), MMIOM_CLOSE, (LPARAM)(DWORD) wFlags, (LPARAM) 0)) != 0)
+ return w;
+
+ /* free the buffer if necessary */
+ mmioSetBuffer(hmmio, NULL, 0L, 0);
+
+ FreeHandle(hmmio);
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api LONG | mmioRead | This function reads a specified number of
+ bytes from a file opened with <f mmioOpen>.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file to be
+ read.
+
+@parm HPSTR | pch | Specifies a huge pointer to a buffer to contain
+ the data read from the file.
+
+@parm LONG | cch | Specifies the number of bytes to read from the
+ file.
+
+@rdesc The return value is the number of bytes actually read. If the
+ end of the file has been reached and no more bytes can be read, the
+ return value is zero. If there is an error reading from the file, the
+ return value is -1.
+
+@xref mmioWrite
+*/
+LONG WINAPI
+mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
+{
+ LONG lTotalBytesRead = 0L; // total no. bytes read
+ LONG lBytes; // no. bytes that can be read
+
+ V_HANDLE(hmmio, TYPE_MMIO, -1);
+ V_WPOINTER(pch, cch, -1);
+
+ while (TRUE)
+ {
+ /* calculate the number of bytes that can be read */
+ lBytes = PH(hmmio)->pchEndRead - PH(hmmio)->pchNext;
+
+ /* can only read at most <cch> bytes from buffer */
+ if (lBytes > cch)
+ lBytes = cch;
+
+ if (lBytes > 0)
+ {
+ /* this is where some performance improvements can
+ * be made, especially for small reads... should
+ * special-case cases when segment boundaries are
+ * not crossed (or maybe MemCopy() should do that)
+ */
+ MemCopy(pch, PH(hmmio)->pchNext, lBytes);
+ PH(hmmio)->pchNext += lBytes;
+ pch += lBytes;
+ cch -= lBytes;
+ lTotalBytesRead += lBytes;
+ }
+
+ /* cannot do MMIOM_READ from memory files */
+ if (PH(hmmio)->fccIOProc == FOURCC_MEM)
+ return lTotalBytesRead;
+
+ if (cch == 0) // no more to read?
+ return lTotalBytesRead;
+
+ /* we need to read beyond this buffer; if we have at least
+ * another bufferful to read, just call the I/O procedure
+ */
+ if (cch > PH(hmmio)->cchBuffer)
+ break;
+
+ /* read the next bufferful and loop around */
+ if (mmioAdvance(hmmio, NULL, MMIO_READ) != 0)
+ return -1;
+
+ /* if mmioAdvance() couldn't read any more data, we must be
+ * at the end of the file
+ */
+ if (PH(hmmio)->pchNext == PH(hmmio)->pchEndRead)
+ return lTotalBytesRead;
+ }
+
+ /* flush and empty the I/O buffer and manipulate <lBufOffset>
+ * directly to change the current file position
+ */
+ if (mmioFlush(hmmio, MMIO_EMPTYBUF) != 0)
+ return -1;
+
+ /* call the I/O procedure to do the rest of the reading */
+ lBytes = mmioDiskIO(PH(hmmio), MMIOM_READ, pch, cch);
+ PH(hmmio)->lBufOffset = PH(hmmio)->lDiskOffset;
+
+ return (lBytes == -1L) ? -1L : lTotalBytesRead + lBytes;
+}
+
+
+/* @doc EXTERNAL
+
+@api LONG | mmioWrite | This function writes a specified number of
+ bytes to a file opened with <f mmioOpen>.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file.
+
+@parm char _huge* | pch | Specifies a huge pointer to the buffer to be
+ written to the file.
+
+@parm LONG | cch | Specifies the number of bytes to write to the
+ file.
+
+@rdesc The return value is the number of bytes actually written. If
+ there is an error writing to the file, the return value is -1.
+
+@comm The current file position is incremented by the number of
+ bytes written.
+
+@xref mmioRead
+*/
+LONG WINAPI
+mmioWrite(HMMIO hmmio, const char _huge* pch, LONG cch)
+{
+ LONG lTotalBytesWritten = 0L; // total no. bytes written
+ LONG lBytes; // no. bytes that can be written
+
+ V_HANDLE(hmmio, TYPE_MMIO, -1);
+ V_RPOINTER(pch, cch, -1);
+
+ while (TRUE)
+ {
+ /* calculate the number of bytes that can be written */
+ lBytes = PH(hmmio)->pchEndWrite - PH(hmmio)->pchNext;
+
+ if ((cch > lBytes) && (PH(hmmio)->fccIOProc == FOURCC_MEM))
+ {
+ /* this is a memory file -- expand it */
+ if (mmioExpandMemFile(PH(hmmio), cch - lBytes) != 0)
+ return -1; // cannot expand
+ lBytes = PH(hmmio)->pchEndWrite - PH(hmmio)->pchNext;
+ }
+
+ /* can only write at most <cch> bytes into the buffer */
+ if (lBytes > cch)
+ lBytes = cch;
+
+ /* this is where some performance improvements can
+ * be made, especially for small writes... should
+ * special-case cases when segment boundaries are
+ * not crossed (or maybe MemCopy() should do that)
+ */
+ if (lBytes > 0)
+ {
+ MemCopy(PH(hmmio)->pchNext, pch, lBytes);
+ PH(hmmio)->dwFlags |= MMIO_DIRTY;
+ PH(hmmio)->pchNext += lBytes;
+ pch += lBytes;
+ cch -= lBytes;
+ lTotalBytesWritten += lBytes;
+ }
+
+ /* validate <pchEndRead>, i.e. re-enforce the invariant that
+ * <pchEndRead> points past the last valid byte in the buffer
+ */
+ if (PH(hmmio)->pchEndRead < PH(hmmio)->pchNext)
+ PH(hmmio)->pchEndRead = PH(hmmio)->pchNext;
+
+ if (cch == 0) // no more to write?
+ return lTotalBytesWritten;
+
+ /* we need to read beyond this buffer; if we have at least
+ * another bufferful to read, just call the I/O procedure
+ */
+ if (cch > PH(hmmio)->cchBuffer)
+ break;
+
+ /* write this buffer (if needed) and read the next
+ * bufferful (if needed)
+ */
+ if (mmioAdvance(hmmio, NULL, MMIO_WRITE) != 0)
+ return -1;
+ }
+
+ /* we should never need to do MMIOM_WRITE with memory files */
+
+ /* flush and empty the I/O buffer and manipulate <lBufOffset>
+ * directly to change the current file position
+ */
+ if (mmioFlush(hmmio, MMIO_EMPTYBUF) != 0)
+ return -1;
+
+ /* call the I/O procedure to do the rest of the writing */
+ lBytes = mmioDiskIO(PH(hmmio), MMIOM_WRITE, (HPSTR)pch, cch);
+ PH(hmmio)->lBufOffset = PH(hmmio)->lDiskOffset;
+
+ return (lBytes == -1L) ? -1L : lTotalBytesWritten + lBytes;
+}
+
+
+/* @doc EXTERNAL
+
+@api LONG | mmioSeek | This function changes the current file
+ position in a file opened with <f mmioOpen>. The current file
+ position is the location in the file where data is read or written.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file to seek
+ in.
+
+@parm LONG | lOffset | Specifies an offset to change the file position.
+
+@parm int | iOrigin | Specifies how the offset specified by
+ <p lOffset> is interpreted. Contains one of the following flags:
+
+ @flag SEEK_SET | Seeks to <p lOffset> bytes from the beginning
+ of the file.
+
+ @flag SEEK_CUR | Seeks to <p lOffset> bytes from the current
+ file position.
+
+ @flag SEEK_END | Seeks to <p lOffset> bytes from the end
+ of the file.
+
+@rdesc The return value is the new file position in bytes, relative
+ to the beginning of the file. If there is an error, the return value
+ is -1.
+
+@comm Seeking to an invalid location in the file, such as past the
+ end of the file, may not cause <f mmioSeek> to return an error,
+ but may cause subsequent I/O operations on the file to fail.
+
+ To locate the end of a file, call <f mmioSeek> with <p lOffset>
+ set to zero and <p iOrigin> set to SEEK_END.
+*/
+LONG WINAPI
+mmioSeek(HMMIO hmmio, LONG lOffset, int iOrigin)
+{
+ LONG lCurOffset; // disk offset of <pchNext>
+ LONG lEndBufOffset; // disk offset of end of buffer
+ LONG lNewOffset; // new disk offset
+
+ V_HANDLE(hmmio, TYPE_MMIO, -1);
+
+ /* careful! all this buffer pointer manipulation is fine, but keep
+ * in mind that buffering may be disabled (in which case <pchEndRead>
+ * and <pchBuffer> will both be NULL, so the buffer will appear to
+ * be zero bytes in size)
+ */
+
+ /* <PH(hmmio)->lBufOffset> is the disk offset of the start of the start
+ * of the buffer; determine <lCurOffset>, the offset of <pchNext>,
+ * and <lEndBufOffset>, the offset of the end of the valid part
+ * of the buffer
+ */
+ lCurOffset = PH(hmmio)->lBufOffset +
+ (PH(hmmio)->pchNext - PH(hmmio)->pchBuffer);
+ lEndBufOffset = PH(hmmio)->lBufOffset +
+ (PH(hmmio)->pchEndRead - PH(hmmio)->pchBuffer);
+
+ /* determine <lNewOffset>, the offset to seek to */
+ switch (iOrigin)
+ {
+ case SEEK_SET: // seek relative to start of file
+
+ lNewOffset = lOffset;
+ break;
+
+ case SEEK_CUR: // seek relative to current location
+
+ lNewOffset = lCurOffset + lOffset;
+ break;
+
+ case SEEK_END: // seek relative to end of file
+
+ if (PH(hmmio)->fccIOProc == FOURCC_MEM)
+ lNewOffset = lEndBufOffset - lOffset;
+ else
+ {
+ LONG lEndFileOffset;
+
+ /* find out where the end of the file is */
+ if ((lEndFileOffset = (LONG) PH(hmmio)->pIOProc((LPSTR) PH(hmmio),
+ MMIOM_SEEK, (LPARAM) 0, (LPARAM) SEEK_END)) == -1)
+ return -1;
+ lNewOffset = lEndFileOffset - lOffset;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if ((lNewOffset >= PH(hmmio)->lBufOffset) && (lNewOffset <= lEndBufOffset))
+ {
+ /* seeking within the valid part of the buffer
+ * (possibly including seeking to <lEndBufOffset>)
+ */
+ PH(hmmio)->pchNext = PH(hmmio)->pchBuffer +
+ (lNewOffset - PH(hmmio)->lBufOffset);
+ }
+ else
+ {
+ /* seeking outside the buffer */
+ if (PH(hmmio)->fccIOProc == FOURCC_MEM)
+ return -1; // can't seek outside mem. file buffer
+ if (mmioFlush(hmmio, 0) != 0)
+ return -1;
+
+ /* the current "buffered file position" (same as <lDiskOffset>
+ * for unbuffered files) equals <lBufOffset> +
+ * (<pchNext> - <pchBuffer>); we'll move the current buffered
+ * file position (and empty the buffer, since it becomes
+ * invalid when <lBufOffset> changes) as follows...
+ */
+ PH(hmmio)->lBufOffset = lNewOffset;
+ PH(hmmio)->pchNext = PH(hmmio)->pchEndRead = PH(hmmio)->pchBuffer;
+
+ /* don't need to actually seek right now, since the next
+ * MMIOM_READ or MMIOM_WRITE will have to seek anyway
+ */
+ }
+
+ return lNewOffset;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioGetInfo | This function retrieves information
+ about a file opened with <f mmioOpen>. This information allows the
+ caller to directly access the I/O buffer, if the file is opened
+ for buffered I/O.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file.
+
+@parm LPMMIOINFO | lpmmioinfo | Specifies a far pointer to a
+ caller-allocated <t MMIOINFO> structure that <f mmioGetInfo>
+ fills with information about the file. See the <t MMIOINFO> structure
+ and the <f mmioOpen> function for information about the fields in
+ this structure.
+
+@parm UINT | wFlags | Is not used and should be set to zero.
+
+@rdesc The return value is zero if the function is successful.
+
+@comm To directly access the I/O buffer of a file opened for
+ buffered I/O, use the following fields of the <t MMIOINFO> structure
+ filled by <f mmioGetInfo>:
+
+ -- The <e MMIOINFO.pchNext> field points to the next byte in the
+ buffer that can be read or written. When you read or write, increment
+ <e MMIOINFO.pchNext> by the number of bytes read or written.
+
+ -- The <e MMIOINFO.pchEndRead> field points to one byte past the
+ last valid byte in the buffer that can be read.
+
+ -- The <e MMIOINFO.pchEndWrite> field points to one byte past the
+ last location in the buffer that can be written.
+
+ Once you read or write to the buffer and modify
+ <e MMIOINFO.pchNext>, do not call any MMIO function except
+ <f mmioAdvance> until you call <f mmioSetInfo>. Call <f mmioSetInfo>
+ when you are finished directly accessing the buffer.
+
+ When you reach the end of the buffer specified by
+ <e MMIOINFO.pchEndRead> or <e MMIOINFO.pchEndWrite>, call
+ <f mmioAdvance> to fill the buffer from the disk, or write
+ the buffer to the disk. The <f mmioAdvance> function
+ will update the <e MMIOINFO.pchNext>, <e MMIOINFO.pchEndRead>, and
+ <e MMIOINFO.pchEndWrite> fields in the <t MMIOINFO> structure for the
+ file.
+
+ Before calling <f mmioAdvance> or <f mmioSetInfo> to flush a
+ buffer to disk, set the MMIO_DIRTY flag in the <e MMIOINFO.dwFlags>
+ field of the <t MMIOINFO> structure for the file. Otherwise, the
+ buffer will not get written to disk.
+
+ Do not decrement <e MMIOINFO.pchNext> or modify any fields in the
+ <t MMIOINFO> structure other than <e MMIOINFO.pchNext> and
+ <e MMIOINFO.dwFlags>. Do not set any flags in <e MMIOINFO.dwFlags>
+ except MMIO_DIRTY.
+
+@xref mmioSetInfo MMIOINFO
+*/
+UINT WINAPI
+mmioGetInfo(HMMIO hmmio, LPMMIOINFO lpmmioinfo, UINT wFlags)
+{
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpmmioinfo, sizeof(MMIOINFO), MMSYSERR_INVALPARAM);
+ V_FLAGS(wFlags, 0, mmioGetInfo, MMSYSERR_INVALFLAG);
+
+ *lpmmioinfo = *PH(hmmio);
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioSetInfo | This function updates the information
+ retrieved by <f mmioGetInfo> about a file opened with <f mmioOpen>.
+ Use this function to terminate direct buffer access of a file opened
+ for buffered I/O.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file.
+
+@parm LPMMIOINFO | lpmmioinfo | Specifies a far pointer to an
+ <t MMIOINFO> structure filled with information with
+ <f mmioGetInfo>.
+
+@parm UINT | wFlags | Is not used and should be set to zero.
+
+@rdesc The return value is zero if the function is successful.
+
+@comm If you have written to the file I/O buffer, set the
+ MMIO_DIRTY flag in the <e MMIOINFO.dwFlags> field of the <t MMIOINFO>
+ structure before calling <f mmioSetInfo> to terminate direct buffer
+ access. Otherwise, the buffer will not get flushed to disk.
+
+@xref mmioGetInfo MMIOINFO
+*/
+UINT WINAPI
+mmioSetInfo(HMMIO hmmio, const MMIOINFO FAR* lpmmioinfo, UINT wFlags)
+{
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+ V_RPOINTER(lpmmioinfo, sizeof(MMIOINFO), MMSYSERR_INVALPARAM);
+ V_WPOINTER0(lpmmioinfo->pchBuffer, lpmmioinfo->cchBuffer, MMSYSERR_INVALPARAM);
+ V_CALLBACK((FARPROC)lpmmioinfo->pIOProc, MMSYSERR_INVALPARAM);
+ V_FLAGS(wFlags, 0, mmioSetInfo, MMSYSERR_INVALFLAG);
+
+ /* copy the relevant information from <lpmmioinfo> back into <hmmio> */
+ *PH(hmmio) = *lpmmioinfo;
+
+ /* validate <pchEndRead>, i.e. re-enforce the invariant that
+ * <pchEndRead> points past the last valid byte in the buffer
+ */
+ if (PH(hmmio)->pchEndRead < PH(hmmio)->pchNext)
+ PH(hmmio)->pchEndRead = PH(hmmio)->pchNext;
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioSetBuffer | This function enables or disables
+ buffered I/O, or changes the buffer or buffer size for a file opened
+ with <f mmioOpen>.
+
+@parm HMMIO | hmmio | Specifies the file handle of the file.
+
+@parm LPSTR | pchBuffer | Specifies a far pointer to a
+ caller-supplied buffer to use for buffered I/O. If NULL,
+ <f mmioSetBuffer> allocates an internal buffer for buffered I/O.
+
+@parm LONG | cchBuffer | Specifies the size of the caller-supplied
+ buffer, or the size of the buffer for <f mmioSetBuffer> to allocate.
+
+@parm UINT | wFlags | Is not used and should be set to zero.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value specifies an error code. If an error
+ occurs, the file handle remains valid. The error code can be one
+ of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | The contents of the old buffer could
+ not be written to disk, so the operation was aborted.
+
+ @flag MMIOERR_OUTOFMEMORY | The new buffer could not be allocated,
+ probably due to a lack of available memory.
+
+@comm To enable buffering using an internal buffer, set
+ <p pchBuffer> to NULL and <p cchBuffer> to the desired buffer size.
+
+ To supply your own buffer, set <p pchBuffer> to point to the buffer,
+ and set <p cchBuffer> to the size of the buffer.
+
+ To disable buffered I/O, set <p pchBuffer> to NULL and
+ <p cchBuffer> to zero.
+
+ If buffered I/O is already enabled using an internal buffer, you
+ can reallocate the buffer to a different size by setting
+ <p pchBuffer> to NULL and <p cchBuffer> to the new buffer size. The
+ contents of the buffer may be changed after resizing.
+ */
+UINT WINAPI
+mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT wFlags)
+{
+ UINT w;
+
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+ V_WPOINTER0(pchBuffer, cchBuffer, MMSYSERR_INVALPARAM);
+ V_FLAGS(wFlags, 0, mmioSetBuffer, MMSYSERR_INVALFLAG);
+
+ if ((PH(hmmio)->dwFlags & MMIO_ALLOCBUF) &&
+ (pchBuffer == NULL) && (cchBuffer > 0))
+ {
+ /* grow or shrink buffer in-place */
+ HPSTR pch;
+ LONG lDeltaNext;
+ LONG lDeltaEndRead;
+
+ /* Since the ALLOCBUF flag is set, we must have a buffer */
+
+ /* write the buffer to disk, but don't empty it */
+ if ((w = mmioFlush(hmmio, 0)) != 0)
+ return w;
+
+ while (TRUE)
+ {
+ /* remember where <pchNext> and <pchEndRead> are
+ * in the buffer
+ */
+ lDeltaNext = PH(hmmio)->pchNext - PH(hmmio)->pchBuffer;
+ lDeltaEndRead = PH(hmmio)->pchEndRead - PH(hmmio)->pchBuffer;
+
+ if (cchBuffer >= lDeltaNext)
+ break;
+
+ /* caller wants to truncate the part of the buffer
+ * that contains <pchNext> -- handle this by
+ * emptying the buffer, recalculating <lDeltaNext>
+ * and <lDeltaEndRead>, and continuing below
+ */
+ if ((w = mmioFlush(hmmio, MMIO_EMPTYBUF)) != 0)
+ return w;
+ }
+
+ /* reallocate buffer */
+ pch = GlobalReAllocPtr(PH(hmmio)->pchBuffer, cchBuffer, GMEM_MOVEABLE);
+
+ /* If we cannot allocate the new buffer, exit with no
+ * harm done.
+ */
+ if (pch == NULL)
+ return MMIOERR_OUTOFMEMORY; // out of memory
+
+ /* transfer pointers to new buffer */
+ PH(hmmio)->cchBuffer = cchBuffer;
+ PH(hmmio)->pchBuffer = pch;
+ PH(hmmio)->pchNext = pch + lDeltaNext;
+ PH(hmmio)->pchEndRead = pch + lDeltaEndRead;
+
+ /* <pchEndWrite> always points to the end of the buf. */
+ PH(hmmio)->pchEndWrite = PH(hmmio)->pchBuffer + cchBuffer;
+
+ /* check if the reallocation truncated valid data */
+ if (lDeltaEndRead > cchBuffer)
+ PH(hmmio)->pchEndRead = PH(hmmio)->pchEndWrite;
+
+ return 0;
+ }
+
+ /* write the buffer to disk and stop using the buffer */
+ if ((w = mmioFlush(hmmio, MMIO_EMPTYBUF)) != 0)
+ return w;
+
+ if (PH(hmmio)->dwFlags & MMIO_ALLOCBUF)
+ {
+ GlobalFreePtr(PH(hmmio)->pchBuffer);
+ PH(hmmio)->dwFlags &= ~MMIO_ALLOCBUF;
+ }
+
+ /* Initially, no error. */
+ w = 0;
+
+ if ((pchBuffer == NULL) && (cchBuffer > 0))
+ {
+ pchBuffer = GlobalAllocPtr(GMEM_MOVEABLE, cchBuffer);
+
+ /* If there is an error, change the file to be un-buffered
+ * and return an error code. The file is still valid.
+ * (Just for a little extra security.)
+ */
+ if (pchBuffer == NULL) {
+ w = MMIOERR_OUTOFMEMORY;
+ cchBuffer = 0L;
+ } else
+ PH(hmmio)->dwFlags |= MMIO_ALLOCBUF;
+ }
+
+ /* invariant: <pchEndRead> points past the end of the "valid" portion
+ * of the buffer, and <pchEndWrite> points past the last byte that
+ * can be written into; <pchNext> points to the next byte to read
+ * or write; <lBufOffset> is the current disk offset of the start
+ * of the buffer, and it will not change
+ */
+ PH(hmmio)->pchBuffer = pchBuffer;
+ PH(hmmio)->cchBuffer = cchBuffer;
+ PH(hmmio)->pchNext = PH(hmmio)->pchEndRead = PH(hmmio)->pchBuffer;
+ PH(hmmio)->pchEndWrite = PH(hmmio)->pchBuffer + cchBuffer;
+
+ return w;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioFlush | This function writes the I/O buffer of a
+ file to disk, if the I/O buffer has been written to.
+
+@parm HMMIO | hmmio | Specifies the file handle of a file opened
+ with <f mmioOpen>.
+
+@parm UINT | wFlags | Is not used and should be set to zero.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value specifies an error code. The error
+ code can be one of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | The contents of the buffer could
+ not be written to disk.
+
+@comm Closing a file with <f mmioClose> will automatically flush
+ its buffer.
+
+ If there is insufficient disk space to write the
+ buffer, <f mmioFlush> will fail, even if the preceding <f mmioWrite>
+ calls were successful.
+*/
+UINT WINAPI
+mmioFlush(HMMIO hmmio, UINT wFlags)
+{
+ LONG lBytesAsk; // no. bytes to write
+ LONG lBytesWritten; // no. bytes actually written
+
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+ V_FLAGS(wFlags, MMIO_FLUSH_VALID, mmioFlush, MMSYSERR_INVALFLAG);
+
+ if ((PH(hmmio)->fccIOProc == FOURCC_MEM) || (PH(hmmio)->pchBuffer == NULL))
+ return 0; // cannot flush memory files
+
+ /* if the file is unbuffered then the dirty flag should not be set */
+ if (PH(hmmio)->dwFlags & MMIO_DIRTY)
+ {
+ /* figure out how many bytes need to be flushed */
+ lBytesAsk = PH(hmmio)->pchEndRead - PH(hmmio)->pchBuffer;
+
+ /* write the buffer to disk */
+ lBytesWritten = mmioDiskIO(PH(hmmio), MMIOM_WRITEFLUSH,
+ PH(hmmio)->pchBuffer, lBytesAsk);
+ if (lBytesWritten != lBytesAsk)
+ return MMIOERR_CANNOTWRITE;
+ PH(hmmio)->dwFlags &= ~MMIO_DIRTY; // buffer is clean now
+ }
+
+ if (wFlags & MMIO_EMPTYBUF)
+ {
+ /* empty the I/O buffer, and update <lBufOffset> to reflect
+ * what the current file position is
+ */
+ PH(hmmio)->lBufOffset += (PH(hmmio)->pchNext - PH(hmmio)->pchBuffer);
+ PH(hmmio)->pchNext = PH(hmmio)->pchEndRead = PH(hmmio)->pchBuffer;
+ }
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioAdvance | This function advances the I/O buffer of
+ a file set up for direct I/O buffer access with <f mmioGetInfo>. If
+ the file is opened for reading, the I/O buffer is filled from the
+ disk. If the file is opened for writing and the MMIO_DIRTY flag is
+ set in the <e MMIOINFO.dwFlags> field of the <t MMIOINFO> structure,
+ the buffer is written to disk. The <e MMIOINFO.pchNext>,
+ <e MMIOINFO.pchEndRead>, and <e MMIOINFO.pchEndWrite> fields of the
+ <t MMIOINFO> structure are updated to reflect the new state of
+ the I/O buffer.
+
+@parm HMMIO | hmmio | Specifies the file handle for a file opened
+ with <f mmioOpen>.
+
+@parm LPMMIOINFO | lpmmioinfo | Optionally specifies a far pointer to the
+ <t MMIOINFO> structure obtained with <f mmioGetInfo>, which is used to
+ set the current file information, then updated after the buffer is
+ advanced.
+
+@parm UINT | wFlags | Specifies options for the operation.
+ Contains exactly one of the following two flags:
+
+ @flag MMIO_READ | The buffer is filled from the file.
+
+ @flag MMIO_WRITE | The buffer is written to the file.
+
+@rdesc The return value is zero if the operation is successful.
+ Otherwise, the return value specifies an error code. The error
+ code can be one of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | The contents of the buffer could
+ not be written to disk.
+
+ @flag MMIOERR_CANNOTREAD | An error occurred while re-filling
+ the buffer.
+
+ @flag MMIOERR_UNBUFFERED | The specified file is not opened
+ for buffered I/O.
+
+ @flag MMIOERR_CANNOTEXPAND | The specified memory file cannot
+ be expanded, probably because the <e MMIOINFO.adwInfo[0]> field
+ was set to zero in the initial call to <f mmioOpen>.
+
+ @flag MMIOERR_OUTOFMEMORY | There was not enough memory to expand
+ a memory file for further writing.
+
+
+@comm If the specified file is opened for writing or for both
+ reading and writing, the I/O buffer will be flushed to disk before
+ the next buffer is read. If the I/O buffer cannot be written to disk
+ because the disk is full, then <f mmioAdvance> will return
+ MMIOERR_CANNOTWRITE.
+
+ If the specified file is only open for writing, the MMIO_WRITE
+ flag must be specified.
+
+ If you have written to the I/O buffer, you must set the MMIO_DIRTY
+ flag in the <e MMIOINFO.dwFlags> field of the <t MMIOINFO> structure
+ before calling <f mmioAdvance>. Otherwise, the buffer will not be
+ written to disk.
+
+ If the end of file is reached, <f mmioAdvance> will still return
+ success, even though no more data can be read. Thus, to check for
+ the end of the file, it is necessary to see if the
+ <e MMIOINFO.pchNext> and <e MMIOINFO.pchEndRead> fields of the
+ <t MMIOINFO> structure are equal after calling <f mmioAdvance>.
+
+@xref mmioGetInfo MMIOINFO
+*/
+UINT WINAPI
+mmioAdvance(HMMIO hmmio, LPMMIOINFO lpmmioinfo, UINT wFlags)
+{
+ LONG lBytesRead; // bytes actually read
+ UINT w;
+
+ V_HANDLE(hmmio, TYPE_MMIO, MMSYSERR_INVALHANDLE);
+ V_FLAGS(wFlags, MMIO_ADVANCE_VALID, mmioAdvance, MMSYSERR_INVALFLAG);
+
+ if (PH(hmmio)->pchBuffer == NULL)
+ return MMIOERR_UNBUFFERED;
+ if (lpmmioinfo != NULL) {
+ V_WPOINTER(lpmmioinfo, sizeof(MMIOINFO), MMSYSERR_INVALPARAM);
+ mmioSetInfo(hmmio, lpmmioinfo, 0);
+ }
+
+ if (PH(hmmio)->fccIOProc == FOURCC_MEM)
+ {
+ /* this is a memory file:
+ * -- if the caller is reading, cannot advance
+ * -- if the caller is writing, then advance by expanding
+ * the buffer (if possible) if the there is less than
+ * <adwInfo[0]> bytes left in the buffer
+ */
+ if (!(wFlags & MMIO_WRITE))
+ return 0;
+ if ((DWORD)(PH(hmmio)->pchEndWrite - PH(hmmio)->pchNext) >= PH(hmmio)->adwInfo[0])
+ return 0;
+ if ((w = mmioExpandMemFile(PH(hmmio), 1L)) != 0)
+ return w; // out of memory, or whatever
+ goto GETINFO_AND_EXIT;
+ }
+
+ /* empty the I/O buffer, which will effectively advance the
+ * buffer by (<pchNext> - <pchBuffer>) bytes
+ */
+ if ((w = mmioFlush(hmmio, MMIO_EMPTYBUF)) != 0)
+ return w;
+
+ /* if MMIO_WRITE bit is not set in wFlags, fill the buffer */
+ if (!(wFlags & MMIO_WRITE))
+ {
+ /* read the next bufferful from the file */
+ lBytesRead = mmioDiskIO(PH(hmmio), MMIOM_READ,
+ PH(hmmio)->pchBuffer, PH(hmmio)->cchBuffer);
+ if (lBytesRead == -1)
+ return MMIOERR_CANNOTREAD;
+
+ /* reading zero bytes should not be treated as an error
+ * condition -- e.g. open a new file R+W and call
+ * mmioAdvance(), and MMIOM_READ will return zero bytes
+ * because the file started off empty
+ */
+ PH(hmmio)->pchEndRead += lBytesRead;
+ }
+
+GETINFO_AND_EXIT:
+
+ /* copy <hmmio> back to <lpmmioinfo> if <lpmmioinfo> is provided */
+ if (lpmmioinfo != NULL)
+ mmioGetInfo(hmmio, lpmmioinfo, 0);
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api FOURCC | mmioStringToFOURCC | This function converts a
+ null-terminated string to a four-character code.
+
+@parm LPCSTR | sz | Specifies a far pointer to a null-terminated
+ string to a four-character code.
+
+@parm UINT | wFlags | Specifies options for the conversion:
+
+ @flag MMIO_TOUPPER | Converts all characters to uppercase.
+
+@rdesc The return value is the four character code created from the
+ given string.
+
+@comm This function does not check to see if the string referenced
+ by <p sz> follows any conventions regarding which characters to
+ include in a four-character code. The string is
+ simply copied to a four-character code and padded with blanks or
+ truncated to four characters if required.
+
+@xref mmioFOURCC
+*/
+FOURCC WINAPI
+mmioStringToFOURCC(LPCSTR sz, UINT wFlags)
+{
+ FOURCC fcc;
+ LPSTR pch = (LPSTR) &fcc;
+ int i;
+
+ V_STRING(sz, -1, NULL);
+ V_FLAGS(wFlags, MMIO_FOURCC_VALID, mmioStringToFOURCC, -1);
+
+ for (i = sizeof(FOURCC) - 1; i >= 0; i--)
+ {
+ if (!*sz)
+ *pch = ' ';
+ else {
+ *pch = *sz++;
+ if (wFlags & MMIO_TOUPPER)
+ *pch = (char)(WORD)(LONG)AnsiUpper((LPSTR)(LONG)*pch);
+ }
+ pch++;
+ }
+ return fcc;
+}
+
+
+/* @doc EXTERNAL
+
+@api LPMMIOPROC | mmioInstallIOProc | This function installs or
+ removes a custom I/O procedure. It will also locate an installed I/O
+ procedure, given its corresponding four-character code.
+
+@parm FOURCC | fccIOProc | Specifies a four-character code
+ identifying the I/O procedure to install, remove, or locate. All
+ characters in this four-character code should be uppercase characters.
+
+@parm LPMMIOPROC | pIOProc | Specifies the address of the I/O
+ procedure to install. To remove or locate an I/O procedure, set this
+ parameter to NULL.
+
+@parm DWORD | dwFlags | Specifies one of the following flags
+ indicating whether the I/O procedure is being installed, removed, or
+ located:
+
+ @flag MMIO_INSTALLPROC | Installs the specified I/O procedure.
+
+ @flag MMIO_GLOBALPROC | This flag is a modifier to the install flag,
+ and indicates the I/O procedure should be installed for global
+ use. This flag is ignored on removal or find.
+
+ @flag MMIO_REMOVEPROC | Removes the specified I/O procedure.
+
+ @flag MMIO_FINDPROC | Searches for the specified I/O procedure.
+
+@rdesc The return value is the address of the I/O procedure
+ installed, removed, or located. If there is an error, the return value
+ is NULL.
+
+@comm If the I/O procedure resides in the application, use
+ <f MakeProcInstance> to get a procedure-instance address and specify
+ this address for <p pIOProc>. You don't need to get a procedure-instance
+ address if the I/O procedure resides in a DLL.
+
+@cb LRESULT FAR PASCAL | IOProc | <f IOProc> is a placeholder for the
+ application-supplied function name. The actual name must be exported
+ by including it in a EXPORTS statement in the application's
+ module-definitions file.
+
+ @parm LPSTR | lpmmioinfo | Specifies a far pointer to an
+ <t MMIOINFO> structure containing information about the open
+ file. The I/O procedure must maintain the <e MMIOINFO.lDiskOffset>
+ field in this structure to indicate the file offset to the
+ next read or write location. The I/O procedure can use the
+ <e MMIOINFO.adwInfo[]> field to store state information. The
+ I/O procedure should not modify any other fields of the
+ <t MMIOINFO> structure.
+
+
+ @parm UINT | wMsg | Specifies a message indicating the
+ requested I/O operation. Messages that can be received include
+ <m MMIOM_OPEN>, <m MMIOM_CLOSE>, <m MMIOM_READ>, <m MMIOM_WRITE>,
+ and <m MMIOM_SEEK>.
+
+ @parm LPARAM | lParam1 | Specifies a parameter for the message.
+
+ @parm LPARAM | lParam2 | Specifies a parameter for the message.
+
+@rdesc The return value depends on the message specified by
+ <p wMsg>. If the I/O procedure does not recognize a message, it should
+ return zero.
+
+@comm The four-character code specified by the
+ <e MMIOINFO.fccIOProc> field in the <t MMIOINFO> structure
+ associated with a file identifies a filename extension for a custom
+ storage system. When an application calls <f mmioOpen> with a
+ filename such as "foo.xyz!bar", the I/O procedure associated with the
+ four-character code "XYZ " is called to open the "bar" element of the
+ file "foo.xyz".
+
+ The <f mmioInstallIOProc> function maintains a separate list of
+ installed I/O procedures for each Windows application. Therefore,
+ different applications can use the same I/O procedure identifier for
+ different I/O procedures without conflict. Installing an I/O procedure
+ globally however enables any process to use the procedure.
+
+ If an application calls <f mmioInstallIOProc> more than once to
+ register the same I/O procedure, then it must call
+ <f mmioInstallIOProc> to remove the procedure once for each time it
+ installed the procedure.
+
+ <f mmioInstallIOProc> will not prevent an application from
+ installing two different I/O procedures with the same identifier, or
+ installing an I/O procedure with one of the predefined identifiers
+ ("DOS ", "MEM "). The most recently installed procedure
+ takes precedence, and the most recently installed procedure is the
+ first one to get removed.
+
+ When searching for a specified I/O procedure, local procedures are
+ searched first, then global procedures.
+
+@xref mmioOpen
+ */
+LPMMIOPROC WINAPI
+mmioInstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, DWORD dwFlags)
+{
+ IOProcMapEntry *pEnt; // an entry in linked list
+ HTASK hTaskCurrent; // current Windows task handl
+
+ V_FLAGS(dwFlags, MMIO_VALIDPROC, mmioInstallIOProc, NULL);
+
+ if (fccIOProc == 0L)
+ return NULL;
+
+ hTaskCurrent = GetCurrentTask();
+
+ if (dwFlags & MMIO_INSTALLPROC)
+ {
+ /* install I/O procedure -- always add at the beginning of
+ * the list, so it overrides any other I/O procedures
+ * with the same identifier installed by the same task
+ */
+ V_CALLBACK((FARPROC)pIOProc, NULL);
+ if ((pEnt = (IOProcMapEntry NEAR *)
+ NewHandle(TYPE_IOPROC, sizeof(IOProcMapEntry))) == NULL)
+ return NULL; // out of memory
+ pEnt->fccIOProc = fccIOProc;
+ pEnt->pIOProc = pIOProc;
+ if (dwFlags & MMIO_GLOBALPROC) {
+
+ char libname[128];
+ char aszFour[sizeof(FOURCC)+1];
+
+ pEnt->hTask = NULL;
+ SetHandleOwner(pEnt, NULL);
+
+ //
+ // This is the hack to allow global IO Procs to be truly
+ // global. That is, if there is a matching 32 bit entry
+ // in win.ini under [IOProcs] for this fccIOProc will we try
+ // load the dll. The dll should install its 32 bit
+ // equivalent IOProc in the dll initialisation routine.
+ //
+
+ *(LPDWORD)&aszFour = (DWORD)fccIOProc;
+ aszFour[ sizeof(FOURCC) ] = '\0';
+ if ( GetProfileString( "IOProcs", aszFour, "", libname,
+ sizeof(libname) ) ) {
+
+ LoadLibraryEx32W( libname, 0L, 0L );
+ }
+
+ } else {
+ pEnt->hTask = hTaskCurrent;
+ }
+ pEnt->wFlags = 0;
+ pEnt->pNext = gIOProcMapHead;
+ gIOProcMapHead = pEnt;
+ return pIOProc;
+ }
+ if (!pIOProc)
+ if (dwFlags & MMIO_REMOVEPROC) {
+ LPMMIOPROC lpmmioproc;
+
+ lpmmioproc = RemoveIOProc(fccIOProc, hTaskCurrent);
+ if (!lpmmioproc)
+ lpmmioproc = RemoveIOProc(fccIOProc, NULL);
+ return lpmmioproc;
+ } else if (dwFlags & MMIO_FINDPROC)
+ return FindIOProc(fccIOProc, hTaskCurrent);
+ return NULL; // couldn't find requested I/O procedure
+}
+
+
+/* @doc EXTERNAL
+
+@api LRESULT | mmioSendMessage | This function sends a message to the
+ I/O procedure associated with the specified file.
+
+@parm HMMIO | hmmio | Specifies the file handle for a file opened
+ with <f mmioOpen>.
+
+@parm UINT | wMsg | Specifies the message to send to the I/O procedure.
+
+@parm LPARAM | lParam1 | Specifies a parameter for the message.
+
+@parm LPARAM | lParam2 | Specifies a parameter for the message.
+
+@rdesc The return value depends on the message. If the I/O procedure
+ does not recognize the message, the return value is zero.
+
+@comm Use this function to send custom user-defined messages. Do
+ not use it to send the <m MMIOM_OPEN>, <m MMIOM_CLOSE>,
+ <m MMIOM_READ>, <m MMIOM_WRITE>, <m MMIOM_WRITEFLUSH>, or
+ <m MMIOM_SEEK> messages. Define
+ custom messages to be greater than or equal to the MMIOM_USER constant.
+
+@xref mmioInstallIOProc
+*/
+LRESULT WINAPI
+mmioSendMessage(HMMIO hmmio, UINT wMsg, LPARAM lParam1, LPARAM lParam2)
+{
+ V_HANDLE(hmmio, TYPE_MMIO, (LRESULT)0);
+ return PH(hmmio)->pIOProc((LPSTR)PH(hmmio), wMsg, lParam1, lParam2);
+}
+
+
+/* @doc INTERNAL
+
+@api LONG | mmioDiskIO | Perform an unbuffered read or write.
+ Do not assume where the current disk offset <p lDiskOffset> will be.
+
+@parm PMMIO | pmmio | The open file handle returned by <f mmioOpen>.
+
+@parm UINT | wMsg | MMIOM_READ if <f mmioDiskIO> should read from the disk,
+ or MMIOM_WRITE if <f mmioDiskIO> should write to the disk.
+
+@parm HPSTR | pch | The buffer to read into or write from.
+
+@parm LONG | cch | The number of bytes to read or write.
+
+ <f mmioDiskIO> changes the disk offset to be <p lBufOffset>
+ and then performs an MMIOM_READ or MMIOM_WRITE operation as
+ specified by <p wMsg>, <p pch>, and <p cch>.
+
+ Note that if the I/O buffer is not empty at this point, this
+ function may not do what you expect.
+
+ Do not call this function for memory files.
+*/
+static LONG NEAR PASCAL
+mmioDiskIO(PMMIO pmmio, UINT wMsg, HPSTR pch, LONG cch)
+{
+ if (pmmio->lDiskOffset != pmmio->lBufOffset)
+ {
+ if ((LONG) pmmio->pIOProc((LPSTR) pmmio, MMIOM_SEEK, (LPARAM) pmmio->lBufOffset,
+ (LPARAM) SEEK_SET) == -1)
+ return -1;
+ }
+
+ return (LONG) pmmio->pIOProc((LPSTR) pmmio, wMsg, (LPARAM) pch, (LPARAM) cch);
+}
+
+
+/* @doc INTERNAL
+
+@api UINT | mmioExpandMemFile | Assuming that <p pmmio> is a memory file,
+ expand it by <p lExpand> bytes or <p adwInfo[0]> bytes, whichever
+ is larger. Do not disturb the contents of the buffer or change
+ the current file position.
+
+@parm PMMIO | pmmio | The open file handle returned by <f mmioOpen>.
+
+@parm LONG | lExpand | The minimum number of bytes to expand the buffer by.
+
+@rdesc If the function succeeds, zero is returned. If the function fails,
+ an error code is returned. In particular, MMIOERR_OUTOFMEMORY is
+ returned if memory reallocation failed.
+
+@comm Only call this function for memory files.
+*/
+static UINT NEAR PASCAL
+mmioExpandMemFile(PMMIO pmmio, LONG lExpand)
+{
+ MMIOMEMINFO * pInfo = (MMIOMEMINFO *) pmmio->adwInfo;
+ DWORD dwFlagsTemp;
+ UINT w;
+
+ /* make sure buffer can be expanded */
+ /* Note: we used to check ALLOC_BUF here, we don't now. */
+ if (pInfo->lExpand == 0)
+ return MMIOERR_CANNOTEXPAND; // cannot grow file
+
+ /* how much should the buffer be expanded by? */
+ if (lExpand < pInfo->lExpand)
+ lExpand = pInfo->lExpand;
+
+ dwFlagsTemp = pmmio->dwFlags;
+ pmmio->dwFlags |= MMIO_ALLOCBUF;
+ w = mmioSetBuffer(HP(pmmio), NULL,
+ pmmio->cchBuffer + lExpand, 0);
+ pmmio->dwFlags = dwFlagsTemp;
+ return w;
+}
+
+
+/************************************************************************/
+/*
+@doc INTERNAL
+
+@func UINT | lrename |
+ Renames the specified DOS file.
+
+@parm LPCSTR | lszOrigPath |
+ Points to the DOS file to rename.
+
+@parm LPCSTR | lszNewPath |
+ Points to the new name for the file.
+
+@rdesc Returns zero if the file was renamed, else the DOS error code.
+*/
+
+static UINT PASCAL NEAR lrename(
+ LPCSTR lszOrigPath,
+ LPCSTR lszNewPath)
+{
+ if (0) // fake out C6 so it does not warn of no return value
+ return 0;
+
+ _asm {
+ push ds
+ lds dx, lszOrigPath ; Original name.
+ les di, lszNewPath ; New name.
+ mov ah, 56H ; Rename file.
+ int 21h ; DOS.
+ sbb bx,bx ; if error (C) BX=FFFF, (NC) BX=000
+ and ax,bx ; set ax to zero if no error
+ pop ds
+ }
+}
+
+/* @doc INTERNAL
+
+@api LRESULT | mmioDOSIOProc | The 'DOS' I/O procedure, which handles I/O
+ on ordinary DOS files.
+
+@parm LPSTR | lpmmioinfo | A pointer to an MMIOINFO block that
+ contains information about the open file.
+
+@parm UINT | wMsg | The message that the I/O procedure is being
+ asked to execute.
+
+@parm LPARAM | lParam1 | Specifies additional message information.
+
+@parm LPARAM | lParam2 | Specifies additional message information.
+
+@rdesc Return value depends on <p wMsg>.
+*/
+static LRESULT CALLBACK
+mmioDOSIOProc(LPSTR lpmmioStr, UINT wMsg, LPARAM lParam1, LPARAM lParam2)
+{
+ PMMIO pmmio = (PMMIO) (UINT) (LONG) lpmmioStr; // only in DLL!
+ MMIODOSINFO * pInfo = (MMIODOSINFO *) pmmio->adwInfo;
+ LONG lResult;
+ OFSTRUCT of;
+
+ switch (wMsg)
+ {
+
+ case MMIOM_OPEN:
+
+ /* If a temporary file name is to be returned, use the file
+ * name parameter as a disk followed by a prefix for the name
+ * to create. The extra info parameter optionally contains a
+ * sequence number to pass.
+ */
+ if (pmmio->dwFlags & MMIO_GETTEMP) {
+ V_RPOINTER((LPSTR)lParam1, 4, (LRESULT) MMSYSERR_INVALPARAM);
+ return (LRESULT)(LONG) (GetTempFileName(*(LPSTR)lParam1,
+ ((LPSTR)lParam1) + 3, (UINT)pmmio->adwInfo[0],
+ (LPSTR)lParam1) ? 0 : MMIOERR_FILENOTFOUND);
+ }
+
+ /* <lParam1> is either a file name or NULL; if it is
+ * NULL, then <adwInfo[0]>, which is actually <pInfo->fh>,
+ * should already contain an open DOS file handle.
+ * note that the low word of <dwFlags> is equivalent to
+ * the <wStyle> parameter of OpenFile()
+ */
+ if (lParam1 != 0)
+ pInfo->fh = OpenFile((LPSTR) lParam1, &of,
+ LOWORD(pmmio->dwFlags));
+ if (pInfo->fh == HFILE_ERROR)
+ return (LRESULT)(LONG) ((pmmio->dwFlags & MMIO_DELETE) ? MMIOERR_CANNOTWRITE : MMIOERR_FILENOTFOUND);
+
+ /* if file is being deleted, there's nothing more to do */
+ if (pmmio->dwFlags & MMIO_DELETE)
+ return (LRESULT) 0;
+
+ /* if file name is being parsed, translate to ansi */
+ if (pmmio->dwFlags & (MMIO_PARSE | MMIO_EXIST))
+ {
+ OemToAnsi(of.szPathName, (LPSTR) lParam1);
+ return (LRESULT) 0;
+ }
+
+ /* check the current file offset */
+ pmmio->lDiskOffset = _llseek(pInfo->fh, 0L, SEEK_CUR);
+
+ return (LRESULT) 0;
+
+ case MMIOM_CLOSE:
+
+ /* MMIO_FHOPEN flag means keep the DOS file handle open */
+ if (!((DWORD)lParam1 & MMIO_FHOPEN) && (_lclose(pInfo->fh) == HFILE_ERROR))
+ return (LRESULT) MMIOERR_CANNOTCLOSE;
+ else
+ return (LRESULT) 0;
+
+ case MMIOM_READ:
+ lResult = _hread(pInfo->fh, (LPVOID)lParam1, (LONG)lParam2);
+
+ if (lResult != -1L)
+ pmmio->lDiskOffset += lResult;
+
+ return (LRESULT) lResult;
+
+ case MMIOM_WRITE:
+ case MMIOM_WRITEFLUSH:
+ lResult = _hwrite(pInfo->fh, (LPVOID)lParam1, (LONG)lParam2);
+
+ if (lResult != -1L)
+ pmmio->lDiskOffset += lResult;
+
+#ifdef DOSCANFLUSH
+ if (wMsg == MMIOM_WRITEFLUSH)
+ {
+ /* Issue hardware flush command */
+ }
+#endif
+ return (LRESULT) lResult;
+
+ case MMIOM_SEEK:
+ lResult = _llseek(pInfo->fh, (LONG)lParam1, (int)(LONG)lParam2);
+
+ if (lResult != -1L)
+ pmmio->lDiskOffset = lResult;
+
+ return (LRESULT) lResult;
+
+ case MMIOM_RENAME:
+ if (lrename((LPCSTR)lParam1, (LPCSTR)lParam2))
+ return (LRESULT) MMIOERR_FILENOTFOUND;
+ break;
+
+ }
+
+ return (LRESULT) 0;
+}
+
+
+/* @doc INTERNAL
+
+@api LRESULT | mmioMEMIOProc | The 'MEM' I/O procedure, which handles I/O
+ on memory files.
+
+@parm LPSTR | lpmmioinfo | A pointer to an MMIOINFO block that
+ contains information about the open file.
+
+@parm UINT | wMsg | The message that the I/O procedure is being
+ asked to execute.
+
+@parm LPARAM | lParam1 | Specifies additional message information.
+
+@parm LPARAM | lParam2 | Specifies additional message information.
+
+@rdesc Return value depends on <p wMsg>.
+*/
+static LRESULT CALLBACK
+mmioMEMIOProc(LPSTR lpmmioStr, UINT wMsg, LPARAM lParam1, LPARAM lParam2)
+{
+ PMMIO pmmio = (PMMIO) (UINT) (LONG) lpmmioStr; // only in DLL!
+
+ switch (wMsg)
+ {
+
+ case MMIOM_OPEN:
+
+ if (pmmio->dwFlags & ~(MMIO_CREATE | MMIO_READWRITE | MMIO_WRITE | MMIO_EXCLUSIVE | MMIO_DENYWRITE | MMIO_DENYREAD | MMIO_DENYNONE | MMIO_ALLOCBUF))
+ return (LRESULT) MMSYSERR_INVALFLAG;
+
+ /* all the data in the buffer is valid */
+ if (!(pmmio->dwFlags & MMIO_CREATE))
+ pmmio->pchEndRead = pmmio->pchEndWrite;
+ return (LRESULT) 0;
+
+ case MMIOM_CLOSE:
+
+ /* nothing special to do on close */
+ return (LRESULT) 0;
+
+ case MMIOM_READ:
+ case MMIOM_WRITE:
+ case MMIOM_WRITEFLUSH:
+ case MMIOM_SEEK:
+ return (LRESULT) -1;
+ }
+
+ return (LRESULT) 0;
+}
diff --git a/private/mvdm/wow16/mmsystem/mmiocf.c b/private/mvdm/wow16/mmsystem/mmiocf.c
new file mode 100644
index 000000000..0d758ed42
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmiocf.c
@@ -0,0 +1,525 @@
+/* cf.c
+ *
+ * MMIO RIFF compound file functions.
+ */
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmiocf.h"
+#include "mmioi.h"
+
+/* @doc CFDOC
+
+@api HMMCF | mmioCFOpen | Open a RIFF compound file by name.
+
+@parm LPSTR | szFileName | The name of the RIFF compound file.
+
+@parm DWORD | dwFlags | Zero or more of the following flags:
+ MMIO_READ, MMIO_WRITE, MMIO_READWRITE, MMIO_COMPAT, MMIO_EXCLUSIVE,
+ MMIO_DENYWRITE, MMIO_DENYREAD, MMIO_DENYNONE, MMIO_CREATE.
+ See <f mmioOpen> for a description of these flags.
+
+@rdesc Returns a handle to the open compound file. Returns NULL if the
+ compound file could not be opened. If the compound file was already
+ opened by this process, a handle to the compound file is returned,
+ and the usage count of the compound file is incremented.
+
+@comm A RIFF compound file is any RIFF file that contains a 'CTOC'
+ chunk (compound file table of contents) and a 'CGRP' chunk
+ (compound file resource group). The RIFF compound file format
+ is documented separately.
+
+ If the MMIO_CREATE flag is specified, then:
+
+ -- If the compound file is already open, the handle to that compound
+ file is returned.
+
+ -- If <p dwFlags> includes MMIO_WRITE, then the compound file will
+ actually be opened for both reading and writing, since a compound
+ file cannot be opened for writing alone.
+
+ Every call to <f mmioCFOpen> must be matched by a call to
+ <f mmioCFClose>.
+*/
+HMMCF API
+mmioCFOpen(LPSTR szFileName, DWORD dwFlags)
+{
+ /* TO DO */
+ return NULL;
+}
+
+
+/* @doc CFDOC
+
+@api HMMCF | mmioCFAccess | Open a RIFF compound file by reading the
+ 'CTOC' chunk (compound file table of contents) from a file that
+ was opened by <f mmioOpen>.
+
+@parm HMMIO | hmmio | The open file handle returned by <f mmioOpen>.
+
+@parm LPMMCFINFO | lpmmcfinfo | Optional information used if
+ <p dwFlags> if the compound file is to be created. <p lpmmcfinfo>
+ may be NULL if default information is to be used.
+ If <p lpmmcfinfo> is provided, then the following
+ fields should be filled in. Note that all these fields, including
+ the arrays, can be coded in a fixed C structure for a specific
+ file format, for the purposes of creating a new compound file.
+ However, note that if an existing compound file is opened, the
+ caller should expect that additional (possibly unknown) "extra
+ fields" may be present.
+
+ @flag dwEntriesTotal | Should contain the initial number of
+ (unused) entries in the table of contents (default 16).
+
+ @flag dwHeaderFlags | Should contain zero.
+
+ @flag wNameSize | The size of the <p achName> field of each
+ CTOC entry (default 13).
+
+ @flag wExHdrFields | The number of extra header fields to
+ allocate at the end of the CTOC header (default 0).
+
+ @flag wExEntFields | The number of extra entry fields
+ at the end of each CTOC entry (default 0).
+
+ @flag awExHdrFldUsage | Usage codes for extra header fields
+ (default no usage code).
+
+ @flag awExHdrEntUsage | Usage codes for extra entry fields
+ (default no usage code).
+
+ @flag adwExHdrField | Extra header field values
+ (default no extra header field values).
+
+@parm DWORD | dwFlags | Zero or more of the following flags:
+
+ @flag MMIO_CREATE | Create a compound file, i.e. create
+ the 'CTOC' and 'CGRP' chunks.
+
+ @flag MMIO_CTOCFIRST | Create the empty 'CTOC' chunk
+ immediately and place it before the 'CGRP' chunk.
+ If the 'CTOC' chunk gets too big, it may later have to
+ be rewritten after the 'CGRP' chunk.
+
+ This flag is ignored unless MMIO_CREATE is specified.
+
+@rdesc Returns a handle to the open compound file. Returns NULL if the
+ compound file could not be opened.
+
+@comm This function will open a RIFF compound file, assuming that
+ <p hmmio> has already been descended into the RIFF file
+ (using <f mmioDescend>) and <p hmmio> points to the beginning
+ of a chunk header. <p mmioCFAccess> scans through the file,
+ looking for a 'CTOC' and 'CGRP' chunk. If these chunks are not
+ found but MMIO_CREATE is specified, then a 'CTOC' chunk is created
+ (if MMIO_CTOCFIRST is specified) then a 'CGRP' chunk is created.
+ The CTOC is then maintained in memory until <f mmioCFClose>
+ is called.
+
+ Every call to <f mmioCFAccess> must be matched by a call to
+ <f mmioCFClose>.
+*/
+HMMCF API
+mmioCFAccess(HMMIO hmmio, LPMMCFINFO lpmmcfinfo, DWORD dwFlags)
+{
+ /* TO DO */
+ return NULL;
+}
+
+
+/* @doc CFDOC
+
+@api WORD | mmioCFClose | Close a compound file that was opened by
+ <f mmioCFOpen> or <f mmioCFAccess>.
+
+@parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
+ or <f mmioCFAccess>.
+
+@parm WORD | wFlags | Is not used and should be set to zero.
+
+@comm This function decrements the usage count of the compound file
+ <p hmmcf>. If the usage count drops to zero, the compound file
+ is closed. If the compound file was opened by <f mmioCFAccess>,
+ then the <p hmmcf> information is deallocated but the HMMIO
+ file handle associated with the compound file is not closed.
+*/
+WORD API
+mmioCFClose(HMMCF hmmcf, WORD wFlags)
+{
+ /* TO DO */
+ return 0;
+}
+
+
+/* @doc CFDOC
+
+@api WORD | mmioCFCopy | Copy the 'CTOC' and 'CGRP' chunks from an open
+ RIFF compound file to another file. The newly written 'CGRP' chunk
+ will be compacted, i.e. it will have no deleted elements.
+
+@parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
+ or <f mmioCFAccess>.
+
+@parm HMMIO | hmmio | An open file handle returned by <f mmioOpen>.
+ The compound file is copied to <p hmmio>.
+
+@parm DWORD | dwFlags | Is not used and should be set to zero.
+
+@rdesc If the function succeeds, zero is returned. If the function fails,
+ an error code is returned.
+
+@comm <f mmioCFCopy> assumes that the current file position of <p hmmio>
+ is the end of a file, descended into a 'RIFF' chunk. <f mmioCFCopy>
+ creates copies the 'CTOC' and 'CGRP' chunks from <p hmmcf> to
+ <p hmmio>. A side effect of the copy operation is that the
+ copy of the compound file is compacted, i.e. there are no deleted
+ elements.
+*/
+WORD API
+mmioCFCopy(HMMCF hmmcf, HMMIO hmmio, DWORD dwFlags)
+{
+ /* TO DO */
+ return 0;
+}
+
+
+/* @doc CFDOC
+
+@api DWORD | mmioCFGetInfo | Retrieve information from the CTOC header
+ of an open RIFF compound file.
+
+@parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
+ or <f mmioCFAccess>.
+
+@parm LPMMCFINFO | lpmmcfinfo | A caller-supplied buffer that will be
+ filled in with the CTOC header.
+
+@parm DWORD | cb | The size of buffer <p lpmmcfinfo>. At most <p cb>
+ bytes will be copied into <p lpmmcfinfo>.
+
+@rdesc Returns the number of bytes copied into <p lpmmcfinfo>.
+
+@comm The information that is copied to <p lpmmcfinfo> consists of
+ an MMCFINFO structure followed by the variable-length arrays
+ <p awExHdrFldUsage>, <p awExEntFldUsage>, and <p adwExHdrField>.
+ See the definition of RIFF Compound Files for more information.
+
+ To find out how big the RIFF CTOC header is (e.g. to allocate
+ enough memory for the entire block), call <f mmioCFGetInfo>
+ with <p cb> equal to the size of a DWORD, and the function will
+ copy the first field of the MMCFINFO structure (i.e.
+ <p dwHeaderSize>, the size of the CTOC header) into <p lpmmcfinfo>.
+*/
+DWORD API
+mmioCFGetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb)
+{
+ DWORD dwBytes;
+
+ dwBytes = min(cb, PC(hmmcf)->pHeader->dwHeaderSize);
+ MemCopy(lpmmcfinfo, PC(hmmcf)->pHeader, dwBytes);
+ return dwBytes;
+}
+
+
+/* @doc CFDOC
+
+@api DWORD | mmioCFSetInfo | Modify information that is stored in the
+ CTOC header of an open RIFF compound file.
+
+@parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
+ or <f mmioCFAccess>.
+
+@parm LPMMCFINFO | lpmmcfinfo | A caller-supplied buffer that was filled
+ in by <f mmioCFGetInfo> and then modified by the caller. Only
+ the <p awExHdrFldUsage> and <p adwExHdrField> fields should be
+ modified.
+
+@parm DWORD | cb | The size of buffer <p lpmmcfinfo>.
+
+@rdesc Returns the number of bytes copied from <p lpmmcfinfo>.
+
+@comm See <f mmioCFGetInfo> for more information.
+*/
+DWORD API
+mmioCFSetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb)
+{
+ /* TO DO:
+ * Re-allocate CTOC header if necessary and copy <p lpmmcfinfo> to it.
+ */
+
+ return 0L;
+}
+
+
+/* @doc CFDOC
+
+@api LPMMCTOCENTRY | mmioCFFindEntry | Find an particular entry in an open
+ RIFF compound file.
+
+@parm HMMCF | hmmcf | A compound file handle returned by <f mmioCFOpen>
+ or <f mmioCFAccess>.
+
+@parm LPSTR | szName | Then name of the compound file element to look for.
+ The search is case-insensitive. Flags in <p wFlags> can be set to
+ specify that an element is to be searched for by some attribute other
+ than name.
+
+@parm WORD | wFlags | Zero or more of the following flags:
+
+ @flag MMIO_FINDFIRST | Find the first entry in the CTOC table.
+
+ @flag MMIO_FINDNEXT | Find the next entry in the CTOC table
+ after the entry <p lParam> (which should be an
+ LPMMCTOCENTRY pointer returned by this function).
+ Returns NULL if <p lParam> refers to the last entry.
+
+ @flag MMIO_FINDUNUSED | Find the first entry in the CTOC table
+ that is marked as "unused", i.e. the entry does not refer
+ to any part of the compound file.
+
+ @flag MMIO_FINDDELETED | Find the first entry in the CTOC table
+ that is marked as "deleted", i.e. the entry refers to a
+ compound file element that occupies space in the CGRP
+ chunk but is currently unused.
+
+@parm LPARAM | lParam | Additional information (see <p wFlags> above).
+
+@rdesc Returns a pointer to the CTOC table entry that was found.
+ If no entry was found, NULL is returned. Warning: assume that
+ the returned pointer is invalid after the next call to any MMIO
+ function.
+
+@comm MMIO_FINDFIRST and MMIO_FINDNEXT can be used to enumerate the entries
+ in an open RIFF compound file.
+*/
+LPMMCTOCENTRY API
+mmioCFFindEntry(HMMCF hmmcf, LPSTR szName, WORD wFlags, LPARAM lParam)
+{
+ LPSTR pchEntry;
+ DWORD dwElemNum;
+
+ if (wFlags & MMIO_FINDFIRST)
+ return (LPMMCTOCENTRY) PC(hmmcf)->pEntries;
+
+ if (wFlags & MMIO_FINDNEXT)
+ {
+ pchEntry = (LPSTR) lParam + PC(hmmcf)->wEntrySize;
+ if (pchEntry > PC(hmmcf)->pEntries
+ + PC(hmmcf)->pHeader->dwEntriesTotal * PC(hmmcf)->wEntrySize)
+ return NULL;
+ else
+ return (LPMMCTOCENTRY) pchEntry;
+ }
+
+ for (pchEntry = PC(hmmcf)->pEntries, dwElemNum = 0;
+ dwElemNum < PC(hmmcf)->pHeader->dwEntriesTotal;
+ pchEntry += PC(hmmcf)->wEntrySize, dwElemNum++)
+ {
+ BYTE bFlags;
+
+ bFlags = *(BYTE FAR *) (pchEntry + PC(hmmcf)->wEntFlagsOffset);
+
+ if ((wFlags & MMIO_FINDUNUSED) && (bFlags & CTOC_EF_UNUSED))
+ return (LPMMCTOCENTRY) pchEntry;
+
+ if ((wFlags & MMIO_FINDDELETED) && (bFlags & CTOC_EF_DELETED))
+ return (LPMMCTOCENTRY) pchEntry;
+
+ if (bFlags & (CTOC_EF_DELETED | CTOC_EF_UNUSED))
+ continue;
+
+ if (lstrcmpi(szName, pchEntry + PC(hmmcf)->wEntNameOffset) == 0)
+ return (LPMMCTOCENTRY) pchEntry;
+ }
+
+ return NULL;
+}
+
+
+/* @doc INTERNAL
+
+@api LRESULT | mmioBNDIOProc | The 'BND' I/O procedure, which handles I/O
+ on RIFF compound file elements (including BND files).
+
+@parm LPSTR | lpmmioinfo | A pointer to an MMIOINFO block that
+ contains information about the open file.
+
+@parm WORD | wMsg | The message that the I/O procedure is being
+ asked to execute.
+
+@parm LPARAM | lParam1 | Specifies additional message information.
+
+@parm LPARAM | lParam2 | Specifies additional message information.
+
+@rdesc Return value depends on <p wMsg>.
+*/
+LRESULT CALLBACK
+mmioBNDIOProc(LPSTR lpmmioStr, WORD wMsg, LPARAM lParam1, LPARAM lParam2)
+{
+ PMMIO pmmio = (PMMIO) (WORD) (LONG) lpmmioStr; // only in DLL!
+ MMIOBNDINFO * pInfo = (MMIOBNDINFO *) pmmio->adwInfo;
+ LPSTR szFileName = (LPSTR) lParam1;
+ PMMCF pmmcf = PC(pInfo->hmmcf); // CF status block
+ LPSTR szElemName; // name of CF element
+ LONG lBytesLeft; // bytes left in file
+ LONG lExpand; // how much element expanded by
+ LONG lEndElement; // offset of end of element
+ LONG lResult;
+ LPSTR pch;
+
+ switch (wMsg)
+ {
+
+ case MMIOM_OPEN:
+
+ if (pmmcf == NULL)
+ {
+
+ /* expect <lParam1> is "...foo.bnd!element" */
+ if ((pch = fstrrchr(szFileName, CFSEPCHAR)) == NULL)
+ return (LRESULT) MMIOERR_CANNOTOPEN;
+
+ *pch = 0; // temporarily zero the "!"
+ if (pch[1] == 0) // is name of form "foo.bnd!"?
+ return (LRESULT) MMIOERR_CANNOTOPEN;
+ pInfo->hmmcf = mmioCFOpen(szFileName, (LONG) lParam2);
+ pmmcf = (PMMCF) pInfo->hmmcf;
+ *pch = CFSEPCHAR;
+ if (pInfo->hmmcf == NULL)
+ return (LRESULT) MMIOERR_CANNOTOPEN;
+ szElemName = pch + 1;
+
+ /* decrement the usage count, since the usage count
+ * was incremented by mmioCFOpen() and will
+ * be incremented below, but this MMIOM_OPEN
+ * represents only a single usage
+ */
+ pmmcf->lUsage--;
+ }
+ else
+ {
+ /* expect <lParam1> is CF element name */
+ szElemName = szFileName;
+ }
+
+ /* TO DO...
+ * If compound file is opened for writing or create(truncate),
+ * then make new entry at end (copying entry if required);
+ */
+
+ /* <pmmcf> is a handle to the compound file containing
+ * the element, and <szElemName> is the name of the element
+ */
+ if ((pInfo->pEntry = mmioCFFindEntry(pInfo->hmmcf,
+ szElemName, 0, 0L)) == NULL)
+ {
+ mmioCFClose(pInfo->hmmcf, 0);
+ return (LRESULT) MMIOERR_CANNOTOPEN;
+ }
+
+ if (pmmio->dwFlags & MMIO_DELETE)
+ {
+ /* TO DO: delete element: mark as deleted, update
+ * CTOC header, etc.
+ */
+ }
+
+ if (pmmio->dwFlags & (MMIO_PARSE | MMIO_EXIST))
+ {
+ /* TO DO: qualify name
+ */
+ }
+
+ return (LRESULT) 0;
+
+ case MMIOM_CLOSE:
+
+ mmioCFClose(pInfo->hmmcf, 0);
+ return (LRESULT) 0;
+
+ case MMIOM_READ:
+
+ lBytesLeft = pInfo->pEntry->dwSize - pmmio->lDiskOffset;
+ if ((LONG) lParam2 > lBytesLeft)
+ (LONG) lParam2 = lBytesLeft;
+ if (mmioSeek(pmmcf->hmmio, pmmio->lDiskOffset, SEEK_SET) == -1L)
+ return (LRESULT) -1L;
+ if ((lResult = mmioRead(pmmcf->hmmio,
+ (HPSTR) lParam1, (LONG) lParam2)) == -1L)
+ return (LRESULT) -1L;
+ pmmio->lDiskOffset += lResult;
+ return (LRESULT) lResult;
+
+ case MMIOM_WRITE:
+ case MMIOM_WRITEFLUSH: /* Note: flush not really handled! */
+
+ lEndElement = pmmcf->lStartCGRPData + pInfo->pEntry->dwOffset
+ + pInfo->pEntry->dwSize;
+ if ((lEndElement != pmmcf->lEndCGRP) ||
+ (pmmcf->lEndCGRP != pmmcf->lEndFile))
+ {
+ /* this CF element is not growable -- limit writing
+ * to the current end of the CF element
+ */
+ lBytesLeft = pInfo->pEntry->dwSize - pmmio->lDiskOffset;
+ if ((LONG) lParam2 > lBytesLeft)
+ (LONG) lParam2 = lBytesLeft;
+ }
+ if ((lResult = mmioWrite(pmmcf->hmmio,
+ (HPSTR) lParam1, (LONG) lParam2)) == -1L)
+ return (LRESULT) -1L;
+ pmmio->lDiskOffset += lResult;
+
+ if ((lExpand = pmmio->lDiskOffset - pInfo->pEntry->dwSize) > 0)
+ {
+ pInfo->pEntry->dwSize += lExpand;
+ pmmcf->lEndCGRP += lExpand;
+ pmmcf->lEndFile += lExpand;
+ pmmcf->lTotalExpand += lExpand;
+ }
+
+ return (LRESULT) lResult;
+
+ case MMIOM_SEEK:
+
+ /* calculate the new <lDiskOffset> (the current disk offset
+ * relative to the beginning of the compound file); don't
+ * bother seeking, since we'll have to seek again anyway
+ * at the next read (since <pmmcf->hmmio> is shared between
+ * all elements of the compound file)
+ */
+ switch ((int)(LONG) lParam2)
+ {
+
+ case SEEK_SET:
+
+ pmmio->lDiskOffset = pmmcf->lStartCGRPData
+ + pInfo->pEntry->dwOffset + (DWORD)lParam1;
+ break;
+
+ case SEEK_CUR:
+
+ pmmio->lDiskOffset += lParam1;
+ break;
+
+ case SEEK_END:
+
+ pmmio->lDiskOffset = pmmcf->lStartCGRPData +
+ + pInfo->pEntry->dwOffset
+ + pInfo->pEntry->dwSize - (DWORD)lParam1;
+ break;
+ }
+
+ return (LRESULT) pmmio->lDiskOffset;
+
+ case MMIOM_GETCF:
+
+ return (LRESULT)(LONG)(WORD) pInfo->hmmcf;
+
+ case MMIOM_GETCFENTRY:
+
+ return (LRESULT) pInfo->pEntry;
+ }
+
+ return (LRESULT) 0;
+}
diff --git a/private/mvdm/wow16/mmsystem/mmiocf.h b/private/mvdm/wow16/mmsystem/mmiocf.h
new file mode 100644
index 000000000..5bdce4db2
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmiocf.h
@@ -0,0 +1,71 @@
+/* mmiocf.h
+ *
+ * Multimedia File I/O Library.
+ *
+ * This include file contains declarations required for compound file support.
+ */
+
+#define PC(hmmcf) ((PMMCF)(hmmcf))
+#define CP(pmmcf) ((HMMCF)(pmmcf))
+
+typedef HLOCAL HMMCF; // a handle to an open RIFF compound file
+
+typedef struct _MMCFINFO // structure for representing CTOC header info.
+{
+ DWORD dwHeaderSize; // size of CTOC header (w/o entries)
+ DWORD dwEntriesTotal; // no. of entries in table of contents
+ DWORD dwEntriesDeleted; // no. of entries ref. to. del. ent.
+ DWORD dwEntriesUnused; // no. of entries that are not used
+ DWORD dwBytesTotal; // total bytes of CGRP contents
+ DWORD dwBytesDeleted; // total bytes of deleted CGRP elements
+ DWORD dwHeaderFlags; // flags
+ WORD wEntrySize; // size of each <CTOC-table-entry>
+ WORD wNameSize; // size of each <achName> field
+ WORD wExHdrFields; // number of "extra header fields"
+ WORD wExEntFields; // number of "extra entry fields"
+} MMCFINFO, FAR *LPMMCFINFO;
+
+typedef struct _MMCTOCENTRY // structure for representing CTOC entry info.
+{
+ DWORD dwOffset; // offset of element inside CGRP chunk
+ DWORD dwSize; // size of element inside CGRP chunk
+ DWORD dwMedType; // media element type of CF element
+ DWORD dwMedUsage; // media element usage information
+ DWORD dwCompressTech; // media element compression technique
+ DWORD dwUncompressBytes; // size after decompression
+ DWORD adwExEntField[1]; // extra CTOC table entry fields
+} MMCTOCENTRY, FAR *LPMMCTOCENTRY;
+
+/* <dwFlags> field of MMIOINFO structure -- many same as OpenFile() flags */
+#define MMIO_CTOCFIRST 0x00020000 // mmioCFOpen(): put CTOC before CGRP
+
+/* flags for other functions */
+#define MMIO_FINDFIRST 0x0010 // mmioCFFindEntry(): find first entry
+#define MMIO_FINDNEXT 0x0020 // mmioCFFindEntry(): find next entry
+#define MMIO_FINDUNUSED 0x0040 // mmioCFFindEntry(): find unused entry
+#define MMIO_FINDDELETED 0x0080 // mmioCFFindEntry(): find deleted entry
+
+/* message numbers for MMIOPROC */
+#define MMIOM_GETCF 10 // get HMMCF of CF element
+#define MMIOM_GETCFENTRY 11 // get ptr. to CTOC table entry
+
+/* four character codes used to identify standard built-in I/O procedures */
+#define FOURCC_BND mmioFOURCC('B', 'N', 'D', ' ')
+
+/* <dwHeaderFlags> field of MMCFINFO structure */
+#define CTOC_HF_SEQUENTIAL 0x00000001 // CF elements in same order as CTOC
+#define CTOC_HF_MEDSUBTYPE 0x00000002 // <dwMedUsage> is a med. el. subtype
+
+/* CTOC table entry flags */
+#define CTOC_EF_DELETED 0x01 // CF element is deleted
+#define CTOC_EF_UNUSED 0x02 // CTOC entry is unused
+
+/* CF I/O prototypes */
+HMMCF API mmioCFOpen(LPSTR szFileName, DWORD dwFlags);
+HMMCF API mmioCFAccess(HMMIO hmmio, LPMMCFINFO lpmmcfinfo,
+ DWORD dwFlags);
+WORD API mmioCFClose(HMMCF hmmcf, WORD wFlags);
+DWORD API mmioCFGetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb);
+DWORD API mmioCFSetInfo(HMMCF hmmcf, LPMMCFINFO lpmmcfinfo, DWORD cb);
+LPMMCTOCENTRY API mmioCFFindEntry(HMMCF hmmcf, LPSTR szName,
+ WORD wFlags, LPARAM lParam);
diff --git a/private/mvdm/wow16/mmsystem/mmioi.h b/private/mvdm/wow16/mmsystem/mmioi.h
new file mode 100644
index 000000000..74d6b5442
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmioi.h
@@ -0,0 +1,37 @@
+/* mmioi.h
+ *
+ * Definitions that are internal to the MMIO library.
+ */
+
+typedef MMIOINFO NEAR *PMMIO;
+
+#define PH(hmmio) ((PMMIO)(hmmio))
+#define HP(pmmio) ((HMMIO)(pmmio))
+
+typedef struct _MMIODOSINFO // How DOS IOProc uses MMIO.adwInfo[]
+{
+ HFILE fh; // DOS file handle
+} MMIODOSINFO;
+
+typedef struct _MMIOMEMINFO // How MEM IOProc uses MMIO.adwInfo[]
+{
+ LONG lExpand; // increment to expand mem. files by
+} MMIOMEMINFO;
+
+#define STATICIOPROC 0x0001
+
+typedef struct _IOProcMapEntry
+{
+ FOURCC fccIOProc; // ID of installed I/O procedure
+ LPMMIOPROC pIOProc; // I/O procedure address
+ HTASK hTask; // task that called mmioRegisterIOProc()
+ UINT wFlags;
+ struct _IOProcMapEntry *pNext; // pointer to next IOProc entry
+} IOProcMapEntry;
+
+// standard I/O procedures
+LRESULT CALLBACK mmioBNDIOProc(LPSTR, UINT, LPARAM, LPARAM);
+
+/* prototypes from "hmemcpy.asm" */
+LPVOID NEAR PASCAL MemCopy(LPVOID dest, const void FAR * source, LONG count);
+LPSTR NEAR PASCAL fstrrchr(LPCSTR lsz, char c);
diff --git a/private/mvdm/wow16/mmsystem/mmioriff.c b/private/mvdm/wow16/mmsystem/mmioriff.c
new file mode 100644
index 000000000..aa7c8112b
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmioriff.c
@@ -0,0 +1,365 @@
+/* mmioriff.c
+ *
+ * MMIO RIFF functions.
+ */
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmsysi.h"
+#include "mmioi.h"
+
+#define BCODE BYTE _based(_segname("_CODE"))
+static BCODE bPad;
+
+/* @doc EXTERNAL
+
+@api UINT | mmioDescend | This function descends into a chunk of a
+ RIFF file opened with <f mmioOpen>. It can also search for a given
+ chunk.
+
+@parm HMMIO | hmmio | Specifies the file handle of an open RIFF file.
+
+@parm LPMMCKINFO | lpck | Specifies a far pointer to a
+ caller-supplied <t MMCKINFO> structure that <f mmioDescend> fills
+ with the following information:
+
+ -- The <e MMCKINFO.ckid> field is the chunk ID of the chunk.
+
+ -- The <e MMCKINFO.cksize> field is the size of the data portion
+ of the chunk. The data size includes the form type or list type (if
+ any), but does not include the 8-byte chunk header or the pad byte at
+ the end of the data (if any).
+
+ -- The <e MMCKINFO.fccType> field is the form type if
+ <e MMCKINFO.ckid> is "RIFF", or the list type if
+ <e MMCKINFO.ckid> is "LIST". Otherwise, it is NULL.
+
+ -- The <e MMCKINFO.dwDataOffset> field is the file offset of the
+ beginning of the data portion of the chunk. If the chunk is a
+ "RIFF" chunk or a "LIST" chunk, then <e MMCKINFO.dwDataOffset>
+ is the offset of the form type or list type.
+
+ -- The <e MMCKINFO.dwFlags> contains other information about the chunk.
+ Currently, this information is not used and is set to zero.
+
+ If the MMIO_FINDCHUNK, MMIO_FINDRIFF, or MMIO_FINDLIST flag is
+ specified for <p wFlags>, then the <t MMCKINFO> structure is also
+ used to pass parameters to <f mmioDescend>:
+
+ -- The <e MMCKINFO.ckid> field specifies the four-character code
+ of the chunk ID, form type, or list type to search for.
+
+@parm LPMMCKINFO | lpckParent | Specifies a far pointer to an
+ optional caller-supplied <t MMCKINFO> structure identifying
+ the parent of the chunk being searched for.
+ A parent of a chunk is the enclosing chunk--only "RIFF" and "LIST"
+ chunks can be parents. If <p lpckParent> is not NULL, then
+ <f mmioDescend> assumes the <t MMCKINFO> structure it refers to
+ was filled when <f mmioDescend> was called to descend into the parent
+ chunk, and <f mmioDescend> will only search for a chunk within the
+ parent chunk. Set <p lpckParent> to NULL if no parent chunk is
+ being specified.
+
+@parm UINT | wFlags | Specifies search options. Contains up to one
+ of the following flags. If no flags are specified,
+ <f mmioDescend> descends into the chunk beginning at the current file
+ position.
+
+ @flag MMIO_FINDCHUNK | Searches for a chunk with the specified chunk ID.
+
+ @flag MMIO_FINDRIFF | Searches for a chunk with chunk ID "RIFF"
+ and with the specified form type.
+
+ @flag MMIO_FINDLIST | Searches for a chunk with chunk ID "LIST"
+ and with the specified form type.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value specifies an error code. If the end of
+ the file (or the end of the parent chunk, if given) is reached before
+ the desired chunk is found, the return value is
+ MMIOERR_CHUNKNOTFOUND.
+
+@comm A RIFF chunk consists of a four-byte chunk ID (type FOURCC),
+ followed by a four-byte chunk size (type DWORD), followed
+ by the data portion of the chunk, followed by a null pad byte if
+ the size of the data portion is odd. If the chunk ID is "RIFF" or
+ "LIST", the first four bytes of the data portion of the chunk are
+ a form type or list type (type FOURCC).
+
+ If <f mmioDescend> is used to search for a chunk, the file
+ position should be at the beginning of a
+ chunk before calling <f mmioDescend>. The search begins at the
+ current file position and continues to the end of the file. If a
+ parent chunk is specified, the file position should be somewhere
+ within the parent chunk before calling <f mmioDescend>. In this case,
+ the search begins at the current file position and continues to the
+ end of the parent chunk.
+
+ If <f mmioDescend> is unsuccessful in searching for a chunk, the
+ current file position is undefined. If <f mmioDescend> is
+ successful, the current file position is changed. If the chunk
+ is a "RIFF" or "LIST" chunk, the new file position
+ will be just after the form type or list type (12 bytes from the
+ beginning of the chunk). For other chunks, the new file position will be
+ the start of the data portion of the chunk (8 bytes from the
+ beginning of the chunk).
+
+ For efficient RIFF file I/O, use buffered I/O.
+
+ @xref mmioAscend MMCKINFO
+*/
+UINT WINAPI
+mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, const MMCKINFO FAR* lpckParent, UINT wFlags)
+{
+ FOURCC ckidFind; // chunk ID to find (or NULL)
+ FOURCC fccTypeFind; // form/list type to find (or NULL)
+
+ V_FLAGS(wFlags, MMIO_DESCEND_VALID, mmioDescend, MMSYSERR_INVALFLAG);
+ V_WPOINTER(lpck, sizeof(MMCKINFO), MMSYSERR_INVALPARAM);
+ V_RPOINTER0(lpckParent, sizeof(MMCKINFO), MMSYSERR_INVALPARAM);
+
+ /* figure out what chunk id and form/list type to search for */
+ if (wFlags & MMIO_FINDCHUNK)
+ ckidFind = lpck->ckid, fccTypeFind = NULL;
+ else
+ if (wFlags & MMIO_FINDRIFF)
+ ckidFind = FOURCC_RIFF, fccTypeFind = lpck->fccType;
+ else
+ if (wFlags & MMIO_FINDLIST)
+ ckidFind = FOURCC_LIST, fccTypeFind = lpck->fccType;
+ else
+ ckidFind = fccTypeFind = NULL;
+
+ lpck->dwFlags = 0L;
+
+ while (TRUE)
+ {
+ UINT w;
+
+ /* read the chunk header */
+ if (mmioRead(hmmio, (HPSTR) lpck, 2 * sizeof(DWORD)) !=
+ 2 * sizeof(DWORD))
+ return MMIOERR_CHUNKNOTFOUND;
+
+ /* store the offset of the data part of the chunk */
+ if ((lpck->dwDataOffset = mmioSeek(hmmio, 0L, SEEK_CUR)) == -1)
+ return MMIOERR_CANNOTSEEK;
+
+ /* see if the chunk is within the parent chunk (if given) */
+ if ((lpckParent != NULL) &&
+ (lpck->dwDataOffset - 8L >=
+ lpckParent->dwDataOffset + lpckParent->cksize))
+ return MMIOERR_CHUNKNOTFOUND;
+
+ /* if the chunk if a 'RIFF' or 'LIST' chunk, read the
+ * form type or list type
+ */
+ if ((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST))
+ {
+ if (mmioRead(hmmio, (HPSTR) &lpck->fccType,
+ sizeof(DWORD)) != sizeof(DWORD))
+ return MMIOERR_CHUNKNOTFOUND;
+ }
+ else
+ lpck->fccType = NULL;
+
+ /* if this is the chunk we're looking for, stop looking */
+ if ( ((ckidFind == NULL) || (ckidFind == lpck->ckid)) &&
+ ((fccTypeFind == NULL) || (fccTypeFind == lpck->fccType)) )
+ break;
+
+ /* ascend out of the chunk and try again */
+ if ((w = mmioAscend(hmmio, lpck, 0)) != 0)
+ return w;
+ }
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioAscend | This function ascends out of a chunk in a
+ RIFF file descended into with <f mmioDescend> or created with
+ <f mmioCreateChunk>.
+
+@parm HMMIO | hmmio | Specifies the file handle of an open RIFF file.
+
+@parm LPMMCKINFO | lpck | Specifies a far pointer to a
+ caller-supplied <t MMCKINFO> structure previously filled by
+ <f mmioDescend> or <f mmioCreateChunk>.
+
+@parm UINT | wFlags | Is not used and should be set to zero.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value specifies an error code. The error
+ code can be one of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | The contents of the buffer could
+ not be written to disk.
+
+ @flag MMIOERR_CANNOTSEEK | There was an error while seeking to
+ the end of the chunk.
+
+@comm If the chunk was descended into using <f mmioDescend>, then
+ <f mmioAscend> seeks to the location following the end of the
+ chunk (past the extra pad byte, if any).
+
+ If the chunk was created and descended into using
+ <f mmioCreateChunk>, or if the MMIO_DIRTY flag is set in the
+ <e MMCKINFO.dwFlags> field of the <t MMCKINFO> structure
+ referenced by <p lpck>, then the current file position
+ is assumed to be the end of the data portion of the chunk.
+ If the chunk size is not the same as the value stored
+ in the <e MMCKINFO.cksize> field when <f mmioCreateChunk>
+ was called, then <f mmioAscend> corrects the chunk
+ size in the file before ascending from the chunk. If the chunk
+ size is odd, <f mmioAscend> writes a null pad byte at the end of the
+ chunk. After ascending from the chunk, the current file position is
+ the location following the end of the chunk (past the extra pad byte,
+ if any).
+
+@xref mmioDescend mmioCreateChunk MMCKINFO
+*/
+UINT WINAPI
+mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT wFlags)
+{
+ V_FLAGS(wFlags, 0, mmioAscend, MMSYSERR_INVALFLAG);
+ V_WPOINTER(lpck, sizeof(MMCKINFO), MMSYSERR_INVALPARAM);
+
+ if (lpck->dwFlags & MMIO_DIRTY)
+ {
+ /* <lpck> refers to a chunk created by mmioCreateChunk();
+ * check that the chunk size that was written when
+ * mmioCreateChunk() was called is the real chunk size;
+ * if not, fix it
+ */
+ LONG lOffset; // current offset in file
+ LONG lActualSize; // actual size of chunk data
+
+ if ((lOffset = mmioSeek(hmmio, 0L, SEEK_CUR)) == -1)
+ return MMIOERR_CANNOTSEEK;
+ if ((lActualSize = lOffset - lpck->dwDataOffset) < 0)
+ return MMIOERR_CANNOTWRITE;
+
+ if (LOWORD(lActualSize) & 1)
+ {
+ /* chunk size is odd -- write a null pad byte */
+ if (mmioWrite(hmmio, (HPSTR) &bPad, sizeof(bPad))
+ != sizeof(bPad))
+ return MMIOERR_CANNOTWRITE;
+
+ }
+
+ if (lpck->cksize == (DWORD)lActualSize)
+ return 0;
+
+ /* fix the chunk header */
+ lpck->cksize = lActualSize;
+ if (mmioSeek(hmmio, lpck->dwDataOffset
+ - sizeof(DWORD), SEEK_SET) == -1)
+ return MMIOERR_CANNOTSEEK;
+ if (mmioWrite(hmmio, (HPSTR) &lpck->cksize,
+ sizeof(DWORD)) != sizeof(DWORD))
+ return MMIOERR_CANNOTWRITE;
+ }
+
+ /* seek to the end of the chunk, past the null pad byte
+ * (which is only there if chunk size is odd)
+ */
+ if (mmioSeek(hmmio, lpck->dwDataOffset + lpck->cksize
+ + (lpck->cksize & 1L), SEEK_SET) == -1)
+ return MMIOERR_CANNOTSEEK;
+
+ return 0;
+}
+
+
+/* @doc EXTERNAL
+
+@api UINT | mmioCreateChunk | This function creates a chunk in a
+ RIFF file opened with <f mmioOpen>. The new chunk is created at the
+ current file position. After the new chunk is created, the current
+ file position is the beginning of the data portion of the new chunk.
+
+@parm HMMIO | hmmio | Specifies the file handle of an open RIFF
+ file.
+
+@parm LPMMCKINFO | lpck | Specifies a pointer to a caller-supplied
+ <t MMCKINFO> structure containing information about the chunk to be
+ created. The <t MMCKINFO> structure should be set up as follows:
+
+ -- The <e MMCKINFO.ckid> field specifies the chunk ID of the
+ chunk. If <p wFlags> includes MMIO_CREATERIFF or MMIO_CREATELIST,
+ this field will be filled by <f mmioCreateChunk>.
+
+ -- The <e MMCKINFO.cksize> field specifies the size of the data
+ portion of the chunk, including the form type or list type (if any).
+ If this value is not correct when <f mmioAscend> is called to mark
+ the end of the chunk, them <f mmioAscend> will correct the chunk
+ size.
+
+ -- The <e MMCKINFO.fccType> field specifies the form type or list
+ type if the chunk is a "RIFF" or "LIST" chunk. If the chunk is not a
+ "RIFF" or "LIST" chunk, this field need not be filled in.
+
+ -- The <e MMCKINFO.dwDataOffset> field need not be filled in. The
+ <f mmioCreateChunk> function will fill this field with the file
+ offset of the data portion of the chunk.
+
+ -- The <e MMCKINFO.dwFlags> field need not be filled in. The
+ <f mmioCreateChunk> function will set the MMIO_DIRTY flag in
+ <e MMCKINFO.dwFlags>.
+
+@parm UINT | wFlags | Specifies flags to optionally create either a
+ "RIFF" chunk or a "LIST" chunk. Can contain one of the following
+ flags:
+
+ @flag MMIO_CREATERIFF | Creates a "RIFF" chunk.
+
+ @flag MMIO_CREATELIST | Creates a "LIST" chunk.
+
+@rdesc The return value is zero if the function is successful.
+ Otherwise, the return value specifies an error code. The error
+ code can be one of the following codes:
+
+ @flag MMIOERR_CANNOTWRITE | Unable to write the chunk header.
+
+ @flag MMIOERR_CANNOTSEEK | Uanble to determine offset of data
+ portion of the chunk.
+
+@comm This function cannot insert a chunk into the middle of a
+ file. If a chunk is created anywhere but the end of a file,
+ <f mmioCreateChunk> will overwrite existing information in the file.
+*/
+UINT WINAPI
+mmioCreateChunk(HMMIO hmmio, LPMMCKINFO lpck, UINT wFlags)
+{
+ int iBytes; // bytes to write
+ LONG lOffset; // current offset in file
+
+ V_FLAGS(wFlags, MMIO_CREATE_VALID, mmioCreateChunk, MMSYSERR_INVALFLAG);
+ V_WPOINTER(lpck, sizeof(MMCKINFO), MMSYSERR_INVALPARAM);
+
+ /* store the offset of the data part of the chunk */
+ if ((lOffset = mmioSeek(hmmio, 0L, SEEK_CUR)) == -1)
+ return MMIOERR_CANNOTSEEK;
+ lpck->dwDataOffset = lOffset + 2 * sizeof(DWORD);
+
+ /* figure out if a form/list type needs to be written */
+ if (wFlags & MMIO_CREATERIFF)
+ lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD);
+ else
+ if (wFlags & MMIO_CREATELIST)
+ lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD);
+ else
+ iBytes = 2 * sizeof(DWORD);
+
+ /* write the chunk header */
+ if (mmioWrite(hmmio, (HPSTR) lpck, (LONG) iBytes) != (LONG) iBytes)
+ return MMIOERR_CANNOTWRITE;
+
+ lpck->dwFlags = MMIO_DIRTY;
+
+ return 0;
+}
diff --git a/private/mvdm/wow16/mmsystem/mmreg.h b/private/mvdm/wow16/mmsystem/mmreg.h
new file mode 100644
index 000000000..3196a5a5c
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmreg.h
@@ -0,0 +1,619 @@
+/****************************************************************************
+ *
+ * mmreg.h - Registered Multimedia Information Public Header File
+ *
+ * Copyright (c) 1991,1992,1993 Microsoft Corporation. All Rights Reserved.
+ *
+ * Multimedia Registration
+ *
+ * Place this system include file in your INCLUDE path with the Windows SDK
+ * include files.
+ *
+ * Obtain the Multimedia Developer Registration Kit from:
+ *
+ * Microsoft Corporation
+ * Multimedia Systems Group
+ * Product Marketing
+ * One Microsoft Way
+ * Redmond, WA 98052-6399
+ *
+ * 800-227-4679 x11771
+ *
+ * Last Update: 01/21/93
+ *
+ ***************************************************************************/
+
+// Define the following to skip definitions
+//
+// NOMMIDS Multimedia IDs are not defined
+// NONEWWAVE No new waveform types are defined except WAVEFORMATEX
+// NONEWRIFF No new RIFF forms are defined
+// NONEWIC No new Image Compressor types are defined
+
+#ifndef _INC_MMREG
+/* use version number to verify compatibility */
+#define _INC_MMREG 130 // version * 100 + revision
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef NOMMIDS
+
+/* manufacturer IDs */
+#ifndef MM_MICROSOFT
+#define MM_MICROSOFT 1 /* Microsoft Corporation */
+#endif
+#define MM_CREATIVE 2 /* Creative Labs Inc. */
+#define MM_MEDIAVISION 3 /* Media Vision Inc. */
+#define MM_FUJITSU 4
+#define MM_ARTISOFT 20 /* Artisoft Inc. */
+#define MM_TURTLE_BEACH 21
+#define MM_IBM 22 /* International Bussiness Machines Corp. */
+#define MM_VOCALTEC 23 /* Vocaltec LTD. */
+#define MM_ROLAND 24
+#define MM_DIGISPEECH 25 /* Digispeech, Inc. */
+#define MM_NEC 26 /* NEC */
+#define MM_ATI 27 /* ATI */
+#define MM_WANGLABS 28 /* Wang Laboratories, Inc. */
+#define MM_TANDY 29 /* Tandy Corporation */
+#define MM_VOYETRA 30 /* Voyetra */
+#define MM_ANTEX 31 /* Antex */
+#define MM_ICL_PS 32
+#define MM_INTEL 33
+#define MM_GRAVIS 34
+#define MM_VAL 35 /* Video Associates Labs */
+#define MM_INTERACTIVE 36 /* InterActive, Inc. */
+#define MM_YAMAHA 37 /* Yamaha Corp. of America */
+#define MM_EVEREX 38 /* Everex Systems, Inc. */
+#define MM_ECHO 39 /* Echo Speech Corporation */
+#define MM_SIERRA 40 /* Sierra Semiconductor */
+#define MM_CAT 41 /* Computer Aided Technologies */
+#define MM_APPS 42 /* APPS Software International */
+#define MM_DSP_GROUP 43 /* DSP Group, Inc. */
+#define MM_MELABS 44 /* microEngineering Labs */
+#define MM_COMPUTER_FRIENDS 45 /* Computer Friends, Inc */
+
+/* MM_MICROSOFT product IDs */
+#ifndef MM_MIDI_MAPPER
+
+#define MM_MIDI_MAPPER 1 /* MIDI Mapper */
+#define MM_WAVE_MAPPER 2 /* Wave Mapper */
+#define MM_SNDBLST_MIDIOUT 3 /* Sound Blaster MIDI output port */
+#define MM_SNDBLST_MIDIIN 4 /* Sound Blaster MIDI input port */
+#define MM_SNDBLST_SYNTH 5 /* Sound Blaster internal synthesizer */
+#define MM_SNDBLST_WAVEOUT 6 /* Sound Blaster waveform output */
+#define MM_SNDBLST_WAVEIN 7 /* Sound Blaster waveform input */
+#define MM_ADLIB 9 /* Ad Lib-compatible synthesizer */
+#define MM_MPU401_MIDIOUT 10 /* MPU401-compatible MIDI output port */
+#define MM_MPU401_MIDIIN 11 /* MPU401-compatible MIDI input port */
+#define MM_PC_JOYSTICK 12 /* Joystick adapter */
+#endif
+
+#define MM_PCSPEAKER_WAVEOUT 13 /* PC Speaker waveform output */
+
+#define MM_MSFT_WSS_WAVEIN 14 /* MS Audio Board waveform input */
+#define MM_MSFT_WSS_WAVEOUT 15 /* MS Audio Board waveform output */
+#define MM_MSFT_WSS_FMSYNTH_STEREO 16 /* MS Audio Board Stereo FM synthesizer */
+#define MM_MSFT_WSS_OEM_WAVEIN 18 /* MS OEM Audio Board waveform input */
+#define MM_MSFT_WSS_OEM_WAVEOUT 19 /* MS OEM Audio Board waveform Output */
+#define MM_MSFT_WSS_OEM_FMSYNTH_STEREO 20 /* MS OEM Audio Board Stereo FM synthesizer */
+#define MM_MSFT_WSS_AUX 21 /* MS Audio Board Auxiliary Port */
+#define MM_MSFT_WSS_OEM_AUX 22 /* MS OEM Audio Auxiliary Port */
+
+#define MM_MSFT_GENERIC_WAVEIN 23 /* MS vanilla driver waveform input */
+#define MM_MSFT_GENERIC_WAVEOUT 24 /* MS vanilla driver waveform output */
+#define MM_MSFT_GENERIC_MIDIIN 25 /* MS vanilla driver MIDI input */
+#define MM_MSFT_GENERIC_MIDIOUT 26 /* MS vanilla driver external MIDI output */
+#define MM_MSFT_GENERIC_MIDISYNTH 27 /* MS vanilla driver MIDI synthesizer */
+#define MM_MSFT_GENERIC_AUX_LINE 28 /* MS vanilla driver aux (line in) */
+#define MM_MSFT_GENERIC_AUX_MIC 29 /* MS vanilla driver aux (mic) */
+#define MM_MSFT_GENERIC_AUX_CD 30 /* MS vanilla driver aux (CD) */
+
+
+/* MM_CREATIVE product IDs */
+#define MM_CREATIVE_SB15_WAVEIN 1 /* SB (r) 1.5 waveform input */
+#define MM_CREATIVE_SB20_WAVEIN 2 /* SB (r) 2.0 waveform input */
+#define MM_CREATIVE_SBPRO_WAVEIN 3 /* SB Pro (r) waveform input */
+#define MM_CREATIVE_SBP16_WAVEIN 4 /* SBP16 (r) waveform input */
+#define MM_CREATIVE_SB15_WAVEOUT 101 /* SB (r) 1.5 waveform output */
+#define MM_CREATIVE_SB20_WAVEOUT 102 /* SB (r) 2.0 waveform output */
+#define MM_CREATIVE_SBPRO_WAVEOUT 103 /* SB Pro (r) waveform output */
+#define MM_CREATIVE_SBP16_WAVEOUT 104 /* SBP16 (r) waveform output */
+#define MM_CREATIVE_MIDIOUT 201 /* SB (r) MIDI output port */
+#define MM_CREATIVE_MIDIIN 202 /* SB (r) MIDI input port */
+#define MM_CREATIVE_FMSYNTH_MONO 301 /* SB (r) FM synthesizer */
+#define MM_CREATIVE_FMSYNTH_STEREO 302 /* SB Pro (r) stereo FM synthesizer */
+#define MM_CREATIVE_AUX_CD 401 /* SB Pro (r) aux (CD) */
+#define MM_CREATIVE_AUX_LINE 402 /* SB Pro (r) aux (line in) */
+#define MM_CREATIVE_AUX_MIC 403 /* SB Pro (r) aux (mic) */
+
+
+/* MM_ARTISOFT product IDs */
+#define MM_ARTISOFT_SBWAVEIN 1 /* Artisoft Sounding Board waveform input */
+#define MM_ARTISOFT_SBWAVEOUT 2 /* Artisoft Sounding Board waveform output */
+
+/* MM_IBM Product IDs */
+#define MM_MMOTION_WAVEAUX 1 /* IBM M-Motion Auxiliary Device */
+#define MM_MMOTION_WAVEOUT 2 /* IBM M-Motion Waveform Output */
+#define MM_MMOTION_WAVEIN 3 /* IBM M-Motion Waveform Input */
+
+/* MM_MEDIAVISION Product IDs */
+#define MM_MEDIAVISION_PROAUDIO 0x10
+#define MM_PROAUD_MIDIOUT MM_MEDIAVISION_PROAUDIO+1
+#define MM_PROAUD_MIDIIN MM_MEDIAVISION_PROAUDIO+2
+#define MM_PROAUD_SYNTH MM_MEDIAVISION_PROAUDIO+3
+#define MM_PROAUD_WAVEOUT MM_MEDIAVISION_PROAUDIO+4
+#define MM_PROAUD_WAVEIN MM_MEDIAVISION_PROAUDIO+5
+#define MM_PROAUD_MIXER MM_MEDIAVISION_PROAUDIO+6
+#define MM_PROAUD_AUX MM_MEDIAVISION_PROAUDIO+7
+
+#define MM_MEDIAVISION_THUNDER 0x20
+#define MM_THUNDER_WAVEOUT MM_MEDIAVISION_THUNDER+1
+#define MM_THUNDER_WAVEIN MM_MEDIAVISION_THUNDER+2
+#define MM_THUNDER_SYNTH MM_MEDIAVISION_THUNDER+3
+
+#define MM_MEDIAVISION_TPORT 0x40
+#define MM_TPORT_WAVEOUT MM_MEDIAVISION_TPORT+1
+#define MM_TPORT_WAVEIN MM_MEDIAVISION_TPORT+2
+#define MM_TPORT_SYNTH MM_MEDIAVISION_TPORT+3
+
+// THIS CARD IS THE OEM VERSION OF THE NEXT PAS
+#define MM_MEDIAVISION_PROAUDIO_PLUS 0x50
+#define MM_PROAUD_PLUS_MIDIOUT MM_MEDIAVISION_PROAUDIO_PLUS+1
+#define MM_PROAUD_PLUS_MIDIIN MM_MEDIAVISION_PROAUDIO_PLUS+2
+#define MM_PROAUD_PLUS_SYNTH MM_MEDIAVISION_PROAUDIO_PLUS+3
+#define MM_PROAUD_PLUS_WAVEOUT MM_MEDIAVISION_PROAUDIO_PLUS+4
+#define MM_PROAUD_PLUS_WAVEIN MM_MEDIAVISION_PROAUDIO_PLUS+5
+#define MM_PROAUD_PLUS_MIXER MM_MEDIAVISION_PROAUDIO_PLUS+6
+#define MM_PROAUD_PLUS_AUX MM_MEDIAVISION_PROAUDIO_PLUS+7
+
+
+// THIS CARD IS THE NEW MEDIA VISION 16-bit card
+#define MM_MEDIAVISION_PROAUDIO_16 0x60
+#define MM_PROAUD_16_MIDIOUT MM_MEDIAVISION_PROAUDIO_16+1
+#define MM_PROAUD_16_MIDIIN MM_MEDIAVISION_PROAUDIO_16+2
+#define MM_PROAUD_16_SYNTH MM_MEDIAVISION_PROAUDIO_16+3
+#define MM_PROAUD_16_WAVEOUT MM_MEDIAVISION_PROAUDIO_16+4
+#define MM_PROAUD_16_WAVEIN MM_MEDIAVISION_PROAUDIO_16+5
+#define MM_PROAUD_16_MIXER MM_MEDIAVISION_PROAUDIO_16+6
+#define MM_PROAUD_16_AUX MM_MEDIAVISION_PROAUDIO_16+7
+
+
+// THIS CARD IS THE NEW MEDIA VISION CDPC card
+#define MM_MEDIAVISION_CDPC 0x70
+#define MM_CDPC_MIDIOUT MM_MEDIAVISION_CDPC+1
+#define MM_CDPC_MIDIIN MM_MEDIAVISION_CDPC+2
+#define MM_CDPC_SYNTH MM_MEDIAVISION_CDPC+3
+#define MM_CDPC_WAVEOUT MM_MEDIAVISION_CDPC+4
+#define MM_CDPC_WAVEIN MM_MEDIAVISION_CDPC+5
+#define MM_CDPC_MIXER MM_MEDIAVISION_CDPC+6
+#define MM_CDPC_AUX MM_MEDIAVISION_CDPC+7
+
+
+//
+// Opus MV1208 Chipset
+//
+#define MM_MEDIAVISION_OPUS1208 0x80
+#define MM_OPUS401_MIDIOUT MM_MEDIAVISION_OPUS1208+1
+#define MM_OPUS401_MIDIIN MM_MEDIAVISION_OPUS1208+2
+#define MM_OPUS1208_SYNTH MM_MEDIAVISION_OPUS1208+3
+#define MM_OPUS1208_WAVEOUT MM_MEDIAVISION_OPUS1208+4
+#define MM_OPUS1208_WAVEIN MM_MEDIAVISION_OPUS1208+5
+#define MM_OPUS1208_MIXER MM_MEDIAVISION_OPUS1208+6
+#define MM_OPUS1208_AUX MM_MEDIAVISION_OPUS1208+7
+
+
+//
+// Opus MV1216 Chipset
+//
+#define MM_MEDIAVISION_OPUS1216 0x90
+#define MM_OPUS1216_MIDIOUT MM_MEDIAVISION_OPUS1216+1
+#define MM_OPUS1216_MIDIIN MM_MEDIAVISION_OPUS1216+2
+#define MM_OPUS1216_SYNTH MM_MEDIAVISION_OPUS1216+3
+#define MM_OPUS1216_WAVEOUT MM_MEDIAVISION_OPUS1216+4
+#define MM_OPUS1216_WAVEIN MM_MEDIAVISION_OPUS1216+5
+#define MM_OPUS1216_MIXER MM_MEDIAVISION_OPUS1216+6
+#define MM_OPUS1216_AUX MM_MEDIAVISION_OPUS1216+7
+
+
+//
+// Mixer
+//
+#define MIXERR_BASE 512
+
+/* MM_VOCALTEC Product IDs */
+#define MM_VOCALTEC_WAVEOUT 1 /* Vocaltec Waveform output port */
+#define MM_VOCALTEC_WAVEIN 2 /* Vocaltec Waveform input port */
+
+/* MM_ROLAND Product IDs */
+#define MM_ROLAND_MPU401_MIDIOUT 15
+#define MM_ROLAND_MPU401_MIDIIN 16
+#define MM_ROLAND_SMPU_MIDIOUTA 17
+#define MM_ROLAND_SMPU_MIDIOUTB 18
+#define MM_ROLAND_SMPU_MIDIINA 19
+#define MM_ROLAND_SMPU_MIDIINB 20
+#define MM_ROLAND_SC7_MIDIOUT 21
+#define MM_ROLAND_SC7_MIDIIN 22
+
+
+/* MM_DIGISPEECH Product IDs */
+#define MM_DIGISP_WAVEOUT 1 /* Digispeech Waveform output port */
+#define MM_DIGISP_WAVEIN 2 /* Digispeech Waveform input port */
+
+/* MM_NEC Product IDs */
+
+/* MM_ATI Product IDs */
+
+/* MM_WANGLABS Product IDs */
+
+#define MM_WANGLABS_WAVEIN1 1
+/* Input audio wave device present on the CPU board of the following Wang models: Exec 4010, 4030 and 3450; PC 251/25C, PC 461/25S and PC 461/33C */
+#define MM_WANGLABS_WAVEOUT1 2
+/* Output audio wave device present on the CPU board of the Wang models listed above. */
+
+/* MM_TANDY Product IDs */
+
+/* MM_VOYETRA Product IDs */
+
+/* MM_ANTEX Product IDs */
+
+/* MM_ICL_PS Product IDs */
+
+/* MM_INTEL Product IDs */
+
+#define MM_INTELOPD_WAVEIN 1 // HID2 WaveAudio Input driver
+#define MM_INTELOPD_WAVEOUT 101 // HID2 WaveAudio Output driver
+#define MM_INTELOPD_AUX 401 // HID2 Auxiliary driver (required for mixing functions)
+
+/* MM_GRAVIS Product IDs */
+
+/* MM_VAL Product IDs */
+
+// values not defined by Manufacturer
+
+// #define MM_VAL_MICROKEY_AP_WAVEIN ??? // Microkey/AudioPort Waveform Input
+// #define MM_VAL_MICROKEY_AP_WAVEOUT ??? // Microkey/AudioPort Waveform Output
+
+/* MM_INTERACTIVE Product IDs */
+
+#define MM_INTERACTIVE_WAVEIN 0x45 // no comment provided by Manufacturer
+#define MM_INTERACTIVE_WAVEOUT 0x45 // no comment provided by Manufacturer
+
+/* MM_YAMAHA Product IDs */
+
+#define MM_YAMAHA_GSS_SYNTH 0x01 // Yamaha Gold Sound Standard FM sythesis driver
+#define MM_YAMAHA_GSS_WAVEOUT 0x02 // Yamaha Gold Sound Standard wave output driver
+#define MM_YAMAHA_GSS_WAVEIN 0x03 // Yamaha Gold Sound Standard wave input driver
+#define MM_YAMAHA_GSS_MIDIOUT 0x04 // Yamaha Gold Sound Standard midi output driver
+#define MM_YAMAHA_GSS_MIDIIN 0x05 // Yamaha Gold Sound Standard midi input driver
+#define MM_YAMAHA_GSS_AUX 0x06 // Yamaha Gold Sound Standard auxillary driver for mixer functions
+
+/* MM_EVEREX Product IDs */
+
+#define MM_EVEREX_CARRIER 0x01 // Everex Carrier SL/25 Notebook
+
+/* MM_ECHO Product IDs */
+
+#define MM_ECHO_SYNTH 0x01 // Echo EuSythesis driver
+#define MM_ECHO_WAVEOUT 0x02 // Wave output driver
+#define MM_ECHO_WAVEIN 0x03 // Wave input driver
+#define MM_ECHO_MIDIOUT 0x04 // MIDI output driver
+#define MM_ECHO_MIDIIN 0x05 // MIDI input driver
+#define MM_ECHO_AUX 0x06 // auxillary driver for mixer functions
+
+
+/* MM_SIERRA Product IDs */
+
+#define MM_SIERRA_ARIA_MIDIOUT 0x14 // Sierra Aria MIDI output
+#define MM_SIERRA_ARIA_MIDIIN 0x15 // Sierra Aria MIDI input
+#define MM_SIERRA_ARIA_SYNTH 0x16 // Sierra Aria Synthesizer
+#define MM_SIERRA_ARIA_WAVEOUT 0x17 // Sierra Aria Waveform output
+#define MM_SIERRA_ARIA_WAVEIN 0x18 // Sierra Aria Waveform input
+#define MM_SIERRA_ARIA_AUX 0x19 // Siarra Aria Auxiliary device
+
+/* MM_CAT Product IDs */
+
+/* MM_APPS Product IDs */
+
+/* MM_DSP_GROUP Product IDs */
+
+#define MM_DSP_GROUP_TRUESPEECH 0x01 // High quality 9.54:1 Speech Compression Vocoder
+
+/* MM_MELABS Product IDs */
+
+#define MM_MELABS_MIDI2GO 0x01 // parellel port MIDI interface
+
+#endif
+
+/*////////////////////////////////////////////////////////////////////////// */
+
+#ifndef NONEWWAVE
+
+/* WAVE form wFormatTag IDs */
+#define WAVE_FORMAT_UNKNOWN (0x0000)
+#define WAVE_FORMAT_ADPCM (0x0002)
+#define WAVE_FORMAT_IBM_CVSD (0x0005)
+#define WAVE_FORMAT_ALAW (0x0006)
+#define WAVE_FORMAT_MULAW (0x0007)
+#define WAVE_FORMAT_OKI_ADPCM (0x0010)
+#define WAVE_FORMAT_DVI_ADPCM (0x0011)
+#define WAVE_FORMAT_IMA_ADPCM (WAVE_FORMAT_DVI_ADPCM)
+#define WAVE_FORMAT_DIGISTD (0x0015)
+#define WAVE_FORMAT_DIGIFIX (0x0016)
+#define WAVE_FORMAT_YAMAHA_ADPCM (0x0020)
+#define WAVE_FORMAT_SONARC (0x0021)
+#define WAVE_FORMAT_DSPGROUP_TRUESPEECH (0x0022)
+#define WAVE_FORMAT_ECHOSC1 (0x0023)
+#define WAVE_FORMAT_CREATIVE_ADPCM (0x0200)
+
+#endif /* NONEWWAVE */
+
+
+#ifndef WAVE_FORMAT_PCM
+
+/* general waveform format structure (information common to all formats) */
+typedef struct waveformat_tag {
+ WORD wFormatTag; /* format type */
+ WORD nChannels; /* number of channels (i.e. mono, stereo...) */
+ DWORD nSamplesPerSec; /* sample rate */
+ DWORD nAvgBytesPerSec; /* for buffer estimation */
+ WORD nBlockAlign; /* block size of data */
+} WAVEFORMAT;
+typedef WAVEFORMAT *PWAVEFORMAT;
+typedef WAVEFORMAT NEAR *NPWAVEFORMAT;
+typedef WAVEFORMAT FAR *LPWAVEFORMAT;
+
+/* flags for wFormatTag field of WAVEFORMAT */
+#define WAVE_FORMAT_PCM 1
+
+/* specific waveform format structure for PCM data */
+typedef struct pcmwaveformat_tag {
+ WAVEFORMAT wf;
+ WORD wBitsPerSample;
+} PCMWAVEFORMAT;
+typedef PCMWAVEFORMAT *PPCMWAVEFORMAT;
+typedef PCMWAVEFORMAT NEAR *NPPCMWAVEFORMAT;
+typedef PCMWAVEFORMAT FAR *LPPCMWAVEFORMAT;
+
+
+#endif /* WAVE_FORMAT_PCM */
+
+
+
+/* general extended waveform format structure
+ Use this for all NON PCM formats
+ (information common to all formats)
+*/
+
+typedef struct waveformat_extended_tag {
+ WORD wFormatTag; /* format type */
+ WORD nChannels; /* number of channels (i.e. mono, stereo...) */
+ DWORD nSamplesPerSec; /* sample rate */
+ DWORD nAvgBytesPerSec; /* for buffer estimation */
+ WORD nBlockAlign; /* block size of data */
+ WORD wBitsPerSample; /* Number of bits per sample of mono data */
+ WORD cbSize; /* The count in bytes of the size of
+ extra information (after cbSize) */
+
+} WAVEFORMATEX;
+typedef WAVEFORMATEX *PWAVEFORMATEX;
+typedef WAVEFORMATEX NEAR *NPWAVEFORMATEX;
+typedef WAVEFORMATEX FAR *LPWAVEFORMATEX;
+
+
+#ifndef NONEWWAVE
+
+/* Define data for MS ADPCM */
+
+typedef struct adpcmcoef_tag {
+ short iCoef1;
+ short iCoef2;
+} ADPCMCOEFSET;
+typedef ADPCMCOEFSET *PADPCMCOEFSET;
+typedef ADPCMCOEFSET NEAR *NPADPCMCOEFSET;
+typedef ADPCMCOEFSET FAR *LPADPCMCOEFSET;
+
+typedef struct adpcmwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD wSamplesPerBlock;
+ WORD wNumCoef;
+ ADPCMCOEFSET aCoef[];
+} ADPCMWAVEFORMAT;
+typedef ADPCMWAVEFORMAT *PADPCMWAVEFORMAT;
+typedef ADPCMWAVEFORMAT NEAR *NPADPCMWAVEFORMAT;
+typedef ADPCMWAVEFORMAT FAR *LPADPCMWAVEFORMAT;
+
+
+//
+// Intel's DVI ADPCM structure definitions
+//
+// for WAVE_FORMAT_DVI_ADPCM (0x0011)
+//
+//
+
+typedef struct dvi_adpcmwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD wSamplesPerBlock;
+} DVIADPCMWAVEFORMAT;
+typedef DVIADPCMWAVEFORMAT *PDVIADPCMWAVEFORMAT;
+typedef DVIADPCMWAVEFORMAT NEAR *NPDVIADPCMWAVEFORMAT;
+typedef DVIADPCMWAVEFORMAT FAR *LPDVIADPCMWAVEFORMAT;
+
+
+//
+// IMA endorsed ADPCM structure definitions--note that this is exactly
+// the same format as Intel's DVI ADPCM.
+//
+// for WAVE_FORMAT_IMA_ADPCM (0x0011)
+//
+//
+
+typedef struct ima_adpcmwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD wSamplesPerBlock;
+} IMAADPCMWAVEFORMAT;
+typedef IMAADPCMWAVEFORMAT *PIMAADPCMWAVEFORMAT;
+typedef IMAADPCMWAVEFORMAT NEAR *NPIMAADPCMWAVEFORMAT;
+typedef IMAADPCMWAVEFORMAT FAR *LPIMAADPCMWAVEFORMAT;
+
+
+//
+// Speech Compression's Sonarc structure definitions
+//
+// for WAVE_FORMAT_SONARC (0x0021)
+//
+//
+
+typedef struct sonarcwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD wCompType;
+} SONARCWAVEFORMAT;
+typedef SONARCWAVEFORMAT *PSONARCWAVEFORMAT;
+typedef SONARCWAVEFORMAT NEAR *NPSONARCWAVEFORMAT;
+typedef SONARCWAVEFORMAT FAR *LPSONARCWAVEFORMAT;
+
+//
+// DSP Groups's TRUESPEECH structure definitions
+//
+// for WAVE_FORMAT_DSPGROUP_TRUESPEECH (0x0022)
+//
+//
+
+typedef struct truespeechwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD nSamplesPerBlock;
+} TRUESPEECHWAVEFORMAT;
+typedef TRUESPEECHWAVEFORMAT *PTRUESPEECHWAVEFORMAT;
+typedef TRUESPEECHWAVEFORMAT NEAR *NPTRUESPEECHWAVEFORMAT;
+typedef TRUESPEECHWAVEFORMAT FAR *LPTRUESPEECHWAVEFORMAT;
+
+
+
+//
+// Creative's ADPCM structure definitions
+//
+// for WAVE_FORMAT_CREATIVE_ADPCM (0x0200)
+//
+//
+
+typedef struct creative_adpcmwaveformat_tag {
+ WAVEFORMATEX wfx;
+ WORD wRevision;
+} CREATIVEADPCMWAVEFORMAT;
+typedef CREATIVEADPCMWAVEFORMAT *PCREATIVEADPCMWAVEFORMAT;
+typedef CREATIVEADPCMWAVEFORMAT NEAR *NPCREATIVEADPCMWAVEFORMAT;
+typedef CREATIVEADPCMWAVEFORMAT FAR *LPCREATIVEADPCMWAVEFORMAT;
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+// New RIFF WAVE Chunks
+//
+*/
+
+#define RIFFWAVE_inst mmioFOURCC('i','n','s','t')
+
+struct tag_s_RIFFWAVE_inst {
+ BYTE bUnshiftedNote;
+ char chFineTune;
+ char chGain;
+ BYTE bLowNote;
+ BYTE bHighNote;
+ BYTE bLowVelocity;
+ BYTE bHighVelocity;
+};
+
+typedef struct tag_s_RIFFWAVE_INST s_RIFFWAVE_inst;
+
+#endif
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+// New RIFF Forms
+//
+*/
+
+#ifndef NONEWRIFF
+
+/* RIFF AVI */
+
+//
+// AVI file format is specified in a seperate file (AVIFMT.H),
+// which is available from the sources listed in MSFTMM
+//
+
+/* RIFF CPPO */
+
+#define RIFFCPPO mmioFOURCC('C','P','P','O')
+
+#define RIFFCPPO_objr mmioFOURCC('o','b','j','r')
+#define RIFFCPPO_obji mmioFOURCC('o','b','j','i')
+
+#define RIFFCPPO_clsr mmioFOURCC('c','l','s','r')
+#define RIFFCPPO_clsi mmioFOURCC('c','l','s','i')
+
+#define RIFFCPPO_mbr mmioFOURCC('m','b','r',' ')
+
+#define RIFFCPPO_char mmioFOURCC('c','h','a','r')
+
+
+#define RIFFCPPO_byte mmioFOURCC('b','y','t','e')
+#define RIFFCPPO_int mmioFOURCC('i','n','t',' ')
+#define RIFFCPPO_word mmioFOURCC('w','o','r','d')
+#define RIFFCPPO_long mmioFOURCC('l','o','n','g')
+#define RIFFCPPO_dwrd mmioFOURCC('d','w','r','d')
+#define RIFFCPPO_flt mmioFOURCC('f','l','t',' ')
+#define RIFFCPPO_dbl mmioFOURCC('d','b','l',' ')
+#define RIFFCPPO_str mmioFOURCC('s','t','r',' ')
+
+
+#endif
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+// DIB Compression Defines
+//
+*/
+
+#ifndef BI_BITFIELDS
+#define BI_BITFIELDS 3
+#endif
+
+#ifndef QUERYDIBSUPPORT
+
+#define QUERYDIBSUPPORT 3073
+#define QDI_SETDIBITS 0x0001
+#define QDI_GETDIBITS 0x0002
+#define QDI_DIBTOSCREEN 0x0004
+#define QDI_STRETCHDIB 0x0008
+
+#endif
+
+
+/*//////////////////////////////////////////////////////////////////////////
+//
+// Defined IC types
+*/
+
+#ifndef NONEWIC
+
+#ifndef ICTYPE_VIDEO
+#define ICTYPE_VIDEO mmioFOURCC('v', 'i', 'd', 'c')
+#define ICTYPE_AUDIO mmioFOURCC('a', 'u', 'd', 'c')
+#endif
+
+#endif
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif /* RC_INVOKED */
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif /* __cplusplus */
+
+#endif /* _INC_MMREG */
diff --git a/private/mvdm/wow16/mmsystem/mmsex.c b/private/mvdm/wow16/mmsystem/mmsex.c
new file mode 100644
index 000000000..22317e630
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmsex.c
@@ -0,0 +1,483 @@
+/*
+** MMSEX.C
+**
+** Example applet DLL to be displayed by the Multimedia Control Panel.
+**
+** History:
+**
+** Wed Apr 18 1990 -by- MichaelE
+**
+*/
+
+#ifndef DEBUG
+ #define DEBUG
+#endif
+
+#include <windows.h>
+#include "mmsystem.h"
+#include <cpl.h>
+#include "mmsysi.h"
+#include "mmsex.dlg"
+
+LRESULT FAR PASCAL _loadds _export CPlApplet ( HWND, UINT, LPARAM, LPARAM );
+BOOL FAR PASCAL _loadds DebugDlg ( HWND, UINT, WPARAM, LPARAM );
+
+static SZCODE szMenuName[] = "mmse&x";
+static SZCODE szInfoName[] = "change mmsystem debug settings 1.01";
+static SZCODE szHelpFile[] = "";
+
+#define MAX_TYPE 7
+static SZCODE szTypes[] =
+ "???????\0" // 0
+ "WaveOut\0" // 1 TYPE_WAVEOUT
+ "WaveIn \0" // 2 TYPE_WAVEIN
+ "MidiOut\0" // 3 TYPE_MIDIOUT
+ "MidiIn \0" // 4 TYPE_MIDIIN
+ "mmio \0" // 5 TYPE_MMIO
+ "IOProc \0"; // 6 TYPE_IOPROC
+
+int nLoadedCount = 0;
+HDRVR hdrv;
+int iNumHandles = 0;
+
+/* This function is exported so CPL.EXE can do a GetProcAddress() on
+** the label and send the messages described below.
+** To make MMCPL.EXE load your DLL, and thus add your applets to its
+** window, add a keyname under the [MMCPL] application in
+** WIN.INI:
+**
+** [MMCPL]
+** myapplets=c:\mydir\applet.dll
+**
+** CPL.EXE loads the WIN3 Control Panel applets first, followed by the
+** applets named in WIN.INI, then those from the directory it was loaded,
+** and finally those in the WIN3 SYSTEM directory.
+**
+*/
+LRESULT FAR PASCAL _loadds _export CPlApplet(
+HWND hCPlWnd,
+UINT Msg,
+LPARAM lParam1,
+LPARAM lParam2)
+{
+ LPNEWCPLINFO lpCPlInfo;
+ int i;
+
+ switch( Msg )
+ {
+ case CPL_INIT:
+ if (!hdrv)
+ hdrv = OpenDriver("mmsystem.dll", NULL, 0);
+
+ if (!hdrv)
+ return (LRESULT)FALSE;
+
+// #if 0
+ if (!SendDriverMessage(hdrv, MM_GET_DEBUG, 0, 0))
+ {
+ CloseDriver(hdrv,0,0);
+ hdrv = NULL;
+ return (LRESULT)FALSE;
+ }
+// #endif
+ nLoadedCount++;
+
+ // first message to CPlApplet(), sent once only
+ return (LRESULT)TRUE;
+
+ case CPL_GETCOUNT:
+ // second message to CPlApplet(), sent once only
+ return (LRESULT)1;
+
+ case CPL_NEWINQUIRE:
+ /* third message to CPlApplet(). It is sent as many times
+ as the number of applets returned by CPL_GETCOUNT message
+ */
+ lpCPlInfo = (LPNEWCPLINFO)lParam2;
+
+ // lParam1 is an index ranging from 0 to (NUM_APPLETS-1)
+ i = (int)lParam1;
+
+ lpCPlInfo->dwSize = sizeof(NEWCPLINFO);
+ lpCPlInfo->dwFlags = 0;
+ lpCPlInfo->dwHelpContext = 0; // help context to use
+ lpCPlInfo->lData = 0; // user defined data
+ lpCPlInfo->hIcon = LoadIcon(ghInst, MAKEINTATOM(DLG_MMSEX));
+ lstrcpy(lpCPlInfo->szName, szMenuName);
+ lstrcpy(lpCPlInfo->szInfo, szInfoName);
+ lstrcpy(lpCPlInfo->szHelpFile, szHelpFile);
+
+ return (LRESULT)TRUE;
+
+ case CPL_SELECT:
+ /* One of your applets has been selected.
+ lParam1 is an index from 0 to (NUM_APPLETS-1)
+ lParam2 is the lData value associated with the applet
+ */
+ break;
+
+ case CPL_DBLCLK:
+ /* One of your applets has been double-clicked.
+ lParam1 is an index from 0 to (NUM_APPLETS-1)
+ lParam2 is the lData value associated with the applet
+ */
+ DialogBox(ghInst,MAKEINTRESOURCE(DLG_MMSEX),hCPlWnd,DebugDlg);
+ break;
+
+ case CPL_STOP:
+ /* Sent once for each applet prior to the CPL_EXIT msg.
+ lParam1 is an index from 0 to (NUM_APPLETS-1)
+ lParam2 is the lData value associated with the applet
+ */
+ break;
+
+ case CPL_EXIT:
+ /* Last message, sent once only, before MMCPL.EXE calls
+ FreeLibrary() on your DLL.
+ */
+ nLoadedCount--;
+
+ if (hdrv && !nLoadedCount)
+ {
+ CloseDriver(hdrv,0,0);
+ hdrv = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return( 0L );
+}
+
+int QueryRadioButton(HWND hdlg, int idFirst, int idLast)
+{
+ int id;
+
+ for (id=idFirst; id<=idLast; id++)
+ {
+ if (IsDlgButtonChecked(hdlg, id))
+ return id;
+ }
+
+ return 0;
+}
+
+#if 0 // API in win31
+
+BOOL NEAR PASCAL IsTask(HANDLE hTask)
+{
+_asm {
+; push si
+ mov ax,hTask
+ or ax,ax
+ jz error
+
+ lsl si,ax
+ jnz error
+
+ call GetCurrentTask
+ lsl ax,ax
+ cmp si,ax
+ je exit
+error:
+ xor ax,ax
+exit:
+; pop si
+}}
+
+#endif
+
+
+void NEAR PASCAL GetTaskName(HANDLE hTask, LPSTR pname)
+{
+ if (!IsTask(hTask))
+ {
+ lstrcpy(pname,"????");
+ }
+ else
+ {
+ ((LPDWORD)pname)[0] = ((LPDWORD)MAKELONG(0xF2,hTask))[0];
+ ((LPDWORD)pname)[1] = ((LPDWORD)MAKELONG(0xF2,hTask))[1];
+ pname[8] = 0;
+ }
+}
+
+#define SLASH(c) ((c) == '/' || (c) == '\\')
+
+LPSTR FileName(LPSTR szPath)
+{
+ LPSTR sz;
+
+ for (sz=szPath; *sz; sz++)
+ ;
+ for (; sz>=szPath && !SLASH(*sz) && *sz!=':'; sz--)
+ ;
+ return ++sz;
+}
+
+int fQuestion(LPSTR sz,...)
+{
+ char ach[128];
+
+ wvsprintf (ach,sz,(LPSTR)(&sz+1)); /* Format the string */
+ return MessageBox(NULL,ach,"mmsex",MB_YESNO|MB_ICONQUESTION|MB_TASKMODAL);
+}
+
+void GetHandles(HWND hdlg)
+{
+ HLOCAL h;
+ HTASK hTask;
+ DWORD wType;
+ UINT n;
+ int i;
+ UINT j;
+ int iSel;
+ char ach[80];
+ char szTask[80];
+ char szName[80];
+ HWND hlb;
+
+ iNumHandles=0;
+
+ hlb = GetDlgItem(hdlg, ID_HANDLES);
+
+ iSel = (int)SendMessage(hlb,LB_GETCURSEL,0,0L);
+ SendMessage(hlb, WM_SETREDRAW, (WPARAM)FALSE, 0);
+ SendMessage(hlb, LB_RESETCONTENT, 0, 0);
+
+ //
+ // fill listbox with all active handles in system
+ //
+ for (h = (HLOCAL)(LONG)SendDriverMessage(hdrv, MM_HINFO_NEXT, NULL, 0);
+ h;
+ h = (HLOCAL)(LONG)SendDriverMessage(hdrv, MM_HINFO_NEXT, (LPARAM)(LONG)(UINT)h, 0) )
+ {
+ iNumHandles++;
+
+ wType = (UINT)SendDriverMessage(hdrv, MM_HINFO_TYPE, (LPARAM)(LONG)(UINT)h, 0);
+ hTask = (HTASK)(LONG)SendDriverMessage(hdrv, MM_HINFO_TASK, (LPARAM)(LONG)(UINT)h, 0);
+
+ if (wType >= MAX_TYPE)
+ wType = 0;
+
+ GetTaskName(hTask, szTask);
+
+ wsprintf(ach, "%ls %04X %ls",(LPSTR)szTypes + wType*(sizeof(szTypes)-1)/MAX_TYPE,h,(LPSTR)szTask);
+
+ i = (int)(LONG)SendMessage(hlb, LB_ADDSTRING, 0, (LPARAM)(LPSTR)ach);
+ SendMessage(hlb, LB_SETITEMDATA, (WPARAM)i, MAKELPARAM(h, wType));
+ }
+
+ //
+ // add to that all MCI handles
+ //
+ n = (UINT)(LONG)SendDriverMessage(hdrv, MM_HINFO_MCI, 0, 0);
+
+ for (j = 1; j < n; j++)
+ {
+ MCI_DEVICE_NODE node;
+
+ if (!SendDriverMessage(hdrv, MM_HINFO_MCI, (LPARAM)j, (LPARAM)(LPVOID)&node))
+ continue;
+
+ iNumHandles++;
+
+ if (node.lpstrName == NULL)
+ node.lpstrName = "";
+ if (node.lpstrInstallName == NULL)
+ node.lpstrInstallName = "";
+
+ GetTaskName(node.hCreatorTask, szTask);
+ wsprintf(ach, "mci %04X %ls %ls %ls",j,(LPSTR)szTask,node.lpstrInstallName,node.lpstrName);
+
+ i = (int)(LONG)SendMessage(hlb, LB_ADDSTRING, 0, (LPARAM)(LPSTR)ach);
+ SendMessage(hlb, LB_SETITEMDATA, (WPARAM)i, MAKELPARAM(j, TYPE_MCI));
+ }
+
+ //
+ // add to that all DRV handles
+ //
+ for (h=GetNextDriver(NULL, 0); h; h=GetNextDriver(h, 0))
+ {
+ if (GetDriverModuleHandle(h))
+ {
+ DRIVERINFOSTRUCT di;
+
+ di.length = sizeof(di);
+ di.szAliasName[0] = 0;
+ GetDriverInfo(h, &di);
+
+ iNumHandles++;
+
+ GetModuleFileName(GetDriverModuleHandle(h), szName, sizeof(szName));
+
+ wsprintf(ach, "Driver %04X %ls (%ls)",h,(LPSTR)di.szAliasName,(LPSTR)FileName(szName));
+ i = (int)(LONG)SendDlgItemMessage(hdlg, ID_HANDLES, LB_ADDSTRING, 0, (LPARAM)(LPSTR)ach);
+ SendDlgItemMessage(hdlg, ID_HANDLES, LB_SETITEMDATA, (WPARAM)i, MAKELPARAM(h,TYPE_DRVR));
+ }
+ }
+
+ SendMessage(hlb,LB_SETCURSEL,(WPARAM)iSel,0L);
+ SendMessage(hlb,WM_SETREDRAW,(WPARAM)TRUE,0);
+ InvalidateRect(hlb, NULL, TRUE);
+}
+
+int CountHandles(void)
+{
+ HLOCAL h;
+ int cnt=0;
+ UINT n;
+ UINT j;
+
+ for (h = (HLOCAL)(LONG)SendDriverMessage(hdrv, MM_HINFO_NEXT, NULL, 0);
+ h;
+ h = (HLOCAL)(LONG)SendDriverMessage(hdrv, MM_HINFO_NEXT, (LPARAM)(LONG)(UINT)h, 0) )
+ {
+ cnt++;
+ }
+
+ n = (UINT)(LONG)SendDriverMessage(hdrv, MM_HINFO_MCI, 0, 0);
+
+ for (j=1; j<n; j++)
+ {
+ MCI_DEVICE_NODE node;
+
+ if (!SendDriverMessage(hdrv, MM_HINFO_MCI, (LPARAM)j, (LPARAM)(LPVOID)&node))
+ continue;
+
+ cnt++;
+ }
+
+ for (h=GetNextDriver(NULL,0); h; h=GetNextDriver(h, 0))
+ {
+ if (GetDriverModuleHandle(h))
+ cnt++;
+ }
+
+ return cnt;
+}
+
+void CloseHandle(DWORD dw)
+{
+ HLOCAL h;
+ h = (HLOCAL)LOWORD(dw);
+
+ switch(HIWORD(dw))
+ {
+ case TYPE_WAVEOUT:
+ if (IDYES == fQuestion("Close WaveOut handle %04X?",h))
+ {
+ waveOutReset(h);
+ waveOutClose(h);
+ }
+ break;
+ case TYPE_WAVEIN:
+ if (IDYES == fQuestion("Close WaveIn handle %04X?",h))
+ {
+ waveInStop(h);
+ waveInClose(h);
+ }
+ break;
+ case TYPE_MIDIOUT:
+ if (IDYES == fQuestion("Close MidiOut handle %04X?",h))
+ {
+ midiOutReset(h);
+ midiOutClose(h);
+ }
+ break;
+ case TYPE_MIDIIN:
+ if (IDYES == fQuestion("Close MidiIn handle %04X?",h))
+ {
+ midiInStop(h);
+ midiInClose(h);
+ }
+ break;
+ case TYPE_MCI:
+ if (IDYES == fQuestion("Close Mci device %04X?",h))
+ {
+ mciSendCommand((UINT)h, MCI_CLOSE, 0, 0);
+ }
+ break;
+ case TYPE_MMIO:
+ if (IDYES == fQuestion("Close MMIO handle %04X?",h))
+ {
+ mmioClose(h,MMIO_FHOPEN);
+ }
+ break;
+ case TYPE_DRVR:
+ break;
+ }
+}
+
+
+BOOL FAR PASCAL _loadds DebugDlg(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DWORD dw;
+ int i;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_ADDSTRING, 0, (LONG)(LPSTR)"(none)");
+ SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_ADDSTRING, 0, (LONG)(LPSTR)"COM1:");
+ SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_ADDSTRING, 0, (LONG)(LPSTR)"Mono Monitor");
+ SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_ADDSTRING, 0, (LONG)(LPSTR)"Windows");
+
+ SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_SETCURSEL, (int)(LONG)SendDriverMessage(hdrv, MM_GET_DEBUGOUT, 0, 0), 0L);
+
+ CheckDlgButton(hdlg, ID_DEBUG_MCI, (int)(LONG)SendDriverMessage(hdrv, MM_GET_MCI_DEBUG, 0, 0));
+ CheckDlgButton(hdlg, ID_DEBUG_MMSYS, (int)(LONG)SendDriverMessage(hdrv, MM_GET_MM_DEBUG, 0, 0));
+
+ iNumHandles = CountHandles();
+ GetHandles(hdlg);
+
+ SetTimer(hdlg, 500, 500, NULL);
+ return TRUE;
+
+ case WM_TIMER:
+ i = CountHandles();
+ if (iNumHandles != i)
+ {
+ iNumHandles = i;
+ GetHandles(hdlg);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch ((UINT)wParam)
+ {
+ case IDOK:
+ SendDriverMessage(hdrv, MM_SET_DEBUGOUT,
+ (LPARAM)SendDlgItemMessage(hdlg, ID_DEBUG_OUT, CB_GETCURSEL, 0, 0), 0);
+
+ SendDriverMessage(hdrv, MM_SET_MCI_DEBUG,
+ (LPARAM)IsDlgButtonChecked(hdlg, ID_DEBUG_MCI),0);
+
+ SendDriverMessage(hdrv, MM_SET_MM_DEBUG,
+ (LPARAM)IsDlgButtonChecked(hdlg, ID_DEBUG_MMSYS),0);
+
+ // fall through
+ case IDCANCEL:
+ EndDialog(hdlg, wParam);
+ break;
+
+ case ID_RESTART:
+ SendDriverMessage(hdrv, MM_DRV_RESTART, 0, 0);
+ break;
+
+ case ID_HANDLES:
+ if (HIWORD(lParam) != LBN_DBLCLK)
+ break;
+
+ i = (int)(LONG)SendDlgItemMessage(hdlg,wParam,LB_GETCURSEL,0,0L);
+ dw = (DWORD)SendDlgItemMessage(hdlg,wParam,LB_GETITEMDATA,(WPARAM)i,0L);
+
+ CloseHandle(dw);
+ GetHandles(hdlg);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/private/mvdm/wow16/mmsystem/mmsex.dlg b/private/mvdm/wow16/mmsystem/mmsex.dlg
new file mode 100644
index 000000000..dc61a7837
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmsex.dlg
@@ -0,0 +1,39 @@
+#define ID_DEBUG_OUT 100
+#define ID_DEBUG_MCI 200
+#define ID_DEBUG_MMSYS 201
+#define ID_HANDLES 300
+#define ID_RESTART 301
+
+#define DLG_MMSEX 400
+
+#ifdef RC_INVOKED
+
+DLG_MMSEX ICON MOVEABLE DISCARDABLE LOADONCALL MMSEX.ICO
+
+DLG_MMSEX DIALOG 39, 26, 205, 160
+STYLE DS_MODALFRAME | DS_NOIDLEMSG | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "MMSYSTEM"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "Ok", IDOK, 155, 3, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 155, 19, 40, 14
+ PUSHBUTTON "&Restart", ID_RESTART, 155, 36, 40, 14
+
+ LTEXT "&Handles", -1, 6, 46, 106, 8
+ LISTBOX ID_HANDLES, 6, 58, 194, 98, LBS_NOINTEGRALHEIGHT |
+ WS_VSCROLL | WS_TABSTOP
+
+ LTEXT "Debug &Output:", -1, 7, 7, 54, 8
+ COMBOBOX ID_DEBUG_OUT, 63, 4, 77, 59, CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+
+ CONTROL "MM&SYS Debug", ID_DEBUG_MMSYS, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 6, 19, 81, 10
+
+ CONTROL "&MCI debugging", ID_DEBUG_MCI, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 6, 32, 83, 10
+
+ ICON DLG_MMSEX, -1, 91, 21, 18, 20
+END
+
+#endif
diff --git a/private/mvdm/wow16/mmsystem/mmsex.ico b/private/mvdm/wow16/mmsystem/mmsex.ico
new file mode 100644
index 000000000..163aed3a4
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmsex.ico
Binary files differ
diff --git a/private/mvdm/wow16/mmsystem/mmsysi.h b/private/mvdm/wow16/mmsystem/mmsysi.h
new file mode 100644
index 000000000..86265d240
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmsysi.h
@@ -0,0 +1,557 @@
+/*
+ mmsysi.h
+
+ private include file for mm kitchen sink
+
+*/
+
+#include <logerror.h>
+
+#ifdef DEBUG
+ #define DEBUG_RETAIL
+#endif
+
+#define WinFlags (WORD)(&__WinFlags)
+extern short pascal __WinFlags;
+
+extern HINSTANCE ghInst;
+
+// Define the product version to be returned from
+// mmsystemgetversion and any other messagebox or
+// API that needs the public product version.
+
+#define MMSYSTEM_VERSION 0X0101
+
+#define MM_SND_PLAY (WM_MM_RESERVED_FIRST+0x2B)
+
+/* -------------------------------------------------------------------------
+** Thunking stuff
+** -------------------------------------------------------------------------
+*/
+DWORD
+mciAppExit(
+ HTASK hTask
+ );
+
+/****************************************************************************
+
+ external interupt time data (in INTDS)
+
+ this global data is in the FIXED DATA SEGMENT.
+
+****************************************************************************/
+
+extern WORD FAR PASCAL gwStackFrames; // in STACK.ASM
+extern WORD FAR PASCAL gwStackSize; // in STACK.ASM
+extern HGLOBAL FAR PASCAL gwStackSelector; // in STACK.ASM
+extern WORD FAR PASCAL gwStackUse; // in STACK.ASM
+extern HLOCAL FAR PASCAL hdrvDestroy; // in STACK.ASM
+extern HDRVR FAR PASCAL hTimeDrv; // in TIMEA.ASM
+extern FARPROC FAR PASCAL lpTimeMsgProc; // in TIMEA.ASM
+extern WORD FAR PASCAL fDebugOutput; // in COMM.ASM
+
+/****************************************************************************
+
+KERNEL APIs we use that are not in WINDOWS.H
+
+****************************************************************************/
+
+//extern long WINAPI _hread(HFILE, void _huge*, long);
+//extern long WINAPI _hwrite(HFILE, const void _huge*, long);
+
+extern UINT FAR PASCAL LocalCountFree(void);
+extern UINT FAR PASCAL LocalHeapSize(void);
+
+/****************************************************************************
+
+ API to install/remove a MMSYS driver
+
+****************************************************************************/
+
+#define MMDRVI_TYPE 0x000F // low 4 bits give driver type
+#define MMDRVI_WAVEIN 0x0001
+#define MMDRVI_WAVEOUT 0x0002
+#define MMDRVI_MIDIIN 0x0003
+#define MMDRVI_MIDIOUT 0x0004
+#define MMDRVI_AUX 0x0005
+
+#define MMDRVI_MAPPER 0x8000 // install this driver as the mapper
+#define MMDRVI_HDRV 0x4000 // hDriver is a installable driver
+#define MMDRVI_REMOVE 0x2000 // remove the driver
+
+// generic prototype for audio device driver entry-point functions
+// midMessage(), modMessage(), widMessage(), wodMessage(), auxMessage()
+typedef DWORD (CALLBACK *DRIVERMSGPROC)(UINT wDeviceID, UINT message, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+
+BOOL WINAPI mmDrvInstall(HANDLE hDriver, DRIVERMSGPROC *drvMessage, UINT wFlags);
+HDRVR NEAR PASCAL mmDrvOpen( LPSTR szAlias );
+
+/****************************************************************************
+****************************************************************************/
+
+//
+// exclude some stuff if MMDDK.H is not included
+//
+#ifdef MMDDKINC // use this to test for MMDDK.H
+
+ //
+ // note this must be the same as MIDIDRV/WAVEDRV/AUXDRV
+ //
+ typedef struct {
+ HDRVR hDriver; // handle to the module
+ DRIVERMSGPROC drvMessage; // pointer to entry point
+ BYTE bNumDevs; // number of devices supported
+ BYTE bUsage; // usage count (number of handle's open)
+ } MMDRV, *PMMDRV;
+
+ #ifndef MMNOMIDI
+
+ typedef MMDRV MIDIDRV, *PMIDIDRV;
+
+
+ #endif //ifndef MMNOMIDI
+
+ #ifndef MMNOWAVE
+
+ typedef MMDRV WAVEDRV, *PWAVEDRV;
+
+ //
+ // Wave Mapper support
+ //
+ extern LPSOUNDDEVMSGPROC PASCAL wodMapper;
+ extern LPSOUNDDEVMSGPROC PASCAL widMapper;
+
+ #endif //ifndef MMNOWAVE
+
+ #ifndef MMNOAUX
+
+ typedef MMDRV AUXDRV, *PAUXDRV;
+
+ #endif //ifndef MMNOAUX
+
+ #ifdef DEBUG_RETAIL
+ extern BYTE fIdReverse;
+ #endif //ifdef DEBUG_RETAIL
+
+#endif //ifdef MMDDKINC
+
+/****************************************************************************
+
+ prototypes
+
+****************************************************************************/
+
+BOOL FAR PASCAL JoyInit(void);
+BOOL NEAR PASCAL TimeInit(void);
+
+BOOL NEAR PASCAL MCIInit(void);
+void NEAR PASCAL MCITerminate(void);
+
+BOOL FAR PASCAL StackInit(void); // in init.c
+
+#define IDS_TASKSTUB 2000
+#define STR_MCIUNKNOWN 2001
+//#define STR_WAVEINPUT 2004
+//#define STR_WAVEOUTPUT 2005
+//#define STR_MIDIINPUT 2006
+//#define STR_MIDIOUTPUT 2007
+#ifdef DEBUG
+#define STR_MCISSERRTXT 2009
+#define STR_MCISCERRTXT 2010
+#endif
+
+#define MAXPATHLEN 157 // 144 chars + "\12345678.123"
+
+BOOL FAR PASCAL HugePageLock(LPVOID lpArea, DWORD dwLength);
+void FAR PASCAL HugePageUnlock(LPVOID lpArea, DWORD dwLength);
+
+/****************************************************************************
+
+ MMSYSTEM global notify window
+
+****************************************************************************/
+
+extern HWND hwndNotify; // in MMWND.C
+
+BOOL NEAR PASCAL WndInit(void); // in MMWND.C
+void NEAR PASCAL WndTerminate(void); // in MMWND.C
+
+void FAR PASCAL MciNotify(WPARAM wParam, LPARAM lParam); // in MCI.C
+void FAR PASCAL WaveOutNotify(WPARAM wParam, LPARAM lParam);// in PLAYWAV.C
+BOOL FAR PASCAL sndPlaySoundI(LPCSTR lszSoundName, UINT wFlags);// in SOUND.C
+BOOL FAR PASCAL sndMessage(LPSTR lszSoundName, UINT wFlags);// in SOUND.C
+
+/****************************************************************************
+
+ MCI allocation stuff
+
+****************************************************************************/
+
+extern HGLOBAL FAR PASCAL HeapCreate(int cbSize);
+extern void FAR PASCAL HeapDestroy(HGLOBAL hHeap);
+extern LPVOID FAR PASCAL HeapAlloc(HGLOBAL hHeap, int cbSize);
+extern LPVOID FAR PASCAL HeapReAlloc(LPVOID lp, int cbSize);
+extern void FAR PASCAL HeapFree(LPVOID lp);
+
+extern HGLOBAL hMciHeap; // in MCISYS.C
+
+#define BMCIHEAP _based((_segment)hMciHeap)
+
+#define mciAlloc(cb) HeapAlloc(hMciHeap, cb)
+#define mciReAlloc(lp, size) HeapReAlloc (lp, size)
+#define mciFree(lp) HeapFree(lp)
+
+/****************************************************************************
+
+ strings
+
+****************************************************************************/
+
+#define SZCODE char _based(_segname("_CODE"))
+
+/****************************************************************************
+
+ handle apis's
+
+****************************************************************************/
+
+//
+// all MMSYSTEM handles are tagged with the following structure.
+//
+// a MMSYSTEM handle is really a fixed local memory object.
+//
+// the functions NewHandle() and FreeHandle() create and release a MMSYSTEM
+// handle.
+//
+//
+//**************************************************************************;
+// IF YOU CHANGE THIS STRUCTURE YOU MUST ALSO CHANGE THE ONE IN DEBUG.ASM
+//**************************************************************************;
+typedef struct tagHNDL {
+ struct tagHNDL *pNext; // link to next handle
+ WORD wType; // type of handle wave, midi, mmio, ...
+ HTASK hTask; // task that owns it
+} HNDL, NEAR *PHNDL;
+//**************************************************************************;
+
+#define HtoPH(h) ((PHNDL)(h)-1)
+#define PHtoH(ph) ((ph) ? (HLOCAL)((PHNDL)(ph)+1) : 0)
+
+//
+// all wave and midi handles will be linked into
+// a global list, so we can enumerate them latter if needed.
+//
+// all handle structures start with a HNDL structure, that contain common fields
+//
+// pHandleList points to the first handle in the list
+//
+// the NewHandle() and FreeHandle() functions are used to add/remove
+// a handle to/from the list
+//
+extern PHNDL pHandleList;
+
+extern HLOCAL FAR PASCAL NewHandle(WORD wType, WORD size);
+extern HLOCAL FAR PASCAL FreeHandle(HLOCAL h);
+
+#define GetHandleType(h) (HtoPH(h)->wType)
+#define GetHandleOwner(h) (HtoPH(h)->hTask)
+#define GetHandleFirst() (PHtoH(pHandleList))
+#define GetHandleNext(h) (PHtoH(HtoPH(h)->pNext))
+#define SetHandleOwner(h,hOwn) (HtoPH(h)->hTask = (hOwn))
+
+/****************************************************************************
+
+ debug support
+
+****************************************************************************/
+
+#if 1 // was #ifdef DEBUG_RETAIL
+
+#define MM_GET_DEBUG DRV_USER
+#define MM_GET_DEBUGOUT DRV_USER+1
+#define MM_SET_DEBUGOUT DRV_USER+2
+#define MM_GET_MCI_DEBUG DRV_USER+3
+#define MM_SET_MCI_DEBUG DRV_USER+4
+#define MM_GET_MM_DEBUG DRV_USER+5
+#define MM_SET_MM_DEBUG DRV_USER+6
+
+#define MM_HINFO_NEXT DRV_USER+10
+#define MM_HINFO_TASK DRV_USER+11
+#define MM_HINFO_TYPE DRV_USER+12
+#define MM_HINFO_MCI DRV_USER+20
+
+#define MM_DRV_RESTART DRV_USER+30
+
+//
+// these validation routines can be found in DEBUG.ASM
+//
+extern BOOL FAR PASCAL ValidateHandle(HANDLE h, WORD wType);
+extern BOOL FAR PASCAL ValidateHeader(const void FAR* p, UINT wSize, WORD wType);
+extern BOOL FAR PASCAL ValidateReadPointer(const void FAR* p, DWORD len);
+extern BOOL FAR PASCAL ValidateWritePointer(const void FAR* p, DWORD len);
+extern BOOL FAR PASCAL ValidateDriverCallback(DWORD dwCallback, UINT wFlags);
+extern BOOL FAR PASCAL ValidateCallback(FARPROC lpfnCallback);
+extern BOOL FAR PASCAL ValidateString(LPCSTR lsz, UINT max_len);
+
+#ifndef MMNOTIMER
+extern BOOL FAR PASCAL ValidateTimerCallback(LPTIMECALLBACK lpfn);
+#endif
+
+#define V_HANDLE(h, t, r) { if (!ValidateHandle(h, t)) return (r); }
+#define V_HEADER(p, w, t, r) { if (!ValidateHeader((p), (w), (t))) return (r); }
+#define V_RPOINTER(p, l, r) { if (!ValidateReadPointer((p), (l))) return (r); }
+#define V_RPOINTER0(p, l, r) { if ((p) && !ValidateReadPointer((p), (l))) return (r); }
+#define V_WPOINTER(p, l, r) { if (!ValidateWritePointer((p), (l))) return (r); }
+#define V_WPOINTER0(p, l, r) { if ((p) && !ValidateWritePointer((p), (l))) return (r); }
+#define V_DCALLBACK(d, w, r) { if (!ValidateDriverCallback((d), (w))) return (r); }
+#define V_TCALLBACK(d, r) { if (!ValidateTimerCallback((d))) return (r); }
+#define V_CALLBACK(f, r) { if (!ValidateCallback(f)) return (r); }
+#define V_CALLBACK0(f, r) { if ((f) && !ValidateCallback(f)) return (r); }
+#define V_STRING(s, l, r) { if (!ValidateString(s,l)) return (r); }
+#define V_FLAGS(t, b, f, r) { if ((t) & ~(b)) {LogParamError(ERR_BAD_FLAGS, (FARPROC)(f), (LPVOID)(DWORD)(t)); return (r); }}
+
+#else //ifdef DEBUG_RETAIL
+
+#define V_HANDLE(h, t, r) { if (!(h)) return (r); }
+#define V_HEADER(p, w, t, r) { if (!(p)) return (r); }
+#define V_RPOINTER(p, l, r) { if (!(p)) return (r); }
+#define V_RPOINTER0(p, l, r) 0
+#define V_WPOINTER(p, l, r) { if (!(p)) return (r); }
+#define V_WPOINTER0(p, l, r) 0
+#define V_DCALLBACK(d, w, r) 0
+#define V_TCALLBACK(d, r) 0
+#define V_CALLBACK(f, r) { if (!(f)) return (r); }
+#define V_CALLBACK0(f, r) 0
+#define V_STRING(s, l, r) { if (!(s)) return (r); }
+#define V_FLAGS(t, b, f, r) 0
+
+#endif //ifdef DEBUG_RETAIL
+
+//**************************************************************************;
+// IF YOU CHANGE THESE TYPES YOU MUST ALSO CHANGE THE ONES IN DEBUG.ASM
+//**************************************************************************;
+#define TYPE_WAVEOUT 1
+#define TYPE_WAVEIN 2
+#define TYPE_MIDIOUT 3
+#define TYPE_MIDIIN 4
+#define TYPE_MMIO 5
+#define TYPE_IOPROC 6
+#define TYPE_MCI 7
+#define TYPE_DRVR 8
+#define TYPE_MIXER 9
+//**************************************************************************;
+
+/****************************************************************************
+
+ support for debug output
+
+****************************************************************************/
+
+#ifdef DEBUG_RETAIL
+
+ #define ROUT(sz) {static SZCODE ach[] = sz; DebugOutput(DBF_TRACE | DBF_MMSYSTEM, ach); }
+ #define ROUTS(sz) {DebugOutput(DBF_TRACE | DBF_MMSYSTEM, sz);}
+ #define DebugErr(flags, sz) {static SZCODE ach[] = "MMSYSTEM: "sz; DebugOutput((flags) | DBF_MMSYSTEM, ach); }
+ #define DebugErr1(flags, sz, a) {static SZCODE ach[] = "MMSYSTEM: "sz; DebugOutput((flags) | DBF_MMSYSTEM, ach,a); }
+ #define DebugErr2(flags, sz, a, b) {static SZCODE ach[] = "MMSYSTEM: "sz; DebugOutput((flags) | DBF_MMSYSTEM, ach,a,b); }
+
+ #define RPRINTF1(sz,x) {static SZCODE ach[] = sz; DebugOutput(DBF_TRACE | DBF_MMSYSTEM, ach, x); }
+ #define RPRINTF2(sz,x,y) {static SZCODE ach[] = sz; DebugOutput(DBF_TRACE | DBF_MMSYSTEM, ach, x, y); }
+
+#else //ifdef DEBUG_RETAIL
+
+ #define ROUT(sz)
+ #define ROUTS(sz)
+ #define DebugErr(flags, sz)
+ #define DebugErr1(flags, sz, a)
+ #define DebugErr2(flags, sz, a, b)
+
+ #define RPRINTF1(sz,x)
+ #define RPRINTF2(sz,x,y)
+
+#endif //ifdef DEBUG_RETAIL
+
+#ifdef DEBUG
+
+ extern void FAR cdecl dprintf(LPSTR, ...); // in COMM.ASM
+ extern void FAR PASCAL dout(LPSTR); // in COMM.ASM
+
+ #define DOUT(sz) {static SZCODE buf[] = sz; dout(buf); }
+ #define DOUTS(sz) dout(sz);
+ #define DPRINTF(x) dprintf x
+ #define DPRINTF1(sz,a) {static SZCODE buf[] = sz; dprintf(buf, a); }
+ #define DPRINTF2(sz,a,b) {static SZCODE buf[] = sz; dprintf(buf, a, b); }
+
+#else //ifdef DEBUG
+
+ #define DOUT(sz) 0
+ #define DOUTS(sz) 0
+ #define DPRINTF(x) 0
+ #define DPRINTF1(sz,a) 0
+ #define DPRINTF2(sz,a,b) 0
+
+#endif //ifdef DEBUG
+
+#ifndef MMNOMCI
+/****************************************************************************
+
+ Internal MCI stuff
+
+****************************************************************************/
+
+#define MCI_VALID_DEVICE_ID(wID) ((wID) > 0 && (wID) < MCI_wNextDeviceID && MCI_lpDeviceList[wID])
+
+#define MCI_MAX_PARAM_SLOTS 30
+
+#define MCI_TOLOWER(c) ((char)((c) >= 'A' && (c) <= 'Z' ? (c) + 0x20 : (c)))
+
+typedef struct
+{
+ HGLOBAL hResource;
+ HINSTANCE hModule; // If not NULL then free module
+ // when device is free'd
+ UINT wType;
+ UINT FAR * lpwIndex;
+ LPSTR lpResource;
+#ifdef DEBUG
+ WORD wLockCount; // Used for debugging
+#endif //ifdef DEBUG
+} command_table_type;
+
+#define MCINODE_ISCLOSING 0x00000001 // Lock out all cmd's during close
+#define MCINODE_ISAUTOCLOSING 0x00010000 // Lock out all cmd's during close
+ // except internally generated close
+#define MCINODE_ISAUTOOPENED 0x00020000 // Device was auto opened
+#define MCINODE_16BIT_DRIVER 0x80000000 // Device is a 16-bit driver
+
+typedef struct {
+ LPSTR lpstrName; // The name used in subsequent calls to
+ // mciSendString to refer to the device
+ LPSTR lpstrInstallName;// The device name from system.ini
+ DWORD dwMCIOpenFlags; // Flags set on open may be:
+ DWORD lpDriverData; // DWORD of driver instance data
+ DWORD dwElementID; // The element ID set by MCI_OPEN_ELEMENT_ID
+ YIELDPROC fpYieldProc; // The current yield procedure if any
+ DWORD dwYieldData; // Data send to the current yield procedure
+ UINT wDeviceID; // The ID used in subsequent calls to
+ // mciSendCommand to refer to the device
+ UINT wDeviceType; // The type returned from the DRV_OPEN call
+ // MCI_OPEN_SHAREABLE
+ // MCI_OPEN_ELEMENT_ID
+ UINT wCommandTable; // The device type specific command table
+ UINT wCustomCommandTable; // The custom device command table if any
+ //(-1 if none)
+ HINSTANCE hDriver; // Module instance handle for the driver
+ HTASK hCreatorTask; // The task context the device is in
+ HTASK hOpeningTask; // The task context which send the open command
+ HDRVR hDrvDriver; // The installable driver handle
+ DWORD dwMCIFlags; // Internal MCI flags
+} MCI_DEVICE_NODE;
+
+typedef MCI_DEVICE_NODE FAR *LPMCI_DEVICE_NODE;
+typedef MCI_DEVICE_NODE BMCIHEAP *PMCI_DEVICE_NODE;
+
+typedef struct {
+ LPSTR lpstrParams;
+ LPSTR FAR * lpstrPointerList;
+ HTASK hCallingTask;
+ UINT wParsingError;
+} MCI_INTERNAL_OPEN_INFO;
+typedef MCI_INTERNAL_OPEN_INFO FAR *LPMCI_INTERNAL_OPEN_INFO;
+
+typedef struct {
+ LPSTR lpstrCommand;
+ LPSTR lpstrReturnString;
+ UINT wReturnLength;
+ HTASK hCallingTask;
+ LPSTR lpstrNewDirectory; // The current directory of the calling
+ // task
+ int nNewDrive; // The current drive of the calling task
+} MCI_SYSTEM_MESSAGE;
+typedef MCI_SYSTEM_MESSAGE FAR *LPMCI_SYSTEM_MESSAGE;
+
+#define MCI_INIT_DEVICE_LIST_SIZE 4
+#define MCI_DEVICE_LIST_GROW_SIZE 4
+
+#define MAX_COMMAND_TABLES 20
+
+extern BOOL MCI_bDeviceListInitialized;
+
+extern LPMCI_DEVICE_NODE FAR *MCI_lpDeviceList;
+extern UINT MCI_wDeviceListSize;
+
+extern UINT MCI_wNextDeviceID; // the next device ID to use for a new device
+
+extern command_table_type command_tables[MAX_COMMAND_TABLES];
+
+// In mciparse.c
+extern void PASCAL NEAR mciToLower (LPSTR lpstrString);
+
+extern UINT NEAR PASCAL mciLoadTableType(UINT wType);
+
+extern LPSTR PASCAL NEAR FindCommandInTable (UINT wTable, LPCSTR lpstrCommand,
+ UINT FAR * lpwMessage);
+
+extern LPSTR PASCAL NEAR FindCommandItem (UINT wDeviceID, LPCSTR lpstrType,
+ LPCSTR lpstrCommand, UINT FAR * lpwMessage,
+ UINT FAR* lpwTable);
+
+extern UINT PASCAL NEAR mciEatToken (LPCSTR FAR *lplpstrInput, char cSeparater,
+ LPSTR FAR *lplpstrOutput, BOOL bMustFind);
+
+extern UINT PASCAL NEAR mciParseParams (LPCSTR lpstrParams,
+ LPCSTR lpCommandList,
+ LPDWORD lpdwFlags,
+ LPSTR lpOutputParams,
+ UINT wParamsSize,
+ LPSTR FAR * FAR * lpPointerList,
+ UINT FAR* lpwParsingError);
+
+extern void NEAR PASCAL mciParserFree (LPSTR FAR *lpstrPointerList);
+
+extern UINT NEAR PASCAL mciEatCommandEntry(LPCSTR lpEntry, LPDWORD lpValue,
+ UINT FAR* lpID);
+
+extern UINT NEAR PASCAL mciParseCommand (UINT wDeviceID,
+ LPSTR lpstrCommand,
+ LPCSTR lpstrDeviceName,
+ LPSTR FAR * lpCommandList,
+ UINT FAR* lpwTable);
+
+extern UINT PASCAL NEAR mciGetParamSize (DWORD dwValue, UINT wID);
+
+extern BOOL PASCAL NEAR mciUnlockCommandTable (UINT wCommandTable);
+
+// In mcisys.c
+extern BOOL NEAR PASCAL mciInitDeviceList(void);
+
+extern UINT NEAR PASCAL mciOpenDevice(DWORD dwFlags,
+ LPMCI_OPEN_PARMS lpOpenParms,
+ LPMCI_INTERNAL_OPEN_INFO lpOpenInfo);
+
+extern UINT NEAR PASCAL mciCloseDevice(UINT wID, DWORD dwFlags,
+ LPMCI_GENERIC_PARMS lpGeneric,
+ BOOL bCloseDriver);
+
+extern UINT NEAR PASCAL mciExtractTypeFromID (LPMCI_OPEN_PARMS lpOpen);
+
+extern DWORD PASCAL NEAR mciSysinfo (UINT wDeviceID, DWORD dwFlags,
+ LPMCI_SYSINFO_PARMS lpSysinfo);
+
+extern UINT PASCAL NEAR mciLookUpType (LPCSTR lpstrTypeName);
+
+extern BOOL PASCAL NEAR mciExtractDeviceType (LPCSTR lpstrDeviceName,
+ LPSTR lpstrDeviceType,
+ UINT wBufLen);
+
+extern UINT NEAR PASCAL mciSetBreakKey (UINT wDeviceID, int nVirtKey, HWND hwndTrap);
+
+extern UINT NEAR PASCAL mciGetDeviceIDInternal (LPCSTR lpstrName, HTASK hTask);
+
+extern BOOL NEAR PASCAL Is16bitDrv(UINT wDeviceID);
+extern BOOL NEAR PASCAL CouldBe16bitDrv(UINT wDeviceID);
+
+// In mci.c
+extern DWORD FAR PASCAL mciRelaySystemString (LPMCI_SYSTEM_MESSAGE lpMessage);
+
+#endif //ifndef MMNOMCI
diff --git a/private/mvdm/wow16/mmsystem/mmsystem.def b/private/mvdm/wow16/mmsystem/mmsystem.def
new file mode 100644
index 000000000..762538f13
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmsystem.def
@@ -0,0 +1,228 @@
+LIBRARY MMSYSTEM
+
+DESCRIPTION 'System APIs for Multimedia'
+
+EXETYPE WINDOWS
+
+PROTMODE
+
+CODE MOVEABLE DISCARDABLE LOADONCALL
+DATA MOVEABLE SINGLE PRELOAD
+
+
+SEGMENTS
+ FIX FIXED PRELOAD
+ INTDS CLASS 'DATA' FIXED PRELOAD
+
+ INIT MOVEABLE DISCARDABLE PRELOAD
+ WAVE MOVEABLE DISCARDABLE PRELOAD ;;for startup sound
+
+ _TEXT MOVEABLE DISCARDABLE PRELOAD ;; to save memory on 1Mb 286
+;;;;_TEXT MOVEABLE NONDISCARDABLE PRELOAD
+
+ MCI MOVEABLE DISCARDABLE LOADONCALL
+ MIDI MOVEABLE DISCARDABLE LOADONCALL
+ MMIO MOVEABLE DISCARDABLE LOADONCALL
+ RARE MOVEABLE DISCARDABLE LOADONCALL
+ MIXER MOVEABLE DISCARDABLE LOADONCALL
+
+HEAPSIZE 128
+
+IMPORTS
+ _DebugOutput = KERNEL.328
+; _HREAD = KERNEL.349
+; _HWRITE = KERNEL.350
+; HMEMCPY = KERNEL.348
+ LSTRCPYN = KERNEL.353
+ LocalCountFree = KERNEL.161
+ LocalHeapSize = KERNEL.162
+ GetLPErrMode = KERNEL.99
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+ SNDPLAYSOUND @2
+ MMSYSTEMGETVERSION @5
+ DRIVERPROC @6 RESIDENTNAME ;Internal
+;
+; driver helper functions
+;
+ OUTPUTDEBUGSTR @30
+ DRIVERCALLBACK @31
+ STACKENTER @32
+ STACKLEAVE @33
+ MMDRVINSTALL @34 ;Internal
+;
+; JOYSTICK interface
+;
+ JOYGETNUMDEVS @101
+ JOYGETDEVCAPS @102
+ JOYGETPOS @103
+ JOYGETTHRESHOLD @104
+ JOYRELEASECAPTURE @105
+ JOYSETCAPTURE @106
+ JOYSETTHRESHOLD @107
+ JOYSETCALIBRATION @109
+;
+; MIDI interface
+;
+ MIDIOUTGETNUMDEVS @201
+ MIDIOUTGETDEVCAPS @202
+ MIDIOUTGETERRORTEXT @203
+ MIDIOUTOPEN @204
+ MIDIOUTCLOSE @205
+ MIDIOUTPREPAREHEADER @206
+ MIDIOUTUNPREPAREHEADER @207
+ MIDIOUTSHORTMSG @208
+ MIDIOUTLONGMSG @209
+ MIDIOUTRESET @210
+ MIDIOUTGETVOLUME @211
+ MIDIOUTSETVOLUME @212
+ MIDIOUTCACHEPATCHES @213
+ MIDIOUTCACHEDRUMPATCHES @214
+ MIDIOUTGETID @215
+ MIDIOUTMESSAGE @216
+;
+; MIDI interface
+;
+ MIDIINGETNUMDEVS @301
+ MIDIINGETDEVCAPS @302
+ MIDIINGETERRORTEXT @303
+ MIDIINOPEN @304
+ MIDIINCLOSE @305
+ MIDIINPREPAREHEADER @306
+ MIDIINUNPREPAREHEADER @307
+ MIDIINADDBUFFER @308
+ MIDIINSTART @309
+ MIDIINSTOP @310
+ MIDIINRESET @311
+ MIDIINGETID @312
+ MIDIINMESSAGE @313
+;
+; AUX interface
+;
+ AUXGETNUMDEVS @350
+ AUXGETDEVCAPS @351
+ AUXGETVOLUME @352
+ AUXSETVOLUME @353
+ AUXOUTMESSAGE @354
+;
+; WAVE interface
+;
+ WAVEOUTGETNUMDEVS @401
+ WAVEOUTGETDEVCAPS @402
+ WAVEOUTGETERRORTEXT @403
+ WAVEOUTOPEN @404
+ WAVEOUTCLOSE @405
+ WAVEOUTPREPAREHEADER @406
+ WAVEOUTUNPREPAREHEADER @407
+ WAVEOUTWRITE @408
+ WAVEOUTPAUSE @409
+ WAVEOUTRESTART @410
+ WAVEOUTRESET @411
+ WAVEOUTGETPOSITION @412
+ WAVEOUTGETPITCH @413
+ WAVEOUTSETPITCH @414
+ WAVEOUTGETVOLUME @415
+ WAVEOUTSETVOLUME @416
+ WAVEOUTGETPLAYBACKRATE @417
+ WAVEOUTSETPLAYBACKRATE @418
+ WAVEOUTBREAKLOOP @419
+ WAVEOUTGETID @420
+ WAVEOUTMESSAGE @421
+
+ WAVEINGETNUMDEVS @501
+ WAVEINGETDEVCAPS @502
+ WAVEINGETERRORTEXT @503
+ WAVEINOPEN @504
+ WAVEINCLOSE @505
+ WAVEINPREPAREHEADER @506
+ WAVEINUNPREPAREHEADER @507
+ WAVEINADDBUFFER @508
+ WAVEINSTART @509
+ WAVEINSTOP @510
+ WAVEINRESET @511
+ WAVEINGETPOSITION @512
+ WAVEINGETID @513
+ WAVEINMESSAGE @514
+;
+; TIME interface
+;
+ TIMEGETSYSTEMTIME @601
+ TIMEGETTIME @607
+ TIMESETEVENT @602
+ TIMEKILLEVENT @603
+ TIMEGETDEVCAPS @604
+ TIMEBEGINPERIOD @605
+ TIMEENDPERIOD @606
+;
+; MCI interface
+;
+ MCISENDCOMMAND @701
+ MCISENDSTRING @702
+ MCIGETDEVICEID @703
+ MCIPARSECOMMAND @704
+ MCILOADCOMMANDRESOURCE @705
+ MCIGETERRORSTRING @706
+ MCISETDRIVERDATA @707
+ MCIGETDRIVERDATA @708
+ MCIDRIVERYIELD @710
+ MCIDRIVERNOTIFY @711
+ MCIEXECUTE @712
+ MCIFREECOMMANDRESOURCE @713
+ MCISETYIELDPROC @714
+ MCIGETDEVICEIDFROMELEMENTID @715
+ MCIGETYIELDPROC @716
+ MCIGETCREATORTASK @717
+
+;
+; MIXER interface
+;
+ MIXERGETNUMDEVS @800
+ MIXERGETDEVCAPS @801
+ MIXEROPEN @802
+ MIXERCLOSE @803
+ MIXERMESSAGE @804
+ MIXERGETLINEINFO @805
+ MIXERGETID @806
+ MIXERGETLINECONTROLS @807
+ MIXERGETCONTROLDETAILS @808
+ MIXERSETCONTROLDETAILS @809
+
+;
+; MMTASK interface
+;
+ MMTASKCREATE @900
+ MMTASKBLOCK @902
+ MMTASKSIGNAL @903
+ MMGETCURRENTTASK @904
+ MMTASKYIELD @905
+
+;
+; Driver interface
+;
+ DRVOPEN @1100
+ DRVCLOSE @1101
+ DRVSENDMESSAGE @1102
+ DRVGETMODULEHANDLE @1103
+ DRVDEFDRIVERPROC @1104
+;
+; MMIO
+;
+ MMIOOPEN @1210
+ MMIOCLOSE @1211
+ MMIOREAD @1212
+ MMIOWRITE @1213
+ MMIOSEEK @1214
+ MMIOGETINFO @1215
+ MMIOSETINFO @1216
+ MMIOSETBUFFER @1217
+ MMIOFLUSH @1218
+ MMIOADVANCE @1219
+ MMIOSTRINGTOFOURCC @1220
+ MMIOINSTALLIOPROC @1221
+ MMIOSENDMESSAGE @1222
+
+ MMIODESCEND @1223
+ MMIOASCEND @1224
+ MMIOCREATECHUNK @1225
+ MMIORENAME @1226
diff --git a/private/mvdm/wow16/mmsystem/mmtask/makefile b/private/mvdm/wow16/mmsystem/mmtask/makefile
new file mode 100644
index 000000000..2c6792a34
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmtask/makefile
@@ -0,0 +1,125 @@
+#
+# constructs mmtask as a small model exe
+#
+
+NAME =mmtask
+EXT =tsk
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(DEBUG)" == "NO"
+CLOPT =-Oas
+MASMOPT =-I..\..\inc
+LINKOPT =
+RCOPT =
+!else
+!if "$(DEBUG)" == "RETAIL"
+CLOPT =-Oas
+MASMOPT =-I..\..\inc
+LINKOPT =
+RCOPT =
+!else
+CLOPT =-Od -Zi -DDEBUG
+MASMOPT =-Zi -t -I..\..\inc
+LINKOPT =/LI/NOPACK
+RCOPT =-DDEBUG
+!endif
+!endif
+
+CC =cl16 -c -nologo -Asnw -G2sw -Zp -W2 $(CLOPT)
+RC =rc16 -i ..\..\inc;..\rinc
+ASM =masm -Mx -D?QUIET $(MASMOPT)
+LINK =link16 /NOD/NOE/MAP/A:16$(LINKOPT)
+DEFFILE =$(NAME).DEF
+
+OBJ =$(NAME).obj
+LIBS =..\..\lib\libw
+
+.c.obj:
+ @$(CC) $*.c
+
+.asm.obj:
+ @echo $(@B).asm
+ @$(ASM) $*;
+
+!IFNDEF LANG
+all: ..\$(NAME).$(EXT) ..\$(NAME).sym ..\$(NAME).map
+!ELSE
+all: $(NAME).$(LANG)
+!ENDIF
+
+$(NAME).$(EXT) $(NAME).map: $(OBJ) $(DEFFILE) $(NAME).res
+ @$(LINK) $(OBJ), $(NAME).$(EXT),,$(LIBS), $(DEFFILE)
+ @$(RC) -t $(NAME).res $(NAME).$(EXT)
+
+..\$(NAME).$(EXT): $$(@F)
+ @copy $(@F) $@
+
+..\$(NAME).sym: $$(@R).$(EXT) $$(@F)
+ @copy $(@F) $@
+
+..\$(NAME).map: $$(@R).$(EXT) $$(@F)
+ @copy $(@F) $@
+
+$(NAME).sym: $$(@B).map
+ @mapsym /n $*.map
+
+################### International mods ###############################
+
+# note INTL_SRC ,INTL_EXE and LANG are external macros set by international
+!IFNDEF LANG
+RES_DIR =..\messages\usa
+!ELSE
+RES_DIR =$(INTL_SRC)\$(LANG)\mmsystem\mmtask
+EXE_DIR =$(INTL_EXE)
+!ENDIF
+
+!IFNDEF LANG
+$(NAME).rc: $(RES_DIR)\$(NAME).rc
+ @copy $(RES_DIR)\$(NAME).rc
+
+$(NAME).rcv: $(RES_DIR)\$$(@F) ..\..\inc\common.ver
+ @copy $(RES_DIR)\$@
+ @touch $@
+
+$(NAME).res: $(NAME).rc $(NAME).h $(NAME).rcv ..\..\inc\common.ver
+ @$(RC) $(RCOPT) -r $(NAME).rc
+!ELSE
+$(NAME).res:
+ @copy $(RES_DIR)\$(NAME).res
+!ENDIF
+
+$(NAME).$(LANG): $(NAME).res
+ @copy $(EXE_DIR)\$(NAME).$(EXT) $(NAME).$(LANG)
+ @$(RC) -t $(NAME).res $(NAME).$(LANG)
+
+########################################################################
+
+clean: cleanup all
+
+cleanup:
+ -@del $(NAME).$(EXT)
+ -@del $(NAME).res
+ -@del *.sym
+ -@del *.map
+ -@del *.obj
+ -@del *.rcv
+ -@del *.rc
+
+depend:
+ mv makefile makefile.old
+ sed "/^# START Dependencies/,/^# END Dependencies/D" makefile.old > makefile
+ del makefile.old
+ echo # START Dependencies >> makefile
+ includes -l *.c *.asm >> makefile
+ echo # END Dependencies >> makefile
+
+# START Dependencies
+mmtask.obj: mmtask.asm
+
+# END Dependencies
diff --git a/private/mvdm/wow16/mmsystem/mmtask/mmtask.asm b/private/mvdm/wow16/mmsystem/mmtask/mmtask.asm
new file mode 100644
index 000000000..c73e50af1
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmtask/mmtask.asm
@@ -0,0 +1,267 @@
+PAGE 58,132
+;*****************************************************************************
+TITLE MMTASK.ASM - Windows MultiMedia Systems Task Stub
+;*****************************************************************************
+;
+; Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+;
+; Title: MMTASK.asm - a windows application that acts as a
+; task stub.
+;
+; Version: 1.00
+;
+; Date: 12-Mar-1990
+;
+; Author: ROBWI
+;
+;-----------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- --------------------------------------------------------
+; 12-Mar-1990 ROBWI First Version
+; 18-APR-1990 ROBWI Moved from idle.asm to mmtask.asm
+;
+;=============================================================================
+
+
+?WIN=0
+?PLM=1
+
+
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ .list
+
+wptr equ WORD PTR
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+
+;----------------------------------------------------------------------
+;
+; MMTASKSTRUC : The following structure should be passed to mmtask (in
+; the command line) when it is exec'd.
+
+
+MMTASKSTRUC struc
+lpfn dd ? ; fp to function to call.
+inst dd ? ; instance data to pass to lpfn
+dwstck dd ? ; stack size.
+MMTASKSTRUC ends
+
+EXIT_PROCESS equ 1
+
+;-----------------------------------------------------------------------;
+;
+; externals from KERNEL
+
+ externFP WaitEvent
+ externFP PostEvent
+ externFP OldYield
+ externFP InitTask
+ externFP InitApp ; to get a msg q so that we can call user
+ externFP OutputDebugString
+
+ externFP SetMessageQueue
+
+
+sBegin DATA
+assumes DS,DATA
+
+; Stuff needed to avoid the C runtime coming in
+
+ DD 0 ; So null pointers get 0
+maxRsrvPtrs = 5
+ DW maxRsrvPtrs
+usedRsrvPtrs = 0
+labelDP <PUBLIC,rsrvptrs>
+
+DefRsrvPtr MACRO name
+globalW name,0
+usedRsrvPtrs = usedRsrvPtrs + 1
+ENDM
+
+DefRsrvPtr pLocalHeap ; Local heap pointer
+DefRsrvPtr pAtomTable ; Atom table pointer
+DefRsrvPtr pStackTop ; top of stack
+DefRsrvPtr pStackMin ; minimum value of SP
+DefRsrvPtr pStackBot ; bottom of stack
+
+if maxRsrvPtrs-usedRsrvPtrs
+ DW maxRsrvPtrs-usedRsrvPtrs DUP (0)
+endif
+
+public __acrtused
+ __acrtused = 1
+
+loadparams DB (SIZE MMTASKSTRUC) DUP (0)
+
+sEnd DATA
+
+
+sBegin Code
+ assumes cs, Code
+ assumes ds, Data
+ assumes es, nothing
+ assumes ss, nothing
+
+;--------------------------Private-Routine-----------------------------;
+;
+; @doc INTERNAL MMTASKAPP
+;
+; @asm AppEntry | called when the APP is loaded
+;
+; @reg CX | size of heap
+; @reg DI | module handle
+; @reg DS | automatic data segment
+; @reg ES:SI | address of command line (not used)
+; @reg
+;
+; @rdesc Register values at return
+;
+; @reg AX | 1 if success, 0 if error
+;
+; @uses AX BX CX DX FLAGS
+;
+; @comm Preserves: SI DI DS BP
+;
+; Calls: None
+;
+; History:
+;
+; 06-27-89 -by- Todd Laney [ToddLa] Created shell appentry
+; routine
+; 03-13-90 -stolen- Rob Williams [RobWi] Added all kinds o'
+; stuff for making it an MMTASK application.
+;
+;-----------------------------------------------------------------------;
+cProc AppEntry,<FAR,PUBLIC,NODATA>,<>
+
+cBegin
+
+; Copy the parameters out of the command line before
+; InitTask gets a chance to modify them.
+
+ push di
+ push si
+ push cx
+
+; switch ds and es so that we can do a string move
+; into the data segment
+
+ push ds ; save ds o
+ mov ax, es
+ mov ds, ax ; ds = es 0
+ pop es ; es = ds 0
+
+; copy the command line if it is the correct length
+
+ mov si, 81h
+ lea di, loadparams
+ mov cx, SIZE MMTASKSTRUC / 2
+ xor ax, ax
+ mov al, byte ptr ds:[80h]
+ shr ax, 1
+ cmp ax, cx ; Q: structure size correct
+ jne Skip_Copy ; N: Skip the copy
+
+.ERRNZ SIZE MMTASKSTRUC MOD 2
+
+ cld ; Y: Copy the structure
+ rep movsw
+
+Skip_Copy:
+
+; restore original es and ds
+
+ push es
+ mov ax, ds
+ mov es, ax ; es = ds = es 0
+ pop ds
+ pop cx
+ pop si
+ pop di
+
+; pretend the command string is 0 length.
+
+ xor ax, ax
+ mov es:[80h], ax
+
+; initialize the task and the event queue
+
+ cCall InitTask
+ cCall InitApp, <di>
+
+ cCall SetMessageQueue, <64>
+ or ax,ax
+ jz MMTASKexit
+
+; DX is now the CmdShow value.
+; CX is stack size.
+
+; event count is initially one so call waitevent to clear the event count
+
+ cCall WaitEvent, <0>
+
+; check parameters
+
+ mov dx, loadparams.lpfn.hi
+ or dx, dx ; callback ok?
+ jz MMTASKExit ; N: out'a here
+
+ cCall OldYield ; be polite.
+
+ mov ax, loadparams.inst.lo
+ mov dx, loadparams.inst.hi
+ cCall loadparams.lpfn, <dx, ax>
+
+MMTASKExit:
+
+ifdef DEBUG
+ ; lets make sure the app did not do anything evil
+
+ cmp wptr ds:[0],0
+ jne evil
+ cmp wptr ds:[2],0
+ jne evil
+ cmp wptr ds:[4],5
+ jne evil
+ je not_evil
+evil:
+ lea ax,evil_str
+ cCall OuputDebugString, <cs,ax>
+ int 3
+ jmp not_evil
+evil_str:
+ db "MMTASK: NULL pointer assignment! fag!",13,10,0
+not_evil:
+endif
+ ; before we actualy exit lets yield, so we don't re-enter
+ ; USERS AppExit code.....
+
+ cCall OldYield
+ cCall OldYield
+ cCall OldYield
+
+ mov ah, 4Ch
+ int 21h
+cEnd
+
+sEnd
+
+end AppEntry
diff --git a/private/mvdm/wow16/mmsystem/mmtask/mmtask.def b/private/mvdm/wow16/mmsystem/mmtask/mmtask.def
new file mode 100644
index 000000000..b5b7ce28a
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmtask/mmtask.def
@@ -0,0 +1,12 @@
+NAME MMTASK
+
+DESCRIPTION 'Microsoft MultiMedia Task App. '
+
+PROTMODE
+EXETYPE WINDOWS
+
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE MULTIPLE
+
+HEAPSIZE 0
+STACKSIZE 4096
diff --git a/private/mvdm/wow16/mmsystem/mmtask/mmtask.h b/private/mvdm/wow16/mmsystem/mmtask/mmtask.h
new file mode 100644
index 000000000..717e8fae9
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmtask/mmtask.h
@@ -0,0 +1,36 @@
+/*****************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: mmtask.h - header file for mmtask app!
+
+ Version: 1.00
+
+ Date: 12-Mar-1990
+
+ Author: ROBWI
+
+-----------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ ----------- --- --------------------------------------------------------
+ 12-Mar-1990 ROBWI First Version
+ 18-Apr-1990 ROBWI Moved to mmtask
+
+****************************************************************************/
+
+/*
+ The mmtask app. expects this structure to be passed as the
+ command tail when the app. is exec'd
+*/
+
+typedef struct _MMTaskStruct {
+ BYTE cb;
+ LPTASKCALLBACK lpfn;
+ DWORD dwInst;
+ DWORD dwStack;
+} MMTaskStruct;
+
+#define MMTASK_STACK 4096
diff --git a/private/mvdm/wow16/mmsystem/mmwnd.c b/private/mvdm/wow16/mmsystem/mmwnd.c
new file mode 100644
index 000000000..126959dc7
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/mmwnd.c
@@ -0,0 +1,187 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: mmwnd.c - contains the window procedure for the MMSYSTEM 'global'
+ window
+
+ the global window is used by sndPlaySound and MCI for
+ reciving notification messages.
+
+ Version: 1.00
+
+ Date: 04-Sep-1990
+
+ Author: ToddLa
+
+*****************************************************************************/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "mmsysver.h"
+
+#define CLASS_NAME MAKEINTATOM(42)
+
+/*
+ SOUND_DELAY is the number of ms to delay before closing the wave device
+ after the buffer is done.
+*/
+
+#define SOUND_DELAY 300
+
+typedef LRESULT (CALLBACK *LPWNDPROC)(HWND, UINT, WPARAM, LPARAM);
+
+// Place the normal code in the _TEXT segment
+
+static LRESULT CALLBACK mmWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#pragma alloc_text(_TEXT, mmWndProc)
+
+HWND hwndNotify;
+
+
+/****************************************************************************
+
+ strings
+
+****************************************************************************/
+
+SZCODE szStartupSound[] = "SystemStart";
+
+
+/***************************************************************************/
+
+static BOOL PASCAL FAR CreateMMClass(void)
+{
+ WNDCLASS cls;
+
+ cls.hCursor = NULL;
+ cls.hIcon = NULL;
+ cls.lpszMenuName = NULL;
+ cls.lpszClassName = CLASS_NAME;
+ cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ cls.hInstance = ghInst;
+ cls.style = CS_GLOBALCLASS;
+ cls.lpfnWndProc = (WNDPROC)mmWndProc;
+ cls.cbWndExtra = 0;
+ cls.cbClsExtra = 0;
+
+ return RegisterClass(&cls);
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL MMSYSTEM
+ *
+ * @api BOOL | WndInit | called to create the MMSYSTEM global window.
+ *
+ * @comm we need to create this window on be-half of the SHELL task
+ * so it will be around all the time.
+ *
+ ***************************************************************************/
+
+BOOL NEAR PASCAL WndInit(void)
+{
+ if (hwndNotify) // if we are init'ed already, just get out
+ return TRUE;
+
+ if (!CreateMMClass())
+ return FALSE;
+
+ if (!(hwndNotify = CreateWindowEx(0, CLASS_NAME, NULL, WS_OVERLAPPED,
+ 0, 0, 0, 0, NULL, NULL, ghInst, NULL))) {
+ UnregisterClass(CLASS_NAME, ghInst);
+ return FALSE;
+ }
+
+
+#ifdef DEBUGX
+ {
+ DPRINTF(("MMSYSTEM: Creating Notify Window: htask=%04X hwnd=%04X\r\n", GetCurrentTask(),hwndNotify));
+ }
+#endif // DEBUGX
+ return TRUE;
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL MMSYSTEM
+ *
+ * @api void | WndTerminate | called when MMSYSTEM is terminating
+ *
+ ***************************************************************************/
+
+void NEAR PASCAL WndTerminate(void)
+{
+ if (hwndNotify)
+ {
+ SendMessage(hwndNotify, WM_CLOSE, 0, 0L);
+ UnregisterClass(CLASS_NAME, ghInst);
+ }
+}
+
+/***************************************************************************
+ *
+ * @doc INTERNAL MMSYSTEM
+ *
+ * @api LRESULT | mmWndProc | The Window procedure for the MMSYSTEM window
+ *
+ * @comm mmWndProc calls DefWindowProc for all messages except:
+ *
+ * MM_MCINOTIFY: calls MciNotify() in MCI.C
+ * MM_WOM_DONE: calls WaveOutNotify() in PLAYWAV.C
+ *
+ * @xref sndPlaySound
+ *
+ ***************************************************************************/
+
+static LRESULT CALLBACK mmWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_CREATE:
+ hwndNotify = hwnd;
+ // sndPlaySound(szStartupSound, SND_ASYNC | SND_NODEFAULT);
+ break;
+
+ case WM_TIMER:
+ KillTimer(hwnd, (UINT)wParam);
+ WaveOutNotify(0,0);
+ break;
+
+ case MM_MCINOTIFY:
+ MciNotify(wParam, lParam);
+ break;
+
+ case MM_WOM_DONE:
+
+ /*
+ The sound started with sndPlaySound has completed
+ so we should call the cleanup routine. We delay
+ this call for several hundred milliseconds because
+ some sound drivers have a nasty characteristic - they
+ will notify before the final DMA transfer is complete
+ because the app. supplied buffer is no longer required.
+ This means that they may have to spin inside a close
+ request until the dma transfer completes. This hangs
+ the system for hundreds of milliseconds.
+
+ */
+
+ SetTimer(hwndNotify, 1, SOUND_DELAY, NULL);
+ break;
+
+ case MM_SND_PLAY:
+ return (LRESULT)(LONG)sndMessage((LPSTR)lParam, (UINT)wParam);
+
+ case MM_MCISYSTEM_STRING:
+ return (LRESULT)mciRelaySystemString ((LPMCI_SYSTEM_MESSAGE)lParam);
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam,lParam);
+ }
+
+ return (LRESULT)0L;
+}
diff --git a/private/mvdm/wow16/mmsystem/msmixmgr.y b/private/mvdm/wow16/mmsystem/msmixmgr.y
new file mode 100644
index 000000000..a56959474
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/msmixmgr.y
@@ -0,0 +1,1000 @@
+//==========================================================================;
+//
+// msmixmgr.h -- Include file for Microsoft Audio Mixer Manager API's
+//
+// Version 3.10 (16 Bit)
+//
+// Copyright (C) 1992, 1993 Microsoft Corporation. All Rights Reserved.
+//
+//--------------------------------------------------------------------------;
+//
+// Define: Prevent inclusion of:
+// -------------- --------------------------------------------------------
+// MMNOMIXER Mixer application development support
+// MMNOMIXERDEV Mixer driver development support
+//
+//--------------------------------------------------------------------------;
+//
+// NOTE: mmsystem.h (and mmddk.h for drivers) must be included _before_
+// msmixmgr.h is included.
+//
+// For mixer applications: For mixer drivers:
+//
+// #include <windows.h> #include <windows.h>
+// #include <windowsx.h> #include <windowsx.h>
+// #include <mmsystem.h> #include <mmsystem.h>
+// #include <msmixmgr.h> #include <mmddk.h>
+// . . . #include <msmixmgr.h>
+// . . .
+//
+//==========================================================================;
+
+#ifndef _INC_MSMIXMGR
+#define _INC_MSMIXMGR // #defined if msmixmgr.h was included
+
+#ifndef RC_INVOKED
+#pragma pack(1) // assume byte packing throughout
+#endif
+
+#ifdef __cplusplus
+extern "C" // assume C declarations for C++
+{
+#endif // __cplusplus
+
+
+//
+//
+//
+//
+#ifndef _MMRESULT_
+#define _MMRESULT_
+typedef UINT MMRESULT;
+#endif
+
+#ifndef _MMVERSION_
+#define _MMVERSION_
+typedef UINT MMVERSION;
+#endif
+
+
+//==========================================================================;
+//
+// Mixer Application Definitions
+//
+//
+//
+//==========================================================================;
+
+#ifdef _INC_MMSYSTEM
+#ifndef MMNOMIXER
+
+#ifndef MM_MIXM_LINE_CHANGE
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+#ifdef WIN32
+#define MIXAPI APIENTRY
+#else
+#ifdef _WINDLL
+ #define MIXAPI _far _pascal _loadds
+#else
+ #define MIXAPI _far _pascal
+#endif
+#endif
+
+
+//
+// mixer callback notification messages. these messages are sent to all
+// clients that have an open instance to a mixer device and have requested
+// notifications by supplying a callback.
+//
+// CALLBACK_WINDOW:
+//
+// uMsg = MM_MIXM_LINE_CHANGE
+// wParam = hmx
+// lParam = dwLineID
+//
+// uMsg = MM_MIXM_CONTROL_CHANGE
+// wParam = hmx
+// lParam = dwControlID
+//
+//
+#define MM_MIXM_LINE_CHANGE 0x3D0 // mixer line change notify
+#define MM_MIXM_CONTROL_CHANGE 0x3D1 // mixer control change notify
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+DECLARE_HANDLE(HMIXEROBJ);
+typedef HMIXEROBJ FAR *LPHMIXEROBJ;
+
+DECLARE_HANDLE(HMIXER);
+typedef HMIXER FAR *LPHMIXER;
+
+
+//
+//
+//
+#define MIXER_SHORT_NAME_CHARS 16
+#define MIXER_LONG_NAME_CHARS 64
+
+
+//
+// MMRESULT error return values specific to the mixer API
+//
+//
+#define MIXERR_BASE 1024
+#define MIXERR_INVALLINE (MIXERR_BASE + 0)
+#define MIXERR_INVALCONTROL (MIXERR_BASE + 1)
+#define MIXERR_INVALVALUE (MIXERR_BASE + 2)
+#define MIXERR_LASTERROR (MIXERR_BASE + 2)
+
+
+//
+//
+//
+#define MIXER_OBJECTF_HANDLE 0x80000000L
+#define MIXER_OBJECTF_MIXER 0x00000000L
+#define MIXER_OBJECTF_HMIXER (MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIXER)
+#define MIXER_OBJECTF_WAVEOUT 0x10000000L
+#define MIXER_OBJECTF_HWAVEOUT (MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_WAVEOUT)
+#define MIXER_OBJECTF_WAVEIN 0x20000000L
+#define MIXER_OBJECTF_HWAVEIN (MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_WAVEIN)
+#define MIXER_OBJECTF_MIDIOUT 0x30000000L
+#define MIXER_OBJECTF_HMIDIOUT (MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIDIOUT)
+#define MIXER_OBJECTF_MIDIIN 0x40000000L
+#define MIXER_OBJECTF_HMIDIIN (MIXER_OBJECTF_HANDLE|MIXER_OBJECTF_MIDIIN)
+#define MIXER_OBJECTF_AUX 0x50000000L
+
+#define MIXER_OBJECTF_TYPEMASK 0xF0000000L // ;Internal
+
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetNumDevs()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+UINT MIXAPI mixerGetNumDevs
+(
+ void
+);
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetDevCaps()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+typedef struct tMIXERCAPS
+{
+ WORD wMid; // manufacturer id
+ WORD wPid; // product id
+ MMVERSION vDriverVersion; // version of the driver
+ char szPname[MAXPNAMELEN]; // product name
+ DWORD fdwSupport; // misc. support bits
+ DWORD cDestinations; // count of destinations
+} MIXERCAPS;
+typedef MIXERCAPS *PMIXERCAPS;
+typedef MIXERCAPS FAR *LPMIXERCAPS;
+
+
+#define MIXERCAPS_SUPPORTF_xxx 0x00000000L // ;Internal
+
+
+//
+//
+//
+MMRESULT MIXAPI mixerGetDevCaps
+(
+ UINT uMxId,
+ LPMIXERCAPS pmxcaps,
+ UINT cbmxcaps
+);
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetID()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+MMRESULT MIXAPI mixerGetID
+(
+ HMIXEROBJ hmxobj,
+ UINT FAR *puMxId,
+ DWORD fdwId
+);
+
+#define MIXER_GETIDF_VALID (MIXER_OBJECTF_TYPEMASK) // ;Internal
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerOpen()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+MMRESULT MIXAPI mixerOpen
+(
+ LPHMIXER phmx,
+ UINT uMxId,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD fdwOpen
+);
+
+#define MIXER_OPENF_VALID (MIXER_OBJECTF_TYPEMASK | /* ;Internal */ \
+ CALLBACK_TYPEMASK) // ;Internal
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerClose()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+MMRESULT MIXAPI mixerClose
+(
+ HMIXER hmx
+);
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerMessage()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+DWORD MIXAPI mixerMessage
+(
+ HMIXER hmx,
+ UINT uMsg,
+ DWORD dwParam1,
+ DWORD dwParam2
+);
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetLineInfo()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+typedef struct tMIXERLINE
+{
+ DWORD cbStruct; // size of MIXERLINE structure
+ DWORD dwDestination; // zero based destination index
+ DWORD dwSource; // zero based source index (if source)
+ DWORD dwLineID; // unique line id for mixer device
+ DWORD fdwLine; // state/information about line
+ DWORD dwUser; // driver specific information
+ DWORD dwComponentType; // component type line connects to
+ DWORD cChannels; // number of channels line supports
+ DWORD cConnections; // number of connections [possible]
+ DWORD cControls; // number of controls at this line
+ char szShortName[MIXER_SHORT_NAME_CHARS];
+ char szName[MIXER_LONG_NAME_CHARS];
+ struct
+ {
+ DWORD dwType; // MIXERLINE_TARGETTYPE_xxxx
+ DWORD dwDeviceID; // target device ID of device type
+ WORD wMid; // of target device
+ WORD wPid; // "
+ MMVERSION vDriverVersion; // "
+ char szPname[MAXPNAMELEN]; // "
+ } Target;
+} MIXERLINE;
+typedef MIXERLINE *PMIXERLINE;
+typedef MIXERLINE FAR *LPMIXERLINE;
+
+
+//
+// MIXERLINE.fdwLine
+//
+//
+#define MIXERLINE_LINEF_ACTIVE 0x00000001L
+#define MIXERLINE_LINEF_DISCONNECTED 0x00008000L
+#define MIXERLINE_LINEF_SOURCE 0x80000000L
+
+
+//
+// MIXERLINE.dwComponentType
+//
+// component types for destinations and sources
+//
+//
+#define MLCT_DST_FIRST 0x00000000L
+#define MLCT_DST_UNDEFINED (MLCT_DST_FIRST + 0)
+#define MLCT_DST_DIGITAL (MLCT_DST_FIRST + 1)
+#define MLCT_DST_LINE (MLCT_DST_FIRST + 2)
+#define MLCT_DST_MONITOR (MLCT_DST_FIRST + 3)
+#define MLCT_DST_SPEAKERS (MLCT_DST_FIRST + 4)
+#define MLCT_DST_HEADPHONES (MLCT_DST_FIRST + 5)
+#define MLCT_DST_TELEPHONE (MLCT_DST_FIRST + 6)
+#define MLCT_DST_WAVEIN (MLCT_DST_FIRST + 7)
+#define MLCT_DST_VOICEIN (MLCT_DST_FIRST + 8)
+#define MLCT_DST_LAST (MLCT_DST_FIRST + 8)
+
+#define MLCT_SRC_FIRST 0x00001000L
+#define MLCT_SRC_UNDEFINED (MLCT_SRC_FIRST + 0)
+#define MLCT_SRC_DIGITAL (MLCT_SRC_FIRST + 1)
+#define MLCT_SRC_LINE (MLCT_SRC_FIRST + 2)
+#define MLCT_SRC_MICROPHONE (MLCT_SRC_FIRST + 3)
+#define MLCT_SRC_SYNTHESIZER (MLCT_SRC_FIRST + 4)
+#define MLCT_SRC_COMPACTDISC (MLCT_SRC_FIRST + 5)
+#define MLCT_SRC_TELEPHONE (MLCT_SRC_FIRST + 6)
+#define MLCT_SRC_PCSPEAKER (MLCT_SRC_FIRST + 7)
+#define MLCT_SRC_WAVEOUT (MLCT_SRC_FIRST + 8)
+#define MLCT_SRC_AUXILIARY (MLCT_SRC_FIRST + 9)
+#define MLCT_SRC_ANALOG (MLCT_SRC_FIRST + 10)
+#define MLCT_SRC_LAST (MLCT_SRC_FIRST + 10)
+
+
+//
+// MIXERLINE.Target.dwType
+//
+//
+#define MIXERLINE_TARGETTYPE_UNDEFINED 0
+#define MIXERLINE_TARGETTYPE_WAVEOUT 1
+#define MIXERLINE_TARGETTYPE_WAVEIN 2
+#define MIXERLINE_TARGETTYPE_MIDIOUT 3
+#define MIXERLINE_TARGETTYPE_MIDIIN 4
+#define MIXERLINE_TARGETTYPE_AUX 5
+
+
+
+//
+//
+//
+//
+MMRESULT MIXAPI mixerGetLineInfo
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINE pmxl,
+ DWORD fdwInfo
+);
+
+#define M_GLINFOF_DESTINATION 0x00000000L
+#define M_GLINFOF_SOURCE 0x00000001L
+#define M_GLINFOF_LINEID 0x00000002L
+#define M_GLINFOF_COMPONENTTYPE 0x00000003L
+#define M_GLINFOF_TARGETTYPE 0x00000004L
+
+#define M_GLINFOF_QUERYMASK 0x0000000FL
+
+#define M_GLINFOF_VALID (MIXER_OBJECTF_TYPEMASK | /* ;Internal */ \
+ M_GLINFOF_QUERYMASK) // ;Internal
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetLineControls()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+//
+// MIXERCONTROL
+//
+//
+typedef struct tMIXERCONTROL
+{
+ DWORD cbStruct; // size in bytes of MIXERCONTROL
+ DWORD dwControlID; // unique control id for mixer device
+ DWORD dwControlType; // MC_CONTROLTYPE_xxx
+ DWORD fdwControl; // MC_CONTROLF_xxx
+ DWORD cMultipleItems; // if MC_CONTROLF_MULTIPLE set
+ char szShortName[MIXER_SHORT_NAME_CHARS];
+ char szName[MIXER_LONG_NAME_CHARS];
+ union
+ {
+ struct
+ {
+ LONG lMinimum; // signed minimum for this control
+ LONG lMaximum; // signed maximum for this control
+ };
+ struct
+ {
+ DWORD dwMinimum; // unsigned minimum for this control
+ DWORD dwMaximum; // unsigned maximum for this control
+ };
+ DWORD dwReserved[6];
+ } Bounds;
+ union
+ {
+ DWORD cSteps; // # of steps between min & max
+ DWORD cbCustomData; // size in bytes of custom data
+ DWORD dwReserved[6]; // !!! needed? we have cbStruct....
+ } Metrics;
+} MIXERCONTROL;
+typedef MIXERCONTROL *PMIXERCONTROL;
+typedef MIXERCONTROL FAR *LPMIXERCONTROL;
+
+
+//
+// MIXERCONTROL.fdwControl
+//
+//
+#define MC_CONTROLF_UNIFORM 0x00000001L
+#define MC_CONTROLF_MULTIPLE 0x00000002L
+#define MC_CONTROLF_DISABLED 0x80000000L
+
+#define MC_CONTROLF_VALID (MC_CONTROLF_UNIFORM | /* ;Internal */ \
+ MC_CONTROLF_MULTIPLE | /* ;Internal */ \
+ MC_CONTROLF_DISABLED) /* ;Internal */
+
+
+
+//
+// MC_CONTROLTYPE_xxx building block defines
+//
+//
+#define MC_CT_CLASS_MASK 0xF0000000L
+#define MC_CT_CLASS_CUSTOM 0x00000000L
+#define MC_CT_CLASS_METER 0x10000000L
+#define MC_CT_CLASS_SWITCH 0x20000000L
+#define MC_CT_CLASS_NUMBER 0x30000000L
+#define MC_CT_CLASS_SLIDER 0x40000000L
+#define MC_CT_CLASS_FADER 0x50000000L
+#define MC_CT_CLASS_TIME 0x60000000L
+#define MC_CT_CLASS_LIST 0x70000000L
+
+
+#define MC_CT_SUBCLASS_MASK 0x0F000000L
+
+#define MC_CT_SC_SWITCH_BOOLEAN 0x00000000L
+#define MC_CT_SC_SWITCH_BUTTON 0x01000000L
+
+#define MC_CT_SC_METER_POLLED 0x00000000L
+
+#define MC_CT_SC_TIME_MICROSECS 0x00000000L
+#define MC_CT_SC_TIME_MILLISECS 0x01000000L
+
+#define MC_CT_SC_LIST_SINGLE 0x00000000L
+#define MC_CT_SC_LIST_MULTIPLE 0x01000000L
+
+
+#define MC_CT_UNITS_MASK 0x00FF0000L
+#define MC_CT_UNITS_CUSTOM 0x00000000L
+#define MC_CT_UNITS_BOOLEAN 0x00010000L
+#define MC_CT_UNITS_SIGNED 0x00020000L
+#define MC_CT_UNITS_UNSIGNED 0x00030000L
+#define MC_CT_UNITS_DECIBELS 0x00040000L // in 10ths
+#define MC_CT_UNITS_PERCENT 0x00050000L // in 10ths
+
+
+//
+// MIXERCONTROL.dwControlType
+//
+
+//
+// Custom Controls
+//
+//
+#define MC_CONTROLTYPE_CUSTOM (MC_CT_CLASS_CUSTOM | MC_CT_UNITS_CUSTOM)
+
+
+
+//
+// Meters (Boolean)
+//
+// simply shows 'on or off' with the Boolean type
+//
+#define MC_CONTROLTYPE_BOOLEANMETER (MC_CT_CLASS_METER | MC_CT_SC_METER_POLLED | MC_CT_UNITS_BOOLEAN)
+
+
+//
+// Meters (signed)
+//
+// MIXERCONTROL.Bounds.lMinimum = min
+// MIXERCONTROL.Bounds.lMaximum = max
+//
+// signed meters are meant for displaying levels that have a signed nature.
+// there is no requirment for the values above and below zero to be
+// equal in magnitude. that is, it is 'ok' to have a range from, say, -3
+// to 12. however, the standard defined signed meter types may have
+// restrictions (such as the peakmeter).
+//
+// MC_CONTROLTYPE_PEAKMETER: a peak meter tells the monitoring
+// application the peak value reached (and phase) of a line (normally
+// wave input and output) over a small period of time. THIS IS NOT VU!
+// the bounds are fixed:
+//
+// MIXERCONTROL.Bounds.lMinimum = -32768 ALWAYS!
+// MIXERCONTROL.Bounds.lMaximum = 32767 ALWAYS!
+//
+// so 8 bit and 24 bit samples must be scaled appropriately. this is so
+// an application can display a 'bouncing blinky light' for a user and
+// also monitor a line for clipping. remember that 8 bit samples must
+// be converted to signed values (by the mixer driver)!
+//
+//
+// NOTE! meters are read only controls. also, a meter should only be
+// 'active' when the line it is associated with is active (see fdwLine
+// in MIXERLINE). it is NOT an error to read a meter that is not active--
+// the mixer driver should simply return 'no value' states (usually zero).
+// but it may be useful to stop monitoring a meter if the line is not
+// active...
+//
+#define MC_CONTROLTYPE_SIGNEDMETER (MC_CT_CLASS_METER | MC_CT_SC_METER_POLLED | MC_CT_UNITS_SIGNED)
+#define MC_CONTROLTYPE_PEAKMETER (MC_CONTROLTYPE_SIGNEDMETER + 1)
+
+
+//
+// Meters (unsigned)
+//
+// MIXERCONTROL.Bounds.dwMinimum = min
+// MIXERCONTROL.Bounds.dwMaximum = max
+//
+// unsigned meters are meant for displaying levels that have an unsigned
+// nature. there is no requirment for the values to be based at zero.
+// that is, it is 'ok' to have a range from, say, 8 to 42. however, the
+// standard defined unsigned meter types may have restrictions.
+//
+//
+// NOTE! meters are read only controls. also, a meter should only be
+// 'active' when the line it is associated with is active (see fdwLine
+// in MIXERLINE). it is NOT an error to read a meter that is not active--
+// the mixer driver should simply return 'no value' states (usually zero).
+// but it may be useful to stop monitoring a meter if the line is not
+// active...
+//
+#define MC_CONTROLTYPE_UNSIGNEDMETER (MC_CT_CLASS_METER | MC_CT_SC_METER_POLLED | MC_CT_UNITS_UNSIGNED)
+
+
+//
+// Switches (Boolean)
+//
+// MIXERCONTROL.Bounds.lMinimum = ignored (though should be zero)
+// MIXERCONTROL.Bounds.lMaximum = ignored (though should be one)
+//
+// Boolean switches are for enabling/disabling things. they are either
+// on (non-zero for fValue, 1 should be used) or off (zero for fValue).
+// a few standard types are defined in case an application wants to search
+// for a specific type of switch (like mute)--and also to allow a different
+// looking control to be used (say for ON/OFF vs a generic Boolean).
+//
+//
+#define MC_CONTROLTYPE_BOOLEAN (MC_CT_CLASS_SWITCH | MC_CT_SC_SWITCH_BOOLEAN | MC_CT_UNITS_BOOLEAN)
+#define MC_CONTROLTYPE_ONOFF (MC_CONTROLTYPE_BOOLEAN + 1)
+#define MC_CONTROLTYPE_MUTE (MC_CONTROLTYPE_BOOLEAN + 2)
+#define MC_CONTROLTYPE_MONO (MC_CONTROLTYPE_BOOLEAN + 3)
+#define MC_CONTROLTYPE_LOUDNESS (MC_CONTROLTYPE_BOOLEAN + 4)
+#define MC_CONTROLTYPE_STEREOENH (MC_CONTROLTYPE_BOOLEAN + 5)
+
+
+//
+// a button switch is 'write only' and simply signals the driver to do
+// something. an example is a 'Calibrate' button like the one in the
+// existing Turtle Beach MultiSound recording prep utility. an application
+// sets the fValue to TRUE for all buttons that should be pressed. if
+// fValue is FALSE, no action will be taken. reading a button's value will
+// always return FALSE (not depressed).
+//
+#define MC_CONTROLTYPE_BUTTON (MC_CT_CLASS_SWITCH | MC_CT_SC_SWITCH_BUTTON | MC_CT_UNITS_BOOLEAN)
+
+
+//
+// Number (signed integer)
+//
+//
+#define MC_CONTROLTYPE_SIGNED (MC_CT_CLASS_NUMBER | MC_CT_UNITS_SIGNED)
+
+
+//
+// the units are in 10ths of 1 decibel
+//
+//
+#define MC_CONTROLTYPE_DECIBELS (MC_CT_CLASS_NUMBER | MC_CT_UNITS_DECIBELS)
+
+
+//
+// Number (usigned integer)
+//
+//
+#define MC_CONTROLTYPE_UNSIGNED (MC_CT_CLASS_NUMBER | MC_CT_UNITS_UNSIGNED)
+
+//
+// the units are in 10ths of 1 percent
+//
+#define MC_CONTROLTYPE_PERCENT (MC_CT_CLASS_NUMBER | MC_CT_UNITS_PERCENT)
+
+
+
+//
+// Sliders (signed integer)
+//
+// sliders are meant 'positioning' type controls (such as panning).
+// the generic slider must have lMinimum, lMaximum, and cSteps filled
+// in--also note that there is no restriction on these values (see
+// signed meters above for more).
+//
+//
+// MC_CONTROLTYPE_PAN: this is meant to be a real simple pan
+// for stereo lines. the Bounds are fixed to be -32768 to 32767 with 0
+// being dead center. these values are LINEAR and there are no units
+// (-32768 = extreme left, 32767 = extreme right).
+//
+// if an application wants to display a scrollbar that does not contain
+// a bunch of 'dead space', then the scrollbar range should be set to
+// MIXERCONTROL.Metrics.cSteps and lValue should be scaled appropriately
+// with MulDiv.
+//
+// MIXERCONTROL.Bounds.lMinimum = -32768 ALWAYS!
+// MIXERCONTROL.Bounds.lMaximum = 32767 ALWAYS!
+// MIXERCONTROL.Metrics.cSteps = number of steps for range.
+//
+//
+// MC_CONTROLTYPE_QSOUNDPAN: the initial version of Q-Sound (tm,
+// etc by Archer Communications) defines 'Q-Space' as a sortof semi-circle
+// with 33 positions (0 = extreme left, 33 = extreme right, 16 = center).
+// in order to work with our 'slider position' concept, we shift these
+// values to -15 = extreme left, 15 = extreme right, 0 = center.
+//
+// MIXERCONTROL.Bounds.lMinimum = -15 ALWAYS!
+// MIXERCONTROL.Bounds.lMaximum = 15 ALWAYS!
+// MIXERCONTROL.Metrics.cSteps = 1 ALWAYS!
+//
+//
+#define MC_CONTROLTYPE_SLIDER (MC_CT_CLASS_SLIDER | MC_CT_UNITS_SIGNED)
+#define MC_CONTROLTYPE_PAN (MC_CONTROLTYPE_SLIDER + 1)
+#define MC_CONTROLTYPE_QSOUNDPAN (MC_CONTROLTYPE_SLIDER + 2)
+
+
+//
+// Simple Faders (unsigned integer)
+//
+// MIXERCONTROL.Bounds.dwMinimum = 0 ALWAYS!
+// MIXERCONTROL.Bounds.dwMaximum = 65535 ALWAYS!
+//
+// MIXERCONTROL.Metrics.cSteps = number of steps for range.
+//
+// these faders are meant to be as simple as possible for an application
+// to use. the Bounds are fixed to be 0 to 0xFFFF with 0x8000 being half
+// volume/level. these values are LINEAR and there are no units. 0 is
+// minimum volume/level, 0xFFFF is maximum.
+//
+// if an application wants to display a scrollbar that does not contain
+// a bunch of 'dead space', then the scrollbar range should be set to
+// MIXERCONTROL.Metrics.cSteps and dwValue should be scaled appropriately
+// with MulDiv.
+//
+#define MC_CONTROLTYPE_FADER (MC_CT_CLASS_FADER | MC_CT_UNITS_UNSIGNED)
+#define MC_CONTROLTYPE_VOLUME (MC_CONTROLTYPE_FADER + 1)
+#define MC_CONTROLTYPE_BASS (MC_CONTROLTYPE_FADER + 2)
+#define MC_CONTROLTYPE_TREBLE (MC_CONTROLTYPE_FADER + 3)
+#define MC_CONTROLTYPE_EQUALIZER (MC_CONTROLTYPE_FADER + 4)
+
+
+//
+// List (single select)
+//
+// MIXERCONTROL.cMultipleItems = number of items in list
+//
+// M_GCDSF_LISTTEXT should be used to get the text
+// for each item.
+//
+// MIXERCONTROLDETAILS_BOOLEAN should be used to set and retrieve
+// what item is selected (fValue = TRUE if selected).
+//
+// the generic single select lists can be used for many things. some
+// examples are 'Effects'. a mixer driver could provide a list of
+// different effects that could be applied like
+//
+// Reverbs: large hall, warm hall, bright plate, warehouse, etc.
+//
+// Delays: sweep delays, hold delays, 1.34 sec delay, etc.
+//
+// Vocal: recital hall, alcove, delay gate, etc
+//
+// lots of uses! gates, compressors, filters, dynamics, etc, etc.
+//
+//
+// MC_CONTROLTYPE_MUX: a 'Mux' is a single selection multiplexer.
+// usually a Mux is used to select, say, an input source for recording.
+// for example, a mixer driver might have a mux that lets the user select
+// between Microphone or Line-In (but not both!) for recording. this
+// would be a perfect place to use a Mux control. some cards (for example
+// Media Vision's 16 bit Pro Audio cards) can record from multiple sources
+// simultaneously, so they would use a MC_CONTROLTYPE_MIXER, not
+// a MC_CONTROLTYPE_MUX).
+//
+//
+// NOTE! because single select lists can change what selections are
+// possible based on other controls (uhg!), the application must examine
+// the fValue's of all items after setting the control details so the
+// display can be refreshed accordingly. an example might be that an
+// audio card cannot change its input source while recording--so the
+// selection would 'fail' by keeping the fValue on the current selection
+// (but mixerSetControlDetails will succeed!).
+//
+#define MC_CONTROLTYPE_SINGLESELECT (MC_CT_CLASS_LIST | MC_CT_SC_LIST_SINGLE | MC_CT_UNITS_BOOLEAN)
+#define MC_CONTROLTYPE_MUX (MC_CONTROLTYPE_SINGLESELECT + 1)
+
+
+//
+// List (multiple select)
+//
+// MIXERCONTROL.cMultipleItems = number of items in list
+//
+// M_GCDSF_LISTTEXT should be used to get the text
+// for each item.
+//
+// MIXERCONTROLDETAILS_BOOLEAN should be used to set and retrieve
+// what item(s) are selected (fValue = TRUE if selected).
+//
+// NOTE! because multiple select lists can change what selections are
+// selected based on other selections (uhg!), the application must examine
+// the fValue's of all items after setting the control details so the
+// display can be refreshed accordingly. an example might be that an
+// audio card cannot change its input source(s) while recording--so the
+// selection would 'fail' by keeping the fValue on the current selection(s)
+// (but mixerSetControlDetails will succeed!).
+//
+#define MC_CONTROLTYPE_MULTIPLESELECT (MC_CT_CLASS_LIST | MC_CT_SC_LIST_MULTIPLE | MC_CT_UNITS_BOOLEAN)
+#define MC_CONTROLTYPE_MIXER (MC_CONTROLTYPE_MULTIPLESELECT + 1)
+
+
+//
+// Time Controls
+//
+// MIXERCONTROL.Bounds.dwMinimum = min
+// MIXERCONTROL.Bounds.dwMaximum = max
+//
+// time controls are meant for inputing time information. these can be
+// used for effects such as delay, reverb, etc.
+//
+//
+#define MC_CONTROLTYPE_MICROTIME (MC_CT_CLASS_TIME | MC_CT_SC_TIME_MICROSECS | MC_CT_UNITS_UNSIGNED)
+
+#define MC_CONTROLTYPE_MILLITIME (MC_CT_CLASS_TIME | MC_CT_SC_TIME_MILLISECS | MC_CT_UNITS_UNSIGNED)
+
+
+
+//
+// MIXERLINECONTROLS
+//
+//
+//
+typedef struct tMIXERLINECONTROLS
+{
+ DWORD cbStruct; // size in bytes of MIXERLINECONTROLS
+ DWORD dwLineID; // line id (from MIXERLINE.dwLineID)
+ union
+ {
+ DWORD dwControlID; // M_GLCONTROLSF_ONEBYID
+ DWORD dwControlType; // M_GLCONTROLSF_ONEBYTYPE
+ };
+ DWORD cControls; // count of controls pmxctrl points to
+ DWORD cbmxctrl; // size in bytes of _one_ MIXERCONTROL
+ LPMIXERCONTROL pamxctrl; // pointer to first MIXERCONTROL array
+} MIXERLINECONTROLS;
+typedef MIXERLINECONTROLS *PMIXERLINECONTROLS;
+typedef MIXERLINECONTROLS FAR *LPMIXERLINECONTROLS;
+
+//
+//
+//
+MMRESULT MIXAPI mixerGetLineControls
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERLINECONTROLS pmxlc,
+ DWORD fdwControls
+);
+
+#define M_GLCONTROLSF_ALL 0x00000000L
+#define M_GLCONTROLSF_ONEBYID 0x00000001L
+#define M_GLCONTROLSF_ONEBYTYPE 0x00000002L
+
+#define M_GLCONTROLSF_QUERYMASK 0x0000000FL
+
+#define M_GLCONTROLSF_VALID (MIXER_OBJECTF_TYPEMASK | /* ;Internal */ \
+ M_GLCONTROLSF_QUERYMASK) // ;Internal
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerGetControlDetails()
+//
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+typedef struct tMIXERCONTROLDETAILS
+{
+ DWORD cbStruct; // size in bytes of MIXERCONTROLDETAILS
+ DWORD dwControlID; // control id to get/set details on
+
+ DWORD cChannels; // number of channels in paDetails array
+
+ union
+ {
+ HWND hwndOwner; // for M_SCDF_CUSTOM
+ DWORD cMultipleItems; // if _MULTIPLE, the number of items per channel
+ };
+
+ DWORD cbDetails; // size of _one_ details_XX struct
+ LPVOID paDetails; // pointer to array of details_XX structs
+
+} MIXERCONTROLDETAILS, *PMIXERCONTROLDETAILS, FAR *LPMIXERCONTROLDETAILS;
+
+
+//
+// M_GCDSF_LISTTEXT
+//
+//
+typedef struct tMIXERCONTROLDETAILS_LISTTEXT
+{
+ DWORD dwParam1;
+ DWORD dwParam2;
+ char szName[MIXER_LONG_NAME_CHARS];
+} MIXERCONTROLDETAILS_LISTTEXT;
+typedef MIXERCONTROLDETAILS_LISTTEXT *PMIXERCONTROLDETAILS_LISTTEXT;
+typedef MIXERCONTROLDETAILS_LISTTEXT FAR *LPMIXERCONTROLDETAILS_LISTTEXT;
+
+
+//
+// M_GCDSF_VALUE
+//
+//
+typedef struct tMIXERCONTROLDETAILS_BOOLEAN
+{
+ LONG fValue;
+} MIXERCONTROLDETAILS_BOOLEAN,
+ *PMIXERCONTROLDETAILS_BOOLEAN,
+ FAR *LPMIXERCONTROLDETAILS_BOOLEAN;
+
+typedef struct tMIXERCONTROLDETAILS_SIGNED
+{
+ LONG lValue;
+} MIXERCONTROLDETAILS_SIGNED,
+ *PMIXERCONTROLDETAILS_SIGNED,
+ FAR *LPMIXERCONTROLDETAILS_SIGNED;
+
+
+typedef struct tMIXERCONTROLDETAILS_UNSIGNED
+{
+ DWORD dwValue;
+} MIXERCONTROLDETAILS_UNSIGNED,
+ *PMIXERCONTROLDETAILS_UNSIGNED,
+ FAR *LPMIXERCONTROLDETAILS_UNSIGNED;
+
+
+
+//
+//
+//
+//
+MMRESULT MIXAPI mixerGetControlDetails
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+);
+
+#define M_GCDSF_VALUE 0x00000000L
+#define M_GCDSF_LISTTEXT 0x00000001L
+
+#define M_GCDSF_QUERYMASK 0x0000000FL
+
+#define M_GCDSF_VALID (MIXER_OBJECTF_TYPEMASK | /* ;Internal */ \
+ M_GCDSF_QUERYMASK) /* ;Internal */
+
+
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+//
+// mixerSetControlDetails()
+//
+//
+//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
+
+MMRESULT MIXAPI mixerSetControlDetails
+(
+ HMIXEROBJ hmxobj,
+ LPMIXERCONTROLDETAILS pmxcd,
+ DWORD fdwDetails
+);
+
+#define M_SCDF_VALUE 0x00000000L
+#define M_SCDF_CUSTOM 0x00000001L
+
+#define M_SCDF_QUERYMASK 0x0000000FL
+
+#define M_SCDF_VALID (MIXER_OBJECTF_TYPEMASK | /* ;Internal */ \
+ M_SCDF_QUERYMASK) /* ;Internal */
+
+#endif // MM_MIXM_LINE_CHANGE
+
+#endif // MMNOMIXER
+#endif // _INC_MMSYSTEM
+
+
+
+//==========================================================================;
+//
+// Mixer Driver Definitions
+//
+//
+//
+//==========================================================================;
+
+#ifdef _INC_MMDDK
+#ifndef MMNOMIXERDEV
+
+#ifndef MAXMIXERDRIVERS
+
+//
+// maximum number of mixer drivers that can be loaded by MSMIXMGR.DLL
+//
+#define MAXMIXERDRIVERS 10
+
+
+//
+// mixer device open information structure
+//
+//
+typedef struct tMIXEROPENDESC
+{
+ HMIXER hmx; // handle that will be used
+ LPVOID pReserved0; // reserved--driver should ignore
+ DWORD dwCallback; // callback
+ DWORD dwInstance; // app's private instance information
+
+} MIXEROPENDESC, *PMIXEROPENDESC, FAR *LPMIXEROPENDESC;
+
+
+
+//
+//
+//
+//
+#define MXDM_INIT 100
+#define MXDM_USER DRV_USER
+
+#define MXDM_BASE (1)
+#define MXDM_GETNUMDEVS (MXDM_BASE + 0)
+#define MXDM_GETDEVCAPS (MXDM_BASE + 1)
+#define MXDM_OPEN (MXDM_BASE + 2)
+#define MXDM_CLOSE (MXDM_BASE + 3)
+#define MXDM_GETLINEINFO (MXDM_BASE + 4)
+#define MXDM_GETLINECONTROLS (MXDM_BASE + 5)
+#define MXDM_GETCONTROLDETAILS (MXDM_BASE + 6)
+#define MXDM_SETCONTROLDETAILS (MXDM_BASE + 7)
+
+#endif // MAXMIXERDRIVERS
+
+#endif // MMNOMIXERDEV
+#endif // _INC_MMDDK
+
+
+#ifdef __cplusplus
+} // end of extern "C" {
+#endif // __cplusplus
+
+#ifndef RC_INVOKED
+#pragma pack() // revert to default packing
+#endif
+
+#endif // _INC_MSMIXMGR
diff --git a/private/mvdm/wow16/mmsystem/playwav.c b/private/mvdm/wow16/mmsystem/playwav.c
new file mode 100644
index 000000000..79b6d0b58
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/playwav.c
@@ -0,0 +1,449 @@
+#include <windows.h>
+#define MMNOTIMER
+#define MMNOSEQ
+#define MMNOJOY
+#define MMNOMIDI
+#define MMNOMCI
+#include "mmsystem.h"
+#include "mmsysi.h" // to get DOUT() and _hread()
+#include "playwav.h"
+
+//
+// These globals are used to keep track of the currently playing sound, and
+// the handle to the wave device. only 1 sound can be playing at a time.
+//
+
+static HWAVEOUT hWaveOut; // handle to open wave device
+LPWAVEHDR lpWavHdr; // current wave file playing
+
+/* flags for _lseek */
+#define SEEK_CUR 1
+#define SEEK_END 2
+#define SEEK_SET 0
+
+#define FMEM (GMEM_MOVEABLE|GMEM_SHARE)
+
+BOOL NEAR PASCAL soundInitWavHdr(LPWAVEHDR lpwh, LPCSTR lpMem, DWORD dwLen);
+BOOL NEAR PASCAL soundOpen(HGLOBAL hSound, UINT wFlags);
+BOOL NEAR PASCAL soundClose(void);
+void NEAR PASCAL soundWait(void);
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api void | WaveOutNotify | called by mmWndProc when it recives a
+ * MM_WOM_DONE message
+ * @rdesc None.
+ *
+ ****************************************************************************/
+
+void FAR PASCAL WaveOutNotify(WPARAM wParam, LPARAM lParam)
+{
+ if (hWaveOut && !(lpWavHdr->dwFlags & WHDR_DONE))
+ return; // wave is not done! get out
+
+ //
+ // wave file is done! release the device
+ //
+
+ DOUT("MMSYSTEM: ASYNC sound done, closing wave device\r\n");
+
+ soundClose();
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api BOOL | soundPlay | Pretty much speaks for itself!
+ *
+ * @parm HGLOBAL | hSound | The sound resource to play.
+ *
+ * @parm wFlags | UINT | flags controlling sync/async etc.
+ *
+ * @flag SND_SYNC | play synchronously (default)
+ * @flag SND_ASYNC | play asynchronously
+ *
+ * @rdesc Returns TRUE if successful and FALSE on failure.
+ ****************************************************************************/
+BOOL NEAR PASCAL soundPlay(HGLOBAL hSound, UINT wFlags)
+{
+ //
+ // Before playing a sound release it
+ //
+ soundClose();
+
+ //
+ // open the sound device and write the sound to it.
+ //
+ if (!soundOpen(hSound, wFlags))
+ return FALSE;
+
+ if (!(wFlags & SND_ASYNC))
+ {
+ soundWait();
+ soundClose();
+ }
+ return TRUE;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api BOOL | soundOpen | Open the wave device and write a sound to it.
+ *
+ * @parm HGLOBAL | hSound | The sound resource to play.
+ *
+ * @rdesc Returns TRUE if successful and FALSE on failure.
+ ****************************************************************************/
+BOOL NEAR PASCAL soundOpen(HGLOBAL hSound, UINT wFlags)
+{
+ UINT wErr;
+
+ if (!hSound || !hwndNotify)
+ return FALSE;
+
+ if (hWaveOut)
+ {
+ DOUT("MMSYSTEM: soundOpen() wave device is currently open.\r\n");
+ return FALSE;
+ }
+
+ lpWavHdr = (LPWAVEHDR)GlobalLock(hSound);
+
+ if (!lpWavHdr)
+ {
+#ifdef DEBUG
+ if ((GlobalFlags(hSound) & GMEM_DISCARDED))
+ DOUT("MMSYSTEM: sound was discarded before play could begin.\r\n");
+#endif
+ return FALSE;
+ }
+
+ //
+ // open the wave device, open any wave device that supports the
+ // format
+ //
+ wErr = waveOutOpen(&hWaveOut, // returns handle to device
+ WAVE_MAPPER, // device id (any device)
+ (LPWAVEFORMAT)lpWavHdr->dwUser, // wave format
+ (DWORD)(UINT)hwndNotify, // callback function
+ 0L, // callback instance data
+ WAVE_ALLOWSYNC | CALLBACK_WINDOW); // flags
+
+ if (wErr != 0)
+ {
+ DOUT("MMSYSTEM: soundOpen() unable to open wave device\r\n");
+ GlobalUnlock(hSound);
+ lpWavHdr = NULL;
+ hWaveOut = NULL;
+ return FALSE;
+ }
+
+ wErr = waveOutPrepareHeader(hWaveOut, lpWavHdr, sizeof(WAVEHDR));
+
+ if (wErr != 0)
+ {
+ DOUT("MMSYSTEM: soundOpen() waveOutPrepare failed\r\n");
+ soundClose();
+ return FALSE;
+ }
+
+ //
+ // Only allow sound looping if playing ASYNC sounds
+ //
+ if ((wFlags & SND_ASYNC) && (wFlags & SND_LOOP))
+ {
+ lpWavHdr->dwLoops = 0xFFFFFFFF; // infinite loop
+ lpWavHdr->dwFlags |= WHDR_BEGINLOOP|WHDR_ENDLOOP;
+ }
+ else
+ {
+ lpWavHdr->dwLoops = 0;
+ lpWavHdr->dwFlags &=~(WHDR_BEGINLOOP|WHDR_ENDLOOP);
+ }
+
+ lpWavHdr->dwFlags &= ~WHDR_DONE; // mark as not done!
+ wErr = waveOutWrite(hWaveOut, lpWavHdr, sizeof(WAVEHDR));
+
+ if (wErr != 0)
+ {
+ DOUT("MMSYSTEM: soundOpen() waveOutWrite failed\r\n");
+ soundClose();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @func BOOL | soundClose | This function closes the sound device
+ *
+ * @rdesc Returns TRUE if successful and FALSE on failure.
+ ****************************************************************************/
+BOOL NEAR PASCAL soundClose(void)
+{
+ UINT wErr;
+
+ //
+ // Do we have the sound device open?
+ //
+ if (!lpWavHdr || !hWaveOut)
+ return TRUE;
+
+ //
+ // if the block is still playing, stop it!
+ //
+ if (!(lpWavHdr->dwFlags & WHDR_DONE))
+ waveOutReset(hWaveOut);
+
+#ifdef DEBUG
+ if (!(lpWavHdr->dwFlags & WHDR_DONE))
+ {
+ DOUT("MMSYSTEM: soundClose() data is not DONE!???\r\n");
+ lpWavHdr->dwFlags |= WHDR_DONE;
+ }
+
+ if (!(lpWavHdr->dwFlags & WHDR_PREPARED))
+ {
+ DOUT("MMSYSTEM: soundClose() data not prepared???\r\n");
+ }
+#endif
+
+ //
+ // unprepare the data anyway!
+ //
+ wErr = waveOutUnprepareHeader(hWaveOut, lpWavHdr, sizeof(WAVEHDR));
+
+ if (wErr != 0)
+ {
+ DOUT("MMSYSTEM: soundClose() waveOutUnprepare failed?\r\n");
+ }
+
+ //
+ // finaly actually close the device, and unlock the data
+ //
+ waveOutClose(hWaveOut);
+ GlobalUnlock((HGLOBAL)HIWORD(lpWavHdr));
+
+ //
+ // update globals, claiming the device is closed.
+ //
+ hWaveOut = NULL;
+ lpWavHdr = NULL;
+ return TRUE;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api void | soundWait | wait for the sound device to complete
+ *
+ * @rdesc none
+ ****************************************************************************/
+void NEAR PASCAL soundWait(void)
+{
+ if (lpWavHdr)
+ while (!(lpWavHdr->dwFlags & WHDR_DONE))
+ ;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api void | soundFree | This function frees a sound resource created
+ * with soundLoadFile or soundLoadMemory
+ *
+ * @rdesc Returns TRUE if successful and FALSE on failure.
+ ****************************************************************************/
+void NEAR PASCAL soundFree(HGLOBAL hSound)
+{
+ if (!hSound)
+ return;
+
+ // !!! we should only close the sound device iff this hSound is playing!
+ //
+ soundClose();
+ GlobalFree(hSound);
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api HGLOBAL | soundLoadFile | Loads a specified sound resource from a
+ * file into a global, discardable object.
+ *
+ * @parm LPCSTR | lpszFile | The file from which to load the sound resource.
+ *
+ * @rdesc Returns NULL on failure, GLOBAL HANDLE to a WAVEHDR iff success
+ ****************************************************************************/
+HGLOBAL NEAR PASCAL soundLoadFile(LPCSTR szFileName)
+{
+ HFILE fh;
+ OFSTRUCT of;
+ DWORD dwSize;
+ LPSTR lpData;
+ HGLOBAL h;
+ UINT wNameLen;
+
+ // open the file
+ fh = OpenFile(szFileName, &of, OF_READ | OF_SHARE_DENY_NONE);
+ if (fh == HFILE_ERROR)
+ return NULL;
+
+ wNameLen = lstrlen(szFileName) + 1;
+ dwSize = _llseek(fh, 0l, SEEK_END); // get the size of file
+ _llseek(fh, 0l, SEEK_SET); // seek back to the start
+
+ // allocate some discardable memory for a wave hdr, name and the file data.
+ h = GlobalAlloc(FMEM+GMEM_DISCARDABLE, sizeof(WAVEHDR) + wNameLen + dwSize);
+ if (!h)
+ goto error1;
+
+ // lock it down
+ lpData = GlobalLock(h);
+
+ // read the file into the memory block
+
+ if (_hread(fh,lpData+sizeof(WAVEHDR)+wNameLen,(LONG)dwSize) != (LONG)dwSize)
+ goto error3;
+
+ // do the rest of it from the memory image
+ if (!soundInitWavHdr((LPWAVEHDR)lpData, lpData+sizeof(WAVEHDR)+wNameLen, dwSize))
+ goto error3;
+
+ _lclose(fh);
+
+ lstrcpy(lpData+sizeof(WAVEHDR), szFileName);
+ GlobalUnlock(h);
+ return h;
+
+error3:
+ GlobalUnlock(h);
+ GlobalFree(h);
+error1:
+ _lclose(fh);
+ return NULL;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api HGLOBAL | soundLoadMemory | Loads a user specified sound resource from a
+ * a memory block supplied by the caller.
+ *
+ * @parm LPCSTR | lpMem | Pointer to a memory image of the file
+ *
+ * @rdesc Returns NULL on failure, GLOBAL HANDLE to a WAVEHDR iff success
+ ****************************************************************************/
+HGLOBAL NEAR PASCAL soundLoadMemory(LPCSTR lpMem)
+{
+ HGLOBAL h;
+ LPSTR lp;
+
+ // allocate some memory, for a wave hdr
+ h = GlobalAlloc(FMEM, (LONG)sizeof(WAVEHDR)+1);
+ if (!h)
+ goto error1;
+
+ // lock it down
+ lp = GlobalLock(h);
+
+ //
+ // we must assume the memory pointer is correct! (hence the -1l)
+ //
+ if (!soundInitWavHdr((LPWAVEHDR)lp, lpMem, -1l))
+ goto error3;
+
+ lp[sizeof(WAVEHDR)] = (char)0; // No file name for memory file
+ GlobalUnlock(h);
+ return h;
+
+error3:
+ GlobalUnlock(h);
+ GlobalFree(h);
+error1:
+ return NULL;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL
+ *
+ * @api BOOL | soundInitWavHdr | Initializes a WAVEHDR data structure from a
+ * pointer to a memory image of a RIFF WAV file.
+ *
+ * @parm LPWAVHDR | lpwh | Pointer to a WAVEHDR
+ *
+ * @parm LPCSTR | lpMem | Pointer to a memory image of a RIFF WAV file
+ *
+ * @rdesc Returns FALSE on failure, TRUE on success.
+ *
+ * @comm the dwUser field of the WAVEHDR structure is initialized to point
+ * to the WAVEFORMAT structure that is inside the RIFF data
+ *
+ ****************************************************************************/
+BOOL NEAR PASCAL soundInitWavHdr(LPWAVEHDR lpwh, LPCSTR lpMem, DWORD dwLen)
+{
+ FPFileHeader fpHead;
+ LPWAVEFORMAT lpFmt;
+ LPCSTR lpData;
+ DWORD dwFileSize,dwCurPos;
+ DWORD dwSize;
+
+ if (dwLen < sizeof(FileHeader))
+ return FALSE;
+
+ // assume the first few bytes are the file header
+ fpHead = (FPFileHeader) lpMem;
+
+ // check that it's a valid RIFF file and a valid WAVE form.
+ if (fpHead->dwRiff != RIFF_FILE || fpHead->dwWave != RIFF_WAVE ) {
+ return FALSE;
+ }
+
+ dwFileSize = fpHead->dwSize;
+ dwCurPos = sizeof(FileHeader);
+ lpData = lpMem + sizeof(FileHeader);
+
+ if (dwLen < dwFileSize) // RIFF header
+ return FALSE;
+
+ // scan until we find the 'fmt' chunk
+ while( 1 ) {
+ if( ((FPChunkHeader)lpData)->dwCKID == RIFF_FORMAT )
+ break; // from the while loop that's looking for it
+ dwCurPos += ((FPChunkHeader)lpData)->dwSize + sizeof(ChunkHeader);
+ if( dwCurPos >= dwFileSize )
+ return FALSE;
+ lpData += ((FPChunkHeader)lpData)->dwSize + sizeof(ChunkHeader);
+ }
+
+ // now we're at the beginning of the 'fmt' chunk data
+ lpFmt = (LPWAVEFORMAT) (lpData + sizeof(ChunkHeader));
+
+ // scan until we find the 'data' chunk
+ lpData = lpData + ((FPChunkHeader)lpData)->dwSize + sizeof(ChunkHeader);
+ while( 1 ) {
+ if( ((FPChunkHeader)lpData)->dwCKID == RIFF_CHANNEL)
+ break; // from the while loop that's looking for it
+ dwCurPos += ((FPChunkHeader)lpData)->dwSize + sizeof(ChunkHeader);
+ if( dwCurPos >= dwFileSize )
+ return NULL;
+ lpData += ((FPChunkHeader)lpData)->dwSize + sizeof(ChunkHeader);
+ }
+
+ // now we're at the beginning of the 'data' chunk data
+ dwSize = ((FPChunkHeader)lpData)->dwSize;
+ lpData = lpData + sizeof(ChunkHeader);
+
+ // initialize the WAVEHDR
+
+ lpwh->lpData = (LPSTR)lpData; // pointer to locked data buffer
+ lpwh->dwBufferLength = dwSize; // length of data buffer
+ lpwh->dwUser = (DWORD)lpFmt; // for client's use
+ lpwh->dwFlags = WHDR_DONE; // assorted flags (see defines)
+ lpwh->dwLoops = 0;
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow16/mmsystem/playwav.h b/private/mvdm/wow16/mmsystem/playwav.h
new file mode 100644
index 000000000..50dbabe79
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/playwav.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+
+ playwav.h
+
+ ****************************************************************************/
+
+BOOL NEAR PASCAL soundPlay(HGLOBAL hSound, UINT wFlags);
+void NEAR PASCAL soundFree(HGLOBAL hSound);
+HGLOBAL NEAR PASCAL soundLoadFile(LPCSTR szFileName);
+HGLOBAL NEAR PASCAL soundLoadMemory(LPCSTR lpMem);
+
+/*****************************************************************************
+
+ STUFF TO SUPPORT MS-WAVE FORMAT FILES
+
+ ****************************************************************************/
+
+#define FOURCC( ch0, ch1, ch2, ch3 ) \
+ ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \
+ ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) )
+
+typedef struct _FileHeader {
+ DWORD dwRiff;
+ DWORD dwSize;
+ DWORD dwWave;
+} FileHeader;
+typedef FileHeader FAR *FPFileHeader;
+
+typedef struct _ChunkHeader {
+ DWORD dwCKID;
+ DWORD dwSize;
+} ChunkHeader;
+typedef ChunkHeader FAR *FPChunkHeader;
+
+/* Chunk Types */
+#define RIFF_FILE FOURCC('R','I','F','F')
+#define RIFF_WAVE FOURCC('W','A','V','E')
+#define RIFF_FORMAT FOURCC('f','m','t',' ')
+#define RIFF_CHANNEL FOURCC('d','a','t','a')
diff --git a/private/mvdm/wow16/mmsystem/rinc/mmsysver.h b/private/mvdm/wow16/mmsystem/rinc/mmsysver.h
new file mode 100644
index 000000000..8ecb05083
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/rinc/mmsysver.h
@@ -0,0 +1,23 @@
+/*
+ * mmsysver.h - internal header file to define the build version for sonic
+ *
+ */
+
+/*
+ * All strings MUST have an explicit \0
+ *
+ * MMSYSRELEASE should be changed every build
+ *
+ * Version string should be changed each build
+ *
+ * Remove build extension on final release
+ */
+
+#define OFFICIAL 1
+#define FINAL 1
+
+#define MMSYSVERSION 03
+#define MMSYSREVISION 10
+#define MMSYSRELEASE 103
+
+#define MMSYSVERSIONSTR "3.1\0"
diff --git a/private/mvdm/wow16/mmsystem/sound.c b/private/mvdm/wow16/mmsystem/sound.c
new file mode 100644
index 000000000..4229dd9c0
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/sound.c
@@ -0,0 +1,323 @@
+/*
+ sound.c
+
+ Level 1 kitchen sink DLL sound driver functions
+
+ Copyright (c) Microsoft Corporation 1990. All rights reserved
+
+*/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "playwav.h"
+
+BOOL WINAPI IsTaskLocked(void); // In Kernel
+
+//
+// place sndPlaySound in the _TEXT segment so the entire wave segment
+// does not come in if no wave devices are loaded.
+//
+
+#pragma alloc_text(_TEXT, sndPlaySound)
+
+static SZCODE szNull[] = "";
+static SZCODE szSoundSection[] = "sounds"; // WIN.INI section for sounds
+ SZCODE szSystemDefault[] = "SystemDefault"; // Name of the default sound
+
+#define SOUNDNAMELEN 128
+static HGLOBAL hCurrentSound; // handle to current sound.
+
+extern LPWAVEHDR lpWavHdr; // current playing sound PLAYWAV.C
+
+/****************************************************************************/
+
+static void PASCAL NEAR GetSoundName(
+ LPCSTR lszSoundName,
+ LPSTR lszBuffer)
+{
+ OFSTRUCT of;
+ int i;
+
+ //
+ // if the sound is defined in the [sounds] section of WIN.INI
+ // get it and remove the description, otherwise assume it is a
+ // file and qualify it.
+ //
+ GetProfileString(szSoundSection, lszSoundName, lszSoundName, lszBuffer, SOUNDNAMELEN);
+
+ // remove any trailing text first
+
+ for (i = 0; lszBuffer[i] && (lszBuffer[i] != ' ') && (lszBuffer[i] != '\t') && (lszBuffer[i] != ','); i++)
+ ;
+ lszBuffer[i] = (char)0;
+
+ if (OpenFile(lszBuffer, &of, OF_EXIST | OF_READ | OF_SHARE_DENY_NONE) != HFILE_ERROR)
+ OemToAnsi(of.szPathName, lszBuffer);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL
+ *
+ * @api BOOL | sndPlaySound | This function plays a waveform
+ * sound specified by a filename or by an entry in the [sounds] section
+ * of WIN.INI. If the sound can't be found, it plays the
+ * default sound specified by the SystemDefault entry in the
+ * [sounds] section of WIN.INI. If there is no SystemDefault
+ * entry or if the default sound can't be found, the function
+ * makes no sound and returns FALSE.
+ *
+ * @parm LPCSTR | lpszSoundName | Specifies the name of the sound to play.
+ * The function searches the [sounds] section of WIN.INI for an entry
+ * with this name and plays the associated waveform file.
+ * If no entry by this name exists, then it assumes the name is
+ * the name of a waveform file. If this parameter is NULL, any
+ * currently playing sound is stopped.
+ *
+ * @parm UINT | wFlags | Specifies options for playing the sound using one
+ * or more of the following flags:
+ *
+ * @flag SND_SYNC | The sound is played synchronously and the
+ * function does not return until the sound ends.
+ * @flag SND_ASYNC | The sound is played asynchronously and the
+ * function returns immediately after beginning the sound. To terminate
+ * an asynchronously-played sound, call <f sndPlaySound> with
+ * <p lpszSoundName> set to NULL.
+ * @flag SND_NODEFAULT | If the sound can't be found, the function
+ * returns silently without playing the default sound.
+ * @flag SND_MEMORY | The parameter specified by <p lpszSoundName>
+ * points to an in-memory image of a waveform sound.
+ * @flag SND_LOOP | The sound will continue to play repeatedly
+ * until <f sndPlaySound> is called again with the
+ * <p lpszSoundName> parameter set to NULL. You must also specify the
+ * SND_ASYNC flag to loop sounds.
+ * @flag SND_NOSTOP | If a sound is currently playing, the
+ * function will immediately return FALSE without playing the requested
+ * sound.
+ *
+ * @rdesc Returns TRUE if the sound is played, otherwise
+ * returns FALSE.
+ *
+ * @comm The sound must fit in available physical memory and be playable
+ * by an installed waveform audio device driver. The directories
+ * searched for sound files are, in order: the current directory;
+ * the Windows directory; the Windows system directory; the directories
+ * listed in the PATH environment variable; the list of directories
+ * mapped in a network. See the Windows <f OpenFile> function for
+ * more information about the directory search order.
+ *
+ * If you specify the SND_MEMORY flag, <p lpszSoundName> must point
+ * to an in-memory image of a waveform sound. If the sound is stored
+ * as a resource, use <f LoadResource> and <f LockResource> to load
+ * and lock the resource and get a pointer to it. If the sound is not
+ * a resource, you must use <f GlobalAlloc> with the GMEM_MOVEABLE and
+ * GMEM_SHARE flags set and then <f GlobalLock> to allocate and lock
+ * memory for the sound.
+ *
+ * @xref MessageBeep
+ ****************************************************************************/
+
+BOOL WINAPI sndPlaySound(LPCSTR szSoundName, UINT wFlags)
+{
+ //
+ // !!! quick exit for no wave devices !!!
+ //
+ static UINT wTotalWaveOutDevs = -1;
+
+ if (wTotalWaveOutDevs == -1 ) {
+ wTotalWaveOutDevs = waveOutGetNumDevs();
+ }
+
+ if (wTotalWaveOutDevs)
+ return sndPlaySoundI(szSoundName, wFlags);
+ else
+ return FALSE;
+}
+
+/****************************************************************************/
+/*
+@doc INTERNAL
+
+@func BOOL | sndPlaySoundI | Internal version of <f>sndPlaySound<d> which
+ resides in the WAVE segment instead.
+
+ If the SND_NOSTOP flag is specifed and a wave file is currently
+ playing, or if for some reason no mmsystem window is present, the
+ function returns failure immediately. The first condition ensures
+ that a current sound is not interrupted if the flag is set. The
+ second condition is only in case of some start up error in which
+ the notification window was not created, or mmsystem was not
+ specified in the [drivers] line, and therefore never loaded.
+
+ Next, if the <p>lszSoundName<d> parameter does not represent a memory
+ file, and it is non-NULL, then it must represent a string. Therefore
+ the string must be parsed before sending the sound message to the
+ mmsystem window. This is because the mmsystem window may reside in a
+ a different task than the task which is calling the function, and
+ would most likely have a different current directory.
+
+ In this case, the parameter is first checked to determine if it
+ actually contains anything. For some reason a zero length string
+ was determined to be able to return TRUE from this function, so that
+ is checked.
+
+ Next the string is checked against INI entries, then parsed.
+
+ After parsing the sound name, ensure that a task switch only occurs if
+ the sound is asyncronous (SND_ASYNC), and a previous sound does not
+ need to be discarded.
+
+ If a task switch is needed, first ensure that intertask messages can
+ be sent by checking to see that this task is not locked, or that the
+ notification window is in the current task.
+
+@parm LPCSTR | lszSoundName | Specifies the name of the sound to play.
+
+@parm UINT | wFlags | Specifies options for playing the sound.
+
+@rdesc Returns TRUE if the function was successful, else FALSE if an error
+ occurred.
+*/
+BOOL FAR PASCAL sndPlaySoundI(LPCSTR lszSoundName, UINT wFlags)
+{
+ BOOL fPlayReturn;
+ PSTR szSoundName;
+
+ V_FLAGS(wFlags, SND_VALID, sndPlaySound, NULL);
+
+ if ((wFlags & SND_LOOP) && !(wFlags & SND_ASYNC)) {
+ LogParamError(ERR_BAD_FLAGS, (FARPROC)sndPlaySound, (LPVOID)(DWORD)wFlags);
+ return FALSE;
+ }
+
+ if (!(wFlags & SND_MEMORY) && lszSoundName)
+ V_STRING(lszSoundName, 128, FALSE);
+
+#ifdef DEBUG
+ if (wFlags & SND_MEMORY) {
+ DPRINTF1("MMSYSTEM: sndPlaySound(%lx)\r\n", lszSoundName);
+ }
+ else if (lszSoundName) {
+ if (wFlags & SND_ASYNC) {
+ if (wFlags & SND_LOOP) {
+ DPRINTF1("MMSYSTEM: sndPlaySound(%ls, SND_ASYNC|SND_LOOP)\r\n", lszSoundName);
+ }
+ else {
+ DPRINTF1("MMSYSTEM: sndPlaySound(%ls, SND_ASYNC)\r\n", lszSoundName);
+ }
+ }
+ else
+ DPRINTF1("MMSYSTEM: sndPlaySound(%ls, SND_SYNC)\r\n", lszSoundName);
+ }
+ else
+ DOUT("MMSYSTEM: sndPlaySound(NULL)\r\n");
+
+#endif //ifdef DEBUG
+
+ if (((wFlags & SND_NOSTOP) && lpWavHdr) || !hwndNotify)
+ return FALSE;
+
+ if (!(wFlags & SND_MEMORY) && lszSoundName) {
+ if (!*lszSoundName)
+ return TRUE;
+ if (!(szSoundName = (PSTR)LocalAlloc(LMEM_FIXED, SOUNDNAMELEN)))
+ return FALSE;
+ GetSoundName(lszSoundName, szSoundName);
+ lszSoundName = (LPCSTR)szSoundName;
+ } else
+ szSoundName = NULL;
+
+ if (!(wFlags & SND_ASYNC) && !lpWavHdr)
+ fPlayReturn = sndMessage((LPSTR)lszSoundName, wFlags);
+ else {
+ if (!IsTaskLocked() || (GetWindowTask(hwndNotify) == GetCurrentTask())) {
+ fPlayReturn = (BOOL)(LONG)SendMessage(hwndNotify, MM_SND_PLAY, (WPARAM)wFlags, (LPARAM)lszSoundName);
+ } else
+ fPlayReturn = FALSE;
+ }
+ if (szSoundName)
+ LocalFree((HLOCAL)szSoundName);
+
+ return fPlayReturn;
+}
+
+/****************************************************************************/
+static BOOL PASCAL NEAR SetCurrentSound(
+ LPCSTR lszSoundName)
+{
+ HGLOBAL hSound;
+ BOOL f;
+ LPSTR lp;
+
+ if (hCurrentSound && (lp = GlobalLock(hCurrentSound))) {
+ f = lstrcmpi(lszSoundName, lp + sizeof(WAVEHDR)) == 0;
+ GlobalUnlock(hCurrentSound);
+ if (f)
+ return TRUE;
+ }
+
+ DPRINTF(("MMSYSTEM: soundLoadFile(%ls)\r\n",lszSoundName));
+
+ if (hSound = soundLoadFile(lszSoundName)) {
+ soundFree(hCurrentSound);
+ hCurrentSound = hSound;
+ return TRUE;
+ }
+ return FALSE;
+}
+/****************************************************************************/
+/*
+@doc INTERNAL
+
+@func BOOL | sndMessage | This function is called in response to an
+ MM_SND_PLAY message sent to the mmsystem window, and attempts to
+ play the specified file, or dump current sound caching.
+
+ If <p>lszSoundName<d> is NULL, any currently cached sound is
+ discarded, and the function returns success.
+
+ If the SND_MEMORY flag is set, then <p>lszSoundName<d> actually
+ points to a buffer containing a RIFF format WAVE memory file, and
+ the function attempts to play it. The load function performs
+ validation on this memory file. Unlike playing sound names,
+ memory files are not cached for future use.
+
+ Otherwise the <p>lszSoundName<d> parameter is actually an INI entry
+ or file name. The function initially attempts to load that sound,
+ and if it fails, attempts to load the system default sound. Note of
+ course that the SND_NODEFAULT flag is first checked to determine if
+ the default sound is to be played when the original name cannot be
+ located. If no default is wanted, or the default cannot be located,
+ the function returns failure. Note that in calling <f>GetSoundName<d>,
+ the <p>lszSoundName<d> parameter is modified. This function assumes
+ that the parameter passed has been previously allocated if a string is
+ passed to this function, and is not the actual user's parameter passed
+ to <f>sndPlaySound<d>.
+
+@parm LPSTR | lszSoundName | Specifies the name of the sound to play.
+
+@parm UINT | wFlags | Specifies options for playing the sound.
+
+@rdesc Returns TRUE if the function was successful, else FALSE if an error
+ occurred.
+*/
+BOOL FAR PASCAL sndMessage(LPSTR lszSoundName, UINT wFlags)
+{
+ if (!lszSoundName) {
+ soundFree(hCurrentSound);
+ hCurrentSound = NULL;
+ return TRUE;
+ }
+ if (wFlags & SND_MEMORY) {
+ soundFree(hCurrentSound);
+ hCurrentSound = soundLoadMemory(lszSoundName);
+ } else if (!SetCurrentSound(lszSoundName)) {
+ if (wFlags & SND_NODEFAULT)
+ return FALSE;
+ GetSoundName(szSystemDefault, lszSoundName);
+ if (!SetCurrentSound(lszSoundName))
+ return FALSE;
+ }
+ return soundPlay(hCurrentSound, wFlags);
+}
diff --git a/private/mvdm/wow16/mmsystem/stack.asm b/private/mvdm/wow16/mmsystem/stack.asm
new file mode 100644
index 000000000..b5f50c612
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/stack.asm
@@ -0,0 +1,1101 @@
+ page 80,132
+;***************************************************************************;
+;
+; STACK.ASM
+;
+; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
+;
+; This module contains a routine that calls a callback function on a
+; internal stack. This is designed to be used by MMSYSTEM drivers that
+; call user callback functions at async interupt time.
+;
+; Revision history:
+;
+; 07/30/90 First created by ToddLa (moved from SndBlst driver)
+; 04/24/91 MikeRo. Added stack usage stuff.
+; 07/07/91 CurtisP. New stack switcher code that allows user to
+; configure size and number of stacks. Default is 3
+; frames of 1.5kb each. This is the minimum that MCISEQ
+; needs in standard mode (running concurrent with wave).
+; [mmsystem]!stackframes= and !stacksize=. stackframes
+; mul stacksize can not be > 64k.
+; 07/24/91 ToddLa. even newer stack switcher code! export StackEnter
+; and StackLeave
+; 11/02/92 StephenE. Hacked the code to make it work on NT/WOW.
+;
+;***************************************************************************;
+
+ifdef MYDEBUG
+ DEBUG_RETAIL equ 1
+endif
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; NO! Windows prolog/epilog code
+
+ .286p
+ .xlist
+ include wow.inc
+ include wowmmcb.inc
+ include wowmmed.inc
+ include cmacros.inc
+
+; include windows.inc
+; include mmsystem.inc
+; include mmddk.inc
+; include wowmmcb.inc
+
+ include vint.inc
+ .list
+
+OFFSEL STRUC
+Off dw ?
+Sel dw ?
+OFFSEL ENDS
+
+LOHI STRUC
+Lo dw ?
+Hi dw ?
+LOHI ENDS
+
+DCB_NOSWITCH equ 0008h ; don't switch stacks for callback
+DCB_TYPEMASK equ 0007h ; callback type mask
+DCB_NULL equ 0000h ; unknown callback type
+
+; flags for wFlags parameter of DriverCallback()
+DCB_WINDOW equ 0001h ; dwCallback is a HWND
+DCB_TASK equ 0002h ; dwCallback is a HTASK
+DCB_FUNCTION equ 0003h ; dwCallback is a FARPROC
+
+ externFP PostMessage ; in USER
+ externFP PostAppMessage ; in USER
+ externFP CALLPROC32W ; in Kernel
+ externFP ThunkInit ; in init.c
+
+;******************************************************************************
+;
+; SEGMENTS
+;
+;******************************************************************************
+createSeg FIX, CodeFix, word, public, CODE
+createSeg INTDS, DataFix, byte, public, DATA
+
+;***************************************************************************;
+;
+; equates and structure definitions
+;
+;***************************************************************************;
+
+STACK_MAGIC equ 0BBADh
+
+
+;***************************************************************************;
+;
+; Local data segment
+;
+;***************************************************************************;
+
+sBegin DataFix
+;
+; This is the stack we will switch to whenever we are calling
+; a user call back
+;
+ public gwStackSize
+ public gwStackFrames
+ public gwStackUse
+ public gwStackSelector
+ public hdrvDestroy
+ public vpCallbackData
+ public hGlobal
+ public DoInterrupt
+ public tid32Message
+ public mmwow32Lib
+ public CheckThunkInit
+
+gwStackSize dw 0
+gwStackFrames dw 0
+gwStackUse dw 0
+gwStackSelector dw 0
+hdrvDestroy dw -1 ; this handle is being closed
+vpCallbackData dd 0
+hGlobal dd 0
+tid32Message dd 0 ; timer driver entry point
+mmwow32Lib dd 0
+
+sEnd DataFix
+
+;-------------------------------------------------------------------------;
+;
+; debug support
+;
+;-------------------------------------------------------------------------;
+externFP OutputDebugString
+
+;--------------------------Private-Macro----------------------------------;
+; DOUT String - send a debug message to the debugger
+;
+; Entry:
+; String String to send to the COM port, does not need a CR,LF
+;
+; Registers Destroyed:
+; none
+;
+; NOTE no code is generated unless the MYDEBUG symbol is defined
+;
+; History:
+; Sun 31-Jul-1989 -by- ToddLa
+; Wrote it.
+;-------------------------------------------------------------------------;
+
+DOUT macro text
+ local string_buffer_stack
+ifdef MYDEBUG
+ push cs
+ push offset string_buffer_stack
+ call OutputDebugString
+ jmp @F
+string_buffer_stack label byte
+ db "mmsystem: "
+ db "&text&",13,10,0
+@@:
+endif
+ endm
+
+
+;***************************************************************************;
+;
+; code segment
+;
+;***************************************************************************;
+
+sBegin CodeFix
+ assumes cs, CodeFix
+ assumes ds, nothing
+ assumes es, nothing
+
+externA __WinFlags
+
+public CodeFixWinFlags
+public CodeFixDS
+
+CodeFixWinFlags dw __WinFlags
+CodeFixDS dw DataFixBASE
+
+;***************************************************************************;
+;
+; @doc DDK MMSYSTEM
+;
+; @asm StackEnter |
+;
+; This function switches to the next internal mmsystem interupt stack
+; available.
+;
+; if one is not available we stay on the current stack.
+;
+; the size and number of mmsystem stacks is controlable from SYSTEM.INI
+; (these are the defaults)
+;
+; [mmsystem]
+; StackSize = 1536
+; StackFrames = 3
+;
+; for every call to StackEnter a call to StackLeave *must* be made (even
+; if StackEnter fails!)
+;
+; this function is intended to be used as the first thing done by a ISR
+;
+; MyISR proc far
+;
+; call StackEnter ; switch to a safe stack
+;
+; pusha ; save registers we use
+;
+; <handle IRQ>
+;
+; popa ; restore registers
+;
+; call StackLeave ; return to interupt stack
+; iret ; done with ISR
+;
+; MyISR endp
+;
+; The old SS:SP is pushed onto the new stack, and the function returns.
+;
+; @rdesc NC ** succesfuly switced to a new stack
+; C ** you are hosed jack, no stacks left
+; (you remain on current stack)
+;
+; @uses flags
+;
+; @saves all
+;
+; @xref StackLeave, DriverCallback
+;
+;***************************************************************************;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc StackEnter, <FAR, PUBLIC>, <>
+cBegin nogen
+
+ ;
+ ; On WOW we only emulate Standard mode therefore I won't bother
+ ; with the test described below.
+ ;
+ ; if we are in 386 mode or better (ie *not* standard mode) then, just
+ ; get the hell out.
+ ;
+; test cs:[CodeFixWinFlags],WF_WIN286
+; jz stack_enter_retf
+
+ push ds
+
+ mov ds,[CodeFixDS]
+ assumes ds,DataFix
+
+ cmp [gwStackUse], 0 ; are we out of stacks?
+ jne stack_enter_have_stack_will_travel ; ..no go grab it
+
+;**********************************************************************-;
+;
+; We are out of internal stacks. To give us the greates chance
+; of coming out of this condition alive, we stay on the current
+; stack. This could fail miserably if we are on a very small
+; stack**but it is better than crashing outright.
+;
+;**********************************************************************-;
+
+ifdef DEBUG_RETAIL
+ cmp [gwStackSelector], 0
+ je stack_enter_stay_here
+
+ DOUT <StackEnter: All stacks in use, increase StackFrames>
+ int 3
+endif
+
+ifdef MYDEBUG
+ call dump_stack_users
+endif
+
+stack_enter_stay_here:
+ pop ds
+ assumes ds,nothing
+ push bp
+ mov bp,sp
+ push ax
+
+ xor ax,ax
+ xchg [bp+4],ax
+ xchg [bp+2],ax
+ xchg [bp],ax
+ xchg [bp-2],ax
+
+ pop bp
+stack_enter_retf:
+ stc
+ retf
+
+;**********************************************************************-;
+;
+; we have a stack to use, allocate stack FIRST, then muck with it
+; leave no window for interrupts to blast us.
+;
+; It does this by using the contents of the gwStackUse variable as
+; the new SP. This initially contains the address of the start (ie top)
+; of the internal stack area, and is subtracted from each time a StackEnter
+; occurs. It is of course added to again when StackLeave is called
+; freeing up that area of stack for the next use.
+;
+; Note that the stack usage counter is modified before anything is
+; is pushed onto the new stack. If an interrupt occurs after the stack
+; switch, but before the usage is set, it will be fine.
+;
+;**********************************************************************-;
+ assumes ds,DataFix
+
+stack_enter_have_stack_will_travel:
+ push ax
+ push bx
+ mov bx,sp
+
+ mov ax, [gwStackSize]
+ sub [gwStackUse], ax ; reserve stack before using
+ add ax, [gwStackUse] ; get current value and hang onto it
+
+;**********************************************************************-;
+;
+; debug code, in the debug version we do crazy things like filling
+; the stack with magic numbers.
+;
+;**********************************************************************-;
+ifdef MYDEBUG
+; ** This code will fill the stack with the magic cookie**this
+; ** is used to see how much stack space is being used at any
+; ** time.
+
+ push es
+ push di
+ push ax
+ push cx
+ mov di, ax ; es:di -> top of stack
+ mov es, [gwStackSelector]
+ mov cx, [gwStackSize] ; get size to fill
+ sub di, cx ; es:di -> bottom of stack
+ shr cx, 1 ; in words
+ mov ax, STACK_MAGIC ; what to fill with
+ cld ; bottom up
+ rep stosw
+ pop cx ; restore munged regs
+ pop ax
+ pop di
+ pop es
+endif
+
+ifdef DEBUG_RETAIL
+; ** This code puts a single magic cookie at the end of the stack.
+; ** This is used by the stack leave routine to check for overflow.
+; ** If the above code (the fill) is running, then this code is
+; ** redundant.
+
+ push es
+ push bx
+ mov es,[gwStackSelector]
+ mov bx,[gwStackUse] ; new stack
+ mov es:[bx], STACK_MAGIC
+ pop bx
+ pop es
+endif
+
+;**********************************************************************-;
+;
+; time to switch to the *new* stack, [gwStackSelector]:AX contains
+; the new SS:SP, but first save the *old* SS:SP and restore
+; the registers we nuked to get here
+;
+;**********************************************************************-;
+
+ push [gwStackSelector] ; push *new* ss
+
+ push ss ; save current ss in ds
+ pop ds
+ assumes ds, nothing
+
+ pop ss ; switch to new stack
+ mov sp, ax ; ints off until after this on >= 286
+
+;**********************************************************************-;
+;
+; now that we are on the new stack, copy some important info from
+; the old stack to this one. note DS:[BX] points to the old stack
+;
+; [BX+0] ==> saved BX
+; [BX+2] ==> saved AX
+; [BX+4] ==> saved DS
+; [BX+6] ==> return IP
+; [BX+8] ==> return CS
+;
+; in the MYDEBUG version we save the callers CS:IP on the stack so we
+; can (in dump_stack_users) walk all the stacks
+;
+;**********************************************************************-;
+
+ifdef MYDEBUG
+ push [bx+8] ; push a CS:IP for dumping stack users
+ push [bx+6]
+endif
+ add bx,10 ; 10 = ax+bx+dx+retf
+ push ds ; save old SS:SP (SP = BX+N)
+ push bx
+ sub bx,10
+
+ push [bx+8] ; push return addr
+ push [bx+6]
+
+ push [bx+4] ; push saved DS
+ push [bx] ; push saved BX
+
+ mov ax,[bx+2] ; restore ax
+ pop bx ; restore bx
+ pop ds ; restore ds
+ clc ; show success
+stack_leave_retf:
+ retf ; return to caller
+
+cEnd nogen
+
+;***************************************************************************;
+;
+; @doc DDK MMSYSTEM
+;
+; @asm StackLeave |
+;
+; This function returns the stack to the original stack saved by StackEnter
+;
+; @uses flags
+;
+; @saves all
+;
+; @xref StackEnter, DriverCallback
+;
+;***************************************************************************;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc StackLeave, <FAR, PUBLIC>, <>
+cBegin nogen
+ ;
+ ; if we are in 386 mode or better (ie *not* standard mode) then, just
+ ; get the hell out.
+ ;
+; test cs:[CodeFixWinFlags],WF_WIN286
+; jz stack_leave_retf
+
+ push bx
+ mov bx,sp
+
+;**********************************************************************-;
+;
+; here is the state of things:
+;
+; [BX+0] ==> saved BX
+; [BX+2] ==> return IP
+; [BX+4] ==> return CS
+; [BX+6] ==> saved SP
+; [BX+8] ==> saved SS
+;
+; the first thing we must check for is EnterStack running out of
+; stacks. in this case StackEnter pushed a single zero where the
+; saved SS should be
+;
+;**********************************************************************-;
+
+ cmp word ptr ss:[bx+6],0 ; check saved SP
+ jnz stack_leave_normal
+
+;**********************************************************************-;
+;
+; StackEnter ran out of stacks, stay on the current stack, but remove
+; the bogus SS
+;
+;**********************************************************************-;
+stack_leave_abby_normal:
+ pop bx ; return to caller taking the
+ retf 2 ; bogus zero SP with us
+
+;**********************************************************************-;
+;
+; we need to return to the stack saved by StackEnter
+;
+;**********************************************************************-;
+stack_leave_normal:
+ push ds ; [BX-2] ==> saved DS
+
+ push ss ; DS = old stack
+ pop ds
+ assumes ds,nothing
+
+ifdef MYDEBUG
+ push ax
+ mov ax,[bx+8]
+ lar ax,ax
+ jz @f
+ DOUT <StackLeave: invalid stack>
+ int 3
+@@: pop ax
+endif
+
+ mov ss,[bx+8] ; switch to new stack
+ mov sp,[bx+6] ; ints off until after this on >= 286
+
+ push [bx+4] ; push return addr
+ push [bx+2]
+
+ push [bx] ; push old BX
+ push [bx-2] ; push old DS
+
+;**********************************************************************-;
+;
+; we are back on the original stack, now it is time to deallocate
+; the stack.
+;
+; The stack usage must only be released after all
+; values have been removed from the stack so that an interrupt can be
+; serviced without writing over any values.
+;
+;**********************************************************************-;
+
+ mov ds,[CodeFixDS] ; get at our globals
+ assumes ds,DataFix
+
+ifdef DEBUG_RETAIL
+ push es
+ push bx
+ mov bx,[gwStackUse] ; before we release it
+ mov es,[gwStackSelector]
+ cmp es:[bx], STACK_MAGIC
+ mov es:[bx], STACK_MAGIC ; and try to recover...
+ pop bx
+ pop es
+ je @f ; true if magic cookie existed
+
+ DOUT <StackLeave: STACK OVERFLOW>
+ int 3
+ifdef MYDEBUG
+ call dump_stack_users
+endif
+@@:
+endif
+ mov bx, [gwStackSize] ; get the size of the stacks
+ add [gwStackUse], bx ; release stack frame after use
+
+ pop ds
+ assumes ds,nothing
+ pop bx
+ retf
+
+cEnd nogen
+
+;****************************************************************************
+; FUNCTION: DoInterrupt()
+;
+; PURPOSE:
+; This routine is called by the ISR in the InstallInerruptHandler
+; routine.
+;
+; void DoInterrupt( void )
+; {
+; VPCALLBACK_ARGS pArgs;
+; WORD wSendCount = vpCallbackData->wSendCount;
+; WORD wTempRecvCount;
+;
+; /*
+; ** At entry to this function the receive count should be one less than
+; ** than the send count. However, it is possible that we have lost some
+; ** interrupts in which case we should try to "catch up" here.
+; **
+; ** The 32 bit side does not increament wSendCount until the
+; ** callback data buffer has been updated. This means that although it
+; ** is possible that it could have been changed before this interrupt
+; ** was generated it will never point to an invalid buffer location.
+; ** We simply process two interrupt request from the first interrupt,
+; ** when the second interrupt goes off we return straight away.
+; */
+; vpCallbackData->wIntsCount++;
+;
+; while ( vpCallbackData->wRecvCount != wSendCount ) {
+;
+; /*
+; ** Increment the recv count. Use of the % operator to makes sure
+; ** that we wrap around to the begining of the array correctly.
+; */
+; wTempRecvCount = (vpCallbackData->wRecvCount + 1)
+; % CALLBACK_ARGS_SIZE;
+;
+; pArgs = &vpCallbackData->args[ wTempRecvCount ];
+; DriverCallback( pArgs->dwFunctionAddr,
+; LOWORD( pArgs->dwFlags ),
+; pArgs->wHandle,
+; pArgs->wMessage,
+; pArgs->dwInstance,
+; pArgs->dwParam1,
+; pArgs->dwParam2 );
+;
+; vpCallbackData->wRecvCount = wTempRecvCount;
+; }
+;
+; }
+;
+;****************************************************************************
+cProc DoInterrupt, <FAR,PUBLIC>, <si,di>
+
+localW wSendCount ;number of interrupts sent
+
+cBegin DoInt
+
+ DOUT <Multi-Media Interupt called>
+
+;
+; Now we take the parameters from the global callback data array
+; and increment the dwRecvCount field. Then we make the
+; callback into the apps routine. Note that the es:bx registers are used
+; instead of the local variable pArgs.
+;
+
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+
+;
+; wSendCount = vpCallbackData->wSendCount
+; vpCallbackData->wIntsCount++;
+;
+ les bx,DWORD PTR es:vpCallbackData
+ mov ax,WORD PTR es:[bx+2]
+ mov wSendCount,ax
+ inc WORD PTR es:[bx+388] ; increment the count of interrupts rcv
+
+ jmp DoIntMakeTheTest
+
+;
+; Make es:bx point to the correct slot in the callback data table.
+;
+
+DoIntMakeTheCall:
+
+;
+; Increment the recv count. Use of the % operator above makes sure
+; that we wrap around to the begining of the array correctly.
+;
+; wTempRecvCount = (vpCallbackData->wRecvCount + 1) % CALLBACK_ARGS_SIZE;
+;
+
+ mov al,BYTE PTR es:[bx]
+ inc al
+ and ax,15
+ mov cx,ax
+
+;
+; pArgs = &vpCallbackData->args[ vpCallbackData->wRecvCount ];
+; vpCallbackData->wRecvCount = wTempRecvCount;
+; Note that pArgs is really es:bx.
+;
+
+ mov es,[CodeFixDS]
+ les bx,DWORD PTR es:vpCallbackData
+ imul ax,WORD PTR es:[bx],24 ;ax = wRecvCount * sizeof(CALLBACKDATA)
+
+;
+; Note: our caller saves ALL registers. We do not need to preserve si
+;
+ mov si,bx
+ add bx,ax ;bx = bx + ax
+ add bx,4 ;bx += sizeof(WORD) * 2
+
+;
+; Set up the stack frame for DriverCallback
+;
+ push WORD PTR es:[bx+6]
+ push WORD PTR es:[bx+4]
+ push WORD PTR es:[bx]
+ push WORD PTR es:[bx+8]
+ push WORD PTR es:[bx+10]
+ push WORD PTR es:[bx+14]
+ push WORD PTR es:[bx+12]
+ push WORD PTR es:[bx+18]
+ push WORD PTR es:[bx+16]
+ push WORD PTR es:[bx+22]
+ push WORD PTR es:[bx+20]
+
+;
+; We have to set up the stack frame before incrementing wRecvCount to
+; prevent the 32 bit code from eating our slot in the buffer.
+;
+ mov WORD PTR es:[si],cx ;wRecvCount = wTempRecvCount
+
+ call FAR PTR DriverCallback
+
+
+;
+; Reload es:bx and ax ready for the loop test
+;
+ mov ax,wSendCount
+ mov es,[CodeFixDS]
+ les bx,DWORD PTR es:vpCallbackData
+
+DoIntMakeTheTest:
+ cmp WORD PTR es:[bx],ax
+ jne DoIntMakeTheCall
+
+cEnd DoInt
+
+
+ifdef XDEBUG
+public stack_enter_stay_here
+public stack_enter_have_stack_will_travel
+public stack_leave_abby_normal
+public stack_leave_normal
+endif
+
+;***************************************************************************;
+;
+; @doc DDK MMSYSTEM
+;
+; @api BOOL | DriverCallback | This function notifies a client
+; application by sending a message to a window or callback
+; function or by unblocking a task.
+;
+; @parm DWORD | dwCallBack | Specifies either the address of
+; a callback function, a window handle, or a task handle, depending on
+; the flags specified in the <p wFlags> parameter.
+;
+; @parm WORD | wFlags | Specifies how the client
+; application is notified, according to one of the following flags:
+;
+; @flag DCB_FUNCTION | The application is notified by
+; sending a message to a callback function. The <p dwCallback>
+; parameter specifies a procedure-instance address.
+; @flag DCB_WINDOW | The application is notified by
+; sending a message to a window. The low-order word of the
+; <p dwCallback> parameter specifies a window handle.
+;
+; @flag DCB_NOSWITCH | DriverCallback should *not* switch to a new stack
+;
+; @parm WORD | hDevice | Specifies a handle to the device
+; associated with the notification. This is the handle assigned by
+; MMSYSTEM when the device was opened.
+;
+; @parm WORD | wMsg | Specifies a message to send to the
+; application.
+;
+; @parm DWORD | dwUser | Specifies the DWORD of user instance
+; data supplied by the application when the device was opened.
+;
+; @parm DWORD | dwParam1 | Specifies a message-dependent parameter.
+; @parm DWORD | dwParam2 | Specifies a message-dependent parameter.
+;
+; @rdesc Returns TRUE if the callback was performed, else FALSE if an invalid
+; parameter was passed, or the task's message queue was full.
+;
+; @comm This function can be called at interrupt time.
+;
+; The flags DCB_FUNCTION and DCB_WINDOW are equivalent to the
+; high-order word of the corresponding flags CALLBACK_FUNCTION
+; and CALLBACK_WINDOW specified when the device was opened.
+;
+; If notification is done with a callback function, <p hDevice>,
+; <p wMsg>, <p dwUser>, <p dwParam1>, and <p dwParam2> are passed to
+; the callback. If notification is done with a window, only <p wMsg>,
+; <p hDevice>, and <p dwParam1> are passed to the window.
+;***************************************************************************;
+
+ assumes ds, nothing
+ assumes es, nothing
+
+cProc DriverCallback, <FAR, PASCAL, PUBLIC>, <>
+
+ parmD dwCallBack ; callback procedure to call
+ parmW fCallBack ; callback flags
+ parmW hdrv ; handle to the driver
+ parmW msg ; driver message
+ parmD dwUser ; user instance data
+ parmD dw1 ; message specific
+ parmD dw2 ; message specific
+
+cBegin
+ cld ; lets not make any assumptions about this!!!!
+
+;**************************************************************************-;
+; check for quick exit cases and get out fast
+;**************************************************************************-;
+ mov ax,dwCallback.lo ; check for dwCallback == NULL
+ or ax,dwCallback.hi
+ jz dcb_error_exit_now ; if NULL get out fast
+
+ mov ax,fCallback ; get flags and mask out the type bits
+ test ax,DCB_TYPEMASK
+ jz dcb_error_exit_now ; if NULL get out fast
+
+ifdef NEVER
+;**************************************************************************-;
+; if this handle is being NUKED don't allow callbacks into the app
+;
+; I won't bother with this test on WOW either. -- StephenE 2nd Nov 1992
+;**************************************************************************-;
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+ mov bx,hdrv
+ cmp bx,es:[hdrvDestroy] ; same as the handle being nuked?
+ je dcb_error_exit_now ; if yes, get out'a here
+ assumes es,nothing
+endif
+
+;**************************************************************************-;
+; set up ES == SS, so we can access stack params after switching
+; stacks, NOTE!! ES:[bp+##] *must* be used to access parameters!
+;**************************************************************************-;
+ mov cx,ss ; set ES == callers stack
+ mov es,cx ; use ES to get at local vars
+ assumes es,nothing
+
+;**************************************************************************-;
+; We won't switch stacks on WOW since DPMI does this for us. Win 3.1
+; would only switch stacks in Standard mode which we no longer support.
+;**************************************************************************-;
+
+; test ax,DCB_NOSWITCH ; should we switch stacks?
+; jnz dcb_on_stack
+
+; call StackEnter ; switch to new stack
+
+;**************************************************************************-;
+; determine the type of the callback, dwCallback is either a FARPROC, HWND
+; or HTASK depending on the value of fCallback
+;**************************************************************************-;
+dcb_on_stack:
+ ;
+ pushf ; Save the interrupt flag state
+ FSTI ; ** Enable interrupts here **
+ ;
+
+; push ax ; save flags for StackLeave test
+
+ and ax,DCB_TYPEMASK ; mask out the type bits
+
+ cmp ax,DCB_WINDOW ; is it a window handle?
+ je dcb_post_message
+
+ cmp ax,DCB_TASK ; is it a task handle?
+ je dcb_post_event
+
+ cmp ax,DCB_FUNCTION ; is it a procedure?
+ je dcb_call_callback
+
+ DOUT <DriverCallback: Invalid flags #ax>
+ xor ax,ax
+ jmp dcb_exit
+
+dcb_error_exit_now:
+ xor ax,ax
+ jmp dcb_exit_now
+
+ifdef NEVER
+;**************************************************************************-;
+; the Callback flags are NULL determine the callback type by the HIWORD
+; of dwCallback, if it is NULL assume it is a WINDOW otherwise it is a
+; FARPROC
+;**************************************************************************-;
+dcb_null_flags:
+ mov ax,es:dwCallback.hi ; get selector of callback
+ or ax,ax
+ jnz dcb_call_callback ; if NULL then assume it is a window
+ errn$ dcb_post_message ; otherwise assume a FARPROC
+endif
+
+;**************************************************************************-;
+; dwCallback is a window handle, call PostMessage() to insert a message in
+; the applications message Que
+;**************************************************************************-;
+dcb_post_event:
+ cmc
+dcb_post_message:
+ push es:dwCallback.lo ; hwnd
+ push es:msg ; message
+ push es:hdrv ; wParam = hdrv
+ push es:dw1.hi ; lParam = dw1
+ push es:dw1.lo
+
+ jc dcb_post_app_message
+ call PostMessage
+ jmp dcb_exit
+
+;**************************************************************************-;
+; dwCallback is a task handle, call PostAppMessage() to 'wake' the task up
+;**************************************************************************-;
+dcb_post_app_message:
+ call PostAppMessage
+ jmp dcb_exit
+
+;**************************************************************************-;
+; dwCallback is a callback procedure, we will call it.
+;**************************************************************************-;
+dcb_call_callback:
+ ;
+ ; is the callback a valid function?
+ ;
+ lar ax,es:dwCallback.hi
+ jnz dcb_invalid_callback
+ test ax,0800H ; test for code/data selector
+ jnz dcb_valid_callback
+
+dcb_invalid_callback:
+ifdef MYDEBUG_RETAIL
+ mov ax,es:dwCallback.lo
+ mov dx,es:dwCallback.hi
+ DOUT <DriverCallback: Invalid callback function #dx:#ax>
+ int 3
+endif
+ xor ax,ax
+ jmp dcb_exit
+
+dcb_valid_callback:
+ push es:hdrv
+ push es:msg
+ push es:dwUser.hi
+ push es:dwUser.lo
+ push es:dw1.hi
+ push es:dw1.lo
+ push es:dw2.hi
+ push es:dw2.lo
+ call es:dwCallback
+ mov ax,1
+ errn$ dcb_exit
+
+dcb_exit:
+ ;
+ popf ; ** restore the interrupt flag **
+ ;
+
+; pop bx ; restore flags
+; test bx,DCB_NOSWITCH ; should we switch back?
+; jnz dcb_exit_now
+
+; call StackLeave ; return to previous stack
+ errn$ dcb_exit_now
+
+dcb_exit_now:
+cEnd
+
+ifdef MYDEBUG
+;**************************************************************************-;
+;
+; each mmsystem stack has a SS:SP and in MYDEBUG a CS:IP of the caller of
+; StackEnter, the top of each stack looks like this.
+;
+; +-------------------------------------+
+; | CS:IP of caller of StackEnter() (in MYDEBUG)
+; +-------------------------------------+
+; | SS:SP to restore
+; +-------------------------------------+
+;
+;**************************************************************************-;
+ assumes ds,DataFix
+ assumes es,nothing
+
+ public dump_stack_users
+dump_stack_users proc near
+
+ cmp [gwStackSelector],0
+ jne @f
+ ret
+
+@@: pusha
+ push es
+
+ mov cx,[gwStackFrames]
+ mov di,[gwStackSize]
+ mov si,[gwStackUse]
+ mov es,gwStackSelector
+
+ DOUT <StackUsers: Frames[#cx] Size[#di] Use[#si]>
+
+dump_stack_loop:
+ lar ax,es:[di-4].sel
+ jnz dump_stack_next
+
+ mov ax,es:[di-4].off ; get CS:IP of StackEnter caller
+ mov dx,es:[di-4].sel
+
+ mov si,es:[di-8].off ; get SS:SP of StackEnter caller
+ mov bx,es:[di-8].sel
+
+ DOUT <StackUser #cx is CS:IP = #dx:#ax SS:SP = #bx:#si>
+
+dump_stack_next:
+ add di,[gwStackSize]
+ loop dump_stack_loop
+
+ pop es
+ popa
+ ret
+
+dump_stack_users endp
+
+endif
+
+;-----------------------------------------------------------------------;
+;
+; @doc INTERNAL
+;
+; @api DWORD | CheckThunkInit | send a message to the timer driver
+;
+; @rdesc Returns 0 if successful, otherwise an error code,
+; (typically MMSYSERR_NODRIVER).
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CheckThunkInit, <FAR, PUBLIC, PASCAL>, <>
+cBegin
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+
+ sub ax,ax ; assume sucess
+ mov bx,WORD PTR es:[mmwow32Lib] ; is mmwow32Lib loaded ?
+ mov cx,WORD PTR es:[mmwow32Lib+2] ; try to load it
+ or cx,bx ; ThunkInit returns ax=1
+ jnz @F ; if it loaded OK, otherwise
+ call ThunkInit ; ax=MMSYSERR_NODRIVER
+@@:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+;
+; @doc INTERNAL
+;
+; @api DWORD | timeMessage | send a message to the timer driver
+;
+; @parm WORD | msg | message to send
+;
+; @parm DWORD | dw1 | first DWORD
+;
+; @parm DWORD | dw2 | first DWORD
+;
+; @rdesc Returns zero if successful, error code otherwise
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW msg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+
+ sub ax,ax ; assume sucess
+ mov bx,WORD PTR es:[mmwow32Lib] ; is mmwow32Lib loaded ?
+ mov cx,WORD PTR es:[mmwow32Lib+2] ; try to load it
+ or cx,bx ; ThunkInit returns ax=1
+ jnz timer_have_thunks ; if it loaded OK, otherwise
+ push es
+ call ThunkInit ; ax=MMSYSERR_NODRIVER
+ pop es
+ or ax,ax
+ jnz timeMessageExit
+
+timer_have_thunks:
+
+ push ax ; uDevID
+ push ax ;
+
+ push ax ; Message passed
+ push msg ;
+
+ push ax ; dwInstance
+ push ax ;
+
+ push dw1.hi ; dwParam1
+ push dw1.lo ;
+
+ push dw2.hi ; dwParam2
+ push dw2.lo ;
+
+ push WORD PTR es:[tid32Message+2] ; Address of function to call
+ push WORD PTR es:[tid32Message] ;
+
+ push ax ; No directory change
+ push ax
+
+ call FAR PTR MMCALLPROC32
+timeMessageExit:
+cEnd
+
+ MMediaThunk MMCALLPROC32
+
+sEnd CodeFix
+
+end
diff --git a/private/mvdm/wow16/mmsystem/task.c b/private/mvdm/wow16/mmsystem/task.c
new file mode 100644
index 000000000..41d84dbbd
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/task.c
@@ -0,0 +1,117 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1990. All rights reserved.
+
+ Title: task.c - support for task creation and blocking
+
+ Version: 1.00
+
+ Date: 05-Mar-1990
+
+ Author: ROBWI
+
+------------------------------------------------------------------------------
+
+ Change log:
+
+ DATE REV DESCRIPTION
+ ----------- ----- -----------------------------------------------------------
+ 05-MAR-1990 ROBWI First Version - APIs and structures
+ 18-APR-1990 ROBWI Ported from Resman to mmsystem
+ 25-JUN-1990 ROBWI Added mmTaskYield
+ 07-JUL-1991 CJP Modified to work with new stack switcher code
+
+*****************************************************************************/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmsysi.h"
+#include "mmddk.h"
+#include "mmtask\mmtask.h"
+
+UINT FAR PASCAL BWinExec(LPSTR lpModuleName, UINT wCmdShow, LPVOID lpParameters);
+
+/***************************************************************************
+ *
+ * @doc DDK MMSYSTEM TASK
+ *
+ * @api UINT | mmTaskCreate | This function creates a new task.
+ *
+ * @parm LPTASKCALLBACK | lpfn | Points to a program supplied
+ * function and represents the starting address of the new
+ * task.
+ *
+ * @parm HTASK FAR * | lph | Points to the variable that receives the
+ * task identifier. This may be NULL in some versions. This
+ * is not an error it simply means that the system could not
+ * determine the task handle of the newly created task.
+ *
+ * @parm DWORD | dwStack | Specifies the size of the stack to be
+ * provided to the task.
+ *
+ * @parm DWORD | dwInst | DWORD of instance data to pass to the task
+ * routine.
+ *
+ * @rdesc Returns zero if the function is successful. Otherwise it
+ * returns an error value which may be one of the following:
+ *
+ * @flag TASKERR_NOTASKSUPPORT | Task support is not available.
+ * @flag TASKERR_OUTOFMEMORY | Not enough memory to create task.
+ *
+ * @comm When a mmsystem task is created, the system will make a far
+ * call to the program-supplied function whose address is
+ * specified by the lpfn parameter. This function may include
+ * local variables and may call other functions as long as
+ * the stack has sufficient space.
+ *
+ * The task terminates when it returns.
+ *
+ * @xref mmTaskSignal mmTaskBlock
+ *
+ ***************************************************************************/
+
+UINT WINAPI mmTaskCreate(LPTASKCALLBACK lpfn, HTASK FAR * lph, DWORD dwInst)
+{
+ MMTaskStruct TaskStruct;
+ char szName[20];
+ UINT wRes;
+ HTASK hTask;
+
+ /*
+ create another app. so that we can run the stream outside of
+ the context of the app.
+ */
+
+ if (!LoadString(ghInst, IDS_TASKSTUB, szName, sizeof(szName)))
+ return TASKERR_NOTASKSUPPORT;
+
+ TaskStruct.cb = sizeof(TaskStruct);
+ TaskStruct.lpfn = lpfn;
+ TaskStruct.dwInst = dwInst;
+ TaskStruct.dwStack = 0L;
+
+ wRes = BWinExec(szName, SW_SHOWNOACTIVATE, &TaskStruct);
+
+ if (wRes > 32)
+ {
+ hTask = wRes;
+ wRes = MMSYSERR_NOERROR;
+ }
+ else if (wRes == 0)
+ {
+ wRes = TASKERR_OUTOFMEMORY;
+ hTask = NULL;
+ }
+ else
+ {
+ wRes = TASKERR_NOTASKSUPPORT;
+ hTask = NULL;
+ }
+
+ if (lph)
+ *lph = hTask;
+
+ DPRINTF2("mmTaskCreate: hTask = %04X, wErr = %04X\r\n", hTask, wRes);
+
+ return wRes;
+}
diff --git a/private/mvdm/wow16/mmsystem/taska.asm b/private/mvdm/wow16/mmsystem/taska.asm
new file mode 100644
index 000000000..720debee2
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/taska.asm
@@ -0,0 +1,225 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: TASKA.ASM - Some task functions
+;
+; Copyright (c) 1984-1991 Microsoft Corporation
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ include mmsystem.inc
+ .list
+
+ externFP Yield
+ externFP GetCurrentTask
+ externFP PostAppMessage
+ externFP PostMessage
+ externFP PeekMessage
+ externFP GetMessage
+ externFP DispatchMessage
+ externFP TranslateMessage
+
+ifndef SEGNAME
+ SEGNAME equ <_TEXT>
+endif
+
+;-----------------------------------------------------------------------;
+
+createSeg %SEGNAME, CodeSeg, word, public, CODE
+
+sBegin CodeSeg
+ assumes cs,CodeSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+;
+; @doc DDK MMSYSTEM TASK
+;
+; @api void | mmTaskYield | This function causes the current task
+; to yield.
+;
+; @comm For predictable results and future compatibility, use this
+; function rather than <f Yield> or the undocumented Kernel yield
+; function to yield within a task created with <f mmTaskCreate>.
+;
+;-----------------------------------------------------------------------;
+cProc mmTaskYield, <FAR, PUBLIC, PASCAL>, <>
+ LocalV msg, %(SIZE MSGSTRUCT)
+cBegin
+ ;
+ ; we need to call PeekMessage() so ScanSysQue gets called
+ ; and USER gets the mouse/keyboard input right
+ ;
+ ; PeekMessage() may not Yield if there is a message in the
+ ; Queue so we yield if it did not.
+ ;
+
+ lea ax, msg
+ cCall PeekMessage, <ss, ax, NULL, 0, 0, PM_NOREMOVE>
+ or ax,ax
+ jz mmTaskYieldExit
+
+ cCall Yield ; PeekMessage() did not yield, so yield
+
+mmTaskYieldExit:
+cEnd
+
+;-----------------------------------------------------------------------;
+;
+; @doc DDK MMSYSTEM TASK
+;
+; @api HTASK | mmGetCurrentTask | This function returns the
+; handle of the currently executing task created with
+; <f mmTaskCreate>.
+;
+; @rdesc Returns a task handle. For predictable results and future
+; compatibility, use this function rather than <f GetCurrentTask>
+; to get the task handle of a task created with <f mmTaskCreate>.
+;
+; @xref mmTaskCreate
+;
+;-----------------------------------------------------------------------;
+cProc mmGetCurrentTask, <FAR, PUBLIC, PASCAL>, <>
+cBegin <nogen>
+ jmp FAR PTR GetCurrentTask ; Jump directly to avoid returning to here
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc DDK MMSYSTEM TASK
+;
+; @api UINT | mmTaskBlock | This function blocks the current
+; task context if its event count is 0.
+;
+; @parm HTASK | hTask | Task handle of the current task. For predictable
+; results, get the task handle from <f mmGetCurrentTask>.
+;
+; @xref mmTaskSignal mmTaskCreate
+;
+; @comm WARNING : For predictable results, must only be called from a
+; task created with <f mmTaskCreate>.
+;
+;-----------------------------------------------------------------------;
+cProc mmTaskBlock, <FAR, PUBLIC, PASCAL, NODATA>, <>
+ ParmW hTask
+ LocalV msg, %(SIZE MSGSTRUCT)
+cBegin
+
+mmTaskBlock_GetMessage:
+ lea ax, msg
+ cCall GetMessage, <ss, ax, NULL, 0, 0>; Retrieve any message for task
+ cmp msg.msHWND, 0 ; Message sent to a window?
+ je mmTaskBlock_CheckMessage ; If so, dispatch it
+ lea ax, msg
+ cCall TranslateMessage, <ss, ax> ; Probably a TaskMan message
+ lea ax, msg
+ cCall DispatchMessage, <ss, ax>
+ jmp mmTaskBlock_GetMessage
+
+;
+; we got a message, wake up on any message >= WM_MM_RESERVED_FIRST
+;
+mmTaskBlock_CheckMessage:
+ mov ax,msg.msMESSAGE
+ cmp ax,WM_MM_RESERVED_FIRST
+ jb mmTaskBlock_GetMessage
+cEnd
+
+sEnd
+
+;-----------------------------------------------------------------------;
+
+createSeg FIX, FixSeg, word, public, CODE
+
+sBegin FixSeg
+ assumes cs,FixSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+;
+; @doc DDK MMSYSTEM TASK
+;
+; @api BOOL | mmTaskSignal | This function signals the specified
+; task, incrementing its event count and unblocking
+; it.
+;
+; @parm HTASK | hTask | Task handle. For predictable results, get the
+; task handle from <f mmGetCurrentTask>.
+;
+; @rdesc Returns TRUE if the signal was sent, else FALSE if the message
+; queue was full.
+;
+; @xref mmTaskBlock mmTaskCreate
+;
+; @comm Must be callable at interrupt time! WARNING : For
+; predictable results, must only be called from a task
+; created with <f mmTaskCreate>.
+;
+;-----------------------------------------------------------------------;
+cProc mmTaskSignal, <FAR, PUBLIC, PASCAL>, <>
+; ParmW hTask
+cBegin <nogen>
+ pop bx ; Fetch the return address
+ pop dx
+ push WM_USER ; Message
+ xor ax, ax
+ push ax ; wParam
+ push ax ; lParam
+ push ax
+ push dx ; Put return address back
+ push bx
+ jmp FAR PTR PostAppMessage ; Jump directly to avoid returning to here
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc DDK MCI
+; @api BOOL | mciDriverNotify | Used by a driver to send
+; a notification message
+;
+; @parm HWND | hwndCallback | The window to notify
+;
+; @parm UINT | wDeviceID | The device ID which triggered the callback
+;
+; @parm UINT | wStatus | The status of the callback. May be one of
+; MCI_NOTIFY_SUCCESSFUL or MCI_NOTIFY_SUPERSEDED or MCI_NOTIFY_ABORTED
+; or MCI_NOTIFY_FAILURE
+;
+; @rdesc Returns TRUE if notify was successfully sent, FALSE if the
+; application's message queue was full.
+;
+; @comm This function is callable at interrupt time.
+;
+;-----------------------------------------------------------------------;
+
+cProc mciDriverNotify, <FAR, PUBLIC, PASCAL>, <>
+; ParmW hwndCallback
+; ParmW wDeviceID
+; ParmW wStatus
+cBegin <nogen>
+ pop bx ; Fetch the return address
+ pop dx
+ pop ax ; Fetch wStatus
+ pop cx ; Fetch wDeviceID
+ push MM_MCINOTIFY ; Message
+ push ax ; wParam == wStatus
+ push 0 ; HIWORD of lParam
+ push cx ; LOWORD of lParam == wDeviceID
+ push dx ; Put return address back
+ push bx
+ jmp FAR PTR PostMessage ; Jump directly to avoid returning to here
+cEnd <nogen>
+
+sEnd
+
+;-----------------------------------------------------------------------;
+
+END
diff --git a/private/mvdm/wow16/mmsystem/thunks.asm b/private/mvdm/wow16/mmsystem/thunks.asm
new file mode 100644
index 000000000..a7b1f8cb7
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/thunks.asm
@@ -0,0 +1,818 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: thunks.asm - Passes control to 32 bit code.
+;
+;
+; Created: 27-09-93
+; Author: Stephen Estrop [StephenE]
+;
+; Copyright (c) 1993 Microsoft Corporation
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ .list
+
+;-----------------------------------------------------------------------;
+;
+;-----------------------------------------------------------------------;
+ externFP MMCALLPROC32 ; in Stack.asm
+ externFP wod32Message
+ externFP wid32Message
+ externFP mod32Message
+ externFP mid32Message
+ externFP joy32Message ; in joy.c
+ externFP aux32Message ; in init.c
+ externFP mci32Message ; in mci.c
+ externFP cb32 ; in init.c
+ externFP CheckThunkInit ; in stack.asm
+ externFP wodMapper ; in init.c
+ externFP widMapper ; in init.c
+
+WAVE_MAPPER equ (-1) ;
+;
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+;
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+FARPOINTER struc
+off dw ?
+sel dw ?
+FARPOINTER ends
+
+
+
+createSeg WAVE, WaveSeg, word, public, CODE
+
+sBegin WaveSeg
+ assumes cs,WaveSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL WAVE
+;
+; @func DWORD | waveOMessage | This function sends messages to the waveform
+; output device drivers.
+;
+; @parm HWAVE | hWave | The handle to the audio device.
+;
+; @parm UINT | wMsg | The message to send.
+;
+; @parm DWORD | dwP1 | Parameter 1.
+;
+; @parm DWORD | dwP2 | Parameter 2.
+;
+; @rdesc Returns the value returned from the thunk.
+;-----------------------------------------------------------------------;
+cProc waveOMessage, <NEAR, PUBLIC, PASCAL>, <>
+ ParmW hWave
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit ; returns ax=0 if sucessful
+ or ax,ax
+ jnz waveOMessage_exit
+
+ mov bx,hWave ; bx = hWave
+ mov ax,WORD PTR [bx+8] ; ax = bx->wDeviceID
+
+
+ cmp ax,WAVE_MAPPER ; Is this the wave mapper
+ jnz @f ; No so thunk to the 32 bit code.
+
+ cmp [wodMapper].hi,0 ; No wave mapper loaded
+ jz @f ; so jump to 32 bit code
+
+ push ax ; push device id
+ push wMsg ; push message
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ call DWORD PTR [wodMapper]
+
+ jmp waveOMessage_exit
+
+@@:
+ sub dx,dx ; dx = 0
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push wod32Message.sel
+ push wod32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+waveOMessage_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL WAVE
+;
+; @func UINT | waveOIDMessage | This function opens a 32 bit wave device
+; on behalf of a 16 bit application.
+;
+; @parm UINT | wDeviceID | Device ID to send message to.
+;
+; @parm UINT | wMessage | The message to send.
+;
+; @parm DWORD | dwUser | The users private DWORD.
+;
+; @parm DWORD | dwParam1 | Parameter 1.
+;
+; @parm DWORD | dwParam2 | Parameter 2.
+;
+; @rdesc The return value is the low word of the returned message.
+;-----------------------------------------------------------------------;
+cProc waveOIDMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW wDeviceID
+ ParmW wMsg
+ ParmD dwUser
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz waveOIDMessage_exit
+
+
+ mov ax,wDeviceID
+ cmp ax,WAVE_MAPPER ; Is this the wave mapper
+ jnz @f ; No so thunk to the 32 bit code.
+
+ cmp [wodMapper].hi,0 ; No wave mapper loaded
+ jz @f ; so jump to 32 bit code
+
+ push ax ; push device id
+ push wMsg ; push message
+
+ push dwUser.hi
+ push dwUser.lo
+ push dw1.hi
+ push dw1.lo
+ push dw2.hi
+ push dw2.lo
+
+ call DWORD PTR [wodMapper]
+
+ jmp waveOIDMessage_exit
+
+@@:
+ sub dx,dx
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push dwUser.hi
+ push dwUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push wod32Message.sel
+ push wod32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+waveOIDMessage_exit:
+cEnd
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL WAVE
+;
+; @func DWORD | waveIMessage | This function sends messages to the waveform
+; output device drivers.
+;
+; @parm HWAVE | hWave | The handle to the audio device.
+;
+; @parm UINT | wMsg | The message to send.
+;
+; @parm DWORD | dwP1 | Parameter 1.
+;
+; @parm DWORD | dwP2 | Parameter 2.
+;
+; @rdesc Returns the value returned from the thunk.
+;-----------------------------------------------------------------------;
+cProc waveIMessage, <NEAR, PUBLIC, PASCAL>, <>
+ ParmW hWave
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz waveIMessage_exit
+
+ mov bx,hWave ; bx = hWave
+ mov ax,WORD PTR [bx+8] ; ax = bx->wDeviceID
+
+ cmp ax,WAVE_MAPPER ; Is this the wave mapper
+ jnz @f ; No so thunk to the 32 bit code.
+
+ cmp [widMapper].hi,0 ; No wave mapper loaded
+ jz @f ; so jump to 32 bit code
+
+ push ax ; push device id
+ push wMsg ; push message
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ call DWORD PTR [widMapper]
+
+ jmp waveIMessage_exit
+
+@@:
+ sub dx,dx ; dx = 0
+
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push wid32Message.sel
+ push wid32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+waveIMessage_exit:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL WAVE
+;
+; @func UINT | waveIIDMessage | This function opens a 32 bit wave device
+; on behalf of a 16 bit application.
+;
+; @parm UINT | wDeviceID | Device ID to send message to.
+;
+; @parm UINT | wMessage | The message to send.
+;
+; @parm DWORD | dwUser | The users private DWORD.
+;
+; @parm DWORD | dwParam1 | Parameter 1.
+;
+; @parm DWORD | dwParam2 | Parameter 2.
+;
+; @rdesc The return value is the low word of the returned message.
+;-----------------------------------------------------------------------;
+cProc waveIIDMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW wDeviceID
+ ParmW wMsg
+ ParmD dwUser
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz waveIIDMessage_exit
+
+ mov ax,wDeviceID
+ cmp ax,WAVE_MAPPER ; Is this the wave mapper
+ jnz @f ; No so thunk to the 32 bit code.
+
+ cmp [widMapper].hi,0 ; No wave mapper loaded
+ jz @f ; so jump to 32 bit code
+
+ push ax ; push device id
+ push wMsg ; push message
+
+ push dwUser.hi
+ push dwUser.lo
+ push dw1.hi
+ push dw1.lo
+ push dw2.hi
+ push dw2.lo
+
+ call DWORD PTR [widMapper]
+
+ jmp waveIIDMessage_exit
+
+@@:
+ sub dx,dx
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push dwUser.hi
+ push dwUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push wid32Message.sel
+ push wid32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+waveIIDMessage_exit:
+cEnd
+
+sEnd
+
+
+createSeg FIX, CodeFix, word, public, CODE
+
+sBegin CodeFix
+ assumes cs,CodeFix
+ assumes ds,nothing
+ assumes es,nothing
+
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL MIDI
+;
+; @func DWORD | midiOMessage | This function sends messages to the midiform
+; output device drivers.
+;
+; @parm HMIDI | hMidi | The handle to the audio device.
+;
+; @parm UINT | wMsg | The message to send.
+;
+; @parm DWORD | dwP1 | Parameter 1.
+;
+; @parm DWORD | dwP2 | Parameter 2.
+;
+; @rdesc Returns the value returned from the thunk.
+;-----------------------------------------------------------------------;
+cProc midiOMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW hMidi
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ mov bx,hMidi ; bx = hMidi
+ mov ax,WORD PTR [bx+8] ; ax = bx->wDeviceID
+ sub dx,dx ; dx = 0
+
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push mod32Message.sel
+ push mod32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL MIDI
+;
+; @func DWORD | midiIMessage | This function sends messages to the midiform
+; output device drivers.
+;
+; @parm HMIDI | hMidi | The handle to the audio device.
+;
+; @parm UINT | wMsg | The message to send.
+;
+; @parm DWORD | dwP1 | Parameter 1.
+;
+; @parm DWORD | dwP2 | Parameter 2.
+;
+; @rdesc Returns the value returned from the thunk.
+;-----------------------------------------------------------------------;
+cProc midiIMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW hMidi
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ mov bx,hMidi ; bx = hMidi
+ mov ax,WORD PTR [bx+8] ; ax = bx->wDeviceID
+ sub dx,dx ; dx = 0
+
+ push dx
+ push ax
+
+ push dx
+ push wMsg
+
+ push WORD PTR [bx+6] ; push bx->dwDrvUser.hi
+ push WORD PTR [bx+4] ; push bx->dwDrvUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push mid32Message.sel
+ push mid32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+sEnd
+
+
+createSeg MIDI, MidiSeg, word, public, CODE
+
+sBegin MidiSeg
+ assumes cs,MidiSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL MIDI
+;
+; @func UINT | midiOIDMessage | This function opens a 32 bit midi device
+; on behalf of a 16 bit application.
+;
+; @parm UINT | wDeviceID | Device ID to send message to.
+;
+; @parm UINT | wMessage | The message to send.
+;
+; @parm DWORD | dwUser | The users private DWORD.
+;
+; @parm DWORD | dwParam1 | Parameter 1.
+;
+; @parm DWORD | dwParam2 | Parameter 2.
+;
+; @rdesc The return value is the low word of the returned message.
+;-----------------------------------------------------------------------;
+cProc midiOIDMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW wDeviceID
+ ParmW wMsg
+ ParmD dwUser
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ sub dx,dx
+
+ push dx
+ push wDeviceID
+
+ push dx
+ push wMsg
+
+ push dwUser.hi
+ push dwUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push mod32Message.sel
+ push mod32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+cEnd
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL MIDI
+;
+; @func UINT | midiIIDMessage | This function opens a 32 bit midi device
+; on behalf of a 16 bit application.
+;
+; @parm UINT | wDeviceID | Device ID to send message to.
+;
+; @parm UINT | wMessage | The message to send.
+;
+; @parm DWORD | dwUser | The users private DWORD.
+;
+; @parm DWORD | dwParam1 | Parameter 1.
+;
+; @parm DWORD | dwParam2 | Parameter 2.
+;
+; @rdesc The return value is the low word of the returned message.
+;-----------------------------------------------------------------------;
+cProc midiIIDMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW wDeviceID
+ ParmW wMsg
+ ParmD dwUser
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ sub dx,dx
+ push dx
+ push wDeviceID
+
+ push dx
+ push wMsg
+
+ push dwUser.hi
+ push dwUser.lo
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push mid32Message.sel
+ push mid32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+
+sEnd
+
+
+createSeg MCI, MciSeg, word, public, CODE
+
+sBegin MciSeg
+ assumes cs,MciSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+; mciMessage
+;
+;
+;-----------------------------------------------------------------------;
+cProc mciMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+ ParmD dw3
+ ParmD dw4
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ sub dx,dx
+ push dx
+ push wMsg
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push dw3.hi
+ push dw3.lo
+
+ push dw4.hi
+ push dw4.lo
+
+ push mci32Message.sel
+ push mci32Message.off
+
+ push dx
+ push 1 ; set directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+sEnd
+
+
+createSeg RARE, RareSeg, word, public, CODE
+
+sBegin RareSeg
+ assumes cs,RareSeg
+ assumes ds,nothing
+ assumes es,nothing
+
+;-----------------------------------------------------------------------;
+; @doc INTERNAL AUX
+;
+; @func UINT | auxOutMessage | This function opens a 32 bit midi device
+; on behalf of a 16 bit application.
+;
+; @parm FARPROC | lpProc | The 32 bit function that will get called.
+;
+; @parm UINT | wDeviceID | Device ID to send message to.
+;
+; @parm UINT | wMessage | The message to send.
+;
+; @parm DWORD | dwParam1 | Parameter 1.
+;
+; @parm DWORD | dwParam2 | Parameter 2.
+;
+; @rdesc The return value is the low word of the returned message.
+;-----------------------------------------------------------------------;
+cProc auxOutMessage, <FAR, PUBLIC, PASCAL, LOADDS>, <>
+ ParmW wDeviceID
+ ParmW wMsg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ sub dx,dx
+ push dx
+ push wDeviceID
+
+ push dx
+ push wMsg
+
+ push dx
+ push dx
+
+ push dw1.hi
+ push dw1.lo
+
+ push dw2.hi
+ push dw2.lo
+
+ push aux32Message.sel
+ push aux32Message.off
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+
+;*****************************Private*Routine******************************\
+; joyMessage
+;
+;
+;
+; History:
+; 27-09-93 - StephenE - Created
+;
+;**************************************************************************/
+cProc joyMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW hdrv,
+ ParmW wMsg,
+ ParmD dw1,
+ ParmD dw2
+cBegin
+ call CheckThunkInit
+ or ax,ax
+ jnz @F
+
+ sub dx,dx
+ push dx
+ mov ax,hdrv
+
+ dec ax ; uDevID
+ push ax ;
+
+ push dx ; uMsg
+ push wMsg ;
+
+ push dx ; dummy dwInstance
+ push dx ;
+
+ push dw1.hi ; dwParam1
+ push dw1.lo ;
+
+ push dw2.hi ; dwParam2
+ push dw2.lo ;
+
+ push joy32Message.sel ; Address of function to be called
+ push joy32Message.off ;
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+@@:
+cEnd
+
+;******************************Public*Routine******************************\
+; Notify_Callback_Data
+;
+;
+;
+; History:
+; 27-09-93 - StephenE - Created
+;
+;**************************************************************************/
+cProc Notify_Callback_Data, <FAR, PUBLIC, PASCAL>, <>
+ ParmD CallbackData
+cBegin
+ sub dx,dx
+
+ push dx ; Dummy uDevId
+ push dx ;
+
+ push dx ; Dummy uMsg
+ push dx ;
+
+ push dx ; Dummy dwInstance
+ push dx ;
+
+ push dx ; Dummy dwParam1
+ push dx ;
+
+ push CallbackData.hi ; Real dwParam2
+ push CallbackData.lo ;
+
+ push cb32.sel ; Address of function to be called
+ push cb32.off ;
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+cEnd
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/mmsystem/thunks.h b/private/mvdm/wow16/mmsystem/thunks.h
new file mode 100644
index 000000000..81a86f8ec
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/thunks.h
@@ -0,0 +1,184 @@
+/******************************Module*Header*******************************\
+* Module Name: thunks.h
+*
+* Function prototypes for Multi-Media thunk functions
+*
+*
+* Created: 27-09-93
+* Author: Stephen Estrop [StephenE]
+*
+* Copyright (c) 1993 Microsoft Corporation
+\**************************************************************************/
+#include <wowmmcb.h>
+
+extern DWORD FAR PASCAL mmwow32Lib; // in stack.asm
+
+/* -------------------------------------------------------------------------
+** Wave stuff
+** -------------------------------------------------------------------------
+*/
+#ifndef MMNOWAVE
+extern DWORD NEAR PASCAL
+waveOMessage(
+ HWAVE hWave,
+ UINT msg,
+ DWORD dwP1,
+ DWORD dwP2
+ );
+
+extern DWORD NEAR PASCAL
+waveIMessage(
+ HWAVE hWave,
+ UINT msg,
+ DWORD dwP1,
+ DWORD dwP2
+ );
+
+extern UINT FAR PASCAL
+waveOIDMessage(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+
+extern UINT FAR PASCAL
+waveIIDMessage(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+#endif
+
+/* -------------------------------------------------------------------------
+** midi stuff
+** -------------------------------------------------------------------------
+*/
+#ifndef MMNOWAVE
+extern DWORD FAR PASCAL
+midiOMessage(
+ HMIDI hMidi,
+ UINT msg,
+ DWORD dwP1,
+ DWORD dwP2
+ );
+
+extern UINT FAR PASCAL
+midiOIDMessage(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+extern DWORD FAR PASCAL
+midiIMessage(
+ HMIDI hMidi,
+ UINT msg,
+ DWORD dwP1,
+ DWORD dwP2
+ );
+
+extern UINT FAR PASCAL
+midiIIDMessage(
+ UINT wDeviceID,
+ UINT wMessage,
+ DWORD dwUser,
+ DWORD dwParam1,
+ DWORD dwParam2
+ );
+#endif
+
+/* -------------------------------------------------------------------------
+** Joystick stuff
+** -------------------------------------------------------------------------
+*/
+typedef DWORD (FAR PASCAL *JOYMESSAGEPROC)( HDRVR, UINT, DWORD, DWORD );
+extern UINT FAR PASCAL
+joyMessage(
+ HDRVR hdrv,
+ UINT msg,
+ LPARAM dw1,
+ LPARAM dw2
+ );
+
+/* -------------------------------------------------------------------------
+** Timer stuff
+** -------------------------------------------------------------------------
+*/
+typedef LRESULT (FAR PASCAL *TIDMESSAGEPROC)( UINT, LPARAM, LPARAM );
+extern TIDMESSAGEPROC FAR PASCAL tid32Message; // stack.asm
+extern DWORD FAR PASCAL // stack.asm
+timeMessage(
+ UINT msg,
+ LPARAM dw1,
+ LPARAM dw2
+ );
+
+
+/* -------------------------------------------------------------------------
+** MCI Stuff
+** -------------------------------------------------------------------------
+*/
+typedef DWORD (CALLBACK MCIMESSAGE)( DWORD, DWORD, DWORD, DWORD, DWORD );
+typedef MCIMESSAGE FAR *LPMCIMESSAGE;
+extern LPMCIMESSAGE PASCAL mci32Message;
+
+extern DWORD FAR PASCAL
+mciMessage(
+ UINT wMsg,
+ DWORD dwP1,
+ DWORD dwP2,
+ DWORD dwP3,
+ DWORD dwP4
+ );
+
+#define THUNK_MCI_SENDCOMMAND 0x0001
+#define THUNK_MCI_SENDSTRING 0x0002
+#define THUNK_MCI_GETDEVICEID 0x0003
+#define THUNK_MCI_GETDEVIDFROMELEMID 0x0004
+#define THUNK_MCI_GETERRORSTRING 0x0005
+#define THUNK_MCI_EXECUTE 0x0006
+#define THUNK_MCI_SETYIELDPROC 0x0007
+#define THUNK_MCI_GETYIELDPROC 0x0008
+#define THUNK_MCI_GETCREATORTASK 0x0009
+#define THUNK_TIMEGETTIME 0x000A
+#define THUNK_APP_EXIT 0x000B
+#define THUNK_MCI_ALLOCATE_NODE 0x000C
+#define THUNK_MCI_FREE_NODE 0x000D
+
+/* -------------------------------------------------------------------------
+** Interrupt callback stuff
+** -------------------------------------------------------------------------
+*/
+typedef VOID (CALLBACK CB32)( VPCALLBACK_DATA vpCallbackData );
+typedef CB32 FAR * LPCB32;
+extern VPCALLBACK_DATA FAR PASCAL vpCallbackData; // in STACK.ASM
+extern HGLOBAL FAR PASCAL hGlobal; // in STACK.ASM
+int FAR PASCAL
+InstallInterruptHandler(
+ void
+ );
+
+int FAR PASCAL
+DeInstallInterruptHandler(
+ void
+ );
+
+VOID FAR PASCAL
+Notify_Callback_Data(
+ VPCALLBACK_DATA vpCallbackData
+ );
+
+BOOL FAR PASCAL
+ StackInit(
+ void
+ );
+
+BOOL NEAR PASCAL
+StackTerminate(
+ void
+ );
diff --git a/private/mvdm/wow16/mmsystem/time.c b/private/mvdm/wow16/mmsystem/time.c
new file mode 100644
index 000000000..5ebcddcd5
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/time.c
@@ -0,0 +1,404 @@
+/******************************************************************************
+
+ Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
+
+ Title: TIME.C : MMSYSTEM TIMER API
+
+ Version: 1.00
+
+*****************************************************************************/
+
+//
+// ***DANGER WARNING****
+//
+// none of these functions in this file need the default data segment
+// so we undefine BUILDDLL, if you write code in this file that needs
+// DS == DGROUP be warned!
+//
+// NOTE: most of this code is interupt time enterable, so we don't want
+// it touching DGROUP anyway!
+//
+#undef BUILDDLL
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "drvr.h"
+#include "thunks.h"
+
+
+#define MIN_RES 1
+#define MIN_DELAY 6
+
+//
+// Define moveable code for timer interface.
+//
+#pragma alloc_text( RARE, timeGetDevCaps )
+
+extern SZCODE szTimerDrv[]; // see init.c
+
+//
+// Define the init code for this file.
+//
+#pragma alloc_text( INIT, TimeInit )
+
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | timeGetSystemTime | This function retrieves the system time
+ in milliseconds. The system time is the time elapsed since
+ Windows was started.
+
+ @parm LPMMTIME | lpTime | Specifies a far pointer to an <t MMTIME> data
+ structure.
+
+ @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
+
+ @rdesc Returns zero.
+ The system time is returned in the <e MMTIME.ms> field of the <t MMTIME>
+ structure.
+
+ @comm The time is always returned in milliseconds.
+
+ @xref timeGetTime
+****************************************************************************/
+UINT WINAPI
+timeGetSystemTime(
+ LPMMTIME lpTime,
+ UINT wSize
+ )
+{
+ //
+ // !!!WARNING DS is not setup right!!! see above
+ //
+ if (wSize < sizeof(MMTIME))
+ return TIMERR_STRUCT;
+
+ lpTime->u.ms = timeGetTime();
+ lpTime->wType = TIME_MS;
+
+ return TIMERR_NOERROR;
+}
+
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | timeSetEvent | This function sets up a timed callback event.
+ The event can be a one-time event or a periodic event. Once activated,
+ the event calls the specified callback function.
+
+ @parm UINT | wDelay | Specifies the event period in milliseconds.
+ If the delay is less than the minimum period supported by the timer,
+ or greater than the maximum period supported by the timer, the
+ function returns an error.
+
+ @parm UINT | wResolution | Specifies the accuracy of the delay in
+ milliseconds. The resolution of the timer event increases with
+ smaller <p wResolution> values. To reduce system overhead, use
+ the maximum <p wResolution> value appropriate for your application.
+
+ @parm LPTIMECALLBACK | lpFunction | Specifies the procedure address of
+ a callback function that is called once upon expiration of a one-shot
+ event or periodically upon expiration of periodic events.
+
+ @parm DWORD | dwUser | Contains user-supplied callback data.
+
+ @parm UINT | wFlags | Specifies the type of timer event, using one of
+ the following flags:
+
+ @flag TIME_ONESHOT | Event occurs once, after <p wPeriod> milliseconds.
+
+ @flag TIME_PERIODIC | Event occurs every <p wPeriod> milliseconds.
+
+ @rdesc Returns an ID code that identifies the timer event. Returns
+ NULL if the timer event was not created. The ID code is also passed to
+ the callback function.
+
+ @comm Using this function to generate a high-frequency periodic-delay
+ event (with a period less than 10 milliseconds) can consume a
+ significant portion of the system CPU bandwidth. Any call to
+ <f timeSetEvent> for a periodic-delay timer
+ must be paired with a call to <f timeKillEvent>.
+
+ The callback function must reside in a DLL. You don't have to use
+ <f MakeProcInstance> to get a procedure-instance address for the callback
+ function.
+
+ @cb void CALLBACK | TimeFunc | <f TimeFunc> is a placeholder for the
+ application-supplied function name. The actual name must be exported by
+ including it in the EXPORTS statement of the module-definition file for
+ the DLL.
+
+ @parm UINT | wID | The ID of the timer event. This is the ID returned
+ by <f timeSetEvent>.
+
+ @parm UINT | wMsg | Not used.
+
+ @parm DWORD | dwUser | User instance data supplied to the <p dwUser>
+ parameter of <f timeSetEvent>.
+
+ @parm DWORD | dw1 | Not used.
+
+ @parm DWORD | dw2 | Not used.
+
+ @comm Because the callback is accessed at interrupt time, it must
+ reside in a DLL, and its code segment must be specified as FIXED
+ in the module-definition file for the DLL. Any data that the
+ callback accesses must be in a FIXED data segment as well.
+ The callback may not make any system calls except for <f PostMessage>,
+ <f timeGetSystemTime>, <f timeGetTime>, <f timeSetEvent>,
+ <f timeKillEvent>, <f midiOutShortMsg>,
+ <f midiOutLongMsg>, and <f OutputDebugStr>.
+
+ @xref timeKillEvent timeBeginPeriod timeEndPeriod
+
+****************************************************************************/
+UINT WINAPI
+timeSetEvent(
+ UINT wDelay,
+ UINT wResolution,
+ LPTIMECALLBACK lpFunction,
+ DWORD dwUser,
+ UINT wFlags
+ )
+{
+ //
+ // !!!WARNING DS is not setup right!!! see above
+ //
+ TIMEREVENT timerEvent;
+
+ V_TCALLBACK(lpFunction, MMSYSERR_INVALPARAM);
+
+ //
+ // the first time this is called init the stacks
+ // !!!this assumes the first caller will not be at interupt time!!
+ //
+// if (!(WinFlags & WF_ENHANCED))
+// timeStackInit();
+
+ wDelay = max( MIN_DELAY, wDelay );
+ wResolution = max( MIN_RES, wResolution );
+
+ timerEvent.wDelay = wDelay;
+ timerEvent.wResolution = wResolution;
+ timerEvent.lpFunction = lpFunction;
+ timerEvent.dwUser = dwUser;
+ timerEvent.wFlags = wFlags;
+
+ return (UINT)timeMessage( TDD_SETTIMEREVENT, (LPARAM)(LPVOID)&timerEvent,
+ (LPARAM)GetCurrentTask() );
+}
+
+
+
+/****************************************************************************
+
+ @doc EXTERNAL
+
+ @api UINT | timeGetDevCaps | This function queries the timer device to
+ determine its capabilities.
+
+ @parm LPTIMECAPS | lpTimeCaps | Specifies a far pointer to a
+ <t TIMECAPS> structure. This structure is filled with information
+ about the capabilities of the timer device.
+
+ @parm UINT | wSize | Specifies the size of the <t TIMECAPS> structure.
+
+ @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if it fails
+ to return the timer device capabilities.
+
+****************************************************************************/
+UINT WINAPI
+timeGetDevCaps(
+ LPTIMECAPS lpTimeCaps,
+ UINT wSize
+ )
+{
+ //
+ // !!!WARNING DS is not setup right!!! see above
+ //
+ return (UINT)timeMessage( TDD_GETDEVCAPS, (LPARAM)lpTimeCaps,
+ (LPARAM)(DWORD)wSize);
+}
+
+
+
+/******************************Public*Routine******************************\
+* timeBeginPeriod
+*
+* @doc EXTERNAL
+*
+* @api WORD | timeBeginPeriod | This function sets the minimum (lowest
+* number of milliseconds) timer resolution that an application or
+* driver is going to use. Call this function immediately before starting
+* to use timer-event services, and call <f timeEndPeriod> immediately
+* after finishing with the timer-event services.
+*
+* @parm WORD | wPeriod | Specifies the minimum timer-event resolution
+* that the application or driver will use.
+*
+* @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the specified
+* <p wPeriod> resolution value is out of range.
+*
+* @xref timeEndPeriod timeSetEvent
+*
+* @comm For each call to <f timeBeginPeriod>, you must call
+* <f timeEndPeriod> with a matching <p wPeriod> value.
+* An application or driver can make multiple calls to <f timeBeginPeriod>,
+* as long as each <f timeBeginPeriod> call is matched with a
+* <f timeEndPeriod> call.
+*
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT WINAPI
+timeBeginPeriod(
+ UINT uPeriod
+ )
+{
+ uPeriod = max( MIN_RES, uPeriod );
+ return (UINT)timeMessage( TDD_BEGINMINPERIOD, (LPARAM)uPeriod, 0L );
+}
+
+
+
+/******************************Public*Routine******************************\
+* timeEndPeriod
+*
+* @doc EXTERNAL
+*
+* @api WORD | timeEndPeriod | This function clears a previously set
+* minimum (lowest number of milliseconds) timer resolution that an
+* application or driver is going to use. Call this function
+* immediately after using timer event services.
+*
+* @parm WORD | wPeriod | Specifies the minimum timer-event resolution
+* value specified in the previous call to <f timeBeginPeriod>.
+*
+* @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the specified
+* <p wPeriod> resolution value is out of range.
+*
+* @xref timeBeginPeriod timeSetEvent
+*
+* @comm For each call to <f timeBeginPeriod>, you must call
+* <f timeEndPeriod> with a matching <p wPeriod> value.
+* An application or driver can make multiple calls to <f timeBeginPeriod>,
+* as long as each <f timeBeginPeriod> call is matched with a
+* <f timeEndPeriod> call.
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT WINAPI
+timeEndPeriod(
+ UINT uPeriod
+ )
+{
+ uPeriod = max( MIN_RES, uPeriod );
+ return (UINT)timeMessage( TDD_ENDMINPERIOD, (LPARAM)uPeriod, 0L );
+}
+
+
+
+/******************************Public*Routine******************************\
+*
+* timeKillEvent
+*
+* @doc EXTERNAL
+*
+* @api WORD | timeKillEvent | This functions destroys a specified timer
+* callback event.
+*
+* @parm WORD | wID | Identifies the event to be destroyed.
+*
+* @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the
+* specified timer event does not exist.
+*
+* @comm The timer event ID specified by <p wID> must be an ID
+* returned by <f timeSetEvent>.
+*
+* @xref timeSetEvent
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+UINT WINAPI
+timeKillEvent(
+ UINT wID
+ )
+{
+ if ( 0 == wID ) {
+ return 0;
+ }
+ return (UINT)timeMessage( TDD_KILLTIMEREVENT, (LPARAM)wID, 0L );
+}
+
+
+/******************************Public*Routine******************************\
+* timeGetTime
+*
+* @doc EXTERNAL
+*
+* @api DWORD | timeGetTime | This function retrieves the system time
+* in milliseconds. The system time is the time elapsed since
+* Windows was started.
+*
+* @rdesc The return value is the system time in milliseconds.
+*
+* @comm The only difference between this function and
+* the <f timeGetSystemTime> function is <f timeGetSystemTime>
+* uses the standard multimedia time structure <t MMTIME> to return
+* the system time. The <f timeGetTime> function has less overhead than
+* <f timeGetSystemTime>.
+*
+* @xref timeGetSystemTime
+*
+*
+*
+* History:
+* dd-mm-93 - StephenE - Created
+*
+\**************************************************************************/
+DWORD WINAPI
+timeGetTime(
+ void
+ )
+{
+ return timeMessage( TDD_GETSYSTEMTIME, 0L, 0L );
+}
+
+
+/****************************************************************************
+
+ @doc INTERNAL
+
+ @api BOOL | TimeInit | This function initialises the timer services.
+
+ @rdesc The return value is TRUE if the services are initialised, FALSE
+ if an error occurs.
+
+ @comm it is not a FATAL error if a timer driver is not installed, this
+ routine will allways return TRUE
+
+****************************************************************************/
+BOOL NEAR PASCAL TimeInit(void)
+{
+ OpenDriver(szTimerDrv, NULL, 0L) ;
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow16/mmsystem/timea.asm b/private/mvdm/wow16/mmsystem/timea.asm
new file mode 100644
index 000000000..ae26243d4
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/timea.asm
@@ -0,0 +1,360 @@
+ page ,132
+;-----------------------------Module-Header-----------------------------;
+; Module Name: TIMEA.ASM - Some time functions
+;
+; Copyright (c) 1984-1991 Microsoft Corporation
+;
+;-----------------------------------------------------------------------;
+
+ ?PLM = 1
+ ?WIN = 0
+ PMODE = 1
+
+ .xlist
+ include cmacros.inc
+ include windows.inc
+ include mmsystem.inc
+ include mmddk.inc
+ .list
+
+ externFP DefTimerProc ; in TIME.C
+ externFP StackInit ; in INIT.C
+ externFP CheckThunkInit ; in stack.asm
+ externFP MMCALLPROC32 ; in Stack.asm
+
+;-----------------------------------------------------------------------;
+
+createSeg FIX, CodeFix, word, public, CODE
+createSeg INTDS, DataFix, byte, public, DATA
+
+sBegin DataFix
+ public lpTimeMsgProc
+ public hTimeDrv
+
+ lpTimeMsgProc dd DefTimerProc ; timer driver entry point
+ hTimeDrv dw 0 ; driver handle for timer
+
+ externW gwStackSize ; in STACK.ASM
+ externD tid32Message ; in Stack.asm
+sEnd
+
+sBegin CodeFix
+ assumes cs,CodeFix
+ assumes ds,nothing
+ assumes es,nothing
+
+ externW CodeFixDS ; in STACK.ASM
+ externW CodeFixWinFlags
+
+;-----------------------------------------------------------------------;
+;
+; @doc EXTERNAL
+;
+; @api WORD | timeBeginPeriod | This function sets the minimum (lowest
+; number of milliseconds) timer resolution that an application or
+; driver is going to use. Call this function immediately before starting
+; to use timer-event services, and call <f timeEndPeriod> immediately
+; after finishing with the timer-event services.
+;
+; @parm WORD | wPeriod | Specifies the minimum timer-event resolution
+; that the application or driver will use.
+;
+; @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the specified
+; <p wPeriod> resolution value is out of range.
+;
+; @xref timeEndPeriod timeSetEvent
+;
+; @comm For each call to <f timeBeginPeriod>, you must call
+; <f timeEndPeriod> with a matching <p wPeriod> value.
+; An application or driver can make multiple calls to <f timeBeginPeriod>,
+; as long as each <f timeBeginPeriod> call is matched with a
+; <f timeEndPeriod> call.
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeBeginPeriod, <FAR, PUBLIC, PASCAL>, <>
+; ParmW wPeriod
+cBegin <nogen>
+;
+; Below is a hack to knobble the minimum period that we support
+; on WOW. 6 ms is about all that a 486dx can cope with.
+;
+ push bp
+ mov bp,sp
+ mov ax,word ptr [bp+6]
+ cmp ax,5
+
+ ja @f
+ mov word ptr [bp+6],6
+@@:
+ pop bp
+
+;
+; start of original code.
+;
+ mov bx, TDD_BEGINMINPERIOD
+ jmp short timeMessageWord
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc EXTERNAL
+;
+; @api WORD | timeEndPeriod | This function clears a previously set
+; minimum (lowest number of milliseconds) timer resolution that an
+; application or driver is going to use. Call this function
+; immediately after using timer event services.
+;
+; @parm WORD | wPeriod | Specifies the minimum timer-event resolution
+; value specified in the previous call to <f timeBeginPeriod>.
+;
+; @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the specified
+; <p wPeriod> resolution value is out of range.
+;
+; @xref timeBeginPeriod timeSetEvent
+;
+; @comm For each call to <f timeBeginPeriod>, you must call
+; <f timeEndPeriod> with a matching <p wPeriod> value.
+; An application or driver can make multiple calls to <f timeBeginPeriod>,
+; as long as each <f timeBeginPeriod> call is matched with a
+; <f timeEndPeriod> call.
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeEndPeriod, <FAR, PUBLIC, PASCAL>, <>
+; ParmW wPeriod
+cBegin <nogen>
+;
+; Below is a hack to knobble the minimum period that we support
+; on WOW. 6 ms is about all that a 486dx can cope with.
+;
+ push bp
+ mov bp,sp
+ mov ax,word ptr [bp+6]
+ cmp ax,5
+
+ ja @f
+ mov word ptr [bp+6],6
+@@:
+ pop bp
+
+;
+; start of original code.
+;
+ mov bx, TDD_ENDMINPERIOD
+ jmp short timeMessageWord
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc EXTERNAL
+;
+; @api WORD | timeKillEvent | This functions destroys a specified timer
+; callback event.
+;
+; @parm WORD | wID | Identifies the event to be destroyed.
+;
+; @rdesc Returns zero if successful. Returns TIMERR_NOCANDO if the
+; specified timer event does not exist.
+;
+; @comm The timer event ID specified by <p wID> must be an ID
+; returned by <f timeSetEvent>.
+;
+; @xref timeSetEvent
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeKillEvent, <FAR, PUBLIC, PASCAL>, <>
+; ParmW wId
+cBegin <nogen>
+ mov bx, TDD_KILLTIMEREVENT
+ errn$ timeMessageWord
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc INTERNAL
+;
+; @api DWORD | timeMessageWord | send a message to the timer driver
+;
+; @reg bx | message to send to driver
+;
+; @parm WORD | w | WORD to send to driver
+;
+; @rdesc Returns zero if successful, error code otherwise
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeMessageWord, <FAR, PUBLIC, PASCAL>, <>
+; ParmW w
+cBegin <nogen>
+ pop ax ; DX:AX = return addr.
+ pop dx
+ pop cx ; CX = LOWORD(dw1)
+
+ mov es, [CodeFixDS]
+ assumes es, DataFix
+
+ push 0 ; 0
+ push 0 ; 0
+ push es:[hTimeDrv]
+ push bx ; Message
+ xor bx,bx
+ push bx ; 0
+ push cx ; wParam
+ push bx ; 0
+ push bx ; 0
+ push dx ; Return address
+ push ax
+ jmp DWORD PTR es:[lpTimeMsgProc]
+
+cEnd <nogen>
+
+;-----------------------------------------------------------------------;
+;
+; @doc EXTERNAL
+;
+; @api DWORD | timeGetTime | This function retrieves the system time
+; in milliseconds. The system time is the time elapsed since
+; Windows was started.
+;
+; @rdesc The return value is the system time in milliseconds.
+;
+; @comm The only difference between this function and
+; the <f timeGetSystemTime> function is <f timeGetSystemTime>
+; uses the standard multimedia time structure <t MMTIME> to return
+; the system time. The <f timeGetTime> function has less overhead than
+; <f timeGetSystemTime>.
+;
+; @xref timeGetSystemTime
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeGetTime, <FAR, PUBLIC, PASCAL>, <>
+cBegin
+ call CheckThunkInit ; changes es to point to fixed data seg
+ or ax,ax
+ jnz @F
+
+ sub dx,dx
+
+ push dx ; api encoded number
+ push 0Ah ; see THUNK_TIMEGETTIME in thunks.h
+
+ push dx ; Dummy dw1
+ push dx ;
+
+ push dx ; Dummy dw2
+ push dx ;
+
+ push dx ; Dummy dw3
+ push dx ;
+
+ push dx ; Dummy dw4
+ push dx ;
+
+ push es:tid32Message.sel ; Address of function to be called
+ push es:tid32Message.off ;
+
+ push dx
+ push dx ; no directory change
+
+ call FAR PTR MMCALLPROC32 ; call the 32 bit code
+
+@@:
+cEnd
+
+
+;-----------------------------------------------------------------------;
+;
+; @doc INTERNAL
+;
+; @api void | timeStackInit | in 286p mode init the stacks when
+; timeSetEvent() is called for the first time.
+;
+; @xref timeSetEvent
+;
+; @rdesc none
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeStackInit, <NEAR, PUBLIC, PASCAL>, <>
+cBegin
+ test cs:[CodeFixWinFlags], WF_WIN386
+ jnz timeStackInitExit
+
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+
+ mov ax,es:[gwStackSize]
+ or ax,ax
+ jnz timeStackInitExit
+
+ push ds ; set DS = DGROUP
+ mov ax,DGROUP
+ mov ds,ax
+ cCall StackInit
+ pop ds
+
+timeStackInitExit:
+cEnd
+
+;-----------------------------------------------------------------------;
+;
+; @doc INTERNAL
+;
+; @api DWORD | timeMessage | send a message to the timer driver
+;
+; @parm WORD | msg | message to send
+;
+; @parm DWORD | dw1 | first DWORD
+;
+; @parm DWORD | dw2 | first DWORD
+;
+; @rdesc Returns zero if successful, error code otherwise
+;
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timeMessage, <FAR, PUBLIC, PASCAL>, <>
+ ParmW msg
+ ParmD dw1
+ ParmD dw2
+cBegin
+ mov es,[CodeFixDS]
+ assumes es,DataFix
+
+ xor ax,ax
+ push ax ; dwDriverId
+ push ax
+ push es:[hTimeDrv]
+ push msg ; Message passed
+ push dw1.hi
+ push dw1.lo
+ push dw2.hi
+ push dw2.lo
+ call DWORD PTR es:[lpTimeMsgProc]
+
+timeMessageExit:
+cEnd
+
+;-----------------------------------------------------------------------;
+
+sEnd CodeFix
+
+;-----------------------------------------------------------------------;
+
+END
diff --git a/private/mvdm/wow16/mmsystem/wave.c b/private/mvdm/wow16/mmsystem/wave.c
new file mode 100644
index 000000000..62bb55cbf
--- /dev/null
+++ b/private/mvdm/wow16/mmsystem/wave.c
@@ -0,0 +1,1862 @@
+/****************************************************************************
+ wave.c
+
+ Level 1 kitchen sink DLL wave support module
+
+ Copyright (c) Microsoft Corporation 1990. All rights reserved
+
+****************************************************************************/
+
+#include <windows.h>
+#include "mmsystem.h"
+#include "mmddk.h"
+#include "mmsysi.h"
+#include "thunks.h"
+
+/* -------------------------------------------------------------------------
+** Local functions
+** -------------------------------------------------------------------------
+*/
+static UINT NEAR PASCAL
+waveGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ );
+
+/* -------------------------------------------------------------------------
+** Local structures
+** -------------------------------------------------------------------------
+*/
+typedef struct wavedev_tag {
+ PWAVEDRV wavedrv;
+ UINT wDevice;
+ DWORD dwDrvUser;
+ UINT wDeviceID;
+} WAVEDEV, *PWAVEDEV;
+
+/* -------------------------------------------------------------------------
+** @doc INTERNAL WAVE validation code for WAVEHDRs
+** -------------------------------------------------------------------------
+*/
+#define IsWaveHeaderPrepared(hWave, lpwh) \
+ ((lpwh)->dwFlags & WHDR_PREPARED)
+
+#define MarkWaveHeaderPrepared(hWave, lpwh) \
+ ((lpwh)->dwFlags |= WHDR_PREPARED)
+
+#define MarkWaveHeaderUnprepared(hWave, lpwh) \
+ ((lpwh)->dwFlags &=~WHDR_PREPARED)
+
+
+/*****************************************************************************
+ * @doc INTERNAL WAVE
+ *
+ * @api UINT | wavePrepareHeader | This function prepares the header and data
+ * if the driver returns MMSYSERR_NOTSUPPORTED.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it
+ * specifies an error number.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+wavePrepareHeader(
+ LPWAVEHDR lpWaveHdr,
+ UINT wSize
+ )
+{
+ if (!HugePageLock(lpWaveHdr, (DWORD)sizeof(WAVEHDR))) {
+ return MMSYSERR_NOMEM;
+ }
+
+ if (!HugePageLock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength)) {
+ HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
+ return MMSYSERR_NOMEM;
+ }
+
+// lpWaveHdr->dwFlags |= WHDR_PREPARED;
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc INTERNAL WAVE
+ *
+ * @api UINT | waveUnprepareHeader | This function unprepares the header and
+ * data if the driver returns MMSYSERR_NOTSUPPORTED.
+ *
+ * @rdesc Currently always returns MMSYSERR_NOERROR.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+waveUnprepareHeader(
+ LPWAVEHDR lpWaveHdr,
+ UINT wSize
+ )
+{
+ HugePageUnlock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength);
+ HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
+
+// lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
+
+ return MMSYSERR_NOERROR;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetNumDevs | This function retrieves the number of
+ * waveform output devices present in the system.
+ *
+ * @rdesc Returns the number of waveform output devices present in the system.
+ *
+ * @xref waveOutGetDevCaps
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetNumDevs(
+ void
+ )
+{
+ return waveOIDMessage( 0, WODM_GETNUMDEVS, 0L, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api DWORD | waveOutMessage | This function sends messages to the waveform
+ * output device drivers.
+ *
+ * @parm HWAVEOUT | hWaveOut | The handle to the audio device.
+ *
+ * @parm UINT | msg | The message to send.
+ *
+ * @parm DWORD | dw1 | Parameter 1.
+ *
+ * @parm DWORD | dw2 | Parameter 2.
+ *
+ * @rdesc Returns the value returned from the driver.
+ ****************************************************************************/
+DWORD WINAPI
+waveOutMessage(
+ HWAVEOUT hWaveOut,
+ UINT msg,
+ DWORD dw1,
+ DWORD dw2
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, 0L);
+
+ return waveOMessage( (HWAVE)hWaveOut, msg, dw1, dw2);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetDevCaps | This function queries a specified waveform
+ * device to determine its capabilities.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform output device.
+ *
+ * @parm LPWAVEOUTCAPS | lpCaps | Specifies a far pointer to a <t WAVEOUTCAPS>
+ * structure. This structure is filled with information about the
+ * capabilities of the device.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEOUTCAPS> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The WAVE_MAPPER constant may also be used as a device id. Only
+ * <p wSize> bytes (or less) of information is copied to the location
+ * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
+ * the function returns zero.
+ *
+ * @xref waveOutGetNumDevs
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetDevCaps(
+ UINT wDeviceID,
+ LPWAVEOUTCAPS lpCaps,
+ UINT wSize
+ )
+{
+ if (wSize == 0)
+ return MMSYSERR_NOERROR;
+
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+
+ return waveOIDMessage( wDeviceID, WODM_GETDEVCAPS, 0L,
+ (DWORD)lpCaps, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetVolume | This function queries the current volume
+ * setting of a waveform output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform output device.
+ *
+ * @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location to
+ * be filled with the current volume setting. The low-order word of
+ * this location contains the left channel volume setting, and the high-order
+ * WORD contains the right channel setting. A value of 0xFFFF represents
+ * full volume, and a value of 0x0000 is silence.
+ *
+ * If a device does not support both left and right volume
+ * control, the low-order word of the specified location contains
+ * the mono volume level.
+ *
+ * The full 16-bit setting(s)
+ * set with <f waveOutSetVolume> is returned, regardless of whether
+ * the device supports the full 16 bits of volume-level control.
+ *
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Not all devices support volume changes. To determine whether the
+ * device supports volume control, use the WAVECAPS_VOLUME
+ * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
+ * structure (filled by <f waveOutGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both
+ * the left and right channels, use the WAVECAPS_VOLUME
+ * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
+ * structure (filled by <f waveOutGetDevCaps>).
+ *
+ * @xref waveOutSetVolume
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetVolume(
+ UINT wDeviceID,
+ LPDWORD lpdwVolume
+ )
+{
+ V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ return waveOIDMessage( wDeviceID,
+ WODM_GETVOLUME, 0L, (DWORD)lpdwVolume, 0);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutSetVolume | This function sets the volume of a
+ * waveform output device.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform output device.
+ *
+ * @parm DWORD | dwVolume | Specifies the new volume setting. The
+ * low-order word contains the left channel volume setting, and the
+ * high-order word contains the right channel setting. A value of
+ * 0xFFFF represents full volume, and a value of 0x0000 is silence.
+ *
+ * If a device does
+ * not support both left and right volume control, the low-order word of
+ * <p dwVolume> specifies the volume level, and the high-order word is
+ * ignored.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Not all devices support volume changes. To determine whether the
+ * device supports volume control, use the WAVECAPS_VOLUME
+ * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
+ * structure (filled by <f waveOutGetDevCaps>).
+ *
+ * To determine whether the device supports volume control on both the
+ * left and right channels, use the WAVECAPS_LRVOLUME flag
+ * flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
+ * structure (filled by <f waveOutGetDevCaps>).
+ *
+ * Most devices don't support the full 16 bits of volume level control
+ * and will not use the high-order bits of the requested volume setting.
+ * For example, for a device that supports 4 bits of volume control,
+ * requested volume level values of 0x4000, 0x4fff, and 0x43be
+ * all produce the same physical volume setting, 0x4000. The
+ * <f waveOutGetVolume> function returns the full 16-bit setting set
+ * with <f waveOutSetVolume>.
+ *
+ * Volume settings are interpreted logarithmically. This means the
+ * perceived increase in volume is the same when increasing the
+ * volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
+ *
+ * @xref waveOutGetVolume
+ ****************************************************************************/
+UINT WINAPI
+waveOutSetVolume(
+ UINT wDeviceID,
+ DWORD dwVolume
+ )
+{
+ return waveOIDMessage( wDeviceID, WODM_SETVOLUME, 0L, dwVolume, 0);
+}
+
+/*****************************************************************************
+ * @doc INTERNAL WAVE
+ *
+ * @func UINT | waveGetErrorText | This function retrieves a textual
+ * description of the error identified by the specified error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to a buffer which
+ * is filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the length of the buffer pointed to by
+ * <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
+ * is returned.
+ ****************************************************************************/
+static UINT NEAR PASCAL
+waveGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ lpText[0] = 0;
+
+#if MMSYSERR_BASE
+ if ( ((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR))
+ && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR))) {
+
+ return MMSYSERR_BADERRNUM;
+ }
+#else
+ if ( (wError > MMSYSERR_LASTERROR)
+ && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR))) {
+
+ return MMSYSERR_BADERRNUM;
+ }
+#endif
+
+ if (wSize > 1) {
+ if (!LoadString(ghInst, wError, lpText, wSize)) {
+ return MMSYSERR_BADERRNUM;
+ }
+ }
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetErrorText | This function retrieves a
+ * textual description of the error identified by the specified
+ * error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to a buffer to be
+ * filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the length of the buffer pointed
+ * to by <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied, and the function
+ * returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ if (wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
+
+ return waveGetErrorText(wError, lpText, wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutOpen | This function opens a specified waveform output
+ * device for playback.
+ *
+ * @parm LPHWAVEOUT | lphWaveOut | Specifies a far pointer to an HWAVEOUT
+ * handle. This location is filled with a handle identifying the opened
+ * waveform output device. Use the handle to identify the device when
+ * calling other waveform output functions. This parameter may be
+ * NULL if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform output device to open.
+ * Use a valid device ID or the following flag:
+ *
+ * @flag WAVE_MAPPER | If this flag is specified, the function
+ * selects a waveform output device
+ * capable of playing the given format.
+ *
+ * @parm LPWAVEFORMAT | lpFormat | Specifies a pointer to a <t WAVEFORMAT>
+ * structure that identifies the format of the waveform data
+ * to be sent to the waveform output device.
+ *
+ * @parm DWORD | dwCallback | Specifies the address of a callback
+ * function or a handle to a window called during waveform
+ * playback to process messages related to the progress of the playback.
+ * Specify NULL for this parameter if no callback is desired.
+ *
+ * @parm DWORD | dwCallbackInstance | Specifies user instance data
+ * passed to the callback. This parameter is not used with
+ * window callbacks.
+ *
+ * @parm DWORD | dwFlags | Specifies flags for opening the device.
+ * @flag WAVE_FORMAT_QUERY | If this flag is specified, the device is
+ * queried to determine if it supports the given format but is not
+ * actually opened.
+ * @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
+ * device will fail to open if it is a synchronous device.
+ * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
+ * assumed to be a window handle.
+ * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
+ * assumed to be a callback procedure address.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ * @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
+ *
+ * @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The WAVE_MAPPER constant may also be used as a device id.
+ *
+ * The <t WAVEFORMAT> structure pointed to by <p lpFormat> may be extended
+ * to include type-specific information for certain data formats.
+ * For example, for PCM data, an extra UINT is added to specify the number
+ * of bits per sample. Use the <t PCMWAVEFORMAT> structure in this case.
+ *
+ * If a window is chosen to receive callback information, the following
+ * messages are sent to the window procedure function to indicate the
+ * progress of waveform output: <m MM_WOM_OPEN>, <m MM_WOM_CLOSE>,
+ * <m MM_WOM_DONE>
+ *
+ * If a function is chosen to receive callback information, the following
+ * messages are sent to the function to indicate the progress of waveform
+ * output: <m WOM_OPEN>, <m WOM_CLOSE>, <m WOM_DONE>. The callback function
+ * must reside in a DLL. You do not have to use <f MakeProcInstance> to get
+ * a procedure-instance address for the callback function.
+ *
+ * @cb void CALLBACK | WaveOutFunc | <f WaveOutFunc> is a placeholder for the
+ * application-supplied function name. The actual name must be exported by
+ * including it in an EXPORTS statement in the DLL's module-definition file.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform device
+ * associated with the callback.
+ *
+ * @parm UINT | wMsg | Specifies a waveform output message.
+ *
+ * @parm DWORD | dwInstance | Specifies the user instance data
+ * specified with <f waveOutOpen>.
+ *
+ * @parm DWORD | dwParam1 | Specifies a parameter for the message.
+ *
+ * @parm DWORD | dwParam2 | Specifies a parameter for the message.
+ *
+ * @comm Because the callback is accessed at interrupt time, it must reside
+ * in a DLL and its code segment must be specified as FIXED in the
+ * module-definition file for the DLL. Any data that the callback accesses
+ * must be in a FIXED data segment as well. The callback may not make any
+ * system calls except for <f PostMessage>, <f timeGetSystemTime>,
+ * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
+ * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
+ *
+ * @xref waveOutClose
+ ****************************************************************************/
+UINT WINAPI
+waveOutOpen(
+ LPHWAVEOUT lphWaveOut,
+ UINT wDeviceID,
+ const WAVEFORMAT FAR* lpFormat,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD dwFlags
+ )
+{
+ WAVEOPENDESC wo;
+ PWAVEDEV pdev;
+ UINT wRet;
+ DWORD dwDrvUser;
+
+ V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
+ V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
+ V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveOutOpen, MMSYSERR_INVALFLAG);
+
+ if (!(dwFlags & WAVE_FORMAT_QUERY)) {
+ V_WPOINTER(lphWaveOut, sizeof(HWAVEOUT), MMSYSERR_INVALPARAM);
+ *lphWaveOut = NULL;
+ }
+
+
+ /*
+ ** Check for no devices
+ */
+// if (wTotalWaveOutDevs == 0 ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+//
+// /*
+// ** check for device ID being to large
+// */
+// if ( wDeviceID != WAVE_MAPPER ) {
+// if ( wDeviceID >= wTotalWaveOutDevs ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+// }
+
+ if (dwFlags & WAVE_FORMAT_QUERY) {
+ pdev = NULL;
+ }
+ else {
+
+ if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEOUT, sizeof(WAVEDEV)))) {
+ return MMSYSERR_NOMEM;
+ }
+
+ pdev->wDevice = wDeviceID;
+ pdev->wDeviceID = wDeviceID;
+
+ }
+
+ wo.hWave = (HWAVE)pdev;
+ wo.dwCallback = dwCallback;
+ wo.dwInstance = dwInstance;
+ wo.lpFormat = lpFormat;
+
+ if ( (wDeviceID == WAVE_MAPPER) && (wodMapper != NULL) ) {
+
+ wRet = (UINT)((*(wodMapper))(0, WODM_OPEN,
+ (DWORD)(LPDWORD)&dwDrvUser,
+ (DWORD)(LPWAVEOPENDESC)&wo,
+ dwFlags));
+ }
+ else {
+
+ wRet = waveOIDMessage( wDeviceID, WODM_OPEN, (DWORD)(LPDWORD)&dwDrvUser,
+ (DWORD)(LPWAVEOPENDESC)&wo, dwFlags );
+ }
+
+ if (pdev) {
+ if (wRet) {
+ FreeHandle((HWAVEOUT)pdev);
+ }
+ else {
+ *lphWaveOut = (HWAVEOUT)pdev;
+ pdev->dwDrvUser = dwDrvUser;
+ }
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutClose | This function closes the specified waveform
+ * output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device. If the function is successful, the handle is no
+ * longer valid after this call.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
+ *
+ * @comm If the device is still playing a waveform, the close
+ * operation will fail. Use <f waveOutReset> to terminate waveform
+ * playback before calling <f waveOutClose>.
+ *
+ * @xref waveOutOpen waveOutReset
+ ****************************************************************************/
+UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ wRet = (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_CLOSE, 0L,0L);
+
+ if (!wRet) {
+ FreeHandle(hWaveOut);
+ }
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutPrepareHeader | This function prepares a
+ * waveform data block for playback.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a
+ * <t WAVEHDR> structure that identifies the data block to be prepared.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ *
+ * @comm The <t WAVEHDR> data structure and the data block pointed to by its
+ * <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
+ * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
+ * Preparing a header that has already been prepared has no effect, and
+ * the function returns zero.
+ *
+ * @xref waveOutUnprepareHeader
+ ****************************************************************************/
+UINT WINAPI
+waveOutPrepareHeader(
+ HWAVEOUT hWaveOut,
+ LPWAVEHDR lpWaveOutHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
+
+ if (IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr)) {
+ DebugErr(DBF_WARNING,"waveOutPrepareHeader: header is already prepared.");
+ return MMSYSERR_NOERROR;
+ }
+
+ lpWaveOutHdr->dwFlags &= (WHDR_BEGINLOOP | WHDR_ENDLOOP);
+
+ wRet = wavePrepareHeader(lpWaveOutHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_PREPARE,
+ (DWORD)lpWaveOutHdr, (DWORD)wSize);
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutUnprepareHeader | This function cleans up the
+ * preparation performed by <f waveOutPrepareHeader>. The function
+ * must be called after
+ * the device driver is finished with a data block. You must call this
+ * function before freeing the data buffer.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a <t WAVEHDR>
+ * structure identifying the data block to be cleaned up.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_STILLPLAYING | <p lpWaveOutHdr> is still in the queue.
+ *
+ * @comm This function is the complementary function to
+ * <f waveOutPrepareHeader>. You must call this function before freeing the
+ * data buffer with <f GlobalFree>.
+ * After passing a buffer to the device driver with <f waveOutWrite>, you
+ * must wait until the driver is finished with the buffer before calling
+ * <f waveOutUnprepareHeader>.
+ *
+ * Unpreparing a buffer that has not been
+ * prepared has no effect, and the function returns zero.
+ *
+ * @xref waveOutPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+waveOutUnprepareHeader(
+ HWAVEOUT hWaveOut,
+ LPWAVEHDR lpWaveOutHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
+
+ if(lpWaveOutHdr->dwFlags & WHDR_INQUEUE) {
+ DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header still in queue.");
+ return WAVERR_STILLPLAYING;
+ }
+
+ if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr)) {
+ DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header is not prepared.");
+ return MMSYSERR_NOERROR;
+ }
+
+ wRet = waveUnprepareHeader(lpWaveOutHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_UNPREPARE,
+ (DWORD)lpWaveOutHdr, (DWORD)wSize);
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutWrite | This function sends a data block to the
+ * specified waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPWAVEHDR | lpWaveOutHdr | Specifies a far pointer to a <t WAVEHDR>
+ * structure containing information about the data block.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_UNPREPARED | <p lpWaveOutHdr> hasn't been prepared.
+ *
+ * @comm The data buffer must be prepared with <f waveOutPrepareHeader> before
+ * it is passed to <f waveOutWrite>. The <t WAVEHDR> data structure
+ * and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
+ * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
+ * locked with <f GlobalLock>. Unless the device is paused by calling
+ * <f waveOutPause>, playback begins when the first data block is sent to
+ * the device.
+ *
+ * @xref waveOutPrepareHeader waveOutPause waveOutReset waveOutRestart
+ ****************************************************************************/
+UINT WINAPI
+waveOutWrite(
+ HWAVEOUT hWaveOut,
+ LPWAVEHDR lpWaveOutHdr,
+ UINT wSize
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
+
+ if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr)) {
+ DebugErr(DBF_WARNING,"waveOutWrite: header not prepared");
+ return WAVERR_UNPREPARED;
+ }
+
+ if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) {
+ DebugErr(DBF_WARNING,"waveOutWrite: header is still in queue");
+ return WAVERR_STILLPLAYING;
+ }
+
+ lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_WRITE,
+ (DWORD)lpWaveOutHdr, (DWORD)wSize );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutPause | This function pauses playback on a specified
+ * waveform output device. The current playback position is saved. Use
+ * <f waveOutRestart> to resume playback from the current playback position.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Calling this function when the output is already paused has no
+ * effect, and the function returns zero.
+ *
+ * @xref waveOutRestart waveOutBreakLoop
+ ****************************************************************************/
+UINT WINAPI
+waveOutPause(
+ HWAVEOUT hWaveOut
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_PAUSE, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutRestart | This function restarts a paused waveform
+ * output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Calling this function when the output is not paused has no
+ * effect, and the function returns zero.
+ *
+ * @xref waveOutPause waveOutBreakLoop
+ ****************************************************************************/
+UINT WINAPI
+waveOutRestart(
+ HWAVEOUT hWaveOut
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_RESTART, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutReset | 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.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @xref waveOutWrite waveOutClose
+/****************************************************************************/
+UINT WINAPI
+waveOutReset(
+ HWAVEOUT hWaveOut
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_RESET, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutBreakLoop | This function breaks a loop on a
+ * given waveform output device and allows playback to continue with the
+ * next block in the driver list.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Waveform looping is controlled by the <e WAVEHDR.dwLoops> and
+ * <e WAVEHDR.dwFlags> fields in the <t WAVEHDR> structures passed to the device
+ * with <f waveOutWrite>. Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags
+ * in the <e WAVEHDR.dwFlags> field to specify the beginning and ending data
+ * blocks for looping.
+ *
+ * To loop on a single block, specify both flags for the same block.
+ * To specify the number of loops, use the <e WAVEHDR.dwLoops> field in
+ * the <t WAVEHDR> structure for the first block in the loop.
+ *
+ * The blocks making up the loop are played to the end before the loop
+ * is terminated.
+ *
+ * Calling this function when the nothing is playing or looping has no
+ * effect, and the function returns zero.
+ *
+ * @xref waveOutWrite waveOutPause waveOutRestart
+/****************************************************************************/
+UINT WINAPI
+waveOutBreakLoop(
+ HWAVEOUT hWaveOut
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_BREAKLOOP, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetPosition | This function retrieves the current
+ * playback position of the specified waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
+ * structure.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Before calling <f waveOutGetPosition>, set the <e MMTIME.wType> field of the
+ * MMTIME structure to indicate the time format that you desire. After
+ * calling <f waveOutGetPosition>, check the <e MMTIME.wType> field
+ * to determine if the desired time format is supported. If the desired
+ * format is not supported, <e MMTIME.wType> will specify an alternative format.
+ *
+ * The position is set to zero when the device is opened or reset.
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetPosition(
+ HWAVEOUT hWaveOut,
+ LPMMTIME lpInfo,
+ UINT wSize
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_GETPOS,
+ (DWORD)lpInfo, (DWORD)wSize );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetPitch | This function queries the the current pitch
+ * setting of a waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPDWORD | lpdwPitch | Specifies a far pointer to a location
+ * to be filled with the current pitch multiplier setting. The pitch
+ * multiplier indicates the current change in pitch from the original
+ * authored setting. The pitch multiplier must be a positive value.
+ *
+ * The pitch multiplier is specified as a fixed-point value. The high-order word
+ * of the DWORD location contains the signed integer part of the number,
+ * and the low-order word contains the fractional part. The fraction is
+ * expressed as a WORD in which a value of 0x8000 represents one half,
+ * and 0x4000 represents one quarter. For example, the value 0x00010000
+ * specifies a multiplier of 1.0 (no pitch change), and a value of
+ * 0x000F8000 specifies a multiplier of 15.5.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ *
+ * @comm Changing the pitch does not change the playback rate, sample
+ * rate, or playback time. Not all devices support
+ * pitch changes. To determine whether the device supports pitch control,
+ * use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
+ * field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
+ *
+ * @xref waveOutSetPitch waveOutGetPlaybackRate waveOutSetPlaybackRate
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetPitch(
+ HWAVEOUT hWaveOut,
+ LPDWORD lpdwPitch
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpdwPitch, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_GETPITCH,
+ (DWORD)lpdwPitch, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutSetPitch | This function sets the pitch of a waveform
+ * output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
+ * output device.
+ *
+ * @parm DWORD | dwPitch | Specifies the new pitch multiplier setting.
+ * The pitch multiplier setting indicates the current change in pitch
+ * from the original authored setting. The pitch multiplier must be a
+ * positive value.
+ *
+ * The pitch multiplier is specified as a fixed-point value. The high-order word
+ * location contains the signed integer part of the number,
+ * and the low-order word contains the fractional part. The fraction is
+ * expressed as a WORD in which a value of 0x8000 represents one half,
+ * and 0x4000 represents one quarter.
+ * For example, the value 0x00010000 specifies a multiplier
+ * of 1.0 (no pitch change), and a value of 0x000F8000 specifies a
+ * multiplier of 15.5.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ *
+ * @comm Changing the pitch does not change the playback rate or the sample
+ * rate. The playback time is also unchanged. Not all devices support
+ * pitch changes. To determine whether the device supports pitch control,
+ * use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
+ * field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
+ *
+ * @xref waveOutGetPitch waveOutSetPlaybackRate waveOutGetPlaybackRate
+ ****************************************************************************/
+UINT WINAPI
+waveOutSetPitch(
+ HWAVEOUT hWaveOut,
+ DWORD dwPitch
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_SETPITCH, dwPitch, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetPlaybackRate | This function queries the
+ * current playback rate setting of a waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
+ * device.
+ *
+ * @parm LPDWORD | lpdwRate | Specifies a far pointer to a location
+ * to be filled with the current playback rate. The playback rate setting
+ * is a multiplier indicating the current change in playback rate from
+ * the original authored setting. The playback rate multiplier must be
+ * a positive value.
+ *
+ * The rate is specified as a fixed-point value. The high-order word
+ * of the DWORD location contains the signed integer part of the number,
+ * and the low-order word contains the fractional part. The fraction is
+ * expressed as a WORD in which a value of 0x8000 represents one half,
+ * and 0x4000 represents one quarter. For example, the value 0x00010000
+ * specifies a multiplier of 1.0 (no playback rate change), and a value
+ * of 0x000F8000 specifies a multiplier of 15.5.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ *
+ * @comm Changing the playback rate does not change the sample rate but does
+ * change the playback time.
+ *
+ * Not all devices support playback rate changes. To determine whether a
+ * device supports playback rate changes, use
+ * the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
+ * <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
+ *
+ * @xref waveOutSetPlaybackRate waveOutSetPitch waveOutGetPitch
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetPlaybackRate(
+ HWAVEOUT hWaveOut,
+ LPDWORD lpdwRate
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpdwRate, sizeof(DWORD), MMSYSERR_INVALPARAM);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut,
+ WODM_GETPLAYBACKRATE, (DWORD)lpdwRate, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutSetPlaybackRate | This function sets the
+ * playback rate of a waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
+ * output device.
+ *
+ * @parm DWORD | dwRate | Specifies the new playback rate setting.
+ * The playback rate setting is a multiplier indicating the current
+ * change in playback rate from the original authored setting. The playback
+ * rate multiplier must be a positive value.
+ *
+ * The rate is specified as a fixed-point value. The high-order word
+ * contains the signed integer part of the number,
+ * and the low-order word contains the fractional part. The fraction is
+ * expressed as a WORD in which a value of 0x8000 represents one half,
+ * and 0x4000 represents one quarter.
+ * For example, the value 0x00010000 specifies a multiplier of 1.0 (no
+ * playback rate change), and a value of 0x000F8000 specifies a
+ * multiplier of 15.5.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
+ *
+ * @comm Changing the playback rate does not change the sample rate but does
+ * change the playback time.
+ *
+ * Not all devices support playback rate changes. To determine whether a
+ * device supports playback rate changes,
+ * use the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
+ * <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
+ *
+ * @xref waveOutGetPlaybackRate waveOutSetPitch waveOutGetPitch
+ ****************************************************************************/
+UINT WINAPI
+waveOutSetPlaybackRate(
+ HWAVEOUT hWaveOut,
+ DWORD dwRate
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveOMessage( (HWAVE)hWaveOut, WODM_SETPLAYBACKRATE, dwRate, 0L );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInGetNumDevs | This function returns the number of waveform
+ * input devices.
+ *
+ * @rdesc Returns the number of waveform input devices present in the system.
+ *
+ * @xref waveInGetDevCaps
+ ****************************************************************************/
+UINT WINAPI
+waveInGetNumDevs(
+ void
+ )
+{
+ return waveIIDMessage( 0, WIDM_GETNUMDEVS, 0L, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api DWORD | waveInMessage | This function sends messages to the waveform
+ * output device drivers.
+ *
+ * @parm HWAVEIN | hWave | The handle to the audio device.
+ *
+ * @parm UINT | wMsg | The message to send.
+ *
+ * @parm DWORD | dw1 | Parameter 1.
+ *
+ * @parm DWORD | dw2 | Parameter 2.
+ *
+ * @rdesc Returns the value returned from the driver.
+ ****************************************************************************/
+DWORD WINAPI
+waveInMessage(
+ HWAVEIN hWaveIn,
+ UINT msg,
+ DWORD dw1,
+ DWORD dw2
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, 0L);
+
+ return waveIMessage((HWAVE)hWaveIn, msg, dw1, dw2);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInGetDevCaps | This function queries a specified waveform
+ * input device to determine its capabilities.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform input device.
+ *
+ * @parm LPWAVEINCAPS | lpCaps | Specifies a far pointer to a <t WAVEINCAPS>
+ * structure. This structure is filled with information about the
+ * capabilities of the device.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEINCAPS> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_NODRIVER | The driver was not installed.
+ *
+ * @comm Use <f waveInGetNumDevs> to determine the number of waveform input
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The WAVE_MAPPER constant may also be used as a device id. Only
+ * <p wSize> bytes (or less) of information is copied to the location
+ * pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
+ * the function returns zero.
+ *
+ * @xref waveInGetNumDevs
+ ****************************************************************************/
+UINT WINAPI
+waveInGetDevCaps(
+ UINT wDeviceID,
+ LPWAVEINCAPS lpCaps,
+ UINT wSize
+ )
+{
+ if (wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
+
+ return waveIIDMessage( wDeviceID, WIDM_GETDEVCAPS,
+ 0L, (DWORD)lpCaps, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInGetErrorText | This function retrieves a textual
+ * description of the error identified by the specified error number.
+ *
+ * @parm UINT | wError | Specifies the error number.
+ *
+ * @parm LPSTR | lpText | Specifies a far pointer to the buffer to be
+ * filled with the textual error description.
+ *
+ * @parm UINT | wSize | Specifies the size of the buffer pointed
+ * to by <p lpText>.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
+ *
+ * @comm If the textual error description is longer than the specified buffer,
+ * the description is truncated. The returned error string is always
+ * null-terminated. If <p wSize> is zero, nothing is copied, and the function
+ * returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
+ ****************************************************************************/
+UINT WINAPI
+waveInGetErrorText(
+ UINT wError,
+ LPSTR lpText,
+ UINT wSize
+ )
+{
+ if (wSize == 0) {
+ return MMSYSERR_NOERROR;
+ }
+
+ V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
+
+ return waveGetErrorText(wError, lpText, wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInOpen | This function opens a specified waveform
+ * input device for recording.
+ *
+ * @parm LPHWAVEIN | lphWaveIn | Specifies a far pointer to a HWAVEIN
+ * handle. This location is filled with a handle identifying the opened
+ * waveform input device. Use this handle to identify the device when
+ * calling other waveform input functions. This parameter may be NULL
+ * if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
+ *
+ * @parm UINT | wDeviceID | Identifies the waveform input device to open. Use
+ * a valid device ID or the following flag:
+ *
+ * @flag WAVE_MAPPER | If this flag is specified, the function
+ * selects a waveform input device capable of recording in the
+ * given format.
+ *
+ * @parm LPWAVEFORMAT | lpFormat | Specifies a pointer to a <t WAVEFORMAT>
+ * data structure that identifies the desired format for recording
+ * waveform data.
+ *
+ * @parm DWORD | dwCallback | Specifies the address of a callback
+ * function or a handle to a window called during waveform
+ * recording to process messages related to the progress of recording.
+ *
+ * @parm DWORD | dwCallbackInstance | Specifies user
+ * instance data passed to the callback. This parameter is not
+ * used with window callbacks.
+ *
+ * @parm DWORD | dwFlags | Specifies flags for opening the device.
+ * @flag WAVE_FORMAT_QUERY | If this flag is specified, the device will
+ * be queried to determine if it supports the given format but will not
+ * actually be opened.
+ * @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
+ * device will fail to open if it is a synchronous device.
+ * @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
+ * assumed to be a window handle.
+ * @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
+ * assumed to be a callback procedure address.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
+ * @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ * @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
+ *
+ * @comm Use <f waveInGetNumDevs> to determine the number of waveform input
+ * devices present in the system. The device ID specified by <p wDeviceID>
+ * varies from zero to one less than the number of devices present.
+ * The WAVE_MAPPER constant may also be used as a device id.
+ *
+ * If a window is chosen to receive callback information, the following
+ * messages are sent to the window procedure function to indicate the
+ * progress of waveform input: <m MM_WIM_OPEN>, <m MM_WIM_CLOSE>,
+ * <m MM_WIM_DATA>
+ *
+ * If a function is chosen to receive callback information, the following
+ * messages are sent to the function to indicate the progress of waveform
+ * input: <m WIM_OPEN>, <m WIM_CLOSE>, <m WIM_DATA>. The callback function
+ * must reside in a DLL. You do not have to use <f MakeProcInstance> to get
+ * a procedure-instance address for the callback function.
+ *
+ * @cb void CALLBACK | WaveInFunc | <f WaveInFunc> is a placeholder for the
+ * application-supplied function name. The actual name must be exported by
+ * including it in an EXPORTS statement in the DLL's module-definition file.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform device
+ * associated with the callback.
+ *
+ * @parm UINT | wMsg | Specifies a waveform input device.
+ *
+ * @parm DWORD | dwInstance | Specifies the user instance
+ * data specified with <f waveInOpen>.
+ *
+ * @parm DWORD | dwParam1 | Specifies a parameter for the message.
+ *
+ * @parm DWORD | dwParam2 | Specifies a parameter for the message.
+ *
+ * @comm Because the callback is accessed at interrupt time, it must reside
+ * in a DLL and its code segment must be specified as FIXED in the
+ * module-definition file for the DLL. Any data that the callback accesses
+ * must be in a FIXED data segment as well. The callback may not make any
+ * system calls except for <f PostMessage>, <f timeGetSystemTime>,
+ * <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
+ * <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
+ *
+ * @xref waveInClose
+ ****************************************************************************/
+UINT WINAPI
+waveInOpen(
+ LPHWAVEIN lphWaveIn,
+ UINT wDeviceID,
+ const WAVEFORMAT FAR* lpFormat,
+ DWORD dwCallback,
+ DWORD dwInstance,
+ DWORD dwFlags
+ )
+{
+ WAVEOPENDESC wo;
+ PWAVEDEV pdev;
+ UINT wRet;
+ DWORD dwDrvUser;
+
+ V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
+ V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
+ V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveInOpen, MMSYSERR_INVALFLAG);
+
+ if (!(dwFlags & WAVE_FORMAT_QUERY)) {
+ V_WPOINTER(lphWaveIn, sizeof(HWAVEIN), MMSYSERR_INVALPARAM);
+ *lphWaveIn = NULL;
+ }
+
+ /*
+ ** Check for no devices
+ */
+// if (wTotalWaveInDevs == 0 ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+//
+// /*
+// ** check for device ID being to large
+// */
+// if ( wDeviceID != WAVE_MAPPER ) {
+// if ( wDeviceID >= wTotalWaveInDevs ) {
+// return MMSYSERR_BADDEVICEID;
+// }
+// }
+
+
+ if (dwFlags & WAVE_FORMAT_QUERY) {
+ pdev = NULL;
+ }
+ else {
+ if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEIN, sizeof(WAVEDEV))))
+ return MMSYSERR_NOMEM;
+
+ pdev->wDevice = wDeviceID;
+ pdev->wDeviceID = wDeviceID;
+ }
+
+ wo.hWave = (HWAVE)pdev;
+ wo.dwCallback = dwCallback;
+ wo.dwInstance = dwInstance;
+ wo.lpFormat = lpFormat;
+
+ if ( (wDeviceID == WAVE_MAPPER) && (wodMapper != NULL) ) {
+
+ wRet = (UINT)((*(widMapper))(0, WIDM_OPEN,
+ (DWORD)(LPDWORD)&dwDrvUser,
+ (DWORD)(LPWAVEOPENDESC)&wo,
+ dwFlags));
+ }
+ else {
+
+ wRet = waveIIDMessage( wDeviceID, WIDM_OPEN,
+ (DWORD)(LPDWORD)&dwDrvUser,
+ (DWORD)(LPWAVEOPENDESC)&wo, dwFlags );
+ }
+
+ if (pdev) {
+
+ if (wRet)
+ FreeHandle((HWAVEIN)pdev);
+ else {
+ *lphWaveIn = (HWAVEIN)pdev;
+ pdev->dwDrvUser = dwDrvUser;
+ }
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInClose | This function closes the specified waveform
+ * input device.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
+ * If the function is successful, the handle is no longer
+ * valid after this call.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
+ *
+ * @comm If there are input buffers that have been sent with
+ * <f waveInAddBuffer>, and haven't been returned to the application,
+ * the close operation will fail. Call <f waveInReset> to mark all
+ * pending buffers as done.
+ *
+ * @xref waveInOpen waveInReset
+ ****************************************************************************/
+UINT WINAPI
+waveInClose(
+ HWAVEIN hWaveIn
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+
+ wRet = (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_CLOSE, 0L, 0L);
+ if (!wRet) {
+ FreeHandle(hWaveIn);
+ }
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInPrepareHeader | This function prepares a buffer
+ * for waveform input.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
+ * device.
+ *
+ * @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a
+ * <t WAVEHDR> structure that identifies the buffer to be prepared.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
+ *
+ * @comm The <t WAVEHDR> data structure and the data block pointed to by its
+ * <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
+ * GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
+ * Preparing a header that has already been prepared will have no effect,
+ * and the function will return zero.
+ *
+ * @xref waveInUnprepareHeader
+ ****************************************************************************/
+UINT WINAPI
+waveInPrepareHeader(
+ HWAVEIN hWaveIn,
+ LPWAVEHDR lpWaveInHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
+
+ if (IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr)) {
+ DebugErr(DBF_WARNING,"waveInPrepareHeader: header is already prepared.");
+ return MMSYSERR_NOERROR;
+ }
+
+ lpWaveInHdr->dwFlags = 0;
+
+ wRet = wavePrepareHeader(lpWaveInHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_PREPARE,
+ (DWORD)lpWaveInHdr, (DWORD)wSize);
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInUnprepareHeader | This function cleans up the
+ * preparation performed by <f waveInPrepareHeader>. The function must
+ * be called after the device
+ * driver fills a data buffer and returns it to the application. You
+ * must call this function before freeing the data buffer.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
+ * device.
+ *
+ * @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a <t WAVEHDR>
+ * structure identifying the data buffer to be cleaned up.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_STILLPLAYING | <p lpWaveInHdr> is still in the queue.
+ *
+ * @comm This function is the complementary function to <f waveInPrepareHeader>.
+ * You must call this function before freeing the data buffer with <f GlobalFree>.
+ * After passing a buffer to the device driver with <f waveInAddBuffer>, you
+ * must wait until the driver is finished with the buffer before calling
+ * <f waveInUnprepareHeader>. Unpreparing a buffer that has not been
+ * prepared has no effect, and the function returns zero.
+ *
+ * @xref waveInPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+waveInUnprepareHeader(
+ HWAVEIN hWaveIn,
+ LPWAVEHDR lpWaveInHdr,
+ UINT wSize
+ )
+{
+ UINT wRet;
+
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
+
+ if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) {
+ DebugErr(DBF_WARNING, "waveInUnprepareHeader: buffer still in queue.");
+ return WAVERR_STILLPLAYING;
+ }
+
+ if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr)) {
+ DebugErr(DBF_WARNING,"waveInUnprepareHeader: header is not prepared.");
+ return MMSYSERR_NOERROR;
+ }
+
+ wRet = waveUnprepareHeader(lpWaveInHdr, wSize);
+
+ if (wRet == MMSYSERR_NOERROR) {
+ wRet = (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_UNPREPARE,
+ (DWORD)lpWaveInHdr, (DWORD)wSize);
+ }
+
+ return wRet;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInAddBuffer | This function sends an input buffer to a
+ * waveform input device. When the buffer is filled, it is sent back
+ * to the application.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
+ *
+ * @parm LPWAVEHDR | lpWaveInHdr | Specifies a far pointer to a <t WAVEHDR>
+ * structure that identifies the buffer.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ * @flag WAVERR_UNPREPARED | <p lpWaveInHdr> hasn't been prepared.
+ *
+ * @comm The data buffer must be prepared with <f waveInPrepareHeader> before
+ * it is passed to <f waveInAddBuffer>. The <t WAVEHDR> data structure
+ * and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
+ * with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
+ * locked with <f GlobalLock>.
+ *
+ * @xref waveInPrepareHeader
+ ****************************************************************************/
+UINT WINAPI
+waveInAddBuffer(
+ HWAVEIN hWaveIn,
+ LPWAVEHDR lpWaveInHdr,
+ UINT wSize
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+ V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
+
+ if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr)) {
+ DebugErr(DBF_WARNING, "waveInAddBuffer: buffer not prepared.");
+ return WAVERR_UNPREPARED;
+ }
+
+ if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) {
+ DebugErr(DBF_WARNING, "waveInAddBuffer: buffer already in queue.");
+ return WAVERR_STILLPLAYING;
+ }
+
+ return (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_ADDBUFFER,
+ (DWORD)lpWaveInHdr, (DWORD)wSize);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInStart | This function starts input on the specified
+ * waveform input device.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Buffers are returned to the client when full or when <f waveInReset>
+ * is called (the <e WAVEHDR.dwBytesRecorded> field in the header will contain the
+ * actual length of data). If there are no buffers in the queue, the data is
+ * thrown away without notification to the client, and input continues.
+ *
+ * Calling this function when input is already started has no effect, and
+ * the function returns zero.
+ *
+ * @xref waveInStop waveInReset
+ ****************************************************************************/
+UINT WINAPI
+waveInStart(
+ HWAVEIN hWaveIn
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_START, 0L, 0L);
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInStop | This function stops waveform input.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
+ * device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm If there are any buffers in the queue, the current buffer will be
+ * marked as done (the <e WAVEHDR.dwBytesRecorded> field in the header will contain
+ * the actual length of data), but any empty buffers in the queue will remain
+ * there. Calling this function when input is not started has no effect,
+ * and the function returns zero.
+ *
+ * @xref waveInStart waveInReset
+ ****************************************************************************/
+UINT WINAPI
+waveInStop(
+ HWAVEIN hWaveIn
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_STOP, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInReset | 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.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @xref waveInStart waveInStop waveInAddBuffer waveInClose
+/****************************************************************************/
+UINT WINAPI
+waveInReset(
+ HWAVEIN hWaveIn
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+
+ return (UINT)waveIMessage( (HWAVE)hWaveIn, WIDM_RESET, 0L, 0L );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInGetPosition | This function retrieves the current input
+ * position of the specified waveform input device.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
+ *
+ * @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
+ * structure.
+ *
+ * @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
+ *
+ * @rdesc Returns zero if the function was successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
+ *
+ * @comm Before calling <f waveInGetPosition>, set the <e MMTIME.wType> field of the
+ * <t MMTIME> structure to indicate the time format that you desire. After
+ * calling <f waveInGetPosition>, be sure to check the <e MMTIME.wType> field to
+ * determine if the desired time format is supported. If the desired
+ * format is not supported, <e MMTIME.wType> will specify an alternative format.
+ *
+ * The position is set to zero when the device is opened or reset.
+ ****************************************************************************/
+UINT WINAPI
+waveInGetPosition(
+ HWAVEIN hWaveIn,
+ LPMMTIME lpInfo,
+ UINT wSize
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
+
+ return (UINT)waveIMessage( (HWAVE)hWaveIn,
+ WIDM_GETPOS, (DWORD)lpInfo, (DWORD)wSize );
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveInGetID | This function gets the device ID for a
+ * waveform input device.
+ *
+ * @parm HWAVEIN | hWaveIn | Specifies the handle to the waveform
+ * input device.
+ * @parm UINT FAR* | lpwDeviceID | Specifies a pointer to the UINT-sized memory
+ * location to be filled with the device ID.
+ *
+ * @rdesc Returns zero if successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | The <p hWaveIn> parameter specifies an
+ * invalid handle.
+ *
+ ****************************************************************************/
+UINT WINAPI
+waveInGetID(
+ HWAVEIN hWaveIn,
+ UINT FAR* lpwDeviceID
+ )
+{
+ V_HANDLE(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpwDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+ *lpwDeviceID = ((PWAVEDEV)hWaveIn)->wDeviceID;
+
+ return MMSYSERR_NOERROR;
+}
+
+/*****************************************************************************
+ * @doc EXTERNAL WAVE
+ *
+ * @api UINT | waveOutGetID | This function gets the device ID for a
+ * waveform output device.
+ *
+ * @parm HWAVEOUT | hWaveOut | Specifies the handle to the waveform
+ * output device.
+ * @parm UINT FAR* | lpwDeviceID | Specifies a pointer to the UINT-sized memory
+ * location to be filled with the device ID.
+ *
+ * @rdesc Returns zero if successful. Otherwise, it returns
+ * an error number. Possible error returns are:
+ * @flag MMSYSERR_INVALHANDLE | The <p hWaveOut> parameter specifies an
+ * invalid handle.
+ ****************************************************************************/
+UINT WINAPI
+waveOutGetID(
+ HWAVEOUT hWaveOut,
+ UINT FAR* lpwDeviceID
+ )
+{
+ V_HANDLE(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
+ V_WPOINTER(lpwDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
+
+ *lpwDeviceID = ((PWAVEDEV)hWaveOut)->wDeviceID;
+
+ return MMSYSERR_NOERROR;
+}
diff --git a/private/mvdm/wow16/ole/client/amabaabo b/private/mvdm/wow16/ole/client/amabaabo
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/amabaabo
diff --git a/private/mvdm/wow16/ole/client/amabaace b/private/mvdm/wow16/ole/client/amabaace
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/amabaace
diff --git a/private/mvdm/wow16/ole/client/bm.c b/private/mvdm/wow16/ole/client/bm.c
new file mode 100644
index 000000000..8753086d4
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/bm.c
@@ -0,0 +1,605 @@
+/****************************** Module Header ******************************\
+* Module Name: BM.C
+*
+* Handles all API routines for the bitmap sub-dll of the ole dll.
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor,Srinik (../../1990,91) Designed, coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+extern int maxPixelsX, maxPixelsY;
+void INTERNAL GetHimetricUnits(HBITMAP, LPPOINT);
+
+#pragma alloc_text(_TEXT, BmSaveToStream, BmStreamWrite, BmLoadFromStream, BmStreamRead, GetBytes, PutBytes, PutStrWithLen, BmQueryBounds, BmChangeData, BmCopy, BmDuplicate, BmUpdateStruct, GetHimetricUnits)
+
+
+OLEOBJECTVTBL vtblBM = {
+
+ ErrQueryProtocol, // check whether the speced protocol is supported
+
+ BmRelease, // Release
+ ErrShow, // Show
+ ErrPlay, // play
+ BmGetData, // Get the object data
+ ErrSetData, // Set the object data
+ ErrSetTargetDevice,//
+
+ ErrSetBounds, // set viewport bounds
+ BmEnumFormat, // enumerate supported formats
+ ErrSetColorScheme, //
+ BmRelease, // delete
+ ErrSetHostNames, //
+
+ BmSaveToStream, // write to file
+ BmClone, // clone object
+ ErrCopyFromLink, // Create embedded from Link
+
+ BmEqual, // compares the given objects for data equality
+
+ BmCopy, // copy to clip
+
+ BmDraw, // draw the object
+
+ ErrActivate, // open
+ ErrExecute, // excute
+ ErrClose, // Stop
+ ErrUpdate, // Update
+ ErrReconnect, // Reconnect
+
+ ErrObjectConvert, // convert object to specified type
+
+ ErrGetUpdateOptions,// update options
+ ErrSetUpdateOptions,// update options
+
+ ObjRename, // Change Object name
+ ObjQueryName, // Get current object name
+
+ ObjQueryType, // Object type
+ BmQueryBounds, // QueryBounds
+ ObjQuerySize, // Find the size of the object
+ ErrQueryOpen, // Query open
+ ErrQueryOutOfDate, // query whether object is current
+
+ ErrQueryRelease, // release related stuff
+ ErrQueryRelease,
+ ErrQueryRelease,
+
+ ErrRequestData, // requestdata
+ ErrObjectLong, // objectLong
+ BmChangeData // change data of the existing object
+};
+
+
+
+OLESTATUS FARINTERNAL BmRelease (lpobj)
+LPOBJECT_BM lpobj;
+{
+ HOBJECT hobj;
+
+ if (lpobj->hBitmap) {
+ DeleteObject (lpobj->hBitmap);
+ lpobj->hBitmap = NULL;
+ }
+
+ if (lpobj->head.lhclientdoc)
+ DocDeleteObject ((LPOLEOBJECT) lpobj);
+
+ if (hobj = lpobj->head.hobj){
+ lpobj->head.hobj = NULL;
+ GlobalUnlock (hobj);
+ GlobalFree (hobj);
+ }
+
+ return OLE_OK;
+}
+
+
+
+OLESTATUS FARINTERNAL BmSaveToStream (lpobj, lpstream)
+LPOBJECT_BM lpobj;
+LPOLESTREAM lpstream;
+{
+ if (!lpobj->hBitmap || !lpobj->sizeBytes)
+ return OLE_ERROR_BLANK;
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutStrWithLen(lpstream, (LPSTR)"BITMAP"))
+ return OLE_ERROR_STREAM;
+
+ if (!PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG))) {
+ if (!PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ if (!PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(DWORD)))
+ return BmStreamWrite (lpstream, lpobj);
+ }
+ return OLE_ERROR_STREAM;
+}
+
+
+OLESTATUS FARINTERNAL BmClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_BM lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_BM FAR * lplpobj;
+{
+ if (!CheckClientDoc ((LPCLIENTDOC)lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (!(*lplpobj = BmCreateObject (lpobjsrc->hBitmap, lpclient, FALSE,
+ lhclientdoc, lpobjname, lpobjsrc->head.ctype)))
+ return OLE_ERROR_MEMORY;
+ else
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL BmEqual (lpobj1, lpobj2)
+LPOBJECT_BM lpobj1;
+LPOBJECT_BM lpobj2;
+{
+ HANDLE hBits1 = NULL, hBits2 = NULL;
+ LPSTR lpBits1 = NULL, lpBits2 = NULL;
+ OLESTATUS retVal;
+ DWORD dwBytes1, dwBytes2;
+
+ if (lpobj1->sizeBytes != lpobj2->sizeBytes)
+ return OLE_ERROR_NOT_EQUAL;
+
+ retVal = OLE_ERROR_MEMORY;
+
+ if (!(hBits1 = GlobalAlloc (GMEM_MOVEABLE, lpobj1->sizeBytes)))
+ goto errEqual;
+
+ if (!(lpBits1 = GlobalLock (hBits1)))
+ goto errEqual;
+
+ if (!(hBits2 = GlobalAlloc (GMEM_MOVEABLE, lpobj2->sizeBytes)))
+ goto errEqual;
+
+ if (!(lpBits2 = GlobalLock (hBits2)))
+ goto errEqual;
+
+ dwBytes1 = GetBitmapBits (lpobj1->hBitmap, lpobj1->sizeBytes, lpBits1);
+ dwBytes2 = GetBitmapBits (lpobj2->hBitmap, lpobj2->sizeBytes, lpBits2);
+
+ if (dwBytes1 != dwBytes2) {
+ retVal = OLE_ERROR_NOT_EQUAL;
+ goto errEqual;
+ }
+
+ // !!! UtilMemCmp has to be redone for >64k bitmaps
+ if (UtilMemCmp (lpBits1, lpBits2, dwBytes1))
+ retVal = OLE_ERROR_NOT_EQUAL;
+ else
+ retVal = OLE_OK;
+
+errEqual:
+ if (lpBits1)
+ GlobalUnlock (hBits1);
+
+ if (lpBits2)
+ GlobalUnlock (hBits2);
+
+ if (hBits1)
+ GlobalFree (hBits1);
+
+ if (hBits2)
+ GlobalFree (hBits2);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FARINTERNAL BmCopy (lpobj)
+LPOBJECT_BM lpobj;
+{
+ HBITMAP hBitmap;
+ DWORD size;
+
+ if (!lpobj->hBitmap)
+ return OLE_ERROR_BLANK;
+
+ if(!(hBitmap = BmDuplicate (lpobj->hBitmap, &size, NULL)))
+ return OLE_ERROR_MEMORY;
+
+ SetClipboardData(CF_BITMAP, hBitmap);
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL BmQueryBounds (lpobj, lpRc)
+LPOBJECT_BM lpobj;
+LPRECT lpRc;
+{
+ Puts("BmQueryBounds");
+
+ if (!lpobj->hBitmap)
+ return OLE_ERROR_BLANK;
+
+ lpRc->left = 0;
+ lpRc->top = 0;
+ lpRc->right = (int) lpobj->head.cx;
+ lpRc->bottom = (int) lpobj->head.cy;
+ return OLE_OK;
+}
+
+
+
+OLECLIPFORMAT FARINTERNAL BmEnumFormat (lpobj, cfFormat)
+LPOBJECT_BM lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ if (!cfFormat)
+ return CF_BITMAP;
+
+ return NULL;
+}
+
+
+
+OLESTATUS FARINTERNAL BmGetData (lpobj, cfFormat, lphandle)
+LPOBJECT_BM lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+ if (cfFormat != CF_BITMAP)
+ return OLE_ERROR_FORMAT;
+
+ if (!(*lphandle = lpobj->hBitmap))
+ return OLE_ERROR_BLANK;
+ return OLE_OK;
+
+}
+
+
+
+
+OLESTATUS FARINTERNAL BmLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpoleobject, objType)
+LPOLESTREAM lpstream;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG objType;
+{
+ LPOBJECT_BM lpobj = NULL;
+
+ *lplpoleobject = NULL;
+
+ if (!(lpobj = BmCreateBlank (lhclientdoc, lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ lpobj->head.lpclient = lpclient;
+
+ if (!GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG))) {
+ if (!GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ if (!GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(DWORD)))
+ if (BmStreamRead (lpstream, lpobj)) {
+ *lplpoleobject = (LPOLEOBJECT)lpobj;
+ return OLE_OK;
+ }
+ }
+
+ OleDelete ((LPOLEOBJECT)lpobj);
+ return OLE_ERROR_STREAM;;
+}
+
+
+
+OLESTATUS INTERNAL BmStreamWrite (lpstream, lpobj)
+LPOLESTREAM lpstream;
+LPOBJECT_BM lpobj;
+{
+ HANDLE hBits;
+ LPSTR lpBits;
+ int retVal = OLE_ERROR_STREAM;
+ BITMAP bm;
+ DWORD dwSize; // size of bit array
+
+ dwSize = lpobj->sizeBytes - sizeof(BITMAP);
+
+ if (hBits = GlobalAlloc (GMEM_MOVEABLE, dwSize)) {
+ if (lpBits = (LPSTR) GlobalLock (hBits)) {
+ if (GetBitmapBits (lpobj->hBitmap, dwSize, lpBits)) {
+ GetObject (lpobj->hBitmap, sizeof(BITMAP), (LPSTR) &bm);
+ if (!PutBytes (lpstream, (LPSTR) &bm, sizeof(BITMAP)))
+ if (!PutBytes (lpstream, (LPSTR) lpBits, dwSize))
+ retVal = OLE_OK;
+ }
+ GlobalUnlock(hBits);
+ } else
+ retVal = OLE_ERROR_MEMORY;
+ GlobalFree(hBits);
+ } else
+ retVal = OLE_ERROR_MEMORY;
+
+ return retVal;
+}
+
+
+
+BOOL INTERNAL BmStreamRead (lpstream, lpobj)
+LPOLESTREAM lpstream;
+LPOBJECT_BM lpobj;
+{
+ HANDLE hBits;
+ LPSTR lpBits;
+ BOOL retVal = FALSE;
+ BITMAP bm;
+ POINT point;
+
+ if (GetBytes (lpstream, (LPSTR)&bm, sizeof(BITMAP)))
+ return FALSE;
+
+ lpobj->sizeBytes = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
+ ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
+
+ if (hBits = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes)) {
+ if (lpBits = (LPSTR) GlobalLock (hBits)) {
+ if (!GetBytes(lpstream, lpBits, lpobj->sizeBytes)) {
+ if (lpobj->hBitmap = CreateBitmap (bm.bmWidth,
+ bm.bmHeight,
+ bm.bmPlanes,
+ bm.bmBitsPixel,
+ lpBits)) {
+ retVal = TRUE;
+ lpobj->xSize = point.x = bm.bmWidth;
+ lpobj->ySize = point.y = bm.bmHeight;
+
+ // size of (bitmap header + bits)
+ lpobj->sizeBytes += sizeof(BITMAP);
+#ifdef OLD
+ // !!! We shouldn't do the conversion. The info should be
+ // part of the stream.
+ if (!lpobj->head.cx) {
+ ConvertToHimetric (&point);
+ lpobj->head.cx = (LONG) point.x;
+ lpobj->head.cy = (LONG) point.y;
+ }
+#endif
+ }
+ }
+ GlobalUnlock(hBits);
+ }
+ GlobalFree(hBits);
+ }
+ return retVal;
+}
+
+
+OLESTATUS FARINTERNAL BmPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG objType;
+{
+ HBITMAP hBitmap;
+
+ *lplpoleobject = NULL;
+
+ if ((hBitmap = (HBITMAP) GetClipboardData(CF_BITMAP)) == NULL)
+ return OLE_ERROR_MEMORY;
+
+ if (!(*lplpoleobject = (LPOLEOBJECT) BmCreateObject (hBitmap,
+ lpclient, FALSE, lhclientdoc,
+ lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ return OLE_OK;
+
+}
+
+
+LPOBJECT_BM INTERNAL BmCreateObject (hBitmap, lpclient, fDelete, lhclientdoc, lpobjname, objType)
+HBITMAP hBitmap;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ LPOBJECT_BM lpobj;
+
+ if (lpobj = BmCreateBlank (lhclientdoc, lpobjname, objType)) {
+ if (BmChangeData (lpobj, hBitmap, lpclient, fDelete) != OLE_OK) {
+ BmRelease (lpobj);
+ lpobj = NULL;
+ }
+ }
+
+ return lpobj;
+}
+
+
+// If the routine fails then the object will be left with it's old data.
+// If fDelete is TRUE, then hNewBitmap will be deleted whether the routine
+// is successful or not.
+
+OLESTATUS FARINTERNAL BmChangeData (lpobj, hNewBitmap, lpclient, fDelete)
+LPOBJECT_BM lpobj;
+HBITMAP hNewBitmap;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+{
+ BITMAP bm;
+ DWORD dwSize;
+ HBITMAP hOldBitmap;
+
+ hOldBitmap = lpobj->hBitmap;
+
+ if (!fDelete) {
+ if (!(hNewBitmap = BmDuplicate (hNewBitmap, &dwSize, &bm)))
+ return OLE_ERROR_MEMORY;
+ }
+ else {
+ if (!GetObject (hNewBitmap, sizeof(BITMAP), (LPSTR) &bm)) {
+ DeleteObject (hNewBitmap);
+ return OLE_ERROR_MEMORY;
+ }
+
+ dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
+ ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
+ }
+
+ BmUpdateStruct (lpobj, lpclient, hNewBitmap, &bm, dwSize);
+ if (hOldBitmap)
+ DeleteObject (hOldBitmap);
+
+ return OLE_OK;
+}
+
+
+void INTERNAL BmUpdateStruct (lpobj, lpclient, hBitmap, lpBm, dwBytes)
+LPOBJECT_BM lpobj;
+LPOLECLIENT lpclient;
+HBITMAP hBitmap;
+LPBITMAP lpBm;
+DWORD dwBytes;
+{
+ POINT point;
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->xSize = point.x = lpBm->bmWidth;
+ lpobj->ySize = point.y = lpBm->bmHeight;
+ GetHimetricUnits (hBitmap, &point);
+ lpobj->head.cx = (LONG) point.x;
+ lpobj->head.cy = (LONG) point.y;
+ lpobj->sizeBytes = dwBytes + sizeof(BITMAP);
+ lpobj->hBitmap = hBitmap;
+}
+
+
+
+LPOBJECT_BM FARINTERNAL BmCreateBlank (lhclientdoc, lpobjname, objType)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ HOBJECT hobj;
+ LPOBJECT_BM lpobj;
+
+ if ((hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_BM)))
+ == NULL)
+ return NULL;
+
+ if (!(lpobj = (LPOBJECT_BM) GlobalLock (hobj))){
+ GlobalFree (hobj);
+ return NULL;
+ }
+
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+ lpobj->head.mm = MM_TEXT;
+ lpobj->head.ctype = objType;
+ lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblBM;
+ lpobj->head.iTable = INVALID_INDEX;
+ lpobj->head.hobj = hobj;
+
+ if (objType == CT_STATIC)
+ DocAddObject ((LPCLIENTDOC) lhclientdoc,
+ (LPOLEOBJECT) lpobj, lpobjname);
+
+ return lpobj;
+}
+
+
+
+HBITMAP FARINTERNAL BmDuplicate (hold, lpdwSize, lpBm)
+HBITMAP hold;
+DWORD FAR * lpdwSize;
+LPBITMAP lpBm;
+{
+ HBITMAP hnew;
+ HANDLE hMem;
+ LPSTR lpMem;
+ LONG retVal = TRUE;
+ DWORD dwSize;
+ BITMAP bm;
+ DWORD dwExtents = NULL;
+
+ // !!! another way to duplicate the bitmap
+
+ GetObject (hold, sizeof(BITMAP), (LPSTR) &bm);
+ dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
+ ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
+
+ if (!(hMem = GlobalAlloc (GMEM_MOVEABLE, dwSize)))
+ return NULL;
+
+ if (!(lpMem = GlobalLock (hMem))){
+ GlobalFree (hMem);
+ return NULL;
+ }
+
+ GetBitmapBits (hold, dwSize, lpMem);
+ if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight,
+ bm.bmPlanes, bm.bmBitsPixel, NULL))
+ retVal = SetBitmapBits (hnew, dwSize, lpMem);
+
+ GlobalUnlock (hMem);
+ GlobalFree (hMem);
+
+ if (hnew && (!retVal)) {
+ DeleteObject (hnew);
+ hnew = NULL;
+ }
+ *lpdwSize = dwSize;
+ if (lpBm)
+ *lpBm = bm;
+
+ if (dwExtents = GetBitmapDimension (hold))
+ SetBitmapDimension (hnew, LOWORD(dwExtents), HIWORD(dwExtents));
+
+ return hnew;
+}
+
+
+void INTERNAL GetHimetricUnits(HBITMAP hBitmap, LPPOINT lpPoint)
+{
+ HDC hdc;
+ DWORD dwDim;
+
+ if (dwDim = GetBitmapDimension (hBitmap)) {
+ lpPoint->x = 10 * LOWORD(dwDim);
+ lpPoint->y = - (10 * HIWORD(dwDim));
+ return;
+ }
+
+ // clip if it exceeds maxPixels. Note that we have a limitation of
+ // 0x8FFF HIMETRIC units in OLE1.0
+
+ if (lpPoint->x > maxPixelsX)
+ lpPoint->x = maxPixelsX;
+
+ if (lpPoint->y > maxPixelsY)
+ lpPoint->y = maxPixelsY;
+
+ if (hdc = GetDC (NULL)) {
+ lpPoint->x = MulDiv (lpPoint->x, 2540,
+ GetDeviceCaps (hdc, LOGPIXELSX));
+ lpPoint->y = - MulDiv (lpPoint->y, 2540,
+ GetDeviceCaps (hdc, LOGPIXELSY));
+ ReleaseDC (NULL, hdc);
+ }
+ else {
+ lpPoint->x = 0;
+ lpPoint->y = 0;
+ }
+}
+
diff --git a/private/mvdm/wow16/ole/client/cmacs.h b/private/mvdm/wow16/ole/client/cmacs.h
new file mode 100644
index 000000000..ca531d9f1
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/cmacs.h
@@ -0,0 +1,61 @@
+/****************************** Module Header ******************************\
+* Module Name: CMACS.H
+*
+* This module contains common macros used by C routines.
+*
+* Created: 9-Feb-1989
+*
+* Copyright (c) 1985 - 1989 Microsoft Corporation
+*
+* History:
+* Created by Raor
+*
+\***************************************************************************/
+
+#define _WINDOWS
+#define DLL_USE
+
+#define INTERNAL PASCAL NEAR
+#define FARINTERNAL PASCAL FAR
+
+#ifdef FIREWALLS
+extern short ole_flags;
+
+#define DEBUG_PUTS 0x01
+#define DEBUG_DEBUG_OUT 0x02
+#define DEBUG_MESSAGEBOX 0x04
+
+extern char szDebugBuffer[];
+
+#define DEBUG_OUT(parm1,parm2){\
+ if(ole_flags & DEBUG_DEBUG_OUT){\
+ wsprintf(szDebugBuffer,parm1,parm2);\
+ OutputDebugString(szDebugBuffer);\
+ OutputDebugString ("^^^ ");\
+ }\
+ }
+
+#define ASSERT(x,y) {\
+ if (!(x)) { \
+ wsprintf (szDebugBuffer, "Assert Failure file %s, line %d\r\n ", \
+ (LPSTR) __FILE__, __LINE__);\
+ OutputDebugString (szDebugBuffer);\
+ OutputDebugString ((LPSTR) (y));\
+ OutputDebugString ("@@@ ");\
+ } \
+}
+
+#define Puts(msg) {\
+ if(ole_flags & DEBUG_PUTS){\
+ OutputDebugString ((LPSTR)(msg));\
+ OutputDebugString ("** ");\
+ }\
+ }
+
+#else
+
+#define DEBUG_OUT(err, val) ;
+#define ASSERT(cond, msg)
+#define Puts(msg)
+
+#endif /* FIREWALLS */
diff --git a/private/mvdm/wow16/ole/client/dde.c b/private/mvdm/wow16/ole/client/dde.c
new file mode 100644
index 000000000..6559c3eac
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/dde.c
@@ -0,0 +1,1327 @@
+
+/****************************** Module Header ******************************\
+* Module Name: DDE.C (Extensible Compound Documents -DDE)
+*
+* Copyright (c) 1985 - 1991 Microsoft Corporation
+*
+* PURPOSE: Handles all API routines for the dde sub-dll of the ole dll.
+*
+* History:
+* Raor,Srinik (../../90,91) Designed and coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dde.h"
+#include "dll.h"
+
+#define WIN32S
+
+/* #define GRAPHBUG */
+
+
+// ### may not need seperate wndproc for system topic!
+HANDLE GetDDEDataHandle (DDEDATA FAR *, WORD, HANDLE);
+
+extern ATOM aSystem;
+extern ATOM aOle;
+extern HANDLE hInstDLL;
+
+
+// DocWndProc: Window procedure used to document DDE conversations
+long FAR PASCAL DocWndProc(hwnd, message, wParam, lParam)
+HWND hwnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+
+{
+ PEDIT_DDE pedit = NULL;
+ LPOBJECT_LE lpobj = NULL;
+
+
+
+ Puts("DocWndProc");
+
+ if (lpobj = (LPOBJECT_LE) GetWindowLong (hwnd, 0))
+ pedit = lpobj->pDocEdit;
+
+ switch (message){
+
+ case WM_DDE_ACK:
+#ifdef FIREWALLS
+ ASSERT (pedit, "Doc conv channel missing");
+#endif
+ DEBUG_OUT ("WM_DDE_ACK ", 0);
+ if (pedit->bTerminating){
+ // ### this error recovery may not be correct.
+ DEBUG_OUT ("No action due to termination process",0)
+ break;
+ }
+
+ switch(pedit->awaitAck){
+
+ case AA_INITIATE:
+ HandleAckInitMsg (pedit, (HWND)wParam);
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ case AA_REQUEST:
+ case AA_UNADVISE:
+ case AA_EXECUTE:
+ case AA_ADVISE:
+ HandleAck (lpobj, pedit, lParam);
+ break;
+
+ case AA_POKE:
+
+ // freeing pokedata is done in handleack
+ HandleAck (lpobj, pedit, lParam);
+ break;
+
+ default:
+ DEBUG_OUT ("received ACK We don't know how to handle ",0)
+ break;
+
+ } // end of switch
+ break;
+
+ case WM_TIMER:
+ HandleTimerMsg (lpobj, pedit);
+ break;
+
+ case WM_DDE_DATA:
+#ifdef FIREWALLS
+ ASSERT (pedit, "Doc conv channel missing");
+#endif
+ DEBUG_OUT ("WM_DDE_DATA",0);
+ HandleDataMsg (lpobj, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case WM_DDE_TERMINATE:
+
+#ifdef FIREWALLS
+ ASSERT (pedit, "Doc conv channel missing");
+#endif
+ DEBUG_OUT ("WM_DDE_TERMINATE",0);
+ HandleTermMsg (lpobj, pedit, (HWND)wParam, TRUE);
+ break;
+
+ case WM_DESTROY:
+
+#ifdef FIREWALLS
+ ASSERT (pedit, "Doc conv channel missing");
+#endif
+ DEBUG_OUT ("Client window being destroyed", 0)
+ pedit->hClient = NULL;
+ break;
+
+ default:
+ return DefWindowProc (hwnd, message, wParam, lParam);
+
+ }
+ return 0L;
+}
+
+
+
+// SrvrWndProc: Window Procedure for System Topic DDE conversations
+// wndproc for system topic
+
+long FAR PASCAL SrvrWndProc(hwnd, message, wParam, lParam)
+HWND hwnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+
+{
+ PEDIT_DDE pedit = NULL;
+ LPOBJECT_LE lpobj = NULL;
+
+ Puts("SysWndProc");
+
+ if (lpobj = (LPOBJECT_LE) GetWindowLong (hwnd, 0))
+ pedit = lpobj->pSysEdit;
+
+ switch (message){
+
+ case WM_DDE_ACK:
+
+#ifdef FIREWALLS
+ ASSERT (pedit, "sys conv edit block missing");
+#endif
+
+ DEBUG_OUT ("SYS: WM_DDE_ACK",0);
+
+ if(pedit->bTerminating){
+ //### Error recovery may not be OK.
+ DEBUG_OUT ("No action due to termination process",0)
+ break;
+ }
+
+ switch (pedit->awaitAck) {
+
+
+ case AA_INITIATE:
+
+#ifdef HISTORY
+ if (GetWindowWord ((HWND)wParam, GWW_HINSTANCE) == pedit->hInst ||
+ IsSrvrDLLwnd ((HWND)wParam, pedit->hInst)) {
+ // For exact instance match or for
+ // DLL instance match, keep the new one
+#ifdef FIREWALLS
+ ASSERT (!pedit->hServer, "Two instances are matching");
+#endif
+
+ pedit->hServer = (HWND)wParam;
+ } else {
+
+ ++pedit->extraTerm;
+ // This post directly is alright since we are
+ // terminating extra initiates.
+
+ PostMessage ((HWND)wParam,
+ WM_DDE_TERMINATE, hwnd, 0);
+ }
+#else
+
+ HandleAckInitMsg (pedit, (HWND)wParam);
+#endif
+ if (LOWORD(lParam))
+ GlobalDeleteAtom (LOWORD(lParam));
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+
+ break;
+
+ case AA_EXECUTE:
+ HandleAck(lpobj, pedit, lParam);
+ break;
+
+
+ default:
+ DEBUG_OUT ("received ACK We don't know how to handle ",0)
+ break;
+
+
+ }
+
+ break;
+
+ case WM_TIMER:
+ HandleTimerMsg (lpobj, pedit);
+ break;
+
+ case WM_DDE_TERMINATE:
+
+#ifdef FIREWALLS
+ ASSERT (pedit, "sys conv edit block missing");
+#endif
+ HandleTermMsg (lpobj, pedit, (HWND)wParam, FALSE);
+ break;
+
+ case WM_DESTROY:
+#ifdef FIREWALLS
+ ASSERT (pedit, "sys conv edit block missing");
+#endif
+ DEBUG_OUT ("destroy window for the sys connection", 0);
+ pedit->hClient = NULL;
+ break;
+
+
+ default:
+ return DefWindowProc (hwnd, message, wParam, lParam);
+
+ }
+ return 0L;
+}
+
+void INTERNAL HandleTimerMsg (lpobj, pedit)
+PEDIT_DDE pedit;
+LPOBJECT_LE lpobj;
+{
+
+
+ // Since there is only one timer for each client, just
+ // repost the message and delete the timer.
+
+ KillTimer (pedit->hClient, 1);
+ pedit->wTimer = 0;
+
+ if (PostMessageToServer(pedit, pedit->msg, pedit->lParam))
+ return ; // return something.
+
+ // Postmessage failed. We need to getback to the main stream of
+ // commands for the object.
+ HandleAck (lpobj, pedit, pedit->lParam);
+ return ;
+}
+
+
+void INTERNAL HandleTermMsg (lpobj, pedit, hwndPost, bDoc)
+LPOBJECT_LE lpobj;
+PEDIT_DDE pedit;
+HWND hwndPost;
+BOOL bDoc;
+{
+ WORD asyncCmd;
+ BOOL bBusy;
+
+ if (pedit->hServer != hwndPost){
+ DEBUG_OUT ("Got terminate for extra conversation",0)
+ if (--pedit->extraTerm == 0 && pedit->bTerminating)
+ ScheduleAsyncCmd (lpobj);
+ return;
+
+ }
+
+ if (!pedit->bTerminating){
+
+ // If we are waiting for any ack, then goto next step with error
+
+ // delete any data if we were in busy mode.
+ bBusy = DeleteBusyData (lpobj, pedit);
+
+ asyncCmd = lpobj->asyncCmd;
+ PostMessageToServer(pedit, WM_DDE_TERMINATE, NULL);
+ pedit->hServer = NULL;
+ if (pedit->awaitAck || bBusy) {
+ // Set error and goto next step.
+ lpobj->subErr = OLE_ERROR_COMM;
+ pedit->awaitAck = NULL;
+ ScheduleAsyncCmd (lpobj);
+ }
+
+ // If the command is delete, do not delete
+ // the edit blocks. It will be deleted
+ // in the OleLnkDelete routine and for delete it is
+ // possible that by the time we come here, the object
+ // may not exist at all.
+
+ if (asyncCmd != OLE_DELETE){
+ // QueryOpen() is done because excel is sending WM_DDE_TERMINATE
+ // for system without sending for doc in case of failure.
+
+ if (bDoc || QueryOpen (lpobj)) {
+ // if the termination is for document and no async command
+ // terminate the server conversation also.
+ if ((asyncCmd == OLE_NONE) || (asyncCmd == OLE_REQUESTDATA)
+ || (asyncCmd == OLE_OTHER) || (asyncCmd == OLE_SETDATA)
+ || (asyncCmd == OLE_RUN) || (asyncCmd == OLE_SHOW)
+ || (asyncCmd == OLE_SETUPDATEOPTIONS)) {
+ if (lpobj->pDocEdit->awaitAck)
+ // we are waiting for an ack on Doc channel. So start
+ // the unlaunch process after we get the ack.
+ lpobj->bUnlaunchLater = TRUE;
+ else
+ CallEmbLnkDelete (lpobj);
+ } else {
+ if (bDoc)
+ DeleteDocEdit (lpobj);
+
+ }
+ }else
+ DeleteSrvrEdit (lpobj);
+
+ }
+ } else {
+ pedit->hServer = NULL;
+ if (pedit->extraTerm == 0)
+ ScheduleAsyncCmd (lpobj);
+ }
+}
+
+#ifdef FIREWALLS
+BOOL INTERNAL CheckAtomValid (ATOM aItem)
+{
+ char buffer[MAX_ATOM];
+ int len, val;
+
+
+ Puts("CheckAtomValid");
+
+ if (aItem == NULL)
+ return TRUE;
+
+ val = GlobalGetAtomName (aItem, buffer, MAX_ATOM);
+ len = lstrlen (buffer);
+ return ((val != 0) && (val == len));
+}
+#endif
+
+
+
+
+// HandleAckInitMsg: Handles WM_DDE_ACKs received while in initiate state. If
+// this is the first reply, save its window handle. If multiple replies
+// are received, take the one with the prefered instance, if there is
+// one. Keep a count of WM_DDE_TERMINATEs we send so that we don't shut
+// the window until we get all of the responses for WM_DDE_TERMINATEs.
+
+void INTERNAL HandleAckInitMsg (pedit, hserver)
+PEDIT_DDE pedit;
+HWND hserver;
+{
+
+ Puts("HandleAckInitMsg");
+
+ if (pedit->hServer){
+ // just take the very first one. Direct post is OK
+ PostMessage (hserver, WM_DDE_TERMINATE, pedit->hClient, 0);
+ ++pedit->extraTerm;
+ } else
+ pedit->hServer = hserver;
+
+}
+
+
+// HandleAck: returns 0 if <ack> is not positive, else non-0. Should probably be
+// a macro.
+
+BOOL INTERNAL HandleAck (lpobj, pedit, lParam)
+LPOBJECT_LE lpobj;
+PEDIT_DDE pedit;
+DWORD lParam;
+{
+
+ BOOL retval = TRUE;
+
+
+ // check for busy bit
+ if ((LOWORD (lParam) & 0x4000) && ContextCallBack (lpobj, OLE_QUERY_RETRY)){
+ // we got busy from the server. create a timer and wait for time out.
+
+ // We do not need makeprocinstance since, DLLs are single insance, all
+ // we need to do is export for this function.
+
+ if (pedit->wTimer = SetTimer (pedit->hClient, 1, 3000, NULL))
+ return TRUE;
+ }
+
+ // even if the client got terminate we have to go thru this path.
+
+ if (pedit->wTimer) {
+ KillTimer (pedit->hClient, 1);
+ pedit->wTimer = 0;
+ }
+
+ if (pedit->awaitAck == AA_POKE)
+ // We have to free the data first. Handleack can trigger
+ // another Poke (like pokehostnames)
+ FreePokeData (lpobj, pedit);
+
+ if (pedit->awaitAck == AA_EXECUTE)
+ GlobalFree (HIWORD (lParam));
+ else {
+ ASSERT (CheckAtomValid(HIWORD(lParam)),"Invalid atom in ACK")
+ if (HIWORD (lParam))
+ GlobalDeleteAtom (HIWORD (lParam));
+ }
+
+ if (!(LOWORD (lParam) & 0x8000)) {
+ // error case. set the error
+ DEBUG_OUT ("DDE ACK with failure", 0)
+
+ if (lpobj->errHint){
+ lpobj->subErr = lpobj->errHint;
+ lpobj->errHint = OLE_OK;
+ } else
+ lpobj->subErr = OLE_ERROR_COMM;
+
+ retval = FALSE;
+
+ if (pedit->awaitAck == AA_ADVISE) {
+
+#ifdef ASSERT
+ ASSERT (pedit->hopt, "failed advise, options block missing");
+#endif
+ GlobalFree (pedit->hopt);
+ }
+ }
+
+ pedit->hopt = NULL;
+ pedit->awaitAck = NULL;
+ ScheduleAsyncCmd (lpobj);
+ return retval;
+}
+
+// HandleDataMsg: Called for WM_DDE_DATA message. If data is from an
+// ADVISE-ON-CLOSE and this is there are no more outstanding
+// ADVISE-ON-CLOSE requests, close the document and end the
+// conversation.
+
+void INTERNAL HandleDataMsg (lpobj, hdata, aItem)
+LPOBJECT_LE lpobj;
+HANDLE hdata;
+ATOM aItem;
+{
+ DDEDATA far *lpdata = NULL;
+ BOOL fAck;
+ BOOL fRelease;
+ int options;
+ PEDIT_DDE pedit;
+
+ Puts("HandleDataMsg");
+
+ if (ScanItemOptions (aItem, (int far *)&options) != OLE_OK) {
+ DEBUG_OUT (FALSE, "Improper item options");
+ return;
+ }
+
+ pedit = lpobj->pDocEdit;
+
+ if (hdata) {
+ if (!(lpdata = (DDEDATA FAR *) GlobalLock(hdata)))
+ return;
+
+ fAck = lpdata->fAckReq;
+ fRelease = lpdata->fRelease;
+
+ if (pedit->bTerminating) {
+ DEBUG_OUT ("Got DDE_DATA in terminate sequence",0)
+ fRelease = TRUE;
+ }
+ else {
+ if (lpdata->cfFormat == (int)cfBinary && aItem == aStdDocName) {
+ ChangeDocName (lpobj, (LPSTR)lpdata->Value);
+ }
+ else
+ SetData (lpobj, hdata, options);
+
+ #ifdef FIREWALLS
+ ASSERT (IsWindowValid(pedit->hServer),
+ "Server window missing in HandleDataMsg")
+ ASSERT (CheckAtomValid(aItem),"HandleDataMsg invalid atom")
+ #endif
+
+ // important that we post the acknowledge first. Otherwist the
+ // messages are not in sync.
+
+ if (fAck)
+ PostMessageToServer (pedit, WM_DDE_ACK,
+ MAKELONG(POSITIVE_ACK,aItem));
+ else if (aItem)
+ GlobalDeleteAtom (aItem);
+
+ if ((lpdata->fResponse) && (pedit->awaitAck == AA_REQUEST)) {
+ // we sent the request. So, schedule next step.
+ pedit->awaitAck = NULL;
+ ScheduleAsyncCmd (lpobj);
+ }
+ }
+
+ GlobalUnlock (hdata);
+ if (fRelease)
+ GlobalFree (hdata);
+ }
+ else {
+ if (CanCallback (lpobj, options)) {
+ if (options != OLE_CLOSED)
+ ContextCallBack (lpobj, options);
+ else
+ lpobj->bSvrClosing = FALSE;
+
+ }
+ }
+
+ if (options == OLE_CLOSED && (lpobj->pDocEdit->nAdviseClose <= 2)
+ && (lpobj->asyncCmd == OLE_NONE)) {
+ InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH, EMBLNKDELETE);
+ EmbLnkDelete (lpobj);
+ }
+}
+
+
+HANDLE GetDDEDataHandle (lpdata, cfFormat, hdata)
+DDEDATA far *lpdata;
+WORD cfFormat;
+HANDLE hdata;
+{
+ if (cfFormat == CF_BITMAP || cfFormat == CF_METAFILEPICT)
+ return *(LPHANDLE)lpdata->Value;
+
+ if (cfFormat == CF_DIB)
+ return GlobalReAlloc (*(LPHANDLE)lpdata->Value, 0L,
+ GMEM_MODIFY|GMEM_SHARE);
+
+ return CopyData (((LPSTR)lpdata)+4, GlobalSize (hdata) - 4);
+}
+
+// SetData: Given the DDEDATA structure from a WM_DDE_DATA message, set up the
+// appropriate data in lpobj. If the native is in native format, add
+// that field, otherwise, if it is in picture format, ask the picture
+// to add it itself.
+
+void INTERNAL SetData (lpobj, hdata, options)
+LPOBJECT_LE lpobj;
+HANDLE hdata;
+int options;
+{
+ DDEDATA far *lpdata = NULL;
+ OLESTATUS retVal = OLE_ERROR_MEMORY;
+ HANDLE hdataDDE;
+
+ Puts("SetData");
+
+ if (!(lpdata = (DDEDATA far *) (GlobalLock (hdata))))
+ goto errrtn;
+
+
+ if (!(hdataDDE = GetDDEDataHandle (lpdata, lpdata->cfFormat, hdata))) {
+ lpobj->subErr = OLE_ERROR_MEMORY;
+ goto errrtn;
+ }
+
+ if (lpdata->cfFormat == (int)cfNative) {
+ retVal = (*lpobj->head.lpvtbl->ChangeData) ( lpobj,
+ hdataDDE,
+ lpobj->head.lpclient,
+ TRUE); // use this data, don't copy
+
+ }
+ else if (lpdata->cfFormat && (lpdata->cfFormat == GetPictType (lpobj))) {
+
+ retVal = (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict,
+ hdataDDE,
+ lpobj->head.lpclient,
+ lpdata->fRelease);
+
+ } else {
+ // case of extra data in the object.
+ DeleteExtraData (lpobj);
+ lpobj->cfExtra = lpdata->cfFormat;
+ lpobj->hextraData = hdataDDE;
+ goto end;
+ }
+
+ if (retVal == OLE_OK) {
+ SetExtents (lpobj);
+ if (CanCallback (lpobj, options)) {
+ if (options == OLE_CLOSED) {
+ ContextCallBack (lpobj, OLE_CHANGED);
+ ContextCallBack (lpobj, OLE_CLOSED);
+ lpobj->bSvrClosing = FALSE;
+ }
+ else
+ ContextCallBack (lpobj, options);
+ }
+ }
+
+end:
+errrtn:
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ return;
+}
+
+
+// SysStartConvDDE: Starts a system conversation. Returns a handle to that
+// conversation, or NULL.
+
+BOOL INTERNAL InitSrvrConv (lpobj, hInst)
+LPOBJECT_LE lpobj;
+HANDLE hInst;
+{
+ HANDLE hedit = NULL;
+ PEDIT_DDE pedit = NULL;
+
+ Puts("InitSrvrConv");
+
+ if (!lpobj->hSysEdit) {
+ hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
+
+ if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL))
+ goto errRtn;
+
+ } else {
+#ifdef FIREWALLS
+ ASSERT (!lpobj->pSysEdit->hClient, "Sys conv lptr is present");
+#endif
+ hedit = lpobj->hSysEdit;
+ pedit = lpobj->pSysEdit;
+ UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE));
+ }
+
+ if((pedit->hClient = CreateWindow ("OleSrvrWndClass", "",
+ WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL)
+ goto errRtn;
+
+
+ lpobj->hSysEdit = hedit;
+ lpobj->pSysEdit = pedit;
+ pedit->hInst = hInst;
+ pedit->awaitAck = AA_INITIATE;
+
+ SetWindowLong (pedit->hClient, 0, (LONG)lpobj);
+ SendMessage (-1, WM_DDE_INITIATE, pedit->hClient,
+ MAKELONG (lpobj->app, aOle));
+
+ ASSERT (CheckAtomValid(aOle),"systopic invalid atom")
+
+ pedit->awaitAck = NULL;
+ if (pedit->hServer == NULL) {
+ pedit->awaitAck = AA_INITIATE;
+ // Now try the System topic
+ SendMessage (-1, WM_DDE_INITIATE, pedit->hClient,
+ MAKELONG (lpobj->app, aSystem));
+
+ ASSERT (CheckAtomValid(aSystem),"systopic invalid atom")
+
+ pedit->awaitAck = NULL;
+ if (pedit->hServer == NULL) {
+ DEBUG_OUT ("Srver connection failed", 0);
+ goto errRtn;
+ }
+ }
+
+ // Put the long ptr handle in the object.
+ return TRUE;
+
+errRtn:
+ if (pedit->hClient)
+ DestroyWindow (pedit->hClient);
+
+ if (pedit)
+ LocalUnlock (hedit);
+
+ if (hedit)
+ LocalFree (hedit);
+
+ lpobj->hSysEdit = NULL;
+ lpobj->pSysEdit = NULL;
+
+ return FALSE;
+}
+
+
+// TermSrvrConv: Ends conversation indicated by hedit.
+void INTERNAL TermSrvrConv (lpobj)
+LPOBJECT_LE lpobj;
+{
+ PEDIT_DDE pedit;
+
+ Puts("TermSrvrConv");
+
+
+ if (!(pedit = lpobj->pSysEdit))
+ return;
+
+ if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)){
+ lpobj->bAsync = TRUE;
+ pedit->bTerminating = TRUE;
+ } else {
+ pedit->bTerminating = FALSE;
+ lpobj->subErr = OLE_ERROR_TERMINATE;
+ }
+ return;
+}
+
+
+void INTERNAL DeleteAbortData (lpobj, pedit)
+LPOBJECT_LE lpobj;
+PEDIT_DDE pedit;
+{
+
+ // kill if any timer active.
+ if (pedit->wTimer) {
+ KillTimer (pedit->hClient, 1);
+ pedit->wTimer = 0;
+ }
+ return;
+
+
+}
+
+BOOL INTERNAL DeleteBusyData (lpobj, pedit)
+LPOBJECT_LE lpobj;
+PEDIT_DDE pedit;
+{
+
+ // kill if any timer active.
+ if (pedit->wTimer) {
+ KillTimer (pedit->hClient, 1);
+ pedit->wTimer = 0;
+
+ if (pedit->hData) {
+ GlobalFree (pedit->hData);
+ pedit->hData = NULL;
+ }
+
+ if (pedit->hopt) {
+ GlobalFree (pedit->hopt);
+ pedit->hopt = NULL;
+ }
+
+ if (pedit->awaitAck && (HIWORD(pedit->lParam))) {
+ if (pedit->awaitAck == AA_EXECUTE)
+ GlobalFree (HIWORD (pedit->lParam));
+ else {
+ ASSERT (CheckAtomValid(HIWORD(pedit->lParam)),
+ "Invalid atom in ACK")
+ if (HIWORD(pedit->lParam))
+ GlobalDeleteAtom (HIWORD(pedit->lParam));
+ }
+
+ // we want to wipe out the HIWORD of lParam
+ pedit->lParam &= 0x0000FFFF;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void INTERNAL DeleteSrvrEdit (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ PEDIT_DDE pedit;
+
+ Puts("deleteSrvrEdit");
+
+ if (!(pedit = lpobj->pSysEdit))
+ return;
+
+
+ // delete any data if we were in busy mode.
+ DeleteBusyData (lpobj, pedit);
+
+ if (pedit->hClient)
+ DestroyWindow (pedit->hClient);
+
+ if (lpobj->pSysEdit)
+ LocalUnlock (lpobj->hSysEdit);
+
+ if (lpobj->hSysEdit)
+ LocalFree (lpobj->hSysEdit);
+
+ lpobj->hSysEdit = NULL;
+ lpobj->pSysEdit = NULL;
+
+ return;
+}
+
+
+void INTERNAL SendStdExit (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+
+ Puts("SendSrvrExit");
+
+ if (!lpobj->pSysEdit)
+ return;
+
+ SrvrExecute (lpobj, MapStrToH ("[StdExit]"));
+
+}
+
+void INTERNAL SendStdClose (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+
+ Puts("SendDocClose");
+
+ if (!lpobj->pDocEdit)
+ return;
+
+ DocExecute (lpobj, MapStrToH ("[StdCloseDocument]"));
+
+}
+
+
+// SrvrExecute: Sends execute command to system conversation.
+BOOL INTERNAL SrvrExecute (lpobj, hdata)
+LPOBJECT_LE lpobj;
+HANDLE hdata;
+{
+ PEDIT_DDE pedit = NULL;
+ int retval = FALSE;
+
+ Puts("SrvrExecute");
+
+#ifdef FIREWALLS
+
+ ASSERT (lpobj->hSysEdit, "Sys conv handle missing");
+ ASSERT (lpobj->pSysEdit, "sys conv lptr is missing");
+
+#endif
+ pedit = lpobj->pSysEdit;
+
+ if (hdata == NULL || pedit == NULL) {
+ lpobj->subErr = OLE_ERROR_MEMORY;
+ return FALSE;
+ }
+
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "In terminate state")
+ ASSERT (pedit->awaitAck == NULL, "trying to Post msg while waiting for ack")
+#endif
+
+ if (lpobj->bOldLink) {
+ GlobalFree (hdata);
+ return TRUE;
+ }
+
+
+ if (PostMessageToServer (pedit, WM_DDE_EXECUTE, MAKELONG (0, hdata))) {
+ // data is being freed in the acknowledge
+ lpobj->bAsync = TRUE;
+ pedit->awaitAck = AA_EXECUTE;
+ return TRUE;
+ } else {
+ lpobj->subErr = OLE_ERROR_COMMAND;
+ GlobalFree (hdata);
+ return FALSE;
+ }
+}
+
+// StartConvDDE: Starts the document conversation for an object based on
+// .app and .topic atoms.
+BOOL FARINTERNAL InitDocConv (lpobj, fNetDlg)
+LPOBJECT_LE lpobj;
+BOOL fNetDlg;
+{
+
+ // ### This routine looks very similar to IitSrvrConv
+ // combine with the it
+
+ HANDLE hedit = NULL;
+ PEDIT_DDE pedit = NULL;
+ char buf[MAX_NET_NAME];
+ int nDrive = 2; // drive C
+ char cOldDrive;
+
+ Puts("InitDocConv");
+
+ if (QueryOpen (lpobj)){
+ DEBUG_OUT ("Attempt to start already existing conversation",0);
+ return FALSE;
+ }
+
+ cOldDrive = lpobj->cDrive;
+ if (CheckNetDrive (lpobj, fNetDlg) != OLE_OK)
+ return FALSE;
+
+ if (!lpobj->pDocEdit) {
+ hedit = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (EDIT_DDE));
+
+ if (hedit == NULL || ((pedit = (PEDIT_DDE) LocalLock (hedit)) == NULL)){
+ lpobj->subErr = OLE_ERROR_MEMORY;
+ goto errRtn;
+ }
+ } else {
+#ifdef FIREWALLS
+ ASSERT (!lpobj->pDocEdit->hClient, "Doc conv lptr is present");
+#endif
+ hedit = lpobj->hDocEdit;
+ pedit = lpobj->pDocEdit;
+ UtilMemClr ((PSTR) pedit, sizeof (EDIT_DDE));
+ }
+
+ if ((pedit->hClient = CreateWindow ("OleDocWndClass", "Window Name",
+ WS_OVERLAPPED,0,0,0,0,NULL,NULL, hInstDLL, NULL)) == NULL) {
+ lpobj->subErr = OLE_ERROR_MEMORY;
+ goto errRtn;
+ }
+ lpobj->hDocEdit = hedit;
+ lpobj->pDocEdit = pedit;
+ SetWindowLong (pedit->hClient, 0, (LONG)lpobj);
+
+ // buf will filled by netname in the first call to SetNextNetDrive()
+ buf[0] = '\0';
+ do {
+ pedit->awaitAck = AA_INITIATE;
+
+ // !!! Where are the atom counts bumped?
+
+ SendMessage (-1, WM_DDE_INITIATE, pedit->hClient,
+ MAKELONG (lpobj->app, lpobj->topic));
+
+ pedit->awaitAck = NULL;
+
+ if (pedit->hServer) {
+ if ((cOldDrive != lpobj->cDrive)
+ && (lpobj->asyncCmd != OLE_CREATEFROMFILE))
+ ContextCallBack (lpobj, OLE_RENAMED);
+ return TRUE;
+ }
+
+ } while ((lpobj->head.ctype == CT_LINK) && (lpobj->aNetName)
+ && SetNextNetDrive (lpobj, &nDrive, buf)) ;
+
+errRtn:
+ if (cOldDrive != lpobj->cDrive) {
+ // put back the old drive
+ lpobj->cDrive = cOldDrive;
+ ChangeTopic (lpobj);
+ }
+
+ if (pedit->hClient)
+ DestroyWindow (pedit->hClient);
+
+ if (pedit)
+ LocalUnlock (hedit);
+
+ if (hedit)
+ LocalFree (hedit);
+
+ lpobj->hDocEdit = NULL;
+ lpobj->pDocEdit = NULL;
+ return FALSE;
+}
+
+
+// Execute: Sends an execute string WM_DDE_EXECUTE to the document conversation.
+BOOL INTERNAL DocExecute (lpobj, hdata)
+LPOBJECT_LE lpobj;
+HANDLE hdata;
+{
+ PEDIT_DDE pedit;
+
+ Puts("DocExecute");
+ pedit = lpobj->pDocEdit;
+
+ if (hdata == NULL || pedit == NULL)
+ return FALSE;
+
+
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "Execute: terminating")
+ ASSERT (pedit->hClient, "Client null")
+ ASSERT (IsWindowValid(pedit->hClient),"Invalid client")
+ ASSERT (pedit->awaitAck == NULL, "trying to Post msg while waiting for ack")
+#endif
+
+ if (lpobj->bOldLink) {
+ GlobalFree (hdata);
+ return TRUE;
+ }
+
+ if (PostMessageToServer (pedit, WM_DDE_EXECUTE, MAKELONG (0, hdata))) {
+ // data is being freed in the execute command
+ pedit->awaitAck = AA_EXECUTE;
+ lpobj->bAsync = TRUE;
+ return TRUE;
+ } else {
+ lpobj->subErr = OLE_ERROR_COMMAND;
+ GlobalFree (hdata);
+ return FALSE;
+ }
+}
+
+
+// EndConvDDE: terminates the doc level conversation.
+void INTERNAL TermDocConv (lpobj)
+LPOBJECT_LE lpobj;
+{
+ PEDIT_DDE pedit;
+
+ Puts ("TermDocConv");
+
+ DEBUG_OUT ("About to terminate convs from destroy",0)
+
+ if (!(pedit = lpobj->pDocEdit))
+ return;
+
+ if (PostMessageToServer (pedit, WM_DDE_TERMINATE, 0)) {
+ pedit->bTerminating = TRUE;
+ lpobj->bAsync = TRUE;
+ } else
+ lpobj->subErr = OLE_ERROR_TERMINATE;
+
+ return;
+
+}
+
+// Deletes the document conversdation memory.
+void INTERNAL DeleteDocEdit (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ PEDIT_DDE pedit;
+
+ Puts ("DeleteDocEdit");
+
+ if (!(pedit = lpobj->pDocEdit))
+ return;
+
+ // delete any data if we were in busy mode.
+ DeleteBusyData (lpobj, pedit);
+
+ // Delete if any data blocks.
+ if (pedit->hClient)
+ DestroyWindow (pedit->hClient);
+
+ if (lpobj->pDocEdit)
+ LocalUnlock (lpobj->hDocEdit);
+
+ if (lpobj->hDocEdit)
+ LocalFree (lpobj->hDocEdit);
+
+ lpobj->hDocEdit = NULL;
+ lpobj->pDocEdit = NULL;
+
+ return;
+}
+
+
+// LeLauchApp: Launches app based on the ClassName in lpobj.
+HANDLE INTERNAL LeLaunchApp (lpobj)
+LPOBJECT_LE lpobj;
+{
+ struct CMDSHOW
+ {
+ WORD first;
+ WORD second;
+ } cmdShow = {2, SW_SHOWNORMAL};
+
+ struct
+ {
+ WORD wEnvSeg;
+ LPSTR lpcmdline;
+ struct CMDSHOW FAR *lpCmdShow;
+ DWORD dwReserved;
+ } paramBlock;
+
+ char cmdline[MAX_STR];
+ char exeName[MAX_STR];
+#ifdef WIN32S
+ char execCmdLine[MAX_STR];
+#endif
+ HANDLE hInst;
+
+ #define EMB_STR " -Embedding "
+
+ Puts("LeLaunchApp");
+
+ GlobalGetAtomName (lpobj->aServer, exeName, MAX_STR);
+
+ if (lpobj->bOldLink) {
+ cmdShow.second = SW_SHOWMINIMIZED;
+ cmdline[0] = ' ';
+ GlobalGetAtomName (lpobj->topic, cmdline + 1, MAX_STR);
+ } else {
+ lstrcpy ((LPSTR)cmdline, (LPSTR) EMB_STR);
+
+ // For all link servers we want to give the filename on the command
+ // line. But Excel is not registering the document before returning
+ // from WinMain, if it has auto load macros. So, we want send StdOpen
+ // for the old servers, instead of giving the file name on the command
+ // line.
+
+ if (lpobj->bOleServer && (lpobj->fCmd & LN_MASK) == LN_LNKACT)
+ GlobalGetAtomName (lpobj->topic, cmdline+sizeof(EMB_STR)-1,
+ MAX_STR-sizeof(EMB_STR));
+ if (lpobj->fCmd & ACT_MINIMIZE)
+ cmdShow.second = SW_SHOWMINIMIZED;
+ else if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB))
+ // we want to launch with show in create invisible case
+ // even though ACT_SHOW flag will be false
+ && ((lpobj->fCmd & LN_MASK) != LN_NEW))
+ cmdShow.second = SW_HIDE;
+ }
+
+ paramBlock.wEnvSeg = NULL;
+ paramBlock.lpcmdline = (LPSTR)cmdline;
+ paramBlock.lpCmdShow = &cmdShow;
+ paramBlock.dwReserved = NULL;
+
+#ifdef WIN32S
+ if (wWinVer != 0x0003) {
+ lstrcpy( (LPSTR)execCmdLine, (LPSTR)exeName);
+ lstrcat( (LPSTR)execCmdLine, (LPSTR)" ");
+ lstrcat( (LPSTR)execCmdLine, (LPSTR)paramBlock.lpcmdline);
+ if ((hInst = WinExec ((LPSTR)execCmdLine, cmdShow.second)) <= 32)
+ hInst = NULL;
+ } else
+#endif
+ if ((hInst = LoadModule ((LPSTR)exeName, &paramBlock)) <= 32)
+ hInst = NULL;
+
+ if (!hInst) {
+ LPSTR lptmp;
+ char ch;
+
+ // strip off the path and try again
+ lptmp = (LPSTR)exeName;
+ lptmp += lstrlen ((LPSTR) exeName);
+ ch = *lptmp;
+ while (ch != '\\' && ch != ':') {
+ if (lptmp == (LPSTR) exeName) {
+ // exe did not have path in it's name. we already tried
+ // loading and it failed, no point trying again.
+ return NULL;
+ }
+ else
+ ch = *--lptmp;
+ }
+
+#ifdef WIN32S
+ if (wWinVer != 0x0003) {
+ lstrcpy( (LPSTR)execCmdLine, (LPSTR)++lptmp);
+ lstrcat( (LPSTR)execCmdLine, (LPSTR)" ");
+ lstrcat( (LPSTR)execCmdLine, (LPSTR)paramBlock.lpcmdline);
+ if ((hInst = WinExec ((LPSTR)execCmdLine, cmdShow.second)) <= 32)
+ hInst = NULL;
+ } else
+#endif
+ if ((hInst = LoadModule (++lptmp, &paramBlock)) <= 32)
+ hInst = NULL;
+ }
+
+ return hInst;
+}
+
+
+
+//ScanItemOptions: Scan for the item options like Close/Save etc.
+
+int INTERNAL ScanItemOptions (aItem, lpoptions)
+ATOM aItem;
+int far *lpoptions;
+{
+
+ ATOM aModifier;
+
+ LPSTR lpbuf;
+ char buf[MAX_STR];
+
+ *lpoptions = OLE_CHANGED;
+
+ if (!aItem) {
+ // NULL item with no modifier means OLE_CHANGED for NULL item
+ return OLE_OK;
+ }
+
+ GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR);
+ lpbuf = (LPSTR)buf;
+
+ while ( *lpbuf && *lpbuf != '/')
+ lpbuf++;
+
+ // no modifier same as /change
+
+ if (*lpbuf == NULL)
+ return OLE_OK;
+
+ *lpbuf++ = NULL; // seperate out the item string
+ // We are using this in the caller.
+
+ if (!(aModifier = GlobalFindAtom (lpbuf)))
+ return OLE_ERROR_SYNTAX;
+
+ if (aModifier == aChange)
+ return OLE_OK;
+
+ // Is it a save?
+ if (aModifier == aSave){
+ *lpoptions = OLE_SAVED;
+ return OLE_OK;
+ }
+ // Is it a Close?
+ if (aModifier == aClose){
+ *lpoptions = OLE_CLOSED;
+ return OLE_OK;
+ }
+
+ // unknown modifier
+ return OLE_ERROR_SYNTAX;
+
+}
+
+void INTERNAL ChangeDocName (lpobj, lpdata)
+LPOBJECT_LE lpobj;
+LPSTR lpdata;
+{
+ ATOM aOldTopic;
+ OLESTATUS retVal;
+
+ aOldTopic = lpobj->topic;
+ lpobj->topic = GlobalAddAtom (lpdata);
+ if ((retVal = SetNetName (lpobj)) != OLE_OK) {
+ if (lpobj->topic)
+ GlobalDeleteAtom (lpobj->topic);
+ lpobj->topic = aOldTopic;
+ return;
+ // !!! what should we do in case of error? Currently, we will not
+ // change the topic if SetNetName fails.
+ }
+
+ if (aOldTopic)
+ GlobalDeleteAtom (aOldTopic);
+
+ // Delete the link data block
+ if (lpobj->hLink) {
+ GlobalFree (lpobj->hLink);
+ lpobj->hLink = NULL;
+ }
+
+ ContextCallBack (lpobj, OLE_RENAMED);
+
+}
+
+
+BOOL INTERNAL CanCallback (lpobj, options)
+LPOBJECT_LE lpobj;
+int options;
+{
+ LPINT lpCount;
+
+ if (options == OLE_CLOSED) {
+ lpobj->bSvrClosing = TRUE;
+ lpCount = &(lpobj->pDocEdit->nAdviseClose);
+ }
+ else if (options == OLE_SAVED) {
+ if (lpobj->head.ctype == CT_LINK)
+ return TRUE;
+ lpCount = &(lpobj->pDocEdit->nAdviseSave);
+ }
+ else {
+ // it must be due to request
+ if ((lpobj->pDocEdit->awaitAck == AA_REQUEST)
+ && lpobj->pDocEdit->bCallLater)
+ return FALSE;
+
+ return TRUE;
+ }
+
+ switch (*lpCount) {
+ case 1:
+ break;
+
+ case 2:
+ ++(*lpCount);
+ return FALSE;
+
+ case 3:
+ --(*lpCount);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void FARINTERNAL CallEmbLnkDelete (lpobj)
+LPOBJECT_LE lpobj;
+{
+ InitAsyncCmd (lpobj, OLE_SERVERUNLAUNCH,EMBLNKDELETE);
+ EmbLnkDelete (lpobj);
+
+ if (lpobj->head.ctype == CT_EMBEDDED) {
+ lpobj->bSvrClosing = TRUE;
+ ContextCallBack (lpobj, OLE_CLOSED);
+ if (FarCheckObject ((LPOLEOBJECT)lpobj))
+ lpobj->bSvrClosing = FALSE;
+ }
+}
diff --git a/private/mvdm/wow16/ole/client/defcreat.c b/private/mvdm/wow16/ole/client/defcreat.c
new file mode 100644
index 000000000..a941abd0f
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/defcreat.c
@@ -0,0 +1,215 @@
+/****************************** Module Header ******************************\
+* Module Name: defcreat.c
+*
+* Purpose: Handles the various object creation routines, which are exported
+* to the DLL writers.
+*
+* Created: November 1990
+*
+* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation
+*
+* History:
+* Srinik (11/12/90) Original
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+
+extern OLECLIPFORMAT cfOwnerLink;
+extern OLECLIPFORMAT cfObjectLink;
+extern OLECLIPFORMAT cfNative;
+
+
+RENDER_ENTRY stdRender[NUM_RENDER] = {
+ { "METAFILEPICT", 0, MfLoadFromStream},
+ { "DIB", 0, DibLoadFromStream},
+ { "BITMAP", 0, BmLoadFromStream}
+};
+
+
+OLESTATUS FARINTERNAL DefLoadFromStream (lpstream, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, objType, aClass, cfFormat)
+LPOLESTREAM lpstream;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LONG objType;
+ATOM aClass;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+ int i;
+
+ *lplpobj = NULL;
+
+ if ((objType == CT_PICTURE) || (objType == CT_STATIC)) {
+ for (i = 0; i < NUM_RENDER; i++) {
+ if (stdRender[i].aClass == aClass) {
+ retVal = (*stdRender[i].Load) (lpstream, lpclient,
+ lhclientdoc, lpobjname, lplpobj, objType);
+ if (aClass)
+ GlobalDeleteAtom (aClass);
+ return retVal;
+ }
+ }
+
+ return GenLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname,
+ lplpobj, objType, aClass, cfFormat);
+ }
+ else {
+ return LeLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname,
+ lplpobj, objType, aClass, cfFormat);
+ }
+}
+
+
+OLESTATUS FAR PASCAL DefCreateFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, objType)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ if (objType == CT_EMBEDDED)
+ return EmbPaste (lpclient, lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (objType == CT_LINK)
+ return LnkPaste (lpclient, lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, cfOwnerLink);
+
+ return OLE_ERROR_CLIPBOARD;
+}
+
+
+
+
+OLESTATUS FAR PASCAL DefCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ return LnkPaste (lpclient, lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, cfObjectLink);
+}
+
+
+OLESTATUS FAR PASCAL DefCreateFromTemplate (lpprotocol, lpclient, lptemplate, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ return LeCreateFromTemplate (lpclient,
+ lptemplate,
+ lhclientdoc,
+ lpobjname,
+ lplpoleobject,
+ optRender,
+ cfFormat);
+}
+
+
+OLESTATUS FAR PASCAL DefCreate (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ return LeCreate (lpclient,
+ lpclass,
+ lhclientdoc,
+ lpobjname,
+ lplpoleobject,
+ optRender,
+ cfFormat);
+}
+
+
+
+OLESTATUS FAR PASCAL DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ return CreateEmbLnkFromFile (lpclient,
+ lpclass,
+ lpfile,
+ NULL,
+ lhclientdoc,
+ lpobjname,
+ lplpoleobject,
+ optRender,
+ cfFormat,
+ CT_EMBEDDED);
+}
+
+
+OLESTATUS FAR PASCAL DefCreateLinkFromFile (lpprotocol, lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LPSTR lpitem;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ return CreateEmbLnkFromFile (lpclient,
+ lpclass,
+ lpfile,
+ lpitem,
+ lhclientdoc,
+ lpobjname,
+ lplpoleobject,
+ optRender,
+ cfFormat,
+ CT_LINK);
+}
+
+
+OLESTATUS FAR PASCAL DefCreateInvisible (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, fActivate)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+BOOL fActivate;
+{
+ return LeCreateInvisible (lpclient,
+ lpclass,
+ lhclientdoc,
+ lpobjname,
+ lplpoleobject,
+ optRender,
+ cfFormat,
+ fActivate);
+}
diff --git a/private/mvdm/wow16/ole/client/dib.c b/private/mvdm/wow16/ole/client/dib.c
new file mode 100644
index 000000000..80d434a9f
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/dib.c
@@ -0,0 +1,495 @@
+/****************************** Module Header ******************************\
+* Module Name: DIB.C
+*
+* Handles all API routines for the device independent bitmap sub-dll of
+* the ole dll.
+*
+* Created: Oct-1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Srinik, Raor (../../1990,91) Designed, coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+void FARINTERNAL DibGetExtents (LPSTR, LPPOINT);
+
+#pragma alloc_text(_TEXT, DibSaveToStream, DibLoadFromStream, DibStreamRead, GetBytes, PutBytes, PutStrWithLen, DibGetExtents)
+
+OLEOBJECTVTBL vtblDIB = {
+
+ ErrQueryProtocol, // check whether the speced protocol is supported
+
+ DibRelease, // Release
+ ErrShow, // Show
+ ErrPlay, // show
+ DibGetData, // Get the object data
+ ErrSetData, // Set the object data
+ ErrSetTargetDevice, //
+
+ ErrSetBounds, // set viewport bounds
+ DibEnumFormat, // enumerate supported formats
+ ErrSetColorScheme, //
+ DibRelease, // delete
+ ErrSetHostNames, //
+
+ DibSaveToStream, // write to file
+ DibClone, // clone object
+ ErrCopyFromLink, // Create embedded from Lnk
+
+ DibEqual, // compares the given objects for data equality
+
+ DibCopy, // copy to clip
+
+ DibDraw, // draw the object
+
+ ErrActivate, // open
+ ErrExecute, // excute
+ ErrClose, // Stop
+ ErrUpdate, // Update
+ ErrReconnect, // Reconnect
+
+ ErrObjectConvert, // convert object to specified type
+
+ ErrGetUpdateOptions, // update options
+ ErrSetUpdateOptions, // update options
+
+ ObjRename, // Change Object name
+ ObjQueryName, // Get current object name
+
+ ObjQueryType, // Object type
+ DibQueryBounds, // QueryBounds
+ ObjQuerySize, // Find the size of the object
+ ErrQueryOpen, // Query open
+ ErrQueryOutOfDate, // query whether object is current
+
+ ErrQueryRelease, // release related stuff
+ ErrQueryRelease,
+ ErrQueryRelease,
+
+ ErrRequestData, // requestdata
+ ErrObjectLong, // objectLong
+ DibChangeData // change data of the existing object
+};
+
+
+
+OLESTATUS FARINTERNAL DibRelease (lpobj)
+LPOBJECT_DIB lpobj;
+{
+ HOBJECT hobj;
+
+ if (lpobj->hDIB){
+ GlobalFree (lpobj->hDIB);
+ lpobj->hDIB = NULL;
+ }
+
+ if (lpobj->head.lhclientdoc)
+ DocDeleteObject ((LPOLEOBJECT) lpobj);
+
+ if (hobj = lpobj->head.hobj){
+ lpobj->head.hobj = NULL;
+ GlobalUnlock (hobj);
+ GlobalFree (hobj);
+ }
+
+ return OLE_OK;
+}
+
+
+
+OLESTATUS FARINTERNAL DibSaveToStream (lpobj, lpstream)
+LPOBJECT_DIB lpobj;
+LPOLESTREAM lpstream;
+{
+ LPSTR lpDIBbuf;
+
+ if (!lpobj->hDIB)
+ return OLE_ERROR_BLANK;
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutStrWithLen (lpstream, (LPSTR)"DIB"))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ lpobj->sizeBytes = GlobalSize (lpobj->hDIB);
+ if (PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (!(lpDIBbuf = GlobalLock (lpobj->hDIB)))
+ return OLE_ERROR_MEMORY;
+
+ if (PutBytes (lpstream, lpDIBbuf, lpobj->sizeBytes))
+ return OLE_ERROR_STREAM;
+
+ GlobalUnlock (lpobj->hDIB);
+ return OLE_OK;
+}
+
+
+
+OLESTATUS FARINTERNAL DibClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_DIB lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_DIB FAR * lplpobj;
+{
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (!(*lplpobj = DibCreateObject (lpobjsrc->hDIB, lpclient, FALSE,
+ lhclientdoc, lpobjname, lpobjsrc->head.ctype)))
+ return OLE_ERROR_MEMORY;
+ else
+ return OLE_OK;
+}
+
+
+
+OLESTATUS FARINTERNAL DibEqual (lpobj1, lpobj2)
+LPOBJECT_DIB lpobj1;
+LPOBJECT_DIB lpobj2;
+{
+ if (CmpGlobals (lpobj1->hDIB, lpobj1->hDIB))
+ return OLE_OK;
+
+ return OLE_ERROR_NOT_EQUAL;
+}
+
+
+OLESTATUS FARINTERNAL DibCopy (lpobj)
+LPOBJECT_DIB lpobj;
+{
+ HANDLE hDIB;
+
+ if (!lpobj->hDIB)
+ return OLE_ERROR_BLANK;
+
+ if (!(hDIB = DuplicateGlobal (lpobj->hDIB, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+
+ SetClipboardData (CF_DIB, hDIB);
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL DibQueryBounds (lpobj, lpRc)
+LPOBJECT_DIB lpobj;
+LPRECT lpRc;
+{
+ Puts("DibQueryBounds");
+
+ if (!lpobj->hDIB)
+ return OLE_ERROR_BLANK;
+
+ lpRc->left = 0;
+ lpRc->top = 0;
+ lpRc->right = (int) lpobj->head.cx;
+ lpRc->bottom = (int) lpobj->head.cy;
+ return OLE_OK;
+}
+
+
+
+OLECLIPFORMAT FARINTERNAL DibEnumFormat (lpobj, cfFormat)
+LPOBJECT_DIB lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ if (!cfFormat)
+ return CF_DIB;
+
+ return NULL;
+}
+
+
+OLESTATUS FARINTERNAL DibGetData (lpobj, cfFormat, lphandle)
+LPOBJECT_DIB lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+ if (cfFormat != CF_DIB)
+ return OLE_ERROR_FORMAT;
+
+ if (!(*lphandle = lpobj->hDIB))
+ return OLE_ERROR_BLANK;
+
+ return OLE_OK;
+}
+
+
+
+LPOBJECT_DIB FARINTERNAL DibCreateObject (hDIB, lpclient, fDelete, lhclientdoc, lpobjname, objType)
+HANDLE hDIB;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ LPOBJECT_DIB lpobj;
+
+ if (lpobj = DibCreateBlank (lhclientdoc, lpobjname, objType)) {
+ if (DibChangeData (lpobj, hDIB, lpclient, fDelete) != OLE_OK) {
+ DibRelease (lpobj);
+ lpobj = NULL;
+ }
+ }
+
+ return lpobj;
+}
+
+
+
+// If the routine fails then the object will be left with it's old data.
+// If fDelete is TRUE, then hNewDIB will be deleted whether the routine
+// is successful or not.
+
+OLESTATUS FARINTERNAL DibChangeData (lpobj, hNewDIB, lpclient, fDelete)
+LPOBJECT_DIB lpobj;
+HANDLE hNewDIB;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+{
+ BITMAPINFOHEADER bi;
+ DWORD dwSize;
+ LPBITMAPINFOHEADER lpBi;
+
+ if (!hNewDIB)
+ return OLE_ERROR_BLANK;
+
+ lpBi = (LPBITMAPINFOHEADER) &bi;
+ if (!fDelete) {
+ if (!(hNewDIB = DuplicateGlobal (hNewDIB, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+ }
+ else {
+ // change the ownership to yourself
+
+ HANDLE htmp;
+
+ if (!(htmp = GlobalReAlloc (hNewDIB, 0L, GMEM_MODIFY|GMEM_SHARE))) {
+ htmp = DuplicateGlobal (hNewDIB, GMEM_MOVEABLE);
+ GlobalFree (hNewDIB);
+ if (!htmp)
+ return OLE_ERROR_MEMORY;
+ }
+
+ hNewDIB = htmp;
+ }
+
+ if (!(lpBi = (LPBITMAPINFOHEADER) GlobalLock (hNewDIB))) {
+ GlobalFree (hNewDIB);
+ return OLE_ERROR_MEMORY;
+ }
+
+ dwSize = GlobalSize (hNewDIB);
+ if (lpobj->hDIB)
+ GlobalFree (lpobj->hDIB);
+ DibUpdateStruct (lpobj, lpclient, hNewDIB, lpBi, dwSize);
+ return OLE_OK;
+}
+
+
+void INTERNAL DibUpdateStruct (lpobj, lpclient, hDIB, lpBi, dwBytes)
+LPOBJECT_DIB lpobj;
+LPOLECLIENT lpclient;
+HANDLE hDIB;
+LPBITMAPINFOHEADER lpBi;
+DWORD dwBytes;
+{
+ POINT point;
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->sizeBytes = dwBytes;
+
+#ifdef OLD
+ lpobj->xSize = point.x = (int) lpBi->biWidth;
+ lpobj->ySize = point.y = (int) lpBi->biHeight;
+ ConvertToHimetric (&point);
+#else
+ DibGetExtents ((LPSTR) lpBi, &point);
+#endif
+
+ lpobj->head.cx = (LONG) point.x;
+ lpobj->head.cy = (LONG) point.y;
+ lpobj->hDIB = hDIB;
+}
+
+
+
+OLESTATUS FARINTERNAL DibLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpoleobject, objType)
+LPOLESTREAM lpstream;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG objType;
+{
+ LPOBJECT_DIB lpobj = NULL;
+
+ *lplpoleobject = NULL;
+
+ if (!(lpobj = DibCreateBlank (lhclientdoc, lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ lpobj->head.lpclient = lpclient;
+ if (GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
+ goto errLoad;
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ goto errLoad;
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
+ goto errLoad;
+
+ if (DibStreamRead (lpstream, lpobj)) {
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+ return OLE_OK;
+ }
+
+errLoad:
+ OleDelete ((LPOLEOBJECT) lpobj);
+ return OLE_ERROR_STREAM;
+}
+
+
+
+LPOBJECT_DIB FARINTERNAL DibCreateBlank (lhclientdoc, lpobjname, objType)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ HOBJECT hobj;
+ LPOBJECT_DIB lpobj;
+
+ if((hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_DIB)))
+ == NULL)
+ return NULL;
+
+ if (!(lpobj = (LPOBJECT_DIB) GlobalLock (hobj))){
+ GlobalFree (hobj);
+ return NULL;
+ }
+
+ // The structure is ZERO initialized at allocation time. So only the
+ // fields that need to be filled with values other than ZEROS are
+ // initialized below
+
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+ lpobj->head.mm = MM_TEXT;
+ lpobj->head.ctype = objType;
+ lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblDIB;
+ lpobj->head.iTable = INVALID_INDEX;
+ lpobj->head.hobj = hobj;
+
+ if (objType == CT_STATIC)
+ DocAddObject ((LPCLIENTDOC) lhclientdoc,
+ (LPOLEOBJECT) lpobj, lpobjname);
+ return lpobj;
+}
+
+
+
+
+BOOL INTERNAL DibStreamRead (lpstream, lpobj)
+LPOLESTREAM lpstream;
+LPOBJECT_DIB lpobj;
+{
+ HANDLE hDIBbuf;
+ LPSTR lpDIBbuf;
+ BOOL retVal = FALSE;
+ BITMAPINFOHEADER bi;
+
+ if (GetBytes (lpstream, (LPSTR) &bi, sizeof(bi)))
+ return FALSE;
+
+ if (hDIBbuf = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes)) {
+ if (lpDIBbuf = (LPSTR)GlobalLock (hDIBbuf)){
+ *((LPBITMAPINFOHEADER) lpDIBbuf) = bi;
+ if (!GetBytes (lpstream, lpDIBbuf+sizeof(bi),
+ (lpobj->sizeBytes - sizeof(bi)))) {
+
+ lpobj->hDIB = hDIBbuf;
+#ifdef OLD
+ //!!! this info should be part of the stream
+ if (!lpobj->head.cx) {
+ DibGetExtents ((LPSTR) lpDIBbuf, &point);
+ lpobj->head.cx = (LONG) point.x;
+ lpobj->head.cy = (LONG) point.y;
+ }
+#endif
+ retVal = TRUE;
+ }
+ GlobalUnlock(hDIBbuf);
+ }
+ //* Hang on to the memory allocated for the DIB
+ }
+ return retVal;
+}
+
+
+OLESTATUS FARINTERNAL DibPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG objType;
+{
+ HANDLE hDIB;
+
+ if ((hDIB = GetClipboardData (CF_DIB)) == NULL)
+ return OLE_ERROR_MEMORY;
+
+ *lplpoleobject = (LPOLEOBJECT) DibCreateObject (hDIB, lpclient, FALSE,
+ lhclientdoc, lpobjname, objType);
+
+ return OLE_OK;
+
+}
+
+
+void FARINTERNAL DibGetExtents (lpData, lpPoint)
+LPSTR lpData;
+LPPOINT lpPoint;
+{
+ #define HIMET_PER_METER 100000L // number of HIMETRIC units / meter
+
+ LPBITMAPINFOHEADER lpbmi;
+
+ lpbmi = (LPBITMAPINFOHEADER)lpData;
+
+ if (!(lpbmi->biXPelsPerMeter && lpbmi->biYPelsPerMeter)) {
+ HDC hdc;
+
+ hdc = GetDC (NULL);
+ lpbmi->biXPelsPerMeter = MulDiv (GetDeviceCaps (hdc, LOGPIXELSX),
+ 10000, 254);
+ lpbmi->biYPelsPerMeter = MulDiv (GetDeviceCaps (hdc, LOGPIXELSY),
+ 10000, 254);
+
+ ReleaseDC (NULL, hdc);
+ }
+
+ lpPoint->x = (int) (lpbmi->biWidth * HIMET_PER_METER
+ / lpbmi->biXPelsPerMeter);
+ lpPoint->y = -(int) (lpbmi->biHeight * HIMET_PER_METER
+ / lpbmi->biYPelsPerMeter);
+}
+
diff --git a/private/mvdm/wow16/ole/client/dll.h b/private/mvdm/wow16/ole/client/dll.h
new file mode 100644
index 000000000..355126a74
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/dll.h
@@ -0,0 +1,958 @@
+/****************************** Module Header ******************************\
+* Module Name: dll.h
+*
+* PURPOSE: Private definitions file for ole.c
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../90,91) Original
+*
+\***************************************************************************/
+
+#define OLE_INTERNAL
+
+#include "cmacs.h"
+#include "ole.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Defines, Object methods table and Structures. //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef HUGE
+#define HUGE huge
+#endif
+
+// Different OS version numbers. One of these values will be in the HIWORD
+// of the OLE version field
+
+#define OS_WIN16 0x0000
+#define OS_MAC 0x0001
+#define OS_WIN32 0x0002
+
+
+// Characteristics Type Field
+#define CT_NULL 0L
+#define CT_LINK 1L
+#define CT_EMBEDDED 2L
+#define CT_STATIC 3L
+#define CT_OLDLINK 4L
+#define CT_PICTURE 5L
+
+#define OLE_NO 0 // for boolean query functions
+#define OLE_YES 1 // for boolean query functions
+
+#define MAX_STR 256
+#define MAX_NET_NAME MAX_STR
+#define INVALID_INDEX -1
+#define MAX_ATOM 256
+
+#define NUM_RENDER 3
+
+#define PROTOCOL_EDIT ((LPSTR)"StdFileEditing")
+#define PROTOCOL_STATIC ((LPSTR)"Static")
+#define PROTOCOL_EXECUTE ((LPSTR)"StdExecute")
+
+#define READ_ACCESS 0
+#define WRITE_ACCESS 1
+
+#define POPUP_NETDLG 1
+
+extern WORD CheckPointer (LPVOID, int);
+WORD FARINTERNAL FarCheckPointer (LPVOID, int);
+
+#define PROBE_OLDLINK(lpobj){\
+ if (lpobj->bOldLink)\
+ return OLE_ERROR_OBJECT;\
+}
+
+
+#define PROBE_READ(lp){\
+ if (!CheckPointer(lp, READ_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+#define PROBE_WRITE(lp){\
+ if (!CheckPointer(lp, WRITE_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+
+#define FARPROBE_READ(lp){\
+ if (!FarCheckPointer(lp, READ_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+#define FARPROBE_WRITE(lp){\
+ if (!FarCheckPointer(lp, WRITE_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+#define PROBE_MODE(bProtMode) {\
+ if (!bProtMode) \
+ return OLE_ERROR_PROTECT_ONLY; \
+}
+
+extern OLECLIPFORMAT cfBinary;
+extern OLECLIPFORMAT cfOwnerLink;
+extern OLECLIPFORMAT cfObjectLink;
+extern OLECLIPFORMAT cfLink;
+extern OLECLIPFORMAT cfNative;
+
+extern ATOM aStdHostNames;
+extern ATOM aStdTargetDevice ;
+extern ATOM aStdDocDimensions;
+extern ATOM aStdDocName;
+extern ATOM aStdColorScheme;
+extern ATOM aNullArg;
+extern ATOM aSave;
+extern ATOM aChange;
+extern ATOM aClose;
+extern ATOM aPackage;
+
+extern HANDLE hInstDLL;
+extern DWORD dwVerToFile;
+extern DWORD dwVerFromFile;
+extern WORD wWinVer;
+extern BOOL bProtMode;
+
+// Used by QuerySize() API;
+extern DWORD dwObjSize;
+
+extern OLESTREAM dllStream;
+extern BOOL bWLO;
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Note: Whenever this table is changed, then we need to update the
+// method table in ole.h. Otherwise we are in trouble.
+//
+////////////////////////////////////////////////////////////////////////////
+
+typedef struct _OLEOBJECTVTBL{
+ LPVOID (FAR PASCAL *QueryProtocol) (LPVOID, LPSTR);
+ OLESTATUS (FAR PASCAL *Release) (LPVOID);
+ OLESTATUS (FAR PASCAL *Show) (LPVOID, BOOL);
+ OLESTATUS (FAR PASCAL *DoVerb) (LPVOID, WORD, BOOL, BOOL);
+ OLESTATUS (FAR PASCAL *GetData) (LPVOID, OLECLIPFORMAT, LPHANDLE);
+ OLESTATUS (FAR PASCAL *SetData) (LPVOID, OLECLIPFORMAT, HANDLE);
+ OLESTATUS (FAR PASCAL *SetTargetDevice) (LPVOID, HANDLE);
+ OLESTATUS (FAR PASCAL *SetBounds) (LPVOID, LPRECT);
+ OLECLIPFORMAT (FAR PASCAL *EnumFormats) (LPVOID, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *SetColorScheme) (LPVOID, LPLOGPALETTE);
+ OLESTATUS (FAR PASCAL *Delete) (LPVOID);
+ OLESTATUS (FAR PASCAL *SetHostNames) (LPVOID, LPSTR, LPSTR);
+
+ OLESTATUS (FAR PASCAL *SaveToStream) (LPVOID, LPOLESTREAM);
+ OLESTATUS (FAR PASCAL *Clone) (LPVOID, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPVOID);
+ OLESTATUS (FAR PASCAL *CopyFromLink) (LPVOID, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPVOID);
+ OLESTATUS (FAR PASCAL *Equal) (LPVOID, LPVOID);
+ OLESTATUS (FAR PASCAL *CopyToClipboard) (LPVOID);
+ OLESTATUS (FAR PASCAL *Draw) (LPVOID, HDC, LPRECT, LPRECT, HDC);
+ OLESTATUS (FAR PASCAL *Activate) (LPVOID, WORD, BOOL, BOOL, HWND, LPRECT);
+ OLESTATUS (FAR PASCAL *Execute) (LPVOID, HANDLE, WORD);
+ OLESTATUS (FAR PASCAL *Close) (LPVOID);
+ OLESTATUS (FAR PASCAL *Update) (LPVOID);
+ OLESTATUS (FAR PASCAL *Reconnect) (LPVOID);
+
+ OLESTATUS (FAR PASCAL *ObjectConvert) (LPVOID, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+
+ OLESTATUS (FAR PASCAL *GetLinkUpdateOptions) (LPVOID, OLEOPT_UPDATE FAR *);
+ OLESTATUS (FAR PASCAL *SetLinkUpdateOptions) (LPVOID, OLEOPT_UPDATE);
+ OLESTATUS (FAR PASCAL *Rename) (LPVOID, LPSTR);
+ OLESTATUS (FAR PASCAL *QueryName) (LPVOID, LPSTR, WORD FAR *);
+ OLESTATUS (FAR PASCAL *QueryType) (LPVOID, LPLONG);
+ OLESTATUS (FAR PASCAL *QueryBounds) (LPVOID, LPRECT);
+ OLESTATUS (FAR PASCAL *QuerySize) (LPVOID, DWORD FAR *);
+ OLESTATUS (FAR PASCAL *QueryOpen) (LPVOID);
+ OLESTATUS (FAR PASCAL *QueryOutOfDate) (LPVOID);
+
+ OLESTATUS (FAR PASCAL *QueryReleaseStatus) (LPVOID);
+ OLESTATUS (FAR PASCAL *QueryReleaseError) (LPVOID);
+ OLE_RELEASE_METHOD (FAR PASCAL *QueryReleaseMethod) (LPVOID);
+
+ OLESTATUS (FAR PASCAL *RequestData) (LPVOID, OLECLIPFORMAT);
+ OLESTATUS (FAR PASCAL *ObjectLong) (LPVOID, WORD, LPLONG);
+ OLESTATUS (FAR PASCAL *ChangeData) (LPVOID, HANDLE, LPOLECLIENT, BOOL);
+
+} OLEOBJECTVTBL;
+
+typedef OLEOBJECTVTBL FAR *LPOLEOBJECTVTBL;
+
+
+typedef struct _OLEOBJECT { /*object */
+ LPOLEOBJECTVTBL lpvtbl;
+ char objId[2];
+ HOBJECT hobj;
+ LPOLECLIENT lpclient;
+ LONG ctype;
+ LONG cx;
+ LONG cy;
+ LONG mm;
+ int iTable; // Index into the dll table
+ ATOM aObjName; //** Client
+ LHCLIENTDOC lhclientdoc; // Document
+ LPOLEOBJECT lpPrevObj; // related
+ LPOLEOBJECT lpNextObj; //** fileds
+ LPOLEOBJECT lpParent; // NULL for LE or Static objects.
+} OBJECT;
+
+
+
+typedef struct _CF_NAME_ATOM {
+ char * cfName;
+ ATOM cfAtom;
+} CF_NAME_ATOM;
+
+extern CF_NAME_ATOM cfNameAtom[];
+
+
+typedef struct _METADC {
+ int xMwo;
+ int yMwo;
+ int xMwe;
+ int yMwe;
+ int xre;
+ int yre;
+ struct _METADC * pNext;
+} METADC, *PMETADC;
+
+typedef struct _METAINFO {
+ METADC headDc;
+ int xwo;
+ int ywo;
+ int xwe;
+ int ywe;
+ int xro;
+ int yro;
+} METAINFO, *PMETAINFO;
+
+typedef struct OBJECT_MF { /* object_mf */
+ OBJECT head;
+ DWORD sizeBytes;
+ METAFILEPICT mfp;
+ HANDLE hmfp;
+ BOOL fMetaDC;
+ OLESTATUS error;
+ int nRecord;
+ PMETAINFO pMetaInfo;
+ PMETADC pCurMdc;
+} OBJECT_MF;
+
+typedef OBJECT_MF FAR * LPOBJECT_MF;
+
+
+
+typedef struct
+{
+ OBJECT head;
+ DWORD sizeBytes;
+ int xSize; // width in pixels
+ int ySize; // height in pixels
+ HBITMAP hBitmap;
+} OBJECT_BM;
+
+typedef OBJECT_BM FAR * LPOBJECT_BM;
+
+
+
+typedef struct _OBJECT_DIB {
+ OBJECT head;
+ DWORD sizeBytes;
+ int xSize;
+ int ySize;
+ HANDLE hDIB;
+} OBJECT_DIB;
+
+typedef OBJECT_DIB FAR * LPOBJECT_DIB;
+
+
+
+typedef struct
+{
+ OBJECT head;
+ OLECLIPFORMAT cfFormat;
+ ATOM aClass;
+ DWORD sizeBytes;
+ HANDLE hData;
+} OBJECT_GEN;
+
+typedef OBJECT_GEN FAR * LPOBJECT_GEN;
+
+
+
+typedef struct _RENDER_ENTRY { /* dll_entry */
+ LPSTR lpClass;
+ ATOM aClass;
+ OLESTATUS (FARINTERNAL *Load) (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+} RENDER_ENTRY;
+
+
+typedef struct _DLL_ENTRY {
+ ATOM aDll; /* global atom for dll name with full path */
+ HANDLE hDll; /* handle to the dll module */
+ int cObj; /* count of objects, unload dll when this is 0 */
+ OLESTATUS (FAR PASCAL *Load) (LPOLESTREAM, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *Clip) (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+ OLESTATUS (FAR PASCAL *Link) (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *CreateFromTemplate) (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *Create) (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *CreateFromFile) (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+ OLESTATUS (FAR PASCAL *CreateLinkFromFile) (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+ OLESTATUS (FAR PASCAL *CreateInvisible) (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+
+} DLL_ENTRY;
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in OLE.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+BOOL INTERNAL CheckObject(LPOLEOBJECT);
+BOOL FARINTERNAL FarCheckObject(LPOLEOBJECT);
+OLESTATUS INTERNAL LeQueryCreateFromClip (LPSTR, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in DEFCREAT.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FAR PASCAL DefLoadFromStream (LPOLESTREAM, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreateFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+OLESTATUS FAR PASCAL DefCreateLinkFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreateFromTemplate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreateFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreateLinkFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL DefCreateInvisible (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in PBHANDLR.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FAR PASCAL PbLoadFromStream (LPOLESTREAM, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreateFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+OLESTATUS FAR PASCAL PbCreateLinkFromClip (LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreateFromTemplate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreate (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreateFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreateLinkFromFile (LPSTR, LPOLECLIENT, LPSTR, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FAR PASCAL PbCreateInvisible (LPSTR, LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Defines common for le.c, ledde.c, dde.c, doc.c //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+// Constants for chekcing whether the instance is SrvrDLL instance.
+
+#define WW_LPTR 0 // ptr tosrvr/doc/item
+#define WW_LE 4 // signature
+#define WW_HANDLE 6 // instance handle
+
+#define WC_LE 0x4c45 // LE chars
+
+
+// command flags
+#define ACT_SHOW 0x0001 // show the window
+#define ACT_ACTIVATE 0x0002 // activate
+#define ACT_DOVERB 0x0004 // Run the item
+#define ACT_ADVISE 0x0008 // advise for data
+#define ACT_REQUEST 0x0010 // request for data
+#define ACT_CLOSE 0x0020 // request for advise only on close
+#define ACT_UNLAUNCH 0x0040 // unload the server after all the
+#define ACT_TERMSRVR 0x0080 // terminate server
+#define ACT_TERMDOC 0x0100 // terminate document
+
+#define ACT_NATIVE 0x0200 // only for LNKed objects, if we
+ // need native data.
+
+#define ACT_MINIMIZE 0x0400 // launch the app minimized
+
+#define ACT_NOLAUNCH 0x0800 // don't launch the server
+
+
+#define LN_TEMPLATE 0x0000 // create from template
+#define LN_NEW 0x1000 // create new
+#define LN_EMBACT 0x2000 // activate emb
+#define LN_LNKACT 0x3000 // activate link
+#define LN_MASK 0xf000 // launch mask
+#define LN_SHIFT 12 // shift count for LN_MASK
+
+typedef struct _EDIT_DDE { /* edit_dde */
+ HANDLE hInst;
+ int extraTerm;
+ HWND hClient;
+ HWND hServer;
+ BOOL bTerminating;
+ BOOL bAbort;
+ BOOL bCallLater; // used in request cases. if this is FALSE
+ // then OLE_CHANGED is sent to client
+ int awaitAck;
+ HANDLE hopt; // Memory block I may have to free
+ int nAdviseClose; // count of outstanding advises on closes
+ int nAdviseSave; // count of outstanding advises on save
+ HANDLE hData; // Poked data/ temp for holding the
+ // handle in DDE messages
+
+ // busy parameters
+ LONG lParam; // lparam value in case we need to
+ // repost the message
+ WORD msg; // busy repost message
+
+ WORD wTimer; // timer id.
+} EDIT_DDE;
+
+typedef EDIT_DDE NEAR *PEDIT_DDE;
+typedef EDIT_DDE FAR *LPEDIT_DDE;
+
+typedef struct _OBJECT_LE { /* object_le */
+ OBJECT head;
+ ATOM app;
+ ATOM topic;
+ ATOM item;
+ ATOM aServer;
+ BOOL bOldLink; // whether a linked object for old link
+ BOOL bOleServer; // server which supports the verbs
+ WORD verb; // verb nuymber;
+ WORD fCmd; // Command flags;
+ OLEOPT_UPDATE optUpdate;
+ OLEOPT_UPDATE optNew; // new update options
+ LPSTR lptemplate; // ptr to the template string, if
+ // create from template
+
+ ATOM aNetName; // network name on which the doc is
+ char cDrive; // local drive for that network
+ DWORD dwNetInfo; // LOW WORD = Net type
+ // HIGH WORD = Driver version
+
+ LPOLEOBJECT lpobjPict;
+
+ LONG lAppData; // apps data
+ LONG lHandlerData; // handler data
+
+ HANDLE hnative;
+ HANDLE hLink;
+ HANDLE hhostNames; // host name block
+ HANDLE htargetDevice; // target device info
+ HANDLE hdocDimensions; // document dimensions
+ HANDLE hextraData; // reqestdata handle
+ WORD cfExtra; // extra format data
+ HANDLE hlogpal; // logiccal palette
+
+
+ WORD oldasyncCmd; // previous asynchronous command
+ WORD asyncCmd; // asynchronous command
+ BOOL endAsync; // true if we need to send END_RELEASE.
+ BOOL bAsync; // true if async command on.
+ WORD mainRtn; // main async routine
+ WORD subRtn; // step within the main async routine
+ WORD mainErr; // failure error
+ WORD subErr; // step error
+ WORD errHint; // ;error hint
+
+ BOOL bSvrClosing; // TRUE - server in the process of
+ // closing down
+ BOOL bUnlaunchLater; // Call EmbLnkDelete from EndAsyncCmd
+ // if this flag is TRUE
+
+ HANDLE hSysEdit; // handle to system edit.
+ PEDIT_DDE pSysEdit; // near ptr to system edit.
+ HANDLE hDocEdit; // handle to doc level channel
+ PEDIT_DDE pDocEdit; // near ptr to the doc level channel
+
+} OBJECT_LE;
+typedef OBJECT_LE FAR * LPOBJECT_LE;
+
+
+typedef struct _CLIENTDOC { /* object_le */
+ char docId[2];
+ LPOLEOBJECT lpHeadObj;
+ LPOLEOBJECT lpTailObj;
+ ATOM aClass;
+ ATOM aDoc;
+ HANDLE hdoc;
+ struct _CLIENTDOC FAR * lpPrevDoc;
+ struct _CLIENTDOC FAR * lpNextDoc;
+} CLIENTDOC;
+typedef CLIENTDOC FAR * LPCLIENTDOC;
+
+
+typedef struct _HOSTNAMES {
+ WORD clientNameOffset;
+ WORD documentNameOffset;
+ BYTE data[];
+} HOSTNAMES;
+
+typedef HOSTNAMES FAR * LPHOSTNAMES;
+
+typedef struct _BOUNDSRECT {
+ WORD defaultWidth;
+ WORD defaultHeight;
+ WORD maxWidth;
+ WORD maxHeight;
+} BOUNDSRECT;
+
+typedef BOUNDSRECT FAR *LPBOUNDSRECT;
+
+
+// AwaitAck values
+#define AA_REQUEST 1
+#define AA_ADVISE 2
+#define AA_POKE 3
+#define AA_EXECUTE 4
+#define AA_UNADVISE 5
+#define AA_INITIATE 6
+
+// Bits for Positive WM_DDE_ACK
+#define POSITIVE_ACK 0x8000
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in LE.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+LPVOID FARINTERNAL LeQueryProtocol (LPOBJECT_LE, LPSTR);
+OLESTATUS FARINTERNAL LeRelease (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeClone (LPOBJECT_LE, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_LE FAR *);
+OLESTATUS FARINTERNAL LeCopyFromLink (LPOBJECT_LE, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_LE FAR *);
+OLESTATUS FARINTERNAL LeEqual (LPOBJECT_LE, LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeCopy (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeQueryBounds (LPOBJECT_LE, LPRECT);
+OLESTATUS FARINTERNAL LeDraw (LPOBJECT_LE, HDC, LPRECT, LPRECT, HDC);
+OLECLIPFORMAT FARINTERNAL LeEnumFormat (LPOBJECT_LE, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL LeGetData (LPOBJECT_LE, OLECLIPFORMAT, HANDLE FAR *);
+OLESTATUS FARINTERNAL LeRequestData (LPOBJECT_LE, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL LeQueryOutOfDate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeObjectConvert (LPOBJECT_LE, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+OLESTATUS FARINTERNAL LeChangeData (LPOBJECT_LE, HANDLE, LPOLECLIENT, BOOL);
+LPOBJECT_LE FARINTERNAL LeCreateBlank(LHCLIENTDOC, LPSTR, LONG);
+void FARINTERNAL SetExtents (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeSaveToStream (LPOBJECT_LE, LPOLESTREAM);
+OLESTATUS FARINTERNAL LeLoadFromStream (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+OLESTATUS INTERNAL LeStreamRead (LPOLESTREAM, LPOBJECT_LE);
+OLESTATUS INTERNAL LeStreamWrite (LPOLESTREAM, LPOBJECT_LE);
+int FARINTERNAL ContextCallBack (LPVOID, OLE_NOTIFICATION);
+void INTERNAL DeleteObjectAtoms (LPOBJECT_LE);
+void FARINTERNAL DeleteExtraData (LPOBJECT_LE);
+
+OLESTATUS FARINTERNAL LeGetUpdateOptions (LPOBJECT_LE, OLEOPT_UPDATE FAR *);
+OLESTATUS FARINTERNAL LnkPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL EmbPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+BOOL INTERNAL SetLink (LPOBJECT_LE, HANDLE, LPSTR FAR *);
+HANDLE INTERNAL GetLink (LPOBJECT_LE);
+void FARINTERNAL SetEmbeddedTopic (LPOBJECT_LE);
+
+OLESTATUS FAR PASCAL LeQueryReleaseStatus (LPOBJECT_LE);
+OLESTATUS FAR PASCAL LeQueryReleaseError (LPOBJECT_LE);
+OLE_RELEASE_METHOD FAR PASCAL LeQueryReleaseMethod (LPOBJECT_LE);
+
+OLESTATUS FARINTERNAL LeQueryType (LPOBJECT_LE, LPLONG);
+OLESTATUS FARINTERNAL LeObjectLong (LPOBJECT_LE, WORD, LPLONG);
+
+
+void SetNetDrive (LPOBJECT_LE);
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in LEDDE.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FARINTERNAL LeDoVerb (LPOBJECT_LE, WORD, BOOL, BOOL);
+OLESTATUS FARINTERNAL LeShow (LPOBJECT_LE, BOOL);
+OLESTATUS FARINTERNAL LeQueryOpen (LPOBJECT_LE);
+BOOL INTERNAL QueryOpen (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeActivate (LPOBJECT_LE, WORD, BOOL, BOOL, HWND, LPRECT);
+OLESTATUS FARINTERNAL LeUpdate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL EmbOpen (LPOBJECT_LE, BOOL, BOOL, HWND, LPRECT);
+OLESTATUS FARINTERNAL EmbUpdate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL EmbOpenUpdate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LnkOpen (LPOBJECT_LE, BOOL, BOOL, HWND, LPRECT);
+OLESTATUS FARINTERNAL LnkUpdate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LnkOpenUpdate (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeClose (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeReconnect (LPOBJECT_LE);
+OLESTATUS INTERNAL PokeNativeData (LPOBJECT_LE);
+BOOL INTERNAL PostMessageToServer (PEDIT_DDE, WORD, LONG);
+
+OLESTATUS FARINTERNAL LeCreateFromTemplate (LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FARINTERNAL LeCreate (LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT);
+
+OLESTATUS FARINTERNAL LeCreateInvisible (LPOLECLIENT, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+
+OLESTATUS FARINTERNAL CreateFromClassOrTemplate (LPOLECLIENT, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, WORD, LPSTR, LHCLIENTDOC, LPSTR);
+
+OLESTATUS FARINTERNAL CreateEmbLnkFromFile (LPOLECLIENT, LPSTR, LPSTR, LPSTR, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+OLESTATUS FARINTERNAL LeSetUpdateOptions (LPOBJECT_LE, OLEOPT_UPDATE);
+
+void INTERNAL AdvisePict (LPOBJECT_LE, ATOM);
+void INTERNAL UnAdvisePict (LPOBJECT_LE);
+int INTERNAL GetPictType (LPOBJECT_LE);
+void INTERNAL AdviseOn (LPOBJECT_LE, int, ATOM);
+void INTERNAL UnAdviseOn (LPOBJECT_LE, int);
+void INTERNAL RequestOn (LPOBJECT_LE, int);
+void INTERNAL RequestPict (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeSetHostNames (LPOBJECT_LE, LPSTR, LPSTR);
+OLESTATUS INTERNAL PokeHostNames (LPOBJECT_LE);
+OLESTATUS INTERNAL SetHostNamesHandle (LPOBJECT_LE, LPSTR, LPSTR);
+void INTERNAL FreePokeData (LPOBJECT_LE, PEDIT_DDE);
+OLESTATUS INTERNAL SendPokeData (LPOBJECT_LE, ATOM, HANDLE, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL LeSetTargetDevice (LPOBJECT_LE, HANDLE);
+OLESTATUS INTERNAL PokeTargetDeviceInfo (LPOBJECT_LE);
+OLESTATUS INTERNAL PokeDocDimensions (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeSetBounds (LPOBJECT_LE, LPRECT);
+OLESTATUS FARINTERNAL LeSetData (LPOBJECT_LE, OLECLIPFORMAT, HANDLE);
+BOOL INTERNAL SendSrvrMainCmd (LPOBJECT_LE, LPSTR);
+ATOM INTERNAL ExtendAtom (LPOBJECT_LE, ATOM);
+BOOL INTERNAL CreatePictObject (LHCLIENTDOC, LPSTR, LPOBJECT_LE, OLEOPT_RENDER, OLECLIPFORMAT, LPSTR);
+BOOL INTERNAL IsSrvrDLLwnd (HWND, HANDLE);
+OLESTATUS INTERNAL ChangeDocAndItem (LPOBJECT_LE, HANDLE);
+BOOL QueryUnlaunch (LPOBJECT_LE);
+BOOL QueryClose (LPOBJECT_LE);
+OLESTATUS FARINTERNAL LeSetColorScheme (LPOBJECT_LE, LPLOGPALETTE);
+OLESTATUS INTERNAL PokeColorScheme (LPOBJECT_LE);
+OLESTATUS FARINTERNAL ProbeAsync (LPOBJECT_LE);
+BOOL INTERNAL IsServerValid (LPOBJECT_LE);
+BOOL INTERNAL IsWindowValid (HWND);
+OLESTATUS FARINTERNAL LeExecute (LPOBJECT_LE, HANDLE, WORD);
+void INTERNAL FreeGDIdata (HANDLE, OLECLIPFORMAT);
+BOOL INTERNAL CanPutHandleInPokeBlock (LPOBJECT_LE, OLECLIPFORMAT);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in DDE.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+long FARINTERNAL DocWndProc(HWND, unsigned, WORD, LONG );
+long FARINTERNAL SrvrWndProc(HWND, unsigned, WORD, LONG );
+BOOL INTERNAL CheckAtomValid (ATOM);
+void INTERNAL HandleAckInitMsg (PEDIT_DDE, HWND);
+BOOL INTERNAL HandleAck (LPOBJECT_LE, PEDIT_DDE, DWORD);
+void INTERNAL HandleDataMsg (LPOBJECT_LE, HANDLE, ATOM);
+void INTERNAL HandleTermMsg (LPOBJECT_LE, PEDIT_DDE, HWND, BOOL);
+void INTERNAL HandleTimerMsg (LPOBJECT_LE, PEDIT_DDE);
+void INTERNAL SetData (LPOBJECT_LE, HANDLE, int);
+BOOL INTERNAL DeleteBusyData (LPOBJECT_LE, PEDIT_DDE);
+void INTERNAL DeleteAbortData (LPOBJECT_LE, PEDIT_DDE);
+
+BOOL INTERNAL WaitDDE (HWND, BOOL);
+BOOL INTERNAL WaitDDEAck (PEDIT_DDE);
+
+BOOL INTERNAL InitSrvrConv (LPOBJECT_LE, HANDLE);
+void INTERNAL TermSrvrConv (LPOBJECT_LE);
+void INTERNAL DeleteSrvrEdit (LPOBJECT_LE);
+BOOL INTERNAL SrvrExecute (LPOBJECT_LE, HANDLE);
+void INTERNAL SendStdExit (LPOBJECT_LE);
+void INTERNAL SendStdClose (LPOBJECT_LE);
+void INTERNAL SendStdExit (LPOBJECT_LE);
+
+BOOL FARINTERNAL InitDocConv (LPOBJECT_LE, BOOL);
+BOOL INTERNAL DocExecute (LPOBJECT_LE, HANDLE);
+void INTERNAL TermDocConv (LPOBJECT_LE);
+void INTERNAL DeleteDocEdit (LPOBJECT_LE);
+
+HANDLE INTERNAL LeLaunchApp (LPOBJECT_LE);
+HANDLE INTERNAL LoadApp (LPSTR, WORD);
+
+int INTERNAL ScanItemOptions (ATOM, int FAR *);
+void INTERNAL ChangeDocName (LPOBJECT_LE, LPSTR);
+BOOL INTERNAL CanCallback (LPOBJECT_LE, int);
+
+void FARINTERNAL CallEmbLnkDelete (LPOBJECT_LE);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Picture Object routines used by routines in other modules //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+LPOBJECT_BM FARINTERNAL BmCreateBlank (LHCLIENTDOC, LPSTR, LONG);
+OLESTATUS FARINTERNAL BmLoadFromStream (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+OLESTATUS FARINTERNAL BmPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+
+
+LPOBJECT_DIB FARINTERNAL DibCreateBlank (LHCLIENTDOC, LPSTR, LONG);
+LPOBJECT_DIB FARINTERNAL DibCreateObject (HANDLE, LPOLECLIENT, BOOL, LHCLIENTDOC, LPSTR, LONG);
+OLESTATUS FARINTERNAL DibLoadFromStream (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+OLESTATUS FARINTERNAL DibPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+
+
+LPOBJECT_MF FARINTERNAL MfCreateBlank (LHCLIENTDOC, LPSTR, LONG);
+LPOBJECT_MF FARINTERNAL MfCreateObject (HANDLE, LPOLECLIENT, BOOL, LHCLIENTDOC, LPSTR, LONG);
+
+OLESTATUS FARINTERNAL MfLoadFromStream (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+OLESTATUS FARINTERNAL MfPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG);
+
+
+LPOBJECT_GEN FARINTERNAL GenCreateBlank (LHCLIENTDOC, LPSTR, LONG, ATOM);
+OLESTATUS FARINTERNAL GenLoadFromStream (LPOLESTREAM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LONG, ATOM, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL GenPaste (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, LPSTR, OLECLIPFORMAT, LONG);
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in MAIN.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+void FARINTERNAL UnloadDll (void);
+int FARINTERNAL LoadDll (LPSTR);
+void FARINTERNAL DecreaseHandlerObjCount (int);
+
+void FARINTERNAL RemoveLinkStringFromTopic (LPOBJECT_LE);
+
+OLESTATUS FARINTERNAL CreatePictFromClip (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LPSTR, LONG);
+
+OLESTATUS FARINTERNAL CreatePackageFromClip (LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *, OLEOPT_RENDER, OLECLIPFORMAT, LONG);
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in UTILS.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+BOOL PutStrWithLen (LPOLESTREAM, LPSTR);
+BOOL GetStrWithLen (LPOLESTREAM, LPSTR);
+ATOM GetAtomFromStream (LPOLESTREAM);
+BOOL PutAtomIntoStream (LPOLESTREAM, ATOM);
+BOOL GetBytes (LPOLESTREAM, LPSTR, LONG);
+BOOL PutBytes (LPOLESTREAM, LPSTR, LONG);
+BOOL QueryApp (LPSTR, LPSTR, LPSTR);
+HANDLE MapStrToH (LPSTR);
+void UtilMemClr (PSTR, WORD);
+BOOL QueryHandler (WORD);
+
+OLESTATUS INTERNAL FileExists (LPOBJECT_LE);
+ATOM FARINTERNAL GetAppAtom (LPSTR);
+HANDLE FARINTERNAL DuplicateGlobal (HANDLE, WORD);
+HANDLE FARINTERNAL CopyData (LPSTR, DWORD);
+ATOM FARINTERNAL DuplicateAtom (ATOM);
+BOOL FARINTERNAL UtilQueryProtocol (LPOBJECT_LE, LPSTR);
+BOOL FARINTERNAL CmpGlobals (HANDLE, HANDLE);
+void FARINTERNAL ConvertToHimetric(LPPOINT);
+BOOL FARINTERNAL QueryVerb (LPOBJECT_LE, WORD, LPSTR, LONG);
+BOOL FARINTERNAL MapExtToClass (LPSTR, LPSTR, int);
+int FARINTERNAL GlobalGetAtomLen (ATOM);
+void FARINTERNAL UtilMemCpy (LPSTR, LPSTR, DWORD);
+BOOL FARINTERNAL UtilMemCmp (LPSTR, LPSTR, DWORD);
+BOOL FARINTERNAL IsObjectBlank (LPOBJECT_LE);
+
+OLESTATUS FARINTERNAL ObjQueryName (LPOLEOBJECT, LPSTR, WORD FAR *);
+OLESTATUS FARINTERNAL ObjRename (LPOLEOBJECT, LPSTR);
+void INTERNAL SetExeAtom (LPOBJECT_LE);
+
+
+// !!!make a routine and let the macro call the routine
+// definitions related to the asynchronous operations.
+#define WAIT_FOR_ASYNC_MSG(lpobj) { \
+ lpobj->subRtn++; \
+ if (lpobj->bAsync){ \
+ lpobj->endAsync = TRUE; \
+ return OLE_WAIT_FOR_RELEASE; \
+ } \
+}
+
+#define STEP_NOP(lpobj) lpobj->subRtn++;
+
+// !!! Assumes all the creates are in order
+#define PROBE_CREATE_ASYNC(lpobj) \
+ if (lpobj->asyncCmd >= OLE_CREATE && \
+ lpobj->asyncCmd <= OLE_CREATEINVISIBLE) {\
+ if(ProbeAsync(lpobj) == OLE_BUSY)\
+ return OLE_BUSY;\
+ }
+
+#define PROBE_OBJECT_BLANK(lpobj) \
+ if (lpobj->asyncCmd >= OLE_CREATE && \
+ lpobj->asyncCmd <= OLE_CREATEFROMFILE) { \
+ if ((ProbeAsync(lpobj) == OLE_BUSY) && IsObjectBlank(lpobj)) \
+ return OLE_ERROR_BLANK;\
+ }
+
+#define PROBE_ASYNC(lpobj)\
+ if(ProbeAsync(lpobj) == OLE_BUSY)\
+ return OLE_BUSY;
+
+#define IS_SVRCLOSING(lpobj)\
+ ((lpobj->bUnlaunchLater || lpobj->bSvrClosing) ? TRUE : FALSE)
+
+#define PROBE_SVRCLOSING(lpobj)\
+ if (IS_SVRCLOSING(lpobj)) \
+ return OLE_ERROR_NOT_OPEN; \
+
+
+#define CLEAR_STEP_ERROR(lpobj) lpobj->subErr = OLE_OK;
+
+
+#define SKIP_TO(a, b) if (a) goto b;
+#define RESETERR(lpobj) lpobj->mainErr = OLE_OK
+#define SETSTEP(lpobj, no) lpobj->subRtn = no
+#define SETERRHINT(lpobj, no) lpobj->errHint = no
+#define CLEARASYNCCMD(lpobj) lpobj->asyncCmd = OLE_NONE
+
+// routines.
+BOOL ProcessErr (LPOBJECT_LE);
+void InitAsyncCmd (LPOBJECT_LE, WORD, WORD);
+void NextAsyncCmd (LPOBJECT_LE, WORD);
+void ScheduleAsyncCmd (LPOBJECT_LE);
+OLESTATUS EndAsyncCmd (LPOBJECT_LE);
+OLESTATUS DocShow (LPOBJECT_LE);
+OLESTATUS DocRun (LPOBJECT_LE);
+void SendStdShow (LPOBJECT_LE);
+OLESTATUS EmbLnkClose (LPOBJECT_LE);
+OLESTATUS LnkSetUpdateOptions (LPOBJECT_LE);
+OLESTATUS EmbSrvrUnlaunch (LPOBJECT_LE);
+OLESTATUS LnkChangeLnk (LPOBJECT_LE);
+OLESTATUS RequestData (LPOBJECT_LE, OLECLIPFORMAT);
+
+OLESTATUS FARINTERNAL EmbLnkDelete(LPOBJECT_LE);
+
+void FARINTERNAL FarInitAsyncCmd(LPOBJECT_LE, WORD, WORD);
+
+// async command routines.
+#define EMBLNKDELETE 1
+#define LNKOPENUPDATE 2
+#define DOCSHOW 3
+#define EMBOPENUPDATE 4
+#define EMBLNKCLOSE 5
+#define LNKSETUPDATEOPTIONS 6
+#define LNKCHANGELNK 7
+#define REQUESTDATA 8
+#define DOCRUN 9
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in DOC.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+BOOL FARINTERNAL CheckClientDoc (LPCLIENTDOC);
+void FARINTERNAL DocAddObject (LPCLIENTDOC, LPOLEOBJECT, LPSTR);
+void FARINTERNAL DocDeleteObject (LPOLEOBJECT);
+LPOLEOBJECT INTERNAL DocGetNextObject (LPCLIENTDOC, LPOLEOBJECT);
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in NET.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+#define IDD_DRIVE 500
+#define IDD_PASSWORD 501
+#define IDD_PATH 502
+
+#define IDS_NETERR 600
+#define IDS_NETCONERRMSG 601
+#define IDS_FILENOTFOUNDMSG 602
+#define IDS_BADPATHMSG 603
+
+OLESTATUS FARINTERNAL SetNetName (LPOBJECT_LE);
+BOOL FARINTERNAL SetNextNetDrive (LPOBJECT_LE, int FAR *, LPSTR);
+OLESTATUS FARINTERNAL CheckNetDrive (LPOBJECT_LE, BOOL);
+OLESTATUS INTERNAL FixNet (LPOBJECT_LE, LPSTR, BOOL);
+OLESTATUS INTERNAL ConnectNet (LPOBJECT_LE, LPSTR);
+BOOL FARINTERNAL ChangeTopic (LPOBJECT_LE);
+VOID INTERNAL FillDrives (HWND);
+int FAR PASCAL ConnectDlgProc(HWND, WORD, WORD, DWORD);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in OLE.ASM //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+WORD GetGDIds (DWORD);
+WORD IsMetaDC (HDC, WORD);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in ERROR.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL ObjQueryType (LPOLEOBJECT, LPLONG);
+OLESTATUS FARINTERNAL ObjQuerySize (LPOLEOBJECT, DWORD FAR *);
+DWORD PASCAL FAR DllPut (LPOLESTREAM, LPSTR, DWORD);
+HANDLE FARINTERNAL DuplicateGDIdata (HANDLE, OLECLIPFORMAT);
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in BM.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+HBITMAP FARINTERNAL BmDuplicate (HBITMAP, DWORD FAR *, LPBITMAP);
diff --git a/private/mvdm/wow16/ole/client/doc.c b/private/mvdm/wow16/ole/client/doc.c
new file mode 100644
index 000000000..c4ae63c02
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/doc.c
@@ -0,0 +1,316 @@
+/****************************** Module Header ******************************\
+* Module Name: doc.c
+*
+* PURPOSE: Contains client document maipulation routines.
+*
+* Created: Jan 1991
+*
+* Copyright (c) 1991 Microsoft Corporation
+*
+* History:
+* Srinik 01/11/1191 Orginal
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+
+#ifdef FIREWALLS
+extern BOOL bShowed;
+extern void FARINTERNAL ShowVersion (void);
+#endif
+
+LPCLIENTDOC lpHeadDoc = NULL;
+LPCLIENTDOC lpTailDoc = NULL;
+
+extern ATOM aClipDoc;
+extern int iUnloadableDll;
+
+#pragma alloc_text(_TEXT, CheckClientDoc, CheckPointer)
+
+
+OLESTATUS FAR PASCAL OleRegisterClientDoc (lpClassName, lpDocName, future, lplhclientdoc)
+LPSTR lpClassName;
+LPSTR lpDocName;
+LONG future;
+LHCLIENTDOC FAR * lplhclientdoc;
+{
+ HANDLE hdoc = NULL;
+ LPCLIENTDOC lpdoc;
+ OLESTATUS retVal;
+ ATOM aClass, aDoc;
+
+
+#ifdef FIREWALLS
+ if (!bShowed && (ole_flags & DEBUG_MESSAGEBOX))
+ ShowVersion ();
+#endif
+
+ Puts ("OleRegisterClientDoc");
+
+ PROBE_MODE(bProtMode);
+ FARPROBE_WRITE(lplhclientdoc);
+ *lplhclientdoc = NULL;
+ FARPROBE_READ(lpClassName);
+ FARPROBE_READ(lpDocName);
+ if (!lpDocName[0])
+ return OLE_ERROR_NAME;
+
+ aDoc = GlobalAddAtom (lpDocName);
+ aClass = GlobalAddAtom (lpClassName);
+
+ if (!(hdoc = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE,
+ sizeof(CLIENTDOC)))
+ || !(lpdoc = (LPCLIENTDOC) GlobalLock (hdoc))) {
+ retVal = OLE_ERROR_MEMORY;
+ goto err;
+ }
+
+ lpdoc->docId[0] = 'C';
+ lpdoc->docId[1] = 'D';
+ lpdoc->aClass = aClass;
+ lpdoc->aDoc = aDoc;
+ lpdoc->hdoc = hdoc;
+
+ // Documents are doubly linked
+
+ if (!lpHeadDoc) {
+#ifdef FIREWALLS
+ ASSERT(!lpTailDoc, "lpTailDoc is not NULL");
+#endif
+ lpHeadDoc = lpTailDoc = lpdoc;
+ }
+ else {
+ lpTailDoc->lpNextDoc = lpdoc;
+ lpdoc->lpPrevDoc = lpTailDoc;
+ lpTailDoc = lpdoc;
+ }
+
+ *lplhclientdoc = (LHCLIENTDOC) lpdoc;
+
+ // inform the link manager;
+ return OLE_OK;
+
+err:
+ if (aClass)
+ GlobalDeleteAtom (aClass);
+
+ if (aDoc)
+ GlobalDeleteAtom (aDoc);
+
+ if (hdoc)
+ GlobalFree (hdoc);
+
+ return retVal;
+}
+
+
+OLESTATUS FAR PASCAL OleRevokeClientDoc (lhclientdoc)
+LHCLIENTDOC lhclientdoc;
+{
+ LPCLIENTDOC lpdoc;
+
+ Puts ("OleRevokeClientDoc");
+
+ // if there is any handler dll that can be freed up, free it now.
+ // Otherwise it might become too late if the app quits.
+ if (iUnloadableDll)
+ UnloadDll ();
+
+ if (!CheckClientDoc (lpdoc = (LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (lpdoc->lpHeadObj) {
+ ASSERT (0, "OleRevokeClientDoc() called without freeing all objects");
+ return OLE_ERROR_NOT_EMPTY;
+ }
+
+ if (lpdoc->aClass)
+ GlobalDeleteAtom (lpdoc->aClass);
+
+ if (lpdoc->aDoc)
+ GlobalDeleteAtom (lpdoc->aDoc);
+
+ // if only one doc is in the list then it's prev and next docs are NULL
+
+ if (lpdoc == lpHeadDoc)
+ lpHeadDoc = lpdoc->lpNextDoc;
+
+ if (lpdoc == lpTailDoc)
+ lpTailDoc = lpdoc->lpPrevDoc;
+
+ if (lpdoc->lpPrevDoc)
+ lpdoc->lpPrevDoc->lpNextDoc = lpdoc->lpNextDoc;
+
+ if (lpdoc->lpNextDoc)
+ lpdoc->lpNextDoc->lpPrevDoc = lpdoc->lpPrevDoc;
+
+ GlobalUnlock (lpdoc->hdoc);
+ GlobalFree (lpdoc->hdoc);
+
+ // inform link manager
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL OleRenameClientDoc (lhclientdoc, lpNewDocName)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpNewDocName;
+{
+ LPCLIENTDOC lpdoc;
+ ATOM aNewDoc;
+ LPOLEOBJECT lpobj = NULL;
+
+ if (!CheckClientDoc (lpdoc = (LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ FARPROBE_READ(lpNewDocName);
+
+ aNewDoc = GlobalAddAtom (lpNewDocName);
+ if (aNewDoc == lpdoc->aDoc) {
+ if (aNewDoc)
+ GlobalDeleteAtom (aNewDoc);
+ return OLE_OK;
+ }
+
+ // Document name has changed. So, change the topic of all embedded objects
+ if (lpdoc->aDoc)
+ GlobalDeleteAtom (lpdoc->aDoc);
+ lpdoc->aDoc = aNewDoc;
+
+ while (lpobj = DocGetNextObject (lpdoc, lpobj)) {
+ if (lpobj->ctype == CT_EMBEDDED)
+ if (OleQueryReleaseStatus (lpobj) != OLE_BUSY)
+ SetEmbeddedTopic ((LPOBJECT_LE) lpobj);
+ }
+
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL OleRevertClientDoc (lhclientdoc)
+LHCLIENTDOC lhclientdoc;
+{
+ // if there is any handler dll that can be freed up, free it now.
+ // Otherwise it might become too late if the app quits.
+ if (iUnloadableDll)
+ UnloadDll ();
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL OleSavedClientDoc (lhclientdoc)
+LHCLIENTDOC lhclientdoc;
+{
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ return OLE_OK;
+}
+
+OLESTATUS FAR PASCAL OleEnumObjects (lhclientdoc, lplpobj)
+LHCLIENTDOC lhclientdoc;
+LPOLEOBJECT FAR * lplpobj;
+{
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ FARPROBE_WRITE(lplpobj);
+
+ if (*lplpobj) {
+ // we are making lhclientdoc field of the object NULL at deletion
+ // time. The check (*lpobj->lhclientdoc != lhclientdoc) will take care
+ // of the case where same chunk of memory is allocated again for the
+ // same pointer and old contents are not erased yet.
+ if (!FarCheckObject (*lplpobj)
+ || ((*lplpobj)->lhclientdoc != lhclientdoc))
+ return OLE_ERROR_OBJECT;
+ }
+
+ *lplpobj = DocGetNextObject ((LPCLIENTDOC) lhclientdoc, *lplpobj);
+ return OLE_OK;
+}
+
+
+
+LPOLEOBJECT INTERNAL DocGetNextObject (lpdoc, lpobj)
+LPCLIENTDOC lpdoc;
+LPOLEOBJECT lpobj;
+{
+ if (!lpobj)
+ return lpdoc->lpHeadObj;
+
+ return lpobj->lpNextObj;
+}
+
+
+BOOL FARINTERNAL CheckClientDoc (lpdoc)
+LPCLIENTDOC lpdoc;
+{
+ if (!CheckPointer(lpdoc, WRITE_ACCESS))
+ return FALSE;
+
+ if ((lpdoc->docId[0] == 'C') && (lpdoc->docId[1] == 'D'))
+ return TRUE;
+ return FALSE;
+}
+
+
+void FARINTERNAL DocAddObject (lpdoc, lpobj, lpobjname)
+LPCLIENTDOC lpdoc;
+LPOLEOBJECT lpobj;
+LPSTR lpobjname;
+{
+ if (lpobjname)
+ lpobj->aObjName = GlobalAddAtom (lpobjname);
+ else
+ lpobj->aObjName = NULL;
+
+ // Objects of a doc are doubly linked
+
+ if (!lpdoc->lpHeadObj)
+ lpdoc->lpHeadObj = lpdoc->lpTailObj = lpobj;
+ else {
+ lpdoc->lpTailObj->lpNextObj = lpobj;
+ lpobj->lpPrevObj = lpdoc->lpTailObj;
+ lpdoc->lpTailObj = lpobj;
+ }
+ lpobj->lhclientdoc = (LHCLIENTDOC)lpdoc;
+}
+
+
+void FARINTERNAL DocDeleteObject (lpobj)
+LPOLEOBJECT lpobj;
+{
+ LPCLIENTDOC lpdoc;
+
+ if (!(lpdoc = (LPCLIENTDOC) lpobj->lhclientdoc))
+ return;
+
+ if (lpobj->aObjName) {
+ GlobalDeleteAtom (lpobj->aObjName);
+ lpobj->aObjName = NULL;
+ }
+
+ // Remove this obj from object chain of the relevant client doc.
+ // The objects of a doc are doubly linked.
+
+ if (lpdoc->lpHeadObj == lpobj)
+ lpdoc->lpHeadObj = lpobj->lpNextObj;
+
+ if (lpdoc->lpTailObj == lpobj)
+ lpdoc->lpTailObj = lpobj->lpPrevObj;
+
+ if (lpobj->lpPrevObj)
+ lpobj->lpPrevObj->lpNextObj = lpobj->lpNextObj;
+
+ if (lpobj->lpNextObj)
+ lpobj->lpNextObj->lpPrevObj = lpobj->lpPrevObj;
+
+ lpobj->lhclientdoc = NULL;
+}
+
diff --git a/private/mvdm/wow16/ole/client/draw.c b/private/mvdm/wow16/ole/client/draw.c
new file mode 100644
index 000000000..aee6e28b4
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/draw.c
@@ -0,0 +1,1023 @@
+/****************************** Module Header ******************************\
+* Module Name: DRAW.C
+*
+* PURPOSE: Contains all the drawing related routines
+*
+* Created: March 1991
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* (03/21/91) Srinik Original
+* (03/22/91) Srinik Added support for drawing metafile in a metafile
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+#define RECORD_COUNT 16
+
+int INTERNAL PaletteSize (int);
+HANDLE INTERNAL DibMakeLogPalette(LPSTR, WORD, LPLOGPALETTE FAR *);
+OLESTATUS FARINTERNAL wDibDraw (HANDLE, HDC, LPRECT, LPRECT, HDC, BOOL);
+OLESTATUS INTERNAL wDrawBitmap (LPOBJECT_BM, HDC, HDC, LPRECT);
+OLESTATUS INTERNAL wDrawBitmapUsingDib (LPOBJECT_BM, HDC, HDC, HDC, LPRECT, LPRECT);
+
+void SetPictOrg (LPOBJECT_MF, HDC, int, int, BOOL);
+void SetPictExt (LPOBJECT_MF, HDC, int, int);
+void ScalePictExt (LPOBJECT_MF, HDC, int, int, int, int);
+void ScaleRectExt (LPOBJECT_MF, HDC, int, int, int, int);
+
+void CleanStack(LPOBJECT_MF, HANDLE);
+BOOL PopDc (LPOBJECT_MF);
+BOOL PushDc (LPOBJECT_MF);
+
+#ifdef META_DEBUG
+void PutMetaFuncName (WORD);
+#endif
+
+OLESTATUS FARINTERNAL BmDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOBJECT_BM lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ HDC hMemDC, hScreenDC;
+ int iScreenDevCaps;
+ OLESTATUS ret = OLE_OK;
+
+ if (!lpobj->hBitmap)
+ return OLE_ERROR_BLANK;
+
+ hScreenDC = GetDC (NULL);
+
+ iScreenDevCaps = GetDeviceCaps (hScreenDC, TECHNOLOGY);
+ if (!OleIsDcMeta (hdc)
+ && (iScreenDevCaps != GetDeviceCaps (hdc, TECHNOLOGY))) {
+ ret = wDrawBitmapUsingDib (lpobj, hdc, hScreenDC,
+ hdcTarget, lprc, lpWrc);
+ }
+ else {
+ hMemDC = CreateCompatibleDC (hdc);
+ ret = wDrawBitmap (lpobj, hdc, hMemDC, lprc);
+ DeleteDC (hMemDC);
+ }
+
+ ReleaseDC (NULL, hScreenDC);
+ return ret;
+}
+
+
+OLESTATUS INTERNAL wDrawBitmap (lpobj, hdc, hMemDC, lprc)
+LPOBJECT_BM lpobj;
+HDC hdc;
+HDC hMemDC;
+LPRECT lprc;
+{
+ HBITMAP hOldBitmap;
+ OLESTATUS ret = OLE_OK;
+
+ if (!hMemDC)
+ return OLE_ERROR_MEMORY;
+
+ if (!(hOldBitmap = SelectObject(hMemDC, lpobj->hBitmap)))
+ return OLE_ERROR_DRAW;
+
+ if (!StretchBlt(hdc,
+ lprc->left, lprc->top,
+ (lprc->right - lprc->left), (lprc->bottom - lprc->top),
+ hMemDC, 0, 0, lpobj->xSize, lpobj->ySize, SRCCOPY)) {
+ ret = OLE_ERROR_DRAW;
+ }
+
+ SelectObject (hMemDC, hOldBitmap);
+ return ret;
+}
+
+
+OLESTATUS INTERNAL wDrawBitmapUsingDib (
+LPOBJECT_BM lpobj,
+HDC hdc,
+HDC hScreenDC,
+HDC hTargetDC,
+LPRECT lprc,
+LPRECT lpWrc)
+{
+ BITMAP bm;
+ LPBITMAPINFOHEADER lpBmi;
+ HANDLE hBmi, hDib = NULL;
+ WORD wBmiSize;
+ OLESTATUS retVal = OLE_ERROR_MEMORY;
+
+ if (!GetObject(lpobj->hBitmap, sizeof(BITMAP), (LPSTR) &bm))
+ return OLE_ERROR_HANDLE;
+
+ wBmiSize = sizeof(BITMAPINFOHEADER)
+ + PaletteSize(bm.bmPlanes * bm.bmBitsPixel);
+
+ if (!(hBmi = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT, (DWORD) wBmiSize)))
+ return OLE_ERROR_MEMORY;
+
+ if (!(lpBmi = (LPBITMAPINFOHEADER) GlobalLock (hBmi))) {
+ GlobalFree (hBmi);
+ return OLE_ERROR_MEMORY;
+ }
+
+ GlobalUnlock (hBmi);
+
+ lpBmi->biSize = (LONG) sizeof(BITMAPINFOHEADER);
+ lpBmi->biWidth = (LONG) bm.bmWidth;
+ lpBmi->biHeight = (LONG) bm.bmHeight;
+ lpBmi->biPlanes = 1;
+ lpBmi->biBitCount = bm.bmPlanes * bm.bmBitsPixel;
+ lpBmi->biCompression = BI_RGB;
+ lpBmi->biSizeImage = 0L;
+ lpBmi->biXPelsPerMeter = 0L;
+ lpBmi->biYPelsPerMeter = 0L;
+ lpBmi->biClrUsed = 0L;
+ lpBmi->biClrImportant = 0L;
+
+ // Call GetDIBits with a NULL lpBits parm, so that it will calculate
+ // the biSizeImage field for us
+ if (!GetDIBits(hScreenDC, lpobj->hBitmap, 0, bm.bmHeight, NULL,
+ (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS))
+ return OLE_ERROR_HANDLE;
+
+ // Realloc the buffer to provide space for the bits
+ if (!(hDib = GlobalReAlloc (hBmi, (wBmiSize + lpBmi->biSizeImage),
+ GMEM_MOVEABLE))) {
+ GlobalFree (hBmi);
+ return OLE_ERROR_MEMORY;
+ }
+
+ // If reallocation gave a new handle then lock that handle and get the
+ // long pointer to it.
+ if (hDib != hBmi) {
+ if (!(lpBmi = (LPBITMAPINFOHEADER) GlobalLock (hDib)))
+ goto errRtn;
+ GlobalUnlock (hDib);
+ }
+
+ // Call GetDIBits with a NON-NULL lpBits parm, and get the actual bits
+
+ if (!GetDIBits(hScreenDC, lpobj->hBitmap, 0, (WORD) lpBmi->biHeight,
+ ((LPSTR)lpBmi)+wBmiSize,
+ (LPBITMAPINFO) lpBmi,
+ DIB_RGB_COLORS)) {
+ retVal = OLE_ERROR_HANDLE;
+ goto errRtn;
+ }
+
+ retVal = wDibDraw (hDib, hdc, lprc, lpWrc, hTargetDC, FALSE);
+
+errRtn:
+ if (hDib)
+ GlobalFree (hDib);
+ return retVal;
+}
+
+
+OLESTATUS FARINTERNAL DibDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOBJECT_DIB lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ return wDibDraw (lpobj->hDIB, hdc, lprc, lpWrc, hdcTarget, FALSE);
+}
+
+
+
+OLESTATUS FARINTERNAL wDibDraw (hData, hdc, lprc, lpWrc, hdcTarget, bPbrushData)
+HANDLE hData;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+BOOL bPbrushData;
+{
+ // !!! current implementation is not using hdcTarget
+ OLESTATUS ret = OLE_ERROR_DRAW;
+ LPSTR lpData;
+ HANDLE hPalette = NULL;
+ HPALETTE hLogPalette = NULL, hOldPalette = NULL;
+ LPLOGPALETTE lpLogPalette;
+ WORD wPalSize;
+ int iOffBits;
+
+ if (!hData)
+ return OLE_ERROR_BLANK;
+
+ if (!(lpData = GlobalLock (hData)))
+ return OLE_ERROR_MEMORY;
+
+ if (bPbrushData)
+ lpData += sizeof(BITMAPFILEHEADER);
+
+ wPalSize = PaletteSize (((LPBITMAPINFOHEADER)lpData)->biBitCount);
+ iOffBits = sizeof(BITMAPINFOHEADER) + wPalSize;
+
+ // if color palette exits do the following
+ if (wPalSize) {
+ if (!(hLogPalette = DibMakeLogPalette(lpData+sizeof(BITMAPINFOHEADER),
+ wPalSize, &lpLogPalette))) {
+ ret = OLE_ERROR_MEMORY;
+ goto end;
+ }
+
+ if (!(hPalette = CreatePalette (lpLogPalette)))
+ goto end;
+
+ // select as a background palette
+ if (!(hOldPalette = SelectPalette (hdc, hPalette, TRUE)))
+ goto end;
+
+ RealizePalette(hdc);
+ }
+
+ if (!StretchDIBits(hdc,
+ lprc->left, lprc->top,
+ (lprc->right - lprc->left), (lprc->bottom - lprc->top),
+ 0, 0,
+ (WORD) ((LPBITMAPINFOHEADER)lpData)->biWidth,
+ (WORD) ((LPBITMAPINFOHEADER)lpData)->biHeight,
+ lpData + iOffBits,
+ ((LPBITMAPINFO) lpData),
+ DIB_RGB_COLORS,
+ SRCCOPY)) {
+ ret = OLE_ERROR_DRAW;
+ }
+ else
+ ret = OLE_OK;
+
+end:
+ // if color palette exists do the following
+ if (wPalSize) {
+ hOldPalette = (OleIsDcMeta (hdc) ? GetStockObject(DEFAULT_PALETTE)
+ : hOldPalette);
+ if (hOldPalette) {
+ // select as a background palette
+ SelectPalette (hdc, hOldPalette, TRUE);
+ RealizePalette (hdc);
+ }
+
+ if (hPalette)
+ DeleteObject (hPalette);
+
+ if (hLogPalette)
+ GlobalFree (hLogPalette);
+ }
+
+ GlobalUnlock (hData);
+ return ret;
+}
+
+
+
+
+
+HANDLE INTERNAL DibMakeLogPalette (lpColorData, wDataSize, lplpLogPalette)
+LPSTR lpColorData;
+WORD wDataSize;
+LPLOGPALETTE FAR * lplpLogPalette;
+{
+ HANDLE hLogPalette=NULL;
+ LPLOGPALETTE lpLogPalette;
+ DWORD dwLogPalSize = wDataSize + 2 * sizeof(WORD);
+ LPPALETTEENTRY lpPE;
+ RGBQUAD FAR * lpQuad;
+
+ if (!(hLogPalette = GlobalAlloc(GMEM_MOVEABLE,dwLogPalSize)))
+ return NULL;
+
+ if (!(lpLogPalette = (LPLOGPALETTE) GlobalLock (hLogPalette))) {
+ GlobalFree (hLogPalette);
+ return NULL;
+ }
+
+ GlobalUnlock (hLogPalette);
+ *lplpLogPalette = lpLogPalette;
+
+ lpLogPalette->palVersion = 0x300;
+ lpLogPalette->palNumEntries = wDataSize / sizeof(PALETTEENTRY);
+
+ /* now convert RGBQUAD to PALETTEENTRY as we copy color info */
+ for (lpQuad = (RGBQUAD far *)lpColorData,
+ lpPE = (LPPALETTEENTRY)lpLogPalette->palPalEntry,
+ wDataSize /= sizeof(RGBQUAD);
+ wDataSize--;
+ ++lpQuad,++lpPE) {
+ lpPE->peFlags=0;
+ lpPE->peRed = lpQuad->rgbRed;
+ lpPE->peBlue = lpQuad->rgbBlue;
+ lpPE->peGreen = lpQuad->rgbGreen;
+ }
+
+ return hLogPalette;
+}
+
+
+int INTERNAL PaletteSize (int iBitCount)
+{
+ switch (iBitCount) {
+ case 1:
+ return (2*sizeof(RGBQUAD));
+
+ case 4:
+ return (16*sizeof(RGBQUAD));
+
+ case 8:
+ return (256*sizeof(RGBQUAD));
+
+ default:
+ return 0; /* A 24 bitcount DIB has no color table */
+ }
+}
+
+
+OLESTATUS FARINTERNAL GenDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOBJECT_GEN lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ return OLE_ERROR_GENERIC;
+}
+
+
+
+
+
+
+
+//*** All the following routines are relevant for metafile drawing only
+
+
+OLESTATUS FARINTERNAL MfDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOBJECT_MF lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ HANDLE hInfo;
+ int iOldDc;
+ RECT rect;
+ LPRECT lpRrc = (LPRECT) &rect;
+
+ rect.left = lprc->left;
+ rect.right = lprc->right;
+ rect.top = lprc->top;
+ rect.bottom = lprc->bottom;
+
+ if (!lpobj->mfp.hMF)
+ return OLE_ERROR_BLANK;
+
+ lpobj->nRecord = RECORD_COUNT;
+ lpobj->fMetaDC = OleIsDcMeta (hdc);
+
+ if (!(iOldDc = SaveDC (hdc)))
+ return OLE_ERROR_MEMORY;
+
+ IntersectClipRect (hdc, lpRrc->left, lpRrc->top,
+ lpRrc->right, lpRrc->bottom);
+
+ if (!lpobj->fMetaDC) {
+ LPtoDP (hdc, (LPPOINT) lpRrc, 2);
+ SetMapMode (hdc, MM_ANISOTROPIC);
+ SetViewportOrg (hdc, lpRrc->left, lpRrc->top);
+ SetViewportExt (hdc, lpRrc->right - lpRrc->left,
+ lpRrc->bottom - lpRrc->top);
+ }
+ else {
+
+ iOldDc = -1;
+
+ if (!lpWrc) {
+#ifdef FIREWALLS
+ ASSERT(0, "Pointer to rect is null")
+#endif
+ return OLE_ERROR_DRAW;
+ }
+
+ if (!(hInfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT,
+ sizeof(METAINFO))))
+ return OLE_ERROR_MEMORY;
+
+ if (!(lpobj->pMetaInfo = (PMETAINFO) LocalLock (hInfo))) {
+ LocalFree (hInfo);
+ return OLE_ERROR_MEMORY;
+ }
+
+ LocalUnlock (hInfo);
+
+ lpobj->pCurMdc = (PMETADC) (lpobj->pMetaInfo);
+
+ lpobj->pMetaInfo->xwo = lpWrc->left;
+ lpobj->pMetaInfo->ywo = lpWrc->top;
+ lpobj->pMetaInfo->xwe = lpWrc->right;
+ lpobj->pMetaInfo->ywe = lpWrc->bottom;
+
+ lpobj->pMetaInfo->xro = lpRrc->left - lpWrc->left;
+ lpobj->pMetaInfo->yro = lpRrc->top - lpWrc->top;
+
+ lpobj->pCurMdc->xre = lpRrc->right - lpRrc->left;
+ lpobj->pCurMdc->yre = lpRrc->bottom - lpRrc->top;
+
+ }
+
+ lpobj->error = OLE_OK;
+ MfInterruptiblePaint(lpobj, hdc);
+
+ if (lpobj->fMetaDC)
+ CleanStack (lpobj, hInfo);
+
+ RestoreDC (hdc, iOldDc);
+ return lpobj->error;
+}
+
+
+void INTERNAL MfInterruptiblePaint (lpobj, hdc)
+LPOBJECT_MF lpobj;
+HDC hdc;
+{
+ FARPROC lpCallbackFunc;
+
+ if (!(lpCallbackFunc = MakeProcInstance (MfCallbackFunc, hInstDLL)))
+ PlayMetaFile (hdc, lpobj->mfp.hMF);
+ else {
+ EnumMetaFile (hdc,lpobj->mfp.hMF, lpCallbackFunc, (LPARAM) lpobj);
+ FreeProcInstance (lpCallbackFunc);
+ }
+}
+
+
+
+int FARINTERNAL MfCallbackFunc (hdc, lpHTable, lpMFR, nObj, lpobj)
+HDC hdc;
+LPHANDLETABLE lpHTable;
+LPMETARECORD lpMFR;
+int nObj;
+BYTE FAR * lpobj;
+{
+ LPOBJECT_MF lpobjMf;
+
+ lpobjMf = (LPOBJECT_MF) lpobj;
+ if (!--lpobjMf->nRecord) {
+ lpobjMf->nRecord = RECORD_COUNT;
+ if (!ContextCallBack ((lpobjMf->head.lpParent
+ ? lpobjMf->head.lpParent
+ : (LPOLEOBJECT) lpobjMf),
+ OLE_QUERY_PAINT)) {
+ lpobjMf->error = OLE_ERROR_ABORT;
+ return FALSE;
+ }
+ }
+
+ if (lpobjMf->fMetaDC) {
+
+#ifdef META_DEBUG
+ PutMetaFuncName (lpMFR->rdFunction);
+#endif
+
+ switch (lpMFR->rdFunction) {
+ case META_SETWINDOWORG:
+ SetPictOrg (lpobjMf, hdc, lpMFR->rdParm[1],
+ lpMFR->rdParm[0], FALSE);
+ return TRUE;
+
+ case META_OFFSETWINDOWORG:
+ SetPictOrg (lpobjMf, hdc, lpMFR->rdParm[1],
+ lpMFR->rdParm[0], TRUE);
+ return TRUE;
+
+ case META_SETWINDOWEXT:
+ SetPictExt (lpobjMf, hdc, lpMFR->rdParm[1], lpMFR->rdParm[0]);
+ return TRUE;
+
+ case META_SCALEWINDOWEXT:
+ ScalePictExt (lpobjMf, hdc,
+ lpMFR->rdParm[3], lpMFR->rdParm[2],
+ lpMFR->rdParm[1], lpMFR->rdParm[0]);
+ return TRUE;
+
+ case META_SAVEDC:
+ if (!PushDc (lpobjMf))
+ return FALSE;
+ break;
+
+ case META_RESTOREDC:
+ PopDc (lpobjMf);
+ break;
+
+ case META_SCALEVIEWPORTEXT:
+ ScaleRectExt (lpobjMf, hdc,
+ lpMFR->rdParm[3], lpMFR->rdParm[2],
+ lpMFR->rdParm[1], lpMFR->rdParm[0]);
+ return TRUE;
+
+ case META_OFFSETVIEWPORTORG:
+#ifdef FIREWALLS
+ ASSERT(0, "OffsetViewportOrg() in metafile");
+#endif
+ return TRUE;
+
+ case META_SETVIEWPORTORG:
+#ifdef FIREWALLS
+ ASSERT(0, "SetViewportOrg() in metafile");
+#endif
+ return TRUE;
+
+ case META_SETVIEWPORTEXT:
+#ifdef FIREWALLS
+ ASSERT(0, "SetViewportExt() in metafile");
+#endif
+ return TRUE;
+
+ case META_SETMAPMODE:
+#ifdef FIREWALLS
+ ASSERT(lpMFR->rdParm[0] == MM_ANISOTROPIC,
+ "SetmapMode() in metafile with invalid mapping mode");
+#endif
+ return TRUE;
+
+ default:
+ break;
+ }
+ }
+ else {
+ switch (lpMFR->rdFunction) {
+ DWORD exts;
+
+ case META_SCALEWINDOWEXT:
+ exts = GetWindowExt (hdc);
+ SetWindowExt (hdc,
+ MulDiv(LOWORD(exts), lpMFR->rdParm[3], lpMFR->rdParm[2]),
+ MulDiv(HIWORD(exts), lpMFR->rdParm[1], lpMFR->rdParm[0]));
+ return TRUE;
+
+ case META_SCALEVIEWPORTEXT:
+ exts = GetViewportExt (hdc);
+ SetViewportExt (hdc,
+ MulDiv(LOWORD(exts), lpMFR->rdParm[3], lpMFR->rdParm[2]),
+ MulDiv(HIWORD(exts), lpMFR->rdParm[1], lpMFR->rdParm[0]));
+ return TRUE;
+
+ default:
+ break;
+ }
+ }
+
+ PlayMetaFileRecord (hdc, lpHTable, lpMFR, nObj);
+ return TRUE;
+}
+
+
+void SetPictOrg (lpobj, hdc, xOrg, yOrg, fOffset)
+LPOBJECT_MF lpobj;
+HDC hdc;
+int xOrg;
+int yOrg;
+BOOL fOffset;
+{
+ if (fOffset) {
+ // it's OffsetWindowOrg() call
+ lpobj->pCurMdc->xMwo += xOrg;
+ lpobj->pCurMdc->yMwo += yOrg;
+ }
+ else {
+ // it's SetWindowOrg()
+ lpobj->pCurMdc->xMwo = xOrg;
+ lpobj->pCurMdc->yMwo = yOrg;
+ }
+
+ if (lpobj->pCurMdc->xMwe && lpobj->pCurMdc->yMwe) {
+ SetWindowOrg (hdc,
+ (lpobj->pCurMdc->xMwo - MulDiv (lpobj->pMetaInfo->xro,
+ lpobj->pCurMdc->xMwe,
+ lpobj->pCurMdc->xre)),
+ (lpobj->pCurMdc->yMwo - MulDiv (lpobj->pMetaInfo->yro,
+ lpobj->pCurMdc->yMwe,
+ lpobj->pCurMdc->yre)));
+ }
+}
+
+
+void SetPictExt (lpobj, hdc, xExt, yExt)
+LPOBJECT_MF lpobj;
+HDC hdc;
+int xExt;
+int yExt;
+{
+ lpobj->pCurMdc->xMwe = xExt;
+ lpobj->pCurMdc->yMwe = yExt;
+
+ SetWindowExt (hdc,
+ MulDiv (lpobj->pMetaInfo->xwe, xExt, lpobj->pCurMdc->xre),
+ MulDiv (lpobj->pMetaInfo->ywe, yExt, lpobj->pCurMdc->yre));
+
+ SetWindowOrg (hdc,
+ (lpobj->pCurMdc->xMwo
+ - MulDiv (lpobj->pMetaInfo->xro, xExt, lpobj->pCurMdc->xre)),
+ (lpobj->pCurMdc->yMwo
+ - MulDiv (lpobj->pMetaInfo->yro, yExt, lpobj->pCurMdc->yre)));
+}
+
+
+void ScalePictExt (lpobj, hdc, xNum, xDenom, yNum, yDenom)
+LPOBJECT_MF lpobj;
+HDC hdc;
+int xNum;
+int xDenom;
+int yNum;
+int yDenom;
+{
+ SetPictExt (lpobj, hdc, MulDiv (lpobj->pCurMdc->xMwe, xNum, xDenom),
+ MulDiv (lpobj->pCurMdc->yMwe, yNum, yDenom));
+}
+
+
+void ScaleRectExt (lpobj, hdc, xNum, xDenom, yNum, yDenom)
+LPOBJECT_MF lpobj;
+HDC hdc;
+int xNum;
+int xDenom;
+int yNum;
+int yDenom;
+{
+ lpobj->pCurMdc->xre = MulDiv (lpobj->pCurMdc->xre, xNum, xDenom);
+ lpobj->pCurMdc->yre = MulDiv (lpobj->pCurMdc->yre, yNum, yDenom);
+
+ SetPictExt (lpobj, hdc, lpobj->pCurMdc->xMwe, lpobj->pCurMdc->yMwe);
+}
+
+
+
+BOOL PushDc (lpobj)
+LPOBJECT_MF lpobj;
+{
+ HANDLE hNode = NULL;
+ PMETADC pNode = NULL;
+
+ if ((hNode = LocalAlloc (LMEM_MOVEABLE, sizeof (METADC)))
+ && (pNode = (PMETADC) LocalLock (hNode))) {
+ *pNode = *lpobj->pCurMdc;
+ lpobj->pCurMdc->pNext = pNode;
+ pNode->pNext = NULL;
+ lpobj->pCurMdc = pNode;
+ LocalUnlock (hNode);
+ return TRUE;
+ }
+
+ if (pNode)
+ LocalFree (hNode);
+
+ lpobj->error = OLE_ERROR_MEMORY;
+ return FALSE;
+}
+
+
+BOOL PopDc (lpobj)
+LPOBJECT_MF lpobj;
+{
+ PMETADC pPrev = (PMETADC) (lpobj->pMetaInfo);
+ PMETADC pCur = ((PMETADC) (lpobj->pMetaInfo))->pNext;
+ HANDLE hCur;
+
+ if (!pCur)
+ // more Pops than Pushes
+ return FALSE;
+
+ while (pCur->pNext) {
+ pPrev = pCur;
+ pCur = pCur->pNext;
+ }
+
+ if (hCur = LocalHandle ((WORD) pCur))
+ LocalFree (hCur);
+ pPrev->pNext = NULL;
+ lpobj->pCurMdc = pPrev;
+}
+
+
+void CleanStack(lpobj, hMetaInfo)
+LPOBJECT_MF lpobj;
+HANDLE hMetaInfo;
+{
+ PMETADC pCur = ((PMETADC) (lpobj->pMetaInfo))->pNext;
+ HANDLE hCur;
+
+ while (pCur) {
+ hCur = LocalHandle ((WORD) pCur);
+ ((PMETADC) (lpobj->pMetaInfo))->pNext = pCur = pCur->pNext;
+ if (hCur)
+ LocalFree (hCur);
+ }
+
+ LocalFree (hMetaInfo);
+ lpobj->fMetaDC = FALSE;
+ lpobj->pCurMdc = NULL;
+ lpobj->pMetaInfo = NULL;
+}
+
+#ifdef META_DEBUG
+void PutMetaFuncName (value)
+WORD value;
+{
+ switch (value) {
+ case META_SETBKCOLOR:
+ OutputDebugString ("SetBkColor ");
+ break;
+
+ case META_SETBKMODE:
+ OutputDebugString ("SetBkMode ");
+ break;
+
+ case META_SETMAPMODE:
+ OutputDebugString ("SetMapMode ");
+ break;
+
+ case META_SETROP2:
+ OutputDebugString ("SetRop2 ");
+ break;
+
+ case META_SETRELABS:
+ OutputDebugString ("SetRelabs ");
+ break;
+
+ case META_SETPOLYFILLMODE:
+ OutputDebugString ("SetPolyfillMode ");
+ break;
+
+ case META_SETSTRETCHBLTMODE:
+ OutputDebugString ("SetStretchBltMode ");
+ break;
+
+ case META_SETTEXTCHAREXTRA:
+ OutputDebugString ("SetTextCharExtra ");
+ break;
+
+ case META_SETTEXTCOLOR:
+ OutputDebugString ("SetTextColor ");
+ break;
+
+ case META_SETTEXTJUSTIFICATION:
+ OutputDebugString ("SetTextJustification ");
+ break;
+
+ case META_SETWINDOWORG:
+ OutputDebugString ("SetWindowOrg ");
+ break;
+
+ case META_SETWINDOWEXT:
+ OutputDebugString ("SetWindowExt ");
+ break;
+
+ case META_SETVIEWPORTORG:
+ OutputDebugString ("SetViewportOrg ");
+ break;
+
+ case META_SETVIEWPORTEXT:
+ OutputDebugString ("SetViewportExt ");
+ break;
+
+ case META_OFFSETWINDOWORG:
+ OutputDebugString ("OffsetWindowOrg ");
+ break;
+
+ case META_SCALEWINDOWEXT:
+ OutputDebugString ("ScaleWindowExt ");
+ break;
+
+ case META_OFFSETVIEWPORTORG:
+ OutputDebugString ("OffsetViewportOrg ");
+ break;
+
+ case META_SCALEVIEWPORTEXT:
+ OutputDebugString ("ScaleViewportExt ");
+ break;
+
+ case META_LINETO:
+ OutputDebugString ("LineTo ");
+ break;
+
+ case META_MOVETO:
+ OutputDebugString ("MoveTo ");
+ break;
+
+ case META_EXCLUDECLIPRECT:
+ OutputDebugString ("ExcludeCliprect ");
+ break;
+
+ case META_INTERSECTCLIPRECT:
+ OutputDebugString ("IntersectCliprect ");
+ break;
+
+ case META_ARC:
+ OutputDebugString ("Arc ");
+ break;
+
+ case META_ELLIPSE:
+ OutputDebugString ("Ellipse ");
+ break;
+
+ case META_FLOODFILL:
+ OutputDebugString ("FloodFill ");
+ break;
+
+ case META_PIE:
+ OutputDebugString ("Pie ");
+ break;
+
+ case META_RECTANGLE:
+ OutputDebugString ("Rectangle ");
+ break;
+
+ case META_ROUNDRECT:
+ OutputDebugString ("RoundRect ");
+ break;
+
+ case META_PATBLT:
+ OutputDebugString ("PatBlt ");
+ break;
+
+ case META_SAVEDC:
+ OutputDebugString ("SaveDC ");
+ break;
+
+ case META_SETPIXEL:
+ OutputDebugString ("SetPixel ");
+ break;
+
+ case META_OFFSETCLIPRGN:
+ OutputDebugString ("OffsetClipRegion ");
+ break;
+
+ case META_TEXTOUT:
+ OutputDebugString ("TextOut ");
+ break;
+
+ case META_BITBLT:
+ OutputDebugString ("BitBlt ");
+ break;
+
+ case META_STRETCHBLT:
+ OutputDebugString ("StrechBlt ");
+ break;
+
+ case META_POLYGON:
+ OutputDebugString ("Polygon ");
+ break;
+
+ case META_POLYLINE:
+ OutputDebugString ("PolyLine ");
+ break;
+
+ case META_ESCAPE:
+ OutputDebugString ("Escape ");
+ break;
+
+ case META_RESTOREDC:
+ OutputDebugString ("RestoreDC ");
+ break;
+
+ case META_FILLREGION:
+ OutputDebugString ("FillRegion ");
+ break;
+
+ case META_FRAMEREGION:
+ OutputDebugString ("FrameRegion ");
+ break;
+
+ case META_INVERTREGION:
+ OutputDebugString ("InvertRegion ");
+ break;
+
+ case META_PAINTREGION:
+ OutputDebugString ("PaintRegion ");
+ break;
+
+ case META_SELECTCLIPREGION:
+ OutputDebugString ("SelectClipRegion ");
+ break;
+
+ case META_SELECTOBJECT:
+ OutputDebugString ("SelectObject ");
+ break;
+
+ case META_SETTEXTALIGN:
+ OutputDebugString ("SetTextAlign ");
+ break;
+
+ case META_DRAWTEXT:
+ OutputDebugString ("DrawText");
+ break;
+
+ case META_CHORD:
+ OutputDebugString ("Chord ");
+ break;
+
+ case META_SETMAPPERFLAGS:
+ OutputDebugString ("SetMapperFlags ");
+ break;
+
+ case META_EXTTEXTOUT:
+ OutputDebugString ("ExtTextOut ");
+ break;
+
+ case META_SETDIBTODEV:
+ OutputDebugString ("SetDIBitsToDevice ");
+ break;
+
+ case META_SELECTPALETTE:
+ OutputDebugString ("SelectPalette ");
+ break;
+
+ case META_REALIZEPALETTE:
+ OutputDebugString ("RealizePalette ");
+ break;
+
+ case META_ANIMATEPALETTE:
+ OutputDebugString ("AnimatePalette ");
+ break;
+
+ case META_SETPALENTRIES:
+ OutputDebugString ("SetPaletteEntries ");
+ break;
+
+ case META_POLYPOLYGON:
+ OutputDebugString ("PolyPolygon ");
+ break;
+
+ case META_RESIZEPALETTE:
+ OutputDebugString ("ResizePalette ");
+ break;
+
+ case META_DIBBITBLT:
+ OutputDebugString ("DibBitBlt ");
+ break;
+
+ case META_DIBSTRETCHBLT:
+ OutputDebugString ("DibStrechBlt ");
+ break;
+
+ case META_DIBCREATEPATTERNBRUSH:
+ OutputDebugString ("DibCreatePatternBrush ");
+ break;
+
+ case META_STRETCHDIB:
+ OutputDebugString ("StretchDIBits ");
+ break;
+
+ case META_DELETEOBJECT:
+ OutputDebugString ("DeleteObject ");
+ break;
+
+ case META_CREATEPALETTE:
+ OutputDebugString ("CreatePalette ");
+ break;
+
+ case META_CREATEBRUSH:
+ OutputDebugString ("CreateBrush ");
+ break;
+
+ case META_CREATEPATTERNBRUSH:
+ OutputDebugString ("CreatePatternBrush ");
+ break;
+
+ case META_CREATEPENINDIRECT:
+ OutputDebugString ("CreatePenIndirect ");
+ break;
+
+ case META_CREATEFONTINDIRECT:
+ OutputDebugString ("CreateFontIndirect ");
+ break;
+
+ case META_CREATEBRUSHINDIRECT:
+ OutputDebugString ("CreateBrushIndirect ");
+ break;
+
+ case META_CREATEBITMAPINDIRECT:
+ OutputDebugString ("CreateBitmapIndirect ");
+ break;
+
+ case META_CREATEBITMAP:
+ OutputDebugString ("CreateBitmap ");
+ break;
+
+ case META_CREATEREGION:
+ OutputDebugString ("CreateRegion ");
+ break;
+
+ default:
+ OutputDebugString ("Invalid+Function+encountered ");
+ break;
+
+ }
+}
+#endif
diff --git a/private/mvdm/wow16/ole/client/error.c b/private/mvdm/wow16/ole/client/error.c
new file mode 100644
index 000000000..a32b18ab2
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/error.c
@@ -0,0 +1,281 @@
+/****************************** Module Header ******************************\
+* Module Name: ERROR.C
+*
+* PURPOSE: Contains routines which are commonly used, as method functions, by
+* bm.c, mf.c and dib.c. These routines do nothing more than
+* returning an error code.
+*
+* Created: November 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (11/20/90) Original
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+OLESTATUS FARINTERNAL ErrQueryRelease (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC;
+}
+
+OLESTATUS FARINTERNAL ErrPlay (lpobj, verb, fShow, fAct)
+WORD verb;
+LPOLEOBJECT lpobj;
+BOOL fAct;
+BOOL fShow;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrShow (lpobj, fAct)
+LPOLEOBJECT lpobj;
+BOOL fAct;
+{
+ return OLE_ERROR_STATIC;
+}
+
+OLESTATUS FARINTERNAL ErrAbort (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC;
+}
+
+OLESTATUS FARINTERNAL ErrCopyFromLink(lpobj, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLEOBJECT lpobj;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrSetHostNames (lpobj, lpclientName, lpdocName)
+LPOLEOBJECT lpobj;
+LPSTR lpclientName;
+LPSTR lpdocName;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrSetTargetDevice (lpobj, hDevInfo)
+LPOLEOBJECT lpobj;
+HANDLE hDevInfo;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrSetColorScheme (lpobj, lplogpal)
+LPOLEOBJECT lpobj;
+LPLOGPALETTE lplogpal;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrSetBounds(lpobj, lprc)
+LPOLEOBJECT lpobj;
+LPRECT lprc;
+{
+ return OLE_ERROR_MEMORY;
+}
+
+
+OLESTATUS FARINTERNAL ErrQueryOpen (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC; // static object
+}
+
+
+OLESTATUS FARINTERNAL ErrActivate (lpobj, verb, fShow, fAct, hWnd, lprc)
+LPOLEOBJECT lpobj;
+WORD verb;
+BOOL fShow;
+BOOL fAct;
+HWND hWnd;
+LPRECT lprc;
+{
+ return OLE_ERROR_STATIC; // static object
+}
+
+OLESTATUS FARINTERNAL ErrEdit (lpobj, fShow, hWnd, lprc)
+LPOLEOBJECT lpobj;
+BOOL fShow;
+HWND hWnd;
+LPRECT lprc;
+{
+ return OLE_ERROR_STATIC; // static object
+}
+
+OLESTATUS FARINTERNAL ErrClose (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC; // static object
+}
+
+
+OLESTATUS FARINTERNAL ErrUpdate (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC; // static object
+}
+
+
+OLESTATUS FARINTERNAL ErrReconnect (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_ERROR_STATIC; // static object
+
+}
+
+
+OLESTATUS FARINTERNAL ErrSetData (lpobj, cfFormat, hData)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+HANDLE hData;
+{
+ return OLE_ERROR_MEMORY;
+}
+
+
+OLESTATUS FARINTERNAL ErrReadFromStream (lpobj, cfFormat, lpstream)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+LPOLESTREAM lpstream;
+{
+ return OLE_ERROR_STREAM;
+}
+
+
+
+OLESTATUS FARINTERNAL ErrQueryOutOfDate (lpobj)
+LPOLEOBJECT lpobj;
+{
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL ErrObjectConvert (lpobj, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLEOBJECT lpobj;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+OLESTATUS FARINTERNAL ErrGetUpdateOptions (lpobj, lpoptions)
+LPOLEOBJECT lpobj;
+OLEOPT_UPDATE FAR *lpoptions;
+{
+ return OLE_ERROR_STATIC;
+
+}
+
+OLESTATUS FARINTERNAL ErrSetUpdateOptions (lpobj, options)
+LPOLEOBJECT lpobj;
+OLEOPT_UPDATE options;
+{
+ return OLE_ERROR_STATIC;
+
+}
+
+LPVOID FARINTERNAL ErrQueryProtocol (lpobj, lpprotocol)
+LPOLEOBJECT lpobj;
+LPSTR lpprotocol;
+{
+ return NULL;
+}
+
+OLESTATUS FARINTERNAL ErrRequestData (lpobj, cfFormat)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ return OLE_ERROR_STATIC;
+
+}
+
+OLESTATUS FARINTERNAL ErrExecute (lpobj, hData, wReserved)
+LPOLEOBJECT lpobj;
+HANDLE hData;
+WORD wReserved;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+
+OLESTATUS FARINTERNAL ErrObjectLong (lpobj, wFlags, lplong)
+LPOLEOBJECT lpobj;
+WORD wFlags;
+LPLONG lplong;
+{
+ return OLE_ERROR_STATIC;
+}
+
+
+HANDLE FARINTERNAL DuplicateGDIdata (hSrcData, cfFormat)
+HANDLE hSrcData;
+OLECLIPFORMAT cfFormat;
+{
+ if (cfFormat == CF_METAFILEPICT) {
+ LPMETAFILEPICT lpSrcMfp;
+ LPMETAFILEPICT lpDstMfp = NULL;
+ HANDLE hMF = NULL;
+ HANDLE hDstMfp = NULL;
+
+ if (!(lpSrcMfp = (LPMETAFILEPICT) GlobalLock(hSrcData)))
+ return NULL;
+
+ GlobalUnlock (hSrcData);
+
+ if (!(hMF = CopyMetaFile (lpSrcMfp->hMF, NULL)))
+ return NULL;
+
+ if (!(hDstMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT))))
+ goto errMfp;
+
+ if (!(lpDstMfp = (LPMETAFILEPICT) GlobalLock (hDstMfp)))
+ goto errMfp;
+
+ GlobalUnlock (hDstMfp);
+
+ *lpDstMfp = *lpSrcMfp;
+ lpDstMfp->hMF = hMF;
+ return hDstMfp;
+errMfp:
+ if (hMF)
+ DeleteMetaFile (hMF);
+
+ if (hDstMfp)
+ GlobalFree (hDstMfp);
+
+ return NULL;
+ }
+
+ if (cfFormat == CF_BITMAP) {
+ DWORD dwSize;
+
+ return BmDuplicate (hSrcData, &dwSize, NULL);
+ }
+
+ if (cfFormat == CF_DIB)
+ return DuplicateGlobal (hSrcData, GMEM_MOVEABLE);
+
+ return NULL;
+}
+
diff --git a/private/mvdm/wow16/ole/client/funchead.c b/private/mvdm/wow16/ole/client/funchead.c
new file mode 100644
index 000000000..d76977875
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/funchead.c
@@ -0,0 +1,21 @@
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// int FAR PASCAL LibMain (hInst, wDataSeg, cbHeapSize, lpszCmdLine)
+//
+// The main library entry point. This routine is called when the library
+// is loaded.
+//
+// Arguments:
+//
+// hInst -
+// wDataSeg -
+// cbHeapSize -
+// lpszCmdLine -
+//
+// Returns:
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
diff --git a/private/mvdm/wow16/ole/client/generic.c b/private/mvdm/wow16/ole/client/generic.c
new file mode 100644
index 000000000..ccf6e84d6
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/generic.c
@@ -0,0 +1,531 @@
+/****************************** Module Header ******************************\
+* Module Name: GENERIC.C
+*
+* Handles all API routines for the generic sub-dll of the ole dll.
+* Since the data format is unknown, all the routines are written with the
+* assumption that all the relevant data is placed in a single global data
+* segment. Note that this assumption is not valid for metafiles, bitmaps, and
+* and there can always be some other formats with such idiosyncracies. To
+* accommodate those cases the rendering dll writer should replace the relevant
+* routines after the creation of the generic object. If for a given class this
+* assumption (about data format) is valid then the dll writer need to replace
+* only the Draw and QueryBounds functions.
+*
+* Created: November-1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+*
+* Srinik, Raor (11/05/90) Designed, coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+char aMacText[4] = {'T', 'E', 'X', 'T'};
+char aMacRtf[4] = "RTF";
+
+extern OLESTATUS FARINTERNAL wCreateDummyMetaFile (LPOBJECT_MF, int, int);
+
+#pragma alloc_text(_TEXT, GenSaveToStream, GenLoadFromStream, GetBytes, PutBytes, PutStrWithLen, PutAtomIntoStream, GenQueryBounds)
+
+
+OLEOBJECTVTBL vtblGEN = {
+
+ ErrQueryProtocol, // check whether the speced protocol is supported
+
+ GenRelease, // Release
+ ErrShow, // Show
+ ErrPlay, // plat
+ GenGetData, // Get the object data
+ GenSetData, // Set the object data
+ ErrSetTargetDevice, //
+
+ ErrSetBounds, // set viewport bounds
+ GenEnumFormat, // enumerate supported formats
+ ErrSetColorScheme, //
+ GenRelease, // delete
+ ErrSetHostNames, //
+
+ GenSaveToStream, // write to file
+ GenClone, // clone object
+ ErrCopyFromLink, // Create embedded from Link
+
+ GenEqual, // compares the given objects for data equality
+
+ GenCopy, // copy to clip
+
+ GenDraw, // draw the object
+
+ ErrActivate, // open
+ ErrExecute, // excute
+ ErrClose, // Stop
+ ErrUpdate, // Update
+ ErrReconnect, // Reconnect
+
+ ErrObjectConvert, // convert object to specified type
+
+ ErrGetUpdateOptions, // update options
+ ErrSetUpdateOptions, // update options
+
+ ObjRename, // Change Object name
+ ObjQueryName, // Get current object name
+
+ GenQueryType, // Object type
+ GenQueryBounds, // QueryBounds
+ ObjQuerySize, // Find the size of the object
+ ErrQueryOpen, // Query open
+ ErrQueryOutOfDate, // query whether object is current
+
+ ErrQueryRelease, // release related stuff
+ ErrQueryRelease,
+ ErrQueryRelease,
+
+ ErrRequestData, // requestdata
+ ErrObjectLong, // objectLong
+ GenChangeData // change data of the existing object
+};
+
+
+OLESTATUS FARINTERNAL GenRelease (lpobj)
+LPOBJECT_GEN lpobj;
+{
+ HOBJECT hobj;
+
+ if (lpobj->hData) {
+ GlobalFree (lpobj->hData);
+ lpobj->hData = NULL;
+ }
+
+ if (lpobj->aClass)
+ GlobalDeleteAtom (lpobj->aClass);
+
+ if (lpobj->head.lhclientdoc)
+ DocDeleteObject ((LPOLEOBJECT) lpobj);
+
+ if (hobj = lpobj->head.hobj){
+ lpobj->head.hobj = NULL;
+ GlobalUnlock (hobj);
+ GlobalFree (hobj);
+ }
+
+ return OLE_OK;
+}
+
+
+
+OLESTATUS FARINTERNAL GenSaveToStream (lpobj, lpstream)
+LPOBJECT_GEN lpobj;
+LPOLESTREAM lpstream;
+{
+ LPSTR lpData;
+ OLESTATUS retVal = OLE_OK;
+ DWORD dwClipFormat = NULL;
+ char formatName[MAX_STR];
+
+ if (!lpobj->hData)
+ return OLE_ERROR_BLANK;
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutAtomIntoStream (lpstream, lpobj->aClass))
+ return OLE_ERROR_STREAM;
+
+ if (lpobj->cfFormat < 0xC000)
+ // then it is a predefined format
+ dwClipFormat = lpobj->cfFormat;
+
+ if (PutBytes (lpstream, (LPSTR) &dwClipFormat, sizeof(DWORD)))
+ return OLE_ERROR_STREAM;
+
+ if (!dwClipFormat) {
+ if (!GetClipboardFormatName (lpobj->cfFormat, (LPSTR) formatName,
+ sizeof(formatName)))
+ return OLE_ERROR_FORMAT;
+
+ if (PutStrWithLen (lpstream, formatName))
+ return OLE_ERROR_STREAM;
+ }
+
+ if (!lpobj->sizeBytes)
+ return OLE_ERROR_BLANK;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(DWORD)))
+ return OLE_ERROR_STREAM;
+
+ if (!(lpData = GlobalLock (lpobj->hData)))
+ return OLE_ERROR_MEMORY;
+
+ if (PutBytes (lpstream, lpData, lpobj->sizeBytes))
+ retVal = OLE_ERROR_STREAM;
+
+ GlobalUnlock (lpobj->hData);
+ return retVal;
+}
+
+
+OLESTATUS FARINTERNAL GenClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_GEN lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_GEN FAR * lplpobj;
+{
+ if (!lpobjsrc->hData)
+ return OLE_ERROR_BLANK;
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (!(*lplpobj = GenCreateObject (lpobjsrc->hData, lpclient,
+ FALSE, lhclientdoc,
+ lpobjname, lpobjsrc->head.ctype)))
+ return OLE_ERROR_MEMORY;
+ else {
+ (*lplpobj)->cfFormat = lpobjsrc->cfFormat;
+ (*lplpobj)->aClass = DuplicateAtom (lpobjsrc->aClass);
+ return OLE_OK;
+ }
+}
+
+
+
+OLESTATUS FARINTERNAL GenEqual (lpobj1, lpobj2)
+LPOBJECT_GEN lpobj1;
+LPOBJECT_GEN lpobj2;
+{
+ if (CmpGlobals (lpobj1->hData, lpobj2->hData))
+ return OLE_OK;
+
+ return OLE_ERROR_NOT_EQUAL;
+}
+
+
+
+OLESTATUS FARINTERNAL GenCopy (lpobj)
+LPOBJECT_GEN lpobj;
+{
+ HANDLE hData;
+
+ if (!lpobj->hData)
+ return OLE_ERROR_BLANK;
+
+ if (!(hData = DuplicateGlobal (lpobj->hData, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+
+ SetClipboardData (lpobj->cfFormat, hData);
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL GenLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpobj, objType, aClass, cfFormat)
+LPOLESTREAM lpstream;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LONG objType;
+ATOM aClass;
+OLECLIPFORMAT cfFormat;
+{
+ LPOBJECT_GEN lpobj = NULL;
+ OLESTATUS retVal = OLE_ERROR_STREAM;
+ HANDLE hData;
+ LPSTR lpData;
+ DWORD dwClipFormat;
+ char formatName[MAX_STR];
+ LONG length;
+
+ if (!(*lplpobj = (LPOLEOBJECT) (lpobj = GenCreateBlank(lhclientdoc,
+ lpobjname, objType,
+ aClass)))) {
+ if (aClass)
+ GlobalDeleteAtom(aClass);
+ return OLE_ERROR_MEMORY;
+ }
+
+ if (GetBytes (lpstream, (LPSTR) &dwClipFormat, sizeof (DWORD)))
+ goto errLoad;
+
+ // If object is from MAC then we will keep the data intact if the data
+ // format is either TEXT or RTF
+ if (HIWORD(dwVerFromFile) == OS_MAC) {
+ if (dwClipFormat == *((DWORD *) aMacText))
+ lpobj->cfFormat = CF_TEXT;
+ else if (dwClipFormat == *((DWORD *) aMacRtf))
+ lpobj->cfFormat = RegisterClipboardFormat ((LPSTR) "Rich Text Format");
+ else
+ lpobj->cfFormat = NULL;
+ }
+ else {
+ // object is created on windows
+ if (!dwClipFormat) {
+ // this is new file format. format name string follows
+ if (GetBytes (lpstream, (LPSTR) &length, sizeof (LONG))
+ || GetBytes (lpstream, (LPSTR)formatName, length)
+ || (!(lpobj->cfFormat = RegisterClipboardFormat ((LPSTR) formatName))))
+ goto errLoad;
+ }
+ else if ((lpobj->cfFormat = (WORD) dwClipFormat) >= 0xc000) {
+ // if format is not predefined and file format is old, then use
+ // what value is passed to you through "cfFormat" argument
+ lpobj->cfFormat = cfFormat;
+ }
+ }
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof (DWORD)))
+ goto errLoad;
+
+ lpobj->head.lpclient = lpclient;
+
+ retVal = OLE_ERROR_MEMORY;
+ if (!(hData = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes)))
+ goto errLoad;
+
+ if (!(lpData = GlobalLock (hData)))
+ goto errMem;
+
+ if (GetBytes (lpstream, lpData, lpobj->sizeBytes)) {
+ retVal = OLE_ERROR_STREAM;
+ GlobalUnlock (hData);
+ goto errMem;
+ }
+
+ lpobj->hData = hData;
+ GlobalUnlock (hData);
+
+ // if the object is from MAC then we want delete this and create blank
+ // metafile object, which draws a rectangle
+ if ((HIWORD(dwVerFromFile) == OS_MAC) && !lpobj->cfFormat) {
+ LPOBJECT_MF lpobjMf;
+
+ OleDelete ((LPOLEOBJECT)lpobj); // delete generic object
+
+ // Now create a dummy metafile object which draws a rectangle of size
+ // 1" x 1". Note that 1" = 2540 HIMETRIC units
+ lpobjMf = MfCreateBlank (lhclientdoc, lpobjname, objType);
+ lpobjMf->head.cx = lpobjMf->mfp.xExt = 2540;
+ lpobjMf->head.cy = - (lpobjMf->mfp.yExt = 2540);
+ if ((retVal = wCreateDummyMetaFile (lpobjMf, lpobjMf->mfp.xExt,
+ lpobjMf->mfp.yExt)) != OLE_OK) {
+ OleDelete ((LPOLEOBJECT) lpobjMf);
+ return retVal;
+ }
+
+ *lplpobj = (LPOLEOBJECT) lpobjMf;
+ }
+
+ return OLE_OK;
+
+errMem:
+ GlobalFree (hData);
+
+errLoad:
+ OleDelete ((LPOLEOBJECT)lpobj);
+ *lplpobj = NULL;
+ return OLE_ERROR_STREAM;
+}
+
+
+
+
+LPOBJECT_GEN INTERNAL GenCreateObject (hData, lpclient, fDelete, lhclientdoc, lpobjname, objType)
+HANDLE hData;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ LPOBJECT_GEN lpobj;
+
+ if (!hData)
+ return NULL;
+
+ if (lpobj = GenCreateBlank (lhclientdoc, lpobjname, objType, NULL)) {
+ if (GenChangeData (lpobj, hData, lpclient, fDelete) != OLE_OK) {
+ GenRelease (lpobj);
+ lpobj = NULL;
+ }
+ }
+
+ return lpobj;
+}
+
+
+// If the routine fails then the object will be left with it's old data.
+// If fDelete is TRUE, then hNewData will be deleted whether the routine
+// is successful or not.
+
+OLESTATUS FARINTERNAL GenChangeData (lpobj, hSrcData, lpclient, fDelete)
+LPOBJECT_GEN lpobj;
+HANDLE hSrcData;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+{
+ HANDLE hDestData;
+
+ if (!fDelete) {
+ if (!(hDestData = DuplicateGlobal (hSrcData, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+ }
+ else {
+ // change the ownership to yourself
+ if (!(hDestData = GlobalReAlloc(hSrcData,0L,GMEM_MODIFY|GMEM_SHARE))){
+ hDestData = DuplicateGlobal (hSrcData, GMEM_MOVEABLE);
+ GlobalFree (hSrcData);
+ if (!hDestData)
+ return OLE_ERROR_MEMORY;
+ }
+ }
+
+ lpobj->head.lpclient = lpclient;
+ if (lpobj->hData)
+ GlobalFree (lpobj->hData);
+ lpobj->hData = hDestData;
+ lpobj->sizeBytes = GlobalSize (hDestData);
+
+ return OLE_OK;
+}
+
+
+
+LPOBJECT_GEN FARINTERNAL GenCreateBlank(lhclientdoc, lpobjname, objType, aClass)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+ATOM aClass;
+{
+ HOBJECT hobj;
+ LPOBJECT_GEN lpobj;
+
+ if ((hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_GEN)))
+ == NULL)
+ return NULL;
+
+ if (!(lpobj = (LPOBJECT_GEN) GlobalLock (hobj))){
+ GlobalFree (hobj);
+ return NULL;
+ }
+
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+ lpobj->head.mm = MM_TEXT;
+ lpobj->head.ctype = objType;
+ lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblGEN;
+ lpobj->head.iTable = INVALID_INDEX;
+ lpobj->head.hobj = hobj;
+ lpobj->aClass = aClass;
+
+ if (objType == CT_STATIC)
+ DocAddObject ((LPCLIENTDOC) lhclientdoc,
+ (LPOLEOBJECT) lpobj, lpobjname);
+
+ return lpobj;
+}
+
+
+OLESTATUS FARINTERNAL GenPaste (lpclient, lhclientdoc, lpobjname, lplpobj, lpClass, cfFormat, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LPSTR lpClass;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ HANDLE hData = NULL;
+
+ *lplpobj = NULL;
+ if (!cfFormat)
+ return OLE_ERROR_FORMAT;
+
+ if (!(hData = GetClipboardData(cfFormat)))
+ return OLE_ERROR_MEMORY;
+
+ if (!(*lplpobj = (LPOLEOBJECT) GenCreateObject (hData, lpclient,
+ FALSE, lhclientdoc,
+ lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ ((LPOBJECT_GEN)(*lplpobj))->cfFormat = cfFormat;
+ ((LPOBJECT_GEN)(*lplpobj))->aClass = GlobalAddAtom (lpClass);
+ return OLE_OK;
+
+}
+
+
+
+OLESTATUS FARINTERNAL GenQueryType (lpobj, lptype)
+LPOLEOBJECT lpobj;
+LPLONG lptype;
+{
+ return OLE_ERROR_GENERIC;;
+}
+
+
+
+OLESTATUS FARINTERNAL GenSetData (lpobj, cfFormat, hData)
+LPOBJECT_GEN lpobj;
+OLECLIPFORMAT cfFormat;
+HANDLE hData;
+{
+
+ if (lpobj->cfFormat != cfFormat)
+ return OLE_ERROR_FORMAT;
+
+ if (!hData)
+ return OLE_ERROR_BLANK;
+
+ GlobalFree (lpobj->hData);
+ lpobj->hData = hData;
+ lpobj->sizeBytes = GlobalSize (hData);
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL GenGetData (lpobj, cfFormat, lphandle)
+LPOBJECT_GEN lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+ if (cfFormat != lpobj->cfFormat)
+ return OLE_ERROR_FORMAT;
+
+ if (!(*lphandle = lpobj->hData))
+ return OLE_ERROR_BLANK;
+
+ return OLE_OK;
+
+}
+
+
+OLECLIPFORMAT FARINTERNAL GenEnumFormat (lpobj, cfFormat)
+LPOBJECT_GEN lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ if (!cfFormat)
+ return lpobj->cfFormat;
+
+ return NULL;
+}
+
+
+OLESTATUS FARINTERNAL GenQueryBounds (lpobj, lpRc)
+LPOBJECT_GEN lpobj;
+LPRECT lpRc;
+{
+ lpRc->right = 0;
+ lpRc->left = 0;
+ lpRc->top = 0;
+ lpRc->bottom = 0;
+ return OLE_ERROR_GENERIC;
+}
+
diff --git a/private/mvdm/wow16/ole/client/le.c b/private/mvdm/wow16/ole/client/le.c
new file mode 100644
index 000000000..14f12c403
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/le.c
@@ -0,0 +1,2324 @@
+
+/****************************** Module Header ******************************\
+* Module Name: le.c
+*
+* Purpose: Handles all API routines for the dde L&E sub-dll of the ole dll.
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, srinik (../../1990,91) Designed and coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+
+#define EMB_ID_INDEX 3 // index of ones digit in #000
+char embStr[] = "#000";
+
+extern HANDLE hInfo;
+extern OLECLIPFORMAT cfNetworkName;
+
+HANDLE GetNetNameHandle (LPOBJECT_LE);
+BOOL AreTopicsEqual (LPOBJECT_LE, LPOBJECT_LE);
+
+ATOM FARINTERNAL wAtomCat (ATOM, ATOM);
+
+#pragma alloc_text(_RARETEXT, LeObjectLong, LeQueryProtocol, LeEqual, AreTopicsEqual, LeObjectConvert, wAtomCat)
+
+#pragma alloc_text(_DDETEXT, LeRequestData, RequestData, LeChangeData, ContextCallBack, DeleteExtraData, NextAsyncCmd, InitAsyncCmd, FarInitAsyncCmd, EndAsyncCmd, ProcessErr, ScheduleAsyncCmd, LeQueryReleaseStatus, EmbLnkDelete, LeRelease, DeleteObjectAtoms, QueryClose, SendStdClose, TermDocConv, DeleteDocEdit, QueryUnlaunch, SendStdExit, QueryOpen, GetPictType, RequestOn, DocShow, EmbLnkClose, LnkSetUpdateOptions, LnkChangeLnk, TermSrvrConv, DeleteSrvrEdit, LeCopyFromLink)
+
+OLEOBJECTVTBL vtblLE = {
+
+ LeQueryProtocol, // check whether the speced protocol is supported
+
+ LeRelease, // release
+ LeShow, // Show
+ LeDoVerb, // run
+ LeGetData,
+ LeSetData,
+ LeSetTargetDevice, //
+
+ LeSetBounds, // set viewport bounds
+ LeEnumFormat, // returns format
+ LeSetColorScheme, // set color scheme
+ LeRelease, // delete
+ LeSetHostNames, //
+ LeSaveToStream, // write to file
+ LeClone, // clone object
+ LeCopyFromLink, // Create embedded from Link
+
+ LeEqual, // test whether the object data is similar
+
+ LeCopy, // copy to clip
+
+ LeDraw, // draw the object
+
+ LeActivate, // activate
+ LeExecute, // excute the given commands
+ LeClose, // stop
+ LeUpdate, // Update
+ LeReconnect, // Reconnect
+
+ LeObjectConvert, // convert object to specified type
+
+ LeGetUpdateOptions, // Get Link Update options
+ LeSetUpdateOptions, // Set Link Update options
+
+ ObjRename, // Change Object name
+ ObjQueryName, // Get current object name
+
+ LeQueryType, // object Type
+ LeQueryBounds, // QueryBounds
+ ObjQuerySize, // Find the size of the object
+ LeQueryOpen, // Query open
+ LeQueryOutOfDate, // query whether object is current
+
+ LeQueryReleaseStatus, // returns release status
+ LeQueryReleaseError, // assynchronusrelease error
+ LeQueryReleaseMethod, // the method/proc which is in assynchronus
+ // operation.
+ LeRequestData, // requestdata
+ LeObjectLong, // objectLong
+ LeChangeData // change native data of existing object
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FAR PASCAL LeObjectLong (lpobj, wFlags, lpData)
+//
+//
+// Returns whether a given object is still processing a previous
+// asynchronous command. returns OLE_BUSY if the object is still
+// processing the previous command
+//
+// Arguments:
+//
+// lpobj - object handle
+// wFlags - get, set flags
+// lpData - long pointer to data
+//
+// Returns:
+//
+// OLE_OK
+// OLE_ERROR_OBJECT
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FARINTERNAL LeObjectLong (lpobj, wFlags, lpData)
+LPOBJECT_LE lpobj;
+WORD wFlags;
+LPLONG lpData;
+{
+ LONG lData;
+
+ Puts("LeObjectLong");
+
+ if (!FarCheckObject((LPOLEOBJECT) lpobj))
+ return OLE_ERROR_OBJECT;
+
+ if ((lpobj->head.ctype != CT_EMBEDDED) && (lpobj->head.ctype != CT_LINK))
+ return OLE_ERROR_OBJECT;
+
+ if (wFlags & OF_HANDLER) {
+ lData = lpobj->lHandlerData;
+ if (wFlags & OF_SET)
+ lpobj->lHandlerData = *lpData;
+
+ if (wFlags & OF_GET)
+ *lpData = lData;
+ }
+ else {
+ lData = lpobj->lAppData;
+ if (wFlags & OF_SET)
+ lpobj->lAppData = *lpData;
+
+ if (wFlags & OF_GET)
+ *lpData = lData;
+ }
+
+ return OLE_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FAR PASCAL LeQueryReleaseStatus (lpobj)
+//
+//
+// Returns whether a given object is still processing a previous
+// asynchronous command. returns OLE_BUSY if the object is still
+// processing the previous command
+//
+// Arguments:
+//
+// lpobj - object handle
+//
+// Returns:
+//
+// OLE_BUSY - object is busy
+// OLE_OK - not busy
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FAR PASCAL LeQueryReleaseStatus (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ // probe async will clean up the channels
+ // if the server died.
+
+
+ PROBE_ASYNC (lpobj);
+ return OLE_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FAR PASCAL LeQueryReleaseError (lpobj)
+//
+// returns the errors of an asynchronous command.
+//
+// Arguments:
+//
+// lpobj - object handle
+//
+// Returns:
+//
+// OLE_ERROR_.. - if there is any error
+// OLE_OK - no error
+//
+// Note: This api is typically valid only during the callback of
+// OLE_RELEASE.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FAR PASCAL LeQueryReleaseError (lpobj)
+LPOBJECT_LE lpobj;
+{
+ return lpobj->mainErr;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLE_RELEASE_METHOD FAR PASCAL LeQueryReleaseMethod (lpobj)
+//
+// returns the method/command of the asynchronous command which
+// resulted in the OLE_RELEASE call back.
+//
+// Arguments:
+//
+// lpobj - object handle
+//
+// Returns:
+// OLE_RELEASE_METHOD
+//
+// Note: This api is typically valid only during the callback of
+// OLE_RELEASE. Using this api, clients can decide which previous
+// asynchronous command resulted in OLE_RELEASE.
+//
+//////////////////////////////////////////////////////////////////////////////
+OLE_RELEASE_METHOD FAR PASCAL LeQueryReleaseMethod (lpobj)
+LPOBJECT_LE lpobj;
+{
+ return lpobj->oldasyncCmd;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// LPVOID FARINTERNAL LeQueryProtocol (lpobj, lpprotocol)
+//
+// Given an oject, returns the new object handle for the new protocol.
+// Does the conversion of objects from one protocol to another one.
+//
+// Arguments:
+//
+// lpobj - object handle
+// lpprotocol - ptr to new protocol string
+//
+// Returns:
+// lpobj - New object handle
+// null - if the protocol is not supported.
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+
+LPVOID FARINTERNAL LeQueryProtocol (lpobj, lpprotocol)
+LPOBJECT_LE lpobj;
+LPSTR lpprotocol;
+{
+ if (lpobj->bOldLink)
+ return NULL;
+
+ if (!lstrcmp (lpprotocol, PROTOCOL_EDIT))
+ return lpobj;
+
+ if (!lstrcmp (lpprotocol, PROTOCOL_EXECUTE)) {
+ if (UtilQueryProtocol (lpobj, lpprotocol))
+ return lpobj;
+
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS EmbLnkDelete (lpobj)
+//
+// Routine for the object termination/deletion. Schedules differnt
+// asynchronous commands depending on different conditions.
+// Arguments:
+//
+// Sends "StdClose" only if it is Ok to close the document. Sends
+// "StdExit" only if the server has to be unlaunched. Deletes the object
+// only if the original command is OLE_DELETE. No need to call back the
+// client if the deletion is internal.
+//
+// While delete, this routine is entered several times. EAIT_FOR_ASYNC_MSG
+// results in going back to from where it is called and the next DDE message
+// brings back the control to this routine.
+//
+// Arguments:
+//
+// lpobj - object handle
+//
+// Returns:
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL EmbLnkDelete (lpobj)
+LPOBJECT_LE lpobj;
+{
+ HOBJECT hobj;
+
+ switch (lpobj->subRtn) {
+
+ case 0:
+
+ SKIP_TO (!QueryClose (lpobj), step1);
+ // Send "StdCloseDocument"
+ SendStdClose (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+
+ step1:
+ SETSTEP (lpobj, 1);
+
+ // End the doc conversation
+ TermDocConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+
+ case 2:
+
+
+ // delete the doc edit block. It is Ok even if the object
+ // is not actually getting deleted.
+ DeleteDocEdit (lpobj);
+
+ // if need to unluanch the app, send stdexit.
+ SKIP_TO (!QueryUnlaunch (lpobj), step3);
+ SendStdExit (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 3:
+
+ step3:
+ SETSTEP (lpobj, 3);
+
+ // Do not set any errors.
+ // Terminate the server conversation.
+ TermSrvrConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 4:
+
+ // delete the server edit block
+ DeleteSrvrEdit (lpobj);
+ if (lpobj->asyncCmd != OLE_DELETE) {
+
+ // if this delete is called because of unlauncinh of
+ // object because of some error, no need to
+ // call end asynchronous. It should have been already
+ // called from somewhere else.
+
+ if (lpobj->asyncCmd == OLE_SERVERUNLAUNCH){
+ // send the async cmd;
+ CLEARASYNCCMD (lpobj);
+ } else
+ EndAsyncCmd (lpobj);
+ return OLE_OK;
+ }
+
+
+
+ // for real delete delete the atoms and space.
+ DeleteObjectAtoms (lpobj);
+
+ if (lpobj->lpobjPict)
+ (*lpobj->lpobjPict->lpvtbl->Delete) (lpobj->lpobjPict);
+
+ if (lpobj->hnative)
+ GlobalFree (lpobj->hnative);
+
+ if (lpobj->hLink)
+ GlobalFree (lpobj->hLink);
+
+ if (lpobj->hhostNames)
+ GlobalFree (lpobj->hhostNames);
+
+ if (lpobj->htargetDevice)
+ GlobalFree (lpobj->htargetDevice);
+
+ if (lpobj->hdocDimensions)
+ GlobalFree (lpobj->hdocDimensions);
+
+ DeleteExtraData (lpobj);
+
+ DocDeleteObject ((LPOLEOBJECT) lpobj);
+ // send the async cmd;
+ EndAsyncCmd (lpobj);
+
+ if (lpobj->head.iTable != INVALID_INDEX)
+ DecreaseHandlerObjCount (lpobj->head.iTable);
+
+ hobj = lpobj->head.hobj;
+ ASSERT (hobj, "Object handle NULL in delete")
+
+ GlobalUnlock (hobj);
+ GlobalFree (hobj);
+
+ return OLE_OK;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeRelease (lpobj)
+//
+// Deletes the given object. This is can be asynchronous operation.
+//
+// Arguments:
+//
+// lpobj - object handle
+//
+// Returns:
+//
+// OLE_WAIT_FOR_RELASE: If any DDE_TRANSACTIONS have been queued
+// OLE_OK : If deletion successfully
+// OLE_ERROR_... : If any error
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeRelease (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+
+ // For delete allow if the object has been aborted.
+
+ PROBE_ASYNC (lpobj);
+
+ // reset the flags so that we do not delete the object based on the old
+ // flags
+ lpobj->fCmd = 0;
+ InitAsyncCmd (lpobj, OLE_DELETE, EMBLNKDELETE);
+ return EmbLnkDelete (lpobj);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+//
+// Clones a given object.
+//
+// Arguments:
+//
+// lpobjsrc: ptr to the src object.
+// lpclient: client callback handle
+// lhclientdoc: doc handle
+// lpobjname: object name
+// lplpobj: holder for returning object.
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_... : error
+//
+// Note: If the object being cloned is connected to the server, then
+// the cloned object is not connected to the server. For linked
+// objects, OleConnect has to be called.
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_LE lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_LE FAR * lplpobj;
+{
+
+ LPOBJECT_LE lpobj = NULL;
+ int retval = OLE_ERROR_MEMORY;
+
+ // Assumes all the creates are in order
+// PROBE_OBJECT_BLANK(lpobjsrc);
+
+ PROBE_CREATE_ASYNC(lpobjsrc);
+
+ if (!(lpobj = LeCreateBlank(lhclientdoc, lpobjname,
+ lpobjsrc->head.ctype)))
+ goto errRtn;
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->head.iTable = lpobjsrc->head.iTable; //!!! dll loading
+ lpobj->head.lpvtbl = lpobjsrc->head.lpvtbl;
+
+ // set the atoms.
+ lpobj->app = DuplicateAtom (lpobjsrc->app);
+ lpobj->topic = DuplicateAtom (lpobjsrc->topic);
+ lpobj->item = DuplicateAtom (lpobjsrc->item);
+ lpobj->aServer = DuplicateAtom (lpobjsrc->aServer);
+
+ lpobj->bOleServer = lpobjsrc->bOleServer;
+ lpobj->verb = lpobjsrc->verb;
+ lpobj->fCmd = lpobjsrc->fCmd;
+
+ lpobj->aNetName = DuplicateAtom (lpobjsrc->aNetName);
+ lpobj->cDrive = lpobjsrc->cDrive;
+ lpobj->dwNetInfo = lpobjsrc->dwNetInfo;
+
+ if (lpobjsrc->htargetDevice)
+ lpobj->htargetDevice = DuplicateGlobal (lpobjsrc->htargetDevice,
+ GMEM_MOVEABLE);
+
+ if (lpobjsrc->head.ctype == CT_EMBEDDED) {
+ if (lpobjsrc->hnative) {
+ if (!(lpobj->hnative = DuplicateGlobal (lpobjsrc->hnative,
+ GMEM_MOVEABLE)))
+ goto errRtn;
+ }
+
+ if (lpobjsrc->hdocDimensions)
+ lpobj->hdocDimensions = DuplicateGlobal (lpobjsrc->hdocDimensions,
+ GMEM_MOVEABLE);
+ if (lpobjsrc->hlogpal)
+ lpobj->hlogpal = DuplicateGlobal (lpobjsrc->hlogpal,
+ GMEM_MOVEABLE);
+ SetEmbeddedTopic (lpobj);
+ }
+ else {
+ lpobj->bOldLink = lpobjsrc->bOldLink;
+ lpobj->optUpdate = lpobjsrc->optUpdate;
+ }
+
+ retval = OLE_OK;
+ // if picture is needed clone the picture object.
+ if ((!lpobjsrc->lpobjPict) ||
+ ((retval = (*lpobjsrc->lpobjPict->lpvtbl->Clone)(lpobjsrc->lpobjPict,
+ lpclient, lhclientdoc, lpobjname,
+ (LPOLEOBJECT FAR *)&lpobj->lpobjPict))
+ == OLE_OK)) {
+ SetExtents (lpobj);
+ *lplpobj = lpobj;
+ if (lpobj->lpobjPict)
+ lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
+ }
+
+ return retval;
+
+errRtn:
+
+ // This oledelete should not result in any async communication.
+ if (lpobj)
+ OleDelete ((LPOLEOBJECT)lpobj);
+
+ return retval;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeCopyFromLink (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+//
+// Creates an embedded object from a lonked object. If the linked object
+// is not activated, then launches the server, gets the native data and
+// unlaunches the server. All these operations are done silently.
+//
+// Arguments:
+//
+// lpobjsrc: ptr to the src object.
+// lpclient: client callback handle
+// lhclientdoc: doc handle
+// lpobjname: object name
+// lplpobj: holder for returning object.
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_... : error
+// OLE_WAITF_FOR_RELEASE : if DDE transcation is queued
+//
+// Note: Could result in asynchronous operation if there is any
+// DDE operaion involved in getting any data from the server.
+//
+// Also, If there is any error in getting the native data, the
+// client is expected delete the object after the OLE_RELEASE
+// call back
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeCopyFromLink (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_LE lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_LE FAR * lplpobj;
+{
+
+ LPOBJECT_LE lpobj;
+ int retval;
+
+
+ *lplpobj = NULL;
+ PROBE_OLDLINK (lpobjsrc);
+ if (lpobjsrc->head.ctype != CT_LINK)
+ return OLE_ERROR_NOT_LINK;
+
+ PROBE_ASYNC (lpobjsrc);
+ PROBE_SVRCLOSING(lpobjsrc);
+
+ if ((retval = LeClone (lpobjsrc, lpclient, lhclientdoc, lpobjname,
+ (LPOBJECT_LE FAR *)&lpobj)) != OLE_OK)
+ return retval;
+
+
+ // we successfully cloned the object. if picture object has native data
+ // then grab it and put it in LE object. otherwise activate and get native
+ // data also.
+
+ if (lpobj->lpobjPict
+ && (*lpobj->lpobjPict->lpvtbl->EnumFormats)
+ (lpobj->lpobjPict, NULL) == cfNative){
+ // Now we know that the picture object is of native format, and it
+ // means that it is a generic object. So grab the handle to native
+ // data and put it in LE object.
+
+ lpobj->hnative = ((LPOBJECT_GEN) (lpobj->lpobjPict))->hData;
+ ((LPOBJECT_GEN) (lpobj->lpobjPict))->hData = NULL;
+ (*lpobj->lpobjPict->lpvtbl->Delete) (lpobj->lpobjPict);
+ lpobj->lpobjPict = NULL;
+ SetEmbeddedTopic (lpobj);
+ *lplpobj = lpobj;
+ return OLE_OK;
+ } else {
+
+ // if necessary launch, get native data and unlaunch the app.
+ lpobj->fCmd = LN_LNKACT | ACT_REQUEST | ACT_NATIVE | (QueryOpen(lpobjsrc) ? ACT_TERMDOC : ACT_UNLAUNCH);
+ InitAsyncCmd (lpobj, OLE_COPYFROMLNK, LNKOPENUPDATE);
+ if ((retval = LnkOpenUpdate (lpobj)) > OLE_WAIT_FOR_RELEASE)
+ LeRelease (lpobj);
+ else
+ *lplpobj = lpobj;
+
+ return retval;
+
+ // we will be changing the topic in end conversation.
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeEqual (lpobj1, lpobj2)
+//
+// Checks whethere two objects are equal. Checks for equality
+// of links, native data and picture data.
+//
+// Arguments:
+//
+// lpobj1: first object
+// lpobj2: second object
+//
+// Returns:
+// OLE_OK : equal
+// OLE_ERROR_NOT_EQUAL : if not equal
+// OLE_ERROR_..... : any errors
+//
+// Note: If any of the objects are connectd to the servers, leequal operaion
+// may not make much sense because the data might be changing from the
+// the server
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeEqual (lpobj1, lpobj2)
+LPOBJECT_LE lpobj1;
+LPOBJECT_LE lpobj2;
+{
+
+ if (lpobj1->app != lpobj2->app)
+ return OLE_ERROR_NOT_EQUAL;
+
+ // type of the objects is same. Otherwise this routine won't be called
+ if (lpobj1->head.ctype == CT_LINK) {
+ if (AreTopicsEqual (lpobj1, lpobj2) && (lpobj1->item == lpobj2->item))
+ return OLE_OK;
+
+ return OLE_ERROR_NOT_EQUAL;
+ }
+ else {
+ ASSERT (lpobj1->head.ctype == CT_EMBEDDED, "Invalid ctype in LeEqual")
+
+ if (lpobj1->item != lpobj2->item)
+ return OLE_ERROR_NOT_EQUAL;
+
+ if (CmpGlobals (lpobj1->hnative, lpobj2->hnative))
+ return OLE_OK;
+ else
+ return OLE_ERROR_NOT_EQUAL;
+ }
+
+ //### we may have to compare the picture data also
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeCopy (lpobj)
+//
+// Copies the object to the clipboard. Even for linked objects
+// we do not render the objectlink. It is up to the client app
+// to render object link
+//
+// Arguments:
+//
+// lpobj: object handle
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_..... : any errors
+//
+// Note: Library does not open the clipboard. Client is supposed to
+// open the librray before this call is made
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeCopy (lpobj)
+LPOBJECT_LE lpobj;
+{
+ HANDLE hlink = NULL;
+ HANDLE hnative = NULL;
+
+ PROBE_OLDLINK (lpobj);
+ // Assumes all the creates are in order
+// PROBE_OBJECT_BLANK(lpobj);
+
+ PROBE_CREATE_ASYNC(lpobj);
+
+ if (lpobj->head.ctype == CT_EMBEDDED){
+ if (!(hnative = DuplicateGlobal (lpobj->hnative, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+ SetClipboardData (cfNative, hnative);
+ }
+
+ hlink = GetLink (lpobj);
+ if (!(hlink = DuplicateGlobal (hlink, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+ SetClipboardData (cfOwnerLink, hlink);
+
+ // copy network name if it exists
+ if (lpobj->head.ctype == CT_LINK && lpobj->aNetName) {
+ HANDLE hNetName;
+
+ if (hNetName = GetNetNameHandle (lpobj))
+ SetClipboardData (cfNetworkName, hNetName);
+ }
+
+ if (lpobj->lpobjPict)
+ return (*lpobj->lpobjPict->lpvtbl->CopyToClipboard)(lpobj->lpobjPict);
+
+ return OLE_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeQueryBounds (lpobj, lpRc)
+//
+// Returns the bounding rectangle of the object. Returns topleft
+// as zero always and the units are himetric units.
+//
+// Arguments:
+//
+// lpobj: object handle
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_..... : any errors
+//
+// Note: Library does not open the clipboard. Client is supposed to
+// open the librray before this call is made
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FARINTERNAL LeQueryBounds (lpobj, lpRc)
+LPOBJECT_LE lpobj;
+LPRECT lpRc;
+{
+ Puts("LeQueryBounds");
+
+ // MM_HIMETRIC units
+
+ lpRc->left = 0;
+ lpRc->top = 0;
+ lpRc->right = (int) lpobj->head.cx;
+ lpRc->bottom = (int) lpobj->head.cy;
+
+ if (lpRc->right || lpRc->bottom)
+ return OLE_OK;
+
+ if (!lpobj->lpobjPict)
+ return OLE_ERROR_BLANK;
+
+ return (*lpobj->lpobjPict->lpvtbl->QueryBounds) (lpobj->lpobjPict, lpRc);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+//
+// Draws the object. Calls the picture object for drawing the object
+//
+//
+// Arguments:
+//
+// lpobj: source object
+// hdc: handle to dest dc. Could be metafile dc
+// lprc: rectangle into which the object should be drawn
+// should be in himetric units and topleft
+// could be nonzero.
+// hdctarget: Target dc for which the object should be drawn
+// (Ex: Draw metafile on the dest dc using the attributes
+// of traget dc).
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_BLANK : no picture
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOBJECT_LE lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ if (lpobj->lpobjPict)
+ return (*lpobj->lpobjPict->lpvtbl->Draw) (lpobj->lpobjPict,
+ hdc, lprc, lpWrc, hdcTarget);
+ return OLE_ERROR_BLANK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLECLIPFORMAT FARINTERNAL LeEnumFormat (lpobj, cfFormat)
+//
+// Enumerates the object formats.
+//
+//
+// Arguments:
+//
+// lpobj : source object
+// cfFormat : ref fprmat
+//
+// Returns:
+// NULL : no more formats or if we do not understand the
+// given format.
+//
+// Note: Even if the object is connected, we do not enumerate all the formats
+// the server can render. Server protocol can render the format list
+// only on system channel. Object can be connected only on the doc
+// channel
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLECLIPFORMAT FARINTERNAL LeEnumFormat (lpobj, cfFormat)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ Puts("LeEnumFormat");
+
+ ASSERT((lpobj->head.ctype == CT_LINK)||(lpobj->head.ctype == CT_EMBEDDED),
+ "Invalid Object Type");
+
+ // switch is not used because case won't take variable argument
+ if (cfFormat == NULL) {
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return cfNative;
+ else
+ return (lpobj->bOldLink ? cfLink : cfObjectLink);
+ }
+
+ if (cfFormat == cfNative) {
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return cfOwnerLink;
+ else
+ return NULL;
+ }
+
+ if (cfFormat == cfObjectLink) {
+ if (lpobj->aNetName)
+ return cfNetworkName;
+ else
+ cfFormat = NULL;
+ }
+ else if (cfFormat == cfOwnerLink || cfFormat == cfLink
+ || cfFormat == cfNetworkName)
+ cfFormat = NULL;
+
+ if (lpobj->lpobjPict)
+ return (*lpobj->lpobjPict->lpvtbl->EnumFormats) (lpobj->lpobjPict, cfFormat);
+
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+// OLESTATUS FARINTERNAL LeRequestData (lpobj, cfFormat)
+//
+// Requests data from the server for a given format, if the server
+// is connected. If the server is not connected returns error.
+//
+//
+// Arguments:
+//
+// lpobj: source object
+// cfFormat: ref fprmat
+//
+// Returns:
+// OLE_WAIT_FOR_RELEASE : If the data request data is sent to
+// the server.
+// OLE_ERROR_NOT_OPEN : Server is not open for data
+//
+// Note: If the server is ready, sends request to the server. When the
+// the data comes back from the server OLE_DATA_READY is sent in
+// the callback and the client can use Getdata to get the data.
+//
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+OLESTATUS FARINTERNAL LeRequestData (lpobj, cfFormat)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+{
+
+ // Assumes all the creates are in order
+ PROBE_ASYNC(lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if (!QueryOpen (lpobj))
+ return OLE_ERROR_NOT_OPEN;
+
+ if (cfFormat == cfOwnerLink || cfFormat == cfObjectLink)
+ return OLE_ERROR_FORMAT;
+
+ if (!(cfFormat == cfNative && lpobj->head.ctype == CT_EMBEDDED)
+ && (cfFormat != (OLECLIPFORMAT) GetPictType (lpobj))) {
+ DeleteExtraData (lpobj);
+ lpobj->cfExtra = cfFormat;
+ }
+
+ InitAsyncCmd (lpobj, OLE_REQUESTDATA, REQUESTDATA);
+ lpobj->pDocEdit->bCallLater = FALSE;
+ return RequestData(lpobj, cfFormat);
+}
+
+
+OLESTATUS RequestData (lpobj, cfFormat)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ switch (lpobj->subRtn) {
+
+ case 0:
+ RequestOn (lpobj, cfFormat);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+ ProcessErr (lpobj);
+ return EndAsyncCmd (lpobj);
+
+ default:
+ ASSERT (TRUE, "unexpected step in Requestdata");
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+// OLESTATUS FARINTERNAL LeGetData (lpobj, cfFormat, lphandle)
+//
+// Returns the data handle for a given format
+//
+// Arguments:
+//
+// lpobj: source object
+// cfFormat: ref fprmat
+// lphandle: handle return
+//
+// Returns:
+// NULL : no more formats or if we do not understand the
+// given format.
+//
+// Note: Even if the object is connected, we do not get the data from the
+// server. Getdata can not be used for getting data in any other
+// format other than the formats available with the object on
+// the client side.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeGetData (lpobj, cfFormat, lphandle)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+
+ // Assumes all the creates are in order
+// PROBE_OBJECT_BLANK(lpobj);
+
+ PROBE_CREATE_ASYNC(lpobj);
+
+ *lphandle = NULL;
+
+ // The assumption made here is that the native data can be in either
+ // LE object or picture object.
+ if ((cfFormat == cfNative) && (lpobj->hnative)) {
+ ASSERT ((lpobj->head.ctype == CT_EMBEDDED) || (!lpobj->lpobjPict) ||
+ ((*lpobj->lpobjPict->lpvtbl->EnumFormats) (lpobj->lpobjPict, NULL)
+ != cfNative), "Native data at wrong Place");
+ *lphandle = lpobj->hnative;
+ return OLE_OK;
+ }
+
+ if (cfFormat == cfOwnerLink && lpobj->head.ctype == CT_EMBEDDED) {
+ if (*lphandle = GetLink (lpobj))
+ return OLE_OK;
+
+ return OLE_ERROR_BLANK;
+ }
+
+ if ((cfFormat == cfObjectLink || cfFormat == cfLink) &&
+ lpobj->head.ctype == CT_LINK) {
+ if (*lphandle = GetLink (lpobj))
+ return OLE_OK;
+
+ return OLE_ERROR_BLANK;
+ }
+
+ if (cfFormat == cfNetworkName) {
+ if (lpobj->aNetName && (*lphandle = GetNetNameHandle (lpobj)))
+ return OLE_WARN_DELETE_DATA;
+
+ return OLE_ERROR_BLANK;
+ }
+
+ if (cfFormat == lpobj->cfExtra) {
+ if (*lphandle = lpobj->hextraData)
+ return OLE_OK;
+
+ return OLE_ERROR_BLANK;
+ }
+
+ if (!lpobj->lpobjPict && cfFormat)
+ return OLE_ERROR_FORMAT;
+
+ return (*lpobj->lpobjPict->lpvtbl->GetData) (lpobj->lpobjPict, cfFormat, lphandle);
+}
+
+
+
+
+OLESTATUS FARINTERNAL LeQueryOutOfDate (lpobj)
+LPOBJECT_LE lpobj;
+{
+ return OLE_OK;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeObjectConvert (lpobj, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+//
+// Converts a given linked/embedded object to static object.
+//
+// Arguments:
+// lpobj : source object
+// lpprotocol : protocol
+// lpclient : client callback for the new object
+// lhclientdoc: client doc
+// lpobjname : object name
+// lplpobj : object return
+//
+//
+// Returns:
+// OLE_OK : successful
+// OLE_ERROR_.... : any errors
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeObjectConvert (lpobj, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_LE lpobj;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ OLESTATUS retVal;
+
+ PROBE_ASYNC (lpobj);
+
+ *lplpobj = NULL;
+
+ if (lstrcmp (lpprotocol, PROTOCOL_STATIC))
+ return OLE_ERROR_PROTOCOL;
+
+ if (!lpobj->lpobjPict ||
+ ((*lpobj->lpobjPict->lpvtbl->QueryType) (lpobj->lpobjPict, NULL)
+ == OLE_ERROR_GENERIC)) {
+ // Either no picture object or non-standard picture object.
+ // Create a metafile Object.
+
+ HDC hMetaDC;
+ RECT rc;
+ HANDLE hMF = NULL, hmfp = NULL;
+ LPMETAFILEPICT lpmfp;
+
+ OleQueryBounds ((LPOLEOBJECT) lpobj, &rc);
+ if (!(hMetaDC = CreateMetaFile (NULL)))
+ goto Cleanup;
+
+ SetWindowOrg (hMetaDC, rc.left, rc.top);
+ SetWindowExt (hMetaDC, rc.right - rc.left, rc.bottom - rc.top);
+ retVal = OleDraw ((LPOLEOBJECT) lpobj, hMetaDC, &rc, &rc, NULL);
+ hMF = CloseMetaFile (hMetaDC);
+ if ((retVal != OLE_OK) || !hMF)
+ goto Cleanup;
+
+ if (!(hmfp = GlobalAlloc (GMEM_MOVEABLE, sizeof (METAFILEPICT))))
+ goto Cleanup;
+
+ if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)))
+ goto Cleanup;
+
+ lpmfp->hMF = hMF;
+ lpmfp->mm = MM_ANISOTROPIC;
+ lpmfp->xExt = rc.right - rc.left;
+ lpmfp->yExt = rc.top - rc.bottom;
+ GlobalUnlock (hmfp);
+
+ if (*lplpobj = (LPOLEOBJECT) MfCreateObject (hmfp, lpclient, TRUE,
+ lhclientdoc, lpobjname, CT_STATIC))
+ return OLE_OK;
+
+Cleanup:
+ if (hMF)
+ DeleteMetaFile (hMF);
+
+ if (hmfp)
+ GlobalFree (hmfp);
+
+ return OLE_ERROR_MEMORY;
+ }
+
+
+ // Picture object is one of the standard objects
+ if ((retVal = (*lpobj->lpobjPict->lpvtbl->Clone) (lpobj->lpobjPict,
+ lpclient, lhclientdoc,
+ lpobjname, lplpobj)) == OLE_OK) {
+ (*lplpobj)->ctype = CT_STATIC;
+ DocAddObject ((LPCLIENTDOC) lhclientdoc, *lplpobj, lpobjname);
+ }
+
+ return retVal;
+}
+
+
+
+// internal method used for changing picture/native data
+OLESTATUS FARINTERNAL LeChangeData (lpobj, hnative, lpoleclient, fDelete)
+LPOBJECT_LE lpobj;
+HANDLE hnative;
+LPOLECLIENT lpoleclient;
+BOOL fDelete;
+{
+ if (!fDelete) {
+ if (!(hnative = DuplicateGlobal (hnative, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+ }
+
+ // In case of a CopyFromLink, eventhough the object type is CT_LINK, the
+ // native data should go to LE object rather than the picture object, as
+ // we are going to change the object type to embedded after the required
+ // data is recieved.
+
+ if ((lpobj->head.ctype == CT_LINK)
+ && (lpobj->asyncCmd != OLE_COPYFROMLNK)
+ && (lpobj->asyncCmd != OLE_CREATEFROMFILE)) {
+ if (lpobj->lpobjPict)
+ return (*lpobj->lpobjPict->lpvtbl->SetData)
+ (lpobj->lpobjPict, cfNative, hnative);
+ }
+ else { // It must be embedded.
+ if (lpobj->hnative)
+ GlobalFree (lpobj->hnative);
+ lpobj->hnative = hnative;
+ return OLE_OK;
+ }
+
+ return OLE_ERROR_BLANK;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// LPOBJECT_LE FARINTERNAL LeCreateBlank (lhclientdoc, lpobjname, ctype)
+//
+// Create a blank object. Global block is used for the object and it is
+// locked once sucessful. Unlocking is done only while deletion. Object
+// is added to the corresponding doc.
+//
+// 'LE' signature is used for object validation.
+//
+// Arguments:
+// lhclientdoc : client doc handle
+// lpobjname : object name
+// ctype : type of object to be created
+//
+// Returns:
+// LPOBJECT : successful
+// NULL : any errors
+//
+//////////////////////////////////////////////////////////////////////////////
+
+LPOBJECT_LE FARINTERNAL LeCreateBlank (lhclientdoc, lpobjname, ctype)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG ctype;
+{
+ HOBJECT hobj;
+ LPOBJECT_LE lpobj;
+
+ if (!(ctype == CT_LINK || ctype == CT_EMBEDDED || ctype == CT_OLDLINK))
+ return NULL;
+
+ if (!(hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,
+ sizeof (OBJECT_LE))))
+ return NULL;
+
+ if (!(lpobj = (LPOBJECT_LE) GlobalLock (hobj))) {
+ GlobalFree (hobj);
+ return NULL;
+ }
+
+ if (ctype == CT_OLDLINK) {
+ ctype = CT_LINK;
+ lpobj->bOldLink = TRUE;
+ }
+
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+ lpobj->head.ctype = ctype;
+ lpobj->head.iTable = INVALID_INDEX;
+
+ lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblLE;
+
+ if (ctype == CT_LINK){
+ lpobj->optUpdate = oleupdate_always;
+
+ }else {
+ lpobj->optUpdate = oleupdate_onclose;
+ }
+ lpobj->head.hobj = hobj;
+ DocAddObject ((LPCLIENTDOC) lhclientdoc, (LPOLEOBJECT) lpobj, lpobjname);
+ return lpobj;
+}
+
+
+void FARINTERNAL SetExtents (LPOBJECT_LE lpobj)
+{
+ RECT rc = {0, 0, 0, 0};
+
+ if (lpobj->lpobjPict) {
+ if ((*lpobj->lpobjPict->lpvtbl->QueryBounds) (lpobj->lpobjPict,
+ (LPRECT)&rc) == OLE_OK) {
+ // Bounds are in MM_HIMETRIC units
+ lpobj->head.cx = (LONG) (rc.right - rc.left);
+ lpobj->head.cy = (LONG) (rc.bottom - rc.top);
+ }
+ return;
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeSaveToStream (lpobj, lpstream)
+//
+// Save the object to the stream. Uses the stream functions provided
+// in the lpclient.
+//
+// Format: (!!! Document the fomrat here).
+//
+//
+//
+// Arguments:
+// lhclientdoc : client doc handle
+// lpobjname : object name
+// ctype : type of object to be created
+//
+// Returns:
+// LPOBJECT : successful
+// NULL : any errors
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeSaveToStream (lpobj, lpstream)
+LPOBJECT_LE lpobj;
+LPOLESTREAM lpstream;
+{
+
+// PROBE_OBJECT_BLANK(lpobj);
+
+ PROBE_CREATE_ASYNC(lpobj);
+
+ if (lpobj->head.ctype == CT_LINK && lpobj->bOldLink)
+ lpobj->head.ctype = CT_OLDLINK;
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (lpobj->bOldLink)
+ lpobj->head.ctype = CT_OLDLINK;
+
+ return LeStreamWrite (lpstream, lpobj);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpoleobject, ctype, aClass, cfFormat)
+//
+// Create an object, loading the object from the stream.
+//
+// Arguments:
+// lpstream : stream table
+// lpclient : client callback table
+// lhclientdoc : Doc handle foe which the object should be created
+// lpobjname : Object name
+// lplpoleobject : object return
+// ctype : Type of object
+// aClass : class atom
+// cfFormat : render format
+//
+// Returns:
+// LPOBJECT : successful
+// NULL : any errors
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpoleobject, ctype, aClass, cfFormat)
+LPOLESTREAM lpstream;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG ctype;
+ATOM aClass;
+OLECLIPFORMAT cfFormat;
+{
+ LPOBJECT_LE lpobj = NULL;
+ OLESTATUS retval = OLE_ERROR_STREAM;
+ LONG type; // this not same as ctype
+ LONG ver;
+ char chVerb [2];
+
+ *lplpoleobject = NULL;
+
+ if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, ctype)))
+ return OLE_ERROR_MEMORY;
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->app = aClass;
+ // if the entry is present, then it is
+ lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
+
+ if (LeStreamRead (lpstream, lpobj) == OLE_OK) {
+
+ // Get exe name from aClass and set it as aServer
+ SetExeAtom (lpobj);
+ if (!GetBytes (lpstream, (LPSTR) &ver, sizeof(LONG))) {
+ if (!GetBytes (lpstream, (LPSTR) &type, sizeof(LONG))) {
+ if (type == CT_NULL)
+ retval = OLE_OK;
+ else if (aClass = GetAtomFromStream (lpstream)) {
+ retval = DefLoadFromStream (lpstream, NULL, lpclient,
+ lhclientdoc, lpobjname,
+ (LPOLEOBJECT FAR *)&lpobj->lpobjPict,
+ CT_PICTURE, aClass, cfFormat);
+ }
+ }
+ }
+
+ if (retval == OLE_OK) {
+ SetExtents (lpobj);
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+ if (lpobj->lpobjPict)
+ lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
+
+ if ((lpobj->head.ctype != CT_LINK)
+ || (!InitDocConv (lpobj, !POPUP_NETDLG))
+ || (lpobj->optUpdate >= oleupdate_oncall))
+ return OLE_OK;
+
+ lpobj->fCmd = ACT_ADVISE;
+
+ // If it's auto update, then get the latest data.
+ if (lpobj->optUpdate == oleupdate_always)
+ lpobj->fCmd |= ACT_REQUEST;
+
+ FarInitAsyncCmd (lpobj, OLE_LOADFROMSTREAM, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+ }
+ }
+
+ // This delete will not run into async command. We did not even
+ // even connect.
+ OleDelete ((LPOLEOBJECT) lpobj);
+ return OLE_ERROR_STREAM;
+}
+
+
+
+//
+
+OLESTATUS INTERNAL LeStreamRead (lpstream, lpobj)
+LPOLESTREAM lpstream;
+LPOBJECT_LE lpobj;
+{
+ DWORD dwBytes;
+ LPSTR lpstr;
+ OLESTATUS retval = OLE_OK;
+
+ if (!(lpobj->topic = GetAtomFromStream(lpstream))
+ && (lpobj->head.ctype != CT_EMBEDDED))
+ return OLE_ERROR_STREAM;
+
+ // !!! This atom could be NULL. How do we distinguish the
+ // error case
+
+ lpobj->item = GetAtomFromStream(lpstream);
+
+ if (lpobj->head.ctype == CT_EMBEDDED) {
+ if (GetBytes (lpstream, (LPSTR) &dwBytes, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (!(lpobj->hnative = GlobalAlloc (GMEM_MOVEABLE, dwBytes)))
+ return OLE_ERROR_MEMORY;
+ else if (!(lpstr = GlobalLock (lpobj->hnative))) {
+ GlobalFree (lpobj->hnative);
+ return OLE_ERROR_MEMORY;
+ }
+ else {
+ if (GetBytes(lpstream, lpstr, dwBytes))
+ retval = OLE_ERROR_STREAM;
+ GlobalUnlock (lpobj->hnative);
+ }
+
+ if (retval == OLE_OK)
+ SetEmbeddedTopic (lpobj);
+ }
+ else {
+ if (lpobj->aNetName = GetAtomFromStream (lpstream)) {
+ if (HIWORD(dwVerFromFile) == OS_MAC) {
+ // if it is a mac file this field will have "ZONE:MACHINE:"
+ // string. Lets prepend this to the topic, so that server
+ // app or user can fix the string
+
+ ATOM aTemp;
+
+ aTemp = wAtomCat (lpobj->aNetName, lpobj->topic);
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = NULL;
+ GlobalDeleteAtom (lpobj->topic);
+ lpobj->topic = aTemp;
+ }
+ else
+ SetNetDrive (lpobj);
+ }
+
+ if (HIWORD(dwVerFromFile) != OS_MAC) {
+ if (GetBytes (lpstream, (LPSTR) &lpobj->dwNetInfo, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+ }
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->optUpdate, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+ }
+ return retval;
+}
+
+
+
+OLESTATUS INTERNAL LeStreamWrite (lpstream, lpobj)
+LPOLESTREAM lpstream;
+LPOBJECT_LE lpobj;
+{
+ LPSTR lpstr;
+ DWORD dwBytes = 0L;
+ LONG nullType = CT_NULL;
+ int error;
+
+ if (PutAtomIntoStream(lpstream, lpobj->app))
+ return OLE_ERROR_STREAM;
+
+ if (lpobj->head.ctype == CT_EMBEDDED) {
+ // we set the topic at load time, no point in saving it
+ if (PutBytes (lpstream, (LPSTR) &dwBytes, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+ }
+ else {
+ if (PutAtomIntoStream(lpstream, lpobj->topic))
+ return OLE_ERROR_STREAM;
+ }
+
+#ifdef OLD
+ if (PutAtomIntoStream(lpstream, lpobj->topic))
+ return OLE_ERROR_STREAM;
+#endif
+
+ if (PutAtomIntoStream(lpstream, lpobj->item))
+ return OLE_ERROR_STREAM;
+
+ // !!! deal with objects > 64k
+
+ if (lpobj->head.ctype == CT_EMBEDDED) {
+
+ if (!lpobj->hnative)
+ return OLE_ERROR_BLANK;
+
+ // assumption low bytes are first
+ dwBytes = GlobalSize (lpobj->hnative);
+
+ if (PutBytes (lpstream, (LPSTR)&dwBytes, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (!(lpstr = GlobalLock (lpobj->hnative)))
+ return OLE_ERROR_MEMORY;
+
+ error = PutBytes (lpstream, lpstr, dwBytes);
+ GlobalUnlock (lpobj->hnative);
+
+ if (error)
+ return OLE_ERROR_STREAM;
+ }
+ else {
+ if (PutAtomIntoStream(lpstream, lpobj->aNetName))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->dwNetInfo, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->optUpdate, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+ }
+
+ if (lpobj->lpobjPict)
+ return (*lpobj->lpobjPict->lpvtbl->SaveToStream) (lpobj->lpobjPict,
+ lpstream);
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &nullType, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ return OLE_OK;
+}
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FARINTERNAL LeQueryType (lpobj, lptype)
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FARINTERNAL LeQueryType (lpobj, lptype)
+LPOBJECT_LE lpobj;
+LPLONG lptype;
+{
+ Puts("LeQueryType");
+
+ if ((lpobj->head.ctype == CT_EMBEDDED)
+ || (lpobj->asyncCmd == OLE_COPYFROMLNK)
+ || (lpobj->asyncCmd == OLE_CREATEFROMFILE))
+ *lptype = CT_EMBEDDED;
+ else if ((lpobj->head.ctype == CT_LINK)
+ || (lpobj->head.ctype == CT_OLDLINK))
+ *lptype = CT_LINK;
+ else
+ return OLE_ERROR_OBJECT;
+
+ return OLE_OK;
+}
+
+
+
+// ContextCallBack: internal function. Calls callback function of <hobj>
+// with flags.
+
+int FARINTERNAL ContextCallBack (lpobj, flags)
+LPOLEOBJECT lpobj;
+OLE_NOTIFICATION flags;
+{
+ LPOLECLIENT lpclient;
+
+ Puts("ContextCallBack");
+
+ if (!FarCheckObject(lpobj))
+ return FALSE;
+
+ if (!(lpclient = lpobj->lpclient))
+ return FALSE;
+
+ ASSERT (lpclient->lpvtbl->CallBack, "Client Callback ptr is NULL");
+
+ return ((*lpclient->lpvtbl->CallBack) (lpclient, flags, lpobj));
+}
+
+
+void FARINTERNAL DeleteExtraData (lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (lpobj->hextraData == NULL)
+ return;
+
+ switch (lpobj->cfExtra) {
+ case CF_BITMAP:
+ DeleteObject (lpobj->hextraData);
+ break;
+
+ case CF_METAFILEPICT:
+ {
+ LPMETAFILEPICT lpmfp;
+
+ if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (lpobj->hextraData)))
+ break;
+
+ DeleteMetaFile (lpmfp->hMF);
+ GlobalUnlock (lpobj->hextraData);
+ GlobalFree (lpobj->hextraData);
+ break;
+ }
+
+ default:
+ GlobalFree (lpobj->hextraData);
+ }
+
+ lpobj->hextraData = NULL;
+}
+
+
+void INTERNAL DeleteObjectAtoms(lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (lpobj->app) {
+ GlobalDeleteAtom (lpobj->app);
+ lpobj->app = NULL;
+ }
+
+ if (lpobj->topic) {
+ GlobalDeleteAtom (lpobj->topic);
+ lpobj->topic = NULL;
+ }
+
+ if (lpobj->item) {
+ GlobalDeleteAtom (lpobj->item);
+ lpobj->item = NULL;
+ }
+
+ if (lpobj->aServer) {
+ GlobalDeleteAtom (lpobj->aServer);
+ lpobj->aServer = NULL;
+ }
+
+ if (lpobj->aNetName) {
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = NULL;
+ }
+}
+
+
+// LeGetUpdateOptions: Gets the update options.
+
+OLESTATUS FARINTERNAL LeGetUpdateOptions (lpobj, lpOptions)
+LPOBJECT_LE lpobj;
+OLEOPT_UPDATE FAR *lpOptions;
+{
+ if (lpobj->head.ctype != CT_LINK)
+ return OLE_ERROR_OBJECT;
+
+ *lpOptions = lpobj->optUpdate;
+ return OLE_OK;
+}
+
+
+
+
+OLESTATUS FARINTERNAL LnkPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, sfFormat)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+OLECLIPFORMAT sfFormat;
+{
+ LPOBJECT_LE lpobj = NULL;
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ LPSTR lpClass = NULL;
+
+ if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_LINK)))
+ goto errRtn;
+
+ lpobj->head.lpclient = lpclient;
+
+#ifdef OLD
+ if (!bWLO) {
+ // we are not running under WLO
+ if (!(hInfo = GetClipboardData (sfFormat))) {
+ if (hInfo = GetClipboardData (cfLink))
+ lpobj->bOldLink = TRUE;
+ }
+ }
+#endif
+
+ if (!hInfo)
+ goto errRtn;
+
+ if (!IsClipboardFormatAvailable (sfFormat))
+ lpobj->bOldLink = TRUE;
+
+ if (!SetLink (lpobj, hInfo, &lpClass))
+ goto errRtn;
+
+ if ((retval = SetNetName(lpobj)) != OLE_OK) {
+ // see whether network name is on the clipboard and try to use it
+ HANDLE hNetName;
+ LPSTR lpNetName;
+
+ if (!IsClipboardFormatAvailable (cfNetworkName))
+ goto errRtn;
+
+ if (!(hNetName = GetClipboardData (cfNetworkName)))
+ goto errRtn;
+
+ if (!(lpNetName = GlobalLock (hNetName)))
+ goto errRtn;
+
+ GlobalUnlock (hNetName);
+ if (!(lpobj->aNetName = GlobalAddAtom (lpNetName)))
+ goto errRtn;
+
+ SetNetDrive (lpobj);
+ }
+
+ retval = CreatePictFromClip (lpclient, lhclientdoc, lpobjname,
+ (LPOLEOBJECT FAR *)&lpobj->lpobjPict, optRender,
+ cfFormat, lpClass, CT_PICTURE);
+
+ if (retval == OLE_OK) {
+ SetExtents (lpobj);
+ // why do we have to update the link, do we show it?
+
+ // Reconnect if we could and advise for updates
+ *lplpoleobject = (LPOLEOBJECT)lpobj;
+ if (lpobj->lpobjPict)
+ lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
+
+ if (!InitDocConv (lpobj, !POPUP_NETDLG))
+ return OLE_OK; // document is not loaded , it is OK.
+
+ lpobj->fCmd = ACT_ADVISE | ACT_REQUEST;
+ FarInitAsyncCmd (lpobj, OLE_LNKPASTE, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+
+ }
+ else {
+errRtn:
+ if (lpobj)
+ OleDelete ((LPOLEOBJECT)lpobj);
+ }
+
+ return retval;
+}
+
+
+
+// !!! EmbPaste and LnkPaste Can be combined
+OLESTATUS FARINTERNAL EmbPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ LPOBJECT_LE lpobj = NULL;
+ HANDLE hnative;
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ LPSTR lpClass = NULL;
+
+ if (!IsClipboardFormatAvailable (cfOwnerLink))
+ return OLE_ERROR_CLIPBOARD;
+
+ if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED)))
+ goto errRtn;
+
+ lpobj->head.lpclient = lpclient;
+
+#ifdef OLD
+ if (!bWLO) {
+ // we are not running under WLO
+ hInfo = GetClipboardData (cfOwnerLink);
+ }
+#endif
+
+ if (!hInfo)
+ goto errRtn;
+
+ if (!SetLink (lpobj, hInfo, &lpClass))
+ goto errRtn;
+
+ SetEmbeddedTopic (lpobj);
+
+ hnative = GetClipboardData (cfNative);
+ if (!(lpobj->hnative = DuplicateGlobal (hnative, GMEM_MOVEABLE)))
+ goto errRtn;
+
+ retval = CreatePictFromClip (lpclient, lhclientdoc, lpobjname,
+ (LPOLEOBJECT FAR *)&lpobj->lpobjPict, optRender,
+ cfFormat, lpClass, CT_PICTURE);
+
+ if (retval == OLE_OK) {
+ SetExtents (lpobj);
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+ if (lpobj->lpobjPict)
+ lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
+ }
+ else {
+errRtn:
+ // Note: This oledelete should not result in any async commands.
+ if (lpobj)
+ OleDelete ((LPOLEOBJECT)lpobj);
+ }
+
+#ifdef EXCEL_BUG
+ // Some server apps (ex: Excel) copy picture (to clipboard) which is
+ // formatted for printer DC. So, we want to update the picture if the
+ // server app is running, and the it's a old server
+
+ if ((retval == OLE_OK) && (!lpobj->bOleServer)) {
+ lpobj->fCmd = LN_EMBACT | ACT_NOLAUNCH | ACT_REQUEST | ACT_UNLAUNCH;
+ FarInitAsyncCmd (lpobj, OLE_EMBPASTE, EMBOPENUPDATE);
+ if ((retval = EmbOpenUpdate (lpobj)) > OLE_WAIT_FOR_RELEASE)
+ return OLE_OK;
+ }
+#endif
+
+ return retval;
+}
+
+
+
+BOOL INTERNAL SetLink (lpobj, hinfo, lpLpClass)
+LPOBJECT_LE lpobj;
+HANDLE hinfo;
+LPSTR FAR * lpLpClass;
+{
+ LPSTR lpinfo;
+ char chVerb[2];
+ // If there exits a conversation, then terminate it.
+
+ if (!(lpinfo = GlobalLock (hinfo)))
+ return FALSE;
+
+ *lpLpClass = lpinfo;
+
+#if FIREWALLS
+ if (lpobj->pDocEdit)
+ ASSERT (!lpobj->pDocEdit->hClient, "unexpected client conv exists");
+#endif
+
+ lpobj->app = GlobalAddAtom (lpinfo);
+ SetExeAtom (lpobj);
+ lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
+
+// lpobj->aServer = GetAppAtom (lpinfo);
+
+ lpinfo += lstrlen (lpinfo) + 1;
+ lpobj->topic = GlobalAddAtom (lpinfo);
+ lpinfo += lstrlen (lpinfo) + 1;
+ if (*lpinfo)
+ lpobj->item = GlobalAddAtom (lpinfo);
+ else
+ lpobj->item = NULL;
+
+ if (lpobj->hLink) { // As the atoms have already changed,
+ GlobalFree (lpobj->hLink); // lpobj->hLink becomes irrelevant.
+ lpobj->hLink = NULL;
+ }
+
+ if (lpinfo)
+ GlobalUnlock(hinfo);
+
+ if (!lpobj->app)
+ return FALSE;
+
+ if (!lpobj->topic && (lpobj->head.ctype == CT_LINK))
+ return FALSE;
+
+ lpobj->hLink = DuplicateGlobal (hinfo, GMEM_MOVEABLE);
+ return TRUE;
+}
+
+
+
+HANDLE INTERNAL GetLink (lpobj)
+LPOBJECT_LE lpobj;
+{
+ HANDLE hLink = NULL;
+ LPSTR lpLink;
+ int len;
+ WORD size;
+
+ if (lpobj->hLink)
+ return lpobj->hLink;
+
+ size = 4; // three nulls and one null at the end
+ size += GlobalGetAtomLen (lpobj->app);
+ size += GlobalGetAtomLen (lpobj->topic);
+ size += GlobalGetAtomLen (lpobj->item);
+
+ if (!(hLink = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size)))
+ return NULL;
+
+ if (!(lpLink = GlobalLock (hLink))) {
+ GlobalFree (hLink);
+ return NULL;
+ }
+
+ len = (int) GlobalGetAtomName (lpobj->app, lpLink, size);
+ lpLink += ++len;
+
+ len = (int) GlobalGetAtomName (lpobj->topic, lpLink, (size -= len));
+ lpLink += ++len;
+
+ if (!lpobj->item)
+ *lpLink = NULL;
+ else {
+ len = (int) GlobalGetAtomName (lpobj->item, lpLink, size - len);
+ lpLink += len;
+ }
+
+ *++lpLink = NULL; // put another null the end
+ GlobalUnlock (hLink);
+ return (lpobj->hLink = hLink);
+
+}
+
+
+void FARINTERNAL SetEmbeddedTopic (lpobj)
+LPOBJECT_LE lpobj;
+{
+ LPCLIENTDOC lpdoc;
+ char buf[MAX_STR];
+ char buf1[MAX_STR];
+ LPSTR lpstr, lptmp;
+ int len;
+
+ if (lpobj->topic)
+ GlobalDeleteAtom (lpobj->topic);
+
+ if (lpobj->aNetName) {
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = NULL;
+ }
+
+ lpobj->cDrive = NULL;
+ lpobj->dwNetInfo = NULL;
+ lpobj->head.ctype = CT_EMBEDDED;
+
+ lpdoc = (LPCLIENTDOC) lpobj->head.lhclientdoc;
+ lpstr = (LPSTR) buf;
+ lptmp = (LPSTR) buf1;
+ ASSERT(lpdoc->aDoc, "lpdoc->aDoc is null");
+ GlobalGetAtomName (lpdoc->aDoc, lpstr, sizeof(buf));
+
+ // strip the path
+ lpstr += (len = lstrlen(lpstr));
+ while (--lpstr != (LPSTR) buf) {
+ if ((*lpstr == '\\') || (*lpstr == ':')) {
+ lpstr++;
+ break;
+ }
+ }
+
+ GlobalGetAtomName (lpdoc->aClass, lptmp, sizeof(buf1));
+ lstrcat (lptmp, "%");
+ lstrcat (lptmp, lpstr);
+ lstrcat (lptmp, "%");
+ lpstr = lptmp;
+ lptmp += lstrlen (lptmp);
+
+ if (lpobj->head.aObjName) {
+ GlobalGetAtomName (lpobj->head.aObjName, lptmp, sizeof(buf)-(len+1));
+ }
+
+ if ((embStr[EMB_ID_INDEX] += 1) > '9') {
+ embStr[EMB_ID_INDEX] = '0';
+ if ((embStr[EMB_ID_INDEX - 1] += 1) > '9') {
+ embStr[EMB_ID_INDEX - 1] = '0';
+ if ((embStr[EMB_ID_INDEX - 2] += 1) > '9')
+ embStr[EMB_ID_INDEX - 2] = '0';
+ }
+ }
+
+ lstrcat (lptmp, embStr);
+
+ lpobj->topic = GlobalAddAtom (lpstr);
+
+ // Topic, item have changed, lpobj->hLink is out of date.
+ if (lpobj->hLink) {
+ GlobalFree (lpobj->hLink);
+ lpobj->hLink = NULL;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// //
+// Routines related to the asynchronous processing. //
+// //
+/////////////////////////////////////////////////////////////////////
+
+void NextAsyncCmd (lpobj, mainRtn)
+LPOBJECT_LE lpobj;
+WORD mainRtn;
+{
+ lpobj->mainRtn = mainRtn;
+ lpobj->subRtn = 0;
+
+}
+
+void InitAsyncCmd (lpobj, cmd, mainRtn)
+LPOBJECT_LE lpobj;
+WORD cmd;
+WORD mainRtn;
+{
+ lpobj->asyncCmd = cmd;
+ lpobj->mainErr = OLE_OK;
+ lpobj->mainRtn = mainRtn;
+ lpobj->subRtn = 0;
+ lpobj->subErr = 0;
+ lpobj->bAsync = 0;
+ lpobj->endAsync = 0;
+ lpobj->errHint = 0;
+}
+
+void FARINTERNAL FarInitAsyncCmd (lpobj, cmd, mainRtn)
+LPOBJECT_LE lpobj;
+WORD cmd;
+WORD mainRtn;
+{
+ return (InitAsyncCmd(lpobj, cmd, mainRtn));
+}
+
+
+OLESTATUS EndAsyncCmd (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ OLESTATUS olderr;
+
+
+ if (!lpobj->endAsync) {
+ lpobj->asyncCmd = OLE_NONE;
+ return OLE_OK;
+ }
+
+
+ // this is an asynchronous operation. Send callback with or without
+ // error.
+
+ switch (lpobj->asyncCmd) {
+
+ case OLE_DELETE:
+ break;
+
+ case OLE_COPYFROMLNK:
+ case OLE_CREATEFROMFILE:
+ // change the topic name to embedded.
+ SetEmbeddedTopic (lpobj);
+ break;
+
+ case OLE_LOADFROMSTREAM:
+ case OLE_LNKPASTE:
+ case OLE_RUN:
+ case OLE_SHOW:
+ case OLE_ACTIVATE:
+ case OLE_UPDATE:
+ case OLE_CLOSE:
+ case OLE_RECONNECT:
+ case OLE_CREATELINKFROMFILE:
+ case OLE_CREATEINVISIBLE:
+ case OLE_CREATE:
+ case OLE_CREATEFROMTEMPLATE:
+ case OLE_SETUPDATEOPTIONS:
+ case OLE_SERVERUNLAUNCH:
+ case OLE_SETDATA:
+ case OLE_REQUESTDATA:
+ case OLE_OTHER:
+ break;
+
+ case OLE_EMBPASTE:
+ lpobj->mainErr = OLE_OK;
+ break;
+
+ default:
+ DEBUG_OUT ("unexpected maincmd", 0);
+ break;
+
+ }
+
+ lpobj->bAsync = FALSE;
+ lpobj->endAsync = FALSE;
+ lpobj->oldasyncCmd = lpobj->asyncCmd;
+ olderr = lpobj->mainErr;
+ lpobj->asyncCmd = OLE_NONE; // no async command in progress.
+
+ if (lpobj->head.lpclient)
+ ContextCallBack (lpobj, OLE_RELEASE);
+
+ lpobj->mainErr = OLE_OK;
+ return olderr;
+}
+
+
+BOOL ProcessErr (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ if (lpobj->subErr == OLE_OK)
+ return FALSE;
+
+ if (lpobj->mainErr == OLE_OK)
+ lpobj->mainErr = lpobj->subErr;
+
+ lpobj->subErr = OLE_OK;
+ return TRUE;
+}
+
+
+void ScheduleAsyncCmd (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ // replacs this with direct proc jump later on.
+#ifdef FIREWALLS
+ ASSERT (lpobj->bAsync, "Not an asynchronous command");
+#endif
+ lpobj->bAsync = FALSE;
+
+ // if the object is active and we do pokes we go thru this path
+ // !!! We may have to go thru the endasynccmd.
+
+ if ((lpobj->asyncCmd == OLE_OTHER)
+ || ((lpobj->asyncCmd == OLE_SETDATA) && !lpobj->mainRtn)) {
+ lpobj->endAsync = TRUE;
+ lpobj->mainErr = lpobj->subErr;
+ EndAsyncCmd (lpobj);
+ if (lpobj->bUnlaunchLater) {
+ lpobj->bUnlaunchLater = FALSE;
+ CallEmbLnkDelete(lpobj);
+ }
+
+ return;
+ }
+
+ switch (lpobj->mainRtn) {
+
+ case EMBLNKDELETE:
+ EmbLnkDelete (lpobj);
+ break;
+
+ case LNKOPENUPDATE:
+ LnkOpenUpdate (lpobj);
+ break;
+
+ case DOCSHOW:
+ DocShow (lpobj);
+ break;
+
+
+ case EMBOPENUPDATE:
+ EmbOpenUpdate (lpobj);
+ break;
+
+
+ case EMBLNKCLOSE:
+ EmbLnkClose (lpobj);
+ break;
+
+ case LNKSETUPDATEOPTIONS:
+ LnkSetUpdateOptions (lpobj);
+ break;
+
+ case LNKCHANGELNK:
+ LnkChangeLnk (lpobj);
+ break;
+
+ case REQUESTDATA:
+ RequestData (lpobj, NULL);
+ break;
+
+ default:
+ DEBUG_OUT ("Unexpected asyn command", 0);
+ break;
+ }
+
+ return;
+}
+
+void SetNetDrive (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR];
+
+ if (GlobalGetAtomName (lpobj->topic, buf, sizeof(buf))
+ && (buf[1] == ':')) {
+ AnsiUpperBuff ((LPSTR) buf, 1);
+ lpobj->cDrive = buf[0];
+ }
+}
+
+HANDLE GetNetNameHandle (lpobj)
+LPOBJECT_LE lpobj;
+{
+ HANDLE hNetName;
+ LPSTR lpNetName;
+ WORD size;
+
+ if (!(size = GlobalGetAtomLen (lpobj->aNetName)))
+ return NULL;
+
+ size++;
+ if (!(hNetName = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size)))
+ return NULL;
+
+ if (lpNetName = GlobalLock (hNetName)) {
+ GlobalUnlock (hNetName);
+ if (GlobalGetAtomName(lpobj->aNetName, lpNetName, size))
+ return hNetName;
+ }
+
+ // error case
+ GlobalFree (hNetName);
+ return NULL;
+}
+
+BOOL AreTopicsEqual (lpobj1, lpobj2)
+LPOBJECT_LE lpobj1;
+LPOBJECT_LE lpobj2;
+{
+ char buf1[MAX_STR];
+ char buf2[MAX_STR];
+
+ if (lpobj1->aNetName != lpobj2->aNetName)
+ return FALSE;
+
+ if (!lpobj1->aNetName) {
+ if (lpobj1->topic == lpobj2->topic)
+ return TRUE;
+
+ return FALSE;
+ }
+
+ if (!GlobalGetAtomName (lpobj1->topic, buf1, MAX_STR))
+ return FALSE;
+
+ if (!GlobalGetAtomName (lpobj2->topic, buf2, MAX_STR))
+ return FALSE;
+
+ if (!lstrcmpi (&buf1[1], &buf2[1]))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+ATOM FARINTERNAL wAtomCat (
+ATOM a1,
+ATOM a2)
+{
+ char buf[MAX_STR+MAX_STR];
+ LPSTR lpBuf = (LPSTR)buf;
+
+ if (!GlobalGetAtomName (a1, lpBuf, MAX_STR+MAX_STR))
+ return NULL;
+
+ lpBuf += lstrlen(lpBuf);
+
+ if (!GlobalGetAtomName(a2, lpBuf, MAX_STR))
+ return NULL;
+
+ return GlobalAddAtom ((LPSTR) buf);
+}
diff --git a/private/mvdm/wow16/ole/client/ledde.c b/private/mvdm/wow16/ole/client/ledde.c
new file mode 100644
index 000000000..648d92c82
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/ledde.c
@@ -0,0 +1,2594 @@
+/****************************** Module Header ******************************\
+* Module Name: LEDDE.C
+*
+* Purpose: ?????
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../1990,91) Designed and coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dde.h"
+#include "dll.h"
+
+#define LN_FUDGE 16 // [],(), 3 * 3 (2 double quotes and comma)
+#define RUNITEM
+
+#define OLEVERB_CONNECT 0xFFFF
+
+// Definitions for sending the server sys command.
+char *srvrSysCmd[] = {"StdNewFromTemplate",
+ "StdNewDocument",
+ "StdEditDocument",
+ "StdOpenDocument"
+ };
+
+#define EMB_ID_INDEX 11 // index of ones digit in #00
+extern char embStr[];
+extern BOOL gbCreateInvisible;
+extern BOOL gbLaunchServer;
+
+extern ATOM aMSDraw;
+
+extern BOOL (FAR PASCAL *lpfnIsTask) (HANDLE);
+
+// !!! set error hints
+
+OLESTATUS FARINTERNAL LeDoVerb (lpobj, verb, fShow, fActivate)
+LPOBJECT_LE lpobj;
+WORD verb;
+BOOL fShow;
+BOOL fActivate;
+{
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if (!QueryOpen(lpobj))
+ return OLE_OK;
+
+ lpobj->verb = verb;
+ lpobj->fCmd = ACT_DOVERB;
+
+ if (fActivate)
+ lpobj->fCmd |= ACT_ACTIVATE;
+
+ if (fShow)
+ lpobj->fCmd |= ACT_SHOW;
+
+ InitAsyncCmd (lpobj, OLE_RUN, DOCSHOW);
+ return DocShow (lpobj);
+}
+
+
+
+OLESTATUS FARINTERNAL LeShow (lpobj, fActivate)
+LPOBJECT_LE lpobj;
+BOOL fActivate;
+{
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if (!QueryOpen(lpobj))
+ return OLE_OK;
+
+ lpobj->fCmd = ACT_SHOW;
+ InitAsyncCmd (lpobj, OLE_SHOW, DOCSHOW);
+ return DocShow (lpobj);
+}
+
+
+// DocShow : If the server is connected, show the item
+// for editing. For embedded objects us NULL Item.
+OLESTATUS DocShow (lpobj)
+LPOBJECT_LE lpobj;
+{
+ switch (lpobj->subRtn) {
+
+ case 0:
+ SendStdShow (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+ ProcessErr (lpobj);
+ return EndAsyncCmd (lpobj);
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+void SendStdShow (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ WORD len;
+ WORD size;
+ LPSTR lpdata = NULL;
+ HANDLE hdata = NULL;
+ BOOL bShow;
+
+ lpobj->subErr = OLE_OK;
+
+ if (lpobj->verb == OLEVERB_CONNECT) {
+ lpobj->verb = NULL;
+ return;
+ }
+
+ if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB)))
+ return;
+
+ if (bShow = (!lpobj->bOleServer || !(lpobj->fCmd & ACT_DOVERB))) {
+
+ // show is off, do not show the server.
+ if (!(lpobj->fCmd & ACT_SHOW))
+ return;
+
+ SETERRHINT(lpobj, OLE_ERROR_SHOW);
+ // and 18 "[StdShowItem(\"")for 5 extra for ",FALSE
+ len = 18 + 7;
+ } else {
+ // 19 for the string [StdDoVerbItem(\"") and
+ // 18 extra is for ",000,FALSE,FALSE
+ SETERRHINT(lpobj, OLE_ERROR_DOVERB);
+ len = 19 + 18;
+ }
+
+ len += GlobalGetAtomLen (lpobj->item);
+
+ len += 4; // ")]" + NULL
+
+ hdata = GlobalAlloc (GMEM_DDESHARE, size = len);
+ if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+ if (bShow)
+ lstrcpy (lpdata, "[StdShowItem(\"");
+ else
+ lstrcpy (lpdata, "[StdDoVerbItem(\"");
+
+ len = lstrlen (lpdata);
+
+ if (lpobj->item)
+ GlobalGetAtomName (lpobj->item , lpdata + len, size - len);
+
+ if (!bShow) {
+
+ lstrcat (lpdata, (LPSTR)"\",");
+ // assume that the number of verbs are < 10
+
+ len = lstrlen (lpdata);
+#ifdef FIREWALLS
+ ASSERT ( (lpobj->verb & 0x000f) < 9 , "Verb value more than 9");
+#endif
+ lpdata += len;
+ *lpdata++ = (char)((lpobj->verb & 0x000f) + '0');
+ *lpdata = 0;
+
+ if (lpobj->fCmd & ACT_SHOW)
+ lstrcat (lpdata, (LPSTR) ",TRUE");
+ else
+ lstrcat (lpdata, (LPSTR) ",FALSE");
+ // StdVerbItem (item, verb, TRUE
+ // add TRUE/FALSE constant for the activate
+ if (!(lpobj->fCmd & ACT_ACTIVATE))
+ lstrcat (lpdata, (LPSTR) ",TRUE)]");
+ else
+ lstrcat (lpdata, (LPSTR) ",FALSE)]");
+ // [StdDoVerb ("item", verb, FALSE, FALSE)]
+ } else
+ lstrcat (lpdata, (LPSTR)"\")]");
+ // apps like excel and wingraph do not suuport activate at
+ // item level.
+
+
+ GlobalUnlock (hdata);
+ DocExecute (lpobj, hdata);
+ return;
+
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+
+ lpobj->subErr = OLE_ERROR_MEMORY;
+ return;
+}
+
+
+
+OLESTATUS FARINTERNAL LeQueryOpen (LPOBJECT_LE lpobj)
+{
+
+ if (QueryOpen(lpobj))
+ return OLE_OK;
+ else
+ return OLE_ERROR_NOT_OPEN;
+
+}
+
+
+BOOL INTERNAL QueryOpen (LPOBJECT_LE lpobj)
+{
+
+ if (lpobj->pDocEdit && lpobj->pDocEdit->hClient) {
+ if (IsServerValid (lpobj))
+ return TRUE;
+ // destroy the windows and pretend as if the server was never
+ // connected.
+
+ DestroyWindow (lpobj->pDocEdit->hClient);
+ if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
+ DestroyWindow (lpobj->pSysEdit->hClient);
+
+ }
+ return FALSE;
+}
+
+
+
+OLESTATUS FARINTERNAL LeActivate (lpobj, verb, fShow, fActivate, hWnd, lprc)
+LPOBJECT_LE lpobj;
+WORD verb;
+BOOL fShow;
+BOOL fActivate;
+HWND hWnd;
+LPRECT lprc;
+{
+
+ lpobj->verb = verb;
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return EmbOpen (lpobj, fShow, fActivate, hWnd, lprc);
+
+#ifdef FIREWALLS
+ ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
+#endif
+ return LnkOpen (lpobj, fShow, fActivate, hWnd, lprc);
+
+}
+
+
+OLESTATUS FARINTERNAL LeUpdate (lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return EmbUpdate (lpobj);
+
+#ifdef FIREWALLS
+ ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
+#endif
+ return LnkUpdate (lpobj);
+}
+
+
+
+OLESTATUS FARINTERNAL EmbOpen (lpobj, fShow, fActivate, hWnd, lprc)
+LPOBJECT_LE lpobj;
+BOOL fShow;
+BOOL fActivate;
+HWND hWnd;
+LPRECT lprc;
+{
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if(QueryOpen (lpobj))
+ return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);
+
+ // show the window
+ // advise for data only on close
+ // and shut down the conv after the advises.
+
+ lpobj->fCmd = LN_EMBACT | ACT_DOVERB | ACT_ADVISE | ACT_CLOSE;
+ if (fActivate)
+ lpobj->fCmd |= ACT_ACTIVATE;
+
+ if (fShow)
+ lpobj->fCmd |= ACT_SHOW;
+
+ InitAsyncCmd (lpobj, OLE_ACTIVATE, EMBOPENUPDATE);
+ return EmbOpenUpdate (lpobj);
+
+}
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FARINTERNAL EmbUpdate (lpobj)
+*
+* This function updates an EMB object. If the server is connected
+* simply send a request for the native as well as the display formats.
+* If the server is connected, then tries to start the conversationa and
+* get the data. If the conversation fails, then load the server and
+* start the conversation. The embeded objects may have links in it.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+
+OLESTATUS FARINTERNAL EmbUpdate (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ // if we are loading the server, then definitly unload.
+ // if the connection is established, then unload if it is
+ // to be unloaded, when all the previous requests are satisfied.
+
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ lpobj->fCmd = LN_EMBACT | ACT_REQUEST | (QueryOpen(lpobj) ? 0 : ACT_UNLAUNCH);
+ InitAsyncCmd (lpobj, OLE_UPDATE, EMBOPENUPDATE);
+ return EmbOpenUpdate (lpobj);
+
+}
+
+
+
+OLESTATUS FARINTERNAL EmbOpenUpdate (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ switch (lpobj->subRtn) {
+
+ case 0:
+
+ SKIP_TO (QueryOpen(lpobj), step6);
+ SendSrvrMainCmd (lpobj, lpobj->lptemplate);
+ lpobj->lptemplate = NULL;
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ // Init doc conversation should set the failure error
+ if (!InitDocConv (lpobj, !POPUP_NETDLG))
+ goto errRtn;
+
+ // If there is no native data, do not do any poke.
+ // creates will not have any poke data to start with
+
+ SKIP_TO (!(lpobj->hnative), step6);
+ PokeNativeData (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 2:
+ if (ProcessErr (lpobj))
+ goto errRtn;
+ // Now poke the hostnames etc stuff.
+ PokeHostNames (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 3:
+
+ // do not worry about the poke hostname errors
+ PokeTargetDeviceInfo (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 4:
+
+ PokeDocDimensions (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 5:
+
+ PokeColorScheme (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+
+ case 6:
+
+ step6:
+
+ // wingraph does not accept the doc dimensions
+ // after sttedit.
+ CLEAR_STEP_ERROR (lpobj);
+ SETSTEP (lpobj, 6);
+ STEP_NOP (lpobj);
+ // step_nop simply increments the step numebr
+ // merge the steps later on
+
+
+
+ case 7:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step11);
+ lpobj->optUpdate = oleupdate_onsave;
+ lpobj->pDocEdit->nAdviseSave = 0;
+ AdviseOn (lpobj, cfNative, aSave);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 8:
+
+ // do not go for errors on /save. Some servers may not support
+ // this.
+
+ CLEAR_STEP_ERROR (lpobj);
+ AdvisePict (lpobj, aSave);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 9:
+
+ // do not worry about the error case for save. Ignore them
+
+ CLEAR_STEP_ERROR (lpobj);
+ lpobj->optUpdate = oleupdate_onclose;
+ lpobj->pDocEdit->nAdviseClose = 0;
+ AdviseOn (lpobj, cfNative, aClose);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+
+ case 10:
+ if (ProcessErr(lpobj))
+ goto errRtn;
+
+ AdvisePict (lpobj, aClose);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 11:
+
+ step11:
+ SETSTEP (lpobj, 11);
+ if (ProcessErr(lpobj))
+ goto errRtn;
+
+ SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step13);
+
+ // we don't want to send OLE_CHANGED when we get this data, if we
+ // are going to request for picture data also.
+ lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
+ RequestOn (lpobj, cfNative);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ // If request pict fails, then native and pict are
+ // not in sync.
+
+ case 12:
+ if (ProcessErr(lpobj))
+ goto errRtn;
+
+ lpobj->pDocEdit->bCallLater = FALSE;
+ RequestPict (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+
+ case 13:
+
+ step13:
+ SETSTEP(lpobj, 13);
+
+ if (ProcessErr(lpobj))
+ goto errRtn;
+
+ SendStdShow (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 14:
+
+
+ if (ProcessErr(lpobj))
+ goto errRtn;
+
+ SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step15);
+ return EndAsyncCmd (lpobj);
+
+
+ case 15:
+
+errRtn:
+ step15:
+ ProcessErr (lpobj);
+
+ if ((lpobj->asyncCmd == OLE_UPDATE)
+ && (!(lpobj->fCmd & ACT_UNLAUNCH)))
+ return EndAsyncCmd (lpobj);
+
+ // if we launched and error, unlaunch (send stdexit)
+ NextAsyncCmd (lpobj, EMBLNKDELETE);
+ lpobj->fCmd |= ACT_UNLAUNCH;
+ EmbLnkDelete (lpobj);
+ return lpobj->mainErr;
+
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+
+
+OLESTATUS FARINTERNAL LnkOpen (lpobj, fShow, fActivate, hWnd, lprc)
+LPOBJECT_LE lpobj;
+BOOL fShow;
+BOOL fActivate;
+HWND hWnd;
+LPRECT lprc;
+{
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if(QueryOpen (lpobj))
+ return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);
+
+ // Just end the system conversation. we are not unloading
+ // this instance at all.
+
+ lpobj->fCmd = LN_LNKACT | ACT_DOVERB;
+
+ if (lpobj->optUpdate == oleupdate_always)
+ lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
+ else if (lpobj->optUpdate == oleupdate_onsave)
+ lpobj->fCmd |= ACT_ADVISE;
+
+ if (fActivate)
+ lpobj->fCmd |= ACT_ACTIVATE;
+
+ if (fShow)
+ lpobj->fCmd |= ACT_SHOW;
+
+ InitAsyncCmd (lpobj, OLE_ACTIVATE, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+
+}
+
+
+OLESTATUS FARINTERNAL LnkUpdate (lpobj)
+LPOBJECT_LE lpobj;
+{
+ // if we are loading the server, then definitly unload.
+ // if the connection is established, then unload if it is
+ // to be unloaded, when all the previous requests are satisfied.
+
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ lpobj->fCmd = LN_LNKACT | ACT_REQUEST | (QueryOpen (lpobj) ? 0 : ACT_UNLAUNCH);
+ InitAsyncCmd (lpobj, OLE_UPDATE, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+}
+
+
+
+OLESTATUS FARINTERNAL LnkOpenUpdate (lpobj)
+LPOBJECT_LE lpobj;
+{
+ switch (lpobj->subRtn) {
+
+ case 0:
+
+ SKIP_TO (QueryOpen(lpobj), step2);
+ InitDocConv (lpobj, !POPUP_NETDLG);
+ if (QueryOpen(lpobj)) {
+ if (lpobj->app == aPackage)
+ RemoveLinkStringFromTopic (lpobj);
+ goto step2;
+ }
+
+ SendSrvrMainCmd (lpobj, NULL);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+
+ case 1:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ if (lpobj->app == aPackage)
+ RemoveLinkStringFromTopic (lpobj);
+
+ if (!InitDocConv (lpobj, POPUP_NETDLG)) {
+ lpobj->subErr = OLE_ERROR_OPEN;
+ goto errRtn;
+ }
+
+ case 2:
+
+ step2:
+
+ SETSTEP (lpobj, 2);
+ PokeTargetDeviceInfo (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 3:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step6);
+ SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step4);
+ AdviseOn (lpobj, cfNative, NULL);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 4:
+ step4:
+ SETSTEP (lpobj, 4);
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ AdvisePict (lpobj, NULL);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 5:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ // Now send advise for renaming the documnet.
+ AdviseOn (lpobj, cfBinary, aStdDocName);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 6:
+
+ step6:
+ // if name advise fails ignore it
+ SETSTEP (lpobj, 6);
+
+ CLEAR_STEP_ERROR (lpobj);
+ SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step8);
+ SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step7);
+
+ // we don't want to send OLE_CHANGED when we get this data, if we
+ // are going to request for picture data also.
+ lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
+ RequestOn (lpobj, cfNative);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 7:
+ step7:
+
+ SETSTEP (lpobj, 7);
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ lpobj->pDocEdit->bCallLater = FALSE;
+ RequestPict (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 8:
+
+ step8:
+
+ SETSTEP (lpobj, 8);
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ SKIP_TO (!(lpobj->fCmd & ACT_TERMDOC), step10);
+ // terminate the document conversataion.
+ TermDocConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 9:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ // delete the server edit block
+ DeleteDocEdit (lpobj);
+
+ SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
+ return EndAsyncCmd (lpobj);
+
+ case 10:
+
+ step10:
+ SETSTEP (lpobj, 10);
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ SKIP_TO (!(lpobj->fCmd & ACT_TERMSRVR), step12);
+
+ // terminate the server conversataion.
+ TermSrvrConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 11:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ // delete the server edit block
+ DeleteSrvrEdit (lpobj);
+ return EndAsyncCmd (lpobj);
+
+
+ case 12:
+
+ step12:
+ SETSTEP (lpobj, 12);
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ SendStdShow (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 13:
+
+ if (ProcessErr (lpobj))
+ goto errRtn;
+ SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
+ return EndAsyncCmd (lpobj);
+
+
+ case 14:
+
+ errRtn:
+ step14:
+ ProcessErr (lpobj);
+
+ if ((lpobj->asyncCmd == OLE_UPDATE)
+ && (!(lpobj->fCmd & ACT_UNLAUNCH)))
+ return EndAsyncCmd (lpobj);
+
+ // if we launched and error, unlaunch (send stdexit)
+ NextAsyncCmd (lpobj, EMBLNKDELETE);
+ lpobj->fCmd |= ACT_UNLAUNCH;
+ EmbLnkDelete (lpobj);
+ return lpobj->mainErr;
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+
+OLESTATUS EmbLnkClose (lpobj)
+LPOBJECT_LE lpobj;
+{
+ switch (lpobj->subRtn) {
+
+ case 0:
+ TermDocConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+
+ // delete the edit block
+ DeleteDocEdit (lpobj);
+ TermSrvrConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 2:
+
+ // Do not set any errors, just delete the object.
+ // delete the server edit block
+ DeleteSrvrEdit (lpobj);
+ return EndAsyncCmd (lpobj);
+
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+OLESTATUS FARINTERNAL LeClose (lpobj)
+LPOBJECT_LE lpobj;
+{
+ PROBE_ASYNC (lpobj);
+ if (IS_SVRCLOSING(lpobj))
+ return OLE_OK;
+
+
+ lpobj->fCmd = 0;
+
+ if (lpobj->head.ctype == CT_EMBEDDED) {
+ InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKDELETE);
+ return EmbLnkDelete (lpobj);
+ }
+ else {
+ InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKCLOSE);
+ return EmbLnkClose (lpobj);
+ }
+}
+
+
+
+OLESTATUS FARINTERNAL LeReconnect (lpobj)
+LPOBJECT_LE lpobj;
+{
+ // check for the existing conversation.
+ // if the client window is non-null, then
+ // connection exits.
+
+ if (lpobj->head.ctype != CT_LINK)
+ return OLE_ERROR_NOT_LINK; // allow only for linked
+
+ PROBE_ASYNC (lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if (QueryOpen (lpobj))
+ return OLE_OK;
+
+ // start just the conversation. Do not load
+ // the app.
+
+ if (!InitDocConv (lpobj, !POPUP_NETDLG))
+ return OLE_OK; // document is not loaded , it is OK.
+
+ lpobj->fCmd = LN_LNKACT;
+ if (lpobj->optUpdate == oleupdate_always)
+ lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
+
+ InitAsyncCmd (lpobj, OLE_RECONNECT, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+}
+
+
+
+
+OLESTATUS INTERNAL PokeNativeData (lpobj)
+LPOBJECT_LE lpobj;
+{
+ SETERRHINT(lpobj, OLE_ERROR_POKE_NATIVE);
+ return SendPokeData (lpobj,
+ lpobj->item,
+ lpobj->hnative,
+ cfNative);
+}
+
+
+
+
+BOOL INTERNAL PostMessageToServer (pedit, msg, lparam)
+PEDIT_DDE pedit;
+WORD msg;
+LONG lparam;
+{
+
+#ifdef FIREWALLS
+ ASSERT (pedit, "Dde edit block is NULL");
+#endif
+ // save the lparam and msg fpr possible reposting incase of error.
+
+ // we are in abort state. no messages except for terminate.
+
+ if (pedit->bAbort && msg != WM_DDE_TERMINATE)
+ return FALSE;
+
+ pedit->lParam = lparam;
+ pedit->msg = msg;
+
+ if (pedit->hClient && pedit->hServer) {
+ while (TRUE){
+ if (!IsWindowValid (pedit->hServer))
+ return FALSE;
+ if (PostMessage (pedit->hServer, msg, pedit->hClient, lparam) == FALSE)
+ Yield ();
+ else
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+OLESTATUS FARINTERNAL LeCreateFromTemplate (lpclient, lptemplate, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPOLECLIENT lpclient;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ char buf[MAX_STR];
+
+ if (!MapExtToClass (lptemplate, (LPSTR)buf, MAX_STR))
+ return OLE_ERROR_CLASS;
+
+ return CreateFromClassOrTemplate (lpclient, (LPSTR) buf, lplpoleobject,
+ optRender, cfFormat, LN_TEMPLATE, lptemplate,
+ lhclientdoc, lpobjname);
+}
+
+
+OLESTATUS FARINTERNAL LeCreate (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpclass;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ if (gbCreateInvisible) {
+ // this is in fact a call for invisible create
+ return LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname,
+ lplpoleobject, optRender, cfFormat, gbLaunchServer);
+ }
+
+ return CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject,
+ optRender, cfFormat, LN_NEW, NULL,
+ lhclientdoc, lpobjname);
+}
+
+
+
+OLESTATUS FARINTERNAL CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject, optRender, cfFormat, lnType, lptemplate, lhclientdoc, lpobjname)
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+WORD lnType;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ LPOBJECT_LE lpobj = NULL;
+ ATOM aServer;
+ char chVerb [2];
+
+ if (!(aServer = GetAppAtom (lpclass)))
+ return OLE_ERROR_CLASS;
+
+ if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
+ GlobalDeleteAtom (aServer);
+ goto errRtn;
+ }
+
+ // Now set the server.
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->app = GlobalAddAtom (lpclass);
+ SetEmbeddedTopic (lpobj);
+ lpobj->item = NULL;
+ lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
+ lpobj->aServer = aServer;
+
+ // launch the app and start the system conversation.
+
+ if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
+ optRender, cfFormat, lpclass))
+ goto errRtn;
+
+
+ // show the window. Advise for data and close on receiving data
+ lpobj->fCmd = lnType | ACT_SHOW | ACT_ADVISE | ACT_CLOSE;
+ InitAsyncCmd (lpobj, lptemplate? OLE_CREATEFROMTEMPLATE : OLE_CREATE, EMBOPENUPDATE);
+ *lplpoleobject = (LPOLEOBJECT)lpobj;
+
+ lpobj->lptemplate = lptemplate;
+
+ if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
+ return retval;
+
+ // If there is error afterwards, then the client app should call
+ // to delete the object.
+
+errRtn:
+
+ // for error termination OleDelete will terminate any conversation
+ // in action.
+
+ if (lpobj) {
+ // This oledelete will not result in asynchronous command.
+ OleDelete ((LPOLEOBJECT)lpobj);
+ *lplpoleobject = NULL;
+ }
+
+ return retval;
+}
+
+
+
+OLESTATUS FARINTERNAL CreateEmbLnkFromFile (lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, objType)
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LPSTR lpitem;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ LPOBJECT_LE lpobj = NULL;
+ ATOM aServer;
+ char buf[MAX_STR];
+ OLE_RELEASE_METHOD releaseMethod;
+ WORD wFlags = NULL;
+ char chVerb[2];
+
+ if (!lpclass && (lpclass = (LPSTR) buf)
+ && !MapExtToClass (lpfile, (LPSTR)buf, MAX_STR))
+ return OLE_ERROR_CLASS;
+
+ if (!(aServer = GetAppAtom (lpclass)))
+ return OLE_ERROR_CLASS;
+
+ if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_LINK))) {
+ GlobalDeleteAtom (aServer);
+ goto errFileCreate;
+ }
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->app = GlobalAddAtom (lpclass);
+ lpobj->topic = GlobalAddAtom (lpfile);
+ lpobj->aServer = aServer;
+ lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
+ if ((retval = SetNetName (lpobj)) != OLE_OK)
+ goto errFileCreate;
+
+ if (lpitem)
+ lpobj->item = GlobalAddAtom (lpitem);
+
+ if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
+ optRender, cfFormat, lpclass)) {
+ retval = OLE_ERROR_MEMORY;
+ goto errFileCreate;
+ }
+
+ *lplpoleobject = (LPOLEOBJECT) lpobj;
+
+ if (objType == CT_EMBEDDED) {
+ releaseMethod = OLE_CREATEFROMFILE;
+ if ((optRender == olerender_format) && (cfFormat == cfNative))
+ wFlags = 0;
+ else
+ wFlags = ACT_NATIVE;
+ }
+ else {
+ // caller wants linked object to be created
+
+ // if no presentation data is requested and the link is to the whole
+ // file, then there is no need to launch the server.
+
+ if ((optRender == olerender_none) && !lpobj->item)
+ return FileExists (lpobj);
+
+ // we want to establish hot link
+ wFlags = ACT_ADVISE;
+ releaseMethod = OLE_CREATELINKFROMFILE;
+ }
+
+ lpobj->fCmd = LN_LNKACT | ACT_REQUEST | ACT_UNLAUNCH | wFlags;
+ InitAsyncCmd (lpobj, releaseMethod , LNKOPENUPDATE);
+
+ if ((retval = LnkOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
+ return retval;
+
+ // If there is error afterwards, then the client app should call
+ // to delete the object.
+
+
+errFileCreate:
+
+ if (lpobj) {
+ // This oledelete will not result in asynchronous command.
+ OleDelete ((LPOLEOBJECT)lpobj);
+ *lplpoleobject = NULL;
+ }
+
+ return retval;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, bActivate)
+//
+// Arguments:
+//
+// lpclient -
+// lpclass -
+// lhclientdoc -
+// lpobjname -
+// lplpoleobject -
+// optRender -
+// cfFormat -
+// fActivate -
+//
+// Returns:
+//
+// OLE_ERROR_CLASS -
+// OLE_OK -
+// EmbOpenUpdate (lpobj) -
+// retval -
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, fActivate)
+LPSTR lpclass;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+BOOL fActivate;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ LPOBJECT_LE lpobj = NULL;
+ ATOM aServer;
+ char chVerb [2];
+
+ if (!(aServer = GetAppAtom (lpclass)))
+ return OLE_ERROR_CLASS;
+
+ if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
+ GlobalDeleteAtom (aServer);
+ goto errRtn;
+ }
+
+ // Now set the server.
+
+ lpobj->head.lpclient = lpclient;
+ lpobj->app = GlobalAddAtom (lpclass);
+ lpobj->item = NULL;
+ lpobj->bOleServer = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
+ lpobj->aServer = aServer;
+ lpobj->lptemplate = NULL;
+ SetEmbeddedTopic (lpobj);
+
+ if (!CreatePictObject (lhclientdoc, lpobjname, lpobj,
+ optRender, cfFormat, lpclass))
+ goto errRtn;
+
+ *lplpoleobject = (LPOLEOBJECT)lpobj;
+
+ if (!fActivate)
+ return OLE_OK;
+
+ // show the window. Advise for data and close on receiving data
+ lpobj->fCmd = LN_NEW | ACT_ADVISE | ACT_CLOSE;
+ InitAsyncCmd (lpobj, OLE_CREATEINVISIBLE, EMBOPENUPDATE);
+
+ // launch the app and start the system conversation.
+ if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
+ return retval;
+
+ // If there is error afterwards, then the client app should call
+ // to delete the object.
+
+errRtn:
+
+ // for error termination OleDelete will terminate any conversation
+ // in action.
+
+ if (lpobj) {
+ // This oledelete will not result in asynchronous command.
+ OleDelete ((LPOLEOBJECT)lpobj);
+ *lplpoleobject = NULL;
+ }
+
+ return retval;
+}
+
+
+
+// LeSetUpdateOptions: sets the update options. If the server
+// is connectd then it unadvises for the current options and
+// advises for the new options.
+
+OLESTATUS FARINTERNAL LeSetUpdateOptions (lpobj, options)
+LPOBJECT_LE lpobj;
+OLEOPT_UPDATE options;
+{
+
+ PROBE_OLDLINK (lpobj);
+ PROBE_ASYNC (lpobj);
+
+ //!!! make sure the options are within range.
+
+ if (lpobj->head.ctype != CT_LINK)
+ return (OLE_ERROR_OBJECT);
+
+ if (options > oleupdate_oncall)
+ return OLE_ERROR_OPTION;
+
+ if (lpobj->optUpdate == options)
+ return OLE_OK;
+
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
+ lpobj->optUpdate = options;
+ return OLE_OK;
+ }
+
+ lpobj->optNew = options;
+ lpobj->fCmd = 0;
+ InitAsyncCmd (lpobj, OLE_SETUPDATEOPTIONS, LNKSETUPDATEOPTIONS);
+ return LnkSetUpdateOptions (lpobj);
+
+}
+
+OLESTATUS LnkSetUpdateOptions (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ switch (lpobj->subRtn) {
+
+ case 0:
+
+ if (lpobj->optUpdate == oleupdate_oncall)
+ goto step1;
+
+ // If the server is active then unadvise for old
+ // options.
+
+ UnAdvisePict (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+ step1:
+
+ SETSTEP (lpobj, 1);
+ ProcessErr (lpobj);
+
+ lpobj->optUpdate = lpobj->optNew;
+ if (lpobj->optUpdate == oleupdate_oncall)
+ goto step3;
+
+ AdvisePict (lpobj, NULL);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 2:
+ SETSTEP (lpobj, 2);
+ if (ProcessErr (lpobj))
+ goto errRtn;
+
+ if (lpobj->optUpdate == oleupdate_onsave)
+ goto step3;
+
+ RequestPict (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 3:
+ errRtn:
+ step3:
+ ProcessErr (lpobj);
+ return EndAsyncCmd (lpobj);
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+
+//AdvisePict: Sends advise for pict data
+
+void INTERNAL AdvisePict (lpobj, aAdvItem)
+LPOBJECT_LE lpobj;
+ATOM aAdvItem;
+{
+ int cftype;
+
+ if (cftype = GetPictType (lpobj))
+ AdviseOn (lpobj, cftype, aAdvItem);
+}
+
+
+//UnAdvisePict: Sends unadvise for pict data
+
+void INTERNAL UnAdvisePict (lpobj)
+LPOBJECT_LE lpobj;
+{
+ int cftype;
+ SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);
+ if (cftype = GetPictType (lpobj))
+ UnAdviseOn (lpobj, cftype);
+}
+
+// GetPictType: Given the object, returns the pict type.
+
+int INTERNAL GetPictType (lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (lpobj->lpobjPict)
+ return (int)(*lpobj->lpobjPict->lpvtbl->EnumFormats)
+ (lpobj->lpobjPict, NULL);
+ return NULL;
+}
+
+
+// AdviseOn : Sends advise for a given picture type
+// Send advise only if the advise options is not on call.
+
+void INTERNAL AdviseOn (lpobj, cftype, advItem)
+LPOBJECT_LE lpobj;
+int cftype;
+ATOM advItem;
+{
+ HANDLE hopt = NULL;
+ DDEADVISE FAR *lpopt = NULL;
+ ATOM item = NULL;
+ PEDIT_DDE pedit;
+ OLESTATUS retval;
+
+ if (cftype == (int)cfNative)
+ SETERRHINT (lpobj, OLE_ERROR_ADVISE_NATIVE);
+ else {
+ if (cftype == (int)cfBinary)
+ SETERRHINT (lpobj, OLE_ERROR_ADVISE_RENAME);
+ else
+ SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);
+
+ }
+
+ if (lpobj->optUpdate == oleupdate_oncall)
+ return;
+
+ if(!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE))))
+ goto errRtn;
+
+ retval = OLE_ERROR_MEMORY;
+ if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
+ goto errRtn;
+
+ pedit = lpobj->pDocEdit;
+ lpopt->fAckReq = TRUE;
+
+ // get data always. Currently there is no way for the
+ // deferred updates.
+
+ lpopt->fDeferUpd = 0;
+ lpopt->cfFormat = cftype;
+ GlobalUnlock (hopt);
+
+ pedit->hopt = hopt;
+
+ if (advItem == aStdDocName)
+ item = DuplicateAtom (advItem);
+ else
+ item = ExtendAtom (lpobj, lpobj->item);
+
+ retval = OLE_ERROR_COMM;
+ if (!PostMessageToServer(pedit, WM_DDE_ADVISE, MAKELONG (hopt, item)))
+ goto errRtn;
+
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "trying to post while termination")
+ ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
+#endif
+ pedit->awaitAck = AA_ADVISE;
+ lpobj->bAsync = TRUE;
+
+ if (advItem == aClose)
+ lpobj->pDocEdit->nAdviseClose++;
+ else if (advItem == aSave)
+ lpobj->pDocEdit->nAdviseSave++;
+
+ return;
+
+errRtn:
+
+ if (item)
+ GlobalDeleteAtom (item);
+
+ if (lpopt)
+ GlobalUnlock (hopt);
+
+ if (hopt)
+ GlobalFree (hopt);
+ lpobj->subErr = retval;
+
+ return ;
+
+
+}
+
+
+
+//UnAdviseOn: Sends unadvise for an item.
+void INTERNAL UnAdviseOn (lpobj, cftype)
+LPOBJECT_LE lpobj;
+int cftype;
+{
+ ATOM item;
+ PEDIT_DDE pedit;
+
+ pedit = lpobj->pDocEdit;
+ item = ExtendAtom (lpobj, lpobj->item);
+
+ if (!PostMessageToServer(pedit, WM_DDE_UNADVISE, MAKELONG (NULL, item)))
+ lpobj->subErr = OLE_ERROR_COMM;
+ else {
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "trying to post while termination")
+ ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
+#endif
+ lpobj->bAsync = TRUE;
+ pedit->awaitAck = AA_UNADVISE;
+ }
+}
+
+// RequestOn: Semd WM_DDE_REQUEST for the item of the
+// for a given type;
+
+void INTERNAL RequestOn (lpobj, cftype)
+LPOBJECT_LE lpobj;
+int cftype;
+{
+ ATOM item = NULL;
+ PEDIT_DDE pedit;
+ OLESTATUS retval = OLE_ERROR_COMM;
+
+ if (cftype == (int)cfNative)
+ SETERRHINT (lpobj, OLE_ERROR_REQUEST_NATIVE);
+ else
+ SETERRHINT (lpobj, OLE_ERROR_REQUEST_PICT);
+
+ pedit = lpobj->pDocEdit;
+
+ item = DuplicateAtom (lpobj->item);
+ if (!PostMessageToServer (pedit, WM_DDE_REQUEST, MAKELONG (cftype, item)))
+ goto errRtn;
+
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "trying to post while termination")
+ ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
+#endif
+
+ lpobj->bAsync = TRUE;
+ pedit->awaitAck = AA_REQUEST;
+ return;
+
+errRtn:
+
+ if (item)
+ GlobalDeleteAtom (item);
+ return ;
+
+}
+
+
+//RequestPict: Sends request for apicture type.
+void INTERNAL RequestPict (lpobj)
+LPOBJECT_LE lpobj;
+{
+ int cftype;
+
+ if (cftype = GetPictType (lpobj))
+ RequestOn (lpobj, cftype);
+}
+
+
+
+// LeSetHostNames: Sets the host names. If the server is connected
+// send the host names to the server.
+OLESTATUS FARINTERNAL LeSetHostNames (lpobj, lpclientName, lpdocName)
+LPOBJECT_LE lpobj;
+LPSTR lpclientName;
+LPSTR lpdocName;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+
+ if (lpobj->head.ctype != CT_EMBEDDED)
+ return OLE_ERROR_OBJECT;
+
+ PROBE_ASYNC (lpobj);
+ if ((retval = SetHostNamesHandle (lpobj, lpclientName, lpdocName))
+ != OLE_OK)
+ return retval;
+
+
+ // If the server is connected poke the hostnames
+ InitAsyncCmd (lpobj, OLE_OTHER, NULL);
+ if ((retval = PokeHostNames (lpobj)) != OLE_WAIT_FOR_RELEASE)
+ CLEARASYNCCMD(lpobj);
+
+ return retval;
+}
+
+
+
+OLESTATUS FARINTERNAL LeSetTargetDevice (lpobj, hdata)
+LPOBJECT_LE lpobj;
+HANDLE hdata;
+{
+ HANDLE hdup = NULL;
+ OLESTATUS retval;
+
+ PROBE_ASYNC (lpobj);
+
+ if (!hdata) {
+ // hdata == NULL means we should not make the target device sticky.
+ // This will give the flexibility to the client app. Note that this
+ // will not be effective till the next activation.
+ if (lpobj->htargetDevice) {
+ GlobalFree (lpobj->htargetDevice);
+ lpobj->htargetDevice = NULL;
+ }
+
+ return OLE_OK;
+ }
+
+ if(!(hdup = DuplicateGlobal (hdata, GMEM_MOVEABLE)))
+ return OLE_ERROR_MEMORY;
+
+ if (lpobj->htargetDevice)
+ GlobalFree (lpobj->htargetDevice);
+
+ lpobj->htargetDevice = hdup;
+ InitAsyncCmd (lpobj, OLE_OTHER, NULL);
+ if ((retval = PokeTargetDeviceInfo (lpobj)) != OLE_WAIT_FOR_RELEASE)
+ CLEARASYNCCMD(lpobj);
+
+ return retval;
+}
+
+
+
+OLESTATUS FARINTERNAL LeSetBounds(lpobj, lprcBounds)
+LPOBJECT_LE lpobj;
+LPRECT lprcBounds;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ HANDLE hdata = NULL;
+ LPBOUNDSRECT lprc = NULL;
+
+ PROBE_ASYNC (lpobj);
+
+ if (lpobj->head.ctype != CT_EMBEDDED)
+ return OLE_ERROR_OBJECT;
+
+ if(!(hdata = GlobalAlloc (GMEM_MOVEABLE, (WORD)sizeof (BOUNDSRECT))))
+ return OLE_ERROR_MEMORY;
+
+ if (!(lprc = (LPBOUNDSRECT)GlobalLock (hdata)))
+ goto errrtn;
+
+ // Now set the data
+
+ lprc->defaultWidth = lprcBounds->right - lprcBounds->left;;
+ lprc->defaultHeight = -(lprcBounds->bottom - lprcBounds->top);
+ lprc->maxWidth = lprcBounds->right - lprcBounds->left;;
+ lprc->maxHeight = -(lprcBounds->bottom - lprcBounds->top);
+
+ GlobalUnlock (hdata);
+
+ if (lpobj->hdocDimensions)
+ GlobalFree (lpobj->hdocDimensions);
+
+ lpobj->hdocDimensions = hdata;
+ InitAsyncCmd (lpobj, OLE_OTHER, NULL);
+ if ((retval = PokeDocDimensions (lpobj)) != OLE_WAIT_FOR_RELEASE)
+ CLEARASYNCCMD(lpobj);
+
+ return retval;
+
+errrtn:
+ if (lprc)
+ GlobalUnlock (hdata);
+ if (hdata)
+ GlobalFree (hdata);
+
+ return retval;
+}
+
+
+OLESTATUS FARINTERNAL LeSetData (lpobj, cfFormat, hData)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+HANDLE hData;
+{
+ OLESTATUS retVal = OLE_OK;
+ BOOL fKnown = FALSE;
+
+ PROBE_ASYNC (lpobj);
+
+ if ((cfFormat == cfObjectLink) || (cfFormat == cfOwnerLink))
+ return ChangeDocAndItem (lpobj, hData);
+
+ if (fKnown = (cfFormat && (cfFormat == ((WORD) GetPictType (lpobj))))) {
+ retVal = (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict,
+ hData, lpobj->head.lpclient, FALSE);
+
+ (*lpobj->lpobjPict->lpvtbl->GetData) (lpobj->lpobjPict,
+ cfFormat, &hData);
+ }
+ else if (fKnown = (cfFormat == cfNative)) {
+ retVal = LeChangeData (lpobj, hData, lpobj->head.lpclient, FALSE);
+ hData = lpobj->hnative;
+ }
+
+ if (retVal != OLE_OK)
+ return retVal;
+
+ if (fKnown)
+ ContextCallBack (lpobj, OLE_CHANGED);
+
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
+ if (!fKnown)
+ return OLE_ERROR_NOT_OPEN;
+ return OLE_OK;
+ }
+
+ // except for the following formats all the other data will be copied
+ // into DDEPOKE block. So there is no need to duplicate the data of the
+ // other formats
+ if ((cfFormat == CF_METAFILEPICT) || (cfFormat == CF_BITMAP)
+ || (cfFormat == CF_DIB)) {
+
+ if (!(hData = DuplicateGDIdata (hData, cfFormat)))
+ return OLE_ERROR_MEMORY;
+ }
+
+ // *** The last parameter must be NULL, don't change it ***
+ InitAsyncCmd (lpobj, OLE_SETDATA, NULL);
+ if ((retVal = SendPokeData (lpobj, lpobj->item, hData, cfFormat))
+ != OLE_WAIT_FOR_RELEASE)
+ CLEARASYNCCMD(lpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FARINTERNAL LeSetColorScheme (lpobj, lplogpal)
+LPOBJECT_LE lpobj;
+LPLOGPALETTE lplogpal;
+{
+ HANDLE hdup = NULL;
+ DWORD cblogpal;
+ OLESTATUS retval;
+ LPBYTE lptemp;
+
+ lptemp = (LPBYTE) lplogpal;
+
+ if (lpobj->head.ctype != CT_EMBEDDED)
+ return OLE_ERROR_OBJECT;
+
+ PROBE_ASYNC (lpobj);
+
+ if (!lplogpal) {
+ // lplogpal == NULL means we should not make color scheme sticky.
+ // This will give the flexibility to the client app. Note that this
+ // will not be effective till next activation.
+ if (lpobj->hlogpal) {
+ GlobalFree (lpobj->hlogpal);
+ lpobj->hlogpal = NULL;
+ }
+
+ return OLE_OK;
+ }
+
+
+ FARPROBE_READ(lptemp + (cblogpal = 2*sizeof(WORD)));
+ cblogpal += ((sizeof(PALETTEENTRY) * lplogpal->palNumEntries) -1);
+ if (!FarCheckPointer (lptemp + cblogpal, READ_ACCESS))
+ return OLE_ERROR_PALETTE;
+
+ if (!(hdup = CopyData ((LPSTR) lplogpal, cblogpal)))
+ return OLE_ERROR_MEMORY;
+
+ if (lpobj->hlogpal)
+ GlobalFree (lpobj->hlogpal);
+
+ lpobj->hlogpal = hdup;
+ InitAsyncCmd (lpobj, OLE_OTHER, NULL);
+ if ((retval = PokeColorScheme (lpobj)) != OLE_WAIT_FOR_RELEASE)
+ CLEARASYNCCMD(lpobj);
+
+ return retval;
+}
+
+
+
+//PokeHostNames: Pokes hostname data to the server
+OLESTATUS INTERNAL PokeHostNames (lpobj)
+LPOBJECT_LE lpobj;
+{
+ OLESTATUS retVal = OLE_ERROR_MEMORY;
+
+ // if the server is connectd then poke the host names
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
+ return OLE_OK;
+
+ if (!lpobj->hhostNames)
+ return OLE_OK;
+
+ aStdHostNames = GlobalAddAtom ("StdHostNames");
+ return SendPokeData (lpobj,aStdHostNames,lpobj->hhostNames,cfBinary);
+}
+
+
+OLESTATUS INTERNAL PokeTargetDeviceInfo (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ // if the server is connectd then poke the host names
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
+ return OLE_OK;
+
+ if (!lpobj->htargetDevice)
+ return OLE_OK;
+
+ aStdTargetDevice = GlobalAddAtom ("StdTargetDevice");
+ return SendPokeData (lpobj, aStdTargetDevice,
+ lpobj->htargetDevice,
+ cfBinary);
+}
+
+
+OLESTATUS INTERNAL PokeDocDimensions (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ // if the server is connectd then poke the host names
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
+ return OLE_OK;
+
+ if (!lpobj->hdocDimensions)
+ return OLE_OK;
+
+ aStdDocDimensions = GlobalAddAtom ("StdDocDimensions");
+ return SendPokeData (lpobj, aStdDocDimensions,
+ lpobj->hdocDimensions,
+ cfBinary);
+}
+
+
+OLESTATUS INTERNAL PokeColorScheme (lpobj)
+LPOBJECT_LE lpobj;
+{
+ // if the server is connected then poke the palette info
+ if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
+ return OLE_OK;
+
+ if (!lpobj->hlogpal)
+ return OLE_OK;
+
+ aStdColorScheme = GlobalAddAtom ("StdColorScheme");
+ return SendPokeData (lpobj, aStdColorScheme,
+ lpobj->hlogpal,
+ cfBinary);
+}
+
+
+OLESTATUS INTERNAL SendPokeData (lpobj, aItem, hdata, cfFormat)
+LPOBJECT_LE lpobj;
+ATOM aItem;
+HANDLE hdata;
+OLECLIPFORMAT cfFormat;
+{
+ HANDLE hdde = NULL;
+ DDEPOKE FAR * lpdde = NULL;
+ LPSTR lpdst = NULL;
+ LPSTR lpsrc = NULL;
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ DWORD dwSize = NULL;
+ PEDIT_DDE pedit;
+ BOOL bGDIdata = FALSE;
+
+ pedit = lpobj->pDocEdit;
+
+ // If it is GDI data then we can stuff the handle into POKE block.
+ // Otherwise we have to copy the data into DDE data block. There
+ // is a special case with old MSDraw, that will be handled by
+ // the routine CanPutHandleInPokeBlock()
+
+ if (!(bGDIdata = CanPutHandleInPokeBlock (lpobj, cfFormat))) {
+ if (!(dwSize = GlobalSize (hdata)))
+ return OLE_ERROR_MEMORY;
+
+ if (!(lpsrc = (LPSTR) GlobalLock (hdata)))
+ return OLE_ERROR_MEMORY;
+
+ GlobalUnlock (hdata);
+ }
+
+ // Now allocate the DDE data block
+
+ if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT,
+ (dwSize + sizeof(DDEPOKE) - sizeof(BYTE) + sizeof(HANDLE)))))
+ goto errRtn;
+
+ if (!(lpdde = (DDEPOKE FAR *)GlobalLock (hdde)))
+ goto errRtn;
+
+ GlobalUnlock (hdde);
+
+ // !!! We may want to set it TRUE, for performance reasons. But it
+ // will require some rework on the server side
+ lpdde->fRelease = 0;
+ lpdde->cfFormat = cfFormat;
+
+ if (bGDIdata)
+ *(LPHANDLE)lpdde->Value = hdata;
+ else {
+ lpdst = (LPSTR)lpdde->Value;
+ UtilMemCpy (lpdst, lpsrc, dwSize);
+
+ // For the CF_METAFILEPICT format, we would come here only if we are
+ // dealing with the old version of MSDraw. In that case we want to
+ // free the handle to METAFILEPICT strcuture, because we've already
+ // copied its contents to DDEPOKE structure.
+
+ // Note that that the old MSDraw expects the contents of METAFILEPICT
+ // structure to be part of DDEPOKE, rather than the handle to it.
+
+ if (cfFormat == CF_METAFILEPICT) {
+ GlobalFree (hdata);
+ hdata = NULL;
+ }
+ }
+
+ // *** From here onwards if there is an error call FreePokeData(), don't
+ // jump to errRtn
+
+ aItem = DuplicateAtom (aItem);
+
+ ASSERT(pedit->hData == NULL, "Poke data is not null");
+
+ pedit->hData = hdde;
+ if (!PostMessageToServer (pedit, WM_DDE_POKE, MAKELONG (hdde, aItem))) {
+ if (aItem)
+ GlobalDeleteAtom (aItem);
+ FreePokeData (lpobj, pedit);
+ return (lpobj->subErr = OLE_ERROR_COMM);
+ }
+
+#ifdef FIREWALLS
+ ASSERT (!pedit->bTerminating, "trying to post while termination")
+ ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
+#endif
+ if (lpobj->asyncCmd == OLE_NONE)
+ lpobj->asyncCmd = OLE_OTHER;
+
+ lpobj->bAsync = TRUE;
+ pedit->awaitAck = AA_POKE;
+ // !!! after poke of the hostnames etc. we are not processing error.,
+
+ // Data is freed after the Poke is acknowledged. OLE_RELEASE will be sent
+ // to when ACK comes.
+
+ return OLE_WAIT_FOR_RELEASE;
+
+errRtn:
+ if (hdata)
+ FreeGDIdata (hdata, cfFormat);
+
+ if (hdde)
+ GlobalFree (hdde);
+
+ pedit->hData = NULL;
+
+ return (lpobj->subErr = retval);
+}
+
+
+
+// FreePokeData: Frees the poked data.
+void INTERNAL FreePokeData (lpobj, pedit)
+LPOBJECT_LE lpobj;
+PEDIT_DDE pedit;
+{
+ DDEPOKE FAR * lpdde;
+
+#ifdef FIREWALLS
+ ASSERT (pedit->hData, "Poke data handle is null");
+
+#endif
+
+ if (lpdde = (DDEPOKE FAR *) GlobalLock (pedit->hData)) {
+ GlobalUnlock (pedit->hData);
+
+ // The old version of MSDraw expects the contents of METAFILEPICT
+ // structure to be part of DDEPOKE, rather than the handle to it.
+
+ if (!lpobj->bOleServer && (lpobj->app == aMSDraw)
+ && (lpdde->cfFormat == CF_METAFILEPICT)) {
+ DeleteMetaFile (((LPMETAFILEPICT) ((LPSTR) &lpdde->Value))->hMF);
+ }
+ else {
+ FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
+ }
+ }
+
+ GlobalFree (pedit->hData);
+ pedit->hData = NULL;
+}
+
+
+
+BOOL INTERNAL SendSrvrMainCmd (lpobj, lptemplate)
+LPOBJECT_LE lpobj;
+LPSTR lptemplate;
+{
+ WORD size;
+ WORD len;
+ OLESTATUS retval;
+ int cmd;
+ HANDLE hInst = NULL;
+ LPSTR lpdata= NULL;
+ HANDLE hdata = NULL;
+ BOOL bLaunch = TRUE;
+
+ Puts("Launch App and Send Sys command");
+
+#ifdef FIREWALLS
+ ASSERT (lpobj->aServer, "Serevr is NULL");
+#endif
+
+ if (!lpobj->aServer) {
+ retval = OLE_ERROR_REGISTRATION;
+ goto errRtn;
+ }
+
+ if (!lpobj->bOldLink) {
+ bLaunch = !(lpobj->fCmd & ACT_NOLAUNCH);
+ cmd = lpobj->fCmd & LN_MASK;
+ }
+
+ if (cmd == LN_LNKACT) {
+ // take care of network based document
+ char cDrive = lpobj->cDrive;
+
+ if ((retval = CheckNetDrive (lpobj, POPUP_NETDLG)) != OLE_OK) {
+ lpobj->cDrive = cDrive;
+ goto errRtn;
+ }
+
+ if (cDrive != lpobj->cDrive)
+ ContextCallBack (lpobj, OLE_RENAMED);
+ }
+
+ if (!InitSrvrConv (lpobj, hInst)) {
+
+ if (!bLaunch)
+ goto errRtn;
+
+ if (!(hInst = LeLaunchApp (lpobj))) {
+ // We failed to launch the app. If it is a linked object, see
+ // whether the docname is valid for new servers. We wouldn't
+ // have given the doc name on the command line for the old
+ // servers. So, there is no point in checking for file existance
+ // in that case.
+ if (lpobj->bOleServer && (lpobj->bOldLink || (cmd == LN_LNKACT))){
+ if ((retval = FileExists (lpobj)) != OLE_OK)
+ goto errRtn;
+ }
+
+ retval = OLE_ERROR_LAUNCH;
+ goto errRtn;
+ }
+
+ if (lpobj->bOldLink)
+ return TRUE;
+
+ if (lpobj->bOleServer && (cmd == LN_LNKACT)) {
+ // We are not using any data blocks if the object is old link.
+ // we launched with docname, and don't have to establish system
+ // level and also we don't have to send exec strings.
+
+ // for non-ole servers like excel, we do want to connect at
+ // the system level, so that we can send "StdOpen". We also
+ // have to send "StdExit" for the server to exit in the
+ // invisible launch case.
+
+ return TRUE;
+ }
+
+ retval = OLE_ERROR_COMM;
+ if(!InitSrvrConv (lpobj, hInst))
+ goto errRtn;
+#ifdef OLD
+ if (!lpobj->bOleServer && (cmd == LN_LNKACT))
+ return TRUE;
+#endif
+ }
+
+ if (!lpobj->bOldLink) {
+ cmd = lpobj->fCmd & LN_MASK;
+ len = lstrlen (srvrSysCmd[cmd >> LN_SHIFT]);
+
+ // for template and new, add the class name also
+ if (cmd == LN_NEW || cmd == LN_TEMPLATE)
+ len += GlobalGetAtomLen (lpobj->app);
+
+ // Now add the document length.
+ len += GlobalGetAtomLen (lpobj->topic);
+
+ // add the length of the template name
+ if (lptemplate)
+ len += lstrlen (lptemplate);
+
+ // now add the fudge factor for the Quotes etc.
+ len += LN_FUDGE;
+
+ // allocate the buffer and set the command.
+ hdata = GlobalAlloc (GMEM_DDESHARE, size = len);
+
+ retval = OLE_ERROR_MEMORY;
+ SETERRHINT(lpobj, OLE_ERROR_MEMORY);
+
+ if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
+ goto errRtn;
+ }
+
+ lstrcpy (lpdata, (LPSTR)"["); // [
+ lstrcat (lpdata, srvrSysCmd[cmd >> LN_SHIFT]); // [Std....
+ lstrcat (lpdata, "(\""); // [std...("
+
+ if (cmd == LN_NEW || cmd == LN_TEMPLATE) {
+ len = lstrlen (lpdata);
+ GlobalGetAtomName (lpobj->app, (LPSTR)lpdata + len, size - len);
+ // [std...("class
+ lstrcat (lpdata, "\",\""); // [std...("class", "
+ }
+ len = lstrlen (lpdata);
+ // now get the topic name.
+ GlobalGetAtomName (lpobj->topic, lpdata + len, (WORD)size - len);
+ // [std...("class","doc
+ if (lptemplate) {
+ lstrcat (lpdata, "\",\""); // [std...("class","doc","
+ lstrcat (lpdata, lptemplate); // [std...("class","doc","temp
+ }
+
+ lstrcat (lpdata, "\")]"); // [std...("class","doc","temp")]
+
+ GlobalUnlock (hdata);
+
+ // !!!optimize with mapping.
+ SETERRHINT(lpobj, (OLE_ERROR_TEMPLATE + (cmd >> LN_SHIFT)));
+
+ return SrvrExecute (lpobj, hdata);
+
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+ lpobj->subErr = retval;
+ return FALSE;
+}
+
+
+
+
+// ExtendAtom: Create a new atom, which is the old one plus extension
+
+ATOM INTERNAL ExtendAtom (lpobj, item)
+LPOBJECT_LE lpobj;
+ATOM item;
+{
+ char buffer[MAX_ATOM+1];
+ LPSTR lpext;
+
+ Puts("ExtendAtom");
+
+ buffer[0] = 0;
+ if (item)
+ GlobalGetAtomName (item, buffer, MAX_ATOM);
+
+ switch (lpobj->optUpdate) {
+
+
+ case oleupdate_always:
+ lpext = (LPSTR)"";
+ break;
+
+ case oleupdate_onsave:
+ lpext = (LPSTR)"/Save";
+ break;
+
+ case oleupdate_onclose:
+ lpext = (LPSTR)"/Close";
+ break;
+
+ default:
+ ASSERT (FALSE, "on call options not expected here");
+ break;
+
+ }
+
+ lstrcat (buffer, lpext);
+ if (buffer[0])
+ return GlobalAddAtom (buffer);
+ else
+ return NULL;
+}
+
+
+BOOL INTERNAL CreatePictObject (lhclientdoc, lpobjname, lpobj, optRender, cfFormat, lpclass)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_LE lpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LPSTR lpclass;
+{
+ LPOLEOBJECT lpPictObj = NULL;
+ ATOM aClass;
+
+ lpobj->lpobjPict = NULL;
+ if (optRender == olerender_format) {
+ switch (cfFormat) {
+ case NULL:
+ return FALSE;
+
+ case CF_METAFILEPICT:
+ if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE)))
+ return FALSE;
+ break;
+
+ case CF_DIB:
+ if (!(lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE)))
+ return FALSE;
+ break;
+
+ case CF_BITMAP:
+ if (!(lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE)))
+ return FALSE;
+ break;
+
+ default:
+ aClass = GlobalAddAtom (lpclass);
+ if (!(lpPictObj = (LPOLEOBJECT) GenCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE, aClass)))
+ return FALSE;
+
+ ((LPOBJECT_GEN)lpPictObj)->cfFormat = cfFormat;
+ break;
+ }
+ }
+ else if (optRender == olerender_draw) {
+ if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE)))
+ return FALSE;
+#ifdef LATER
+ if (AdviseOn (lpobj, (cfFormat = CF_METAFILEPICT), NULL))
+ lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE);
+ // !!! for the time being take assume we need to get metafile.
+ else if (AdviseOn (lpobj, (cfFormat = CF_DIB), NULL))
+ lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE);
+ else if (AdviseOn (lpobj, (cfFormat = CF_BITMAP), NULL))
+ lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc,
+ lpobjname, CT_PICTURE);
+ else
+ goto errPict;
+#endif
+
+ }
+ else
+ return (optRender == olerender_none);
+
+ if (lpobj->lpobjPict = lpPictObj)
+ lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
+ return TRUE;
+}
+
+
+OLESTATUS LnkChangeLnk (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ switch (lpobj->subRtn) {
+
+ case 0:
+ TermDocConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 1:
+
+ // delete the edit block
+ DeleteDocEdit (lpobj);
+ TermSrvrConv (lpobj);
+ WAIT_FOR_ASYNC_MSG (lpobj);
+
+ case 2:
+
+ // Do not set any errors, just delete the object.
+ // delete the server edit block
+ DeleteSrvrEdit (lpobj);
+
+ // now try to activate the new link.
+ SKIP_TO (!InitDocConv (lpobj, !POPUP_NETDLG), step3);
+ lpobj->fCmd = LN_LNKACT | ACT_ADVISE | ACT_REQUEST;
+ InitAsyncCmd (lpobj, OLE_SETDATA, LNKOPENUPDATE);
+ return LnkOpenUpdate (lpobj);
+
+ case 3:
+ step3:
+ return EndAsyncCmd (lpobj);
+
+ default:
+ DEBUG_OUT ("Unexpected subroutine", 0);
+ return OLE_ERROR_GENERIC;
+ }
+}
+
+
+OLESTATUS INTERNAL ChangeDocAndItem (lpobj, hinfo)
+LPOBJECT_LE lpobj;
+HANDLE hinfo;
+{
+ LPSTR lpinfo;
+ ATOM aNewTopic, aNewItem = NULL, aOldTopic;
+ OLESTATUS retVal = OLE_ERROR_BLANK;
+
+ PROBE_SVRCLOSING(lpobj);
+
+ if (!(lpinfo = GlobalLock (hinfo)))
+ return OLE_ERROR_MEMORY;
+
+ lpinfo += lstrlen (lpinfo) + 1;
+ aNewTopic = GlobalAddAtom (lpinfo);
+ lpinfo += lstrlen (lpinfo) + 1;
+ if (*lpinfo)
+ aNewItem = GlobalAddAtom (lpinfo);
+
+ if (!aNewTopic && (lpobj->head.ctype == CT_LINK))
+ goto errRtn;
+
+ aOldTopic = lpobj->topic;
+ lpobj->topic = aNewTopic;
+ if ((retVal = SetNetName (lpobj)) != OLE_OK) {
+ if (lpobj->topic)
+ GlobalDeleteAtom (lpobj->topic);
+ lpobj->topic = aOldTopic;
+ goto errRtn;
+ }
+
+ if (aOldTopic)
+ GlobalDeleteAtom (aOldTopic);
+
+ if (lpobj->item)
+ GlobalDeleteAtom (lpobj->item);
+
+ lpobj->item = aNewItem;
+
+ // As the atoms have already changed, lpobj->hLink becomes irrelevant.
+ if (lpobj->hLink) {
+ GlobalFree (lpobj->hLink);
+ lpobj->hLink = NULL;
+ }
+
+ GlobalUnlock(hinfo);
+
+ // Now disconnect the old link and try to connect to the new one.
+ lpobj->fCmd = 0;
+ InitAsyncCmd (lpobj, OLE_SETDATA, LNKCHANGELNK);
+ return LnkChangeLnk (lpobj);
+
+errRtn:
+
+ if (aNewItem)
+ GlobalDeleteAtom (aNewItem);
+
+ GlobalUnlock (hinfo);
+ return retVal;
+}
+
+
+BOOL QueryUnlaunch (lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (!(lpobj->fCmd & ACT_UNLAUNCH))
+ return FALSE;
+
+ // only if we loaded the app
+ if (lpobj->pSysEdit && lpobj->pSysEdit->hClient && lpobj->pSysEdit->hInst)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL QueryClose (lpobj)
+LPOBJECT_LE lpobj;
+{
+ if (!((lpobj->fCmd & ACT_UNLAUNCH) ||
+ (lpobj->head.ctype == CT_EMBEDDED)))
+ return FALSE;
+
+ // only if we loaded the documnet
+ if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+OLESTATUS INTERNAL SetHostNamesHandle (lpobj, lpclientName, lpdocName)
+LPOBJECT_LE lpobj;
+LPSTR lpclientName;
+LPSTR lpdocName;
+{
+ WORD cbClient;
+ WORD size;
+ HANDLE hhostNames = NULL;
+ LPHOSTNAMES lphostNames = NULL;
+ LPSTR lpdata;
+
+ // 4 bytes is for the two offsets
+ size = (cbClient = lstrlen(lpclientName)+1) + (lstrlen(lpdocName)+1) + 4;
+
+ if ((hhostNames = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size))
+ == NULL)
+ goto errRtn;
+
+ if ((lphostNames = (LPHOSTNAMES)GlobalLock (hhostNames)) == NULL)
+ goto errRtn;
+
+ lphostNames->clientNameOffset = 0;
+ lphostNames->documentNameOffset = cbClient;
+
+ lpdata = (LPSTR)lphostNames->data;
+ lstrcpy (lpdata, lpclientName);
+ lstrcpy (lpdata + cbClient, lpdocName);
+ if (lpobj->hhostNames)
+ GlobalFree ( lpobj->hhostNames);
+ GlobalUnlock (hhostNames);
+ lpobj->hhostNames = hhostNames;
+ return OLE_OK;
+
+errRtn:
+ if (lphostNames)
+ GlobalUnlock (hhostNames);
+
+ if (hhostNames)
+ GlobalFree (hhostNames);
+
+ return OLE_ERROR_MEMORY;
+}
+
+
+#if 0
+OLESTATUS FARINTERNAL LeAbort (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+
+ BOOL bAbort = FALSE;
+ PEDIT_DDE pedit;
+
+
+ // check whether the any transaction pending for
+ // the document level.
+
+ // channel open
+ // any transaction pending.
+ // and we are not in terminate mode.
+
+
+ if ((pedit = lpobj->pDocEdit) && pedit->hServer &&
+ pedit->awaitAck && !pedit->bTerminating) {
+ pedit->bAbort = bAbort = TRUE;
+ // delete any data we need to delete. Ricght now
+ // we kill only the timer. We can not delete any
+ // since the server could potentially look at the data.
+
+ DeleteAbortData (lpobj, pedit);
+ }
+
+ if ((pedit = lpobj->pSysEdit) && pedit->hServer &&
+ pedit->awaitAck && !pedit->bTerminating) {
+ pedit->bAbort = bAbort = TRUE;
+ DeleteAbortData (lpobj, pedit);
+
+ }
+
+ if (!bAbort)
+ return OLE_OK;
+
+ // Now send the EndAsync
+ lpobj->mainErr = OLE_ERROR_ABORT;
+ EndAsyncCmd (lpobj);
+ return OLE_OK;
+
+}
+#endif
+
+
+OLESTATUS FARINTERNAL ProbeAsync(lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ if (lpobj->asyncCmd == OLE_NONE)
+ return OLE_OK;
+
+ if (!IsServerValid (lpobj)) {
+
+ // Now send the EndAsync
+ lpobj->mainErr = OLE_ERROR_TASK;
+ EndAsyncCmd (lpobj);
+ return OLE_OK;
+ }
+
+ return OLE_BUSY;
+}
+
+
+BOOL INTERNAL IsWindowValid (hwnd)
+HWND hwnd;
+{
+
+#define TASK_OFFSET 0x00FA
+
+ LPSTR lptask;
+ HANDLE htask;
+
+ if (!IsWindow (hwnd))
+ return FALSE;
+
+ if (bWLO)
+ return TRUE;
+
+ // now get the task handle and find out it is valid.
+ htask = GetWindowTask (hwnd);
+
+ if ((wWinVer == 0x0003) || !lpfnIsTask) {
+ lptask = (LPSTR)(MAKELONG (TASK_OFFSET, htask));
+
+ if (!FarCheckPointer(lptask, READ_ACCESS))
+ return FALSE;
+
+ // now check for the signature bytes of task block in kernel
+ if (*lptask++ == 'T' && *lptask == 'D')
+ return TRUE;
+ }
+ else {
+ // From win31 onwards the API IsTask can be used for task validation
+ if ((*lpfnIsTask)(htask))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+BOOL INTERNAL IsServerValid (lpobj)
+LPOBJECT_LE lpobj;
+{
+
+ MSG msg;
+ BOOL retval = FALSE;
+
+
+ if (lpobj->pDocEdit && lpobj->pDocEdit->hServer) {
+
+ retval = TRUE;
+
+ if (!IsWindowValid (lpobj->pDocEdit->hServer)) {
+ if (!PeekMessage ((LPMSG)&msg, lpobj->pDocEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
+ PM_NOREMOVE | PM_NOYIELD)){
+#ifdef FIREWALLS
+ ASSERT (FALSE, "Server truely died");
+#endif
+ return FALSE;
+ }
+
+ }
+
+ }
+
+ if (lpobj->pSysEdit && lpobj->pSysEdit->hServer) {
+ retval = TRUE;
+
+ if (!IsWindowValid (lpobj->pSysEdit->hServer)) {
+
+ if (!PeekMessage ((LPMSG)&msg, lpobj->pSysEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
+ PM_NOREMOVE | PM_NOYIELD)){
+#ifdef FIREWALLS
+ ASSERT (FALSE, "Server truely died");
+#endif
+ return FALSE;
+
+ }
+
+
+ }
+ }
+
+ return retval;
+}
+
+
+OLESTATUS FARINTERNAL LeExecute (lpobj, hCmds, wReserve)
+LPOBJECT_LE lpobj;
+HANDLE hCmds;
+WORD wReserve;
+{
+ // Assumes all the creates are in order
+ PROBE_CREATE_ASYNC(lpobj);
+ PROBE_SVRCLOSING(lpobj);
+
+ if (!(lpobj = (*lpobj->head.lpvtbl->QueryProtocol) (lpobj,
+ PROTOCOL_EXECUTE)))
+ return OLE_ERROR_PROTOCOL;
+
+ if (!QueryOpen (lpobj))
+ return OLE_ERROR_NOT_OPEN;
+
+ if (!(hCmds = DuplicateGlobal (hCmds, GMEM_MOVEABLE|GMEM_DDESHARE)))
+ return OLE_ERROR_MEMORY;
+
+ InitAsyncCmd (lpobj, OLE_OTHER, NULL);
+ SETERRHINT(lpobj, OLE_ERROR_COMMAND);
+ if (DocExecute(lpobj, hCmds))
+ return OLE_WAIT_FOR_RELEASE;
+ else
+ return OLE_ERROR_COMMAND;
+}
+
+
+void INTERNAL FreeGDIdata (hData, cfFormat)
+HANDLE hData;
+OLECLIPFORMAT cfFormat;
+{
+ if (cfFormat == CF_METAFILEPICT) {
+ LPMETAFILEPICT lpMfp;
+
+ if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) {
+ GlobalUnlock (hData);
+ DeleteMetaFile (lpMfp->hMF);
+ }
+
+ GlobalFree (hData);
+ }
+
+ else if (cfFormat == CF_BITMAP)
+ DeleteObject (hData);
+
+ else if (cfFormat == CF_DIB)
+ GlobalFree (hData);
+}
+
+
+// This routine figures out whether the handle to data block can be copied
+// to DDEPOKE block rather than the contents of the handle
+
+BOOL INTERNAL CanPutHandleInPokeBlock (lpobj, cfFormat)
+LPOBJECT_LE lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ if (cfFormat == CF_BITMAP || cfFormat == CF_DIB)
+ return TRUE;
+
+ if (cfFormat == CF_METAFILEPICT) {
+ // The old version of MSDraw expects the contents of METAFILEPICT
+ // structure to be part of DDEPOKE, rather than the handle to it.
+
+ if (!lpobj->bOleServer && lpobj->app == aMSDraw)
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow16/ole/client/main.c b/private/mvdm/wow16/ole/client/main.c
new file mode 100644
index 000000000..d64c5743f
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/main.c
@@ -0,0 +1,781 @@
+
+/****************************** Module Header ******************************\
+* Module Name: MAIN.C
+*
+* PURPOSE: WinMain, WEP and some other misc routines
+*
+* Created: 1991
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Srinik (04/01/91) Pulled some routines, into this, from ole.c.
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "dll.h"
+
+#ifndef WF_WLO
+#define WF_WLO 0x8000
+#endif
+
+// ordinal number new win31 API IsTask
+#define ORD_IsTask 320
+
+#define NUM_DLL 30 /* space for this many DLL_ENTRYs is created on */
+ /* each alloc/realloc */
+
+OLECLIPFORMAT cfOwnerLink = 0; // global variables for clip frmats
+OLECLIPFORMAT cfObjectLink = 0;
+OLECLIPFORMAT cfLink = 0;
+OLECLIPFORMAT cfNative = 0;
+OLECLIPFORMAT cfBinary = 0;
+OLECLIPFORMAT cfFileName = 0;
+OLECLIPFORMAT cfNetworkName = 0;
+
+ATOM aStdHostNames;
+ATOM aStdTargetDevice ;
+ATOM aStdDocDimensions;
+ATOM aStdDocName;
+ATOM aStdColorScheme;
+ATOM aNullArg = 0;
+ATOM aSave;
+ATOM aChange;
+ATOM aClose;
+ATOM aSystem;
+ATOM aOle;
+ATOM aClipDoc;
+ATOM aPackage;
+
+// Used in work around for MSDraw bug
+ATOM aMSDraw;
+
+extern LPCLIENTDOC lpHeadDoc;
+extern LPCLIENTDOC lpTailDoc;
+
+extern RENDER_ENTRY stdRender[];
+
+HANDLE hInstDLL;
+BOOL bProtMode;
+BOOL bWLO = FALSE;
+
+/* HANDLE hDllTable; !!! Add this when bug in WEP is fixed */
+DLL_ENTRY lpDllTable[NUM_DLL]; //!!! change this when WEP bug is fixed
+DWORD dllTableSize;
+int iLast = 0;
+int iMax = NUM_DLL -1;
+int iUnloadableDll = NULL; // index to handler than can be freed up
+
+char packageClass[] = "Package";
+
+// For QuerySize() API & methods.
+extern OLESTREAMVTBL dllStreamVtbl;
+extern CLIENTDOC lockDoc;
+
+#ifdef FIREWALLS
+BOOL bShowed = FALSE;
+char szDebugBuffer[80];
+short ole_flags;
+
+void FARINTERNAL ShowVersion (void);
+void FARINTERNAL SetOleFlags(void);
+#endif
+
+// LOWWORD - BYTE 0 major verision, BYTE1 minor version,
+// HIWORD reserved
+
+DWORD dwOleVer = 0x2001L; // change this when we want to update dll version
+ // number
+
+
+DWORD dwVerToFile = 0x0501L; // This is used while object is being saved to
+ // file. There is no need to change this value
+ // whenever we change ole dll version number
+
+
+
+static BOOL bLibInit = FALSE;
+
+
+WORD wWinVer;
+
+HANDLE hModule;
+
+#define MAX_HIMETRIC 0x7FFF
+
+int maxPixelsX = MAX_HIMETRIC;
+int maxPixelsY = MAX_HIMETRIC;
+void SetMaxPixel (void);
+
+VOID FAR PASCAL WEP (int);
+
+#pragma alloc_text(WEP_TEXT, WEP)
+
+
+FARPROC lpfnIsTask = NULL; // the API IsTask() became available from
+ // win31 onwards, hence we are trying to
+ // get it's address through GetProcAddress
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// int FAR PASCAL LibMain (hInst, wDataSeg, cbHeapSize, lpszCmdLine)
+//
+// The main library entry point. This routine is called when the library
+// is loaded.
+//
+// Arguments:
+//
+// hInst - dll's instance handle
+// wDataSeg - DS register value
+// cbHeapSize - heap size defined def file
+// lpszCmdLine - command line info
+//
+// Returns:
+//
+// 0 - failure
+// 1 - success
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+int FAR PASCAL LibMain (hInst, wDataSeg, cbHeapSize, lpszCmdLine)
+HANDLE hInst;
+WORD wDataSeg;
+WORD cbHeapSize;
+LPSTR lpszCmdLine;
+{
+ WNDCLASS wc;
+ int i;
+
+ Puts("LibMain");
+
+#ifdef FIREWALLS
+ SetOleFlags();
+#endif
+
+ bLibInit = TRUE;
+ hInstDLL = hInst;
+ hModule = GetModuleHandle ("OLECLI");
+
+ bProtMode = (BOOL) (GetWinFlags() & WF_PMODE);
+ bWLO = (BOOL) (GetWinFlags() & WF_WLO);
+ wWinVer = (WORD) GetVersion();
+
+ // REGISTER LINK FORMAT
+
+ cfObjectLink = RegisterClipboardFormat("ObjectLink");
+ cfLink = RegisterClipboardFormat("Link");
+ cfOwnerLink = RegisterClipboardFormat("OwnerLink");
+ cfNative = RegisterClipboardFormat("Native");
+ cfBinary = RegisterClipboardFormat("Binary");
+ cfFileName = RegisterClipboardFormat("FileName");
+ cfNetworkName = RegisterClipboardFormat("NetworkName");
+
+ if (!(cfObjectLink && cfOwnerLink && cfNative && cfLink))
+ return 0;
+
+ // SET UP OLEWNDCLASS
+ wc.style = NULL;
+ wc.lpfnWndProc = DocWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LONG); //we are storing longs
+ wc.hInstance = hInst;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground= NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName= "OleDocWndClass";
+ if (!RegisterClass(&wc))
+ return 0;
+
+ wc.lpfnWndProc = SrvrWndProc;
+ wc.lpszClassName = "OleSrvrWndClass";
+
+ if (!RegisterClass(&wc))
+ return 0;
+/*
+ // !!! Add this when bug in WEP is fixed.
+ // Allocate memory for DLL table
+ dllTableSize = NUM_DLL * sizeof(DLL_ENTRY);
+ if (!(hDllTable = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT,
+ dllTableSize)))
+ return 0;
+
+ if (!(lpDllTable = (DLL_ENTRY FAR *) GlobalLock (hDllTable)))
+ return 0;
+*/
+
+ // !!! remove the following when WEP bug is fixed
+ for (i = 0; i < NUM_DLL; i++)
+ lpDllTable[i].aDll = 0;
+
+ // !!! BEGIN hack for Pbrush.
+
+ lpDllTable[0].hDll = NULL;
+ lpDllTable[0].aDll = GlobalAddAtom ((LPSTR) "ole");
+ lpDllTable[0].Load = PbLoadFromStream;
+ lpDllTable[0].Clip = PbCreateFromClip;
+ lpDllTable[0].Link = PbCreateLinkFromClip;
+ lpDllTable[0].Create = PbCreate;
+ lpDllTable[0].CreateFromTemplate = PbCreateFromTemplate;
+ lpDllTable[0].CreateFromFile = PbCreateFromFile;
+ lpDllTable[0].CreateLinkFromFile = PbCreateLinkFromFile;
+ lpDllTable[0].CreateInvisible = PbCreateInvisible;
+
+
+ // !!! END hack for pbrush
+
+ // For ObjectSize API
+ dllStream.lpstbl = (LPOLESTREAMVTBL) &dllStreamVtbl;
+ dllStream.lpstbl->Put = DllPut;
+
+ // add the atoms required.
+ aStdDocName = GlobalAddAtom ((LPSTR)"StdDocumentName");
+ aSave = GlobalAddAtom ((LPSTR)"Save");
+ aChange = GlobalAddAtom ((LPSTR)"Change");
+ aClose = GlobalAddAtom ((LPSTR)"Close");
+ aSystem = GlobalAddAtom ((LPSTR)"System");
+ aOle = GlobalAddAtom ((LPSTR)"OLEsystem");
+ aPackage = GlobalAddAtom ((LPSTR) packageClass);
+
+ // Used in work around for MSDraw bug
+ aMSDraw = GlobalAddAtom ((LPSTR) "MSDraw");
+
+ // clipboard document name atom
+ aClipDoc = GlobalAddAtom ((LPSTR)"Clipboard");
+
+ stdRender[0].aClass = GlobalAddAtom ("METAFILEPICT");
+ stdRender[1].aClass = GlobalAddAtom ("DIB");
+ stdRender[2].aClass = GlobalAddAtom ("BITMAP");
+
+ SetMaxPixel();
+
+ if (wWinVer != 0x0003) {
+ HANDLE hModule;
+
+ if (hModule = GetModuleHandle ("KERNEL"))
+ lpfnIsTask = GetProcAddress (hModule,
+ (LPSTR) MAKELONG (ORD_IsTask, 0));
+ }
+
+ if (cbHeapSize != 0)
+ UnlockData(0);
+
+ return 1;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// VOID FAR PASCAL WEP (nParameter)
+//
+// Called just before the library is being unloaded. Delete all the atoms
+// added by this dll and also frees up all unloaded handler dlls.
+//
+// Arguments:
+//
+// nParameter - Termination code
+//
+// Returns:
+//
+// none
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+VOID FAR PASCAL WEP (nParameter)
+int nParameter;
+{
+ int i;
+
+
+ Puts("LibExit");
+
+ // case when the DLLs are missing
+ if (!bLibInit)
+ return;
+
+ if (nParameter == WEP_SYSTEM_EXIT)
+ DEBUG_OUT ("---L&E DLL EXIT on system exit---",0)
+ else if (nParameter == WEP_FREE_DLL)
+ DEBUG_OUT ("---L&E DLL EXIT---\n",0)
+ else
+ return;
+
+ // Delete atoms added by us
+
+ for (i = 0; i < NUM_RENDER; i++) {
+ if (stdRender[i].aClass)
+ GlobalDeleteAtom (stdRender[i].aClass);
+ }
+
+ if (aStdDocName)
+ GlobalDeleteAtom (aStdDocName);
+ if (aSave)
+ GlobalDeleteAtom (aSave);
+ if (aChange)
+ GlobalDeleteAtom (aChange);
+ if (aClose)
+ GlobalDeleteAtom (aClose);
+ if (aSystem)
+ GlobalDeleteAtom (aSystem);
+ if (aOle)
+ GlobalDeleteAtom (aOle);
+ if (aPackage)
+ GlobalDeleteAtom (aPackage);
+ if (aClipDoc)
+ GlobalDeleteAtom (aClipDoc);
+ if (aMSDraw)
+ GlobalDeleteAtom (aMSDraw);
+
+ // Free handler dlls if there are any still loaded. Entry 0 is used for
+ // Pbrush handler which is part of this dll.
+
+
+ for (i = 0; i <= iLast; i++) {
+ if (lpDllTable[i].aDll)
+ GlobalDeleteAtom (lpDllTable[i].aDll);
+
+ if (lpDllTable[i].hDll)
+ FreeLibrary (lpDllTable[i].hDll);
+ }
+
+
+#ifdef FIREWALLS
+ ASSERT(!lpHeadDoc, "Some client doc structures are not deleted");
+ ASSERT(!lockDoc.lpHeadObj, "Some servers are left in a locked state");
+#endif
+
+/* !!! Add this when bug in WEP is fixed
+
+ if (lpDllTable)
+ GlobalUnlock (hDllTable);
+
+ if (hDllTable)
+ GlobalFree (hDllTable);
+*/
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// void FARINTERNAL SetOleFlags()
+//
+// Sets the debug level flags for controlling the level of debug information
+// on the comm terminal. This will be included only in the debug version.
+//
+// Arguments:
+//
+// none
+//
+// Returns:
+//
+// none
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef FIREWALLS
+
+void FARINTERNAL SetOleFlags()
+{
+
+ char buffer[80];
+
+ if(GetProfileString ("OLE",
+ "Puts","", (LPSTR)buffer, 80))
+ ole_flags = DEBUG_PUTS;
+ else
+ ole_flags = 0;
+
+
+ if(GetProfileString ("OLE",
+ "DEBUG_OUT","", (LPSTR)buffer, 80))
+ ole_flags |= DEBUG_DEBUG_OUT;
+
+
+ if(GetProfileString ("OLE",
+ "MESSAGEBOX","", (LPSTR)buffer, 80))
+ ole_flags |= DEBUG_MESSAGEBOX;
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// void FARINTERNAL ShowVersion (void)
+//
+// Displays version, date, time and copyright info in client app's window.
+// Called by all the object create functions after checking the flag bShowed.
+// This will be included only in the debug version.
+//
+// Arguments:
+//
+// none
+//
+// Returns:
+//
+// none
+//
+// Effects:
+//
+// sets bShowed
+//
+//////////////////////////////////////////////////////////////////////////////
+
+void FARINTERNAL ShowVersion ()
+{
+
+ if (!bShowed && (ole_flags & DEBUG_MESSAGEBOX)) {
+ MessageBox (NULL, "\
+ VER: 1.09.000\n\
+ TIME: 16:00:00\n\
+ DATE: 01/31/1992\n\
+ Copyright (c) 1990, 1991 Microsoft Corp.\n\
+ All Rights Reserved.",
+ "Ole Client Library",
+ MB_OK | MB_TASKMODAL);
+ bShowed = TRUE;
+ }
+}
+
+#endif
+
+
+
+
+int FARINTERNAL LoadDll (lpClass)
+LPSTR lpClass;
+{
+ char str[MAX_STR];
+ char str1[MAX_STR];
+ ATOM aDll = NULL;
+ int index;
+ int iEmpty;
+ BOOL found = FALSE;
+ HANDLE hDll;
+ int refcnt;
+ LONG cb = MAX_STR;
+
+ if (!lstrcmpi (lpClass, "Pbrush"))
+ return 0;
+
+ lstrcpy (str, lpClass);
+ lstrcat (str, "\\protocol\\StdFileEditing\\handler");
+ if (RegQueryValue (HKEY_CLASSES_ROOT, str, str1, &cb))
+ return INVALID_INDEX;
+
+ if (aDll = GlobalFindAtom (str1)) {
+ for (index = 1; index <= iLast; index++) {
+ if (lpDllTable[index].aDll == aDll) { // Dll already loaded
+ lpDllTable[index].cObj ++;
+
+ if (index == iUnloadableDll) {
+ // since the object count is not zero anymore, this
+ // handler can not be freed up.
+ iUnloadableDll = NULL;
+ }
+
+ return index;
+ }
+ }
+ }
+
+ aDll = GlobalAddAtom (str1);
+
+ // Look for an empty entry
+ for (iEmpty = 1; iEmpty <= iLast; iEmpty++) {
+ if (!lpDllTable[iEmpty].aDll) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (iEmpty > iMax)
+ goto errLoad;
+/*
+ if (!found) {// no empty entry exists create a new one if necessary.
+ if (iEmpty > iMax) {
+ dllTableSize += (blockSize = NUM_DLL * sizeof(DLL_ENTRY));
+ hTable = GlobalReAlloc (hDllTable, dllTableSize,
+ GMEM_MOVEABLE | GMEM_ZEROINIT);
+ if (hTable == hDllTable)
+ iMax += NUM_DLL;
+ else {
+ dllTableSize -= blockSize;
+ iEmpty = INVALID_INDEX;
+ }
+ }
+ }
+*/
+
+ // !!! reference count of OLECLI is increasing by 2 when the handlers are
+ // are loaded, looks like windows bug. Following is a temporary fix.
+
+ refcnt = GetModuleUsage (hModule);
+ hDll = LoadLibrary ((LPSTR) str1);
+ refcnt = (GetModuleUsage (hModule) - refcnt);
+
+ while (refcnt > 1) {
+ FreeModule (hModule);
+ refcnt--;
+ }
+
+ if (hDll < 32)
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].Load = GetProcAddress (hDll,
+ "DllLoadFromStream")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].Clip = GetProcAddress (hDll,
+ "DllCreateFromClip")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].Link = GetProcAddress (hDll,
+ "DllCreateLinkFromClip")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].CreateFromTemplate = GetProcAddress (hDll,
+ "DllCreateFromTemplate")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].Create = GetProcAddress (hDll, "DllCreate")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].CreateFromFile = GetProcAddress (hDll,
+ "DllCreateFromFile")))
+ goto errLoad;
+
+ if (!(lpDllTable[iEmpty].CreateLinkFromFile = GetProcAddress (hDll,
+ "DllCreateLinkFromFile")))
+ goto errLoad;
+
+ lpDllTable[iEmpty].CreateInvisible = GetProcAddress (hDll,
+ "DllCreateInvisible");
+
+ lpDllTable[iEmpty].aDll = aDll;
+ lpDllTable[iEmpty].cObj = 1;
+ lpDllTable[iEmpty].hDll = hDll;
+ if (iEmpty > iLast)
+ iLast++;
+ return iEmpty;
+
+errLoad:
+ if (aDll)
+ GlobalDeleteAtom (aDll);
+ if (hDll >= 32)
+ FreeLibrary (hDll);
+ return INVALID_INDEX;
+}
+
+
+// unload the the handler that can be free up (whose object count is NULL)
+
+void FARINTERNAL UnloadDll ()
+{
+ if (!iUnloadableDll)
+ return;
+
+ if (iUnloadableDll == iLast)
+ iLast--;
+
+ if (lpDllTable[iUnloadableDll].aDll)
+ GlobalDeleteAtom (lpDllTable[iUnloadableDll].aDll);
+ lpDllTable[iUnloadableDll].aDll = NULL;
+ FreeLibrary (lpDllTable[iUnloadableDll].hDll);
+ lpDllTable[iUnloadableDll].hDll = NULL;
+
+ iUnloadableDll = NULL;
+}
+
+
+//
+// Reduce the object count of the handler, refered to by the index, by one.
+// If the object count becomes NULL, free up the handler that is ready to be
+// freed (refered to by index iUnloadableDll), and then make this handler the
+// freeable one.
+//
+// As you can see we are trying to implement a simple mechanism of caching.
+//
+
+void FARINTERNAL DecreaseHandlerObjCount (iTable)
+int iTable;
+{
+ if (!iTable)
+ return;
+
+ if (iTable != INVALID_INDEX) {
+ ASSERT (lpDllTable[iTable].cObj, "Handler Obj count is already NULL");
+ if (!--lpDllTable[iTable].cObj) {
+ UnloadDll ();
+ iUnloadableDll = iTable;
+ }
+ }
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FARINTERNAL CreatePictFromClip (lpclient, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, lpClass, ctype)
+*
+* CreatePictFromClip: This function creates the LP to an object
+* from the clipboard. It will try to create a static picture object if
+* it understands any rendering formats on the clipboard. Currently, it
+* understands only bitmaps and metafiles.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FARINTERNAL CreatePictFromClip (lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, lpClass, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LPSTR lpClass;
+LONG objType;
+{
+ OLESTATUS retVal = OLE_ERROR_OPTION;
+
+ *lplpobj = NULL;
+
+ if (optRender == olerender_none)
+ return OLE_OK;
+ else if (optRender == olerender_format) {
+ switch (cfFormat) {
+ case NULL:
+ return OLE_ERROR_FORMAT;
+
+ case CF_METAFILEPICT:
+ return MfPaste (lpclient, lhclientdoc, lpobjname,
+ lplpobj, objType);
+
+ case CF_DIB:
+ return DibPaste (lpclient, lhclientdoc, lpobjname,
+ lplpobj, objType);
+
+ case CF_BITMAP:
+ return BmPaste (lpclient, lhclientdoc, lpobjname,
+ lplpobj, objType);
+
+ default:
+ return GenPaste (lpclient, lhclientdoc, lpobjname, lplpobj,
+ lpClass, cfFormat, objType);
+ }
+ }
+ else if (optRender == olerender_draw) {
+ cfFormat = EnumClipboardFormats (NULL);
+ while ((cfFormat) && (retVal > OLE_WAIT_FOR_RELEASE)) {
+ switch (cfFormat) {
+ case CF_METAFILEPICT:
+ retVal = MfPaste (lpclient, lhclientdoc,
+ lpobjname, lplpobj, objType);
+ break;
+
+ case CF_DIB:
+ retVal = DibPaste (lpclient, lhclientdoc,
+ lpobjname, lplpobj, objType);
+ break;
+
+ case CF_BITMAP:
+ retVal = BmPaste (lpclient, lhclientdoc,
+ lpobjname, lplpobj, objType);
+ break;
+ }
+
+ cfFormat = EnumClipboardFormats (cfFormat);
+ }
+ }
+
+ return retVal;
+}
+
+
+
+OLESTATUS FARINTERNAL CreatePackageFromClip (lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ char file[MAX_STR+6];
+ HANDLE hData;
+ LPSTR lpFileName;
+
+ if (!(hData = GetClipboardData (cfFileName))
+ || !(lpFileName = GlobalLock (hData)))
+ return OLE_ERROR_CLIPBOARD;
+
+
+ if (objType == OT_LINK) {
+ lstrcpy (file, lpFileName);
+ lstrcat (file, "/Link");
+ lpFileName = (LPSTR) file;
+ }
+
+ GlobalUnlock (hData);
+
+ return CreateEmbLnkFromFile (lpclient, packageClass, lpFileName,
+ NULL, lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, OT_EMBEDDED);
+}
+
+
+
+void FARINTERNAL RemoveLinkStringFromTopic (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR+6];
+ int i = 0;
+
+ if (GlobalGetAtomName (lpobj->topic, buf, sizeof(buf))) {
+ // scan the topic for "/Link"
+ while (buf[i] != '/') {
+ if (!buf[i])
+ return;
+ i++;
+ }
+
+ buf[i] = '\0';
+ if (lpobj->topic)
+ GlobalDeleteAtom (lpobj->topic);
+ lpobj->topic = GlobalAddAtom (buf);
+ }
+}
+
+void SetMaxPixel ()
+{
+ HDC hdc;
+ // find out the pixel equivalent of MAX_HIMETRIC in X and Y directions
+
+ if (hdc = GetDC (NULL)) {
+ maxPixelsX = MulDiv (MAX_HIMETRIC, GetDeviceCaps(hdc, LOGPIXELSX),
+ 2540);
+ maxPixelsY = MulDiv (MAX_HIMETRIC, GetDeviceCaps(hdc, LOGPIXELSY),
+ 2540);
+ ReleaseDC (NULL, hdc);
+ }
+}
+
+
diff --git a/private/mvdm/wow16/ole/client/makefile b/private/mvdm/wow16/ole/client/makefile
new file mode 100644
index 000000000..cdb658f3e
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/makefile
@@ -0,0 +1,169 @@
+#
+# Make file for ole library routines
+#
+# International mods
+# NOTE: INTL_SRC, INTL_EXE and LANG are macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=$(INTL_SRC)\$(LANG)\sdk\ole\client
+EXE_DIR=$(INTL_EXE)
+!ENDIF
+
+
+# Flags set assuming small model
+
+LIBS= sdllcew libw shell
+LIBENTRY_OBJ=libentry.obj
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+DEBUG=1
+CDEBUG = /Od /Oi /Zd
+ADEBUG = -Zd
+LDEBUG = /LI
+!endif
+
+!ifdef DEBUG
+BLD=debug
+CFLAGS= -c -ASw -G2sw -Od -Zipe -W3 -DFIREWALLS $(CDEBUG)
+LFLAGS=/NOD /NOE /M $(LDEBUG)
+AFLAGS= -D?PLM=0 -D?WIN=1 -ZI -W2 $(ADEBUG)
+!else
+BLD=retail
+CFLAGS=-c -ASw -G2sw -Zpe -W3 -Ox
+LFLAGS=/NOD /NOE /M
+AFLAGS=-D?PLM=0 -D?WIN=1 -W2
+!endif
+
+
+LE_OBJ= $(BLD)\main.obj $(BLD)\ole.obj $(BLD)\defcreat.obj $(BLD)\le.obj $(BLD)\dde.obj $(BLD)\ledde.obj $(BLD)\utils.obj $(BLD)\pbhandlr.obj $(BLD)\doc.obj $(BLD)\oleasm.obj $(BLD)\net.obj
+
+PICT_OBJ= $(BLD)\mf.obj $(BLD)\generic.obj $(BLD)\bm.obj $(BLD)\dib.obj $(BLD)\error.obj $(BLD)\draw.obj
+
+
+#International mods
+!IFNDEF LANG
+ALL: $(BLD)\olecli.dll $(BLD)\olecli.lib
+!ELSE
+all: retail\olecli.$(LANG)
+!ENDIF
+
+
+!IFNDEF LANG
+ole.rc: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+olecli.rcv: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+
+ole.res: ole.rc olecli.rcv
+ rc16 -r ole.rc $@
+!ELSE
+ole.res: $(RES_DIR)\$@
+ copy $(RES_DIR)\$@
+!ENDIF
+
+
+$(BLD)\olecli.lib: olecli.def
+ mkpublic olecli.def stripped.def
+ implib $@ stripped.def
+ del stripped.def
+
+$(BLD)\oleasm.obj: ole.asm
+ masm $(AFLAGS) ole.asm, $@;
+
+$(BLD)\main.obj: main.c
+ cl16 $(CFLAGS) -NT _MAIN -Fo$@ $**
+
+$(BLD)\doc.obj: doc.c
+ cl16 $(CFLAGS) -NT _MAIN -Fo$@ $**
+
+$(BLD)\error.obj: error.c
+ cl16 $(CFLAGS) -NT _MISC -Fo$@ $**
+
+$(BLD)\dde.obj: dde.c
+ cl16 $(CFLAGS) -NT _DDETEXT -Fo$@ $**
+
+$(BLD)\ledde.obj: ledde.c
+ cl16 $(CFLAGS) -NT _DDETEXT -Fo$@ $**
+
+$(BLD)\defcreat.obj: defcreat.c
+ cl16 $(CFLAGS) -NT _DEFTEXT -Fo$@ $**
+
+$(BLD)\draw.obj: draw.c
+ cl16 $(CFLAGS) -NT _DRAW -Fo$@ $**
+
+$(BLD)\mf.obj: mf.c
+ cl16 $(CFLAGS) -NT _MF -Fo$@ $**
+
+$(BLD)\bm.obj: bm.c
+ cl16 $(CFLAGS) -NT _BM -Fo$@ $**
+
+$(BLD)\dib.obj: dib.c
+ cl16 $(CFLAGS) -NT _DIB -Fo$@ $**
+
+$(BLD)\generic.obj: generic.c
+ cl16 $(CFLAGS) -NT _GEN -Fo$@ $**
+
+$(BLD)\net.obj: net.c
+ cl16 $(CFLAGS) -NT _NET -Fo$@ $**
+
+$(BLD)\pbhandlr.obj: pbhandlr.c
+ cl16 $(CFLAGS) -NT _PBRUSH -Fo$@ $**
+
+{}.c{$(BLD)}.obj:
+ cl16 $(CFLAGS) -Fo$@ $<
+
+
+$(BLD)\olecli.dll: $(LE_OBJ) $(PICT_OBJ) ole.res olecli.def
+ link $(LFLAGS) @<<
+$(LE_OBJ) +
+$(PICT_OBJ) +
+$(LIBENTRY_OBJ)
+$(BLD)\olecli.dll
+$(BLD)\olecli.map
+$(LIBS)
+olecli.def;
+<<
+ -@ cd $(BLD)
+ rc16 -30 ..\ole.res olecli.dll
+ mapsym olecli
+ convdll olecli.dll
+ -@ cd..
+
+ole.c: dll.h
+defcreat.c: dll.h
+utils.c: dll.h
+dde.c: dll.h
+le.c: dll.h
+ledde.c: dll.h
+pbhandlr.c: dll.h
+doc.c: dll.h
+net.c: dll.h
+bm.c: dll.h pict.h
+mf.c: dll.h pict.h
+dib.c: dll.h pict.h
+generic.c: dll.h pict.h
+error.c: dll.h pict.h
+draw.c: dll.h pict.h
+
+dll.h: ole.h
+
+
+iclean:
+ del *.rc
+ del *.rcv
+ del *.res
+
+retail\olecli.$(LANG): iclean ole.res
+ copy $(EXE_DIR)\olecli.dll retail\olecli.$(LANG)
+ -@ cd retail
+ rc16 -t -30 ..\ole.res olecli.$(LANG)
+ -@ cd..
diff --git a/private/mvdm/wow16/ole/client/mf.c b/private/mvdm/wow16/ole/client/mf.c
new file mode 100644
index 000000000..9aaf4fc9b
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/mf.c
@@ -0,0 +1,645 @@
+/****************************** Module Header ******************************\
+* Module Name:MF.C (Extensible Compound Documents - Metafile)
+*
+* PURPOSE:Handles all API routines for the metafile sub-dll of the ole dll.
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+*
+* Raor, Srinik (../../1990,91) Designed, coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+#include "pict.h"
+
+WORD wGDIds = NULL;
+
+OLESTATUS FARINTERNAL wCreateDummyMetaFile (LPOBJECT_MF, int, int);
+
+#pragma alloc_text(_TEXT, MfSaveToStream, MfLoadFromStream, GetBytes, PutBytes, PutStrWithLen, MfQueryBounds, OleIsDcMeta, GetGDIds, IsMetaDC)
+
+OLEOBJECTVTBL vtblMF = {
+
+ ErrQueryProtocol, // check whether the speced protocol is supported
+
+ MfRelease, // Release
+ ErrShow, // show
+ ErrPlay, // play
+ MfGetData, // Get the object data
+ ErrSetData, // Set the object data
+ ErrSetTargetDevice,//
+ ErrSetBounds, // set viewport bounds
+ MfEnumFormat, // enumerate supported formats
+ ErrSetColorScheme, //
+ MfRelease, // delete
+ ErrSetHostNames, //
+
+ MfSaveToStream, // write to file
+ MfClone, // clone object
+ ErrCopyFromLink, // Create embedded from Lnk
+
+ MfEqual, // compares the given objects for data equality
+
+ MfCopy, // copy to clip
+
+ MfDraw, // draw the object
+
+ ErrActivate, // open
+ ErrExecute, // excute
+ ErrClose, // stop
+ ErrUpdate, // Update
+ ErrReconnect, // Reconnect
+
+ ErrObjectConvert, // convert object to specified type
+
+ ErrGetUpdateOptions, // update options
+ ErrSetUpdateOptions, // update options
+
+ ObjRename, // Change Object name
+ ObjQueryName, // Get current object name
+ ObjQueryType, // Object type
+ MfQueryBounds, // QueryBounds
+ ObjQuerySize, // Find the size of the object
+ ErrQueryOpen, // Query open
+ ErrQueryOutOfDate, // query whether object is current
+
+ ErrQueryRelease, // release related stuff
+ ErrQueryRelease,
+ ErrQueryRelease,
+
+ ErrRequestData, // requestdata
+ ErrObjectLong, // objectLong
+ MfChangeData // change data of the existing object
+};
+
+
+
+
+OLESTATUS FARINTERNAL MfRelease (lpobj)
+LPOBJECT_MF lpobj;
+{
+ HOBJECT hobj;
+
+ if (lpobj->mfp.hMF) {
+ DeleteMetaFile (lpobj->mfp.hMF);
+ lpobj->mfp.hMF = NULL;
+ }
+
+ if (lpobj->hmfp)
+ GlobalFree (lpobj->hmfp);
+
+ if (lpobj->head.lhclientdoc)
+ DocDeleteObject ((LPOLEOBJECT)lpobj);
+
+ if (hobj = lpobj->head.hobj) {
+ lpobj->head.hobj = NULL;
+ GlobalUnlock (hobj);
+ GlobalFree (hobj);
+ }
+
+ return OLE_OK;
+}
+
+
+OLESTATUS FARINTERNAL MfSaveToStream (lpobj, lpstream)
+LPOBJECT_MF lpobj;
+LPOLESTREAM lpstream;
+{
+ OLESTATUS retVal = OLE_ERROR_STREAM;
+ HANDLE hBits;
+ LPSTR lpBits;
+
+ if (!lpobj->mfp.hMF)
+ return OLE_ERROR_BLANK;
+
+ if (PutBytes (lpstream, (LPSTR) &dwVerToFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutStrWithLen(lpstream, (LPSTR)"METAFILEPICT"))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (PutBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (!(hBits = GetMetaFileBits (lpobj->mfp.hMF)))
+ return OLE_ERROR_MEMORY;
+
+ if (lpBits = (LPSTR) GlobalLock (hBits)) {
+ if (!PutBytes (lpstream, (LPSTR)&lpobj->mfp, sizeof(METAFILEPICT)))
+ if (!PutBytes (lpstream, (LPSTR)lpBits,
+ lpobj->sizeBytes - sizeof(METAFILEPICT)))
+ retVal = OLE_OK;
+
+ GlobalUnlock(hBits);
+ }
+ else
+ retVal = OLE_ERROR_MEMORY;
+
+ lpobj->mfp.hMF = SetMetaFileBits (hBits);
+ return retVal;
+}
+
+
+
+
+OLESTATUS FARINTERNAL MfClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOBJECT_MF lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOBJECT_MF FAR * lplpobj;
+{
+ LPOBJECT_MF lpobjMf;
+ HANDLE hmf;
+
+ *lplpobj = NULL;
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (!(hmf = CopyMetaFile (lpobjsrc->mfp.hMF, NULL)))
+ return OLE_ERROR_MEMORY;
+
+ if (lpobjMf = MfCreateBlank (lhclientdoc, lpobjname,
+ lpobjsrc->head.ctype)) {
+ lpobjMf->mfp = lpobjsrc->mfp;
+ lpobjMf->sizeBytes = lpobjsrc->sizeBytes;
+ lpobjMf->mfp.hMF = hmf;
+ lpobjMf->head.lpclient = lpclient;
+ lpobjMf->head.mm = lpobjMf->mfp.mm;
+ MfSetExtents (lpobjMf);
+
+ *lplpobj = lpobjMf;
+ return OLE_OK;
+ }
+
+ return OLE_ERROR_MEMORY;
+}
+
+
+
+OLESTATUS FARINTERNAL MfEqual (lpobj1, lpobj2)
+LPOBJECT_MF lpobj1;
+LPOBJECT_MF lpobj2;
+{
+ HANDLE hBits1 = NULL, hBits2 = NULL;
+ OLESTATUS retval = OLE_ERROR_NOT_EQUAL;
+
+ if (!(hBits1 = GetMetaFileBits (lpobj1->mfp.hMF)))
+ goto errEqual;
+
+ if (!(hBits2 = GetMetaFileBits (lpobj2->mfp.hMF)))
+ goto errEqual;
+
+ if (CmpGlobals (hBits1, hBits2))
+ retval = OLE_OK;
+
+errEqual:
+ if (hBits1)
+ lpobj1->mfp.hMF = SetMetaFileBits (hBits1);
+
+ if (hBits2)
+ lpobj2->mfp.hMF = SetMetaFileBits (hBits2);
+
+ return retval;
+}
+
+
+OLESTATUS FARINTERNAL MfCopy (LPOBJECT_MF lpobj)
+{
+ HANDLE hMF;
+
+ if (!(hMF = CopyMetaFile (lpobj->mfp.hMF, NULL)))
+ return OLE_ERROR_MEMORY;
+
+ return (MfCopyToClip (lpobj, hMF));
+}
+
+
+
+OLESTATUS FARINTERNAL MfQueryBounds (lpobj, lpRc)
+LPOBJECT_MF lpobj;
+LPRECT lpRc;
+{
+ Puts("MfQueryBounds");
+
+ if (!lpobj->mfp.hMF)
+ return OLE_ERROR_BLANK;
+
+ // Bounds are given in MM_HIMETRIC mode.
+
+ lpRc->left = 0;
+ lpRc->top = 0;
+ lpRc->right = (int) lpobj->head.cx;
+ lpRc->bottom = (int) lpobj->head.cy;
+ return OLE_OK;
+}
+
+
+
+OLECLIPFORMAT FARINTERNAL MfEnumFormat (lpobj, cfFormat)
+LPOBJECT_MF lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ if (!cfFormat)
+ return CF_METAFILEPICT;
+
+ return NULL;
+}
+
+
+OLESTATUS FARINTERNAL MfGetData (lpobj, cfFormat, lphandle)
+LPOBJECT_MF lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+ if (cfFormat != CF_METAFILEPICT)
+ return OLE_ERROR_FORMAT;
+
+ if (!(*lphandle = GetHmfp (lpobj)))
+ return OLE_ERROR_BLANK;
+
+ return OLE_OK;
+}
+
+
+LPOBJECT_MF FARINTERNAL MfCreateObject (hMeta, lpclient, fDelete, lhclientdoc, lpobjname, objType)
+HANDLE hMeta;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ LPOBJECT_MF lpobj;
+
+ if (lpobj = MfCreateBlank (lhclientdoc, lpobjname, objType)) {
+ if (MfChangeData (lpobj, hMeta, lpclient, fDelete) != OLE_OK) {
+ MfRelease (lpobj);
+ lpobj = NULL;
+ }
+ }
+
+ return lpobj;
+}
+
+// If the routine fails then the object will be left with it's old data.
+// If fDelete is TRUE, then hMeta, and the hMF it contains will be deleted
+// whether the routine is successful or not.
+
+OLESTATUS FARINTERNAL MfChangeData (lpobj, hMeta, lpclient, fDelete)
+LPOBJECT_MF lpobj;
+HANDLE hMeta;
+LPOLECLIENT lpclient;
+BOOL fDelete;
+{
+ HANDLE hNewMF;
+ LPMETAFILEPICT lpMetaPict;
+
+ if ((lpMetaPict = (LPMETAFILEPICT) GlobalLock (hMeta)) == NULL) {
+ if (fDelete)
+ GlobalFree (hMeta);
+ return OLE_ERROR_MEMORY;
+ }
+
+ GlobalUnlock (hMeta);
+
+ if (!fDelete) {
+ if (!(hNewMF = CopyMetaFile (lpMetaPict->hMF, NULL)))
+ return OLE_ERROR_MEMORY;
+ }
+ else {
+ hNewMF = lpMetaPict->hMF;
+ }
+
+ return MfUpdateStruct (lpobj, lpclient, hMeta, lpMetaPict, hNewMF, fDelete);
+}
+
+
+OLESTATUS INTERNAL MfUpdateStruct (lpobj, lpclient, hMeta, lpMetaPict, hMF, fDelete)
+LPOBJECT_MF lpobj;
+LPOLECLIENT lpclient;
+HANDLE hMeta;
+LPMETAFILEPICT lpMetaPict;
+HANDLE hMF;
+BOOL fDelete;
+{
+ OLESTATUS retVal;
+ DWORD size;
+ HANDLE hOldMF;
+
+ hOldMF = lpobj->mfp.hMF;
+
+ ASSERT(lpMetaPict->mm == MM_ANISOTROPIC, "Wrong mapping mode")
+ if (lpMetaPict->mm != MM_ANISOTROPIC)
+ retVal = OLE_ERROR_METAFILE;
+ else if (!(size = MfGetSize (&hMF)))
+ retVal = OLE_ERROR_BLANK;
+ else {
+ lpobj->mfp = *lpMetaPict;
+ lpobj->mfp.hMF = hMF;
+ lpobj->sizeBytes = size + sizeof(METAFILEPICT);
+ lpobj->head.lpclient = lpclient;
+ lpobj->head.mm = lpobj->mfp.mm;
+ if (lpobj->hmfp) {
+ GlobalFree (lpobj->hmfp);
+ lpobj->hmfp = NULL;
+ }
+ MfSetExtents (lpobj);
+ if (hOldMF)
+ DeleteMetaFile (hOldMF);
+ retVal = OLE_OK;
+ }
+
+ if (retVal != OLE_OK)
+ DeleteMetaFile (hMF);
+
+ if (fDelete)
+ GlobalFree (hMeta);
+ return retVal;
+}
+
+
+LPOBJECT_MF FARINTERNAL MfCreateBlank(lhclientdoc, lpobjname, objType)
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LONG objType;
+{
+ HOBJECT hobj;
+ LPOBJECT_MF lpobj;
+
+ if(!(hobj = GlobalAlloc (GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof (OBJECT_MF))))
+ return NULL;
+
+ if (!(lpobj = (LPOBJECT_MF) GlobalLock (hobj))){
+ GlobalFree (hobj);
+ return NULL;
+ }
+
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+ lpobj->head.ctype = objType;
+ lpobj->head.lpvtbl = (LPOLEOBJECTVTBL)&vtblMF;
+ lpobj->head.iTable = INVALID_INDEX;
+ lpobj->head.mm = MM_TEXT;
+ lpobj->head.hobj = hobj;
+
+ if (objType == CT_STATIC)
+ DocAddObject ((LPCLIENTDOC) lhclientdoc,
+ (LPOLEOBJECT) lpobj, lpobjname);
+
+ // Unlock will be done at object deletion time.
+ return lpobj;
+}
+
+
+OLESTATUS FARINTERNAL MfLoadFromStream (lpstream, lpclient, lhclientdoc, lpobjname, lplpobj, objType)
+LPOLESTREAM lpstream;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LONG objType;
+{
+ LPOBJECT_MF lpobj = NULL;
+ OLESTATUS retVal = OLE_ERROR_STREAM;
+ HANDLE hBits;
+ LPSTR lpBits;
+ DWORD dwSizeMfp = NULL;
+
+ // Class name would've been read by this time.
+
+ *lplpobj = NULL;
+
+ if (!(lpobj = MfCreateBlank (lhclientdoc, lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ lpobj->head.lpclient = lpclient;
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->head.cx, sizeof(LONG)))
+ goto errLoad;
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->head.cy, sizeof(LONG)))
+ goto errLoad;
+
+ if (GetBytes (lpstream, (LPSTR) &lpobj->sizeBytes, sizeof(LONG)))
+ goto errLoad;
+
+ if (!lpobj->sizeBytes) {
+ retVal = OLE_ERROR_BLANK;
+ goto errLoad;
+ }
+
+ // if we are reading a MAC object we want to skip this
+ if (HIWORD(dwVerFromFile) == OS_WIN16) {
+ if (GetBytes (lpstream, (LPSTR) &lpobj->mfp, sizeof(METAFILEPICT)))
+ goto errLoad;
+
+ dwSizeMfp = sizeof(METAFILEPICT);
+ }
+
+ retVal = OLE_ERROR_MEMORY;
+ if (!(hBits = GlobalAlloc (GMEM_MOVEABLE, lpobj->sizeBytes - dwSizeMfp)))
+ goto errLoad;
+
+ if (!(lpBits = (LPSTR)GlobalLock (hBits)))
+ goto errMem;
+
+ if (GetBytes (lpstream, (LPSTR)lpBits, lpobj->sizeBytes - dwSizeMfp)) {
+ retVal = OLE_ERROR_MEMORY;
+ GlobalUnlock (hBits);
+ goto errMem;
+ }
+
+ lpobj->head.mm = lpobj->mfp.mm;
+ GlobalUnlock (hBits);
+
+ if (HIWORD(dwVerFromFile) == OS_WIN16) {
+ if (!(lpobj->mfp.hMF = SetMetaFileBits (hBits)))
+ goto errMem;
+ }
+ else {
+ // if we are reading a MAC object we want to delete the original
+ // presentation data and show some rectangle
+
+ GlobalFree (hBits);
+ lpobj->mfp.xExt = (int) lpobj->head.cx;
+ lpobj->mfp.yExt = (int) lpobj->head.cy;
+
+ if ((retVal = wCreateDummyMetaFile (lpobj, lpobj->mfp.xExt,
+ lpobj->mfp.yExt)) != OLE_OK)
+ goto errLoad;
+ }
+
+ MfSetExtents (lpobj);
+
+ *lplpobj = (LPOLEOBJECT) lpobj;
+ return OLE_OK;
+
+errMem:
+ GlobalFree (hBits);
+
+errLoad:
+ OleDelete ((LPOLEOBJECT)lpobj);
+ return retVal;
+}
+
+
+
+
+OLESTATUS FARINTERNAL MfPaste (lpclient, lhclientdoc, lpobjname, lplpoleobject, objType)
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+LONG objType;
+{
+ HANDLE hMeta;
+
+ *lplpoleobject = NULL;
+
+ if((hMeta = GetClipboardData (CF_METAFILEPICT)) == NULL)
+ return OLE_ERROR_MEMORY;
+
+ if (!(*lplpoleobject = (LPOLEOBJECT) MfCreateObject (hMeta, lpclient,
+ FALSE, lhclientdoc,
+ lpobjname, objType)))
+ return OLE_ERROR_MEMORY;
+
+ return OLE_OK;
+}
+
+
+
+
+OLESTATUS INTERNAL MfCopyToClip (lpobj, hMF)
+LPOBJECT_MF lpobj;
+HANDLE hMF;
+{
+ LPMETAFILEPICT lpMeta;
+ HANDLE hMeta;
+
+ if (!(hMeta = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT))))
+ return OLE_ERROR_MEMORY;
+
+ if (lpMeta = (LPMETAFILEPICT) GlobalLock(hMeta)){
+ *lpMeta = lpobj->mfp;
+ if (hMF)
+ lpMeta->hMF = hMF;
+ else
+ lpobj->mfp.hMF = NULL;
+ GlobalUnlock (hMeta);
+ SetClipboardData(CF_METAFILEPICT, hMeta);
+ return OLE_OK;
+ }
+
+ GlobalFree(hMeta);
+ return OLE_ERROR_MEMORY;
+}
+
+
+
+void FARINTERNAL MfSetExtents (LPOBJECT_MF lpobj)
+{
+ if (lpobj->mfp.xExt > 0) {
+ // The extents are assumed to be in MM_HIMETIRC units
+ lpobj->head.cx = (LONG) lpobj->mfp.xExt;
+ lpobj->head.cy = (LONG) - lpobj->mfp.yExt;
+ }
+}
+
+
+DWORD INTERNAL MfGetSize (lphmf)
+LPHANDLE lphmf;
+{
+ HANDLE hBits;
+ DWORD size;
+
+ if ((hBits = GetMetaFileBits (*lphmf)) == NULL)
+ return NULL;
+
+ size = GlobalSize(hBits);
+ *lphmf = SetMetaFileBits (hBits);
+ return size;
+}
+
+
+
+HANDLE INTERNAL GetHmfp (lpobj)
+LPOBJECT_MF lpobj;
+{
+ HANDLE hmfp;
+ LPMETAFILEPICT lpmfp = NULL;
+
+ if (lpobj->hmfp)
+ return lpobj->hmfp;
+
+ if (!(hmfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT))))
+ return NULL;
+
+ if (!(lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp))) {
+ GlobalFree (hmfp);
+ return NULL;
+ }
+
+ *lpmfp = lpobj->mfp;
+ GlobalUnlock (hmfp);
+ return (lpobj->hmfp = hmfp);
+}
+
+
+BOOL FAR PASCAL OleIsDcMeta (hdc)
+HDC hdc;
+{
+ if (!bWLO && (wWinVer == 0x0003)) {
+
+ WORD wDsAlias, wGDIcs = HIWORD(SaveDC);
+ WORD wOffset = LOWORD(((DWORD)SaveDC));
+ WORD FAR PASCAL AllocCStoDSAlias (WORD);
+ WORD FAR PASCAL FreeSelector (WORD);
+
+ if (!wGDIds) {
+ wDsAlias = AllocCStoDSAlias (wGDIcs);
+ wGDIds = GetGDIds (MAKELONG(wOffset, wDsAlias));
+ FreeSelector (wDsAlias);
+ }
+
+ return IsMetaDC (hdc, wGDIds);
+ }
+ else
+ return (GetDeviceCaps (hdc, TECHNOLOGY) == DT_METAFILE);
+}
+
+OLESTATUS FARINTERNAL wCreateDummyMetaFile (
+LPOBJECT_MF lpobj,
+int xExt,
+int yExt)
+{
+ HDC hMetaDC;
+
+ if (!(hMetaDC = CreateMetaFile (NULL)))
+ return OLE_ERROR_MEMORY;
+
+ SetWindowOrg (hMetaDC, 0, 0);
+ SetWindowExt (hMetaDC, xExt, yExt);
+ Rectangle (hMetaDC, 0, 0, xExt, yExt);
+ if (!(lpobj->mfp.hMF = CloseMetaFile (hMetaDC)))
+ return OLE_ERROR_MEMORY;
+ lpobj->mfp.mm = MM_ANISOTROPIC;
+ lpobj->sizeBytes = MfGetSize (&lpobj->mfp.hMF) + sizeof(METAFILEPICT);
+ return OLE_OK;
+}
diff --git a/private/mvdm/wow16/ole/client/mk.cmd b/private/mvdm/wow16/ole/client/mk.cmd
new file mode 100644
index 000000000..484f0121d
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/mk.cmd
@@ -0,0 +1,55 @@
+@Echo off
+
+REM Cmd file building DEBUG, RETAIL, and RELEASE versions of DLL
+
+SET DEBUG=
+SET RETAIL=
+REM set path2=%path%
+REM set include2=%include%
+REM set lib2=%lib%
+REM set path=\ole\bin;\ole\bin\os2
+REM set include=\ole\inc
+REM set lib=\ole\lib
+
+if %1x==x goto debug
+
+if %1==debug goto debug
+
+if %1==retail goto retail
+
+if %1==release goto retail
+goto end
+
+:retail
+SET RETAIL=TRUE
+if NOT EXIST retail md retail
+goto make
+
+:debug
+SET DEBUG=TRUE
+if NOT EXIST debug md debug
+goto make
+
+:make
+nmake >z.msg
+goto end
+
+:release
+if NOT EXIST retail md retail
+SET RETAIL=TRUE
+nmake >z.msg
+if NOT EXIST release md release
+copy retail\*.dll release > nul 2>&1
+copy retail\*.exe release > nul 2>&1
+copy retail\*.map release > nul 2>&1
+goto end
+
+:end
+REM set path=%path2%
+REM set path2=
+REM set include=%include2%
+REM set include2=
+REM set lib=%lib2%
+REM set lib2=
+SET DEBUG=
+SET RETAIL=
diff --git a/private/mvdm/wow16/ole/client/net.asv b/private/mvdm/wow16/ole/client/net.asv
new file mode 100644
index 000000000..6b4c0c4d4
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/net.asv
@@ -0,0 +1,371 @@
+/****************************** Module Header ******************************\
+* Module Name: net.c
+*
+* PURPOSE: Contains routines network support
+*
+* Created: Feb 1991
+*
+* Copyright (c) 1991 Microsoft Corporation
+*
+* History:
+* Srinik 02\12\1190 Orginal
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include <winnet.h>
+
+#include "dll.h"
+
+#define MAX_DRIVE 26
+
+char szNULL[] = "";
+char szSS[] = "SS";
+char szOffset[] = "OFFSET";
+
+
+BOOL FAR PASCAL GetTaskVisibleWindow (HWND, DWORD);
+void INTERNAL RemoveNetName (LPOBJECT_LE);
+
+// Gets the drive letter from topic (if one exists) and then gets the remote
+// name for that drive and then saves it in the object.
+
+OLESTATUS FARINTERNAL SetNetName (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR];
+ WORD cbBuf = sizeof(buf);
+ WORD driveType;
+ char szDrive[3];
+
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return OLE_OK;
+
+ if (!GlobalGetAtomName (lpobj->topic, buf, cbBuf))
+ return OLE_ERROR_BLANK;
+
+ if (buf[1] != ':') {
+ RemoveNetName (lpobj);
+ return OLE_OK;
+ }
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ szDrive[0] = buf[0];
+ AnsiUpperBuff ((LPSTR) szDrive, 1);
+
+ if (!(driveType = GetDriveType (szDrive[0] - 'A'))) {
+ // drive is non existent
+ return OLE_ERROR_DRIVE;
+ }
+
+ if (driveType == DRIVE_REMOTE) {
+ if (WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ != WN_SUCCESS)
+ return OLE_ERROR_DRIVE;
+
+ lpobj->cDrive = szDrive[0];
+ if (lpobj->aNetName)
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = GlobalAddAtom(buf);
+ lpobj->dwNetInfo = MAKELONG((WNetGetCaps (WNNC_NET_TYPE)),
+ (WNetGetCaps (WNNC_DRIVER_VERSION)));
+ }
+ else {
+ RemoveNetName (lpobj);
+ }
+
+ return OLE_OK;
+}
+
+
+// If netname exists for the given object, then it makes sure that drive
+// in topic corresponds to the netname. If it's not the drive letter will
+// be fixed by calling FixNet()
+
+OLESTATUS FARINTERNAL CheckNetDrive (lpobj, fNetDlg)
+LPOBJECT_LE lpobj;
+BOOL fNetDlg;
+{
+ char buf[MAX_NET_NAME];
+ char netName[MAX_NET_NAME];
+ WORD cbBuf = sizeof(buf);
+ char szDrive[3];
+
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return OLE_OK;
+
+ if (!lpobj->aNetName)
+ return OLE_OK;
+
+ if (!GlobalGetAtomName (lpobj->aNetName, netName, sizeof(netName)))
+ return OLE_ERROR_MEMORY;
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ if (!(szDrive[0] = lpobj->cDrive)) {
+ if (GlobalGetAtomName (lpobj->topic, buf, sizeof(buf)))
+ szDrive[0] = lpobj->cDrive = buf[0];
+ }
+
+ if ((WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ == WN_SUCCESS) && (!lstrcmp(netName, buf)))
+ return OLE_OK;
+
+ return FixNet (lpobj, netName, fNetDlg);
+}
+
+
+// Find if there is a drive connected to the given server. If so, get the
+// drive letter and set it in topic. If not try to make connection, and if
+// that attempt is successful the set the drive letter in topic.
+
+OLESTATUS INTERNAL FixNet (lpobj, lpNetName, fNetDlg)
+LPOBJECT_LE lpobj;
+LPSTR lpNetName;
+BOOL fNetDlg;
+{
+ int nDrive = 2; // drive 'C'
+ OLESTATUS retVal;
+
+ if (SetNextNetDrive(lpobj, &nDrive, lpNetName))
+ return OLE_OK;
+
+ if (fNetDlg != POPUP_NETDLG)
+ return OLE_ERROR_NETWORK;
+
+ if ((retVal = ConnectNet (lpobj, lpNetName)) == OLE_OK) {
+ if (!ChangeTopic (lpobj))
+ return OLE_ERROR_BLANK;
+ }
+
+ return retVal;
+}
+
+
+
+BOOL FARINTERNAL SetNextNetDrive (lpobj, lpnDrive, lpNetName)
+LPOBJECT_LE lpobj;
+int FAR * lpnDrive;
+LPSTR lpNetName;
+{
+ char buf[MAX_STR];
+ WORD cbBuf = sizeof(buf);
+ char szDrive[3];
+
+ if (!lpNetName[0]) {
+ if (!GlobalGetAtomName(lpobj->aNetName, lpNetName, MAX_STR))
+ return FALSE;
+ }
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ while (*lpnDrive < MAX_DRIVE) {
+ if (GetDriveType (++*lpnDrive) == DRIVE_REMOTE) {
+ szDrive[0] = (char) ('A' + *lpnDrive);
+ cbBuf = sizeof(buf);
+ if ((WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ == WN_SUCCESS) && (!lstrcmp(lpNetName, buf))) {
+ lpobj->cDrive = szDrive[0];
+ return ChangeTopic (lpobj);
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+BOOL FARINTERNAL ChangeTopic (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR];
+
+ if (!GlobalGetAtomName(lpobj->topic, buf, sizeof(buf)))
+ return FALSE;
+ if (lpobj->topic)
+ GlobalDeleteAtom(lpobj->topic);
+ buf[0] = lpobj->cDrive;
+ lpobj->topic = GlobalAddAtom (buf);
+ if (lpobj->hLink) {
+ GlobalFree (lpobj->hLink);
+ lpobj->hLink = NULL;
+ }
+
+ return TRUE;
+}
+
+
+
+OLESTATUS INTERNAL ConnectNet (lpobj, lpNetName)
+LPOBJECT_LE lpobj;
+LPSTR lpNetName;
+{
+ FARPROC lpConnectDlg;
+ FARPROC lpGetTaskVisWnd;
+ OLESTATUS retVal = OLE_ERROR_MEMORY;
+ HWND hCurTask;
+ HWND hwndParent = NULL;
+
+ if (!(lpConnectDlg = MakeProcInstance ((FARPROC) ConnectDlgProc,
+ hInstDLL)))
+ return OLE_ERROR_MEMORY;
+
+
+ hCurTask = GetCurrentTask();
+ ASSERT (hCurTask, "Current task handle in NULL");
+
+ if (!(lpGetTaskVisWnd = MakeProcInstance (GetTaskVisibleWindow,hInstDLL)))
+ goto errRtn;
+
+ // Get the container task's main window, and use that as parent for
+ // the dlg box.
+ EnumTaskWindows (hCurTask, lpGetTaskVisWnd,
+ (DWORD) ((WORD FAR *) &hwndParent));
+
+ if (lpobj->cDrive = (char) DialogBoxParam (hInstDLL, "CONNECTDLG",
+ hwndParent, lpConnectDlg,
+ (DWORD) lpNetName))
+ retVal = OLE_OK;
+ else
+ retVal = OLE_ERROR_NETWORK;
+
+ FreeProcInstance (lpGetTaskVisWnd);
+
+errRtn:
+ FreeProcInstance (lpConnectDlg);
+ return retVal;
+}
+
+
+
+int FAR PASCAL ConnectDlgProc(HWND hDlg, WORD wMsg, WORD wParam, DWORD lParam)
+{
+ char szPassword[32];
+ char szTitle[64];
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+ SetProp (hDlg, szSS, HIWORD (lParam));
+ SetProp (hDlg, szOffset, LOWORD (lParam));
+ FillDrives (hDlg);
+ SetDlgItemText (hDlg, IDD_PATH, (LPSTR) lParam);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case IDOK:
+ {
+ WORD cch = 128;
+ char szMessage[128];
+ char szDrive[3];
+ LPSTR lpNetName;
+
+ GetDlgItemText(hDlg, IDD_DRIVE, szDrive, sizeof(szDrive));
+ GetDlgItemText(hDlg, IDD_PASSWORD, szPassword,
+ sizeof(szPassword));
+ lpNetName = (LPSTR) MAKELONG(((WORD) GetProp (hDlg, szOffset)), ((WORD) GetProp (hDlg, szSS)));
+ wParam = WNetAddConnection (lpNetName,
+ (LPSTR) szPassword, szDrive);
+
+ if (wParam == WN_SUCCESS) {
+ RemoveProp (hDlg, szSS);
+ RemoveProp (hDlg, szOffset);
+ EndDialog (hDlg, szDrive[0]);
+ return TRUE;
+ }
+
+ LoadString (hInstDLL, IDS_NETERR, szTitle,
+ sizeof(szTitle));
+ if (WNetGetErrorText (wParam, szMessage, &cch)
+ != WN_SUCCESS)
+ LoadString (hInstDLL, IDS_NETCONERRMSG,
+ szMessage, sizeof(szMessage));
+
+ if (MessageBox (hDlg, szMessage, szTitle,
+ MB_RETRYCANCEL | MB_SYSTEMMODAL) == IDCANCEL)
+ goto error;
+
+ if (wParam == WN_ALREADY_CONNECTED)
+ FillDrives (hDlg);
+ SetDlgItemText (hDlg, IDD_PASSWORD, szNULL);
+ break;
+ }
+
+ case IDCANCEL:
+error:
+ RemoveProp (hDlg, szSS);
+ RemoveProp (hDlg, szOffset);
+ EndDialog(hDlg, NULL);
+ return TRUE;
+
+ case IDD_DRIVE:
+ break;
+
+ case IDD_PATH:
+ if (HIWORD(lParam) == EN_KILLFOCUS) {
+ LPSTR lpNetName;
+
+ lpNetName = (LPSTR) MAKELONG(((WORD)GetProp (hDlg, szOffset)), ((WORD) GetProp (hDlg, szSS)));
+
+ SendDlgItemMessage (hDlg, IDD_PATH, WM_SETTEXT, 0,
+ (DWORD) lpNetName);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+VOID INTERNAL FillDrives (hDlg)
+HWND hDlg;
+{
+ HWND hwndCB;
+ int nDrive = 3;
+ char szDrive[3];
+
+ hwndCB = GetDlgItem(hDlg, IDD_DRIVE);
+ SendMessage(hwndCB, CB_RESETCONTENT, 0, 0L);
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ while (nDrive < MAX_DRIVE) {
+ szDrive[0] = (char) ('A' + nDrive);
+ if (!GetDriveType (nDrive))
+ SendMessage(hwndCB, CB_ADDSTRING, 0, (DWORD)(LPSTR)szDrive);
+ nDrive++;
+ }
+ SendMessage(hwndCB, CB_SETCURSEL, 0, 0L);
+}
+
+
+BOOL FAR PASCAL GetTaskVisibleWindow (hWnd, lpTaskVisWnd)
+HWND hWnd;
+DWORD lpTaskVisWnd;
+{
+ if (IsWindowVisible (hWnd)) {
+ *(WORD FAR *) lpTaskVisWnd = hWnd;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void INTERNAL RemoveNetName (LPOBJECT_LE lpobj)
+{
+ if (lpobj->aNetName) {
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = NULL;
+ }
+
+ lpobj->cDrive = NULL;
+}
diff --git a/private/mvdm/wow16/ole/client/net.c b/private/mvdm/wow16/ole/client/net.c
new file mode 100644
index 000000000..6b4c0c4d4
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/net.c
@@ -0,0 +1,371 @@
+/****************************** Module Header ******************************\
+* Module Name: net.c
+*
+* PURPOSE: Contains routines network support
+*
+* Created: Feb 1991
+*
+* Copyright (c) 1991 Microsoft Corporation
+*
+* History:
+* Srinik 02\12\1190 Orginal
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include <winnet.h>
+
+#include "dll.h"
+
+#define MAX_DRIVE 26
+
+char szNULL[] = "";
+char szSS[] = "SS";
+char szOffset[] = "OFFSET";
+
+
+BOOL FAR PASCAL GetTaskVisibleWindow (HWND, DWORD);
+void INTERNAL RemoveNetName (LPOBJECT_LE);
+
+// Gets the drive letter from topic (if one exists) and then gets the remote
+// name for that drive and then saves it in the object.
+
+OLESTATUS FARINTERNAL SetNetName (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR];
+ WORD cbBuf = sizeof(buf);
+ WORD driveType;
+ char szDrive[3];
+
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return OLE_OK;
+
+ if (!GlobalGetAtomName (lpobj->topic, buf, cbBuf))
+ return OLE_ERROR_BLANK;
+
+ if (buf[1] != ':') {
+ RemoveNetName (lpobj);
+ return OLE_OK;
+ }
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ szDrive[0] = buf[0];
+ AnsiUpperBuff ((LPSTR) szDrive, 1);
+
+ if (!(driveType = GetDriveType (szDrive[0] - 'A'))) {
+ // drive is non existent
+ return OLE_ERROR_DRIVE;
+ }
+
+ if (driveType == DRIVE_REMOTE) {
+ if (WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ != WN_SUCCESS)
+ return OLE_ERROR_DRIVE;
+
+ lpobj->cDrive = szDrive[0];
+ if (lpobj->aNetName)
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = GlobalAddAtom(buf);
+ lpobj->dwNetInfo = MAKELONG((WNetGetCaps (WNNC_NET_TYPE)),
+ (WNetGetCaps (WNNC_DRIVER_VERSION)));
+ }
+ else {
+ RemoveNetName (lpobj);
+ }
+
+ return OLE_OK;
+}
+
+
+// If netname exists for the given object, then it makes sure that drive
+// in topic corresponds to the netname. If it's not the drive letter will
+// be fixed by calling FixNet()
+
+OLESTATUS FARINTERNAL CheckNetDrive (lpobj, fNetDlg)
+LPOBJECT_LE lpobj;
+BOOL fNetDlg;
+{
+ char buf[MAX_NET_NAME];
+ char netName[MAX_NET_NAME];
+ WORD cbBuf = sizeof(buf);
+ char szDrive[3];
+
+ if (lpobj->head.ctype == CT_EMBEDDED)
+ return OLE_OK;
+
+ if (!lpobj->aNetName)
+ return OLE_OK;
+
+ if (!GlobalGetAtomName (lpobj->aNetName, netName, sizeof(netName)))
+ return OLE_ERROR_MEMORY;
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ if (!(szDrive[0] = lpobj->cDrive)) {
+ if (GlobalGetAtomName (lpobj->topic, buf, sizeof(buf)))
+ szDrive[0] = lpobj->cDrive = buf[0];
+ }
+
+ if ((WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ == WN_SUCCESS) && (!lstrcmp(netName, buf)))
+ return OLE_OK;
+
+ return FixNet (lpobj, netName, fNetDlg);
+}
+
+
+// Find if there is a drive connected to the given server. If so, get the
+// drive letter and set it in topic. If not try to make connection, and if
+// that attempt is successful the set the drive letter in topic.
+
+OLESTATUS INTERNAL FixNet (lpobj, lpNetName, fNetDlg)
+LPOBJECT_LE lpobj;
+LPSTR lpNetName;
+BOOL fNetDlg;
+{
+ int nDrive = 2; // drive 'C'
+ OLESTATUS retVal;
+
+ if (SetNextNetDrive(lpobj, &nDrive, lpNetName))
+ return OLE_OK;
+
+ if (fNetDlg != POPUP_NETDLG)
+ return OLE_ERROR_NETWORK;
+
+ if ((retVal = ConnectNet (lpobj, lpNetName)) == OLE_OK) {
+ if (!ChangeTopic (lpobj))
+ return OLE_ERROR_BLANK;
+ }
+
+ return retVal;
+}
+
+
+
+BOOL FARINTERNAL SetNextNetDrive (lpobj, lpnDrive, lpNetName)
+LPOBJECT_LE lpobj;
+int FAR * lpnDrive;
+LPSTR lpNetName;
+{
+ char buf[MAX_STR];
+ WORD cbBuf = sizeof(buf);
+ char szDrive[3];
+
+ if (!lpNetName[0]) {
+ if (!GlobalGetAtomName(lpobj->aNetName, lpNetName, MAX_STR))
+ return FALSE;
+ }
+
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ while (*lpnDrive < MAX_DRIVE) {
+ if (GetDriveType (++*lpnDrive) == DRIVE_REMOTE) {
+ szDrive[0] = (char) ('A' + *lpnDrive);
+ cbBuf = sizeof(buf);
+ if ((WNetGetConnection (szDrive, buf, (WORD FAR *) &cbBuf)
+ == WN_SUCCESS) && (!lstrcmp(lpNetName, buf))) {
+ lpobj->cDrive = szDrive[0];
+ return ChangeTopic (lpobj);
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+BOOL FARINTERNAL ChangeTopic (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char buf[MAX_STR];
+
+ if (!GlobalGetAtomName(lpobj->topic, buf, sizeof(buf)))
+ return FALSE;
+ if (lpobj->topic)
+ GlobalDeleteAtom(lpobj->topic);
+ buf[0] = lpobj->cDrive;
+ lpobj->topic = GlobalAddAtom (buf);
+ if (lpobj->hLink) {
+ GlobalFree (lpobj->hLink);
+ lpobj->hLink = NULL;
+ }
+
+ return TRUE;
+}
+
+
+
+OLESTATUS INTERNAL ConnectNet (lpobj, lpNetName)
+LPOBJECT_LE lpobj;
+LPSTR lpNetName;
+{
+ FARPROC lpConnectDlg;
+ FARPROC lpGetTaskVisWnd;
+ OLESTATUS retVal = OLE_ERROR_MEMORY;
+ HWND hCurTask;
+ HWND hwndParent = NULL;
+
+ if (!(lpConnectDlg = MakeProcInstance ((FARPROC) ConnectDlgProc,
+ hInstDLL)))
+ return OLE_ERROR_MEMORY;
+
+
+ hCurTask = GetCurrentTask();
+ ASSERT (hCurTask, "Current task handle in NULL");
+
+ if (!(lpGetTaskVisWnd = MakeProcInstance (GetTaskVisibleWindow,hInstDLL)))
+ goto errRtn;
+
+ // Get the container task's main window, and use that as parent for
+ // the dlg box.
+ EnumTaskWindows (hCurTask, lpGetTaskVisWnd,
+ (DWORD) ((WORD FAR *) &hwndParent));
+
+ if (lpobj->cDrive = (char) DialogBoxParam (hInstDLL, "CONNECTDLG",
+ hwndParent, lpConnectDlg,
+ (DWORD) lpNetName))
+ retVal = OLE_OK;
+ else
+ retVal = OLE_ERROR_NETWORK;
+
+ FreeProcInstance (lpGetTaskVisWnd);
+
+errRtn:
+ FreeProcInstance (lpConnectDlg);
+ return retVal;
+}
+
+
+
+int FAR PASCAL ConnectDlgProc(HWND hDlg, WORD wMsg, WORD wParam, DWORD lParam)
+{
+ char szPassword[32];
+ char szTitle[64];
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+ SetProp (hDlg, szSS, HIWORD (lParam));
+ SetProp (hDlg, szOffset, LOWORD (lParam));
+ FillDrives (hDlg);
+ SetDlgItemText (hDlg, IDD_PATH, (LPSTR) lParam);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case IDOK:
+ {
+ WORD cch = 128;
+ char szMessage[128];
+ char szDrive[3];
+ LPSTR lpNetName;
+
+ GetDlgItemText(hDlg, IDD_DRIVE, szDrive, sizeof(szDrive));
+ GetDlgItemText(hDlg, IDD_PASSWORD, szPassword,
+ sizeof(szPassword));
+ lpNetName = (LPSTR) MAKELONG(((WORD) GetProp (hDlg, szOffset)), ((WORD) GetProp (hDlg, szSS)));
+ wParam = WNetAddConnection (lpNetName,
+ (LPSTR) szPassword, szDrive);
+
+ if (wParam == WN_SUCCESS) {
+ RemoveProp (hDlg, szSS);
+ RemoveProp (hDlg, szOffset);
+ EndDialog (hDlg, szDrive[0]);
+ return TRUE;
+ }
+
+ LoadString (hInstDLL, IDS_NETERR, szTitle,
+ sizeof(szTitle));
+ if (WNetGetErrorText (wParam, szMessage, &cch)
+ != WN_SUCCESS)
+ LoadString (hInstDLL, IDS_NETCONERRMSG,
+ szMessage, sizeof(szMessage));
+
+ if (MessageBox (hDlg, szMessage, szTitle,
+ MB_RETRYCANCEL | MB_SYSTEMMODAL) == IDCANCEL)
+ goto error;
+
+ if (wParam == WN_ALREADY_CONNECTED)
+ FillDrives (hDlg);
+ SetDlgItemText (hDlg, IDD_PASSWORD, szNULL);
+ break;
+ }
+
+ case IDCANCEL:
+error:
+ RemoveProp (hDlg, szSS);
+ RemoveProp (hDlg, szOffset);
+ EndDialog(hDlg, NULL);
+ return TRUE;
+
+ case IDD_DRIVE:
+ break;
+
+ case IDD_PATH:
+ if (HIWORD(lParam) == EN_KILLFOCUS) {
+ LPSTR lpNetName;
+
+ lpNetName = (LPSTR) MAKELONG(((WORD)GetProp (hDlg, szOffset)), ((WORD) GetProp (hDlg, szSS)));
+
+ SendDlgItemMessage (hDlg, IDD_PATH, WM_SETTEXT, 0,
+ (DWORD) lpNetName);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+VOID INTERNAL FillDrives (hDlg)
+HWND hDlg;
+{
+ HWND hwndCB;
+ int nDrive = 3;
+ char szDrive[3];
+
+ hwndCB = GetDlgItem(hDlg, IDD_DRIVE);
+ SendMessage(hwndCB, CB_RESETCONTENT, 0, 0L);
+ szDrive[2] = NULL;
+ szDrive[1] = ':';
+ while (nDrive < MAX_DRIVE) {
+ szDrive[0] = (char) ('A' + nDrive);
+ if (!GetDriveType (nDrive))
+ SendMessage(hwndCB, CB_ADDSTRING, 0, (DWORD)(LPSTR)szDrive);
+ nDrive++;
+ }
+ SendMessage(hwndCB, CB_SETCURSEL, 0, 0L);
+}
+
+
+BOOL FAR PASCAL GetTaskVisibleWindow (hWnd, lpTaskVisWnd)
+HWND hWnd;
+DWORD lpTaskVisWnd;
+{
+ if (IsWindowVisible (hWnd)) {
+ *(WORD FAR *) lpTaskVisWnd = hWnd;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void INTERNAL RemoveNetName (LPOBJECT_LE lpobj)
+{
+ if (lpobj->aNetName) {
+ GlobalDeleteAtom (lpobj->aNetName);
+ lpobj->aNetName = NULL;
+ }
+
+ lpobj->cDrive = NULL;
+}
diff --git a/private/mvdm/wow16/ole/client/ole.asm b/private/mvdm/wow16/ole/client/ole.asm
new file mode 100644
index 000000000..f90aed7f5
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/ole.asm
@@ -0,0 +1,139 @@
+ ;\
+ ; ole.asm
+ ;
+ ; Copyright (C) 1991, MicroSoft Corporation
+ ;
+ ; Contains pointer vaildation routine
+ ;
+ ; History: sriniK 02/01/1991 original
+ ; srinik 02/21/1991 added GetGDIds, IsMetaDC
+ ;/
+
+.286p
+.MODEL SMALL
+.CODE
+
+;**************************** _CheckPointer ****************************
+;
+; WORD CheckPointer (lp, access)
+;
+; Args:
+; lp pointer to be verified
+; access 0 test the pointer for read access
+; 1 test the pointer for write access
+; returns:
+; FALSE invalid pointer
+; TRUE valid pointer
+;
+;
+;
+ public _CheckPointer
+
+_CheckPointer proc
+
+ push bp
+ mov bp, sp
+
+ xor ax, ax
+ and word ptr [bp+8], -1
+ jnz check_write_access
+
+ verr word ptr [bp+6] ; check selector for read access
+ jnz error
+ jmp short check_offset
+
+check_write_access:
+ verw word ptr [bp+6] ; check selector for write access
+ jnz error
+
+check_offset:
+ lsl bx, word ptr [bp+6] ; segment limit gets copied into BX
+ jnz error
+ cmp [bp+4], bx
+ ja error
+ or ax, -1
+error:
+ pop bp
+ ret
+
+_CheckPointer endp
+
+
+
+;**************************** _GetGdiDS ****************************
+;
+; WORD GetGDIds (lpGdiFunc)
+;
+; Args:
+; lpGdiFunc long pointer to one of the GDI functions, with selector
+; part being aliased to a data selector
+; returns:
+; GDI DS value
+;
+ public _GetGDIds
+
+_GetGDIds proc
+
+ push bp
+ mov bp, sp
+
+ mov ax, word ptr [bp+6] ; data selector
+ push ds
+ mov ds, ax
+ mov bx, word ptr [bp+4]
+ mov ax, word ptr ds:[bx+1]
+ pop ds
+
+ pop bp
+ ret
+
+_GetGDIds endp
+
+
+
+
+;**************************** _IsMetaDC ****************************
+;
+; WORD IsMetaDC (hdc, wGDIds)
+;
+; Args:
+; hdc handle device context
+; wGDIds GDI's data segment selector
+;
+; returns:
+; TRUE if hdc is metafile dc
+; FALSE otherwise
+;
+; ilObjHead struc
+; dw ? ; pointer to next obj in chain
+; ilObjType dw ? ; defines type of object
+; ilObjCount dd ? ; the count of the object
+; ilObjMetaList dw ? ; handle to the list of metafile
+; ilObjHead ends
+;
+
+ public _IsMetaDC
+
+OBJ_METAFILE equ 10
+
+_IsMetaDC proc
+
+ push bp
+ mov bp, sp
+
+ mov ax, [bp+6] ; data selector
+ push ds
+ mov ds, ax
+ mov di, [bp+4] ; hdc
+ mov di, [di]
+ cmp word ptr [di+2], OBJ_METAFILE
+ jz metafile
+ xor ax, ax
+metafile:
+ pop ds
+ pop bp
+ ret
+
+_IsMetaDC endp
+
+ end
diff --git a/private/mvdm/wow16/ole/client/ole.c b/private/mvdm/wow16/ole/client/ole.c
new file mode 100644
index 000000000..06564fcb8
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/ole.c
@@ -0,0 +1,1812 @@
+/******************************* Module Header *******************************
+* Module Name: OLE.C
+*
+* Purpose: Handles all API routines for the dde L&E sub-dll of the ole dll.
+*
+* PURPOSE: API routines for handling generic objects (which may be static,
+* linked, or embedded). These routines will be made into a DLL.
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../90, 91) Designed/coded.
+*
+*****************************************************************************/
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "dll.h"
+
+extern DLL_ENTRY lpDllTable[];
+extern char packageClass[];
+extern OLECLIPFORMAT cfFileName;
+extern DWORD dwOleVer;
+
+DWORD dwVerFromFile;
+HANDLE hInfo = NULL;
+CLIENTDOC lockDoc = {{'C', 'D'}, 0L, 0L, 0, 0, 0, 0L, 0L};
+LHCLIENTDOC lhLockDoc = (LHCLIENTDOC) ((LPCLIENTDOC) &lockDoc);
+BOOL gbCreateInvisible = FALSE;
+BOOL gbLaunchServer;
+
+
+OLESTATUS INTERNAL LockServer (LPOBJECT_LE);
+
+#pragma alloc_text(_DDETEXT, OleLockServer, OleUnlockServer, LockServer, IsServerValid, DeleteSrvrEdit, InitSrvrConv, LeLaunchApp)
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// LPVOID FAR PASCAL OleQueryProtocol (lpobj, lpprotocol)
+//
+// Tells whether the object supports the specified protocol.
+//
+// Arguments:
+//
+// lpobj - object pointer
+// lpprotocol - protocol string
+//
+// Returns:
+//
+// long ptr to object if the protocol is supported
+// NULL if not.
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+LPVOID FAR PASCAL OleQueryProtocol (lpobj, lpprotocol)
+LPOLEOBJECT lpobj;
+LPSTR lpprotocol;
+{
+ if (!CheckObject(lpobj))
+ return NULL;
+
+ return (*lpobj->lpvtbl->QueryProtocol) (lpobj, lpprotocol);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FAR PASCAL OleDelete (lpobj)
+//
+// Deletes the given object and all memory associated with its sub-parts.
+// The calling function should cease to use 'lpobj', as it is now invalid.
+// If handler dll is used reference count is reduced by one, and if it
+// reaches zero the hanlder dll will be freed up.
+//
+// Arguments:
+//
+// lpobj - object pointer
+//
+// Returns:
+//
+// OLE_OK
+// OLE_ERROR_OBJECT
+// OLE_WAIT_FOR_RELEASE
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FAR PASCAL OleDelete (lpobj)
+LPOLEOBJECT lpobj;
+{
+ Puts("OleDelete");
+
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->Delete) (lpobj);
+}
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRelease (lpobj)
+*
+* OleRelease:
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRelease (lpobj)
+LPOLEOBJECT lpobj;
+{
+ Puts("OleRelease");
+
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->Release) (lpobj);
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleSaveToStream (lpobj, lpstream)
+*
+* oleSaveToStream: This will read <hobj> to the stream based on the <hfile>
+* structure. It will return TRUE on success. This is the only object
+* function for which it is not an error to pass a NULL <hobj>. In the case
+* of NULL, this function will simply put a placemarker for an object.
+* See oleLoadFromStream.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleSaveToStream (lpobj, lpstream)
+LPOLEOBJECT lpobj;
+LPOLESTREAM lpstream;
+{
+ Puts("OleSaveToStream");
+
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ PROBE_READ(lpstream);
+
+ return ((*lpobj->lpvtbl->SaveToStream) (lpobj, lpstream));
+}
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleLoadFromStream (lpstream, lpprotcol, lpclient, lhclientdoc, lpobjname, lplpobj)
+*
+* oleLoadFromStream: This will read an object out of the stream based on the
+* <hfile> structure. It will return a HANDLE to the object it creates.
+* On error, the return value is NULL, but since NULL is also a valid object
+* in the file, the <error> parameter should be checked as well.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleLoadFromStream (lpstream, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLESTREAM lpstream;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ LONG len;
+ OLESTATUS retVal = OLE_ERROR_STREAM;
+ char class[100];
+ ATOM aClass;
+ BOOL bEdit = FALSE, bStatic = FALSE;
+ LONG ctype;
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+ Puts("OleLoadFromStream");
+
+ *lplpobj = NULL;
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpstream);
+ PROBE_WRITE(lplpobj);
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleLoadFromStream\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ if (!(bEdit = !lstrcmpi (lpprotocol, PROTOCOL_EDIT)))
+ if (!(bStatic = !lstrcmpi (lpprotocol, PROTOCOL_STATIC)))
+ return OLE_ERROR_PROTOCOL;
+
+ if (GetBytes (lpstream, (LPSTR) &dwVerFromFile, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (GetBytes (lpstream, (LPSTR)&ctype, sizeof(LONG)))
+ return OLE_ERROR_STREAM;
+
+ if (ctype == CT_NULL)
+ return (bStatic ? OLE_OK: OLE_ERROR_PROTOCOL);
+
+ if (((ctype != CT_PICTURE) && (ctype != CT_STATIC) && bStatic) ||
+ ((ctype != CT_LINK) && (ctype != CT_OLDLINK)
+ && (ctype != CT_EMBEDDED) && bEdit))
+ return OLE_ERROR_PROTOCOL;
+
+ if ((ctype == CT_STATIC) && ((HIWORD(dwVerFromFile)) != OS_WIN16))
+ return OLE_ERROR_STATIC_FROM_OTHER_OS;
+
+ //** Get Class
+ if (GetBytes(lpstream, (LPSTR)&len, sizeof(len)))
+ return OLE_ERROR_STREAM;
+
+ if (len == 0)
+ return OLE_ERROR_STREAM;
+
+ if (GetBytes(lpstream, (LPSTR)&class, len))
+ return OLE_ERROR_STREAM;
+
+ aClass = GlobalAddAtom (class);
+
+ if ((ctype == CT_PICTURE) || (ctype == CT_STATIC))
+ retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj, ctype, aClass, NULL);
+
+ //!!! It's the DLL's responsibility to delete the atom. But in case of
+ // failure we delete the atom if our DefLoadFromStream().
+
+ else if ((iTable = LoadDll (class)) == INVALID_INDEX) {
+ retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj, ctype, aClass, NULL);
+ }
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retVal = (*lpDllTable[iTable].Load) (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj, ctype, aClass, NULL);
+ if (retVal > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpobj)->iTable = iTable;
+ }
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL OleClone (lpobjsrc, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLEOBJECT lpobjsrc;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ OLESTATUS retVal;
+
+ Puts("OleClone");
+
+ if (!CheckObject(lpobjsrc))
+ return OLE_ERROR_OBJECT;
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpclient);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleClone\n");
+#endif
+
+ PROBE_READ(lpobjname);
+
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ PROBE_WRITE(lplpobj);
+
+ *lplpobj = NULL;
+
+ retVal = (*lpobjsrc->lpvtbl->Clone) (lpobjsrc, lpclient,
+ lhclientdoc, lpobjname, lplpobj);
+
+ if ((lpobjsrc->iTable != INVALID_INDEX) && (retVal <= OLE_WAIT_FOR_RELEASE))
+ lpDllTable[lpobjsrc->iTable].cObj++;
+
+ return retVal;
+}
+
+
+OLESTATUS FAR PASCAL OleCopyFromLink (lpobjsrc, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLEOBJECT lpobjsrc;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ OLESTATUS retVal;
+
+ Puts("OleCopyFromLnk");
+
+ if (!CheckObject(lpobjsrc))
+ return(OLE_ERROR_OBJECT);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_WRITE(lplpobj);
+ PROBE_READ(lpclient);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCopyFromLink\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ *lplpobj = NULL;
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ retVal = (*lpobjsrc->lpvtbl->CopyFromLink) (lpobjsrc, lpclient,
+ lhclientdoc, lpobjname, lplpobj);
+
+ if ((lpobjsrc->iTable != INVALID_INDEX) && (retVal <= OLE_WAIT_FOR_RELEASE))
+ lpDllTable[lpobjsrc->iTable].cObj++;
+
+
+ return retVal;
+
+}
+
+
+
+OLESTATUS FAR PASCAL OleEqual (lpobj1, lpobj2)
+LPOLEOBJECT lpobj1;
+LPOLEOBJECT lpobj2;
+{
+ if (!CheckObject(lpobj1))
+ return OLE_ERROR_OBJECT;
+
+ if (!CheckObject(lpobj2))
+ return OLE_ERROR_OBJECT;
+
+ if (lpobj1->ctype != lpobj2->ctype)
+ return OLE_ERROR_NOT_EQUAL;
+
+ return ((*lpobj1->lpvtbl->Equal) (lpobj1, lpobj2));
+}
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleQueryLinkFromClip (lpprotcol, optRender, cfFormat)
+*
+* oleQueryFromClip: Returns OLE_OK if a linked object can be created.
+*
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+
+OLESTATUS FAR PASCAL OleQueryLinkFromClip (lpprotocol, optRender, cfFormat)
+LPSTR lpprotocol;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ Puts("OleQueryLinkFromClip");
+ return LeQueryCreateFromClip (lpprotocol, optRender, cfFormat, CT_LINK);
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleQueryCreateFromClip (lpprotcol, optRender, cfFormat)
+*
+* oleQueryCreateFromClip: Returns true if a non-linked object can be
+* created.
+*
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+
+OLESTATUS FAR PASCAL OleQueryCreateFromClip (lpprotocol, optRender, cfFormat)
+LPSTR lpprotocol;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ Puts("OleQueryCreateFromClip");
+ return (LeQueryCreateFromClip (lpprotocol, optRender,
+ cfFormat, CT_EMBEDDED));
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleCreateLinkFromClip (lpprotcol, lpclient, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+*
+*
+* oleCreateLinkFromClip: This function creates the LP to an object from the
+* clipboard. It will try to create a linked object. Return value is OLE_OK
+* is the object is successfully created it
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ int objCount;
+ int iTable = INVALID_INDEX;
+ OLESTATUS retVal;
+ LPSTR lpInfo;
+
+ Puts("OleCreateLinkFromClip");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_WRITE(lplpobj);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreateLinkFromClip\n");
+#endif
+
+ PROBE_READ(lpobjname);
+
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ *lplpobj = NULL;
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ if (IsClipboardFormatAvailable (cfFileName))
+ return CreatePackageFromClip (lpclient, lhclientdoc, lpobjname,
+ lplpobj, optRender, cfFormat, CT_LINK);
+
+ if (!(hInfo = GetClipboardData (cfObjectLink)))
+ return OLE_ERROR_CLIPBOARD;
+
+ if (!(lpInfo = GlobalLock(hInfo)))
+ return OLE_ERROR_CLIPBOARD;
+
+ iTable = LoadDll (lpInfo);
+ GlobalUnlock (hInfo);
+
+
+ if (iTable == INVALID_INDEX)
+ retVal = DefCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc,
+ lpobjname, lplpobj, optRender, cfFormat);
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retVal = (*lpDllTable[iTable].Link) (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj, optRender, cfFormat);
+ if (retVal > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpobj)->iTable = iTable;
+ }
+
+ hInfo = NULL;
+ return retVal;
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleCreateFromClip (lpprotcol, lpclient, lplpoleobject, optRender, cfFormat)
+*
+*
+* oleCreateFromClip: This function creates the LP to an object
+* from the clipboard. It will try to create an embedded object if
+* OwnerLink and Native are available, otherwise it will create a static
+* picture. Return value is OLE_OK if the object is successfully
+* created it.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleCreateFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+ LONG ctype;
+ int iTable = INVALID_INDEX;
+ LPSTR lpInfo;
+ LPSTR lpClass = NULL;
+ int objCount;
+ OLECLIPFORMAT cfEnum = NULL;
+
+ Puts("OleCreateFromClip");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_WRITE(lplpobj);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreateFromClip\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ *lplpobj = NULL;
+
+ if (!lstrcmpi (lpprotocol, PROTOCOL_STATIC)) {
+ if (optRender == olerender_none)
+ return OLE_ERROR_OPTION;
+
+ if ((optRender == olerender_format) && (cfFormat != CF_METAFILEPICT)
+ && (cfFormat != CF_DIB) && (cfFormat != CF_BITMAP))
+ return OLE_ERROR_FORMAT;
+
+ if (!IsClipboardFormatAvailable (CF_METAFILEPICT)
+ && !IsClipboardFormatAvailable (CF_DIB)
+ && !IsClipboardFormatAvailable (CF_BITMAP))
+ return OLE_ERROR_FORMAT;
+
+ return CreatePictFromClip (lpclient, lhclientdoc,
+ lpobjname, lplpobj, optRender,
+ cfFormat, NULL, CT_STATIC);
+ }
+ else if (!lstrcmpi (lpprotocol, PROTOCOL_EDIT)) {
+ if (IsClipboardFormatAvailable (cfFileName))
+ return CreatePackageFromClip (lpclient, lhclientdoc, lpobjname,
+ lplpobj, optRender, cfFormat, CT_EMBEDDED);
+
+ if (!(hInfo = GetClipboardData (cfOwnerLink)))
+ return OLE_ERROR_CLIPBOARD;
+
+ while (TRUE) {
+ cfEnum = EnumClipboardFormats (cfEnum);
+ if (cfEnum == cfNative) {
+ ctype = CT_EMBEDDED;
+ break;
+ }
+ else if (cfEnum == cfOwnerLink) {
+ ctype = CT_LINK;
+ break;
+ }
+ }
+
+ if (!(lpInfo = GlobalLock(hInfo)))
+ return OLE_ERROR_CLIPBOARD;
+
+ iTable = LoadDll (lpInfo);
+ GlobalUnlock (hInfo);
+ }
+ else {
+ return OLE_ERROR_PROTOCOL;
+ }
+
+ if (iTable == INVALID_INDEX)
+ retVal = DefCreateFromClip (lpprotocol, lpclient, lhclientdoc,
+ lpobjname, lplpobj, optRender, cfFormat, ctype);
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retVal = (*lpDllTable[iTable].Clip) (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, ctype);
+
+ if (retVal > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpobj)->iTable = iTable;
+ }
+
+ hInfo = NULL;
+ return retVal;
+}
+
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleCopyToClipboard (lpobj)
+*
+*
+* oleCopyToClipboard: This routine executes the standard "Copy" menu item
+* on the typical "Edit" menu. Returns TRUE if successful.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleCopyToClipboard (lpobj)
+LPOLEOBJECT lpobj;
+{
+ Puts("OleCopyToClipboard");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return ((*lpobj->lpvtbl->CopyToClipboard) (lpobj));
+}
+
+
+OLESTATUS FAR PASCAL OleSetHostNames (lpobj, lpclientName, lpdocName)
+LPOLEOBJECT lpobj;
+LPSTR lpclientName;
+LPSTR lpdocName;
+{
+ Puts ("OleSetHostNames");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_READ(lpclientName);
+ PROBE_READ(lpdocName);
+
+ return ((*lpobj->lpvtbl->SetHostNames) (lpobj, lpclientName, lpdocName));
+}
+
+
+
+OLESTATUS FAR PASCAL OleSetTargetDevice (lpobj, hDevInfo)
+LPOLEOBJECT lpobj;
+HANDLE hDevInfo;
+{
+ Puts("OleSetTargetDevice");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return ((*lpobj->lpvtbl->SetTargetDevice) (lpobj, hDevInfo));
+}
+
+
+
+OLESTATUS FAR PASCAL OleSetColorScheme (lpobj, lplogpal)
+LPOLEOBJECT lpobj;
+LPLOGPALETTE lplogpal;
+{
+ Puts("OleSetColorScheme");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return ((*lpobj->lpvtbl->SetColorScheme) (lpobj, lplogpal));
+}
+
+
+
+OLESTATUS FAR PASCAL OleSetBounds(lpobj, lprc)
+LPOLEOBJECT lpobj;
+LPRECT lprc;
+{
+ Puts("OleSetBounds");
+
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ PROBE_READ(lprc);
+
+ return ((*lpobj->lpvtbl->SetBounds) (lpobj, lprc));
+
+}
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleQueryBounds (lpobj, lpRc)
+*
+* Returns the bounds of the object in question in MM_HIMETRIC mode.
+* width = lprc->right - lprc->left; in HIMETRIC units
+* height = lprc->top - lprc->bottom; in HIMETRIC units
+*
+* Returns OLE_OK or OLE_ERROR_MEMORY.
+*
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleQueryBounds (lpobj, lprc)
+LPOLEOBJECT lpobj;
+LPRECT lprc;
+{
+
+ Puts("OleQueryBounds");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_WRITE(lprc);
+
+ return (*lpobj->lpvtbl->QueryBounds) (lpobj, lprc);
+}
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleQuerySize (lpobj, lpsize)
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleQuerySize (lpobj, lpdwSize)
+LPOLEOBJECT lpobj;
+DWORD FAR * lpdwSize;
+{
+ Puts("OleQuerySize");
+
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ PROBE_WRITE(lpdwSize);
+
+ *lpdwSize = NULL;
+ return (*lpobj->lpvtbl->QuerySize) (lpobj, lpdwSize);
+}
+
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleDraw (lpobj, hdc, lprc, lpWrc, lphdcTarget)
+*
+* oleObjectDraw: This displays the given object on the device context <hcd>.
+* The <htargetdc> parameter is not currently used. Returns same as Draw().
+*
+* Expects rectangle coordinates in MM_HIMETRIC units.
+*
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOLEOBJECT lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+
+ Puts("OleObjectDraw");
+
+ if (!FarCheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_READ(lprc);
+ if (lpWrc)
+ PROBE_READ(lpWrc);
+
+ return ((*lpobj->lpvtbl->Draw) (lpobj, hdc, lprc, lpWrc, hdcTarget));
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleQueryOpen (lpobj)
+*
+* returns TRUE is an object has been activated.
+*
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleQueryOpen (lpobj)
+LPOLEOBJECT lpobj;
+{
+ Puts("OleQueryOpen");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->QueryOpen) (lpobj);
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleActivate (lpobj)
+*
+* Activates an object. For embeded objects always a new instance is
+* loaded and the instance is destroyed once the data is transferred
+* at close time. For linked objects, an instance of the render is created
+* only if one does not exist.
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleActivate (lpobj, verb, fShow, fActivate, hWnd, lprc)
+LPOLEOBJECT lpobj;
+WORD verb;
+BOOL fShow;
+BOOL fActivate;
+HWND hWnd;
+LPRECT lprc;
+{
+
+ Puts("OleActivate");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ /* PROBE_READ(lprc); */
+
+ return (*lpobj->lpvtbl->Activate) (lpobj, verb, fShow, fActivate, hWnd, lprc);
+}
+
+
+
+
+OLESTATUS FAR PASCAL OleClose (lpobj)
+LPOLEOBJECT lpobj;
+{
+
+ Puts("OleClose");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->Close) (lpobj);
+}
+
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleUpdate (lpobj)
+*
+* If there exists a link, sends advise for getting the latest rendering
+* infromation. If there is no link, loads an instance, advises for the
+* render information and closes the instance once the data is available.
+* (If possible should not show the window).
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleUpdate (lpobj)
+LPOLEOBJECT lpobj;
+{
+
+ Puts("OleUpdate");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->Update) (lpobj);
+
+}
+
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleReconnect (lpobj)
+*
+* Reconnects to the renderer if one does not exist already.
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleReconnect (lpobj)
+LPOLEOBJECT lpobj;
+{
+ Puts("OleReconnect");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->Reconnect) (lpobj);
+}
+
+
+OLESTATUS FAR PASCAL OleGetLinkUpdateOptions (lpobj, lpOptions)
+LPOLEOBJECT lpobj;
+OLEOPT_UPDATE FAR * lpOptions;
+{
+ Puts("OleGetLinkUpdateOptions");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_WRITE(lpOptions);
+
+ return (*lpobj->lpvtbl->GetLinkUpdateOptions) (lpobj, lpOptions);
+}
+
+
+
+OLESTATUS FAR PASCAL OleSetLinkUpdateOptions (lpobj, options)
+LPOLEOBJECT lpobj;
+OLEOPT_UPDATE options;
+{
+ Puts("OleSetLinkUpdateOptions");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->SetLinkUpdateOptions) (lpobj, options);
+
+}
+
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleEnumFormats (lpobj, cfFormat)
+*
+* Returns OLE_YES if the object is of type LINK or EMBEDDED.
+*
+* Effects:
+*
+* History:
+* Wrote it.
+\***************************************************************************/
+
+OLECLIPFORMAT FAR PASCAL OleEnumFormats (lpobj, cfFormat)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ Puts("OleEnumFormats");
+
+ if (!CheckObject(lpobj))
+ return NULL;
+
+ return (*lpobj->lpvtbl->EnumFormats) (lpobj, cfFormat);
+}
+
+OLESTATUS FAR PASCAL OleRequestData (lpobj, cfFormat)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ Puts("OleGetData");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ if (!cfFormat)
+ return OLE_ERROR_FORMAT;
+
+ return (*lpobj->lpvtbl->RequestData) (lpobj, cfFormat);
+}
+
+
+OLESTATUS FAR PASCAL OleGetData (lpobj, cfFormat, lphandle)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+LPHANDLE lphandle;
+{
+ Puts("OleGetData");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_WRITE(lphandle);
+
+ return (*lpobj->lpvtbl->GetData) (lpobj, cfFormat, lphandle);
+}
+
+
+OLESTATUS FAR PASCAL OleSetData (lpobj, cfFormat, hData)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+HANDLE hData;
+{
+ Puts("OleSetData");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->SetData) (lpobj, cfFormat, hData);
+}
+
+
+
+OLESTATUS FAR PASCAL OleQueryOutOfDate (lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->QueryOutOfDate) (lpobj);
+}
+
+
+OLESTATUS FAR PASCAL OleLockServer (lpobjsrc, lplhsrvr)
+LPOLEOBJECT lpobjsrc;
+LHSERVER FAR * lplhsrvr;
+{
+ LPOBJECT_LE lpobj;
+ OLESTATUS retVal = OLE_OK;
+ ATOM aCliClass, aSvrClass;
+
+ Puts ("OleLockServer");
+
+ if (!FarCheckObject(lpobjsrc))
+ return OLE_ERROR_OBJECT;
+
+ if (lpobjsrc->ctype == CT_STATIC)
+ return OLE_ERROR_STATIC;
+
+ // Assumes all the creates are in order
+ PROBE_CREATE_ASYNC(((LPOBJECT_LE)lpobjsrc));
+ FARPROBE_WRITE(lplhsrvr);
+
+ aCliClass = ((LPCLIENTDOC)(lpobjsrc->lhclientdoc))->aClass;
+ aSvrClass = ((LPOBJECT_LE)lpobjsrc)->app;
+
+ // See whether the server is already locked
+ lpobj = (LPOBJECT_LE) (lockDoc.lpHeadObj);
+ while (lpobj) {
+ if ((lpobj->app == aSvrClass) && (lpobj->topic == aCliClass)) {
+ if (!lpobj->head.cx) {
+ // The unlocking process of server handle has started. This
+ // is an asynchronous process. We want to let it complete.
+ // Let's try the next handle
+
+ ;
+ }
+ else {
+ if (!IsServerValid (lpobj)) {
+ DeleteSrvrEdit (lpobj);
+ retVal = LockServer (lpobj);
+ }
+ else {
+ // Lock count
+ lpobj->head.cx++;
+ }
+
+ if (retVal == OLE_OK)
+ *lplhsrvr = (LHSERVER) lpobj;
+
+ return retVal;
+ }
+ }
+
+ lpobj = (LPOBJECT_LE) (lpobj->head.lpNextObj);
+ }
+
+
+ if (!(lpobj = LeCreateBlank(lhLockDoc, NULL, OT_EMBEDDED)))
+ return OLE_ERROR_MEMORY;
+
+ lpobj->head.lpclient = NULL;
+ lpobj->head.lpvtbl = lpobjsrc->lpvtbl;
+ lpobj->app = DuplicateAtom (aSvrClass);
+ lpobj->topic = DuplicateAtom (aCliClass);
+ lpobj->aServer = DuplicateAtom(((LPOBJECT_LE)lpobjsrc)->aServer);
+ lpobj->bOleServer = ((LPOBJECT_LE)lpobjsrc)->bOleServer;
+
+ if ((retVal = LockServer (lpobj)) == OLE_OK) {
+ // Change signature
+ lpobj->head.objId[0] = 'S';
+ lpobj->head.objId[1] = 'L';
+ *lplhsrvr = (LHSERVER) lpobj;
+ }
+ else {
+ LeRelease (lpobj);
+ }
+
+ return retVal;
+}
+
+
+OLESTATUS INTERNAL LockServer (lpobj)
+LPOBJECT_LE lpobj;
+{
+ HANDLE hInst;
+
+ if (!InitSrvrConv (lpobj, NULL)) {
+ if (!lpobj->bOleServer)
+ lpobj->fCmd = ACT_MINIMIZE;
+ else
+ lpobj->fCmd = NULL;
+
+ if (!(hInst = LeLaunchApp (lpobj)))
+ return OLE_ERROR_LAUNCH;
+
+ if (!InitSrvrConv (lpobj, hInst))
+ return OLE_ERROR_COMM;
+
+ }
+
+ // lock count
+ lpobj->head.cx++;
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL OleUnlockServer (lhsrvr)
+LHSERVER lhsrvr;
+{
+ LPOBJECT_LE lpobj;
+ OLESTATUS retval;
+
+ Puts ("OleUnlockServer");
+
+ if (!FarCheckPointer ((lpobj = (LPOBJECT_LE)lhsrvr), WRITE_ACCESS))
+ return OLE_ERROR_HANDLE;
+
+ if (lpobj->head.objId[0] != 'S' || lpobj->head.objId[1] != 'L')
+ return OLE_ERROR_HANDLE;
+
+ if (!lpobj->head.cx)
+ return OLE_OK;
+
+ if (--lpobj->head.cx)
+ return OLE_OK;
+
+ //change signature
+ lpobj->head.objId[0] = 'L';
+ lpobj->head.objId[1] = 'E';
+
+ if ((retval = LeRelease (lpobj)) == OLE_WAIT_FOR_RELEASE)
+ DocDeleteObject ((LPOLEOBJECT)lpobj);
+
+ return retval;
+}
+
+
+OLESTATUS FAR PASCAL OleObjectConvert (lpobj, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj)
+LPOLEOBJECT lpobj;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+{
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_WRITE(lplpobj);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleObjectConvert\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+
+ return (*lpobj->lpvtbl->ObjectConvert) (lpobj, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj);
+}
+
+
+//OleCreateFromTemplate: Creates an embedded object from Template
+
+OLESTATUS FAR PASCAL OleCreateFromTemplate (lpprotocol, lpclient, lptemplate, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat )
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ char buf[MAX_STR];
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+ Puts("OleCreateFromTemplate");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_READ(lptemplate);
+ PROBE_WRITE(lplpoleobject);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreateFromTemplate\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ if (!MapExtToClass (lptemplate, (LPSTR)buf, MAX_STR))
+ return OLE_ERROR_CLASS;
+
+
+ // !!! we found the class name. At this point, we need to load
+ // the right library and call the right entry point;
+
+ iTable = LoadDll ((LPSTR)buf);
+ if (iTable == INVALID_INDEX)
+ retval = DefCreateFromTemplate (lpprotocol, lpclient, lptemplate,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retval = (*lpDllTable[iTable].CreateFromTemplate) (lpprotocol,
+ lpclient, lptemplate,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ if (retval > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpoleobject)->iTable = iTable;
+ }
+
+ return retval;
+}
+
+
+//OleCreate: Creates an embedded object from the class.
+
+OLESTATUS FAR PASCAL OleCreate (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+
+ Puts("OleCreate");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_READ(lpclass);
+ PROBE_WRITE(lplpoleobject);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreate\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ iTable = LoadDll (lpclass);
+ if (iTable == INVALID_INDEX)
+ retval = DefCreate (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retval = (*lpDllTable[iTable].Create) (lpprotocol,
+ lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ if (retval > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpoleobject)->iTable = iTable;
+ }
+
+ return retval;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// OLESTATUS FAR PASCAL OleCreateInvisible (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, bLaunchServer)
+//
+// Creates an embedded object from the class.
+//
+// Arguments:
+//
+// lpprotocol -
+// lpclient -
+// lpclass -
+// lhclientdoc -
+// lpobjname -
+// lplpoleobject -
+// optRender -
+// cfFormat -
+// bLaunchServer -
+//
+// Returns:
+//
+// OLE_ERROR_HANDLE -
+// OLE_ERROR_NAME -
+// OLE_ERROR_PROTOCOL -
+//
+// Effects:
+//
+//////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FAR PASCAL OleCreateInvisible (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, bLaunchServer)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+BOOL bLaunchServer;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+
+ Puts("OleCreateInvisible");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_READ(lpclass);
+ PROBE_WRITE(lplpoleobject);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreate\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ iTable = LoadDll (lpclass);
+ if (iTable == INVALID_INDEX) {
+ retval = DefCreateInvisible (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat, bLaunchServer);
+ }
+ else {
+ objCount = lpDllTable[iTable].cObj;
+
+ if (!(lpDllTable[iTable].CreateInvisible)) {
+ // dll didn't export this function. Lets call DllCreate, so that
+ // handler will get a chance to replace the methods. The flag is
+ // used to tell the internal functions that this call infact wants
+ // to achieve the effect of CreateInvisble.
+ gbCreateInvisible = TRUE;
+ gbLaunchServer = bLaunchServer;
+ retval = (*lpDllTable[iTable].Create) (lpprotocol,
+ lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ gbCreateInvisible = FALSE;
+ }
+ else {
+ retval = (*lpDllTable[iTable].CreateInvisible) (lpprotocol,
+ lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat, bLaunchServer);
+ }
+
+ if (retval > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpoleobject)->iTable = iTable;
+ }
+
+ return retval;
+}
+
+
+//OleCreateFromFile: Creates an embedded object from file
+
+OLESTATUS FAR PASCAL OleCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat )
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ char buf[MAX_STR];
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+ Puts("OleCreateFromFile");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_READ(lpfile);
+ PROBE_WRITE(lplpoleobject);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreateFromFile\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+ if (lpclass)
+ PROBE_READ(lpclass);
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ if (lpclass) {
+ if (!QueryApp (lpclass, lpprotocol, buf))
+ return OLE_ERROR_CLASS;
+
+ if (!lstrcmp (lpclass, packageClass))
+ iTable = INVALID_INDEX;
+ else
+ iTable = LoadDll (lpclass);
+ }
+ else if (MapExtToClass (lpfile, (LPSTR)buf, MAX_STR))
+ iTable = LoadDll (buf);
+ else
+ return OLE_ERROR_CLASS;
+
+ if (iTable == INVALID_INDEX)
+ retval = DefCreateFromFile (lpprotocol,
+ lpclient, lpclass, lpfile,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retval = (*lpDllTable[iTable].CreateFromFile) (lpprotocol,
+ lpclient, lpclass, lpfile,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ if (retval > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpoleobject)->iTable = iTable;
+ }
+
+ return retval;
+}
+
+
+//OleCreateLinkFromFile: Creates a linked object from file
+
+OLESTATUS FAR PASCAL OleCreateLinkFromFile (lpprotocol, lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat )
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LPSTR lpitem;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpoleobject;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ char buf[MAX_STR+6];
+ int objCount;
+ int iTable = INVALID_INDEX;
+
+ Puts("OleCreateLinkFromFile");
+
+ PROBE_MODE(bProtMode);
+
+ if (!CheckClientDoc ((LPCLIENTDOC) lhclientdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpprotocol);
+ PROBE_READ(lpclient);
+ PROBE_READ(lpfile);
+ PROBE_WRITE(lplpoleobject);
+
+#ifdef FIREWALLS
+ ASSERT (lpobjname, "NULL lpobjname passed to OleCreateLinkFromFile\n");
+#endif
+
+ PROBE_READ(lpobjname);
+ if (!lpobjname[0])
+ return OLE_ERROR_NAME;
+ if (lpclass)
+ PROBE_READ(lpclass);
+ if (lpitem)
+ PROBE_READ(lpitem);
+
+ if (lstrcmpi (lpprotocol, PROTOCOL_EDIT))
+ return OLE_ERROR_PROTOCOL;
+
+ if (lpclass) {
+ if (!QueryApp (lpclass, lpprotocol, buf))
+ return OLE_ERROR_CLASS;
+
+ if (!lstrcmp (lpclass, packageClass)) {
+ lstrcpy (buf, lpfile);
+ lstrcat (buf, "/Link");
+ return CreateEmbLnkFromFile (lpclient, packageClass, buf,
+ NULL, lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat, OT_EMBEDDED);
+ }
+ else
+ iTable = LoadDll (lpclass);
+ }
+ else if (MapExtToClass (lpfile, (LPSTR)buf, MAX_STR))
+ iTable = LoadDll (buf);
+ else
+ return OLE_ERROR_CLASS;
+
+ if (iTable == INVALID_INDEX)
+ retval = DefCreateLinkFromFile (lpprotocol,
+ lpclient, lpclass, lpfile, lpitem,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+
+ else {
+ objCount = lpDllTable[iTable].cObj;
+ retval = (*lpDllTable[iTable].CreateLinkFromFile) (lpprotocol,
+ lpclient, lpclass, lpfile, lpitem,
+ lhclientdoc, lpobjname, lplpoleobject,
+ optRender, cfFormat);
+ if (retval > OLE_WAIT_FOR_RELEASE)
+ lpDllTable[iTable].cObj = objCount - 1;
+ else
+ (*lplpoleobject)->iTable = iTable;
+ }
+
+ return retval;
+}
+
+
+
+// Routines related to asynchronous operations.
+OLESTATUS FAR PASCAL OleQueryReleaseStatus (lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (!CheckPointer (lpobj, WRITE_ACCESS))
+ return OLE_ERROR_OBJECT;
+
+ // make sure that it is a long pointer to L&E object or a lock handle
+ if (!(lpobj->objId[0] == 'L' && lpobj->objId[1] == 'E')
+ && !(lpobj->objId[0] == 'S' && lpobj->objId[1] == 'L'))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->QueryReleaseStatus) (lpobj);
+}
+
+
+OLESTATUS FAR PASCAL OleQueryReleaseError (lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->QueryReleaseError) (lpobj);
+}
+
+OLE_RELEASE_METHOD FAR PASCAL OleQueryReleaseMethod (lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ return (*lpobj->lpvtbl->QueryReleaseMethod) (lpobj);
+}
+
+
+OLESTATUS FAR PASCAL OleRename (lpobj, lpNewName)
+LPOLEOBJECT lpobj;
+LPSTR lpNewName;
+{
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->Rename) (lpobj, lpNewName);
+}
+
+
+OLESTATUS FAR PASCAL OleExecute (lpobj, hCmds, wReserved)
+LPOLEOBJECT lpobj;
+HANDLE hCmds;
+WORD wReserved;
+{
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->Execute) (lpobj, hCmds, wReserved);
+}
+
+
+OLESTATUS FAR PASCAL OleQueryName (lpobj, lpBuf, lpcbBuf)
+LPOLEOBJECT lpobj;
+LPSTR lpBuf;
+WORD FAR * lpcbBuf;
+{
+ if (!CheckObject(lpobj))
+ return OLE_ERROR_OBJECT;
+
+ return (*lpobj->lpvtbl->QueryName) (lpobj, lpBuf, lpcbBuf);
+}
+
+OLESTATUS FAR PASCAL OleQueryType (lpobj, lptype)
+LPOLEOBJECT lpobj;
+LPLONG lptype;
+{
+ Puts("OleQueryType");
+
+ if (!CheckObject(lpobj))
+ return(OLE_ERROR_OBJECT);
+
+ PROBE_WRITE(lptype);
+
+ return (*lpobj->lpvtbl->QueryType) (lpobj, lptype);
+}
+
+
+
+DWORD FAR PASCAL OleQueryClientVersion ()
+{
+ return dwOleVer;
+}
+
+
+OLESTATUS INTERNAL LeQueryCreateFromClip (lpprotocol, optRender, cfFormat, cType)
+LPSTR lpprotocol;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG cType;
+{
+ OLESTATUS retVal = TRUE;
+ BOOL bEdit = FALSE, bStatic = FALSE;
+
+ PROBE_MODE(bProtMode);
+ PROBE_READ(lpprotocol);
+
+ if (bEdit = !lstrcmpi (lpprotocol, PROTOCOL_EDIT)) {
+ if (IsClipboardFormatAvailable (cfFileName))
+ return OLE_OK;
+
+ if (cType == CT_LINK)
+ retVal = IsClipboardFormatAvailable (cfObjectLink);
+#ifdef OLD
+ || IsClipboardFormatAvailable (cfLink) ;
+#endif
+ else if (cType == CT_EMBEDDED)
+ retVal = IsClipboardFormatAvailable (cfOwnerLink);
+
+ if (!retVal)
+ return OLE_ERROR_FORMAT;
+
+ if (optRender == olerender_none)
+ return OLE_OK;
+ }
+ else if (bStatic = !lstrcmpi (lpprotocol, PROTOCOL_STATIC)) {
+ if (cType == CT_LINK)
+ return OLE_ERROR_PROTOCOL;
+
+ if (optRender == olerender_none)
+ return OLE_ERROR_FORMAT;
+ }
+ else {
+ return OLE_ERROR_PROTOCOL;
+ }
+
+ if (optRender == olerender_draw) {
+ if (!IsClipboardFormatAvailable (CF_METAFILEPICT) &&
+ !IsClipboardFormatAvailable (CF_DIB) &&
+ !IsClipboardFormatAvailable (CF_BITMAP) &&
+ !(bEdit && QueryHandler((cType == CT_LINK) ? cfObjectLink : cfOwnerLink)))
+ return OLE_ERROR_FORMAT;
+ }
+ else if (optRender == olerender_format) {
+ if (!IsClipboardFormatAvailable (cfFormat))
+ return OLE_ERROR_FORMAT;
+
+ if (bStatic && (cfFormat != CF_METAFILEPICT)
+ && (cfFormat != CF_DIB) && (cfFormat != CF_BITMAP))
+ return OLE_ERROR_FORMAT;
+
+ }
+ else {
+ return OLE_ERROR_FORMAT;
+ }
+
+ return OLE_OK;
+}
+
+
+
+BOOL INTERNAL CheckObject(lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (!CheckPointer(lpobj, WRITE_ACCESS))
+ return FALSE;
+
+ if (lpobj->objId[0] == 'L' && lpobj->objId[1] == 'E')
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL FARINTERNAL FarCheckObject(lpobj)
+LPOLEOBJECT lpobj;
+{
+ return (CheckObject (lpobj));
+}
+
diff --git a/private/mvdm/wow16/ole/client/ole.h b/private/mvdm/wow16/ole/client/ole.h
new file mode 100644
index 000000000..37bcf9cad
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/ole.h
@@ -0,0 +1,504 @@
+/*****************************************************************************\
+* *
+* ole.h - Object Linking and Embedding functions, types, and definitions*
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1990-1992, Microsoft Corp. All rights reserved.*
+* *
+\*****************************************************************************/
+
+#ifndef _INC_OLE
+#define _INC_OLE
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif /* !RC_INVOKED */
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef WINAPI /* If not included with 3.1 headers... */
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define LPCSTR LPSTR
+#define UINT WORD
+#define LPARAM LONG
+#define WPARAM WORD
+#define LRESULT LONG
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#endif /* _INC_WINDOWS */
+
+#ifdef STRICT
+#define OLE_LPCSTR LPCSTR
+#define OLE_CONST const
+#else /* STRICT */
+#define OLE_LPCSTR LPSTR
+#define OLE_CONST
+#endif /* !STRICT */
+
+
+/* Object types */
+#define OT_LINK 1L
+#define OT_EMBEDDED 2L
+#define OT_STATIC 3L
+
+/* activate verbs */
+#define OLEVERB_PRIMARY 0
+
+/* target device info structure */
+typedef struct _OLETARGETDEVICE
+{
+ UINT otdDeviceNameOffset;
+ UINT otdDriverNameOffset;
+ UINT otdPortNameOffset;
+ UINT otdExtDevmodeOffset;
+ UINT otdExtDevmodeSize;
+ UINT otdEnvironmentOffset;
+ UINT otdEnvironmentSize;
+ BYTE otdData[1];
+} OLETARGETDEVICE;
+typedef OLETARGETDEVICE FAR* LPOLETARGETDEVICE;
+
+/* flags used in some methods */
+#define OF_SET 0x0001
+#define OF_GET 0x0002
+#define OF_HANDLER 0x0004
+
+/* return codes for OLE functions */
+typedef enum
+{
+ OLE_OK, /* 0 Function operated correctly */
+
+ OLE_WAIT_FOR_RELEASE, /* 1 Command has been initiated, client */
+ /* must wait for release. keep dispatching */
+ /* messages till OLE_RELESE in callback */
+
+ OLE_BUSY, /* 2 Tried to execute a method while another */
+ /* method is in progress. */
+
+ OLE_ERROR_PROTECT_ONLY, /* 3 Ole APIs are called in real mode */
+ OLE_ERROR_MEMORY, /* 4 Could not alloc or lock memory */
+ OLE_ERROR_STREAM, /* 5 (OLESTREAM) stream error */
+ OLE_ERROR_STATIC, /* 6 Non static object expected */
+ OLE_ERROR_BLANK, /* 7 Critical data missing */
+ OLE_ERROR_DRAW, /* 8 Error while drawing */
+ OLE_ERROR_METAFILE, /* 9 Invalid metafile */
+ OLE_ERROR_ABORT, /* 10 Client chose to abort metafile drawing */
+ OLE_ERROR_CLIPBOARD, /* 11 Failed to get/set clipboard data */
+ OLE_ERROR_FORMAT, /* 12 Requested format is not available */
+ OLE_ERROR_OBJECT, /* 13 Not a valid object */
+ OLE_ERROR_OPTION, /* 14 Invalid option(link update / render) */
+ OLE_ERROR_PROTOCOL, /* 15 Invalid protocol */
+ OLE_ERROR_ADDRESS, /* 16 One of the pointers is invalid */
+ OLE_ERROR_NOT_EQUAL, /* 17 Objects are not equal */
+ OLE_ERROR_HANDLE, /* 18 Invalid handle encountered */
+ OLE_ERROR_GENERIC, /* 19 Some general error */
+ OLE_ERROR_CLASS, /* 20 Invalid class */
+ OLE_ERROR_SYNTAX, /* 21 Command syntax is invalid */
+ OLE_ERROR_DATATYPE, /* 22 Data format is not supported */
+ OLE_ERROR_PALETTE, /* 23 Invalid color palette */
+ OLE_ERROR_NOT_LINK, /* 24 Not a linked object */
+ OLE_ERROR_NOT_EMPTY, /* 25 Client doc contains objects. */
+ OLE_ERROR_SIZE, /* 26 Incorrect buffer size passed to the api */
+ /* that places some string in caller's */
+ /* buffer */
+
+ OLE_ERROR_DRIVE, /* 27 Drive letter in doc name is invalid */
+ OLE_ERROR_NETWORK, /* 28 Failed to establish connection to a */
+ /* network share on which the document */
+ /* is located */
+
+ OLE_ERROR_NAME, /* 29 Invalid name(doc name, object name), */
+ /* etc.. passed to the APIs */
+
+ OLE_ERROR_TEMPLATE, /* 30 Server failed to load template */
+ OLE_ERROR_NEW, /* 31 Server failed to create new doc */
+ OLE_ERROR_EDIT, /* 32 Server failed to create embedded */
+ /* instance */
+ OLE_ERROR_OPEN, /* 33 Server failed to open document, */
+ /* possible invalid link */
+
+ OLE_ERROR_NOT_OPEN, /* 34 Object is not open for editing */
+ OLE_ERROR_LAUNCH, /* 35 Failed to launch server */
+ OLE_ERROR_COMM, /* 36 Failed to communicate with server */
+ OLE_ERROR_TERMINATE, /* 37 Error in termination */
+ OLE_ERROR_COMMAND, /* 38 Error in execute */
+ OLE_ERROR_SHOW, /* 39 Error in show */
+ OLE_ERROR_DOVERB, /* 40 Error in sending do verb, or invalid */
+ /* verb */
+ OLE_ERROR_ADVISE_NATIVE, /* 41 Item could be missing */
+ OLE_ERROR_ADVISE_PICT, /* 42 Item could be missing or server doesn't */
+ /* this format. */
+
+ OLE_ERROR_ADVISE_RENAME, /* 43 Server doesn't support rename */
+ OLE_ERROR_POKE_NATIVE, /* 44 Failure of poking native data to server */
+ OLE_ERROR_REQUEST_NATIVE, /* 45 Server failed to render native data */
+ OLE_ERROR_REQUEST_PICT, /* 46 Server failed to render presentation */
+ /* data */
+ OLE_ERROR_SERVER_BLOCKED, /* 47 Trying to block a blocked server or */
+ /* trying to revoke a blocked server */
+ /* or document */
+
+ OLE_ERROR_REGISTRATION, /* 48 Server is not registered in regestation */
+ /* data base */
+ OLE_ERROR_ALREADY_REGISTERED,/*49 Trying to register same doc multiple */
+ /* times */
+ OLE_ERROR_TASK, /* 50 Server or client task is invalid */
+ OLE_ERROR_OUTOFDATE, /* 51 Object is out of date */
+ OLE_ERROR_CANT_UPDATE_CLIENT,/* 52 Embed doc's client doesn't accept */
+ /* updates */
+ OLE_ERROR_UPDATE, /* 53 erorr while trying to update */
+ OLE_ERROR_SETDATA_FORMAT, /* 54 Server app doesn't understand the */
+ /* format given to its SetData method */
+ OLE_ERROR_STATIC_FROM_OTHER_OS,/* 55 trying to load a static object created */
+ /* on another Operating System */
+
+ /* Following are warnings */
+ OLE_WARN_DELETE_DATA = 1000 /* Caller must delete the data when he is */
+ /* done with it. */
+} OLESTATUS;
+
+
+
+/* Codes for CallBack events */
+typedef enum
+{
+ OLE_CHANGED, /* 0 */
+ OLE_SAVED, /* 1 */
+ OLE_CLOSED, /* 2 */
+ OLE_RENAMED, /* 3 */
+ OLE_QUERY_PAINT, /* 4 Interruptible paint support */
+ OLE_RELEASE, /* 5 Object is released(asynchronous operation */
+ /* is completed) */
+ OLE_QUERY_RETRY /* 6 Query for retry when server sends busy ACK */
+} OLE_NOTIFICATION;
+
+typedef enum
+{
+ OLE_NONE, /* 0 no method active */
+ OLE_DELETE, /* 1 object delete */
+ OLE_LNKPASTE, /* 2 PasteLink(auto reconnect) */
+ OLE_EMBPASTE, /* 3 paste(and update) */
+ OLE_SHOW, /* 4 Show */
+ OLE_RUN, /* 5 Run */
+ OLE_ACTIVATE, /* 6 Activate */
+ OLE_UPDATE, /* 7 Update */
+ OLE_CLOSE, /* 8 Close */
+ OLE_RECONNECT, /* 9 Reconnect */
+ OLE_SETUPDATEOPTIONS, /* 10 setting update options */
+ OLE_SERVERUNLAUNCH, /* 11 server is being unlaunched */
+ OLE_LOADFROMSTREAM, /* 12 LoadFromStream(auto reconnect) */
+ OLE_SETDATA, /* 13 OleSetData */
+ OLE_REQUESTDATA, /* 14 OleRequestData */
+ OLE_OTHER, /* 15 other misc async operations */
+ OLE_CREATE, /* 16 create */
+ OLE_CREATEFROMTEMPLATE, /* 17 CreatefromTemplate */
+ OLE_CREATELINKFROMFILE, /* 18 CreateLinkFromFile */
+ OLE_COPYFROMLNK, /* 19 CopyFromLink(auto reconnect) */
+ OLE_CREATEFROMFILE, /* 20 CreateFromFile */
+ OLE_CREATEINVISIBLE /* 21 CreateInvisible */
+} OLE_RELEASE_METHOD;
+
+/* rendering options */
+typedef enum
+{
+ olerender_none,
+ olerender_draw,
+ olerender_format
+} OLEOPT_RENDER;
+
+/* standard clipboard format type */
+typedef WORD OLECLIPFORMAT;
+
+/* Link update options */
+typedef enum
+{
+ oleupdate_always,
+ oleupdate_onsave,
+#ifndef OLE_INTERNAL
+ oleupdate_oncall
+#else
+ oleupdate_oncall,
+ oleupdate_onclose
+#endif /* OLE_INTERNAL */
+} OLEOPT_UPDATE;
+
+typedef HANDLE HOBJECT;
+typedef LONG LHSERVER;
+typedef LONG LHCLIENTDOC;
+typedef LONG LHSERVERDOC;
+
+typedef struct _OLEOBJECT FAR* LPOLEOBJECT;
+typedef struct _OLESTREAM FAR* LPOLESTREAM;
+typedef struct _OLECLIENT FAR* LPOLECLIENT;
+
+
+#ifndef OLE_INTERNAL
+/* object method table definitions. */
+typedef struct _OLEOBJECTVTBL
+{
+ void FAR* (CALLBACK* QueryProtocol) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* Release) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Show) (LPOLEOBJECT, BOOL);
+ OLESTATUS (CALLBACK* DoVerb) (LPOLEOBJECT, UINT, BOOL, BOOL);
+ OLESTATUS (CALLBACK* GetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+ OLESTATUS (CALLBACK* SetData) (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+ OLESTATUS (CALLBACK* SetTargetDevice) (LPOLEOBJECT, HGLOBAL);
+ OLESTATUS (CALLBACK* SetBounds) (LPOLEOBJECT, OLE_CONST RECT FAR*);
+ OLECLIPFORMAT (CALLBACK* EnumFormats) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* SetColorScheme) (LPOLEOBJECT, OLE_CONST LOGPALETTE FAR*);
+ /* Server has to implement only the above methods. */
+
+#ifndef SERVERONLY
+ /* Extra methods required for client. */
+ OLESTATUS (CALLBACK* Delete) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* SetHostNames) (LPOLEOBJECT, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SaveToStream) (LPOLEOBJECT, LPOLESTREAM);
+ OLESTATUS (CALLBACK* Clone) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* CopyFromLink) (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* Equal) (LPOLEOBJECT, LPOLEOBJECT);
+ OLESTATUS (CALLBACK* CopyToClipboard) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Draw) (LPOLEOBJECT, HDC, OLE_CONST RECT FAR*, OLE_CONST RECT FAR*, HDC);
+ OLESTATUS (CALLBACK* Activate) (LPOLEOBJECT, UINT, BOOL, BOOL, HWND, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLEOBJECT, HGLOBAL, UINT);
+ OLESTATUS (CALLBACK* Close) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Update) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* Reconnect) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* ObjectConvert) (LPOLEOBJECT, OLE_LPCSTR, LPOLECLIENT, LHCLIENTDOC, OLE_LPCSTR, LPOLEOBJECT FAR*);
+ OLESTATUS (CALLBACK* GetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+ OLESTATUS (CALLBACK* SetLinkUpdateOptions) (LPOLEOBJECT, OLEOPT_UPDATE);
+
+ OLESTATUS (CALLBACK* Rename) (LPOLEOBJECT, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* QueryName) (LPOLEOBJECT, LPSTR, UINT FAR*);
+
+ OLESTATUS (CALLBACK* QueryType) (LPOLEOBJECT, LONG FAR*);
+ OLESTATUS (CALLBACK* QueryBounds) (LPOLEOBJECT, RECT FAR*);
+ OLESTATUS (CALLBACK* QuerySize) (LPOLEOBJECT, DWORD FAR*);
+ OLESTATUS (CALLBACK* QueryOpen) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryOutOfDate) (LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* QueryReleaseStatus) (LPOLEOBJECT);
+ OLESTATUS (CALLBACK* QueryReleaseError) (LPOLEOBJECT);
+ OLE_RELEASE_METHOD (CALLBACK* QueryReleaseMethod)(LPOLEOBJECT);
+
+ OLESTATUS (CALLBACK* RequestData) (LPOLEOBJECT, OLECLIPFORMAT);
+ OLESTATUS (CALLBACK* ObjectLong) (LPOLEOBJECT, UINT, LONG FAR*);
+
+/* This method is internal only */
+ OLESTATUS (CALLBACK* ChangeData) (LPOLEOBJECT, HANDLE, LPOLECLIENT, BOOL);
+#endif /* !SERVERONLY */
+} OLEOBJECTVTBL;
+typedef OLEOBJECTVTBL FAR* LPOLEOBJECTVTBL;
+
+typedef struct _OLEOBJECT
+{
+ LPOLEOBJECTVTBL lpvtbl;
+} OLEOBJECT;
+#endif /* !OLE_NTERNAL */
+
+/* ole client definitions */
+typedef struct _OLECLIENTVTBL
+{
+ int (CALLBACK* CallBack)(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT);
+} OLECLIENTVTBL;
+
+typedef OLECLIENTVTBL FAR* LPOLECLIENTVTBL;
+
+typedef struct _OLECLIENT
+{
+ LPOLECLIENTVTBL lpvtbl;
+} OLECLIENT;
+
+/* Stream definitions */
+typedef struct _OLESTREAMVTBL
+{
+ DWORD (CALLBACK* Get)(LPOLESTREAM, void FAR*, DWORD);
+ DWORD (CALLBACK* Put)(LPOLESTREAM, OLE_CONST void FAR*, DWORD);
+} OLESTREAMVTBL;
+typedef OLESTREAMVTBL FAR* LPOLESTREAMVTBL;
+
+typedef struct _OLESTREAM
+{
+ LPOLESTREAMVTBL lpstbl;
+} OLESTREAM;
+
+/* Public Function Prototypes */
+OLESTATUS WINAPI OleDelete(LPOLEOBJECT);
+OLESTATUS WINAPI OleRelease(LPOLEOBJECT);
+OLESTATUS WINAPI OleSaveToStream(LPOLEOBJECT, LPOLESTREAM);
+OLESTATUS WINAPI OleEqual(LPOLEOBJECT, LPOLEOBJECT );
+OLESTATUS WINAPI OleCopyToClipboard(LPOLEOBJECT);
+OLESTATUS WINAPI OleSetHostNames(LPOLEOBJECT, LPCSTR, LPCSTR);
+OLESTATUS WINAPI OleSetTargetDevice(LPOLEOBJECT, HGLOBAL);
+OLESTATUS WINAPI OleSetBounds(LPOLEOBJECT, const RECT FAR*);
+OLESTATUS WINAPI OleSetColorScheme(LPOLEOBJECT, const LOGPALETTE FAR*);
+OLESTATUS WINAPI OleQueryBounds(LPOLEOBJECT, RECT FAR*);
+OLESTATUS WINAPI OleQuerySize(LPOLEOBJECT, DWORD FAR*);
+OLESTATUS WINAPI OleDraw(LPOLEOBJECT, HDC, const RECT FAR*, const RECT FAR*, HDC);
+OLESTATUS WINAPI OleQueryOpen(LPOLEOBJECT);
+OLESTATUS WINAPI OleActivate(LPOLEOBJECT, UINT, BOOL, BOOL, HWND, const RECT FAR*);
+OLESTATUS WINAPI OleExecute(LPOLEOBJECT, HGLOBAL, UINT);
+OLESTATUS WINAPI OleClose(LPOLEOBJECT);
+OLESTATUS WINAPI OleUpdate(LPOLEOBJECT);
+OLESTATUS WINAPI OleReconnect(LPOLEOBJECT);
+OLESTATUS WINAPI OleGetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE FAR*);
+OLESTATUS WINAPI OleSetLinkUpdateOptions(LPOLEOBJECT, OLEOPT_UPDATE);
+void FAR* WINAPI OleQueryProtocol(LPOLEOBJECT, LPCSTR);
+
+/* Routines related to asynchronous operations. */
+OLESTATUS WINAPI OleQueryReleaseStatus(LPOLEOBJECT);
+OLESTATUS WINAPI OleQueryReleaseError(LPOLEOBJECT);
+OLE_RELEASE_METHOD WINAPI OleQueryReleaseMethod(LPOLEOBJECT);
+
+OLESTATUS WINAPI OleQueryType(LPOLEOBJECT, LONG FAR*);
+
+/* LOWORD is major version, HIWORD is minor version */
+DWORD WINAPI OleQueryClientVersion(void);
+DWORD WINAPI OleQueryServerVersion(void);
+
+/* Converting to format (as in clipboard): */
+OLECLIPFORMAT WINAPI OleEnumFormats(LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS WINAPI OleGetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR*);
+OLESTATUS WINAPI OleSetData(LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS WINAPI OleQueryOutOfDate(LPOLEOBJECT);
+OLESTATUS WINAPI OleRequestData(LPOLEOBJECT, OLECLIPFORMAT);
+
+/* Query apis for creation from clipboard */
+OLESTATUS WINAPI OleQueryLinkFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleQueryCreateFromClip(LPCSTR, OLEOPT_RENDER, OLECLIPFORMAT);
+
+/* Object creation functions */
+OLESTATUS WINAPI OleCreateFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromClip(LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateLinkFromFile(LPCSTR, LPOLECLIENT, LPCSTR, LPCSTR, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleLoadFromStream(LPOLESTREAM, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCreate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleCreateInvisible(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT, BOOL);
+OLESTATUS WINAPI OleCreateFromTemplate(LPCSTR, LPOLECLIENT, LPCSTR, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*, OLEOPT_RENDER, OLECLIPFORMAT);
+OLESTATUS WINAPI OleClone(LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleCopyFromLink(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleObjectConvert(LPOLEOBJECT, LPCSTR, LPOLECLIENT, LHCLIENTDOC, LPCSTR, LPOLEOBJECT FAR*);
+OLESTATUS WINAPI OleRename(LPOLEOBJECT, LPCSTR);
+OLESTATUS WINAPI OleQueryName(LPOLEOBJECT, LPSTR, UINT FAR*);
+OLESTATUS WINAPI OleRevokeObject(LPOLECLIENT);
+BOOL WINAPI OleIsDcMeta(HDC);
+
+/* client document API */
+OLESTATUS WINAPI OleRegisterClientDoc(LPCSTR, LPCSTR, LONG, LHCLIENTDOC FAR*);
+OLESTATUS WINAPI OleRevokeClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleRenameClientDoc(LHCLIENTDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleSavedClientDoc(LHCLIENTDOC);
+OLESTATUS WINAPI OleEnumObjects(LHCLIENTDOC, LPOLEOBJECT FAR*);
+
+/* server usage definitions */
+typedef enum {
+ OLE_SERVER_MULTI, /* multiple instances */
+ OLE_SERVER_SINGLE /* single instance(multiple document) */
+} OLE_SERVER_USE;
+
+/* Server API */
+typedef struct _OLESERVER FAR* LPOLESERVER;
+
+OLESTATUS WINAPI OleRegisterServer(LPCSTR, LPOLESERVER, LHSERVER FAR*, HINSTANCE, OLE_SERVER_USE);
+OLESTATUS WINAPI OleRevokeServer(LHSERVER);
+OLESTATUS WINAPI OleBlockServer(LHSERVER);
+OLESTATUS WINAPI OleUnblockServer(LHSERVER, BOOL FAR*);
+
+/* APIs to keep server open */
+OLESTATUS WINAPI OleLockServer(LPOLEOBJECT, LHSERVER FAR*);
+OLESTATUS WINAPI OleUnlockServer(LHSERVER);
+
+/* Server document API */
+
+typedef struct _OLESERVERDOC FAR* LPOLESERVERDOC;
+
+OLESTATUS WINAPI OleRegisterServerDoc(LHSERVER, LPCSTR, LPOLESERVERDOC, LHSERVERDOC FAR*);
+OLESTATUS WINAPI OleRevokeServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleRenameServerDoc(LHSERVERDOC, LPCSTR);
+OLESTATUS WINAPI OleRevertServerDoc(LHSERVERDOC);
+OLESTATUS WINAPI OleSavedServerDoc(LHSERVERDOC);
+
+typedef struct _OLESERVERVTBL
+{
+ OLESTATUS (CALLBACK* Open) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* document name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Create)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* CreateFromTemplate)(LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* lp template name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Edit) (LPOLESERVER, LHSERVERDOC, OLE_LPCSTR, OLE_LPCSTR, LPOLESERVERDOC FAR*);
+ /* long handle to doc(privtate to DLL) */
+ /* lp to OLESERVER */
+ /* lp class name */
+ /* lp doc name */
+ /* place holder for returning oledoc. */
+
+ OLESTATUS (CALLBACK* Exit) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Release) (LPOLESERVER);
+ /* lp OLESERVER */
+
+ OLESTATUS (CALLBACK* Execute)(LPOLESERVER, HGLOBAL);
+ /* lp OLESERVER */
+ /* handle to command strings */
+} OLESERVERVTBL;
+typedef OLESERVERVTBL FAR* LPOLESERVERVTBL;
+
+typedef struct _OLESERVER
+{
+ LPOLESERVERVTBL lpvtbl;
+} OLESERVER;
+
+typedef struct _OLESERVERDOCVTBL
+{
+ OLESTATUS (CALLBACK* Save) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* Close) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetHostNames)(LPOLESERVERDOC, OLE_LPCSTR, OLE_LPCSTR);
+ OLESTATUS (CALLBACK* SetDocDimensions)(LPOLESERVERDOC, OLE_CONST RECT FAR*);
+ OLESTATUS (CALLBACK* GetObject) (LPOLESERVERDOC, OLE_LPCSTR, LPOLEOBJECT FAR*, LPOLECLIENT);
+ OLESTATUS (CALLBACK* Release) (LPOLESERVERDOC);
+ OLESTATUS (CALLBACK* SetColorScheme)(LPOLESERVERDOC, OLE_CONST LOGPALETTE FAR*);
+ OLESTATUS (CALLBACK* Execute) (LPOLESERVERDOC, HGLOBAL);
+} OLESERVERDOCVTBL;
+typedef OLESERVERDOCVTBL FAR* LPOLESERVERDOCVTBL;
+
+typedef struct _OLESERVERDOC
+{
+ LPOLESERVERDOCVTBL lpvtbl;
+} OLESERVERDOC;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif /* !RC_INVOKED */
+
+#endif /* !_INC_OLE */
diff --git a/private/mvdm/wow16/ole/client/olecli.def b/private/mvdm/wow16/ole/client/olecli.def
new file mode 100644
index 000000000..cb161aa47
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/olecli.def
@@ -0,0 +1,233 @@
+LIBRARY OLECLI INITINSTANCE
+
+DESCRIPTION "OLE Client. support (c) Copyright Microsoft Corp. 1990 - All Rights Reserved";"
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE MOVABLE DISCARDABLE
+DATA MOVABLE SINGLE
+
+SEGMENTS
+ WEP_TEXT CLASS 'CODE' FIXED
+
+HEAPSIZE 2048
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+ OLEDELETE @2
+
+ OLESAVETOSTREAM @3
+ OLELOADFROMSTREAM @4
+ OLECLONE @6
+ OLECOPYFROMLINK @7
+
+ OLEEQUAL @8
+
+ OLEQUERYLINKFROMCLIP @9
+ OLEQUERYCREATEFROMCLIP @10
+
+ OLECREATELINKFROMCLIP @11
+ OLECREATEFROMCLIP @12
+
+ OLECOPYTOCLIPBOARD @13
+
+ OLEQUERYTYPE @14
+ OLESETHOSTNAMES @15
+ OLESETTARGETDEVICE @16
+ OLESETBOUNDS @17
+
+ OLEQUERYBOUNDS @18
+ OLEDRAW @19
+
+ OLEQUERYOPEN @20
+ OLEACTIVATE @21
+ OLEUPDATE @22
+ OLERECONNECT @23
+
+ OLEGETLINKUPDATEOPTIONS @24
+ OLESETLINKUPDATEOPTIONS @25
+
+ OLEENUMFORMATS @26
+ OLECLOSE @27
+
+ OLEGETDATA @28
+ OLESETDATA @29
+
+ OLEQUERYPROTOCOL @30
+
+ OLEQUERYOUTOFDATE @31
+
+ OLEOBJECTCONVERT @32
+ OLECREATEFROMTEMPLATE @33
+ OLECREATE @34
+ OLEQUERYRELEASESTATUS @35
+ OLEQUERYRELEASEERROR @36
+ OLEQUERYRELEASEMETHOD @37
+
+ OLECREATEFROMFILE @38
+ OLECREATELINKFROMFILE @39
+
+ OLERELEASE @40
+
+ OLEREGISTERCLIENTDOC @41
+ OLEREVOKECLIENTDOC @42
+ OLERENAMECLIENTDOC @43
+ OLEREVERTCLIENTDOC @44
+ OLESAVEDCLIENTDOC @45
+
+ OLERENAME @46
+ OLEENUMOBJECTS @47
+ OLEQUERYNAME @48
+
+ OLESETCOLORSCHEME @49
+ OLEREQUESTDATA @50
+
+ OLELOCKSERVER @54
+ OLEUNLOCKSERVER @55
+
+ OLEQUERYSIZE @56
+
+ OLEEXECUTE @57
+ OLECREATEINVISIBLE @58
+ OLEQUERYCLIENTVERSION @59
+
+ OLEISDCMETA @60
+
+ DocWndProc @100 ;Internal
+ SrvrWndProc @101 ;Internal
+ MfCallbackFunc @102 ;Internal
+
+ DEFLOADFROMSTREAM @110
+ DEFCREATEFROMCLIP @111
+ DEFCREATELINKFROMCLIP @112
+ DEFCREATEFROMTEMPLATE @113
+ DEFCREATE @114
+ DEFCREATEFROMFILE @115
+ DEFCREATELINKFROMFILE @116
+ DEFCREATEINVISIBLE @117
+
+ LeRelease @200 ;Internal
+ LeShow @201 ;Internal
+ LeGetData @202 ;Internal
+ LeSetData @203 ;Internal
+ LeSetHostNames @204 ;Internal
+ LeSetTargetDevice @205 ;Internal
+ LeSetBounds @206 ;Internal
+ LeSaveToStream @207 ;Internal
+ LeClone @208 ;Internal
+ LeCopyFromLink @209 ;Internal
+ LeEqual @210 ;Internal
+ LeCopy @211 ;Internal
+ LeQueryType @212 ;Internal
+ LeQueryBounds @213 ;Internal
+ LeDraw @214 ;Internal
+ LeQueryOpen @215 ;Internal
+ LeActivate @216 ;Internal
+ LeUpdate @218 ;Internal
+ LeReconnect @219 ;Internal
+ LeEnumFormat @220 ;Internal
+ LeQueryProtocol @221 ;Internal
+ LeQueryOutOfDate @222 ;Internal
+ LeObjectConvert @223 ;Internal
+ LeChangeData @224 ;Internal
+ LeClose @225 ;Internal
+ LeGetUpdateOptions @226 ;Internal
+ LeSetUpdateOptions @227 ;Internal
+ LeExecute @228 ;Internal
+ LeObjectLong @229 ;Internal
+ LeCreateInvisible @230 ;Internal
+
+ MfRelease @300 ;Internal
+ MfGetData @301 ;Internal
+ MfSaveToStream @302 ;Internal
+ MfClone @303 ;Internal
+ MfEqual @304 ;Internal
+ MfCopy @305 ;Internal
+ MfQueryBounds @307 ;Internal
+ MfDraw @308 ;Internal
+ MfEnumFormat @309 ;Internal
+ MfChangeData @310 ;Internal
+
+
+ BmRelease @400 ;Internal
+ BmGetData @401 ;Internal
+ BmSaveToStream @402 ;Internal
+ BmClone @403 ;Internal
+ BmEqual @404 ;Internal
+ BmCopy @405 ;Internal
+ BmQueryBounds @407 ;Internal
+ BmDraw @408 ;Internal
+ BmEnumFormat @409 ;Internal
+ BmChangeData @410 ;Internal
+
+
+ DibRelease @500 ;Internal
+ DibGetData @501 ;Internal
+ DibSaveToStream @502 ;Internal
+ DibClone @503 ;Internal
+ DibEqual @504 ;Internal
+ DibCopy @505 ;Internal
+ DibQueryBounds @507 ;Internal
+ DibDraw @508 ;Internal
+ DibEnumFormat @509 ;Internal
+ DibChangeData @510 ;Internal
+
+ GenRelease @600 ;Internal
+ GenGetData @601 ;Internal
+ GenSetData @602 ;Internal
+ GenSaveToStream @603 ;Internal
+ GenClone @604 ;Internal
+ GenEqual @605 ;Internal
+ GenCopy @606 ;Internal
+ GenQueryBounds @608 ;Internal
+ GenDraw @609 ;Internal
+ GenEnumFormat @610 ;Internal
+ GenChangeData @611 ;Internal
+
+
+ ErrShow @701 ;Internal
+ ErrSetData @702 ;Internal
+ ErrSetHostNames @703 ;Internal
+ ErrSetTargetDevice @704 ;Internal
+ ErrSetBounds @705 ;Internal
+ ErrCopyFromLink @706 ;Internal
+ ErrQueryOpen @707 ;Internal
+ ErrActivate @708 ;Internal
+ ErrClose @709 ;Internal
+ ErrUpdate @710 ;Internal
+ ErrReconnect @711 ;Internal
+ ErrQueryProtocol @712 ;Internal
+ ErrQueryOutOfDate @713 ;Internal
+ ErrObjectConvert @714 ;Internal
+ ErrGetUpdateOptions @715 ;Internal
+ ErrSetUpdateOptions @716 ;Internal
+ ErrExecute @717 ;Internal
+ ErrObjectLong @718 ;Internal
+
+
+ PbLoadFromStream @800 ;Internal
+ PbCreateFromClip @801 ;Internal
+ PbCreateLinkFromClip @802 ;Internal
+ PbCreateFromTemplate @803 ;Internal
+ PbCreate @804 ;Internal
+ PbDraw @805 ;Internal
+ PbQueryBounds @806 ;Internal
+ PbCopyToClipboard @807 ;Internal
+ PbCreateFromFile @808 ;Internal
+ PbCreateLinkfromFile @809 ;Internal
+ PbEnumFormats @810 ;Internal
+ PbGetData @811 ;Internal
+ PbCreateInvisible @812 ;Internal
+
+ ObjQueryName @910 ;Internal
+ ObjRename @911 ;Internal
+ ObjQueryType @912 ;Internal
+ ObjQuerySize @913 ;Internal
+
+ ConnectDlgProc @950 ;Internal
+ SetNetName @951 ;Internal
+ CheckNetDrive @952 ;Internal
+ SetNextNetDrive @953 ;Internal
+ GetTaskVisibleWindow @954
diff --git a/private/mvdm/wow16/ole/client/pbhandlr.c b/private/mvdm/wow16/ole/client/pbhandlr.c
new file mode 100644
index 000000000..bf448d59a
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/pbhandlr.c
@@ -0,0 +1,511 @@
+/****************************** Module Header ******************************\
+* Module Name: Pbhandlr.C -- Native data based handler (for Pbrush server)
+*
+* PURPOSE: Contains handler routines for Pbrush server. This handler makes
+* use of most of the standard library methods. It replaces only the "Draw",
+* "QueryBounds", "CopyToClipboard" methods of the OLE object. Note that this
+* handler draws the picture from the native data.
+*
+* Created: December 1990
+*
+* Copyright (c) 1990 Microsoft Corporation
+*
+* History:
+* SriniK (../12/1990) Original
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "dll.h"
+
+
+OLESTATUS FAR PASCAL _loadds PbDraw (LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS FAR PASCAL _loadds PbQueryBounds (LPOLEOBJECT, LPRECT);
+OLESTATUS FAR PASCAL _loadds PbCopyToClipboard (LPOLEOBJECT);
+OLESTATUS FAR PASCAL _loadds PbGetData (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR *);
+OLECLIPFORMAT FAR PASCAL _loadds PbEnumFormats (LPOLEOBJECT, OLECLIPFORMAT);
+
+extern OLESTATUS FARINTERNAL wDibDraw (HANDLE, HDC, LPRECT, LPRECT, HDC, BOOL);
+
+
+void PbGetExtents (LPSTR, LPPOINT);
+void PbReplaceFunctions (LPOLEOBJECT);
+HANDLE PbGetPicture (LPOLEOBJECT);
+BOOL IsStandardPict (LPOLEOBJECT);
+
+extern void FARINTERNAL DibGetExtents(LPSTR, LPPOINT);
+
+OLEOBJECTVTBL vtblDLL;
+
+extern OLECLIPFORMAT cfOwnerLink;
+extern OLECLIPFORMAT cfObjectLink;
+extern OLECLIPFORMAT cfNative;
+
+OLESTATUS (FAR PASCAL *DefQueryBounds) (LPVOID, LPRECT);
+OLESTATUS (FAR PASCAL *DefDraw) (LPVOID, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS (FAR PASCAL *DefCopyToClipboard) (LPVOID);
+OLECLIPFORMAT (FAR PASCAL *DefEnumFormats) (LPVOID, OLECLIPFORMAT);
+OLESTATUS (FAR PASCAL *DefGetData) (LPVOID, OLECLIPFORMAT, HANDLE FAR *);
+
+
+OLESTATUS FAR PASCAL PbLoadFromStream (lpstream, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, objType, aClass, cfFormat)
+LPOLESTREAM lpstream;
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+LONG objType;
+ATOM aClass;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if (objType == OT_LINK)
+ retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ objType, aClass, cfNative);
+ else
+ retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ objType, aClass, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreateFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, objType)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+LONG objType;
+{
+ OLESTATUS retVal;
+
+ if ((optRender == olerender_draw)
+ && (IsClipboardFormatAvailable (cfNative))) {
+ if (objType == OT_EMBEDDED)
+ retVal = DefCreateFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_none, NULL, objType);
+ else
+ retVal = DefCreateFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_format, cfNative, objType);
+ }
+ else {
+ retVal = DefCreateFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, objType);
+ }
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if ((optRender == olerender_draw)
+ && (IsClipboardFormatAvailable (cfNative))) {
+ retVal = DefCreateLinkFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_format, cfNative);
+ }
+ else {
+ retVal = DefCreateLinkFromClip (lpprotocol, lpclient,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+ }
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreateFromTemplate (lpprotocol, lpclient, lptemplate, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lptemplate;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if (optRender == olerender_draw)
+ retVal = DefCreateFromTemplate (lpprotocol, lpclient, lptemplate,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_none, NULL);
+
+ else
+ retVal = DefCreateFromTemplate (lpprotocol, lpclient, lptemplate,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreate (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if (optRender == olerender_draw)
+ retVal = DefCreate (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_none, NULL);
+ else
+ retVal = DefCreate (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if (optRender == olerender_draw)
+ retVal = DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_none, NULL);
+
+ else
+ retVal = DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+OLESTATUS FAR PASCAL PbCreateLinkFromFile (lpprotocol, lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LPSTR lpfile;
+LPSTR lpitem;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+{
+ OLESTATUS retVal;
+
+ if (optRender == olerender_draw)
+ retVal = DefCreateLinkFromFile (lpprotocol, lpclient,
+ lpclass, lpfile, lpitem,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_format, cfNative);
+
+ else
+ retVal = DefCreateLinkFromFile (lpprotocol, lpclient,
+ lpclass, lpfile, lpitem,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+
+OLESTATUS FAR PASCAL PbCreateInvisible (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, fActivate)
+LPSTR lpprotocol;
+LPOLECLIENT lpclient;
+LPSTR lpclass;
+LHCLIENTDOC lhclientdoc;
+LPSTR lpobjname;
+LPOLEOBJECT FAR * lplpobj;
+OLEOPT_RENDER optRender;
+OLECLIPFORMAT cfFormat;
+BOOL fActivate;
+{
+ OLESTATUS retVal;
+
+ if (optRender == olerender_draw)
+ retVal = DefCreateInvisible (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpobj,
+ olerender_none, NULL, fActivate);
+ else
+ retVal = DefCreateInvisible (lpprotocol, lpclient, lpclass,
+ lhclientdoc, lpobjname, lplpobj,
+ optRender, cfFormat, fActivate);
+
+ if (retVal <= OLE_WAIT_FOR_RELEASE)
+ PbReplaceFunctions (*lplpobj);
+
+ return retVal;
+}
+
+
+void PbReplaceFunctions (lpobj)
+LPOLEOBJECT lpobj;
+{
+ if (IsStandardPict (lpobj))
+ return;
+
+ vtblDLL = *lpobj->lpvtbl;
+ lpobj->lpvtbl = (LPOLEOBJECTVTBL) &vtblDLL;
+
+ DefDraw = lpobj->lpvtbl->Draw;
+ DefQueryBounds = lpobj->lpvtbl->QueryBounds;
+ DefCopyToClipboard = lpobj->lpvtbl->CopyToClipboard;
+ DefEnumFormats = lpobj->lpvtbl->EnumFormats;
+ DefGetData = lpobj->lpvtbl->GetData;
+
+ lpobj->lpvtbl->Draw = PbDraw;
+ lpobj->lpvtbl->QueryBounds = PbQueryBounds;
+ lpobj->lpvtbl->CopyToClipboard = PbCopyToClipboard;
+ lpobj->lpvtbl->EnumFormats = PbEnumFormats;
+ lpobj->lpvtbl->GetData = PbGetData;
+}
+
+
+
+OLESTATUS FAR PASCAL _loadds PbQueryBounds (lpobj, lprc)
+LPOLEOBJECT lpobj;
+LPRECT lprc;
+{
+ OLESTATUS retVal;
+ HANDLE hData;
+ LPSTR lpData;
+ POINT point;
+
+ if ((retVal = (*DefQueryBounds) (lpobj, lprc)) == OLE_OK) {
+ if (lprc->top || lprc->bottom || lprc->right || lprc->left)
+ return OLE_OK;
+ }
+
+ if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
+ return retVal;
+
+ if (!hData)
+ return OLE_ERROR_BLANK;
+
+ if (!(lpData = GlobalLock (hData)))
+ return OLE_ERROR_MEMORY;
+
+ DibGetExtents ((lpData+sizeof(BITMAPFILEHEADER)), &point);
+ GlobalUnlock (hData);
+
+ lprc->left = 0;
+ lprc->top = 0;
+ lprc->right = point.x;
+ lprc->bottom = point.y;
+
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL _loadds PbDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
+LPOLEOBJECT lpobj;
+HDC hdc;
+LPRECT lprc;
+LPRECT lpWrc;
+HDC hdcTarget;
+{
+ HANDLE hData;
+
+ if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
+ return (*DefDraw) (lpobj, hdc, lprc, lpWrc, hdcTarget);
+
+ return wDibDraw (hData, hdc, lprc, lpWrc, hdcTarget, TRUE);
+}
+
+
+OLECLIPFORMAT FAR PASCAL _loadds PbEnumFormats (lpobj, cfFormat)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+{
+ OLECLIPFORMAT retFormat = NULL;
+
+ if (cfFormat == CF_METAFILEPICT)
+ return NULL;
+
+ if (!(retFormat = (*DefEnumFormats) (lpobj, cfFormat)))
+ return CF_METAFILEPICT;
+
+ return retFormat;
+}
+
+
+OLESTATUS FAR PASCAL _loadds PbGetData (lpobj, cfFormat, lpHandle)
+LPOLEOBJECT lpobj;
+OLECLIPFORMAT cfFormat;
+HANDLE FAR * lpHandle;
+{
+ OLESTATUS retval;
+
+ retval = (*DefGetData) (lpobj, cfFormat, lpHandle);
+
+ if (retval == OLE_OK || retval == OLE_BUSY || retval == OLE_ERROR_BLANK)
+ return retval;
+
+ if (cfFormat == CF_METAFILEPICT) {
+ if (*lpHandle = PbGetPicture (lpobj))
+ return OLE_WARN_DELETE_DATA;
+
+ return OLE_ERROR_MEMORY;
+ }
+
+ return OLE_ERROR_FORMAT;
+}
+
+
+
+OLESTATUS FAR PASCAL _loadds PbCopyToClipboard (lpobj)
+LPOLEOBJECT lpobj;
+{
+ OLESTATUS retVal;
+ HANDLE hPict;
+
+ if ((retVal = (*DefCopyToClipboard) (lpobj)) == OLE_OK) {
+ if (hPict = PbGetPicture (lpobj))
+ SetClipboardData (CF_METAFILEPICT, hPict);
+ else
+ retVal = OLE_ERROR_MEMORY;
+ }
+
+ return retVal;
+}
+
+HANDLE PbGetPicture (lpobj)
+LPOLEOBJECT lpobj;
+{
+ HANDLE hMF, hMfp, hData;
+ RECT rc = {0, 0, 0, 0};
+ POINT point;
+ HDC hMetaDC;
+ LPMETAFILEPICT lpmfp;
+ OLESTATUS retVal;
+ LPSTR lpData;
+
+ if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
+ return NULL;
+
+ if (!hData)
+ return NULL;
+
+ if (!(lpData = GlobalLock (hData)))
+ return NULL;
+
+ lpData += sizeof(BITMAPFILEHEADER);
+ rc.right = (int) ((LPBITMAPINFOHEADER)lpData)->biWidth;
+ rc.bottom = (int) ((LPBITMAPINFOHEADER)lpData)->biHeight;
+ DibGetExtents(lpData, &point);
+ GlobalUnlock (hData);
+
+ if (!(hMetaDC = CreateMetaFile (NULL)))
+ return NULL;
+
+ SetWindowOrg (hMetaDC, 0, 0);
+ SetWindowExt (hMetaDC, rc.right, rc.bottom);
+ retVal = PbDraw (lpobj, hMetaDC, &rc, NULL, NULL);
+ hMF = CloseMetaFile (hMetaDC);
+
+ if (retVal != OLE_OK)
+ goto error;
+
+ if (hMF && (hMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))
+ && (lpmfp = (LPMETAFILEPICT) GlobalLock (hMfp))) {
+ lpmfp->hMF = hMF;
+ lpmfp->xExt = point.x;
+ lpmfp->yExt = -point.y;
+ lpmfp->mm = MM_ANISOTROPIC;
+ GlobalUnlock (hMfp);
+ return hMfp;
+ }
+
+error:
+
+ if (hMF)
+ DeleteMetaFile (hMF);
+
+ if (hMfp)
+ GlobalFree (hMfp);
+
+ return NULL;
+}
+
+
+// normal handler can't do this. since this handler is part of olecli.dll, we
+// we are doing this.
+
+BOOL IsStandardPict (lpobj)
+LPOLEOBJECT lpobj;
+{
+ LPOBJECT_LE lpLEobj;
+ LONG type;
+
+ lpLEobj = (LPOBJECT_LE) lpobj;
+ if (!lpLEobj->lpobjPict)
+ return FALSE;
+
+ if ((*lpLEobj->lpobjPict->lpvtbl->QueryType) (lpLEobj->lpobjPict, &type)
+ == OLE_ERROR_GENERIC)
+ return FALSE;
+
+ return TRUE;
+}
+
+
diff --git a/private/mvdm/wow16/ole/client/pict.h b/private/mvdm/wow16/ole/client/pict.h
new file mode 100644
index 000000000..7824c39c8
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/pict.h
@@ -0,0 +1,190 @@
+/****************************** Module Header ******************************\
+* Module Name: pict.h
+*
+* PURPOSE: Private definitions file for presentation object related files
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../90,91) Original
+*
+\***************************************************************************/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in MF.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+OLESTATUS FARINTERNAL MfRelease (LPOBJECT_MF);
+OLESTATUS FARINTERNAL MfSaveToStream (LPOBJECT_MF, LPOLESTREAM);
+OLESTATUS FARINTERNAL MfClone (LPOBJECT_MF, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_MF FAR *);
+OLESTATUS FARINTERNAL MfEqual (LPOBJECT_MF, LPOBJECT_MF);
+OLESTATUS FARINTERNAL MfCopy (LPOBJECT_MF);
+OLESTATUS FARINTERNAL MfQueryBounds (LPOBJECT_MF, LPRECT);
+OLESTATUS FARINTERNAL MfGetData (LPOBJECT_MF, OLECLIPFORMAT, LPHANDLE);
+OLESTATUS FARINTERNAL MfSetData (LPOBJECT_MF, OLECLIPFORMAT, HANDLE);
+OLESTATUS FARINTERNAL MfChangeData (LPOBJECT_MF, HANDLE, LPOLECLIENT, BOOL);
+OLESTATUS INTERNAL MfCopyToClip (LPOBJECT_MF, HANDLE);
+void FARINTERNAL MfSetExtents (LPOBJECT_MF);
+DWORD INTERNAL MfGetSize (LPHANDLE);
+HANDLE INTERNAL GetHmfp (LPOBJECT_MF);
+OLESTATUS INTERNAL MfUpdateStruct (LPOBJECT_MF, LPOLECLIENT, HANDLE,
+ LPMETAFILEPICT, HANDLE, BOOL);
+OLECLIPFORMAT FARINTERNAL MfEnumFormat (LPOBJECT_MF, OLECLIPFORMAT);
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in DIB.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+/* The DIB file will be of the following format: */
+/* */
+/* 0004 */
+/* "DIB" */
+/* 4 bytes of xExtent in MM_HIMETIRC units (or) 0 */
+/* 4 bytes of yExtent in MM_HIMETIRC units (or) 0 */
+/* 4 bytes of size of (BITMAPINFOHEADER + RBGQUAD + bit array) */
+/* BITMAPINFOHEADER structure */
+/* RBGQUAD array */
+/* array of DI bits */
+/* */
+
+OLESTATUS FARINTERNAL DibRelease (LPOBJECT_DIB);
+OLESTATUS FARINTERNAL DibSaveToStream (LPOBJECT_DIB, LPOLESTREAM);
+OLESTATUS FARINTERNAL DibClone (LPOBJECT_DIB, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_DIB FAR *);
+OLESTATUS FARINTERNAL DibEqual (LPOBJECT_DIB, LPOBJECT_DIB);
+OLESTATUS FARINTERNAL DibCopy (LPOBJECT_DIB);
+OLESTATUS FARINTERNAL DibQueryBounds (LPOBJECT_DIB, LPRECT);
+OLESTATUS FARINTERNAL DibGetData (LPOBJECT_DIB, OLECLIPFORMAT, LPHANDLE);
+OLESTATUS FARINTERNAL DibChangeData (LPOBJECT_DIB, HANDLE, LPOLECLIENT, BOOL);
+BOOL INTERNAL DibStreamRead (LPOLESTREAM,LPOBJECT_DIB);
+void INTERNAL DibUpdateStruct (LPOBJECT_DIB, LPOLECLIENT, HANDLE, LPBITMAPINFOHEADER, DWORD);
+
+OLECLIPFORMAT FARINTERNAL DibEnumFormat (LPOBJECT_DIB, OLECLIPFORMAT);
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in BM.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+/* The BM file will be of the following format: */
+/* */
+/* 0007 */
+/* "BITMAP" */
+/* 4 bytes of xExtent in MM_HIMETIRC units (or) 0 */
+/* 4 bytes of yExtent in MM_HIMETIRC units (or) 0 */
+/* 4 bytes of size of (BITMAP + bits) */
+/* BITMAP structure */
+/* bitmap bits */
+/* */
+
+OLESTATUS FARINTERNAL BmRelease (LPOBJECT_BM);
+OLESTATUS FARINTERNAL BmSaveToStream (LPOBJECT_BM, LPOLESTREAM);
+OLESTATUS FARINTERNAL BmClone (LPOBJECT_BM, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_BM FAR *);
+OLESTATUS FARINTERNAL BmEqual (LPOBJECT_BM, LPOBJECT_BM);
+OLESTATUS FARINTERNAL BmCopy (LPOBJECT_BM);
+OLESTATUS FARINTERNAL BmQueryBounds (LPOBJECT_BM, LPRECT);
+OLESTATUS FARINTERNAL BmGetData (LPOBJECT_BM, OLECLIPFORMAT, LPHANDLE);
+OLESTATUS FARINTERNAL BmChangeData (LPOBJECT_BM, HBITMAP, LPOLECLIENT, BOOL);
+OLESTATUS INTERNAL BmStreamWrite (LPOLESTREAM, LPOBJECT_BM);
+BOOL INTERNAL BmStreamRead (LPOLESTREAM, LPOBJECT_BM);
+void INTERNAL BmUpdateStruct (LPOBJECT_BM, LPOLECLIENT, HBITMAP, LPBITMAP, DWORD);
+
+OLECLIPFORMAT FARINTERNAL BmEnumFormat (LPOBJECT_BM, OLECLIPFORMAT);
+LPOBJECT_BM INTERNAL BmCreateObject (HBITMAP, LPOLECLIENT, BOOL,
+ LHCLIENTDOC, LPSTR, LONG);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in GENERIC.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+
+/* The GENERIC file will be of the following format: */
+/* */
+/* 0007 */
+/* "GENERIC" */
+/* 4 bytes of cfFormat */
+
+OLESTATUS FARINTERNAL GenRelease (LPOBJECT_GEN);
+OLESTATUS FARINTERNAL GenSaveToStream (LPOBJECT_GEN, LPOLESTREAM);
+OLESTATUS FARINTERNAL GenEqual (LPOBJECT_GEN, LPOBJECT_GEN);
+OLESTATUS FARINTERNAL GenCopy (LPOBJECT_GEN);
+OLESTATUS FARINTERNAL GenQueryBounds (LPOBJECT_GEN, LPRECT);
+OLESTATUS FARINTERNAL GenGetData (LPOBJECT_GEN, OLECLIPFORMAT, LPHANDLE);
+OLESTATUS FARINTERNAL GenSetData (LPOBJECT_GEN, OLECLIPFORMAT, HANDLE);
+OLESTATUS FARINTERNAL GenChangeData (LPOBJECT_GEN, HANDLE, LPOLECLIENT, BOOL);
+OLESTATUS INTERNAL GenDeleteData (HANDLE);
+OLESTATUS FARINTERNAL GenQueryType (LPOLEOBJECT, LPLONG);
+OLESTATUS FARINTERNAL GenClone(LPOBJECT_GEN, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOBJECT_GEN FAR *);
+
+OLECLIPFORMAT FARINTERNAL GenEnumFormat (LPOBJECT_GEN, OLECLIPFORMAT);
+LPOBJECT_GEN INTERNAL GenCreateObject (HANDLE, LPOLECLIENT, BOOL,
+ LHCLIENTDOC, LPSTR, LONG);
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in ERROR.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FARINTERNAL ErrPlay (LPOLEOBJECT, WORD, BOOL, BOOL);
+OLESTATUS FARINTERNAL ErrShow (LPOLEOBJECT, BOOL);
+OLESTATUS FARINTERNAL ErrSetHostNames (LPOLEOBJECT, LPSTR, LPSTR);
+OLESTATUS FARINTERNAL ErrSetTargetDevice (LPOLEOBJECT, HANDLE);
+OLESTATUS FARINTERNAL ErrSetColorScheme (LPOLEOBJECT, LPLOGPALETTE);
+OLESTATUS FARINTERNAL ErrSetBounds (LPOLEOBJECT, LPRECT);
+OLESTATUS FARINTERNAL ErrQueryOpen (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrActivate (LPOLEOBJECT, WORD, BOOL, BOOL, HWND, LPRECT);
+OLESTATUS FARINTERNAL ErrClose (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrUpdate (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrReconnect (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrSetData (LPOLEOBJECT, OLECLIPFORMAT, HANDLE);
+OLESTATUS FARINTERNAL ErrQueryOutOfDate (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrGetUpdateOptions (LPOLEOBJECT, OLEOPT_UPDATE FAR *);
+OLESTATUS FARINTERNAL ErrSetUpdateOptions (LPOLEOBJECT, OLEOPT_UPDATE);
+LPVOID FARINTERNAL ErrQueryProtocol (LPOLEOBJECT, LPSTR);
+OLESTATUS FARINTERNAL ErrQueryRelease (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrAbort (LPOLEOBJECT);
+OLESTATUS FARINTERNAL ErrCopyFromLink (LPOLEOBJECT, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+OLESTATUS FARINTERNAL ErrRequestData (LPOLEOBJECT, OLECLIPFORMAT);
+OLESTATUS FARINTERNAL ErrExecute (LPOLEOBJECT, HANDLE, WORD);
+
+OLESTATUS FARINTERNAL ErrObjectConvert (LPOLEOBJECT, LPSTR, LPOLECLIENT, LHCLIENTDOC, LPSTR, LPOLEOBJECT FAR *);
+
+OLESTATUS FARINTERNAL ErrObjectLong (LPOLEOBJECT, WORD, LPLONG);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// //
+// Routines in DRAW.C //
+// //
+/////////////////////////////////////////////////////////////////////////////
+
+
+OLESTATUS FARINTERNAL DibDraw (LPOBJECT_DIB, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS FARINTERNAL BmDraw (LPOBJECT_BM, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS FARINTERNAL GenDraw (LPOBJECT_GEN, HDC, LPRECT, LPRECT, HDC);
+OLESTATUS FARINTERNAL MfDraw (LPOBJECT_MF, HDC, LPRECT, LPRECT, HDC);
+void INTERNAL MfInterruptiblePaint (LPOBJECT_MF, HDC);
+int FARINTERNAL MfCallbackFunc (HDC, LPHANDLETABLE, LPMETARECORD, int, BYTE FAR *);
diff --git a/private/mvdm/wow16/ole/client/utils.c b/private/mvdm/wow16/ole/client/utils.c
new file mode 100644
index 000000000..4ad1ebf00
--- /dev/null
+++ b/private/mvdm/wow16/ole/client/utils.c
@@ -0,0 +1,669 @@
+
+/****************************** Module Header ******************************\
+* Module Name: utils.c
+*
+* Purpose: Conatains all the utility routines
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, srinik (../../1990,91) Designed and coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "dll.h"
+
+#define KB_64 65536
+
+extern ATOM aPackage;
+extern OLEOBJECTVTBL vtblMF, vtblBM, vtblDIB, vtblGEN;
+
+// QuerySize API support
+DWORD dwObjSize = NULL;
+OLESTREAMVTBL dllStreamVtbl;
+OLESTREAM dllStream;
+
+
+#pragma alloc_text(_DDETEXT, UtilMemClr, MapStrToH, MapExtToClass, FileExists)
+
+BOOL PutStrWithLen(lpstream, lpbytes)
+LPOLESTREAM lpstream;
+LPSTR lpbytes;
+{
+ LONG len;
+
+ len = (LONG) lstrlen(lpbytes) + 1;
+
+ if (PutBytes (lpstream, (LPSTR)&len, sizeof(len)))
+ return TRUE;
+
+ return PutBytes(lpstream, lpbytes, len);
+
+}
+
+BOOL GetStrWithLen(lpstream, lpbytes)
+LPOLESTREAM lpstream;
+LPSTR lpbytes;
+{
+ if (GetBytes (lpstream, lpbytes, sizeof(LONG)))
+ return TRUE;
+
+ return GetBytes (lpstream, lpbytes + sizeof(LONG), (*(LONG FAR *)lpbytes));
+}
+
+ATOM GetAtomFromStream(lpstream)
+LPOLESTREAM lpstream;
+{
+ BOOL err = TRUE;
+ LONG len;
+ char str[MAX_STR+1];
+
+
+ if (GetBytes (lpstream, (LPSTR)&len, sizeof(len)))
+ return NULL;
+
+ if (len == 0)
+ return NULL;
+
+ if (GetBytes(lpstream, (LPSTR)str, len))
+ return NULL;
+
+ return GlobalAddAtom(str);
+
+}
+
+BOOL PutAtomIntoStream(lpstream, at)
+LPOLESTREAM lpstream;
+ATOM at;
+{
+ LONG len = 0;
+ char buf[MAX_STR + 1];
+
+ if (at == 0)
+ return (PutBytes (lpstream, (LPSTR)&len, sizeof(len)));
+
+
+ len = GlobalGetAtomName (at,(LPSTR)buf, MAX_STR) + 1;
+
+ if (PutBytes (lpstream, (LPSTR)&len, sizeof(len)))
+ return TRUE;
+
+ return PutBytes(lpstream, buf, len);
+}
+
+
+// DuplicateAtom: Bump the use count up on a global atom.
+
+ATOM FARINTERNAL DuplicateAtom (ATOM atom)
+{
+ char buffer[MAX_ATOM+1];
+
+ Puts("DuplicateAtom");
+
+ if (!atom)
+ return NULL;
+
+ GlobalGetAtomName (atom, buffer, MAX_ATOM);
+ return GlobalAddAtom (buffer);
+}
+
+
+
+BOOL GetBytes(lpstream, lpstr, len)
+LPOLESTREAM lpstream;
+LPSTR lpstr;
+LONG len;
+{
+
+ ASSERT (lpstream->lpstbl->Get , "stream get function is null");
+ return (((*lpstream->lpstbl->Get)(lpstream, lpstr, (DWORD)len)) != (DWORD)len);
+}
+
+
+BOOL PutBytes(lpstream, lpstr, len)
+LPOLESTREAM lpstream;
+LPSTR lpstr;
+LONG len;
+{
+
+ ASSERT (lpstream->lpstbl->Put , "stream get function is null");
+ return (((*lpstream->lpstbl->Put)(lpstream, lpstr, (DWORD)len)) != (DWORD)len);
+}
+
+
+BOOL FARINTERNAL UtilMemCmp (lpmem1, lpmem2, dwCount)
+LPSTR lpmem1;
+LPSTR lpmem2;
+DWORD dwCount;
+{
+ WORD HUGE * hpmem1;
+ WORD HUGE * hpmem2;
+ WORD FAR * lpwMem1;
+ WORD FAR * lpwMem2;
+ DWORD words;
+ DWORD bytes;
+
+ bytes = dwCount % 2;
+ words = dwCount >> 1; //* we should compare DWORDS
+ //* in the 32 bit version
+ if (dwCount <= KB_64) {
+ lpwMem1 = (WORD FAR *) lpmem1;
+ lpwMem2 = (WORD FAR *) lpmem2;
+
+ while (words--) {
+ if (*lpwMem1++ != *lpwMem2++)
+ return FALSE;
+ }
+
+ if (bytes) {
+ if (* (char FAR *) lpwMem1 != *(char FAR *) lpwMem2)
+ return FALSE;
+ }
+
+ }
+ else {
+ hpmem1 = (WORD HUGE *) lpmem1;
+ hpmem2 = (WORD HUGE *) lpmem2;
+
+ while (words--) {
+ if (*hpmem1++ != *hpmem2++)
+ return FALSE;
+ }
+
+ if (bytes) {
+ if (* (char HUGE *) hpmem1 != * (char HUGE *) hpmem2)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+void FARINTERNAL UtilMemCpy (lpdst, lpsrc, dwCount)
+LPSTR lpdst;
+LPSTR lpsrc;
+DWORD dwCount;
+{
+ WORD HUGE * hpdst;
+ WORD HUGE * hpsrc;
+ WORD FAR * lpwDst;
+ WORD FAR * lpwSrc;
+ DWORD words;
+ DWORD bytes;
+
+ bytes = dwCount % 2;
+ words = dwCount >> 1; //* we should compare DWORDS
+ //* in the 32 bit version
+ if (dwCount <= KB_64) {
+ lpwDst = (WORD FAR *) lpdst;
+ lpwSrc = (WORD FAR *) lpsrc;
+
+ while (words--)
+ *lpwDst++ = *lpwSrc++;
+
+ if (bytes)
+ * (char FAR *) lpwDst = * (char FAR *) lpwSrc;
+ }
+ else {
+ hpdst = (WORD HUGE *) lpdst;
+ hpsrc = (WORD HUGE *) lpsrc;
+
+ while (words--)
+ *hpdst++ = *hpsrc++;
+
+ if (bytes)
+ *(char HUGE *) hpdst = * (char HUGE *) hpsrc;
+ }
+}
+
+
+//DuplicateData: Duplicates a given Global data handle.
+HANDLE FARINTERNAL DuplicateGlobal (hdata, flags)
+HANDLE hdata;
+WORD flags;
+{
+ LPSTR lpdst = NULL;
+ LPSTR lpsrc = NULL;
+ HANDLE hdup = NULL;
+ DWORD size;
+ BOOL err = TRUE;
+
+ if (!hdata)
+ return NULL;
+
+ if(!(lpsrc = GlobalLock (hdata)))
+ return NULL;
+
+ hdup = GlobalAlloc (flags, (size = GlobalSize(hdata)));
+
+ if(!(lpdst = GlobalLock (hdup)))
+ goto errRtn;;
+
+ err = FALSE;
+ UtilMemCpy (lpdst, lpsrc, size);
+
+errRtn:
+ if(lpsrc)
+ GlobalUnlock (hdata);
+
+ if(lpdst)
+ GlobalUnlock (hdup);
+
+ if (err && hdup) {
+ GlobalFree (hdup);
+ hdup = NULL;
+ }
+
+ return hdup;
+}
+
+
+BOOL FARINTERNAL CmpGlobals (hdata1, hdata2)
+HANDLE hdata1;
+HANDLE hdata2;
+{
+ LPSTR lpdata1 = NULL;
+ LPSTR lpdata2 = NULL;
+ DWORD size1;
+ DWORD size2;
+ BOOL retval = FALSE;
+
+
+ size1 = GlobalSize (hdata1);
+ size2 = GlobalSize (hdata2);
+
+ if (size1 != size2)
+ return FALSE;
+
+ if (!(lpdata1 = GlobalLock (hdata1)))
+ goto errRtn;
+
+ if (!(lpdata2 = GlobalLock (hdata2)))
+ goto errRtn;
+
+ retval = UtilMemCmp (lpdata1, lpdata2, size1);
+
+errRtn:
+ if (lpdata1)
+ GlobalUnlock (hdata1);
+
+ if (lpdata2)
+ GlobalUnlock (hdata2);
+
+ return retval;
+}
+
+
+int FARINTERNAL GlobalGetAtomLen (aItem)
+ATOM aItem;
+{
+ // !!! Change this
+ char buf[MAX_STR];
+
+ if (!aItem)
+ return NULL;
+
+ return (GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR));
+
+}
+
+
+BOOL FARINTERNAL MapExtToClass (lptemplate, lpbuf, len)
+LPSTR lptemplate;
+LPSTR lpbuf;
+int len;
+{
+ LONG cb;
+
+ while (*lptemplate && *lptemplate != '.')
+ lptemplate++;
+
+ cb = len;
+ if (*(lptemplate+1) == NULL)
+ return FALSE;
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, lptemplate, lpbuf, &cb))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+// Get exe name from aClass and set it as aServer
+void INTERNAL SetExeAtom (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char key[MAX_STR];
+
+ // if old link object assume the class same as the exe file name.
+ if (lpobj->bOldLink)
+ lpobj->aServer = DuplicateAtom (lpobj->app);
+ else {
+ if (GlobalGetAtomName (lpobj->app, key, sizeof(key)))
+ lpobj->aServer = GetAppAtom ((LPSTR)key);
+ }
+}
+
+
+ATOM FARINTERNAL GetAppAtom (lpclass)
+LPSTR lpclass;
+{
+ char buf1[MAX_STR];
+
+
+ if (!QueryApp (lpclass, PROTOCOL_EDIT, buf1)) {
+ return NULL;
+ }
+
+ return GlobalAddAtom ((LPSTR)buf1);
+}
+
+
+BOOL FARINTERNAL QueryVerb (lpobj, verb, lpbuf, cbmax)
+LPOBJECT_LE lpobj;
+WORD verb;
+LPSTR lpbuf;
+LONG cbmax;
+{
+ LONG cb = MAX_STR;
+ char key[MAX_STR];
+ // do not need 256 bytes buffer
+ char class[MAX_STR];
+ int len;
+
+ if (!GlobalGetAtomName (lpobj->app, (LPSTR)class, sizeof(class)))
+ return FALSE;
+
+ lstrcpy (key, (LPSTR)class);
+ lstrcat (key, "\\protocol\\StdFileEditing\\verb\\");
+ len = lstrlen (key);
+ key [len++] = (char) ('0' + verb);
+ key [len++] = 0;
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, lpbuf, &cbmax))
+ return FALSE;
+ return TRUE;
+}
+
+
+
+
+BOOL QueryApp (lpclass, lpprotocol, lpbuf)
+LPSTR lpclass;
+LPSTR lpprotocol;
+LPSTR lpbuf;
+{
+ LONG cb = MAX_STR;
+ char key[MAX_STR];
+
+ lstrcpy (key, lpclass);
+ lstrcat (key, "\\protocol\\");
+ lstrcat (key, lpprotocol);
+ lstrcat (key, "\\server");
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, lpbuf, &cb))
+ return FALSE;
+ return TRUE;
+}
+
+
+HANDLE MapStrToH (lpstr)
+LPSTR lpstr;
+{
+
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+
+ hdata = GlobalAlloc (GMEM_DDESHARE, lstrlen (lpstr) + 1);
+ if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+ lstrcpy (lpdata, lpstr);
+ GlobalUnlock (hdata);
+ return hdata;
+
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+ return NULL;
+}
+
+
+HANDLE FARINTERNAL CopyData (lpsrc, dwBytes)
+LPSTR lpsrc;
+DWORD dwBytes;
+{
+ HANDLE hnew;
+ LPSTR lpnew;
+ BOOL retval = FALSE;
+
+ if (hnew = GlobalAlloc (GMEM_MOVEABLE, dwBytes)){
+ if (lpnew = GlobalLock (hnew)){
+ UtilMemCpy (lpnew, lpsrc, dwBytes);
+ GlobalUnlock (hnew);
+ return hnew;
+ }
+ else
+ GlobalFree (hnew);
+ }
+
+ return NULL;
+}
+
+void UtilMemClr (pstr, size)
+PSTR pstr;
+WORD size;
+{
+
+ while (size--)
+ *pstr++ = 0;
+
+}
+
+
+OLESTATUS FAR PASCAL ObjQueryName (lpobj, lpBuf, lpcbBuf)
+LPOLEOBJECT lpobj;
+LPSTR lpBuf;
+WORD FAR * lpcbBuf;
+{
+ if (lpobj->ctype != CT_LINK && lpobj->ctype != CT_EMBEDDED
+ && lpobj->ctype != CT_STATIC)
+ return OLE_ERROR_OBJECT;
+
+ PROBE_WRITE(lpBuf);
+ if (!*lpcbBuf)
+ return OLE_ERROR_SIZE;
+
+ if (!CheckPointer(lpBuf+*lpcbBuf-1, WRITE_ACCESS))
+ return OLE_ERROR_SIZE;
+
+ ASSERT(lpobj->aObjName, "object name ATOM is NULL\n");
+ *lpcbBuf = GlobalGetAtomName (lpobj->aObjName, lpBuf, *lpcbBuf);
+ return OLE_OK;
+}
+
+
+OLESTATUS FAR PASCAL ObjRename (lpobj, lpNewName)
+LPOLEOBJECT lpobj;
+LPSTR lpNewName;
+{
+ if (lpobj->ctype != CT_LINK && lpobj->ctype != CT_EMBEDDED
+ && lpobj->ctype != CT_STATIC)
+ return OLE_ERROR_OBJECT;
+
+ PROBE_READ(lpNewName);
+ if (!lpNewName[0])
+ return OLE_ERROR_NAME;
+
+ if (lpobj->aObjName)
+ GlobalDeleteAtom (lpobj->aObjName);
+ lpobj->aObjName = GlobalAddAtom (lpNewName);
+ return OLE_OK;
+}
+
+
+
+
+BOOL QueryHandler(cfFormat)
+WORD cfFormat;
+{
+ HANDLE hInfo = NULL;
+ LPSTR lpInfo = NULL;
+ BOOL fRet = FALSE, fOpen = FALSE;
+ LONG cb = MAX_STR;
+ char str[MAX_STR];
+ HKEY hKey;
+
+ // we don't have the client app window handle, use the screen handle
+ fOpen = OpenClipboard (NULL);
+
+ if (!(hInfo = GetClipboardData (cfFormat)))
+ goto errRtn;
+
+ if (!(lpInfo = GlobalLock(hInfo)))
+ goto errRtn;
+
+ // First string of lpInfo is CLASS. See whether any handler is installed
+ // for this class.
+
+ lstrcpy (str, lpInfo);
+ lstrcat (str, "\\protocol\\StdFileEditing\\handler");
+ if (RegOpenKey (HKEY_CLASSES_ROOT, str, &hKey))
+ goto errRtn;
+ RegCloseKey (hKey);
+ fRet = TRUE;
+
+errRtn:
+ if (lpInfo)
+ GlobalUnlock (hInfo);
+
+ if (fOpen)
+ CloseClipboard();
+ return fRet;
+}
+
+OLESTATUS INTERNAL FileExists (lpobj)
+LPOBJECT_LE lpobj;
+{
+ char filename[MAX_STR];
+ OFSTRUCT ofstruct;
+
+ if (!GlobalGetAtomName (lpobj->topic, filename, MAX_STR))
+ return OLE_ERROR_MEMORY;
+
+ // For package with link we append "/LINK" to the filename. We don't want
+ // to check for it's existence here.
+ if (lpobj->app != aPackage) {
+ // when OF_EXIST is specified, file is opened and closed immediately
+ if (OpenFile (filename, &ofstruct, OF_EXIST) == -1)
+ return OLE_ERROR_OPEN;
+ }
+
+ return OLE_OK;
+}
+
+
+BOOL FARINTERNAL UtilQueryProtocol (lpobj, lpprotocol)
+LPOBJECT_LE lpobj;
+LPSTR lpprotocol;
+{
+ char buf[MAX_STR];
+ ATOM aExe;
+
+ if (!GlobalGetAtomName (lpobj->app, (LPSTR) buf, MAX_STR))
+ return FALSE;
+
+ if (!QueryApp (buf, lpprotocol, (LPSTR) buf))
+ return FALSE;
+
+ aExe = GlobalAddAtom (buf);
+ if (aExe)
+ GlobalDeleteAtom (aExe);
+ if (aExe != lpobj->aServer)
+ return FALSE;
+
+ return TRUE;
+}
+
+WORD FARINTERNAL FarCheckPointer (lp, iAccessType)
+LPVOID lp;
+int iAccessType;
+{
+ return (CheckPointer (lp, iAccessType));
+}
+
+
+DWORD PASCAL FAR DllPut (lpstream, lpstr, dwSize)
+LPOLESTREAM lpstream;
+LPSTR lpstr;
+DWORD dwSize;
+{
+ dwObjSize += dwSize;
+ return dwSize;
+}
+
+
+
+OLESTATUS FARINTERNAL ObjQueryType (lpobj, lptype)
+LPOLEOBJECT lpobj;
+LPLONG lptype;
+{
+ Puts("ObjQueryType");
+
+ if (lpobj->ctype != CT_STATIC)
+ return OLE_ERROR_OBJECT;
+
+ *lptype = lpobj->ctype;
+ return OLE_OK;
+}
+
+OLESTATUS FARINTERNAL ObjQuerySize (lpobj, lpdwSize)
+LPOLEOBJECT lpobj;
+DWORD FAR * lpdwSize;
+{
+ Puts("ObjQuerySize");
+
+ *lpdwSize = dwObjSize = NULL;
+
+ if ((*lpobj->lpvtbl->SaveToStream) (lpobj, &dllStream) == OLE_OK) {
+ *lpdwSize = dwObjSize;
+ return OLE_OK;
+ }
+
+ return OLE_ERROR_BLANK;
+}
+
+BOOL FARINTERNAL IsObjectBlank (lpobj)
+LPOBJECT_LE lpobj;
+{
+ LPOLEOBJECT lpPictObj;
+ BOOL retval;
+
+ // Cleaner way is to provide a method like QueryBlank()
+
+ if (!lpobj->hnative)
+ return TRUE;
+
+ if (!(lpPictObj = lpobj->lpobjPict))
+ return FALSE;
+
+ if (lpPictObj->lpvtbl == (LPOLEOBJECTVTBL)&vtblMF)
+ retval = (BOOL) (((LPOBJECT_MF)lpPictObj)->hmfp);
+ else if (lpPictObj->lpvtbl == (LPOLEOBJECTVTBL)&vtblBM)
+ retval = (BOOL) (((LPOBJECT_BM)lpPictObj)->hBitmap);
+ if (lpPictObj->lpvtbl == (LPOLEOBJECTVTBL)&vtblDIB)
+ retval = (BOOL) (((LPOBJECT_DIB)lpPictObj)->hDIB);
+ if (lpPictObj->lpvtbl == (LPOLEOBJECTVTBL)&vtblGEN)
+ retval = (BOOL) (((LPOBJECT_GEN)lpPictObj)->hData);
+
+ return retval;
+}
diff --git a/private/mvdm/wow16/ole/server/block.c b/private/mvdm/wow16/ole/server/block.c
new file mode 100644
index 000000000..4d0646420
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/block.c
@@ -0,0 +1,309 @@
+/****************************** Module Header ******************************\
+* Module Name: Block.c
+*
+* Purpose: Includes OleServerBlock(), OleServerUnblock() and related routines.
+*
+* Created: Dec. 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Srinik (../12/1990) Designed, coded
+*
+\***************************************************************************/
+
+
+#include "cmacs.h"
+#include "windows.h"
+#include "dde.h"
+#include "ole.h"
+#include "srvr.h"
+
+
+OLESTATUS FAR PASCAL OleBlockServer (lhsrvr)
+LHSERVER lhsrvr;
+{
+ LPSRVR lpsrvr;
+
+ if (!CheckServer (lpsrvr = (LPSRVR) lhsrvr))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_BLOCK(lpsrvr);
+ lpsrvr->bBlock = TRUE;
+ return OLE_OK;
+}
+
+
+// On return from this routine, if *lpStatus is TRUE it means that more
+// messages are to be unblocked.
+
+OLESTATUS FAR PASCAL OleUnblockServer (lhsrvr, lpStatus)
+LHSERVER lhsrvr;
+BOOL FAR * lpStatus;
+{
+ HANDLE hq;
+ PQUE pq;
+ LPSRVR lpsrvr;
+
+ if (!CheckServer (lpsrvr = (LPSRVR) lhsrvr))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_WRITE(lpStatus);
+
+ *lpStatus = lpsrvr->bBlock;
+ if (hq = lpsrvr->hqHead) {
+ if (!(pq = (PQUE) LocalLock (hq)))
+ return OLE_ERROR_MEMORY;
+ lpsrvr->bBlockedMsg = TRUE;
+ lpsrvr->hqHead = pq->hqNext;
+ SendMessage (pq->hwnd, pq->msg, pq->wParam, pq->lParam);
+ LocalUnlock (hq);
+ LocalFree (hq);
+
+ // Server could've got freed up as a result of the above SendMessage
+ // Validate server handle before trying to access it.
+ if (CheckServer (lpsrvr)) {
+ lpsrvr->bBlockedMsg = FALSE;
+
+ if (!lpsrvr->hqHead) {
+ lpsrvr->hqTail = NULL;
+ *lpStatus = lpsrvr->bBlock = FALSE;
+ }
+ }
+ else {
+ *lpStatus = FALSE;
+ }
+ }
+ else {
+ *lpStatus = lpsrvr->bBlock = FALSE;
+ }
+
+ return OLE_OK;
+}
+
+
+BOOL INTERNAL AddMessage (hwnd, msg, wParam, lParam, wType)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+int wType;
+{
+ LPSRVR lpsrvr;
+ HANDLE hq = NULL;
+ PQUE pq = NULL, pqTmp = NULL;
+ BOOL bBlocked = TRUE;
+
+ if ((msg <= WM_DDE_INITIATE) || (msg > WM_DDE_LAST))
+ return FALSE;
+
+
+ if (!(lpsrvr = (LPSRVR) GetWindowLong ((wType == WT_DOC) ? GetParent (hwnd) : hwnd, 0)))
+ return FALSE;
+
+ if (lpsrvr->bBlockedMsg || !lpsrvr->bBlock)
+ return FALSE;
+
+#ifdef LATER
+ if ((msg == WM_DDE_INITIATE) && (lpsrvr->useFlags == OLE_SERVER_MULTI))
+ return TRUE;
+#endif
+
+ // Create a queue node and fill up with data
+
+ if (!(hq = LocalAlloc (LMEM_MOVEABLE, sizeof(QUE))))
+ goto errRet;
+
+ if (!(pq = (PQUE) LocalLock (hq)))
+ goto errRet;
+
+ pq->hwnd = hwnd;
+ pq->msg = msg;
+ pq->wParam = wParam;
+ pq->lParam = lParam;
+ pq->hqNext = NULL;
+ LocalUnlock (hq);
+
+ // Now we got a node that we can add to the queue
+
+ if (!lpsrvr->hqHead) {
+ // Queue is empty.
+#ifdef FIREWALLS
+ ASSERT (!lpsrvr->hqTail, "Tail is unexpectedly non NULL")
+#endif
+ lpsrvr->hqHead = lpsrvr->hqTail = hq;
+ }
+ else {
+ if (!(pqTmp = (PQUE) LocalLock (lpsrvr->hqTail)))
+ goto errRet;
+ pqTmp->hqNext = hq;
+ LocalUnlock(lpsrvr->hqTail);
+ lpsrvr->hqTail = hq;
+ }
+
+ return TRUE;
+
+errRet:
+
+ if (pq)
+ LocalUnlock (hq);
+
+ if (hq)
+ LocalFree (hq);
+
+ while (bBlocked && !OleUnblockServer ((LHSERVER) lpsrvr, &bBlocked))
+ ;
+
+ return FALSE;
+}
+
+
+
+// dispatches the queued message, till all the messages are posted
+// does yielding if necessary. if bPeek is true, may allow some of
+// incoming messages to get in.
+
+
+BOOL INTERNAL UnblockPostMsgs (hwnd, bPeek)
+HWND hwnd;
+BOOL bPeek;
+{
+ HANDLE hq = NULL;
+ PQUE pq = NULL;
+ LPSRVR lpsrvr;
+ HWND hwndTmp;
+
+ // get the parent windows
+ while (hwndTmp = GetParent (hwnd))
+ hwnd = hwndTmp;
+
+ lpsrvr = (LPSRVR) GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ ASSERT (lpsrvr, "No server window handle in server window");
+ ASSERT (lpsrvr->hqPostHead, "Unexpectedly blocked queue is empty");
+#endif
+
+
+ while (hq = lpsrvr->hqPostHead) {
+
+ if (!(pq = (PQUE) LocalLock (hq))) {
+
+#ifdef FIREWALLS
+ ASSERT (FALSE, "Local lock failed for blocked messages");
+#endif
+ break;
+ }
+ if (IsWindowValid (pq->hwnd)) {
+ if (!PostMessage (pq->hwnd, pq->msg, pq->wParam, pq->lParam)) {
+ LocalUnlock (hq);
+ break;
+ }
+ }
+
+ lpsrvr->hqPostHead = pq->hqNext;
+ LocalUnlock (hq);
+ LocalFree (hq);
+ }
+
+
+ if (!lpsrvr->hqPostHead)
+ lpsrvr->hqPostTail = NULL;
+
+ return TRUE;
+}
+
+
+// Moves a message which can not be posted to a server to
+// the internal queue. We use this when we have to enumerate
+// the properties. When we change the properties stuff to
+// some other form, this may not be necassry.
+
+BOOL INTERNAL BlockPostMsg (hwnd, msg, wParam, lParam)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+{
+ LPSRVR lpsrvr;
+ HANDLE hq = NULL;
+ PQUE pq = NULL, pqTmp = NULL;
+ HWND hwndTmp;
+ HWND hwndParent;
+
+ hwndParent = (HWND)wParam;
+ // get the parent windows
+ while (hwndTmp = GetParent ((HWND)hwndParent))
+ hwndParent = hwndTmp;
+
+ lpsrvr = (LPSRVR) GetWindowLong (hwndParent, 0);
+
+#ifdef FIREWALLS
+ ASSERT (lpsrvr, "No server window handle in server window");
+#endif
+
+ // Create a queue node and fill up with data
+
+ if (!(hq = LocalAlloc (LMEM_MOVEABLE, sizeof(QUE))))
+ goto errRet;
+
+ if (!(pq = (PQUE) LocalLock (hq)))
+ goto errRet;
+
+ pq->hwnd = hwnd;
+ pq->msg = msg;
+ pq->wParam = wParam;
+ pq->lParam = lParam;
+ pq->hqNext = NULL;
+ LocalUnlock (hq);
+
+ // Now we got a node that we can add to the queue
+
+ if (!lpsrvr->hqPostHead) {
+ // Queue is empty.
+#ifdef FIREWALLS
+ ASSERT (!lpsrvr->hqPostTail, "Tail is unexpectedly non NULL")
+#endif
+ lpsrvr->hqPostHead = lpsrvr->hqPostTail = hq;
+
+ // create a timer.
+ if (!SetTimer (lpsrvr->hwnd, 1, 100, NULL))
+ return FALSE;
+
+ }
+ else {
+ if (!(pqTmp = (PQUE) LocalLock (lpsrvr->hqPostTail)))
+ goto errRet;
+ pqTmp->hqNext = hq;
+ LocalUnlock(lpsrvr->hqPostTail);
+ lpsrvr->hqPostTail = hq;
+ }
+
+ return TRUE;
+
+errRet:
+
+ if (pq)
+ LocalUnlock (hq);
+
+ if (hq)
+ LocalFree (hq);
+ return FALSE;
+}
+
+
+BOOL INTERNAL IsBlockQueueEmpty (hwnd)
+HWND hwnd;
+{
+
+ LPSRVR lpsrvr;
+ HWND hwndTmp;
+
+ // get the parent windows
+ while (hwndTmp = GetParent ((HWND)hwnd))
+ hwnd= hwndTmp;
+ lpsrvr = (LPSRVR) GetWindowLong (hwnd, 0);
+ return (!lpsrvr->hqPostHead);
+
+
+}
diff --git a/private/mvdm/wow16/ole/server/doc.c b/private/mvdm/wow16/ole/server/doc.c
new file mode 100644
index 000000000..5716f4d35
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/doc.c
@@ -0,0 +1,1091 @@
+/****************************** Module Header ******************************\
+* Module Name: Doc.c Document Main module
+*
+* Purpose: Includes All the document communication related routines.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded
+*
+\***************************************************************************/
+
+#include "cmacs.h"
+#include "windows.h"
+#include "ole.h"
+#include "dde.h"
+#include "srvr.h"
+
+extern ATOM cfBinary;
+extern ATOM aStdClose;
+extern ATOM aStdShowItem;
+extern ATOM aStdDoVerbItem;
+extern ATOM aStdDocName;
+extern ATOM aTrue;
+extern ATOM aFalse;
+
+extern FARPROC lpTerminateDocClients;
+extern FARPROC lpSendRenameMsg;
+extern FARPROC lpFindItemWnd;
+extern FARPROC lpEnumForTerminate;
+
+extern HANDLE hdllInst;
+extern HANDLE hddeRename;
+extern HWND hwndRename;
+
+
+extern BOOL fAdviseSaveDoc;
+
+// ### Do we have to create a seperate window for each doc conversation.
+// EDF thinks so.
+
+/***************************** Public Function ****************************\
+*
+* OLESTATUS FAR PASCAL OleRegisterServerDoc (lhsrvr, lpdocname, lpoledoc, lplhdoc)
+*
+* OleRegisterServerDoc: Registers the Document with the server lib.
+*
+* Parameters:
+* 1. Server long handle(server with which the document should
+* be registered)
+* 2. Document name.
+* 3. Handle to the doc of the server app (private to the server app).
+* 4. Ptr for returning the Doc handle of the lib (private to the lib).
+*
+* return values:
+* returns OLE_OK if the server is successfully registered .
+* else returns the corresponding error.
+*
+* History:
+* Raor: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRegisterServerDoc (lhsrvr, lpdocname, lpoledoc, lplhdoc)
+LHSRVR lhsrvr; // handle we passed back as part of registration.
+LPSTR lpdocname; // document name
+LPOLESERVERDOC lpoledoc; // Private doc handle of the server app.
+LHDOC FAR * lplhdoc; // where we will be passing our doc private handle
+{
+
+ LPSRVR lpsrvr = NULL;
+ LPDOC lpdoc = NULL;
+ HANDLE hdoc = NULL;
+
+
+ Puts ("OleRegisterServerDoc");
+
+ if (!CheckServer (lpsrvr = (LPSRVR)lhsrvr))
+ return OLE_ERROR_HANDLE;
+
+ // server's termination has already started.
+ if (lpsrvr->bTerminate)
+ return OLE_ERROR_TERMINATE;
+
+ PROBE_READ(lpdocname);
+ PROBE_WRITE(lplhdoc);
+
+ // we are using the null from inside the server lib
+ if (lpoledoc)
+ PROBE_WRITE(lpoledoc);
+
+ hdoc = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (DOC));
+
+ if (!(hdoc && (lpdoc = (LPDOC)GlobalLock (hdoc))))
+ goto errReturn;
+
+ // set the signature, handle and the doc atom.
+ lpdoc->sig[0] = 'S';
+ lpdoc->sig[1] = 'D';
+ lpdoc->hdoc = hdoc;
+ lpdoc->aDoc = GlobalAddAtom (lpdocname);
+ lpdoc->lpoledoc = lpoledoc;
+
+
+ if (!(lpdoc->hwnd = CreateWindow ("DocWndClass", "Doc",
+ WS_CHILD,0,0,0,0,lpsrvr->hwnd,NULL, hdllInst, NULL)))
+ goto errReturn;
+
+ // save the ptr to the struct in the window.
+ SetWindowLong (lpdoc->hwnd, 0, (LONG)lpdoc);
+ SetWindowWord (lpdoc->hwnd, WW_LE, WC_LE);
+ SetWindowWord (lpdoc->hwnd, WW_HANDLE,
+ (WORD) (GetWindowWord (lpsrvr->hwnd, WW_HANDLE)));
+ *lplhdoc = (LONG)lpdoc;
+
+ return OLE_OK;
+
+errReturn:
+ if (lpdoc){
+ if (lpdoc->hwnd)
+ DestroyWindow (lpsrvr->hwnd);
+
+ if (lpdoc->aDoc)
+ GlobalDeleteAtom (lpdoc->aDoc);
+
+ GlobalUnlock(hdoc);
+ }
+
+ if (hdoc)
+ GlobalFree (hdoc);
+
+ return OLE_ERROR_MEMORY;
+}
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRevokeServerDoc (lhdoc)
+*
+* OleRevokeServerDoc: Unregisters the document which has been registered.
+*
+* Parameters:
+* 1. DLL Doc handle.
+*
+* return values:
+* returns OLE_OK if the document is successfully unregisterd.
+* ( It is Ok for the app to free the associated space).
+* If the unregistration is intiated, returns OLE_STARTED.
+* Calls the Doc class release entry point when the doc
+* can be released. App should wait till the Release is called
+*
+* History:
+* Raor: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRevokeServerDoc (lhdoc)
+LHDOC lhdoc;
+{
+ HWND hwndSrvr;
+ LPSRVR lpsrvr;
+ HWND hwndDoc;
+ LPDOC lpdoc;
+
+ Puts ("OleRevokeServerDoc");
+
+ if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
+ return OLE_ERROR_HANDLE;
+
+ if (lpdoc->bTerminate && lpdoc->termNo)
+ return OLE_WAIT_FOR_RELEASE;
+
+ // ### this code is very similar to the srvr code.
+ // we should optimize.
+
+ hwndDoc = lpdoc->hwnd;
+
+#ifdef FIREWALLS
+ ASSERT (hwndDoc, "No doc window")
+#endif
+
+ hwndSrvr = GetParent (hwndDoc);
+ lpsrvr = (LPSRVR) GetWindowLong (hwndSrvr, 0);
+#ifdef FIREWALLS
+ ASSERT (hwndSrvr, "No srvr window")
+ ASSERT (lpsrvr, "No srvr structure")
+#endif
+
+ // delete all the items(objects) for this doc
+ DeleteAllItems (lpdoc->hwnd);
+
+ // we are terminating.
+ lpdoc->bTerminate = TRUE;
+ lpdoc->termNo = 0;
+
+ // send ack if Revoke is done as a result of StdClose
+ if (lpdoc->fAckClose) {
+ // Post the acknowledge to the client
+ if (!PostMessageToClient (lpdoc->hwndClose, WM_DDE_ACK, lpdoc->hwnd,
+ MAKELONG (0x8000, lpdoc->hDataClose)))
+ // if the window died or post failed, delete the atom.
+ GlobalFree (lpdoc->hDataClose);
+ }
+
+ // Post termination for each of the doc clients.
+ EnumProps (hwndDoc, lpTerminateDocClients);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (hwndDoc, TRUE);
+
+#ifdef WAIT_DDE
+ if (lpdoc->termNo)
+ WaitForTerminate((LPSRVR)lpdoc);
+#endif
+
+ return ReleaseDoc (lpdoc);
+}
+
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRenameServerDoc (lhdoc, lpNewName)
+*
+* OleRenameServerDoc: Changes the name of the document
+*
+* Parameters:
+* 1. DLL Doc handle.
+* 2. New name for document
+*
+* return values:
+* returns OLE_OK if the document is successfully renamed
+*
+* History:
+* Srinik: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRenameServerDoc (lhdoc, lpNewName)
+LHDOC lhdoc;
+LPSTR lpNewName;
+{
+ LPDOC lpdoc;
+ OLESTATUS retVal = OLE_OK;
+ HANDLE hdata;
+ HWND hStdWnd;
+
+ if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
+ return OLE_ERROR_HANDLE;
+
+ PROBE_READ(lpNewName);
+
+ if (!(hdata = MakeGlobal (lpNewName)))
+ return OLE_ERROR_MEMORY;
+
+ if (lpdoc->aDoc)
+ GlobalDeleteAtom (lpdoc->aDoc);
+ lpdoc->aDoc = GlobalAddAtom (lpNewName);
+
+ // if StdDocName item is present send rename to relevant clients
+ if (hStdWnd = SearchItem (lpdoc, (LPSTR) MAKEINTATOM(aStdDocName))) {
+ if (!MakeDDEData (hdata, (int)cfBinary, (LPHANDLE)&hddeRename,FALSE))
+ retVal = OLE_ERROR_MEMORY;
+ else {
+ EnumProps (hStdWnd, lpSendRenameMsg);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (hStdWnd, FALSE);
+ GlobalFree (hddeRename);
+
+ }
+ }
+
+
+ hwndRename = hStdWnd;
+ // Post termination for each of the doc clients.
+ EnumProps (lpdoc->hwnd, lpEnumForTerminate);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (lpdoc->hwnd, TRUE);
+
+ // If it was an embedded object, from now on it won't be
+ lpdoc->fEmbed = FALSE;
+
+ if (!hStdWnd || retVal != OLE_OK)
+ GlobalFree(hdata);
+
+ // Do link manager stuff
+ return retVal;
+}
+
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleSavedServerDoc (lhdoc)
+*
+* OleSavedServerDoc: Changes the name of the document
+*
+* Parameters:
+* 1. DLL Doc handle.
+*
+* return values:
+* returns OLE_OK if the link manager is successfully notified
+*
+* History:
+* Srinik: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleSavedServerDoc (lhdoc)
+LHDOC lhdoc;
+{
+ LPDOC lpdoc;
+
+ if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
+ return OLE_ERROR_HANDLE;
+
+ fAdviseSaveDoc = TRUE;
+ EnumChildWindows (lpdoc->hwnd, lpFindItemWnd,
+ MAKELONG (NULL, ITEM_SAVED));
+
+ if (lpdoc->fEmbed && !fAdviseSaveDoc)
+ return OLE_ERROR_CANT_UPDATE_CLIENT;
+
+ return OLE_OK;
+}
+
+
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRevertServerDoc (lhdoc)
+*
+* OleRevertServerDoc: Changes the name of the document
+*
+* Parameters:
+* 1. DLL Doc handle.
+*
+* return values:
+* returns OLE_OK if the link manager has been successfully informed
+*
+* History:
+* Srinik: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRevertServerDoc (lhdoc)
+LHDOC lhdoc;
+{
+ LPDOC lpdoc;
+
+ if (!CheckServerDoc (lpdoc = (LPDOC)lhdoc))
+ return OLE_ERROR_HANDLE;
+
+ return OLE_OK;
+}
+
+
+
+// TerminateDocClients: Call back for the document window for
+// enumerating all the clients. Posts terminate for each of
+// the clients.
+
+BOOL FAR PASCAL TerminateDocClients (hwnd, lpstr, hdata)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hdata;
+{
+ LPDOC lpdoc;
+
+ lpdoc = (LPDOC)GetWindowLong (hwnd, 0);
+ if (IsWindowValid ((HWND)hdata)){
+ lpdoc->termNo++;
+ // irrespective of the post, incremet the count, so
+ // that client does not die.
+ PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, hwnd, NULL);
+ }
+ else
+ ASSERT(FALSE, "TERMINATE: Client's Doc channel is missing");
+ return TRUE;
+}
+
+
+// ReleaseDoc: If there are no more matching terminates pending
+// Call the server for its release. (Server might be waiting for the
+// docs to be terminated. Called thru OleRevokeServer).
+
+
+int INTERNAL ReleaseDoc (lpdoc)
+LPDOC lpdoc;
+{
+
+ HWND hwndSrvr;
+ HANDLE hdoc;
+ LPSRVR lpsrvr;
+
+
+ // release srvr is called only when everything is
+ // cleaned and srvr app can post WM_QUIT.
+
+ if (lpdoc->bTerminate && lpdoc->termNo)
+ return OLE_WAIT_FOR_RELEASE;
+
+ // Call Release for the app to release its space.
+
+
+ if (lpdoc->lpoledoc){
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpdoc->lpoledoc, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOC")
+ else if (!CheckPointer (lpdoc->lpoledoc->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
+ else
+ ASSERT (lpdoc->lpoledoc->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+ (*lpdoc->lpoledoc->lpvtbl->Release) (lpdoc->lpoledoc);
+
+ }
+
+ if (lpdoc->aDoc) {
+ GlobalDeleteAtom (lpdoc->aDoc);
+ lpdoc->aDoc = NULL;
+ }
+
+ hwndSrvr = GetParent (lpdoc->hwnd);
+ DestroyWindow (lpdoc->hwnd);
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwndSrvr, 0);
+
+ // if the server is waiting for us, inform the server
+ // we are done
+ if (!lpsrvr->bTerminate) {
+ // if we are not in terminate mode, then send advise to the server
+ // if server can be revoked. raor (04/09)
+
+ if (QueryRelease (lpsrvr)){
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVER")
+ else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl,
+ WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+
+ (*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr);
+ }
+
+ } else
+ ReleaseSrvr (lpsrvr);
+
+ GlobalUnlock (hdoc = lpdoc->hdoc);
+ GlobalFree (hdoc);
+
+ return OLE_OK;
+}
+
+
+//RevokeAllDocs : revokes all the documents attached to a given
+//server.
+
+int INTERNAL RevokeAllDocs (lpsrvr)
+LPSRVR lpsrvr;
+{
+
+ HWND hwnd;
+ HWND hwndnext;
+
+ hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
+
+ // Go thru each of the child windows and revoke the corresponding
+ // document. Doc windows are child windows for the server window.
+
+ while (hwnd){
+ // sequence is important
+ hwndnext = GetWindow (hwnd, GW_HWNDNEXT);
+ OleRevokeServerDoc ((LHDOC)GetWindowLong (hwnd, 0));
+ hwnd = hwndnext;
+ }
+ return OLE_OK;
+}
+
+
+
+// FindDoc: Given a document, searches for the document
+// in the given server document tree. returns true if the
+// document is available.
+
+
+LPDOC INTERNAL FindDoc (lpsrvr, lpdocname)
+LPSRVR lpsrvr;
+LPSTR lpdocname;
+{
+
+ ATOM aDoc;
+ HWND hwnd;
+ LPDOC lpdoc;
+
+ aDoc = (ATOM)GlobalFindAtom (lpdocname);
+ hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
+
+ while (hwnd){
+ lpdoc = (LPDOC)GetWindowLong (hwnd, 0);
+ if (lpdoc->aDoc == aDoc)
+ return lpdoc;
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ return NULL;
+}
+
+
+
+// DocWndProc: document window procedure.
+// ### We might be able to merge this code with
+// the server window proc.
+
+
+long FAR PASCAL DocWndProc (hwnd, msg, wParam, lParam)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+{
+
+ LPDOC lpdoc;
+ WORD status = NULL;
+ HWND hwndClient;
+ BOOL fack;
+ HANDLE hdata = NULL;
+ OLESTATUS retval;
+ LPSRVR lpsrvr;
+
+ if (AddMessage (hwnd, msg, wParam, lParam, WT_DOC))
+ return 0L;
+
+ lpdoc = (LPDOC)GetWindowLong (hwnd, 0);
+
+ switch (msg){
+
+
+ case WM_CREATE:
+ DEBUG_OUT ("doc create window", 0)
+ break;
+
+ case WM_DDE_INITIATE:
+
+ DEBUG_OUT ("doc: DDE init",0);
+ if (lpdoc->bTerminate){
+ DEBUG_OUT ("doc: No action due to termination process",0)
+ break;
+ }
+
+ // if we are the documnet then respond.
+
+ if (! (lpdoc->aDoc == (ATOM)(HIWORD(lParam))))
+ break;
+
+ // We can enterain this client. Put this window in the client list
+ // and acknowledge the initiate.
+
+ if (!AddClient (hwnd, (HWND)wParam, (HWND)wParam))
+ break;
+
+ lpdoc->cClients++;
+ lpsrvr = (LPSRVR) GetWindowLong (GetParent(lpdoc->hwnd), 0);
+
+ lpsrvr->bnoRelease = FALSE;
+
+ // post the acknowledge
+ DuplicateAtom (LOWORD(lParam));
+ DuplicateAtom (HIWORD(lParam));
+ SendMessage ((HWND)wParam, WM_DDE_ACK, (WORD)hwnd, lParam);
+
+ break;
+
+ case WM_DDE_EXECUTE:
+
+ DEBUG_OUT ("doc: execute", 0)
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpdoc->hwnd, (HWND)wParam);
+ ASSERT (hwndClient, "Client is missing from the server")
+#endif
+ // Are we terminating
+ if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam)) {
+ DEBUG_OUT ("doc: execute after terminate posted",0)
+ // !!! are we supposed to free the data
+ GlobalFree (HIWORD (lParam));
+ break;
+
+ }
+
+ retval = DocExecute (hwnd, HIWORD (lParam), (HWND)wParam);
+ SET_MSG_STATUS (retval, status);
+
+#ifdef OLD
+ // if we posted the terminate because of execute, do not send
+ // ack.
+
+ if (lpdoc->bTerminate) {
+ // !!! We got close but, we are posting the
+ // the terminate. Excel does not complain about
+ // this. But powerpoint complains.
+#ifdef POWERPNT_BUG
+ GlobalFree (HIWORD(lParam));
+#endif
+ break;
+ }
+#endif
+ if (!lpdoc->bTerminate) {
+ // Post the acknowledge to the client
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(status, HIWORD(lParam))))
+ // the window either died or post failed, delete the data
+ GlobalFree (HIWORD(lParam));
+ }
+
+ break;
+
+ case WM_DDE_TERMINATE:
+ DEBUG_OUT ("doc: DDE terminate",0)
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpdoc->hwnd,(HWND)wParam);
+ ASSERT(hwndClient || lpdoc->termNo, "Client is missing from the server")
+#endif
+ // We do not need this client any more. Delete him from the
+ // client list.
+
+ DeleteClient (lpdoc->hwnd, (HWND)wParam);
+ lpdoc->cClients--;
+
+ if (lpdoc->bTerminate){
+ lpsrvr = (LPSRVR) GetWindowLong (GetParent(lpdoc->hwnd), 0);
+ if (!--lpdoc->termNo)
+ // Release this Doc and may be the server also
+ // if the server is waiting to be released also.
+ ReleaseDoc (lpdoc);
+ } else {
+ if (lpdoc->termNo == 0){
+
+ // If client intiated the terminate. Post matching terminate
+
+ PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE,
+ hwnd, NULL);
+ } else
+ lpdoc->termNo--;
+
+ //Client initiated the termination. So, we shoudl take him
+ // out from any of our items client lists.
+ DeleteFromItemsList (lpdoc->hwnd, (HWND)wParam);
+
+ lpsrvr = (LPSRVR)GetWindowLong (GetParent (lpdoc->hwnd), 0);
+
+ if (QueryRelease (lpsrvr)){
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVER")
+ else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl,
+ WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+
+ (*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr);
+ }
+
+ }
+ break;
+
+ case WM_DESTROY:
+ DEBUG_OUT ("doc: Destroy window",0)
+ break;
+
+ case WM_DDE_POKE: {
+ int iStdItem;
+
+ if (lpdoc->bTerminate || !IsWindowValid ((HWND) wParam)) {
+ // we are getting pke message after we have posted the
+ // the termination or the client got deleted.
+ PokeErr:
+ FreePokeData ((HANDLE) (LOWORD (lParam)));
+#ifdef OLD
+ GlobalFree ((HANDLE) (LOWORD (lParam)));
+#endif
+ // !!! Are we supposed to delete the atoms also.
+ PokeErr1:
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ break;
+
+ }
+
+ if (iStdItem = GetStdItemIndex (HIWORD(lParam)))
+ retval = PokeStdItems (lpdoc, (HWND)wParam,
+ MAKELONG((LOWORD(lParam)), iStdItem));
+ else
+ retval = PokeData (lpdoc, (HWND)wParam, lParam);
+
+ SET_MSG_STATUS (retval, status);
+ // !!! If the fRelease is false and the post fails
+ // then we are not freeing the hdata. Are we supposed to
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(status, HIWORD(lParam))))
+ goto PokeErr1;
+
+ break;
+ }
+
+ case WM_DDE_ADVISE:
+
+ fack = TRUE;
+
+ if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam))
+ goto PokeErr;
+
+ if (IsAdviseStdItems (HIWORD(lParam)))
+ retval = AdviseStdItems (lpdoc, (HWND)wParam, lParam, (BOOL FAR *)&fack);
+ else
+ // advise data will not have any OLE_BUSY
+ retval = AdviseData (lpdoc, (HWND)wParam, lParam, (BOOL FAR *)&fack);
+
+ SET_MSG_STATUS (retval, status);
+
+ if (fack) {
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(status, HIWORD(lParam))))
+ goto PokeErr;
+
+ }
+ else if ((ATOM)(HIWORD (lParam)))
+ GlobalDeleteAtom ((ATOM)(HIWORD (lParam)));
+
+ break;
+
+ case WM_DDE_UNADVISE:
+ if (lpdoc->bTerminate || !IsWindowValid ((HWND)wParam))
+ goto PokeErr;
+
+ retval = UnAdviseData (lpdoc, (HWND)wParam, lParam);
+ SET_MSG_STATUS (retval, status);
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(status, HIWORD(lParam))))
+ goto PokeErr;
+
+ break;
+
+ case WM_DDE_REQUEST:
+
+ if (lpdoc->bTerminate || !IsWindowValid ((HWND) wParam))
+ goto PokeErr1;
+
+ retval = RequestData (lpdoc, (HWND)wParam, lParam, (HANDLE FAR *)&hdata);
+
+ if(retval == OLE_OK) {
+ // post the data message and we are not asking for any
+ // acknowledge.
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, hwnd,
+ MAKELONG(hdata, HIWORD(lParam)))) {
+ GlobalFree (hdata);
+ goto PokeErr1;
+ }
+ break;
+ }
+
+ if (retval == OLE_BUSY)
+ status = 0x4000;
+ else
+ status = 0;
+
+ // if request failed, then acknowledge with error.
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(status, HIWORD(lParam))))
+ goto PokeErr1;
+
+
+ break;
+
+ default:
+ DEBUG_OUT("doc: Default message",0)
+ return DefWindowProc (hwnd, msg, wParam, lParam);
+
+ }
+
+ return 0L;
+
+}
+
+//DocExecute: Interprets the execute command for the
+//document conversation.
+
+
+OLESTATUS INTERNAL DocExecute(hwnd, hdata, hwndClient)
+HWND hwnd;
+HANDLE hdata;
+HWND hwndClient;
+{
+
+ ATOM acmd;
+ BOOL fShow;
+ BOOL fActivate;
+
+ HANDLE hdup = NULL;
+ int retval = OLE_ERROR_MEMORY;
+ LPDOC lpdoc;
+ LPOLESERVERDOC lpoledoc;
+ LPCLIENT lpclient = NULL;
+
+ LPSTR lpitemname;
+ LPSTR lpopt;
+ LPSTR lpnextarg;
+ LPSTR lpdata = NULL;
+ LPSTR lpverb = NULL;
+ WORD verb;
+ WORD wCmdType;
+
+ // !!!Can we modify the string which has been passed to us
+ // rather than duplicating the data. This will get some speed
+ // and save some space.
+
+ if(!(hdup = DuplicateData(hdata)))
+ goto errRtn;
+
+ if (!(lpdata = GlobalLock (hdup)))
+ goto errRtn;
+
+ DEBUG_OUT (lpdata, 0)
+
+ lpdoc = (LPDOC)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ ASSERT (lpdoc, "doc: doc does not exist");
+#endif
+ lpoledoc = lpdoc->lpoledoc;
+
+ retval = OLE_ERROR_SYNTAX;
+
+ if(*lpdata++ != '[') // commands start with the left sqaure bracket
+ goto errRtn;
+
+ // scan the command and scan upto the first arg.
+ if (!(wCmdType = ScanCommand(lpdata, WT_DOC, &lpnextarg, &acmd)))
+ goto errRtn;
+
+ if (wCmdType == NON_OLE_COMMAND) {
+ LPSRVR lpsrvr;
+
+ if (lpsrvr = (LPSRVR) GetWindowLong (GetParent (hwnd), 0)) {
+ if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE))
+ retval = OLE_ERROR_PROTOCOL;
+ else {
+#ifdef FIREWALLS
+ if (!CheckPointer (lpoledoc, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOC")
+ else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
+ else
+ ASSERT (lpoledoc->lpvtbl->Execute,
+ "Invalid pointer to Execute method")
+#endif
+
+ retval = (*lpoledoc->lpvtbl->Execute) (lpoledoc, hdata);
+ }
+ }
+
+ goto errRtn;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdCloseDocument]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd == aStdClose){
+
+ // if not terminated by NULL error
+ if (*lpnextarg)
+ goto errRtn;
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpoledoc, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOC")
+ else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
+ else
+ ASSERT (lpoledoc->lpvtbl->Close,"Invalid pointer to Close method")
+#endif
+ lpdoc->fAckClose = TRUE;
+ lpdoc->hwndClose = hwndClient;
+ lpdoc->hDataClose = hdata;
+ retval = (*lpoledoc->lpvtbl->Close) (lpoledoc);
+ lpdoc->fAckClose = FALSE;
+ goto end;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdDoVerbItem("itemname", verb, BOOL, BOOL]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd == aStdDoVerbItem){
+ lpitemname = lpnextarg;
+
+ if(!(lpverb = ScanArg(lpnextarg)))
+ goto errRtn;
+
+
+ if(!(lpnextarg = ScanNumArg(lpverb, (LPINT)&verb)))
+ goto errRtn;
+
+#ifdef FIREWALLS
+ ASSERT (verb < 9 , "Unexpected verb number");
+#endif
+
+ // now scan the show BOOL
+
+ if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fShow)))
+ goto errRtn;
+
+ fActivate = FALSE;
+
+ // if activate BOOL is present, scan it.
+
+ if (*lpnextarg) {
+ if (!(lpnextarg = ScanBoolArg (lpnextarg, (BOOL FAR *)&fActivate)))
+ goto errRtn;
+ }
+
+ if (*lpnextarg)
+ goto errRtn;
+
+
+ retval = DocDoVerbItem (lpdoc, lpitemname, verb, fShow, !fActivate);
+ goto end;
+ }
+
+
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdShowItem("itemname"[, "true"])]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (acmd != aStdShowItem)
+ goto errRtn;
+
+ lpitemname = lpnextarg;
+
+ if(!(lpopt = ScanArg(lpitemname)))
+ goto errRtn;
+
+ // Now scan for optional parameter.
+
+ fActivate = FALSE;
+
+ if (*lpopt) {
+
+ if(!(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
+ goto errRtn;
+
+ if (*lpnextarg)
+ goto errRtn;
+
+
+ }
+
+ retval = DocShowItem (lpdoc, lpitemname, !fActivate);
+
+end:
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdup);
+
+ if (hdup)
+ GlobalFree (hdup);
+
+ return retval;
+}
+
+int INTERNAL DocShowItem (lpdoc, lpitemname, fAct)
+LPDOC lpdoc;
+LPSTR lpitemname;
+BOOL fAct;
+
+{
+ LPCLIENT lpclient;
+ int retval;
+
+ if ((retval = FindItem (lpdoc, lpitemname, (LPCLIENT FAR *)&lpclient))
+ != OLE_OK)
+ return retval;
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpclient->lpoleobject->lpvtbl->Show,
+ "Invalid pointer to Show method")
+#endif
+
+ // protocol sends false for activating and TRUE for not activating.
+ // for api send TRUE for avtivating and FALSE for not activating.
+
+ return (*lpclient->lpoleobject->lpvtbl->Show)(lpclient->lpoleobject, fAct);
+}
+
+
+int INTERNAL DocDoVerbItem (lpdoc, lpitemname, verb, fShow, fAct)
+LPDOC lpdoc;
+LPSTR lpitemname;
+WORD verb;
+BOOL fShow;
+BOOL fAct;
+{
+ LPCLIENT lpclient;
+ int retval = OLE_ERROR_PROTOCOL;
+
+ if ((retval = FindItem (lpdoc, lpitemname, (LPCLIENT FAR *)&lpclient))
+ != OLE_OK)
+ return retval;
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpclient->lpoleobject->lpvtbl->DoVerb,
+ "Invalid pointer to Run method")
+#endif
+
+ // pass TRUE to activate and False not to activate. Differnt from
+ // protocol.
+
+ retval = (*lpclient->lpoleobject->lpvtbl->DoVerb)(lpclient->lpoleobject, verb, fShow, fAct);
+
+ return retval;
+}
+
+
+
+// FreePokeData: Frees the poked dats.
+void INTERNAL FreePokeData (hdde)
+HANDLE hdde;
+{
+ DDEPOKE FAR * lpdde;
+
+ if (hdde) {
+ if (lpdde = (DDEPOKE FAR *) GlobalLock (hdde)) {
+ GlobalUnlock (hdde);
+ FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
+ }
+
+ GlobalFree (hdde);
+ }
+}
+
+
+
+// Returns TRUE if GDI format else returns FALSE
+
+BOOL INTERNAL FreeGDIdata (hData, cfFormat)
+HANDLE hData;
+OLECLIPFORMAT cfFormat;
+{
+ if (cfFormat == CF_METAFILEPICT) {
+ LPMETAFILEPICT lpMfp;
+
+ if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) {
+ GlobalUnlock (hData);
+ DeleteMetaFile (lpMfp->hMF);
+ }
+
+ GlobalFree (hData);
+ }
+ else if (cfFormat == CF_BITMAP)
+ DeleteObject (hData);
+ else if (cfFormat == CF_DIB)
+ GlobalFree (hData);
+ else
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow16/ole/server/give2gdi.asm b/private/mvdm/wow16/ole/server/give2gdi.asm
new file mode 100644
index 000000000..e35ef987d
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/give2gdi.asm
@@ -0,0 +1,111 @@
+ ;\
+ ; give2gdi.asm
+ ;
+ ; Copyright (C) 1991, MicroSoft Corporation
+ ;
+ ; Contains code which changes memory metafile ownership to GDI
+ ;
+ ; History: sriniK 05/22/1991
+ ;/
+
+
+include cmacros.inc
+include windows.inc
+
+.286
+
+
+;**************************** Data Segment ********************************
+
+sBegin data
+ assumes ds, data
+
+szGDI db 'GDI', 0
+szWEP db 'WEP', 0
+
+sEnd data
+
+
+;*************************** Code Segment *********************************
+
+externFP GlobalRealloc
+externFP GlobalSize
+externFP GetModuleHandle
+externFP GetProcAddress
+
+createSeg Give2GDI, Give2GDI, para, public, code
+
+sBegin Give2GDI
+ assumes cs,Give2GDI
+ assumes ds,data
+ assumes es,nothing
+
+;**************************** Public Functions ****************************
+
+cProc GiveToGDI, <PUBLIC,FAR>
+;
+;
+; HANDLE FAR PASCAL GiveToGDI(HANDLE hMem)
+;
+; Assign ownership of the given global memory block to GDI
+;
+; returns a handle to the memory block if successful, otherwise returns NULL
+;
+
+ parmW hMem
+
+ localD lpGDIWEP
+cBegin
+ ;*************************************************************
+ ;** Get address of retf in fixed GDI code segment **
+ ;*************************************************************
+
+ push ds
+ push dataOFFSET szGDI
+ cCall GetModuleHandle
+
+ push ax
+ push ds
+ push dataOFFSET szWEP
+ cCall GetProcAddress
+
+ mov [word ptr lpGDIWEP[0]], ax
+ mov [word ptr lpGDIWEP[2]], dx
+
+ ;*************************************************************
+ ;** Kludge a call to GlobalReAlloc with GDI as caller **
+ ;*************************************************************
+
+ push 0 ; Params for WEP
+
+ push cs ; GDI's WEP returns here
+ push offset ReturnHere
+
+ push hMem ; Params to GlobalReAlloc
+ push 0
+ push 0
+ push [GMEM_MOVEABLE or GMEM_SHARE or GMEM_MODIFY]
+
+ push [word ptr lpGDIWEP[2]] ; GlobalReAlloc returns here
+ push [word ptr lpGDIWEP[0]] ; GlobalReAlloc returns here
+
+ push 0 ; Params for WEP
+
+ push seg GlobalReAlloc ; GDI's WEP returns here
+ push offset GlobalReAlloc
+
+ jmp lpGDIWEP ; Dive off the end
+ReturnHere:
+ ;*************************************************************
+ ;** Return handle to reallocated block **
+ ;*************************************************************
+
+ mov ax,hMem
+cEnd
+
+;*************************************************************************
+
+sEnd Give2GDI
+end
+
+;*************************************************************************
diff --git a/private/mvdm/wow16/ole/server/item.c b/private/mvdm/wow16/ole/server/item.c
new file mode 100644
index 000000000..c41d3c70d
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/item.c
@@ -0,0 +1,1771 @@
+/****************************** Module Header ******************************\
+* Module Name: Item.c Object(item) main module
+*
+* Purpose: Includes All the object releated routiens.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded
+*
+*
+\***************************************************************************/
+
+
+#include "cmacs.h"
+#include "windows.h"
+#include "ole.h"
+#include "dde.h"
+#include "srvr.h"
+
+extern HANDLE hdllInst;
+extern FARPROC lpFindItemWnd;
+extern FARPROC lpItemCallBack;
+extern FARPROC lpSendDataMsg;
+extern FARPROC lpSendRenameMsg;
+extern FARPROC lpDeleteClientInfo;
+extern FARPROC lpEnumForTerminate;
+
+
+extern ATOM cfNative;
+extern ATOM cfBinary;
+extern ATOM aClose;
+extern ATOM aChange;
+extern ATOM aSave;
+extern ATOM aEditItems;
+extern ATOM aStdDocName;
+
+extern WORD cfLink;
+extern WORD cfOwnerLink;
+
+extern BOOL bWin30;
+
+HWND hwndItem;
+HANDLE hddeRename;
+HWND hwndRename;
+
+WORD enummsg;
+WORD enuminfo;
+LPOLEOBJECT enumlpoleobject;
+OLECLIENTVTBL clVtbl;
+BOOL bClientUnlink;
+
+BOOL fAdviseSaveDoc;
+BOOL fAdviseSaveItem;
+
+char * stdStrTable[STDHOSTNAMES+1] = {NULL,
+ "StdTargetDevice",
+ "StdDocDimensions",
+ "StdColorScheme",
+ "StdHostNames"};
+
+
+extern HANDLE (FAR PASCAL *lpfnSetMetaFileBitsBetter) (HANDLE);
+
+void ChangeOwner (HANDLE hmfp);
+
+// !!!change child enumeration.
+// !!!No consistency in errors (Sometimes Bools and sometimes OLESTATUS).
+
+
+//SearchItem: Searches for a given item in a document tree.
+//If found, returns the corresponding child windows handle.
+
+HWND INTERNAL SearchItem (lpdoc, lpitemname)
+LPDOC lpdoc;
+LPSTR lpitemname;
+{
+ ATOM aItem;
+
+ Puts ("SearchItem");
+
+ // If the item passed is an atom, get its name.
+ if (!HIWORD(lpitemname))
+ aItem = (ATOM) (LOWORD((DWORD)lpitemname));
+ else if (!lpitemname[0])
+ aItem = NULL;
+ else
+ aItem = GlobalFindAtom (lpitemname);
+
+ hwndItem = NULL;
+
+ // !!! We should avoid hwndItem static. It should not cause
+ // any problems since while enumerating we will not be calling
+ // any window procs or no PostMessages are entertained.
+
+ EnumChildWindows (lpdoc->hwnd, lpFindItemWnd,
+ MAKELONG (aItem, ITEM_FIND));
+
+ return hwndItem;
+
+}
+
+// FindItem: Given the itemname and the document handle,
+// searches for the the item (object) in the document tree.
+// Items are child windows for the document window.
+
+// !!! change the child windows to somekind of
+// linked lists at the item level. This will free up
+// the space taken by the item windows.
+
+int INTERNAL FindItem (lpdoc, lpitemname, lplpclient)
+LPDOC lpdoc;
+LPSTR lpitemname;
+LPCLIENT FAR * lplpclient;
+{
+ LPCLIENT lpclient;
+ HWND hwnd;
+ char buf[MAX_STR];
+
+ Puts ("FindItem");
+
+ hwnd = SearchItem (lpdoc, lpitemname);
+
+ if (!HIWORD(lpitemname)){
+ if (LOWORD(lpitemname))
+ GlobalGetAtomName ((ATOM)LOWORD((DWORD)lpitemname),
+ (LPSTR)buf, MAX_STR);
+ else
+ buf[0] = NULL;
+
+ lpitemname = (LPSTR)buf;
+ }
+
+ if (hwnd) {
+ // we found the item window
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ ASSERT ((CheckPointer(lpclient, WRITE_ACCESS)),
+ "In Item the client handle missing")
+ ASSERT ((CheckPointer(lpclient->lpoleobject, WRITE_ACCESS)),
+ "In Item object handle missing")
+
+#endif
+ *lplpclient = lpclient;
+ return OLE_OK;
+
+ }
+
+ // Item (object)window is not create yet. Let us create one.
+ return RegisterItem ((LHDOC)lpdoc, lpitemname, lplpclient, TRUE);
+}
+
+
+
+//RegisterItem: Given the document handle and the item string
+//creates item with the given document.
+
+int INTERNAL RegisterItem (lhdoc, lpitemname, lplpclient, bSrvr)
+LHDOC lhdoc;
+LPSTR lpitemname;
+LPCLIENT FAR * lplpclient;
+BOOL bSrvr;
+{
+
+
+ LPDOC lpdoc;
+ HANDLE hclient = NULL;
+ LPCLIENT lpclient = NULL;
+ int retval = OLE_ERROR_MEMORY;
+ LPOLESERVERDOC lpoledoc;
+ LPOLEOBJECT lpoleobject = NULL;
+
+
+ Puts ("CreateItem");
+
+ lpdoc = (LPDOC)lhdoc;
+
+#ifdef FIREWALLS
+ ASSERT ((CheckPointer (lplpclient, WRITE_ACCESS)), "invalid lplpclient");
+#endif
+
+ // First create the callback client structure.
+
+ hclient = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (CLIENT));
+ if(!(hclient && (lpclient = (LPCLIENT)GlobalLock (hclient))))
+ goto errRtn;
+
+ lpclient->hclient = hclient;
+ hclient = NULL;
+
+ if (!HIWORD(lpitemname)) {
+ ASSERT (!bSrvr, "invalid lpitemname in RegisterItem\n");
+ lpclient->aItem = LOWORD((DWORD)lpitemname);
+ }
+ else if (!lpitemname[0])
+ lpclient->aItem = NULL;
+ else
+ lpclient->aItem = GlobalAddAtom (lpitemname);
+
+ lpclient->oleClient.lpvtbl = &clVtbl;
+ lpclient->oleClient.lpvtbl->CallBack = lpItemCallBack;
+
+ lpoledoc = lpdoc->lpoledoc;
+
+ // Call the server app to create its own object structure and link
+ // it to the given document.
+
+ // Call the server if the item is not one of the standard items.
+
+ if (bSrvr) {
+ retval = (*lpoledoc->lpvtbl->GetObject)(lpoledoc, lpitemname,
+ (LPOLEOBJECT FAR *)&lpoleobject, (LPOLECLIENT)lpclient);
+ if (retval != OLE_OK)
+ goto errRtn;
+ }
+
+ lpclient->lpoleobject = lpoleobject;
+
+ lpclient->hwnd = CreateWindow ("ItemWndClass", "ITEM",
+ WS_CHILD,0,0,0,0,lpdoc->hwnd,NULL, hdllInst, NULL);
+
+ if (lpclient->hwnd == NULL)
+ goto errRtn;
+
+ // save the ptr to the item in the window.
+ SetWindowLong (lpclient->hwnd, 0, (LONG)lpclient);
+ *lplpclient = lpclient;
+ return OLE_OK;
+
+errRtn:
+
+ if (lpclient)
+ RevokeObject ((LPOLECLIENT)lpclient, FALSE);
+
+ else {
+ if(hclient)
+ GlobalFree (hclient);
+ }
+
+ return retval;
+
+}
+
+
+OLESTATUS FAR PASCAL OleRevokeObject (lpoleclient)
+LPOLECLIENT lpoleclient;
+{
+ return RevokeObject (lpoleclient, TRUE);
+
+}
+// OleRevokeObject: Revokes an object (unregisres an object
+// from the document tree.
+
+OLESTATUS INTERNAL RevokeObject (lpoleclient, bUnlink)
+LPOLECLIENT lpoleclient;
+BOOL bUnlink;
+{
+
+ HANDLE hclient;
+ LPCLIENT lpclient;
+
+ lpclient = (LPCLIENT)lpoleclient;
+
+ PROBE_WRITE(lpoleclient);
+ if (lpclient->lpoleobject) {
+ // first call the object for deletetion.
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBECT")
+
+ if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT(lpclient->lpoleobject->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+
+ (*lpclient->lpoleobject->lpvtbl->Release)(lpclient->lpoleobject);
+
+ }
+
+ if (ISATOM(lpclient->aItem)) {
+ GlobalDeleteAtom (lpclient->aItem);
+ lpclient->aItem = NULL;
+ }
+
+ if (lpclient->hwnd) {
+ SetWindowLong (lpclient->hwnd, 0, (LONG)NULL);
+
+ // another static for enumerating the properties.
+ // we need to change these .
+ bClientUnlink = bUnlink;
+
+ EnumProps(lpclient->hwnd, lpDeleteClientInfo);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (lpclient->hwnd, FALSE);
+ DestroyWindow (lpclient->hwnd);
+ }
+
+ GlobalUnlock (hclient = lpclient->hclient);
+ GlobalFree (hclient);
+ return OLE_OK;
+
+}
+
+BOOL FAR PASCAL DeleteClientInfo (hwnd, lpstr, hclinfo)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hclinfo;
+{
+ PCLINFO pclinfo = NULL;
+ HWND hwndDoc;
+ LPDOC lpdoc;
+
+#ifdef FIREWALLS
+ ASSERT (hclinfo, "Client info null in item property list");
+#endif
+
+
+ // delete the printer dev info block
+ if(pclinfo = (PCLINFO)LocalLock (hclinfo)){
+ if(pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+
+
+ if (bClientUnlink) {
+ // terminate the conversation for the client.
+ TerminateDocClients ((hwndDoc = GetParent(hwnd)), NULL, pclinfo->hwnd);
+ lpdoc = (LPDOC)GetWindowLong (hwndDoc, 0);
+ // for some reason this delete is gving circular lists for properties
+
+ //DeleteClient (hwndDoc, pclinfo->hwnd);
+ //lpdoc->cClients--;
+ }
+ LocalUnlock (hclinfo);
+ }
+ LocalFree (hclinfo);
+ RemoveProp (hwnd, lpstr);
+ return TRUE;
+}
+
+
+
+
+// Call back for the Object windows numeration. data field
+// has the command and the extra information
+
+
+BOOL FAR PASCAL FindItemWnd (hwnd, data)
+HWND hwnd;
+LONG data;
+{
+
+ LPCLIENT lpclient;
+ int cmd;
+ HANDLE hclinfo;
+ PCLINFO pclinfo;
+
+
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ // ASSERT (lpclient, "In Item the client handle missing")
+#endif
+
+ cmd = HIWORD(data);
+ switch (cmd) {
+ case ITEM_FIND:
+ if (lpclient->aItem == (ATOM)(LOWORD (data))) {
+ // we found the window we required. Remember the
+ // object window.
+
+ hwndItem = hwnd;
+ return FALSE; // terminate enumeration.
+
+ }
+ break;
+
+ case ITEM_SAVED:
+ if (lpclient->lpoleobject) {
+ if (ItemCallBack ((LPOLECLIENT) lpclient, OLE_SAVED,
+ lpclient->lpoleobject) == OLE_ERROR_CANT_UPDATE_CLIENT)
+ fAdviseSaveDoc = FALSE;
+ }
+ break;
+
+ case ITEM_DELETECLIENT:
+
+ // delete the client from our list if we have one
+
+ hclinfo = FindClient (hwnd, (HWND) (LOWORD(data)));
+ if (hclinfo){
+ // delete the printer dev info block
+ if(pclinfo = (PCLINFO)LocalLock (hclinfo)){
+ if(pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+ LocalUnlock (hclinfo);
+ }
+ LocalFree (hclinfo);
+ DeleteClient ( hwnd, (HWND) (LOWORD(data)));
+ }
+ break;
+
+ case ITEM_DELETE:
+ // delete the client it self.
+ RevokeObject ((LPOLECLIENT)lpclient, FALSE);
+ break;
+
+ }
+ return TRUE; // continue enumeration.
+}
+
+
+
+//DeleteFromItemsList: Deletes a client from the object lists of
+//all the objects of a given document. Thie client possibly
+//is terminating the conversation with our doc window.
+
+
+void INTERNAL DeleteFromItemsList (hwndDoc, hwndClient)
+HWND hwndDoc;
+HWND hwndClient;
+{
+
+ EnumChildWindows (hwndDoc, lpFindItemWnd,
+ MAKELONG (hwndClient, ITEM_DELETECLIENT));
+
+}
+
+
+// DeleteAllItems: Deletes all the objects of a given
+// document window.
+
+
+void INTERNAL DeleteAllItems (hwndDoc)
+HWND hwndDoc;
+{
+
+ EnumChildWindows (hwndDoc, lpFindItemWnd,
+ MAKELONG (NULL, ITEM_DELETE));
+
+}
+
+
+// Object widnow proc:
+
+long FAR PASCAL ItemWndProc(hwnd, msg, wParam, lParam)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+{
+
+ LPCLIENT lpclient;
+
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+ switch (msg) {
+ case WM_DESTROY:
+ DEBUG_OUT("Item: Destroy window",0)
+
+#ifdef FIREWALLS
+ ASSERT (!lpclient, "while destroy Item client is not null")
+#endif
+ break;
+ default:
+ DEBUG_OUT("item: Default message",0)
+ return DefWindowProc (hwnd, msg, wParam, lParam);
+
+ }
+ return 0L;
+
+}
+
+// PokeData: Prepares and gives the data to the server app thru
+// the SetData object method.
+
+OLESTATUS INTERNAL PokeData (lpdoc, hwndClient, lparam)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+{
+ int retval = OLE_ERROR_MEMORY;
+ LPCLIENT lpclient;
+ DDEPOKE FAR * lpPoke = NULL;
+ HANDLE hPoke = NULL;
+ HANDLE hnew = NULL;
+ int format;
+ BOOL fRelease = FALSE;
+
+ // Get the object handle first. Look in the registration
+ // tree and if one is not created otherwise create one.
+
+ retval = FindItem (lpdoc, (LPSTR) MAKEINTATOM(HIWORD(lparam)),
+ (LPCLIENT FAR *)&lpclient);
+
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ hPoke = (HANDLE)(LOWORD (lparam));
+ if(!(hPoke && (lpPoke = (DDEPOKE FAR *) GlobalLock (hPoke))))
+ goto errRtn;
+
+ GlobalUnlock (hPoke);
+
+ format = lpPoke->cfFormat;
+ fRelease = lpPoke->fRelease;
+
+ // We found the item. Now prepare the data to be given to the object
+ if (!(hnew = MakeItemData (lpPoke, hPoke, format)))
+ goto errRtn;
+
+ // Now send the data to the object
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpclient->lpoleobject->lpvtbl->SetData,
+ "Invalid pointer to SetData method")
+#endif
+
+ retval = (*lpclient->lpoleobject->lpvtbl->SetData) (lpclient->lpoleobject,
+ format, hnew);
+
+ // We free the data if server returns OLE_ERROR_SETDATA_FORMAT.
+ // Otherwise server must've deleted it.
+
+ if (retval == OLE_ERROR_SETDATA_FORMAT) {
+ if (!FreeGDIdata (hnew, format))
+ GlobalFree (hnew);
+ }
+
+
+errRtn:
+ if (retval == OLE_OK && fRelease) {
+ if (hPoke)
+ GlobalFree (hPoke);
+ }
+
+ return retval;
+}
+
+
+
+
+OLESTATUS INTERNAL UnAdviseData (lpdoc, hwndClient, lparam)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+{
+
+
+ char buf[MAX_STR];
+ int options;
+ LPCLIENT lpclient;
+ int retval = OLE_ERROR_MEMORY;
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+
+ if (!(HIWORD (lparam)))
+ buf[0] = NULL;
+ else
+ GlobalGetAtomName ((ATOM)(HIWORD (lparam)), (LPSTR)buf, MAX_STR);
+
+ // Scan for the advise options like "Close", "Save" etc
+ // at the end of the item.
+
+ if((retval = ScanItemOptions ((LPSTR)buf, (int far *)&options)) !=
+ OLE_OK)
+ goto errRtn;
+
+
+ if (buf[0] == NULL) {
+ // Unadvise for null should terminate all the advises
+ DeleteFromItemsList (lpdoc->hwnd, hwndClient);
+ return OLE_OK;
+ }
+
+ // Now get the corresponding object.
+ retval = FindItem (lpdoc, (LPSTR)buf, (LPCLIENT FAR *)&lpclient);
+ if (retval != OLE_OK)
+ goto errRtn;
+
+
+ // Find the client structure to be attcahed to the object.
+ if ((hclinfo = FindClient (lpclient->hwnd, hwndClient)) == NULL ||
+ (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL ){
+ retval = OLE_ERROR_MEMORY;
+ goto errRtn;
+ }
+
+ pclinfo->options &= (~(0x0001 << options));
+
+errRtn:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+ return retval;
+
+}
+
+
+
+// AdviseStdItems: This routine takes care of the DDEADVISE for a
+//particular object in given document. Creates a client strutcure
+//and attaches to the property list of the object window.
+
+OLESTATUS INTERNAL AdviseStdItems (lpdoc, hwndClient, lparam, lpfack)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+BOOL FAR * lpfack;
+{
+
+ HANDLE hopt = NULL;
+ DDEADVISE FAR *lpopt;
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+
+
+ hopt = (HANDLE) (LOWORD (lparam));
+ if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
+ goto errrtn;
+
+#ifdef FIREWALLS
+ ASSERT ((ATOM) (HIWORD (lparam) == aStdDocName), "AdviseStdItem is not Documentname");
+#endif
+
+ *lpfack = lpopt->fAckReq;
+ retval = SetStdInfo (lpdoc, hwndClient, (LPSTR)"StdDocumentName", NULL);
+
+ if (lpopt)
+ GlobalUnlock (hopt);
+
+errrtn:
+
+ if (retval == OLE_OK)
+ // !!! make sure that we have to free the data for error case
+ GlobalFree (hopt);
+ return retval;
+}
+
+
+
+//AdviseData: This routine takes care of the DDEADVISE for a
+//particular object in given document. Creates a client strutcure
+//and attaches to the property list of the object window.
+
+OLESTATUS INTERNAL AdviseData (lpdoc, hwndClient, lparam, lpfack)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+BOOL FAR * lpfack;
+{
+
+
+ HANDLE hopt = NULL;
+ DDEADVISE FAR *lpopt = NULL;
+ int format = NULL;
+ char buf[MAX_STR];
+ int options;
+ LPCLIENT lpclient;
+ int retval = OLE_ERROR_MEMORY;
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+
+
+
+ hopt = (HANDLE) (LOWORD (lparam));
+ if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
+ goto errRtn;
+
+ if (!(HIWORD (lparam)))
+ buf[0] = NULL;
+ else
+ GlobalGetAtomName ((ATOM)(HIWORD (lparam)), (LPSTR)buf, MAX_STR);
+
+ // Scan for the advise options like "Close", "Save" etc
+ // at the end of the item.
+
+ if((retval = ScanItemOptions ((LPSTR)buf, (int far *)&options)) !=
+ OLE_OK)
+ goto errRtn;
+
+
+ // Now get the corresponding object.
+ retval = FindItem (lpdoc, (LPSTR)buf, (LPCLIENT FAR *)&lpclient);
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ if (!IsFormatAvailable (lpclient, lpopt->cfFormat)){
+ retval = OLE_ERROR_DATATYPE; // this format is not supported;
+ goto errRtn;
+ }
+
+ *lpfack = lpopt->fAckReq;
+
+ // Create the client structure to be attcahed to the object.
+ if (!(hclinfo = FindClient (lpclient->hwnd, hwndClient)))
+ hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
+
+ if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL){
+ retval = OLE_ERROR_MEMORY;
+ goto errRtn;
+ }
+
+ // Remember the client window (Needed for sending DATA later on
+ // when the data change message comes from the server)
+
+ pclinfo->hwnd = hwndClient;
+ if (lpopt->cfFormat == (int)cfNative)
+ pclinfo->bnative = TRUE;
+ else
+ pclinfo->format = lpopt->cfFormat;
+
+ // Remeber the data transfer options.
+ pclinfo->options |= (0x0001 << options);
+ pclinfo->bdata = !lpopt->fDeferUpd;
+ LocalUnlock (hclinfo);
+ pclinfo = NULL;
+
+
+ // if the entry exists already, delete it.
+ DeleteClient (lpclient->hwnd, hwndClient);
+
+ // Now add this client to item client list
+ // !!! This error recovery is not correct.
+ if(!AddClient (lpclient->hwnd, hwndClient, hclinfo))
+ goto errRtn;
+
+
+errRtn:
+ if (lpopt)
+ GlobalUnlock (hopt);
+
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (retval == OLE_OK) {
+ // !!! make sure that we have to free the data
+ GlobalFree (hopt);
+
+ }else {
+ if (hclinfo)
+ LocalFree (hclinfo);
+ }
+ return retval;
+
+}
+
+BOOL INTERNAL IsFormatAvailable (lpclient, cfFormat)
+LPCLIENT lpclient;
+OLECLIPFORMAT cfFormat;
+{
+ OLECLIPFORMAT cfNext = 0;
+
+
+ do{
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBECT")
+ else if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpclient->lpoleobject->lpvtbl->EnumFormats,
+ "Invalid pointer to EnumFormats method")
+#endif
+
+ cfNext = (*lpclient->lpoleobject->lpvtbl->EnumFormats)
+ (lpclient->lpoleobject, cfNext);
+ if (cfNext == cfFormat)
+ return TRUE;
+
+ }while (cfNext != 0);
+
+ return FALSE;
+}
+
+//ScanItemOptions: Scan for the item options like Close/Save etc.
+
+OLESTATUS INTERNAL ScanItemOptions (lpbuf, lpoptions)
+LPSTR lpbuf;
+int far *lpoptions;
+{
+
+ ATOM aModifier;
+
+ *lpoptions = OLE_CHANGED;
+ while ( *lpbuf && *lpbuf != '/')
+ lpbuf++;
+
+ // no modifier same as /change
+
+ if (*lpbuf == NULL)
+ return OLE_OK;
+
+ *lpbuf++ = NULL; // seperate out the item string
+ // We are using this in the caller.
+
+ if (!(aModifier = GlobalFindAtom (lpbuf)))
+ return OLE_ERROR_SYNTAX;
+
+ if (aModifier == aChange)
+ return OLE_OK;
+
+ // Is it a save?
+ if (aModifier == aSave){
+ *lpoptions = OLE_SAVED;
+ return OLE_OK;
+ }
+ // Is it a Close?
+ if (aModifier == aClose){
+ *lpoptions = OLE_CLOSED;
+ return OLE_OK;
+ }
+
+ // unknow modifier
+ return OLE_ERROR_SYNTAX;
+
+}
+
+//RequestData: Sends data in response to a DDE Request message.
+// for agiven doc and an object.
+
+OLESTATUS INTERNAL RequestData (lpdoc, hwndClient, lparam, lphdde)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+LPHANDLE lphdde;
+{
+
+ OLESTATUS retval = OLE_OK;
+ HANDLE hdata;
+ LPCLIENT lpclient;
+ char buf[6];
+
+ // If edit environment Send data if we can
+ if ((HIWORD (lparam)) == aEditItems)
+ return RequestDataStd (lparam, lphdde);
+
+ // Get the object.
+ retval = FindItem (lpdoc, (LPSTR) MAKEINTATOM(HIWORD(lparam)),
+ (LPCLIENT FAR *)&lpclient);
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ retval = OLE_ERROR_DATATYPE;
+ if (!IsFormatAvailable (lpclient, (int)(LOWORD (lparam))))
+ goto errRtn;
+
+ // Now ask the item for the given format data
+
+#ifdef FIREWALLS
+ ASSERT (lpclient->lpoleobject->lpvtbl->GetData,
+ "Invalid pointer to GetData method")
+#endif
+
+ MapToHexStr ((LPSTR)buf, hwndClient);
+ SendDevInfo (lpclient, (LPSTR)buf);
+
+ retval = (*lpclient->lpoleobject->lpvtbl->GetData) (lpclient->lpoleobject,
+ (int)(LOWORD (lparam)), (LPHANDLE)& hdata);
+
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ if (LOWORD(lparam) == CF_METAFILEPICT)
+ ChangeOwner (hdata);
+
+ // Duplicate the DDE data
+ if(MakeDDEData(hdata, (int)(LOWORD (lparam)), lphdde, TRUE)){
+ // !!! Why do we have to duplicate the atom
+ DuplicateAtom ((ATOM)(HIWORD (lparam)));
+ return OLE_OK;
+ }
+ else
+ return OLE_ERROR_MEMORY;
+
+errRtn:
+ return retval;
+
+}
+
+//MakeDDEData: Create a Global DDE data handle from the server
+// app data handle.
+
+BOOL INTERNAL MakeDDEData (hdata, format, lph, fResponse)
+HANDLE hdata;
+LPHANDLE lph;
+int format;
+BOOL fResponse;
+{
+ DWORD size;
+ HANDLE hdde = NULL;
+ DDEDATA FAR *lpdata= NULL;
+ BOOL bnative;
+ LPSTR lpdst;
+ LPSTR lpsrc;
+
+ if (!hdata) {
+ *lph = NULL;
+ return TRUE;
+ }
+
+ if (bnative = !(format == CF_METAFILEPICT || format == CF_DIB ||
+ format == CF_BITMAP))
+ size = GlobalSize (hdata) + sizeof (DDEDATA);
+ else
+ size = sizeof (LONG) + sizeof (DDEDATA);
+
+
+ hdde = (HANDLE) GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, size);
+ if (hdde == NULL || (lpdata = (DDEDATA FAR *) GlobalLock (hdde)) == NULL)
+ goto errRtn;
+
+ // set the data otions. Ask the client to delete
+ // it always.
+
+ lpdata->fRelease = TRUE; // release the data
+ lpdata->cfFormat = format;
+ lpdata->fResponse = fResponse;
+
+ if (!bnative)
+ // If not native, stick in the handle what the server gave us.
+ *(LPHANDLE)lpdata->Value = hdata;
+
+ else {
+ // copy the native data junk here.
+ lpdst = (LPSTR)lpdata->Value;
+ if(!(lpsrc = (LPSTR)GlobalLock (hdata)))
+ goto errRtn;
+
+ size -= sizeof (DDEDATA);
+ UtilMemCpy (lpdst, lpsrc, size);
+ GlobalUnlock (hdata);
+ GlobalFree (hdata);
+
+ }
+
+ GlobalUnlock (hdde);
+ *lph = hdde;
+ return TRUE;
+
+errRtn:
+ if (lpdata)
+ GlobalUnlock (hdde);
+
+ if (hdde)
+ GlobalFree (hdde);
+
+ if (bnative)
+ GlobalFree (hdata);
+
+ return FALSE;
+}
+
+
+// ItemCallback: Calback routine for the server to inform the
+// data changes. When the change message is received, DDE data
+// message is sent to each of the clients depending on the
+// options.
+
+int FAR PASCAL ItemCallback (lpoleclient, msg, lpoleobject)
+LPOLECLIENT lpoleclient;
+WORD msg; // notification message
+LPOLEOBJECT lpoleobject;
+{
+
+ LPCLIENT lpclient;
+ int retval = OLE_OK;
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+ LPDOC lpdoc;
+ HWND hStdWnd;
+
+ lpclient = (LPCLIENT)lpoleclient;
+ lpdoc = (LPDOC)GetWindowLong (GetParent (lpclient->hwnd), 0);
+
+ if (msg == OLE_RENAMED) {
+#ifdef FIREWALLS
+ if (!CheckPointer (lpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid lpoleobject")
+ else if (!CheckPointer (lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpoleobject->lpvtbl->GetData,
+ "Invalid pointer to GetData method")
+#endif
+
+ if (IsFormatAvailable (lpclient, cfLink)) {
+
+ // Get the link data.
+
+ retval = (*lpoleobject->lpvtbl->GetData) (lpoleobject,
+ (int)cfLink, (LPHANDLE)&hdata);
+ }
+ else {
+ if(IsFormatAvailable (lpclient, cfOwnerLink)) {
+
+ // Get the link data.
+ retval = (*lpoleobject->lpvtbl->GetData) (lpoleobject,
+ (int)cfOwnerLink, (LPHANDLE)& hdata);
+#ifdef FIREWALLS
+ ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY")
+#endif
+
+
+ } else
+ retval = OLE_ERROR_DATATYPE;
+ }
+
+ if (retval != OLE_OK)
+ goto errrtn;
+
+ if (!(lpdata = (LPSTR)GlobalLock (hdata)))
+ goto errrtn;
+
+ if (lpdoc->aDoc) {
+ GlobalDeleteAtom (lpdoc->aDoc);
+ lpdoc->aDoc = NULL;
+ }
+
+ // Move the string to the beginning and still terminated by null;
+ lstrcpy (lpdata, lpdata + lstrlen (lpdata) + 1);
+ lpdoc->aDoc = GlobalAddAtom (lpdata);
+
+ // Now make the DDE data block
+ GlobalUnlock (hdata);
+ lpdata = NULL;
+
+ // find if any StdDocName item is present at all
+ if (!(hStdWnd = SearchItem (lpdoc, (LPSTR) MAKEINTATOM(aStdDocName))))
+ GlobalFree (hdata);
+ else {
+
+ // hdata is freed by Makeddedata
+ if (!MakeDDEData (hdata, (int)cfBinary, (LPHANDLE)&hddeRename,
+ FALSE)) {
+ retval = OLE_ERROR_MEMORY;
+ goto errrtn;
+ }
+
+ EnumProps(hStdWnd, lpSendRenameMsg);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (hStdWnd, FALSE);
+ GlobalFree (hddeRename);
+ }
+
+ // static. Avoid this. This may not cause any problems for now.
+ // if there is any better way, change it.
+ hwndRename = hStdWnd;
+
+ // Post termination for each of the doc clients.
+ EnumProps (lpdoc->hwnd, lpEnumForTerminate);
+
+ lpdoc->fEmbed = FALSE;
+
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (lpdoc->hwnd, FALSE);
+ return OLE_OK;
+
+ errrtn:
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+ if (hdata)
+ GlobalFree (hdata);
+
+ return retval;
+
+ } else {
+
+ // !!! any better way to do instead of putting in static
+ // (There may not be any problems since we are not allowing
+ // any messages to get thru while we are posting messages).
+
+
+ if ((enummsg = msg) == OLE_SAVED)
+ fAdviseSaveItem = FALSE;
+
+ enumlpoleobject = lpoleobject;
+
+#ifdef FIREWALLS
+ ASSERT (lpclient->hwnd && IsWindowValid (lpclient->hwnd), " Not valid object")
+#endif
+
+ // Enumerate all the clients and send DDE_DATA if necessary.
+ EnumProps(lpclient->hwnd, lpSendDataMsg);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (lpclient->hwnd, FALSE);
+
+ if ((msg == OLE_SAVED) && lpdoc->fEmbed && !fAdviseSaveItem)
+ return OLE_ERROR_CANT_UPDATE_CLIENT;
+
+ return OLE_OK;
+ }
+}
+
+
+BOOL FAR PASCAL EnumForTerminate (hwnd, lpstr, hdata)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hdata;
+{
+
+ LPDOC lpdoc;
+
+ lpdoc = (LPDOC)GetWindowLong (hwnd , 0);
+
+ // This client is in the rename list. So, no terminate
+ if(hwndRename && FindClient (hwndRename, (HWND)hdata))
+ return TRUE;
+
+
+ if (PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, hwnd, NULL))
+ lpdoc->termNo++;
+
+ //DeleteClient (hwnd, (HWND)hdata);
+ //lpdoc->cClients--;
+ return TRUE;
+}
+
+
+BOOL FAR PASCAL SendRenameMsg (hwnd, lpstr, hclinfo)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hclinfo;
+{
+ ATOM aData = NULL;
+ HANDLE hdde = NULL;
+ PCLINFO pclinfo = NULL;
+ HWND hwndClient;
+
+ if (!(pclinfo = (PCLINFO) LocalLock (hclinfo)))
+ goto errrtn;
+
+ // Make the item atom with the options.
+ aData = DuplicateAtom (aStdDocName);
+ hdde = DuplicateData (hddeRename);
+
+ hwndClient = pclinfo->hwnd;
+ LocalUnlock (hclinfo);
+
+ // Post the message
+ if (!PostMessageToClientWithBlock (hwndClient, WM_DDE_DATA, (HWND)GetParent (hwnd),
+ MAKELONG (hdde, aData)))
+ goto errrtn;
+
+ return TRUE;
+
+errrtn:
+
+ if (hdde)
+ GlobalFree (hdde);
+ if (aData)
+ GlobalDeleteAtom (aData);
+
+ return TRUE;
+
+}
+
+
+
+//SendDataMsg: Send data to the clients, if the data change options
+//match the data advise options.
+
+BOOL FAR PASCAL SendDataMsg (hwnd, lpstr, hclinfo)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hclinfo;
+{
+ PCLINFO pclinfo = NULL;
+ HANDLE hdde = NULL;
+ ATOM aData = NULL;
+ int retval;
+ HANDLE hdata;
+ LPCLIENT lpclient;
+
+
+ if (!(pclinfo = (PCLINFO) LocalLock (hclinfo)))
+ goto errRtn;
+
+ lpclient = (LPCLIENT)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ ASSERT ((CheckPointer(lpclient, WRITE_ACCESS)),
+ "In Item the client handle missing")
+#endif
+
+ // if the client dead, then no message
+ if (!IsWindowValid(pclinfo->hwnd))
+ goto errRtn;
+
+ if (pclinfo->options & (0x0001 << enummsg)) {
+ fAdviseSaveItem = TRUE;
+ SendDevInfo (lpclient, lpstr);
+
+ // send message if the client needs data for every change or
+ // only for the selective ones he wants.
+
+ // now look for the data option.
+ if (pclinfo->bnative){
+ // prepare native data
+ if (pclinfo->bdata){
+
+ // Wants the data with DDE_DATA message
+ // Get native data from the server.
+
+#ifdef FIREWALLS
+ if (!CheckPointer (enumlpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBECT")
+ else if (!CheckPointer (enumlpoleobject->lpvtbl,WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (enumlpoleobject->lpvtbl->GetData,
+ "Invalid pointer to GetData method")
+#endif
+
+ retval = (*enumlpoleobject->lpvtbl->GetData) (enumlpoleobject,
+ (int)cfNative, (LPHANDLE)& hdata);
+#ifdef FIREWALLS
+ ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY");
+#endif
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ // Prepare the DDE data block.
+ if(!MakeDDEData (hdata, (int)cfNative, (LPHANDLE)&hdde, FALSE))
+ goto errRtn;
+
+ }
+
+
+ // Make the item atom with the options.
+ aData = MakeDataAtom (lpclient->aItem, enummsg);
+ // Post the message
+ if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA,
+ (HWND)GetParent (hwnd), MAKELONG (hdde, aData)))
+ goto errRtn;
+ hdde = NULL;
+ aData = NULL;
+ }
+
+ // Now post the data for the disply format
+ if (pclinfo->format){
+ if (pclinfo->bdata){
+#ifdef FIREWALLS
+ if (!CheckPointer (enumlpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBECT")
+ else if (!CheckPointer (enumlpoleobject->lpvtbl,WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (enumlpoleobject->lpvtbl->GetData,
+ "Invalid pointer to GetData method")
+#endif
+ retval = (*enumlpoleobject->lpvtbl->GetData) (enumlpoleobject,
+ pclinfo->format, (LPHANDLE)& hdata);
+
+#ifdef FIREWALLS
+ ASSERT (retval != OLE_BUSY, "Getdata returns with OLE_BUSY");
+#endif
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ if (pclinfo->format == CF_METAFILEPICT)
+ ChangeOwner (hdata);
+
+ if(!MakeDDEData (hdata, pclinfo->format, (LPHANDLE)&hdde, FALSE))
+ goto errRtn;
+
+ }
+
+ // atom is deleted. So, we need to duplicate for every post
+ aData = MakeDataAtom (lpclient->aItem, enummsg);
+ // now post the message to the client;
+ if (!PostMessageToClientWithBlock (pclinfo->hwnd, WM_DDE_DATA,
+ (HWND)GetParent (hwnd), MAKELONG (hdde, aData)))
+ goto errRtn;
+
+ hdde = NULL;
+ aData = NULL;
+
+ }
+
+ }
+
+
+errRtn:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (hdde)
+ GlobalFree (hdde);
+
+ if (aData)
+ GlobalDeleteAtom (aData);
+
+ return TRUE;
+
+}
+
+
+// IsAdviseStdItems: returns true if the item is one of the standard items
+// StdDocName;
+BOOL INTERNAL IsAdviseStdItems (aItem)
+ATOM aItem;
+{
+
+ if ( aItem == aStdDocName)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+// GetStdItemIndex: returns index to Stditems in the "stdStrTable" if the item
+// is one of the standard items StdHostNames, StdTargetDevice,
+// StdDocDimensions, StdColorScheme
+
+int INTERNAL GetStdItemIndex (aItem)
+ATOM aItem;
+{
+ char str[MAX_STR];
+
+ if (!aItem)
+ return NULL;
+
+ if (!GlobalGetAtomName (aItem, (LPSTR) str, MAX_STR))
+ return NULL;
+
+ if (!lstrcmpi (str, stdStrTable[STDTARGETDEVICE]))
+ return STDTARGETDEVICE;
+ else if (!lstrcmpi (str, stdStrTable[STDHOSTNAMES]))
+ return STDHOSTNAMES;
+ else if (!lstrcmpi (str, stdStrTable[STDDOCDIMENSIONS]))
+ return STDDOCDIMENSIONS;
+ else if (!lstrcmpi (str, stdStrTable[STDCOLORSCHEME]))
+ return STDCOLORSCHEME;
+
+ return NULL;
+}
+
+
+// PokeStdItems: Pokes the data for the standard items.
+// For StdHostnames, StdDocDimensions and SetColorScheme the data is
+// sent immediately and for the the StdTargetDeviceinfo the
+// data is set in each client block and the data is sent just
+// before the GetData call for rendering the right data.
+
+
+OLESTATUS INTERNAL PokeStdItems (lpdoc, hwndClient, lparam)
+LPDOC lpdoc;
+HWND hwndClient;
+LONG lparam;
+{
+ int index;
+ DDEDATA FAR * lpdata = NULL;
+ HANDLE hdata = NULL;
+ HANDLE hnew = NULL;
+ LPOLESERVERDOC lpoledoc;
+ LPHOSTNAMES lphostnames;
+ OLESTATUS retval = OLE_ERROR_MEMORY;
+ int format;
+ BOOL fRelease;
+ RECT rcDoc;
+
+ index = HIWORD(lparam);
+ hdata = (HANDLE)(LOWORD (lparam));
+ if(!(hdata && (lpdata = (DDEDATA FAR *)GlobalLock (hdata))))
+ goto errRtn;
+
+ format = lpdata->cfFormat;
+ fRelease = lpdata->fRelease;
+
+#ifdef FIREWALSS
+ ASSERT (format == (int)cfBinary, "Format is not binary");
+#endif
+
+ // we have extracted the data successfully.
+ lpoledoc = lpdoc->lpoledoc;
+#ifdef FIREWALLS
+ if (!CheckPointer (lpoledoc, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOC")
+ else if (!CheckPointer (lpoledoc->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
+#endif
+
+ if (index == STDHOSTNAMES){
+ lphostnames = (LPHOSTNAMES)lpdata->Value;
+#ifdef FIREWALLS
+ ASSERT (lpoledoc->lpvtbl->SetHostNames,
+ "Invalid pointer to SetHostNames method")
+#endif
+ retval = (*lpoledoc->lpvtbl->SetHostNames)(lpdoc->lpoledoc,
+ (LPSTR)lphostnames->data,
+ ((LPSTR)lphostnames->data) +
+ lphostnames->documentNameOffset);
+ goto end;
+ }
+
+ if (index == STDDOCDIMENSIONS){
+#ifdef FIREWALLS
+ ASSERT (lpoledoc->lpvtbl->SetDocDimensions,
+ "Invalid pointer to SetDocDimensions method")
+#endif
+ rcDoc.left = 0;
+ rcDoc.top = ((LPRECT)(lpdata->Value))->top;
+ rcDoc.bottom = 0;
+ rcDoc.right = ((LPRECT)lpdata->Value)->left;
+
+ retval = (*lpoledoc->lpvtbl->SetDocDimensions)(lpdoc->lpoledoc,
+ (LPRECT)&rcDoc);
+
+ goto end;
+
+ }
+
+ if (index == STDCOLORSCHEME) {
+#ifdef FIREWALLS
+ ASSERT (lpoledoc->lpvtbl->SetColorScheme,
+ "Invalid pointer to SetColorScheme method")
+#endif
+ retval = (*lpoledoc->lpvtbl->SetColorScheme)(lpdoc->lpoledoc,
+ (LPLOGPALETTE) lpdata->Value);
+ goto end;
+ }
+#ifdef FIREWALLS
+ ASSERT (index == STDTARGETDEVICE, "Unknown standard item");
+#endif
+
+ // case of the printer decvice info
+
+ if (!(hnew = MakeItemData ((DDEPOKE FAR *)lpdata, hdata, format)))
+ goto errRtn;
+
+ // Go thru the all the items lists for this doc and replace the
+ // printer device info information.
+ // Free the block we duplicated.
+ retval = SetStdInfo (lpdoc, hwndClient,
+ (LPSTR) (MAKELONG(STDTARGETDEVICE,0)),hnew);
+
+
+end:
+errRtn:
+ if (hnew)
+ // can only be global memory block
+ GlobalFree (hnew);
+
+ if (lpdata) {
+ GlobalUnlock (hdata);
+ if (retval == OLE_OK && fRelease)
+ GlobalFree (hdata);
+ }
+ return retval;
+}
+
+
+// SetStdInfo: Sets the targetdevice info. Creates a client
+// for "StdTargetDevice". This item is created only within the
+// lib and it is never visible in server app. When the change
+// message comes from the server app, before we ask for
+// the data, we send the targetdevice info if there is
+// info for the client whom we are trying to send the data
+// on advise.
+
+
+int INTERNAL SetStdInfo (lpdoc, hwndClient, lpitemname, hdata)
+LPDOC lpdoc;
+HWND hwndClient;
+LPSTR lpitemname;
+HANDLE hdata;
+{
+ HWND hwnd;
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+ LPCLIENT lpclient;
+ OLESTATUS retval = OLE_OK;
+
+
+ // first create/find the StdTargetDeviceItem.
+
+ if ((hwnd = SearchItem (lpdoc, lpitemname))
+ == NULL){
+ retval = RegisterItem ((LHDOC)lpdoc, lpitemname,
+ (LPCLIENT FAR *)&lpclient, FALSE);
+
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ hwnd = lpclient->hwnd;
+
+ }
+
+#ifdef FIREWALLS
+ ASSERT (retval == OLE_OK, "No StdTragetDevice or StdDocname item");
+#endif
+
+
+ if(hclinfo = FindClient (hwnd, hwndClient)){
+ if (pclinfo = (PCLINFO) LocalLock (hclinfo)){
+ if (pclinfo->hdevInfo)
+ GlobalFree (pclinfo->hdevInfo);
+ pclinfo->bnewDevInfo = TRUE;
+ if (hdata)
+ pclinfo->hdevInfo = DuplicateData (hdata);
+ else
+ pclinfo->hdevInfo = NULL;
+ pclinfo->hwnd = hwndClient;
+ LocalUnlock (hclinfo);
+
+ // We do not have to reset the client because we did not
+ // change the handle it self.
+ }
+ } else {
+ // Create the client structure to be attcahed to the object.
+ hclinfo = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof (CLINFO));
+ if (hclinfo == NULL || (pclinfo = (PCLINFO) LocalLock (hclinfo)) == NULL)
+ goto errRtn;
+
+ pclinfo->bnewDevInfo = TRUE;
+ if (hdata)
+ pclinfo->hdevInfo = DuplicateData (hdata);
+ else
+ pclinfo->hdevInfo = NULL;
+
+ pclinfo->hwnd = hwndClient;
+ LocalUnlock (hclinfo);
+
+
+ // Now add this client to item client list
+ // !!! This error recovery is not correct.
+ if (!AddClient (hwnd, hwndClient, hclinfo))
+ goto errRtn;
+
+ }
+ return OLE_OK;
+errRtn:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ if (hclinfo)
+ LocalFree (hclinfo);
+ return OLE_ERROR_MEMORY;
+}
+
+
+// SendDevInfo: Sends targetdevice info to the the object.
+// Caches the last targetdevice info sent to the object.
+// If the targetdevice block is same as the one in the
+// cache, then no targetdevice info is sent.
+// (!!! There might be some problem here getting back
+// the same global handle).
+
+void INTERNAL SendDevInfo (lpclient, lppropname)
+LPCLIENT lpclient;
+LPSTR lppropname;
+{
+
+ HANDLE hclinfo = NULL;
+ PCLINFO pclinfo = NULL;
+ HANDLE hdata;
+ OLESTATUS retval;
+ HWND hwnd;
+ LPDOC lpdoc;
+
+
+
+ lpdoc = (LPDOC)GetWindowLong (GetParent (lpclient->hwnd), 0);
+
+ // find if any StdTargetDeviceInfo item is present at all
+ hwnd = SearchItem (lpdoc, (LPSTR) (MAKELONG(STDTARGETDEVICE, 0)));
+ if (hwnd == NULL)
+ return;
+
+ hclinfo = GetProp (hwnd, lppropname);
+
+ // This client has not set any target device info. no need to send
+ // any stdtargetdevice info
+ if (hclinfo != NULL) {
+ if (!(pclinfo = (PCLINFO)LocalLock (hclinfo)))
+ goto end;
+
+ // if we cached it, do not send it again.
+ if ((!pclinfo->bnewDevInfo) && pclinfo->hdevInfo == lpclient->hdevInfo)
+ goto end;
+
+ pclinfo->bnewDevInfo = FALSE;
+ if(!(hdata = DuplicateData (pclinfo->hdevInfo)))
+ goto end;
+ } else {
+
+ // already screen
+ if (!lpclient->hdevInfo)
+ goto end;
+
+ //for screen send NULL.
+ hdata = NULL;
+ }
+
+
+ // Now send the targetdevice info
+#ifdef FIREWALLS
+ if (!CheckPointer (lpclient->lpoleobject, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBECT")
+ else if (!CheckPointer (lpclient->lpoleobject->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLEOBJECTVTBL")
+ else
+ ASSERT (lpclient->lpoleobject->lpvtbl->SetTargetDevice,
+ "Invalid pointer to SetTargetDevice method")
+#endif
+ retval = (*lpclient->lpoleobject->lpvtbl->SetTargetDevice)
+ (lpclient->lpoleobject, hdata);
+
+ if (retval == OLE_OK) {
+ if (pclinfo)
+ lpclient->hdevInfo = pclinfo->hdevInfo;
+ else
+ lpclient->hdevInfo = NULL;
+
+ }
+ // !!! error case who frees the data?'
+
+end:
+ if (pclinfo)
+ LocalUnlock (hclinfo);
+
+ return;
+}
+
+void ChangeOwner (hmfp)
+HANDLE hmfp;
+{
+ LPMETAFILEPICT lpmfp;
+
+ if (lpmfp = (LPMETAFILEPICT) GlobalLock (hmfp)) {
+ if (bWin30)
+ GiveToGDI (lpmfp->hMF);
+ else {
+ if (lpfnSetMetaFileBitsBetter)
+ (*lpfnSetMetaFileBitsBetter) (lpmfp->hMF);
+ }
+
+ GlobalUnlock (hmfp);
+ }
+}
+
+
+HANDLE INTERNAL MakeItemData (lpPoke, hPoke, cfFormat)
+DDEPOKE FAR * lpPoke;
+HANDLE hPoke;
+OLECLIPFORMAT cfFormat;
+{
+ HANDLE hnew;
+ LPSTR lpnew;
+ DWORD dwSize;
+
+ if (cfFormat == CF_METAFILEPICT)
+ return DuplicateMetaFile (*(LPHANDLE)lpPoke->Value);
+
+ if (cfFormat == CF_BITMAP)
+ return DuplicateBitmap (*(LPHANDLE)lpPoke->Value);
+
+ if (cfFormat == CF_DIB)
+ return DuplicateData (*(LPHANDLE)lpPoke->Value);
+
+ // Now we are dealing with normal case
+ if (!(dwSize = GlobalSize (hPoke)))
+ return NULL;
+
+ dwSize = dwSize - sizeof (DDEPOKE) + sizeof(BYTE);
+
+ if (hnew = GlobalAlloc (GMEM_MOVEABLE, dwSize)) {
+ if (lpnew = GlobalLock (hnew)) {
+ UtilMemCpy (lpnew, (LPSTR) lpPoke->Value, dwSize);
+ GlobalUnlock (hnew);
+ }
+ else {
+ GlobalFree (hnew);
+ hnew = NULL;
+ }
+ }
+
+ return hnew;
+}
+
+
+
+HANDLE INTERNAL DuplicateMetaFile (hSrcData)
+HANDLE hSrcData;
+{
+ LPMETAFILEPICT lpSrcMfp;
+ LPMETAFILEPICT lpDstMfp = NULL;
+ HANDLE hMF = NULL;
+ HANDLE hDstMfp = NULL;
+
+ if (!(lpSrcMfp = (LPMETAFILEPICT) GlobalLock(hSrcData)))
+ return NULL;
+
+ GlobalUnlock (hSrcData);
+
+ if (!(hMF = CopyMetaFile (lpSrcMfp->hMF, NULL)))
+ return NULL;
+
+ if (!(hDstMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT))))
+ goto errMfp;
+
+ if (!(lpDstMfp = (LPMETAFILEPICT) GlobalLock (hDstMfp)))
+ goto errMfp;
+
+ GlobalUnlock (hDstMfp);
+
+ *lpDstMfp = *lpSrcMfp;
+ lpDstMfp->hMF = hMF;
+ return hDstMfp;
+errMfp:
+ if (hMF)
+ DeleteMetaFile (hMF);
+
+ if (hDstMfp)
+ GlobalFree (hDstMfp);
+
+ return NULL;
+}
+
+
+
+HBITMAP INTERNAL DuplicateBitmap (hold)
+HBITMAP hold;
+{
+ HBITMAP hnew;
+ HANDLE hMem;
+ LPSTR lpMem;
+ LONG retVal = TRUE;
+ DWORD dwSize;
+ BITMAP bm;
+
+ // !!! another way to duplicate the bitmap
+
+ GetObject (hold, sizeof(BITMAP), (LPSTR) &bm);
+ dwSize = ((DWORD) bm.bmHeight) * ((DWORD) bm.bmWidthBytes) *
+ ((DWORD) bm.bmPlanes) * ((DWORD) bm.bmBitsPixel);
+
+ if (!(hMem = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize)))
+ return NULL;
+
+ if (!(lpMem = GlobalLock (hMem))){
+ GlobalFree (hMem);
+ return NULL;
+ }
+
+ GetBitmapBits (hold, dwSize, lpMem);
+ if (hnew = CreateBitmap (bm.bmWidth, bm.bmHeight,
+ bm.bmPlanes, bm.bmBitsPixel, NULL))
+ retVal = SetBitmapBits (hnew, dwSize, lpMem);
+
+ GlobalUnlock (hMem);
+ GlobalFree (hMem);
+
+ if (hnew && (!retVal)) {
+ DeleteObject (hnew);
+ hnew = NULL;
+ }
+
+ return hnew;
+}
+
+
+
diff --git a/private/mvdm/wow16/ole/server/makefile b/private/mvdm/wow16/ole/server/makefile
new file mode 100644
index 000000000..3dc7d7015
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/makefile
@@ -0,0 +1,95 @@
+#
+# Make file for srvr library
+#
+
+# Flags set assuming small model
+
+INCLUDE=-I..\..\inc -I..\..\..\inc
+
+
+LIBS= ..\..\lib\sdllcew ..\..\lib\libw ..\..\lib\shell
+LIBENTRY_OBJ=..\..\lib\libentry.obj
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+DEBUG=1
+CDEBUG = /Od /Oi /Zd
+ADEBUG = -Zd
+LDEBUG = /LI
+!endif
+
+!ifdef DEBUG
+BLD=debug
+CFLAGS=-c -ASw -G2sw -Zpe -I..\client -DDEBUG -DFIREWALLS -DSERVERONLY $(INCLUDE) $(CDEBUG)
+LFLAGS=/NOD /NOE /M $(LDEBUG)
+AFLAGS= -D?WIN=1 -W2 $(INCLUDE) $(ADEBUG)
+!else
+BLD=retail
+CFLAGS=-c -ASw -Ox -G2sw -Zpe -I..\client -DSERVERONLY $(INCLUDE)
+LFLAGS=/NOD /NOE /M
+AFLAGS= -D?WIN=1 -W2 $(INCLUDE)
+!endif
+
+SRVR_OBJ= $(BLD)\srvrmain.obj $(BLD)\srvr.obj $(BLD)\doc.obj $(BLD)\item.obj \
+ $(BLD)\utils.obj $(BLD)\block.obj $(BLD)\olesvr.obj \
+ $(BLD)\give2gdi.obj
+
+
+ALL: $(BLD)\olesvr.dll $(BLD)\olesvr.lib
+
+clean: cleanup all
+
+cleanup:
+ if exist *.obj del *.obj
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+srvr.res: srvr.rc olesvr.rcv
+ rc16 -r $(INCLUDE) srvr.rc $@
+
+$(BLD)\olesvr.lib: olesvr.def
+ mkpublic olesvr.def stripped.def
+ implib $@ stripped.def
+ del stripped.def
+
+$(BLD)\olesvr.obj: olesvr.asm
+ masm -D?PLM=0 $(AFLAGS) olesvr.asm, $@;
+
+$(BLD)\give2gdi.obj: give2gdi.asm
+ masm -D?PLM=1 $(AFLAGS) give2gdi.asm, $@;
+
+{}.c{$(BLD)}.obj:
+ cl16 $(CFLAGS) $<
+ copy $(@B).obj $(BLD)
+ del $(@B).obj
+
+$(BLD)\olesvr.dll: $(SRVR_OBJ) srvr.res olesvr.def
+ link16 $(LFLAGS) @<<
+$(SRVR_OBJ) $(LIBENTRY_OBJ)
+$(BLD)\olesvr.dll
+$(BLD)\olesvr.map
+$(LIBS)
+olesvr.def;
+<<
+ -@ cd $(BLD)
+ rc16 -t -30 $(INCLUDE) ..\srvr.res olesvr.dll
+ mapsym olesvr
+ -binplace olesvr.dll olesvr.map olesvr.sym
+ -@ cd..
+
+HEADERS = srvr.h ..\client\ole.h ..\client\cmacs.h
+srvrmain.c: $(HEADERS)
+srvr.c: $(HEADERS)
+doc.c.c: $(HEADERS)
+item.c: $(HEADERS)
+utils.c: $(HEADERS)
+block.c: $(HEADERS)
+#olesvr.rcv: ver.h
diff --git a/private/mvdm/wow16/ole/server/olesvr.asm b/private/mvdm/wow16/ole/server/olesvr.asm
new file mode 100644
index 000000000..6bce6a452
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/olesvr.asm
@@ -0,0 +1,61 @@
+ ;\
+ ; ole.asm
+ ;
+ ; Copyright (C) 1991, MicroSoft Corporation
+ ;
+ ; Contains pointer vaildation routine
+ ;
+ ; History: sriniK 02/26/1991 original
+ ;/
+
+.286p
+.MODEL SMALL
+.CODE
+
+;**************************** _CheckPointer ****************************
+;
+; WORD CheckPointer (lp, access)
+;
+; Args:
+; lp pointer to be verified
+; access 0 test the pointer for read access
+; 1 test the pointer for write access
+; returns:
+; FALSE invalid pointer
+; TRUE valid pointer
+;
+;
+;
+ public _CheckPointer
+
+_CheckPointer proc
+
+ push bp
+ mov bp, sp
+
+ xor ax, ax
+ and word ptr [bp+8], -1
+ jnz check_write_access
+
+ verr word ptr [bp+6] ; check selector for read access
+ jnz error
+ jmp short check_offset
+
+check_write_access:
+ verw word ptr [bp+6] ; check selector for write access
+ jnz error
+
+check_offset:
+ lsl bx, word ptr [bp+6] ; segment limit gets copied into BX
+ jnz error
+ cmp [bp+4], bx
+ ja error
+ or ax, -1
+error:
+ pop bp
+ ret
+
+_CheckPointer endp
+ end
+
+
diff --git a/private/mvdm/wow16/ole/server/olesvr.def b/private/mvdm/wow16/ole/server/olesvr.def
new file mode 100644
index 000000000..1adad0886
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/olesvr.def
@@ -0,0 +1,48 @@
+LIBRARY OLESVR INITINSTANCE
+
+DESCRIPTION "OLE Server. (c) Copyright Microsoft Corp. 1990 - All Rights Reserved";
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+CODE MOVABLE DISCARDABLE
+DATA MOVABLE SINGLE
+
+SEGMENTS
+ WEP_TEXT CLASS 'CODE' FIXED
+ Give2GDI CLASS 'CODE' FIXED
+
+
+HEAPSIZE 8000
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+
+ OLEREGISTERSERVER @2
+ OLEREVOKESERVER @3
+
+ OLEBLOCKSERVER @4
+ OLEUNBLOCKSERVER @5
+
+ OLEREGISTERSERVERDOC @6
+ OLEREVOKESERVERDOC @7
+ OLERENAMESERVERDOC @8
+ OLEREVERTSERVERDOC @9
+ OLESAVEDSERVERDOC @10
+
+ OLEREVOKEOBJECT @11
+ OLEQUERYSERVERVERSION @12
+
+ SrvrWndProc @21 ;Internal
+ DocWndProc @22 ;Internal
+ ItemWndProc @23 ;Internal
+
+ SendDataMsg @24 ;Internal
+ FindItemWnd @25 ;Internal
+ ItemCallBack @26 ;Internal
+ TerminateClients @27 ;Internal
+ TerminateDocClients @28 ;Internal
+ DeleteClientInfo @29 ;Internal
+ SendRenameMsg @30 ;Internal
+ EnumForTerminate @31 ;Internal
diff --git a/private/mvdm/wow16/ole/server/olesvr.rcv b/private/mvdm/wow16/ole/server/olesvr.rcv
new file mode 100644
index 000000000..a12caff97
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/olesvr.rcv
@@ -0,0 +1,58 @@
+#include <ver.h>
+#include <version.h>
+
+#ifdef NT
+#define OLEVER_FILEOS VOS__WINDOWS32
+#define OLEVER_FILEVERSION 1,11,000
+#define OLEVER_FILEVERSION_STR "1.11.000\0"
+#else
+#define OLEVER_FILEOS VOS_DOS_WINDOWS16
+#define OLEVER_FILEVERSION 1,11,000
+#define OLEVER_FILEVERSION_STR "1.11.000\0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION OLEVER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK 0x0000003FL
+FILEFLAGS VER_FILEFLAGS
+FILEOS OLEVER_FILEOS
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0"
+ VALUE "FileDescription", "Object Linking and Embedding Server Library\0"
+ VALUE "FileVersion", OLEVER_FILEVERSION_STR
+ VALUE "InternalName", "OLESVR\0"
+ VALUE "LegalCopyright", "Copyright \251 Microsoft Corp. 1991-1996\0"
+ VALUE "OriginalFilename", "OLESVR.DLL\0"
+ VALUE "ProductName", "Microsoft Object Linking and Embedding Libraries for Windows"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ VALUE "WOW Version", "4.0", "\0"
+ END
+#ifdef INTL
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0"
+ VALUE "FileDescription", "Object Linking and Embedding Server Library\0"
+ VALUE "FileVersion", OLEVER_FILEVERSION_STR
+ VALUE "InternalName", "OLESVR\0"
+ VALUE "LegalCopyright", "Copyright \251 Microsoft Corp. 1991-1996\0"
+ VALUE "OriginalFilename", "OLESVR.DLL\0"
+ VALUE "ProductName", "Microsoft Object Linking and Embedding Libraries for Windows"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ VALUE "WOW Version", "4.0", "\0"
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 1252
+ END
+
+END
diff --git a/private/mvdm/wow16/ole/server/olever.h b/private/mvdm/wow16/ole/server/olever.h
new file mode 100644
index 000000000..a84e7261c
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/olever.h
@@ -0,0 +1,38 @@
+#include <ver.h>
+
+#ifndef DEBUG
+#define OLEVER_DEBUG 0
+#else
+#define OLEVER_DEBUG 1
+#endif
+
+
+#ifndef OFFICIAL
+#define OLEVER_PRIVATEBUILD 1
+#else
+#define OLEVER_PRIVATEBUILD 0
+#endif
+
+
+#ifndef FINAL
+#define OLEVER_PRERELEASE 1
+#else
+#define OLEVER_PRERELEASE 0
+#endif
+
+#define OLEVER_FILEFLAGS (OLEVER_PRIVATEBUILD|OLEVER_PRERELEASE|OLEVER_DEBUG)
+
+#ifdef NT
+#define OLEVER_FILEOS VOS_WINDOWS32
+#define OLEVER_FILEVERSION 1,03, 001
+#define OLEVER_PRODUCTVERSION 3,10,0,043
+#elseif PWIN
+#define OLEVER_FILEOS VOS_DOS_WINDOWS16
+#define OLEVER_FILEVERSION 1,10
+#define OLEVER_PRODUCTVERSION 3,10,0,043
+#else
+#define OLEVER_FILEOS VOS_DOS_WINDOWS16
+#define OLEVER_FILEVERSION 1,03, 001
+#define OLEVER_PRODUCTVERSION 3,10,0,043
+#endif
+
diff --git a/private/mvdm/wow16/ole/server/srvr.c b/private/mvdm/wow16/ole/server/srvr.c
new file mode 100644
index 000000000..4ddb7c5c5
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/srvr.c
@@ -0,0 +1,1136 @@
+/****************************** Module Header ******************************\
+* Module Name: Srvr.c Server Main module
+*
+* Purpose: Includes All the server communication related routines.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1985, 1986, 1987, 1988, 1989 Microsoft Corporation
+*
+* History:
+* Raor: Wrote the original version.
+*
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include <shellapi.h>
+#include "cmacs.h"
+#include "ole.h"
+#include "dde.h"
+#include "srvr.h"
+
+// LOWWORD - BYTE 0 major verision, BYTE1 minor version,
+// HIWORD is reserved
+
+#define OLE_VERSION 0x1001L
+
+
+extern ATOM aOLE;
+extern ATOM aSysTopic;
+extern ATOM aStdExit;
+extern ATOM aStdCreate;
+extern ATOM aStdOpen;
+extern ATOM aStdEdit;
+extern ATOM aStdCreateFromTemplate;
+extern ATOM aStdShowItem;
+extern ATOM aProtocols;
+extern ATOM aTopics;
+extern ATOM aFormats;
+extern ATOM aStatus;
+extern ATOM cfNative;
+extern ATOM aEditItems;
+extern ATOM aStdClose;
+
+
+extern HANDLE hdllInst;
+extern BOOL bProtMode;
+
+extern FARPROC lpTerminateClients;
+
+#ifdef FIREWALLS
+BOOL bShowed = FALSE;
+void ShowVersion (void);
+#endif
+
+
+DWORD FAR PASCAL OleQueryServerVersion ()
+{
+ return OLE_VERSION;
+}
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRegisterServer (lpclass, lpolesrvr, lplhsrvr)
+*
+* OleRegisterServer: Registers the server with the server library.
+*
+* Parameters:
+* 1. Ptr to the server class.
+* 2. Ptr to the olesrvr. This is private to the server app.
+* (Typically this is the ptr to the private storage area of
+* server app server related info).
+* 3. Ptr to the LHSRVR. Place where to pass back the long
+* handle of the server in DLL (This is private to the DLL).
+*
+* return values:
+* returns OLE_OK if the server is successfully registered .
+* else returns the corresponding error.
+*
+*
+* History:
+* Raor: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRegisterServer (lpclass, lpolesrvr, lplhsrvr, hInst, useFlags)
+LPSTR lpclass; // class name
+LPOLESERVER lpolesrvr; // ole srvr(private to srvr app)
+LHSRVR FAR * lplhsrvr; // where we pass back our private handle
+HANDLE hInst;
+OLE_SERVER_USE useFlags;
+{
+
+ HANDLE hsrvr = NULL;
+ LPSRVR lpsrvr = NULL;
+ ATOM aExe = NULL;
+
+ Puts ("OleRegisterServer");
+
+ if (!bProtMode)
+ return OLE_ERROR_PROTECT_ONLY;
+
+ PROBE_READ(lpclass);
+ PROBE_WRITE(lpolesrvr);
+ PROBE_WRITE(lplhsrvr);
+
+ // add the app atom to global list
+ if (!ValidateSrvrClass (lpclass, &aExe))
+ return OLE_ERROR_CLASS;
+
+ hsrvr = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_DDESHARE, sizeof (SRVR));
+ if (! (hsrvr && (lpsrvr = (LPSRVR)GlobalLock (hsrvr))))
+ goto errReturn;
+
+ // set the signature handle and the app atom.
+ lpsrvr->sig[0] = 'S';
+ lpsrvr->sig[1] = 'R';
+ lpsrvr->hsrvr = hsrvr;
+ lpsrvr->aClass = GlobalAddAtom (lpclass);
+ lpsrvr->lpolesrvr = lpolesrvr;
+ lpsrvr->relLock = TRUE; // set the release lock.
+ lpsrvr->aExe = aExe;
+ lpsrvr->useFlags = useFlags;
+
+#ifdef FIREWALLS
+ ASSERT ((useFlags == OLE_SERVER_SINGLE || useFlags == OLE_SERVER_MULTI), "invalid server options");
+#endif
+
+ // Create the servre window and do not show it.
+ if (!(lpsrvr->hwnd = CreateWindow ("SrvrWndClass", "Srvr",
+ WS_OVERLAPPED,0,0,0,0,NULL,NULL, hdllInst, NULL)))
+ goto errReturn;
+
+ // save the ptr to the srever struct in the window.
+ SetWindowLong (lpsrvr->hwnd, 0, (LONG)lpsrvr);
+
+ // Set the signature.
+ SetWindowWord (lpsrvr->hwnd, WW_LE, WC_LE);
+ SetWindowWord (lpsrvr->hwnd, WW_HANDLE, (WORD)hInst);
+ *lplhsrvr = (LONG)lpsrvr;
+
+ return OLE_OK;
+
+errReturn:
+ if (lpsrvr){
+ if (lpsrvr->hwnd)
+ DestroyWindow (lpsrvr->hwnd);
+
+ if (lpsrvr->aClass)
+ GlobalDeleteAtom (lpsrvr->aClass);
+
+ if (lpsrvr->aExe)
+ GlobalDeleteAtom (lpsrvr->aExe);
+
+ GlobalUnlock (hsrvr);
+ }
+
+ if (hsrvr)
+ GlobalFree (hsrvr);
+
+ return OLE_ERROR_MEMORY;
+
+}
+
+
+// ValidateSrvrClass checks whether the given server class is valid by
+// looking in the win.ini.
+
+BOOL INTERNAL ValidateSrvrClass (lpclass, lpAtom)
+LPSTR lpclass;
+ATOM FAR * lpAtom;
+{
+
+ char buf[MAX_STR];
+ LONG cb = MAX_STR;
+ char key[MAX_STR];
+ LPSTR lptmp;
+ LPSTR lpbuf;
+ char ch;
+
+ lstrcpy (key, lpclass);
+ lstrcat (key, "\\protocol\\StdFileEditing\\server");
+
+ if (RegQueryValue (HKEY_CLASSES_ROOT, key, buf, &cb))
+ return FALSE;
+
+ if (!buf[0])
+ return FALSE;
+
+ // Get exe name without path and then get an atom for that
+
+ lptmp = lpbuf = (LPSTR)buf;
+ while ((ch = *lptmp++) && ch != '\0') {
+ if (ch == '\\' || ch == ':')
+ lpbuf = lptmp;
+ }
+ *lpAtom = GlobalAddAtom (lpbuf);
+
+ return TRUE;
+}
+
+
+/***************************** Public Function ****************************\
+* OLESTATUS FAR PASCAL OleRevokeServer (lhsrvr)
+*
+* OlerevokeServer: Unregisters the server which has been registered.
+*
+* Parameters:
+* 1. DLL server handle.
+*
+*
+* return values:
+* returns OLE_OK if the server is successfully unregisterd.
+* ( It is Ok for the app free the associated space).
+* If the unregistration is intiated, returns OLE_STARTED.
+* Calls the Server class release entry point when the server
+* can be released.
+*
+* History:
+* Raor: Wrote it,
+\***************************************************************************/
+
+OLESTATUS FAR PASCAL OleRevokeServer (lhsrvr)
+LHSRVR lhsrvr;
+{
+
+ HWND hwndSrvr;
+ LPSRVR lpsrvr;
+
+ Puts ("OleRevokeServer");
+
+ if (!CheckServer (lpsrvr = (LPSRVR)lhsrvr))
+ return OLE_ERROR_HANDLE;
+
+ if (lpsrvr->bTerminate && lpsrvr->termNo)
+ return OLE_WAIT_FOR_RELEASE;
+
+ hwndSrvr = lpsrvr->hwnd;
+
+#ifdef FIREWALLS
+ ASSERT (hwndSrvr, "Illegal server handle ")
+#endif
+
+ // Terminate the conversation with all clients.
+ // If there are any clients to be terminated
+ // return back with OLE_STARTED and srvr relase
+ // will be called for releasing the server finally.
+
+ // we are terminating.
+ lpsrvr->bTerminate = TRUE;
+ lpsrvr->termNo = 0;
+
+ // send ack if Revoke is done as a result of StdExit
+ if (lpsrvr->fAckExit) {
+ // Post the acknowledge to the client
+ if (!PostMessageToClient (lpsrvr->hwndExit, WM_DDE_ACK, lpsrvr->hwnd,
+ MAKELONG (0x8000, lpsrvr->hDataExit)))
+ // if the window died or post failed, delete the atom.
+ GlobalFree (lpsrvr->hDataExit);
+ }
+
+ // revoks all the documents registered with this server.
+ RevokeAllDocs (lpsrvr);
+
+ // enumerate all the clients which are in your list and post the
+ // termination.
+ EnumProps (hwndSrvr, lpTerminateClients);
+ // post all the messages with yield which have been collected in enum
+ // UnblockPostMsgs (hwndSrvr, TRUE);
+
+ // reset the release lock. Now it is ok to release the server
+ // when all the doc clients and server clients have sent back the
+ // termination.
+
+ lpsrvr->relLock = FALSE;
+ return ReleaseSrvr (lpsrvr);
+
+}
+
+
+// ReleaseSrvr: Called when ever a matching WM_TERMINATE is received
+// from doc clients or the server clients of a particular server.
+// If there are no more terminates pending, it is ok to release the server.
+// Calls the server app "release" proc for releasing the server.
+
+int INTERNAL ReleaseSrvr (lpsrvr)
+LPSRVR lpsrvr;
+{
+
+ HANDLE hsrvr;
+
+
+ // release srvr is called only when everything is
+ // cleaned and srvr app can post WM_QUIT
+
+ if (lpsrvr->bTerminate){
+ // only if we are revoking server then see whether it is ok to
+ // call Release.
+
+ // First check whethere any docs are active.
+ // Doc window is a child window for server window.
+
+ if (lpsrvr->termNo || GetWindow (lpsrvr->hwnd, GW_CHILD))
+ return OLE_WAIT_FOR_RELEASE;
+
+ // if the block queue is not empty, do not quit
+ if (!IsBlockQueueEmpty(lpsrvr->hwnd))
+ return OLE_WAIT_FOR_RELEASE;
+
+ }
+
+ if (lpsrvr->relLock)
+ return OLE_WAIT_FOR_RELEASE; // server is locked. So, delay releasing
+
+ // Inform server app it is time to clean up and post WM_QUIT.
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
+ ASSERT(0, "Invalid LPOLESERVER")
+ else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT(0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+
+ (*lpsrvr->lpolesrvr->lpvtbl->Release)(lpsrvr->lpolesrvr);
+
+ if (lpsrvr->aClass)
+ GlobalDeleteAtom (lpsrvr->aClass);
+ if (lpsrvr->aExe)
+ GlobalDeleteAtom (lpsrvr->aExe);
+ DestroyWindow (lpsrvr->hwnd);
+ GlobalUnlock (hsrvr = lpsrvr->hsrvr);
+ GlobalFree (hsrvr);
+ return OLE_OK;
+}
+
+
+//TerminateClients: Call back for the enum properties.
+
+BOOL FAR PASCAL TerminateClients (hwnd, lpstr, hdata)
+HWND hwnd;
+LPSTR lpstr;
+HANDLE hdata;
+{
+ LPSRVR lpsrvr;
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+ // If the client already died, no terminate.
+ if (IsWindowValid ((HWND)hdata)) {
+ lpsrvr->termNo++;
+
+ // irrespective of the post, incremet the count, so
+ // that client does not die.
+
+ PostMessageToClientWithBlock ((HWND)hdata, WM_DDE_TERMINATE, hwnd, NULL);
+ }
+ else
+ ASSERT (FALSE, "TERMINATE: Client's System chanel is missing");
+
+ return TRUE;
+}
+
+
+long FAR PASCAL SrvrWndProc (hwnd, msg, wParam, lParam)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+{
+
+ LPSRVR lpsrvr;
+ WORD status = NULL;
+ HWND hwndClient;
+ HANDLE hdata;
+ OLESTATUS retval;
+
+ if (AddMessage (hwnd, msg, wParam, lParam, WT_SRVR))
+ return 0L;
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+
+ switch (msg){
+
+ case WM_TIMER:
+ UnblockPostMsgs (hwnd, FALSE);
+
+ // if no more blocked message empty the queue.
+ if (IsBlockQueueEmpty (hwnd))
+ KillTimer (hwnd, wParam);
+
+ if (lpsrvr->bTerminate && IsBlockQueueEmpty(lpsrvr->hwnd))
+ // Now see wheteher we can release the server .
+ ReleaseSrvr (lpsrvr);
+ break;
+
+ case WM_CREATE:
+ DEBUG_OUT ("Srvr create window", 0)
+ break;
+
+ case WM_DDE_INITIATE:
+#ifdef FIREWALLS
+ ASSERT (lpsrvr, "No server window handle in server window");
+#endif
+
+ DEBUG_OUT ("Srvr: DDE init",0);
+ if (lpsrvr->bTerminate){
+ DEBUG_OUT ("Srvr: No action due to termination process",0)
+ break;
+ }
+
+ // class is not matching, so it is not definitely for us.
+ // for apps sending the EXE for initiate, do not allow if the app
+ // is mutiple server.
+
+ if (!(lpsrvr->aClass == (ATOM)(LOWORD(lParam)) ||
+ (lpsrvr->aExe == (ATOM)(LOWORD(lParam)) && IsSingleServerInstance ())))
+
+ break;
+
+ if (!HandleInitMsg (lpsrvr, lParam)) {
+ if (!(aSysTopic == (ATOM)(HIWORD(lParam)))) {
+
+ // if the server window is not the right window for
+ // DDE conversation, then try with the doc windows.
+ SendMsgToChildren (hwnd, msg, wParam, lParam);
+
+ }
+ break;
+ }
+
+ // We can enterain this client. Put him in our client list
+ // and acknowledge the intiate.
+
+ if (!AddClient (hwnd, (HWND)wParam, (HWND)wParam))
+ break;
+
+ lpsrvr->cClients++;
+ lpsrvr->bnoRelease = FALSE;
+ // add the atoms and post acknowledge
+
+ DuplicateAtom (LOWORD(lParam));
+ DuplicateAtom (HIWORD(lParam));
+
+ SendMessage ((HWND)wParam, WM_DDE_ACK, (WORD)hwnd, lParam);
+ break;
+
+ case WM_DDE_EXECUTE:
+#ifdef FIREWALLS
+ ASSERT (lpsrvr, "No server window handle in server window");
+#endif
+ DEBUG_OUT ("srvr: execute", 0)
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->hwnd, (HWND)wParam);
+ ASSERT (hwndClient, "Client is missing from the server")
+#endif
+ // Are we terminating
+ if (lpsrvr->bTerminate) {
+ DEBUG_OUT ("Srvr: sys execute after terminate posted",0)
+ // !!! are we supposed to free the data
+ GlobalFree (HIWORD(lParam));
+ break;
+ }
+
+
+ retval = SrvrExecute (hwnd, HIWORD (lParam), (HWND)wParam);
+ SET_MSG_STATUS (retval, status)
+
+ if (!lpsrvr->bTerminate) {
+ // Post the acknowledge to the client
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG (status, HIWORD(lParam))))
+ // if the window died or post failed, delete the atom.
+ GlobalFree (HIWORD(lParam));
+ }
+
+ break;
+
+ case WM_DDE_TERMINATE:
+ DEBUG_OUT ("Srvr: DDE terminate",0)
+
+#ifdef FIREWALLS
+ // find the client in the client list.
+ hwndClient = FindClient (lpsrvr->hwnd, (HWND)wParam);
+ ASSERT (hwndClient, "Client is missing from the server")
+#endif
+ DeleteClient (lpsrvr->hwnd, (HWND)wParam);
+ lpsrvr->cClients--;
+
+ if (lpsrvr->bTerminate){
+ if ((--lpsrvr->termNo == 0) && (IsBlockQueueEmpty (lpsrvr->hwnd)))
+ // Now see wheteher we can release the server .
+ ReleaseSrvr (lpsrvr);
+
+ // if we released the server, then
+ // by the time we come here,, we have destroyed the window
+
+ }else {
+ // If client intiated the terminate. post matching terminate
+ PostMessageToClient ((HWND)wParam, WM_DDE_TERMINATE,
+ hwnd, NULL);
+
+ // callback release tell the srvr app, it can exit if needs.
+ // Inform server app it is time to clean up and post WM_QUIT.
+ // only if no docs present.
+#if 0
+ if (lpsrvr->cClients == 0
+ && (GetWindow (lpsrvr->hwnd, GW_CHILD) == NULL)) {
+#endif
+ if (QueryRelease (lpsrvr)){
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpsrvr->lpolesrvr, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVER")
+ else if (!CheckPointer (lpsrvr->lpolesrvr->lpvtbl,
+ WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpsrvr->lpolesrvr->lpvtbl->Release,
+ "Invalid pointer to Release method")
+#endif
+
+ (*lpsrvr->lpolesrvr->lpvtbl->Release) (lpsrvr->lpolesrvr);
+ }
+ }
+ break;
+
+
+ case WM_DDE_REQUEST:
+ if (lpsrvr->bTerminate || !IsWindowValid ((HWND) wParam))
+ goto RequestErr;
+
+ if(RequestDataStd (lParam, (HANDLE FAR *)&hdata) != OLE_OK){
+ // if request failed, then acknowledge with error.
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_ACK, hwnd,
+ MAKELONG(0x8000, HIWORD(lParam))))
+
+ RequestErr:
+ if (HIWORD(lParam))
+ GlobalDeleteAtom (HIWORD(lParam));
+ } else {
+
+ // post the data message and we are not asking for any
+ // acknowledge.
+
+ if (!PostMessageToClient ((HWND)wParam, WM_DDE_DATA, hwnd,
+ MAKELONG(hdata, HIWORD(lParam)))) {
+ GlobalFree (hdata);
+ goto RequestErr;
+ }
+ }
+ break;
+
+
+
+ case WM_DESTROY:
+ DEBUG_OUT ("Srvr: Destroy window",0)
+ break;
+
+ default:
+ DEBUG_OUT ("Srvr: Default message",0)
+ return DefWindowProc (hwnd, msg, wParam, lParam);
+
+ }
+
+ return 0L;
+
+}
+
+BOOL INTERNAL HandleInitMsg (lpsrvr, lParam)
+LPSRVR lpsrvr;
+LONG lParam;
+{
+
+
+ // If it is not system or Ole, this is not the server.
+ if (!((aSysTopic == (ATOM)(HIWORD(lParam))) ||
+ (aOLE == (ATOM)(HIWORD(lParam)))))
+
+ return FALSE;
+
+
+ // single instance MDI accept
+ if (lpsrvr->useFlags == OLE_SERVER_SINGLE)
+ return TRUE;
+
+
+ // this server is multiple instance. So, check for any clients or docs.
+ if (!GetWindow (lpsrvr->hwnd, GW_CHILD) && !lpsrvr->cClients)
+ return TRUE;
+
+ return FALSE;
+
+}
+
+
+// AddClient: Adds the client as property to the server
+// window. Key is the string generated from the window
+// handle and the data is the window itself.
+
+
+BOOL INTERNAL AddClient (hwnd, hkey, hdata)
+HWND hwnd;
+HANDLE hkey;
+HANDLE hdata;
+{
+ char buf[6];
+
+ MapToHexStr ((LPSTR)buf, hkey);
+ return SetProp (hwnd, (LPSTR)buf, hdata);
+
+}
+
+
+//DeleteClient: deletes the client from the server clients list.
+
+BOOL INTERNAL DeleteClient (hwnd, hkey)
+HWND hwnd;
+HANDLE hkey;
+{
+
+ char buf[6];
+
+ MapToHexStr ((LPSTR)buf, hkey);
+ return RemoveProp (hwnd, (LPSTR)buf);
+
+
+}
+
+// FindClient: Finds whether a given client is
+// in the server client list.
+
+HANDLE INTERNAL FindClient (hwnd, hkey)
+HWND hwnd;
+HANDLE hkey;
+{
+
+ char buf[6];
+
+
+ MapToHexStr ((LPSTR)buf, hkey);
+ return GetProp (hwnd, (LPSTR)buf);
+}
+
+
+
+// SrvrExecute: takes care of the WM_DDE_EXEXCUTE for the
+// server.
+
+
+OLESTATUS INTERNAL SrvrExecute (hwnd, hdata, hwndClient)
+HWND hwnd;
+HANDLE hdata;
+HWND hwndClient;
+{
+ ATOM aCmd;
+ BOOL fActivate;
+
+ LPSTR lpdata = NULL;
+ HANDLE hdup = NULL;
+ int retval = OLE_ERROR_MEMORY;
+
+ LPSTR lpdocname;
+ LPSTR lptemplate;
+
+ LPOLESERVERDOC lpoledoc = NULL;
+ LPDOC lpdoc = NULL;
+ LPSRVR lpsrvr;
+ LPOLESERVER lpolesrvr;
+ LPSTR lpnextarg;
+ LPSTR lpclassname;
+ LPSTR lpitemname;
+ LPSTR lpopt;
+ char buf[MAX_STR];
+ WORD wCmdType;
+
+ // !!! this code can be lot simplified if we do the argument scanning
+ // seperately and return the ptrs to the args. Rewrite later on.
+
+ if (!(hdup = DuplicateData (hdata)))
+ goto errRtn;
+
+ if (!(lpdata = GlobalLock (hdup)))
+ goto errRtn;
+
+ DEBUG_OUT (lpdata, 0)
+
+ lpsrvr = (LPSRVR)GetWindowLong (hwnd, 0);
+
+#ifdef FIREWALLS
+ ASSERT (lpsrvr, "Srvr: srvr does not exist");
+#endif
+
+ lpolesrvr = lpsrvr->lpolesrvr;
+
+#ifdef FIREWALLS
+ ASSERT ((CheckPointer (lpolesrvr, WRITE_ACCESS)),
+ "Srvr: lpolesrvr does not exist");
+#endif
+
+ if (*lpdata++ != '[') // commands start with the left sqaure bracket
+ goto errRtn;
+
+ retval = OLE_ERROR_SYNTAX;
+ // scan upto the first arg
+ if (!(wCmdType = ScanCommand (lpdata, WT_SRVR, &lpdocname, &aCmd)))
+ goto errRtn;
+
+ if (wCmdType == NON_OLE_COMMAND) {
+ if (!UtilQueryProtocol (lpsrvr->aClass, PROTOCOL_EXECUTE))
+ retval = OLE_ERROR_PROTOCOL;
+ else {
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->Execute,
+ "Invalid pointer to Exit method")
+#endif
+
+ retval = (*lpolesrvr->lpvtbl->Execute) (lpolesrvr, hdata);
+ }
+
+ goto errRtn1;
+ }
+
+ if (aCmd == aStdExit){
+ if (*lpdocname)
+ goto errRtn1;
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->Exit, "Invalid pointer to Exit method")
+#endif
+ lpsrvr->fAckExit = TRUE;
+ lpsrvr->hwndExit = hwndClient;
+ lpsrvr->hDataExit = hdata;
+ retval = (*lpolesrvr->lpvtbl->Exit) (lpolesrvr);
+ lpsrvr->fAckExit = FALSE;
+ goto end2;
+ }
+
+ // scan the next argument.
+ if (!(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn;
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdShowItem("docname", "itemname"[, "true"])]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdShowItem) {
+
+ // first find the documnet. If the doc does not exist, then
+ // blow it off.
+
+ if (!(lpdoc = FindDoc (lpsrvr, lpdocname)))
+ goto errRtn1;
+
+ lpitemname = lpnextarg;
+
+ if( !(lpopt = ScanArg(lpitemname)))
+ goto errRtn1;
+
+ // scan for the optional parameter
+ // Optional can be only TRUE or FALSE.
+
+ fActivate = FALSE;
+ if (*lpopt) {
+
+ if( !(lpnextarg = ScanBoolArg (lpopt, (BOOL FAR *)&fActivate)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+ }
+
+
+ // scan it. But, igonre the arg.
+ retval = DocShowItem (lpdoc, lpitemname, !fActivate);
+ goto end2;
+
+
+
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdCloseDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdClose) {
+ if (!(lpdoc = FindDoc (lpsrvr, lpdocname)))
+ goto errRtn1;
+
+ if (*lpnextarg)
+ goto errRtn1;
+
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpdoc->lpoledoc, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOC")
+ else if (!CheckPointer (lpdoc->lpoledoc->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERDOCVTBL")
+ else
+ ASSERT (lpdoc->lpoledoc->lpvtbl->Close,
+ "Invalid pointer to Close method")
+#endif
+
+ retval = (*lpdoc->lpoledoc->lpvtbl->Close)(lpdoc->lpoledoc);
+ goto end2;
+ }
+
+
+ if (aCmd == aStdOpen) {
+ // find if any document is already open.
+ // if the doc is open, then no need to call srvr app.
+ if (FindDoc (lpsrvr, lpdocname)){
+ retval = OLE_OK;
+ goto end1;
+
+ }
+ }
+
+ if (aCmd == aStdCreate || aCmd == aStdCreateFromTemplate) {
+ lpclassname = lpdocname;
+ lpdocname = lpnextarg;
+ if( !(lpnextarg = ScanArg(lpdocname)))
+ goto errRtn1;
+
+ }
+
+ // check whether we can create/open more than one doc.
+
+ if ((lpsrvr->useFlags == OLE_SERVER_MULTI) &&
+ GetWindow (lpsrvr->hwnd, GW_CHILD))
+ goto errRtn;
+
+
+
+ // No Doc. register the document. lpoledoc is being probed
+ // for validity. So, pass some writeable ptr. It is not
+ // being used to access anything yet
+
+ if (OleRegisterServerDoc ((LHSRVR)lpsrvr, lpdocname,
+ (LPOLESERVERDOC)NULL, (LHDOC FAR *)&lpdoc))
+ goto errRtn;
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdOpenDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ // Documnet does not exit.
+
+ if(aCmd == aStdOpen) {
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->Open, "Invalid pointer to Open method")
+#endif
+
+ retval = (*lpolesrvr->lpvtbl->Open)(lpolesrvr, (LHDOC)lpdoc,
+ lpdocname, (LPOLESERVERDOC FAR *) &lpoledoc);
+ goto end;
+ }
+ else {
+ lpdoc->fEmbed = TRUE;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewDocument ("classname", "docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdCreate) {
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->Create,
+ "Invalid pointer to Create method")
+#endif
+ retval = (*lpolesrvr->lpvtbl->Create) (lpolesrvr, (LHDOC)lpdoc,
+ lpclassname, lpdocname,
+ (LPOLESERVERDOC FAR *) &lpoledoc);
+
+ goto end;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdEditDocument ("docname")]
+ //
+ //////////////////////////////////////////////////////////////////////////
+ if (aCmd == aStdEdit){
+
+ GlobalGetAtomName (lpsrvr->aClass, (LPSTR)buf, MAX_STR);
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->Edit, "Invalid pointer to Edit method")
+#endif
+
+ retval = (*lpolesrvr->lpvtbl->Edit) (lpolesrvr, (LHDOC)lpdoc,
+ (LPSTR)buf, lpdocname,
+ (LPOLESERVERDOC FAR *) &lpoledoc);
+ goto end;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ //
+ // [StdNewFormTemplate ("classname", "docname". "templatename)]
+ //
+ //////////////////////////////////////////////////////////////////////////
+
+ if (aCmd == aStdCreateFromTemplate){
+ lptemplate = lpnextarg;
+ if(!(lpnextarg = ScanArg(lpnextarg)))
+ goto errRtn;
+
+#ifdef FIREWALLS
+ if (!CheckPointer (lpolesrvr->lpvtbl, WRITE_ACCESS))
+ ASSERT (0, "Invalid LPOLESERVERVTBL")
+ else
+ ASSERT (lpolesrvr->lpvtbl->CreateFromTemplate,
+ "Invalid pointer to CreateFromTemplate method")
+#endif
+ retval = (*lpolesrvr->lpvtbl->CreateFromTemplate)(lpolesrvr,
+ (LHDOC)lpdoc, lpclassname, lpdocname, lptemplate,
+ (LPOLESERVERDOC FAR *) &lpoledoc);
+
+ goto end;
+
+ }
+
+
+ DEBUG_OUT ("Unknown command", 0);
+
+end:
+
+ if (retval != OLE_OK)
+ goto errRtn;
+
+ // Successful execute. remember the server app private doc handle here.
+
+ lpdoc->lpoledoc = lpoledoc;
+
+end1:
+ // make sure that the srg string is indeed terminated by
+ // NULL.
+ if (*lpnextarg)
+ retval = OLE_ERROR_SYNTAX;
+
+errRtn:
+
+ if ( retval != OLE_OK){
+ // delete the oledoc structure
+ if (lpdoc)
+ OleRevokeServerDoc ((LHDOC)lpdoc);
+ }
+
+end2:
+errRtn1:
+
+ if (lpdata)
+ GlobalUnlock (hdup);
+
+ if (hdup)
+ GlobalFree (hdup);
+
+ if (retval == OLE_OK)
+ lpsrvr->bnoRelease = TRUE;
+
+ return retval;
+}
+
+
+
+
+void SendMsgToChildren (hwnd, msg, wParam, lParam)
+HWND hwnd;
+unsigned msg;
+WORD wParam;
+LONG lParam;
+{
+
+ hwnd = GetWindow(hwnd, GW_CHILD);
+ while (hwnd) {
+ SendMessage (hwnd, msg, wParam, lParam);
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+}
+
+
+OLESTATUS INTERNAL RequestDataStd (lparam, lphdde)
+LONG lparam;
+LPHANDLE lphdde;
+{
+
+ char buf[MAX_STR];
+ ATOM item;
+ HANDLE hnew = NULL;
+
+ if (!(item = (ATOM)(HIWORD (lparam))))
+ goto errRtn;
+
+ GlobalGetAtomName (item, (LPSTR)buf, MAX_STR);
+
+ if (item == aEditItems){
+ hnew = MakeGlobal ((LPSTR)"StdHostNames\tStdDocDimensions\tStdTargetDevice");
+ goto PostData;
+
+ }
+
+ if (item == aProtocols) {
+ hnew = MakeGlobal ((LPSTR)"Embedding\tStdFileEditing");
+ goto PostData;
+ }
+
+ if (item == aTopics) {
+ hnew = MakeGlobal ((LPSTR)"Doc");
+ goto PostData;
+ }
+
+ if (item == aFormats) {
+ hnew = MakeGlobal ((LPSTR)"Picture\tBitmap");
+ goto PostData;
+ }
+
+ if (item == aStatus) {
+ hnew = MakeGlobal ((LPSTR)"Ready");
+ goto PostData;
+ }
+
+ // format we do not understand.
+ goto errRtn;
+
+PostData:
+
+ // Duplicate the DDE data
+ if (MakeDDEData (hnew, CF_TEXT, lphdde, TRUE)){
+ // !!! why are we duplicating the atom.
+ DuplicateAtom ((ATOM)(HIWORD (lparam)));
+ return OLE_OK;
+ }
+errRtn:
+ return OLE_ERROR_MEMORY;
+}
+
+
+BOOL INTERNAL QueryRelease (lpsrvr)
+LPSRVR lpsrvr;
+{
+
+ HWND hwnd;
+ LPDOC lpdoc;
+
+
+ // Incase the terminate is called immediately after
+ // the Std at sys level clear this.
+
+ if (lpsrvr->bnoRelease) {
+ lpsrvr->bnoRelease = FALSE;
+ return FALSE;
+ }
+
+
+ if (lpsrvr->cClients)
+ return FALSE;
+
+ hwnd = GetWindow (lpsrvr->hwnd, GW_CHILD);
+
+ // if either the server or the doc has any clients
+ // return FALSE;
+
+ while (hwnd){
+ lpdoc = (LPDOC)GetWindowLong (hwnd, 0);
+ if (lpdoc->cClients)
+ return FALSE;
+
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+ return TRUE;
+
+}
+
+
+//IsSingleServerInstance: returns true if the app is single server app else
+//false.
+
+BOOL INTERNAL IsSingleServerInstance ()
+{
+ HWND hwnd;
+ WORD cnt = 0;
+ HANDLE hTask;
+ char buf[MAX_STR];
+
+
+ hwnd = GetWindow (GetDesktopWindow(), GW_CHILD);
+ hTask = GetCurrentTask();
+
+ while (hwnd) {
+ if (hTask == GetWindowTask (hwnd)) {
+ GetClassName (hwnd, (LPSTR)buf, MAX_STR);
+ if (lstrcmp ((LPSTR)buf, SRVR_CLASS) == 0)
+ cnt++;
+ }
+ hwnd = GetWindow (hwnd, GW_HWNDNEXT);
+ }
+#ifdef FIREWALLS
+ ASSERT (cnt > 0, "srvr window instance count is zero");
+#endif
+ if (cnt == 1)
+ return TRUE;
+ else
+ return FALSE;
+
+}
diff --git a/private/mvdm/wow16/ole/server/srvr.h b/private/mvdm/wow16/ole/server/srvr.h
new file mode 100644
index 000000000..6f2fceb22
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/srvr.h
@@ -0,0 +1,294 @@
+/****************************** Module Header ******************************\
+* Module Name: srvr.h
+*
+* PURPOSE: Private definitions file for server code
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../../90,91) Original
+*
+\***************************************************************************/
+
+#define DEFSTD_ITEM_INDEX 0
+#define STDTARGETDEVICE 1
+#define STDDOCDIMENSIONS 2
+#define STDCOLORSCHEME 3
+#define STDHOSTNAMES 4
+
+
+#define PROTOCOL_EDIT ((LPSTR)"StdFileEditing")
+#define PROTOCOL_EXECUTE ((LPSTR)"StdExecute")
+
+#define SRVR_CLASS ((LPSTR)"SrvrWndClass")
+#define DOC_CLASS ((LPSTR)"DocWndClass")
+#define ITEM_CLASS ((LPSTR)"ItemWndClass")
+
+
+#define ISATOM(a) ((a >= 0xC000) && (a <= 0xFFFF))
+
+#define MAX_STR 124
+
+#define WW_LPTR 0 // ptr tosrvr/doc/item
+#define WW_LE 4 // signature
+#define WW_HANDLE 6 // instance handle
+
+#define WC_LE 0x4c45 // LE chars
+
+// If we running under WLO, the HIGHWORD of version number will be >= 0x0A00
+#define VER_WLO 0x0A00
+
+extern WORD CheckPointer (LPVOID, int);
+
+#define READ_ACCESS 0
+#define WRITE_ACCESS 1
+
+#define PROBE_READ(lp){\
+ if (!CheckPointer(lp, READ_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+#define PROBE_WRITE(lp){\
+ if (!CheckPointer(lp, WRITE_ACCESS))\
+ return OLE_ERROR_ADDRESS; \
+}
+
+#define OLE_COMMAND 1
+#define NON_OLE_COMMAND 2
+
+
+#define WT_SRVR 0 // server window
+#define WT_DOC 1 // document window
+
+#define PROBE_BLOCK(lpsrvr) { \
+ if (lpsrvr->bBlock) \
+ return OLE_ERROR_SERVER_BLOCKED; \
+}
+
+
+#define SET_MSG_STATUS(retval, status) { \
+ if (retval == OLE_OK) \
+ status |= 0x8000; \
+ if (retval == OLE_BUSY) \
+ status |= 0x4000; \
+}
+
+
+typedef LHSERVER LHSRVR;
+typedef LHSERVERDOC LHDOC;
+
+typedef struct _QUE { // nodes in Block/Unblock queue
+ HWND hwnd; //***
+ unsigned msg; // window
+ WORD wParam; // procedure parameters
+ LONG lParam; //***
+ HANDLE hqNext; // handle to next node
+} QUE;
+
+typedef QUE NEAR * PQUE;
+typedef QUE FAR * LPQUE;
+
+
+typedef struct _SRVR { /*srvr*/ // private data
+ LPOLESERVER lpolesrvr; // corresponding server
+ char sig[2]; // signature "SR"
+ HANDLE hsrvr; // global handle
+ ATOM aClass; // class atom
+ ATOM aExe;
+ HWND hwnd; // corresponding window
+ BOOL bTerminate; // Set if we are terminating.
+ int termNo; // termination count
+ BOOL relLock; // ok to release the server.
+ BOOL bnoRelease; // Block release. call
+ WORD useFlags; // instance usage flags
+ int cClients; // no of clients;
+ BOOL bBlock; // blocked if TRUE
+ BOOL bBlockedMsg; // msg from block queue if TRUE
+ HANDLE hqHead; // Head and tail of the blocked
+ HANDLE hqTail; // messages queue.
+
+ HANDLE hqPostHead; // Head and tail of the blocked post msg
+ HANDLE hqPostTail; // .
+ BOOL fAckExit;
+ HWND hwndExit;
+ HANDLE hDataExit;
+} SRVR;
+
+typedef SRVR FAR *LPSRVR;
+
+
+LONG FAR PASCAL DocWndProc (HWND, WORD, WORD, LONG);
+LONG FAR PASCAL ItemWndProc (HWND, WORD, WORD, LONG);
+LONG FAR PASCAL SrvrWndProc (HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL TerminateClients (HWND, LPSTR, HANDLE);
+void SendMsgToChildren (HWND, WORD, WORD, LONG);
+
+
+OLESTATUS INTERNAL RequestDataStd (LONG, HANDLE FAR *);
+BOOL INTERNAL ValidateSrvrClass (LPSTR, ATOM FAR *);
+ATOM INTERNAL GetExeAtom (LPSTR);
+BOOL INTERNAL AddClient (HWND, HANDLE, HANDLE);
+BOOL INTERNAL DeleteClient (HWND, HANDLE);
+HANDLE INTERNAL FindClient (HWND, HANDLE);
+BOOL INTERNAL MakeSrvrStr(LPSTR, int, LPSTR, HANDLE);
+int INTERNAL RevokeAllDocs (LPSRVR);
+int INTERNAL ReleaseSrvr (LPSRVR);
+void INTERNAL WaitForTerminate (LPSRVR);
+OLESTATUS INTERNAL SrvrExecute (HWND, HANDLE, HWND);
+BOOL INTERNAL HandleInitMsg (LPSRVR, LONG);
+BOOL INTERNAL QueryRelease (LPSRVR);
+BOOL INTERNAL IsSingleServerInstance (void);
+
+void INTERNAL MapToHexStr (LPSTR, HANDLE);
+void INTERNAL UtilMemCpy (LPSTR, LPSTR, DWORD);
+HANDLE INTERNAL DuplicateData (HANDLE);
+LPSTR INTERNAL ScanBoolArg (LPSTR, BOOL FAR *);
+LPSTR INTERNAL ScanNumArg (LPSTR, LPINT);
+LPSTR INTERNAL ScanArg(LPSTR);
+ATOM INTERNAL MakeDataAtom (ATOM, int);
+ATOM INTERNAL DuplicateAtom (ATOM);
+
+
+// doc stuff
+typedef struct _DOC { /*doc*/ // private data
+ LPOLESERVERDOC lpoledoc; // corresponding oledoc
+ char sig[2]; // signature "SD"
+ HANDLE hdoc; // global handle
+ ATOM aDoc;
+ HWND hwnd;
+ BOOL bTerminate;
+ int termNo;
+ int cClients; // no of clients;
+ BOOL fEmbed; // TRUE if embedded document
+ BOOL fAckClose;
+ HWND hwndClose;
+ HANDLE hDataClose;
+} DOC;
+
+typedef DOC FAR *LPDOC;
+
+
+LPDOC INTERNAL FindDoc (LPSRVR, LPSTR);
+int INTERNAL ReleaseDoc (LPDOC);
+OLESTATUS INTERNAL DocExecute (HWND, HANDLE, HWND);
+BOOL FAR PASCAL TerminateDocClients (HWND, LPSTR, HANDLE);
+int INTERNAL DocShowItem (LPDOC, LPSTR, BOOL);
+int INTERNAL DocDoVerbItem (LPDOC, LPSTR, WORD, BOOL, BOOL);
+
+
+// client struct definitions.
+
+typedef struct _CLIENT { /*doc*/ // private data
+ OLECLIENT oleClient; // oleclient structure
+ LPOLEOBJECT lpoleobject; // corresponding oledoc
+ HANDLE hclient; // global handle
+ ATOM aItem; // item atom or index for some std items
+ HWND hwnd; // item window
+ HANDLE hdevInfo; // latest printer dev info sent
+} CLIENT;
+
+typedef CLIENT FAR *LPCLIENT;
+
+typedef struct _CLINFO { /*clInfo*/ // client transaction info
+ HWND hwnd; // client window handle
+ BOOL bnative; // doe sthis client require native
+ int format; // dusplay format
+ int options; // transaction advise time otipns
+ BOOL bdata; // need wdat with advise?
+ HANDLE hdevInfo; // device info handle
+ BOOL bnewDevInfo; // new device info
+} CLINFO;
+
+typedef CLINFO *PCLINFO;
+
+
+
+
+BOOL FAR PASCAL FindItemWnd (HWND, LONG);
+BOOL FAR PASCAL SendRenameMsg (HWND, LPSTR, HANDLE);
+BOOL FAR PASCAL EnumForTerminate (HWND, LPSTR, HANDLE);
+BOOL FAR PASCAL SendDataMsg(HWND, LPSTR, HANDLE);
+BOOL FAR PASCAL DeleteClientInfo (HWND, LPSTR, HANDLE);
+int FAR PASCAL ItemCallBack (LPOLECLIENT, int, LPOLEOBJECT);
+
+int INTERNAL RegisterItem (LHDOC, LPSTR, LPCLIENT FAR *, BOOL);
+int INTERNAL FindItem (LPDOC, LPSTR, LPCLIENT FAR *);
+HWND INTERNAL SearchItem (LPDOC, LPSTR);
+void INTERNAL DeleteFromItemsList (HWND, HWND);
+void INTERNAL DeleteAllItems (HWND);
+OLESTATUS INTERNAL PokeData (LPDOC, HWND, LONG);
+HANDLE INTERNAL MakeItemData (DDEPOKE FAR *, HANDLE, OLECLIPFORMAT);
+OLESTATUS INTERNAL AdviseData (LPDOC, HWND, LONG, BOOL FAR *);
+OLESTATUS INTERNAL AdviseStdItems (LPDOC, HWND, LONG, BOOL FAR *);
+OLESTATUS INTERNAL UnAdviseData (LPDOC, HWND, LONG);
+OLESTATUS INTERNAL RequestData (LPDOC, HWND, LONG, HANDLE FAR *);
+BOOL INTERNAL MakeDDEData (HANDLE, int, LPHANDLE, BOOL);
+HANDLE INTERNAL MakeGlobal (LPSTR);
+int INTERNAL ScanItemOptions (LPSTR, int far *);
+OLESTATUS INTERNAL PokeStdItems (LPDOC, HWND, LONG);
+int INTERNAL GetStdItemIndex (ATOM);
+BOOL INTERNAL IsAdviseStdItems (ATOM);
+int INTERNAL SetStdInfo (LPDOC, HWND, LPSTR, HANDLE);
+void INTERNAL SendDevInfo (LPCLIENT, LPSTR);
+BOOL INTERNAL IsFormatAvailable (LPCLIENT, OLECLIPFORMAT);
+OLESTATUS INTERNAL RevokeObject (LPOLECLIENT, BOOL);
+
+
+BOOL INTERNAL AddMessage (HWND, unsigned, WORD, LONG, int);
+
+#define ITEM_FIND 1 // find the item
+#define ITEM_DELETECLIENT 2 // delete the client from item clients
+#define ITEM_DELETE 3 // delete th item window itself
+#define ITEM_SAVED 4 // item saved
+
+// host names data structcure
+typedef struct _HOSTNAMES {
+ WORD clientNameOffset;
+ WORD documentNameOffset;
+ BYTE data[];
+} HOSTNAMES;
+
+typedef HOSTNAMES FAR * LPHOSTNAMES;
+
+
+// routines in UTILS.C
+
+void INTERNAL MapToHexStr (LPSTR, HANDLE);
+void INTERNAL UtilMemCpy (LPSTR, LPSTR, DWORD);
+HANDLE INTERNAL DuplicateData (HANDLE);
+LPSTR INTERNAL ScanLastBoolArg (LPSTR);
+LPSTR INTERNAL ScanArg(LPSTR);
+WORD INTERNAL ScanCommand(LPSTR, WORD, LPSTR FAR *, ATOM FAR *);
+ATOM INTERNAL MakeDataAtom (ATOM, int);
+ATOM INTERNAL DuplicateAtom (ATOM);
+WORD INTERNAL StrToInt (LPSTR);
+BOOL INTERNAL CheckServer (LPSRVR);
+BOOL INTERNAL CheckServerDoc (LPDOC);
+BOOL INTERNAL PostMessageToClientWithBlock (HWND, WORD, WORD, DWORD);
+BOOL INTERNAL PostMessageToClient (HWND, WORD, WORD, DWORD);
+BOOL INTERNAL IsWindowValid (HWND);
+BOOL INTERNAL IsOleCommand (ATOM, WORD);
+BOOL INTERNAL UtilQueryProtocol (ATOM, LPSTR);
+
+
+// routines for queueing messages and posting them
+BOOL INTERNAL UnblockPostMsgs(HWND, BOOL);
+BOOL INTERNAL BlockPostMsg (HWND, WORD, WORD, LONG);
+BOOL INTERNAL IsBlockQueueEmpty (HWND);
+
+// routine in GIVE2GDI.ASM
+HANDLE FAR PASCAL GiveToGDI (HANDLE);
+
+
+// routine in item.c
+HBITMAP INTERNAL DuplicateBitmap (HBITMAP);
+HANDLE INTERNAL DuplicateMetaFile (HANDLE);
+
+// routines in doc.c
+void INTERNAL FreePokeData (HANDLE);
+BOOL INTERNAL FreeGDIdata (HANDLE, OLECLIPFORMAT);
+
+
+
diff --git a/private/mvdm/wow16/ole/server/srvr.rc b/private/mvdm/wow16/ole/server/srvr.rc
new file mode 100644
index 000000000..8f1e7ecc1
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/srvr.rc
@@ -0,0 +1,4 @@
+#include <windows.h>
+#include "olesvr.rcv"
+
+
diff --git a/private/mvdm/wow16/ole/server/srvrmain.c b/private/mvdm/wow16/ole/server/srvrmain.c
new file mode 100644
index 000000000..eb468726e
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/srvrmain.c
@@ -0,0 +1,319 @@
+/****************************** Module Header ******************************\
+* Module Name: Srvrmain.c Server Main module
+*
+* Purpose: Includes server intialization and termination code.
+*
+* Created: Oct 1990.
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor (../10/1990) Designed, coded
+*
+*
+\***************************************************************************/
+
+#include "cmacs.h"
+#include "windows.h"
+#include "ole.h"
+#include "dde.h"
+#include "srvr.h"
+
+#ifndef WF_WLO
+#define WF_WLO 0x8000
+#endif
+
+// ordinal number of new Win31 API IsTask
+#define ORD_IsTask 320
+
+// ordinal number of new Win31 API SetMetaFileBitsBetter
+#define ORD_SetMetaFileBitsBetter 196
+
+
+#ifdef FIREWALLS
+short ole_flags;
+char szDebugBuffer[80];
+void SetOleFlags(void);
+#endif
+
+
+// public vars.
+
+// atomes used in the systems
+ATOM aStdExit; // "StdExit"
+ATOM aStdCreate; // "StdNewDicument"
+ATOM aStdOpen; // "StdOpenDocument"
+ATOM aStdEdit; // "StdOpenDocument"
+ATOM aStdCreateFromTemplate; // "StdNewFromTemplate"
+ATOM aStdClose; // "StdCloseDocument"
+ATOM aStdShowItem; // "StdShowItem"
+ATOM aStdDoVerbItem; // "StddoVerbItem"
+ATOM aSysTopic; // "System"
+ATOM aOLE; // "OLE"
+ATOM aStdDocName; // "StdDocumentName"
+
+ATOM cfBinary; // "Binary format"
+ATOM cfNative; // "NativeFormat"
+ATOM cfLink; // "ObjectLink"
+ATOM cfOwnerLink; // "Ownerlink"
+
+ATOM aChange; // "Change"
+ATOM aSave; // "Save"
+ATOM aClose; // "Close"
+ATOM aProtocols; // "Protocols"
+ATOM aTopics; // "Topics"
+ATOM aFormats; // "Formats"
+ATOM aStatus; // "Status"
+ATOM aEditItems; // "Edit items
+ATOM aTrue; // "True"
+ATOM aFalse; // "False"
+
+
+
+
+
+// !!! free the proc instances.
+FARPROC lpSendRenameMsg; // Call back enum props for rename
+FARPROC lpSendDataMsg; // Call back enum props for data
+FARPROC lpFindItemWnd; // Callback in enum props of
+FARPROC lpItemCallBack; // CallBack for object
+FARPROC lpTerminateClients; // Callback in Doc enum properties
+FARPROC lpTerminateDocClients; // Callback in Doc enum properties
+FARPROC lpDeleteClientInfo; // proc for deleteing each item client
+FARPROC lpEnumForTerminate; // proc for terminating clients not in rename list
+
+FARPROC lpfnSetMetaFileBitsBetter = NULL;
+FARPROC lpfnIsTask = NULL;
+
+HANDLE hdllInst;
+BOOL bProtMode;
+BOOL bWLO = FALSE;
+BOOL bWin30 = FALSE;
+
+VOID FAR PASCAL WEP (int);
+#pragma alloc_text(WEP_TEXT, WEP)
+
+int FAR PASCAL LibMain (hInst, wDataSeg, cbHeapSize, lpszCmdLine)
+HANDLE hInst;
+WORD wDataSeg;
+WORD cbHeapSize;
+LPSTR lpszCmdLine;
+{
+ WNDCLASS wc;
+
+ Puts("LibMain");
+
+#ifdef FIREWALLS
+ SetOleFlags();
+#endif
+
+ hdllInst = hInst;
+
+ bProtMode = (BOOL) (GetWinFlags() & WF_PMODE & 0x0000FFFF);
+ bWLO = (BOOL) (GetWinFlags() & WF_WLO);
+ bWin30 = (!bWLO && ((WORD) GetVersion()) <= 0x0003);
+
+ // !!! Put all this stuff thru soemkind of table so that we can
+ // save code.
+
+ // register all the atoms.
+ aStdExit = GlobalAddAtom ((LPSTR)"StdExit");
+ aStdCreate = GlobalAddAtom ((LPSTR)"StdNewDocument");
+ aStdOpen = GlobalAddAtom ((LPSTR)"StdOpenDocument");
+ aStdEdit = GlobalAddAtom ((LPSTR)"StdEditDocument");
+ aStdCreateFromTemplate = GlobalAddAtom ((LPSTR)"StdNewfromTemplate");
+
+ aStdClose = GlobalAddAtom ((LPSTR)"StdCloseDocument");
+ aStdShowItem = GlobalAddAtom ((LPSTR)"StdShowItem");
+ aStdDoVerbItem = GlobalAddAtom ((LPSTR)"StdDoVerbItem");
+ aSysTopic = GlobalAddAtom ((LPSTR)"System");
+ aOLE = GlobalAddAtom ((LPSTR)"OLEsystem");
+ aStdDocName = GlobalAddAtom ((LPSTR)"StdDocumentName");
+
+ aProtocols = GlobalAddAtom ((LPSTR)"Protocols");
+ aTopics = GlobalAddAtom ((LPSTR)"Topics");
+ aFormats = GlobalAddAtom ((LPSTR)"Formats");
+ aStatus = GlobalAddAtom ((LPSTR)"Status");
+ aEditItems = GlobalAddAtom ((LPSTR)"EditEnvItems");
+
+ aTrue = GlobalAddAtom ((LPSTR)"True");
+ aFalse = GlobalAddAtom ((LPSTR)"False");
+
+ aChange = GlobalAddAtom ((LPSTR)"Change");
+ aSave = GlobalAddAtom ((LPSTR)"Save");
+ aClose = GlobalAddAtom ((LPSTR)"Close");
+
+ // create the proc instances for the required entry pts.
+ lpSendRenameMsg = MakeProcInstance (SendRenameMsg, hdllInst);
+ lpSendDataMsg = MakeProcInstance (SendDataMsg, hdllInst);
+ lpFindItemWnd = MakeProcInstance (FindItemWnd, hdllInst);
+ lpItemCallBack = MakeProcInstance (ItemCallBack, hdllInst);
+ lpTerminateClients = MakeProcInstance (TerminateClients, hdllInst);
+ lpTerminateDocClients = MakeProcInstance (TerminateDocClients, hdllInst);
+ lpDeleteClientInfo = MakeProcInstance (DeleteClientInfo, hdllInst);
+ lpEnumForTerminate = MakeProcInstance (EnumForTerminate , hdllInst);
+
+ // register the clipboard formats
+ cfNative = RegisterClipboardFormat("Native");
+ cfBinary = RegisterClipboardFormat("Binary");
+ cfLink = RegisterClipboardFormat("ObjectLink");
+ cfOwnerLink = RegisterClipboardFormat("OwnerLink");
+
+
+
+ wc.style = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LONG) + //Ask for extra space for storing the
+ //ptr to srvr/doc/iteminfo.
+ sizeof (WORD) + // for LE chars
+ sizeof (WORD); // for keeping the hDLLInst.
+
+ wc.hInstance = hInst;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground= NULL;
+ wc.lpszMenuName = NULL;
+
+
+ // Srvr window class
+ wc.lpfnWndProc = SrvrWndProc;
+ wc.lpszClassName= SRVR_CLASS;
+ if (!RegisterClass(&wc))
+ return 0;
+
+ // document window class
+ wc.lpfnWndProc = DocWndProc;
+ wc.lpszClassName = DOC_CLASS;
+
+ if (!RegisterClass(&wc))
+ return 0;
+
+ // Item (object) window class
+ wc.lpfnWndProc = ItemWndProc;
+ wc.lpszClassName = ITEM_CLASS;
+
+ wc.cbWndExtra = sizeof(LONG); // for items do not need extra stuff.
+ if (!RegisterClass(&wc))
+ return 0;
+
+
+ if (!bWin30) {
+ HANDLE hModule;
+
+ if (hModule = GetModuleHandle ("GDI"))
+ lpfnSetMetaFileBitsBetter
+ = GetProcAddress (hModule,
+ (LPSTR) MAKELONG(ORD_SetMetaFileBitsBetter, 0));
+
+ if (hModule = GetModuleHandle ("KERNEL"))
+ lpfnIsTask
+ = GetProcAddress (hModule, (LPSTR) MAKELONG(ORD_IsTask, 0));
+ }
+
+ if (cbHeapSize != 0)
+ UnlockData(0);
+
+ return 1;
+}
+
+
+VOID FAR PASCAL WEP (nParameter)
+int nParameter;
+{
+
+ Puts("LibExit");
+
+ if (nParameter == WEP_SYSTEM_EXIT)
+ DEBUG_OUT ("---L&E DLL EXIT on system exit---",0)
+
+ else {
+ if (nParameter == WEP_FREE_DLL)
+ DEBUG_OUT ("---L&E DLL EXIT---",0)
+
+ else
+ return;
+ }
+
+ // free the global atoms.
+ if (aStdExit)
+ GlobalDeleteAtom (aStdExit);
+ if (aStdCreate)
+ GlobalDeleteAtom (aStdCreate);
+ if (aStdOpen)
+ GlobalDeleteAtom (aStdOpen);
+ if (aStdEdit)
+ GlobalDeleteAtom (aStdEdit);
+ if (aStdCreateFromTemplate)
+ GlobalDeleteAtom (aStdCreateFromTemplate);
+ if (aStdClose)
+ GlobalDeleteAtom (aStdClose);
+ if (aStdShowItem)
+ GlobalDeleteAtom (aStdShowItem);
+ if (aStdDoVerbItem)
+ GlobalDeleteAtom (aStdDoVerbItem);
+ if (aSysTopic)
+ GlobalDeleteAtom (aSysTopic);
+ if (aOLE)
+ GlobalDeleteAtom (aOLE);
+ if (aStdDocName)
+ GlobalDeleteAtom (aStdDocName);
+
+ if (aProtocols)
+ GlobalDeleteAtom (aProtocols);
+ if (aTopics)
+ GlobalDeleteAtom (aTopics);
+ if (aFormats)
+ GlobalDeleteAtom (aFormats);
+ if (aStatus)
+ GlobalDeleteAtom (aStatus);
+ if (aEditItems)
+ GlobalDeleteAtom (aEditItems);
+
+ if (aTrue)
+ GlobalDeleteAtom (aTrue);
+ if (aFalse)
+ GlobalDeleteAtom (aFalse);
+
+ if (aChange)
+ GlobalDeleteAtom (aChange);
+ if (aSave)
+ GlobalDeleteAtom (aSave);
+ if (aClose)
+ GlobalDeleteAtom (aClose);
+
+ // !!! for some reason these FreeprocInstances are crashing the system.
+#if 0
+ FreeProcInstance (lpSendRenameMsg);
+ FreeProcInstance (lpSendDataMsg);
+ FreeProcInstance (lpFindItemWnd);
+ FreeProcInstance (lpItemCallBack);
+ FreeProcInstance (lpTerminateClients);
+ FreeProcInstance (lpTerminateDocClients);
+ FreeProcInstance (lpDeleteClientInfo);
+ FreeProcInstance (EnumForTerminate);
+#endif
+
+}
+
+
+
+#ifdef FIREWALLS
+void SetOleFlags()
+{
+
+ char buffer[80];
+
+ if(GetProfileString ("OleDll",
+ "Puts","", (LPSTR)buffer, 80))
+ ole_flags = DEBUG_PUTS;
+ else
+ ole_flags = 0;
+
+
+ if(GetProfileString ("OleDll",
+ "DEBUG_OUT","", (LPSTR)buffer, 80))
+ ole_flags |= DEBUG_DEBUG_OUT;
+
+}
+
+#endif
diff --git a/private/mvdm/wow16/ole/server/utils.c b/private/mvdm/wow16/ole/server/utils.c
new file mode 100644
index 000000000..63512e539
--- /dev/null
+++ b/private/mvdm/wow16/ole/server/utils.c
@@ -0,0 +1,573 @@
+/****************************** Module Header ******************************\
+* Module Name: utils.c
+*
+* Purpose: Conatains all the utility routines
+*
+* Created: 1990
+*
+* Copyright (c) 1990, 1991 Microsoft Corporation
+*
+* History:
+* Raor, Srinik (../../1990) Designed and coded
+*
+\***************************************************************************/
+
+#include <windows.h>
+#include "cmacs.h"
+#include <shellapi.h>
+
+#include "ole.h"
+#include "dde.h"
+#include "srvr.h"
+
+
+#ifndef HUGE
+#define HUGE huge
+#endif
+
+#define KB_64 65536
+
+extern ATOM aTrue;
+extern ATOM aFalse;
+extern BOOL bWLO;
+extern BOOL bWin30;
+
+extern ATOM aStdCreateFromTemplate;
+extern ATOM aStdCreate;
+extern ATOM aStdOpen;
+extern ATOM aStdEdit;
+extern ATOM aStdShowItem;
+extern ATOM aStdClose;
+extern ATOM aStdExit;
+extern ATOM aStdDoVerbItem;
+
+extern BOOL (FAR PASCAL *lpfnIsTask) (HANDLE);
+
+// MapToHexStr: Converts WORD to hex string.
+void INTERNAL MapToHexStr (lpbuf, hdata)
+LPSTR lpbuf;
+HANDLE hdata;
+{
+ int i;
+ char ch;
+
+ *lpbuf++ = '@';
+ for ( i = 3; i >= 0; i--) {
+
+ ch = (char) ((((WORD)hdata) >> (i * 4)) & 0x000f);
+ if(ch > '9')
+ ch += 'A' - 10;
+ else
+ ch += '0';
+
+ *lpbuf++ = ch;
+ }
+
+ *lpbuf++ = NULL;
+
+}
+
+
+void INTERNAL UtilMemCpy (lpdst, lpsrc, dwCount)
+LPSTR lpdst;
+LPSTR lpsrc;
+DWORD dwCount;
+{
+ WORD HUGE * hpdst;
+ WORD HUGE * hpsrc;
+ WORD FAR * lpwDst;
+ WORD FAR * lpwSrc;
+ DWORD words;
+ DWORD bytes;
+
+ bytes = dwCount % 2;
+ words = dwCount >> 1; //* we should compare DWORDS
+ //* in the 32 bit version
+ if (dwCount <= KB_64) {
+ lpwDst = (WORD FAR *) lpdst;
+ lpwSrc = (WORD FAR *) lpsrc;
+
+ while (words--)
+ *lpwDst++ = *lpwSrc++;
+
+ if (bytes)
+ * (char FAR *) lpwDst = * (char FAR *) lpwSrc;
+ }
+ else {
+ hpdst = (WORD HUGE *) lpdst;
+ hpsrc = (WORD HUGE *) lpsrc;
+
+ while (words--)
+ *hpdst++ = *hpsrc++;
+
+ if (bytes)
+ *(char HUGE *) hpdst = * (char HUGE *) hpsrc;
+ }
+}
+
+
+//DuplicateData: Duplicates a given Global data handle.
+HANDLE INTERNAL DuplicateData (hdata)
+HANDLE hdata;
+{
+ LPSTR lpsrc = NULL;
+ LPSTR lpdst = NULL;
+ HANDLE hdup = NULL;
+ DWORD size;
+ BOOL err = TRUE;
+
+ if(!(lpsrc = GlobalLock (hdata)))
+ return NULL;
+
+ hdup = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, (size = GlobalSize(hdata)));
+
+ if(!(lpdst = GlobalLock (hdup)))
+ goto errRtn;;
+
+ err = FALSE;
+ UtilMemCpy (lpdst, lpsrc, size);
+
+errRtn:
+ if(lpsrc)
+ GlobalUnlock (hdata);
+
+ if(lpdst)
+ GlobalUnlock (hdup);
+
+ if (err && hdup)
+ GlobalFree (hdup);
+
+ return hdup;
+}
+
+
+//ScanBoolArg: scans the argument which is not included in
+//the quotes. These args could be only TRUE or FALSE for
+//the time being. !!!The scanning routines should be
+//merged and it should be generalized.
+
+LPSTR INTERNAL ScanBoolArg (lpstr, lpflag)
+LPSTR lpstr;
+BOOL FAR *lpflag;
+{
+
+
+ LPSTR lpbool;
+ ATOM aShow;
+ char ch;
+
+ lpbool = lpstr;
+
+ // !!! These routines does not take care of quoted quotes.
+
+ while((ch = *lpstr) && (!(ch == ')' || ch == ',')))
+ lpstr++;
+
+ if(ch == NULL)
+ return NULL;
+
+ *lpstr++ = NULL; // terminate the arg by null
+
+ // if terminated by paren, then check for end of command
+ // syntax.
+
+ // Check for the end of the command string.
+ if (ch == ')') {
+ if (*lpstr++ != ']')
+ return NULL;
+
+ if(*lpstr != NULL)
+ return NULL; //finally should be terminated by null.
+
+ }
+
+ aShow = GlobalFindAtom (lpbool);
+ if (aShow == aTrue)
+ *lpflag = TRUE;
+
+ else {
+ if (aShow ==aFalse)
+ *lpflag = FALSE;
+ else
+ return NULL;;
+ }
+ return lpstr;
+}
+
+
+
+
+//ScannumArg: Checks for the syntax of num arg in Execute and if
+//the arg is syntactically correct, returns the ptr to the
+//beginning of the next arg and also, returns the number
+//Does not take care of the last num arg in the list.
+
+LPSTR INTERNAL ScanNumArg (lpstr, lpnum)
+LPSTR lpstr;
+LPINT lpnum;
+{
+
+ WORD val = 0;
+ char ch;
+
+ while((ch = *lpstr++) && (ch != ',')) {
+ if (ch < '0' || ch >'9')
+ return NULL;
+ val += val * 10 + (ch - '0');
+
+ }
+
+ if(!ch)
+ return NULL;
+
+ *lpnum = val;
+ return lpstr;
+}
+
+
+
+
+//ScanArg: Checks for the syntax of arg in Execute and if
+//the arg is syntactically correct, returns the ptr to the
+//beginning of the next arg or to the end of the excute string.
+
+LPSTR INTERNAL ScanArg (lpstr)
+LPSTR lpstr;
+{
+
+
+ // !!! These routines does not take care of quoted quotes.
+
+ // first char should be quote.
+
+ if (*(lpstr-1) != '\"')
+ return NULL;
+
+ while(*lpstr && *lpstr != '\"')
+ lpstr++;
+
+ if(*lpstr == NULL)
+ return NULL;
+
+ *lpstr++ = NULL; // terminate the arg by null
+
+ if(!(*lpstr == ',' || *lpstr == ')'))
+ return NULL;
+
+
+ if(*lpstr++ == ','){
+
+ if(*lpstr == '\"')
+ return ++lpstr;
+ // If it is not quote, leave the ptr on the first char
+ return lpstr;
+ }
+
+ // terminated by paren
+ // already skiped right paren
+
+ // Check for the end of the command string.
+ if (*lpstr++ != ']')
+ return NULL;
+
+ if(*lpstr != NULL)
+ return NULL; //finally should be terminated by null.
+
+ return lpstr;
+}
+
+// ScanCommand: scanns the command string for the syntax
+// correctness. If syntactically correct, returns the ptr
+// to the first arg or to the end of the string.
+
+WORD INTERNAL ScanCommand (lpstr, wType, lplpnextcmd, lpAtom)
+LPSTR lpstr;
+WORD wType;
+LPSTR FAR * lplpnextcmd;
+ATOM FAR * lpAtom;
+{
+ // !!! These routines does not take care of quoted quotes.
+ // and not taking care of blanks arround the operators
+
+ // !!! We are not allowing blanks after operators.
+ // Should be allright! since this is arestricted syntax.
+
+ char ch;
+ LPSTR lptemp = lpstr;
+
+
+ while(*lpstr && (!(*lpstr == '(' || *lpstr == ']')))
+ lpstr++;
+
+ if(*lpstr == NULL)
+ return NULL;
+
+ ch = *lpstr;
+ *lpstr++ = NULL; // set the end of command
+
+ *lpAtom = GlobalFindAtom (lptemp);
+
+ if (!IsOleCommand (*lpAtom, wType))
+ return NON_OLE_COMMAND;
+
+ if (ch == '(') {
+ ch = *lpstr++;
+
+ if (ch == ')') {
+ if (*lpstr++ != ']')
+ return NULL;
+ }
+ else {
+ if (ch != '\"')
+ return NULL;
+ }
+
+ *lplpnextcmd = lpstr;
+ return OLE_COMMAND;
+ }
+
+ // terminated by ']'
+
+ if (*(*lplpnextcmd = lpstr)) // if no nul termination, then it is error.
+ return NULL;
+
+ return OLE_COMMAND;
+}
+
+
+//MakeDataAtom: Creates a data atom from the item string
+//and the item data otions.
+
+ATOM INTERNAL MakeDataAtom (aItem, options)
+ATOM aItem;
+int options;
+{
+ char buf[MAX_STR];
+
+ if (options == OLE_CHANGED)
+ return DuplicateAtom (aItem);
+
+ if (!aItem)
+ buf[0] = NULL;
+ else
+ GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR);
+
+ if (options == OLE_CLOSED)
+ lstrcat ((LPSTR)buf, (LPSTR) "/Close");
+ else {
+ if (options == OLE_SAVED)
+ lstrcat ((LPSTR)buf, (LPSTR) "/Save");
+ }
+
+ if (buf[0])
+ return GlobalAddAtom ((LPSTR)buf);
+ else
+ return NULL;
+}
+
+//DuplicateAtom: Duplicates an atom
+ATOM INTERNAL DuplicateAtom (atom)
+ATOM atom;
+{
+ char buf[MAX_STR];
+
+ Puts ("DuplicateAtom");
+
+ if (!atom)
+ return NULL;
+
+ GlobalGetAtomName (atom, buf, MAX_STR);
+ return GlobalAddAtom (buf);
+}
+
+// MakeGlobal: makes global out of strings.
+// works only for << 64k
+
+HANDLE INTERNAL MakeGlobal (lpstr)
+LPSTR lpstr;
+{
+
+ int len = 0;
+ HANDLE hdata = NULL;
+ LPSTR lpdata = NULL;
+
+ len = lstrlen (lpstr) + 1;
+
+ hdata = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, len);
+ if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
+ goto errRtn;
+
+
+ UtilMemCpy (lpdata, lpstr, (DWORD)len);
+ GlobalUnlock (hdata);
+ return hdata;
+
+errRtn:
+
+ if (lpdata)
+ GlobalUnlock (hdata);
+
+
+ if (hdata)
+ GlobalFree (hdata);
+
+ return NULL;
+
+}
+
+
+
+BOOL INTERNAL CheckServer (lpsrvr)
+LPSRVR lpsrvr;
+{
+ if (!CheckPointer(lpsrvr, WRITE_ACCESS))
+ return FALSE;
+
+ if ((lpsrvr->sig[0] == 'S') && (lpsrvr->sig[1] == 'R'))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL INTERNAL CheckServerDoc (lpdoc)
+LPDOC lpdoc;
+{
+ if (!CheckPointer(lpdoc, WRITE_ACCESS))
+ return FALSE;
+
+ if ((lpdoc->sig[0] == 'S') && (lpdoc->sig[1] == 'D'))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL INTERNAL PostMessageToClientWithBlock (hWnd, wMsg, wParam, lParam)
+HWND hWnd;
+WORD wMsg;
+WORD wParam;
+DWORD lParam;
+{
+ if (!IsWindowValid (hWnd)) {
+ ASSERT(FALSE, "Client's window is missing");
+ return FALSE;
+ }
+
+ if (IsBlockQueueEmpty ((HWND)wParam) && PostMessage (hWnd, wMsg, wParam, lParam))
+ return TRUE;
+
+ BlockPostMsg (hWnd, wMsg, wParam, lParam);
+ return TRUE;
+}
+
+
+
+BOOL INTERNAL PostMessageToClient (hWnd, wMsg, wParam, lParam)
+HWND hWnd;
+WORD wMsg;
+WORD wParam;
+DWORD lParam;
+{
+ if (!IsWindowValid (hWnd)) {
+ ASSERT(FALSE, "Client's window is missing");
+ return FALSE;
+ }
+
+ if (IsBlockQueueEmpty ((HWND)wParam) && PostMessage (hWnd, wMsg, wParam, lParam))
+ return TRUE;
+
+ BlockPostMsg (hWnd, wMsg, wParam, lParam);
+ return TRUE;
+}
+
+
+BOOL INTERNAL IsWindowValid (hwnd)
+HWND hwnd;
+{
+
+#define TASK_OFFSET 0x00FA
+
+ LPSTR lptask;
+ HANDLE htask;
+
+ if (!IsWindow (hwnd))
+ return FALSE;
+
+ if (bWLO)
+ return TRUE;
+
+ // now get the task handle and find out it is valid.
+ htask = GetWindowTask (hwnd);
+
+ if (bWin30 || !lpfnIsTask) {
+ lptask = (LPSTR)(MAKELONG (TASK_OFFSET, htask));
+
+ if (!CheckPointer(lptask, READ_ACCESS))
+ return FALSE;
+
+ // now check for the signature bytes of task block in kernel
+ if (*lptask++ == 'T' && *lptask == 'D')
+ return TRUE;
+ }
+ else {
+ // From win31 onwards the API IsTask() can be used for task validation
+ if ((*lpfnIsTask)(htask))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+BOOL INTERNAL UtilQueryProtocol (aClass, lpprotocol)
+ATOM aClass;
+LPSTR lpprotocol;
+{
+ HKEY hKey;
+ char key[MAX_STR];
+ char class[MAX_STR];
+
+ if (!aClass)
+ return FALSE;
+
+ if (!GlobalGetAtomName (aClass, class, MAX_STR))
+ return FALSE;
+
+ lstrcpy (key, class);
+ lstrcat (key, "\\protocol\\");
+ lstrcat (key, lpprotocol);
+ lstrcat (key, "\\server");
+
+ if (RegOpenKey (HKEY_CLASSES_ROOT, key, &hKey))
+ return FALSE;
+
+ RegCloseKey (hKey);
+ return TRUE;
+}
+
+
+BOOL INTERNAL IsOleCommand (aCmd, wType)
+ATOM aCmd;
+WORD wType;
+{
+ if (wType == WT_SRVR) {
+ if ((aCmd == aStdCreateFromTemplate)
+ || (aCmd == aStdCreate)
+ || (aCmd == aStdOpen)
+ || (aCmd == aStdEdit)
+ || (aCmd == aStdShowItem)
+ || (aCmd == aStdClose)
+ || (aCmd == aStdExit))
+ return TRUE;
+ }
+ else {
+ if ((aCmd == aStdClose)
+ || (aCmd == aStdDoVerbItem)
+ || (aCmd == aStdShowItem))
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow16/rasapi16/bseerr.h b/private/mvdm/wow16/rasapi16/bseerr.h
new file mode 100644
index 000000000..f0c76ad18
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/bseerr.h
@@ -0,0 +1,617 @@
+/****************************** Module Header ******************************\
+*
+* Module Name: BSEERR.H
+*
+* Copy of the Lanman BSEERR.H used for their base error codes.
+* Not used by anyone else.
+*
+\***************************************************************************/
+
+#ifndef BSEERR_INCLUDED
+#define BSEERR_INCLUDED
+
+#define NO_ERROR 0
+#define ERROR_INVALID_FUNCTION 1
+#define ERROR_FILE_NOT_FOUND 2
+#define ERROR_PATH_NOT_FOUND 3
+#define ERROR_TOO_MANY_OPEN_FILES 4
+#define ERROR_ACCESS_DENIED 5
+#define ERROR_INVALID_HANDLE 6
+#define ERROR_ARENA_TRASHED 7
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#define ERROR_INVALID_BLOCK 9
+#define ERROR_BAD_ENVIRONMENT 10
+#define ERROR_BAD_FORMAT 11
+#define ERROR_INVALID_ACCESS 12
+#define ERROR_INVALID_DATA 13
+/* 14 is reserved */
+#define ERROR_INVALID_DRIVE 15
+#define ERROR_CURRENT_DIRECTORY 16
+#define ERROR_NOT_SAME_DEVICE 17
+#define ERROR_NO_MORE_FILES 18
+#define ERROR_WRITE_PROTECT 19
+#define ERROR_BAD_UNIT 20
+#define ERROR_NOT_READY 21
+#define ERROR_BAD_COMMAND 22
+#define ERROR_CRC 23
+#define ERROR_BAD_LENGTH 24
+#define ERROR_SEEK 25
+#define ERROR_NOT_DOS_DISK 26
+#define ERROR_SECTOR_NOT_FOUND 27
+#define ERROR_OUT_OF_PAPER 28
+#define ERROR_WRITE_FAULT 29
+#define ERROR_READ_FAULT 30
+#define ERROR_GEN_FAILURE 31
+#define ERROR_SHARING_VIOLATION 32
+#define ERROR_LOCK_VIOLATION 33
+#define ERROR_WRONG_DISK 34
+#define ERROR_FCB_UNAVAILABLE 35
+#define ERROR_SHARING_BUFFER_EXCEEDED 36
+#define ERROR_NOT_SUPPORTED 50
+#define ERROR_REM_NOT_LIST 51 /* Remote computer not listening */
+#define ERROR_DUP_NAME 52 /* Duplicate name on network */
+#define ERROR_BAD_NETPATH 53 /* Network path not found */
+#define ERROR_NETWORK_BUSY 54 /* Network busy */
+#define ERROR_DEV_NOT_EXIST 55 /* Network device no longer exists */
+#define ERROR_TOO_MANY_CMDS 56 /* Net BIOS command limit exceeded */
+#define ERROR_ADAP_HDW_ERR 57 /* Network adapter hardware error */
+#define ERROR_BAD_NET_RESP 58 /* Incorrect response from network */
+#define ERROR_UNEXP_NET_ERR 59 /* Unexpected network error */
+#define ERROR_BAD_REM_ADAP 60 /* Incompatible remote adapter */
+#define ERROR_PRINTQ_FULL 61 /* Print queue full */
+#define ERROR_NO_SPOOL_SPACE 62 /* Not enough space for print file */
+#define ERROR_PRINT_CANCELLED 63 /* Print file was cancelled */
+#define ERROR_NETNAME_DELETED 64 /* Network name was deleted */
+#define ERROR_NETWORK_ACCESS_DENIED 65 /* Access denied */
+#define ERROR_BAD_DEV_TYPE 66 /* Network device type incorrect */
+#define ERROR_BAD_NET_NAME 67 /* Network name not found */
+#define ERROR_TOO_MANY_NAMES 68 /* Network name limit exceeded */
+#define ERROR_TOO_MANY_SESS 69 /* Net BIOS session limit exceeded */
+#define ERROR_SHARING_PAUSED 70 /* Sharing temporarily paused */
+#define ERROR_REQ_NOT_ACCEP 71 /* Network request not accepted */
+#define ERROR_REDIR_PAUSED 72 /* Print|disk redirection is paused*/
+#define ERROR_FILE_EXISTS 80
+#define ERROR_DUP_FCB 81
+#define ERROR_CANNOT_MAKE 82
+#define ERROR_FAIL_I24 83
+#define ERROR_OUT_OF_STRUCTURES 84
+#define ERROR_ALREADY_ASSIGNED 85
+#define ERROR_INVALID_PASSWORD 86
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_NET_WRITE_FAULT 88
+#define ERROR_NO_PROC_SLOTS 89 /* no process slots available */
+#define ERROR_NOT_FROZEN 90
+#define ERR_TSTOVFL 91 /* timer service table overflow */
+#define ERR_TSTDUP 92 /* timer service table duplicate */
+#define ERROR_NO_ITEMS 93 /* no items to operate upon */
+#define ERROR_INTERRUPT 95 /* interrupted system call */
+#define ERROR_DEVICE_IN_USE 99 /* Device in use by another thread */
+#define ERROR_TOO_MANY_SEMAPHORES 100
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101
+#define ERROR_SEM_IS_SET 102
+#define ERROR_TOO_MANY_SEM_REQUESTS 103
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104
+#define ERROR_SEM_OWNER_DIED 105 /* waitsem found owner died */
+#define ERROR_SEM_USER_LIMIT 106 /* too many procs have this sem */
+#define ERROR_DISK_CHANGE 107
+#define ERROR_DRIVE_LOCKED 108 /* drive locked by another process*/
+#define ERROR_BROKEN_PIPE 109 /* write on pipe with no reader */
+#define ERROR_OPEN_FAILED 110 /* open/created failed due to */
+ /* explicit fail command */
+#define ERROR_BUFFER_OVERFLOW 111 /* buffer passed to system call */
+ /* is too small to hold return */
+ /* data. */
+#define ERROR_DISK_FULL 112 /* not enough space on the disk */
+ /* (DOSNEWSIZE/w_NewSize) */
+#define ERROR_NO_MORE_SEARCH_HANDLES 113 /* can't allocate another search */
+ /* structure and handle. */
+ /* (DOSFINDFIRST/w_FindFirst) */
+#define ERROR_INVALID_TARGET_HANDLE 114 /* Target handle in DOSDUPHANDLE */
+ /* is invalid */
+#define ERROR_PROTECTION_VIOLATION 115 /* Bad user virtual address */
+#define ERROR_VIOKBD_REQUEST 116
+#define ERROR_INVALID_CATEGORY 117 /* Category for DEVIOCTL in not */
+ /* defined */
+#define ERROR_INVALID_VERIFY_SWITCH 118 /* invalid value passed for */
+ /* verify flag */
+#define ERROR_BAD_DRIVER_LEVEL 119 /* DosDevIOCTL looks for a level */
+ /* four driver. If the driver */
+ /* is not level four we return */
+ /* this code */
+#define ERROR_CALL_NOT_IMPLEMENTED 120 /* returned from stub api calls. */
+ /* This call will disappear when */
+ /* all the api's are implemented. */
+#define ERROR_SEM_TIMEOUT 121 /* Time out happened from the */
+ /* semaphore api functions. */
+#define ERROR_INSUFFICIENT_BUFFER 122 /* Some calls require the */
+ /* application to pass in a buffer */
+ /* filled with data. This error is */
+ /* returned if the data buffer is too */
+ /* small. For example: DosSetFileInfo */
+ /* requires 4 bytes of data. If a */
+ /* two byte buffer is passed in then */
+ /* this error is returned. */
+ /* error_buffer_overflow is used when */
+ /* the output buffer in not big enough.*/
+#define ERROR_INVALID_NAME 123 /* illegal character or malformed */
+ /* file system name */
+#define ERROR_INVALID_LEVEL 124 /* unimplemented level for info */
+ /* retrieval or setting */
+#define ERROR_NO_VOLUME_LABEL 125 /* no volume label found with */
+ /* DosQFSInfo command */
+#define ERROR_MOD_NOT_FOUND 126 /* w_getprocaddr,w_getmodhandle */
+#define ERROR_PROC_NOT_FOUND 127 /* w_getprocaddr */
+#define ERROR_WAIT_NO_CHILDREN 128 /* CWait finds to children */
+#define ERROR_CHILD_NOT_COMPLETE 129 /* CWait children not dead yet */
+#define ERROR_DIRECT_ACCESS_HANDLE 130 /* handle operation is invalid */
+ /* for direct disk access */
+ /* handles */
+#define ERROR_NEGATIVE_SEEK 131 /* application tried to seek */
+ /* with negitive offset */
+#define ERROR_SEEK_ON_DEVICE 132 /* application tried to seek */
+ /* on device or pipe */
+#define ERROR_IS_JOIN_TARGET 133
+#define ERROR_IS_JOINED 134
+#define ERROR_IS_SUBSTED 135
+#define ERROR_NOT_JOINED 136
+#define ERROR_NOT_SUBSTED 137
+#define ERROR_JOIN_TO_JOIN 138
+#define ERROR_SUBST_TO_SUBST 139
+#define ERROR_JOIN_TO_SUBST 140
+#define ERROR_SUBST_TO_JOIN 141
+#define ERROR_BUSY_DRIVE 142
+#define ERROR_SAME_DRIVE 143
+#define ERROR_DIR_NOT_ROOT 144
+#define ERROR_DIR_NOT_EMPTY 145
+#define ERROR_IS_SUBST_PATH 146
+#define ERROR_IS_JOIN_PATH 147
+#define ERROR_PATH_BUSY 148
+#define ERROR_IS_SUBST_TARGET 149
+#define ERROR_SYSTEM_TRACE 150 /* system trace error */
+#define ERROR_INVALID_EVENT_COUNT 151 /* DosMuxSemWait errors */
+#define ERROR_TOO_MANY_MUXWAITERS 152
+#define ERROR_INVALID_LIST_FORMAT 153
+#define ERROR_LABEL_TOO_LONG 154
+#define ERROR_TOO_MANY_TCBS 155
+#define ERROR_SIGNAL_REFUSED 156
+#define ERROR_DISCARDED 157
+#define ERROR_NOT_LOCKED 158
+#define ERROR_BAD_THREADID_ADDR 159
+#define ERROR_BAD_ARGUMENTS 160
+#define ERROR_BAD_PATHNAME 161
+#define ERROR_SIGNAL_PENDING 162
+#define ERROR_UNCERTAIN_MEDIA 163
+#define ERROR_MAX_THRDS_REACHED 164
+#define ERROR_MONITORS_NOT_SUPPORTED 165
+#define ERROR_UNC_DRIVER_NOT_INSTALLED 166
+
+/* The following error codes refer to demand loading segments */
+#define ERROR_LOCK_FAILED 167
+#define ERROR_SWAPIO_FAILED 168
+#define ERROR_SWAPIN_FAILED 169
+#define ERROR_BUSY 170
+
+#define ERROR_INVALID_SEGMENT_NUMBER 180
+#define ERROR_INVALID_CALLGATE 181
+#define ERROR_INVALID_ORDINAL 182
+#define ERROR_ALREADY_EXISTS 183
+#define ERROR_NO_CHILD_PROCESS 184
+#define ERROR_CHILD_ALIVE_NOWAIT 185
+#define ERROR_INVALID_FLAG_NUMBER 186
+#define ERROR_SEM_NOT_FOUND 187
+
+/* following error codes make loader error messages distinct */
+#define ERROR_INVALID_STARTING_CODESEG 188
+#define ERROR_INVALID_STACKSEG 189
+#define ERROR_INVALID_MODULETYPE 190
+#define ERROR_INVALID_EXE_SIGNATURE 191
+#define ERROR_EXE_MARKED_INVALID 192
+#define ERROR_BAD_EXE_FORMAT 193
+#define ERROR_ITERATED_DATA_EXCEEDS_64K 194
+#define ERROR_INVALID_MINALLOCSIZE 195
+#define ERROR_DYNLINK_FROM_INVALID_RING 196
+#define ERROR_IOPL_NOT_ENABLED 197
+#define ERROR_INVALID_SEGDPL 198
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202
+#define ERROR_ENVVAR_NOT_FOUND 203
+#define ERROR_NOT_CURRENT_CTRY 204
+#define ERROR_NO_SIGNAL_SENT 205
+#define ERROR_FILENAME_EXCED_RANGE 206 /* if filename > 8.3 */
+#define ERROR_RING2_STACK_IN_USE 207 /* for FAPI */
+#define ERROR_META_EXPANSION_TOO_LONG 208 /* if "*a" > 8.3 */
+#define ERROR_INVALID_SIGNAL_NUMBER 209
+#define ERROR_THREAD_1_INACTIVE 210
+#define ERROR_INFO_NOT_AVAIL 211
+#define ERROR_LOCKED 212
+#define ERROR_BAD_DYNALINK 213
+#define ERROR_TOO_MANY_MODULES 214
+#define ERROR_NESTING_NOT_ALLOWED 215
+#define ERROR_CANNOT_SHRINK 216 /* attempt to shrink ring 2 stack */
+#define ERROR_ZOMBIE_PROCESS 217
+#define ERROR_STACK_IN_HIGH_MEMORY 218
+#define ERROR_INVALID_EXITROUTINE_RING 219
+#define ERROR_GETBUF_FAILED 220
+#define ERROR_FLUSHBUF_FAILED 221
+#define ERROR_TRANSFER_TOO_LONG 222
+#define ERROR_NO_CHILDREN 228
+#define ERROR_INVALID_SCREEN_GROUP 229
+/*
+ * Error codes 230 - 249 are reserved
+ */
+#define ERROR_BAD_PIPE 230 /* Non-existant pipe or bad operation */
+#define ERROR_PIPE_BUSY 231 /* Pipe is busy */
+#define ERROR_NO_DATA 232 /* No data on non-blocking read */
+#define ERROR_PIPE_NOT_CONNECTED 233 /* Pipe was disconnected by server*/
+#define ERROR_MORE_DATA 234 /* More data is available */
+
+#define ERROR_VC_DISCONNECTED 240
+#define ERROR_CIRCULARITY_REQUESTED 250 /* When renaming a dir which */
+ /* would cause a circularity */
+#define ERROR_DIRECTORY_IN_CDS 251 /* When renaming a dir */
+ /* which is "in use" */
+#define ERROR_INVALID_FSD_NAME 252 /* when trying to access */
+ /* nonexistent FSD */
+#define ERROR_INVALID_PATH 253 /* bad pseudo device */
+#define ERROR_INVALID_EA_NAME 254 /* Illegal chars in name */
+#define ERROR_EA_LIST_INCONSISTENT 255 /* Size or some field bad */
+#define ERROR_EA_LIST_TOO_LONG 256 /* FEAlist > 64K-1 bytes */
+#define ERROR_NO_META_MATCH 257 /* string doesn't match expression*/
+#define ERROR_FINDNOTIFY_TIMEOUT 258 /* FindNotify request timeout */
+#define ERROR_NO_MORE_ITEMS 259 /* QFSAttach ordinal query */
+#define ERROR_SEARCH_STRUC_REUSED 260 /* 3xbox findfirst/next
+ search structure reused */
+#define ERROR_CHAR_NOT_FOUND 261 /* can not find character */
+#define ERROR_TOO_MUCH_STACK 262 /* Stack request exceeds sys limit*/
+#define ERROR_INVALID_ATTR 263 /* invalid FS_ATTRIBUTE */
+#define ERROR_INVALID_STARTING_RING 264
+#define ERROR_INVALID_DLL_INIT_RING 265
+#define ERROR_CANNOT_COPY 266 /* doscopy */
+#define ERROR_DIRECTORY 267 /* doscopy */
+#define ERROR_OPLOCKED_FILE 268
+#define ERROR_OPLOCK_THREAD_EXISTS 269
+
+/* error codes for DosFindNotify */
+#define ERROR_VOLUME_CHANGED 270
+#define ERROR_FINDNOTIFY_HANDLE_IN_USE 271
+#define ERROR_FINDNOTIFY_HANDLE_CLOSED 272
+#define ERROR_NOTIFY_OBJECT_REMOVED 273
+
+/* Error to indicate that ShutDown already done */
+#define ERROR_ALREADY_SHUTDOWN 274
+
+/* error code for DOSFINDFIRST2/NEXT */
+#define ERROR_EAS_DIDNT_FIT 275
+
+/* error codes for EA file format change */
+#define ERROR_EA_FILE_CORRUPT 276
+#define ERROR_EA_TABLE_FULL 277
+#define ERROR_INVALID_EA_HANDLE 278
+#define ERROR_NO_CLUSTER 279
+#define ERROR_CREATE_EA_FILE 280
+#define ERROR_CANNOT_OPEN_EA_FILE 281
+
+#define ERROR_INVALID_PROCID 303
+#define ERROR_INVALID_PDELTA 304
+#define ERROR_NOT_DESCENDANT 305
+#define ERROR_NOT_SESSION_MANAGER 306
+#define ERROR_INVALID_PCLASS 307
+#define ERROR_INVALID_SCOPE 308
+#define ERROR_INVALID_THREADID 309
+#define ERROR_DOSSUB_SHRINK 310
+#define ERROR_DOSSUB_NOMEM 311
+#define ERROR_DOSSUB_OVERLAP 312
+#define ERROR_DOSSUB_BADSIZE 313
+#define ERROR_DOSSUB_BADFLAG 314
+#define ERROR_DOSSUB_BADSELECTOR 315
+#define ERROR_MR_MSG_TOO_LONG 316
+#define ERROR_MR_MID_NOT_FOUND 317
+#define ERROR_MR_UN_ACC_MSGF 318
+#define ERROR_MR_INV_MSGF_FORMAT 319
+#define ERROR_MR_INV_IVCOUNT 320
+#define ERROR_MR_UN_PERFORM 321
+#define ERROR_TS_WAKEUP 322
+#define ERROR_TS_SEMHANDLE 323
+#define ERROR_TS_NOTIMER 324
+#define ERROR_TS_HANDLE 326
+#define ERROR_TS_DATETIME 327
+#define ERROR_SYS_INTERNAL 328
+#define ERROR_QUE_CURRENT_NAME 329
+#define ERROR_QUE_PROC_NOT_OWNED 330
+#define ERROR_QUE_PROC_OWNED 331
+#define ERROR_QUE_DUPLICATE 332
+#define ERROR_QUE_ELEMENT_NOT_EXIST 333
+#define ERROR_QUE_NO_MEMORY 334
+#define ERROR_QUE_INVALID_NAME 335
+#define ERROR_QUE_INVALID_PRIORITY 336
+#define ERROR_QUE_INVALID_HANDLE 337
+#define ERROR_QUE_LINK_NOT_FOUND 338
+#define ERROR_QUE_MEMORY_ERROR 339
+#define ERROR_QUE_PREV_AT_END 340
+#define ERROR_QUE_PROC_NO_ACCESS 341
+#define ERROR_QUE_EMPTY 342
+#define ERROR_QUE_NAME_NOT_EXIST 343
+#define ERROR_QUE_NOT_INITIALIZED 344
+#define ERROR_QUE_UNABLE_TO_ACCESS 345
+#define ERROR_QUE_UNABLE_TO_ADD 346
+#define ERROR_QUE_UNABLE_TO_INIT 347
+#define ERROR_VIO_INVALID_MASK 349
+#define ERROR_VIO_PTR 350
+#define ERROR_VIO_APTR 351
+#define ERROR_VIO_RPTR 352
+#define ERROR_VIO_CPTR 353
+#define ERROR_VIO_LPTR 354
+#define ERROR_VIO_MODE 355
+#define ERROR_VIO_WIDTH 356
+#define ERROR_VIO_ATTR 357
+#define ERROR_VIO_ROW 358
+#define ERROR_VIO_COL 359
+#define ERROR_VIO_TOPROW 360
+#define ERROR_VIO_BOTROW 361
+#define ERROR_VIO_RIGHTCOL 362
+#define ERROR_VIO_LEFTCOL 363
+#define ERROR_SCS_CALL 364
+#define ERROR_SCS_VALUE 365
+#define ERROR_VIO_WAIT_FLAG 366
+#define ERROR_VIO_UNLOCK 367
+#define ERROR_SGS_NOT_SESSION_MGR 368
+#define ERROR_SMG_INVALID_SGID 369
+#define ERROR_SMG_INVALID_SESSION_ID 369
+#define ERROR_SMG_NOSG 370
+#define ERROR_SMG_NO_SESSIONS 370
+#define ERROR_SMG_GRP_NOT_FOUND 371
+#define ERROR_SMG_SESSION_NOT_FOUND 371
+#define ERROR_SMG_SET_TITLE 372
+#define ERROR_KBD_PARAMETER 373
+#define ERROR_KBD_NO_DEVICE 374
+#define ERROR_KBD_INVALID_IOWAIT 375
+#define ERROR_KBD_INVALID_LENGTH 376
+#define ERROR_KBD_INVALID_ECHO_MASK 377
+#define ERROR_KBD_INVALID_INPUT_MASK 378
+#define ERROR_MON_INVALID_PARMS 379
+#define ERROR_MON_INVALID_DEVNAME 380
+#define ERROR_MON_INVALID_HANDLE 381
+#define ERROR_MON_BUFFER_TOO_SMALL 382
+#define ERROR_MON_BUFFER_EMPTY 383
+#define ERROR_MON_DATA_TOO_LARGE 384
+#define ERROR_MOUSE_NO_DEVICE 385
+#define ERROR_MOUSE_INV_HANDLE 386
+#define ERROR_MOUSE_INV_PARMS 387
+#define ERROR_MOUSE_CANT_RESET 388
+#define ERROR_MOUSE_DISPLAY_PARMS 389
+#define ERROR_MOUSE_INV_MODULE 390
+#define ERROR_MOUSE_INV_ENTRY_PT 391
+#define ERROR_MOUSE_INV_MASK 392
+#define NO_ERROR_MOUSE_NO_DATA 393
+#define NO_ERROR_MOUSE_PTR_DRAWN 394
+#define ERROR_INVALID_FREQUENCY 395
+#define ERROR_NLS_NO_COUNTRY_FILE 396
+#define ERROR_NLS_OPEN_FAILED 397
+#define ERROR_NLS_NO_CTRY_CODE 398
+#define ERROR_NO_COUNTRY_OR_CODEPAGE 398
+#define ERROR_NLS_TABLE_TRUNCATED 399
+#define ERROR_NLS_BAD_TYPE 400
+#define ERROR_NLS_TYPE_NOT_FOUND 401
+#define ERROR_VIO_SMG_ONLY 402
+#define ERROR_VIO_INVALID_ASCIIZ 403
+#define ERROR_VIO_DEREGISTER 404
+#define ERROR_VIO_NO_POPUP 405
+#define ERROR_VIO_EXISTING_POPUP 406
+#define ERROR_KBD_SMG_ONLY 407
+#define ERROR_KBD_INVALID_ASCIIZ 408
+#define ERROR_KBD_INVALID_MASK 409
+#define ERROR_KBD_REGISTER 410
+#define ERROR_KBD_DEREGISTER 411
+#define ERROR_MOUSE_SMG_ONLY 412
+#define ERROR_MOUSE_INVALID_ASCIIZ 413
+#define ERROR_MOUSE_INVALID_MASK 414
+#define ERROR_MOUSE_REGISTER 415
+#define ERROR_MOUSE_DEREGISTER 416
+#define ERROR_SMG_BAD_ACTION 417
+#define ERROR_SMG_INVALID_CALL 418
+#define ERROR_SCS_SG_NOTFOUND 419
+#define ERROR_SCS_NOT_SHELL 420
+#define ERROR_VIO_INVALID_PARMS 421
+#define ERROR_VIO_FUNCTION_OWNED 422
+#define ERROR_VIO_RETURN 423
+#define ERROR_SCS_INVALID_FUNCTION 424
+#define ERROR_SCS_NOT_SESSION_MGR 425
+#define ERROR_VIO_REGISTER 426
+#define ERROR_VIO_NO_MODE_THREAD 427
+#define ERROR_VIO_NO_SAVE_RESTORE_THD 428
+#define ERROR_VIO_IN_BG 429
+#define ERROR_VIO_ILLEGAL_DURING_POPUP 430
+#define ERROR_SMG_NOT_BASESHELL 431
+#define ERROR_SMG_BAD_STATUSREQ 432
+#define ERROR_QUE_INVALID_WAIT 433
+#define ERROR_VIO_LOCK 434
+#define ERROR_MOUSE_INVALID_IOWAIT 435
+#define ERROR_VIO_INVALID_HANDLE 436
+#define ERROR_VIO_ILLEGAL_DURING_LOCK 437
+#define ERROR_VIO_INVALID_LENGTH 438
+#define ERROR_KBD_INVALID_HANDLE 439
+#define ERROR_KBD_NO_MORE_HANDLE 440
+#define ERROR_KBD_CANNOT_CREATE_KCB 441
+#define ERROR_KBD_CODEPAGE_LOAD_INCOMPL 442
+#define ERROR_KBD_INVALID_CODEPAGE_ID 443
+#define ERROR_KBD_NO_CODEPAGE_SUPPORT 444
+#define ERROR_KBD_FOCUS_REQUIRED 445
+#define ERROR_KBD_FOCUS_ALREADY_ACTIVE 446
+#define ERROR_KBD_KEYBOARD_BUSY 447
+#define ERROR_KBD_INVALID_CODEPAGE 448
+#define ERROR_KBD_UNABLE_TO_FOCUS 449
+#define ERROR_SMG_SESSION_NON_SELECT 450
+#define ERROR_SMG_SESSION_NOT_FOREGRND 451
+#define ERROR_SMG_SESSION_NOT_PARENT 452
+#define ERROR_SMG_INVALID_START_MODE 453
+#define ERROR_SMG_INVALID_RELATED_OPT 454
+#define ERROR_SMG_INVALID_BOND_OPTION 455
+#define ERROR_SMG_INVALID_SELECT_OPT 456
+#define ERROR_SMG_START_IN_BACKGROUND 457
+#define ERROR_SMG_INVALID_STOP_OPTION 458
+#define ERROR_SMG_BAD_RESERVE 459
+#define ERROR_SMG_PROCESS_NOT_PARENT 460
+#define ERROR_SMG_INVALID_DATA_LENGTH 461
+#define ERROR_SMG_NOT_BOUND 462
+#define ERROR_SMG_RETRY_SUB_ALLOC 463
+#define ERROR_KBD_DETACHED 464
+#define ERROR_VIO_DETACHED 465
+#define ERROR_MOU_DETACHED 466
+#define ERROR_VIO_FONT 467
+#define ERROR_VIO_USER_FONT 468
+#define ERROR_VIO_BAD_CP 469
+#define ERROR_VIO_NO_CP 470
+#define ERROR_VIO_NA_CP 471
+#define ERROR_INVALID_CODE_PAGE 472
+#define ERROR_CPLIST_TOO_SMALL 473
+#define ERROR_CP_NOT_MOVED 474
+#define ERROR_MODE_SWITCH_INIT 475
+#define ERROR_CODE_PAGE_NOT_FOUND 476
+#define ERROR_UNEXPECTED_SLOT_RETURNED 477
+#define ERROR_SMG_INVALID_TRACE_OPTION 478
+#define ERROR_VIO_INTERNAL_RESOURCE 479
+#define ERROR_VIO_SHELL_INIT 480
+#define ERROR_SMG_NO_HARD_ERRORS 481
+#define ERROR_CP_SWITCH_INCOMPLETE 482
+#define ERROR_VIO_TRANSPARENT_POPUP 483
+#define ERROR_CRITSEC_OVERFLOW 484
+#define ERROR_CRITSEC_UNDERFLOW 485
+#define ERROR_VIO_BAD_RESERVE 486
+#define ERROR_INVALID_ADDRESS 487
+#define ERROR_ZERO_SELECTORS_REQUESTED 488
+#define ERROR_NOT_ENOUGH_SELECTORS_AVA 489
+#define ERROR_INVALID_SELECTOR 490
+#define ERROR_SMG_INVALID_PROGRAM_TYPE 491
+#define ERROR_SMG_INVALID_PGM_CONTROL 492
+#define ERROR_SMG_INVALID_INHERIT_OPT 493
+#define ERROR_VIO_EXTENDED_SG 494
+#define ERROR_VIO_NOT_PRES_MGR_SG 495
+#define ERROR_VIO_SHIELD_OWNED 496
+#define ERROR_VIO_NO_MORE_HANDLES 497
+#define ERROR_VIO_SEE_ERROR_LOG 498
+#define ERROR_VIO_ASSOCIATED_DC 499
+#define ERROR_KBD_NO_CONSOLE 500
+#define ERROR_MOUSE_NO_CONSOLE 501
+#define ERROR_MOUSE_INVALID_HANDLE 502
+#define ERROR_SMG_INVALID_DEBUG_PARMS 503
+#define ERROR_KBD_EXTENDED_SG 504
+#define ERROR_MOU_EXTENDED_SG 505
+#define ERROR_SMG_INVALID_ICON_FILE 506
+
+
+#define ERROR_USER_DEFINED_BASE 0xFF00
+
+#define ERROR_I24_WRITE_PROTECT 0
+#define ERROR_I24_BAD_UNIT 1
+#define ERROR_I24_NOT_READY 2
+#define ERROR_I24_BAD_COMMAND 3
+#define ERROR_I24_CRC 4
+#define ERROR_I24_BAD_LENGTH 5
+#define ERROR_I24_SEEK 6
+#define ERROR_I24_NOT_DOS_DISK 7
+#define ERROR_I24_SECTOR_NOT_FOUND 8
+#define ERROR_I24_OUT_OF_PAPER 9
+#define ERROR_I24_WRITE_FAULT 10
+#define ERROR_I24_READ_FAULT 11
+#define ERROR_I24_GEN_FAILURE 12
+#define ERROR_I24_DISK_CHANGE 13
+#define ERROR_I24_WRONG_DISK 15
+#define ERROR_I24_UNCERTAIN_MEDIA 16
+#define ERROR_I24_CHAR_CALL_INTERRUPTED 17
+#define ERROR_I24_NO_MONITOR_SUPPORT 18
+#define ERROR_I24_INVALID_PARAMETER 19
+#define ERROR_I24_DEVICE_IN_USE 20
+
+#define ALLOWED_FAIL 0x0001
+#define ALLOWED_ABORT 0x0002
+#define ALLOWED_RETRY 0x0004
+#define ALLOWED_IGNORE 0x0008
+#define ALLOWED_ACKNOWLEDGE 0x0010
+#define ALLOWED_DISPATCH 0x8000
+
+#define I24_OPERATION 0x01
+#define I24_AREA 0x06
+#define I24_CLASS 0x80
+
+/* Values for error CLASS */
+#define ERRCLASS_OUTRES 1 /* Out of Resource */
+#define ERRCLASS_TEMPSIT 2 /* Temporary Situation */
+#define ERRCLASS_AUTH 3 /* Permission problem */
+#define ERRCLASS_INTRN 4 /* Internal System Error */
+#define ERRCLASS_HRDFAIL 5 /* Hardware Failure */
+#define ERRCLASS_SYSFAIL 6 /* System Failure */
+#define ERRCLASS_APPERR 7 /* Application Error */
+#define ERRCLASS_NOTFND 8 /* Not Found */
+#define ERRCLASS_BADFMT 9 /* Bad Format */
+#define ERRCLASS_LOCKED 10 /* Locked */
+#define ERRCLASS_MEDIA 11 /* Media Failure */
+#define ERRCLASS_ALREADY 12 /* Collision with Existing Item */
+#define ERRCLASS_UNK 13 /* Unknown/other */
+#define ERRCLASS_CANT 14
+#define ERRCLASS_TIME 15
+
+/* Values for error ACTION */
+#define ERRACT_RETRY 1 /* Retry */
+#define ERRACT_DLYRET 2 /* Delay Retry, retry after pause */
+#define ERRACT_USER 3 /* Ask user to regive information */
+#define ERRACT_ABORT 4 /* abort with clean up */
+#define ERRACT_PANIC 5 /* abort immediately */
+#define ERRACT_IGNORE 6 /* ignore */
+#define ERRACT_INTRET 7 /* Retry after User Intervention */
+
+/* Values for error LOCUS */
+#define ERRLOC_UNK 1 /* No appropriate value */
+#define ERRLOC_DISK 2 /* Random Access Mass Storage */
+#define ERRLOC_NET 3 /* Network */
+#define ERRLOC_SERDEV 4 /* Serial Device */
+#define ERRLOC_MEM 5 /* Memory */
+
+/* Abnormal termination codes */
+#define TC_NORMAL 0
+#define TC_HARDERR 1
+#define TC_GP_TRAP 2
+#define TC_SIGNAL 3
+
+#define ERROR_SWAPPER_NOT_ACTIVE 32768
+#define ERROR_INVALID_SWAPID 32769
+#define ERROR_IOERR_SWAP_FILE 32770
+#define ERROR_SWAP_TABLE_FULL 32771
+#define ERROR_SWAP_FILE_FULL 32772
+#define ERROR_CANT_INIT_SWAPPER 32773
+#define ERROR_SWAPPER_ALREADY_INIT 32774
+#define ERROR_PMM_INSUFFICIENT_MEMORY 32775
+#define ERROR_PMM_INVALID_FLAGS 32776
+#define ERROR_PMM_INVALID_ADDRESS 32777
+#define ERROR_PMM_LOCK_FAILED 32778
+#define ERROR_PMM_UNLOCK_FAILED 32779
+#define ERROR_PMM_MOVE_INCOMPLETE 32780
+#define ERROR_UCOM_DRIVE_RENAMED 32781
+#define ERROR_UCOM_FILENAME_TRUNCATED 32782
+#define ERROR_UCOM_BUFFER_LENGTH 32783
+#define ERROR_MON_CHAIN_HANDLE 32784
+#define ERROR_MON_NOT_REGISTERED 32785
+#define ERROR_SMG_ALREADY_TOP 32786
+#define ERROR_PMM_ARENA_MODIFIED 32787
+#define ERROR_SMG_PRINTER_OPEN 32788
+#define ERROR_PMM_SET_FLAGS_FAILED 32789
+#define ERROR_INVALID_DOS_DD 32790
+#define ERROR_CPSIO_CODE_PAGE_INVALID 65026
+#define ERROR_CPSIO_NO_SPOOLER 65027
+#define ERROR_CPSIO_FONT_ID_INVALID 65028
+#define ERROR_CPSIO_INTERNAL_ERROR 65033
+#define ERROR_CPSIO_INVALID_PTR_NAME 65034
+#define ERROR_CPSIO_NOT_ACTIVE 65037
+#define ERROR_CPSIO_PID_FULL 65039
+#define ERROR_CPSIO_PID_NOT_FOUND 65040
+#define ERROR_CPSIO_READ_CTL_SEQ 65043
+#define ERROR_CPSIO_READ_FNT_DEF 65045
+#define ERROR_CPSIO_WRITE_ERROR 65047
+#define ERROR_CPSIO_WRITE_FULL_ERROR 65048
+#define ERROR_CPSIO_WRITE_HANDLE_BAD 65049
+#define ERROR_CPSIO_SWIT_LOAD 65074
+#define ERROR_CPSIO_INV_COMMAND 65077
+#define ERROR_CPSIO_NO_FONT_SWIT 65078
+
+#endif
diff --git a/private/mvdm/wow16/rasapi16/makefile b/private/mvdm/wow16/rasapi16/makefile
new file mode 100644
index 000000000..89f5d297f
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/makefile
@@ -0,0 +1,89 @@
+# Copyright (c) 1994, Microsoft Corporation, all rights reserved
+#
+# makefile
+# Remote Access external APIs
+# Windows NT WOS 16->32 thunks, 16-bit side
+#
+# 04/02/94 Steve Cobb (adapted from WFWNET makefile)
+
+
+.SUFFIXES:
+.SUFFIXES: .c .h .obj .lst .exe .map .sym .def .lib .dll .res .rc
+
+
+# W0 used because the CallProc32W prototype causes scads of warnings
+# in normal use. CallProcEx32W should solve this, when available.
+#
+DEFINES = -DWOW $(MVDMFLAGS) -DBUILDDLL
+INCS = -I. -I..\inc
+CW16 = -Alfu -G2s -W0 $(DEFINES) $(INCS)
+LINK = /map /align:16 /nod
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /align:16 /LI
+!endif
+
+!IF "$(QFE_BUILD)" != "1"
+CL16=cl16
+!ELSE
+CL16=cl
+!ENDIF
+
+
+.c.obj:
+ $(CL16) -c -nologo $(CW16) $*.c
+
+.c.lst:
+ $(CL16) -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 $(INCS) -r $*.rc
+
+
+all: rasapi16.dll rasapi16.sym
+ -binplace rasapi16.dll rasapi16.map rasapi16.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+
+rasapi16.obj: .\ras.h .\raserror.h ..\inc\windows.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+rasapi16.lrf: makefile
+ echo rasapi16.obj+ >> $@
+ echo ..\lib\libentry.obj >> $@
+ echo rasapi16.dll >> $@
+ echo rasapi16.map >> $@
+ echo ..\lib\libw.lib+ >> $@
+ echo ..\lib\ldllcew.lib >> $@
+ echo rasapi16.def >> $@
+
+rasapi16.res: $*.rc ..\inc\common.ver ..\inc\version.h ..\inc\ver.h
+ rc16 $(INCS) -r $*.rc
+
+rasapi16.dll: $*.obj $*.res $*.lrf
+rasapi16.dll: ..\lib\libentry.obj ..\lib\libw.lib
+ link16 $(LINK) @$*.lrf;
+ rc16 -t $*.res $*.dll
diff --git a/private/mvdm/wow16/rasapi16/ras.h b/private/mvdm/wow16/rasapi16/ras.h
new file mode 100644
index 000000000..24cb23558
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/ras.h
@@ -0,0 +1,183 @@
+/* Copyright (c) 1992, Microsoft Corporation, all rights reserved
+**
+** ras.h
+** Remote Access external Win16 API
+** Public header for external Win16 API clients
+**
+** Note: The 'dwSize' member of a data structure X must be set to sizeof(X)
+** before calling the associated API, otherwise ERROR_INVALID_SIZE is
+** returned. The value expected by the API is listed next to each
+** 'dwSize' member.
+*/
+
+#ifndef _RAS_H_
+#define _RAS_H_
+
+#ifndef RC_INVOKED
+#pragma pack(2)
+#endif
+
+#ifndef NETCONS_INCLUDED
+#define UNLEN 20
+#define PWLEN 14
+#define DNLEN 15
+#endif
+
+#ifndef APIENTRY
+#define APIENTRY FAR PASCAL
+#endif
+
+#ifndef CHAR
+#define CHAR char
+#endif
+
+#ifndef UINT
+#define UINT unsigned int
+#endif
+
+
+#define RAS_MaxEntryName 20
+#define RAS_MaxDeviceName 32
+#define RAS_MaxDeviceType 16
+#define RAS_MaxParamKey 32
+#define RAS_MaxParamValue 128
+#define RAS_MaxPhoneNumber 128
+#define RAS_MaxCallbackNumber 48
+
+
+#define HRASCONN const void far*
+#define LPHRASCONN HRASCONN FAR*
+
+
+/* Pass this string to the RegisterWindowMessage() API to get the message
+** number that will be used for notifications on the hwnd you pass to the
+** RasDial() API. WM_RASDIALEVENT is used only if a unique message cannot be
+** registered.
+*/
+#define RASDIALEVENT "RasDialEvent"
+#define WM_RASDIALEVENT 0xCCCD
+
+
+/* Identifies an active RAS connection. (See RasConnectEnum)
+*/
+#define RASCONN struct tagRASCONN
+
+RASCONN
+{
+ DWORD dwSize; /* 30 */
+ HRASCONN hrasconn;
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+};
+
+#define LPRASCONN RASCONN FAR*
+
+
+/* Enumerates intermediate states to a connection. (See RasDial)
+*/
+#define RASCS_PAUSED 0x1000
+#define RASCS_DONE 0x2000
+
+#define RASCONNSTATE enum tagRASCONNSTATE
+
+RASCONNSTATE
+{
+ RASCS_OpenPort = 0,
+ RASCS_PortOpened,
+ RASCS_ConnectDevice,
+ RASCS_DeviceConnected,
+ RASCS_AllDevicesConnected,
+ RASCS_Authenticate,
+ RASCS_AuthNotify,
+ RASCS_AuthRetry,
+ RASCS_AuthCallback,
+ RASCS_AuthChangePassword,
+ RASCS_AuthProject,
+ RASCS_AuthLinkSpeed,
+ RASCS_AuthAck,
+ RASCS_ReAuthenticate,
+ RASCS_Authenticated,
+ RASCS_PrepareForCallback,
+ RASCS_WaitForModemReset,
+ RASCS_WaitForCallback,
+
+ RASCS_Interactive = RASCS_PAUSED,
+ RASCS_RetryAuthentication,
+ RASCS_CallbackSetByCaller,
+ RASCS_PasswordExpired,
+
+ RASCS_Connected = RASCS_DONE,
+ RASCS_Disconnected
+};
+
+#define LPRASCONNSTATE RASCONNSTATE FAR*
+
+
+/* Describes the status of a RAS connection. (See RasConnectionStatus)
+*/
+#define RASCONNSTATUS struct tagRASCONNSTATUS
+
+RASCONNSTATUS
+{
+ DWORD dwSize; /* 60 */
+ RASCONNSTATE rasconnstate;
+ DWORD dwError;
+ CHAR szDeviceType[ RAS_MaxDeviceType + 1 ];
+ CHAR szDeviceName[ RAS_MaxDeviceName + 1 ];
+};
+
+#define LPRASCONNSTATUS RASCONNSTATUS FAR*
+
+
+/* Describes connection establishment parameters. (See RasDial)
+*/
+#define RASDIALPARAMS struct tagRASDIALPARAMS
+
+RASDIALPARAMS
+{
+ DWORD dwSize; /* 256 */
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+ CHAR szPhoneNumber[ RAS_MaxPhoneNumber + 1 ];
+ CHAR szCallbackNumber[ RAS_MaxCallbackNumber + 1 ];
+ CHAR szUserName[ UNLEN + 1 ];
+ CHAR szPassword[ PWLEN + 1 ];
+ CHAR szDomain[ DNLEN + 1 ];
+};
+
+#define LPRASDIALPARAMS RASDIALPARAMS FAR*
+
+
+/* Describes an enumerated RAS phone book entry name. (See RasEntryEnum)
+*/
+#define RASENTRYNAME struct tagRASENTRYNAME
+
+RASENTRYNAME
+{
+ DWORD dwSize; /* 26 */
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+};
+
+#define LPRASENTRYNAME RASENTRYNAME FAR*
+
+
+/* External RAS API function prototypes.
+*/
+DWORD APIENTRY RasDial( LPSTR, LPSTR, LPRASDIALPARAMS, LPVOID, HWND,
+ LPHRASCONN );
+
+DWORD APIENTRY RasEnumConnections( LPRASCONN, LPDWORD, LPDWORD );
+
+DWORD APIENTRY RasEnumEntries( LPSTR, LPSTR, LPRASENTRYNAME, LPDWORD,
+ LPDWORD );
+
+DWORD APIENTRY RasGetConnectStatus( HRASCONN, LPRASCONNSTATUS );
+
+DWORD APIENTRY RasGetErrorString( UINT, LPSTR, DWORD );
+
+DWORD APIENTRY RasHangUp( HRASCONN );
+
+
+#ifndef RC_INVOKED
+#pragma pack()
+#endif
+
+#endif
diff --git a/private/mvdm/wow16/rasapi16/rasapi16.c b/private/mvdm/wow16/rasapi16/rasapi16.c
new file mode 100644
index 000000000..65992631d
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/rasapi16.c
@@ -0,0 +1,665 @@
+/* Copyright (c) 1994, Microsoft Corporation, all rights reserved
+**
+** rasapi16.c
+** Remote Access external APIs
+** Windows NT WOW 16->32 thunks, 16-bit side
+**
+** 04/02/94 Steve Cobb
+**
+** This is Win16 code and all included headers are Win16 headers. By it's
+** nature, this code is sensitive to changes in either the Win16 or Win32
+** versions of RAS.H and the system definitions used therein. Numerous name
+** conflicts make it unfeasible to include the Win32 headers here. Win32
+** definitions needed for mapping are defined locally with a "Win32: <header>"
+** comment indicating the location of the duplicated Win32 definition.
+*/
+
+#include <bseerr.h>
+#include <windows.h>
+#include <ras.h>
+#include <raserror.h>
+
+//#define BREAKONENTRY
+
+LPVOID AlignedAlloc( HGLOBAL FAR* ph, DWORD cb );
+VOID AlignedFree( HGLOBAL h );
+DWORD MapErrorCode( DWORD dwError );
+
+
+/*---------------------------------------------------------------------------
+** Win32 definitions
+**---------------------------------------------------------------------------
+*/
+
+/* The Win32 RAS structures are packed on 4-byte boundaries.
+*/
+#pragma pack(4)
+
+
+/* Win32: ras.h - RASCONNA
+** Pads to different size.
+*/
+#define RASCONNA struct tagRASCONNA
+RASCONNA
+{
+ DWORD dwSize;
+ HRASCONN hrasconn;
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+};
+
+#define LPRASCONNA RASCONNA FAR*
+
+/* Win32: ras.h - RASCONNSTATUSA
+** The size of the RASCONNSTATE enum is different.
+** Pads to different size.
+*/
+#define RASCONNSTATUSA struct tagRASCONNSTATUSA
+RASCONNSTATUSA
+{
+ DWORD dwSize;
+ DWORD rasconnstate;
+ DWORD dwError;
+ CHAR szDeviceType[ RAS_MaxDeviceType + 1 ];
+ CHAR szDeviceName[ RAS_MaxDeviceName + 1 ];
+};
+
+#define LPRASCONNSTATUSA RASCONNSTATUSA FAR*
+
+/* Win32: lmcons.h - UNLEN, PWLEN, and DNLEN
+*/
+#define NTUNLEN 256
+#define NTPWLEN 256
+#define NTDNLEN 15
+
+/* Win32: ras.h - RASDIALPARAMSA
+** The credential constants are different.
+*/
+#define RASDIALPARAMSA struct tagRASDIALPARAMSA
+RASDIALPARAMSA
+{
+ DWORD dwSize;
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+ CHAR szPhoneNumber[ RAS_MaxPhoneNumber + 1 ];
+ CHAR szCallbackNumber[ RAS_MaxCallbackNumber + 1 ];
+ CHAR szUserName[ NTUNLEN + 1 ];
+ CHAR szPassword[ NTPWLEN + 1 ];
+ CHAR szDomain[ NTDNLEN + 1 ];
+};
+
+#define LPRASDIALPARAMSA RASDIALPARAMSA FAR*
+
+
+/* Win32: ras.h - RASENTRYNAMEA
+** Pads to different size.
+*/
+#define RASENTRYNAMEA struct tagRASENTRYNAMEA
+RASENTRYNAMEA
+{
+ DWORD dwSize;
+ CHAR szEntryName[ RAS_MaxEntryName + 1 ];
+};
+
+#define LPRASENTRYNAMEA RASENTRYNAMEA FAR*
+
+
+#pragma pack()
+
+
+/* Win32: <rasui>\extapi\src\wow.c - RASAPI32.DLL WOW entry point prototypes
+*/
+typedef DWORD (FAR PASCAL* RASDIALWOW)( LPSTR, LPRASDIALPARAMS, DWORD, LPRASCONN );
+typedef DWORD (FAR PASCAL* RASENUMCONNECTIONSWOW)( LPRASCONN, LPDWORD, LPDWORD );
+typedef DWORD (FAR PASCAL* RASENUMENTRIESWOW)( LPSTR, LPSTR, LPRASENTRYNAME, LPDWORD, LPDWORD );
+typedef DWORD (FAR PASCAL* RASGETCONNECTSTATUSWOW)( HRASCONN, LPRASCONNSTATUS );
+typedef DWORD (FAR PASCAL* RASGETERRORSTRINGWOW)( DWORD, LPSTR, DWORD );
+typedef DWORD (FAR PASCAL* RASHANGUPWOW)( HRASCONN );
+
+
+/*---------------------------------------------------------------------------
+** Globals
+**---------------------------------------------------------------------------
+*/
+
+/* The handle of the RASAPI32.DLL module returned by LoadLibraryEx32W.
+*/
+DWORD HRasApi32Dll = NULL;
+
+/* The unique RasDial notification message as registered in the system at
+** startup (WM_RASDIALEVENT is just a default).
+*/
+UINT UnRasDialEventMsg = WM_RASDIALEVENT;
+
+
+/*---------------------------------------------------------------------------
+** Standard DLL entry points
+**---------------------------------------------------------------------------
+*/
+
+int FAR PASCAL
+LibMain(
+ HINSTANCE hInst,
+ WORD wDataSeg,
+ WORD cbHeapSize,
+ LPSTR lpszCmdLine )
+
+ /* Standard DLL startup routine.
+ */
+{
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ /* Don't even load on anything but NT WOW.
+ */
+ if (!(GetWinFlags() & WF_WINNT))
+ return FALSE;
+
+ /* Load the Win32 RAS API DLL.
+ */
+ HRasApi32Dll = LoadLibraryEx32W( "RASAPI32.DLL", NULL, 0 );
+
+ if (!HRasApi32Dll)
+ return FALSE;
+
+ /* Register a unique message for RasDial notifications.
+ */
+ {
+ UINT unMsg = RegisterWindowMessage( RASDIALEVENT );
+
+ if (unMsg > 0)
+ UnRasDialEventMsg = unMsg;
+ }
+
+ return TRUE;
+}
+
+
+int FAR PASCAL
+WEP(
+ int nExitType )
+
+ /* Standard DLL exit routine.
+ */
+{
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ if (HRasApi32Dll)
+ FreeLibrary32W( HRasApi32Dll );
+
+ return TRUE;
+}
+
+
+/*---------------------------------------------------------------------------
+** 16->32 thunks
+**---------------------------------------------------------------------------
+*/
+
+DWORD APIENTRY
+RasDial(
+ LPSTR reserved,
+ LPSTR lpszPhonebookPath,
+ LPRASDIALPARAMS lprasdialparams,
+ LPVOID reserved2,
+ HWND hwndNotify,
+ LPHRASCONN lphrasconn )
+{
+ DWORD dwErr;
+ RASDIALWOW proc;
+ LPRASDIALPARAMSA prdpa;
+ HGLOBAL hrdpa;
+ LPHRASCONN phrc;
+ HGLOBAL hhrc;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASDIALWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasDialWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ (void )reserved;
+ (void )reserved2;
+
+ /* Account for the increased user name and password field lengths on NT.
+ */
+ if (!(prdpa = (LPRASDIALPARAMSA )AlignedAlloc(
+ &hrdpa, sizeof(RASDIALPARAMSA) )))
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ prdpa->dwSize = sizeof(RASDIALPARAMSA);
+ lstrcpy( prdpa->szEntryName, lprasdialparams->szEntryName );
+ lstrcpy( prdpa->szPhoneNumber, lprasdialparams->szPhoneNumber );
+ lstrcpy( prdpa->szCallbackNumber, lprasdialparams->szCallbackNumber );
+ lstrcpy( prdpa->szUserName, lprasdialparams->szUserName );
+ lstrcpy( prdpa->szPassword, lprasdialparams->szPassword );
+ lstrcpy( prdpa->szDomain, lprasdialparams->szDomain );
+
+ if (!(phrc = (LPHRASCONN )AlignedAlloc(
+ &hhrc, sizeof(HRASCONN) )))
+ {
+ AlignedFree( hrdpa );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ *phrc = *lphrasconn;
+
+ dwErr =
+ CallProc32W(
+ /* 16 */ (DWORD )lpszPhonebookPath,
+ /* 8 */ (DWORD )prdpa,
+ /* 4 */ (DWORD )hwndNotify | 0xFFFF0000,
+ /* 2 */ (DWORD )UnRasDialEventMsg,
+ /* 1 */ (DWORD )phrc,
+ (LPVOID )proc,
+ (DWORD )(16 + 8 + 1),
+ (DWORD )5 );
+
+ *lphrasconn = *phrc;
+
+ AlignedFree( hrdpa );
+ AlignedFree( hhrc );
+
+ return MapErrorCode( dwErr );
+}
+
+
+DWORD APIENTRY
+RasEnumConnections(
+ LPRASCONN lprasconn,
+ LPDWORD lpcb,
+ LPDWORD lpcConnections )
+{
+ DWORD dwErr;
+ RASENUMCONNECTIONSWOW proc;
+ LPRASCONNA prca;
+ HGLOBAL hrca;
+ LPDWORD pcb;
+ HGLOBAL hcb;
+ LPDWORD pcConnections;
+ HGLOBAL hcConnections;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASENUMCONNECTIONSWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasEnumConnectionsWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ /* Check for bad sizes on this side before setting up a substitute buffer.
+ */
+ if (!lprasconn || lprasconn->dwSize != sizeof(RASCONN))
+ return ERROR_INVALID_SIZE;
+
+ if (!lpcb)
+ return ERROR_INVALID_PARAMETER;
+
+ if (!(pcb = (LPDWORD )AlignedAlloc( &hcb, sizeof(DWORD) )))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ *pcb = (*lpcb / sizeof(RASCONN)) * sizeof(RASCONNA);
+
+ if (!(pcConnections = (LPDWORD )AlignedAlloc(
+ &hcConnections, sizeof(DWORD) )))
+ {
+ AlignedFree( hcb );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (lpcConnections)
+ *pcConnections = *lpcConnections;
+
+ if (!(prca = (LPRASCONNA )AlignedAlloc( &hrca, *pcb )))
+ {
+ AlignedFree( hcb );
+ AlignedFree( hcConnections );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ prca->dwSize = sizeof(RASCONNA);
+
+ dwErr =
+ CallProc32W(
+ /* 4 */ (DWORD )prca,
+ /* 2 */ (DWORD )pcb,
+ /* 1 */ (DWORD )pcConnections,
+ (LPVOID )proc,
+ (DWORD )(4 + 2 + 1),
+ (DWORD )3 );
+
+ /* Copy result from substitute buffer back to caller's buffer.
+ */
+ *lpcb = (*pcb / sizeof(RASCONNA)) * sizeof(RASCONN);
+
+ if (lpcConnections)
+ *lpcConnections = *pcConnections;
+
+ if (MapErrorCode( dwErr ) != ERROR_BUFFER_TOO_SMALL)
+ {
+ DWORD i;
+ LPRASCONNA lprcaSub = prca;
+ LPRASCONN lprcCaller = lprasconn;
+
+ for (i = 0; i < *pcConnections; ++i)
+ {
+ lprcCaller->dwSize = sizeof(RASCONN);
+ lprcCaller->hrasconn = lprcaSub->hrasconn;
+ lstrcpy( lprcCaller->szEntryName, lprcaSub->szEntryName );
+
+ ++lprcaSub;
+ ++lprcCaller;
+ }
+ }
+
+ AlignedFree( hcb );
+ AlignedFree( hcConnections );
+ AlignedFree( hrca );
+
+ return MapErrorCode( dwErr );
+}
+
+
+DWORD APIENTRY
+RasEnumEntries(
+ LPSTR reserved,
+ LPSTR lpszPhonebookPath,
+ LPRASENTRYNAME lprasentryname,
+ LPDWORD lpcb,
+ LPDWORD lpcEntries )
+{
+ DWORD dwErr;
+ RASENUMENTRIESWOW proc;
+ LPRASENTRYNAMEA prena;
+ HGLOBAL hrena;
+ LPDWORD pcb;
+ HGLOBAL hcb;
+ LPDWORD pcEntries;
+ HGLOBAL hcEntries;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASENUMENTRIESWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasEnumEntriesWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ /* Check for bad sizes on this side before setting up a substitute buffer.
+ */
+ if (!lprasentryname || lprasentryname->dwSize != sizeof(RASENTRYNAME))
+ return ERROR_INVALID_SIZE;
+
+ if (!lpcb)
+ return ERROR_INVALID_PARAMETER;
+
+ if (!(pcb = (LPDWORD )AlignedAlloc( &hcb, sizeof(DWORD) )))
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ *pcb = (*lpcb / sizeof(RASENTRYNAME)) * sizeof(RASENTRYNAMEA);
+
+ if (!(pcEntries = (LPDWORD )AlignedAlloc(
+ &hcEntries, sizeof(DWORD) )))
+ {
+ AlignedFree( hcb );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ if (lpcEntries)
+ *pcEntries = *lpcEntries;
+
+ if (!(prena = (LPRASENTRYNAMEA )AlignedAlloc( &hrena, *pcb )))
+ {
+ AlignedFree( hcb );
+ AlignedFree( hcEntries );
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ prena->dwSize = sizeof(RASENTRYNAMEA);
+
+ dwErr =
+ CallProc32W(
+ /* 16 */ (DWORD )reserved,
+ /* 8 */ (DWORD )lpszPhonebookPath,
+ /* 4 */ (DWORD )prena,
+ /* 2 */ (DWORD )pcb,
+ /* 1 */ (DWORD )pcEntries,
+ (LPVOID )proc,
+ (DWORD )(16 + 8 + 4 + 2 + 1),
+ (DWORD ) 5 );
+
+ /* Copy result from substitute buffer back to caller's buffer.
+ */
+ *lpcb = (*pcb / sizeof(RASENTRYNAMEA)) * sizeof(RASENTRYNAME);
+
+ if (lpcEntries)
+ *lpcEntries = *pcEntries;
+
+ if (MapErrorCode( dwErr ) != ERROR_BUFFER_TOO_SMALL)
+ {
+ DWORD i;
+ LPRASENTRYNAMEA lprenaSub = prena;
+ LPRASENTRYNAME lprenCaller = lprasentryname;
+
+ for (i = 0; i < *pcEntries; ++i)
+ {
+ lprenCaller->dwSize = sizeof(RASENTRYNAME);
+ lstrcpy( lprenCaller->szEntryName, lprenaSub->szEntryName );
+
+ ++lprenaSub;
+ ++lprenCaller;
+ }
+ }
+
+ AlignedFree( hcb );
+ AlignedFree( hcEntries );
+ AlignedFree( hrena );
+
+ return MapErrorCode( dwErr );
+}
+
+
+DWORD APIENTRY
+RasGetConnectStatus(
+ HRASCONN hrasconn,
+ LPRASCONNSTATUS lprasconnstatus )
+{
+ DWORD dwErr;
+ RASGETCONNECTSTATUSWOW proc;
+ LPRASCONNSTATUSA prcsa;
+ HGLOBAL hrcsa;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASGETCONNECTSTATUSWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasGetConnectStatusWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ /* Check for bad size on this side before setting up a substitute buffer.
+ */
+ if (!lprasconnstatus || lprasconnstatus->dwSize != sizeof(RASCONNSTATUS))
+ return ERROR_INVALID_SIZE;
+
+ if (!(prcsa = (LPRASCONNSTATUSA )AlignedAlloc(
+ &hrcsa, sizeof(RASCONNSTATUSA) )))
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ prcsa->dwSize = sizeof(RASCONNSTATUSA);
+
+ dwErr =
+ CallProc32W(
+ /* 2 */ (DWORD )hrasconn,
+ /* 1 */ (DWORD )prcsa,
+ (LPVOID )proc,
+ (DWORD )1,
+ (DWORD )2 );
+
+ /* Copy result from substitute buffer back to caller's buffer.
+ */
+ lprasconnstatus->rasconnstate = (RASCONNSTATE )prcsa->rasconnstate;
+ lprasconnstatus->dwError = prcsa->dwError;
+ lstrcpy( lprasconnstatus->szDeviceType, prcsa->szDeviceType );
+ lstrcpy( lprasconnstatus->szDeviceName, prcsa->szDeviceName );
+
+ AlignedFree( hrcsa );
+
+ return MapErrorCode( dwErr );
+}
+
+
+DWORD APIENTRY
+RasGetErrorString(
+ UINT uErrorCode,
+ LPSTR lpszBuf,
+ DWORD cbBuf )
+{
+ DWORD dwErr;
+ RASGETERRORSTRINGWOW proc;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASGETERRORSTRINGWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasGetErrorStringWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ dwErr =
+ CallProc32W(
+ /* 4 */ (DWORD )uErrorCode,
+ /* 2 */ (DWORD )lpszBuf,
+ /* 1 */ (DWORD )cbBuf,
+ (LPVOID )proc,
+ (DWORD )2,
+ (DWORD )3 );
+
+ return MapErrorCode( dwErr );
+}
+
+
+DWORD APIENTRY
+RasHangUp(
+ HRASCONN hrasconn )
+{
+ DWORD dwErr;
+ RASHANGUPWOW proc;
+
+#ifdef BREAKONENTRY
+ { _asm int 3 }
+#endif
+
+ proc =
+ (RASHANGUPWOW )GetProcAddress32W(
+ HRasApi32Dll, "RasHangUpWow" );
+
+ if (!proc)
+ return ERROR_INVALID_FUNCTION;
+
+ dwErr =
+ CallProc32W(
+ /* 1 */ (DWORD )hrasconn,
+ (LPVOID )proc,
+ (DWORD )0,
+ (DWORD )1 );
+
+ return MapErrorCode( dwErr );
+}
+
+
+/*---------------------------------------------------------------------------
+** Utilities
+**---------------------------------------------------------------------------
+*/
+
+LPVOID
+AlignedAlloc(
+ HGLOBAL FAR* ph,
+ DWORD cb )
+
+ /* Returns address of block of 'cb' bytes aligned suitably for all
+ ** platforms, or NULL if out of memory. If successful, callers '*ph' is
+ ** set to the handle of the block, used with AllignedFree.
+ */
+{
+ LPVOID pv = NULL;
+ *ph = NULL;
+
+ if (!(*ph = GlobalAlloc( GPTR, cb )))
+ return NULL;
+
+ if (!(pv = (LPVOID )GlobalLock( *ph )))
+ {
+ GlobalFree( *ph );
+ *ph = NULL;
+ }
+
+ return pv;
+}
+
+
+VOID
+AlignedFree(
+ HGLOBAL h )
+
+ /* Frees a block allocated with AlignedAlloc identified by the 'h'
+ ** returned from same.
+ */
+{
+ if (h)
+ {
+ GlobalUnlock( h );
+ GlobalFree( h );
+ }
+}
+
+
+DWORD
+MapErrorCode(
+ DWORD dwError )
+
+ /* Map Win32 error codes to Win16. (Win32: raserror.h)
+ */
+{
+ /* These codes map, but the codes are different in Win16 and Win32.
+ ** ERROR_NO_ISDN_CHANNELS_AVAILABLE truncated to 31 characters. See
+ ** raserror.h.
+ */
+ switch (dwError)
+ {
+ case 709: return ERROR_CHANGING_PASSWORD;
+ case 710: return ERROR_OVERRUN;
+ case 713: return ERROR_NO_ACTIVE_ISDN_LINES;
+ case 714: return ERROR_NO_ISDN_CHANNELS_AVAILABL;
+ }
+
+ /* Pass everything else thru including codes that don't match up to
+ ** anything on Win16 (e.g. RAS errors outside the 600 to 706 range).
+ ** Reasoning is that an unmapped code is more valuable that some generic
+ ** error like ERROR_UNKNOWN.
+ */
+ return dwError;
+}
diff --git a/private/mvdm/wow16/rasapi16/rasapi16.def b/private/mvdm/wow16/rasapi16/rasapi16.def
new file mode 100644
index 000000000..0f04f2468
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/rasapi16.def
@@ -0,0 +1,22 @@
+LIBRARY RASAPI16
+EXETYPE WINDOWS
+DESCRIPTION 'Remote Access Service API WOW thunks'
+
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE
+
+IMPORTS
+ kernel.LoadLibraryEx32W
+ kernel.FreeLibrary32W
+ kernel.GetProcAddress32W
+ kernel.CallProc32W
+
+EXPORTS
+ WEP @1 RESIDENTNAME
+ LibMain
+ RasDial
+ RasEnumConnections
+ RasEnumEntries
+ RasGetConnectStatus
+ RasGetErrorString
+ RasHangUp
diff --git a/private/mvdm/wow16/rasapi16/rasapi16.rc b/private/mvdm/wow16/rasapi16/rasapi16.rc
new file mode 100644
index 000000000..1ee74a9ea
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/rasapi16.rc
@@ -0,0 +1,9 @@
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Remote Access 16->32 API thunks"
+#define VER_INTERNALNAME_STR "RASAPI16"
+#define VER_ORIGINALFILENAME_STR "rasapi16.dll"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/rasapi16/raserror.h b/private/mvdm/wow16/rasapi16/raserror.h
new file mode 100644
index 000000000..bfdcd525c
--- /dev/null
+++ b/private/mvdm/wow16/rasapi16/raserror.h
@@ -0,0 +1,153 @@
+/* Copyright (c) 1993, Microsoft Corporation, all rights reserved
+**
+** raserror.h
+** Remote Access external Win16 API
+** RAS specific error codes
+**
+** Note: The constant names have been truncated at 31 characters to keep C6.0a
+** happy. If there's a switch to get it to accept longer constants it
+** should be used. I didn't find it.
+*/
+
+#ifndef _RASERROR_H_
+#define _RASERROR_H_
+
+#ifndef ERROR_INVALID_HANDLE
+#define ERROR_INVALID_HANDLE 6
+#endif
+
+#ifndef ERROR_NOT_ENOUGH_MEMORY
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#endif
+
+#define RASBASE 600
+
+#define SUCCESS 0
+
+#define PENDING (RASBASE+0)
+#define ERROR_INVALID_PORT_HANDLE (RASBASE+1)
+#define ERROR_PORT_ALREADY_OPEN (RASBASE+2)
+#define ERROR_BUFFER_TOO_SMALL (RASBASE+3)
+#define ERROR_WRONG_INFO_SPECIFIED (RASBASE+4)
+#define ERROR_CANNOT_SET_PORT_INFO (RASBASE+5)
+#define ERROR_PORT_NOT_CONNECTED (RASBASE+6)
+#define ERROR_EVENT_INVALID (RASBASE+7)
+#define ERROR_DEVICE_DOES_NOT_EXIST (RASBASE+8)
+#define ERROR_DEVICETYPE_DOES_NOT_EXIST (RASBASE+9)
+#define ERROR_INVALID_BUFFER (RASBASE+10)
+#define ERROR_ROUTE_NOT_AVAILABLE (RASBASE+11)
+#define ERROR_ROUTE_NOT_ALLOCATED (RASBASE+12)
+#define ERROR_INVALID_COMPRESSION_SPECI (RASBASE+13)
+#define ERROR_OUT_OF_BUFFERS (RASBASE+14)
+#define ERROR_PORT_NOT_FOUND (RASBASE+15)
+#define ERROR_ASYNC_REQUEST_PENDING (RASBASE+16)
+#define ERROR_ALREADY_DISCONNECTING (RASBASE+17)
+#define ERROR_PORT_NOT_OPEN (RASBASE+18)
+#define ERROR_PORT_DISCONNECTED (RASBASE+19)
+#define ERROR_NO_ENDPOINTS (RASBASE+20)
+#define ERROR_CANNOT_OPEN_PHONEBOOK (RASBASE+21)
+#define ERROR_CANNOT_LOAD_PHONEBOOK (RASBASE+22)
+#define ERROR_CANNOT_FIND_PHONEBOOK_ENT (RASBASE+23)
+#define ERROR_CANNOT_WRITE_PHONEBOOK (RASBASE+24)
+#define ERROR_CORRUPT_PHONEBOOK (RASBASE+25)
+#define ERROR_CANNOT_LOAD_STRING (RASBASE+26)
+#define ERROR_KEY_NOT_FOUND (RASBASE+27)
+#define ERROR_DISCONNECTION (RASBASE+28)
+#define ERROR_REMOTE_DISCONNECTION (RASBASE+29)
+#define ERROR_HARDWARE_FAILURE (RASBASE+30)
+#define ERROR_USER_DISCONNECTION (RASBASE+31)
+#define ERROR_INVALID_SIZE (RASBASE+32)
+#define ERROR_PORT_NOT_AVAILABLE (RASBASE+33)
+#define ERROR_CANNOT_PROJECT_CLIENT (RASBASE+34)
+#define ERROR_UNKNOWN (RASBASE+35)
+#define ERROR_WRONG_DEVICE_ATTACHED (RASBASE+36)
+#define ERROR_BAD_STRING (RASBASE+37)
+#define ERROR_REQUEST_TIMEOUT (RASBASE+38)
+#define ERROR_CANNOT_GET_LANA (RASBASE+39)
+#define ERROR_NETBIOS_ERROR (RASBASE+40)
+#define ERROR_SERVER_OUT_OF_RESOURCES (RASBASE+41)
+#define ERROR_NAME_EXISTS_ON_NET (RASBASE+42)
+#define ERROR_SERVER_GENERAL_NET_FAILUR (RASBASE+43)
+#define WARNING_MSG_ALIAS_NOT_ADDED (RASBASE+44)
+#define ERROR_AUTH_INTERNAL (RASBASE+45)
+#define ERROR_RESTRICTED_LOGON_HOURS (RASBASE+46)
+#define ERROR_ACCT_DISABLED (RASBASE+47)
+#define ERROR_PASSWD_EXPIRED (RASBASE+48)
+#define ERROR_NO_DIALIN_PERMISSION (RASBASE+49)
+#define ERROR_SERVER_NOT_RESPONDING (RASBASE+50)
+#define ERROR_FROM_DEVICE (RASBASE+51)
+#define ERROR_UNRECOGNIZED_RESPONSE (RASBASE+52)
+#define ERROR_MACRO_NOT_FOUND (RASBASE+53)
+#define ERROR_MACRO_NOT_DEFINED (RASBASE+54)
+#define ERROR_MESSAGE_MACRO_NOT_FOUND (RASBASE+55)
+#define ERROR_DEFAULTOFF_MACRO_NOT_FOUN (RASBASE+56)
+#define ERROR_FILE_COULD_NOT_BE_OPENED (RASBASE+57)
+#define ERROR_DEVICENAME_TOO_LONG (RASBASE+58)
+#define ERROR_DEVICENAME_NOT_FOUND (RASBASE+59)
+#define ERROR_NO_RESPONSES (RASBASE+60)
+#define ERROR_NO_COMMAND_FOUND (RASBASE+61)
+#define ERROR_WRONG_KEY_SPECIFIED (RASBASE+62)
+#define ERROR_UNKNOWN_DEVICE_TYPE (RASBASE+63)
+#define ERROR_ALLOCATING_MEMORY (RASBASE+64)
+#define ERROR_PORT_NOT_CONFIGURED (RASBASE+65)
+#define ERROR_DEVICE_NOT_READY (RASBASE+66)
+#define ERROR_READING_INI_FILE (RASBASE+67)
+#define ERROR_NO_CONNECTION (RASBASE+68)
+#define ERROR_BAD_USAGE_IN_INI_FILE (RASBASE+69)
+#define ERROR_READING_SECTIONNAME (RASBASE+70)
+#define ERROR_READING_DEVICETYPE (RASBASE+71)
+#define ERROR_READING_DEVICENAME (RASBASE+72)
+#define ERROR_READING_USAGE (RASBASE+73)
+#define ERROR_READING_MAXCONNECTBPS (RASBASE+74)
+#define ERROR_READING_MAXCARRIERBPS (RASBASE+75)
+#define ERROR_LINE_BUSY (RASBASE+76)
+#define ERROR_VOICE_ANSWER (RASBASE+77)
+#define ERROR_NO_ANSWER (RASBASE+78)
+#define ERROR_NO_CARRIER (RASBASE+79)
+#define ERROR_NO_DIALTONE (RASBASE+80)
+#define ERROR_IN_COMMAND (RASBASE+81)
+#define ERROR_WRITING_SECTIONNAME (RASBASE+82)
+#define ERROR_WRITING_DEVICETYPE (RASBASE+83)
+#define ERROR_WRITING_DEVICENAME (RASBASE+84)
+#define ERROR_WRITING_MAXCONNECTBPS (RASBASE+85)
+#define ERROR_WRITING_MAXCARRIERBPS (RASBASE+86)
+#define ERROR_WRITING_USAGE (RASBASE+87)
+#define ERROR_WRITING_DEFAULTOFF (RASBASE+88)
+#define ERROR_READING_DEFAULTOFF (RASBASE+89)
+#define ERROR_EMPTY_INI_FILE (RASBASE+90)
+#define ERROR_AUTHENTICATION_FAILURE (RASBASE+91)
+#define ERROR_PORT_OR_DEVICE (RASBASE+92)
+#define ERROR_NOT_BINARY_MACRO (RASBASE+93)
+#define ERROR_DCB_NOT_FOUND (RASBASE+94)
+#define ERROR_STATE_MACHINES_NOT_STARTE (RASBASE+95)
+#define ERROR_STATE_MACHINES_ALREADY_ST (RASBASE+96)
+#define ERROR_PARTIAL_RESPONSE_LOOPING (RASBASE+97)
+#define ERROR_UNKNOWN_RESPONSE_KEY (RASBASE+98)
+#define ERROR_RECV_BUF_FULL (RASBASE+99)
+#define ERROR_CMD_TOO_LONG (RASBASE+100)
+#define ERROR_UNSUPPORTED_BPS (RASBASE+101)
+#define ERROR_UNEXPECTED_RESPONSE (RASBASE+102)
+#define ERROR_INTERACTIVE_MODE (RASBASE+103)
+#define ERROR_BAD_CALLBACK_NUMBER (RASBASE+104)
+#define ERROR_INVALID_AUTH_STATE (RASBASE+105)
+#define ERROR_WRITING_INITBPS (RASBASE+106)
+#define ERROR_INVALID_WIN_HANDLE (RASBASE+107)
+#define ERROR_NO_PASSWORD (RASBASE+108)
+#define ERROR_NO_USERNAME (RASBASE+109)
+#define ERROR_CANNOT_START_STATE_MACHIN (RASBASE+110)
+#define ERROR_GETTING_COMMSTATE (RASBASE+111)
+#define ERROR_SETTING_COMMSTATE (RASBASE+112)
+#define ERROR_COMM_FUNCTION (RASBASE+113)
+#define ERROR_CONFIGURATION_PROBLEM (RASBASE+114)
+#define ERROR_X25_DIAGNOSTIC (RASBASE+115)
+#define ERROR_TOO_MANY_LINE_ERRORS (RASBASE+116)
+#define ERROR_OVERRUN (RASBASE+117)
+#define ERROR_ACCT_EXPIRED (RASBASE+118)
+#define ERROR_CHANGING_PASSWORD (RASBASE+119)
+#define ERROR_NO_ACTIVE_ISDN_LINES (RASBASE+120)
+#define ERROR_NO_ISDN_CHANNELS_AVAILABL (RASBASE+121)
+
+#define RASBASEEND (RASBASE+121)
+
+
+#endif // _RASERROR_H_
diff --git a/private/mvdm/wow16/regedit/common.h b/private/mvdm/wow16/regedit/common.h
new file mode 100644
index 000000000..afdab71ab
--- /dev/null
+++ b/private/mvdm/wow16/regedit/common.h
@@ -0,0 +1,162 @@
+#ifndef REG_COMMON
+#define REG_COMMON
+
+#ifdef NOHELP
+
+#define MyHelp( x , y , z)
+
+#endif
+
+#include <shellapi.h>
+
+
+/*********************************************************/
+/******************* Constants ***************************/
+/*********************************************************/
+
+#define OPENDLG 4096
+#define MAINICON 4097
+#define MAINMENU 4098
+#define SDKMAINMENU 4099
+
+#define ID_HELP 0x0400
+#define ID_HELPBUTTON 0x0401
+
+#define ID_MERGEFILE 0x0410
+#define ID_EXIT (ID_MERGEFILE+1)
+
+#define ID_ADD 0x0420
+#define ID_COPY (ID_ADD+1)
+#define ID_MODIFY (ID_ADD+2)
+#define ID_DELETE (ID_ADD+3)
+#define ID_EDITVAL (ID_ADD+4)
+
+#define ID_FINISHMERGE 0x0430
+#define ID_IDLIST (ID_FINISHMERGE+1)
+
+#define ID_FIRSTREGEDIT 0x0500
+#define ID_FIRSTSDKREGED 0x0600
+
+/* The help ID's should be last */
+#define ID_HELPINDEX 0x0700
+#define ID_HELPSEARCH (ID_HELPINDEX+1)
+#define ID_HELPUSINGHELP (ID_HELPINDEX+2)
+#define ID_ABOUT (ID_HELPINDEX+3)
+
+#define IDS_SHORTNAME 0x0100
+#define IDS_WIDTH (IDS_SHORTNAME+1)
+#define IDS_HEIGHT (IDS_SHORTNAME+2)
+
+#define IDS_MEDIUMNAME 0x0110
+#define IDS_DESCRIPTION (IDS_MEDIUMNAME+1)
+
+#define IDS_MERGETITLE 0x0120
+#define IDS_REGS (IDS_MERGETITLE+1)
+#define IDS_CUSTREGS (IDS_MERGETITLE+2)
+
+#define IDS_OUTOFMEMORY 0x0130
+#define IDS_LONGNAME (IDS_OUTOFMEMORY+1)
+
+#define IDS_CANTOPENFILE 0x0140
+#define IDS_CANTREADFILE (IDS_CANTOPENFILE+1)
+#define IDS_REGHEADER (IDS_CANTOPENFILE+2)
+#define IDS_BADFORMAT (IDS_CANTOPENFILE+3)
+#define IDS_SUCCESSREAD (IDS_CANTOPENFILE+4)
+
+#define IDS_HELPFILE 0x0150
+#define IDS_HELP (IDS_HELPFILE+1)
+#define IDS_HELPERR (IDS_HELPFILE+2)
+#define IDS_SDKHELPFILE (IDS_HELPFILE+3)
+
+#define IDS_BADDB 0x0160
+#define IDS_BADKEY (IDS_BADDB+1)
+#define IDS_CANTOPENDB (IDS_BADDB+2)
+#define IDS_CANTREADDB (IDS_BADDB)
+#define IDS_CANTWRITEDB (IDS_BADDB+3)
+#define IDS_INVALIDPARM (IDS_BADKEY)
+#define IDS_ENDERROR (IDS_BADDB+4)
+
+#define IDS_BUSY 0x0170
+
+#define IDS_FIRSTREGEDIT 0x0200
+#define IDS_FIRSTSDKREGED 0x0300
+
+#define FLAG_SILENT 0x0001
+#define FLAG_NOMESSAGES 0x0002
+#define FLAG_VERBOSE 0x0004
+#define FLAG_WRITETHROUGH 0x0008
+#define FLAG_LEAVECOMMAND 0x0010
+
+#define IDH_SYSMENU 0x2000
+#define IDW_MAIN (IDH_SYSMENU+1)
+#define IDW_SDKMAIN (IDW_MAIN+0x80)
+
+#define IDW_OPENREG 0x3000
+#define IDW_OPENEXE (IDW_OPENREG+1)
+#define IDW_SAVEREG (IDW_OPENREG+2)
+
+#define IDW_MODIFY 0x4000
+
+#define MAX_KEY_LENGTH 64
+
+
+/*********************************************************/
+/******************* Macros ******************************/
+/*********************************************************/
+
+#define OFFSET(x) ((PSTR)(LOWORD((DWORD)(x))))
+
+
+/*********************************************************/
+/******************* Globals *****************************/
+/*********************************************************/
+
+extern HANDLE hInstance;
+extern HWND hWndMain, hWndDlg, hWndHelp;
+extern LPSTR lpCmdLine;
+extern WORD wCmdFlags, wHelpMenuItem, wHelpId;
+extern LONG (FAR PASCAL *lpfnEditor)(HWND, WORD, WORD, LONG);
+extern FARPROC lpOldHook;
+extern FARPROC lpMainWndDlg;
+extern WORD wHelpIndex;
+
+
+/*********************************************************/
+/******************* Functions ***************************/
+/*********************************************************/
+
+/***** cutils1.c *****/
+extern HANDLE NEAR PASCAL StringToLocalHandle(LPSTR szStr, WORD wFlags);
+extern LPSTR NEAR _fastcall MyStrTok(LPSTR szList, char cEnd);
+extern int NEAR PASCAL DoDialogBoxParam(LPCSTR lpDialog, HWND hWnd,
+ FARPROC lpfnProc, DWORD dwParam);
+extern int NEAR PASCAL DoDialogBox(LPCSTR, HWND, FARPROC);
+extern unsigned long NEAR PASCAL MyQueryValue(HKEY hKey, PSTR pSubKey,
+ HANDLE *hBuf);
+extern HANDLE NEAR PASCAL GetEditString(HWND hWndEdit);
+extern HANDLE NEAR _fastcall MyLoadString(WORD wId, WORD *pwSize, WORD wFlags);
+extern int NEAR cdecl MyMessageBox(HWND hWnd, WORD wText, WORD wType,
+ WORD wExtra, ...);
+extern VOID NEAR PASCAL WriteProfileInt(WORD wAppName, WORD wKey, int nVal);
+extern int NEAR PASCAL MyGetProfileInt(WORD wAppName, WORD wKey, int nDefault);
+extern HANDLE NEAR PASCAL StringToHandle(LPSTR szStr);
+extern int FAR PASCAL MessageFilter(int nCode, WORD wParam, LPMSG lpMsg);
+
+#ifndef NOHELP
+extern VOID NEAR PASCAL MyHelp(HWND hWnd, WORD wCommand, DWORD wId);
+#endif
+
+extern HANDLE NEAR PASCAL GetListboxString(HWND hWndEdit, int nId);
+extern unsigned long NEAR PASCAL MyEnumKey(HKEY hKey, WORD wIndex,
+ HANDLE *hBuf);
+extern WORD NEAR _fastcall GetErrMsg(WORD wRet);
+extern VOID NEAR PASCAL RepeatMove(LPSTR lpDest, LPSTR lpSrc, WORD wBytes);
+
+/***** merge.c *****/
+extern VOID NEAR PASCAL ProcessFiles(HWND hDlg, HANDLE hCmdLine, WORD wFlags);
+
+/***** filename.c *****/
+extern BOOL NEAR PASCAL DoFileOpenDlg(HWND hWnd, WORD wTitle, WORD wFilter,
+ WORD wCustomFilter, HANDLE *hCustomFilter, HANDLE *hFileName, BOOL bOpen);
+
+#endif
diff --git a/private/mvdm/wow16/regedit/cutils1.c b/private/mvdm/wow16/regedit/cutils1.c
new file mode 100644
index 000000000..56c9de5c3
--- /dev/null
+++ b/private/mvdm/wow16/regedit/cutils1.c
@@ -0,0 +1,389 @@
+#include <windows.h>
+#include "common.h"
+
+#define BLOCKLEN 100
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+extern HANDLE hInstance;
+extern FARPROC lpOldHook;
+extern HWND hWndMain, hWndHelp;
+extern WORD wHelpMain;
+
+extern char *pszLongName;
+extern char *pszOutOfMemory;
+
+HANDLE NEAR PASCAL StringToLocalHandle(LPSTR szStr, WORD wFlags)
+{
+ HANDLE hStr;
+ LPSTR lpStr;
+
+ if(!(hStr=LocalAlloc(wFlags, lstrlen(szStr) + 1)))
+ goto Error1;
+ if(!(lpStr=LocalLock(hStr)))
+ goto Error2;
+ lstrcpy(lpStr, szStr);
+ LocalUnlock(hStr);
+ goto Error1;
+
+Error2:
+ LocalFree(hStr);
+ hStr = NULL;
+Error1:
+ return(hStr);
+}
+
+LPSTR NEAR _fastcall MyStrTok(LPSTR szList, char cEnd)
+{
+ LPSTR szTemp;
+
+ /* if there are no more tokens return NULL */
+ if(!*szList)
+ return NULL;
+
+ /* find delimiter or end of string */
+ while(*szList && *szList!=cEnd)
+ szList = AnsiNext(szList);
+
+ /* if we found a delimiter insert string terminator and skip */
+ if(*szList) {
+ szTemp = szList;
+ szList = AnsiNext(szTemp);
+ *szTemp = '\0';
+ }
+
+ /* return token */
+ return(szList);
+}
+
+int NEAR PASCAL DoDialogBoxParam(LPCSTR lpDialog, HWND hWnd, FARPROC lpfnProc,
+ DWORD dwParam)
+{
+ int result = -1;
+
+ if(!(lpfnProc = MakeProcInstance(lpfnProc, hInstance)))
+ goto Error1;
+ result = DialogBoxParam(hInstance, lpDialog, hWnd, lpfnProc, dwParam);
+ FreeProcInstance(lpfnProc);
+
+Error1:
+ return(result);
+}
+
+int NEAR PASCAL DoDialogBox(LPCSTR lpDialog, HWND hWnd, FARPROC lpfnProc)
+{
+ return(DoDialogBoxParam(lpDialog, hWnd, lpfnProc, 0L));
+}
+
+unsigned long NEAR PASCAL MyQueryValue(HKEY hKey, PSTR pSubKey, HANDLE *hBuf)
+{
+ HANDLE hTemp;
+ PSTR pBuf;
+ WORD wBufSize = BLOCKLEN;
+ unsigned long result = ERROR_OUTOFMEMORY;
+ LONG lSize;
+
+ if(!(*hBuf=LocalAlloc(LMEM_MOVEABLE, wBufSize)))
+ goto Error1;
+ if(!(pBuf=LocalLock(*hBuf)))
+ goto Error2;
+
+ while((lSize=wBufSize, (result=RegQueryValue(hKey, pSubKey, pBuf, &lSize))
+ ==ERROR_SUCCESS) && (WORD)lSize>wBufSize-10) {
+ LocalUnlock(*hBuf);
+ wBufSize += BLOCKLEN;
+ if(!(hTemp=LocalReAlloc(*hBuf, wBufSize, LMEM_MOVEABLE))) {
+ result = ERROR_OUTOFMEMORY;
+ goto Error2;
+ }
+ pBuf = LocalLock(*hBuf=hTemp);
+ }
+ LocalUnlock(*hBuf);
+ if(result!=ERROR_SUCCESS || !lSize)
+ goto Error2;
+ goto Error1;
+
+Error2:
+ LocalFree(*hBuf);
+ *hBuf = NULL;
+Error1:
+ return(result);
+}
+
+HANDLE NEAR PASCAL GetEditString(HWND hWndEdit)
+{
+ HANDLE hEdit = NULL;
+ PSTR pEdit;
+ WORD wLen;
+
+ wLen = LOWORD(SendMessage(hWndEdit, WM_GETTEXTLENGTH, 0, 0L)) + 1;
+ if(!(hEdit=LocalAlloc(LMEM_MOVEABLE, wLen)))
+ goto Error1;
+ if(!(pEdit=LocalLock(hEdit)))
+ goto Error2;
+
+ SendMessage(hWndEdit, WM_GETTEXT, wLen, (DWORD)((LPSTR)pEdit));
+ LocalUnlock(hEdit);
+ goto Error1;
+
+Error2:
+ LocalFree(hEdit);
+ hEdit = NULL;
+Error1:
+ return(hEdit);
+}
+
+HANDLE NEAR _fastcall MyLoadString(WORD wId, WORD *pwSize, WORD wFlags)
+{
+ char szString[258]; /* RC limits strings to 256 chars */
+ WORD wSize;
+
+ wSize = LoadString(hInstance, wId, szString, sizeof(szString));
+ if(pwSize)
+ *pwSize = wSize;
+ return(StringToLocalHandle(szString, wFlags));
+}
+
+int NEAR cdecl MyMessageBox(HWND hWnd, WORD wText, WORD wType, WORD wExtra, ...)
+{
+ HANDLE hText, hRText;
+ PSTR pText, pRText;
+ WORD wSize;
+ int result = 0;
+
+ if(wText == IDS_OUTOFMEMORY)
+ goto Error1;
+
+ if(!(hText=MyLoadString(wText, &wSize, LMEM_MOVEABLE)))
+ goto Error1;
+
+ /* We allocate enough room for a bunch of numbers and the strings
+ */
+ if(!(hRText=LocalAlloc(LMEM_MOVEABLE, 2*wSize + wExtra)))
+ goto Error2;
+ if(!(pRText=LocalLock(hRText)))
+ goto Error3;
+
+ pText = LocalLock(hText);
+ wvsprintf(pRText, pText, (LPSTR)(&wExtra+1));
+ result = MessageBox(hWnd, pRText, pszLongName, wType);
+
+ LocalUnlock(hText);
+ LocalUnlock(hRText);
+Error3:
+ LocalFree(hRText);
+Error2:
+ LocalFree(hText);
+Error1:
+ if(!result) {
+ MessageBox(hWnd, pszOutOfMemory, pszLongName,
+ MB_ICONHAND | MB_SYSTEMMODAL | MB_OK);
+ }
+
+ return(result);
+}
+
+VOID NEAR PASCAL WriteProfileInt(WORD wAppName, WORD wKey, int nVal)
+{
+ HANDLE hAppName, hKey;
+ char buf[10];
+
+ if(!(hAppName=MyLoadString(wAppName, NULL, LMEM_MOVEABLE)))
+ goto Error1;
+ if(!(hKey=MyLoadString(wKey, NULL, LMEM_MOVEABLE)))
+ goto Error2;
+
+ wsprintf(buf, "%d", nVal);
+ WriteProfileString(LocalLock(hAppName), LocalLock(hKey), buf);
+
+ LocalUnlock(hKey);
+ LocalUnlock(hAppName);
+Error2:
+ LocalFree(hKey);
+Error1:
+ LocalFree(hAppName);
+}
+
+int NEAR PASCAL MyGetProfileInt(WORD wAppName, WORD wKey, int nDefault)
+{
+ HANDLE hAppName, hKey;
+
+ if(!(hAppName=MyLoadString(wAppName, NULL, LMEM_MOVEABLE)))
+ goto Error1;
+ if(!(hKey=MyLoadString(wKey, NULL, LMEM_MOVEABLE)))
+ goto Error2;
+
+ nDefault = GetProfileInt(LocalLock(hAppName), LocalLock(hKey), nDefault);
+
+ LocalUnlock(hKey);
+ LocalUnlock(hAppName);
+Error2:
+ LocalFree(hKey);
+Error1:
+ LocalFree(hAppName);
+ return(nDefault);
+}
+
+HANDLE NEAR PASCAL StringToHandle(LPSTR szStr)
+{
+ HANDLE hStr;
+ LPSTR lpStr;
+
+ if(!(hStr=GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,
+ (DWORD)(lstrlen(szStr)+1))))
+ goto Error1;
+ if(!(lpStr=GlobalLock(hStr)))
+ goto Error2;
+ lstrcpy(lpStr, szStr);
+ GlobalUnlock(hStr);
+ goto Error1;
+
+Error2:
+ GlobalFree(hStr);
+ hStr = NULL;
+Error1:
+ return(hStr);
+}
+
+int FAR PASCAL MessageFilter(int nCode, WORD wParam, LPMSG lpMsg)
+{
+ switch(nCode) {
+ case MSGF_MENU:
+ case MSGF_DIALOGBOX:
+ if(lpMsg->message==WM_KEYDOWN && lpMsg->wParam==VK_F1
+ && !(lpMsg->lParam&(1L<<30)))
+ PostMessage(hWndHelp, WM_COMMAND, ID_HELP,
+ MAKELONG(lpMsg->hwnd, nCode));
+ break;
+
+ default:
+ DefHookProc(nCode, wParam, (DWORD)lpMsg, &lpOldHook);
+ return(FALSE);
+ }
+
+ return(FALSE);
+}
+
+#ifndef NOHELP
+
+// #define ONLYID
+VOID NEAR PASCAL MyHelp(HWND hWnd, WORD wCommand, DWORD wId)
+{
+#ifdef ONLYID
+ if(wCommand != HELP_QUIT)
+ MyMessageBox(hWnd, IDS_HELP, MB_OK, 0, wId);
+#else
+ HANDLE hHelpFile;
+ PSTR pHelpFile;
+
+ if(!(hHelpFile=MyLoadString(wHelpMain==IDW_SDKMAIN ?
+ IDS_SDKHELPFILE : IDS_HELPFILE, NULL, LMEM_MOVEABLE)))
+ return;
+
+ if(!WinHelp(hWndMain, pHelpFile=LocalLock(hHelpFile), wCommand, wId))
+ MyMessageBox(hWnd, IDS_HELPERR, MB_OK, 0);
+ else
+ WinHelp(hWndMain, pHelpFile, HELP_SETINDEX, wHelpIndex);
+
+ LocalUnlock(hHelpFile);
+ LocalFree(hHelpFile);
+#endif
+}
+
+#endif
+
+HANDLE NEAR PASCAL GetListboxString(HWND hWndEdit, int nId)
+{
+ HANDLE hEdit = NULL;
+ PSTR pEdit;
+ WORD wLen;
+
+ wLen = LOWORD(SendMessage(hWndEdit, LB_GETTEXTLEN, nId, 0L)) + 1;
+ if(!(hEdit=LocalAlloc(LMEM_MOVEABLE, wLen)))
+ goto Error1;
+ if(!(pEdit=LocalLock(hEdit)))
+ goto Error2;
+
+ SendMessage(hWndEdit, LB_GETTEXT, nId, (DWORD)((LPSTR)pEdit));
+ LocalUnlock(hEdit);
+ goto Error1;
+
+Error2:
+ LocalFree(hEdit);
+ hEdit = NULL;
+Error1:
+ return(hEdit);
+}
+
+unsigned long NEAR PASCAL MyEnumKey(HKEY hKey, WORD wIndex, HANDLE *hBuf)
+{
+ HANDLE hTemp;
+ PSTR pBuf;
+ WORD wBufSize = BLOCKLEN, wSize;
+ unsigned long result = ERROR_OUTOFMEMORY;
+
+ if(!(*hBuf=LocalAlloc(LMEM_MOVEABLE, wBufSize)))
+ goto Error1;
+ if(!(pBuf=LocalLock(*hBuf)))
+ goto Error2;
+
+ while((result=RegEnumKey(hKey, wIndex, pBuf, (DWORD)wBufSize))
+ ==ERROR_SUCCESS && (wSize=lstrlen(pBuf))>wBufSize-10) {
+ LocalUnlock(*hBuf);
+ wBufSize += BLOCKLEN;
+ if(!(hTemp=LocalReAlloc(*hBuf, wBufSize, LMEM_MOVEABLE))) {
+ result = ERROR_OUTOFMEMORY;
+ goto Error2;
+ }
+ pBuf = LocalLock(*hBuf=hTemp);
+ }
+ LocalUnlock(*hBuf);
+ if(result!=ERROR_SUCCESS || !wSize)
+ goto Error2;
+ goto Error1;
+
+Error2:
+ LocalFree(*hBuf);
+ *hBuf = NULL;
+Error1:
+ return(result);
+}
+
+static WORD wErrMsgs[] = {
+ 0, IDS_BADDB, IDS_BADKEY, IDS_CANTOPENDB, IDS_CANTREADDB, IDS_CANTWRITEDB,
+ IDS_OUTOFMEMORY, IDS_INVALIDPARM
+} ;
+
+WORD NEAR _fastcall GetErrMsg(WORD wRet)
+{
+ return(wRet>=sizeof(wErrMsgs)/sizeof(wErrMsgs[0]) ?
+ IDS_INVALIDPARM : wErrMsgs[wRet]);
+}
+
+VOID NEAR PASCAL RepeatMove(LPSTR lpDest, LPSTR lpSrc, WORD wBytes)
+{
+/* WARNING: This assumes that the buffers are in different segments, or
+ * the offset of the dest is less than the offset of the src
+ */
+
+/* Save DS, and load up ES:DI, DS:SI, and CX with the parameters */
+_asm push ds
+_asm les di,lpDest
+_asm lds si,lpSrc
+_asm mov cx,wBytes
+_asm cld
+
+/* Do a movsb if CX is odd, and then do movsw for CX/2 */
+_asm shr CX,1
+_asm jnc repm1
+_asm movsb
+_asm repm1:
+_asm jcxz repm2
+_asm rep movsw
+_asm repm2:
+
+/* Restore DS and return */
+_asm pop ds
+}
diff --git a/private/mvdm/wow16/regedit/dbase.c b/private/mvdm/wow16/regedit/dbase.c
new file mode 100644
index 000000000..c12c77bbe
--- /dev/null
+++ b/private/mvdm/wow16/regedit/dbase.c
@@ -0,0 +1,276 @@
+#include <windows.h>
+#include "RegEdit.h"
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+#define NUMACTIONS (ID_LASTACTIONRADIO-ID_FIRSTACTIONRADIO+1)
+#define EDITSPERACTION (ID_LASTEDIT-ID_FIRSTACTIONEDIT+1)
+#define OFFSET_COMMAND 0
+#define OFFSET_FIRSTDDE 1
+#define OFFSET_DDEEXEC 1
+#define OFFSET_DDEIFEXEC 2
+#define OFFSET_DDEAPP 3
+#define OFFSET_DDETOPIC 4
+#define BLOCKLEN 100
+
+char szNull[] = "";
+
+static char szShell[] = "shell";
+static char szCommand[] = "command";
+static char szDDEExec[] = "ddeexec";
+static char szDDEIfExec[] = "ddeexec\\ifexec";
+static char szDDEApplication[] = "ddeexec\\application";
+static char szDDETopic[] = "ddeexec\\topic";
+static char *ppCommands[] = {
+ szCommand, szDDEExec, szDDEIfExec, szDDEApplication, szDDETopic
+} ;
+static char szOpen[] = "open";
+static char szPrint[] = "print";
+static char *ppActionIds[] = {
+ szOpen, szPrint
+} ;
+static char szSystem[] = "System";
+
+char cUsesDDE[NUMACTIONS];
+
+HANDLE *pLocalVals = NULL;
+
+WORD NEAR PASCAL CreateId(HANDLE hId)
+{
+ HKEY hKeyNew;
+ PSTR pId, pTemp;
+ WORD wErrMsg = IDS_INVALIDID;
+
+ pId = LocalLock(hId);
+ if(!*pId || *pId=='.')
+ goto Error1;
+ for(pTemp=pId; *pTemp; ++pTemp)
+/* this excludes '\\' and all other chars except 33-127 */
+ if(*pTemp=='\\' || *pTemp<=' ')
+ goto Error1;
+
+ wErrMsg = IDS_EXISTS;
+ if(RegOpenKey(HKEY_CLASSES_ROOT, pId, &hKeyNew) == ERROR_SUCCESS)
+ goto Error2;
+
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT, pId, &hKeyNew)))
+ goto Error1;
+ wErrMsg = NULL;
+
+Error2:
+ RegCloseKey(hKeyNew);
+Error1:
+ LocalUnlock(hId);
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL MyGetClassName(HANDLE hId, HANDLE *hName)
+{
+ WORD wErrMsg;
+
+ wErrMsg = GetErrMsg((WORD)MyQueryValue(HKEY_CLASSES_ROOT, LocalLock(hId),
+ hName));
+ LocalUnlock(hId);
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL DeleteClassId(HANDLE hId)
+{
+ WORD wErrMsg;
+
+ wErrMsg = GetErrMsg((WORD)RegDeleteKey(HKEY_CLASSES_ROOT, LocalLock(hId)));
+ LocalUnlock(hId);
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL MergeData(HWND hWndName, HANDLE hId)
+{
+ HANDLE hName;
+ HANDLE *phTemp;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+ HKEY hKeyId, hKeyShell, hKeyAction;
+ int i, j;
+
+ if(!(hName=GetEditString(hWndName)))
+ goto Error2;
+ if(wErrMsg=GetErrMsg((WORD)RegOpenKey(HKEY_CLASSES_ROOT, LocalLock(hId),
+ &hKeyId)))
+ goto Error3;
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(hKeyId, szShell, &hKeyShell)))
+ goto Error4;
+ if(wErrMsg=GetErrMsg((WORD)RegSetValue(hKeyId, szNull, (DWORD)REG_SZ,
+ LocalLock(hName), 0L)))
+ goto Error5;
+
+ for(i=0, phTemp=pLocalVals; i<NUMACTIONS; ++i) {
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(hKeyShell, ppActionIds[i],
+ &hKeyAction)))
+ goto Error5;
+
+ for(j=0; j<EDITSPERACTION; ++j, ++phTemp) {
+ if(*phTemp && (j<OFFSET_FIRSTDDE || cUsesDDE[i])) {
+ PSTR pTemp;
+
+ pTemp = LocalLock(*phTemp);
+ if((j==OFFSET_DDETOPIC && !lstrcmpi(pTemp, szSystem)) ||
+ (j==OFFSET_DDEAPP && !lstrcmpi(pTemp,
+ GetAppName(*(phTemp+OFFSET_COMMAND-OFFSET_DDEAPP)))))
+ RegDeleteKey(hKeyAction, ppCommands[j]);
+ else
+ wErrMsg = GetErrMsg((WORD)RegSetValue(hKeyAction, ppCommands[j],
+ (DWORD)REG_SZ, pTemp, 0L));
+ LocalUnlock(*phTemp);
+ if(wErrMsg)
+ goto Error5;
+ } else {
+ RegDeleteKey(hKeyAction, ppCommands[j]);
+ }
+ }
+
+ RegCloseKey(hKeyAction);
+ }
+ wErrMsg = NULL;
+
+Error5:
+ LocalUnlock(hName);
+ RegCloseKey(hKeyShell);
+Error4:
+ RegCloseKey(hKeyId);
+Error3:
+ LocalUnlock(hId);
+ LocalFree(hName);
+Error2:
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL ResetClassList(HWND hWndIdList, HWND hWndNameList)
+{
+ HANDLE hClassId, hClassName;
+ HKEY hKeyClasses;
+ int i;
+ WORD wErrMsg;
+
+/* Reset the name list */
+ SendMessage(hWndIdList, LB_RESETCONTENT, 0, 0L);
+ SendMessage(hWndNameList, LB_RESETCONTENT, 0, 0L);
+
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT, szNull,
+ &hKeyClasses)))
+ goto Error1;
+
+ for(i=0; MyEnumKey(hKeyClasses, i, &hClassId)==ERROR_SUCCESS && !wErrMsg;
+ ++i) {
+ int nId;
+ PSTR pClassId;
+
+ pClassId = LocalLock(hClassId);
+ if(*pClassId=='.' || (wErrMsg=MyGetClassName(hClassId, &hClassName)))
+ goto Error2;
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if((nId=(int)SendMessage(hWndNameList, LB_ADDSTRING, 0,
+ (DWORD)((LPSTR)LocalLock(hClassName))))==LB_ERR
+ || SendMessage(hWndIdList, LB_INSERTSTRING, nId,
+ (DWORD)((LPSTR)pClassId))==LB_ERR)
+ goto Error3;
+
+ wErrMsg = NULL;
+Error3:
+ LocalUnlock(hClassName);
+ LocalFree(hClassName);
+Error2:
+ LocalUnlock(hClassId);
+ LocalFree(hClassId);
+ }
+
+ SendMessage(hWndNameList, LB_SETTOPINDEX, 0, 0L);
+ SendMessage(hWndNameList, LB_SETCURSEL, 0, 0L);
+
+ RegCloseKey(hKeyClasses);
+Error1:
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL GetLocalCopies(HWND hWndName, HANDLE hId)
+{
+ HKEY hKeyId, hKeyShell, hSubKey;
+ HANDLE hName, *phTemp;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+ int i, j;
+
+ if(!pLocalVals) {
+ HANDLE hLocalVals;
+
+ if(!(hLocalVals=LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
+ NUMACTIONS*EDITSPERACTION*sizeof(HANDLE)))
+ || !(pLocalVals=(HANDLE *)LocalLock(hLocalVals)))
+ goto Error1;
+ }
+
+ for(i=0, phTemp=pLocalVals; i<NUMACTIONS; ++i) {
+ cUsesDDE[i] = 0;
+
+ for(j=0; j<EDITSPERACTION; ++j, ++phTemp) {
+ if(*phTemp) {
+ LocalFree(*phTemp);
+ *phTemp = NULL;
+ }
+ }
+ }
+ SendMessage(hWndName, WM_SETTEXT, 0, (DWORD)((LPSTR)szNull));
+ if(!hId)
+ return(NULL);
+
+ if(wErrMsg=GetErrMsg((WORD)RegOpenKey(HKEY_CLASSES_ROOT, LocalLock(hId),
+ &hKeyId)))
+ goto Error3;
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(hKeyId, szShell, &hKeyShell)))
+ goto Error4;
+
+ if(wErrMsg=GetErrMsg((WORD)MyQueryValue(hKeyId, szNull, &hName)))
+ goto Error5;
+ SendMessage(hWndName, WM_SETTEXT, 0, (DWORD)((LPSTR)LocalLock(hName)));
+ LocalUnlock(hName);
+ LocalFree(hName);
+
+ for(i=0, phTemp=pLocalVals; i<NUMACTIONS; ++i) {
+ if(wErrMsg=GetErrMsg((WORD)RegCreateKey(hKeyShell, ppActionIds[i],
+ &hSubKey)))
+ goto Error5;
+
+ for(j=0; j<EDITSPERACTION; ++j, ++phTemp) {
+ if((wErrMsg=(WORD)MyQueryValue(hSubKey, ppCommands[j], phTemp))
+ !=(WORD)ERROR_BADKEY && (wErrMsg=GetErrMsg(wErrMsg)))
+ goto Error5;
+
+ if(j>=OFFSET_FIRSTDDE) {
+ if(*phTemp)
+ cUsesDDE[i] = 1;
+ else if(j == OFFSET_DDETOPIC) {
+ *phTemp = StringToLocalHandle(szSystem, LMEM_MOVEABLE);
+ } else if(j == OFFSET_DDEAPP) {
+ HANDLE hTemp;
+
+ if(hTemp = *(phTemp-(OFFSET_DDEAPP+OFFSET_COMMAND)))
+ *phTemp = StringToLocalHandle(GetAppName(hTemp),
+ LMEM_MOVEABLE);
+ }
+ }
+ }
+
+ RegCloseKey(hSubKey);
+ }
+
+ wErrMsg = NULL;
+Error5:
+ RegCloseKey(hKeyShell);
+Error4:
+ RegCloseKey(hKeyId);
+Error3:
+ LocalUnlock(hId);
+Error1:
+ return(wErrMsg);
+}
+
diff --git a/private/mvdm/wow16/regedit/filename.c b/private/mvdm/wow16/regedit/filename.c
new file mode 100644
index 000000000..65af9008d
--- /dev/null
+++ b/private/mvdm/wow16/regedit/filename.c
@@ -0,0 +1,162 @@
+#include <windows.h>
+#include <commdlg.h>
+#include <dlgs.h>
+#include "common.h"
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+#define MYMAXPATH 255
+
+extern HANDLE hInstance;
+extern HWND hWndHelp;
+extern WORD wHelpId;
+
+static VOID NEAR PASCAL ReplaceChar(LPSTR lpStr, char cOld, char cNew)
+{
+ for( ; *lpStr; lpStr=AnsiNext(lpStr))
+ if(*lpStr == cOld)
+ *lpStr = cNew;
+}
+
+int FAR PASCAL MyOpenDlgProc(HWND hWnd, WORD message, WORD wParam, DWORD lParam)
+{
+ switch(message) {
+ case WM_ACTIVATE:
+ if(wParam)
+ hWndHelp = hWnd;
+ return(FALSE);
+
+ case WM_INITDIALOG:
+ return(TRUE);
+
+ case WM_COMMAND:
+ switch(wParam) {
+ case ID_HELP:
+ if(GetParent(LOWORD(lParam)) != hWnd)
+ break;
+ case psh15:
+ MyHelp(hWnd, HELP_CONTEXT, wHelpId);
+ break;
+ }
+ break;
+ }
+
+ return(FALSE);
+}
+
+HANDLE NEAR PASCAL MyLoadGlobalString(HANDLE wString, WORD *wSize)
+{
+ HANDLE hlString, hString;
+
+ if(!(hlString=MyLoadString(wString, wSize, LMEM_MOVEABLE)))
+ goto Error1;
+ hString = StringToHandle(LocalLock(hlString));
+ LocalUnlock(hlString);
+ LocalFree(hlString);
+
+Error1:
+ return(hString);
+}
+
+BOOL NEAR PASCAL DoFileOpenDlg(HWND hWnd, WORD wTitle, WORD wFilter,
+ WORD wCustomFilter, HANDLE *hCustomFilter, HANDLE *hFileName, BOOL bOpen)
+{
+ HANDLE hOfn, hFilter, hTitle;
+ LPOPENFILENAME lpOfn;
+ LPSTR lpFileName, lpFilter;
+ BOOL result = FALSE;
+#ifdef USECUSTOMFILTER
+ HANDLE hpFilter;
+ LPSTR lpCustomFilter;
+ WORD wSize;
+#endif
+
+ if(!(hOfn=GlobalAlloc(GMEM_FIXED, sizeof(OPENFILENAME))))
+ goto Error1;
+ if(!(lpOfn=(LPOPENFILENAME)GlobalLock(hOfn)))
+ goto Error2;
+
+ if(!(hFilter=MyLoadGlobalString(wFilter, NULL)))
+ goto Error3;
+ lpFilter = GlobalLock(hFilter);
+ ReplaceChar(AnsiNext(lpFilter), *lpFilter, '\0');
+
+ if(!(hTitle=MyLoadGlobalString(wTitle, NULL)))
+ goto Error4;
+
+ if(!(*hFileName=GlobalAlloc(GMEM_MOVEABLE, MYMAXPATH)))
+ goto Error5;
+ if(!(lpFileName=GlobalLock(*hFileName)))
+ goto Error6;
+ *lpFileName = '\0';
+
+#ifdef USECUSTOMFILTER
+ if(*hCustomFilter) {
+ lpCustomFilter = GlobalLock(*hCustomFilter);
+ } else {
+ if(!(*hCustomFilter=MyLoadGlobalString(wCustomFilter, &wSize)))
+ goto Error7;
+ if(hpFilter=GlobalReAlloc(*hCustomFilter, 2*wSize, GMEM_MOVEABLE))
+ *hCustomFilter = hpFilter;
+ lpCustomFilter = GlobalLock(*hCustomFilter);
+ ReplaceChar(AnsiNext(lpCustomFilter), *lpCustomFilter, '\0');
+ }
+#endif
+
+ lpOfn->lStructSize = sizeof(OPENFILENAME);
+ lpOfn->hwndOwner = hWnd;
+ lpOfn->hInstance = hInstance;
+ lpOfn->lpstrFilter = AnsiNext(lpFilter);
+#ifdef USECUSTOMFILTER
+ lpOfn->lpstrCustomFilter = AnsiNext(lpCustomFilter);
+ lpOfn->nMaxCustFilter = GlobalSize(*hCustomFilter) - 1;
+#else
+ lpOfn->lpstrCustomFilter = NULL;
+ lpOfn->nMaxCustFilter = 0;
+#endif
+ lpOfn->nFilterIndex = 0;
+ lpOfn->lpstrFile = lpFileName;
+ lpOfn->nMaxFile = MYMAXPATH;
+ lpOfn->lpstrFileTitle = NULL;
+ lpOfn->nMaxFileTitle = 0;
+ lpOfn->lpstrInitialDir = NULL;
+ lpOfn->lpstrTitle = GlobalLock(hTitle);
+ lpOfn->Flags = OFN_HIDEREADONLY
+#ifndef NOHELP
+ | OFN_SHOWHELP
+#endif
+ | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK;
+ lpOfn->lpstrDefExt = NULL;
+ lpOfn->lCustData = 0;
+ lpOfn->lpfnHook = MakeProcInstance(MyOpenDlgProc, hInstance);
+ lpOfn->lpTemplateName = NULL;
+
+ result = bOpen ? GetOpenFileName(lpOfn) : GetSaveFileName(lpOfn);
+
+ if(lpOfn->lpfnHook)
+ FreeProcInstance(lpOfn->lpfnHook);
+
+ GlobalUnlock(hTitle);
+#ifdef USECUSTOMFILTER
+ GlobalUnlock(*hCustomFilter);
+Error7:
+#endif
+ GlobalUnlock(*hFileName);
+Error6:
+ if(!result)
+ GlobalFree(*hFileName);
+Error5:
+ GlobalFree(hTitle);
+Error4:
+ GlobalUnlock(hFilter);
+ GlobalFree(hFilter);
+Error3:
+ GlobalUnlock(hOfn);
+Error2:
+ GlobalFree(hOfn);
+Error1:
+ return(result);
+}
+
diff --git a/private/mvdm/wow16/regedit/makefile b/private/mvdm/wow16/regedit/makefile
new file mode 100644
index 000000000..2b7c43291
--- /dev/null
+++ b/private/mvdm/wow16/regedit/makefile
@@ -0,0 +1,211 @@
+#International mods
+# NOTE: INTL_SRC, INTL_EXE nad LANG are external macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=$(INTL_SRC)\$(LANG)\sdk\regedit
+EXE_DIR=$(INTL_EXE)
+!ENDIF
+
+.SUFFIXES: .sym .map
+SRCDIR = .
+NAME1=$(DSTDIR)\regedt16
+NAME2=$(DSTDIR)\regload
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!ifdef NOHELP
+DEF =/DNOHELP
+!else
+DEF=
+!endif
+
+CFLAGS = -c -W3 -AS -G2sw -Zlp -Os $(DEF) -I..\inc -I\nt\public\sdk\inc
+AFLAGS = -Mx
+LFLAGS = /ALIGN:16/NOE/LI/MAP
+DSTDIR = .
+
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+DODEBUG=1
+DEF = -DDEBUG $(DEF)
+CFLAGS = $(CFLAGS) -Od -Zi
+AFLAGS = $(AFLAGS) /Zi
+LFLAGS = $(LFLAGS) /CO
+DSTDIR = .\debug
+!ENDIF
+
+COMMON1 = $(DSTDIR)\cutils1.obj $(DSTDIR)\merge.obj $(DSTDIR)\dbase.obj
+COMMON2 = $(DSTDIR)\utils1.obj $(DSTDIR)\regporte.obj $(DSTDIR)\regthunk.obj
+OBJ1_1 = $(DSTDIR)\regmain.obj $(DSTDIR)\regedit.obj $(DSTDIR)\filename.obj
+OBJ1_2 = $(DSTDIR)\sdkreged.obj $(DSTDIR)\sdbase.obj $(DSTDIR)\virt.obj
+OBJ2_1 = $(NAME2).obj
+LIB1 = ..\lib\libw ..\lib\slibcew ..\lib\snocrt ..\lib\commdlg ..\lib\shell
+LIB2 = ..\lib\libw ..\lib\slibcew ..\lib\snocrt ..\lib\shell
+
+# International mods
+!IFNDEF LANG
+all: $(NAME1).exe
+allall: all $(NAME2).exe
+!ELSE
+all: $(NAME1).$(LANG)
+!ENDIF
+!IFNDEF DODEBUG
+!IFDEF DEBUG
+ nmake DODEBUG=
+!ENDIF
+!ENDIF
+
+!IFNDEF LANG
+$(DSTDIR)\regedit.res: $(RES_DIR)\regedit.rc $(RES_DIR)\sdkreged.dlg $(RES_DIR)\regedit.rcv
+ rc16 -I..\inc -r $(DEF) -fo$(DSTDIR)\regedit.res $(RES_DIR)\regedit.rc
+
+$(NAME2).res: $(RES_DIR)\regedit.rc $(RES_DIR)\sdkreged.dlg $(RES_DIR)\regload.rcv
+ rc16 -I..\inc -r $(DEF) -DREGLOAD -fo$(NAME2).res $(RES_DIR)\regedit.rc
+!ELSE
+regedit.res: $(RES_DIR)\regedit.res
+ copy $(RES_DIR)\regedit.res
+!ENDIF
+
+{$(SRCDIR)}.c{$(DSTDIR)}.obj:
+ cl16 $(CFLAGS) /Fo$*.obj $<
+
+{$(SRCDIR)}.asm{$(DSTDIR)}.obj:
+ masm $(AFLAGS) $<, $*.obj;
+
+regedt16: $(NAME1).exe
+!IFNDEF DODEBUG
+!IFDEF DEBUG
+ nmake DODEBUG= regedt16
+!ENDIF
+!ENDIF
+
+regload: $(NAME2).exe
+!IFNDEF DODEBUG
+!IFDEF DEBUG
+ nmake DODEBUG= regload
+!ENDIF
+!ENDIF
+
+#International mods
+iclean:
+ del *.rc
+ del *.dlg
+ del *.res
+
+$(NAME1).$(LANG): iclean $(DSTDIR)\regedit.res
+ copy $(EXE_DIR)\$(NAME1).exe $(NAME1).$(LANG)
+ rc16 -I..\inc -t -30 $(DSTDIR)\regedit.res $(NAME1).$(LANG)
+
+$(NAME1).exe: $(NAME1).tmp $(DSTDIR)\regedit.res
+ rc16 -I..\inc -t -30 $(DSTDIR)\regedit.res $(NAME1).exe
+ -binplace $@
+
+$(NAME2).exe: $(NAME2).tmp $(NAME2).res
+ rc16 -I..\inc -t -30 $(NAME2).res $(NAME2).exe
+ -binplace $@
+
+$(NAME1).tmp $(NAME1).map: $(OBJ1_1) $(OBJ1_2) $(COMMON1) $(COMMON2) regedit.def
+ link16 $(LFLAGS) @<<
+ $(OBJ1_1) +
+ $(OBJ1_2) +
+ $(COMMON1) +
+ $(COMMON2),
+ $(NAME1).exe,
+ $(NAME1),
+ $(LIB1),
+ regedit.def
+<<
+!IFDEF DODEBUG
+ cd debug
+ mapsym regedt16.map
+ cd ..
+!ELSE
+ mapsym regedt16.map
+!ENDIF
+ type regedit.def > $(NAME1).tmp
+
+$(NAME2).tmp $(NAME2).map: $(OBJ2_1) $(COMMON1) $(COMMON2) regload.def
+ link16 $(LFLAGS) @<<
+ $(OBJ2_1) +
+ $(COMMON1) +
+ $(COMMON2),
+ $(NAME2).exe,
+ $(NAME2),
+ $(LIB2),
+ regload.def
+<<
+!IFDEF DODEBUG
+ cd debug
+ mapsym regload.map
+ cd ..
+!ELSE
+ mapsym regload.map
+!ENDIF
+ type regload.def > $(NAME2).tmp
+
+debug:
+ nmake DODEBUG=
+
+clean: cleanup all
+
+cleanup:
+ -del debug\$(NAME1).exe
+ -del debug\$(NAME2).exe
+ -del debug\$(NAME1).tmp
+ -del debug\$(NAME2).tmp
+ -del debug\*.res
+ -del debug\*.obj
+ -del debug\*.map
+ -del debug\*.sym
+ -del $(NAME1).exe
+ -del $(NAME2).exe
+ -del $(NAME1).tmp
+ -del $(NAME2).tmp
+ -del *.res
+ -del *.obj
+ -del *.map
+ -del *.sym
+
+
+$(NAME2).obj: regmain.c
+ cl16 -c -Fo$(NAME2).obj -DREGLOAD $(CFLAGS) regmain.c
+
+depend:
+ mv makefile makefile.old
+ sed "/^# START Dependencies/,/^# END Dependencies/D" makefile.old > makefile
+ del makefile.old
+ echo # START Dependencies >> makefile
+ includes -l *.c *.asm >> makefile
+ echo # END Dependencies >> makefile
+
+# START Dependencies
+$(DSTDIR)\cutils1.obj: cutils1.c common.h
+
+$(DSTDIR)\dbase.obj: dbase.c RegEdit.h common.h
+
+$(DSTDIR)\filename.obj: filename.c common.h
+
+$(DSTDIR)\regedit.obj: regedit.c RegEdit.h common.h
+
+$(DSTDIR)\regmain.obj: regmain.c RegEdit.h SDKRegEd.h common.h
+
+$(DSTDIR)\sdbase.obj: sdbase.c SDKRegEd.h common.h
+
+$(DSTDIR)\sdkreged.obj: sdkreged.c SDKRegEd.h common.h
+
+$(DSTDIR)\utils1.obj: utils1.c
+
+$(DSTDIR)\virt.obj: virt.c SDKRegEd.h common.h
+
+$(DSTDIR)\merge.obj: merge.c common.h
+
+$(DSTDIR)\regporte.obj: regporte.c reg1632.h regdef.h regporte.h regresid.h
+
+$(DSTDIR)\regthunk.obj: regthunk.c regporte.h
+# END Dependencies
diff --git a/private/mvdm/wow16/regedit/merge.c b/private/mvdm/wow16/regedit/merge.c
new file mode 100644
index 000000000..61d5738ad
--- /dev/null
+++ b/private/mvdm/wow16/regedit/merge.c
@@ -0,0 +1,241 @@
+#include <windows.h>
+#include "common.h"
+
+#define BLOCKLEN 100
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+LPSTR lpMerge;
+char szDotClasses[] = "\\.classes\\";
+char szHkeyClassesRoot[] = "HKEY_CLASSES_ROOT\\";
+
+extern HWND hWndHelp;
+
+extern unsigned long NEAR PASCAL MySetValue(HKEY hKey, PSTR pSubKey, PSTR pVal);
+
+NEAR PASCAL
+ImportWin40RegFile(
+ VOID
+ );
+
+static PSTR NEAR PASCAL GetFileLine(void)
+{
+ static HANDLE hFile = NULL;
+ static PSTR pFile;
+ static WORD wLen;
+
+ LPSTR lpStart;
+ HANDLE hTemp;
+ WORD wLineLen;
+ char cFile;
+
+/* We need a place to put the file line */
+ if(!hFile) {
+ if(!(hFile=LocalAlloc(LMEM_MOVEABLE, wLen=BLOCKLEN)))
+ goto Error1;
+ if(!(pFile=LocalLock(hFile)))
+ goto Error2;
+ }
+
+/* If we have read the whole file, then clean up and return */
+ if(!*lpMerge)
+ goto Error3;
+
+ for(lpStart=lpMerge; ; ) {
+ cFile = *lpMerge;
+ lpMerge = AnsiNext(lpMerge);
+
+ switch(cFile) {
+ case('\n'):
+ case('\r'):
+ case('\0'):
+/* EOL so return */
+ goto CopyLine;
+ }
+ }
+
+CopyLine:
+ wLineLen = lpMerge - lpStart - 1;
+/* Make the buffer larger if necessary */
+ if(wLineLen >= wLen) {
+ LocalUnlock(hFile);
+ wLen = wLineLen + BLOCKLEN;
+ if(!(hTemp=LocalReAlloc(hFile, wLen, LMEM_MOVEABLE)))
+ goto Error2;
+ if(!(pFile=LocalLock(hFile=hTemp)))
+ goto Error2;
+ }
+ RepeatMove(pFile, lpStart, wLineLen);
+ pFile[wLineLen] = '\0';
+ return(pFile);
+
+
+Error3:
+ LocalUnlock(hFile);
+Error2:
+ LocalFree(hFile);
+ hFile = NULL;
+Error1:
+ return(NULL);
+}
+
+static VOID NEAR PASCAL MergeFileData(void)
+{
+ static struct tagKEYANDROOT
+ {
+ PSTR szKey;
+ HKEY hKeyRoot;
+ } krClasses[] =
+ {
+ szHkeyClassesRoot, HKEY_CLASSES_ROOT,
+ szDotClasses, HKEY_CLASSES_ROOT
+ } ;
+#define NUM_KEYWORDS (sizeof(krClasses)/sizeof(krClasses[0]))
+
+ PSTR pLine;
+ PSTR pLast;
+ HKEY hKeyRoot, hSubKey;
+ int i;
+
+ /* Get the initial line if this is the first time through */
+ if(!(pLine=GetFileLine()))
+ return;
+ /* Otherwise, open a key so that we only do one write to the disk */
+ if(RegCreateKey(HKEY_CLASSES_ROOT, NULL, &hSubKey) != ERROR_SUCCESS)
+ return;
+
+ do
+ {
+ for (i=0; i<NUM_KEYWORDS; ++i)
+ {
+ char cTemp;
+ int nCmp, nLen;
+
+ cTemp = pLine[nLen=lstrlen(krClasses[i].szKey)];
+ pLine[nLen] = '\0';
+ nCmp = lstrcmp(krClasses[i].szKey, pLine);
+ pLine[nLen] = cTemp;
+ if (!nCmp)
+ {
+ pLine += nLen;
+ hKeyRoot = krClasses[i].hKeyRoot;
+ goto MergeTheData;
+ }
+ }
+ continue;
+
+MergeTheData:
+ /* This is a line that needs to get merged.
+ * Find a space (and then skip spaces) or "= " */
+ for(pLast=pLine; *pLast; pLast=AnsiNext(pLast))
+ {
+ if(*pLast == ' ')
+ {
+ *pLast = '\0';
+ while(*(++pLast) == ' ')
+ /* find the first non-space */ ;
+ break;
+ }
+ }
+
+ /* There is an error if we don't have "= " */
+ if(*pLast=='=' && *(++pLast)==' ')
+ ++pLast;
+
+ /* Set the value */
+ MySetValue(hKeyRoot, pLine, pLast);
+ } while(pLine=GetFileLine()) ;
+
+ RegCloseKey(hSubKey);
+}
+
+
+VOID NEAR PASCAL ProcessFiles(HWND hDlg, HANDLE hCmdLine, WORD wFlags)
+{
+ HANDLE hMerge, hHeader;
+ PSTR pHeader;
+ int hFile;
+ LONG lSize;
+ LPSTR lpFileName, lpTemp;
+ OFSTRUCT of;
+ WORD wErrMsg;
+
+ lpFileName = GlobalLock(hCmdLine);
+/* We need to process all file names on the command line */
+ while(lpTemp=MyStrTok(lpFileName, ' ')) {
+/* Open the file */
+ wErrMsg = IDS_CANTOPENFILE;
+ if((hFile=OpenFile(lpFileName, &of, OF_READ)) == -1)
+ goto Error2;
+
+/* Determine the file size; limit it to just less than 64K */
+ wErrMsg = IDS_CANTREADFILE;
+ if((lSize=_llseek(hFile, 0L, 2))==-1 || lSize>0xfff0)
+ goto Error3;
+ _llseek(hFile, 0L, 0);
+
+/* Allocate a block of memory for the file */
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hMerge=GlobalAlloc(GHND, lSize+2)))
+ goto Error3;
+ if(!(lpMerge=GlobalLock(hMerge)))
+ goto Error4;
+
+/* Read in the file */
+ wErrMsg = IDS_CANTREADFILE;
+ if(_lread(hFile, lpMerge, LOWORD(lSize)) != LOWORD(lSize))
+ goto Error5;
+
+/* Look for the header */
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hHeader=MyLoadString(IDS_REGHEADER, NULL, LMEM_MOVEABLE)))
+ goto Error5;
+ pHeader = LocalLock(hHeader);
+
+ wErrMsg = IDS_BADFORMAT;
+ while(*lpMerge == ' ')
+ ++lpMerge;
+ while(*pHeader)
+ if(*lpMerge++ != *pHeader++)
+ goto Error6;
+ if(*lpMerge=='4')
+ {
+ ImportWin40RegFile();
+ wErrMsg = IDS_SUCCESSREAD;
+ goto Error6;
+ }
+ while(*lpMerge == ' ')
+ ++lpMerge;
+ if(*lpMerge!='\r' && *lpMerge!='\n')
+ goto Error6;
+
+/* Merge the data */
+ MergeFileData(); /* This makes the changes */
+
+ wErrMsg = IDS_SUCCESSREAD;
+Error6:
+ LocalUnlock(hHeader);
+ LocalFree(hHeader);
+Error5:
+ GlobalUnlock(hMerge);
+Error4:
+ GlobalFree(hMerge);
+Error3:
+ _lclose(hFile);
+Error2:
+/* Display the status message */
+ if(!(wFlags&FLAG_SILENT) || wErrMsg!=IDS_SUCCESSREAD)
+ MyMessageBox(hDlg, wErrMsg, MB_OK | MB_ICONEXCLAMATION,
+ lstrlen(lpFileName), lpFileName);
+
+ lpFileName = lpTemp;
+ while(*lpFileName == ' ')
+ ++lpFileName;
+ }
+
+ GlobalUnlock(hCmdLine);
+
+ GlobalFree(hCmdLine);
+}
diff --git a/private/mvdm/wow16/regedit/messages/usa/regedit.rc b/private/mvdm/wow16/regedit/messages/usa/regedit.rc
new file mode 100644
index 000000000..9396881a8
--- /dev/null
+++ b/private/mvdm/wow16/regedit/messages/usa/regedit.rc
@@ -0,0 +1,199 @@
+#define WIN31
+
+#include <windows.h>
+#include "RegEdit.h"
+#include "SDKRegEd.h"
+
+MAINICON ICON RegEdit.ico
+
+STRINGTABLE PRELOAD MOVEABLE DISCARDABLE
+BEGIN
+ IDS_LONGNAME, "Registration Info Editor"
+ IDS_MEDIUMNAME, "Registration Editor"
+ IDS_SHORTNAME, "RegEdit"
+
+ IDS_OUTOFMEMORY, "Not enough memory to continue. Quit one or more applications, and then try again."
+
+ IDS_WIDTH, "width"
+ IDS_HEIGHT, "height"
+ IDS_DESCRIPTION, "An editor for registration information for applications."
+
+ IDS_SUREDELETE, "Are you sure you want to delete ""%s"" File Type?"
+
+ IDS_MERGETITLE, "Merge Registration File"
+ IDS_BROWSETITLE, "Browse"
+ IDS_EXES, ",Programs,*.com;*.exe;*.bat;*.pif,All Files (*.*),*.*,"
+ IDS_REGS, ",Registration Files (*.reg),*.reg,All Files (*.*),*.*,"
+#ifdef USECUSTOMFILTER
+ IDS_CUSTEXES, ",Default,*.com;*.exe;*.bat;*.pif,"
+ IDS_CUSTREGS, ",Default,*.reg,"
+#endif
+
+ IDS_REGHEADER, "REGEDIT"
+ IDS_CANTOPENFILE, "Cannot open file: %s.\nMake sure the specified path and filename are correct."
+ IDS_CANTREADFILE, "Cannot read file: %s"
+ IDS_BADFORMAT, "This is not a registration file.\nSelect a registration file (.REG), and then try again."
+ IDS_SUCCESSREAD, "Information in %s has been successfully registered in the registration database."
+
+ IDS_BUSY, "The registration database editor is busy with another operation;\nfinish that and try again."
+
+ IDS_HELPFILE, "regedit.hlp"
+ IDS_HELP, "Id 0x%04x"
+ IDS_HELPERR, "There is a problem with the Help system."
+ IDS_SDKHELPFILE, "regeditv.hlp"
+
+ IDS_EXISTS, "The identifier %s already exists.\nType a unique name in the Identifier box."
+ IDS_INVALIDID, "The specified identifier is not valid.\n\nSpecify a valid identifier. The identifier must be unique and can contain up to 63 characters. It cannot contain any spaces, extended or control characters, or backslashes (\)."
+ IDS_INVALIDNAME, "There is no File Type specified.\n\nType a description of the file type in the File Type box."
+
+ IDS_ADD, "Add File Type"
+ IDS_COPY, "Copy File Type"
+
+ IDS_BADDB, "There is a problem with the REG.DAT file. Quit Windows, delete REG.DAT, and then restart Windows. Then run REGEDIT.EXE and restore the registration database. For more information, see online Help for the Registration Info Editor."
+ IDS_BADKEY, "There was an error in modifying the database. The registration database may be corrupted."
+ IDS_CANTOPENDB, "The file REG.DAT could not be opened. Make sure that it exists in your Windows directory and that it is not currently being used by another application."
+ IDS_CANTWRITEDB, "Cannot write to file REG.DAT. Make sure there is enough space on the disk."
+ IDS_ENDERROR, "%s\n\nDo you want to close Registration Info Editor?"
+
+ IDS_WRITETITLE, "Save Registration File"
+ IDS_CANTWRITEFILE, "Cannot write to the file. Make sure the disk is not full or write-protected."
+
+ IDS_NOSUBKEY, "Cannot copy key to a subkey of itself."
+ IDS_ALREADYEXIST, "Cannot copy key to an existing key. Specify a new key name in the To box."
+
+ IDS_SAVECHANGES, "Changes have been made to the registration database. Do you want to save them?"
+ IDS_ERRORSAVING, "There was an error saving the changes."
+ IDS_SURERESTORE, "Are you sure you want to lose all changes?"
+ IDS_NODELROOT, "Cannot delete the root key. Delete all subkeys instead."
+
+ IDS_SOURCENOTEXIST, "The key '%s' does not exist."
+END
+
+MAINMENU MENU PRELOAD MOVEABLE DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Merge Registration File...", ID_MERGEFILE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_EXIT
+ END
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Add File Type...", ID_ADD
+ MENUITEM "&Copy File Type...", ID_COPY
+ MENUITEM "&Modify File Type...", ID_MODIFY
+ MENUITEM "&Delete File Type", ID_DELETE
+ END
+#ifndef NOHELP
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents", ID_HELPINDEX
+ MENUITEM "&Search for Help On...", ID_HELPSEARCH
+ MENUITEM "&How to Use Help", ID_HELPUSINGHELP
+ MENUITEM SEPARATOR
+ MENUITEM "&About Registration Editor...", ID_ABOUT
+ END
+#else
+ POPUP "&Info"
+ BEGIN
+ MENUITEM "&About Registration Editor...", ID_ABOUT
+ END
+#endif
+END
+
+SDKMAINWND DIALOG PRELOAD MOVEABLE DISCARDABLE 16, 16, 160, 128
+STYLE WS_CHILD
+FONT 8, "Helv"
+BEGIN
+ LISTBOX ID_IDLIST, 0, 26, 160, 100, WS_TABSTOP | WS_VSCROLL | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS
+ LISTBOX ID_VALLIST, -100, -100, 10, 10
+ LISTBOX ID_DELLIST, -100, -100, 10, 10
+
+ LTEXT "Full Path:", -1, 4, 2, 48, 8
+ LTEXT "", ID_FULLPATH, 54, 2, 100, 8
+ LTEXT "Value:", -1, 4, 14, 48, 8
+ EDITTEXT ID_VALUE, 54, 12, 100, 12, ES_AUTOHSCROLL
+END
+
+#include "messages\usa\sdkreged.dlg"
+
+MAINWND DIALOG PRELOAD MOVEABLE DISCARDABLE 0, 0, 160, 96
+STYLE WS_CHILD
+FONT 8, "Helv"
+BEGIN
+ LTEXT "Registered File Types:", -1, 4, 4, 80, 10
+ LISTBOX ID_NAMELIST, 0, 16, 160, 80, WS_TABSTOP | WS_VSCROLL | LBS_DISABLENOSCROLL | LBS_SORT
+ LISTBOX ID_IDLIST, -100, -100, 10, 10
+END
+
+EDITDLG DIALOG LOADONCALL MOVEABLE DISCARDABLE 16, 16, 212, 172
+STYLE WS_CAPTION | WS_SYSMENU | DS_MODALFRAME
+CAPTION "Modify File Type"
+FONT 8, "Helv"
+BEGIN
+ LTEXT "&Identifier:", -1, 4, 4, 40, 10
+ LTEXT "", ID_STATCLASSID, 48, 4, 92, 10
+ EDITTEXT ID_CLASSID, 48, 2, 92, 12, ES_AUTOHSCROLL
+ LTEXT "&File Type:", -1, 4, 20, 40, 10
+ EDITTEXT ID_CLASSNAME, 48, 18, 92, 12, ES_AUTOHSCROLL
+ GROUPBOX "Action", -1, 4, 30, 136, 24
+ RADIOBUTTON "&Open", ID_OPENRADIO, 20, 42, 52, 10
+ RADIOBUTTON "&Print", ID_PRINTRADIO, 76, 42, 52, 10
+ LTEXT "&Command:", -1, 4, 60, 40, 10
+ EDITTEXT ID_COMMAND, 48, 58, 92, 12, ES_AUTOHSCROLL
+ CHECKBOX "&Uses DDE", ID_USESDDE, 4, 76, 68, 10
+
+ GROUPBOX "DDE", ID_GROUPDDE, 4, 96, 204, 72
+ LTEXT "&DDE Message:", -1, 8, 108, 108, 10
+ EDITTEXT ID_FIRSTDDEEDIT, 8, 118, 108, 12, ES_AUTOHSCROLL
+ LTEXT "(optional)\nDDE Application &Not Running:", -1, 8, 134, 108, 18
+ EDITTEXT ID_FIRSTDDEEDIT+1, 8, 152, 108, 12, ES_AUTOHSCROLL
+ LTEXT "&Application:", -1, 132, 108, 56, 10
+ EDITTEXT ID_FIRSTDDEEDIT+2, 132, 118, 56, 12, ES_AUTOHSCROLL
+ LTEXT "&Topic:", -1, 132, 142, 56, 10
+ EDITTEXT ID_FIRSTDDEEDIT+3, 132, 152, 56, 12, ES_AUTOHSCROLL
+
+ DEFPUSHBUTTON "OK", IDOK, 160, 6, 48, 12
+ PUSHBUTTON "Cancel", IDCANCEL, 160, 20, 48, 12
+
+ PUSHBUTTON "&Browse...", ID_BROWSE, 160, 38, 48, 12
+#ifndef NOHELP
+ PUSHBUTTON "&Help", ID_HELPBUTTON, 160, 52, 48, 12
+#endif
+END
+
+RegEdit ACCELERATORS
+BEGIN
+#ifndef NOHELP
+ VK_F1, ID_HELPINDEX, VIRTKEY
+#endif
+ VK_RETURN, ID_MODIFY, VIRTKEY
+ VK_DELETE, ID_DELETE, VIRTKEY
+END
+
+SDKRegEd ACCELERATORS
+BEGIN
+#ifndef NOHELP
+ VK_F1, ID_HELPINDEX, VIRTKEY
+#endif
+ VK_F2, ID_EDITVAL, VIRTKEY
+ VK_F3, ID_FINDNEXT, VIRTKEY
+ VK_RETURN, ID_MODIFY, VIRTKEY
+ VK_DELETE, ID_DELETE, VIRTKEY
+END
+
+SDKRegEdVal ACCELERATORS
+BEGIN
+#ifndef NOHELP
+ VK_F1, ID_HELPINDEX, VIRTKEY
+#endif
+ VK_F3, ID_FINDNEXT, VIRTKEY
+ VK_RETURN, ID_MODIFY, VIRTKEY
+END
+
+#ifdef REGLOAD
+#include "messages\usa\regload.rcv"
+#else
+#include "messages\usa\regedit.rcv"
+#endif
+
diff --git a/private/mvdm/wow16/regedit/messages/usa/regedit.rcv b/private/mvdm/wow16/regedit/messages/usa/regedit.rcv
new file mode 100644
index 000000000..b355b1da6
--- /dev/null
+++ b/private/mvdm/wow16/regedit/messages/usa/regedit.rcv
@@ -0,0 +1,17 @@
+/********************************************************************/
+/* REGEDIT.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Registration Database Editor"
+#define VER_INTERNALNAME_STR "REGEDIT"
+#define VER_LEGALCOPYRIGHT_YEARS "1991-1995"
+#define VER_ORIGINALFILENAME_STR "REGEDIT.EXE"
+
+
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/regedit/messages/usa/regload.rcv b/private/mvdm/wow16/regedit/messages/usa/regload.rcv
new file mode 100644
index 000000000..0f4aee14c
--- /dev/null
+++ b/private/mvdm/wow16/regedit/messages/usa/regload.rcv
@@ -0,0 +1,17 @@
+/********************************************************************/
+/* REGEDIT.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Registration File Loader"
+#define VER_INTERNALNAME_STR "REGLOAD"
+#define VER_LEGALCOPYRIGHT_YEARS "1991-1995"
+#define VER_ORIGINALFILENAME_STR "REGLOAD.EXE"
+
+
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/regedit/messages/usa/sdkreged.dlg b/private/mvdm/wow16/regedit/messages/usa/sdkreged.dlg
new file mode 100644
index 000000000..e64050973
--- /dev/null
+++ b/private/mvdm/wow16/regedit/messages/usa/sdkreged.dlg
@@ -0,0 +1,104 @@
+AddKey DIALOG 26, 59, 218, 68
+CAPTION "Add Key"
+FONT 8, "Helv"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ LTEXT "Path:", -1, 8, 9, 18, 11, WS_GROUP
+ LTEXT "", ID_STAT1, 38, 9, 128, 11
+ LTEXT "&Key:", -1, 8, 30, 26, 11, WS_GROUP
+ EDITTEXT ID_EDIT1, 38, 27, 128, 14, ES_AUTOHSCROLL
+ LTEXT "&Value:", -1, 8, 48, 26, 11, WS_GROUP
+ EDITTEXT ID_EDIT2, 38, 46, 128, 14, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 177, 4, 38, 17, WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 177, 23, 38, 17, WS_TABSTOP
+#ifndef NOHELP
+ PUSHBUTTON "&Help", ID_HELPBUTTON, 177, 46, 38, 17, WS_TABSTOP
+#endif
+END
+
+CopyKey DIALOG 26, 59, 217, 65
+CAPTION "Copy Key"
+FONT 8, "Helv"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ LTEXT "&To:", -1, 8, 35, 26, 11, WS_GROUP
+ EDITTEXT ID_EDIT2, 38, 35, 128, 14, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 177, 4, 38, 17, WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 177, 23, 38, 17, WS_TABSTOP
+#ifndef NOHELP
+ PUSHBUTTON "&Help", ID_HELPBUTTON, 177, 46, 38, 17, WS_TABSTOP
+#endif
+ LTEXT "&From:", -1, 8, 19, 26, 11, WS_GROUP
+ EDITTEXT ID_EDIT1, 38, 14, 128, 14, ES_AUTOHSCROLL
+END
+
+DeleteKey DIALOG 26, 59, 218, 67
+CAPTION "Delete Key"
+FONT 8, "Helv"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ LTEXT "&Key:", -1, 8, 38, 26, 11, WS_GROUP
+ EDITTEXT ID_EDIT1, 38, 36, 128, 14, ES_AUTOHSCROLL
+ LTEXT "Deleting a Key removes all subkeys and their values.", -1, 8, 9, 156, 22, WS_GROUP
+ DEFPUSHBUTTON "OK", IDOK, 177, 4, 38, 17, WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 177, 23, 38, 17, WS_TABSTOP
+#ifndef NOHELP
+ PUSHBUTTON "&Help", ID_HELPBUTTON, 177, 46, 38, 17, WS_TABSTOP
+#endif
+END
+
+FindKeyDlg DIALOG 26, 59, 209, 67
+CAPTION "Find Key"
+FONT 8, "Helv"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ LTEXT "Fi&nd What:", -1, 8, 20, 37, 11, WS_GROUP
+ EDITTEXT ID_EDIT1, 52, 15, 105, 14, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Find Next", IDOK, 166, 3, 41, 17, WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 166, 23, 41, 17, WS_TABSTOP
+#ifndef NOHELP
+ PUSHBUTTON "&Help", ID_HELPBUTTON, 166, 46, 41, 17, WS_TABSTOP
+#endif
+END
+
+SDKMAINMENU MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Save Changes", ID_SAVE
+ MENUITEM "&Restore To Last Save", ID_RESTORE
+ MENUITEM SEPARATOR
+ MENUITEM "&Merge Registration File...", ID_MERGEFILE
+ MENUITEM "Save Registration &File...", ID_WRITEFILE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_EXIT
+ END
+
+ POPUP "&Edit"
+ BEGIN
+ MENUITEM "&Add Key...", ID_ADD
+ MENUITEM "&Copy Key...", ID_COPY
+ MENUITEM "&Delete Key...", ID_DELETE
+ END
+
+ POPUP "&Search"
+ BEGIN
+ MENUITEM "&Find Key...", ID_FINDKEY
+ MENUITEM "Find &Next", ID_FINDNEXT
+ END
+#ifndef NOHELP
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents", ID_HELPINDEX
+ MENUITEM "&Search for Help On...", ID_HELPSEARCH
+ MENUITEM "&How to Use Help", ID_HELPUSINGHELP
+ MENUITEM SEPARATOR
+ MENUITEM "&About Registration Editor...", ID_ABOUT
+ END
+#else
+ POPUP "&Info"
+ BEGIN
+ MENUITEM "&About Registration Editor...", ID_ABOUT
+ END
+#endif
+END
diff --git a/private/mvdm/wow16/regedit/reg1632.h b/private/mvdm/wow16/regedit/reg1632.h
new file mode 100644
index 000000000..6850bc918
--- /dev/null
+++ b/private/mvdm/wow16/regedit/reg1632.h
@@ -0,0 +1,151 @@
+/*******************************************************************************
+*
+* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
+*
+* TITLE: REG1632.H
+*
+* VERSION: 4.01
+*
+* AUTHOR: Tracy Sharpe
+*
+* DATE: 06 Apr 1994
+*
+* Win32 and MS-DOS compatibility macros for the Registry Editor.
+*
+********************************************************************************
+*
+* CHANGE LOG:
+*
+* DATE REV DESCRIPTION
+* ----------- --- -------------------------------------------------------------
+* 06 Apr 1994 TCS Original implementation.
+*
+*******************************************************************************/
+
+#ifndef _INC_REG1632
+#define _INC_REG1632
+
+#ifndef LPCHAR
+typedef CHAR FAR* LPCHAR;
+#endif
+
+#ifdef WIN32
+#define WSPRINTF(x) wsprintf ##x
+#else
+#define WSPRINTF(x) sprintf ##x
+#endif
+
+#ifdef WIN32
+#define STRCMP(string1, string2) lstrcmp(string1, string2)
+#else
+#define STRCMP(string1, string2) _fstrcmp(string1, string2)
+#endif
+
+#ifdef WIN32
+#define STRCPY(string1, string2) lstrcpy(string1, string2)
+#else
+#define STRCPY(string1, string2) _fstrcpy(string1, string2)
+#endif
+
+#ifdef WIN32
+#define STRLEN(string) lstrlen(string)
+#else
+#define STRLEN(string) _fstrlen(string)
+#endif
+
+#ifdef WIN32
+#define STRCHR(string, character) StrChr(string, character)
+#else
+#ifdef DBCS
+#define STRCHR(string, character) DBCSStrChr(string, character)
+#else
+#define STRCHR(string, character) _fstrchr(string, character)
+#endif
+#endif
+
+#ifdef WIN32
+#define CHARNEXT(string) CharNext(string)
+#else
+#define CHARNEXT(string) (string + 1)
+#endif
+
+#ifdef WIN32
+#define CHARUPPERSTRING(string) CharUpper(string)
+#else
+#define CHARUPPERSTRING(string) _fstrupr(string)
+#endif
+
+#ifdef WIN32
+#define FILE_HANDLE HANDLE
+#else
+#define FILE_HANDLE int
+#endif
+
+#ifdef WIN32
+#define FILE_NUMBYTES DWORD
+#else
+#define FILE_NUMBYTES unsigned
+#endif
+
+#if 1 //def WIN32
+#define OPENREADFILE(pfilename, handle) \
+ ((handle = (FILE_HANDLE) OpenFile(pfilename, &OFStruct, OF_READ)) != \
+ (FILE_HANDLE) HFILE_ERROR)
+#else
+#define OPENREADFILE(pfilename, handle) \
+ (_dos_open(pfilename, _O_RDONLY, &handle) == 0)
+#endif
+
+#ifdef WIN32
+#define OPENWRITEFILE(pfilename, handle) \
+ ((handle = CreateFile(pfilename, GENERIC_WRITE, 0, \
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != \
+ INVALID_HANDLE_VALUE)
+#else
+#define OPENWRITEFILE(pfilename, handle) \
+ (HFILE_ERROR!=(handle=_lcreat(pfilename, 0)))
+#endif
+
+#ifdef WIN32
+#define READFILE(handle, buffer, count, pnumbytes) \
+ ReadFile(handle, buffer, count, pnumbytes, NULL)
+#else
+#define READFILE(handle, buffer, count, pnumbytes) \
+ (count==(*pnumbytes=_hread(handle, buffer, count)))
+#endif
+
+#ifdef WIN32
+#define WRITEFILE(handle, buffer, count, pnumbytes) \
+ WriteFile(handle, buffer, count, pnumbytes, NULL)
+#else
+#define WRITEFILE(handle, buffer, count, pnumbytes) \
+ (count==(*pnumbytes=_hwrite(handle, buffer, count)))
+#endif
+
+#ifdef WIN32
+#define SEEKCURRENTFILE(handle, count) \
+ (SetFilePointer(handle, (LONG) count, NULL, FILE_CURRENT))
+#else
+#define SEEKCURRENTFILE(handle, count) \
+ (_llseek(handle, count, SEEK_CUR))
+#endif
+
+#ifdef WIN32
+#define CLOSEFILE(handle) CloseHandle(handle)
+#else
+#define CLOSEFILE(handle) _lclose(handle)
+#endif
+
+#ifdef WIN32
+#define GETFILESIZE(handle) GetFileSize(handle, NULL)
+#else
+DWORD
+NEAR PASCAL
+GetFileSize(
+ FILE_HANDLE hFile
+ );
+#define GETFILESIZE(handle) GetFileSize(handle)
+#endif
+
+#endif // _INC_REG1632
+
diff --git a/private/mvdm/wow16/regedit/regdef.h b/private/mvdm/wow16/regedit/regdef.h
new file mode 100644
index 000000000..3c29496ba
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regdef.h
@@ -0,0 +1,178 @@
+
+/* Do not include this before Windows.h */
+
+/* ASM
+; DO NOT INCLUDE THIS BEFORE WINDOWS.INC
+*/
+
+#define Dereference(x) x=x;
+
+#ifdef _WIN32
+/*XLATOFF*/
+#pragma warning (disable:4209) // turn off redefinition warning (with vmm.h)
+/*XLATON*/
+#endif // #ifdef _WIN32
+
+#ifndef _WINREG_
+// WINREG.H uses DECLARE_HANDLE(HKEY) giving incompatible types.
+typedef DWORD HKEY;
+#endif
+
+#ifdef _WIN32
+/*XLATOFF*/
+#pragma warning (default:4209) // turn on redefinition warning (with vmm.h)
+/*XLATON*/
+#endif // #ifdef _WIN32
+
+#define MAXKEYNAME 256
+ // Max length of a key name string
+#define MAXVALUENAME_LENGTH MAXKEYNAME
+ // Max length of a value name string
+#define MAXDATA_LENGTH 1024L
+ // Max length of a value data item
+
+
+#ifndef REG_SZ
+#define REG_SZ 0x0001
+#endif
+
+#ifndef REG_BINARY
+#define REG_BINARY 0x0003
+#endif
+
+#ifndef REG_DWORD
+#define REG_DWORD 0x0004
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE ~FALSE
+#endif
+
+/* following equates are also defined in Windows.h. To avoid warnings
+ * we should make these equates conditional
+ */
+
+
+#ifndef ERROR_SUCCESS
+#define ERROR_SUCCESS 0L
+#endif
+
+#ifndef ERROR_FILE_NOT_FOUND
+#define ERROR_FILE_NOT_FOUND 2L
+#endif
+
+#ifndef ERROR_ACCESS_DENIED
+#define ERROR_ACCESS_DENIED 5L
+#endif
+
+#ifndef ERROR_BADDB
+#define ERROR_BADDB 1009L
+#endif
+
+#ifndef ERROR_MORE_DATA
+#define ERROR_MORE_DATA 234L
+#endif
+
+#ifndef ERROR_BADKEY
+#define ERROR_BADKEY 1010L
+#endif
+
+#ifndef ERROR_CANTOPEN
+#define ERROR_CANTOPEN 1011L
+#endif
+
+#ifndef ERROR_CANTREAD
+#define ERROR_CANTREAD 1012L
+#define ERROR_CANTWRITE 1013L
+#endif
+
+#ifndef ERROR_REGISTRY_CORRUPT
+#define ERROR_REGISTRY_CORRUPT 1015L
+#define ERROR_REGISTRY_IO_FAILED 1016L
+#endif
+
+#ifndef ERROR_KEY_DELETED
+#define ERROR_KEY_DELETED 1018L
+#endif
+
+#ifndef ERROR_OUTOFMEMORY
+#define ERROR_OUTOFMEMORY 14L
+#endif
+
+#ifndef ERROR_INVALID_PARAMETER
+#define ERROR_INVALID_PARAMETER 87L
+#endif
+
+#ifndef ERROR_LOCK_FAILED
+#define ERROR_LOCK_FAILED 167L
+#endif
+
+#ifndef ERROR_NO_MORE_ITEMS
+#define ERROR_NO_MORE_ITEMS 259L
+#endif
+
+// INTERNAL
+
+#ifndef ERROR_CANTOPEN16_FILENOTFOUND32
+#define ERROR_CANTOPEN16_FILENOTFOUND32 0xffff0000
+#define ERROR_CANTREAD16_FILENOTFOUND32 0xffff0001
+#endif
+
+#ifndef HKEY_LOCAL_MACHINE // to avoid compilation warnings
+#define HKEY_CLASSES_ROOT 0x80000000
+#define HKEY_CURRENT_USER 0x80000001
+#define HKEY_LOCAL_MACHINE 0x80000002
+#define HKEY_USERS 0x80000003
+#define HKEY_PERFORMANCE_DATA 0x80000004
+#define HKEY_CURRENT_CONFIG 0x80000005
+#define HKEY_DYN_DATA 0x80000006
+#endif // ifndef HKEY_LOCAL_MACHINE
+
+// INTERNAL
+
+#ifndef HKEY_PREDEF_KEYS
+#define HKEY_PREDEF_KEYS 7
+#endif
+
+#define MAXREGFILES HKEY_PREDEF_KEYS
+
+// sub function indices for Registry services in VMM for 16 bit callers
+
+#define RegOpenKey_Idx 0x100
+#define RegCreateKey_Idx 0x101
+#define RegCloseKey_Idx 0x102
+#define RegDeleteKey_Idx 0x103
+#define RegSetValue_Idx 0x104
+#define RegQueryValue_Idx 0x105
+#define RegEnumKey_Idx 0x106
+#define RegDeleteValue_Idx 0x107
+#define RegEnumValue_Idx 0x108
+#define RegQueryValueEx_Idx 0x109
+#define RegSetValueEx_Idx 0x10A
+#define RegFlushKey_Idx 0x10B
+#define RegLoadKey_Idx 0x10C
+#define RegUnLoadKey_Idx 0x10D
+#define RegSaveKey_Idx 0x10E
+#define RegRestore_Idx 0x10F
+#define RegRemapPreDefKey_Idx 0x110
+
+// Data structure passed to SYSDM.CPL DMRegistryError function
+// After UI, the function is to call
+// RegRestore(DWORD iLevel, LPREGQRSTR lpRgRstr)
+//
+
+struct Reg_Query_Restore_s {
+DWORD dwRQR_Err; // Error code
+DWORD hRQR_RootKey; // Root key for file
+DWORD dwRQR_Reference; // Reference data for RegRestore
+char szRQR_SubKey[MAXKEYNAME]; // Subkey (for hives) or NULL string
+char szRQR_FileName[256]; // File name of bad file
+};
+typedef struct Reg_Query_Restore_s REGQRSTR;
+typedef REGQRSTR FAR * LPREGQRSTR;
+
+
+// END INTERNAL
diff --git a/private/mvdm/wow16/regedit/regedit.c b/private/mvdm/wow16/regedit/regedit.c
new file mode 100644
index 000000000..04d8d1921
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regedit.c
@@ -0,0 +1,523 @@
+#define WIN31
+#include <windows.h>
+#include "RegEdit.h"
+
+HWND hWndNames, hWndIds;
+WORD fMode;
+
+extern char cUsesDDE[];
+extern HANDLE *pLocalVals;
+
+
+WORD NEAR PASCAL StoreValue(HWND hWndEdit, HANDLE *pValue)
+{
+ HANDLE hTemp = NULL;
+
+ if(!SendMessage(hWndEdit, EM_GETMODIFY, 0, 0L))
+ return(0);
+
+ SendMessage(hWndEdit, EM_SETMODIFY, 0, 0L);
+
+ if(SendMessage(hWndEdit, WM_GETTEXTLENGTH, 0, 0L))
+ if(!(hTemp=GetEditString(hWndEdit)))
+ return(IDS_OUTOFMEMORY);
+
+ if(*pValue)
+ LocalFree(*pValue);
+ *pValue = hTemp;
+
+ return(NULL);
+}
+
+
+VOID NEAR PASCAL SetValue(HWND hDlg, int i, HWND hWndEdit, HANDLE hValue,
+ BOOL bEnable)
+{
+ if(bEnable) {
+ if(i >= ID_FIRSTDDEEDIT)
+ EnableWindow(GetWindow(hWndEdit, GW_HWNDPREV), TRUE);
+ EnableWindow(hWndEdit, TRUE);
+ if(hValue) {
+ SendMessage(hWndEdit, WM_SETTEXT, 0, (LONG)(LPSTR)LocalLock(hValue));
+ LocalUnlock(hValue);
+ } else
+ goto ClearEdit;
+ } else {
+ if(GetFocus() == hWndEdit)
+ SendMessage(hDlg, WM_NEXTDLGCTL, GetDlgItem(hDlg, ID_CLASSID), 1L);
+ EnableWindow(GetWindow(hWndEdit, GW_HWNDPREV), FALSE);
+ EnableWindow(hWndEdit, FALSE);
+ClearEdit:
+ SendMessage(hWndEdit, WM_SETTEXT, 0, (LONG)(LPSTR)"");
+ }
+}
+
+
+int FAR PASCAL EditDlg(HWND hDlg, WORD message, WORD wParam, DWORD lParam)
+{
+ static HANDLE hCustExes = NULL;
+
+ switch(message) {
+ case WM_ACTIVATE:
+ if(wParam)
+ hWndHelp = hDlg;
+ return(FALSE);
+
+ case WM_DESTROY:
+ GetLocalCopies(GetDlgItem(hDlg, ID_CLASSNAME), NULL);
+ break;
+
+ case WM_COMMAND:
+ switch(wParam) {
+ case ID_SAVEACTION:
+ wParam = IsDlgButtonChecked(hDlg, ID_OPENRADIO)
+ ? ID_OPENRADIO : ID_PRINTRADIO;
+/* We fall through here */
+ case ID_OPENRADIO:
+ case ID_PRINTRADIO:
+ {
+ WORD wOld, wNew, wTemp, wErrMsg = NULL;
+ BOOL bCheck;
+ HWND hWndEdit;
+ int i;
+
+ wOld = (ID_LASTEDIT-ID_FIRSTACTIONEDIT+1) *
+ (IsDlgButtonChecked(hDlg, ID_OPENRADIO) ? 0 : 1);
+ wNew = wParam==ID_OPENRADIO ? 0 : 1;
+ bCheck = cUsesDDE[wNew];
+ wNew *= ID_LASTEDIT-ID_FIRSTACTIONEDIT+1;
+
+ for(i=ID_FIRSTACTIONEDIT; i<=ID_LASTEDIT; ++i, ++wOld, ++wNew) {
+ if(wTemp=StoreValue(hWndEdit=GetDlgItem(hDlg, i), pLocalVals+wOld))
+ wErrMsg = wTemp;
+
+ SetValue(hDlg, i, hWndEdit, pLocalVals[wNew], i<ID_FIRSTDDEEDIT ||
+ (bCheck && (i!=(ID_FIRSTDDEEDIT+1) || SendDlgItemMessage(hDlg,
+ ID_FIRSTDDEEDIT, WM_GETTEXTLENGTH, 0, 0L))));
+ }
+
+ CheckDlgButton(hDlg, ID_USESDDE, bCheck);
+ EnableWindow(GetDlgItem(hDlg, ID_GROUPDDE), bCheck);
+ CheckRadioButton(hDlg, ID_OPENRADIO, ID_PRINTRADIO, wParam);
+
+ if(wErrMsg)
+ MyMessageBox(hDlg, wErrMsg, MB_OK, 0);
+ break;
+ }
+
+ case ID_USESDDE:
+ {
+ WORD wOld;
+
+ wOld = IsDlgButtonChecked(hDlg, ID_OPENRADIO) ? 0 : 1;
+ cUsesDDE[wOld] = (char)(!IsDlgButtonChecked(hDlg, ID_USESDDE));
+ SendMessage(hDlg, WM_COMMAND, ID_SAVEACTION, 0L);
+ break;
+ }
+
+ case ID_FIRSTDDEEDIT:
+ if(HIWORD(lParam) == EN_CHANGE) {
+ BOOL bCheck, bEnabled;
+ HWND hWndEdit;
+ WORD wNew;
+
+ hWndEdit = GetDlgItem(hDlg, ID_FIRSTDDEEDIT+1);
+ bEnabled = IsWindowEnabled(hWndEdit);
+ bCheck = (BOOL)SendMessage(LOWORD(lParam), WM_GETTEXTLENGTH, 0, 0L);
+ if((bCheck && bEnabled) || (!bCheck && !bEnabled))
+ break;
+
+ wNew = ID_FIRSTDDEEDIT+1-ID_FIRSTACTIONEDIT;
+ if(!IsDlgButtonChecked(hDlg, ID_OPENRADIO))
+ wNew += ID_LASTEDIT-ID_FIRSTACTIONEDIT+1;
+
+ if(StoreValue(hWndEdit, pLocalVals+wNew))
+ break;
+ SetValue(hDlg, ID_FIRSTDDEEDIT+1, hWndEdit, pLocalVals[wNew],
+ bCheck);
+ }
+ break;
+
+ case IDOK:
+ {
+ HANDLE hId;
+ HWND hWndName;
+ WORD wErrMsg = IDS_INVALIDNAME;
+ WORD wErrCtl = ID_CLASSNAME;
+
+ if(!SendMessage(hWndName=GetDlgItem(hDlg, ID_CLASSNAME),
+ WM_GETTEXTLENGTH, 0, 0L))
+ goto Error1_1;
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ wErrCtl = NULL;
+ /* Update our memory handles for the current action */
+ SendMessage(hDlg, WM_COMMAND, ID_SAVEACTION, 0L);
+
+ /* Get the current class id */
+ if(!(hId=GetEditString(GetDlgItem(hDlg, ID_CLASSID))))
+ goto Error1_1;
+
+ if((fMode&(FLAG_NEW|FLAG_COPY)) && (wErrMsg=CreateId(hId))) {
+ PSTR pId;
+
+ MyMessageBox(hDlg, wErrMsg, MB_OK, lstrlen(pId=LocalLock(hId)),
+ (LPSTR)pId);
+ SetFocus(GetDlgItem(hDlg, ID_CLASSID));
+
+ LocalUnlock(hId);
+ LocalFree(hId);
+ break;
+ }
+
+ /* Merge the data with the given class */
+ if(wErrMsg=MergeData(hWndName, hId))
+ goto Error1_2;
+ EndDialog(hDlg, hId);
+ break;
+
+Error1_2:
+ LocalFree(hId);
+Error1_1:
+ MyMessageBox(hDlg, wErrMsg, MB_OK, 0);
+ if(wErrCtl)
+ SetFocus(GetDlgItem(hDlg, wErrCtl));
+ break;
+ }
+
+ case IDCANCEL:
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case ID_BROWSE:
+ {
+ HANDLE hPath, hLocPath;
+ LPSTR lpPath;
+ HWND hWndEdit, hWndApp;
+
+ wHelpId = IDW_OPENEXE;
+ if(!DoFileOpenDlg(hDlg, IDS_BROWSETITLE, IDS_EXES, IDS_CUSTEXES,
+ &hCustExes, &hPath, TRUE))
+ break;
+ lpPath = GlobalLock(hPath);
+
+ hWndApp = GetDlgItem(hDlg, ID_FIRSTDDEEDIT+2);
+ if(IsDlgButtonChecked(hDlg, ID_USESDDE) &&
+ !SendMessage(hWndApp, WM_GETTEXTLENGTH, 0, 0L) &&
+ (hLocPath=StringToLocalHandle(lpPath, LMEM_MOVEABLE))) {
+ SendMessage(hWndApp, WM_SETTEXT, 0,
+ (DWORD)((LPSTR)GetAppName(hLocPath)));
+ SendMessage(hWndApp, EM_SETMODIFY, 1, 0L);
+ LocalFree(hLocPath);
+ }
+
+ hWndEdit = GetDlgItem(hDlg, ID_COMMAND);
+ SendMessage(hWndEdit, WM_SETTEXT, 0, (DWORD)lpPath);
+ SendMessage(hWndEdit, EM_SETMODIFY, 1, 0L);
+
+ GlobalUnlock(hPath);
+ GlobalFree(hPath);
+ break;
+ }
+
+ case ID_HELP:
+ if(GetParent(LOWORD(lParam)) != hDlg)
+ break;
+ case ID_HELPBUTTON:
+ MyHelp(hDlg, HELP_CONTEXT, IDW_MODIFY+fMode);
+ break;
+
+ default:
+ break;
+ }
+ return(FALSE);
+ break;
+
+ case WM_INITDIALOG:
+ {
+ HANDLE hId, hTitle;
+ HWND hWndId, hWndName;
+ WORD wErrMsg;
+
+ hId = GetListboxString(hWndIds,
+ (WORD)SendMessage(hWndNames, LB_GETCURSEL, 0, 0L));
+
+ hWndName = GetDlgItem(hDlg, ID_CLASSNAME);
+ if(fMode&FLAG_NEW) {
+ if(wErrMsg=GetLocalCopies(hWndName, NULL))
+ goto Error2_1;
+ cUsesDDE[0] = cUsesDDE[1] = 1;
+ } else {
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!hId || (wErrMsg=GetLocalCopies(hWndName, hId)))
+ goto Error2_1;
+ }
+
+ hWndId = GetDlgItem(hDlg, ID_CLASSID);
+ SendMessage(hWndId, EM_LIMITTEXT, MAX_KEY_LENGTH-1, 0L);
+ if(fMode&(FLAG_NEW|FLAG_COPY)) {
+ DestroyWindow(GetDlgItem(hDlg, ID_STATCLASSID));
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hTitle=MyLoadString(fMode&FLAG_NEW ? IDS_ADD : IDS_COPY, NULL,
+ LMEM_MOVEABLE)))
+ goto Error2_1;
+ SendMessage(hDlg, WM_SETTEXT, 0, (DWORD)((LPSTR)LocalLock(hTitle)));
+ LocalUnlock(hTitle);
+ LocalFree(hTitle);
+
+ SetFocus(hWndId);
+ } else {
+ DestroyWindow(hWndId);
+ hWndId = GetDlgItem(hDlg, ID_STATCLASSID);
+ SetWindowWord(hWndId, GWW_ID, ID_CLASSID);
+
+ SendMessage(hWndId, WM_SETTEXT, 0, (DWORD)((LPSTR)LocalLock(hId)));
+ LocalUnlock(hId);
+
+ SetFocus(GetDlgItem(hDlg, ID_CLASSNAME));
+ }
+
+ CheckRadioButton(hDlg, ID_OPENRADIO, ID_PRINTRADIO, ID_OPENRADIO);
+ SendMessage(hDlg, WM_COMMAND, ID_OPENRADIO, 0L);
+
+ if(hId)
+ LocalFree(hId);
+ return(FALSE);
+
+Error2_1:
+ MyMessageBox(hDlg, wErrMsg, MB_OK, 0);
+ PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);
+ if(hId)
+ LocalFree(hId);
+ break;
+ }
+
+ default:
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+int FAR PASCAL MainWndDlg(HWND hDlg, WORD message, WORD wParam, DWORD lParam)
+{
+ static int nTop;
+
+ switch(message) {
+ case WM_COMMAND:
+ switch(wParam) {
+ case ID_NAMELIST:
+ if(HIWORD(lParam) == LBN_DBLCLK)
+ SendMessage(hWndMain, WM_COMMAND, ID_MODIFY, 0L);
+ break;
+
+ default:
+ break;
+ }
+ return(FALSE);
+ break;
+
+ case WM_SIZE:
+ {
+ RECT rcList, rcWnd;
+ int hgtWnd, hgt;
+
+ hgtWnd = HIWORD(lParam) + 1;
+ hgt = hgtWnd - nTop;
+ SetWindowPos(hWndNames, NULL, -1, nTop, LOWORD(lParam)+2, hgt,
+ SWP_NOZORDER);
+ GetWindowRect(hWndNames, &rcList);
+ ScreenToClient(hDlg, (POINT *)(&rcList) + 1);
+ if(rcList.bottom != hgtWnd) {
+ GetWindowRect(hDlg, &rcWnd);
+ SetWindowPos(hDlg, NULL, 0, 0, rcWnd.right-rcWnd.left,
+ rcWnd.bottom-rcWnd.top-hgtWnd+rcList.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ RECT rcTemp;
+
+ GetWindowRect(GetDlgItem(hDlg, ID_NAMELIST), &rcTemp);
+ ScreenToClient(hDlg, (POINT *)&rcTemp);
+ nTop = rcTemp.top;
+ break;
+ }
+
+ default:
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+long FAR PASCAL MainWnd(HWND hWnd, WORD iMessage, WORD wParam, LONG lParam)
+{
+ HCURSOR oldCursor;
+
+ switch(iMessage) {
+ case WM_ACTIVATE:
+ if(wParam)
+ break;
+ goto DoDefault;
+
+ case WM_CREATE:
+ {
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+
+ if(!(lpMainWndDlg=MakeProcInstance(MainWndDlg, hInstance)))
+ goto Error1_1;
+ if(!(hWndDlg=CreateDialog(hInstance, MAKEINTRESOURCE(MAINWND), hWnd,
+ lpMainWndDlg)))
+ goto Error1_1;
+
+ hWndNames = GetDlgItem(hWndDlg, ID_NAMELIST);
+ hWndIds = GetDlgItem(hWndDlg, ID_IDLIST);
+
+ if(wErrMsg=ResetClassList(hWndIds, hWndNames))
+ goto Error1_1;
+
+ ShowWindow(hWndDlg, SW_SHOW);
+ goto DoDefault;
+
+Error1_1:
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ DestroyWindow(hWnd);
+ break;
+ }
+
+ /* Return 1 to say it's OK to close
+ */
+ case WM_CLOSE:
+ case WM_QUERYENDSESSION:
+ return(1L);
+
+ case WM_COMMAND:
+ oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ switch(wParam) {
+ case ID_FINISHMERGE:
+ {
+ WORD wErrMsg;
+
+ if(wErrMsg=ResetClassList(hWndIds, hWndNames))
+ MyMessageBox(GetLastActivePopup(hWnd), wErrMsg, MB_OK, 0);
+ break;
+ }
+
+ case ID_ADD:
+ fMode = FLAG_NEW;
+ goto DoDlg;
+ case ID_COPY:
+ fMode = FLAG_COPY;
+ goto DoDlg;
+ case ID_MODIFY:
+ fMode = 0;
+DoDlg:
+ {
+ HANDLE hId, hName;
+ PSTR pId, pName;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+ int nNewId;
+
+ if(!(hId=DoDialogBox(MAKEINTRESOURCE(EDITDLG), hWnd, EditDlg)))
+ break;
+ if(hId == 0xffff)
+ goto Error2_1;
+
+ if(wErrMsg=MyGetClassName(hId, &hName))
+ goto Error2_2;
+
+ if(wParam == ID_MODIFY) {
+ int nClassId;
+
+ nClassId = (WORD)SendMessage(hWndNames, LB_GETCURSEL, 0, 0L);
+
+ SendMessage(hWndNames, WM_SETREDRAW, 0, 0L);
+ SendMessage(hWndNames, LB_DELETESTRING, nClassId, 0L);
+ SendMessage(hWndIds, LB_DELETESTRING, nClassId, 0L);
+ SendMessage(hWndNames, WM_SETREDRAW, 1, 0L);
+ }
+
+ pName = LocalLock(hName);
+ pId = LocalLock(hId);
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if((nNewId=(int)SendMessage(hWndNames, LB_ADDSTRING, 0,
+ (DWORD)((LPSTR)pName)))!=LB_ERR
+ && SendMessage(hWndIds, LB_INSERTSTRING, nNewId,
+ (DWORD)((LPSTR)pId))!=LB_ERR)
+ wErrMsg = NULL;
+ SendMessage(hWndNames, LB_SETCURSEL, nNewId, 0L);
+
+ LocalUnlock(hId);
+ LocalUnlock(hName);
+ LocalFree(hName);
+Error2_2:
+ LocalFree(hId);
+Error2_1:
+ if(wErrMsg)
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ break;
+ }
+
+ case ID_DELETE:
+ {
+ HANDLE hId, hName;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+ PSTR pName;
+ int nClassId;
+
+ if((nClassId=(int)SendMessage(hWndNames, LB_GETCURSEL, 0, 0L))
+ == LB_ERR)
+ break;
+ if(!(hId=GetListboxString(hWndIds, nClassId)))
+ goto Error4_1;
+ if(!(hName=GetListboxString(hWndNames, nClassId)))
+ goto Error4_2;
+ pName = LocalLock(hName);
+
+ wErrMsg = NULL;
+ if(MyMessageBox(hWnd, IDS_SUREDELETE, MB_ICONEXCLAMATION | MB_YESNO,
+ lstrlen(pName), (LPSTR)pName) != IDYES)
+ goto Error4_3;
+ if(wErrMsg=DeleteClassId(hId))
+ goto Error4_3;
+
+ SendMessage(hWndIds, LB_DELETESTRING, nClassId, 0L);
+ SendMessage(hWndNames, LB_DELETESTRING, nClassId, 0L);
+ if(SendMessage(hWndNames, LB_SETCURSEL, nClassId, 0L) == LB_ERR)
+ SendMessage(hWndNames, LB_SETCURSEL, --nClassId, 0L);
+
+Error4_3:
+ LocalUnlock(hName);
+ LocalFree(hName);
+Error4_2:
+ LocalFree(hId);
+Error4_1:
+ if(wErrMsg)
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ SetCursor(oldCursor);
+ break;
+
+ default:
+DoDefault:
+ return(DefWindowProc(hWnd, iMessage, wParam, lParam));
+ break;
+ }
+ return 0L;
+}
+
diff --git a/private/mvdm/wow16/regedit/regedit.def b/private/mvdm/wow16/regedit/regedit.def
new file mode 100644
index 000000000..a23e0f280
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regedit.def
@@ -0,0 +1,21 @@
+NAME REGEDIT WINDOWAPI
+
+DESCRIPTION 'Registration Info Editor'
+
+STUB 'WINSTUB.EXE'
+EXETYPE WINDOWS
+
+CODE MOVEABLE PRELOAD
+DATA MOVEABLE MULTIPLE PRELOAD
+
+HEAPSIZE 1024
+STACKSIZE 4096
+
+EXPORTS
+ EditDlg @2
+ MainWndDlg @3
+ MessageFilter @4
+ WndProc @5
+ MyOpenDlgProc @6
+ SDKMainWndDlg @7
+ GetKeyProc @8
diff --git a/private/mvdm/wow16/regedit/regedit.h b/private/mvdm/wow16/regedit/regedit.h
new file mode 100644
index 000000000..8b1038025
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regedit.h
@@ -0,0 +1,75 @@
+#include "common.h"
+
+
+/*********************************************************/
+/******************* Constants ***************************/
+/*********************************************************/
+
+#define EDITDLG 200
+#define MAINWND 201
+
+#define ID_NAMELIST (ID_FIRSTREGEDIT)
+
+#define ID_CLASSID (ID_FIRSTREGEDIT+0x10)
+#define ID_STATCLASSID (ID_CLASSID+1)
+#define ID_USESDDE (ID_CLASSID+2)
+#define ID_BROWSE (ID_CLASSID+3)
+#define ID_SAVEACTION (ID_CLASSID+4)
+#define ID_GROUPDDE (ID_CLASSID+5)
+
+#define ID_FIRSTACTIONRADIO (ID_FIRSTREGEDIT+0x20)
+#define ID_OPENRADIO (ID_FIRSTACTIONRADIO)
+#define ID_PRINTRADIO (ID_FIRSTACTIONRADIO+1)
+#define ID_LASTACTIONRADIO (ID_PRINTRADIO)
+
+#define ID_FIRSTEDIT (ID_FIRSTREGEDIT+0x30)
+#define ID_CLASSNAME (ID_FIRSTEDIT)
+#define ID_FIRSTACTIONEDIT (ID_FIRSTEDIT+1)
+#define ID_COMMAND (ID_FIRSTACTIONEDIT)
+#define ID_FIRSTDDEEDIT (ID_FIRSTEDIT+2)
+#define ID_LASTEDIT (ID_FIRSTEDIT+5)
+
+#define CI_SUCCESS 0
+#define CI_EXISTS 1
+#define CI_CANTCREATE 2
+
+#define IDS_BROWSETITLE (IDS_FIRSTREGEDIT)
+#define IDS_EXES (IDS_BROWSETITLE+1)
+#define IDS_CUSTEXES (IDS_BROWSETITLE+2)
+
+#define IDS_EXISTS (IDS_FIRSTREGEDIT+0x10)
+#define IDS_INVALIDID (IDS_EXISTS+1)
+#define IDS_INVALIDNAME (IDS_EXISTS+2)
+
+#define IDS_ADD (IDS_FIRSTREGEDIT+0x20)
+#define IDS_COPY (IDS_ADD+1)
+
+#define IDS_SUREDELETE (IDS_FIRSTREGEDIT+0x30)
+
+#define CC_INVALIDNAME -1
+#define CC_OUTOFMEMORY -2
+#define CC_ALREADYEXISTS -3
+#define CC_CANTCREATE -4
+
+#define FLAG_NEW (1)
+#define FLAG_COPY (2)
+
+
+/*********************************************************/
+/******************* Functions ***************************/
+/*********************************************************/
+
+/***** regedit.c *****/
+extern long FAR PASCAL MainWnd(HWND, WORD, WORD, LONG);
+
+/***** dbase.c *****/
+extern WORD NEAR PASCAL CreateId(HANDLE hId);
+extern WORD NEAR PASCAL MyGetClassName(HANDLE hId, HANDLE *hName);
+extern WORD NEAR PASCAL DeleteClassId(HANDLE hId);
+extern WORD NEAR PASCAL MergeData(HWND hWndName, HANDLE hId);
+extern WORD NEAR PASCAL ResetClassList(HWND hWndIdList, HWND hWndNameList);
+extern WORD NEAR PASCAL GetLocalCopies(HWND hWndName, HANDLE hId);
+
+/***** utils1.c *****/
+extern PSTR NEAR PASCAL GetAppName(HANDLE hCommand);
+extern HANDLE NEAR cdecl ConstructPath(PSTR pHead, ...);
diff --git a/private/mvdm/wow16/regedit/regedit.ico b/private/mvdm/wow16/regedit/regedit.ico
new file mode 100644
index 000000000..b06d8635d
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regedit.ico
Binary files differ
diff --git a/private/mvdm/wow16/regedit/regload.def b/private/mvdm/wow16/regedit/regload.def
new file mode 100644
index 000000000..c76ffabe5
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regload.def
@@ -0,0 +1,14 @@
+NAME REGLOAD WINDOWAPI
+
+DESCRIPTION 'File Associations Loader'
+
+STUB 'WINSTUB.EXE'
+EXETYPE WINDOWS
+
+CODE MOVEABLE PRELOAD
+DATA MOVEABLE MULTIPLE PRELOAD
+
+HEAPSIZE 1024
+STACKSIZE 4096
+
+EXPORTS
diff --git a/private/mvdm/wow16/regedit/regmain.c b/private/mvdm/wow16/regedit/regmain.c
new file mode 100644
index 000000000..6f8af97c8
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regmain.c
@@ -0,0 +1,518 @@
+#define WIN31
+#include <windows.h>
+#include "RegEdit.h"
+#include "SDKRegEd.h"
+
+
+/*********************************************************/
+/******************* Globals *****************************/
+/*********************************************************/
+
+char szAppName[] = "Registration Editor" ;
+char szSDKRegEd[] = "SDKRegEd";
+char *pszLongName;
+char *pszOutOfMemory;
+
+extern char szNull[];
+
+HANDLE hInstance;
+HWND hWndMain, hWndDlg = NULL, hWndHelp;
+LPSTR lpCmdLine;
+WORD wCmdFlags, wHelpMenuItem, wHelpId, wHelpMain;
+LONG (FAR PASCAL *lpfnEditor)(HWND, WORD, WORD, LONG);
+FARPROC lpOldHook;
+FARPROC lpMainWndDlg = NULL;
+WORD wHelpIndex;
+HANDLE hAcc;
+BOOL fOpenError = FALSE;
+
+
+/*********************************************************/
+/******************* Functions ***************************/
+/*********************************************************/
+
+unsigned long NEAR PASCAL RetSetValue(HKEY hKey, PSTR pSubKey, PSTR pVal)
+{
+ return(RegSetValue(hKey, pSubKey, REG_SZ, pVal, 0L));
+}
+
+#ifndef REGLOAD
+unsigned long NEAR PASCAL WriteThroughSetValue(HKEY hKey, PSTR pSubKey,
+ PSTR pVal)
+{
+ long lRet;
+
+ if (!(lRet=RegSetValue(hKey, pSubKey, REG_SZ, pVal, 0L)))
+ lRet = SDKSetValue(hKey, pSubKey, pVal);
+ return(lRet);
+}
+#endif
+
+unsigned long (NEAR PASCAL *lpfnSetValue)(HKEY, PSTR, PSTR) = RetSetValue;
+
+
+unsigned long NEAR PASCAL MySetValue(HKEY hKey, PSTR pSubKey, PSTR pVal)
+{
+ return((*lpfnSetValue)(hKey, pSubKey, pVal));
+}
+
+
+VOID NEAR PASCAL GetCommandFlags(void)
+{
+ wCmdFlags = 0;
+
+ while(1) {
+/* skip spaces */
+ while(*lpCmdLine == ' ')
+ ++lpCmdLine;
+/* check if this is a command line switch */
+ if(*lpCmdLine!='/' && *lpCmdLine!='-')
+ break;
+ ++lpCmdLine;
+
+/* set known flags */
+ while(*lpCmdLine && *lpCmdLine!=' ') {
+ switch(*lpCmdLine) {
+ case('s'): /* for silent */
+ case('S'): /* for silent */
+ wCmdFlags |= FLAG_SILENT;
+ break;
+
+ case('v'): /* use tree editor */
+ case('V'): /* use tree editor */
+ wCmdFlags |= FLAG_VERBOSE;
+ break;
+
+ case('u'): /* update, don't overwrite existing path entries */
+ case('U'): /* in shell\open\command or shell\open\print */
+ wCmdFlags |= FLAG_LEAVECOMMAND;
+ break;
+ }
+
+ lpCmdLine = AnsiNext(lpCmdLine);
+ }
+ }
+}
+
+
+#ifndef REGLOAD
+long FAR PASCAL WndProc(HWND hWnd, WORD wMessage, WORD wParam, LONG lParam)
+{
+ static HANDLE hCustRegs = NULL;
+
+ HCURSOR oldCursor;
+
+ switch(wMessage) {
+ case WM_ACTIVATE:
+ if(wParam) {
+ hWndHelp = hWnd;
+ SetFocus(hWndDlg);
+ }
+ break;
+
+ case WM_CREATE:
+ {
+ RECT rcWnd, rcClt;
+
+ DragAcceptFiles(hWnd, TRUE);
+
+ lpfnEditor(hWnd, wMessage, wParam, lParam);
+
+ if((rcWnd.right=MyGetProfileInt(IDS_SHORTNAME, IDS_WIDTH, 0))<=0 ||
+ (rcWnd.bottom=MyGetProfileInt(IDS_SHORTNAME, IDS_HEIGHT, 0))<=0) {
+ GetWindowRect(hWndDlg, &rcWnd);
+ rcWnd.right -= rcWnd.left;
+ rcWnd.bottom -= rcWnd.top;
+ }
+ GetClientRect(hWnd, &rcClt);
+ rcClt.right -= rcWnd.right;
+ rcClt.bottom -= rcWnd.bottom;
+ GetWindowRect(hWnd, &rcWnd);
+
+ SetWindowPos(hWnd, NULL, 0, 0, rcWnd.right-rcWnd.left-rcClt.right,
+ rcWnd.bottom-rcWnd.top-rcClt.bottom, SWP_NOMOVE | SWP_NOZORDER);
+
+ return(DefWindowProc(hWnd, wMessage, wParam, lParam));
+ }
+
+ case WM_CLOSE:
+ case WM_QUERYENDSESSION:
+ {
+ HKEY hKeyRoot;
+ WORD wErrMsg;
+ int nReturn;
+
+ if(!fOpenError) {
+ if(!lpfnEditor(hWnd, wMessage, wParam, lParam))
+ return(0L);
+
+ if(RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKeyRoot) == ERROR_SUCCESS) {
+ if(wErrMsg=GetErrMsg((WORD)RegCloseKey(hKeyRoot))) {
+ PSTR pError;
+
+ if(pError=(PSTR)MyLoadString(wErrMsg, NULL, LMEM_FIXED)) {
+ nReturn = MyMessageBox(hWnd, IDS_ENDERROR,
+ MB_YESNO|MB_ICONHAND|MB_SYSTEMMODAL, lstrlen(pError),
+ (LPSTR)pError);
+ LocalFree((HANDLE)pError);
+ } else
+ /* Notice the flags are ignored for OOM
+ */
+ nReturn = MyMessageBox(hWnd, IDS_OUTOFMEMORY,
+ MB_OK|MB_ICONHAND|MB_SYSTEMMODAL, 0);
+
+ if(nReturn != IDYES)
+ return(0L);
+ }
+ }
+ }
+
+ return(DefWindowProc(hWnd, wMessage, wParam, lParam));
+ }
+
+ case WM_DESTROY:
+ if(hWndDlg)
+ DestroyWindow(hWndDlg);
+ if(lpMainWndDlg)
+ FreeProcInstance(lpMainWndDlg);
+
+#ifndef NOHELP
+ WinHelp(hWnd, NULL, HELP_QUIT, 0L);
+#endif
+
+ DragAcceptFiles(hWnd, FALSE);
+ PostQuitMessage(0);
+ break;
+
+ case WM_SIZE:
+ {
+ RECT rcDlg, rcWnd;
+ int hgt;
+
+ if(wParam == SIZEICONIC)
+ break;
+
+ if(!hWndDlg) {
+ /* This should only happen during the create message
+ */
+ PostMessage(hWnd, wMessage, wParam, lParam);
+ break;
+ }
+
+ if(wParam == SIZENORMAL) {
+ WriteProfileInt(IDS_SHORTNAME, IDS_WIDTH, LOWORD(lParam));
+ WriteProfileInt(IDS_SHORTNAME, IDS_HEIGHT, HIWORD(lParam));
+ }
+
+ hgt = HIWORD(lParam);
+ SetWindowPos(hWndDlg, NULL, 0, 0, LOWORD(lParam), hgt, SWP_NOZORDER);
+ GetWindowRect(hWndDlg, &rcDlg);
+ ScreenToClient(hWnd, (POINT *)(&rcDlg) + 1);
+ if((WORD)rcDlg.bottom != HIWORD(lParam)) {
+ GetWindowRect(hWnd, &rcWnd);
+ SetWindowPos(hWnd, NULL, 0, 0, rcWnd.right-rcWnd.left,
+ rcWnd.bottom-rcWnd.top-HIWORD(lParam)+rcDlg.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+ break;
+ }
+
+ case WM_DROPFILES:
+ {
+ int result, i, nFileName;
+ HANDLE hFileName;
+ WORD wFlags;
+
+ wFlags = (GetKeyState(VK_CONTROL)&0x8000) ? FLAG_SILENT : 0;
+
+ lpfnEditor(hWnd, wMessage, wParam, lParam);
+
+ for(result=DragQueryFile(wParam, -1, NULL, 0), i=0; i<result; ++i) {
+ if(!(hFileName=GlobalAlloc(GMEM_MOVEABLE,
+ (DWORD)(nFileName=DragQueryFile(wParam, i, NULL, 0)+1))))
+ continue;
+ DragQueryFile(wParam, i, GlobalLock(hFileName), nFileName);
+ GlobalUnlock(hFileName);
+ SendMessage(hWnd, WM_COMMAND, ID_FINISHMERGE,
+ MAKELONG(hFileName,wFlags));
+ }
+
+ DragFinish(wParam);
+
+ return(TRUE);
+ }
+
+ case WM_COMMAND:
+ oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+ switch(wParam) {
+ case ID_HELP:
+ if(HIWORD(lParam)==MSGF_MENU && IsWindowEnabled(hWnd)
+ && wHelpMenuItem) {
+ WORD m = wHelpMenuItem;
+
+/* Get outta menu mode if help for a menu item */
+ SendMessage(hWnd, WM_CANCELMODE, 0, 0L);
+
+ MyHelp(hWnd, HELP_CONTEXT, m);
+ }
+ break;
+
+ case ID_FINISHMERGE:
+ {
+ unsigned long (NEAR PASCAL *lpfnSave)();
+
+ /* If there was a file selected then merge it; otherwise,
+ * just let lpfnEditor do its cleanup (at the end of the switch)
+ */
+ if (LOWORD(lParam)) {
+ lpfnSave = lpfnSetValue;
+ if (HIWORD(lParam)&FLAG_WRITETHROUGH && lpfnSetValue==SDKSetValue)
+ lpfnSetValue = WriteThroughSetValue;
+
+ lpfnEditor(hWnd, WM_COMMAND, ID_MERGEFILE, 0L);
+
+ ProcessFiles(GetLastActivePopup(hWnd), LOWORD(lParam),
+ HIWORD(lParam));
+ lpfnSetValue = lpfnSave;
+ }
+ break;
+ }
+
+ case ID_MERGEFILE:
+ {
+ HANDLE hPath;
+
+ lpfnEditor(hWnd, wMessage, wParam, lParam);
+
+ wHelpId = IDW_OPENREG;
+ if(!DoFileOpenDlg(hWnd, IDS_MERGETITLE, IDS_REGS, IDS_CUSTREGS,
+ &hCustRegs, &hPath, TRUE))
+ hPath = NULL;
+ SendMessage(hWnd, WM_COMMAND, ID_FINISHMERGE, MAKELONG(hPath, 0));
+
+ return(TRUE);
+ }
+
+ case ID_WRITEFILE:
+ {
+ HANDLE hPath;
+
+ wHelpId = IDW_SAVEREG;
+ if(DoFileOpenDlg(hWnd, IDS_WRITETITLE, IDS_REGS, IDS_CUSTREGS,
+ &hCustRegs, &hPath, FALSE))
+ lParam = (LONG)hPath;
+ else
+ lParam = NULL;
+ break;
+ }
+
+ case ID_EXIT:
+ PostMessage(hWnd, WM_CLOSE, 0, 0L);
+ break;
+
+ case ID_HELPINDEX:
+ MyHelp(hWnd, HELP_CONTEXT, wHelpIndex);
+ break;
+
+ case ID_HELPSEARCH:
+ MyHelp(hWnd, HELP_PARTIALKEY, (DWORD)(LPSTR)"");
+ break;
+
+ case ID_HELPUSINGHELP:
+ MyHelp(hWnd, HELP_HELPONHELP, 0);
+ break;
+
+ case ID_ABOUT:
+ {
+ HANDLE hShortName, hDesc;
+
+ if(!(hShortName=MyLoadString(IDS_MEDIUMNAME, NULL, LMEM_MOVEABLE)))
+ goto Error3_1;
+ if(!(hDesc=MyLoadString(IDS_DESCRIPTION, NULL, LMEM_MOVEABLE)))
+ goto Error3_2;
+
+ ShellAbout(hWnd, LocalLock(hShortName), LocalLock(hDesc),
+ LoadIcon(hInstance, MAKEINTRESOURCE(MAINICON)));
+
+ LocalUnlock(hDesc);
+ LocalUnlock(hShortName);
+ LocalFree(hDesc);
+Error3_2:
+ LocalFree(hShortName);
+Error3_1:
+ break;
+ }
+
+ default:
+ break;
+ }
+ SetCursor(oldCursor);
+ break;
+
+ case WM_MENUSELECT:
+ if(LOWORD(lParam)&MF_POPUP)
+ wHelpMenuItem = 0;
+ else if(LOWORD(lParam)&MF_SYSMENU)
+ wHelpMenuItem = IDH_SYSMENU;
+ else
+ wHelpMenuItem = wHelpMain+wParam;
+ break;
+
+ default:
+ break;
+ }
+
+ return(lpfnEditor(hWnd, wMessage, wParam, lParam));
+}
+
+
+BOOL NEAR PASCAL CreateMainWindow(void)
+{
+ WNDCLASS wndclass;
+
+ wndclass.style = 0;
+ wndclass.lpfnWndProc = (WNDPROC)WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(MAINICON));
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = COLOR_APPWORKSPACE + 1;
+ wndclass.lpszClassName = szAppName;
+
+ if(wCmdFlags&FLAG_VERBOSE) {
+ wndclass.lpszMenuName = MAKEINTRESOURCE(SDKMAINMENU);
+ lpfnEditor = SDKMainWnd;
+ lpfnSetValue = SDKSetValue;
+ wHelpMain = IDW_SDKMAIN;
+ wHelpIndex = IDW_SDKMAIN + 0x0100 + ID_HELPINDEX;
+ } else {
+ wndclass.lpszMenuName = MAKEINTRESOURCE(MAINMENU);
+ lpfnEditor = MainWnd;
+ wHelpMain = IDW_MAIN;
+ wHelpIndex = IDW_MAIN + 0x0100 + ID_HELPINDEX;
+ }
+
+ return(RegisterClass(&wndclass)
+ && (hWndMain=CreateWindow(szAppName, pszLongName,
+ WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL)));
+}
+#endif
+
+
+int PASCAL WinMain (HANDLE hInst, HANDLE hPrevInstance,
+ LPSTR lpszCmdLine, int nCmdShow)
+{
+ HANDLE hTemp, hCmd = NULL;
+#ifndef REGLOAD
+ FARPROC lpMessageFilter;
+ MSG msg;
+ VOID (FAR PASCAL *lpfnRegisterPenApp)(WORD, BOOL) = NULL;
+#endif
+
+ hInstance = hInst;
+
+ lpCmdLine = lpszCmdLine;
+ GetCommandFlags();
+
+ if(!(hTemp=MyLoadString(IDS_LONGNAME, NULL, LMEM_FIXED)))
+ return(FALSE);
+ pszLongName = LocalLock(hTemp);
+ if(!(hTemp=MyLoadString(IDS_OUTOFMEMORY, NULL, LMEM_FIXED)))
+ return(FALSE);
+ pszOutOfMemory = LocalLock(hTemp);
+
+ if(*lpCmdLine && !(hCmd=StringToHandle(lpCmdLine)))
+ return(FALSE);
+
+#ifdef REGLOAD
+ if ((hTemp=GetModuleHandle("REGEDIT")) > 1) {
+ PSTR pLocal;
+ WORD wFileLen = 130;
+ WORD wCmdLen = lstrlen(lpCmdLine) + 1;
+
+ while(1) {
+ if(!(pLocal=(PSTR)LocalAlloc(LMEM_FIXED, wFileLen+wCmdLen))) {
+ MyMessageBox(NULL, IDS_OUTOFMEMORY,
+ MB_OK|MB_ICONHAND|MB_SYSTEMMODAL, 0);
+ return(FALSE);
+ }
+ if(GetModuleFileName(hTemp, pLocal, wFileLen) < (int)wFileLen-5)
+ break;
+
+ LocalFree((HANDLE)pLocal);
+ wFileLen += 130;
+ }
+
+ lstrcat(pLocal, " ");
+ lstrcat(pLocal, lpCmdLine);
+
+ return(WinExec(pLocal, SW_SHOWNORMAL) > 32);
+ }
+#else
+ if(hPrevInstance) {
+ GetInstanceData(hPrevInstance, (PSTR)&hWndMain, sizeof(hWndMain));
+ if(hCmd)
+ PostMessage(hWndMain, WM_COMMAND, ID_FINISHMERGE,
+ MAKELONG(hCmd, wCmdFlags | FLAG_WRITETHROUGH));
+ else {
+ SetWindowPos(hWndMain, NULL, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ if(IsIconic(hWndMain))
+ ShowWindow(hWndMain, SW_RESTORE);
+ else
+ SetActiveWindow(GetLastActivePopup(hWndMain));
+ }
+ return(TRUE);
+ }
+#endif
+
+ if(hCmd) {
+ ProcessFiles(NULL, hCmd, wCmdFlags);
+ return(TRUE);
+ }
+
+#ifdef REGLOAD
+ return(TRUE);
+#else
+ if(!CreateMainWindow())
+ return(FALSE);
+
+ if(fOpenError)
+ PostMessage(hWndMain, WM_COMMAND, ID_EXIT, 0L);
+ else {
+ ShowWindow(hWndMain, nCmdShow);
+ UpdateWindow(hWndMain);
+ }
+
+ if(lpMessageFilter=MakeProcInstance(MessageFilter, hInstance))
+ lpOldHook = SetWindowsHook(WH_MSGFILTER, lpMessageFilter);
+
+ hAcc = LoadAccelerators(hInstance, wCmdFlags&FLAG_VERBOSE ?
+ szSDKRegEd : "RegEdit");
+
+ if (lpfnRegisterPenApp = GetProcAddress(GetSystemMetrics(SM_PENWINDOWS),
+ "RegisterPenApp"))
+ (*lpfnRegisterPenApp)(1, TRUE);
+
+ while(GetMessage(&msg, NULL, 0, 0)) {
+ if(!hAcc || !TranslateAccelerator(hWndMain, hAcc, &msg)) {
+ if(!hWndDlg || !IsDialogMessage(hWndDlg, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ if (lpfnRegisterPenApp)
+ (*lpfnRegisterPenApp)(1, FALSE);
+
+ if(lpMessageFilter) {
+ UnhookWindowsHook(WH_MSGFILTER, lpMessageFilter);
+ FreeProcInstance(lpMessageFilter);
+ }
+
+ return(msg.wParam);
+#endif
+}
diff --git a/private/mvdm/wow16/regedit/regporte.c b/private/mvdm/wow16/regedit/regporte.c
new file mode 100644
index 000000000..4e2d381cf
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regporte.c
@@ -0,0 +1,2213 @@
+#include <windows.h>
+#include <shellapi.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef CHAR
+#define CHAR char
+#endif // ifndef CHAR
+// from winreg.h:
+// HKEY_CLASSES_ROOT already defined
+#define HKEY_CURRENT_USER (( HKEY ) 0x80000001 )
+#define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 )
+#define HKEY_USERS (( HKEY ) 0x80000003 )
+#define HKEY_PERFORMANCE_DATA (( HKEY ) 0x80000004 )
+#define HKEY_CURRENT_CONFIG (( HKEY ) 0x80000005 )
+#define HKEY_DYN_DATA (( HKEY ) 0x80000006 )
+
+#include "regdef.h" // regdef.h from \\guilo\slm\src\dev\inc)
+
+//from pch.h, remove extern
+CHAR g_ValueNameBuffer[MAXVALUENAME_LENGTH];
+BYTE g_ValueDataBuffer[MAXDATA_LENGTH];
+
+// interface to regmain values
+extern LPSTR lpMerge;
+
+#include "reg1632.h"
+#include "regporte.h"
+#include "regresid.h"
+
+
+/*******************************************************************************
+*
+* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
+*
+* TITLE: REGPORTE.C
+*
+* VERSION: 4.01
+*
+* AUTHOR: Tracy Sharpe
+*
+* DATE: 06 Apr 1994
+*
+* File import and export engine routines for the Registry Editor.
+*
+*******************************************************************************/
+
+//#include "pch.h"
+//#include "regresid.h"
+//#include "reg1632.h"
+
+// When building for the Registry Editor, put all of the following constants
+// in a read-only data section.
+#ifdef WIN32
+#pragma data_seg(DATASEG_READONLY)
+#endif
+
+// Association between the ASCII name and the handle of the registry key.
+const REGISTRY_ROOT g_RegistryRoots[] = {
+ "HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT,
+ "HKEY_CURRENT_USER", HKEY_CURRENT_USER,
+ "HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE,
+ "HKEY_USERS", HKEY_USERS,
+// "HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA,
+ "HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG,
+ "HKEY_DYN_DATA", HKEY_DYN_DATA
+};
+
+const CHAR s_RegistryHeader[] = "REGEDIT";
+
+const CHAR s_OldWin31RegFileRoot[] = ".classes";
+
+const CHAR s_Win40RegFileHeader[] = "REGEDIT4\n\n";
+
+const CHAR s_HexPrefix[] = "hex";
+const CHAR s_DwordPrefix[] = "dword:";
+const CHAR g_HexConversion[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+const CHAR s_FileLineBreak[] = ",\\\n ";
+
+#ifdef WIN32
+#pragma data_seg()
+#endif
+
+#define SIZE_FILE_IO_BUFFER 512
+
+typedef struct _FILE_IO {
+ CHAR Buffer[SIZE_FILE_IO_BUFFER];
+ FILE_HANDLE hFile;
+ int BufferOffset;
+ int CurrentColumn;
+ int CharsAvailable;
+ DWORD FileSizeDiv100;
+ DWORD FileOffset;
+ UINT LastPercentage;
+#ifdef DEBUG
+ BOOL fValidateUngetChar;
+#endif
+} FILE_IO;
+
+FILE_IO s_FileIo;
+
+UINT g_FileErrorStringID;
+
+VOID
+NEAR PASCAL
+ImportWin31RegFile(
+ VOID
+ );
+
+VOID
+NEAR PASCAL
+ImportWin40RegFile(
+ VOID
+ );
+
+VOID
+NEAR PASCAL
+ParseHeader(
+ LPHKEY lphKey
+ );
+
+VOID
+NEAR PASCAL
+ParseValuename(
+ HKEY hKey
+ );
+
+VOID
+NEAR PASCAL
+ParseDefaultValue(
+ HKEY hKey
+ );
+
+BOOL
+NEAR PASCAL
+ParseString(
+ LPSTR lpString,
+ LPDWORD cbStringData
+ );
+
+BOOL
+NEAR PASCAL
+ParseHexSequence(
+ LPBYTE lpHexData,
+ LPDWORD lpcbHexData
+ );
+
+BOOL
+NEAR PASCAL
+ParseHexDword(
+ LPDWORD lpDword
+ );
+
+BOOL
+NEAR PASCAL
+ParseHexByte(
+ LPBYTE lpByte
+ );
+
+BOOL
+NEAR PASCAL
+ParseHexDigit(
+ LPBYTE lpDigit
+ );
+
+BOOL
+NEAR PASCAL
+ParseEndOfLine(
+ VOID
+ );
+
+VOID
+NEAR PASCAL
+SkipWhitespace(
+ VOID
+ );
+
+VOID
+NEAR PASCAL
+SkipPastEndOfLine(
+ VOID
+ );
+
+BOOL
+NEAR PASCAL
+GetChar(
+ LPCHAR lpChar
+ );
+
+VOID
+NEAR PASCAL
+UngetChar(
+ VOID
+ );
+
+BOOL
+NEAR PASCAL
+MatchChar(
+ CHAR CharToMatch
+ );
+
+BOOL
+NEAR PASCAL
+IsWhitespace(
+ CHAR Char
+ );
+
+BOOL
+NEAR PASCAL
+IsNewLine(
+ CHAR Char
+ );
+
+VOID
+NEAR PASCAL
+PutBranch(
+ HKEY hKey,
+ LPSTR lpKeyName
+ );
+
+VOID
+NEAR PASCAL
+PutLiteral(
+ LPCSTR lpString
+ );
+
+VOID
+NEAR PASCAL
+PutString(
+ LPCSTR lpString
+ );
+
+VOID
+NEAR PASCAL
+PutBinary(
+ CONST BYTE FAR* lpBuffer,
+ DWORD Type,
+ DWORD cbBytes
+ );
+
+VOID
+NEAR PASCAL
+PutDword(
+ DWORD Dword,
+ BOOL fLeadingZeroes
+ );
+
+VOID
+NEAR PASCAL
+PutChar(
+ CHAR Char
+ );
+
+VOID
+NEAR PASCAL
+FlushIoBuffer(
+ VOID
+ );
+
+#ifdef DBCS
+#ifndef WIN32
+LPSTR
+NEAR PASCAL
+DBCSStrChr(
+ LPSTR string,
+ CHAR chr
+ );
+
+BOOL
+NEAR PASCAL
+IsDBCSLeadByte(
+ BYTE chr
+ );
+#endif
+#endif
+
+/*******************************************************************************
+*
+* CreateRegistryKey
+*
+* DESCRIPTION:
+* Parses the pFullKeyName string and creates a handle to the registry key.
+*
+* PARAMETERS:
+* lphKey, location to store handle to registry key.
+* lpFullKeyName, string of form "HKEY_LOCAL_MACHINE\Subkey1\Subkey2".
+* fCreate, TRUE if key should be created, else FALSE for open only.
+* (returns), ERROR_SUCCESS, no errors occurred, phKey is valid,
+* ERROR_CANTOPEN, registry access error of some form,
+* ERROR_BADKEY, incorrectly formed pFullKeyName.
+*
+*******************************************************************************/
+
+DWORD
+PASCAL
+CreateRegistryKey(
+ LPHKEY lphKey,
+ LPSTR lpFullKeyName,
+ BOOL fCreate
+ )
+{
+
+ LPSTR lpSubKeyName;
+ CHAR PrevChar;
+ HKEY hRootKey;
+ UINT Counter;
+ DWORD Result;
+
+ if ((lpSubKeyName = (LPSTR) STRCHR(lpFullKeyName, '\\')) != NULL) {
+
+ PrevChar = *lpSubKeyName;
+ *lpSubKeyName++ = '\0';
+
+ }
+
+ CHARUPPERSTRING(lpFullKeyName);
+
+ hRootKey = NULL;
+
+ for (Counter = 0; Counter < NUMBER_REGISTRY_ROOTS; Counter++) {
+
+ if (STRCMP(g_RegistryRoots[Counter].lpKeyName, lpFullKeyName) == 0) {
+
+ hRootKey = g_RegistryRoots[Counter].hKey;
+ break;
+
+ }
+
+ }
+
+ if (hRootKey) {
+
+ Result = ERROR_CANTOPEN;
+
+ if (fCreate) {
+
+ if (RegCreateKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
+ Result = ERROR_SUCCESS;
+
+ }
+
+ else {
+
+ if (RegOpenKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
+ Result = ERROR_SUCCESS;
+
+ }
+
+ }
+
+ else
+ Result = ERROR_BADKEY;
+
+ if (lpSubKeyName != NULL) {
+
+ lpSubKeyName--;
+ *lpSubKeyName = PrevChar;
+
+ }
+
+ return Result;
+
+}
+
+/*******************************************************************************
+*
+* ImportRegFile
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+* lpFileName, address of name of file to be imported.
+*
+*******************************************************************************/
+#ifdef WIN95
+VOID
+PASCAL
+ImportRegFile(
+ LPSTR lpFileName
+ )
+{
+
+ CHAR Char;
+ LPCCH lpHeader;
+ BOOL fNewRegistryFile;
+#ifdef WIN32
+ OFSTRUCT OFStruct;
+#endif
+
+ g_FileErrorStringID = IDS_IMPFILEERRSUCCESS;
+
+ if (OPENREADFILE(lpFileName, s_FileIo.hFile)) {
+
+ s_FileIo.FileSizeDiv100 = GETFILESIZE(s_FileIo.hFile) / 100;
+ s_FileIo.FileOffset = 0;
+ s_FileIo.LastPercentage = 0;
+
+ //
+ // The following will force GetChar to read in the first block of data.
+ //
+
+ s_FileIo.BufferOffset = SIZE_FILE_IO_BUFFER;
+
+ SkipWhitespace();
+
+ lpHeader = s_RegistryHeader;
+
+ while (*lpHeader != '\0') {
+
+ if (MatchChar(*lpHeader))
+ lpHeader++;
+
+ else
+ break;
+
+ }
+
+ if (*lpHeader == '\0') {
+
+ fNewRegistryFile = MatchChar('4');
+
+ SkipWhitespace();
+
+ if (GetChar(&Char) && IsNewLine(Char)) {
+
+ if (fNewRegistryFile)
+ ImportWin40RegFile();
+
+ else
+ ImportWin31RegFile();
+
+ }
+
+ }
+
+ else
+ g_FileErrorStringID = IDS_IMPFILEERRFORMATBAD;
+
+ CLOSEFILE(s_FileIo.hFile);
+
+ }
+
+ else
+ g_FileErrorStringID = IDS_IMPFILEERRFILEOPEN;
+
+}
+
+/*******************************************************************************
+*
+* ImportWin31RegFile
+*
+* DESCRIPTION:
+* Imports the contents of a Windows 3.1 style registry file into the
+* registry.
+*
+* We scan over the file looking for lines of the following type:
+* HKEY_CLASSES_ROOT\keyname = value_data
+* HKEY_CLASSES_ROOT\keyname =value_data
+* HKEY_CLASSES_ROOT\keyname value_data
+* HKEY_CLASSES_ROOT\keyname (null value data)
+*
+* In all cases, any number of spaces may follow 'keyname'. Although we
+* only document the first syntax, the Windows 3.1 Regedit handled all of
+* these formats as valid, so this version will as well (fortunately, it
+* doesn't make the parsing any more complex!).
+*
+* Note, we also support replacing HKEY_CLASSES_ROOT with \.classes above
+* which must come from some early releases of Windows.
+*
+* PARAMETERS:
+* (none).
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+ImportWin31RegFile(
+ VOID
+ )
+{
+
+ HKEY hKey;
+ CHAR Char;
+ BOOL fSuccess;
+ LPCSTR lpClassesRoot;
+ CHAR KeyName[MAXKEYNAME];
+ UINT Index;
+
+ //
+ // Keep an open handle to the classes root. We may prevent some
+ // unneccessary flushing.
+ //
+
+ if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS) {
+
+ g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
+ return;
+
+ }
+
+ while (TRUE) {
+
+ //
+ // Check for the end of file condition.
+ //
+
+ if (!GetChar(&Char))
+ break;
+
+ UngetChar(); // Not efficient, but works for now.
+
+ //
+ // Match the beginning of the line against one of the two aliases for
+ // HKEY_CLASSES_ROOT.
+ //
+
+ if (MatchChar('\\'))
+ lpClassesRoot = s_OldWin31RegFileRoot;
+
+ else
+ lpClassesRoot = g_RegistryRoots[INDEX_HKEY_CLASSES_ROOT].lpKeyName;
+
+ fSuccess = TRUE;
+
+ while (*lpClassesRoot != '\0') {
+
+ if (!MatchChar(*lpClassesRoot++)) {
+
+ fSuccess = FALSE;
+ break;
+
+ }
+
+ }
+
+ //
+ // Make sure that we have a backslash seperating one of the aliases
+ // from the keyname.
+ //
+
+ if (fSuccess)
+ fSuccess = MatchChar('\\');
+
+ if (fSuccess) {
+
+ //
+ // We've found one of the valid aliases, so read in the keyname.
+ //
+
+ // fSuccess = TRUE; // Must be TRUE if we're in this block
+ Index = 0;
+
+ while (GetChar(&Char)) {
+
+ if (Char == ' ' || IsNewLine(Char))
+ break;
+
+ //
+ // Make sure that the keyname buffer doesn't overflow. We must
+ // leave room for a terminating null.
+ //
+
+ if (Index >= sizeof(KeyName) - 1) {
+
+ fSuccess = FALSE;
+ break;
+
+ }
+
+ KeyName[Index++] = Char;
+
+ }
+
+ if (fSuccess) {
+
+ KeyName[Index] = '\0';
+
+ //
+ // Now see if we have a value to assign to this keyname.
+ //
+
+ SkipWhitespace();
+
+ if (MatchChar('='))
+ MatchChar(' ');
+
+ // fSuccess = TRUE; // Must be TRUE if we're in this block
+ Index = 0;
+
+ while (GetChar(&Char)) {
+
+ if (IsNewLine(Char))
+ break;
+
+ //
+ // Make sure that the value data buffer doesn't overflow.
+ // Because this is always string data, we must leave room
+ // for a terminating null.
+ //
+
+ if (Index >= MAXDATA_LENGTH - 1) {
+
+ fSuccess = FALSE;
+ break;
+
+ }
+
+ g_ValueDataBuffer[Index++] = Char;
+
+ }
+
+ if (fSuccess) {
+
+ g_ValueDataBuffer[Index] = '\0';
+
+ if (RegSetValue(hKey, KeyName, REG_SZ, g_ValueDataBuffer,
+ Index) != ERROR_SUCCESS)
+ g_FileErrorStringID = IDS_IMPFILEERRREGSET;
+
+ }
+
+ }
+
+ }
+
+ //
+ // Somewhere along the line, we had a parsing error, so resynchronize
+ // on the next line.
+ //
+
+ if (!fSuccess)
+ SkipPastEndOfLine();
+
+ }
+
+ RegFlushKey(hKey);
+ RegCloseKey(hKey);
+
+}
+#endif // ifdef WIN95
+/*******************************************************************************
+*
+* ImportWin40RegFile
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+ImportWin40RegFile(
+ VOID
+ )
+{
+
+ HKEY hLocalMachineKey;
+ HKEY hUsersKey;
+ HKEY hKey;
+ CHAR Char;
+
+ //
+ // Keep open handles for the predefined roots to prevent the registry
+ // library from flushing after every single RegOpenKey/RegCloseKey
+ // operation.
+ //
+
+ RegOpenKey(HKEY_LOCAL_MACHINE, NULL, &hLocalMachineKey);
+ RegOpenKey(HKEY_USERS, NULL, &hUsersKey);
+
+#ifdef DEBUG
+ if (hLocalMachineKey == NULL)
+ OutputDebugString("Unable to open HKEY_LOCAL_MACHINE\n\r");
+ if (hUsersKey == NULL)
+ OutputDebugString("Unable to open HKEY_USERS\n\r");
+#endif
+
+ hKey = NULL;
+
+ while (TRUE) {
+
+ SkipWhitespace();
+
+ //
+ // Check for the end of file condition.
+ //
+
+ if (!GetChar(&Char))
+ break;
+
+ switch (Char) {
+
+ case '[':
+ //
+ // If a registry key is currently open, we must close it first.
+ // If ParseHeader happens to fail (for example, no closing
+ // bracket), then hKey will be NULL and any values that we
+ // parse must be ignored.
+ //
+
+ if (hKey != NULL) {
+
+ RegCloseKey(hKey);
+ hKey = NULL;
+
+ }
+
+ ParseHeader(&hKey);
+
+ break;
+
+ case '"':
+ //
+ // As noted above, if we don't have an open registry key, then
+ // just skip the line.
+ //
+
+ if (hKey != NULL)
+ ParseValuename(hKey);
+
+ else
+ SkipPastEndOfLine();
+
+ break;
+
+ case '@':
+ //
+ //
+ //
+
+ if (hKey != NULL)
+ ParseDefaultValue(hKey);
+
+ else
+ SkipPastEndOfLine();
+
+ break;
+
+ case ';':
+ //
+ // This line is a comment so just dump the rest of it.
+ //
+
+ SkipPastEndOfLine();
+
+ break;
+
+ default:
+ if (IsNewLine(Char))
+ break;
+
+ SkipPastEndOfLine();
+
+ break;
+
+ }
+
+ }
+
+ if (hKey != NULL)
+ RegCloseKey(hKey);
+
+ if (hUsersKey != NULL)
+ RegCloseKey(hUsersKey);
+
+ if (hLocalMachineKey != NULL)
+ RegCloseKey(hLocalMachineKey);
+
+}
+
+/*******************************************************************************
+*
+* ParseHeader
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+#define SIZE_FULL_KEYNAME (MAXKEYNAME + 40)
+
+VOID
+NEAR PASCAL
+ParseHeader(
+ LPHKEY lphKey
+ )
+{
+
+ CHAR FullKeyName[SIZE_FULL_KEYNAME];
+ int CurrentIndex;
+ int LastRightBracketIndex;
+ CHAR Char;
+
+ CurrentIndex = 0;
+ LastRightBracketIndex = -1;
+
+ while (GetChar(&Char)) {
+
+ if (IsNewLine(Char))
+ break;
+
+ if (Char == ']')
+ LastRightBracketIndex = CurrentIndex;
+
+ FullKeyName[CurrentIndex++] = Char;
+
+ if (CurrentIndex == SIZE_FULL_KEYNAME) {
+
+ do {
+
+ if (Char == ']')
+ LastRightBracketIndex = -1;
+
+ if (IsNewLine(Char))
+ break;
+
+ } while (GetChar(&Char));
+
+ break;
+
+ }
+
+ }
+
+ if (LastRightBracketIndex != -1) {
+
+ FullKeyName[LastRightBracketIndex] = '\0';
+
+ switch (CreateRegistryKey(lphKey, FullKeyName, TRUE)) {
+
+ case ERROR_CANTOPEN:
+ g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
+ break;
+
+ }
+
+ }
+
+}
+
+/*******************************************************************************
+*
+* ParseValuename
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+ParseValuename(
+ HKEY hKey
+ )
+{
+
+ DWORD Type;
+ CHAR ValueName[MAXVALUENAME_LENGTH];
+ DWORD cbData;
+ LPCSTR lpPrefix;
+
+ cbData = sizeof(ValueName);
+
+ if (!ParseString(ValueName, &cbData))
+ goto ParseError;
+
+ SkipWhitespace();
+
+ if (!MatchChar('='))
+ goto ParseError;
+
+ SkipWhitespace();
+
+ //
+ // REG_SZ.
+ //
+ // "ValueName" = "string of text"
+ //
+
+ if (MatchChar('"')) {
+
+ // LATER: Line continuations for strings?
+
+ cbData = MAXDATA_LENGTH;
+
+ if (!ParseString(g_ValueDataBuffer, &cbData) || !ParseEndOfLine())
+ goto ParseError;
+
+ Type = REG_SZ;
+
+ }
+
+ //
+ // REG_DWORD.
+ //
+ // "ValueName" = dword: 12345678
+ //
+
+ else if (MatchChar(s_DwordPrefix[0])) {
+
+ lpPrefix = &s_DwordPrefix[1];
+
+ while (*lpPrefix != '\0')
+ if (!MatchChar(*lpPrefix++))
+ goto ParseError;
+
+ SkipWhitespace();
+
+ if (!ParseHexDword((LPDWORD) g_ValueDataBuffer) || !ParseEndOfLine())
+ goto ParseError;
+
+ Type = REG_DWORD;
+ cbData = sizeof(DWORD);
+
+ }
+
+ //
+ // REG_BINARY and other.
+ //
+ // "ValueName" = hex: 00 , 11 , 22
+ // "ValueName" = hex(12345678): 00, 11, 22
+ //
+
+ else {
+
+ lpPrefix = s_HexPrefix;
+
+ while (*lpPrefix != '\0')
+ if (!MatchChar(*lpPrefix++))
+ goto ParseError;
+
+ //
+ // Check if this is a type of registry data that we don't directly
+ // support. If so, then it's just a dump of hex data of the specified
+ // type.
+ //
+
+ if (MatchChar('(')) {
+
+ if (!ParseHexDword(&Type) || !MatchChar(')'))
+ goto ParseError;
+
+ }
+
+ else
+ Type = REG_BINARY;
+
+ if (!MatchChar(':') || !ParseHexSequence(g_ValueDataBuffer, &cbData) ||
+ !ParseEndOfLine())
+ goto ParseError;
+
+ }
+
+ if (RegSetValueEx(hKey, ValueName, 0, Type, g_ValueDataBuffer, cbData) !=
+ ERROR_SUCCESS)
+ g_FileErrorStringID = IDS_IMPFILEERRREGSET;
+
+ return;
+
+ParseError:
+ SkipPastEndOfLine();
+
+}
+
+/*******************************************************************************
+*
+* ParseDefaultValue
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+ParseDefaultValue(
+ HKEY hKey
+ )
+{
+
+ BOOL fSuccess;
+ DWORD cbData;
+
+ fSuccess = FALSE;
+
+ SkipWhitespace();
+
+ if (MatchChar('=')) {
+
+ SkipWhitespace();
+
+ if (MatchChar('"')) {
+
+ // LATER: Line continuations for strings?
+
+ cbData = MAXDATA_LENGTH;
+
+ if (ParseString(g_ValueDataBuffer, &cbData) && ParseEndOfLine()) {
+
+ if (RegSetValue(hKey, NULL, REG_SZ, g_ValueDataBuffer,
+ cbData) != ERROR_SUCCESS)
+ g_FileErrorStringID = IDS_IMPFILEERRREGSET;
+
+ fSuccess = TRUE;
+
+ }
+
+ }
+
+ }
+
+ if (!fSuccess)
+ SkipPastEndOfLine();
+
+}
+
+/*******************************************************************************
+*
+* ParseString
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseString(
+ LPSTR lpString,
+ LPDWORD lpcbStringData
+ )
+{
+
+ CHAR Char;
+ DWORD cbMaxStringData;
+ DWORD cbStringData;
+
+ cbMaxStringData = *lpcbStringData;
+ cbStringData = 1; // Account for the null terminator
+
+ while (GetChar(&Char)) {
+
+ if (cbStringData >= cbMaxStringData)
+ return FALSE;
+
+ switch (Char) {
+
+ case '\\':
+ if (!GetChar(&Char))
+ return FALSE;
+
+ switch (Char) {
+
+ case '\\':
+ *lpString++ = '\\';
+ break;
+
+ case '"':
+ *lpString++ = '"';
+ break;
+
+ default:
+ OutputDebugString("ParseString: Invalid escape sequence");
+ return FALSE;
+
+ }
+ break;
+
+ case '"':
+ *lpString = '\0';
+ *lpcbStringData = cbStringData;
+ return TRUE;
+
+ default:
+ if (IsNewLine(Char))
+ return FALSE;
+
+ *lpString++ = Char;
+
+#ifdef DBCS
+ if (IsDBCSLeadByte((BYTE)Char))
+ {
+ if (!GetChar(&Char))
+ return FALSE;
+ *lpString++ = Char;
+ }
+#endif
+
+ break;
+
+ }
+
+ cbStringData++;
+
+ }
+
+ return FALSE;
+
+}
+
+/*******************************************************************************
+*
+* ParseHexSequence
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseHexSequence(
+ LPBYTE lpHexData,
+ LPDWORD lpcbHexData
+ )
+{
+
+ DWORD cbHexData;
+
+ cbHexData = 0;
+
+ do {
+
+ if (cbHexData >= MAXDATA_LENGTH)
+ return FALSE;
+
+ SkipWhitespace();
+
+ if (MatchChar('\\') && !ParseEndOfLine())
+ return FALSE;
+
+ SkipWhitespace();
+
+ if (!ParseHexByte(lpHexData++))
+ break;
+
+ cbHexData++;
+
+ SkipWhitespace();
+
+ } while (MatchChar(','));
+
+ *lpcbHexData = cbHexData;
+
+ return TRUE;
+
+}
+
+/*******************************************************************************
+*
+* ParseHexDword
+*
+* DESCRIPTION:
+* Parses a one dword hexadecimal string from the registry file stream and
+* converts it to a binary number. A maximum of eight hex digits will be
+* parsed from the stream.
+*
+* PARAMETERS:
+* lpByte, location to store binary number.
+* (returns), TRUE if a hexadecimal dword was parsed, else FALSE.
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseHexDword(
+ LPDWORD lpDword
+ )
+{
+
+ UINT CountDigits;
+ DWORD Dword;
+ BYTE Byte;
+
+ Dword = 0;
+ CountDigits = 0;
+
+ while (TRUE) {
+
+ if (!ParseHexDigit(&Byte))
+ break;
+
+ Dword = (Dword << 4) + (DWORD) Byte;
+
+ if (++CountDigits == 8)
+ break;
+
+ }
+
+ *lpDword = Dword;
+
+ return CountDigits != 0;
+
+}
+
+/*******************************************************************************
+*
+* ParseHexByte
+*
+* DESCRIPTION:
+* Parses a one byte hexadecimal string from the registry file stream and
+* converts it to a binary number.
+*
+* PARAMETERS:
+* lpByte, location to store binary number.
+* (returns), TRUE if a hexadecimal byte was parsed, else FALSE.
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseHexByte(
+ LPBYTE lpByte
+ )
+{
+
+ BYTE SecondDigit;
+
+ if (ParseHexDigit(lpByte)) {
+
+ if (ParseHexDigit(&SecondDigit))
+ *lpByte = (BYTE) ((*lpByte << 4) | SecondDigit);
+
+ return TRUE;
+
+ }
+
+ else
+ return FALSE;
+
+}
+
+/*******************************************************************************
+*
+* ParseHexDigit
+*
+* DESCRIPTION:
+* Parses a hexadecimal character from the registry file stream and converts
+* it to a binary number.
+*
+* PARAMETERS:
+* lpDigit, location to store binary number.
+* (returns), TRUE if a hexadecimal digit was parsed, else FALSE.
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseHexDigit(
+ LPBYTE lpDigit
+ )
+{
+
+ CHAR Char;
+ BYTE Digit;
+
+ if (GetChar(&Char)) {
+
+ if (Char >= '0' && Char <= '9')
+ Digit = (BYTE) (Char - '0');
+
+ else if (Char >= 'a' && Char <= 'f')
+ Digit = (BYTE) (Char - 'a' + 10);
+
+ else if (Char >= 'A' && Char <= 'F')
+ Digit = (BYTE) (Char - 'A' + 10);
+
+ else {
+
+ UngetChar();
+
+ return FALSE;
+
+ }
+
+ *lpDigit = Digit;
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+/*******************************************************************************
+*
+* ParseEndOfLine
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+ParseEndOfLine(
+ VOID
+ )
+{
+
+ CHAR Char;
+ BOOL fComment;
+ BOOL fFoundOneEndOfLine;
+
+ fComment = FALSE;
+ fFoundOneEndOfLine = FALSE;
+
+ while (GetChar(&Char)) {
+
+ if (IsWhitespace(Char))
+ continue;
+
+ if (IsNewLine(Char)) {
+
+ fComment = FALSE;
+ fFoundOneEndOfLine = TRUE;
+
+ }
+
+ //
+ // Like .INIs and .INFs, comments begin with a semicolon character.
+ //
+
+ else if (Char == ';')
+ fComment = TRUE;
+
+ else if (!fComment) {
+
+ UngetChar();
+
+ break;
+
+ }
+
+ }
+
+ return fFoundOneEndOfLine;
+
+}
+
+/*******************************************************************************
+*
+* SkipWhitespace
+*
+* DESCRIPTION:
+* Advances the registry file pointer to the first character past any
+* detected whitespace.
+*
+* PARAMETERS:
+* (none).
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+SkipWhitespace(
+ VOID
+ )
+{
+
+ CHAR Char;
+
+ while (GetChar(&Char)) {
+
+ if (!IsWhitespace(Char)) {
+
+ UngetChar();
+ break;
+
+ }
+
+ }
+
+}
+
+/*******************************************************************************
+*
+* SkipPastEndOfLine
+*
+* DESCRIPTION:
+* Advances the registry file pointer to the first character past the first
+* detected new line character.
+*
+* PARAMETERS:
+* (none).
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+SkipPastEndOfLine(
+ VOID
+ )
+{
+
+ CHAR Char;
+
+ while (GetChar(&Char)) {
+
+ if (IsNewLine(Char))
+ break;
+
+ }
+
+ while (GetChar(&Char)) {
+
+ if (!IsNewLine(Char)) {
+
+ UngetChar();
+ break;
+
+ }
+
+ }
+
+}
+
+/*******************************************************************************
+*
+* GetChar
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+GetChar(
+ LPCHAR lpChar
+ )
+{
+#ifdef WIN95
+
+ FILE_NUMBYTES NumberOfBytesRead;
+ UINT NewPercentage;
+
+ if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER) {
+
+ if (!READFILE(s_FileIo.hFile, s_FileIo.Buffer,
+ sizeof(s_FileIo.Buffer), &NumberOfBytesRead)) {
+
+ g_FileErrorStringID = IDS_IMPFILEERRFILEREAD;
+ return FALSE;
+
+ }
+
+ s_FileIo.BufferOffset = 0;
+ s_FileIo.CharsAvailable = ((int) NumberOfBytesRead);
+
+ s_FileIo.FileOffset += NumberOfBytesRead;
+
+ if (s_FileIo.FileSizeDiv100 != 0) {
+
+ NewPercentage = ((UINT) (s_FileIo.FileOffset /
+ s_FileIo.FileSizeDiv100));
+
+ if (NewPercentage > 100)
+ NewPercentage = 100;
+
+ }
+
+ else
+ NewPercentage = 100;
+
+ if (s_FileIo.LastPercentage != NewPercentage) {
+
+ s_FileIo.LastPercentage = NewPercentage;
+ ImportRegFileUICallback(NewPercentage);
+
+ }
+
+ }
+
+ if (s_FileIo.BufferOffset >= s_FileIo.CharsAvailable)
+ return FALSE;
+
+ *lpChar = s_FileIo.Buffer[s_FileIo.BufferOffset++];
+
+ return TRUE;
+#else
+ if (*lpMerge) {
+ *lpChar=*lpMerge++;
+ return TRUE;
+ } else
+ return FALSE;
+#endif // ifdef WIN95
+
+}
+
+/*******************************************************************************
+*
+* UngetChar
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+UngetChar(
+ VOID
+ )
+{
+#ifdef WIN95
+#ifdef DEBUG
+ if (s_FileIo.fValidateUngetChar)
+ OutputDebugString("REGEDIT ERROR: Too many UngetChar's called!\n\r");
+#endif // ifdef DEBUG
+
+ s_FileIo.BufferOffset--;
+#else
+ lpMerge--;
+#endif // ifdef WIN95
+
+}
+
+/*******************************************************************************
+*
+* MatchChar
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+MatchChar(
+ CHAR CharToMatch
+ )
+{
+
+ BOOL fMatch;
+ CHAR NextChar;
+
+ fMatch = FALSE;
+
+ if (GetChar(&NextChar)) {
+
+ if (CharToMatch == NextChar)
+ fMatch = TRUE;
+
+ else
+ UngetChar();
+
+ }
+
+ return fMatch;
+
+}
+
+/*******************************************************************************
+*
+* IsWhitespace
+*
+* DESCRIPTION:
+* Checks if the given character is whitespace.
+*
+* PARAMETERS:
+* Char, character to check.
+* (returns), TRUE if character is whitespace, else FALSE.
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+IsWhitespace(
+ CHAR Char
+ )
+{
+
+ return Char == ' ' || Char == '\t';
+
+}
+
+/*******************************************************************************
+*
+* IsNewLine
+*
+* DESCRIPTION:
+* Checks if the given character is a new line character.
+*
+* PARAMETERS:
+* Char, character to check.
+* (returns), TRUE if character is a new line, else FALSE.
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+IsNewLine(
+ CHAR Char
+ )
+{
+
+ return Char == '\n' || Char == '\r';
+
+}
+#ifdef WIN95
+/*******************************************************************************
+*
+* ExportWin40RegFile
+*
+* DESCRIPTION:
+*
+* PARAMETERS:
+*
+*******************************************************************************/
+
+VOID
+PASCAL
+ExportWin40RegFile(
+ LPSTR lpFileName,
+ LPSTR lpSelectedPath
+ )
+{
+
+ HKEY hKey;
+ CHAR SelectedPath[SIZE_SELECTED_PATH];
+
+ g_FileErrorStringID = IDS_EXPFILEERRSUCCESS;
+
+ if (lpSelectedPath != NULL && CreateRegistryKey(&hKey, lpSelectedPath,
+ FALSE) != ERROR_SUCCESS) {
+
+ g_FileErrorStringID = IDS_EXPFILEERRBADREGPATH;
+ return;
+
+ }
+
+ if (OPENWRITEFILE(lpFileName, s_FileIo.hFile)) {
+
+ s_FileIo.BufferOffset = 0;
+ s_FileIo.CurrentColumn = 0;
+
+ PutLiteral(s_Win40RegFileHeader);
+
+ if (lpSelectedPath != NULL) {
+
+ STRCPY(SelectedPath, lpSelectedPath);
+ PutBranch(hKey, SelectedPath);
+
+ }
+
+ else {
+
+ STRCPY(SelectedPath,
+ g_RegistryRoots[INDEX_HKEY_LOCAL_MACHINE].lpKeyName);
+ PutBranch(HKEY_LOCAL_MACHINE, SelectedPath);
+
+ STRCPY(SelectedPath,
+ g_RegistryRoots[INDEX_HKEY_USERS].lpKeyName);
+ PutBranch(HKEY_USERS, SelectedPath);
+
+ }
+
+ FlushIoBuffer();
+
+ CLOSEFILE(s_FileIo.hFile);
+
+ }
+
+ else
+ g_FileErrorStringID = IDS_EXPFILEERRFILEOPEN;
+
+ if (lpSelectedPath != NULL)
+ RegCloseKey(hKey);
+
+}
+
+/*******************************************************************************
+*
+* PutBranch
+*
+* DESCRIPTION:
+* Writes out all of the value names and their data and recursively calls
+* this routine for all of the key's subkeys to the registry file stream.
+*
+* PARAMETERS:
+* hKey, registry key to write to file.
+* lpFullKeyName, string that gives the full path, including the root key
+* name, of the hKey.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutBranch(
+ HKEY hKey,
+ LPSTR lpFullKeyName
+ )
+{
+
+ LONG RegError;
+ DWORD EnumIndex;
+ DWORD cbValueName;
+ DWORD cbValueData;
+ DWORD Type;
+ LPSTR lpSubKeyName;
+ int MaximumSubKeyLength;
+ HKEY hSubKey;
+
+ //
+ // Write out the section header.
+ //
+
+ PutChar('[');
+ PutLiteral(lpFullKeyName);
+ PutLiteral("]\n");
+
+ //
+ // Write out all of the value names and their data.
+ //
+
+ EnumIndex = 0;
+
+ while (TRUE) {
+
+ cbValueName = sizeof(g_ValueNameBuffer);
+ cbValueData = MAXDATA_LENGTH;
+
+ if ((RegError = RegEnumValue(hKey, EnumIndex++, g_ValueNameBuffer,
+ &cbValueName, NULL, &Type, g_ValueDataBuffer, &cbValueData))
+ != ERROR_SUCCESS)
+ break;
+
+ //
+ // If cbValueName is zero, then this is the default value of
+ // the key, or the Windows 3.1 compatible key value.
+ //
+
+ if (cbValueName)
+ PutString(g_ValueNameBuffer);
+
+ else
+ PutChar('@');
+
+ PutChar('=');
+
+ switch (Type) {
+
+ case REG_SZ:
+ PutString((LPSTR) g_ValueDataBuffer);
+ break;
+
+ case REG_DWORD:
+ if (cbValueData == sizeof(DWORD)) {
+
+ PutLiteral(s_DwordPrefix);
+ PutDword(*((LPDWORD) g_ValueDataBuffer), TRUE);
+ break;
+
+ }
+ // FALL THROUGH
+
+ case REG_BINARY:
+ default:
+ PutBinary((LPBYTE) g_ValueDataBuffer, Type, cbValueData);
+ break;
+
+ }
+
+ PutChar('\n');
+
+ if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
+ return;
+
+ }
+
+ PutChar('\n');
+
+ if (RegError != ERROR_NO_MORE_ITEMS)
+ g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
+
+ //
+ // Write out all of the subkeys and recurse into them.
+ //
+
+ lpSubKeyName = lpFullKeyName + STRLEN(lpFullKeyName);
+ *lpSubKeyName++ = '\\';
+ MaximumSubKeyLength = MAXKEYNAME - STRLEN(lpSubKeyName);
+
+ EnumIndex = 0;
+
+ while (TRUE) {
+
+ if ((RegError = RegEnumKey(hKey, EnumIndex++, lpSubKeyName,
+ MaximumSubKeyLength)) != ERROR_SUCCESS)
+ break;
+
+ if (RegOpenKey(hKey, lpSubKeyName, &hSubKey) == ERROR_SUCCESS) {
+
+ PutBranch(hSubKey, lpFullKeyName);
+
+ RegCloseKey(hSubKey);
+
+ if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
+ return;
+
+ }
+
+ else
+ g_FileErrorStringID = IDS_EXPFILEERRREGOPEN;
+
+ }
+
+ if (RegError != ERROR_NO_MORE_ITEMS)
+ g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
+
+}
+
+/*******************************************************************************
+*
+* PutLiteral
+*
+* DESCRIPTION:
+* Writes a literal string to the registry file stream. No special handling
+* is done for the string-- it is written out as is.
+*
+* PARAMETERS:
+* lpLiteral, null-terminated literal to write to file.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutLiteral(
+ LPCSTR lpLiteral
+ )
+{
+
+ while (*lpLiteral != '\0')
+ PutChar(*lpLiteral++);
+
+}
+
+/*******************************************************************************
+*
+* PutString
+*
+* DESCRIPTION:
+* Writes a string to the registry file stream. A string is surrounded by
+* double quotes and some characters may be translated to escape sequences
+* to enable a parser to read the string back in.
+*
+* PARAMETERS:
+* lpString, null-terminated string to write to file.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutString(
+ LPCSTR lpString
+ )
+{
+
+ CHAR Char;
+
+ PutChar('"');
+
+ while ((Char = *lpString++) != '\0') {
+
+ switch (Char) {
+
+ case '\\':
+ case '"':
+ PutChar('\\');
+ // FALL THROUGH
+
+ default:
+ PutChar(Char);
+#ifdef DBCS
+ if (IsDBCSLeadByte((BYTE)Char))
+ PutChar(*lpString++);
+#endif
+ break;
+
+ }
+
+ }
+
+ PutChar('"');
+
+}
+
+/*******************************************************************************
+*
+* PutBinary
+*
+* DESCRIPTION:
+* Writes a sequence of hexadecimal bytes to the registry file stream. The
+* output is formatted such that it doesn't exceed a defined line length.
+*
+* PARAMETERS:
+* lpBuffer, bytes to write to file.
+* Type, value data type.
+* cbBytes, number of bytes to write.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutBinary(
+ CONST BYTE FAR* lpBuffer,
+ DWORD Type,
+ DWORD cbBytes
+ )
+{
+
+ BOOL fFirstByteOnLine;
+ BYTE Byte;
+
+ PutLiteral(s_HexPrefix);
+
+ if (Type != REG_BINARY) {
+
+ PutChar('(');
+ PutDword(Type, FALSE);
+ PutChar(')');
+
+ }
+
+ PutChar(':');
+
+ fFirstByteOnLine = TRUE;
+
+ while (cbBytes--) {
+
+ if (s_FileIo.CurrentColumn > 75) {
+
+ PutLiteral(s_FileLineBreak);
+
+ fFirstByteOnLine = TRUE;
+
+ }
+
+ if (!fFirstByteOnLine)
+ PutChar(',');
+
+ Byte = *lpBuffer++;
+
+ PutChar(g_HexConversion[Byte >> 4]);
+ PutChar(g_HexConversion[Byte & 0x0F]);
+
+ fFirstByteOnLine = FALSE;
+
+ }
+
+}
+
+/*******************************************************************************
+*
+* PutChar
+*
+* DESCRIPTION:
+* Writes a 32-bit word to the registry file stream.
+*
+* PARAMETERS:
+* Dword, dword to write to file.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutDword(
+ DWORD Dword,
+ BOOL fLeadingZeroes
+ )
+{
+
+ int CurrentNibble;
+ CHAR Char;
+ BOOL fWroteNonleadingChar;
+
+ fWroteNonleadingChar = fLeadingZeroes;
+
+ for (CurrentNibble = 7; CurrentNibble >= 0; CurrentNibble--) {
+
+ Char = g_HexConversion[(Dword >> (CurrentNibble * 4)) & 0x0F];
+
+ if (fWroteNonleadingChar || Char != '0') {
+
+ PutChar(Char);
+ fWroteNonleadingChar = TRUE;
+
+ }
+
+ }
+
+ //
+ // We need to write at least one character, so if we haven't written
+ // anything yet, just spit out one zero.
+ //
+
+ if (!fWroteNonleadingChar)
+ PutChar('0');
+
+}
+
+/*******************************************************************************
+*
+* PutChar
+*
+* DESCRIPTION:
+* Writes one character to the registry file stream using an intermediate
+* buffer.
+*
+* PARAMETERS:
+* Char, character to write to file.
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+PutChar(
+ CHAR Char
+ )
+{
+
+ //
+ // Keep track of what column we're currently at. This is useful in cases
+ // such as writing a large binary registry record. Instead of writing one
+ // very long line, the other Put* routines can break up their output.
+ //
+
+ if (Char != '\n')
+ s_FileIo.CurrentColumn++;
+
+ else {
+
+ //
+ // Force a carriage-return, line-feed sequence to keep things like, oh,
+ // Notepad happy.
+ //
+
+ PutChar('\r');
+
+ s_FileIo.CurrentColumn = 0;
+
+ }
+
+ s_FileIo.Buffer[s_FileIo.BufferOffset++] = Char;
+
+ if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER)
+ FlushIoBuffer();
+
+}
+
+/*******************************************************************************
+*
+* FlushIoBuffer
+*
+* DESCRIPTION:
+* Flushes the contents of the registry file stream to the disk and resets
+* the buffer pointer.
+*
+* PARAMETERS:
+* (none).
+*
+*******************************************************************************/
+
+VOID
+NEAR PASCAL
+FlushIoBuffer(
+ VOID
+ )
+{
+
+ FILE_NUMBYTES NumberOfBytesWritten;
+
+ if (s_FileIo.BufferOffset) {
+
+ if (!WRITEFILE(s_FileIo.hFile, s_FileIo.Buffer, s_FileIo.BufferOffset,
+ &NumberOfBytesWritten) || (FILE_NUMBYTES) s_FileIo.BufferOffset !=
+ NumberOfBytesWritten)
+ g_FileErrorStringID = IDS_EXPFILEERRFILEWRITE;
+
+ }
+
+ s_FileIo.BufferOffset = 0;
+
+}
+#endif // ifdef WIN95
+#ifndef WIN32
+/*******************************************************************************
+*
+* GetFileSize
+*
+* DESCRIPTION:
+* Returns the file size for the given file handle.
+*
+* DESTRUCTIVE: After this call, the file pointer will be set to byte zero.
+*
+* PARAMETERS:
+* hFile, file handle opened via MS-DOS.
+* (returns), size of file.
+*
+*******************************************************************************/
+
+DWORD
+NEAR PASCAL
+GetFileSize(
+ FILE_HANDLE hFile
+ )
+{
+
+ DWORD FileSize;
+
+ FileSize = _llseek(hFile, 0, SEEK_END);
+ _llseek(hFile, 0, SEEK_SET);
+
+ return FileSize;
+
+}
+#endif
+
+#ifdef DBCS
+#ifndef WIN32
+/*******************************************************************************
+*
+* DBCSSTRCHR
+*
+* DESCRIPTION:
+* DBCS enabled STRCHR
+*
+*******************************************************************************/
+
+LPSTR
+NEAR PASCAL
+DBCSStrChr(
+ LPSTR string,
+ CHAR chr
+ )
+{
+ LPSTR p;
+
+ p = string;
+ while (*p)
+ {
+ if (IsDBCSLeadByte((BYTE)*p))
+ {
+ p++;
+ if (*p == 0)
+ break;
+ }
+ else if (*p == chr)
+ return (p);
+ p++;
+ }
+ if (*p == chr)
+ return (p);
+ return NULL;
+}
+
+/*******************************************************************************
+*
+* IsDBCSLeadByte
+*
+* DESCRIPTION:
+* Test if the character is DBCS lead byte
+*
+*******************************************************************************/
+
+BOOL
+NEAR PASCAL
+IsDBCSLeadByte(
+ BYTE chr
+ )
+{
+ static unsigned char far *DBCSLeadByteTable = NULL;
+
+ WORD off,segs;
+ LPSTR p;
+
+ if (DBCSLeadByteTable == NULL)
+ {
+ _asm {
+ push ds
+ mov ax,6300h
+ int 21h
+ mov off,si
+ mov segs,ds
+ pop ds
+ }
+ FP_OFF(DBCSLeadByteTable) = off;
+ FP_SEG(DBCSLeadByteTable) = segs;
+ }
+
+ p = DBCSLeadByteTable;
+ while (p[0] || p[1])
+ {
+ if (chr >= p[0] && chr <= p[1])
+ return TRUE;
+ p += 2;
+ }
+ return FALSE;
+}
+#endif // WIN32
+#endif // DBCS
diff --git a/private/mvdm/wow16/regedit/regporte.h b/private/mvdm/wow16/regedit/regporte.h
new file mode 100644
index 000000000..0836dd7b6
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regporte.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+*
+* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
+*
+* TITLE: REGPORTE.H
+*
+* VERSION: 4.01
+*
+* AUTHOR: Tracy Sharpe
+*
+* DATE: 06 Apr 1994
+*
+* File import and export engine routines for the Registry Editor.
+*
+*******************************************************************************/
+
+#ifndef _INC_REGPORTE
+#define _INC_REGPORTE
+
+#ifndef LPHKEY
+#define LPHKEY HKEY FAR*
+#endif
+
+typedef struct _REGISTRY_ROOT {
+ LPSTR lpKeyName;
+ HKEY hKey;
+} REGISTRY_ROOT;
+
+#define INDEX_HKEY_CLASSES_ROOT 0
+#define INDEX_HKEY_CURRENT_USER 1
+#define INDEX_HKEY_LOCAL_MACHINE 2
+#define INDEX_HKEY_USERS 3
+// #define INDEX_HKEY_PERFORMANCE_DATA 4
+#define INDEX_HKEY_CURRENT_CONFIG 5
+#define INDEX_HKEY_DYN_DATA 6
+
+// #define NUMBER_REGISTRY_ROOTS 7
+#define NUMBER_REGISTRY_ROOTS 6
+
+// This is supposed to be enough for one keyname plus one predefined
+// handle name. The longest predefined handle name is < 25 characters, so
+// this gives us room for growth should more predefined keys be added.
+
+#define SIZE_SELECTED_PATH (MAXKEYNAME + 40)
+
+extern const CHAR g_HexConversion[];
+
+extern UINT g_FileErrorStringID;
+
+DWORD
+PASCAL
+CreateRegistryKey(
+ LPHKEY lphKey,
+ LPSTR lpFullKeyName,
+ BOOL fCreate
+ );
+
+VOID
+PASCAL
+ImportRegFile(
+ LPSTR lpFileName
+ );
+
+VOID
+PASCAL
+ExportWin40RegFile(
+ LPSTR lpFileName,
+ LPSTR lpSelectedPath
+ );
+
+VOID
+PASCAL
+ImportRegFileUICallback(
+ UINT Percentage
+ );
+
+LONG RegSetValueEx(
+ HKEY hKey, // handle of key to set value for
+ LPCSTR lpValueName, // address of value to set
+ DWORD Reserved, // reserved
+ DWORD dwType, // flag for value type
+ CONST BYTE FAR * lpData, // address of value data
+ DWORD cbData // size of value data
+ );
+
+#endif // _INC_REGPORTE
diff --git a/private/mvdm/wow16/regedit/regresid.h b/private/mvdm/wow16/regedit/regresid.h
new file mode 100644
index 000000000..ee6eb48b9
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regresid.h
@@ -0,0 +1,346 @@
+/*******************************************************************************
+*
+* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
+*
+* TITLE: REGRESID.H
+*
+* VERSION: 4.01
+*
+* AUTHOR: Tracy Sharpe
+*
+* DATE: 05 Mar 1994
+*
+* Resource identifiers for the Registry Editor.
+*
+*******************************************************************************/
+
+#ifndef _INC_REGRESID
+#define _INC_REGRESID
+
+#define HEXEDIT_CLASSNAME "HEX"
+
+//
+//
+//
+
+#define IDD_REGEXPORT 100
+#define IDD_REGPRINT 108
+
+#define IDC_FIRSTREGCOMMDLGID 1280
+#define IDC_RANGEALL 1280
+#define IDC_RANGESELECTEDPATH 1281
+#define IDC_SELECTEDPATH 1282
+#define IDC_EXPORTRANGE 1283
+#define IDC_LASTREGCOMMDLGID 1283
+
+//
+//
+//
+
+#define IDD_EDITSTRINGVALUE 102
+#define IDD_EDITBINARYVALUE 103
+#define IDD_EDITDWORDVALUE 111
+
+#define IDC_VALUENAME 1000
+#define IDC_VALUEDATA 1001
+#define IDC_HEXADECIMAL 1002
+#define IDC_DECIMAL 1003
+
+//
+//
+//
+
+#define IDD_REGCONNECT 104
+
+#define IDC_REMOTENAME 1100
+#define IDC_BROWSE 1101
+
+//
+//
+//
+
+#define IDD_REGPRINTABORT 105
+
+//
+// Dialog box for the Edit-> Find... menu option.
+//
+
+#define IDD_REGFIND 106
+
+#define IDC_FINDWHAT 1150
+#define IDC_WHOLEWORDONLY 1151
+// NOTE: The flags IDC_FOR* must be consecutive.
+#define IDC_FORKEYS 1152
+#define IDC_FORVALUES 1153
+#define IDC_FORDATA 1154
+#define IDC_GROUPBOX 1160
+
+#define IDD_REGDISCONNECT 107
+#define IDC_REMOTELIST 1175
+
+//
+// Dialog box for the find abort.
+//
+
+#define IDD_REGFINDABORT 109
+
+//
+// Dialog box for Import Registry File progress display.
+//
+
+#define IDD_REGPROGRESS 110
+
+#define IDC_FILENAME 100
+#define IDC_PROGRESSBAR 101
+
+//
+// Menu resource identifiers.
+//
+
+#define IDM_REGEDIT 103
+#define IDM_KEY_CONTEXT 104
+#define IDM_VALUE_CONTEXT 105
+#define IDM_VALUELIST_NOITEM_CONTEXT 106
+#define IDM_COMPUTER_CONTEXT 107
+
+//
+// HexEdit context menu identifier and items. The IDKEY_* identifier
+// correspond to the WM_CHAR message that it corresponds to. For example,
+// IDKEY_COPY would send a control-c to the HexEdit_OnChar routine.
+//
+
+#define IDM_HEXEDIT_CONTEXT 108
+
+#define IDKEY_COPY 3
+#define IDKEY_PASTE 22
+#define IDKEY_CUT 24
+#define ID_SELECTALL 0x0400
+
+//
+// Popup menu item identifiers. Used to determine the context menu help
+// string.
+//
+
+#define ID_FIRSTMENUPOPUPITEM 0x0200
+#define ID_LASTMENUPOPUPITEM 0x027F
+
+#define IDMP_REGISTRY 0x0200
+#define IDMP_EDIT 0x0201
+#define IDMP_VIEW 0x0202
+#define IDMP_HELP 0x0203
+#define IDMP_NEW 0x0204
+
+//
+// Main menu items. If any of these items are selected from a context menu,
+// they will be automatically routed to the main window's command handler.
+//
+
+#define ID_FIRSTMAINMENUITEM 0x0280
+#define ID_LASTMAINMENUITEM 0x02FF
+
+// Following are really keyboard accelerators.
+#define ID_CYCLEFOCUS (ID_FIRSTMAINMENUITEM + 0x0000)
+
+// IMPORTANT: Do not change the position of this identifier. If Regedit is
+// already running and Regedit is then invoked through its commandline
+// interface, then the second instance will send a WM_COMMAND message with this
+// identifier to force a refresh.
+#define ID_REFRESH (ID_FIRSTMAINMENUITEM + 0x0008)
+
+#define ID_CONNECT (ID_FIRSTMAINMENUITEM + 0x0011)
+#define ID_IMPORTREGFILE (ID_FIRSTMAINMENUITEM + 0x0012)
+#define ID_EXPORTREGFILE (ID_FIRSTMAINMENUITEM + 0x0013)
+#define ID_PRINT (ID_FIRSTMAINMENUITEM + 0x0014)
+#define ID_EXIT (ID_FIRSTMAINMENUITEM + 0x0015)
+#define ID_FIND (ID_FIRSTMAINMENUITEM + 0x0016)
+#define ID_NEWKEY (ID_FIRSTMAINMENUITEM + 0x0017)
+#define ID_NEWSTRINGVALUE (ID_FIRSTMAINMENUITEM + 0x0018)
+#define ID_NEWBINARYVALUE (ID_FIRSTMAINMENUITEM + 0x0019)
+#define ID_EXECCALC (ID_FIRSTMAINMENUITEM + 0x001A)
+#define ID_ABOUT (ID_FIRSTMAINMENUITEM + 0x001B)
+#define ID_STATUSBAR (ID_FIRSTMAINMENUITEM + 0x001C)
+#define ID_SPLIT (ID_FIRSTMAINMENUITEM + 0x001E)
+#define ID_FINDNEXT (ID_FIRSTMAINMENUITEM + 0x001F)
+#define ID_HELPTOPICS (ID_FIRSTMAINMENUITEM + 0x0020)
+#define ID_NETSEPARATOR (ID_FIRSTMAINMENUITEM + 0x0021)
+#define ID_NEWDWORDVALUE (ID_FIRSTMAINMENUITEM + 0x0022)
+
+//
+// Dual menu items. The routing of these items depends on whether it was
+// selected from the main menu or from a context menu.
+//
+
+#define ID_FIRSTDUALMENUITEM 0x0300
+#define ID_LASTDUALMENUITEM 0x037F
+
+#define ID_DISCONNECT (ID_FIRSTDUALMENUITEM + 0x0000)
+
+//
+// Context menu items. If any of these items are selected from the main menu,
+// they will be automatically routed to the focus pane's command handler.
+//
+
+#define ID_FIRSTCONTEXTMENUITEM 0x0380
+#define ID_LASTCONTEXTMENUITEM 0x03FF
+
+// Following are really keyboard accelerators.
+#define ID_CONTEXTMENU (ID_FIRSTCONTEXTMENUITEM + 0x0000)
+
+#define ID_MODIFY (ID_FIRSTCONTEXTMENUITEM + 0x0010)
+#define ID_DELETE (ID_FIRSTCONTEXTMENUITEM + 0x0011)
+#define ID_RENAME (ID_FIRSTCONTEXTMENUITEM + 0x0012)
+#define ID_TOGGLE (ID_FIRSTCONTEXTMENUITEM + 0x0013)
+#define ID_SENDTOPRINTER (ID_FIRSTCONTEXTMENUITEM + 0x0014)
+
+//
+// String resource identifiers.
+//
+
+#define IDS_REGEDIT 16
+#define IDS_NAMECOLUMNLABEL 17
+#define IDS_DATACOLUMNLABEL 18
+#define IDS_COMPUTER 19
+#define IDS_DEFAULTVALUE 20
+// #define IDS_EMPTYSTRING 21
+#define IDS_EMPTYBINARY 22
+#define IDS_NEWKEYNAMETEMPLATE 23
+#define IDS_NEWVALUENAMETEMPLATE 24
+#define IDS_COLLAPSE 25
+#define IDS_MODIFY 26
+#define IDS_VALUENOTSET 27
+#define IDS_HELPFILENAME 28
+#define IDS_DWORDDATAFORMATSPEC 29
+#define IDS_INVALIDDWORDDATA 30
+
+#define IDS_IMPORTREGFILETITLE 32
+#define IDS_EXPORTREGFILETITLE 33
+#define IDS_REGFILEFILTER 34
+#define IDS_REGFILEDEFEXT 35
+
+#define IDS_REGEDITDISABLED 40
+#define IDS_SEARCHEDTOEND 41
+#define IDS_COMPUTERBROWSETITLE 42
+
+#define IDS_CONFIRMDELKEYTEXT 48
+#define IDS_CONFIRMDELKEYTITLE 49
+#define IDS_CONFIRMDELVALMULTITEXT 50
+#define IDS_CONFIRMDELVALTITLE 51
+#define IDS_CONFIRMDELVALTEXT 52
+
+#define IDS_RENAMEKEYERRORTITLE 64
+#define IDS_RENAMEPREFIX 65 // Reserved
+#define IDS_RENAMEKEYOTHERERROR 66
+#define IDS_RENAMEKEYTOOLONG 67
+#define IDS_RENAMEKEYEXISTS 68
+#define IDS_RENAMEKEYBADCHARS 69
+
+#define IDS_RENAMEVALERRORTITLE 72
+#define IDS_RENAMEVALOTHERERROR 73
+#define IDS_RENAMEVALEXISTS 74
+
+#define IDS_DELETEKEYERRORTITLE 80
+#define IDS_DELETEPREFIX 81 // Reserved
+#define IDS_DELETEKEYDELETEFAILED 82
+
+#define IDS_DELETEVALERRORTITLE 88
+#define IDS_DELETEVALDELETEFAILED 89
+
+#define IDS_OPENKEYERRORTITLE 96
+#define IDS_OPENKEYCANNOTOPEN 97
+
+#define IDS_EDITVALERRORTITLE 112
+#define IDS_EDITPREFIX 113 // Reserved
+#define IDS_EDITVALCANNOTREAD 114
+#define IDS_EDITVALCANNOTWRITE 115
+
+#define IDS_IMPFILEERRSUCCESS 128
+#define IDS_IMPFILEERRFILEOPEN 129
+#define IDS_IMPFILEERRFILEREAD 130
+#define IDS_IMPFILEERRREGOPEN 131
+#define IDS_IMPFILEERRREGSET 132
+#define IDS_IMPFILEERRFORMATBAD 133
+
+#define IDS_EXPFILEERRSUCCESS 136
+#define IDS_EXPFILEERRBADREGPATH 137
+#define IDS_EXPFILEERRFILEOPEN 138
+#define IDS_EXPFILEERRREGOPEN 139
+#define IDS_EXPFILEERRREGENUM 140
+#define IDS_EXPFILEERRFILEWRITE 141
+
+#define IDS_PRINTERRNOMEMORY 144
+#define IDS_PRINTERRPRINTER 145
+
+#define IDS_ERRINVALIDREGPATH 148
+
+#define IDS_CONNECTERRORTITLE 152
+#define IDS_CONNECTNOTLOCAL 153
+#define IDS_CONNECTBADNAME 154
+#define IDS_CONNECTROOTFAILED 155
+#define IDS_CONNECTACCESSDENIED 156
+
+#define IDS_NEWKEYERRORTITLE 160
+#define IDS_NEWKEYPARENTOPENFAILED 161
+#define IDS_NEWKEYCANNOTCREATE 162
+#define IDS_NEWKEYNOUNIQUE 163
+
+#define IDS_NEWVALUEERRORTITLE 168
+#define IDS_NEWVALUECANNOTCREATE 169
+#define IDS_NEWVALUENOUNIQUE 170
+
+// The range IDS_FIRSTMENUPOPUPITEM through IDS_LASTMENUPOPUPITEM is reserved
+// for context menu help. This must match up with ID_FIRSTMENUPOPUPITEM
+// through ID_LASTMENUPOPUPITEM.
+#define IDS_FIRSTMENUPOPUPITEM ID_FIRSTMENUPOPUPITEM
+#define IDS_LASTMENUPOPUPITEM ID_LASTMENUPOPUPITEM
+
+// The range IDS_FIRSTMAINMENUITEM through IDS_LASTMAINMENUITEM is reserved for
+// context menu help. This must match up with ID_FIRSTMAINMENUITEM through
+// ID_LASTMAINMENUITEM.
+
+#define IDS_FIRSTMAINMENUITEM ID_FIRSTMAINMENUITEM
+#define IDS_LASTMAINMENUITEM ID_LASTMAINMENUITEM
+
+// The range IDS_FIRSTCONTEXTMENUITEM through IDS_LASTCONTEXTMENUITEM is
+// reserved for context menu help. This must match up with
+// ID_FIRSTCONTEXTMENUITEM through ID_LASTCONTEXTMENUITEM.
+
+#define IDS_FIRSTCONTEXTMENUITEM ID_FIRSTCONTEXTMENUITEM
+#define IDS_LASTCONTEXTMENUITEM ID_LASTCONTEXTMENUITEM
+
+// The range IDS_FIRSTDUALMENUITEM through IDS_LASTDUALMENUITEM is reserved for
+// context menu help. This must match up with ID_FIRSTDUALMENUITEM through
+// ID_LASTDUALMENUITEM.
+#define IDS_FIRSTDUALMENUITEM ID_FIRSTDUALMENUITEM
+#define IDS_LASTDUALMENUITEM ID_LASTDUALMENUITEM
+
+//
+// Icon resource identifiers.
+//
+
+#define IDI_REGEDIT 100
+#define IDI_REGEDDOC 101
+#define IDI_REGFIND 102
+
+#define IDI_FIRSTIMAGE 201
+// #define IDI_DIAMOND 200
+#define IDI_COMPUTER 201
+#define IDI_REMOTE 202
+#define IDI_FOLDER 203
+#define IDI_FOLDEROPEN 204
+#define IDI_STRING 205
+#define IDI_BINARY 206
+#define IDI_LASTIMAGE IDI_BINARY
+
+//
+// Cursor resource identifiers.
+//
+
+#define IDC_SPLIT 100
+
+//
+// Accelerator resource identifiers.
+//
+
+#define IDACCEL_REGEDIT 100
+
+#endif // _INC_REGRESID
diff --git a/private/mvdm/wow16/regedit/regthunk.c b/private/mvdm/wow16/regedit/regthunk.c
new file mode 100644
index 000000000..fb2601d25
--- /dev/null
+++ b/private/mvdm/wow16/regedit/regthunk.c
@@ -0,0 +1,44 @@
+/*
+ RegThunk.c
+
+ Created by Lee Hart, 4/27/95
+
+ Purpose: Generic Thunks to Win32 Registry APIs that are not
+ supported in Win16
+
+*/
+
+#include <windows.h>
+#include <shellapi.h>
+#include <wownt16.h>
+
+#ifndef CHAR
+#define CHAR char
+#endif // ifndef CHAR
+
+#include "regporte.h"
+
+LONG RegSetValueEx(
+ HKEY hKey, // handle of key to set value for
+ LPCSTR lpValueName, // address of value to set
+ DWORD Reserved, // reserved
+ DWORD dwType, // flag for value type
+ CONST BYTE FAR * lpData, // address of value data
+ DWORD cbData // size of value data
+ )
+{
+ DWORD hAdvApi32=LoadLibraryEx32W("ADVAPI32.DLL", NULL, 0);
+ DWORD pFn;
+ DWORD dwResult = ERROR_ACCESS_DENIED; //random error if fail
+
+ if ((DWORD)0!=hAdvApi32)
+ {
+ pFn=GetProcAddress32W(hAdvApi32, "RegSetValueExA"); // call ANSI version
+ if ((DWORD)0!=pFn)
+ {
+ dwResult=CallProcEx32W( CPEX_DEST_STDCALL | 6, 0x12, pFn, hKey, lpValueName, Reserved, dwType, lpData, cbData );
+ }
+ }
+ if (hAdvApi32) FreeLibrary32W(hAdvApi32);
+ return(dwResult);
+}
diff --git a/private/mvdm/wow16/regedit/sdbase.c b/private/mvdm/wow16/regedit/sdbase.c
new file mode 100644
index 000000000..e1d0b2899
--- /dev/null
+++ b/private/mvdm/wow16/regedit/sdbase.c
@@ -0,0 +1,377 @@
+#include <windows.h>
+#include "SDKRegEd.h"
+
+extern HWND hWndIds;
+extern HANDLE hPars;
+
+extern char szHkeyClassesRoot[];
+
+DWORD NEAR PASCAL GetTreeMarkers(int nId)
+{
+ int *pPars;
+ int nKeys, nLevel, nTemp;
+ DWORD dwMarkers, thisMarker;
+ int i, j;
+
+ nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
+ pPars = (WORD *)LocalLock(hPars);
+
+ for(i=nId, nLevel= -1; i>=0; i=pPars[i], ++nLevel)
+ /* do nothing */ ;
+
+ dwMarkers = 0L;
+ for(thisMarker=1; nLevel>0; thisMarker<<=1, --nLevel) {
+ for(i=nId, nTemp=nLevel; nTemp>0; i=pPars[i], --nTemp)
+ /* do nothing */ ;
+
+ for(j=nId+1; j<nKeys; ++j) {
+ if(pPars[j] == i) {
+ dwMarkers |= thisMarker;
+ break;
+ }
+ }
+ nKeys = j;
+ }
+
+ LocalUnlock(hPars);
+ return(dwMarkers);
+}
+
+int NEAR PASCAL GetLevel(int nId)
+{
+ int nLevel;
+ int *pPars;
+
+ if(!hPars || !(pPars=(WORD *)LocalLock(hPars)))
+ return(0);
+ for(nLevel= -1; nId>=0; nId=pPars[nId], ++nLevel)
+ /* do nothing */ ;
+ LocalUnlock(hPars);
+ return(nLevel);
+}
+
+HANDLE NEAR PASCAL MyGetPartialPath(int index, int nParent)
+{
+ BOOL bFirst;
+ HANDLE hPath;
+ PSTR pPath;
+ int nLevel, nTemp, i;
+ DWORD dwLen;
+ WORD wLen = 2;
+ int *pPars;
+
+ if(!hPars || !(pPars=(WORD *)LocalLock(hPars)))
+ goto Error1;
+
+ for(i=index, nLevel=0; i!=nParent; i=pPars[i], ++nLevel) {
+ if((dwLen=SendMessage(hWndIds, LB_GETTEXTLEN, i, 0L)) == LB_ERR)
+ goto Error2;
+ wLen += LOWORD(dwLen) + 1;
+ }
+
+ if(!(hPath=LocalAlloc(LMEM_MOVEABLE, wLen)))
+ goto Error2;
+ if(!(pPath=LocalLock(hPath)))
+ goto Error3;
+
+ if(nParent == 0)
+ *pPath++ = '\\';
+ *pPath = '\0';
+ for(--nLevel, bFirst=TRUE; nLevel>=0; --nLevel) {
+ for(i=index, nTemp=nLevel; nTemp>0; i=pPars[i], --nTemp)
+ /* do nothing */ ;
+
+ if(bFirst)
+ bFirst = FALSE;
+ else
+ *pPath++ = '\\';
+ dwLen = SendMessage(hWndIds, LB_GETTEXT, i, (DWORD)((LPSTR)pPath));
+ pPath += LOWORD(dwLen);
+ }
+
+ LocalUnlock(hPath);
+ goto Error2;
+
+Error3:
+ LocalFree(hPath);
+ hPath = NULL;
+Error2:
+ LocalUnlock(hPars);
+Error1:
+ return(hPath);
+}
+
+HANDLE NEAR PASCAL MyGetPath(int i)
+{
+ return(MyGetPartialPath(i, 0));
+}
+
+int NEAR PASCAL FindKey(PSTR pKey)
+{
+ HANDLE hPath;
+ PSTR pLast, pTemp;
+ int nLast, index, nCmp;
+
+ pLast = pKey;
+ if(*(pKey+1)) {
+ for(pTemp=pKey; *pTemp; pTemp=OFFSET(AnsiNext(pTemp))) {
+ if(*pTemp == '\\') {
+ pLast = pTemp + 1;
+ }
+ }
+ }
+
+ nLast = index = -1;
+ do {
+ if((index=(int)SendMessage(hWndIds, LB_FINDSTRING, index,
+ (DWORD)((LPSTR)pLast)))==LB_ERR ||
+ index<=nLast || !(hPath=MyGetPath(index)))
+ return(-1);
+
+ nLast = index;
+ nCmp = lstrcmpi(pKey, LocalLock(hPath));
+ LocalUnlock(hPath);
+ LocalFree(hPath);
+ } while(nCmp) ;
+
+ return(index);
+}
+
+int NEAR PASCAL FindLastExistingKey(int nParent, PSTR pPath)
+{
+ HANDLE hPath, hTemp;
+ PSTR pEnd, pLast, pFullPath;
+ int nFound, nResult = -1;
+ WORD wLen;
+
+ if(!(hPath=MyGetPath(nParent)))
+ goto Error1;
+ wLen = lstrlen(LocalLock(hPath));
+ LocalUnlock(hPath);
+ if(!(hTemp=LocalReAlloc(hPath, wLen+lstrlen(pPath)+2, LMEM_MOVEABLE)))
+ goto Error2;
+ if(!(pFullPath=LocalLock(hPath=hTemp)))
+ goto Error2;
+
+ pEnd = pFullPath + wLen;
+ if(nParent) {
+ *pEnd++ = '\\';
+ *pEnd = '\0';
+ }
+ lstrcpy(pEnd, pPath);
+
+ for(pLast=pEnd; *pEnd; pEnd=OFFSET(AnsiNext(pEnd))) {
+ if(*pEnd == '\\') {
+ *pEnd = '\0';
+ nFound = FindKey(pFullPath);
+ *pEnd = '\\';
+ if(nFound == -1)
+ goto FoundLast;
+
+ pLast = pEnd + 1;
+ nParent = nFound;
+ }
+ }
+
+/* If we got to the end of the string, try the whole thing */
+ if((nFound=FindKey(pFullPath)) >= 0) {
+/* The key already exists */
+ nParent = nFound;
+ pLast = pEnd;
+ }
+FoundLast:
+
+ nResult = nParent;
+ lstrcpy(pPath, pLast);
+
+ LocalUnlock(hPath);
+Error2:
+ LocalFree(hPath);
+Error1:
+ return(nResult);
+}
+
+#define BIGBLOCK 1024L
+
+static WORD NEAR PASCAL BufferedWrite(int hFile, PSTR pWrite, WORD wBytes)
+{
+ static HANDLE hBuffer = NULL;
+ static WORD wOffset;
+ static DWORD dwSize;
+
+ LPSTR lpBuffer;
+
+/* wBytes = 0 means to write out the buffer and clean up */
+ if(!wBytes) {
+ WORD wErrMsg = NULL;
+
+ if(hBuffer) {
+ if(lpBuffer=GlobalLock(hBuffer)) {
+ if(_lwrite(hFile, lpBuffer, wOffset) != wOffset)
+ wErrMsg = IDS_CANTWRITEFILE;
+ GlobalUnlock(hBuffer);
+ } else
+ wErrMsg = IDS_OUTOFMEMORY;
+
+ GlobalFree(hBuffer);
+ hBuffer = NULL;
+ }
+ return(wErrMsg);
+ }
+
+/* hBuffer = NULL means we need to allocate a buffer */
+ if(!hBuffer) {
+ if(!(hBuffer=GlobalAlloc(GMEM_MOVEABLE, dwSize=BIGBLOCK)))
+ return(IDS_OUTOFMEMORY);
+ wOffset = 0;
+ }
+
+/* If the total is > 64K, flush the buffer */
+ if((DWORD)wBytes+(DWORD)wOffset > 0xffffL) {
+ if(lpBuffer=GlobalLock(hBuffer)) {
+ WORD wTemp;
+
+ wTemp = _lwrite(hFile, lpBuffer, wOffset);
+ GlobalUnlock(hBuffer);
+ if(wTemp != wOffset)
+ return(IDS_CANTWRITEFILE);
+ } else
+ return(IDS_OUTOFMEMORY);
+ wOffset = 0;
+ }
+
+/* If the total is greater than the size we have allocated, try to
+ * increase the buffer size to fit. If we cannot, then flush the
+ * buffer, and if wBytes is still too big, then write it straight to
+ * disk.
+ */
+ if((DWORD)(wBytes+wOffset) > dwSize) {
+ HANDLE hTemp;
+ DWORD dwTemp;
+
+ dwTemp = (((wBytes+wOffset)/BIGBLOCK) + 1) * BIGBLOCK;
+ if(hTemp=GlobalReAlloc(hBuffer, dwTemp, GMEM_MOVEABLE)) {
+ hBuffer = hTemp;
+ dwSize = dwTemp;
+ } else {
+ WORD wTemp;
+
+ if(wOffset) {
+ if(!(lpBuffer=GlobalLock(hBuffer)))
+ return(IDS_OUTOFMEMORY);
+ wTemp = _lwrite(hFile, lpBuffer, wOffset);
+ wOffset = 0;
+ GlobalUnlock(hBuffer);
+ if(wTemp != wOffset)
+ return(IDS_CANTWRITEFILE);
+ }
+ if(wBytes > LOWORD(dwSize)) {
+ if(_lwrite(hFile, pWrite, wBytes) == wBytes)
+ return(NULL);
+ else
+ return(IDS_CANTWRITEFILE);
+ }
+ }
+ }
+
+/* If we got to here, then there is room in the buffer */
+ if(!(lpBuffer=GlobalLock(hBuffer)))
+ return(IDS_OUTOFMEMORY);
+ RepeatMove(lpBuffer+wOffset, pWrite, wBytes);
+ wOffset += wBytes;
+ GlobalUnlock(hBuffer);
+
+ return(NULL);
+}
+
+WORD NEAR PASCAL DoWriteFile(int nId, HANDLE hFileName)
+{
+ HANDLE hHeader;
+ PSTR pHeader;
+ WORD wErrMsg;
+ int *pPars;
+ LPSTR lpFileName;
+ int hFile, nKeys, i, j;
+ OFSTRUCT of;
+ WORD wRootLen = lstrlen(szHkeyClassesRoot);
+
+/* Open the file */
+ wErrMsg = IDS_CANTOPENFILE;
+ lpFileName = GlobalLock(hFileName);
+ if((hFile=OpenFile(lpFileName, &of, OF_CREATE)) == -1)
+ goto Error1;
+
+ pPars = (WORD *)LocalLock(hPars);
+ nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
+
+/* Find the first key that does not have nId in its parent chain */
+ for(i=nId+1; i<nKeys; ++i) {
+ for(j=pPars[i]; j>=0 && j!=nId; j=pPars[j])
+ /* do nothing */ ;
+ if(j != nId)
+ break;
+ }
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hHeader=MyLoadString(IDS_REGHEADER, NULL, LMEM_MOVEABLE)))
+ goto Error2;
+ pHeader = LocalLock(hHeader);
+ wErrMsg = BufferedWrite(hFile, pHeader, lstrlen(pHeader));
+ LocalUnlock(hHeader);
+ LocalFree(hHeader);
+ if(wErrMsg || (wErrMsg=BufferedWrite(hFile, "\r\n", 2)))
+ goto Error2;
+
+/* Write the strings */
+ for(j=nId, wErrMsg=NULL; j<i && !wErrMsg; ++j) {
+ HANDLE hPath, hValue;
+ PSTR pPath, pValue;
+
+/* Get the path and the value */
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hPath=MyGetPath(j)))
+ goto Error2;
+ pPath = LocalLock(hPath);
+ if(MyGetValue(j, &hValue))
+ goto Error3;
+ pValue = LocalLock(hValue);
+
+/* We don't need to write this key if it has subkeys but no value */
+ wErrMsg = NULL;
+ if(!(*pValue) && pPars[j+1]==j)
+ goto Error4;
+
+/* Write HKEY_CLASSES_ROOT<path> = <value>\r\n */
+ if((wErrMsg=BufferedWrite(hFile, szHkeyClassesRoot, wRootLen)) ||
+ (wErrMsg=BufferedWrite(hFile, pPath+1, lstrlen(pPath+1))) ||
+ (wErrMsg=BufferedWrite(hFile, " = ", 3)))
+ goto Error4;
+
+/* Don't write the value if it is of 0 length */
+ if(*pValue && (wErrMsg=BufferedWrite(hFile, pValue, lstrlen(pValue))))
+ goto Error4;
+ wErrMsg = BufferedWrite(hFile, "\r\n", 2);
+
+Error4:
+ LocalUnlock(hValue);
+ LocalFree(hValue);
+Error3:
+ LocalUnlock(hPath);
+ LocalFree(hPath);
+Error2:
+ ;
+ }
+
+/* One last write with 0 length to clean up */
+ wErrMsg = BufferedWrite(hFile, NULL, 0);
+ LocalUnlock(hPars);
+ _lclose(hFile);
+
+/* Delete the file if there was an error */
+ if(wErrMsg)
+ OpenFile(lpFileName, &of, OF_DELETE);
+Error1:
+ GlobalUnlock(hFileName);
+ return(wErrMsg);
+}
+
diff --git a/private/mvdm/wow16/regedit/sdkreged.c b/private/mvdm/wow16/regedit/sdkreged.c
new file mode 100644
index 000000000..a7d839a25
--- /dev/null
+++ b/private/mvdm/wow16/regedit/sdkreged.c
@@ -0,0 +1,672 @@
+#define WIN31
+#include <windows.h>
+#include "SDKRegEd.h"
+
+#define RONSPACE 3
+#define misParam ((MEASUREITEMSTRUCT FAR *)lParam)
+#define disParam ((DRAWITEMSTRUCT FAR *)lParam)
+
+extern char szNull[];
+extern char szSDKRegEd[];
+
+static char szEquals[] = " = ";
+
+static WORD wKey=0;
+static HANDLE hSearchString = NULL;
+
+static BOOL bDoUpdate = TRUE;
+
+static HWND hStat1, hEdit1, hEdit2;
+
+extern BOOL bChangesMade;
+extern HWND hWndIds;
+extern HANDLE hAcc;
+extern BOOL fOpenError;
+
+
+VOID NEAR PASCAL MySetSel(HWND hWndList, int index)
+{
+ if (!bDoUpdate)
+ return;
+
+ if(index == -2)
+ index = (int)SendMessage(hWndList, LB_GETCURSEL, 0, 0L);
+ else
+ SendMessage(hWndList, LB_SETCURSEL, index, 0L);
+
+ SendMessage(GetParent(hWndList), WM_COMMAND, GetWindowWord(hWndList, GWW_ID),
+ MAKELONG(hWndList, LBN_SELCHANGE));
+}
+
+int FAR PASCAL SDKMainWndDlg(HWND hDlg, WORD message, WORD wParam, DWORD lParam)
+{
+ static int xSpace;
+ static int nTop, nLeft, nValHgt, nPthHgt;
+
+ switch(message) {
+ case WM_COMMAND:
+ switch(wParam) {
+ case IDCANCEL:
+ SendDlgItemMessage(hDlg, ID_VALUE, EM_SETMODIFY, 0, 0L);
+ goto NewSelection;
+
+ case ID_VALUE:
+ if (HIWORD(lParam) == EN_KILLFOCUS) {
+ hAcc = LoadAccelerators(hInstance, szSDKRegEd);
+ goto NewSelection;
+ } else if (HIWORD(lParam) == EN_SETFOCUS)
+ hAcc = LoadAccelerators(hInstance, "SDKRegEdVal");
+ break;
+
+ case ID_IDLIST:
+ if(HIWORD(lParam) == LBN_SELCHANGE) {
+ HANDLE hTmp;
+ HWND hWndTmp;
+ WORD wErrMsg, wNewKey;
+
+NewSelection:
+ wNewKey = (WORD)SendMessage(hWndIds, LB_GETCURSEL, 0, 0L);
+
+ hWndTmp = GetDlgItem(hDlg, ID_VALUE);
+ if (SendMessage(hWndTmp, EM_GETMODIFY, 0, 0L)) {
+ SendMessage(hWndTmp, EM_SETMODIFY, 0, 0L);
+ bDoUpdate = FALSE;
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(hEdit1 = GetEditString(hWndTmp)) {
+ wErrMsg = GetErrMsg((WORD)SDKSetValue(-wKey, szNull,
+ LocalLock(hEdit1)));
+ LocalUnlock(hEdit1);
+ }
+
+ if(wErrMsg) {
+ MyMessageBox(hWndMain, wErrMsg, MB_OK, 0);
+ break;
+ }
+ bDoUpdate = TRUE;
+
+ InvalidateRect(hWndIds, NULL, TRUE);
+ }
+
+ if((wKey=wNewKey)!=(WORD)SendMessage(hWndIds, LB_GETCURSEL, 0, 0L))
+ SendMessage(hWndIds, LB_SETCURSEL, wKey, 0L);
+
+ if(!MyGetValue(wKey, &hTmp)) {
+ SendMessage(hWndTmp, WM_SETTEXT, 0,
+ (DWORD)((LPSTR)LocalLock(hTmp)));
+ LocalUnlock(hTmp);
+ LocalFree(hTmp);
+ } else
+ SendMessage(hWndTmp, WM_SETTEXT, 0, (DWORD)((LPSTR)szNull));
+
+ hWndTmp = GetDlgItem(hDlg, ID_FULLPATH);
+ if(hTmp=MyGetPath(wKey)) {
+ SendMessage(hWndTmp, WM_SETTEXT, 0,
+ (DWORD)((LPSTR)LocalLock(hTmp)));
+ LocalUnlock(hTmp);
+ LocalFree(hTmp);
+ } else
+ SendMessage(hWndTmp, WM_SETTEXT, 0, (DWORD)((LPSTR)szNull));
+ }
+ break;
+
+ default:
+ break;
+ }
+ return(FALSE);
+ break;
+
+ case WM_SIZE:
+ {
+ HWND hWndTmp;
+ RECT rcList, rcWnd;
+ int hgtWnd, hgt;
+
+ hgtWnd = HIWORD(lParam) + 1;
+ hgt = hgtWnd - nTop;
+
+ SetWindowPos(hWndIds, NULL, -1, nTop, LOWORD(lParam)+2, hgt,
+ SWP_NOZORDER);
+ GetWindowRect(hWndIds, &rcList);
+ ScreenToClient(hDlg, (POINT *)(&rcList) + 1);
+ if(rcList.bottom != hgtWnd) {
+ GetWindowRect(hDlg, &rcWnd);
+ SetWindowPos(hDlg, NULL, 0, 0, rcWnd.right-rcWnd.left,
+ rcWnd.bottom-rcWnd.top-hgtWnd+rcList.bottom,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ hWndTmp = GetDlgItem(hDlg, ID_VALUE);
+ SetWindowPos(hWndTmp, NULL, 0, 0, LOWORD(lParam)-nLeft,
+ nValHgt, SWP_NOMOVE | SWP_NOZORDER);
+ InvalidateRect(hWndTmp, NULL, TRUE);
+
+ hWndTmp = GetDlgItem(hDlg, ID_FULLPATH);
+ SetWindowPos(hWndTmp, NULL, 0, 0, LOWORD(lParam)-nLeft,
+ nPthHgt, SWP_NOMOVE | SWP_NOZORDER);
+ InvalidateRect(hWndTmp, NULL, TRUE);
+ break;
+ }
+
+ case WM_INITDIALOG:
+ {
+ RECT rcTemp;
+ WORD wErrMsg;
+
+ hWndIds = GetDlgItem(hDlg, ID_IDLIST);
+
+ SendMessage(hWndIds, WM_SETREDRAW, 0, 0L);
+ if(wErrMsg=MyResetIdList(hDlg)) {
+ MyMessageBox(hWndMain, wErrMsg, MB_OK, 0);
+ fOpenError = TRUE;
+ }
+ SendMessage(hWndIds, WM_SETREDRAW, 1, 0L);
+ InvalidateRect(hWndIds, NULL, TRUE);
+
+ GetWindowRect(hWndIds, &rcTemp);
+ ScreenToClient(hDlg, (POINT FAR *)&rcTemp);
+ nTop = rcTemp.top;
+
+ GetWindowRect(GetDlgItem(hDlg, ID_VALUE), &rcTemp);
+ nValHgt = rcTemp.bottom - rcTemp.top;
+ GetWindowRect(GetDlgItem(hDlg, ID_FULLPATH), &rcTemp);
+ nPthHgt = rcTemp.bottom - rcTemp.top;
+ ScreenToClient(hDlg, (POINT FAR *)&rcTemp);
+ nLeft = rcTemp.left;
+ break;
+ }
+
+ case WM_MEASUREITEM:
+ {
+ HDC hDC;
+
+ hDC = GetDC(hWndIds);
+ misParam->itemHeight = HIWORD(GetTextExtent(hDC, "Ag", 2));
+ xSpace = LOWORD(GetTextExtent(hDC, " ", 1));
+ ReleaseDC(hWndIds, hDC);
+ break;
+ }
+
+ case WM_DRAWITEM:
+ {
+ HDC hDC;
+ HANDLE hKeyName, hValue;
+ PSTR pKeyName;
+ WORD wSize;
+ int theLevel;
+ RECT rcTextExt;
+ DWORD dwMarkers, thisMarker;
+ DWORD dwRGBBkGnd, dwRGBText;
+
+ hDC = disParam->hDC;
+
+ if(!(hKeyName=GetListboxString(disParam->hwndItem, disParam->itemID)))
+ break;
+ pKeyName = LocalLock(hKeyName);
+ wSize = lstrlen(pKeyName);
+
+ if(!MyGetValue(disParam->itemID, &hValue)) {
+ PSTR pValue;
+ HANDLE hTemp;
+ WORD wTemp;
+
+ if(*(pValue = LocalLock(hValue))) {
+ LocalUnlock(hKeyName);
+ wTemp = wSize + sizeof(szEquals) - 1 + lstrlen(pValue);
+ if(hTemp=LocalReAlloc(hKeyName, wTemp+1, LMEM_MOVEABLE)) {
+ hKeyName = hTemp;
+ pKeyName = LocalLock(hKeyName);
+ lstrcat(pKeyName, szEquals);
+ lstrcat(pKeyName, pValue);
+ wSize = wTemp;
+ } else {
+ pKeyName = LocalLock(hKeyName);
+ }
+ }
+
+ LocalUnlock(hValue);
+ LocalFree(hValue);
+ }
+
+ theLevel = GetLevel(disParam->itemID);
+
+ rcTextExt.left = disParam->rcItem.left + RONSPACE*theLevel*xSpace;
+ rcTextExt.top = disParam->rcItem.top;
+ rcTextExt.right = rcTextExt.left + LOWORD(GetTextExtent(hDC,
+ pKeyName, wSize)) + 2*xSpace;
+ rcTextExt.bottom = disParam->rcItem.bottom;
+
+ if(disParam->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
+ if(disParam->itemID>0 && (disParam->itemAction&ODA_DRAWENTIRE)) {
+ HPEN hPen, hOldPen;
+ int theLeft, theMiddle;
+
+ if(theLevel <= 32)
+ dwMarkers = GetTreeMarkers(disParam->itemID);
+ else
+ dwMarkers = 0;
+
+ --theLevel;
+ theLeft = disParam->rcItem.left + RONSPACE*theLevel*xSpace + xSpace;
+ theMiddle = (rcTextExt.top+rcTextExt.bottom)/2;
+ thisMarker = 1L << (LONG)theLevel;
+
+ if(hPen=CreatePen(PS_SOLID, 1, GetTextColor(hDC)))
+ hOldPen = SelectObject(hDC, hPen);
+
+ MoveTo(hDC, theLeft, theMiddle);
+ LineTo(hDC, theLeft+(RONSPACE-1)*xSpace, theMiddle);
+ MoveTo(hDC, theLeft, rcTextExt.top);
+ LineTo(hDC, theLeft,
+ (dwMarkers&thisMarker) ? rcTextExt.bottom : theMiddle);
+ goto NextLevel;
+
+ for( ; theLevel>=0;
+ --theLevel, thisMarker>>=1, theLeft-=RONSPACE*xSpace) {
+ if(dwMarkers&thisMarker) {
+ MoveTo(hDC, theLeft, rcTextExt.top);
+ LineTo(hDC, theLeft, rcTextExt.bottom);
+ }
+NextLevel:
+ ;
+ }
+
+ if(hPen) {
+ if(hOldPen)
+ SelectObject(hDC, hOldPen);
+ DeleteObject(hPen);
+ }
+ }
+
+ if(disParam->itemState & ODS_SELECTED) {
+ dwRGBBkGnd = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
+ dwRGBText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+
+ ExtTextOut(hDC, rcTextExt.left+xSpace, rcTextExt.top+1,
+ ETO_CLIPPED | ETO_OPAQUE, &rcTextExt, pKeyName, wSize, 0L);
+
+ if(disParam->itemState & ODS_SELECTED) {
+ SetBkColor(hDC, dwRGBBkGnd);
+ SetTextColor(hDC, dwRGBText);
+ }
+
+ if(disParam->itemState & ODS_FOCUS)
+ disParam->itemAction |= ODA_FOCUS;
+ }
+
+ if(disParam->itemAction & ODA_FOCUS)
+ DrawFocusRect(disParam->hDC, &rcTextExt);
+
+ LocalUnlock(hKeyName);
+ LocalFree(hKeyName);
+ break;
+ }
+
+ default:
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+VOID NEAR _fastcall FillDlgItem(HWND hDlg, WORD wId, HANDLE hTemp)
+{
+ if(hTemp) {
+ SendDlgItemMessage(hDlg, wId, WM_SETTEXT, 0,
+ (DWORD)((LPSTR)LocalLock(hTemp)));
+ LocalUnlock(hTemp);
+ LocalFree(hTemp);
+ }
+}
+
+
+int FAR PASCAL GetKeyProc(HWND hDlg, WORD message, WORD wParam, DWORD lParam)
+{
+ switch(message) {
+ case WM_ACTIVATE:
+ if(wParam)
+ hWndHelp = hDlg;
+ return(FALSE);
+
+ case WM_COMMAND:
+ switch(wParam) {
+ case IDOK:
+ {
+ HWND hWndEdit2;
+
+ if(!(hEdit1=GetEditString(GetDlgItem(hDlg, ID_EDIT1))))
+ goto Error1;
+ if((hWndEdit2=GetDlgItem(hDlg, ID_EDIT2)) &&
+ !(hEdit2 = GetEditString(hWndEdit2)))
+ goto Error2;
+ }
+
+ case IDCANCEL:
+ EndDialog(hDlg, wParam);
+ break;
+
+Error2:
+ LocalFree(hEdit1);
+Error1:
+ MyMessageBox(hDlg, IDS_OUTOFMEMORY, MB_OK, 0);
+ break;
+
+ case ID_HELP:
+ if(GetParent(LOWORD(lParam)) != hDlg)
+ break;
+ case ID_HELPBUTTON:
+ MyHelp(hDlg, HELP_CONTEXT, wHelpId);
+ break;
+ }
+ break;
+
+ case WM_INITDIALOG:
+ FillDlgItem(hDlg, ID_STAT1, hStat1);
+ FillDlgItem(hDlg, ID_EDIT1, hEdit1);
+ FillDlgItem(hDlg, ID_EDIT2, hEdit2);
+
+ return(TRUE);
+
+ default:
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+long FAR PASCAL SDKMainWnd(HWND hWnd, WORD message, WORD wParam, LONG lParam)
+{
+ HCURSOR oldCursor;
+
+ switch(message) {
+ case WM_ACTIVATE:
+ if(wParam)
+ break;
+ goto DoDefault;
+
+ case WM_CREATE:
+ {
+ hWndMain = hWnd;
+ if(!(lpMainWndDlg=MakeProcInstance(SDKMainWndDlg, hInstance)))
+ goto Error1_1;
+ if(!(hWndDlg=CreateDialog(hInstance, MAKEINTRESOURCE(SDKMAINWND), hWnd,
+ lpMainWndDlg)))
+ goto Error1_1;
+
+ ShowWindow(hWndDlg, SW_SHOW);
+ goto DoDefault;
+ }
+
+Error1_1:
+ /* BUG: There should be a MessageBox here
+ */
+ DestroyWindow(hWnd);
+ break;
+
+ /* We need to return 1 if it is OK to close, 0 otherwise
+ */
+ case WM_CLOSE:
+ case WM_QUERYENDSESSION:
+ {
+ MySetSel(hWndIds, -2);
+
+ if(bChangesMade) {
+ int nReturn;
+
+ nReturn = MyMessageBox(hWnd, IDS_SAVECHANGES, MB_YESNOCANCEL, 0);
+ if(nReturn == IDYES) {
+ if(!SendMessage(hWnd, WM_COMMAND, ID_SAVE, 0L))
+ break;
+ } else if(nReturn == IDCANCEL)
+ break;
+ }
+ return(1L);
+ }
+
+ case WM_DROPFILES:
+ goto DoMergeFile;
+
+ case WM_COMMAND:
+ oldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
+ switch(wParam) {
+ case ID_MODIFY:
+ SetFocus(GetDlgItem(hWndDlg, ID_IDLIST));
+ break;
+
+ case ID_EDITVAL:
+ SetFocus(GetDlgItem(hWndDlg, ID_VALUE));
+ break;
+
+ case ID_SAVE:
+ {
+ WORD wErrMsg;
+
+ MySetSel(hWndIds, -2);
+
+ if(wErrMsg=MySaveChanges()) {
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ break;
+ }
+
+ /* Now we reset our local version of the database to make sure
+ * we are all talking about the same thing
+ */
+ PostMessage(hWnd, WM_COMMAND, ID_DORESTORE, 0L);
+ return(1L);
+ }
+
+ case ID_RESTORE:
+ if(MyMessageBox(hWnd, IDS_SURERESTORE, MB_OKCANCEL, 0)
+ != IDOK)
+ break;
+
+ /* Fall through */
+ case ID_DORESTORE:
+ {
+ WORD wErrMsg;
+
+ SendMessage(hWnd, WM_ACTIVATEAPP, 0, 0L);
+ SendMessage(hWndIds, WM_SETREDRAW, 0, 0L);
+ if(wErrMsg=MyResetIdList(hWndDlg)) {
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ PostMessage(hWnd, WM_COMMAND, ID_EXIT, 0L);
+ fOpenError = TRUE;
+ }
+ SendMessage(hWndIds, WM_SETREDRAW, 1, 0L);
+ InvalidateRect(hWndIds, NULL, TRUE);
+ SendMessage(hWnd, WM_ACTIVATEAPP, 1, 0L);
+ break;
+ }
+
+ case ID_MERGEFILE:
+DoMergeFile:
+ MySetSel(hWndIds, -2);
+ SendMessage(hWndIds, WM_SETREDRAW, 0, 0L);
+ break;
+
+ case ID_FINISHMERGE:
+ SendMessage(hWndIds, WM_SETREDRAW, 1, 0L);
+ InvalidateRect(hWndIds, NULL, TRUE);
+ break;
+
+ case ID_WRITEFILE:
+ {
+ WORD wErrMsg;
+
+ MySetSel(hWndIds, -2);
+
+ if(!LOWORD(lParam))
+ break;
+
+ if(wErrMsg=DoWriteFile(wKey, LOWORD(lParam)))
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ GlobalUnlock(LOWORD(lParam));
+ GlobalFree(LOWORD(lParam));
+ break;
+ }
+
+ case ID_ADD:
+ {
+ int nResult;
+ WORD wErrMsg;
+
+ MySetSel(hWndIds, -2);
+
+ if(!(hStat1=MyGetPath(wKey)))
+ goto Error6_1;
+ hEdit1 = hEdit2 = NULL;
+ wHelpId = IDW_ADDKEY;
+ if((nResult=DoDialogBox(MAKEINTRESOURCE(AddKey), hWnd, GetKeyProc))
+ < 0)
+ goto Error6_2;
+ else if(nResult == IDCANCEL)
+ break;
+
+ SendMessage(hWndIds, WM_SETREDRAW, 0, 0L);
+ if (wErrMsg=GetErrMsg((WORD)SDKSetValue(-wKey, LocalLock(hEdit1),
+ LocalLock(hEdit2))))
+ MyMessageBox(hWnd, wErrMsg, MB_OK, 0);
+ SendMessage(hWndIds, WM_SETREDRAW, 1, 0L);
+ InvalidateRect(hWndIds, NULL, TRUE);
+
+ LocalUnlock(hEdit2);
+ LocalFree(hEdit2);
+ LocalUnlock(hEdit1);
+ LocalFree(hEdit1);
+ break;
+
+Error6_2:
+ LocalFree(hStat1);
+Error6_1:
+ MyMessageBox(hWnd, IDS_OUTOFMEMORY, MB_OK, 0);
+ break;
+ }
+
+ case ID_DELETE:
+ /* Fall through */
+ case ID_COPY:
+ {
+ int nNewKey, nOldKey, nResult;
+ PSTR pEdit1, pEdit2;
+
+ MySetSel(hWndIds, -2);
+
+/* Get the key name to copy to */
+ if(!(hEdit1=MyGetPath(wKey)))
+ goto Error5_1;
+ hStat1 = hEdit2 = NULL;
+ wHelpId = wParam==ID_COPY ? IDW_COPYKEY : IDW_DELETE;
+ if((nResult=DoDialogBox(wParam==ID_COPY ? MAKEINTRESOURCE(CopyKey) :
+ MAKEINTRESOURCE(DeleteKey), hWnd, GetKeyProc)) < 0)
+ goto Error5_2;
+ else if(nResult == IDCANCEL)
+ break;
+
+/* Do the operation and clean up */
+ pEdit1 = LocalLock(hEdit1);
+
+ if((nOldKey=FindKey(pEdit1)) < 0) {
+ MyMessageBox(hWnd, IDS_SOURCENOTEXIST, MB_OK, lstrlen(pEdit1),
+ (LPSTR)pEdit1);
+ goto Error5_3;
+ }
+
+ SendMessage(hWndIds, WM_SETREDRAW, 0, 0L);
+ if(wParam == ID_COPY) {
+ /* hEdit2 is only set in the copy dialog; not the delete
+ */
+ pEdit2 = LocalLock(hEdit2);
+ if((nNewKey=DoCopyKey(nOldKey, pEdit2)) < 0)
+ MyMessageBox(hWnd, -nNewKey, MB_OK, 0);
+ LocalUnlock(hEdit2);
+ LocalFree(hEdit2);
+ } else {
+ nNewKey = IDS_NODELROOT;
+ if(!nOldKey || (nNewKey=MyDeleteKey(nOldKey)))
+ MyMessageBox(hWnd, nNewKey, MB_OK, 0);
+ if(nOldKey >= (int)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L))
+ --nOldKey;
+ MySetSel(hWndIds, nOldKey);
+ }
+ SendMessage(hWndIds, WM_SETREDRAW, 1, 0L);
+ InvalidateRect(hWndIds, NULL, TRUE);
+
+Error5_3:
+ LocalUnlock(hEdit1);
+ LocalFree(hEdit1);
+ break;
+
+/* WARNING: ID_FIND also uses these error labels */
+Error5_2:
+ LocalFree(hEdit1);
+Error5_1:
+ MyMessageBox(hWnd, IDS_OUTOFMEMORY, MB_OK, 0);
+ break;
+ }
+
+ case ID_FINDKEY:
+ {
+ int nResult;
+
+ if(!(hEdit1=StringToLocalHandle(LocalLock(hSearchString),
+ LMEM_MOVEABLE)))
+ goto Error5_1;
+ LocalUnlock(hSearchString);
+ hStat1 = hEdit2 = NULL;
+ wHelpId = IDW_FINDKEY;
+ if((nResult=DoDialogBox(MAKEINTRESOURCE(FindKeyDlg), hWnd,
+ GetKeyProc)) < 0)
+ goto Error5_2;
+ else if(nResult == IDCANCEL)
+ break;
+
+ if(hSearchString)
+ LocalFree(hSearchString);
+ hSearchString = hEdit1;
+ }
+/* Fall through */
+ case ID_FINDNEXT:
+ {
+ int index = LB_ERR;
+ PSTR pSearchString;
+
+ if(!hSearchString)
+ goto Error2_1;
+ pSearchString = LocalLock(hSearchString);
+
+ if(*pSearchString == '\\') {
+ if((index=FindKey(pSearchString)) == -1)
+ goto Error2_2;
+ } else {
+ if((index=(int)SendMessage(hWndIds, LB_FINDSTRING, wKey,
+ (DWORD)((LPSTR)pSearchString)))==LB_ERR)
+ goto Error2_2;
+ }
+ MySetSel(hWndIds, index);
+
+Error2_2:
+ LocalUnlock(hSearchString);
+Error2_1:
+ if(index < 0)
+ MessageBeep(0);
+ break;
+ }
+
+ default:
+ break;
+ }
+ SetCursor(oldCursor);
+ break;
+
+ default:
+DoDefault:
+ return(DefWindowProc(hWnd, message, wParam, lParam));
+ break;
+ }
+
+ return(0L);
+}
+
diff --git a/private/mvdm/wow16/regedit/sdkreged.def b/private/mvdm/wow16/regedit/sdkreged.def
new file mode 100644
index 000000000..dd2ec2fac
--- /dev/null
+++ b/private/mvdm/wow16/regedit/sdkreged.def
@@ -0,0 +1,19 @@
+NAME SDKREGED
+
+DESCRIPTION 'View Registration Database'
+
+STUB 'WINSTUB.EXE'
+EXETYPE WINDOWS
+
+CODE MOVEABLE PRELOAD
+DATA MOVEABLE MULTIPLE PRELOAD
+
+HEAPSIZE 1024
+STACKSIZE 4096
+
+EXPORTS
+ WndProc @3
+ MainWndDlg @4
+ MessageFilter @5
+ MyOpenDlgProc @6
+ GetKeyProc @8
diff --git a/private/mvdm/wow16/regedit/sdkreged.h b/private/mvdm/wow16/regedit/sdkreged.h
new file mode 100644
index 000000000..13aece4e1
--- /dev/null
+++ b/private/mvdm/wow16/regedit/sdkreged.h
@@ -0,0 +1,74 @@
+#include "common.h"
+
+
+/*********************************************************/
+/******************* Constants ***************************/
+/*********************************************************/
+
+#define SDKMAINWND 300
+#define ModifyKey 301
+#define AddKey 302
+#define CopyKey 303
+#define DeleteKey 304
+#define FindKeyDlg 305
+
+#define ID_SAVE (ID_FIRSTSDKREGED)
+#define ID_RESTORE (ID_SAVE+1)
+#define ID_WRITEFILE (ID_SAVE+2)
+#define ID_DORESTORE (ID_SAVE+3)
+
+#define ID_FINDKEY (ID_FIRSTSDKREGED+0x10)
+#define ID_FINDNEXT (ID_FINDKEY+1)
+
+#define ID_VALUE (ID_FIRSTSDKREGED+0x20)
+#define ID_VALLIST (ID_VALUE+1)
+#define ID_DELLIST (ID_VALUE+2)
+#define ID_FULLPATH (ID_VALUE+3)
+
+#define ID_STAT1 (ID_FIRSTSDKREGED+0x30)
+#define ID_EDIT1 (ID_STAT1+1)
+#define ID_EDIT2 (ID_STAT1+2)
+
+#define IDS_NOSUBKEY (IDS_FIRSTSDKREGED)
+#define IDS_ALREADYEXIST (IDS_NOSUBKEY+1)
+
+#define IDS_WRITETITLE (IDS_FIRSTSDKREGED+0x10)
+#define IDS_CANTWRITEFILE (IDS_WRITETITLE+1)
+
+#define IDS_SAVECHANGES (IDS_FIRSTSDKREGED+0x20)
+#define IDS_ERRORSAVING (IDS_SAVECHANGES+1)
+#define IDS_SURERESTORE (IDS_SAVECHANGES+2)
+#define IDS_NODELROOT (IDS_SAVECHANGES+3)
+
+#define IDS_SOURCENOTEXIST (IDS_FIRSTSDKREGED+0x30)
+
+#define IDW_ADDKEY (IDW_MODIFY-1)
+#define IDW_COPYKEY (IDW_MODIFY-2)
+#define IDW_DELETE (IDW_MODIFY-3)
+#define IDW_FINDKEY (IDW_MODIFY-4)
+
+
+/*********************************************************/
+/******************* Functions ***************************/
+/*********************************************************/
+
+/***** sdkreged.c *****/
+extern long FAR PASCAL SDKMainWnd(HWND, WORD, WORD, LONG);
+
+/***** sdbase.c *****/
+extern DWORD NEAR PASCAL GetTreeMarkers(int nId);
+extern int NEAR PASCAL GetLevel(int nId);
+extern HANDLE NEAR PASCAL MyGetPartialPath(int index, int nParent);
+extern HANDLE NEAR PASCAL MyGetPath(int i);
+extern int NEAR PASCAL FindKey(PSTR pKey);
+extern int NEAR PASCAL FindLastExistingKey(int nParent, PSTR pPath);
+extern WORD NEAR PASCAL DoWriteFile(int nId, HANDLE hFileName);
+
+/***** virt.c *****/
+extern WORD NEAR PASCAL MyResetIdList(HWND hDlg);
+extern WORD NEAR PASCAL MySaveChanges(void);
+extern WORD NEAR PASCAL MyDeleteKey(int nId);
+extern unsigned long NEAR PASCAL MyGetValue(int nId, HANDLE *hValue);
+extern unsigned long NEAR PASCAL SDKSetValue(HKEY, PSTR, PSTR);
+extern int NEAR PASCAL DoCopyKey(int nId, PSTR pPath);
+
diff --git a/private/mvdm/wow16/regedit/sdkreged.ico b/private/mvdm/wow16/regedit/sdkreged.ico
new file mode 100644
index 000000000..e503e31b9
--- /dev/null
+++ b/private/mvdm/wow16/regedit/sdkreged.ico
Binary files differ
diff --git a/private/mvdm/wow16/regedit/utils1.c b/private/mvdm/wow16/regedit/utils1.c
new file mode 100644
index 000000000..df1f818b3
--- /dev/null
+++ b/private/mvdm/wow16/regedit/utils1.c
@@ -0,0 +1,93 @@
+#include <windows.h>
+#include <commdlg.h>
+#include <shellapi.h>
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+#define BLOCKLEN 100
+
+PSTR NEAR PASCAL GetAppName(HANDLE hCommand)
+{
+ static char szApp[17];
+
+ PSTR pLast, pCommand, pDot;
+ char cSave;
+
+ for(pCommand=LocalLock(hCommand); *pCommand==' ';
+ pCommand=AnsiNext(pCommand))
+ /* skip spaces */ ;
+
+ for(pDot=pLast=pCommand; ; pCommand=AnsiNext(pCommand)) {
+ switch(*pCommand) {
+ case ':':
+ case '\\':
+ pLast = pCommand + 1;
+ break;
+
+ case '.':
+ pDot = pCommand;
+ break;
+
+ case '\0':
+ case ' ':
+ case '/':
+ goto FoundEnd;
+ }
+ }
+FoundEnd:
+
+/* If there was a dot in the name or the name was too long */
+ if(pDot > pLast)
+ pCommand = pDot;
+ if(pCommand-pLast > 8)
+ pCommand = pLast+8;
+
+ cSave = *pCommand;
+ *pCommand = '\0';
+ lstrcpy(szApp, pLast);
+ *pCommand = cSave;
+
+ AnsiUpper(szApp);
+ pLast = AnsiNext(szApp);
+ AnsiLower(pLast);
+
+ LocalUnlock(hCommand);
+ return(szApp);
+}
+
+HANDLE NEAR cdecl ConstructPath(PSTR pHead, ...)
+{
+ HANDLE hBuf = NULL;
+ PSTR *ppName, pBuf, pTemp;
+ WORD wLen;
+
+ if(!pHead)
+ goto Error1;
+
+ for(ppName=&pHead, wLen=0; *ppName; ++ppName)
+ wLen += lstrlen(*ppName) + 1;
+
+ if(!(hBuf=LocalAlloc(LMEM_MOVEABLE, wLen)))
+ goto Error1;
+ if(!(pBuf=LocalLock(hBuf)))
+ goto Error2;
+
+ for(ppName=&pHead, wLen=0, pTemp=pBuf; *ppName; ++ppName) {
+ lstrcpy(pTemp, *ppName);
+ pTemp += lstrlen(pTemp);
+ *pTemp++ = '\\';
+ }
+ *(pTemp-1) = '\0';
+
+ LocalUnlock(hBuf);
+ goto Error1;
+
+Error2:
+ LocalFree(hBuf);
+ hBuf = NULL;
+Error1:
+ return(hBuf);
+}
+
diff --git a/private/mvdm/wow16/regedit/virt.c b/private/mvdm/wow16/regedit/virt.c
new file mode 100644
index 000000000..6d978c248
--- /dev/null
+++ b/private/mvdm/wow16/regedit/virt.c
@@ -0,0 +1,519 @@
+#include <windows.h>
+#include "SDKRegEd.h"
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#endif
+
+HANDLE hPars = NULL;
+WORD maxKeys = 0;
+BOOL bChangesMade = FALSE;
+
+static HWND hWndVals, hWndDels;
+char szListbox[] = "listbox";
+
+extern HANDLE hInstance;
+extern HWND hWndIds, hWndMain;
+extern char szNull[];
+
+extern VOID NEAR PASCAL MySetSel(HWND hWndList, int index);
+
+static int NEAR PASCAL AddKeyToList(PSTR szPath, int index, int nLevel)
+{
+ PSTR szLast, pNext;
+ DWORD dwResult;
+ int nResult = -IDS_OUTOFMEMORY;
+ WORD *pPars;
+ int i, nKeys, nParent, nLevels;
+
+/* Create the list of parents if necessary */
+ if(!hPars) {
+ if(!(hPars=LocalAlloc(LMEM_MOVEABLE, 8*sizeof(WORD))))
+ goto Error1;
+ else
+ maxKeys = 8;
+ }
+
+/* Get the current number of keys, and check index
+ * index == -1 means to add to the end of the list
+ */
+ if((nKeys=(WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L)) == LB_ERR)
+ nKeys = 0;
+ if(index == 0xffff)
+ index = nKeys;
+ else if(index > nKeys)
+ goto Error1;
+
+ if(!(pPars=(WORD *)LocalLock(hPars)))
+ goto Error1;
+
+ szLast = szPath;
+
+ if(*szPath == '\\') {
+/* This is a full path name, which will be inserted the first
+ * place it can be. The level and index are ignored: they will
+ * need to be determined
+ * if this is the root, set the variables and jump to the adding part
+ * otherwise, find the existing parent and the new tail
+ */
+ if(!*(szPath+1)) {
+ /* If the root exists, just return its index
+ */
+ if((nResult=FindKey(szPath)) >= 0)
+ goto Error2;
+ nParent = -1;
+ nLevels = 0;
+ pNext = szPath + 1;
+ goto AddNewKey;
+ } else {
+ ++szLast;
+ if((nParent=FindLastExistingKey(0, szLast)) < 0)
+ goto Error2;
+ index = nParent + 1;
+ }
+ } else {
+/* Not an absolute path
+ * nLevel == -1 means the preceding index is the parent, so nLevel is ignored
+ * otherwise, find the ancestor of the preceding key with a lower
+ * level than nLevel, and that is the parent
+ * Finally, check for existing keys, and adjust nParent and index if necessary
+ */
+ if(nLevel == -1) {
+ nParent = index - 1;
+ } else {
+ for(i=index-1; i>=0; i=pPars[i], --nLevel)
+ /* do nothing */ ;
+ if(nLevel > 0)
+ goto Error2;
+
+ for(i=index-1; nLevel<0; i=pPars[i], ++nLevel)
+ /* do nothing */ ;
+ nParent = i;
+ }
+
+ if(index < nKeys) {
+ if((nParent=FindLastExistingKey(nParent, szLast)) < 0)
+ goto Error2;
+ else if(nParent >= index)
+ index = nParent + 1;
+ }
+ }
+
+/* At this point, index should be set to the intended index,
+ * nParent should be set to the parent of the new key,
+ * and szLast is the path for the new key (which may have subkeys)
+ */
+ for(nLevels=0; pNext=OFFSET(MyStrTok(szLast, '\\'));
+ ++nLevels, szLast=pNext) {
+AddNewKey:
+ if (pNext-szLast > MAX_KEY_LENGTH) {
+ nResult = -IDS_BADKEY;
+ goto CleanUp;
+ }
+
+ /* Make sure we have room for the new parents */
+ if(nKeys+nLevels+1 > (int)maxKeys) {
+ HANDLE hTemp;
+
+ LocalUnlock(hPars);
+ if(!(hTemp=LocalReAlloc(hPars,(maxKeys+8)*sizeof(WORD),LMEM_MOVEABLE)))
+ goto Error1;
+ hPars = hTemp;
+ if(!(pPars=(WORD *)LocalLock(hPars)))
+ goto Error1;
+ maxKeys += 8;
+ }
+
+ if((dwResult=SendMessage(hWndIds, LB_INSERTSTRING, index+nLevels,
+ (DWORD)((LPSTR)szLast)))==LB_ERR)
+ break;
+ if((dwResult=SendMessage(hWndVals, LB_INSERTSTRING, index+nLevels,
+ (DWORD)((LPSTR)szNull)))==LB_ERR) {
+ SendMessage(hWndIds, LB_DELETESTRING, index+nLevels, 0L);
+ break;
+ }
+ SendMessage(hWndVals, LB_SETITEMDATA, index+nLevels, 1L);
+ }
+
+/* If the new key already exists, return it */
+ if(!nLevels)
+ nResult = nParent;
+ else if(dwResult != LB_ERR)
+ nResult = LOWORD(dwResult);
+
+CleanUp:
+ /* update the parent list */
+ for(--nKeys; nKeys>=index; --nKeys) {
+ if(pPars[nKeys] >= (WORD)index)
+ pPars[nKeys+nLevels] = pPars[nKeys] + nLevels;
+ else
+ pPars[nKeys+nLevels] = pPars[nKeys];
+ }
+ for(--nLevels; nLevels>=0; --nLevels)
+ pPars[index+nLevels] = nParent+nLevels;
+
+Error2:
+ LocalUnlock(hPars);
+Error1:
+ return(nResult);
+}
+
+static WORD NEAR PASCAL ListRegs(HWND hWnd, HKEY hKey, int wLevel)
+{
+ HANDLE hTail;
+ PSTR pTail;
+ int i;
+ HKEY hSubKey;
+ WORD wErrMsg = NULL;
+
+ for(i=0; !wErrMsg; ++i) {
+ if(MyEnumKey(hKey, i, &hTail) != ERROR_SUCCESS)
+ break;
+ pTail = LocalLock(hTail);
+
+ if((int)(wErrMsg=-AddKeyToList(pTail, -1, wLevel))>0 ||
+ (wErrMsg=GetErrMsg((WORD)RegOpenKey(hKey, pTail, &hSubKey))))
+ goto Error1;
+ wErrMsg = ListRegs(hWnd, hSubKey, wLevel+1);
+ RegCloseKey(hSubKey);
+
+Error1:
+ LocalUnlock(hTail);
+ LocalFree(hTail);
+ }
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL MyResetIdList(HWND hDlg)
+{
+ HKEY hKey;
+ int i, nNum;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+
+ if((!hWndVals && !(hWndVals=GetDlgItem(hDlg, ID_VALLIST))) ||
+ (!hWndDels && !(hWndDels=GetDlgItem(hDlg, ID_DELLIST))))
+ goto Error1;
+
+ bChangesMade = FALSE;
+
+ SendMessage(hWndIds, LB_RESETCONTENT, 0, 0L);
+ SendMessage(hWndVals, LB_RESETCONTENT, 0, 0L);
+ SendMessage(hWndDels, LB_RESETCONTENT, 0, 0L);
+
+ if((int)(wErrMsg=-AddKeyToList("\\", 0, 0)) <= 0) {
+ if(!(wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT,
+ NULL, &hKey)))) {
+ wErrMsg = ListRegs(hWndIds, hKey, 1);
+ RegCloseKey(hKey);
+
+ nNum = (int)SendMessage(hWndVals, LB_GETCOUNT, 0, 0L);
+ for(i=0; i<nNum; ++i)
+ SendMessage(hWndVals, LB_SETITEMDATA, i, 0L);
+
+ }
+
+ MySetSel(hWndIds, 0);
+ }
+
+Error1:
+ return(wErrMsg);
+}
+
+WORD NEAR PASCAL MySaveChanges(void)
+{
+ HKEY hKeyTemp;
+ HANDLE hPath, hVal;
+ WORD wNum, wErrMsg;
+ DWORD dwTemp;
+ int i;
+
+ if(wErrMsg=GetErrMsg((WORD)RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKeyTemp)))
+ goto Error1;
+
+ wNum = (WORD)SendMessage(hWndDels, LB_GETCOUNT, 0, 0L);
+ for(i=0; !wErrMsg && (WORD)i<wNum; ++i) {
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hPath=GetListboxString(hWndDels, i)))
+ break;
+ dwTemp = RegDeleteKey(HKEY_CLASSES_ROOT, LocalLock(hPath)+1);
+ wErrMsg = dwTemp==ERROR_BADKEY ? NULL : GetErrMsg((WORD)dwTemp);
+
+ LocalUnlock(hPath);
+ LocalFree(hPath);
+ }
+
+ wNum = GetErrMsg((WORD)RegCloseKey(hKeyTemp));
+ if(wErrMsg || (wErrMsg=wNum) ||
+ (wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT, NULL,
+ &hKeyTemp))))
+ goto Error1;
+
+ wNum = (WORD)SendMessage(hWndVals, LB_GETCOUNT, 0, 0L);
+ for(i=wNum-1; !wErrMsg && i>=0; --i) {
+ if(!SendMessage(hWndVals, LB_GETITEMDATA, i, 0L))
+ continue;
+
+ wErrMsg = IDS_OUTOFMEMORY;
+ if(!(hPath=MyGetPath(i)))
+ break;
+ if(!(hVal=GetListboxString(hWndVals, i)))
+ goto Error2;
+
+ wErrMsg = GetErrMsg((WORD)RegSetValue(HKEY_CLASSES_ROOT,
+ LocalLock(hPath)+1, REG_SZ, LocalLock(hVal), 0L));
+
+ LocalUnlock(hVal);
+ LocalUnlock(hPath);
+
+ LocalFree(hVal);
+Error2:
+ LocalFree(hPath);
+ }
+
+ wNum = GetErrMsg((WORD)RegCloseKey(hKeyTemp));
+Error1:
+ return(wErrMsg ? wErrMsg : wNum);
+}
+
+WORD NEAR PASCAL MyDeleteKey(int nId)
+{
+ HANDLE hPath;
+ WORD *pPars;
+ int nKeys, i, j;
+ WORD wErrMsg = IDS_OUTOFMEMORY;
+
+/* Get the path and try to delete it */
+ if(!(hPath=MyGetPath(nId)))
+ goto Error1;
+ if(SendMessage(hWndDels, LB_ADDSTRING, 0, (DWORD)((LPSTR)LocalLock(hPath)))
+ == LB_ERR)
+ goto Error2;
+
+ pPars = (WORD *)LocalLock(hPars);
+ nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
+
+/* Find the first key that does not have nId in its parent chain */
+ for(i=nId+1; i<nKeys; ++i) {
+ for(j=pPars[i]; j>=0 && j!=nId; j=pPars[j])
+ /* do nothing */ ;
+ if(j != nId)
+ break;
+ }
+
+/* Do not delete the root from the list */
+ if(!nId)
+ ++nId;
+
+/* Delete the string from the listbox */
+ for(j=nId; j<i; ++j) {
+ SendMessage(hWndIds, LB_DELETESTRING, nId, 0L);
+ SendMessage(hWndVals, LB_DELETESTRING, nId, 0L);
+ }
+
+/* Update the parent list */
+ i -= nId;
+ nKeys -= i;
+ for(j=nId; j<nKeys; ++j) {
+ if(pPars[j+i] >= (WORD)nId)
+ pPars[j] = pPars[j+i] - i;
+ else
+ pPars[j] = pPars[j+i];
+ }
+ bChangesMade = TRUE;
+ wErrMsg = NULL;
+
+ LocalUnlock(hPars);
+Error2:
+ LocalUnlock(hPath);
+ LocalFree(hPath);
+Error1:
+ return(wErrMsg);
+}
+
+unsigned long NEAR PASCAL MyGetValue(int nId, HANDLE *hValue)
+{
+ unsigned long result;
+ HANDLE hPath;
+
+ if(SendMessage(hWndVals, LB_GETITEMDATA, nId, 0L)) {
+ if(!(*hValue=GetListboxString(hWndVals, nId)))
+ return(ERROR_OUTOFMEMORY);
+ result = ERROR_SUCCESS;
+ } else {
+ if(!(hPath=MyGetPath(nId)))
+ return(ERROR_OUTOFMEMORY);
+ result = MyQueryValue(HKEY_CLASSES_ROOT, LocalLock(hPath)+1, hValue);
+ LocalUnlock(hPath);
+ LocalFree(hPath);
+ }
+
+ return(result);
+}
+
+/* Strip off leading and trailing spaces, and return
+ * -1 if there are any invalid characters, otherwise the address
+ * of the first non-blank.
+ */
+PSTR NEAR PASCAL VerifyKey(PSTR lpK)
+{
+ PSTR lpT;
+ char cLast = '\0';
+
+ /* skip some spaces, just to be wierd
+ */
+ while (*lpK == ' ')
+ lpK++;
+
+ /* Special case the string "\"
+ */
+ if (*(unsigned int *)lpK == (unsigned int)'\\')
+ return(lpK);
+
+ /* Note that no extended characters are allowed, so no DBCS
+ * characters are allowed in a key
+ */
+ for (lpT=lpK; ; ++lpT)
+ {
+ switch (*lpT)
+ {
+ case '\0':
+ /* We do not allow a \ as the last char
+ */
+ return(cLast=='\\' ? (PSTR)-1 : lpK);
+
+ case '\\':
+ /* We do not allow two \'s in a row
+ */
+ if (cLast == '\\')
+ return((PSTR)-1);
+ break;
+
+ default:
+ /* If we get a control or extended character, return -1.
+ */
+ if ((char)(*lpT) <= ' ')
+ return((PSTR)-1);
+ break;
+ }
+
+ cLast = *lpT;
+ }
+}
+
+unsigned long NEAR PASCAL SDKSetValue(HKEY hKey, PSTR pSubKey, PSTR pVal)
+{
+ WORD wNewKey;
+
+ if (hKey == HKEY_CLASSES_ROOT)
+ hKey = 0L;
+ else
+ hKey = -(long)hKey;
+
+ if ((pSubKey=VerifyKey(pSubKey)) == (PSTR)-1)
+ return(ERROR_BADKEY);
+
+ if((int)(wNewKey=(WORD)AddKeyToList(pSubKey, (WORD)hKey+1, -1))>=0 &&
+ SendMessage(hWndVals, LB_INSERTSTRING, wNewKey, (LONG)(LPSTR)pVal)
+ !=LB_ERR) {
+ SendMessage(hWndVals, LB_DELETESTRING, wNewKey+1, 0L);
+ SendMessage(hWndVals, LB_SETITEMDATA, wNewKey, 1L);
+ MySetSel(hWndIds, wNewKey);
+ bChangesMade = TRUE;
+
+ return(ERROR_SUCCESS);
+ }
+
+ return(ERROR_OUTOFMEMORY);
+}
+
+int NEAR PASCAL DoCopyKey(int nId, PSTR pPath)
+{
+ WORD *pPars;
+ int nParent, result, i, j, nKeys, nNewKey;
+
+ pPars = (WORD *)LocalLock(hPars);
+
+/* Cannot copy the whole tree */
+ result = -IDS_NOSUBKEY;
+ if(!nId)
+ goto Error1;
+
+/* Find the longest path that currently exists
+ * return an error if that is the whole string
+ * or a subkey of the key to be copied
+ */
+ if(*pPath == '\\') {
+ ++pPath;
+ if((result=nParent=FindLastExistingKey(0, pPath)) < 0)
+ goto Error1;
+ } else {
+ if((result=nParent=FindLastExistingKey(pPars[nId], pPath)) < 0)
+ goto Error1;
+ }
+ result = -IDS_NOSUBKEY;
+ for(i=nParent; i>=0; i=pPars[i])
+ if(i == nId)
+ goto Error1;
+ result = -IDS_ALREADYEXIST;
+ if(!*pPath)
+ goto Error1;
+
+/* Find the first key that does not have nId in its parent chain */
+ nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
+ for(i=nId+1; i<nKeys; ++i) {
+ for(j=pPars[i]; j>=0 && j!=nId; j=pPars[j])
+ /* do nothing */ ;
+ if(j != nId)
+ break;
+ }
+
+/* Add the new keys
+ * hPars should be unlocked in case it needs to grow
+ */
+ LocalUnlock(hPars);
+ pPars = NULL;
+ if(SDKSetValue(-nParent, pPath, szNull) != ERROR_SUCCESS)
+ goto Error1;
+ nNewKey = (int)SendMessage(hWndIds, LB_GETCURSEL, 0, 0L);
+
+ for(--i, result=nId; i>=nId && result==nId; --i) {
+ HANDLE hPart, hValue;
+ PSTR pPart;
+
+ if(nNewKey <= nId) {
+ int nDiff;
+
+/* Need to update i and nId if keys were added before them */
+ nDiff = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L) - nKeys;
+ nKeys += nDiff;
+ i += nDiff;
+ nId += nDiff;
+ }
+
+ result = -IDS_OUTOFMEMORY;
+ if(!(hPart=MyGetPartialPath(i, nId)))
+ goto Error2;
+ pPart = LocalLock(hPart);
+ if(MyGetValue(i, &hValue) != ERROR_SUCCESS)
+ goto Error3;
+
+ if(SDKSetValue(-nNewKey, pPart, LocalLock(hValue)) != ERROR_SUCCESS)
+ goto Error4;
+
+ result = nId;
+Error4:
+ LocalUnlock(hValue);
+ LocalFree(hValue);
+Error3:
+ LocalUnlock(hPart);
+ LocalFree(hPart);
+Error2:
+ ;
+ }
+
+Error1:
+ if(pPars)
+ LocalUnlock(hPars);
+ return(result);
+}
+
diff --git a/private/mvdm/wow16/shell/dragdrop.c b/private/mvdm/wow16/shell/dragdrop.c
new file mode 100644
index 000000000..680ad5154
--- /dev/null
+++ b/private/mvdm/wow16/shell/dragdrop.c
@@ -0,0 +1,48 @@
+/*
+ * dragdrop.c -
+ *
+ * Code for Drag/Drop API's.
+ *
+ * This code assumes something else does all the dragging work; it just
+ * takes a list of files after all the extra stuff.
+ *
+ * The File Manager is responsible for doing the drag loop, determining
+ * what files will be dropped, formatting the file list, and posting
+ * the WM_DROPFILES message.
+ *
+ * The list of files is a sequence of zero terminated filenames, fully
+ * qualified, ended by an empty name (double NUL). The memory is allocated
+ * DDESHARE.
+ */
+
+#include <windows.h>
+#include "shellapi.h"
+
+void WINAPI DragFinishWOW(HDROP hDrop);
+
+//
+// Make sure that we correctly alias wParam of WM_DROPFILES, because that's
+// the handle in hDrop
+//
+
+BOOL WINAPI DragQueryPoint(HDROP hDrop, LPPOINT lppt)
+{
+ LPDROPFILESTRUCT lpdfs;
+ BOOL fNC;
+
+ lpdfs = (LPDROPFILESTRUCT)GlobalLock((HGLOBAL)hDrop);
+
+ *lppt = lpdfs->pt;
+ fNC = lpdfs->fNC;
+ GlobalUnlock((HGLOBAL)hDrop);
+ return !fNC;
+}
+
+
+void WINAPI DragFinish(HDROP hDrop)
+{
+ GlobalFree((HGLOBAL)hDrop);
+ DragFinishWOW(hDrop);
+}
+
+
diff --git a/private/mvdm/wow16/shell/library/shell.def b/private/mvdm/wow16/shell/library/shell.def
new file mode 100644
index 000000000..ee9eba65c
--- /dev/null
+++ b/private/mvdm/wow16/shell/library/shell.def
@@ -0,0 +1,40 @@
+LIBRARY SHELL
+
+EXETYPE WINDOWS
+
+DESCRIPTION 'Windows 3.1 Shell API Library'
+
+CODE MOVEABLE DISCARDABLE
+DATA MOVEABLE SINGLE SHARED
+
+SEGMENTS
+ _TEXT MOVEABLE DISCARDABLE PRELOAD
+ _DBF MOVEABLE PRELOAD
+ _WEP FIXED PRELOAD
+
+EXPORTS
+ RegOpenKey @1 ;public
+ RegCreateKey @2 ;public
+ RegCloseKey @3 ;public
+ RegDeleteKey @4 ;public
+ RegSetValue @5 ;public
+ RegQueryValue @6 ;public
+ RegEnumKey @7 ;public
+
+ DragAcceptFiles @9 ;public
+ DragQueryFile @11 ;public
+ DragFinish @12 ;public
+ DragQueryPoint @13 ;public
+
+ ShellExecute @20 ;internal private for shell
+ FindExecutable @21 ;internal private for shell
+ ShellAbout @22 ;internal private for shell
+ AboutDlgProc @33 ;internal
+ ExtractIcon @34 ;internal private for shell
+ DuplicateIcon @35 ;internal private for shell
+ ExtractAssociatedIcon @36 ;internal private for shell
+ DoEnvironmentSubst @37 ;public
+ FindEnvironmentString @38 ;public
+
+ HereTharBeTygars @100 ;internal
+ WEP ;internal
diff --git a/private/mvdm/wow16/shell/makefile b/private/mvdm/wow16/shell/makefile
new file mode 100644
index 000000000..2f849f111
--- /dev/null
+++ b/private/mvdm/wow16/shell/makefile
@@ -0,0 +1,104 @@
+# USER16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+RINCS = -I..\inc
+!endif
+
+DEFINES = -DWOW -DBUILDDLL $(MVDMFLAGS)
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+
+CW16 = -Asnw -G2sw -Os -W2 -Zp $(DEFINES) $(INCS)
+
+LINK = /map
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\snocrtd.lib
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ RC16 -r $(RINCS) $*.rc
+
+
+all: shell.dll shell.sym
+ -binplace shell.dll
+ -binplace shell.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.lst del *.lst
+ if exist *.res del *.res
+
+shell.obj: shell.asm ..\..\inc\wow.inc ..\..\inc\wowshell.inc
+ masm $(AOBJ) shell;
+
+dragdrop.obj: dragdrop.c ..\..\inc\wow.inc ..\..\inc\wowshell.inc
+ cl16 -c $(CW16) dragdrop.c
+
+shell.lrf: makefile
+ echo shell.obj dragdrop.obj>shell.lrf
+ echo shell.dll>>shell.lrf
+ echo shell $(LINK)>>shell.lrf
+ echo ..\lib\libw.lib /nod >>shell.lrf
+ echo shell;>>shell.lrf
+
+shell.dll shell.map: shell.obj shell.lrf shell.def shell.res dragdrop.obj
+ link16 @shell.lrf;
+ rc16 -t shell.res shell.dll
+
+shell.res: shell.rc shell.rcv ..\inc\common.ver
+
+!ENDIF
diff --git a/private/mvdm/wow16/shell/shell.asm b/private/mvdm/wow16/shell/shell.asm
new file mode 100644
index 000000000..676cd814b
--- /dev/null
+++ b/private/mvdm/wow16/shell/shell.asm
@@ -0,0 +1,124 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; SHELL.ASM
+; Win16 SHELL thunks
+;
+; History:
+;
+; Created 14-April-1992 by Chandan S. Chauhan (ChandanC)
+;
+;--
+
+ TITLE SHELL.ASM
+ PAGE ,132
+
+ ; Some applications require that USER have a heap. This means
+ ; we must always have: LIBINIT equ 1
+ LIBINIT equ 1
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowshell.inc
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+ifdef LIBINIT
+externFP LocalInit
+endif
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows
+SHELL_Identifier db 'SHELL16 Data Segment'
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+
+cProc SHELL16,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+
+ cBegin <nogen>
+
+ IFDEF LIBINIT
+ ; push params and call user initialisation code
+
+ push di ;hModule
+
+ ; if we have a local heap declared then initialize it
+
+ jcxz no_heap
+
+ push 0 ;segment
+ push 0 ;start
+ push cx ;length
+ call LocalInit
+
+no_heap:
+ pop di
+ mov ax, 1
+ ELSE
+ mov ax,1 ;are we dressed for success or WHAT?!
+ ENDIF
+ ret
+ cEnd <nogen>
+
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+
+assumes DS,NOTHING
+
+ SHELLThunk REGOPENKEY
+ SHELLThunk REGCREATEKEY
+ SHELLThunk REGCLOSEKEY
+ SHELLThunk REGDELETEKEY
+ SHELLThunk REGSETVALUE
+ SHELLThunk REGQUERYVALUE
+ SHELLThunk REGENUMKEY
+ SHELLThunk DRAGACCEPTFILES
+ SHELLThunk DRAGQUERYFILE
+FUN_DragFinishWOW equ FUN_DragFinish
+ SHELLThunk DRAGFINISHWOW, %(size DRAGFINISH16)
+;;; SHELLThunk DRAGQUERYPOINT
+ SHELLThunk SHELLEXECUTE ;internal private for shell
+ SHELLThunk FINDEXECUTABLE ;internal private for shell
+ SHELLThunk SHELLABOUT ;internal private for shell
+ SHELLThunk WCI ;internal
+ SHELLThunk ABOUTDLGPROC ;internal
+ SHELLThunk EXTRACTICON
+ SHELLThunk EXTRACTASSOCIATEDICON ;internal private for shell
+ SHELLThunk DOENVIRONMENTSUBST
+ SHELLThunk FINDENVIRONMENTSTRING
+ SHELLThunk INTERNALEXTRACTICON ;internal private for shell
+ SHELLThunk HERETHARBETYGARS ;internal
+ SHELLThunk FINDEXEDLGPROC
+ SHELLThunk REGISTERSHELLHOOK
+ SHELLThunk SHELLHOOKPROC
+
+
+sEnd CODE
+
+end SHELL16
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/shell/shell.def b/private/mvdm/wow16/shell/shell.def
new file mode 100644
index 000000000..6eae6a432
--- /dev/null
+++ b/private/mvdm/wow16/shell/shell.def
@@ -0,0 +1,37 @@
+LIBRARY SHELL
+DESCRIPTION 'WOW REPLACEMENT SHELL'
+EXETYPE WINDOWS
+STUB '..\BIN\WINSTUB.EXE'
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+EXPORTS
+ REGOPENKEY @1 ;public
+ REGCREATEKEY @2 ;public
+ REGCLOSEKEY @3 ;public
+ REGDELETEKEY @4 ;public
+ REGSETVALUE @5 ;public
+ REGQUERYVALUE @6 ;public
+ REGENUMKEY @7 ;public
+
+ DRAGACCEPTFILES @9 ;public
+ DRAGQUERYFILE @11 ;public
+ DRAGFINISH @12 ;public
+ DRAGQUERYPOINT @13 ;public
+
+ SHELLEXECUTE @20 ;internal private for shell
+ FINDEXECUTABLE @21 ;internal private for shell
+ SHELLABOUT @22 ;internal private for shell
+ WCI @32 ;internal
+ ABOUTDLGPROC @33 ;internal
+ EXTRACTICON @34 ;public
+ EXTRACTASSOCIATEDICON @36 ;internal private for shell
+ DOENVIRONMENTSUBST @37 ;public
+ FINDENVIRONMENTSTRING @38 ;public
+ INTERNALEXTRACTICON @39 ;internal private for shell
+
+ HERETHARBETYGARS @100 ;internal
+ FINDEXEDLGPROC @101 ;internal
+ REGISTERSHELLHOOK @102 ;internal private for shell
+ SHELLHOOKPROC @103 ;internal private for shell
+ WEP ;internal
diff --git a/private/mvdm/wow16/shell/shell.rc b/private/mvdm/wow16/shell/shell.rc
new file mode 100644
index 000000000..def64770e
--- /dev/null
+++ b/private/mvdm/wow16/shell/shell.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* SHELL.RC */
+/********************************************************************/
+#include "shell.rcv"
diff --git a/private/mvdm/wow16/shell/shell.rcv b/private/mvdm/wow16/shell/shell.rcv
new file mode 100644
index 000000000..6b100e77c
--- /dev/null
+++ b/private/mvdm/wow16/shell/shell.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* SHELL.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Shell library"
+#define VER_INTERNALNAME_STR "SHELL"
+#define VER_ORIGINALFILENAME_STR "SHELL.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/sherlock/disasm.c b/private/mvdm/wow16/sherlock/disasm.c
new file mode 100644
index 000000000..7e83981ba
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/disasm.c
@@ -0,0 +1,1228 @@
+/* disasm.c
+ Future Features -
+
+ Current bugs -
+ Data32 for
+ (callf fword ptr [mem]), (jmpf fword ptr [mem])
+ Floating point insns
+ Call not tested
+ jecxz disassembled as large_address, not large_data
+ lidt/lgdt are 6-byte operands
+ segload doesn't set memXxxxx vars
+ some 0x0f opcodes should set gpSafe flag
+ bt, bts, btr, btc
+ SetBcc [mem]
+ SHD[l,r]
+*/
+
+#include <string.h>
+#include <windows.h> /* wsprintf() */
+#include "disasm.h"
+
+#define STATIC /* static */
+
+STATIC byte lookup[256]; /* lookup table for first byte of opcode */
+
+STATIC int dataSize, adrSize, /* flag to indicate 32 bit data/code */
+ segSize; /* flag if 32 bit code segment */
+STATIC char *preSeg = ""; /* segment prefix string */
+/* static char *prefix = ""; /* REP/REPE prefix string */
+
+enum { /* operand decoding classes */
+ UNK, NOOP, BREG, VREG, SREG, BWI, BRI, WRI,
+ SMOV, IMOV, IBYTE, IWORD, JMPW, JMPB, LEA, JCond,
+ GrpF, Grp1, Grp2, Grp3, Grp4, Grp5, IADR, MOVABS,
+ RRM, RRMW, IMUL, POPMEM, TEST, ENTER, FLOP, ARPL,
+ INOUT, IWORD1, ASCII, XLAT,
+};
+
+STATIC char bregs[8][3] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};
+STATIC char wregs[8][3] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
+STATIC char dregs[8][4] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
+
+STATIC char sregs[8][3] = {"es", "cs", "ss", "ds", "fs", "gs", "?", "?"};
+STATIC char grp1[8][4] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
+STATIC char grp2[8][4] = {"rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar"};
+STATIC char grp3[8][5] = {"test", "?", "not", "neg", "mul", "imul", "div", "idiv"};
+STATIC char grp5[8][6] = {"inc", "dec", "call", "callf", "jmp", "jmpf", "push", "?"};
+STATIC char grp6[8][5] = {"sldt", "str", "lldt", "ltr", "verr", "verw", "?", "?"};
+STATIC char grp7[8][7] = {"sgdt", "sidt", "lgdt", "lidt", "smsw", "?", "lmsw", "invlpg"};
+STATIC char grp8[8][4] = {"?", "?", "?", "?", "bt", "bts", "btr", "btc"};
+STATIC char *jcond[] = {"jo", "jno", "jb", "jae", "jz", "jnz", "jbe", "ja",
+ "js", "jns", "jp", "jnp", "jl", "jge", "jle", "jg"};
+
+#define opBase 0
+STATIC struct {
+ char *name; /* opcode mnemonic */
+ byte base, count; /* first table entry, number of entries */
+ byte operand; /* operand class */
+} ops[] = {
+ "?UNKNOWN", 0, 0, UNK, "add", 0x00, 6, BWI,
+ "or", 0x08, 6, BWI, "FGrp", 0x0f, 1, GrpF,
+ "adc", 0x10, 6, BWI, "sbb", 0x18, 6, BWI,
+ "and", 0x20, 6, BWI, "sub", 0x28, 6, BWI,
+ "xor", 0x30, 6, BWI, "cmp", 0x38, 6, BWI,
+ "inc", 0x40, 8, VREG, "dec", 0x48, 8, VREG,
+ "push", 0x50, 8, VREG, "pop", 0x58, 8, VREG,
+ "bound", 0x62, 1, RRMW, "arpl", 0x63, 1, ARPL,
+ "push", 0x68, 1, IWORD, "imul", 0x69, 3, IMUL,
+ "push", 0x6a, 1, IBYTE, "jcond", 0x70, 16, JCond,
+ "Grp1", 0x80, 4, Grp1, "test", 0x84, 2, RRM,
+ "xchg", 0x86, 2, RRM, "mov", 0x88, 4, BWI,
+ "mov", 0x8c, 3, SMOV, "lea", 0x8d, 1, LEA,
+ "pop", 0x8f, 1, POPMEM, "xchg", 0x90, 8, VREG,
+ "callf", 0x9a, 1, IADR, "mov", 0xa0, 4, MOVABS,
+ "test", 0xa8, 2, TEST, "mov", 0xb0, 8, BRI,
+ "mov", 0xb8, 8, WRI, "Grp2", 0xc0, 2, Grp2,
+ "retn", 0xc2, 1, IWORD1, "les", 0xc4, 1, RRMW,
+ "lds", 0xc5, 1, RRMW, "mov", 0xc6, 2, IMOV,
+ "enter", 0xc8, 1, ENTER, "retf", 0xca, 1, IWORD1,
+ "int", 0xcd, 1, IBYTE, "Grp2", 0xd0, 4, Grp2,
+ "aam", 0xd4, 1, ASCII, "aad", 0xd5, 1, ASCII,
+ "xlat", 0xd7, 1, XLAT,
+ "float", 0xd8, 8, FLOP, "loopne", 0xe0, 1, JMPB,
+ "loope", 0xe1, 1, JMPB, "loop", 0xe2, 1, JMPB,
+ "jcxz", 0xe3, 1, JMPB, "in", 0xe4, 2, INOUT,
+ "out", 0xe6, 2, INOUT, "call", 0xe8, 1, JMPW,
+ "jmp", 0xe9, 1, JMPW, "jmpf", 0xea, 1, IADR,
+ "jmp", 0xeb, 1, JMPB, "Grp3", 0xf6, 2, Grp3,
+ "Grp4", 0xfe, 1, Grp4, "Grp5", 0xff, 1, Grp5,
+};
+#define opCnt (sizeof(ops)/sizeof(ops[0]))
+
+#define simpleBase (opBase + opCnt)
+STATIC struct { /* these are single byte opcodes, no decode */
+ byte val;
+ char *name;
+} simple[] = {
+ 0x06, "push es",
+ 0x07, "pop es",
+ 0x0e, "push cs",
+ 0x16, "push ss",
+ 0x17, "pop ss",
+ 0x1e, "push ds",
+ 0x1f, "pop ds",
+ 0x27, "daa",
+ 0x2f, "das",
+ 0x37, "aaa",
+ 0x3f, "aas",
+ 0x90, "nop",
+ 0x9b, "wait",
+ 0x9e, "sahf",
+ 0x9f, "lahf",
+ 0xc3, "retn",
+ 0xc9, "leave",
+ 0xcb, "retf",
+ 0xcc, "int 3",
+ 0xce, "into",
+ 0xec, "in al, dx",
+ 0xee, "out dx, al",
+ 0xf0, "lock",
+ 0xf2, "repne",
+ 0xf3, "rep/repe",
+ 0xf4, "hlt",
+ 0xf5, "cmc",
+ 0xf8, "clc",
+ 0xf9, "stc",
+ 0xfa, "cli",
+ 0xfb, "sti",
+ 0xfc, "cld",
+ 0xfd, "std",
+};
+#define simpleCnt (sizeof(simple)/sizeof(simple[0]))
+
+#define dSimpleBase (simpleBase + simpleCnt)
+STATIC struct { /* these are simple opcodes that change */
+ byte val; /* based on current data size */
+ char *name, *name32;
+} dsimple[] = {
+ 0x60, "pusha", "pushad",
+ 0x61, "popa", "popad",
+ 0x98, "cbw", "cwde",
+ 0x99, "cwd", "cdq",
+ 0x9c, "pushf", "pushfd",
+ 0x9d, "popf", "popfd",
+ 0xcf, "iret", "iretd",
+ 0xed, "in ax, dx", "in eax, dx",
+ 0xef, "out dx, ax", "out dx, eax",
+};
+#define dSimpleCnt (sizeof(dsimple)/sizeof(dsimple[0]))
+
+#define STR_S 1 /* string op, source regs */
+#define STR_D 2 /* string op, dest regs */
+#define STR_D_Read 4 /* string op, reads from dest regs */
+#define STR_NO_COND 8 /* rep ignores flags */
+#define stringOpBase (dSimpleBase+ dSimpleCnt)
+STATIC struct {
+ byte val;
+ char *name;
+ byte flag; /* should be 'next' to op, to pack nicely */
+} stringOp[] = {
+ 0x6c, "ins", STR_D | STR_NO_COND,
+ 0x6e, "outs", STR_S | STR_NO_COND,
+ 0xa4, "movs", STR_S | STR_D | STR_NO_COND,
+ 0xa6, "cmps", STR_S | STR_D | STR_D_Read,
+ 0xaa, "stos", STR_D | STR_NO_COND,
+ 0xac, "lods", STR_S | STR_NO_COND,
+ 0xae, "scas", STR_D | STR_D_Read,
+};
+#define stringOpCnt (sizeof(stringOp)/sizeof(stringOp[0]))
+
+STATIC void InitDisAsm86(void) {
+ int i, j;
+ for (i=0; i<opCnt; i++) { /* Init complex entries */
+ for (j=0; j<(int)ops[i].count; j++)
+ lookup[ops[i].base+j] = (byte)i + opBase;
+ }
+
+ for (i=0; i<simpleCnt; i++) /* Init simple entries */
+ lookup[simple[i].val] = (byte)(i + simpleBase);
+
+ for (i=0; i<dSimpleCnt; i++) /* Init simple 16/32 bit entries */
+ lookup[dsimple[i].val] = (byte)(i + dSimpleBase);
+
+ for (i=0; i<stringOpCnt; i++) { /* Init string op table */
+ lookup[stringOp[i].val] = (byte)(i + stringOpBase);
+ lookup[stringOp[i].val+1] = (byte)(i + stringOpBase);
+ }
+} /* InitDisAsm86 */
+
+STATIC byte far *code; /* this is ugly - it saves passing current */
+ /* code position to all the GetByte() funcs */
+
+#define Mid(v) (((v) >> 3) & 7) /* extract middle 3 bits from a byte */
+
+word gpSafe, gpRegs, gpStack; /* indicate side effects of instruction */
+
+extern word regs[]; /* this is a lie - this is really a struct - */
+extern dword regs32[]; /* and so is this - but array access is more */
+ /* convenient in this module */
+
+ /* If you don't want to return memory access info, #def NO_MEM */
+#if !defined(NO_MEM)
+ /* global vars set by DisAsm() to indicate current instruction's memory */
+ /* access type. */
+word memSeg, memSize, memOp; /* segment value, operand size, operation */
+word memSeg2, memSize2, memOp2, /* instruction may have two memory accesses */
+ memDouble;
+dword memLinear, memLinear2; /* offset from segment of access */
+
+STATIC dword memReg, memDisp; /* used to pass information from GetReg()... */
+char *memName[] = { /* used to convert 'enum memOp' to ascii */
+ "NOP",
+ "Read",
+ "Write",
+ "RMW",
+ "MovStr",
+};
+
+#define SetMemSize(s) memSize = s
+#define SetMemSeg(s) memSeg = regs[s+9]
+#define SetMemOp(o) memOp = o
+#define SetMemLinear(l) memLinear = l
+#define SetMemSeg2(s) memSeg2 = regs[s+9]
+#define SetMemOp2(o) memOp2 = o
+#define SetMemLinear2(l) memLinear2 = l
+#define ModMemLinear(l) memLinear += l
+#define SetMemReg(r) memReg = r
+#define SetMemDisp(d) memDisp = d
+#define Read_RMW(o) ((o) ? memRead : memRMW)
+
+#else
+
+#define SetMemSeg(s)
+#define SetMemSize(s)
+#define SetMemOp(o)
+#define SetMemLinear(l)
+#define SetMemSeg2(s)
+#define SetMemOp2(o)
+#define SetMemLinear2(l)
+#define ModMemLinear(l)
+#define SetMemReg(r)
+#define SetMemDisp(d)
+#define Read_RMW(o) 0
+
+#endif
+
+/******************** Register Decode *******************************/
+/* These helper functions return char pointers to register names.
+ They are safe to call multiple times, as the return values are not
+ stored in a single buffer. The ?Reg() functions are passed a register
+ number. They mask this with 7, so you can pass in the raw opcode.
+ The ?Mid() functions extract the register field from e.g. a ModRM byte.
+ The Vxxx() functions look at dataSize to choose between 16 and 32 bit
+ registers. The Xxxx() functions look at the passed in W bit, and then
+ the dataSize global, do decide between 8, 16, and 32 bit registers.
+*/
+
+STATIC char *BReg(int reg) { /* Byte Registers */
+ reg &= 7;
+ SetMemReg(((byte *)regs)[reg]);
+ return bregs[reg];
+} /* BReg */
+
+STATIC char *BMid(int reg) {
+ return BReg(Mid(reg));
+} /* BMid */
+
+STATIC char *WReg(int reg) { /* Word Registers */
+ reg &= 7;
+ SetMemReg(regs[reg]);
+ return wregs[reg];
+} /* WReg */
+
+/* STATIC char *WMid(int op) {
+ return WReg(Mid(op));
+} /* WMid */
+
+STATIC char *DReg(int reg) { /* DWord Registers */
+ reg &= 7;
+ SetMemReg(regs32[reg]);
+ return dregs[reg];
+} /* DReg */
+
+STATIC char *DMid(int op) {
+ return DReg(Mid(op));
+} /* DMid */
+
+STATIC char *VReg(int reg) { /* Word or DWord Registers */
+ if (dataSize) return DReg(reg);
+ return WReg(reg);
+} /* VReg */
+
+STATIC char *VMid(int op) {
+ return VReg(Mid(op));
+} /* VMid */
+
+STATIC char *XReg(int w, int reg) { /* Byte, Word, DWord Registers */
+ if (!w) return BReg(reg);
+ return VReg(reg);
+} /* XReg */
+
+STATIC char *XMid(int w, int op) {
+ return XReg(w, Mid(op));
+} /* XMid */
+
+/************************* Opcode Fetch ***************************/
+
+ /* hexData is a global array, containing a hexadecimal dump of the */
+ /* opcodes of the last instruction disassembled. */
+char hexData[40]; /* We dump the opcode fetched here */
+STATIC int hexPos; /* current position in hexData buffer */
+
+ /* GetByte(), GetWord(), and GetDWord() read from the code segment */
+ /* and increment the pointer appropriately. They also add the current */
+ /* value to the hexData display, and set the MemDisp global in case the */
+ /* value fetched was a memory displacement */
+STATIC byte GetByte(void) { /* Read one byte from code segment */
+ sprintf(hexData+hexPos, " %02x", *code);
+ hexPos += 3;
+ SetMemDisp(*code);
+ return *code++;
+} /* GetByte */
+
+STATIC word GetWord(void) { /* Read two bytes from code seg */
+ word w = *(word far *)code;
+ sprintf(hexData+hexPos, " %04x", w);
+ hexPos += 5;
+ code += 2;
+ SetMemDisp(w);
+ return w;
+} /* GetWord */
+
+STATIC long GetDWord(void) { /* Read four bytes from code seg */
+ unsigned long l = *(long far *)code;
+ sprintf(hexData+hexPos, " %08lx", l);
+ hexPos += 9;
+ code += 4;
+ SetMemDisp(l);
+ return l;
+} /* GetDWord */
+
+
+STATIC char immData[9]; /* Get Immediate values from code */
+
+
+ /* GetImmByte(), GetImmWord(), and GetImmDWord() all get the proper size */
+ /* data object, convert it to hex/ascii, and return the string created. */
+ /* They return a pointer to a shared static object, so don't combine */
+ /* multiple calls to these functions in a single expression. */
+STATIC char *GetImmByte(void) {
+ sprintf(immData, "%02x", GetByte());
+ return immData;
+} /* GetImmByte */
+
+STATIC char *GetSImmByte(void) {
+ sprintf(immData, "%02x", (char)GetByte());
+ memDisp = (signed char)memDisp; /* sign extend */
+ return immData;
+} /* GetSImmByte */
+
+STATIC char *GetImmWord(void) {
+ sprintf(immData, "%04x", GetWord());
+ return immData;
+} /* GetImmWord */
+
+STATIC char *GetImmDWord(void) {
+ sprintf(immData, "%08lx", GetDWord());
+ return immData;
+} /* GetImmDWord */
+
+ /* GetImmAdr() and GetImmData() call GetImm????() as required by the */
+ /* 'width' flag passed in, and the adrSize or dataSize global flags. */
+ /* They return the proper character string - note that these just call */
+ /* GetImm????(), and use the same static buffer, so don't call more than */
+ /* once in a single expression */
+STATIC char *GetImmAdr(int w) { /* Get an immediate address value */
+ if (!w) return GetImmByte();
+ else if (!adrSize) return GetImmWord();
+ return GetImmDWord();
+} /* GetImmAdr */
+
+STATIC char *GetImmData(int w) { /* Get an immediate data value */
+ if (!w) return GetImmByte();
+ else if (!dataSize) return GetImmWord();
+ return GetImmDWord();
+} /* GetImmData */
+
+/************************* Helper Functions **************************/
+
+STATIC char *JRel(int jsize) { /* Perform relative jump sizing */
+ long rel;
+ static char adr[9];
+ char *s;
+
+ if (jsize < 2) {
+ rel = (char)GetByte();
+ s = "short ";
+ } else if (!adrSize) {
+ rel = (short)GetWord();
+ s = "near ";
+ } else {
+ rel = GetDWord();
+ s = "";
+ }
+ rel += (word)(long)code;
+ sprintf(adr, adrSize ? "%s%08lx" : "%s%04lx", (FP)s, rel);
+ return adr;
+} /* JRel */
+
+
+enum {
+ RegAX, RegCX, RegDX, RegBX, RegSP, RegBP, RegSI, RegDI
+};
+
+#define Reg1(r1) (r1) | 0x80
+#define Reg2(r1, r2) (r1 | (r2 << 4))
+#define RegSS 8
+
+STATIC byte rms[] = { /* 16 bit addressing modes */
+ Reg2(RegBX, RegSI),
+ Reg2(RegBX, RegDI),
+ Reg2(RegBP|RegSS, RegSI), /* if base reg is BP, def seg is SS */
+ Reg2(RegBP|RegSS, RegDI),
+ Reg1(RegSI),
+ Reg1(RegDI),
+ Reg1(RegBP|RegSS),
+ Reg1(RegBX),
+};
+
+ /* Based on the second byte of opcode, width flag, adrSize and dataSize, */
+ /* determine the disassembly of the current instruction, and what */
+ /* memory address was referenced */
+ /* needinfo indicates that we need a size override on a memory operand */
+ /* for example, "mov [bx], ax" is obviously a 16 bit move, while */
+ /* "mov [bx], 0" could be 8, 16, or 32 bit. We add the proper */
+ /* "mov word ptr [bx], 0" information. */
+ /* The 'mem' parameter indicates the kind of operation, Read, Write, RMW */
+
+ /* don't bother trying to understand this code without an Intel manual */
+ /* and assembler nearby. :-) */
+STATIC char *ModRMGeneral(byte op, int w, int needInfo, int mem) {
+ static char m[30]; /* write result to this static buf */
+ int mod = op >> 6;
+ int rm = op & 7;
+ char *size, *base, *index, *disp;
+ char indexBuf[6];
+
+ base = index = disp = "";
+ if (!w) { /* set mem size, and info string */
+ size = "byte ptr ";
+ SetMemSize(1);
+ } else if (!dataSize) {
+ size = "word ptr ";
+ SetMemSize(2);
+ } else {
+ size = "dword ptr ";
+ SetMemSize(4);
+ }
+ if (!needInfo) size = ""; /* never-mind */
+
+ if (adrSize) { /* do 32 bit addressing */
+ if (mod == 3) return XReg(w, rm); /* register operand */
+
+ if (rm == 4) { /* [esp+?] is special S-I-B style */
+ byte sib = GetByte();
+ int scaleVal = sib >> 6, indexVal = Mid(sib), baseVal = sib & 7;
+
+ SetMemLinear(0);
+ if (baseVal == 5 && mod == 0) /* [ebp+{s_i}] becomes [d32+{s_i}] */
+ mod = 2;
+ else {
+ base = DReg(baseVal);
+ ModMemLinear(memReg);
+ }
+
+ if (indexVal != 4) { /* [base+esp*X] is undefined */
+ sprintf(indexBuf, "%s*%d", (FP)DMid(sib), 1 << scaleVal);
+ index = indexBuf;
+ ModMemLinear(memReg << scaleVal);
+ }
+ } else { /* not S-I-B */
+ if (mod == 0 && rm == 5) mod = 2; /* [ebp] becomes [d32] */
+ else base = DReg(rm);
+ }
+
+ if (mod==1) disp = GetImmAdr(0);
+ else if (mod == 2) disp = GetImmAdr(1);
+ if (mod) ModMemLinear(memDisp);
+
+ } else { /* do 16 bit addressing */
+ if (mod == 3) return XReg(w, rm); /* register operand */
+ if (mod == 0 && rm == 6) { /* [bp] becomes [mem16] */
+ disp = GetImmAdr(1);
+ SetMemLinear(memDisp);
+ } else {
+ base = WReg(rms[rm] & 7);
+ SetMemLinear(memReg);
+ if (!(rms[rm] & 0x80)) { /* if two-reg effective address */
+ index = WReg(rms[rm] >> 4);
+ ModMemLinear(memReg);
+ }
+ if (rms[rm] & RegSS && !preSeg[0]) { /* BP is relative to SS */
+ SetMemSeg(memSS);
+ }
+ if (mod) { /* (mod3 already returned) */
+ disp = GetImmAdr(mod-1); /* mod==1 is byte, mod==2 is (d)word */
+ ModMemLinear(memDisp);
+ }
+ }
+ }
+ sprintf(m, "%s%s[%s", (FP)size, (FP)preSeg, (FP)base);
+ if (*index) strcat(strcat(m, "+"), index);
+ if (*disp) {
+ if (*base || *index) strcat(m, "+");
+ strcat(m, disp);
+ }
+ SetMemOp(mem);
+ strcat(m, "]");
+ return m;
+} /* ModRMGeneral */
+
+ /* magic func that sets 'info-required' flag to ModRMGeneral */
+STATIC char *ModRMInfo(byte op, int w, int mem) {
+ return ModRMGeneral(op, w, 1, mem);
+} /* ModRMInfo */
+
+ /* magic func that doesn't require info */
+STATIC char *ModRM(byte op, int w, int mem) {
+ return ModRMGeneral(op, w, 0, mem);
+} /* ModRM */
+
+
+STATIC char line[80]; /* this is bad - global var where insn is created */
+
+ /* CatX() - combine opcode and 0 to 3 operands, store in line[] */
+ /* It places the TAB after the opcode, and ', ' between operands */
+
+STATIC char *Cat0(char *s0) {
+ return strcat(line, s0);
+#if 0
+ if (prefix[0]) {
+ char temp[80];
+ if (s0 == line) {
+ strcpy(temp, s0);
+ s0 = temp;
+ }
+ strcat(strcpy(line, prefix), s0);
+ prefix = "";
+ } else strcpy(line, s0);
+ return line;
+#endif
+} /* Cat0 */
+
+STATIC char *Cat1(char *s0, char *s1) {
+ return strcat(strcat(Cat0(s0), "\t"), s1);
+} /* Cat1 */
+
+STATIC char *Cat2(char *s0, char *s1, char *s2) {
+ return strcat(strcat(Cat1(s0, s1), ", "), s2);
+} /* Cat2 */
+
+STATIC char *Cat3(char *s0, char *s1, char *s2, char *s3) {
+ return strcat(strcat(Cat2(s0, s1, s2), ", "), s3);
+} /* Cat3 */
+
+#define SetGroup(g) /* group = g */
+/* STATIC int group; */
+
+ /* Disassemble the 386 instructions whose first opcode is 0x0f */
+ /* Sorry, but this is just too ugly to comment */
+STATIC char *DisAsmF(void) {
+ byte op0, op1;
+ char temp[8];
+ char *s0, *s1;
+ int mask;
+
+ op0 = GetByte();
+ switch (op0 >> 4) { /* switch on top 4 bits of opcode */
+ case 0:
+ switch (op0 & 0xf) {
+ case 0: /* grp6 */
+ SetGroup(2);
+ op1 = GetByte();
+ dataSize = 0;
+ return Cat1(grp6[Mid(op1)], ModRMInfo(op1, 1, Read_RMW(Mid(op1) >= 2)));
+ case 1: /* grp7 */
+ SetGroup(2);
+ op1 = GetByte();
+ dataSize = 0;
+ return Cat1(grp7[Mid(op1)], ModRMInfo(op1, 1, Read_RMW(Mid(op1) & 2)));
+ case 2:
+ op1 = GetByte();
+ s1 = VMid(op1);
+ /* dataSize = 0; */
+ return Cat2("lar", s1, ModRMInfo(op1, 1, memRead));
+ case 3:
+ op1 = GetByte();
+ s1 = VMid(op1);
+ /* dataSize = 0; */
+ return Cat2("lsl", s1, ModRMInfo(op1, 1, memRead));
+ case 6: return "clts";
+ case 8: return "invd";
+ case 9: return "wbinvd";
+ }
+ break;
+
+ case 2: /* Mov C/D/Treg, reg */
+ op1 = GetByte();
+ switch (op0 & 0xf) {
+ case 0:
+ case 2:
+ s1 = "c";
+ mask = 1 + 4 + 8;
+ break;
+ case 1:
+ case 3:
+ s1 = "d";
+ mask = 1 + 2 + 4 + 8 + 64 + 128;
+ break;
+ case 4:
+ case 6:
+ s1 = "t";
+ mask = 8 + 16 + 32 + 64 + 128;
+ break;
+ default:
+ s1 = "??";
+ mask = 0;
+ }
+ if (!((1 << Mid(op1)) & mask)) /* various legal register combos */
+ return "Illegal reg";
+
+ s0 = DReg(op1);
+ if (op0 & 2) sprintf(line, "mov\t%sr%d, %s", (FP)s1, Mid(op1), (FP)s0);
+ else sprintf(line, "mov\t%s, %sr%d", (FP)s0, (FP)s1, Mid(op1));
+ return line;
+
+ case 8: /* long displacement jump on condition */
+ return Cat1(jcond[op0&0xf], JRel(2));
+
+ case 9: /* byte set on condition */
+ strcpy(temp, "set");
+ strcat(temp, jcond[op0&0xf]+1);
+ return Cat1(temp, ModRMInfo(GetByte(), 0, memWrite));
+
+ case 0xa:
+ switch (op0 & 0xf) {
+ case 0: return "push fs";
+ case 1: return "pop fs";
+ case 3: case 0xb:
+ s0 = op0 & 8 ? "bts" : "bt";
+ op1 = GetByte();
+ return Cat2(s0, ModRM(op1, 1, memRMW), VMid(op1));
+ case 4: case 0xc:
+ s0 = op0 & 8 ? "shrd" : "shld";
+ op1 = GetByte();
+ s1 = ModRM(op1, 1, memRMW);
+ return Cat3(s0, s1, VMid(op1), GetImmData(0));
+ case 5: case 0xd:
+ s0 = op0 & 8 ? "shrd" : "shld";
+ op1 = GetByte();
+ s1 = ModRM(op1, 1, memRMW);
+ return Cat3(s0, s1, VMid(op1), "cl");
+ case 6:
+ op1 = GetByte();
+ return Cat2("cmpxchg", ModRM(op1, 0, memRMW), BMid(op1));
+ case 7:
+ op1 = GetByte();
+ return Cat2("cmpxchg", ModRM(op1, 1, memRMW), VMid(op1));
+ case 8: return "push gs";
+ case 9: return "pop gs";
+ case 0xf:
+ op1 = GetByte();
+ return Cat2("imul", VMid(op1), ModRM(op1, 1, memRead));
+ }
+ break;
+
+ case 0xb:
+ switch (op0 & 0xf) {
+ case 2: case 4: case 5:
+ s0 = (op0 & 2) ? "lss" : (op0 &1) ? "lgs" : "lfs";
+ op1 = GetByte();
+ return Cat2(s0, VMid(op1), ModRM(op1, 1, memRead));
+ case 3: case 0xb:
+ s0 = (op0 & 8) ? "btc": "btr";
+ op1 = GetByte();
+ return Cat2(s0, ModRM(op1, 1, memRMW), VMid(op1));
+ case 6: case 7: case 0xe: case 0xf:
+ s0 = (op0 & 8) ? "movsx" : "movzx";
+ op1 = GetByte();
+ s1 = VMid(op1);
+ dataSize = 0;
+ return Cat2(s0, s1, ModRMInfo(op1, op0&1, memRead));
+ case 0xa:
+ SetGroup(2);
+ op1 = GetByte();
+ s0 = grp8[Mid(op1)];
+ s1 = ModRMInfo(op1, 1, memRMW);
+ return Cat2(s0, s1, GetImmData(0));
+ case 0xc: case 0xd:
+ op1 = GetByte();
+ s0 = (op0 & 1) ? "bsr" : "bsf";
+ return Cat2(s0, VMid(op1), ModRM(op1, 1, memRead));
+ }
+ break;
+
+ case 0xc:
+ if (op0 > 0xc7) return Cat1("bswap", DReg(op0 & 7));
+ if (op0 < 0xc2) {
+ op1 = GetByte();
+ return Cat2("xadd", ModRM(op1, op0&1, memRMW), XMid(op0&1, op1));
+ }
+ break;
+ default:
+ break;
+ }
+ sprintf(line, "?Unknown 0f %02x", op0);
+ return line;
+} /* DisAsmF */
+
+int IsPrefix(byte op0) {
+ switch (op0) { /* check for prefix bytes */
+
+#define CSEG 0x2e
+#define DSEG 0x3e
+#define ESEG 0x26
+#define SSEG 0x36
+#define FSEG 0x64
+#define GSEG 0x65
+#define REP 0xf3
+#define REPNE 0xf2
+#define DATA32 0x66
+#define ADR32 0x67
+
+ case CSEG: preSeg = "cs:"; SetMemSeg(memCS); break;
+ case DSEG: preSeg = "ds:"; SetMemSeg(memDS); break;
+ case ESEG: preSeg = "es:"; SetMemSeg(memES); break;
+ case SSEG: preSeg = "ss:"; SetMemSeg(memSS); break;
+ case FSEG: preSeg = "fs:"; SetMemSeg(memFS); break;
+ case GSEG: preSeg = "gs:"; SetMemSeg(memGS); break;
+ case REP: strcpy(line, "repe\t"); gpRegs |= strCX; break;
+ case REPNE: strcpy(line, "repne\t"); gpRegs |= strCX; break;
+ case ADR32:
+ /* printf("Adr32\n"); */
+ adrSize = !adrSize; break;
+ case DATA32:
+ /* printf("Data32\n"); */
+ dataSize = !dataSize; break;
+ default:
+ return 0;
+ }
+ return 1;
+} /* IsPrefix */
+
+ /* like, call this with a pointer to the instruction, it will return */
+ /* the opcode bytes used in *len, and a pointer to the disassembled insn */
+char *DisAsm86(byte far *codeParm, int *len) {
+ byte far *oldcode;
+ byte op0, op1;
+ byte opclass;
+ static int init;
+ char operand[40];
+ char *(*Reg)(int);
+ char *s0, *s1, *s2, *s3;
+
+ if (!init) {
+ InitDisAsm86();
+ init = 1;
+ }
+ adrSize = dataSize = segSize;
+ preSeg = "";
+ hexPos = 0;
+ memDouble = 0;
+ line[0] = 0;
+ gpSafe = gpRegs = gpStack = 0;
+ code = oldcode = codeParm;
+ do {
+ op0 = GetByte();
+ } while (IsPrefix(op0));
+ opclass = lookup[op0];
+
+ SetMemOp(memNOP);
+ if (!preSeg[0]) SetMemSeg(memDS);
+
+ if (opclass >= simpleBase) { /* is it special */
+ if (opclass >= stringOpBase) { /* string operations? */
+ char cmd;
+
+ opclass -= stringOpBase;
+ cmd = stringOp[opclass].flag;
+ if (cmd & STR_NO_COND) strcpy(line+3, "\t");
+ if (cmd & STR_S) {
+ gpRegs |= strSI;
+ SetMemOp(memRead);
+ /* DS already set */
+ VReg(RegSI);
+ SetMemLinear(memReg);
+ if (cmd & STR_D) {
+ gpRegs |= strDI;
+ SetMemOp2(cmd & STR_D_Read ? memRead : memWrite);
+ SetMemSeg2(memES);
+ VReg(RegDI);
+ SetMemLinear2(memReg);
+ memDouble = 1;
+ }
+ } else {
+ gpRegs |= strDI;
+ SetMemOp(cmd & STR_D_Read ? memRead : memWrite);
+ SetMemSeg(memES);
+ VReg(RegDI);
+ SetMemLinear(memReg);
+ }
+
+ if (op0 & 1) {
+ if (dataSize) { s1 = "d"; SetMemSize(4); }
+ else { s1 = "w"; SetMemSize(2); }
+ } else { s1 = "b"; SetMemSize(1); }
+
+
+ s0 = strcat(strcpy(operand, stringOp[opclass].name), s1);
+ } else if (opclass >= dSimpleBase) {
+ opclass -= dSimpleBase;
+ s0 = dataSize ? dsimple[opclass].name32 : dsimple[opclass].name;
+ } else {
+ s0 = simple[opclass-simpleBase].name;
+ if (op0 == 7) { /* pop ES */
+ gpRegs = segES;
+ gpSafe = 1;
+ gpStack = 1;
+ } else if (op0 == 0x1f) { /* pop DS */
+ gpRegs = segDS;
+ gpSafe = 1;
+ gpStack = 1;
+ }
+ }
+ Cat0(s0);
+ goto DisAsmDone;
+ }
+
+ if (op0 == 0x0f) { /* is it an extended opcode? */
+ s0 = DisAsmF();
+ strcpy(line, s0);
+ goto DisAsmDone;
+ }
+
+ s0 = ops[opclass].name;
+ switch (ops[opclass].operand) {
+ case NOOP:
+ Cat0(s0);
+ break;
+
+ case VREG: /* inc, dec, push, pop, xchg */
+ if ((op0 & ~7) == 0x90) Cat2(s0, "ax", VReg(op0&7));
+ else Cat1(s0, VReg(op0&7));
+ /* Set memop for Push/Pop as modifying stack values */
+ break;
+
+ case BWI: /* byte/word/immediate */
+ gpSafe = 1;
+ if (!(op0&1)) Reg = BReg;
+ else if (!dataSize) Reg = WReg;
+ else Reg = DReg;
+ if (op0 & 4) {
+ Cat2(s0, Reg(0), GetImmData(op0&1));
+ } else {
+ int i;
+ op1 = GetByte();
+ if ((op0 & 0xf8) == 0x38) i = memRead;
+ else if ((op0 & 0xfe) == 0x88) i = memWrite;
+ else i = Read_RMW(op0 & 2);
+ s1 = ModRM(op1, op0&1, i);
+ s2 = Reg(Mid(op1));
+ if (op0 & 2) {
+ s3 = s2; s2 = s1; s1 = s3;
+ }
+ Cat2(s0, s1, s2);
+ }
+ break;
+
+ case BRI: /* byte reg immediate */
+ Cat2(s0, BReg(op0 & 7), GetImmData(0));
+ break;
+
+ case WRI: /* word reg immediate */
+ Cat2(s0, VReg(op0 & 7), GetImmData(1));
+ break;
+
+ case Grp1: /* group 1 instructions */
+ gpSafe = 1;
+ SetGroup(1);
+ op1 = GetByte();
+ s1 = ModRMInfo(op1, op0&1, Mid(op1) == 7 ? memRead : memRMW);
+ Cat2(grp1[Mid(op1)], s1, GetImmData((op0&3)==1));
+ break;
+
+ case Grp2: /* group 2 instructions */
+ gpSafe = 1;
+ SetGroup(1);
+ op1 = GetByte();
+ s1 = ModRMInfo(op1, op0&1, memRMW);
+ s2 = (op0 & 0x10) ? (op0 & 2 ? "cl" : "1") : GetImmData(0);
+ Cat2(grp2[Mid(op1)], s1, s2);
+ break;
+
+ case Grp3: /* group 3 instructions */
+ gpSafe = 1;
+ SetGroup(1);
+ op1 = GetByte();
+ s1 = ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) <2 || Mid(op1) >3));
+ s0 = grp3[Mid(op1)];
+ if (Mid(op1) < 2) Cat2(s0, s1, GetImmData(op0&1));
+ else Cat1(s0, s1);
+ break;
+
+ case Grp4: /* group 4 instructions */
+ SetGroup(1);
+ op1 = GetByte();
+ if (Mid(op1) > 1) Cat0("?");
+ else {
+ Cat1(grp5[Mid(op1)], ModRMInfo(op1, op0&1, memRMW));
+ gpSafe = 1;
+ }
+ break;
+
+ case Grp5: /* group 5 instructions */
+ op1 = GetByte();
+ if (Mid(op1) < 3) {
+ gpSafe = 1;
+ if (Mid(op1) == 2) {
+ gpStack = -1 << dataSize;
+ }
+ }
+ SetGroup(1);
+ Cat1(grp5[Mid(op1)], ModRMInfo(op1, op0&1, Read_RMW(Mid(op1) >= 2)));
+ break;
+
+ case SMOV: /* segment move */
+ gpSafe = 1;
+ op1 = GetByte();
+ dataSize = 0;
+ s1 = ModRM(op1, 1, Read_RMW(op0&2));
+ s2 = sregs[Mid(op1)];
+ if (op0 & 2) { /* if moving _to_ SREG */
+ s3 = s2; s2 = s1; s1 = s3; /* switch operands */
+ switch (Mid(op1)) {
+ case 0: gpRegs = segES; break;
+ case 3: gpRegs = segDS; break;
+ case 4: gpRegs = segFS; break;
+ case 5: gpRegs = segGS; break;
+ default: gpSafe = 0;
+ }
+ }
+ Cat2(s0, s1, s2);
+ break;
+
+ case IMOV: /* immediate move to reg/mem */
+ gpSafe = 1;
+ op1 = GetByte();
+ s1 = ModRMInfo(op1, op0&1, memWrite);
+ Cat2(s0, s1, GetImmData(op0&1));
+ break;
+
+ case IBYTE: /* immediate byte to reg */
+ sprintf(line, "%s\t%02x", (FP)s0, (char)GetByte());
+ break;
+
+ case IWORD: /* immediate word to reg - size of data */
+ Cat1(s0, GetImmData(1));
+ break;
+
+ case IWORD1: /* immediate word - always 16 bit */
+ Cat1(s0, GetImmWord());
+ break;
+
+ case JMPW:
+ Cat1(s0, JRel(2));
+ break;
+
+ case JMPB:
+ Cat1(s0, JRel(1));
+ break;
+
+ case LEA:
+ op1 = GetByte();
+ Cat2(s0, VMid(op1), ModRM(op1, 1, memNOP));
+ break;
+
+ case JCond:
+ Cat1(jcond[op0&0xf], JRel(1));
+ break;
+
+ case IADR:
+ s2 = GetImmAdr(1);
+ sprintf(line, "%s\t%04x:%s", (FP)s0, GetWord(), (FP)s2);
+ break;
+
+ case MOVABS: /* move between accum and abs mem address */
+ gpSafe = 1;
+ s1 = XReg(op0 & 1, 0);
+ sprintf(operand, "[%s%s]", (FP)preSeg, (FP)GetImmAdr(1));
+ SetMemLinear(memDisp);
+ SetMemSize(!(op0&1) ? 1 : (!dataSize ? 2 : 4));
+ SetMemOp(op0&2 ? memWrite : memRead);
+ s2 = operand;
+ if (op0 & 2) {
+ s3 = s2; s2 = s1; s1 = s3;
+ }
+ Cat2(s0, s1, s2);
+ break;
+
+ case IMUL:
+ op1 = GetByte();
+ s1 = VMid(op1);
+ s2 = ModRM(op1, 1, memRead);
+ s3 = GetImmData(!(op0&2));
+ Cat3(s0, s1, s2, s3);
+ break;
+
+ case POPMEM:
+ gpSafe = 1;
+ gpStack = 1 << dataSize;
+ Cat1(s0, ModRMInfo(GetByte(), 1, memWrite));
+ break;
+
+ case RRM: /* test and xchg */
+ gpSafe = 1;
+ op1 = GetByte();
+ s2 = ModRM(op1, op0&1, memRMW);
+ Cat2(s0, XMid(op0&1, op1), s2);
+ break;
+
+ case RRMW: /* bound, les, lds */
+ op1 = GetByte();
+ switch (op0) {
+ case 0xc4: /* les reg, [mem] */
+ gpRegs = segES;
+ gpSafe = 1;
+ break;
+ case 0xc5: /* lds reg, [mem] */
+ gpRegs = segDS;
+ gpSafe = 1;
+ break;
+ }
+ Cat2(s0, VMid(op1), ModRM(op1, 1, memRead));
+ break;
+
+ case TEST: /* test al/ax/eax, imm */
+ Cat2(s0, XReg(op0&1, 0), GetImmData(op0&1));
+ break;
+
+ case ENTER:
+ strcpy(operand, GetImmWord());
+ Cat2(s0, operand, GetImmData(0));
+ break;
+
+ case FLOP:
+ op1 = GetByte();
+ Cat1(s0, ModRMInfo(op1, 1, memNOP));
+ break;
+
+ case ARPL:
+ op1 = GetByte();
+ dataSize = 0;
+ s1 = ModRM(op1, 1, memRMW);
+ s2 = VMid(op1);
+ Cat2(s0, s1, s2);
+ break;
+
+ case INOUT:
+ s1 = XReg(op0&1, 0);
+ s2 = GetImmAdr(0);
+ if (op0 & 2) {
+ s3 = s2; s2 = s1; s1 = s3;
+ }
+ Cat2(s0, s1, s2);
+ break;
+
+ case ASCII:
+ Cat0(GetByte() == 10 ? s0 : "?");
+ break;
+
+ case XLAT:
+ gpSafe = 1;
+ SetMemOp(memRead);
+ SetMemLinear(regs[RegBX] + (regs[RegAX] & 0xff));
+ break;
+
+ default:
+ sprintf(line, "?Unknown opcode %02x", op0);
+ }
+DisAsmDone:
+ *len = (int)(code - oldcode);
+ return line;
+} /* DisAsm86 */
+
+ /* if you're in a 32 bit code segment, call DisAsm386 which sets */
+ /* default data and address size to 32 bit */
+char *DisAsm386(byte far *code, int *len) {
+ adrSize = dataSize = 1;
+ return DisAsm86(code, len);
+} /* DisAsm386 */
+
+/* #define FOOBAR */
+#if defined(FOOBAR)
+
+STATIC int GroupSize(int op) {
+ if (op == 0xf) return 256;
+/* op = lookup[op];
+ if (op > 0x80) return 1;
+ if (ops[op].name[0] == 'G') return 8;
+ if (ops[op].name[0] == 'F') return 256; */
+ return 1;
+} /* IsGroup */
+
+/* #pragma inline */
+
+void testfunc() {
+/* asm {
+ .386p
+ mov eax, ss:[si+33h]
+ rep movsb
+ mov eax, ds:[ebp+eax*2+1234h]
+ } */
+}
+
+
+byte foo[10];
+
+/* #include <dos.h> */
+
+extern void DisTest(), EndTest();
+
+word regs[] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, -1, -1,
+ 0xeeee, 0xcccc, 0x5555, 0xdddd, 0xffff, 0x6666};
+dword regs32[] = {0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000};
+
+STATIC char *Tab2Spc(char *temp) {
+ char newbuf[80], *s1, *s2;
+ s1 = temp;
+ s2 = newbuf;
+ while ((*s2 = *s1++) != 0) {
+ if (*s2++ == 9) {
+ s2[-1] = ' ';
+ while ((s2-newbuf) & 7) *s2++ = ' ';
+ }
+ }
+ strcpy(temp, newbuf);
+ return temp;
+} /* Tab2Spc */
+
+
+void MemTest(void) {
+ void far *vp = (void far *)DisTest;
+ byte far *cp = vp, far *ep;
+ int len;
+ char *s;
+
+ vp = (void far *)EndTest;
+ ep = vp;
+
+ while (cp < ep) {
+ s = DisAsm86(cp, &len);
+ Tab2Spc(s);
+ printf("\n%04x\t%-28s", (int)cp, s);
+ if (memOp) {
+ printf("%04x:%04lx(%d) %-6s ",
+ memSeg, memLinear, memSize, memName[memOp]);
+ if (memDouble) {
+ printf("%04x:%04lx(%d) %-6s",
+ memSeg2, memLinear2, memSize, memName[memOp2]);
+ }
+ }
+ memSeg = memLinear = memSize = memOp = 0;
+ cp += len;
+ }
+} /* MemTest */
+
+void main(void) {
+#if 0
+ int i, j, g;
+ void far *vp = (void far *)DisTest;
+ byte far *cp = vp;
+ byte far *ep;
+ int len = 3, count;
+ char *s;
+#endif
+ MemTest();
+#if 0
+ vp = (void far *)EndTest;
+ ep = vp;
+ printf("DisAsm86\n", (int)foo << len);
+
+ for (i=0; i<9; i++) foo[i] = i;
+/* #define CHECK */
+#if defined(CHECK)
+ for (i=0x0; i<256; i++) {
+ foo[0] = i;
+ count = GroupSize(i);
+ for (j=0; j<count; j++) {
+ if (((count > 1) && ((j & 7) == 0)) ||
+ ((count == 1) && ((i & 7) == 0)))
+ printf("\n");
+ foo[1] = j;
+ foo[2] = 0;
+ s = DisAsm386(foo, &len);
+ if (*s != '?') printf("%02x\t%s\n", i, (FP)s);
+ if (group) {
+ for (g = 1; g<8; g++) {
+ foo[group] = g << 3;
+ s = DisAsm386(foo, &len);
+ if (*s != '?') printf("%02x %02x\t%s\n", i, foo[group], (FP)s);
+ }
+ group = 0;
+ }
+ }
+#else
+ /* for (i=0; i<10; i++) { */
+ while (cp < ep) {
+ s = DisAsm86(cp, &len);
+ printf("%04x\t%s\n", (word)cp, (FP)s);
+ cp += len;
+#endif
+ }
+#endif
+} /* main */
+
+void far foobar() {}
+#endif
+
diff --git a/private/mvdm/wow16/sherlock/disasm.h b/private/mvdm/wow16/sherlock/disasm.h
new file mode 100644
index 000000000..765eeb8c5
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/disasm.h
@@ -0,0 +1,51 @@
+/* Disasm.h - definitions for Don's Tiny Disassembler */
+
+typedef unsigned long dword;
+typedef unsigned short word;
+typedef unsigned char byte;
+
+
+extern word memOp; /* actual operation performed */
+extern char *memName[]; /* name corresponding to memOp */
+enum { memNOP, memRead, memWrite, memRMW, memSegReg, memSegMem};
+
+extern word memSeg; /* value of segment of memory address */
+extern dword memLinear, /* offset of operand */
+ memLinear2;
+extern word memSeg2, /* duplicate of above if dual mem op */
+ memSize2, memOp2,
+ memDouble; /* true if two-mem-operand instruction */
+
+extern word memSize; /* bytes of memory of operation */
+enum { MemByte=1, MemWord=2, MemDWord=4, MemQWord=8, MemTword=10,
+ Adr4, Adr6=6};
+
+enum { memNoSeg, memES, memCS, memSS, memDS, memFS, memGS};
+
+enum {strCX=1, strSI=2, strDI=4, segDS=8, segES=16, segFS=32, segGS=64};
+extern word gpSafe, /* 1 if may continue instruction */
+ gpRegs, /* regs which instruction modifies as side effect */
+ gpStack; /* amount stack is changed by */
+
+ /* DisAsm86 is my nifty 80x86 disassembler (even handles 32 bit code) */
+ /* Given current CS:IP, it disassembles the instruction, and returns */
+ /* the number of code bytes used, and a pointer to a static array of */
+ /* chars holding the disassembly. It also sets up a bunch of global */
+ /* vars indicating what memory operations occurred, to aid in decoding */
+ /* the fault type. */
+extern char *DisAsm86(byte far *cp, int *len);
+
+
+ /* Same as DisAsm86, but assumes 32 bit code and data */
+extern char *DisAsm386(byte far *cp, int *len);
+
+extern char hexData[];
+
+#if !defined(MS_DOS)
+#define sprintf wsprintf
+#define vsprintf wvsprintf
+#define FP void far *
+#else
+#define FP void *
+#endif
+
diff --git a/private/mvdm/wow16/sherlock/doctor.ico b/private/mvdm/wow16/sherlock/doctor.ico
new file mode 100644
index 000000000..00420a6c5
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/doctor.ico
Binary files differ
diff --git a/private/mvdm/wow16/sherlock/drwatson.c b/private/mvdm/wow16/sherlock/drwatson.c
new file mode 100644
index 000000000..3e086b43a
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/drwatson.c
@@ -0,0 +1,1573 @@
+/* sherlock.c - Help deduce cause of Unrecoverable Application Errors
+ (C) Copyright 1991, Microsoft Corp
+ Written by Don Corbitt, based upon work of Cameron Stevens and others.
+ Features -
+ Help Script
+ Dialog box to change options
+ Option to trap Ctrl-Alt-SysRq to break endless loops
+ Disassembler should look up symbols for CALL instructions
+ Button could call up editor - file extension associations
+ Toggle Icon when message occurs
+ Write formal spec - (Program is done, so write the spec)
+ Disable operation in Real Mode
+ Dump stack bytes
+ If all is blown, dump message to text monitor
+ Data Symbols in disassembly
+
+ Bugs -
+ Doesn't buffer file output - this could be slow (but how many GP/hour?)
+ Need to watch for invalid memory
+ Need to handle Jump to bad address
+ What if there aren't any file handles left at fault time???
+ Need to handle no file handles available for .SYM file reader
+ Should open files (.sym, .log) with proper share flags
+ Could dump config.sys and autoexec.bat also
+ Can't handle fault in Sherlock - locks up machine - very ugly
+ Need to check InDOS flag
+ Some errors not detected
+ Jump/Call to invalid address
+ Load invalid selector
+ Run twice in Real Mode causes system hang
+ GP Continue doesn't update 32 bit registers for string moves
+*/
+
+#define DRWATSON_C
+#define STRICT
+#include <windows.h>
+#include <string.h> /* strcpy() */
+#include <stdarg.h> /* va_stuff() */
+#include <io.h> /* dup() - why is this spread over 3 files ??? */
+#include "toolhelp.h" /* all the good stuff */
+#include "disasm.h" /* DisAsm86(), memXxxx vars */
+#include "drwatson.h"
+#include "str.h" /* Support for string resources */
+
+#define STATIC /*static */
+
+char far foo[1]; /* force far data seg, make single instance */
+// Does this make sense considering we have code and strings to
+// tell the user they're foolish to run two copies of Dr. Watson?
+
+
+/******************/
+/***** Macros *****/
+/******************/
+#define version "1.00b"
+
+ /* This string is concatenated with other strings in various places */
+ /* so it can't be an array variable. It must stay a #define. */
+ /* These strings are not localized. */
+#define szAppNameMacro "Dr. Watson"
+#define szAppNameShortMacro "drwatson"
+STATIC char szAppName[] = szAppNameMacro;
+STATIC char szAppNameShort[] = szAppNameShortMacro;
+STATIC char szAppNameShortLog[] = szAppNameShortMacro ".log";
+static char szAppNameVers[] = szAppNameMacro " " version;
+
+#define YOO_HOO (WM_USER+22) /* user activated Dr. Watson */
+#define HEAP_BIG_FILE (WM_USER+23) /* log file is getting large */
+#define JUST_THE_FACTS (WM_USER+24) /* tell me about your problem */
+#define BIG_FILE 100000L
+
+ /* Don't like MSC-style FP macros, use my own */
+#undef MK_FP
+#undef FP_SEG
+#undef FP_OFF
+#define MK_FP(seg, off) (void far *)(((long)(seg) << 16) | (unsigned short)(off))
+#define FP_SEG(fp) (unsigned)((long)(fp) >> 16)
+#define FP_OFF(fp) (unsigned)(long)fp
+
+/***************************/
+/***** Data Structures *****/
+/***************************/
+
+LPSTR aszStrings[STRING_COUNT];
+
+ /* This points to the stack the GP fault handler should use */
+char *newsp;
+
+ /* These structures are used by Watson.asm and Disasm.c - don't change */
+ /* Also, they can't be static. They contain the CPU register contents */
+ /* at the time the fault occurred. */
+struct {
+ word ax, cx, dx, bx, sp, bp, si, di, ip, flags;
+ word es, cs, ss, ds, fs, gs, intNum;
+} regs;
+
+ /* If we have a 32 bit CPU, the full 32 bit values will be stored here. */
+ /* The lower 16 bits will still be in the generic regs above. */
+struct {
+ DWORD eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags;
+} regs32;
+
+ /* Each of these flags disables a part of the error output report */
+ /* The error report itself indicates how each section is named. */
+ /* The word in () can be added to the [Dr. Watson] section of WIN.INI */
+ /* to disable that section of the report. */
+ /* clu Clues dialog box */
+ /* deb OutputDebugString trapping */
+ /* dis Simple disassembly */
+ /* err Error logging */
+ /* inf System info */
+ /* loc Local vars on stack dump */
+ /* mod Module dump */
+ /* par Parameter error logging */
+ /* reg Register dump */
+ /* sum 3 line summary */
+ /* seg not visible to users, but available */
+ /* sou But I _like_ the sound effects! */
+ /* sta Stack trace */
+ /* tas Task dump */
+ /* tim Time start/stop */
+ /* 32b 32 bit register dump */
+
+STATIC char syms[] =
+ "clu deb dis err inf lin loc mod par reg sum seg sou sta tas tim 32b ";
+#define cntFlag (sizeof(syms)/4)
+ /* This array is used to decode the flags in WIN.INI. I only check */
+ /* the first 3 chars of an entry. Each entry must be separated by a */
+ /* space from the previous one. */
+
+unsigned long ddFlag;
+
+int retflag; /* used in watson.asm */
+
+struct {
+ char bit, name;
+} flBit[] = {
+ 11, 'O',
+ 10, 'D',
+ 9, 'I',
+ 7, 'S',
+ 6, 'Z',
+ 4, 'A',
+ 2, 'P',
+ 0, 'C',
+};
+#define cntFlBit (sizeof(flBit)/sizeof(flBit[0]))
+
+STATIC int disLen = 8; /* Number of instructions to disassemble */
+STATIC int trapZero = 0; /* Should I trap divide by 0 faults */
+STATIC int iFeelLucky = 1; /* Should we restart after GP fault? */
+ /* 1 = allow continue
+ 2 = skip report
+ 4 = continue in Kernel
+ 8 = continue in User
+ 16 = allow sound
+ */
+STATIC int imTrying; /* trying to continue operation */
+
+STATIC struct {
+ FARPROC adr;
+ WORD code;
+ HTASK task;
+ DWORD parm;
+} lastErr;
+
+STATIC int disStack = 2; /* Disassemble 2 levels of stack trace */
+int cpu32; /* True if cpu has 32 bit regs */
+STATIC int fh = -1; /* Handle of open log file */
+STATIC int level; /* if >0, in nested FileOpen() call */
+STATIC int bugCnt, sound;
+STATIC int pending; /* If a pending Clues dialog */
+STATIC int whined; /* If already warned about a large file */
+STATIC long pitch, deltaPitch = 250L << 16;
+STATIC HINSTANCE hInst;
+
+STATIC char logFile[80]; /* Default log file is "drwatson.log" */
+ /* and is stored in the windows dir */
+
+STATIC struct { /* Help print out value of CPU flags */
+ WORD mask;
+ LPSTR name;
+} wf[] = {
+ WF_80x87, (LPSTR) IDSTRCoprocessor, // IDSTRs are fixed up to pointers
+ WF_CPU086, (LPSTR) IDSTR8086, // by LoadStringResources
+ WF_CPU186, (LPSTR) IDSTR80186,
+ WF_CPU286, (LPSTR) IDSTR80286,
+ WF_CPU386, (LPSTR) IDSTR80386,
+ WF_CPU486, (LPSTR) IDSTR80486,
+ WF_ENHANCED, (LPSTR) IDSTREnhancedMode,
+ WF_PMODE, (LPSTR) IDSTRProtectMode,
+ WF_STANDARD, (LPSTR) IDSTRStandardMode,
+ WF_WINNT, (LPSTR) IDSTRWindowsNT,
+};
+#define wfCnt (sizeof(wf)/sizeof(wf[0]))
+
+HWND hWnd; /* Handle to main window */
+HANDLE hTask; /* current task (me) */
+
+/***********************/
+/***** Extern Defs *****/
+/***********************/
+
+ /* Get base 32 bit linear address of a memory segment - calls DPMI */
+extern DWORD SegBase(WORD segVal);
+
+ /* Get segment flags - 0 if error */
+extern WORD SegRights(WORD segVal);
+
+ /* Get (segment length -1) */
+extern DWORD SegLimit(WORD segVal);
+
+ /* Fills in regs32 structure with value from regs struct and current high */
+ /* word of registers - don't do any 32 bit ops before calling this func */
+extern void GetRegs32(void);
+
+ /* Fills in non-standard time/date structure using DOS calls. The C */
+ /* run-time has a similar function (asctime()), but it pulls in over */
+ /* 6K of other functions. This is much smaller and faster, and */
+ /* doesn't depend on environment variables, etc. */
+extern void GetTimeDate(void *tdstruc);
+
+ /* Called by ToolHelp as a notify hook */
+extern BOOL far /*pascal*/ CallMe(WORD, DWORD);
+
+char *LogParamErrorStr(WORD err, FARPROC lpfn, DWORD param);
+
+extern int FindFile(void *ffstruct, char *name);
+
+ /* This routine is called by ToolHelp when a GP fault occurs. It */
+ /* switches stacks and calls Sherlock() to handle the fault. */
+extern void CALLBACK GPFault(void);
+
+ /* Return name of nearest symbol in file, or 0 */
+extern char *NearestSym(int segIndex, unsigned offset, char *exeName);
+
+STATIC void cdecl Show(const LPSTR format, ...);
+
+/************************************/
+/***** Segment Helper Functions *****/
+/************************************/
+
+/************************************
+Name: LPSTR SegFlags(WORD segVal)
+Desc: Given a selector, SegFlags checks for validity and then returns
+ an ascii string indicating whether it is a code or data selector,
+ and read or writeable.
+Bugs: Should check other flags (accessed), and call gates.
+ Returns pointer to static array, overwritten on each new call.
+*************************************/
+STATIC LPSTR SegFlags(WORD segVal) {
+ static char flag[10];
+
+ if (segVal == 0) return STR(NullPtr);
+
+ segVal = SegRights(segVal);
+ if (segVal == 0) return STR(Invalid);
+
+ segVal >>= 8;
+ if (!(0x80 & segVal)) return STR(NotPresent);
+
+ if (segVal & 8) {
+ lstrcpy(flag, STR(Code));
+ lstrcat(flag, segVal & 2 ? STR(ExR) : STR(ExO));
+ } else {
+ lstrcpy(flag, STR(Data));
+ lstrcat(flag, segVal&2 ? STR(RW) : STR(RO));
+ }
+ return flag;
+} /* SegFlags */
+
+/************************************
+Name: char *SegInfo(WORD seg)
+Desc: Given a selector, SegInfo returns an ascii string indicating the
+ linear base address, limit, and attribute flags of the selector.
+Bugs: Returns pointer to static array, overwritten on each new call.
+*************************************/
+STATIC char *SegInfo(WORD seg) {
+ static char info[30];
+ if (noSeg) return "";
+
+ wsprintf(info, "%8lx:%04lx %-9s",
+ SegBase(seg), SegLimit(seg), (FP)SegFlags(seg));
+ return info;
+} /* SegInfo */
+
+/************************************
+Name: WORD SegNum(WORD segVal)
+Desc: Returns the index of this segment in the module table. Used to
+ translate between a physical segment number and the index as
+ seen in e.g. the map file.
+Bugs: Don't know what ToolHelp returns for data or GlobalAlloc segments.
+ This is mainly useful for converting a code segment value.
+ Check for GT_DATA - will also be valid index.
+*************************************/
+STATIC WORD SegNum(HGLOBAL segVal) {
+ GLOBALENTRY ge;
+ ge.dwSize = sizeof(ge);
+ if (GlobalEntryHandle(&ge, segVal) && (ge.wType == GT_CODE)) {
+ return ge.wData; /* defined to be 'file segment index' */
+ }
+ return (WORD)-1;
+} /* SegNum */
+
+/************************************
+Name: LPSTR ModuleName(WORD segVal)
+Desc: Returns name of this code segment's module
+Bugs:
+*************************************/
+STATIC LPSTR ModuleName(WORD segVal) {
+ static char name[12];
+ GLOBALENTRY ge;
+ MODULEENTRY me;
+ ge.dwSize = sizeof(ge);
+ me.dwSize = sizeof(me);
+ if (GlobalEntryHandle(&ge, (HGLOBAL)segVal) && (ge.wType == GT_CODE)) {
+ if (ModuleFindHandle(&me, ge.hOwner)) {
+ strcpy(name, me.szModule);
+ return name;
+ } /* else Show("ModuleFindHandle() failed\n"); */
+ } /* else Show("GlobalEntryHandle() failed\n"); */
+ return STR(Unknown);
+} /* ModuleName */
+
+/**********************************/
+/***** Other Helper Functions *****/
+/**********************************/
+
+/************************************
+Name: char *FaultType(void)
+Desc: Returns ascii string indicating what kind of fault caused ToolHelp
+ to call our GPFault handler.
+Bugs: May not handle Ctrl-Alt-SysR nicely (we shouldn't trap it)
+*************************************/
+/* static char *FaultType(void) {
+ switch (regs.intNum) {
+ case 0: return STR(DivideByZero);
+ case 6: return STR(InvalidOpcode);
+ case 13: return STR(GeneralProtection);
+ default: return STR(Unknown);
+ }
+} /* FaultType */
+
+/************************************
+Name: char *DecodeFault(int op, word seg, dword offset, word size)
+Desc: Pokes at memory address passed in, trying to determine fault cause
+ Segment wrap-around
+ Null selector
+ Write to read only data
+ Write to code segment
+ Read from execute only code segment
+ Exceed segment limit
+ Invalid selector
+Bugs: Jump, string, call, and stack memory adr's aren't set by DisAsm
+*************************************/
+STATIC LPSTR DecodeFault(int op, word seg, dword offset, word size) {
+ int v;
+ dword lim;
+
+ switch (op) {
+ case memNOP:
+ break; /* since no mem access, no fault */
+
+ case memSegMem: /* load seg reg from memory */
+ seg = *(short far *)MK_FP(seg, offset);
+ /* fall through */
+ case memSegReg: /* load seg reg with value */
+ v = SegRights(seg); /* lets see if this is a selector */
+ if (!v) return STR(InvalidSelector);
+ break; /* See no evil... */
+
+ case memRead:
+ case memRMW:
+ case memWrite:
+ if (seg == 0) return STR(NullSelector);
+
+ v = SegRights(seg);
+ if (!v) return STR(InvalidSelector);
+
+ v >>= 8;
+ if (!(0x80 & v)) return STR(SegmentNotPresent);
+
+ lim = SegLimit(seg);
+ if (lim < (offset+size)) return STR(ExceedSegmentBounds);
+
+ if (v & 8) { /* code segment */
+ if ((op == memRMW) || (op == memWrite))
+ return /* Write to */ STR(CodeSegment);
+ else if (!(v&2)) return /* Read */ STR(ExecuteOnlySegment);
+
+ } else { /* data segment */
+ if (((op == memRMW) || (op == memWrite)) && !(v&2))
+ return /* Write to */ STR(ReadOnlySegment);
+ }
+ break;
+ default:
+ return 0; /* obviously unknown condition */
+ }
+ return 0;
+} /* DecodeFault */
+
+
+LPSTR SafeDisAsm86(void far *code, int *len) {
+ unsigned long limit = SegLimit(FP_SEG(code));
+ if ((unsigned long)(FP_OFF(code)+10) > limit) {
+ *len = 1;
+ return STR(SegNotPresentOrPastEnd);
+ }
+ return DisAsm86(code, (int *)len);
+} /* SafeDisAsm86 */
+
+
+/************************************
+Name: LPSTR FaultCause(void)
+Desc: Decodes the actual cause of the fault. This is trivial for Div0
+ and Invalid Opcode, but much trickier for GP Faults. I need to
+ try to detect at least the following:
+ Segment wrap-around
+ Null selector
+ Write to read only data
+ Write to code segment
+ Read from execute only code segment
+ Exceed segment limit
+ Invalid selector
+Bugs:
+*************************************/
+STATIC LPSTR FaultCause(void) {
+ int foo;
+ LPSTR s, s1;
+ static char cause[54];
+
+ switch (regs.intNum) {
+ case 0: return STR(DivideByZero);
+ case 6: return STR(InvalidOpcode);
+ case 20: return STR(ErrorLog);
+ case 21: return STR(ParameterErrorLog);
+ case 13:
+ SafeDisAsm86(MK_FP(regs.cs, regs.ip), &foo); /* Set global memXxxx vars */
+
+ /* See if first memory access caused fault */
+ s = DecodeFault(memOp, memSeg, memLinear, memSize);
+ s1 = memName[memOp];
+
+ /* no, see if second memory access caused fault */
+ if (!s && memDouble) {
+ s = DecodeFault(memOp2, memSeg2, memLinear2, memSize2);
+ s1 = memName[memOp2];
+ }
+
+ if (s) {
+ wsprintf(cause, "%s (%s)", s, s1);
+ return cause;
+ }
+ }
+ return STR(Unknown);
+} /* FaultCause */
+
+/************************************
+Name: LPSTR CurModuleName(hTask task)
+Desc: Call ToolHelp to find name of faulting module
+Bugs:
+*************************************/
+STATIC LPSTR CurModuleName(HTASK hTask) {
+ TASKENTRY te;
+ static char name[10];
+
+ te.dwSize = sizeof(te);
+ if (!TaskFindHandle(&te, hTask)) /* Thanks, ToolHelp */
+ return STR(Unknown);
+ strcpy(name, te.szModule);
+ return name;
+} /* ModuleName */
+
+/************************************
+Name: LPSTR FileInfo(char *name)
+Desc: Find file time, date, and size
+Bugs:
+*************************************/
+STATIC LPSTR FileInfo(char *name) {
+ struct {
+ char resv[21];
+ char attr;
+ unsigned time;
+ unsigned date;
+ long len;
+ char name[13];
+ char resv1[10];
+ } f;
+ static char buf[30];
+
+ if (FindFile(&f, name)) return STR(FileNotFound);
+ wsprintf(buf, "%7ld %02d-%02d-%02d %2d:%02d",
+ f.len,
+ (f.date >> 5) & 15, f.date & 31, (f.date >> 9) + 80,
+ f.time >> 11, (f.time >> 5) & 63);
+ return buf;
+} /* FileInfo */
+
+/************************************
+Name: char *CurFileName(void)
+Desc: Call ToolHelp to find filename and path of faulting module
+Bugs:
+*************************************/
+/* STATIC char *CurFileName(void) {
+ TASKENTRY te;
+ MODULEENTRY me;
+ static char name[80];
+ te.dwSize = sizeof(te);
+ me.dwSize = sizeof(me);
+ if (!TaskFindHandle(&te, GetCurrentTask()) ||
+ !ModuleFindName(&me, te.szModule))
+ return STR(Unknown);
+ strcpy(name, me.szExePath);
+ return name;
+} /* FileName */
+
+/************************************
+Name: char *CurTime(void)
+Desc: Generates string with current time and date. Similar to asctime(),
+ except it doesn't pull in another 6K of run-time library code :-)
+Bugs: Magic structure passed to asm routine
+*************************************/
+STATIC char *CurTime(void) {
+ static char t[48];
+ struct { /* This magic struct is hard-coded to */
+ char week, resv; /* match the assembly language in */
+ short year; /* watson.asm GetTimeDate() */
+ char day, month; /* This means I recommend you don't */
+ char minute, hour; /* change the size or order of the */
+ char hund, second; /* fields! */
+ } td;
+ GetTimeDate(&td);
+ wsprintf(t, "%s %s %2d %02d:%02d:%02d %d",
+ aszStrings[IDSTRSun + td.week], aszStrings[IDSTRJan + td.month - 1],
+ td.day, td.hour, td.minute, td.second, td.year);
+ return t;
+} /* CurTime */
+
+
+/************************************
+Name: LPSTR Tab2Spc(LPSTR temp)
+Desc: Converts tabs found in string 'temp' into the proper number of
+ spaces. I need this since DisAsm86() returns a string with tabs
+ in it, and TextOut() didn't like them. This was easier than
+ getting TabbedTextOut() set up to work. Since I'm no longer dumping
+ to the screen, this routine may be superfluous.
+Bugs:
+*************************************/
+STATIC LPSTR Tab2Spc(LPSTR temp) {
+ char newbuf[80];
+ LPSTR s1, s2;
+
+ s1 = temp;
+ s2 = newbuf;
+ while ((*s2 = *s1++) != 0) {
+ if (*s2++ == 9) {
+ s2[-1] = ' ';
+ while ((s2-(LPSTR)newbuf) & 7) *s2++ = ' ';
+ }
+ }
+ lstrcpy(temp, newbuf);
+ return temp;
+} /* Tab2Spc */
+
+
+/************************************
+Name: void Show(const LPSTR format, ...)
+Desc: Think of this as (minor) shortcut fprintf(). I originally had this
+ dumping info to a Windows window, and then changed it to write to
+ the file we want. All output goes through this func, so if you
+ want to change something, this is the place.
+Bugs: Now writing to a file handle, opened in text mode so it does the
+ LF->CR/LF translation for me.
+ No buffering performed on writes, except for what DOS might do.
+ Blows up if stuff passed in expands to longer than 200 chars.
+*************************************/
+STATIC void cdecl Show(const LPSTR format, ...) {
+ char line[CCH_MAX_STRING_RESOURCE];
+ char *prev, *cur;
+ wvsprintf(line, format, (LPSTR)(&format + 1));
+ if (fh != -1) {
+ prev = cur = line;
+ while (*cur) { /* expand LF to CR/LF */
+ if (cur[0] == '\n' && /* at LF */
+ ((prev == cur) || /* and first of line */
+ (cur[-1] != '\r'))) { /* or previous wasn't CR */
+ cur[0] = '\r'; /* append CR to text up to LF */
+ _lwrite(fh, prev, cur-prev+1);
+ cur[0] = '\n'; /* leave LF for next write */
+ prev = cur;
+ }
+ cur++;
+ }
+ if (prev != cur) /* write trailing part */
+ _lwrite(fh, prev, cur-prev);
+ }
+} /* Show */
+
+/************************************
+Name: void MyFlush(void)
+Desc: Any routine named MyXxxx() had better be a private hack, and this
+ one is. It just appends an extra CRLF to the output file, and makes
+ sure that the info written so far makes it to disk. This way, if
+ a later part of the program blows up, at least you will know this
+ much.
+Bugs:
+*************************************/
+STATIC void MyFlush(void) {
+ int h;
+ Show("\n");
+ if (fh != -1) {
+ h = dup(fh);
+ if (h != -1) _lclose(h);
+ }
+ if (sound) {
+ StopSound();
+ SetVoiceSound(1, pitch, 20);
+ pitch += deltaPitch;
+ StartSound();
+ }
+} /* MyFlush */
+
+/************************************
+Name: void DisAsmAround(char far *cp, int count)
+Desc: The 'cp' parameter is a pointer to a code segment in memory. This
+ routine backs up a few instructions from the current point, and
+ dumps a disassembly showing the context of the selected instruction.
+Bugs: Needs to check for segmentation problems, such as invalid selector.
+*************************************/
+STATIC void DisAsmAround(byte far *cp, int count) {
+ int len, back;
+ byte far *oldcp = cp;
+ byte far *cp1;
+ GLOBALENTRY ge;
+ MODULEENTRY me;
+ char *szSym = 0;
+ long limit;
+ unsigned segLim;
+ char symBuf[40];
+
+ ge.dwSize = sizeof(ge);
+ me.dwSize = sizeof(me);
+ if (GlobalEntryHandle(&ge, (HGLOBAL)FP_SEG(cp)) && (ge.wType == GT_CODE)) {
+ if (ModuleFindHandle(&me, ge.hOwner)) {
+ szSym = NearestSym(ge.wData, FP_OFF(cp), me.szExePath);
+ if (!szSym) { /* if we know module name, but no syms */
+ sprintf(symBuf, "%d:%04x", ge.wData, FP_OFF(cp));
+ szSym = symBuf;
+ }
+ }
+ }
+
+ cp -= count*2 + 10; /* back up */
+ if ((FP_OFF(cp) & 0xff00) == 0xff00) /* if wrapped around, trunc to 0 */
+ cp = MK_FP(FP_SEG(cp), 0);
+ cp1 = cp;
+
+ limit = SegLimit(FP_SEG(cp));
+ segLim = limit > 0xffffL ? 0xffff : (int)limit;
+ if (segLim == 0) {
+ Show(STR(CodeSegmentNPOrInvalid));
+ return;
+ }
+
+ back = 0;
+ while (cp < oldcp) { /* count how many instructions to point */
+ SafeDisAsm86(cp, &len);
+ cp += len;
+ back++;
+ }
+ cp = cp1;
+ back -= (count >> 1);
+ while (back>0) { /* step forward until (len/2) remain */
+ SafeDisAsm86(cp, &len); /* before desired instruction point */
+ cp += len;
+ back--;
+ }
+
+ while (count--) { /* display desired instructions */
+ if (cp == oldcp) {
+ if (szSym) Show("(%s:%s)\n", (FP)me.szModule, (FP)szSym);
+ else Show(STR(NoSymbolsFound));
+ }
+ Show("%04x:%04x %-22s %s\n",
+ FP_SEG(cp), FP_OFF(cp), /* address */
+ (FP)hexData, /* opcodes in hex */
+ (FP)/*Tab2Spc*/(SafeDisAsm86(cp, &len)));/* actual disassembly */
+ cp += len;
+ }
+} /* DisAsmAround */
+
+/************************************
+Name: int MyOpen(void)
+Desc: Tries to open logFile for append. If this fails, tries to
+ create it.
+Bugs: Should set sharing flags?
+*************************************/
+STATIC int MyOpen(void) {
+ if (fh != -1) return fh; /* Already open */
+ fh = _lopen(logFile, OF_WRITE | OF_SHARE_DENY_WRITE);
+ if (fh == -1) {
+ fh = _lcreat(logFile, 0);
+ } else _llseek(fh, 0L, 2);
+ if (fh != -1) level++;
+ return fh != -1;
+} /* MyOpen */
+
+/************************************
+Name: void MyClose(void)
+Desc: close output file, clear handle to -1
+Bugs: Should set sharing flags?
+*************************************/
+STATIC void MyClose(void) {
+ if (--level == 0) {
+ if (fh != -1) _lclose(fh);
+ fh = -1;
+ }
+} /* MyClose */
+
+void PutDate(LPSTR msg) {
+ MyOpen();
+ if (fh == -1) return;
+ Show("%s %s - %s\n", (FP)msg, (FP)szAppNameVers, (FP)CurTime());
+ MyClose();
+} /* PutDate */
+
+int far pascal SherlockDialog(HWND hDlg, WORD wMsg, WPARAM wParam, LPARAM lParam) {
+ char line[255];
+ int i, len, count;
+ HWND hItem;
+
+ lParam = lParam;
+ if (wMsg == WM_INITDIALOG) return 1;
+
+ if ((wMsg != WM_COMMAND) ||
+ (wParam != IDOK && wParam != IDCANCEL))
+ return 0;
+
+ if (wParam == IDOK) {
+ MyOpen();
+ if (fh != -1) {
+ hItem = GetDlgItem(hDlg, 102);
+ if (hItem) {
+ count = (int)SendMessage(hItem, EM_GETLINECOUNT, 0, 0L);
+ for (i=0; i<count; i++) {
+ *(int *)line = sizeof(line) - sizeof(int) -1;
+ len = (int)SendMessage(hItem, EM_GETLINE, i, (long)((void far *)line));
+ line[len] = 0;
+ Show("%d> %s\n", i+1, (FP)line);
+ }
+ }
+ MyClose();
+ }
+ }
+ EndDialog(hDlg, 0);
+ return 1;
+} /* SherlockDialog */
+
+
+extern int far pascal SysErrorBox(char far *text, char far *caption,
+ int b1, int b2, int b3);
+#define SEB_OK 1 /* Button with "OK". */
+#define SEB_CANCEL 2 /* Button with "Cancel" */
+#define SEB_YES 3 /* Button with "&Yes" */
+#define SEB_NO 4 /* Button with "&No" */
+#define SEB_RETRY 5 /* Button with "&Retry" */
+#define SEB_ABORT 6 /* Button with "&Abort" */
+#define SEB_IGNORE 7 /* Button with "&Ignore" */
+#define SEB_CLOSE 8 /* Button with "Close" */
+
+#define SEB_DEFBUTTON 0x8000 /* Mask to make this button default */
+
+#define SEB_BTN1 1 /* Button 1 was selected */
+#define SEB_BTN2 2 /* Button 1 was selected */
+#define SEB_BTN3 3 /* Button 1 was selected */
+
+
+/************************************
+Name: int PrepareToParty(LPSTR modName, LPSTR appName)
+Desc: Checks whether we can continue the current app by skipping an
+ instruction. If so, it performs the side effects of the
+ instruction. This must be called after a call to DisAsm86() has
+ set the gpXxxx global vars.
+ Checks value of iFeelLucky, bit 0 must be set to continue a fault.
+Bugs: Should do more checking, should check for within a device driver,
+ shouldn't require that DisAsm86() be called for the failing
+ instruction immediately before call.
+*************************************/
+int PrepareToParty(LPSTR modName, LPSTR appName) {
+
+ if (!(iFeelLucky&1)) return 0;
+ if (!gpSafe) return 0;
+
+ /* compare module to KERNEL */
+ if (!(iFeelLucky&4) && !lstrcmp(modName, "KERNEL")) return 0;
+
+ /* compare module to USER */
+ if (!(iFeelLucky&8) && !lstrcmp(modName, "USER")) return 0;
+
+ /* already asked, trying to continue, skip this fault */
+ if (imTrying>0) return 1;
+
+ if (3 != SysErrorBox(STR(GPText), appName, SEB_CLOSE|SEB_DEFBUTTON, 0, SEB_IGNORE))
+ return 0;
+
+ imTrying = 100;
+ return 1;
+} /* PrepareToParty */
+
+STATIC void DumpInfo(void) {
+ WORD w = (int)GetVersion();
+ DWORD lw = GetWinFlags();
+ SYSHEAPINFO si;
+ int i;
+ MEMMANINFO mm;
+
+ Show(STR(SystemInfoInfo));
+ Show(STR(WindowsVersion), w&0xff, w>>8);
+ if (GetSystemMetrics(SM_DEBUG)) Show(STR(DebugBuild));
+ else Show(STR(RetailBuild));
+ {
+ HANDLE hUser = GetModuleHandle("USER");
+ char szBuffer[80];
+ if (LoadString(hUser, 516, szBuffer, sizeof(szBuffer)))
+ Show(STR(WindowsBuild), (FP)szBuffer);
+
+ if (LoadString(hUser, 514, szBuffer, sizeof(szBuffer)))
+ Show(STR(Username), (FP)szBuffer);
+
+ if (LoadString(hUser, 515, szBuffer, sizeof(szBuffer)))
+ Show(STR(Organization), (FP)szBuffer);
+ }
+
+
+ Show(STR(SystemFreeSpace), GetFreeSpace(0));
+
+ if (SegLimit(regs.ss) > 0x10) {
+ int far *ip = MK_FP(regs.ss, 0);
+ Show(STR(StackBaseTopLowestSize),
+ ip[5], ip[7], ip[6], ip[7]-ip[5]);
+ }
+
+ si.dwSize = sizeof(si);
+ if (SystemHeapInfo(&si))
+ Show(STR(SystemResourcesUserGDI),
+ si.wUserFreePercent, si.hUserSegment,
+ si.wGDIFreePercent, si.hGDISegment);
+
+ mm.dwSize = sizeof(mm);
+ if (MemManInfo(&mm)) {
+ Show(STR(MemManInfo1),
+ mm.dwLargestFreeBlock, mm.dwMaxPagesAvailable, mm.dwMaxPagesLockable);
+ Show(STR(MemManInfo2),
+ mm.dwTotalLinearSpace, mm.dwTotalUnlockedPages, mm.dwFreePages);
+ Show(STR(MemManInfo3),
+ mm.dwTotalPages, mm.dwFreeLinearSpace, mm.dwSwapFilePages);
+ Show(STR(MemManInfo4), mm.wPageSize);
+ }
+ Show(STR(TasksExecuting), GetNumTasks());
+ Show(STR(WinFlags));
+ for (i=0; i<wfCnt; i++) if (lw & wf[i].mask)
+ Show(" %s\n", (FP)wf[i].name);
+ MyFlush();
+} /* DumpInfo */
+
+LPSTR GetProcName(FARPROC fn) {
+ GLOBALENTRY ge;
+ MODULEENTRY me;
+ LPSTR szSym = STR(UnknownAddress);
+ static char symBuf[80];
+
+ ge.dwSize = sizeof(ge);
+ me.dwSize = sizeof(me);
+ if (GlobalEntryHandle(&ge, (HGLOBAL)FP_SEG(fn)) && (ge.wType == GT_CODE)) {
+ if (ModuleFindHandle(&me, ge.hOwner)) {
+ szSym = NearestSym(ge.wData, FP_OFF(fn), me.szExePath);
+ if (!szSym) { /* if we know module name, but no syms */
+ sprintf(symBuf, "%s %d:%04x", (FP)me.szModule, ge.wData, FP_OFF(fn));
+ } else sprintf(symBuf, "%s %s", (FP)me.szModule, szSym);
+ szSym = symBuf;
+ }
+ }
+ return szSym;
+} /* GetProcName */
+
+STATIC void DumpStack(int disCnt, int parmCnt, int cnt, int first) {
+ STACKTRACEENTRY ste;
+ MODULEENTRY me;
+ int frame = 0;
+ unsigned oldsp = regs.sp+16;
+
+ ste.dwSize = sizeof(ste);
+ me.dwSize = sizeof(me);
+
+ Show(STR(StackDumpStack));
+ if (StackTraceCSIPFirst(&ste, regs.ss, regs.cs, regs.ip, regs.bp)) do {
+ if (frame >= first--) {
+ me.szModule[0] = 0;
+ ModuleFindHandle(&me, ste.hModule);
+ Show(STR(StackFrameInfo),
+ frame++,
+ (FP)GetProcName((FARPROC)MK_FP(ste.wCS, ste.wIP)),
+ ste.wSS, ste.wBP);
+ if (!noLocal && (parmCnt-- > 0)) {
+ if (oldsp & 15) {
+ int i;
+ Show("ss:%04x ", oldsp & ~15);
+ for (i=0; i < (int)(oldsp & 15); i++) Show(" ");
+ }
+ while (oldsp < ste.wBP) {
+ if (!(oldsp & 15)) Show("\nss:%04x ", oldsp);
+ Show("%02x ", *(byte far *)MK_FP(regs.ss, oldsp++));
+ }
+ Show("\n");
+ }
+ if (frame <= disStack && (disCnt-- >0)) {
+ Show("\n");
+ DisAsmAround(MK_FP(ste.wCS, ste.wIP), 8);
+ }
+ MyFlush();
+ } /* if after first to show */
+ } while (StackTraceNext(&ste) && (cnt-- > 0));
+} /* DumpStack */
+
+int BeginReport(LPSTR time) {
+ int i;
+
+ MyOpen();
+ if (fh == -1) { /* maybe we're out of handles */
+ _lclose(4); /* trash one at random */
+ MyOpen(); /* and try again */
+ }
+ if (fh == -1) return 0;
+
+ for (i=0; i<4; i++) Show("*******************");
+ Show(STR(FailureReport), (FP)szAppNameVers, (FP)time);
+ MyFlush();
+ if (!noSound) {
+ sound = OpenSound();
+ pitch = 1000L << 16;
+ } else sound = 0;
+ return 1;
+} /* BeginReport */
+
+void EndReport(void) {
+ if (fh != -1) {
+ if (!whined && _llseek(fh, 0L, 2) > BIG_FILE) {
+ PostMessage(hWnd, HEAP_BIG_FILE, 0, 0);
+ whined = 1;
+ }
+ MyClose();
+ }
+ if (sound) {
+ StopSound();
+ CloseSound();
+ sound = 0;
+ }
+} /* EndReport */
+
+void ShowParamError(int sync) {
+ if (GetCurrentTask() == lastErr.task)
+ Show("$param$, %s %s\n",
+ sync ? (FP)"" : (FP)STR(LastParamErrorWas),
+ (FP)LogParamErrorStr(lastErr.code, lastErr.adr, lastErr.parm));
+ lastErr.task = 0;
+} /* ShowParamError */
+
+/************************************
+Name: void Sherlock(void)
+Desc: Handles GP faults in applications by dumping as much system
+ information as I can think of to a log file.
+ This is the big routine.
+Bugs:
+*************************************/
+enum {s_prog, s_fault, s_name, s_instr, s_time, s_last};
+int Sherlock(void) {
+ int i, faultlen, party;
+ LPSTR s[s_last];
+
+ if ((!trapZero || regs.intNum != 0) &&
+ regs.intNum != 6 &&
+ regs.intNum != 13)
+ return 0;
+
+ if (imTrying>0) {
+ s[s_prog] = CurModuleName(GetCurrentTask());
+ SafeDisAsm86(MK_FP(regs.cs, regs.ip), &faultlen);
+ party = PrepareToParty(ModuleName(regs.cs), s[s_prog]);
+ imTrying--;
+ if (party) goto SkipReport;
+ }
+
+ if (++bugCnt > 20) return 0;
+
+ if (!BeginReport(s[s_time] = CurTime()))
+ return 0;
+
+ s[s_prog] = CurModuleName(GetCurrentTask());
+ s[s_fault] = FaultCause();
+ s[s_name] = GetProcName((FARPROC)MK_FP(regs.cs, regs.ip));
+
+ Show(STR(HadAFaultAt),
+ (FP)s[s_prog],
+ (FP)s[s_fault],
+ (FP)s[s_name]);
+
+ if (!noSummary) Show("$tag$%s$%s$%s$",
+ (FP)s[s_prog],
+ (FP)s[s_fault],
+ (FP)s[s_name]);
+
+ s[s_instr] = Tab2Spc(SafeDisAsm86(MK_FP(regs.cs, regs.ip), &faultlen));
+ Show("%s$%s\n", (FP)s[s_instr], (FP)s[s_time]);
+ ShowParamError(0);
+ MyFlush();
+
+ party = PrepareToParty(ModuleName(regs.cs), s[s_prog]);
+ if ((bugCnt > 3) || ((party>0) && (iFeelLucky & 2))) {
+ goto SkipReport;
+ }
+
+ if (!noReg) {
+ Show(STR(CPURegistersRegs));
+ Show("ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x\n",
+ regs.ax, regs.bx, regs.cx, regs.dx, regs.si, regs.di);
+ Show("ip=%04x sp=%04x bp=%04x ", regs.ip, regs.sp+16, regs.bp);
+ for (i=0; i<cntFlBit; i++)
+ Show("%c%c ", flBit[i].name, regs.flags & (1 << flBit[i].bit) ? '+' : '-');
+ Show("\n");
+ Show("cs = %04x %s\n", regs.cs, (FP)SegInfo(regs.cs));
+ Show("ss = %04x %s\n", regs.ss, (FP)SegInfo(regs.ss));
+ Show("ds = %04x %s\n", regs.ds, (FP)SegInfo(regs.ds));
+ Show("es = %04x %s\n", regs.es, (FP)SegInfo(regs.es));
+ MyFlush();
+ }
+
+ if (cpu32 && !noReg32) {
+ Show(STR(CPU32bitRegisters32bit));
+ Show("eax = %08lx ebx = %08lx ecx = %08lx edx = %08lx\n",
+ regs32.eax, regs32.ebx, regs32.ecx, regs32.edx);
+ Show("esi = %08lx edi = %08lx ebp = %08lx esp = %08lx\n",
+ regs32.esi, regs32.edi, regs32.ebp, regs32.esp);
+ Show("fs = %04x %s\n", regs.fs, (FP)SegInfo(regs.fs));
+ Show("gs = %04x %s\n", regs.gs, (FP)SegInfo(regs.gs));
+ Show("eflag = %08lx\n", regs32.eflags);
+ MyFlush();
+ }
+
+ if (!noDisasm) {
+ Show(STR(InstructionDisasm));
+ DisAsmAround(MK_FP(regs.cs, regs.ip), disLen);
+ MyFlush();
+ }
+
+ if (!noInfo)
+ DumpInfo();
+
+ if (!noStack)
+ DumpStack(disStack, 0x7fff, 0x7fff, 0);
+
+ if (!noTasks) {
+ TASKENTRY te;
+ MODULEENTRY me;
+
+ te.dwSize = sizeof(te);
+ me.dwSize = sizeof(me);
+
+ Show(STR(SystemTasksTasks));
+ if (TaskFirst(&te)) do {
+ ModuleFindName(&me, te.szModule);
+ Show(STR(TaskHandleFlagsInfo),
+ (FP)te.szModule, te.hTask, me.wcUsage,
+ (FP)FileInfo(me.szExePath));
+ Show(STR(Filename), (FP)me.szExePath); /* */
+ } while (TaskNext(&te));
+ MyFlush();
+ }
+
+ if (!noModules) {
+ MODULEENTRY me;
+
+ Show(STR(SystemModulesModules));
+ me.dwSize = sizeof(me);
+ if (ModuleFirst(&me)) do {
+ Show(STR(ModuleHandleFlagsInfo),
+ (FP)me.szModule, me.hModule, me.wcUsage,
+ (FP)FileInfo(me.szExePath));
+ Show(STR(File), (FP)me.szExePath); /* */
+ } while (ModuleNext(&me));
+ MyFlush();
+ }
+
+SkipReport:
+ if (party>0) {
+ int len;
+ word far * stack = MK_FP(regs.ss, regs.sp);
+ Show(STR(ContinuingExecution), (FP)CurTime());
+ MyFlush();
+ /* fix up regs */
+ if (gpRegs & segDS) regs.ds = 0;
+ if (gpRegs & segES) regs.es = 0;
+ if (gpRegs & segFS) regs.fs = 0;
+ if (gpRegs & segGS) regs.gs = 0;
+ regs.ip += faultlen; /* set at top of func - don't reuse */
+ if ((int)gpStack < 0) {
+ for (i=0; i<8; i++) stack[i+gpStack] = stack[i];
+ } else if (gpStack) {
+ for (i=7; i>=0; i--) stack[i+gpStack] = stack[i];
+ }
+ regs.sp += gpStack << 1;
+ if (gpRegs & strCX) {
+ len = regs.cx * memSize;
+ regs.cx = 0;
+ } else len = memSize;
+ if (gpRegs & strSI) { /* doesn't handle 32 bit regs */
+ regs.si += len;
+ if (regs.si < (word)len) /* if overflow, set to big value */
+ regs.si = 0xfff0; /* so global vars in heap don't get */
+ } /* trashed when we continue */
+ if (gpRegs & strDI) {
+ regs.di += len;
+ if (regs.di < (word)len) regs.di = 0xfff0;
+ }
+ }
+
+ EndReport();
+ if (!noClues && /* if we want clues */
+ !pending && /* no clues waited for */
+ (!party || !(iFeelLucky & 2))) { /* and we aren't quiet partiers */
+ PostMessage(hWnd, JUST_THE_FACTS, (WPARAM)GetCurrentTask(), party);
+ pending++;
+ }
+ if (party < 0) TerminateApp(GetCurrentTask(), NO_UAE_BOX);
+ return party;
+} /* Sherlock */
+
+void far *bogus;
+
+int CallMeToo(WORD wID, DWORD dwData) {
+ NFYLOGPARAMERROR far *lpep;
+ LPSTR s[s_last];
+
+ if (wID == NFY_OUTSTR) {
+ if (noDebStr)
+ return FALSE;
+ MyOpen();
+ if (fh == -1) return FALSE;
+ Show(STR(DebugString), dwData);
+ MyClose();
+ return TRUE;
+ }
+
+ if (wID == NFY_LOGERROR && noErr)
+ return FALSE;
+
+ lpep = (void far *)dwData; /* Get the data for next log entry */
+ lastErr.adr = lpep->lpfnErrorAddr;
+ lastErr.code = lpep->wErrCode;
+ lastErr.parm = (DWORD)(lpep->lpBadParam);
+ lastErr.task = GetCurrentTask();
+ if ((lastErr.code & 0x3000) == 0x1000)
+ lastErr.parm = (WORD)lastErr.parm;
+ else if ((lastErr.code & 0x3000) == 0)
+ lastErr.parm = (BYTE)lastErr.parm;
+
+ if (wID == NFY_LOGPARAMERROR && noParam) {
+ return FALSE;
+ }
+
+ if (bugCnt++ > 60)
+ return FALSE;
+ if (!BeginReport(s[s_time] = CurTime())) /* Can't open file */
+ return FALSE;
+
+ switch (wID) {
+ case NFY_LOGERROR:
+#if 0
+ lep = (void far *)dwData;
+ cs = ip = 0;
+ parm = 0;
+ code = lep->wErrCode;
+ s[s_fault] = STR(ApplicationError);
+#endif
+ break;
+ case NFY_LOGPARAMERROR:
+ s[s_fault] = STR(InvalidParameter);
+ break;
+ default:
+ return FALSE;
+ }
+
+ s[s_prog] = CurModuleName(lastErr.task);
+ s[s_name] = GetProcName(lastErr.adr);
+ s[s_instr] = STR(NA); /* not interesting */
+ Show(STR(HadAFaultAt2),
+ (FP)s[s_prog],
+ (FP)s[s_fault], lastErr.code,
+ (FP)s[s_name]);
+ if (!noSummary) Show("$tag$%s$%s (%x)$%s$",
+ (FP)s[s_prog],
+ (FP)s[s_fault], lastErr.code,
+ (FP)s[s_name]);
+ Show(STR(ParamIs), lastErr.parm, (FP)s[s_time]);
+
+ ShowParamError(1);
+ MyFlush();
+
+ if (!noInfo && bugCnt < 2)
+ DumpInfo();
+
+ if (!noStack)
+ DumpStack(0, 0, 0x7fff, 4);
+
+ EndReport();
+ return TRUE;
+} /* CallMe */
+
+ /* Parse SkipInfo= and ShowInfo= lines into flags array */
+void ParseInfo(char *s, int val) {
+ int i;
+ strlwr(s);
+ while (*s) {
+ for (i=0; i<cntFlag; i++) if (0 == strncmp(s, syms+(i<<2), 3)) {
+ if (val) SetFlag(i);
+ else ClrFlag(i);
+ break;
+ }
+ while (*s && *s++ != ' ')
+ if (s[-1] == ',') break;
+ while (*s && *s == ' ') s++;
+ }
+} /* ParseInfo */
+
+
+/************************************
+Name: BOOL LoadStringResources(void)
+Desc: Load all string resources into GlobalAlloc'd buffer and
+ initialize aszStrings array with pointers to each string.
+ Also fixes up string IDs in wf (winflags) array to pointers.
+ Note that we don't free the memory allocated, we count on
+ kernel to clean up for us on termination.
+Bugs:
+*************************************/
+BOOL LoadStringResources(void)
+{
+ int n;
+ HANDLE h;
+ LPSTR lp;
+ WORD cbTotal;
+ WORD cbUsed;
+ WORD cbStrLen;
+
+ //
+ // Allocate too much memory for strings (maximum possible) at first,
+ // reallocate to the real size when we're done loading strings.
+ //
+
+#if (STRING_COUNT * CCH_MAX_STRING_RESOURCE > 65536 - 64)
+#error Need to use HUGE pointer for lp and DWORD for cb in LoadStringResources
+#endif
+
+ cbTotal = STRING_COUNT * CCH_MAX_STRING_RESOURCE;
+
+ h = GlobalAlloc(GMEM_FIXED, cbTotal);
+
+ if ( ! h ) {
+ return FALSE;
+ }
+
+ lp = GlobalLock(h);
+
+ cbUsed = 0;
+
+ for ( n = 0; n < STRING_COUNT; n++ ) {
+
+ cbStrLen = LoadString(hInst, n, lp, CCH_MAX_STRING_RESOURCE);
+
+ if ( ! cbStrLen ) {
+ return FALSE;
+ }
+
+ aszStrings[n] = lp;
+
+ lp += cbStrLen + 1; // LoadString return doesn't count null terminator
+ cbUsed += cbStrLen + 1;
+
+ }
+
+ GlobalReAlloc(h, cbUsed, 0);
+
+
+ //
+ // Fix up winflags array elements from string resource IDs to pointers
+ //
+
+ for ( n = 0; n < wfCnt; n++ ) {
+ wf[n].name = aszStrings[ (int)(DWORD)wf[n].name ];
+ }
+
+ return TRUE;
+}
+
+
+
+/************************************
+Name: void DumpIni(void)
+Desc: Write profile strings to log file
+Bugs:
+*************************************/
+#if 0
+void DumpIni() {
+ int i;
+ char buf[4];
+
+ buf[3] = 0;
+ MyOpen();
+ Show("Re-read win.ini\nshowinfo="); // move to resource file if ever used
+ for (i=0; i<cntFlag; i++) {
+ if (!flag(i)) {
+ memcpy(buf, syms+(i<<2), 3);
+ Show("%s ", (FP)buf);
+ }
+ }
+ Show("\nskipinfo=");
+ for (i=0; i<cntFlag; i++) {
+ if (flag(i)) {
+ memcpy(buf, syms+(i<<2), 3);
+ Show("%s ", (FP)buf);
+ }
+ }
+ Show("\n");
+ MyClose();
+} /* DumpIni */
+
+#endif
+
+/************************************
+Name: int ReadWinIni(void)
+Desc: Read profile strings from WIN.INI.
+ Return 0 if failure.
+Bugs:
+*************************************/
+STATIC int ReadWinIni(void) {
+ char line[80];
+ int len;
+
+ /* how many instructions should I disassemble by default? */
+ disLen = GetProfileInt(szAppName, "dislen", 8);
+
+ /* should I trap divide by 0 faults? */
+ trapZero = GetProfileInt(szAppName, "trapzero", 0);
+
+ /* should we allow restarting apps? */
+ iFeelLucky = GetProfileInt(szAppName, "GPContinue", 1);
+ /* if (!(iFeelLucky & 16)) noSound = 1; */
+
+ /* how many stack frames should be disassembled? */
+ disStack = GetProfileInt(szAppName, "DisStack", 2);
+
+ /* where should I write the log file to? */
+ GetProfileString(szAppName, "logfile", szAppNameShortLog, logFile, sizeof(logFile));
+ len = strlen(logFile);
+
+ if ((len == 0) || // logfile=
+ (logFile[len-1] == '\\') || // directory only (boo, hiss)
+ (logFile[len-1] == '/') ||
+ (logFile[len-1] == ':')) { // drive only
+ if (len && (logFile[len-1] == ':')) { // drive only, put in root
+ strcat(logFile, "\\");
+ }
+ strcat(logFile, szAppNameShortLog); // append a file name
+ }
+ if (!(strchr(logFile, '\\') // if no path specified, put in WinDir
+ || strchr(logFile, ':')
+ || strchr(logFile, '/'))) {
+ char logname[80];
+ int n;
+ GetWindowsDirectory(logname, sizeof(logname));
+ n = strlen(logname);
+ if (n && logname[n-1] != '\\')
+ strcat(logname, "\\");
+ strcat(logname, logFile);
+ strcpy(logFile, logname);
+ }
+
+ /* Set default flag values - see DrWatson.h for default values */
+ ddFlag = DefFlag;
+
+ /* do I really have to print out all this information? */
+ if (GetProfileString(szAppName, "skipinfo", "", line, sizeof(line)))
+ ParseInfo(line, 1);
+
+ if (GetProfileString(szAppName, "showinfo", "", line, sizeof(line)))
+ ParseInfo(line, 0);
+
+#if 0
+ DumpIni();
+#endif
+ return 1;
+} /* ReadWinIni */
+
+/************************************
+Name: int InitSherlock(void)
+Desc: Initialize Sherlock processing. Install GP fault handler.
+ Return 0 if failure.
+Bugs:
+*************************************/
+STATIC int InitSherlock(void) {
+
+ /* do I have 32 bit registers? */
+ cpu32 = (GetWinFlags() & (WF_CPU386|WF_CPU486)) != 0;
+
+ /* see what WIN.INI [drwatson] has to say */
+ if (!ReadWinIni()) return 0;
+
+ NotifyRegister(hTask, (LPFNNOTIFYCALLBACK)CallMe, NF_NORMAL);
+
+ /* Now get ToolHelp to do the dirty work */
+ return InterruptRegister(hTask, GPFault);
+} /* InitSherlock */
+
+/************************************
+Name: void Moriarty
+Desc: Destroy any evidence Sherlock was loaded.
+Bugs: Am I freeing all resources I used?
+*************************************/
+int init;
+STATIC void Moriarty(void) {
+ if (init) {
+ if (!noTime) PutDate(STR(Stop));
+ InterruptUnRegister(hTask);
+ NotifyUnRegister(hTask);
+ init = 0;
+ }
+} /* Moriary */
+
+/************************************
+Name: WINAPI SherlockWndProc(hWnd, wMessage, wParam, lParam)
+Desc: Handle sherlock icon, close processing
+Bugs: Should pull up dialog boxes for About and GetInfo
+*************************************/
+LRESULT CALLBACK SherlockWndProc (HWND hWnd, UINT iMessage,
+ WPARAM wParam, LPARAM lParam) {
+ char msg[200];
+ /* int (FAR PASCAL *dfp)(HWND, WORD, WORD, DWORD); */
+ FARPROC dfp;
+
+ switch (iMessage) {
+ case WM_ENDSESSION:
+ if (wParam) Moriarty();
+ break;
+
+ case WM_DESTROY: /* Quit Sherlock */
+ PostQuitMessage (0);
+ break;
+
+ case WM_QUERYOPEN: /* never open a window??? */
+ PostMessage(hWnd, YOO_HOO, 0, 1);
+ ReadWinIni();
+ break;
+
+ case WM_WININICHANGE: /* Re-read WIN.INI parameters */
+ ReadWinIni();
+ break;
+
+ case YOO_HOO:
+ if (bugCnt) {
+ wsprintf(msg, STR(Faulty), bugCnt, (FP)logFile);
+ MessageBox(hWnd, msg, szAppNameVers,
+ MB_ICONINFORMATION | MB_OK | MB_TASKMODAL);
+ } else {
+ MessageBox(hWnd, STR(NoFault), szAppNameVers,
+ MB_ICONINFORMATION | MB_OK | MB_TASKMODAL);
+ }
+ break;
+
+ case HEAP_BIG_FILE:
+ wsprintf(msg, STR(LogFileGettingLarge),
+ (FP)logFile);
+ MessageBox(hWnd, msg, szAppNameVers,
+ MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL);
+ break;
+
+ case JUST_THE_FACTS:
+ dfp = MakeProcInstance((FARPROC)SherlockDialog, hInst);
+ DialogBox(hInst, "SherDiag", hWnd, (DLGPROC)dfp);
+ FreeProcInstance(dfp);
+ pending = 0; /* finished all old business */
+ break;
+
+ default:
+ return DefWindowProc (hWnd,iMessage,wParam,lParam);
+ }
+ return 0L;
+}
+
+/************************************
+Name: WinMain(hInst, hPrevInst, cmdLine, cmdShow)
+Desc: Init Sherlock - this is where it all begins
+Bugs:
+*************************************/
+int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ LPSTR lpszCmdLine, int nCmdShow) {
+ MSG msg; /* Message returned from message loop */
+ WNDCLASS wndclass; /* Sherlock window class */
+ char watsonStack[4096];
+
+ nCmdShow = nCmdShow;
+ lpszCmdLine = lpszCmdLine;
+ newsp = watsonStack + sizeof(watsonStack);
+ hInst = hInstance;
+ hTask = GetCurrentTask();
+
+ /* Check if Sherlock is already running */
+ if (!hPrevInstance) {
+
+ if (!LoadStringResources()) {
+ MessageBox(NULL, "Dr. Watson could not load all string resources",
+ szAppNameVers, MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
+ return 1;
+ }
+
+ /* Define a new window class */
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+ wndclass.lpfnWndProc = SherlockWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = hInstance;
+ wndclass.hIcon = LoadIcon (hInstance, szAppNameShortMacro "Icon");
+ wndclass.hCursor = LoadCursor (NULL,IDC_ARROW);
+ wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szAppName;
+
+ if (!RegisterClass (&wndclass)) {
+ MessageBox(NULL, STR(ClassMsg), szAppNameVers, MB_ICONEXCLAMATION | MB_OK |
+ MB_SYSTEMMODAL);
+ return 1;
+ }
+ } else {
+ /* Instance is already running, issue warning and terminate */
+ MessageBox (NULL, STR(ErrMsg), szAppNameVers, MB_ICONEXCLAMATION | MB_OK |
+ MB_SYSTEMMODAL);
+ return 1;
+ }
+
+ /* Create window and display in iconic form */
+ hWnd = CreateWindow (szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
+ 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+ ShowWindow (hWnd, SW_SHOWMINNOACTIVE);
+ UpdateWindow (hWnd);
+
+ if (!InitSherlock()) {
+ MessageBox (/*NULL*/hWnd, STR(Vers), szAppNameVers, MB_ICONEXCLAMATION | MB_OK |
+ MB_SYSTEMMODAL);
+ DestroyWindow(hWnd);
+ return 1;
+ }
+
+ if (!noTime) PutDate(STR(Start));
+ init = 1;
+
+ while (GetMessage (&msg, NULL, 0, 0)) {/* Enter message loop */
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ imTrying = 0;
+ }
+
+ Moriarty(); /* Remove Sherlock GP Handler from GP Handler chain */
+
+ return msg.wParam;
+} /* WinMain */
diff --git a/private/mvdm/wow16/sherlock/drwatson.def b/private/mvdm/wow16/sherlock/drwatson.def
new file mode 100644
index 000000000..bad6299d7
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/drwatson.def
@@ -0,0 +1,13 @@
+NAME DRWATSON WINDOWAPI
+DESCRIPTION 'System Diagnostic Utility'
+EXETYPE WINDOWS
+STUB '..\bin\WINSTUB.EXE'
+CODE MOVEABLE PRELOAD NONDISCARDABLE
+DATA MULTIPLE MOVEABLE PRELOAD
+HEAPSIZE 512
+STACKSIZE 9216 ; 4K for interrupt, 5K for program
+EXPORTS
+ SherlockWndProc @1
+ SherlockDialog @2
+; CallMe @3
+
diff --git a/private/mvdm/wow16/sherlock/drwatson.h b/private/mvdm/wow16/sherlock/drwatson.h
new file mode 100644
index 000000000..1f3d3a1a4
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/drwatson.h
@@ -0,0 +1,55 @@
+/* DrWatson.h - global info for Dr. Watson */
+
+enum {
+ eClu, eDeb, eDis, eErr, eInf, eLin, eLoc, eMod,
+ ePar, eReg, eSum, eSeg, eSou, eSta, eTas, eTim,
+ e32b
+};
+
+#define bClu (1L << eClu)
+#define bDeb (1L << eDeb)
+#define bDis (1L << eDis)
+#define bErr (1L << eErr)
+#define bInf (1L << eInf)
+#define bLin (1L << eLin)
+#define bLoc (1L << eLoc)
+#define bMod (1L << eMod)
+#define bPar (1L << ePar)
+#define bReg (1L << eReg)
+#define bSum (1L << eSum)
+#define bSeg (1L << eSeg)
+#define bSou (1L << eSou)
+#define bSta (1L << eSta)
+#define bTas (1L << eTas)
+#define bTim (1L << eTim)
+#define b32b (1L << e32b)
+
+
+#define flag(b) (((char *)&ddFlag)[b >> 3] & 1 << (b & 7))
+#define SetFlag(b) ((char *)&ddFlag)[b >> 3] |= 1 << (b&7)
+#define ClrFlag(b) ((char *)&ddFlag)[b >> 3] &= ~(1 << (b&7))
+
+
+#define noClues flag(eClu) /* Clues dialog box */
+#define noDebStr flag(eDeb) /* OutputDebugString trapping */
+#define noDisasm flag(eDis) /* Simple disassembly */
+#define noErr flag(eErr) /* Error logging */
+#define noInfo flag(eInf) /* System info */
+#define noLine flag(eLin) /* Lookup line# in SYM file */
+#define noLocal flag(eLoc) /* Local vars on stack dump */
+#define noModules flag(eMod) /* Module dump */
+
+#define noParam flag(ePar) /* Parameter error logging */
+#define noReg flag(eReg) /* Register dump */
+#define noSummary flag(eSum) /* 3 line summary */
+#define noSeg flag(eSeg) /* not visible to users, but available */
+#define noSound flag(eSou) /* But I _like_ the sound effects! */
+#define noStack flag(eSta) /* Stack trace */
+#define noTasks flag(eTas) /* Task dump */
+#define noTime flag(eTim) /* Time start/stop */
+
+#define noReg32 flag(e32b) /* 32 bit register dump */
+
+#define DefFlag (bDeb | bDis | bErr | bMod | bLin | bLoc | bPar | bSou)
+
+extern unsigned long ddFlag;
diff --git a/private/mvdm/wow16/sherlock/error.c b/private/mvdm/wow16/sherlock/error.c
new file mode 100644
index 000000000..883393584
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/error.c
@@ -0,0 +1,87 @@
+#include <windows.h>
+#include <logerror.h>
+#include "str.h"
+
+#ifdef API
+#undef API
+#endif
+#define API _far _pascal _loadds
+
+
+#define SELECTOROF(lp) HIWORD(lp)
+#define OFFSETOF(lp) LOWORD(lp)
+
+static WORD wErrorOpts = 0;
+
+static char rgch[80];
+
+char *LogErrorStr(WORD err, VOID FAR* lpInfo) {
+ void DebugLogError(WORD err, VOID FAR* lpInfo);
+
+ if (err & ERR_WARNING)
+ wsprintf(rgch, STR(WarningError), err);
+ else
+ wsprintf(rgch, STR(FatalError), err);
+ return rgch;
+}
+
+LPSTR GetProcName(FARPROC fn);
+
+char *LogParamErrorStr(WORD err, FARPROC lpfn, VOID FAR* param) {
+ LPSTR rgchProcName;
+
+ rgchProcName = GetProcName(lpfn);
+
+
+ switch ((err & ~ERR_FLAGS_MASK) | ERR_PARAM)
+ {
+ case ERR_BAD_VALUE:
+ case ERR_BAD_INDEX:
+ wsprintf(rgch, STR(ParamErrorBadInt), rgchProcName, (WORD)(DWORD)param);
+ break;
+
+ case ERR_BAD_FLAGS:
+ case ERR_BAD_SELECTOR:
+ wsprintf(rgch, STR(ParamErrorBadFlags), rgchProcName, (WORD)(DWORD)param);
+ break;
+
+ case ERR_BAD_DFLAGS:
+ case ERR_BAD_DVALUE:
+ case ERR_BAD_DINDEX:
+ wsprintf(rgch, STR(ParamErrorBadDWord), rgchProcName, (DWORD)param);
+ break;
+
+ case ERR_BAD_PTR:
+ case ERR_BAD_FUNC_PTR:
+ case ERR_BAD_STRING_PTR:
+ wsprintf(rgch, STR(ParamErrorBadPtr), rgchProcName,
+ SELECTOROF(param), OFFSETOF(param));
+ break;
+
+ case ERR_BAD_HINSTANCE:
+ case ERR_BAD_HMODULE:
+ case ERR_BAD_GLOBAL_HANDLE:
+ case ERR_BAD_LOCAL_HANDLE:
+ case ERR_BAD_ATOM:
+ case ERR_BAD_HWND:
+ case ERR_BAD_HMENU:
+ case ERR_BAD_HCURSOR:
+ case ERR_BAD_HICON:
+ case ERR_BAD_GDI_OBJECT:
+ case ERR_BAD_HDC:
+ case ERR_BAD_HPEN:
+ case ERR_BAD_HFONT:
+ case ERR_BAD_HBRUSH:
+ case ERR_BAD_HBITMAP:
+ case ERR_BAD_HRGN:
+ case ERR_BAD_HPALETTE:
+ case ERR_BAD_HANDLE:
+ wsprintf(rgch, STR(ParamErrorBadHandle), rgchProcName, (WORD)(DWORD)param);
+ break;
+
+ default:
+ wsprintf(rgch, STR(ParamErrorParam), rgchProcName, (DWORD)param);
+ break;
+ }
+ return rgch;
+}
diff --git a/private/mvdm/wow16/sherlock/getsym.c b/private/mvdm/wow16/sherlock/getsym.c
new file mode 100644
index 000000000..659cd5cc8
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/getsym.c
@@ -0,0 +1,113 @@
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include "disasm.h" /* wsprintf() */
+#include "drwatson.h"
+
+#define _lread(h, adr, cnt) _lread(h, (LPSTR)(adr), cnt)
+
+/* Last entry in .SYM file */
+
+typedef struct tagMAPEND {
+ unsigned chnend; /* end of map chain (0) */
+ char rel; /* release */
+ char ver; /* version */
+} MAPEND;
+
+/* Structure of .SYM file symbol entry */
+
+typedef struct tagSYMDEF {
+ unsigned sym_val; /* 16 bit symbol addr or const */
+ char nam_len; /* 8 bit symbol name length */
+} SYMDEF;
+
+/* Structure of a .SYM file segment entry */
+
+typedef struct tagSEGDEF {
+ unsigned nxt_seg; /* 16 bit ptr to next segment(0 if end) */
+ int sym_cnt; /* 16 bit count of symbols in sym list */
+ unsigned sym_ptr; /* 16 bit ptr to symbol list */
+ unsigned seg_lsa; /* 16 bit Load Segment address */
+ unsigned seg_in0; /* 16 bit instance 0 physical address */
+ unsigned seg_in1; /* 16 bit instance 1 physical address */
+ unsigned seg_in2; /* 16 bit instance 2 physical address */
+ unsigned seg_in3; /* 16 bit instance 3 physical address */
+ unsigned seg_lin; /* 16 bit ptr to line number record */
+ char seg_ldd; /* 8 bit boolean 0 if seg not loaded */
+ char seg_cin; /* 8 bit current instance */
+ char nam_len; /* 8 bit Segment name length */
+} SEGDEF;
+
+/* Structure of a .SYM file MAP entry */
+
+typedef struct tagMAPDEF {
+ unsigned map_ptr; /* 16 bit ptr to next map (0 if end) */
+ unsigned lsa ; /* 16 bit Load Segment address */
+ unsigned pgm_ent; /* 16 bit entry point segment value */
+ int abs_cnt; /* 16 bit count of constants in map */
+ unsigned abs_ptr; /* 16 bit ptr to constant chain */
+ int seg_cnt; /* 16 bit count of segments in map */
+ unsigned seg_ptr; /* 16 bit ptr to segment chain */
+ char nam_max; /* 8 bit Maximum Symbol name length */
+ char nam_len; /* 8 bit Symbol table name length */
+} MAPDEF;
+
+/* should cache last 4 files, last 4 segments, last 4 symbol blocks */
+
+void cdecl Show(char *foo, ...);
+
+#define MAXSYM 64
+char *FindSym(unsigned segIndex, unsigned offset, int h) {
+ static char sym_name[MAXSYM+5];
+ char name[MAXSYM+3];
+ int i;
+ MAPDEF mod;
+ SEGDEF seg;
+ SYMDEF sym, *sp;
+
+ if (sizeof(mod) != _lread(h, &mod, sizeof(mod))) return 0;
+ if (segIndex > (unsigned)mod.seg_cnt) return 0;
+ seg.nxt_seg = mod.seg_ptr;
+ for (i=0; i<mod.seg_cnt; i++) {
+ _llseek(h, (long)seg.nxt_seg << 4, SEEK_SET);
+ _lread(h, &seg, sizeof(seg));
+ if (seg.seg_lsa == segIndex) break;
+ }
+ if (seg.seg_lsa != segIndex) return 0;
+ _llseek(h, seg.nam_len, SEEK_CUR);
+ sym_name[0] = 0;
+ sym.sym_val = 0xffff;
+ sym.nam_len = 0;
+ for (i=0; i<seg.sym_cnt; i++) {
+ unsigned len = sizeof(sym) + sym.nam_len;
+ if (len >= sizeof(name)) return 0;
+ if (len != _lread(h, name, len)) return 0;
+ sp = (SYMDEF *)(name + sym.nam_len);
+ if (sp->sym_val > offset)
+ break;
+ sym = *sp;
+ }
+ name[sym.nam_len] = 0;
+ if (name[0] == 0) return 0;
+ if (sym.sym_val == offset) strcpy(sym_name, name);
+ else sprintf(sym_name, "%s+%04x", (FP)name, offset-sym.sym_val);
+ return sym_name;
+} /* FindSym */
+
+char *NearestSym(int segIndex, unsigned offset, char *exeName) {
+ char fName[80];
+ /* OFSTRUCT reOpen; */
+ char *s;
+ int h;
+
+ strcpy(fName, exeName);
+ strcpy(fName+strlen(fName)-4, ".sym");
+
+ h = _lopen(fName, OF_READ | OF_SHARE_DENY_WRITE);
+
+ if (h == -1) return 0;
+ s = FindSym(segIndex, offset, h);
+ _lclose(h);
+ return s;
+} /* NearestSym */
+
diff --git a/private/mvdm/wow16/sherlock/makefile b/private/mvdm/wow16/sherlock/makefile
new file mode 100644
index 000000000..760c5a659
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/makefile
@@ -0,0 +1,77 @@
+#
+# retail flags
+CL = cl16 -c -AS -G2sw -Os -D__MSC__ -W3 -Zpe $(INCS)
+MASM = masm $(INCS)
+#
+# debug flags
+#
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+DEBUG=1
+CDEBUG = /Od /Oi /Zd
+ADEBUG = -Zd
+LDEBUG = /LI
+!endif
+
+!ifdef DEBUG
+CL = $(CL) $(CDEBUG)
+MASM = $(MASM) $(ADEBUG)
+LDEBUG = $(LDEBUG)
+!endif
+
+INCS = -I..\inc -I..\..\inc -I..\toolhelp
+
+OBJ = drwatson.obj disasm.obj getsym.obj watson.obj error.obj
+
+RES_DIR=.\messages\usa
+!IFDEF COUNTRY
+RES_DIR=.\messages\$(COUNTRY)
+!ENDIF
+!ifdef DBCS
+RES_DIR=.\messages\$(DBCS)
+!endif
+
+
+all: drwatson.exe
+
+.c.obj:
+ $(CL) $*.c
+
+drwatson.obj: drwatson.c drwatson.h disasm.h str.h
+
+error.obj: error.c str.h
+
+disasm.obj : disasm.c disasm.h
+
+getsym.obj : getsym.c drwatson.h disasm.h
+
+watson.obj : watson.asm
+ $(MASM) watson.asm,,watson.lst;
+
+$(RES_DIR)\drwatson.res: $(RES_DIR)\drwatson.rc $(RES_DIR)\drwatson.rcv ..\inc\common.ver str.h
+ rc16 -r $(INCS) $(RES_DIR)\drwatson.rc
+
+drwatson.exe: $(OBJ) $(RES_DIR)\drwatson.res sherlock.lnk drwatson.def
+ link16 $(LDEBUG) @sherlock.lnk
+ mapsym drwatson
+ rc16 -t -30 $(RES_DIR)\drwatson.res drwatson.exe
+ binplace drwatson.exe drwatson.map drwatson.sym
+
+# note that TOOLHELP.LIB must exist somewhere on your lib path
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist drwatson.exe del drwatson.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
diff --git a/private/mvdm/wow16/sherlock/messages/usa/drwatson.rc b/private/mvdm/wow16/sherlock/messages/usa/drwatson.rc
new file mode 100644
index 000000000..ac02ba7c1
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/messages/usa/drwatson.rc
@@ -0,0 +1,235 @@
+#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "drwatson.rcv"
+
+#include "str.h"
+
+drwatsonIcon ICON doctor.ico
+
+#define DS_3DLOOK 0x0004
+
+SHERDIAG DIALOG DISCARDABLE LOADONCALL PURE MOVEABLE 59, 42, 179, 124
+STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | DS_3DLOOK
+CAPTION "Dr. Watson's Clues"
+BEGIN
+ CONTROL "To help fix the problem you just encountered, please describe what you were doing before the fault occurred." 101, "STATIC", WS_CHILD | WS_VISIBLE | 0x1L, 26, 5, 128, 26
+ CONTROL "" 102, "EDIT", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | 0x44L, 13, 33, 151, 62
+ CONTROL "OK" 1, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 32, 101, 32, 14
+ CONTROL "Cancel" 2, "BUTTON", WS_CHILD | WS_VISIBLE | WS_TABSTOP, 110, 101, 36, 14
+END
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+
+/* Note all strings below must be <= CCH_MAX_STRING_RESOURCE chars! */
+
+/* drwatson.c */
+
+IDSTRNoFault "No Faults Detected\n\nCopyright 1991-1995, Microsoft Corp."
+IDSTRFaulty "%d new 'Dr. Watson' Failure Reports can be found in file '%s'\n\nCopyright 1991-1995, Microsoft Corp."
+IDSTRGPText "An error has occurred in your application.\nIf you choose Ignore, you should save your work in a new file.\nIf you choose Close, your application will terminate."
+IDSTRErrMsg "A copy of 'Dr. Watson' is already running on the system."
+IDSTRVers "Unable to install 'Dr. Watson', may have wrong version of TOOLHELP.DLL"
+IDSTRClassMsg "Unable to install 'Dr. Watson', can't register window class."
+IDSTRCoprocessor "Math coprocessor"
+IDSTR8086 "8086"
+IDSTR80186 "80186 or 80188"
+IDSTR80286 "80286"
+IDSTR80386 "80386 or 80386 SX"
+IDSTR80486 "80486"
+IDSTREnhancedMode "Enhanced mode"
+IDSTRProtectMode "Protect mode"
+IDSTRStandardMode "Standard mode"
+IDSTRWindowsNT "Windows NT"
+
+/* drwatson.c SegFlags */
+
+IDSTRNullPtr "Null Ptr"
+IDSTRInvalid "Invalid"
+IDSTRNotPresent "!Present"
+IDSTRCode "Code "
+IDSTRExR "Ex/R"
+IDSTRExO "Ex/O"
+IDSTRData "Data "
+IDSTRRW "R/W"
+IDSTRRO "R-O"
+
+/* drwatson.c ModuleName (and several others) */
+
+IDSTRUnknown "Unknown"
+
+/* drwatson.c FaultType */
+
+IDSTRDivideByZero "Divide by 0"
+IDSTRInvalidOpcode "Invalid Opcode"
+IDSTRGeneralProtection "General Protection"
+
+/* drwatson.c DecodeFault */
+
+IDSTRInvalidSelector "Invalid selector"
+IDSTRNullSelector "Null Selector"
+IDSTRSegmentNotPresent "Segment Not Present"
+IDSTRExceedSegmentBounds "Exceed Segment Bounds"
+IDSTRCodeSegment "Code Segment"
+IDSTRExecuteOnlySegment "Execute-Only Segment"
+IDSTRReadOnlySegment "Read-Only Segment"
+
+/* drwatson.c SafeDisAsm86 */
+
+IDSTRSegNotPresentOrPastEnd "Segment not present, or past end"
+
+/* drwatson.c FaultCause */
+
+IDSTRErrorLog "Error Log"
+IDSTRParameterErrorLog "Parameter Error Log"
+
+/* drwatson.c FileInfo */
+
+IDSTRFileNotFound "File Not Found"
+
+/* drwatson.c DisAsmAround */
+
+IDSTRCodeSegmentNPOrInvalid "Code segment not present, or invalid\n"
+IDSTRNoSymbolsFound "(no symbols found)\n"
+
+/* drwatson.c DumpInfo */
+
+IDSTRSystemInfoInfo "System Info (info)\n"
+IDSTRWindowsVersion "Windows version %d.%02d\n"
+IDSTRDebugBuild "Debug build\n"
+IDSTRRetailBuild "Retail build\n"
+IDSTRWindowsBuild "Windows Build %s\n"
+IDSTRUsername "Username %s\n"
+IDSTROrganization "Organization %s\n"
+IDSTRSystemFreeSpace "System Free Space %ld\n"
+IDSTRStackBaseTopLowestSize "Stack base %u, top %u, lowest %u, size %u\n"
+IDSTRSystemResourcesUserGDI "System resources: USER: %u%% free, seg %04x GDI: %u%% free, seg %04x\n"
+IDSTRMemManInfo1 "LargestFree %ld, MaxPagesAvail %ld, MaxPagesLockable %ld\n"
+IDSTRMemManInfo2 "TotalLinear %ld, TotalUnlockedPages %ld, FreePages %ld\n"
+IDSTRMemManInfo3 "TotalPages %ld, FreeLinearSpace %ld, SwapFilePages %ld\n"
+IDSTRMemManInfo4 "Page Size %d\n"
+IDSTRTasksExecuting "%d tasks executing.\n"
+IDSTRWinFlags "WinFlags -\n"
+
+/* drwatson.c GetProcName */
+
+IDSTRUnknownAddress "Unknown address"
+
+/* drwatson.c DumpStack */
+
+IDSTRStackDumpStack "Stack Dump (stack)\n"
+IDSTRStackFrameInfo "Stack Frame %d is %-28s ss:bp %04x:%04x"
+
+/* drwatson.c BeginReport */
+
+IDSTRFailureReport "\n%s Failure Report - %s"
+
+/* drwatson.c ShowParamError */
+
+IDSTRLastParamErrorWas "Last param error was:"
+
+/* drwatson.c Sherlock */
+
+IDSTRHadAFaultAt "%s had a '%s' fault at %s\n"
+IDSTRCPURegistersRegs "CPU Registers (regs)\n"
+IDSTRCPU32bitRegisters32bit "CPU 32 bit Registers (32bit)\n"
+IDSTRInstructionDisasm "Instruction Disassembly (disasm)\n"
+IDSTRSystemTasksTasks "System Tasks (tasks)\n"
+IDSTRTaskHandleFlagsInfo "Task %8s, Handle %04x, Flags %04x, Info %s\n"
+IDSTRFilename " FileName %s\n"
+IDSTRSystemModulesModules "System Modules (modules)\n"
+IDSTRModuleHandleFlagsInfo "Module %8s, Handle %04x, Flags %04x, Info %s\n"
+IDSTRFile " File %s\n"
+IDSTRContinuingExecution "Attempting to continue execution at user request, %s"
+
+/* drwatson.c CallMeToo */
+
+IDSTRDebugString "DebugString: %s"
+IDSTRApplicationError "Application Error"
+IDSTRInvalidParameter "Invalid Parameter"
+IDSTRNA "n.a."
+IDSTRHadAFaultAt2 "%s had a '%s (%x)' fault at %s\n"
+IDSTRParamIs "param is %lx$%s\n"
+
+/* drwatson.c Moriarty */
+
+IDSTRStop "Stop"
+
+/* drwatson.c SherlockWndProc */
+
+IDSTRLogFileGettingLarge "Your 'Dr. Watson' log file '%s' is getting quite large."
+
+/* drwatson.c WinMain */
+
+IDSTRStart "\nStart"
+
+/* error.c LogErrorStr */
+
+IDSTRWarningError "\r\n\r\nWarning error #%04x"
+IDSTRFatalError "\r\n\r\nFatal error #%04x"
+
+/* error.c LogParamErrorStr */
+
+IDSTRParamErrorParam "Invalid parameter passed to %s: %ld"
+IDSTRParamErrorBadInt "Invalid parameter passed to %s: %d"
+IDSTRParamErrorBadFlags "Invalid flags passed to %s: %#04x"
+IDSTRParamErrorBadDWord "Invalid flags passed to %s: %#08lx"
+IDSTRParamErrorBadHandle "Invalid handle passed to %s: %#04x"
+IDSTRParamErrorBadPtr "Invalid pointer passed to %s: %#04x:%#04x"
+
+/* drwatson.c CurTime -- These strings must be short enough to not overflow
+ the 48-byte buffer used by CurTime with a string of
+ the form "Fri Sep 1 01:58:19 1995" (which is 24
+ characters + 1 for the null terminator). */
+
+IDSTRJan "Jan"
+IDSTRFeb "Feb"
+IDSTRMar "Mar"
+IDSTRApr "Apr"
+IDSTRMay "May"
+IDSTRJun "Jun"
+IDSTRJul "Jul"
+IDSTRAug "Aug"
+IDSTRSep "Sep"
+IDSTROct "Oct"
+IDSTRNov "Nov"
+IDSTRDec "Dec"
+
+IDSTRSun "Sun"
+IDSTRMon "Mon"
+IDSTRTue "Tue"
+IDSTRWed "Wed"
+IDSTRThu "Thu"
+IDSTRFri "Fri"
+IDSTRSat "Sat"
+
+END
diff --git a/private/mvdm/wow16/sherlock/messages/usa/drwatson.rcv b/private/mvdm/wow16/sherlock/messages/usa/drwatson.rcv
new file mode 100644
index 000000000..85e1100ac
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/messages/usa/drwatson.rcv
@@ -0,0 +1,16 @@
+/********************************************************************/
+/* DRWATSON.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Fault detection utility"
+#define VER_INTERNALNAME_STR "DRWATSON"
+#define VER_ORIGINALFILENAME_STR "DRWATSON.EXE"
+
+
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/sherlock/sherlock.doc b/private/mvdm/wow16/sherlock/sherlock.doc
new file mode 100644
index 000000000..32a821adf
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/sherlock.doc
Binary files differ
diff --git a/private/mvdm/wow16/sherlock/sherlock.ico b/private/mvdm/wow16/sherlock/sherlock.ico
new file mode 100644
index 000000000..cdd79d25c
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/sherlock.ico
Binary files differ
diff --git a/private/mvdm/wow16/sherlock/sherlock.lnk b/private/mvdm/wow16/sherlock/sherlock.lnk
new file mode 100644
index 000000000..75136b1bc
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/sherlock.lnk
@@ -0,0 +1,5 @@
+drwatson disasm getsym watson error
+drwatson.exe
+drwatson.map
+..\lib\libw ..\lib\slibcew ..\toolhelp\toolhelp
+drwatson.def /ALIGN:16 /NOE /NOD /MAP;
diff --git a/private/mvdm/wow16/sherlock/sherlock.txt b/private/mvdm/wow16/sherlock/sherlock.txt
new file mode 100644
index 000000000..8feb49eec
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/sherlock.txt
@@ -0,0 +1,111 @@
+Changes to Sherlock
+
+8 May 1991
+==========
+donc Put report in Windows, not Windows\System, directory (before today)
+donc Fix hang when switched to using TaskMan (before today)
+donc Increase stack size - TIGA hang (before today)
+donc Change version to 0.71
+donc Avoid divide-by-0 in GDI (jont)
+donc Link with ToolHelp again, not Sherlock.DLL (timg)
+donc Fix mispelled 'occurred'
+donc Validate code segment on stack walk (hang bug)
+donc Add sherlock version # to pop-up box
+donc Decode more faulting instructions - [rep] string group
+donc Decode xlat instruction
+donc Show file date, size, and time
+donc Detect large Sherlock file and warn user
+donc Show local variables
+donc Reformat output, so it fits 80 column lines even when mailed
+donc Show owner of code in DisAsm
+donc Two line summary of important info
+
+9 May 1991
+==========
+donc Disable divide-by-0 fault unless "trapzero=1" in [sherlock] win.ini
+donc Changed version to 0.72
+donc Return whether error was Read, Write or Read/Write of memory
+
+15 May 1991
+===========
+donc Change version to 0.73
+donc Change name to Dr. Watson (when?)
+
+5 June 1991
+===========
+donc Change version to 0.74
+donc cmp was treated as RMW, now is Read
+donc "xchg ax, reg" was shown as "xchg reg"
+donc Change icon from Sherlock pipe to Doctor bag and stethescope
+donc Print out app stack values (base, top, lowest, size)
+donc Return 1 to WM_INITDIALOG (fix focus bug??)
+donc Sign extend 1 byte address immediates
+donc Change "occured" to "occurred" in dialog box
+donc Disable disassembly of stack trace after 'N' levels, default 2
+donc Print out USER and GDI heap stats (free, max, %, seg)
+kensy Write util to add symbols to log file created with no access
+donc Reduce memory used - don't call sprintf(), vsprintf(), open(), write()
+donc Move information (windows version, etc) to top of log entry
+donc "mov [mem], reg" was RMW, now is Write
+donc Remove Tab2Spc() in DisAsm86(), leave tabs in disassmbly
+donc Don't save regs unless we are trapping the interrupt
+donc Allow just commas between entries in skipinfo= in [Dr. Watson]
+donc Add asterisk (*****) line before each report
+donc Add "Stop Dr. Watson" entry each time program is terminated
+donc Show Windows build, user, organization in report (Win 3.10.34d+)
+donc Make OK button the default in Clues dialog box
+donc Change JNLE to JG, etc
+
+7 June 1991
+===========
+donc Change version to 0.74a
+donc Allow skipping local vars (skipinfo=locals)
+donc Change default skipinfo from nothing to modules+disasm
+donc Change $tag$ line so all seperators are '$', not tabs
+
+15 June 1991
+============
+donc Add sound to GP fault printing (skipinfo=sound)
+donc Allow GP continuation if GPFault&1
+donc Don't bring up dialog box if GPFault&2
+donc Allow GP continuation for memory access, segment load instructions
+donc Don't do complete report if more than 2 reports have already been done
+
+24 June 1991
+============
+donc Disable sound unless GPContinue & 16
+donc Add SysErrorBox() if fault is ignorable.
+donc SysErrorBox behaves differently Win3 and Win3.1, so do I
+donc Default GPContine == 1
+
+26 June 1991
+============
+donc Fix crash in Win 3.0 when compiled with MSC (GetVersion())
+donc Allow 3 full reports, 20 total reports, per session
+donc Skip UAE box when RAE box seen
+
+24 July 1991
+============
+donc Use pretty new icon Doctor.ico
+donc Show stack values as unsigned
+donc Return 1 to WM_INITDIALOG (bug #9248)
+
+31 July 1991
+============
+donc Include time on "Attempt to continue" line
+
+2 Aug 1991
+==========
+donc Only ask for clues once
+donc Show debug/retail in info
+donc Version 0.77
+donc Show parameter validation messages
+donc Stack trace show calling routine
+donc skipinfo 'par' to skip param validation tracing
+donc skipinfo 'err' to skip error tracing
+donc Copyright line in message box
+
+5 Aug 1991
+==========
+donc Version 0.78
+donc Only warn large file once
diff --git a/private/mvdm/wow16/sherlock/str.h b/private/mvdm/wow16/sherlock/str.h
new file mode 100644
index 000000000..7b5fb601a
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/str.h
@@ -0,0 +1,147 @@
+//
+// str.h for Dr. Watson
+//
+// Created by DaveHart 31-Aug-95 to allow localization of Dr. Watson
+//
+
+#define CCH_MAX_STRING_RESOURCE 512
+
+//
+// IDSTR manifests start at zero and are consecutive to allow
+// the ID to be an index into an array of string pointers at
+// runtime.
+//
+
+#define IDSTRNoFault 0
+#define IDSTRFaulty 1
+#define IDSTRGPText 2
+#define IDSTRErrMsg 3
+#define IDSTRVers 4
+#define IDSTRClassMsg 5
+#define IDSTRCoprocessor 6
+#define IDSTR8086 7
+#define IDSTR80186 8
+#define IDSTR80286 9
+#define IDSTR80386 10
+#define IDSTR80486 11
+#define IDSTREnhancedMode 12
+#define IDSTRProtectMode 13
+#define IDSTRStandardMode 14
+#define IDSTRWindowsNT 15
+#define IDSTRNullPtr 16
+#define IDSTRInvalid 17
+#define IDSTRNotPresent 18
+#define IDSTRCode 19
+#define IDSTRExR 20
+#define IDSTRExO 21
+#define IDSTRData 22
+#define IDSTRRW 23
+#define IDSTRRO 24
+#define IDSTRUnknown 25
+#define IDSTRDivideByZero 26
+#define IDSTRInvalidOpcode 27
+#define IDSTRGeneralProtection 28
+#define IDSTRInvalidSelector 29
+#define IDSTRNullSelector 30
+#define IDSTRSegmentNotPresent 31
+#define IDSTRExceedSegmentBounds 32
+#define IDSTRCodeSegment 33
+#define IDSTRExecuteOnlySegment 34
+#define IDSTRReadOnlySegment 35
+#define IDSTRSegNotPresentOrPastEnd 36
+#define IDSTRErrorLog 37
+#define IDSTRParameterErrorLog 38
+#define IDSTRFileNotFound 39
+#define IDSTRCodeSegmentNPOrInvalid 40
+#define IDSTRNoSymbolsFound 41
+#define IDSTRSystemInfoInfo 42
+#define IDSTRWindowsVersion 43
+#define IDSTRDebugBuild 44
+#define IDSTRRetailBuild 45
+#define IDSTRWindowsBuild 46
+#define IDSTRUsername 47
+#define IDSTROrganization 48
+#define IDSTRSystemFreeSpace 49
+#define IDSTRStackBaseTopLowestSize 50
+#define IDSTRSystemResourcesUserGDI 51
+#define IDSTRMemManInfo1 52
+#define IDSTRMemManInfo2 53
+#define IDSTRMemManInfo3 54
+#define IDSTRMemManInfo4 55
+#define IDSTRTasksExecuting 56
+#define IDSTRWinFlags 57
+#define IDSTRUnknownAddress 58
+#define IDSTRStackDumpStack 59
+#define IDSTRStackFrameInfo 60
+#define IDSTRFailureReport 61
+#define IDSTRLastParamErrorWas 62
+#define IDSTRHadAFaultAt 63
+#define IDSTRCPURegistersRegs 64
+#define IDSTRCPU32bitRegisters32bit 65
+#define IDSTRInstructionDisasm 66
+#define IDSTRSystemTasksTasks 67
+#define IDSTRTaskHandleFlagsInfo 68
+#define IDSTRFilename 69
+#define IDSTRSystemModulesModules 70
+#define IDSTRModuleHandleFlagsInfo 71
+#define IDSTRFile 72
+#define IDSTRContinuingExecution 73
+#define IDSTRDebugString 74
+#define IDSTRApplicationError 75
+#define IDSTRInvalidParameter 76
+#define IDSTRNA 77
+#define IDSTRHadAFaultAt2 78
+#define IDSTRParamIs 79
+#define IDSTRStop 80
+#define IDSTRLogFileGettingLarge 81
+#define IDSTRStart 82
+#define IDSTRWarningError 83
+#define IDSTRFatalError 84
+#define IDSTRParamErrorParam 85
+#define IDSTRParamErrorBadInt 86
+#define IDSTRParamErrorBadFlags 87
+#define IDSTRParamErrorBadDWord 88
+#define IDSTRParamErrorBadHandle 89
+#define IDSTRParamErrorBadPtr 90
+
+// These must be numerically in order Jan - Dec.
+
+#define IDSTRJan 91
+#define IDSTRFeb 92
+#define IDSTRMar 93
+#define IDSTRApr 94
+#define IDSTRMay 95
+#define IDSTRJun 96
+#define IDSTRJul 97
+#define IDSTRAug 98
+#define IDSTRSep 99
+#define IDSTROct 100
+#define IDSTRNov 101
+#define IDSTRDec 102
+
+// These must be numerically in order Sun - Sat
+
+#define IDSTRSun 103
+#define IDSTRMon 104
+#define IDSTRTue 105
+#define IDSTRWed 106
+#define IDSTRThu 107
+#define IDSTRFri 108
+#define IDSTRSat 109
+
+
+//
+// Since IDSTR's start at zero, STRING_COUNT is one more than the highest ID
+//
+
+#define STRING_COUNT 110
+
+//
+// Macro to fetch string pointer based on name without preceeding IDSTR
+//
+
+#define STR(name) (aszStrings[IDSTR##name])
+
+#ifndef DRWATSON_C
+extern LPSTR aszStrings[];
+#endif
diff --git a/private/mvdm/wow16/sherlock/watson.asm b/private/mvdm/wow16/sherlock/watson.asm
new file mode 100644
index 000000000..a330636cc
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/watson.asm
@@ -0,0 +1,325 @@
+; Watson.asm - Helper routines for Sherlock
+
+ memS = 1
+ ?PLM = 0
+ ?WIN = 0
+ ?QUIET = 1
+include cmacros.inc
+include toolhelp.inc
+ .286p
+ .model small
+
+ .data?
+;newStack db 4096 dup (?)
+externW newsp
+externW cpu32
+externW retflag
+;newsp = (newStack+4096)
+
+externW regs
+ val = 0
+irp reg, <ax,cx,dx,bx,sp,bp,si,di,ip,flag,es,cs,ss,ds,fs,gs,int>
+ r&reg = val
+ val = val+2
+endm
+
+
+externD regs32
+ val = 0
+irp reg, <ax, cx, dx, bx, sp, bp, si, di, ip, flags>
+ re&reg = val
+ val = val+4
+endm
+
+ .code
+externP Sherlock
+
+cProc SegLimit, <PUBLIC>,
+ parmW segVal
+cBegin
+ cmp [cpu32], 0
+ jnz SegLimit32
+ xor ax, ax
+ xor dx, dx
+ lsl ax, [segVal]
+ jmp short done
+SegLimit32:
+ .386p
+ push edx ; save EDX.hi
+ pop dx
+
+ push eax ; save EAX.hi
+ pop ax
+
+ xor edx, edx ; return 0 if failure
+ movzx eax, [segVal]
+ lsl edx, eax ; EDX = return result
+
+ push dx ; push ans.lo
+ pop eax ; EAX.lo = ans.lo, EAX.hi restored
+
+ push edx ; stack is ans.lo, ans.hi, EDX.hi
+ pop dx ; discard ans.lo (already in EAX.lo)
+ pop edx ; DX has ans.hi, EDX.hi restored
+ .286p
+done:
+cEnd
+
+cProc SegBase, <PUBLIC>
+ parmW segVal
+cBegin
+ mov ax, 6
+ mov bx, [segVal]
+ or bx, bx ; DPMI whines on a 0 selector
+ jz baseBad
+ int 31h ; call DPMI
+ jnc baseOK
+baseBad:
+ xor dx, dx
+ xor cx, cx
+baseOK:
+ mov ax, dx
+ mov dx, cx
+cEnd
+
+cProc SegRights, <PUBLIC>
+ parmW segVal
+cBegin
+ lar ax, [segVal]
+ jz rightOK
+ xor ax, ax
+rightOK:
+cEnd
+
+externNP CallMeToo
+
+cProc CallMe,<PUBLIC,FAR> ; I was a big Blondie fan
+; parmD foo ; BP+6, BP+8
+; parmW id ; BP+10
+cBegin nogen
+ push bp
+ mov bp, sp
+id equ word ptr [bp+10]
+seg_foo equ word ptr [bp+8]
+off_foo equ word ptr [bp+6]
+ xor ax, ax
+ cmp id, NFY_LOGERROR
+ jz cm_stay
+ cmp id, NFY_LOGPARAMERROR
+; jz cm_stay
+; cmp id, NFY_OUTSTR
+ jnz cm_go ; "if I go there will be trouble"
+cm_stay: ; "if I stay it will be double"
+ mov ax, DGROUP
+ mov bx, ss
+ cmp ax, bx
+ jz cm_go
+ push ds ; I like The Clash too
+ mov ds, ax
+ mov dx, SEG_foo
+ mov cx, OFF_foo
+ mov bx, id
+ mov [regs+rss], ss ; for stack trace, and to continue
+ mov [regs+rsp], sp
+ mov [regs+rbp], bp
+ mov [regs+rcs], cs
+ mov [regs+rip], offset cm_stay
+ mov ss, ax
+ mov sp, [newsp]
+ mov bp, 0
+ push dx
+ push cx
+ push bx
+ cCall CallMeToo
+ mov bp, [regs+rbp]
+ mov ss, [regs+rss]
+ mov sp, [regs+rsp]
+ pop ds
+cm_go:
+ pop bp
+ retf 6
+cEnd nogen
+
+; GPFault - called as part of gpfault chain by ToolHelp
+; Ret IP Far ret back to ToolHelp fault handler
+; Ret CS
+; AX Saved in case prolog trashes AX
+;6 IntNum Number of interrupt that occurred
+; Resv Magic value, don't trash
+;10 Fault IP IRET back to faulting instruction
+;12 Fault CS
+;14 Fault Flags
+
+fint = 6
+fip = 10
+fcs = 12
+fflag = 14
+
+GPFAULT proc far ; pascal
+public GPFAULT
+ push ds ; save ds
+ push ax
+ push bp
+ mov bp, sp
+ mov ax, [bp+12]
+ cmp ax, 0 ; only save regs if int Div0,
+ jz keeper
+ cmp ax, 6 ; invalid opcode
+ jz keeper
+ cmp ax, 13 ; GP fault
+ jz keeper
+nokeep: pop bp ; don't like this fault, chain on
+ pop ax
+ pop ds
+ ret
+
+keeper: push bx
+ mov bx, ss
+ mov ax, DGROUP ; and address our group
+ cmp ax, bx
+ pop bx
+ je nokeep ; don't go re-entrant
+ mov ds, ax
+ pop [regs+rbp]
+ pop [regs+rax] ;save AX
+ pop [regs+rds] ; and DS in regs[]
+
+irp reg, <cx,dx,bx, sp, si,di, es,ss>
+ mov [regs+r&reg], reg ; all but ip, flag, intNum,
+endm ; cs, fs, gs, int
+ mov bp, sp ; nothing local on stack
+irp reg, <cs, ip, flag, int>
+ mov bx, [bp+f&reg]
+ mov [regs+r&reg], bx
+endm
+
+; Save away 32 bit registers if required
+ cmp [cpu32], 0
+ jz NoSave32
+ .386p
+ mov ax, [regs+rax]
+irp reg, <eax, ecx, edx, esi, edi>
+ mov [regs32+r&reg], reg
+endm
+irp reg, <bx, sp, bp>
+ mov eax, e&reg
+ mov ax, [regs+r&reg]
+ mov [regs32+re&reg], eax
+endm
+ pushfd
+ pop [regs32+reflags]
+ mov [regs+rfs], fs
+ mov [regs+rgs], gs
+ .286p
+NoSave32:
+ mov ax, ds
+ mov ss, ax
+ mov sp, [newsp]
+ mov bp, 0
+
+ cmp ax, [regs+rss] ; can't debug ourselves
+ jz oh_no
+
+; Save high halves of registers if required
+ cmp [cpu32], 0
+ jz CallSherlock286
+ .386p
+ pushad
+ call Sherlock ; Display the info
+ mov retflag, ax
+ popad
+ mov eax, [regs32+reax]
+ .286p
+
+ jmp short DoneWithSherlock
+
+CallSherlock286:
+ pusha
+ call Sherlock ; Display the info
+ mov retflag, ax
+ popa
+
+DoneWithSherlock:
+ mov ax, retflag
+ or ax, ax ; 0 - fault, 1 = continue
+ jz oh_no
+ mov es, [regs+rss]
+ mov bx, [regs+rsp]
+ mov ax, [regs+rip]
+ mov es:[bx+10], ax
+oh_no: ; restore all regs, then test again
+irp reg, <ax,cx,dx,bx, ss,sp, bp,si,di, es,ds>
+ mov reg, [regs+r&reg]
+endm
+ jz oh_no_2
+ add sp, 10
+ iret
+oh_no_2:
+ ret
+GPFAULT endp
+
+ .386p
+cProc GetRegs32, <PUBLIC>
+cBegin
+cEnd
+
+irp reg, <sp, bp, si, di>
+ mov eax, [regs32+re&reg]
+ mov ax, reg
+ mov e&reg, eax
+endm
+
+irp reg, <ebx, edx, ecx, eax>
+ mov reg, [regs32+r&reg]
+endm
+cEnd
+ .286p
+
+cProc GetTimeDate, <PUBLIC>
+ parmW buf
+cBegin
+ mov ah, 2ah
+ int 21h
+ mov bx, [buf]
+ mov [bx], ax
+ mov [bx+2], cx
+ mov [bx+4], dx
+ mov ah, 2ch
+ int 21h
+ mov bx, [buf]
+ mov [bx+6], cx
+ mov [bx+8], dx
+cEnd
+
+cProc FindFile, <PUBLIC>
+ parmW buf
+ parmW _name
+ localW dtaSeg
+ localW dtaOff
+cBegin
+ mov ah, 2fh ;get DTA
+ int 21h
+ mov [dtaSeg], es
+ mov [dtaOff], bx
+
+ mov ah, 1ah
+ mov dx, buf
+ int 21h ; set DTA to caller's buffer
+
+ mov ah, 4eh ; find first matching file
+ mov cx, 0
+ mov dx, _name
+ int 21h
+ sbb ax, ax
+ push ax
+
+ push ds ; restore DTA
+ mov ds, [dtaSeg]
+ mov dx, [dtaOff]
+ mov ah, 1ah
+ int 21h
+
+ pop ds
+ pop ax ; return value, 0 == OK
+cEnd
+ end
diff --git a/private/mvdm/wow16/sherlock/watson.ico b/private/mvdm/wow16/sherlock/watson.ico
new file mode 100644
index 000000000..7d6e64da8
--- /dev/null
+++ b/private/mvdm/wow16/sherlock/watson.ico
Binary files differ
diff --git a/private/mvdm/wow16/system/envect.asm b/private/mvdm/wow16/system/envect.asm
new file mode 100644
index 000000000..f1e49de68
--- /dev/null
+++ b/private/mvdm/wow16/system/envect.asm
@@ -0,0 +1,257 @@
+.xlist
+include cmacros.inc
+;
+;~~vvr 091989
+;
+SYS=1
+include equate.inc
+;~~
+include vecsys.inc
+include int31.inc
+.list
+
+page
+;======= EnableVectra ========================================================
+;
+; If we have a Vectra A, A+, or A++ with EX-BIOS, save the current HPEntry
+; vector, HPHIL state and set HPentry=6Fh, Turn ON HPHIL.
+;
+; Entry:
+; DS: Code segment
+;
+;
+; Exit:
+; CurHPentry, CurHILState
+;
+; Regs:
+; AX,
+;
+;=============================================================================
+
+ assumes cs, code
+sBegin DATA
+
+fFirst dw 0 ; =0: First time in
+;
+;~~vvr 091989
+;
+fVectra db 0 ; bit0 =1: We have a Vectra with EX-BIOS
+CurHPEntry db 0 ; Current HPEntry vector (usually 6Fh)
+CurHILState db 0 ; bit6 =1: HIL is OFF
+ db ? ; Word aligned
+
+RealMode_Word_Struc Real_Mode_Call_Struc <>
+
+externA WinFlags
+externA __ROMBIOS
+WF_PMODE equ 01h
+sEnd
+
+sBegin CODE
+assumes cs, CODE
+externW MyCSDS
+
+cProc EnableVectra, <PUBLIC,NEAR>
+
+cBegin
+ push CX
+ push BX
+ push BP
+ push DS
+
+ mov ds, MyCSDS
+ assumes ds,DATA
+
+ test [fVectra], 10000000B ; Any previous Vectra check?
+ jne EnVNext ; Yes, proceed
+;
+; Check if the PC is a Vectra. If Yes, then call HPSystem to get the
+; current size of the HP state
+
+ or [fVectra], 80H ; Mark as gone through the identification
+ ; ..process
+ push ES ; Save it
+ mov AX, __ROMBIOS
+ mov ES, AX ; ES: Segment of ID code
+ cmp Word Ptr ES:[ID_OFFSET], 'PH'
+ pop ES ; Restore entry ES
+ jz EnVCont1
+ jmp EnVRet ; Not a Vectra, so no extra HP processing
+EnVCont1:
+;
+; Check if EX-BIOS is present
+;
+
+ mov AX, F16_INQUIRE
+ mov BX, AX
+ int INT_KBD
+ cmp BX, 'HP' ; EX-BIOS present?
+ je EnVCont
+ jmp EnVRet ; No, finish
+EnVCont:
+ or [fVectra], 1 ; Yes, flag we have a Vectra
+
+EnvNext:
+ test [fVectra], 1
+ jnz EnVContinue
+ jmp EnVRet ; No special processing if not a vectra
+EnVContinue:
+;
+; We need to save the EX-BIOS vector and the HIL state only once since it is
+; assumed that these parameters will not be changed while running under
+; Windows, especially by an old app.
+;
+ xor BH, BH
+ cmp [CurHPEntry], BH ; first time?
+ jnz EnVSet ; no, don't have to save it again
+;
+; Save current HP entry and set it to be 6Fh
+;
+ mov AX, F16_GET_INT_NUMBER
+ int INT_KBD
+ inc BH ; Flag as the first time
+ mov [CurHPEntry], HPENTRY ; Assume we have HPentry= 6Fh
+ cmp AH, RS_UNSUPPORTED
+ je EnVSet ; We have a Vectra A, A+ if unsupported
+ mov [CurHPEntry], AH ; Save it if valid
+;
+EnVSet:
+ mov BL, HPENTRY
+ mov AX, F16_SET_INT_NUMBER
+ int INT_KBD ; BH preserved
+;
+; Save current HPHIL state and set it ON
+;
+ mov cx, WinFlags
+ and cx, WF_PMODE
+ cmp cx, WF_PMODE ; prot-mode only
+ jne sys_real_mode
+
+sys_prot_mode:
+ or BH, BH ; BH= 0: Not the first time
+ jz EnVSetHIL_PM ; so don't save state
+ HPSysCall V_HPHIL, F_SYSTEM, SF_REPORT_STATE
+ mov [CurHILState], BH
+;
+; Bit 14 of BX (Status Word) = 1: HPHIL OFF
+; 0: ON
+;
+EnVSetHIL_PM:
+ HPSysCall V_HPHIL, F_IO_CONTROL, SF_HIL_ON
+ jmp EnVret
+
+sys_real_mode:
+ or BH, BH ; BH= 0: Not the first time
+ jz EnVSetHIL ; so don't save state
+ mov AH, F_SYSTEM
+ mov AL, SF_REPORT_STATE
+ mov BP, V_HPHIL
+ int HPENTRY ; int 6f to get the state
+;
+; Bit 14 of BX (Status Word) = 1: HPHIL OFF
+; 0: ON
+;
+ mov [CurHILState], BH
+;
+; Turn HIL ON
+;
+EnVSetHIL:
+ mov AH, F_IO_CONTROL
+ mov AL, SF_HIL_ON
+ mov BP, V_HPHIL
+ int HPENTRY
+;
+EnVret:
+ pop DS
+ pop BP
+ pop BX
+ pop CX
+;
+cEnd EnableVectra
+
+
+page
+;======= DisableVectra =======================================================
+;
+; Restore the Vectra environment according to CurHPEntry and CurHILState
+; Assume that HPENTRY is always 6Fh
+;
+; Entry:
+; DS: Code Segment
+;
+; Exit:
+;
+;
+; Regs:
+; AX,
+;
+;=============================================================================
+
+cProc DisableVectra, <PUBLIC,NEAR>
+
+cBegin
+ push BX
+ push BP
+ push DS
+
+ ; make it run in both
+ mov ds,MyCSDS ; real and prot modes
+ assumes ds,DATA
+
+ test [fVectra], 1 ; are we on a Vectra ?
+ jnz DisVCont
+ jmp DisVRet ; no
+DisVCont:
+
+; check if we are prot or real mode
+
+ mov bx, WinFlags ; get mode flag
+ and bx, WF_PMODE
+ cmp bx, WF_PMODE ; is it prot_mode ?
+ jne sys_dis_real_mode ; we are in real mode
+
+sys_dis_prot_mode:
+
+ test [CurHILState], B_HIL_STATE
+ je DisVHIL_PM
+ HPSysCall V_HPHIL, F_IO_CONTROL, SF_HIL_OFF
+ jmp DisRestHIL
+DisVHIL_PM:
+ HPSysCall V_HPHIL, F_IO_CONTROL, SF_HIL_ON
+ jmp DisRestHIL
+
+sys_dis_real_mode:
+;
+;
+; Restore the HIL state according to CurHILState
+;
+ mov AH, F_IO_CONTROL
+ mov BP, V_HPHIL
+ mov AL, SF_HIL_ON ; Assume HIL is ON
+ test [CurHILState], B_HIL_STATE
+ je DisVHIL ; 0= correct assumption
+ mov AL, SF_HIL_OFF
+
+DisVHIL:
+ push ds
+ int HPENTRY
+ pop ds
+;
+; Restore the Saved HPEntry
+;
+DisRestHIL:
+
+ mov AX, F16_SET_INT_NUMBER
+ mov BL, [CurHPEntry]
+ int INT_KBD
+;
+DisVRet:
+ pop DS
+ pop BP
+ pop BX
+
+;
+cEnd DisableVectra
+
+Send code
+ end
diff --git a/private/mvdm/wow16/system/equate.inc b/private/mvdm/wow16/system/equate.inc
new file mode 100644
index 000000000..0be97e0a4
--- /dev/null
+++ b/private/mvdm/wow16/system/equate.inc
@@ -0,0 +1,608 @@
+page ,132
+
+;**************************************************************************
+; This file contains equates, data structures and definitions needed to
+; access both the Standard BIOS (STD-BIOS) and the Extended BIOS (EX-BIOS)
+; of Vectra using MASM 3.0. Depending on what part of the BIOS you are
+; accessing you might not need all the equates. The equates are organized
+; as follows:
+;
+; o Usefull macros.
+; o 80286 Support Macros and Equates.
+; o EX-BIOS Equates:
+; 1) Generic Structures and equates used by all drivers.
+; 2) Equates for Vector Addressed.
+; 3) Function and SubFunction Equates common to all drivers.
+; 4) Function and Subfunction Equates individual to drivers. These
+; are order by vector number.
+; o Industry Standard (STD-BIOS) Interrupt numbers and function equates.
+; o Industry Standard (STD-BIOS) Data Area
+;
+; The major reason for organizing the equate file in this form is that
+; the programmer can extract only those equates that he needs to create
+; a tailored equate file.
+;**************************************************************************
+
+;**************************************************************************
+; Useful macros.
+;**************************************************************************
+; none at this time
+
+
+;**************************************************************************
+; 80286 Support macros and equates.
+;**************************************************************************
+;**************************************************************************
+; The following macro is used to compensate for a bug in the 80286
+; hardware interrupt system. It seems that during a normal
+; POPF instruction cycle interrupts are always enabled regardless
+; of the state of the interrupt enable flag prior to the pop or after
+; the pop.
+;**************************************************************************
+POPPF macro
+ jmp $+3
+ iret
+ push cs
+ call $-2
+ endm
+
+;**************************************************************************
+; EX-BIOS support macros and equates.
+;**************************************************************************
+
+; Equates for EX-BIOS interrupt number and vector address.
+HPENTRY equ 6FH
+F_HPENTRY equ HPENTRY
+
+BIOS_SEG EQU 0F000H ; Vectra BIOS ROM Segment
+ID_OFFSET EQU 0F8H ; Vectra ROM ID Offset
+;
+;**************************************************************************
+; SYSCALL [vector_address]
+;**************************************************************************
+syscall macro vector
+ ifnb <vector>
+ mov bp,vector
+ endif
+ int HPENTRY
+ endm
+
+ifndef SYS
+;
+;**************************************************************************
+; HP_VECTOR_TABLE Entry
+;**************************************************************************
+HP_TABLE_ENTRY struc ;<1,2,3>
+HP_ENTRY_IP dw 0
+HP_ENTRY_CS dw 0
+HP_ENTRY_DS dw 0
+HP_TABLE_ENTRY ends
+;**********************************************************************
+; Structure of Data Header for HP's vectors.
+;**********************************************************************
+HP_SHEADER STRUC ;<1,2,3,4,5,6,7,8,9,0>
+DH_ATR dw 0 ; Attribute
+DH_NAME_INDEX dw 0 ; Name index of driver.
+DH_V_DEFAULT dw 0 ; Driver vector position in HPtable
+DH_P_CLASS dw 0 ; Parent class
+DH_C_CLASS dw 0 ; Child class
+DH_V_PARENT dw 0 ; Vector used when the driver cannot handle
+ ; an F_ISR function call
+DH_V_CHILD dw 0 ; Vector used when the driver cannot handle
+ ; a regular function call
+DH_MAJOR db 0 ; Driver's major address if any.
+DH_MINOR db 0 ; Driver's minor address if any.
+HP_SHEADER ENDS
+
+;**********************************************************************
+; DH_ATR bit record
+;**********************************************************************
+ATR_HP equ 1000000000000000B ; 1- The Rest of header is valid
+ATR_DEVCFG equ 0100000000000000B ; 1- Present in DEVCONFG
+ATR_ISR equ 0010000000000000B ; 1- Replace My ISR (Child)
+ATR_ENTRY equ 0001000000000000B ; 1- Replace My ENTRY (Parent)
+ATR_RSVD equ 0000000000000000B ; 0 - Available on allocation from HP
+ATR_FREE equ 0000001000000000B ; 1 - Available Vector
+ATR_SRVC equ 0000010000000000B ; 2 - Service Vector
+ATR_LOG equ 0000011000000000B ; 3 - Logical Device Start DEVCONFG CHA
+ATR_IND equ 0000100000000000B ; 4 - Filter, show driver (options)
+ATR_BOT equ 0000101000000000B ; 5 - End of Chain
+ATR_ESC equ 0000110000000000B ; 6 - Filter, Pass thru , No options
+ATR_TYPE7 equ 0000111000000000B ; 7 - Available
+ATR_TYPE_MASK equ 0000111000000000B
+ATR_INP equ 0000000100000000B ; 1 - Chain ISR ( to Parents )
+ ; 0 - Chain Entry ( Child)
+ATR_SUBADD equ 0000000000000000B
+ATR_MAJOR equ 0000000000100000B
+ATR_MINOR equ 0000000001000000B
+ATR_MID equ 0000000001100000B
+ATR_PSHARE equ 0000000000010000B
+ATR_CSHARE equ 0000000000001000B
+ATR_ROM equ 0000000000000100B
+ATR_YIELD equ 0000000000000010B ;
+ATR_0 equ 0000000000000001B
+
+;**********************************************************************
+; DH_Class
+;**********************************************************************
+CL_KBDFC equ 1000000000000000B ; 1 - HP Softkey Transaltor
+CL_KBD equ 0100000000000000B ; 1 - Keyboard
+CL_CCP equ 0010000000000000B ; 1 - Cursor Control pad
+CL_CON equ 0001000000000000B ; 1 - Console Device
+CL_BYTE equ 0000100000000000B ; 1 - PRN device
+CL_COMM equ 0000010000000000B ; 1 - COMM device
+CL_INTERFACE equ 0000001000000000B ; 1 - interface, HPHIL, HPIB
+CL_FILT equ 0000000100000000B ; 1 - charachter filter
+CL_BLK equ 0000000010000000B ; 1 - block device
+CL_BOOT equ 0000000001000000B ; 1 - boot block device
+CL_LGID equ 0000000000100000B ; 1 - logical physical gid
+ ; e.g. ccp to gid translator
+CL_PGID equ 0000000000010000B ; 1 - physical gid
+CL_GID equ 0000000000001000B ; 1 - any graphics input device
+CL_PTS equ 0000000000000100B ; 1 - physical touch screen
+CL_ASCII equ 0000000000000010B ; 1 - ascii input device
+CL_EXTEND equ 0000000000000001B ; 0 - set of classes above
+ ; 1 - alternate class set
+CL_ALL equ 1111111111111111B ; Member of all classes
+CL_NULL equ 0000000000000000B ; Member No Classes
+
+;***************************************************************************
+; Vector Addresses
+;***************************************************************************
+V_SCOPY equ 0000H ; Copyright Notice
+V_DOLITTLE equ 0006H ; Nop Routine
+V_PNULL equ 000CH ; No Device
+V_SYSTEM equ 0012H ; System Intrinsics
+V_SINPUT equ 002AH ; Input Inquire routines
+V_SQWERTY equ 0036H ; Qwerty KBD Translator
+V_PSOFTKEY equ 003CH ; HP f1-f8 Translator
+V_PFUNCTION equ 0042H ; IBM F1-F10 Translator
+V_PNUM_PAD equ 0048H ; Numeric Pad Translator
+V_SPCCP equ 004EH ; CCP Translator Driver
+V_PVIDEO equ 0054H ; Video Intrinsics
+V_STRACK equ 005AH ; Common cursor control funcs.
+V_EVENT_TOUCH equ 0060H ; Touch Event Intercept
+V_EVENT_TABLET equ 0066H ; Tablet Event Intercept
+V_EVENT_POINTER equ 006CH ; Pointer Event Intercept
+V_LCCP_CURSOR equ 008AH ; CCP to Cursor Always Filter (Default)
+V_RAW equ 0090H ; CCP+Softkey RAW Mode Filter
+V_LCCP_NUMPAD equ 0096H ; CCP to Numeric Pad Filter
+V_OFF equ 009CH ; CCP+Softkey Off Filter
+V_LCCP_GID equ 00A2H ; CCP to GID Filter ( Not Implemented)
+V_LFUNCTION equ 00A8H ; Softkey (f1-f8) to Function
+ ; key (F1-F8) Filter (Default)
+V_L8041 equ 00AEH ; 8041 Interface
+V_PGID_CCP equ 00B4H ; Graphic to CCP Filter
+V_LTABLET equ 00BAH ; Tablet driver
+V_LPOINTER equ 00C0H ; Pointer driver
+V_LTOUCH equ 00C6H ; Touch driver
+V_LHPMOUSE equ 00CCH ; Microsoft/Mouse System's
+ ; Compatible Driver
+V_LNULL equ 0108H ; No Driver
+
+endif ; SYS
+
+V_HPHIL equ 0114H ; HPHIL Driver
+;
+V_WINDOWS equ 168H ; HP Windows protocol driver
+V_SCANDOOR equ 016EH ; Scan Door driver
+;
+;~~tqn 060887
+;
+;*********************************************************************
+; Extended Keyboard functions (int 16h)
+;*********************************************************************
+
+INT_KBD equ 16H ; Int 16h vetor
+F16_INQUIRE equ 6F00H ; EX-BIOS presence
+F16_GET_INT_NUMBER equ 6F0DH ; Get HPentry vector
+F16_SET_INT_NUMBER equ 6F0EH ; Set HPentry vector
+;
+;~~
+;*********************************************************************
+; Common Function Codes for HP Routines.
+;*********************************************************************
+F_ISR equ 00H*2 ; Interrupt service call
+F_SYSTEM equ 01H*2 ; System func. call,
+ ; Subfunction required
+F_IO_CONTROL equ 02H*2 ; Device/Driver Dependent
+ ; Functions
+F_ITF_TO_ENVOY equ F_IO_CONTROL ; Translation function for
+ ; SITF_ENVOY service.
+F_PUT_BYTE equ 03H*2 ; Write one byte of data:
+ ; Byte is in AL
+F_GET_BYTE equ 04H*2 ; Read a byte of data:
+ ; Byte returned in AL
+F_PUT_BUFFER equ 05H*2 ; Write a buffer of data,
+ ; ES,DI pointer, CX count
+F_GET_BUFFER equ 06H*2 ; Read a buffer if data,
+ ; ES,DI pointer, CX count
+F_PUT_WORD equ 07H*2 ; Write word of data, BX data
+F_GET_WORD equ 08H*2 ; Read word of data, BX data
+F_GETTRM_BUFFER equ 009H*2 ; Reads buffer of data,
+ ; ES,DI pointer, CX count
+ ; BH upper bound, BL lower bound
+F_PUT_BLOCK equ F_PUT_BUFFER ;used for disk applications
+F_GET_BLOCK equ F_GET_BUFFER
+
+;*********************************************************************
+; Common Subfunction codes of the F_SYSTEM Function.
+;*********************************************************************
+SF_INIT equ 00H*2 ;Initialize command
+SF_START equ 01H*2 ;Secondary Init--initialize dependent
+ ; upon other drivers/data structures
+SF_REPORT_STATE equ 02H*2 ;Reports state of driver
+SF_VERSION_DESC equ 03H*2 ;Report version and option describe
+ ; record
+SF_DEF_ATTR equ 04H*2 ;Reports default Configuration
+ ; (Baud Rate)
+SF_GET_ATTR equ 05H*2 ;Reports Current Configuration
+ ; ES,DI pointer
+SF_SET_ATTR equ 06H*2 ;Sets Next Configuration ES,DI, CX
+SF_OPEN equ 07H*2 ;Reserve Driver for exclusive access
+SF_CLOSE equ 08H*2 ;Release " from " "
+SF_TIMEOUT equ 09H*2 ;Notify Driver Timeout Occurred
+SF_INTERVAL equ 0AH*2 ;Notify Driver Interval Occurred
+SF_TEST equ 0BH*2 ;Test Function
+
+;*********************************************************************
+; Common Subfunction Codes for the F_IO_CONTROL function.
+;*********************************************************************
+SF_LOCK equ 00H*2 ; Lock Device for exclusive access
+SF_UNLOCK equ 01H*2 ; Unlock Device for exclusivce access
+;
+;~~tqn 060887
+;
+SF_HIL_ON equ 26H ; Turn ON HIL (A++)
+SF_HIL_OFF equ 28H ; Turn OFF HIL (A++)
+B_HIL_STATE equ 01000000B ; HIL OFF state from SF_REPORT_STATE
+;
+;~~
+;*********************************************************************
+; HP Routines Return Status: Sucessful codes are positive and failure
+; are negative.
+;*********************************************************************
+RS_BREAK equ 00CH ; Break -- IFC
+RS_DATA_NREADY equ 00AH ; RS232 Data Not Ready=>Retry Operation
+RS_OVERRUN equ 008H ; RS232 Port Data Overrun =>Retry Operation
+RS_DONE equ 006H ; indicates all done return child
+RS_NOT_SERVICED equ 004H ; indicates a chained ISR--not handled
+RS_UNSUPPORTED equ 002H ; indicates function is NOPed/not valid
+ ; for this driver
+RS_SUCCESSFUL equ F_ISR ; indicates executed just fine
+RS_SERVICED equ rs_SUCCESSFUL ; indicates chained ISR done
+RS_PASSTHRU equ rs_SERVICED ; indicates launch data to parent
+
+
+ifndef SYS
+;
+;************************************************************************
+RS_FAIL equ 0FEH ; To be used with hardware failure
+RS_TIMEOUT equ 0FCH ; to indicate remote device timeout
+RS_BAD_PARAMETER equ 0FAH ; to indicate a bad parameter
+RS_BUSY equ 0F8H ; to indicate driver/device is busy
+RS_NO_VECTOR equ 0F6H ; out of hp_VT vectors
+RS_OFFLINE equ 0F4H ; device is offline
+RS_OUT_OF_PAPER equ 0F2H ; out of paper on printer device
+RS_PARITY equ 0F0H ; parity error in transmission
+RS_FRAME equ 0EEH ; framing error
+
+;******************************************************************************
+; Function Number Equates for the EX-BIOS routines and its Data Structures.
+;******************************************************************************
+
+;*********************************************************************
+; V_SYSTEM (0012H) function codes.
+;*********************************************************************
+F_INS_BASEHPVT equ 0004H
+F_INS_XCHGFIX equ 0006H
+F_INS_XCHGRSVD equ 0008H
+F_INS_XCHGFREE equ 000AH
+F_INS_FIXOWNDS equ 000CH
+F_INS_FIXGETDS equ 000EH
+F_INS_FIXGLBDS equ 0010H
+F_INS_FREEOWNDS equ 0012H
+F_INS_FREEGETDS equ 0014H
+F_INS_FREEGLBDS equ 0016H
+F_INS_FIND equ 0018H
+F_INS_FINDALL equ 001AH
+F_INS_NXTLOGBLK equ 001CH
+F_RAM_GET equ 001EH
+F_RAM_RET equ 0020H
+F_CMOS_GET equ 0022H
+F_CMOS_RET equ 0024H
+F_CMOS_HPDFLTS equ 0026H
+F_CMOS_IBMDFLTS equ 0028H
+F_YIELD equ 002AH
+F_INS_ADR equ 002CH
+F_RESERVE_STRING3 equ 002EH
+F_SND_CLICK_ENABLE equ 0030H
+F_SND_CLICK_DISABLE equ 0032H
+F_SND_CLICK equ 0034H
+F_SND_BEEP_ENABLE equ 0036H
+F_SND_BEEP_DISABLE equ 0038H
+F_SND_BEEP equ 003AH
+F_SND_SET_BEEP equ 003CH
+F_SND_TONE equ 003EH
+F_STR_GET_FREE_INDEX equ 0040H
+F_STR_DEL_BUCKET equ 0042H
+F_STR_PUT_BUCKET equ 0044H
+F_STR_GET_STRING equ 0046H
+F_STR_GET_INDEX equ 0048H
+
+;**********************************************************************
+; String Bucket Header. This structure is usefull if using the
+; following V_SYSTEM functions: F_STR_DEL_BUCKET and F_STR_PUT_BUCKET.
+;**********************************************************************
+STR_HEADER STRUC
+STR_NXT_HDR dd (?)
+STR_UPPER_BOUND dw (?)
+STR_LOWER_BOUND dw (?)
+STR_LIST_PTR dd (?)
+STR_SEGMENT dw (?)
+STR_HEADER ENDS
+
+;**********************************************************************
+; V_SYSTEM Global Data Segment
+;**********************************************************************
+HP_GLB_HEADER STRUC
+T_HP_HEADER dw (?)
+T_USED_AND_RESERVED dw 6 dup (?)
+T_HP_LAST_DS dw (?)
+T_HP_MAX_DS dw (?)
+T_HP_NXT_VCTR dw (?)
+T_SND_FLAG db (?) ;
+T_SND_CLICK_COUNT db (?) ;
+T_SND_CLICK_DURA db (?) ;
+T_SND_CLICK_VOLUME db (?) ;
+T_SND_BEEP_CYCLE dw (?) ;
+T_SND_BEEP_DURA dw (?) ;
+T_SND_BEEP_COUNT db (?) ;
+ db (?) ; 1 reserved byte for volume
+T_STR_NEXT_INDEX dw (?)
+T_STR_ROOT dd (?)
+T_STR_VCT_HDR db size STR_HEADER dup (?) ; Area vector's name and
+T_STR_MSG_HDR db size STR_HEADER dup (?) ; ROM message strings
+T_8259_FLAGS db (?)
+ db 31 dup (?) ; reserve 2 paragraph
+HP_GLB_HEADER ENDS
+
+;*********************************************************************
+; V_SINPUT (2AH) Function and subfunction codes.
+;*********************************************************************
+; F_ISR, F_SYSTEM and F_IO_CONTROL are functions common to all drivers.
+F_INQUIRE equ 0006H
+F_INQUIRE_ALL equ 0008H ; Reports ID's of devices
+F_INQUIRE_FIRST equ 000AH ; Reports (V_HPHIL1) offset
+F_REPORT_ENTRY equ 000CH ; Reports entrypoint of (V_PGID)
+
+;
+; Extra subfunctions under F_IO_CONTROL.
+;
+SF_DEF_LINKS equ 0000H ; Sets default cofiguration
+SF_GET_LINKS equ 0002H ; Reports current configuration
+SF_SET_LINKS equ 0004H ; Sets Next Configuation
+;
+SF_MOUSE_DSIZE equ 0006H ; Return sizes of HPMouse and HPTrack
+
+;**********************************************************************
+; V_LGID Fucntion Codes. This is a common driver for: V_LTABLET,
+; V_LPOINTER and V_LTOUCH.
+;**********************************************************************
+F_SAMPLE equ 06
+; F_IO_CONTROL:
+SF_TRACK_ON equ 4
+SF_TRACK_OFF equ 6
+SF_CREATE_EVENT equ 8
+SF_EVENT_ON equ 0Ah
+SF_EVENT_OFF equ 0Ch
+SF_CLIPPING_ON equ 0Eh
+SF_CLIPPING_OFF equ 10h
+;**********************************************************************
+; V_LGID LD_DEVICE_STATE
+;**********************************************************************
+EVENT_ENABLED equ 10h
+TRACK_ENABLED equ 08h
+CLIP_ENABLED equ 04h
+BUTTON_ERROR equ 02H
+ISR_IN_PROGRESS equ 01H
+
+;*********************************************************************
+; V_PGID Data Structures
+;*********************************************************************
+DESCRIBE STRUC
+ db size HP_SHEADER dup (?) ; this data is always offset by
+D_SOURCE db ? ; 7-4 (high nibble) contains the GID type
+ ; 3-0 (low nibble) is the address of the device
+D_HPHIL_ID db ? ; device id byte returned by an HPHIL device
+D_DESC_MASK db ? ; describe header from HPHIL device
+D_IO_MASK db ? ; I/O descriptor byte from device
+D_XDESC_MASK db ? ; extended describe byte from device
+D_MAX_AXIS db ? ; maximum number of axis reported
+D_CLASS db ? ; device class
+ ; 7-4 (high nibble) contains current class
+ ; 3-0 (low nibble) contain the default class
+D_PROMPTS db ? ; number of buttons/prompts
+ ; 7-4 (high nibble) is the number of prompts
+ ; 3-0 (low nibble) is the number of buttons
+D_RESERVED db ? ; reserved for future
+D_BURST_LEN db ? ; maximum burst length output to a device
+ ; if devices supports more than 255 bytes then
+ ; 255 bytes is the default maximum
+D_WR_REG db ? ; number of write registers supported by a device
+D_RD_REG db ? ; number of read registers supported by a device
+D_TRANSITION db ? ; transitions reported per button
+D_STATE db ? ; current state of buttons
+D_RESOLUTION dw ? ; counts / cm (m) returned by HPHIL device
+D_SIZE_X dw ? ; Maximum count of in units of resolution
+D_SIZE_Y dw ? ;
+D_ABS_X dw ? ; data reported from device
+D_ABS_Y dw ? ; that reports absolute data
+D_REL_X dw ? ; data reported from device
+D_REL_Y dw ? ; that is relitive
+D_ACCUM_X dw ? ; these are used to accumulate scaling
+D_ACCUM_Y dw ? ; remainder
+DESCRIBE ENDS
+
+DESCRIBE_SIZE equ size DESCRIBE
+D_CCP_STATE equ D_STATE + 1
+D_SIZE equ D_SIZE_X
+D_SAMPLE_ABSOLUTE equ D_ABS_X
+D_SAMPLE_RELATIVE equ D_REL_X
+D_REMAINDER_ACCUM equ D_ACCUM_X
+D_BUFFER equ D_SIZE_X ; offset where buffer begins
+D_CLASS_CURRENT equ 0F0H
+D_CLASS_DEFAULT equ 00FH
+; The field LD_SOURCE uses the following to access the defined nibbles
+D_ADDR_MASK equ 00FH
+D_TYPE_MASK equ 0F0H
+;*********************************************************************
+; V_LGID Data Structures
+;*********************************************************************
+LDESCRIBE STRUC
+ db size HP_SHEADER dup (?) ; this data is always offset by
+LD_SOURCE db ? ; 7-4 (high nibble) contains the GID type
+ ; 3-0 reserved
+LD_HPHIL_ID db ? ; device id byte returned by an HPHIL device
+LD_DEVICE_STATE dw ? ; status bits for logical device
+LD_INDEX db ? ; vector index of invoking driver
+LD_MAX_AXIS db ? ; maximum number of axis reported
+LD_CLASS db ? ; device class
+ ; 7-4 (high nibble) contains current class
+ ; 3-0 (low nibble) contain the default class
+LD_PROMPTS db ? ; number of buttons/prompts
+ ; 7-4 (high nibble) is the number of prompts
+ ; 3-0 (low nibble) is the number of buttons
+LD_RESERVED db ? ; reserved for future
+LD_RES2 db ?
+LD_RES3 db ?
+LD_RES4 db ?
+LD_TRANSITION db ? ; transitions reported per button
+LD_STATE db ? ; current state of buttons
+LD_RESOLUTION dw ? ; counts / cm (m) returned by HPHIL device
+LD_SIZE_X dw ? ; Maximum count of in units of resolution
+LD_SIZE_Y dw ? ;
+LD_ABS_X dw ? ; data reported from device
+LD_ABS_Y dw ? ; that reports absolute data
+LD_REL_X dw ? ; data reported from device
+LD_REL_Y dw ? ; that is relitive
+LD_ACCUM_X dw ? ; these are used to accumulate scaling
+LD_ACCUM_Y dw ? ; remainders
+LDESCRIBE ENDS
+LDESCRIBE_SIZE equ size LDESCRIBE
+
+LD_SIZE equ LD_SIZE_X
+LD_SAMPLE_ABSOLUTE equ LD_ABS_X
+LD_SAMPLE_RELATIVE equ LD_REL_X
+LD_REMAINDER_ACCUM equ LD_ACCUM_X
+LD_BUFFER equ LD_RESOLUTION ; offset where buffer begins
+; the following mask are used in the field LD_CLASS
+LD_CLASS_CURRENT equ 0F0H
+LD_CLASS_DEFAULT equ 00FH
+
+;************************************************************************
+; V_LHPMOUSE (00CCH) Function and subfunction codes.
+;************************************************************************
+; F_ISR, F_SYSTEM and F_IO_CONTROL are functions common to all drivers.
+; Subfunction under F_IO_CONTROL particular to this driver.
+SF_MOUSE_COM equ 0000H ; This function is used during the
+ ; reinit call from DOS. It is used
+ ; to set up INT 33H. This is done
+ ; because DOS takes INT 33H when it
+ ; is initialized.
+SF_MOUSE_OVERRIDE equ 0002H ; This function is used to force the
+ ; V_LHPMOUSE driver to install INT 33
+ ; even when the mouse is not present.
+ ; This allows a programmer to map
+ ; devices to the V_LHPMOUSE driver if
+ ; a mouse is not present.
+
+;************************************************************************
+; V_STRACK (05AH) Function and subfunction codes.
+;************************************************************************
+F_TRACK_INIT equ 0004H ; used to perform a soft initialization
+ ; of the tracking driver.
+F_TRACK_ON equ 0006H ; enables tracking
+F_TRACK_OFF equ 0008H ; disables tracking
+F_DEF_MASKS equ 000AH ; define masks for sprite
+F_SET_LIMITS_X equ 000CH ; define X limit of screen coordinates
+F_SET_LIMITS_Y equ 000EH ; define Y limits
+F_PUT_SPRITE equ 0010H ; Used to put the sprite on the screen
+F_REMOVE_SPRITE equ 0012H ; removes the sprite from the screen
+
+;************************************************************************
+; V_HPHIL (0114H) Function and subfunction codes.
+;************************************************************************
+; F_ISR, F_SYSTEM and F_IO_CONTROL are functions common to all drivers.
+; Subfunction under F_IO_CONTROL particular to this driver.
+;
+SF_CRV_CRV_MAJ_MIN equ 0004 ; This is used to set a default
+ ; major and minor addresses
+SF_CRV_RECONFIGURE equ 0006 ; Funtion id used to force the HPHIL
+ ; link to reconfigure the devices
+SF_CRV_WR_PROMPTS equ 0008 ; Used to write a prompt to a device
+SF_CRV_WR_ACK equ 000A ; Used to write an acknowledge to a
+ ; device
+SF_CRV_REPEAT equ 000C ; Function is used to set a 30 Hz or
+ ; 60 Hz repeat for keyboards
+SF_CRV_DISABLE_REPEAT equ 000E ; Used to cancel the repeat rates in
+ ; keyboards
+SF_CRV_SELF_TEST equ 0010 ; Used to issue a selftest command
+ ; to a physical device
+SF_CRV_REPORT_STATUS equ 0012 ; Used to get the status information
+ ; that an HPHIL device might wish to
+ ; report. For specific information
+ ; on what is reported, see the specs
+ ; for the device.
+SF_CRV_REPORT_NAME equ 0014 ; This function is used to return the
+ ; ascii name that a device has.
+SF_ENVOY_REPEAT equ 0016 ; Used to set the keyboard repeat
+ ; and delay rates
+SF_ENVOY_LED equ 0018 ; Used to set the keyboard LEDs
+
+;************************************************************************
+; V_SCANDOOR (016EH) Function and subfunction codes.
+;************************************************************************
+; F_ISR, F_SYSTEM and F_IO_CONTROL are functions common to all drivers.
+; Subfunction under F_STATE_IOCTL particular to this driver.
+;
+F_STATE_IOCTL equ 0008H ; Get and set the state
+
+SF_GET_STATE equ 0000H ;
+SF_SET_STATE equ 0002H ;
+
+;**********************************************************************
+; V_HPHIL Data Structure - do not tread lightly in this data structure
+;**********************************************************************
+HPHIL_DATA struc
+ db size HP_SHEADER DUP (?) ; dirver header
+CRV_STATUS dw ?
+CRV_ENVOY_STATUS db ? ; status bits used to support
+ ; the envoy keyboard
+CRV_CURRENT_STATE db ? ; current configuration address
+CRV_ADDRESS db ? ; configuration address
+CRV_POLL_ADDRESS db ? ; address of device whose poll
+CRV_POLL_HEADER db ? ; poll header of data being proc
+CRV_MAJOR db ? ; default major address
+CRV_MINOR db ? ; default minor address
+CRV_EXPECTED_CMD db ? ; command expected to return
+CRV_KBD_ADDRESS db ? ; address of the keyboard
+CRV_MAX_DEVICES db ? ; status byte of itf keycode tra
+CRV_KC_STATE db ? ; state of itf kc translation
+CRV_POLL_RECORD db 32 DUP (?) ; poll record buffer
+RQ_ENV_REPEAT db ? ; envoy special command for repe
+RQ_ENV_DELAY db ? ; envoy special command for dela
+RQ_ENV_LED db ? ; envoy special command for led'
+RQ_RequEST db ?
+RQ_REGISTER db ?
+RQ_ADDRESS db ?
+RQ_DATA db ?
+RQ_MAX_BURST dw ?
+RQ_COUNT dw ?
+RQ_OFFSET dw ?
+RQ_SEGMENT dw ?
+RQ_SPECIAL db ?
+RQ_TIMEOUT db ?
+HPHIL_DATA ends
+;
+endif ; SYS
diff --git a/private/mvdm/wow16/system/hpsystem b/private/mvdm/wow16/system/hpsystem
new file mode 100644
index 000000000..d779d18eb
--- /dev/null
+++ b/private/mvdm/wow16/system/hpsystem
@@ -0,0 +1,24 @@
+#
+# Standard command line definitions
+#
+as=masm -R
+
+#
+# Standard inference rules
+#
+.asm.obj:
+ $(as) $*.asm;
+
+target: hpsystem.drv
+
+hpsystem.obj: system.asm system.inc
+ masm -R -DHPSYSTEM system,hpsystem;
+
+timer.obj: timer.asm system.inc
+
+envect.obj: envect.asm vecsys.inc
+
+hpsystem.drv: hpsystem.def hpsystem.lnk hpsystem.obj timer.obj envect.obj
+ link @hpsystem.lnk
+ rc hpsystem.drv
+ mapsym hpsystem
diff --git a/private/mvdm/wow16/system/hpsystem.def b/private/mvdm/wow16/system/hpsystem.def
new file mode 100644
index 000000000..94f447efa
--- /dev/null
+++ b/private/mvdm/wow16/system/hpsystem.def
@@ -0,0 +1,28 @@
+LIBRARY SYSTEM
+
+DESCRIPTION 'Microsoft Windows System configuration module for HP Vectra'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD FIXED
+DATA NONE
+
+IMPORTS
+
+ ALLOCCSALIAS = KERNEL.170
+ __ROMBIOS = KERNEL.173
+ WinFlags = KERNEL.178
+
+EXPORTS
+ InquireSystem @1
+ CreateSystemTimer @2
+ KillSystemTimer @3
+ EnableSystemTimers @4
+ DisableSystemTimers @5
+ GetSystemMsecCount @6
+ Get80x87SaveSize @7
+ Save80x87State @8
+ Restore80x87State @9
+
+ A20_Proc @20
+ WEP
diff --git a/private/mvdm/wow16/system/hpsystem.lnk b/private/mvdm/wow16/system/hpsystem.lnk
new file mode 100644
index 000000000..58d67b1e5
--- /dev/null
+++ b/private/mvdm/wow16/system/hpsystem.lnk
@@ -0,0 +1,5 @@
+hpsystem timer envect
+hpsystem.drv
+hpsystem.map/map /AL:16
+kernel /NOD
+hpsystem.def
diff --git a/private/mvdm/wow16/system/makefile b/private/mvdm/wow16/system/makefile
new file mode 100644
index 000000000..d0f63a51e
--- /dev/null
+++ b/private/mvdm/wow16/system/makefile
@@ -0,0 +1,116 @@
+# SYSTEM makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -R -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+W16LIBS = ..\lib\sdllcew.lib
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+
+all: system.drv system.sym
+ -binplace system.drv system.map system.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.drv del *.drv
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+
+system.lrf: makefile
+ echo system.obj timer.obj >system.lrf
+ echo system.exe/align:16>>system.lrf
+ echo system $(LINK)>>system.lrf
+ echo ..\lib\libw.lib /nod>>system.lrf
+ echo system;>>system.lrf
+
+system.obj: system.asm
+ masm $(AOBJ) system;
+
+timer.obj: timer.asm ..\..\inc\wow.inc
+ masm $(AOBJ) timer;
+
+system.res: system.rc ..\inc\common.ver
+
+system.drv: system.obj timer.obj system.lrf system.res
+ link16 @system.lrf;
+ rc16 -t system.res system.exe
+ if exist *.drv del *.drv
+ ren system.exe system.drv
+
+system.sym: system.map
+
+!ENDIF
diff --git a/private/mvdm/wow16/system/romstuff.inc b/private/mvdm/wow16/system/romstuff.inc
new file mode 100644
index 000000000..7cf53602e
--- /dev/null
+++ b/private/mvdm/wow16/system/romstuff.inc
@@ -0,0 +1,39 @@
+;;
+;; macros and equates intended for ROM differences
+;;
+
+ifndef ROM
+ROM = 0
+endif
+
+if ROM
+
+if1
+%out Creating Data Segment For ROM System
+endif
+
+SDSEG macro
+sBegin DATA
+endm
+
+AssumeData macro
+assumes ds, DATA
+endm
+
+DSEG equ DATA
+doffset EQU <DataOffset>
+
+else
+
+SDSEG macro
+sBegin CODE
+endm
+
+AssumeData macro
+assumes ds, CODE
+endm
+
+DSEG equ CODE
+doffset EQU <CodeOffset>
+
+endif
diff --git a/private/mvdm/wow16/system/romsys b/private/mvdm/wow16/system/romsys
new file mode 100644
index 000000000..add0dc684
--- /dev/null
+++ b/private/mvdm/wow16/system/romsys
@@ -0,0 +1,21 @@
+#
+# Standard command line definitions
+#
+as=masm -R -DROM=1
+
+#
+# Standard inference rules
+#
+.asm.obj:
+ $(as) $*.asm,,$*.lst;
+
+target: system.drv
+
+system.obj: system.asm system.inc
+
+timer.obj: timer.asm system.inc
+
+system.drv: romsys.def system.lnk system.obj timer.obj
+ link system timer, system.drv/al:16, system.map/map, /nod, system.def;
+ rc system.drv
+ mapsym system
diff --git a/private/mvdm/wow16/system/romsys.def b/private/mvdm/wow16/system/romsys.def
new file mode 100644
index 000000000..7c91c5669
--- /dev/null
+++ b/private/mvdm/wow16/system/romsys.def
@@ -0,0 +1,28 @@
+LIBRARY SYSTEM
+
+DESCRIPTION 'Microsoft Windows System Configuration Module for ROM Systems'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD FIXED
+DATA NONE
+
+IMPORTS
+
+ NOHOOKDOSCALL = KERNEL.101
+ __ROMBIOS = KERNEL.173
+ __0040h = KERNEL.193
+
+EXPORTS
+ InquireSystem @1
+ CreateSystemTimer @2
+ KillSystemTimer @3
+ EnableSystemTimers @4
+ DisableSystemTimers @5
+ GetSystemMsecCount @6
+ Get80x87SaveSize @7
+ Save80x87State @8
+ Restore80x87State @9
+ WEP
+
+ A20_Proc @20
diff --git a/private/mvdm/wow16/system/system b/private/mvdm/wow16/system/system
new file mode 100644
index 000000000..5f3f22eee
--- /dev/null
+++ b/private/mvdm/wow16/system/system
@@ -0,0 +1,21 @@
+#
+# Standard command line definitions
+#
+as=masm -R
+
+#
+# Standard inference rules
+#
+.asm.obj:
+ $(as) $*.asm;
+
+target: system.drv
+
+system.obj: system.asm system.inc
+
+timer.obj: timer.asm system.inc
+
+system.drv: system.def system.lnk system.obj timer.obj
+ link system timer, system.drv/al:16, system.map/map, /nod, system.def;
+ rc system.drv
+ mapsym system
diff --git a/private/mvdm/wow16/system/system.asm b/private/mvdm/wow16/system/system.asm
new file mode 100644
index 000000000..49980d43a
--- /dev/null
+++ b/private/mvdm/wow16/system/system.asm
@@ -0,0 +1,710 @@
+;** SYSTEM.ASM **********************************************************
+; *
+; Copyright (C) 1983,1984,1985,1986,1987,1988 by Microsoft Inc. *
+; *
+;************************************************************************
+; History
+; 18 oct 88 peterbe Added fBootDrive and test for it,
+; for diskless workstations.
+;************************************************************************
+
+ TITLE SYSTEM - InquireSystem procedure to return info about devices
+
+ include system.inc
+
+;; AT&T Machines running DOS 3.10, revisions 1.0 and 1.01 place
+;; this value into SingleDriveLoc
+
+ATT31Loc EQU 10d0h
+
+MultHIMEM EQU 43h ; HIMEM.SYS int 2fh multiplex
+MHM_ReqInstall EQU 00h ; Installation check
+MHM_ReqInstall_Ret EQU 0FFh ; I'm here Return
+
+externA __ROMBIOS
+externA __0040h
+
+externFP NoHookDOSCall
+
+
+ifdef HPSYSTEM
+ExternNP <EnableVectra, DisableVectra> ;~~vvr 091989
+endif
+
+assumes CS,CODE
+
+sBegin DATA
+
+externB timerTable
+
+;
+; InquireSystem(what,which) - returns oem specific information
+; what is the code for the device
+; which specifies which one of those devices
+;
+; WHAT = 0 Timer resolution
+; Return the resolution of the timer specified by the which
+; parameter in DX:AX. Windows always uses which == 0
+;
+; WHAT = 1 Disk Drive Information (Drive A = 0)
+; which is the disk drive (A = 0)
+; Returns:
+; ax = 0 means the drive does not exist. if dx != 0 then the drive
+; maps to the drive in dx instead (A = 1) AND the drive is
+; REMOVEABLE.
+; ax = 1 means the drive does not exist. if dx != 0 then the drive
+; maps to the drive in dx instead (A = 1) AND the drive is
+; FIXED.
+; ax = 2 means the drive is removable media
+; ax = 3 means the drive is fixed media
+; ax = 4 means the drive is fixed media and remote
+;
+; WHAT = 2 Enable/Disable one drive logic
+; which = 0 means disable, which <> 0 means enable
+; This code enables/disables the RAM BIOS message:
+; "Please insert disk for drive B:"
+;
+
+;
+; The following flag deals with some unpleasantness in the fast boot code.
+; The fast boot code delays our INIT call till to late because some code
+; in KERNEL which uses InquireSystem is called first. We fix this problem
+; with this flag......
+;
+globalB SystemIsInited,0
+
+; Following from RAMDRIVE
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Unfortunately the code in ramdrive is very machine dependent
+; necessitating the use of a system flag to store the machine
+; configuration. The system flag is initialised during init time
+; and used when the caching services are requested. One bit which
+; is set and tested during caching is the state of the a20 line
+; when the cache code is entered. This is used because there are
+; applications which enable the a20 line and leave it enabled
+; throughout the duration of execution. Since ramdrive is a device
+; driver it shouldn't change the state of the environment.
+;
+; The system flag bit assignments are:
+;
+; -------------------------------------------------
+; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+; -------------------------------------------------
+; |-----| | | | | | |
+; | | | | | | -----286 (and AT)
+; | | | | | -----------386 (later than B0)
+; not | | | -----------------PS/2 machine
+; used | | -----------------------Olivetti (not used)
+; | -----------------------------A20 state (enabled ?)
+; -----------------------------------DOS 3.x >= 3.3
+
+; The Olivetti guys have defined a flag of their own. This should be removed
+; and the bit assigned out here for them should be used.
+;
+sys_flg db 0
+;
+; equates used for the system flag
+;
+M_286 equ 00000001B
+M_386 equ 00000010B
+M_PS2 equ 00000100B
+M_OLI equ 00001000B
+A20_ST equ 00010000B
+DOS_33 equ 00100000B
+HAVE_FFFE equ 01000000B
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; A20 address line state determination addresses
+;
+low_mem label dword
+ dw 20h*4
+ dw 0
+
+high_mem label dword
+ dw 20h*4 + 10h
+ dw 0ffffh
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; A20 PS2 equates
+;
+PS2_PORTA equ 0092h
+GATE_A20 equ 010b
+
+; End RAMDRIVE stuff
+
+globalB numFloppies,0
+globalB fBootDrive,0
+globalB oneDriveFlag,0
+globalW coProcFlag,0
+globalD HiMem,0
+globalW DosVer,0
+
+;; SingleDriveLoc defaults to the value of SingleDrive (104h) on other
+;; than AT&T machines. Otherwise the value is changed during
+;; the execution of single drive enable/disable.
+
+SingleDriveLoc dw SingleDrive
+
+sEnd
+
+sBegin CODE
+
+GlobalW MyCSDS, _DATA
+
+;-----------------------------------------------------------------------;
+; InquireSystem
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 21-Nov-1988 14:57:21 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InquireSystem,<FAR,PUBLIC,NODATA>
+ parmW what
+ parmW which
+cBegin
+ push ds
+ mov ds, MyCSDS
+ assumes ds,DATA
+
+ cmp SystemIsInited,0 ; Are we ready for this call?
+ jnz DoInq ; Yes
+ call far ptr InitSystem ; No, Set up
+DoInq:
+ mov ax,what
+
+;---------------------------------------
+;
+; Timer information
+;
+ or ax,ax
+ jnz is1
+ mov dx,res_high
+ mov ax,res_low
+ jmp ISDone
+
+;---------------------------------------
+;
+; Drive information
+;
+is1: dec ax ; ax = 1?
+ jz DriveInfo
+ jmp is5
+
+DriveInfo:
+ mov ah,19h ; get the current disk
+ cCall NoHookDOSCall
+ mov bx,Which ; try to set to this disk
+ cmp al,bl ; already there?
+ jz DriveData ; yes, drive is good
+
+ push ax
+ mov dx,bx
+ mov ah,0Eh ; set to new disk
+ cCall NoHookDOSCall
+ mov ah,19h ; get the current disk
+ cCall NoHookDOSCall
+ mov bh,al
+ pop dx
+ mov ah,0Eh ; restore current disk
+ cCall NoHookDOSCall
+ cmp bh,bl ; Drive good?
+ jz DriveData ; yes
+ jmp is9 ; no, this drive totally bad
+
+; First check if this is network. We must do this first because
+; the removeable and phantom IOCTL calls return errors if you feed
+; them network drives. If it is network then we know it is non-removable
+; and not phantom.
+
+DriveData:
+ cmp DosVer,0400h
+ jb no_4
+ cmp DosVer,0401h
+ ja no_4
+ cCall Dos4IsRemote,<Which>
+ or ax,ax
+ jmp short well_is_it
+
+no_4: mov ax,4409h ; IOCTL is Remote
+ mov bx,Which
+ inc bx ; A = 1
+ cCall NoHookDOSCall
+ jc DoRem ; Call didn't work, go ahead
+ test dx,0001000000000000B
+well_is_it:
+ jz DoRem ; Drive is local
+ mov cx,REMOTE ; Drive is not removeable
+ jmp short NoRemap ; Drive is not phantom
+
+; Now Check "removeability"
+
+DoRem:
+ mov ax,4408h ; IOCTL is removeable
+ mov bx,Which
+ inc bx ; A = 1
+ cCall NoHookDOSCall
+ jc OLDRemove ; Call didn't work, use old method
+ mov cx,FIXED
+ test ax,1
+ jnz DrivePhantom
+ mov cx,REMOVEABLE
+
+; The drive is removable ...
+; This code accounts for the fact that the code above on a PS/2
+; Mod 50 diskless workstation reports the existence of a floppy
+; drive on A: or B: even if it's unplugged. If this is drive A:
+; or B:, we need to test fBootDrive to see if this drive REALLY
+; exists.
+
+ cmp Which, 2 ; this isn't likely, but..
+ jae DrivePhantom ; there ARE removable hard drives.
+ test fBootDrive,1 ; Must be a floppy, does this system have any?
+ jnz DrivePhantom ; if 0,
+ jmp Is9 ; we assume there are none
+
+; Now check for phantom drives
+
+DrivePhantom:
+ mov ax,440EH ; IOCTL get logical map
+ mov bx,Which
+ inc bx ; A = 1
+ cCall NoHookDOSCall
+ jc OLDPhantom ; Call didn't work, use old method
+ or al,al ; If AL=0, drive is NOT phantom
+ jz NoRemap
+ cmp bl,al ; Drive maps to self?
+ jz NoRemap ; Yes, drive is not phantom
+ xor ah,ah
+ mov dx,ax ; DX is real drive
+SetPhantomRet:
+ xor ax,ax ; Set removeable return
+ cmp cx,REMOVEABLE
+ jz IsDoneV
+ inc ax ; Set fixed return
+ jmp short IsDoneV
+
+NoRemap:
+ xchg ax,cx ; AX = type of drive
+ xor dx,dx ; Indicate no remapping
+IsDoneV:
+ jmp ISDone
+
+
+; Check removeability with equipment word
+
+OLDRemove:
+ xor ax,ax
+ or al,numFloppies ; just one floppy on system?
+ jnz OLDR1 ; no, continue
+ inc ax ; pretend we have two floppies...
+OLDR1:
+ cmp ax,which
+ mov cx,FIXED
+ jb DrivePhantom
+ mov cx,REMOVEABLE
+ jmp short DrivePhantom
+
+; Check phantomness with equipment word
+
+OLDPhantom:
+ cmp Which,1 ; Drive B is only phantom
+ jnz NoRemap ; Not drive B, so not phantom
+ cmp numFloppies,0 ; Single floppy system?
+ jnz NoRemap ; No, drive B is real
+ mov dx,1 ; Drive B is really drive A
+ jmp short SetPhantomRet
+
+;---------------------------------------------------
+;
+; Single Floppy enable/disable
+;
+is5: dec ax ; floppy enable disable?
+ jnz is9
+
+is5b: cmp which,0 ; 0=disable
+ jnz is6
+
+; Disable various OEM things
+
+ cmp DosVer,0314h ; Below DOS 3.20?
+ jae nosingdrv1 ; No, no ROM area diddle
+
+;;
+;; AT&T MS-DOS 3.10 does not keep information on the last floppy
+;; drive accessed at 504h. The purpose of this section
+;; of code is to locate the bytes and patch them accordingly.
+;;
+
+ mov ax,__ROMBIOS ;; is this an AT&T machine ?
+ mov es,ax ;; look for start of 'OLIVETTI'
+ cmp es:[0C050h],'LO'
+ jnz ATTCheckDone ;; No, continue
+ mov SingleDriveLoc,ATT31Loc
+ATTCheckDone:
+
+ mov ax,__0040h
+ mov es,ax
+ mov bx,SingleDriveLoc ;; set to drive A
+ xor ah, ah ; set to drive A: also! (A=0)
+ xchg ah,es:[bx]
+ mov oneDriveFlag,ah ; remember previous setting
+nosingdrv1:
+ jmp short is9
+
+; Enable various OEM things
+
+is6: cmp DosVer,0314h ; Below DOS 3.20?
+ jae nosingdrv2 ; No, no ROM diddle
+ mov ax,__0040h
+ mov es,ax
+ mov bx,SingleDriveLoc ;; pointer to value
+ mov ah,oneDriveFlag
+ mov es:[bx],ah ;; restore to correct drive
+nosingdrv2:
+
+is9: xor dx,dx
+ xor ax,ax
+ISDone:
+ pop ds
+
+cEnd Inquire
+
+
+;-----------------------------------------------------------------------;
+; Get80x87SaveSize ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Feb 05, 1987 10:15:13p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Get80x87SaveSize,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+ mov ds, MyCSDS
+ assumes ds, DATA
+ mov ax,CoProcFlag
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Save80x87State ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Feb 05, 1987 10:15:17p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Save80x87State,<PUBLIC,FAR>
+; parmD savearea
+cBegin nogen
+ mov bx,sp
+ les bx,[bx][4]
+ fsave es:[bx]
+ ret 4
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; Restore80x87State ;
+; ;
+; ;
+; Arguments: ;
+; ;
+; Returns: ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Thu Feb 05, 1987 10:15:23p -by- David N. Weise [davidw] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc Restore80x87State,<PUBLIC,FAR>
+; parmD savearea
+cBegin nogen
+ mov bx,sp
+ les bx,[bx][4]
+ frstor es:[bx]
+ ret 4
+cEnd nogen
+
+if2
+%out Dummy A20 handler still here
+endif
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc A20_Proc,<PUBLIC,FAR>
+; parmW enable
+cBegin nogen
+ mov ax, 2 ; No himem area error code
+ ret 2
+cEnd nogen
+
+
+; the following routine is added per DavidW's suggestion that the disable
+; calls be made through WEP routine and this WEP will call any clean-up
+; to be done by the driver.
+
+ifdef HPSYSTEM
+
+cProc WEP, <PUBLIC, FAR>
+ parmW dummy
+cBegin
+ call DisableVectra ;~~vvr 091989
+ mov ax, 1 ; by convention
+cEnd
+
+else
+
+cProc WEP,<PUBLIC,FAR>
+; parmW dummy
+cBegin nogen
+ mov ax,1
+ ret 2
+cEnd nogen
+
+endif ;HPSYSTEM
+
+
+;-----------------------------------------------------------------------;
+; ;
+; BOOL Dos4IsRemote(int); ;
+; ;
+; ENTRY: Word, iPDrive: must be of the form ( logical volume A = 0 ) ;
+; Physical Drive Spec. B = 1 ;
+; C = 2 ;
+; ect. ;
+; EXIT: BOOL returned in AX True = Remote ;
+; False = Local ;
+; ;
+; DESTROYS: AX. (preserves all registers except AX for return value) ;
+; ;
+; Wed 27-Sep-1989 20:08:18 -by- David N. Weise [davidw] ;
+; Stole this from setup, made it smaller. ;
+; ;
+; AUTHOR: MC ;
+;-----------------------------------------------------------------------;
+
+cProc Dos4IsRemote,<NEAR,PUBLIC.ATOMIC,NODATA>, <si,di,ds,es>
+
+ ParmW iPDrive ; Int Physical drive spec 0 - 25
+ localV local_name,16 ; Buffer to hold redirected local name.
+ localV net_name,128 ; Buffer to hold remote device name.
+ ; redirected local device names.
+cBegin
+
+; We have to use DOS call int 21h/5f02h because DOS call int 21h/4409h
+; is not reliable under DOS versions 4.00 and 4.01.
+
+ xor cx,cx
+ mov ax,ss ; Load segs for stack vars.
+ mov es,ax
+ mov ds,ax
+
+next_entry:
+ mov bx,cx ; CX = redirection list index.
+ lea si,local_name ; ds:si = local_name
+ lea di,net_name ; es:di = net_name
+ push cx ; save CX
+ mov ax,5F02h ; func 5f/02 Get redirection list.
+ call NoHookDOSCall
+ pop cx ; restore CX
+ mov ax,0 ; don't change flags
+ jc IsRemoteDone ; error, not supported or end of list.
+
+ cmp bl,04h ; Is redirected device a drive ?
+ jne not_a_drive ; If not, we don't care !
+
+ mov al,ds:[si] ; Grab volume name.
+ sub al,41h ; Convert to volume number A=0 ect.
+ cmp ax,iPDrive
+ jz remote_found
+
+not_a_drive:
+ inc cx ; CX = redirection list index.
+ jmp short next_entry
+
+remote_found:
+ mov ax,1 ; Indicate Volume is remote !
+
+IsRemoteDone:
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; InitSystem
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 21-Nov-1988 14:57:21 -by- David N. Weise [davidw]
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc InitSystem,<PUBLIC,FAR>
+cBegin nogen
+ push ds
+
+ mov ds, MyCSDS
+ assumes ds, DATA
+
+ cmp SystemIsInited,0 ; Have we already done this?
+ jnz no_80x87 ; Yes
+ inc SystemIsInited ; We will now init
+
+ mov ah,30h ; Get DOS version
+ int 21h
+ xchg ah,al ; major <-> minor
+ mov DosVer,ax
+
+ifdef HPSYSTEM
+ call EnableVectra ;~~vvr 091889
+endif
+
+ int 11h ; get equipment word
+ push ax
+ mov cl,6
+ shr ax,cl
+ and al,00000011b ; isolate drive count
+ mov numFloppies,al
+ pop ax
+
+; Set fBootDrive
+
+ mov fBootDrive,al ; bit 0 has boot volume installed flag
+
+; Set CoProcFlag
+
+ mov CoProcFlag,0
+ test al,2 ; this is the IBM approved method
+ jz no_80x87 ; to check for an 8087
+ mov CoProcFlag,94 ; size of save area
+ FNINIT
+no_80x87:
+ mov ax,1
+ pop ds
+ ret
+
+cEnd nogen
+
+ifdef JAPAN
+;-----------------------------------------------------------------------;
+; JapanInquireSystem( what, which )
+; Get system information - Japanese specific.
+;
+; Entry:
+; what - function code as;
+; 0 - Inquire interrupt vector modification
+; 'which' contains interrupt vector number (0-FF)
+; to get it is can be changed. Returns zero if a
+; vector cannot be changed
+; 1 - Get Boot drive
+; Returns boot drive. 0=A,1=B...etc.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc JapanInquireSystem,<PUBLIC,FAR>
+ parmW what
+ parmW which
+cBegin
+ mov ax,what
+ test ax,ax ; what=1?
+ jnz jis2 ; jump if not
+ mov ax,which ; get vector number to examine
+ cmp al,1bh ; try to change 1b?
+ jz jis1 ; jump if so - cannot modify
+ cmp al,1ch ; try to change 1c?
+ jz jis1 ; jump if so - channot modify
+ mov ax,1 ; OK to modify
+ jmp jisx
+jis1:
+ xor ax,ax ; cannot modify
+ jmp jisx
+jis2:
+ dec ax ; what=2?
+ jnz jis3 ; jump if not
+ mov ax,2 ; drive 'C:' is a default boot drive for
+ ; industrial standard PC
+ jmp jisx
+jis3:
+ mov ax,-1 ; error!
+jisx:
+cEnd
+
+endif ;JAPAN
+
+
+sEnd CODE ; End of code segment
+
+
+END InitSystem
diff --git a/private/mvdm/wow16/system/system.def b/private/mvdm/wow16/system/system.def
new file mode 100644
index 000000000..4262fb972
--- /dev/null
+++ b/private/mvdm/wow16/system/system.def
@@ -0,0 +1,32 @@
+LIBRARY SYSTEM
+
+DESCRIPTION 'Microsoft Windows System configuration module for IBM/PC/XT/AT'
+EXETYPE WINDOWS
+
+STUB '..\bin\winstub.exe'
+CODE PRELOAD FIXED
+DATA NONE
+
+IMPORTS
+
+ NOHOOKDOSCALL = KERNEL.101
+ ALLOCCSALIAS = KERNEL.170
+ __ROMBIOS = KERNEL.173
+ __0040h = KERNEL.193
+
+EXPORTS
+ InquireSystem @1
+ CreateSystemTimer @2
+ KillSystemTimer @3
+ EnableSystemTimers @4
+ DisableSystemTimers @5
+ GetSystemMsecCount @6
+ Get80x87SaveSize @7
+ Save80x87State @8
+ Restore80x87State @9
+ WEP
+
+ A20_Proc @20
+;;IFDEF JAPAN
+;;; JapanInquireSystem ; MSKK specific
+;;ENDIF
diff --git a/private/mvdm/wow16/system/system.inc b/private/mvdm/wow16/system/system.inc
new file mode 100644
index 000000000..b9803624d
--- /dev/null
+++ b/private/mvdm/wow16/system/system.inc
@@ -0,0 +1,45 @@
+;***************************************************************************
+; *
+; Copyright (C) 1983,1984 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+;***************************************************************************
+; *
+; Header file for IBM/PC timer device driver. Contains all machine *
+; specific constant and data structure definitions. *
+; *
+;***************************************************************************
+
+ .xlist
+ include cmacros.inc
+; include windefs.inc
+ .list
+
+; picked off romstuff.inc
+
+DSEG equ DATA
+doffset EQU <DataOffset>
+
+; Approximate value of timer tic in milliseconds * 1000.
+
+res_low EQU 54925
+res_high EQU 0
+
+; equates for disk status
+
+REMOVEABLE equ 2
+FIXED equ 3
+REMOTE equ 4
+
+; Offset of Single Diskette indicator from beginning of Bios Data Area, 400h
+
+SingleDrive equ 104h
+
+; Timer structure
+
+tiblock STRUC
+tirate DW ? ; -1 means not used, 0 means call as fast as possible
+ticount DW ? ; -1 means end of table.
+tiproc DD ? ; far proc to call.
+tiblock ENDS
diff --git a/private/mvdm/wow16/system/system.lnk b/private/mvdm/wow16/system/system.lnk
new file mode 100644
index 000000000..f46eac847
--- /dev/null
+++ b/private/mvdm/wow16/system/system.lnk
@@ -0,0 +1,5 @@
+system timer
+system.drv
+system.map/map /AL:16
+/NOD
+system.def
diff --git a/private/mvdm/wow16/system/system.rc b/private/mvdm/wow16/system/system.rc
new file mode 100644
index 000000000..bac3fb0c8
--- /dev/null
+++ b/private/mvdm/wow16/system/system.rc
@@ -0,0 +1,5 @@
+/********************************************************************/
+/* SYSTEM.RC */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include "system.rcv"
diff --git a/private/mvdm/wow16/system/system.rcv b/private/mvdm/wow16/system/system.rcv
new file mode 100644
index 000000000..3b61258a4
--- /dev/null
+++ b/private/mvdm/wow16/system/system.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* SYSTEM.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows System Driver core component"
+#define VER_INTERNALNAME_STR "SYSTEM"
+#define VER_ORIGINALFILENAME_STR "SYSTEM.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/system/timer.asm b/private/mvdm/wow16/system/timer.asm
new file mode 100644
index 000000000..a36609383
--- /dev/null
+++ b/private/mvdm/wow16/system/timer.asm
@@ -0,0 +1,519 @@
+;------------------------------ Module Header ------------------------------;
+; Module Name: Timer interface procedures
+;
+; Created: ??-???-83
+;
+; Copyright (c) 1983, 1984, 1985, 1986, 1987 Microsoft Corporation
+;
+; History:
+; 10-Jan-87 by ronm Adusted StackBase to be even
+; 9-Jan-87 by ronm Patches to support HiTime.asm
+;---------------------------------------------------------------------------;
+
+ TITLE Timer interface procedures
+
+include system.inc
+include wow.inc
+include wowusr.inc
+include vint.inc
+
+; Interrupt vector to use
+
+VECTOR equ 08h
+
+assumes CS,CODE
+
+sBegin DATA
+
+ PUBLIC timerTable
+timerTable LABEL BYTE
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+tiblock <-1,0,0>
+ DW -1
+ DW -1
+
+ifdef WOW
+cTimers DW 0
+endif
+
+enabled DB 0 ; 0 means int 8 hook not installed
+ ; 1 means int 8 hook installed
+ ; >1 means inside our int 8 hook
+
+
+if 0
+;
+; no longer used
+;
+ public StackBase
+ EVEN ; Put the stack at a word boundary!
+StackBase DB 64 DUP (-1)
+
+ PUBLIC prevInt8Proc,prevSSSP,enabled
+ PUBLIC cms, cmsRound
+
+ DB 128 DUP (?)
+int8stack LABEL BYTE ; Stack to use inside our int 8 hook
+
+prevSSSP DD 0 ; Previous stack when inside our hook
+endif
+
+prevInt8Proc DD 0 ; Previous int 8 interrupt handler
+cms DD 0 ; msec count.
+cmsRound DW 0 ; for rounding off the msec count.
+
+sEnd
+
+sBegin CODE ; Beginning of code segment
+assumes CS,CODE
+
+externW MyCSDS ; always in CS (even in ROM)
+
+;--- timer hardware service -----------------------
+;
+noevent:
+ assumes ds, DATA
+ ; push address
+ push word ptr prevInt8Proc[2]
+ push word ptr prevInt8Proc[0]
+
+ ; restore ds out of stack
+ push bp
+ mov bp, sp
+ mov ds, [bp+6]
+ assumes ds,nothing
+ pop bp
+
+ ; jump to prev proc popping saved ds
+ retf 2
+
+;----------------------------- Private Function ----------------------------;
+;
+; Entry: call far ptr timer_int
+;
+; Returns: nothing
+;
+; Registers Destroyed: none
+;
+; History:
+; 09-Jan-87 by ronm Added hooks for the high resolution timer fns
+; in hitime.asm
+; ??-???-?? by ???? Wrote it
+;---------------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc timer_int,<FAR,PUBLIC>
+
+cBegin nogen
+
+; Don't trash any registers.
+
+ push ds
+ mov ds,MyCSDS
+ assumes ds, DATA
+ add word ptr [cms][0],(res_low / 1000)
+ adc word ptr [cms][2],0
+ add [cmsRound],(res_low - ((res_low / 1000) * 1000))
+ cmp [cmsRound],1000
+ jb ti0
+ sub [cmsRound],1000
+ inc word ptr [cms][0]
+ jnz ti0
+ inc word ptr [cms][2]
+ti0:
+ cmp [enabled],1
+ jne noevent
+ inc [enabled]
+
+ pushf
+
+ ; enable IF flag in stack flags to prevInt8Proc if they were
+ ; on when this routine was entered -- this allows the 286 DOS
+ ; extender to enable ints after running real mode Int 8 handler.
+
+ FLAGS1 = 3 ; +0 +2 +4 +6 +8 +10
+ FLAGS2 = 11 ; BP -> [bp] [fl] [ds] [ip] [cs] [fl]
+
+ push bp
+ mov bp,sp
+ test byte ptr FLAGS2[bp],02h
+ jz @f
+ or byte ptr FLAGS1[bp],02h
+@@: pop bp
+
+
+ call [prevInt8Proc] ; call previous Int 8 routine
+
+ public ti1
+ti1:
+
+comment ~
+ FCLI
+ mov word ptr [prevSSSP][2],ss
+ mov word ptr [prevSSSP][0],sp
+ push ds
+ pop ss
+ mov sp,codeOffset int8stack
+ FSTI ; Allow interrupts
+
+end comment ~
+
+ push ax
+
+ mov al,00001011b ; ask for 8259 status
+ out 20h,al
+ jmp $+2
+ in al,20h ; get the status
+ or al,al
+ jnz TheEnd ; if other pending EOIs, just exit
+
+ push bp
+ push es
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+
+ xor bp,bp ; No valid BP chain
+ mov si,doffset TimerTable
+nextent:
+ cld
+ lodsw ; Get timer rate
+ .errnz tirate
+ inc ax ; -1 means unused entry
+ jnz checkent ; no, check used entry
+ lodsw ; yes, get timer count
+ .errnz 2-ticount
+ inc ax ; another -1 means end of table
+ jz lastent ; yes, all done
+ add si,4 ; o.w. skip to next entry
+ jmp nextent
+checkent:
+ dec ax ; 0 means call at maximum rate
+ jz callent
+ dec word ptr DS:[si] ; o.w. decrement rate counter
+ .errnz 2-ticount
+ jz callent ; zero means timer has gone off
+ add si,6 ; o.w. skip to next entry
+ jmp nextent
+callent:
+ mov DS:[si],ax
+ inc si
+ inc si
+ lea ax,[si-4] ; Pass timer handle in AX
+ .errnz 4-tiproc
+ call dword ptr DS:[si]
+ add si,4
+ jmp nextent
+lastent:
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop es
+ pop bp
+TheEnd:
+ pop ax
+ dec [enabled]
+
+comment ~
+ FCLI
+ mov ss,word ptr [prevSSSP][2]
+ mov sp,word ptr [prevSSSP][0]
+ FSTI
+
+end comment ~
+
+ pop ds
+
+
+ iret
+
+cEnd nogen
+
+
+;============================================================================
+; DWORD GetSystemMsecCount(void) - returns msec count.
+;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+ DUserThunk GETSYSTEMMSECCOUNT,0
+
+;LabelFP <PUBLIC, GetSystemMsecCount>
+;
+; push ds
+; mov ds, MyCSDS
+; assumes ds, DATA
+;
+; mov ax,word ptr [cms][0]
+; mov dx,word ptr [cms][2]
+; pop ds
+; retf
+
+;----------------------------- Private Function ----------------------------;
+;
+; EnableSystemTimers() - enable hardware timer interrupts
+;
+; Entry: cCall far ptr EnableSystemTimers
+;
+; Returns: nothing
+;
+; Registers Destroyed: ??
+;
+; History:
+; 09-Jan-87 by ronm Patched to support hitime.asm
+; ??-???-?? by ???? Wrote it
+;---------------------------------------------------------------------------;
+
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc EnableSystemTimers,<FAR,PUBLIC>
+cBegin nogen
+
+; All done if just already enabled
+
+ push ds
+ mov ds,MyCSDS
+ assumes ds, DATA
+
+ifdef WOW
+ ; see if we're being called by Create to really enable tics
+ cmp cTimers, 1
+ je est_doit
+endif
+
+ cmp enabled,0
+ jne edone
+
+est_doit:
+ mov [enabled],1
+
+ifdef WOW
+ ; don't install the tic handler if no systemtimers registered
+ cmp cTimers, 0
+ je edone
+endif
+
+; Save away current timer interrupt vector value
+
+ mov ax,3500h or VECTOR
+ int 21h
+ mov word ptr [PrevInt8Proc][0],bx
+ mov word ptr [PrevInt8Proc][2],es
+
+; Setup timer interrupt vector to point to our interrupt routine
+
+ mov ax,2500h or VECTOR
+ push cs
+ pop ds
+ mov dx,codeOFFSET timer_int
+ int 21h
+edone:
+ pop ds
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; DisableSystemTimers
+;
+; DisableSystemTimers() - disable system timer interrupts, restoring
+; the previous timer interrupt handler.
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 21-Nov-1988 18:44:44 -by- David N. Weise [davidw]
+; Added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc DisableSystemTimers,<FAR,PUBLIC>
+cBegin nogen
+
+ push ds
+ mov ds,MyCSDS
+ assumes ds, DATA
+
+; Do nothing if not enabled
+
+ cmp [enabled],0
+ je ddone
+ mov [enabled],0
+
+; Restore the timer interrupt vector to point to previous value
+
+ mov ax,2500h or VECTOR
+ lds dx,prevInt8Proc
+ int 21h
+ddone:
+ pop ds
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; CreateSystemTimer
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 21-Nov-1988 18:44:44 -by- David N. Weise [davidw]
+; Added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc CreateSystemTimer,<PUBLIC,FAR>
+ ParmW rate
+ ParmD lpproc
+cBegin
+ mov ds,MyCSDS
+ assumes ds, DATA
+ mov bx,doffset timerTable
+ mov ax,rate
+ or ax,ax
+ jz ctfirst
+ mov cx,1000 ; change msecs into ticks.
+ mul cx
+ mov cx,res_low
+ div cx
+ctfirst:
+ FCLI ; beginning of critical section
+ctloop:
+ cmp ds:[bx].tirate,-1
+ jne ctnext
+ cmp ds:[bx].ticount,-1
+ je ctfail
+ mov cx,OFF_lpproc
+ mov dx,SEG_lpproc
+ mov word ptr ds:[bx].tiproc[0],cx
+ mov word ptr ds:[bx].tiproc[2],dx
+ mov ds:[bx].ticount,ax
+ mov ds:[bx].tirate,ax ; Set this last
+
+ifdef WOW
+ ; turn on tics if the count is going from 0 -> 1 and they're
+ ; supposed to be enabled
+
+ inc cTimers
+ cmp cTimers, 1
+ jne @f
+
+ cmp enabled, 0 ; need to turn on tics?
+ je @f ; -> nope
+
+ push bx
+ call EnableSystemTimers
+ pop bx
+@@:
+endif
+
+ jmp short ctexit
+
+ctnext: add bx,SIZE tiblock
+ jmp ctloop
+
+ctfail: xor bx,bx
+
+ctexit: FSTI ; end of critical section
+ mov ax,bx
+ mov cx,bx
+cEnd
+
+;-----------------------------------------------------------------------;
+; KillSystemTimer
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Mon 21-Nov-1988 18:44:44 -by- David N. Weise [davidw]
+; Added this nifty comment block.
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc KillSystemTimer,<PUBLIC,FAR>,<di>
+ parmW htimer
+cBegin
+ mov es,MyCSDS
+ assumes es,nothing
+ mov di,doffset TimerTable
+ mov ax,htimer
+
+ktloop: cmp es:[di].tirate,-1
+ jne ktmatch
+ cmp es:[di].ticount,-1
+ jne ktnext
+ jmp short ktexit
+ktmatch:
+ cmp di,ax
+ jne ktnext
+ cld
+ mov ax,-1
+ stosw
+ not ax
+ stosw
+ stosw
+ stosw
+ifdef WOW
+ dec es:[cTimers] ; was this the last one?
+ jnz @f ; -> nope
+
+ cmp es:[enabled], 0 ; are tics on?
+ je @f ; -> nope
+
+; Restore the timer interrupt vector to point to previous value
+
+ push ax
+
+ mov ax,2500h or VECTOR
+ lds dx,es:[prevInt8Proc]
+ int 21h
+
+ pop ax
+@@:
+endif
+
+ jmp short ktexit
+
+ktnext: add di,SIZE tiblock
+ jmp ktloop
+
+ktexit: mov cx,ax
+cEnd
+
+sEnd CODE ; End of code segment
+
+END
diff --git a/private/mvdm/wow16/system/vecsys.inc b/private/mvdm/wow16/system/vecsys.inc
new file mode 100644
index 000000000..35cc1ba81
--- /dev/null
+++ b/private/mvdm/wow16/system/vecsys.inc
@@ -0,0 +1,45 @@
+;------------------------------------------------------------------
+;
+; HPsysCall(Service, Function, Subfunction)
+;
+; Purpose General purpose HP system calling routine
+;
+; Parameters Service - HP vector
+; Function
+; Subfunction - function numbers
+;
+; Results returns AH which is 0 for success
+;
+;-------------------------------------------------------------------
+HPSysCall macro Device, Function, SubFunc
+
+ push ds
+ push bp
+ push ax
+
+ mov bx, offset RealMode_Word_Struc
+ pushf
+ pop RealMode_flags[bx]
+ mov RealMode_BP[bx], Device
+ mov RealMode_AH[bx], Function
+ mov RealMode_AL[bx], SubFunc
+ mov ax, ds
+ mov es, ax ; make es = ds
+ mov di, bx
+ mov bl, 6fh
+ xor bh, bh
+ xor cx, cx
+ mov ax, 0300h
+ int 31h
+ mov bx, offset RealMode_Word_Struc
+ mov ax, es
+ mov ds, ax
+ mov bx, RealMode_BX[bx]
+
+ pop ax
+ pop bp
+ pop ds
+
+ endm
+
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/system/windefs.inc b/private/mvdm/wow16/system/windefs.inc
new file mode 100644
index 000000000..92a4ecb4b
--- /dev/null
+++ b/private/mvdm/wow16/system/windefs.inc
@@ -0,0 +1,104 @@
+;***************************************************************************
+; *
+; Copyright (C) 1983,1984 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+; Macros for disabling and restoring hardware interrupt enable flag
+;
+; The LeaveCrit macro has been updated for the mask problem on
+; the 80286 processor.
+
+
+include vint.inc
+
+EnterCrit MACRO
+ pushf
+ FCLI
+ENDM
+
+LeaveCrit MACRO
+ POPFF
+ENDM
+
+POPFF MACRO
+ local a
+ jmp $+3
+a label near
+ iret
+ push cs
+ call a
+ENDM
+
+
+
+
+
+;***************************************************************************
+; *
+; Inquire data structures for Timer, Keyboard, Mouse and Cursor modules *
+; *
+;***************************************************************************
+
+TIMERINFO STRUC
+tiResolution DD 0 ; #microseconds each timer tick
+TIMERINFO ENDS
+
+KBINFO STRUC
+kbRanges DB 4 dup (0) ; Far East ranges for KANJI
+kbStateSize DW 0 ; #bytes of state info maintained by TOASCII
+kbNumFuncKeys DW 0 ; How many function keys are on the keyboard
+kbHasBreak DW 0 ; true => keyboard supplies make and break
+kbRate DW 0 ; maximum rate of keyboard input events
+KBINFO ENDS
+
+
+MOUSEINFO STRUC
+msExists DB 0 ; true => mouse exists
+msRelative DB 0 ; true => relative coordinate
+msNumButtons DW 0 ; number of buttons on the mouse
+msRate DW 0 ; maximum rate of mouse input events
+msXThresh DW 0 ; threshold before acceleration
+msYThresh DW 0 ;
+msXRes DW 0 ; x resolution
+msYRes DW 0 ; y resolution
+MOUSEINFO ENDS
+
+
+CURSORINFO STRUC
+dpXRate DW 0 ; horizontal mickey/pixel ratio
+dpYRate DW 0 ; vertical mickey/pixel ratio
+CURSORINFO ENDS
+
+
+;***************************************************************************
+; *
+; Cursor data structure passed to OEM routines. Defines a graphics display*
+; cursor in terms of a hotspot, an AND mask and an XOR mask. The hot *
+; spot defines the pixel within the cursor that is the cursor is "pointing"*
+; to. So when displaying a cursor at location X,Y the pixel that *
+; is the hot spot should be painted at that X,Y coordinate. The "shape" *
+; of the cursor is defined by two pixel masks. The first mask is ANDed *
+; with the bits in the display bitmap and the second mask is XORed with *
+; the result to determine the bits that will be placed in the display *
+; bitmap. The bits for the masks are in the byte array that begins *
+; at the csBits field, with the AND mask bits first, followed by the *
+; XOR mask bits. The csWidthBytes field is the width of ONE mask, in *
+; bytes. Currently, MS-WIN will only generate cursors whose width and *
+; height are both 16. *
+; *
+;***************************************************************************
+
+cursorShape STRUC
+csHotX DW 0
+csHotY DW 0
+csWidth DW 0
+csHeight DW 0
+csWidthBytes DW 0
+csColor DW 0
+ ; Beginning of an array of bytes that contain the bits for the AND and
+ ; XOR masks. The first csHeight * csWidthBytes bytes contain the bits
+ ; for the AND mask and the next csHeight * csWidthBytes bytes contain
+ ; the bits for the XOR mask.
+;csBits DB 2*2*16 DUP (?)
+cursorShape ENDS
diff --git a/private/mvdm/wow16/test/hello/hello.c b/private/mvdm/wow16/test/hello/hello.c
new file mode 100644
index 000000000..57b9a9074
--- /dev/null
+++ b/private/mvdm/wow16/test/hello/hello.c
@@ -0,0 +1,169 @@
+/*++
+ *
+ * Hello.c
+ * Simple 16-bit Windows App
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * From "Programming Windows" by C. Petzold, p.16-19
+ *
+ * Updated 02-May-1991 by Jeff Parsons (jeffpar)
+ * To serve as a bare-bones shell (user-friendly of course)
+--*/
+
+#include <windows.h>
+#include "hello.h"
+
+
+#define BUTTON_REVERSI 1 // button IDs
+
+#define BUTTON_WIDTH 80 // width and height for all buttons
+#define BUTTON_HEIGHT 20
+
+
+BOOL FAR PASCAL EnumWindowFunc(HWND hwnd, DWORD lParam)
+{
+ char achTmp[80];
+
+ wsprintf(achTmp, "HELLO: Window %04x enumerated\n", hwnd);
+ OutputDebugString(achTmp);
+
+ return TRUE; // return non-zero to continue enumeration
+}
+
+
+LONG FAR PASCAL WndProc(HWND hwnd, WORD wMsg, int wParam, LONG lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ HANDLE hTask;
+ char achTmp[80];
+ static char achTextOut[] = "The User-Friendly WOW Shell";
+
+ switch(wMsg) {
+
+ case WM_CREATE:
+ CreateWindow("Button",
+ "Reversi",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+ 8,
+ 8 + BUTTON_REVERSI*24,
+ BUTTON_WIDTH,
+ BUTTON_HEIGHT,
+ hwnd,
+ BUTTON_REVERSI,
+ ((LPCREATESTRUCT)lParam)->hInstance, NULL);
+ return 0;
+
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+ TextOut(hdc, 8, 8, achTextOut, sizeof(achTextOut)-1);
+ EndPaint(hwnd, &ps);
+ return 0;
+
+ case WM_COMMAND:
+
+ // See if the command is from a menu
+
+ if (LOWORD(lParam) == 0) {
+
+ switch(wParam) {
+
+ case IDM_BREAKPOINT:
+ _asm int 3
+
+ // Hokey timing test -JTP
+ GetParent(hwnd);
+ {
+ int i;
+ for (i=0; i<10000; i++)
+ GetParent(hwnd);
+ }
+ return 0;
+
+ case IDM_ENUMWINDOWS:
+ OutputDebugString("HELLO: Enumerating windows\n");
+ EnumWindows(EnumWindowFunc, 0x10000001);
+ return 0;
+
+ case IDM_ENUMCHILDWINDOWS:
+ wsprintf(achTmp, "HELLO: Enumerating child windows for hwnd %04x\n", hwnd);
+ OutputDebugString(achTmp);
+ EnumChildWindows(hwnd, EnumWindowFunc, 0x10000002);
+ return 0;
+
+ case IDM_ENUMTASKWINDOWS:
+ hTask = GetCurrentTask();
+ wsprintf(achTmp, "HELLO: Enumerating task windows for task %04x\n", hTask);
+ OutputDebugString(achTmp);
+ EnumTaskWindows(hTask, EnumWindowFunc, 0x10000003);
+ return 0;
+ }
+ }
+
+ // The command must be a button notification
+ // (or something else I'm too ignorant to know about -JTP)
+
+ else {
+
+ if (wParam == BUTTON_REVERSI) {
+ // _asm int 3
+ WinExec("REVERSI.EXE", SW_SHOWNORMAL);
+ // _asm int 3
+ }
+ return 0;
+ }
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+ return DefWindowProc(hwnd, wMsg, wParam, lParam);
+}
+
+
+int PASCAL WinMain(HANDLE hInstance,
+ HANDLE hPrevInstance, LPSTR lpszCmd, int iCmd)
+{
+ HWND hwnd;
+ MSG msg;
+ WNDCLASS wc;
+ static char szApp[] = "WOW";
+
+ if (!hPrevInstance) {
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground= GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = szApp;
+ wc.lpszClassName= szApp;
+ if (!RegisterClass(&wc))
+ return 0;
+ }
+ hwnd = CreateWindow(
+ szApp, // window class name
+ szApp, // window caption
+ (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME) | WS_VISIBLE,
+ 50, 50, 250, 128,
+ NULL, // parent window handle
+ NULL, // window menu handle
+ hInstance, // program instance handle
+ NULL // creation parameters
+ );
+ if (!hwnd)
+ return 0;
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return msg.wParam;
+}
diff --git a/private/mvdm/wow16/test/hello/hello.h b/private/mvdm/wow16/test/hello/hello.h
new file mode 100644
index 000000000..8df0651e0
--- /dev/null
+++ b/private/mvdm/wow16/test/hello/hello.h
@@ -0,0 +1,20 @@
+/*++
+ *
+ * Hello.h
+ * Simple 16-bit Windows App
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * History:
+ * Created 27-Jan-1991 by Jeff Parsons (jeffpar)
+ * From "Programming Windows" by C. Petzold, p.16-19
+ *
+ * Updated 02-May-1991 by Jeff Parsons (jeffpar)
+ * To serve as a bare-bones shell (user-friendly of course)
+--*/
+
+
+#define IDM_BREAKPOINT 100
+#define IDM_ENUMWINDOWS 101
+#define IDM_ENUMCHILDWINDOWS 102
+#define IDM_ENUMTASKWINDOWS 103
diff --git a/private/mvdm/wow16/test/hello/hello.rc b/private/mvdm/wow16/test/hello/hello.rc
new file mode 100644
index 000000000..afab8eee8
--- /dev/null
+++ b/private/mvdm/wow16/test/hello/hello.rc
@@ -0,0 +1,12 @@
+#include "hello.h"
+
+WOW MENU
+BEGIN
+ POPUP "&Test"
+ BEGIN
+ MENUITEM "&Breakpoint", IDM_BREAKPOINT
+ MENUITEM "&EnumWindows", IDM_ENUMWINDOWS
+ MENUITEM "Enum&ChildWindows", IDM_ENUMCHILDWINDOWS
+ MENUITEM "Enum&TaskWindows", IDM_ENUMTASKWINDOWS
+ END
+END
diff --git a/private/mvdm/wow16/test/hello/makefile b/private/mvdm/wow16/test/hello/makefile
new file mode 100644
index 000000000..1b95e60a0
--- /dev/null
+++ b/private/mvdm/wow16/test/hello/makefile
@@ -0,0 +1,99 @@
+# HELLO makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+AOBJ = -Ml -t -DDEBUG $(INCS)
+COBJ = -AS -Gs -Os -W2 -Zp -DDEBUG $(INCS)
+
+CW16 = -AS -Gsw -Os -W2 -Zp -DDEBUG $(INCS)
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /stack:8192
+
+W16LIBS = ..\..\lib\slibcew.lib ..\..\lib\libw.lib
+
+
+.h.inc:
+ h2inc -t $*.h -o $*.inc
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+
+all: hello.exe hello.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.def del *.def
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+
+
+hello.lrf: makefile
+ echo hello.obj>hello.lrf
+ echo hello $(LINK)>>hello.lrf
+ echo hello>>hello.lrf
+ echo $(W16LIBS) /nod>>hello.lrf
+ echo hello;>>hello.lrf
+
+hello.def: makefile
+ echo name hello>hello.def
+ echo exetype windows>>hello.def
+ echo stub '..\..\bin\winstub.exe'>>hello.def
+ echo code preload moveable discardable>>hello.def
+ echo data preload moveable multiple>>hello.def
+ echo heapsize 4096>>hello.def
+ echo exports WndProc>>hello.def
+ echo exports EnumWindowFunc>>hello.def
+
+hello.res: hello.rc hello.h
+ rc16 -r -fo hello.res $(INCS) hello.rc
+
+hello.exe hello.map: hello.obj hello.lrf hello.def hello.res
+ link16 @hello.lrf;
+ rc16 hello.res hello.exe
+!ENDIF
diff --git a/private/mvdm/wow16/test/makefile b/private/mvdm/wow16/test/makefile
new file mode 100644
index 000000000..306381583
--- /dev/null
+++ b/private/mvdm/wow16/test/makefile
@@ -0,0 +1,18 @@
+# WOW16 TEST makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 28-Mar-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+all:
+ cd shell
+ $(MAKE)
+ cd ..
+
+clean:
+ cd shell
+ $(MAKE) clean
+ cd ..
diff --git a/private/mvdm/wow16/test/shell/makefile b/private/mvdm/wow16/test/shell/makefile
new file mode 100644
index 000000000..0c151a989
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/makefile
@@ -0,0 +1,124 @@
+# wowexec makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Matt Felton (mattfe)
+# 21-Mar-1992 Matt Felton Code from win 3.1 progman
+# Created.
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+AOBJ = -W2 -DSEGNAME=COMMAND $(INCS)
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+COBJ = -AS -G2s -Os -W2 -Zp -DDEBUG $(INCS)
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG $(INCS)
+!else
+COBJ = -AS -G2s -Os -W2 -Zp $(INCS)
+CW16 = -AS -G2sw -Os -W2 -Zp $(INCS)
+!endif
+
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /stack:8192 /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+RCFLAGS = -DDEBUG
+!endif
+
+W16LIBS = ..\..\lib\snocrt.lib ..\..\lib\libw.lib
+
+
+.h.inc:
+ h2inc -t $*.h -o $*.inc
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+
+all: wowexec.exe wowexec.sym
+ binplace wowexec.exe wowexec.map wowexec.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.def del *.def
+ if exist *.res del *.res
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+wowexec.obj: wowexec.c ..\..\..\inc\wowinfo.h
+ cl16 -c -nologo $(CW16) $*.c
+
+wowexfax.obj: wowexfax.c wowexec.h ..\..\..\inc\wowfax.h
+ cl16 -c -nologo $(CW16) $*.c
+
+
+wowexec.lrf: makefile
+ echo wowexec.obj pmdos.obj wowexfax.obj>wowexec.lrf
+ echo wowexec $(LINK)>>wowexec.lrf
+ echo wowexec>>wowexec.lrf
+ echo $(W16LIBS) /nod>>wowexec.lrf
+ echo wowexec;>>wowexec.lrf
+
+wowexec.def: makefile
+ echo name wowexec>wowexec.def
+ echo exetype windows>>wowexec.def
+ echo stub '..\..\bin\winstub.exe'>>wowexec.def
+ echo code preload moveable discardable>>wowexec.def
+ echo data preload moveable multiple>>wowexec.def
+ echo heapsize 512>>wowexec.def
+ echo exports WndProc>>wowexec.def
+ echo exports FaxWndProc>>wowexec.def
+ echo imports>>wowexec.def
+ echo WOWQUERYDEBUG = KERNEL.512>>wowexec.def
+ echo WOWWAITFORMSGANDEVENT = KERNEL.262>>wowexec.def
+ echo WOWMSGBOX = KERNEL.263>>wowexec.def
+ echo WOWPARTYBYNUMBER = KERNEL.273>>wowexec.def
+
+wowexec.exe: wowexec.obj wowexec.lrf wowexec.def pmdos.obj wowexfax.obj
+ rc16 -r $(RCFLAGS) -fo wowexec.res $(INCS) wowexec.rc
+ link16 @wowexec.lrf;
+ rc16 -t wowexec.res wowexec.exe
diff --git a/private/mvdm/wow16/test/shell/pmdos.asm b/private/mvdm/wow16/test/shell/pmdos.asm
new file mode 100644
index 000000000..ce7ea070a
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/pmdos.asm
@@ -0,0 +1,544 @@
+;****************************************************************************
+;* *
+;* PMDOS.ASM - *
+;* *
+;* Low level DOS routines needed by the Program Manager. *
+;* *
+;****************************************************************************
+
+memS=1
+?PLM=1
+?WIN=1
+
+include cmacros.inc
+
+SelectDisk equ 0Eh
+FCBFindFirstFile equ 11h
+FCBFindNextFile equ 12h
+FCBDeleteFile equ 13h
+FCBRenameFile equ 17h
+GetCurrentDisk equ 19h
+SetDTAAddress equ 1Ah
+GetFileSize equ 23h
+GetDiskFreeSpace equ 36h
+CreateDir equ 39h
+RemoveDir equ 3Ah
+ChangeCurrentDir equ 3Bh
+CreateFile equ 3Ch
+DeleteFile equ 41h
+GetSetFileAttributes equ 43h
+GetCurrentDir equ 47h
+FindFirstFile equ 4Eh
+FindNextFile equ 4Fh
+RenameFile equ 56h
+
+externFP DOS3CALL
+
+externFP AnsiToOem
+ifdef DBCS
+externFP IsDBCSLeadByte
+endif
+
+;=============================================================================
+
+createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE
+
+sBegin %SEGNAME
+
+assumes CS,%SEGNAME
+assumes DS,DATA
+
+cProc PathType, <FAR, PUBLIC>
+
+ parmD lpFile
+
+ localV szOEM, 128
+
+cBegin
+
+ RegPtr lpszOEM, ss, bx
+ lea bx, szOEM
+ cCall AnsiToOem, <lpFile, lpszOEM>
+
+ lea dx, szOEM
+ mov ax, 4300h
+ call DOS3CALL
+ jnc id_noerror
+ xor ax, ax
+ jmp short id_exit
+
+id_noerror:
+ and cx, 10h
+ jnz id_dir
+ mov ax, 1
+ jmp short id_exit
+
+id_dir:
+ mov ax, 2
+
+id_exit:
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* FileTime*() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc FileTime, <FAR, PUBLIC>
+
+ parmW hFile
+
+cBegin
+ mov ax, 5700h
+ mov bx, hFile
+ cCall DOS3CALL
+ jnc ft_ok
+ sub ax, ax
+ sub dx, dx
+ jmp short ft_ex
+ft_ok:
+ mov ax, cx
+ft_ex:
+cEnd
+
+;*--------------------------------------------------------------------------*
+;* *
+;* IsReadOnly() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc IsReadOnly, <FAR, PUBLIC>
+
+ parmD lpFile
+
+ localV szOEM, 128
+
+cBegin
+
+ RegPtr lpszOEM, ss, bx
+ lea bx, szOEM
+ cCall AnsiToOem,<lpFile,lpszOEM>
+
+ mov ax, 4300h ; get attributes...
+ lea dx, szOEM ; ...for given file...
+ call DOS3CALL
+ jc f_exit ; ax == 0 if error...
+ and ax, 1 ; test RO bit
+ jmp short t_exit ; true
+f_exit:
+ xor ax, ax ; false
+t_exit:
+cEnd
+
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* GetDOSErrorCode() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc GetDOSErrorCode, <FAR, PUBLIC>, <SI,DI>
+
+cBegin
+
+ mov ah,59h ; Get DOS extended error
+ sub bx,bx ; cause ray duncan says so
+ push ds ; function trashes registers
+ push bp ; so we gotta save 'em for cProc
+ call DOS3CALL
+ pop bp ; be nice to C
+ pop ds ; get DS
+ mov dl,bh ; class in byte 2
+ mov dh,ch ; locus in byte 3 (skip the rec. action)
+
+cEnd
+
+;*--------------------------------------------------------------------------*
+;* *
+;* GetCurrentDrive() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc GetCurrentDrive, <FAR, PUBLIC>
+
+cBegin
+ mov ah,GetCurrentDisk
+ call DOS3CALL
+ sub ah,ah ; Zero out AH
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetCurrentDrive() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Returns the number of drives in AX.
+
+cProc SetCurrentDrive, <FAR, PUBLIC>
+
+ParmW Drive
+
+cBegin
+ mov dx,Drive
+ mov ah,SelectDisk
+ call DOS3CALL
+ sub ah,ah ; Zero out AH
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* GetCurrentDirectory() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc GetCurrentDirectory, <FAR, PUBLIC>, <SI, DI>
+
+parmW wDrive
+ParmD lpDest
+
+cBegin
+ push ds ; Preserve DS
+
+ mov ax,wDrive
+ or al,al
+ jnz GCDHaveDrive
+
+ call GetCurrentDrive
+
+ inc al ; Convert to logical drive number
+
+GCDHaveDrive:
+ les di,lpDest ; ES:DI = lpDest
+ push es
+ pop ds ; DS:DI = lpDest
+ cld
+
+ mov dl,al ; DL = Logical Drive Number
+ add al,'@' ; Convert to ASCII drive letter
+ stosb
+ mov al,':'
+ stosb
+ mov al,'\' ; Start string with a backslash
+ stosb
+ mov byte ptr es:[di],0 ; Null terminate in case of error
+ mov si,di ; DS:SI = lpDest[1]
+ mov ah,GetCurrentDir
+ call DOS3CALL
+ jc GCDExit ; Skip if error
+ xor ax,ax ; Return FALSE if no error
+GCDExit:
+ pop ds ; Restore DS
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetCurrentDirectory() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc SetCurrentDirectory, <FAR, PUBLIC>, <DS, DI>
+
+ParmD lpDirName
+
+cBegin
+ lds di,lpDirName ; DS:DI = lpDirName
+
+ ; Is there a drive designator?
+ifdef DBCS
+ mov al, byte ptr [di] ; fetch a first byte of path
+ xor ah,ah
+ cCall IsDBCSLeadByte, <ax>
+ test ax,ax ; DBCS lead byte?
+ jnz SCDNoDrive ; jump if so
+endif
+ cmp byte ptr [di+1],':'
+ jne SCDNoDrive ; Nope, continue
+ mov al,byte ptr [di] ; Yup, change to that drive
+ sub ah,ah
+ and al, 0DFH ;Make drive letter upper case
+ sub al,'A'
+ push ax
+ call SetCurrentDrive
+ inc di ; Move past the drive letter
+ inc di ; and colon
+
+ ; Are we at the end of the string?
+ mov al,byte ptr [di] ; Are we at the end of the string?
+ cbw
+ or ax,ax
+ jz SCDExit ; Yup, exit
+SCDNoDrive:
+ mov dx,di
+ mov ah,ChangeCurrentDir
+ call DOS3CALL
+ jc SCDExit ; Skip on error
+ xor ax,ax ; Return FALSE if successful
+SCDExit:
+cEnd
+
+
+if 0
+;*--------------------------------------------------------------------------*
+;* *
+;* IsRemovableDrive() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc IsRemovableDrive, <FAR, PUBLIC>
+
+ParmW wDrive
+
+cBegin
+ mov ax,4408h ; IOCTL: Check If Block Device Is Removable
+ mov bx,wDrive
+ inc bx
+ call DOS3CALL
+ and ax,1 ; Only test bit 0
+ xor ax,1 ; Flip so 1 == Removable
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* IsRemoteDrive() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc IsRemoteDrive, <FAR, PUBLIC>
+
+ParmW wDrive
+
+cBegin
+ mov ax,4409h ; IOCTL: Check If Block Device Is Remote
+ mov bx,wDrive
+ inc bx
+ call DOS3CALL
+ xor ax,ax
+ and dx,0001000000000000b ; Test bit 12
+ jz IRDRet
+ mov ax,1
+IRDRet:
+cEnd
+endif
+
+;*--------------------------------------------------------------------------*
+;* *
+;* DosDelete() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+%out assuming SS==DS
+
+cProc DosDelete, <FAR, PUBLIC>
+
+ParmD lpSource
+
+localV szOEM, 128
+
+cBegin
+
+ RegPtr lpszOEM,ss,bx ; convert path to OEM chars
+ lea bx, szOEM
+ cCall AnsiToOem, <lpSource, lpszOEM>
+
+ lea dx, szOEM
+ mov ah,DeleteFile ;
+ call DOS3CALL
+ jc DDExit
+ xor ax,ax ; Return 0 if successful
+DDExit:
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* DosRename() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc DosRename, <FAR, PUBLIC>, <DI>
+
+ParmD lpSource
+ParmD lpDest
+
+localV szOEM1, 128
+localV szOEM2, 128
+
+cBegin
+ RegPtr lpszOEM1, ss, bx
+ lea bx, szOEM1
+ cCall AnsiToOem, <lpSource, lpszOEM1>
+
+ RegPtr lpszOEM2, ss, bx
+ lea bx, szOEM2
+ cCall AnsiToOem, <lpDest, lpszOEM2>
+
+ lea dx, szOEM1
+ lea di, szOEM2
+ push ss
+ pop es
+ mov ah,RenameFile
+ call DOS3CALL
+ jc DRExit
+ xor ax,ax ; Return 0 if successful
+DRExit:
+cEnd
+
+; lmemmove() -
+;
+; Shamelessly heisted from the C5.1 runtime library, and modified to
+; work in mixed model Windows programs!
+;
+;***
+;memcpy.asm - contains memcpy and memmove routines
+;
+; Copyright (c) 1986-1988, Microsoft Corporation. All right reserved.
+;
+;Purpose:
+; memmove() copies a source memory buffer to a destination memory buffer.
+; This routine recognize overlapping buffers to avoid propogation.
+;
+; Algorithm:
+;
+; void * memmove(void * dst, void * src, size_t count)
+; {
+; void * ret = dst;
+;
+; if (dst <= src || dst >= (src + count)) {
+; /*
+; * Non-Overlapping Buffers
+; * copy from lower addresses to higher addresses
+; */
+; while (count--)
+; *dst++ = *src++;
+; }
+; else {
+; /*
+; * Overlapping Buffers
+; * copy from higher addresses to lower addresses
+; */
+; dst += count - 1;
+; src += count - 1;
+;
+; while (count--)
+; *dst-- = *src--;
+; }
+;
+; return(ret);
+; }
+;
+;
+;Entry:
+; void *dst = pointer to destination buffer
+; const void *src = pointer to source buffer
+; size_t count = number of bytes to copy
+;
+;Exit:
+; Returns a pointer to the destination buffer in DX:AX
+;
+;Uses:
+; CX,DX,ES
+;
+;Exceptions:
+;*******************************************************************************
+
+cProc lmemmove,<FAR,PUBLIC>,<si,di>
+
+ parmD dst ; destination pointer
+ parmD src ; source pointer
+ parmW count ; number of bytes to copy
+
+cBegin
+ push ds ; Preserve DS
+ lds si,src ; DS:SI = src
+ les di,dst ; ES:DI = dst
+
+ mov ax,di ; save dst in AX for return value
+ mov cx,count ; cx = number of bytes to move
+ jcxz done ; if cx = 0 Then nothing to copy
+
+;
+; Check for overlapping buffers:
+; If segments are different, assume no overlap
+; Do normal (Upwards) Copy
+; Else If (dst <= src) Or (dst >= src + Count) Then
+; Do normal (Upwards) Copy
+; Else
+; Do Downwards Copy to avoid propogation
+;
+ mov ax,es ; compare the segments
+ cmp ax,word ptr (src+2)
+ jne CopyUp
+ cmp di,si ; src <= dst ?
+ jbe CopyUp
+
+ mov ax,si
+ add ax,cx
+ cmp di,ax ; dst >= (src + count) ?
+ jae CopyUp
+;
+; Copy Down to avoid propogation in overlapping buffers
+;
+ mov ax,di ; AX = return value (offset part)
+
+ add si,cx
+ add di,cx
+ dec si ; DS:SI = src + count - 1
+ dec di ; ES:DI = dst + count - 1
+ std ; Set Direction Flag = Down
+ rep movsb
+ cld ; Set Direction Flag = Up
+ jmp short done
+
+CopyUp:
+ mov ax,di ; AX = return value (offset part)
+;
+; There are 4 situations as far as word alignment of "src" and "dst":
+; 1. src and dst are both even (best case)
+; 2. src is even and dst is odd
+; 3. src is odd and dst is even
+; 4. src and dst are both odd (worst case)
+;
+; Case #4 is much faster if a single byte is copied before the
+; REP MOVSW instruction. Cases #2 and #3 are effectively unaffected
+; by such an operation. To maximum the speed of this operation,
+; only DST is checked for alignment. For cases #2 and #4, the first
+; byte will be copied before the REP MOVSW.
+;
+ test al,1 ; fast check for dst being odd address
+ jz move
+
+ movsb ; move a byte to improve alignment
+ dec cx
+;
+; Now the bulk of the copy is done using REP MOVSW. This is much
+; faster than a REP MOVSB if the src and dst addresses are both
+; word aligned and the processor has a 16-bit bus. Depending on
+; the initial alignment and the size of the region moved, there
+; may be an extra byte left over to be moved. This is handled
+; by the REP MOVSB, which moves either 0 or 1 bytes.
+;
+move:
+ shr cx,1 ; Shift CX for count of words
+ rep movsw ; CF set if one byte left over
+ adc cx,cx ; CX = 1 or 0, depending on Carry Flag
+ rep movsb ; possible final byte
+;
+; Return the "dst" address in AX/DX:AX
+;
+done:
+ pop ds ;restore ds
+ mov dx,es ;segment part of dest address
+
+cEnd
+
+sEnd %SEGNAME
+
+end
diff --git a/private/mvdm/wow16/test/shell/wowexec.c b/private/mvdm/wow16/test/shell/wowexec.c
new file mode 100644
index 000000000..583244012
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexec.c
@@ -0,0 +1,1360 @@
+/****************************** Module Header ******************************\
+* Module Name: wowexec.c
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* WOWEXEC - 16 Bit Server Task - Does Exec Calls on Behalf of 32 bit CreateProcess
+*
+*
+* History:
+* 05-21-91 MattFe Ported to Windows
+* mar-20-92 MattFe Added Error Message Boxes (from win 3.1 progman)
+* apr-1-92 mattfe added commandline exec and switch to path (from win 3.1 progman)
+* jun-1-92 mattfe changed wowgetnextvdmcommand
+* 12-Nov-93 DaveHart Multiple WOW support and remove captive
+* GetNextVDMCommand thread from WOW32.
+* 16-Nov-93 DaveHart Reduce data segment size.
+\***************************************************************************/
+#include "wowexec.h"
+#include "wowinfo.h"
+#include "shellapi.h"
+#ifndef PULONG
+#define PULONG
+#endif
+#include "vint.h"
+#include "dde.h"
+
+
+/*
+ * External Prototypes
+ */
+extern WORD FAR PASCAL WOWQueryDebug( void );
+extern WORD FAR PASCAL WowWaitForMsgAndEvent( HWND);
+extern void FAR PASCAL WowMsgBox(LPSTR szMsg, LPSTR szTitle, DWORD dwOptionalStyle);
+extern DWORD FAR PASCAL WowPartyByNumber(DWORD dw, LPSTR psz);
+extern DWORD FAR PASCAL WowKillTask(WORD htask);
+HWND FaxInit(HINSTANCE hInst);
+
+/*
+ * Global Variables
+ */
+HANDLE hAppInstance;
+HWND ghwndMain = NULL;
+HWND ghwndEdit = NULL;
+char szOOMExitTitle[32+1];
+char szOOMExitMsg[64+1];
+char szAppTitleBuffer[32];
+LPSTR lpszAppTitle = szAppTitleBuffer;
+char szWindowsDirectory[MAXITEMPATHLEN+1];
+char szOriginalDirectory[MAXITEMPATHLEN+1];
+BOOL gfSharedWOW = FALSE;
+WORD gwFirstCmdShow;
+
+
+
+/*
+ * Forward declarations.
+ */
+BOOL InitializeApp(LPSTR lpszCommandLine);
+LONG FAR PASCAL WndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam);
+WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo);
+BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo);
+void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz);
+PSTR FAR PASCAL GetFilenameFromPath( PSTR szPath );
+void NEAR PASCAL GetPathInfo ( PSTR szPath, PSTR *pszFileName, PSTR *pszExt, WORD *pich, BOOL *pfUnc);
+BOOL NEAR PASCAL StartRequestedApp(VOID);
+#ifdef DEBUG
+BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam);
+#endif
+
+#ifndef DBCS
+#define AnsiNext(x) ((x)+1)
+#define AnsiPrev(y,x) ((x)-1)
+#define IsDBCSLeadByte(x) (FALSE)
+#endif
+
+typedef struct PARAMETERBLOCK {
+ WORD wEnvSeg;
+ LPSTR lpCmdLine;
+ LPVOID lpCmdShow;
+ DWORD dwReserved;
+} PARAMETERBLOCK, *PPARAMETERBLOCK;
+
+typedef struct CMDSHOW {
+ WORD two;
+ WORD nCmdShow;
+} CMDSHOW, *PCMDSHOW;
+
+#define CCHMAX 256+13 // MAX_PATH plus 8.3 plus NULL
+
+#define ERROR_ERROR 0
+#define ERROR_FILENOTFOUND 2
+#define ERROR_PATHNOTFOUND 3
+#define ERROR_MANYOPEN 4
+#define ERROR_DYNLINKSHARE 5
+#define ERROR_LIBTASKDATA 6
+#define ERROR_MEMORY 8
+#define ERROR_VERSION 10
+#define ERROR_BADEXE 11
+#define ERROR_OTHEREXE 12
+#define ERROR_DOS4EXE 13
+#define ERROR_UNKNOWNEXE 14
+#define ERROR_RMEXE 15
+#define ERROR_MULTDATAINST 16
+#define ERROR_PMODEONLY 18
+#define ERROR_COMPRESSED 19
+#define ERROR_DYNLINKBAD 20
+#define ERROR_WIN32 21
+
+
+/* FindPrevInstanceProc -
+ * A silly little enumproc to find any window (EnumWindows) which has a
+ * matching EXE file path. The desired match EXE pathname is pointed to
+ * by the lParam. The found window's handle is stored in the
+ * first word of this buffer.
+ */
+
+BOOL CALLBACK FindPrevInstanceProc(HWND hWnd, LPSTR lpszParam)
+{
+ char szT[260];
+ HANDLE hInstance;
+
+ // Filter out invisible and disabled windows
+ //
+
+ if (!IsWindowEnabled(hWnd) || !IsWindowVisible(hWnd))
+ return TRUE;
+
+ hInstance = GetWindowWord(hWnd, GWW_HINSTANCE);
+ GetModuleFileName(hInstance, szT, sizeof (szT)-1);
+
+ // Make sure that the hWnd belongs to the current VDM process
+ //
+ // GetWindowTask returns the wowexec htask16 if the window belongs
+ // to a different process - thus we filter out windows in
+ // 'separate VDM' processes.
+ // - nanduri
+
+ if (lstrcmpi(szT, lpszParam) == 0 &&
+ GetWindowTask(hWnd) != GetWindowTask(ghwndMain)) {
+ *(LPHANDLE)lpszParam = hWnd;
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+HWND near pascal FindPopupFromExe(LPSTR lpExe)
+{
+ HWND hwnd = (HWND)0;
+ BOOL b;
+
+ b = EnumWindows(FindPrevInstanceProc, (LONG)(LPSTR)lpExe);
+ if (!b && (hwnd = *(LPHANDLE)(LPSTR)lpExe)) {
+ // Find a "main" window that is the ancestor of a given window
+ //
+
+ HWND hwndT;
+
+ // First go up the parent chain to find the popup window. Then go
+ // up the owner chain to find the main window
+ //
+
+ while (hwndT = GetParent(hwnd))
+ hwnd = hwndT;
+
+ while (hwndT = GetWindow(hwnd, GW_OWNER))
+ hwnd = hwndT;
+ }
+
+ return hwnd;
+}
+
+WORD ActivatePrevInstance(LPSTR lpszPath)
+{
+ HWND hwnd;
+ HINSTANCE ret = IDS_MULTIPLEDSMSG;
+
+ if (hwnd = FindPopupFromExe(lpszPath)) {
+ if (IsIconic(hwnd)) {
+ ShowWindow(hwnd,SW_SHOWNORMAL);
+ }
+ else {
+ HWND hwndT = GetLastActivePopup(hwnd);
+ BringWindowToTop(hwnd);
+ if (hwndT && hwnd != hwndT)
+ BringWindowToTop(hwndT);
+ }
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* ExecProgram() - */
+/* */
+/* Taken from Win 3.1 Progman -maf */
+/*--------------------------------------------------------------------------*/
+
+/* Returns 0 for success. Otherwise returns a IDS_ string code. */
+
+WORD NEAR PASCAL ExecProgram(PWOWINFO pWowInfo)
+{
+ WORD ret;
+ PARAMETERBLOCK ParmBlock;
+ CMDSHOW CmdShow;
+ char CmdLine[CCHMAX];
+
+ ret = 0;
+
+ // Don't mess with the mouse state; unless we're on a mouseless system.
+ if (!GetSystemMetrics(SM_MOUSEPRESENT))
+ ShowCursor(TRUE);
+
+ //
+ // prepare the dos style cmd line (counted pascal string)
+ // pWowInfo->lpCmdLine contains the command tail (excluding argv[0])
+ //
+ CmdLine[0] = lstrlen(pWowInfo->lpCmdLine) - 2;
+ lstrcpy( &CmdLine[1], pWowInfo->lpCmdLine);
+
+ // We have a WOWINFO structure, then use it to pass the correct environment
+
+ ParmBlock.wEnvSeg = HIWORD(pWowInfo->lpEnv);
+ ParmBlock.lpCmdLine = CmdLine;
+ ParmBlock.lpCmdShow = &CmdShow;
+ CmdShow.two = 2;
+ CmdShow.nCmdShow = pWowInfo->wShowWindow;
+
+ ParmBlock.dwReserved = NULL;
+
+ ret = LoadModule(pWowInfo->lpAppName,(LPVOID)&ParmBlock) ;
+
+ switch (ret)
+ {
+ case ERROR_ERROR:
+ case ERROR_MEMORY:
+ ret = IDS_NOMEMORYMSG;
+ break;
+
+ case ERROR_FILENOTFOUND:
+ ret = IDS_FILENOTFOUNDMSG;
+ break;
+
+ case ERROR_PATHNOTFOUND:
+ ret = IDS_BADPATHMSG;
+ break;
+
+ case ERROR_MANYOPEN:
+ ret = IDS_MANYOPENFILESMSG;
+ break;
+
+ case ERROR_DYNLINKSHARE:
+ ret = IDS_ACCESSDENIED;
+ break;
+
+ case ERROR_VERSION:
+ ret = IDS_NEWWINDOWSMSG;
+ break;
+
+ case ERROR_RMEXE:
+ /* KERNEL has already put up a messagebox for this one. */
+ ret = 0;
+ break;
+
+ case ERROR_MULTDATAINST:
+ ret = ActivatePrevInstance(pWowInfo->lpAppName);
+ break;
+
+ case ERROR_COMPRESSED:
+ ret = IDS_COMPRESSEDEXE;
+ break;
+
+ case ERROR_DYNLINKBAD:
+ ret = IDS_INVALIDDLL;
+ break;
+
+ case SE_ERR_SHARE:
+ ret = IDS_SHAREERROR;
+ break;
+
+ case ERROR_WIN32:
+ ret = IDS_CANTLOADWIN32DLL;
+ break;
+
+ //
+ // We shouldn't get any of the following errors,
+ // so the strings have been removed from the resource
+ // file. That's why there's the OutputDebugString
+ // on checked builds only.
+ //
+
+#ifdef DEBUG
+ case ERROR_OTHEREXE:
+ case ERROR_PMODEONLY:
+ case SE_ERR_ASSOCINCOMPLETE:
+ case SE_ERR_DDETIMEOUT:
+ case SE_ERR_DDEFAIL:
+ case SE_ERR_DDEBUSY:
+ case SE_ERR_NOASSOC:
+ {
+ char szTmp[64];
+ wsprintf(szTmp, "WOWEXEC: Unexpected error %d executing app, fix that code!\n", (int)ret);
+ OutputDebugString(szTmp);
+ }
+ //
+ // fall through to default case, so the execution
+ // is the same as on the free build.
+ //
+#endif
+
+ default:
+ if (ret < 32)
+ goto EPExit;
+ ret = 0;
+ }
+
+EPExit:
+
+ if (!GetSystemMetrics(SM_MOUSEPRESENT)) {
+ /*
+ * We want to turn the mouse off here on mouseless systems, but
+ * the mouse will already have been turned off by USER if the
+ * app has GP'd so make sure everything's kosher.
+ */
+ if (ShowCursor(FALSE) != -1)
+ ShowCursor(TRUE);
+ }
+
+ return(ret);
+}
+
+/***************************************************************************\
+* ExecApplication
+*
+* Code Taken From Win 3.1 ExecItem()
+*
+\***************************************************************************/
+
+#define TDB_PDB_OFFSET 0x60
+#define PDB_ENV_OFFSET 0x2C
+
+BOOL NEAR PASCAL ExecApplication(PWOWINFO pWowInfo)
+{
+
+ WORD ret;
+ LPSTR szEnv;
+ LPSTR szEnd;
+ BYTE bDrive;
+ WORD wSegEnvSave;
+ HANDLE hTask;
+ LPSTR lpTask;
+ HANDLE hPDB;
+ LPSTR lpPDB;
+ HANDLE hNewEnv;
+
+ int nLength;
+ int nNewEnvLength;
+ LPSTR lpstrEnv;
+ LPSTR lpstr;
+ LPSTR lpOriginalEnv;
+ BOOL bBlanks;
+ LPSTR szEnvTmp;
+
+
+ if (!pWowInfo) {
+ return FALSE;
+ }
+
+ //
+ // Seup the environment from WOWINFO record from getvdmcommand
+ //
+
+
+ // Figure out who we are (so we can edit our PDB/PSP)
+
+ hTask = GetCurrentTask();
+ lpTask = GlobalLock( hTask );
+ if ( lpTask == NULL ) {
+ ret = IDS_NOMEMORYMSG;
+ goto punt;
+ }
+
+ hPDB = *((LPWORD)(lpTask + TDB_PDB_OFFSET));
+ lpPDB = GlobalLock( hPDB );
+
+ // Save our environment block
+ wSegEnvSave = *((LPWORD)(lpPDB + PDB_ENV_OFFSET));
+
+
+ // Now determine the length of the original env
+
+ lpOriginalEnv = (LPSTR)MAKELONG(0,wSegEnvSave);
+
+ do {
+ nLength = lstrlen(lpOriginalEnv);
+ lpOriginalEnv += nLength + 1;
+ } while ( nLength != 0 );
+
+ lpOriginalEnv += 2; // Skip over magic word, see comment below
+
+ nNewEnvLength = 4 + lstrlen(lpOriginalEnv); // See magic comments below!
+
+ // WOW Apps cannot deal with an invalid TEMP=c:\bugusdir directory
+ // Usually on Win 3.1 the TEMP= is checked in ldboot.asm check_temp
+ // routine. However on NT since we get a new environment with each
+ // WOW app it means that we have to check it here. If it is not
+ // valid then it is edited in the environment.
+ // - mattfe june 11 93
+
+ szEnv = pWowInfo->lpEnv;
+ szEnd = szEnv + pWowInfo->EnvSize;
+ szEnd--;
+
+ while ( szEnv < szEnd ) {
+
+ nLength = lstrlen(szEnv) + 1;
+
+ if ( (*szEnv == 'T') &&
+ (*(szEnv+1) == 'E') &&
+ (*(szEnv+2) == 'M') &&
+ (*(szEnv+3) == 'P') &&
+ (*(szEnv+4) == '=') ) {
+
+ // Try to set the current directory to the TEMP= dir
+ // If it fails then nuke the TEMP= part of the environment
+ // in the same way check_TEMP does in ldboot.asm
+ // We also scan for blanks, just like check_TEMP
+
+ bBlanks = FALSE;
+ szEnvTmp = szEnv+5;
+ while (*szEnvTmp != 0) {
+ if (*szEnvTmp == ' ') {
+ bBlanks = TRUE;
+ break;
+ }
+ szEnvTmp++;
+ }
+
+ if (bBlanks || (SetCurrentDirectory(szEnv+5) )) {
+ while (*szEnv != 0) {
+ *szEnv = 'x';
+ szEnv++;
+ }
+ }
+ break;
+ }
+ szEnv += nLength;
+ }
+
+ // WOW Apps only have a Single Current Directory
+ // Find =d:=D:\path where d is the active drive letter
+ // Note that the drive info doesn have to be at the start
+ // of the environment.
+
+ bDrive = pWowInfo->CurDrive + 'A';
+ szEnv = pWowInfo->lpEnv;
+ szEnd = szEnv + pWowInfo->EnvSize;
+ szEnd--;
+
+ while ( szEnv < szEnd ) {
+
+ nLength = lstrlen(szEnv) + 1;
+ if ( *szEnv == '=' ) {
+ if ( (bDrive == (*(szEnv+1) & 0xdf)) &&
+ (*(szEnv+2) == ':') && (*(szEnv+3) == '=') ) {
+ SetCurrentDirectory(szEnv+4);
+ }
+ } else {
+ nNewEnvLength += nLength;
+ }
+ szEnv += nLength;
+ }
+
+ // Now allocate and make a personal copy of the Env
+
+ hNewEnv = GlobalAlloc( GMEM_MOVEABLE, (DWORD)nNewEnvLength );
+ if ( hNewEnv == NULL ) {
+ ret = IDS_NOMEMORYMSG;
+ goto punt;
+ }
+ lpstrEnv = GlobalLock( hNewEnv );
+ if ( lpstrEnv == NULL ) {
+ GlobalFree( hNewEnv );
+ ret = IDS_NOMEMORYMSG;
+ goto punt;
+ }
+
+ // Copy only the non-current directory env variables
+
+ szEnv = pWowInfo->lpEnv;
+ lpstr = lpstrEnv;
+
+ while ( szEnv < szEnd ) {
+ nLength = lstrlen(szEnv) + 1;
+
+ // Copy everything except the drive letters
+
+ if ( *szEnv != '=' ) {
+ lstrcpy( lpstr, szEnv );
+ lpstr += nLength;
+ }
+ szEnv += nLength;
+ }
+ *lpstr++ = '\0'; // Extra '\0' on the end
+
+ // Magic environment goop!
+ //
+ // Windows only supports the passing of environment information
+ // using the LoadModule API. The WinExec API just causes
+ // the application to inherit the current DOS PDB's environment.
+ //
+ // Also, the environment block has a little gotcha at the end. Just
+ // after the double-nuls there is a magic WORD value 0x0001 (DOS 3.0
+ // and later). After the value is a nul terminated string indicating
+ // the applications executable file name (including PATH).
+ //
+ // We copy the value from WOWEXEC's original environment because
+ // that is what WinExec appears to do.
+ //
+ // -BobDay
+
+ *lpstr++ = '\1';
+ *lpstr++ = '\0'; // Magic 0x0001 from DOS
+
+ lstrcpy( lpstr, lpOriginalEnv ); // More Magic (see comment above)
+
+ // Temporarily update our environment block
+
+ *((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = (WORD)hNewEnv | 1;
+
+ pWowInfo->lpEnv = lpstrEnv;
+
+
+ //
+ // Set our current drive & directory as requested.
+ //
+
+ SetCurrentDirectory(pWowInfo->lpCurDir);
+
+ ret = ExecProgram(pWowInfo);
+
+ // Restore our environment block
+
+ *((LPWORD)(lpPDB + PDB_ENV_OFFSET)) = wSegEnvSave;
+
+ GlobalUnlock( hPDB );
+ GlobalUnlock( hTask );
+ GlobalUnlock( hNewEnv );
+ GlobalFree( hNewEnv );
+
+
+punt:
+
+ // Change back to the Windows Directory
+ // So that if we are execing from a NET Drive its
+ // Not kept Active
+
+ SetCurrentDirectory(szWindowsDirectory);
+
+ // Check for errors.
+ if (ret) {
+ MyMessageBox(IDS_EXECERRTITLE, ret, pWowInfo->lpAppName);
+ }
+
+ // Always call this when we are done try to start an app.
+ // It will do nothing if we were successful in starting an
+ // app, otherwise if we were unsucessful it will signal that
+ // the app has completed.
+ WowFailedExec();
+
+ return(ret);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* MyMessageBox() - */
+/* Taken From Win 3.1 Progman - maf */
+/*--------------------------------------------------------------------------*/
+
+void NEAR PASCAL MyMessageBox(WORD idTitle, WORD idMessage, LPSTR psz)
+{
+ char szTitle[MAXTITLELEN+1];
+ char szMessage[MAXMESSAGELEN+1];
+ char szTempField[MAXMESSAGELEN+1];
+
+
+ if (!LoadString(hAppInstance, idTitle, szTitle, sizeof(szTitle)))
+ goto MessageBoxOOM;
+
+ if (idMessage > IDS_LAST)
+ {
+ if (!LoadString(hAppInstance, IDS_UNKNOWNMSG, szTempField, sizeof(szTempField)))
+ goto MessageBoxOOM;
+ wsprintf(szMessage, szTempField, idMessage);
+ }
+ else
+ {
+ if (!LoadString(hAppInstance, idMessage, szTempField, sizeof(szTempField)))
+ goto MessageBoxOOM;
+
+ if (psz)
+ wsprintf(szMessage, szTempField, (LPSTR)psz);
+ else
+ lstrcpy(szMessage, szTempField);
+ }
+
+ WowMsgBox(szMessage, szTitle, MB_ICONEXCLAMATION);
+ return;
+
+
+MessageBoxOOM:
+ WowMsgBox(szOOMExitMsg, szOOMExitTitle, MB_ICONHAND);
+
+ return ;
+}
+
+
+
+/***************************************************************************\
+* main
+*
+*
+* History:
+* 04-13-91 ScottLu Created - from 32 bit exec app
+* 21-mar-92 mattfe significant alterations for WOW
+\***************************************************************************/
+
+int PASCAL WinMain(HANDLE hInstance,
+ HANDLE hPrevInstance, LPSTR lpszCmdLine, int iCmd)
+
+{
+ int i;
+ MSG msg;
+ LPSTR pch,pch1;
+ WORD ret;
+ WOWINFO wowinfo;
+ char aszWOWDEB[CCHMAX];
+ LPSTR pchWOWDEB;
+ HANDLE hMMDriver;
+
+
+ char szBuffer[150];
+ BOOL bFinished;
+ int iStart;
+ int iEnd;
+
+
+ hAppInstance = hInstance ;
+
+ // Only Want One WOWExec
+ if (hPrevInstance != NULL) {
+ return(FALSE);
+ }
+
+ if (!InitializeApp(lpszCmdLine)) {
+ OutputDebugString("WOWEXEC: InitializeApp failure!\n");
+ return 0;
+ }
+
+/*
+ * Look for a drivers= line in the [boot] section of SYSTEM.INI
+ * If present it is the 16 bit MultiMedia interface, so load it
+ */
+
+#ifdef OLD_MMSYSTEM_LOAD
+ if (GetPrivateProfileString((LPSTR)"boot", (LPSTR)"drivers",(LPSTR)"", aszMMDriver, sizeof(aszMMDriver), (LPSTR)"SYSTEM.INI")) {
+/*
+ * We have now discovered an app that rewrites the "drivers" entry with
+ * multiple drivers - so the existing load method fails. As a temporary fix
+ * while we decide what the "proper" fix is I will always load MMSYSTEM and
+ * ONLY MMSYSTEM.
+ *
+ * aszMMDriver[sizeof(aszMMDriver)-1] = '\0';
+ * hMMDriver = LoadLibrary((LPSTR)aszMMDriver);
+ * #ifdef DEBUG
+ * if (hMMDriver < 32) {
+ * OutputDebugString("WOWEXEC: Load of MultiMedia driver failed\n");
+ * }
+ * #endif
+ */
+ LoadLibrary("MMSYSTEM.DLL");
+ }
+#else
+ /* Load DDL's from DRIVERS section in system.ini
+ */
+ GetPrivateProfileString( (LPSTR)"boot", /* [Boot] section */
+ (LPSTR)"drivers", /* Drivers= */
+ (LPSTR)"", /* Default if no match */
+ szBuffer, /* Return buffer */
+ sizeof(szBuffer),
+ (LPSTR)"system.ini" );
+
+ if (!*szBuffer) {
+ goto Done;
+ }
+
+ bFinished = FALSE;
+ iStart = 0;
+
+ while (!bFinished) {
+ iEnd = iStart;
+
+ while (szBuffer[iEnd] && (szBuffer[iEnd] != ' ') &&
+ (szBuffer[iEnd] != ',')) {
+ iEnd++;
+ }
+
+ if (szBuffer[iEnd] == NULL) {
+ bFinished = TRUE;
+ }
+ else {
+ szBuffer[iEnd] = NULL;
+ }
+
+ /* Load and enable the driver.
+ */
+ OpenDriver( &(szBuffer[iStart]), NULL, NULL );
+ iStart = iEnd + 1;
+ }
+
+Done:
+
+#endif
+
+/*
+ * Look for a debug= line in the [boot] section of SYSTEM.INI
+ * If present it is the 16 bit MultiMedia interface, so load it
+ */
+
+ if ( WOWQueryDebug() & 0x0001 ) {
+ pchWOWDEB = "WOWDEB.EXE";
+ } else {
+ pchWOWDEB = "";
+ }
+
+ GetPrivateProfileString((LPSTR)"boot", (LPSTR)"debug",pchWOWDEB, aszWOWDEB, sizeof(aszWOWDEB), (LPSTR)"SYSTEM.INI");
+ aszWOWDEB[sizeof(aszWOWDEB)-1] = '\0';
+
+ if ( lstrlen(pchWOWDEB) != 0 ) {
+ WinExec((LPSTR)aszWOWDEB,SW_SHOW);
+ }
+
+#if 0
+/* Preload winspool.exe. Apps will keep loading and freeing it
+ * which is slow. We might as well load it now so the reference
+ * count is 1 so it will never be loaded or freed
+ */
+ //
+ // Disabled load of winspool.exe to save 8k. Size vs. speed,
+ // which one do we care about? Right now, size!
+ //
+ LoadLibrary("WINSPOOL.EXE");
+#endif
+
+ // Always load SHELL.DLL, FileMaker Pro and Lotus Install require it.
+
+ LoadLibrary("SHELL.DLL");
+
+ //
+ // Start any apps pending in basesrv queue
+ //
+
+ while (StartRequestedApp() && gfSharedWOW) {
+ /* null stmt */ ;
+ }
+
+
+ while (1) {
+ if (!WowWaitForMsgAndEvent(ghwndMain) &&
+ PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) &&
+ msg.message != WM_WOWEXECHEARTBEAT )
+ {
+ if (msg.message != WM_QUIT) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+/***************************************************************************\
+* InitializeApp
+*
+* History:
+* 04-13-91 ScottLu Created.
+\***************************************************************************/
+
+BOOL InitializeApp(LPSTR lpszCommandLine)
+{
+ WNDCLASS wc;
+ int cyExecStart, cxExecStart;
+ USHORT TitleLen, cbCopy;
+ HWND hwndFax;
+
+
+ // Remove Real Mode Segment Address
+
+ wc.style = 0;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hAppInstance;
+ wc.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszClassName = "WOWExecClass";
+#ifdef DEBUG
+ wc.lpszMenuName = "MainMenu";
+#else
+ wc.lpszMenuName = NULL;
+#endif
+
+ if (!RegisterClass(&wc)) {
+ OutputDebugString("WOWEXEC: RegisterClass failed\n");
+ return FALSE;
+ }
+
+ /*
+ * Guess size for now.
+ */
+ cyExecStart = GetSystemMetrics(SM_CYMENU) * 6;
+ cxExecStart = GetSystemMetrics(SM_CXSCREEN) / 2;
+
+ /* Load these strings now. If we need them later, we won't be able to load
+ * them at that time.
+ */
+ LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, sizeof(szOOMExitTitle));
+ LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, sizeof(szOOMExitMsg));
+ LoadString(hAppInstance, IDS_APPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
+
+ ghwndMain = CreateWindow("WOWExecClass", lpszAppTitle,
+ WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |
+ WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |
+ WS_SYSMENU,
+ 30, 30, cxExecStart, cyExecStart,
+ NULL, NULL, hAppInstance, NULL);
+
+ if (ghwndMain == NULL ) {
+#ifdef DEBUG
+ OutputDebugString("WOWEXEC: ghwndMain Null\n");
+#endif
+ return FALSE;
+ }
+
+ hwndFax = FaxInit(hAppInstance);
+
+ //
+ // Give our window handle to BaseSrv, which will post WM_WOWEXECSTARTAPP
+ // messages when we have commands to pick up. The return value tells
+ // us if we are the shared WOW VDM or not (a seperate WOW VDM).
+ // We also pick up the ShowWindow parameter (SW_SHOW, SW_MINIMIZED, etc)
+ // for the first WOW app here. Subsequent ones we get from BaseSrv.
+ //
+
+ //
+ // gwFirstCmdShow is no longer used, and is available.
+ //
+
+ gfSharedWOW = WOWRegisterShellWindowHandle(ghwndMain,
+ &gwFirstCmdShow,
+ hwndFax
+ );
+
+
+
+ //
+ // If this isn't the shared WOW, tell the kernel to exit when the
+ // last app (except WowExec) exits.
+ //
+
+ if (!gfSharedWOW) {
+ WowSetExitOnLastApp(TRUE);
+ }
+
+ /* Remember the original directory. */
+ GetCurrentDirectory(NULL, szOriginalDirectory);
+ GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
+
+#ifdef DEBUG
+
+ ShowWindow(ghwndMain, SW_MINIMIZE);
+
+ //
+ // If this is the shared WOW, change the app title string to
+ // reflect this and change the window title.
+ //
+
+ if (gfSharedWOW) {
+
+ LoadString(hAppInstance, IDS_SHAREDAPPTITLE, szAppTitleBuffer, sizeof(szAppTitleBuffer));
+
+ }
+
+ SetWindowText(ghwndMain, lpszAppTitle);
+ UpdateWindow(ghwndMain);
+
+#endif
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+* WndProc
+*
+* History:
+* 04-07-91 DarrinM Created.
+\***************************************************************************/
+
+LONG FAR PASCAL WndProc(
+ HWND hwnd,
+ WORD message,
+ WORD wParam,
+ LONG lParam)
+{
+ char chbuf[50];
+ HICON hIcon;
+
+ switch (message) {
+ case WM_CREATE:
+ break;
+
+ case WM_DESTROY:
+ // ignore since wowexec must stay around
+ return 0;
+
+#ifdef DEBUG
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case MM_ABOUT:
+ LoadString(hAppInstance, errTitle, (LPSTR)chbuf, sizeof(chbuf));
+ hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(ID_WOWEXEC_ICON));
+ ShellAbout(ghwndMain, (LPSTR)chbuf, (LPSTR)lpszAppTitle, hIcon);
+ break;
+
+ case MM_BREAK:
+ _asm int 3
+ break;
+
+ case MM_FAULT:
+ _asm mov cs:0,ax
+ break;
+
+ case MM_EXIT:
+ ExitKernelThunk(0);
+ break;
+
+ case MM_WATSON:
+ WinExec("drwatson", SW_MINIMIZE );
+ break;
+
+ case MM_PARTY:
+ {
+ FARPROC lpPartyDialogProc;
+
+ lpPartyDialogProc = MakeProcInstance(PartyDialogProc, hAppInstance);
+
+ DialogBox(hAppInstance, MAKEINTRESOURCE(ID_PARTY_DIALOG),
+ hwnd, lpPartyDialogProc);
+
+ FreeProcInstance(lpPartyDialogProc);
+ }
+ break;
+
+ }
+ break;
+#endif
+
+ case WM_WOWEXECSTARTAPP: // WM_USER+0
+
+#ifdef DEBUG
+ OutputDebugString("WOWEXEC - got WM_WOWEXECSTARTAPP\n");
+#endif
+
+ //
+ // Either BaseSrv or Wow32 asked us to go looking for
+ // commands to run.
+ //
+
+ if (!gfSharedWOW) {
+
+ //
+ // We shouldn't get this message unless we are the shared
+ // WOW VDM!
+ //
+
+#ifdef DEBUG
+ OutputDebugString("WOWEXEC - separate WOW VDM got WM_WOWEXECSTARTAPP!\n");
+ _asm int 3;
+#endif
+ break;
+ }
+
+ //
+ // Start requested apps until there are no more to start.
+ // This handles the case where several Win16 apps are launched
+ // in a row, before BaseSrv has the window handle for WowExec.
+ //
+
+ while (StartRequestedApp()) {
+ /* Null stmt */ ;
+ }
+ break;
+
+#define WM_WOWEXEC_START_TASK (WM_USER+2)
+ case WM_WOWEXEC_START_TASK:
+ {
+ char sz[512];
+
+ sz[ GlobalGetAtomName(wParam, sz, sizeof sz) ] = 0;
+ GlobalDeleteAtom(wParam);
+ WinExec(sz, (WORD)lParam);
+ }
+
+ case WM_WOWEXECHEARTBEAT:
+ // Probably will never get here...
+ break;
+
+ case WM_TIMECHANGE:
+ *((DWORD *)(((DWORD)40 << 16) | FIXED_NTVDMSTATE_REL40))
+ |= VDM_TIMECHANGE;
+ break;
+
+ case WM_DDE_INITIATE:
+ {
+ // In win31, the Program Manager WindowProc calls peekmessage to filterout
+ // otherwindowcreated and otherwindowdestroyed messages (which are atoms in win31)
+ // whenever it receives WM_DDE_INITIATE message.
+ //
+ // This has a side effect - basically when peekmessage is called the app ie program
+ // manager effectively yields allowing scheduling of other apps.
+ //
+ // So we do the side effect thing (simulate win31 behaviour) -
+ //
+ // The bug: 20221, rumba as/400 can't connect the firsttime to sna server.
+ // Scenario: Rumbawsf execs snasrv and blocks on yield, snasrv execs wnap and blocks
+ // on yield. Eventually wnap yields and rumbawsf is scheduled which
+ // broadcasts a ddeinitiate message. When WOWEXEC receives this message
+ // it will peek for nonexistent msg, which allows snasrv to get scheduled
+
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0xFFFF, 0xFFFF, PM_REMOVE))
+ DispatchMessage(&msg);
+ }
+ break;
+
+
+
+ case WM_CLOSE:
+#ifdef DEBUG
+ ExitKernelThunk(0);
+#else
+ // ignore since wowexec must stay around
+ return 0;
+#endif // ! DEBUG
+
+
+ default:
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+
+ return 1;
+}
+
+BOOL FAR PASCAL PartyDialogProc(HWND hDlg, WORD msg, WORD wParam, LONG lParam)
+{
+#ifdef DEBUG
+ BOOL f;
+ DWORD dw;
+ char szBuf[255];
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+ SendDlgItemMessage(hDlg, IDD_PARTY_NUMBER, EM_LIMITTEXT, 5, 0L);
+ SendDlgItemMessage(hDlg, IDD_PARTY_STRING, EM_LIMITTEXT, sizeof(szBuf)-1, 0L);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case 0xdab /* IDCANCEL */:
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case 0xdad /* IDOK */:
+ dw = GetDlgItemInt(hDlg, IDD_PARTY_NUMBER, &f, FALSE);
+ GetDlgItemText(hDlg, IDD_PARTY_STRING, szBuf, sizeof(szBuf));
+ WowPartyByNumber(dw, szBuf);
+ EndDialog(hDlg, TRUE);
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+// Misc File Routines - taken from progman (pmdlg.c) mattfe apr-1 92
+
+//-------------------------------------------------------------------------
+PSTR FAR PASCAL GetFilenameFromPath
+ // Given a full path returns a ptr to the filename bit. Unless it's a UNC style
+ // path in which case
+ (
+ PSTR szPath
+ )
+ {
+ DWORD dummy;
+ PSTR pFileName;
+ BOOL fUNC;
+
+
+ GetPathInfo(szPath, &pFileName, (PSTR*) &dummy, (WORD*) &dummy,
+ &fUNC);
+
+ // If it's a UNC then the 'filename' part is the whole thing.
+ if (fUNC)
+ pFileName = szPath;
+
+ return pFileName;
+ }
+
+
+//-------------------------------------------------------------------------
+void NEAR PASCAL GetPathInfo
+ // Get pointers and an index to specific bits of a path.
+ // Stops scaning at first space.
+ (
+ // Uses:
+ PSTR szPath, // The path.
+
+ // Returns:
+ PSTR *pszFileName, // The start of the filename in the path.
+ PSTR *pszExt, // Extension part of path (starting with the dot).
+ WORD *pich, // Index (in DBCS characters) of filename part starting at 0.
+ BOOL *pfUnc // Contents set to true if it's a UNC style path.
+ )
+ {
+ char *pch; // Temp variable.
+ WORD ich = 0; // Temp.
+
+ *pszExt = NULL; // If no extension, return NULL.
+ *pszFileName = szPath; // If no seperate filename component, return path.
+ *pich = 0;
+ *pfUnc = FALSE; // Default to not UNC style.
+
+ // Check for UNC style paths.
+ if (*szPath == '\\' && *(szPath+1) == '\\')
+ *pfUnc = TRUE;
+
+ // Search forward to find the last backslash or colon in the path.
+ // While we're at it, look for the last dot.
+ for (pch = szPath; *pch; pch = AnsiNext(pch))
+ {
+ if (*pch == ' ')
+ {
+ // Found a space - stop here.
+ break;
+ }
+ if (*pch == '\\' || *pch == ':')
+ {
+ // Found it, record ptr to it and it's index.
+ *pszFileName = pch+1;
+ *pich = ich+1;
+ }
+ if (*pch == '.')
+ {
+ // Found a dot.
+ *pszExt = pch;
+ }
+ ich++;
+ }
+
+ // Check that the last dot is part of the last filename.
+ if (*pszExt < *pszFileName)
+ *pszExt = NULL;
+
+ }
+
+
+//-----------------------------------------------------------------------------
+// StartRequestedApp
+// Calls WIN32 Base GetNextVDMCommand
+// and then starts the application
+//
+//-----------------------------------------------------------------------------
+
+#define LargeEnvSize() 0x1000 // Size of a large env
+
+BOOL NEAR PASCAL StartRequestedApp(VOID)
+{
+ char achCmdLine[CCHMAX];
+ char achAppName[CCHMAX];
+#ifdef DEBUG
+ char achAppNamePlusCmdLine[sizeof(achCmdLine) + sizeof(achAppName)];
+ int iGetNextVdmCmdLoops = 0;
+#endif
+ char achCurDir[CCHMAX];
+ WOWINFO wowinfo;
+ BOOL b;
+ HANDLE hmemEnvironment;
+ USHORT usEnvSize;
+
+ achCmdLine[0] = '\0';
+ achAppName[0] = '\0';
+
+ // We start by assuming that the app will have an environment that will
+ // be less than a large environment size. If not then
+ // WowGetNextVdmCommand will fail and we will try again with the
+ // enviroment size needed for the app as returned from the failed
+ // WowGetNextVdmCommand call. If we detect that WowGetNextVdmCommand fails
+ // but that we have plenty of environment space then we know another
+ // problem has occured and we give up.
+
+ // We don't worry about wasting memory since the environment will be
+ // merged into another buffer and this buffer will be freed below.
+
+ wowinfo.EnvSize = LargeEnvSize();
+ hmemEnvironment = NULL;
+
+ do {
+ if (hmemEnvironment != NULL) {
+ GlobalUnlock(hmemEnvironment);
+ GlobalFree(hmemEnvironment);
+ }
+
+ // We need to allocate twice the space specified so that international
+ // character set conversions can be successful.
+ hmemEnvironment = GlobalAlloc(GMEM_MOVEABLE, 2*wowinfo.EnvSize);
+ if (hmemEnvironment == NULL) {
+#ifdef DEBUG
+ OutputDebugString("WOWEXEC - failed to allocate Environment Memory\n");
+#endif
+ MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, NULL);
+ return FALSE;
+ }
+
+ wowinfo.lpEnv = GlobalLock(hmemEnvironment);
+#ifdef DEBUG
+ if (wowinfo.lpEnv == NULL) {
+ OutputDebugString("WOWEXEC ASSERT - GlobalLock failed, fix this!\n");
+ _asm { int 3 };
+ }
+
+ if (2*wowinfo.EnvSize > GlobalSize(hmemEnvironment)) {
+ OutputDebugString("WOWEXEC ASSERT - alloced memory too small, fix this!\n");
+ _asm { int 3 };
+ }
+#endif
+ wowinfo.lpCmdLine = achCmdLine;
+ wowinfo.CmdLineSize = CCHMAX;
+ wowinfo.lpAppName = achAppName;
+ wowinfo.AppNameSize = CCHMAX;
+ wowinfo.CurDrive = 0;
+ wowinfo.lpCurDir = achCurDir;
+ wowinfo.CurDirSize = sizeof(achCurDir);
+ wowinfo.iTask = 0;
+
+ usEnvSize = wowinfo.EnvSize;
+
+#ifdef DEBUG
+ if (++iGetNextVdmCmdLoops == 4) {
+ OutputDebugString("WOWEXEC ASSERT - Too many calls to GetNextVdmCommand\n");
+ _asm { int 3 };
+ }
+#endif
+ } while (! (b = WowGetNextVdmCommand(&wowinfo)) &&
+ (wowinfo.EnvSize > usEnvSize));
+
+ if ( ! b ) {
+#ifdef DEBUG
+ OutputDebugString("WOWEXEC - GetNextVdmCommand failed.\n");
+#endif
+ MyMessageBox(IDS_EXECERRTITLE, IDS_NOMEMORYMSG, achCmdLine);
+ GlobalUnlock( hmemEnvironment );
+ GlobalFree( hmemEnvironment );
+ return FALSE;
+ }
+
+ //
+ // If CmdLineSize == 0, no more commands (wowexec was the command)
+ // see WK32WowGetNextVdm
+ //
+ if (! wowinfo.CmdLineSize) {
+ GlobalUnlock( hmemEnvironment );
+ GlobalFree( hmemEnvironment );
+ return FALSE;
+ }
+
+
+#ifdef DEBUG
+ lstrcpy(achAppNamePlusCmdLine, achAppName);
+ lstrcat(achAppNamePlusCmdLine, ":");
+ lstrcat(achAppNamePlusCmdLine, achCmdLine);
+ // Chop off trailing CRLF from command tail.
+ achAppNamePlusCmdLine[ lstrlen(achAppNamePlusCmdLine) - 2 ] = '\0';
+
+ OutputDebugString("WOWEXEC: CommandLine = <");
+ OutputDebugString(achAppNamePlusCmdLine);
+ OutputDebugString(">\n");
+
+ SetWindowText(ghwndMain, achAppNamePlusCmdLine);
+ UpdateWindow(ghwndMain);
+#endif
+
+ ExecApplication(&wowinfo);
+
+#ifdef DEBUG
+
+ if ( ! gfSharedWOW ) {
+
+ //
+ // If this is a separate WOW, we have just executed the one and only
+ // app we're going to spawn. Change our window title to
+ // Command Line - WOWExec so that it's easy to see which WOW this
+ // window is associated with. No need to worry about freeing
+ // this memory, since when we go away the VDM goes away and
+ // vice-versa.
+ //
+
+ lpszAppTitle = GlobalLock(
+ GlobalAlloc(GMEM_FIXED,
+ lstrlen(achAppNamePlusCmdLine) +
+ 3 + // for " - "
+ lstrlen(szAppTitleBuffer) +
+ 1 // for null terminator
+ ));
+
+ lstrcpy(lpszAppTitle, achAppNamePlusCmdLine);
+ lstrcat(lpszAppTitle, " - ");
+ lstrcat(lpszAppTitle, szAppTitleBuffer);
+ }
+
+
+ SetWindowText(ghwndMain, lpszAppTitle);
+ UpdateWindow(ghwndMain);
+#endif
+
+ GlobalUnlock(hmemEnvironment);
+ GlobalFree(hmemEnvironment);
+
+ return TRUE; // We ran an app.
+}
+
+
diff --git a/private/mvdm/wow16/test/shell/wowexec.h b/private/mvdm/wow16/test/shell/wowexec.h
new file mode 100644
index 000000000..1abd4ec2a
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexec.h
@@ -0,0 +1,99 @@
+/****************************** Module Header ******************************\
+* Module Name: exec.h
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Niblet's header file
+*
+* History:
+* 04-13-91 ScottLu Stolen from niblet sources
+* 21-mar-92 mattfe added stuff form win3.1 progman
+\***************************************************************************/
+#include "windows.h"
+
+
+/*
+ * Resource defines
+ */
+#define WINDOWMENU 1
+#define ID_WOWEXEC_ICON 2
+#define ID_PARTY_DIALOG 3
+
+#ifdef RC_INVOKED
+#define ID(id) id
+#else
+#define ID(id) MAKEINTRESOURCE(id)
+#endif
+
+/*
+ * Menu ID's
+ */
+#define MM_BREAK 8001
+#define MM_ABOUT 8002
+#define MM_EXIT 8003
+#define MM_FAULT 8004
+#define MM_WATSON 8005
+#define MM_PARTY 8006
+
+/*
+ * Dialog control IDs
+ */
+#define IDD_PARTY_NUMBER 1
+#define IDD_PARTY_STRING 2
+#define IDD_PARTY_NUMLABEL 3
+#define IDD_PARTY_STRLABEL 4
+
+/* String Table Defines */
+#define errTitle 0
+#define IDS_BADPATHMSG3 1
+#define IDS_NOMEMORYMSG 2
+#define IDS_FILENOTFOUNDMSG 3
+#define IDS_MANYOPENFILESMSG 4
+#define IDS_NOASSOCMSG 5
+#define IDS_ASSOCINCOMPLETE 6
+#define IDS_MULTIPLEDSMSG 7
+#define IDS_OS2APPMSG 8
+#define IDS_NEWWINDOWSMSG 9
+#define IDS_PMODEONLYMSG 10
+#define IDS_ACCESSDENIED 11
+#define IDS_DDEFAIL 12
+#define IDS_COMPRESSEDEXE 13
+#define IDS_INVALIDDLL 14
+#define IDS_SHAREERROR 15
+#define IDS_BADPATHMSG 16
+#define IDS_OOMEXITTITLE 17
+#define IDS_OOMEXITMSG 18
+#define IDS_UNKNOWNMSG 19
+#define IDS_EXECERRTITLE 20
+#define IDS_BADPATHTITLE 21
+#define IDS_APPTITLE 22
+#define IDS_SHAREDAPPTITLE 23
+#define IDS_CANTLOADWIN32DLL 24
+
+#define IDS_LAST 24 // Put New Strings Before this one
+
+
+#ifdef JAPAN
+#define MAXTITLELEN 42 /* Length of MessageBox titles */
+#else
+#define MAXTITLELEN 50 /* Length of MessageBox titles */
+#endif
+#define MAXMESSAGELEN 256 /* Length of MessageBox messages */
+#define MAXITEMPATHLEN 64+16+48 /* Path + 8.3 + Drive(colon) + arguments */
+
+/* PMDOS.ASM */
+BOOL FAR PASCAL IsReadOnly(LPSTR);
+BOOL FAR PASCAL PathType(LPSTR);
+LONG FAR PASCAL GetDOSErrorCode( void );
+int FAR PASCAL GetCurrentDrive(void);
+int FAR PASCAL SetCurrentDrive(WORD);
+int FAR PASCAL GetCurrentDirectory(WORD, LPSTR);
+int FAR PASCAL SetCurrentDirectory(LPSTR);
+BOOL FAR PASCAL IsRemoteDrive(int);
+BOOL FAR PASCAL IsRemovableDrive(int);
+int FAR PASCAL DosDelete(LPSTR);
+int FAR PASCAL DosRename(LPSTR, LPSTR);
+LPSTR FAR PASCAL lmemmove(LPSTR, LPSTR, WORD);
+DWORD FAR PASCAL FileTime(HANDLE);
+
+typedef unsigned short USHORT;
diff --git a/private/mvdm/wow16/test/shell/wowexec.ico b/private/mvdm/wow16/test/shell/wowexec.ico
new file mode 100644
index 000000000..47a08c694
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexec.ico
Binary files differ
diff --git a/private/mvdm/wow16/test/shell/wowexec.rc b/private/mvdm/wow16/test/shell/wowexec.rc
new file mode 100644
index 000000000..fbd24e4ae
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexec.rc
@@ -0,0 +1,79 @@
+/****************************** Module Header ******************************\
+* Module Name: WOWEXEC.RC
+*
+* Copyright (c) 1991, Microsoft Corporation
+*
+* Resources
+*
+* History:
+* 04-07-91 MattFe Created.
+* 21-mar-92 mattfe added exec error strings from win 3.1 progman
+\***************************************************************************/
+
+#define OEMRESOURCE
+
+#include "windows.h"
+#include "wowexec.h"
+
+ID_WOWEXEC_ICON ICON wowexec.ico
+
+#ifdef DEBUG
+
+MainMenu MENU
+BEGIN
+ POPUP "&Debug"
+ BEGIN
+ MENUITEM "&Int 3", MM_BREAK
+ MENUITEM "E&xit WOW", MM_EXIT
+ MENUITEM "&GP Fault", MM_FAULT
+ MENUITEM "Dr. &Watson", MM_WATSON
+ MENUITEM "&Party By Number", MM_PARTY
+ MENUITEM SEPARATOR
+ MENUITEM "&About WOWExec...", MM_ABOUT
+ END
+END
+
+ID_PARTY_DIALOG DIALOG 47, 59, 231, 64
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "PartyByNumber"
+/* FONT 8, "MS Shell Dlg" */
+BEGIN
+ CONTROL "&Number:", IDD_PARTY_NUMLABEL, "Static", SS_LEFTNOWORDWRAP, 3, 19, 33, 10
+ EDITTEXT IDD_PARTY_NUMBER, 50, 18, 125, 12, ES_AUTOHSCROLL
+
+ CONTROL "&String:", IDD_PARTY_STRLABEL, "Static", SS_LEFTNOWORDWRAP, 3, 33, 33, 10
+ EDITTEXT IDD_PARTY_STRING, 50, 32, 125, 12, ES_AUTOHSCROLL
+
+ DEFPUSHBUTTON "OK", 0xdad /* IDOK */, 185, 6, 40, 14
+ PUSHBUTTON "Cancel", 0xdab /* IDCANCEL */, 185, 23, 40, 14
+
+END
+
+#endif // DEBUG
+
+
+/* 0....5....1....56...2....5....3.2..5....4....5....5....6...45....7....5....8....5....9....5....0....5....1....5....2....5..8 */
+
+STRINGTABLE PRELOAD
+BEGIN /* Maximum # of chars: */
+ errTitle "16-bit Windows Subsystem" /* 50 */
+ IDS_NOMEMORYMSG, "Insufficient memory to run this application. Quit one or more Windows applications and then try again." /* 256 */
+ IDS_FILENOTFOUNDMSG, "Cannot find file %s (or one of its components). Check to ensure the path and filename are correct and that all required libraries are available." /* 256 */
+ IDS_MANYOPENFILESMSG, "Too many other files are currently in use. Quit one or more applications, or increase the FILES command in CONFIG.SYS." /* 256 */
+ IDS_MULTIPLEDSMSG, "Cannot start more than one copy of the specified program." /* 256 */
+ IDS_NEWWINDOWSMSG, "This application is not supported by Microsoft Windows NT." /* 256 */
+ IDS_ACCESSDENIED, "Access to the specified device, path, or file is denied." /* 256 */
+ IDS_COMPRESSEDEXE, "This program or one of its components is compressed.\n\nUse the MS-DOS Expand command to copy the file from the Windows Setup disks."
+ IDS_INVALIDDLL, "One of the library files needed to run %s is damaged. Please reinstall this application." /* 256 */
+ IDS_SHAREERROR, "This file is in use by some other application." /* 256 */
+ IDS_BADPATHMSG, "The path %s is invalid." /* 256 */
+ IDS_OOMEXITTITLE, "WOWExec Extremely Low on Memory" /* 32 */
+ IDS_OOMEXITMSG, "Close an application and try again." /* 64 */
+ IDS_UNKNOWNMSG, "Unknown message ID: %d." /*256 */
+ IDS_EXECERRTITLE, "Can't run 16-bit Windows program" /* 50 */
+ IDS_APPTITLE, "WOWExec" /* 32 */
+ IDS_SHAREDAPPTITLE, "Shared WOWExec" /* 32 */
+ IDS_CANTLOADWIN32DLL "One of the library files needed to run %s cannot load in the 16-bit Windows sybsystem because it is a Win32 DLL."
+END
+
+#include "wowexec.rcv"
diff --git a/private/mvdm/wow16/test/shell/wowexec.rcv b/private/mvdm/wow16/test/shell/wowexec.rcv
new file mode 100644
index 000000000..08f0bc29f
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexec.rcv
@@ -0,0 +1,22 @@
+/********************************************************************/
+/* WOWEXEC.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows NT Win16 Application Launcher"
+#define VER_INTERNALNAME_STR "WOWEXEC"
+#define VER_ORIGINALFILENAME_STR "WOWEXEC.EXE"
+
+/* change product name from Windows to Windows NT */
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows NT(TM) Operating System\0"
+
+#undef VER_LEGALTRADEMARKS_STR
+#define VER_LEGALTRADEMARKS_STR \
+"Microsoft\256 is a registered trademark of Microsoft Corporation. Windows NT(TM) is a trademark of Microsoft Corporation.\0"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/test/shell/wowexfax.c b/private/mvdm/wow16/test/shell/wowexfax.c
new file mode 100644
index 000000000..f3c0856f2
--- /dev/null
+++ b/private/mvdm/wow16/test/shell/wowexfax.c
@@ -0,0 +1,321 @@
+//**************************************************************************
+// WOW fax support:
+// supports delrina winfax only
+// - nandurir created
+//**************************************************************************
+
+
+#define NOGDI
+#define PRINTDRIVER
+#define _WOWFAX16_
+#define DEFINE_DDRV_DEBUG_STRINGS
+#include "wowexec.h"
+#include "wowfax.h"
+
+#define WOWDRV_BITBLT MAKEINTRESOURCE(1)
+#define WOWDRV_CONTROL MAKEINTRESOURCE(3)
+#define WOWDRV_DISABLE MAKEINTRESOURCE(4)
+#define WOWDRV_ENABLE MAKEINTRESOURCE(5)
+#define WOWDRV_EXTDEVMODE MAKEINTRESOURCE(90)
+#define WOWDRV_DEVCAPS MAKEINTRESOURCE(91)
+
+//**************************************************************************
+// FaxWndProc
+//
+// NOTE: the definitions such as 'BITMAP' struct is different in this
+// file. This file is compiled with NOGDI option so that the
+// printer driver versions of the structure get defined
+// (in gdidefs.inc). However we donot use printer drivers version
+// of such structures, particularly BITMAP.
+//**************************************************************************
+
+LONG FAR PASCAL FaxWndProc(HWND hwnd, WORD message, WORD hdc,
+ LPWOWFAXINFO16 lpfaxinfo)
+{
+ LPPOINT lppt;
+ HANDLE hMem;
+ RECT rc;
+ HINSTANCE hInst;
+ WORD wSize;
+ LONG lRet = (LONG)lpfaxinfo;
+ WORD wRet;
+ char szDriverFileName[MAXITEMPATHLEN+1];
+
+#ifdef DEBUG
+ char szTmp[128];
+
+ if ((message >= WM_DDRV_FIRST) && (message <= WM_DDRV_LAST)) {
+ wsprintf(szTmp, "FaxWndProc, 0x%XH, %s, 0x%XH, 0x%lX\n", hwnd, (LPSTR) szWmDdrvDebugStrings[message - WM_DDRV_FIRST], hdc, lpfaxinfo);
+ OutputDebugString((LPSTR) szTmp);
+ }
+#endif
+
+ switch (message) {
+ default:
+ return DefWindowProc(hwnd, message, hdc, (LPARAM)lpfaxinfo);
+ break;
+
+ case WM_DDRV_INITFAXINFO16:
+ // allocate and initialize lpfaxinfo
+
+ hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
+ sizeof(WOWFAXINFO16));
+ lpfaxinfo = (LPWOWFAXINFO16)GlobalLock(hMem);
+ if (lpfaxinfo) {
+ lpfaxinfo->hmem = hMem;
+ }
+
+ lRet = (LONG)lpfaxinfo;
+ break;
+
+ case WM_DDRV_ENABLE:
+ case WM_DDRV_LOAD:
+ // now load the drv - lpfaxinfo must have been initialized
+
+ if (lpfaxinfo == (LPWOWFAXINFO16)NULL)
+ break;
+
+ lstrcpy(szDriverFileName, lpfaxinfo->lpDriverName);
+ lstrcat(szDriverFileName, ".DRV");
+ hInst = lpfaxinfo->hInst = LoadLibrary(szDriverFileName);
+
+ if (hInst) {
+
+ // store necessary info
+ (FARPROC)lpfaxinfo->lpControl = GetProcAddress(hInst, WOWDRV_CONTROL);
+ (FARPROC)lpfaxinfo->lpDisable = GetProcAddress(hInst, WOWDRV_DISABLE);
+ (FARPROC)lpfaxinfo->lpEnable = GetProcAddress(hInst, WOWDRV_ENABLE);
+ (FARPROC)lpfaxinfo->lpBitblt = GetProcAddress(hInst, WOWDRV_BITBLT);
+ (FARPROC)lpfaxinfo->lpExtDMode = GetProcAddress(hInst, WOWDRV_EXTDEVMODE);
+ (FARPROC)lpfaxinfo->lpDevCaps = GetProcAddress(hInst, WOWDRV_DEVCAPS);
+
+ if (!lpfaxinfo->lpControl || !lpfaxinfo->lpDisable || !lpfaxinfo->lpEnable ||
+ !lpfaxinfo->lpBitblt || !lpfaxinfo->lpExtDMode || !lpfaxinfo->lpDevCaps) {
+
+#ifdef DEBUG
+ wsprintf(szTmp, "FaxWndProc, Failed GetProcAddress on: %s\n", szDriverFileName);
+ OutputDebugString((LPSTR) szTmp);
+#endif
+ lRet = 0;
+ }
+ }
+ else {
+#ifdef DEBUG
+ wsprintf(szTmp, "FaxWndProc, Failed load of: %s\n", szDriverFileName);
+ OutputDebugString((LPSTR) szTmp);
+#endif
+ lRet = 0;
+ }
+ if (message == WM_DDRV_LOAD || lRet == 0)
+ break;
+
+ // case WM_DDRV_ENABLE continues
+
+ if (lpfaxinfo) {
+ // win31 gdi calls 'enable' twice - first to get the gdiinfo struct and next to get
+ // pdevice struct
+ wRet = (*lpfaxinfo->lpEnable)(lpfaxinfo->lpOut, InquireInfo,
+ lpfaxinfo->szDeviceName, lpfaxinfo->lpPortName, lpfaxinfo->lpIn);
+#ifdef DEBUG
+ if (!wRet) {
+ wsprintf(szTmp, "FaxWndProc, Enable InquireInfo Failed: %s, %s\n", szDriverFileName, lpfaxinfo->lpPortName);
+ OutputDebugString((LPSTR) szTmp);
+ }
+#endif
+ hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
+ ((LPGDIINFO)lpfaxinfo->lpOut)->dpDEVICEsize);
+ lpfaxinfo->hmemdevice = hMem;
+ lpfaxinfo->lpDevice = GlobalLock(hMem);
+ if (!lpfaxinfo->lpDevice) {
+#ifdef DEBUG
+ wsprintf(szTmp, "FaxWndProc, GlobalAlloc Failed: 0x%lX\n", ((LPGDIINFO)lpfaxinfo->lpOut)->dpDEVICEsize);
+ OutputDebugString((LPSTR) szTmp);
+#endif
+ return(0);
+ }
+ wRet = (*lpfaxinfo->lpEnable)(lpfaxinfo->lpDevice, EnableDevice,
+ lpfaxinfo->szDeviceName, lpfaxinfo->lpPortName, lpfaxinfo->lpIn);
+#ifdef DEBUG
+ if (!wRet) {
+ wsprintf(szTmp, "FaxWndProc, Enable, EnableDevice Failed: %s, %s\n", szDriverFileName, lpfaxinfo->lpPortName);
+ OutputDebugString((LPSTR) szTmp);
+ }
+#endif
+ lppt = (LPPOINT)((LPSTR)lpfaxinfo->lpOut + sizeof(GDIINFO16));
+ lppt->x = lppt->y = 0;
+ wRet = (*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice, GETPRINTINGOFFSET, 0, lppt);
+#ifdef DEBUG
+ if (!wRet) {
+ OutputDebugString((LPSTR) "FaxWndProc, Control GETPRINTINGOFFSET Failed\n");
+ }
+#endif
+ lpfaxinfo->flState |= WFINFO16_ENABLED;
+ }
+ break;
+
+ case WM_DDRV_STARTDOC:
+ if (lpfaxinfo) {
+ lRet = (LONG)(*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice,
+ SETPRINTERDC, (LPSTR)&hdc, 0);
+ if (lRet) {
+ lRet = (LONG)(*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice,
+ STARTDOC, (LPSTR)"", 0);
+#ifdef DEBUG
+ if (lRet < 0) {
+ OutputDebugString((LPSTR) "FaxWndProc, Control STARTDOC Failed\n");
+ }
+#endif
+ }
+#ifdef DEBUG
+ else {
+ OutputDebugString((LPSTR) "FaxWndProc, Control SETPRINTERDC Failed\n");
+ }
+#endif
+ }
+ break;
+
+ case WM_DDRV_PRINTPAGE:
+ if (lpfaxinfo) {
+ for (;;) {
+ lRet = (LONG)(*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice,
+ NEXTBAND, NULL, (LPSTR)&rc);
+ if (lRet < 0) {
+#ifdef DEBUG
+ OutputDebugString((LPSTR) "FaxWndProc, Control NEXTBAND Failed\n");
+#endif
+ break;
+ }
+
+ if (rc.left || rc.top || rc.right || rc.bottom) {
+ wRet = (*lpfaxinfo->lpBitblt)(lpfaxinfo->lpDevice, rc.left, rc.top,
+ NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
+ SRCCOPY, NULL, NULL);
+#ifdef DEBUG
+ if (!wRet) {
+ OutputDebugString((LPSTR) "FaxWndProc, BitBlt Failed\n");
+ }
+#endif
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case WM_DDRV_ENDDOC:
+ if (lpfaxinfo) {
+ lRet = (LONG)(*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice, ENDDOC, 0, 0);
+#ifdef DEBUG
+ if (lRet <= 0) {
+ OutputDebugString((LPSTR) "FaxWndProc, Control ENDDOC Failed\n");
+ }
+#endif
+ }
+ break;
+
+ case WM_DDRV_ESCAPE:
+ if (lpfaxinfo) {
+ lRet = (LONG)(*lpfaxinfo->lpControl)(lpfaxinfo->lpDevice, lpfaxinfo->wCmd, 0, 0);
+#ifdef DEBUG
+ if (lRet <= 0) {
+ wsprintf(szTmp, "FaxWndProc, Escape %X Failed\n", lpfaxinfo->wCmd);
+ OutputDebugString((LPSTR) szTmp);
+ }
+#endif
+ }
+ break;
+
+ case WM_DDRV_DISABLE:
+ if (lpfaxinfo) {
+
+ if (lpfaxinfo->flState & WFINFO16_ENABLED) {
+ (*lpfaxinfo->lpDisable)(lpfaxinfo->lpDevice);
+ }
+
+ GlobalUnlock(lpfaxinfo->hmemdevice);
+ GlobalFree(lpfaxinfo->hmemdevice);
+ }
+
+ lRet = 0;
+
+ // fall through
+
+ case WM_DDRV_UNLOAD:
+
+ if (lpfaxinfo) {
+ if (lpfaxinfo->hInst) {
+ FreeLibrary(lpfaxinfo->hInst);
+ }
+ }
+
+ lRet = 0;
+
+ // fall through
+
+ case WM_DDRV_FREEFAXINFO16:
+
+ if (lpfaxinfo) {
+ GlobalUnlock(lpfaxinfo->hmem);
+ GlobalFree(lpfaxinfo->hmem);
+ lpfaxinfo = (LPWOWFAXINFO16)NULL;
+ }
+
+ lRet = 0;
+ break;
+
+ case WM_DDRV_EXTDMODE:
+ if (lpfaxinfo) {
+ lRet = (*lpfaxinfo->lpExtDMode)(lpfaxinfo->hwndui, lpfaxinfo->hInst,
+ lpfaxinfo->lpOut, lpfaxinfo->szDeviceName, lpfaxinfo->lpPortName,
+ lpfaxinfo->lpIn, 0, lpfaxinfo->wCmd);
+ }
+ break;
+
+ case WM_DDRV_DEVCAPS:
+ if (lpfaxinfo) {
+ lRet = (*lpfaxinfo->lpDevCaps)(lpfaxinfo->szDeviceName, lpfaxinfo->lpPortName,
+ lpfaxinfo->wCmd, lpfaxinfo->lpOut, 0);
+ }
+ break;
+
+ }
+
+ return lRet;
+}
+
+//**************************************************************************
+// FaxInit
+//
+//**************************************************************************
+
+
+HWND FaxInit(HINSTANCE hInst)
+{
+ WNDCLASS wc;
+
+ // Make sure we only allow one FaxWndProc to handle WowFax messages
+
+ if (FindWindow(WOWFAX_CLASS, NULL)) {
+ return((HWND)0);
+ }
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)FaxWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInst;
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = 0;
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = WOWFAX_CLASS;
+
+ if (!RegisterClass(&wc)) {
+ return (HWND)0;
+ }
+
+ return CreateWindow(wc.lpszClassName, "", WS_OVERLAPPEDWINDOW,
+ 0, 0, 0, 0, NULL, NULL, hInst, NULL);
+}
diff --git a/private/mvdm/wow16/timer/api.asm b/private/mvdm/wow16/timer/api.asm
new file mode 100644
index 000000000..d4c883f98
--- /dev/null
+++ b/private/mvdm/wow16/timer/api.asm
@@ -0,0 +1,288 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; API.ASM
+;
+; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
+;
+; Contains the routine tddMessage which communicates to either
+; the 386 timer API's of the 286 timer API's depending on the
+; WinFlags settings WF_WIN286,WF_WIN386.
+;
+;
+; Revision history:
+;
+; 2/12/90 First created by w-glenns
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+?DF=1
+PMODE=1
+
+.xlist
+include cmacros.inc
+include windows.inc
+include mmsystem.inc
+include mmddk.inc
+include timer.inc
+.list
+
+ .286p
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; External functions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+externFP Enable
+externFP Disable
+
+ifdef DEBUG
+externFP tddGetTickCount
+endif
+
+externFP tddSetTimerEvent
+externFP tddKillTimerEvent
+externFP tddGetSystemTime
+externFP tddGetDevCaps
+externFP tddBeginMinPeriod
+externFP tddEndMinPeriod
+
+;externFP vtdSetTimerEvent
+;externFP vtdKillTimerEvent
+;externFP vtdGetSystemTime
+;externFP vtdGetDevCaps
+;externFP vtdBeginMinPeriod
+;externFP vtdEndMinPeriod
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Local data segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+externA WinFlags
+
+sBegin Data
+
+ externW wEnabled
+
+ errnz <TDD_KILLTIMEREVENT-DRV_RESERVED>
+ errnz <TDD_SETTIMEREVENT-4-DRV_RESERVED>
+ errnz <TDD_GETSYSTEMTIME-8-DRV_RESERVED>
+ errnz <TDD_GETDEVCAPS-12-DRV_RESERVED>
+ errnz <TDD_BEGINMINPERIOD-16-DRV_RESERVED>
+ errnz <TDD_ENDMINPERIOD-20-DRV_RESERVED>
+
+ tblCall286 dd tddKillTimerEvent,tddSetTimerEvent,tddGetSystemTime,tddGetDevCaps,tddBeginMinPeriod, tddEndMinPeriod
+ tblCall386 dd tddKillTimerEvent,tddSetTimerEvent,tddGetSystemTime,tddGetDevCaps,tddBeginMinPeriod, tddEndMinPeriod
+; tblCall386 dd vtdKillTimerEvent,vtdSetTimerEvent,vtdGetSystemTime,vtdGetDevCaps,vtdBeginMinPeriod, vtdEndMinPeriod
+ tblCallLen equ ($-tblCall286)/2
+
+ifdef DEBUG
+ externD RModeIntCount
+ externD PModeIntCount
+endif
+
+sEnd Data
+
+sBegin CodeFixed
+ assumes cs,CodeFixed
+ assumes ds,Data
+ assumes es,nothing
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; @doc INTERNAL
+;
+; @api DWORD | DriverProc | Pass messages to functions that really do work
+;
+; @parm DWORD | nDevice | The id of the device to get the message.
+;
+; @parm WORD | msg | The message.
+;
+; @parm LONG | lParam1 | Parameter 1.
+;
+; @parm LONG | lParam2 | Parameter 2.
+;
+; @rdesc The return value depends on the message being sent.
+;
+; @comm Devices not supporting a message should return 0.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;
+; driver message handler table
+;
+; These two tables define which routine handles which driver message.
+;
+; NOTE WARNING: ProcTbl must IMMEDIATELY follow MsgTbl.
+;
+MsgTbl dw TDD_GETSYSTEMTIME
+ dw TDD_BEGINMINPERIOD
+ dw TDD_ENDMINPERIOD
+ dw TDD_KILLTIMEREVENT
+ dw TDD_SETTIMEREVENT
+ dw TDD_GETDEVCAPS
+
+ dw DRV_LOAD
+ dw DRV_OPEN
+ dw DRV_CLOSE
+ dw DRV_ENABLE
+ dw DRV_DISABLE
+ dw DRV_QUERYCONFIGURE
+ dw DRV_INSTALL
+ifdef DEBUG
+ dw TDD_GETTICK
+ dw TDD_GETRINTCOUNT
+ dw TDD_GETPINTCOUNT
+endif
+ dw -1
+
+MsgLen equ $-MsgTbl
+
+ProcTbl dw msg_TDD_GETSYSTEMTIME ; TDD_GETSYSTEMTIME
+ dw msg_TDD_BEGINMINPERIOD ; TDD_BEGINMINPERIOD
+ dw msg_TDD_ENDMINPERIOD ; TDD_ENDMINPERIOD
+ dw msg_TDD_KILLTIMEREVENT ; TDD_KILLTIMEREVENT
+ dw msg_TDD_SETTIMEREVENT ; TDD_SETTIMEREVENT
+ dw msg_TDD_GETDEVCAPS ; TDD_GETDEVCAPS
+ ;
+ dw msg_DRV_LOAD ; DRV_OPEN
+ dw msg_DRV_OPEN ; DRV_OPEN
+ dw msg_DRV_CLOSE ; DRV_CLOSE
+ dw msg_DRV_ENABLE ; DRV_ENABLE
+ dw msg_DRV_DISABLE ; DRV_DISABLE
+ dw msg_DRV_QUERYCONFIGURE ; DRV_QUERYCONFIGURE
+ dw msg_DRV_INSTALL ; DRV_INSTALL
+ifdef DEBUG
+ dw msg_TDD_GETTICK ; TDD_GETTICK
+ dw msg_TDD_GETRINTCOUNT ; TDD_GETRINTCOUNT
+ dw msg_TDD_GETPINTCOUNT ; TDD_GETPINTCOUNT
+endif
+ dw msg_fail ; default
+
+ProcLen equ $-ProcTbl
+
+errnz <ProcLen-MsgLen> ; these had better be the same!
+errnz <ProcTbl-MsgTbl-MsgLen> ; ProcTbl *must* follow MsgTbl
+
+cProc DriverProc <PUBLIC,FAR,LOADDS> <di>
+ ParmD id
+ ParmW hDriver
+ ParmW msg
+ ParmD lParam1
+ ParmD lParam2
+cBegin
+ mov ax,cs ; es == Code
+ mov es,ax
+ assumes es,CodeFixed
+
+ mov ax,msg ; AX = Message number
+ cmp ax,DRV_RESERVED ; messages below DRV_RESERVED dont
+ jl msg_dispatch ; ...need driver to be enabled
+
+ cmp wEnabled,0 ; must be enabled for msgs > DRV_RESERVED
+ jz msg_error
+
+msg_dispatch:
+ mov di,CodeFixedOFFSET MsgTbl
+ mov cx,MsgLen/2
+ cld
+ repnz scasw
+ lea bx,[di+MsgLen-2]
+ jmp cs:[bx]
+ assumes es,nothing
+
+msg_error:
+ mov ax, TIMERR_NOCANDO
+ jmp short msg_makelong
+
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+; handle std. installable driver messages.
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+msg_DRV_ENABLE:
+ cCall Enable, <ax> ; enable driver
+ jmp short msg_makelong
+
+msg_DRV_DISABLE:
+ cCall Disable, <ax>
+ jmp short msg_makelong
+
+msg_DRV_LOAD:
+msg_DRV_OPEN:
+msg_DRV_CLOSE:
+msg_success:
+ mov ax,1 ; return 1 for all others
+ jmp short msg_makelong
+
+msg_fail:
+msg_DRV_QUERYCONFIGURE:
+ xor ax, ax ; no - return 0
+ jmp short msg_makelong
+
+msg_DRV_INSTALL:
+ mov ax, DRVCNF_RESTART ; restart after install
+ errn$ msg_makelong
+
+msg_makelong:
+ cwd ; make sure high word (dx) is set
+ jmp short msg_done
+
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+; handle timer driver specific massages
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+ifdef DEBUG
+msg_TDD_GETTICK:
+ cCall tddGetTickCount
+ jmp short msg_done
+
+msg_TDD_GETRINTCOUNT:
+ mov ax,RModeIntCount.lo
+ mov dx,RModeIntCount.hi
+ jmp short msg_done
+
+msg_TDD_GETPINTCOUNT:
+ mov ax,PModeIntCount.lo
+ mov dx,PModeIntCount.hi
+ jmp short msg_done
+endif
+
+msg_TDD_GETDEVCAPS:
+ push lParam1.hi
+ push lParam1.lo
+ push lParam2.lo
+ jmp short msg_call
+
+msg_TDD_SETTIMEREVENT:
+ push lParam1.hi
+
+msg_TDD_BEGINMINPERIOD:
+msg_TDD_ENDMINPERIOD:
+msg_TDD_KILLTIMEREVENT:
+ push lParam1.lo
+
+msg_TDD_GETSYSTEMTIME:
+ errn$ msg_call
+
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+msg_call:
+ sub ax,DRV_RESERVED ; map msg into table index
+ mov di,offset DGROUP:tblCall286
+ add di,ax
+ mov ax,WinFlags
+ test ax,WF_WIN386
+ jz @f ; jump if not win386
+ add di,tblCallLen
+@@: call dword ptr [di] ; index into table
+ errn$ msg_done
+
+msg_done:
+cEnd
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/timer/libinit.asm b/private/mvdm/wow16/timer/libinit.asm
new file mode 100644
index 000000000..ff2373e4b
--- /dev/null
+++ b/private/mvdm/wow16/timer/libinit.asm
@@ -0,0 +1,374 @@
+;
+; LibInit.asm library stub to do local init for a Dynamic linked library
+;
+; NOTE!!!! link this MODULE first or you will be sorry!!!!
+;
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+?DF=1
+PMODE=1
+
+.286
+.xlist
+include cmacros.inc
+include windows.inc
+include sysinfo.inc
+include mmddk.inc
+include mmsystem.inc
+include timer.inc
+;include vtdapi.inc
+.list
+
+.list
+
+sBegin Data
+;
+; Stuff needed to avoid the C runtime coming in
+;
+; also known as "MAGIC THAT SAVED ME" - Glenn Steffler 2/7/90
+;
+; Do not remove under penalty of sex change operation!!
+;
+ DD 0 ; So null pointers get 0
+maxRsrvPtrs = 5
+ DW maxRsrvPtrs
+usedRsrvPtrs = 0
+labelDP <PUBLIC,rsrvptrs>
+
+DefRsrvPtr MACRO name
+globalW name,0
+usedRsrvPtrs = usedRsrvPtrs + 1
+ENDM
+
+DefRsrvPtr pLocalHeap ; Local heap pointer
+DefRsrvPtr pAtomTable ; Atom table pointer
+DefRsrvPtr pStackTop ; top of stack
+DefRsrvPtr pStackMin ; minimum value of SP
+DefRsrvPtr pStackBot ; bottom of stack
+
+if maxRsrvPtrs-usedRsrvPtrs
+ DW maxRsrvPtrs-usedRsrvPtrs DUP (0)
+endif
+
+public __acrtused
+ __acrtused = 1
+
+sEnd Data
+
+;
+;
+; END of nasty shit wierdness stuff that made my life a living hell...
+;
+
+externA WinFlags
+externFP LocalInit
+externFP Disable286
+externFP Enable286
+externW wMaxResolution
+externW wMinPeriod
+
+; here lies the global data
+
+sBegin Data
+
+public wEnabled
+wEnabled dw 0 ; enable = 1 ;disable = 0
+
+public PS2_MCA
+PS2_MCA db ? ; Micro Channel Flag
+
+sEnd Data
+
+ assumes es,nothing
+
+sBegin CodeInit
+ assumes cs,CodeInit
+ assumes ds,Data
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Library unload function
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Disable routine is same as WEP
+
+cProc WEP,<FAR,PUBLIC>,<>
+; parmW silly_param
+cBegin nogen
+
+ errn$ Disable
+
+cEnd nogen
+
+cProc Disable,<FAR,PUBLIC>,<>
+; parmW silly_param
+cBegin nogen
+ push ds
+ mov ax,DGROUP ; set up DS==DGROUP for exported funcs
+ mov ds,ax
+ assumes ds,Data
+
+ xor ax,ax ; return value = no error
+
+ cmp wEnabled,ax ; Q: enabled ?
+ jz dis_done ; N: exit
+
+ mov wEnabled,ax ; disabled now
+
+ mov ax,WinFlags
+ test ax,WF_WIN386
+ jnz dis_386
+
+ ; running under win286
+dis_286:
+ call Disable286
+ jmp dis_done
+
+ ; running under win386
+dis_386:
+ call Disable286
+
+dis_done:
+ pop ds
+ ret 2
+
+cEnd nogen
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Library Enable function
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+cProc Enable,<FAR,PUBLIC>,<>
+; parmW silly_param
+cBegin nogen
+ mov ax,wEnabled
+ or ax,ax ; Q: already enabled ?
+ jnz enable_done ; Y: exit
+
+ inc wEnabled ; mark as being enabled
+
+ mov ax,WinFlags
+ test ax,WF_WIN386
+ jnz enable_386
+
+ ; running under win286
+enable_286:
+ call Enable286
+ jmp enable_done
+
+ ; running under win386
+enable_386:
+ call Enable286
+
+enable_done:
+ ret 2
+
+cEnd nogen
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Library entry point
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+public LibInit
+LibInit proc far
+
+ ; CX = size of heap
+ ; DI = module handle
+ ; DS = automatic data segment
+ ; ES:SI = address of command line (not used)
+
+ jcxz lib_heapok ; heap size zero? jump over unneeded LocalInit call
+
+ cCall LocalInit,<ds,ax,cx> ; dataseg, 0, heapsize
+ or ax,ax
+ jnz lib_heapok ; if heap set continue on
+
+lib_error:
+ xor ax,ax
+ ret ; return FALSE (ax = 0) -- couldn't init
+
+lib_heapok:
+ mov ax,WinFlags
+ test ax,WF_WIN386
+ jnz lib_386
+
+ ; running under win286
+lib_286:
+ call Lib286Init
+ jmp lib_realdone ; win 286 will enable timer on first event request
+
+ ; running under win386
+lib_386:
+ call Lib286Init
+
+lib_realdone:
+ ret
+
+LibInit endp
+
+sEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Win 386 timer VTD code for initialization, and removal
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ externFP GetVersion ; in KERNEL
+ externFP MessageBox ; in USER
+ externFP LoadString ; in USER
+
+sBegin CodeInit
+assumes cs,CodeInit
+assumes ds,Data
+
+;externNP VTDAPI_GetEntryPt
+
+; Assumes DI contains module handle
+cProc WarningMessage <NEAR,PASCAL> <>
+ LocalV aszErrorTitle, 32
+ LocalV aszErrorMsg, 256
+cBegin
+ lea ax, WORD PTR aszErrorTitle
+ cCall LoadString, <di, IDS_ERRORTITLE, ss, ax, 32>
+ lea ax, WORD PTR aszErrorMsg
+ cCall LoadString, <di, IDS_ERRORTEXT, ss, ax, 256>
+ lea ax, WORD PTR aszErrorTitle
+ lea bx, WORD PTR aszErrorMsg
+ cCall MessageBox, <NULL, ss, bx, ss, ax, MB_SYSTEMMODAL+MB_OK+MB_ICONHAND>
+cEnd
+
+if 0
+Lib386Init proc near
+
+ call VTDAPI_GetEntryPt ; this will return 0 if the VxD is not loaded
+
+ or ax,ax
+ jnz Lib386InitOk
+
+ DOUT <TIMER: *** unable to find vtdapi.386 ***>
+
+ ;
+ ; warn the USER that we can't find our VxD, under windows 3.0
+ ; we can't bring up a message box, so only do this in win 3.1
+ ;
+
+ cCall GetVersion
+ xchg al,ah
+ cmp ax,030Ah
+ jb Lib386InitFail
+
+ cCall WarningMessage,<>
+
+Lib386InitFail:
+ xor ax,ax
+
+Lib386InitOk:
+
+ ret
+
+Lib386Init endp
+endif
+
+Disable386 proc near
+
+ errn$ Enable386 ; fall through
+
+Disable386 endp
+
+Enable386 proc near
+
+ mov ax,1 ; nothing to do
+ ret
+
+Enable386 endp
+
+sEnd Code386
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Win 286 timer drv code for initialization, and removal
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ externW Events
+ externFP tddISR ; in local.asm
+
+ externFP GlobalWire ; in KERNEL
+ externFP GlobalPageLock ; in KERNEL
+
+sBegin CodeInit
+ assumes cs,CodeInit
+ assumes ds,Data
+
+Lib286Init proc near
+ ; get the system configuration
+
+ ;
+ ; the FIXED_286 segment is not loaded, load it and pagelock it.
+ ;
+ mov dx,seg tddISR ; get the 286 code segment
+ mov es,dx
+ mov ax,es:[0] ; load it!
+ cCall GlobalWire, <dx> ; get it low in memory
+ cCall GlobalPageLock, <dx> ; and nail it down!
+
+ mov PS2_MCA,0 ; Initialize PS2_MCA = FALSE
+ stc ; Set this in case BIOS doesn't
+ mov ah,GetSystemConfig
+ int 15h
+ jc Lib286Init_NoMicroChannel ; Successful call?
+ or ah,ah ; Valid return?
+ jnz Lib286Init_NoMicroChannel
+ test es:[bx.SD_feature1],SF1_MicroChnPresent
+ jz Lib286Init_NoMicroChannel
+ inc PS2_MCA ; PS2_MCA = TRUE
+Lib286Init_NoMicroChannel:
+
+ push di
+
+ push ds
+ pop es
+ mov di,DataOFFSET Events ; ES:DI --> Events
+ xor ax,ax
+ mov cx,(MAXEVENTS * SizeEvent)/2
+ rep stosw ; zero out event structures.
+
+ ; set up one event as the standard call-back routine for the
+ ; BIOS timer service
+ ;
+ xor bx,bx ; BX:CX = 64k
+ xor cx,cx
+ inc bx
+
+ mov di,DataOFFSET Events ; DS:DI --> Events
+
+ mov [di].evTime.lo,cx ; Program next at ~= 55ms
+ mov [di].evTime.hi,bx ; standard 18.2 times per second event
+ mov [di].evDelay.lo,cx ; First event will be set off
+ mov [di].evDelay.hi,bx ; at 55ms (65536 ticks)
+ mov [di].evResolution,TDD_MINRESOLUTION ; Allow 55ms either way
+ mov [di].evFlags,TIME_BIOSEVENT+TIME_PERIODIC
+
+ mov ax,WinFlags
+ test ax,WF_CPU286
+ jz @f
+ mov wMaxResolution,TDD_MAX286RESOLUTION
+ mov wMinPeriod,TDD_MIN286PERIOD
+@@:
+ mov ax,bx ; Return TRUE
+ mov [di].evID,ax ; enable event
+
+ pop di
+ ret
+
+Lib286Init endp
+
+sEnd
+
+ end LibInit
diff --git a/private/mvdm/wow16/timer/local.asm b/private/mvdm/wow16/timer/local.asm
new file mode 100644
index 000000000..c409e9608
--- /dev/null
+++ b/private/mvdm/wow16/timer/local.asm
@@ -0,0 +1,701 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; LOCAL.ASM
+;
+; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
+;
+; This module contains the routines which interface with the
+; timer counter hardware itself.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+?DF=1
+PMODE=1
+
+.xlist
+include cmacros.inc
+include windows.inc
+include mmddk.inc
+include mmsystem.inc
+include timer.inc
+.list
+
+ externFP DriverCallback ; in MMSYSTEM.DLL
+ externFP StackEnter ; in MMSYSTEM.DLL
+ externFP StackLeave ; in MMSYSTEM.DLL
+ externFP tddEndMinPeriod ; timer.asm
+ externA __WinFlags ; Somewhere in Kernel ?
+
+ .286p
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Local data segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+externW Events
+externD lpOLDISR
+externB PS2_MCA
+
+sBegin Data
+
+; Current Time
+public CurTime
+CurTime dw 3 dup(0) ; 48 bit current tick count.
+
+public wProgTime
+wProgTime dw 0 ; Time currently programmed into timer chip
+ ; ...NOTE 0=64k !!!
+public wNextTime
+wNextTime dw 0 ; Time next programmed into timer chip
+
+public nInt8Count
+nInt8Count dw 0 ; # times int8 handler re-entered
+
+ifdef DEBUG
+public RModeIntCount, PModeIntCount
+RModeIntCount dd 0
+PModeIntCount dd 0
+endif
+
+public IntCount
+IntCount dw 0
+fBIOSCall dw 0 ; Bios callback needed: TRUE or FALSE
+fIntsOn dw 0 ; Interrupts have already been turned back on
+ifdef RMODE_INT
+dRModeTicks dd ? ; Temporary storage for Rmode ticks
+endif
+
+public dTickUpdate
+dTickUpdate dd 0 ; Amount to actually update times with
+
+sEnd Data
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Code segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+sBegin Code286
+ assumes cs,Code286
+ assumes ds,data
+ assumes es,nothing
+
+CodeFixWinFlags dw __WinFlags
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Local (private) functions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; @doc INTERNAL
+;
+; @asm tddRModeISR | Service routine for timer interrupts on IRQ 0.
+; when in REAL mode
+;
+; @comm
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ifdef RMODE_INT
+ assumes ds,nothing
+ assumes es,nothing
+
+externD RModeOldISR
+
+public RModeDataSegment
+RModeDataSegment dw 0
+
+public tddRmodeISR
+tddRmodeISR proc far
+ push ds
+ push ax
+ push bx
+
+ mov ax,cs:[RModeDataSegment]
+ mov ds,ax
+ assumes ds,Data
+
+ inc [IntCount]
+
+ifdef DEBUG
+ add [RModeIntCount].lo,1
+ adc [RModeIntCount].hi,0
+endif
+
+ mov ax,[wNextTime] ; Next time programmed into timer chip
+ xchg ax,[wProgTime] ; Update current time if it was reset
+
+ xor bx,bx
+ dec ax ; convert 0 -> 64k
+ add ax,1
+ adc bx,bx
+
+ cmp [nInt8Count],1 ; Do not allow multiple re-entrancy
+ jge tddRmodeISRNormalExit
+
+ cld
+ push di
+ push cx
+ mov di,DataOFFSET Events ; DS:DI --> first event
+ mov cx,MAXEVENTS
+
+tddRmodeISRLoop:
+ cmp [di].evID,0 ; is this event active?
+ jz tddRmodeISRNext
+ cmp [di].evDestroy,EVENT_DESTROYING
+ je tddRmodeISRNext
+ test [di].evFlags,TIME_BIOSEVENT
+ jz tddRmodeISRNext
+
+ mov dRModeTicks.lo,ax
+ mov dRModeTicks.hi,bx
+ add ax,[dTickUpdate.lo]
+ adc bx,[dTickUpdate.hi]
+ cmp [di].evTime.hi,bx
+ jg @f
+ jl tddRmodeISRChain
+ cmp [di].evTime.lo,ax
+ jle tddRmodeISRChain
+
+@@:
+ mov ax,dRModeTicks.lo
+ mov bx,dRModeTicks.hi
+ jmp tddRmodeISRSearchExit
+
+tddRmodeISRChain:
+ pop cx
+ pop di
+ pop bx
+ pop ax
+ push [RModeOldISR.hi]
+ push [RModeOldISR.lo]
+
+ push bp ; Restore DS from stack
+ mov bp,sp
+ mov ds,[bp+6] ; stack: [ds] [RModeOldISR.hi] [RModeOldISR.lo] [bp]
+ assumes ds,nothing
+ pop bp
+
+ retf 2
+
+tddRmodeISRNext:
+ assumes ds,Data
+ add di,SizeEvent ; Increment to next event slot
+ loop tddRmodeISRLoop
+
+tddRmodeISRSearchExit:
+ pop cx
+ pop di
+
+tddRmodeISRNormalExit:
+ add CurTime[0],ax
+ adc CurTime[2],bx
+ adc CurTime[4],0
+
+ add [dTickUpdate.lo],ax ; Update total needed to be added
+ adc [dTickUpdate.hi],bx
+
+ cmp PS2_MCA,0 ; Check for a PS/2 Micro Channel
+ jz @f
+ in al,PS2_SysCtrlPortB ; Get current System Control Port status
+ or al,PS2_LatchBit ; Set latch clear bit
+ IO_Delay
+ out PS2_SysCtrlPortB,al ; Set new System Control Port status
+@@:
+ mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
+ out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
+
+ pop bx
+ pop ax
+ pop ds
+ assumes ds,nothing
+ iret
+
+tddRmodeISR endp
+endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@asm tddISR |
+; Service routine for timer interrupts on IRQ 0.
+;
+; The ISR runs through all the event slots available, looking for
+; slots that are currently in used, and are not currently being
+; destroyed. For each valid event found the callback time is updated.
+; After all times have been updated, the table is run through again,
+; calling all events that are due, and removing any due events that are
+; oneshots. By updating all the events first, any new events that are
+; created during a callback will not be accidentally called too early.
+;
+; Note that interrupts are not immediately restored, as this causes even
+; more problems with slow machines. Also, the EOI is not sent to the
+; PIC, as the BIOS interrupt handler does a non-specific EOI, and this
+; would in turn EOI the last outstanding interrupt.
+;
+; First there is a special check for the presence of a Micro Channel,
+; in which case, the System Control Port B must have bit 7 set in order
+; to have the IRQ 0 latch released. This flag is aquired during Enable
+; time with an int 15h service C0h, requesting machine information, which
+; includes the presence of a Micro Channel.
+;
+; The ISR then updates the tick count based on the count that was in
+; the timer's CE register. While retrieving that previously programmed
+; time, it updates it to the new time that is contained in the timer's
+; CR register, in case these to items are different. Note that the
+; maximum CE value of 0 is converted to 65536 through the decrement and
+; adding with carry.
+;
+; Next, the ISR must determine if it is re-entering itself. If this is
+; so, callbacks are not performed, and only a "missed ticks" count is
+; updated, indicating how many additional ticks should be subtracted
+; from each event due time. This allows the ISR to finish immediately
+; if a timer interrupt is currently being serviced. This is important
+; for both speed in general, and for slow machines that might generate
+; mouse events during timer events. Note that only 6 bytes have been
+; pushed onto the stack for this case, and that everything but DS must
+; be removed before jumping to the exit label. In this case, the
+; function can safely EOI the PIC, as the BIOS call will not be
+; performed, then the function will just return.
+;
+; In the normal case, the ISR is not being re-entered, and timer event
+; due times are updated, and callbacks are made. In this case, the
+; number of "missed ticks" is added to the CE tick count, bringing the
+; total up to the number of ticks passed since the last time the event
+; times were updated. This global counter is then zeroed for the next
+; time re-entrancy occurs. Note that interrupts are still turned off
+; at this point, and there is no need to fear bad things happening.
+;
+; When checking for a valid event ID, the Destroy flag must be checked
+; in case the interrupt occured during a kill timer function call after
+; the Destroy flag was grabbed the second time, but before the actual ID
+; could be reset.
+;
+; When a valid ID is found, its due time is updated with the CE value,
+; plus the amount of ticks that were missed because of re-entrancy, if
+; any.
+;
+; After updating times, the event list is checked again, this time to
+; perform any of the callbacks that are due. To make things easy, a
+; global flag is used to determine if interrupts have been turned back
+; on, and thus stacks have been switched.
+;
+; If a valid event is found that is also due, meaning that the callback
+; time is <= 0, the fIntsOn flag is checked to determine if the stack
+; has already been switched and interrupts are already on. If not, then
+; just that occurs. The <f>tddEvent<d> function is then called to
+; service the event.
+;
+; After all events have been called, interrupts are turned back off if
+; needed, and the original stack restored. If no callback actually
+; occurred, then the stack is never switched. The function then either
+; exits as a normal ISR would, or it chains to the BIOS ISR. This is
+; done if the BIOS event was up for being called, and the fBIOSCall flag
+; was set because of that. Since the flag cannot be set when this ISR
+; is being pre-entered, as callbacks are not performed, there is no need
+; to do a test and set proceedure on the fBIOSCall flag, just a simple
+; compare will do. Note though that the nInt8Count re-entrancy count is
+; not decremented until after interrupts are turned off.
+;
+; Interrupts are also cleared to ensure that the BIOS ISR is not
+; re-entered itself, since there is no re-entrancy control after this
+; function chains to BIOS. Notice that DS was the first register pushed
+; onto the stack, and therefore the last item to get rid of, which is
+; done with the "retf 2". DS itself is restored from stack before
+; chaining so that lpOLDISR (BIOS) can be accessed and pushed onto stack
+; as the return address.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+public tddISR
+tddISR proc far
+
+ push ds ; This is pushed first for the case of BIOS
+
+;----------------------------------------------------------------------------
+;If we are on a 386 save all registers.
+;----------------------------------------------------------------------------
+ test cs:[CodeFixWinFlags],WF_WIN286
+ jnz @F
+.386
+ pushad
+ push fs
+ push gs
+.286p
+@@:
+
+ push ax
+ push bx
+
+ mov ax,DGROUP ; set up local DS
+ mov ds,ax
+ assumes ds,Data
+
+ cmp PS2_MCA,0 ; Check for a PS/2 Micro Channel
+ jz @f
+ in al,PS2_SysCtrlPortB ; Get current System Control Port status
+ or al,PS2_LatchBit ; Set latch clear bit
+ IO_Delay
+ out PS2_SysCtrlPortB,al ; Set new System Control Port status
+
+@@:
+ inc [IntCount] ; Ever-increasing Int counter
+ inc [nInt8Count] ; Number of times int 8 re-entered
+
+ mov ax,[wNextTime] ; Next time programmed into timer chip
+ xchg ax,[wProgTime] ; Update current time if it was reset
+
+ xor bx,bx
+ dec ax ; convert 0 -> 64k
+ add ax,1 ; Force carry flag
+ adc bx,bx ; Set bx:ax == current tick count
+
+ add CurTime[0],ax ; Add tick count to total ticks
+ adc CurTime[2],bx
+ adc CurTime[4],0
+
+ifdef DEBUG
+; cmp [nInt8Count],1 ; Re-entrancy counter
+; je @f
+; add [RModeIntCount].lo,1
+; adc [RModeIntCount].hi,0
+;@@:
+ add [PModeIntCount].lo,1 ; For debug Pmode count message
+ adc [PModeIntCount].hi,0
+endif
+ cmp [nInt8Count],1 ; Do not allow multiple re-entrancy
+ je tddISRCheckCallbacks
+ add [dTickUpdate.lo],ax ; Update total needed to be added
+ adc [dTickUpdate.hi],bx
+ pop bx
+ jmp tddISREOIExit ; EOI before exiting
+
+tddISRCheckCallbacks:
+ add ax,[dTickUpdate.lo] ; Add any extra ticks from re-entrancy
+ adc bx,[dTickUpdate.hi]
+ push cx
+ xor cx,cx
+ mov [dTickUpdate.lo],cx ; Reset tick re-entrant counter
+ mov [dTickUpdate.hi],cx
+
+ cld ; never assume the value of this in an ISR!
+ push di
+ mov di,DataOFFSET Events ; DS:DI --> first event
+ mov cx,MAXEVENTS
+
+tddISRUpdateTimeLoop:
+ cmp [di].evID,0 ; is this event active?
+ jz tddISRUpdateTimeNext
+ sub [di].evTime.lo,ax ; Subtract the amount of ticks gone by
+ sbb [di].evTime.hi,bx
+
+tddISRUpdateTimeNext:
+ add di,SizeEvent ; Increment to next event slot
+ loop tddISRUpdateTimeLoop
+
+ mov fIntsOn,0 ; Initialize interrupts set flag
+ mov di,DataOFFSET Events ; DS:DI --> first event
+ mov cx,MAXEVENTS
+
+tddISRCallLoop:
+ cmp [di].evID,0 ; is this event active?
+ jz tddISRNextEvent
+ cmp [di].evDestroy,EVENT_DESTROYING
+ je tddISRNextEvent
+ cmp [di].evTime.hi,0 ; Is it time to call the event?
+ jg tddISRNextEvent ; evTime <= 0
+ jl tddISREvent
+ cmp [di].evTime.lo,0
+ jg tddISRNextEvent
+
+tddISREvent:
+ test [di].evFlags,TIME_BIOSEVENT
+ jnz tddISRCallEvent ; No need to switch, as no call will be made.
+ cmp fIntsOn,0 ; Have interrupts been turned on already?
+ jnz tddISRCallEvent
+ inc fIntsOn ; fIntsOn == TRUE
+ cCall StackEnter ; Switch to a new stack
+ sti ; Can be re-entered now with new stack
+
+; A timer callback needs to be called, but first before calling it,
+; we need to check to determine if the original timer interrupt function
+; is to be called during this interrupt. The reason is that a timer
+; callback could take a long time, and the PIC should be EOI'ed as soon
+; as possible.
+; It is not possible to just do a specific EOI, as the BIOS timer
+; interrupt performs a non-specific EOI, which would turn back on some
+; other random interrupt. So if the the BIOS needs to be called, it
+; is done now, else the EOI is performed now. This assumes that the
+; BIOS callback is the first item in the list of callbacks.
+; If the BIOS callback occurs now, then the fBIOSCall flag is reset,
+; as there is no need to chain to it at the end of this interrupt. So
+; if no other callbacks are to be performed, the BIOS interrupt is
+; chained to, else it is just called before the first timer callback
+; is performed.
+
+ cmp [fBIOSCall],0 ; Does BIOS need to be called?
+ je tddISREOI
+ mov [fBIOSCall],0 ; No need to call BIOS again at the end
+ pushf ; Simulate an interrupt call
+ call lpOLDISR ; Call original timer interrupt
+ jmp tddISRCallEvent ; Do actual timer callback
+
+; No BIOS interrupt call is to be performed, so do EOI.
+tddISREOI:
+ mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
+ out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
+tddISRCallEvent:
+ call tddEvent ; handle the event
+
+tddISRNextEvent:
+ add di,SizeEvent ; Increment to next event slot
+ loop tddISRCallLoop
+
+ cmp fIntsOn,0 ; Where interrupts turned back on?
+ jz @f
+ cli ; Interrupts were turned on, so remove them
+ cCall StackLeave ; Switch back to old stack
+
+@@:
+ pop di ; Restore everything except DS
+ pop cx
+ pop bx
+ cmp [fBIOSCall],0 ; Does BIOS need to be called?
+ je tddISREOIExit
+ pop ax
+ mov [fBIOSCall],0
+
+;----------------------------------------------------------------------------
+;If we are on a 386 restore all registers.
+;----------------------------------------------------------------------------
+ test cs:[CodeFixWinFlags],WF_WIN286
+ jnz @F
+.386
+ pop gs
+ pop fs
+ popad
+.286p
+@@:
+ push [lpOLDISR.hi] ; Push return address
+ push [lpOLDISR.lo]
+ dec [nInt8Count] ; exiting, decrement entry count
+
+ push bp ; Restore DS from stack
+ mov bp,sp
+ mov ds,[bp+6] ; stack: [ds] [lpOLDISR.hi] [lpOLDISR.lo] [bp]
+ assumes ds,nothing
+ pop bp
+
+ retf 2 ; Chain to BIOS ISR, removing DS from stack
+
+tddISREOIExit:
+ mov al,SPECIFIC_EOI ; specific EOI for IRQ 0 interrupt line
+ out PICDATA,al ; send End-Of-Interrupt to PIC DATA port
+ pop ax
+ assumes ds,Data
+ dec [nInt8Count] ; exiting, decrement entry count
+
+;----------------------------------------------------------------------------
+;If we are on a 386 restore all registers.
+;----------------------------------------------------------------------------
+ test cs:[CodeFixWinFlags],WF_WIN286
+ jnz @F
+.386
+ pop gs
+ pop fs
+ popad
+.286p
+@@:
+ pop ds
+ assumes ds,nothing
+
+ iret
+
+tddISR endp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@asm tddEvent |
+; Handle an event when it is due.
+;
+; For a valid event, the ID is saved in case the slot needs to be zeroed
+; and the type of event is checked. If this is a oneshot event
+; timer, the entry is freed. Note that at this point, as in the kill
+; event function, the Destroy flag must be checked to determine if the
+; slot is currently being checked. If so, the EVENT_DESTROYED flag must
+; be set instead of resetting the flag so that the function that was
+; interrupted can determine that the entry was killed while being
+; checked.
+;
+; After saving the event handle, the function checks to see if the event
+; is a One Shot, in which case it is destroyed, and the event's
+; resolution is removed from resolution the table.
+;
+; If on the other hand the event is a periodic one, the next calling
+; time is updated with the delay period. Note that if the event is far
+; behind, or the last minimum resolution was very large, many delay
+; periods are added to the next call time.
+;
+; If this is a BIOS event, then the fBIOSCall flag is set so that the
+; ISR chains to the old BIOS ISR instead of returning normally. If this
+; is a normal event, the parameters are pushed, and the driver callback
+; function is called using the DCB_FUNCTION flag.
+;
+; After returning from the callback, the return value from
+; <f>DriverCallback<d> is checked to determine if the callback succeeded.
+; If it did not, then the timer event needs to be removed. The timer
+; event however may have been a oneshot, in which case it was already
+; been removed before the call was made, and the EVENT_DESTROYED flag
+; may have been set, so it is just left alone. If the event is still
+; present however, it is destroyed after doing the checking to see if
+; this interrupt came while the event was being destroyed. Note that
+; there is no check to see if the event IDs are the same before destroying
+; the event. This is because if the callback failed, then the timer
+; structure cannot have changed, and no check is needed.
+;
+;@parm DS:DI |
+; Points to the event slot.
+;
+;@comm Uses AX,BX.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes es,nothing
+ assumes ds,Data
+
+cProc tddEvent, <NEAR, PUBLIC>, <>
+cBegin
+ push dx
+
+ mov dx,[di].evID
+ test [di].evFlags,TIME_PERIODIC
+ jnz tddEventPeriodic
+
+tddEventKillOneShot:
+ xor ax,ax
+ mov [di].evID,ax ; Invalidate slot
+ cmp [di].evDestroy,EVENT_CHECKING ; Did this interrupt a Kill?
+ jne @f
+ mov al,EVENT_DESTROYED ; Let the interrupted Kill know
+@@:
+ mov [di].evDestroy,al
+ mov [di].evCreate,ah ; pEvent->evCreate = FALSE
+ push dx
+ push cx
+ cCall tddEndMinPeriod,<[di].evResolution>
+ pop cx
+ pop dx
+ jmp tddEventCallback
+
+tddEventPeriodic:
+ mov ax,[di].evDelay.lo
+ mov bx,[di].evDelay.hi
+@@:
+ add [di].evTime.lo,ax
+ adc [di].evTime.hi,bx
+ jl @b
+
+tddEventCallback:
+ test [di].evFlags,TIME_BIOSEVENT
+ jz tddEventDriverCallback
+ inc [fBIOSCall]
+ jmp tddEventExit
+
+tddEventDriverCallback:
+ push cx
+ push es
+ ;
+ ; call DriverCallback() in MMSYSTEM
+ ;
+ push [di].evCallback.hi ; execute callback function
+ push [di].evCallback.lo
+ push DCB_FUNCTION or DCB_NOSWITCH; callback flags
+ push dx ; idTimer
+ xor dx,dx
+ push dx ; msg = 0
+ push [di].evUser.hi ; dwUser
+ push [di].evUser.lo
+ push dx ; dw1 = 0
+ push dx
+ push dx ; dw2 = 0
+ push dx
+ call DriverCallback ; execute callback function
+ pop es
+ or ax,ax ; Check for a successful return
+ jnz tddEventSucceed ; If callback succeeded, just continue
+ cmp [di].evID,ax ; If the timer was already destroyed,
+ jz tddEventSucceed ; just leave
+ mov [di].evID,ax ; Else destroy the event
+ cmp [di].evDestroy,EVENT_CHECKING ; Did this interrupt a Kill?
+ jne @f
+ mov al,EVENT_DESTROYED ; Let the interrupted Kill know
+@@:
+ mov [di].evDestroy,al
+ mov [di].evCreate,ah ; pEvent->evCreate = FALSE
+ cCall tddEndMinPeriod,<[di].evResolution>
+
+tddEventSucceed:
+ pop cx
+
+tddEventExit:
+ pop dx
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; @doc INTERNAL
+;
+; @asm GetCounterElement | Low level routine which loads the tick count
+; from the timer counter device, and returns the number of ticks that
+; have already passed.
+;
+; @rdesc Returns the tick count in AX.
+;
+; @comm All registers preserved.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+public GetCounterElement
+GetCounterElement proc near
+
+ ; Get rid of any latched count if this is called during interrupt time
+ cmp [nInt8Count],1
+ jb @f
+ in al,TMR_CNTR_0
+ IO_Delay
+ in al,TMR_CNTR_0
+
+@@:
+ ; read counter first time
+ xor ax,ax ; LATCH counter 0 command
+ out TMR_CTRL_REG,al ; send command
+
+ in al,TMR_CNTR_0 ; read low byte
+ mov ah,al
+ in al,TMR_CNTR_0 ; read high byte
+ xchg al,ah
+ sub ax,wProgTime ; Convert to number of ticks already past
+ neg ax
+
+ ret
+
+GetCounterElement endp
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/timer/makefile b/private/mvdm/wow16/timer/makefile
new file mode 100644
index 000000000..fb815d1f9
--- /dev/null
+++ b/private/mvdm/wow16/timer/makefile
@@ -0,0 +1,138 @@
+#
+# constructs timer.drv
+#
+# Defines:
+# DEBUG - Enable debug code
+# STRICT - Build a version with STRICT enabled
+#
+
+NAME =timer
+EXT =drv
+OBJFIRST=$Zlibinit.obj
+OBJ1 =$Ztimer.obj $Zlocal.obj $Zstartend.obj $Zapi.obj $Zmath.obj
+
+OBJ =$(OBJ1)
+LIBS =..\lib\libw ..\lib\mdllcew ..\lib\mmsystem
+INCS = -I. -I..\inc -I..\..\inc
+
+OPT = -Oxws
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+#
+# build a retail build
+#
+!if "$(NTDEBUG)" == "" || "$(NTDEBUG)" == "retail" && "$(NTDEBUG)" != "ntsdnodbg"
+
+CLOPT =-I..\inc -I.\rinc -I..\..\inc
+MASMOPT =-I..\inc -I..\..\inc
+LINKOPT =
+RC =rc16 -i..\inc
+OBJD =
+Z = .\retail^\
+MMDEBUG =
+
+#
+# build a full debug build
+#
+!else
+CDEBUG =-Zd -Odi
+ADEBUG =-Zd
+LDEBUG =/LI
+
+CLOPT =$(CDEBUG) -DDEBUG -I..\inc -I.\rinc -I..\..\inc
+MASMOPT =$(ADEBUG) -DDEBUG -I..\inc -I..\..\inc
+LINKOPT =$(LDEBUG)
+RC =rc16 -DDEBUG -i..\inc -i..\mmsystem\rinc
+OBJD =
+Z = .\debug^\
+MMDEBUG = DEBUG=1
+
+!endif
+
+
+!if "$(STRICT)" == "YES"
+TYPES =-DSTRICT
+!else
+TYPES =
+!endif
+
+#
+# NOTE
+#
+# this code is compiled *without* windows prolog/epilog (no -Gw)
+# thus all exported routines, must have _loadds
+#
+
+CC = cl16 -c -Alnw -G2s -Zp -W3 $(CLOPT) $(OPT) $(TYPES)
+ASM = masm -Mx -t -D?QUIET $(MASMOPT)
+LINK = link16 /NOD/NOE/MAP/ALIGN:16 $(LINKOPT)
+
+.c{$Z}.obj:
+ $(CC) -Fo$*.obj $(@B).c
+
+.asm{$Z}.obj:
+ $(ASM) -DSEGNAME=_TEXT $(@B).asm, $*.obj;
+
+
+###################################
+
+all: $(NAME).$(EXT) $(NAME).sym
+
+$(NAME).$(EXT): $(OBJFIRST) $(OBJ) $(NAME).def $(NAME).res
+ $(LINK) @<<
+$(OBJFIRST) +
+$(OBJ1),
+$(NAME).$(EXT),
+$(NAME),
+$(LIBS),
+$(NAME).def
+<<
+ $(RC) -t $(NAME).res $(NAME).$(EXT)
+ @mapsym /n $*.map
+ -binplace timer.drv timer.map timer.sym
+
+RES_DIR =.\messages\usa
+
+$(NAME).rc: $(RES_DIR)\$(NAME).rc
+ @copy $(RES_DIR)\$(NAME).rc
+
+$(NAME).rcv: $(RES_DIR)\$(NAME).rcv
+ @copy $(RES_DIR)\$(NAME).rcv
+
+$(NAME).res: $(NAME).rc $(NAME).rcv ..\inc\common.ver
+ $(RC) -r $(NAME).rc
+
+
+
+############## clean ##############
+clean: cleanup all
+
+cleanup:
+ -@del $(NAME).$(EXT)
+ -@del $(NAME).res
+ -@del *.sym
+ -@del *.map
+ -@del *.lib
+ -@del $Z*.cod
+ -@del $Z*.obj
+ -@del *.rcv
+ -@del *.rc
+
+# START Dependencies
+api.obj: api.asm timer.inc
+
+libinit.obj: libinit.asm timer.inc
+
+local.obj: local.asm timer.inc
+
+startend.obj: startend.asm timer.inc
+
+timer.obj: timer.asm timer.inc
+
+# END Dependencies
diff --git a/private/mvdm/wow16/timer/math.asm b/private/mvdm/wow16/timer/math.asm
new file mode 100644
index 000000000..0a08b3c75
--- /dev/null
+++ b/private/mvdm/wow16/timer/math.asm
@@ -0,0 +1,349 @@
+ page ,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: MATH.ASM
+;
+; Contains FIXED point math routines.
+;
+; Created: Sun 30-Aug-1987 19:28:30
+; Author: Charles Whitmer [chuckwh]
+;
+; Copyright (c) 1987 Microsoft Corporation
+;-----------------------------------------------------------------------;
+
+?WIN = 0
+?PLM = 1
+?NODATA = 0
+?DF=1
+PMODE=1
+
+ .xlist
+ include cmacros.inc
+; include windows.inc
+ include timer.inc
+ .list
+
+UQUAD struc
+uq0 dw ?
+uq1 dw ?
+uq2 dw ?
+uq3 dw ?
+UQUAD ends
+
+; The following structure should be used to access high and low
+; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
+
+LONG struc
+lo dw ?
+hi dw ?
+LONG ends
+
+sBegin Code286
+ assumes cs,Code286
+ assumes ds,nothing
+ assumes es,nothing
+
+;---------------------------Public-Routine------------------------------;
+; qdiv
+;
+; This is an extended precision divide routine which is intended to
+; emulate the 80386 64 bit/32 bit DIV instruction. We don't have the
+; 32 bit registers to work with, but we pack the arguments and results
+; into what registers we do have. We will divide two unsigned numbers
+; and return the quotient and remainder. We will do INT 0 for overflow,
+; just like the 80386 microcode. This should ease conversion later.
+;
+; Entry:
+; DX:CX:BX:AX = UQUAD Numerator
+; SI:DI = ULONG Denominator
+; Returns:
+; DX:AX = quotient
+; CX:BX = remainder
+; Registers Destroyed:
+; none
+; History:
+; Tue 26-Jan-1988 00:02:09 -by- Charles Whitmer [chuckwh]
+; Wrote it.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc qdiv,<PUBLIC,NEAR>,<si,di>
+ localQ uqNumerator
+ localD ulDenominator
+ localD ulQuotient
+ localW cShift
+cBegin
+
+; stuff the quad word into local memory
+
+ mov uqNumerator.uq0,ax
+ mov uqNumerator.uq1,bx
+ mov uqNumerator.uq2,cx
+ mov uqNumerator.uq3,dx
+
+
+; check for a zero Numerator
+
+ or ax,bx
+ or ax,cx
+ or ax,dx
+ jz qdiv_exit_relay ; quotient = remainder = 0
+
+; handle the special case when the denominator lives in the low word
+
+ or si,si
+ jnz not_that_special
+
+; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=0):DI
+
+ cmp di,1 ; separate out the trivial case
+ jz div_by_one
+ xchg dx,cx ; CX = remainder.hi = 0
+ mov ax,bx
+ div di
+ mov bx,ax ; BX = quotient.hi
+ mov ax,uqNumerator.uq0
+ div di ; AX = quotient.lo
+ xchg bx,dx ; DX = quotient.hi, BX = remainder.lo
+ifdef WIMP
+ or ax,ax ; clear OF
+endif
+qdiv_exit_relay:
+ jmp qdiv_exit
+
+; calculate (DX=0):(CX=0):BX:uqNumerator.uq0 / (SI=0):(DI=1)
+
+div_by_one:
+ xchg dx,bx ; DX = quotient.hi, BX = remainder.lo = 0
+ mov ax,uqNumerator.uq0 ; AX = quotient.lo
+ jmp qdiv_exit
+not_that_special:
+
+; handle the special case when the denominator lives in the high word
+
+ or di,di
+ jnz not_this_special_either
+
+; calculate DX:CX:BX:uqNumerator.uq0 / SI:(DI=0)
+
+ cmp si,1 ; separate out the trivial case
+ jz div_by_10000h
+ mov ax,cx
+ div si
+ mov cx,ax ; CX = quotient.hi
+ mov ax,bx
+ div si ; AX = quotient.lo
+ xchg cx,dx ; DX = quotient.hi, CX = remainder.hi
+ mov bx,uqNumerator.uq0 ; BX = remainder.lo
+ifdef WIMP
+ or ax,ax ; clear OF
+endif
+ jmp qdiv_exit
+
+; calculate (DX=0):CX:BX:uqNumerator.uq0 / (SI=1):(DI=0)
+
+div_by_10000h:
+ xchg cx,dx ; DX = quotient.hi, CX = remainder.hi = 0
+ mov ax,bx ; AX = quotient.lo
+ mov bx,uqNumerator.uq0 ; BX = remainder.lo
+ jmp qdiv_exit
+not_this_special_either:
+
+; normalize the denominator
+
+ mov dx,si
+ mov ax,di
+ call ulNormalize ; DX:AX = normalized denominator
+ mov cShift,cx ; CX < 16
+ mov ulDenominator.lo,ax
+ mov ulDenominator.hi,dx
+
+
+; shift the Numerator by the same amount
+
+ jcxz numerator_is_shifted
+ mov si,-1
+ shl si,cl
+ not si ; SI = mask
+ mov bx,uqNumerator.uq3
+ shl bx,cl
+ mov ax,uqNumerator.uq2
+ rol ax,cl
+ mov di,si
+ and di,ax
+ or bx,di
+ mov uqNumerator.uq3,bx
+ xor ax,di
+ mov bx,uqNumerator.uq1
+ rol bx,cl
+ mov di,si
+ and di,bx
+ or ax,di
+ mov uqNumerator.uq2,ax
+ xor bx,di
+ mov ax,uqNumerator.uq0
+ rol ax,cl
+ mov di,si
+ and di,ax
+ or bx,di
+ mov uqNumerator.uq1,bx
+ xor ax,di
+ mov uqNumerator.uq0,ax
+numerator_is_shifted:
+
+; set up registers for division
+
+ mov dx,uqNumerator.uq3
+ mov ax,uqNumerator.uq2
+ mov di,uqNumerator.uq1
+ mov cx,ulDenominator.hi
+ mov bx,ulDenominator.lo
+
+; check for case when Denominator has only 16 bits
+
+ or bx,bx
+ jnz must_do_long_division
+ div cx
+ mov si,ax
+ mov ax,uqNumerator.uq1
+ div cx
+ xchg si,dx ; DX:AX = quotient
+ mov di,uqNumerator.uq0 ; SI:DI = remainder (shifted)
+ jmp short unshift_remainder
+must_do_long_division:
+
+; do the long division, part IZ@NL@%
+
+ cmp dx,cx ; we only know that DX:AX < CX:BX!
+ jb first_division_is_safe
+ mov ulQuotient.hi,0 ; i.e. 10000h, our guess is too big
+ mov si,ax
+ sub si,bx ; ... remainder is negative
+ jmp short first_adjuster
+first_division_is_safe:
+ div cx
+ mov ulQuotient.hi,ax
+ mov si,dx
+ mul bx ; fix remainder for low order term
+ sub di,ax
+ sbb si,dx
+ jnc first_adjuster_done ; The remainder is UNSIGNED! We have
+first_adjuster: ; to use the carry flag to keep track
+ dec ulQuotient.hi ; of the sign. The adjuster loop
+ add di,bx ; watches for a change to the carry
+ adc si,cx ; flag which would indicate a sign
+ jnc first_adjuster ; change IF we had more bits to keep
+first_adjuster_done: ; a sign in.
+
+; do the long division, part II
+
+ mov dx,si
+ mov ax,di
+ mov di,uqNumerator.uq0
+ cmp dx,cx ; we only know that DX:AX < CX:BX!
+ jb second_division_is_safe
+ mov ulQuotient.lo,0 ; i.e. 10000h, our guess is too big
+ mov si,ax
+ sub si,bx ; ... remainder is negative
+ jmp short second_adjuster
+second_division_is_safe:
+ div cx
+ mov ulQuotient.lo,ax
+ mov si,dx
+ mul bx ; fix remainder for low order term
+ sub di,ax
+ sbb si,dx
+ jnc second_adjuster_done
+second_adjuster:
+ dec ulQuotient.lo
+ add di,bx
+ adc si,cx
+ jnc second_adjuster
+second_adjuster_done:
+ mov ax,ulQuotient.lo
+ mov dx,ulQuotient.hi
+
+; unshift the remainder in SI:DI
+
+unshift_remainder:
+ mov cx,cShift
+ jcxz remainder_unshifted
+ mov bx,-1
+ shr bx,cl
+ not bx
+ shr di,cl
+ ror si,cl
+ and bx,si
+ or di,bx
+ xor si,bx
+remainder_unshifted:
+ mov cx,si
+ mov bx,di
+ifdef WIMP
+ or ax,ax ; clear OF
+endif
+qdiv_exit:
+cEnd
+
+;---------------------------Public-Routine------------------------------;
+; ulNormalize
+;
+; Normalizes a ULONG so that the highest order bit is 1. Returns the
+; number of shifts done. Also returns ZF=1 if the ULONG was zero.
+;
+; Entry:
+; DX:AX = ULONG
+; Returns:
+; DX:AX = normalized ULONG
+; CX = shift count
+; ZF = 1 if the ULONG is zero, 0 otherwise
+; Registers Destroyed:
+; none
+; History:
+; Mon 25-Jan-1988 22:07:03 -by- Charles Whitmer [chuckwh]
+; Wrote it.
+;-----------------------------------------------------------------------;
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc ulNormalize,<PUBLIC,NEAR>
+cBegin
+
+; shift by words
+
+ xor cx,cx
+ or dx,dx
+ js ulNormalize_exit
+ jnz top_word_ok
+ xchg ax,dx
+ or dx,dx
+ jz ulNormalize_exit ; the zero exit
+ mov cl,16
+ js ulNormalize_exit
+top_word_ok:
+
+; shift by bytes
+
+ or dh,dh
+ jnz top_byte_ok
+ xchg dh,dl
+ xchg dl,ah
+ xchg ah,al
+ add cl,8
+ or dh,dh
+ js ulNormalize_exit
+top_byte_ok:
+
+; do the rest by bits
+
+next_byte:
+ inc cx
+ add ax,ax
+ adc dx,dx
+ jns next_byte
+ulNormalize_exit:
+cEnd
+
+sEnd
+
+ end
diff --git a/private/mvdm/wow16/timer/messages/usa/timer.rc b/private/mvdm/wow16/timer/messages/usa/timer.rc
new file mode 100644
index 000000000..94c191c88
--- /dev/null
+++ b/private/mvdm/wow16/timer/messages/usa/timer.rc
@@ -0,0 +1,8 @@
+#include <windows.h>
+#include "timer.rcv"
+
+STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE
+BEGIN
+ 1, "Timer Driver"
+ 2, "Cannot find the VTDAPI.386 file. The multimedia timers are not available.\nMake sure VTDAPI.386 is in your Windows SYSTEM directory and the\ndevice=VTDAPI.386 line is included in the [386Enh] section of the SYSTEM.INI file."
+END
diff --git a/private/mvdm/wow16/timer/messages/usa/timer.rcv b/private/mvdm/wow16/timer/messages/usa/timer.rcv
new file mode 100644
index 000000000..4e43776c0
--- /dev/null
+++ b/private/mvdm/wow16/timer/messages/usa/timer.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* TIMER.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_INSTALLABLE
+#define VER_FILEDESCRIPTION_STR "Timer driver for PC compatibles"
+#define VER_INTERNALNAME_STR "timer.drv"
+#define VER_ORIGINALFILENAME_STR "timer.drv"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/timer/njumps.mac b/private/mvdm/wow16/timer/njumps.mac
new file mode 100644
index 000000000..7a5e26fbf
--- /dev/null
+++ b/private/mvdm/wow16/timer/njumps.mac
@@ -0,0 +1,36 @@
+ .xlist
+
+ irp q,<c,a,ae,b,be,z,e,s>
+
+nj&q &macro dest
+ local jump
+ jn&q jump
+ if2
+ if dest ge ($-126-2)
+ if dest le ($+127+3)
+ %out nj&q dest :: can be replaced with j&q dest
+ endif
+ endif
+ endif
+ jmp dest
+jump label near
+ &endm
+
+njn&q &macro dest
+ local jump
+ j&q jump
+ if2
+ if dest ge ($-126-2)
+ if dest le ($+127+3)
+ %out njn&q dest :: can be replaced with jn&q dest
+ endif
+ endif
+ endif
+ jmp dest
+jump label near
+ &endm
+
+ endm
+
+ .list
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/timer/startend.asm b/private/mvdm/wow16/timer/startend.asm
new file mode 100644
index 000000000..045a2f801
--- /dev/null
+++ b/private/mvdm/wow16/timer/startend.asm
@@ -0,0 +1,285 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; STARTEND.ASM
+;
+; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
+;
+; This module contains the routines which initialize, and clean
+; up the driver after Libentry/WEP/Enable/Diable called by windows.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+?DF=1
+
+ PMODE=1
+ .xlist
+ include cmacros.inc
+ include int31.inc
+ include windows.inc
+ include mmddk.inc
+ include mmsystem.inc
+ include timer.inc
+ .list
+
+ externA __WinFlags
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Local data segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+sBegin DATA
+
+ ; ISR support
+
+ public lpOLDISR
+ lpOldISR dd ?
+
+ifdef RMODE_INT
+ public RModeOldISR
+ RModeOldISR dd 0
+
+ public RModeCodeSegment
+ RModeCodeSegment dw ?
+
+endif ;RMODE_INT
+
+ externW Events
+ externW wNextTime
+
+sEnd DATA
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Code segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ externFP tddISR ; in local.asm
+ externFP tddSetInterruptPeriodFar ; in timer.asm
+
+ifdef RMODE_INT
+ externW RmodeDataSegment ; in local.asm
+ externFP tddRModeISR ; in local.asm
+endif
+ externFP GetSelectorBase ; kernel
+ externFP AllocCStoDSAlias ; kernel
+ externFP FreeSelector ; kernel
+
+sBegin CodeInit
+ assumes cs,CodeInit
+ assumes ds,Data
+ assumes es,nothing
+
+;----------------------------Private-Routine----------------------------;
+; SegmentFromSelector
+;
+; Converts a selector to a segment...note that this routine assumes
+; the memory pointed to by the selector is below the 1Meg line!
+;
+; Params:
+; AX = selector to convert to segment
+;
+; Returns:
+; AX = segment of selector given
+;
+; Error Returns:
+; None
+;
+; Registers Destroyed:
+; none
+;
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SegmentFromSelector proc near
+
+ cCall GetSelectorBase,<ax> ;DX:AX = base of selector
+rept 4
+ shr dx,1
+ rcr ax,1
+endm
+ ;AX now points to *segment* (iff selector is based below 1Mb)
+
+ ret
+
+SegmentFromSelector endp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; @doc INTERNAL
+;
+; @api WORD | Enable | This function enables the driver. It
+; will hook interrupts and validate the hardware.
+;
+; @rdesc Returns 1 if successfull, and 0 otherwise.
+;
+; @comm This function is automatically invoked when the library is
+; first loaded. It is included so that win386 could call it
+; when it switches VMs.
+;
+; @xref Disable
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+cProc Enable286 <FAR, PUBLIC> <si, di>
+
+cBegin
+ ; make sure clock interrupts are disabled until after
+ ; service routine has been initialized!!
+ AssertSLI
+ cli
+
+ ; get the currently owned timer interrupt vector
+
+ ; get interrupt vector, and specify timer interrupt number
+; mov ax,03500H + TIMERINTERRUPT
+; push es
+; int 21h ; get the current vector in ES:BX
+; mov lpOldISR.Sel,es
+; mov lpOldISR.Off,bx ; save the old vector
+; pop es
+;
+; ; set vector to our isr
+;
+; ; set interrupt vector function, and specify the timer interrupt number
+; mov ax,02500h + TIMERINTERRUPT
+; push ds
+; mov dx,seg tddISR
+; mov ds,dx
+; assumes ds,nothing
+; mov dx,offset tddISR
+; int 21h ; set the new vector
+; pop ds
+; assumes ds,DATA
+;
+; mov ax,[wNextTime]
+; not ax
+; mov [wNextTime],ax ; force set of period
+; call tddSetInterruptPeriodFar
+
+ifdef RMODE_INT
+ ;
+ ; if running under DOSX set the RMODE interrupt too
+ ;
+ mov ax,__WinFlags
+ test ax,WF_PMODE
+ jz enable_no_dosx
+
+ mov ax,seg tddRModeISR
+ call SegmentFromSelector
+
+ or dx,dx ; ACK! above 1Mb
+ jnz enable_no_dosx
+
+ mov [RModeCodeSegment],ax ; save the segment of the code segment
+
+ mov ax,ds ; get SEGMENT of our data segment
+ call SegmentFromSelector
+ push ax ; save on stack
+
+ mov ax,seg tddRModeISR ; write data SEGMENT into _INTERRUPT
+ cCall AllocCStoDSAlias,<ax> ; code segment -- requires a data alias
+ mov es,ax
+ pop ax
+ mov es:[RModeDataSegment],ax
+ cCall FreeSelector,<es> ; don't need CS alias any longer
+
+ mov ax,Get_RM_IntVector ; get the real mode IRQ0 vector
+ mov bl,DOSX_IRQ + TIMERINTERRUPT
+ int 31h ; DOSX get real mode vector in CX:DX
+
+ mov RModeOldISR.lo,dx ; save old ISR
+ mov RModeOldISR.hi,cx
+
+ mov cx,RModeCodeSegment ; CX:DX --> real mode ISR
+ mov dx,offset tddRModeISR
+
+ mov ax,Set_RM_IntVector ; DOSX Set Vector Function
+ int 31h ; Set the DOS vector real mode
+
+enable_no_dosx:
+endif
+ sti
+
+ mov ax,1
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; @doc INTERNAL
+;
+; @api WORD | Disable | This function disables the driver.
+; It disables the hardware, unhooks interrupts and removes
+; all time events from the queue.
+;
+; @rdesc Returns 1 if successfull, and 0 otherwise.
+;
+; @comm This function is called automatically when Windows unloads
+; the library and invokes the WEP() function. It is included
+; here so that WIN386 can use it when switching VMs.
+;
+; @xref Enable
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+cProc Disable286 <FAR, PUBLIC> <si, di>
+
+ ; note that all this is in the reverse order to Enable
+
+cBegin
+ AssertSLI
+ cli
+ ; set timer back to 55ms BIOS service
+ xor cx,cx ; 65536 ticks per period
+
+ mov al,TMR_MODE3_RW ; Read/Write counter 0 mode 3 (two bytes)
+ out TMR_CTRL_REG,al
+
+ mov al,cl
+ out TMR_CNTR_0,al ; write low byte
+
+ mov al,ch
+ out TMR_CNTR_0,al ; write high byte
+
+ifdef RMODE_INT
+ ;
+ ; check for a REAL mode int handler and un-hook it.
+ ;
+ mov dx,RModeOldISR.lo
+ mov cx,RModeOldISR.hi
+ jcxz disable_no_dosx
+
+ mov bl,DOSX_IRQ + TIMERINTERRUPT
+ mov ax,Set_RM_IntVector ;DOSX Set Vector Function
+ int 31h ;Set the DOS vector real mode
+
+disable_no_dosx:
+endif
+
+ ; restore the old interrupt vector
+
+ mov ax,02500h + TIMERINTERRUPT
+ ; set interrupt vector function, and specify the timer interrupt number
+
+ push ds
+ lds dx,lpOldISR
+ assumes ds,nothing
+ int 21h ; reset the old vector
+ pop ds
+ assumes ds,DATA
+
+ sti
+ mov ax,1
+cEnd
+
+sEnd
+
+end
diff --git a/private/mvdm/wow16/timer/sysinfo.inc b/private/mvdm/wow16/timer/sysinfo.inc
new file mode 100644
index 000000000..31d999879
--- /dev/null
+++ b/private/mvdm/wow16/timer/sysinfo.inc
@@ -0,0 +1,53 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1989-1990
+;
+; Title: sysinfo.inc - structure & equates for INT 15h service 0C0h
+;
+; Version: 1.00
+;
+; Date: 28-Mar-1989
+;
+; Author: RAP
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 28-Mar-1989 RAP
+;
+;==============================================================================
+
+; System Descriptor Structure returned from INT 15h, service C0h
+
+SysDescStruc STRUC
+SD_len dw ?
+SD_model db ?
+SD_submodel db ?
+SD_ROM_rev db ?
+SD_feature1 db ?
+SD_feature2 db ?
+SD_feature3 db ?
+SD_feature4 db ?
+SD_feature5 db ?
+SysDescStruc ENDS
+
+
+; Feature byte 1 bits assignments:
+
+SF1_FD_uses_DMA3 = 10000000b
+SF1_FD_uses_DMA3_bit = 7
+SF1_PIC_2_present = 01000000b
+SF1_PIC_2_present_bit = 6
+SF1_RealTimeClock = 00100000b
+SF1_RealTimeClock_bit = 5
+SF1_INT15s_called = 00010000b
+SF1_INT15s_called_bit = 4
+SF1_ExtEventWait = 00001000b
+SF1_ExtEventWait_bit = 3
+SF1_EBIOS_allocated = 00000100b
+SF1_EBIOS_allocated_bit = 2
+SF1_MicroChnPresent = 00000010b
+SF1_MicroChnPresent_bit = 1
diff --git a/private/mvdm/wow16/timer/timer.asm b/private/mvdm/wow16/timer/timer.asm
new file mode 100644
index 000000000..decab4ae9
--- /dev/null
+++ b/private/mvdm/wow16/timer/timer.asm
@@ -0,0 +1,842 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; TIMER.ASM
+;
+; Copyright (c) Microsoft Corporation 1991. All rights reserved.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+?PLM=1 ; pascal call convention
+?WIN=0 ; Windows prolog/epilog code
+?DF=1
+PMODE=1
+
+.xlist
+include cmacros.inc
+include windows.inc
+include mmddk.inc
+include mmsystem.inc
+include timer.inc
+.list
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; External functions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+externNP GetCounterElement
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Local data segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+sBegin DATA
+
+externW CurTime
+externW nInt8Count
+externW wProgTime
+externW wNextTime
+externW IntCount
+externD dTickUpdate
+
+public Events,wNextID
+
+; This structure is used in keeping track of all the current events,
+; including any BIOS event.
+;
+Events EventStruct MAXEVENTS DUP (<>)
+
+; This value is used as an ever incrementing counter that is OR'ed into
+; handles returned from <f>tddSetTimerEvent<d>. This is so that events
+; can be uniquely identified in <f>tddKillTimerEvent<d>.
+;
+wNextID dw 0
+
+;
+; The following is a table of timer resolution byte counters. Each entry
+; N represents an interest in having the timer resolution set to N+1 MS.
+; Thus there are TDD_MAX386RESOLUTION to TDD_MINRESOLUTION entries to
+; represent 1..55 MS. Each time <f>tddBeginMinPeriod<d> is called with
+; a timer period, the appropriate entry is incremented, and each time
+; <f>tddEndMinPeriod<d> is called with a timer period, that entry is
+; decremented. Presumably there is a one to one match on the Begin and
+; End minimum period calls.
+;
+; This is of course all a workaround for the fact that the timer chip
+; cannot be immediately reprogrammed the way it is wired in PCs in the
+; mode in which it needs to be run, thus a separate resolution table
+; must be kept in order to allow applications to set up a minimum
+; resolution before actually setting any events.
+;
+tddIntPeriodTable db TDD_MINRESOLUTION dup (0)
+
+public wMaxResolution,wMinPeriod
+wMaxResolution dw TDD_MAX386RESOLUTION
+wMinPeriod dw TDD_MIN386PERIOD
+
+sEnd DATA
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Code segment
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+sBegin Code286
+ assumes cs,Code286
+ assumes ds,data
+ assumes es,nothing
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Public exported functions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddBeginMinPeriod |
+; Increments sets the specified resolution in the table of period
+; resolutions. This optionally programming the timer for a new
+; higher resolution if the parameter passed is a new minimum.
+;
+;@parm WORD | wPeriod |
+; Contains a resolution period from wMaxResolution through 55
+; milliseconds.
+;
+;@rdesc Returns 0 for success, else TIMERR_NOCANDO if the resolution period
+; passed was out of range.
+;
+;@uses ax,bx,dx.
+;
+;@xref tddEndMinPeriod,tddSetInterruptPeriod.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes es,nothing
+ assumes ds,Data
+
+cProc tddBeginMinPeriod <PUBLIC,FAR> <>
+ parmW wPeriod
+cBegin
+ mov ax,TIMERR_NOCANDO ; Initialize return to error return
+
+ mov bx,wPeriod
+ cmp bx,[wMaxResolution]
+ jb tddBeginMinPeriodExit ; Return TIMERR_NOCANDO
+ cmp bx,TDD_MINRESOLUTION
+ ja tddBeginMinPeriodExit ; Return TIMERR_NOCANDO
+ dec bx ; Zero based resolution slot entries
+ cmp tddIntPeriodTable[bx],0FFh
+ifdef DEBUG
+ jne tddBeginMinPeriodInRange
+ inc bx ; Show correct period in error
+ DOUT <tddBeginMinPeriod(#bx) overflow>
+ jmp tddBeginMinPeriodExit ; Return TIMERR_NOCANDO
+tddBeginMinPeriodInRange:
+else
+ je tddBeginMinPeriodExit ; Return TIMERR_NOCANDO
+endif
+
+ inc tddIntPeriodTable[bx] ; Increment resolution[entry - 1]
+ cmp tddIntPeriodTable[bx],1 ; Don't set period if entry is >1
+ jne @f
+ call tddSetInterruptPeriod
+@@:
+ xor ax,ax ; Return ok (FALSE)
+
+tddBeginMinPeriodExit:
+ cwd ; Set to zero
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddEndMinPeriod |
+; Decrements the specified resolution in the table of period resolutions
+; that was presumably set previously with a <f>tddBeginMinPeriod<d> call.
+; This optionally programming the timer for a new lower resolution if
+; the parameter passed removed the current minimum.
+;
+;@parm WORD | wPeriod |
+; Contains a resolution period from 1 through 55 milliseconds.
+;
+;@rdesc Returns 0 for success, else TIMERR_NOCANDO if the resolution period
+; passed was out of range.
+;
+;@uses ax,bx,dx.
+;
+;@xref tddBeginMinPeriod,tddSetInterruptPeriod.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes es,nothing
+ assumes ds,Data
+
+cProc tddEndMinPeriod <PUBLIC,FAR> <>
+ parmW wPeriod
+cBegin
+ mov ax,TIMERR_NOCANDO ; Initialize return to error return
+
+ mov bx,wPeriod
+ cmp bx,[wMaxResolution]
+ jb tddEndMinPeriodExit ; Return TIMERR_NOCANDO
+ cmp bx,TDD_MINRESOLUTION
+ ja tddEndMinPeriodExit ; Return TIMERR_NOCANDO
+ dec bx ; Zero based resolution slot entries
+ cmp tddIntPeriodTable[bx],0
+ifdef DEBUG
+ jne tddEndMinPeriodInRange
+ inc bx ; Show correct period in error
+ DOUT <tddEndMinPeriod(#bx) underflow>
+ jmp tddEndMinPeriodExit ; Return TIMERR_NOCANDO
+tddEndMinPeriodInRange:
+else
+ je tddEndMinPeriodExit ; Return TIMERR_NOCANDO
+endif
+
+ dec tddIntPeriodTable[bx] ; Decrement resolution[entry - 1]
+ jnz @f ; No need to set interrupt period
+ call tddSetInterruptPeriod
+@@:
+ xor ax,ax ; Return ok (FALSE)
+
+tddEndMinPeriodExit:
+ cwd ; Set to zero
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@func void | tddSetInterruptPeriod |
+; This function optionally programs the timer with a new interrupt
+; period if the maximum resolution in the resolution table has changed.
+if 0 ; !!!
+;
+; If the function is being called outside of interrupt time, the function
+; must first turn off interrupts so that the resolution table is not
+; changed between the time the the function finds a resolution to set,
+; and the time it starts to program the timer. Once the timer begins to
+; be programmed, it won't send any more interrupts until programming is
+; finished. The documentation does not specify that, but it was verified
+; through testing the timer. If however the function is being called
+; during a timer interrupt, there is no need to turn off interrupts, as
+; the resolution table will not be changed at that time.
+;
+endif
+; In any case, the resolution table is searched, looking for the first
+; non-zero entry, which is taken as the maximum resolution the timer
+; should currently be programmed to. If nothing is set in the table,
+; then the programming defaults to the minimum resolution of 55 MS.
+;
+; Once an entry is found, it is compared to the previous programmed
+; time, not the currently programmed time. This is in case an interrupt
+; has not occurred since the last time the timer was programmed using
+; this function. Note that in converting to clock ticks, any period
+; that overflows a single word is taken to be 65536 ticks, which is the
+; maximum number allowable in the timer, and is equal to almost 55 MS.
+;
+; If a new time must be programmed, the new resolution is sent out to
+; the timer, and eventually interrupts are set again.
+;
+;@rdesc Nothing.
+;
+;@uses ax,bx,dx.
+;
+;@xref tddBeginMinPeriod,tddEndMinPeriod.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes es,nothing
+ assumes ds,Data
+
+cProc tddSetInterruptPeriodFar <PUBLIC,FAR> <>
+cBegin
+ call tddSetInterruptPeriod
+cEnd
+
+cProc tddSetInterruptPeriod <PUBLIC,NEAR> <>
+
+cBegin
+ xor bx, bx ; Start at the beginning of the table
+
+ EnterCrit ; !!!
+
+tdd_sip_loop:
+ cmp bx,TDD_MINRESOLUTION ; Has the last entry been passed up?
+ je tdd_sip_Set_This_Period ; Jump out using TDD_MINRESOLUTION
+ inc bx
+ cmp tddIntPeriodTable[bx-1],0
+ je tdd_sip_loop
+
+tdd_sip_Set_This_Period:
+ mov ax,bx
+ call tddMsToTicks
+
+ or dx,dx ; Check for overflow of WORD
+ jz tdd_sip_period_ok
+ xor ax,ax ; Set to 64k instead.
+tdd_sip_period_ok:
+
+ cmp ax,[wNextTime] ; Compare with last programmed time
+ je tdd_sip_exit ; No need to reprogram
+
+ DOUT <tddSetInterruptPeriod: ms=#bx ticks=#ax>
+
+ mov bx,ax ; Save this value
+ mov [wNextTime],bx ; This is now the last programmed time
+
+ mov al, TMR_MODE2_RW ; Set counter 0 to mode 2
+ out TMR_CTRL_REG, al
+
+ mov al, bl
+ out TMR_CNTR_0, al
+ mov al, bh
+ out TMR_CNTR_0, al
+
+tdd_sip_exit:
+ LeaveCrit ; !!!
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddSetTimerEvent |
+; Adds a timer event, possibly periodic to the event queue.
+;
+; A timer event is set by first looking through the table of external
+; event slots, trying to locate a currently vacant slot that is not
+; currently being checked or deleted. If one is found, the Create flag
+; is test-and-set in order to try and grab the slot.
+;
+; If this succeeds, the slot can be set up with the information, and the
+; resolution entered into the event resolution table. The very last
+; thing that occurs is setting the ID element of the slot. This is so
+; that an inturrupt will not try to execute this event until all the
+; parameters are set. This means that the event could be executed
+; immediately after the ID is set, but before this function actually
+; returns to the caller.
+;
+; If the function fails to grab the event slot, it means that either an
+; interrupt occurred, and another event was created in this slot, or that
+; this function is running during an interrupt that occurred while a new
+; event was being created. In any case, the slot must be passed by.
+;
+; If an interrupt had occurred during this function, it also means that
+; some other event could have been freed, but already passed by, so the
+; function misses it. The function cannot go back though, because it
+; might actually be processing during an interrupt, and the slot being
+; passed by would continue in its present state, and thus cause an
+; infinite loop to occur.
+;
+; When checking for a free event slot, not only is the ID checked, but
+; also the state of the Destroy flag. This flag is used during the kill
+; event function to indicate that an event slot is currently being
+; checked or destroyed, or was destroyed during an interrupt while the
+; slot was being checked. In either case, it indicates that this
+; function is being called during interrupt time, and the slot cannot be
+; re-used until the flag is removed by the kill event function. This
+; means that during the kill event function, there is one less event
+; slot that can be used than normal.
+;
+; Once the ID of the event slot is set, the event can be called. Note
+; that the event may then be called before this function even returns.
+;
+;@rdesc Returns a handle which identifies the timer event, or NULL if the
+; requested event is invalid, or the event queue is full.
+;
+;@xref tddKillTimerEvent
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddSetTimerEvent <PUBLIC,FAR> <si,di,es>
+ parmD pTIMEREVENT
+ localW wResolution
+ localW wEventID
+cBegin
+ les si,pTIMEREVENT ; timer event structure
+ mov ax,es
+ or ax,si
+ ; (pTIMEREVENT != NULL)
+ jz SetEventError ; NULL pointer, exit
+
+ mov bx,es:[si].te_wDelay
+
+ ; ((te_wDelay >= wMinPeriod) && (te_wDelay <= TDD_MAXPERIOD))
+ cmp bx,[wMinPeriod] ; delay less than min period?
+ jb SetEventError ; Yes, error
+
+ cmp bx,TDD_MAXPERIOD ; delay greater than max period?
+ ja SetEventError ; Yes, error
+
+ ; (!te_wResolution)
+ mov ax,es:[si].te_wResolution
+ or ax,ax ; resolution not set?
+ jz SetDefaultResolution ; Yes, set default resolution
+
+ ; ((te_wResolution >= TDD_MINRESOLUTION) && (te_wResolution <= wMaxResolution))
+ cmp ax,TDD_MINRESOLUTION ; resolution less than min resolution?
+ jb @f ; No, skip to next check
+ mov ax,TDD_MINRESOLUTION
+
+@@:
+ cmp ax,[wMaxResolution] ; resolution greater than max resolution?
+ ja @f ; No, skip to next check
+ mov ax,[wMaxResolution]
+
+@@:
+ ; (te_wResolution > te_wDelay)
+ cmp bx,ax ; delay less than resolution?
+ jb SetDefaultResolution ; Yes, set default resolution
+
+ jmp short SetEventValidParms
+
+SetEventError:
+ xor ax,ax ; Return NULL
+ jmp SetEventExit
+
+SetDefaultResolution:
+ ; te_wResolution = min(TDD_MINRESOLUTION, te_wDelay)
+ mov ax,TDD_MINRESOLUTION
+ cmp bx,ax ; delay less than min resolution?
+ ja SetEventValidParms ; No, just use min resolution then
+ mov ax,bx ; Yes, use the period as the resolution
+
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
+SetEventValidParms:
+ mov wResolution,ax ; save calculated resolution
+
+ lea di,Events ; DS:DI --> events
+ xor ax,ax ; event slot = 0
+
+SetEventFindLoop:
+ ; if (!pEvent->evID && !pEvent->evDestroy)
+ cmp [di].evID,0
+ jne SetEventFindLoopNext
+ cmp BYTE PTR [di].evDestroy,0
+ jne SetEventFindLoopNext
+ mov bl,1
+ xchg BYTE PTR [di].evCreate,bl ; Test and set Create flag
+ or bl,bl
+ jz SetEventFindLoopFound
+
+SetEventFindLoopNext:
+ ; pEvent++, wEventID++
+ add di,SizeEvent
+ inc ax
+ ; wEventID < MAXEVENTS
+ cmp ax,MAXEVENTS
+ jb SetEventFindLoop
+
+ ; Return NULL
+ xor ax,ax ; Slot not found, return NULL
+ jmp SetEventExit
+
+SetEventFindLoopFound:
+ ;
+ ; combine the slot index and wNextID to produce a unique id to
+ ; return to the caller
+ ;
+ add [wNextID],MASKINCREMENT
+ jz SetEventFindLoopFound ; Ensure a non-zero mask
+ or ax,[wNextID] ; Add in the mask
+ mov wEventID,ax ; Save the event
+ errnz MAXEVENTS-16
+
+ ; tddBeginMinPeriod(pEvent->evResolution)
+ mov ax,wResolution
+ mov [di].evResolution,ax
+ cCall tddBeginMinPeriod <ax>
+
+ ; pEvent->evDelay = tddMsToTicks(pTIMEREVENT->te_wDelay)
+ mov ax,es:[si].te_wDelay
+ call tddMsToTicks
+ mov [di].evDelay.lo,ax
+ mov [di].evDelay.hi,dx
+
+ ; pEvent->evCallback = pTIMEREVENT->te_lpFunction
+ mov ax,es:[si].te_lpFunction.lo
+ mov dx,es:[si].te_lpFunction.hi
+ mov [di].evCallback.lo,ax
+ mov [di].evCallback.hi,dx
+
+ ; pEvent->evUser = pTIMEREVENT->te_dwUser
+ mov ax,es:[si].te_dwUser.lo
+ mov dx,es:[si].te_dwUser.hi
+ mov [di].evUser.lo,ax
+ mov [di].evUser.hi,dx
+
+ ; pEvent->evFlags = pTIMEREVENT->te_wFlags
+ mov ax,es:[si].te_wFlags
+ mov [di].evFlags,ax
+
+@@:
+ mov bx,[IntCount] ; check for interrupt occurring
+ call GetCounterElement ; Get number of ticks passed
+ xor cx,cx
+ add ax,dTickUpdate.lo ; Add extra currently skipped.
+ adc cx,dTickUpdate.hi
+ cmp bx,[IntCount]
+ jne @b ; If interrupt occurred try again
+
+ ; pEvent->evTime = pEvent->evDelay + GetCounterElement + dTickUpdate
+ mov bx,[di].evDelay.lo
+ mov dx,[di].evDelay.hi
+ add bx,ax
+ adc dx,cx
+ mov [di].evTime.lo,bx
+ mov [di].evTime.hi,dx
+
+ ; pEvent->evID = wEventID
+ mov ax,wEventID
+ mov [di].evID,ax
+ ; Return wEventID
+
+SetEventExit:
+ xor dx,dx
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddKillTimerEvent |
+; Removes a timer event from the event queue. If the event was periodic,
+; this is the only way to discontinue operation. Otherwise, this may be
+; used to remove an unwanted one shot event in case of application
+; termination.
+;
+; A timer event it killed by trying to grab the Destroy flag in a two
+; step process, which succeeds only if the function was able to grab
+; the slot before any interrupt destroyed the event.
+;
+; After verifying that the event handle is valid, the function checks the
+; Destroy flag to determine if this function is being called during
+; interrupt time, and interrupted another process killing the same
+; timer. If this is so, the function just aborts before wasting time
+; doing any other flag setting.
+;
+; The function then sets the Destroy flag to a EVENT_CHECKING state,
+; grabbing the current state of the flag in order to use when setting
+; the final state of the Destroy flag if the function succeeds.
+;
+; If the event handles match, the Destroy flag is set to a
+; EVENT_DESTROYING state. At this point, the Destroy flag is either in
+; the state in which this function left it, or an interrupt occurred, and
+; the flag was set to a EVENT_DESTROYED state durring interrupt time. If
+; an interrupt ended up destroying the event out from under this call,
+; the function is exited after clearing the Destroy flag so that the
+; event slot can be used. Note that the event slot cannot be used until
+; the function exits so that the EVENT_DESTROYED flag is not disturbed.
+;
+; If the flag is grabbed, no other call can destroy the event, and the
+; event will not be executed during interrupt time. As was previously
+; mentioned, the Destroy flag is either reset, or if this function was
+; called during interrupt time while the event was being checked, the
+; flag is set to EVENT_DESTROYED.
+;
+; The resolution entered into the event resolution table is removed.
+; The very last thing to occur is resetting the Create flag. At that
+; point the event slot could be re-used if the Destroy flag was reset.
+;
+; Note that if the event handles do not match, the Destroyed flag is also
+; reset so that it can be used in creating a new event when this event
+; is destroyed, which may have happened while checking the handles.
+;
+;@parm WORD | wID | The event handle returned by the <f>tddSetTimerEvent<d>
+; function which identifies the event to destroy.
+;
+;@rdesc Returns 0 if timer event destroyed, or TIMERR_NOCANDO if the
+; event was not registered in the system event queue.
+;
+;@xref tddSetTimerEvent
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddKillTimerEvent <PUBLIC,FAR> <si,di>
+ parmW wID
+cBegin
+ mov ax,wID
+ and ax,MASKFILTER ; Remove ID mask first
+ errnz MAXEVENTS-16
+
+ imul ax,SizeEvent ; Retrieve slot address
+ lea di,Events
+ add di,ax
+
+ ; if (pEvent->evDestroy == EVENT_DESTROYING)
+ cmp BYTE PTR [di].evDestroy,EVENT_DESTROYING ; If interrupting a destroy,
+ je KillEventError ; Leave with error
+
+ mov bl,EVENT_CHECKING
+ xchg BYTE PTR [di].evDestroy,bl ; Test and set Destroy check
+
+ ; if (pEvent->evID == wID)
+ mov ax,wID
+ cmp [di].evID,ax
+ jne KillEventRelease ; Wrong ID
+
+ mov bh,EVENT_DESTROYING
+ xchg BYTE PTR [di].evDestroy,bh ; Test and set Destroying
+
+ cmp bh,EVENT_CHECKING ; Was destroy interrupted?
+ jne KillEventRelease ; Slot has already been deleted
+
+ mov [di].evID,0 ; Invalidate ID
+
+ cmp bl,EVENT_CHECKING ; Did this interrupt a destroy?
+ jne @f ; No, was already ZERO
+ mov bl,EVENT_DESTROYED ; Let the interrupted destroy know
+@@:
+ mov BYTE PTR [di].evDestroy,bl
+ cCall tddEndMinPeriod,<[di].evResolution>
+
+ ; pEvent->evCreate = FALSE
+ mov BYTE PTR [di].evCreate,0 ; Free up slot
+ xor ax,ax ; Return 0
+ jmp KillEventExit
+
+KillEventRelease:
+ ; Free up checking flag
+ mov BYTE PTR [di].evDestroy,0
+
+KillEventError:
+ ; Invalid ID or was deleted during interrupt time (test and set failed)
+ mov ax,TIMERR_NOCANDO
+
+KillEventExit:
+ cwd ; Set to zero
+cEnd
+
+ assumes ds,Data
+ assumes es,nothing
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+public GetTickCount
+GetTickCount proc near
+
+@@:
+ mov cx,[IntCount] ; Save current interrupt count
+ call GetCounterElement ; Get number of ticks passed
+
+ xor dx,dx
+ xor bx,bx
+ add ax,CurTime[0] ; Add total tick count to current number past
+ adc dx,CurTime[2]
+ adc bx,CurTime[4]
+
+ cmp cx,[IntCount] ; Interrupt occurred while getting count
+ jne @b ; Get the count again
+ ret
+GetTickCount endp
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddGetSystemTime |
+; Returns a system time in milliseconds.
+;
+;@rdesc Returns a 32 bit value in dx:ax representing the number of milliseconds
+; since the timer driver was started.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddGetSystemTime <PUBLIC,FAR> <>
+
+cBegin
+ call GetTickCount
+ call tddTicksToMs
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@asm tddGetTickCount |
+; Returns a system time in clock ticks.
+;
+;@rdesc Returns a 48 bit value in bx:dx:ax representing the number of clock
+; ticks since the timer driver was started. A C interface would only
+; be able to access the lower 32 bits of this value.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddGetTickCount <PUBLIC,FAR> <>
+
+cBegin
+ call GetTickCount
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddGetDevCaps |
+; Fills in TIMECAPS structure.
+;
+;@parm <t>LPTIMECAPS<d> | lpTIMECAPS |
+; Points to the structure to fill.
+;
+;@parm WORD | wSize |
+; Indicates the size of the structure passed. Normally this should be
+; the size of the <t>TIMECAPS<d> structure this module was compiled with.
+;
+;@rdesc Returns 0 on success, or TIMERR_NOCANDO on failure.
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc tddGetDevCaps <PUBLIC,FAR> <si,ds>
+ parmD lpTIMECAPS
+ parmW wSize
+cBegin
+ mov ax,TIMERR_NOCANDO ; Initialize return to an error state
+
+ cmp wSize,(SIZE TIMECAPS) ; Check the size of the structure passed
+ jne Caps_Exit
+
+ lds si,lpTIMECAPS ; timer event structure
+
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ assumes ds,Data
+ mov ax,[wMinPeriod] ; Fill in the structure
+ pop ds
+ assumes ds,nothing
+
+ mov dx,TDD_MAXPERIOD
+ mov [si].tc_wPeriodMin,ax
+ mov [si].tc_wPeriodMax,dx
+ xor ax,ax ; Return success
+
+Caps_Exit:
+ cwd ; Set to zero
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddTicksToMs |
+; Convert clock ticks (1.19318 MHz) to milliseconds (1000 Hz)
+;
+;@parm BX:DX:AX |
+; Tick count to convert to milliseconds.
+;
+;@rdesc DX:AX |
+; Converted millisecond count.
+;
+;@comm There is a 0.0000005% positive error in the approximation of
+; 1193.18 ticks per millisecond by the process to avoid floating point
+; arithmetic, which effectively divides by 1193.179993 instead.
+;
+; time `Ms' = clock ticks `T' / 1193.18
+;
+; In order to be able to use fixed point, the math actually done is:
+;
+; Ms = (T * 10000h) / (DWORD)(1193.18 * 10000h)
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddTicksToMs <PUBLIC,NEAR> <si,di>
+
+cBegin
+ externNP qdiv ; In math.asm
+
+; qdiv
+;
+; Entry:
+; DX:CX:BX:AX = QUAD Numerator
+; SI:DI = LONG Denominator
+; Returns:
+; DX:AX = quotient
+; CX:BX = remainder
+
+ ; multiply BX:DX:AX by 10000h and place result in DX:CX:BX:AX for qdiv
+ mov cx,dx
+ mov dx,bx
+ mov bx,ax
+ xor ax,ax
+
+ ; SI:DI = 1193.18 * 10000h (essentially in 16.16 fixed notation)
+ mov si,1193 ; 1193 * 10000h
+ mov di,11796 ; 0.18 * 10000h = 11796.48
+
+ call qdiv ; (T * 10000h) / (DWORD)(1193.18 * 10000h)
+cEnd
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+;@doc INTERNAL TIMER
+;
+;@api DWORD | tddMsToTicks |
+; Convert milliseconds (1000 Hz) to clock ticks (1.193 MHz).
+;
+;@parm AX |
+; Millisecond count to convert to clock ticks
+;
+;@rdesc DX:AX |
+; Converted clock tick count.
+;
+;@comm There is a slight error in the approximation of 1193.18 ticks per
+; millisecond by the process to avoid floating point arithmetic, which
+; effectively multiplies by 1193.1875 instead.
+;
+; clock ticks `T' = time `Ms' * 1193.18
+;
+; In order to be able to use fixed point, the math actually done is
+;
+; T = (Ms * (WORD)(1193.18 * 20h)) / 20h
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ assumes ds,Data
+ assumes es,nothing
+
+cProc tddMsToTicks <PUBLIC,NEAR> <>
+
+cBegin
+ mov dx,38182 ; 1193.18 * 20h = 38181.76
+ mul dx ; Ms * (WORD)(1193.18 * 20h)
+ shr ax,5 ; Divide the result by 20h
+ mov cx,dx ; Save original first
+ shl cx,11 ; Keep only the bottom part
+ shr dx,5 ; Shift top part of return
+ or ax,cx ; Put two halves of bottom part together
+cEnd
+
+sEnd Code286
+
+end
diff --git a/private/mvdm/wow16/timer/timer.def b/private/mvdm/wow16/timer/timer.def
new file mode 100644
index 000000000..4b10a73d0
--- /dev/null
+++ b/private/mvdm/wow16/timer/timer.def
@@ -0,0 +1,34 @@
+LIBRARY TIMER
+
+DESCRIPTION 'timer:Timer'
+
+EXETYPE WINDOWS
+
+PROTMODE
+
+;CODE MOVEABLE DISCARDABLE LOADONCALL SHARED
+DATA PRELOAD FIXED SINGLE
+
+SEGMENTS
+ INIT_CODE PRELOAD MOVEABLE DISCARDABLE SHARED
+ FIXED_TEXT PRELOAD FIXED SHARED
+
+ ; we want the 286 segment to come in only when needed
+ ; what we want is LOADONCALL FIXED (but this does not work,
+ ; it works for boot time drivers but not DLLs)
+ ;
+ ; so we make it LOADONCALL MOVEABLE, and PageLock it in
+ ; place if we need it, see libinit.asm!Lib286Init
+ ;
+ ; FIXED_286 LOADONCALL FIXED SHARED
+
+ FIXED_286 MOVEABLE DISCARDABLE LOADONCALL SHARED
+
+HEAPSIZE 0
+
+EXPORTS
+ WEP @1 RESIDENTNAME
+ DriverProc @2 RESIDENTNAME
+
+IMPORTS
+ WINFLAGS = KERNEL.178
diff --git a/private/mvdm/wow16/timer/timer.inc b/private/mvdm/wow16/timer/timer.inc
new file mode 100644
index 000000000..cd4da3679
--- /dev/null
+++ b/private/mvdm/wow16/timer/timer.inc
@@ -0,0 +1,267 @@
+;
+; timer.inc
+;
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; segments
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+createSeg FIXED_TEXT,Code386, word, public, CODE
+createSeg FIXED_TEXT,CodeFixed, word, public, CODE
+createSeg FIXED_286, Code286, word, public, CODE
+createSeg INIT_CODE, CodeInit, word, public, CODE
+
+createSeg _DATA,Data,word,public,DATA,DGROUP
+defgrp DGROUP,Data
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; Equates and structure definitions
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IDS_ERRORTITLE equ 1
+IDS_ERRORTEXT equ 2
+
+;RMODE_INT equ 1
+
+ifdef DEBUG
+ TDD_GETTICK equ 42
+ TDD_GETRINTCOUNT equ 43
+ TDD_GETPINTCOUNT equ 44
+endif
+
+TDD_MINRESOLUTION equ 55 ; minimum resolution. (ms)
+TDD_MAX386RESOLUTION equ 1 ; maximum resolution. (ms)
+TDD_MAX286RESOLUTION equ 2 ; maximum resolution. (ms)
+
+TDD_MAXPERIOD equ 0FFFFh ; maximum ms period.
+TDD_MIN386PERIOD equ 01h ; minimum ms period.
+TDD_MIN286PERIOD equ 02h ; minimum ms period.
+
+TMR_CNTR_0 equ 040h ; counter 0 - programmable system interrupt
+TMR_CTRL_REG equ 043h ; timer control word register
+
+TMR_MODE2_RW equ 00110100b ; Read/Write counter 0 mode 2 (two bytes)
+ ; (countdown mode)
+
+TMR_MODE3_RW equ 00110110b ; Read/Write counter 0 mode 3 (two bytes)
+ ; (square wave mode)
+
+
+PS2_SysCtrlPortB equ 61h ; IBM PS2 System Control Port B
+PS2_LatchBit equ 80h ; Latch clear bit for PS2
+PICDATA equ 020h ; Programmable interrupt controller port
+SPECIFIC_EOI equ 01100000b ; IRQ 0 end-of-interrupt PIC command
+EOI_STATUS equ 00001011b ; Status of pending EOIs
+
+TIME_BIOSEVENT equ 8000h ; special flag for bios event
+
+TIMERINTERRUPT equ 8 ; interrupt number for timer counter
+
+
+; The following defines the maximum number of simultaneous events which
+; can be queued. This value covers event slots 0 to 15. Note that this
+; is 4 bits of data, which is relied upon in the code.
+;
+; The two constants defined after are used to increment and filter the
+; mask added to the event slot IDs to create an event handle to return.
+; They illustrate the dependence upon the MAXEVENTS constant.
+
+MAXEVENTS equ 16
+
+MASKINCREMENT equ 0010h
+MASKFILTER equ 000fh
+
+; The following flags are used during the process of killing an event.
+;
+; The first flag indicates that an event slot is being checked by the
+; kill event function, and that the EVENT_DESTROYED flag should be set
+; if the pevent is killed during interrupt time before the original
+; function completes its check.
+;
+; The second flag indicates that an event is currently being killed, and
+; should not be allowed to execute. This is set in the kill timer
+; function, and either cleared, or replaced with the EVENT_DESTROYED
+; flag when complete.
+;
+; The third flag can be set either in the interrupt handler for oneshot
+; events, or in the kill timer function. This is only set if the timer
+; was currently being checked when an interrupt occurred, and the event
+; was killed by the interrupt. This flag disallows any new event to be
+; created in the event slot until the flag is cleared by the original
+; kill event function exiting.
+
+EVENT_CHECKING equ 1
+EVENT_DESTROYING equ 2
+EVENT_DESTROYED equ 4
+
+EventStruct STRUC
+
+evTime dd ? ; actual time when the event will go off (in ticks)
+
+evDelay dd ? ; event delay time (in ticks)
+
+evCallback dd ? ; call back function
+
+evUser dd ? ; parameter to call-back function
+
+evResolution dw ? ; event resolution (in Ms)
+
+evID dw ? ; timer event id
+
+evFlags dw ? ; bits 1,0 = flags (one-shot/periodic)
+
+evCreate db ? ; Creation flag
+
+evDestroy db ? ; Destroying flag
+
+EventStruct ENDS
+
+ errnz <(SIZE EventStruct) and 1>
+
+ SizeEvent equ <(SIZE EventStruct)>
+
+; Macro to cause a delay in between I/O accesses to the same device.
+
+IO_Delay MACRO
+ jmp $+2
+ENDM
+
+; this macro makes sure interrupts are disabled in debug driver
+AssertCLI MACRO
+ifdef DEBUG
+ push ax
+ pushf
+ pop ax
+ test ah,2
+ jz @f
+ int 3
+@@: pop ax
+endif
+ENDM
+
+; this macro makes sure interrupts are enabled in debug driver
+AssertSLI MACRO
+ifdef DEBUG
+ push ax
+ pushf
+ pop ax
+ test ah,2
+ jnz @f
+ int 3
+@@: pop ax
+endif
+ENDM
+
+DefineInfo MACRO
+ifdef DEBUG
+externNP savedebuginfo
+endif
+ENDM
+
+SaveInfo MACRO value
+ifdef DEBUG
+ifdef savedebuginfo
+ push ax
+ mov ax,value
+ call savedebuginfo
+ pop ax
+else
+ safd
+endif
+endif
+ENDM
+
+; The DOS Extender used for Standard mode Windows remaps the master 8259 from
+; Int vectors 8h-Fh to 50h-57h. In order to speed up com port interrupt
+; response as much as possible, this driver hooks real mode interrupts
+; when running in Standard mode. It currently uses the following adjustment
+; value to hook the real hardware int vector. When time permits, this
+; HARDCODED equate should be changed to be adjustible at run time.
+
+DOSX_IRQ equ (50h - 8h) ; Adjustment for DOSX remapping the
+ ; master 8259 from 8h to 50h
+; WinFlags[0] constants...remove when included in windows.inc
+
+WF_PMODE equ 01h
+WF_CPU286 equ 02h
+WF_CPU386 equ 04h
+WF_CPU486 equ 08h
+WF_WIN286 equ 10h ; WF_STANDARD
+WF_WIN386 equ 20h ; WF_ENHANCED
+WF_CPU086 equ 40h
+WF_CPU186 equ 80h
+
+; Interrupt 31h service call equates
+
+Get_RM_IntVector equ <(Int31_Int_Serv SHL 8 ) OR Int_Get_Real_Vec>
+Set_RM_IntVector equ <(Int31_Int_Serv SHL 8 ) OR Int_Set_Real_Vec>
+
+GetSystemConfig equ 0c0h
+
+;---------------------------------Macro---------------------------------;
+;
+; EnterCrit
+;
+; saves the current state of the interrupt flag on the stack then
+; disables interrupts.
+;
+; Registers Destroyed:
+; BX, FLAGS
+;
+;------------------------------------------------------------------------;
+
+EnterCrit macro
+ local no_cli
+ pushf
+ pushf
+ pop cx
+ test ch,2 ; if interrupts are already off, dont blow
+ jz no_cli ; ... ~300 clocks doing the cli
+ cli
+no_cli:
+endm
+
+;---------------------------------Macro---------------------------------;
+;
+; LeaveCrit
+;
+; restore the interrupt state saved by EnterCrit
+;
+; Registers Destroyed:
+; CX, FLAGS
+;
+;------------------------------------------------------------------------;
+
+LeaveCrit macro reg
+ local no_sti
+ pop cx
+ test ch, 2
+ jz no_sti
+ sti
+no_sti:
+endm
+
+;------------------------------------------------------------------------;
+;------------------------------------------------------------------------;
+
+externFP OutputDebugStr
+
+DOUT macro text
+ local string_buffer
+
+ifdef DEBUG
+
+_DATA segment
+string_buffer label byte
+ db "&text&",13,10,0
+_DATA ends
+
+ push DataBASE
+ push DataOFFSET string_buffer
+ call OutputDebugStr
+endif
+ endm
diff --git a/private/mvdm/wow16/toolhelp/class1.c b/private/mvdm/wow16/toolhelp/class1.c
new file mode 100644
index 000000000..4b44d010e
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/class1.c
@@ -0,0 +1,88 @@
+/*************************************************************************
+ * CLASS1.C
+ *
+ * Routines used to enumerate window classes
+ *
+ *************************************************************************/
+
+#include "toolpriv.h"
+#include <testing.h>
+
+/* ----- Types ----- */
+
+/* The following was stolen from the 3.1 USER but is the same as 3.0.
+ * Note that the only fielda we use (for now) are the atomClassName
+ * and the pclsNext fields.
+ * Oops. We're going to use the hInstance field also.
+ */
+typedef struct tagCLS
+{
+ struct tagCLS *pclsNext;
+ unsigned clsMagic;
+ unsigned atomClassName;
+ char *pdce; /* DCE * to DC associated with class */
+ int cWndReferenceCount; /* Windows registered with this class */
+ unsigned style;
+ long (far *lpfnWndProc)();
+ int cbclsExtra;
+ int cbwndExtra;
+ HANDLE hInstance;
+ HANDLE hIcon;
+ HANDLE hCursor;
+ HANDLE hbrBackground;
+ char far *lpszMenuName;
+ char far *lpszClassName;
+} CLS;
+typedef CLS FAR *LPCLS;
+
+/* ----- Functions ----- */
+
+/* ClassFirst
+ * Returns information about the first task in the task chain.
+ */
+
+BOOL TOOLHELPAPI ClassFirst(
+ CLASSENTRY FAR *lpClass)
+{
+ WORD wClassHead;
+
+ /* Check for errors */
+ if (!wLibInstalled || !lpClass || lpClass->dwSize != sizeof (CLASSENTRY))
+ return FALSE;
+
+ /* If we're in Win3.1, call the special entry point to get the head */
+ if (!(wTHFlags & TH_WIN30))
+ wClassHead = (WORD)(*lpfnUserSeeUserDo)(SD_GETCLASSHEADPTR, 0, 0L);
+
+ /* In 3.0 (and 3.0a) we're forced to use a fixed offset. Unfortunately,
+ * this offset is different in debug and nondebug versions.
+ */
+ else
+ {
+ if (GetSystemMetrics(SM_DEBUG))
+ wClassHead = 0x1cc;
+ else
+ wClassHead = 0x1b8;
+ wClassHead = *(WORD FAR *)MAKEFARPTR(hUserHeap, wClassHead);
+ }
+
+ /* Now get the stuff */
+ return ClassInfo(lpClass, wClassHead);
+}
+
+
+/* ClassNext
+ * Returns information about the next task in the task chain.
+ */
+
+BOOL TOOLHELPAPI ClassNext(
+ CLASSENTRY FAR *lpClass)
+{
+ /* Check for errors */
+ if (!wLibInstalled || !lpClass || !lpClass->wNext ||
+ lpClass->dwSize != sizeof (CLASSENTRY))
+ return FALSE;
+
+ return ClassInfo(lpClass, lpClass->wNext);
+}
+
diff --git a/private/mvdm/wow16/toolhelp/class2.asm b/private/mvdm/wow16/toolhelp/class2.asm
new file mode 100644
index 000000000..b22a42526
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/class2.asm
@@ -0,0 +1,92 @@
+;**************************************************************************
+;* CLASS2.ASM
+;*
+;* Assembly support for the class enumeration routines.
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+PMODE32 = 0
+PMODE = 0
+SWAPPRO = 0
+ INCLUDE TDB.INC
+
+;** Class structure
+CLS STRUC
+cls_pclsNext DW ?
+cls_clsMagic DW ?
+cls_atom DW ?
+cls_pdce DW ?
+cls_RefCount DW ?
+cls_style DW ?
+cls_lpfnWndProc DD ?
+cls_cbclsExtra DW ?
+cls_cbwndExtra DW ?
+cls_hInstance DW ?
+cls_hIcon DW ?
+cls_hCursor DW ?
+cls_hbrBackgr DW ?
+cls_lpszMnName DW ?
+cls_lpszClsName DW ?
+CLS ENDS
+
+;** External functions
+externNP HelperVerifySeg
+externFP GetAtomName
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+
+; ClassInfo
+;
+; Returns information about the class with the given block handle
+
+cProc ClassInfo, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpClass
+ parmW wOffset
+cBegin
+ ;** Start by verifying that we can read the segment here
+ mov ax,hUserHeap ;Get the selector
+ mov bx,wOffset ; and the desired offset
+ cCall HelperVerifySeg, <ax,bx>
+ or ax,ax ;FALSE return?
+ jnz CI_SelOk ;We're OK
+ xor ax,ax ;Return FALSE
+ jmp CI_End
+CI_SelOk:
+
+ ;** Point to the CLS structure with DS:SI. Note that using DS to
+ ;** point to USER's DS is useful to get USER's local atoms
+ mov ax,hUserHeap ;User's heap is User's DGROUP
+ mov ds,ax
+ mov si,wOffset ;Get a pointer to the CLS structure
+
+ ;** Copy the hInstance
+ les di,lpClass ;Get the structure
+ mov ax,[si].cls_hInstance ;Get the hInst of the class owner
+ mov es:[di].ce_hInst,ax ;Save in the CLASSENTRY struct
+
+ ;** Get the string from the atom and copy the next pointer
+ mov ax,[si].cls_atom ;Get the desired atom number
+ lea bx,[di].ce_szClassName ;Get the offset to copy string to
+ push es ;Save ES (GetAtomName may trash)
+ mov cx,MAX_CLASSNAME ;Get max classname length
+ cCall GetAtomName, <ax,es,bx,cx> ;Copy the atom string
+ pop es
+ or ax,ax ;OK?
+ jnz CI_20 ;Yes
+ mov es:[di].ce_szClassName,0 ;No. Clear the string
+CI_20: mov ax,[si].cls_pclsNext ;Get the next pointer
+ mov es:[di].ce_wNext,ax ;Save it
+
+ ;** Return TRUE on success
+ mov ax,TRUE
+CI_End:
+cEnd
+
+sEnd
+
+ END
diff --git a/private/mvdm/wow16/toolhelp/dllentry.asm b/private/mvdm/wow16/toolhelp/dllentry.asm
new file mode 100644
index 000000000..be77125d0
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/dllentry.asm
@@ -0,0 +1,117 @@
+PAGE,132
+;***************************************************************************
+;*
+;* DLLENTRY.ASM
+;*
+;* TOOLHELP.DLL Entry code
+;*
+;* This module generates a code segment called INIT_TEXT.
+;* It initializes the local heap if one exists and then calls
+;* the C routine LibMain() which should have the form:
+;* BOOL FAR PASCAL LibMain(HANDLE hInstance,
+;* WORD wDataSeg,
+;* WORD cbHeap,
+;* LPSTR lpszCmdLine);
+;*
+;* The result of the call to LibMain is returned to Windows.
+;* The C routine should return TRUE if it completes initialization
+;* successfully, FALSE if some error occurs.
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+extrn LocalInit:FAR
+extrn GlobalUnwire:FAR
+
+sBegin CODE
+ assumes CS,CODE
+
+externNP ToolHelpLibMain
+externNP HelperReleaseSelector
+externNP NotifyUnInit
+externNP InterruptUnInit
+
+?PLM=0
+externA <_acrtused> ;Ensures that Win DLL startup code is linked
+?PLM=1
+
+
+; LibEntry
+;
+; KERNEL calls this when the TOOLHELP is loaded the first time
+
+cProc LibEntry, <PUBLIC,FAR>
+cBegin
+ push di ;Handle of the module instance
+ push ds ;Library data segment
+ push cx ;Heap size
+ push es ;Command line segment
+ push si ;Command line offset
+
+ ;** If we have some heap then initialize it
+ jcxz callc ;Jump if no heap specified
+
+ ;** Call the Windows function LocalInit() to set up the heap
+ ;** LocalInit((LPSTR)start, WORD cbHeap);
+ xor ax,ax
+ cCall LocalInit <ds, ax, cx>
+ or ax,ax ;Did it do it ok ?
+ jz error ;Quit if it failed
+
+ ;** Invoke our initialization routine
+callc:
+ call ToolHelpLibMain ;Invoke the 'C' routine (result in AX)
+ jmp SHORT exit
+
+error:
+ pop si ;Clean up stack on a LocalInit error
+ pop es
+ pop cx
+ pop ds
+ pop di
+exit:
+
+cEnd
+
+; WEP
+; Windows Exit Procedure
+
+cProc WEP, <FAR,PUBLIC>, <si,di,ds>
+ parmW wState
+cBegin
+ ;** Make sure our DS is safe
+ mov ax,_DATA ;Get the DS value
+ lar cx,ax ;Is it OK?
+ jz @F
+ jmp SHORT WEP_Bad ;No
+@@: and cx,8a00h ;Clear all but P, Code/Data, R/W bits
+ cmp cx,8200h ;Is it P, R/W, Code/Data?
+ jne WEP_Bad ;No
+ mov ax,_DATA ;Get our DS now
+ mov ds,ax
+
+ ;** Uninstall the Register PTrace notifications if necessary
+ cmp wNotifyInstalled,0
+ jz @F
+ cCall NotifyUnInit
+@@:
+ ;** Release fault handlers
+ cmp wIntInstalled,0
+ jz @F
+ cCall InterruptUnInit
+@@:
+ ;** Release our roving selector
+ test wTHFlags, TH_WIN30STDMODE
+ jz @F
+ cCall HelperReleaseSelector, <wSel>
+@@:
+
+WEP_Bad:
+ mov ax,1
+cEnd
+
+sEnd
+
+ END LibEntry
+
diff --git a/private/mvdm/wow16/toolhelp/global.c b/private/mvdm/wow16/toolhelp/global.c
new file mode 100644
index 000000000..65346714b
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/global.c
@@ -0,0 +1,246 @@
+/**************************************************************************
+ * GLOBAL.C
+ *
+ * Routines used to walk the global heap.
+ *
+ **************************************************************************/
+
+#include "toolpriv.h"
+#include <newexe.h>
+#include <string.h>
+
+/* GlobalInfo
+ * Reports information about the state of the global heap,
+ * specifically, the number of elements that will be returned by
+ * a global heap walk.
+ */
+
+BOOL TOOLHELPAPI GlobalInfo(
+ GLOBALINFO FAR *lpGlobalInfo)
+{
+ /* Check the structure size and verify proper installation */
+ if (!wLibInstalled || lpGlobalInfo->dwSize != sizeof (GLOBALINFO))
+ return FALSE;
+
+ /* Get the item counts */
+ if (wTHFlags & TH_KERNEL_386)
+ {
+ lpGlobalInfo->wcItems = Walk386Count(GLOBAL_ALL);
+ lpGlobalInfo->wcItemsFree = Walk386Count(GLOBAL_FREE);
+ lpGlobalInfo->wcItemsLRU = Walk386Count(GLOBAL_LRU);
+ }
+ else
+ {
+ lpGlobalInfo->wcItems = Walk286Count(GLOBAL_ALL);
+ lpGlobalInfo->wcItemsFree = Walk286Count(GLOBAL_FREE);
+ lpGlobalInfo->wcItemsLRU = Walk286Count(GLOBAL_LRU);
+ }
+
+ return TRUE;
+}
+
+/* GlobalFirst
+ * Finds the first element in the global heap. This is modified by
+ * wFlags which modifies which list (GLOBAL_ALL, GLOBAL_FREE,
+ * GLOBAL_LRU) should be walked
+ */
+
+BOOL TOOLHELPAPI GlobalFirst(
+ GLOBALENTRY FAR *lpGlobal,
+ WORD wFlags)
+{
+ DWORD dwFirst;
+
+ /* Check the structure size and verify proper installation */
+ if (!wLibInstalled || !lpGlobal ||
+ lpGlobal->dwSize != sizeof (GLOBALENTRY))
+ return FALSE;
+
+ /* Call the appropriate low-level routine to find the first block */
+ if (wTHFlags & TH_KERNEL_386)
+ {
+ /* Get the first item. Return false if no items in this list */
+ if (!(dwFirst = Walk386First(wFlags)))
+ return FALSE;
+
+ /* Return information about this first item */
+ Walk386(dwFirst, lpGlobal, wFlags);
+ }
+ else
+ {
+ /* Get the first item. Return false if no items in this list */
+ if (!(dwFirst = Walk286First(wFlags)))
+ return FALSE;
+
+ /* Return information about this first item */
+ Walk286(dwFirst, lpGlobal, wFlags);
+ }
+
+ /* Guess at the type of the object */
+ HelperGlobalType(lpGlobal);
+
+ return TRUE;
+}
+
+
+/* GlobalNext
+ * Returns the next item in the chain pointed to by lpGlobal and
+ * in the list indicated by wFlags (same choices as for GlobalFirst().
+ */
+
+BOOL TOOLHELPAPI GlobalNext(
+ GLOBALENTRY FAR *lpGlobal,
+ WORD wFlags)
+{
+ DWORD dwNext;
+
+ /* Check the structure size and verify proper installation */
+ if (!wLibInstalled || !lpGlobal ||
+ lpGlobal->dwSize != sizeof (GLOBALENTRY))
+ return FALSE;
+
+ /* Check to see if we're at the end of the list */
+ dwNext = wFlags & 3 ? lpGlobal->dwNextAlt : lpGlobal->dwNext;
+ if (!dwNext)
+ return FALSE;
+
+ /* If we're using the 386 kernel, call the 386 heap walk routine with
+ * a pointer to the appropriate heap item
+ * (Note that this depends on GLOBAL_ALL being zero)
+ */
+ if (wTHFlags & TH_KERNEL_386)
+ Walk386(dwNext, lpGlobal, wFlags);
+ else
+ Walk286(dwNext, lpGlobal, wFlags);
+
+ /* Guess at the type of the object */
+ HelperGlobalType(lpGlobal);
+
+ return TRUE;
+}
+
+
+/* GlobalEntryHandle
+ * Used to find information about a global heap entry. Information
+ * about this entry is returned in the structure.
+ */
+
+BOOL TOOLHELPAPI GlobalEntryHandle(
+ GLOBALENTRY FAR *lpGlobal,
+ HANDLE hItem)
+{
+ DWORD dwBlock;
+
+ /* Check the structure size and verify proper installation */
+ if (!wLibInstalled || !lpGlobal ||
+ lpGlobal->dwSize != sizeof (GLOBALENTRY))
+ return FALSE;
+
+ /* Make sure this is a valid block */
+ if (wTHFlags & TH_KERNEL_386)
+ {
+ if (!(dwBlock = Walk386Handle(hItem)))
+ return FALSE;
+ }
+ else
+ {
+ if (!(dwBlock = Walk286Handle(hItem)))
+ return FALSE;
+ }
+
+ /* Return information about this item */
+ if (wTHFlags & TH_KERNEL_386)
+ Walk386(dwBlock, lpGlobal, GLOBAL_ALL);
+ else
+ Walk286(dwBlock, lpGlobal, GLOBAL_ALL);
+
+ /* Guess at the type of the object */
+ HelperGlobalType(lpGlobal);
+
+ return TRUE;
+}
+
+
+/* GlobalEntryModule
+ * Returns global information about the block with the given module
+ * handle and segment number.
+ */
+
+BOOL TOOLHELPAPI GlobalEntryModule(
+ GLOBALENTRY FAR *lpGlobal,
+ HANDLE hModule,
+ WORD wSeg)
+{
+ struct new_exe FAR *lpNewExe;
+ struct new_seg1 FAR *lpSeg;
+ DWORD dwBlock;
+
+ /* Check the structure size and verify proper installation */
+ if (!wLibInstalled || !lpGlobal ||
+ lpGlobal->dwSize != sizeof (GLOBALENTRY))
+ return FALSE;
+
+ /* Grunge in the module database to find the proper selector. Start
+ * by first verifying the module database pointer
+ */
+ if (!HelperVerifySeg(hModule, sizeof (struct new_exe)))
+ return FALSE;
+
+ /* Get a pointer to the module database */
+ lpNewExe = MAKEFARPTR(hModule, 0);
+
+ /* Make sure this is a module database */
+ if (lpNewExe->ne_magic != NEMAGIC)
+ return FALSE;
+
+ /* See if the number requested is past the end of the segment table.
+ * Note that the first segment is segment 1.
+ */
+ --wSeg;
+ if (lpNewExe->ne_cseg <= wSeg)
+ return FALSE;
+
+ /* Get a pointer to the segment table */
+ lpSeg = MAKEFARPTR(hModule, lpNewExe->ne_segtab);
+
+ /* Jump to the right spot in the segment table */
+ lpSeg += wSeg;
+
+ /* Make sure this is a valid block and get its arena pointer */
+ if (wTHFlags & TH_KERNEL_386)
+ {
+ if (!(dwBlock = Walk386Handle(lpSeg->ns_handle)))
+ return FALSE;
+ }
+ else
+ {
+ if (!(dwBlock = Walk286Handle(lpSeg->ns_handle)))
+ return FALSE;
+ }
+
+ /* Return information about this item */
+ if (wTHFlags & TH_KERNEL_386)
+ Walk386(dwBlock, lpGlobal, GLOBAL_ALL);
+ else
+ Walk286(dwBlock, lpGlobal, GLOBAL_ALL);
+
+ /* Guess at the type of the object */
+ HelperGlobalType(lpGlobal);
+
+ /* If we've gotten to here, it must be OK */
+ return TRUE;
+}
+
+
+/* GlobalHandleToSel
+ * Provides a generic method of converting a handle to a selector.
+ * This works across Windows versions as well as working when the
+ * value is already a selector.
+ */
+
+WORD TOOLHELPAPI GlobalHandleToSel(
+ HANDLE hMem)
+{
+ return HelperHandleToSel(hMem);
+}
+
diff --git a/private/mvdm/wow16/toolhelp/helper.asm b/private/mvdm/wow16/toolhelp/helper.asm
new file mode 100644
index 000000000..b8ff65962
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/helper.asm
@@ -0,0 +1,555 @@
+;**************************************************************************
+;* HELPER.ASM
+;*
+;* Assembly routines used by more than one module
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE WINDOWS.INC
+PMODE32 = 0
+PMODE = 1
+SWAPPRO = 0
+ INCLUDE WINKERN.INC
+ INCLUDE NEWEXE.INC
+ INCLUDE TDB.INC
+
+;** External functions
+externNP Walk386VerifyLocHeap
+externNP Walk286VerifyLocHeap
+externFP GetCurrentTask
+externFP InterruptUnRegister
+externFP NotifyUnRegister
+externNP SignalUnRegister
+externFP TaskFirst
+externFP TaskNext
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+
+.286p
+
+; HelperVerifySeg
+;
+; Verifies that a selector is valid and that the segment it points
+; to is safe for reading out to wcb bytes offset
+; Returns 0 if too short or the length of the segment.
+; Preserves all used registers except the return value, AX
+
+cProc HelperVerifySeg, <PUBLIC,NEAR>, <dx>
+ parmW wSeg
+ parmW wcb
+cBegin
+ ;** Verify that this is a valid selector and that it is long enough
+ cCall HelperSegLen, <wSeg> ;Check the segment
+ or dx,dx ;>64K? If so, always return OK
+ jnz HVS_End
+ cmp ax,wcb ;Long enough?
+ ja HVS_End ;Yes, return the length
+HVS_Bad:
+ xor ax,ax ;No. Return FALSE
+HVS_End:
+cEnd
+
+
+; HelperHandleToSel
+; Converts a handle to a selector. This routine knows how to
+; handle 3.0 and 3.1 differences as well as 286 & 386 differences.
+
+cProc HelperHandleToSel, <NEAR,PUBLIC>, <ds>
+ parmW h ;Handle
+cBegin
+ mov ax,_DATA ;Get the data segment
+ mov ds,ax ;Point with DS
+ mov ax,h ;Get the handle
+ test wTHFlags,TH_WIN30 ;Win3.0?
+ jz HTS_Win31 ;No
+ test ax,1 ;Check the low bit
+ jnz HTS_End ;It's already a selector
+ dec ax ;Decrement for proper selector
+ jmp SHORT HTS_End ;Out of here
+
+HTS_Win31:
+ or ax,1 ;Set the bit
+
+HTS_End:
+
+cEnd
+
+
+; HelperVerifyLocHeap
+;
+; Uses the processor-specific local heap verify routine to check the
+; validity of a local heap.
+;
+; Call:
+; AX = Block handle or selector
+; DS must point to TOOLHELP's DGROUP
+; Return:
+; Carry flag set iff NOT a local heap segment
+;
+; Destroys all registers except AX, ESI, EDI, DS, and ES
+
+HelperVerifyLocHeap PROC Near
+ PUBLIC HelperVerifyLocHeap
+
+ test wTHFlags,TH_KERNEL_386 ;Are we using KRNL386?
+ jz HVL_286 ;No
+ jmp Walk386VerifyLocHeap ;Jump to the 386 routine
+
+HVL_286:
+ jmp Walk286VerifyLocHeap ;Jump to the 286 routine
+
+HVL_End:
+ ret
+
+HelperVerifyLocHeap ENDP
+
+
+; HelperGlobalType
+;
+; Given data about a block, gropes around trying to decipher the
+; block type. Parameters are passed and returned in the GLOBALENTRY
+; structure.
+
+cProc HelperGlobalType, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpGlobal
+ localV Task,<SIZE TASKENTRY>
+cBegin
+ lds si,lpGlobal ;Get the pointer
+ mov [si].ge_wData,0 ;Clear the wData field
+ ; Zero's not a valid seg # or type #
+
+ ;** Check for internal block types
+ mov bx,[si].ge_hOwner ;Get the owner handle
+ mov ax,GT_SENTINEL ;Just in case...
+ cmp bx,GA_SENTINAL ;Is this a sentinel?
+ jz HGT_JmpEnd ;Yes, get out
+ mov ax,GT_BURGERMASTER ;Just in case...
+ cmp bx,GT_BURGERMASTER ;Burgermaster?
+ jz HGT_JmpEnd ;Yes, get out
+ cmp bx,-7 ;Lowest number reserved
+ jb HGT_0 ;Not an internal block
+ mov ax,GT_INTERNAL ;Internal KERNEL block type
+HGT_JmpEnd:
+ jmp HGT_End ;Get out
+HGT_0:
+
+ ;** Check for a free block
+ or bx,bx ;Check for 0: Free block
+ jnz HGT_2 ;Not zero
+ mov ax,GT_FREE ;Free blocks have zero owner
+ jmp HGT_End ;Unknown type
+HGT_2:
+
+ ;** Check for DGROUP and other data segments
+ mov ax,[si].ge_wFlags ;Get the block flags
+ test ax,GAH_DGROUP ;Is this a DGROUP segment
+ jnz @F
+ jmp HGT_10 ;Didn't find it so continue
+@@:
+
+ ;** Save the segment number of the segment
+ mov ax,[si].ge_hOwner ;Get the module database
+ push ax ;Save for later
+ mov bx,[si].ge_hBlock ;Get the handle
+ cCall HelperGetSegNumber ;Get the segment number
+ mov [si].ge_wData,ax ;Save the segment number
+ pop bx ;Get hExe back in BX
+
+ ;** Try two methods: First, see if it is the hInst of the FIRST
+ ;** instance of its module
+ lsl cx, bx ;Is this segment OK?
+ jnz HGT_5 ;No, punt and call it unknown data
+ cmp cx, ne_pautodata ;Long enough?
+ jbe HGT_5 ;No, get out
+ mov es,bx ;Point with ES
+ cmp es:[ne_magic],NEMAGIC ;Make sure we have a module database
+ jnz HGT_5 ;It isn't so get out
+ mov bx,es:[ne_pautodata] ;Point to the segment table entry
+ or bx,bx ;Is there a DGROUP segment?
+ jz HGT_5 ;No, flag as unknown data
+ mov ax,es:[bx].ns_handle ;Get the handle from the table
+ cmp ax,[si].ge_hBlock ;Does the DGROUP handle point here?
+ jnz HGT_3 ;No, might be multiple instance
+ mov ax,GT_DGROUP ;Matches, must be DGROUP
+ jmp HGT_End ;Get out
+HGT_3:
+ ;** It's not the first instance of this module.
+ ;** All multiple instance things will be on the task list
+ ;** so try to find it there.
+ mov bx,[si].ge_hBlock ;Get the handle
+ cCall HelperHandleToSel,<bx> ;Get the selector for this
+ mov di,ax ;Save in DI
+ mov ax,SIZE TASKENTRY ;Get the struct size
+ mov WORD PTR Task.te_dwSize[0],ax ;Put in struct
+ mov WORD PTR Task.te_dwSize[2],0 ;Clear high word
+ lea ax,Task ;Get the structure
+ cCall TaskFirst, <ss,ax> ;Get the first task's info
+ or ax,ax ;No tasks?
+ jz HGT_5 ;Just call it data (not DGROUP)
+HGT_TaskLoop:
+ mov ax,Task.te_hInst ;Get this task's hInst
+ cCall HelperHandleToSel, <ax> ;Convert to selector
+ cmp ax,di ;Is this a match?
+ je HGT_TaskFound ;Yes, do it
+ lea ax,Task ;Point to the struct
+ cCall TaskNext, <ss,ax> ;Get the next one
+ or ax,ax ;End of the line?
+ jnz HGT_TaskLoop ;Nope, do the next one
+HGT_5: mov ax,GT_DATA ;Unknown data segment
+ jmp HGT_End ;Get out
+HGT_TaskFound:
+ mov ax,GT_DGROUP ;Matches, must be DGROUP
+ jmp HGT_End ;Get out
+HGT_10:
+
+ ;** Check for a task database
+ mov ax,[si].ge_hBlock ;Get the segment
+ mov bx,TDBSize ;Get the limit to verify
+ push ax ;Save the segment
+ cCall HelperVerifySeg <ax,bx> ;Make sure we can check signature
+ pop bx ;Retrieve the segment value
+ or ax,ax ;Zero return means bad
+ jz HGT_20 ;Not a task database
+ mov es,bx ;Point to the segment
+ cmp es:[TDB_sig],TDB_SIGNATURE ;Is this really a TDB?
+ jnz HGT_20 ;Nope, go on
+ mov ax,GT_TASK ;Set the task flag
+ jmp HGT_End ;Get out
+HGT_20:
+
+ ;** Now check for Module database
+ mov ax,[si].ge_hOwner ;Get the owner handle
+ cCall HelperHandleToSel, <ax> ;Convert to selector for compare
+ mov cx,ax ;Save in CX
+ mov ax,[si].ge_hBlock ;Does this block own itself?
+ cCall HelperHandleToSel, <ax> ;Convert to selector for compare
+ cmp ax,cx ;Do the pointers match?
+ jnz HGT_24 ;No, so it's not a module database
+ mov ax,GT_MODULE ;Set type
+ jmp HGT_End ;Get out
+HGT_24:
+
+ ;** Check for a code segment. If found, return segment number
+ mov ax,[si].ge_hOwner ;Get the module database
+ push ax ;Save the selector
+ cCall HelperVerifySeg <ax,2> ;Make sure this is OK to put in ES
+ pop bx ;Retrieve in BX
+ or ax,ax ;Zero means bad
+ jnz @F
+ jmp SHORT HGT_Unknown
+@@: mov es,bx ;Point with ES
+ xor dx,dx ;Use DX to count segments
+ cmp es:[ne_magic],NEMAGIC ;Make sure we have a module database
+ jz HGT_25 ;Looks good
+ jmp SHORT HGT_40 ;Not code or resource, try next
+HGT_25: mov cx,es:[ne_cseg] ;Get max number of segments
+ jcxz HGT_30 ;No segments
+ mov di,es:[ne_segtab] ;Point to the segment table
+ mov bx,[si].ge_hBlock ;Get the block we're looking for
+HGT_SegLoop:
+ inc dx ;Bump the segment number
+ cmp bx,es:[di].ns_handle ;Is this the correct segment entry?
+ jz HGT_27 ;Yes, get out
+ add di,SIZE new_seg1 ;Bump to next entry
+ loop HGT_SegLoop ;Loop back to check next entry
+ jmp SHORT HGT_30 ;Now check resources
+HGT_27:
+ mov [si].ge_wData,dx ;Save the segment count
+ mov ax,GT_CODE ;Flag that it's a code segment
+ jmp SHORT HGT_End ;Get out
+
+ ;** Check to see if it's a resource. If so, return resource type #
+HGT_30: mov di,es:[ne_rsrctab] ;Point to the resource table
+ cmp di,es:[ne_restab] ;If both point to same place, no rsrc
+ jz HGT_40 ;No resource table -- unknown type
+ add di,2 ;Skip past alignment count
+HGT_TypeLoop:
+ mov dx,es:[di].rt_id ;DX holds current type number
+ or dx,dx ;Zero type means end of res table
+ jz HGT_40 ;Not found so get out!
+ mov cx,es:[di].rt_nres ;Get the number of resources
+ add di,SIZE RSRC_TYPEINFO ;Bump past the structure
+HGT_ResLoop:
+ cmp bx,es:[di].rn_handle ;Is it this resource?
+ jz HGT_FoundRes ;Yep. This is the one
+ add di,SIZE RSRC_NAMEINFO ;Bump past this structure
+ loop HGT_ResLoop ;Loop for next resource structure
+ jmp HGT_TypeLoop ;Try the next type
+
+ ;** Found the resource, now compute the resource type
+HGT_FoundRes:
+ test dx,RSORDID ;If this bit set, must be ordinal type
+ jnz HGT_32 ;Yep. Ordinal
+ mov dx,GD_USERDEFINED ;Named resources are all user-def
+HGT_32: and dx,NOT RSORDID ;Clear the flag bit
+ cmp dx,GD_MAX_RESOURCE ;If the type is too big, it's user-def
+ jbe HGT_34 ;Standard type
+ mov dx,GD_USERDEFINED ;User-defined resource type
+HGT_34: mov [si].ge_wData,dx ;Save the type
+ mov ax,GT_RESOURCE ;Return that it's a resource
+ jmp SHORT HGT_End ;Get out
+
+HGT_40:
+HGT_Unknown:
+ mov ax,GT_UNKNOWN ;Unknown type
+HGT_End:
+ mov [si].ge_wType,ax ;Save the type and exit
+cEnd
+
+
+; HelperGrabSelector
+;
+; Allocates a selector from DPMI.
+
+cProc HelperGrabSelector, <NEAR,PUBLIC>
+cBegin
+ xor ax,ax ;DPMI Function 0, allocate LDT sels
+ mov cx,1 ;Just 1 sel
+ int 31h ;Call DPMI. Selector in AX
+cEnd
+
+
+; HelperReleaseSelector
+;
+; Frees a selector to DPMI
+
+cProc HelperReleaseSelector, <NEAR,PUBLIC>
+ parmW wSelector
+cBegin
+ mov ax,1 ;DPMI function 1, free LDT sels
+ mov bx,wSelector ;Get the sel
+ int 31h ;Free it
+cEnd
+
+; HelperSetSignalProc
+; Puts a signal proc in a task's TDB so that it gets called in place
+; of USER's proc. Returns the old USER proc.
+
+cProc HelperSetSignalProc, <NEAR,PUBLIC>, <si,di>
+ parmW hTask,
+ parmD lpfn
+cBegin
+ ;** Point to the TDB
+ mov es,hTask ;Point with ES
+
+ ;** Swap the new with the old and return the old one
+ mov ax,WORD PTR lpfn ;Get the new signal proc
+ xchg ax,WORD PTR es:[TDB_USignalProc] ;Switch with the old one
+ mov dx,WORD PTR lpfn + 2 ;Get HIWORD
+ xchg dx,WORD PTR es:[TDB_USignalProc + 2] ;Switch with old one
+cEnd
+
+
+; HelperSignalProc
+; Cleans up when a TOOLHELP-using app is terminated. This proc
+; MUST chain on to USER's signal proc. Note that action is only taken
+; on the death signal (BX = 0666h)
+
+cProc HelperSignalProc, <FAR,PUBLIC>
+cBegin NOGEN
+
+ ;** Save all registers
+ sub sp,4
+ push bp
+ mov bp,sp ;Make a stack frame
+ pusha
+ push ds
+ push es
+
+ ;** Get a pointer to the correct SIGNAL structure
+ mov ax,_DATA ;Get the TOOLHELP.DLL DS
+ mov ds,ax ;Point with DS
+ cCall GetCurrentTask ;Get the current task in AX
+ mov di,ax ;Save task in DI
+ mov si,npSignalHead ;Get the first struct
+HSP_SigLoop:
+ or si,si ;End of the list?
+ jz HSP_Return ;Yes -- This is bad!!
+ cmp di,[si].si_hTask ;Task match?
+ je HSP_FoundIt ;Yes
+ mov si,[si].si_pNext ;Get the next one
+ jmp HSP_SigLoop ;Loop around
+
+ ;** Compute the fake return address (old signal proc)
+HSP_FoundIt:
+ mov ax,WORD PTR [si].si_lpfnOld ;Get LOWORD of old proc
+ mov [bp + 2],ax ;Put on stack frame
+ mov dx,WORD PTR [si].si_lpfnOld + 2 ;Get HIWORD of old proc
+ mov [bp + 4],dx ;Put on stack frame
+
+ ;** See if we have the death signal. If not, don't do anything
+ ;** but just chain on. 20h is the signal for task exit
+ cmp bx, 20h ;Is this the death signal?
+ jne HSP_Done ;No. Don't cleanup
+
+ ;** Since we have a death signal, use it to clean up everything
+ push ax ;Save the return address
+ push dx
+ cCall InterruptUnRegister, <di> ;Unregister any interrupt callbacks
+ cCall NotifyUnRegister, <di> ;Unregister any notification callbacks
+ cCall SignalUnRegister, <di> ;Unregister any signal callbacks
+
+ ;** If we have fooled with the LRU lock (we only do this on 286
+ ;** machines), we must force it unlocked.
+ cmp wLRUCount, 0 ;Is it set?
+ je HSP_NoLRUFoolingAround ;No, don't mess with this
+ mov es, hMaster ;Point to GlobalInfo struct
+ mov ax, es:[gi_lrulock] ;Get current lock count
+ sub ax, wLRUCount ;Get rid of the amount we messed it up
+ jns @F ;Result is OK--no underflow
+ xor ax, ax ;We don't like negative, so zero it
+@@: mov es:[gi_lrulock], ax ;Save the result
+ mov wLRUCount, 0 ;No more LRU count
+HSP_NoLRUFoolingAround:
+ pop dx
+ pop ax
+
+ ;** Make sure we have a proc to chain to
+HSP_Done:
+ or ax,dx ;NULL pointer?
+ jz HSP_Return ;Yes, don't chain to this one
+
+HSP_ChainOn:
+ pop es
+ pop ds
+ popa
+ pop bp
+ retf ;Jump to next signal proc
+
+HSP_Return:
+ pop es
+ pop ds
+ popa
+ pop bp
+ add sp,4 ;Clear fake return address
+ retf 10 ;Return to signal caller
+
+cEnd NOGEN
+
+
+; HelperSegLen
+; Gets the length of a segment, regardless whether it is a 286 or
+; 386 segment.
+; Returns the DWORD length of the segment or zero on error.
+; Doesn't trash registers except DX:AX
+
+cProc HelperSegLen, <NEAR,PUBLIC>, <si,di,cx>
+ parmW wSeg
+cBegin
+ ;** Make sure the segment is present
+ mov cx,wSeg ;Get the selector
+ lar ax,cx ;Get the access rights
+ jnz HSL_Bad ;If LAR fails, this is bad
+ test ax,8000h ;Is this segment present?
+ jz HSL_Bad ;No, call it bad
+
+ ;** Do different stuff on 286 and 386/486
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_CPU286 ;286?
+ jnz HSL_Do286 ;Yes, do 16 bit stuff
+
+ ;** Get the 32 bit length
+.386p
+ lsl eax,ecx ;Get the limit
+ jnz SHORT HSL_Bad ;We have an error
+ mov edx,eax ;Get HIWORD in DX
+ shr edx,16
+ jmp SHORT HSL_End ;Done
+.286p
+
+ ;** Get the 16 bit length
+HSL_Do286:
+ xor dx,dx ;286 never has >64K segs
+ lsl ax,cx ;Get the limit
+ jnz HSL_Bad ;Bad if LSL fails
+ jmp SHORT HSL_End ;Done
+
+HSL_Bad:
+ xor ax,ax ;Zero return value
+ xor dx,dx
+
+HSL_End:
+
+cEnd
+
+; HelperGetSegNumber
+;
+; Returns the segment number corresponding to a selector given the
+; hExe.
+;
+; Caller: AX=hExe, BX=Handle
+; Exit: AX=Seg Number or 0
+
+cProc HelperGetSegNumber, <NEAR,PUBLIC>, <di>
+cBegin
+ lsl cx, ax ;Is the segment OK to load?
+ jnz HGSN_Error ;No, don't do it
+ cmp cx, ne_segtab ;Long enough?
+ jbe HGSN_Error ;No
+ mov es,ax ;Point with ES
+ xor dx,dx ;Use DX to count segments
+ cmp es:[ne_magic],NEMAGIC ;Make sure we have an hExe
+ jnz HGSN_Error ;Nope, get out
+ mov cx,es:[ne_cseg] ;Get max number of segments
+ jcxz HGSN_Error ;No segments
+ mov di,es:[ne_segtab] ;Point to the segment table
+HGSN_SegLoop:
+ inc dx ;Bump the segment number
+ cmp bx,es:[di].ns_handle ;Is this the correct segment entry?
+ je HGSN_FoundIt ;Yes, get out
+ add di,SIZE new_seg1 ;Bump to next entry
+ loop HGSN_SegLoop ;Loop back to check next entry
+ jmp SHORT HGSN_Error ;Not found
+
+HGSN_FoundIt:
+ mov ax,dx ;Get segment number
+ jmp SHORT HGSN_End
+
+HGSN_Error:
+ xor ax,ax ;Error return
+
+HGSN_End:
+cEnd
+
+;** Internal helper functions
+
+; HelperPDBtoTDB
+;
+; Takes a PDB handle and finds the task handle associated with it.
+; Caller: AX = PDB Handle
+; Return: AX = TDB handle or zero if no TDB exists for it
+
+cProc HelperPDBtoTDB, <NEAR,PUBLIC>
+cBegin
+ ;** Point to the first TDB
+ mov dx,_DATA ;Get the library static segment
+ mov es,dx ;Point with ES
+ mov bx,es:[npwTDBHead] ;Get pointer to first TDB
+ mov dx,es:[segKernel] ;Get the KERNEL data segment
+ mov es,dx ;Point with ES
+ mov dx,es:[bx] ;Get the first TDB
+
+ ;** Check this TDB's PDB to see if it matches
+PT_Loop:
+ mov es,dx ;Get the TDB segment
+ cmp ax,es:[TDB_PDB] ;Compare PDB pointers
+ jz PT_Found ;This is it
+ mov dx,es:[TDB_next] ;Get the next TDB
+ or dx,dx ;End of the line?
+ jnz PT_Loop ;Nope, loop back
+ xor ax,ax ;Return NULL'
+ jmp SHORT PT_End ;Outta here
+
+PT_Found:
+ mov ax,es ;Save the found value
+PT_End:
+
+cEnd
+
+sEnd
+
+ END
diff --git a/private/mvdm/wow16/toolhelp/int1.c b/private/mvdm/wow16/toolhelp/int1.c
new file mode 100644
index 000000000..3acd50307
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/int1.c
@@ -0,0 +1,153 @@
+/**************************************************************************
+ * INT1.C
+ *
+ * Routines used to implement the interrupt trapping API in
+ * TOOLHELP.DLL
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include "toolpriv.h"
+
+/* ----- Global variables ----- */
+ WORD wIntInstalled;
+ INTERRUPT NEAR *npIntHead;
+
+/* InterruptRegister
+ * Registers an interrupt callback.
+ */
+
+BOOL TOOLHELPAPI InterruptRegister(
+ HANDLE hTask,
+ FARPROC lpfnCallback)
+{
+ INTERRUPT *pInt;
+ INTERRUPT *pTemp;
+
+ /* Make sure TOOLHELP.DLL is installed */
+ if (!wLibInstalled)
+ return FALSE;
+
+ /* If the interrupt hook has not yet been installed, install it */
+ if (!wIntInstalled)
+ {
+ /* Make sure we can hook! */
+ if (!InterruptInit())
+ return FALSE;
+ wIntInstalled = TRUE;
+ }
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* Register a death signal handler for this task (does nothing if one
+ * is already installed.
+ */
+ SignalRegister(hTask);
+
+ /* Check to see if this task is already registered */
+ for (pInt = npIntHead ; pInt ; pInt = pInt->pNext)
+ if (pInt->hTask == hTask)
+ return FALSE;
+
+ /* Allocate a new INTERRUPT structure */
+ pInt = (INTERRUPT *)LocalAlloc(LMEM_FIXED, sizeof (INTERRUPT));
+ if (!pInt)
+ return FALSE;
+
+ /* Fill in the useful fields */
+ pInt->hTask = hTask;
+ pInt->lpfn = lpfnCallback;
+
+ /* If this is the only handler, just insert it */
+ if (!npIntHead)
+ {
+ pInt->pNext = npIntHead;
+ npIntHead = pInt;
+ }
+
+ /* Otherwise, insert at the end of the list */
+ else
+ {
+ for (pTemp = npIntHead ; pTemp->pNext ; pTemp = pTemp->pNext)
+ ;
+ pInt->pNext = pTemp->pNext;
+ pTemp->pNext = pInt;
+ }
+
+ return TRUE;
+}
+
+
+/* InterruptUnRegister
+ * Called by an app whose callback is no longer to be used.
+ * NULL hTask uses current task.
+ */
+
+BOOL TOOLHELPAPI InterruptUnRegister(
+ HANDLE hTask)
+{
+ INTERRUPT *pInt;
+ INTERRUPT *pBefore;
+
+ /* Make sure we have interrupt installed and that TOOLHELP is OK */
+ if (!wLibInstalled || !wIntInstalled)
+ return FALSE;
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* First try to find the task */
+ pBefore = NULL;
+ for (pInt = npIntHead ; pInt ; pInt = pInt->pNext)
+ if (pInt->hTask == hTask)
+ break;
+ else
+ pBefore = pInt;
+ if (!pInt)
+ return FALSE;
+
+ /* Unhook the death signal proc only if there is no interrupt handler */
+ if (!NotifyIsHooked(hTask))
+ SignalUnRegister(hTask);
+
+ /* Remove it from the list */
+ if (!pBefore)
+ npIntHead = pInt->pNext;
+ else
+ pBefore->pNext = pInt->pNext;
+
+ /* Free the structure */
+ LocalFree((HANDLE)pInt);
+
+ /* If there are no more handlers, unhook the callback */
+ if (!npIntHead)
+ {
+ InterruptUnInit();
+ wIntInstalled = FALSE;
+ }
+
+ return TRUE;
+}
+
+/* ----- Helper functions ----- */
+
+/* InterruptIsHooked
+ * Returns TRUE iff the parameter task already has a interrupt hook.
+ */
+
+BOOL PASCAL InterruptIsHooked(
+ HANDLE hTask)
+{
+ INTERRUPT *pInt;
+
+ /* Loop thorugh all interrupts */
+ for (pInt = npIntHead ; pInt ; pInt = pInt->pNext)
+ if (pInt->hTask == hTask)
+ break;
+
+ /* Return found/not found */
+ return (BOOL)pInt;
+}
diff --git a/private/mvdm/wow16/toolhelp/int2.asm b/private/mvdm/wow16/toolhelp/int2.asm
new file mode 100644
index 000000000..25e52ffea
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/int2.asm
@@ -0,0 +1,1088 @@
+ PAGE 60,150
+;***************************************************************************
+;* INT2.ASM
+;*
+;* Assembly code support routines used for the TOOLHELP.DLL interrupt
+;* trapping API
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE WINDOWS.INC
+ include vint.inc
+.286p
+
+;** Symbols
+I_EXCEPTION EQU 0
+I_INTERRUPT EQU 1
+MAX_INTERRUPT EQU 7
+GIVE_WDEB386 EQU 8000h
+BAD_STACK_FLAG EQU 8000h
+MIN_STACK_ALLOWED EQU 128
+
+;** Local types
+
+INT_INFO STRUC
+ii_wNumber DW ? ;INT nn
+ii_wType DW ? ;I_EXCEPTION or I_INTERRUPT
+ii_dwChain DD ?
+ii_wHandler DW ? ;Note that this is CS relative
+INT_INFO ENDS
+
+;** Data
+sBegin DATA
+
+IntInfo LABEL BYTE
+ public IntInfo
+UD_Info DW 6 ;Undefined opcode
+ DW I_EXCEPTION ;This should be DPMI-hooked
+ DD 0 ;Chain address (will be initialized)
+ DW OFFSET _TEXT:UD_Handler
+Div0_Info DW 0 ;Divide by zero
+ DW I_EXCEPTION ;Hook with DPMI
+ DW OFFSET _TEXT:Div0_Handler
+ DW 0
+ DW OFFSET _TEXT:Div0_Handler
+Int1_Info DW 1 ;Single step + debug register
+ DW I_INTERRUPT ;Hook with DOS
+ DD 0 ;Chain address
+ DW OFFSET _TEXT:Int1_Handler
+Int3_Info DW 3 ;Software debug int
+ DW I_INTERRUPT ;Hook with DOS
+ DD 0 ;Chain address
+ DW OFFSET _TEXT:Int3_Handler
+GP_Info DW 13 ;GP Fault
+ DW I_EXCEPTION ;This should be DPMI-hooked
+ ;** This entry is a special case entry for the Win30 std mode
+ ;* handler. This is a separate entry point into the
+ ;** interrupt handler routine
+ DW OFFSET _TEXT:GP_StdModeHandler
+ DW 0
+ DW OFFSET _TEXT:GP_Handler
+SF_Info DW 12 ;Stack fault
+ DW I_EXCEPTION ;This should be DPMI-hooked
+ ;** This entry is a special case entry for the Win30 std mode
+ ;* handler. This is a separate entry point into the
+ ;** interrupt handler routine
+ DW OFFSET _TEXT:SF_StdModeHandler
+ DW 0
+ DW OFFSET _TEXT:SF_Handler
+PF_Info DW 14 ;Page fault
+ DW I_EXCEPTION ;This should be DPMI-hooked
+ ;** This entry is a special case entry for the Win30 std mode
+ ;* handler. This is a separate entry point into the
+ ;** interrupt handler routine
+ DW OFFSET _TEXT:PF_StdModeHandler
+ DW 0
+ DW OFFSET _TEXT:PF_Handler
+CASRq_Info DW 256 ;CtlAltSysRq (fake interrupt)
+ DW I_INTERRUPT ;Hook with DOS
+ DD 0 ;Chain address
+ DW OFFSET _TEXT:CASRq_Handler
+
+ ;** The following data is used to see if GDI wants the
+ ;** Div0 we have trapped
+lpGDIFlag DD 0
+hGDI DW 0
+szGDI DB 'GDI', 0
+ public lpGDIFlag, hGDI
+
+ ;** Points to a KERNEL routine to see if it wants the
+ ;** GP fault first
+lpfnPV DD 0 ;Call to see if PV GP fault
+ public lpfnPV
+
+ ;** Globals used for DPMI emulation
+lpOldHandler DD 0 ;Previous DPMI exception handler
+lpChainCSIP DD 0 ;Next exception handler on chain
+wException DW 0
+ public lpOldHandler, lpChainCSIP
+
+externW wCASRqFlag ;Set when an CASRq INT3 has been set
+externD dwCASRqCSIP ;Holds the CS:IP of the CASRq INT3
+sEnd
+
+;** Imports
+externNP TerminateApp
+externNP HelperHandleToSel
+externNP HelperVerifySeg
+externFP AllocCStoDSAlias
+externFP FreeSelector
+externFP GetModuleHandle
+externFP GetProcAddress
+externFP GlobalEntryHandle
+externFP _wsprintf
+externFP OutputDebugString
+externA __WinFlags
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+;** Interrupt trapping API
+
+; InterruptInit
+; Hooks all necessary interrupts and exceptions to allow an API
+; for app-level interrupt hooks.
+
+cProc InterruptInit, <NEAR,PUBLIC>, <si,di>
+cBegin
+ ;** Loop through all possible handlers
+ mov cx,MAX_INTERRUPT ;Number of ints to hook
+ lea si,IntInfo ;Get the address of the array
+DII_HandlerLoop:
+ push cx ;Save loop counter
+ cmp [si].ii_wNumber,256 ;Fake exception?
+ jae DII_Continue ;Yes, don't hook anything!
+ cmp [si].ii_wType,I_EXCEPTION ;Exception?
+ jnz DII_Interrupt ;Nope, hook as interrupt
+
+ ;** Do a special case for 3.0 Std Mode
+ test wTHFlags,TH_WIN30STDMODE ;Are we in Win30 std mode?
+ jz DII_NotStdMode ;No.
+ mov ax,WORD PTR [si].ii_dwChain ;Get the secondary handler
+ mov [si].ii_wHandler,ax ;Make sure we use it instead!
+DII_NotStdMode:
+
+ ;** Hook as an exception (DPMI)
+ mov ax,0202h ;Get exception handler - DPMI
+ mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
+ int 31h ;Call DPMI
+ mov WORD PTR [si].ii_dwChain,dx ;Save the old offset
+ mov WORD PTR [si].ii_dwChain + 2,cx ;Save the old selector
+ mov ax,0203h ;Set exception handler - DPMI
+ mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
+ mov dx,[si].ii_wHandler ;Address of exception handler
+ mov cx,cs ;Selector value of handler
+ int 31h ;Call DPMI
+ jmp SHORT DII_Continue
+
+ ;** Hook as an interrupt (DOS)
+DII_Interrupt:
+ mov ah,35h ;Get interrrupt handler - DOS
+ mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
+ int 21h ;Call DOS
+ mov WORD PTR [si].ii_dwChain,bx ;Save the old offset
+ mov WORD PTR [si].ii_dwChain + 2,es ;Save the old selector
+ mov ah,25h ;Set interrupt handler - DOS
+ mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
+ mov dx,[si].ii_wHandler ;Address of exception handler
+ push ds ;Save static DS for later
+ push cs ;DS = CS
+ pop ds
+ int 21h ;Call DOS
+ pop ds ;Get segment back
+
+ ;** Prepare for next in table
+DII_Continue:
+ add si,SIZE INT_INFO ;Bump to next entry
+ pop cx ;Get loop counter back
+ loop DII_HandlerLoop ;Loop back
+
+ ;** Prepare the linked list
+ mov npIntHead,0 ;Put a NULL in the list head
+
+ ;** Get information so we can check the GDI flag
+ lea ax,szGDI ;Get the string
+ cCall GetModuleHandle, <ds,ax> ;Get GDI's module handle
+ cCall HelperHandleToSel, <ax> ;Convert the owner to a selector
+ mov hGDI,ax ;Save it for later
+ cCall GetProcAddress, <ax,0,355> ;The flag is ordinal 355
+ mov WORD PTR lpGDIFlag[0],ax ;Save it for later
+ mov WORD PTR lpGDIFlag[2],dx
+
+DII_End:
+ ;** Return TRUE
+ mov ax,1
+cEnd
+
+
+; InterruptUnInit
+; Unhooks all interrupts and exceptions hooked by DebugInterruptUnInit.
+
+cProc InterruptUnInit, <NEAR,PUBLIC>, <si,di>
+cBegin
+
+ ;** Loop through all possible handlers
+ mov cx,MAX_INTERRUPT ;Number of ints to hook
+ lea si,IntInfo ;Get the address of the array
+DIU_HandlerLoop:
+ push cx ;Save loop counter
+ cmp [si].ii_wNumber,256 ;Fake exception?
+ jae DIU_Continue ;Yes, don't unhook anything!
+ cmp [si].ii_wType,I_EXCEPTION ;Exception?
+ jnz DIU_Interrupt ;Nope, hook as interrupt
+
+ ;** Unhook exception (DPMI)
+ mov ax,0203h ;Set exception handler - DPMI
+ mov bl,BYTE PTR [si].ii_wNumber ;Interrupt number
+ mov dx,WORD PTR [si].ii_dwChain ;Put back the old offset
+ mov cx,WORD PTR [si].ii_dwChain + 2 ;Put back the old selector
+ int 31h ;Call DPMI
+ jmp SHORT DIU_Continue
+
+ ;** Unhook interrupt (DOS)
+DIU_Interrupt:
+ mov ah,35h ;Get interrrupt handler - DOS
+ mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
+ int 21h ;Call DOS
+ mov ah,25h ;Set interrupt handler - DOS
+ mov al,BYTE PTR [si].ii_wNumber ;Interrupt number
+ mov dx,WORD PTR [si].ii_dwChain ;Put back the old offset
+ push ds
+ mov ds,WORD PTR [si].ii_dwChain + 2 ;Put back the old selector
+ int 21h ;Call DOS
+ pop ds
+
+ ;** Prepare for next in table
+DIU_Continue:
+ add si,SIZE INT_INFO ;Bump to next entry
+ pop cx ;Get loop counter back
+ loop DIU_HandlerLoop ;Loop back
+
+ ;** Prepare the linked list
+ mov npIntHead,0 ;Put a NULL in the list head
+
+DIU_End:
+
+cEnd
+
+InterruptEntry MACRO Name, wBytes
+ labelFP Name ;;Start at this address
+ PUBLIC Name
+ sub sp,wBytes ;;Leave room on stack for return val
+ push bx ;;Save for the info pointer
+ENDM
+
+InterruptJump MACRO pInfo
+ mov bx,OFFSET pInfo ;;Point to interrupt info
+ jmp DIH_Main
+ENDM
+
+; InterruptHandler
+; This routine is used to handle interrupts as they come in. This
+; routine has multiple entry points; a seperate one for each int/
+; exception trapped. Because interrupts and exceptions have
+; different stack frames, they are handled by two different code
+; sections.
+
+cProc InterruptHandler, <FAR,PUBLIC>
+cBegin NOGEN
+
+ ;** All interrupt entry points here
+
+ InterruptEntry GP_Handler, 14 ;Normal GP fault
+ InterruptJump GP_Info
+ InterruptEntry GP_StdModeHandler, 12 ;3.0 Std mode GP fault
+ InterruptJump GP_Info
+ InterruptEntry SF_Handler, 14 ;Normal Stack Fault
+ InterruptJump SF_Info
+ InterruptEntry SF_StdModeHandler, 12 ;3.0 Std mode Stack Fault
+ InterruptJump SF_Info
+ InterruptEntry PF_Handler, 14 ;Page fault
+ InterruptJump PF_Info
+ InterruptEntry PF_StdModeHandler, 10 ;3.0 Std mode Page fault
+ InterruptJump PF_Info
+ InterruptEntry UD_Handler, 14 ;Undefined opcode
+ InterruptJump UD_Info
+ InterruptEntry Int1_Handler, 14 ;Int 1
+ InterruptJump Int1_Info
+ InterruptEntry Int3_Handler, 14 ;Int 3
+ InterruptJump Int3_Info
+ InterruptEntry CASRq_Handler, 14 ;Ctrl-Alt-SysRq (not really an int)
+ InterruptJump CASRq_Info
+
+ ;** The divide by zero case has to include checking to make sure
+ ;** that this isn't GDI's divide by zero.
+
+ InterruptEntry Div0_Handler, 14
+
+ ;** Check to see if GDI wants this Div0
+ push ds ;Save some registers
+ push es
+ mov bx,_DATA ;Point to our data
+ mov ds,bx ; with DS
+ mov bx,WORD PTR lpGDIFlag[0];Get the low word
+ push bx
+ or bx,WORD PTR lpGDIFlag[2];Do we have a flag to look at?
+ pop bx
+ jz DIH_NoFlag ;No. Do this the hard way
+
+ ;** Since we have a pointer to GDI's flag to look at, use it
+ mov es,WORD PTR lpGDIFlag[2];Get the seg value
+ cmp WORD PTR es:[bx],0 ;The flag is nonzero if GDI wants it
+ je DIH_NormalDiv0 ;GDI doesn't want it
+
+ ;** GDI wants the Div0 so chain to it
+DIH_ChainToGDI:
+ pop es ;Restore registers
+ pop ds ; (Doesn't trash flags)
+ push bp ;Make the same stack frame for compat
+ mov bp,sp
+ pusha ;Save all registers
+ push ds
+ push es
+ mov ax,_DATA ;Get the data segment
+ mov ds,ax ;Point with DS
+ mov bx,OFFSET Div0_Info ;This fault's info
+ jmp DIH_DPMIChainOn ;Chain on (ignore the int)
+
+DIH_NormalDiv0:
+ pop es ;Restore registers
+ pop ds
+ InterruptJump Div0_Info
+
+ ;** We didn't get a GDI flag (only present in 3.1) so instead, we
+ ;* check the owner of the CS where the fault occurred. If
+ ;** the owner is GDI, we ignore the Div0.
+DIH_NoFlag:
+ push bp ;Make a stack frame
+ mov bp,sp
+ sub sp,SIZE GLOBALENTRY ;Make room for a structure
+Global EQU [bp - SIZE GLOBALENTRY] ;Point to our structure
+ pusha ;Save all registers
+ mov WORD PTR Global.ge_dwSize[0],SIZE GLOBALENTRY ;Size of struct
+ mov WORD PTR Global.ge_dwSize[2],0
+ lea bx,Global ;Point to the structure
+ test wTHFlags,TH_WIN30STDMODE ;3.0 std mode?
+ jnz DIH_Div0_StdMode ;Yes
+ mov ax,[bp + 1ah + 4] ;Get the CS value (4 is extra BP,BX
+ jmp SHORT @F ; pushed by InterruptEntry macro)
+DIH_Div0_StdMode:
+ mov ax,[bp + 14h + 4] ;Get the CS value
+@@: cCall GlobalEntryHandle, <ss,bx,ax> ;Get info about the CS
+ or ax,ax ;Did the call succeed?
+ jne @F ;Yes, go on
+ popa ;No, clear stack frame and do normal
+ mov sp,bp
+ pop bp
+ jmp DIH_NormalDiv0 ;Jump to normal processing
+@@: mov ax,Global.ge_hOwner ;Get the owner
+ cCall HelperHandleToSel, <ax> ;Make it a selector
+ cmp hGDI,ax ;Is this owned by GDI?
+ popa ;Restore the registers
+ mov sp,bp ;Clear stack frame
+ pop bp
+ je DIH_ChainToGDI ;Yes, so give the interrupt to it
+ jmp DIH_NormalDiv0 ;No, do normal stuff
+
+ ;** We now have to first find the item on the block to see if we
+ ;** want to handle the interrupt.
+PubLabel CommonInterruptEntry
+DIH_Main:
+ push bp ;Make a stack frame
+ mov bp,sp
+ pusha ;Save all registers
+ push ds
+ push es
+
+ ;** We check first to see if this was a GP fault received from the
+ ;* parameter validation code. If it was, we just chain on
+ ;* just as if we don't find any handlers.
+ ;**
+ mov ax,_DATA ;Get our data segment
+ mov ds,ax
+ FSTI ;Must have interrupts on
+ cmp bx,OFFSET GP_Info ;GP Fault?
+ jnz DIH_NotPVGPFault ;No.
+ mov cx,WORD PTR lpfnPV[0] ;Get the low word
+ or cx,WORD PTR lpfnPV[2] ;Param Validation stuff present?
+ jz DIH_NotPVGPFault ;No, skip this
+
+ ;** Check to see if the parameter validation code wants the fault
+ push ds
+ push bx
+ push [bp + 1Ah] ;Push faulting CS:IP
+ push [bp + 18h]
+ call [lpfnPV] ;Call it
+ pop bx
+ pop ds
+ or ax,ax ;Non-zero means this was PV fault
+ je DIH_NotPVGPFault ;Not a PV GP fault
+
+ ;** It is a parameter validation fault so ignore it
+ jmp DIH_DPMIChainOn ;Chain the fault on--we don't want it
+
+ ;** We check here to see if the INT3 we received is from the CASRq
+ ;* handler. If it was, we have to replace the INT3 with the
+ ;* previous byte and tell the user this was actually a CASRq
+ ;** event (not an INT3).
+PubLabel DIH_NotPVGPFault
+ cmp bx,OFFSET Int3_Info ;INT3?
+ jnz DIH_NotCASRq ;Nope, ignore all this
+ cmp wCASRqFlag,0 ;Was this because of CASRq?
+ je DIH_NotCASRq ;No.
+ mov ax,[bp + 12h] ;INT3 is an IRET frame. Get bkpt IP
+ dec ax ;Breaks AFTER instruction
+ cmp WORD PTR dwCASRqCSIP[0],ax ;Is this the right CASRq address?
+ jne DIH_NotCASRq ;Nope
+ mov dx,[bp + 14h] ;Get the breakpoint CS
+ cmp WORD PTR dwCASRqCSIP[2],dx ;Is this correct?
+ jne DIH_NotCASRq ;Nope
+ push ax ;Save the IP value
+ cCall AllocCStoDSAlias, <dx> ;Get a data alias to the CS
+ mov es,ax ;Point with ES
+ pop si ;Restore the IP value
+ mov [bp + 12h],si ;Back to instr where INT3 was
+ mov al,BYTE PTR wCASRqFlag ;Get the saved byte
+ mov es:[si],al ;Put it back in the code
+ mov wCASRqFlag,0 ;Clear the flag
+ cCall FreeSelector, <es> ;Get rid of the alias
+ mov bx,OFFSET CASRq_Info ;Point to the CASRq information
+
+ ;** See if we have at least one handler. We should always have one.
+PubLabel DIH_NotCASRq
+ mov si,npIntHead ;Get the list start
+ or si,si ;Are there any routines hooked?
+ jnz DIH_Found ;There should ALWAYS be at least one
+ ; routine hooked (otherwise, the
+ ; interrupt hooks should have
+ ; already been removed)
+
+ ;** Return the stack to its prior state and chain on.
+ ;* We only get here in an erroneous state. We keep the code in
+ ;* to avoid GP faulting if things get wierd.
+ ;* The stack looks like this:
+ ;* ------------
+ ;* | ES |
+ ;* | DS |
+ ;* | PUSHA |
+ ;* BP-->| Old BP | [BP + 00h]
+ ;* | BX | [BP + 02h]
+ ;* | Empty | [BP + 04h]
+ ;* | Empty | [BP + 06h]
+ ;* | Empty | [BP + 08h]
+ ;* | Empty | [BP + 0Ah]
+ ;* | Empty | [BP + 0Ch]
+ ;* |Our Ret IP| [BP + 0Eh]
+ ;* |Our Ret CS| [BP + 10h]
+ ;* |Original |
+ ;* | Frame |
+ ;* | .... |
+ ;* ------------
+ ;**
+PubLabel DIH_DPMIChainOn
+ mov ax,WORD PTR [bx].ii_dwChain ;Get the LOWORD
+ mov [bp + 0eh],ax ;Put into the frame we created
+ mov ax,WORD PTR [bx].ii_dwChain + 2 ;Get the HIWORD
+ mov [bp + 10h],ax ;Put into the frame
+ pop es ;Clear the stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,10 ;Clear extra space
+ retf ;This uses our own "return" frame
+ ; to chain on
+
+ ;** Since we found the entry, we have to call the user callback.
+ ;* Because we must be reentrant at this state, we have to make
+ ;* sure that we're safe. To do so, we must do different
+ ;** actions for DPMI and for DOS frames.
+PubLabel DIH_Found
+ cmp [bx].ii_wType,I_EXCEPTION ;DPMI Exception frame?
+ je @F
+ jmp DIH_SkipDPMI ;No. Skip DPMI processing
+@@:
+
+ ;** If we are in Win3.0 Std Mode, the DPMI frame was broken. It
+ ;* simply left the normal IRET frame on the stack *AND* the
+ ;** error code.
+ test wTHFlags,TH_Win30StdMode ;3.0 Std mode?
+ jz @F
+ jmp DIH_SkipDPMI ;Yes
+@@:
+
+ ;** Tell DPMI that the exception is over. Before we do this,
+ ;* however, save information we'll need later on the user stack.
+ ;* The stack currently looks like this:
+ ;* ------------
+ ;* | ES |
+ ;* | DS |
+ ;* | PUSHA |
+ ;* BP-->| Old BP | [BP + 00h]
+ ;* | BX | [BP + 02h]
+ ;* | Empty | [BP + 04h]
+ ;* | Empty | [BP + 06h]
+ ;* | Empty | [BP + 08h]
+ ;* | Empty | [BP + 0Ah]
+ ;* | Empty | [BP + 0Ch]
+ ;* | Empty | [BP + 0Eh]
+ ;* | Empty | [BP + 10h]
+ ;* | Ret IP | [BP + 12h] <-
+ ;* | Ret CS | [BP + 14h] |
+ ;* |Error Code| [BP + 16h] | Pushed by DPMI
+ ;* | IP | [BP + 18h] |
+ ;* | CS | [BP + 1Ah] | (Locked stack)
+ ;* | Flags | [BP + 1Ch] |
+ ;* | SP | [BP + 1Eh] |
+ ;* | SS | [BP + 20h] <-
+ ;* ------------
+ ;*
+ ;* Before returning to DPMI, however, we want to create a
+ ;* stack frame on the user's stack that we will be returning
+ ;* to so we can preserve information in a reentrant fashion.
+ ;* The user's stack will appear like this:
+ ;* ------------
+ ;* BP---->| Old BP | [BP + 00h]
+ ;* | BX | [BP + 02h]
+ ;* |Our Ret IP| [BP + 04h]
+ ;* |Our Ret CS| [BP + 06h]
+ ;* | Ret IP | [BP + 08h]
+ ;* | Ret CS | [BP + 0Ah]
+ ;* | AX | [BP + 0Ch]
+ ;* |Exception#| [BP + 0Eh]
+ ;* | Handle | [BP + 10h]
+ ;* | IP | [BP + 12h]
+ ;* | CS | [BP + 14h]
+ ;* | Flags | [BP + 16h]
+ ;* ------------
+ ;**
+
+PubLabel DIH_Exception
+
+ ;** Check to see if we're already on the faulting stack. If we are,
+ ;** we want to shift everything up on this stack so that we
+ ;** have room for the TOOLHELP user frame
+ mov ax,ss ;Get the current SS
+ cmp ax,WORD PTR ss:[bp + 20h] ;Is it the same as the user frame?
+ jne DIH_EnoughRoomOnStack ;No, ignore all of this
+
+ ;** Move everything up by copy everything that's on stack now to
+ ;** above where SP starts at. This actually uses too much
+ ;** stack, but it's safe and easy.
+ push bp ;We use BP to do copy
+ lea bp,[bp + 20h] ;Point to lowest WORD to copy
+ mov ax,sp ;Point to position to copy to
+ dec ax
+ dec ax
+DIH_CopyLoop:
+ push WORD PTR [bp] ;Copy a WORD
+ dec bp ;Point to next WORD to copy
+ dec bp
+ cmp bp,ax ;Done yet?
+ jne DIH_CopyLoop ;No
+ pop bp ;Yes, compute new BP value
+ sub bp,56 ;Point BP to right place
+
+ ;** Put stuff on DPMI's stack
+PubLabel DIH_EnoughRoomOnStack
+ mov di,[bp + 1Eh] ;Get the old SP value
+ mov cx,[bp + 20h] ; and the SS value
+ cmp di,MIN_STACK_ALLOWED ;Are we going to stack fault?
+ jb DIH_BadStack ;Yes, so swich
+ mov ax,__WinFlags ;Make sure we have a 386 or higher
+ test ax,WF_CPU286
+ jnz DIH_SkipBigCheck ;No need to check big bit
+.386p
+ push eax ;Make sure we don't trash EAX
+ lar eax,ecx ;Get the access rights DWORD
+ test eax,00400000h ;Check the BIG bit
+ pop eax
+ jnz DIH_BadStack ;Don't use this stack if BIG
+.286p
+DIH_SkipBigCheck:
+ mov ax,di ;Get the stack pointer
+ add ax,2 ;Point just beyond
+ cCall HelperVerifySeg, <cx,ax> ;Is this seg OK?
+ or ax,ax ;Check for success
+ jz DIH_BadStack ;Stack is bogus, don't change to it
+
+PubLabel DIH_StackOK
+ sub di,20 ;Reserve space for the user frame
+ mov ds,cx ;Get stack value in DS
+ mov dx,[bp + 1Ah] ;Get the old CS value
+ mov cx,[bp + 18h] ;Get the old IP value
+ mov ax,[bp + 1Ch] ;Get the old flags
+ mov [bp + 1Eh],di ;Save as new SP value
+ sub di,4 ;Make DI equal to what BP will be
+ mov [bp + 1Ah],cs ;Prepare to IRET to ourself
+ mov [bp + 18h],OFFSET _TEXT:DIH_DPMIRestart
+
+ ;** Save some things on the user's stack before returning
+ mov [di + 16h],ax ;Save the flags
+ mov [di + 14h],dx ;Save the old CS value
+ mov [di + 12h],cx ;Save the old IP value
+ mov [di + 0Eh],bx ;INT_INFO pointer to new stack
+ mov [di + 10h],si ;Handle to new stack
+
+ ;** Clear the Trace and Ints Enabled flags
+ and [bp + 1Ch],NOT 0100h ;Clear TF. We don't want to trace here
+ pop es ;Clear the DPMI stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,14 ;Clear extra allocated space
+ retf
+
+ ;** The user stack is bad, so we want to stay on the fault handler
+ ;** stack. In order to do this, we have to build a frame for
+ ;** the callback directly on the fault handler stack.
+ ;** We build the frame here and jump to it.
+ ;** ------------
+ ;** | ES |
+ ;** | DS |
+ ;** | PUSHA |
+ ;** BP-->| Old BP | [BP + 00h]
+ ;** | BX | [BP + 02h]
+ ;** | Empty | [BP + 04h]
+ ;** |Our Ret IP| [BP + 06h] ; Client callback addr
+ ;** |Our Ret CS| [BP + 08h]
+ ;** | Ret IP | [BP + 0Ah] ; TOOLHELP restart addr
+ ;** | Ret CS | [BP + 0Ch]
+ ;** | AX | [BP + 0Eh] ; Saved AX for MPI
+ ;** |Exception#| [BP + 10h] ; Exception number
+ ;** | Handle | [BP + 12h] ; TOOLHELP handle
+ ;** | IP | [BP + 14h] ; IRET frame of fault
+ ;** | CS | [BP + 16h]
+ ;** | Flags | [BP + 18h]
+ ;** | SP | [BP + 1Ah] ; Faulting SS:SP
+ ;** | SS | [BP + 1Ch]
+ ;** | Ret IP | [BP + 1Eh] ; DPMI return address
+ ;** | Ret CS | [BP + 20h]
+ ;** ------------
+PubLabel DIH_BadStack
+ mov dx,[bp + 12h] ;DPMI return CS:IP
+ mov cx,[bp + 14h] ; stored in CX:DX
+ mov ax,[bp + 18h] ;Faulting IP
+ mov [bp + 14h],ax
+ mov ax,[bp + 1Ah] ;Faulting CS
+ mov [bp + 16h],ax
+ mov ax,[bp + 1Ch] ;Flags
+ mov [bp + 18h],ax
+ mov ax,[bp + 1Eh] ;Faulting SP
+ mov [bp + 1Ah],ax
+ mov ax,[bp + 20h] ;Faulting SS
+ mov [bp + 1Ch],ax
+ mov [bp + 1Eh],dx ;DPMI ret IP
+ mov [bp + 20h],cx ;DPMI ret CS
+ mov [bp + 12h],si ;Point to INTERRUPT struct
+ mov ax,[bx].ii_wNumber ;Get the interrupt number
+ or ax,BAD_STACK_FLAG ;Flag the client that stack is bad
+ mov [bp + 10h],ax
+ mov ax,[bp - 02h] ;Get the AX value from the PUSHA frame
+ mov [bp + 0Eh],ax
+ mov [bp + 0Ch],cs ;Point to callback return address
+ mov [bp + 0Ah],OFFSET _TEXT:DIH_CallbackRestart
+ mov ax,WORD PTR [si].i_lpfn ;Point to the user callback OFFSET
+ mov [bp + 06h],ax
+ mov ax,WORD PTR [si].i_lpfn + 2 ;Point to callback segment
+ mov [bp + 08h],ax
+ pop es ;Clear the stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,2
+ retf ;Jump to the user callback
+
+ ;** At this point, DPMI IRETs back to us instead of to the faulting
+ ;** app. We have to now create a stack frame identical to the
+ ;** frame used by interrupt-style hooks. Note that we have
+ ;** already allocated the frame space (but not initialized it)
+ ;** before returning to DPMI.
+ ;** It will look like this:
+ ;** ------------
+ ;** | ES | [BP - 14h]
+ ;** | DS | [BP - 12h]
+ ;** | DI | [BP - 10h]
+ ;** | SI | [BP - 0Eh]
+ ;** | BP | [BP - 0Ch]
+ ;** | SP | [BP - 0Ah]
+ ;** | BX | [BP - 08h]
+ ;** | DX | [BP - 06h]
+ ;** | CX | [BP - 04h]
+ ;** | AX | [BP - 02h]
+ ;** BP---->| Old BP | [BP + 00h]
+ ;** | BX | [BP + 02h]
+ ;** |Our Ret IP| [BP + 04h]
+ ;** |Our Ret CS| [BP + 06h]
+ ;** | Ret IP | [BP + 08h]
+ ;** | Ret CS | [BP + 0Ah]
+ ;** | AX | [BP + 0Ch]
+ ;** |Exception#| [BP + 0Eh]
+ ;** | Handle | [BP + 10h]
+ ;** | IP | [BP + 12h]
+ ;** | CS | [BP + 14h]
+ ;** | Flags | [BP + 16h]
+ ;** ------------
+ ;**
+PubLabel DIH_DPMIRestart
+ push bx ;Save this register we're using
+ push bp ;Make a stack frame
+ mov bp,sp
+ pusha ;Save all the registers
+ push ds
+ push es
+ mov bx,[bp + 0Eh] ;Get the INT_INFO pointer back
+ mov si,[bp + 10h] ;Get the INTERRUPT structure back
+ mov ax,_DATA ;Get our data segment
+ mov ds,ax
+
+ ;** We can now proceed with joint processing as we've matched the
+ ;** DOS interrupt frame
+PubLabel DIH_SkipDPMI
+
+ ;** Build our return frame and jump to the user callback
+ mov [bp + 10h],si ;Point to INTERRUPT struct
+ mov ax,[bx].ii_wNumber ;Get the interrupt number
+ mov [bp + 0Eh],ax ;Put on frame
+ mov ax,[bp - 02h] ;Get the AX value from the PUSHA frame
+ mov [bp + 0Ch],ax ;Put on frame
+ mov [bp + 0Ah],cs ;Point to callback return address
+ mov [bp + 08h],OFFSET _TEXT:DIH_CallbackRestart
+ mov ax,WORD PTR [si].i_lpfn ;Point to the user callback OFFSET
+ mov [bp + 04h],ax
+ mov ax,WORD PTR [si].i_lpfn + 2 ;Point to callback segment
+ mov [bp + 06h],ax
+ pop es ;Clear the stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ retf ;Jump to the user callback
+
+ ;** When the callback returns, we have to know how to call the
+ ;* next matching callback or to chain on the interrupt list.
+ ;* We have to do a raft of special stuff if this was an
+ ;* exception so that the chained on handlers think it was
+ ;** DPMI that called them.
+PubLabel DIH_CallbackRestart
+ sub sp,8 ;Leave room for ret addresses
+ push bx ;For compat. with the above code
+ push bp ;Make the same stack frame
+ mov bp,sp
+ pusha
+ push ds
+ push es
+
+ ;** Get the next matching item on the list
+ mov ax,_DATA ;Get our data segment
+ mov ds,ax
+ mov ax,[bp + 0Ch] ;Get the saved AX value
+ mov [bp - 02h],ax ;Put in PUSHA frame
+ mov si,[bp + 10h] ;Get the last handle used
+ or si,si ;If NULL, app has messed with it
+ jz DIH_NukeIt ;Nuke the app--it did a no-no
+ mov si,[si].i_pNext ;Get the next item in the list
+ or si,si ;End of the line?
+ jz DIH_NextNotFound ;Yes, chain on
+ mov ax,[bp + 0Eh] ;Get the exception number
+ cCall InterruptInfo ;Get the INT_INFO structure
+ or ax,ax ;If NULL return, user messed with #
+ jz DIH_NukeIt ; so nuke it
+ mov bx,ax ;Point with BX
+ jmp DIH_SkipDPMI ;Process this one
+
+ ;** If we don't find a match, we pass on to previous handler
+PubLabel DIH_NextNotFound
+ mov ax,[bp + 0Eh] ;Get the exception number
+ and ax,7fffh ;Clear the new stack bit
+ cCall InterruptInfo ;Find the INT_INFO structure
+ or ax,ax ;If the user messed with it,
+ jz DIH_NukeIt ; nuke the app.
+ mov si,ax ;Get the pointer in AX
+ test wTHFlags,TH_Win30StdMode ;3.0 Std mode?
+ jnz DIH_30StdChainOn ;Always do normal chain on in 3.0sm
+ cmp [si].ii_wType,I_INTERRUPT ;Was this an interrupt?
+ je DIH_ChainOn ;Yes, do normal chain on
+ jmp DIH_EmulateDPMI ;No, do the DPMI chain on
+
+PubLabel DIH_NukeIt
+ push [bp + 16h] ;Copy the IRET frame for KERNEL
+ push [bp + 14h]
+ push [bp + 12h]
+
+ push 0 ;Nuke current task
+ push UAE_BOX OR GIVE_WDEB386 ;UAE box + give to wdeb
+ push cs ;Simulate a far jump
+ call NEAR PTR TerminateApp ;Nuke the app
+
+ ;** We only get here if WDEB386 is installed. We tell it to set
+ ;* a breakpoint, then restart the app, in effect giving
+ ;* control to WDEB386. Unfortunately, at this point, all
+ ;** fault handlers for this task have been removed
+ add sp,6 ;Clear fake IRET frame
+ mov cx,[bp + 14h] ;Faulting CS
+ mov bx,[bp + 12h] ;Faulting IP
+ mov ax, 40h ;16 bit forced go command
+ int 41h ;Call debugger
+ pop es ;Restore registers and clear stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,14 ;Clear extra words
+ ; all that remains is IRET frame
+ iret ;WDEB386 will get control
+
+PubLabel DIH_NukeApp
+ push 0 ;Nuke current task
+ push UAE_BOX ;Draw the UAE box
+ push cs ;Simulate a far jump
+ call NEAR PTR TerminateApp ;Nuke the app
+ int 1 ;Should never return
+ jmp SHORT DIH_ChainOn
+
+ ;** In 3.0 standard mode we have to put an error code on the stack
+ ;** if it's a GP fault or. If not, we just chain on normally
+PubLabel DIH_30StdChainOn
+ cmp si,OFFSET GP_Info ;Is this a GP fault?
+ jne DIH_ChainOn ;No, handle normally
+ mov ax,WORD PTR [si].ii_dwChain ;Get the LOWORD
+ mov dx,WORD PTR [si].ii_dwChain + 2 ;Get HIWORD
+ mov bx,ax ;Save the LOWORD
+ or ax,dx ;Is there a chain on address?
+ jz DIH_NoChainAddr ;No, just restart the instruction
+ mov [bp + 0Ch],bx ;Put on stack so we can retf to it
+ mov [bp + 0Eh],dx
+ mov WORD PTR [bp + 10h],0 ;Zero the error code
+ pop es ;Restore registers and clear stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,8 ;Clear extra words
+ retf
+
+PubLabel DIH_ChainOn
+ mov ax,WORD PTR [si].ii_dwChain ;Get the LOWORD
+ mov dx,WORD PTR [si].ii_dwChain + 2 ;Get HIWORD
+ mov bx,ax ;Save the LOWORD
+ or ax,dx ;Is there a chain on address?
+ jz DIH_NoChainAddr ;No, just restart the instruction
+ mov [bp + 0Eh],bx ;Put on stack so we can retf to it
+ mov [bp + 10h],dx
+ pop es ;Restore registers and clear stack
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,10 ;Clear extra words
+ retf
+
+ ;** No chain on address was recorded so just restart the instruction
+PubLabel DIH_NoChainAddr
+ pop es
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,14 ;Clear all extra words
+ iret ; and restart instruction
+
+ ;** Chain on a DPMI-style exception:
+ ;**
+ ;** The goal here is to make a fault frame that appears that DPMI
+ ;** has passed the next exception handler the interrupt. We
+ ;** have only two important cases here:
+ ;** 1) We have already told DPMI the int was finished.
+ ;** 2) We have not told DPMI the int was finished and
+ ;** have not switched off the fault handler stack
+ ;** We handle the cases differently:
+ ;** -If we have already told DPMI that the fault was handled,
+ ;** we have to make a new fault so that the next handler can see
+ ;** the frame. This can be best accomplished by restarting the
+ ;** faulting instruction. This will cause the same fault to
+ ;** happen and will make the same frame.
+ ;** -In the case of us still being on the fh stack, we have to
+ ;** rebuild the frame and chain on.
+ ;** The stack we're given looks like this:
+ ;** ------------
+ ;** | ES | [BP - 14h]
+ ;** | DS | [BP - 12h]
+ ;** | DI | [BP - 10h]
+ ;** | SI | [BP - 0Eh]
+ ;** | BP | [BP - 0Ch]
+ ;** | SP | [BP - 0Ah]
+ ;** | BX | [BP - 08h]
+ ;** | DX | [BP - 06h]
+ ;** | CX | [BP - 04h]
+ ;** | AX | [BP - 02h]
+ ;** BP---->| Old BP | [BP + 00h]
+ ;** | BX | [BP + 02h]
+ ;** |Our Ret IP| [BP + 04h]
+ ;** |Our Ret CS| [BP + 06h]
+ ;** | Ret IP | [BP + 08h]
+ ;** | Ret CS | [BP + 0Ah]
+ ;** | AX | [BP + 0Ch]
+ ;** |Exception#| [BP + 0Eh]
+ ;** | Handle | [BP + 10h]
+ ;** | IP | [BP + 12h]
+ ;** | CS | [BP + 14h]
+ ;** | Flags | [BP + 16h]
+ ;** | SP | [BP + 18h] ;Only here if on fh stack
+ ;** | SS | [BP + 1Ah]
+ ;** | Ret IP | [BP + 1Ch] ;DPMI return address
+ ;** | Ret CS | [BP + 1Eh]
+ ;** ------------
+PubLabel DIH_EmulateDPMI
+ mov ax,[bp + 0Eh] ;Get the exception number
+ test ax,BAD_STACK_FLAG ;Still on fh stack?
+ jnz DIH_RebuildDPMIFrame ;Yes, rebuild the frame
+
+ ;** Rehook the exception so we're sure to get it first
+ push si ;Preserve handle
+ mov bx,ax ;Fault number in bx
+ mov wException,bx ;Save as a static also
+ mov ax,0202h ;Get exception handler - DPMI
+ int 31h ;Call DPMI
+ mov WORD PTR lpOldHandler[0],dx ;Save the old exception handler
+ mov WORD PTR lpOldHandler[2],cx
+ mov ax,0203h ;Set exception handler - DPMI
+ mov dx,OFFSET DIH_EmDPMIRestart
+ mov cx,cs ;Selector value of handler
+ int 31h ;Call DPMI
+ pop si
+
+ ;** Save the address of the next exception handler
+ mov ax,WORD PTR [si].ii_dwChain[0] ;Address to chain fault to
+ mov WORD PTR lpChainCSIP[0],ax
+ mov ax,WORD PTR [si].ii_dwChain[2]
+ mov WORD PTR lpChainCSIP[2],ax
+
+ ;** Restart the instruction. This will fault and jump to our
+ ;** newly-established handler at DIH_EmDPMIRestart
+ pop es
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,14 ;Clear all extra words
+ iret ; and restart instruction
+
+ ;** Now we're on the fault handler stack with a DPMI frame. Throw
+ ;** it to the next handler on the chain
+PubLabel DIH_EmDPMIRestart
+ sub sp,4 ;Enough room for a RETF frame
+ push bp
+ mov bp,sp
+ pusha
+ push ds
+ push es
+ mov ax,_DATA ;Point to TOOLHELP's DS
+ mov ds,ax
+
+ ;** Restore the exception handler
+ mov ax,0203h ;Set exception handler - DPMI
+ mov bx,wException ;Get exception number
+ mov dx,WORD PTR lpOldHandler[0] ;Get the exception handler address
+ mov cx,WORD PTR lpOldHandler[2]
+ int 31h ;Call DPMI
+
+ ;** Put the chain address on the stack so we can return to it
+ mov ax,WORD PTR lpChainCSIP[0] ;Get chain address
+ mov [bp + 02h],ax
+ mov ax,WORD PTR lpChainCSIP[2]
+ mov [bp + 04h],ax
+
+ ;** Restore registers and jump to the handler
+ pop es
+ pop ds
+ popa
+ pop bp
+ retf
+
+ ;** Since we are already on the fault handler stack, there is no
+ ;** need to fault again. All we have to do here is recreate the
+ ;** DPMI fault stack as if the fault had just occurred. It would
+ ;** be nice to clear the exception and then make it fault again,
+ ;** but since we only get here in potentially stack-faulting
+ ;** conditions, we cannot do this. We just build a reasonable
+ ;** facsimile of the frame and chain on. This frame should
+ ;** look as follows when we're done:
+ ;** ------------
+ ;** | ES | [BP - 14h]
+ ;** | DS | [BP - 12h]
+ ;** | DI | [BP - 10h]
+ ;** | SI | [BP - 0Eh]
+ ;** | BP | [BP - 0Ch]
+ ;** | SP | [BP - 0Ah]
+ ;** | BX | [BP - 08h]
+ ;** | DX | [BP - 06h]
+ ;** | CX | [BP - 04h]
+ ;** | AX | [BP - 02h]
+ ;** BP---->| Old BP | [BP + 00h]
+ ;** | BX | [BP + 02h]
+ ;** | Empty | [BP + 04h]
+ ;** | Empty | [BP + 06h]
+ ;** | Empty | [BP + 08h]
+ ;** | Empty | [BP + 0Ah]
+ ;** | Chain IP | [BP + 0Ch]
+ ;** | Chain CS | [BP + 0Eh]
+ ;** | Ret IP | [BP + 10h]
+ ;** | Ret CS | [BP + 12h]
+ ;** |Error Code| [BP + 14h] ;Always return zero
+ ;** | IP | [BP + 16h]
+ ;** | CS | [BP + 18h] ;Only here if on fh stack
+ ;** | Flags | [BP + 1Ah]
+ ;** | SP | [BP + 1Ch] ;DPMI return address
+ ;** | SS | [BP + 1Eh]
+ ;** ------------
+
+PubLabel DIH_RebuildDPMIFrame
+ mov dx,[bp + 1Ch] ;DPMI return CS:IP
+ mov cx,[bp + 1Eh] ; stored in CX:DX
+ mov ax,[bp + 1Ah] ;Faulting SS
+ mov [bp + 1Eh],ax
+ mov ax,[bp + 18h] ;Faulting SP
+ mov [bp + 1Ch],ax
+ mov ax,[bp + 16h] ;Flags
+ mov [bp + 1Ah],ax
+ mov ax,[bp + 14h] ;Faulting CS
+ mov [bp + 18h],ax
+ mov ax,[bp + 12h] ;Faulting IP
+ mov [bp + 16h],ax
+ xor ax,ax ;Error code
+ mov [bp + 14h],ax
+ mov [bp + 12h],cx ;DPMI ret CS
+ mov [bp + 10h],dx ;DPMI ret IP
+ mov ax,WORD PTR [si].ii_dwChain[2] ;Address to chain fault to
+ mov [bp + 0Eh],ax
+ mov ax,WORD PTR [si].ii_dwChain[0]
+ mov [bp + 0Ch],ax
+ pop es
+ pop ds
+ popa
+ pop bp
+ pop bx
+ add sp,8 ;Clear all extra words
+ retf
+
+cEnd NOGEN
+
+
+;** Helper functions
+
+; InterruptInfo
+; Gets a pointer to the INT_INFO structure given the interrupt
+; number. Accepts the int number in AX and returns the pointer in AX.
+; Preserves all other registers
+
+cProc InterruptInfo, <NEAR,PUBLIC>, <si,cx>
+cBegin
+ ;** Loop through all possible handlers
+ mov cx,MAX_INTERRUPT + 1 ;Number of ints to hook
+ lea si,IntInfo ;Get the address of the array
+
+ ;** Is this a match?
+II_HandlerLoop:
+ cmp [si].ii_wNumber,ax ;Match?
+ jz II_End ;Yes, return the pointer
+
+ ;** Prepare for next in table
+II_Continue:
+ add si,SIZE INT_INFO ;Bump to next entry
+ loop II_HandlerLoop ;Loop back
+ xor si,si ;Return NULL for not found
+
+II_End:
+ mov ax,si ;Get return value
+cEnd
+
+sEnd
+
+ END
diff --git a/private/mvdm/wow16/toolhelp/krnlpeek.asm b/private/mvdm/wow16/toolhelp/krnlpeek.asm
new file mode 100644
index 000000000..0e34099f9
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/krnlpeek.asm
@@ -0,0 +1,110 @@
+;***************************************************************************
+;* KRNLPEEK.ASM
+;*
+;* Assembly code used to peer into the heart of KERNEL and return
+;* information in global variables.
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC ;Include the TOOLHELP values
+PMODE32 = 0 ;This should work either way
+PMODE = 0
+ INCLUDE WINKERN.INC
+ INCLUDE WINDOWS.INC
+
+;** Functions
+externFP GlobalMasterHandle
+externFP GlobalLock
+externFP GetVersion
+externFP GetProcAddress
+externFP GetModuleHandle
+externNP HelperHandleToSel
+
+sBegin DATA
+externB _szKernel
+sEnd DATA
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+
+; void KernelType(void)
+;
+; Returns information from KERNEL in global variables
+
+cProc KernelType, <PUBLIC>, <si,di>
+cBegin
+ ;** Make sure we're in PMODE. TOOLHELP does not run in non-PMODE
+ ;** Windows.
+ mov ax,__WinFlags ;Get WinFlags
+ test ax,1 ;In PMODE?
+ mov wTHFlags,0 ;Zero flags indicates error
+ jnz @F ;Yes, go on
+ jmp KT_End ;No, not in PMODE, return error
+@@:
+.286
+ ;** Call the undocumented function GlobalMasterHandle to get
+ ;* a pointer to the global HeapInfo structure.
+ ;** This is the means we can use to detect the kernel types.
+
+ cCall GlobalMasterHandle
+ cCall HelperHandleToSel, <dx> ;Convert it to a selector
+ mov hMaster,ax ;Save the handle
+ mov es,ax ;Use ES to point to the block
+ mov ax,es:[hi_first] ;Get low word of first heap entry
+ test ax,01fh ;Mask out lowest 5 bits
+ jz KT_Krnl386 ;Must be Krnl386 so leave the flags
+ mov wTHFlags,TH_KERNEL_286
+ jmp SHORT KT_BothPModes ;Skip TH_KERNEL_386 stuff
+KT_Krnl386:
+ mov wTHFlags,TH_KERNEL_386
+KT_BothPModes:
+
+ ;** Now get pmode KERNEL information
+ cCall GetVersion ;Which Windows version are we on
+ mov bx,SEG GlobalLock ;KERNEL code segment selector
+ cmp ax,0003h ;Win 3.0 or Win 3.0a?
+ je KT_Win30 ;Yes
+ cmp ax,0103h ;Beta releas of Win 3.0a?
+ je KT_Win30 ;Yes
+ cmp ax,0a03h ;Win 3.1?
+ je KT_Win31 ;Yes
+ mov wTHFlags,0 ;Zero wTHFlags indicates error
+ jmp SHORT KT_End ;Unknown Windows version
+KT_Win31:
+ mov ax,seg _DATA
+ mov dx,offset _DATA:_szKernel
+ cCall GetModuleHandle,<ax,dx>
+ cCall GetProcAddress,<ax,0,332> ; DX:AX -> hGlobalHeap
+ mov segKernel,dx ;Save for later
+ mov es,dx ;Point with ES
+ add ax,4
+ mov npwExeHead,ax
+ add ax,10
+ mov npwTDBHead,ax
+ add ax,2
+ mov npwTDBCur,ax
+ add ax,6
+ mov npwSelTableLen,ax
+ add ax,2
+ mov npdwSelTableStart,ax
+ jmp SHORT KT_End ;Skip the 3.0 std mode check
+KT_Win30:
+ or wTHFlags,TH_WIN30 ;Flag we're in Win30
+ mov npwSelTableLen,0324h ;Correct values for 3.0
+ mov npdwSelTableStart,0326h
+ mov ax,__WinFlags ;Get the WinFlags variable
+ mov segKernel,bx ;Save for later
+ mov npwExeHead,0014h ;Save the offsets of these vars
+ mov npwTDBHead,001eh
+ mov npwTDBCur,0020h
+ test ax,WF_STANDARD ;3.0 Standard mode?
+ jz KT_End ;No.
+ or wTHFlags,TH_WIN30STDMODE ;Yes
+.8086
+KT_End:
+
+cEnd
+
+sEnd
+ END
diff --git a/private/mvdm/wow16/toolhelp/local.c b/private/mvdm/wow16/toolhelp/local.c
new file mode 100644
index 000000000..34285cee1
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/local.c
@@ -0,0 +1,138 @@
+/**************************************************************************
+ * LOCAL.C
+ *
+ * Routines used to walk local heaps
+ *
+ **************************************************************************/
+
+#include "toolpriv.h"
+
+/* ----- Function prototypes ----- */
+
+ NOEXPORT void NEAR PASCAL ComputeType(
+ LOCALENTRY FAR *lpLocal);
+
+/* LocalInfo
+ * Reports information about the state of the indicated heap
+ */
+
+BOOL TOOLHELPAPI LocalInfo(
+ LOCALINFO FAR *lpLocalInfo,
+ HANDLE hHeap)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpLocalInfo ||
+ lpLocalInfo->dwSize != sizeof (LOCALINFO))
+ return FALSE;
+
+ /* Get the item counts */
+ if (wTHFlags & TH_KERNEL_386)
+ lpLocalInfo->wcItems = WalkLoc386Count(hHeap);
+ else
+ lpLocalInfo->wcItems = WalkLoc286Count(hHeap);
+
+ return TRUE;
+}
+
+/* LocalFirst
+ * Finds the first block on a local heap.
+ */
+
+BOOL TOOLHELPAPI LocalFirst(
+ LOCALENTRY FAR *lpLocal,
+ HANDLE hHeap)
+{
+ WORD wFirst;
+
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpLocal || lpLocal->dwSize != sizeof (LOCALENTRY))
+ return FALSE;
+
+ /* Convert the heap variable to a selector */
+ hHeap = HelperHandleToSel(hHeap);
+
+ /* Get the first item from the heap */
+ if (wTHFlags & TH_KERNEL_386)
+ {
+ if (!(wFirst = WalkLoc386First(hHeap)))
+ return FALSE;
+ }
+ else
+ {
+ if (!(wFirst = WalkLoc286First(hHeap)))
+ return FALSE;
+ }
+
+
+ /* Fill in other miscellaneous stuff */
+ lpLocal->hHeap = hHeap;
+
+ /* Get information about this item */
+ if (wTHFlags & TH_KERNEL_386)
+ WalkLoc386(wFirst, lpLocal, hHeap);
+ else
+ WalkLoc286(wFirst, lpLocal, hHeap);
+
+ /* Guess at the type of the object */
+ ComputeType(lpLocal);
+
+ return TRUE;
+}
+
+
+/* LocalNext
+ * Continues a local heap walk by getting information about the
+ * next item.
+ */
+
+BOOL TOOLHELPAPI LocalNext(
+ LOCALENTRY FAR *lpLocal)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpLocal || lpLocal->dwSize != sizeof (LOCALENTRY))
+ return FALSE;
+
+ if (wTHFlags & TH_KERNEL_386)
+ WalkLoc386(lpLocal->wNext, lpLocal, lpLocal->hHeap);
+ else
+ WalkLoc286(lpLocal->wNext, lpLocal, lpLocal->hHeap);
+
+ /* See if this item is the last one. If so, return done because this
+ * last item is NOT useful.
+ */
+ if (!lpLocal->wNext)
+ return FALSE;
+
+ /* Guess at the type of the object */
+ ComputeType(lpLocal);
+
+ return TRUE;
+}
+
+
+/* ComputeType
+ * Computes the object type of an object
+ */
+
+NOEXPORT void NEAR PASCAL ComputeType(
+ LOCALENTRY FAR *lpLocal)
+{
+ /* Decode the free/fixed/moveable bits */
+ if (lpLocal->wFlags & 2)
+ lpLocal->wFlags = LF_MOVEABLE;
+ else if (lpLocal->wFlags & 1)
+ lpLocal->wFlags = LF_FIXED;
+ else
+ {
+ /* Free blocks never have a unique type so return */
+ lpLocal->wFlags = LF_FREE;
+ lpLocal->wType = LT_FREE;
+ lpLocal->hHandle = NULL;
+ return;
+ }
+
+ /* Decode the heap type if possible */
+ UserGdiType(lpLocal);
+}
+
+
diff --git a/private/mvdm/wow16/toolhelp/makefile b/private/mvdm/wow16/toolhelp/makefile
new file mode 100644
index 000000000..7f99d2f88
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/makefile
@@ -0,0 +1,168 @@
+# TOOLHELP.DLL for WOW makefile
+#
+# Copyright (c) 1992, Microsoft Corporation
+#
+# History:
+# 4-Nov-1992 Dave Hart (davehart)
+# Created.
+#
+
+#
+# Macros for build utilities
+#
+
+#RC16 = .\rc
+RC16 = rc16 # use after rc16 is Win 3.1 flavor, and delfile rc*
+CL16 = cl16
+MASM16 = masm
+LINK16 = link16
+MAPSYM16 = mapsym
+IMPLIB16 = implib
+MKPUB16 = mkpublic
+
+#
+# Command line options common to C compiler and assembler
+#
+
+DEFINES = -DWOW $(MVDMFLAGS)
+INCLUDES = -I..\inc -I..\..\inc -I..\kernel31
+
+#
+# C, MASM, Link16, and RC16 options
+#
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+ADEBUG = -Zd
+CDEBUG = /Od /Oi /Zd
+LDEBUG = /LI
+!endif
+
+CFLAGS = -c -ASw -G2s -Oas -W3 -Zpe $(DEFINES) $(INCLUDES) $(CDEBUG)
+AFLAGS = -DmemS=1 -w2 $(DEFINES) $(INCLUDES) $(ADEBUG)
+LFLAGS = /ALIGN:16 $(LDEBUG)
+RFLAGS = $(INCLUDES)
+
+#
+# Libraries to link with.
+#
+
+W16LIBS = ..\lib\sdllcew.LIB ..\lib\LIBW.LIB
+
+#
+# Target objects (keep in sync with dependencies below)
+#
+
+OBJS = toolhelp.obj dllentry.obj global.obj krnlpeek.obj \
+ walk386.obj local.obj module.obj task1.obj task2.obj stack1.obj \
+ stack2.obj usergdi1.obj usergdi2.obj memman.obj helper.obj \
+ walk286.obj notify1.obj notify2.obj int1.obj int2.obj terminat.obj \
+ signal.obj memory.obj timer.obj ththunks.obj
+
+
+#
+# Common build pseudotargets:
+# all builds everything - must be be first target in file
+# cleanup deletes everything
+# clean deletes & then builds everything
+#
+
+all: toolhelp.dll toolhelp.sym toolhelp.map toolhelp.lib
+ -binplace toolhelp.dll
+ -binplace toolhelp.map
+ -binplace toolhelp.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.obj del *.obj
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+ if exist *.lib del *.lib
+ if exist stripped.def del stripped.def
+
+#
+# Default build rules.
+#
+
+.c.obj:
+ $(CL16) $(CFLAGS) $*.c
+
+.asm.obj:
+ $(MASM16) $(AFLAGS) $*.asm;
+
+.asm.lst:
+ $(MASM16) $(AFLAGS) -l $*.asm,nul,$*.lst;
+
+.rc.res:
+ $(RC16) $(RFLAGS) -r $*.rc
+
+.def.lib:
+ $(IMPLIB16) $@ $**
+
+#
+# Dependencies that use default build rules.
+#
+
+# NOTE: Class1.c and Class2.asm are checked in for reference but are not
+# ---- built for WOW. Instead THTHUNKS.ASM contains thunks to WOW32.
+#
+# class1.obj: class1.c toolpriv.h toolhelp.h
+# class2.obj: class2.asm toolpriv.inc toolhelp.inc
+dllentry.obj: dllentry.asm
+global.obj: global.c toolpriv.h toolhelp.h string.h
+helper.obj: helper.asm toolpriv.inc toolhelp.inc
+int1.obj: int1.c toolpriv.h toolhelp.h string.h
+int2.obj: int2.asm toolpriv.inc toolhelp.inc
+krnlpeek.obj: krnlpeek.asm toolpriv.inc toolhelp.inc
+local.obj: local.c toolpriv.h toolhelp.h
+memman.obj: memman.asm toolpriv.inc toolhelp.inc
+memory.obj: memory.asm toolpriv.inc toolhelp.inc
+module.obj: module.c toolpriv.h toolhelp.h string.h
+notify1.obj: notify1.c toolpriv.h toolhelp.h string.h
+notify2.obj: notify2.asm toolpriv.inc toolhelp.inc
+signal.obj: signal.c toolpriv.h toolhelp.h string.h
+stack1.obj: stack1.c toolpriv.h toolhelp.h string.h
+stack2.obj: stack2.asm toolpriv.inc toolhelp.inc
+task1.obj: task1.c toolpriv.h toolhelp.h string.h
+task2.obj: task2.asm toolpriv.inc toolhelp.inc
+terminat.obj: terminat.asm toolpriv.inc toolhelp.inc
+ththunks.obj: ththunks.asm ..\..\inc\wow.inc ..\..\inc\wowth.inc
+timer.obj: timer.asm toolpriv.inc toolhelp.inc
+toolhelp.obj: toolhelp.c toolpriv.h toolhelp.h
+usergdi1.obj: usergdi1.c toolpriv.h toolhelp.h
+usergdi2.obj: usergdi2.asm toolpriv.inc toolhelp.inc
+walk286.obj: walk286.asm toolpriv.inc toolhelp.inc
+walk386.obj: walk386.asm toolpriv.inc toolhelp.inc
+
+#
+# Targets with specialized build rules
+#
+
+toolhelp.dll: $(OBJS) toolhelp.def
+ $(LINK16) $(LFLAGS) @<<
+ toolhelp + dllentry + krnlpeek + global + walk386 +
+ local + module + task1 + task2 + stack1 + stack2 +
+ usergdi1 + usergdi2 + memman + helper + walk286 +
+ notify1 + notify2 + int1 + int2 + terminat + signal +
+ memory + timer + ththunks
+ toolhelp.dll
+ toolhelp.map/map
+ $(W16LIBS) /NOE/NOD
+ toolhelp.def;
+
+<<
+ $(MAPSYM16) toolhelp.map
+ $(RC16) $(RFLAGS) -t -30 toolhelp.rcv toolhelp.dll
+
+toolhelp.lib: toolhelp.def
+ $(MKPUB16) toolhelp.def stripped.def
+ $(IMPLIB16) toolhelp.lib stripped.def
diff --git a/private/mvdm/wow16/toolhelp/memman.asm b/private/mvdm/wow16/toolhelp/memman.asm
new file mode 100644
index 000000000..0c75f04b5
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/memman.asm
@@ -0,0 +1,88 @@
+;**************************************************************************
+;* MEMMAN.ASM
+;*
+;* Returns information about the VMM.
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+
+sBegin CODE
+ assumes CS,CODE
+
+; MemManInfo
+;
+; Returns information through DPMI about the VMM
+
+cProc MemManInfo, <PUBLIC,FAR>, <si,di,ds>
+ parmD lpMemMan
+ localV DPMIBuffer,30h ;30h byte buffer for DPMI info
+cBegin
+ mov ax,_DATA ;Get our data segment
+ mov ds,ax
+
+ ;** Fill the buffer with -1 so if the call messes up like
+ ;** in 3.0 std mode we get the correct results
+ push ss ;Point to the local variable block
+ pop es
+ lea di,DPMIBuffer ;Get offset of buffer
+ mov cx,30h ;Max len of DPMI buffer
+ mov al,0ffh ;-1
+ rep stosb ;Fill buffer
+
+ ;** Prepare to build public structure
+ mov ax,0500h ;DPMI -- Get Free Memory Info
+ lea di,DPMIBuffer ;Get offset of buffer
+ int 31h ;Call DPMI
+ jnc MMI_10 ;Success
+ xor ax,ax ;Return FALSE
+ jmp MMI_End ;Get out because of DPMI error
+MMI_10: lds si,lpMemMan ;Point to the MEMMANINFO structure
+
+ ;** Fill MEMMANINFO structure
+ mov ax,es:[di+0] ;Loword of largest free block
+ mov WORD PTR [si].vmm_dwLargestFreeBlock,ax
+ mov ax,es:[di+2] ;High word
+ mov WORD PTR [si].vmm_dwLargestFreeBlock + 2,ax
+ mov ax,es:[di+4] ;Loword of largest unlockable block
+ mov WORD PTR [si].vmm_dwMaxPagesAvailable,ax
+ mov ax,es:[di+6] ;Hiword
+ mov WORD PTR [si].vmm_dwMaxPagesAvailable + 2,ax
+ mov ax,es:[di+8] ;Loword of largest lockable page
+ mov WORD PTR [si].vmm_dwMaxPagesLockable,ax
+ mov ax,es:[di+0ah] ;Hiword
+ mov WORD PTR [si].vmm_dwMaxPagesLockable + 2,ax
+ mov ax,es:[di+0ch] ;Loword of linear address space
+ mov WORD PTR [si].vmm_dwTotalLinearSpace,ax
+ mov ax,es:[di+0eh] ;Hiword
+ mov WORD PTR [si].vmm_dwTotalLinearSpace + 2,ax
+ mov ax,es:[di+10h] ;Loword of number of unlocked pages
+ mov WORD PTR [si].vmm_dwTotalUnlockedPages,ax
+ mov ax,es:[di+12h] ;Hiword
+ mov WORD PTR [si].vmm_dwTotalUnlockedPages + 2,ax
+ mov ax,es:[di+14h] ;Loword of number of free pages
+ mov WORD PTR [si].vmm_dwFreePages,ax
+ mov ax,es:[di+16h] ;Hiword
+ mov WORD PTR [si].vmm_dwFreePages + 2,ax
+ mov ax,es:[di+18h] ;Loword of total physical pages
+ mov WORD PTR [si].vmm_dwTotalPages,ax
+ mov ax,es:[di+1ah] ;Hiword
+ mov WORD PTR [si].vmm_dwTotalPages + 2,ax
+ mov ax,es:[di+1ch] ;Loword of free lin addr space (pages)
+ mov WORD PTR [si].vmm_dwFreeLinearSpace,ax
+ mov ax,es:[di+1eh] ;Hiword
+ mov WORD PTR [si].vmm_dwFreeLinearSpace + 2,ax
+ mov ax,es:[di+20h] ;Loword of size of paging file (pages)
+ mov WORD PTR [si].vmm_dwSwapFilePages,ax
+ mov ax,es:[di+22h] ;Hiword
+ mov WORD PTR [si].vmm_dwSwapFilePages + 2,ax
+ mov [si].vmm_wPageSize,4096 ;Safe to hard code this for 386/486
+ mov ax,TRUE ;Return TRUE
+
+MMI_End:
+
+cEnd
+
+sEnd
+ END
diff --git a/private/mvdm/wow16/toolhelp/memory.asm b/private/mvdm/wow16/toolhelp/memory.asm
new file mode 100644
index 000000000..1227218f6
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/memory.asm
@@ -0,0 +1,608 @@
+ PAGE 60,150
+;***************************************************************************
+;* MEMORY.ASM
+;*
+;* Routines used to handle the read/write random memory API
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE WINDOWS.INC
+
+;** Symbols
+SI_CRITICAL EQU 1
+DI_CRITICAL EQU 2
+
+;** Imports
+externA __AHINCR
+externFP GlobalEntryHandle
+externNP HelperHandleToSel
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+; MemoryRead
+; Uses the passed in selector and offset to read memory into a user-
+; specified buffer. This works for >64K segments and, if code, may
+; have been discarded.
+;
+; This function is normally used for heap selectors. However, if
+; a non-global heap selector is used, it must be less than 64K on
+; a 286.
+;
+; Prototype:
+; DWORD MemoryRead(
+; WORD wSel, /* Selector to read from */
+; DWORD dwOffset, /* Offset to read at */
+; LPSTR lpBuffer, /* Buffer to put data into */
+; DWORD dwcb) /* Number of characters to read */
+; Returns number of characters read (ends at segment limit)
+
+cProc MemoryRead, <FAR,PUBLIC>, <si,di,ds>
+ parmW wSelector
+ parmD dwOffset
+ parmD lpBuffer
+ parmD dwcb
+ localD dwcbCopied
+ localV Global,<SIZE GLOBALENTRY>
+cBegin
+ ;** Make sure the segment is present. We only will fault the
+ ;** segment in if it is a code segment
+ cCall HelperHandleToSel, <wSelector> ;Convert to sel from handle
+ mov wSelector, ax ;Save it so we have a good sel
+ mov cx, ax
+ push WORD PTR lpBuffer[2] ;Convert handle to selector
+ cCall HelperHandleToSel
+ mov WORD PTR lpBuffer[2], ax ;Save converted handle
+ lar ax,cx ;Get the access rights
+ jnz MR_ShortBad ;Failed. It's bad
+ test ax,8000h ;Is it present?
+ jnz MR_Present ;Yes
+ test ax,0800h ;This bit set for code segments
+ jnz MR_FaultIn ;Code segment, fault it in
+MR_ShortBad:
+ jmp MR_Bad ;Return error
+MR_FaultIn:
+ mov es,wSelector ;Get the selector in ES.
+ mov al,es:[0] ;Must be at least one byte long
+MR_Present:
+
+ ;** Check this block's length. We use the global heap functions
+ ;* to do this because they check in the arena for the length.
+ ;* This is the only way to get lengths of 286 heap blocks
+ ;** beyond 64K.
+ mov ax,SIZE GLOBALENTRY ;Get the size of the structure
+ mov WORD PTR Global.ge_dwSize[0],ax ;Save in the structure
+ mov WORD PTR Global.ge_dwSize[2],0 ;Clear the HIWORD
+ lea ax,Global ;Point to the structure
+ cCall GlobalEntryHandle, <ss,ax,wSelector>
+ or ax,ax ;Was this a valid selector?
+ jnz MR_HeapSel ;Yes, this is a heap selector
+
+ ;** If this wasn't a heap selector, we get the length with an LSL.
+ ;** When used like this, 64K is the max on a 286
+MR_NonHeap:
+ mov bx,wSelector ;Get the selector
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_CPU286 ;286?
+ jz MR_32BitSize ;No, do 32 bit size stuff
+ lsl dx,bx ;Get length in DX
+ mov WORD PTR Global.ge_dwBlockSize[0],dx ;Put in GLOBALENTRY struct
+ mov WORD PTR Global.ge_dwBlockSize[2],0
+ jmp SHORT MR_HeapSel
+MR_32BitSize:
+.386p
+ lsl edx,ebx
+ mov Global.ge_dwBlockSize,edx ;Put in GLOBALENTRY struct for later
+.286p
+
+MR_HeapSel:
+ mov dx,WORD PTR dwOffset[2] ;Get the HIWORD of segment offset
+ cmp dx,WORD PTR Global.ge_dwBlockSize[2] ;Check HIWORD of size
+ jb MR_OK ;Offset should be OK
+ je @F ;Equal. Must check LOWORD
+ jmp MR_Bad ;Offset is not inside segment
+@@: mov ax,WORD PTR dwOffset[0] ;Get the LOWORD of segment offset
+ cmp ax,WORD PTR Global.ge_dwBlockSize[0] ;Check LOWORD of size
+ jb MR_OK ;It's inside segment
+ jmp MR_Bad ;Not inside segment
+MR_OK:
+
+ ;** Do different stuff on 286 and 386/486
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_CPU286 ;286?
+ jnz MR_Do16Bit ;Yes, do 16 bit stuff
+
+ ;** Do this the 386 way (easy)
+.386p
+ mov ax,wSelector ;Point with DS
+ mov ds,ax ; (keep copy in AX)
+ mov esi,dwOffset ;Point into the big segment
+ mov ecx,dwcb ;Get the copy length
+ lsl edx,eax ;Get the segment limit
+ sub edx,esi ;Get distance from offset to limit
+ inc edx ;Make this the real length
+ cmp ecx,edx ;Are we within the limit?
+ jbe SHORT MR_LimitOK ;Yes
+ mov ecx,edx ;No, so make this the copy amount
+MR_LimitOK:
+ mov edx,ecx ;Get the # of bytes to read for ret
+ xor edi,edi ;Clear the high word
+ les di,lpBuffer ;Point to the dest. buffer
+ mov ax,cx ;Save the low bits of ECX
+ shr ecx,2 ;Prepare for DWORD move
+ jecxz @F ;No zero-length DWORD moves!
+ rep movs DWORD PTR [edi],DWORD PTR [esi]
+ db 67h ;Handles 386 bug
+ db 90h
+@@: mov cx,ax ;Get a copy
+ jecxz @F ;Don't do zero!
+ and cx,03 ;Do the remaining 3,2, or 1
+ rep movs BYTE PTR [edi], BYTE PTR [esi]
+ db 67h ;Handles 386 bug
+ db 90h
+@@: mov ax,dx ;Bytes copied returned in DX:AX
+ shr edx,16
+ jmp MR_End ;Get out
+.286p
+
+ ;** Do this the 286 way (hard)
+MR_Do16Bit:
+
+ ;** Compute the actual copy length
+ mov ax,WORD PTR Global.ge_dwBlockSize[0] ;Get the segment size
+ mov dx,WORD PTR Global.ge_dwBlockSize[2]
+ sub ax,WORD PTR dwOffset[0] ;Get distance from offset to limit
+ sbb dx,WORD PTR dwOffset[2]
+ cmp dx,WORD PTR dwcb[2] ;Off end of heap block?
+ ja MR_LimOk ;No, just do it
+ jb MR_Truncate ;Yes, must truncate our length
+ cmp ax,WORD PTR dwcb[0] ;Are we off the end?
+ jae MR_LimOk ;No, just do it
+MR_Truncate:
+ mov WORD PTR dwcb[0],ax ;Force this to be the new length
+ mov WORD PTR dwcb[2],dx
+MR_LimOk:
+
+ ;** Save the number of bytes to be copied for the return value
+ mov ax,WORD PTR dwcb[0] ;Get the LOWORD
+ mov WORD PTR dwcbCopied[0],ax ;Save it
+ mov ax,WORD PTR dwcb[2] ;Get the HIWORD
+ mov WORD PTR dwcbCopied[2],ax ;Save it
+
+ ;** Position the initial copying selectors
+ mov al,BYTE PTR dwOffset[2] ;Grab the HIWORD (286 is only 24 bits)
+ mov ah,__AHINCR ;Get the selector inc value
+ mul ah ;Multiply to get sel offset
+ add ax,wSelector ;AX = sel in sel array
+ mov ds,ax ;Point to this with DS
+ mov si,WORD PTR dwOffset[0] ;Get the current pointers
+ les di,lpBuffer
+
+ ;** This is the main copying loop
+MR_CopyLoop:
+
+ ;** Compute the size of this block copy. This is done by finding the
+ ;* smaller of the following quantities:
+ ;* - Distance to end of source segment
+ ;* - Distance to end of dest. segment
+ ;** - Distance to end of copy
+ xor bx,bx ;Flags start at zero
+ xor cx,cx ;Get the highest segment value (64K)
+ cmp di,si ;The bigger of the two will win
+ je MR_Equal ;They're the same
+ ja MR_DIBigger ;DI is bigger
+ sub cx,si ;SI bigger, compute dist to end
+ or bx,SI_CRITICAL ;Flag set for SI-critical
+ jmp SHORT MR_CheckEndCopy ;Go on
+MR_Equal:
+ sub cx,di ;Use DI (SI and DI are the same)
+ or bx,SI_CRITICAL OR DI_CRITICAL ;Both will come true
+ jmp SHORT MR_CheckEndCopy ;Go on
+MR_DIBigger:
+ sub cx,di ;SI is bigger
+ or bx,DI_CRITICAL ;Flag clear for DI-critical
+MR_CheckEndCopy:
+ cmp WORD PTR dwcb[2],0 ;Check for less than 64K left
+ ja MR_DoCopy ;Nope. More than 64K left
+ jcxz MR_GetSize ;CX = 0 is full 64K segment
+ cmp WORD PTR dwcb[0],cx ;Less than in either segment left?
+ ja MR_DoCopy ;No. Do it
+MR_GetSize:
+ mov cx,WORD PTR dwcb[0] ;Get in CX
+MR_DoCopy:
+
+ ;** Do this block of 64K or less.
+ mov dx,cx ;Save the number of bytes we did
+ jcxz @F ;Do 64K
+ shr cx,1 ;Do WORDS
+ jmp SHORT MR_10 ;Skip over
+@@: mov cx,8000h ;32K WORDS
+MR_10: jcxz @F ;No zero length WORD moves!
+ rep movsw ;Do the copy
+@@: mov cx,dx ;Get any remaining bits
+ and cx,1 ;Any more to do?
+ jcxz @F ;No, don't do it
+ movsb ;Do the odd byte if necessary
+@@: mov cx,dx ;Get back in CX
+
+ ;** Bump the loop pointers
+ jcxz MR_BigCount ;We did 64K
+ sub WORD PTR dwcb[0],cx ;Subtract the bytes done
+ sbb WORD PTR dwcb[2],0 ; and don't forget the HIWORD
+ jmp SHORT MR_20 ;Continue
+MR_BigCount:
+ sub WORD PTR dwcb[2],1 ;Subtract 64K
+MR_20: mov ax,WORD PTR dwcb[0] ;We're done if the count of bytes
+ or ax,WORD PTR dwcb[2] ; is zero
+ jnz @F ;Not zero, go on
+ mov dx,WORD PTR dwcbCopied[2] ;Get the return count
+ mov ax,WORD PTR dwcbCopied[0]
+ jmp SHORT MR_End ;Get out
+@@: test bx,SI_CRITICAL ;Does SI need incrementing?
+ jz MR_TestDI ;No, try DI
+ mov ax,ds ;Get the segment value
+ add ax,__AHINCR ;Bump to next selector
+ mov ds,ax ;Point with DS still
+ xor si,si ;Point to start of this segment
+MR_TestDI:
+ test bx,DI_CRITICAL ;Does SI need incrementing?
+ jz MR_Continue ;No, try DI
+ mov ax,es ;Get the segment value
+ add ax,__AHINCR ;Bump to next selector
+ mov es,ax ;Point with DS still
+ xor di,di ;Point to start of this segment
+MR_Continue:
+ jmp MR_CopyLoop ;Do it again
+
+MR_Bad:
+ xor ax,ax ;Return DWORD 0
+ cwd
+
+MR_End:
+
+cEnd
+
+
+; MemoryWrite
+; Uses the passed in selector and offset to write memory from a user-
+; specified buffer. This works for >64K segments and, if code, may
+; have been discarded. The selector may be a selector or a handle
+; but MUST be on the global heap (no aliases or selector array
+; members). If worried about low memory conditions, lpBuffer should
+; be in a (temporarily) fixed segment.
+;
+; Prototype:
+; DWORD MemoryWrite(
+; WORD wSel, /* Selector to read from */
+; DWORD dwOffset, /* Offset to read at */
+; LPSTR lpBuffer, /* Buffer to put data into */
+; DWORD dwcb) /* Number of characters to read */
+; Returns number of characters read (ends at segment limit)
+
+cProc MemoryWrite, <FAR,PUBLIC>, <si,di,ds>
+ parmW wSelector
+ parmD dwOffset
+ parmD lpBuffer
+ parmD dwcb
+ localW wSelFlag
+ localD dwcbCopied
+ localV DPMISelBuf,8
+ localV Global,<SIZE GLOBALENTRY>
+cBegin
+ ;** Make sure the segment is present. We only will fault the
+ ;** segment in if it is a code segment
+ cCall HelperHandleToSel, <wSelector> ;Convert to sel from handle
+ mov wSelector, ax ;Save it
+ mov cx,ax ;Get the selector
+ push WORD PTR lpBuffer[2] ;Convert handle to selector
+ cCall HelperHandleToSel
+ mov WORD PTR lpBuffer[2], ax ;Save converted handle
+ mov wSelFlag,0 ;Clear the flag
+ lar ax,cx ;Get the access rights
+ jnz MW_ShortBad ;Failed
+ test ax,8000h ;Is it present?
+ jnz MW_Present ;Yes
+ test ax,0800h ;This bit set for code segments
+ jnz MW_FaultIn ;Code segment, fault it in
+MW_ShortBad:
+ jmp MW_Bad ;Return error
+MW_FaultIn:
+ mov es,wSelector ;Get the selector in ES.
+ mov al,es:[0] ;Must be at least one byte long
+MW_Present:
+
+ ;** Check this block's length. We use the global heap functions
+ ;* to do this because they check in the arena for the length.
+ ;* This is the only way to get lengths of 286 heap blocks
+ ;** beyond 64K.
+ mov ax,SIZE GLOBALENTRY ;Get the size of the structure
+ mov WORD PTR Global.ge_dwSize[0],ax ;Save in the structure
+ mov WORD PTR Global.ge_dwSize[2],0 ;Clear the HIWORD
+ lea ax,Global ;Point to the structure
+ cCall GlobalEntryHandle, <ss,ax,wSelector>
+ or ax,ax ;Was this a valid selector?
+ jnz MW_HeapSel ;Yes, this is a heap selector
+
+ ;** If this wasn't a heap selector, we get the length with an LSL.
+ ;** When used like this, 64K is the max on a 286
+MW_NonHeap:
+ mov bx,wSelector ;Get the selector
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_CPU286 ;286?
+ jz MW_32BitSize ;No, do 32 bit size stuff
+ lsl dx,bx ;Get length in DX
+ mov WORD PTR Global.ge_dwBlockSize[0],dx ;Put in GLOBALENTRY struct
+ mov WORD PTR Global.ge_dwBlockSize[2],0
+ jmp SHORT MW_HeapSel
+MW_32BitSize:
+.386p
+ lsl edx,ebx
+ mov Global.ge_dwBlockSize,edx ;Put in GLOBALENTRY struct for later
+.286p
+
+MW_HeapSel:
+ mov dx,WORD PTR dwOffset[2] ;Get the HIWORD of segment offset
+ cmp dx,WORD PTR Global.ge_dwBlockSize[2] ;Check HIWORD of size
+ jb MW_OK ;Offset should be OK
+ je @F ;Equal. Must check LOWORD
+ jmp MW_Bad ;Offset is not inside segment
+@@: mov ax,WORD PTR dwOffset[0] ;Get the LOWORD of segment offset
+ cmp ax,WORD PTR Global.ge_dwBlockSize[0] ;Check LOWORD of size
+ jb MW_OK ;It's inside segment
+ jmp MW_Bad ;Not inside segment
+MW_OK:
+ ;** Do different stuff on 286 and 386/486
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_CPU286 ;286?
+ jnz MW_Do16Bit ;Yes, do 16 bit stuff
+
+ ;** Do this the 386 way (easy)
+.386p
+ ;** Get an alias selector if necessary
+ mov ax,wSelector ;Get the source selector
+ push ss ;Get ES = SS
+ pop es
+ lea di,DPMISelBuf ;Point to our descriptor buffer
+ cCall MakeAlias ;Make the alias selector
+ jnc SHORT @F ;No error
+ jmp MW_Bad ;Must be error
+@@: mov wSelFlag,bx ;Set the selector flag
+ mov wSelector,ax ;Save the new selector
+
+ ;** Do the copying
+ mov ax,wSelector ;Point with DS
+ mov es,ax ; (keep copy in AX)
+ mov edi,dwOffset ;Point into the big segment
+ mov ecx,dwcb ;Get the copy length
+ lsl edx,eax ;Get the segment limit
+ sub edx,edi ;Get distance from offset to limit
+ inc edx ;Make this the real length
+ cmp ecx,edx ;Are we within the limit?
+ jbe SHORT MW_LimitOK ;Yes
+ mov ecx,edx ;No, so make this the copy amount
+MW_LimitOK:
+ xor esi,esi ;Clear the high word
+ lds si,lpBuffer ;Point to the dest. buffer
+ mov eax,ecx ;Save ECX
+ shr ecx,2 ;Prepare for DWORD move
+ jecxz @F ;No zero-length DWORD moves!
+ rep movs DWORD PTR [edi],DWORD PTR [esi]
+ db 67h ;Handles 386 bug
+ db 90h
+@@: mov ecx,eax ;Get a copy
+ jecxz @F ;Don't do zero!
+ and ecx,03 ;Do the remaining 3,2, or 1
+ rep movs BYTE PTR [edi], BYTE PTR [esi]
+ db 67h ;Handles 386 bug
+ db 90h
+@@: mov edx,eax ;Bytes copied returned in DX:AX
+ shr edx,16
+
+ ;** Free alias if necessary
+ push ax ;Save return value
+ push dx
+ cmp wSelFlag,0 ;Selector flag set?
+ je SHORT @F ;Nope
+ mov ax,1 ;DPMI function - Free Selector
+ mov bx,wSelector ;Selector to free
+ int 31h ;Call DPMI
+@@: pop dx
+ pop ax
+ jmp MW_End ;Get out
+.286p
+
+ ;** Do this the 286 way (hard)
+MW_Do16Bit:
+
+ ;** Compute the actual copy length
+ mov ax,WORD PTR Global.ge_dwBlockSize[0] ;Get the segment size
+ mov dx,WORD PTR Global.ge_dwBlockSize[2]
+ sub ax,WORD PTR dwOffset[0] ;Get distance from offset to limit
+ sbb dx,WORD PTR dwOffset[2]
+ cmp dx,WORD PTR dwcb[2] ;Off end of heap block?
+ ja MW_LimOk ;No, just do it
+ jb MW_Truncate ;Yes, must truncate our length
+ cmp ax,WORD PTR dwcb[0] ;Are we off the end?
+ jae MW_LimOk ;No, just do it
+MW_Truncate:
+ mov WORD PTR dwcb[0],ax ;Force this to be the new length
+ mov WORD PTR dwcb[2],dx
+MW_LimOk:
+
+ ;** Save the number of bytes to be copied for the return value
+ mov ax,WORD PTR dwcb[0] ;Get the LOWORD
+ mov WORD PTR dwcbCopied[0],ax ;Save it
+ mov ax,WORD PTR dwcb[2] ;Get the HIWORD
+ mov WORD PTR dwcbCopied[2],ax ;Save it
+
+ ;** Position the initial copying selectors
+ mov al,BYTE PTR dwOffset[2] ;Grab the HIWORD (286 is only 24 bits)
+ mov ah,__AHINCR ;Get the selector inc value
+ mul ah ;Multiply to get sel offset
+ add ax,wSelector ;AX = sel in sel array
+ mov es,ax ;Point to this with DS
+ mov di,WORD PTR dwOffset[0] ;Get the current pointers
+ lds si,lpBuffer
+
+ ;** This is the main copying loop
+MW_CopyLoop:
+
+ ;** Get an alias selector if necessary
+ push si ;Save regs
+ push di
+ mov ax,es ;Get the source selector
+ push ss ;Get ES = SS
+ pop es
+ lea di,DPMISelBuf ;Point to our descriptor buffer
+ cCall MakeAlias ;Make the alias selector
+ pop di ;Restore regs
+ pop si
+ jnc @F ;No error
+ jmp MW_Bad ;Must be error
+@@: mov wSelFlag,bx ;Set the selector flag
+ mov es,ax ;Save the new selector
+
+ ;** Compute the size of this block copy. This is done by finding the
+ ;* smaller of the following quantities:
+ ;* - Distance to end of source segment
+ ;* - Distance to end of dest. segment
+ ;** - Distance to end of copy
+ xor bx,bx ;Flags start at zero
+ xor cx,cx ;Get the highest segment value (64K)
+ cmp di,si ;The bigger of the two will win
+ je MW_Equal ;They're the same
+ ja MW_DIBigger ;DI is bigger
+ sub cx,si ;SI bigger, compute dist to end
+ or bx,SI_CRITICAL ;Flag set for SI-critical
+ jmp SHORT MW_CheckEndCopy ;Go on
+MW_Equal:
+ sub cx,di ;Use DI (SI and DI are the same)
+ or bx,SI_CRITICAL OR DI_CRITICAL ;Both will come true
+ jmp SHORT MW_CheckEndCopy ;Go on
+MW_DIBigger:
+ sub cx,di ;SI is bigger
+ or bx,DI_CRITICAL ;Flag clear for DI-critical
+MW_CheckEndCopy:
+ cmp WORD PTR dwcb[2],0 ;Check for less than 64K left
+ ja MW_DoCopy ;Nope. More than 64K left
+ jcxz MW_GetSize ;CX = 0 is full 64K segment
+ cmp WORD PTR dwcb[0],cx ;Less than in either segment left?
+ ja MW_DoCopy ;No. Do it
+MW_GetSize:
+ mov cx,WORD PTR dwcb[0] ;Get in CX
+MW_DoCopy:
+
+ ;** Do this block of 64K or less.
+ mov dx,cx ;Save the number of bytes we did
+ jcxz @F ;Do 64K
+ shr cx,1 ;Do WORDS
+ jmp SHORT MW_10 ;Skip over
+@@: mov cx,8000h ;32K WORDS
+MW_10: jcxz @F ;No zero-length WORD moves
+ rep movsw ;Do the copy
+@@: mov cx,dx ;Get any remaining bits
+ and cx,1 ;Any more to do?
+ jcxz @F ;No, don't do it
+ movsb ;Do the odd byte if necessary
+@@: mov cx,dx ;Get back in CX
+
+ ;** Bump the loop pointers
+ jcxz MW_BigCount ;We did 64K
+ sub WORD PTR dwcb[0],cx ;Subtract the bytes done
+ sbb WORD PTR dwcb[2],0 ; and don't forget the HIWORD
+ jmp SHORT MW_20 ;Continue
+MW_BigCount:
+ sub WORD PTR dwcb[2],1 ;Subtract 64K
+MW_20: mov ax,WORD PTR dwcb[0] ;We're done if the count of bytes
+ or ax,WORD PTR dwcb[2] ; is zero
+ jnz @F ;Not zero, go on
+ mov dx,WORD PTR dwcbCopied[2] ;Get the return count
+ mov ax,WORD PTR dwcbCopied[0]
+ jmp SHORT MW_End ;Get out
+@@: test bx,SI_CRITICAL ;Does SI need incrementing?
+ jz MW_TestDI ;No, try DI
+ mov ax,ds ;Get the segment value
+ add ax,__AHINCR ;Bump to next selector
+ mov ds,ax ;Point with DS still
+ xor si,si ;Point to start of this segment
+MW_TestDI:
+ test bx,DI_CRITICAL ;Does SI need incrementing?
+ jz MW_Continue ;No, try DI
+ mov ax,es ;Get the segment value
+ add ax,__AHINCR ;Bump to next selector
+ mov es,ax ;Point with DS still
+ xor di,di ;Point to start of this segment
+MW_Continue:
+
+ ;** Free alias if necessary
+ cmp wSelFlag,0 ;Selector flag set?
+ je @F ;Nope
+ mov ax,1 ;DPMI function - Free Selector
+ mov bx,wSelector ;Selector to free
+ int 31h ;Call DPMI
+@@: jmp MW_CopyLoop ;Do it again
+
+MW_Bad:
+ xor ax,ax ;Return DWORD 0
+ cwd
+
+MW_End:
+
+cEnd
+
+
+;** Helper functions
+
+; MakeAlias
+; Makes an alias selector for the selector in AX. The new selector
+; is returned in AX. Carry is set on exit if error.
+; Returns nonzero in BX if an alias was made, zero if not
+; ES:DI points to an 8-byte descriptor buffer
+
+cProc MakeAlias, <NEAR, PUBLIC>, <si,di>
+cBegin
+
+ ;** If this is not a read/write selector, we must create an alias.
+ ;* In order to be able to free up the selector, we set a flag
+ ;** so we know to free it.
+ xor si,si ;No alias made, just in case
+ lar cx,ax ;Get its access rights
+ jnz MA_Bad ;Failed
+ test cx,800h ;Is this a code segment?
+ jnz MA_MakeAlias ;Yes. Always make an alias
+ test cx,200h ;Is it read/write?
+ jnz MA_End ;Yes, no need for alias
+MA_MakeAlias:
+ mov bx,ax ;Get the selector
+ mov ax,0bh ;DPMI function - Get Descriptor
+ ;ES:DI already point to buffer
+ int 31h ;Call DPMI
+ jc MA_Bad ;Error
+ xor ax,ax ;DPMI Function - Alloc selector
+ mov cx,1 ;Alloc 1 selector
+ int 31h ;Call DPMI
+ jc MA_Bad ;Error
+ mov si,1 ;Set flag to say alias made
+ and BYTE PTR DPMISelBuf[5],0f0h ;Mask out unwanted bits
+ or BYTE PTR DPMISelBuf[5],2 ;Make it a R/W Data segment
+ mov bx,ax ;Selector in BX
+ mov ax,0ch ;DPMI function - Set Descriptor
+ int 31h ;Call DPMI
+ jc MA_Bad ;Error
+ mov ax,bx ;Get the new selector in AX
+ jmp SHORT MA_End ;Get out
+
+MA_Bad:
+ stc ;Error
+
+MA_End:
+ mov bx,si ;Get flag in BX
+cEnd
+
+
+sEnd
+
+ END
+
diff --git a/private/mvdm/wow16/toolhelp/module.c b/private/mvdm/wow16/toolhelp/module.c
new file mode 100644
index 000000000..72270feba
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/module.c
@@ -0,0 +1,156 @@
+/*************************************************************************
+ * MODULE.C
+ *
+ * Routines to enumerate the various module headers on the module
+ * chain.
+ *
+ *************************************************************************/
+
+#include "toolpriv.h"
+#include <newexe.h>
+#include <string.h>
+
+/* ----- Function prototypes ----- */
+
+ NOEXPORT BOOL PASCAL ModuleGetInfo(
+ WORD wModule,
+ MODULEENTRY FAR *lpModule);
+
+/* ModuleFirst
+ * Finds the first module in the module list and returns information
+ * about this module.
+ */
+
+BOOL TOOLHELPAPI ModuleFirst(
+ MODULEENTRY FAR *lpModule)
+{
+ WORD FAR *lpwExeHead;
+
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpModule ||
+ lpModule->dwSize != sizeof (MODULEENTRY))
+ return FALSE;
+
+ /* Get a pointer to the module head */
+ lpwExeHead = MAKEFARPTR(segKernel, npwExeHead);
+
+ /* Use this pointer to get information about this module */
+ return ModuleGetInfo(*lpwExeHead, lpModule);
+}
+
+
+/* ModuleNext
+ * Finds the next module in the module list.
+ */
+
+BOOL TOOLHELPAPI ModuleNext(
+ MODULEENTRY FAR *lpModule)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpModule ||
+ lpModule->dwSize != sizeof (MODULEENTRY))
+ return FALSE;
+
+ /* Use the next handle to get information about this module */
+ return ModuleGetInfo(lpModule->wNext, lpModule);
+}
+
+
+/* ModuleFindName
+ * Finds a module with the given module name and returns information
+ * about it.
+ */
+
+HANDLE TOOLHELPAPI ModuleFindName(
+ MODULEENTRY FAR *lpModule,
+ LPCSTR lpstrName)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpModule || !lpstrName ||
+ lpModule->dwSize != sizeof (MODULEENTRY))
+ return NULL;
+
+ /* Loop through module chain until we find the name (or maybe we don't) */
+ if (ModuleFirst(lpModule))
+ do
+ {
+ /* Is this the name? If so, we have the info, so return */
+ if (!lstrcmp(lpstrName, lpModule->szModule))
+ return lpModule->hModule;
+ }
+ while (ModuleNext(lpModule));
+
+ /* If we get here, we didn't find it or there was an error */
+ return NULL;
+}
+
+
+/* ModuleFindHandle
+ * Returns information about a module with the given handle.
+ */
+
+HANDLE TOOLHELPAPI ModuleFindHandle(
+ MODULEENTRY FAR *lpModule,
+ HANDLE hModule)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpModule || !hModule ||
+ lpModule->dwSize != sizeof (MODULEENTRY))
+ return NULL;
+
+ /* Use the helper function to find out about this module */
+ if (!ModuleGetInfo(hModule, lpModule))
+ return NULL;
+
+ return lpModule->hModule;
+}
+
+
+/* ----- Helper functions ----- */
+
+NOEXPORT BOOL PASCAL ModuleGetInfo(
+ WORD wModule,
+ MODULEENTRY FAR *lpModule)
+{
+ struct new_exe FAR *lpNewExe;
+ BYTE FAR *lpb;
+
+ /* Verify the segment so we don't GP fault */
+ if (!HelperVerifySeg(wModule, 2))
+ return FALSE;
+
+ /* Get a pointer to the module database */
+ lpNewExe = MAKEFARPTR(wModule, 0);
+
+ /* Make sure this is a module database */
+ if (lpNewExe->ne_magic != NEMAGIC)
+ return FALSE;
+
+ /* Get the module name (it's the first name in the resident names
+ * table
+ */
+ lpb = ((BYTE FAR *)lpNewExe) + lpNewExe->ne_restab;
+ _fstrncpy(lpModule->szModule, lpb + 1, *lpb);
+ lpModule->szModule[*lpb] = '\0';
+
+ /* Get the EXE file path. A pointer is stored in the same place as
+ * the high word of the CRC was in the EXE file. (6th word in new_exe)
+ * This pointer points to the length of a PASCAL string whose first
+ * eight characters are meaningless to us.
+ */
+ lpb = MAKEFARPTR(wModule, *(((WORD FAR *)lpNewExe) + 5));
+ _fstrncpy(lpModule->szExePath, lpb + 8, *lpb - 8);
+ lpModule->szExePath[*lpb - 8] = '\0';
+
+ /* Get other information from the EXE Header
+ * The usage count is stored in the second word of the EXE header
+ * The handle of the next module in the chain is stored in the
+ * ne_cbenttab structure member.
+ */
+ lpModule->hModule = wModule;
+ lpModule->wcUsage = *(((WORD FAR *)lpNewExe) + 1);
+ lpModule->wNext = lpNewExe->ne_cbenttab;
+
+ return TRUE;
+}
+
diff --git a/private/mvdm/wow16/toolhelp/notify1.c b/private/mvdm/wow16/toolhelp/notify1.c
new file mode 100644
index 000000000..bf101ad4d
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/notify1.c
@@ -0,0 +1,165 @@
+/**************************************************************************
+ * NOTIFY1.C
+ *
+ * Routines used to implement the Debugger Notification API in
+ * TOOLHELP.DLL
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include "toolpriv.h"
+
+/* ----- Global variables ----- */
+ WORD wNotifyInstalled;
+ NOTIFYSTRUCT NEAR *npNotifyHead;
+ NOTIFYSTRUCT NEAR *npNotifyNext;
+
+/* NotifyRegister
+ * Registers a debugger notification callback. This callback will
+ * be called whenever KERNEL has a notification to be sent.
+ * The format of the call to the callback function is documented
+ * elsewhere.
+ */
+
+BOOL TOOLHELPAPI NotifyRegister(
+ HANDLE hTask,
+ LPFNNOTIFYCALLBACK lpfn,
+ WORD wFlags)
+{
+ NOTIFYSTRUCT *pInfo;
+ NOTIFYSTRUCT *pTemp;
+
+ /* Make sure TOOLHELP.DLL is installed */
+ if (!wLibInstalled)
+ return FALSE;
+
+ /* If the notification hook has not yet been installed, install it */
+ if (!wNotifyInstalled)
+ {
+ /* Make sure we can get a hook! */
+ if (!NotifyInit())
+ return FALSE;
+ wNotifyInstalled = TRUE;
+ }
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* Register a death signal handler for this task (does nothing if one
+ * is already installed.
+ */
+ SignalRegister(hTask);
+
+ /* Check to see if this task is already registered */
+ for (pInfo = npNotifyHead ; pInfo ; pInfo = pInfo->pNext)
+ if (pInfo->hTask == hTask)
+ return FALSE;
+
+ /* Allocate a new NOTIFYSTRUCT structure */
+ pInfo = (NOTIFYSTRUCT *)LocalAlloc(LMEM_FIXED, sizeof (NOTIFYSTRUCT));
+ if (!pInfo)
+ return FALSE;
+
+ /* Fill in the useful fields */
+ pInfo->hTask = hTask;
+ pInfo->wFlags = wFlags;
+ pInfo->lpfn = lpfn;
+
+ /* If this is the only handler, just insert it */
+ if (!npNotifyHead)
+ {
+ pInfo->pNext = npNotifyHead;
+ npNotifyHead = pInfo;
+ }
+
+ /* Otherwise, insert at the end of the list */
+ else
+ {
+ for (pTemp = npNotifyHead ; pTemp->pNext ; pTemp = pTemp->pNext)
+ ;
+ pInfo->pNext = pTemp->pNext;
+ pTemp->pNext = pInfo;
+ }
+
+ return TRUE;
+}
+
+
+/* NotifyUnRegister
+ * Called by an app whose callback is no longer to be used.
+ * NULL hTask uses current task.
+ */
+
+BOOL TOOLHELPAPI NotifyUnRegister(
+ HANDLE hTask)
+{
+ NOTIFYSTRUCT *pNotify;
+ NOTIFYSTRUCT *pBefore;
+
+ /* Make sure we have notifications installed and that TOOLHELP is OK */
+ if (!wLibInstalled || !wNotifyInstalled)
+ return FALSE;
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* First try to find the task */
+ pBefore = NULL;
+ for (pNotify = npNotifyHead ; pNotify ; pNotify = pNotify->pNext)
+ if (pNotify->hTask == hTask)
+ break;
+ else
+ pBefore = pNotify;
+ if (!pNotify)
+ return FALSE;
+
+ /* Unhook the death signal proc only if there is no interrupt handler */
+ if (!InterruptIsHooked(hTask))
+ SignalUnRegister(hTask);
+
+ /* Check to see if the notification handler is about to use this entry.
+ * If it is, we point it to the next one, if any.
+ */
+ if (npNotifyNext == pNotify)
+ npNotifyNext = pNotify->pNext;
+
+ /* Remove it from the list */
+ if (!pBefore)
+ npNotifyHead = pNotify->pNext;
+ else
+ pBefore->pNext = pNotify->pNext;
+
+ /* Free the structure */
+ LocalFree((HANDLE)pNotify);
+
+ /* If there are no more handlers, unhook the callback */
+ if (!npNotifyHead)
+ {
+ NotifyUnInit();
+ wNotifyInstalled = FALSE;
+ }
+
+ return TRUE;
+}
+
+/* ----- Helper functions ----- */
+
+/* NotifyIsHooked
+ * Returns TRUE iff the parameter task already has a notification hook.
+ */
+
+BOOL PASCAL NotifyIsHooked(
+ HANDLE hTask)
+{
+ NOTIFYSTRUCT *pNotify;
+
+ /* Loop thorugh all notifications */
+ for (pNotify = npNotifyHead ; pNotify ; pNotify = pNotify->pNext)
+ if (pNotify->hTask == hTask)
+ break;
+
+ /* Return found/not found */
+ return (BOOL)pNotify;
+}
diff --git a/private/mvdm/wow16/toolhelp/notify2.asm b/private/mvdm/wow16/toolhelp/notify2.asm
new file mode 100644
index 000000000..974c192b1
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/notify2.asm
@@ -0,0 +1,643 @@
+ PAGE 60,150
+;***************************************************************************
+;* NOTIFY2.ASM
+;*
+;* Assembly code support routines used for the TOOLHELP.DLL
+;* notification API
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+.286p
+
+;** Data
+sBegin DATA
+
+globalW wCASRqFlag,0 ;Set when an CASRq INT3 has been set
+globalD dwCASRqCSIP,0 ;Holds the CS:IP of the CASRq INT3
+globalD lpfnOldProc,0 ;Old hook from new PTrace hook
+szWinDebug DB 'WINDEBUG', 0
+
+;** WARNING!!
+;** This structure is set to the size of the largest notification
+;** structure. This is currently NFYLOADSEG which is 16 bytes long.
+;** If a structure is added that is longer than this or if any other
+;** structure is added, this space must be increased to match!!
+ReturnStruct DB 16 DUP (?)
+
+sEnd
+
+;** Imports
+externFP GetModuleHandle
+externFP RegisterPTrace
+externFP OutputDebugString
+externFP AllocCStoDSAlias
+externFP FreeSelector
+externNP HelperHandleToSel
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+; NotifyInit
+; Called when the first app registers a notification handler.
+; Hooks the Register PTrace notification.
+; Returns FALSE if we couldn't initialize, TRUE otherwise
+
+cProc NotifyInit, <NEAR,PUBLIC>, <si,di,ds>
+cBegin
+ ;** In the Windows 3.1 KERNEL, there is a special hook just for
+ ;* TOOLHELP that lets us get PTrace stuff and still coexist
+ ;* with old-fashioned debuggers. We can check to see if the
+ ;* hook exists by simply checking the TOOLHELP flags
+ ;**
+ test wTHFlags,TH_GOODPTRACEHOOK ;Good hook around?
+ jz DNI_UseRegPTrace ;Nope, use the old one
+ lea si,NotifyHandler ;Point to the routine
+ push cs ;Parameter is lpfn to callback
+ push si
+ call lpfnNotifyHook ;Hook it
+ mov WORD PTR lpfnOldProc[0],ax ;Save old proc
+ mov WORD PTR lpfnOldProc[2],dx
+ jmp SHORT DNI_10 ;We're in
+
+ ;** Since there's no way we can see if someone else has Register
+ ;* PTrace, we just connect and hope for the best!
+ ;** We do check, however, to see if WINDEBUG.DLL is installed.
+DNI_UseRegPTrace:
+ lea si,szWinDebug ;Get the name of the module
+ cCall GetModuleHandle, <ds,si> ;Is WINDEBUG present?
+ or ax,ax ;Check the handle
+ jnz DNI_Fail ;It's here so fail
+ or wTHFlags,TH_GOTOLDPTRACE ;Flag that we made the hook
+ lea si,NotifyHandler ;Point to our routine
+ cCall RegisterPTrace, <cs,si> ;Tell KERNEL to use it
+
+ ;** Connect to the FatalExit hook. We currently ignore
+ ;** the return value, thus unhooking anyone else
+DNI_10: cmp WORD PTR lpfnFatalExitHook + 2,0 ;Can we hook it?
+ jz DNI_20 ;Can't do it
+ push cs ;Get the CS:IP of RIP handler
+ push OFFSET NotifyRIPHandler
+ call DWORD PTR lpfnFatalExitHook ;Tell KERNEL to insert the hook
+DNI_20:
+
+ ;** Return OK
+ mov ax,TRUE ;Return TRUE
+ jmp SHORT DNI_End ;Get out
+
+DNI_Fail:
+ xor ax,ax ;FALSE
+
+DNI_End:
+cEnd
+
+
+; NotifyUnInit
+; Called when the no more apps have hooked notification handlers
+; so the hook to the Register PTrace notification is no longer needed.
+
+cProc NotifyUnInit, <NEAR,PUBLIC>, <si,di,ds>
+cBegin
+ ;** Did we have a new hook to undo?
+ test wTHFlags,TH_GOODPTRACEHOOK ;Do we have a new hook?
+ jz DNU_TryOldPTrace ;No
+ push WORD PTR lpfnOldProc[0] ;Get the old proc
+ push WORD PTR lpfnOldProc[2]
+ call lpfnNotifyHook ;Unhook ourself
+ jmp SHORT DNU_NoOldPTrace
+
+ ;** Unhook the old-style hook if necessary
+DNU_TryOldPTrace:
+ test wTHFlags,TH_GOTOLDPTRACE ;Did we have a hook?
+ jz DNU_NoOldPTrace ;No
+ push 0
+ push 0
+ call RegisterPTrace ;Call KERNEL's routine to unhook
+DNU_NoOldPTrace:
+
+ ;** Unhook alternate hooks
+ cmp WORD PTR lpfnFatalExitHook + 2,0 ;Can we unhook it?
+ jz DNU_NoRIP ;Can't do it
+ xor ax,ax ;Remove any other hooks
+ push ax ;NULL procedure
+ push ax
+ call DWORD PTR lpfnFatalExitHook
+DNU_NoRIP:
+
+cEnd
+
+
+; NotifyHandler
+; This routine is called directly by PTrace and is used to
+; dispatch the notifications to all registered callbacks.
+
+cProc NotifyHandler, <FAR,PUBLIC>
+cBegin NOGEN
+
+ ;** Push a register frame
+ ;* When done, it should look like this:
+ ;* ------------
+ ;* | ES | [BP - 14h]
+ ;* | DS | [BP - 12h]
+ ;* | DI | [BP - 10h]
+ ;* | SI | [BP - 0Eh]
+ ;* | BP | [BP - 0Ch]
+ ;* | SP | [BP - 0Ah]
+ ;* | BX | [BP - 08h]
+ ;* | DX | [BP - 06h]
+ ;* | CX | [BP - 04h]
+ ;* | AX | [BP - 02h]
+ ;* BP-->| Old BP | [BP - 00h]
+ ;* | IP | [BP + 02h]
+ ;* | CS | [BP + 04h]
+ ;* ------------
+ ;**
+ push bp ;Make a stack frame
+ mov bp,sp
+ pusha ;Save all registers
+ push ds ;Save segment registers, too
+ push es
+
+ ;** Get the data segment
+ mov bx,_DATA ;Get TOOLHELP data segment
+ mov ds,bx
+
+ ;** If in 3.0 std mode and we get this wild notification 69h,
+ ;** translate it to a inchar notification as this is what it
+ ;** is supposed to be.
+ cmp ax,69h ;Bogus notification?
+ jne NH_NoBogusNotify ;No, don't do this
+ test wTHFlags,TH_WIN30STDMODE ;3.0 standard mode?
+ jz NH_NoBogusNotify ;No, might be valid in the future...
+ mov ax,NI_INCHAR ;Put in real notify value
+NH_NoBogusNotify:
+
+ ;** Special case notifications:
+ ;* Notification 63h means that CtlAltSysRq was pressed. For
+ ;* this, we want to handle as an interrupt, not a notification.
+ ;* To do this, we set a breakpoint and set a flag so that the
+ ;** INT3 handler knows what to do with it
+ cmp ax,63h ;CtlAltSysRq?
+ jne NH_NoCASRq ;No.
+ mov ax,[bp + 04h] ;Since we can't use IRET CS:IP, get
+ mov si,[bp + 02h] ; a safe address in KERNEL
+ mov WORD PTR dwCASRqCSIP[2],ax ;Save the CS:IP value
+ cCall AllocCStoDSAlias, <ax> ;Get a data alias to the CS
+ or ax,ax ;Error?
+ jnz @F
+ jmp SHORT DNH_End ;Yes, get out
+@@: verw ax ;OK to write to?
+ jnz DNH_NoWrite ;Yes, so do it
+DNH_IRETCSOK:
+ mov es,ax ;Point with ES
+ mov WORD PTR dwCASRqCSIP[0],si
+ mov al,es:[si] ;Get the character there
+ mov ah,1 ;Make sure there's something in AH
+ mov wCASRqFlag,ax ;Save the thing for the INT3 handler
+ mov BYTE PTR es:[si],0cch ;Poke the INT3 in there
+ mov ax,es ;Get the selector back
+DNH_NoWrite:
+ cCall FreeSelector, <ax> ;Get rid of the alias
+ jmp SHORT DNH_End ;Get out. This will INT3 soon
+
+NH_NoCASRq: ; Does not return
+
+ ;** Notifications to ignore here:
+ ;** Notification 60h is bogus and should be ignored
+ cmp ax,60h ;PostLoad notification?
+ jz DNH_End ;Yes, don't report
+
+ ;** Decode the notification
+ cCall DecodeNotification ;Returns dwData in CX:DX, AX is wID
+ ; BX is NOTIFYSTRUCT match flags
+ ;** This is an entry point for notifications from sources other than
+ ;** PTrace
+DNH_Decoded:
+
+ ;** Loop through callbacks
+ mov di,npNotifyHead ;Point to the start of the list
+ xor si,si ;FALSE return value is default
+DNH_Loop:
+ push ax
+ mov ax,ds:[di].ns_pNext ;Save the next pointer in a global
+ mov npNotifyNext,ax ; so we can chain in NotifyUnregister
+ pop ax
+
+ or di,di ;End of list?
+ jz DNH_Done ;Yep. Get out
+
+ ;** If the flags for this notification are zero, we always send it
+ or bx,bx ;Check the matching flags
+ jz DNH_DoIt ;Do notification
+
+ ;** See if the flags match
+ test bx,ds:[di].ns_wFlags ;Check against the NOTIFYSTRUCT flags
+ jz DNH_Continue ;If zero, no match, don't do it
+
+ ;** Call the user callback
+DNH_DoIt:
+ push ax ;Save everything we need
+ push bx
+ push cx
+ push dx
+
+ push ax ;wID
+ push cx ;High word of dwData
+ push dx ;Low word
+ call DWORD PTR ds:[di].ns_lpfn ;Call the callback (PASCAL style)
+ mov si,ax ;Get return value in SI
+
+ pop dx ;Restore everything
+ pop cx
+ pop bx
+ pop ax
+
+ ;** If the return value is nonzero, we don't want to give this to
+ ;** any more callbacks
+ or si,si ;TRUE return value?
+ jnz DNH_Done ;Yes, get out
+
+ ;** Get the next callback
+DNH_Continue:
+ mov di,npNotifyNext ;Get next pointer
+ jmp DNH_Loop ; and loop back
+
+ ;** End of callback loop.
+DNH_Done:
+
+ ;** If this was an InChar message but everyone ignored it, force
+ ;** the return to be an 'i' for 'ignore' on RIPs. This i
+ ;** only necessary in 3.0 because the 3.1 KERNEL treats 0
+ ;** returns just like 'i'
+ cmp ax,NFY_INCHAR ;Is this an InChar notification?
+ jne DNH_Default ;No, so ignore
+ test wTHFlags,TH_WIN30 ;In 3.0?
+ jz DNH_Default ;No, don't do this
+ and si,0ffh ;Ignore all but low byte
+ or si,si ;Non-zero?
+ jnz DNH_Default ;Yes, return it as the character
+ mov si,'i' ;Instead of zero, return 'i'gnore.
+DNH_Default:
+ mov [bp - 02h],si ;Return the return code in AX
+
+ ;** Clear off the stack and exit
+DNH_End:
+ mov npNotifyNext,0 ;No current next pointer
+
+ pop es ;Restore all registers
+ pop ds
+ popa
+ pop bp
+ retf ;Just return
+
+cEnd NOGEN
+
+
+; NotifyRIPHandler
+; Gets called by KERNEL when a RIP occurs. If it returns TRUE,
+; KERNEL will act like the RIP was ignored. Otherwise, the RIP
+; procedes normally.
+; This routine does not need to worry about saving non-C regs
+
+cProc NotifyRIPHandler, <FAR,PUBLIC>
+; parmW wExitCode
+cBegin nogen
+
+ ;** Clear PASCAL-style parameters
+ push bp ;Make a stack frame
+ mov bp,sp
+ mov bx,[bp + 6] ;Get the BP value
+ mov dx,[bp + 8] ;Get the Exit code
+ mov [bp - 2],ax ;Save it out of the way for now
+ mov ax,[bp + 4] ;Get the RETF CS value
+ mov [bp + 8],ax ;Shift down to clear parameters
+ mov ax,[bp + 2] ;Get the RETF IP value
+ mov [bp + 6],ax ;Shift down to clear parameters
+ mov ax,[bp + 0] ;Get the old BP value
+ mov [bp + 4],ax ;Shift down
+ add bp,4 ;Move BP down on the stack
+ mov sp,bp ;Point SP there too
+ pusha ;Save matching register frame
+ push ds
+ push es
+
+ ;** Get the data segment
+ mov ax,_DATA ;Get TOOLHELP data segment
+ mov ds,ax
+
+
+ ;** Prepare to jump into the notification handler.
+ ;** The trick here is that if a notification callback returns
+ ;** non-zero, the RIP has been handled. Otherwise, it has not.
+ ;** DX holds the exit code here, BX has the old BP value
+ lea si,ReturnStruct ;Get a pointer to the return struct
+ mov WORD PTR [si].nrp_dwSize[0],SIZE NFYRIP
+ mov WORD PTR [si].nrp_dwSize[2],0
+ mov ax,ss:[bx + 4] ;Get old CS value from stack
+ mov [si].nrp_wCS,ax ; (BX is BP from FatalExit stack)
+ mov ax,ss:[bx + 2] ;Get old IP value
+ mov [si].nrp_wIP,ax
+ mov [si].nrp_wSS,ss ;Save SS:BP for stack trace
+ mov [si].nrp_wBP,bx
+ mov [si].nrp_wExitCode,dx
+ mov cx,ds ;Point to structure
+ mov dx,si
+ mov bx,NF_RIP ;Get the NOTIFYINFO match flags
+ mov ax,NFY_RIP ;TOOLHELP ID
+
+ ;** Jump to the real handler
+ jmp DNH_Decoded ;Jump to alternate entry point
+
+cEnd nogen
+
+;** Helper routines
+
+; DecodeNotification
+; Decodes a notification by pointing to a static structure and filling
+; this structure with notification-specific information.
+; The PTrace notification ID is in AX.
+; Returns the ToolHelp ID in AX
+; and the dwData value is in CX:DX.
+
+cProc DecodeNotification, <NEAR,PUBLIC>
+cBegin
+ ;** Point dwData to the structure just in case
+ mov cx,ds ;Get the segment value
+ lea dx,ReturnStruct ;Get a pointer to the return struct
+ xor bx,bx ;Most notifications always match
+
+ ;** The stack frame looks like this:
+ ;* ------------
+ ;* | ES | [BP - 14h]
+ ;* | DS | [BP - 12h]
+ ;* | DI | [BP - 10h]
+ ;* | SI | [BP - 0Eh]
+ ;* | BP | [BP - 0Ch]
+ ;* | SP | [BP - 0Ah]
+ ;* | BX | [BP - 08h]
+ ;* | DX | [BP - 06h]
+ ;* | CX | [BP - 04h]
+ ;* | AX | [BP - 02h]
+ ;* BP-->| Old BP | [BP - 00h]
+ ;* ------------
+ ;**
+FrameES EQU [BP - 14h]
+FrameDS EQU [BP - 12h]
+FrameDI EQU [BP - 10h]
+FrameSI EQU [BP - 0Eh]
+FrameBP EQU [BP - 0Ch]
+FrameSP EQU [BP - 0Ah]
+FrameBX EQU [BP - 08h]
+FrameDX EQU [BP - 06h]
+FrameCX EQU [BP - 04h]
+FrameAX EQU [BP - 02h]
+
+ ;** Check for LoadSeg
+ cmp ax,NI_LOADSEG ;LoadSeg?
+ jnz DN_10 ;No
+
+ ;** LoadSeg:
+ ;* CX is selector
+ ;* BX is segment number
+ ;* SI is type: Low bit set for data segment, clear for code
+ ;* DX is instance count only for data segments
+ ;** ES:DI module name
+ mov si,dx ;Point to NFYLOADSEG struct
+ mov ax,SIZE NFYLOADSEG ;Get the structure size
+ mov WORD PTR [si].nls_dwSize,ax ;Save the LOWORD of the size
+ mov WORD PTR [si].nls_dwSize + 2,0 ;HIWORD is zero
+ mov ax,FrameCX ;Get selector
+ mov [si].nls_wSelector,ax ;Save in structure
+ mov ax,FrameBX ;Get segment number
+ inc ax ;Segment number is 1-based
+ mov [si].nls_wSegNum,ax ;Save in structure
+ mov ax,FrameSI ;Get the segment type
+ mov [si].nls_wType,ax ;Put in structure
+ mov ax,FrameDX ;Get instance count
+ mov [si].nls_wcInstance,ax ;Put in structure
+ mov ax,FrameDI ;Get offset of module name str
+ mov WORD PTR [si].nls_lpstrModuleName,ax ;Save it
+ mov ax,FrameES ;Get segment of module name str
+ mov WORD PTR [si].nls_lpstrModuleName + 2,ax ;Save it
+ mov ax,NFY_LOADSEG ;Get the TOOLHELP ID
+ jmp DN_End
+
+ ;** Check for FreeSeg
+DN_10: cmp ax,NI_FREESEG ;FreeSeg?
+ jnz DN_15 ;No
+
+ ;** FreeSeg:
+ ;** BX is selector
+ xor cx,cx ;Clear high word
+ mov dx,FrameBX ;Get the selector
+ test wTHFlags,TH_WIN30STDMODE ;3.0 standard mode?
+ jz DN_FS_GotSelValue ;No, what we have is correct
+ mov si,FrameSP ;Point to old stack frame
+ mov dx, ss:[si + 6] ;Selector is 6 bytes down
+ lsl ax, dx
+ jz DN_FS_CheckLen ;Selector is OK
+ mov dx, FrameBX ;Revert to BX value
+ jmp SHORT DN_FS_GotSelValue
+DN_FS_CheckLen:
+ cmp ax, 15 ;If the segment is 15 bytes long,
+ jne DN_FS_GotSelValue ; this is a bogus selector and is
+ ; really an arena header.
+ push es
+ mov es, dx ;Get handle
+ cCall HelperHandleToSel, <es:[0ah]> ;Convert to selector
+ mov dx, ax ;Get handle out of arena header
+ pop es
+DN_FS_GotSelValue:
+ mov ax,NFY_FREESEG ;Get the TOOLHELP ID
+ jmp DN_End
+
+ ;** Check for StartDLL
+DN_15: cmp ax,NI_LOADDLL
+ jnz DN_20
+
+ ;** StartDLL:
+ ;** CX is CS
+ ;** BX is IP
+ ;** SI is Module handle
+ mov si,dx ;Point with SI
+ mov ax,SIZE NFYSTARTDLL ;Get the size
+ mov WORD PTR [si].nsd_dwSize,ax ;Save the LOWORD of the size
+ mov WORD PTR [si].nsd_dwSize + 2,0 ;HIWORD is always zero
+ mov ax,FrameSI ;Get the hInstance
+ mov [si].nsd_hModule,ax ;Save in structure
+ mov ax,FrameCX ;Get the starting CS
+ mov [si].nsd_wCS,ax ;Save in structure
+ mov ax,FrameBX ;Get the starting IP
+ mov [si].nsd_wIP,ax ;Save in structure
+ mov ax,NFY_STARTDLL
+ jmp DN_End
+
+ ;** Check for StartTask
+DN_20: cmp ax,NI_STARTTASK ;StartTask?
+ jnz DN_30 ;No
+
+ ;** StartTask:
+ ;* CX is CS
+ ;** BX is IP
+ mov cx,FrameCX
+ mov dx,FrameBX
+ mov ax,NFY_STARTTASK
+ jmp DN_End
+
+ ;** Check for ExitCall
+DN_30: cmp ax,NI_EXITCALL ;ExitCall
+ jnz DN_40 ;No
+
+ ;** ExitCall:
+ ;* Exit code is on stack somewhere if we don't have the new
+ ;** notification handler. If we do, it's in BL.
+ xor cx,cx ;Clear all but low byte
+ xor dh,dh
+ test wTHFlags,TH_GOODPTRACEHOOK ;Do we have the good hook?
+ jz DN_DoOldHook ;Nope, grope on the stack
+ mov dl,BYTE PTR FrameBX ;Get the exit code
+ mov ax,NFY_EXITTASK ;Get the TOOLHELP ID
+ jmp DN_End
+DN_DoOldHook:
+ mov si,FrameSP ;Point to old stack frame
+ mov dl,ss:[si + 6] ;Exit code is 6 bytes down on stack
+ mov ax,NFY_EXITTASK ;Get the TOOLHELP ID
+ jmp DN_End
+
+ ;** Check for DelModule
+DN_40: cmp ax,NI_DELMODULE ;DelModule?
+ jnz DN_60 ;No
+
+ ;** DelModule:
+ ;** ES is module handle
+ xor cx,cx ;Clear HIWORD
+ mov dx,FrameES ;Get the module handle
+ mov ax,NFY_DELMODULE ;Get the TOOLHELP ID
+ jmp DN_End
+
+ ;** Check for TaskSwitchIn
+DN_60: cmp ax,NI_TASKIN ;TaskSwitchIn?
+ jnz DN_70 ;No
+
+ ;** TaskSwitchIn:
+ ;** No data. Callback should do GetCurrentTask()
+ xor cx,cx ;Clear data
+ xor dx,dx
+ mov ax,NFY_TASKIN ;Get the TOOLHELP ID
+ mov bx,NF_TASKSWITCH ;Get the NOTIFYSTRUCT match flag
+ jmp DN_End
+
+ ;** Check for TaskSwitchOut
+DN_70: cmp ax,NI_TASKOUT ;TaskSwitchOut?
+ jnz DN_90 ;No
+
+ ;** TaskSwitchOut:
+ ;** No data
+ xor cx,cx ;Clear data
+ xor dx,dx
+ mov ax,NFY_TASKOUT ;Get the TOOLHELP ID
+ mov bx,NF_TASKSWITCH ;Get the NOTIFYSTRUCT match flag
+ jmp DN_End
+
+ ;** Check for OutStr
+DN_90: cmp ax,NI_OUTSTR ;OutStr?
+ jnz DN_100 ;No
+
+ ;** OutStr:
+ ;** ES:SI points to string to display in 3.1
+ ;** DS:SI in 3.0
+ test wTHFlags,TH_WIN30 ;3.0?
+ jz DN_OS_Win31 ;Nope
+ mov cx,FrameDS ;Get the segment value
+ jmp SHORT @F
+DN_OS_Win31:
+ mov cx,FrameES ;Get the segment value
+@@: mov dx,FrameSI ; and the offset
+ mov ax,NFY_OUTSTR ;Get the TOOLHELP ID
+ jmp DN_End
+
+ ;** Check for InChar
+DN_100: cmp ax,NI_INCHAR ;InChar?
+ jnz DN_105 ;No
+
+ ;** InChar:
+ ;** No data passed (it wants data back in AL)
+ xor cx,cx ;Clear dwData
+ xor dx,dx
+ mov ax,NFY_INCHAR ;Get the TOOLHELP ID
+ jmp SHORT DN_End
+
+ ;** NOTE: The following notifications are defined as "NEW" and
+ ;** are NOT sent through the normal PTrace interface so as to
+ ;** not break brain-damaged CodeSpew. It stack faults when
+ ;** it is sent a notification it doesn't understand. So,
+ ;** here we don't bother decoding any of these unless we have
+ ;** the new (Win 3.1) style hook
+DN_105: test wTHFlags,TH_GOODPTRACEHOOK ;Do we have the advanced hook?
+ jnz DN_110 ;Yes
+ jmp SHORT DN_End
+
+ ;** Check for the parameter validation notifications
+DN_110: cmp ax,NI_LOGERROR ;SDM_LOGERROR?
+ jne DN_120 ;No
+
+ ;** SDM_LOGERROR:
+ ;* CX is Error code
+ ;** DX:BX is lpInfo
+ mov si,dx ;Point with SI
+ mov ax,SIZE NFYLOGERROR ;Get the size
+ mov WORD PTR [si].nle_dwSize[0],ax ;Save the LOWORD of the size
+ mov WORD PTR [si].nle_dwSize[2],0 ;HIWORD is always zero
+ mov ax,FrameCX ;Get the error code
+ mov [si].nle_wErrCode,ax ;Save in structure
+ mov ax,FrameDX ;Get the lpInfo
+ mov WORD PTR [si].nle_lpInfo[2],ax ;Save in structure
+ mov ax,FrameBX
+ mov WORD PTR [si].nle_lpInfo[0],ax ;Save in structure
+ mov ax,NFY_LOGERROR ;Get the TOOLHELP ID
+ jmp SHORT DN_End
+
+DN_120: cmp ax,NI_LOGPARAMERROR ;SDM_LOGPARAMERROR?
+ jne DN_Unknown ;No
+
+ ;** SDM_LOGPARAMERROR:
+ ;** ES:BX points to a structure:
+ ;** WORD wErr
+ ;** FARPROC lpfn
+ ;** VOID FAR* lpBadParam
+ mov si,dx ;Point with SI
+ mov ax,SIZE NFYLOGPARAMERROR ;Struct size
+ mov WORD PTR [si].nlp_dwSize[0],ax ;Save the LOWORD of the size
+ mov WORD PTR [si].nlp_dwSize[2],0 ;HIWORD is always zero
+ mov es,FrameES ;Point to the structure
+ mov bx,FrameBX
+ mov ax,es:[bx] ;Get wErr
+ mov [si].nlp_wErrCode,ax ;Save in structure
+ mov ax,es:[bx + 2] ;Get lpfn[0]
+ mov WORD PTR [si].nlp_lpfnErrorAddr[0],ax
+ mov ax,es:[bx + 4] ;Get lpfn[2]
+ mov WORD PTR [si].nlp_lpfnErrorAddr[2],ax
+ mov ax,es:[bx + 6] ;Get lpBadParam[0]
+ mov WORD PTR [si].nlp_lpBadParam[0],ax
+ mov ax,es:[bx + 8] ;Get lpBadParam[2]
+ mov WORD PTR [si].nlp_lpBadParam[2],ax
+ mov ax,NFY_LOGPARAMERROR ;Get the TOOLHELP ID
+ xor bx,bx ;Always match
+ jmp SHORT DN_End
+
+ ;** Must be unknown, return TOOLHELP ID NFY_UNKNOWN with KERNEL value
+ ;** in LOWORD(wData)
+DN_Unknown:
+ mov dx,ax ;Get the notification value
+ mov ax,NFY_UNKNOWN ;Unknown KERNEL notification
+ xor cx,cx ;Clear high WORD
+
+DN_End:
+
+cEnd
+
+sEnd
+ END
+
+
diff --git a/private/mvdm/wow16/toolhelp/signal.c b/private/mvdm/wow16/toolhelp/signal.c
new file mode 100644
index 000000000..674100a3a
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/signal.c
@@ -0,0 +1,110 @@
+/**************************************************************************
+ * SIGNAL.C
+ *
+ * Routines used to clean up on a forced KERNEL termination of a
+ * TOOLHELP using app.
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include "toolpriv.h"
+
+/* ----- Global variables ----- */
+ WORD wSignalInstalled;
+ SIGNAL NEAR *npSignalHead;
+
+/* SignalRegister
+ * Registers a default signal proc to a task. This signal proc is
+ * called when the task is about to be terminated and is called before
+ * the USER signal proc is called. The registered callback is
+ * called HelperSignalProc() [HELPER.ASM] and chains to the USER signal
+ * proc (if any) instead of returning.
+ */
+
+BOOL PASCAL SignalRegister(
+ HANDLE hTask)
+{
+ SIGNAL *pSig;
+ SIGNAL *pTemp;
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* Check to see if this task is already registered */
+ for (pSig = npSignalHead ; pSig ; pSig = pSig->pNext)
+ if (pSig->hTask == hTask)
+ return FALSE;
+
+ /* Allocate a new SIGNAL structure */
+ pSig = (SIGNAL *)LocalAlloc(LMEM_FIXED, sizeof (SIGNAL));
+ if (!pSig)
+ return FALSE;
+
+ /* Fill in the useful fields */
+ pSig->hTask = hTask;
+ pSig->lpfn = (LPFNCALLBACK)HelperSignalProc;
+ pSig->lpfnOld = (LPFNCALLBACK)
+ HelperSetSignalProc(hTask, (DWORD)HelperSignalProc);
+
+ /* If this is the only handler, just insert it */
+ if (!npSignalHead)
+ {
+ pSig->pNext = npSignalHead;
+ npSignalHead = pSig;
+ }
+
+ /* Otherwise, insert at the end of the list */
+ else
+ {
+ for (pTemp = npSignalHead ; pTemp->pNext ; pTemp = pTemp->pNext)
+ ;
+ pSig->pNext = pTemp->pNext;
+ pTemp->pNext = pSig;
+ }
+
+ return TRUE;
+}
+
+
+/* SignalUnRegister
+ * Called by an app whose callback is no longer to be used.
+ * NULL hTask uses current task.
+ */
+
+BOOL PASCAL SignalUnRegister(
+ HANDLE hTask)
+{
+ SIGNAL *pSig;
+ SIGNAL *pBefore;
+
+ /* NULL hTask means current task */
+ if (!hTask)
+ hTask = GetCurrentTask();
+
+ /* First try to find the task */
+ pBefore = NULL;
+ for (pSig = npSignalHead ; pSig ; pSig = pSig->pNext)
+ if (pSig->hTask == hTask)
+ break;
+ else
+ pBefore = pSig;
+ if (!pSig)
+ return FALSE;
+
+ /* Remove it from the list */
+ if (!pBefore)
+ npSignalHead = pSig->pNext;
+ else
+ pBefore->pNext = pSig->pNext;
+
+ /* Replace the old signal proc */
+ HelperSetSignalProc(hTask, (DWORD)pSig->lpfnOld);
+
+ /* Free the structure */
+ LocalFree((HANDLE)pSig);
+
+ return TRUE;
+}
+
+
diff --git a/private/mvdm/wow16/toolhelp/stack1.c b/private/mvdm/wow16/toolhelp/stack1.c
new file mode 100644
index 000000000..b7ed4a15d
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/stack1.c
@@ -0,0 +1,155 @@
+/***************************************************************************
+ * STACK1.C
+ *
+ * Code to support stack tracing on task stacks.
+ *
+ ***************************************************************************/
+
+#include "toolpriv.h"
+#include <newexe.h>
+#include <string.h>
+
+/* ----- Function prototypes ----- */
+
+ NOEXPORT void StackTraceInfo(
+ STACKTRACEENTRY FAR *lpStack);
+
+/* ----- Functions ----- */
+
+/* StackTraceFirst
+ * Starts a task stack trace by returning information about the
+ * first frame on the task's stack.
+ */
+
+BOOL TOOLHELPAPI StackTraceFirst(
+ STACKTRACEENTRY FAR *lpStackTrace,
+ HANDLE hTDB)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpStackTrace ||
+ lpStackTrace->dwSize != sizeof (STACKTRACEENTRY))
+ return FALSE;
+
+ /* Get the first value */
+ if (!(StackFrameFirst(lpStackTrace, hTDB)))
+ return FALSE;
+
+ /* Get module and segment number information */
+ StackTraceInfo(lpStackTrace);
+
+ return TRUE;
+}
+
+
+/* StackTraceCSIPFirst
+ * Traces the stack of an arbitrary CS:IP. All parameters must be
+ * given, and once started, the StackTraceNext function can be used
+ * to trace the remainder of the stack
+ */
+
+BOOL TOOLHELPAPI StackTraceCSIPFirst(
+ STACKTRACEENTRY FAR *lpStack,
+ WORD wSS,
+ WORD wCS,
+ WORD wIP,
+ WORD wBP)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpStack ||
+ lpStack->dwSize != sizeof (STACKTRACEENTRY))
+ return FALSE;
+
+ /* Get the user information */
+ lpStack->wSS = wSS;
+ lpStack->wCS = wCS;
+ lpStack->wIP = wIP;
+ lpStack->wBP = wBP;
+
+ /* Get module and segment number information */
+ StackTraceInfo(lpStack);
+
+ /* Set the hTask to the current task as we are in the current task
+ * context. The CS may not be owned by this task, but at least
+ * we put a reasonable value in there.
+ */
+ lpStack->hTask = GetCurrentTask();
+
+ return TRUE;
+}
+
+
+/* StackTraceNext
+ * Continues a stack trace by returning information about the next
+ * frame on the task's stack.
+ * structure.
+ */
+
+BOOL TOOLHELPAPI StackTraceNext(
+ STACKTRACEENTRY FAR *lpStackTrace)
+{
+ /* Check the version number and verify proper installation */
+ if (!wLibInstalled || !lpStackTrace ||
+ lpStackTrace->dwSize != sizeof (STACKTRACEENTRY))
+ return FALSE;
+
+ /* Get information about this frame */
+ if (!StackFrameNext(lpStackTrace))
+ return FALSE;
+
+ /* Get module and segment number information */
+ StackTraceInfo(lpStackTrace);
+
+ return TRUE;
+}
+
+/* ----- Helper functions ----- */
+
+/* StackTraceInfo
+ * Gets module and segment number info about the given entry
+ */
+
+NOEXPORT void StackTraceInfo(
+ STACKTRACEENTRY FAR *lpStack)
+{
+ GLOBALENTRY GlobalEntry;
+ struct new_exe FAR *lpNewExe;
+ struct new_seg1 FAR *lpSeg;
+ WORD i;
+
+ /* If we have a NULL CS, this is a NEAR frame. Just return because we
+ * assume the user hasn't trashed the structure. The module and seg
+ * info will be the same as the last time
+ */
+ if (!lpStack->wCS)
+ return;
+
+ /* Get information about the code segment block */
+ GlobalEntry.dwSize = sizeof (GLOBALENTRY);
+ if (!GlobalEntryHandle(&GlobalEntry, lpStack->wCS))
+ return;
+
+ /* The owner of all code segments is the hModule */
+ lpStack->hModule = GlobalEntry.hOwner;
+
+ /* To find the segment number, we look in the EXE header and count the
+ * listed segments till we find this one
+ */
+
+ /* Get a pointer to the EXE Header module */
+ lpNewExe = MAKEFARPTR(HelperHandleToSel(lpStack->hModule), 0);
+
+ /* Make sure this is a EXE Header segment */
+ if (lpNewExe->ne_magic != NEMAGIC)
+ return;
+
+ /* Get the list of segments and go for it */
+ lpSeg = MAKEFARPTR(HIWORD((DWORD)lpNewExe), lpNewExe->ne_segtab);
+ for (i = 0 ; i < lpNewExe->ne_cseg ; ++i, ++lpSeg)
+ if (HelperHandleToSel(lpSeg->ns_handle) == lpStack->wCS)
+ break;
+ if (i == lpNewExe->ne_cseg)
+ return;
+
+ /* Save the segment number (seg numbers start at one) */
+ lpStack->wSegment = i + 1;
+}
diff --git a/private/mvdm/wow16/toolhelp/stack2.asm b/private/mvdm/wow16/toolhelp/stack2.asm
new file mode 100644
index 000000000..61bdc4308
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/stack2.asm
@@ -0,0 +1,178 @@
+;**************************************************************************
+;* STACK2.ASM
+;*
+;* Assembly support code for stack tracing.
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE TDB.INC
+
+;** External functions
+
+externNP HelperVerifySeg
+externNP HelperHandleToSel
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+
+; StackFrameFirst
+; Returns information about the first stack frame and checks it
+; for validity as much as possible. The first stack frame is found
+; by getting the information from the TDB. If this task is active,
+; or if the task was changed in an unusual way, this information
+; may be incorrect. If it is, the user must set up the first
+; CS, IP, and BP, and BPNext in the user structure, log it as the
+; first stack trace and call StackTraceNext directly.
+
+cProc StackFrameFirst, <NEAR,PUBLIC>, <si,di,ds>
+ parmD lpStack
+ parmW hTDB
+cBegin
+ ;** Verify that we have a good TDB first
+ ;** Start by verifying the selector
+ mov ax,hTDB ;Get the selector
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ push ax ;Save it
+ mov bx,TDBSize
+ cCall HelperVerifySeg, <ax,bx>
+ pop bx ;Get selector back
+ or ax,ax ;FALSE return?
+ jnz SHORT SF_SelOk ;Selector's OK
+ xor ax,ax ;Return FALSE
+ jmp SHORT SF_End
+SF_SelOk:
+
+ ;** Verify that the TDB signature matches
+ mov ds,bx ;Point with DS
+ cmp ds:[TDB_sig],TDB_SIGNATURE ;Is this really a TDB?
+ jz SF_SigOk ;Must be
+ xor ax,ax ;Return FALSE
+ jmp SHORT SF_End
+SF_SigOk:
+
+ ;** Get the BP value from the task stack and store in structure
+ les di,lpStack ;Get a pointer to the user struct
+ mov ax,ds:[TDB_taskSS] ;Get the SS value
+ mov bx,ds:[TDB_taskSP] ;Get the max segment offset we need
+ add bx,Task_CS + 2
+ cCall HelperVerifySeg, <ax,bx> ;Make sure we can read all this
+ or ax,ax ;Error?
+ jz SF_End ;Yes, can't do walk
+ lds bx,DWORD PTR ds:[TDB_taskSP] ;Get the SS:SP value
+ mov si,ds:[bx].Task_BP ;Get the BP value from the stack
+ and si,NOT 1 ;Clear the FAR frame bit, if any
+ mov es:[di].st_wBP,si ;Store the BP value
+ mov ax,ds:[bx].Task_IP ;Store initial IP
+ mov es:[di].st_wIP,ax
+ mov ax,ds:[bx].Task_CS ;Store the initial CS
+ mov es:[di].st_wCS,ax
+
+ ;** Return as much info as possible about this first frame
+ mov ax,hTDB ;Get the TDB handle
+ mov es:[di].st_hTask,ax ;Save in structure
+ mov es:[di].st_wSS,ds ;Save the SS value
+ mov es:[di].st_wFlags,FRAME_FAR ;Force a FAR frame this time
+
+ ;** Try to verify this stuff
+ xor ax,ax ;In case we need to exit
+ or si,si ;End of the line?
+ jz SF_End ;Nope
+ cmp si,ds:[0ah] ;Compare against stack top
+ jb SF_End ;Fine with top
+ cmp si,ds:[0eh] ;Check against stack bottom
+ jae SF_End ;OK with bottom too
+ mov ax,1 ;Return TRUE
+
+SF_End:
+cEnd
+
+
+; StackFrameNext
+; Returns information in a public structure about the stack frame
+; pointed to by the BP value passed in. Returns TRUE if the
+; information seems valid, or FALSE if information could not be
+; returned.
+
+cProc StackFrameNext, <NEAR,PUBLIC>, <si,di,ds>
+ parmD lpStack
+cBegin
+ ;** Get pointers to the frame
+ les di,lpStack ;Get a pointer to the structure
+ mov ax,es:[di].st_wSS ;Get the stack segment
+ mov ds,ax ;Point with DS
+
+ ;** Get the next stack frame
+ mov si,es:[di].st_wBP ;Get the current BP value
+ lea ax,[si + 6] ;Get the max stack probe
+ cmp ax,si ;No stack wraparound allowed
+ jb SN_End ;If below, we have wrapped
+ cCall HelperVerifySeg, <ds,ax> ;Make sure the stack is OK
+ or ax,ax ;OK?
+ jnz @F ;Yes.
+ jmp SHORT SN_End ;Return FALSE
+@@: mov dx,ds:[si+4] ;DX:CX is the return address
+ mov cx,ds:[si+2]
+ mov bx,ds:[si] ;Get next BP value
+
+ ;** Zero BP is end of chain
+ xor ax,ax ;In case we need to exit
+ or bx,bx ;End of the line?
+ jz SN_End ;Nope
+
+ ;** If the new BP is higher on the stack than the old, it's invalid
+ cmp bx,si ;New BP <= Old BP?
+ jbe SN_End ;OK.
+
+ ;** Make sure we're still on the stack (variables from KDATA.ASM)
+ cmp bx,ds:[0ah] ;Compare against stack top
+ jb SN_End ;Fine with top
+ cmp bx,ds:[0eh] ;Check against stack bottom
+ jae SN_End ;OK with bottom too
+
+ ;** Return what we can about the frame
+ mov es:[di].st_wSS,ds ;Save the SS value
+ mov es:[di].st_wBP,si ; and the BP value
+ test bx,1 ;Far or near frame?
+ jnz SN_FarFrame ;For sure far if BP is odd
+
+ ;** Even when BP is not odd, we may have a far frame
+ mov ax,cs ;Get our RPL bits
+ and al,3 ;Mask RPL bits
+ mov ah,dl ;Get frame's RPL bits
+ and ah,3 ;Mask RPL bits
+ cmp al,ah ;If CS is a handle, they won't match
+ jne SN_NearFrame ;Bits don't match
+ lar ax,dx ;Get the access bits
+ test ax,800h ;Is this a code segment?
+ jz SN_NearFrame ;No. MUST be near frame
+ lsl ax,dx ;Get the limit
+ cmp ax,cx ;Inside limit?
+ jbe SN_NearFrame ;No. MUST be near
+
+ ;** Otherwise, probably is a far frame. It may not be, of course,
+ ;** because this may be a code seg parameter
+SN_FarFrame:
+ mov es:[di].st_wIP,cx ;Save the offset
+ mov es:[di].st_wCS,dx ; and selector value
+ mov ax,FRAME_FAR ;Tell the user what we did
+ and bx,NOT 1 ;Clear the far frame bit
+ jmp SHORT SN_20 ;Skip near section
+
+ ;** Must be a near frame
+SN_NearFrame:
+ mov es:[di].st_wIP,cx ;Save the offset
+ ;Leave the old CS value in
+ mov ax,FRAME_NEAR ;Tell the user what we did
+SN_20: mov es:[di].st_wFlags,ax ;Save in the structure
+ mov es:[di].st_wBP,bx ;Save BP in the structure
+ mov ax,1 ;Return TRUE
+
+SN_End:
+cEnd
+
+sEnd
+
+ END
diff --git a/private/mvdm/wow16/toolhelp/string.h b/private/mvdm/wow16/toolhelp/string.h
new file mode 100644
index 000000000..2c39b8d91
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/string.h
@@ -0,0 +1,121 @@
+/***
+*string.h - declarations for string manipulation functions
+*
+* Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file contains the function declarations for the string
+* manipulation functions.
+* [ANSI/System V]
+*
+****/
+
+#if defined(_DLL) && !defined(_MT)
+#error Cannot define _DLL without _MT
+#endif
+
+#ifdef _MT
+#define _FAR_ _far
+#else
+#define _FAR_
+#endif
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+/* function prototypes */
+
+void _FAR_ * _FAR_ _cdecl memccpy(void _FAR_ *, const void _FAR_ *,
+ int, unsigned int);
+void _FAR_ * _FAR_ _cdecl memchr(const void _FAR_ *, int, size_t);
+int _FAR_ _cdecl memcmp(const void _FAR_ *, const void _FAR_ *,
+ size_t);
+int _FAR_ _cdecl memicmp(const void _FAR_ *, const void _FAR_ *,
+ unsigned int);
+void _FAR_ * _FAR_ _cdecl memcpy(void _FAR_ *, const void _FAR_ *,
+ size_t);
+void _FAR_ * _FAR_ _cdecl memmove(void _FAR_ *, const void _FAR_ *,
+ size_t);
+void _FAR_ * _FAR_ _cdecl memset(void _FAR_ *, int, size_t);
+void _FAR_ _cdecl movedata(unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int);
+char _FAR_ * _FAR_ _cdecl strcat(char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strchr(const char _FAR_ *, int);
+int _FAR_ _cdecl strcmp(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl strcmpi(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl strcoll(const char _FAR_ *, const char _FAR_ *);
+int _FAR_ _cdecl stricmp(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strcpy(char _FAR_ *, const char _FAR_ *);
+size_t _FAR_ _cdecl strcspn(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strdup(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl _strerror(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strerror(int);
+size_t _FAR_ _cdecl strlen(const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strlwr(char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strncat(char _FAR_ *, const char _FAR_ *,
+ size_t);
+int _FAR_ _cdecl strncmp(const char _FAR_ *, const char _FAR_ *,
+ size_t);
+int _FAR_ _cdecl strnicmp(const char _FAR_ *, const char _FAR_ *,
+ size_t);
+char _FAR_ * _FAR_ _cdecl strncpy(char _FAR_ *, const char _FAR_ *,
+ size_t);
+char _FAR_ * _FAR_ _cdecl strnset(char _FAR_ *, int, size_t);
+char _FAR_ * _FAR_ _cdecl strpbrk(const char _FAR_ *,
+ const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strrchr(const char _FAR_ *, int);
+char _FAR_ * _FAR_ _cdecl strrev(char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strset(char _FAR_ *, int);
+size_t _FAR_ _cdecl strspn(const char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strstr(const char _FAR_ *,
+ const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strtok(char _FAR_ *, const char _FAR_ *);
+char _FAR_ * _FAR_ _cdecl strupr(char _FAR_ *);
+size_t _FAR_ _cdecl strxfrm (char _FAR_ *, const char _FAR_ *,
+ size_t);
+
+/* model independent function prototypes */
+
+void _far * _far _cdecl _fmemccpy(void _far *, const void _far *,
+ int, unsigned int);
+void _far * _far _cdecl _fmemchr(const void _far *, int, size_t);
+int _far _cdecl _fmemcmp(const void _far *, const void _far *,
+ size_t);
+void _far * _far _cdecl _fmemcpy(void _far *, const void _far *,
+ size_t);
+int _far _cdecl _fmemicmp(const void _far *, const void _far *,
+ unsigned int);
+void _far * _far _cdecl _fmemmove(void _far *, const void _far *,
+ size_t);
+void _far * _far _cdecl _fmemset(void _far *, int, size_t);
+char _far * _far _cdecl _fstrcat(char _far *, const char _far *);
+char _far * _far _cdecl _fstrchr(const char _far *, int);
+int _far _cdecl _fstrcmp(const char _far *, const char _far *);
+int _far _cdecl _fstricmp(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrcpy(char _far *, const char _far *);
+size_t _far _cdecl _fstrcspn(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrdup(const char _far *);
+char _near * _far _cdecl _nstrdup(const char _far *);
+size_t _far _cdecl _fstrlen(const char _far *);
+char _far * _far _cdecl _fstrlwr(char _far *);
+char _far * _far _cdecl _fstrncat(char _far *, const char _far *,
+ size_t);
+int _far _cdecl _fstrncmp(const char _far *, const char _far *,
+ size_t);
+int _far _cdecl _fstrnicmp(const char _far *, const char _far *,
+ size_t);
+char _far * _far _cdecl _fstrncpy(char _far *, const char _far *,
+ size_t);
+char _far * _far _cdecl _fstrnset(char _far *, int, size_t);
+char _far * _far _cdecl _fstrpbrk(const char _far *,
+ const char _far *);
+char _far * _far _cdecl _fstrrchr(const char _far *, int);
+char _far * _far _cdecl _fstrrev(char _far *);
+char _far * _far _cdecl _fstrset(char _far *, int);
+size_t _far _cdecl _fstrspn(const char _far *, const char _far *);
+char _far * _far _cdecl _fstrstr(const char _far *,
+ const char _far *);
+char _far * _far _cdecl _fstrtok(char _far *, const char _far *);
+char _far * _far _cdecl _fstrupr(char _far *);
diff --git a/private/mvdm/wow16/toolhelp/task1.c b/private/mvdm/wow16/toolhelp/task1.c
new file mode 100644
index 000000000..01286b0af
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/task1.c
@@ -0,0 +1,73 @@
+/*************************************************************************
+ * TASK1.C
+ *
+ * Routines used to enumerate all tasks.
+ *
+ *************************************************************************/
+
+#include <string.h>
+#include "toolpriv.h"
+
+/* ----- Functions ----- */
+
+/* TaskFirst
+ * Returns information about the first task in the task chain.
+ */
+
+BOOL TOOLHELPAPI TaskFirst(
+ TASKENTRY FAR *lpTask)
+{
+ /* Check for errors */
+ if (!wLibInstalled || !lpTask || lpTask->dwSize != sizeof (TASKENTRY))
+ return FALSE;
+
+ /* Pass a pointer to the first block to the assembly routine */
+ return TaskInfo(lpTask, *(WORD FAR *)MAKEFARPTR(segKernel, npwTDBHead));
+}
+
+
+/* TaskNext
+ * Returns information about the next task in the task chain.
+ */
+
+BOOL TOOLHELPAPI TaskNext(
+ TASKENTRY FAR *lpTask)
+{
+ /* Check for errors */
+ if (!wLibInstalled || !lpTask || !lpTask->hNext ||
+ lpTask->dwSize != sizeof (TASKENTRY))
+ return FALSE;
+
+ /* Pass a pointer to the next block to the assembly routine */
+ return TaskInfo(lpTask, lpTask->hNext);
+}
+
+
+/* TaskFindHandle
+ * Returns information about the task with the given task handle.
+ */
+
+BOOL TOOLHELPAPI TaskFindHandle(
+ TASKENTRY FAR *lpTask,
+ HANDLE hTask)
+{
+ /* Check for errors */
+ if (!wLibInstalled || !lpTask || lpTask->dwSize != sizeof (TASKENTRY))
+ return FALSE;
+
+#ifdef WOW
+ if ( (hTask & 0x4) == 0 && hTask <= 0xffe0 && hTask != 0 ) {
+ //
+ // If they are getting a task handle for an htask alias, then
+ // just fill in the hinst method and return.
+ //
+ // Special hack for OLE 2.0's BusyDialog.
+ //
+ lpTask->hInst = hTask;
+ return( TRUE );
+ }
+#endif
+
+ /* Pass a pointer to the first block to the assembly routine */
+ return TaskInfo(lpTask, hTask);
+}
diff --git a/private/mvdm/wow16/toolhelp/task2.asm b/private/mvdm/wow16/toolhelp/task2.asm
new file mode 100644
index 000000000..f01829234
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/task2.asm
@@ -0,0 +1,326 @@
+;**************************************************************************
+;* TASK2.ASM
+;*
+;* Assembly support for the task enumeration routines.
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+PMODE32 = 0
+PMODE = 0
+SWAPPRO = 0
+ INCLUDE TDB.INC
+ifdef WOW
+ INCLUDE WOW.INC
+endif
+
+;** Data
+
+sBegin DATA
+
+lpfnRetAddr DD 0 ;Return address after stack switch
+
+sEnd
+
+;** External functions
+externNP HelperHandleToSel
+externNP HelperVerifySeg
+externFP GetCurrentTask
+externFP DirectedYield
+ifdef WOW
+externFP PostAppMessage
+endif
+
+;** Functions
+
+.286p
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+
+; TaskSetCSIP
+; Allows the user to set the CS:IP of a sleeping task so that it will
+; begin execution at this address when the task is yielded to.
+; Returns the old address.
+
+cProc TaskSetCSIP, <PUBLIC,FAR>, <si>
+ parmW hTask
+ parmW wCS
+ parmW wIP
+cBegin
+ assumes DS,nothing
+ assumes ES,nothing
+
+ ;** If this is the current task, do nothing: we only work on
+ ;** sleeping tasks
+ cCall GetCurrentTask ;Gets current task in AX
+ mov bx,hTask ;Get desired task
+ cmp ax,bx ;Same?
+ jne @F ;No, it's OK
+ xor ax,ax ;Return a DWORD zero
+ cwd
+ jmp SHORT TC_End
+@@:
+
+ ;** Get the TDB SS:SP
+ mov es,bx ;Point to TDB with ES
+ les si,DWORD PTR es:[TDB_TaskSP] ;Get a pointer to the task stack
+ifdef WOW
+ ;
+ ; ES:SI now points to the place where we had the TDB's SS:SP pointing
+ ; This spot in wow is actually the SS:BP frame of the WOW16CALL
+ ; function. The definitions for this frame come from WOW.INC (WOW.H).
+ ; The addition of this strange value adjusts the SS:SP pointer back
+ ; onto the stack, undoing a previous adjustment in TASKING.ASM
+ add si,(vf_vpCSIP-vf_wThunkCSIP)
+endif
+ ;** Change the CS:IP
+ mov ax,wIP ;Get the new IP value
+ xchg ax,es:[si].Task_IP ;Swap with the old one
+ mov dx,wCS ;Get the new CS value
+ xchg dx,es:[si].Task_CS ;Swap with the old one
+
+TC_End:
+cEnd
+
+
+; TaskGetCSIP
+; Gets the next CS:IP that this task will run at.
+
+cProc TaskGetCSIP, <PUBLIC,FAR>, <si>
+ parmW hTask
+cBegin
+ assumes DS,nothing
+ assumes ES,nothing
+
+ ;** If this is the current task, do nothing: we only work on
+ ;** sleeping tasks
+ cCall GetCurrentTask ;Gets current task in AX
+ mov bx,hTask ;Get desired task
+ cmp ax,bx ;Same?
+ jne @F ;No, it's OK
+ xor ax,ax ;Return a DWORD zero
+ cwd
+ jmp SHORT TG_End
+@@:
+
+ ;** Get the TDB SS:SP
+ mov es,bx ;Point to TDB with ES
+ les si,DWORD PTR es:[TDB_TaskSP] ;Get a pointer to the task stack
+
+ifdef WOW
+ ;
+ ; ES:SI now points to the place where we had the TDB's SS:SP pointing
+ ; This spot in wow is actually the SS:BP frame of the WOW16CALL
+ ; function. The definitions for this frame come from WOW.INC (WOW.H).
+ ; The addition of this strange value adjusts the SS:SP pointer back
+ ; onto the stack, undoing a previous adjustment in TASKING.ASM
+ add si,(vf_vpCSIP-vf_wThunkCSIP)
+endif
+ ;** Change the CS:IP
+ mov ax,es:[si].Task_IP ;Get the CS:IP to return
+ mov dx,es:[si].Task_CS
+
+TG_End:
+cEnd
+
+
+; TaskSwitch
+; Switches to the indicated task from the current one.
+; Returns FALSE if it couldn't task switch.
+; Jumps to the address given by lpJmpAddr
+
+cProc TaskSwitch, <PUBLIC,FAR>, <si,di>
+ parmW hTask
+ parmD lpJmpAddr
+cBegin
+ push ds
+ mov ax, _DATA ;Make sure to set DS
+ mov ds, ax
+ assumes ds,DATA
+
+ ;** Check to make sure TOOLHELP is installed
+ cmp wLibInstalled,0 ;Library installed?
+ pop ds
+ assumes ds,nothing
+ jnz @F ;Yes
+ xor ax,ax ;Return FALSE
+ jmp TS_End ;No. Fail the API
+@@:
+
+ ;** Get the task handle
+ cCall GetCurrentTask ;Get the current task
+ cmp ax,hTask ;Switch to current task?
+ jne @F ;No, it's OK
+ xor ax,ax ;Yes, we can't do that so return FALSE
+
+ifdef WOW
+ jmp TS_End
+else
+ jmp SHORT TS_End
+endif
+
+@@: cCall HelperVerifySeg, <hTask,TDB_sig+1> ;Verify the segment
+ or ax,ax ;Segment OK?
+ jz TS_End ;Nope. Get out
+ mov es,hTask ;Get the TDB
+ xor ax,ax ;Get a zero just in case
+ cmp es:[TDB_sig], TDB_SIGNATURE ;Signature match?
+ jne TS_End ;Return FALSE
+
+ ;** Poke in the address to jump to
+ mov si,es ;Save the hTask
+ lea ax,TS_FromYield ;Point to new task address
+ cCall TaskSetCSIP, <si,cs,ax> ;Set the new address
+ mov es,si ;Get hTask back
+
+ ;** Save the jump address from the stack so we can jump to it later
+ push ds
+ mov ax,_DATA ;Point to our data segment
+ mov ds,ax
+ assumes ds,DATA
+ mov ax,WORD PTR lpJmpAddr[0];Get the low word of the ret address
+ mov WORD PTR lpfnRetAddr[0],ax
+ mov ax,WORD PTR lpJmpAddr[2];Get the selector value
+ mov WORD PTR lpfnRetAddr[2],ax
+ pop ds
+
+ifdef WOW
+ ;** Force a task switch by posting a message. This is because the
+ ;** event count is not used under WOW.
+ cCall PostAppMessage,<es, 0, 0, 0, 0>
+else
+ ;** Force a task switch by tampering with the event count
+ inc es:[TDB_nEvents] ;Force at least one event so we
+ ; will switch to this task next
+endif ;WOW
+
+ ;** Switch to the new task. DirectedYield() returns only when this
+ ;** task is next scheduled
+ cCall DirectedYield, <si> ;Switch to the new task
+ mov ax,1 ;Return TRUE
+ jmp SHORT TS_End ;Get out
+
+ ;** Restore from the directed yield
+TS_FromYield:
+
+ ;** Make a stack frame to work on. We can't trash any regs
+ PUBLIC TS_FromYield
+ sub sp,4 ;Save room for a far ret frame
+ push bp ;Make a stack frame
+ mov bp,sp
+ pusha ;Save everything
+ push ds
+ push es
+
+ ;** Get our jump address from our DS and put in far ret frame
+ mov ax,_DATA ;Get the TOOLHELP DS
+ mov ds,ax
+ mov ax,WORD PTR lpfnRetAddr[0] ;Get the offset
+ mov [bp + 2],ax ;Put it on the stack
+ mov ax,WORD PTR lpfnRetAddr[2] ;Get the selector
+ mov [bp + 4],ax ;Put on the stack
+
+ ;** Restore the event count
+ mov es,segKernel ;Get the KERNEL segment
+ mov bx,npwTDBCur ;Get the current task pointer
+ mov es,es:[bx] ;Get the TDB pointer in ES
+ifndef WOW
+ dec es:[TDB_nEvents] ;Clear the dummy event we put in
+endif
+
+ ;** Clear the stack and 'return' to the new address
+ pop es
+ pop ds
+ popa
+ pop bp
+ retf
+
+TS_End:
+cEnd
+
+
+; TaskInfo
+;
+; Returns information about the task with the given block handle
+
+cProc TaskInfo, <PUBLIC,NEAR>, <si,di,ds>
+ parmD lpTask
+ parmW wTask
+cBegin
+ ;** Start by verifying the selector
+ mov ax,wTask ;Get the selector
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ push ax ;Save it
+ mov bx,TDBSize
+ cCall HelperVerifySeg, <ax,bx>
+ pop bx ;Get selector back
+ or ax,ax ;FALSE return?
+ jnz TI_SelOk ;Selector's OK
+ xor ax,ax ;Return FALSE
+ jmp TI_End
+TI_SelOk:
+
+ ;** Verify that the TDB signature matches
+ mov ds,bx ;Point with DS
+ cmp ds:[TDB_sig],TDB_SIGNATURE ;Is this really a TDB?
+ jz TI_SigOk ;Must be
+ xor ax,ax ;Return FALSE
+ jmp SHORT TI_End
+TI_SigOk:
+
+ ;** Now, get information from the TDB
+ les di,lpTask ;Point to destination buffer
+ mov ax,ds:[TDB_next] ;Get the next TDB handle
+ mov es:[di].te_hNext,ax ;Save in public structure
+ mov ax,wTask ;Get this task's handle
+ mov es:[di].te_hTask,ax ;Save in buffer
+ mov ax,ds:[TDB_Parent] ;Get this task's parent
+ mov es:[di].te_hTaskParent,ax ;Save
+ mov ax,ds:[TDB_taskSS] ;Get the SS
+ mov es:[di].te_wSS,ax
+ mov ax,ds:[TDB_taskSP] ;Get the SP
+ mov es:[di].te_wSP,ax
+ mov ax,ds:[TDB_nEvents] ;Event counter
+ mov es:[di].te_wcEvents,ax
+ mov ax,ds:[TDB_Queue] ;Queue pointer
+ mov es:[di].te_hQueue,ax
+ mov ax,ds:[TDB_PDB] ;Offset of DOS PSP
+ mov es:[di].te_wPSPOffset,ax
+ mov ax,ds:[TDB_Module] ;Instance handle (DS) of task
+ mov es:[di].te_hInst,ax
+ mov ax,ds:[TDB_pModule] ;Module database handle
+ mov es:[di].te_hModule,ax
+ mov cx,8 ;Copy module name
+ push di ;Save structure pointer
+ mov si,TDB_ModName ;Point to the string
+ add di,te_szModule ; and to the string dest
+ cld
+ repnz movsb ;Copy the string
+ mov BYTE PTR es:[di],0 ;Zero terminate it
+ pop di ;Get structure pointer back
+
+ ;** Get information from the stack segment. Vars from KDATA.ASM
+ mov ax,es:[di].te_wSS ;Get the SS value
+ verr ax ;OK to read here?
+ jnz TI_SkipThis ;No, so don't do it
+ mov ds,ax ;Point with DS
+ mov ax,ds:[0ah] ;Lowest value of SP allowed
+ mov es:[di].te_wStackTop,ax ;Save in structure
+ mov ax,ds:[0ch] ;Get stack minimum value so far
+ mov es:[di].te_wStackMinimum,ax ;Save in structure
+ mov ax,ds:[0eh] ;Largest value of SP allowed
+ mov es:[di].te_wStackBottom,ax ;Save in structure
+
+ ;** Return TRUE on success
+TI_SkipThis:
+ mov ax,1 ;Return TRUE code
+TI_End:
+cEnd
+
+sEnd
+
+ END
diff --git a/private/mvdm/wow16/toolhelp/terminat.asm b/private/mvdm/wow16/toolhelp/terminat.asm
new file mode 100644
index 000000000..c04a324c9
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/terminat.asm
@@ -0,0 +1,145 @@
+ PAGE 60,150
+;***************************************************************************
+;* TERMINAT.ASM
+;*
+;* Assembly code routine used for the TOOLHELP.DLL app terminate
+;* routine.
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE TDB.INC
+
+;** Symbols
+I_EXCEPTION EQU 0
+I_INTERRUPT EQU 1
+MAX_INTERRUPT EQU 5
+GIVE_WDEB386 EQU 8000h
+Q_HACK_30 EQU 54h
+
+.286p
+
+;** Data
+
+sBegin DATA
+
+wTermFlags DW ? ;Save terminate flags across Yield
+
+sEnd
+
+;** Imported values
+externFP InterruptUnRegister
+externFP NotifyUnRegister
+externFP GetCurrentTask
+externFP FatalAppExit
+externFP TaskSetCSIP
+externFP DirectedYield
+externFP TaskSwitch
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+; TerminateApp
+; Terminates the task in one of two ways: TERMINATE_NORMAL or
+; TERMINATE_USER_DISPLAY. TERMINATE_NORMAL calls KERNEL to display
+; the UAE box and terminates the app. TERMINATE_USER_DISPLAY also
+; terminates the app but assumes the user has displayed some warning.
+; If the task passed in is not the current task, this function does
+; the DirectedYield() to switch to the correct task before terminating
+; it.
+; This function does not return when terminating the current task
+; except when WDEB386 is installed and the (undocumented) GIVE_WDEB386
+; flag is set.
+; Caller: TerminateApp(
+; HANDLE hTask, (If NULL, does current task)
+; WORD wFlags)
+
+cProc TerminateApp, <FAR,PUBLIC>, <si,di,ds>
+ parmW hTask
+ parmW wFlags
+cBegin
+ mov ax, _DATA ;Get our DS
+ mov ds, ax
+
+ ;** Save the flags in the DS so we can get after DYield
+ mov ax,wFlags ;Get the parameter flags
+ mov wTermFlags,ax ;Save them
+
+ ;** Get the task value
+ cCall GetCurrentTask ;Get the task
+ mov si,hTask ;Get the hTask value
+ or si,si ;Zero?
+ jnz TA_10 ;No
+ mov es,ax ;Point ES at current task
+ jmp SHORT TA_NukeCurrent ;In this case we always nuke current
+TA_10:
+ ;** If this is the current task, just nuke it and don't return
+ cmp ax,si ;Current?
+ mov es,si ;Point ES at task
+ je TA_NukeCurrent ;Yes, nuke it directly
+
+ ;** Switch to the new task and prepare to nuke it
+ lea ax,TA_NewTask ;Get address of new task entry
+ cCall TaskSwitch, <si,cs,ax> ;Switch to this task
+ jmp SHORT TA_End ;Get out
+
+ ;** We're in the new task now
+TA_NewTask:
+ mov ax,_DATA ;Get the TOOLHELP DS
+ mov ds,ax
+ mov es,segKernel ;Get the KERNEL segment
+ mov bx,npwTDBCur ;Get the current task pointer
+ mov es,es:[bx] ;Get the TDB pointer in ES
+
+ ;** HACK ALERT!!!! In order to get USER to allow us to terminate
+ ;* this app, we are manually nuking the semaphore. This is
+ ;* at a fixed offsets in the Q structure and only needs to
+ ;** be done in 3.0
+ test wTHFlags,TH_WIN30 ;In 3.0?
+ jz TA_NukeCurrent ;No, don't do this ugly hack
+ push es ;Save ES while we play with the queue
+ mov es,es:[TDB_Queue] ;ES points to queue now
+ mov bx,Q_HACK_30 ;Get 3.0 offset
+ mov WORD PTR es:[bx],0 ;Clear the semaphore count
+ mov WORD PTR es:[bx + 2],0 ; and the semaphore value to wait for
+ pop es ;ES points to TDB again
+
+TA_NukeCurrent:
+ ;** Check the flag values. If NO_UAE_BOX, tell KERNEL
+ ;** not to display the normal UAE box.
+ test wTermFlags,NO_UAE_BOX ;Display the box?
+ jz TA_20 ;Yes, so skip this stuff
+ or es:[TDB_ErrMode],02 ;Set the no display box flag
+TA_20:
+ ;** Terminate the app using KERNEL
+ cCall FatalAppExit, <0,0,0> ;Do it
+
+ ;** If we're flagged that this is an internal terminate, we just want
+ ;* to return if WDEB is installed so that we can pass the
+ ;** fault on. To do this, we must return here to the caller.
+ test wFlags,GIVE_WDEB386 ;Internal entry?
+ jnz TA_End ;Yes, don't nuke app
+
+ ;** If KERNEL doesn't nuke the app (does this if WDEB386
+ ;** is installed), nuke it ourselves (no UAE box)
+ mov es,segKernel ;Get the KERNEL segment
+ mov bx,npwTDBCur ;Get the current task pointer
+ mov es,es:[bx] ; in ES
+ cmp WORD PTR es:[TDB_USignalProc] + 2,0 ;USER signal proc?
+ jz @F ;No
+ mov bx,0666h ;Death knell
+ mov di, -1
+ cCall es:[TDB_USignalProc],<es,bx,di,es:[TDB_Module],es:[TDB_Queue]>
+@@: mov ax,4CFFH ;Nuke the app
+ int 21h ;We don't return here
+
+TA_End:
+
+cEnd
+
+sEnd
+
+ END
+
+
diff --git a/private/mvdm/wow16/toolhelp/ththunks.asm b/private/mvdm/wow16/toolhelp/ththunks.asm
new file mode 100644
index 000000000..1b940c522
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/ththunks.asm
@@ -0,0 +1,50 @@
+ TITLE THTHUNKS.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991-1992, Microsoft Corporation
+;
+; THTHUNKS.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+;
+; 09-Nov-1992 Dave Hart (davehart)
+; Adapted from mvdm\wow16\kernel31\kthunks.asm for ToolHelp
+;
+; 02-Apr-1991 Matt Felton (mattfe)
+; Created.
+;
+
+ifndef WINDEBUG
+ KDEBUG = 0
+ WDEBUG = 0
+else
+ KDEBUG = 1
+ WDEBUG = 1
+endif
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ include wow.inc
+ include wowth.inc
+ .list
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+; Kernel API thunks
+
+ ToolHelpThunk ClassFirst
+ ToolHelpThunk ClassNext
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/toolhelp/timer.asm b/private/mvdm/wow16/toolhelp/timer.asm
new file mode 100644
index 000000000..ee984fa7e
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/timer.asm
@@ -0,0 +1,180 @@
+ PAGE 60,150
+;***************************************************************************
+;* TIMER.ASM
+;*
+;* Routines used to give a cleaner interface to the VTD.
+;* This interface also works on a 286 by calling GetTickCount() in
+;* this case.
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+ INCLUDE WINDOWS.INC
+
+;** Symbols
+SI_CRITICAL EQU 1
+DI_CRITICAL EQU 2
+
+;** Imports
+externA __WinFlags
+externFP GetTickCount
+
+sBegin DATA
+
+dwLastTimeReturned dd 0
+wLastCountDown dw 0
+
+
+sEnd
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+; TimerCount
+; Returns the count from either the virtual timer device or from the
+; Windows function GetTickCount() depending on the processor.
+; Prototype:
+; BOOL FAR PASCAL TimerCount(
+; TIMERINFO FAR *lpTimer)
+;
+
+cProc TimerCount, <FAR,PUBLIC>, <si,di,ds>
+ parmD lpTimer
+ localD dwJumpAddr
+cBegin
+ mov ax, _DATA ;Get our data segment
+ mov es, ax
+
+ ;** Point to the structure
+ lds si,lpTimer ;Point to the structure
+
+ ;** Make sure the size is correct
+ xor ax,ax ;FALSE
+ cmp WORD PTR [si].ti_dwSize[2],0 ;High word must be zero
+ je @F
+ jmp TC_End
+@@: cmp WORD PTR [si].ti_dwSize[0],SIZE TIMERINFO ;Low word must match
+ je @F
+ jmp TC_End
+@@:
+
+ifndef WOW
+ ;** If we are in standard mode, always use Windows entry point
+ mov ax,__WinFlags ;Get the flags
+ test ax,WF_STANDARD ;Standard mode?
+ jnz TC_TryMMSys ;Yes, don't even try VTD
+.386p
+ ;** Try to get the VTD entry point
+ mov ax,1684h ;Get device entry point
+ mov bx,5 ;VTD device number
+ int 2fh ;Win386 entry point
+ mov ax,es ;Did we get a value?
+ or ax,di ; (zero means no device)
+ jz SHORT TC_UseWinAPI ;No VTD--use Win API
+
+ ;** Get the VTD values
+ mov WORD PTR dwJumpAddr[0],di ;Save the address
+ mov WORD PTR dwJumpAddr[2],es ;Save the address
+ mov ax,0101h ;VTD: ms since start of Win386
+ call DWORD PTR dwJumpAddr ;Call the VTD
+ jc SHORT TC_UseWinAPI ;Carry set means error
+ mov [si].ti_dwmsSinceStart,eax ;Save in structure
+ mov ax,0102h ;VTD: ms in this VM
+ call DWORD PTR dwJumpAddr ;Call the VTD
+ jc SHORT TC_UseWinAPI ;Carry set means VTD error
+ mov [si].ti_dwmsThisVM,eax ;Save value in structure
+ jmp TC_ReturnOK ;We're done
+.286p
+
+ ;** See if mmsystem timer is installed
+TC_TryMMSys:
+ cmp WORD PTR es:[lpfntimeGetTime][2], 0 ;Installed?
+ je TC_UseWinAPI ;No, do this the hard way
+ call DWORD PTR es:lpfntimeGetTime
+
+ ;** Fill the structure with this information
+ mov WORD PTR [si].ti_dwmsSinceStart[0],ax
+ mov WORD PTR [si].ti_dwmsSinceStart[2],dx
+ mov WORD PTR [si].ti_dwmsThisVM[0],ax
+ mov WORD PTR [si].ti_dwmsThisVM[2],dx
+ jmp TC_ReturnOK
+endif ; ndef WOW
+
+ ;** Use the Windows API
+TC_UseWinAPI:
+ cCall GetTickCount ;Call the Windows API
+ mov WORD PTR [si].ti_dwmsSinceStart[0],ax ;Save the value for now
+ mov WORD PTR [si].ti_dwmsSinceStart[2],dx
+
+ ;** Read the countdown timer. Note that the timer starts at 54 * 1193
+ ;** and counts down to zero. Each count is 1193 ms.
+ xor al,al ;Prepare to read tick count
+ out 43h,al ;Send to timer
+ in al,40h ;Get the low byte
+ mov ah,al ;Save in AH
+ in al,40h ;Get the high byte
+ xchg ah,al
+ mov dx,0ffffh ;Get total countdown amount
+ sub dx,ax ;Get number of counts expired
+ mov ax,dx ;Get the number in AX for div
+ xor dx,dx ;Zero the high word
+ mov cx,1193 ;Divide to get ms
+ div cx ;Divide it
+ mov cx, ax ;cx == saved Curr count
+
+ ;** Now fill the structure. Note that the 'ThisVM' entry is the
+ ;** same as the 'SinceStart' entry in standard mode.
+ xor dx, dx
+ add ax, WORD PTR [si].ti_dwmsSinceStart[0] ;Add this count in
+ adc dx, WORD PTR [si].ti_dwmsSinceStart[2]
+
+ ;** Check to make sure we didn't mess up. If we did (if the timer
+ ;** was reset right in the middle of us reading it). If we
+ ;** messed up, do it again until we get it right.
+ mov bx, _DATA ;Get our data segment
+ mov es, bx
+ cmp dx, WORD PTR es:dwLastTimeReturned[2]
+ jne TC_TimeOK
+ cmp ax, WORD PTR es:dwLastTimeReturned[0]
+ jae TC_TimeOK
+
+ ; New time is less than the old time so estimate the curr time
+ ; using LastTimeReturned as the base
+ mov ax, WORD PTR es:dwLastTimeReturned[0]
+ mov dx, WORD PTR es:dwLastTimeReturned[2]
+
+ xor bx, bx ;check for wrap
+ cmp cx, word ptr es:wLastCountDown
+ jae TC_NoWrap ;if wrap
+ add ax, cx ; += curr count
+ adc dx, 0
+ jmp short TC_TimeOK
+
+TC_NoWrap: ;else no wrap
+ mov bx, cx ; += Curr - LastCountDown
+ sub bx, word ptr es:wLastCountDown
+ add ax, bx
+ adc dx, 0
+
+TC_TimeOK:
+ mov word ptr es:wLastCountDown, cx
+ mov WORD PTR es:dwLastTimeReturned[0], ax
+ mov WORD PTR es:dwLastTimeReturned[2], dx
+ mov WORD PTR [si].ti_dwmsSinceStart[0], ax ;Save good count
+ mov WORD PTR [si].ti_dwmsSinceStart[2], dx
+ mov WORD PTR [si].ti_dwmsThisVM[0],ax ;Save in structure
+ mov WORD PTR [si].ti_dwmsThisVM[2],dx ;Save in structure
+
+TC_ReturnOK:
+ mov ax,1 ;Return TRUE
+
+TC_End:
+
+
+
+cEnd
+
+sEnd
+
+END
diff --git a/private/mvdm/wow16/toolhelp/toolhelp.c b/private/mvdm/wow16/toolhelp/toolhelp.c
new file mode 100644
index 000000000..c79d2438f
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolhelp.c
@@ -0,0 +1,147 @@
+/**************************************************************************
+ * TOOLHELP.C
+ *
+ * Contains the initalization and deinitialization code for the
+ * TOOLHELP DLL.
+ *
+ **************************************************************************/
+
+#include "toolpriv.h"
+#undef VERSION
+#include <mmsystem.h>
+
+/* ----- Global variables ----- */
+ WORD segKernel;
+ WORD wLibInstalled;
+ WORD wTHFlags;
+ HANDLE hMaster;
+ HANDLE hGDIHeap;
+ HANDLE hUserHeap;
+ WORD NEAR *npwExeHead;
+ WORD NEAR *npwTDBHead;
+ WORD NEAR *npwTDBCur;
+ DWORD NEAR *npdwSelTableStart;
+ WORD NEAR *npwSelTableLen;
+ FARPROC lpfnGetUserLocalObjType;
+ FARPROC lpfnFatalExitHook;
+ FARPROC lpfnNotifyHook;
+ LPFNUSUD lpfnUserSeeUserDo;
+ FARPROC lpfnGetFreeSystemResources;
+ FARPROC lpfntimeGetTime;
+ WORD wSel;
+ WORD wLRUCount;
+ char szKernel[] = "KERNEL";
+
+/* ----- Import values ----- */
+#define FATALEXITHOOK MAKEINTRESOURCE(318)
+#define GETUSERLOCALOBJTYPE MAKEINTRESOURCE(480)
+#define USERSEEUSERDO MAKEINTRESOURCE(216)
+#define HASGPHANDLER MAKEINTRESOURCE(338)
+#define TOOLHELPHOOK MAKEINTRESOURCE(341)
+#define GETFREESYSTEMRESOURCES MAKEINTRESOURCE(284)
+
+
+/* ToolHelpLibMain
+ * Called by DLL startup code.
+ * Initializes TOOLHELP.DLL.
+ */
+
+int PASCAL ToolHelpLibMain(
+ HANDLE hInstance,
+ WORD wDataSeg,
+ WORD wcbHeapSize,
+ LPSTR lpszCmdLine)
+{
+ HANDLE hKernel;
+ HANDLE hUser;
+ HANDLE hMMSys;
+
+ /* Unless we say otherwise, the library is installed OK */
+ wLibInstalled = TRUE;
+
+ /* Do the KERNEL type-checking. Puts the results in global variables */
+ KernelType();
+
+ /* If the KERNEL check failed (not in PMODE) return that the library did
+ * not correctly install but allow the load anyway.
+ */
+ if (!wTHFlags)
+ {
+ wLibInstalled = FALSE;
+
+ /* Return success anyway, just fails all API calls */
+ return 1;
+ }
+
+ /* Grab a selector. This is only necessary in Win30StdMode */
+ if (wTHFlags & TH_WIN30STDMODE)
+ wSel = HelperGrabSelector();
+
+ /* Get the User and GDI heap handles if possible */
+ hKernel = GetModuleHandle((LPSTR)szKernel);
+ hUser = GetModuleHandle("USER");
+ hUserHeap = UserGdiDGROUP(hUser);
+ hGDIHeap = UserGdiDGROUP(GetModuleHandle("GDI"));
+
+ /* Get all the functions we may need. These functions only exist in
+ * the 3.1 USER and KERNEL.
+ */
+ if (!(wTHFlags & TH_WIN30))
+ {
+ /* FatalExit hook */
+ lpfnFatalExitHook = GetProcAddress(hKernel, FATALEXITHOOK);
+
+ /* Internal USER routine to get head of class list */
+ lpfnUserSeeUserDo = (LPFNUSUD)(FARPROC)
+ GetProcAddress(hUser, USERSEEUSERDO);
+
+ /* Identifies objects on USER's local heap */
+ lpfnGetUserLocalObjType = GetProcAddress(hUser, GETUSERLOCALOBJTYPE);
+
+ /* Identifies parameter validation GP faults */
+ lpfnPV = GetProcAddress(hKernel, HASGPHANDLER);
+
+ /* See if the new TOOLHELP KERNEL hook is around */
+ lpfnNotifyHook = (FARPROC) GetProcAddress(hKernel, TOOLHELPHOOK);
+ if (lpfnNotifyHook)
+ wTHFlags |= TH_GOODPTRACEHOOK;
+
+ /* Get the USER system resources function */
+ lpfnGetFreeSystemResources = (FARPROC)
+ GetProcAddress(hUser, GETFREESYSTEMRESOURCES);
+ }
+
+ /* Make sure we don't ever call these in 3.0 */
+ else
+ {
+ lpfnFatalExitHook = NULL;
+ lpfnUserSeeUserDo = NULL;
+ lpfnGetUserLocalObjType = NULL;
+ lpfnPV = NULL;
+ }
+
+ /* Try to get the multimedia system timer function address */
+ hMMSys = GetModuleHandle("MMSYSTEM");
+ if (hMMSys)
+ {
+ TIMECAPS tc;
+ UINT (WINAPI* lpfntimeGetDevCaps)(
+ TIMECAPS FAR* lpTimeCaps,
+ UINT wSize);
+
+ /* Call the timer API to see if the timer's really installed,
+ * and if it is, get the address of the get time function
+ */
+ lpfntimeGetDevCaps =
+ GetProcAddress(hMMSys, MAKEINTRESOURCE(604));
+ if ((*lpfntimeGetDevCaps)(&tc, sizeof (tc)) == TIMERR_NOERROR)
+ lpfntimeGetTime =
+ GetProcAddress(hMMSys, MAKEINTRESOURCE(607));
+ }
+
+ /* Return success */
+ return 1;
+}
+
+
+
diff --git a/private/mvdm/wow16/toolhelp/toolhelp.def b/private/mvdm/wow16/toolhelp/toolhelp.def
new file mode 100644
index 000000000..0d6d6884a
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolhelp.def
@@ -0,0 +1,45 @@
+LIBRARY TOOLHELP
+DESCRIPTION 'TOOLHELP for WOW - Debug/Tool Helper library'
+EXETYPE WINDOWS
+
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+
+HEAPSIZE 512
+
+EXPORTS
+ WEP @1 RESIDENTNAME ;Internal
+ GLOBALHANDLETOSEL @50
+ GLOBALFIRST @51
+ GLOBALNEXT @52
+ GLOBALINFO @53
+ GLOBALENTRYHANDLE @54
+ GLOBALENTRYMODULE @55
+ LOCALINFO @56
+ LOCALFIRST @57
+ LOCALNEXT @58
+ MODULEFIRST @59
+ MODULENEXT @60
+ MODULEFINDNAME @61
+ MODULEFINDHANDLE @62
+ TASKFIRST @63
+ TASKNEXT @64
+ TASKFINDHANDLE @65
+ STACKTRACEFIRST @66
+ STACKTRACECSIPFIRST @67
+ STACKTRACENEXT @68
+ CLASSFIRST @69
+ CLASSNEXT @70
+ SYSTEMHEAPINFO @71
+ MEMMANINFO @72
+ NOTIFYREGISTER @73
+ NOTIFYUNREGISTER @74
+ INTERRUPTREGISTER @75
+ INTERRUPTUNREGISTER @76
+ TERMINATEAPP @77
+ MEMORYREAD @78
+ MEMORYWRITE @79
+ TIMERCOUNT @80
+ TASKSETCSIP @81
+ TASKGETCSIP @82
+ TASKSWITCH @83
diff --git a/private/mvdm/wow16/toolhelp/toolhelp.h b/private/mvdm/wow16/toolhelp/toolhelp.h
new file mode 100644
index 000000000..25b918f80
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolhelp.h
@@ -0,0 +1,469 @@
+/*****************************************************************************\
+* *
+* toolhelp.h - toolhelp.dll functions, types, and definitions *
+* *
+* Version 1.0 *
+* *
+* NOTE: windows.h must be #included first *
+* *
+* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
+* *
+\*****************************************************************************/
+
+#ifndef _INC_TOOLHELP
+#define _INC_TOOLHELP
+
+#ifndef RC_INVOKED
+#pragma pack(1) /* Assume byte packing throughout */
+#endif
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifndef _INC_WINDOWS /* If included with 3.0 headers... */
+#define LPCSTR LPSTR
+#define WINAPI FAR PASCAL
+#define CALLBACK FAR PASCAL
+#define UINT WORD
+#define HMODULE HANDLE
+#define HINSTANCE HANDLE
+#define HLOCAL HANDLE
+#define HGLOBAL HANDLE
+#define HTASK HANDLE
+#endif /* _INC_WINDOWS */
+
+/****** General symbols ******************************************************/
+#define MAX_DATA 11
+#define MAX_PATH 255
+#define MAX_MODULE_NAME 8 + 1
+#define MAX_CLASSNAME 255
+
+/****** Global heap walking ***************************************************/
+typedef struct tagGLOBALINFO
+{
+ DWORD dwSize;
+ WORD wcItems;
+ WORD wcItemsFree;
+ WORD wcItemsLRU;
+} GLOBALINFO;
+
+typedef struct tagGLOBALENTRY
+{
+ DWORD dwSize;
+ DWORD dwAddress;
+ DWORD dwBlockSize;
+ HGLOBAL hBlock;
+ WORD wcLock;
+ WORD wcPageLock;
+ WORD wFlags;
+ BOOL wHeapPresent;
+ HGLOBAL hOwner;
+ WORD wType;
+ WORD wData;
+ DWORD dwNext;
+ DWORD dwNextAlt;
+} GLOBALENTRY;
+
+/* GlobalFirst()/GlobalNext() flags */
+#define GLOBAL_ALL 0
+#define GLOBAL_LRU 1
+#define GLOBAL_FREE 2
+
+/* GLOBALENTRY.wType entries */
+#define GT_UNKNOWN 0
+#define GT_DGROUP 1
+#define GT_DATA 2
+#define GT_CODE 3
+#define GT_TASK 4
+#define GT_RESOURCE 5
+#define GT_MODULE 6
+#define GT_FREE 7
+#define GT_INTERNAL 8
+#define GT_SENTINEL 9
+#define GT_BURGERMASTER 10
+
+/* If GLOBALENTRY.wType==GT_RESOURCE, the following is GLOBALENTRY.wData: */
+#define GD_USERDEFINED 0
+#define GD_CURSORCOMPONENT 1
+#define GD_BITMAP 2
+#define GD_ICONCOMPONENT 3
+#define GD_MENU 4
+#define GD_DIALOG 5
+#define GD_STRING 6
+#define GD_FONTDIR 7
+#define GD_FONT 8
+#define GD_ACCELERATORS 9
+#define GD_RCDATA 10
+#define GD_ERRTABLE 11
+#define GD_CURSOR 12
+#define GD_ICON 14
+#define GD_NAMETABLE 15
+#define GD_MAX_RESOURCE 15
+
+/* GLOBALENTRY.wFlags */
+#define GF_PDB_OWNER 0x0100 /* Low byte is KERNEL flags */
+
+BOOL WINAPI GlobalInfo(GLOBALINFO FAR* lpGlobalInfo);
+BOOL WINAPI GlobalFirst(GLOBALENTRY FAR* lpGlobal, WORD wFlags);
+BOOL WINAPI GlobalNext(GLOBALENTRY FAR* lpGlobal, WORD wFlags);
+BOOL WINAPI GlobalEntryHandle(GLOBALENTRY FAR* lpGlobal, HGLOBAL hItem);
+BOOL WINAPI GlobalEntryModule(GLOBALENTRY FAR* lpGlobal, HMODULE hModule, WORD wSeg);
+WORD WINAPI GlobalHandleToSel(HGLOBAL hMem);
+
+/****** Local heap walking ***************************************************/
+
+typedef struct tagLOCALINFO
+{
+ DWORD dwSize;
+ WORD wcItems;
+} LOCALINFO;
+
+typedef struct tagLOCALENTRY
+{
+ DWORD dwSize;
+ HLOCAL hHandle;
+ WORD wAddress;
+ WORD wSize;
+ WORD wFlags;
+ WORD wcLock;
+ WORD wType;
+ WORD hHeap;
+ WORD wHeapType;
+ WORD wNext;
+} LOCALENTRY;
+
+/* LOCALENTRY.wHeapType flags */
+#define NORMAL_HEAP 0
+#define USER_HEAP 1
+#define GDI_HEAP 2
+
+/* LOCALENTRY.wFlags */
+#define LF_FIXED 1
+#define LF_FREE 2
+#define LF_MOVEABLE 4
+
+/* LOCALENTRY.wType */
+#define LT_NORMAL 0
+#define LT_FREE 0xff
+#define LT_GDI_PEN 1 /* LT_GDI_* is for GDI's heap */
+#define LT_GDI_BRUSH 2
+#define LT_GDI_FONT 3
+#define LT_GDI_PALETTE 4
+#define LT_GDI_BITMAP 5
+#define LT_GDI_RGN 6
+#define LT_GDI_DC 7
+#define LT_GDI_DISABLED_DC 8
+#define LT_GDI_METADC 9
+#define LT_GDI_METAFILE 10
+#define LT_GDI_MAX LT_GDI_METAFILE
+#define LT_USER_CLASS 1 /* LT_USER_* is for USER's heap */
+#define LT_USER_WND 2
+#define LT_USER_STRING 3
+#define LT_USER_MENU 4
+#define LT_USER_CLIP 5
+#define LT_USER_CBOX 6
+#define LT_USER_PALETTE 7
+#define LT_USER_ED 8
+#define LT_USER_BWL 9
+#define LT_USER_OWNERDRAW 10
+#define LT_USER_SPB 11
+#define LT_USER_CHECKPOINT 12
+#define LT_USER_DCE 13
+#define LT_USER_MWP 14
+#define LT_USER_PROP 15
+#define LT_USER_LBIV 16
+#define LT_USER_MISC 17
+#define LT_USER_ATOMS 18
+#define LT_USER_LOCKINPUTSTATE 19
+#define LT_USER_HOOKLIST 20
+#define LT_USER_USERSEEUSERDOALLOC 21
+#define LT_USER_HOTKEYLIST 22
+#define LT_USER_POPUPMENU 23
+#define LT_USER_HANDLETABLE 32
+#define LT_USER_MAX LT_USER_HANDLETABLE
+
+BOOL WINAPI LocalInfo(LOCALINFO FAR* lpLocal, HGLOBAL hHeap);
+BOOL WINAPI LocalFirst(LOCALENTRY FAR* lpLocal, HGLOBAL hHeap);
+BOOL WINAPI LocalNext(LOCALENTRY FAR* lpLocal);
+
+/****** Stack Tracing ********************************************************/
+
+typedef struct tagSTACKTRACEENTRY
+{
+ DWORD dwSize;
+ HTASK hTask;
+ WORD wSS;
+ WORD wBP;
+ WORD wCS;
+ WORD wIP;
+ HMODULE hModule;
+ WORD wSegment;
+ WORD wFlags;
+} STACKTRACEENTRY;
+
+/* STACKTRACEENTRY.wFlags values */
+#define FRAME_FAR 0
+#define FRAME_NEAR 1
+
+BOOL WINAPI StackTraceFirst(STACKTRACEENTRY FAR* lpStackTrace, HTASK hTask);
+BOOL WINAPI StackTraceCSIPFirst(STACKTRACEENTRY FAR* lpStackTrace,
+ WORD wSS, WORD wCS, WORD wIP, WORD wBP);
+BOOL WINAPI StackTraceNext(STACKTRACEENTRY FAR* lpStackTrace);
+
+/****** Module list walking **************************************************/
+
+typedef struct tagMODULEENTRY
+{
+ DWORD dwSize;
+ char szModule[MAX_MODULE_NAME + 1];
+ HMODULE hModule;
+ WORD wcUsage;
+ char szExePath[MAX_PATH + 1];
+ WORD wNext;
+} MODULEENTRY;
+
+BOOL WINAPI ModuleFirst(MODULEENTRY FAR* lpModule);
+BOOL WINAPI ModuleNext(MODULEENTRY FAR* lpModule);
+HMODULE WINAPI ModuleFindName(MODULEENTRY FAR* lpModule, LPCSTR lpstrName);
+HMODULE WINAPI ModuleFindHandle(MODULEENTRY FAR* lpModule, HMODULE hModule);
+
+/****** Task list walking *****************************************************/
+
+typedef struct tagTASKENTRY
+{
+ DWORD dwSize;
+ HTASK hTask;
+ HTASK hTaskParent;
+ HINSTANCE hInst;
+ HMODULE hModule;
+ WORD wSS;
+ WORD wSP;
+ WORD wStackTop;
+ WORD wStackMinimum;
+ WORD wStackBottom;
+ WORD wcEvents;
+ HGLOBAL hQueue;
+ char szModule[MAX_MODULE_NAME + 1];
+ WORD wPSPOffset;
+ HANDLE hNext;
+} TASKENTRY;
+
+BOOL WINAPI TaskFirst(TASKENTRY FAR* lpTask);
+BOOL WINAPI TaskNext(TASKENTRY FAR* lpTask);
+BOOL WINAPI TaskFindHandle(TASKENTRY FAR* lpTask, HTASK hTask);
+DWORD WINAPI TaskSetCSIP(HTASK hTask, WORD wCS, WORD wIP);
+DWORD WINAPI TaskGetCSIP(HTASK hTask);
+BOOL WINAPI TaskSwitch(HTASK hTask, DWORD dwNewCSIP);
+
+/****** Window Class enumeration **********************************************/
+
+typedef struct tagCLASSENTRY
+{
+ DWORD dwSize;
+ HMODULE hInst; /* This is really an hModule */
+ char szClassName[MAX_CLASSNAME + 1];
+ WORD wNext;
+} CLASSENTRY;
+
+BOOL WINAPI ClassFirst(CLASSENTRY FAR* lpClass);
+BOOL WINAPI ClassNext(CLASSENTRY FAR* lpClass);
+
+/****** Information functions *************************************************/
+
+typedef struct tagMEMMANINFO
+{
+ DWORD dwSize;
+ DWORD dwLargestFreeBlock;
+ DWORD dwMaxPagesAvailable;
+ DWORD dwMaxPagesLockable;
+ DWORD dwTotalLinearSpace;
+ DWORD dwTotalUnlockedPages;
+ DWORD dwFreePages;
+ DWORD dwTotalPages;
+ DWORD dwFreeLinearSpace;
+ DWORD dwSwapFilePages;
+ WORD wPageSize;
+} MEMMANINFO;
+
+BOOL WINAPI MemManInfo(MEMMANINFO FAR* lpEnhMode);
+
+typedef struct tagSYSHEAPINFO
+{
+ DWORD dwSize;
+ WORD wUserFreePercent;
+ WORD wGDIFreePercent;
+ HGLOBAL hUserSegment;
+ HGLOBAL hGDISegment;
+} SYSHEAPINFO;
+
+BOOL WINAPI SystemHeapInfo(SYSHEAPINFO FAR* lpSysHeap);
+
+/****** Interrupt Handling ****************************************************/
+
+/* Hooked interrupts */
+#define INT_DIV0 0
+#define INT_1 1
+#define INT_3 3
+#define INT_UDINSTR 6
+#define INT_STKFAULT 12
+#define INT_GPFAULT 13
+#define INT_BADPAGEFAULT 14
+#define INT_CTLALTSYSRQ 256
+
+/* TOOLHELP Interrupt callbacks registered with InterruptRegister should
+ * always be written in assembly language. The stack frame is not
+ * compatible with high level language conventions.
+ *
+ * This stack frame looks as follows to the callback. All registers
+ * should be preserved across this callback to allow restarting fault.
+ * ------------
+ * | Flags | [SP + 0Eh]
+ * | CS | [SP + 0Ch]
+ * | IP | [SP + 0Ah]
+ * | Handle | [SP + 08h]
+ * |Exception#| [SP + 06h]
+ * | AX | [SP + 04h] AX Saved to allow MakeProcInstance
+ * | Ret CS | [SP + 02h]
+ * SP---> | Ret IP | [SP + 00h]
+ * ------------
+ */
+BOOL WINAPI InterruptRegister(HTASK hTask, FARPROC lpfnIntCallback);
+BOOL WINAPI InterruptUnRegister(HTASK hTask);
+
+/* Notifications:
+ * When a notification callback is called, two parameters are passed
+ * in: a WORD, wID, and another DWORD, dwData. wID is one of
+ * the values NFY_* below. Callback routines should ignore unrecog-
+ * nized values to preserve future compatibility. Callback routines
+ * are also passed a dwData value. This may contain data or may be
+ * a FAR pointer to a structure, or may not be used depending on
+ * which notification is being received.
+ *
+ * In all cases, if the return value of the callback is TRUE, the
+ * notification will NOT be passed on to other callbacks. It has
+ * been handled. This should be used sparingly and only with certain
+ * notifications. Callbacks almost always return FALSE.
+ */
+
+/* NFY_UNKNOWN: An unknown notification has been returned from KERNEL. Apps
+ * should ignore these.
+ */
+#define NFY_UNKNOWN 0
+
+/* NFY_LOADSEG: dwData points to a NFYLOADSEG structure */
+#define NFY_LOADSEG 1
+typedef struct tagNFYLOADSEG
+{
+ DWORD dwSize;
+ WORD wSelector;
+ WORD wSegNum;
+ WORD wType; /* Low bit set if data seg, clear if code seg */
+ WORD wcInstance; /* Instance count ONLY VALID FOR DATA SEG */
+ LPCSTR lpstrModuleName;
+} NFYLOADSEG;
+
+/* NFY_FREESEG: LOWORD(dwData) is the selector of the segment being freed */
+#define NFY_FREESEG 2
+
+/* NFY_STARTDLL: dwData points to a NFYLOADSEG structure */
+#define NFY_STARTDLL 3
+typedef struct tagNFYSTARTDLL
+{
+ DWORD dwSize;
+ HMODULE hModule;
+ WORD wCS;
+ WORD wIP;
+} NFYSTARTDLL;
+
+/* NFY_STARTTASK: dwData is the CS:IP of the start address of the task */
+#define NFY_STARTTASK 4
+
+/* NFY_EXITTASK: The low byte of dwData contains the program exit code */
+#define NFY_EXITTASK 5
+
+/* NFY_DELMODULE: LOWORD(dwData) is the handle of the module to be freed */
+#define NFY_DELMODULE 6
+
+/* NFY_RIP: dwData points to a NFYRIP structure */
+#define NFY_RIP 7
+typedef struct tagNFYRIP
+{
+ DWORD dwSize;
+ WORD wIP;
+ WORD wCS;
+ WORD wSS;
+ WORD wBP;
+ WORD wExitCode;
+} NFYRIP;
+
+/* NFY_TASKIN: No data. Callback should do GetCurrentTask() */
+#define NFY_TASKIN 8
+
+/* NFY_TASKOUT: No data. Callback should do GetCurrentTask() */
+#define NFY_TASKOUT 9
+
+/* NFY_INCHAR: Return value from callback is used. If NULL, mapped to 'i' */
+#define NFY_INCHAR 10
+
+/* NFY_OUTSTR: dwData points to the string to be displayed */
+#define NFY_OUTSTR 11
+
+/* NFY_LOGERROR: dwData points to a NFYLOGERROR struct */
+#define NFY_LOGERROR 12
+typedef struct tagNFYLOGERROR
+{
+ DWORD dwSize;
+ UINT wErrCode;
+ void FAR* lpInfo; /* Error code-dependent */
+} NFYLOGERROR;
+
+/* NFY_LOGPARAMERROR: dwData points to a NFYLOGPARAMERROR struct */
+#define NFY_LOGPARAMERROR 13
+typedef struct tagNFYLOGPARAMERROR
+{
+ DWORD dwSize;
+ UINT wErrCode;
+ FARPROC lpfnErrorAddr;
+ void FAR* FAR* lpBadParam;
+} NFYLOGPARAMERROR;
+
+/* NotifyRegister() flags */
+#define NF_NORMAL 0
+#define NF_TASKSWITCH 1
+#define NF_RIP 2
+
+typedef BOOL (CALLBACK* LPFNNOTIFYCALLBACK)(WORD wID, DWORD dwData);
+
+BOOL WINAPI NotifyRegister(HTASK hTask, LPFNNOTIFYCALLBACK lpfn, WORD wFlags);
+BOOL WINAPI NotifyUnRegister(HTASK hTask);
+
+/****** Miscellaneous *********************************************************/
+
+void WINAPI TerminateApp(HTASK hTask, WORD wFlags);
+
+/* TerminateApp() flag values */
+#define UAE_BOX 0
+#define NO_UAE_BOX 1
+
+DWORD WINAPI MemoryRead(WORD wSel, DWORD dwOffset, void FAR* lpBuffer, DWORD dwcb);
+DWORD WINAPI MemoryWrite(WORD wSel, DWORD dwOffset, void FAR* lpBuffer, DWORD dwcb);
+
+typedef struct tagTIMERINFO
+{
+ DWORD dwSize;
+ DWORD dwmsSinceStart;
+ DWORD dwmsThisVM;
+} TIMERINFO;
+
+BOOL WINAPI TimerCount(TIMERINFO FAR* lpTimer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifndef RC_INVOKED
+#pragma pack() /* Revert to default packing */
+#endif
+
+#endif /* !_INC_TOOLHELP */
diff --git a/private/mvdm/wow16/toolhelp/toolhelp.inc b/private/mvdm/wow16/toolhelp/toolhelp.inc
new file mode 100644
index 000000000..37537623b
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolhelp.inc
@@ -0,0 +1,292 @@
+;**************************************************************************
+;* TOOLHELP.INC
+;*
+;* Assembly-language public include file for TOOLHELP.DLL
+;*
+;**************************************************************************
+
+;** General symbol values
+MAX_DATA EQU 11
+MAX_PATH EQU 255
+MAX_MODULE_NAME EQU 8 + 1 ;Leave room for the zero and padding
+MAX_CLASSNAME EQU 255
+
+; ----- Global heap walking -----
+
+GLOBALENTRY STRUC
+ge_dwSize DD ? ;Structure version
+ge_dwAddress DD ? ;This block's address
+ge_dwBlockSize DD ? ;This block's size
+ge_hBlock DW ? ;This block's handle
+ge_wcLock DW ? ;Lock count
+ge_wcPageLock DW ? ;Page lock count
+ge_wFlags DW ? ;Block flags
+ge_wHeapPresent DW ? ;Size of available local heap
+ge_hOwner DW ? ;Owner handle
+ge_wType DW ? ;Block type
+ge_wData DW ? ;Type-specific data
+ge_dwNext DD ? ;Pointer to next block
+ge_dwNextAlt DD ? ;Next free/LRU block in chain
+GLOBALENTRY ENDS
+
+; ** GlobalFirst()/GlobalNext() flags
+GLOBAL_ALL EQU 0
+GLOBAL_LRU EQU 1
+GLOBAL_FREE EQU 2
+
+; ** GLOBALENTRY.ge_wType entries
+GT_UNKNOWN EQU 0
+GT_DGROUP EQU 1
+GT_DATA EQU 2
+GT_CODE EQU 3
+GT_TASK EQU 4
+GT_RESOURCE EQU 5
+GT_MODULE EQU 6
+GT_FREE EQU 7
+GT_INTERNAL EQU 8
+GT_SENTINEL EQU 9
+GT_BURGERMASTER EQU 10
+
+; ** if GLOBALENTRY.wType==GT_RESOURCE, the following is GLOBALENTRY.wData:
+GD_USERDEFINED EQU 0
+GD_CURSORCOMPONENT EQU 1
+GD_BITMAP EQU 2
+GD_ICONCOMPONENT EQU 3
+GD_MENU EQU 4
+GD_DIALOG EQU 5
+GD_STRING EQU 6
+GD_FONTDIR EQU 7
+GD_FONT EQU 8
+GD_ACCELERATORS EQU 9
+GD_RCDATA EQU 10
+GD_ERRTABLE EQU 11
+GD_CURSOR EQU 12
+GD_ICON EQU 14
+GD_NAMETABLE EQU 15
+GD_MAX_RESOURCE EQU 15
+
+;** GLOBALENTRY.wFlags
+GF_PDB_OWNER EQU 100h ;Low byte is KERNEL flags
+
+; ----- Local heap walking -----
+
+LOCALENTRY STRUC
+le_dwSize DD ?
+le_hHandle DW ?
+le_wAddress DW ?
+le_wSize DW ?
+le_wFlags DW ?
+le_wcLock DW ?
+le_wType DW ?
+le_hHeap DW ?
+le_wHeapType DW ?
+le_wNext DW ?
+LOCALENTRY ENDS
+
+; ** LOCALENTRY.wHeapType flags
+NORMAL_HEAP EQU 0
+USER_HEAP EQU 1
+GDI_HEAP EQU 2
+
+;** LOCALENTRY.wFlags
+LF_FIXED EQU 1
+LF_FREE EQU 2
+LF_MOVEABLE EQU 4
+
+;** LOCALENTRY.wType
+LT_NORMAL EQU 0
+LT_GDI_PEN EQU 1
+LT_GDI_BRUSH EQU 2
+LT_GDI_FONT EQU 3
+LT_GDI_PALETTE EQU 4
+LT_GDI_BITMAP EQU 5
+LT_GDI_RGN EQU 6
+LT_GDI_DC EQU 7
+LT_GDI_DISABLED_DC EQU 8
+LT_GDI_METADC EQU 9
+LT_GDI_METAFILE EQU 10
+LT_GDI_MAX EQU LT_GDI_METAFILE
+LT_FREE EQU 0ffh
+
+; ----- Stack tracing -----
+
+STACKTRACEENTRY STRUC
+st_dwSize DD ?
+st_hTask DW ?
+st_wSS DW ?
+st_wBP DW ?
+st_wCS DW ?
+st_wIP DW ?
+st_hModule DW ?
+st_wSegment DW ?
+st_wFlags DW ?
+STACKTRACEENTRY ENDS
+
+;** STACKTRACEENTRY.wFlags values
+FRAME_FAR EQU 0
+FRAME_NEAR EQU 1
+
+; ----- Module list walking -----
+
+MODULEENTRY STRUC
+me_dwSize DD ?
+me_szModule DB MAX_MODULE_NAME + 1 DUP(?)
+me_hModule DW ?
+me_wcUsage DW ?
+me_szExePath DB MAX_PATH + 1 + 1 DUP(?)
+me_wNext DW ?
+MODULEENTRY ENDS
+
+; ----- Task list walking -----
+
+TASKENTRY STRUC
+te_dwSize DD ?
+te_hTask DW ?
+te_hTaskParent DW ?
+te_hInst DW ?
+te_hModule DW ?
+te_wSS DW ?
+te_wSP DW ?
+te_wStackTop DW ?
+te_wStackMinimum DW ?
+te_wStackBottom DW ?
+te_wcEvents DW ?
+te_hQueue DW ?
+te_szModule DB MAX_MODULE_NAME + 1 DUP(?)
+te_wPSPOffset DW ?
+te_hNext DW ?
+TASKENTRY ENDS
+
+;** TaskSwitch() return values
+TS_ERROR EQU 0
+TS_NEW EQU 1
+TS_OLD EQU 2
+
+; ----- Window Class enumeration -----
+
+CLASSENTRY STRUC
+ce_dwSize DD ?
+ce_hInst DW ?
+ce_szClassName DB MAX_CLASSNAME + 1 DUP(?)
+ce_wNext DW ?
+CLASSENTRY ENDS
+
+; ----- Information functions -----
+
+VMEMMANINFO STRUC
+vmm_dwSize DD ?
+vmm_dwLargestFreeBlock DD ?
+vmm_dwMaxPagesAvailable DD ?
+vmm_dwMaxPagesLockable DD ?
+vmm_dwTotalLinearSpace DD ?
+vmm_dwTotalUnlockedPages DD ?
+vmm_dwFreePages DD ?
+vmm_dwTotalPages DD ?
+vmm_dwFreeLinearSpace DD ?
+vmm_dwSwapFilePages DD ?
+vmm_wPageSize DW ?
+VMEMMANINFO ENDS
+
+SYSHEAPINFO STRUC
+si_dwSize DD ?
+si_wUserFreePercent DW ?
+si_wGDIFreePercent DW ?
+si_hUserSegment DW ?
+si_hGDISegment DW ?
+SYSHEAPINFO ENDS
+
+; ----- Notifications -----
+
+;* NFY_UNKNOWN: An unknown notification has been returned from KERNEL. Apps
+;* should ignore these.
+;*
+NFY_UNKNOWN EQU 0
+
+;** NFY_LOADSEG: dwData points to a NFYLOADSEG structure
+NFY_LOADSEG EQU 1
+NFYLOADSEG STRUC
+nls_dwSize DD ?
+nls_wSelector DW ?
+nls_wSegNum DW ?
+nls_wType DW ? ;Low bit set for DATA, clear for CODE
+nls_wcInstance DW ? ;Instance count ONLY VALID FOR DATA!
+nls_lpstrModuleName DD ?
+NFYLOADSEG ENDS
+
+;** NFY_FREESEG: LOWORD(dwData) is the selector of the segment being freed
+NFY_FREESEG EQU 2
+
+;** NFY_STARTDLL: dwData points to a NFYSTARTDLL structure
+NFY_STARTDLL EQU 3
+NFYSTARTDLL STRUC
+nsd_dwSize DD ?
+nsd_hModule DW ?
+nsd_wCS DW ?
+nsd_wIP DW ?
+NFYSTARTDLL ENDS
+
+;** NFY_STARTTASK: dwData is the CS:IP of the task start address
+NFY_STARTTASK EQU 4
+
+;** NFY_EXITTASK: The low byte of dwData contains the program exit code
+NFY_EXITTASK EQU 5
+
+;** NFY_DELMODULE: LOWORD(dwData) is the handle of the module to be freed
+NFY_DELMODULE EQU 6
+
+;** NFY_RIP: LOWORD(dwData) is the fatal exit code
+;** NFY_RIP: dwData points to a NFYRIP structure
+NFY_RIP EQU 7
+NFYRIP STRUC
+nrp_dwSize DD ?
+nrp_wIP DW ?
+nrp_wCS DW ?
+nrp_wSS DW ?
+nrp_wBP DW ?
+nrp_wExitCode DW ?
+NFYRIP ENDS
+
+;** NFY_TASKIN: No data. Callback should do GetCurrentTask()
+NFY_TASKIN EQU 8
+
+;** NFY_TASKOUT: No data. Callback should do GetCurrentTask()
+NFY_TASKOUT EQU 9
+
+;** NFY_INCHAR: Return value of callback is used. If FALSE, mapped to 'i'
+NFY_INCHAR EQU 10
+
+;** NFY_OUTSTR: dwData points to the string to be displayed
+NFY_OUTSTR EQU 11
+
+;** NFY_LOGERROR: dwData points to a NFYLOGERROR struct
+NFY_LOGERROR EQU 12
+NFYLOGERROR STRUC
+nle_dwSize DD ?
+nle_wErrCode DW ?
+nle_lpInfo DD ? ;Error-code dependent
+NFYLOGERROR ENDS
+
+;** NFY_LOGPARAMERROR: dwData points to a NFYLOGPARAMERROR struct
+NFY_LOGPARAMERROR EQU 13
+NFYLOGPARAMERROR STRUC
+nlp_dwSize DD ?
+nlp_wErrCode DW ?
+nlp_lpfnErrorAddr DD ?
+nlp_lpBadParam DD ?
+NFYLOGPARAMERROR ENDS
+
+;** NotifyRegister() flags
+NF_NORMAL EQU 0
+NF_TASKSWITCH EQU 1
+NF_RIP EQU 2
+
+;** TerminateApp() flag values
+UAE_BOX EQU 0
+NO_UAE_BOX EQU 1
+
+TIMERINFO STRUC
+ti_dwSize DD ?
+ti_dwmsSinceStart DD ?
+ti_dwmsThisVM DD ?
+TIMERINFO ENDS
+
diff --git a/private/mvdm/wow16/toolhelp/toolhelp.rcv b/private/mvdm/wow16/toolhelp/toolhelp.rcv
new file mode 100644
index 000000000..014720674
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolhelp.rcv
@@ -0,0 +1,14 @@
+/********************************************************************/
+/* TOOLHELP.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Debug/Tool helper library"
+#define VER_INTERNALNAME_STR "TOOLHELP"
+#define VER_ORIGINALFILENAME_STR "TOOLHELP.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/toolhelp/toolpriv.h b/private/mvdm/wow16/toolhelp/toolpriv.h
new file mode 100644
index 000000000..f14f613aa
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolpriv.h
@@ -0,0 +1,220 @@
+/**************************************************************************
+ * TOOLPRIV.H
+ *
+ * Private header file for routines in the tool helper library
+ *
+ **************************************************************************/
+
+#ifndef TOOLPRIV_H
+#define TOOLPRIV_H
+
+#define BUILDDLL
+
+#include <windows.h>
+#include "toolhelp.h"
+
+/* ----- Symbols ----- */
+#define VERSION 1
+#ifndef NOEXPORT
+#define NOEXPORT static
+#endif
+#define TOOLHELPAPI WINAPI
+
+#define FAULT_ACTIVE 2
+#define NUM_EXCEPTIONS 3
+
+/* wTHFlag values */
+#define TH_KERNEL_286 1
+#define TH_KERNEL_386 2
+#define TH_WIN30 4
+#define TH_WIN30STDMODE 8 /* THWIN30STDMODE set if TH_WIN30 & Std mode */
+#define TH_GOODPTRACEHOOK 16
+#define TH_GOTOLDPTRACE 32
+
+/* ----- Code macros ----- */
+#define MAKEFARPTR(s, o) ((void FAR *)(((WORD)(o)) | \
+ (((DWORD)(WORD)(s)) << 16)))
+
+/* ----- Types ----- */
+
+typedef struct tagNOTIFYSTRUCT
+{
+ struct tagNOTIFYSTRUCT *pNext;
+ HANDLE hTask;
+ LPFNNOTIFYCALLBACK lpfn;
+ WORD wFlags;
+} NOTIFYSTRUCT;
+
+typedef void (FAR PASCAL *LPFNCALLBACK)(void);
+
+typedef struct tagINTERRUPT
+{
+ struct tagINTERRUPT *pNext;
+ HANDLE hTask;
+ LPFNCALLBACK lpfn;
+} INTERRUPT;
+
+typedef struct tagSIGNAL
+{
+ struct tagSIGNAL *pNext;
+ HANDLE hTask;
+ LPFNCALLBACK lpfn;
+ LPFNCALLBACK lpfnOld;
+} SIGNAL;
+
+typedef LONG (FAR PASCAL *LPFNUSUD)(
+ WORD wID,
+ WORD wParam,
+ LONG lParam);
+
+/* ----- TOOLHELP global variables ----- */
+ extern WORD segKernel;
+ extern WORD wLibInstalled;
+ extern HANDLE hMaster;
+ extern WORD wTHFlags;
+ extern HANDLE hUserHeap;
+ extern HANDLE hGDIHeap;
+ extern WORD NEAR *npwExeHead;
+ extern WORD NEAR *npwTDBHead;
+ extern WORD NEAR *npwTDBCur;
+ extern DWORD NEAR *npdwSelTableStart;
+ extern WORD NEAR *npwSelTableLen;
+ extern WORD wNotifyInstalled;
+ extern NOTIFYSTRUCT NEAR *npNotifyHead;
+ extern WORD wIntInstalled;
+ extern INTERRUPT NEAR *npIntHead;
+ extern FARPROC lpfnGetUserLocalObjType;
+ extern FARPROC lpfnFatalExitHook;
+ extern FARPROC PASCAL lpfnPV;
+ extern FARPROC lpfnNotifyHook;
+ extern FARPROC lpfnGetFreeSystemResources;
+ extern FARPROC lpfntimeGetTime;
+ extern LPFNUSUD lpfnUserSeeUserDo;
+ extern WORD wSignalInstalled;
+ extern SIGNAL NEAR *npSignalHead;
+ extern NOTIFYSTRUCT NEAR* npNotifyNext;
+ extern WORD wLRUCount;
+
+/* ----- Private function prototypes ----- */
+
+ void PASCAL KernelType(void);
+
+ DWORD PASCAL Walk386First(
+ WORD wFlags);
+
+ WORD PASCAL Walk386Count(
+ WORD wFlags);
+
+ void PASCAL Walk386(
+ DWORD dwBlock,
+ GLOBALENTRY FAR *lpGlobal,
+ WORD wFlags);
+
+ DWORD PASCAL Walk386Handle(
+ HANDLE hBlock);
+
+ WORD PASCAL WalkLoc386Count(
+ HANDLE hHeap);
+
+ HANDLE PASCAL WalkLoc386First(
+ HANDLE hHeap);
+
+ void PASCAL WalkLoc386(
+ WORD wBlock,
+ LOCALENTRY FAR *lpLocal,
+ HANDLE hHeap);
+
+ DWORD PASCAL Walk286First(
+ WORD wFlags);
+
+ WORD PASCAL Walk286Count(
+ WORD wFlags);
+
+ void PASCAL Walk286(
+ DWORD dwBlock,
+ GLOBALENTRY FAR *lpGlobal,
+ WORD wFlags);
+
+ DWORD PASCAL Walk286Handle(
+ HANDLE hBlock);
+
+ WORD PASCAL WalkLoc286Count(
+ HANDLE hHeap);
+
+ HANDLE PASCAL WalkLoc286First(
+ HANDLE hHeap);
+
+ void PASCAL WalkLoc286(
+ WORD wBlock,
+ LOCALENTRY FAR *lpLocal,
+ HANDLE hHeap);
+
+ BOOL PASCAL TaskInfo(
+ TASKENTRY FAR *lpTask,
+ WORD wBlock);
+
+ WORD PASCAL StackFrameFirst(
+ STACKTRACEENTRY FAR *lpStack,
+ HANDLE hTDB);
+
+ BOOL PASCAL StackFrameNext(
+ STACKTRACEENTRY FAR *lpStack);
+
+ HANDLE PASCAL UserGdiDGROUP(
+ HANDLE hModule);
+
+ DWORD PASCAL UserGdiSpace(
+ HANDLE hData);
+
+ WORD PASCAL HelperVerifySeg(
+ WORD wSeg,
+ WORD wcb);
+
+ WORD PASCAL HelperHandleToSel(
+ HANDLE h);
+
+ void PASCAL HelperGlobalType(
+ GLOBALENTRY FAR *lpGlobal);
+
+ WORD PASCAL HelperGrabSelector(void);
+
+ void PASCAL HelperReleaseSelector(
+ WORD wSelector);
+
+ void PASCAL UserGdiType(
+ LOCALENTRY FAR *lpLocal);
+
+ BOOL PASCAL NotifyInit(void);
+
+ void PASCAL NotifyUnInit(void);
+
+ BOOL PASCAL NotifyIsHooked(
+ HANDLE hTask);
+
+ BOOL PASCAL InterruptInit(void);
+
+ void PASCAL InterruptUnInit(void);
+
+ BOOL PASCAL InterruptIsHooked(
+ HANDLE hTask);
+
+ BOOL PASCAL SignalRegister(
+ HANDLE hTask);
+
+ BOOL PASCAL SignalUnRegister(
+ HANDLE hTask);
+
+ void FAR PASCAL HelperSignalProc(void);
+
+ DWORD PASCAL HelperSetSignalProc(
+ HANDLE hTask,
+ DWORD lpfn);
+
+ BOOL PASCAL ClassInfo(
+ CLASSENTRY FAR *lpClass,
+ WORD wOffset);
+
+ DWORD PASCAL HelperSegLen(
+ WORD wSeg);
+
+#endif
diff --git a/private/mvdm/wow16/toolhelp/toolpriv.inc b/private/mvdm/wow16/toolhelp/toolpriv.inc
new file mode 100644
index 000000000..1001cfd99
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/toolpriv.inc
@@ -0,0 +1,112 @@
+;**************************************************************************
+;* TOOLPRIV.INC
+;*
+;* Private assembly-language include file for modules assembled as a
+;* part of TOOLHELP.DLL.
+;*
+;**************************************************************************
+
+;** CMACROS.INC variables for correct assembly
+DOS5 = 1
+PMODE = 1
+?WIN = 0
+?PLM = 1
+
+.286p
+
+ INCLUDE CMACROS.INC
+ INCLUDE TOOLHELP.INC
+
+externA __WinFlags
+
+;** TOOLHELP global variables
+?PLM = 0
+externW segKernel
+externW wLibInstalled
+externW hMaster
+externW wTHFlags
+externW npwExeHead
+externW npwTDBHead
+externW npwTDBCur
+externW hUserHeap
+externW hGDIHeap
+externW npdwSelTableStart
+externW npwSelTableLen
+externW wNotifyInstalled
+externW npNotifyHead
+externW wIntInstalled
+externW npIntHead
+externD lpfnGetUserLocalObjType
+externD lpfnFatalExitHook
+externD lpfnUserSeeUserDo
+externD lpfnNotifyHook
+externD lpfnGetFreeSystemResources
+externD lpfntimeGetTime;
+externW wSel
+externW wSignalInstalled
+externW npSignalHead
+externW npNotifyNext
+externW wLRUCount
+?PLM = 1
+
+;** Symbols
+TRUE = 1
+FALSE = 0
+
+KERNEL_286 EQU 1
+KERNEL_386 EQU 2
+
+FAULT_ACTIVE EQU 2
+
+NUM_EXCEP EQU 3
+
+;** wTHFlag values
+TH_KERNEL_286 EQU 1
+TH_KERNEL_386 EQU 2
+TH_WIN30 EQU 4
+TH_WIN30STDMODE EQU 8 ;THWIN30STDMODE set if TH_WIN30 & Std mode
+TH_GOODPTRACEHOOK EQU 16
+TH_GOTOLDPTRACE EQU 32
+
+;** Notification values
+NI_INCHAR EQU 01h
+NI_OUTSTR EQU 12h
+NI_LOADSEG EQU 50h
+NI_FREESEG EQU 52h
+NI_STARTTASK EQU 59h
+NI_EXITCALL EQU 62h
+NI_LOADDLL EQU 64h
+NI_DELMODULE EQU 65h
+NI_TASKOUT EQU 0dh
+NI_TASKIN EQU 0eh
+NI_CTLALTSYSRQ EQU 63h
+NI_LOGERROR EQU 66h
+NI_LOGPARAMERROR EQU 67h
+
+;** Structures
+
+NOTIFYSTRUCT STRUC
+ns_pNext DW ?
+ns_hTask DW ?
+ns_lpfn DD ?
+ns_wFlags DW ?
+NOTIFYSTRUCT ENDS
+
+INTERRUPT STRUC
+i_pNext DW ?
+i_hTask DW ?
+i_lpfn DD ?
+INTERRUPT ENDS
+
+SIGNAL STRUC
+si_pNext DW ?
+si_hTask DW ?
+si_lpfn DD ?
+si_lpfnOld DD ?
+SIGNAL ENDS
+
+;** Macros
+PubLabel MACRO PLabel
+ labelNP PLabel
+ PUBLIC PLabel
+ENDM
diff --git a/private/mvdm/wow16/toolhelp/usergdi1.c b/private/mvdm/wow16/toolhelp/usergdi1.c
new file mode 100644
index 000000000..05aac84ce
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/usergdi1.c
@@ -0,0 +1,77 @@
+/**************************************************************************
+ * USERGDI1.C
+ *
+ * Returns information about USER.EXE and GDI.EXE
+ *
+ **************************************************************************/
+
+#include "toolpriv.h"
+
+/* SystemHeapInfo
+ * Returns information about USER's and GDI's heaps
+ */
+
+BOOL TOOLHELPAPI SystemHeapInfo(
+ SYSHEAPINFO FAR* lpSysHeap)
+{
+ MODULEENTRY ModuleEntry;
+#ifndef WOW
+ DWORD dw;
+ WORD wFreeK;
+ WORD wMaxHeapK;
+#endif
+
+ /* Check the structure version number and pointer */
+ if (!wLibInstalled || !lpSysHeap ||
+ lpSysHeap->dwSize != sizeof (SYSHEAPINFO))
+ return FALSE;
+
+ /* Find the user data segment */
+ ModuleEntry.dwSize = sizeof (MODULEENTRY);
+ lpSysHeap->hUserSegment =
+ UserGdiDGROUP(ModuleFindName(&ModuleEntry, "USER"));
+ lpSysHeap->hGDISegment =
+ UserGdiDGROUP(ModuleFindName(&ModuleEntry, "GDI"));
+
+#ifndef WOW
+ /* We get the information about the heap percentages differently in
+ * 3.0 and 3.1
+ */
+ if ((wTHFlags & TH_WIN30) || !lpfnGetFreeSystemResources)
+ {
+ /* Get the space information about USER's heap */
+ dw = UserGdiSpace(lpSysHeap->hUserSegment);
+ wFreeK = LOWORD(dw) / 1024;
+ wMaxHeapK = HIWORD(dw) / 1024;
+ if (wMaxHeapK)
+ lpSysHeap->wUserFreePercent = wFreeK * 100 / wMaxHeapK;
+ else
+ lpSysHeap->wUserFreePercent = 0;
+
+ /* Get the space information about GDI's heap */
+ dw = UserGdiSpace(lpSysHeap->hGDISegment);
+ wFreeK = LOWORD(dw) / 1024;
+ wMaxHeapK = HIWORD(dw) / 1024;
+ if (wMaxHeapK)
+ lpSysHeap->wGDIFreePercent = wFreeK * 100 / wMaxHeapK;
+ else
+ lpSysHeap->wGDIFreePercent = 0;
+ }
+
+ /* Get the information from USER in 3.1 */
+ else
+ {
+ lpSysHeap->wUserFreePercent =
+ (*(WORD (FAR PASCAL *)(WORD))lpfnGetFreeSystemResources)(2);
+ lpSysHeap->wGDIFreePercent =
+ (*(WORD (FAR PASCAL *)(WORD))lpfnGetFreeSystemResources)(1);
+ }
+#else
+
+ lpSysHeap->wUserFreePercent = GetFreeSystemResources(GFSR_USERRESOURCES);
+ lpSysHeap->wGDIFreePercent = GetFreeSystemResources(GFSR_GDIRESOURCES);
+
+#endif
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow16/toolhelp/usergdi2.asm b/private/mvdm/wow16/toolhelp/usergdi2.asm
new file mode 100644
index 000000000..35d72aba6
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/usergdi2.asm
@@ -0,0 +1,209 @@
+;***************************************************************************
+;* USERGDI2.ASM
+;*
+;* Assembly routines used in computing heap space remaining for
+;* USER, GDI, and any other heaps.
+;*
+;***************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+SWAPPRO = 0
+PMODE32 = 0
+PMODE = 1
+ INCLUDE WINKERN.INC
+ INCLUDE NEWEXE.INC
+
+;** This slimy thing is from GDIOBJ.INC and is subtracted from the
+;** object type nunbers only in 3.1
+LT_GDI_BASE EQU ('G' or ('O' * 256)) - 1
+
+;** External functions
+
+externNP HelperVerifyLocHeap
+externNP HelperHandleToSel
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+ assumes DS,DATA
+
+.286p
+
+; UserGdiDGROUP
+; Returns a handle to the DGROUP segment for a given module
+;
+; HANDLE UserGdiDGROUP(
+; HANDLE hModule)
+
+cProc UserGdiDGROUP, <PUBLIC,NEAR>, <di,si>
+ parmW hModule
+cBegin
+ mov ax,hModule ;Get the handle
+ cCall HelperHandleToSel, <ax> ;Convert to a selector
+ mov es,ax ;Point with ES for this
+ xor ax,ax ;Prepare to return NULL
+ cmp es:[ne_magic],NEMAGIC ;Make sure we have a module database
+ jnz UGD_End ;It isn't so get out
+ mov bx,es:[ne_pautodata] ;Point to the segment table entry
+ mov ax,es:[bx].ns_handle ;Get the handle from the table
+ cCall HelperHandleToSel, <ax> ;Convert to a selector for return
+UGD_End:
+cEnd
+
+
+; UserGdiSpace
+; This function was stolen from KERNEL where it is used to compute
+; the space remaining in the USER and GDI heaps. It actually works
+; on any local heap.
+;
+; DWORD UserGdiSpace(
+; HANDLE hData)
+; HIWORD of return is maximum size of heap (64K less statics, etc.)
+; LOWORD of return is space remaining on heap
+
+cProc UserGdiSpace, <PUBLIC,NEAR>, <di,si,ds>
+ parmW hData
+cBegin
+ ;** Count the free space in this heap. First: Is this heap valid?
+ mov ax,hData ;Get the heap selector
+ cCall HelperVerifyLocHeap ;Call the verify routine
+ mov ax,0 ;In case we jump -- set error
+ mov dx,0 ; Use MOV to not mess up carry
+ jc UGS_Exit ;No valid local heap!!
+
+ ;** Loop through all local blocks, adding free space
+ cCall HelperHandleToSel, <hData> ;Convert to selector
+ mov ds,ax ;Point to the segment
+ mov di,ds:[6] ;Get pHeapInfo
+ mov di,[di].hi_first ;First arena header
+ mov di,[di].la_free_next ;First free block
+UGS_Loop:
+ add ax,[di].la_size ;Add in size of this block
+ sub ax,SIZE LocalArenaFree ;Less block overhead
+ mov si,[di].la_free_next ;Get next free block
+ or si,si ;NULL?
+ jz UGS_Break ;Yes, say we're done
+ cmp si,di ;Last block? (points to self)
+ mov di,si ;Save for next time around
+ jnz UGS_Loop ;Not last block so loop some more
+UGS_Break:
+
+ ;** We have the size of the local heap
+ mov si,ax ;Save the size
+ mov cx,ds ;Get the selector in a non-segreg
+ lsl ax,cx ;Get the size of the segment
+ neg ax ;64K - segment size
+ add ax,si ;Add in the free holes in the heap
+ mov dx,-1 ;Compute the max size of heap
+ sub dx,ds:[6] ; which is 64K less statics
+
+UGS_Exit:
+
+cEnd
+
+
+; UserGdiType
+;
+; Tries to compute the type of local heap block if possible
+; Prototype:
+;
+; void PASCAL UserGdiType(
+; LOCALENTRY FAR *lpLocal)
+
+cProc UserGdiType, <PUBLIC,NEAR>, <si,di>
+ parmD lpLocal
+cBegin
+ ;** Get info from our static variables
+ mov ax,_DATA ;Get the variables first
+ mov ds,ax ;Point to our DS
+ mov bx,hUserHeap ;BX=User's heap block
+ mov cx,hGDIHeap ;CX=GDI's heap block
+
+ ;** See if we can do anything with this heap
+ les si,lpLocal ;Get a pointer to the structure
+ mov es:[si].le_wType,LT_NORMAL ;In case we don't find anything
+ mov ax,es:[si].le_hHeap ;Get the heap pointer
+ cmp ax,bx ;User's heap?
+ jnz UGT_10 ;Nope, try next
+ cCall GetUserType ;Call routine to get user type
+ jmp SHORT UGT_End ;Get out
+
+UGT_10: cmp ax,cx ;GDI's heap?
+ jnz UGT_End ;Nope, can't do anything with it
+ cCall GetGDIType ;Call routine to get GDI type
+
+UGT_End:
+
+cEnd
+
+
+;** Internal helper functions
+
+; GetUserType
+;
+; Uses the tags in debug USER.EXE to give information on what type
+; block is pointed to by the current LOCALENTRY structure.
+; Caller: ES:SI points to the parameter LOCALENTRY structure
+; Return: LOCALENTRY structure is correctly updated
+
+cProc GetUserType, <NEAR>
+cBegin
+ ;** Make sure we have a function to call
+ cmp WORD PTR lpfnGetUserLocalObjType + 2,0 ;Selector zero?
+ je GUT_End ;Yes
+
+ ;** Call USER to get the type
+ push es ;Save ES
+ mov bx,es:[si].le_wAddress ;Get the block address
+ sub bx, la_fixedsize ;The USER call needs the arena header
+ test es:[si].le_wFlags, LF_MOVEABLE ;Moveable block?
+ jz @F ;No
+ sub bx, (SIZE LocalArena) - la_fixedsize ;Moveable arena bigger
+@@: push bx ;Parameter arena handle
+ call DWORD PTR lpfnGetUserLocalObjType ;Call the function
+ pop es
+ xor ah,ah ;Clear the upper byte
+ mov es:[si].le_wType,ax ;Save the type
+GUT_End:
+cEnd
+
+
+; GetGDIType
+;
+; Uses the tags in debug GDI.EXE to give information on what type
+; block is pointed to by the current LOCALENTRY structure.
+; Caller: ES:SI points to the parameter LOCALENTRY structure
+; Return: LOCALENTRY structure is correctly updated
+
+cProc GetGDIType, <NEAR>, <ds>
+cBegin
+ ;** All fixed blocks are unknown to us
+ test es:[si].le_wFlags,LF_FIXED ;Is it fixed?
+ jz GGT_10 ;Nope
+ jmp SHORT GGT_End ;Yes, get out
+GGT_10:
+
+ ;** Prepare to find the type
+ cCall HelperHandleToSel,es:[si].le_hHeap ;Get the selector value
+ mov cx,wTHFlags ;Save for when we trash DS
+ mov ds,ax ;Get the heap pointer
+ mov di,es:[si].le_wAddress ;Get the block pointer
+
+ ;** Get the type word
+ mov ax,[di+2] ;Get the type word from the heap
+ and ax,05fffh ;Mask out the stock object flag
+ test cx,TH_WIN30 ;In 3.0?
+ jnz CGT_Win30 ;Yes
+ sub ax,LT_GDI_BASE ;No, subtract type tag base
+CGT_Win30:
+ cmp ax,LT_GDI_MAX ;Recognizable type code?
+ ja GGT_End ;No, get out
+ mov es:[si].le_wType,ax ;Save in the structure
+
+GGT_End:
+cEnd
+
+sEnd
+ END
+
diff --git a/private/mvdm/wow16/toolhelp/walk286.asm b/private/mvdm/wow16/toolhelp/walk286.asm
new file mode 100644
index 000000000..ef358449b
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/walk286.asm
@@ -0,0 +1,562 @@
+;**************************************************************************
+;* walk286.ASM
+;*
+;* Assembly support code for the KRNL286 global heap routines
+;* for TOOLHELP.DLL
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+PMODE32 = 0
+PMODE = 1
+SWAPPRO = 0
+ INCLUDE WINKERN.INC
+
+;** External functions
+externNP HelperVerifySeg
+externNP HelperHandleToSel
+externNP HelperPDBtoTDB
+externNP HelperSegLen
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+
+; Walk286Count
+;
+; Returns the number of blocks in the given list
+
+cProc Walk286Count, <PUBLIC,NEAR>, <di>
+ parmW wFlags
+cBegin
+ mov es,hMaster ;Segment of master block
+ mov ax,wFlags ;Get the flag value
+ shr ax,1 ;Check for GLOBAL_LRU
+ jc W2C_LRU ;Bit set, must be LRU
+ shr ax,1 ;Check for GLOBAL_FREE
+ jc W2C_Free ;Must be free
+ ;Must be GLOBAL_ALL
+
+ ;** Get total object count
+ mov ax,es:[hi_count] ;Get heap count
+ inc ax ;Bump to include first sentinel
+ jmp SHORT W2C_End ;Get out
+
+ ;** Get LRU object count
+W2C_LRU:
+ mov ax,es:[gi_lrucount] ;Get the LRU count
+ jmp SHORT W2C_End ;Get out
+
+ ;** Get Free list object count
+W2C_Free:
+ mov ax,es:[gi_free_count] ;Get free count
+ jmp SHORT W2C_End ;Get out
+
+ ;** Return the result in AX
+W2C_End:
+
+cEnd
+
+; Walk286First
+;
+; Returns a handle to the first block in the 286 global heap.
+
+cProc Walk286First, <PUBLIC,NEAR>, <di>
+ parmW wFlags
+cBegin
+ mov es,hMaster ;Segment of master block
+ mov ax,wFlags ;Get the flag value
+ shr ax,1 ;Check for GLOBAL_LRU
+ jc W2F_LRU ;Bit set, must be LRU
+ shr ax,1 ;Check for GLOBAL_FREE
+ jc W2F_Free ;Must be free
+ ;Must be GLOBAL_ALL
+
+ ;** Get first object in complete heap (wFlags == GLOBAL_ALL)
+ mov ax,es:[hi_first] ;Get handle of first arena header
+ jmp SHORT W2F_End ;Get out
+
+ ;** Get first object in LRU list
+W2F_LRU:
+ mov ax,es:[gi_lrucount] ;Get the number of objects
+ or ax,ax ;Are there any objects?
+ je W2F_End ;No, return NULL
+ inc es:[gi_lrulock] ;No LRU sweeping for awhile
+ inc wLRUCount ;Keep a count of this
+ mov ax,es:[gi_lruchain] ;Get a pointer to the first item
+ jmp SHORT W2F_End ;Done
+
+ ;** Get first object in Free list
+W2F_Free:
+ mov ax,es:[gi_free_count] ;Get the number of objects
+ or ax,ax ;Are there any objects?
+ jz W2F_End ;No, return NULL
+ mov es,es:[hi_first] ;Get the first object
+ mov ax,es:[ga_freenext] ;Skip to the first free block
+ ;Fall through to the return
+
+ ;** Return the result in AX (return DX = NULL)
+W2F_End:
+ xor dx,dx ;Clear high word
+cEnd
+
+
+; Walk286
+;
+; Takes a pointer to a block and returns a GLOBALENTRY structure
+; full of information about the block. If the block pointer is
+; NULL, looks at the first block. The last field in the GLOBALENTRY
+; structure is used to chain to the next block and is thus used to walk
+; the heap.
+
+cProc Walk286, <PUBLIC,NEAR>, <di,si,ds>
+ parmD dwBlock
+ parmD lpGlobal
+ parmW wFlags
+cBegin
+ ;** Set up to build public structure
+ mov es,WORD PTR dwBlock ;Point to this block
+ lds si,lpGlobal ;Point to the GLOBALENTRY structure
+
+ ;** Fill public structure
+ mov ax,es:[ga_handle] ;Get the handle of the block
+ mov [si].ge_hBlock,ax ;Put in public structure
+ mov ax,es:[ga_size] ;Get the size of the block (LOWORD)
+ mov dx,ax ;Clear high word
+ shl ax,4 ;Left shift DX:AX by 4
+ shr dx,16-4
+ mov WORD PTR [si].ge_dwBlockSize,ax ;Put in public structure
+ mov WORD PTR [si].ge_dwBlockSize + 2,dx ;Put in public structure
+ mov ax,es:[ga_owner] ;Owning task of block
+ mov [si].ge_hOwner,ax ;Put in public structure
+ xor ah,ah ;No upper BYTE
+ mov al,es:[ga_count] ;Lock count (moveable segments)
+ mov [si].ge_wcLock,ax ;Put in public structure
+ mov WORD PTR [si].ge_wcPageLock,0 ;Zero the page lock count
+ mov al,es:[ga_flags] ;BYTE of flags
+ xor ah,ah ;No upper BYTE
+ mov [si].ge_wFlags,ax ;Put in public structure
+ mov ax,es:[ga_next] ;Put next pointer in structure
+ mov WORD PTR [si].ge_dwNext,ax
+ mov WORD PTR [si].ge_dwNext + 2,0
+
+ ;** Use DPMI to compute linear address of selector
+ mov ax,6 ;Get Segment Base Address
+ mov bx,es ;Get the segment value
+ int 31h ;Call DPMI
+ mov WORD PTR [si].ge_dwAddress,dx ;Save linear address
+ mov WORD PTR [si].ge_dwAddress + 2,cx
+
+ ;** If this is a data segment, get local heap information
+ mov ax,[si].ge_hBlock ;Get the handle
+ cCall Walk286VerifyLocHeap
+ mov [si].ge_wHeapPresent,TRUE ;Flag that there's a heap
+ jnc W2_10 ;There really is no heap
+ mov [si].ge_wHeapPresent,FALSE ;Flag that there's no heap
+W2_10:
+
+ ;** If the owner is a PDB, translate this to the TDB
+ mov bx,[si].ge_hOwner ;Get the owner
+ cCall HelperHandleToSel, <bx> ;Translate to selector
+ mov bx,ax ;Get the selector in BX
+ cCall HelperVerifySeg, <ax,2> ;Must be two bytes long
+ or ax,ax ;Is it?
+ jz W2_15 ;No.
+ push es ;Save ES for later
+ mov es,bx ;Point to possible PDB block
+ cmp es:[0],20CDh ;Int 20h is first word of PDB
+ jnz W2_12 ;Nope, don't mess with this
+ mov ax,bx ;Pass parameter in AX
+ cCall HelperPDBtoTDB ;Get the corresponding TDB
+ or ax,ax ;Was one found?
+ jz W2_11 ;No.
+ mov [si].ge_hOwner,ax ;Make the owner the TDB instead
+W2_11: or [si].ge_wFlags,GF_PDB_OWNER ;Flag that a PDB owned block
+W2_12: pop es ;Restore ES
+W2_15:
+
+ ;** Check for this being the last item in both lists
+ mov ax,es ;Get the current pointer
+ cmp ax,es:[ga_next] ;See if we're at the end
+ jne W2_20 ;No
+ mov WORD PTR [si].ge_dwNext,0 ;NULL the next pointer
+ mov WORD PTR [si].ge_dwNext + 2,0
+W2_20: mov ax,es ;Get current pointer
+ mov cx,wFlags ;Get the flags back
+ cCall NextLRU286 ;Get next LRU list pointer or 0
+ mov WORD PTR [si].ge_dwNextAlt,ax
+ mov WORD PTR [si].ge_dwNextAlt + 2,0
+
+W2_End:
+cEnd
+
+
+; Walk286Handle
+;
+; Finds an arena pointer given a block handle
+
+cProc Walk286Handle, <PUBLIC,NEAR>, <di,si,ds>
+ parmW hBlock
+cBegin
+ mov ax,hBlock ;Get the block handle
+ cCall HelperHandleToSel, <ax> ;Convert to selector
+ cCall SelToArena286 ;Get the arena pointer
+ jnc W2H_10 ;Must be OK
+ xor ax,ax ;Return a 0L
+ xor dx,dx
+ jmp SHORT W2H_End ;Error in conversion, get out
+W2H_10: mov ax,bx ;Get the low word
+ xor dx,dx ;No high word
+W2H_End:
+cEnd
+
+
+; WalkLoc286Count
+;
+; Returns the number of blocks in the given local heap
+
+cProc WalkLoc286Count, <PUBLIC,NEAR>, <di>
+ parmW hHeap
+cBegin
+ ;** Verify that it has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk286VerifyLocHeap ;Verify it
+ jnc LC_10 ;It's OK
+ xor ax,ax ;No heap
+ jmp SHORT LC_End ;Get out
+LC_10:
+
+ ;** Point to the block
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ mov bx,es:[6] ;Get a pointer to the HeapInfo struct
+
+ ;** Get the number of blocks
+ mov ax,es:[bx].hi_count ;Get the count
+LC_End:
+cEnd
+
+
+; WalkLoc286First
+;
+; Returns a handle to the first block in the 286 global heap.
+
+cProc WalkLoc286First, <PUBLIC,NEAR>, <di>
+ parmW hHeap
+cBegin
+ ;** Verify that the given global block has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk286VerifyLocHeap ;Verify it
+ jnc LF_10 ;It's OK
+ xor ax,ax ;No heap
+ jmp SHORT LF_End ;Get out
+LF_10:
+
+ ;** Point to the global block
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ mov bx,es:[6] ;Get a pointer to the HeapInfo struct
+
+ ;** Get the first block and return it
+ mov ax,WORD PTR es:[bx].hi_first ;Get the first block
+LF_End:
+cEnd
+
+
+; WalkLoc286
+;
+; Takes a pointer to a block and returns a GLOBALENTRY structure
+; full of information about the block. If the block pointer is
+; NULL, looks at the first block. The last field in the GLOBALENTRY
+; structure is used to chain to the next block and is thus used to walk
+; the heap.
+
+cProc WalkLoc286, <PUBLIC,NEAR>, <di,si,ds>
+ parmW wBlock
+ parmD lpLocal
+ parmW hHeap
+cBegin
+ ;** Verify that it has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk286VerifyLocHeap ;Verify it
+ jnc LW_10 ;It's OK
+ jmp LW_End ;Get out
+LW_10:
+
+ ;** Get variables from the TOOLHELP DGROUP
+ mov ax,_DATA ;Get the variables first
+ mov ds,ax ;Point to our DS
+ mov bx,hUserHeap ;BX=User's heap block
+ mov cx,hGDIHeap ;CX=GDI's heap block
+
+ ;** Point to the heap
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ lds di,lpLocal ;Point to the LOCALENTRY structure
+ mov [di].le_wHeapType,NORMAL_HEAP ;In case we don't match below...
+ cmp bx,hHeap ;User's heap?
+ jnz LW_3 ;No
+ mov [di].le_wHeapType,USER_HEAP ;Yes
+ jmp SHORT LW_5 ;Skip on
+LW_3: cmp cx,hHeap ;GDI's heap?
+ jnz LW_5 ;No
+ mov [di].le_wHeapType,GDI_HEAP ;Yes
+LW_5:
+ mov si,wBlock ;Get the address of the block
+
+ ;** Get information about the given block
+ mov bx,es:[si].la_handle ;Get the handle
+ mov [di].le_hHandle,bx ;Save in the public structure
+ mov ax,si ;Get block address
+ add ax,la_fixedsize ;Skip fixed size local arena
+ mov [di].le_wAddress,ax ;Save the block address
+ mov ax,es:[si].la_next ;Get the address of the next block
+ mov [di].le_wNext,ax ;Save the next pointer
+ sub ax,si ;Compute the size
+ sub ax,SIZE LocalArena ;Don't count arena size
+ mov [di].le_wSize,ax ;Save in public structure
+ mov ax,es:[si].la_prev ;Get the flags
+ and ax,3 ;Mask out all but flags
+ mov [di].le_wFlags,ax ;Save in structure
+
+ ;** Moveable arenas are bigger and have a lock count to get
+ test al,LA_MOVEABLE ;Block has a handle iff it's moveable
+ jz SHORT LW_NoHandle ;No handle info
+ sub [di].le_wSize, (SIZE LocalArena) - la_fixedsize
+ add [di].le_wAddress, (SIZE LocalArena) - la_fixedsize
+ xor ah,ah ;Clear upper word
+ mov al,es:[bx].lhe_count ;Get lock count
+ mov [di].le_wcLock,ax ;Save it
+ jmp SHORT LW_20 ;Skip no handle info
+LW_NoHandle:
+ mov ax, [di].le_wAddress ;Handle of fixed block is real offset
+ mov [di].le_hHandle, ax
+ mov [di].le_wcLock,0
+LW_20:
+ ;** See if it's the end
+ cmp [di].le_wNext,si ;Loop pointer?
+ jnz LW_End ;Nope
+ mov [di].le_wNext,0 ;Set a zero pointer
+LW_End:
+cEnd
+
+
+; Walk286VerifyLocHeap
+;
+; Verifies that the given global block points to a data segment
+; with a local heap.
+;
+; Call:
+; AX = Block handle or selector
+; Return:
+; Carry flag set iff NOT a local heap segment
+;
+; Destroys all registers except AX, ESI, EDI, DS, and ES
+
+cProc Walk286VerifyLocHeap, <PUBLIC,NEAR>, <es,si,di>
+cBegin
+ ;** Convert to a handle
+ cCall HelperHandleToSel, <ax>
+
+ ;** Verify the selector
+ push ax ;Save the parameter
+ mov bx,SIZE LocalInfo ;Get the size
+ cCall HelperVerifySeg, <ax,bx> ;Check the selector
+ or ax,ax ;Is it valid?
+ pop ax ;Restore parameter
+ jnz VLH_SelOK ;Yes.
+ stc ;Set error flag
+ jmp SHORT VLH_End ;Get out
+VLH_SelOK:
+
+ ;** Check data segment to see if it has a local heap
+ mov es,ax ;Point to the local block with ES
+ cCall HelperSegLen, <ax> ;Get the length of the heap
+ or ax,ax ;Check for error
+ jz VLH_NoHeap ;Get out on error
+ mov cx,ax ;Use CX for comparisons
+ cmp cx,8 ;At least 8 bytes long?
+ ja VLH_10 ;Yes
+ stc ;No -- set error flag and get out
+ jmp SHORT VLH_End
+VLH_10: mov bx,es:[6] ;Get offset to HeapInfo struct
+ or bx,bx ;If NULL, no local heap
+ jz VLH_NoHeap ;Get out
+ sub cx,bx ;See if HeapInfo is beyond segment
+ jbe VLH_NoHeap
+ sub cx,li_sig + 2 ;Compare against last structure mem
+ jbe VLH_NoHeap
+ cmp es:[bx].li_sig,LOCALHEAP_SIG ;Make sure the signature matches
+ jne VLH_NoHeap ;Doesn't match
+ clc ;Must be a heap!
+ jmp SHORT VLH_End
+
+VLH_NoHeap:
+ stc ;Set error flag
+
+VLH_End:
+cEnd
+
+
+;** Private helper functions
+
+; SelToArena286
+;
+; Finds the arena entry for the given selector or handle.
+; The arena entry is stored 16 bytes before the block in linear
+; address space.
+;
+; Caller: AX = Selector
+; Returns: BX = Arena entry
+; Trashes everything except segment registers and AX
+; Carry set on error
+
+cProc SelToArena286, <NEAR>, <es,ds,ax>
+cBegin
+ ;** Convert to a handle
+ cCall HelperHandleToSel, <ax>
+
+ ;** Verify selector
+ push ax ;Save the parameter
+ cCall HelperVerifySeg, <ax,1> ;Check the selector
+ or ax,ax ;Is it valid?
+ pop ax ;Restore parameter
+ jnz STA_SelOK ;Must be
+ stc ;Nope. Set error flag and exit
+ jmp SHORT STA_End
+STA_SelOK:
+ ;** If this is Win30StdMode, we're in the old KRNL286 which used
+ ;* an arcane method of finding the arena. If that's the case
+ ;** here, handle it seperately.
+ mov bx,_DATA ;Get the static data segment
+ mov ds,bx
+ test wTHFlags,TH_WIN30STDMODE ;3.0 Std Mode?
+ jnz STA_OldKRNL286 ;Yes
+ mov bx,segKernel ;Get the KERNEL variable segment
+ mov es,bx
+ mov bx,npwSelTableLen ;Get the pointer
+ mov dx,es:[bx] ;Get the selector table length
+ mov bx,npdwSelTableStart ;Get the start of the sel table
+ mov bx,es:[bx] ;Get the linear offset (32 bits)
+ mov es,hMaster ;Point to the arena table
+ and al,not 7 ;Clear the RPL bits for table lookup
+ shr ax,2 ;Convert to WORD offset
+ cmp ax,dx ;Check to see if off the end of table
+ jb STA_InTable ;It's in the table
+ stc ;Set error flag--not in table
+ jmp SHORT STA_End ;Get out
+STA_InTable:
+ add bx,ax ;Add the selector offset
+ mov bx,es:[bx] ;Do the sel table indirection
+ clc ;BX now points to arena segment
+ jmp SHORT STA_End ;Skip the old stuff
+
+STA_OldKRNL286:
+ mov bx,ax ;Selector in BX
+ mov ax,6 ;DPMI function 6, Get Seg Base Addr
+ int 31h ;Call DPMI
+ sub dx,10h ;Move back 16 bytes
+ sbb cx,0 ; (this is a linear address)
+ mov ax,7 ;DPMI function 7, Set Seg Base Addr
+ mov bx,wSel ;Use our roving selector
+ int 31h ;Call DPMI
+ mov ax,8 ;DPMI function 8, Set Seg Limit
+ xor cx,cx ;No upper byte
+ mov dx,16 ;Just 16 bytes
+ int 31h ;Call DPMI
+ mov ax,9 ;DPMI function 9, Set Access Rights
+ mov cl,0b2h ;Desired rights byte
+ int 31h ;Call DPMI
+ ;Return arena segment pointer in BX
+STA_End:
+cEnd
+
+
+; NextLRU286
+;
+; Checks the given arena table pointer to see if it is the last
+; arena entry on the list.
+; Uses a grungy method that is necessitated because of the
+; unterminated linked lists we're dealing with here. The count
+; stored is the only reliable method for finding the end. So, to
+; provide random access to blocks in the heap, the heap is searched
+; from top to bottom to find the block and see if it is the last
+; one. If it is or if it is not on the given list, returns a 0
+; pointer to the next item.
+;
+; If this search is for the entire global heap, we do not get the
+; LRU link, but return NULL in AX. This speeds this up alot!
+;
+; Caller: AX = Arena table pointer
+; CX = GLOBAL_ALL, GLOBAL_FREE, or GLOBAL_LRU
+; Return: AX = Next arena table pointer or 0 if no more
+; Trashes all registers except segment registers and SI,DI
+
+cProc NextLRU286, <NEAR,PUBLIC>, <es,ds,si,di>
+cBegin
+ ;** Decode the flags
+ mov bx,_DATA ;Get the static data segment
+ mov ds,bx ;Point with DS
+ mov es,hMaster ;Segment of master block
+ cmp cx,GLOBAL_ALL ;Don't do this on full heap search
+ jne @F
+ jmp SHORT NL_BadList ;Just return NULL for this one
+@@: cmp cx,GLOBAL_FREE ;Check free list?
+ je NL_Free ;Yes
+
+ ;** Loop through LRU list until we find this item
+NL_LRU:
+ mov si,ax ;Save the selector in AX
+ mov cx,es:[gi_lrucount] ;Get the number of objects
+ jcxz NL_Bad ;No object so return end
+ dec cx ;We don't want to find the last one
+ jcxz NL_Bad ;1 object so return end
+ mov ds,es:[gi_lruchain] ;Get a pointer to the first item
+NL_LRULoop:
+ mov ax,ds ;Get in AX so we can compare
+ cmp si,ax ;Match yet?
+ je NL_ReturnNext ;Found it, return next item
+ mov ds,ds:[ga_lrunext] ;Not found yet, get the next one
+ loop NL_LRULoop ;Loop through all items
+
+ ;** Unlock the LRU sweeping
+NL_Bad: dec es:[gi_lrulock] ;OK to LRU sweep now
+ mov ax, _DATA ;Point to TH Data seg
+ mov ds, ax
+ dec wLRUCount ;Keep a count of this
+ jmp SHORT NL_BadList ;Not here either. Get out
+
+ ;** Loop through free list until we find this item
+NL_Free:
+ mov si,ax ;Save the selector in SI
+ mov cx,es:[gi_free_count] ;Get the number of objects
+ jcxz NL_BadList ;0 objects so return end
+ dec cx ;We don't want to find the last one
+ jcxz NL_BadList ;1 object so return end
+ mov ds,es:[hi_first] ;Get a pointer to the first item
+NL_FreeLoop:
+ mov ds,ds:[ga_lrunext] ;Not found yet, get the next one
+ mov ax,ds ;Get the pointer so we can compare it
+ cmp ax,si ;Is this the one?
+ je NL_ReturnNext ;Yes, return it
+ loop NL_FreeLoop ;Loop through all items
+ jmp SHORT NL_BadList ;Not here either. Get out
+
+NL_ReturnNext:
+ mov ax,ds:[ga_lrunext] ;Return the next one
+ jmp SHORT NL_End ;Get out
+
+NL_BadList:
+ xor ax,ax ;Return zero for error
+
+NL_End:
+cEnd
+
+sEnd
+ END
+
diff --git a/private/mvdm/wow16/toolhelp/walk386.asm b/private/mvdm/wow16/toolhelp/walk386.asm
new file mode 100644
index 000000000..2be63562b
--- /dev/null
+++ b/private/mvdm/wow16/toolhelp/walk386.asm
@@ -0,0 +1,541 @@
+;**************************************************************************
+;* walk386.ASM
+;*
+;* Assembly support code for the KERNEL386 global heap routines
+;* for TOOLHELP.DLL
+;*
+;**************************************************************************
+
+ INCLUDE TOOLPRIV.INC
+
+PMODE32 = 1
+PMODE = 0
+SWAPPRO = 0
+ INCLUDE WINKERN.INC
+
+;** External functions
+externNP HelperVerifySeg
+externNP HelperHandleToSel
+externNP HelperPDBtoTDB
+externNP HelperSegLen
+
+;** Functions
+
+sBegin CODE
+ assumes CS,CODE
+.386p
+
+; Walk386Count
+;
+; Returns the number of blocks in the given list
+
+cProc Walk386Count, <PUBLIC,NEAR>, <di>
+ parmW wFlags
+cBegin
+ mov es,hMaster ;Segment of master block
+ mov ax,wFlags ;Get the flag value
+ shr ax,1 ;Check for GLOBAL_LRU
+ jc SHORT W3C_LRU ;Bit set, must be LRU
+ shr ax,1 ;Check for GLOBAL_FREE
+ jc SHORT W3C_Free ;Must be free
+ ;Must be GLOBAL_ALL
+
+ ;** Get total object count
+ mov ax,es:[hi_count] ;Get heap count
+ inc ax ;Bump to include first sentinel
+ jmp SHORT W3C_End ;Get out
+
+ ;** Get LRU object count
+W3C_LRU:
+ mov ax,es:[gi_lrucount] ;Get the LRU count
+ jmp SHORT W3C_End ;Get out
+
+ ;** Get Free list object count
+W3C_Free:
+ mov ax,es:[gi_free_count] ;Get free count
+ jmp SHORT W3C_End ;Get out
+
+ ;** Return the result in AX
+W3C_End:
+
+cEnd
+
+; Walk386First
+;
+; Returns a handle to the first block in the 386 global heap.
+
+cProc Walk386First, <PUBLIC,NEAR>, <di>
+ parmW wFlags
+cBegin
+ mov es,hMaster ;Segment of master block
+ mov ax,wFlags ;Get the flag value
+ shr ax,1 ;Check for GLOBAL_LRU
+ jc SHORT W3F_LRU ;Bit set, must be LRU
+ shr ax,1 ;Check for GLOBAL_FREE
+ jc SHORT W3F_Free ;Must be free
+ ;Must be GLOBAL_ALL
+
+ ;** Get first object in complete heap (wFlags == GLOBAL_ALL)
+ mov edi,es:[phi_first] ;Get offset of first arena header
+ jmp SHORT W3F_End ;Get out
+
+ ;** Get first object in LRU list
+W3F_LRU:
+ xor edi,edi ;Zero upper word
+ mov di,es:[gi_lrucount] ;Get the number of objects
+ or di,di ;Are there any objects?
+ jz SHORT W3F_End ;No, return NULL
+ mov edi,es:[gi_lruchain] ;Get a pointer to the first item
+ jmp SHORT W3F_End ;Done
+
+ ;** Get first object in Free list
+W3F_Free:
+ xor edi,edi ;Zero upper word
+ mov di,es:[gi_free_count] ;Get the number of objects
+ or di,di ;Are there any objects?
+ jz SHORT W3F_End ;No, return NULL
+ mov edi,es:[phi_first] ;Get the first object
+ mov edi,es:[edi].pga_freenext ;Skip to the first free block
+ ;Fall through to the return
+
+ ;** Save the result in DX:AX for the return
+W3F_End:
+ mov ax,di ;Get the low word
+ shr edi,16 ;Get the high word out
+ mov dx,di ;Get the high word
+cEnd
+
+
+; Walk386
+;
+; Takes a pointer to a block and returns a GLOBALENTRY structure
+; full of information about the block. If the block pointer is
+; NULL, looks at the first block. The last field in the GLOBALENTRY
+; structure is used to chain to the next block and is thus used to walk
+; the heap.
+
+cProc Walk386, <PUBLIC,NEAR>, <di,si,ds>
+ parmD dwBlock
+ parmD lpGlobal
+ parmW wFlags
+cBegin
+ ;** Set up to build public structure
+ mov es,hMaster ;Get the correct segment
+ mov edi,dwBlock ;Point to this block
+ lds si,lpGlobal ;Point to the GLOBALENTRY structure
+
+ ;** Fill public structure
+ mov ax,es:[edi].pga_handle ;Get the handle of the block
+ mov [si].ge_hBlock,ax ;Put in public structure
+ mov eax,es:[edi].pga_address ;Get linear address of block
+ mov [si].ge_dwAddress,eax ;Put in public structure
+ mov eax,es:[edi].pga_size ;Get the size of the block
+ mov [si].ge_dwBlockSize,eax ;Put in public structure
+ mov ax,es:[edi].pga_owner ;Owning task of block
+ mov [si].ge_hOwner,ax ;Put in public structure
+ xor ah,ah
+ mov al,es:[edi].pga_count ;Lock count (moveable segments)
+ mov [si].ge_wcLock,ax ;Put in public structure
+ mov al,es:[edi].pga_pglock ;Page lock count
+ mov [si].ge_wcPageLock,ax ;Save in structure
+ mov al,es:[edi].pga_flags ;Word of flags
+ xor ah,ah
+ mov [si].ge_wFlags,ax ;Put in public structure
+ mov eax,es:[edi].pga_next ;Put next pointer in structure
+ mov [si].ge_dwNext,eax
+
+ ;** If this is a data segment, get local heap information
+ mov ax,[si].ge_hBlock ;Get the handle
+ cCall Walk386VerifyLocHeap
+ mov [si].ge_wHeapPresent,TRUE ;Flag that there's a heap
+ jnc SHORT W3_10 ;There really is no heap
+ mov [si].ge_wHeapPresent,FALSE ;Flag that there's no heap
+W3_10:
+
+ ;** If the owner is a PDB, translate this to the TDB
+ mov bx,[si].ge_hOwner ;Get the owner
+ cCall HelperHandleToSel, <bx> ;Translate to selector
+ mov bx,ax ;Get the selector in BX
+ cCall HelperVerifySeg, <ax,2> ;Must be two bytes long
+ or ax,ax ;Is it?
+ jz SHORT W3_15 ;No.
+ push es ;Save ES for later
+ mov es,bx ;Point to possible PDB block
+ cmp es:[0],20CDh ;Int 20h is first word of PDB
+ jnz SHORT W3_12 ;Nope, don't mess with this
+ mov ax,bx ;Pass parameter in AX
+ cCall HelperPDBtoTDB ;Get the corresponding TDB
+ or ax,ax ;Was one found?
+ jz SHORT W3_11 ;No.
+ mov [si].ge_hOwner,ax ;Make the owner the TDB instead
+W3_11: or [si].ge_wFlags,GF_PDB_OWNER ;Flag that a PDB owned block
+W3_12: pop es ;Restore ES
+W3_15:
+
+ ;** Check for this being the last item in both lists
+ cmp edi,es:[edi].pga_next ;See if we're at the end
+ jnz SHORT W3_20 ;No
+ mov [si].ge_dwNext,0 ;NULL the next pointer
+W3_20: mov eax,edi ;Get current pointer
+ mov cx,wFlags ;Get the flags back
+ cCall NextLRU386 ;Get next LRU list pointer or 0
+ mov [si].ge_dwNextAlt,eax ;Save it
+
+W3_End:
+cEnd
+
+
+; Walk386Handle
+;
+; Finds an arena pointer given a block handle
+
+cProc Walk386Handle, <PUBLIC,NEAR>, <di,si,ds>
+ parmW hBlock
+cBegin
+ mov ax,hBlock ;Get the block handle
+ cCall HelperHandleToSel, <ax> ;Convert to selector
+ cCall SelToArena386 ;Get the arena pointer
+ jnc SHORT W3H_10 ;Must be OK
+ xor ax,ax ;Return a 0L
+ xor dx,dx
+ jmp SHORT W3H_End ;Error in conversion, get out
+W3H_10: mov ax,bx ;Get the low word
+ shr ebx,16 ;Get the high word in DX
+ mov dx,bx
+W3H_End:
+cEnd
+
+
+; WalkLoc386Count
+;
+; Returns the number of blocks in the given local heap
+
+cProc WalkLoc386Count, <PUBLIC,NEAR>, <di>
+ parmW hHeap
+cBegin
+ ;** Verify that it has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk386VerifyLocHeap ;Verify it
+ jnc SHORT LC_10 ;It's OK
+ xor ax,ax ;No heap
+ jmp SHORT LC_End ;Get out
+LC_10:
+
+ ;** Point to the block
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ mov bx,es:[6] ;Get a pointer to the HeapInfo struct
+
+ ;** Get the number of blocks
+ mov ax,es:[bx].hi_count ;Get the count
+LC_End:
+cEnd
+
+
+; WalkLoc386First
+;
+; Returns a handle to the first block in the 386 global heap.
+
+cProc WalkLoc386First, <PUBLIC,NEAR>, <di>
+ parmW hHeap
+cBegin
+ ;** Verify that the given global block has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk386VerifyLocHeap ;Verify it
+ jnc SHORT LF_10 ;It's OK
+ xor ax,ax ;No heap
+ jmp SHORT LF_End ;Get out
+LF_10:
+
+ ;** Point to the global block
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ mov bx,es:[6] ;Get a pointer to the HeapInfo struct
+
+ ;** Get the first block and return it
+ mov ax,WORD PTR es:[bx].hi_first ;Get the first block
+LF_End:
+cEnd
+
+
+; WalkLoc386
+;
+; Takes a pointer to a block and returns a GLOBALENTRY structure
+; full of information about the block. If the block pointer is
+; NULL, looks at the first block. The last field in the GLOBALENTRY
+; structure is used to chain to the next block and is thus used to walk
+; the heap.
+
+cProc WalkLoc386, <PUBLIC,NEAR>, <di,si,ds>
+ parmW wBlock
+ parmD lpLocal
+ parmW hHeap
+cBegin
+ ;** Verify that it has a local heap
+ mov ax, hHeap ;Get the block
+ cCall Walk386VerifyLocHeap ;Verify it
+ jnc SHORT LW_10 ;It's OK
+ jmp LW_End ;Get out
+LW_10:
+
+ ;** Get variables from the TOOLHELP DGROUP
+ mov ax,_DATA ;Get the variables first
+ mov ds,ax ;Point to our DS
+ mov bx,hUserHeap ;BX=User's heap block
+ mov cx,hGDIHeap ;CX=GDI's heap block
+
+ ;** Point to the heap
+ mov ax,hHeap ;Get the heap block
+ cCall HelperHandleToSel, <ax> ;Convert it to a selector
+ mov es,ax ;Use ES to point to it
+ lds di,lpLocal ;Point to the LOCALENTRY structure
+ mov [di].le_wHeapType,NORMAL_HEAP ;In case we don't match below...
+ cmp bx,hHeap ;User's heap?
+ jnz SHORT W3_3 ;No
+ mov [di].le_wHeapType,USER_HEAP ;Yes
+ jmp SHORT W3_5 ;Skip on
+W3_3: cmp cx,hHeap ;GDI's heap?
+ jnz SHORT W3_5 ;No
+ mov [di].le_wHeapType,GDI_HEAP ;Yes
+W3_5:
+ mov si,wBlock ;Get the address of the block
+
+ ;** Get information about the given block
+ mov bx,es:[si].la_handle ;Get the handle
+ mov [di].le_hHandle,bx ;Save in the public structure
+ mov ax,si ;Get block address
+ add ax,la_fixedsize ;Skip fixed size local arena
+ mov [di].le_wAddress,ax ;Save the block address
+ mov ax,es:[si].la_next ;Get the address of the next block
+ mov [di].le_wNext,ax ;Save the next pointer
+ sub ax,si ;Compute the size
+ sub ax,la_fixedsize ;Size of fixed arena
+ mov [di].le_wSize,ax ;Save in public structure
+ mov ax,es:[si].la_prev ;Get the flags
+ and ax,3 ;Mask out all but flags
+ mov [di].le_wFlags,ax ;Save in structure
+
+ ;** Moveable arenas are bigger and have a lock count to get
+ test al,LA_MOVEABLE ;Block has a handle iff it's moveable
+ jz SHORT LW_NoHandle ;No handle info
+ sub [di].le_wSize, (SIZE LocalArena) - la_fixedsize
+ add [di].le_wAddress, (SIZE LocalArena) - la_fixedsize
+ xor ah,ah ;Clear upper word
+ mov al,es:[bx].lhe_count ;Get lock count
+ mov [di].le_wcLock,ax ;Save it
+ jmp SHORT LW_20 ;Skip no handle info
+LW_NoHandle:
+ mov ax, [di].le_wAddress ;Handle of fixed block is real offset
+ mov [di].le_hHandle, ax
+ mov [di].le_wcLock,0 ;No lock count either
+LW_20:
+ ;** See if it's the end
+ cmp [di].le_wNext,0 ;Check for NULL pointer just in case
+ jz SHORT LW_End ;It is so get out
+ cmp [di].le_wNext,si ;Loop pointer?
+ jnz SHORT LW_End ;Nope
+ mov [di].le_wNext,0 ;Set a zero pointer
+LW_End:
+cEnd
+
+
+; Walk386VerifyLocHeap
+;
+; Verifies that the given global block points to a data segment
+; with a local heap.
+;
+; Call:
+; AX = Block handle or selector
+; Return:
+; Carry flag set iff NOT a local heap segment
+;
+; Destroys all registers except AX, ESI, EDI, DS, and ES
+
+cProc Walk386VerifyLocHeap, <PUBLIC,NEAR>, <es>
+cBegin
+ push esi ;Save certain registers
+ push edi
+
+ ;** Convert to a selector
+ cCall HelperHandleToSel, <ax>
+
+ ;** Verify that the selector is long enough
+ push ax ;Save parameter
+ mov bx,SIZE LocalInfo
+ cCall HelperVerifySeg, <ax,bx> ;Check the selector
+ or ax,ax ;Is it valid?
+ pop ax ;Restore parameter
+ jnz SHORT VLH_SelOK ;Yes
+ stc ;Set error flag
+ jmp SHORT VLH_End ;Get out
+VLH_SelOK:
+
+ ;** Check data segment to see if it has a local heap
+ mov es,ax ;Point to the local block with ES
+ cCall HelperSegLen, <ax> ;Get the length of the heap
+ movzx ecx,dx ;ECX gets the length
+ shl ecx,16 ;Put high word in high word of EAX
+ mov cx,ax ;Get the low word
+ cmp ecx,8 ;At least 8 bytes long?
+ ja SHORT VLH_10 ;Yes
+ stc ;No -- set error flag and get out
+ jmp SHORT VLH_End
+VLH_10: xor ebx,ebx ;Clear high word
+ mov bx,es:[6] ;Get offset to HeapInfo struct
+ or bx,bx ;If NULL, no local heap
+ jz SHORT VLH_NoHeap ;Get out
+ sub ecx,ebx ;See if HeapInfo is beyond segment
+ jbe SHORT VLH_NoHeap
+ sub ecx,li_sig + 2 ;Compare against last structure mem
+ jbe SHORT VLH_NoHeap
+ cmp es:[bx].li_sig,LOCALHEAP_SIG ;Make sure the signature matches
+ jne SHORT VLH_NoHeap ;Doesn't match
+ clc ;Must be a heap!
+ jmp SHORT VLH_End
+
+VLH_NoHeap:
+ stc ;Set error flag
+
+VLH_End:
+ pop edi
+ pop esi
+cEnd
+
+
+;** Private helper functions
+
+; SelToArena386
+;
+; Finds the arena entry for the given selector or handle.
+; Uses the selector table which is located just after the arena table.
+; Since this is a large segment, use 32 bit offsets into it.
+; The selector-to-arena mapping table is simply an array of arena
+; offsets indexed by the (selector number >> 3) * 4 [DWORD offsets].
+;
+; Caller: AX = Selector
+; Returns: DX:EBX = Arena entry
+; Trashes everything except segment registers and AX
+; Carry set on error
+
+cProc SelToArena386, <NEAR,PUBLIC>, <es,ds,ax>
+cBegin
+ ;** Convert to a selector
+ cCall HelperHandleToSel, <ax>
+
+ ;** Verify selector
+ push ax ;Save parameter
+ cCall HelperVerifySeg, <ax,1> ;Check the selector
+ or ax,ax ;Is it valid?
+ pop ax ;Restore parameter
+ jnz SHORT STA_SelOK ;Must be
+ stc ;Nope. Set error flag and exit
+ jmp SHORT STA_End
+STA_SelOK:
+ mov bx,_DATA ;Get the static data segment
+ mov ds,bx
+ mov bx,segKernel ;Get the KERNEL variable segment
+ mov es,bx
+ mov bx,npwSelTableLen ;Get the pointer
+ mov dx,es:[bx] ;Get the selector table length
+ mov bx,npdwSelTableStart ;Get the start of the sel table
+ mov ebx,es:[bx] ;Get the linear offset (32 bits)
+ mov es,hMaster ;Point to the arena table
+ and al,not 7 ;Clear the RPL bits for table lookup
+ shr ax,1 ;Convert to DWORD offset
+ cmp ax,dx ;Check to see if off the end of table
+ jb SHORT STA_InTable ;It's in the table
+ stc ;Set error flag--not in table
+ jmp SHORT STA_End ;Get out
+STA_InTable:
+ movzx eax,ax ;Convert the offset to 32 bits
+ add ebx,eax ;Add the selector offset
+ mov ebx,es:[ebx] ;Do the sel table indirection
+ mov dx,hMaster ;DX points to the arena segment
+ clc ;No error; return OK
+STA_End:
+cEnd
+
+
+; NextLRU386
+;
+; Checks the given arena table pointer to see if it is the last
+; arena entry on the list.
+; Uses a grungy method that is necessitated because of the
+; unterminated linked lists we're dealing with here. The count
+; stored is the only reliable method for finding the end. So, to
+; provide random access to blocks in the heap, the heap is searched
+; from top to bottom to find the block and see if it is the last
+; one. If it is or if it is not on the given list, returns a 0
+; pointer to the next item.
+;
+; If this search is for the entire global heap, we do not get the
+; LRU link, but return NULL in EAX. This speeds this up alot!
+;
+; Caller: EAX = Arena table pointer
+; CX = GLOBAL_ALL, GLOBAL_FREE, or GLOBAL_LRU
+; Return: EAX = Next arena table pointer or 0 if no more
+; Trashes all registers except segment registers and ESI,EDI
+
+cProc NextLRU386, <NEAR,PUBLIC>, <es,ds>
+cBegin
+ push esi
+ push edi
+
+ mov bx,_DATA ;Get the static data segment
+ mov ds,bx ;Point with DS
+ mov es,hMaster ;Segment of master block
+ cmp cx,GLOBAL_ALL ;If doing entire heap, don't do this!
+ je SHORT NL_BadList ;Must not be entire heap
+ shr cx,1 ;Check for GLOBAL_LRU
+ jc SHORT NL_LRU ;Bit set, must be LRU
+ shr cx,1 ;Check for GLOBAL_FREE
+ jc SHORT NL_Free ;Must be free
+ ;Must be GLOBAL_ALL
+
+ ;** Decide which list the block is in then hand off
+ cmp es:[eax].pga_owner,0 ;If the owner is zero, it's free
+ jz SHORT NL_Free ;Handle this as if on free list
+ ;Otherwise, might be on LRU list
+
+ ;** Loop through LRU list until we find this item
+NL_LRU:
+ mov cx,es:[gi_lrucount] ;Get the number of objects
+ jcxz NL_Bad ;No object so return end
+ dec cx ;We don't want to find the last one
+ jcxz NL_Bad ;1 object so return end
+ mov edi,es:[gi_lruchain] ;Get a pointer to the first item
+NL_LRULoop:
+ cmp edi,eax ;Match yet?
+ jz SHORT NL_ReturnNext ;Found it, return next item
+ mov edi,es:[edi].pga_lrunext ;Not found yet, get the next one
+ loop NL_LRULoop ;Loop through all items
+NL_Bad: jmp SHORT NL_BadList ;Not here either. Get out
+
+ ;** Loop through free list until we find this item
+NL_Free:
+ mov cx,es:[gi_free_count] ;Get the number of objects
+ jcxz NL_BadList ;1 object so return end
+ mov edi,es:[phi_first] ;Get a pointer to the first item
+NL_FreeLoop:
+ mov edi,es:[edi].pga_lrunext ;Not found yet, get the next one
+ cmp edi,eax ;Match yet?
+ jz SHORT NL_ReturnNext ;Found it, return next item
+ loop NL_FreeLoop ;Loop through all items
+ jmp SHORT NL_BadList ;Not here either. Get out
+
+NL_ReturnNext:
+ mov eax,es:[edi].pga_lrunext ;Return the next one
+ jmp SHORT NL_End ;Get out
+
+NL_BadList:
+ xor eax,eax ;Return zero for error
+
+NL_End:
+ pop edi
+ pop esi
+cEnd
+
+sEnd
+ END
diff --git a/private/mvdm/wow16/user/combcom.h b/private/mvdm/wow16/user/combcom.h
new file mode 100644
index 000000000..c8dbdf022
--- /dev/null
+++ b/private/mvdm/wow16/user/combcom.h
@@ -0,0 +1,101 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * COMBCOM.H
+ *
+ * History:
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16
+--*/
+
+/*
+ * combcom.h - Common include file for combo boxs. This include file is used
+ * in the combo box code, the single line edit control code, listbox code, and
+ * static control code.
+ */
+
+/* ID numbers (hMenu) for the child controls in the combo box */
+#define CBLISTBOXID 1000
+#define CBEDITID 1001
+#define CBBUTTONID 1002
+
+typedef struct tagCBox
+ {
+ HWND hwnd; /* Window for the combo box */
+ HWND hwndParent; /* Parent of the combo box */
+ RECT comboDownrc; /* Rectangle used for the "dropped"
+ (listbox visible) combo box */
+ RECT editrc; /* Rectangle for the edit control/static text
+ area */
+ RECT buttonrc; /* Rectangle where the dropdown button is */
+ HWND editHwnd; /* Edit control window handle */
+ HWND listboxHwnd; /* List box control window handle */
+ WORD CBoxStyle; /* Combo box style */
+ WORD OwnerDraw; /* Owner draw combo box if nonzero. value
+ * specifies either fixed or varheight
+ */
+ WORD fFocus:1; /* Combo box has focus? */
+ WORD fNoRedraw:1; /* Stop drawing? */
+ WORD fNoEdit:1; /* True if editing is not allowed in the edit
+ * window.
+ */
+ WORD fButtonDownClicked:1;/* Was the popdown button just clicked and
+ mouse still down? */
+ WORD fButtonInverted:1; /* Is the dropdown button in an inverted state?
+ */
+ WORD fLBoxVisible:1; /* Is list box visible? (dropped down?) */
+ WORD fKeyboardSelInListBox:1; /* Is the user keyboarding through the
+ * listbox. So that we don't hide the
+ * listbox on selchanges caused by the
+ * user keyboard through it but we do
+ * hide it if the mouse causes the
+ * selchange.
+ */
+ WORD fExtendedUI:1; /* Are we doing TandyT's UI changes on this
+ * combo box?
+ */
+ HANDLE hFont; /* Font for the combo box */
+ LONG styleSave; /* Save the style bits when creating window.
+ * Needed because we strip off some bits and
+ * pass them on to the listbox or edit box.
+ */
+ } CBOX;
+
+typedef CBOX NEAR *PCBOX;
+typedef CBOX FAR *LPCBOX;
+
+/*
+ * For CBOX.cBoxType field, we define the following combo box styles. These
+ * numbers are the same as the CBS_ style codes as defined in windows.h.
+ */
+#define SSIMPLE 1
+#define SDROPDOWN 2
+#define SDROPDOWNLIST 3
+
+/* Owner draw types */
+#define OWNERDRAWFIXED 1
+#define OWNERDRAWVAR 2
+
+/*
+ * Special styles for static controls, edit controls & listboxes so that we
+ * can do combo box specific stuff in their wnd procs.
+ */
+#define ES_COMBOBOX 0x0200L
+#define LBS_COMBOBOX 0x8000L
+
+/* Special internal combo box messages */
+#define CBEC_SETCOMBOFOCUS CB_MSGMAX+1
+#define CBEC_KILLCOMBOFOCUS CB_MSGMAX+2
+
+
+/* Special messages for listboxes so give combo box support */
+#define LBCB_CARETON LB_MSGMAX+1
+#define LBCB_CARETOFF LB_MSGMAX+2
+
+/* Common Procedures */
+VOID FAR PASCAL CBUpdateEditWindow(register PCBOX);
+VOID FAR PASCAL CBHideListBoxWindow(register PCBOX pcbox, BOOL fNotifyParent);
+VOID FAR PASCAL CBShowListBoxWindow(register PCBOX);
diff --git a/private/mvdm/wow16/user/comdev.c b/private/mvdm/wow16/user/comdev.c
new file mode 100644
index 000000000..332807f13
--- /dev/null
+++ b/private/mvdm/wow16/user/comdev.c
@@ -0,0 +1,1134 @@
+/****************************************************************************/
+/* */
+/* COMDEV.C - */
+/* */
+/* Windows Communication Routines */
+/* */
+/****************************************************************************/
+
+/*************************************************************************
+**
+** Windows Communication Layer
+**
+** This is the library interface layer for the Communications Device Driver.
+** The driver presents an interface between windows based applications and the
+** communications hardware.
+**
+** /-----------------------------\
+** / Windows \
+** \ Application Program /
+** \-----------------------------/
+** | Windows Interface |
+** +-----------------------------+
+** | OEM Dependant LowLevel Code |
+** /-----------------------------\
+** / Machine Layer \
+** \ Communications Hardware /
+** \-----------------------------/
+**
+*************************************************************************/
+#define USECOMM
+#include "user.h"
+#include "comdev.h" /* Device driver structure defs */
+#include "comdevi.h" /* Device driver internal defs */
+
+HANDLE FAR GlobalDOSAlloc(LONG h);
+void FAR GlobalDOSFree(HANDLE h);
+
+#define length(string) lstrlen((char FAR *)string)
+#define UPPERCASE(x) MyToUpper(x)
+
+
+LPSTR NEAR PASCAL field(LPSTR, LPSTR);
+short getid(LPSTR);
+char FAR *GetMem(WORD);
+cinfo *cinfoPtr(int);
+void FreeMem(LPSTR);
+char _fastcall NEAR MyToUpper(char);
+
+/* Array of information for each communications device that we support. */
+cinfo rgcinfo[DEVMAX] = {0}; /* Device additional info table */
+
+/* Strings used for determining device characteristics. */
+
+static char CODESEG COMbuf[] = "COM1:9600,E,7,1";
+static char CODESEG LPTbuf[] = "LPT1";
+static char CODESEG AUXbuf[] = "AUX1"; /* AUX will map to COM1 */
+static char CODESEG PRNbuf[] = "PRN1"; /* PRN will map to LPT1 */
+#define CONFIGINDEX 5 /* Index to 9600,... in COMbuf */
+
+/*************************************************************************
+** OpenComm - open a communication device
+**
+** Synopsis:
+** short OpenComm(pszComName, cbInQue, cbOutQue)
+** FAR char *pszComName;
+** ushort cbInQue;
+** ushort cbOutQue;
+**
+** Description:
+** OpenComm opens a comunication device an associates a com handle with it. The
+** communication device is initialized to a default configuration. The csetcom
+** function call, below, should be used to initialized the device to alternate
+** values.
+**
+** OpenComm returns an id which is used in subsequent calls to reference the
+** communication device, or a negative error initialization error code.
+**
+** pszComName points to a string which contains "COMn" where "n" is allowed to
+** range from 1 to the number of COMM devices supported by the OEM. cbInQue
+** and cbOutQue reflect the receive and transmit queue sizes, respectively.
+** These queues are allocated at open time, deallocated at close time, and are
+** used by the interrupt driven transmit/receive software.
+**
+** pszComName may also point to a string which contains "LPTn" where "n" is
+** allowed to range from 1 to the number of LPT devices supported by the OEM.
+** cbInQue and cbOutQue are ignored for LPT devices. LPT devices are not
+** interrupt driven.
+**
+*************************************************************************/
+
+int API IOpenComm(LPSTR pszComName, WORD cbInQue, WORD cbOutQue)
+
+{
+ short cidCur; /* ID of device */
+ DCB dcbNew; /* Temp DCB */
+ short ierr; /* Return code from inicom */
+ register cinfo *pcinfo; /* pointer to information block */
+ register qdb *pqdbNew; /* pointer to queue information */
+
+
+ if ((cidCur = getid(pszComName)) == -1) /* if not recognized, return */
+ return(IE_BADID); /* error to caller */
+ pcinfo = cinfoPtr(cidCur); /* form pointer to info block */
+
+ if (pcinfo->fOpen) /* if device already open */
+ return(IE_OPEN); /* return error to caller */
+
+ if (pcinfo->fReservedHardware)
+ /* if device locked for some reason return error to caller ex locked for
+ * use by mouse.
+ */
+ return(IE_HARDWARE);
+
+ /* do nothing if device is LPTn. */
+ if (!(cidCur & LPTx))
+ {
+ if( (cbInQue == 0) && (cbOutQue == 0) ) /* if Queue length's zero, */
+ return(IE_MEMORY); /* return memory error right away, */
+ /* so a buildDCB isn't done...
+ this is a common method of
+ finding if the comm port is
+ already opened or not...
+ wanted to make it fast */
+
+
+ if (lstrlen(pszComName) < 4 || BuildCommDCB(pszComName, &dcbNew) == -1)
+ {
+ if (BuildCommDCB(COMbuf, &dcbNew) == -1)
+ return(IE_DEFAULT);
+ }
+
+ pqdbNew = &pcinfo->qdbCur; /* form pointer to qdb */
+ if ((pqdbNew->pqRx = GetMem(cbInQue)) == (char FAR *)NULL)
+ return(IE_MEMORY); /* no room for Rx queue */
+
+ if ((pqdbNew->pqTx = GetMem(cbOutQue)) == (char FAR *)NULL)
+ {
+ FreeMem(pqdbNew->pqRx); /* no room for Tx queue */
+ return(IE_MEMORY);
+ }
+
+ pqdbNew->cbqRx = cbInQue;
+ pqdbNew->cbqTx = cbOutQue;
+ setque(cidCur,(qdb FAR *)pqdbNew); /* init the queue's as well */
+ }
+
+ dcbNew.Id = (char)cidCur; /* set device ID in dcb */
+ ierr = inicom((DCB FAR *)&dcbNew); /* attempt to init */
+ if (ierr)
+ {
+ if (!(cidCur & LPTx)) /* if a comm device */
+ {
+ FreeMem(pqdbNew->pqRx); /* free Tx queue */
+ FreeMem(pqdbNew->pqTx); /* free Rx queue */
+ }
+
+ return(ierr); /* return error code */
+ }
+
+ pcinfo->fOpen = TRUE; /* indicate device open */
+ pcinfo->hTask = GetCurrentTask();
+ return(cidCur); /* all's well, return dev id */
+}
+
+#ifdef DISABLE
+int FAR PASCAL OpenCommFromDCB(LPDCB pdcb, WORD cbInQue, WORD cbOutQue)
+
+{
+ short cidCur; /* ID of device */
+ short ierr; /* Return code from inicom */
+ register cinfo *pcinfo; /* pointer to information block */
+ register qdb *pqdbNew; /* pointer to queue information */
+
+
+ cidCur = (WORD)pdcb->Id & 0x00FF;
+
+ if ((cidCur & LPTxMask) > ((cidCur & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(IE_BADID); /* check cid for validity */
+
+ pcinfo = cinfoPtr(cidCur); /* form pointer to info block */
+
+ if (pcinfo->fOpen) /* if device already open */
+ return(IE_OPEN); /* return error to caller */
+
+ if (!(cidCur & LPTx)) /* device is LPTn */
+ {
+ if( (cbInQue == 0) && (cbOutQue == 0) ) /* if Queue length's zero, */
+ return(IE_MEMORY); /* return memory error right away, */
+ /* so a buildDCB isn't done... this
+ * is a common method of finding if
+ * the comm port is already opened
+ * or not... wanted to make it fast
+ */
+
+ pqdbNew = &pcinfo->qdbCur; /* form pointer to qdb */
+ if ((pqdbNew->pqRx = GetMem(cbInQue)) == (char FAR *)NULL)
+ return(IE_MEMORY); /* no room for Rx queue */
+
+ if ((pqdbNew->pqTx = GetMem(cbOutQue)) == (char FAR *)NULL)
+ {
+ FreeMem(pqdbNew->pqRx); /* no room for Tx queue */
+ return(IE_MEMORY);
+ }
+
+ pqdbNew->cbqRx = cbInQue;
+ pqdbNew->cbqTx = cbOutQue;
+ setque(cidCur,(qdb FAR *)pqdbNew); /* init the queue's as well */
+ }
+
+ ierr = inicom(pdcb); /* attempt to init */
+ if (ierr)
+ {
+ if (!(cidCur & LPTx)) /* if a comm device */
+ {
+ FreeMem(pqdbNew->pqRx); /* free Tx queue */
+ FreeMem(pqdbNew->pqTx); /* free Rx queue */
+ }
+
+ return(ierr); /* return error code */
+ }
+
+ pcinfo->fOpen = TRUE; /* indicate device open */
+ pcinfo->hTask = GetCurrentTask();
+ return(cidCur); /* all's well, return dev id */
+}
+#endif
+
+
+/*************************************************************************
+** SetCommState - set communciation device configuration
+**
+** Synopsis:
+** int SetCommState(pdcb)
+** LPDCB pdcb;
+**
+** Description:
+** pdcb points to an initialized Device Control Block for a device which
+** has been openned. The referenced device, as defined by the dcb's id field,
+** is set to the state as defined by the dcb. SetCommState returns 0 on
+** success, or a negative initialization error code if an error occurred. Note
+** that this will reinitialize all hardware and control as defined in the dcb,
+** but will not empty transmit or receive queues.
+**
+*************************************************************************/
+
+int API ISetCommState(LPDCB pdcb)
+{
+ if (cinfoPtr(pdcb->Id)->fOpen == 0)
+ return(IE_NOPEN); /* File must be open first */
+
+ return(setcom(pdcb));
+}
+
+
+
+/*************************************************************************
+** GetCommState - return current dcb values
+**
+** Synopsis:
+** int GetCommState(cid,pdcb)
+** WORD cid;
+** LPDCB *pdcb;
+**
+** Description:
+** The dcb pointed to by pdcb is updated to reflect the current dcb in use
+** for the device referenced by cid. Returns 0 on success, -1 on illegal
+** handle or IE_OPEN if port has not been opened yet.
+**
+*************************************************************************/
+
+int API IGetCommState(register int cid, LPDCB pdcb)
+
+{
+ LPDCB pdcbSrc;
+ register int i;
+
+ if (cinfoPtr(cid)->fOpen == 0) /* File must be open first */
+ return(IE_NOPEN);
+
+ if ( (pdcbSrc = getdcb(cid)) ) /* pointer to dcb for device */
+ {
+ i = sizeof(DCB);
+ while (i--)
+ *((char FAR *)pdcb)++ = *((char FAR *)pdcbSrc)++;
+
+ return(0);
+ }
+ else
+ return(-1);
+}
+
+
+/*************************************************************************
+** ReadComm - read characters from communication device
+**
+** Synopsis:
+** int ReadComm(cid, pbuf, size)
+** WORD cid;
+** LPSTR *pbuf;
+** int size;
+**
+** Description:
+** ReadComm reads size characters into pbuf and returns the number of characters
+** actually read. If the return value equals size bytes there may exist
+** additional characters to read. The return count will be less if the number
+** of characters present in the receive queue is less. If the return value is
+** 0 then no characters were present.
+**
+** If the return value is negative, then an error was also detected, and an
+** error code can be retrieved from GetCommError. The absolute value of the return
+** value is the number of characters read. Note that this implies that if
+** there are no characters to be read, then no error status can be returned,
+** and GetCommError should be used to read the status.
+**
+*************************************************************************/
+
+int API IReadComm(int cid, LPSTR pbuf, int size)
+
+{
+ register int cbT;
+ int ch;
+
+ cid &= 0xff; /* get "pure" device ID */
+ if (size == 0) /* Empty read */
+ return(0);
+ if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(0); /* check cid for validity */
+
+ if (cinfoPtr(cid)->fOpen == 0)
+ return(0); /* can't assume valid dcb... */
+
+ cbT = 0;
+ if (cinfoPtr(cid)->fchUnget) /* if there's a backed-up char */
+ {
+ cinfoPtr(cid)->fchUnget = FALSE; /* return backed up char */
+ *pbuf++ = cinfoPtr(cid)->chUnget; /* and update transfer count */
+ cbT++;
+ }
+ /*note. reccom returns -2 if no */
+ /*data available, - 1 if error */
+ ch = 0;
+
+ if (SELECTOROF(lpCommReadString) == NULL)
+ {
+ while (cbT < size) /* up to size characters */
+ {
+ if ((ch = reccom(cid)) < 0) /* stop when no char available */
+ break; /* or error */
+ *pbuf++ = (char)ch; /* place character in users buf */
+ cbT++; /* and update transfer count */
+ }
+ }
+ else
+ {
+ ch = 0;
+ cbT = lpCommReadString(cid, pbuf, size);
+ }
+
+ return(ch == -1 ? -cbT : cbT);
+}
+
+
+/*************************************************************************
+** UngetCommChar - push a character back onto receive queue.
+**
+** Synopsis:
+** int UngetCommChar(cid,ch)
+** WORD cid;
+** char ch;
+**
+** Description:
+** Allows an application to "back-up" one character in the receive character
+** stream by placing a character back into the receive stream. This character
+** is then the first character returned by the next call to ReadComm. UngetCommChar may
+** only be called once between calls to ReadComm. Returns 0 on success, -1 if
+** illegal id, or unable to back-up.
+**
+*************************************************************************/
+
+int API IUngetCommChar(int cid, char ch)
+
+{
+ cid &= 0xFF; /* get "pure" device ID */
+ if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(0); /* check cid for validity */
+
+ if (cinfoPtr(cid)->fchUnget) /* have we already backed up 1 */
+ return(-1);
+
+ if (cinfoPtr(cid)->fOpen == 0) /* can't assume valid dcb... */
+ return(-1);
+
+ cinfoPtr(cid)->fchUnget = TRUE; /* set flag indicating backed-up*/
+ cinfoPtr(cid)->chUnget = ch; /* and save the character */
+
+ return(0);
+}
+
+
+/*************************************************************************
+** WriteComm - write characters to communication device
+**
+** Synopsis:
+** int WriteComm(cid, pbuf, size)
+** int cid;
+** LPSTR *pbuf;
+** int size;
+**
+** Description:
+** WriteComm will write size character to the communication device. The byte
+** count written is returned on success, negative byte count on error. GetCommError
+** can be used to retrieve any error code.
+**
+*************************************************************************/
+
+int API IWriteComm(int cid, LPSTR pbuf, int size)
+
+{
+ int cbT;
+
+ cid &= 0xFF; /* get "pure" device ID */
+
+ if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(0); /* check cid for validity */
+ /*return zero if not valid */
+ if (cinfoPtr(cid)->fOpen == 0) /* verify port has been opened */
+ return(-1);
+
+ cbT = 0;
+
+ if (SELECTOROF(lpCommWriteString) == NULL)
+ {
+ while (size--)
+ {
+ if (sndcom(cid,*pbuf++)) /* transmit character */
+ return(-cbT); /* return if error */
+
+ cbT++;
+ }
+ }
+ else
+ {
+ cbT = lpCommWriteString(cid, pbuf, size);
+ if (cbT < size)
+ {
+ /* For consistency, if we couldn't transmit all the characters we
+ * were asked to, return the negative of the number actually
+ * transmitted.
+ */
+ cbT = -cbT;
+ }
+ }
+
+ return(cbT);
+}
+
+
+/*************************************************************************
+** CloseComm - close communication device
+**
+** Synopsis:
+** int CloseComm(cid)
+** ushort cid;
+**
+** Description:
+** closes the communication device and dealloctes any buffers. Returns 0 on
+** success, -1 on error.
+**
+*************************************************************************/
+
+int API ICloseComm(int cid)
+
+{
+ register cinfo *pcinfo;
+ WORD retval;
+
+ cid &= 0xFF; /* get "pure" device ID */
+ if ((cid & LPTxMask) > ((cid & LPTx) ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(-1); /* return error, cid not valid */
+
+ if ((pcinfo = cinfoPtr(cid))->fOpen==0) /* verify port opened ... */
+ return(-1); /* return error, port not open */
+
+ retval = trmcom(cid); /* terminate the device */
+ if (retval == 0x8000) /* if invalid ID */
+ return(-1); /* return error code */
+
+ pcinfo->fOpen = FALSE; /* indicate not open */
+
+ if (!(cid & LPTx))
+ {
+ FreeMem(pcinfo->qdbCur.pqRx); /* Free Rx buffer */
+ FreeMem(pcinfo->qdbCur.pqTx); /* Free Rx buffer */
+ }
+
+ return(retval); /* 0 if OK, -2 if queue trashed */
+}
+
+
+/*************************************************************************
+** GetCommError - return device status
+**
+** Synopsis:
+** short GetCommError(cid,pstat)
+** ushort cid;
+** stat FAR *pstat;
+**
+** Description:
+** GetCommError returns the most recent error code for the referenced device, or -1
+** for an illegal handle. In addition, if pstat is non-zero, GetCommError also
+** updates the status record it points to.
+**
+*************************************************************************/
+
+int API IGetCommError(int cid, COMSTAT FAR *pstat)
+
+{
+ register WORD st;
+
+ cid &= 0xFF;
+ st = stacom(cid,pstat);
+ if ((st != 0x8000) && pstat && (cinfoPtr(cid)->fchUnget))
+ pstat->cbInQue++;
+
+ return(st);
+}
+
+
+void FAR PASCAL SP_GPFaultCommCleanup(HANDLE hTask)
+/* effects: When the given task gp faults, we check if it had any comm ports
+ * opened and we close them.
+ */
+{
+ register int i;
+
+ for (i=0; i<DEVMAX; i++) /* check all devices */
+ if (rgcinfo[i].fOpen && rgcinfo[i].hTask == hTask)
+ /* if device is open */
+ CloseComm(i); /* close it */
+}
+
+
+
+/*************************************************************************
+** BuildCommDCB - Parse a string into a dcb.
+**
+** Synopsis:
+** short BuildCommDCB(pszDef,pdcb)
+** char FAR *pszDef;
+** DCB FAR *pdcb;
+**
+** Description:
+** Parses a passed string and fills appropriate fields in a dcb, the address
+** off which is also passed. The string conforms to that of a DOS MODE
+** command for COMn. For example: "COM1:9600,N,7,1". Returns 0 on success,
+** -1 on error.
+**
+*************************************************************************/
+
+int API IBuildCommDCB(LPSTR pszDef, LPDCB pdcb)
+
+{
+ register int i;
+ register int tempid;
+ char c;
+ char szT[80]; /* buffer in which to put things*/
+
+
+ LFillStruct((LPSTR)pdcb, sizeof(DCB), 0);/* zero the dcb since probably on
+ * app's stack
+ */
+
+ pszDef = field(pszDef,(char FAR *)szT); /* Get first token */
+ if ((tempid=getid((char FAR *)szT))==-1)/* Get ID of device */
+ return(-1); /* Unknown device */
+
+ pdcb->Id = (char)tempid; /* we have a device id */
+
+
+ if (tempid & LPTx) /* if a LPTx port, then let the */
+ return(0); /* rest default to whatever */
+
+
+ pszDef = field(pszDef,(char FAR *)szT); /* next field */
+ if (length(szT) < 2)
+ return(-1); /* must be at least two chars */
+
+
+ i = (szT[0] << 8) | szT[1]; /* cheap and sleazy mapping */
+ switch (i) /* based on first 2 chars */
+ {
+ case 0x3131:
+ i = 110;
+ break;
+
+ case 0x3135:
+ i = 150;
+ break;
+
+ case 0x3330:
+ i = 300;
+ break;
+
+ case 0x3630:
+ i = 600;
+ break;
+
+ case 0x3132:
+ i = 1200;
+ break;
+
+ case 0x3234:
+ i = 2400;
+ break;
+
+ case 0x3438:
+ i = 4800;
+ break;
+
+ case 0x3936:
+ i = 9600;
+ break;
+
+ case 0x3139:
+ i = 19200;
+ break;
+
+ case 0x3338: /* handle 38400 baud in BuildCommDCB() */
+ i = 38400;
+ break;
+
+ default:
+ return(-1);
+ }
+
+ pdcb->BaudRate = i;
+ pdcb->XonLim = 10; /* Set these up always. */
+ pdcb->XoffLim = 10; /* Set these up always. */
+ pdcb->fBinary = 1; /* Set these up always. */
+ pdcb->XonChar = 0x11; /* Ctrl-Q */
+ pdcb->XoffChar = 0x13; /* Ctrl-S */
+
+ if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
+ return(0);
+
+ switch (szT[0])
+ {
+ case 0:
+ case 'E':
+ c = EVENPARITY;
+ break;
+
+ case 'O':
+ c = ODDPARITY;
+ break;
+
+ case 'N':
+ c = NOPARITY;
+ break;
+
+ case 'M':
+ c = MARKPARITY;
+ break;
+
+ case 'S':
+ c = SPACEPARITY;
+ break;
+
+ default:
+ return(-1);
+ }
+ pdcb->Parity = c;
+
+ if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
+ return(0);
+
+ switch (szT[0])
+ {
+ case 0:
+ case '7':
+ c = 7;
+ break;
+
+ case '8':
+ c = 8;
+ break;
+
+ default:
+ return(-1);
+ }
+ pdcb->ByteSize = c;
+
+ if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
+ return(0);
+
+ switch (szT[0])
+ {
+ case 0:
+ if (pdcb->BaudRate == 110)
+ {
+ c = TWOSTOPBITS;
+ break;
+ }
+ /*** FALL THRU ***/
+
+ case '1':
+ c = ONESTOPBIT;
+ break;
+
+ case '2':
+ c = TWOSTOPBITS;
+ break;
+
+ default:
+ return(-1);
+ }
+ pdcb->StopBits = c;
+
+ if ((pszDef = field(pszDef,(char FAR *)szT)) == 0)
+ return(0);
+
+ if (szT[0] != 'P')
+ return(-1);
+
+ pdcb->RlsTimeout = INFINITE;
+ pdcb->CtsTimeout = INFINITE;
+ pdcb->DsrTimeout = INFINITE;
+
+ return(0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* field() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+LPSTR NEAR PASCAL field(LPSTR pszSrc, LPSTR lpszDst)
+{
+ register char c;
+
+ if (!(pszSrc))
+ return(char FAR *)0;
+
+ if (!(*pszSrc))
+ return(char FAR *)0;
+
+ /* While not the end of the string. */
+ while (c = *pszSrc)
+ {
+ pszSrc++;
+
+ /* Look for end of string. */
+ if ((c == ' ') || (c == ':') || (c == ','))
+ {
+ *lpszDst = 0;
+
+ while (*pszSrc == ' ')
+ pszSrc++;
+
+ if (*pszSrc)
+ return(pszSrc);
+
+ return(char FAR *)0;
+ }
+
+ *lpszDst++ = UPPERCASE(c);
+ }
+
+ *lpszDst = 0;
+
+ return(pszSrc);
+}
+
+
+/*************************************************************************
+**
+** U T I L I T Y R O U T I N E S
+**
+**************************************************************************
+**
+** getid
+** Given a (far) pointer to a string, returns the comm ID of that device,
+** or -1 indicating error. This routine accepts all device references of
+** the form "COMn", where n is any number from 0 to 9, or "LPTn" where
+** n is any number from 1 to 9
+**
+*************************************************************************/
+
+short getid(LPSTR pszComName)
+
+{
+ int id;
+ register int base;
+ ushort isLPTorCOM;
+ LPSTR pszName;
+
+#ifdef JAPAN
+ /* Brought from WIN2 */
+ /* ------------- support 'oemgetid' (Jul,29,1987 SatoN) ----------- */
+ typedef int (far *FARPROC)();
+
+ extern void far int3();
+ static FARPROC lpOEMgetid = (FARPROC)(-1L);
+
+ /* If lpOEMgetid has not been initialized yet, initialize it.
+ This assumes 'GetProcAddress' does not cause FatalExit. */
+ if (lpOEMgetid==(FARPROC)(-1L))
+ {
+ unsigned hComm;
+ if ((hComm = GetModuleHandle( (char far *)"COMM" ))==NULL)
+ lpOEMgetid = NULL;
+ else
+ lpOEMgetid = GetProcAddress( hComm,(char far *)"oemgetid" );
+ }
+
+ /* If COMM driver has the routine 'oemgetid', then call it. */
+ if (lpOEMgetid && (id=(*lpOEMgetid)(pszComName))!=-1)
+ return id;
+ /* ------------- end of support 'oemgetid' ---------------------- */
+#endif /* JAPAN */
+
+ isLPTorCOM = TRUE; /* assume LPTx or COMx */
+ base = 0; /* assume serial */
+ id = 0; /* assume LPT1 or COM1 9/25/86 */
+
+ switch (UPPERCASE(*pszComName))
+ {
+ case 'A': /* AUX possibility */
+ pszName = AUXbuf; /* Search string to match */
+ isLPTorCOM = FALSE; /* Show AUX or PRN */
+ break;
+
+ case 'C': /* COMx possibility */
+ pszName = COMbuf; /* Search string to match */
+ break; /* cid base */
+
+ case 'L': /* LPTx possibility */
+ pszName = LPTbuf; /* Search string to match */
+ base = LPTx; /* cid base */
+ break;
+
+ case 'P': /* PRN possibility */
+ pszName = PRNbuf; /* Search string to match */
+ base = LPTx; /* cid base */
+ isLPTorCOM = FALSE; /* Show AUX or PRN */
+ break;
+
+ default:
+ return(-1);
+ }
+
+ while(*pszName != '1') /* make sure strings match */
+ {
+ if (*pszName++ != UPPERCASE(*pszComName++))
+ return(-1);
+ }
+
+ if (isLPTorCOM || /* then get device number */
+ (*pszComName && *pszComName != ':'))/* accept PRN or AUX */
+ id = (*pszComName++) - '1';
+
+ if (*pszComName == ':') /* skip ':' if present */
+ pszComName++;
+
+ if ((id < 0) || (*pszComName != '\0'))
+ return(-1);
+
+ if (id > (base ? (PIOMAX - 1) : (CDEVMAX - 1)))
+ return(-1);
+
+ return(base + id);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* cinfoPtr() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+cinfo *cinfoPtr(int cid)
+
+{
+ if (cid & LPTx)
+ return(&rgcinfo[((cid & LPTxMask)+CDEVMAX)]);
+
+ return(&rgcinfo[(cid & 0xFF)]);
+}
+
+
+/*************************************************************************
+**
+** GetMem
+** Uses windows memory allocator to get far, global memory. We fudge here,
+** in that GlobalAlloc returns a handle, which happens to be the segment
+** of the fixed memory we've asked for. Hence we need to fudge it to get
+** an address.
+**
+*************************************************************************/
+
+LPSTR GetMem(WORD size)
+
+{
+ /* See if the 286 DOS extender is installed, and if so, we must allocate
+ memory from conventional memory, so the queue can be used in both
+ protect and real modes (segment/selector ablility)
+ */
+
+ if( (WinFlags & (WF_PMODE|WF_WIN286)) == (WF_PMODE|WF_WIN286) )
+ {
+ return(MAKELP(GlobalDOSAlloc((LONG)size), NULL));
+ }
+ else
+ {
+ return(MAKELP(GlobalAlloc(
+ GMEM_LOWER | GMEM_SHARE | GMEM_ZEROINIT | GMEM_FIXED,
+ (LONG)size), NULL));
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FreeMem() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FreeMem(LPSTR pMem)
+
+{
+ /* See if the 286 DOS extender is installed, and if so, we must deallocate
+ memory from conventional memory, so the queue can be used in both
+ protect and real modes (segment/selector ablility)
+ */
+
+ if( (WinFlags & (WF_PMODE|WF_WIN286)) == (WF_PMODE|WF_WIN286) )
+ {
+ GlobalDOSFree((HANDLE)(((LONG)pMem) >> 16));
+ }
+ else
+ {
+ GlobalFree((HANDLE)(((LONG)pMem) >> 16));
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* TransmitCommChar() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int API ITransmitCommChar(int cid, char character)
+
+{
+ cid &= 0xFF;
+ return(ctx(cid, character));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* SetCommEventMask() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD FAR * API ISetCommEventMask(int cid, WORD evtmask)
+
+{
+ cid &= 0xFF;
+ return(cevt(cid, evtmask));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* GetCommEventMask() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD API IGetCommEventMask(int cid, int evtmask)
+
+{
+ cid &= 0xFF;
+ return(cevtGet(cid, evtmask));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* SetCommBreak() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int API ISetCommBreak(int cid)
+
+{
+ cid &= 0xFF;
+ return(csetbrk(cid));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* ClearCommBreak() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int API IClearCommBreak(int cid)
+
+{
+ cid &= 0xFF;
+ return(cclrbrk(cid));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FlushComm() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Parameters:
+ * ushort cid -- 0=com1 1=com2
+ * ushort queue -- 0 = clear transmit 1 = receive
+ */
+
+int API IFlushComm(int cid, int queue)
+
+{
+ cid &= 0xFF;
+ return(cflush(cid, queue));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* EscapeCommFunction() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+LONG API IEscapeCommFunction(int cid, int fcn)
+{
+ LONG ret;
+
+ cid &= 0xFF;
+
+ ret = cextfcn(cid, fcn);
+
+ if (SELECTOROF(lpCommWriteString) == NULL)
+ {
+#if 0
+ if (fcn == GETMAXBAUD)
+ /* For 3.0 drivers, fake the maxbaud rate escape.
+ */
+ ret = (LONG)CBR_19200;
+ else
+#endif
+ if (fcn == GETMAXLPT)
+ ret = (LONG)LPTx+2; /* 3 lpt ports */
+ else
+ if (fcn == GETMAXCOM)
+ ret = (LONG)9;
+ else
+ if ((WORD)fcn <= RESETDEV)
+ /* New for 3.1, we need to return a long from this function. So fix
+ * things up for old 3.0 drivers who used the defined escape range
+ * (we had 7 escapes for 3.0 drivers).
+ */
+ ret = (LONG)(int)(LOWORD(ret));
+ }
+
+ return(ret);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* EnableCommNotification() - */
+/* */
+/*--------------------------------------------------------------------------*/
+BOOL API IEnableCommNotification(int cid, HWND hwnd,
+ int recvth, int sendth)
+{
+ cid &= 0xFF;
+
+ if (SELECTOROF(lpCommEnableNotification) == NULL)
+ return(FALSE);
+
+ return(lpCommEnableNotification(cid, hwnd, recvth, sendth));
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* MyToUpper() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+char _fastcall NEAR MyToUpper(char c)
+{
+ return((c < (char)'a') ? c : c - (char)32);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LW_DriversInit() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void LW_DriversInit(void)
+
+{
+ HMODULE hModule;
+ char szString[128];
+
+ /*------------------------------------------------------------------------*/
+ /* Comm Initialization */
+ /*------------------------------------------------------------------------*/
+ /* Find out if the poor user is running with a 3.0 comm driver. Do this by
+ * checking for the 3.1 function WriteCommString. Also, save off the
+ * addresses of these functions so we don't rip had we imported them
+ * directly.
+ */
+ LoadString(hInstanceWin, STR_COMMMODULENAME, szString, sizeof(szString));
+ hModule = GetModuleHandle(szString);
+ LoadString(hInstanceWin, STR_COMMWRITESTRING, szString, sizeof(szString));
+ (FARPROC)lpCommWriteString = GetProcAddress((HINSTANCE)hModule, szString);
+ LoadString(hInstanceWin, STR_COMMREADSTRING, szString, sizeof(szString));
+ (FARPROC)lpCommReadString = GetProcAddress((HINSTANCE)hModule, szString);
+ LoadString(hInstanceWin, STR_COMMENABLENOTIFICATION, szString, sizeof(szString));
+ (FARPROC)lpCommEnableNotification = GetProcAddress((HINSTANCE)hModule, szString);
+}
+
diff --git a/private/mvdm/wow16/user/comdev.h b/private/mvdm/wow16/user/comdev.h
new file mode 100644
index 000000000..a65c9117c
--- /dev/null
+++ b/private/mvdm/wow16/user/comdev.h
@@ -0,0 +1,240 @@
+/*************************************************************************
+**
+** Miscelaneous definitions.
+*/
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+
+#ifdef NOCOMM
+/*************************************************************************
+**
+** device control block.
+** This block of information defines the functional parameters of the
+** communications software and hardware.
+**
+** Fields in the DCB are defined as follows:
+**
+** Id - Comm device ID, set by the device driver.
+** BaudRate - Baud rate at which operating.
+** ByteSize - Number of bits per transmitted/received byte. (4-8)
+** Received data is also masked off to this size.
+** Parity - Transmitt/Receive Parity. (0,1,2,3,4) = (None, Odd,
+** Even, Mark, Space)
+** StopBits - Number of stop bits. (0,1,2) = (1, 1.5, 2)
+** RlsTimeout - Amount of time, in milleseconds, to wait for RLSD to
+** become high. RLSD, Receive Line Signal Detect is also
+** known as CD, Carrier Detect. RLSD flow control can be
+** achieved by specifying infinite timeout.
+** CtsTimeout - Amount of time, in milleseconds, to wait for CTS,
+** Clear To Send, to become high. CTS flow control can
+** be achieved by specifying infinite timeout.
+** DsrTimeout - Amount of time, in milleseconds, to wait for DSR,
+** Data Set Ready, to become high. DSR flow control can
+** be acheived by specifying infinite timeout.
+** fBinary - Binary Mode flag. In non-binary mode, EofChar is
+** recognized and remembered as end of data.
+** fRtsDisable - Disable RTS flag. If set, Request To Send is NOT
+** used, and remains low. Normally, RTS is asserted when
+** the device is openned, and dropped when closed.
+** fParity - Enable Parity Checking. Parity errors are not
+** reported when 0.
+** fOutxCtsFlow - enable output xon/xoff(hardware) using cts
+** fOutxDsrFlow - enable output xon/xoff(hardware) using dsr
+** fOutX - Indicates that X-ON/X-OFF flow control is to be used
+** during transmission. The transmitter will halt if
+** an X-OFF character is received, and will start again
+** when an X-ON character is received.
+** fInX - Indicates that X-ON/X-OFF flow control is to be used
+** during reception. An X-OFF character will be
+** transmitted when the receive queue comes within 10
+** characters of being full, after which an X-ON will be
+** transmitted when the queue comes with 10 characters
+** of being empty.
+** fPeChar - Indicates that characters received with parity errors
+** are to be replaced with the character specified in
+** PeChar, below.
+** fNull - Indicates that received NULL characters are to be
+** discarded.
+** fChEvt - Indicates that the reception of EvtChar is to be
+** flagged as an event by cevt.
+** fDtrFlow - Indicates that the DTR signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear DTR, overriding this definition).
+** fRtsFlow - Indicates that the RTS signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear RTS, overriding this definition).
+** XonChar - X-ON character for both transmit and receive
+** XoffChar - X-OFF character for both transmit and receive
+** XonLim - When the number of characters in the receive queue
+** drops below this value, then an X-ON character is
+** sent, if enabled, and DTR is set, if enabled.
+** XoffLim - When the number of characters in the receive queue
+** exceeds this value, then an X-OFF character is sent,
+** if enabled, and DTR is dropped, if enabled.
+** PeChar - Parity Error replacement character.
+** EvtChar - Character which triggers an event flag.
+** EofChar - Character which specifies end of input.
+** TxDelay - Specifies the minimum amount of time that must pass
+** between transmission of characters.
+**
+** Timeouts are in milleseconds. 0 means ignore the signal. 0xffff means
+** infinite timeout.
+**
+*************************************************************************/
+typedef struct {
+ char Id; /* Internal Device ID */
+ ushort BaudRate; /* Baudrate at which runing */
+ char ByteSize; /* Number of bits/byte, 4-8 */
+ char Parity; /* 0,1,2,3,4 = None,Odd,Even,Mark,Sp*/
+ char StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ ushort RlsTimeout; /* Timeout for RLSD to be set */
+ ushort CtsTimeout; /* Timeout for CTS to be set */
+ ushort DsrTimeout; /* Timeout for DSR to be set */
+
+ uchar fBinary: 1; /* CTRL-Z as EOF flag */
+ uchar fRtsDisable:1; /* Suppress RTS */
+ uchar fParity: 1; /* Enable parity check */
+ uchar fOutxCtsFlow: 1; /* Enable output xon/xoff with cts */
+ uchar fOutxDsrFlow: 1; /* Enable output xon/xoff with dsr */
+ uchar fDummy: 3;
+
+ uchar fOutX: 1; /* Enable output X-ON/X-OFF */
+ uchar fInX: 1; /* Enable input X-ON/X-OFF */
+ uchar fPeChar: 1; /* Enable Parity Err Replacement */
+ uchar fNull: 1; /* Enable Null stripping */
+ uchar fChEvt: 1; /* Enable Rx character event. */
+ uchar fDtrflow: 1; /* Enable DTR flow control */
+ uchar fRtsflow: 1; /* Enable RTS flow control */
+ uchar fDummy2: 1;
+
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ ushort XonLim; /* Transmit X-ON threshold */
+ ushort XoffLim; /* Transmit X-OFF threshold */
+ char PeChar; /* Parity error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Recieved Event character */
+ ushort TxDelay; /* Amount of time between chars */
+ } DCB;
+
+/*************************************************************************
+**
+** COMSTAT
+** Status record returned by GetCommError
+**
+*************************************************************************/
+typedef struct {
+ uchar fCtsHold: 1; /* Transmit is on CTS hold */
+ uchar fDsrHold: 1; /* Transmit is on DSR hold */
+ uchar fRlsdHold: 1; /* Transmit is on RLSD hold */
+ uchar fXoffHold: 1; /* Transmit is on X-Off hold */
+ uchar fXoffSent: 1; /* Recieve in X-Off or DTR hold */
+ uchar fEof: 1; /* End of file character found */
+ uchar fTxim: 1; /* Character being transmitted */
+ uchar fPerr:1; /* Printer error */ /*081985*/
+ ushort cbInQue; /* count of characters in Rx Que*/
+ ushort cbOutQue; /* count of characters in Tx Que*/
+ } COMSTAT;
+
+/*************************************************************************
+**
+** DCB field definitions.
+**
+*************************************************************************/
+#define NOPARITY 0
+#define ODDPARITY 1
+#define EVENPARITY 2
+#define MARKPARITY 3
+#define SPACEPARITY 4
+
+#define ONESTOPBIT 0
+#define ONE5STOPBITS 1
+#define TWOSTOPBITS 2
+
+#define IGNORE 0 /* Ignore signal */
+#define INFINITE 0xffff /* Infinite timeout */
+
+/*************************************************************************
+**
+** Comm Device Driver Error Bits.
+**
+*************************************************************************/
+#define CE_RXOVER 0x0001 /* Receive Queue overflow */
+#define CE_OVERRUN 0x0002 /* Receive Overrun Error */
+#define CE_RXPARITY 0x0004 /* Receive Parity Error */
+#define CE_FRAME 0x0008 /* Receive Framing error */
+#define CE_CTSTO 0x0020 /* CTS Timeout */
+#define CE_DSRTO 0x0040 /* DSR Timeout */
+#define CE_RLSDTO 0x0080 /* RLSD Timeout */
+#define CE_PTO 0x0100 /* LPTx Timeout */ /*081985*/
+#define CE_IOE 0x0200 /* LPTx I/O Error */ /*081985*/
+#define CE_DNS 0x0400 /* LPTx Device not selected */ /*081985*/
+#define CE_OOP 0x0800 /* LPTx Out-Of-Paper */ /*081985*/
+#define CE_MODE 0x8000 /* Requested mode unsupported */
+
+/*************************************************************************
+**
+** Initialization Error Codes
+**
+*************************************************************************/
+#define IE_BADID -1 /* Invalid or unsupported id */
+#define IE_OPEN -2 /* Device Already Open */
+#define IE_NOPEN -3 /* Device Not Open */
+#define IE_MEMORY -4 /* Unable to allocate queues */
+#define IE_DEFAULT -5 /* Error in default parameters */
+#define IE_HARDWARE -10 /* Hardware Not Present */
+#define IE_BYTESIZE -11 /* Illegal Byte Size */
+#define IE_BAUDRATE -12 /* Unsupported BaudRate */
+/*************************************************************************
+**
+** Event mask definitions. Used by SetCommEventMask and GetCommEventMask
+**
+** RXCHAR - Set when any character is received and placed in the input
+** queue.
+** RXFLAG - Set when a particular character, as defined in the dcb, is
+** received and placed in the input queue.
+** TXEMPTY - Set when the last character in the transmit queue is
+** transmitted.
+** CTS - Set when the CTS signal changes state.
+** DSR - Set when the DSR signal changes state.
+** RLSD - Set when the RLSD signal changes state.
+** BREAK - Set when a break is detected on input.
+** ERR - Set when a line status error occurs.
+**
+*************************************************************************/
+#define EV_RXCHAR 0x0001 /* Any Character received */
+#define EV_RXFLAG 0x0002 /* Received certain character */
+#define EV_TXEMPTY 0x0004 /* Transmitt Queue Empty */
+#define EV_CTS 0x0008 /* CTS changed state */
+#define EV_DSR 0x0010 /* DSR changed state */
+#define EV_RLSD 0x0020 /* RLSD changed state */
+#define EV_BREAK 0x0040 /* BREAK received */
+#define EV_ERR 0x0080 /* Line Status Error Occurred */
+#define EV_RING 0x0100 /* Ring signal detected */
+#define EV_PERR 0x0200 /* LPTx error occured */ /*081985*/
+
+/*************************************************************************
+**
+** Extended Functions
+**
+** SETXOFF - Causes transmit to behave as if an X-OFF character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+** SETXON - Causes transmit to behave as if an X-ON character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+*************************************************************************/
+#define SETXOFF 1 /* Set X-Off for output control */
+#define SETXON 2 /* Set X-ON for output control */
+#define SETRTS 3 /* Set RTS high */
+#define CLRRTS 4 /* Set RTS low */
+#define SETDTR 5 /* Set DTR high */
+#define CLRDTR 6 /* Set DTR low */
+#define RESETDEV 7 /* Reset device if possible */ /*081985*/
+#endif
+
+
+/* Escapes for comm */
+#define GETMAXLPT 8 /* Max supported LPT id */
+#define GETMAXCOM 9 /* Max supported COM id */
+#define GETBASEIRQ 10 /* Get port base & irq for a port */
diff --git a/private/mvdm/wow16/user/comdevi.h b/private/mvdm/wow16/user/comdevi.h
new file mode 100644
index 000000000..89e10d0b1
--- /dev/null
+++ b/private/mvdm/wow16/user/comdevi.h
@@ -0,0 +1,18 @@
+WORD FAR PASCAL inicom(DCB FAR *);
+WORD FAR PASCAL setcom(DCB FAR *);
+void FAR PASCAL setque(int, qdb FAR *);
+int FAR PASCAL reccom(int);
+WORD FAR PASCAL sndcom(int, int);
+WORD FAR PASCAL ctx(int, int);
+int FAR PASCAL trmcom(int);
+WORD FAR PASCAL stacom(int, COMSTAT FAR *);
+LONG FAR PASCAL cextfcn(int, int);
+WORD FAR PASCAL cflush(int, int);
+WORD FAR *FAR PASCAL cevt(int, int);
+WORD FAR PASCAL cevtGet(int, int);
+int FAR PASCAL csetbrk(int);
+int FAR PASCAL cclrbrk(int);
+DCB FAR *FAR PASCAL getdcb(int);
+int FAR PASCAL CommWriteString(int cid, LPSTR pbuf, int size);
+BOOL FAR PASCAL EnableNotification(int cid, HWND hwnd,
+ int recvth, int sendth);
diff --git a/private/mvdm/wow16/user/debug.c b/private/mvdm/wow16/user/debug.c
new file mode 100644
index 000000000..e5c733a14
--- /dev/null
+++ b/private/mvdm/wow16/user/debug.c
@@ -0,0 +1,247 @@
+/*++
+ *
+ * WOW v3.5
+ *
+ * Copyright (c) 1980-1994, Microsoft Corporation
+ *
+ * DEBUG.C
+ * USER16 debug support
+ *
+ * History:
+ *
+ * Created 18-Aug-94 by Dave Hart (davehart)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+ * At this time, all we want is GetSystemDebugState.
+--*/
+
+/* Debug api support */
+#include "user.h"
+#ifndef WOW
+#include "menu.h"
+
+typedef struct tagMSGR
+ {
+ LPARAM lParam;
+ WPARAM wParam;
+ WORD message;
+ HWND hwnd;
+ } MSGR;
+typedef MSGR FAR *LPMSGR;
+
+
+/* A debug hook gets called by Windows just before calling any other type of
+ * hook. Let us call the hook which is about to be called as "App hook"; Debug
+ * hook is provided with all the details of the App hook so that it can decide
+ * whether to prevent Windows from calling the App hook or not; If the debug
+ * hook wants Windows to skip the call to the App hook, it must return TRUE;
+ * Otherwise, it must call the DefHookProc.
+ */
+
+/* Debug Hooks recieve three params just like anyother type of hook:
+
+ iCode = Hook Code (must be HC_ACTION in the current implementaion).
+ wParam = hook type of the App hook, which is about to be called by
+ Windows.
+ lParam = a FAR pointer to DEBUGHOOKSTRUCT structure which contains all
+ the details about the App hook;
+ */
+
+
+/* Our helper call which returns a pointer to the senders message queue.
+ */
+LPMSGR FAR PASCAL QuerySendMessageReversed(void);
+
+
+
+BOOL API QuerySendMessage(HANDLE h1, HANDLE h2, HANDLE h3, LPMSG lpmsg)
+{
+ LPMSGR lpmsgr;
+
+ if (h1 || h2 || h3)
+ return(FALSE);
+
+ if (!InSendMessage())
+ return(FALSE);
+
+ /* Get the inter task sendmessage we are servicing out of the apps queue.
+ */
+ lpmsgr = QuerySendMessageReversed();
+
+ lpmsg->hwnd = lpmsgr->hwnd;
+ lpmsg->message = lpmsgr->message;
+ lpmsg->wParam = lpmsgr->wParam;
+ lpmsg->lParam = lpmsgr->lParam;
+
+ return(TRUE);
+}
+
+typedef struct
+{
+ BOOL fOldHardwareInputState;
+ BOOL fMessageBox;
+ BOOL fDialog;
+
+ BOOL fMenu;
+ BOOL fInsideMenuLoop;
+ PPOPUPMENU pGlobalPopupMenu;
+
+ RECT rcClipCursor;
+
+ HWND hwndFocus;
+ HWND hwndActive;
+ HWND hwndSysModal;
+ HWND hwndCapture;
+} SAVESTATESTRUCT;
+typedef SAVESTATESTRUCT NEAR *PSAVESTATESTRUCT;
+typedef SAVESTATESTRUCT FAR *LPSAVESTATESTRUCT;
+
+static PSAVESTATESTRUCT pLockInputSaveState=NULL;
+
+BOOL API LockInput(HANDLE h1, HWND hwndInput, BOOL fLock)
+{
+ if (h1)
+ return(FALSE);
+
+ if (fLock)
+ {
+ if (pLockInputSaveState)
+ {
+ /* Save state struct currently in use.
+ */
+ DebugErr(DBF_ERROR, "LockInput() called when already locked");
+ return(NULL);
+ }
+
+ if (!hwndInput || hwndInput != GetTopLevelWindow(hwndInput))
+ return(FALSE);
+
+ pLockInputSaveState=(PSAVESTATESTRUCT)UserLocalAlloc(ST_LOCKINPUTSTATE,
+ LPTR,
+ sizeof(SAVESTATESTRUCT));
+
+ if (!pLockInputSaveState)
+ /* No memory, can't lock.
+ */
+ return(FALSE);
+
+ if (hwndInput)
+ ChangeToCurrentTask(hwndInput, hwndDesktop);
+
+ LockMyTask(TRUE);
+
+ /* Set global which tells us a task is locked. Needs to be set after
+ * calling LockMyTask...
+ */
+ hTaskLockInput = GetCurrentTask();
+
+ /* For DBCS, save are we in a dlg box global. */
+ pLockInputSaveState->fDialog = fDialog;
+
+ /* Save menu state and clear it so that the debugger can bring up menus
+ * if needed.
+ */
+ pLockInputSaveState->fMenu = fMenu;
+ pLockInputSaveState->fInsideMenuLoop = fInsideMenuLoop;
+ fMenu = FALSE;
+ fInsideMenuLoop = FALSE;
+
+ pLockInputSaveState->pGlobalPopupMenu = pGlobalPopupMenu;
+ pGlobalPopupMenu = NULL;
+
+ /* Change focus etc without sending messages...
+ */
+ pLockInputSaveState->hwndFocus = hwndFocus;
+ pLockInputSaveState->hwndActive = hwndActive;
+ hwndFocus = hwndInput;
+ hwndActive = hwndInput;
+
+ /* Save capture and set it to null */
+ pLockInputSaveState->hwndCapture = hwndCapture;
+ SetCapture(NULL);
+
+ /* Save sysmodal window */
+ pLockInputSaveState->hwndSysModal= hwndSysModal;
+ pLockInputSaveState->fMessageBox = fMessageBox;
+ SetSysModalWindow(hwndInput);
+
+ /* Save clipcursor rect */
+ CopyRect(&pLockInputSaveState->rcClipCursor, &rcCursorClip);
+ ClipCursor(NULL);
+
+ /* Enable hardware input so that we can get mouse/keyboard messages.
+ */
+ pLockInputSaveState->fOldHardwareInputState=EnableHardwareInput(TRUE);
+
+ }
+ else
+ {
+ if (!pLockInputSaveState)
+ {
+ /* Save state struct not in use, nothing to restore.
+ */
+ DebugErr(DBF_ERROR, "LockInput called with input already unlocked");
+ return(NULL);
+ }
+
+
+ /* For DBCS, save are we in a dlg box global. */
+ fDialog = pLockInputSaveState->fDialog;
+
+ /* Restore clipcursor rect */
+ ClipCursor(&pLockInputSaveState->rcClipCursor);
+
+ /* Set active and focus windows manually so we avoid sending messages to
+ * the applications.
+ */
+ hwndFocus = pLockInputSaveState->hwndFocus;
+ hwndActive= pLockInputSaveState->hwndActive;
+
+ SetSysModalWindow(pLockInputSaveState->hwndSysModal);
+ fMessageBox = pLockInputSaveState->fMessageBox;
+
+ pGlobalPopupMenu = pLockInputSaveState->pGlobalPopupMenu;
+ fMenu = pLockInputSaveState->fMenu;
+ fInsideMenuLoop = pLockInputSaveState->fInsideMenuLoop;
+
+ SetCapture(pLockInputSaveState->hwndCapture);
+ EnableHardwareInput(pLockInputSaveState->fOldHardwareInputState);
+
+ /* Unset global which tells us a task is locked. Has to be unset before
+ * we call LockMyTask...
+ */
+ hTaskLockInput = NULL;
+ LockMyTask(FALSE);
+
+ LocalFree((HANDLE)pLockInputSaveState);
+ pLockInputSaveState = NULL;
+ }
+
+ return(TRUE);
+}
+#endif // !WOW
+
+LONG API GetSystemDebugState(void)
+{
+ LONG returnval = 0;
+ HANDLE hTask;
+
+ hTask = GetCurrentTask();
+ if (!GetTaskQueue(hTask))
+ returnval = returnval | SDS_NOTASKQUEUE;
+
+#ifndef WOW
+ if (fMenu)
+ returnval = returnval | SDS_MENU;
+
+ if (fDialog)
+ returnval = returnval | SDS_DIALOG;
+
+ if (fTaskIsLocked)
+ returnval = returnval | SDS_TASKLOCKED;
+
+ if (hwndSysModal)
+ returnval = returnval | SDS_SYSMODAL;
+#endif // !WOW
+
+ return(returnval);
+}
diff --git a/private/mvdm/wow16/user/drvr.c b/private/mvdm/wow16/user/drvr.c
new file mode 100644
index 000000000..80db15424
--- /dev/null
+++ b/private/mvdm/wow16/user/drvr.c
@@ -0,0 +1,266 @@
+/* Installable drivers for windows. Often used stuff.
+ */
+#include "user.h"
+
+LRESULT FAR InternalBroadcastDriverMessage(HDRVR hDriverStart,
+ WORD message,
+ LPARAM lParam1,
+ LPARAM lParam2,
+ LONG flags)
+/* effects: Allows for sending messages to the drivers. Supports sending
+ * messages to one instance of every driver, supports running through the list
+ * in reverse order, and supports sending a message to a particular driver id.
+ *
+ * If flags & IBDM_SENDMESSAGE then only send message to
+ * hDriverStart and ignore other flags. Fail if not
+ * 0<hDriverStart<=cInstalledDrivers.
+ *
+ * If flags & IBDM_FIRSTINSTANCEONLY then send message to one instance of
+ * each driver between hDriverStart and cInstalledDrivers.
+ *
+ * If flags & IBDM_REVERSE then send message to drivers in reverse
+ * order from hDriverStart to 1. If hDriverStart is 0 then send
+ * messages to drivers from cInstalledDrivers to 1
+ */
+{
+ LPDRIVERTABLE lpdt;
+ LRESULT result=0;
+ int id;
+ int idEnd;
+
+ if (!hInstalledDriverList || (int)hDriverStart > cInstalledDrivers)
+ return(FALSE);
+
+ if (idFirstDriver == -1)
+ /* No drivers in the list
+ */
+ return(FALSE);
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+
+ if (flags & IBDM_SENDMESSAGE)
+ {
+ if (!hDriverStart)
+ return(FALSE);
+ idEnd = lpdt[(int)hDriverStart-1].idNextDriver;
+ flags &= ~(IBDM_REVERSE | IBDM_FIRSTINSTANCEONLY);
+ }
+ else
+ {
+ if (flags & IBDM_REVERSE)
+ {
+ if (!hDriverStart)
+ hDriverStart = (HDRVR)(idLastDriver+1);
+ idEnd = lpdt[idFirstDriver].idPrevDriver;
+ }
+ else
+ {
+ if (!hDriverStart)
+ hDriverStart = (HDRVR)(idFirstDriver+1);
+ idEnd = lpdt[idLastDriver].idNextDriver;
+ }
+ }
+
+ /* Ids are -1 into the global driver list. */
+ ((int)hDriverStart)--;
+
+ for (id = (int)hDriverStart; id != idEnd; id = (flags & IBDM_REVERSE ? lpdt[id].idPrevDriver : lpdt[id].idNextDriver))
+ {
+ if (lpdt[id].hModule)
+ {
+ if ((flags & IBDM_FIRSTINSTANCEONLY) &&
+ !lpdt[id].fFirstEntry)
+ continue;
+
+ result =
+ (*lpdt[id].lpDriverEntryPoint)(lpdt[id].dwDriverIdentifier,
+ (HDRVR)(id+1),
+ message,
+ lParam1,
+ lParam2);
+
+ /* If this isn't a IBDM_SENDMESSAGE, we want to update our end
+ * points in case the driver callback added or removed some drivers
+ */
+ if (flags & IBDM_REVERSE)
+ {
+ idEnd = lpdt[idFirstDriver].idPrevDriver;
+ }
+ else if (!(flags & IBDM_SENDMESSAGE))
+ {
+ idEnd = lpdt[idLastDriver].idNextDriver;
+ }
+ else
+ {
+ /* This is a IBDM_SENDMESSAGE. We need to break out of the for
+ * loop here otherwise we run into problems if a new driver was
+ * installed in the list during the callback and idEnd got
+ * updated or something...
+ */
+ break;
+ }
+ }
+ }
+
+ return(result);
+}
+
+
+LRESULT API ISendDriverMessage(HDRVR hDriverID,
+ WORD message,
+ LPARAM lParam1,
+ LPARAM lParam2)
+{
+ return(InternalBroadcastDriverMessage(hDriverID,
+ message,
+ lParam1,
+ lParam2,
+ IBDM_SENDMESSAGE));
+}
+
+
+
+
+BOOL API IGetDriverInfo(HDRVR hDriver, LPDRIVERINFOSTRUCT lpDriverInfoStruct)
+{
+ LPDRIVERTABLE lpdt;
+ BOOL ret = FALSE;
+
+ if (!lpDriverInfoStruct ||
+ lpDriverInfoStruct->length != sizeof(DRIVERINFOSTRUCT))
+ {
+ /* Error in struct size
+ */
+ DebugErr(DBF_ERROR, "Invalid size for DRIVERINFOSTRUCT");
+ return(ret);
+ }
+
+#ifdef DEBUG
+ DebugFillStruct(lpDriverInfoStruct, sizeof(DRIVERINFOSTRUCT));
+ lpDriverInfoStruct->length = sizeof(DRIVERINFOSTRUCT);
+#endif
+
+ if (!hInstalledDriverList || (int)hDriver <= 0 || (int)hDriver > cInstalledDrivers)
+ return(ret);
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList, 0);
+
+ if (lpdt[(int)hDriver-1].hModule)
+ {
+ lpDriverInfoStruct->hDriver = hDriver;
+ lpDriverInfoStruct->hModule = lpdt[(int)hDriver-1].hModule;
+ lstrcpy(lpDriverInfoStruct->szAliasName, lpdt[(int)hDriver-1].szAliasName);
+
+ ret = TRUE;
+ }
+
+
+ return(ret);
+}
+
+
+
+HDRVR API IGetNextDriver(HDRVR hStart, DWORD dwFlags)
+{
+ int iStart;
+ int iEnd;
+ int id;
+ HDRVR h;
+ LPDRIVERTABLE lpdt;
+
+ if (!hInstalledDriverList || !cInstalledDrivers || idFirstDriver == -1)
+ return(0);
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ if (dwFlags & GND_REVERSE)
+ {
+ if (!hStart)
+ iStart = idLastDriver;
+ else
+ {
+ iStart = (int)hStart-1;
+
+ if (iStart == idFirstDriver)
+ /* If we are at the first driver, nothing left to do
+ */
+ return((HDRVR)0);
+
+ iStart = lpdt[iStart].idPrevDriver;
+ }
+
+ iEnd = lpdt[idFirstDriver].idPrevDriver;
+
+ }
+ else
+ {
+ if (!hStart)
+ iStart = idFirstDriver;
+ else
+ {
+ iStart = (int)hStart-1;
+
+ if (iStart == idLastDriver)
+ /* If we are at the last driver, nothing left to do.
+ */
+ return((HDRVR)0);
+
+ iStart = lpdt[iStart].idNextDriver;
+ }
+
+ iEnd = lpdt[idLastDriver].idNextDriver;
+
+ }
+
+ if (!lpdt[iStart].hModule)
+ {
+ /* Bogus driver handle passed in
+ */
+ DebugErr(DBF_ERROR, "GetNextDriver: Invalid starting driver handle");
+ return(0);
+ }
+
+ h = NULL;
+
+ for (id = iStart; id != iEnd; id = (dwFlags & GND_REVERSE ? lpdt[id].idPrevDriver : lpdt[id].idNextDriver))
+ {
+ if (lpdt[id].hModule)
+ {
+ if ((dwFlags & GND_FIRSTINSTANCEONLY) &&
+ !lpdt[id].fFirstEntry)
+ continue;
+
+ h = (HDRVR)(id+1);
+ break;
+ }
+ }
+
+ return(h);
+}
+
+
+LRESULT API IDefDriverProc(dwDriverIdentifier, driverID, message, lParam1, lParam2)
+DWORD dwDriverIdentifier;
+HDRVR driverID;
+WORD message;
+LPARAM lParam1;
+LPARAM lParam2;
+{
+
+ switch (message)
+ {
+ case DRV_INSTALL:
+ return((LRESULT)(DWORD)DRVCNF_OK);
+ break;
+
+ case DRV_LOAD:
+ case DRV_ENABLE:
+ case DRV_DISABLE:
+ case DRV_FREE:
+ return((LRESULT)(DWORD)TRUE);
+ break;
+ }
+
+ return(0L);
+}
diff --git a/private/mvdm/wow16/user/drvrrare.c b/private/mvdm/wow16/user/drvrrare.c
new file mode 100644
index 000000000..7ee577947
--- /dev/null
+++ b/private/mvdm/wow16/user/drvrrare.c
@@ -0,0 +1,559 @@
+/* Installable drivers for windows. Less common code.
+ */
+#include "user.h"
+
+/*--------------------------------------------------------------------------*\
+**
+** NewSignalProc() -
+**
+\*--------------------------------------------------------------------------*/
+#define SG_EXIT 0x0020
+#define SG_LOAD_DLL 0x0040
+#define SG_EXIT_DLL 0x0080
+#define SG_GP_FAULT 0x0666
+
+BOOL
+CALLBACK NewSignalProc(
+ HTASK hTask,
+ WORD message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ BOOL fRet;
+
+ // Notify installable drivers this app is going away.
+ if ( message == SG_EXIT || message == SG_GP_FAULT ) {
+ InternalBroadcastDriverMessage( NULL, DRV_EXITAPPLICATION,
+ (message == SG_GP_FAULT
+ ? DRVEA_ABNORMALEXIT
+ : DRVEA_NORMALEXIT),
+ 0L, IBDM_FIRSTINSTANCEONLY );
+ }
+
+ //
+ // Pass notification on to WOW32 (which passes on to USER32)
+ //
+
+ fRet = SignalProc( hTask, message, wParam, lParam );
+
+ //
+ // After letting WOW32 and User32 cleanup, destroy the shadow
+ // message queue created by InitApp.
+ //
+
+ if ( message == SG_EXIT || message == SG_GP_FAULT ) {
+ DeleteQueue();
+ }
+
+ return fRet;
+}
+
+HINSTANCE LoadAliasedLibrary(LPCSTR szLibFileName,
+ LPCSTR szSection,
+ LPCSTR szIniFile,
+ LPSTR lpstrTail,
+ WORD cbTail)
+{
+ char sz[128];
+ LPSTR pch;
+ OFSTRUCT os;
+ HFILE fd;
+ HINSTANCE h;
+ WORD errMode;
+
+ if (!szLibFileName || !*szLibFileName)
+ return((HINSTANCE)2); /* File not found */
+
+ /* read the filename and additional info. into sz
+ */
+ GetPrivateProfileString(szSection, // ini section
+ szLibFileName, // key name
+ szLibFileName, // default if no match
+ sz, // return buffer
+ sizeof(sz), // return buffer size
+ szIniFile); // ini. file
+
+ sz[sizeof(sz)-1] = 0;
+
+ /* strip off the additional info. Remember, DS!=SS so we need to get a lpstr
+ * to our stack allocated sz.
+ */
+ pch = (LPSTR)sz;
+ while (*pch)
+ {
+ if (*pch == ' ')
+ {
+ *pch++ = '\0';
+ break;
+ }
+ pch++;
+ }
+
+ // pch pts to ch after first space or null ch
+
+ fd = OpenFile(sz, &os, OF_EXIST|OF_SHARE_DENY_NONE);
+ if (fd < 0)
+ return((HINSTANCE)2);
+
+ /* copy additional info. to lpstrTail
+ */
+
+ if (lpstrTail && cbTail)
+ {
+ while (cbTail-- && (*lpstrTail++ = *pch++))
+ ;
+ *(lpstrTail-1) = 0;
+ }
+
+ errMode = SetErrorMode(0x8001);
+
+ h = LoadLibrary(sz);
+
+ SetErrorMode(errMode);
+
+ return (h);
+}
+
+
+
+int GetDrvrUsage(HMODULE hModule)
+/* effects: Runs through the driver list and figures out how many instances of
+ * this driver module handle we have. We use this instead of GetModuleUsage
+ * so that we can have drivers loaded as normal DLLs and as installable
+ * drivers.
+ */
+{
+ LPDRIVERTABLE lpdt;
+ int index;
+ int count;
+
+ if (!hInstalledDriverList || !cInstalledDrivers || !hModule)
+ return(0);
+
+ count = 0;
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ for (index=0;index<cInstalledDrivers;index++)
+ {
+ if (lpdt->hModule==hModule)
+ count++;
+
+ lpdt++;
+ }
+
+
+ return(count);
+}
+
+
+BOOL PASCAL CheckValidDriverProc(LPDRIVERTABLE lpdt, HDRVR hdrv)
+/* effects: Some vendors shipped multimedia style installable drivers with
+ * bogus entry procs. This test checks for these bogus drivers and refuses to
+ * install them.
+ */
+{
+ WORD currentSP;
+ WORD saveSP;
+
+ _asm mov saveSP, sp
+ (void)(lpdt->lpDriverEntryPoint)(0, hdrv, 0, 0L, 0L);
+ _asm mov currentSP, sp
+ _asm mov sp, saveSP
+
+ if (saveSP != currentSP)
+ DebugErr(DBF_ERROR, "Invalid driver entry proc address");
+
+ return (saveSP == currentSP);
+}
+
+LRESULT FAR InternalLoadDriver(LPCSTR szDriverName,
+ LPCSTR szSectionName,
+ LPCSTR lpstrTail,
+ WORD cbTail,
+ BOOL fSendEnable)
+{
+ int index;
+ int i;
+ LPDRIVERTABLE lpdt;
+ LPDRIVERTABLE lpdtBegin;
+ LRESULT result;
+ HGLOBAL h;
+ HINSTANCE hInstance;
+ char szDrivers[20];
+ char szSystemIni[20];
+
+ /* Drivers receive the following messages: if the driver was loaded,
+ * DRV_LOAD. If DRV_LOAD returns non-zero and fSendEnable, DRV_ENABLE.
+ */
+
+ if (!hInstalledDriverList)
+ h = GlobalAlloc(GHND|GMEM_SHARE, (DWORD)((WORD)sizeof(DRIVERTABLE)));
+ else
+ /* Alloc space for the next driver we will install. We may not really
+ * install the driver in the last slot but rather in an intermediate
+ * slot which was freed.
+ */
+ h = GlobalReAlloc(hInstalledDriverList,
+ (DWORD)((WORD)sizeof(DRIVERTABLE)*(cInstalledDrivers+1)),
+ GHND|GMEM_SHARE);
+
+ if (!h)
+ return(0L);
+
+ cInstalledDrivers++;
+ hInstalledDriverList = h;
+
+ if (!szSectionName)
+ LoadString(hInstanceWin, STR_DRIVERS, szDrivers, sizeof(szDrivers));
+ LoadString(hInstanceWin, STR_SYSTEMINI, szSystemIni, sizeof(szSystemIni));
+
+ lpdtBegin = lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList, NULL);
+
+ /* Find an empty driver entry */
+ for (i = 0; i < cInstalledDrivers; i++)
+ {
+ if (lpdt->hModule == NULL)
+ {
+ index = i;
+ break;
+ }
+
+ lpdt++;
+ }
+
+ if (index + 1 < cInstalledDrivers)
+ /* The driver went into an unused slot in the middle somewhere so
+ * decrement cInstalledDrivers count.
+ */
+ cInstalledDrivers--;
+
+ /* Temporarly use an hModule to 1 to reserve this entry in case the driver
+ * loads another driver in its LibMain.
+ */
+ lpdt->hModule = (HMODULE)1;
+
+ hInstance = LoadAliasedLibrary(szDriverName,
+ szSectionName ? szSectionName : szDrivers,
+ szSystemIni,
+ lpstrTail,
+ cbTail);
+ if (hInstance < HINSTANCE_ERROR)
+ {
+ lpdt->hModule = NULL;
+
+ /* Load failed with an error. Return error code in highword.
+ */
+ return(MAKELRESULT(0, hInstance));
+ }
+
+ (FARPROC)lpdt->lpDriverEntryPoint = GetProcAddress(hInstance, "DriverProc");
+
+ if (!lpdt->lpDriverEntryPoint)
+ {
+ FreeLibrary(hInstance);
+ lpdt->hModule = 0;
+ result = 0L;
+ goto LoadCleanUp;
+ }
+
+ lpdt->hModule = hInstance;
+
+ /* Save either the alias or filename of this driver. (depends on what the
+ * app passed to us to load it)
+ */
+ lstrcpy(lpdt->szAliasName, szDriverName);
+
+ if (GetDrvrUsage(hInstance) == 1)
+ {
+ /* If this is the first instance, send the drv_load message. Don't use
+ * SendDriverMessage because we haven't initialized the linked list yet
+ */
+ if (!CheckValidDriverProc(lpdt, (HDRVR)(index+1)) ||
+ !(lpdt->lpDriverEntryPoint)(lpdt->dwDriverIdentifier,
+ (HDRVR)(index+1),
+ DRV_LOAD,
+ 0L, 0L))
+ {
+ /* Driver failed load call.
+ */
+ lpdt->lpDriverEntryPoint = NULL;
+ lpdt->hModule = NULL;
+ FreeLibrary(hInstance);
+ result = 0L;
+ goto LoadCleanUp;
+ }
+
+ lpdt->fFirstEntry = 1;
+ }
+
+ /* Put driver in the load order linked list
+ */
+ if (idFirstDriver == -1)
+ {
+ /* Initialize everything when first driver is loaded.
+ */
+ idFirstDriver = index;
+ idLastDriver = index;
+ lpdt->idNextDriver = -1;
+ lpdt->idPrevDriver = -1;
+ }
+ else
+ {
+ /* Insert this driver at the end of the load chain.
+ */
+ lpdtBegin[idLastDriver].idNextDriver = index;
+ lpdt->idPrevDriver = idLastDriver;
+ lpdt->idNextDriver = -1;
+ idLastDriver = index;
+ }
+
+ if (fSendEnable && lpdt->fFirstEntry)
+ SendDriverMessage((HDRVR)(index+1), DRV_ENABLE, 0L, 0L);
+
+ result = MAKELRESULT(index+1, hInstance);
+
+LoadCleanUp:
+ return(result);
+}
+
+
+
+WORD FAR InternalFreeDriver(HDRVR hDriver, BOOL fSendDisable)
+{
+ LPDRIVERTABLE lpdt;
+ WORD w;
+ int id;
+
+ /* The driver will receive the following message sequence:
+ *
+ * if usage count of driver is 1
+ * DRV_DISABLE (normally)
+ * DRV_FREE
+ */
+
+ if ((int)hDriver > cInstalledDrivers || !hDriver)
+ return(0);
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ if (!lpdt[(int)hDriver-1].hModule)
+ return(0);
+
+ /* If the driver usage count is 1, then send free and disable messages.
+ */
+
+ /* Clear dwDriverIdentifier so that the sendmessage for DRV_OPEN and
+ * DRV_ENABLE have dwDriverIdentifier = 0 if an entry gets reused and so
+ * that the DRV_DISABLE and DRV_FREE messages below also get
+ * dwDriverIdentifier = 0.
+ */
+
+ lpdt[(int)hDriver-1].dwDriverIdentifier = 0;
+
+ w = GetDrvrUsage(lpdt[(int)hDriver-1].hModule);
+ if (w == 1)
+ {
+ if (fSendDisable)
+ SendDriverMessage(hDriver, DRV_DISABLE, 0L, 0L);
+ SendDriverMessage(hDriver, DRV_FREE, 0L, 0L);
+ }
+ FreeLibrary(lpdt[(int)hDriver-1].hModule);
+
+ // Clear the rest of the table entry
+
+ lpdt[(int)hDriver-1].hModule = 0; // this indicates free entry
+ lpdt[(int)hDriver-1].fFirstEntry = 0; // this is also just to be tidy
+ lpdt[(int)hDriver-1].lpDriverEntryPoint = 0; // this is also just to be tidy
+
+ /* Fix up the driver load linked list */
+ if (idFirstDriver == (int)hDriver-1)
+ {
+ idFirstDriver = lpdt[(int)hDriver-1].idNextDriver;
+ if (idFirstDriver == -1)
+ {
+ /* No more drivers in the chain */
+ idFirstDriver = -1;
+ idLastDriver = -1;
+ cInstalledDrivers= 0;
+ goto Done;
+ }
+ else
+ {
+ /* Make prev entry of new first driver -1 */
+ lpdt[idFirstDriver].idPrevDriver = -1;
+ }
+ }
+ else if (idLastDriver == (int)hDriver-1)
+ {
+ /* We are freeing the last driver. So find a new last driver. */
+ idLastDriver = lpdt[(int)hDriver-1].idPrevDriver;
+ lpdt[idLastDriver].idNextDriver = -1;
+ }
+ else
+ {
+ /* We are freeing a driver in the middle of the list somewhere. */
+ id = lpdt[(int)hDriver-1].idPrevDriver;
+ lpdt[id].idNextDriver = lpdt[(int)hDriver-1].idNextDriver;
+
+ id = lpdt[(int)hDriver-1].idNextDriver;
+ lpdt[id].idPrevDriver = lpdt[(int)hDriver-1].idPrevDriver;
+ }
+
+Done:
+ return(w-1);
+}
+
+
+
+
+LRESULT InternalOpenDriver(LPCSTR szDriverName,
+ LPCSTR szSectionName,
+ LPARAM lParam2,
+ BOOL fSendEnable)
+{
+ HDRVR hDriver;
+ LPDRIVERTABLE lpdt;
+ LRESULT result;
+ char sz[128];
+
+ if (hDriver = (HDRVR)LOWORD(InternalLoadDriver(szDriverName, szSectionName,
+ sz, sizeof(sz), fSendEnable)))
+ {
+ /* Set the driver identifier to the DRV_OPEN call to the driver
+ * handle. This will let people build helper functions that the driver
+ * can call with a unique identifier if they want to.
+ */
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)(WORD)hDriver;
+
+ result = SendDriverMessage(hDriver,
+ DRV_OPEN,
+ (LPARAM)(LPSTR)sz,
+ lParam2);
+ if (!result)
+ InternalFreeDriver(hDriver, fSendEnable);
+ else
+ {
+ lpdt = (LPDRIVERTABLE)MAKELONG(0,hInstalledDriverList);
+
+ lpdt[(int)hDriver-1].dwDriverIdentifier = (DWORD)result;
+
+ result = (LRESULT)(DWORD)(WORD)hDriver;
+ }
+ }
+ else
+ result = 0L;
+
+ return(result);
+}
+
+
+LRESULT InternalCloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2, BOOL fSendDisable)
+{
+ LPDRIVERTABLE lpdt;
+ LRESULT result;
+ int index;
+ BOOL f;
+ HMODULE hm;
+
+ // check handle in valid range.
+
+ if ((int)hDriver > cInstalledDrivers)
+ return(FALSE);
+
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ if (!lpdt[(int)hDriver-1].hModule)
+ return(FALSE);
+
+ result = SendDriverMessage(hDriver, DRV_CLOSE, lParam1, lParam2);
+
+ if (result)
+ {
+ // Driver didn't abort close
+
+ f = lpdt[(int)hDriver-1].fFirstEntry;
+ hm = lpdt[(int)hDriver-1].hModule;
+
+ if (InternalFreeDriver(hDriver, fSendDisable) && f)
+ {
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ /* Only one entry for the driver in the driver list has the first
+ * instance flag set. This is to make it easier to handle system
+ * messages that only need to be sent to a driver once.
+ *
+ * To maintain the flag, we must set the flag in one of the other
+ * entries if we remove the driver entry with the flag set.
+ *
+ * Note that InternalFreeDriver returns the new usage count of
+ * the driver so if it is zero, we know that there are no other
+ * entries for the driver in the list and so we don't have to
+ * do this loop.
+ */
+
+ for (index=0;index<cInstalledDrivers;index++)
+ if (lpdt[index].hModule == hm && !lpdt[index].fFirstEntry)
+ {
+ lpdt[index].fFirstEntry = 1;
+ break;
+ }
+ }
+
+ }
+
+ return(result);
+}
+
+
+HDRVR API IOpenDriver(LPCSTR szDriverName, LPCSTR szSectionName, LPARAM lParam)
+{
+ LRESULT result;
+
+ /* The driver receives the following messages when it is opened. If it isn't
+ * loaded, the library is loaded and the DRV_LOAD message is sent. If
+ * DRV_LOAD returns nonzero, the DRV_ENABLE message is sent. Once the
+ * driver is loaded or if it was previously loaded, the DRV_OPEN message is
+ * sent.
+ */
+ result = InternalOpenDriver(szDriverName, szSectionName, lParam, TRUE);
+
+ return((HDRVR)LOWORD(result));
+}
+
+
+LRESULT API ICloseDriver(HDRVR hDriver, LPARAM lParam1, LPARAM lParam2)
+{
+ /* The driver will receive the following message sequence:
+ *
+ * DRV_CLOSE
+ * if DRV_CLOSE returns non-zero
+ * if driver usage count = 1
+ * DRV_DISABLE
+ * DRV_FREE
+ */
+
+ return(InternalCloseDriver(hDriver, lParam1, lParam2, TRUE));
+}
+
+
+HINSTANCE API IGetDriverModuleHandle(HDRVR hDriver)
+/* effects: Returns the module handle associated with the given driver ID.
+ */
+{
+ LPDRIVERTABLE lpdt;
+ HINSTANCE hModule = NULL;
+
+ if (hDriver && ((int)hDriver <= cInstalledDrivers))
+ {
+ lpdt = (LPDRIVERTABLE)MAKELP(hInstalledDriverList,0);
+
+ return lpdt[(int)hDriver-1].hModule;
+ }
+ else
+ return NULL;
+}
diff --git a/private/mvdm/wow16/user/edecrare.c b/private/mvdm/wow16/user/edecrare.c
new file mode 100644
index 000000000..37f87c8f2
--- /dev/null
+++ b/private/mvdm/wow16/user/edecrare.c
@@ -0,0 +1,400 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDECRARE.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* edECRare.c - EC Edit controls Routines Called rarely are to be */
+/* put in a seperate segment _EDECRare. This file contains */
+/* these routines. */
+/* */
+/* Created: 02-08-89 sankar */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Support Routines common to Single-line and Multi-Line edit controls */
+/* called Rarely. */
+/****************************************************************************/
+
+
+ICH FAR PASCAL ECGetTextHandler(ped, maxCchToCopy, lpBuffer)
+register PED ped;
+register ICH maxCchToCopy;
+LPSTR lpBuffer;
+/* effects: Copies at most maxCchToCopy bytes to the buffer lpBuffer. Returns
+ * how many bytes were actually copied. Null terminates the string thus at
+ * most maxCchToCopy-1 characters will be returned.
+ */
+{
+ PSTR pText;
+
+ if (maxCchToCopy)
+ {
+#ifdef DEBUG
+ /* In debug mode, trash their buffer so that we can catch
+ * stack/allocation problems early.
+ */
+ DebugFillStruct(lpBuffer, maxCchToCopy);
+#endif
+
+ /* Zero terminator takes the extra byte */
+ maxCchToCopy = umin(maxCchToCopy-1, ped->cch);
+
+ /* Zero terminate the string */
+ *(LPSTR)(lpBuffer+maxCchToCopy) = 0;
+
+
+ pText = LocalLock(ped->hText);
+ LCopyStruct((LPSTR)pText, lpBuffer, maxCchToCopy);
+ LocalUnlock(ped->hText);
+ }
+
+ return(maxCchToCopy);
+}
+
+
+BOOL FAR PASCAL ECNcCreate(hwnd, lpCreateStruct)
+HWND hwnd;
+LPCREATESTRUCT lpCreateStruct;
+{
+ LONG windowStyle;
+ register PED ped;
+
+ /* Initially no ped for the window. In case of no memory error, we can
+ * return with a -1 for the window's PED
+ */
+ SetWindowWord(hwnd, 0, (WORD)-1); /* No ped for this window */
+
+ /* If pLocalHeap = 0, then we need to LocalInit our "new" data segment for
+ * dialog boxes.
+ */
+ if (!pLocalHeap)
+ {
+ LocalInit((WORD) NULL,
+ (WORD) 0,
+ (WORD) GlobalSize(lpCreateStruct->hInstance)-64);
+
+ /* Since LocalInit locked the segment (and it was locked previously, we
+ * will unlock it to prevent lock count from being greater than 1).
+ */
+ UnlockSegment((WORD)-1);
+ }
+
+ windowStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ /* Try to allocate space for the ped. HACK: Note that the handle to a fixed
+ * local object is the same as a near pointer to the object.
+ */
+ SwapHandle(&lpCreateStruct->lpszName);
+ SwapHandle(&lpCreateStruct);
+
+ if (!(ped = (PED) LocalAlloc(LPTR, sizeof(ED))))
+ /* Error, no memory */
+ return(NULL);
+
+ if (windowStyle & ES_MULTILINE)
+ /* Allocate memory for a char width buffer if we can get it. If we can't
+ * we'll just be a little slower...
+ */
+ ped->charWidthBuffer = LocalAlloc(LHND, sizeof(int)*256);
+
+ if (windowStyle & ES_READONLY)
+ ped->fReadOnly = 1;
+
+ /* Allocate storage for the text for the edit controls. Storage for single
+ * line edit controls will always get allocated in the local data segment.
+ * Multiline will allocate in the local ds but the app may free this and
+ * allocate storage elsewhere...
+ */
+ ped->hText = LocalAlloc(LHND, CCHALLOCEXTRA);
+ if (!ped->hText) /* If no_memory error */
+ return(FALSE);
+ ped->cchAlloc = CCHALLOCEXTRA;
+
+ SwapHandle(&lpCreateStruct);
+ SwapHandle(&lpCreateStruct->lpszName);
+
+ /* Set a field in the window to point to the ped so that we can recover the
+ * edit structure in later messages when we are only given the window
+ * handle.
+ */
+ SetWindowWord(hwnd, 0, (WORD)ped);
+
+ ped->hwnd = hwnd;
+ ped->hwndParent = lpCreateStruct->hwndParent;
+
+ if (windowStyle & WS_BORDER)
+ {
+ ped->fBorder = 1;
+ /*
+ * Strip the border bit from the window style since we draw the border
+ * ourselves.
+ */
+ windowStyle = windowStyle & ~WS_BORDER;
+ SetWindowLong(hwnd, GWL_STYLE, windowStyle);
+ }
+
+ return((BOOL)DefWindowProc(hwnd, WM_NCCREATE, 0, (LONG)lpCreateStruct));
+}
+
+
+BOOL FAR PASCAL ECCreate(hwnd, ped, lpCreateStruct)
+HWND hwnd;
+register PED ped;
+LPCREATESTRUCT lpCreateStruct;
+
+/* effects: Creates the edit control for the window hwnd by allocating memory
+ * as required from the application's heap. Notifies parent if no memory
+ * error (after cleaning up if needed). Returns PED if no error else returns
+ * NULL. Just does the stuff which is independent of the style of the edit
+ * control. LocalAllocs done here may cause memory to move...
+ */
+{
+ LONG windowStyle;
+
+
+ /*
+ * Get values from the window instance data structure and put them in the
+ * ped so that we can access them easier.
+ */
+ windowStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ if (windowStyle & ES_AUTOHSCROLL)
+ ped->fAutoHScroll = 1;
+ if (windowStyle & ES_NOHIDESEL)
+ ped->fNoHideSel = 1;
+
+ ped->cchTextMax = MAXTEXT; /* Max # chars we will initially allow */
+
+ /* Set up undo initial conditions... (ie. nothing to undo) */
+ ped->ichDeleted = -1;
+ ped->ichInsStart = -1;
+ ped->ichInsEnd = -1;
+
+ /* Initialize the hilite attributes */
+#ifdef WOW
+ ped->hbrHiliteBk = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
+#else
+ ped->hbrHiliteBk = GetSysClrObject(COLOR_HIGHLIGHT);
+#endif
+ ped->rgbHiliteBk = GetSysColor(COLOR_HIGHLIGHT);
+ ped->rgbHiliteText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+
+ return(TRUE);
+}
+
+
+void FAR PASCAL ECNcDestroyHandler(hwnd,ped,wParam,lParam)
+HWND hwnd;
+register PED ped;
+WORD wParam;
+LONG lParam;
+/*
+ * effects: Destroys the edit control ped by freeing up all memory used by it.
+ */
+{
+ if (ped)
+ /* ped could be NULL if WM_NCCREATE failed to create it... */
+ {
+ if (ped->fFocus)
+ /* Destroy the caret if we have the focus and we are being
+ killed */
+ DestroyCaret();
+
+ LocalFree(ped->hText);
+
+#ifdef WOW
+ DeleteObject(ped->hbrHiliteBk);
+#endif
+ /* Free up undo buffer and line start array (if present) */
+ GlobalFree(ped->hDeletedText);
+ LocalFree((HANDLE)ped->chLines);
+ LocalFree((HANDLE)ped->charWidthBuffer);
+ if (ped->pTabStops)
+ /* Free tab stop buffer if it exists.
+ */
+ LocalFree((HANDLE)ped->pTabStops);
+
+ /* Since a pointer and a handle to a fixed local object are the same */
+ LocalFree((HANDLE)ped);
+ }
+
+ /* In case rogue messages float through after we have freed the ped, set the
+ * handle in the window structure to FFFF and test for this value at the top
+ * of EdWndProc.
+ */
+ SetWindowWord(hwnd,0,(WORD)-1);
+
+ /* Call DefWindowProc to free all little chunks of memory such as szName and
+ * rgwScroll.
+ */
+ DefWindowProc(hwnd,WM_NCDESTROY,wParam,lParam);
+}
+
+
+void FAR PASCAL ECSetPasswordChar(ped, pwchar)
+register PED ped;
+WORD pwchar;
+/* Sets the password char to display. */
+{
+ HDC hdc;
+ LONG style;
+
+ ped->charPasswordChar = pwchar;
+
+ if (pwchar)
+ {
+ hdc = ECGetEditDC(ped, TRUE);
+ ped->cPasswordCharWidth = max(LOWORD(GetTextExtent(hdc,
+ (LPSTR)&pwchar,
+ 1)),
+ 1);
+ ECReleaseEditDC(ped, hdc, TRUE);
+ }
+
+ style = GetWindowLong(ped->hwnd, GWL_STYLE);
+ if (pwchar)
+ style |= ES_PASSWORD;
+ else
+ style = style & (~ES_PASSWORD);
+
+ SetWindowLong(ped->hwnd, GWL_STYLE, style);
+}
+
+
+void FAR PASCAL ECSetFont(ped, hfont, fRedraw)
+register PED ped;
+HANDLE hfont;
+BOOL fRedraw;
+/* effects: Sets the edit control to use the font hfont. warning: Memory
+ * compaction may occur if hfont wasn't previously loaded. If hfont == NULL,
+ * then assume the system font is being used.
+ */
+{
+ register short i;
+ TEXTMETRIC TextMetrics;
+ HDC hdc;
+ HANDLE hOldFont=NULL;
+ RECT rc;
+ PINT charWidth;
+
+ hdc = GetDC(ped->hwnd);
+ ped->hFont = hfont;
+
+ if (hfont)
+ {
+ /* Since the default font is the system font, no need to select it in if
+ * that's what the user wants.
+ */
+ if (!(hOldFont = SelectObject(hdc, hfont)))
+ {
+ hfont = ped->hFont = NULL;
+ }
+ }
+
+ /* Get the metrics and ave char width for the currently selected font */
+ ped->aveCharWidth = GetCharDimensions(hdc, (TEXTMETRIC FAR *)&TextMetrics);
+
+ ped->lineHeight = TextMetrics.tmHeight;
+ ped->charOverhang = TextMetrics.tmOverhang;
+
+ /* Check if Proportional Width Font */
+ ped->fNonPropFont = !(TextMetrics.tmPitchAndFamily & 1);
+
+ /* Get char widths */
+ if (ped->charWidthBuffer)
+ {
+ charWidth = (PINT)LocalLock(ped->charWidthBuffer);
+ if (!GetCharWidth(hdc, 0, 0xff, (LPINT)charWidth))
+ {
+ LocalUnlock(ped->charWidthBuffer);
+ LocalFree((HANDLE)ped->charWidthBuffer);
+ ped->charWidthBuffer=NULL;
+ }
+ else
+ {
+ /* We need to subtract out the overhang associated with each
+ * character since GetCharWidth includes it...
+ */
+ for (i=0;i<=0xff;i++)
+ charWidth[i] -= ped->charOverhang;
+
+ LocalUnlock(ped->charWidthBuffer);
+ }
+ }
+
+#ifdef DBCS
+ /* In DBCS Windows, Edit Control must handle Double Byte Character
+ * in case of charset of the font is 128(Japan) or 129(Korea).
+ */
+ ped->charSet = TextMetrics.tmCharSet;
+ ECGetDBCSVector( ped );
+ ped->fDBCS = 1;
+#endif
+
+ if (!hfont)
+ {
+ /* We are getting the statitics for the system font so update the system
+ * font fields in the ed structure since we use these when determining
+ * the border size of the edit control.
+ */
+ ped->cxSysCharWidth = ped->aveCharWidth;
+ ped->cySysCharHeight= ped->lineHeight;
+ }
+ else
+ SelectObject(hdc, hOldFont);
+
+ if (ped->fFocus)
+ {
+ /* Fix the caret size to the new font if we have the focus. */
+ CreateCaret(ped->hwnd, (HBITMAP)NULL, 2, ped->lineHeight);
+ ShowCaret(ped->hwnd);
+ }
+
+ ReleaseDC(ped->hwnd,hdc);
+
+ if (ped->charPasswordChar)
+ /* Update the password char metrics to match the new font. */
+ ECSetPasswordChar(ped, ped->charPasswordChar);
+
+ if (ped->fSingle)
+ SLSizeHandler(ped);
+ else
+ {
+ MLSizeHandler(ped);
+ /* If word-wrap is not there, then we must calculate the maxPixelWidth
+ * It is done by calling MLBuildChLines;
+ * Also, reposition the scroll bar thumbs.
+ * Fix for Bug #5141 --SANKAR-- 03/14/91 --
+ */
+ if(!ped->fWrap)
+ MLBuildchLines(ped, 0, 0, FALSE);
+ SetScrollPos(ped->hwnd, SB_VERT,
+ (int)MLThumbPosFromPed(ped,TRUE), fRedraw);
+ SetScrollPos(ped->hwnd, SB_HORZ,
+ (int)MLThumbPosFromPed(ped,FALSE), fRedraw);
+ }
+
+ if (fRedraw)
+ {
+ GetWindowRect(ped->hwnd, (LPRECT)&rc);
+ ScreenToClient(ped->hwnd, (LPPOINT)&rc.left);
+ ScreenToClient(ped->hwnd, (LPPOINT)&rc.right);
+ InvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE);
+ UpdateWindow(ped->hwnd);
+ }
+}
diff --git a/private/mvdm/wow16/user/edit.h b/private/mvdm/wow16/user/edit.h
new file mode 100644
index 000000000..3b4273bb9
--- /dev/null
+++ b/private/mvdm/wow16/user/edit.h
@@ -0,0 +1,321 @@
+/*++ BUILD Version: 0001
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDIT.H
+ *
+ * History:
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16
+--*/
+
+/****************************************************************************/
+/* */
+/* EDIT.H - */
+/* */
+/* Edit Control Defines and Procedures */
+/* */
+/****************************************************************************/
+#include "combcom.h"
+
+/* NOTE: Text handle is sized as multiple of this constant
+ * (should be power of 2).
+ */
+#define CCHALLOCEXTRA 0x20
+
+/* Maximum width in pixels for a line/rectangle */
+#define MAXPIXELWIDTH 30000
+
+/* Limit multiline edit controls to at most 1024 characters on a single line.
+ * We will force a wrap if the user exceeds this limit.
+ */
+#define MAXLINELENGTH 1024
+
+#define ES_FMTMASK 0x00000003L
+
+/* Allow an initial maximum of 30000 characters in all edit controls since
+ * some apps will run into unsigned problems otherwise. If apps know about
+ * the 64K limit, they can set the limit themselves.
+ */
+#define MAXTEXT 30000
+
+#define BACKSPACE 0x08
+#define TAB 0x09
+
+/* Key modifiers which have been pressed. Code in KeyDownHandler and
+ CharHandler depend on these exact values. */
+#define NONEDOWN 0 /* Neither shift nor control down */
+#define CTRLDOWN 1 /* Control key only down */
+#define SHFTDOWN 2 /* Shift key only down */
+#define SHCTDOWN 3 /* Shift and control keys down = CTRLDOWN + SHFTDOWN */
+#define NOMODIFY 4 /* Neither shift nor control down */
+
+/* Types of undo supported in this ped */
+#define UNDO_NONE 0 /* We can't undo the last operation. */
+#define UNDO_INSERT 1 /* We can undo the user's insertion of characters */
+#define UNDO_DELETE 2 /* We can undo the user's deletion of characters */
+
+typedef struct tagED
+ {
+ HANDLE hText; /* Block of text we are editing */
+ ICH cchAlloc; /* Number of chars we have allocated for hText
+ */
+ ICH cchTextMax; /* Max number bytes allowed in edit control
+ */
+ ICH cch; /* Current number of bytes of actual text
+ */
+ int cLines; /* Number of lines of text */
+
+ ICH ichMinSel; /* Selection extent. MinSel is first selected
+ char */
+ ICH ichMaxSel; /* MaxSel is first unselected character */
+ ICH ichCaret; /* Caret location. Caret is on left side of
+ char */
+ int iCaretLine; /* The line the caret is on. So that if word
+ * wrapping, we can tell if the caret is at end
+ * of a line of at beginning of next line...
+ */
+ ICH screenStart; /* Index of left most character displayed on
+ * screen for sl ec and index of top most line
+ * for multiline edit controls
+ */
+ int ichLinesOnScreen; /* Number of lines we can display on screen */
+ WORD xOffset; /* x (horizontal) scroll position in pixels
+ * (for multiline text horizontal scroll bar)
+ */
+ WORD charPasswordChar; /* If non null, display this character instead
+ * of the real text. So that we can implement
+ * hidden text fields.
+ */
+ WORD cPasswordCharWidth;/* Width of password char */
+
+ HWND hwnd; /* Window for this edit control */
+ RECT rcFmt; /* Client rectangle */
+ HWND hwndParent; /* Parent of this edit control window */
+
+ /* These vars allow us to automatically scroll
+ * when the user holds the mouse at the bottom
+ * of the multiline edit control window.
+ */
+ POINT ptPrevMouse; /* Previous point for the mouse for system
+ * timer.
+ */
+ WORD prevKeys; /* Previous key state for the mouse */
+
+
+ WORD fSingle : 1; /* Single line edit control? (or multiline) */
+ WORD fNoRedraw : 1; /* Redraw in response to a change? */
+ WORD fMouseDown : 1; /* Is mouse button down? when moving mouse */
+ WORD fFocus : 1; /* Does ec have the focus ? */
+ WORD fDirty : 1; /* Modify flag for the edit control */
+ WORD fDisabled : 1; /* Window disabled? */
+ WORD fNonPropFont : 1; /* Fixed width font? */
+ WORD fBorder : 1; /* Draw a border? */
+ WORD fAutoVScroll : 1; /* Automatically scroll vertically */
+ WORD fAutoHScroll : 1; /* Automatically scroll horizontally */
+ WORD fNoHideSel : 1; /* Hide sel when we lose focus? */
+#ifdef DBCS
+ WORD fDBCS : 1; /* Are we use DBCS font set for editing? */
+#else
+ WORD fKanji : 1;
+#endif
+ WORD fFmtLines : 1; /* For multiline only. Do we insert CR CR LF at
+ * word wrap breaks?
+ */
+ WORD fWrap : 1; /* Do word wrapping? */
+ WORD fCalcLines : 1; /* Recalc ped->chLines array? (recalc line
+ * breaks?)
+ */
+ WORD fEatNextChar : 1; /* Hack for ALT-NUMPAD stuff with combo boxes.
+ * If numlock is up, we want to eat the next
+ * character generated by the keyboard driver
+ * if user enter num pad ascii value...
+ */
+ WORD fStripCRCRLF :1; /* CRCRLFs have been added to text. Strip them
+ * before doing any internal edit control
+ * stuff
+ */
+ WORD fInDialogBox :1; /* True if the ml edit control is in a dialog
+ * box and we have to specially treat TABS and
+ * ENTER
+ */
+ WORD fReadOnly :1; /* Is this a read only edit control? Only
+ * allow scrolling, selecting and copying.
+ */
+ WORD fCaretHidden :1; /* This indicates whether the caret is
+ * currently hidden because the width or height
+ * of the edit control is too small to show it.
+ */
+ int *chLines; /* index of the start of each line */
+ WORD format; /* Left, center, or right justify multiline
+ * text.
+ */
+ LPSTR (FAR *lpfnNextWord)(); /* Next word function */
+ ICH maxPixelWidth; /* Width (in pixels) of longest line */
+
+ WORD undoType; /* Current type of undo we support */
+ HANDLE hDeletedText; /* Handle to text which has been deleted (for
+ undo)
+ */
+ ICH ichDeleted; /* Starting index from which text was deleted*/
+ ICH cchDeleted; /* Count of deleted characters in buffer */
+ ICH ichInsStart; /* Starting index from which text was
+ inserted */
+ ICH ichInsEnd; /* Ending index of inserted text */
+
+
+ HANDLE hFont; /* Handle to the font for this edit control.
+ Null if system font.
+ */
+ int aveCharWidth; /* Ave width of a character in the hFont */
+ int lineHeight; /* Height of a line in the hFont */
+ int charOverhang; /* Overhang associated with the hFont */
+ int cxSysCharWidth; /* System font ave width */
+ int cySysCharHeight; /* System font height */
+ HWND listboxHwnd; /* ListBox hwnd. Non null if we are a combo
+ box */
+ int *pTabStops; /* Points to an array of tab stops; First
+ * element contains the number of elements in
+ * the array
+ */
+ HANDLE charWidthBuffer;
+ HBRUSH hbrHiliteBk; /* Hilite background color brush. */
+ DWORD rgbHiliteBk; /* Hilite background color */
+ DWORD rgbHiliteText; /* Hilite Text color */
+#ifdef DBCS
+ BYTE charSet; /* Character set for current selected font */
+ HANDLE hDBCSVector; /* Handle to the DBCS vector table */
+ BYTE DBCSVector[8]; /* DBCS vector table which contains flag
+ * to detect lead byte of DBC.
+ */
+#endif
+ } ED;
+
+typedef ED *PED;
+
+
+/* The following structure is used to store a selection block; In Multiline
+ * edit controls, "StPos" and "EndPos" fields contain the Starting and Ending
+ * lines of the block. In Single line edit controls, "StPos" and "EndPos"
+ * contain the Starting and Ending character positions of the block;
+ */
+typedef struct tagBLOCK
+ {
+ ICH StPos;
+ ICH EndPos;
+ } BLOCK;
+typedef BLOCK FAR *LPBLOCK;
+
+
+
+BOOL FAR PASCAL ECNcCreate(HWND, LPCREATESTRUCT);
+BOOL FAR PASCAL ECCreate(HWND, PED, LPCREATESTRUCT);
+LONG FAR PASCAL ECWord(PED, ICH, BOOL); /* no register for PED */
+ICH FAR PASCAL ECFindTab(LPSTR, register ICH);
+void FAR PASCAL ECNcDestroyHandler(HWND, register PED, WORD, LONG);
+BOOL FAR PASCAL ECSetText(register PED, LPSTR);
+void FAR PASCAL ECSetPasswordChar(register PED, WORD);
+ICH FAR PASCAL ECCchInWidth(register PED, HDC, LPSTR, register ICH, unsigned int);
+void FAR PASCAL ECEmptyUndo(register PED);
+BOOL FAR PASCAL ECInsertText(register PED, LPSTR, ICH);
+ICH FAR PASCAL ECDeleteText(register PED);
+void FAR PASCAL ECNotifyParent(register PED, short);
+void FAR PASCAL ECSetEditClip(register PED, HDC);
+HDC FAR PASCAL ECGetEditDC(register PED, BOOL);
+void FAR PASCAL ECReleaseEditDC(register PED, HDC, BOOL);
+void FAR PASCAL ECCreateHandler(register PED);
+ICH FAR PASCAL ECGetTextHandler(register PED, register ICH, LPSTR);
+void FAR PASCAL ECSetFont(register PED, HANDLE, BOOL);
+ICH FAR PASCAL ECCopyHandler(register PED);
+BOOL FAR PASCAL ECCalcChangeSelection(PED, ICH, ICH, LPBLOCK, LPBLOCK);
+void NEAR PASCAL ECFindXORblks(LPBLOCK, LPBLOCK, LPBLOCK, LPBLOCK);
+LONG FAR PASCAL ECTabTheTextOut(HDC, int, int, LPSTR, int, PED, int, BOOL);
+
+/****************************************************************************/
+/* Multi-Line Support Routines */
+/****************************************************************************/
+
+ICH FAR PASCAL MLInsertText(PED, LPSTR, WORD, BOOL);
+BOOL FAR PASCAL MLEnsureCaretVisible(register PED);
+void NEAR PASCAL MLDrawText(register PED, HDC, ICH, ICH);
+void NEAR PASCAL MLDrawLine(register PED, HDC, int, ICH, int, BOOL);
+void NEAR PASCAL MLPaintABlock(PED, HDC, int, int);
+int NEAR PASCAL GetBlkEndLine(int, int, BOOL FAR *, int, int);
+LONG FAR PASCAL MLBuildchLines(register PED, int, int, BOOL);
+void NEAR PASCAL MLShiftchLines(register PED, register int, int);
+BOOL NEAR PASCAL MLInsertchLine(register PED, int, ICH, BOOL);
+void FAR PASCAL MLSetCaretPosition(register PED,HDC);
+LONG NEAR PASCAL MLIchToXYPos(register PED, HDC, ICH, BOOL);
+int FAR PASCAL MLIchToLineHandler(register PED, ICH);
+void NEAR PASCAL MLRepaintChangedSelection(PED, HDC, ICH, ICH);
+void NEAR PASCAL MLMouseMotionHandler(PED, WORD, WORD, POINT);
+ICH FAR PASCAL MLLineLength(register PED, int);
+void FAR PASCAL MLStripCrCrLf(register PED);
+BOOL FAR PASCAL MLSetTextHandler(register PED, LPSTR);
+int FAR PASCAL MLCalcXOffset(register PED, HDC, int);
+BOOL FAR PASCAL MLUndoHandler(register PED);
+LONG FAR PASCAL MLEditWndProc(HWND, register PED, WORD, register WORD, LONG);
+void FAR PASCAL MLCharHandler(PED, WORD, int);
+void FAR PASCAL MLSetSelectionHandler(register PED, ICH, ICH);
+LONG FAR PASCAL MLCreateHandler(HWND, PED, LPCREATESTRUCT);
+BOOL FAR PASCAL MLInsertCrCrLf(register PED);
+void FAR PASCAL MLSetHandleHandler(register PED, HANDLE);
+LONG FAR PASCAL MLGetLineHandler(register PED, WORD, ICH, LPSTR);
+ICH FAR PASCAL MLLineIndexHandler(register PED, register int);
+ICH FAR PASCAL MLLineLengthHandler(register PED, ICH);
+void FAR PASCAL MLSizeHandler(register PED);
+void FAR PASCAL MLChangeSelection(register PED, HDC, ICH, ICH);
+void FAR PASCAL MLSetRectHandler(register PED, LPRECT);
+BOOL FAR PASCAL MLExpandTabs(register PED);
+BOOL FAR PASCAL MLSetTabStops(PED, int, LPINT);
+int FAR PASCAL MLThumbPosFromPed(register PED, BOOL);
+
+/****************************************************************************/
+/* Single Line Support Routines */
+/****************************************************************************/
+
+void NEAR PASCAL SLReplaceSelHandler(register PED, LPSTR);
+BOOL FAR PASCAL SLUndoHandler(register PED);
+void FAR PASCAL SLSetCaretPosition(register PED, HDC);
+int NEAR PASCAL SLIchToLeftXPos(register PED, HDC, ICH);
+void FAR PASCAL SLChangeSelection(register PED, HDC, ICH, ICH);
+void NEAR PASCAL SLDrawText(register PED, register HDC, ICH);
+void NEAR PASCAL SLDrawLine(register PED, register HDC, ICH, int, BOOL);
+int NEAR PASCAL SLGetBlkEnd(PED, ICH, ICH, BOOL FAR *);
+BOOL FAR PASCAL SLScrollText(register PED, HDC);
+void FAR PASCAL SLSetSelectionHandler(register PED,ICH, ICH);
+ICH FAR PASCAL SLInsertText(register PED, LPSTR, register ICH);
+ICH NEAR PASCAL SLPasteText(register PED);
+void FAR PASCAL SLCharHandler(register PED, WORD, int);
+void NEAR PASCAL SLKeyUpHandler(register PED, WORD);
+void NEAR PASCAL SLKeyDownHandler(register PED, WORD, int);
+ICH NEAR PASCAL SLMouseToIch(register PED, HDC, POINT);
+void NEAR PASCAL SLMouseMotionHandler(register PED, WORD, WORD, POINT);
+LONG FAR PASCAL SLCreateHandler(HWND, PED, LPCREATESTRUCT);
+void FAR PASCAL SLSizeHandler(register PED);
+void NEAR PASCAL SLPaintHandler(register PED, HDC);
+BOOL FAR PASCAL SLSetTextHandler(register PED, LPSTR);
+void NEAR PASCAL SLSetFocusHandler(register PED);
+void NEAR PASCAL SLKillFocusHandler(register PED, HWND);
+LONG FAR PASCAL SLEditWndProc(HWND, register PED, WORD, register WORD, LONG);
+
+
+/****************************************************************************/
+/* EditWndProc() */
+/****************************************************************************/
+LONG FAR PASCAL EditWndProc(HWND, WORD, register WORD, LONG);
+
+
+#ifdef DBCS
+/****************************************************************************/
+/* DBCS Support Routines */
+/****************************************************************************/
+int FAR PASCAL DBCSCombine( HWND, int );
+ICH FAR PASCAL ECAdjustIch( PED, LPSTR, ICH );
+VOID FAR PASCAL ECGetDBCSVector( PED );
+LPSTR FAR PASCAL ECAnsiNext( PED, LPSTR );
+LPSTR FAR PASCAL ECAnsiPrev( PED, LPSTR, LPSTR );
+BOOL FAR PASCAL ECIsDBCSLeadByte( PED, BYTE );
+#endif
diff --git a/private/mvdm/wow16/user/editec.c b/private/mvdm/wow16/user/editec.c
new file mode 100644
index 000000000..c48f6a2d2
--- /dev/null
+++ b/private/mvdm/wow16/user/editec.c
@@ -0,0 +1,1641 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDITEC.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* editec.c - Edit controls rewrite. Version II of edit controls. */
+/* */
+/* */
+/* Created: 24-Jul-88 davidds */
+/****************************************************************************/
+
+/* Warning: The single line editcontrols contain internal styles and API which
+ * are need to support comboboxes. They are defined in combcom.h/combcom.inc
+ * and may be redefined or renumbered as needed.
+ */
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Handlers common to both single and multi line edit controls. */
+/****************************************************************************/
+LONG FAR PASCAL ECTabTheTextOut(hdc, x, y, lpstring, nCount, ped, iTabOrigin,
+ fDrawTheText)
+HDC hdc;
+int x;
+int y;
+register int nCount; /* Count of chars in string */
+LPSTR lpstring;
+register PED ped;
+int iTabOrigin; /* Tab stops are with respect to this */
+BOOL fDrawTheText;
+/* effects: Outputs the tabbed text if fDrawTheText is TRUE and returns the
+ * textextent of the tabbed text. This is a local function for edit control
+ * use so that it can be optimized for speed.
+ */
+{
+ int nTabPositions; /* Count of tabstops in tabstop array */
+ LPINT lpintTabStopPositions; /* Tab stop positions in pixels */
+
+ int initialx = x; /* Save the initial x value so that we can get
+ total width of the string */
+ int cch;
+ int textextent;
+ int pixeltabstop = 0;
+ int i;
+ int cxCharWidth;
+ int cyCharHeight = 0;
+ RECT rc;
+ BOOL fOpaque = GetBkMode(hdc) == OPAQUE;
+ PINT charWidthBuff;
+
+ if (!lpstring || !nCount)
+ return(MAKELONG(0,0));
+
+ nTabPositions = (ped->pTabStops ? *(ped->pTabStops) : 0);
+ lpintTabStopPositions = (LPINT)(ped->pTabStops ? (ped->pTabStops+1): NULL);
+
+ cxCharWidth = ped->aveCharWidth;
+ cyCharHeight = ped->lineHeight;
+
+ /* If no tabstop positions are specified, then use a default of 8 system
+ * font ave char widths or use the single fixed tab stop.
+ */
+ if (!lpintTabStopPositions)
+ pixeltabstop = 8*cxCharWidth;
+ else
+ {
+ if (nTabPositions == 1)
+ {
+ pixeltabstop = lpintTabStopPositions[0];
+
+ if (!pixeltabstop)
+ pixeltabstop=1;
+ }
+ }
+
+ rc.left = initialx;
+ rc.top = y;
+ rc.bottom = rc.top+cyCharHeight;
+
+ while(nCount)
+ {
+ if (ped->charWidthBuffer)
+ {
+ charWidthBuff = (PINT)LMHtoP(ped->charWidthBuffer);
+ textextent=0;
+ /* Initially assume no tabs exist in the text so cch=nCount.
+ */
+ cch = nCount;
+ for (i=0; i<nCount; i++)
+ {
+ /* Warning danger. We gotta be careful here and convert lpstr
+ * (which is a SIGNED char) into an unsigned char before using
+ * it to index into the array otherwise the C Compiler screws
+ * us and gives a negative number...
+ */
+#ifdef DBCS
+ if (ECIsDBCSLeadByte(ped,lpstring[i])
+ && i+1 < nCount) {
+ textextent += LOWORD(GetTextExtent(hdc,&lpstring[i],2));
+ i++;
+ } else if (lpstring[i] == TAB ){
+ cch = i;
+ break;
+ } else
+ textextent += (charWidthBuff[(WORD)(((unsigned char FAR *)lpstring)[i])]);
+#else
+ if (lpstring[i] == TAB)
+ {
+ cch = i;
+ break;
+ }
+
+ textextent += (charWidthBuff[(WORD)(((unsigned char FAR *)lpstring)[i])]);
+#endif
+ }
+
+ nCount = nCount - cch;
+ }
+ else
+ {
+ /* Gotta call the driver to do our text extent.
+ */
+ cch = (int)ECFindTab(lpstring, nCount);
+ nCount = nCount - cch;
+ textextent = LOWORD(GetTextExtent(hdc, lpstring, cch));
+ }
+
+
+ if (fDrawTheText)
+ {
+ /* Output all text up to the tab (or end of string) and get its
+ * extent.
+ */
+ rc.right = x+LOWORD(textextent);
+ ExtTextOut(hdc,x, y, (fOpaque ? ETO_OPAQUE : 0),
+ (LPRECT)&rc, lpstring, cch, 0L);
+ rc.left = rc.right;
+ }
+
+ if (!nCount)
+ /* If we're at the end of the string, just return without bothering
+ * to calc next tab stop.
+ */
+ return(MAKELONG(LOWORD(textextent)+(x-initialx),cyCharHeight));
+
+ /* Find the next tab position and update the x value.
+ */
+ if (pixeltabstop)
+ x = (((x-iTabOrigin+LOWORD(textextent))/pixeltabstop)*pixeltabstop)+
+ pixeltabstop + iTabOrigin;
+ else
+ {
+ x += LOWORD(textextent);
+ for (i=0; i < nTabPositions; i++)
+ {
+ if (x < (lpintTabStopPositions[i] + iTabOrigin))
+ {
+ x = (lpintTabStopPositions[i] + iTabOrigin);
+ break;
+ }
+ }
+ /* Check if all the tabstops set are exhausted; Then start using
+ * default tab stop positions.
+ */
+ if (i == nTabPositions)
+ {
+ pixeltabstop = 8 * cxCharWidth;
+ x = ((x - iTabOrigin)/pixeltabstop)*pixeltabstop +
+ pixeltabstop + iTabOrigin;
+ }
+ }
+
+ /* Skip over the tab and the characters we just drew.
+ */
+ lpstring += (cch+1);
+ nCount--; /* Skip over tab */
+ if (!nCount && fDrawTheText)
+ {
+ /* This string ends with a tab. We need to opaque the rect produced
+ * by this tab...
+ */
+ rc.right = x;
+ ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE,
+ (LPRECT)&rc, "", 0, 0L);
+ }
+ }
+
+ return(MAKELONG((x-initialx), cyCharHeight));
+}
+
+
+
+ICH FAR PASCAL ECCchInWidth(ped, hdc, lpText, cch, width)
+register PED ped;
+HDC hdc;
+LPSTR lpText;
+register ICH cch;
+unsigned int width;
+/* effects: Returns maximum count of characters (up to cch) from the given
+ * string which will fit in the given width. ie. Will tell you how much of
+ * lpstring will fit in the given width even when using proportional
+ * characters. WARNING: If we use kerning, then this loses...
+ */
+{
+ int stringExtent;
+ int cchhigh;
+ int cchnew = 0;
+ int cchlow = 0;
+
+ if ((width<=0) || !cch)
+ return(0);
+
+ /* Optimize nonproportional fonts for single line ec since they don't have
+ * tabs.
+ */
+ if (ped->fNonPropFont && ped->fSingle)
+ /* umin is unsigned min function */
+ return(umin(width/ped->aveCharWidth,cch));
+
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ return(umin(width/ped->cPasswordCharWidth,cch));
+
+ cchhigh = cch+1;
+ while (cchlow < cchhigh-1)
+ {
+ cchnew = umax((cchhigh - cchlow)/2,1)+cchlow;
+
+ if (ped->fSingle)
+ stringExtent = LOWORD(GetTextExtent(hdc, (LPSTR)lpText, cchnew));
+ else
+ stringExtent = LOWORD(ECTabTheTextOut(hdc, 0, 0,
+ (LPSTR)lpText,
+ cchnew,
+ ped, 0, FALSE));
+
+ if (stringExtent > width)
+ cchhigh = cchnew;
+ else
+ cchlow = cchnew;
+ }
+#ifdef DBCS
+ cchlow = ECAdjustIch( ped, lpText, cchlow );
+#endif
+ return(cchlow);
+}
+
+
+ICH FAR PASCAL ECFindTab(lpstr, cch)
+LPSTR lpstr;
+register ICH cch;
+/* effects: Scans lpstr and returns the number of chars till the first TAB.
+ * Scans at most cch chars of lpstr.
+ */
+{
+ LPSTR copylpstr = lpstr;
+
+ if (!cch)
+ return(0);
+
+ while (*lpstr != TAB)
+ {
+ lpstr++;
+ if (--cch == 0)
+ break;
+ }
+ return((ICH)(lpstr - copylpstr));
+
+}
+
+
+BOOL NEAR _fastcall ECIsDelimiter(char bCharVal)
+{
+ return((bCharVal == ' ') || (bCharVal == '\t'));
+}
+
+LONG FAR PASCAL ECWord(ped, ichStart, fLeft)
+PED ped; /* Yes, I mean no register ped */
+ICH ichStart;
+BOOL fLeft;
+/* effects: if fLeft Returns the ichMinSel and ichMaxSel of the word to the
+ * left of ichStart. ichMinSel contains the starting letter of the word,
+ * ichmaxsel contains all spaces up to the first character of the next word.
+ *
+ * if !fLeft Returns the ichMinSel and ichMaxSel of the word to the right of
+ * ichStart. ichMinSel contains the starting letter of the word, ichmaxsel
+ * contains the first letter of the next word. If ichStart is in the middle
+ * of a word, that word is considered the left or right word. ichMinSel is in
+ * the low order word and ichMaxSel is in the high order word. ichMinSel is
+ * in the low order word and ichMaxSel is in the high order word. A CR LF
+ * pair or CRCRLF triple is considered a single word for the purposes of
+ * multiline edit controls.
+ */
+{
+ PSTR pText;
+ register PSTR pWordMinSel;
+ register PSTR pWordMaxSel;
+ BOOL charLocated=FALSE;
+ BOOL spaceLocated=FALSE;
+#ifdef DBCS
+ PSTR pWordStr;
+ BOOL fAlpha = FALSE;
+#endif
+
+ if ((!ichStart && fLeft) || (ichStart == ped->cch && !fLeft))
+ /* We are at the beginning of the text (looking left) or we are at end
+ * of text (looking right), no word here
+ */
+ return(0L);
+
+ pText = (PSTR) LocalLock(ped->hText);
+ pWordMinSel = pWordMaxSel = pText+ichStart;
+
+ /* if fLeft: Move pWordMinSel to the left looking for the start of a word.
+ * If we start at a space, we will include spaces in the selection as we
+ * move left untill we find a nonspace character. At that point, we continue
+ * looking left until we find a space. Thus, the selection will consist of
+ * a word with its trailing spaces or, it will consist of any leading at the
+ * beginning of a line of text.
+ */
+
+ /* if !fLeft: (ie. right word) Move pWordMinSel looking for the start of a
+ * word. If the pWordMinSel points to a character, then we move left
+ * looking for a space which will signify the start of the word. If
+ * pWordMinSel points to a space, we look right till we come upon a
+ * character. pMaxWord will look right starting at pMinWord looking for the
+ * end of the word and its trailing spaces.
+ */
+
+
+#ifdef DBCS
+ if (fLeft || (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0D && !ECIsDBCSLeadByte(ped,*pWordMinSel)))
+#else
+ if (fLeft || (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0D))
+#endif
+ /* If we are moving left or if we are moving right and we are not on a
+ * space or a CR (the start of a word), then we was look left for the
+ * start of a word which is either a CR or a character. We do this by
+ * looking left till we find a character (or if CR we stop), then we
+ * continue looking left till we find a space or LF.
+ */
+ {
+#ifdef DBCS
+ while (pWordMinSel > pText &&
+ ((!ECIsDelimiter(*(pWordStr=(PSTR)LOWORD(ECAnsiPrev(ped,pText,pWordMinSel)))) && *pWordStr != 0x0A) ||
+ !charLocated)) /* DBCS */
+ { /* DBCS */
+ if (!fLeft && /* DBCS */
+ (ECIsDelimiter(*(pWordStr=ECAnsiPrev(ped,pText,pWordMinSel))) || /* DBCS */
+ *pWordStr == 0x0A)) /* DBCS */
+#else
+ while (pWordMinSel > pText &&
+ ((!ECIsDelimiter(*(pWordMinSel-1)) && *(pWordMinSel-1) != 0x0A) ||
+ !charLocated))
+ {
+ if (!fLeft &&
+ (ECIsDelimiter(*(pWordMinSel-1)) ||
+ *(pWordMinSel-1) == 0x0A))
+#endif
+ /*
+ * If we are looking for the start of the word right, then we
+ * stop when we have found it. (needed in case charLocated is
+ * still FALSE)
+ */
+ break;
+
+#ifdef DBCS
+ if( !ECIsDBCSLeadByte(ped,*pWordMinSel) && !ECIsDelimiter(*pWordMinSel) &&
+ *pWordMinSel != 0x0d && *pWordMinSel != 0x0a &&
+ pWordMinSel != pText+ichStart )
+ fAlpha = TRUE;
+#endif
+
+#ifdef DBCS
+ pWordMinSel = ECAnsiPrev(ped,pText,pWordMinSel);
+#else
+ pWordMinSel--;
+#endif
+
+#ifdef DBCS
+ if( ECIsDBCSLeadByte(ped, *pWordMinSel ) ){
+ if( !fLeft || fAlpha )
+ pWordMinSel = ECAnsiNext(ped,pWordMinSel);
+ break;
+ }
+#endif
+
+ if (!ECIsDelimiter(*pWordMinSel) && *pWordMinSel != 0x0A)
+ /*
+ * We have found the last char in the word. Continue looking
+ * backwards till we find the first char of the word
+ */
+ {
+ charLocated = TRUE;
+ /* We will consider a CR the start of a word */
+ if (*pWordMinSel == 0x0D)
+ break;
+ }
+
+ }
+ }
+ else
+ {
+ /* We are moving right and we are in between words so we need to move
+ * right till we find the start of a word (either a CR or a character.
+ */
+ while ((ECIsDelimiter(*pWordMinSel) ||
+ *pWordMinSel == 0x0A) &&
+ pWordMinSel<pText+ped->cch)
+ pWordMinSel++;
+
+ }
+
+#ifdef DBCS
+ pWordMaxSel = (PSTR) umin((WORD)ECAnsiNext(ped,pWordMinSel),(WORD)pText+ped->cch);
+#else
+ pWordMaxSel = (PSTR) umin((WORD)pWordMinSel+1,(WORD)pText+ped->cch);
+#endif
+ if (*pWordMinSel == 0x0D)
+ {
+#ifdef DBCS
+ if (pWordMinSel>pText && *(ECAnsiPrev(ped,pText,pWordMinSel)) == 0x0D)
+#else
+ if (pWordMinSel>pText && *(pWordMinSel-1) == 0x0D)
+#endif
+ /* So that we can treat CRCRLF as one word also. */
+ pWordMinSel--;
+ else if (*(pWordMinSel+1) == 0x0D)
+ /* Move MaxSel on to the LF */
+ pWordMaxSel++;
+ }
+
+
+ /* Check if we have a one character word */
+ if (ECIsDelimiter(*pWordMaxSel))
+ spaceLocated = TRUE;
+
+ /* Move pWordMaxSel to the right looking for the end of a word and its
+ * trailing spaces. WordMaxSel stops on the first character of the next
+ * word. Thus, we break either at a CR or at the first nonspace char after
+ * a run of spaces or LFs.
+ */
+ while ((pWordMaxSel < pText+ped->cch) &&
+ (!spaceLocated || (ECIsDelimiter(*pWordMaxSel))))
+
+ {
+ if (*pWordMaxSel == 0x0D)
+ break;
+
+#ifdef DBCS
+ if( ECIsDBCSLeadByte(ped,*pWordMaxSel) )
+ break;
+ else if( !ECIsDelimiter(*pWordMaxSel) && *pWordMaxSel != 0x0a &&
+ *pWordMaxSel != 0x0d && ECIsDBCSLeadByte(ped,*pWordMinSel) )
+ break;
+#endif
+
+#ifdef DBCS
+ pWordMaxSel = ECAnsiNext(ped,pWordMaxSel);
+#else
+ pWordMaxSel++;
+#endif
+
+ if (ECIsDelimiter(*pWordMaxSel))
+ spaceLocated = TRUE;
+
+
+#ifdef DBCS
+ if (*(ECAnsiPrev(ped,pText,pWordMaxSel)) == 0x0A)
+ break;
+#else
+ if (*(pWordMaxSel-1) == 0x0A)
+ break;
+#endif
+ }
+
+
+ LocalUnlock(ped->hText);
+
+ return(MAKELONG(pWordMinSel-pText,pWordMaxSel-pText));
+}
+
+
+void FAR PASCAL ECEmptyUndo(ped)
+register PED ped;
+/* effects: empties the undo buffer.
+ */
+{
+ ped->undoType = UNDO_NONE;
+ if (ped->hDeletedText)
+ {
+ GlobalFree(ped->hDeletedText);
+ ped->hDeletedText = NULL;
+ }
+}
+
+
+BOOL FAR PASCAL ECInsertText(ped, lpText, cchInsert)
+register PED ped;
+LPSTR lpText;
+ICH cchInsert;
+/* effects: Adds cch characters from lpText into the ped->hText starting at
+ * ped->ichCaret. Returns TRUE if successful else FALSE. Updates
+ * ped->cchAlloc and ped->cch properly if additional memory was allocated or
+ * if characters were actually added. Updates ped->ichCaret to be at the end
+ * of the inserted text. min and maxsel are equal to ichcaret.
+ */
+{
+ register PSTR pedText;
+ PSTR pTextBuff;
+ LONG style;
+ WORD i;
+ WORD allocamt;
+ HANDLE hTextCopy;
+ WORD lcompact;
+
+#ifdef DBCS
+ /* Make sure we don't split a DBCS in half - 05/15/90 */
+ cchInsert = ECAdjustIch(ped, lpText, cchInsert);
+#endif
+
+ if (!cchInsert)
+ return(TRUE);
+
+ /* Do we already have enough memory?? */
+ if (cchInsert >= (ped->cchAlloc - ped->cch))
+ {
+ /* Save lpText across the allocs */
+ SwapHandle(&lpText);
+
+ /* Allocate what we need plus a little extra. Return FALSE if we are
+ * unsuccessful.
+ */
+ allocamt = ped->cch+cchInsert;
+
+ if (allocamt+CCHALLOCEXTRA > allocamt)
+ /* Need to avoid wrapping around 64K if ped->cch+cchInsert is close
+ * to 64K.
+ */
+ allocamt += CCHALLOCEXTRA;
+
+ if (!ped->fSingle)
+ {
+ /* If multiline, try reallocing the text allowing it to be movable.
+ * If it fails, move the line break array out of the way and try
+ * again. We really fail if this doesn't work...
+ */
+ hTextCopy = LocalReAlloc(ped->hText, allocamt, LHND);
+ if (hTextCopy)
+ ped->hText = hTextCopy;
+ else
+ {
+ /* If the above localrealloc fails, we need to take extreme
+ * measures to try to alloc some memory. This is because the
+ * local memory manager is broken when dealing with large
+ * reallocs.
+ */
+ if (ped->chLines)
+ {
+ hTextCopy = (HANDLE)LocalReAlloc((HANDLE)ped->chLines,
+ LocalSize((HANDLE)ped->chLines),
+ LHND);
+ if (!hTextCopy)
+ return(FALSE);
+ ped->chLines = (int *)hTextCopy;
+ }
+ LocalShrink(0,0x100);
+
+ lcompact = umin(allocamt, CCHALLOCEXTRA*100);
+ hTextCopy = LocalAlloc(LHND|LMEM_NOCOMPACT|LMEM_NODISCARD,
+ lcompact);
+ if (hTextCopy)
+ LocalFree(hTextCopy);
+
+ hTextCopy = LocalReAlloc(ped->hText, allocamt, LHND);
+ if (hTextCopy)
+ ped->hText = hTextCopy;
+ else
+ return(FALSE);
+ }
+ }
+ else
+ {
+ if (!LocalReAlloc(ped->hText, allocamt, 0))
+ return(FALSE);
+ }
+
+ ped->cchAlloc = LocalSize(ped->hText);
+ /* Restore lpText */
+ SwapHandle(&lpText);
+ }
+
+ /* Ok, we got the memory. Now copy the text into the structure
+ */
+ pedText = (PSTR) LocalLock(ped->hText);
+
+ /* Get a pointer to the place where text is to be inserted */
+ pTextBuff = pedText + ped->ichCaret;
+ if (ped->ichCaret != ped->cch)
+ {
+ /* We are inserting text into the middle. We have to shift text to the
+ * right before inserting new text.
+ */
+ LCopyStruct( (LPSTR)pTextBuff,
+ (LPSTR)(pTextBuff + cchInsert),
+ ped->cch-ped->ichCaret);
+ }
+ /* Make a copy of the text being inserted in the edit buffer. */
+ /* Use this copy for doing UPPERCASE/LOWERCASE ANSI/OEM conversions */
+ /* Fix for Bug #3406 -- 01/29/91 -- SANKAR -- */
+ LCopyStruct(lpText, (LPSTR)pTextBuff, cchInsert);
+
+#ifndef PMODE
+ LockData(0); /* Calls to Language drivers are made later; So, to be safe.*/
+#endif
+
+ /* We need to get the style this way since edit controls use their own ds.
+ */
+ style = GetWindowLong(ped->hwnd, GWL_STYLE);
+ if (style & ES_LOWERCASE)
+ AnsiLowerBuff((LPSTR)pTextBuff, cchInsert);
+ else
+ if (style & ES_UPPERCASE)
+ AnsiUpperBuff((LPSTR)pTextBuff, cchInsert);
+
+#ifdef DBCS
+ if( style & ES_OEMCONVERT ){
+ for( i = 0; i < cchInsert; i++ ){
+ /* Do not make any case conversion if a character is DBCS */
+ if( ECIsDBCSLeadByte(ped, *((LPSTR)pTextBuff+i) ) )
+ i++;
+ else {
+ if( IsCharLower( *((LPSTR)pTextBuff+i) ) ){
+ AnsiUpperBuff( (LPSTR)pTextBuff+i, 1 );
+ AnsiToOemBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
+ OemToAnsiBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
+ AnsiLowerBuff( (LPSTR)pTextBuff+i, 1 );
+ } else {
+ AnsiToOemBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
+ OemToAnsiBuff( (LPSTR)pTextBuff+i, (LPSTR)pTextBuff+i, 1 );
+ }
+ }
+ }
+ }
+#else
+ if (style & ES_OEMCONVERT)
+ {
+ for (i=0;i<cchInsert;i++)
+ {
+ if (IsCharLower(*((LPSTR)pTextBuff+i)))
+ {
+ AnsiUpperBuff((LPSTR)pTextBuff+i, 1);
+ AnsiToOemBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
+ OemToAnsiBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
+ AnsiLowerBuff((LPSTR)pTextBuff+i,1);
+ }
+ else
+ {
+ AnsiToOemBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
+ OemToAnsiBuff((LPSTR)pTextBuff+i,(LPSTR)pTextBuff+i,1);
+ }
+ }
+ }
+#endif
+#ifndef PMODE
+ UnlockData(0);
+#endif
+
+ LocalUnlock(ped->hText); /* Hereafter pTextBuff is invalid */
+
+ /* Adjust UNDO fields so that we can undo this insert... */
+ if (ped->undoType == UNDO_NONE)
+ {
+ ped->undoType = UNDO_INSERT;
+ ped->ichInsStart = ped->ichCaret;
+ ped->ichInsEnd = ped->ichCaret+cchInsert;
+ }
+ else
+ if (ped->undoType & UNDO_INSERT)
+ {
+ if (ped->ichInsEnd == ped->ichCaret)
+ ped->ichInsEnd += cchInsert;
+ else
+ {
+UNDOINSERT:
+ if (ped->ichDeleted != ped->ichCaret)
+ {
+ /* Free Deleted text handle if any since user is inserting into
+ a different point. */
+ GlobalFree(ped->hDeletedText);
+ ped->hDeletedText = NULL;
+ ped->ichDeleted = -1;
+ ped->undoType &= ~UNDO_DELETE;
+ }
+ ped->ichInsStart = ped->ichCaret;
+ ped->ichInsEnd = ped->ichCaret+cchInsert;
+ ped->undoType |= UNDO_INSERT;
+ }
+ }
+ else
+ if (ped->undoType == UNDO_DELETE)
+ {
+ goto UNDOINSERT;
+ }
+
+ ped->cch += cchInsert;
+ ped->ichMinSel = ped->ichMaxSel = (ped->ichCaret += cchInsert);
+ /* Set dirty bit */
+ ped->fDirty = TRUE;
+
+ return(TRUE);
+}
+
+
+ICH FAR PASCAL ECDeleteText(ped)
+register PED ped;
+/* effects: Deletes the text between ped->ichMinSel and ped->ichMaxSel. The
+ * character at ichMaxSel is not deleted. But the character at ichMinSel is
+ * deleted. ped->cch is updated properly and memory is deallocated if enough
+ * text is removed. ped->ichMinSel, ped->ichMaxSel, and ped->ichCaret are set
+ * to point to the original ped->ichMinSel. Returns the number of characters
+ * deleted.
+ */
+{
+ register PSTR pedText;
+ ICH cchDelete;
+ LPSTR lpDeleteSaveBuffer;
+ HANDLE hDeletedText;
+ WORD bufferOffset;
+
+ cchDelete = ped->ichMaxSel - ped->ichMinSel;
+
+ if (!cchDelete)
+ return(0);
+
+ /* Ok, now lets delete the text. */
+
+ pedText = (PSTR) LocalLock(ped->hText);
+
+ /* Adjust UNDO fields so that we can undo this delete... */
+ if (ped->undoType == UNDO_NONE)
+ {
+UNDODELETEFROMSCRATCH:
+ if (ped->hDeletedText = GlobalAlloc(GHND, (LONG)(cchDelete+1)))
+ {
+ ped->undoType = UNDO_DELETE;
+ ped->ichDeleted = ped->ichMinSel;
+ ped->cchDeleted = cchDelete;
+ lpDeleteSaveBuffer = GlobalLock(ped->hDeletedText);
+ LCopyStruct((LPSTR)(pedText+ped->ichMinSel),
+ lpDeleteSaveBuffer,
+ cchDelete);
+ lpDeleteSaveBuffer[cchDelete]=0;
+ GlobalUnlock(ped->hDeletedText);
+ }
+ }
+ else
+ if (ped->undoType & UNDO_INSERT)
+ {
+UNDODELETE:
+ ped->undoType = UNDO_NONE;
+ ped->ichInsStart = ped->ichInsEnd = -1;
+ GlobalFree(ped->hDeletedText);
+ ped->hDeletedText = NULL;
+ ped->ichDeleted = -1;
+ ped->cchDeleted = 0;
+ goto UNDODELETEFROMSCRATCH;
+ }
+ else
+ if (ped->undoType == UNDO_DELETE)
+ {
+ if (ped->ichDeleted == ped->ichMaxSel)
+ {
+ /* Copy deleted text to front of undo buffer */
+ hDeletedText = GlobalReAlloc(ped->hDeletedText,
+ (LONG)(cchDelete+ped->cchDeleted+1),
+ GHND);
+ if (!hDeletedText)
+ goto UNDODELETE;
+ bufferOffset = 0;
+ ped->ichDeleted = ped->ichMinSel;
+ }
+ else
+ if (ped->ichDeleted == ped->ichMinSel)
+ {
+ /* Copy deleted text to end of undo buffer */
+ hDeletedText = GlobalReAlloc(ped->hDeletedText,
+ (LONG)(cchDelete+ped->cchDeleted+1),
+ GHND);
+ if (!hDeletedText)
+ goto UNDODELETE;
+ bufferOffset = ped->cchDeleted;
+ }
+ else
+ /* Clear the current UNDO delete and add the new one since
+ the deletes aren't contigous. */
+ goto UNDODELETE;
+
+
+ ped->hDeletedText = hDeletedText;
+ lpDeleteSaveBuffer = (LPSTR)GlobalLock(hDeletedText);
+ if (!bufferOffset)
+ {
+ /* Move text in delete buffer up so that we can insert the next
+ text at the head of the buffer. */
+ LCopyStruct(lpDeleteSaveBuffer,
+ (LPSTR)(lpDeleteSaveBuffer+cchDelete),
+ ped->cchDeleted);
+ }
+ LCopyStruct((LPSTR)(pedText+ped->ichMinSel),
+ (LPSTR)(lpDeleteSaveBuffer+bufferOffset),
+ cchDelete);
+
+ lpDeleteSaveBuffer[ped->cchDeleted+cchDelete]=0;
+ GlobalUnlock(ped->hDeletedText);
+ ped->cchDeleted += cchDelete;
+ }
+
+
+ if (ped->ichMaxSel != ped->cch)
+ {
+ /* We are deleting text from the middle of the buffer so we have to
+ shift text to the left. */
+
+ LCopyStruct((LPSTR)(pedText + ped->ichMaxSel),
+ (LPSTR)(pedText + ped->ichMinSel),
+ ped->cch-ped->ichMaxSel);
+ }
+
+ LocalUnlock(ped->hText);
+
+ if (ped->cchAlloc-ped->cch > CCHALLOCEXTRA)
+ {
+ /* Free some memory since we deleted a lot */
+ LocalReAlloc(ped->hText, (WORD)(ped->cch+(CCHALLOCEXTRA/2)), 0);
+ ped->cchAlloc = LocalSize(ped->hText);
+ }
+
+
+ ped->cch = ped->cch - cchDelete;
+ ped->ichCaret = ped->ichMaxSel = ped->ichMinSel;
+ /* Set dirty bit */
+ ped->fDirty = TRUE;
+
+ return(cchDelete);
+}
+
+
+void FAR PASCAL ECNotifyParent(ped, notificationCode)
+register PED ped;
+short notificationCode;
+/* effects: Sends the notification code to the parent of the edit control */
+{
+ /*
+ * Lowword contains handle to window highword has the notification code.
+ */
+ SendMessage(ped->hwndParent, WM_COMMAND,
+ GetWindowWord(ped->hwnd,GWW_ID),
+ MAKELONG(ped->hwnd, notificationCode));
+}
+
+
+void FAR PASCAL ECSetEditClip(ped, hdc)
+register PED ped;
+HDC hdc;
+/* effects: Sets the clip rectangle for the dc to ped->rcFmt intersect
+ * rcClient.
+ */
+{
+ RECT rectClient;
+
+ GetClientRect(ped->hwnd,(LPRECT)&rectClient);
+
+ /*
+ * If border bit is set, deflate client rectangle appropriately.
+ */
+ if (ped->fBorder)
+ /* Shrink client area to make room for the border */
+ InflateRect((LPRECT)&rectClient,
+ -min(ped->aveCharWidth,ped->cxSysCharWidth)/2,
+ -min(ped->lineHeight,ped->cySysCharHeight)/4);
+
+
+ /* Set clip rectangle to rectClient intersect ped->rcFmt */
+ if (!ped->fSingle)
+ IntersectRect((LPRECT)&rectClient,
+ (LPRECT)&rectClient, (LPRECT)&ped->rcFmt);
+
+ IntersectClipRect(hdc,rectClient.left, rectClient.top,
+ rectClient.right, rectClient.bottom);
+
+}
+
+
+HDC FAR PASCAL ECGetEditDC(ped, fFastDC)
+register PED ped;
+BOOL fFastDC;
+/* effects: Hides the caret, gets the DC for the edit control, and clips to
+ * the rcFmt rectangle specified for the edit control and sets the proper
+ * font. If fFastDC, just select the proper font but don't bother about clip
+ * regions or hiding the caret.
+ */
+{
+ register HDC hdc;
+
+ if (!fFastDC)
+ HideCaret(ped->hwnd);
+
+ hdc = GetDC(ped->hwnd);
+
+ ECSetEditClip(ped, hdc);
+
+ /*
+ * Select the proper font for this edit control's dc.
+ */
+ if (ped->hFont)
+ SelectObject(hdc, ped->hFont);
+
+ return(hdc);
+}
+
+
+void FAR PASCAL ECReleaseEditDC(ped,hdc,fFastDC)
+register PED ped;
+HDC hdc;
+BOOL fFastDC;
+/* effects: Releases the DC (hdc) for the edit control and shows the caret.
+ * If fFastDC, just select the proper font but don't bother about showing the
+ * caret.
+ */
+{
+ if (ped->hFont)
+ /*
+ * Release the font selected in this dc.
+ */
+ SelectObject(hdc, GetStockObject(SYSTEM_FONT));
+
+ ReleaseDC(ped->hwnd,hdc);
+
+ if (!fFastDC)
+ ShowCaret(ped->hwnd);
+}
+
+
+BOOL FAR PASCAL ECSetText(ped, lpstr)
+register PED ped;
+LPSTR lpstr;
+/* effects: Copies the null terminated text in lpstr to the ped. Notifies the
+ * parent if there isn't enough memory. Sets the minsel, maxsel, and caret to
+ * the beginning of the inserted text. Returns TRUE if successful else FALSE
+ * if no memory (and notifies the parent).
+ */
+{
+ ICH cchLength;
+ ICH cchSave = ped->cch;
+ ICH ichCaretSave = ped->ichCaret;
+
+ ped->cch = ped->ichCaret = 0;
+
+ ped->cchAlloc = LocalSize(ped->hText);
+ if (!lpstr)
+ {
+ LocalReAlloc(ped->hText, CCHALLOCEXTRA, 0);
+ ped->cch = 0;
+ }
+ else
+ {
+ cchLength = lstrlen(lpstr);
+ if (ped->fSingle)
+ /* Limit single line edit controls to 32K */
+ cchLength = umin(cchLength, 0x7ffe);
+
+ /* Add the text */
+ if (cchLength && !ECInsertText(ped,lpstr,cchLength))
+ {
+ /*
+ * Restore original state and notify parent we ran out of memory.
+ */
+ ped->cch = cchSave;
+ ped->ichCaret = ichCaretSave;
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return(FALSE);
+ }
+ }
+
+ ped->cchAlloc = LocalSize(ped->hText);
+ ped->screenStart = ped->iCaretLine = 0;
+ /* Update caret and selection extents */
+ ped->ichMaxSel = ped->ichMinSel = ped->ichCaret = 0;
+ ped->cLines = 1;
+ return(TRUE);
+}
+
+
+ICH FAR PASCAL ECCopyHandler(ped)
+register PED ped;
+/* effects: Copies the text between ichMinSel and ichMaxSel to the clipboard.
+ * Returns the number of characters copied.
+ */
+{
+ HANDLE hData;
+ char *pchSel;
+ char FAR *lpchClip;
+ ICH cbData;
+
+ cbData = ped->ichMaxSel - ped->ichMinSel;
+
+ if (!cbData)
+ return(0);
+
+ if (!OpenClipboard(ped->hwnd))
+ return(0);
+
+ EmptyClipboard();
+
+ /* +1 for the terminating NULL */
+ if (!(hData = GlobalAlloc(LHND, (LONG)(cbData+1))))
+ {
+ CloseClipboard();
+ return(0);
+ }
+
+ lpchClip = GlobalLock(hData);
+ pchSel = LocalLock(ped->hText) + ped->ichMinSel;
+
+ LCopyStruct((LPSTR)(pchSel), (LPSTR)lpchClip, cbData);
+
+ *(lpchClip+cbData) = 0;
+
+ LocalUnlock(ped->hText);
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_TEXT, hData);
+
+ CloseClipboard();
+
+ return(cbData);
+}
+
+
+/****************************************************************************/
+/* EditWndProc() */
+/****************************************************************************/
+LONG FAR PASCAL EditWndProc3(hwnd, message, wParam, lParam)
+HWND hwnd;
+WORD message;
+register WORD wParam;
+LONG lParam;
+/* effects: Class procedure for all edit controls.
+ Dispatches all messages to the appropriate handlers which are named
+ as follows:
+ SL (single line) prefixes all single line edit control procedures while
+ ML (multi line) prefixes all multi- line edit controls.
+ EC (edit control) prefixes all common handlers.
+
+ The EditWndProc only handles messages common to both single and multi
+ line edit controls. Messages which are handled differently between
+ single and multi are sent to SLEditWndProc or MLEditWndProc.
+
+ Top level procedures are EditWndPoc, SLEditWndProc, and MLEditWndProc.
+ SL*Handler or ML*Handler or EC*Handler procs are called to handle
+ the various messages. Support procedures are prefixed with SL ML or
+ EC depending on which code they support. They are never called
+ directly and most assumpttions/effects are documented in the effects
+ clause.
+ */
+
+{
+ register PED ped;
+
+ /* Get the ped for the given window now since we will use it a lot in
+ * various handlers. This was stored using SetWindowWord(hwnd,0,ped) when we
+ * initially created the edit control.
+ */
+ ped = (PED) GetWindowWord(hwnd,0);
+ if ((WORD)ped == (WORD)-1)
+ /* The ped was destroyed and this is a rogue message to be ignored. */
+ return(0L);
+
+
+ /* Dispatch the various messages we can receive */
+ switch (message)
+ {
+ /* Messages which are handled the same way for both single and multi line
+ * edit controls.
+ */
+
+ case WM_COPY:
+ /* wParam - not used
+ lParam - not used */
+ return((LONG)ECCopyHandler(ped));
+ break;
+
+ case WM_ENABLE:
+ /* wParam - nonzero is window is enables else disable window if 0.
+ lParam - not used
+ */
+ if (ped->fSingle)
+ /* Cause the rectangle to be redrawn in grey.
+ */
+ InvalidateRect(ped->hwnd, NULL, FALSE);
+ return((LONG)(ped->fDisabled = !wParam));
+ break;
+
+ case EM_GETLINECOUNT:
+ /* wParam - not used
+ lParam - not used */
+ return((LONG)ped->cLines);
+ break;
+
+ case EM_GETMODIFY:
+ /* wParam - not used
+ lParam - not used */
+ /* effects: Gets the state of the modify flag for this edit control.
+ */
+ return((LONG)ped->fDirty);
+ break;
+
+ case EM_GETRECT:
+ /* wParam - not used
+ lParam - pointer to a RECT data structure that gets the dimensions. */
+ /*
+ * effects: Copies the rcFmt rect to *lpRect. Note that the return value
+ * of the copyrect has no meaning and we don't care...
+ */
+ return((LONG)CopyRect((LPRECT)lParam, (LPRECT)&ped->rcFmt));
+ break;
+
+ case WM_GETFONT:
+ /* wParam - not used
+ lParam - not used */
+ return(ped->hFont);
+ break;
+
+ case WM_GETTEXT:
+ /* wParam - max number of bytes to copy
+ lParam - buffer to copy text to. Text is 0 terminated. */
+ return((LONG)ECGetTextHandler(ped, wParam, (LPSTR)lParam));
+ break;
+
+ case WM_GETTEXTLENGTH:
+ return((LONG)ped->cch);
+ break;
+
+ case WM_NCDESTROY:
+ /* wParam - used by DefWndProc called within ECNcDestroyHandler
+ lParam - used by DefWndProc called within ECNcDestroyHandler */
+ ECNcDestroyHandler(hwnd, ped, wParam, lParam);
+ break;
+
+ case WM_SETFONT:
+ /* wParam - handle to the font
+ lParam - redraw if true else don't */
+ ECSetFont(ped, (HANDLE)wParam, (BOOL)LOWORD(lParam));
+ break;
+
+ case WM_SETREDRAW:
+ /* wParam - specifies state of the redraw flag. nonzero = redraw
+ lParam - not used */
+ /* effects: Sets the state of the redraw flag for this edit control.
+ */
+ return((LONG)(ped->fNoRedraw = !(BOOL)wParam));
+ /* If NoRedraw is true, we don't redraw... (Yes, this is backwards we
+ * are keeping track of the opposite of the command ...
+ */
+ break;
+
+ case EM_CANUNDO:
+ /* wParam - not used
+ lParam - not used */
+ return((LONG)(ped->undoType != UNDO_NONE));
+ break;
+
+ case EM_EMPTYUNDOBUFFER:
+ /* wParam - not used
+ lParam - not used */
+ ECEmptyUndo(ped);
+ break;
+
+ case EM_GETSEL:
+ /* wParam - not used
+ lParam - not used */
+ /* effects: Gets the selection range for the given edit control. The
+ * starting position is in the low order word. It contains the position
+ * of the first nonselected character after the end of the selection in
+ * the high order word.
+ */
+
+ return(MAKELONG(ped->ichMinSel,ped->ichMaxSel));
+ break;
+
+ case EM_LIMITTEXT:
+ /* wParam - max number of bytes that can be entered
+ lParam - not used */
+ /* effects: Specifies the maximum number of bytes of text the user may
+ * enter. If maxLength is 0, we may enter MAXINT number of characters.
+ */
+ if (ped->fSingle)
+ {
+ if (wParam)
+ wParam = umin(0x7FFEu,wParam);
+ else
+ wParam = 0x7FFEu;
+ }
+
+ if (wParam)
+ ped->cchTextMax = (ICH)wParam;
+ else
+ ped->cchTextMax = 0xFFFFu;
+ break;
+
+ case EM_SETMODIFY:
+ /* wParam - specifies the new value for the modify flag
+ lParam - not used */
+ /*
+ * effects: Sets the state of the modify flag for this edit control.
+ */
+ ped->fDirty = wParam;
+ break;
+
+ case EM_SETPASSWORDCHAR:
+ /* wParam - sepecifies the new char to display instead of the real text.
+ if null, display the real text. */
+ ECSetPasswordChar(ped, wParam);
+ break;
+
+ case EM_GETFIRSTVISIBLE:
+ /* wParam - not used
+ lParam - not used */
+ /* effects: Returns the first visible char for single line edit controls
+ * and returns the first visible line for multiline edit controls.
+ */
+ return((LONG)(WORD)ped->screenStart);
+ break;
+
+ case EM_SETREADONLY:
+ /* wParam - state to set read only flag to */
+ ped->fReadOnly = wParam;
+ lParam = GetWindowLong(ped->hwnd, GWL_STYLE);
+ if (wParam)
+ lParam |= ES_READONLY;
+ else
+ lParam &= (~ES_READONLY);
+ SetWindowLong(ped->hwnd, GWL_STYLE, lParam);
+ return(1L);
+ break;
+
+ /* Messages handled differently for single and multi line edit controls */
+ case WM_CREATE:
+ /* Since the ped for this edit control is not defined, we have to check
+ * the style directly.
+ */
+ if (GetWindowLong(hwnd, GWL_STYLE) & ES_MULTILINE)
+ return(MLEditWndProc(hwnd, ped, message, wParam, lParam));
+ else
+ return(SLEditWndProc(hwnd, ped, message, wParam, lParam));
+ break;
+
+ case WM_NCCREATE:
+ return(ECNcCreate(hwnd, (LPCREATESTRUCT)lParam));
+ break;
+
+
+ default:
+ if (ped->fSingle)
+ return(SLEditWndProc(hwnd, ped, message, wParam, lParam));
+ else
+ return(MLEditWndProc(hwnd, ped, message, wParam, lParam));
+ break;
+ } /* switch (message) */
+
+ return(1L);
+} /* EditWndProc */
+
+
+
+void NEAR PASCAL ECFindXORblks(lpOldBlk, lpNewBlk, lpBlk1, lpBlk2)
+
+/*
+ * This finds the XOR of lpOldBlk and lpNewBlk and returns resulting blocks
+ * through the lpBlk1 and lpBlk2; This could result in a single block or
+ * at the maximum two blocks;
+ * If a resulting block is empty, then it's StPos field has -1.
+ * NOTE:
+ * When called from MultiLine edit control, StPos and EndPos fields of
+ * these blocks have the Starting line and Ending line of the block;
+ * When called from SingleLine edit control, StPos and EndPos fields
+ * of these blocks have the character index of starting position and
+ * ending position of the block.
+ */
+
+LPBLOCK lpOldBlk;
+LPBLOCK lpNewBlk;
+LPBLOCK lpBlk1;
+LPBLOCK lpBlk2;
+
+{
+ if(lpOldBlk -> StPos >= lpNewBlk ->StPos)
+ {
+ lpBlk1 -> StPos = lpNewBlk -> StPos;
+ lpBlk1 -> EndPos = umin(lpOldBlk -> StPos, lpNewBlk -> EndPos);
+ }
+ else
+ {
+ lpBlk1 -> StPos = lpOldBlk -> StPos;
+ lpBlk1 -> EndPos = umin(lpNewBlk -> StPos, lpOldBlk -> EndPos);
+ }
+
+ if(lpOldBlk -> EndPos <= lpNewBlk -> EndPos)
+ {
+ lpBlk2 -> StPos = umax(lpOldBlk -> EndPos, lpNewBlk -> StPos);
+ lpBlk2 -> EndPos = lpNewBlk -> EndPos;
+ }
+ else
+ {
+ lpBlk2 -> StPos = umax(lpNewBlk -> EndPos, lpOldBlk -> StPos);
+ lpBlk2 -> EndPos = lpOldBlk -> EndPos;
+ }
+}
+
+/*
+ * This function finds the XOR between two selection blocks(OldBlk and NewBlk)
+ * and returns the resulting areas thro the same parameters; If the XOR of
+ * both the blocks is empty, then this returns FALSE; Otherwise TRUE.
+ *
+ * NOTE:
+ * When called from MultiLine edit control, StPos and EndPos fields of
+ * these blocks have the Starting line and Ending line of the block;
+ * When called from SingleLine edit control, StPos and EndPos fields
+ * of these blocks have the character index of starting position and
+ * ending position of the block.
+ */
+BOOL FAR PASCAL ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel, OldBlk,
+ NewBlk)
+
+PED ped;
+ICH ichOldMinSel;
+ICH ichOldMaxSel;
+LPBLOCK OldBlk;
+LPBLOCK NewBlk;
+
+{
+ BLOCK Blk[2];
+ int iBlkCount = 0;
+ int i;
+
+
+ Blk[0].StPos = Blk[0].EndPos = Blk[1].StPos = Blk[1].EndPos = -1;
+
+
+ /* Check if the Old selection block existed */
+ if(ichOldMinSel != ichOldMaxSel)
+ {
+ /* Yes! Old block existed. */
+ Blk[0].StPos = OldBlk -> StPos;
+ Blk[0].EndPos = OldBlk -> EndPos;
+ iBlkCount++;
+ }
+
+ /* Check if the new Selection block exists */
+ if(ped -> ichMinSel != ped -> ichMaxSel)
+ {
+ /* Yes! New block exists */
+ Blk[1].StPos = NewBlk -> StPos;
+ Blk[1].EndPos = NewBlk -> EndPos;
+ iBlkCount++;
+ }
+
+ /* If both the blocks exist find the XOR of them */
+ if(iBlkCount == 2)
+ {
+ /* Check if both blocks start at the same character position */
+ if(ichOldMinSel == ped->ichMinSel)
+ {
+ /* Check if they end at the same character position */
+ if(ichOldMaxSel == ped -> ichMaxSel)
+ return(FALSE); /* Nothing changes */
+
+#ifdef DBCS
+ /* This look like bug, Because it uses min/max to compare
+ * two ICH values even if ICH is unsigned!
+ */
+ Blk[0].StPos = umin(NewBlk -> EndPos, OldBlk -> EndPos);
+ Blk[0].EndPos = umax(NewBlk -> EndPos, OldBlk -> EndPos);
+#else
+ Blk[0].StPos = min(NewBlk -> EndPos, OldBlk -> EndPos);
+ Blk[0].EndPos = max(NewBlk -> EndPos, OldBlk -> EndPos);
+#endif
+ Blk[1].StPos = -1;
+ }
+ else
+ {
+ if(ichOldMaxSel == ped -> ichMaxSel)
+ {
+ Blk[0].StPos = umin(NewBlk -> StPos, OldBlk -> StPos);
+ Blk[0].EndPos = umax(NewBlk -> StPos, OldBlk -> StPos);
+ Blk[1].StPos = -1;
+ }
+ else
+ ECFindXORblks(OldBlk, NewBlk, &Blk[0], &Blk[1]);
+ }
+ }
+
+ LCopyStruct((LPSTR)&Blk[0], (LPSTR)OldBlk, sizeof(BLOCK));
+ LCopyStruct((LPSTR)&Blk[1], (LPSTR)NewBlk, sizeof(BLOCK));
+
+ return(TRUE); /* Yup , There is something to paint */
+}
+
+
+#ifdef DBCS
+
+/*
+ * Set DBCS Vector for specified character set.
+ */
+VOID FAR PASCAL ECGetDBCSVector( ped )
+PED ped;
+{
+ HANDLE hTable;
+ PBYTE pTable, pDBCS;
+ unsigned i;
+
+ switch( ped->charSet ) {
+ case SHIFTJIS_CHARSET: /* 128 -> Japan */
+ ped->DBCSVector[0] = 0x81;
+ ped->DBCSVector[1] = 0x9f;
+ ped->DBCSVector[2] = 0xe0;
+ ped->DBCSVector[3] = 0xfc;
+ break;
+ case SHIFTJIS_CHARSET+1: /* 129 -> Korea */
+ ped->DBCSVector[0] = 0x81;
+ ped->DBCSVector[1] = 0xbf;
+ break;
+#if 0
+ case ?????: /* ??? -> People's Republic of China */
+ ped->DBCSVector[0] = 0x81;
+ ped->DBCSVector[1] = 0xfc;
+ break;
+ case ?????: /* ??? -> Taiwan */
+ ped->DBCSVector[0] = 0x81;
+ ped->DBCSVector[1] = 0xfd;
+ break;
+#endif
+ default:
+ ped->DBCSVector[0] = 0x0;
+ break;
+ }
+ /* If we can allocate 256 bytes of local memory, edit control
+ * operations are more comfortable
+ */
+ if ((ped->hDBCSVector = LocalAlloc( LHND, sizeof(BYTE)*256 )) == NULL)
+ return;
+
+ pTable = (PBYTE)LocalLock( ped->hDBCSVector );
+ pDBCS = ped->DBCSVector;
+ while(pDBCS[0]) {
+ for (i = pDBCS[0]; i <= pDBCS[1]; i++) pTable[i] = 1;
+ pDBCS += 2;
+ }
+ LocalUnlock( ped->hDBCSVector );
+}
+
+/*
+ * Advance string pointer for Edit Control use only.
+ */
+LPSTR FAR PASCAL ECAnsiNext( ped, lpCurrent )
+PED ped;
+LPSTR lpCurrent;
+{
+ return lpCurrent+((ECIsDBCSLeadByte(ped,*lpCurrent)==TRUE)?2:1);
+}
+
+/*
+ * Decrement string pointer for Edit Control use only.
+ */
+LPSTR FAR PASCAL ECAnsiPrev( ped, lpBase, lpStr )
+PED ped;
+LPSTR lpBase, lpStr;
+{
+ LPSTR lpCurrent = lpStr;
+
+// human C discompiler version 1.0---
+//; parmD pFirst ; [bx+10] es:di
+//; parmD pStr ; [bx+6] ds:si
+//
+// cmp si,di ; pointer to first char?
+// jz ap5 ; yes, just quit
+
+ if (lpBase == lpCurrent)
+ return lpBase;
+
+// dec si ; backup once
+// cmp si,di ; pointer to first char?
+// jz ap5 ; yse, just quit
+
+ if (--lpCurrent == lpBase)
+ return lpBase;
+
+//ap1:
+// dec si ; backup once
+// mov al, [si] ; fetch a character
+// cCall IsDBCSLeadByte,<ax> ; DBCS lead byte candidate?
+// test ax,ax ;
+// jz ap2 ; jump if not.
+// cmp si,di ; backword exhausted?
+// jz ap3 ; jump if so
+// jmp ap1 ; repeat if not
+
+ do {
+ lpCurrent--;
+ if (!ECIsDBCSLeadByte(ped, *lpCurrent)) {
+ lpCurrent++;
+ break;
+ }
+ } while(lpCurrent != lpBase);
+
+//ap2:
+// inc si ; adjust pointer correctly
+//ap3:
+
+ return lpStr - (((lpStr - lpCurrent) & 1) ? 1 : 2);
+
+// mov bx, [bp+6] ;
+// mov di, bx ; result in DI
+// dec di ;
+// sub bx, si ; how many characters backworded
+// test bx, 1 ; see even or odd...
+// jnz ap4 ; odd - previous char is SBCS
+// dec di ; make DI for DBCS
+//ap4:
+// mov si, di ; final result in SI
+//ap5:
+// mov ax,si
+// mov dx,ds
+//
+// pop di
+// pop si
+// pop ds
+//
+// pop bp
+// ret 8
+//cEnd nogen
+}
+
+/*
+ * Test to see DBCS lead byte or not - Edit Control use only.
+ */
+BOOL FAR PASCAL ECIsDBCSLeadByte( ped, cch )
+PED ped;
+BYTE cch;
+{
+ BYTE ch1, ch2;
+ PBYTE pTable;
+
+ if (!ped->fDBCS)
+ return FALSE;
+
+ if (ped->hDBCSVector) {
+ pTable = (PBYTE)LMHtoP(ped->hDBCSVector);
+ return pTable[ cch ];
+ }
+
+ pTable = ped->DBCSVector;
+ while( *pTable ) {
+ ch1 = *pTable++;
+ ch2 = *pTable++;
+ if (cch >= ch1 && cch <= ch2)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * Assemble two WM_CHAR messages to single DBCS character.
+ * If program detects first byte of DBCS character in WM_CHAR message,
+ * it calls this function to obtain second WM_CHAR message from queue.
+ * finally this routine assembles first byte and second byte into single
+ * DBCS character.
+ */
+int FAR PASCAL DBCSCombine(hwnd, ch)
+register HWND hwnd;
+int ch;
+{
+ MSG msg;
+ int i;
+
+ i = 10; /* loop counter to avoid the infinite loop */
+ while (!PeekMessage((LPMSG)&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)) {
+ if (--i == 0)
+ return( NULL );
+ Yield();
+ }
+
+ return ((unsigned)ch | ((unsigned)(msg.wParam)<<8));
+}
+
+/*
+ * This function adjusts a current pointer correctly. If a current
+ * pointer is lying between DBCS first byte and second byte, this
+ * function adjusts a current pointer to a first byte of DBCS position
+ * by decrement once.
+ */
+ICH FAR PASCAL ECAdjustIch( ped, lpstr, ch )
+PED ped;
+LPSTR lpstr;
+ICH ch;
+{
+ ICH newch = ch;
+
+ if ( newch == 0 )
+ return ( newch );
+
+ if ( !ECIsDBCSLeadByte(ped, lpstr[--newch] ) )
+ return ( ch ); // previous char is SBCS
+ while(1) {
+ if (!ECIsDBCSLeadByte(ped, lpstr[newch] )) {
+ newch++;
+ break;
+ }
+ if (newch)
+ newch--;
+ else
+ break;
+ }
+ return ((ch - newch) & 1) ? ch-1 : ch;
+}
+
+#endif
diff --git a/private/mvdm/wow16/user/editml.c b/private/mvdm/wow16/user/editml.c
new file mode 100644
index 000000000..696ac215e
--- /dev/null
+++ b/private/mvdm/wow16/user/editml.c
@@ -0,0 +1,3043 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDITML.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* editml.c - Edit controls rewrite. Version II of edit controls. */
+/* */
+/* */
+/* Created: 24-Jul-88 davidds */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Multi-Line Support Routines */
+/****************************************************************************/
+
+BOOL NEAR _fastcall MLIsDelimiter(char bCharVal)
+{
+ return((bCharVal == ' ') || (bCharVal == '\t'));
+}
+
+
+DWORD NEAR PASCAL LocGetTabbedTextExtent(HDC hdc, PSTR pstring,
+ int nCount, PED ped)
+{
+ return(ECTabTheTextOut(hdc, 0, 0, (LPSTR)pstring, nCount, ped, 0, FALSE));
+}
+
+int FAR PASCAL MLCalcXOffset(register PED ped,
+ HDC hdc,
+ int lineNumber)
+/* effects: Calculates the horizontal offset (indent) required for centered
+ * and right justified lines.
+ */
+{
+ PSTR pText;
+ ICH lineLength;
+ register ICH lineWidth;
+
+ if (ped->format == ES_LEFT)
+ return(0);
+
+
+ lineLength = MLLineLength(ped, lineNumber);
+
+ if (lineLength)
+ {
+ pText = LocalLock(ped->hText)+ped->chLines[lineNumber];
+ hdc = ECGetEditDC(ped,TRUE);
+ lineWidth = LOWORD(LocGetTabbedTextExtent(hdc, pText, lineLength,
+ ped));
+ ECReleaseEditDC(ped,hdc,TRUE);
+ LocalUnlock(ped->hText);
+ }
+ else
+ lineWidth = 0;
+
+ /*
+ * If a SPACE or a TAB was eaten at the end of a line by MLBuildchLines
+ * to prevent a delimiter appearing at the begining of a line, the
+ * the following calculation will become negative causing this bug.
+ * So, now, we take zero in such cases.
+ * Fix for Bug #3566 --01/31/91-- SANKAR --
+ */
+ lineWidth = max(0, ped->rcFmt.right-ped->rcFmt.left-lineWidth);
+
+ if (ped->format == ES_CENTER)
+ return(lineWidth/2);
+
+ if (ped->format == ES_RIGHT)
+ /* Subtract 1 so that the 1 pixel wide cursor will be in the visible
+ * region on the very right side of the screen.
+ */
+ return(max(0, lineWidth-1));
+}
+
+
+ICH NEAR PASCAL MLMoveSelection(register PED ped,
+ ICH ich,
+ BOOL fLeft)
+/* effects: Moves the selection character in the direction indicated. Assumes
+ * you are starting at a legal point, we decrement/increment the ich. Then,
+ * This decrements/increments it some more to get past CRLFs...
+ */
+{
+ register PSTR pText;
+
+ if (fLeft && ich > 0)
+ {
+ /* Move left */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ich;
+ if( ECIsDBCSLeadByte(ped, *ECAnsiPrev(ped, LMHtoP(ped->hText), pText ) ) )
+ ich--;
+#endif /* DBCS */
+ ich--;
+ if (ich)
+ {
+ /* Check for CRLF or CRCRLF */
+ /*pText = LocalLock(ped->hText)+ich;*/
+ pText = LMHtoP(ped->hText)+ich;
+
+ /* Move before CRLF or CRCRLF */
+ if (*pText == 0x0A)
+ {
+ ich--;
+ if (ich && *(pText-2) == 0x0D)
+ ich--;
+ }
+ /*LocalUnlock(ped->hText);*/
+ }
+ }
+ else if (!fLeft && ich < ped->cch)
+ {
+#ifdef DBCS
+ pText = LMHtoP(ped->hText)+ich;
+ if( ECIsDBCSLeadByte(ped, *pText ) )
+ ich++;
+#endif /* DBCS */
+ ich++;
+ if (ich < ped->cch)
+ {
+ /*pText = LocalLock(ped->hText)+ich;*/
+ pText = LMHtoP(ped->hText)+ich;
+
+ /* Move after CRLF */
+ if (*pText == 0x0A)
+ ich++;
+ else /* Check for CRCRLF */
+ if (ich && *pText == 0x0D && *(pText-1) == 0x0D)
+ ich+=2;
+ /*LocalUnlock(ped->hText);*/
+ }
+ }
+ return(ich);
+}
+
+
+void FAR PASCAL MLSetCaretPosition(register PED ped, HDC hdc)
+/* effects: If the window has the focus, find where the caret belongs and move
+ * it there.
+ */
+{
+ LONG position;
+ BOOL prevLine;
+
+ /* We will only position the caret if we have the focus since we don't want
+ * to move the caret while another window could own it.
+ */
+
+ if (!ped->fFocus || ped->fNoRedraw)
+ return;
+
+ if(ped->fCaretHidden)
+ {
+ SetCaretPos(-20000, -20000);
+ return;
+ }
+
+ /* Find the position of the caret */
+ if ((ped->iCaretLine < ped->screenStart) ||
+ (ped->iCaretLine > ped->screenStart+ped->ichLinesOnScreen))
+ /* Caret is not visible. Make it a very small value so that it won't be
+ * seen.
+ */
+ SetCaretPos(-20000,-20000);
+ else
+ {
+ if (ped->cLines-1 != ped->iCaretLine &&
+ ped->ichCaret == ped->chLines[ped->iCaretLine+1])
+ prevLine=TRUE;
+ else
+ prevLine=FALSE;
+
+ position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
+ if (ped->fWrap)
+ {
+ if (HIWORD(position) > ped->rcFmt.bottom-ped->lineHeight)
+ SetCaretPos(-20000,-20000);
+ else
+ {
+ /* Make sure the caret is in the visible region if word
+ * wrapping. This is so that the caret will be visible if the
+ * line ends with a space.
+ */
+ SetCaretPos(min(LOWORD(position),ped->rcFmt.right-1),
+ HIWORD(position));
+ }
+ }
+ else
+ {
+ if (LOWORD(position) > ped->rcFmt.right ||
+ HIWORD(position) > ped->rcFmt.bottom)
+ SetCaretPos(-20000,-20000);
+ else
+ SetCaretPos(LOWORD(position),HIWORD(position));
+ }
+ }
+}
+
+
+ICH FAR PASCAL MLLineLength(register PED ped, int lineNumber)
+/* effects: Returns the length of the line given by lineNumber ignoring any
+ * CRLFs in the line.
+ */
+{
+ ICH result;
+ register PSTR pText;
+
+ if (lineNumber >= ped->cLines)
+ return(0);
+
+ if (lineNumber == ped->cLines-1)
+ /* Since we can't have a CRLF on the last line */
+ return(ped->cch - ped->chLines[ped->cLines-1]);
+ else
+ {
+ result = ped->chLines[lineNumber+1] - ped->chLines[lineNumber];
+ /* Now check for CRLF or CRCRLF at end of line */
+ if (result > 1)
+ {
+ /*pText = LocalLock(ped->hText)+ped->chLines[lineNumber+1]-2;*/
+ pText = LMHtoP(ped->hText)+ped->chLines[lineNumber+1]-2;
+ if (*pText == 0x0D)
+ {
+ result = result - 2;
+ if (result && *(--pText) == 0x0D)
+ /* In case there was a CRCRLF */
+ result--;
+ }
+ /*LocalUnlock(ped->hText);*/
+ }
+ }
+ return(result);
+}
+
+
+int FAR PASCAL MLIchToLineHandler(register PED ped, ICH ich)
+/* effects: Returns the line number (starting from 0) which contains the given
+ * character index. If ich is -1, return the line the the first char in the
+ * selection is on (the caret if no selection)
+ */
+{
+ register int line = ped->cLines-1;
+
+ if (ich == 0xFFFF)
+ ich = ped->ichMinSel;
+
+ /* We could do a binary search here but is it really worth it??? We will
+ * have to wait and see how often this proc is being called...
+ */
+
+ while (line && (ich < ped->chLines[line]))
+ line--;
+
+ return(line);
+}
+
+
+LONG NEAR PASCAL MLIchToXYPos(register PED ped,
+ HDC hdc,
+ ICH ich,
+ BOOL prevLine)
+/* effects: Given an ich, return its x,y coordinates with respect to the top
+ * left character displayed in the window. Returns the coordinates of the top
+ * left position of the char. If prevLine is TRUE then if the ich is at the
+ * beginning of the line, we will return the coordinates to the right of the
+ * last char on the previous line (if it is not a CRLF). x is in the loword,
+ * y in the highword.
+ */
+{
+ int iline;
+ ICH cch;
+ int xPosition,yPosition;
+ int xOffset;
+ /*
+ * For horizontal scroll displacement on left justified text and
+ * for indent on centered or right justified text
+ */
+ PSTR pText,pTextStart,pLineStart;
+
+ /* Determine what line the character is on */
+ iline = MLIchToLineHandler(ped, ich);
+
+ /* Calc. the yPosition now. Note that this may change by the height of one
+ * char if the prevLine flag is set and the ICH is at the beginning of a
+ * line.
+ */
+ yPosition = (iline-ped->screenStart)*ped->lineHeight+ped->rcFmt.top;
+
+
+ /* Now determine the xPosition of the character */
+ pTextStart = LocalLock(ped->hText);
+
+ if (prevLine && iline && (ich == ped->chLines[iline]) &&
+ (*(pTextStart+ich-1) != 0x0A))
+ {
+ /* First char in the line. We want text extent upto end of the previous
+ * line if we aren't at the 0th line.
+ */
+ iline--;
+
+ yPosition = yPosition - ped->lineHeight;
+ pLineStart = pTextStart+ped->chLines[iline];
+
+ /* Note that we are taking the position in front of any CRLFs in the
+ * text.
+ */
+ cch = MLLineLength(ped, iline);
+ }
+ else
+ {
+ pLineStart = pTextStart + ped->chLines[iline];
+ pText = pTextStart + ich;
+
+ /* Strip off CRLF or CRCRLF. Note that we may be pointing to a CR but in
+ * which case we just want to strip off a single CR or 2 CRs.
+ */
+ /* We want pText to point to the first CR at the end of the line if
+ * there is one. Thus, we will get an xPosition to the right of the last
+ * visible char on the line otherwise we will be to the left of
+ * character ich.
+ */
+
+ /* Check if we at the end of text */
+ if(ich < ped -> cch)
+ {
+ if (ich && *pText == 0x0A)
+ pText--;
+ if (ich > 2 && *(pText-1) == 0x0D)
+ pText--;
+ }
+
+ cch = pText - pLineStart;
+ }
+
+ /* Find out how many pixels we indent the line for funny formats */
+ if (ped->format != ES_LEFT)
+ xOffset = MLCalcXOffset(ped, hdc, iline);
+ else
+ xOffset = -ped->xOffset;
+
+
+ xPosition = ped->rcFmt.left + xOffset +
+ LOWORD(LocGetTabbedTextExtent(hdc, pLineStart, cch, ped));
+
+ LocalUnlock(ped->hText);
+ return(MAKELONG(xPosition,yPosition));
+}
+
+
+LONG NEAR PASCAL MLMouseToIch(register PED ped,
+ HDC hdc,
+ POINT mousePt)
+/* effects: Returns the closest cch to where the mouse point is. cch is in
+ * the lowword and lineindex is in the high word. (So that we can tell if we
+ * are at the beginning of the line or end of the previous line.)
+ */
+{
+ int xOffset;
+ PSTR pText;
+ PSTR pLineStart;
+ int height = mousePt.y;
+ int line;
+ int width = mousePt.x;
+ ICH cch;
+ ICH cLineLength;
+ ICH cLineLengthNew;
+ ICH cLineLengthHigh=0;
+ ICH cLineLengthLow=0;
+ int textWidth;
+ int iOldTextWidth;
+ int iCurWidth;
+
+ /* First determine which line the mouse is pointing to.
+ */
+ line = ped->screenStart;
+ if (height <= ped->rcFmt.top)
+ /* Either return 0 (the very first line, or one line before the top line
+ * on the screen. Note that these are signed mins and maxes since we
+ * don't expect (or allow) more than 32K lines.
+ */
+ line = max(0, line-1);
+ else if (height >= ped->rcFmt.bottom)
+ /* Are we below the last line displayed */
+ line = min(line+ped->ichLinesOnScreen,ped->cLines-1);
+ else
+ /* We are somewhere on a line visible on screen */
+ line=min(line+((height-ped->rcFmt.top)/ped->lineHeight),ped->cLines-1);
+
+
+ /* Now determine what horizontal character the mouse is pointing to.
+ */
+ pLineStart=(pText=LocalLock(ped->hText))+ped->chLines[line];
+ cLineLength = MLLineLength(ped,line); /* Length is sans CRLF or CRCRLF */
+
+
+ /* xOffset will be a negative value for center and right justified lines.
+ * ie. We will just displace the lines left by the amount of indent for
+ * right and center justification. Note that ped->xOffset will be 0 for
+ * these lines since we don't support horizontal scrolling with them.
+ */
+ if (ped->format != ES_LEFT)
+ xOffset = MLCalcXOffset(ped,hdc,line);
+ else
+ /* So that we handle a horizontally scrolled window for left justified
+ * text.
+ */
+ xOffset = 0;
+
+ width = width - xOffset;
+
+ /* The code below is tricky... I depend on the fact that ped->xOffset is 0
+ * for right and center justified lines
+ */
+
+ /* Now find out how many chars fit in the given width */
+ if (width >= ped->rcFmt.right)
+ {
+ /* Return 1+last char in line or one plus the last char visible */
+ cch = ECCchInWidth(ped, hdc, (LPSTR)pLineStart, cLineLength,
+ ped->rcFmt.right-ped->rcFmt.left+ped->xOffset);
+#ifdef DBCS
+ {
+ ICH cch2;
+ cch2 = umin(cch+1,cLineLength);
+ if (ECAdjustIch( ped, pLineStart, cch2 ) != cch2)
+ /* Displayed character on the right edge is DBCS */
+ cch = umin(cch+2,cLineLength);
+ else cch = cch2;
+ cch += ped->chLines[line];
+ }
+#else
+ cch = ped->chLines[line]+umin(cch+1,cLineLength);
+#endif
+ }
+ else if (width <= ped->rcFmt.left + ped->aveCharWidth/2)
+ {
+ /* Return first char in line or one minus first char visible. Note that
+ * ped->xOffset is 0 for right and centered text so we will just return
+ * the first char in the string for them. (Allow a avecharwidth/2
+ * positioning border so that the user can be a little off...
+ */
+ cch = ECCchInWidth(ped, hdc, (LPSTR)pLineStart, cLineLength,
+ ped->xOffset);
+ if (cch)
+ cch--;
+
+#ifdef DBCS
+ cch = ECAdjustIch( ped, pLineStart, cch );
+#endif
+ cch = ped->chLines[line]+cch;
+ }
+ else
+ {
+ /* Now the mouse is somewhere on the visible portion of the text
+ * remember cch contains the length the line.
+ */
+ iCurWidth = width + ped->xOffset;
+
+ cLineLengthHigh = cLineLength+1;
+ while(cLineLengthLow < cLineLengthHigh-1)
+ {
+ cLineLengthNew = umax((cLineLengthHigh-cLineLengthLow)/2,1)+
+ cLineLengthLow;
+
+ /* Add in a avecharwidth/2 so that if user is half way on the next
+ * char, it is still considered the previous char. For that feel.
+ */
+ textWidth = ped->rcFmt.left + ped->aveCharWidth/2 +
+ LOWORD(LocGetTabbedTextExtent(hdc, pLineStart,
+ cLineLengthNew, ped));
+ if (textWidth > iCurWidth)
+ cLineLengthHigh = cLineLengthNew;
+ else
+ cLineLengthLow = cLineLengthNew;
+
+ /* Preserve the old Width */
+ iOldTextWidth = textWidth;
+ }
+
+ /* Find out which side of the character the mouse click occurred */
+ if ((iOldTextWidth - iCurWidth) < (iCurWidth - textWidth))
+ cLineLengthNew++;
+
+ cLineLength = umin(cLineLengthNew,cLineLength);
+
+#ifdef DBCS
+ cLineLength = ECAdjustIch( ped, pLineStart, cLineLength );
+#endif
+
+ cch = ped->chLines[line]+cLineLength;
+ }
+ LocalUnlock(ped->hText);
+ return(MAKELONG(cch,line));
+}
+
+
+void NEAR PASCAL MLRepaintChangedSelection(PED ped,
+ HDC hdc,
+ ICH ichOldMinSel,
+ ICH ichOldMaxSel)
+
+/* When selection changes, this takes care of drawing the changed portions
+ * with proper attributes.
+ */
+{
+ BLOCK Blk[2];
+ int iBlkCount = 0;
+ int i;
+
+ Blk[0].StPos = ichOldMinSel;
+ Blk[0].EndPos = ichOldMaxSel;
+ Blk[1].StPos = ped->ichMinSel;
+ Blk[1].EndPos = ped->ichMaxSel;
+
+ if (ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
+ (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
+ {
+ /* Paint the rectangles where selection has changed */
+ /* Paint both Blk[0] and Blk[1], if they exist */
+ for(i = 0; i < 2; i++)
+ {
+ if (Blk[i].StPos != -1)
+ MLDrawText(ped, hdc, Blk[i].StPos, Blk[i].EndPos);
+ }
+ }
+}
+
+
+void FAR PASCAL MLChangeSelection(register PED ped,
+ HDC hdc,
+ ICH ichNewMinSel,
+ ICH ichNewMaxSel)
+/* effects: Changes the current selection to have the specified starting and
+ * ending values. Properly highlights the new selection and unhighlights
+ * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
+ * them. Doesn't update the caret position.
+ */
+{
+
+ ICH temp;
+ ICH ichOldMinSel, ichOldMaxSel;
+
+ if (ichNewMinSel > ichNewMaxSel)
+ {
+ temp = ichNewMinSel;
+ ichNewMinSel = ichNewMaxSel;
+ ichNewMaxSel = temp;
+ }
+ ichNewMinSel = umin(ichNewMinSel, ped->cch);
+ ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
+
+ /* Save the current selection */
+ ichOldMinSel = ped->ichMinSel;
+ ichOldMaxSel = ped->ichMaxSel;
+
+ /* Set new selection */
+ ped->ichMinSel = ichNewMinSel;
+ ped->ichMaxSel = ichNewMaxSel;
+
+ /* We only update the selection on the screen if redraw is on and if we have
+ * the focus or if we don't hide the selection when we don't have the focus.
+ */
+ if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
+ {
+ /* Find old selection region, find new region, and invert the XOR of the
+ * two and invert only the XOR region.
+ */
+
+ MLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
+
+ MLSetCaretPosition(ped,hdc);
+ }
+
+}
+
+// This updates the ped->iCaretLine field from the ped->ichCaret;
+// Also, when the caret gets to the beginning of next line, pop it up to
+// the end of current line when inserting text;
+void NEAR PASCAL MLUpdateiCaretLine(PED ped)
+{
+ PSTR pText;
+
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ /* If caret gets to beginning of next line, pop it up to end of current line
+ * when inserting text.
+ */
+ pText = LMHtoP(ped->hText)+ped->ichCaret-1;
+ if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret &&
+ *pText != 0x0A)
+ ped->iCaretLine--;
+}
+
+ICH FAR PASCAL MLInsertText(ped, lpText, cchInsert, fUserTyping)
+register PED ped;
+LPSTR lpText;
+ICH cchInsert;
+BOOL fUserTyping;
+/* effects: Adds up to cchInsert characters from lpText to the ped starting at
+ * ichCaret. If the ped only allows a maximum number of characters, then we
+ * will only add that many characters to the ped. The number of characters
+ * actually added is returned (could be 0). If we can't allocate the required
+ * space, we notify the parent with EN_ERRSPACE and no characters are added.
+ * We will rebuild the lines array as needed. fUserTyping is true if the
+ * input was the result of the user typing at the keyboard. This is so we can
+ * do some stuff faster since we will be getting only one or two chars of
+ * input.
+ */
+{
+ HDC hdc;
+ ICH validCch=cchInsert;
+ ICH oldCaret = ped->ichCaret;
+ int oldCaretLine = ped->iCaretLine;
+ BOOL fCRLF=FALSE;
+ LONG l;
+ WORD localundoType = 0;
+ HANDLE localhDeletedText;
+ ICH localichDeleted;
+ ICH localcchDeleted;
+ ICH localichInsStart;
+ ICH localichInsEnd;
+ LONG xyPosInitial=0L;
+ LONG xyPosFinal=0L;
+
+ if (!validCch)
+ return(0);
+
+ if (validCch)
+ {
+ /* Limit the amount of text we add */
+ _asm int 3
+ if (ped->cchTextMax <= ped->cch)
+ {
+ /* When the max chars is reached already, notify parent */
+ /* Fix for Bug #4183 -- 02/06/91 -- SANKAR -- */
+ ECNotifyParent(ped,EN_MAXTEXT);
+ return(0);
+ }
+
+ validCch = umin(validCch, ped->cchTextMax - ped->cch);
+ /* Make sure we don't split a CRLF in half */
+ if (validCch && *(lpText+validCch) == 0x0A)
+ validCch--;
+ if (!validCch)
+ {
+ /* When the max chars is reached already, notify parent */
+ /* Fix for Bug #4183 -- 02/06/91 -- SANKAR -- */
+ ECNotifyParent(ped,EN_MAXTEXT);
+ return(0);
+ }
+
+ if (validCch == 2 && (*(WORD FAR *)lpText) == 0x0A0D)
+ fCRLF=TRUE;
+
+ if (!ped->fAutoVScroll &&
+ (ped->undoType==UNDO_INSERT || ped->undoType==UNDO_DELETE))
+ {
+ /* Save off the current undo state */
+ localundoType = ped->undoType;
+ localhDeletedText = ped->hDeletedText;
+ localichDeleted = ped->ichDeleted;
+ localcchDeleted = ped->cchDeleted;
+ localichInsStart = ped->ichInsStart;
+ localichInsEnd = ped->ichInsEnd;
+
+ /* Kill undo */
+ ped->undoType = UNDO_NONE;
+ ped->hDeletedText = NULL;
+ ped->ichDeleted=
+ ped->cchDeleted =
+ ped->ichInsStart=
+ ped->ichInsEnd = 0;
+ }
+
+ hdc = ECGetEditDC(ped,FALSE);
+ if (ped->cch)
+ xyPosInitial = MLIchToXYPos(ped, hdc, ped->cch-1, FALSE);
+
+
+ /* Insert the text */
+ if (!ECInsertText(ped, lpText, validCch))
+ {
+ ECReleaseEditDC(ped,hdc,FALSE);
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return(0);
+ }
+ /* Note that ped->ichCaret is updated by ECInsertText */
+ }
+
+ l = MLBuildchLines(ped, oldCaretLine, validCch,
+ (fCRLF ? FALSE : fUserTyping));
+
+ if (ped->cch)
+ xyPosFinal = MLIchToXYPos(ped, hdc, ped->cch-1, FALSE);
+
+ if (HIWORD(xyPosFinal) < HIWORD(xyPosInitial) &&
+ ped->screenStart+ped->ichLinesOnScreen >= ped->cLines-1)
+ {
+ RECT rc;
+ CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
+ rc.top = HIWORD(xyPosFinal)+ped->lineHeight;
+ InvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE);
+ }
+
+ if (!ped->fAutoVScroll)
+ {
+ if (ped->ichLinesOnScreen < ped->cLines)
+ {
+ MLUndoHandler(ped);
+ ECEmptyUndo(ped);
+ if (localundoType == UNDO_INSERT || localundoType == UNDO_DELETE)
+ {
+ ped->undoType = localundoType;
+ ped->hDeletedText = localhDeletedText;
+ ped->ichDeleted = localichDeleted;
+ ped->cchDeleted = localcchDeleted;
+ ped->ichInsStart = localichInsStart;
+ ped->ichInsEnd = localichInsEnd;
+ }
+ MessageBeep(0);
+ ECReleaseEditDC(ped,hdc,FALSE);
+ return(0);
+ }
+ else
+ {
+ if (localundoType == UNDO_INSERT || localundoType == UNDO_DELETE)
+ GlobalFree(localhDeletedText);
+ }
+ }
+
+ if (fUserTyping && ped->fWrap)
+#ifdef DBCS
+ /* To avoid oldCaret points intermediate of DBCS character,
+ * adjust oldCaret position if necessary.
+ */
+ oldCaret = ECAdjustIch(ped, LMHtoP(ped->hText), umin(LOWORD(l), oldCaret));
+#else
+ oldCaret = umin(LOWORD(l), oldCaret);
+#endif
+
+
+ /* These are updated by ECInsertText so we won't do it again */
+ /* ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;*/
+#ifdef NEVER
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ /* If caret gets to beginning of next line, pop it up to end of current line
+ * when inserting text.
+ */
+ pText = LMHtoP(ped->hText)+ped->ichCaret-1;
+ if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret &&
+ *pText != 0x0A)
+ ped->iCaretLine--;
+#else
+ // Update ped->iCaretLine properly.
+ MLUpdateiCaretLine(ped);
+#endif
+
+ ECNotifyParent(ped,EN_UPDATE);
+
+ if (fCRLF || !fUserTyping)
+ /* Redraw to end of screen/text if crlf or large insert.
+ */
+ MLDrawText(ped, hdc, (fUserTyping ? oldCaret : 0), ped->cch);
+ else
+ MLDrawText(ped, hdc, oldCaret, umax(ped->ichCaret,HIWORD(l)));
+
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+ /* Make sure we can see the cursor */
+ MLEnsureCaretVisible(ped);
+
+ ped->fDirty = TRUE;
+
+ ECNotifyParent(ped,EN_CHANGE);
+
+ if (validCch < cchInsert)
+ ECNotifyParent(ped,EN_MAXTEXT);
+
+ return(validCch);
+}
+
+
+ICH NEAR PASCAL MLDeleteText(register PED ped)
+/* effects: Deletes the characters between ichMin and ichMax. Returns the
+ * number of characters we deleted.
+ */
+{
+ ICH minSel = ped->ichMinSel;
+ ICH maxSel = ped->ichMaxSel;
+ ICH cchDelete;
+ HDC hdc;
+ int minSelLine;
+ int maxSelLine;
+ LONG xyPos;
+ RECT rc;
+ BOOL fFastDelete = FALSE;
+ LONG l;
+#ifdef DBCS
+ ICH cchcount;
+#endif
+
+ /* Get what line the min selection is on so that we can start rebuilding the
+ * text from there if we delete anything.
+ */
+ minSelLine = MLIchToLineHandler(ped,minSel);
+ maxSelLine = MLIchToLineHandler(ped,maxSel);
+#ifdef DBCS
+ switch(maxSel - minSel)
+ {
+ case 2:
+ if (ECIsDBCSLeadByte(ped,*(LMHtoP(ped->hText)+minSel)) == FALSE)
+ break;
+ /* Fall thru */
+ case 1:
+// if ((minSelLine==maxSelLine) && (ped->chLines[minSelLine] != minSel))
+ if (minSelLine==maxSelLine)
+ {
+ if (!ped->fAutoVScroll)
+ fFastDelete = FALSE;
+ else
+ {
+ fFastDelete = TRUE;
+ cchcount = ((maxSel - minSel) == 1) ? 0 : -1;
+ }
+ }
+ }
+#else
+ if (((maxSel - minSel) == 1) &&
+ (minSelLine==maxSelLine) &&
+ (ped->chLines[minSelLine] != minSel))
+ {
+ if (!ped->fAutoVScroll)
+ fFastDelete = FALSE;
+ else
+ fFastDelete = TRUE;
+ }
+#endif
+ if (!(cchDelete=ECDeleteText(ped)))
+ return(0);
+
+ /* Start building lines at minsel line since caretline may be at the max sel
+ * point.
+ */
+ if (fFastDelete)
+ {
+#ifdef DBCS
+ MLShiftchLines(ped, minSelLine+1, -2+cchcount);
+#else
+ MLShiftchLines(ped, minSelLine+1, -2);
+#endif
+ l=MLBuildchLines(ped, minSelLine, 1, TRUE);
+ }
+ else
+ {
+ MLBuildchLines(ped,max(minSelLine-1,0),-cchDelete, FALSE);
+ }
+#ifdef NEVER
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ /* If caret gets to beginning of this line, pop it up to end of previous
+ * line when deleting text
+ */
+ pText = LMHtoP(ped->hText)+ped->ichCaret;
+ if (ped->iCaretLine && ped->chLines[ped->iCaretLine] == ped->ichCaret
+ && *(pText-1)!= 0x0A)
+ ped->iCaretLine--;
+#else
+ MLUpdateiCaretLine(ped);
+#endif
+
+#if 0
+ if (!ped->fAutoVScroll)
+ ECEmptyUndo(ped);
+#endif
+ ECNotifyParent(ped,EN_UPDATE);
+
+ /* Now update the screen to reflect the deletion */
+ hdc = ECGetEditDC(ped,FALSE);
+ /* Otherwise just redraw starting at the line we just entered */
+ minSelLine = max(minSelLine-1,0);
+ if (fFastDelete)
+ MLDrawText(ped, hdc, ped->chLines[minSelLine], HIWORD(l));
+ else
+ MLDrawText(ped, hdc, ped->chLines[minSelLine], ped->cch);
+
+ if (ped->cch)
+ {
+ /* Clear from end of text to end of window.
+ */
+ xyPos = MLIchToXYPos(ped, hdc, ped->cch, FALSE);
+ CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
+ rc.top = HIWORD(xyPos)+ped->lineHeight;
+ InvalidateRect(ped->hwnd, (LPRECT)&rc, TRUE);
+ }
+ else
+ {
+ InvalidateRect(ped->hwnd, (LPRECT)&ped->rcFmt, TRUE);
+ }
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+ MLEnsureCaretVisible(ped);
+
+ ped->fDirty = TRUE;
+
+ ECNotifyParent(ped,EN_CHANGE);
+ return(cchDelete);
+}
+
+
+BOOL NEAR PASCAL MLInsertchLine(register PED ped,
+ int iLine,
+ ICH ich,
+ BOOL fUserTyping)
+/* effects: Inserts the line iline and sets its starting character index to be
+ * ich. All the other line indices are moved up. Returns TRUE if successful
+ * else FALSE and notifies the parent that there was no memory.
+ */
+{
+ HANDLE hResult;
+
+ if (fUserTyping && iLine < ped->cLines)
+ {
+ ped->chLines[iLine] = ich;
+ return(TRUE);
+ }
+
+ hResult =
+ LocalReAlloc((HANDLE)ped->chLines,(ped->cLines+2)*sizeof(int),LHND);
+
+ if (!hResult)
+ {
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return(FALSE);
+ }
+
+ ped->chLines = (int *)hResult;
+ /* Move indices starting at iLine up */
+ LCopyStruct((LPSTR)(&ped->chLines[iLine]),(LPSTR)(&ped->chLines[iLine+1]),
+ (ped->cLines-iLine)*sizeof(int));
+ ped->cLines++;
+
+ ped->chLines[iLine] = ich;
+ return(TRUE);
+}
+
+#if 0
+BOOL NEAR PASCAL MLGrowLinesArray(ped, cLines)
+register PED ped;
+int cLines;
+/* effects: Grows the line start array in the ped so that it holds cLines.
+ * Notifies parent and returns FALSE if no memory error. We won't allow more
+ * than 32700 lines in the edit control. This allows us to use signed values
+ * for line counts while still providing good functionality.
+ */
+{
+ HANDLE hResult;
+
+
+ if (cLines<32700 &&
+ (hResult = LocalReAlloc((HANDLE)ped->chLines,
+ (cLines+1)*sizeof(ICH),LHND)))
+
+ ped->chLines = (int *)hResult;
+ else
+ ECNotifyParent(ped, EN_ERRSPACE);
+
+
+ return((BOOL)hResult);
+}
+#endif
+
+void NEAR PASCAL MLShiftchLines(register PED ped,
+ register int iLine,
+ int delta)
+/* effects: Move the starting index of all lines iLine or greater by delta
+ * bytes.
+ */
+{
+ if (iLine >= ped->cLines)
+ return;
+
+ /* Just add delta to the starting point of each line after iLine */
+ for (;iLine<ped->cLines;iLine++)
+ ped->chLines[iLine] += delta;
+}
+
+
+LONG FAR PASCAL MLBuildchLines(ped, iLine, cchDelta, fUserTyping)
+register PED ped;
+int iLine;
+int cchDelta;
+BOOL fUserTyping;
+/* effects: Rebuilds the start of line array (ped->chLines) starting at line
+ * number ichLine. Returns TRUE if any new lines were made else returns
+ * false.
+ */
+{
+ register PSTR ptext; /* Starting address of the text */
+ /* We keep these ICH's so that we can Unlock ped->hText when we have to grow
+ * the chlines array. With large text handles, it becomes a problem if we
+ * have a locked block in the way.
+ */
+ ICH ichLineStart;
+ ICH ichLineEnd;
+ ICH ichLineEndBeforeCRLF;
+ ICH ichCRLF;
+
+ int iLineStart = iLine;
+ ICH cLineLength;
+ ICH cch;
+ HDC hdc;
+
+ BOOL fLineBroken = FALSE; /* Initially, no new line breaks are made */
+ ICH minCchBreak;
+ ICH maxCchBreak;
+
+ if (!ped->cch)
+ {
+ ped->maxPixelWidth = 0;
+ ped->xOffset = 0;
+ ped->screenStart = 0;
+ ped->cLines = 1;
+ return(TRUE);
+ }
+
+ if (fUserTyping && cchDelta)
+ MLShiftchLines(ped, iLine+1, cchDelta);
+
+ hdc = ECGetEditDC(ped, TRUE);
+
+ if (!iLine && !cchDelta && !fUserTyping)
+ {
+ /* Reset maxpixelwidth only if we will be running through the whole
+ * text. Better too long than too short.
+ */
+ ped->maxPixelWidth = 0;
+ /* Reset number of lines in text since we will be running through all
+ * the text anyway...
+ */
+ ped->cLines = 1;
+ }
+
+ /* Set min and max line built to be the starting line */
+ minCchBreak = maxCchBreak = (cchDelta ? ped->chLines[iLine] : 0);
+
+ ptext = LocalLock(ped->hText);
+
+ ichCRLF = ichLineStart = ped->chLines[iLine];
+
+ while (ichLineStart < ped->cch)
+ {
+ if (ichLineStart >= ichCRLF)
+ {
+ ichCRLF = ichLineStart;
+ /* Move ichCRLF ahead to either the first CR or to the end of text.
+ */
+ while (ichCRLF < ped->cch && *(ptext+ichCRLF) != 0x0D)
+ ichCRLF++;
+ }
+
+ if (!ped->fWrap)
+ {
+ /* If we are not word wrapping, line breaks are signified by CRLF.
+ */
+
+ /* We will limit lines to MAXLINELENGTH characters maximum */
+ ichLineEnd=ichLineStart + umin(ichCRLF-ichLineStart,MAXLINELENGTH);
+
+#ifdef DBCS
+ /* To avoid separating between DBCS char, adjust character
+ * position to DBCS lead byte if necessary.
+ */
+ ichLineEnd = ECAdjustIch(ped, ptext, ichLineEnd);
+#endif
+ /* We will keep track of what the longest line is for the horizontal
+ * scroll bar thumb positioning.
+ */
+ ped->maxPixelWidth = umax(ped->maxPixelWidth,
+ (unsigned int)
+ LOWORD(LocGetTabbedTextExtent(hdc,
+ (ptext+ichLineStart),
+ ichLineEnd-ichLineStart,
+ ped)));
+ }
+ else
+ {
+ /* Find the end of the line based solely on text extents */
+ ichLineEnd = ichLineStart +
+ ECCchInWidth(ped, hdc, (LPSTR)(ptext+ichLineStart),
+ ichCRLF-ichLineStart,
+ ped->rcFmt.right-ped->rcFmt.left);
+ if (ichLineEnd == ichLineStart && ichCRLF-ichLineStart)
+ {
+ /* Maintain a minimum of one char per line */
+ ichLineEnd++;
+ }
+
+
+#ifdef NEVER
+ /* Now starting from ichLineEnd, if we are not at a hard line break,
+ * then if we are not at a space (or CR) or the char before us is
+ * not a space, we will look word left for the start of the word to
+ * break at.
+ */
+ if (ichLineEnd != ichCRLF)
+ if (!MLIsDelimiter(*(ptext+ichLineEnd)) ||
+ *(ptext+ichLineEnd) == 0x0D ||
+ !MLIsDelimiter(*(ptext+ichLineEnd-1)))
+#else
+ /* Now starting from ichLineEnd, if we are not at a hard line break,
+ * then if we are not at a space AND the char before us is
+ * not a space,(OR if we are at a CR) we will look word left for the
+ * start of the word to break at.
+ * This change was done for TWO reasons:
+ * 1. If we are on a delimiter, no need to look word left to break at.
+ * 2. If the previous char is a delimter, we can break at current char.
+ * Change done by -- SANKAR --01/31/91--
+ */
+ if (ichLineEnd != ichCRLF)
+ if ((!MLIsDelimiter(*(ptext+ichLineEnd)) &&
+ !MLIsDelimiter(*(ptext+ichLineEnd-1))) ||
+ *(ptext+ichLineEnd) == 0x0D)
+#endif
+ {
+#ifdef DBCS
+ cch = LOWORD(ECWord(ped, ichLineEnd, FALSE));
+#else
+ cch = LOWORD(ECWord(ped, ichLineEnd, TRUE));
+#endif
+ if (cch > ichLineStart)
+ ichLineEnd = cch;
+ /* Now, if the above test fails, it means the word left goes
+ * back before the start of the line ie. a word is longer
+ * than a line on the screen. So, we just fit as much of
+ * the word on the line as possible. Thus, we use the
+ * pLineEnd we calculated solely on width at the beginning
+ * of this else block...
+ */
+ }
+ }
+#if 0
+ if (!MLIsDelimiter((*(ptext+ichLineEnd-1))) &&
+ MLIsDelimiter((*(ptext+ichLineEnd))))
+#endif
+ if ((*(ptext+ichLineEnd-1)!= ' ' && *(ptext+ichLineEnd-1)!= TAB) &&
+ (*(ptext+ichLineEnd) == ' ' || *(ptext+ichLineEnd) == TAB))
+ /* Swallow the space at the end of a line. */
+ ichLineEnd++;
+
+ /* Skip over crlf or crcrlf if it exists. Thus, ichLineEnd is the first
+ * character in the next line.
+ */
+ ichLineEndBeforeCRLF = ichLineEnd;
+
+ if (*(ptext+ichLineEnd) == 0x0D)
+ ichLineEnd +=2;
+ /* Skip over CRCRLF */
+ if (*(ptext+ichLineEnd) == 0x0A)
+ ichLineEnd++;
+
+ /* Now, increment iLine, allocate space for the next line, and set its
+ * starting point
+ */
+ iLine++;
+
+ if (!fUserTyping ||/* (iLineStart+1 >= iLine) || */
+ (iLine > ped->cLines-1) ||
+ (ped->chLines[iLine] != ichLineEnd))
+ {
+ /* The line break occured in a different place than before. */
+ if (!fLineBroken)
+ {
+ /* Since we haven't broken a line before, just set the min break
+ * line.
+ */
+ fLineBroken = TRUE;
+ if (ichLineEndBeforeCRLF == ichLineEnd)
+ minCchBreak = maxCchBreak = (ichLineEnd ? ichLineEnd-1 : 0);
+ else
+ minCchBreak = maxCchBreak = ichLineEndBeforeCRLF;
+ }
+ maxCchBreak = umax(maxCchBreak,ichLineEnd);
+
+ LocalUnlock(ped->hText);
+ /* Now insert the new line into the array */
+ if (!MLInsertchLine(ped, iLine, ichLineEnd, (BOOL)(cchDelta!=0)))
+ {
+ ECReleaseEditDC(ped,hdc,TRUE);
+ return(MAKELONG(minCchBreak,maxCchBreak));
+ }
+
+ ptext = LocalLock(ped->hText);
+ }
+ else
+ {
+ maxCchBreak = ped->chLines[iLine];
+ /* Quick escape */
+ goto EndUp;
+ }
+
+ ichLineStart = ichLineEnd;
+ } /* end while (ichLineStart < ped->cch) */
+
+
+ if (iLine != ped->cLines)
+ {
+ ped->cLines = iLine;
+ ped->chLines[ped->cLines] = 0;
+ }
+
+ /* Note that we incremented iLine towards the end of the while loop so, the
+ * index, iLine, is actually equal to the line count
+ */
+ if (ped->cch &&
+ *(ptext+ped->cch-1) == 0x0A &&
+ ped->chLines[ped->cLines-1]<ped->cch)
+ /* Make sure last line has no crlf in it */
+ {
+ if (!fLineBroken)
+ {
+ /* Since we haven't broken a line before, just set the min break
+ * line.
+ */
+ fLineBroken = TRUE;
+ minCchBreak = ped->cch-1;
+ }
+ maxCchBreak= umax(maxCchBreak,ichLineEnd);
+ LocalUnlock(ped->hText);
+ MLInsertchLine(ped, iLine, ped->cch, FALSE);
+ }
+ else
+EndUp:
+ LocalUnlock(ped->hText);
+
+ ECReleaseEditDC(ped, hdc, TRUE);
+ return(MAKELONG(minCchBreak,maxCchBreak));
+}
+
+
+void NEAR PASCAL MLPaintHandler(register PED ped,
+ HDC althdc)
+/* effects: Handles WM_PAINT messages.
+ */
+{
+ PAINTSTRUCT ps;
+ HDC hdc;
+ HDC hdcWindow;
+ RECT rcEdit;
+ DWORD dwStyle;
+ HANDLE hOldFont;
+ POINT pt;
+ ICH imin;
+ ICH imax;
+
+ /* Allow subclassed hdcs.
+ */
+ if (althdc)
+ hdc = althdc;
+ else
+ hdc = BeginPaint(ped->hwnd, (PAINTSTRUCT FAR *)&ps);
+
+ if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
+ {
+#if 0
+ if (althdc || ps.fErase)
+ {
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+ /* Erase the background since we don't do it in the erasebkgnd
+ * message
+ */
+ FillWindow(ped->hwndParent, ped->hwnd, hdc, hBrush);
+ }
+#endif
+ if (ped->fBorder)
+ {
+// hdcWindow = GetWindowDC(ped->hwnd);
+ hdcWindow = hdc;
+ GetWindowRect(ped->hwnd, &rcEdit);
+ OffsetRect(&rcEdit, -rcEdit.left, -rcEdit.top);
+
+ dwStyle = GetWindowLong(ped->hwnd, GWL_STYLE);
+ if (HIWORD(dwStyle) & HIWORD(WS_SIZEBOX))
+ {
+ /* Note we can't use user's globals here since we are on a
+ * different ds when in the edit control code.
+ */
+ InflateRect(&rcEdit,
+ -GetSystemMetrics(SM_CXFRAME)+
+ GetSystemMetrics(SM_CXBORDER),
+ -GetSystemMetrics(SM_CYFRAME)+
+ GetSystemMetrics(SM_CYBORDER));
+
+ }
+
+ DrawFrame(hdcWindow, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
+// ReleaseDC(ped->hwnd, hdcWindow);
+ }
+
+ ECSetEditClip(ped, hdc);
+ if (ped->hFont)
+ hOldFont = SelectObject(hdc, ped->hFont);
+
+ if (!althdc)
+ {
+ pt.x = ps.rcPaint.left;
+ pt.y = ps.rcPaint.top;
+ imin = MLMouseToIch(ped, hdc, pt)-1;
+ if (imin == -1)
+ imin = 0;
+ pt.x = ps.rcPaint.right;
+ pt.y = ps.rcPaint.bottom;
+ imax = MLMouseToIch(ped, hdc, pt)+1;
+ MLDrawText(ped, hdc, imin, imax);
+ }
+ else
+ MLDrawText(ped, hdc, 0, ped->cch);
+
+ if (ped->hFont && hOldFont)
+ SelectObject(hdc, hOldFont);
+ }
+
+ if (!althdc)
+ EndPaint(ped->hwnd, (PAINTSTRUCT FAR *)&ps);
+}
+
+
+void FAR PASCAL MLCharHandler(ped, keyValue, keyMods)
+register PED ped;
+WORD keyValue;
+int keyMods;
+/* effects: Handles character input (really, no foolin')
+ */
+{
+ char unsigned keyPress = LOBYTE(keyValue);
+ BOOL updateText = FALSE;
+ int scState;
+#ifdef DBCS
+ WORD DBCSkey;
+#endif
+
+ if (ped->fMouseDown || keyPress == VK_ESCAPE)
+ /* If we are in the middle of a mousedown command, don't do anything.
+ * Also, just ignore it if we get a translated escape key which happens
+ * with multiline edit controls in a dialog box.
+ */
+ return;
+
+ if (!keyMods)
+ {
+ /* Get state of modifier keys for use later. */
+ scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
+ /* We are just interested in state of the ctrl key */
+ /* scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0); */
+ }
+ else
+ scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
+
+ if (ped->fInDialogBox && ((keyPress == VK_TAB && scState != CTRLDOWN) ||
+ keyPress == VK_RETURN))
+ /* If this multiline edit control is in a dialog box, then we want the
+ * TAB key to take you to the next control, shift TAB to take you to the
+ * previous control, and CTRL-TAB to insert a tab into the edit control.
+ * We moved the focus when we received the keydown message so we will
+ * ignore the TAB key now unless the ctrl key is down. Also, we want
+ * CTRL-RETURN to insert a return into the text and RETURN to be sent to
+ * the default button.
+ */
+ return;
+
+ if (ped->fReadOnly)
+ /* Ignore keys in read only controls.
+ */
+ return;
+
+ if (keyPress == 0x0A)
+ keyPress = VK_RETURN;
+
+ if (keyPress == VK_TAB || keyPress == VK_RETURN ||
+ keyPress == VK_BACK || keyPress >= ' ')
+ /* Delete the selected text if any */
+ if (MLDeleteText(ped))
+ updateText=TRUE;
+
+#ifdef DBCS
+ if( IsDBCSLeadByte( keyPress ) )
+ if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
+ keyValue = DBCSkey;
+#endif
+
+ switch(keyPress)
+ {
+ case VK_BACK:
+ /* Delete any selected text or delete character left if no sel */
+ if (!updateText && ped->ichMinSel)
+ {
+ /* There was no selection to delete so we just delete character
+ * left if available
+ */
+ ped->ichMinSel = MLMoveSelection(ped,ped->ichCaret,TRUE);
+ MLDeleteText(ped);
+ }
+ break;
+
+ default:
+ if (keyPress == VK_RETURN)
+ keyValue = 0x0A0D;
+
+ if (keyPress >= ' ' || keyPress == VK_RETURN || keyPress == VK_TAB)
+ MLInsertText(ped, (LPSTR) &keyValue,
+ HIBYTE(keyValue) ? 2 : 1, TRUE);
+ else
+ MessageBeep(0);
+
+ break;
+ }
+}
+
+
+void NEAR PASCAL MLKeyDownHandler(register PED ped,
+ WORD virtKeyCode,
+ int keyMods)
+/* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
+ * us to make MLKeyDownHandler calls and specify if the modifier keys (shift
+ * and control) are up or down. If keyMods == 0, we get the keyboard state
+ * using GetKeyState(VK_SHIFT) etc. Otherwise, the bits in keyMods define the
+ * state of the shift and control keys.
+ */
+{
+ HDC hdc;
+
+ /* Variables we will use for redrawing the updated text */
+ register ICH newMaxSel = ped->ichMaxSel;
+ register ICH newMinSel = ped->ichMinSel;
+
+ /* Flags for drawing the updated text */
+ BOOL changeSelection = FALSE; /* new selection is specified by
+ newMinSel, newMaxSel */
+
+ /* Comparisons we do often */
+ BOOL MinEqMax = (newMaxSel == newMinSel);
+ BOOL MinEqCar = (ped->ichCaret == newMinSel);
+ BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
+
+ /* State of shift and control keys. */
+ int scState = 0;
+
+ long position;
+ BOOL prevLine;
+ POINT mousePt;
+ int defaultDlgId;
+ int iScrollAmt;
+
+
+ if (ped->fMouseDown)
+ /* If we are in the middle of a mousedown command, don't do anything.
+ */
+ return;
+
+ if (!keyMods)
+ {
+ /* Get state of modifier keys for use later. */
+ scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
+ scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
+ }
+ else
+ scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
+
+
+ switch(virtKeyCode)
+ {
+ case VK_ESCAPE:
+ if (ped->fInDialogBox)
+ {
+ /* This condition is removed because, if the dialogbox does not
+ * have a CANCEL button and if ESC is hit when focus is on a
+ * ML edit control the dialogbox must close whether it has cancel
+ * button or not to be consistent with SL edit control;
+ * DefDlgProc takes care of the disabled CANCEL button case.
+ * Fix for Bug #4123 -- 02/07/91 -- SANKAR --
+ */
+#if 0
+ if (GetDlgItem(ped->hwndParent, IDCANCEL))
+#endif
+ /* User hit ESC...Send a close message (which in turn sends a
+ * cancelID to the app in DefDialogProc...
+ */
+ PostMessage(ped->hwndParent, WM_CLOSE, 0, 0L);
+ }
+ return;
+
+ case VK_RETURN:
+ if (ped->fInDialogBox)
+ {
+ /* If this multiline edit control is in a dialog box, then we want
+ * the RETURN key to be sent to the default dialog button (if there
+ * is one). CTRL-RETURN will insert a RETURN into the text. Note
+ * that CTRL-RETURN automatically translates into a linefeed (0x0A)
+ * and in the MLCharHandler, we handle this as if a return was
+ * entered.
+ */
+ if (scState != CTRLDOWN)
+ {
+ defaultDlgId = LOWORD(SendMessage(ped->hwndParent,
+ DM_GETDEFID,
+ 0, 0L));
+ if (defaultDlgId)
+ {
+ defaultDlgId=(WORD)GetDlgItem(ped->hwndParent,
+ defaultDlgId);
+ if (defaultDlgId)
+ {
+ SendMessage(ped->hwndParent, WM_NEXTDLGCTL,
+ defaultDlgId, 1L);
+ if (!ped->fFocus)
+ PostMessage((HWND)defaultDlgId,
+ WM_KEYDOWN, VK_RETURN, 0L);
+ }
+ }
+ }
+
+ return;
+ }
+ break;
+
+ case VK_TAB:
+ /* If this multiline edit control is in a dialog box, then we want the
+ * TAB key to take you to the next control, shift TAB to take you to the
+ * previous control. We always want CTRL-TAB to insert a tab into the
+ * edit control regardless of weather or not we're in a dialog box.
+ */
+ if (scState == CTRLDOWN)
+ MLCharHandler(ped, virtKeyCode, keyMods);
+ else
+ if (ped->fInDialogBox)
+ SendMessage(ped->hwndParent, WM_NEXTDLGCTL,
+ scState==SHFTDOWN, 0L);
+ return;
+ break;
+
+ case VK_LEFT:
+ /* If the caret isn't already at 0, we can move left */
+ if (ped->ichCaret)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret left */
+ ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, TRUE);
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret left */
+ ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, TRUE);
+ if (MaxEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMaxSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ /* Hint: Suppose WORD. OR is selected. Cursor between
+ R and D. Hit select word left, we want to just select
+ the W and leave cursor before the W. */
+ newMinSel = ped->ichMinSel;
+ newMaxSel = ped->ichCaret;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move left and we are at the 0th character
+ and there is a selection, then cancel the selection. */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ changeSelection = TRUE;
+ newMaxSel = newMinSel = ped->ichCaret;
+ }
+ }
+ break;
+
+
+ case VK_RIGHT:
+ /* If the caret isn't already at ped->cch, we can move right */
+ if (ped->ichCaret < ped->cch)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret right */
+ ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret right */
+ ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
+ if (MinEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ if (MinEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move right and we are at the last character
+ * and there is a selection, then cancel the selection.
+ */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ newMaxSel = newMinSel = ped->ichCaret;
+ changeSelection = TRUE;
+ }
+ }
+ break;
+
+
+ case VK_UP:
+ case VK_DOWN:
+ if (virtKeyCode == VK_UP &&
+ ped->cLines-1 != ped->iCaretLine &&
+ ped->ichCaret == ped->chLines[ped->iCaretLine+1])
+ prevLine= TRUE;
+ else
+ prevLine=FALSE;
+
+ hdc = ECGetEditDC(ped,TRUE);
+ position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
+ ECReleaseEditDC(ped, hdc, TRUE);
+ mousePt.x = LOWORD(position);
+ mousePt.y = HIWORD(position)+1+
+ (virtKeyCode == VK_UP ? -ped->lineHeight : ped->lineHeight);
+
+ if (scState == NONEDOWN || scState == SHFTDOWN)
+ {
+ /* Send fake mouse messages to handle this */
+ /* NONEDOWN: Clear selection, move caret up/down 1 line */
+ /* SHFTDOWN: Extend selection, move caret up/down 1 line */
+ MLMouseMotionHandler(ped, WM_LBUTTONDOWN,
+ scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
+ MLMouseMotionHandler(ped, WM_LBUTTONUP,
+ scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
+ }
+ break;
+
+
+ case VK_HOME:
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move cursor to beginning of line */
+ newMaxSel = newMinSel = ped->ichCaret =
+ ped->chLines[ped->iCaretLine];
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret to beginning of text */
+ newMaxSel = newMinSel = ped->ichCaret = 0;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret to beginning of line */
+ ped->ichCaret = ped->chLines[ped->iCaretLine];
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichMinSel;
+ newMaxSel = ped->ichCaret;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret to beginning of text */
+ ped->ichCaret = newMinSel = 0;
+ if (MaxEqCar && !MinEqMax)
+ /* Reduce/negate selection extent */
+ newMaxSel = ped->ichMinSel;
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_END:
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret to end of line */
+ newMaxSel = newMinSel = ped->ichCaret =
+ ped->chLines[ped->iCaretLine]+MLLineLength(ped, ped->iCaretLine);
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret to end of text */
+ newMaxSel = newMinSel = ped->ichCaret = ped->cch;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret to end of line */
+ ped->ichCaret = ped->chLines[ped->iCaretLine]+
+ MLLineLength(ped, ped->iCaretLine);
+ if (MinEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ newMaxSel = ped->ichCaret = ped->cch;
+ /* Extend selection, move caret to end of text */
+ if (MinEqCar && !MinEqMax)
+ /* Reduce/negate selection extent */
+ newMinSel = ped->ichMaxSel;
+ /* else Extend selection extent */
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_PRIOR:
+ case VK_NEXT:
+
+ switch (scState)
+ {
+ case NONEDOWN:
+ case SHFTDOWN:
+ /* Vertical scroll by one visual screen */
+ hdc = ECGetEditDC(ped,TRUE);
+ position = MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine);
+ ECReleaseEditDC(ped, hdc, TRUE);
+ mousePt.x = LOWORD(position);
+ mousePt.y = HIWORD(position)+1;
+
+ SendMessage(ped->hwnd, WM_VSCROLL,
+ virtKeyCode == VK_PRIOR ? SB_PAGEUP : SB_PAGEDOWN,
+ 0L);
+
+ /* Move the cursor there */
+ MLMouseMotionHandler(ped, WM_LBUTTONDOWN,
+ scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
+ MLMouseMotionHandler(ped, WM_LBUTTONUP,
+ scState==NONEDOWN ? 0 : MK_SHIFT, mousePt);
+ break;
+
+ case CTRLDOWN:
+ /* Horizontal scroll by one screenful minus one char */
+ iScrollAmt = ((ped->rcFmt.right - ped->rcFmt.left)
+ /ped->aveCharWidth) - 1;
+ if(virtKeyCode == VK_PRIOR)
+ iScrollAmt *= -1; /* For previous page */
+
+ SendMessage(ped->hwnd, WM_HSCROLL,
+ EM_LINESCROLL, (long)iScrollAmt);
+
+ break;
+ }
+ break;
+
+ case VK_DELETE:
+ if (ped->fReadOnly)
+ break;
+
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection. If no selection, delete (clear) character
+ * right
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ /* Move cursor forwards and send a backspace message... */
+ ped->ichCaret = MLMoveSelection(ped, ped->ichCaret, FALSE);
+ ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
+ SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
+ break;
+
+ case SHFTDOWN:
+ /* CUT selection ie. remove and copy to clipboard, or if no
+ * selection, delete (clear) character left.
+ */
+
+ if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
+ (ped->ichMinSel == ped->ichMaxSel))
+ /* If copy successful, delete the copied text by sending a
+ * backspace message which will redraw the text and take care
+ * of notifying the parent of changes. Or if there is no
+ * selection, just delete char left.
+ */
+ SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, or delete to end of line if no selection
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ ped->ichMaxSel = ped->ichCaret =
+ ped->chLines[ped->iCaretLine]+
+ MLLineLength(ped, ped->iCaretLine);
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
+ break;
+ }
+
+ /*
+ * No need to update text or selection since BACKSPACE message does it
+ * for us.
+ */
+ break;
+
+ case VK_INSERT:
+ if (scState == CTRLDOWN ||
+ (scState == SHFTDOWN && !ped->fReadOnly))
+ /* if CTRLDOWN Copy current selection to clipboard */
+ /* if SHFTDOWN Paste clipboard */
+ SendMessage(ped->hwnd, scState == CTRLDOWN ? WM_COPY : WM_PASTE,
+ (WORD)NULL, (LONG)NULL);
+ break;
+
+ }
+
+ if (changeSelection)
+ {
+ hdc = ECGetEditDC(ped,FALSE);
+ MLChangeSelection(ped,hdc,newMinSel,newMaxSel);
+ /* Set the caret's line */
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ if (virtKeyCode == VK_END && ped->ichCaret < ped->cch && ped->fWrap &&
+ ped->iCaretLine > 0)
+ {
+ /* Handle moving to the end of a word wrapped line. This keeps the
+ * cursor from falling to the start of the next line if we have word
+ * wrapped and there is no CRLF.
+ */
+ if (*((PSTR)LMHtoP(ped->hText)+ped->chLines[ped->iCaretLine]-2) !=
+ 0x0D)
+ ped->iCaretLine--;
+ }
+ /* Since drawtext sets the caret position */
+ MLSetCaretPosition(ped,hdc);
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+ /* Make sure we can see the cursor */
+ MLEnsureCaretVisible(ped);
+ }
+
+}
+
+
+ICH PASCAL NEAR MLPasteText(register PED ped)
+/* effects: Pastes a line of text from the clipboard into the edit control
+ * starting at ped->ichCaret. Updates ichMaxSel and ichMinSel to point to the
+ * end of the inserted text. Notifies the parent if space cannot be
+ * allocated. Returns how many characters were inserted.
+ */
+{
+ HANDLE hData;
+ LPSTR lpchClip;
+ LPSTR lpchClip2;
+ register ICH cchAdded=0; /* No added data initially */
+ DWORD clipboardDataSize;
+ HCURSOR hCursorOld;
+
+ if (!ped->fAutoVScroll)
+ /* Empty the undo buffer if this edit control limits the amount of text
+ * the user can add to the window rect. This is so that we can undo this
+ * operation if doing in causes us to exceed the window boundaries.
+ */
+ ECEmptyUndo(ped);
+
+ /* See if any text should be deleted */
+ MLDeleteText(ped);
+
+ hCursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
+
+ if (!OpenClipboard(ped->hwnd))
+ goto PasteExitNoCloseClip;
+
+
+ if (!(hData = GetClipboardData(CF_TEXT)))
+ {
+ goto PasteExit;
+ }
+
+ if (GlobalFlags(hData) & GMEM_DISCARDED)
+ {
+ goto PasteExit;
+ }
+
+ lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
+
+ /* Assumes lstrlen returns at most 64K
+ */
+ cchAdded = umin((WORD)lstrlen(lpchClip),64000L);
+
+ /* Insert the text (MLInsertText checks line length) */
+ cchAdded = MLInsertText(ped, lpchClip, cchAdded, FALSE);
+
+ GlobalUnlock(hData);
+
+
+PasteExit:
+ CloseClipboard();
+
+PasteExitNoCloseClip:
+ if (hCursorOld)
+ SetCursor(hCursorOld);
+
+ return(cchAdded);
+}
+
+
+void NEAR PASCAL MLMouseMotionHandler(register PED ped,
+ WORD message,
+ WORD virtKeyDown,
+ POINT mousePt)
+{
+ LONG selection;
+ BOOL updateText = FALSE;
+ BOOL changeSelection = FALSE;
+
+ HDC hdc = ECGetEditDC(ped,TRUE);
+
+ ICH newMaxSel = ped->ichMaxSel;
+ ICH newMinSel = ped->ichMinSel;
+ ICH ichStart = ped->screenStart;
+
+ ICH mouseCch;
+ ICH mouseLine;
+ int i,j;
+
+ selection = MLMouseToIch(ped, hdc, mousePt);
+ mouseCch = LOWORD(selection);
+ mouseLine = HIWORD(selection);
+
+ /* Save for timer */
+ ped->ptPrevMouse = mousePt;
+ ped->prevKeys = virtKeyDown;
+
+ switch (message)
+ {
+ case WM_LBUTTONDBLCLK:
+ /*
+ * if shift key is down, extend selection to word we double clicked on
+ * else clear current selection and select word.
+ */
+#ifdef DBCS
+ /*
+ * if character on the caret is DBCS, word selection is only one
+ * DBCS character on the caret (or right side from the caret).
+ */
+ {
+ PSTR pCaretChr = LocalLock(ped->hText)+ped->ichCaret;
+ selection = ECWord(ped,ped->ichCaret,
+ ECIsDBCSLeadByte(ped,*pCaretChr) ? FALSE : TRUE);
+ LocalUnlock(ped->hText);
+ }
+#else
+ selection = ECWord(ped,ped->ichCaret,TRUE);
+#endif
+ newMinSel = LOWORD(selection);
+ newMaxSel = ped->ichCaret = HIWORD(selection);
+
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ changeSelection = TRUE;
+ /*
+ * Set mouse down to false so that the caret isn't reposition on the
+ * mouseup message or on a accidental move...
+ */
+ ped->fMouseDown = FALSE;
+ break;
+
+ case WM_MOUSEMOVE:
+ if (ped->fMouseDown)
+ {
+ /* Set the system timer to automatically scroll when mouse is
+ * outside of the client rectangle. Speed of scroll depends on
+ * distance from window.
+ */
+ i = mousePt.y < 0 ? -mousePt.y : mousePt.y - ped->rcFmt.bottom;
+ j = 400 - ((WORD)i << 4);
+ if (j < 100)
+ j = 100;
+ SetTimer(ped->hwnd, 1, j, (FARPROC)NULL);
+
+ changeSelection = TRUE;
+ /* Extend selection, move caret right */
+ if ((ped->ichMinSel == ped->ichCaret) &&
+ (ped->ichMinSel != ped->ichMaxSel))
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret = mouseCch;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ {
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret=mouseCch;
+ }
+ ped->iCaretLine = mouseLine;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+/* if (ped->fFocus)
+ {*/
+ /*
+ * Only handle this if we have the focus.
+ */
+ ped->fMouseDown = TRUE;
+ SetCapture(ped->hwnd);
+ changeSelection = TRUE;
+ if (!(virtKeyDown & MK_SHIFT))
+ {
+ /*
+ * If shift key isn't down, move caret to mouse point and clear
+ * old selection
+ */
+ newMinSel = newMaxSel = ped->ichCaret = mouseCch;
+ ped->iCaretLine = mouseLine;
+ }
+ else
+ {
+ /*
+ * Shiftkey is down so we want to maintain the current selection
+ * (if any) and just extend or reduce it
+ */
+ if (ped->ichMinSel == ped->ichCaret)
+ newMinSel = ped->ichCaret = mouseCch;
+ else
+ newMaxSel = ped->ichCaret = mouseCch;
+ ped->iCaretLine = mouseLine;
+ }
+
+ /*
+ * Set the timer so that we can scroll automatically when the mouse
+ * is moved outside the window rectangle.
+ */
+ ped->ptPrevMouse=mousePt;
+ ped->prevKeys = virtKeyDown;
+ SetTimer(ped->hwnd, 1, 400, (FARPROC)NULL);
+/* }*/
+ break;
+
+ case WM_LBUTTONUP:
+ if (ped->fMouseDown)
+ {
+ /* Kill the timer so that we don't do auto mouse moves anymore */
+ KillTimer(ped->hwnd, 1);
+ ReleaseCapture();
+ MLSetCaretPosition(ped,hdc);
+ ped->fMouseDown = FALSE;
+ }
+ break;
+ }
+
+
+ if (changeSelection)
+ {
+ MLChangeSelection(ped, hdc, newMinSel, newMaxSel);
+ MLEnsureCaretVisible(ped);
+ }
+
+ ECReleaseEditDC(ped,hdc,TRUE);
+
+ if (!ped->fFocus && (message == WM_LBUTTONDOWN))
+ /* If we don't have the focus yet, get it */
+ SetFocus(ped->hwnd);
+
+}
+
+
+
+int NEAR PASCAL MLPixelFromCount(register PED ped,
+ int dCharLine,
+ WORD message)
+/* effects: Given a character or line count (depending on message == hscroll
+ * or vscroll), calculate the number of pixels we must scroll to get there.
+ * Updates the start of screen or xoffset to reflect the new positions.
+ */
+{
+ /* This can be an int since we can have 32K max lines/pixels
+ */
+ int oldLineChar;
+
+
+ if (message != WM_HSCROLL)
+ {
+ /* We want to scroll screen by dCharLine lines */
+ oldLineChar = ped->screenStart;
+
+ /* Find the new starting line for the ped */
+ ped->screenStart = max(ped->screenStart+dCharLine,0);
+ ped->screenStart = min(ped->screenStart,ped->cLines-1);
+
+ dCharLine = oldLineChar - ped->screenStart;
+
+ /* We will scroll at most a screen full of text */
+ if (dCharLine < 0)
+ dCharLine = -min(-dCharLine, ped->ichLinesOnScreen);
+ else
+ dCharLine = min(dCharLine, ped->ichLinesOnScreen);
+
+ return(dCharLine*ped->lineHeight);
+ }
+
+ /* No horizontal scrolling allowed if funny format */
+ if (ped->format != ES_LEFT)
+ return(0);
+
+ /* Convert delta characters into delta pixels */
+ dCharLine = dCharLine*ped->aveCharWidth;
+
+ oldLineChar = ped->xOffset;
+
+ /* Find new horizontal starting point */
+ ped->xOffset = max(ped->xOffset+dCharLine,0);
+ ped->xOffset = min(ped->xOffset,ped->maxPixelWidth);
+
+ dCharLine = oldLineChar - ped->xOffset;
+
+ /* We will scroll at most a screen full of text */
+ if (dCharLine < 0)
+ dCharLine = -min(-dCharLine, ped->rcFmt.right+1-ped->rcFmt.left);
+ else
+ dCharLine = min(dCharLine, ped->rcFmt.right+1-ped->rcFmt.left);
+
+ return(dCharLine);
+}
+
+
+int NEAR PASCAL MLPixelFromThumbPos(register PED ped,
+ int pos,
+ BOOL fVertical)
+/* effects: Given a thumb position from 0 to 100, return the number of pixels
+ * we must scroll to get there.
+ */
+{
+ int dxy;
+ int iLineOld;
+ ICH iCharOld;
+
+ if (fVertical)
+ {
+ iLineOld = ped->screenStart;
+ ped->screenStart = (int)MultDiv(ped->cLines-1, pos, 100);
+ ped->screenStart = min(ped->screenStart,ped->cLines-1);
+ dxy = (iLineOld - ped->screenStart)*ped->lineHeight;
+ }
+ else
+ {
+ /* Only allow horizontal scrolling with left justified text */
+ if (ped->format == ES_LEFT)
+ {
+ iCharOld = ped->xOffset;
+ ped->xOffset = MultDiv(ped->maxPixelWidth-ped->aveCharWidth, pos, 100);
+ dxy = iCharOld - ped->xOffset;
+ }
+ else
+ dxy = 0;
+ }
+
+ return(dxy);
+}
+
+
+int FAR PASCAL MLThumbPosFromPed(register PED ped,
+ BOOL fVertical)
+/*
+ * effects: Given the current state of the edit control, return its vertical
+ * thumb position if fVertical else returns its horizontal thumb position.
+ * The thumb position ranges from 0 to 100.
+ */
+{
+ WORD d1;
+ WORD d2;
+
+ if (fVertical)
+ {
+ if (ped->cLines < 2)
+ return(0);
+ d1 = (WORD)(ped->screenStart);
+ d2 = (WORD)(ped->cLines-1);
+ }
+ else
+ {
+ if (ped->maxPixelWidth < (ped->aveCharWidth*2))
+ return(0);
+ d1 = (WORD)(ped->xOffset);
+ d2 = (WORD)(ped->maxPixelWidth);
+ }
+
+ /* Do the multiply/division and avoid overflows and divide by zero errors */
+ return(MultDiv(d1, 100, d2));
+}
+
+
+LONG NEAR PASCAL MLScrollHandler(register PED ped,
+ WORD message,
+ int cmd,
+ int iAmt)
+{
+ RECT rc;
+ RECT rcUpdate;
+ int dx;
+ int dy;
+ int dcharline;
+ BOOL fVertical;
+ HDC hdc;
+
+ UpdateWindow(ped->hwnd);
+
+ /* Are we scrolling vertically or horizontally? */
+ fVertical = (message != WM_HSCROLL);
+ dx = dy = dcharline = 0;
+
+ switch (cmd)
+ {
+ case SB_LINEDOWN:
+ dcharline = 1;
+ break;
+
+ case SB_LINEUP:
+ dcharline = -1;
+ break;
+
+ case SB_PAGEDOWN:
+ dcharline = ped->ichLinesOnScreen-1;
+ break;
+
+ case SB_PAGEUP:
+ dcharline = -(ped->ichLinesOnScreen-1);
+ break;
+
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION:
+ dy = MLPixelFromThumbPos(ped, iAmt, fVertical);
+ dcharline = -dy / (message == WM_VSCROLL ? ped->lineHeight :
+ ped->aveCharWidth);
+ if (!fVertical)
+ {
+ dx = dy;
+ dy = 0;
+ }
+ break;
+
+ case EM_LINESCROLL:
+ dcharline = iAmt;
+ break;
+
+ case EM_GETTHUMB:
+ return(MLThumbPosFromPed(ped,fVertical));
+ break;
+
+ default:
+ return(0L);
+ break;
+ }
+
+ GetClientRect(ped->hwnd, (LPRECT)&rc);
+ IntersectRect((LPRECT)&rc, (LPRECT)&rc, (LPRECT)&ped->rcFmt);
+ rc.bottom++;
+
+ if (cmd != SB_THUMBPOSITION && cmd != SB_THUMBTRACK)
+ {
+ if (message == WM_VSCROLL)
+ {
+ dx = 0;
+ dy = MLPixelFromCount(ped, dcharline, message);
+ }
+ else if (message == WM_HSCROLL)
+ {
+ dx = MLPixelFromCount(ped, dcharline, message);
+ dy = 0;
+ }
+ }
+
+ SetScrollPos(ped->hwnd, fVertical ? SB_VERT : SB_HORZ,
+ (int)MLThumbPosFromPed(ped,fVertical), TRUE);
+
+ if (cmd != SB_THUMBTRACK)
+ /* We don't want to notify the parent of thumbtracking since they might
+ * try to set the thumb position to something bogus. For example
+ * NOTEPAD is such a #@@!@#@ an app since they don't use editcontrol
+ * scroll bars and depend on these EN_*SCROLL messages to update their
+ * fake scroll bars.
+ */
+ ECNotifyParent(ped,fVertical ? EN_VSCROLL : EN_HSCROLL);
+
+ if (!ped->fNoRedraw)
+ {
+ hdc = ECGetEditDC(ped,FALSE);
+ ScrollDC(hdc,dx,dy, (LPRECT)&rc, (LPRECT)&rc, NULL, (LPRECT)&rcUpdate);
+ MLSetCaretPosition(ped,hdc);
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+ if (ped->ichLinesOnScreen+ped->screenStart >= ped->cLines)
+ {
+ InvalidateRect(ped->hwnd, (LPRECT)&rcUpdate, TRUE);
+ }
+ else
+ {
+ InvalidateRect(ped->hwnd, (LPRECT)&rcUpdate, FALSE);
+ }
+ UpdateWindow(ped->hwnd);
+ }
+
+ return(MAKELONG(dcharline, 1));
+}
+
+
+void NEAR PASCAL MLSetFocusHandler(register PED ped)
+/* effects: Gives the edit control the focus and notifies the parent
+ * EN_SETFOCUS.
+ */
+{
+ HDC hdc;
+
+ if (!ped->fFocus)
+ {
+ ped->fFocus = 1; /* Set focus */
+
+ hdc = ECGetEditDC(ped,TRUE);
+
+
+ /* Draw the caret */
+ CreateCaret(ped->hwnd, (HBITMAP)NULL, 2, ped->lineHeight);
+ ShowCaret(ped->hwnd);
+ MLSetCaretPosition(ped, hdc);
+
+ /* Show the current selection. Only if the selection was hidden when we
+ * lost the focus, must we invert (show) it.
+ */
+ if (!ped->fNoHideSel && ped->ichMinSel!=ped->ichMaxSel)
+ MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel);
+
+ ECReleaseEditDC(ped,hdc,TRUE);
+ }
+#if 0
+ MLEnsureCaretVisible(ped);
+#endif
+ /* Notify parent we have the focus */
+ ECNotifyParent(ped, EN_SETFOCUS);
+}
+
+
+void NEAR PASCAL MLKillFocusHandler(register PED ped)
+/* effects: The edit control loses the focus and notifies the parent via
+ * EN_KILLFOCUS.
+ */
+{
+ HDC hdc;
+
+ if (ped->fFocus)
+ {
+ ped->fFocus = 0; /* Clear focus */
+
+ /* Do this only if we still have the focus. But we always notify the
+ * parent that we lost the focus whether or not we originally had the
+ * focus.
+ */
+ /* Hide the current selection if needed */
+ if (!ped->fNoHideSel && ped->ichMinSel!=ped->ichMaxSel)
+ {
+ hdc = ECGetEditDC(ped,FALSE);
+ MLDrawText(ped, hdc, ped->ichMinSel, ped->ichMaxSel);
+ ECReleaseEditDC(ped,hdc,FALSE);
+ }
+
+ /* Destroy the caret */
+ HideCaret(ped->hwnd);
+ DestroyCaret();
+ }
+
+ /* Notify parent that we lost the focus. */
+ ECNotifyParent(ped, EN_KILLFOCUS);
+}
+
+
+
+BOOL FAR PASCAL MLEnsureCaretVisible(ped)
+register PED ped;
+/*
+ * effects: Scrolls the caret into the visible region. Returns TRUE if
+ * scrolling was done else returns FALSE.
+ */
+{
+ int cLinesToScroll;
+ int iLineMax;
+ int xposition;
+ BOOL prevLine;
+ register HDC hdc;
+ BOOL fScrolled = FALSE;
+
+
+ if (IsWindowVisible(ped->hwnd))
+ {
+ if (ped->fAutoVScroll)
+ {
+ iLineMax = ped->screenStart + ped->ichLinesOnScreen-1;
+
+ if (fScrolled = ped->iCaretLine > iLineMax)
+ {
+ MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL,
+ ped->iCaretLine-iLineMax);
+ }
+ else
+ {
+ if (fScrolled = ped->iCaretLine < ped->screenStart)
+ MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL,
+ ped->iCaretLine-ped->screenStart);
+ }
+ }
+
+
+ if (ped->fAutoHScroll &&
+ ped->maxPixelWidth > ped->rcFmt.right-ped->rcFmt.left)
+ {
+ /* Get the current position of the caret in pixels */
+ if (ped->cLines-1 != ped->iCaretLine &&
+ ped->ichCaret == ped->chLines[ped->iCaretLine+1])
+ prevLine=TRUE;
+ else
+ prevLine=FALSE;
+
+ hdc = ECGetEditDC(ped,TRUE);
+ xposition = LOWORD(MLIchToXYPos(ped, hdc, ped->ichCaret, prevLine));
+ ECReleaseEditDC(ped,hdc,TRUE);
+
+ /* Remember, MLIchToXYPos returns coordinates with respect to the
+ * top left pixel displayed on the screen. Thus, if xPosition < 0,
+ * it means xPosition is less than current ped->xOffset.
+ */
+ if (xposition < 0)
+ /* Scroll to the left */
+ MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL,
+ (xposition-(ped->rcFmt.right-ped->rcFmt.left)/3)
+ /ped->aveCharWidth);
+ else if (xposition > ped->rcFmt.right)
+ /* Scroll to the right */
+ MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL,
+ (xposition-ped->rcFmt.right+
+ (ped->rcFmt.right-ped->rcFmt.left)/3)/
+ ped->aveCharWidth);
+ }
+ }
+ xposition = (int)MLThumbPosFromPed(ped,TRUE);
+ if (xposition != GetScrollPos(ped->hwnd, SB_VERT))
+ SetScrollPos(ped->hwnd, SB_VERT, xposition, TRUE);
+
+ xposition = (int)MLThumbPosFromPed(ped,FALSE);
+ if (xposition != GetScrollPos(ped->hwnd, SB_HORZ))
+ SetScrollPos(ped->hwnd, SB_HORZ, xposition, TRUE);
+
+ return(fScrolled);
+}
+
+
+void FAR PASCAL MLSetRectHandler(ped, lprect)
+register PED ped;
+LPRECT lprect;
+/*
+ * effects: Sets the edit control's format rect to be the rect specified if
+ * reasonable. Rebuilds the lines if needed.
+ */
+{
+ RECT rc;
+
+ CopyRect((LPRECT)&rc, lprect);
+
+ if (!(rc.right-rc.left) || !(rc.bottom-rc.top))
+ {
+ if (ped->rcFmt.right - ped->rcFmt.left)
+ {
+ ped->fCaretHidden = 1; // then, hide it.
+ SetCaretPos(-20000, -20000);
+ /* If rect is being set to zero width or height, and our formatting
+ rectangle is already defined, just return. */
+ return;
+ }
+
+ SetRect((LPRECT)&rc, 0, 0, ped->aveCharWidth*10, ped->lineHeight);
+ }
+
+ if (ped->fBorder)
+ /* Shrink client area to make room for the border */
+ InflateRect((LPRECT)&rc, -(ped->cxSysCharWidth/2),
+ -(ped->cySysCharHeight/4));
+
+ /*
+ * If resulting rectangle is too small to do anything with, don't change it
+ */
+ if ((rc.right-rc.left < ped->aveCharWidth) ||
+ ((rc.bottom - rc.top)/ped->lineHeight == 0))
+ {
+ // If the resulting rectangle is too small to display the caret, then
+ // do not display the caret.
+ ped->fCaretHidden = 1;
+ SetCaretPos(-20000, -20000);
+ /* If rect is too narrow or too short, do nothing */
+ return;
+ }
+ else
+ ped->fCaretHidden = 0;
+
+ /* Calc number of lines we can display on the screen */
+ ped->ichLinesOnScreen = (rc.bottom - rc.top)/ped->lineHeight;
+
+ CopyRect((LPRECT)&ped->rcFmt, (LPRECT)&rc);
+
+ /* Get an integral number of lines on the screen */
+ ped->rcFmt.bottom = rc.top+ped->ichLinesOnScreen * ped->lineHeight;
+
+ /* Rebuild the chLines if we are word wrapping only */
+ if (ped->fWrap)
+ {
+ MLBuildchLines(ped, 0, 0, FALSE);
+ // Update the ped->iCaretLine field properly based on ped->ichCaret
+ MLUpdateiCaretLine(ped);
+ }
+}
+
+
+
+
+
+/*******************/
+/* MLEditWndProc() */
+/*******************/
+LONG FAR PASCAL MLEditWndProc(hwnd, ped, message, wParam, lParam)
+HWND hwnd;
+register PED ped;
+WORD message;
+register WORD wParam;
+LONG lParam;
+/* effects: Class procedure for all multi line edit controls.
+ Dispatches all messages to the appropriate handlers which are named
+ as follows:
+ SL (single line) prefixes all single line edit control procedures while
+ EC (edit control) prefixes all common handlers.
+
+ The MLEditWndProc only handles messages specific to multi line edit
+ controls.
+ */
+
+{
+ switch (message)
+ {
+ case WM_CHAR:
+ /* wParam - the value of the key
+ lParam - modifiers, repeat count etc (not used) */
+ MLCharHandler(ped, wParam, 0);
+ break;
+
+ case WM_CLEAR:
+ /* wParam - not used
+ lParam - not used */
+ if (ped->ichMinSel != ped->ichMaxSel && !ped->fReadOnly)
+ SendMessage(ped->hwnd, WM_CHAR, (WORD) BACKSPACE, 0L);
+ break;
+
+ case WM_CUT:
+ /* wParam - not used
+ lParam - not used */
+ if (ped->ichMinSel != ped->ichMaxSel && !ped->fReadOnly)
+ MLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
+ break;
+
+
+ case WM_ERASEBKGND:
+ FillWindow(ped->hwndParent, hwnd, (HDC)wParam, CTLCOLOR_EDIT);
+ return((LONG)TRUE);
+
+ case WM_GETDLGCODE:
+ /* wParam - not used
+ lParam - not used */
+ /* Should also return DLGC_WANTALLKEYS for multiline edit controls */
+ ped->fInDialogBox=TRUE; /* Mark the ML edit ctrl as in a dialog box */
+ return(DLGC_WANTCHARS | DLGC_HASSETSEL |
+ DLGC_WANTARROWS | DLGC_WANTALLKEYS);
+ break;
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ return(MLScrollHandler(ped, message, wParam, (int)lParam));
+ break;
+
+ case WM_KEYDOWN:
+ /* wParam - virt keycode of the given key
+ lParam - modifiers such as repeat count etc. (not used) */
+ MLKeyDownHandler(ped, wParam, 0);
+ break;
+
+ case WM_KILLFOCUS:
+ /* wParam - handle of the window that receives the input focus
+ lParam - not used */
+ MLKillFocusHandler(ped);
+ break;
+
+ case WM_SYSTIMER:
+ /* This allows us to automatically scroll if the user holds the mouse
+ * outside the edit control window. We simulate mouse moves at timer
+ * intervals set in MouseMotionHandler.
+ */
+ if (ped->fMouseDown)
+ MLMouseMotionHandler(ped, WM_MOUSEMOVE,
+ ped->prevKeys,ped->ptPrevMouse);
+ break;
+
+ case WM_MOUSEMOVE:
+ if (!ped->fMouseDown)
+ break;
+ /* else fall through */
+
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ /* wParam - contains a value that indicates which virtual keys are down
+ lParam - contains x and y coords of the mouse cursor */
+ MLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
+ break;
+
+ case WM_CREATE:
+ /* wParam - handle to window being created
+ lParam - points to a CREATESTRUCT that contains copies of parameters
+ passed to the CreateWindow function. */
+ return(MLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
+ break;
+
+ case WM_PAINT:
+ /* wParam - officially not used (but some apps pass in a DC here)
+ lParam - not used */
+ MLPaintHandler(ped, wParam);
+ break;
+
+ case WM_PASTE:
+ /* wParam - not used
+ lParam - not used */
+ if (!ped->fReadOnly)
+ MLPasteText(ped);
+ break;
+
+ case WM_SETFOCUS:
+ /* wParam - handle of window that loses the input focus (may be NULL)
+ lParam - not used */
+ MLSetFocusHandler(ped);
+ break;
+
+ case WM_SETTEXT:
+ /* wParam - not used
+ lParam - points to a null-terminated string that is used to set the
+ window text. */
+ return(MLSetTextHandler(ped, (LPSTR)lParam));
+ break;
+
+ case WM_SIZE:
+ /* wParam - defines the type of resizing fullscreen, sizeiconic,
+ sizenormal etc.
+ lParam - new width in LOWORD, new height in HIGHWORD of client area */
+ MLSizeHandler(ped);
+ break;
+
+ case EM_FMTLINES:
+ /* wParam - indicates disposition of end-of-line chars. If non
+ * zero, the chars CR CR LF are placed at the end of a word
+ * wrapped line. If wParam is zero, the end of line chars are
+ * removed. This is only done when the user gets a handle (via
+ * EM_GETHANDLE) to the text. lParam - not used.
+ */
+ if (wParam)
+ MLInsertCrCrLf(ped);
+ else
+ MLStripCrCrLf(ped);
+ MLBuildchLines(ped, 0, 0, FALSE);
+ return((LONG)(ped->fFmtLines = wParam));
+ break;
+
+ case EM_GETHANDLE:
+ /* wParam - not used
+ lParam - not used */
+ /* effects: Returns a handle to the edit control's text. */
+ /*
+ * Null terminate the string. Note that we are guaranteed to have the
+ * memory for the NULL since ECInsertText allocates an extra
+ * byte for the NULL terminator.
+ */
+ /**(LocalLock(ped->hText)+ped->cch) = 0;*/
+ /*LocalUnlock(ped->hText);*/
+ *(LMHtoP(ped->hText)+ped->cch) = 0;
+ return((LONG)ped->hText);
+ break;
+
+ case EM_GETLINE:
+ /* wParam - line number to copy (0 is first line)
+ lParam - buffer to copy text to. First word is max # of bytes to
+ copy */
+ return(MLGetLineHandler(ped, wParam,
+ *(WORD FAR *)lParam, (LPSTR)lParam));
+ break;
+
+ case EM_LINEFROMCHAR:
+ /* wParam - Contains the index value for the desired char in the text
+ of the edit control. These are 0 based.
+ lParam - not used */
+ return((LONG)MLIchToLineHandler(ped, wParam));
+ break;
+
+ case EM_LINEINDEX:
+ /* wParam - specifies the desired line number where the number of the
+ first line is 0. If linenumber = 0, the line with the caret is used.
+ lParam - not used.
+ This function returns the number of character positions that occur
+ preceeding the first char in a given line. */
+ return((LONG)MLLineIndexHandler(ped, wParam));
+ break;
+
+ case EM_LINELENGTH:
+ /* wParam - specifies the character index of a character in the
+ specified line, where the first line is 0. If -1, the length
+ of the current line (with the caret) is returned not including the
+ length of any selected text.
+ lParam - not used */
+ return((LONG)MLLineLengthHandler(ped, wParam));
+ break;
+
+ case EM_LINESCROLL:
+ /* wParam - not used
+ lParam - Contains the number of lines and char positions to scroll */
+ MLScrollHandler(ped, WM_VSCROLL, EM_LINESCROLL, LOWORD(lParam));
+ MLScrollHandler(ped, WM_HSCROLL, EM_LINESCROLL, HIWORD(lParam));
+ break;
+
+ case EM_REPLACESEL:
+ /* wParam - not used
+ lParam - Points to a null terminated replacement text. */
+ SwapHandle(&lParam);
+ ECEmptyUndo(ped);
+ MLDeleteText(ped);
+ ECEmptyUndo(ped);
+ SwapHandle(&lParam);
+ MLInsertText(ped, (LPSTR)lParam, lstrlen((LPSTR)lParam), FALSE);
+ ECEmptyUndo(ped);
+ break;
+
+ case EM_SCROLL:
+ /* Scroll the window vertically */
+ /* wParam - contains the command type
+ lParam - not used. */
+ return(MLScrollHandler(ped, WM_VSCROLL, wParam, (int)lParam));
+ break;
+
+ case EM_SETHANDLE:
+ /* wParam - contains a handle to the text buffer
+ lParam - not used */
+ MLSetHandleHandler(ped, (HANDLE)wParam);
+ break;
+
+ case EM_SETRECT:
+ /* wParam - not used
+ lParam - Points to a RECT which specifies the new dimensions of the
+ rectangle. */
+ MLSetRectHandler(ped, (LPRECT)lParam);
+ /* Do a repaint of the whole client area since the app may have shrunk
+ * the rectangle for the text and we want to be able to erase the old
+ * text.
+ */
+ InvalidateRect(hwnd, (LPRECT)NULL, TRUE);
+ UpdateWindow(hwnd);
+ break;
+
+ case EM_SETRECTNP:
+ /* wParam - not used
+ lParam - Points to a RECT which specifies the new dimensions of the
+ rectangle.
+ */
+ /* We don't do a repaint here. */
+ MLSetRectHandler(ped, (LPRECT)lParam);
+ break;
+
+ case EM_SETSEL:
+ /* wParam - not used
+ lParam - starting pos in lowword ending pos in high word */
+ MLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case WM_UNDO:
+ case EM_UNDO:
+ return(MLUndoHandler(ped));
+ break;
+
+ case EM_SETTABSTOPS:
+ /* This sets the tab stop positions for multiline edit controls.
+ * wParam - Number of tab stops
+ * lParam - Far ptr to a WORD array containing the Tab stop positions
+ */
+ return(MLSetTabStops(ped, (int)wParam, (LPINT)lParam));
+ break;
+
+ default:
+ return(DefWindowProc(hwnd,message,wParam,lParam));
+ break;
+ }
+
+ return(1L);
+} /* MLEditWndProc */
+
+
+
+void NEAR PASCAL MLDrawText(register PED ped,
+ HDC hdc,
+ ICH ichStart,
+ ICH ichEnd)
+/* effects: draws the characters between ichstart and ichend.
+ */
+{
+ DWORD textColorSave;
+ DWORD bkColorSave;
+ LONG xyPos;
+ LONG xyNonLeftJustifiedStart;
+ HBRUSH hBrush;
+ ICH ich;
+ PSTR pText;
+ int line;
+ ICH length;
+ ICH length2;
+ int xOffset;
+ DWORD ext;
+ RECT rc;
+ BOOL fPartialLine = FALSE;
+ BOOL fSelected = FALSE;
+ BOOL fLeftJustified = TRUE;
+#ifdef WOW
+ HWND hwndSend;
+#endif
+
+ if (ped->fNoRedraw || !ped->ichLinesOnScreen)
+ /* Just return if nothing to draw */
+ return;
+
+ /* Set initial state of dc */
+#ifndef WOW
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+#else
+ if (!(hwndSend = GetParent(ped->hwnd)))
+ hwndSend = ped->hwnd;
+ SendMessage(hwndSend, WM_CTLCOLOR, (WORD)hdc, MAKELONG(ped->hwnd, CTLCOLOR_EDIT));
+#endif
+
+ if ((WORD)ichStart < (WORD)ped->chLines[ped->screenStart])
+ {
+ ichStart = ped->chLines[ped->screenStart];
+ if (ichStart > ichEnd)
+ return;
+ }
+
+ line = min(ped->screenStart+ped->ichLinesOnScreen,ped->cLines-1);
+ ichEnd = umin(ichEnd, ped->chLines[line]+MLLineLength(ped, line));
+
+ line = MLIchToLineHandler(ped, ichStart);
+ if (ped->format != ES_LEFT)
+ {
+ ichStart = ped->chLines[line];
+ fLeftJustified = FALSE;
+ }
+
+ pText = LocalLock(ped->hText);
+
+ HideCaret(ped->hwnd);
+
+ while (ichStart <= ichEnd)
+ {
+StillWithSameLine:
+ length2 = MLLineLength(ped, line);
+ if (length2 < (ichStart - ped->chLines[line]))
+ {
+ goto NextLine;
+ }
+
+ length = length2 - (ichStart - ped->chLines[line]);
+
+ xyPos = MLIchToXYPos(ped, hdc, ichStart, FALSE);
+
+ if (!fLeftJustified && ichStart == ped->chLines[line])
+ xyNonLeftJustifiedStart = xyPos;
+
+ /* Find out how many pixels we indent the line for funny formats */
+ if (ped->format != ES_LEFT)
+ xOffset = MLCalcXOffset(ped, hdc, line);
+ else
+ xOffset = -ped->xOffset;
+
+ if (!(ped->ichMinSel == ped->ichMaxSel ||
+ ichStart >= ped->ichMaxSel ||
+ ichEnd < ped->ichMinSel ||
+ (!ped->fNoHideSel && !ped->fFocus)))
+ {
+ if (ichStart < ped->ichMinSel)
+ {
+ fSelected = FALSE;
+ length2 = umin(ichStart+length, ped->ichMinSel)-ichStart;
+ }
+ else
+ {
+ fSelected = TRUE;
+ length2 = umin(ichStart+length, ped->ichMaxSel)-ichStart;
+ /* Select in the highlight colors */
+ bkColorSave = SetBkColor(hdc, ped->rgbHiliteBk);
+ textColorSave = SetTextColor(hdc, ped->rgbHiliteText);
+ }
+ fPartialLine = (length != length2);
+ length = length2;
+ }
+
+ ext = ECTabTheTextOut(hdc, LOWORD(xyPos), HIWORD(xyPos),
+ (LPSTR)(pText+ichStart), length,
+ ped,/*iLeft+xOffset*/ped->rcFmt.left+xOffset, TRUE);
+
+ if (fSelected)
+ {
+ fSelected = FALSE;
+ SetBkColor(hdc, bkColorSave);
+ SetTextColor(hdc, textColorSave);
+ }
+
+ if (fPartialLine)
+ {
+ fPartialLine = FALSE;
+ ichStart += length;
+ goto StillWithSameLine;
+ }
+
+ /* Fill to end of line so use a very large width for this rectangle.
+ */
+ SetRect((LPRECT)&rc,
+ LOWORD(xyPos)+LOWORD(ext), HIWORD(xyPos),
+ 32764,
+ HIWORD(xyPos)+ped->lineHeight);
+ ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, (LPRECT)&rc, "",0,0L);
+ if (!fLeftJustified)
+ {
+ SetRect((LPRECT)&rc,
+ ped->rcFmt.left,
+ HIWORD(xyNonLeftJustifiedStart),
+ LOWORD(xyNonLeftJustifiedStart),
+ HIWORD(xyNonLeftJustifiedStart)+ped->lineHeight);
+ ExtTextOut(hdc, rc.left, rc.top,
+ ETO_OPAQUE, (LPRECT)&rc, "",0,0L);
+ }
+
+NextLine:
+ line++;
+ if (ped->cLines > line)
+ {
+ ichStart = ped->chLines[line];
+ }
+ else
+ ichStart = ichEnd+1;
+ }
+
+ LocalUnlock(ped->hText);
+ ShowCaret(ped->hwnd);
+ MLSetCaretPosition(ped,hdc);
+}
diff --git a/private/mvdm/wow16/user/editsl.c b/private/mvdm/wow16/user/editsl.c
new file mode 100644
index 000000000..285f322ad
--- /dev/null
+++ b/private/mvdm/wow16/user/editsl.c
@@ -0,0 +1,1785 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDITSL.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* editsl.c - Edit controls rewrite. Version II of edit controls. */
+/* */
+/* */
+/* Created: 24-Jul-88 davidds */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Single Line Support Routines */
+/****************************************************************************/
+
+void FAR PASCAL SLSetCaretPosition(ped,hdc)
+register PED ped;
+HDC hdc;
+/* effects: If the window has the focus, find where the caret belongs and move
+ * it there.
+ */
+{
+ int xPosition;
+ /* We will only position the caret if we have the focus since we don't want
+ * to move the caret while another window could own it.
+ */
+ if (ped->fNoRedraw || !ped->fFocus)
+ return;
+
+ xPosition = SLIchToLeftXPos(ped, hdc, ped->ichCaret);
+ if (!ped->fAutoHScroll)
+ /* Don't leet caret go out of bounds of edit contol if there is too much
+ * text in a non scrolling edit control.
+ */
+ xPosition = min(xPosition, ped->rcFmt.right-1);
+
+ SetCaretPos(xPosition, ped->rcFmt.top);
+}
+
+
+int NEAR PASCAL SLIchToLeftXPos(ped, hdc, ich)
+register PED ped;
+HDC hdc;
+ICH ich;
+/* effects: Given a character index, find its (left side) x coordinate within
+ * the ped->rcFmt rectangle assuming the character ped->screenStart is at
+ * coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
+ * returned if the character ich is to the left of ped->screenStart. WARNING:
+ * ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
+ * There may be 64K total characters in the editcontrol, but we can only
+ * display 1000 without scrolling. This shouldn't be a problem obviously.
+ */
+{
+ int textExtent;
+ register PSTR pText;
+
+ /* Check if we are adding lots and lots of chars. A paste for example could
+ * cause this and GetTextExtents could overflow on this.
+ */
+ if (ich > ped->screenStart && ich - ped->screenStart > 1000)
+ return(30000);
+ if (ped->screenStart > ich && ped->screenStart - ich > 1000)
+ return(-30000);
+
+ if (ped->fNonPropFont)
+ return((ich-ped->screenStart)*ped->aveCharWidth + ped->rcFmt.left);
+
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ return((ich-ped->screenStart)*ped->cPasswordCharWidth+ped->rcFmt.left);
+
+ pText = LocalLock(ped->hText);
+
+ if (ped->screenStart <= ich)
+ {
+ textExtent = LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart),
+ ich-ped->screenStart));
+ /* In case of signed/unsigned overflow since the text extent may be
+ * greater than maxint. This happens with long single line edit
+ * controls. The rect we edit text in will never be greater than 30000
+ * pixels so we are ok if we just ignore them.
+ */
+ if (textExtent < 0 || textExtent > 31000)
+ textExtent = 30000;
+ }
+ else
+ textExtent = (-1) *
+ (int)LOWORD(GetTextExtent(hdc,(LPSTR)(pText + ich),
+ ped->screenStart-ich));
+
+ LocalUnlock(ped->hText);
+
+ return(textExtent-ped->charOverhang + ped->rcFmt.left);
+}
+
+/* effects: This finds out if the given ichPos falls within the current
+ * Selection range and if so returns TRUE; Else returns FALSE.
+ */
+BOOL NEAR PASCAL SLGetHiliteAttr(PED ped, ICH ichPos)
+{
+ return((ichPos >= ped->ichMinSel) && (ichPos < ped->ichMaxSel));
+}
+
+/* effects: This takes care of erasing the old selection and drawing the new
+ * selection
+ */
+void NEAR PASCAL SLRepaintChangedSelection(
+ PED ped, HDC hdc,
+ ICH ichOldMinSel, ICH ichOldMaxSel)
+{
+ BLOCK Blk[2];
+ int i;
+
+ Blk[0].StPos = ichOldMinSel;
+ Blk[0].EndPos = ichOldMaxSel;
+ Blk[1].StPos = ped->ichMinSel;
+ Blk[1].EndPos = ped->ichMaxSel;
+
+ if(ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
+ (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
+ {
+ UpdateWindow(ped->hwnd);
+ /* Paint the rectangles where selection has changed */
+ /* Paint both Blk[0] and Blk[1], if they exist */
+ for(i = 0; i < 2; i++)
+ {
+ if (Blk[i].StPos != -1)
+ SLDrawLine(ped, hdc, Blk[i].StPos, Blk[i].EndPos - Blk[i].StPos,
+ SLGetHiliteAttr(ped, Blk[i].StPos));
+ }
+ }
+}
+
+
+void FAR PASCAL SLChangeSelection(ped, hdc, ichNewMinSel, ichNewMaxSel)
+register PED ped;
+HDC hdc;
+ICH ichNewMinSel;
+ICH ichNewMaxSel;
+/* effects: Changes the current selection to have the specified starting and
+ * ending values. Properly highlights the new selection and unhighlights
+ * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
+ * them. Doesn't update the caret position.
+ */
+{
+ ICH temp;
+ ICH ichOldMinSel;
+ ICH ichOldMaxSel;
+
+ if (ichNewMinSel > ichNewMaxSel)
+ {
+ temp = ichNewMinSel;
+ ichNewMinSel = ichNewMaxSel;
+ ichNewMaxSel = temp;
+ }
+ ichNewMinSel = umin(ichNewMinSel, ped->cch);
+ ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
+
+ /* Preserve the Old selection */
+ ichOldMinSel = ped->ichMinSel;
+ ichOldMaxSel = ped->ichMaxSel;
+
+ /* Set new selection */
+ ped->ichMinSel = ichNewMinSel;
+ ped->ichMaxSel = ichNewMaxSel;
+
+ /* We will find the intersection of current selection rectangle with the new
+ * selection rectangle. We will then invert the parts of the two rectangles
+ * not in the intersection.
+ */
+
+ if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
+ {
+ if (ped->fFocus)
+ HideCaret(ped->hwnd);
+ SLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
+ SLSetCaretPosition(ped,hdc);
+ if (ped->fFocus)
+ ShowCaret(ped->hwnd);
+ }
+}
+
+
+void NEAR PASCAL SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus)
+
+register PED ped;
+register HDC hdc;
+ICH ichStart;
+int iCount;
+BOOL fSelStatus;
+
+/* This draws the line starting from ichStart, iCount number of characters;
+ * fSelStatus is TRUE, if it is to be drawn with the "selection" attribute.
+ */
+{
+ RECT rc;
+ HBRUSH hBrush;
+ PSTR pText;
+ DWORD rgbSaveBk;
+ DWORD rgbSaveText;
+ int iStCount;
+ DWORD rgbGray=0;
+
+ if (ped->fNoRedraw)
+ return;
+
+ if (ichStart < ped->screenStart)
+ {
+ if (ichStart+iCount < ped->screenStart)
+ return;
+
+ iCount = iCount - (ped->screenStart-ichStart);
+ ichStart = ped->screenStart;
+ }
+
+ CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
+
+ /* Set the proper clipping rectangle */
+ ECSetEditClip(ped, hdc);
+
+ pText = (PSTR) LocalLock(ped->hText);
+
+ /* Calculates the rectangle area to be wiped out */
+ if (iStCount = ichStart - ped->screenStart)
+ {
+ if (ped->charPasswordChar)
+ rc.left += ped->cPasswordCharWidth * iStCount;
+ else
+ rc.left += LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart),
+ iStCount)) -
+ ped->charOverhang;
+ }
+
+ if (ped->charPasswordChar)
+ rc.right = rc.left + ped->cPasswordCharWidth * iCount;
+ else
+ rc.right = rc.left + LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ichStart),
+ iCount));
+ /* Set the background mode before calling GetControlBrush so that the app
+ * can change it to TRANSPARENT if it wants to.
+ */
+ SetBkMode(hdc, OPAQUE);
+
+ if (fSelStatus)
+ {
+ hBrush = ped->hbrHiliteBk;
+ rgbSaveBk = SetBkColor(hdc, ped->rgbHiliteBk);
+ rgbSaveText = SetTextColor(hdc, ped->rgbHiliteText);
+ }
+ else
+ {
+ /* We always want to send this so that the app has a chance to muck with
+ * the DC
+ */
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+ }
+
+ if (ped->fDisabled &&
+ (rgbGray = GetSysColor(COLOR_GRAYTEXT)))
+ {
+ /* Grey the text in the edit control if disabled.
+ */
+ rgbSaveText = SetTextColor(hdc, rgbGray);
+ }
+
+ /* Erase the rectangular area before text is drawn. Note that we inflate the
+ * rect by 1 so that the selection color has a one pixel border around the
+ * text.
+ */
+ InflateRect((LPRECT)&rc, 0, 1);
+ /* Use paint rect so that the brush gets aligned if dithered.
+ */
+ PaintRect(ped->hwndParent, ped->hwnd, hdc, hBrush, (LPRECT)&rc);
+ InflateRect((LPRECT)&rc, 0, -1);
+
+ if (ped->charPasswordChar)
+ {
+ for (iStCount = 0; iStCount < iCount; iStCount++)
+ TextOut(hdc,
+ rc.left+iStCount*ped->cPasswordCharWidth,
+ rc.top,
+ (LPSTR)&ped->charPasswordChar,
+ 1);
+ }
+ else
+ TextOut(hdc,rc.left,rc.top,(LPSTR)(pText+ichStart),iCount);
+
+ if (fSelStatus || rgbGray)
+ {
+ SetTextColor(hdc, rgbSaveText);
+ if (fSelStatus)
+ SetBkColor(hdc, rgbSaveBk);
+
+ }
+
+ LocalUnlock(ped->hText);
+}
+
+int NEAR PASCAL SLGetBlkEnd(ped, ichStart, ichEnd, lpfStatus)
+register PED ped;
+register ICH ichStart;
+ICH ichEnd;
+BOOL FAR *lpfStatus;
+/* Given a Starting point and and end point, this function returns whether the
+ * first few characters fall inside or outside the selection block and if so,
+ * howmany characters?
+ */
+{
+ *lpfStatus = FALSE;
+ if (ichStart >= ped->ichMinSel)
+ {
+ if(ichStart >= ped->ichMaxSel)
+ return(ichEnd - ichStart);
+ *lpfStatus = TRUE;
+ return(min(ichEnd, ped->ichMaxSel) - ichStart);
+ }
+ return(min(ichEnd, ped->ichMinSel) - ichStart);
+}
+
+void NEAR PASCAL SLDrawText(ped, hdc, ichStart)
+register PED ped;
+register HDC hdc;
+ICH ichStart;
+/* effects: Draws text for a single line edit control in the rectangle
+ * specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
+ * side of the window starting at character index ped->screenStart and draws
+ * as much as will fit. If ichStart > 0, then it appends the characters
+ * starting at ichStart to the end of the text showing in the window. (ie. We
+ * are just growing the text length and keeping the left side
+ * (ped->screenStart to ichStart characters) the same. Assumes the hdc came
+ * from ECGetEditDC so that the caret and such are properly hidden.
+ */
+{
+ ICH cchToDraw;
+ RECT rc;
+
+ PSTR pText;
+ BOOL fSelStatus;
+ int iCount;
+ ICH ichEnd;
+ BOOL fNoSelection;
+
+ if (ped->fNoRedraw)
+ return;
+
+ if (ichStart == 0)
+ ichStart = ped->screenStart;
+
+ CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
+
+ /* Find out how many characters will fit on the screen so that we don't do
+ * any needless drawing.
+ */
+
+ pText = (PSTR) LocalLock(ped->hText);
+
+ cchToDraw = ECCchInWidth(ped, hdc,
+ (LPSTR)(pText+ped->screenStart),
+ ped->cch-ped->screenStart,
+ rc.right - rc.left);
+ ichEnd = ped->screenStart + cchToDraw;
+
+ /*
+ * There is no selection if,
+ * 1. MinSel and MaxSel are equal OR
+ * 2. (This has lost the focus AND Selection is to be hidden)
+ */
+ fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) ||
+ (!ped->fFocus && !ped->fNoHideSel));
+ while (ichStart < ichEnd)
+ {
+ if (fNoSelection)
+ {
+ fSelStatus = FALSE;
+ iCount = ichEnd - ichStart;
+ }
+ else
+ iCount = SLGetBlkEnd(ped, ichStart, ichEnd,
+ (BOOL FAR *)&fSelStatus);
+
+ SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus);
+ ichStart += iCount;
+ }
+
+ if (cchToDraw)
+ {
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ rc.left += ped->cPasswordCharWidth * cchToDraw;
+ else
+ rc.left += LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart), cchToDraw));
+ }
+
+ LocalUnlock(ped->hText);
+
+ /* Check if anything to be erased on the right hand side */
+ if (rc.left < rc.right)
+ {
+ SetBkMode(hdc, OPAQUE);
+ /* Erase the rectangular area before text is drawn. Note that we inflate
+ * the rect by 1 so that the selection color has a one pixel border
+ * around the text.
+ */
+ InflateRect((LPRECT)&rc, 0, 1);
+ PaintRect(ped->hwndParent, ped->hwnd, hdc, NULL, (LPRECT)&rc);
+ }
+
+ SLSetCaretPosition(ped, hdc);
+}
+
+
+BOOL FAR PASCAL SLScrollText(ped, hdc)
+register PED ped;
+HDC hdc;
+/* effects: Scrolls the text to bring the caret into view. If the text is
+ * scrolled, the current selection is unhighlighted. Returns TRUE if the text
+ * is scrolled else returns false.
+ */
+{
+ register PSTR pText;
+ ICH scrollAmount = (ped->rcFmt.right-ped->rcFmt.left)/4/ped->aveCharWidth+1;
+ ICH newScreenStartX = ped->screenStart;
+
+ if (!ped->fAutoHScroll)
+ return(FALSE);
+
+ /* Calculate the new starting screen position */
+ if (ped->ichCaret <= ped->screenStart)
+ {
+ /* Caret is to the left of the starting text on the screen we must
+ * scroll the text backwards to bring it into view. Watch out when
+ * subtracting unsigned numbers when we have the possibility of going
+ * negative.
+ */
+ if (ped->ichCaret > scrollAmount)
+ newScreenStartX = ped->ichCaret - scrollAmount;
+ else
+ newScreenStartX = 0;
+ }
+ else
+ {
+ pText = (PSTR) LocalLock(ped->hText);
+ if ((ped->ichCaret != ped->screenStart) &&
+ (ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
+ ped->ichCaret - ped->screenStart,
+ ped->rcFmt.right-ped->rcFmt.left) <
+ ped->ichCaret - ped->screenStart))
+ {
+ newScreenStartX = ((ped->ichCaret < scrollAmount*2) ? 0 :
+ ped->ichCaret - scrollAmount*2);
+ }
+ LocalUnlock(ped->hText);
+ }
+
+#ifdef DBCS
+ pText = (PSTR) LocalLock(ped->hText);
+ newScreenStartX = ECAdjustIch( ped,pText,newScreenStartX );
+ LocalUnlock(ped->hText);
+#endif
+
+ if (ped->screenStart != newScreenStartX)
+ {
+ ped->screenStart = newScreenStartX;
+ SLDrawText(ped, hdc, 0);
+ /* Caret pos is set by drawtext */
+ return(TRUE);
+ }
+
+ return(FALSE);
+
+}
+
+
+ICH FAR PASCAL SLInsertText(ped, lpText, cchInsert)
+register PED ped;
+LPSTR lpText;
+register ICH cchInsert;
+/* effects: Adds up to cchInsert characters from lpText to the ped starting at
+ * ichCaret. If the ped only allows a maximum number of characters, then we
+ * will only add that many characters to the ped and send a EN_MAXTEXT
+ * notification code to the parent of the ec. Also, if !fAutoHScroll, then we
+ * only allow as many chars as will fit in the client rectangle. The number of
+ * characters actually added is returned (could be 0). If we can't allocate
+ * the required space, we notify the parent with EN_ERRSPACE and no characters
+ * are added.
+ */
+{
+ HDC hdc;
+ PSTR pText;
+ ICH cchInsertCopy = cchInsert;
+ int textWidth;
+
+ /* First determine exactly how many characters from lpText we can insert
+ * into the ped.
+ */
+ if (!ped->fAutoHScroll)
+ {
+ pText = (PSTR)LocalLock(ped->hText);
+ hdc = ECGetEditDC(ped, TRUE);
+
+ /* If ped->fAutoHScroll bit is not set, then we only insert as many
+ * characters as will fit in the ped->rcFmt rectangle upto a maximum of
+ * ped->cchTextMax - ped->cch characters. Note that if password style is
+ * on, we allow the user to enter as many chars as the number of
+ * password chars which fit in the rect.
+ */
+ if (ped->cchTextMax <= ped->cch)
+ cchInsert = 0;
+ else
+ {
+ cchInsert = umin(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
+ if (ped->charPasswordChar)
+ textWidth = ped->cch * ped->cPasswordCharWidth;
+ else
+ textWidth = LOWORD(GetTextExtent(hdc, (LPSTR)pText, ped->cch));
+
+ cchInsert = umin(cchInsert,
+ ECCchInWidth(ped, hdc, lpText, cchInsert,
+ ped->rcFmt.right-ped->rcFmt.left-
+ textWidth));
+ }
+
+ LocalUnlock(ped->hText);
+ ECReleaseEditDC(ped, hdc, TRUE);
+ }
+ else
+ {
+ if (ped->cchTextMax <= ped->cch)
+ cchInsert = 0;
+ else
+ cchInsert = umin((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
+ }
+
+ /* Now try actually adding the text to the ped */
+ if (cchInsert && !ECInsertText(ped, lpText, cchInsert))
+ {
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return(0);
+ }
+
+ if (cchInsert)
+ ped->fDirty = TRUE; /* Set modify flag */
+
+ if (cchInsert < cchInsertCopy)
+ /* Notify parent that we couldn't insert all the text requested */
+ ECNotifyParent(ped, EN_MAXTEXT);
+
+ /* Update selection extents and the caret position. Note that ECInsertText
+ * updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
+ * the inserted text.
+ */
+
+ return(cchInsert);
+}
+
+
+ICH PASCAL NEAR SLPasteText(register PED ped)
+/* effects: Pastes a line of text from the clipboard into the edit control
+ * starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
+ * the end of the inserted text. Notifies the parent if space cannot be
+ * allocated. Returns how many characters were inserted.
+ */
+{
+ HANDLE hData;
+ LPSTR lpchClip;
+ LPSTR lpchClip2;
+ register ICH cchAdded;
+ ICH clipLength;
+
+ if (!OpenClipboard(ped->hwnd))
+ return(0);
+
+ if (!(hData = GetClipboardData(CF_TEXT)))
+ {
+ CloseClipboard();
+ return(0);
+ }
+
+ lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
+
+ /* Find the first carrage return or line feed. Just add text to that point.
+ */
+ clipLength = (WORD)lstrlen(lpchClip);
+ for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
+ if (*lpchClip2++ == 0x0D)
+ break;
+
+ /* Insert the text (SLInsertText checks line length) */
+ cchAdded = SLInsertText(ped, lpchClip, cchAdded);
+
+ GlobalUnlock(hData);
+ CloseClipboard();
+
+ return(cchAdded);
+}
+
+
+void NEAR PASCAL SLReplaceSelHandler(register PED ped,
+ LPSTR lpText)
+/* effects: Replaces the text in the current selection with the given text.
+ */
+{
+ BOOL fUpdate;
+ HDC hdc;
+
+ SwapHandle(&lpText);
+ ECEmptyUndo(ped);
+ fUpdate = (BOOL)ECDeleteText(ped);
+ ECEmptyUndo(ped);
+ SwapHandle(&lpText);
+ fUpdate = (BOOL)SLInsertText(ped, lpText, lstrlen(lpText)) || fUpdate;
+ ECEmptyUndo(ped);
+
+ if (fUpdate)
+ {
+ ECNotifyParent(ped, EN_UPDATE);
+ hdc = ECGetEditDC(ped,FALSE);
+ if (!SLScrollText(ped,hdc))
+ SLDrawText(ped,hdc,0);
+ ECReleaseEditDC(ped,hdc,FALSE);
+ ECNotifyParent(ped,EN_CHANGE);
+ }
+}
+
+
+
+void FAR PASCAL SLCharHandler(ped, keyValue, keyMods)
+register PED ped;
+WORD keyValue;
+int keyMods;
+/* effects: Handles character input (really, no foolin')
+ */
+{
+ register HDC hdc;
+ unsigned char keyPress = LOBYTE(keyValue);
+ BOOL updateText = FALSE;
+#ifdef DBCS
+ PSTR pText;
+ int InsertTextLen = 0;
+ WORD DBCSkey;
+#endif
+
+ if (ped->fMouseDown || ped->fReadOnly)
+ /* Don't do anything if we are in the middle of a mousedown deal or if
+ * this is a read only edit control.
+ */
+ return;
+
+ if ((keyPress == BACKSPACE) || (keyPress >= ' '))
+ {
+ /* Delete the selected text if any */
+ if (ECDeleteText(ped))
+ updateText=TRUE;
+ }
+
+ switch(keyPress)
+ {
+ case BACKSPACE:
+ /* Delete any selected text or delete character left if no sel */
+ if (!updateText && ped->ichMinSel)
+ {
+ /* There was no selection to delete so we just delete character
+ left if available */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped,pText, pText+ped->ichMinSel) == pText+ped->ichMinSel-2)
+ ped->ichMinSel--;
+#endif
+ ped->ichMinSel--;
+ (void) ECDeleteText(ped);
+ updateText = TRUE;
+ }
+ break;
+
+ default:
+ if (keyPress >= ' ')
+ {
+#ifdef DBCS
+ InsertTextLen = 1;
+ if( IsDBCSLeadByte( keyPress ) )
+ if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
+ if( SLInsertText( ped, (LPSTR)&DBCSkey, 2 ) == 2){
+ InsertTextLen = 2;
+ updateText = TRUE;
+ }else
+ MessageBeep(0);
+ else
+ MessageBeep(0);
+ else
+#endif
+ if (SLInsertText(ped, (LPSTR) &keyPress, 1))
+ updateText = TRUE;
+ else
+ /* Beep. Since we couldn't add the text */
+ MessageBeep(0);
+ }
+ else
+ /* User hit an illegal control key */
+ MessageBeep(0);
+
+ break;
+ }
+
+
+ if (updateText)
+ {
+ /* Dirty flag (ped->fDirty) was set when we inserted text */
+ ECNotifyParent(ped, EN_UPDATE);
+ hdc = ECGetEditDC(ped,FALSE);
+ if (!SLScrollText(ped,hdc))
+#ifdef DBCS
+ SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - InsertTextLen));
+#else
+ SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - 1));
+#endif
+ ECReleaseEditDC(ped,hdc,FALSE);
+ ECNotifyParent(ped,EN_CHANGE);
+ }
+
+}
+
+
+
+void NEAR PASCAL SLKeyDownHandler(register PED ped,
+ WORD virtKeyCode,
+ int keyMods)
+/* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
+ * us to make SLKeyDownHandler calls and specify if the modifier keys (shift
+ * and control) are up or down. This is useful for imnplementing the
+ * cut/paste/clear messages for single line edit controls. If keyMods == 0,
+ * we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
+ * bits in keyMods define the state of the shift and control keys.
+ */
+{
+ HDC hdc;
+
+
+ /* Variables we will use for redrawing the updated text */
+ register ICH newMaxSel = ped->ichMaxSel;
+ ICH newMinSel = ped->ichMinSel;
+
+ /* Flags for drawing the updated text */
+ BOOL updateText = FALSE;
+ BOOL changeSelection = FALSE; /* new selection is specified by
+ newMinSel, newMaxSel */
+
+ /* Comparisons we do often */
+ BOOL MinEqMax = (newMaxSel == newMinSel);
+ BOOL MinEqCar = (ped->ichCaret == newMinSel);
+ BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
+
+ /* State of shift and control keys. */
+ int scState = 0;
+
+ /* Combo box support */
+ BOOL fIsListVisible;
+ BOOL fIsExtendedUI;
+
+#ifdef DBCS
+ PSTR pText;
+#endif
+
+ if (ped->fMouseDown)
+ {
+ /* If we are in the middle of a mouse down handler, then don't do
+ * anything. ie. ignore keyboard input.
+ */
+ return;
+ }
+
+ if (!keyMods)
+ {
+ /* Get state of modifier keys for use later. */
+ scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
+ scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
+ }
+ else
+ scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
+
+
+
+ switch(virtKeyCode)
+ {
+ case VK_UP:
+ if (ped->listboxHwnd)
+ {
+ /* Handle Combobox support */
+ fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
+ fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
+
+ if (!fIsListVisible && fIsExtendedUI)
+ {
+ /* For TandyT
+ */
+DropExtendedUIListBox:
+ /* Since an extendedui combo box doesn't do anything on f4, we
+ * turn off the extended ui, send the f4 to drop, and turn it
+ * back on again.
+ */
+ SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0L);
+ SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L);
+ SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0L);
+ return;
+ }
+ else
+ goto SendKeyToListBox;
+ }
+
+ /* else fall through */
+
+ case VK_LEFT:
+ /* If the caret isn't already at 0, we can move left */
+ if (ped->ichCaret)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret left */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
+ pText + ped->ichCaret - 2 )
+ ped->ichCaret--;
+#endif
+ ped->ichCaret--;
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret left */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
+ pText + ped->ichCaret - 2 )
+ ped->ichCaret--;
+#endif
+ ped->ichCaret--;
+ if (MaxEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMaxSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ /*
+ * Hint: Suppose WORD. OR is selected. Cursor between R
+ * and D. Hit select word left, we want to just select the
+ * W and leave cursor before the W.
+ */
+ newMinSel = ped->ichMinSel;
+ newMaxSel = ped->ichCaret;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move left and we are at the 0th character
+ and there is a selection, then cancel the selection. */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ changeSelection = TRUE;
+ newMaxSel = newMinSel = ped->ichCaret;
+ }
+ }
+ break;
+
+ case VK_DOWN:
+ if (ped->listboxHwnd)
+ {
+ /* Handle Combobox support */
+ fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
+ fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
+
+ if (!fIsListVisible && fIsExtendedUI)
+ {
+ /* For TandyT
+ */
+ goto DropExtendedUIListBox;
+ }
+ else
+ goto SendKeyToListBox;
+ }
+
+ /* else fall through */
+
+ case VK_RIGHT:
+ /*
+ * If the caret isn't already at ped->cch, we can move right.
+ */
+ if (ped->ichCaret < ped->cch)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret right */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret right */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ if (MinEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ if (MinEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move right and we are at the last character
+ and there is a selection, then cancel the selection. */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ newMaxSel = newMinSel = ped->ichCaret;
+ changeSelection = TRUE;
+ }
+ }
+ break;
+
+ case VK_HOME:
+ ped->ichCaret = 0;
+ switch (scState)
+ {
+ case NONEDOWN:
+ case CTRLDOWN:
+ /* Clear selection, move caret home */
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ case SHCTDOWN:
+ /* Extend selection, move caret home */
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce/negate selection extent */
+ newMinSel = 0;
+ newMaxSel = ped->ichMinSel;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_END:
+ newMaxSel = ped->ichCaret = ped->cch;
+ switch (scState)
+ {
+ case NONEDOWN:
+ case CTRLDOWN:
+ /* Clear selection, move caret to end of text */
+ newMinSel = ped->cch;
+ break;
+
+ case SHFTDOWN:
+ case SHCTDOWN:
+ /* Extend selection, move caret to end of text */
+ if (MinEqCar && !MinEqMax)
+ /* Reduce/negate selection extent */
+ newMinSel = ped->ichMaxSel;
+ /* else Extend selection extent */
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_DELETE:
+ if (ped->fReadOnly)
+ break;
+
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection. If no selection, delete (clear) character
+ * right.
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ /* Move cursor forwards and simulate a backspace.
+ */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+
+ case SHFTDOWN:
+ /* CUT selection ie. remove and copy to clipboard, or if no
+ * selection, delete (clear) character left.
+ */
+
+ if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
+ (ped->ichMinSel == ped->ichMaxSel))
+ /* If copy successful, delete the copied text by simulating a
+ * backspace message which will redraw the text and take care
+ * of notifying the parent of changes. Or if there is no
+ * selection, just delete char left.
+ */
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+
+ case CTRLDOWN:
+ /* Delete to end of line if no selection else delete (clear)
+ * selection.
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ /* Move cursor to end of line and simulate a backspace.
+ */
+ ped->ichMaxSel = ped->ichCaret = ped->cch;
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+ }
+
+ /* No need to update text or selection since BACKSPACE message does it
+ * for us.
+ */
+ break;
+
+ case VK_INSERT:
+ switch (scState)
+ {
+ case CTRLDOWN:
+ /* Copy current selection to clipboard */
+ SendMessage(ped->hwnd, WM_COPY, (WORD)NULL, (LONG)NULL);
+ break;
+
+ case SHFTDOWN:
+ if (ped->fReadOnly)
+ break;
+
+ /* Insert contents of clipboard (PASTE) */
+ /* Unhighlight current selection and delete it, if any */
+ ECDeleteText(ped);
+ SLPasteText(ped);
+ updateText = TRUE;
+ ECNotifyParent(ped, EN_UPDATE);
+ break;
+ }
+ break;
+
+ case VK_F4:
+ case VK_PRIOR:
+ case VK_NEXT:
+ /* Send keys to the listbox if we are a part of a combo box. This
+ * assumes the listbox ignores keyup messages which is correct right
+ * now.
+ */
+ if (ped->listboxHwnd)
+ {
+SendKeyToListBox:
+ /* Handle Combobox support */
+ SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
+ return;
+ }
+ }
+
+
+
+ if (changeSelection || updateText)
+ {
+ hdc = ECGetEditDC(ped,FALSE);
+ /* Scroll if needed */
+ SLScrollText(ped,hdc);
+
+ if (changeSelection)
+ SLChangeSelection(ped,hdc,newMinSel,newMaxSel);
+ if (updateText)
+ SLDrawText(ped,hdc,0);
+
+ /* SLSetCaretPosition(ped,hdc);*/
+ ECReleaseEditDC(ped,hdc,FALSE);
+ if (updateText)
+ ECNotifyParent(ped, EN_CHANGE);
+ }
+
+}
+
+
+ICH NEAR PASCAL SLMouseToIch(ped, hdc, mousePt)
+register PED ped;
+HDC hdc;
+POINT mousePt;
+/* effects: Returns the closest cch to where the mouse point is.
+ */
+{
+ register PSTR pText;
+ int width = mousePt.x;
+ int textWidth;
+ ICH cch;
+
+ if (width <= ped->rcFmt.left)
+ {
+ /* Return either the first non visible character or return 0 if at
+ * beginning of text
+ */
+ if (ped->screenStart)
+ return(ped->screenStart - 1);
+ else
+ return(0);
+ }
+
+ if (width > ped->rcFmt.right)
+ {
+ pText = LocalLock(ped->hText);
+
+ /* Return last char in text or one plus the last char visible */
+ cch = ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
+ ped->cch - ped->screenStart,
+ ped->rcFmt.right-ped->rcFmt.left) +
+ ped->screenStart;
+ LocalUnlock(ped->hText);
+ if (cch >= ped->cch)
+ return(ped->cch);
+ else
+ return(cch+1);
+ }
+
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ return(umin((width-ped->rcFmt.left)/ped->cPasswordCharWidth,ped->cch));
+
+ if (!ped->cch)
+ return(0);
+
+ pText = LocalLock(ped->hText);
+ cch = ped->cch;
+
+ while(((textWidth =
+ LOWORD(GetTextExtent(hdc, (LPSTR)(pText+ped->screenStart),
+ cch-ped->screenStart)))
+ > (width-ped->rcFmt.left)) && (cch-ped->screenStart) )
+ {
+ /* For that "feel" */
+ if ((textWidth - ped->aveCharWidth/2) < (width-ped->rcFmt.left))
+ break;
+
+ cch--;
+ }
+
+#ifdef DBCS
+ cch = ECAdjustIch( ped, pText, cch );
+#endif
+
+ LocalUnlock(ped->hText);
+ return(cch);
+}
+
+
+
+
+void NEAR PASCAL SLMouseMotionHandler(ped, message, virtKeyDown, mousePt)
+register PED ped;
+WORD message;
+WORD virtKeyDown;
+POINT mousePt;
+{
+ LONG selection;
+ BOOL changeSelection = FALSE;
+
+ HDC hdc = ECGetEditDC(ped,FALSE);
+
+ ICH newMaxSel = ped->ichMaxSel;
+ ICH newMinSel = ped->ichMinSel;
+
+ ICH mouseIch = SLMouseToIch(ped, hdc, mousePt);
+
+#ifdef DBCS
+ LPSTR pText;
+
+ pText = LocalLock( ped->hText );
+ mouseIch = ECAdjustIch( ped, pText, mouseIch );
+ LocalUnlock( ped->hText );
+#endif
+
+ switch (message)
+ {
+ case WM_LBUTTONDBLCLK:
+ /* Note that we don't have to worry about this control having the focus
+ * since it got it when the WM_LBUTTONDOWN message was first sent. If
+ * shift key is down, extend selection to word we double clicked on else
+ * clear current selection and select word.
+ */
+#ifdef DBCS
+ pText = LocalLock( ped->hText ) + ped->ichCaret;
+ selection = ECWord(ped,ped->ichCaret,
+ (ECIsDBCSLeadByte(ped,*pText) && ped->ichCaret < ped->cch) ? FALSE : TRUE );
+ LocalUnlock( ped->hText );
+#else
+ selection = ECWord(ped,ped->ichCaret,TRUE);
+#endif
+ newMinSel = LOWORD(selection);
+ newMaxSel = ped->ichCaret = HIWORD(selection);
+ changeSelection = TRUE;
+ /* Set mouse down to false so that the caret isn't reposition on the
+ * mouseup message or on an accidental move...
+ */
+ ped->fMouseDown = FALSE;
+ break;
+
+ case WM_MOUSEMOVE:
+ if (ped->fMouseDown)
+ {
+ changeSelection = TRUE;
+ /* Extend selection, move caret word right */
+ if ((ped->ichMinSel == ped->ichCaret) &&
+ (ped->ichMinSel != ped->ichMaxSel))
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret = mouseIch;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret=mouseIch;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ /*
+ * If we currently don't have the focus yet, try to get it.
+ */
+ if (!ped->fFocus)
+ {
+ if (!ped->fNoHideSel)
+ /* Clear the selection before setting the focus so that we don't
+ * get refresh problems and flicker. Doesn't matter since the
+ * mouse down will end up changing it anyway.
+ */
+ ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
+
+ SetFocus(ped->hwnd);
+ /* If we are part of a combo box, then this is the first time the
+ * edit control is getting the focus so we just want to highlight
+ * the selection and we don't really want to position the caret.
+ */
+ if (ped->listboxHwnd)
+ break;
+ }
+
+ if (ped->fFocus)
+ {
+ /* Only do this if we have the focus since a clever app may not want
+ * to give us the focus at the SetFocus call above.
+ */
+ ped->fMouseDown = TRUE;
+ SetCapture(ped->hwnd);
+ changeSelection = TRUE;
+ if (!(virtKeyDown & MK_SHIFT))
+ {
+ /*
+ * If shift key isn't down, move caret to mouse point and clear
+ * old selection
+ */
+ newMinSel = newMaxSel = ped->ichCaret = mouseIch;
+ }
+ else
+ {
+ /* Shiftkey is down so we want to maintain the current selection
+ * (if any) and just extend or reduce it
+ */
+ if (ped->ichMinSel == ped->ichCaret)
+ newMinSel = ped->ichCaret = mouseIch;
+ else
+ newMaxSel = ped->ichCaret = mouseIch;
+ }
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (ped->fMouseDown)
+ {
+ ReleaseCapture();
+ /*SLSetCaretPosition(ped,hdc);*/
+ ped->fMouseDown = FALSE;
+ }
+ break;
+ }
+
+
+ if (changeSelection)
+ {
+ SLScrollText(ped,hdc);
+ SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
+ }
+
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+}
+
+
+
+
+void NEAR PASCAL SLPaintHandler(ped,althdc)
+register PED ped;
+HDC althdc;
+/* effects: Handles painting of the edit control window. Draws the border if
+ * necessary and draws the text in its current state.
+ */
+{
+ HWND hwnd = ped->hwnd;
+ HBRUSH hBrush;
+ register HDC hdc;
+ PAINTSTRUCT paintstruct;
+ RECT rcEdit;
+ HANDLE hOldFont;
+
+ /* Had to put in hide/show carets. The first one needs to be done before
+ * beginpaint to correctly paint the caret if part is in the update region
+ * and part is out. The second is for 1.03 compatibility. It breaks
+ * micrografix's worksheet edit control if not there.
+ */
+
+ HideCaret(hwnd);
+
+ /* Allow subclassing hdc */
+ if (!althdc)
+ hdc = BeginPaint(hwnd, (PAINTSTRUCT FAR *)&paintstruct);
+ else
+ hdc = althdc;
+
+ HideCaret(hwnd);
+
+ if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
+ {
+ /* Erase the background since we don't do it in the erasebkgnd message.
+ */
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+ FillWindow(ped->hwndParent, hwnd, hdc, hBrush);
+
+ if (ped->fBorder)
+ {
+ GetClientRect(hwnd, (LPRECT)&rcEdit);
+ DrawFrame(hdc, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
+ }
+
+ if (ped->hFont)
+ /* We have to select in the font since this may be a subclassed dc
+ * or a begin paint dc which hasn't been initialized with out fonts
+ * like ECGetEditDC does.
+ */
+ hOldFont = SelectObject(hdc, ped->hFont);
+
+ SLDrawText(ped, hdc, 0);
+
+ if (ped->hFont && hOldFont)
+ SelectObject(hdc, hOldFont);
+
+ }
+ ShowCaret(hwnd);
+
+ if (!althdc)
+ EndPaint(hwnd, (LPPAINTSTRUCT)&paintstruct);
+
+ ShowCaret(hwnd);
+}
+
+
+
+void NEAR PASCAL SLSetFocusHandler(ped)
+register PED ped;
+/* effects: Gives the edit control the focus and notifies the parent
+ * EN_SETFOCUS.
+ */
+{
+ register HDC hdc;
+
+ if (!ped->fFocus)
+ {
+ UpdateWindow(ped->hwnd);
+
+ ped->fFocus = TRUE; /* Set focus */
+
+ /* We don't want to muck with the caret since it isn't created. */
+ hdc = ECGetEditDC(ped,TRUE);
+
+ /* Show the current selection. Only if the selection was hidden when we
+ * lost the focus, must we invert (show) it.
+ */
+ if (!ped->fNoHideSel)
+ SLDrawText(ped, hdc, 0);
+
+ /* Create the caret. Add in the +1 because we have an extra pixel for
+ * highlighting around the text. If the font is at least as wide as the
+ * system font, use a wide caret else use a 1 pixel wide caret.
+ */
+ CreateCaret(ped->hwnd, (HBITMAP)NULL,
+ (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
+ ped->lineHeight+1);
+ SLSetCaretPosition(ped,hdc);
+ ECReleaseEditDC(ped,hdc,TRUE);
+ ShowCaret(ped->hwnd);
+ }
+
+ /* Notify parent we have the focus */
+ ECNotifyParent(ped, EN_SETFOCUS);
+}
+
+
+
+
+void NEAR PASCAL SLKillFocusHandler(ped, newFocusHwnd)
+register PED ped;
+HWND newFocusHwnd;
+/* effects: The edit control loses the focus and notifies the parent via
+ * EN_KILLFOCUS.
+ */
+{
+ RECT rcEdit;
+
+ if (ped->fFocus)
+ {
+ /* Destroy the caret */
+ HideCaret(ped->hwnd);
+ DestroyCaret();
+
+ ped->fFocus = FALSE; /* Clear focus */
+
+ /* Do this only if we still have the focus. But we always notify the
+ * parent that we lost the focus whether or not we originally had the
+ * focus.
+ */
+ /* Hide the current selection if needed */
+ if (!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel))
+ {
+ GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
+ if (ped->fBorder && rcEdit.right-rcEdit.left &&
+ rcEdit.bottom-rcEdit.top)
+ {
+ /* Don't invalidate the border so that we avoid flicker */
+ InflateRect((LPRECT)&rcEdit, -1, -1);
+ }
+ InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
+ UpdateWindow(ped->hwnd);
+
+#if 0
+ SLSetSelectionHandler(ped, ped->ichCaret, ped->ichCaret);
+#endif
+ }
+ }
+
+ /* If we aren't a combo box, notify parent that we lost the focus.
+ */
+ if (!ped->listboxHwnd)
+ ECNotifyParent(ped, EN_KILLFOCUS);
+ else
+ {
+ /* This editcontrol is part of a combo box and is losing the focus. If
+ * the focus is NOT being sent to another control in the combo box
+ * window, then it means the combo box is losing the focus. So we will
+ * notify the combo box of this fact.
+ */
+ if (!IsChild(ped->hwndParent, newFocusHwnd))
+ {
+ /* Focus is being sent to a window which is not a child of the combo
+ * box window which implies that the combo box is losing the focus.
+ * Send a message to the combo box informing him of this fact so
+ * that he can clean up...
+ */
+ SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
+ }
+ }
+}
+
+
+/*******************/
+/* SLEditWndProc() */
+/*******************/
+LONG FAR PASCAL SLEditWndProc(hwnd, ped, message, wParam, lParam)
+HWND hwnd;
+register PED ped;
+WORD message;
+register WORD wParam;
+LONG lParam;
+/* effects: Class procedure for all single line edit controls.
+ Dispatches all messages to the appropriate handlers which are named
+ as follows:
+ SL (single line) prefixes all single line edit control procedures while
+ EC (edit control) prefixes all common handlers.
+
+ The SLEditWndProc only handles messages specific to single line edit
+ controls.
+ */
+
+{
+ /* Dispatch the various messages we can receive */
+ switch (message)
+ {
+ case WM_CLEAR:
+ /* wParam - not used
+ lParam - not used */
+ /*
+ * Call SLKeyDownHandler with a VK_DELETE keycode to clear the selected
+ * text.
+ */
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLKeyDownHandler(ped, VK_DELETE, NOMODIFY);
+ break;
+
+ case WM_CHAR:
+ /* wParam - the value of the key
+ lParam - modifiers, repeat count etc (not used) */
+ if (!ped->fEatNextChar)
+ SLCharHandler(ped, wParam, 0);
+ else
+ ped->fEatNextChar = FALSE;
+ break;
+
+ case WM_CUT:
+ /* wParam - not used
+ lParam - not used */
+ /* Call SLKeyDownHandler with a VK_DELETE keycode to cut the selected
+ * text. (Delete key with shift modifier.) This is needed so that apps
+ * can send us WM_PASTE messages.
+ */
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
+ break;
+
+ case WM_ERASEBKGND:
+ /* wParam - device context handle
+ lParam - not used */
+ /* We do nothing on this message and we don't want DefWndProc to do
+ * anything, so return 1
+ */
+ return(1L);
+ break;
+
+ case WM_GETDLGCODE:
+ /* wParam - not used
+ lParam - not used */
+ return(DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS);
+ break;
+
+ case WM_KEYDOWN:
+ /* wParam - virt keycode of the given key
+ lParam - modifiers such as repeat count etc. (not used) */
+ SLKeyDownHandler(ped, wParam, 0);
+ break;
+
+ case WM_KILLFOCUS:
+ /* wParam - handle of the window that receives the input focus
+ lParam - not used */
+ SLKillFocusHandler(ped, (HWND)wParam);
+ break;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ /* wParam - contains a value that indicates which virtual keys are down
+ lParam - contains x and y coords of the mouse cursor */
+ SLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
+ break;
+
+ case WM_CREATE:
+ /* wParam - handle to window being created
+ lParam - points to a CREATESTRUCT that contains copies of parameters
+ passed to the CreateWindow function. */
+ return(SLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
+ break;
+
+ case WM_PAINT:
+ /* wParam - not used - actually sometimes used as a hdc when subclassing
+ lParam - not used */
+ SLPaintHandler(ped, wParam);
+ break;
+
+ case WM_PASTE:
+ /* wParam - not used
+ lParam - not used */
+ /* Call SLKeyDownHandler with a SHIFT VK_INSERT keycode to paste the
+ * clipboard into the edit control. This is needed so that apps can
+ * send us WM_PASTE messages.
+ */
+ SLKeyDownHandler(ped, VK_INSERT, SHFTDOWN);
+ break;
+
+ case WM_SETFOCUS:
+ /* wParam - handle of window that loses the input focus (may be NULL)
+ lParam - not used */
+ SLSetFocusHandler(ped);
+ break;
+
+ case WM_SETTEXT:
+ /* wParam - not used
+ lParam - points to a null-terminated string that is used to set the
+ window text. */
+ return(SLSetTextHandler(ped, (LPSTR)lParam));
+ break;
+
+ case WM_SIZE:
+ /* wParam - defines the type of resizing fullscreen, sizeiconic,
+ sizenormal etc.
+ lParam - new width in LOWORD, new height in HIGHWORD of client area */
+ SLSizeHandler(ped);
+ return(0L);
+ break;
+
+ case WM_SYSKEYDOWN:
+ if (ped->listboxHwnd && /* Check if we are in a combo box */
+ (lParam & 0x20000000L)) /* Check if the alt key is down */
+ {
+ /*
+ * Handle Combobox support. We want alt up or down arrow to behave
+ * like F4 key which completes the combo box selection
+ */
+ ped->fEatNextChar = FALSE;
+ if (lParam & 0x1000000)
+ {
+ /* This is an extended key such as the arrow keys not on the
+ * numeric keypad so just drop the combobox.
+ */
+ if (wParam == VK_DOWN || wParam == VK_UP)
+ goto DropCombo;
+ else
+ goto foo;
+ }
+
+ if (GetKeyState(VK_NUMLOCK) < 0)
+ {
+ ped->fEatNextChar = FALSE;
+ /* If numlock down, just send all system keys to dwp */
+ goto foo;
+ }
+ else
+ /* Num lock is up. Eat the characters generated by the key board
+ * driver.
+ */
+ ped->fEatNextChar = TRUE;
+
+ if (!(wParam == VK_DOWN || wParam == VK_UP))
+ goto foo;
+
+DropCombo:
+ if (SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L) & 0x00000001)
+ {
+ /* Extended ui doesn't honor VK_F4. */
+ if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))
+ return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0L));
+ else
+ return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0L));
+ }
+ else
+ return(SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L));
+ }
+foo:
+ if (wParam == VK_BACK)
+ {
+ SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
+ break;
+ }
+ goto PassToDefaultWindowProc;
+ break;
+
+ case EM_GETLINE:
+ /* wParam - line number to copy (always the first line for SL)
+ lParam - buffer to copy text to. FIrst word is max # of bytes to copy
+ */
+ return(ECGetTextHandler(ped, (*(WORD FAR *)lParam), (LPSTR)lParam));
+ break;
+
+ case EM_LINELENGTH:
+ /* wParam - ignored
+ lParam - ignored */
+ return((LONG)ped->cch);
+ break;
+
+ case EM_SETSEL:
+ /* wParam - not used
+ lParam - starting pos in lowword ending pos in high word */
+ SLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case EM_REPLACESEL:
+ /* wParam - not used
+ lParam - points to a null terminated string of replacement text */
+ SLReplaceSelHandler(ped, (LPSTR)lParam);
+ break;
+
+ case WM_UNDO:
+ case EM_UNDO:
+ SLUndoHandler(ped);
+ break;
+
+ default:
+PassToDefaultWindowProc:
+ return(DefWindowProc(hwnd,message,wParam,lParam));
+ break;
+
+ } /* switch (message) */
+
+ return(1L);
+} /* SLEditWndProc */
diff --git a/private/mvdm/wow16/user/edmlonce.c b/private/mvdm/wow16/user/edmlonce.c
new file mode 100644
index 000000000..ff9c0e433
--- /dev/null
+++ b/private/mvdm/wow16/user/edmlonce.c
@@ -0,0 +1,179 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDMLONCE.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* edmlonce.c - Edit controls Routines Called just once or twice are to be */
+/* put in a seperate segment _EDMLONCE. This file contains */
+/* these routines. */
+/* */
+/* */
+/* Created: 02-08-89 sankar */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Multi-Line Support Routines called just once */
+/****************************************************************************/
+
+void FAR PASCAL MLSizeHandler(ped)
+register PED ped;
+
+/* effects: Handles sizing of the edit control window and properly updating
+ * the fields that are dependent on the size of the control. ie. text
+ * characters visible etc.
+ */
+{
+ RECT rc;
+
+ GetClientRect(ped->hwnd, (LPRECT)&rc);
+
+ MLSetRectHandler(ped, (LPRECT)&rc);
+
+ GetWindowRect(ped->hwnd, (LPRECT)&rc);
+ ScreenToClient(ped->hwnd, (LPPOINT)&rc.left);
+ ScreenToClient(ped->hwnd, (LPPOINT)&rc.right);
+ InvalidateRect(ped->hwnd, (LPRECT) &rc, TRUE);
+ /*UpdateWindow(ped->hwnd);*/
+}
+
+
+
+BOOL FAR PASCAL MLSetTextHandler(ped, lpstr)
+register PED ped;
+LPSTR lpstr;
+/* effects: Copies the null terminated text in lpstr to the ped. Notifies the
+ * parent if there isn't enough memory. Returns TRUE if successful else FALSE
+ * if memory error.
+ */
+{
+ BOOL fInsertSuccessful;
+
+ /* Set the text and update the window if text was added */
+ fInsertSuccessful = ECSetText(ped, lpstr);
+
+ if (fInsertSuccessful)
+ {
+ MLStripCrCrLf(ped);
+ /* Always build lines even if no text was inserted. */
+ MLBuildchLines(ped, 0, 0, FALSE);
+
+
+ /* Reset caret and selections since the text could have changed */
+ ped->screenStart = ped->ichMinSel = ped->ichMaxSel = 0;
+ ped->ichCaret = 0;
+ ped->xOffset = 0;
+ ped->iCaretLine = 0;
+ ped->fDirty = FALSE;
+ }
+ ECEmptyUndo(ped);
+
+ SetScrollPos(ped->hwnd, SB_VERT, 0, TRUE);
+ SetScrollPos(ped->hwnd, SB_HORZ, 0, TRUE);
+
+ /* We will always redraw the text whether or not the insert was successful
+ * since we may set to null text. Since PaintHandler checks the redraw flag,
+ * we won't bother to check it here.
+ */
+ InvalidateRect(ped->hwnd, (LPRECT)NULL, TRUE);
+ /* Need to do the updatewindow to keep raid happy.*/
+ UpdateWindow(ped->hwnd);
+
+ return(fInsertSuccessful);
+}
+
+
+
+LONG FAR PASCAL MLCreateHandler(hwnd, ped, lpCreateStruct)
+HWND hwnd;
+register PED ped;
+LPCREATESTRUCT lpCreateStruct;
+
+/* effects: Creates the edit control for the window hwnd by allocating memory
+ * as required from the application's heap. Notifies parent if no memory
+ * error (after cleaning up if needed). Returns TRUE if no error else returns
+ * -1.
+ */
+{
+ LONG windowStyle;
+ LPSTR lpWindowText=lpCreateStruct->lpszName;
+ RECT rc;
+
+
+ /* Save the text across the local allocs in ECNcCreate */
+ SwapHandle(&lpWindowText);
+
+ /* Do the standard creation stuff */
+ if (!ECCreate(hwnd, ped, lpCreateStruct))
+ return(-1);
+
+ /* Allocate line start array as a fixed block in local heap */
+ if (!(ped->chLines = (int *)LocalAlloc(LPTR,2*sizeof(int))))
+ return(-1);
+
+ /* Call it one line of text... */
+ ped->cLines = 1;
+
+ /* Get values from the window instance data structure and put them in the
+ * ped so that we can access them easier
+ */
+ windowStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ /* If app wants WS_VSCROLL or WS_HSCROLL, it automatically gets AutoVScroll
+ * or AutoHScroll.
+ */
+ if ((windowStyle & ES_AUTOVSCROLL) || (windowStyle & WS_VSCROLL))
+ ped->fAutoVScroll = 1;
+
+ ped->format = (LOWORD(windowStyle) & LOWORD(ES_FMTMASK));
+ if (ped->format != ES_LEFT)
+ {
+ /* If user wants right or center justified text, then we turn off
+ * AUTOHSCROLL and WS_HSCROLL since non-left styles don't make sense
+ * otherwise.
+ */
+ windowStyle = windowStyle & ~WS_HSCROLL;
+ SetWindowLong(hwnd, GWL_STYLE, windowStyle);
+ ped->fAutoHScroll = FALSE;
+ }
+
+ if (windowStyle & WS_HSCROLL)
+ ped->fAutoHScroll = 1;
+
+ ped->fWrap = (!ped->fAutoHScroll && !(windowStyle & WS_HSCROLL));
+
+ ped->fSingle = FALSE; /* Set multi line edit control */
+ _asm int 3
+ ped->cchTextMax = MAXTEXT; /* Max # chars we will allow user to enter */
+
+ /* Set the default font to be the system font.
+ */
+ ECSetFont(ped, NULL, FALSE);
+
+ SetRect((LPRECT)&rc, 0, 0, ped->aveCharWidth*10, ped->lineHeight);
+ MLSetRectHandler(ped, (LPRECT)&rc);
+ /* Set the window text if needed and notify parent if not enough memory to
+ * set the initial text.
+ */
+ /* Restore the text from the save we did at the beginning */
+ SwapHandle(&lpWindowText);
+
+ if (lpWindowText && !MLSetTextHandler(ped, lpWindowText))
+ return(-1);
+
+ return(TRUE);
+}
diff --git a/private/mvdm/wow16/user/edmlrare.c b/private/mvdm/wow16/user/edmlrare.c
new file mode 100644
index 000000000..f1b774a1c
--- /dev/null
+++ b/private/mvdm/wow16/user/edmlrare.c
@@ -0,0 +1,422 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDMLRARE.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* edmlRare.c - Edit controls Routines Called rarely are to be */
+/* put in a seperate segment _EDMLRare. This file contains */
+/* these routines. */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Multi-Line Support Routines called Rarely */
+/****************************************************************************/
+
+BOOL FAR PASCAL MLInsertCrCrLf(ped)
+register PED ped;
+/* effects: Inserts CR CR LF characters into the text at soft (word-wrap) line
+ * breaks. CR LF (hard) line breaks are unaffected. Assumes that the text
+ * has already been formatted ie. ped->chLines is where we want the line
+ * breaks to occur. Note that ped->chLines is not updated to reflect the
+ * movement of text by the addition of CR CR LFs. Returns TRUE if successful
+ * else notify parent and return FALSE if the memory couldn't be allocated.
+ */
+{
+ ICH dch;
+ ICH li;
+ ICH lineSize;
+ /*register*/ unsigned char *pchText;
+ unsigned char *pchTextNew;
+
+
+ if (!ped->fWrap || !ped->cch)
+ /* There are no soft line breaks if word-wrapping is off or if no chars
+ */
+ return(TRUE);
+
+ /* Calc an upper bound on the number of additional characters we will be
+ * adding to the text when we insert CR CR LFs.
+ */
+ dch = 3 * sizeof(char) * ped->cLines;
+
+ if (!LocalReAlloc(ped->hText, ped->cch + dch, 0))
+ {
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return (FALSE);
+ }
+
+ ped->cchAlloc = ped->cch + dch;
+
+ /* Move the text up dch bytes and then copy it back down, inserting the CR
+ * CR LF's as necessary.
+ */
+
+ pchTextNew = pchText = LocalLock(ped->hText);
+ pchText += dch;
+ dch = 0; /* Now we will use this to keep track of how many chars we add
+ to the text */
+
+ /* Copy the text up dch bytes to pchText. This will shift all indices in
+ * ped->chLines up by dch bytes.
+ */
+ LCopyStruct((LPSTR)pchTextNew, (LPSTR)pchText, ped->cch);
+
+ /* Now copy chars from pchText down to pchTextNew and insert CRCRLF at soft
+ * line breaks.
+ */
+ for (li = 0; li < ped->cLines-1; li++)
+ {
+ lineSize = ped->chLines[li+1]-ped->chLines[li];
+ LCopyStruct((LPSTR)pchText, (LPSTR)pchTextNew, lineSize);
+ pchTextNew += lineSize;
+ pchText += lineSize;
+ /* If last character in newly copied line is not a line feed, then we
+ * need to add the CR CR LF triple to the end
+ */
+ if (*(PSTR)(pchTextNew-1) != 0x0A)
+ {
+ *pchTextNew++ = 0x0D;
+ *pchTextNew++ = 0x0D;
+ *pchTextNew++ = 0x0A;
+ dch += 3;
+ }
+ }
+
+ /* Now move the last line up. It won't have any line breaks in it... */
+ LCopyStruct((LPSTR)pchText, (LPSTR)pchTextNew,
+ ped->cch-ped->chLines[ped->cLines-1]);
+
+ LocalUnlock(ped->hText);
+
+ /* Update number of characters in text handle */
+ ped->cch += dch;
+
+ if (dch)
+ /*
+ * So that the next time we do anything with the text, we can strip the
+ * CRCRLFs
+ */
+ ped->fStripCRCRLF = TRUE;
+
+ return((dch != 0));
+}
+
+
+void FAR PASCAL MLStripCrCrLf(ped)
+register PED ped;
+/* effects: Strips the CR CR LF character combination from the text. This
+ * shows the soft (word wrapped) line breaks. CR LF (hard) line breaks are
+ * unaffected.
+ */
+{
+ register unsigned char *pchSrc;
+ unsigned char *pchDst;
+ unsigned char *pchLast;
+
+ if (ped->cch)
+ {
+ pchSrc = pchDst = LocalLock(ped->hText);
+ pchLast = pchSrc + ped->cch;
+ while (pchSrc < pchLast)
+ {
+ if (*(int *)pchSrc != 0x0D0D)
+ *pchDst++ = *pchSrc++;
+ else
+ {
+ pchSrc += 3;
+ ped->cch = ped->cch - 3;
+ }
+ }
+ LocalUnlock(ped->hText);
+ }
+}
+
+
+void FAR PASCAL MLSetHandleHandler(ped, hNewText)
+register PED ped;
+HANDLE hNewText;
+/* effects: Sets the ped to contain the given handle.
+ */
+{
+ ICH newCch;
+
+ ped->cch = ped->cchAlloc = LocalSize(ped->hText = hNewText);
+ if (ped->cch)
+ {
+ /* We have to do it this way in case the app gives us a zero size
+ handle */
+ ped->cch = lstrlen((LPSTR)LocalLock(ped->hText));
+ LocalUnlock(ped->hText);
+ }
+
+ /* Empty the undo buffer since the text will be in an inconsistant state.
+ */
+ ECEmptyUndo(ped);
+
+ newCch = (ICH)(ped->cch + CCHALLOCEXTRA);
+ /* We do this LocalReAlloc in case the app changed the size of the handle */
+ if (LocalReAlloc(ped->hText, newCch, 0))
+ ped->cchAlloc = newCch;
+
+ ped->fDirty = FALSE;
+
+ MLStripCrCrLf(ped);
+ MLBuildchLines(ped,0,0,FALSE);
+
+ /* Reset caret and selections since the text could have changed causing
+ * these to be out of range.
+ */
+ ped->xOffset = ped->screenStart = ped->ichMinSel = ped->ichMaxSel = 0;
+ ped->iCaretLine = ped->ichCaret = 0;
+
+ SetScrollPos(ped->hwnd, SB_VERT, 0, TRUE);
+ SetScrollPos(ped->hwnd, SB_HORZ, 0, TRUE);
+
+ /* We will always redraw the text whether or not the insert was successful
+ * since we may set to null text. Also, since PaintHandler checks the redraw
+ * flag, we won't bother to check it here.
+ */
+ InvalidateRect(ped->hwnd, (LPRECT)NULL, TRUE);
+ UpdateWindow(ped->hwnd);
+}
+
+
+LONG FAR PASCAL MLGetLineHandler(ped, lineNumber, maxCchToCopy, lpBuffer)
+register PED ped;
+WORD lineNumber;
+ICH maxCchToCopy;
+LPSTR lpBuffer;
+/* effects: Copies maxCchToCopy bytes of line lineNumber to the buffer
+ * lpBuffer. The string is not zero terminated.
+ */
+{
+ PSTR pText;
+
+ if (lineNumber > ped->cLines-1)
+ return(0L);
+
+ maxCchToCopy = umin(MLLineLength(ped, lineNumber), maxCchToCopy);
+
+ if (maxCchToCopy)
+ {
+ pText = (PSTR)(LocalLock(ped->hText) + ped->chLines[lineNumber]);
+ LCopyStruct((LPSTR)pText, (LPSTR)lpBuffer, maxCchToCopy);
+ LocalUnlock(ped->hText);
+ }
+
+ return(maxCchToCopy);
+
+}
+
+
+ICH FAR PASCAL MLLineIndexHandler(ped, iLine)
+register PED ped;
+register int iLine;
+/* effects: This function returns the number of character positions that occur
+ * preceeding the first char in a given line.
+ */
+{
+ if (iLine == -1)
+ iLine = ped->iCaretLine;
+ return(iLine < ped->cLines ? ped->chLines[iLine] : -1);
+}
+
+
+
+ICH FAR PASCAL MLLineLengthHandler(ped, ich)
+register PED ped;
+ICH ich;
+/* effects: if ich = -1, return the length of the lines containing the current
+ * selection but not including the selection. Otherwise, return the length of
+ * the line containing ich.
+ */
+{
+ ICH il1, il2;
+
+ if (ich != 0xFFFF)
+ return(MLLineLength(ped, MLIchToLineHandler(ped, ich)));
+
+ /* Find length of lines corresponding to current selection */
+ il1 = MLIchToLineHandler(ped, ped->ichMinSel);
+ il2 = MLIchToLineHandler(ped, ped->ichMaxSel);
+ if (il1 == il2)
+ return(MLLineLength(ped, il1) - (ped->ichMaxSel - ped->ichMinSel));
+
+ return(ped->ichMinSel - ped->chLines[il1] +
+ MLLineLength(ped, il2) - (ped->ichMaxSel - ped->chLines[il2]));
+}
+
+
+void FAR PASCAL MLSetSelectionHandler(ped, ichMinSel, ichMaxSel)
+register PED ped;
+ICH ichMinSel;
+ICH ichMaxSel;
+/*
+ * effects: Sets the selection to the points given and puts the cursor at
+ * ichMaxSel.
+ */
+{
+ register HDC hdc;
+
+ if (ichMinSel == 0xFFFF)
+ /* Set no selection if we specify -1
+ */
+ ichMinSel = ichMaxSel = ped->ichCaret;
+
+ /* Since these are unsigned, we don't check if they are greater than 0.
+ */
+ ichMinSel = umin(ped->cch,ichMinSel);
+ ichMaxSel = umin(ped->cch,ichMaxSel);
+
+ /* Set the caret's position to be at ichMaxSel.
+ */
+ ped->ichCaret = ichMaxSel;
+ ped->iCaretLine = MLIchToLineHandler(ped, ped->ichCaret);
+
+ hdc = ECGetEditDC(ped,FALSE);
+ MLChangeSelection(ped, hdc, ichMinSel, ichMaxSel);
+
+ MLSetCaretPosition(ped,hdc);
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+ MLEnsureCaretVisible(ped);
+}
+
+
+/**
+** MLSetTabStops(ped, nTabPos, lpTabStops)
+**
+** This sets the tab stop positions set by the App by sending
+** a EM_SETTABSTOPS message.
+**
+** nTabPos : Number of tab stops set by the caller
+** lpTabStops: array of tab stop positions in Dialog units.
+**
+** Returns:
+** TRUE if successful
+** FALSE if memory allocation error.
+**/
+
+BOOL FAR PASCAL MLSetTabStops(ped, nTabPos, lpTabStops)
+
+PED ped;
+int nTabPos;
+LPINT lpTabStops;
+
+{
+ int * pTabStops;
+
+ /* Check if tab positions already exist */
+ if (!ped -> pTabStops)
+ {
+ /* Check if the caller wants the new tab positions */
+ if (nTabPos)
+ {
+ /* Allocate the array of tab stops */
+ if(!(pTabStops = (int *)LocalAlloc(LPTR, (nTabPos + 1)*sizeof(int))))
+ return(FALSE);
+ }
+ else
+ return(TRUE); /* No stops then and no stops now! */
+ }
+ else
+ {
+ /* Check if the caller wants the new tab positions */
+ if(nTabPos)
+ {
+ /* Check if the number of tab positions is different */
+ if (ped->pTabStops[0] != nTabPos)
+ {
+ /* Yes! So ReAlloc to new size */
+ if(!(pTabStops = (int *)LocalReAlloc((HANDLE)ped->pTabStops,
+ (nTabPos + 1) * sizeof(int), LPTR)))
+ return(FALSE);
+ }
+ else
+ pTabStops = ped->pTabStops;
+ }
+ else
+ {
+ /* Caller wants to remove all the tab stops; So, release */
+ if (LocalFree((HANDLE)ped->pTabStops))
+ return(FALSE); /* Failure */
+ ped->pTabStops = NULL;
+ return(TRUE);
+ }
+ }
+
+ /* Copy the new tab stops onto the tab stop array after converting the
+ * dialog co-ordinates into the pixel co-ordinates
+ */
+
+ ped -> pTabStops = pTabStops;
+ *pTabStops++ = nTabPos; /* First element contains the count */
+ while(nTabPos--)
+ {
+ /* aveCharWidth must be used instead of cxSysCharWidth.
+ * Fix for Bug #3871 --SANKAR-- 03/14/91
+ */
+ *pTabStops++ = MultDiv(*lpTabStops++, ped->aveCharWidth, 4);
+ }
+
+ return(TRUE);
+}
+
+BOOL FAR PASCAL MLUndoHandler(ped)
+register PED ped;
+/* effects: Handles Undo for multiline edit controls. */
+{
+ HANDLE hDeletedText = ped->hDeletedText;
+ BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE);
+ WORD cchDeleted = ped->cchDeleted;
+ WORD ichDeleted = ped->ichDeleted;
+
+ if (ped->undoType == UNDO_NONE)
+ /* No undo... */
+ return(FALSE);
+
+ ped->hDeletedText = NULL;
+ ped->cchDeleted = 0;
+ ped->ichDeleted = -1;
+ ped->undoType &= ~UNDO_DELETE;
+
+ if (ped->undoType == UNDO_INSERT)
+ {
+ ped->undoType = UNDO_NONE;
+ /* Set the selection to the inserted text */
+ MLSetSelectionHandler(ped, ped->ichInsStart, ped->ichInsEnd);
+ ped->ichInsStart = ped->ichInsEnd = -1;
+ /* Now send a backspace to delete and save it in the undo buffer...
+ */
+ MLCharHandler(ped, VK_BACK, NOMODIFY);
+ }
+
+ if (fDelete)
+ {
+ /* Insert deleted chars */
+ /* Set the selection to the inserted text */
+ MLSetSelectionHandler(ped, ichDeleted, ichDeleted);
+ MLInsertText(ped, GlobalLock(hDeletedText), cchDeleted, FALSE);
+ GlobalUnlock(hDeletedText);
+ GlobalFree(hDeletedText);
+ MLSetSelectionHandler(ped, ichDeleted, ichDeleted+cchDeleted);
+ }
+
+ return(TRUE);
+}
+
diff --git a/private/mvdm/wow16/user/edslrare.c b/private/mvdm/wow16/user/edslrare.c
new file mode 100644
index 000000000..4fc13c95d
--- /dev/null
+++ b/private/mvdm/wow16/user/edslrare.c
@@ -0,0 +1,288 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDSLRARE.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* edslRare.c - SL Edit controls Routines Called rarely are to be */
+/* put in a seperate segment _EDSLRare. This file contains */
+/* these routines. */
+/* */
+/* */
+/* Created: 02-08-89 sankar */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Single-Line Support Routines called Rarely */
+/****************************************************************************/
+
+void FAR PASCAL SLSetSelectionHandler(ped, ichSelStart, ichSelEnd)
+register PED ped;
+ICH ichSelStart;
+ICH ichSelEnd;
+/* effects: Sets the PED to have the new selection specified.
+ */
+{
+ register HDC hdc = ECGetEditDC(ped, FALSE);
+
+ if (ichSelStart == 0xFFFF)
+ /* Set no selection if we specify -1 */
+ ichSelStart = ichSelEnd = ped->ichCaret;
+
+ /* Bounds ichSelStart, ichSelEnd are checked in SLChangeSelection... */
+ SLChangeSelection(ped, hdc, ichSelStart, ichSelEnd);
+ /* Put the caret at the end of the selected text */
+ ped->ichCaret = ped->ichMaxSel;
+
+ SLSetCaretPosition(ped,hdc);
+
+ /* We may need to scroll the text to bring the caret into view... */
+ SLScrollText(ped,hdc);
+
+ ECReleaseEditDC(ped,hdc,FALSE);
+}
+
+
+void FAR PASCAL SLSizeHandler(ped)
+register PED ped;
+/* effects: Handles sizing of the edit control window and properly updating
+ * the fields that are dependent on the size of the control. ie. text
+ * characters visible etc.
+ */
+{
+ RECT rc;
+ GetClientRect(ped->hwnd, &rc);
+ if (!(rc.right-rc.left) || !(rc.bottom-rc.top))
+ {
+ if (ped->rcFmt.right-ped->rcFmt.left)
+ /* Don't do anything if we are becomming zero width or height and
+ out formatting rect is already set... */
+ return;
+ /* Otherwise set some initial values to avoid divide by zero problems
+ later... */
+ SetRect((LPRECT)&rc,0,0,10,10);
+ }
+
+ CopyRect(&ped->rcFmt, &rc);
+ if (ped->fBorder)
+ /* Shrink client area to make room for the border */
+ InflateRect((LPRECT)&ped->rcFmt,
+ -(min(ped->aveCharWidth,ped->cxSysCharWidth)/2),
+ -(min(ped->lineHeight,ped->cySysCharHeight)/4));
+
+#ifdef BROKEN
+ ped->rcFmt.bottom = min(ped->rcFmt.top+
+ max(ped->lineHeight,ped->cySysCharHeight),
+ ped->rcFmt.bottom);
+#else
+ ped->rcFmt.bottom = min(ped->rcFmt.top+
+ ped->lineHeight,
+ ped->rcFmt.bottom);
+#endif
+}
+
+
+BOOL FAR PASCAL SLSetTextHandler(ped, lpstr)
+register PED ped;
+LPSTR lpstr;
+/* effects: Copies the null terminated text in lpstr to the ped. Notifies the
+ * parent if there isn't enough memory. Returns TRUE if successful else
+ * FALSE.
+ */
+{
+ BOOL fInsertSuccessful;
+ RECT rcEdit;
+
+ SwapHandle(&lpstr);
+ ECEmptyUndo(ped);
+ SwapHandle(&lpstr);
+
+ /* Add the text and update the window if text was added. The parent is
+ * notified of no memory in ECSetText.
+ */
+ if (fInsertSuccessful = ECSetText(ped, lpstr))
+ ped->fDirty = FALSE;
+
+ ECEmptyUndo(ped);
+
+ if (!ped->listboxHwnd)
+ ECNotifyParent(ped, EN_UPDATE);
+
+#ifndef WOW
+ if (FChildVisible(ped->hwnd))
+#else
+ if (IsWindowVisible(GetParent(ped->hwnd)))
+#endif
+ {
+ /* We will always redraw the text whether or not the insert was
+ * successful since we may set to null text.
+ */
+ GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
+ if (ped->fBorder &&
+ rcEdit.right-rcEdit.left && rcEdit.bottom-rcEdit.top)
+ {
+ /* Don't invalidate the border so that we avoid flicker */
+ InflateRect((LPRECT)&rcEdit, -1, -1);
+ }
+ InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
+ UpdateWindow(ped->hwnd);
+ }
+
+ if (!ped->listboxHwnd)
+ ECNotifyParent(ped, EN_CHANGE);
+
+ return(fInsertSuccessful);
+}
+
+
+LONG FAR PASCAL SLCreateHandler(hwnd, ped, lpCreateStruct)
+HWND hwnd;
+register PED ped;
+LPCREATESTRUCT lpCreateStruct;
+
+/* effects: Creates the edit control for the window hwnd by allocating memory
+ * as required from the application's heap. Notifies parent if no memory
+ * error (after cleaning up if needed). Returns TRUE if no error else returns
+ * -1.
+ */
+{
+ LPSTR lpWindowText = lpCreateStruct->lpszName;
+ LONG windowStyle = GetWindowLong(hwnd, GWL_STYLE);
+
+ /* Save text across the local allocs in ECNcCreate */
+ SwapHandle(&lpWindowText);
+
+ /* Do the standard creation stuff */
+ if (!ECCreate(hwnd, ped, lpCreateStruct))
+ return(-1);
+
+ ped->fSingle = TRUE; /* Set single line edit control */
+
+ /* Single lines always have no undo and 1 line */
+ ped->cLines = 1;
+ ped->undoType = UNDO_NONE;
+
+ /* Check if this edit control is part of a combobox and get a pointer to the
+ * combobox structure.
+ */
+ if (windowStyle & ES_COMBOBOX)
+ ped->listboxHwnd = GetDlgItem(lpCreateStruct->hwndParent,CBLISTBOXID);
+
+ /* Set the default font to be the system font.
+ */
+ ECSetFont(ped, NULL, FALSE);
+
+ /* Set the window text if needed. Return false if we can't set the text
+ * SLSetText notifies the parent in case there is a no memory error.
+ */
+ /* Restore text */
+ SwapHandle(&lpWindowText);
+ if (lpWindowText && *lpWindowText && !SLSetTextHandler(ped, lpWindowText))
+ return(-1);
+
+ if (windowStyle & ES_PASSWORD)
+ ECSetPasswordChar(ped, (WORD)'*');
+
+ return(TRUE);
+}
+
+
+
+BOOL FAR PASCAL SLUndoHandler(ped)
+register PED ped;
+/* effects: Handles UNDO for single line edit controls. */
+{
+ HANDLE hDeletedText = ped->hDeletedText;
+ BOOL fDelete = (BOOL)(ped->undoType & UNDO_DELETE);
+ WORD cchDeleted = ped->cchDeleted;
+ WORD ichDeleted = ped->ichDeleted;
+ BOOL fUpdate = FALSE;
+ RECT rcEdit;
+
+
+ if (ped->undoType == UNDO_NONE)
+ /* No undo... */
+ return(FALSE);
+
+ ped->hDeletedText = NULL;
+ ped->cchDeleted = 0;
+ ped->ichDeleted = -1;
+ ped->undoType &= ~UNDO_DELETE;
+
+ if (ped->undoType == UNDO_INSERT)
+ {
+ ped->undoType = UNDO_NONE;
+ /* Set the selection to the inserted text */
+ SLSetSelectionHandler(ped, ped->ichInsStart, ped->ichInsEnd);
+ ped->ichInsStart = ped->ichInsEnd = -1;
+
+#ifdef NEVER
+ /* Now send a backspace to deleted and save it in the undo buffer... */
+ SLCharHandler(ped, VK_BACK, NOMODIFY);
+ fUpdate = TRUE;
+#else
+ /* Delete the selected text and save it in undo buff */
+ /* Call ECDeleteText() instead of sending a VK_BACK message which
+ * results in a EN_UPDATE notification sent even before we insert
+ * the deleted chars. This results in Bug #6610.
+ * Fix for Bug #6610 -- SANKAR -- 04/19/91 --
+ */
+ if (ECDeleteText(ped))
+ fUpdate = TRUE;
+#endif
+ }
+
+ if (fDelete)
+ {
+ /* Insert deleted chars */
+ /* Set the selection to the inserted text */
+ SLSetSelectionHandler(ped, ichDeleted, ichDeleted);
+ SLInsertText(ped, GlobalLock(hDeletedText), cchDeleted);
+ GlobalUnlock(hDeletedText);
+ GlobalFree(hDeletedText);
+ SLSetSelectionHandler(ped, ichDeleted, ichDeleted+cchDeleted);
+ fUpdate=TRUE;
+ }
+
+ if(fUpdate)
+ {
+ /* If we have something to update, send EN_UPDATE before and EN_CHANGE
+ * after the actual update.
+ * A part of the Fix for Bug #6610 -- SANKAR -- 04/19/91 --
+ */
+ ECNotifyParent(ped, EN_UPDATE);
+#ifndef WOW
+ if (FChildVisible(ped->hwnd))
+#else
+ if (IsWindowVisible(GetParent(ped->hwnd)))
+#endif
+ {
+ GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
+ if (ped->fBorder && rcEdit.right-rcEdit.left &&
+ rcEdit.bottom-rcEdit.top)
+ {
+ /* Don't invalidate the border so that we avoid flicker */
+ InflateRect((LPRECT)&rcEdit, -1, -1);
+ }
+ InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
+ UpdateWindow(ped->hwnd);
+ }
+ ECNotifyParent(ped,EN_CHANGE);
+ }
+ return(TRUE);
+}
+
diff --git a/private/mvdm/wow16/user/fastres.c b/private/mvdm/wow16/user/fastres.c
new file mode 100644
index 000000000..8b86ad44b
--- /dev/null
+++ b/private/mvdm/wow16/user/fastres.c
@@ -0,0 +1,427 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * FASTRES.C
+ * WOW16 user resource services
+ *
+ * History:
+ *
+ * Created 12-Jan-1993 by Chandan Chuahan (ChandanC)
+ *
+ * This file provides the Win 3.1 routines for loading BITMAP, MENU, ICON,
+ * CURSOR, and DIALOG resources. These routines load the resources from the
+ * App EXE and then pass the pointers to the corresponding 32 bit WOW
+ * thunks. Thus saving the call backs from USER client to find, load, lock,
+ * size, unlock, and free the resources.
+ *
+--*/
+
+#include "user.h"
+
+HBITMAP FAR PASCAL WOWLoadBitmap (HINSTANCE hInst, LPCSTR lpszBitmap, LPBYTE lpByte, DWORD ResSize);
+HMENU FAR PASCAL WOWLoadMenu (HINSTANCE hInst, LPCSTR lpszMenuName, LPBYTE lpByte, DWORD ResSize, WORD WinVer);
+HCURSOR FAR PASCAL WOWLoadCursorIcon (HINSTANCE hInst, LPCSTR lpszCursor, LPBYTE lpByte, DWORD ResSize, HGLOBAL hGbl, WORD WinVer, WORD wRttype);
+
+//
+// fDialogApi is TRUE for DialogBox* apis
+// fDialogApi is FALSE for CreateDialog* apis
+//
+
+HWND FAR PASCAL WOWDialogBoxParam (HINSTANCE hInst, LPBYTE lpByte,
+ HWND hwndOwner, DLGPROC dlgprc, LPARAM lParamInit,
+ DWORD ResSize, WORD fDialogApi);
+
+DWORD FAR PASCAL NotifyWOW (WORD Id, LPBYTE pData);
+DWORD FAR PASCAL WOWGetIdFromDirectory (LPBYTE lpByte, WORD ResType);
+HANDLE FAR PASCAL WOWSetClipboardData (UINT, HANDLE);
+
+typedef struct _ICONCUR16 { /* iconcur */
+ WORD hInst;
+ DWORD lpStr;
+} ICONCUR16;
+
+#define FUN_LOADICON 174 //
+#define FUN_LOADCURSOR 173 //
+
+HINSTANCE CheckDispHandle (HINSTANCE hInst)
+{
+ HMODULE hIns;
+
+ if (hInst) {
+ hIns = GetModuleHandle ("DISPLAY");
+ return ((hInst == (HINSTANCE) hIns) ? 0:hInst);
+ }
+ else {
+ return (0);
+ }
+}
+
+
+HBITMAP API ILoadBitmap (HINSTANCE hInst, LPCSTR lpszBitmap)
+{
+ HRSRC hRsrc = 0;
+ HGLOBAL hGbl = 0;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ HBITMAP ul = (HBITMAP)0;
+
+ if (hInst = CheckDispHandle (hInst)) {
+
+ hRsrc = FindResource (hInst, lpszBitmap, MAKEINTRESOURCE(RT_BITMAP));
+ if (!hRsrc) {
+ goto lbm_exit;
+ }
+ ResSize = SizeofResource (hInst, hRsrc);
+ if (!ResSize) {
+ goto lbm_exit;
+ }
+
+ hGbl = LoadResource (hInst, hRsrc);
+ if (!hGbl) {
+ goto lbm_exit;
+ }
+
+ lpByte = LockResource (hGbl);
+ if (!lpByte) {
+ goto lbm_exit;
+ }
+ }
+
+ ul = (HBITMAP) WOWLoadBitmap (hInst, lpszBitmap, lpByte, ResSize);
+
+
+lbm_exit:
+ if (lpByte) {
+ GlobalUnlock (hGbl);
+ }
+ if (hGbl) {
+ FreeResource(hGbl);
+ }
+
+ return (ul);
+}
+
+
+
+
+HMENU API ILoadMenu (HINSTANCE hInst, LPCSTR lpszMenuName)
+{
+ HRSRC hRsrc;
+ HGLOBAL hGbl;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ HMENU ul;
+ WORD WinVer;
+
+ if (hRsrc = FindResource (hInst, lpszMenuName, MAKEINTRESOURCE(RT_MENU))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ if (lpByte = LockResource (hGbl))
+ WinVer = GetExpWinVer (hInst);
+ }
+
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ ul = (HMENU) WOWLoadMenu (hInst, lpszMenuName, lpByte, ResSize, WinVer);
+
+ if (hInst) {
+ GlobalUnlock (hGbl);
+ }
+
+ return (ul);
+}
+
+
+HICON API ILoadIcon (HINSTANCE hInst, LPCSTR lpszIcon)
+{
+ HRSRC hRsrc;
+ HGLOBAL hGbl;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ HICON ul;
+ DWORD IconId;
+ WORD WinVer;
+
+ ICONCUR16 IconCur;
+
+ WinVer = GetExpWinVer (hInst);
+
+ if (!(hInst = CheckDispHandle (hInst))) {
+ ul = WOWLoadCursorIcon (hInst, lpszIcon, lpByte, ResSize, NULL, WinVer, RT_ICON);
+ }
+ else {
+ IconCur.hInst = (WORD) hInst;
+ IconCur.lpStr = (DWORD) lpszIcon;
+
+ if (!(ul = (HICON) NotifyWOW (FUN_LOADICON, (LPBYTE) &IconCur))) {
+ if (WinVer >= VER30) {
+ if (hRsrc = FindResource (hInst, lpszIcon, MAKEINTRESOURCE(RT_GROUP_ICON))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ lpByte = LockResource (hGbl);
+ }
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ IconId = WOWGetIdFromDirectory (lpByte, (WORD) RT_ICON);
+
+ GlobalUnlock (hGbl);
+ }
+ else {
+ IconId = (DWORD)lpszIcon;
+ }
+
+ if (hRsrc = FindResource (hInst, (LPCSTR) IconId, MAKEINTRESOURCE(RT_ICON))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ lpByte = LockResource (hGbl);
+ }
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ ul = WOWLoadCursorIcon (hInst, lpszIcon, lpByte, ResSize, hGbl, WinVer, RT_ICON);
+
+ GlobalUnlock (hGbl);
+ }
+ }
+
+ return (ul);
+}
+
+
+HCURSOR API ILoadCursor (HINSTANCE hInst, LPCSTR lpszCursor)
+{
+ HRSRC hRsrc;
+ HGLOBAL hGbl;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ HCURSOR ul;
+ DWORD CursorId;
+ WORD WinVer;
+
+ ICONCUR16 IconCur;
+
+ WinVer = GetExpWinVer (hInst);
+
+ if (!(hInst = CheckDispHandle (hInst))) {
+ ul = WOWLoadCursorIcon (hInst, lpszCursor, lpByte, ResSize, NULL, WinVer, RT_CURSOR);
+ }
+ else {
+ IconCur.hInst = (WORD) hInst;
+ IconCur.lpStr = (DWORD) lpszCursor;
+
+ if (!(ul = (HICON) NotifyWOW (FUN_LOADCURSOR, (LPBYTE) &IconCur))) {
+ if (WinVer >= VER30) {
+ if (hRsrc = FindResource (hInst, lpszCursor, MAKEINTRESOURCE((UINT)RT_GROUP_CURSOR))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ lpByte = LockResource (hGbl);
+ }
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ CursorId = WOWGetIdFromDirectory ((LPBYTE)lpByte, (WORD) RT_CURSOR);
+
+ GlobalUnlock (hGbl);
+ }
+ else {
+ CursorId = (DWORD)lpszCursor;
+ }
+
+ if (hRsrc = FindResource (hInst, (LPCSTR) CursorId, MAKEINTRESOURCE(RT_CURSOR))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ if (lpByte = LockResource (hGbl))
+ WinVer = GetExpWinVer (hInst);
+ }
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ ul = WOWLoadCursorIcon (hInst, lpszCursor, lpByte, ResSize, hGbl, WinVer, RT_CURSOR);
+
+ GlobalUnlock (hGbl);
+ }
+ }
+
+ return (ul);
+}
+
+
+
+HWND API ICreateDialogParam (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc, LPARAM lParamInit)
+{
+ HRSRC hRsrc;
+ HGLOBAL hGbl;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ HWND ul;
+
+ if (hRsrc = FindResource (hInst, lpszDlgTemp, (LPCSTR) MAKEINTRESOURCE(RT_DIALOG))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ lpByte = LockResource (hGbl);
+ }
+
+ if (!lpByte) {
+ return (NULL);
+ }
+
+ ul = (HWND) WOWDialogBoxParam (hInst, lpByte, hwndOwner,
+ dlgprc, lParamInit, ResSize, FALSE);
+
+ if (hInst) {
+ GlobalUnlock (hGbl);
+ }
+
+ return (ul);
+}
+
+HWND API ICreateDialog (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc)
+{
+ return (ICreateDialogParam (hInst, lpszDlgTemp, hwndOwner, dlgprc, 0L));
+}
+
+
+HWND API ICreateDialogIndirectParam (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc, LPARAM lParamInit)
+{
+ return WOWDialogBoxParam (hInst, (LPBYTE)lpszDlgTemp, hwndOwner,
+ dlgprc, lParamInit, 0, FALSE);
+}
+
+HWND API ICreateDialogIndirect (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc)
+{
+ return WOWDialogBoxParam (hInst, (LPBYTE)lpszDlgTemp, hwndOwner,
+ dlgprc, 0, 0, FALSE);
+}
+
+int API IDialogBoxParam (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc, LPARAM lParamInit)
+{
+ HRSRC hRsrc;
+ HGLOBAL hGbl;
+ DWORD ResSize = 0;
+ LPBYTE lpByte = (LPBYTE) NULL;
+ int ul;
+
+ if (hRsrc = FindResource (hInst, lpszDlgTemp, MAKEINTRESOURCE(RT_DIALOG))) {
+ if (ResSize = SizeofResource (hInst, hRsrc))
+ if (hGbl = LoadResource (hInst, hRsrc))
+ lpByte = LockResource (hGbl);
+ }
+
+ if (!lpByte) {
+ return (-1);
+ }
+
+ ul = (int)WOWDialogBoxParam (hInst, lpByte, hwndOwner, dlgprc,
+ lParamInit, ResSize, TRUE);
+
+ if (hInst) {
+ GlobalUnlock (hGbl);
+ }
+
+ return (ul);
+}
+
+
+int API IDialogBox (HINSTANCE hInst, LPCSTR lpszDlgTemp, HWND hwndOwner, DLGPROC dlgprc)
+{
+ return (IDialogBoxParam (hInst, lpszDlgTemp, hwndOwner, dlgprc, 0L));
+}
+
+
+int API IDialogBoxIndirectParam (HINSTANCE hInst, HGLOBAL hGbl, HWND hwndOwner, DLGPROC dlgprc, LPARAM lParamInit)
+{
+ DWORD ResSize;
+ LPBYTE lpByte;
+ int ul;
+
+ if (lpByte = LockResource (hGbl)) {
+ ResSize = GlobalSize(hGbl);
+ ul = (int)WOWDialogBoxParam (hInst, lpByte, hwndOwner, dlgprc,
+ lParamInit, ResSize, TRUE);
+ GlobalUnlock (hGbl);
+ }
+ else {
+ ul = -1;
+ }
+
+ return (ul);
+}
+
+
+int API IDialogBoxIndirect(HINSTANCE hInst, HGLOBAL hGbl, HWND hwndOwner, DLGPROC dlgprc)
+{
+ return IDialogBoxIndirectParam (hInst, hGbl, hwndOwner, dlgprc, 0);
+}
+
+HANDLE API SetClipboardData (UINT cbformat, HANDLE hMem)
+{
+ HANDLE ul;
+ LPMETAFILEPICT lpMf;
+
+ switch (cbformat) {
+
+ case CF_DSPMETAFILEPICT:
+ case CF_METAFILEPICT:
+ if (hMem) {
+ lpMf = (LPMETAFILEPICT) GlobalLock(hMem);
+ if (lpMf) {
+
+ /* If the handle is bad make hMF = NULL. This is needed
+ * for Micrograpfx. They don't check for failure when rendering
+ * data
+ */
+
+ if (!(GlobalReAlloc (lpMf->hMF, 0L, GMEM_MODIFY | GMEM_SHARE))) {
+ lpMf->hMF = NULL;
+ }
+ }
+ GlobalUnlock(hMem);
+ }
+
+
+ // It is intentional to let it thru to the "case statements".
+ // ChandanC 5/11/92.
+
+
+/*
+* These are the defaults.
+*
+* 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:
+*/
+
+ default:
+ if (hMem) {
+ hMem = GlobalReAlloc (hMem, 0L, GMEM_MODIFY | GMEM_DDESHARE);
+ }
+ break;
+
+ case CF_DSPBITMAP:
+ case CF_BITMAP:
+ case CF_PALETTE:
+ break;
+
+ }
+
+ ul = WOWSetClipboardData (cbformat, hMem);
+ return (ul);
+}
diff --git a/private/mvdm/wow16/user/helpcall.c b/private/mvdm/wow16/user/helpcall.c
new file mode 100644
index 000000000..f599d2358
--- /dev/null
+++ b/private/mvdm/wow16/user/helpcall.c
@@ -0,0 +1,301 @@
+/*****************************************************************************
+* *
+* HELPCALL.C *
+* *
+* Copyright (C) Microsoft Corporation 1989. *
+* All Rights reserved. *
+* *
+******************************************************************************
+* *
+* Program Description: Sample interface to windows help *
+* *
+******************************************************************************
+* *
+* Revision History: Created by RKB 11/30/88 *
+* Revised to new API 1/12/88 (RKB) *
+* Added to USER 3/28/89 (BG) *
+* Slight update 6/15/89 (BG) *
+* Clean ugly code 10/30/89 (BG) *
+* GlobalFree if QUIT 1/26/90 (CRC) *
+* *
+******************************************************************************
+*/
+
+#define NO_REDEF_SENDMESSAGE
+#include "user.h"
+
+//
+// We define certain things here because including mvdm\inc\*.h files here
+// will lead to endless mess.
+//
+
+#define WM_WINHELP 0x38
+DWORD API NotifyWow(WORD, LPBYTE);
+#define FUN_WINHELP 171 //
+
+WORD msgWinHelp = 0;
+char CODESEG szMS_WINHELP[] = "MS_WINHELP";
+
+
+/*
+
+Communicating with WinHelp involves using Windows SendMessage() function
+to pass blocks of information to WinHelp. The call looks like.
+
+ SendMessage(hwndHelp, msgWinHelp, hwndMain, (LONG)hHlp);
+
+Where:
+
+ hwndHelp - the window handle of the help application. This
+ is obtained by enumerating all the windows in the
+ system and sending them HELP_FIND commands. The
+ application may have to load WinHelp.
+ msgWinHelp - the value obtained from a RegisterWindowMessage()
+ szWINHELP
+ hwndMain - the handle to the main window of the application
+ calling help
+ hHlp - a handle to a block of data with a HLP structure
+ at it head.
+
+The data in the handle will look like:
+
+ +-------------------+
+ | cbData |
+ | usCommand |
+ | ulTopic |
+ | ulReserved |
+ | offszHelpFile |\ - offsets measured from beginning
+ / | offaData | \ of header.
+ / +-------------------| /
+ / | Help file name |/
+ \ | and path |
+ \ +-------------------+
+ \ | Other data |
+ | (keyword) |
+ +-------------------+
+
+The defined commands are:
+
+ HELP_CONTEXT 0x0001 Display topic in ulTopic
+ HELP_KEY 0x0101 Display topic for keyword in offabData
+ HELP_QUIT 0x0002 Terminate help
+
+*/
+
+
+/*******************
+**
+** Name: HFill
+**
+** Purpose: Builds a data block for communicating with help
+**
+** Arguments: lpszHelp - pointer to the name of the help file to use
+** usCommand - command being set to help
+** ulData - data for the command
+**
+** Returns: a handle to the data block or hNIL if the the
+** block could not be created.
+**
+*******************/
+
+
+HANDLE HFill(LPCSTR lpszHelp, WORD usCommand, DWORD ulData)
+{
+ WORD cb; /* Size of the data block */
+ HANDLE hHlp; /* Handle to return */
+ BYTE bHigh; /* High byte of usCommand */
+ LPHLP qhlp; /* Pointer to data block */
+ /* Calculate size */
+ if (lpszHelp)
+ cb = sizeof(HLP) + lstrlen(lpszHelp) + 1;
+ else
+ cb = sizeof(HLP);
+
+ bHigh = (BYTE)HIBYTE(usCommand);
+
+ if (bHigh == 1)
+ cb += lstrlen((LPSTR)ulData) + 1;
+ else if (bHigh == 2)
+ cb += *((int far *)ulData);
+
+ /* Get data block */
+ if (!(hHlp = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)cb)))
+ return NULL;
+
+ if (!(qhlp = (LPHLP)GlobalLock(hHlp)))
+ {
+ GlobalFree(hHlp);
+ return NULL;
+ }
+
+ qhlp->cbData = cb; /* Fill in info */
+ qhlp->usCommand = usCommand;
+ qhlp->ulReserved = 0;
+ if (lpszHelp)
+ {
+ qhlp->offszHelpFile = sizeof(HLP);
+ lstrcpy((LPSTR)(qhlp+1), lpszHelp);
+ }
+ else
+ qhlp->offszHelpFile = 0;
+
+ switch(bHigh)
+ {
+ case 0:
+ qhlp->offabData = 0;
+ qhlp->ulTopic = ulData;
+ break;
+ case 1:
+ qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1;
+ lstrcpy((LPSTR)qhlp + qhlp->offabData, (LPSTR)ulData);
+ break;
+ case 2:
+ qhlp->offabData = sizeof(HLP) + lstrlen(lpszHelp) + 1;
+ LCopyStruct((LPSTR)ulData, (LPSTR)qhlp + qhlp->offabData, *((int far *)ulData));
+ break;
+ }
+
+ GlobalUnlock(hHlp);
+ return hHlp;
+ }
+
+
+
+char CODESEG szEXECHELP[] = "\\WINHELP -x";
+
+BOOL _fastcall LaunchHelper(LPSTR lpfile)
+{
+ int len;
+
+ len = lstrlen(lpfile);
+
+ if (lpfile[len-1]=='\\')
+ /* Are we at the root?? If so, skip over leading backslash in text
+ * string. */
+ lstrcat(lpfile, szEXECHELP+1);
+ else
+ lstrcat(lpfile, szEXECHELP);
+
+ return ((HINSTANCE)WinExec(lpfile, SW_SHOW) > HINSTANCE_ERROR);
+}
+
+
+BOOL LaunchHelp(VOID)
+{
+ char szFile[128];
+
+ /* Search in windows directory */
+ GetWindowsDirectory(szFile, sizeof(szFile));
+ if (LaunchHelper(szFile))
+ return(TRUE);
+
+ /* Search system directory */
+ GetSystemDirectory(szFile, sizeof(szFile));
+ if (LaunchHelper(szFile))
+ return(TRUE);
+
+ /* Last ditch: simply let dos do it */
+ lstrcpy(szFile, szEXECHELP+1);
+ return ((HINSTANCE)WinExec(szFile, SW_SHOW) > HINSTANCE_ERROR);
+}
+
+
+/*******************
+**
+** Name: WinHelp
+**
+** Purpose: Displays help
+**
+** Arguments:
+** hwndMain handle to main window of application
+** lpszHelp path (if not current directory) and file
+** to use for help topic.
+** usCommand Command to send to help
+** ulData Data associated with command:
+** HELP_QUIT - no data (undefined)
+** HELP_LAST - no data (undefined)
+** HELP_CONTEXT - context number to display
+** HELP_KEY - string ('\0' terminated)
+** use as keyword to topic
+** to display
+** HELP_FIND - no data (undefined)
+**
+** Returns: TRUE iff success
+**
+*******************/
+
+BOOL API IWinHelp(hwndMain, lpszHelp, usCommand, ulData)
+HWND hwndMain;
+LPCSTR lpszHelp;
+WORD usCommand;
+DWORD ulData;
+{
+ register HANDLE hHlp;
+ DWORD dwHelpPid; /* loword is hwndHelp */
+ /* hiword TRUE if hwndHelp is of this process */
+
+ if (msgWinHelp == 0) {
+
+ /* Register private WinHelp message for communicating to WinHelp via
+ * WinHelp api.
+ */
+ char static CODESEG szWM_WINHELP[] = "WM_WINHELP";
+ msgWinHelp = RegisterWindowMessage(szWM_WINHELP);
+ }
+
+ /* Move Help file name to a handle */
+ if (!(hHlp = HFill(lpszHelp, usCommand, ulData)))
+ return(FALSE);
+
+ if ((dwHelpPid = (DWORD)NotifyWow(FUN_WINHELP, szMS_WINHELP)) == (DWORD)NULL)
+ {
+ if (usCommand == HELP_QUIT) /* Don't bother to load HELP just to*/
+ {
+ GlobalFree(hHlp);
+ return(TRUE);
+ }
+
+ /* Can't find it --> launch it */
+ if (!LaunchHelp() || ((dwHelpPid = (DWORD)NotifyWow(FUN_WINHELP, szMS_WINHELP)) == (DWORD)NULL))
+ {
+ /* Can't find help, or not enough memory to load help.*/
+ GlobalFree(hHlp);
+ return(FALSE);
+ }
+
+ }
+
+ // if winhelp.exe was launched from this process, normal sendmessage else
+ // we need to thunk the data across WOWVDM processes and the format is
+ // msg = WM_WINHELP, a private msg
+ // wparam = 0 instead of hwndMain, (note 1)
+ // lparam = LPHLP
+ //
+ // note 1: winhelp, calls GetWindowWord(wParam, GWW_HINSTANCE) when it receives HELP_QUIT
+ // command. If this matches a value in its table and is the only registered instance
+ // winhelp will close - this is quite ok undernormal circumstances (just one WOWVDM)
+ // but under multiple WOWVDM, numeric value of hinstances could be same for different
+ // hwnds.
+ //
+ // So we workaround this by passing a NULL hwnd in wParam and by not sending HELP_QUIT
+ // message - which effectively implies that WinHelp will close only if there are no
+ // references to it from the same WOWVDM (as itself).
+ //
+ // This is the best compromise I could comeup with for running "only one WinHelp for all
+ // WOWVDMs".
+ //
+ // - nanduri
+
+ if (HIWORD(dwHelpPid)) {
+ SendMessage((HWND)LOWORD(dwHelpPid), msgWinHelp, (WPARAM)hwndMain, MAKELPARAM(hHlp, 0));
+ }
+ else {
+ if (usCommand != HELP_QUIT) {
+ SendMessage((HWND)LOWORD(dwHelpPid), WM_WINHELP, (WPARAM)0, (LPARAM)GlobalLock(hHlp));
+ GlobalUnlock(hHlp);
+ }
+ }
+
+ GlobalFree(hHlp);
+ return(TRUE);
+}
diff --git a/private/mvdm/wow16/user/init.c b/private/mvdm/wow16/user/init.c
new file mode 100644
index 000000000..f4cbf3dd7
--- /dev/null
+++ b/private/mvdm/wow16/user/init.c
@@ -0,0 +1,200 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * INIT.C
+ * WOW16 user initialisation code
+ *
+ * History:
+ *
+ * Created 15-Apr-1991 by Nigel Thompson (nigelt)
+ *
+ * Revised 19-May-1991 by Jeff Parsons (jeffpar)
+ * IFDEF'ed everything, since everything was only needed by RMLOAD.C,
+ * and that has been largely IFDEF'ed as well (see RMLOAD.C for details)
+--*/
+
+#define FIRST_CALL_MUST_BE_USER_BUG
+
+#include "user.h"
+
+
+#define FUN_FINALUSERINIT 400 // Internal
+DWORD API NotifyWow(WORD, LPBYTE);
+VOID FAR PASCAL PatchUserStrRtnsToThunk(VOID);
+/***************************************************************************
+
+ global data items
+
+***************************************************************************/
+
+
+#ifdef NEEDED
+HDC hdcBits; // USER's general hdc
+OEMINFO oemInfo; // lots of interresting info
+#endif
+#ifdef FIRST_CALL_MUST_BE_USER_BUG
+HWND hwndDesktop; // handle to the desktop window
+#endif
+
+BOOL fThunkStrRtns; // if TRUE we thunk to Win32 (see winlang.asm)
+
+FARPROC LPCHECKMETAFILE;
+
+/***************************************************************************
+
+ initialisation routine
+
+***************************************************************************/
+
+int FAR PASCAL LibMain(HANDLE hInstance)
+{
+#ifdef NEEDED
+ HDC hDC;
+#endif
+ HANDLE hLib;
+
+ dprintf(3,"Initializing...");
+
+ // Notify the hInstance of USER to wow32. the index FUN_FINALUSERINIT is
+ // just an existing index - no need to define new index.
+ // - Nanduri
+ //
+ // Overload this to return the ANSI code page from Win32 GetACP.
+ // - DaveHart 5-May-94
+ //
+
+ {
+#ifdef PMODE32
+ extern _cdecl wow16gpsi(void);
+ extern _cdecl wow16CsrFlag(void);
+#endif
+ WORD wCS;
+ extern WORD MaxDWPMsg;
+ extern BYTE DWPBits[1];
+ extern WORD cbDWPBits;
+
+ struct {
+ WORD hInstance;
+ LPSTR FAR *lpgpsi;
+ LPSTR FAR *lpCallCsrFlag;
+ DWORD dwBldInfo;
+ LPWORD lpwMaxDWPMsg;
+ LPSTR lpDWPBits;
+ WORD cbDWPBits;
+ } UserInit16;
+
+ UserInit16.hInstance = (WORD)hInstance;
+#ifdef PMODE32
+ UserInit16.lpgpsi = (LPSTR *)wow16gpsi;
+ UserInit16.lpCallCsrFlag = (LPSTR *)wow16CsrFlag;
+#else
+ UserInit16.lpgpsi = (LPSTR *)0;
+ UserInit16.lpCallCsrFlag = (LPSTR *)0;
+#endif
+
+#ifdef WOWDBG
+ UserInit16.dwBldInfo = (((DWORD)WOW) << 16) | 0x80000000;
+#else
+ UserInit16.dwBldInfo = (((DWORD)WOW) << 16);
+#endif
+
+ _asm mov wCS, cs;
+ UserInit16.lpwMaxDWPMsg = (LPWORD) MAKELONG((WORD)&MaxDWPMsg, wCS);
+ UserInit16.lpDWPBits = (LPBYTE) MAKELONG((WORD)&DWPBits[0], wCS);
+ UserInit16.cbDWPBits = *(LPWORD) MAKELONG((WORD)&cbDWPBits, wCS);
+
+ fThunkStrRtns = NotifyWow(FUN_FINALUSERINIT, (LPBYTE)&UserInit16);
+
+ //
+ // fThunkStrRtns defaults to TRUE outside the U.S. English
+ // locale and FALSE in the U.S. English locale. If we are
+ // thunking, patch the exported U.S. implementations to simply
+ // near jmp to the equivalent thunk.
+ //
+
+ if (fThunkStrRtns) {
+ PatchUserStrRtnsToThunk();
+ }
+ }
+
+#ifdef FIRST_CALL_MUST_BE_USER_BUG
+ // get the desktop window handle
+
+ WinEval(hwndDesktop = GetDesktopWindow());
+#endif
+
+
+#ifdef NEEDED
+
+ // create a compatible dc we can use for general bitmap stuff
+
+ WinEval(hDC = GetDC(hwndDesktop));
+ WinEval(hdcBits = CreateCompatibleDC(hDC));
+
+ // fill in the oemInfo structure
+ // NOTE: We only fill in the bits we need for WOW not all of it
+
+ oemInfo.cxIcon = GetSystemMetrics(SM_CXICON);
+ oemInfo.cyIcon = GetSystemMetrics(SM_CYICON);
+ oemInfo.cxCursor = GetSystemMetrics(SM_CXCURSOR);
+ oemInfo.cyCursor = GetSystemMetrics(SM_CYCURSOR);
+ oemInfo.ScreenBitCount = GetDeviceCaps(hDC, BITSPIXEL)
+ * GetDeviceCaps(hDC, PLANES);
+ oemInfo.DispDrvExpWinVer= GetVersion();
+
+
+ ReleaseDC(hwndDesktop, hDC);
+
+#endif
+
+ hLib = LoadLibrary( "gdi.exe" );
+ LPCHECKMETAFILE = GetProcAddress( hLib, "CHECKMETAFILE" );
+
+ LoadString(hInstanceWin, STR_SYSERR, szSysError, 20);
+ LoadString(hInstanceWin, STR_DIVBYZERO,szDivZero, 50);
+
+ dprintf(3,"Initialisation complete");
+
+ return TRUE;
+}
+
+/***************************************************************************
+
+ debugging support
+
+***************************************************************************/
+
+
+#ifdef DEBUG
+
+void cdecl dDbgOut(int iLevel, LPSTR lpszFormat, ...)
+{
+ char buf[256];
+ int iLogLevel;
+ char far *lpcLogLevel;
+
+ // Get the external logging level from the emulated ROM
+
+ iLogLevel = 0;
+ (LONG)lpcLogLevel = 0x00400042;
+ if (*lpcLogLevel >= '0' && *lpcLogLevel <= '9')
+ iLogLevel = (*lpcLogLevel-'0')*10+(*(lpcLogLevel+1)-'0');
+
+ if (iLevel==iLogLevel && (iLogLevel&1) || iLevel<=iLogLevel && !(iLogLevel&1)) {
+ OutputDebugString(" W16USER:");
+ wvsprintf(buf, lpszFormat, (LPSTR)(&lpszFormat + 1));
+ OutputDebugString(buf);
+ OutputDebugString("\r\n");
+ }
+}
+
+void cdecl dDbgAssert(LPSTR exp, LPSTR file, int line)
+{
+ dDbgOut(0, "Assertion FAILED in file %s, line %d: %s\n",
+ (LPSTR)file, line, (LPSTR)exp);
+}
+
+#endif
diff --git a/private/mvdm/wow16/user/intds.asm b/private/mvdm/wow16/user/intds.asm
new file mode 100644
index 000000000..2a3dc5ad1
--- /dev/null
+++ b/private/mvdm/wow16/user/intds.asm
@@ -0,0 +1,188 @@
+;****************************************************************************
+;
+; This file contains all global data that must be modified at interrupt
+; level. Everthing in this file is placed in a fixed data segment
+; named INTDATA. Only things that must be accessed and modified at
+; interrupt level may be placed in this file. All values here must be
+; referenced as FAR in the code.
+;
+; The creation of this segment allowed USER to eliminate all code segment
+; variables. This was needed for protect mode as well as moving USER's
+; text segment into HIMEM.
+;****************************************************************************
+
+NOEXTERNS = 1
+.xlist
+include user.inc
+.list
+
+
+createSeg _INTDS, INTDS, BYTE, PUBLIC, DATA
+
+sBegin INTDS
+
+GlobalW hqSysQueue, 00h
+
+ifndef WOW
+
+GlobalW fMouseMoved, 00h
+;; GlobalB fAltKeyUp, 80h ; no longer used
+
+GlobalW fInt24 00h ; used for INT24 detection in NCMOUSEDOWN
+
+;
+; For Asynchronous key state information.
+;
+public rgbAsyncKeyState
+rgbAsyncKeyState db 64 DUP(0) ; 512 bits of information, 2 per key.
+
+GlobalW fEnableInput, TRUE
+
+endif ; !WOW
+
+GlobalW hqSysModal, 0 ; hq of system modal window
+
+ifndef WOW
+
+;
+; These are for the code that always keeps enough room for KEYUP/MOUSEUP msgs.
+;
+GlobalW cMsgRsrv, 0
+GlobalB vKeyDown, 0
+
+;
+; Mouse Code Variables
+;
+GlobalW x_mickey_rate, 0 ; mickeys/pixel ratio for x
+GlobalW y_mickey_rate, 0 ; mickeys/pixel ratio for y
+GlobalW cur_x_mickey, 0 ; current mickey count in x
+GlobalW cur_y_mickey, 0 ; current mickey count in y
+GlobalW fSwapButtons, 0 ; TRUE if L/R are to be swapped.
+
+public ptTrueCursor
+ptTrueCursor POINT <0, 0> ; interrupt-level cursor position
+
+public ptCursor
+ptCursor POINT <0, 0> ; cursor position as of last SkipSysMsg
+
+public rcCursorClip
+rcCursorClip RECT <0, 0, 0, 0>
+
+GlobalD dwMouseMoveExtraInfo, 0 ; Extra info for deferred MOUSE MOVE msgs
+
+;
+; CS copies of cxScreen, cyScreen for abs mouse scaling
+;
+GlobalW cxScreenCS, 0
+GlobalW cyScreenCS, 0
+
+;
+; These are CS copies of msInfo.msXThresh & msYThresh
+; (copied at initialization)
+;
+GlobalW MouseThresh1,0
+GlobalW MouseThresh2,0
+GlobalW MouseSpeed, 0 ;0 - no accel, 1 - singel accel, 2 - dual accel
+
+ifndef PMODE
+;
+; Mouse interrupt stack
+;
+public lpMouseStack
+public prevSSSP
+public NestCount
+endif
+
+lpMouseStack dd ?
+prevSSSP dd ? ;Previous stack when inside our hook
+NestCount db 0
+
+;
+; Hardware level (interrupt) hook addresse. Called from event proc's
+;
+
+GlobalW fJournalPlayback, 0 ; != 0 if WH_JOURNALPLAYBACK hook installed
+
+; Table of interrupt-level hotkey hooks
+
+GlobalW cHotKeyHooks, 0
+
+public rghkhHotKeyHooks
+rghkhHotKeyHooks dw CHOTKEYHOOKMAX * (size HOTKEYHOOK)/2 dup (0)
+
+; Hardware event hook
+
+GlobalD hwEventHook, NULL
+
+endif ; !WOW
+
+
+;
+; Q management.
+;
+GlobalW hqList, 0 ; list of allocated queues
+GlobalW hqCursor, 0 ; hq of window under cursor
+GlobalW hqCapture, 0 ; hq of capture
+GlobalW hqActive, 0 ; hq of active window
+GlobalW hqMouse, 0 ; hq last to get mouse msg
+GlobalW hqKeyboard, 0 ; hq last to get kbd msg
+GlobalW cQEntries, 120 ; System queue size
+GlobalW hqSysLock 0 ; HQ of guy looking at the current event
+GlobalW idSysLock 0ffffh ; Msg ID of event that's locking sys queue
+
+
+ifndef WOW
+
+;
+; Timer management
+;
+public timerInfo
+timerInfo STIMERINFO <0>
+;
+; Timer related stuff
+;
+public TimerTable
+TimerTable dw (size TIMER)/2 * CTIMERSMAX dup (0)
+
+GlobalW hSysTimer, 0 ; system timer handle
+GlobalD tSysTimer, 0 ; system timer time
+GlobalW dtSysTimer, 0 ; delta time before next timer goes off
+GlobalB fInScanTimers, 0 ; flag to prevent ScanTimers recursion
+GlobalW TimerTableMax, 0 ; end of active timer entries
+
+;
+; Journalling stuff
+;
+GlobalD dtJournal, 0 ; dt till next event is ready
+GlobalW msgJournal, 0 ; next journal message.
+
+;
+; Used in SaveEvent()
+;
+GlobalB fDontMakeAltUpASysKey 0 ; whether any intervening chars have arrived
+
+
+;*--------------------------------------------------------------------------*
+;* Internal Strings *
+;*--------------------------------------------------------------------------*
+
+; These strings reside in user.rc but are loaded at boot time. They must
+; remain in user.rc for localization reasons.
+
+endif ; !WOW
+
+public szSysError
+public szDivZero
+szSysError db 20 DUP(0) ; "System Error"
+szDivZero db 50 DUP(0) ; "Divide By Zero or Overflow Error"
+
+ifndef WOW
+
+public szNull
+szNull db 0,13
+
+endif ; !WOW
+
+sEnd INTDS
+
+end
diff --git a/private/mvdm/wow16/user/inuserds.c b/private/mvdm/wow16/user/inuserds.c
new file mode 100644
index 000000000..d88f17c3b
--- /dev/null
+++ b/private/mvdm/wow16/user/inuserds.c
@@ -0,0 +1,43 @@
+/****************************************************************************/
+/* */
+/* INUSERDS - */
+/* */
+/* User's DS Global Variables */
+/* */
+/****************************************************************************/
+
+#include "user.h"
+
+//***** Initialization globals
+
+HINSTANCE hInstanceWin = NULL;
+HMODULE hModuleWin = NULL;
+
+
+//***** Comm driver globals
+
+int (FAR PASCAL *lpCommWriteString)(int, LPCSTR, WORD);
+ /* Ptr to the comm driver's
+ * commwritestring function. Only
+ * exists in 3.1 drivers.
+ */
+int (FAR PASCAL *lpCommReadString)(int, LPSTR, WORD);
+ /* Ptr to the comm driver's
+ * commreadstring function. Only
+ * exists in 3.1 drivers.
+ */
+BOOL (FAR PASCAL *lpCommEnableNotification)(int, HWND, int, int);
+ /* Ptr to the comm driver's
+ * commwritestring function. Only
+ * exists in 3.1 drivers.
+ */
+//***** PenWindows globals
+
+void (CALLBACK *lpRegisterPenAwareApp)(WORD i, BOOL fRegister) = NULL; /* Register dlg box as pen aware */
+
+//***** Driver management globals
+
+int cInstalledDrivers =0; /* Count of installed driver structs allocated*/
+HDRVR hInstalledDriverList =NULL; /* List of installable drivers */
+int idFirstDriver=-1; /* First driver in load order */
+int idLastDriver=-1; /* Last driver in load order */
diff --git a/private/mvdm/wow16/user/iuser.h b/private/mvdm/wow16/user/iuser.h
new file mode 100644
index 000000000..85e349233
--- /dev/null
+++ b/private/mvdm/wow16/user/iuser.h
@@ -0,0 +1,219 @@
+//--------------------
+// Function prototypes
+
+#define GetMessage IGetMessage
+#define TranslateMessage ITranslateMessage
+#define DispatchMessage IDispatchMessage
+#define PeekMessage IPeekMessage
+#define lstrcmp Ilstrcmp
+#define lstrcmpi Ilstrcmpi
+#define SetSysModalWindow ISetSysModalWindow
+// #define SendMessage ISendMessage
+#define PostMessage IPostMessage
+#define PostAppMessage IPostAppMessage
+#define CallWindowProc ICallWindowProc
+#define IsChild IIsChild
+#define IsWindowVisible IIsWindowVisible
+#define IsIconic IIsIconic
+#define CallMsgFilter ICallMsgFilter
+#define GetKeyboardState IGetKeyboardState
+#define SetKeyboardState ISetKeyboardState
+// #define SetCapture ISetCapture
+#define GetQueueStatus IGetQueueStatus
+#define SetTimer ISetTimer
+#define KillTimer IKillTimer
+#define IsWindowEnabled IIsWindowEnabled
+#define GetSystemMetrics IGetSystemMetrics
+#define GetMenu IGetMenu
+#define GetMenuState IGetMenuState
+#define DrawMenuBar IDrawMenuBar
+#define DestroyMenu IDestroyMenu
+#define CheckMenuItem ICheckMenuItem
+#define EnableMenuItem IEnableMenuItem
+#define GetSubMenu IGetSubMenu
+#define GetMenuItemID IGetMenuItemID
+#define SetActiveWindow ISetActiveWindow
+#define BeginPaint IBeginPaint
+#define InvalidateRect IInvalidateRect
+#define ValidateRect IValidateRect
+#define InvalidateRgn IInvalidateRgn
+#define ValidateRgn IValidateRgn
+#define SetWindowText ISetWindowText
+#define GetWindowText IGetWindowText
+#define GetWindowTextLength IGetWindowTextLength
+#define GetClientRect IGetClientRect
+#define GetWindowRect IGetWindowRect
+#define GetCursorPos IGetCursorPos
+#define ClipCursor IClipCursor
+#define GetClipCursor IGetClipCursor
+#define ClientToScreen IClientToScreen
+#define ScreenToClient IScreenToClient
+#define DefDlgProc IDefDlgProc
+#define GetSysColor IGetSysColor
+#define DrawFocusRect IDrawFocusRect
+#define FillRect IFillRect
+#define FrameRect IFrameRect
+#define InvertRect IInvertRect
+#define SetRect ISetRect
+#define SetRectEmpty ISetRectEmpty
+#define CopyRect ICopyRect
+#define InflateRect IInflateRect
+#define IntersectRect IIntersectRect
+#define UnionRect IUnionRect
+#define SubtractRect ISubtractRect
+#define OffsetRect IOffsetRect
+#define IsRectEmpty IIsRectEmpty
+#define EqualRect IEqualRect
+#define PtInRect IPtInRect
+#define GetWindowWord IGetWindowWord
+#define SetWindowWord ISetWindowWord
+#define GetWindowLong IGetWindowLong
+#define SetWindowLong ISetWindowLong
+#define GetClassWord IGetClassWord
+#define SetClassWord ISetClassWord
+#define GetClassLong IGetClassLong
+#define SetClassLong ISetClassLong
+#define EnumTaskWindows IEnumTaskWindows
+#define MapWindowPoints IMapWindowPoints
+#define GetWindowTask IGetWindowTask
+#define SetWindowsHook ISetWindowsHook
+#define UnhookWindowsHook IUnhookWindowsHook
+#define DefHookProc IDefHookProc
+#define SetWindowsHookEx ISetWindowsHookEx
+#define UnhookWindowsHookEx IUnhookWindowsHookEx
+#define CallNextHookEx ICallNextHookEx
+
+#define DrawText IDrawText
+#define GetTabbedTextExtent IGetTabbedTextExtent
+#define TabbedTextOut ITabbedTextOut
+#define DrawIcon IDrawIcon
+#define GetWindowDC IGetWindowDC
+#define GetDC IGetDC
+#define ReleaseDC IReleaseDC
+#define GetDCEx IGetDCEx
+#define DefWindowProc IDefWindowProc
+#define RegisterClass IRegisterClass
+#define UnregisterClass IUnregisterClass
+#define GetClassInfo IGetClassInfo
+#define GetClassName IGetClassName
+#define GetNextQueueWindow IGetNextQueueWindow
+#define CreateWindowEx ICreateWindowEx
+#define DestroyWindow IDestroyWindow
+#define ShowWindow IShowWindow
+#define FlashWindow IFlashWindow
+#define ShowOwnedPopups IShowOwnedPopups
+#define OpenIcon IOpenIcon
+#define CloseWindow ICloseWindow
+#define MoveWindow IMoveWindow
+#define SetWindowPos ISetWindowPos
+#define DeferWindowPos IDeferWindowPos
+#define EndDeferWindowPos IEndDeferWindowPos
+#define CreateDialogParam ICreateDialogParam
+#define CreateDialogIndirectParam ICreateDialogIndirectParam
+// #define DialogBoxParam IDialogBoxParam
+#define DialogBoxIndirectParam IDialogBoxIndirectParam
+#define EndDialog IEndDialog
+#define GetDlgItem IGetDlgItem
+#define GetDlgItemInt IGetDlgItemInt
+#define SetDlgItemText ISetDlgItemText
+#define GetDlgItemText IGetDlgItemText
+#define CheckDlgButton ICheckDlgButton
+#define IsDlgButtonChecked IIsDlgButtonChecked
+#define SendDlgItemMessage ISendDlgItemMessage
+#define GetNextDlgGroupItem IGetNextDlgGroupItem
+#define GetNextDlgTabItem IGetNextDlgTabItem
+#define GetDlgCtrlID IGetDlgCtrlID
+#define OpenClipboard IOpenClipboard
+#define SetClipboardViewer ISetClipboardViewer
+#define ChangeClipboardChain IChangeClipboardChain
+#define GetPriorityClipboardFormat IGetPriorityClipboardFormat
+#define SetFocus ISetFocus
+#define EnableWindow IEnableWindow
+#define TranslateAccelerator ITranslateAccelerator
+#define LoadAccelerators ILoadAccelerators
+#define LoadMenu ILoadMenu
+#define LoadMenuIndirect ILoadMenuIndirect
+#define SetMenu ISetMenu
+#define ChangeMenu IChangeMenu
+#define HiliteMenuItem IHiliteMenuItem
+#define GetMenuString IGetMenuString
+#define GetSystemMenu IGetSystemMenu
+#define SetSystemMenu ISetSystemMenu
+#define GetMenuItemCount IGetMenuItemCount
+#define InsertMenu IInsertMenu
+#define AppendMenu IAppendMenu
+#define ModifyMenu IModifyMenu
+#define RemoveMenu IRemoveMenu
+#define DeleteMenu IDeleteMenu
+#define SetMenuItemBitmaps ISetMenuItemBitmaps
+#define TrackPopupMenu ITrackPopupMenu
+#define GrayString IGrayString
+#define UpdateWindow IUpdateWindow
+#define EndPaint IEndPaint
+#define GetUpdateRect IGetUpdateRect
+#define GetUpdateRgn IGetUpdateRgn
+#define ExcludeUpdateRgn IExcludeUpdateRgn
+#define RedrawWindow IRedrawWindow
+#define LockWindowUpdate ILockWindowUpdate
+#define ScrollDC IScrollDC
+#define ScrollWindowEx IScrollWindowEx
+#define SetScrollPos ISetScrollPos
+#define GetScrollPos IGetScrollPos
+#define SetScrollRange ISetScrollRange
+#define GetScrollRange IGetScrollRange
+#define ShowScrollBar IShowScrollBar
+#define EnableScrollBar IEnableScrollBar
+#define SetProp ISetProp
+#define GetProp IGetProp
+#define RemoveProp IRemoveProp
+#define EnumProps IEnumProps
+#define AdjustWindowRectEx IAdjustWindowRectEx
+#define MessageBox IMessageBox
+#define SetCursor ISetCursor
+#define CreateCaret ICreateCaret
+#define HideCaret IHideCaret
+#define ShowCaret IShowCaret
+#define ChildWindowFromPoint IChildWindowFromPoint
+#define SetSysColors ISetSysColors
+#define GetParent IGetParent
+#define SetParent ISetParent
+#define EnumChildWindows IEnumChildWindows
+#define FindWindow IFindWindow
+#define EnumWindows IEnumWindows
+#define GetTopWindow IGetTopWindow
+#define GetLastActivePopup IGetLastActivePopup
+#define GetWindow IGetWindow
+#define InvalidateDCCache InvalidateDCCache
+#define LoadBitmap ILoadBitmap
+#define LoadCursor ILoadCursor
+#define CreateCursor ICreateCursor
+#define DestroyCursor IDestroyCursor
+#define LoadIcon ILoadIcon
+#define CreateIcon ICreateIcon
+#define DestroyIcon IDestroyIcon
+#define LoadString ILoadString
+#define IsDialogMessage IIsDialogMessage
+#define MapDialogRect IMapDialogRect
+#define DlgDirList IDlgDirList
+#define DlgDirSelect IDlgDirSelect
+#define DlgDirSelectEx IDlgDirSelectEx
+#define DlgDirListComboBox IDlgDirListComboBox
+#define DlgDirSelectComboBox IDlgDirSelectComboBox
+#define DlgDirSelectComboBoxEx IDlgDirSelectComboBoxEx
+#define DefFrameProc IDefFrameProc
+#define DefMDIChildProc IDefMDIChildProc
+#define TranslateMDISysAccel ITranslateMDISysAccel
+#define ArrangeIconicWindows IArrangeIconicWindows
+#define SystemParametersInfo ISystemParametersInfo
+#define WinHelp IWinHelp
+#define OpenDriver IOpenDriver
+#define CloseDriver ICloseDriver
+#define GetDriverModuleHandle IGetDriverModuleHandle
+#define SendDriverMessage ISendDriverMessage
+#define DefDriverProc IDefDriverProc
+#define GetNextDriver IGetNextDriver
+#define GetDriverInfo IGetDriverInfo
+#define SelectPalette ISelectPalette
+#define RealizePalette IRealizePalette
+#define wsprintf Iwsprintf
+#define wvsprintf Iwvsprintf
diff --git a/private/mvdm/wow16/user/iuser.inc b/private/mvdm/wow16/user/iuser.inc
new file mode 100644
index 000000000..07669bba5
--- /dev/null
+++ b/private/mvdm/wow16/user/iuser.inc
@@ -0,0 +1,216 @@
+GetMessage equ <IGetMessage>
+TranslateMessage equ <ITranslateMessage>
+DispatchMessage equ <IDispatchMessage>
+PeekMessage equ <IPeekMessage>
+lstrcmp equ <Ilstrcmp>
+lstrcmpi equ <Ilstrcmpi>
+SetSysModalWindow equ <ISetSysModalWindow>
+SendMessage equ <ISendMessage>
+PostMessage equ <IPostMessage>
+PostAppMessage equ <IPostAppMessage>
+CallWindowProc equ <ICallWindowProc>
+;IsChild equ <IIsChild>
+;IsWindowVisible equ <IIsWindowVisible>
+;IsIconic equ <IIsIconic>
+CallMsgFilter equ <ICallMsgFilter>
+GetKeyboardState equ <IGetKeyboardState>
+SetKeyboardState equ <ISetKeyboardState>
+SetCapture equ <ISetCapture>
+;GetQueueStatus equ <IGetQueueStatus>
+SetTimer equ <ISetTimer>
+KillTimer equ <IKillTimer>
+;IsWindowEnabled equ <IIsWindowEnabled>
+GetSystemMetrics equ <IGetSystemMetrics>
+GetMenu equ <IGetMenu>
+GetMenuState equ <IGetMenuState>
+DrawMenuBar equ <IDrawMenuBar>
+DestroyMenu equ <IDestroyMenu>
+CheckMenuItem equ <ICheckMenuItem>
+EnableMenuItem equ <IEnableMenuItem>
+GetSubMenu equ <IGetSubMenu>
+GetMenuItemID equ <IGetMenuItemID>
+SetActiveWindow equ <ISetActiveWindow>
+BeginPaint equ <IBeginPaint>
+InvalidateRect equ <IInvalidateRect>
+ValidateRect equ <IValidateRect>
+InvalidateRgn equ <IInvalidateRgn>
+ValidateRgn equ <IValidateRgn>
+SetWindowText equ <ISetWindowText>
+GetWindowText equ <IGetWindowText>
+GetWindowTextLength equ <IGetWindowTextLength>
+;GetClientRect equ <IGetClientRect>
+;GetWindowRect equ <IGetWindowRect>
+GetCursorPos equ <IGetCursorPos>
+ClipCursor equ <IClipCursor>
+GetClipCursor equ <IGetClipCursor>
+;ClientToScreen equ <IClientToScreen>
+;ScreenToClient equ <IScreenToClient>
+;GetSysColor equ <IGetSysColor>
+DrawFocusRect equ <IDrawFocusRect>
+FillRect equ <IFillRect>
+FrameRect equ <IFrameRect>
+InvertRect equ <IInvertRect>
+;SetRect equ <ISetRect>
+;SetRectEmpty equ <ISetRectEmpty>
+;CopyRect equ <ICopyRect>
+;InflateRect equ <IInflateRect>
+;IntersectRect equ <IIntersectRect>
+;UnionRect equ <IUnionRect>
+;SubtractRect equ <ISubtractRect>
+;OffsetRect equ <IOffsetRect>
+;IsRectEmpty equ <IIsRectEmpty>
+;EqualRect equ <IEqualRect>
+;PtInRect equ <IPtInRect>
+;GetWindowWord equ <IGetWindowWord>
+SetWindowWord equ <ISetWindowWord>
+;GetWindowLong equ <IGetWindowLong>
+SetWindowLong equ <ISetWindowLong>
+GetClassWord equ <IGetClassWord>
+SetClassWord equ <ISetClassWord>
+GetClassLong equ <IGetClassLong>
+SetClassLong equ <ISetClassLong>
+EnumTaskWindows equ <IEnumTaskWindows>
+;MapWindowPoints equ <IMapWindowPoints>
+GetWindowTask equ <IGetWindowTask>
+SetWindowsHook equ <ISetWindowsHook>
+UnhookWindowsHook equ <IUnhookWindowsHook>
+DefHookProc equ <IDefHookProc>
+SetWindowsHookEx equ <ISetWindowsHookEx>
+UnhookWindowsHookEx equ <IUnhookWindowsHookEx>
+CallNextHookEx equ <ICallNextHookEx>
+
+DrawText equ <IDrawText>
+GetTabbedTextExtent equ <IGetTabbedTextExtent>
+TabbedTextOut equ <ITabbedTextOut>
+DrawIcon equ <IDrawIcon>
+GetWindowDC equ <IGetWindowDC>
+GetDC equ <IGetDC>
+ReleaseDC equ <IReleaseDC>
+GetDCEx equ <IGetDCEx>
+DefWindowProc equ <IDefWindowProc>
+RegisterClass equ <IRegisterClass>
+UnregisterClass equ <IUnregisterClass>
+GetClassInfo equ <IGetClassInfo>
+GetClassName equ <IGetClassName>
+GetNextQueueWindow equ <IGetNextQueueWindow>
+CreateWindowEx equ <ICreateWindowEx>
+DestroyWindow equ <IDestroyWindow>
+ShowWindow equ <IShowWindow>
+FlashWindow equ <IFlashWindow>
+ShowOwnedPopups equ <IShowOwnedPopups>
+OpenIcon equ <IOpenIcon>
+CloseWindow equ <ICloseWindow>
+MoveWindow equ <IMoveWindow>
+SetWindowPos equ <ISetWindowPos>
+DeferWindowPos equ <IDeferWindowPos>
+EndDeferWindowPos equ <IEndDeferWindowPos>
+CreateDialogParam equ <ICreateDialogParam>
+CreateDialogIndirectParam equ <ICreateDialogIndirectParam>
+DialogBoxParam equ <IDialogBoxParam>
+DialogBoxIndirectParam equ <IDialogBoxIndirectParam>
+EndDialog equ <IEndDialog>
+GetDlgItem equ <IGetDlgItem>
+GetDlgItemInt equ <IGetDlgItemInt>
+SetDlgItemText equ <ISetDlgItemText>
+GetDlgItemText equ <IGetDlgItemText>
+CheckDlgButton equ <ICheckDlgButton>
+IsDlgButtonChecked equ <IIsDlgButtonChecked>
+SendDlgItemMessage equ <ISendDlgItemMessage>
+GetNextDlgGroupItem equ <IGetNextDlgGroupItem>
+GetNextDlgTabItem equ <IGetNextDlgTabItem>
+GetDlgCtrlID equ <IGetDlgCtrlID>
+DefDlgProc equ <IDefDlgProc>
+OpenClipboard equ <IOpenClipboard>
+SetClipboardViewer equ <ISetClipboardViewer>
+ChangeClipboardChain equ <IChangeClipboardChain>
+GetPriorityClipboardFormat equ <IGetPriorityClipboardFormat>
+SetFocus equ <ISetFocus>
+EnableWindow equ <IEnableWindow>
+TranslateAccelerator equ <ITranslateAccelerator>
+LoadAccelerators equ <ILoadAccelerators>
+LoadMenu equ <ILoadMenu>
+LoadMenuIndirect equ <ILoadMenuIndirect>
+SetMenu equ <ISetMenu>
+ChangeMenu equ <IChangeMenu>
+HiliteMenuItem equ <IHiliteMenuItem>
+GetMenuString equ <IGetMenuString>
+GetSystemMenu equ <IGetSystemMenu>
+SetSystemMenu equ <ISetSystemMenu>
+GetMenuItemCount equ <IGetMenuItemCount>
+InsertMenu equ <IInsertMenu>
+AppendMenu equ <IAppendMenu>
+ModifyMenu equ <IModifyMenu>
+RemoveMenu equ <IRemoveMenu>
+DeleteMenu equ <IDeleteMenu>
+SetMenuItemBitmaps equ <ISetMenuItemBitmaps>
+TrackPopupMenu equ <ITrackPopupMenu>
+GrayString equ <IGrayString>
+UpdateWindow equ <IUpdateWindow>
+EndPaint equ <IEndPaint>
+GetUpdateRect equ <IGetUpdateRect>
+GetUpdateRgn equ <IGetUpdateRgn>
+ExcludeUpdateRgn equ <IExcludeUpdateRgn>
+RedrawWindow equ <IRedrawWindow>
+LockWindowUpdate equ <ILockWindowUpdate>
+ScrollDC equ <IScrollDC>
+ScrollWindowEx equ <IScrollWindowEx>
+SetScrollPos equ <ISetScrollPos>
+GetScrollPos equ <IGetScrollPos>
+SetScrollRange equ <ISetScrollRange>
+GetScrollRange equ <IGetScrollRange>
+ShowScrollBar equ <IShowScrollBar>
+EnableScrollBar equ <IEnableScrollBar>
+SetProp equ <ISetProp>
+;GetProp equ <IGetProp>
+RemoveProp equ <IRemoveProp>
+EnumProps equ <IEnumProps>
+AdjustWindowRectEx equ <IAdjustWindowRectEx>
+MessageBox equ <IMessageBox>
+SetCursor equ <ISetCursor>
+CreateCaret equ <ICreateCaret>
+HideCaret equ <IHideCaret>
+ShowCaret equ <IShowCaret>
+ChildWindowFromPoint equ <IChildWindowFromPoint>
+SetSysColors equ <ISetSysColors>
+GetParent equ <IGetParent>
+SetParent equ <ISetParent>
+EnumChildWindows equ <IEnumChildWindows>
+FindWindow equ <IFindWindow>
+EnumWindows equ <IEnumWindows>
+GetTopWindow equ <IGetTopWindow>
+GetLastActivePopup equ <IGetLastActivePopup>
+GetWindow equ <IGetWindow>
+;InvalidateDCCache equ <IInvalidateDCCache>
+LoadBitmap equ <ILoadBitmap>
+LoadCursor equ <ILoadCursor>
+CreateCursor equ <ICreateCursor>
+DestroyCursor equ <IDestroyCursor>
+LoadIcon equ <ILoadIcon>
+CreateIcon equ <ICreateIcon>
+DestroyIcon equ <IDestroyIcon>
+LoadString equ <ILoadString>
+IsDialogMessage equ <IIsDialogMessage>
+MapDialogRect equ <IMapDialogRect>
+DlgDirList equ <IDlgDirList>
+DlgDirSelect equ <IDlgDirSelect>
+DlgDirSelectEx equ <IDlgDirSelectEx>
+DlgDirListComboBox equ <IDlgDirListComboBox>
+DlgDirSelectComboBox equ <IDlgDirSelectComboBox>
+DlgDirSelectComboBoxEx equ <IDlgDirSelectComboBoxEx>
+DefFrameProc equ <IDefFrameProc>
+DefMDIChildProc equ <IDefMDIChildProc>
+TranslateMDISysAccel equ <ITranslateMDISysAccel>
+ArrangeIconicWindows equ <IArrangeIconicWindows>
+SystemParametersInfo equ <ISystemParametersInfo>
+WinHelp equ <IWinHelp>
+OpenDriver equ <IOpenDriver>
+CloseDriver equ <ICloseDriver>
+GetDriverModuleHandle equ <IGetDriverModuleHandle>
+SendDriverMessage equ <ISendDriverMessage>
+DefDriverProc equ <IDefDriverProc>
+GetNextDriver equ <IGetNextDriver>
+GetDriverInfo equ <IGetDriverInfo>
+SelectPalette equ <ISelectPalette>
+RealizePalette equ <IRealizePalette>
+wsprintf equ <Iwsprintf>
+wvsprintf equ <Iwvsprintf>
diff --git a/private/mvdm/wow16/user/ks386p.inc b/private/mvdm/wow16/user/ks386p.inc
new file mode 100644
index 000000000..ad4c8bba7
--- /dev/null
+++ b/private/mvdm/wow16/user/ks386p.inc
@@ -0,0 +1,29 @@
+; extracted from sdk\inc\ks386.inc
+;
+; Yes I know this is not the right thing to do, but the 16bit
+; masm runs "out of memory" while assembling (for cairo builds
+; it runs out of memory in ks386.inc itself, so splitting our
+; source file wouldn't do the trick).
+;
+; - nanduri
+
+
+;
+; Defines for user shared data
+;
+MM_SHARED_USER_DATA_VA equ 07FFE0000H
+UsTickCountLow equ 00H
+UsTickCountMultiplier equ 04H
+
+
+;
+; Gdt Descriptor Offset Definitions
+;
+
+KGDT_R3_DATA equ 020H
+KGDT_R3_TEB equ 038H
+
+;
+; constants for system irql and IDT vector conversion
+;
+RPL_MASK equ 03H
diff --git a/private/mvdm/wow16/user/layer.asm b/private/mvdm/wow16/user/layer.asm
new file mode 100644
index 000000000..2e5b0efe6
--- /dev/null
+++ b/private/mvdm/wow16/user/layer.asm
@@ -0,0 +1,58 @@
+ title LAYER.ASM - Parameter validation layer
+
+.xlist
+
+include layer.inc
+
+LAYER_INCLUDE=1 ; to suppress including most of the crap in user.inc
+include user.inc
+;include usermenu.inc
+
+.list
+
+LAYER_START
+
+include user.api
+
+LAYER_END
+
+; Force menu validation subroutines to get generated in the TEXT
+; segment for the message validation layer...
+;
+genVHMENUtext = 1
+
+LAYER_EXPAND TEXT
+
+;
+; WOW USER has only one segment
+;
+
+; We (NT WOW) do not need these.
+;
+
+;LAYER_EXPAND TEXTMOVE
+;LAYER_EXPAND WINCRTDST
+;LAYER_EXPAND WINUTIL
+;LAYER_EXPAND LANG
+;LAYER_EXPAND RUNAPP
+;LAYER_EXPAND SWITCH
+;LAYER_EXPAND WMGR
+;LAYER_EXPAND WINSWP
+;LAYER_EXPAND DLGBEGIN
+;LAYER_EXPAND DLGCORE
+;LAYER_EXPAND CLPBRD
+;LAYER_EXPAND MENUAPI
+;LAYER_EXPAND MENUCORE
+;LAYER_EXPAND MDKEY
+;LAYER_EXPAND RESOURCE
+;LAYER_EXPAND LBOXDIR
+;LAYER_EXPAND RARE
+;LAYER_EXPAND ICON
+;LAYER_EXPAND SCRLBAR
+;LAYER_EXPAND MDIWIN
+;LAYER_EXPAND WMGR2
+;LAYER_EXPAND SPRINTF
+;LAYER_EXPAND COMDEV
+;LAYER_EXPAND NET
+
+end
diff --git a/private/mvdm/wow16/user/listing.inc b/private/mvdm/wow16/user/listing.inc
new file mode 100644
index 000000000..9e1f10dd1
--- /dev/null
+++ b/private/mvdm/wow16/user/listing.inc
@@ -0,0 +1,34 @@
+; for wow.asm
+.286p
+.model SMALL
+.386p
+
+
+ifndef WOWRTL
+
+EXTRN GetAppCompatFlags:FAR
+PUBLIC _GetAppCompatFlags@4
+_TEXT SEGMENT
+_GetAppCompatFlags@4 PROC FAR ; COMDAT
+ push 0
+ call GetAppCompatFlags
+ movzx eax, ax
+ shl edx, 16
+ or eax, edx
+ ret 4
+_GetAppCompatFlags@4 ENDP
+_TEXT ENDS
+
+else
+
+_TEXT SEGMENT
+EXTRN _GetAppCompatFlags@4:FAR
+_TEXT ENDS
+
+endif
+
+_TEXT SEGMENT
+EXTRN _wow16gpsi:NEAR
+EXTRN _wow16CsrFlag:NEAR
+_TEXT ENDS
+
diff --git a/private/mvdm/wow16/user/makefile b/private/mvdm/wow16/user/makefile
new file mode 100644
index 000000000..953bf9183
--- /dev/null
+++ b/private/mvdm/wow16/user/makefile
@@ -0,0 +1,272 @@
+# USER16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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.
+
+CAIRO_PRODUCT = 1
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+CINCS = ..\inc;..\..\inc
+!endif
+
+# work around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!IFNDEF ALT_PROJECT
+ALT_PROJECT=DAYTONA
+ALT_PROJECT_TARGET=.
+!ENDIF
+
+!IFNDEF ALT_PROJECT_TARGET
+!IF "$(ALT_PROJECT)" == "DAYTONA"
+ALT_PROJECT_TARGET=.
+!ELSE
+ALT_PROJECT_TARGET=$(ALT_PROJECT)
+!ENDIF
+!ENDIF
+
+O=k\$(ALT_PROJECT)
+
+
+# WOW matches 32bit WINVER value this was built for.
+DEFINES = -DWOW=0x0400 $(MVDMFLAGS) -DBUILDDLL
+!ifdef DBG
+DEFINES = $(DEFINES) -DDEBUG
+!endif
+
+OBJ386 =
+
+!IFNDEF NONX86
+!IF "$(PROCESSOR_ARCHITECTURE)" == "x86" || "$(BUILD_DEFAULT_TARGETS)" == "-386"
+DEFINES = $(DEFINES) -DPMODE32
+OBJ386 = $(O)\wowk.obj $(O)\wowkr.obj
+!ENDIF
+!ENDIF
+
+
+AOBJ = -Mx -t $(DEFINES) $(INCS)
+COBJ = -AS -Gs -Ols -W2 -Zp $(DEFINES) $(INCS)
+
+CW16 = -PLM -Asnw -G2s -W2 $(DEFINES)
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16 /batch
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Odi /Zdp -DWOWDBG
+LINK = $(LINK) /LI
+!else
+CW16 = $(CW16) /Os /Zp
+!endif
+
+W16LIBS = ..\lib\sdllcew.lib
+
+OBJ1 = $(O)\user.obj $(O)\user1a.obj $(O)\user2.obj $(O)\user2a.obj $(O)\user3.obj $(O)\user3a.obj $(O)\user4.obj $(O)\winrect.obj $(O)\layer.obj $(O)\msglayer.obj
+OBJ2 = $(O)\init.obj $(O)\rmload.obj $(O)\wsprintf.obj $(O)\wclass.obj $(O)\fastres.obj $(O)\wowcomm.obj $(O)\usercli.obj
+OBJ3 = $(O)\wsphelp.obj $(O)\net.obj $(O)\winnet.obj $(O)\inuserds.obj $(O)\intds.obj $(O)\drvr.obj $(O)\drvrrare.obj $(O)\winq.obj $(O)\debug.obj
+OBJ4 = $(O)\winlang.obj $(O)\winstr.obj $(O)\winstack.obj $(O)\helpcall.obj $(O)\winhook.obj $(O)\winmisc2.obj $(O)\rmcreate.obj
+
+.asm{$(O)\}.obj:
+ masm $(AOBJ) $<,$*;
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c{$(O)\}.obj:
+ set include=$(CINCS);$(INCLUDE)
+ cl16 -c -nologo $(CW16) /Fo$*.obj $<
+
+.c.obj:
+ set include=$(CINCS);$(INCLUDE)
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ set include=$(CINCS);$(INCLUDE)
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+{$(O)\}.map{$(O)\}.sym:
+ mapsym $*
+ copy user.sym $(O)
+ erase user.sym
+
+.rc{$(O)\}.res:
+ rc16 -r $(INCS) $<
+ copy user.res $*.res
+ erase user.res
+
+# Check to see if we're being invoked from ntuser\client
+
+!IFDEF NTUSERK
+!UNDEF TUKWILA
+!ENDIF
+
+all: $(O)\user.exe $(O)\user.sym $(O)\user.map
+ -binplace -O $(ALT_PROJECT_TARGET) $(O)\user.exe
+ -binplace -O $(ALT_PROJECT_TARGET) $(O)\user.sym
+ -binplace -O $(ALT_PROJECT_TARGET) $(O)\user.map
+
+clean: cleanup all
+
+cleanup:
+ if exist $(O)\*.lrf del $(O)\*.lrf
+ if exist $(O)\*.obj del $(O)\*.obj
+ if exist $(O)\*.exe del $(O)\*.exe
+ if exist $(O)\*.map del $(O)\*.map
+ if exist $(O)\*.sym del $(O)\*.sym
+ if exist $(O)\*.res del $(O)\*.res
+
+
+$(O)\debug.obj: debug.c user.h
+
+$(O)\drvr.obj: drvr.c user.h
+
+$(O)\drvrrare.obj: drvrrare.c user.h
+
+$(O)\fastres.obj: fastres.c user.h
+
+$(O)\helpcall.obj: helpcall.c user.h
+
+$(O)\init.obj: init.c user.h
+
+$(O)\intds.obj: intds.asm user.inc
+
+$(O)\inuserds.obj: inuserds.c user.h
+
+$(O)\layer.obj: layer.asm user.inc ..\inc\layer.inc user.api
+
+$(O)\msglayer.obj: msglayer.asm user.inc ..\inc\layer.inc messages.api msglayer.inc
+
+$(O)\net.obj: net.c user.h netdlg.h ..\inc\winnet.h
+
+$(O)\rmcreate.obj: rmcreate.c user.h
+
+$(O)\rmload.obj: rmload.c user.h ..\inc\multires.h
+
+$(O)\user.obj: user.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user1a.obj: user1a.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user2.obj: user2.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user2a.obj: user2a.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user3.obj: user3.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user3a.obj: user3a.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\user4.obj: user4.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\usercli.obj: usercli.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\wclass.obj: wclass.asm
+
+$(O)\winhook.obj: winhook.asm user.inc ..\inc\newexe.inc
+
+$(O)\winlang.obj: winlang.asm user.inc
+
+$(O)\winmisc2.obj: winmisc2.asm user.inc
+
+$(O)\winrect.obj: winrect.asm user.inc ..\..\inc\wow.inc ..\..\inc\wowusr.inc
+
+$(O)\winq.obj: winq.asm user.inc
+
+$(O)\winstack.obj: winstack.asm user.inc
+
+$(O)\winstr.obj: winstr.asm user.inc
+
+$(O)\winnet.obj: winnet.asm
+ masm -DSEGNAME=TEXT $(AOBJ) $(@B).asm,$*;
+
+$(O)\wowcomm.obj: wowcomm.c ..\inc\windows.h ..\..\inc\wowcomm.h
+
+$(O)\wsphelp.obj: wsphelp.asm
+
+$(O)\wsprintf.obj: wsprintf.c ..\inc\windows.h ..\inc\winexp.h
+
+
+USERBASE=\nt\private\ntos\w32\ntuser
+
+USER32CL= $(USERBASE)\client
+
+USER32CLPROJ= $(USER32CL)\$(ALT_PROJECT)
+
+$(USER32CLPROJ)\wowasm.asm : $(USER32CL)\wow.c $(USER32CL)\precomp.h
+ cd $(USER32CLPROJ)
+ nmake wowasm.asm
+ cd $(MAKEDIR)
+
+$(O)\wowk.asm: $(USER32CLPROJ)\wowasm.asm
+ copy $(USER32CLPROJ)\wowasm.asm $(O)\wowasmk.asm
+ wowasmk.cmd wowasmk wowk $(ALT_PROJECT)
+
+$(O)\wowk.obj: $(O)\wowk.asm
+ masm $(AOBJ) $*,$*;
+
+USER32RTL= $(USERBASE)\rtl
+USER32RTLCL= $(USER32RTL)\client
+USER32RTLCLPROJ= $(USER32RTLCL)\$(ALT_PROJECT)
+
+$(USER32RTLCLPROJ)\wowrtl.asm : $(USER32RTL)\wow.c $(USER32RTLCL)\wow.c $(USER32RTL)\precomp.h
+ cd $(USER32RTLCLPROJ)
+ nmake wowrtl.asm
+ cd $(MAKEDIR)
+
+$(O)\wowkr.asm: $(USER32RTLCLPROJ)\wowrtl.asm
+ copy $(USER32RTLCLPROJ)\wowrtl.asm $(O)\wowrtl.asm
+ wowasmk.cmd wowrtl wowkr1 $(ALT_PROJECT)
+ wowasmk.cmd wowkr1 wowkr $(ALT_PROJECT)
+
+$(O)\wowkr.obj: $(O)\wowkr.asm
+ masm -DWOWRTL $(AOBJ) $*,$*;
+
+$(O)\user.res: user.rc user.rcv ..\inc\common.ver
+
+$(O)\user.sym: $(O)\user.map
+
+$(O)\userk.lrf: makefile
+ echo $(OBJ386) $(OBJ1)+>$(O)\userk.lrf
+ echo $(OBJ2)+>>$(O)\userk.lrf
+ echo $(OBJ3)+>>$(O)\userk.lrf
+ echo $(OBJ4)>>$(O)\userk.lrf
+ echo $(O)\user.exe>>$(O)\userk.lrf
+ echo $(O)\user.map $(LINK)>>$(O)\userk.lrf
+ echo ..\lib\libw.lib ..\lib\system.lib /nod >>$(O)\userk.lrf
+ echo user;>>$(O)\userk.lrf
+
+$(O)\user.exe $(O)\user.map: $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(O)\userk.lrf user.def $(O)\user.res $(OBJ386)
+ link16 @$(O)\userk.lrf;
+ rc16 -t $(O)\user.res $(O)\user.exe
+
+!ENDIF
diff --git a/private/mvdm/wow16/user/messages.api b/private/mvdm/wow16/user/messages.api
new file mode 100644
index 000000000..46b295ce7
--- /dev/null
+++ b/private/mvdm/wow16/user/messages.api
@@ -0,0 +1,1079 @@
+;------------------------
+; General window messages
+;
+; MSDWP.C and others
+;
+; MP_CTRLID assumes hWnd
+;
+MESSAGE_CLASS COMMON
+
+MESSAGE WM_CREATE, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LONG lpCS ;ObjectVision breaks if we validate
+
+MESSAGE WM_DESTROY, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_MOVE, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_int X ;new X location of upper left of client area
+MP_int Y ;new Y location of upper left of client area
+
+MESSAGE WM_SIZE, <SYSTEM>
+MP_VALUE wSizeType, SIZE_MAX ;** range 0-4
+MP_int CX ;new width of window
+MP_int CY ;new height of window
+
+MESSAGE WM_ACTIVATE, <SYSTEM>
+MP_BOOL bActivating ;** wParam == 0 => lParamLo is handle to
+MP_HWNDW0 hwndActDeact ;activated window otherwise lParamLo is handle
+ ;to inactive window (can be NULL)
+ ;Made this a warning because WinProject 1.0
+ ;passes in a 1 here when using for its own
+ ;use
+MP_BOOL bMaximized ;BOOL value
+
+MESSAGE WM_SETFOCUS, <SYSTEM>
+MP_HWND0 hWndFocus ;handle to window losing focus.
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_KILLFOCUS, <SYSTEM>
+MP_HWND0 hWndFocus ;handle to window receiving focus.
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_ENABLE, <SYSTEM>
+MP_BOOL bEnabled ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_SETREDRAW
+MP_BOOL bRedraw ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_SETTEXT
+MP_WMBZ wParam ;unused
+MP_CLPSTR0 lpString
+
+MESSAGE WM_GETTEXT
+MP_LPBUFFERX nCount, lpBuffer
+
+MESSAGE WM_GETTEXTLENGTH
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_PAINT, <SYSTEM>
+MP_HDC0 hdc ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_CLOSE, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_QUERYENDSESSION, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_QUIT, <POSTED, SYSTEM>
+MP_WORD nExitCode
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_QUERYOPEN, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_ERASEBKGND, <SYSTEM>
+MP_HDC hDC
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_SYSCOLORCHANGE, <POSTED, SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_ENDSESSION, <SYSTEM>
+MP_BOOL bSessionEnding ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_SHOWWINDOW, <SYSTEM>
+MP_BOOL bStatus ;BOOL value
+MP_SHOWVALUE wShow ;** 0, SW_PARENTCLOSING or SW_PARENTOPENING
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_CTLCOLOR
+MP_HDC hDC ; child window DC
+MP_HWND hWndChild ; LOWORD is handle to child window
+MP_VALUE wType, CTLCOLOR_MAX
+
+MESSAGE WM_WININICHANGE, <SYSTEM, POSTED>
+MP_WMBZ wParam ;unused
+MP_CLPSTR0 lpSectionName ;NULL used by some apps
+
+MESSAGE WM_DEVMODECHANGE, <SYSTEM, POSTED>
+MP_WMBZ wParam ;unused
+MP_CLPSTR0 lpDeviceName ;NULL used by some apps
+
+MESSAGE WM_ACTIVATEAPP, <SYSTEM>
+MP_BOOL bActivate ;BOOL value
+MP_HTASK0 hTask ;task handle of app. owning window
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_FONTCHANGE, <SYSTEM, POSTED>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_TIMECHANGE, <SYSTEM, POSTED>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_CANCELMODE
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_SETCURSOR, <SYSTEM>
+MP_HWND hWndCur ;handle to window containing cursor
+MP_VALUE wHTCode, HT_MAX ;** hit test area codes. Range 0-17
+MP_RVALUE wMsg, WM_MOUSEFIRST, WM_MOUSELAST ;mouse message number
+
+MESSAGE WM_MOUSEACTIVATE, <SYSTEM>
+MP_HWND hWndParent ;topmost parent of activated window
+MP_VALUE wHTCode, HT_MAX ;** hit test area codes. Range 0-17
+MP_RVALUE wMsg, WM_MOUSEFIRST, WM_MOUSELAST ;mouse message number
+
+MESSAGE WM_CHILDACTIVATE, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_GETMINMAXINFO, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_CLP5POINTBUFFER lpPoints ;points to an array of 5 points
+
+MESSAGE WM_PAINTICON, <SYSTEM>
+MP_WORD wParam ;unused, but 3.0 passed 1 for some reason
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_ICONERASEBKGND, <SYSTEM>
+MP_HDC hDC ;DC of icon
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_NEXTDLGCTL, <SYSTEM>
+MP_WMNEXTDLGCTL wCtlFlg, bFlag ;** if lParam is 0 wParam is a flag
+ ;otherwise it is the control handle
+
+MESSAGE WM_SPOOLERSTATUS
+MP_CONST wStatus,SMP_JOBSTATUS ;** set to SMP_JOBSTATUS
+MP_WORD wJobs ;no. of jobs left in queue
+MP_WMBZ wParamHi ;unused
+
+MESSAGE WM_DRAWITEM
+MP_WORD idHwnd ;hwnd id of item to be drawn
+MP_CLPDRAWITEMSTRUCT lpDrawItem ;**
+
+MESSAGE WM_MEASUREITEM
+MP_WORD idHwnd ;hwnd id of item to be measured
+MP_LPMEASUREITEMSTRUCT lpMeasureItem ;**
+
+MESSAGE WM_DELETEITEM
+MP_WORD idHwnd ;hwnd id of item to be deleted
+MP_CLPDELETEITEMSTRUCT lpDeleteItem ;**
+
+MESSAGE WM_VKEYTOITEM
+MP_VKEY wVKey ;** virt. key code
+MP_HWND hWndList ;handle to listbox window
+MP_WORD wCaretPos ;caret position
+
+MESSAGE WM_CHARTOITEM
+MP_CHARVALUE wChar ;**
+MP_HWND hWndList ;handle to listbox window
+MP_WORD wCaretPos ;caret position
+
+MESSAGE WM_SETFONT
+MP_HFONT0 hFont ;handle to font or NULL
+MP_BOOL bRedraw ;BOOL value
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_GETFONT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_QUERYDRAGICON
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_COMPAREITEM
+MP_WORD idHwnd ;hwnd id of item to be compared
+MP_CLPCOMPAREITEMSTRUCT lpCompareItem ;**
+
+MESSAGE WM_COMPACTING
+MP_WORD wCPUTimeRatio ;time currently spent compacting
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_COMMNOTIFY ;?? not implemented yet.
+MP_CID wCommID ;**
+MP_LONG lParam
+
+MESSAGE WM_NCCREATE, <SYSTEM>
+MP_WMBZ wParam
+MP_LPCREATESTRUCT lpCS
+
+MESSAGE WM_NCDESTROY, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_NCCALCSIZE, <SYSTEM>
+MP_BOOL fCalcClientOnly
+MP_CLPRECT lpRect ;window rectangle coordinates
+
+MESSAGE WM_NCHITTEST, <SYSTEM>
+MP_WMBZ wParam ;unused
+MP_int X
+MP_int Y
+
+MESSAGE WM_NCPAINT, <SYSTEM>
+MP_HRGN01 hrgn
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_NCACTIVATE, <SYSTEM>
+MP_BOOL bActive ;BOOL value
+MP_HWND0 hwndActDeact
+MP_BOOL fIconic
+
+MESSAGE WM_GETDLGCODE
+MP_WORD msg
+MP_CLPMSG0 lpMsg
+
+MESSAGE WM_NCMOUSEMOVE
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCLBUTTONDOWN
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCLBUTTONUP
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCLBUTTONDBLCLK
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCRBUTTONDOWN
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCRBUTTONUP
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCRBUTTONDBLCLK
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCMBUTTONDOWN
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCMBUTTONUP
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_NCMBUTTONDBLCLK
+MP_VALUE wHTCode, HT_MAX ;hit test area codes. Range 0-17
+MP_POINT pt
+
+MESSAGE WM_KEYDOWN
+MP_VKEY wVKey ; virt. key code
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_KEYUP
+MP_VKEY wVKey ; virt. key code
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_CHAR
+MP_CHARVALUE wChar
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_DEADCHAR
+MP_CHARVALUE wChar
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_SYSKEYDOWN
+MP_VKEY wVKey ; virt. key code
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_SYSKEYUP
+MP_VKEY wVKey ; virt. key code
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_SYSCHAR
+MP_CHARVALUE wChar
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_SYSDEADCHAR
+MP_CHARVALUE wChar
+MP_LONG lKeyData ; repeat count and flags
+
+MESSAGE WM_INITDIALOG
+MP_HWND0 hCtrl ; handle of first child
+MP_LONG lInitValue ; initialization value
+
+; No validation of wParam & lParam because so many people do screwy
+; things with the parameter. Also, since it's sent by the system
+; almost all the time, validation will be of little help.
+;
+MESSAGE WM_COMMAND ;lParamLo is 0 => wParam is menu item.
+MP_WORD wParam ;lParamHi is 1 => wParam is accelerator ID.
+MP_LONG lParam ;Otherwise lParamLo is control handle, lParamHi
+ ;is notification code and wParam is control ID.
+
+MESSAGE WM_SYSCOMMAND
+MP_SYSCOMMAND wSysCommand ;** SC_ code
+MP_int X
+MP_int Y
+
+MESSAGE WM_TIMER
+MP_WORD idTimer ;** timer ID
+MP_LPFNTIMER0 lpTimerProc ;timer function or NULL
+
+MESSAGE WM_HSCROLL
+MP_VALUE wParam, SB_MAX ;** range 0-7
+MP_WORD pos ;position
+MP_HWND0 hwndCtl ;control handle if message is due
+ ;to scrollbar control, otherwise
+ ;unused
+
+MESSAGE WM_VSCROLL
+MP_VALUE wParam, SB_MAX ;** range 0-7
+MP_WORD pos ;position
+MP_HWNDW0 hwndCtl ;control handle if message is due
+ ;to scrollbar control, otherwise
+ ;unused. Make it a warning because
+ ;Norton Utilities passes "random"
+ ;numbers here.
+
+MESSAGE WM_INITMENU
+MP_HMENU hMenu ;handle of menu being init.
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_INITMENUPOPUP
+MP_HMENU hMenu ;handle of popup being init.
+MP_WORD wIndex ;popup menu index
+MP_BOOL bSysMenu ;BOOL value
+
+MESSAGE WM_MENUSELECT
+MP_WMMENUSELECT wHandle, wFlags ; **lParamLo has a combination of: MF_BITMAP
+ ; MF_CHECKED, MF_DISABLED, MF_GRAYED,
+ ; MF_MOUSESELECT, MF_OWNERDRAW, MF_POPUP
+ ; and MF_SYSMENU or can be -1
+ ; If MF_POPUP, wParam has popup handle
+
+MESSAGE WM_MENUCHAR
+MP_CHARVALUE wChar
+MP_BIVALUE wMenuType, MF_POPUP, MF_SYSMENU ; ** either MF_POPUP or MF_SYSMENU
+MP_HMENU hMenu ; handle to menu
+
+MESSAGE WM_ENTERIDLE
+MP_BIVALUE wType, MSGF_DIALOGBOX, MSGF_MENU
+MP_HWND0 hwndIdle
+MP_WMBZ lParamHi ; unused
+
+MESSAGE WM_MOUSEMOVE
+MP_FLAGS wFlags, MK_VALID ;** one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_LBUTTONDOWN
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_LBUTTONUP
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_LBUTTONDBLCLK
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_RBUTTONDOWN
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_RBUTTONUP
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_RBUTTONDBLCLK
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_MBUTTONDOWN
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_MBUTTONUP
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_MBUTTONDBLCLK
+MP_FLAGS wFlags, MK_VALID ;one or more of the MK_ flags
+MP_int X
+MP_int Y
+
+MESSAGE WM_PARENTNOTIFY
+MP_WORD wValue ;** WM_CREATE, WM_DESTROY or WM_?BUTTONDOWN
+MP_WORD hwndChildOrX ; hwnd or X, depending on message
+MP_WORD idOrY ; id or Y
+
+MESSAGE WM_MDICREATE
+MP_WMBZ wParam ; unused
+MP_CLPMDICREATESTRUCT lpMCS ; **
+
+MESSAGE WM_MDIDESTROY
+MP_HWND hWndChild ; MDI child window
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDIACTIVATE
+MP_HWND01 hwnd ; ** can be 0, 1 or window handle
+MP_HWND0 hWndChild1
+MP_HWND0 hWndChild2
+
+MESSAGE WM_MDIRESTORE
+MP_CTRLID wID
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDINEXT
+MP_HWND0 hWndStart ; Goto next guy from this hwnd; NULL if active
+MP_BOOL fPrev ; if TRUE, goto PREVIOUS instead of NEXT
+MP_WMBZ lParamHi ; unused
+
+MESSAGE WM_MDIMAXIMIZE
+MP_CTRLID wID
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDITILE
+MP_FLAGS wFlags, MDITILE_VALID ; **MDITILE_HORIZONTAL|MDITILESKIPDISABLED
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDICASCADE
+MP_FLAGS wFlags, MDITILE_VALID ; MDITILESKIPDISABLED
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDIICONARRANGE
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDIGETACTIVE
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_MDISETMENU
+MP_BOOL bRefresh
+MP_HMENU0 hMenuFrame
+MP_HMENU0 hMenuPopup
+
+MESSAGE WM_DROPFILES ; ?? not implemented yet.
+MP_WORD wParam
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_CUT
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_COPY
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_PASTE
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_CLEAR
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_UNDO
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_RENDERFORMAT
+MP_ATOM wClipFmt
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_RENDERALLFORMATS
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_DESTROYCLIPBOARD
+MP_WMBZ wParam ; unused
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_DRAWCLIPBOARD
+MP_HWND0 hWndClipboardOwner ; handle to current clipboard owner
+MP_LMBZ lParam ; unused
+
+MESSAGE WM_PAINTCLIPBOARD
+MP_HWNDCLIP hWnd ;**handle to clipboard app. window
+MP_GHANDLE hPS ;handle of PAINTSTRUCT struct.
+MP_WMBZ lParamHi
+
+MESSAGE WM_VSCROLLCLIPBOARD
+MP_HWNDCLIP hWndClip ;handle to clipboard app. window
+MP_VALUE wSBCode, SB_MAX ;** range 0-7
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_SIZECLIPBOARD
+MP_HWNDCLIP hWndClip ;handle to clipboard app. window
+MP_GHANDLE hRect ;handle of RECT
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_ASKCBFORMATNAME
+MP_LPBUFFERX nCount, lpBuffer
+
+MESSAGE WM_CHANGECBCHAIN
+MP_HWND hWndRemove ; window being removed
+MP_HWND0 hWndNext ; next window in chain
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_HSCROLLCLIPBOARD
+MP_HWNDCLIP hWndClip ;handle to clipboard app. window
+MP_VALUE wSBCode, SB_MAX ;range 0-7
+MP_WMBZ lParamHi ;unused
+
+MESSAGE WM_QUERYNEWPALETTE
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_PALETTECHANGED
+MP_HWND hWnd ;Window that caused palette change
+MP_LMBZ lParam ;unused
+
+MESSAGE WM_POWER
+MP_VALUE wPower, PWR_MAX ;power management code
+MP_LMBZ lParam ;unused
+
+;-----------------------
+; Windows DDE messages
+
+MESSAGE WM_DDE_INITIATE
+MP_HWND hWndSend ;sender window
+MP_ATOM0 aApplication ;** app. with whom conversation is required
+MP_ATOM0 aTopic ;conversation topic
+
+MESSAGE WM_DDE_TERMINATE, <POSTED>
+;MP_HWNDW0 hWndSend ;sender window (warn if bogus)
+MP_WORD hwndSend ;NOTE: can be an invalid window handle
+ ; app exit time, so no validation.
+MP_LMBZ lReserved ;reserved
+
+MESSAGE WM_DDE_ADVISE, <POSTED>
+MP_HWND hWndSend ;sender window
+MP_GHANDLEDDE hOptions ;** object allicated with GMEM_DDE_SHARE opt.
+MP_ATOM aItem ;** global atom
+
+MESSAGE WM_DDE_UNADVISE, <POSTED>
+MP_HWND hWndSend ;sender window
+MP_ATOM0 aItem ;data for which req. is being retracted
+MP_ATOM0 cfFormat ;
+
+MESSAGE WM_DDE_ACK, <POSTED>
+MP_HWND hWndSend ;sender window
+MP_LONG lParam ;lParam depends on the type of msg. being
+ ;ack. Typically it is app-specific status flags.
+
+MESSAGE WM_DDE_DATA, <POSTED>
+MP_HWND hWndSend ;sender window
+MP_GHANDLEDDE0 hData ;** can be null
+MP_ATOM aItem ;global atom identifying data
+
+MESSAGE WM_DDE_REQUEST, <POSTED>
+MP_HWND hWndSend ;sender window
+MP_ATOM cfFormat ;std. or registered clipboard format.
+MP_ATOM aItem ;atom identifying item being requested.
+
+MESSAGE WM_DDE_POKE, <POSTED>
+MP_HWNDW hWndSend ;sender window, warn NULL/bad
+MP_GHANDLEDDE0 hData ;global data and other inf. allow NULL
+MP_ATOM aItem ;global atom identifying data
+
+; Removed the "<POSTED>" to fix Bug #14828
+;MESSAGE WM_DDE_EXECUTE, <POSTED>
+MESSAGE WM_DDE_EXECUTE
+MP_HWNDW hWndSend ;sender window. Must warn for VirtualMonitor app
+MP_WMBZ wReserved
+;MP_GHANDLEDDE hCommands ;global obj. with commands to be executed.
+MP_GHANDLEDDEW hCommands ; Legacy Tutorial uses an atom. So, we warn
+
+;------------------------
+; dialog manager messages
+; in DLGMGR.C
+
+MESSAGE DM_GETDEFID
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE DM_SETDEFID
+MP_WORD wIdItem ;new ID of item
+MP_LMBZ lParam ;unused
+
+MESSAGE_CLASS_END
+
+;----------------
+; Button messages
+; in BTNCTL.C
+
+MESSAGE_CLASS BUTTON
+
+MESSAGE BM_GETCHECK
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE BM_SETCHECK
+MP_BOOL bCheck ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE BM_GETSTATE
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE BM_SETSTATE
+MP_BOOL bHilite ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE BM_SETSTYLE
+MP_FLAGS wFlags, BS_VALID ;** button control style
+MP_BOOL bRedraw ;BOOL value
+MP_WMBZ lParamHi ;unused
+
+MESSAGE_CLASS_END
+
+;-------------------------------------------
+; combobox messages
+; in COMBO.C
+;
+; MP_CBINDEX*, MP_CBITEMHEIGHT*
+; MP_CLPSTRCB and MP_EDITPOS assume hWnd.
+
+MESSAGE_CLASS COMBOBOX
+
+MESSAGE CB_GETEDITSEL
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_LIMITTEXT
+MP_WORD wBytes ;max. number of bytes
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_SETEDITSEL
+MP_WMBZ wParam ;unused
+MP_EDITPOS wStart ;** start of edit selection
+MP_EDITPOS wEnd ;end of edit selection
+
+MESSAGE CB_ADDSTRING
+MP_WMBZ wParam ;unused
+MP_CLPSTRCB lpString ;** if combobox is ownerdraw, then CLPSTR
+ ;only if style includes CB_HASSTRINGS
+
+MESSAGE CB_DELETESTRING
+MP_CBINDEX wIndex ;** index of item to be deleted
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_DIR
+MP_FLAGS wFlags,DOSATTR_VALID ;** DOS file attributes (0 valid)
+MP_CLPSTR lpFileName ;filename
+
+MESSAGE CB_GETCOUNT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_GETCURSEL
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_GETLBTEXT
+MP_CBINDEX wIndex
+MP_LPSTRCB lpString ; pointer to DWORD if !CB_HASSTRINGS
+
+MESSAGE CB_GETLBTEXTLEN
+MP_CBINDEX wIndex ;index of item
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_INSERTSTRING
+MP_CBINDEX wIndex ;index of item
+MP_CLPSTRCB lpString ;** if combobox is ownerdraw, then CLPSTR
+ ;only if style includes CB_HASSTRINGS
+
+MESSAGE CB_RESETCONTENT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_FINDSTRING
+MP_CBINDEXFFFF wIndex ;** index of item. Can be -1
+MP_CLPSTRCB lpString ;combobox is ownerdraw, then CLPSTR
+ ;only if style includes CB_HASSTRING
+
+MESSAGE CB_SELECTSTRING
+MP_CBINDEXFFFF wIndex ;index of item. Can be -1
+MP_CLPSTRCB lpString ;combobox is ownerdraw, then CLPSTR
+ ;only if style includes CB_HASSTRINGS
+
+MESSAGE CB_SETCURSEL
+MP_CBINDEXFFFF wIndex ;index of item. Can be -1
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_SHOWDROPDOWN
+MP_BOOL bDisplay ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_GETITEMDATA
+MP_CBINDEX wIndex ;index of item.
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_SETITEMDATA
+MP_CBINDEX wIndex ;index of item.
+MP_LONG lParam ;new value of item (can be anything)
+
+MESSAGE CB_GETDROPPEDCONTROLRECT
+MP_WMBZ wParam ;unused
+MP_LPRECT lpRect
+
+MESSAGE CB_SETITEMHEIGHT
+MP_CBITEMHEIGHTFFFF wIndex ;** index or -1 if style is CBS_OWNERDRAWVARIABLE
+ ;must be 0 otherwise
+MP_WORD wHeight
+MP_WMBZ lParamHi ;unused
+
+MESSAGE CB_GETITEMHEIGHT
+MP_CBITEMHEIGHTFFFF wIndex ;** index or -1 if style is CBS_OWNERDRAWVARIABLE
+ ;must be 0 otherwise
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_SETEXTENDEDUI
+MP_BOOL bSet ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_GETEXTENDEDUI
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_GETDROPPEDSTATE
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE CB_FINDSTRINGEXACT
+MP_CBINDEXFFFF wIndex ;** index of item. Can be -1
+MP_CLPSTRCB lpString ;combobox is ownerdraw, then CLPSTR
+ ;only if style includes CB_HASSTRING
+
+MESSAGE_CLASS_END
+
+;---------------------------------------------
+; edit control messages
+; in EDITEC.CML.C and EDITSL.C
+;
+; MP_EDITPOS, MP_EMLINES, MP_EMLINE*, MP_EMCHARPOS
+; MP_CLPSTRLB and MP_CHARINDEX* assume hWnd.
+
+;----- in EDITEC.C (processed by commom edit control handler)---------
+
+MESSAGE_CLASS EDIT
+
+MESSAGE EM_GETSEL
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETRECT
+MP_WMBZ wParam ;unused
+MP_LPRECT lpRect ;ptr. to RECT
+
+MESSAGE EM_GETMODIFY
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETMODIFY
+MP_WORD wValue ;new value for modify flag
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETLINECOUNT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_LIMITTEXT
+MP_WORD wBytes ;max. bytes that can be entered (can be 0)
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_CANUNDO
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_EMPTYUNDOBUFFER
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETPASSWORDCHAR
+MP_WORD wChar ;char to be displayed
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETFIRSTVISIBLELINE
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETREADONLY
+MP_BOOL bSet ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETPASSWORDCHAR
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETWORDBREAKPROC
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+;---- in EDITML.C (processed by multiline control handler) ------------
+
+MESSAGE EM_SETRECT, <MLCONLY> ;only applicable to multiline controls
+MP_WMBZ wParam ;unused
+MP_CLPRECT lpRect ;ptr. to new RECT dimensions
+
+MESSAGE EM_SETRECTNP, <MLCONLY>;only applicable to multiline controls
+MP_WMBZ wParam ;unused
+MP_CLPRECT lpRect ;ptr. to new RECT dimensions
+
+MESSAGE EM_SCROLL, <MLCONLY>
+MP_VALUE wScroll, SB_LPMAX ;** range 0-4 (only SB_LINEUP, SB_LINEDOWN,
+ ;SB_PAGEUP and SB_PAGEDOWN)
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_LINESCROLL, <MLCONLY>
+MP_WMBZ wParam ;unused
+MP_EMCLINE nLines ;** number of lines to scroll vertically
+MP_EMCHARPOS nPos ;** char positions to scroll horizontally
+
+MESSAGE EM_LINEINDEX, <MLCONLY>
+MP_EMLINEFFFF wLineNumber ;** Required line number. Can be -1
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETHANDLE, <MLCONLY>
+MP_LHANDLE wHandle ;handle in app's DS
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETHANDLE, <MLCONLY>
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_FMTLINES, <MLCONLY>
+MP_BOOL bRemoveEOL ;BOOL value
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_LINEFROMCHAR, <MLCONLY>
+MP_CHARINDEXFFFF wIndex ;**index of char from beginning of text (or -1)
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETWORDBREAK, <MLCONLY> ;?? not implemented
+MP_WMBZ wParam ;unused
+MP_LPFNWORDBREAK0 lpfnWordBreak ;WordBreak callback function
+
+
+MESSAGE EM_SETTABSTOPS, <MLCONLY>
+MP_LPTSBUFFER0 wTabs, lpTabs ;** wParam: number of tab stops
+ ;lParam: ptr. to array of int. values.
+ ;lParam is a ptr. only if wParam is not
+ ;0 or 1. If wParam is 0, lParam can be NULL.
+
+;in EDITML.C and EDITSL.C (processed by single line and
+;multiline control handlers) --------------------------------
+
+MESSAGE EM_SETSEL
+MP_BOOL bDontScrollToView ;for 3.1 apps, don't scroll caret into view if set
+MP_int wStartPos ;start of edit selection
+MP_int wEndPos ;end of edit selection
+
+MESSAGE EM_LINELENGTH
+MP_EMLINEFFFF wLine ;Required line number. Can be -1
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_GETLINE
+MP_EMLINE wLine ;Required line number.
+MP_LPBUFFERCNT lpBuffer ;** first WORD of buffer contains count
+
+MESSAGE EM_REPLACESEL
+MP_WMBZ wParam ;unused
+MP_CLPSTR lpString ;replacement string
+
+MESSAGE EM_UNDO
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE EM_SETWORDBREAKPROC ; New for Win3.1
+MP_WMBZ wParam ;unused
+MP_LPFNWORDBREAK0 lpfnWordBreak ;WordBreak callback function
+
+MESSAGE_CLASS_END
+
+;----------------------------------------------------
+; Listbox messages
+; processed in LB1.ASM. Helper routines in LBOXCTL?.C
+;
+; MP_LBINDEX* and MP_LBLPBUFFERINDEX assume hWnd
+
+MESSAGE_CLASS LISTBOX
+
+MESSAGE LB_ADDSTRING
+MP_WMBZ wParam ;unused
+MP_CLPSTRLB lpString ;** if listbox is ownerdraw, then CLPSTR
+ ;only if style includes LB_HASSTRINGS
+
+MESSAGE LB_INSERTSTRING
+MP_LBINDEXFFFF wIndex ;** position index (can be -1)
+MP_CLPSTRLB lpString ;if listbox is ownerdraw, then CLPSTR
+ ;only if style includes LB_HASSTRINGS
+
+MESSAGE LB_DELETESTRING
+MP_LBINDEX wIndex ;position index
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_RESETCONTENT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETSEL
+MP_BOOL bHilite ;BOOL value
+MP_LBINDEXFFFF wIndex ;position index (can be -1)
+MP_WORD lParamHi ;unused (but may be -1 due to sign extension)
+
+MESSAGE LB_SETCURSEL
+MP_LBINDEXFFFF wIndex ;position index (can be -1)
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETSEL
+MP_LBINDEX wIndex ;position index
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETCURSEL
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETTEXT
+MP_LBLPBUFFERINDEX wIndex, lpBuf ;** wParam:position index
+ ;lParam:ptr. to buffer to recieve string.
+
+MESSAGE LB_GETTEXTLEN
+MP_LBINDEX wIndex ;position index
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETCOUNT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SELECTSTRING
+MP_LBINDEXFFFF wIndex ;index of item. Can be -1
+MP_CLPSTRLB lpString ;if listbox is ownerdraw, then CLPSTR
+ ;only if style includes LB_HASSTRINGS
+
+MESSAGE LB_DIR
+MP_FLAGS wFlags,DOSATTR_VALID ;** DOS file attributes (0 valid)
+MP_CLPSTR lpString ;filename
+
+MESSAGE LB_GETTOPINDEX
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_FINDSTRING
+MP_LBINDEXFFFF wIndex ;index of item. Can be -1
+MP_CLPSTRLB lpString ;if listbox is ownerdraw, then CLPSTR
+ ;only if style includes LB_HASSTRINGS
+
+MESSAGE LB_GETSELCOUNT, <MULTISELONLY>
+ ;applicable only to LBS_MULTIPLESEL listboxes
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETSELITEMS, <MULTISELONLY>
+MP_LPWBUFFERX wCount, lpBuf ;** lpBuf is int. buffer
+
+MESSAGE LB_SETTABSTOPS
+MP_LPTSBUFFER0 wTabs, lpTabs ;wParam: number of tab stops
+ ;lParam: ptr. to array of int. values.
+ ;lParam is a ptr. only if wParam is not
+ ;0 or 1. If wParam is 0, lParam can be NULL.
+
+MESSAGE LB_GETHORIZONTALEXTENT
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETHORIZONTALEXTENT
+MP_WORD wPixels ;no. pixels by which lbox can be scrolled.
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETCOLUMNWIDTH, <MULTICOLONLY>
+ ;only sent to LBS_MULTICOLUMN listboxes
+MP_WORD wWidth ;width in pixels of all columns
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETTOPINDEX
+MP_LBINDEX wIndex ;position index
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_GETITEMRECT
+MP_LBINDEX wIndex ;position index
+MP_LPRECT lpRect ;client coords. of item
+
+MESSAGE LB_GETITEMDATA
+MP_LBINDEX wIndex ;position index
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETITEMDATA
+MP_LBINDEX wIndex ;position index
+MP_LONG lParam ;new value for item
+
+MESSAGE LB_SELITEMRANGE, <MULTISELONLY> ;
+MP_BOOL bSelect ;BOOL value
+MP_LBINDEX wFirstIndex ;start index of selection
+MP_LBINDEX wLastIndex ;end index of selection
+
+MESSAGE LB_SETCARETINDEX
+MP_LBINDEX wIndex
+MP_BOOL fNoScrollIntoView
+MP_WMBZ lParamHi ;unused
+
+MESSAGE LB_GETCARETINDEX
+MP_WMBZ wParam ;unused
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_SETITEMHEIGHT, <OWNERDRAWVARONLY> ;only processed by
+ ;listboxes with LB_OWNERDRAWVARIABLE style
+MP_LBINDEX wIndex
+MP_WORD wHeight
+MP_WMBZ lParamHi ;unused
+
+MESSAGE LB_GETITEMHEIGHT, <OWNERDRAWVARONLY>
+MP_LBINDEX wIndex
+MP_LMBZ lParam ;unused
+
+MESSAGE LB_FINDSTRINGEXACT
+MP_LBINDEXFFFF wIndex ;index of item. Can be -1
+MP_CLPSTRLB lpString ;if listbox is ownerdraw, then CLPSTR
+ ;only if style includes LBS_HASSTRINGS
+MESSAGE_CLASS_END
+
+;
+; Static control messages
+;
+MESSAGE_CLASS STATIC
+
+MESSAGE STM_SETICON
+MP_HICON0 hIcon
+MP_LMBZ lParam
+
+MESSAGE STM_GETICON
+MP_WMBZ wParam
+MP_LMBZ lParam
+
+MESSAGE_CLASS_END
diff --git a/private/mvdm/wow16/user/msglayer.asm b/private/mvdm/wow16/user/msglayer.asm
new file mode 100644
index 000000000..38409ae23
--- /dev/null
+++ b/private/mvdm/wow16/user/msglayer.asm
@@ -0,0 +1,21 @@
+ title LAYER.ASM - Parameter validation layer
+
+.xlist
+
+include layer.inc
+
+LAYER_INCLUDE=1 ; to suppress including most of the crap in user.inc
+include user.inc
+
+.list
+.xall
+
+include msglayer.inc
+
+MESSAGE_START TEXT
+
+include messages.api
+
+MESSAGE_END
+
+END
diff --git a/private/mvdm/wow16/user/msglayer.inc b/private/mvdm/wow16/user/msglayer.inc
new file mode 100644
index 000000000..5cb5d9690
--- /dev/null
+++ b/private/mvdm/wow16/user/msglayer.inc
@@ -0,0 +1,1161 @@
+;==========================================================================
+;
+; Message validation layer include file
+;
+;- Where applicable, i've specified a class id. as a param. to the MESSAGE
+; macro. For others (WM_ messages), i've specified the ID "COMMON".
+;
+;- For messages meaningful only to controls having a particular style, i've
+; added an option to the MESSAGE macro:
+;
+; <MLCONLY> for messages applicable to ES_MULTILINE edit controls
+; <OWNERDRAWVARONLY> " " " " LBS_OWNERDRAWVARIABLE listboxes
+; <MULTISELONLY> " " " " LBS_MULTIPLESEL listboxes
+; <MULTICOLONLY> " " " " LBS_MULTICOLUMN listboxes
+;
+;
+; Generic message IDs
+;
+WM_NULL equ 0000h
+WM_CREATE equ 0001h
+WM_DESTROY equ 0002h
+WM_MOVE equ 0003h
+WM_SIZEWAIT equ 0004h ;Internal
+WM_SIZE equ 0005h
+WM_ACTIVATE equ 0006h
+WM_SETFOCUS equ 0007h
+WM_KILLFOCUS equ 0008h
+WM_SETVISIBLE equ 0009h ;Internal
+WM_ENABLE equ 000Ah
+WM_SETREDRAW equ 000Bh
+WM_SETTEXT equ 000Ch
+WM_GETTEXT equ 000Dh
+WM_GETTEXTLENGTH equ 000Eh
+WM_PAINT equ 000Fh
+WM_CLOSE equ 0010h
+WM_QUERYENDSESSION equ 0011h
+WM_QUIT equ 0012h
+WM_QUERYOPEN equ 0013h
+WM_ERASEBKGND equ 0014h
+WM_SYSCOLORCHANGE equ 0015h
+WM_ENDSESSION equ 0016h
+WM_SYSTEMERROR equ 0017h ;Internal
+WM_SHOWWINDOW equ 0018h
+WM_CTLCOLOR equ 0019h
+WM_WININICHANGE equ 001Ah
+WM_DEVMODECHANGE equ 001Bh
+WM_ACTIVATEAPP equ 001Ch
+WM_FONTCHANGE equ 001Dh
+WM_TIMECHANGE equ 001Eh
+WM_CANCELMODE equ 001Fh
+WM_SETCURSOR equ 0020h
+WM_MOUSEACTIVATE equ 0021h
+WM_CHILDACTIVATE equ 0022h
+WM_QUEUESYNC equ 0023h
+WM_GETMINMAXINFO equ 0024h
+WM_PAINTICON equ 0026h
+WM_ICONERASEBKGND equ 0027h
+WM_NEXTDLGCTL equ 0028h
+WM_ALTTABACTIVE equ 0029h ;Internal
+WM_SPOOLERSTATUS equ 002Ah
+WM_DRAWITEM equ 002Bh
+WM_MEASUREITEM equ 002Ch
+WM_DELETEITEM equ 002Dh
+WM_VKEYTOITEM equ 002Eh
+WM_CHARTOITEM equ 002Fh
+WM_SETFONT equ 0030h
+WM_GETFONT equ 0031h
+WM_SETHOTKEY equ 0032h
+WM_GETHOTKEY equ 0033h
+WM_FILESYSCHANGE equ 0034h ;Internal
+WM_ISACTIVEICON equ 0035h ;Internal
+;WM_UNUSED0036 equ 0036h ;Internal
+WM_QUERYDRAGICON equ 0037h
+WM_COMPAREITEM equ 0039h
+WM_TESTING equ 0040h ;Internal
+WM_COMPACTING equ 0041h
+;WM_UNUSED equ 0042h
+;WM_UNUSED equ 0043h
+WM_COMMNOTIFY equ 0044h
+;WM_UNUSED equ 0045h
+WM_WINDOWPOSCHANGING equ 0046h
+WM_WINDOWPOSCHANGED equ 0047h
+WM_POWER equ 0048h
+WM_NCCREATE equ 0081h
+WM_NCDESTROY equ 0082h
+WM_NCCALCSIZE equ 0083h
+WM_NCHITTEST equ 0084h
+WM_NCPAINT equ 0085h
+WM_NCACTIVATE equ 0086h
+WM_GETDLGCODE equ 0087h
+WM_SYNCPAINT equ 0088h ;Internal
+WM_SYNCTASK equ 0089h ;Internal
+WM_NCMOUSEMOVE equ 00A0h
+WM_NCLBUTTONDOWN equ 00A1h
+WM_NCLBUTTONUP equ 00A2h
+WM_NCLBUTTONDBLCLK equ 00A3h
+WM_NCRBUTTONDOWN equ 00A4h
+WM_NCRBUTTONUP equ 00A5h
+WM_NCRBUTTONDBLCLK equ 00A6h
+WM_NCMBUTTONDOWN equ 00A7h
+WM_NCMBUTTONUP equ 00A8h
+WM_NCMBUTTONDBLCLK equ 00A9h
+WM_KEYFIRST equ 0100h
+WM_KEYDOWN equ 0100h
+WM_KEYUP equ 0101h
+WM_CHAR equ 0102h
+WM_DEADCHAR equ 0103h
+WM_SYSKEYDOWN equ 0104h
+WM_SYSKEYUP equ 0105h
+WM_SYSCHAR equ 0106h
+WM_SYSDEADCHAR equ 0107h
+WM_YOMICHAR equ 0108h ;Internal
+WM_KEYLAST equ 0108h
+WM_CONVERTREQUEST equ 010Ah ;Internal
+WM_CONVERTRESULT equ 010Bh ;Internal
+WM_INITDIALOG equ 0110h
+WM_COMMAND equ 0111h
+WM_SYSCOMMAND equ 0112h
+WM_TIMER equ 0113h
+WM_HSCROLL equ 0114h
+WM_VSCROLL equ 0115h
+WM_INITMENU equ 0116h
+WM_INITMENUPOPUP equ 0117h
+WM_SYSTIMER equ 0118h ;Internal
+WM_MENUSELECT equ 011Fh
+WM_MENUCHAR equ 0120h
+WM_ENTERIDLE equ 0121h
+WM_LBTRACKPOINT equ 0131h ;Internal
+WM_MOUSEFIRST equ 0200h
+WM_MOUSEMOVE equ 0200h
+WM_LBUTTONDOWN equ 0201h
+WM_LBUTTONUP equ 0202h
+WM_LBUTTONDBLCLK equ 0203h
+WM_RBUTTONDOWN equ 0204h
+WM_RBUTTONUP equ 0205h
+WM_RBUTTONDBLCLK equ 0206h
+WM_MBUTTONDOWN equ 0207h
+WM_MBUTTONUP equ 0208h
+WM_MBUTTONDBLCLK equ 0209h
+WM_MOUSELAST equ 0209h
+WM_PARENTNOTIFY equ 0210h
+WM_ENTERMENULOOP equ 0211h ;Internal
+WM_EXITMENULOOP equ 0212h ;Internal
+WM_NEXTMENU equ 0213h ;Internal
+WM_MDICREATE equ 0220h
+WM_MDIDESTROY equ 0221h
+WM_MDIACTIVATE equ 0222h
+WM_MDIRESTORE equ 0223h
+WM_MDINEXT equ 0224h
+WM_MDIMAXIMIZE equ 0225h
+WM_MDITILE equ 0226h
+WM_MDICASCADE equ 0227h
+WM_MDIICONARRANGE equ 0228h
+WM_MDIGETACTIVE equ 0229h
+WM_DROPOBJECT equ 022Ah ;Internal
+WM_QUERYDROPOBJECT equ 022Bh ;Internal
+WM_BEGINDRAG equ 022Ch ;Internal
+WM_DRAGLOOP equ 022Dh ;Internal
+WM_DRAGSELECT equ 022Eh ;Internal
+WM_DRAGMOVE equ 022Fh ;Internal
+WM_MDISETMENU equ 0230h
+WM_ENTERSIZEMOVE equ 0231h ;Internal
+WM_EXITSIZEMOVE equ 0232h ;Internal
+WM_DROPFILES equ 0233h
+WM_KANJIFIRST equ 0280h ;Internal
+WM_KANJILAST equ 029Fh ;Internal
+WM_CUT equ 0300h
+WM_COPY equ 0301h
+WM_PASTE equ 0302h
+WM_CLEAR equ 0303h
+WM_UNDO equ 0304h
+WM_RENDERFORMAT equ 0305h
+WM_RENDERALLFORMATS equ 0306h
+WM_DESTROYCLIPBOARD equ 0307h
+WM_DRAWCLIPBOARD equ 0308h
+WM_PAINTCLIPBOARD equ 0309h
+WM_VSCROLLCLIPBOARD equ 030Ah
+WM_SIZECLIPBOARD equ 030Bh
+WM_ASKCBFORMATNAME equ 030Ch
+WM_CHANGECBCHAIN equ 030Dh
+WM_HSCROLLCLIPBOARD equ 030Eh
+WM_QUERYNEWPALETTE equ 030Fh
+WM_PALETTEGONNACHANGE equ 0310h ;Internal
+WM_PALETTEISCHANGING equ 0310h
+WM_CHANGEPALETTE equ 0311h ;Internal
+WM_PALETTECHANGED equ 0311h
+WM_PENWINFIRST equ 0380h
+WM_PENWINLAST equ 038Fh
+WM_INTERNAL_COALESCE_FIRST equ 0390h ;Internal
+WM_COALESCE_FIRST equ 0390h
+WM_COALESCE_LAST equ 039Fh
+WM_MM_RESERVED_FIRST equ 03A0h ;Internal
+WM_MM_RESERVED_LAST equ 03DFh ;Internal
+WM_INTERNAL_COALESCE_LAST equ (WM_MM_RESERVED_FIRST+16) ;Internal
+WM_INTERNAL_DDE_FIRST equ 03E0h ;Internal
+WM_INTERNAL_DDE_LAST equ 03EFh ;Internal
+WM_CBT_RESERVED_FIRST equ 03F0h ;Internal
+WM_CBT_RESERVED_LAST equ 03FFh ;Internal
+WM_USER equ 0400h
+
+; Edit control messages
+
+EM_GETSEL equ (WM_USER+0)
+EM_SETSEL equ (WM_USER+1)
+EM_GETRECT equ (WM_USER+2)
+EM_SETRECT equ (WM_USER+3)
+EM_SETRECTNP equ (WM_USER+4)
+EM_SCROLL equ (WM_USER+5)
+EM_LINESCROLL equ (WM_USER+6)
+EM_GETMODIFY equ (WM_USER+8)
+EM_SETMODIFY equ (WM_USER+9)
+EM_GETLINECOUNT equ (WM_USER+10)
+EM_LINEINDEX equ (WM_USER+11)
+EM_SETHANDLE equ (WM_USER+12)
+EM_GETHANDLE equ (WM_USER+13)
+EM_GETTHUMB equ (WM_USER+14)
+EM_LINELENGTH equ (WM_USER+17)
+EM_REPLACESEL equ (WM_USER+18)
+EM_SETFONT equ (WM_USER+19)
+EM_GETLINE equ (WM_USER+20)
+EM_LIMITTEXT equ (WM_USER+21)
+EM_CANUNDO equ (WM_USER+22)
+EM_UNDO equ (WM_USER+23)
+EM_FMTLINES equ (WM_USER+24)
+EM_LINEFROMCHAR equ (WM_USER+25)
+EM_SETWORDBREAK equ (WM_USER+26)
+EM_SETTABSTOPS equ (WM_USER+27)
+EM_SETPASSWORDCHAR equ (WM_USER+28)
+EM_EMPTYUNDOBUFFER equ (WM_USER+29)
+EM_GETFIRSTVISIBLELINE equ (WM_USER+30)
+EM_SETREADONLY equ (WM_USER+31)
+EM_SETWORDBREAKPROC equ (WM_USER+32)
+EM_GETWORDBREAKPROC equ (WM_USER+33)
+EM_GETPASSWORDCHAR equ (WM_USER+34)
+EM_MSGMAX equ (WM_USER+35)
+
+; Button control messages
+
+BM_GETCHECK equ (WM_USER+0)
+BM_SETCHECK equ (WM_USER+1)
+BM_GETSTATE equ (WM_USER+2)
+BM_SETSTATE equ (WM_USER+3)
+BM_SETSTYLE equ (WM_USER+4)
+
+; Static control messages
+
+STM_SETICON equ (WM_USER+0)
+STM_GETICON equ (WM_USER+1)
+STM_MSGMAX equ (WM_USER+2)
+
+; Dialog box messages
+
+DM_GETDEFID equ (WM_USER+0)
+DM_SETDEFID equ (WM_USER+1)
+
+; Listbox messages
+
+LB_ADDSTRING equ (WM_USER+1)
+LB_INSERTSTRING equ (WM_USER+2)
+LB_DELETESTRING equ (WM_USER+3)
+LB_RESETCONTENT equ (WM_USER+5)
+LB_SETSEL equ (WM_USER+6)
+LB_SETCURSEL equ (WM_USER+7)
+LB_GETSEL equ (WM_USER+8)
+LB_GETCURSEL equ (WM_USER+9)
+LB_GETTEXT equ (WM_USER+10)
+LB_GETTEXTLEN equ (WM_USER+11)
+LB_GETCOUNT equ (WM_USER+12)
+LB_SELECTSTRING equ (WM_USER+13)
+LB_DIR equ (WM_USER+14)
+LB_GETTOPINDEX equ (WM_USER+15)
+LB_FINDSTRING equ (WM_USER+16)
+LB_GETSELCOUNT equ (WM_USER+17)
+LB_GETSELITEMS equ (WM_USER+18)
+LB_SETTABSTOPS equ (WM_USER+19)
+LB_GETHORIZONTALEXTENT equ (WM_USER+20)
+LB_SETHORIZONTALEXTENT equ (WM_USER+21)
+LB_SETCOLUMNWIDTH equ (WM_USER+22)
+LB_ADDFILE equ (WM_USER+23) ;Internal
+LB_SETTOPINDEX equ (WM_USER+24)
+LB_GETITEMRECT equ (WM_USER+25)
+LB_GETITEMDATA equ (WM_USER+26)
+LB_SETITEMDATA equ (WM_USER+27)
+LB_SELITEMRANGE equ (WM_USER+28)
+LB_SETANCHORINDEX equ (WM_USER+29) ;Internal
+LB_GETANCHORINDEX equ (WM_USER+30) ;Internal
+LB_SETCARETINDEX equ (WM_USER+31)
+LB_GETCARETINDEX equ (WM_USER+32)
+LB_SETITEMHEIGHT equ (WM_USER+33)
+LB_GETITEMHEIGHT equ (WM_USER+34)
+LB_FINDSTRINGEXACT equ (WM_USER+35)
+LBCB_CARETON equ (WM_USER+36) ;Internal
+LBCB_CARETOFF equ (WM_USER+37) ;Internal
+LB_MSGMAX equ (WM_USER+38)
+
+; Combo box messages
+
+CB_GETEDITSEL equ (WM_USER+0)
+CB_LIMITTEXT equ (WM_USER+1)
+CB_SETEDITSEL equ (WM_USER+2)
+CB_ADDSTRING equ (WM_USER+3)
+CB_DELETESTRING equ (WM_USER+4)
+CB_DIR equ (WM_USER+5)
+CB_GETCOUNT equ (WM_USER+6)
+CB_GETCURSEL equ (WM_USER+7)
+CB_GETLBTEXT equ (WM_USER+8)
+CB_GETLBTEXTLEN equ (WM_USER+9)
+CB_INSERTSTRING equ (WM_USER+10)
+CB_RESETCONTENT equ (WM_USER+11)
+CB_FINDSTRING equ (WM_USER+12)
+CB_SELECTSTRING equ (WM_USER+13)
+CB_SETCURSEL equ (WM_USER+14)
+CB_SHOWDROPDOWN equ (WM_USER+15)
+CB_GETITEMDATA equ (WM_USER+16)
+CB_SETITEMDATA equ (WM_USER+17)
+CB_GETDROPPEDCONTROLRECT equ (WM_USER+18)
+CB_SETITEMHEIGHT equ (WM_USER+19)
+CB_GETITEMHEIGHT equ (WM_USER+20)
+CB_SETEXTENDEDUI equ (WM_USER+21)
+CB_GETEXTENDEDUI equ (WM_USER+22)
+CB_GETDROPPEDSTATE equ (WM_USER+23)
+CB_FINDSTRINGEXACT equ (WM_USER+24)
+CB_MSGMAX equ (WM_USER+25)
+
+; DDE messages
+
+WM_DDE_FIRST equ 03E0h
+WM_DDE_INITIATE equ (WM_DDE_FIRST)
+WM_DDE_TERMINATE equ (WM_DDE_FIRST+1)
+WM_DDE_ADVISE equ (WM_DDE_FIRST+2)
+WM_DDE_UNADVISE equ (WM_DDE_FIRST+3)
+WM_DDE_ACK equ (WM_DDE_FIRST+4)
+WM_DDE_DATA equ (WM_DDE_FIRST+5)
+WM_DDE_REQUEST equ (WM_DDE_FIRST+6)
+WM_DDE_POKE equ (WM_DDE_FIRST+7)
+WM_DDE_EXECUTE equ (WM_DDE_FIRST+8)
+WM_DDE_LAST equ (WM_DDE_FIRST+8)
+
+;==================================================
+
+VLmopen = 0
+VLmpoff = 0
+VLmname equ <>
+VLmcont equ <>
+
+
+DGROUP group _DATA
+sBegin DATA
+assume ds:_DATA
+;extrn atomSysClass:word
+sEnd DATA
+
+ExternFP IsMenu
+IFNDEF WOW
+ ExternFP IsGDIObject
+ENDIF
+ExternFP IsWindow
+
+
+MESSAGE_START macro seg
+ _SwitchSeg <seg>,%VLseg
+
+IFNDEF WOW
+ ExternNP VHWND&seg
+ ExternNP VHWND0&seg
+ ExternNP VHMENU&seg
+ ExternNP VHMENU0&seg
+ ExternNP GHANDLE&seg
+ ExternNP GHANDLE0&seg
+ENDIF
+
+ExternNP LP&seg
+ExternNP LP0&seg
+ExternNP CLP&seg
+ExternNP CLP0&seg
+ExternNP LPFN&seg
+ExternNP LPFN0&seg
+ExternNP CLPSZ&seg
+ExternNP CLPSZ0&seg
+ExternNP Inval_Param_&seg
+
+hwnd equ <[bp].0eh>
+msg equ <[bp].0ch>
+wParam equ <[bp].0ah>
+lParam equ <dword ptr [bp]+06h>
+
+;cProc ValidateMessage,<FAR, PUBLIC>
+;ParmW hwnd
+;ParmW msg
+;ParmW wParam
+;ParmD lParam
+;cBegin
+public ValidateMessage
+ValidateMessage proc far
+
+ push bp
+ mov bp,sp
+
+ push offset VM_ERROR ; push error handler address
+
+ IFNDEF WOW
+ mov bx,hwnd ; validate the window handle
+ lcall VHWND
+ ENDIF
+
+ mov ax,msg
+ cmp ax,WM_USER
+ jb VM_COMMON
+
+ jmp SHORT VM_VALID ;
+
+ IFNDEF WOW
+ mov bx,_DATA
+ mov es,bx
+ assume es:_DATA
+ mov bx,hwnd ; ax = hwnd->pcls->atomClassName
+ mov bx,es:[bx].wndPcls
+ mov ax,es:[bx].uclsAtomClassName
+
+ mov cx,ICLS_CTL_MAX ; look up the class name
+ push di ; in the atomSysClass array
+ mov di,offset DGROUP:atomSysClass+(ICLS_CTL_MAX-1)*2
+ std
+ repnz scasw
+ pop di
+ cld
+ jnz VM_VALID ; Not special window class: just return.
+ mov bx,cx ; cx has ICLS index
+ add bx,bx
+ mov ax,msg
+ jmp word ptr cs:vmjump[bx]
+
+ ENDIF
+
+VM_VALID:
+ mov ax,1 ; return TRUE
+VM_EXIT:
+ pop dx ; strip off error handler address
+assume es:NOTHING
+
+ pop bp
+
+VM_ERROR:
+ retf 2+2+2+4 ; error handler jmps here, with clean stack
+
+ValidateMessage endp
+;
+; NOTE: The order of the following jump table is dependent
+; on the order of the ICLS_* values defined in user.h
+;
+
+IFNDEF WOW
+vmjump:
+ dw VM_BUTTON
+ errnz <ICLS_BUTTON-0>
+
+ dw VM_EDIT
+ errnz <ICLS_EDIT-1>
+
+ dw VM_STATIC
+ errnz <ICLS_STATIC-2>
+
+ dw VM_LISTBOX
+ errnz <ICLS_LISTBOX-3>
+
+ dw VM_VALID ; No scrollbar messages
+ errnz <ICLS_SCROLLBAR-4>
+
+ dw VM_COMBOBOX
+ errnz <ICLS_COMBOBOX-5>
+
+ENDIF
+
+endm ; MESSAGE_START
+
+MESSAGE_END macro
+ if VLmopen
+ ENDMESSAGE
+ endif
+ sEnd %VLseg
+endm
+
+;
+; MESSAGE - begins a structure declaration
+;
+MESSAGE macro name,opts
+
+ if VLmopen
+ ENDMESSAGE
+ endif
+
+ VLmopen=1
+ VLmpoff = 4
+ VLmjmp = 0
+
+ _MOpts <opts>
+
+concat VLmcont,<VLm>,name
+concat VLmname,name
+VLcbstruct = 0
+endm
+
+_MOpts macro opts
+ VLnogen = 0
+ VLnogenparm = 0
+ irp opt,<opts>
+ ifidni <opt>,<NOGEN>
+ VLnogen = 1
+ endif
+ ifidni <opt>,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogen = 1
+ endif
+ endif
+ ifidni <opt>,<POSTED>
+ endif
+ ifidni <opt>,<INTERNAL>
+ endif
+ endm
+ VLgen = 0
+
+endm
+;
+; ENDMESSAGE - Terminates a message declaration
+;
+ENDMESSAGE macro
+VLmopen = 0
+ ife VLmjmp
+ ;_print <Nothing to validate for >,%VLmname
+ else
+ jmp VM_VALID
+ endif
+ irp label,<VLmcont>
+label:
+ endm
+endm
+
+;
+; MESSAGE_CLASS - Announce
+;
+MESSAGE_CLASS macro cls
+VM_&cls:
+endm
+
+MESSAGE_CLASS_END macro
+ if VLmopen
+ ENDMESSAGE
+ endif
+
+ jmp VM_VALID
+endm
+
+_FlsMJmp2 macro name
+public PV_&name
+PV_&name:
+endm
+
+_FlsMJmp macro
+ife VLmjmp
+ _FlsMJmp2 %VLmname
+ cmp ax,VLmname
+ jnz VLmcont
+ VLmjmp = 1
+endif
+endm
+
+;
+; Increment mpOff: 4 -> 0 -> 2
+;
+_IncMpOff macro size
+
+ife VLmpoff-99
+ _print <Too many message parameters>
+ errnz 1
+else
+ ife size-2
+
+ ife VLmpoff-4
+ VLmpoff = 0
+ else
+ ife VLmpoff-0
+ VLmpoff = 2
+ else
+ VLmpoff = 99
+ endif
+ endif
+
+ else
+
+ ife VLmpoff-4
+ _print <First message parameter must be 16 bits>
+ errnz 1
+ else
+ ife VLmpoff-0
+ VLmpoff = 99
+ else
+ _print <Too many message parameters>
+ errnz 1
+ endif
+ endif
+
+ endif
+endif
+
+endm
+
+;
+;
+;
+_GenMP macro name,size,opts
+
+ VLnogenparm = 0
+
+ irp opt,<opts>
+ ifidni opt,<NOGEN>
+ VLnogenparm = 1
+ endif
+ ifidni opt,<DEBUGONLY>
+ ifndef DEBUG
+ VLnogenparm = 1
+ endif
+ endif
+ endm
+
+ VLgen = 1
+ if VLnogenparm or VLnogen
+ VLgen = 0
+ endif
+
+concat _P_&name,<[bp]+2+4+>,%VLmpoff
+
+_IncMpOff size
+endm
+
+;
+; Message parameter macros
+;
+MP_2 macro name,opts
+_GenMP <name>,2,<opts>
+endm
+
+MP_4 macro name,opts
+_GenMP <name>,4,<opts>
+endm
+
+MP_WMBZ macro name,opts
+_GenMP <name>,2,<opts>
+if VLgen
+ifdef DEBUG
+ _FlsMJmp
+ mov ax,_P_&name
+ or ax,ax
+ jz @F
+ mov bx,ERR_BAD_VALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+endif
+endif
+endm
+
+MP_LMBZ macro name,opts
+_GenMP <name>,4,<opts>
+if VLgen
+ifdef DEBUG
+ _FlsMJmp
+ mov bx,_P_&name
+ mov cx,_P_&name+2
+ or bx,cx
+ jz @F
+ mov ax,_P_&name
+ mov bx,ERR_BAD_DVALUE or ERR_WARNING
+ lcall Inval_Param_
+@@:
+endif ; DEBUG
+endif
+endm
+
+; Simple types
+
+MP_int equ <MP_2>
+MP_BOOL equ <MP_2>
+MP_LONG equ <MP_4>
+MP_DWORD equ <MP_4>
+MP_WORD equ <MP_2>
+
+MP_POINT equ <MP_4>
+
+MP_RVALUE macro val, min, max, opts
+ MP_2 <flags>,<opts>
+endm
+
+MP_VALUE macro val, max, opts
+ MP_2 <flags>,<opts>
+endm
+
+MP_FLAGS macro flags, valid, opts
+ MP_2 <flags>,<opts>
+endm
+
+; Handles
+;
+; Generate a GDI object validation macro.
+;
+; If nullok is 1, allow NULL.
+; min & max are the allowed OBJ_* range.
+; except, if specified, is an OBJ_* value within the range to reject.
+;
+_GenMPHGDI macro name,nullok,min,max,except
+ name &macro hObj,opts
+ local badobj
+ local objok
+ _GenMP <hObj>,2,<opts>
+ if VLgen
+ _FlsMJmp
+
+ IFNDEF WOW
+
+ if nullok
+ mov cx,_P_&&hObj
+ jcxz objok
+ push cx
+ else
+ push _P_&&hObj
+ endif
+ call IsGDIObject
+ ifnb <except>
+ cmp al,except
+ jz badobj
+ endif
+ ife min-max
+ cmp al,min
+ je objok
+ else
+ cmp al,min
+ jb badobj
+ cmp al,max
+ jbe objok
+ endif
+ badobj:
+ mov ax,_P_&&hObj
+ mov bx,ERR_BAD_HANDLE
+ lcall Inval_Param_
+ objok:
+
+ ENDIF
+
+ endif
+ &endm
+endm
+
+OBJ_PEN equ 1
+OBJ_BRUSH equ 2
+OBJ_FONT equ 3
+OBJ_PALETTE equ 4
+OBJ_BITMAP equ 5
+OBJ_RGN equ 6
+OBJ_DC equ 7
+OBJ_IC equ 8
+OBJ_DISABLED_DC equ 9
+OBJ_METADC equ 10
+OBJ_METAFILE equ 11
+
+_GenMPHGDI <MP_HDC>,0,OBJ_DC,OBJ_METAFILE
+_GenMPHGDI <MP_HDC0>,1,OBJ_DC,OBJ_METAFILE
+
+_GenMPHGDI <MP_HPEN>,0,OBJ_PEN,OBJ_PEN
+_GenMPHGDI <MP_HPEN0>,1,OBJ_PEN,OBJ_PEN
+
+_GenMPHGDI <MP_HBRUSH>,0,OBJ_BRUSH,OBJ_BRUSH
+_GenMPHGDI <MP_HBRUSH0>,1,OBJ_BRUSH,OBJ_BRUSH
+
+_GenMPHGDI <MP_HFONT>,0,OBJ_FONT,OBJ_FONT
+_GenMPHGDI <MP_HFONT0>,1,OBJ_FONT,OBJ_FONT
+
+_GenMPHGDI <MP_HPALETTE>,0,OBJ_PALETTE,OBJ_PALETTE
+_GenMPHGDI <MP_HPALETTE0>,1,OBJ_PALETTE,OBJ_PALETTE
+
+_GenMPHGDI <MP_HBITMAP>,0,OBJ_BITMAP,OBJ_BITMAP
+_GenMPHGDI <MP_HBITMAP0>,1,OBJ_BITMAP,OBJ_BITMAP
+
+_GenMPHGDI <MP_HRGN>,0,OBJ_RGN,OBJ_RGN
+_GenMPHGDI <MP_HRGN0>,1,OBJ_RGN,OBJ_RGN
+
+MP_HRGN01 equ <MP_2> ; hrgn, NULL, or (HRGN)1
+
+MP_HMENU macro hMenu,opts
+ _GenMP <hMenu>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov bx,_P_&hMenu
+ lcall VHMENU
+ ENDIF
+ _gensub VHMENU
+ @@:
+ endif
+endm
+
+MP_HMENU0 macro hMenu,opts
+ _GenMP <hMenu>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov bx,_P_&hMenu
+ lcall VHMENU0
+ ENDIF
+ _gensub VHMENU
+ endif
+endm
+
+MP_HWND macro hwnd,opts
+ _GenMP <hwnd>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov bx,_P_&hwnd
+ lcall VHWND
+ ENDIF
+ _gensub VHWND
+ endif
+endm
+
+MP_HWND0 macro hwnd,opts
+ _GenMP <hwnd>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov bx,_P_&hwnd
+ lcall VHWND0
+ ENDIF
+ _gensub VHWND
+ endif
+endm
+
+; Warn if the window handle is 0 or a bad window handle
+
+MP_HWNDW macro hwnd,opts
+ Local ZeroHandle
+ _GenMP <hwnd>,2,<opts>
+ifdef DEBUG
+ if VLgen
+ _FlsMJmp
+ mov cx,_P_&hwnd
+ mov ax, cx ;; Error reporting expects window handle in AX
+ jcxz ZeroHandle
+
+ jmp @F
+
+ IFNDEF WOW
+ push cx ;; Save window handle
+ push cx
+ call IsWindow
+ or ax,ax
+ pop ax ;; Resore the window handle to AX
+ jnz @F
+ ENDIF
+
+ZeroHandle:
+ ;; AX must have the bad Window handle
+ mov bx,ERR_BAD_HWND or ERR_WARNING
+ lcall Inval_Param_
+ @@:
+ endif
+endif
+endm
+
+; Warning only.
+
+MP_HWNDW0 macro hwnd,opts
+ _GenMP <hwnd>,2,<opts>
+ifdef DEBUG
+ if VLgen
+ _FlsMJmp
+
+ IFNDEF WOW
+ mov cx,_P_&hwnd
+ jcxz @F
+ push cx
+ push cx
+ call IsWindow
+ or ax,ax
+ pop ax
+ jnz @F
+ mov bx,ERR_BAD_HWND or ERR_WARNING
+ lcall Inval_Param_
+ @@:
+ ENDIF
+
+ endif
+endif
+endm
+
+MP_HWND01 macro hwnd,opts ; hwnd, 0, or 1
+ _GenMP <hwnd>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov bx,_P_&hwnd
+ cmp bx,1
+ jbe @F
+ lcall VHWND
+ ENDIF
+ _gensub VHWND
+ @@:
+ endif
+endm
+
+MP_HWNDCLIP equ <MP_HWND>
+
+MP_LHANDLE macro name,opts
+ _GenMP <name>,2,<opts>
+ if VLgen
+ _FlsMJmp
+ mov ax,_P_&name
+ or ax,ax
+ jnz @F
+ mov bx,ERR_BAD_LOCAL_HANDLE
+ lcall Inval_Param_
+ @@:
+ endif
+endm
+
+MP_LHANDLE0 equ <MP_2>
+
+MP_GHANDLE macro h,opts
+_GenMP <h>,2,<opts>
+if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov ax,_P_&h
+ lcall GHANDLE
+ ENDIF
+endif
+endm
+
+MP_GHANDLE0 macro h,opts
+_GenMP <h>,2,<opts>
+if VLgen
+ _FlsMJmp
+ IFNDEF WOW
+ mov ax,_P_&h
+ lcall GHANDLE0
+ ENDIF
+endif
+endm
+
+MP_GHANDLEDDE equ <MP_GHANDLE>
+MP_GHANDLEDDE0 equ <MP_GHANDLE0>
+
+MP_GHANDLEDDEW macro h,opts
+local GHexit
+_GenMP <h>,2,<opts>
+ifdef DEBUG
+ if VLgen
+ _FlsMJmp
+ mov ax,_P_&h
+ test al,0100b ; Reject GDT selectors
+ jz @F
+ cmp ax,0ffffh ; special case: -1 -> DS
+ jz GHexit
+ lar dx,ax ; is it a valid selector?
+ jz GHexit
+@@:
+ mov bx,ERR_BAD_GLOBAL_HANDLE or ERR_WARNING
+ lcall Inval_Param_
+GHexit:
+ endif
+endif
+endm
+
+MP_HICON equ <MP_GHANDLE>
+MP_HICON0 equ <MP_GHANDLE0>
+
+MP_HTASK equ <MP_GHANDLE>
+MP_HTASK0 equ <MP_GHANDLE0>
+
+; Pointers
+
+MP_LP macro lptr,opts
+_GenMP <lptr>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lptr
+ mov cx,_P_&lptr+2
+ mov bx,1
+ lcall LP
+ _gensub LP
+endif
+endm
+
+MP_CLP macro lp,opts
+_GenMP <lp>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,1
+ lcall CLP
+ _gensub LP
+endif
+endm
+
+MP_LP0 macro lp,opts
+_GenMP <lp>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,1
+ lcall LP0
+ _gensub LP
+endif
+endm
+
+MP_CLP0 macro lp,opts
+_GenMP <lp>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lp
+ mov cx,_P_&lp+2
+ mov bx,1
+ lcall CLP0
+ _gensub LP
+endif
+endm
+
+MP_LPBUFFERCNT equ <MP_LP>
+
+MP_CLPSTR macro lpsz,opts
+_GenMP <lpsz>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lpsz
+ mov cx,_P_&lpsz+2
+ mov bx,-1
+ lcall CLPSZ
+ _gensub LPSZ
+endif
+endm
+
+MP_CLPSTR0 macro lpsz,opts
+_GenMP <lpsz>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&lpsz
+ mov cx,_P_&lpsz+2
+ mov bx,-1
+ lcall CLPSZ0
+ _gensub LPSZ
+endif
+endm
+
+MP_LPSTRCB equ <MP_4> ; may be arbitrary 32-bit value
+MP_CLPSTRCB equ <MP_4>
+
+MP_CLPSTRLB equ <MP_4> ; may be arbitrary 32-bit value
+
+MP_CLPMSG0 equ <MP_CLP0>
+
+MP_LPRECT equ <MP_LP>
+MP_CLPRECT equ <MP_LP>
+
+MP_LPBUFFERX macro count, lpBuffer, opts
+ MP_int <count>,<opts>
+ MP_LP <lpBuffer>,<opts>
+endm
+
+MP_LPTSBUFFER0 macro cTabs, lpTabs, opts
+ MP_int <cTabs>,<opts>
+ MP_LP0 <lpTabs>,<opts>
+endm
+
+MP_LPWBUFFERX macro wCount, lpBuf, opts ;** lpBuf is int. buffer
+ MP_int <count>,<opts>
+ MP_LP <lpTabs>,<opts>
+endm
+
+MP_LPMEASUREITEMSTRUCT equ <MP_LP>
+MP_LPCREATESTRUCT equ <MP_LP>
+
+MP_CLPCOMPAREITEMSTRUCT equ <MP_CLP>
+MP_CLPDELETEITEMSTRUCT equ <MP_CLP>
+MP_CLPDRAWITEMSTRUCT equ <MP_CLP>
+MP_CLPMDICREATESTRUCT equ <MP_CLP>
+MP_CLP5POINTBUFFER equ <MP_CLP> ; array of 5 points
+
+; Function pointers
+
+MP_LPFNWORDBREAK0 macro pfn,opts
+_GenMP <pfn>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&pfn
+ mov cx,_P_&pfn+2
+ lcall LPFN0
+ _gensub LPFN
+endif
+endm
+
+MP_LPFNTIMER0 macro pfn,opts
+_GenMP <pfn>,4,<opts>
+if VLgen
+ _FlsMJmp
+ mov ax,_P_&pfn
+ mov cx,_P_&pfn+2
+ lcall LPFN0
+ _gensub LPFN
+endif
+endm
+
+; More types
+
+MP_ATOM equ <MP_2>
+MP_ATOM0 equ <MP_2>
+
+MP_BIVALUE macro val,v1,v2,opts
+ MP_2 <val>,<opts>
+endm
+
+MP_CBINDEX equ <MP_2>
+MP_CBINDEXFFFF equ <MP_2>
+MP_CBITEMHEIGHTFFFF equ <MP_2>
+MP_CHARINDEXFFFF equ <MP_2>
+MP_CHARVALUE equ <MP_2>
+MP_CID equ <MP_2>
+
+MP_CONST macro val, constant, opts ;** set to SMP_JOBSTATUS
+ MP_2 <val>,<opts>
+endm
+
+MP_CTRLID equ <MP_2>
+MP_EDITPOS equ <MP_2>
+MP_EMCHARPOS equ <MP_2>
+MP_EMLINE equ <MP_2>
+MP_EMLINEFFFF equ <MP_2>
+MP_EMLINEFFFF equ <MP_2>
+MP_EMCLINE equ <MP_2>
+
+MP_LBINDEX equ <MP_2>
+MP_LBINDEXFFFF equ <MP_2>
+
+MP_LBLPBUFFERINDEX macro wIndex, lpBuf, opts
+ MP_2 <wIndex>,<opts>
+ MP_4 <lpBuf>,<opts>
+endm
+
+MP_SHOWVALUE equ <MP_WORD>
+MP_SYSCOMMAND equ <MP_WORD>
+MP_VKEY equ <MP_WORD>
+
+MP_WMMENUSELECT macro idOrHandle, flags, opts
+ MP_2 idOrHMenu ; id or menu handle
+ MP_2 flags ; may be -1
+ MP_2 hMenu ; may be NULL
+endm
+
+MP_WMNEXTDLGCTL macro hwndOrFPrev, fHandle, opts ;** if lParam is 0 wParam is a flag
+ MP_2 <hwndOrFPrev>,<opts>
+ MP_BOOL <fHandle>,<opts>
+ MP_WMBZ lParamH,<opts>
+endm
diff --git a/private/mvdm/wow16/user/msutil.c b/private/mvdm/wow16/user/msutil.c
new file mode 100644
index 000000000..a7c623f1f
--- /dev/null
+++ b/private/mvdm/wow16/user/msutil.c
@@ -0,0 +1,332 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * MSUTIL.C
+ * WOW16 misc. routines
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+ * At this time, all we want is GetCharDimensions(), which the edit
+ * controls use.
+--*/
+
+/****************************************************************************/
+/* */
+/* MSUTIL.C - */
+/* */
+/* Miscellaneous Messaging Routines */
+/* */
+/****************************************************************************/
+
+#include "user.h"
+
+#ifndef WOW
+#include "winmgr.h"
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* CancelMode() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FAR PASCAL CancelMode(hwnd)
+
+register HWND hwnd;
+
+{
+ if (hwnd != NULL)
+ {
+ if (hwnd != hwndCapture)
+ CancelMode(hwndCapture);
+ SendMessage(hwnd, WM_CANCELMODE, 0, 0L);
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* BcastCopyString() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Copy strings which are going to be Broadcast into USER's DS to prevent
+ * EMS problems when switching tasks.
+ */
+
+HANDLE FAR PASCAL BcastCopyString(lParam)
+
+LONG lParam;
+
+{
+ LPSTR ptrbuf;
+ register int len;
+ register HANDLE hMem;
+
+ len = lstrlen((LPSTR)lParam) + 1;
+
+ if ((hMem = GlobalAlloc(GMEM_FIXED | GMEM_LOWER, (LONG)len)) == NULL)
+ return(NULL);
+
+ /* Get the address of the allocated block. */
+ ptrbuf = GlobalLock(hMem);
+ LCopyStruct((LPSTR)lParam, ptrbuf, len);
+
+ return(hMem);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* SendSizeMessages() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FAR PASCAL SendSizeMessage(hwnd, cmdSize)
+
+register HWND hwnd;
+WORD cmdSize;
+
+{
+ DWORD lParam;
+
+ lParam = MAKELONG(hwnd->rcClient.right - hwnd->rcClient.left,
+ hwnd->rcClient.bottom - hwnd->rcClient.top);
+ SendMessage(hwnd, WM_SIZE, cmdSize, lParam);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* AdjustWindowRect() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void USERENTRY AdjustWindowRect(lprc, style, fMenu)
+
+LPRECT lprc;
+LONG style;
+BOOL fMenu;
+
+{
+ AdjustWindowRectEx(lprc, style, fMenu, (DWORD)0);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* AdjustWindowRectEx() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void USERENTRY AdjustWindowRectEx(lprc, style, fMenu, dwExStyle)
+
+LPRECT lprc;
+LONG style;
+BOOL fMenu;
+DWORD dwExStyle;
+
+{
+ register int cx;
+ register int cy;
+
+ cx = cxBorder;
+ cy = cyBorder;
+
+ if (fMenu)
+ lprc->top -= rgwSysMet[SM_CYMENU];
+
+ /* Let us first decide if it is no-border, single border or dlg border */
+
+ /* Check if the WS_EX_DLGMODALFRAME bit is set, if so Dlg border */
+ if(dwExStyle & WS_EX_DLGMODALFRAME)
+ {
+ cx *= (CLDLGFRAME + 2*CLDLGFRAMEWHITE + 1);
+ cy *= (CLDLGFRAME + 2*CLDLGFRAMEWHITE + 1);
+ }
+ else
+ {
+ /* C6.0 will not generate jump table for this switch because of the
+ * range of values tested in case statemts;
+ */
+ switch (HIWORD(style) & HIWORD(WS_CAPTION))
+ {
+ case HIWORD(WS_CAPTION):
+ case HIWORD(WS_BORDER):
+ break; /* Single border */
+
+ case HIWORD(WS_DLGFRAME):
+ cx *= (CLDLGFRAME + 2*CLDLGFRAMEWHITE + 1);
+ cy *= (CLDLGFRAME + 2*CLDLGFRAMEWHITE + 1);
+ break; /* Dlg Border */
+
+ default: /* case 0 */
+ cx = 0; /* No border */
+ cy = 0;
+ break;
+ }
+ }
+
+
+ if((HIWORD(style) & HIWORD(WS_CAPTION)) == HIWORD(WS_CAPTION))
+ lprc->top -= (cyCaption - cyBorder);
+
+ if(cx || cy)
+ InflateRect(lprc, cx, cy);
+
+ /* Shouldn't we check if it has DLG frame and if so skip the following ?? */
+ if (style & WS_SIZEBOX)
+ InflateRect(lprc, cxSzBorder, cySzBorder);
+}
+#endif // WOW
+
+/*----------------------------------------------------------------------*/
+/* */
+/* GetCharDimensions(hDC, lpTextMetrics) */
+/* */
+/* This function loads the Textmetrics of the font currently */
+/* selected into the hDC and returns the Average char width of the */
+/* font; Pl Note that the AveCharWidth value returned by the Text */
+/* metrics call is wrong for proportional fonts. So, we compute them */
+/* On return, lpTextMetrics contains the text metrics of the */
+/* currently selected font. */
+/* */
+/*----------------------------------------------------------------------*/
+
+int FAR PASCAL GetCharDimensions(HDC hDC, LPTEXTMETRIC lpTextMetrics)
+{
+ int cxWidth;
+ int i;
+ char AveCharWidthData[52];
+
+ /* Store the System Font metrics info. */
+ GetTextMetrics(hDC, lpTextMetrics);
+
+ if (!(lpTextMetrics -> tmPitchAndFamily & 1)) /* If !variable_width font */
+ cxWidth = lpTextMetrics -> tmAveCharWidth;
+ else
+ {
+ /* Change from tmAveCharWidth. We will calculate a true average as
+ opposed to the one returned by tmAveCharWidth. This works better
+ when dealing with proportional spaced fonts. */
+
+ for (i=0;i<=25;i++)
+ AveCharWidthData[i] = (char)(i+(int)'a');
+ for (i=0;i<=25;i++)
+ AveCharWidthData[i+26] = (char)(i+(int)'A');
+ cxWidth = LOWORD(GetTextExtent(hDC,AveCharWidthData,52)) / 26;
+
+ cxWidth = (cxWidth + 1) / 2; // round up
+
+#if 0
+ {
+ char buf[80];
+ wsprintf(buf, "cxWidth = %d tmAveCharWidth %d\r\n", cxWidth, lpTextMetrics -> tmAveCharWidth);
+ OutputDebugString(buf);
+ }
+#endif
+
+ }
+
+ return(cxWidth);
+}
+
+#ifndef WOW
+/*----------------------------------------------------------------------*/
+/* */
+/* GetAveCharWidth(hDC) */
+/* */
+/* This function loads the Textmetrics of the font currently */
+/* selected into the hDC and returns the Average char width of the */
+/* font; Pl Note that the AveCharWidth value returned by the Text */
+/* metrics call is wrong for proportional fonts. So, we compute them */
+/* On return, lpTextMetrics contains the text metrics of the */
+/* currently selected font. */
+/* */
+/*----------------------------------------------------------------------*/
+
+int FAR PASCAL GetAveCharWidth(hDC)
+
+HDC hDC;
+
+{
+ TEXTMETRIC TextMetric;
+
+ return(GetCharDimensions(hDC, &TextMetric));
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* MB_FindLongestString() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD FAR PASCAL MB_FindLongestString()
+
+{
+ int i;
+ int iMaxLen = 0;
+ int iNewMaxLen;
+ PSTR *pszCurStr;
+ PSTR szMaxStr;
+ HDC hdc;
+ WORD wRetVal;
+
+ hdc = (HDC)GetScreenDC();
+
+ for(i = 0, pszCurStr = AllMBbtnStrings; i < MAX_SEB_STYLES; i++, pszCurStr++)
+ {
+ if((iNewMaxLen = lstrlen((LPSTR)*pszCurStr)) > iMaxLen)
+ {
+ iMaxLen = iNewMaxLen;
+ szMaxStr = *pszCurStr;
+ }
+ }
+
+ /* Find the longest string */
+
+ wRetVal = ((WORD)PSMGetTextExtent(hdc, (LPSTR)szMaxStr, lstrlen((LPSTR)szMaxStr))
+ + ((int)PSGetTextExtent(hdc, (LPSTR)szOneChar, 1) << 1));
+
+ InternalReleaseDC(hdc);
+
+ return(wRetVal);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* InitPwSB() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int * FAR PASCAL InitPwSB(hwnd)
+
+register HWND hwnd;
+
+{
+ register int *pw;
+
+ if (hwnd->rgwScroll)
+ /* If memory is already allocated, don't bother to do it again.
+ */
+ return(hwnd->rgwScroll);
+
+ if ((hwnd->rgwScroll = pw = (int *)UserLocalAlloc(ST_WND, LPTR, 7 * sizeof(int))) != NULL)
+ {
+ /* rgw[0] = 0; */ /* LPTR zeros all 6 words */
+ /* rgw[1] = 0; */
+ /* rgw[3] = 0; */
+ /* rgw[4] = 0; */
+ /* rgw[6] = 0; Enable/Disable Flags */
+ pw[2] = pw[5] = 100;
+ }
+
+ return(pw);
+}
+
+#endif // WOW
diff --git a/private/mvdm/wow16/user/net.c b/private/mvdm/wow16/user/net.c
new file mode 100644
index 000000000..3b8e62c89
--- /dev/null
+++ b/private/mvdm/wow16/user/net.c
@@ -0,0 +1,535 @@
+#include "user.h"
+#include "winnet.h"
+#include "netdlg.h"
+
+void FAR PASCAL WriteOutProfiles(void);
+
+#define IFNRESTORECONNECTION 23
+#define IERR_MustBeLoggedOnToConnect 5000
+
+#define CFNNETDRIVER 22 /* number of winnet entrypoints */
+#define CFNNETDRIVER2 35 /* ... in Windows 3.1 */
+
+extern FARPROC NEAR* pNetInfo; /* pointer to list of WINNET entrypoints */
+extern HANDLE hWinnetDriver;
+
+extern void FAR PASCAL WNetEnable( void );
+extern WORD FAR PASCAL WNetGetCaps2(WORD nIndex); /* winnet.asm */
+
+typedef struct _conntext
+ {
+ char szDevice[5];
+ char szPath[64];
+ char szPassword[32];
+ } CONNTEXT;
+
+
+char CODESEG szNet[] = "Network";
+char CODESEG szDialogs[] = "DefaultDialogs";
+
+HWND hwndTopNet = NULL;
+CONNTEXT FAR * lpctDlg;
+
+
+WORD API IWNetGetCaps(WORD nIndex)
+{
+ WORD wRet;
+
+ if (nIndex == 0xFFFF)
+ wRet = (WORD)hWinnetDriver;
+ else {
+ wRet = WNetGetCaps2(nIndex);
+
+ if (nIndex == WNNC_DIALOG) {
+ // turn off the drivers built in dialogs if
+ // win.ini [network] defaultdialogs=1
+ if (GetProfileInt(szNet, szDialogs, 0)) {
+ wRet &= ~(WNNC_DLG_ConnectDialog |
+ WNNC_DLG_DisconnectDialog |
+ WNNC_DLG_ConnectionDialog);
+ }
+ }
+ }
+ return wRet;
+}
+
+
+WORD API WNetErrorText(WORD wError,LPSTR lpsz, WORD cbMax)
+{
+ WORD wInternalError;
+ WORD cb;
+ char szT[40];
+
+ if ((wError == WN_NET_ERROR)
+ && (WNetGetError(&wInternalError) == WN_SUCCESS)
+ && (WNetGetErrorText(wInternalError,lpsz,&cbMax) == WN_SUCCESS))
+ {
+ return cbMax;
+ }
+ else
+ {
+ cb = LoadString(hInstanceWin,STR_NETERRORS+wError,lpsz,cbMax);
+ if (!cb)
+ {
+ LoadString(hInstanceWin,STR_NETERRORS,szT,sizeof(szT));
+ cb = wvsprintf(lpsz, szT, (LPSTR)&wError);
+ }
+ }
+ return cb;
+}
+
+#if 0
+
+/* CenterDialog() -
+ *
+ * Puts a dialog in an aesthetically pleasing place relative to its parent
+ */
+
+void near pascal CenterDialog(HWND hwnd)
+{
+ int x, y;
+
+ /* center the dialog
+ */
+ if (hwnd->hwndOwner)
+ {
+ x = hwnd->hwndOwner->rcWindow.left;
+ y = hwnd->hwndOwner->rcWindow.right;
+
+ x += rgwSysMet[SM_CXSIZE] + rgwSysMet[SM_CXFRAME];
+ y += rgwSysMet[SM_CYSIZE] + rgwSysMet[SM_CYFRAME];
+ }
+ else
+ {
+ x = (hwndDesktop->rcWindow.right
+ - (hwnd->rcWindow.right-hwnd->rcWindow.left)) / 2;
+
+ y = (hwndDesktop->rcWindow.bottom
+ - (hwnd->rcWindow.bottom-hwnd->rcWindow.top)) / 2;
+ }
+
+ SetWindowPos(hwnd,NULL,x,y,0,0,SWP_NOSIZE);
+}
+#endif
+
+/* stub dlg proc for status dialog
+ */
+
+BOOL CALLBACK ProgressDlgProc(HWND hwnd, WORD wMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+ // CenterDialog(hwnd);
+ break;
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* PasswordDlgProc() -
+ *
+ * Get a password for a network resource
+ */
+
+BOOL CALLBACK PasswordDlgProc(HWND hwnd, WORD wMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+ // CenterDialog(hwnd);
+ // Tell PenWin about this
+ if (lpRegisterPenAwareApp)
+ (*lpRegisterPenAwareApp)(1, TRUE);
+
+// SetDlgItemText(hwnd,IDD_DEV,lpctDlg->szDevice);
+ SetDlgItemText(hwnd,IDD_PATH,lpctDlg->szPath);
+ SendDlgItemMessage(hwnd, IDD_PASS, EM_LIMITTEXT, (WPARAM)(sizeof(lpctDlg->szPassword)-1), 0L);
+ SetTimer(hwnd, 1, 30 * 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ KillTimer(hwnd, 1);
+ wParam = (WPARAM)IDCANCEL;
+ goto TimeOut;
+
+ case WM_COMMAND:
+ switch ((WORD)wParam)
+ {
+ case IDD_PASS:
+ if (HIWORD(lParam) == EN_CHANGE)
+ KillTimer(hwnd, 1);
+ break;
+
+ case IDOK:
+ GetDlgItemText(hwnd,IDD_PASS,lpctDlg->szPassword, sizeof(lpctDlg->szPassword));
+ /*** FALL THRU ***/
+
+ case IDCANCEL:
+ case IDABORT:
+TimeOut:
+ if (lpRegisterPenAwareApp)
+ (*lpRegisterPenAwareApp)(1, FALSE);
+ EndDialog(hwnd, (int)wParam);
+ break;
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* RestoreDevice() -
+ *
+ * Restores a single device. If fStartup is true, a dialog box is
+ * posted to list the connections being made (this posting is deferred
+ * until here so that if no permanant connections exist, none are
+ * restored.
+ */
+
+WORD NEAR PASCAL RestoreDevice(HWND hwndParent, LPSTR lpDev, BOOL fStartup, CONNTEXT FAR *lpct)
+{
+ WORD wT;
+ WORD err;
+ WORD errorMode;
+ WORD result;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ result = WN_BAD_VALUE;
+ if (lstrlen(lpDev) > 4)
+ goto Done;
+
+ lstrcpy(lpct->szDevice,lpDev);
+
+ // If it's a drive that already exists then don't try to connect
+ // over it.
+ if (fStartup && *(lpDev+1) == ':') {
+ if (GetDriveType(*lpDev-'A')) {
+ // Drive already exists - don't stomp on it.
+ result = WN_CANCEL; // Don't report error.
+ goto Done;
+ }
+ }
+
+ if (fStartup)
+ goto GetFromINI;
+
+ wT = sizeof(lpct->szPath);
+ err = WNetGetConnection(lpct->szDevice,lpct->szPath,&wT);
+
+ if (err == WN_SUCCESS) {
+ result = WN_SUCCESS;
+ goto Done;
+ }
+
+ if (err == WN_DEVICE_ERROR) {
+ err = WNetCancelConnection(lpct->szDevice,FALSE);
+ if (err == WN_OPEN_FILES) {
+ // report a warning error to the user
+ WNetCancelConnection(lpct->szDevice,TRUE);
+ } else if (err != WN_SUCCESS) {
+ result = err;
+ goto Done;
+ }
+ } else if (err == WN_NOT_CONNECTED) {
+GetFromINI:
+ if (!GetProfileString(szNet,lpct->szDevice,"",lpct->szPath,sizeof(lpct->szPath))) {
+ result = WN_NOT_CONNECTED;
+ goto Done;
+ }
+ } else if (err != WN_CONNECTION_CLOSED) {
+ result = err;
+ goto Done;
+ }
+
+ // initially attempt with a blank password
+ //
+ lpct->szPassword[0] = 0;
+
+ // if on startup, show the status dialog
+ //
+ if (fStartup) {
+ if (!hwndTopNet) {
+ hwndTopNet = CreateDialog(hInstanceWin,IDD_CONNECTPROGRESS,NULL,ProgressDlgProc);
+ if (!hwndTopNet)
+ goto TryConnection;
+
+ ShowWindow(hwndTopNet,SW_SHOW);
+ }
+ SetDlgItemText(hwndTopNet,IDD_DEV,lpct->szDevice);
+ SetDlgItemText(hwndTopNet,IDD_PATH,lpct->szPath);
+ UpdateWindow(hwndTopNet);
+ hwndParent = hwndTopNet;
+ }
+
+TryConnection:
+
+ // lpct->szPath now contains the path
+ // and lpct->szPassword the password...
+ err = WNetAddConnection(lpct->szPath,lpct->szPassword,lpct->szDevice);
+
+ // if we're booting and the thing is connected, ignore
+ if (fStartup && err == WN_ALREADY_CONNECTED) {
+ result = WN_SUCCESS;
+ goto Done;
+ }
+
+ // if it was success or some other error, return
+ if (err != WN_BAD_PASSWORD && err != WN_ACCESS_DENIED) {
+ result = err;
+ goto Done;
+ }
+
+ // it was bad password. prompt the user for the correct password
+ lpctDlg = lpct;
+
+ switch (DialogBox(hInstanceWin,IDD_PASSWORD,hwndParent,PasswordDlgProc)) {
+ case -1:
+ result = WN_OUT_OF_MEMORY;
+ break;
+
+ case IDOK:
+ goto TryConnection;
+ break;
+
+ case IDCANCEL:
+ result = WN_CANCEL;
+ break;
+
+ case IDABORT:
+ result = WN_NET_ERROR;
+ break;
+ }
+
+Done:
+ SetErrorMode(errorMode);
+
+ return result;
+}
+
+/* ReportError() -
+ *
+ * Tell the user why the network connection failed
+ */
+
+void NEAR PASCAL ReportError(HWND hwndParent, WORD err, CONNTEXT FAR *lpct)
+{
+ char szTitle[80];
+ char szT[200];
+ char szError[150];
+ LPSTR rglp[2];
+
+ switch (err)
+ {
+ case WN_SUCCESS:
+ case WN_CANCEL:
+ case WN_NOT_CONNECTED:
+ return;
+ }
+
+ WNetErrorText(err,szT,sizeof(szT));
+ LoadString(hInstanceWin,STR_NETCONNMSG,szTitle,sizeof(szTitle));
+ rglp[0] = (LPSTR)lpct->szPath;
+ rglp[1] = (LPSTR)szT;
+ wvsprintf(szError,szTitle,(LPSTR)rglp);
+ LoadString(hInstanceWin,STR_NETCONNTTL,szTitle,sizeof(szTitle));
+ MessageBox(hwndParent,szError,szTitle,MB_OK|MB_ICONEXCLAMATION);
+}
+
+/* WNetRestoreConnection() -
+ *
+ * This function implements the "standard" restore-connection process.
+ * If the function is supported by the network driver, the driver is
+ * called instead. Otherwise, standard behaviour is supplied.
+ */
+
+typedef WORD (FAR PASCAL* PFN_NETRESTORECON)(HWND, LPSTR);
+
+WORD API WNetRestoreConnection(HWND hwndParent, LPSTR lpszDevice)
+{
+ static char CODESEG szInRestore[]="InRestoreNetConnect";
+ static char CODESEG szRestore[]="Restore";
+ char szDevice[10];
+ char szTitle[50];
+ char szMsg[255];
+ CONNTEXT ct;
+ WORD i;
+ WORD err;
+ BOOL bLoggedIn;
+
+ if (!pNetInfo)
+ return(WN_NOT_SUPPORTED);
+
+
+ if (WNetGetCaps(WNNC_CONNECTION) & WNNC_CON_RestoreConnection)
+ {
+ /* The device driver supports this call
+ */
+ return (*(PFN_NETRESTORECON)(pNetInfo[IFNRESTORECONNECTION - 1]))(hwndParent, lpszDevice);
+ }
+
+
+ /* the network does not support restore connections. do the default
+ */
+ if (HIWORD(lpszDevice))
+ return RestoreDevice(hwndParent,lpszDevice,FALSE,&ct);
+
+ // check to see if restoring net connects is enabled
+ if (!GetProfileInt(szNet,szRestore,1))
+ return(WN_SUCCESS);
+
+ /* Check if we previously aborted in the middle of restoring net
+ * connections.
+ */
+ if (GetProfileInt(szNet,szInRestore,0))
+ {
+ /* We died in the middle of restoring net connects. Inform user.
+ */
+ LoadString(hInstanceWin, STR_NETCRASHEDTITLE, szTitle, sizeof(szTitle));
+ LoadString(hInstanceWin, STR_NETCRASHEDMSG, szMsg, sizeof(szMsg));
+ err = MessageBox(NULL, szMsg, szTitle,
+ MB_ICONEXCLAMATION | MB_RETRYCANCEL | MB_SYSTEMMODAL);
+
+ if (err == IDCANCEL)
+ goto ExitRestoreNet;
+
+ }
+ WriteProfileString(szNet,szInRestore,"1");
+ /* Flush cache.
+ */
+ WriteOutProfiles();
+
+
+ szDevice[1]=':';
+ szDevice[2]=0;
+ bLoggedIn = TRUE;
+ for (i = 0; i < 26; i++)
+ {
+ szDevice[0] = (char)('A' + i);
+
+ err = GetDriveType(i);
+ if (err == DRIVE_FIXED || err == DRIVE_REMOVABLE)
+ {
+ /* Don't restore to system drives in case the user added a ram
+ * drive or new hard disk or something...
+ */
+ continue;
+ }
+ else
+ {
+ err = RestoreDevice(hwndParent,szDevice,TRUE,&ct);
+ }
+
+ hwndParent = hwndTopNet;
+
+ if ( (err == WN_NET_ERROR) &&
+ (WNetGetCaps (WNNC_NET_TYPE) == WNNC_NET_LanMan) &&
+ (WNetGetError (&err) == WN_SUCCESS) &&
+ (err == IERR_MustBeLoggedOnToConnect) )
+ {
+ bLoggedIn = FALSE;
+ break; /* if not logged on to LanMan, skip rest #8361 RAID */
+ }
+ else
+ // report error to user
+ ReportError(hwndParent,err,&ct);
+ }
+
+ /* Try to restore printer connections only if logged in. Fix for #8361
+ * [lalithar] - 11/14/91
+ */
+ if (bLoggedIn)
+ {
+ szDevice[0] = 'L';
+ szDevice[1] = 'P';
+ szDevice[2] = 'T';
+ szDevice[4] = 0;
+ for (i = 0; i < 3; i++)
+ {
+ szDevice[3] = (char)('1' + i);
+ err = RestoreDevice(hwndParent,szDevice,TRUE,&ct);
+ hwndParent = hwndTopNet;
+
+ ReportError(hwndParent,err,&ct);
+ }
+ }
+ if (hwndTopNet)
+ {
+ DestroyWindow(hwndTopNet);
+ hwndTopNet = NULL;
+ }
+
+ExitRestoreNet:
+ /* Write out a 0 since we are no longer restoring net connections.
+ */
+ WriteProfileString(szNet,szInRestore,NULL);
+
+ return(WN_SUCCESS);
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LW_InitNetInfo() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FAR PASCAL LW_InitNetInfo(void)
+{
+ int i;
+ char szDriver[64];
+ char szFile[32];
+ char szSection[32];
+
+ pNetInfo=NULL;
+
+ if (!LoadString(hInstanceWin,STR_NETDRIVER,szDriver,sizeof(szDriver)))
+ return;
+ if (!LoadString(hInstanceWin,STR_BOOT,szSection,sizeof(szSection)))
+ return;
+ if (!LoadString(hInstanceWin,STR_SYSTEMINI,szFile,sizeof(szFile)))
+ return;
+
+ /* look for in the tag NETWORK.DRV, with that as the output and the
+ * default string...
+ */
+ GetPrivateProfileString(szSection,szDriver,szDriver,szDriver,
+ sizeof(szDriver),szFile);
+
+ /* if entry present, but blank, punt
+ */
+ if (!*szDriver)
+ return;
+
+ hWinnetDriver = LoadLibrary(szDriver);
+ if (hWinnetDriver < HINSTANCE_ERROR)
+ return;
+
+ pNetInfo = (FARPROC NEAR*)UserLocalAlloc(ST_STRING,LPTR,sizeof(FARPROC)*CFNNETDRIVER2);
+ if (!pNetInfo)
+ {
+ FreeLibrary(hWinnetDriver);
+ return;
+ }
+
+ for (i=0; i<CFNNETDRIVER; i++)
+ {
+ pNetInfo[i]=GetProcAddress(hWinnetDriver,MAKEINTRESOURCE(i+1));
+ }
+
+ if (WNetGetCaps(WNNC_SPEC_VERSION) >= 0x30D)
+ {
+ for (;i<CFNNETDRIVER2; i++)
+ {
+ pNetInfo[i]=GetProcAddress(hWinnetDriver,MAKEINTRESOURCE(i+1));
+ }
+ }
+
+ WNetEnable();
+}
diff --git a/private/mvdm/wow16/user/netdlg.h b/private/mvdm/wow16/user/netdlg.h
new file mode 100644
index 000000000..576099b2e
--- /dev/null
+++ b/private/mvdm/wow16/user/netdlg.h
@@ -0,0 +1,17 @@
+
+/* netdlg.h -
+ *
+ * constants for network dialogs
+ */
+
+#ifdef RC_INVOKED
+#define IDD_CONNECTPROGRESS 100
+#define IDD_PASSWORD 101
+#else
+#define IDD_CONNECTPROGRESS ((LPSTR)100L)
+#define IDD_PASSWORD ((LPSTR)101L)
+#endif
+
+#define IDD_DEV 100
+#define IDD_PASS 101
+#define IDD_PATH 102
diff --git a/private/mvdm/wow16/user/readme.txt b/private/mvdm/wow16/user/readme.txt
new file mode 100644
index 000000000..bd26921bf
--- /dev/null
+++ b/private/mvdm/wow16/user/readme.txt
@@ -0,0 +1,11 @@
+Building user16:
+
+If you don't have USER sources that match the build you're testing on,
+and you're building x86 free, you will want to use:
+
+nmake NONX86=1
+
+which will build a version which does not embed copies of user32.dll
+code into user.exe.
+
+When you're building checked or on RISC, this is a non-issue.
diff --git a/private/mvdm/wow16/user/rmcreate.c b/private/mvdm/wow16/user/rmcreate.c
new file mode 100644
index 000000000..4fcd3d40b
--- /dev/null
+++ b/private/mvdm/wow16/user/rmcreate.c
@@ -0,0 +1,316 @@
+
+/****************************************************************************/
+/* */
+/* RMCREATE.C - */
+/* */
+/* Resource creating Routines. */
+/* */
+/****************************************************************************/
+
+#define RESOURCESTRINGS
+#include "user.h"
+
+#ifdef NOT_USED_ANYMORE
+#define NSMOVE 0x0010
+
+HGLOBAL FAR PASCAL DirectResAlloc(HGLOBAL, WORD, WORD);
+
+
+/******************************************************************************
+**
+** CreateCursorIconIndirect()
+**
+** This is the common function called by CreateCursor and
+** CreateIcon()
+** DirectResAlloc() is called instead of GlobalAlloc() because
+** the Icons/Cursors created by one instance of the app can be used in
+** a WNDCLASS structure to Register a class which will be used by other
+** instances of the app and when the instance that created the icons/
+** cursors terminates, the resources SHOULD NOT BE FREED; If GlobalAlloc()
+** is used this is what will happen; At the same time, when the last
+** instance also dies, the memory SHOULD BE FREED; To achieve this,
+** DirectResAlloc() is used instead of GlobalAlloc();
+**
+******************************************************************************/
+
+HGLOBAL CALLBACK CreateCursorIconIndirect(HINSTANCE hInstance,
+ LPCURSORSHAPE lpHeader,
+ CONST VOID FAR* lpANDplane,
+ CONST VOID FAR* lpXORplane)
+{
+ register WORD ANDmaskSize;
+ register WORD XORmaskSize;
+ WORD wTotalSize;
+ HRSRC hResource;
+ LPSTR lpRes;
+
+
+ ANDmaskSize = lpHeader -> cbWidth * lpHeader -> cy;
+ XORmaskSize = (((lpHeader -> cx * lpHeader -> BitsPixel + 0x0F) & ~0x0F)
+ >> 3) * lpHeader -> cy * lpHeader -> Planes;
+
+ /* It is assumed that Cursor/Icon size won't be more than 64K */
+ wTotalSize = sizeof(CURSORSHAPE) + ANDmaskSize + XORmaskSize;
+
+#ifdef NEVER
+ /* Allocate the required memory */
+ if((hResource = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE,
+ (DWORD)wTotalSize)) == NULL)
+ return(NULL);
+#else
+ /* Let us preserve the long pointers */
+ SwapHandle(&lpANDplane);
+ SwapHandle(&lpXORplane);
+
+ hResource = DirectResAlloc(hInstance, NSMOVE, wTotalSize);
+
+ /* Let us restore the long pointers */
+ SwapHandle(&lpANDplane);
+ SwapHandle(&lpXORplane);
+
+ if(hResource == NULL)
+ return(NULL);
+#endif
+
+ if(!(lpRes = GlobalLock(hResource)))
+ {
+ GlobalFree(hResource);
+ return(NULL);
+ }
+
+ LCopyStruct((LPSTR)lpHeader, lpRes, sizeof(CURSORSHAPE));
+ lpRes += sizeof(CURSORSHAPE);
+ LCopyStruct(lpANDplane, lpRes, ANDmaskSize);
+ lpRes += ANDmaskSize;
+ LCopyStruct(lpXORplane, lpRes, XORmaskSize);
+
+ GlobalUnlock(hResource);
+ return(hResource);
+}
+
+/******************************************************************************
+**
+** CreateCursor()
+**
+** This is the API call to create a Cursor "on-the-fly";
+**
+*******************************************************************************/
+
+HCURSOR API ICreateCursor(hInstance, iXhotspot, iYhotspot, iWidth,
+ iHeight, lpANDplane, lpXORplane)
+
+HINSTANCE hInstance;
+int iXhotspot;
+int iYhotspot;
+int iWidth;
+int iHeight;
+CONST VOID FAR* lpANDplane;
+CONST VOID FAR* lpXORplane;
+{
+ CURSORSHAPE Header;
+
+ Header.xHotSpot = iXhotspot;
+ Header.yHotSpot = iYhotspot;
+ Header.cx = iWidth;
+ Header.cy = iHeight;
+ Header.Planes = 1; /* Cursors are only monochrome */
+ Header.BitsPixel = 1;
+ Header.cbWidth = ((iWidth + 0x0F) & ~0x0F) >> 3;
+
+ return(CreateCursorIconIndirect(hInstance, &Header,
+ lpANDplane, lpXORplane));
+}
+
+/******************************************************************************
+**
+** CreateIcon()
+**
+** This is the API call to create an Icon "on-the-fly";
+**
+*******************************************************************************/
+
+HICON API ICreateIcon(hInstance, iWidth, iHeight, bPlanes,
+ bBitsPixel, lpANDplane, lpXORplane)
+
+HINSTANCE hInstance;
+int iWidth;
+int iHeight;
+BYTE bPlanes;
+BYTE bBitsPixel;
+CONST VOID FAR* lpANDplane;
+CONST VOID FAR* lpXORplane;
+{
+ CURSORSHAPE Header;
+
+ Header.xHotSpot = iWidth/2;
+ Header.yHotSpot = iHeight/2;
+ Header.cx = iWidth;
+ Header.cy = iHeight;
+ Header.Planes = bPlanes; /* Icons can be in color */
+ Header.BitsPixel = bBitsPixel;
+ Header.cbWidth = ((iWidth + 0x0F) & ~0x0F) >> 3;
+
+ return(CreateCursorIconIndirect(hInstance, (LPCURSORSHAPE)&Header,
+ lpANDplane, lpXORplane));
+}
+
+/******************************************************************************
+ *
+ * DestroyIcon(hIcon)
+ * This can be called to delete only those icons created "on the fly"
+ * using the CreateIcon() function
+ * Returns:
+ * TRUE if successful, FALSE otherwise.
+ *
+ ******************************************************************************/
+
+BOOL API IDestroyIcon(HICON hIcon)
+
+{
+ return(!FreeResource(hIcon));
+}
+
+/******************************************************************************
+ *
+ * DestroyCursor(hIcon)
+ * This can be called to delete only those icons created "on the fly"
+ * using the CreateIcon() function
+ * Returns:
+ * TRUE if successful, FALSE otherwise.
+ *
+ ******************************************************************************/
+
+BOOL API IDestroyCursor(HCURSOR hCursor)
+
+{
+ if (hCursor == hCurCursor)
+ {
+ /* #12068: if currently selected cursor resore arrow cursor and RIP [lalithar] */
+ SetCursor(hCursNormal);
+ DebugErr(DBF_ERROR, "DestroyCursor: Destroying current cursor");
+ }
+ return(!FreeResource(hCursor));
+}
+
+#endif /* NOT_USED_ANYMORE */
+
+
+/****************************************************************************
+**
+** DumpIcon()
+**
+** This function is called to get the details of a given Icon;
+**
+** The caller must lock hIcon using LockResource() and pass the pointer
+** thro lpIcon; This is the pointer to the header structure;
+** Thro lpHeaderSize, the size of header is returned;
+** Thro lplpANDplane and lplpXORplane pointers to actual bit info is
+** returned;
+** This function returns a DWORD with the size of AND plane in loword
+** and size of XOR plane in hiword;
+**
+****************************************************************************/
+
+DWORD CALLBACK DumpIcon(LPSTR lpIcon,
+ WORD FAR * lpHeaderSize,
+ LPSTR FAR * lplpANDplane,
+ LPSTR FAR * lplpXORplane)
+
+{
+ register WORD ANDmaskSize;
+ register WORD XORmaskSize;
+ LPCURSORSHAPE lpHeader;
+
+ *lpHeaderSize = sizeof(CURSORSHAPE);
+
+ if(!lpIcon)
+ return((DWORD)0);
+
+ lpHeader = (LPCURSORSHAPE)lpIcon;
+
+ ANDmaskSize = lpHeader -> cbWidth * lpHeader -> cy;
+ XORmaskSize = (((lpHeader -> cx * lpHeader -> BitsPixel + 0x0F) & ~0x0F)
+ >> 3) * lpHeader -> cy * lpHeader -> Planes;
+
+ *lplpANDplane = (lpIcon += sizeof(CURSORSHAPE));
+ *lplpXORplane = (lpIcon + ANDmaskSize);
+
+ return(MAKELONG(ANDmaskSize, XORmaskSize));
+}
+
+#ifdef NOT_USED_ANYMORE
+/****************************************************************************
+**
+** GetInternalIconHeader(lpIcon, lpDestBuff)
+**
+** This function has been added to fix bug #6351 with cornerstone
+** XTRA_LARGE display driver. (It uses 64 X 64 Icons; Internally we
+** keep the size as 32 X 32. Progman must know this internal size sothat
+** it can tell that to WinOldApp.
+****************************************************************************/
+
+void API IGetInternalIconHeader(LPSTR lpIcon, LPSTR lpDestBuff)
+{
+ LCopyStruct(lpIcon, lpDestBuff, sizeof(CURSORSHAPE));
+}
+#endif /* NOT_USED_ANYMORE */
+
+/* APIs to make a copy of an icon or cursor */
+
+HICON API ICopyIcon(HINSTANCE hInstance, HICON hIcon)
+{
+ LPSTR lpAND;
+ LPSTR lpXOR;
+ LPSTR lpIcon;
+ WORD wHeaderSize;
+ HICON hIconCopy;
+ LPCURSORSHAPE lpHeader;
+
+ lpIcon = LockResource(hIcon);
+ if (!lpIcon)
+ return NULL;
+
+ lpHeader = (LPCURSORSHAPE)lpIcon;
+
+ DumpIcon(lpIcon, &wHeaderSize, &lpAND, &lpXOR);
+
+ hIconCopy = CreateIcon(hInstance,
+ lpHeader->cx,
+ lpHeader->cy,
+ lpHeader->Planes,
+ lpHeader->BitsPixel,
+ lpAND, lpXOR);
+
+ UnlockResource(hIcon);
+
+ return(hIconCopy);
+}
+
+HCURSOR API ICopyCursor(HINSTANCE hInstance, HICON hCursor)
+{
+ LPSTR lpAND;
+ LPSTR lpXOR;
+ LPSTR lpCursor;
+ WORD wHeaderSize;
+ HCURSOR hCursorCopy;
+ LPCURSORSHAPE lpHeader;
+
+ lpCursor = LockResource(hCursor);
+ if (!lpCursor)
+ return NULL;
+
+ lpHeader = (LPCURSORSHAPE)lpCursor;
+
+ DumpIcon(lpCursor, &wHeaderSize, &lpAND, &lpXOR);
+
+ hCursorCopy = CreateCursor(hInstance,
+ lpHeader->xHotSpot,
+ lpHeader->yHotSpot,
+ lpHeader->cx,
+ lpHeader->cy,
+ lpAND, lpXOR);
+
+ UnlockResource(hCursor);
+
+ return(hCursorCopy);
+}
diff --git a/private/mvdm/wow16/user/rmload.c b/private/mvdm/wow16/user/rmload.c
new file mode 100644
index 000000000..1e66e1621
--- /dev/null
+++ b/private/mvdm/wow16/user/rmload.c
@@ -0,0 +1,1755 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * RMLOAD.C
+ * WOW16 user resource services
+ *
+ * History:
+ *
+ * Created 12-Apr-1991 by Nigel Thompson (nigelt)
+ * Much hacked about version of the Win 3.1 rmload.c source
+ * It doesn't attempt any device driver resource loading
+ * or do anything to support Win 2.x apps.
+ *
+ * Revised 19-May-1991 by Jeff Parsons (jeffpar)
+ * IFDEF'ed everything except LoadString; because of the client/server
+ * split in USER32, most resources are copied to the server's context and
+ * freed in the client's, meaning the client no longer gets a handle to
+ * a global memory object. We could give it one, but it would be a separate
+ * object, which we would have to keep track of, and which would be difficult
+ * to keep in sync with the server's copy if changes were made.
+--*/
+
+/****************************************************************************/
+/* */
+/* RMLOAD.C - */
+/* */
+/* Resource Loading Routines. */
+/* */
+/****************************************************************************/
+
+#define RESOURCESTRINGS
+#include "user.h"
+#include "multires.h"
+
+//
+// We define certain things here because including mvdm\inc\*.h files here
+// will lead to endless mess.
+//
+
+DWORD API NotifyWow(WORD, LPBYTE);
+
+typedef struct _LOADACCEL16 { /* ldaccel */
+ WORD hInst;
+ WORD hAccel;
+ LPBYTE pAccel;
+ DWORD cbAccel;
+} LOADACCEL16, FAR *PLOADACCEL16;
+
+#define FUN_LOADACCELERATORS 177 //
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadAccelerators() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HACCEL API ILoadAccelerators(HINSTANCE hInstance, LPCSTR lpszAccName)
+{
+ HRSRC hrl;
+ HACCEL hAccel = NULL;
+ LOADACCEL16 loadaccel;
+
+ hrl = FindResource(hInstance, lpszAccName, RT_ACCELERATOR);
+#ifdef WOW
+ if (hrl) {
+ hAccel = (HACCEL)LoadResource(hInstance, hrl);
+ if (hAccel) {
+
+ // create 32bit accelerator and 16-32 alias.
+
+ loadaccel.hInst = (WORD)hInstance;
+ loadaccel.hAccel = (WORD)hAccel;
+ loadaccel.pAccel = (LPBYTE)LockResource(hAccel);
+ loadaccel.cbAccel = (DWORD)SizeofResource(hInstance, hrl);
+
+ if (NotifyWow(FUN_LOADACCELERATORS, (LPBYTE)&loadaccel)) {
+ UnlockResource(hAccel);
+ }
+ else {
+ UnlockResource(hAccel);
+ hAccel = NULL;
+ }
+ }
+
+ }
+
+ return (hAccel);
+#else
+ if (!hrl)
+ return NULL;
+
+ return (HACCEL)LoadResource(hInstance, hrl);
+#endif
+}
+
+
+
+int API ILoadString(h16Task, wID, lpBuffer, nBufferMax)
+
+HANDLE h16Task;
+WORD wID;
+LPSTR lpBuffer;
+register int nBufferMax;
+
+{
+ HANDLE hResInfo;
+ HANDLE hStringSeg;
+ LPSTR lpsz;
+ register int cch, i;
+
+ /* Make sure the parms are valid. */
+ if (!lpBuffer || (nBufferMax-- == 0))
+ return(0);
+
+ cch = 0;
+
+ /* String Tables are broken up into 16 string segments. Find the segment
+ * containing the string we are interested in.
+ */
+ if (hResInfo = FindResource(h16Task, (LPSTR)((LONG)((wID >> 4) + 1)), RT_STRING))
+ {
+ /* Load that segment. */
+ hStringSeg = LoadResource(h16Task, hResInfo);
+
+ /* Lock the resource. */
+ if (lpsz = (LPSTR)LockResource(hStringSeg))
+ {
+ /* Move past the other strings in this segment. */
+ wID &= 0x0F;
+ while (TRUE)
+ {
+ cch = *((BYTE FAR *)lpsz++);
+ if (wID-- == 0)
+ break;
+ lpsz += cch;
+ }
+
+ /* Don't copy more than the max allowed. */
+ if (cch > nBufferMax)
+ cch = nBufferMax;
+
+ /* Copy the string into the buffer. */
+ LCopyStruct(lpsz, lpBuffer, cch);
+
+ GlobalUnlock(hStringSeg);
+
+ /* BUG: If we free the resource here, we will have to reload it
+ * immediately for many apps with sequential strings.
+ * Force it to be discardable however because non-discardable
+ * string resources make no sense. Chip
+ */
+ GlobalReAlloc(hStringSeg, 0L,
+ GMEM_MODIFY | GMEM_MOVEABLE | GMEM_DISCARDABLE);
+ }
+ }
+
+ /* Append a NULL. */
+ lpBuffer[cch] = 0;
+
+ return(cch);
+}
+
+
+#ifdef NEEDED
+
+#define DIB_RGB_COLORS 0
+
+HBITMAP FAR PASCAL ConvertBitmap(HBITMAP hBitmap);
+HANDLE NEAR PASCAL LoadDIBCursorIconHandler(HANDLE, HANDLE, HANDLE, BOOL);
+WORD FAR PASCAL GetIconId(HANDLE, LPSTR);
+HBITMAP FAR PASCAL StretchBitmap(int, int, int, int, HBITMAP, BYTE, BYTE);
+WORD NEAR PASCAL StretchIcon(LPCURSORSHAPE, WORD, HBITMAP, BOOL);
+WORD NEAR PASCAL SizeReqd(BOOL, WORD, WORD, BOOL, int, int);
+WORD NEAR PASCAL CrunchAndResize(LPCURSORSHAPE, BOOL, BOOL, BOOL, BOOL);
+HANDLE FAR PASCAL LoadCursorIconHandler2(HANDLE, LPCURSORSHAPE, WORD);
+HANDLE FAR PASCAL LoadDIBCursorIconHandler2(HANDLE, LPCURSORSHAPE, WORD, BOOL);
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadIconHandler() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HICON FAR PASCAL LoadIconHandler(hIcon, fNewFormat)
+
+HICON hIcon;
+BOOL fNewFormat;
+
+{
+ LPCURSORSHAPE lpIcon;
+ WORD wSize;
+
+ dprintf(7,"LoadIconHandler");
+ wSize = (WORD)GlobalSize(hIcon);
+ lpIcon = (LPCURSORSHAPE)(GlobalLock(hIcon));
+
+ if (fNewFormat)
+ return(LoadDIBCursorIconHandler2(hIcon, lpIcon, wSize, TRUE));
+ else
+ return(LoadCursorIconHandler2(hIcon, lpIcon, wSize));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* FindIndividualResource() */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE NEAR PASCAL FindIndividualResource(register HANDLE hResFile,
+ LPSTR lpszName,
+ LPSTR lpszType)
+
+{
+ WORD idIcon;
+ register HANDLE h;
+
+ dprintf(7,"FindIndividualResource");
+ /* Check if the resource is to be taken from the display driver.
+ * If so, check the driver version; If the resource is to be taken from
+ * the application, check the app version.
+ */
+
+ if ((lpszType != RT_BITMAP) && ((LOWORD(GetExpWinVer(hResFile)) >= VER)))
+ {
+ /* Locate the directory resource */
+ h = SplFindResource(hResFile, lpszName, (LPSTR)(lpszType + DIFFERENCE));
+ if (h == NULL)
+ return((HANDLE)0);
+
+ /* Load the directory resource */
+ h = LoadResource(hResFile, h);
+
+ /* Get the name of the matching resource */
+ idIcon = GetIconId(h, lpszType);
+
+ /* NOTE: Don't free the (discardable) directory resource!!! - ChipA */
+ /*
+ * We should not call SplFindResource here, because idIcon is
+ * internal to us and GetDriverResourceId won't know how tomap it.
+ */
+ return(FindResource(hResFile, MAKEINTRESOURCE(idIcon), lpszType));
+ }
+ else
+ /* It is an Old app; The resource is in old format */
+ return(SplFindResource(hResFile, lpszName, lpszType));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* GetBestFormIcon() */
+/* */
+/* Among the different forms of Icons present, choose the one that */
+/* matches the PixelsPerInch values and the number of colors of the */
+/* current display. */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD NEAR PASCAL GetBestFormIcon(LPRESDIR ResDirPtr,
+ WORD ResCount)
+
+{
+ register WORD wIndex;
+ register WORD ColorCount;
+ WORD MaxColorCount;
+ WORD MaxColorIndex;
+ WORD MoreColorCount;
+ WORD MoreColorIndex;
+ WORD LessColorCount;
+ WORD LessColorIndex;
+ WORD DevColorCount;
+
+ dprintf(7,"GetBestFormIcon");
+ /* Initialse all the values to zero */
+ MaxColorCount = MaxColorIndex = MoreColorCount =
+ MoreColorIndex = LessColorIndex = LessColorCount = 0;
+
+ /* get number of colors on device. if device is very colorful,
+ ** set to a high number without doing meaningless 1<<X operation.
+ */
+ if (oemInfo.ScreenBitCount >= 16)
+ DevColorCount = 32000;
+ else
+ DevColorCount = 1 << oemInfo.ScreenBitCount;
+
+ for (wIndex=0; wIndex < ResCount; wIndex++, ResDirPtr++)
+ {
+ /* Check for the number of colors */
+ if ((ColorCount = (ResDirPtr->ResInfo.Icon.ColorCount)) <= DevColorCount)
+ {
+ if (ColorCount > MaxColorCount)
+ {
+ MaxColorCount = ColorCount;
+ MaxColorIndex = wIndex;
+ }
+ }
+
+ /* Check for the size */
+ /* Match the pixels per inch information */
+ if ((ResDirPtr->ResInfo.Icon.Width == (BYTE)oemInfo.cxIcon) &&
+ (ResDirPtr->ResInfo.Icon.Height == (BYTE)oemInfo.cyIcon))
+ {
+ /* Matching size found */
+ /* Check if the color also matches */
+ if (ColorCount == DevColorCount)
+ return(wIndex); /* Exact match found */
+
+ if (ColorCount < DevColorCount)
+ {
+ /* Choose the one with max colors, but less than reqd */
+ if (ColorCount > LessColorCount)
+ {
+ LessColorCount = ColorCount;
+ LessColorIndex = wIndex;
+ }
+ }
+ else
+ {
+ if ((LessColorCount == 0) && (ColorCount < MoreColorCount))
+ {
+ MoreColorCount = ColorCount;
+ MoreColorIndex = wIndex;
+ }
+ }
+ }
+ }
+
+ /* Check if we have a correct sized but with less colors than reqd */
+ if (LessColorCount)
+ return(LessColorIndex);
+
+ /* Check if we have a correct sized but with more colors than reqd */
+ if (MoreColorCount)
+ return(MoreColorIndex);
+
+ /* Check if we have one that has maximum colors but less than reqd */
+ if (MaxColorCount)
+ return(MaxColorIndex);
+
+ return(0);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* GetBestFormCursor() */
+/* */
+/* Among the different forms of cursors present, choose the one that */
+/* matches the width and height defined by the current display driver. */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD NEAR PASCAL GetBestFormCursor(LPRESDIR ResDirPtr,
+ WORD ResCount)
+
+{
+ register WORD wIndex;
+
+ dprintf(7,"GetBestFormCursor");
+ for (wIndex=0; wIndex < ResCount; wIndex++, ResDirPtr++)
+ {
+ /* Match the Width and Height of the cursor */
+ if ((ResDirPtr->ResInfo.Cursor.Width == oemInfo.cxCursor) &&
+ ((ResDirPtr->ResInfo.Cursor.Height >> 1) == oemInfo.cyCursor))
+ return(wIndex);
+ }
+
+ return(0);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* GetIconId() */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD FAR PASCAL GetIconId(hRes, lpszType)
+
+HANDLE hRes;
+LPSTR lpszType;
+
+{
+ WORD w;
+ LPRESDIR ResDirPtr;
+ LPNEWHEADER DataPtr;
+ register WORD RetIndex;
+ register WORD ResCount;
+
+ dprintf(7,"GetIconId");
+ if ((DataPtr = (LPNEWHEADER)LockResource(hRes)) == NULL)
+ return(0);
+
+ ResCount = DataPtr->ResCount;
+ ResDirPtr = (LPRESDIR)(DataPtr + 1);
+
+ switch (LOWORD((DWORD)lpszType))
+ {
+ case RT_ICON:
+ RetIndex = GetBestFormIcon(ResDirPtr, ResCount);
+ break;
+
+ case RT_CURSOR:
+ RetIndex = GetBestFormCursor(ResDirPtr, ResCount);
+ break;
+ }
+
+ if (RetIndex == ResCount)
+ RetIndex = 0;
+
+ ResCount = ((LPRESDIR)(ResDirPtr+RetIndex))->idIcon;
+
+ UnlockResource(hRes);
+
+ return(ResCount);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* UT_LoadCursorIconBitmap() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE NEAR PASCAL UT_LoadCursorIconBitmap(register HANDLE hrf,
+ LPSTR lpszName,
+ int type)
+
+{
+ register HANDLE h;
+
+ dprintf(7,"LoadCursorIconBitmap");
+ if (hrf == NULL) return (HANDLE)0; // no 2.x support - NigelT
+
+ h = FindIndividualResource(hrf, lpszName, MAKEINTRESOURCE(type));
+
+ if (h != NULL)
+ h = LoadResource(hrf, h);
+
+ return(h);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* fCheckMono() - */
+/* Checks a DIB for being truely monochrome. Only called if */
+/* BitCount == 1. This function checks the color table (address */
+/* passed) for true black and white RGB's */
+/* */
+/*--------------------------------------------------------------------------*/
+
+BOOL NEAR PASCAL fCheckMono(LPVOID lpColorTable,
+ BOOL fNewDIB)
+
+{
+ LPLONG lpRGB;
+ LPWORD lpRGBw;
+
+ dprintf(7,"fCheckMono");
+ lpRGB = lpColorTable;
+ if (fNewDIB)
+ {
+ if ((*lpRGB == 0 && *(lpRGB + 1) == 0x00FFFFFF) ||
+ (*lpRGB == 0x00FFFFFF && *(lpRGB + 1) == 0))
+ return(TRUE);
+ }
+ else
+ {
+ lpRGBw = lpColorTable;
+ if (*(LPSTR)lpRGBw == 0)
+ {
+ if (*lpRGBw == 0 && *(lpRGBw+1) == 0xFF00 && *(lpRGBw+2) == 0xFFFF)
+ return(TRUE);
+ }
+ else if (*lpRGBw == 0xFFFF && *(lpRGBw+1) == 0x00FF && *(lpRGBw+2) == 0)
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadNewBitmap() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+/* Loads a 3.x format bitmap into the DIB structure. */
+
+HBITMAP NEAR PASCAL LoadNewBitmap(HANDLE hRes,
+ LPSTR lpName)
+
+{
+ register HBITMAP hbmS;
+ register HBITMAP hBitmap;
+
+ dprintf(7,"LoadNewBitmap");
+
+ if ((hbmS = hBitmap = UT_LoadCursorIconBitmap(hRes,lpName,(WORD)RT_BITMAP)))
+ {
+ /* Convert the DIB bitmap into a bitmap in the internal format */
+ hbmS = ConvertBitmap(hBitmap);
+
+ /* Converted bitmap is in hbmS; So, release the DIB */
+ FreeResource(hBitmap);
+ }
+ return(hbmS);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* ConvertBitmap() */
+/* */
+/* This takes in a handle to data in PM 1.1 or 1.2 DIB format or */
+/* Windows 3.0 DIB format and creates a bitmap in the internal */
+/* bitmap format and returns the handle to it. */
+/* */
+/* NOTE: */
+/* This function is exported because it is called from CLIPBRD.EXE */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HBITMAP FAR PASCAL ConvertBitmap(HBITMAP hBitmap)
+
+{
+ int Width;
+ register int Height;
+ HDC hDC;
+ BOOL fMono = FALSE;
+ LPSTR lpBits;
+ register HBITMAP hbmS;
+ LPBITMAPINFOHEADER lpBitmap1;
+ LPBITMAPCOREHEADER lpBitmap2;
+
+ dprintf(7,"ConvertBitmap");
+ lpBitmap1 = (LPBITMAPINFOHEADER)LockResource(hBitmap);
+
+ if (!lpBitmap1)
+ return(NULL);
+
+ if ((WORD)lpBitmap1->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ /* This is an "old form" DIB. This matches the PM 1.1 format. */
+ lpBitmap2 = (LPBITMAPCOREHEADER)lpBitmap1;
+ Width = lpBitmap2->bcWidth;
+ Height = lpBitmap2->bcHeight;
+
+ /* Calcluate the pointer to the Bits information */
+ /* First skip over the header structure */
+ lpBits = (LPSTR)(lpBitmap2 + 1);
+
+ /* Skip the color table entries, if any */
+ if (lpBitmap2->bcBitCount != 24)
+ {
+ if (lpBitmap2->bcBitCount == 1)
+ fMono = fCheckMono(lpBits, FALSE);
+ lpBits += (1 << (lpBitmap2->bcBitCount)) * sizeof(RGBTRIPLE);
+ }
+ }
+ else
+ {
+ Width = (WORD)lpBitmap1->biWidth;
+ Height = (WORD)lpBitmap1->biHeight;
+
+ /* Calcluate the pointer to the Bits information */
+ /* First skip over the header structure */
+ lpBits = (LPSTR)(lpBitmap1 + 1);
+
+ /* Skip the color table entries, if any */
+ if (lpBitmap1->biClrUsed != 0)
+ {
+ if (lpBitmap1->biClrUsed == 2)
+ fMono = fCheckMono(lpBits, TRUE);
+ lpBits += lpBitmap1->biClrUsed * sizeof(RGBQUAD);
+ }
+ else
+ {
+ if (lpBitmap1->biBitCount != 24)
+ {
+ if (lpBitmap1->biBitCount == 1)
+ fMono = fCheckMono(lpBits, TRUE);
+ lpBits += (1 << (lpBitmap1->biBitCount)) * sizeof(RGBQUAD);
+ }
+ }
+ }
+
+ /* Create a bitmap */
+ if (fMono)
+ hbmS = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL);
+ else
+ {
+ /* Create a color bitmap compatible with the display device */
+ hDC = GetScreenDC();
+ hbmS = CreateCompatibleBitmap(hDC, Width, Height);
+ InternalReleaseDC(hDC);
+ }
+
+ /* Initialize the new bitmap by converting from PM format */
+ if (hbmS != NULL)
+ SetDIBits(hdcBits, hbmS, 0, Height, lpBits,
+ (LPBITMAPINFO)lpBitmap1, DIB_RGB_COLORS);
+
+ GlobalUnlock(hBitmap);
+
+ return(hbmS);
+}
+
+
+HANDLE NEAR PASCAL Helper_LoadCursorOrIcon(HANDLE hRes,
+ LPSTR lpName,
+ WORD type)
+{
+ HANDLE h;
+
+ dprintf(7,"Helper_LoadCursorOrIcon");
+
+ /* If we can't find the cursor/icon in the app, and this is a 2.x app, we
+ * need to search into the display driver to find it.
+ */
+ h = UT_LoadCursorIconBitmap(hRes, lpName, type);
+ return(h);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadCursor() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HCURSOR API LoadCursor(hRes, lpName)
+
+HANDLE hRes;
+LPSTR lpName;
+
+{
+ HCURSOR hcur;
+
+ dprintf(5,"LoadCursor");
+
+ if (hRes == NULL) {
+ dprintf(9," Calling Win32 to load Cursor");
+ hcur = WOWLoadCursor32(hRes, lpName);
+ } else {
+ hcur = ((HCURSOR)Helper_LoadCursorOrIcon(hRes, lpName, (WORD)RT_CURSOR));
+ }
+#ifdef DEBUG
+ if (hcur == NULL) {
+ dprintf(9," Failed, BUT returning 1 so app won't die (yet)");
+ return (HCURSOR)1;
+ }
+#endif
+
+ dprintf(5,"LoadCursor returning %4.4XH", hcur);
+
+ return hcur;
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadIcon() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HICON API LoadIcon(hRes, lpName)
+
+HANDLE hRes;
+LPSTR lpName;
+
+{
+ HICON hicon;
+
+ dprintf(5,"LoadIcon");
+
+ if (hRes == NULL) {
+ dprintf(9," Calling Win32 to load Icon");
+ hicon = WOWLoadIcon32(hRes, lpName);
+ } else {
+ hicon = ((HICON)Helper_LoadCursorOrIcon(hRes, lpName, (WORD)RT_ICON));
+ }
+#ifdef DEBUG
+ if (hicon == NULL) {
+ dprintf(9," Failed, BUT returning 1 so app won't die (yet)");
+ return (HICON)1;
+ }
+#endif
+ dprintf(5,"LoadIcon returning %4.4XH", hicon);
+
+ return hicon;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* StretchBitmap() - */
+/* */
+/* This routine stretches a bitmap into another bitmap, */
+/* and returns the stretched bitmap. */
+/*--------------------------------------------------------------------------*/
+
+HBITMAP FAR PASCAL StretchBitmap(iOWidth, iOHeight, iNWidth, iNHeight, hbmS,
+ byPlanes, byBitsPixel)
+
+int iOWidth;
+int iOHeight;
+int iNWidth;
+int iNHeight;
+HBITMAP hbmS;
+BYTE byPlanes;
+BYTE byBitsPixel;
+
+{
+ register HBITMAP hbmD;
+ HBITMAP hbmDSave;
+ register HDC hdcSrc;
+
+
+
+
+ dprintf(7,"StretchBitmap");
+ if ((hdcSrc = CreateCompatibleDC(hdcBits)) != NULL)
+ {
+ if ((hbmD = (HBITMAP)CreateBitmap(iNWidth, iNHeight, byPlanes, byBitsPixel, (LPINT)NULL)) == NULL)
+ goto GiveUp;
+
+ if ((hbmDSave = SelectObject(hdcBits, hbmD)) == NULL)
+ goto GiveUp;
+
+ if (SelectObject(hdcSrc, hbmS) != NULL)
+ {
+ /* NOTE: We don't have to save the bitmap returned from
+ * SelectObject(hdcSrc) and select it back in to hdcSrc,
+ * because we delete hdcSrc.
+ */
+ SetStretchBltMode(hdcBits, COLORONCOLOR);
+
+ StretchBlt(hdcBits, 0, 0, iNWidth, iNHeight, hdcSrc, 0, 0, iOWidth, iOHeight, SRCCOPY);
+
+ SelectObject(hdcBits, hbmDSave);
+
+ DeleteDC(hdcSrc);
+
+ return(hbmD);
+ }
+ else
+ {
+GiveUp:
+ if (hbmD != NULL)
+ DeleteObject(hbmD);
+ DeleteDC(hdcSrc);
+ goto Step1;
+ }
+
+ }
+ else
+ {
+Step1:
+ return(NULL);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadOldBitmap() - */
+/* */
+/* This loads bitmaps in old formats( Version 2.10 and below) */
+/*--------------------------------------------------------------------------*/
+
+HANDLE NEAR PASCAL LoadOldBitmap(HANDLE hRes,
+ LPSTR lpName)
+
+{
+ int oWidth;
+ int oHeight;
+ BYTE planes;
+ BYTE bitsPixel;
+ WORD wCount;
+ DWORD dwCount;
+ LPBITMAP lpBitmap;
+ register HBITMAP hbmS;
+ HBITMAP hbmD;
+ register HBITMAP hBitmap;
+ BOOL fCrunch;
+ WORD wDevDep;
+
+ dprintf(7,"LoadOldBitmap");
+
+ if (hbmS = hBitmap = UT_LoadCursorIconBitmap(hRes, lpName, BMR_BITMAP))
+ {
+ lpBitmap = (LPBITMAP)LockResource(hBitmap);
+
+ fCrunch = ((*(((BYTE FAR *)lpBitmap) + 1) & 0x0F) != BMR_DEVDEP);
+ lpBitmap = (LPBITMAP)((BYTE FAR *)lpBitmap + 2);
+
+ oWidth = lpBitmap->bmWidth;
+ oHeight = lpBitmap->bmHeight;
+ planes = lpBitmap->bmPlanes;
+ bitsPixel = lpBitmap->bmBitsPixel;
+
+ if (!(*(((BYTE FAR *)lpBitmap) + 1) & 0x80))
+ {
+ hbmS = CreateBitmap(oWidth, oHeight, planes, bitsPixel,
+ (LPSTR)(lpBitmap + 1));
+ }
+ else
+ {
+ hbmS = (HBITMAP)CreateDiscardableBitmap(hdcBits, oWidth, oHeight);
+ wCount = (((oWidth * bitsPixel + 0x0F) & ~0x0F) >> 3);
+ dwCount = wCount * oHeight * planes;
+ SetBitmapBits(hbmS, dwCount, (LPSTR)(lpBitmap + 1));
+ }
+
+ GlobalUnlock(hBitmap);
+ FreeResource(hBitmap);
+
+ if (hbmS != NULL)
+ {
+ if (fCrunch && ((64/oemInfo.cxIcon + 64/oemInfo.cyIcon) > 2))
+ {
+ /* Stretch the Bitmap to suit the device */
+ hbmD = StretchBitmap(oWidth, oHeight,
+ (oWidth * oemInfo.cxIcon/64),
+ (oHeight * oemInfo.cyIcon/64),
+ hbmS, planes, bitsPixel);
+
+ /* Delete the old bitmap */
+ DeleteObject(hbmS);
+
+ if (hbmD == NULL)
+ return(NULL); /* Some problem in stretching */
+ else
+ return(hbmD); /* Return the stretched bitmap */
+ }
+ }
+ }
+ else
+ {
+ return (HANDLE)0;
+ }
+ return(hbmS);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadBitmap() - */
+/* */
+/* This routine decides whether the bitmap to be loaded is in old or */
+/* new (DIB) format and calls appropriate handlers. */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE API LoadBitmap(hRes, lpName)
+
+HANDLE hRes;
+LPSTR lpName;
+
+{
+ HANDLE hbmp;
+
+ dprintf(5,"LoadBitmap");
+ if (hRes == NULL) {
+ dprintf(9," Calling Win32 to load Bitmap");
+ hbmp = WOWLoadBitmap32(hRes, lpName);
+ } else {
+
+ /* Check if the resource is to be taken from the display driver. If so,
+ * check the driver version; If the resource is to be taken from the
+ * application, check the app version
+ */
+ if (((hRes == NULL) && (oemInfo.DispDrvExpWinVer >= VER)) ||
+ ((hRes != NULL) && (LOWORD(GetExpWinVer(hRes)) >= VER))) {
+ hbmp = (LoadNewBitmap(hRes, lpName));
+ } else {
+ hbmp = (LoadOldBitmap(hRes, lpName));
+ }
+ }
+#ifdef DEBUG
+ if (hbmp == NULL) {
+ dprintf(9," Failed, BUT returning 1 so app won't die (yet)");
+ return (HANDLE)1;
+ }
+#endif
+ dprintf(5,"LoadBitmap returning %4.4XH", hbmp);
+
+ return hbmp;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* CrunchAndResize() - */
+/* This Crunches the monochrome icons and cursors if required and */
+/* returns the newsize of the resource after crunching. */
+/* This routine is also called to resize the monochrome AND mask of a */
+/* color icon. */
+/* Parameters: */
+/* lpIcon: Ptr to the resource */
+/* fIcon : TRUE, if the resource is an icon. FALSE, if it is a cursor. */
+/* fCrunch : TRUE if resource is to be resized. */
+/* fSinglePlane: TRUE if only AND mask of a color icon is passed */
+/* through lpIcon */
+/* fUseSysMetrics: Whether to use the icon/cursor values found in */
+/* oemInfo or not. */
+/* Returns: */
+/* The new size of the resource is returned. */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD NEAR PASCAL CrunchAndResize(lpIcon, fIcon, fCrunch, fSinglePlane, fUseSysMetrics)
+
+LPCURSORSHAPE lpIcon;
+BOOL fIcon;
+BOOL fCrunch;
+BOOL fSinglePlane;
+BOOL fUseSysMetrics;
+
+
+{
+ WORD size;
+ register int cx;
+ register int cy;
+ int oHeight;
+ int nHeight;
+ int iNewcbWidth;
+ BOOL bStretch;
+ HBITMAP hbmS;
+ HBITMAP hbmD;
+
+ dprintf(7,"CrunhAndResize");
+ if(fUseSysMetrics)
+ {
+ if(fIcon)
+ {
+ cx = oemInfo.cxIcon;
+ cy = oemInfo.cyIcon;
+ }
+ else
+ {
+ cx = oemInfo.cxCursor;
+ cy = oemInfo.cyCursor;
+ }
+ }
+ else
+ {
+ cx = lpIcon->cx;
+ cy = lpIcon->cy;
+ }
+
+ if (fIcon)
+ {
+ lpIcon->xHotSpot = cx >> 1;
+ lpIcon->yHotSpot = cy >> 1;
+ if (fSinglePlane)
+ {
+ /* Only the AND mask exists */
+ oHeight = lpIcon->cy;
+ nHeight = cy;
+ }
+ else
+ {
+ /* Both AND ans XOR masks exist; So, height must be twice */
+ oHeight = lpIcon->cy << 1;
+ nHeight = cy << 1;
+ }
+ }
+ else
+ {
+ oHeight = lpIcon->cy << 1;
+ nHeight = cy << 1;
+ }
+
+ iNewcbWidth = ((cx + 0x0F) & ~0x0F) >> 3;
+ size = iNewcbWidth * nHeight;
+
+ if (fCrunch && ((lpIcon->cx != cx) || (lpIcon->cy != cy)))
+ {
+ if (!fIcon)
+ {
+ lpIcon->xHotSpot = (lpIcon->xHotSpot * cx)/(lpIcon->cx);
+ lpIcon->yHotSpot = (lpIcon->yHotSpot * cy)/(lpIcon->cy);
+ }
+
+ /* To begin with, assume that no stretching is required */
+ bStretch = FALSE;
+
+ /* Check if the width is to be reduced */
+ if (lpIcon->cx != cx)
+ {
+ /* Stretching the Width is necessary */
+ bStretch = TRUE;
+ }
+
+ /* Check if the Height is to be reduced */
+ if (lpIcon->cy != cy)
+ {
+ /* Stretching in Y direction is necessary */
+ bStretch = TRUE;
+ }
+
+ /* Check if stretching is necessary */
+ if (bStretch)
+ {
+ /* Create a monochrome bitmap with the icon/cursor bits */
+ if ((hbmS = CreateBitmap(lpIcon->cx, oHeight, 1, 1, (LPSTR)(lpIcon + 1))) == NULL)
+ return(NULL);
+
+ if ((hbmD = StretchBitmap(lpIcon->cx, oHeight, cx, nHeight, hbmS, 1, 1)) == NULL)
+ {
+ DeleteObject(hbmS);
+ return(NULL);
+ }
+
+ DeleteObject(hbmS);
+
+ lpIcon->cx = cx;
+ lpIcon->cy = cy;
+ lpIcon->cbWidth = iNewcbWidth;
+
+ GetBitmapBits(hbmD, (DWORD)size, (LPSTR)(lpIcon + 1));
+ DeleteObject(hbmD);
+ }
+ }
+
+ return(size + sizeof(CURSORSHAPE));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadCursorIconHandler() - */
+/* */
+/* This handles 2.x (and less) Cursors and Icons */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE FAR PASCAL LoadCursorIconHandler(hRes, hResFile, hResIndex)
+
+register HANDLE hRes;
+HANDLE hResFile;
+HANDLE hResIndex;
+
+{
+ register int fh = 0;
+ BOOL bNew = FALSE;
+ WORD wMemSize;
+ LPCURSORSHAPE lpIcon;
+ HANDLE hTempRes;
+
+ dprintf(7,"LoadCursorIconHandler");
+ wMemSize = SizeofResource(hResFile, hResIndex);
+
+#if 1 // was 0 - NigelT
+ if (!hRes)
+ {
+ if (!(hRes = AllocResource(hResFile, hResIndex, 0L)))
+ return(NULL);
+ fh = -1;
+ bNew = TRUE;
+ }
+
+ while (!(lpIcon = (LPCURSORSHAPE)GlobalLock(hRes)))
+ {
+ if (!GlobalReAlloc(hRes, (DWORD)wMemSize, 0))
+ goto LoadCIFail;
+ else
+ fh = -1;
+ }
+
+ if (fh)
+ {
+ fh = AccessResource(hResFile, hResIndex);
+ if (fh != -1 && _lread(fh, (LPSTR)lpIcon, wMemSize) != 0xFFFF)
+ _lclose(fh);
+ else
+ {
+ if (fh != -1)
+ _lclose(fh);
+ GlobalUnlock(hRes);
+ goto LoadCIFail;
+ }
+
+ }
+#else
+ /* Call kernel's resource handler instead of doing the stuff ourselves
+ * because we use cached file handles that way. davidds
+ */
+ // For resources which are not preloaded, hRes will be NULL at this point.
+ // For such cases, the default resource handler does the memory allocation
+ // and returns a valid handle.
+ // Fix for Bug #4257 -- 01/21/91 -- SANKAR
+ if (!(hTempRes = lpDefaultResourceHandler(hRes, hResFile, hResIndex)))
+ goto LoadCIFail;
+ // We must use the handle returned by lpDefaultResourceHandler.
+ hRes = hTempRes;
+
+ lpIcon = (LPCURSORSHAPE)GlobalLock(hRes);
+#endif
+
+ if (LoadCursorIconHandler2(hRes, lpIcon, wMemSize))
+ return(hRes);
+
+LoadCIFail:
+ /* If the loading of the resource fails, we MUST discard the memory we
+ * reallocated above, or kernel will simply globallock the thing on the
+ * next call to LockResource(), leaving invalid data in the object.
+ */
+ if (bNew)
+ GlobalFree(hRes);
+ else
+ GlobalDiscard(hRes);
+
+ return(NULL);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadCursorIconHandler2() - */
+/* */
+/* This handles all 2.x Cursors and Icons */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE FAR PASCAL LoadCursorIconHandler2(hRes, lpIcon, wMemSize)
+
+register HANDLE hRes;
+LPCURSORSHAPE lpIcon;
+register WORD wMemSize;
+
+{
+ BOOL fCrunch;
+ BOOL fIcon;
+ WORD wNewSize;
+ BOOL fStretchInXdirection;
+ BOOL fStretchInYdirection;
+
+ dprintf(7,"LoadCursorIconHandler2");
+ fIcon = (*(LPSTR)lpIcon == BMR_ICON);
+
+ /* Is this a device dependant icon/cursor?. */
+ fCrunch = (*((LPSTR)lpIcon+1) != BMR_DEVDEP);
+
+ LCopyStruct((LPSTR)lpIcon+2, (LPSTR)lpIcon, wMemSize-2);
+
+ fCrunch = fCrunch || (lpIcon->cx != GetSystemMetrics(SM_CXICON)) ||
+ (lpIcon->cy != GetSystemMetrics(SM_CYICON));
+
+ /* Only support monochrome cursors. */
+ lpIcon->Planes = lpIcon->BitsPixel = 1;
+
+ fStretchInXdirection = fStretchInYdirection = TRUE; // Assume we need stretching.
+
+ if(fIcon)
+ {
+ if((oemInfo.cxIcon > STD_ICONWIDTH) && (lpIcon->cx <= oemInfo.cxIcon))
+ fStretchInXdirection = FALSE; // No Need to stretch in X direction;
+ if((oemInfo.cyIcon > STD_ICONHEIGHT) && (lpIcon->cy <= oemInfo.cyIcon))
+ fStretchInYdirection = FALSE; // No need to stretch in Y direction;
+ }
+ else
+ {
+ if((oemInfo.cxCursor > STD_CURSORWIDTH) && (lpIcon->cx <= oemInfo.cxCursor))
+ fStretchInXdirection = FALSE; // No need to stretch in X direction.
+ if((oemInfo.cyCursor > STD_CURSORHEIGHT) && (lpIcon->cy <= oemInfo.cyCursor))
+ fStretchInYdirection = FALSE; // No need to stretch in Y direction.
+ }
+
+ // Check if the Icon/Cursor needs to be stretched now or not
+ if(!(fStretchInXdirection || fStretchInYdirection))
+ {
+ GlobalUnlock(hRes);
+ return(hRes);
+ }
+ wNewSize = SizeReqd(fIcon, 1, 1, TRUE, 0, 0);
+
+ /* Before we crunch, let us make sure we have a big enough resource. */
+ if (fCrunch)
+ {
+ if (wNewSize > wMemSize)
+ {
+ GlobalUnlock(hRes);
+
+ /* Make this non discardable so that kernel will try to move this
+ * block when reallocing. DavidDS
+ */
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_NODISCARD);
+
+ if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0))
+ {
+ /* So it gets discarded. Note that since the above realloc is
+ * less than 64K, the handle won't change.
+ */
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE);
+ return(NULL);
+ }
+
+ /* So it gets discarded */
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE);
+
+ if (!(lpIcon = (LPCURSORSHAPE)GlobalLock(hRes)))
+ return(NULL);
+ wMemSize = wNewSize;
+ }
+ }
+
+ wNewSize = CrunchAndResize(lpIcon, fIcon, fCrunch, FALSE, TRUE);
+
+ GlobalUnlock(hRes);
+
+ /* Has it already been resized? */
+ if (wNewSize < wMemSize)
+ {
+ /* Make it an exact fit. */
+ if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0))
+ return(NULL);
+ }
+
+ return(hRes);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadDIBCursorHandler() - */
+/* */
+/* This is called when a Cursor in DIB format is loaded */
+/* This converts the cursor into Old format and returns the handle */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE FAR PASCAL LoadDIBCursorHandler(hRes, hResFile, hResIndex)
+
+HANDLE hRes;
+HANDLE hResFile;
+HANDLE hResIndex;
+
+{
+ dprintf(7,"LoadDIBCursorIconHandler");
+ return(LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, FALSE));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadDIBIconHandler() - */
+/* */
+/* This is called when an Icon in DIB format is loaded */
+/* This converts the cursor into Old format and returns the handle */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE FAR PASCAL LoadDIBIconHandler(hRes, hResFile, hResIndex)
+
+HANDLE hRes;
+HANDLE hResFile;
+HANDLE hResIndex;
+
+{
+ dprintf(7,"LoadDIBIconHandler");
+ return(LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, TRUE));
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* StretchIcon() - */
+/* When this routine is called, lpIcon already has the monochrome */
+/* AND bitmap properly sized. This routine adds the color XOR bitmap at */
+/* end of lpIcon and updates the header with the values of the color */
+/* info(bitcount and Planes); */
+/* wOldSize : Contains the size of AND mask + CURSORSHAPE */
+/* */
+/* Returns: The new size ( Size of AND mask + XOR bitmap + CURSORSHAPE) */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD NEAR PASCAL StretchIcon(lpIcon, wOldSize, hXORbitmap, fStretchToSysMetrics)
+
+LPCURSORSHAPE lpIcon;
+WORD wOldSize;
+register HBITMAP hXORbitmap;
+BOOL fStretchToSysMetrics;
+
+{
+ WORD wCount;
+ BITMAP bitmap;
+ register HBITMAP hNewBitmap;
+
+ dprintf(7,"StretchIcon");
+ GetObject(hXORbitmap, sizeof(BITMAP), (LPSTR)&bitmap);
+
+ if(fStretchToSysMetrics)
+ {
+ /* Do we need to resize things? */
+ if ((oemInfo.cxIcon != bitmap.bmWidth) || (oemInfo.cyIcon != bitmap.bmHeight))
+ {
+ hNewBitmap = StretchBitmap(bitmap.bmWidth, bitmap.bmHeight,
+ oemInfo.cxIcon, oemInfo.cyIcon, hXORbitmap,
+ bitmap.bmPlanes, bitmap.bmBitsPixel);
+ DeleteObject(hXORbitmap);
+
+ if (hNewBitmap == NULL)
+ return(0);
+
+ GetObject(hNewBitmap, sizeof(BITMAP), (LPSTR)&bitmap);
+ hXORbitmap = hNewBitmap;
+ }
+ }
+
+ /* Update the Planes and BitsPixels field with the color values */
+ lpIcon->Planes = bitmap.bmPlanes;
+ lpIcon->BitsPixel = bitmap.bmBitsPixel;
+
+ wCount = bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes;
+ GetBitmapBits(hXORbitmap, (DWORD)wCount, (LPSTR)((LPSTR)lpIcon + wOldSize));
+ DeleteObject(hXORbitmap);
+
+ return(wCount + wOldSize);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadDIBCursorIconHandler() - */
+/* */
+/* This is called when a Cursor/Icon in DIB format is loaded */
+/* This converts the cursor/icon internal format and returns the */
+/* handle */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE NEAR PASCAL LoadDIBCursorIconHandler(hRes, hResFile, hResIndex, fIcon)
+
+register HANDLE hRes;
+HANDLE hResFile;
+HANDLE hResIndex;
+BOOL fIcon;
+
+{
+ register int fh = 0;
+ BOOL bNew = FALSE;
+ WORD wMemBlkSize;
+ LPCURSORSHAPE lpCurSh;
+ HANDLE hTempRes;
+
+ dprintf(7,"LoadDIBCursorIconHandler");
+ wMemBlkSize = (WORD)SizeofResource(hResFile, hResIndex);
+
+#if 1 // was 0 - NigelT
+ if (!hRes)
+ {
+ if (!(hRes = AllocResource(hResFile, hResIndex, 0L)))
+ goto LoadDIBFail;
+ fh = -1;
+ bNew = TRUE;
+ }
+
+ while (!(lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes)))
+ {
+ if (!GlobalReAlloc(hRes, (DWORD)wMemBlkSize, 0))
+ goto LoadDIBFail;
+ else
+ fh = -1;
+ }
+
+ if (fh)
+ {
+ fh = AccessResource(hResFile, hResIndex);
+ if (fh != -1 && _lread(fh, (LPSTR)lpCurSh, wMemBlkSize) != 0xFFFF)
+ _lclose(fh);
+ else
+ {
+ if (fh != -1)
+ _lclose(fh);
+ GlobalUnlock(hRes);
+ goto LoadDIBFail;
+ }
+ }
+#else
+ /* Call kernel's resource handler instead of doing the stuff ourselves
+ * because we use cached file handles that way. davidds
+ */
+ // For resources which are not preloaded, hRes will be NULL at this point.
+ // For such cases, the default resource handler does the memory allocation
+ // and returns a valid handle.
+ // Fix for Bug #4257 -- 01/21/91 -- SANKAR
+ if (!(hTempRes = lpDefaultResourceHandler(hRes, hResFile, hResIndex)))
+ goto LoadDIBFail;
+ // We must use the handle returned by lpDefaultResourceHandler.
+ hRes = hTempRes;
+
+ lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes);
+#endif
+
+ if (LoadDIBCursorIconHandler2(hRes, lpCurSh, wMemBlkSize, fIcon))
+ return(hRes);
+
+LoadDIBFail:
+ /* if the loading of the resource fails, we MUST discard the memory we
+ * reallocated above, or kernel will simply globallock the thing on the
+ * next call to LockResource(), leaving invalid data in the object.
+ */
+ if (bNew)
+ FreeResource(hRes);
+ else
+ GlobalDiscard(hRes);
+
+ return(NULL);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* LoadDIBCursorIconHandler2() - */
+/* */
+/* This is called when a Cursor/Icon in DIB format is loaded */
+/* This converts the cursor/icon into Old format and returns the */
+/* handle */
+/* */
+/* NOTE: All cursors(always monochrome) and Monochrome Icons are treated */
+/* alike by this routine. Color Icons are treated as special case */
+/* determined by the local flag "fMono". */
+/* */
+/*--------------------------------------------------------------------------*/
+
+HANDLE FAR PASCAL LoadDIBCursorIconHandler2(hRes, lpCurSh, wMemBlkSize, fIcon)
+
+register HANDLE hRes;
+WORD wMemBlkSize;
+LPCURSORSHAPE lpCurSh;
+register BOOL fIcon;
+
+{
+ HDC hDC;
+ BOOL fMono = FALSE;
+ WORD Width;
+ WORD Height;
+ WORD wCount;
+ WORD BitCount;
+ WORD Planes;
+ LPSTR lpBits;
+ BITMAP bitmap;
+ HBITMAP hBitmap;
+ WORD wNewSize;
+ HBITMAP hANDbitmap;
+ HBITMAP hXORbitmap;
+ LPWORD lpColorTable;
+ LPBITMAPINFOHEADER lpHeader;
+ LPBITMAPCOREHEADER lpHeader1 = 0;
+ BOOL fStretchToSysMetrics;
+ BOOL fStretchInXdirection;
+ BOOL fStretchInYdirection;
+
+
+ dprintf(7,"LoadDIBCursorIconHandler2");
+ lpHeader = (LPBITMAPINFOHEADER)lpCurSh;
+
+ if (!fIcon)
+ {
+ /* Skip over the cursor hotspot data in the first 2 words. */
+ lpHeader = (LPBITMAPINFOHEADER)((LPSTR)lpHeader + 4);
+ }
+
+ if ((WORD)lpHeader->biSize == sizeof(BITMAPCOREHEADER))
+ {
+ /* This is an "old form" DIB. This matches the PM 1.1 format. */
+ lpHeader1 = (LPBITMAPCOREHEADER)lpHeader;
+
+ Width = lpHeader1->bcWidth;
+ Height = lpHeader1->bcHeight;
+ BitCount = lpHeader1->bcBitCount;
+ Planes = lpHeader1->bcPlanes;
+
+ /* Calcluate the pointer to the Bits information */
+ /* First skip over the header structure */
+ lpColorTable = (LPWORD)(lpBits = (LPSTR)(lpHeader1 + 1));
+
+ /* Skip the color table entries, if any */
+ if (lpHeader1->bcBitCount != 24)
+ {
+ if (lpHeader1->bcBitCount == 1)
+ fMono = fCheckMono(lpBits, FALSE);
+ lpBits += (1 << (lpHeader1->bcBitCount)) * sizeof(RGBTRIPLE);
+ }
+ }
+ else
+ {
+ Width = (WORD)lpHeader->biWidth;
+ Height = (WORD)lpHeader->biHeight;
+ BitCount = lpHeader->biBitCount;
+ Planes = lpHeader->biPlanes;
+
+ /* Calcluate the pointer to the Bits information */
+ /* First skip over the header structure */
+ lpColorTable = (LPWORD)(lpBits = (LPSTR)(lpHeader + 1));
+
+ /* Skip the color table entries, if any */
+ if (lpHeader->biClrUsed != 0)
+ {
+ if (lpHeader->biClrUsed == 2)
+ fMono = fCheckMono(lpBits, TRUE);
+ lpBits += lpHeader->biClrUsed * sizeof(RGBQUAD);
+ }
+ else
+ {
+ if (lpHeader->biBitCount != 24)
+ {
+ if (lpHeader->biBitCount == 1)
+ fMono = fCheckMono(lpBits, TRUE);
+ lpBits += (1 << (lpHeader->biBitCount)) * sizeof(RGBQUAD);
+ }
+ }
+ }
+
+ // By default Stretch the icon/cursor to the dimensions in oemInfo;
+ // If this is FALSE, then the stretching will take place during DrawIcon();
+ fStretchInXdirection = TRUE;
+ fStretchInYdirection = TRUE;
+
+ // Check if the Icon/Cursor needs to be stretched to the dimensions in
+ // oemInfo now or not.
+ if(fIcon)
+ {
+ if((oemInfo.cxIcon > STD_ICONWIDTH) && (Width <= oemInfo.cxIcon))
+ fStretchInXdirection = FALSE; // No Need to stretch in X direction;
+ if((oemInfo.cyIcon > STD_ICONHEIGHT) && (Height <= oemInfo.cyIcon))
+ fStretchInYdirection = FALSE; // No need to stretch in Y direction;
+ }
+ else
+ {
+ if((oemInfo.cxCursor > STD_CURSORWIDTH) && (Width <= oemInfo.cxCursor))
+ fStretchInXdirection = FALSE; // No need to stretch in X direction.
+ if((oemInfo.cyCursor > STD_CURSORHEIGHT) && (Height <= oemInfo.cyCursor))
+ fStretchInYdirection = FALSE; // No need to stretch in Y direction.
+ }
+
+ fStretchToSysMetrics = fStretchInXdirection || fStretchInYdirection;
+
+ if (fMono)
+ {
+ /* Create a bitmap */
+ if (!(hBitmap = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL)))
+ {
+ GlobalUnlock(hRes);
+ return(NULL);
+ }
+
+ /* Convert the DIBitmap format into internal format */
+ SetDIBits(hdcBits, hBitmap, 0, Height, lpBits, (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS);
+ // Cursors/Icons in DIB format have a height twice the actual height.
+ wNewSize = SizeReqd(fIcon, BitCount, Planes, fStretchToSysMetrics, Width, Height>>1);
+ }
+ else
+ {
+ /* The height is twice that of icons */
+ Height >>= 1;
+ if (lpHeader1)
+ lpHeader1->bcHeight = Height;
+ else
+ lpHeader->biHeight = Height;
+
+ /* Create the XOR bitmap Compatible with the current device */
+ hDC = GetScreenDC();
+ if (!(hXORbitmap = CreateCompatibleBitmap(hDC, Width, Height)))
+ {
+ InternalReleaseDC(hDC);
+ GlobalUnlock(hRes);
+ return(NULL);
+ }
+ InternalReleaseDC(hDC);
+
+ /* Convert the DIBitmap into internal format */
+ SetDIBits(hdcBits, hXORbitmap, 0, Height, lpBits,
+ (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS);
+
+ GetObject(hXORbitmap, sizeof(BITMAP), (LPSTR)(&bitmap));
+ wNewSize = SizeReqd(fIcon, bitmap.bmBitsPixel, bitmap.bmPlanes,
+ fStretchToSysMetrics, Width, Height);
+
+ /* Create the monochrome AND bitmap */
+ if (!(hANDbitmap = CreateBitmap(Width, Height, 1, 1, (LPSTR)NULL)))
+ {
+ GlobalUnlock(hRes);
+ return(NULL);
+ }
+
+ /* Get the offset to the AND bitmap */
+ lpBits += (((Width * BitCount + 0x1F) & ~0x1F) >> 3) * Height;
+
+ /* Set the header with data for a monochrome bitmap */
+ Planes = BitCount = 1;
+
+ /* Set the color table for a monochrome bitmap */
+ *lpColorTable++ = 0;
+ *lpColorTable++ = 0xFF00;
+ *lpColorTable = 0xFFFF;
+
+ if (lpHeader1)
+ {
+ lpHeader1->bcWidth = Width;
+ lpHeader1->bcHeight = Height;
+ lpHeader1->bcPlanes = Planes;
+ lpHeader1->bcBitCount = BitCount;
+ }
+ else
+ {
+ lpHeader->biWidth = Width;
+ lpHeader->biHeight = Height;
+ lpHeader->biPlanes = Planes;
+ lpHeader->biBitCount = BitCount;
+ }
+
+ SetDIBits(hdcBits, hANDbitmap, 0, Height, lpBits,
+ (LPBITMAPINFO)lpHeader, DIB_RGB_COLORS);
+ hBitmap = hANDbitmap;
+ }
+
+ GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bitmap);
+
+ if (fIcon)
+ {
+ lpCurSh->xHotSpot = 0;
+ lpCurSh->yHotSpot = 0;
+ }
+
+ /* The following lines are replaced by a single functon call
+ *
+ * lpCurSh->cx = bitmap.bmwidth;
+ * lpCurSh->cy = bitmap.bmHeight;
+ * lpCurSh->cbWidth = bitmap.bmWidthBytes;
+ * lpCurSh->Planes = bitmap.bmPlanes;
+ * lpCurSh->BitsPixel = bitmap.bmBitsPixel;
+ */
+
+ LCopyStruct((LPSTR)&(bitmap.bmWidth),
+ (LPSTR)&(lpCurSh->cx), (sizeof(WORD)) << 2);
+
+ /* Cursors in PM format have twice the actual height. */
+ if (fMono)
+ lpCurSh->cy = lpCurSh->cy >> 1;
+
+ wCount = bitmap.bmWidthBytes * bitmap.bmHeight * bitmap.bmPlanes;
+
+ lpBits = (LPSTR)(lpCurSh + 1);
+
+ /* Copy the bits in Bitmap into the resource */
+ GetBitmapBits(hBitmap, (DWORD)wCount, lpBits);
+
+ /* Delete the bitmap */
+ DeleteObject(hBitmap);
+
+
+ /* Before crunching, let us make sure we have a big enough resource */
+ if (wNewSize > wMemBlkSize)
+ {
+ GlobalUnlock(hRes);
+
+ /* Make this non discardable so that kernel will try to move this block
+ * when reallocing. DavidDS
+ */
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_NODISCARD);
+
+ if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0))
+ {
+ /* So it gets discarded. Note that since the above realloc is less
+ * than 64K, the handle won't change.
+ */
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE);
+ return(NULL);
+ }
+
+ GlobalReAlloc(hRes, 0L, GMEM_MODIFY | GMEM_DISCARDABLE);
+ if (!(lpCurSh = (LPCURSORSHAPE)GlobalLock(hRes)))
+ return(NULL);
+
+ wMemBlkSize = wNewSize;
+ }
+
+ wNewSize = CrunchAndResize(lpCurSh, fIcon, TRUE, !fMono, fStretchToSysMetrics);
+
+ if (!fMono)
+ {
+ if (!(wNewSize = StretchIcon(lpCurSh, wNewSize, hXORbitmap, fStretchToSysMetrics)))
+ {
+ GlobalUnlock(hRes);
+ return(NULL);
+ }
+ }
+
+ GlobalUnlock(hRes);
+
+ /* Does it need to be resized? */
+ if (wNewSize < wMemBlkSize)
+ {
+ if (!GlobalReAlloc(hRes, (DWORD)wNewSize, 0))
+ return(NULL);
+ }
+
+ return(hRes);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* SizeReqd() - */
+/* This returns the size of an Icon or Cursor after it is stretched */
+/* or crunched */
+/* */
+/*--------------------------------------------------------------------------*/
+
+WORD NEAR PASCAL SizeReqd(fIcon, BitCount, Planes, fUseSysMetrics, iWidth, iHeight)
+
+BOOL fIcon;
+WORD BitCount;
+WORD Planes;
+BOOL fUseSysMetrics;
+int iWidth;
+int iHeight;
+
+{
+ WORD size;
+
+ dprintf(7,"SizeReqd");
+ if(fUseSysMetrics) //Use the dimensions in oemInfo; Else, use given dimensions
+ {
+ if(fIcon)
+ {
+ iWidth = oemInfo.cxIcon;
+ iHeight = oemInfo.cyIcon;
+ }
+ else
+ {
+ iWidth = oemInfo.cxCursor;
+ iHeight = oemInfo.cyCursor;
+ }
+ }
+
+ size = (((iWidth*BitCount+0x0F) & ~0x0F) >> 3) *
+ iHeight * Planes;
+
+ if ((BitCount == 1) && (Planes == 1))
+ size <<= 1;
+ else
+ size += (((iWidth+0x0F) & ~0x0F) >> 3)*iHeight;
+
+ return(size + sizeof(CURSORSHAPE));
+}
+
+#endif // NEEDED
diff --git a/private/mvdm/wow16/user/user.api b/private/mvdm/wow16/user/user.api
new file mode 100644
index 000000000..430201ed0
--- /dev/null
+++ b/private/mvdm/wow16/user/user.api
@@ -0,0 +1,3036 @@
+;===========================================================================
+;
+; Validation constants
+;
+DCX_VALID_L equ 004fbh
+DCX_VALID_H equ 00001h
+WS_VALID_L equ 00000h
+WS_VALID_H equ 0ffffh
+WS_EX_VALID_L equ 07fffh
+WS_EX_VALID_H equ 00007h
+GND_VALID_L equ 00003h
+GND_VALID_H equ 00000h
+
+DT_VALID equ 0ffffh
+CS_VALID equ 07fefh
+SWP_VALID equ 03fffh
+QS_VALID equ 000ffh
+TPM_VALID equ 0000fh
+RDW_VALID equ 00fffh
+SW_VALID equ 08007h
+MB_VALID equ 0b377h
+IDC_VALID equ 00007h
+MF_VALID equ 04fffh
+MF_CHANGE_VALID equ 05fffh
+EV_VALID equ 03fffh
+SPIF_VALID equ 00003h
+DDL_VALID equ 0e03fh
+PM_VALID equ 00003h
+WPF_VALID equ 00003h
+
+SB_MAX equ 3
+ESB_MAX equ 3
+SB_CMD_MAX equ 8
+SW_MAXIMIZE equ 3
+SW_MAX equ 9
+SM_MAX equ 80
+CTLCOLOR_MAX equ 8
+COLOR_MAX equ 20
+GW_MAX equ 5
+WH_MIN equ -1
+WH_MAX equ 10
+MSGF_MAX equ 7
+SPI_MAX equ 65
+PWR_MAX equ 3
+
+HHOOK_MAGIC equ ('H' or ('K' * 256))
+WS_CHILD equ 4000h
+
+;=======================================================================
+;
+; GDI types
+;
+
+IFNDEF WOW
+; ExternFP <IsGDIObject>
+ENDIF
+
+;
+; Generate a GDI object validation macro.
+;
+; If nullok is 1, allow NULL.
+; min & max are the allowed OBJ_* range.
+; except, if specified, is an OBJ_* value within the range to reject.
+;
+_GenHGDI macro name,nullok,htype,min,max,except
+ name &macro hObj,opts
+ local badobj
+ local objok
+ _GenParm <hObj>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ if nullok
+ mov cx,_P_&&hObj
+ jcxz objok
+ push cx
+ else
+ push _P_&&hObj
+ endif
+; call IsGDIObject
+ ifnb <except>
+ cmp al,except
+ jz badobj
+ endif
+ ife min-max
+ cmp al,min
+ je objok
+ else
+ cmp al,min
+ jb badobj
+ cmp al,max
+ jbe objok
+ endif
+ badobj:
+ mov ax,_P_&&hObj
+ mov bx,ERR_BAD_&htype
+ lcall Inval_Param_
+ objok:
+ ENDIF
+ endif
+ &endm
+endm
+
+OBJ_PEN equ 1
+OBJ_BRUSH equ 2
+OBJ_FONT equ 3
+OBJ_PALETTE equ 4
+OBJ_BITMAP equ 5
+OBJ_RGN equ 6
+OBJ_DC equ 7
+OBJ_IC equ 8
+OBJ_DISABLED_DC equ 9
+OBJ_METADC equ 10
+OBJ_METAFILE equ 11
+
+_GenHGDI <P_HDC>,0,HDC,OBJ_DC,OBJ_METAFILE
+_GenHGDI <P_HDC0>,1,HDC,OBJ_DC,OBJ_METAFILE
+
+_GenHGDI <P_HPEN>,0,HPEN,OBJ_PEN,OBJ_PEN
+_GenHGDI <P_HPEN0>,1,HPEN,OBJ_PEN,OBJ_PEN
+
+_GenHGDI <P_HBRUSH>,0,HBRUSH,OBJ_BRUSH,OBJ_BRUSH
+_GenHGDI <P_HBRUSH0>,1,HBRUSH,OBJ_BRUSH,OBJ_BRUSH
+
+_GenHGDI <P_HFONT>,0,HFONT,OBJ_FONT,OBJ_FONT
+_GenHGDI <P_HFONT0>,1,HFONT,OBJ_FONT,OBJ_FONT
+
+_GenHGDI <P_HPALETTE>,0,HPALETTE,OBJ_PALETTE,OBJ_PALETTE
+_GenHGDI <P_HPALETTE0>,1,HPALETTE,OBJ_PALETTE,OBJ_PALETTE
+
+_GenHGDI <P_HBITMAP>,0,HBITMAP,OBJ_BITMAP,OBJ_BITMAP
+_GenHGDI <P_HBITMAP0>,1,HBITMAP,OBJ_BITMAP,OBJ_BITMAP
+
+_GenHGDI <P_HRGN>,0,HRGN,OBJ_RGN,OBJ_RGN
+_GenHGDI <P_HRGN0>,1,HRGN,OBJ_RGN,OBJ_RGN
+
+P_HBITMAP01 macro hbm,opts
+ _GenParm <hbm>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov ax, _P_&hbm
+ cmp ax, 1 ; allow NULL or (HBITMAP)1
+ jbe @F
+ push ax
+ push ax
+; call IsGDIObject
+ cmp al, OBJ_BITMAP
+ pop ax
+ jz @F
+ mov bx,ERR_BAD_HBITMAP
+ lcall Inval_Param_
+ @@:
+ ENDIF
+ endif
+endm
+
+;============================================================================
+;
+; USER types
+;
+ExternFP <IsMenu>
+ExternFP <IsWindow>
+
+sBegin TEXT
+ExternNP <ValidateMessage> TEMPLY!!!! ChandanC
+sEnd TEXT
+
+sBegin DATA
+ IFNDEF WOW
+ ExternW <hMenuHeap>
+ ExternW <cInstalledDrivers>
+ ENDIF
+sEnd DATA
+
+DGROUP group _DATA
+
+P_HWND macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall VHWND
+ _gensub VHWND
+ ENDIF
+ endif
+endm
+
+P_HWND0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall VHWND0
+ _gensub VHWND
+ ENDIF
+ endif
+endm
+
+P_HWNDNOFAIL macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ lea bx, _P_&h
+ lcall VHWNDNOFAIL
+ _gensub VHWNDNOFAIL
+ @@:
+ ENDIF
+ endif
+endm
+
+P_HWNDNOFAIL0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ lea bx, _P_&h
+ lcall VHWNDNOFAIL0
+ _gensub VHWNDNOFAIL
+ @@:
+ ENDIF
+ endif
+endm
+
+P_HWNDINSERT macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ inc bx
+ inc bx
+ cmp bx,3 ; accept HWND_TOP (0), HWND_BOTTOM (1),
+ jbe @F ; HWND_NOTOPMOST (0xfffe) HWND_TOPMOST (0xffff)
+ dec bx
+ dec bx
+ lcall VHWND
+ _gensub VHWND
+ @@:
+ ENDIF
+ endif
+endm
+
+P_HWNDFFFF macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ inc bx ;; accept hwnd == 0xffff
+ jz @F
+ dec bx
+ lcall VHWND
+ _gensub VHWND
+ @@:
+ ENDIF
+ endif
+endm
+
+P_HOOK_HK macro name,opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov ax,_P_&name+2
+ cmp ax, HHOOK_MAGIC ; magic for unhook
+ jz @F
+ mov ax,_P_&name
+ mov cx,_P_&name+2
+ lcall LPFN
+ _gensub LPFN
+ @@:
+ ENDIF
+ endif
+endm
+
+;
+; CreateWindow and CreateWindowEx HMENU parameter. If WS_CHILD, then
+; hMenu is an ID, else it's a menu handle.
+;
+P_HMENU0CW macro style, x, y, cx, cy, hwndParent, hMenu, opts
+ local hmenu0cw_exit
+ _GenParm <style>,4,<opts>
+ _GenParm <x>,2,<opts>
+ _GenParm <y>,2,<opts>
+ _GenParm <cx>,2,<opts>
+ _GenParm <cy>,2,<opts>
+ _GenParm <hwndParent>,2,<opts>
+ _GenParm <hMenu>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&hwndParent ;validate parent window handle (can be NULL)
+ lcall VHWND0
+ _gensub VHWND
+
+ test word ptr _P_&style+2, WS_CHILD
+ jnz hmenu0cw_exit ;if this is a child window, we're done...
+ mov bx,_P_&hMenu ;...else verify menu handle (can be NULL)
+ lcall VHMENU0
+ _gensub VHMENU
+ hmenu0cw_exit:
+ ENDIF
+ endif
+endm
+
+P_HMENU macro hMenu,opts
+ _GenParm <hMenu>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&hMenu
+ lcall VHMENU
+ _gensub VHMENU
+ ENDIF
+ endif
+endm
+
+P_HMENU0 macro hMenu,opts
+ _GenParm <hMenu>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&hMenu
+ lcall VHMENU0
+ _gensub VHMENU
+ ENDIF
+ endif
+endm
+
+;
+; HDRVR validation
+;
+P_HDRVR macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall HDRVR
+ _gensub HDRVR
+ ENDIF
+ endif
+endm
+
+P_HDRVR0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall HDRVR0
+ _gensub HDRVR
+ ENDIF
+ endif
+endm
+
+;
+; HDWP validation
+;
+P_HDWP macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall HDWP
+ _gensub HDWP
+ ENDIF
+ endif
+endm
+
+P_HDWP0 macro h,opts
+ _GenParm <h>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov bx,_P_&h
+ lcall HDWP0
+ _gensub HDWP
+ ENDIF
+ endif
+endm
+
+;-----------------------------
+; HICON and HCURSOR validation
+
+P_HICON equ <P_GHANDLE>
+P_HCURSOR equ <P_GHANDLE>
+P_HCURSOR0 equ <P_GHANDLE0>
+
+STRUCT <CURSORSHAPE>
+F_int xHotSpot
+F_int yHotSpot
+F_int cx
+F_int cy
+F_int cbWidth
+F_BYTE Planes
+F_BYTE BitsPixel
+ENDSTRUCT
+
+;----------------------------------
+
+EXTRA_EXPAND macro lseg
+
+IFNDEF WOW
+;
+; HDRVR validation
+;
+ifdef genHDRVR&lseg
+
+public HDRVR0&lseg
+HDRVR0&lseg:
+ or bx,bx ; accept NULL
+ jz HDRVR_ok&lseg
+
+public HDRVR&lseg
+HDRVR&lseg:
+ or bx,bx
+ jz HDRVR_err&lseg
+ mov ax,DGROUP
+ mov es,ax
+assume es:DGROUP
+ cmp bx,es:[_DATA:cInstalledDrivers]
+assume es:NOTHING
+ ja HDRVR_err&lseg
+HDRVR_ok&lseg:
+ ret
+
+HDRVR_err&lseg:
+ xchg ax,bx
+ mov bx,ERR_BAD_HDRVR
+ jmp Inval_Param_&lseg
+
+endif ; genHDRVR&lseg
+
+; HDWP validation
+;
+ifdef genHDWP&lseg
+
+public HDWP0&lseg
+HDWP0&lseg:
+ or bx,bx ; accept NULL
+ jz HDWP_ok&lseg
+
+public HDWP&lseg
+HDWP&lseg:
+ or bx,bx
+ jz HDWP_err&lseg
+beg_fault_trap HDWP_trap&lseg
+ mov ax,DGROUP
+ mov es,ax
+assume es:DGROUP
+ cmp es:[bx].SmwpSignature,SMWP_SIG
+assume es:NOTHING
+ jnz HDWP_err&lseg
+end_fault_trap
+HDWP_ok&lseg:
+ ret
+
+HDWP_trap&lseg:
+ fault_fix_stack
+
+HDWP_err&lseg:
+ xchg ax,bx
+ mov bx,ERR_BAD_HDWP
+ jmp short Inval_Param_&lseg
+
+endif ; genHDWP&lseg
+
+;
+; HWND validation
+;
+ifdef genVHWND&lseg
+
+public VHWND0&lseg
+VHWND0&lseg:
+ or bx,bx ; accept NULL
+ jz HWND_ok&lseg
+
+public VHWND&lseg
+VHWND&lseg:
+ mov cx,bx ; put copy of window handle into cx
+beg_fault_trap HWND_trap&lseg
+ or bx,bx ; reject NULL without dereferencing
+ jz HWND_err&lseg
+
+ mov ax,_DATA
+ mov es,ax ; ES = window's DS
+
+ mov bx,es:[bx].wndPcls
+ cmp es:[bx].uclsMagic,'N'+'K'*256
+ jnz HWND_err&lseg
+end_fault_trap
+HWND_ok&lseg:
+ ret
+
+HWND_trap&lseg:
+ fault_fix_stack
+HWND_err&lseg:
+ xchg ax,cx ; ax = hwnd
+ mov bx,ERR_BAD_HWND
+ jmp short Inval_Param_&lseg
+
+endif ; genVHWND&lseg
+
+
+;HWND validation no failure. If failure, replace with NULL and warn
+; Takes a ptr on stack to the hwnd parameter.
+ifdef genVHWNDNOFAIL&lseg
+
+public VHWNDNOFAIL0&lseg
+VHWNDNOFAIL0&lseg:
+ mov cx,ss:[bx]
+ jcxz HWNDNOFAIL_ok&lseg ; accept NULL
+
+public VHWNDNOFAIL&lseg
+VHWNDNOFAIL&lseg:
+ mov cx,bx ; put copy of ptr to window handle into cx
+ mov bx,ss:[bx] ; put window handle in bx
+beg_fault_trap HWNDNOFAIL_trap&lseg
+ or bx,bx ; reject NULL without dereferencing
+ jz HWNDNOFAIL_err&lseg
+
+ mov ax,_DATA
+ mov es,ax ; ES = window's DS
+
+ mov bx,es:[bx].wndPcls
+ cmp es:[bx].uclsMagic,'N'+'K'*256
+ jnz HWNDNOFAIL_err&lseg
+end_fault_trap
+HWNDNOFAIL_ok&lseg:
+ ret
+
+HWNDNOFAIL_trap&lseg:
+ fault_fix_stack
+HWNDNOFAIL_err&lseg:
+ mov bx,cx
+ mov ax,ss:[bx] ; ax = hwnd
+ mov word ptr ss:[bx],0 ; Patch stack with NULL
+ mov bx,ERR_BAD_HWND or ERR_WARNING
+ lcall Inval_Param_
+ ret
+endif ; genVHWNDNOFAIL&lseg
+
+
+; HMENU validation
+
+ifdef genVHMENU&lseg
+
+public VHMENU0&lseg
+VHMENU0&lseg:
+ or bx,bx ; Accept NULL
+ jz HMENU_ok&lseg
+
+public VHMENU&lseg
+VHMENU&lseg:
+beg_fault_trap HMENU_trap&lseg
+ or bx,bx ; reject NULL without dereferencing
+ jz HMENU_err&lseg
+ mov ax,DGROUP
+ mov es,ax
+assume es:DGROUP
+ mov es,es:[_DATA:hMenuHeap]
+assume es:NOTHING
+ cmp es:[bx].mnSignature,SIG_MENU
+ jnz HMENU_err&lseg
+end_fault_trap
+HMENU_ok&lseg:
+ ret
+
+HMENU_trap&lseg:
+ fault_fix_stack
+HMENU_err&lseg:
+ xchg ax,bx
+ mov bx,ERR_BAD_HMENU
+ jmp short Inval_Param_&lseg
+
+endif ; genVHMENU&lseg
+ENDIF
+endm ; EXTRA_EXPAND
+
+P_HACCEL equ <P_GHANDLE>
+P_HACCEL0 equ <P_GHANDLE0>
+
+P_HCLIPDATA equ <P_H> ; depends on type.
+P_HCLIPDATA0 equ <P_H0>
+
+
+P_HHOOK macro hhook,opts
+ local hhook_err
+ local hhook_ok
+ _GenParm <hhook>,4,<opts>
+ if VLgen
+ IFNDEF WOW
+ mov cx,_P_&hhook
+ mov ax,_P_&hhook+2
+ jcxz hhook_err
+ cmp ax,HHOOK_MAGIC
+ je hhook_ok
+ hhook_err:
+ mov bx,ERR_BAD_DVALUE
+ lcall Inval_Param_
+ hhook_ok:
+ ENDIF
+ endif
+endm
+
+P_GWWINDEX equ <P_2> ; GetWindowWord index
+P_GCWINDEX equ <P_2> ; GetClassWord index
+
+P_CID macro cid,opts
+ local cid_err
+ local cid_ok
+ _GenParm <cid>,2,<opts>
+ if VLgen
+ mov ax,_P_&cid
+ or ah,ah
+ jz cid_ok
+ cid_err:
+ mov bx,ERR_BAD_HANDLE
+ lcall Inval_Param_
+ cid_ok:
+ endif
+endm
+
+; Field types
+
+_DefSimpleF F_HDC,2
+_DefSimpleF F_HWND,2
+_DefSimpleF F_CID,2
+_DefSimpleF F_HINSTANCE,2
+_DefSimpleF F_HICON0,2
+_DefSimpleF F_HCURSOR0,2
+_DefSimpleF F_HBRUSHVAL0,2
+
+_DefSimpleF F_LPFNWP,4
+_DefSimpleF F_LPFNWND,4
+_DefSimpleF F_CLPSTRRSRC,4
+_DefSimpleF F_CLPSTRRSRC0,4
+_DefSimpleF F_CLPSTRATOM,4
+
+_DefSimpleF F_RGB16,16
+
+STRUCT <MSG>
+F_HWND hwnd
+F_WORD message
+F_WORD wParam
+F_LONG lParam
+F_DWORD time
+F_POINT pt
+ENDSTRUCT
+
+_GenLP <P_LPMSG>,<LP>,%VLcbsMSG
+_GenLP <P_LPMSG0>,<LP0>,%VLcbsMSG
+
+P_CLPMSG macro lpmsg,opts
+ _GenParm <lpmsg>,4,<opts>
+ if VLgen
+ mov ax,_P_&lpmsg
+ mov cx,_P_&lpmsg+2
+ mov bx,VLcbsMSG
+ lcall CLP
+ _gensub LP
+ ifdef DEBUG
+ IFNDEF WOW
+ mov es,cx
+ mov bx,ax
+ mov bx,es:[bx]._F_hwnd ; DEBUG: just validate the hwnd.
+ lcall VHWND0
+ _gensub VHWND
+ ENDIF
+ else
+ mov es,cx
+ mov bx,ax
+ mov cx,es:[bx]._F_hwnd ; accept hwnd == NULL
+ jcxz @F
+ push cx
+ push es:[bx]._F_message
+ push es:[bx]._F_wParam
+ push es:[bx]._F_lParam+2
+ push es:[bx]._F_lParam
+ call far ptr ValidateMessage
+ or ax,ax
+ jnz @F
+ mov ax,_P_&lpmsg ; report error.
+ mov cx,_P_&lpmsg+2
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+ @@:
+ endif
+ endif
+endm
+
+STRUCT <PAINTSTRUCT>
+F_HDC hdc
+F_BOOL fErase
+F_RECT rcPaint
+F_BOOL fRestore
+F_BOOL fIncUpdate
+F_RGB16 rgbReserved ;16 reserved bytes
+ENDSTRUCT
+
+_GenLP <P_LPPAINTSTRUCT>,<LP>,%VLcbsPAINTSTRUCT
+_GenLP <P_LPPAINTSTRUCT0>,<LP0>,%VLcbsPAINTSTRUCT
+_GenLP <P_CLPPAINTSTRUCT>,<CLP>,%VLcbsPAINTSTRUCT
+_GenLP <P_CLPPAINTSTRUCT0>,<CLP0>,%VLcbsPAINTSTRUCT
+
+STRUCT <WNDCLASS>
+F_FLAGS style, CS_VALID
+F_LPFNWP lpfnWndProc ;** check for nop/nop/nop or mov ax.
+F_int cbClsExtra
+F_int cbWndExtra
+F_HINSTANCE hInstance
+F_HICON0 hIcon
+F_HCURSOR0 hCursor
+F_HBRUSHVAL0 hbrBackground ;** hBrush, color value or NULL
+F_CLPSTRRSRC0 lpMenuName ;** integer or ptr to null-term. string
+ ;If integer, HIWORD must be 0
+F_CLPSTRATOM lpszClassName
+ENDSTRUCT
+
+_GenLP <P_LPWNDCLASS>,<LP>,%VLcbsWNDCLASS
+_GenLP <P_LPWNDCLASS0>,<LP0>,%VLcbsWNDCLASS
+
+;ExternFP <ValidateWNDCLASS>
+P_CLPWNDCLASS macro lpwc,opts
+ _GenParm <lpwc>,4,<opts>
+ if VLgen
+; push _P_&lpwc+2
+; push _P_&lpwc
+; call ValidateWNDCLASS
+; or ax,ax
+; jnz @F
+; mov cx,_P_&lpwc+2
+; mov ax,_P_&lpwc
+; mov bx,ERR_BAD_PTR
+; lcall Inval_Param_
+; @@:
+ endif
+endm
+
+STRUCT <DCB>
+F_CID Id ;comm. device ID
+F_WORD BaudRate
+F_BYTE ByteSize ;** BYTE. Range 4-8
+F_BYTE Parity ;** BYTE. Range 0-4
+F_BYTE StopBits ;** BYTE. Range 0-2
+F_WORD RlsTimeout
+F_WORD CtsTimeout
+F_WORD DsrTimeout
+F_WORD flags ; room for the fXXX bitfields
+F_char XonChar
+F_char XoffChar
+F_WORD XonLim
+F_WORD XoffLim
+F_char PeChar
+F_char EofChar
+F_char EvtChar
+F_WORD TxDelay
+ENDSTRUCT
+
+_GenLP <P_LPDCB>,<LP>,%VLcbsDCB
+_GenLP <P_LPDCB0>,<LP0>,%VLcbsDCB
+_GenLP <P_CLPDCB>,<CLP>,%VLcbsDCB
+_GenLP <P_CLPDCB0>,<CLP0>,%VLcbsDCB
+
+_GenLP <P_CLPDT>,<CLP>,4 ; dialog template ptr
+_GenLP <P_CLPMT>,<CLP>,4 ; menu template ptr
+
+P_CLPMENUSTR equ <P_DWORD> ; menu string ptr: type depends on MF_*
+
+_GenLP <P_LPKBDSTATE>,<LP>,256
+_GenLP <P_CLPKBDSTATE>,<CLP>,256
+
+STRUCT <COMSTAT>
+F_BYTE flags
+F_WORD cbInQue
+F_WORD cbOutQue
+ENDSTRUCT
+
+_GenLP <P_LPCOMSTAT0>,<LP0>,%VLcbsCOMSTAT
+
+_DefSimpleF F_HDRVR,2
+_DefSimpleF F_HMODULE,2
+_DefSimpleF F_RGB128,128
+
+STRUCT <DRIVERINFOSTRUCT>
+F_WORD length
+F_HDRVR hDriver
+F_HMODULE hModule
+F_RGB128 szAliasName
+ENDSTRUCT
+
+P_LPDRIVERINFOSTRUCT macro lpdi,opts
+ _GenParm <lpdi>,4,<opts>
+ if VLgen
+ mov ax,_P_&lpdi
+ mov cx,_P_&lpdi+2
+ lcall LP0
+ _gensub LP
+ mov es,cx
+ mov bx,ax
+ cmp word ptr es:[bx]._F_length,VLcbsDRIVERINFOSTRUCT
+ jz @F
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+STRUCT <WINDOWPLACEMENT>
+F_WORD length
+F_FLAGS flags, WPF_VALID
+F_WORD showCmd
+F_POINT ptMinPosition
+F_POINT ptMaxPosition
+F_RECT rcNormalPosition
+ENDSTRUCT
+
+P_LPWINDOWPLACEMENT macro lpwp,opts
+ _GenParm <lpwp>,4,<opts>
+ if VLgen
+ mov ax,_P_&lpwp
+ mov cx,_P_&lpwp+2
+ mov bx,VLcbsWINDOWPLACEMENT
+ lcall LP
+ _gensub LP
+ mov es,cx
+ mov bx,ax
+ cmp word ptr es:[bx]._F_length,VLcbsWINDOWPLACEMENT
+ jz @F
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+P_CLPWINDOWPLACEMENT macro lpwp,opts
+ _GenParm <lpwp>,4,<opts>
+ if VLgen
+ mov ax,_P_&lpwp
+ mov cx,_P_&lpwp+2
+ mov bx,VLcbsWINDOWPLACEMENT
+ lcall CLP
+ _gensub CLP
+ mov es,cx
+ mov bx,ax
+ cmp word ptr es:[bx]._F_length,VLcbsWINDOWPLACEMENT
+ jz @F
+ mov bx,ERR_BAD_PTR
+ lcall Inval_Param_
+@@:
+ endif
+endm
+
+; Function pointers
+;
+P_LPFNWP equ <P_LPFN> ; Window proc
+P_LPFNDP equ <P_LPFN> ; dialog proc
+P_LPFNDP0 equ <P_LPFN0>
+P_LPFNWENUM equ <P_LPFN> ; EnumWindows() enumeration proc
+P_LPFNTIMER equ <P_LPFN> ; Timer proc
+P_LPFNTIMER0 equ <P_LPFN0>
+P_LPFNPENUM equ <P_LPFN> ; EnumProps() enumeration proc
+P_LPFNEVENTPROC0 equ <P_LPFN0> ; SetEventHook proc
+
+P_HOOKPROC equ <P_LPFN> ; SetWindowsHookEx() hook function
+_GenLP <P_LPHOOKPROC>,<LP>,4 ; Pointer to pointer to function
+
+P_HOTKEYPROC equ <P_LPFN>
+
+; SystemParametersInfo arguments
+
+P_SPIPARAMS macro id,wParam,lpParam,flags,opts
+P_UVALUE <id>,SPI_MAX,<opts>
+P_WORD <wParam>,<opts>
+P_LPVOID0 <lpParam>,<opts>
+P_FLAGS <flags>,SPIF_VALID,<opts>
+endm
+;
+; SetSysColors() parameters
+;
+P_CLPSYSCLRBUF macro count, lpIds, lpColors
+ P_int <count>, <opts>
+ P_CLPINT <id>, <opts>
+ P_CLPLONG <lpColors>, <opts>
+endm
+;
+; TabbedTextOut, et al
+;
+P_CLPTABBUF0 macro cTabStops, lpTabStops
+ _DefParm <cTabStops>,2,<opts>
+ _DefParm <lpTabStops>,4,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lpTabStops
+ mov cx,_P_&lpTabStops+2
+ mov bx,_P_&cTabStops
+ add bx,bx
+ lcall CLP0
+ _gensub LP
+ endif
+endm
+;
+; DrawText() lpch, cch
+;
+; if cch == -1, then lpch is a pointer to a zero-terminated string.
+;
+P_CLPBUFFERM1 macro lpch, cch, opts
+ local dt_chkstr
+ local dt_ok
+ _DefParm <lpch>,4,<opts>
+ _DefParm <cch>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lpch
+ mov cx,_P_&lpch+2
+ mov bx,_P_&cch
+ inc bx ;; if cch == -1, check zero-terminated string
+ jz dt_chkstr
+ dec bx
+ lcall CLP
+ _gensub LP
+ jmp short dt_ok
+dt_chkstr:
+ mov bx,-1
+ lcall CLPSZ
+ _gensub LPSZ
+dt_ok:
+ endif
+endm
+;
+; Buffer of words
+;
+P_LPWBUFFER macro lpw, cw, opts
+ _DefParm <lpw>,4,<opts>
+ _DefParm <cw>,2,<opts>
+ if VLgen
+ _FlsFrame
+ mov ax,_P_&lpw
+ mov cx,_P_&lpw+2
+ mov bx,_P_&cw
+ add bx,bx
+ lcall LP
+ _gensub LP
+ endif
+endm
+
+.list
+.lall
+
+;===========================================================================
+;
+; API Descriptions
+;
+; in CTLMGR.C
+API int, DrawText, TEXT
+P_HDC hdc
+P_CLPBUFFERM1 lpszText, cchText ; cchText == -1 means do strlen.
+P_LPRECT lprc
+P_FLAGS flags,DT_VALID ; if DT_TABSTOP, then hi byte is val.
+
+; in wTEXT.c
+API int, wvsprintf, TEXT
+P_LPSTR lpOut
+P_CLPSTR lpFmt
+P_CLPSTR0 lpParams
+APIERR
+E_SETEMPTYNC lpOut
+APIEND
+
+;;;;;;;;ChandanC TEMPLY!!! FIX ME
+; in wsprintf.c
+;API int, wsprintf, TEXT
+;P_LPSTR lpOut
+;P_CLPSTR lpFmt
+;APIERR
+;E_SETEMPTYNC lpOut
+;APIEND
+
+; in CTLMGR.C
+API DWORD, GetTabbedTextExtent, TEXT
+P_HDC hdc
+P_CLPBUFFER lpchText, cchText
+P_CLPTABBUF0 cTabStops, lpTabStops
+
+; in CTLMGR.C
+API LONG, TabbedTextOut, TEXT
+P_HDC hdc
+P_int x
+P_int y
+P_CLPBUFFER lpchText, cchText
+P_CLPTABBUF0 cTabStops, lpTabStops
+P_int xTabOrigin
+
+; in WMICON.C
+API BOOL, DrawIcon, TEXT
+P_HDC hdc
+P_int x
+P_int y
+P_HICON hIcon
+
+; in WMDC.C
+API HDC, GetWindowDC, TEXT ; ** calls GetDCEx directly
+P_HWND0 hwnd ; obsolete NULL - source of errors
+
+; in WMDC.C
+API HDC, GetDC, TEXT ; ** calls GetDCEx directly
+P_HWND0 hwnd ; obsolete NULL - source of errors
+
+; in WMDC.C
+API BOOL, ReleaseDC, TEXT ; return type is int in windows.h -- fix it
+P_HWND0 hwnd ; not used at all
+P_HDC hdc ; only used for comparison
+
+; in WMDC.C
+API HDC, GetDCEx, TEXT
+P_HWND hwnd ; Must be a real window.
+P_HRGN0 hrgn ; Can be NULL, what about (HRGN)1???
+P_DFLAGS flags,DCX_VALID_L,DCX_VALID_H
+
+; in WINLOOP3.ASM
+API WORD, RegisterWindowMessage, TEXT, <ASM, NOGEN> ; <WIN> calls AddAtom
+P_CLPSTRATOM lpszName ; const
+
+; in WINLOOP1.ASM
+API BOOL, GetMessage, TEXT, <ASM, FUNNYFRAME>
+P_LPMSG lpmsg ; Compound parameter
+P_HWND0 hwndFilter
+P_WORD msgFilterFirst
+P_WORD msgFilterLast
+APIERR
+ mov ax, -1 ;0 return indicates WM_QUIT was retrieved.
+APIEND ;so return -1 instead
+
+; in WINLOOP1.ASM
+API BOOL, TranslateMessage, TEXT, <ASM> ; <WIN>
+P_CLPMSG lpmsg
+
+; in WINLOOP1.ASM
+API LONG, DispatchMessage, TEXT, <ASM> ; <WIN>
+P_CLPMSG lpmsg ; const
+
+; in WINLOOP1.ASM
+API BOOL, PeekMessage, TEXT, <ASM, FUNNYFRAME>
+P_LPMSG lpmsg
+P_HWND0 hwndFilter
+P_WORD msgFilterFirst
+P_WORD msgFilterLast
+P_FLAGS flags,PM_VALID
+
+; in WINLANG.ASM
+API int, lstrcmp, TEXT, <ASM> ;error return value ?? (0 is valid)
+P_CLPSTR lpsz1, -1, DEBUGONLY
+P_CLPSTR lpsz2, -1, DEBUGONLY
+
+; in WINLANG.ASM
+API int, lstrcmpi, TEXT, <ASM>
+P_CLPSTR lpsz1, -1, DEBUGONLY ;error return value ?? (0 is valid)
+P_CLPSTR lpsz2, -1, DEBUGONLY
+
+; in INEXIT.C
+API BOOL, ExitWindows, TEXT, <NOGEN>
+P_DWORD errorCode
+P_WORDMBZ unused ; must be 0.
+
+; in INEXIT.C
+API BOOL, ExitWindowsExec, TEXT
+P_CLPSTR lpExeName
+P_CLPSTR0 lpParams
+
+; in WINMISC2.ASM
+API BOOL, SwapMouseButton, TEXT, <NOGEN, ASM, FUNNYFRAME>
+P_BOOL fSwap
+
+; in WINLOOP3.ASM
+API DWORD, GetMessagePos, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINLOOP3.ASM
+API LONG, GetMessageTime, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINLOOP3.ASM
+API LONG, GetMessageExtraInfo, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINMISC1.ASM
+API HWND, GetSysModalWindow, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINMISC1.ASM
+API HWND, SetSysModalWindow, TEXT, <ASM> ; <SMALL>
+P_HWND0 hwnd
+
+; SendMessage/PostMessage parameters
+;
+
+P_SMPARMS macro hwnd, msg, wParam, lParam, opts
+_DefParm <hwnd>,2,<opts>
+_DefParm <msg>,2,<opts>
+_DefParm <wParam>,2,<opts>
+_DefParm <lParam>,4,<opts>
+if VLgen
+ _FlsFrame
+ mov ax,_P_&hwnd ;; If hwnd == 0xFFFF, skip validation
+ inc ax
+ jz @F
+ push _P_&hwnd
+ push _P_&msg
+ push _P_&wParam
+ push _P_&lParam+2
+ push _P_&lParam
+ call far ptr ValidateMessage
+ or ax,ax
+ jnz @F
+ pop bx ; pop off error handler addr addr
+ pop bp ; and saved bp
+ cwd ; dx:ax = 0
+ jmp bx ; jump to error handler
+@@:
+endif
+endm
+
+; in WINSEND.ASM
+API LONG, SendMessage, TEXT, <ASM, FUNNYFRAME>
+P_SMPARMS hwnd, <msg>, wParam, lParam
+
+; in WINLOOP1.ASM
+API BOOL, PostMessage, TEXT, <ASM, FUNNYFRAME>
+P_SMPARMS hwnd, <msg>, wParam, lParam
+
+; in WINLOOP1.ASM
+API BOOL, PostAppMessage, TEXT, <ASM, FUNNYFRAME>
+P_HTASK hTask
+P_WORD <msg>
+P_WORD wParam
+P_LONG lParam
+
+; in WINSEND.ASM
+API void, ReplyMessage, TEXT, <NOGEN, ASM>
+P_LONG result
+
+; in WINSEND.ASM
+API void, WaitMessage, TEXT, <VOID, ASM>
+
+P_MSGPARMS macro hwnd, msg, wParam, lParam, opts
+_DefParm <hwnd>,2,<opts>
+_DefParm <msg>,2,<opts>
+_DefParm <wParam>,2,<opts>
+_DefParm <lParam>,4,<opts>
+if VLgen
+ _FlsFrame
+ push _P_&hwnd
+ push _P_&msg
+ push _P_&wParam
+ push _P_&lParam+2
+ push _P_&lParam
+ call far ptr ValidateMessage
+ or ax,ax
+ jnz @F
+ pop bx ; pop off error handler addr addr
+ pop bp ; and saved bp
+ cwd
+ jmp bx ; jump to error handler
+@@:
+endif
+endm
+
+; in MSDWP.C
+API LONG, DefWindowProc, TEXT
+P_MSGPARMS hwnd,<msg>,wParam,lParam
+
+; in WINLOOP3.ASM
+API void, PostQuitMessage, TEXT, <NOGEN, ASM>
+P_int exitCode
+
+; in WINLOOP1.ASM
+API LONG, CallWindowProc, TEXT, <ASM> ; <WIN>
+P_LPFNWP lpfnWndProc
+P_MSGPARMS hwnd,<msg>,wParam,lParam
+
+; in WINSEND.ASM
+API BOOL, InSendMessage, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINLOOP3.ASM
+API WORD, GetDoubleClickTime, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINLOOP3.ASM
+API void, SetDoubleClickTime, TEXT, <NOGEN, ASM, FUNNYFRAME>
+P_WORD ticks
+
+; in WMCLASS.C
+API BOOL, RegisterClass, TEXT
+P_CLPWNDCLASS lpwcls ; const
+
+; in WMCLASS.C
+API BOOL, UnregisterClass, TEXT
+P_CLPSTRATOM lpszClass
+P_HINSTANCE32 hInstance
+
+; in WMCLASS.C
+API BOOL, GetClassInfo, TEXT
+P_HINSTANCE0 hInstance
+P_CLPSTRATOM lpszClass
+P_LPWNDCLASS lpwcls
+
+; in WMCLASS.C
+API int, GetClassName, TEXT
+P_HWND hwnd
+P_LPBUFFER lpszName, cchName
+APIERR
+E_SETEMPTY lpszName, cchName
+APIEND
+
+; in WINQ.ASM
+API BOOL, SetMessageQueue, TEXT, <NOGEN, ASM>
+P_int cMsgs
+
+; in TMSWITCH.C
+API HWND, GetNextQueueWindow, TEXT
+P_HWND hwnd
+P_BOOL fPrevious ;; ??? HEADER FILE ERROR: should be BOOL
+
+; in CLASS.ASM
+API HWND, CreateWindow, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTRATOM lpszClass
+P_CLPSTR0 lpszText
+P_HMENU0CW style, x, y, cx, cy, hwndParent, hMenu
+P_HINSTANCE0 hInstance ; Need to allow 0 because IdleWild Bozos didn't initialize some variables
+P_DWORD lpCreateParams ; Should be CLPVOID0, but sometimes people pass other stuff
+
+; in WMCREATE.C
+API HWND, CreateWindowEx, TEXT
+P_DFLAGS exStyle, WS_EX_VALID_L, WS_EX_VALID_H
+P_CLPSTRATOM lpszClass
+P_CLPSTR0 lpszText
+P_HMENU0CW style, x, y, cx, cy, hwndParent, hMenu
+P_HINSTANCE hInstance
+P_DWORD lpCreateParams ; Should be CLPVOID0, but sometimes people pass other stuff
+
+; in WINMISC1.ASM
+API BOOL, IsWindow, TEXT, <NOGEN, ASM, FUNNYFRAME> ; No validation needed
+P_HWND hwnd
+
+; in WINMISC2.ASM
+API BOOL, IsChild, TEXT, <ASM, FUNNYFRAME, DEBUGONLY>
+P_HWND hwndParent, DEBUGONLY ;used for comparison only
+P_HWND0 hwndChild ; allow NULL for backward compatibility
+
+; in WMDSTROY.C
+API BOOL, DestroyWindow, TEXT
+P_HWND hwnd
+
+; in WINOBJ.C
+API BOOL, DragDetect, TEXT
+P_HWND hwndFrom
+P_POINT ptScreen
+
+API LRESULT, DragObject, TEXT
+P_HWND hwndParent
+P_HWND0 hwndFrom
+P_WORD wFmt
+P_LONG dwData
+P_HCURSOR0 hCursor
+
+; in WMSTATE.C
+API BOOL, GetWindowPlacement, TEXT
+P_HWND hwnd
+P_LPWINDOWPLACEMENT lpp
+
+; in WMSTATE.C
+API BOOL, SetWindowPlacement, TEXT
+P_HWND hwnd
+P_CLPWINDOWPLACEMENT lpp
+
+; in WMSHOW.C
+API BOOL, ShowWindow, TEXT
+P_HWND hwnd
+P_VALUE cmd,SW_MAX
+
+; in WMFLASH.C
+API BOOL, FlashWindow, TEXT
+P_HWND hwnd
+P_BOOL fFlash
+
+; in WMSHOW.C
+API void, ShowOwnedPopups, TEXT
+P_HWND hwnd
+P_BOOL fShow
+
+; in WMSHOW.C
+API BOOL, OpenIcon, TEXT
+P_HWND hwnd
+
+; in WMSHOW.C
+API void, CloseWindow, TEXT
+P_HWND hwnd
+
+; in WMMOVE.C
+API BOOL, MoveWindow, TEXT
+P_HWND hwnd
+P_int x
+P_int y
+P_int cx
+P_int cy
+P_BOOL fRedraw
+
+; in WMSWP.C
+API BOOL, SetWindowPos, TEXT
+P_HWND hwnd
+P_HWNDINSERT hwndInsertAfter
+P_int x
+P_int y
+P_int cx
+P_int cy
+P_FLAGS flags, SWP_VALID
+
+; in WMSWP.C
+API HDWP, BeginDeferWindowPos, TEXT, <NOGEN>
+P_int cwndHint
+
+; in WMSWP.C
+API HDWP, DeferWindowPos, TEXT,
+P_HDWP hdwp ; must be non-null
+P_HWND hwnd
+P_HWNDINSERT hwndInsertAfter
+P_int x
+P_int y
+P_int cx
+P_int cy
+P_FLAGS flags, SWP_VALID
+
+; in WMSWP.C
+API BOOL, EndDeferWindowPos, TEXT
+P_HDWP hdwp ; must be non-null
+
+; in WMSWP.C
+API BOOL, BringWindowToTop, TEXT
+P_HWND hwnd
+
+; in WINMISC2.ASM
+API BOOL, IsWindowVisible, TEXT, <ASM, FUNNYFRAME, DEBUGONLY>
+P_HWND hwnd
+
+; in WINMISC1.ASM
+API BOOL, IsIconic, TEXT, <ASM, FUNNYFRAME, DEBUGONLY>
+P_HWND hwnd
+
+; in WMMISC.C
+API BOOL, AnyPopup, TEXT, <VOID>
+
+; in WINMISC1.ASM
+API BOOL, IsZoomed, TEXT, <ASM, FUNNYFRAME, DEBUGONLY>
+P_HWND hwnd
+
+; in DLGBEGIN.C
+API HWND, CreateDialog, TEXT ; Calls CreateDialogParam
+P_HINSTANCE hModule
+P_CLPSTRRSRC lpszTemplateName
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+
+; in DLGBEGIN.C
+API HWND, CreateDialogIndirect, TEXT ; Calls CreateDialogIndirectParam
+P_HINSTANCE hInstance
+P_CLPDT lpDlgTemplate
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+
+; in DLGBEGIN.C
+API HWND, CreateDialogParam, TEXT
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpszTemplateName
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+P_LONG lParam
+
+; in DLGBEGIN.C
+API HWND, CreateDialogIndirectParam, TEXT
+P_HINSTANCE hInstance
+P_CLPDT lpDlgTemplate
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+P_LONG lParam
+
+; in DLGMGR.C
+API int, DialogBox, TEXT ; Calls DialogBoxParam
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpszTemplateName
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+
+; in DLGMGR.C
+API int, DialogBoxIndirect, TEXT ; Calls DialogBoxIndirectParam
+P_HINSTANCE hInstance
+P_GHANDLE hDlgTemplate
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+
+; in DLGMGR.C
+API int, DialogBoxParam, TEXT
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpszTemplateName
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+P_LONG lParam
+
+; in DLGMGR.C
+API int, DialogBoxIndirectParam, TEXT
+P_HINSTANCE hInstance
+P_GHANDLE hDlgTemplate
+P_HWND0 hwndOwner
+P_LPFNDP0 lpfnDlgProc
+P_LONG lParam
+
+; in DLGEND.C
+API void, EndDialog, TEXT
+P_HWND hwndDlg
+P_int result
+
+; in DLGMGR.C
+API HWND, GetDlgItem, TEXT
+P_HWND hwndDlg
+P_int idItem
+
+; in DLGMGR.C
+API void, SetDlgItemInt, TEXT ; calls SetDlgItemText
+P_HWND hwndDlg
+P_int idItem
+P_WORD value
+P_BOOL fSigned
+
+; in DLGMGR.C
+API WORD, GetDlgItemInt, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_LPBOOL0 lpfValOk
+P_BOOL fSigned
+
+
+; in DLGMGR.C
+API void, SetDlgItemText, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_CLPSTR0 lpszText
+
+ifdef DEBUG
+; in DLGMGR.C
+API int, GetDlgItemText, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_LPBUFFER lpszText, cchText
+APIERR
+E_SETEMPTY lpszText, cchText
+APIEND
+else
+; in DLGMGR.C
+API int, GetDlgItemText, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_DWORD lpszText
+P_WORD cchText
+endif
+
+; in DLGMGR.C
+API void, CheckDlgButton, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_WORD checkState
+
+; in DLGMGR.C
+API void, CheckRadioButton, TEXT ; calls CheckDlgButton
+P_HWND hwndDlg
+P_int idFirst
+P_int idLast
+P_int idCheck
+
+; in DLGMGR.C
+API WORD, IsDlgButtonChecked, TEXT
+P_HWND hwndDlg
+P_int idItem
+
+; in DLGMGR.C
+API LONG, SendDlgItemMessage, TEXT
+P_HWND hwndDlg
+P_int idItem
+P_WORD <msg>
+P_WORD wParam
+P_LONG lParam
+
+; in DMGROUP.C
+API HWND, GetNextDlgGroupItem, TEXT
+P_HWND hwndDlg
+P_HWND0 hwndCurrent
+P_BOOL fPrev
+
+; in DMGROUP.C
+API HWND, GetNextDlgTabItem, TEXT
+P_HWND hwndDlg
+P_HWND0 hwndCurrent
+P_BOOL fPrev
+
+; in DLGMGR.C
+API int, GetDlgCtrlID, TEXT
+P_HWND hwndCtl
+
+; in DLGBEGIN.C
+API long, GetDialogBaseUnits, TEXT, <VOID> ;??? SHOULD BE DWORD
+
+; in DLGMGR.C
+API LONG, DefDlgProc, TEXT
+P_MSGPARMS hwndDlg,<msg>,wParam,lParam
+;P_HWND hwndDlg
+;P_WORD <msg> ;??? should be unsigned
+;P_WORD wParam
+;P_LONG lParam
+
+; in WINHOOK.ASM
+API BOOL, CallMsgFilter, TEXT, <ASM>
+P_LPMSG lpmsg
+P_WORD code
+
+; in CLIPBRD.C
+API BOOL, OpenClipboard, TEXT
+P_HWND0 hwnd
+
+; in CLIPBRD.C
+API BOOL, CloseClipboard, TEXT, <VOID>
+
+; in CLIPBRD.C
+API HWND, GetOpenClipboardWindow, TEXT, <VOID>
+
+; in CBVIEWER.C
+API HWND, GetClipboardOwner, TEXT, <VOID>
+
+; in CBVIEWER.C
+API HWND, SetClipboardViewer, TEXT
+P_HWND0 hwndViewer
+
+; in CBVIEWER.C
+API HWND, GetClipboardViewer, TEXT, <VOID>
+
+; in CBVIEWER.C
+API BOOL, ChangeClipboardChain, TEXT
+P_HWND hwndRemove
+P_HWND0 hwndNewNext
+
+; in CBMGR.C
+API HANDLE, SetClipboardData, TEXT, <NOGEN>
+P_WORD fmt
+P_HCLIPDATA0 data
+
+; in CBMGR.C
+API HCLIPDATA, GetClipboardData, TEXT, <NOGEN>
+P_WORD fmt
+
+; in WINLOOP3.ASM
+API WORD, RegisterClipboardFormat, TEXT, <ASM> ; calls AddAtom
+P_CLPSTRATOM lpszName
+
+; in CBFORMAT.C
+API int, CountClipboardFormats, TEXT, <VOID>
+
+; in CLIPBRD.C
+API WORD, EnumClipboardFormats, TEXT, <NOGEN>
+P_WORD fmtCurrent
+
+; in CBFORMAT.C
+API int, GetClipboardFormatName, TEXT
+P_WORD fmt
+P_LPBUFFER lpszName, cchName
+APIERR
+E_SETEMPTY lpszName, cchName
+APIEND
+
+; in CBMGR.C
+API BOOL, EmptyClipboard, TEXT, <VOID>
+
+; in CBFORMAT.C
+API BOOL, IsClipboardFormatAvailable, TEXT, <NOGEN>
+P_WORD fmt
+
+; in CBFORMAT.C
+API int, GetPriorityClipboardFormat, TEXT ;??? Should be WORD return
+P_LPWBUFFER lpFmtList, cFmt
+
+; in WINLOOP2.C
+API HWND, SetFocus, TEXT
+P_HWND0 hwndNewFocus
+
+; in WINLOOP3.ASM
+API HWND, GetFocus, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINLOOP3.ASM
+API HWND, GetActiveWindow, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINEVENT.ASM
+API int, GetKeyState, TEXT, <NOGEN, ASM, FUNNYFRAME>
+P_int vkey ;??? SHOULD BE WORD
+
+; in WINEVENT.ASM
+API int, GetAsyncKeyState, TEXT, <NOGEN, ASM, FUNNYFRAME>
+P_int vkey ;??? SHOULD BE WORD
+
+; in WINEVENT.ASM
+API void, GetKeyboardState, TEXT, <ASM, FUNNYFRAME>
+P_LPKBDSTATE pKbdState
+
+; in WINEVENT.ASM
+API void, SetKeyboardState, TEXT, <ASM, FUNNYFRAME>
+P_CLPKBDSTATE pKbdState
+
+; in WINEVENT.ASM
+API BOOL, EnableHardwareInput, TEXT, <ASM, FUNNYFRAME, NOGEN> ; <NODATA, ATOMIC>
+P_BOOL fEnable
+
+; in WINEVENT.ASM
+API BOOL, GetInputState, TEXT, <ASM, VOID, FUNNYFRAME>
+
+; in WINEVENT.ASM
+API FARPROC, SetEventHook, TEXT, <ASM, FUNNYFRAME>
+P_LPFNEVENTPROC0 lpfnEventHookProc
+
+; in WINLOOP3.ASM
+API HWND, GetCapture, TEXT, <ASM, VOID, FUNNYFRAME>
+
+; in WINLOOP.C
+API HWND, SetCapture, TEXT, <ASM> ; <WIN>
+P_HWND0 hwndCapture
+
+; in WINLOOP.C
+API void, ReleaseCapture, TEXT, <ASM, VOID> ; <WIN>
+
+; in WINEVENT.ASM
+API DWORD, GetQueueStatus, TEXT, <ASM, FUNNYFRAME>
+P_FLAGS flags, QS_VALID
+
+ifdef DISABLE
+; in WINLOOP.C
+API WORD, GetSysInputMode, TEXT, <VOID>
+
+; in WINEVENT.ASM
+API BOOL, SetHotKeyHook, TEXT, <ASM> ; <PASCAL>
+P_HOTKEYPROC lpfnHookProc
+P_HINSTANCE hInstance
+P_BOOL fHook
+
+; in WINEVENT.ASM
+API BOOL, PostHotKeyEvent, TEXT, <ASM, FUNNYFRAME>
+P_HTASK hTask
+
+endif
+
+; in WINTIMER.ASM
+API WORD, SetTimer, TEXT, <ASM, FUNNYFRAME>
+P_HWND0 hwnd
+P_int id ;??? SHOULD BE WORD?
+P_WORD rate
+P_LPFNTIMER0 lpfnTimer
+
+; in WINTIMER.ASM
+API BOOL, KillTimer, TEXT, <ASM, FUNNYFRAME>
+P_HWND0 hwnd
+P_int id
+
+; in WMACT.C
+API BOOL, EnableWindow, TEXT
+P_HWND hwnd
+P_BOOL fEnable
+
+; in WINMISC1.ASM
+API BOOL, IsWindowEnabled, TEXT, <ASM, FUNNYFRAME, DEBUGONLY>
+P_HWND hwnd
+
+; in RMLOAD.ASM
+API HACCEL, LoadAccelerators, TEXT
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpszTemplateName
+
+; in MNACCEL.C
+API int, TranslateAccelerator, TEXT
+P_HWND hwnd
+P_HACCEL haccel
+P_CLPMSG lpmsg
+
+; in WINMISC2.ASM
+API int, GetSystemMetrics, TEXT, <ASM, FUNNYFRAME>
+P_VALUE metric,SM_MAX
+
+; in MNCREATE.C
+API HMENU, LoadMenu, TEXT
+P_HINSTANCE hInstance
+P_CLPSTRRSRC lpszTemplateName
+
+; in MNCREATE.C
+API HMENU, LoadMenuIndirect, TEXT
+P_CLPMT lpMenuTemplate
+
+; in WINMISC2.ASM
+API HMENU, GetMenu, TEXT, <ASM>
+P_HWND hwnd
+
+; in MNAPI.C
+API BOOL, SetMenu, TEXT
+P_HWND hwnd
+P_HMENU0 hMenu
+
+; in MNCHANGE.C
+API BOOL, ChangeMenu, TEXT
+P_HMENU hMenu
+P_WORD cmdInsert
+P_CLPMENUSTR lpNewItem
+P_WORD id
+P_FLAGS flags,MF_CHANGE_VALID
+
+; in MNACCEL.C
+API BOOL, HiliteMenuItem, TEXT
+P_HWND hwnd
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+
+; in MNAPI.C
+API int, GetMenuString, TEXT
+P_HMENU hMenu
+P_WORD id
+P_LPBUFFER lpszString, cchString
+P_FLAGS flags,MF_VALID
+APIERR
+E_SETEMPTY lpszString, cchString
+APIEND
+
+; in MNAPI2.ASM
+API WORD, GetMenuState, TEXT, <ASM> ; <WIN>
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+APIERR
+ mov ax,-1
+APIEND
+
+; in MNDRAW.ASM
+API void, DrawMenuBar, TEXT
+P_HWND hwnd
+
+; in MNSYS.C
+API HMENU, GetSystemMenu, TEXT
+P_HWND hwnd
+P_BOOL fRevert
+
+; in MNAPI.C
+API BOOL, SetSystemMenu, TEXT
+P_HWND hwnd
+P_HMENU hMenu
+
+; in MNCREATE.C
+API HMENU, CreateMenu, TEXT, <VOID>
+
+; in MNCREATE.C
+API HMENU, CreatePopupMenu, TEXT, <VOID>
+
+; in MNDSTRY.ASM
+API BOOL, DestroyMenu, TEXT, <ASM> ; <WIN>
+P_HMENU hMenu ; Old 3.1 code had HMENU0 here: is this true for 3.0?
+
+; in MNAPI2.ASM
+API BOOL, CheckMenuItem, TEXT, <ASM, FUNNYFRAME>
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+APIERR
+ mov ax, -1 ;return -1 (item doesn't exist) instead of 0
+APIEND ;since 0 is a valid return (MF_UNCHECKED)
+
+; in MNAPI2.ASM
+API BOOL, EnableMenuItem, TEXT, <ASM, FUNNYFRAME>
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+APIERR
+ mov ax, -1 ;return -1 (item doesn't exist) instead of 0
+APIEND ;since 0 is a valid return (MF_ENABLED)
+
+; in MNAPI2.ASM
+API HMENU, GetSubMenu, TEXT, <ASM> ; <WIN>
+P_HMENU hMenu
+P_int index
+
+; in MNDSTRY.ASM
+API WORD, GetMenuItemID, TEXT, <ASM> ; <WIN>
+P_HMENU hMenu
+P_int index
+APIERR
+ mov ax,-1
+APIEND
+
+; in MNAPI.C
+API WORD, GetMenuItemCount, TEXT
+P_HMENU hMenu
+APIERR
+ mov ax,-1
+APIEND
+
+; in MNCHANGE.C
+API BOOL, InsertMenu, TEXT
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+P_WORD idNew
+P_CLPMENUSTR lpszNew ; may be bitmap handle or arbitrary long
+
+; in MNCHANGE.C
+API BOOL, AppendMenu, TEXT
+P_HMENU hMenu
+P_FLAGS flags,MF_VALID
+P_WORD id
+P_CLPMENUSTR lpsz ; may be bitmap handle or arbitrary long
+
+; in MNCHANGE.C
+API BOOL, ModifyMenu, TEXT
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+P_WORD id
+P_CLPMENUSTR lpsz
+
+; in MNCHANGE.C
+API BOOL, RemoveMenu, TEXT
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+
+; in MNCHANGE.C
+API BOOL, DeleteMenu, TEXT
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+
+; in MNCHANGE.C
+API BOOL, SetMenuItemBitmaps, TEXT
+P_HMENU hMenu
+P_WORD id
+P_FLAGS flags,MF_VALID
+P_HBITMAP0 hbmCheckOff
+P_HBITMAP0 hbmCheckOn
+
+; in MNCHANGE.C
+API LONG, GetMenuCheckMarkDimensions, TEXT, <VOID> ; should return DWORD
+
+; in MNPOPUP.C
+API BOOL, TrackPopupMenu, TEXT
+P_HMENU hMenu
+P_FLAGS flags,TPM_VALID
+P_int x
+P_int y
+P_int cx
+P_HWND hwndOwner
+P_CLPRECT0 lprcClickSlop
+
+; in MNGRAY.C
+API BOOL, GrayString, TEXT
+P_HDC hdc ;??? not validated
+P_HBRUSH0 hbr
+P_LPFN0 lpfnPrint
+P_DWORD lpData
+P_int nCount
+P_int x
+P_int y
+P_int cx
+P_int cy
+
+; in WINLOOP4.ASM
+API HWND, SetActiveWindow, TEXT, <ASM>
+P_HWND0 hwndActive
+
+; in WMUPDATE.C
+API void, UpdateWindow, TEXT
+P_HWND hwnd
+
+; in PAINT.ASM
+API HDC, BeginPaint, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_LPPAINTSTRUCT lpps
+
+; in WMPAINT.C
+API void, EndPaint, TEXT
+P_HWND hwnd
+P_CLPPAINTSTRUCT lpps
+
+; in WMUPDATE.C
+API BOOL, GetUpdateRect, TEXT
+P_HWND hwnd
+P_LPRECT0 lprcUpdate
+P_BOOL fErase
+
+; in WMUPDATE.C
+API int, GetUpdateRgn, TEXT
+P_HWND hwnd
+P_HRGN hrgnUpdate
+P_BOOL fErase
+
+; in WMUPDATE.C
+API int, ExcludeUpdateRgn, TEXT
+P_HDC hdc
+P_HWND hwnd
+
+; in PAINT.ASM
+API void, InvalidateRect, TEXT, <ASM, FUNNYFRAME> ; Calls RedrawWindow
+P_HWND0 hwnd
+P_CLPRECT0 lprcInvalid
+P_BOOL fErase
+
+; in PAINT.ASM
+API void, ValidateRect, TEXT, <ASM, FUNNYFRAME> ; Calls RedrawWindow
+P_HWND hwnd
+P_CLPRECT0 lprcValid
+
+; in PAINT.ASM
+API void, InvalidateRgn, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_HRGN0 hrgnInvalid
+P_BOOL fErase
+
+; in PAINT.ASM
+API void, ValidateRgn, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_HRGN0 hrgnValid
+
+; in WMUPDATE.C
+API BOOL, RedrawWindow, TEXT
+P_HWND0 hwnd
+P_CLPRECT0 lprcRedraw
+P_HRGN0 hrgnRedraw
+P_FLAGS flags,RDW_VALID
+
+; in WINSPB2.C
+API BOOL, LockWindowUpdate, TEXT
+P_HWND0 hwnd
+
+; in WMSCROLL.C
+API void, ScrollWindow, TEXT ; Calls ScrollWindowEx
+P_HWND hwnd
+P_int dx
+P_int dy
+P_CLPRECT0 lprcScroll
+P_CLPRECT0 lprcClip
+
+; in WMSCROLL.C
+API BOOL, ScrollDC, TEXT
+P_HDC hdc
+P_int dx
+P_int dy
+P_CLPRECT0 lprcScroll
+P_CLPRECT0 lprcClip
+P_HRGN0 hrgnUpdate
+P_LPRECT0 lprcUpdate
+
+; in WMSCROLL.C
+API int, ScrollWindowEx, TEXT
+P_HWND hwnd
+P_int dx
+P_int dy
+P_CLPRECT0 lprcScroll
+P_CLPRECT0 lprcClip
+P_HRGN0 hrgnUpdate
+P_LPRECT0 lprcUpdate
+P_FLAGS flags,SW_VALID
+
+; in WINSBCTL.C
+API int, SetScrollPos, TEXT
+P_HWND hwnd
+P_VALUE code,SB_MAX
+P_int pos
+P_BOOL fRedraw
+
+; in SBRARE.C
+API int, GetScrollPos, TEXT
+P_HWND hwnd
+P_VALUE code,SB_MAX
+
+; in WINSBCTL.C
+API void, SetScrollRange, TEXT
+P_HWND hwnd
+P_VALUE code,SB_MAX
+P_int posMin
+P_int posMax
+P_BOOL fRedraw
+
+; in WINSB.C
+API void, GetScrollRange, TEXT
+P_HWND hwnd
+P_VALUE code,SB_MAX
+P_LPINT lpMin
+P_LPINT lpMax
+
+; in SBRARE.C
+API void, ShowScrollBar, TEXT
+P_HWND hwnd ;??? not validated
+P_VALUE code,SB_MAX ;??? Should be int in windows.h
+P_BOOL fRedraw
+
+; in WINSBCTL.C
+API BOOL, EnableScrollBar, TEXT
+P_HWND hwnd
+P_VALUE code,SB_MAX
+P_FLAGS flags,ESB_MAX
+
+; in WINPROPS.C
+API BOOL, SetProp, TEXT
+P_HWND hwnd
+P_CLPSTRATOM lpszName
+P_HANDLE0 hData
+
+; in WINMISC2.ASM
+API HANDLE, GetProp, TEXT, <ASM>
+P_HWND hwnd
+P_CLPSTRATOM lpszName
+
+; in WINPROPS.C
+API HANDLE, RemoveProp, TEXT
+P_HWND hwnd
+P_CLPSTRATOM lpszName
+
+; in WINPROPS.C
+API int, EnumProps, TEXT
+P_HWND hwnd
+P_LPFNPENUM lpfnPropEnum
+
+; in WINMISC1.ASM
+API void, SetWindowText, TEXT, <ASM> ; <SMALL>
+P_HWND hwnd
+P_CLPSTR0 lpszText
+
+ifdef DEBUG
+; in WINMISC1.ASM
+API int, GetWindowText, TEXT, <ASM> ; <SMALL>
+P_HWND hwnd
+P_LPBUFFER lpszText, cchText
+APIERR
+E_SETEMPTY lpszText, cchText
+APIEND
+else
+; in WINMISC1.ASM
+API int, GetWindowText, TEXT, <ASM> ; <SMALL>
+P_HWND hwnd
+P_DWORD lpszText
+P_WORD cchText
+APIERR
+E_SETEMPTY lpszText, cchText
+APIEND
+endif
+
+; in WINMISC1.ASM
+API int, GetWindowTextLength, TEXT, <ASM> ; <SMALL>
+P_HWND hwnd
+
+; in WINMISC1.ASM
+API void, GetClientRect, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_LPRECT lprcClient
+
+; in WINMISC1.ASM
+API void, GetWindowRect, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_LPRECT lprcWindow
+
+; in MSUTIL.C
+API void, AdjustWindowRect, TEXT ; calls AdjustWindowRectEx
+P_LPRECT lprcAdjust
+P_LONG style
+P_BOOL fMenu
+
+; in MSUTIL.C
+API void, AdjustWindowRectEx, TEXT
+P_LPRECT lprcAdjust ;??? not validated
+P_LONG style
+P_BOOL fMenu
+P_DWORD exStyle
+
+; in WMSYSERR.C
+API int, MessageBox, TEXT
+P_HWND0 hwndOwner
+P_CLPSTR0 lpszText
+P_CLPSTR0 lpszCaption
+P_FLAGS flags,MB_VALID
+
+; in WINMISC2.ASM
+API void, MessageBeep, TEXT, <NOGEN, ASM>
+P_WORD flags
+
+; in WMCURSOR.C
+API int, ShowCursor, TEXT, <NOGEN>
+P_BOOL fShow
+
+; in WINLOOP3.ASM
+API void, SetCursorPos, TEXT, <NOGEN, ASM, FUNNYFRAME>
+P_int x
+P_int y
+
+; in WMCURSOR.C
+API HCURSOR, GetCursor, TEXT, <VOID>
+
+; in WMCURSOR.C
+API HCURSOR, SetCursor, TEXT
+P_HCURSOR0 hcsr
+
+; in WINLOOP3.ASM
+API void, GetCursorPos, TEXT, <ASM, FUNNYFRAME>
+P_LPPOINT lppt
+
+; in WINMOUSE.ASM
+API void, ClipCursor, TEXT, <ASM>
+P_CLPRECT0 lprcClip
+
+; in WINMOUSE.ASM
+API void, GetClipCursor, TEXT, <ASM>
+P_LPRECT lprcClip
+
+; in WMCARET.C
+API void, CreateCaret, TEXT
+P_HWND hwnd
+P_HBITMAP01 hbmCaret ; can be 0 or 1 (1 for dithered caret)
+P_int x
+P_int y
+
+; in WMCARET.C
+API WORD, GetCaretBlinkTime, TEXT, <VOID>
+
+; in INCTLPAN.C
+API void, SetCaretBlinkTime, TEXT, <NOGEN>
+P_WORD rate
+
+; in WMCARET.C
+API void, DestroyCaret, TEXT, <VOID>
+
+; in WMCARET.C
+API void, HideCaret, TEXT
+P_HWND0 hwnd ;??? Why is NULL allowed?
+
+; in WMCARET.C
+API void, ShowCaret, TEXT
+P_HWND0 hwnd ;??? Why is NULL allowed?
+
+; in WMCARET.C
+API void, SetCaretPos, TEXT, <NOGEN>
+P_int x
+P_int y
+
+; in WMCARET.C
+API void, GetCaretPos, TEXT, <NOGEN>
+P_LPPOINT lppt
+
+; in WINMISC1.ASM
+API void, ClientToScreen, TEXT, <ASM>
+P_HWND0 hwnd
+P_LPPOINT lppt
+
+; in WINMISC1.ASM
+API void, ScreenToClient, TEXT, <ASM>
+P_HWND0 hwnd
+P_LPPOINT lppt
+
+; in WINMISC1.C
+API void, MapWindowPoints, TEXT, <ASM>
+P_HWND0 hwndFrom
+P_HWND0 hwndTo
+P_LPPOINT lppt
+P_WORD cpt
+
+; in WINWHERE.C
+API HWND, WindowFromPoint, TEXT, <NOGEN>
+P_POINT pt
+
+; in WINWHERE.C
+API HWND, ChildWindowFromPoint, TEXT
+P_HWND hwnd
+P_POINT pt
+
+; in WINLOOP3.ASM
+API DWORD, GetSysColor, TEXT, <ASM, FUNNYFRAME>
+P_VALUE idColor,COLOR_MAX
+
+; in WMCOLOR.C
+API void, SetSysColors, TEXT
+P_CLPSYSCLRBUF count, lpIds, lpColors
+
+; in WINRECT.ASM
+API void, DrawFocusRect, TEXT, <ASM, FUNNYFRAME> ; <NODATA>
+P_HDC hdc
+P_CLPRECT lprc
+
+; in WINRECT.ASM
+API int, FillRect, TEXT, <ASM, FUNNYFRAME> ; <NODATA>
+P_HDC hdc
+P_CLPRECT lprc
+P_HBRUSH hbr
+
+; in WINRECT.ASM
+API int, FrameRect, TEXT, <ASM, FUNNYFRAME> ; <NODATA>
+P_HDC hdc
+P_CLPRECT lprc
+P_HBRUSH hbr
+
+; in WINRECT.ASM
+API void, InvertRect, TEXT, <ASM, FUNNYFRAME> ; <NODATA>
+P_HDC hdc
+P_CLPRECT lprc
+
+; in WINRECT.ASM
+API void, SetRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ; <NODATA>
+P_LPRECT lprc
+P_int left
+P_int top
+P_int right
+P_int bottom
+
+; in WINRECT.ASM
+API void, SetRectEmpty, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ; <NODATA>
+P_LPRECT lprc
+
+; in WINRECT.ASM
+API void, CopyRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_CLPRECT lprcSrc
+P_LPRECT lprcDst
+
+; in WINRECT.ASM
+API void, InflateRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_LPRECT lprc
+P_int dx
+P_int dy
+
+; in WINRECT.ASM
+API BOOL IntersectRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_LPRECT lprcDst
+P_CLPRECT lprc1
+P_CLPRECT lprc2
+
+; in WINRECT.ASM
+API BOOL UnionRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_LPRECT lprcDst
+P_CLPRECT lprc1
+P_CLPRECT lprc2
+
+; in WINRECT.ASM
+API int, SubtractRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>, ??? Add to windows.h
+P_LPRECT lprcDst
+P_CLPRECT lprc1
+P_CLPRECT lprc2
+
+; in WINRECT.ASM
+API void, OffsetRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_LPRECT lprcDst
+P_int lprc1
+P_int lprc2
+
+; in WINRECT.ASM
+API BOOL, IsRectEmpty, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ;<NODATA>
+P_CLPRECT lprc
+
+; in WINRECT.ASM
+API BOOL, EqualRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ; <NODATA>
+P_CLPRECT lprc1
+P_CLPRECT lprc2
+
+; in WINRECT.ASM
+API BOOL, PtInRect, TEXT, <ASM, FUNNYFRAME, DEBUGONLY> ; <NODATA>
+P_CLPRECT lprc
+P_POINT pt
+
+_GenLP <P_CLPANSISTR>,<CLP>,1 ; AnsiNext/Prev string ptr
+
+P_CLPSTRCHAR macro name, opts
+ _GenParm <name>,4,<opts>
+ if VLgen
+ mov ax,_P_&name ; if it's NULL or char, accept.
+ mov cx,_P_&name+2
+ jcxz @F
+ mov bx,1 ; otherwise make sure there is at least
+ lcall CLP ; one byte available.
+ _gensub LP
+ @@:
+ endif
+endm
+
+; in winstr.asm
+API LPSTR, AnsiUpper, TEXT, <ASM,FUNNYFRAME>
+P_CLPSTRCHAR lpString
+
+; in winstr.asm
+API LPSTR, AnsiLower, TEXT, <ASM,FUNNYFRAME>
+P_CLPSTRCHAR lpString
+
+; in winlang.asm
+API LPSTR, AnsiUpperBuff, TEXT, <ASM,FUNNYFRAME>
+P_LPBUFFER lpch, cch
+
+; in winlang.asm
+API LPSTR, AnsiLowerBuff, TEXT, <ASM,FUNNYFRAME>
+P_LPBUFFER lpch, cch
+
+; in winlang.asm
+API LPSTR, AnsiNext, TEXT, <ASM,FUNNYFRAME>
+P_CLPANSISTR lpString
+
+; in winlang.asm
+API LPSTR, AnsiPrev, TEXT, <ASM,FUNNYFRAME>
+P_CLPANSISTR lpString
+P_CLPANSISTR lpCurrentChar
+
+; in WINTIMER.ASM
+API DWORD, GetCurrentTime, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINTIMER.ASM
+API DWORD, GetTickCount, TEXT, <VOID, ASM, FUNNYFRAME>
+
+; in WINTIMER.ASM
+API DWORD, GetTimerResolution, TEXT, <VOID, ASM, FUNNYFRAME>
+
+ifndef WOW
+; blow this off, it doesn't do anything but waste 6 instructions
+; in WINSTRUC.ASM
+API WORD, GetWindowWord, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GWWINDEX index
+endif
+
+GWW_HWNDPARENT equ -8
+
+P_SWWPARMS macro index,value
+ _GenParm <index>,2,<opts>
+ _GenParm <value>,2,<opts>
+ if VLgen
+ IFNDEF WOW
+ cmp word ptr _P_&index,GWW_HWNDPARENT
+ jnz @F
+ mov bx,_P_&value ; validate the supplied parent.
+ lcall VHWND0
+ _gensub VHWND
+ @@:
+ ENDIF
+ endif
+endm
+
+; in WINSTRUC.ASM
+API WORD, SetWindowWord, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_SWWPARMS index,value
+
+ifndef WOW
+; blow this off, it doesn't do anything but waste 6 instructions
+; in WINSTRUC.ASM
+API LONG, GetWindowLong, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GWWINDEX index
+endif
+
+GWL_WNDPROC equ -4
+GWL_EXSTYLE equ -20
+
+P_SWLPARMS macro index,value,opts
+ local notwndproc,notexstyle,cont
+ _DefParm <index>,2,<opts>
+ _DefParm <value>,4,<opts>
+ if VLgen
+ _FlsFrame
+
+ mov ax,word ptr _P_&index
+ cmp ax,GWL_WNDPROC ; is he subclassing?
+ jnz notwndproc
+ mov ax,_P_&value
+ mov cx,_P_&value+2
+ lcall LPFN
+ _gensub LPFN
+if 0 ; Not always a bug,
+ ; and too many people get an error.
+ ; Could compare DS with hwnd->hInstance
+ ; if different: then check.
+ifdef DEBUG
+ mov es,cx
+ mov bx,ax
+ cmp es:[bx],09090h ; nop, nop, nop?
+ jnz @F ; that's bogus...
+ mov bx,ERR_BAD_PTR or ERR_WARNING
+ lcall Inval_Param_
+endif
+endif
+ jmp short cont;
+notwndproc:
+ cmp word ptr _P_&index,GWL_EXSTYLE
+ jnz notexstyle
+
+ IFDEF WOW ; ChandanC
+ jmp SHORT notexstyle
+ ENDIF
+
+ mov ax,_p_&value
+ mov cx,_p_&value+2
+ test ax,not WS_EX_VALID_L
+ jnz @F
+ test cx,not WS_EX_VALID_H
+ jnz @F
+ jmp notexstyle
+@@:
+ mov bx,ERR_BAD_DFLAGS or ERR_WARNING
+ lcall Inval_Param_
+notexstyle:
+cont:
+ endif
+endm
+
+; in WINSTRUC.ASM
+API LONG, SetWindowLong, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_SWLPARMS index, value
+
+; in WINSTRUC.ASM
+API WORD, GetClassWord, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GCWINDEX index
+
+; in WINSTRUC.ASM
+API WORD, SetClassWord, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GCWINDEX index
+P_WORD value
+
+; in WINSTRUC.ASM
+API LONG, GetClassLong, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GCWINDEX index
+
+; in WINSTRUC.ASM
+API LONG, SetClassLong, TEXT, <ASM, FUNNYFRAME>
+P_HWND hwnd
+P_GCWINDEX index
+P_LONG value
+
+; in WINMISC1.ASM
+API HWND, GetDesktopHwnd, TEXT, <VOID, ASM>
+
+; in WINMISC1.ASM
+API HWND, GetDesktopWindow, TEXT, <VOID, ASM>
+
+; in WINSHOW.C
+API HWND, GetParent, TEXT
+P_HWND hwnd
+
+; in WMMISC.C
+API HWND, SetParent, TEXT
+P_HWND hwnd
+P_HWND0 hwndNewParent ; NULL is allowed here, but not for create. Need hwndObject or something.
+
+; in WMLIST.C
+API BOOL, EnumChildWindows, TEXT
+P_HWND hwnd
+P_LPFNWENUM lpfnEnum
+P_LONG lParam
+
+; in WMFIND.C
+API HWND, FindWindow, TEXT
+P_CLPSTRATOM0 lpszClass
+P_CLPSTR0 lpszText
+
+; in WMLIST.C
+API BOOL, EnumWindows, TEXT
+P_LPFNWENUM lpfnEnum
+P_LONG lParam
+
+; in WINMISC1.ASM
+API BOOL, EnumTaskWindows, TEXT, <ASM> ; <SMALL>
+P_HTASK hTask ;??? not validated
+P_LPFNWENUM lpfnEnum
+P_LONG lParam
+
+; in WINSHOW.C
+API HWND, GetTopWindow, TEXT
+P_HWND0 hwnd
+
+; in WINSHOW.ASM
+API HWND, GetNextWindow, TEXT, <OBSOLETE, NOGEN>
+P_HWND hwnd
+P_UVALUE code,GW_MAX
+
+; in WINMISC1.ASM
+API HTASK, GetWindowTask, TEXT, <ASM>
+P_HWND hwnd
+
+; in WINSHOW.C
+API HWND, GetLastActivePopup, TEXT
+P_HWND hwnd
+
+; in WMDC.C
+API HWND, GetWindow, TEXT
+P_HWND hwnd
+P_UVALUE cmd,GW_MAX
+
+; in WINHOOK.ASM
+API HOOKPROC, SetWindowsHook, TEXT, <ASM>
+P_RVALUE idHook,WH_MIN,WH_MAX
+P_HOOK_HK lpfnHook
+
+; in WINHOOK.ASM
+API BOOL, UnhookWindowsHook, TEXT, <ASM>
+P_RVALUE idHook,WH_MIN,WH_MAX
+P_HOOKPROC lpfnHook
+
+; in WINHOOK.ASM
+API DWORD, DefHookProc, TEXT, <ASM>
+P_int code
+P_WORD wParam
+P_DWORD lParam
+P_LPHOOKPROC lplpfnHook
+
+; in WINHOOK.ASM
+API HHOOK, SetWindowsHookEx, TEXT, <ASM, FUNNYFRAME>
+P_RVALUE idHook,WH_MIN,WH_MAX
+P_HOOKPROC lpfnHook
+P_HINSTANCE hInstance
+P_HTASK0 hTask
+
+; in WINHOOK.ASM
+API BOOL, UnhookWindowsHookEx, TEXT, <ASM, FUNNYFRAME>
+P_HHOOK hHook
+
+; in WINHOOK.ASM
+API DWORD, CallNextHookEx, TEXT, <ASM>
+P_HHOOK hHook
+P_RVALUE idHook,WH_MIN,WH_MAX
+P_WORD wParam
+P_LONG lParam
+
+; in RMLOAD.C
+API HBITMAP, LoadBitmap, TEXT
+P_HINSTANCE0 hInstance
+P_CLPSTRRSRC lpszRsrcName
+
+; in RMLOAD.C
+API HCURSOR, LoadCursor, TEXT
+P_HINSTANCE0 hInstance
+P_CLPSTRRSRC lpszRsrcName
+
+; in RMCREATE.C
+API HCURSOR, CreateCursor, TEXT
+P_HINSTANCE hInstance
+P_int xHotSpot
+P_int yHotSpot
+P_int cx
+P_int cy
+P_CLPBYTE lpAndMask ;??? LPBYTE, not LPSTR
+P_CLPBYTE lpXorMask
+
+; in RMCREATE.C
+API BOOL, DestroyCursor, TEXT
+P_HCURSOR hCursor
+
+; in RMCREATE.C
+API HCURSOR, CopyCursor, TEXT
+P_HINSTANCE hInstance
+P_HCURSOR hCursor
+
+
+; in RMLOAD.C
+API HICON, LoadIcon, TEXT
+P_HINSTANCE0 hInstance
+P_CLPSTRRSRC lpszRsrcName
+
+; in RMCREATE.C
+API HICON, CreateIcon, TEXT
+P_HINSTANCE hInstance
+P_int cx
+P_int cy
+P_BYTE cPlanes
+P_BYTE cBitsPixel
+P_CLPBYTE lpAndMask ;??? LPBYTE, not LPSTR
+P_CLPBYTE lpXorMask
+
+; in RMCREATE.C
+API BOOL, DestroyIcon, TEXT
+P_HICON hIcon
+
+; in RMCREATE.C
+API HICON, CopyIcon, TEXT
+P_HINSTANCE hInstance
+P_HICON hIcon
+
+; in RMCREATE.C
+API void, GetInternalIconHeader, TEXT
+P_CLPBYTE lpHeader
+P_LPBYTE lpDestBuff
+
+
+; in RMLOAD.C
+API int, LoadString, TEXT
+P_HINSTANCE hInstance
+P_WORD idString
+P_LPBUFFER0 lpszString, cchString
+APIERR
+E_SETEMPTY lpszString, cchString
+APIEND
+
+; in WINMISC1.ASM
+API BOOL, IsTwoByteCharPrefix, TEXT, <ASM, NOGEN>
+P_char ch
+
+; in DLGMGR2.C
+API BOOL, IsDialogMessage, TEXT
+P_HWND hwndDlg
+P_CLPMSG lpmsg
+
+; in DLGBEGIN.C
+API void, MapDialogRect, TEXT
+P_HWND hwndDlg
+P_LPRECT lprcMap
+
+; in LBOXCTL3.C
+API int, DlgDirList, TEXT
+P_HWNDNOFAIL0 hwndDlg
+P_LPSTR0 lpszPathSpec
+P_int idListBox
+P_int idStatic
+P_FLAGS flags,DDL_VALID ;??? Need constants in windows.h
+
+; in LBOXCTL3.C
+API BOOL, DlgDirSelect, TEXT
+P_HWND hwndDlg
+P_LPSTR lpszPathSpec
+P_int idListBox
+
+API BOOL, DlgDirSelectEx, TEXT
+P_HWND hwndDlg
+P_LPBUFFER lpszPathSpec,cchMax
+P_int idListBox
+
+; in COMBODIR.C
+API int, DlgDirListComboBox, TEXT
+P_HWND hwndDlg
+P_LPSTR0 lpszPathSpec
+P_int idComboBox
+P_int idStatic
+P_FLAGS flags,DDL_VALID
+
+API BOOL, GlobalFindAtom, TEXT
+P_CLPSTR lpszPath
+
+; in COMBODIR.C
+API BOOL, DlgDirSelectComboBox, TEXT
+P_HWND hwnd
+P_LPSTR lpszPath
+P_int idComboBox
+
+API BOOL, DlgDirSelectComboBoxEx, TEXT
+P_HWND hwnd
+P_LPBUFFER lpszPath, cchMax
+P_int idComboBox
+
+; in MDIWIN.C
+API LONG, DefFrameProc, TEXT
+P_HWND hwnd ;??? not validated
+P_WORD hwndMDI ;Need to validate specially since not always
+ ;used and may be destroyed when DFP is called
+P_WORD <msg> ;??? Should be unsigned
+P_WORD wParam
+P_LONG lParam
+
+; in MDIWIN.C
+API LONG, DefMDIChildProc, TEXT
+P_MSGPARMS hwndDlg,<msg>,wParam,lParam
+;P_HWND hwnd
+;P_WORD <msg> ;??? Should be unsigned
+;P_WORD wParam
+;P_LONG lParam
+
+; in MDIWIN.C
+API BOOL, TranslateMDISysAccel, TEXT
+P_HWND hwnd
+P_CLPMSG lpmsg
+
+; in DTPARK.C
+API WORD, ArrangeIconicWindows, TEXT
+P_HWND hwnd
+
+; in WINRARE.C
+API BOOL, SystemParametersInfo, TEXT
+P_SPIPARAMS id, wParam, lpParam, flags
+
+; in HELPCALL.C
+API BOOL, WinHelp, TEXT
+P_HWND0 hwnd ; Allow NULL cause WinHelp.exe uses it internally
+P_CLPSTR0 lpszHelp
+P_WORD cmd
+P_DWORD data
+
+; in DRVRRARE.C
+API HDRVR, OpenDriver, TEXT
+P_CLPSTR szDriverName
+P_CLPSTR0 szSectionName
+P_LONG lParam2
+
+; in DRVRRARE.C
+API LONG, CloseDriver, TEXT
+P_HDRVR hDriver
+P_LONG lParam1
+P_LONG lParam2
+
+; in DRVRRARE.C
+API HMODULE,GetDriverModuleHandle, TEXT
+P_HDRVR hDriver
+
+; in DRVR.C
+API LONG, SendDriverMessage, TEXT
+P_HDRVR0 hDriver
+P_WORD message
+P_LONG lParam1
+P_LONG lParam2
+
+; in DRVR.C
+API LONG, DefDriverProc, TEXT
+P_DWORD idDriver
+P_HDRVR hDriver ;??? not validated
+P_WORD message
+P_LONG lParam1
+P_LONG lParam2
+
+; in DRVR.C
+API HDRVR, GetNextDriver, TEXT
+P_HDRVR0 hDriverCurrent
+P_DFLAGS flags,GND_VALID_L, GND_VALID_H
+
+; in DRVR.C
+API BOOL, GetDriverInfo, TEXT
+P_HDRVR hDriver
+P_LPDRIVERINFOSTRUCT lpInfo
+
+; in PALETTE.C
+API HPALETTE, SelectPalette, TEXT
+P_HDC hdc
+P_HPALETTE hpal ;??? not validated
+P_BOOL fForceBackground
+
+; in PALETTE.C
+API WORD, RealizePalette, TEXT
+P_HDC hdc
+
+; in COMDEV.C
+API CID, OpenComm, TEXT
+P_CLPSTR pszComName
+P_WORD cbInQueue
+P_WORD cbOutQueue
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, SetCommState, TEXT
+P_CLPDCB lpdcb
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, GetCommState, TEXT
+P_CID cid
+P_LPDCB lpdcb
+APIERR
+ mov ax, -1 ;negative error code
+APIEND ;0 => success
+
+; in COMDEV.C
+API int, ReadComm, TEXT
+P_CID cid
+P_LPBUFFER lpBuffer, cbBuffer
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, UngetCommChar, TEXT
+P_CID cid
+P_char ch
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, WriteComm, TEXT
+P_CID cid
+P_CLPBUFFER lpBuffer, cbBuffer
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, CloseComm, TEXT
+P_CID cid
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, GetCommError, TEXT
+P_CID cid
+P_LPCOMSTAT0 lpComStat
+
+; in COMDEV.C
+API int, BuildCommDCB, TEXT
+P_CLPSTR lpszDef
+P_LPDCB lpdcb
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, TransmitCommChar, TEXT
+P_CID cid
+P_char ch
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API LPWORD, SetCommEventMask, TEXT
+P_CID cid
+P_FLAGS evtMask,EV_VALID
+
+; in COMDEV.C
+API WORD, GetCommEventMask, TEXT
+P_CID cid
+P_FLAGS evtMask,EV_VALID
+
+; in COMDEV.C
+API int, SetCommBreak, TEXT
+P_CID cid
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, ClearCommBreak, TEXT
+P_CID cid
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API int, FlushComm, TEXT
+P_CID cid
+P_int queue
+APIERR
+ mov ax, -1 ;negative error code
+APIEND
+
+; in COMDEV.C
+API LONG, EscapeCommFunction, TEXT
+P_CID cid
+P_int fcn
+APIERR
+ mov ax, -1 ;negative error code
+ cwd
+APIEND
+
+; in COMDEV.C
+API BOOL, EnableCommNotification, TEXT
+P_CID cid
+P_HWND0 hwnd
+P_int recvTh
+P_int sendTh
+
+
+;===========================================================================
+;
+; WNet API validation
+;
+WNNC_MIN equ -1
+WNNC_MAX equ 11
+WNBD_CONN_MIN equ 1
+WNBD_CONN_MAX equ 3
+
+; error returns (defined in winnet.h)
+
+WN_BAD_POINTER equ 4
+WN_BAD_VALUE equ 5
+
+;-------------------------------
+; Special-case macro definitions
+
+P_LPBUFFERLPWSIZE macro lpbuf, lpsize, opts
+ _DefParm <lpbuf>,4,<opts>
+ _DefParm <lpsize>,4,<opts>
+ if VLgen
+
+ _FlsFrame
+ mov ax, _P_&lpsize
+ mov cx, _P_&lpsize+2
+ mov bx, 2
+ lcall LP ;first check ptr. to size WORD
+ _gensub LP
+
+ les bx,_P_&lpsize
+ mov bx,es:[bx] ;ax = size of buffer
+
+ mov ax,_P_&lpbuf
+ mov cx,_P_&lpbuf+2
+ lcall LP ;check buffer size
+ endif
+endm
+
+;----------------
+; API definitions (all in winnet.asm)
+
+API WORD, WNetGetCaps, TEXT, <ASM, FUNNYFRAME>
+P_RVALUE nIndex, WNNC_MIN, WNNC_MAX
+
+API WORD, WNetDeviceMode, TEXT, <ASM, FUNNYFRAME>
+P_HWND0 hWndParent ;Driver calls DialogBox with hWndParent as
+ ;dialog owner => NULL hWnd is acceptable
+APIERR
+ mov ax, WN_BAD_VALUE
+APIEND
+
+API WORD, WNetBrowseDialog, TEXT, <ASM, FUNNYFRAME>
+P_HWND0 hWndParent
+P_RVALUE wType, WNBD_CONN_MIN, WNBD_CONN_MAX
+P_LPSTR lpPath ;buffer should be at least 128 chars. long
+APIERR
+ mov ax, WN_BAD_VALUE
+APIEND
+
+API WORD, WNetGetUser, TEXT, <ASM, FUNNYFRAME>
+P_LPBUFFERLPWSIZE lpUserName, lpwSize ; lpwSize is far ptr. to WORD
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetAddConnection, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR lpNetPath
+P_CLPSTR0 lpPassWd
+P_CLPSTR lpLocal ;"A:"-"Z:", "LPT1:"-"LPT4:"
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetCancelConnection, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR lpName
+P_BOOL bForce
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetGetConnection, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR lpLocal
+P_LPBUFFERLPWSIZE lpRemoteName, lpwSize ;lpwSize is far ptr. to WORD
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetWatchQueue, TEXT, <ASM, FUNNYFRAME>
+P_HWND hWndNotify ;can be null?
+P_CLPSTR lpLocal
+P_CLPSTR0 szUSer
+P_WORD nQueue
+APIERR
+ mov ax, WN_BAD_VALUE
+APIEND
+
+API WORD, WNetUnwatchQueue, TEXT,<ASM, FUNNYFRAME>
+P_CLPSTR lpLocal
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetLockQueueData, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_CLPSTR0 szUser
+P_LPDWORD lplpQueueStruct ;driver returns ptr to QUEUESTRUCT
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetUnlockQueueData, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API HFILE, WNetOpenJob, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_CLPSTR0 szTitle
+P_WORD nCopies
+P_LPWORD lpw ;file handle returned
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+P_HFILE equ <P_H>
+
+API WORD, WNetCloseJob, TEXT, <ASM, FUNNYFRAME>
+P_HFILE fh
+P_LPWORD0 lpwIDJob
+P_LPSTR0 szQueue ;name of net. queue returned here
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetHoldJob, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_WORD wJobID
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetReleaseJob, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_WORD wJobID
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetCancelJob, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_WORD wJobID
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetSetJobCopies, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR szQueue
+P_WORD wJobID
+P_WORD nCopies
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetAbortJob, TEXT, <ASM, FUNNYFRAME>
+P_CLPSTR lpDevice
+P_HFILE fh
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetGetError, TEXT, <ASM, FUNNYFRAME>
+P_LPWORD lpwError
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
+
+API WORD, WNetGetErrorText, TEXT, <ASM, FUNNYFRAME>
+P_WORD wError
+P_LPBUFFERLPWSIZE lpRemoteName, lpwSize ;lpwSize is far ptr. to WORD
+APIERR
+ mov ax, WN_BAD_POINTER
+APIEND
diff --git a/private/mvdm/wow16/user/user.asm b/private/mvdm/wow16/user/user.asm
new file mode 100644
index 000000000..9c38bbac9
--- /dev/null
+++ b/private/mvdm/wow16/user/user.asm
@@ -0,0 +1,413 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; USER.ASM
+; Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+;
+;--
+
+ TITLE USER.ASM
+ PAGE ,132
+
+ ; Some applications require that USER have a heap. This means
+ ; we must always have: LIBINIT equ 1
+ LIBINIT equ 1
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+ifdef LIBINIT
+externFP LocalInit
+endif
+externFP LW_InitNetInfo
+ifndef WOW
+externNP LW_DriversInit
+endif
+
+externFP GetModuleHandle
+externFP SetTaskSignalProc
+externFP NewSignalProc
+externFP IsWindow
+externFP CreateQueue
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+
+sBegin DATA
+DontMove db 2 dup (0) ; <<< WARNING 2 bytes *must* be reserved at the start
+ ; users DS for compatability >>>>
+Reserved db 16 dup (0) ;reserved for Windows
+USER_Identifier db 'USER16 Data Segment'
+fFirstApp db 1
+
+externD LPCHECKMETAFILE;
+ExternW <hInstanceWin>
+ExternW <hWinnetDriver>
+
+GlobalW hwndSysModal,0
+
+sEnd DATA
+
+;
+; GP fault exception handler table definition
+;
+sBegin GPFIX0
+__GP label word
+public __GP
+sEnd GPFIX0
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+ifdef LIBINIT
+externFP LibMain
+endif
+
+ifdef WOW
+externFP EnableSystemTimers
+externFP SetDivZero
+endif
+
+cProc USER16,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+
+ cBegin <nogen>
+
+ifdef WOW
+ call EnableSystemTimers
+endif
+
+ IFDEF LIBINIT
+ ; push params and call user initialisation code
+
+ push di ;hModule
+ mov hInstanceWin, di
+
+ ; if we have a local heap declared then initialize it
+
+ jcxz no_heap
+
+ push 0 ;segment
+ push 0 ;start
+ push cx ;length
+ call LocalInit
+
+no_heap:
+ call LibMain ;return exit code from LibMain
+ ELSE
+ mov ax,1 ;are we dressed for success or WHAT?!
+ ENDIF
+ push ax
+ cmp hInstanceWin, 0
+ jne hInstNotNull
+ mov hInstanceWin, di
+
+hInstNotNull:
+ifndef WOW
+ call LW_DriversInit
+endif
+ pop ax
+
+ ret
+ cEnd <nogen>
+
+cProc InitApp,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW hInst ; App's hInstance
+
+ cBegin
+
+ mov ax,8 ; MAGIC Win3.1 default message queue size
+ push ax ; NOTE Win3.1 (and User32) read the size
+ call CreateQueue ; from win.ini, we don't.
+ cmp ax,0 ; hq
+ jne IA_HaveQ
+ mov ax,0 ; return FALSE
+ jmp IA_Ret
+
+IA_HaveQ:
+ push ds
+
+ mov ax, _DATA ; set USER16's DS
+ mov ds,ax
+assumes ds, DATA
+
+ xor dx,dx
+ push dx
+ push seg NewSignalProc
+ push offset NewSignalProc
+ call SetTaskSignalProc
+;
+; Init WNET apis.
+;
+ cmp fFirstApp, 1
+ jne IA_notfirstapp
+ mov fFirstApp, 0
+ call LW_InitNetInfo
+
+IA_notfirstapp:
+
+;
+; Setup Divide By Zero handler
+;
+ call SetDivZero
+
+ mov ax,1
+ xor dx,dx
+
+ pop ds
+IA_Ret:
+ cEnd
+
+
+assumes DS,NOTHING
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+;*--------------------------------------------------------------------------*
+;*
+;* LFillStruct() -
+;*
+;*--------------------------------------------------------------------------*
+
+cProc LFillStruct, <PUBLIC, FAR, NODATA, ATOMIC>,<di>
+parmD lpStruct
+parmW cb
+parmW fillChar
+cBegin
+ les di,lpStruct
+ mov cx,cb
+ mov ax,fillChar
+ cld
+ rep stosb
+cEnd
+
+;*--------------------------------------------------------------------------*
+;* *
+;* GetSysModalWindow() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc GetSysModalWindow, <PUBLIC, FAR>
+cBegin nogen
+ mov ax,_DATA
+ nop
+ mov es,ax
+ mov ax,es:[hwndSysModal]
+ or ax,ax
+ jz GSMW_ItsZero
+
+ push es
+ push ax ; make sure we only return valid
+ call IsWindow ; windows.
+ pop es
+ or ax,ax
+ jnz GSMW_ItsNotZero
+ mov es:[hwndSysModal], ax ; zero out hwndSysModal
+
+GSMW_ItsNotZero:
+ mov ax,es:[hwndSysModal]
+
+GSMW_ItsZero:
+ retf
+cEnd nogen
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetSysModalWindow() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc ISetSysModalWindow, <PUBLIC, FAR>
+ParmW hwnd
+cBegin nogen
+ mov ax,_DATA
+ nop
+ mov es,ax
+ mov bx,sp
+ mov ax,ss:[bx+4]
+ xchg ax,es:[hwndSysModal]
+ retf 2
+cEnd nogen
+
+;
+; The DWPBits table defines which messages have actual processing for
+; DefWindowProc. We get these bits from user32. User32 assumes the
+; buffer passed in is zero-initialized, hence the DUP(0) below.
+;
+
+DWPBits DB 101 DUP(0) ; Room for bits for msgs 0 - 807 (decimal)
+public DWPBits
+
+cbDWPBits DW ($ - codeoffset DWPBits)
+public cbDWPBits
+
+MaxDWPMsg DW 0
+public MaxDWPMsg
+
+;*--------------------------------------------------------------------------*
+;*
+;* CheckDefWindowProc()
+;*
+;* Checks to see if the message gets processed by DefWindowProc. If not,
+;* the API returns 0.
+;*
+;*--------------------------------------------------------------------------*
+
+ALIGN 4
+
+cProc CheckDefWindowProc, <PUBLIC, NEAR>
+parmW hWnd
+parmW wMsg
+parmW wParam
+parmD lParam
+parmD lpReturn ; Callers Return Address
+;parmW wBP ; Thunk saved BP
+;parmW wDS ; Thunk saved DS
+cBegin
+ mov bx,wMsg
+ cmp bx,cs:MaxDWPMsg
+ ja @f ; jump if above (return with 0)
+ mov cx,bx
+ shr bx,3 ; make byte index into table
+ mov al,cs:[bx+DWPBits] ; get proper 8-bits
+ and cx,0007H
+ shr al,cl ; get proper bit into bit 0 of al
+ test al,1
+ jz @f
+
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+@@:
+ pop bp
+ xor ax,ax ; return (ULONG)0 to flag no window processing
+ add sp,2 ; skip thunk IP
+ xor dx,dx ; return (ULONG)0 to flag no window processing
+ retf 10 ; 10 bytes to pop
+
+
+cEnd <nogen>
+
+
+
+ UserThunk ADJUSTWINDOWRECT
+ UserThunk ADJUSTWINDOWRECTEX
+
+ ; Hack to use original IDs. These functions have local implementations
+ ; that thunk to Win32 if the locale is other than U.S. English.
+
+ FUN_WIN32ANSILOWER equ FUN_ANSILOWER
+ FUN_WIN32ANSILOWERBUFF equ FUN_ANSILOWERBUFF
+ FUN_WIN32ANSINEXT equ FUN_ANSINEXT
+ FUN_WIN32ANSIPREV equ FUN_ANSIPREV
+ FUN_WIN32ANSIUPPER equ FUN_ANSIUPPER
+ FUN_WIN32ANSIUPPERBUFF equ FUN_ANSIUPPERBUFF
+
+ DUserThunk WIN32ANSILOWER, %(size ANSILOWER16)
+ DUserThunk WIN32ANSILOWERBUFF, %(size ANSILOWERBUFF16)
+ DUserThunk WIN32ANSINEXT, %(size ANSINEXT16)
+ DUserThunk WIN32ANSIPREV, %(size ANSIPREV16)
+ DUserThunk WIN32ANSIUPPER, %(size ANSIUPPER16)
+ DUserThunk WIN32ANSIUPPERBUFF, %(size ANSIUPPERBUFF16)
+
+ DUserThunk ANYPOPUP,0
+ UserThunk APPENDMENU
+ UserThunk ARRANGEICONICWINDOWS
+ DUserThunk BEGINDEFERWINDOWPOS
+ UserThunk BEGINPAINT
+ UserThunk BRINGWINDOWTOTOP
+ UserThunk BROADCASTMESSAGE
+ UserThunk BUILDCOMMDCB
+;;; UserThunk BUTTONWNDPROC ;LOCALAPI in wsubcls.c
+ DUserThunk CALCCHILDSCROLL
+ UserThunk CALLMSGFILTER
+ UserThunk CALLWINDOWPROC
+ UserThunk CARETBLINKPROC
+ DUserThunk CASCADECHILDWINDOWS
+ UserThunk CHANGECLIPBOARDCHAIN
+ UserThunk CHANGEMENU
+ UserThunk CHECKDLGBUTTON
+ UserThunk CHECKMENUITEM
+ UserThunk CHECKRADIOBUTTON
+ UserThunk CHILDWINDOWFROMPOINT
+ UserThunk CLEARCOMMBREAK
+ UserThunk CLIPCURSOR
+ DUserThunk CLOSECLIPBOARD,0
+
+FUN_WOWCLOSECOMM EQU FUN_CLOSECOMM
+ DUserThunk WOWCLOSECOMM %(size CLOSECOMM16)
+
+ UserThunk CLOSEWINDOW
+;;; UserThunk COMBOBOXCTLWNDPROC ;LOCALAPI in wsubcls.c
+ UserThunk COMPUPDATERECT
+ UserThunk COMPUPDATERGN
+ DUserThunk CONTROLPANELINFO
+ UserThunk CONTSCROLL
+;;; UserThunk COPYRECT ; LOCALAPI in winrect.asm
+ DUserThunk COUNTCLIPBOARDFORMATS,0
+ UserThunk CREATECARET
+ UserThunk CREATECURSOR
+ DUserThunk CREATECURSORICONINDIRECT
+; UserThunk CREATEDIALOG ; defined in fastres.c
+; UserThunk CREATEDIALOGINDIRECT
+; UserThunk CREATEDIALOGINDIRECTPARAM
+
+;FUN_WOWCREATEDIALOGPARAM EQU FUN_CREATEDIALOGPARAM
+; DUserThunk WOWCREATEDIALOGPARAM, %(size CREATEDIALOGPARAM16)
+
+ UserThunk CREATEICON
+ DUserThunk CREATEMENU,0
+ DUserThunk CREATEPOPUPMENU,0
+ UserThunk CREATEWINDOW
+ UserThunk CREATEWINDOWEX
+ DUserThunk DCHOOK
+ UserThunk DEFDLGPROC
+ UserThunk DEFERWINDOWPOS
+ UserThunk DEFFRAMEPROC
+ UserThunk DEFMDICHILDPROC
+ PUserThunk DEFWINDOWPROC,CheckDefWindowProc
+
+; From Win 3.1 final inentry.asm - mattfe
+;=========================================================================
+; OldExitWindows()
+;
+; This function is at the same ordinal value as the old 2.x ExitWindows. This
+; does nothing more than terminate the app. If it is the only app running the
+; system will go away too.
+
+LabelFP <PUBLIC, OldExitWindows>
+ mov ax,4c00h
+ int 21h
+ retf ; just in case the int21 returns...
+
+sEnd CODE
+
+end USER16
diff --git a/private/mvdm/wow16/user/user.def b/private/mvdm/wow16/user/user.def
new file mode 100644
index 000000000..dbcfa5f20
--- /dev/null
+++ b/private/mvdm/wow16/user/user.def
@@ -0,0 +1,539 @@
+LIBRARY USER
+DESCRIPTION 'WOW REPLACEMENT USER'
+EXETYPE WINDOWS
+STUB '..\BIN\WINSTUB.EXE'
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+SEGMENTS
+ _TEXT CLASS 'CODE' FIXED PRELOAD
+ _GPFIX0 CLASS 'CODE' FIXED PRELOAD
+ _GPFIX CLASS 'CODE' FIXED PRELOAD
+ _GPFIX1 CLASS 'CODE' FIXED PRELOAD
+ _INTDS CLASS 'FAR_DATA' FIXED PRELOAD
+HEAPSIZE 6144
+EXPORTS
+ WEP ;Internal
+ MESSAGEBOX @1
+ OLDEXITWINDOWS @2 ;Internal
+ ENABLEOEMLAYER @3 ;Internal
+ DISABLEOEMLAYER @4 ;Internal
+ INITAPP @5
+ POSTQUITMESSAGE @6
+ EXITWINDOWS @7
+;;
+ SETTIMER @10
+ BEAR11 = SETSYSTEMTIMER @11 ;Internal
+ KILLTIMER @12
+ GETTICKCOUNT @13
+ GETTIMERRESOLUTION @14 NODATA ;Internal
+ GETCURRENTTIME @15
+ CLIPCURSOR @16
+ GETCURSORPOS @17
+ SETCAPTURE @18
+ RELEASECAPTURE @19
+ SETDOUBLECLICKTIME @20
+ GETDOUBLECLICKTIME @21
+ SETFOCUS @22
+ GETFOCUS @23
+ REMOVEPROP @24
+ GETPROP @25
+ SETPROP @26
+ ENUMPROPS @27
+ CLIENTTOSCREEN @28
+ SCREENTOCLIENT @29
+ WINDOWFROMPOINT @30
+ ISICONIC @31
+ GETWINDOWRECT @32
+ GETCLIENTRECT @33
+ ENABLEWINDOW @34
+ ISWINDOWENABLED @35
+ GETWINDOWTEXT @36
+ SETWINDOWTEXT @37
+ GETWINDOWTEXTLENGTH @38
+ BEGINPAINT @39
+ ENDPAINT @40
+ CREATEWINDOW @41
+ SHOWWINDOW @42
+ CLOSEWINDOW @43
+ OPENICON @44
+ BRINGWINDOWTOTOP @45
+ GETPARENT @46
+ ISWINDOW @47
+ ISCHILD @48
+ ISWINDOWVISIBLE @49
+ FINDWINDOW @50
+ BEAR51=ISTWOBYTECHARPREFIX @51 ;Internal
+ ANYPOPUP @52
+ DESTROYWINDOW @53
+ ENUMWINDOWS @54
+ ENUMCHILDWINDOWS @55
+ MOVEWINDOW @56
+ REGISTERCLASS @57
+ GETCLASSNAME @58
+ SETACTIVEWINDOW @59
+ GETACTIVEWINDOW @60
+ SCROLLWINDOW @61
+ SETSCROLLPOS @62
+ GETSCROLLPOS @63
+ SETSCROLLRANGE @64
+ GETSCROLLRANGE @65
+ GETDC @66
+ GETWINDOWDC @67
+ RELEASEDC @68
+ SETCURSOR @69
+ SETCURSORPOS @70
+ SHOWCURSOR @71
+ SETRECT @72
+ SETRECTEMPTY @73
+ COPYRECT @74
+ ISRECTEMPTY @75
+ PTINRECT @76
+ OFFSETRECT @77
+ INFLATERECT @78
+ INTERSECTRECT @79
+ UNIONRECT @80
+ FILLRECT @81
+ INVERTRECT @82
+ FRAMERECT @83
+ DRAWICON @84
+ DRAWTEXT @85
+ BEAR86=ICONSIZE @86 ;Internal
+ DIALOGBOX @87
+ ENDDIALOG @88
+ CREATEDIALOG @89
+ ISDIALOGMESSAGE @90
+ GETDLGITEM @91
+ SETDLGITEMTEXT @92
+ GETDLGITEMTEXT @93
+ SETDLGITEMINT @94
+ GETDLGITEMINT @95
+ CHECKRADIOBUTTON @96
+ CHECKDLGBUTTON @97
+ ISDLGBUTTONCHECKED @98
+ DLGDIRSELECT @99
+ DLGDIRLIST @100
+ SENDDLGITEMMESSAGE @101
+ ADJUSTWINDOWRECT @102
+ MAPDIALOGRECT @103
+ MESSAGEBEEP @104
+ FLASHWINDOW @105
+ GETKEYSTATE @106
+ DEFWINDOWPROC @107
+ GETMESSAGE @108
+ PEEKMESSAGE @109
+ POSTMESSAGE @110
+ SENDMESSAGE @111
+ WAITMESSAGE @112
+ TRANSLATEMESSAGE @113
+ DISPATCHMESSAGE @114
+ REPLYMESSAGE @115
+ POSTAPPMESSAGE @116
+;; GETTASKFROMHWND @117 ;Internal
+ REGISTERWINDOWMESSAGE @118
+ GETMESSAGEPOS @119
+ GETMESSAGETIME @120
+ SETWINDOWSHOOK @121
+ CALLWINDOWPROC @122
+ CALLMSGFILTER @123
+ UPDATEWINDOW @124
+ INVALIDATERECT @125
+ INVALIDATERGN @126
+ VALIDATERECT @127
+ VALIDATERGN @128
+ GETCLASSWORD @129
+ SETCLASSWORD @130
+ GETCLASSLONG @131
+ SETCLASSLONG @132
+ GETWINDOWWORD @133
+ SETWINDOWWORD @134
+ GETWINDOWLONG @135
+ SETWINDOWLONG @136
+ OPENCLIPBOARD @137
+ CLOSECLIPBOARD @138
+ EMPTYCLIPBOARD @139
+ GETCLIPBOARDOWNER @140
+ SETCLIPBOARDDATA @141
+ GETCLIPBOARDDATA @142
+ COUNTCLIPBOARDFORMATS @143
+ ENUMCLIPBOARDFORMATS @144
+ REGISTERCLIPBOARDFORMAT @145
+ GETCLIPBOARDFORMATNAME @146
+ SETCLIPBOARDVIEWER @147
+ GETCLIPBOARDVIEWER @148
+ CHANGECLIPBOARDCHAIN @149
+ LOADMENU @150
+ CREATEMENU @151
+ DESTROYMENU @152
+ CHANGEMENU @153
+ CHECKMENUITEM @154
+ ENABLEMENUITEM @155
+ GETSYSTEMMENU @156
+ GETMENU @157
+ SETMENU @158
+ GETSUBMENU @159
+ DRAWMENUBAR @160
+ GETMENUSTRING @161
+ HILITEMENUITEM @162
+ CREATECARET @163
+ DESTROYCARET @164
+ SETCARETPOS @165
+ HIDECARET @166
+ SHOWCARET @167
+ SETCARETBLINKTIME @168
+ GETCARETBLINKTIME @169
+ ARRANGEICONICWINDOWS @170
+ WINHELP @171
+ SWITCHTOTHISWINDOW @172 ;Internal
+ LOADCURSOR @173
+ LOADICON @174
+ LOADBITMAP @175
+ LOADSTRING @176
+ LOADACCELERATORS @177
+ TRANSLATEACCELERATOR @178
+ GETSYSTEMMETRICS @179
+ GETSYSCOLOR @180
+ SETSYSCOLORS @181
+ BEAR182=KILLSYSTEMTIMER @182 ;Internal
+ GETCARETPOS @183
+ QUERYSENDMESSAGE @184
+ GRAYSTRING @185
+ SWAPMOUSEBUTTON @186 NODATA
+ ENDMENU @187 ;Internal
+ SETSYSMODALWINDOW @188
+ GETSYSMODALWINDOW @189
+ GETUPDATERECT @190
+ CHILDWINDOWFROMPOINT @191
+ INSENDMESSAGE @192
+ ISCLIPBOARDFORMATAVAILABLE @193
+ DLGDIRSELECTCOMBOBOX @194
+ DLGDIRLISTCOMBOBOX @195
+ TABBEDTEXTOUT @196
+ GETTABBEDTEXTEXTENT @197
+ CASCADECHILDWINDOWS @198 ;Internal
+ TILECHILDWINDOWS @199 ;Internal
+ OPENCOMM @200
+ SETCOMMSTATE @201
+ GETCOMMSTATE @202
+ GETCOMMERROR @203
+ READCOMM @204
+ WRITECOMM @205
+ TRANSMITCOMMCHAR @206
+ CLOSECOMM @207
+ SETCOMMEVENTMASK @208
+ GETCOMMEVENTMASK @209
+ SETCOMMBREAK @210
+ CLEARCOMMBREAK @211
+ UNGETCOMMCHAR @212
+ BUILDCOMMDCB @213
+ ESCAPECOMMFUNCTION @214
+ FLUSHCOMM @215
+ USERSEEUSERDO @216 ;Internal (was MyOpenComm)
+ LOOKUPMENUHANDLE @217 ;Internal
+ DIALOGBOXINDIRECT @218
+ CREATEDIALOGINDIRECT @219
+ LOADMENUINDIRECT @220
+ SCROLLDC @221
+ GETKEYBOARDSTATE @222
+ SETKEYBOARDSTATE @223
+ GETWINDOWTASK @224
+ ENUMTASKWINDOWS @225
+ LOCKINPUT @226
+ GETNEXTDLGGROUPITEM @227
+ GETNEXTDLGTABITEM @228
+ GETTOPWINDOW @229
+ GETNEXTWINDOW @230
+ GETSYSTEMDEBUGSTATE @231
+ SETWINDOWPOS @232
+ SETPARENT @233
+ UNHOOKWINDOWSHOOK @234
+ DEFHOOKPROC @235
+ GETCAPTURE @236
+ GETUPDATERGN @237
+ EXCLUDEUPDATERGN @238
+ DIALOGBOXPARAM @239
+ DIALOGBOXINDIRECTPARAM @240
+ CREATEDIALOGPARAM @241
+ CREATEDIALOGINDIRECTPARAM @242
+ GETDIALOGBASEUNITS @243
+ EQUALRECT @244
+ ENABLECOMMNOTIFICATION @245
+ EXITWINDOWSEXEC @246
+ GETCURSOR @247
+ GETOPENCLIPBOARDWINDOW @248
+ GETASYNCKEYSTATE @249
+ GETMENUSTATE @250
+ SENDDRIVERMESSAGE @251
+ OPENDRIVER @252
+ CLOSEDRIVER @253
+ GETDRIVERMODULEHANDLE @254
+ DEFDRIVERPROC @255
+ GETDRIVERINFO @256
+ GETNEXTDRIVER @257
+ MAPWINDOWPOINTS @258
+ BEGINDEFERWINDOWPOS @259
+ DEFERWINDOWPOS @260
+ ENDDEFERWINDOWPOS @261
+ GETWINDOW @262
+ GETMENUITEMCOUNT @263
+ GETMENUITEMID @264
+ SHOWOWNEDPOPUPS @265
+ SETMESSAGEQUEUE @266
+ SHOWSCROLLBAR @267
+ GLOBALADDATOM @268
+ GLOBALDELETEATOM @269
+ GLOBALFINDATOM @270
+ GLOBALGETATOMNAME @271
+ ISZOOMED @272
+ CONTROLPANELINFO @273 ;Internal
+ GETNEXTQUEUEWINDOW @274 ;Internal
+ REPAINTSCREEN @275
+ LOCKMYTASK @276 ;Internal
+ GETDLGCTRLID @277
+ GETDESKTOPHWND @278 ;Internal
+ OLDSETDESKPATTERN @279 ;Internal
+ SETSYSTEMMENU @280 ;Internal
+ SELECTPALETTE @282
+ REALIZEPALETTE @283
+ GETFREESYSTEMRESOURCES @284
+ BEAR285=OLDSETDESKWALLPAPER @285 ;Internal
+ GETDESKTOPWINDOW @286
+ GETLASTACTIVEPOPUP @287
+ GETMESSAGEEXTRAINFO @288
+ KEYBD_EVENT @289
+;
+; Added AFX 3.1 APIs
+;
+ REDRAWWINDOW @290
+ SETWINDOWSHOOKEX @291
+ UNHOOKWINDOWSHOOKEX @292
+ CALLNEXTHOOKEX @293
+ LOCKWINDOWUPDATE @294
+;;;;BEGINDRAWBUFFER @295
+;;;;ENDDRAWBUFFER @296
+;;;;FLUSHDRAWBUFFER @297
+;;;;GETSYSINPUTMODE @298
+;
+; End of AFX APIs
+;
+ MOUSE_EVENT @299
+;
+; private externals.
+;
+; @300
+ EDITWNDPROC @301 ;Internal ; ChandanC
+ STATICWNDPROC @302 ;Internal ; ChandanC
+ BUTTONWNDPROC @303 ;Internal ; ChandanC
+ SBWNDPROC @304 ;Internal ; ChandanC
+ DESKTOPWNDPROC @305 ;Internal
+ BEAR306=MENUWINDOWPROC @306 ;Internal
+ ; WinWart 1.x depends on menu
+ ; proc being exported
+ LBOXCTLWNDPROC @307 ;Internal ; ChandanC
+ DEFDLGPROC @308
+ GETCLIPCURSOR @309
+;;;;BEAR310=CONTSCROLL @310 ;Internal
+;;;;CARETBLINKPROC @311 ;Internal
+;;;;SENDMESSAGE2 @312 ;Internal
+;;;;POSTMESSAGE2 @313 ;Internal
+ SIGNALPROC @314 ;Internal
+;;;;XCSTODS @315 ;Internal
+;;;;INTERNALBEGINPAINT @316 ;Internal
+;
+; More AFX 3.1 APIs
+;
+;;;;SETHOTKEYHOOK @317
+;;;;POSTHOTKEYEVENT @318
+ SCROLLWINDOWEX @319
+
+
+
+; End of AFX APIs
+;
+ SYSERRORBOX @320 ;Internal
+ SETEVENTHOOK @321
+ WINOLDAPPHACKOMATIC @322 ;Internal
+ GETMESSAGE2 @323 ;Internal
+ FILLWINDOW @324 ;Internal
+ PAINTRECT @325 ;Internal
+ GETCONTROLBRUSH @326 ;Internal
+;;;;KILLTIMER2 @327 ;Internal
+;;;;SETTIMER2 @328 ;Internal
+;;;;BEAR329=MENUITEMSTATE @329 ;Internal
+;;;;SETGETKBDSTATE @330 ;Internal
+ ENABLEHARDWAREINPUT @331 NODATA
+ USERYIELD @332 ;Internal
+ ISUSERIDLE @333 ;Internal
+ GETQUEUESTATUS @334
+ GETINPUTSTATE @335
+
+; The following was added on request from IRIS
+ LOADCURSORICONHANDLER @336 ;Internal
+ GETMOUSEEVENTPROC @337 ;Internal
+;;;;BEAR338=DESTROYTASKWINDOWSENUM @338 ;Internal
+;;;;BEAR339=ACTIVATEAPP @339 ;Internal
+
+ WINFARFRAME @340 ;Internal ; ChandanC
+
+;;;;BEAR340=SOW_SENDZOOM @340 ;Internal
+ _FFFE_FARFRAME @341 ;Internal
+;;;;BEAR342=BROADCASTPROC @342 ;Internal
+ GETFILEPORTNAME @343 ;Internal
+ COMBOBOXCTLWNDPROC @344 ;Internal ;ChandanC
+ BEAR345=TITLEWNDPROC @345 ;Internal ;MSMoney needs this
+;;;;FILEPORTDLGPROC @346 ;Internal
+;;;;*EAR347=SWITCHWNDPROC @347 ;Internal
+;;;;BEAR348=FCHILDVISIBLE @348 ;Internal
+;;;;BEAR349=DRAWFRAME @349 ;Internal
+;;;;BEAR350=LOOKUPMENUITEM @350 ;Internal
+;;;;BEAR351=RECALCTABSTRINGS @351 ;Internal
+;;;;BEAR352=BTNGRAYSTRINGTEXTOUT @352 ;Internal
+;;;;BEAR353=LBGRAYPRINT @353 ;Internal
+;;;;BEAR354=TABTHETEXTOUTFORWIMPS @354 ;Internal
+;;;;BROADCASTMESSAGE @355 ;Internal
+ LOADDIBCURSORHANDLER @356 ;Internal
+ LOADDIBICONHANDLER @357 ;Internal
+;;;;BEAR358=FREEITEM @358 ;Internal
+ ISMENU @358
+;
+; Even more AFX 3.1 APIs
+;
+ GETDCEX @359
+;;;;INVALIDATEDCCACHE @360
+;;;;DEFVISRGNHOOK @361
+ DCHOOK @362 ;Internal
+;
+; End of AFX APIs
+;
+;;;;BEAR363=FNENUMTASK @363 ;Internal
+;;;;BEAR364=GRAYSTATICPRINT @364 ;Internal
+;;;;BEAR365=IREDRAWWINDOW @365 ;Internal
+;;;;BEAR366=FQUERYQUITENUM @366 ;Internal
+;;;; @367
+ COPYICON @368
+ COPYCURSOR @369
+ GETWINDOWPLACEMENT @370
+ SETWINDOWPLACEMENT @371
+ GETINTERNALICONHEADER @372 ;Internal
+ SUBTRACTRECT @373
+
+ FINALUSERINIT @400 ;Internal
+;;;;BEAR401=ANSISTRRTNS @401 ;Internal
+ GETPRIORITYCLIPBOARDFORMAT @402
+ UNREGISTERCLASS @403
+ GETCLASSINFO @404
+;;;;BEAR405=ANSIBUFFRTNS @405 ;Internal
+ CREATECURSOR @406
+ CREATEICON @407
+ CREATECURSORICONINDIRECT @408 ;Internal
+;;;;MB_DLGPROC @409 ;Internal
+ INSERTMENU @410
+ APPENDMENU @411
+ REMOVEMENU @412
+ DELETEMENU @413
+ MODIFYMENU @414
+ CREATEPOPUPMENU @415
+ TRACKPOPUPMENU @416
+ GETMENUCHECKMARKDIMENSIONS @417
+ SETMENUITEMBITMAPS @418
+;;;;BEAR419=CHARRTNS @419 ;Internal
+ _WSPRINTF @420 ; _WSPRINTF to WSPRINTF;ChandanC
+ WVSPRINTF @421
+ DLGDIRSELECTEX @422
+ DLGDIRSELECTCOMBOBOXEX @423
+
+ LSTRCMP @430
+ ANSIUPPER @431
+ ANSILOWER @432
+ ISCHARALPHA @433
+ ISCHARALPHANUMERIC @434
+ ISCHARUPPER @435
+ ISCHARLOWER @436
+ ANSIUPPERBUFF @437
+ ANSILOWERBUFF @438
+;;
+ MDICLIENTWNDPROC @444 ;Internal ; ChandanC
+ DEFFRAMEPROC @445
+ DEFMDICHILDPROC @447
+;;
+ TRANSLATEMDISYSACCEL @451
+ CREATEWINDOWEX @452
+;; BEAR453=LBOXCARETBLINKER @453 ;Internal
+ ADJUSTWINDOWRECTEX @454
+ GETICONID @455 ;Internal
+ LOADICONHANDLER @456 ;Internal
+ DESTROYICON @457
+ DESTROYCURSOR @458
+ DUMPICON @459 ;Internal
+ GETINTERNALWINDOWPOS @460 ;Internal
+ SETINTERNALWINDOWPOS @461 ;Internal
+ CALCCHILDSCROLL @462 ;Internal
+ SCROLLCHILDREN @463 ;Internal
+ DRAGOBJECT @464 ;Internal
+ DRAGDETECT @465 ;Internal
+ DRAWFOCUSRECT @466
+;;
+ STRINGFUNC @470 ;Internal ChandanC
+ LSTRCMPI @471
+ ANSINEXT @472
+ ANSIPREV @473
+;;
+ GETUSERLOCALOBJTYPE @480 ;Internal Debug purposes
+;; hardware_event is the generic entrypoint for adding hardware events
+ HARDWARE_EVENT @481
+ ENABLESCROLLBAR @482
+ SYSTEMPARAMETERSINFO @483
+;
+; GP fault exception handler table
+;
+ __GP @484 RESIDENTNAME ;Internal
+
+;;
+;; exports 500 and so are for WinNet entry points.
+;; FarCallNetDriver exported to get DS right in winnet.asm...
+;; There are about 30 right now.
+;;
+ WNETERRORTEXT @499 ;Internal
+;;;;FARCALLNETDRIVER @500 ;Internal
+ WNETOPENJOB @501 ;Internal
+ WNETCLOSEJOB @502 ;Internal
+ WNETABORTJOB @503 ;Internal
+ WNETHOLDJOB @504 ;Internal
+ WNETRELEASEJOB @505 ;Internal
+ WNETCANCELJOB @506 ;Internal
+ WNETSETJOBCOPIES @507 ;Internal
+ WNETWATCHQUEUE @508 ;Internal
+ WNETUNWATCHQUEUE @509 ;Internal
+ WNETLOCKQUEUEDATA @510 ;Internal
+ WNETUNLOCKQUEUEDATA @511 ;Internal
+ WNETGETCONNECTION @512
+ WNETGETCAPS @513 ;Internal
+ WNETDEVICEMODE @514 ;Internal
+ WNETBROWSEDIALOG @515 ;Internal
+ WNETGETUSER @516 ;Internal
+ WNETADDCONNECTION @517
+ WNETCANCELCONNECTION @518
+ WNETGETERROR @519 ;Internal
+ WNETGETERRORTEXT @520 ;Internal
+ WNETENABLE @521 ;Internal
+ WNETDISABLE @522 ;Internal
+ WNETRESTORECONNECTION @523 ;Internal
+ WNETWRITEJOB @524 ;Internal
+ WNETCONNECTDIALOG @525 ;Internal
+ WNETDISCONNECTDIALOG @526 ;Internal
+ WNETCONNECTIONDIALOG @527 ;Internal
+ WNETVIEWQUEUEDIALOG @528 ;Internal
+ WNETPROPERTYDIALOG @529 ;Internal
+ WNETGETDIRECTORYTYPE @530 ;Internal
+ WNETDIRECTORYNOTIFY @531 ;Internal
+ WNETGETPROPERTYTEXT @532 ;Internal
+ NOTIFYWOW @533 ;Internal for WOW
+ DEFDLGPROCTHUNK @534 ;Internal for WOW
+ WOWWORDBREAKPROC @535 ;Internal for WOW
+ NEWSIGNALPROC @536 ;Internal for WOW
+ MOUSEEVENT @537 ;Internal for WOW
+ KEYBDEVENT @538 ;Internal for WOW
+
+IMPORTS
+
+ HandleParamError = KERNEL.327
diff --git a/private/mvdm/wow16/user/user.h b/private/mvdm/wow16/user/user.h
new file mode 100644
index 000000000..d7ec9d4b4
--- /dev/null
+++ b/private/mvdm/wow16/user/user.h
@@ -0,0 +1,2697 @@
+/***************************************************************************/
+/* */
+/* USER.H - */
+/* */
+/* User's main include file. */
+/* */
+/***************************************************************************/
+
+#ifdef WOW
+#define NO_LOCALOBJ_TAGS
+#endif
+
+// If #defined, only 16 bits of the window extended style will be stored
+// in the window instance.
+//
+//#define WORDEXSTYLE
+
+
+// This magic definition ensures that HWND is declared as a near
+// pointer to our internal window data structure. See
+// the DECLARE_HANDLE macro in windows.h.
+//
+#define tagWND HWND__
+
+// substitute API names with the "I" internal names
+//
+#ifndef DEBUG
+#include "iuser.h"
+#endif
+
+#ifdef DEBUG
+#ifndef NO_REDEF_SENDMESSAGE
+#define SendMessage RevalSendMessage
+#endif
+#endif
+
+//***** Include standard headers...
+
+#define NOSOUND
+#define NOFONT
+#define NOKANJI
+#define LSTRING
+#define LFILEIO
+#define WIN31
+
+#define STRICT
+
+#include <windows.h>
+
+/* Structure types that occupy the USER Data Segment */
+#define ST_CLASS 1
+#define ST_WND 2
+#define ST_STRING 3
+#define ST_MENU 4
+#define ST_CLIP 5
+#define ST_CBOX 6
+#define ST_PALETTE 7
+#define ST_ED 8
+#define ST_BWL 9
+#define ST_OWNERDRAWMENU 10
+#define ST_SPB 11
+#define ST_CHECKPOINT 12
+#define ST_DCE 13
+#define ST_MWP 14
+#define ST_PROP 15
+#define ST_LBIV 16
+#define ST_MISC 17
+#define ST_ATOMS 18
+#define ST_LOCKINPUTSTATE 19
+#define ST_HOOKNODE 20
+#define ST_USERSEEUSERDOALLOC 21
+#define ST_HOTKEYLIST 22
+#define ST_POPUPMENU 23
+#define ST_HANDLETABLE 32 /* Defined by Kernel; We have no control */
+#define ST_FREE 0xFF
+
+#define CODESEG _based(_segname("_CODE"))
+#define INTDSSEG _based(_segname("_INTDS"))
+
+// Returns TRUE if currently executing app is 3.10 compatible
+//
+#define Is310Compat(hInstance) (LOWORD(GetExpWinVer(hInstance)) >= 0x30a)
+#define Is300Compat(hInstance) (LOWORD(GetExpWinVer(hInstance)) >= 0x300)
+
+#define VER 0x0300
+#define VER31 0x0310
+#define VER30 0x0300
+#define VER20 0x0201
+
+#define CR_CHAR 13
+#define ESC_CHAR 27
+#define SPACE_CHAR 32
+
+typedef HANDLE HQ;
+
+struct tagDCE;
+
+/* Window class structure */
+typedef struct tagCLS
+{
+ /* NOTE: The order of the following fields is assumed. */
+ struct tagCLS* pclsNext;
+ WORD clsMagic;
+ ATOM atomClassName;
+ struct tagDCE* pdce; /* DCE * to DC associated with class */
+ int cWndReferenceCount; /* The number of windows registered
+ with this class */
+ WORD style;
+ WNDPROC lpfnWndProc;
+ int cbclsExtra;
+ int cbwndExtra;
+ HMODULE hModule;
+ HICON hIcon;
+ HCURSOR hCursor;
+ HBRUSH hbrBackground;
+ LPSTR lpszMenuName;
+ LPSTR lpszClassName;
+} CLS;
+typedef CLS *PCLS;
+typedef CLS far *LPCLS;
+typedef PCLS *PPCLS;
+
+#define CLS_MAGIC ('N' | ('K' << 8))
+
+struct tagPROPTABLE;
+
+/* Window instance structure */
+typedef struct tagWND
+{
+ struct tagWND* hwndNext; /* 0x0000 Handle to the next window */
+ struct tagWND* hwndChild; /* 0x0002 Handle to child */
+ struct tagWND* hwndParent; /* 0x0004 Backpointer to the parent window. */
+ struct tagWND* hwndOwner; /* 0x0006 Popup window owner field */
+ RECT rcWindow; /* 0x0008 Window outer rectangle */
+ RECT rcClient; /* 0x0010 Client rectangle */
+ HQ hq; /* 0x0018 Queue handle */
+ HRGN hrgnUpdate; /* 0x001a Accumulated paint region */
+ struct tagCLS* pcls; /* 0x001c Pointer to window class */
+ HINSTANCE hInstance; /* 0x001e Handle to module instance data. */
+ WNDPROC lpfnWndProc; /* 0x0020 Far pointer to window proc. */
+ DWORD state; /* 0x0024 Internal state flags */
+ DWORD style; /* 0x0028 Style flags */
+#ifdef WORDEXSTYLE
+ WORD dwExStyle; /* 0x002c Extended Style (ONLY LOW 16 BITS STORED) */
+#else
+ DWORD dwExStyle; /* 0x002c Extended Style */
+#endif
+ HMENU hMenu; /* 0x0030 Menu handle or ID */
+ HLOCAL hName; /* 0x0032 Alt DS handle of the window text */
+ int* rgwScroll; /* 0x0034 Words used for scroll bar state */
+ struct tagPROPTABLE* pproptab; /* 0x0036 Handle to the start of the property list */
+ struct tagWND* hwndLastActive; /* 0x0038 Last active in owner/ownee list */
+ HMENU hSysMenu; /* 0x003a Handle to system menu */
+} WND;
+
+#undef API
+#define API _loadds _far _pascal
+
+#undef CALLBACK
+#define CALLBACK _loadds _far _pascal
+
+#ifndef MSDWP
+
+#include <winexp.h>
+#include "strtable.h"
+#include "wmsyserr.h"
+
+#endif /* MSDWP */
+
+/*** AWESOME HACK ALERT!
+ *
+ * Window Style and State Masks -
+ *
+ * High byte of word is byte index from the start of the state field
+ * in the WND structure, low byte is the mask to use on the byte.
+ * These masks assume the order of the state and style fields of a
+ * window instance structure.
+ */
+
+// hwnd->state flags (offset 0, 1, 2, 3)
+#define WFMPRESENT 0x0001
+#define WFVPRESENT 0x0002
+#define WFHPRESENT 0x0004
+#define WFCPRESENT 0x0008
+#define WFSENDSIZEMOVE 0x0010
+#define WFNOPAINT 0x0020
+#define WFFRAMEON 0x0040
+#define WFHASSPB 0x0080
+#define WFNONCPAINT 0x0101
+#define WFSENDERASEBKGND 0x0102
+#define WFERASEBKGND 0x0104
+#define WFSENDNCPAINT 0x0108
+#define WFINTERNALPAINT 0x0110 // Internal paint required flag
+#define WFUPDATEDIRTY 0x0120
+#define WFHIDDENPOPUP 0x0140
+#define WFMENUDRAW 0x0180
+
+#define WFHASPALETTE 0x0201
+#define WFPAINTNOTPROCESSED 0x0202 // WM_PAINT message not processed
+#define WFWIN31COMPAT 0x0204 // Win 3.1 compatible window
+#define WFALWAYSSENDNCPAINT 0x0208 // Always send WM_NCPAINT to children
+#define WFPIXIEHACK 0x0210 // Send (HRGN)1 to WM_NCPAINT (see PixieHack)
+#define WFTOGGLETOPMOST 0x0220 // Toggle the WS_EX_TOPMOST bit ChangeStates
+
+// hwnd->style style bits (offsets 4, 5, 6, 7)
+#define WFTYPEMASK 0x07C0
+#define WFTILED 0x0700
+#define WFICONICPOPUP 0x07C0
+#define WFPOPUP 0x0780
+#define WFCHILD 0x0740
+#define WFMINIMIZED 0x0720
+#define WFVISIBLE 0x0710
+#define WFDISABLED 0x0708
+#define WFDISABLE WFDISABLED
+#define WFCLIPSIBLINGS 0x0704
+#define WFCLIPCHILDREN 0x0702
+#define WFMAXIMIZED 0x0701
+#define WFICONIC WFMINIMIZED
+
+#define WFMINBOX 0x0602
+#define WFMAXBOX 0x0601
+
+#define WFBORDERMASK 0x06C0
+#define WFBORDER 0x0680
+#define WFCAPTION 0x06C0
+#define WFDLGFRAME 0x0640
+#define WFTOPLEVEL 0x0640
+
+#define WFVSCROLL 0x0620
+#define WFHSCROLL 0x0610
+#define WFSYSMENU 0x0608
+#define WFSIZEBOX 0x0604
+#define WFGROUP 0x0602
+#define WFTABSTOP 0x0601
+
+// If this dlg bit is set, WM_ENTERIDLE message will not be sent
+#define WFNOIDLEMSG 0x0501
+
+// hwnd->dwExStyle extended style bits (offsets 8, 9)
+#define WEFDLGMODALFRAME 0x0801
+#define WEFDRAGOBJECT 0x0802
+#define WEFNOPARENTNOTIFY 0x0804
+#define WEFTOPMOST 0x0808
+#define WEFACCEPTFILES 0x0810
+#define WEFTRANSPARENT 0x0820 // "Transparent" child window
+
+// Class styles
+#define CFVREDRAW 0x0001
+#define CFHREDRAW 0x0002
+#define CFKANJIWINDOW 0x0004
+#define CFDBLCLKS 0x0008
+#define CFOEMCHARS 0x0010
+#define CFOWNDC 0x0020
+#define CFCLASSDC 0x0040
+#define CFPARENTDC 0x0080
+#define CFNOKEYCVT 0x0101
+#define CFNOCLOSE 0x0102
+#define CFLVB 0x0104
+#define CFCLSDC CFCLASSDC
+#define CFSAVEBITS 0x0108
+#define CFSAVEPOPUPBITS CFSAVEBITS
+#define CFBYTEALIGNCLIENT 0x0110
+#define CFBYTEALIGNWINDOW 0x0120
+
+
+/*** AWESOME HACK ALERT!!!
+ *
+ * The low byte of the WF?PRESENT state flags must NOT be the
+ * same as the low byte of the WFBORDER and WFCAPTION flags,
+ * since these are used as paint hint masks. The masks are calculated
+ * with the MaskWF macro below.
+ *
+ * The magnitute of this hack compares favorably with that of the national debt.
+ */
+#define TestWF(hwnd, flag) ((BYTE)*((BYTE *)(&(hwnd)->state) + HIBYTE(flag)) & (BYTE)LOBYTE(flag))
+#define SetWF(hwnd, flag) ((BYTE)*((BYTE *)(&(hwnd)->state) + HIBYTE(flag)) |= (BYTE)LOBYTE(flag))
+#define ClrWF(hwnd, flag) ((BYTE)*((BYTE *)(&(hwnd)->state) + HIBYTE(flag)) &= ~(BYTE)LOBYTE(flag))
+#define MaskWF(flag) ((WORD)( (HIBYTE(flag) & 1) ? LOBYTE(flag) << 8 : LOBYTE(flag)) )
+
+#define TestCF(hwnd, flag) (*((BYTE *)(&(hwnd)->pcls->style) + HIBYTE(flag)) & LOBYTE(flag))
+#define SetCF(hwnd, flag) (*((BYTE *)(&(hwnd)->pcls->style) + HIBYTE(flag)) |= LOBYTE(flag))
+#define ClrCF(hwnd, flag) (*((BYTE *)(&(hwnd)->pcls->style) + HIBYTE(flag)) &= ~LOBYTE(flag))
+#define TestCF2(pcls, flag) (*((BYTE *)(&pcls->style) + HIBYTE(flag)) & LOBYTE(flag))
+#define SetCF2(pcls, flag) (*((BYTE *)(&pcls->style) + HIBYTE(flag)) |= LOBYTE(flag))
+#define ClrCF2(pcls, flag) (*((BYTE *)(&pcls->style) + HIBYTE(flag)) &= ~LOBYTE(flag))
+
+#define TestwndChild(hwnd) (TestWF(hwnd, WFTYPEMASK) == (BYTE)LOBYTE(WFCHILD))
+#define TestwndTiled(hwnd) (TestWF(hwnd, WFTYPEMASK) == (BYTE)LOBYTE(WFTILED))
+#define TestwndIPopup(hwnd) (TestWF(hwnd, WFTYPEMASK) == (BYTE)LOBYTE(WFICONICPOPUP))
+#define TestwndNIPopup(hwnd) (TestWF(hwnd, WFTYPEMASK) == (BYTE)LOBYTE(WFPOPUP))
+#define TestwndPopup(hwnd) (TestwndNIPopup(hwnd) || TestwndIPopup(hwnd))
+#define TestwndHI(hwnd) (TestwndTiled(hwnd) || TestwndIPopup(hwnd))
+
+/* Special macro to test if WM_PAINT is needed */
+
+#define NEEDSPAINT(hwnd) (hwnd->hrgnUpdate != NULL || TestWF(hwnd, WFINTERNALPAINT))
+
+/* Areas to be painted during activation and inactivation */
+#define NC_DRAWNONE 0x00
+#define NC_DRAWCAPTION 0x01
+#define NC_DRAWFRAME 0x02
+#define NC_DRAWBOTH (NC_DRAWCAPTION | NC_DRAWFRAME)
+
+void FAR DrawCaption(HWND hwnd, HDC hdc, WORD flags, BOOL fActive);
+
+/* ActivateWindow() commands */
+#define AW_USE 1
+#define AW_TRY 2
+#define AW_SKIP 3
+#define AW_TRY2 4
+#define AW_SKIP2 5 /* used internally in ActivateWindow() */
+#define AW_USE2 6 /* nc mouse activation added by craigc */
+
+/* These numbers serve as indices into the atomSysClass[] array
+ * so that we can get the atoms for the various classes.
+ * The order of the control classes is assumed to be
+ * the same as the class XXXCODE constants defined in dlgmgr.h.
+ */
+#define ICLS_BUTTON 0
+#define ICLS_EDIT 1
+#define ICLS_STATIC 2
+#define ICLS_LISTBOX 3
+#define ICLS_SCROLLBAR 4
+#define ICLS_COMBOBOX 5 // End of special dlgmgr indices
+
+#define ICLS_CTL_MAX 6 // Number of public control classes
+
+#define ICLS_DESKTOP 6
+#define ICLS_DIALOG 7
+#define ICLS_MENU 8
+#define ICLS_SWITCH 9
+#define ICLS_ICONTITLE 10
+#define ICLS_MDICLIENT 11
+#define ICLS_COMBOLISTBOX 12
+
+#define ICLS_MAX 13 // Number of system classes
+
+// The following are the atom values for the atom-named public classes
+// NOTE: DIALOGCLASS at least should be in windows.h
+//
+#define MENUCLASS 0x8000 /* Public Knowledge */
+#define DESKTOPCLASS 0x8001
+#define DIALOGCLASS 0x8002
+#define SWITCHWNDCLASS 0x8003
+#define ICONTITLECLASS 0x8004
+
+/* Z Ordering() return values */
+#define ZO_ERROR (-1)
+#define ZO_EQUAL 0
+#define ZO_DISJOINT 1
+#define ZO_ABOVE 2
+#define ZO_BELOW 3
+
+#ifdef DEBUG
+#ifndef NO_LOCALOBJ_TAGS
+HANDLE FAR UserLocalAlloc(WORD, WORD, WORD);
+HANDLE FAR UserLocalFree(HANDLE);
+char* FAR UserLocalLock(HANDLE);
+BOOL FAR UserLocalUnlock(HANDLE);
+HANDLE FAR UserLocalReAlloc(HANDLE, WORD, WORD);
+WORD FAR UserLocalSize(HANDLE);
+
+#define LocalAlloc(A,B) UserLocalAlloc(ST_MISC,A,B)
+#define LocalFree UserLocalFree
+#define LocalLock UserLocalLock
+#define LocalUnlock UserLocalUnlock
+#define LocalReAlloc UserLocalReAlloc
+#define LocalSize UserLocalSize
+#endif
+#endif
+
+#ifndef DEBUG
+#define UserLocalAlloc(TagType,MemType,Size) LocalAlloc(MemType,Size)
+#else
+#ifdef NO_LOCALOBJ_TAGS
+#define UserLocalAlloc(TagType,MemType,Size) LocalAlloc(MemType,Size)
+#endif
+#endif
+
+#define XCOORD(l) ((int)LOWORD(l))
+#define YCOORD(l) ((int)HIWORD(l))
+#define abs(A) ((A < 0)? -A : A)
+
+/* CheckPoint structure */
+typedef struct tagCHECKPOINT
+ {
+ RECT rcNormal;
+ POINT ptMin;
+ POINT ptMax;
+ HWND hwndTitle;
+ WORD fDragged:1;
+ WORD fWasMaximizedBeforeMinimized:1;
+ WORD fWasMinimizedBeforeMaximized:1;
+ WORD fParkAtTop:1;
+ } CHECKPOINT;
+
+// Internal property name definitions
+
+#define CHECKPOINT_PROP_NAME "SysCP"
+extern ATOM atomCheckpointProp;
+#define WINDOWLIST_PROP_NAME "SysBW"
+extern ATOM atomBwlProp;
+
+#define InternalSetProp(hwnd, key, value, fInternal) SetProp(hwnd, key, value)
+#define InternalGetProp(hwnd, key, fInternal) GetProp(hwnd, key)
+#define InternalRemoveProp(hwnd, key, fInternal) RemoveProp(hwnd, key)
+#define InternalEnumProps(hwnd, pfn, fInternal) EnumProps(hwnd, pfn)
+
+/* Window List Structure */
+typedef struct tagBWL
+ {
+ struct tagBWL *pbwlNext;
+ HWND *phwndMax;
+ HWND rghwnd[1];
+ } BWL;
+typedef BWL *PBWL;
+
+#define CHWND_BWLCREATE 32 // Initial BWL size
+#define CHWND_BWLGROW 16 // Amt to grow BWL by when it needs to grow.
+
+// BuildHwndList() commands
+#define BWL_ENUMCHILDREN 1
+#define BWL_ENUMLIST 2
+
+
+/* DOS Semaphore Structure */
+typedef struct tagSEMAPHORE
+ {
+ DWORD semaphore;
+ HQ hqOwner;
+ BYTE cBusy;
+ BYTE bOrder;
+ } SEMAPHORE;
+typedef SEMAPHORE FAR *LPSEM;
+
+#define CheckHwnd(hwnd) TRUE
+#define CheckHwndNull(hwnd) TRUE
+#define ValidateWindow(hwnd) TRUE
+#define ValidateWindowNull(hwnd) TRUE
+
+#define AllocP(wType,cb) UserLocalAlloc(wType,LPTR, cb)
+#define FreeP(h) LocalFree(h)
+
+#ifndef DEBUG
+#define LMHtoP(handle) (*((char**)(handle)))
+#else
+#ifdef NO_LOCALOBJ_TAGS
+#define LMHtoP(handle) (*((char**)(handle)))
+#else
+#define LMHtoP(handle) (*((char**)(handle))+sizeof(long))
+#endif
+#endif
+
+/* Evil nasty macros to work with movable local objects */
+#define LLock(handle) ((*(((BYTE *)(handle))+3))++)
+#define LUnlock(handle) ((*(((BYTE *)(handle))+3))--)
+
+
+#define dpHorzRes HORZRES
+#define dpVertRes VERTRES
+
+
+HWND WindowHitTest(HWND hwnd, POINT pt, int FAR* ppart);
+
+/*
+ * If the handle for CF_TEXT/CF_OEMTEXT is a dummy handle then this implies
+ * that data is available in the other format (as CF_OEMTEXT/CF_TEXT)
+ */
+#define DUMMY_TEXT_HANDLE ((HANDLE)0xFFFF)
+#define DATA_NOT_BANKED ((HANDLE)0xFFFF)
+
+typedef struct tagCLIP
+ {
+ WORD fmt;
+ HANDLE hData;
+ } CLIP;
+typedef CLIP *PCLIP;
+
+extern CLIP* pClipboard;
+
+typedef struct tagSYSMSG
+ {
+ WORD message;
+ WORD paramL;
+ WORD paramH;
+ DWORD time;
+ } SYSMSG;
+
+typedef struct tagINTERNALSYSMSG
+ {
+ DWORD ismExtraInfo; /* Additional Info */
+ SYSMSG ismOldMsg; /* External System Msg structure */
+ } INTERNALSYSMSG;
+
+typedef struct tagINTERNALMSG
+ {
+ DWORD imExtraInfo; /* Additional Info */
+ MSG imOldMsg; /* External App Msg structure */
+ } INTERNALMSG;
+
+
+typedef struct tagTIMERINFO
+ {
+ LONG resolution;
+ } TIMERINFO;
+
+
+typedef struct tagKBINFO
+ {
+ BYTE Begin_First_range; /* Values used for Far East systems */
+ BYTE End_First_range;
+ BYTE Begin_Second_range;
+ BYTE End_Second_range;
+ int stateSize; /* size of ToAscii()'s state block */
+ } KBINFO;
+
+
+typedef struct tagMOUSEINFO
+ {
+ char fExist;
+ char fRelative;
+ int cButton;
+ int cmsRate;
+ int xThreshold;
+ int yThreshold;
+ int cxResolution; /* resolution needed for absolute mouse coordinate */
+ int cyResolution;
+ int mouseCommPort; /* comm port # to reserve since mouse is using it */
+ } MOUSEINFO;
+
+
+typedef struct tagCURSORINFO
+ {
+ int csXRate;
+ int csYRate;
+ } CURSORINFO;
+
+
+typedef struct tagCURSORSHAPE
+ {
+ int xHotSpot;
+ int yHotSpot;
+ int cx;
+ int cy;
+ int cbWidth; /* Bytes per row, accounting for word alignment. */
+ BYTE Planes;
+ BYTE BitsPixel;
+ } CURSORSHAPE;
+typedef CURSORSHAPE *PCURSORSHAPE;
+typedef CURSORSHAPE FAR * LPCURSORSHAPE;
+
+// Standard ICON dimensions;
+#define STD_ICONWIDTH 32
+#define STD_ICONHEIGHT 32
+#define STD_CURSORWIDTH 32
+#define STD_CURSORHEIGHT 32
+
+typedef struct tagICONINFO
+ {
+ int iIconCurrent;
+ int fHeightChange;
+ int crw; /* current nunber of rows. */
+ int cIconInRow; /* maximum icons in a row. */
+ int cIcon;
+ int wEvent;
+ } ICONINFO;
+
+
+/* Height and Width of the desktop pattern bitmap. */
+#define CXYDESKPATTERN 16
+
+/* System object colors. */
+#define CSYSCOLORS 21
+
+typedef struct tagSYSCLROBJECTS
+ {
+ HBRUSH hbrScrollbar;
+ HBRUSH hbrDesktop;
+ HBRUSH hbrActiveCaption;
+ HBRUSH hbrInactiveCaption;
+ HBRUSH hbrMenu;
+ HBRUSH hbrWindow;
+ HBRUSH hbrWindowFrame;
+ HBRUSH hbrMenuText;
+ HBRUSH hbrWindowText;
+ HBRUSH hbrCaptionText;
+ HBRUSH hbrActiveBorder;
+ HBRUSH hbrInactiveBorder;
+ HBRUSH hbrAppWorkspace;
+ HBRUSH hbrHiliteBk;
+ HBRUSH hbrHiliteText;
+ HBRUSH hbrBtnFace;
+ HBRUSH hbrBtnShadow;
+ HBRUSH hbrGrayText;
+ HBRUSH hbrBtnText;
+ HBRUSH hbrInactiveCaptionText;
+ HBRUSH hbrBtnHilite;
+ } SYSCLROBJECTS;
+
+typedef struct tagSYSCOLORS
+ {
+ LONG clrScrollbar;
+ LONG clrDesktop;
+ LONG clrActiveCaption;
+ LONG clrInactiveCaption;
+ LONG clrMenu;
+ LONG clrWindow;
+ LONG clrWindowFrame;
+ LONG clrMenuText;
+ LONG clrWindowText;
+ LONG clrCaptionText;
+ LONG clrActiveBorder;
+ LONG clrInactiveBorder;
+ LONG clrAppWorkspace;
+ LONG clrHiliteBk;
+ LONG clrHiliteText;
+ LONG clrBtnFace;
+ LONG clrBtnShadow;
+ LONG clrGrayText;
+ LONG clrBtnText;
+ LONG clrInactiveCaptionText;
+ LONG clrBtnHilite;
+ } SYSCOLORS;
+
+typedef struct tagCARET
+ {
+ HWND hwnd;
+ BOOL fVisible;
+ BOOL fOn;
+ int iHideLevel;
+ int x;
+ int y;
+ int cy;
+ int cx;
+ HBITMAP hBitmap;
+ WORD cmsBlink; /* Blink time in milliseconds. */
+ WORD hTimer;
+ } CARET;
+
+/* Resource ID of system menus. */
+#define ID_SYSMENU MAKEINTRESOURCE(1)
+#define ID_CLOSEMENU MAKEINTRESOURCE(2)
+
+/* Menu Item Structure */
+typedef struct tagITEM
+ {
+ WORD fFlags; /* Item Flags. Must be first in this
+ * structure.
+ */
+ HMENU cmdMenu; /* Handle to a popup */
+ int xItem;
+ int yItem;
+ int cxItem;
+ int cyItem;
+ int dxTab;
+ HBITMAP hbmpCheckMarkOn; /* Bitmap for an on check */
+ HBITMAP hbmpCheckMarkOff; /* Bitmap for an off check */
+ HBITMAP hItem; /* Handle to a bitmap or string */
+ int ulX; /* String: Underline start */
+ int ulWidth; /* String: underline width */
+ int cch; /* String: character count */
+ } ITEM;
+typedef ITEM *PITEM;
+typedef ITEM FAR *LPITEM;
+
+#define SIG_MENU ('M' | ('U' << 8))
+
+/* Menu Structure */
+typedef struct tagMENU
+ {
+ struct tagMENU* pMenuNext;
+ WORD fFlags; /* Menu Flags.*/
+ WORD signature; // signature
+ HQ hqOwner; // owner queue
+ int cxMenu;
+ int cyMenu;
+ int cItems; /* Number of items in rgItems */
+ HWND hwndNotify; /* The owner hwnd of this menu */
+ ITEM* rgItems; /* The list of items in this menu */
+#ifdef JAPAN
+ int MenuMode; /* Kanji menu mode flag */
+#endif
+ } MENU;
+typedef MENU *PMENU;
+
+// Layout of first part of menu heap structure.
+//
+typedef struct
+{
+ WORD rgwReserved[8]; // reserve 8 words for standard DS stuff.
+ MENU* pMenuList;
+} MENUHEAPHEADER;
+
+// Head of menu list (USE ONLY WITH DS == MENUHEAP)
+#define PMENULIST (((MENUHEAPHEADER*)NULL)->pMenuList)
+
+void FAR SetMenuDS(void);
+void FAR SetMenuStringDS(void);
+
+#define MENUSYSMENU SPACE_CHAR /* Space character */
+#define MENUCHILDSYSMENU '-' /* Hyphen */
+
+
+/* Defines for the fVirt field of the Accelerator table structure. */
+#define FVIRTKEY TRUE /* Assumed to be == TRUE */
+#define FLASTKEY 0x80 /* Indicates last key in the table */
+#define FNOINVERT 0x02
+#define FSHIFT 0x04
+#define FCONTROL 0x08
+#define FALT 0x10
+
+/* Accelerator Table structure */
+typedef struct tagACCEL
+ {
+ BYTE fVirt; /* Also called the flags field */
+ WORD key;
+ WORD cmd;
+ } ACCEL;
+typedef ACCEL FAR *LPACCEL;
+
+/* OEM Bitmap Information Structure */
+typedef struct tagOEMBITMAPINFO
+ {
+ HBITMAP hBitmap;
+ int cx;
+ int cy;
+ } OEMBITMAPINFO;
+
+/* OEM Information Structure */
+typedef struct tagOEMINFO
+ {
+ OEMBITMAPINFO bmFull;
+ OEMBITMAPINFO bmUpArrow;
+ OEMBITMAPINFO bmDnArrow;
+ OEMBITMAPINFO bmRgArrow;
+ OEMBITMAPINFO bmLfArrow;
+ OEMBITMAPINFO bmReduce;
+ OEMBITMAPINFO bmZoom;
+ OEMBITMAPINFO bmRestore;
+ OEMBITMAPINFO bmMenuArrow;
+ OEMBITMAPINFO bmComboArrow;
+ OEMBITMAPINFO bmReduceD;
+ OEMBITMAPINFO bmZoomD;
+ OEMBITMAPINFO bmRestoreD;
+ OEMBITMAPINFO bmUpArrowD;
+ OEMBITMAPINFO bmDnArrowD;
+ OEMBITMAPINFO bmRgArrowD;
+ OEMBITMAPINFO bmLfArrowD;
+ OEMBITMAPINFO bmUpArrowI; // Up Arrow Inactive
+ OEMBITMAPINFO bmDnArrowI; // Down Arrow Inactive
+ OEMBITMAPINFO bmRgArrowI; // Right Arrow Inactive
+ OEMBITMAPINFO bmLfArrowI; // Left Arrow Inactive
+ int cxbmpHThumb;
+ int cybmpVThumb;
+ int cxMin;
+ int cyMin;
+ int cxIconSlot;
+ int cyIconSlot;
+ int cxIcon;
+ int cyIcon;
+ WORD cxPixelsPerInch; /* logical pixels per inch in X direction */
+ WORD cyPixelsPerInch; /* logical pixels per inch in Y direction */
+ int cxCursor;
+ int cyCursor;
+ WORD DispDrvExpWinVer; /* Display driver expected win version no */
+ WORD ScreenBitCount; /* (BitCount * No of planes) for display */
+ int cSKanji;
+ int fMouse;
+ } OEMINFO;
+
+/* OEMINFO structure for the monochrome bitmaps */
+typedef struct tagOEMINFOMONO
+ {
+ OEMBITMAPINFO bmAdjust;
+ OEMBITMAPINFO bmSize;
+ OEMBITMAPINFO bmCheck; /* Check mark */
+ OEMBITMAPINFO bmbtnbmp; /* Check boxes */
+ OEMBITMAPINFO bmCorner; /* Corner of buttons */
+ int cxbmpChk;
+ int cybmpChk;
+ } OEMINFOMONO;
+
+typedef struct tagBMPDIMENSION
+ {
+ int cxBits; /* Width of the Bitmap */
+ int cyBits; /* Height of the huge bitmap */
+ } BMPDIMENSION;
+
+/* Holds the offsets of all bitmaps in bmBits (of hdcBits). */
+typedef struct tagRESINFO
+ {
+ /* The next 9 match resInfo */
+ int dxClose;
+ int dxUpArrow;
+ int dxDnArrow;
+ int dxRgArrow;
+ int dxLfArrow;
+ int dxReduce;
+ int dxZoom;
+ int dxRestore;
+ int dxMenuArrow;
+ int dxComboArrow;
+ int dxReduceD;
+ int dxZoomD;
+ int dxRestoreD;
+ int dxUpArrowD;
+ int dxDnArrowD;
+ int dxRgArrowD;
+ int dxLfArrowD;
+ int dxUpArrowI; // Up Arrow Inactive.
+ int dxDnArrowI; // Down Arrow Inactive.
+ int dxRgArrowI; // Right Arrow Inactive.
+ int dxLfArrowI; // Left Arrow Inactive.
+ HBITMAP hbmBits;
+ BMPDIMENSION bmpDimension;
+ } RESINFO;
+
+typedef struct tagRESINFOMONO
+ {
+ int dxSize;
+ int dxBtSize;
+ int dxCheck;
+ int dxCheckBoxes;
+ int dxBtnCorners;
+ HBITMAP hbmBits;
+ BMPDIMENSION bmpDimensionMono;
+ } RESINFOMONO;
+
+typedef struct tagTASK
+ {
+ HQ hq;
+ HWND hwnd;
+ int ID;
+ WORD count;
+ WORD freq;
+ WORD ready;
+ FARPROC lpfnTask;
+ } TASK;
+
+//**** SetWindowsHook() related definitions
+
+typedef struct tagHOOKNODE
+{
+ struct tagHOOKNODE* phkNext;// Next in chain
+ HOOKPROC lpfn; // function ptr to call (NULL if deleted during call)
+ int idHook; // hook ID for this node
+ HQ hq; // hq for which this hook applies
+ HMODULE hmodOwner; // Module handle that contains this hook
+ BOOL fCalled; // Whether inside call or not
+} HOOKNODE;
+
+#define HHOOK_MAGIC ('H' | ('K' << 8))
+
+extern HOOKNODE* rgphkSysHooks[];
+extern HOOKNODE* phkDeleted;
+extern BYTE rgbHookFlags[];
+
+LRESULT FAR CallHook(int code, WPARAM wParam, LPARAM lParam, int idHook);
+
+BOOL FAR IsHooked(WORD idHook);
+BOOL CallKbdHook(int code, WPARAM wParam, LPARAM lParam);
+BOOL CallMouseHook(int code, WPARAM wParam, LPARAM lParam);
+
+void UnhookHooks(HANDLE h, BOOL fQueue);
+
+HMODULE GetProcModule(FARPROC lpfn);
+HQ HqFromTask(HTASK htask);
+
+void UnhookHotKeyHooks(HMODULE hmodule);
+
+#ifdef DISABLE
+#define CallVisRgnHook(pparams) (int)CallHook(0, 0, (LONG)(VOID FAR*)pparams, WH_VISRGN) // ;Internal
+#endif
+
+// DC cache related declarations
+
+// DC Cache Entry structure (DCE)
+#define CACHESIZE 5
+
+typedef struct tagDCE
+{
+ struct tagDCE *pdceNext;
+ HDC hdc;
+ HWND hwnd;
+ HWND hwndOrg;
+ HWND hwndClip;
+ HRGN hrgnClip;
+ DWORD flags;
+} DCE;
+
+extern DCE *pdceFirst; // Pointer to first element of cache
+
+extern HRGN hrgnGDC; // Temp used by GetCacheDC et al
+extern HRGN hrgnEWL; // Temp used by ExcludeWindowList()
+extern HRGN hrgnDCH; // Temp used by DCHook()
+extern BOOL fSiblingsTouched;
+
+#define InternalReleaseDC(hdc) ReleaseCacheDC(hdc, FALSE)
+
+/* InvalidateDCCache() flag values */
+#define IDC_DEFAULT 0x0001
+#define IDC_CHILDRENONLY 0x0002
+#define IDC_CLIENTONLY 0x0004
+
+#define IDC_VALID 0x0007 /* ;Internal */
+
+BOOL FAR InvalidateDCCache(HWND hwnd, WORD flags);
+
+int CalcWindowRgn(HWND hwnd, HRGN hrgn, BOOL fClient);
+
+BOOL FAR CalcVisRgn(HRGN hrgn, HWND hwndOrg, HWND hwndClip, DWORD flags);
+BOOL FAR ReleaseCacheDC(HDC hdc, BOOL fEndPaint);
+HDC FAR GetCacheDC(HWND hwndOrg, HWND hwndClip, HRGN hrgnClip, HDC hdcMatch, DWORD flags);
+HDC FAR CreateCacheDC(HWND hwndOrg, DWORD flags);
+BOOL FAR DestroyCacheDC(HDC hdc);
+HWND FAR WindowFromCacheDC(HDC hdc);
+
+BOOL FAR IntersectWithParents(HWND hwnd, LPRECT lprc);
+
+
+//**************************************************************************
+//
+// void SetVisible(hwnd, fSet)
+//
+// This routine must be used to set or clear the WS_VISIBLE style bit.
+// It also handles the setting or clearing of the WF_TRUEVIS bit.
+//
+#define SetVisible(hwnd, fSet) \
+ if (fSet) \
+ { \
+ SetWF((hwnd), WFVISIBLE); \
+ } \
+ else \
+ { \
+ ClrWF((hwnd), WFVISIBLE); \
+ ClrFTrueVis(hwnd); \
+ }
+
+void FAR ClrFTrueVis(HWND hwnd);
+
+/* Saved Popup Bits structure */
+typedef struct tagSPB
+ {
+ struct tagSPB *pspbNext;
+ HWND hwnd;
+ HBITMAP hbm;
+ RECT rc;
+ HRGN hrgn;
+ WORD flags;
+ } SPB;
+
+#define SPB_SAVESCREENBITS 0x0001 // (*lpSaveScreenBits) was called
+#define SPB_LOCKUPDATE 0x0002 // LockWindowUpdate() SPB
+#ifdef DISABLE
+#define SPB_DRAWBUFFER 0x0004 // BeginDrawBuffer() SPB
+#endif
+
+// SPB related functions
+
+extern SPB* pspbFirst;
+
+extern HRGN hrgnSCR; // Temp rgn used by SpbCheckRect() */
+
+extern HRGN hrgnSPB1; // More temp regions
+
+extern HRGN hrgnSPB2;
+
+// This macro can be used to quickly avoid far calls to the SPB code.
+// In some cases it can prevent sucking in the segment that contains
+// all the code.
+//
+#define AnySpbs() (pspbFirst != NULL) // TRUE if there are any SPBs
+
+BOOL SpbValidate(SPB* pspb, HWND hwnd, BOOL fChildren);
+void SpbCheckDce(DCE* pdce);
+BOOL FBitsTouch(HWND hwndInval, LPRECT lprcDirty, SPB* pspb, DWORD flagsDcx);
+void FAR DeleteHrgnClip(DCE* pdce);
+
+void FAR CreateSpb(HWND hwnd, WORD flags, HDC hdcScreen);
+void FAR FreeSpb(SPB* pspb);
+SPB* FAR FindSpb(HWND hwnd);
+void FAR SpbCheckRect(HWND hwnd, LPRECT lprc, DWORD flagsDcx);
+void FAR SpbCheckHwnd(HWND hwnd);
+BOOL FAR RestoreSpb(HWND hwnd, HRGN hrgnUncovered, HDC FAR* phdcScreen);
+void FAR SpbCheck(void);
+BOOL FAR SpbCheckRect2(SPB* pspb, HWND hwnd, LPRECT lprc, DWORD flagsDcx);
+
+// LockWindowUpdate related stuff
+
+extern HWND hwndLockUpdate;
+extern HQ hqLockUpdate;
+
+void FAR InternalInvalidate(register HWND hwnd, HRGN hrgnUpdate, WORD flags);
+BOOL InternalInvalidate2(HWND hwnd, HRGN hrgn, HRGN hrgnSubtract, LPRECT prcParents, WORD flags);
+void _fastcall DeleteUpdateRgn(HWND hwnd);
+
+// SmartRectInRegion return codes
+//
+#define RIR_OUTSIDE 0
+#define RIR_INTERSECT 1
+#define RIR_INSIDE 2
+
+WORD FAR SmartRectInRegion(HRGN hrgn, LPRECT lprc);
+
+// Function used to redraw the screen
+
+#define RedrawScreen() \
+ InternalInvalidate(hwndDesktop, (HRGN)1, \
+ RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN)
+
+extern HRGN hrgnInv1; // Temp used by RedrawWindow()
+extern HRGN hrgnInv2; // Temp used by InternalInvalidate()
+
+HDC CALLBACK InternalBeginPaint(HWND hwnd, PAINTSTRUCT FAR *lpps, BOOL fWindowDC);
+
+// Background and frame drawing related stuff
+
+// WM_SYNCPAINT wParam and DoSyncPaint flags
+
+void FAR DoSyncPaint(HWND hwnd, HRGN hrgn, WORD flags);
+
+// NOTE: the first 4 values must be as defined for backward compatibility
+// reasons. They are sent as parameters to the WM_SYNCPAINT message.
+// They used to be hard-coded constants.
+//
+// Only ENUMCLIPPEDCHILDREN, ALLCHILDREN, and NOCHECKPARENTS are passed on
+// during recursion. The other bits reflect the current window only.
+//
+#define DSP_ERASE 0x0001 // Send WM_ERASEBKGND
+#define DSP_FRAME 0x0002 // Send WM_NCPAINT
+#define DSP_ENUMCLIPPEDCHILDREN 0x0004 // Enum children if WS_CLIPCHILDREN
+#define DSP_WM_SYNCPAINT 0x0008 // Called from WM_SYNCPAINT handler
+#define DSP_NOCHECKPARENTS 0x0010 // Don't check parents for update region
+#define DSP_ALLCHILDREN 0x0020 // Enumerate all children.
+
+BOOL FAR SendEraseBkgnd(HWND hwnd, HDC hdcBeginPaint, HRGN hrgnUpdate);
+void SendNCPaint(HWND hwnd, HRGN hrgnUpdate);
+HWND _fastcall ParentNeedsPaint(HWND hwnd);
+
+// UpdateWindow definitions
+
+#define UW_ENUMCHILDREN 0x0001
+#define UW_VALIDATEPARENTS 0x0002
+
+void InternalUpdateWindow(HWND hwnd, WORD flags);
+void UpdateWindow2(register HWND hwnd, WORD flags);
+void ValidateParents(register HWND hwnd);
+
+// Used for UpdateWindow() calls that really shouldn't be there...
+#define UpdateWindow31(hwnd)
+
+// ScrollWindow() definitions
+
+extern HRGN hrgnSW;
+extern HRGN hrgnScrl1;
+extern HRGN hrgnScrl2;
+extern HRGN hrgnScrlVis;
+extern HRGN hrgnScrlSrc;
+extern HRGN hrgnScrlDst;
+extern HRGN hrgnScrlValid;
+extern HRGN hrgnScrlUpdate;
+
+// Scroll bar definitions
+
+typedef struct tagSBINFO
+{
+ int pos;
+ int posMin;
+ int posMax;
+ int cpxThumb;
+ int cpxArrow;
+ int cpx;
+ int pxMin;
+ int cxBorder;
+ int cyBorder;
+ int nBar;
+ HWND calcHwnd; /* used to identify the window described by this info */
+} SBINFO;
+
+// The following masks can be used along with the wDisableFlags field of SB
+// to find if the Up/Left or Down/Right arrow or Both are disabled;
+// Now it is possible to selectively Enable/Disable just one or both the
+// arrows in a scroll bar control;
+#define LTUPFLAG 0x0001 // Left/Up arrow disable flag.
+#define RTDNFLAG 0x0002 // Right/Down arrow disable flag.
+#define SBFLAGSINDEX 6 // Index of Scroll bar flags in Wnd->rgwScroll[]
+
+typedef struct tagSB
+ {
+ WND wnd;
+ int pos;
+ int min;
+ int max;
+ BOOL fVert;
+ WORD wDisableFlags; // Indicates which arrow is disabled;
+#ifdef DBCS_IME
+ BOOL bImeStatus; // IME status save
+#endif
+ } SB;
+
+typedef SB *PSB;
+typedef SB FAR *LPSB;
+
+/* Structure for list of drivers installed by USER and opened by applications.
+ */
+
+typedef struct tagDRIVERTABLE
+{
+ WORD fBusy:1;
+ WORD fFirstEntry:1;
+ int idNextDriver; /* Next driver in load chain -1 if end */
+ int idPrevDriver; /* Prev driver in load chain -1 if begin */
+ HANDLE hModule;
+ DWORD dwDriverIdentifier;
+ char szAliasName[128];
+ LRESULT (FAR * lpDriverEntryPoint)(DWORD, HDRVR, WORD, LPARAM, LPARAM);
+} DRIVERTABLE;
+typedef DRIVERTABLE FAR *LPDRIVERTABLE;
+
+LRESULT FAR InternalLoadDriver(LPCSTR szDriverName,
+ LPCSTR szSectionName,
+ LPCSTR lpstrTail,
+ WORD cbTail,
+ BOOL fSendEnable);
+WORD FAR InternalFreeDriver(HDRVR hDriver, BOOL fSendDisable);
+
+/* Defines for InternalBroadcastDriverMessage flags */
+#define IBDM_SENDMESSAGE 0x00000001
+#define IBDM_REVERSE 0x00000002
+#define IBDM_FIRSTINSTANCEONLY 0x00000004
+
+LRESULT FAR InternalBroadcastDriverMessage(HDRVR, WORD, LPARAM, LPARAM, LONG);
+
+/* Application queue structure */
+
+#define MSGQSIZE 10
+
+typedef struct tagQ
+ {
+ HQ hqNext;
+ HTASK hTask;
+ int cbEntry;
+ int cMsgs;
+ WORD pmsgRead;
+ WORD pmsgWrite;
+ WORD pmsgMax;
+ LONG timeLast; /* Time, position, and ID of last message */
+ POINT ptLast;
+ int idLast;
+ DWORD dwExtraInfoLast; /* Additional info */
+ WORD unused;
+ LPARAM lParam;
+ WPARAM wParam;
+ int message;
+ HWND hwnd;
+ LRESULT result;
+ int cQuit;
+ int exitCode;
+ WORD flags;
+ WORD pMsgFilterChain;
+ HGLOBAL hDS;
+ int wVersion;
+ HQ hqSender;
+ HQ hqSendList;
+ HQ hqSendNext;
+ WORD cPaintsReady;
+ WORD cTimersReady;
+ WORD changebits;
+ WORD wakebits;
+ WORD wakemask;
+ WORD pResult;
+ WORD pResultSend;
+ WORD pResultReceive;
+ HOOKNODE* phkCurrent;
+ HOOKNODE* rgphkHooks[WH_CHOOKS];
+ DWORD semInput;
+ HQ hqSemNext;
+ INTERNALMSG rgmsg[MSGQSIZE];
+ } Q;
+typedef Q FAR *LPQ;
+
+// NOTE: These macros can be recoded to be much faster if
+// hqCurrent and lpqCurrent are defined as globals that are set
+// at task switch time.
+//
+#define Lpq(hq) ((LPQ)MAKELP((hq), 0))
+#define LpqFromHq(hq) Lpq(hq)
+#define LpqCurrent() ((LPQ)(MAKELP(HqCurrent(), 0)))
+
+typedef WORD ICH;
+
+// Q flags field bits
+
+#define QF_SEMWAIT 0x01
+#define QF_INIT 0x02
+#define QF_PALETTEAPP 0x04 /* This app used the palette */
+
+// Internal GetQueueStatus() flags
+
+#define QS_SMRESULT 0x8000
+#define QS_SMPARAMSFREE 0x4000
+
+/* Capture codes */
+#define NO_CAP_CLIENT 0 /* no capture; in client area */
+#define NO_CAP_SYS 1 /* no capture; in sys area */
+#define CLIENT_CAPTURE 2 /* client-relative capture */
+#define WINDOW_CAPTURE 3 /* window-relative capture */
+#define SCREEN_CAPTURE 4 /* screen-relative capture */
+
+// Extra bytes needed for specific window classes
+//
+#define CBEDITEXTRA 6
+#define CBSTATICEXTRA 6
+#ifdef DBCS_IME
+#define CBBUTTONEXTRA 4 /* need one byte for IME status save */
+#else
+#define CBBUTTONEXTRA 3
+#endif
+#define CBMENUEXTRA 2
+
+/* DrawBtnText codes */
+#define DBT_TEXT 0x0001
+#define DBT_FOCUS 0x0002
+
+/* RIP error codes */
+#define RIP_SEMCHECK 0xFFF4 /* Decimal -12 */
+#define RIP_SWP 0xFFF1 /* Decimal -15 */ /* SetMultipleWindowPos */
+#define RIP_MEMALLOC 0x0001 /* Insufficient memory for allocation */
+#define RIP_MEMREALLOC 0x0002 /* Error realloc memory */
+#define RIP_MEMFREE 0x0003 /* Memory cannot be freed */
+#define RIP_MEMLOCK 0x0004 /* Memory cannot be locked */
+#define RIP_MEMUNLOCK 0x0005 /* Memory cannot be unlocked */
+#define RIP_BADGDIOBJECT 0x0006 /* Invalid GDI object */
+#define RIP_BADWINDOWHANDLE 0x0007 /* Invalid Window handle */
+#define RIP_DCBUSY 0x0008 /* Cached display contexts are busy */
+#define RIP_NODEFWINDOWPROC 0x0009
+#define RIP_CLIPBOARDOPEN 0x000A
+#define RIP_GETDCWITHOUTRELEASE 0x000B /* App did a GetDC and destroyed window without release*/
+#define RIP_INVALKEYBOARD 0x000C
+#define RIP_INVALMOUSE 0x000D
+#define RIP_INVALCURSOR 0x000E
+#define RIP_DSUNLOCKED 0x000F
+#define RIP_INVALLOCKSYSQ 0x0010
+#define RIP_CARETBUSY 0x0011
+#define RIP_GETCWRANGE 0x0012
+#define RIP_HWNDOWNSDCS 0x0013 /* One hwnd owns all the DCs */
+#define RIP_BADHQ 0x0014 /* operation on something of wrong task */
+#define RIP_BADDCGRAY 0x0015 /* bad dc gray */
+#define RIP_REFCOUNTOVERFLOW 0x0016 /* Ref Count in CLS overflows */
+#define RIP_REFCOUNTUNDERFLOW 0x0017 /* Ref Count in CLS becomes negative */
+#define RIP_COUNTBAD 0x0018 /* Ref Count should be zero; But not so */
+#define RIP_INVALIDWINDOWSTYLE 0x0019 /* Illegal window style bits were set */
+#define RIP_GLOBALCLASS 0x001A /* An application that registered a global
+ * class is terminating, but the reference
+ * count is non-zero(somebody else is using
+ * it). */
+#define RIP_BADHOOKHANDLE 0x001B
+#define RIP_BADHOOKID 0x001C
+#define RIP_BADHOOKPROC 0x001D
+#define RIP_BADHOOKMODULE 0x001E
+#define RIP_BADHOOKCODE 0x001F
+#define RIP_HOOKNOTALLOWED 0x0020
+
+#define RIP_UNREMOVEDPROP 0x0021
+#define RIP_BADPROPNAME 0x0022
+#define RIP_BADTASKHANDLE 0x0023
+
+#define RIP_GETSETINFOERR1 0x0027 /* Bad negative index for Get/Set/Window etc., */
+#define RIP_GETSETINFOERR2 0x0028 /* Bad Positive index for Get/Set/Window etc., */
+
+#define RIP_DIALOGBOXDESTROYWINDOWED 0x0029 /* App called DestroyWindow on a DialogBox window */
+#define RIP_WINDOWIDNOTFOUND 0x002A /* Dialog control ID not found */
+#define RIP_SYSTEMERRORBOXFAILED 0x002B /* Hard sys error box failed due to no hq */
+#define RIP_INVALIDMENUHANDLE 0x002C /* Invalid hMenu */
+#define RIP_INVALIDMETAFILEINCLPBRD 0x002D /* Invalid meta file pasted into clipboard */
+#define RIP_MESSAGEBOXWITHNOQUEUE 0x002E /* MessageBox called with no message queue initialized */
+#define RIP_DLGWINDOWEXTRANOTALLOCATED 0x002F /* DLGWINDOWEXTRA bytes not allocated for dlg box */
+#define RIP_INTERTASKSENDMSGHANG 0x0030 /* Intertask send message with tasks locked */
+
+#define RIP_INVALIDPARAM 0x0031 /* Invalid parameter passed to a function */
+#define RIP_ASSERTFAILED 0x0032
+#define RIP_INVALIDFUNCTIONCALLED 0x0033 /* Invalid function was called */
+#define RIP_LOCKINPUTERROR 0x0034 /* LockInput called when input was already locked or when never locked.*/
+#define RIP_NULLWNDPROC 0x0035 /* SetWindowLong uses a NULL wnd proc */
+#define RIP_BAD_UNHOOK 0x0036 /* SetWindowsHook is used to unhook. */
+#define RIP_QUEUE_FULL 0x0037 /* PostMessage failed due to full queue. */
+
+#ifdef DEBUG
+
+#define DebugFillStruct DebugFillBuffer
+
+#define DebugErr(flags, sz) \
+ { static char CODESEG rgch[] = "USER: "sz; DebugOutput((flags) | DBF_USER, rgch); }
+
+extern char CODESEG ErrAssertFailed[];
+
+#define Assert(f) ((f) ? TRUE : (DebugOutput(DBF_ERROR, ErrAssertFailed), FALSE))
+
+extern BOOL fRevalidate;
+
+#define DONTREVALIDATE() fRevalidate = FALSE;
+
+VOID FAR CheckCbDlgExtra(HWND hwnd);
+
+#else
+
+#define DebugErr(flags, sz)
+
+#define Assert(f) FALSE
+
+#define DONTREVALIDATE()
+
+#define CheckCbDlgExtra(hwnd)
+
+#endif
+
+#define UserLogError(flags, errcode, sz) \
+ { DebugErr((flags), sz); \
+ LogError(errcode, NULL); }
+
+#define BM_CLICK WM_USER+99
+#define CH_PREFIX '&'
+#define CH_HELPPREFIX 0x08
+
+#if defined(JAPAN) || defined(KOREA)
+// Japan and Korea support both Kanji and English mnemonic characters,
+// toggled from control panel. Both mnemonics are embedded in menu
+// resource templates. The following prefixes guide their parsing.
+//
+#define CH_ENGLISHPREFIX 0x1E
+#define CH_KANJIPREFIX 0x1F
+
+#define KMM_ENGLISH 2 // English/Romaji menu mode
+#define KMM_KANJI 3 // Kanji/Hangeul menu mode
+extern int KanjiMenuMode;
+#endif
+
+/* The total number of strings used as Button strings in MessageBoxes */
+#define MAX_MB_STRINGS 8
+
+/* Dialog box activation border width factor. */
+#define CLDLGFRAME 4
+#define CLDLGFRAMEWHITE 0
+
+/* Constants for onboard bitmap save. */
+#define ONBOARD_SAVE 0x0000
+#define ONBOARD_RESTORE 0x0001
+#define ONBOARD_CLEAR 0x0002
+
+/* Bitmap resource IDs */
+#define BMR_ICON 1
+#define BMR_BITMAP 2
+#define BMR_CURSOR 3
+#define BMR_DEVDEP 0
+#define BMR_DEVIND 1
+#define BMR_DEPIND 2
+
+/* PID definitions */
+#define get_PID 0
+#define get_EMSSave_area 1
+#define dont_free_banks 2
+#define free_PIDs_banks 3
+#define free_handle 4
+#define memory_sizes 5
+#define DDE_shared 6
+
+// SetWindowPos() related structures and definitions
+//
+extern HRGN hrgnInvalidSum;
+extern HRGN hrgnVisNew;
+extern HRGN hrgnSWP1;
+extern HRGN hrgnValid;
+extern HRGN hrgnValidSum;
+extern HRGN hrgnInvalid;
+
+// CalcValidRects() "Region Empty" flag values
+// A set bit indicates the corresponding region is empty.
+//
+#define RE_VISNEW 0x0001 // CVR "Region Empty" flag values
+#define RE_VISOLD 0x0002 // A set bit indicates the
+#define RE_VALID 0x0004 // corresponding region is empty.
+#define RE_INVALID 0x0008
+#define RE_SPB 0x0010
+#define RE_VALIDSUM 0x0020
+#define RE_INVALIDSUM 0x0040
+
+typedef struct tagCVR // cvr
+{
+ WINDOWPOS pos; // MUST be first field of CVR!
+ int xClientNew; // New client rectangle
+ int yClientNew;
+ int cxClientNew;
+ int cyClientNew;
+ RECT rcBlt;
+ int dxBlt; // Distance blt rectangle is moving
+ int dyBlt;
+ WORD fsRE; // RE_ flags: whether hrgnVisOld is empty or not
+ HRGN hrgnVisOld; // Previous visrgn
+} CVR;
+
+typedef struct tagSMWP // smwp
+{
+ int ccvr; // Number of CVRs in the SWMP
+ int ccvrAlloc; // Number of actual CVRs allocated in the SMWP
+ BOOL fInUse;
+ WORD signature; // signature word for handle validation
+ CVR rgcvr[1];
+} SMWP;
+
+#define SMWP_SIG ('W' | ('P' << 8))
+
+#define PEMWP HDWP
+
+#define NEAR_SWP_PTRS
+#ifdef NEAR_SWP_PTRS
+
+typedef SMWP* PSMWP;
+typedef CVR* PCVR;
+#else
+
+typedef SMWP FAR* PSMWP;
+typedef CVR FAR* PCVR;
+#endif
+
+BOOL ValidateSmwp(PSMWP psmwp, BOOL FAR* pfSyncPaint);
+HWND SmwpFindActive(PSMWP psmwp);
+void SendChangedMsgs(PSMWP psmwp);
+BOOL ValidateWindowPos(WINDOWPOS FAR *ppos);
+BOOL BltValidBits(PSMWP psmwp);
+BOOL SwpCalcVisRgn(HWND hwnd, HRGN hrgn);
+BOOL CombineOldNewVis(HRGN hrgn, HRGN hrgnVisOld, HRGN hrgnVisNew, WORD crgn, WORD fsRgnEmpty);
+void CalcValidRects(PSMWP psmwp, HWND FAR* phwndNewActive);
+BOOL ValidateZorder(PCVR pcvr);
+PSMWP ZOrderByOwner(PSMWP psmwp);
+PSMWP AddCvr(PSMWP psmwp, HWND hwnd, HWND hwndInsertAfter, WORD flags);
+BOOL SwpActivate(HWND hwndNewActive);
+
+void FAR HandleWindowPosChanged(HWND hwnd, WINDOWPOS FAR *lppos);
+void FAR OffsetChildren(HWND hwnd, int dx, int dy, LPRECT prcHitTest);
+BOOL FAR IntersectWithParents(HWND hwnd, LPRECT lprcParents);
+
+// Preallocated buffers for use during SetWindowPos to prevent memory
+// allocation failures.
+//
+#define CCVR_WORKSPACE 4
+#define CCVR_MSG_WORKSPACE 2
+
+#define CB_WORKSPACE ((sizeof(SMWP) - sizeof(CVR)) + CCVR_WORKSPACE * sizeof(CVR))
+#define CB_MSG_WORKSPACE ((sizeof(SMWP) - sizeof(CVR)) + CCVR_MSG_WORKSPACE * sizeof(CVR))
+
+extern BYTE workspace[];
+extern BYTE msg_workspace[];
+
+typedef struct tagSTAT
+ {
+ WND wnd;
+ HFONT hFont;
+ HBRUSH hBrush;
+ HICON hIcon;
+ } STAT;
+typedef STAT *PSTAT;
+
+#define IsCrlf(x) ((char)(x)==0x0D)
+
+/* Help Engine stuff */
+
+typedef struct
+ {
+ unsigned short cbData; /* Size of data */
+ unsigned short usCommand; /* Command to execute */
+ unsigned long ulTopic; /* Topic/context number (if needed) */
+ unsigned long ulReserved; /* Reserved (internal use) */
+ unsigned short offszHelpFile; /* Offset to help file in block */
+ unsigned short offabData; /* Offset to other data in block */
+ } HLP;
+
+typedef HLP FAR *LPHLP;
+
+typedef HANDLE HDCS;
+
+/* DrawFrame() Commands */
+#define DF_SHIFT0 0x0000
+#define DF_SHIFT1 0x0001
+#define DF_SHIFT2 0x0002
+#define DF_SHIFT3 0x0003
+#define DF_PATCOPY 0x0000
+#define DF_PATINVERT 0x0004
+
+#define DF_SCROLLBAR (COLOR_SCROLLBAR << 3)
+#define DF_BACKGROUND (COLOR_BACKGROUND << 3)
+#define DF_ACTIVECAPTION (COLOR_ACTIVECAPTION << 3)
+#define DF_INACTIVECAPTION (COLOR_INACTIVECAPTION << 3)
+#define DF_MENU (COLOR_MENU << 3)
+#define DF_WINDOW (COLOR_WINDOW << 3)
+#define DF_WINDOWFRAME (COLOR_WINDOWFRAME << 3)
+#define DF_MENUTEXT (COLOR_MENUTEXT << 3)
+#define DF_WINDOWTEXT (COLOR_WINDOWTEXT << 3)
+#define DF_CAPTIONTEXT (COLOR_CAPTIONTEXT << 3)
+#define DF_ACTIVEBORDER (COLOR_ACTIVEBORDER << 3)
+#define DF_INACTIVEBORDER (COLOR_INACTIVEBORDER << 3)
+#define DF_APPWORKSPACE (COLOR_APPWORKSPACE << 3)
+#define DF_GRAY (DF_APPWORKSPACE + (1 << 3))
+
+
+#ifdef FASTFRAME
+
+typedef struct tagFRAMEBITMAP
+{
+ int x; /* Top Left co-ordinates */
+ int y;
+ int dx; /* Width of the bitmap */
+ int dy; /* Height of the bitmap */
+} FRAMEBITMAP;
+
+#define FB_THICKFRAME FALSE
+#define FB_DLGFRAME TRUE
+
+#define FB_ACTIVE 0
+#define FB_INACTIVE 1
+
+#define FB_HORZ 0
+#define FB_VERT 1
+#define FB_DLG_HORZ 2
+#define FB_DLG_VERT 3
+#define FB_CAPTION 4
+
+typedef struct tagFRAMEDETAILS
+{
+ HBITMAP hFrameBitmap[5][2]; /* indices explained above */
+ FRAMEBITMAP ActBorderH[4]; /* Four parts of Thick frame Horz bitmap */
+ FRAMEBITMAP ActBorderV[4];
+ FRAMEBITMAP DlgFrameH[4]; /* Four parts of Dlg Frame Horz bitmap */
+ FRAMEBITMAP DlgFrameV[4];
+ FRAMEBITMAP CaptionInfo[7];
+ int clBorderWidth;
+} FRAMEDETAILS;
+
+typedef FRAMEBITMAP *PFRAMEBITMAP;
+
+// Fast frame related macros
+#define FC_ACTIVEBORDER 0x01
+#define FC_INACTIVEBORDER 0x02
+#define FC_ACTIVECAPTION 0x04
+#define FC_INACTIVECAPTION 0x08
+#define FC_WINDOWFRAME 0x10
+
+#define FC_ACTIVEBIT 0x01
+#define FC_INACTIVEBIT 0x02
+#define FC_STATUSBITS (FC_ACTIVEBIT | FC_INACTIVEBIT)
+
+#endif /* FASTFRAME */
+
+// The following defines the components of nKeyboardSpeed
+#define KSPEED_MASK 0x001F // Defines the key repeat speed.
+#define KDELAY_MASK 0x0060 // Defines the keyboard delay.
+#define KDELAY_SHIFT 5
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* Secret Imports - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+#ifndef MSDWP
+
+/* Imported from Kernel. */
+HQ FAR GetTaskQueue(HTASK);
+HQ FAR SetTaskQueue(HTASK, HQ);
+void FAR LockCurrentTask(BOOL);
+HANDLE FAR emscopy();
+//void FAR ExitKernel(int);
+int FAR LocalCountFree(void);
+int FAR LocalHeapSize(void);
+BOOL FAR IsWinoldapTask(HTASK);
+WORD FAR GetExeVersion(void);
+DWORD FAR GetTaskDS(void);
+void FAR SetTaskSignalProc(WORD, FARPROC);
+DWORD FAR GetHeapSpaces(HMODULE hModule);
+int FAR IsScreenGrab(void);
+
+/* Imported from GDI. */
+int API IntersectVisRect(HDC, int, int, int, int);
+int API ExcludeVisRect(HDC, int, int, int, int);
+int API SelectVisRgn(HDC, HRGN);
+int API SaveVisRgn(HDC);
+int API RestoreVisRgn(HDC);
+HRGN API InquireVisRgn(HDC);
+HDCS API GetDCState(HDC);
+BOOL API SetDCState(HDC, HDCS);
+HFONT API GetCurLogFont(HDC); // From GDI
+#define SwapHandle(foo)
+
+HANDLE FAR GDIInit2(HANDLE, HANDLE);
+HRGN API GetClipRgn(HDC);
+HBITMAP FAR CreateUserBitmap(int, int, int, int, LONG);
+void FAR UnRealizeObject(HBRUSH);
+void FAR LRCCFrame(HDC, LPRECT, HBRUSH, DWORD);
+void FAR Death(HDC);
+void FAR Resurrection(HDC, LONG, LONG, LONG);
+void FAR DeleteAboveLineFonts(void);
+BOOL FAR GDIInitApp(void);
+HBITMAP FAR CreateUserDiscardableBitmap(HDC, int, int);
+void FAR FinalGDIInit(HBRUSH);
+void FAR GDIMoveBitmap(HBITMAP);
+BOOL FAR IsValidMetaFile(HMETAFILE);
+#define GDIMoveBitmap(d1)
+
+#endif /* MSDWP */
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* DS Global Variables (from WINDS.C) */
+/* */
+/*--------------------------------------------------------------------------*/
+
+//***** Initialization globals
+
+extern HINSTANCE hInstanceWin;
+extern HMODULE hModuleWin;
+
+//WORD rgwSysMet[]; // Defined in winmisc2.asm
+
+//***** System mode globals
+
+extern BOOL fDialog; // Dialog box is active
+extern BOOL fEndSession; // Shutting down system
+extern BOOL fTaskIsLocked; // LockTask() called
+
+extern BOOL fMessageBox; // hard message box active
+extern HWND hwndSysModal;
+
+extern HQ hqAppExit; // hq of app in app termination code
+
+//***** System option settings globals
+
+extern int nKeyboardSpeed; // keyboard repeat rate
+
+extern int iScreenSaveTimeOut; // screen saver timeout
+
+extern BOOL fHires; /* VERTRES > 300? */
+extern BOOL fPaletteDisplay; /* Are we on a palette display driver? */
+extern BOOL fEdsunChipSet; /* Edsun vga chip set? */
+
+//***** Window manager globals
+
+extern HWND hwndDesktop; // Desktop window
+
+extern PCLS pclsList; // List of registered classes
+
+extern PBWL pbwlCache; // BuildWindowList() globals
+extern PBWL pbwlList;
+
+//***** Input globals
+
+extern BOOL fThunklstrcmp; // if TRUE we thunk to Win32
+
+extern WORD idSysPeek; /* ID in sys queue of msg being looked at */
+
+extern DWORD timeLastInputMessage; // Time of the last keyboard, mouse, or
+ // other input message.
+
+extern HWND hwndCursor;
+
+extern HWND hwndDblClk; // doubleclick parsing
+extern RECT rcDblClk;
+extern WORD dtDblClk;
+extern WORD msgDblClk;
+extern DWORD timeDblClk;
+
+extern int defQueueSize; // Default msg queue size
+
+extern HTASK hTaskLockInput; /* Task which has called LockInput() */
+
+extern KBINFO keybdInfo;
+extern BYTE *pState; // Pointer to buffer for ToAscii
+
+extern BOOL fShrinkGDI; /* Does GDI's heap needs shrinking? */
+extern BOOL fLockNorem; /* PeekMsg NOREMOVE flag */
+
+//***** Activation/Focus/Capture related globals
+
+extern HWND hwndActive;
+extern HWND hwndActivePrev;
+
+extern HWND hwndFocus;
+
+extern int codeCapture;
+extern HWND hwndCapture;
+
+//***** SetWindowPos() related globals
+
+extern HRGN hrgnInvalidSum; // Temps used by SetWindowPos()
+extern HRGN hrgnVisNew;
+extern HRGN hrgnSWP1;
+extern HRGN hrgnValid;
+extern HRGN hrgnValidSum;
+extern HRGN hrgnInvalid;
+
+#ifdef LATER
+// Are these still needed now that SysErrorBox() is working?
+#endif
+
+extern BYTE workspace[]; // Buffers used to prevent mem alloc
+extern BYTE msg_workspace[]; // failures in messagebox
+
+//***** General graphics globals
+
+extern HDC hdcBits; /* DC with User's bitmaps */
+extern HDC hdcMonoBits; /* DC with User's MONO bitmaps */
+
+extern OEMINFO oemInfo;
+extern OEMINFOMONO oemInfoMono;
+
+extern RESINFO resInfo;
+extern RESINFOMONO resInfoMono;
+
+extern SYSCLROBJECTS sysClrObjects;
+extern SYSCOLORS sysColors;
+
+extern HFONT hFontSys; // alias for GetStockObject(SYSTEM_FONT);
+extern HFONT hFontSysFixed; // alias for GetStockObject(SYSTEM_FIXED_FONT);
+extern HBRUSH hbrWhite; // alias for GetStockObject(WHITE_BRUSH);
+extern HBRUSH hbrBlack; // alias for GetStockObject(BLACK_BRUSH);
+extern HPALETTE hPalDefaultPalette; // alias for GetStockObject(DEFAULT_PALETTE);
+
+//***** DC Cache related globals
+
+extern DCE* pdceFirst; /* Ptr to first entry in cache */
+
+extern HRGN hrgnEWL; // Temp used by ExcludeWindowList()
+extern HRGN hrgnGDC; // Temp used by GetCacheDC() et al
+extern HRGN hrgnDCH; // Temp used by DCHook()
+
+extern HRGN hrgnNull; // empty rgn
+extern HRGN hrgnScreen; // rcScreen-sized rgn
+
+extern HDCS hdcsReset;
+
+extern HDC hdcScreen;
+
+//***** Begin/EndDrawBuffer() globals
+
+#ifdef DISABLE
+extern HWND hwndBuffer;
+extern HBITMAP hbmBuffer;
+extern HBITMAP hbmBufferSave;
+extern int cxBuffer;
+extern int cyBuffer;
+extern int dxBuffer;
+extern DCE* pdceBuffer;
+extern int dxBufferVisRgn;
+extern int dyBufferVisRgn;
+extern BOOL fBufferFlushed;
+extern RECT rcBuffer;
+
+extern HDCS hdcsMemReset;
+#endif
+
+//***** LockWindowUpdate related globals
+
+extern HQ hqLockUpdate;
+extern HWND hwndLockUpdate;
+
+//***** SPB related globals
+
+extern SPB *pspbFirst;
+
+extern HRGN hrgnSCR; // Temp used by SpbCheckRect()
+extern HRGN hrgnSPB1;
+extern HRGN hrgnSPB2;
+
+extern HRGN hrgnInv0; // Temps used by InternalInvalidate()
+extern HRGN hrgnInv1;
+extern HRGN hrgnInv2;
+
+//***** General Metrics
+
+extern RECT rcScreen; // Screen rectangle
+extern int cxScreen; // Screen height/width
+extern int cyScreen;
+
+extern BOOL fBeep; /* Warning beeps allowed? */
+
+extern int cxSysFontChar; // System font metrics
+extern int cxSysFontOverhang;
+extern int cySysFontAscent;
+extern int cySysFontChar;
+extern int cySysFontExternLeading;
+
+extern int cxBorder; // Nominal border width/height
+extern int cyBorder;
+
+extern int cyCaption; // height of caption
+
+extern int cxSize; // dimensions of system menu bitmap
+extern int cySize;
+
+extern int cyHScroll; // scroll bar dimensions
+extern int cxVScroll;
+
+extern int cxSlot; // icon slot dimensions
+extern int cySlot;
+
+//***** ScrollWindow/ScrollDC related globals
+
+extern HRGN hrgnSW; // Temps used by ScrollDC/ScrollWindow
+extern HRGN hrgnScrl1;
+extern HRGN hrgnScrl2;
+extern HRGN hrgnScrlVis;
+extern HRGN hrgnScrlSrc;
+extern HRGN hrgnScrlDst;
+extern HRGN hrgnScrlValid;
+extern HRGN hrgnScrlUpdate;
+
+//***** Clipboard globals
+
+extern int cNumClipFormats; // Number of formats in clipboard
+extern CLIP *pClipboard; // Clipboard data
+extern HQ hqClipLock; // hq of app accessing clipboard
+extern HWND hwndClipOwner; // clipboard owner
+extern HWND hwndClipViewer; // clipboard viewer
+extern BOOL fClipboardChanged; // TRUE if DrawClipboard needs to be called
+extern BOOL fDrawingClipboard; // TRUE if inside DrawClipboard()
+extern HWND hwndClipOpen; // hwnd of app accessing clipboard
+extern BOOL fCBLocked; /* Is clibboard locked? */
+
+//***** Fast frame drawing globals
+
+#ifdef FASTFRAME
+extern BOOL fFastFrame;
+extern FRAMEDETAILS Frame;
+#endif /* FASTFRAME */
+
+//***** WinOldAppHackoMaticFlags
+
+extern WORD winOldAppHackoMaticFlags; /* Flags for doing special things for
+ winold app */
+//***** TaskManager exec globals
+
+extern PSTR pTaskManName; // Task manager file name
+
+//***** atom management globals
+
+extern HANDLE hWinAtom; // global atom manager heap
+
+//***** WM_HOTKEY globals
+
+extern PSTR pHotKeyList; /* Pointer to list of hot keys in system. */
+extern int cHotKeyCount; /* Count of hot keys in list. */
+
+//***** WinHelp() globals
+
+extern WORD msgWinHelp;
+
+//***** SetWindowsHook() system hook table
+
+extern HOOKNODE* rgphkSysHooks[];
+extern HOOKNODE* phkDeleted;
+
+//***** Driver management globals
+
+extern int cInstalledDrivers; /* Count of installed driver structs allocated*/
+extern HDRVR hInstalledDriverList; /* List of installable drivers */
+extern int idFirstDriver; /* First driver in load chain */
+extern int idLastDriver; /* Last driver in load chain */
+
+//***** Display driver globals
+
+extern HINSTANCE hInstanceDisplay;
+
+extern BOOL fOnBoardBitmap; /* Can display save bitmaps onboard? */
+extern BOOL (CALLBACK *lpSaveBitmap)(LPRECT lprc, WORD flags);
+extern VOID (CALLBACK *lpDisplayCriticalSection)(BOOL fLock);
+extern VOID (CALLBACK *lpWin386ShellCritSection)(VOID);
+typedef int (FAR *FARGETDRIVERPROC)(int, LPCSTR);
+extern FARGETDRIVERPROC lpfnGetDriverResourceId;
+
+//***** Comm driver definitions and globals
+
+// Comm driver constants
+//
+#define LPTx 0x80 /* Mask to indicate cid is for LPT device */
+#define LPTxMask 0x7F /* Mask to get cid for LPT device */
+
+#define PIOMAX 3 /* Max number of LPTx devices in high level */
+#define CDEVMAX 10 /* Max number of COMx devices in high level */
+#define DEVMAX (CDEVMAX+PIOMAX) /* Max number of devices in high level */
+
+// qdb - queue definition block
+//
+typedef struct {
+ char far *pqRx; /* pointer to rx queue */
+ int cbqRx; /* size of RX Queue in bytes */
+ char far *pqTx; /* Pointer to TX Queue */
+ int cbqTx; /* Size of TX Queue in bytes */
+} qdb;
+
+// cinfo - Communications Device Information
+//
+typedef struct
+{
+ WORD fOpen : 1; /* Device open flag */
+ WORD fchUnget : 1; /* Flag for backed-up character */
+ WORD fReservedHardware:1; /* Reserved for hardware (mouse etc) */
+ HTASK hTask; /* Handle to task who opened us */
+ char chUnget; /* Backed-up character */
+ qdb qdbCur; /* Queue information */
+} cinfo;
+
+extern cinfo rgcinfo[];
+
+extern int (FAR PASCAL *lpCommWriteString)(int, LPCSTR, WORD);
+ /* Ptr to the comm driver's
+ * commwritestring function. Only
+ * exists in 3.1 drivers.
+ */
+extern int (FAR PASCAL *lpCommReadString)(int, LPSTR, WORD);
+ /* Ptr to the comm driver's
+ * commreadstring function. Only
+ * exists in 3.1 drivers.
+ */
+extern BOOL (FAR PASCAL *lpCommEnableNotification)(int, HWND, int, int);
+ /* Ptr to the comm driver's
+ * EnableNotification function.
+ * Only exists in 3.1 drivers.
+ */
+
+//***** PenWinProc globals
+/* Ptr to register us as pen aware dlg box
+ */
+extern VOID (CALLBACK *lpRegisterPenAwareApp)(WORD i, BOOL fRegister);
+
+
+//***** Resource handler globals
+
+extern RSRCHDLRPROC lpDefaultResourceHandler;
+
+//***** NLS related globals
+
+extern HINSTANCE hLangDrv; /* The module handle of the language driver */
+extern FARPROC fpLangProc; /* The entry point into the language driver */
+
+#ifdef DBCS_IME
+extern HINSTANCE hWinnls; /* WINNLS.DLL module handle */
+#endif
+
+//***** Caret globals
+
+extern CARET caret;
+extern HQ hqCaret;
+
+//***** Cursor globals
+
+extern CURSORINFO cursInfo;
+
+#ifdef LATER
+// Is this array big enough?
+#endif
+
+extern HCURSOR rghCursor[];
+
+extern HBITMAP hbmCursorBitmap; /* Pre created bitmap for SetCursor */
+extern HGLOBAL hPermanentCursor; /* Precreated permanent cursor resource */
+
+extern HCURSOR hCurCursor;
+
+extern HCURSOR hCursNormal;
+extern HCURSOR hCursUpArrow;
+extern HCURSOR hCursIBeam;
+extern HCURSOR hCursSizeAll;
+
+//INT iLevelCursor; NOTE: overlays sys metrics array (winmisc2.asm)
+
+//***** Icon globals
+
+extern HICON hIconBang;
+extern HICON hIconHand;
+extern HICON hIconNote;
+extern HICON hIconQues;
+extern HICON hIconSample;
+extern HICON hIconWarn;
+extern HICON hIconErr;
+
+extern HBITMAP hbmDrawIconMono; /* Pre created bitmaps for drawicon */
+extern HBITMAP hbmDrawIconColor; /* Pre created bitmaps for drawicon */
+
+extern HTASK hTaskGrayString; /* Task in graystring */
+
+//***** Desktop/Wallpaper globals
+
+extern HBITMAP hbmDesktop; /* Monochrome Desktop pattern */
+extern HBITMAP hbmWallpaper; /* Bitmap that will be drawn on the desktop */
+
+//***** Window move/size tracking globals
+
+extern RECT rcDrag;
+extern RECT rcWindow;
+extern RECT rcParent;
+extern WORD cmd;
+extern HICON hdragIcon;
+extern BOOL fTrack;
+extern int dxMouse;
+extern int dyMouse;
+extern int impx;
+extern int impy;
+extern HWND hwndTrack;
+extern BOOL fInitSize;
+extern POINT ptMinTrack;
+extern POINT ptMaxTrack;
+extern BOOL fmsKbd;
+extern POINT ptRestore;
+extern HCURSOR hIconWindows; /* Cool windows icon */
+extern BOOL fDragFullWindows; /* Drag xor rect or full windows */
+
+/* Added flag to stop anyone from setting the cursor while
+ * we are moving the hDragIcon. This was done to fix a bug in micrografix
+ * Draw (They are doing a Setcursor() whenever they get a paint message).
+ */
+extern BOOL fdragIcon; // Prevent SetCursor while dragging icon
+
+/* When an iconic window is moved around with a mouse, IsWindowVisible() call
+ * returns FALSE! This is because, the window is internally hidden and what is
+ * visible is only a mouse cursor! But how will the Tracer guys know this?
+ * They won't! So, when an Icon window is moved around, its hwnd is preserved
+ * in this global and IsWindowVisible() will return a true for
+ * this window!
+ */
+extern HWND hwndDragIcon;
+
+//***** MessageBox globals
+
+extern int cntMBox; // Nesting level for overlap tiling of mboxes
+extern WORD wDefButton; // index of current default button
+extern WORD wMaxBtnSize; // width of biggest button in any message box
+
+//***** Size border metric globals
+
+extern int clBorder; /* # of logical units in window frame */
+extern int cxSzBorder; /* Window border width (cxBorder*clBorder) */
+extern int cySzBorder; /* Window border height (cyBorder*clBorder) */
+extern int cxSzBorderPlus1; /* cxBorder*(clBorder+1). We overlap a line */
+extern int cySzBorderPlus1; /* cyBorder*(clBorder+1). We overlap a line */
+
+//***** Window tiling/cascading globals
+
+extern int cxyGranularity; /* Top-level window grid granularity */
+extern int cyCWMargin; /* Space on top of toplevel window 'stack' */
+extern int cxCWMargin; /* Space on right of toplevel window 'stack'*/
+extern int iwndStack;
+
+extern int cxHalfIcon; // rounding helpers for icon positioning
+extern int cyHalfIcon;
+
+//***** Alt-tab switching globals
+
+extern HWND hwndAltTab;
+extern HWND hwndSwitch;
+extern HWND hwndKbd;
+extern BOOL fFastAltTab; /* Don't use Tandy's switcher? */
+extern BOOL fInAltTab;
+
+//***** Icon title globals
+
+extern int cyTitleSpace;
+extern BOOL fIconTitleWrap; /* Wrap icon titles or just use single line? */
+extern LOGFONT iconTitleLogFont; /* LogFont struct for icon title font */
+extern HFONT hIconTitleFont; /* Font used in icon titles */
+
+//***** GrayString globals
+
+extern HBRUSH hbrGray; // GrayString globals.
+extern HBITMAP hbmGray;
+extern HDC hdcGray;
+extern int cxGray; // current dimensions of hbmGray
+extern int cyGray;
+
+//***** WM_GETMINMAXINFO globals
+
+extern POINT rgptMinMaxWnd[];
+extern POINT rgptMinMax[];
+
+//***** Menu globals
+
+extern int menuSelect;
+extern int mnFocus;
+
+extern HANDLE hMenuHeap; /* Menu heap */
+extern _segment menuBase;
+extern HANDLE hMenuStringHeap;
+extern _segment menuStringBase;
+
+
+//PPOPUPMENU pGlobalPopupMenu; // mnloop.c
+
+extern HWND hwndRealPopup;
+
+extern BOOL fMenu; /* Using a menu? */
+extern BOOL fSysMenu;
+extern BOOL fInsideMenuLoop; /* MenuLoop capture? */
+
+extern BOOL fMenuStatus;
+extern int iActivatedWindow;/* This global is examined in the menu loop
+ * code so that we exit from menu mode if
+ * another window was activated while we were
+ * tracking menus. This global is incremented
+ * whenever we activate a new window.
+ */
+extern WORD iDelayMenuShow; /* Delay till the hierarchical menu is shown*/
+extern WORD iDelayMenuHide; /* Delay till the hierarchical menu is hidden
+ when user drags outside of it */
+extern HMENU hSysMenu;
+
+extern HBITMAP hbmSysMenu;
+extern RECT rcSysMenuInvert;
+
+//***** Scroll bar globals
+
+extern ATOM atomScrollBar; /* Atom for the scrollbar control wnd class */
+extern HWND hwndSB;
+extern HWND hwndSBNotify;
+extern HWND hwndSBTrack;
+extern int dpxThumb;
+extern int posOld;
+extern int posStart;
+extern int pxBottom;
+extern int pxDownArrow;
+extern int pxLeft;
+extern int pxOld;
+extern int pxRight;
+extern int pxStart;
+extern int pxThumbBottom;
+extern int pxThumbTop;
+extern int pxTop;
+extern int pxUpArrow;
+extern BOOL fHitOld;
+extern int cmdSB;
+extern VOID (*pfnSB)(HWND, WORD, WPARAM, LPARAM);
+extern RECT rcSB;
+extern RECT rcThumb;
+extern RECT rcTrack;
+extern BOOL fTrackVert;
+extern BOOL fCtlSB;
+extern WORD hTimerSB;
+extern BOOL fVertSB;
+extern SBINFO *psbiSB;
+extern SBINFO sbiHorz;
+extern SBINFO sbiVert;
+extern int cmsTimerInterval;
+
+//***** Control globals
+
+extern ATOM atomSysClass[];
+
+//***** Constant strings
+
+extern char szUNTITLED[];
+extern char szERROR[];
+extern char szOK[];
+extern char szCANCEL[];
+extern char szABORT[];
+extern char szRETRY[];
+extern char szIGNORE[];
+extern char szYYES[];
+extern char szCLOSE[];
+extern char szNO[];
+
+extern char szAM[];
+extern char szPM[];
+extern PSTR pTimeTagArray[];
+
+extern char szAttr[];
+extern char szOEMBIN[];
+extern char szDISPLAY[];
+extern char szOneChar[];
+extern char szSLASHSTARDOTSTAR[];
+extern char szYes[];
+extern char szNullString[];
+
+#ifdef DEBUG
+
+extern char CODESEG ErrAssertFailed[];
+extern char CODESEG ErrInvalParam[];
+
+#endif
+
+#ifdef JAPAN
+extern char szJWordBreak[]; // Japanese word breaking char table
+#endif
+
+#ifdef KOREA
+void FAR SetLevel(HWND);
+BOOL FAR RequestHanjaMode(HWND, LPSTR);
+WORD FAR PASCAL TranslateHangeul(WORD);
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* Global Variables from ASM files */
+/* */
+/*--------------------------------------------------------------------------*/
+
+extern BYTE rgbKeyState[];
+extern int iLevelCursor;
+extern WORD rgwSysMet[];
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* INTDS interrupt-accessible globals
+/* */
+/*--------------------------------------------------------------------------*/
+
+extern BOOL INTDSSEG fInt24;
+extern BOOL INTDSSEG fMouseMoved;
+extern BOOL INTDSSEG fEnableInput;
+extern BOOL INTDSSEG fSwapButtons;
+extern BOOL INTDSSEG fQueueDirty;
+extern BOOL INTDSSEG fInScanTimers;
+
+extern BYTE INTDSSEG vKeyDown;
+extern BYTE INTDSSEG TimerTable[];
+extern BYTE INTDSSEG rgbAsyncKeyState[];
+
+extern BYTE* INTDSSEG TimerTableMax;
+
+extern char INTDSSEG szDivZero[];
+extern char INTDSSEG szNull[];
+extern char INTDSSEG szSysError[];
+
+
+extern DWORD INTDSSEG tSysTimer;
+
+#ifdef DOS30
+extern INTDSSEGPROC INTDSSEG lpSysProc;
+#endif
+
+extern HANDLE INTDSSEG hSysTimer;
+
+extern TIMERINFO INTDSSEG timerInfo;
+
+extern WORD __WinFlags;
+#define WinFlags ((WORD)(&__WinFlags))
+
+// Input globals
+
+#ifdef DISABLE
+extern WORD modeInput;
+#endif
+
+extern HQ INTDSSEG hqSysLock; /* HQ of guy who is looking at current event */
+extern WORD INTDSSEG idSysLock; /* Msg ID of event that is locking sys queue */
+extern POINT INTDSSEG ptTrueCursor;
+extern POINT INTDSSEG ptCursor;
+extern RECT INTDSSEG rcCursorClip;
+
+extern WORD INTDSSEG MouseSpeed;
+extern WORD INTDSSEG MouseThresh1;
+extern WORD INTDSSEG MouseThresh2;
+extern WORD INTDSSEG cMsgRsrv;
+extern WORD INTDSSEG x_mickey_rate;
+extern WORD INTDSSEG y_mickey_rate;
+extern WORD INTDSSEG cur_x_mickey;
+extern WORD INTDSSEG cur_y_mickey;
+extern WORD INTDSSEG cxScreenCS;
+extern WORD INTDSSEG cyScreenCS;
+extern WORD INTDSSEG cQEntries;
+extern WORD INTDSSEG dtSysTimer;
+
+extern DWORD INTDSSEG dtJournal;
+extern WORD INTDSSEG msgJournal;
+extern BOOL INTDSSEG fJournalPlayback;
+
+extern WORD INTDSSEG rgMsgUpDowns[];
+extern DWORD INTDSSEG lpMouseStack;
+extern LPVOID INTDSSEG prevSSSP;
+extern BYTE INTDSSEG nestCount;
+
+extern WORD INTDSSEG cHotKeyHooks;
+
+extern HQ INTDSSEG hqActive;
+extern HQ INTDSSEG hqList;
+extern HQ INTDSSEG hqCursor;
+extern HQ INTDSSEG hqSysQueue;
+extern HQ INTDSSEG hqSysModal;
+extern HQ INTDSSEG hqMouse;
+extern HQ INTDSSEG hqKeyboard;
+extern HQ INTDSSEG hqCapture;
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* Assembly Function Declarations */
+/* */
+/*--------------------------------------------------------------------------*/
+
+#ifdef WOWEDIT
+void FAR LCopyStruct(CONST VOID FAR* lpSrc, LPVOID lpDest, WORD cb);
+#else
+/*
+ why is this required? Its here for the intrinsic pragma
+ to recognize memcpy ... jonle on a saturday!
+*/
+#ifndef WOWDBG
+LPVOID memcpy(LPVOID lpDst, LPVOID lpSrc, int cb);
+#endif
+
+#pragma intrinsic(memcpy)
+#define LCopyStruct(s,d,n) memcpy((LPVOID)(d),(LPVOID)(s),(int)(n))
+#endif
+WORD FAR GetAppVer(void);
+
+#ifndef MSDWP
+
+/* Suppport routines for separate segment stuff. */
+#undef min
+#undef max
+#define min(a, b) ((int)(a) < (int)(b) ? (int)(a) : (int)(b))
+#define max(a, b) ((int)(a) > (int)(b) ? (int)(a) : (int)(b))
+#define umin(a, b) ((unsigned)(a) < (unsigned)(b) ? (unsigned)(a) : (unsigned)(b))
+#define umax(a, b) ((unsigned)(a) > (unsigned)(b) ? (unsigned)(a) : (unsigned)(b))
+
+int FAR MultDiv(WORD a, WORD b, WORD c);
+void FAR LFillStruct(LPVOID, WORD, WORD);
+HDC FAR GetClientDc(void);
+HQ FAR HqCurrent(void);
+BOOL FAR ActivateWindow(HWND, WORD);
+
+BOOL CheckHwndFilter(HWND, HWND);
+BOOL CheckMsgFilter(WORD, WORD, WORD);
+BOOL WriteMessage(HQ, LONG, WORD, WORD, HWND, DWORD);
+BOOL ReceiveMessage(VOID);
+VOID FlushSentMessages(VOID);
+LPSTR WINAPI lstrcpyn(LPSTR, LPCSTR, int);
+
+#define PSTextOut(a, b, c, d, e) TextOut(a, b, c, d, e)
+#define PSGetTextExtent(a, b, c) GetTextExtent(a, b, c)
+#define PSFillRect(a, b, c) FillRect(a, b, c)
+#define PSInvertRect(a, b) InvertRect(a, b)
+WORD FAR GetNextSysMsg(WORD, INTERNALSYSMSG FAR *);
+void FAR SkipSysMsg(SYSMSG FAR *, BOOL);
+
+void TransferWakeBit(WORD);
+void ClearWakeBit(WORD, BOOL);
+void SetWakeBit(HQ, WORD);
+void FAR FarSetWakeBit(HQ, WORD);
+void FAR InitSysQueue(void);
+BOOL FAR CreateQueue(int);
+void DeleteQueue(void);
+void SuspendTask(void);
+void ReleaseTask(void);
+
+void FAR GlobalInitAtom(void);
+
+void MoveRect(LONG);
+void SizeRect(LONG);
+
+BOOL FAR SysHasKanji(void);
+
+void FAR SetDivZero(void);
+
+int FAR FindCharPosition(LPCSTR, char);
+
+void FAR OEMSetCursor(LPSTR);
+void FAR SetFMouseMoved(void);
+BOOL AttachDC(HWND);
+BOOL LastApplication(void);
+void CheckCursor(HWND);
+void FAR IncPaintCount(HWND);
+void FAR DecPaintCount(HWND);
+void FAR DeleteProperties(HWND);
+void FAR DestroyTimers(HQ, HWND);
+
+int FAR InquireSystem(int, int);
+int FAR EnableKeyboard(FARPROC, LPSTR);
+int FAR InquireKeyboard(LPSTR);
+void FAR DisableKeyboard(void);
+int FAR EnableMouse(FARPROC);
+int FAR InquireMouse(LPSTR);
+void FAR DisableMouse(void);
+int FAR InquireCursor(LPSTR);
+void FAR EnableSystemTimers(void);
+void FAR DisableSystemTimers(void);
+void FAR CreateSystemTimer(int, TIMERPROC);
+WORD FAR SetSystemTimer(HWND, int, int, TIMERPROC);
+BOOL FAR KillSystemTimer(HWND, int);
+
+void FAR CrunchX2(CURSORSHAPE FAR *, CURSORSHAPE FAR *, int, int);
+void FAR CrunchY(CURSORSHAPE FAR *, CURSORSHAPE FAR *, int, int, int);
+
+void FAR MenuBarDraw(HWND hwnd, HDC hdc, int cxFrame, int cyFrame);
+
+BOOL FAR ReadMessage(HQ, LPMSG, HWND, WORD, WORD, BOOL);
+
+int GetCurrentDrive(void);
+int GetCurrentDirectory(LPSTR, int);
+int SetCurrentDrive(int);
+int SetCurrentDirectory(LPCSTR);
+BOOL FFirst(LPSTR, LPSTR, WORD);
+BOOL FNext(LPSTR, WORD);
+
+FAR DestroyAllWindows(void);
+
+BOOL FAR LockWindowVerChk(HWND);
+
+#ifndef NOFASTFRAME
+void FAR SplitRectangle(LPRECT, LPRECT, int, int); /* WinRect.asm */
+#endif
+
+#endif /* MSDWP */
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* Internal Function Declarations */
+/* */
+/*--------------------------------------------------------------------------*/
+
+#ifndef MSDWP
+
+LRESULT CALLBACK ButtonWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK StaticWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK TitleWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK SwitchWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK DesktopWndProc(HWND hwndIcon, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK MenuWindowProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT FAR EditWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK LBoxCtlWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK ComboBoxCtlWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK SBWndProc(PSB psb, WORD message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK MDIClientWndProc(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+
+void FAR SkipSM2(void);
+HWND FAR GetFirstTab(HWND hwnd);
+CONST BYTE FAR* SkipSz(CONST BYTE FAR *lpsz);
+void FAR DlgSetFocus(HWND hwnd);
+HWND FAR PrevChild(HWND hwndDlg, HWND hwnd);
+HWND FAR NextChild(HWND hwndDlg, HWND hwnd);
+HWND FAR GetFirstLevelChild(HWND hwndDlg, HWND hwndLevel);
+void FAR CheckDefPushButton(HWND hwndDlg, HWND hwndOldFocus, HWND hwndNewFocus);
+HWND FAR GotoNextMnem(HWND hwndDlg, HWND hwndStart, char ch);
+int FAR FindMnemChar(LPSTR lpstr, char ch, BOOL fFirst, BOOL fPrefix);
+int FAR FindNextValidMenuItem(PMENU pMenu, int i, int dir, BOOL fHelp);
+BOOL CALLBACK MenuPrint(HDC hdc, LPARAM lParam, int cch);
+int FAR MenuBarCompute(HMENU hMenu, HWND hwndNotify, int yMenuTop, int xMenuLeft, int cxMax);
+HMENU CALLBACK LookupMenuHandle(HMENU hMenu, WORD cmd);
+BOOL CALLBACK StaticPrint(HDC hdc, LPRECT lprc, HWND hwnd);
+
+HICON FAR ColorToMonoIcon(HICON);
+HGLOBAL CALLBACK LoadCursorIconHandler(HGLOBAL hRes, HINSTANCE hResFile, HRSRC hResIndex);
+HGLOBAL CALLBACK LoadDIBCursorHandler(HGLOBAL hRes, HINSTANCE hResFile, HRSRC hResIndex);
+HGLOBAL CALLBACK LoadDIBIconHandler(HGLOBAL hRes, HINSTANCE hResFile, HRSRC hResIndex);
+void CallOEMCursor(void);
+void FAR DestroyClipBoardData(void);
+BOOL FAR SendClipboardMessage(int message);
+void FAR DrawClipboard(void);
+PCLIP FAR FindClipFormat(WORD format);
+BOOL IsDummyTextHandle(PCLIP pClip);
+HANDLE InternalSetClipboardData(WORD format, HANDLE hData);
+
+PPCLS FAR GetClassPtr(LPCSTR lpszClassName, HINSTANCE hInstance, BOOL fUserModule);
+PPCLS GetClassPtrASM(ATOM, HMODULE, BOOL);
+void FAR DelWinClass(PPCLS ppcls);
+
+VOID CALLBACK CaretBlinkProc(HWND hwnd, WORD message, WORD id, DWORD time);
+void FAR InternalHideCaret(void);
+void FAR InternalShowCaret(void);
+void FAR InternalDestroyCaret(void);
+HDC FAR GetScreenDC(void);
+PBWL FAR BuildHwndList(HWND hwnd, int flags);
+void FAR FreeHwndList(PBWL pbwl);
+void CALLBACK DrawFrame(HDC hdc, LPRECT lprect, int clFrame, int cmd);
+void FAR RedrawFrame(HWND hwnd);
+void FAR BltColor(HDC, HBRUSH, HDC, int, int, int, int, int, int, BOOL);
+void FAR EnableInput(void);
+void FAR DisableInput(void);
+void FAR CopyKeyState(void);
+void CALLBACK EnableOEMLayer(void);
+void CALLBACK DisableOEMLayer(void);
+void FAR ColorInit(void);
+BOOL FAR SetKeyboardSpeed(BOOL fInquire);
+void FAR InitBorderSysMetrics(void);
+void FAR InitSizeBorderDimensions(void);
+void FAR SetMinMaxInfo(void);
+
+// Returns TRUE if a GetDC() will return an empty visrgn or not
+// (doesn't take into account being clipped away; just checks WFVISIBE
+// and WFMINIMIZED)
+//
+BOOL FAR IsVisible(HWND hwnd, BOOL fClient);
+
+// Returns TRUE if hwndChild == hwndParent or is one of its children.
+//
+BOOL FAR IsDescendant(HWND hwndParent, HWND hwndChild);
+
+void FAR SetRedraw(HWND hwnd, BOOL fRedraw);
+HBRUSH CALLBACK GetControlColor(HWND hwndParent, HWND hwndCtl, HDC hdc, WORD type);
+HBRUSH CALLBACK GetControlBrush(HWND hwnd, HDC hdc, WORD type);
+void FAR StoreMessage(LPMSG lpMsg, HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam, DWORD time);
+LONG FAR GetPrefixCount(LPCSTR lpstr, int cch, LPSTR lpstrCopy, int copycount);
+void FAR PSMTextOut(HDC hdc, int xLeft, int yTop, LPCSTR lpsz, int cch);
+DWORD FAR PSMGetTextExtent(HDC hdc, LPCSTR lpstr, int cch);
+HWND FAR GetTopLevelTiled(HWND hwnd);
+BOOL FAR TrueIconic(HWND hwnd);
+void FAR ChangeToCurrentTask(HWND hwnd1, HWND hwnd2);
+
+HWND FAR GetLastTopMostWindow(void);
+void FAR SendSizeMessage(HWND hwnd, WORD cmdSize);
+HWND FAR NextTopWindow(HWND hwnd, HWND hwndSkip, BOOL fPrev, BOOL fDisabled);
+
+void FAR DisableVKD(BOOL fDisable);
+void FAR CheckFocus(HWND hwnd);
+BOOL CALLBACK FChildVisible(HWND hwnd);
+#define InternalGetClientRect(hwnd, lprc) CopyRect(lprc, &hwnd->rcClient)
+void FAR CheckByteAlign(HWND hwnd, LPRECT lprc);
+void FAR CancelMode(HWND hwnd);
+void FAR RedrawIconTitle(HWND hwnd);
+void FAR DisplayIconicWindow(HWND hwnd, BOOL fActivate, BOOL fShow);
+DWORD FAR GetIconTitleSize(HWND hwnd);
+BOOL FAR SendZoom(HWND hwnd, LPARAM lParam);
+BOOL CALLBACK DestroyTaskWindowsEnum(HWND hwnd, LPARAM lParam);
+void CALLBACK LockMyTask(BOOL fLock);
+void CALLBACK RepaintScreen(void);
+HANDLE FAR BcastCopyString(LPARAM lParam);
+BOOL CALLBACK SignalProc(HTASK hTask, WORD message, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK NewSignalProc(HTASK hTask, WORD message, WPARAM wParam, LPARAM lParam);
+HWND FAR GetWindowCreator(HWND hwnd);
+
+void FAR InitSendValidateMinMaxInfo(HWND hwnd);
+void FAR DrawDragRect(LPRECT lprc, WORD flags);
+void FAR MoveSize(HWND hwnd, WORD cmdMove);
+BYTE FAR SetClrWindowFlag(HWND hwnd, WORD style, BYTE cmd);
+void FAR ParkIcon(HWND hwnd, CHECKPOINT * pcp);
+void FAR ShowOwnedWindows(HWND hwndOwner, WORD cmdShow);
+HWND FAR MinMaximize(HWND hwnd, WORD cmd, BOOL fKeepHidden);
+void FAR SetTiledRect(HWND hwnd, LPRECT lprc);
+#endif // MSDWP
+void FAR AdjustSize(HWND hwnd, LPINT lpcx, LPINT lpcy);
+#ifndef MSDWP
+
+void FAR NextWindow(WORD flags);
+void FAR DoScroll(HWND hwnd, HWND hwndNotify, int cmd, int pos, BOOL fVert);
+void CALLBACK ContScroll(HWND hwnd, WORD message, WORD id, DWORD time);
+void FAR MoveThumb(HWND hwnd, int px, BOOL fCancel);
+void FAR SBTrackInit(HWND hwnd, LPARAM lParam, int curArea);
+void FAR DrawSize(HWND hwnd, HDC hdc, int cxFrame, int cyFrame, BOOL fBorder);
+void FAR CalcSBStuff(HWND hwnd, BOOL fVert);
+WORD GetWndSBDisableFlags(HWND, BOOL);
+void FreeWindow(HWND hwnd);
+void FAR DestroyTaskWindows(HQ hq);
+BOOL FAR TrackInitSize(HWND hwnd, WORD message, WPARAM wParam, LPARAM lParam);
+void FAR DrawPushButton(HDC hdc, LPRECT lprc, WORD style, BOOL fInvert, HBRUSH hbrBtn, HWND hwnd);
+void FAR DrawBtnText(HDC hdc, HWND hwnd, BOOL dbt, BOOL fDepress);
+void FAR Capture(HWND hwnd, int code);
+int FAR SystoChar(WORD message, LPARAM lParam);
+void FAR LinkWindow(HWND, HWND, HWND *);
+void FAR UnlinkWindow(HWND, HWND *);
+void FAR DrawScrollBar(HWND hwnd, HDC hdc, BOOL fVert);
+void CALLBACK PaintRect(HWND hwndBrush, HWND hwndPaint, HDC hdc, HBRUSH hbr, LPRECT lprc);
+
+BOOL FAR SetDeskPattern(LPSTR);
+BOOL FAR SetDeskWallpaper(LPSTR);
+void FAR SetGridGranularity(WORD);
+
+int FAR GetAveCharWidth(HDC);
+#ifndef NOTEXTMETRIC
+int FAR GetCharDimensions(HDC, TEXTMETRIC FAR *);
+#endif
+
+BOOL FAR LW_ReloadLangDriver(LPSTR);
+HBRUSH FAR GetSysClrObject(int);
+int API SysErrorBox(LPCSTR lpszText, LPCSTR lpszCaption, unsigned int btn1, unsigned int btn2, unsigned int btn3);
+BOOL FAR SnapWindow(HWND hwnd);
+WORD FAR MB_FindLongestString(void);
+#ifdef FASTFRAME
+HBITMAP FAR CreateCaptionBitmaps(void);
+HBITMAP FAR CreateBorderVertBitmaps(BOOL fDlgFrame);
+HBITMAP FAR CreateBorderHorzBitmaps(BOOL fDlgFrame);
+void FAR GetCaptionBitmapsInfo(FRAMEBITMAP Caption[], HBITMAP hBitmap);
+void FAR GetHorzBitmapsInfo(FRAMEBITMAP Bitmap[], BOOL fDlgFrame, HBITMAP hBitmap);
+void FAR GetVertBitmapsInfo(FRAMEBITMAP Bitmap[], BOOL fDlgFrame, HBITMAP hBitmap);
+BOOL FAR DrawIntoCaptionBitmaps(HDC hdc,HBITMAP hBitmap, FRAMEBITMAP FrameInfo[], BOOL fActive);
+BOOL FAR DrawIntoHorzBitmaps(HDC hdc, HBITMAP hBitmap, FRAMEBITMAP FrameInfoH[], BOOL fActive, BOOL fDlgFrame);
+BOOL FAR DrawIntoVertBitmaps(HDC hdc, HBITMAP hBitmap, FRAMEBITMAP FrameInfoH[], FRAMEBITMAP FrameInfoV[], BOOL fActive, BOOL fDlgFrame);
+BOOL FAR RecreateFrameBitmaps(void);
+void FAR DeleteFrameBitmaps(int, int);
+BOOL FAR PASCAL UpdateFrameBitmaps(WORD wColorFlags);
+BOOL FAR PASCAL RecolorFrameBitmaps(WORD wColorFlags);
+#endif /* FASTFRAME */
+
+void PostButtonUp(WORD msg);
+
+#endif /* MSDWP */
+
+
+void CALLBACK EndMenu(void);
+void CALLBACK FillWindow(HWND hwndBrush, HWND hwndPaint, HDC hdc, HBRUSH hbr);
+void FAR SysCommand(HWND hwnd, int cmd, LPARAM lParam);
+void FAR HandleNCMouseGuys(HWND hwnd, WORD message, int htArea, LPARAM lParam);
+void FAR EndScroll(HWND hwnd, BOOL fCancel);
+HWND FAR GetTopLevelWindow(HWND hwnd);
+void FAR RedrawIconTitle(HWND hwnd);
+int FAR FindNCHit(HWND hwnd, LONG lPt);
+void FAR CalcClientRect(HWND hwnd, LPRECT lprc);
+BOOL FAR DepressTitleButton(HWND hwnd, RECT rcCapt, RECT rcInvert, WORD hit);
+void FAR SetSysMenu(HWND hwnd);
+HMENU FAR GetSysMenuHandle(HWND hwnd);
+int *FAR InitPwSB(HWND hwnd);
+BOOL FAR DefSetText(HWND hwnd, LPCSTR lpsz);
+void FAR DrawWindowFrame(HWND hwnd, HRGN hrgnClip);
+void FAR ShowIconTitle(HWND hwnd, BOOL fShow);
+HBRUSH FAR GetBackBrush(HWND hwnd);
+BOOL FAR IsSystemFont(HDC);
+BOOL FAR IsSysFontAndDefaultMode(HDC);
+VOID FAR DiagOutput(LPCSTR);
+VOID FAR UserDiagOutput(int, LPCSTR);
+#define UDO_INIT 0
+#define UDO_INITDONE 1
+#define UDO_STATUS 2
+
+
+HANDLE FAR TextAlloc(LPCSTR);
+HANDLE FAR TextFree(HANDLE);
+WORD FAR TextCopy(HANDLE, LPSTR, WORD);
+#define TextPointer(h) (LPSTR)MAKELP(hWinAtom, h)
+
+BOOL CALLBACK FARValidatePointer(LPVOID);
+
+// GDI exports
+#ifdef DEBUG
+VOID CALLBACK SetObjectOwner(HGDIOBJ, HINSTANCE);
+#else
+#define SetObjectOwner(d1, d2)
+#endif
+BOOL CALLBACK MakeObjectPrivate(HGDIOBJ, BOOL);
+VOID CALLBACK GDITaskTermination(HTASK);
+VOID CALLBACK RealizeDefaultPalette(HDC);
+
+// Internal functions called directly by debug version to
+// prevent validation errors
+//
+#ifdef DEBUG
+HDC API IGetDCEx(register HWND hwnd, HRGN hrgnClip, DWORD flags);
+BOOL API IGrayString(HDC, HBRUSH, GRAYSTRINGPROC, LPARAM, int, int, int, int, int);
+BOOL API IRedrawWindow(HWND hwnd, CONST RECT FAR* lprcUpdate, HRGN hrgnUpdate, WORD flags);
+int API IScrollWindowEx(HWND hwnd, int dx, int dy,
+ CONST RECT FAR* prcScroll, CONST RECT FAR* prcClip,
+ HRGN hrgnUpdate, RECT FAR* prcUpdate, WORD flags);
+#endif
+
+#ifdef DBCS_IME
+#define WM_IMECONTROL WM_USER
+void FAR InitIME(void); // wmcaret.c
+BOOL _loadds FAR EnableIME( HWND, BOOL ); // wmcaret.c
+VOID API SetImeBoundingRect(HWND, DWORD, LPRECT); // wmcaret.c
+BOOL API ControlIME(HWND, BOOL); // wmcaret.c
+HANDLE API SetFontForIME(HWND, HANDLE); // wmcaret.c
+VOID API ControlCaretIme(BOOL); // wmcaret.c
+BOOL API EatString(HWND, LPSTR, WORD); // editec.c
+VOID API CheckKatanaInstalled(HWND); // wmcaret.c
+#endif
+
+#ifdef JAPAN
+// Save time of WM_LBUTTONDOWN and WM_LBUTTONUP, used to decided
+// whether to lock large popup menus that cover the static portion
+// of the menu...
+extern int fLongPMenu;
+extern DWORD lbuttondown_time;
+#endif
+
+/****************************************************************************
+
+ debugging support
+
+****************************************************************************/
+
+#ifdef DEBUG
+
+ extern void cdecl dDbgOut(int iLevel, LPSTR lpszFormat, ...);
+ extern void cdecl dDbgAssert(LPSTR exp, LPSTR file, int line);
+
+ DWORD __dwEval;
+
+ #define dprintf dDbgOut
+
+ #define WinAssert(exp) \
+ ((exp) ? (void)0 : dDbgAssert(#exp, __FILE__, __LINE__))
+ #define WinEval(exp) \
+ ((__dwEval=(DWORD)(LPVOID)(exp)) ? (void)0 : dDbgAssert(#exp, __FILE__, __LINE__), __dwEval)
+
+#else
+
+ #define dprintf /##/
+// #define dprintf if (0) ((int (*)(char *, ...)) 0)
+
+ #define WinAssert(exp) 0
+ #define WinEval(exp) (exp)
+
+#endif
diff --git a/private/mvdm/wow16/user/user.inc b/private/mvdm/wow16/user/user.inc
new file mode 100644
index 000000000..d3cb4ed94
--- /dev/null
+++ b/private/mvdm/wow16/user/user.inc
@@ -0,0 +1,1987 @@
+;****************************************************************************
+;* *
+;* USER.INC - *
+;* *
+;* User Data Structures and Defines *
+;* *
+;****************************************************************************
+;
+; Conditional include #defines:
+;
+; LAYER_INCLUDE - Just define POINT, RECT, WND, and CLS structs, plus ICLS_*
+; NOTEXT - Blow off TEXTMETRICS and some other stuff
+;
+
+ifdef WOW
+NOTEXT equ 1
+endif
+
+.286P
+
+ifndef LAYER_INCLUDE
+
+?DF=1 ; Don't define _TEXT or _DATA
+?WIN=0 ; turn off Windows support (no default preserve DS in far calls)
+include cmacros.inc
+include vint.inc
+
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+;createSeg _TEXT,TEXT,WORD,PUBLIC,CODE,IGROUP
+
+createSeg _GPFIX0,GPFIX0,WORD,PUBLIC,CODE,IGROUP ; GP fault trapping
+createSeg _GPFIX, GPFIX, WORD,PUBLIC,CODE,IGROUP
+createSeg _GPFIX1,GPFIX1,WORD,PUBLIC,CODE,IGROUP
+
+;defGrp IGROUP,TEXT
+
+endif
+
+
+
+
+include gpfix.inc ; GP fault handler stuff
+
+VER20 equ 0201h
+VER300 equ 0300h
+VER310 equ 0310h
+
+FALSE equ 0
+TRUE equ 1
+NULL equ 0
+
+; Debug fill constants
+
+DBGFILL_ALLOC equ 0fdh
+DBGFILL_FREE equ 0fbh
+DBGFILL_BUFFER equ 0f9h
+DBGFILL_STACK equ 0f7h
+
+;*--------------------------------------------------------------------------*
+;* *
+;* Window and internal class structures
+;* *
+;*--------------------------------------------------------------------------*
+
+;
+; POINT Structure
+;
+POINT struc
+ ptX dw ?
+ ptY dw ?
+POINT ends
+
+;
+; RECT Structure
+;
+RECT struc
+ rcLeft dw ?
+ rcTop dw ?
+ rcRight dw ?
+ rcBottom dw ?
+RECT ends
+
+ifdef WOW
+;
+; RECTL Structure
+;
+RECTL struc
+ rclLeft dd ?
+ rclTop dd ?
+ rclRight dd ?
+ rclBottom dd ?
+RECTL ends
+endif
+
+ifndef WOW
+ifdef WORDEXSTYLE
+WND struc
+ wndHwndNext dw ?
+ wndHwndChild dw ?
+ wndPwndParent dw ?
+ wndHwndOwner dw ?
+ wndRcWindow db size RECT dup(?)
+ wndRcClient db size RECT dup(?)
+ wndHq dw ?
+ wndHRgnUpdate dw ?
+ wndPcls dw ?
+ wndHInstance dw ?
+ wndLpfnWndProc dd ?
+ wndState dd ?
+ wndStyle dd ?
+ wndDwExStyle dw ?
+ wndHMenu dw ?
+ wndHName dw ?
+ wndRgwScroll dw ?
+ wndPproptab dw ?
+ wndHwndLastActive dw ?
+ wndHSysMenu dw ?
+WND ends
+
+else
+
+WND struc
+ wndHwndNext dw ?
+ wndHwndChild dw ?
+ wndPwndParent dw ?
+ wndHwndOwner dw ?
+ wndRcWindow db size RECT dup(?)
+ wndRcClient db size RECT dup(?)
+ wndHq dw ?
+ wndHRgnUpdate dw ?
+ wndPcls dw ?
+ wndHInstance dw ?
+ wndLpfnWndProc dd ?
+ wndState dd ?
+ wndStyle dd ?
+ wndDwExStyle dd ?
+ wndHMenu dw ?
+ wndHName dw ?
+ wndRgwScroll dw ?
+ wndPproptab dw ?
+ wndHwndLastActive dw ?
+ wndHSysMenu dw ?
+WND ends
+
+endif ; WORDEXSTYLE
+
+
+;
+; Internal window class structure
+;
+CLS struc
+ uclspclsNext dw ?
+ uclsMagic dw ?
+ uclsatomClassName dw ?
+ uclshdc dw ?
+ uclscWndReferenceCount dw ? ; Number of windows registered with this
+ ; Class
+
+; NOTE: the remaining fields are in the same order as in the WNDCLASS struct
+
+ uclsstyle dw ? ; Class style
+ uclslpfnWndProc dd ?
+ uclscbclsExtra dw ?
+ uclscbwndExtra dw ?
+ uclshModule dw ? ; Module handle
+ uclshIcon dw ? ; Class icon handle
+ uclshCursor dw ? ; Class cursor handle
+ uclshbrBackground dw ? ; Class background brush
+ uclslpszMenuName dd ? ; Menu name
+ uclslpszClassName dd ? ; Far ptr to class name
+CLS ends
+
+CLS_MAGIC equ ('N' or ('K' * 256))
+
+; System class ID constants
+;
+; See comments in USER.H
+;
+ICLS_BUTTON equ 0
+ICLS_EDIT equ 1
+ICLS_STATIC equ 2
+ICLS_LISTBOX equ 3
+ICLS_SCROLLBAR equ 4
+ICLS_COMBOBOX equ 5 ; End of special dlgmgr indices
+
+ICLS_CTL_MAX equ 6 ; Number of public control classes
+
+ICLS_DESKTOP equ 6
+ICLS_DIALOG equ 7
+ICLS_MENU equ 8
+ICLS_SWITCH equ 9
+ICLS_ICONTITLE equ 10
+ICLS_MDICLIENT equ 11
+ICLS_COMBOLISTBOX equ 12
+
+ICLS_MAX equ 13 ; Number of system classes
+endif ; !WOW
+
+;
+; SetWindowPos() SMWP structure header
+;
+SMWP struc
+ SmwpCcvr dw ?
+ SmwpCcvrAlloc dw ?
+ SmwpFInUse dw ?
+ SmwpSignature dw ?
+; SmwpRgcvr db 1
+SMWP ends
+
+SMWP_SIG equ ('W' or ('P' * 256))
+
+ifndef LAYER_INCLUDE ; If not included from layer.asm...
+
+;
+; Substitute API names with "I" internal names if RETAIL
+;
+ifndef DEBUG
+include iuser.inc
+endif
+
+ifndef WOW
+; Internal window class names
+;
+MENUCLASS equ 8000h
+DESKTOPCLASS equ 8001h
+DIALOGCLASS equ 8002h
+SWITCHWNDCLASS equ 8003h
+ICONTITLECLASS equ 8004h
+
+;
+; Window flag Test, Set, and Clear macros
+;
+TSTWF macro pwnd, flag
+ LOCAL wlow, whigh
+ wlow = LOW flag
+ whigh = HIGH flag
+ test byte ptr [pwnd+wndState+whigh], wlow
+ endm
+
+SETWF macro pwnd, flag
+ LOCAL wlow, whigh
+ wlow = LOW flag
+ whigh = HIGH flag
+ or byte ptr [pwnd+wndState+whigh], wlow
+ endm
+
+CLRWF macro pwnd, flag
+ LOCAL nwlow, whigh
+ nwlow = NOT(LOW flag)
+ whigh = HIGH flag
+ and byte ptr [pwnd+wndState+whigh], nwlow
+ endm
+
+;
+; Window Flags
+;
+; hwnd->state flags (offset 0, 1, 2, 3)
+;
+WFMPRESENT equ 0001h
+WFVPRESENT equ 0002h
+WFHPRESENT equ 0004h
+WFCPRESENT equ 0008h
+WFSENDSIZEMOVE equ 0010h
+WFNOPAINT equ 0020h
+WFFRAMEON equ 0040h
+WFHASSPB equ 0080h
+WFNONCPAINT equ 0101h
+WFSENDERASEBKGND equ 0102h
+WFERASEBKGND equ 0104h
+WFSENDNCPAINT equ 0108h
+WFINTERNALPAINT equ 0110h ; Internal paint required flag
+WFUPDATEDIRTY equ 0120h
+WFHIDDENPOPUP equ 0140h
+WFMENUDRAW equ 0180h
+
+WFHASPALETTE equ 0201h
+WFPAINTNOTPROCESSED equ 0202h
+WFWIN31COMPAT equ 0204h
+WFALWAYSSENDNCPAINT equ 0208h
+WFPIXIEHACK equ 0210h
+WFTOGGLETOPMOST equ 0220h
+;
+; hwnd->style style bits (offsets 4, 5, 6, 7)
+;
+WFTYPEMASK equ 07C0h
+WFTILED equ 0700h
+WFICONICPOPUP equ 07C0h
+WFPOPUP equ 0780h
+WFCHILD equ 0740h
+WFMINIMIZED equ 0720h
+WFVISIBLE equ 0710h
+WFDISABLED equ 0708h
+WFDISABLE equ WFDISABLED
+WFCLIPSIBLINGS equ 0704h
+WFCLIPCHILDREN equ 0702h
+WFMAXIMIZED equ 0701h
+WFICONIC equ WFMINIMIZED
+
+WFMINBOX equ 0602h
+WFMAXBOX equ 0601h
+
+WFBORDERMASK equ 06C0h
+WFBORDER equ 0680h
+WFCAPTION equ 06C0h
+WFDLGFRAME equ 0640h
+WFTOPLEVEL equ 0640h
+
+WFVSCROLL equ 0620h
+WFHSCROLL equ 0610h
+WFSYSMENU equ 0608h
+WFSIZEBOX equ 0604h
+WFGROUP equ 0602h
+WFTABSTOP equ 0601h
+
+; If this dlg bit is set, WM_ENTERIDLE message will not be sent
+WFNOIDLEMSG equ 0501h
+;
+; hwnd->dwExStyle extended style bits (offsets 8, 9)
+;
+WEFDLGMODALFRAME equ 0801h
+WEFDRAGOBJECT equ 0802h
+WEFNOPARENTNOTIFY equ 0804h
+WEFTOPMOST equ 0808h
+WEFACCEPTFILES equ 0810h
+WEFTRANSPARENT equ 0820h ; "Transparent" child window
+
+; Class styles
+;
+CFVREDRAW equ 0001h
+CFHREDRAW equ 0002h
+CFKANJIWINDOW equ 0004h
+CFDBLCLKS equ 0008h
+CFOEMCHARS equ 0010h
+CFOWNDC equ 0020h
+CFCLASSDC equ 0040h
+CFPARENTDC equ 0080h
+CFNOKEYCVT equ 0101h
+CFNOCLOSE equ 0102h
+CFLVB equ 0104h
+CFCLSDC equ CFCLASSDC
+CFSAVEBITS equ 0108h
+CFSAVEPOPUPBITS equ CFSAVEBITS
+CFBYTEALIGNCLIENT equ 0110h
+CFBYTEALIGNWINDOW equ 0120h
+
+ST_CLASS equ 1
+ST_WND equ 2
+ST_STRING equ 3
+ST_MENU equ 4
+ST_CLIP equ 5
+ST_CBOX equ 6
+ST_PALETTE equ 7
+ST_ED equ 8
+ST_BWL equ 9
+ST_OWNERDRAWMENU equ 10
+ST_SPB equ 11
+ST_CHECKPOINT equ 12
+ST_DCE equ 13
+ST_MWP equ 14
+ST_PROP equ 15
+ST_LBIV equ 16
+ST_MISC equ 17
+ST_ATOMS equ 18
+ST_LOCKINPUTSTATE equ 19
+ST_HOOKNODE equ 20
+ST_USERSEEUSERDOALLOC equ 21
+ST_HOTKEYLIST equ 22
+ST_POPUPMENU equ 23
+ST_HANDLETABLE equ 32
+ST_FREE equ 0ffh
+endif ; !WOW
+
+ifdef DEBUG
+ifndef winmisc1
+LocalAlloc equ <UserLocalAlloc>
+LocalFree equ <UserLocalFree>
+LocalLock equ <UserLocalLock>
+LocalUnlock equ <UserLocalUnlock>
+LocalReAlloc equ <UserLocalReAlloc>
+LocalSize equ <UserLocalSize>
+
+TAGSIZE equ 4 ; Size of a tag in debug USER
+endif
+endif
+
+; The following is required to special-case the SetWindowWord(., GCW_HMODULE);
+GCW_HMODULE = (-16)
+
+; Conditional Block includes: (True states)
+; NOTEXT - don't include TextMetric struc & text drawing modes & stock objs.
+
+ifndef NOTEXT
+;
+; TEXTMETRIC Structure
+;
+TEXTMETRIC struc
+ tmHeight dw ?
+ tmAscent dw ?
+ tmDescent dw ?
+ tmInternalLeading dw ?
+ tmExternalLeading dw ?
+ tmAveCharWidth dw ?
+ tmMaxCharWidth dw ?
+ tmWeight dw ?
+ tmItalic db ?
+ tmUnderlined db ?
+ tmStruckOut db ?
+ tmFirstChar db ?
+ tmLastChar db ?
+ tmDefaultChar db ?
+ tmBreakChar db ?
+ tmPitch db ?
+ tmOverhang dw ?
+ tmDigitizedAspectX dw ?
+ tmDigitizedAspectY dw ?
+ tmCharSet db ?
+TEXTMETRIC ends
+
+;
+; Text Drawing modes
+;
+TRANSPARENT equ 1
+OPAQUE equ 2
+
+;
+; Stock Logical Objects
+;
+WHITE_BRUSH equ 0
+LTGRAY_BRUSH equ 1
+GRAY_BRUSH equ 2
+DKGRAY_BRUSH equ 3
+BLACK_BRUSH equ 4
+HOLLOW_BRUSH equ 5
+WHITE_PEN equ 6
+BLACK_PEN equ 7
+NULL_PEN equ 8
+DOT_MARKER equ 9
+OEM_FIXED_FONT equ 10
+ANSI_FIXED_FONT equ 11
+ANSI_VAR_FONT equ 12
+
+endif ; NOTEXT
+
+
+ANSI_CHARSET equ 0
+OEM_CHARSET equ 255
+
+ifndef WOW
+;
+; Styles for CombineRgn
+;
+RGN_AND equ 1
+RGN_OR equ 2
+RGN_XOR equ 3
+RGN_DIFF equ 4
+RGN_COPY equ 5
+
+;
+; Predefined cursor & icon IDs
+;
+IDC_ARROW equ 1
+IDC_IBEAM equ 2
+IDC_WAIT equ 3
+IDC_UPARROW equ 8
+IDC_SIZE equ 9
+IDC_ICON equ 10
+
+IDI_APPLICATION equ 1
+IDI_NOTE equ 2
+IDI_ERROR equ 3
+endif ; !WOW
+
+;
+; Memory manager flags
+;
+LMEM_FIXED equ 0000h
+LMEM_MOVEABLE equ 0002h
+LMEM_ZEROINIT equ 0040h
+LMEM_DISCARDABLE equ 0F00h
+LHND equ LMEM_MOVEABLE+LMEM_ZEROINIT
+LPTR equ LMEM_FIXED+LMEM_ZEROINIT
+
+GMEM_FIXED equ 0000h
+GMEM_MOVEABLE equ 0002h
+GMEM_ZEROINIT equ 0040h
+GMEM_SHAREALL equ 2000h
+GMEM_LOWER equ 1000h
+GMEM_DISCARDABLE equ 0F00h
+GHND equ GMEM_MOVEABLE+GMEM_ZEROINIT
+GPTR equ GMEM_FIXED+GMEM_ZEROINIT
+
+
+ifndef WOW
+;*--------------------------------------------------------------------------*
+;* *
+;* Miscellaneous structures & constants *
+;* *
+;*--------------------------------------------------------------------------*
+
+BITMAP struc
+ bmType dw ?
+ bmWidth dw ?
+ bmHeight dw ?
+ bmWidthBytes dw ?
+ bmPlanes db ?
+ bmBitsPixel db ?
+ bmBits dq ?
+BITMAP ends
+
+PAINTSTRUCT struc
+ PShdc dw ?
+ PSfErase dw ?
+ PSrcPaint db size RECT dup(?)
+ PSfRestore dw ?
+ PSfIncUpdate dw ?
+ PSrgbReserved db 16 dup(?)
+PAINTSTRUCT ends
+
+;
+; Message structure
+;
+MSGSTRUCT struc
+ msHWND dw ?
+ msMESSAGE dw ?
+ msWPARAM dw ?
+ msLPARAM dd ?
+ msTIME dd ?
+ msPT dd ?
+MSGSTRUCT ends
+
+NEWPARMS struc
+ nprmHwnd dw ?
+ nprmCmd db ?
+NEWPARMS ends
+
+;
+; CreateStruct structure
+;
+; Note: This is used in WinUtil.ASM
+; Modify this definition when this struct is modified in WINDOWS.H
+;
+
+CREATESTRUCT struc
+ csLPCreateParams dd ?
+ csHInstance dw ?
+ csHMenu dw ?
+ csHwndParent dw ?
+ csCY dw ?
+ csCX dw ?
+ csY dw ?
+ csX dw ?
+ csStyle dd ?
+ csLPszName dd ?
+ csLPszClass dd ?
+ csExStyle dd ?
+CREATESTRUCT ends
+
+;
+; ShowWindow commands
+;
+HIDE_WINDOW equ 0
+SHOW_OPENWINDOW equ 1
+SHOW_ICONWINDOW equ 2
+
+;
+; PostError constants
+;
+WARNING equ 0 ; command codes
+MINOR_ERROR equ 1
+FATAL_ERROR equ 2
+
+IGNORE equ 0 ; response codes
+RETRY equ 1
+ABORT equ 2
+
+;
+; GDI-related constants & commands
+;
+ERRORREGION equ 0
+NULLREGION equ 1
+SIMPLEREGION equ 2
+COMPLEXREGION equ 3
+
+;
+; StretchBlt modes
+;
+BLACKONWHITE equ 1
+WHITEONBLACK equ 2
+COLORONCOLOR equ 3
+
+;
+; PolyFill modes
+;
+ALTERNATE equ 1
+WINDING equ 2
+
+;
+; Size message commands
+;
+SIZENORMAL equ 0
+SIZEICONIC equ 1
+SIZEFULLSCREEN equ 2
+
+;
+; Key state masks for mouse messages
+;
+MK_LBUTTON equ 0001h
+MK_RBUTTON equ 0002h
+MK_SHIFT equ 0004h
+MK_ALTERNATE equ 0008h
+MK_CONTROL equ 0010h
+
+;
+; Predefined clipboard formats
+;
+CF_TEXT equ 1
+CF_BITMAP equ 2
+CF_METAFILEPICT equ 3
+CF_SYLK equ 4
+CF_DIF equ 5
+CF_TIFF equ 6
+CF_OEMTEXT equ 7
+CF_DIB equ 8
+CF_PALETTE equ 9
+CF_PENDATA equ 10
+
+CF_OWNERDISPLAY equ 80h ; owner display
+CF_DSPTEXT equ 81h ; display text
+CF_DSPBITMAP equ 82h ; display bitmap
+CF_DSPMETAFILE equ 83h ; display metafile
+
+;
+; Private clipboard format range
+;
+CF_PRIVATEFIRST equ 200h ; Anything in this range doesn't
+CF_PRIVATELAST equ 2FFh ; get GlobalFree'd
+CF_GDIOBJFIRST equ 300h ; Anything in this range gets
+CF_GDIOBJLAST equ 3FFh ; DeleteObject'ed
+
+MAKEINTRESOURCE macro a
+ mov ax,a
+ cwd
+ endm
+
+;
+; Predefined resource types
+;
+RT_CURSOR equ 1 ; must be passed through MAKEINTRESOURCE
+RT_BITMAP equ 2
+RT_ICON equ 3
+RT_MENU equ 4
+RT_DIALOG equ 5
+RT_STRING equ 6
+RT_FONTDIR equ 7
+RT_FONT equ 8
+
+;
+; Virtual Key definitions
+;
+VK_MOUSE equ 00H
+VK_LBUTTON equ 01h
+VK_RBUTTON equ 02h
+VK_CANCEL equ 03h
+VK_MBUTTON equ 04h
+VK_BACK equ 08h
+VK_TAB equ 09h
+VK_CLEAR equ 0Ch
+VK_RETURN equ 0Dh
+VK_SHIFT equ 10h
+VK_CONTROL equ 11h
+VK_MENU equ 12h
+VK_PAUSE equ 13h
+VK_CAPITAL equ 14h
+VK_ESCAPE equ 1Bh
+VK_SPACE equ 20h
+VK_PRIOR equ 21h
+VK_NEXT equ 22h
+VK_END equ 23h
+VK_HOME equ 24h
+VK_LEFT equ 25h
+VK_UP equ 26h
+VK_RIGHT equ 27h
+VK_DOWN equ 28h
+VK_SELECT equ 29h
+VK_PRINT equ 2Ah
+VK_EXECUTE equ 2Bh
+VK_SNAPSHOT equ 2Ch
+VK_INSERT equ 2Dh
+VK_DELETE equ 2Eh
+VK_HELP equ 2Fh
+VK_NUMPAD0 equ 60h
+VK_NUMPAD1 equ 61h
+VK_NUMPAD2 equ 62h
+VK_NUMPAD3 equ 63h
+VK_NUMPAD4 equ 64h
+VK_NUMPAD5 equ 65h
+VK_NUMPAD6 equ 66h
+VK_NUMPAD7 equ 67h
+VK_NUMPAD8 equ 68h
+VK_NUMPAD9 equ 69h
+VK_MULTIPLY equ 6Ah
+VK_ADD equ 6Bh
+VK_SEPARATOR equ 6Ch
+VK_SUBTRACT equ 6Dh
+VK_DECIMAL equ 6Eh
+VK_DIVIDE equ 6Fh
+VK_F1 equ 70h
+VK_F2 equ 71h
+VK_F3 equ 72h
+VK_F4 equ 73h
+VK_F5 equ 74h
+VK_F6 equ 75h
+VK_F7 equ 76h
+VK_F8 equ 77h
+VK_F9 equ 78h
+VK_F10 equ 79h
+VK_F11 equ 7Ah
+VK_F12 equ 7Bh
+VK_F13 equ 7Ch
+VK_F14 equ 7Dh
+VK_F15 equ 7Eh
+VK_F16 equ 7Fh
+
+;
+; Menu flags for Change/Check/Enable MenuItem
+;
+MF_CHANGE equ 0080h
+MF_INSERT equ 0000h
+MF_APPEND equ 0100h
+MF_DELETE equ 0200h
+MF_BYPOSITION equ 0400h
+MF_BYCOMMAND equ 0000h
+MF_GRAYED equ 0001h
+MF_DISABLED equ 0002h
+MF_ENABLED equ 0000h
+MF_CHECKED equ 0008h
+MF_BITMAP equ 0004h
+MF_STRING equ 0000h
+MF_POPUP equ 0010h
+MF_DIVIDER equ 0020h
+MF_BREAK equ 0040h
+
+;
+; Window Procedure Messages
+;
+WM_NULL equ 0000h
+WM_CREATE equ 0001h
+WM_DESTROY equ 0002h
+WM_BRUSHALIGN equ 0003h
+WM_SIZEWAIT equ 0004h
+WM_SIZE equ 0005h
+WM_ACTIVATE equ 0006h
+WM_SETFOCUS equ 0007h
+WM_KILLFOCUS equ 0008h
+WM_SETVISIBLE equ 0009h
+WM_ENABLE equ 000Ah
+WM_SETREDRAW equ 000Bh
+WM_SETTEXT equ 000Ch
+WM_GETTEXT equ 000Dh
+WM_GETTEXTLENGTH equ 000Eh
+WM_PAINT equ 000Fh
+WM_CLOSE equ 0010h
+WM_QUERYQUIT equ 0011h
+WM_QUIT equ 0012h
+WM_QUERYOPEN equ 0013h
+WM_ERASEBKGND equ 0014h
+WM_SYSCOLORCHANGE equ 0015h
+WM_ENDSESSION equ 0016h
+WM_SYSTEMERROR equ 0017h
+WM_SHOWWINDOW equ 0018h
+WM_CTLCOLOR equ 0019h
+WM_WININICHANGE equ 001Ah
+WM_DEVMODECHANGE equ 001Bh
+WM_ACTIVATEAPP equ 001Ch
+
+WM_QUEUESYNC equ 0023h
+WM_SETFONT equ 0030h
+WM_GETFONT equ 0031h
+
+WM_WINDOWPOSCHANGING equ 0046h
+WM_WINDOWPOSCHANGED equ 0047h
+
+WM_NCCREATE equ 0081h
+WM_NCDESTROY equ 0082h
+WM_NCCALCSIZE equ 0083h
+WM_NCHITTEST equ 0084h
+WM_NCPAINT equ 0085h
+WM_NCACTIVATE equ 0086h
+WM_GETDLGCODE equ 0087h
+WM_ENDDIALOG equ 0088h
+
+WM_NCMOUSEMOVE equ 00A0h
+WM_NCLBUTTONDOWN equ 00A1h
+WM_NCLBUTTONUP equ 00A2h
+WM_NCLBUTTONDBLCLK equ 00A3h
+WM_NCRBUTTONDOWN equ 00A4h
+WM_NCRBUTTONUP equ 00A5h
+WM_NCRBUTTONDBLCLK equ 00A6h
+WM_NCMBUTTONDOWN equ 00A7h
+WM_NCMBUTTONUP equ 00A8h
+WM_NCMBUTTONDBLCLK equ 00A9h
+
+WM_KEYFIRST equ 0100h
+WM_KEYLAST equ 0107h
+
+WM_KEYDOWN equ 0100h
+WM_KEYUP equ 0101h
+WM_CHAR equ 0102h
+WM_DEADCHAR equ 0103h
+WM_SYSKEYDOWN equ 0104h
+WM_SYSKEYUP equ 0105h
+WM_SYSCHAR equ 0106h
+WM_SYSDEADCHAR equ 0107h
+
+WM_INITDIALOG equ 0110h
+WM_COMMAND equ 0111h
+WM_SYSCOMMAND equ 0112h
+WM_TIMER equ 0113h
+WM_HSCROLL equ 0114h
+WM_VSCROLL equ 0115h
+WM_INITMENU equ 0116h
+WM_INITMENUPOPUP equ 0117h
+WM_SYSTIMER equ 0118h
+
+WM_MOUSEFIRST equ 0200h
+WM_MOUSELAST equ 0209h
+
+WM_MOUSEMOVE equ 0200h
+WM_LBUTTONDOWN equ 0201h
+WM_LBUTTONUP equ 0202h
+WM_LBUTTONDBLCLK equ 0203h
+WM_RBUTTONDOWN equ 0204h
+WM_RBUTTONUP equ 0205h
+WM_RBUTTONDBLCLK equ 0206h
+WM_MBUTTONDOWN equ 0207h
+WM_MBUTTONUP equ 0208h
+WM_MBUTTONDBLCLK equ 0209h
+WM_DROPOBJECT equ 022Ah
+WM_QUERYDROPOBJECT equ 022Bh
+WM_BEGINDRAG equ 022Ch
+WM_DRAGLOOP equ 022Dh
+WM_DRAGSELECT equ 022Eh
+WM_DRAGMOVE equ 022Fh
+WM_DROPFILES equ 0233h
+
+WM_CUT equ 0300h
+WM_COPY equ 0301h
+WM_PASTE equ 0302h
+WM_CLEAR equ 0303h
+WM_UNDO equ 0304h
+WM_RENDERFORMAT equ 0305h
+WM_RENDERALLFORMATS equ 0306h
+WM_DESTROYCLIPBOARD equ 0307h
+WM_DRAWCLIPBOARD equ 0308h
+WM_PAINTCLIPBOARD equ 0309h
+WM_VSCROLLCLIPBOARD equ 030Ah
+WM_SIZECLIPBOARD equ 030Bh
+WM_ASKCBFORMATNAME equ 030Ch
+
+WM_INTERNAL_COALESCE_FIRST equ 0390h ; internal
+
+WM_COALESCE_FIRST equ 0390h
+WM_COALESCE_LAST equ 039Fh
+
+; The following message range reserved ;Internal
+; for multi-media ;Internal
+
+WM_MM_RESERVED_FIRST equ 03A0h ;Internal
+WM_MM_RESERVED_LAST equ 03DFh ;Internal
+
+WM_INTERNAL_COALESCE_LAST equ (WM_MM_RESERVED_FIRST+16) ;internal
+
+WM_INTERNAL_DDE_FIRST equ 03E0h ;Internal
+WM_INTERNAL_DDE_LAST equ 03EFh ;Internal
+
+; The following messages are reserved for CBT ;Internal
+WM_CBT_RESERVED_FIRST equ 03F0h ;Internal
+WM_CBT_RESERVED_LAST equ 03FFh ;Internal
+
+
+WM_USER equ 0400h
+
+;
+; System Menu Command Values
+;
+SC_SIZE equ 0F000h
+SC_MOVE equ 0F010h
+SC_ICON equ 0F020h
+SC_ZOOM equ 0F030h
+SC_NEXTWINDOW equ 0F040h
+SC_PREVWINDOW equ 0F050h
+SC_CLOSE equ 0F060h
+
+;******** RedrawWindow() flags
+
+RDW_INVALIDATE equ 0001h ; Invalidate
+RDW_INTERNALPAINT equ 0002h ; Set WFINTERNALPAINT
+RDW_ERASE equ 0004h ; Set WFSENDERASEBKGND
+
+RDW_VALIDATE equ 0008h ; Validate
+RDW_NOINTERNALPAINT equ 0010h ; Clear WFINTERNALPAINT
+RDW_NOERASE equ 0020h ; Clear WFSENDERASEBKGND
+
+RDW_NOCHILDREN equ 0040h ; Don't include children
+RDW_ALLCHILDREN equ 0080h ; Include all children
+
+RDW_UPDATENOW equ 0100h ; Update the window now if needed
+RDW_ERASENOW equ 0200h ; Erase the background now (implied by UPDATENOW)
+
+; Internal-only RedrawWindow() flags
+;
+RDW_FRAME equ 0400h ; Set WFSENDNCPAINT
+RDW_NOFRAME equ 0800h ; Clear WFSENDNCPAINT
+
+RDW_REDRAWWINDOW equ 1000h ; Called from RedrawWindow()
+RDW_SUBTRACTSELF equ 2000h ; Subtract self from hrgn
+
+RDW_COPYRGN equ 4000h ; Copy the passed-in region
+
+; WM_HOTKEYEVENT stuff
+
+WM_HOTKEYEVENT equ 0045h
+
+endif ; !WOW
+
+;
+; SetWindowsHook() definitions
+;
+WH_MSGFILTER equ -1
+WH_JOURNALRECORD equ 0
+WH_JOURNALPLAYBACK equ 1
+WH_KEYBOARD equ 2
+WH_GETMESSAGE equ 3
+WH_CALLWNDPROC equ 4
+WH_CBT equ 5
+WH_SYSMSGFILTER equ 6
+WH_MOUSE equ 7
+WH_HARDWARE equ 8
+WH_DEBUG equ 9
+WH_SHELL equ 10
+
+ifndef WOW
+
+;
+; Standard hook code values
+;
+HC_GETLPLPFN equ -3
+HC_LPLPFNNEXT equ -2
+HC_LPFNNEXT equ -1
+HC_ACTION equ 0
+HC_GETNEXT equ 1
+HC_SKIP equ 2
+HC_SYSMODALON equ 4
+HC_SYSMODALOFF equ 5
+
+endif ; !WOW
+
+; Lowest and highest valued windows hook IDs
+
+WH_MINHOOK equ -1
+WH_MAXHOOK equ 10
+WH_CHOOKS equ (WH_MAXHOOK - WH_MINHOOK + 1)
+
+HOOKNODE struc
+ hkPhkNext dw ?
+ hkLpfn dd ?
+ hkIdHook dw ?
+ hkHq dw ?
+ hkHmodOwner dw ?
+ hkFCalled dw ?
+HOOKNODE ends
+
+HHOOK_MAGIC equ ('H' or ('K' * 256))
+
+; SetHotKeyHook() definitions
+
+HOTKEYHOOK struc
+ hkhPfn dd ?
+ hkhHmodule dw ?
+HOTKEYHOOK ends
+
+CHOTKEYHOOKMAX equ 16
+
+ifndef NOEXTERNS
+sBegin DATA
+
+ifndef WOW
+ExternW rgphkSysHooks
+endif
+
+sEnd DATA
+endif ;NOEXTERNS
+
+MAX_SEB_STYLES equ 8 ; number of SEB_* values
+
+SEB_OK equ 1 ; Button with "OK".
+SEB_CANCEL equ 2 ; Button with "Cancel"
+SEB_YES equ 3 ; Button with "&Yes"
+SEB_NO equ 4 ; Button with "&No"
+SEB_RETRY equ 5 ; Button with "&Retry"
+SEB_ABORT equ 6 ; Button with "&Abort"
+SEB_IGNORE equ 7 ; Button with "&Ignore"
+SEB_CLOSE equ 8 ; Button with "Close"
+
+SEB_DEFBUTTON equ 8000h ;Mask to make this button default
+
+SEB_BTN1 equ 1 ; Button 1 was selected
+SEB_BTN2 equ 2 ; Button 1 was selected
+SEB_BTN3 equ 3 ; Button 1 was selected
+
+;
+; InvalidateDCCache() flags
+;
+IDC_DEFAULT equ 0001h
+IDC_CHILDRENONLY equ 0002h
+IDC_CLIENTONLY equ 0004h
+
+;
+; Window field offsets for GetWindowLong() and GetWindowWord()
+;
+GWL_WNDPROC = (-4)
+GWW_HINSTANCE = (-6)
+GWW_HWNDPARENT = (-8)
+GWW_ID = (-12)
+GWL_STYLE = (-16)
+GWL_EXSTYLE = (-20)
+
+;
+; Class field offsets for GetClassLong() and GetClassWord()
+;
+GCL_MENUNAME = (-8)
+GCW_HBRBACKGROUND = (-10)
+GCW_HCURSOR = (-12)
+GCW_HICON = (-14)
+GCW_HMODULE = (-16)
+GCW_CBWNDEXTRA = (-18)
+GCW_CBCLSEXTRA = (-20)
+GCL_WNDPROC = (-24)
+GCW_STYLE = (-26)
+GCW_ATOM = (-32)
+
+;
+; CTLCOLOR_* for the message WM_CTLCOLOR.
+;
+CTLCOLOR_MSGBOX equ 0
+CTLCOLOR_EDIT equ 1
+CTLCOLOR_LISTBOX equ 2
+CTLCOLOR_BTN equ 3
+CTLCOLOR_DLG equ 4
+CTLCOLOR_SCROLLBAR equ 5
+CTLCOLOR_MAX equ 8 ; 3 bits max
+
+DLGC_WANTARROWS equ 01h
+DLGC_HASSETSEL equ 08h
+DLGC_WANTCHARS equ 80h
+
+SUENUMCHILDREN equ 0001h
+SUPAINTFRAME equ 0002h
+SUSTOPCLIPCHILDREN equ 0004h
+SUVALIDATE equ 8000h
+
+MB_OKCANCEL equ 00001h
+MB_ICONHAND equ 00010h
+MB_SYSTEMMODAL equ 01000h
+
+
+
+ASMSYSCLROBJECTS struc
+ syshbrScrollbar dw ?
+ syshbrDesktop dw ?
+ syshbrActiveCaption dw ?
+ syshbrInactiveCaption dw ?
+ syshbrMenu dw ?
+ syshbrWindow dw ?
+ syshbrWindowFrame dw ?
+ syshbrMenuText dw ?
+ syshbrWindowText dw ?
+ syshbrCaptionText dw ?
+ syshbrActiveBorder dw ?
+ syshbrInactiveBorder dw ?
+ syshbrAppWorkspace dw ?
+ syshbrHiliteBk dw ?
+ syshbrHiliteText dw ?
+ syshbrBtnFace dw ?
+ syshbrBtnShadow dw ?
+ syshbrGrayText dw ?
+ASMSYSCLROBJECTS ends
+
+
+ASMSYSCOLORS struc
+ sysclrScrollbar dd ?
+ sysclrDesktop dd ?
+ sysclrActiveCaption dd ?
+ sysclrInactiveCaption dd ?
+ sysclrMenu dd ?
+ sysclrWindow dd ?
+ sysclrWindowFrame dd ?
+ sysclrMenuText dd ?
+ sysclrWindowText dd ?
+ sysclrCaptionText dd ?
+ sysclrActiveBorder dd ?
+ sysclrInactiveBorder dd ?
+ sysclrAppWorkspace dd ?
+ sysclrHiliteBk dd ?
+ sysclrHiliteText dd ?
+ sysclrBtnFace dd ?
+ sysclrBtnShadow dd ?
+ sysclrGrayText dd ?
+ASMSYSCOLORS ends
+
+SCREEN struc
+ scrncy dw ?
+ scrncx dw ?
+ scrnrc db size RECT dup(?)
+ scrncLock dw ?
+ scrncclm dw ?
+ scrncclmSave dw ?
+ scrncwnd dw ?
+SCREEN ends
+
+;
+; Property List structures
+;
+PROP struc
+ propAtom dw 0
+ propValue dw 0
+PROP ends
+
+PROPTABLE struc
+ proptabCprop dw 0
+ proptabRgprop db size PROP dup(?)
+PROPTABLE ends
+
+;*--------------------------------------------------------------------------*
+;* *
+;* Window Class Structures and Defines *
+;* *
+;*--------------------------------------------------------------------------*
+
+WNDCLASS struc
+ clsStyle dw ? ; Class style
+ clsLpfnWndProc dd ?
+ clsCbClsExtra dw ?
+ clsCbWndExtra dw ?
+ clsHInstance dw ? ; Instance handle
+ clsHIcon dw ? ; Class icon handle
+ clsHCursor dw ? ; Class cursor handle
+ clsHbrBackground dw ? ; Class background brush
+ clsLpszMenuName dd ? ; Menu name
+ clsLpszClassName dd ? ; Far ptr to class name
+WNDCLASS ends
+
+WNDSTRUC struc
+ WSwndStyle dd ?
+ WSwndID dw ?
+ WSwndText dw ?
+ WSwndParent dw ?
+ WSwndInstance dw ?
+ WSwndClassProc dd ?
+WNDSTRUC ends
+
+;
+; Window Styles (high words only)
+;
+WS_TILED equ 0000h
+WS_POPUP equ 8000h
+WS_CHILD equ 4000h
+WS_ICONIC equ 2000h
+WS_VISIBLE equ 1000h
+WS_DISABLED equ 0800h
+WS_CLIPSIBLINGS equ 0400h
+WS_CLIPCHILDREN equ 0200h
+WS_COLUMN equ 0100h
+
+WS_BORDER equ 0080h
+WS_CAPTION equ 0040h
+WS_VSCROLL equ 0020h
+WS_HSCROLL equ 0010h
+WS_SYSMENU equ 0008h
+WS_SIZEBOX equ 0004h
+WS_GROUP equ 0002h
+WS_TABSTOP equ 0001h
+
+;
+; Class Styles
+;
+CS_VREDRAW equ 0001h
+CS_HREDRAW equ 0002h
+CS_KEYCVTWINDOW equ 0004h
+CS_DBLCLKS equ 0008h
+CS_OEMCHARS equ 0010h
+CS_OWNDC equ 0020h
+CS_CLASSDC equ 0040h
+CS_PARENTDC equ 0080h
+CS_NOKEYCVT equ 0100h
+CS_LVB equ 0400h
+CS_SAVEPOPUPBITS equ 0800h
+CS_GLOBALCLASS equ 4000h
+
+
+;
+; WinWhere Area Codes
+;
+HTTRANSPARENT equ -1
+HTNOWHERE equ 0
+HTCLIENT equ 1
+HTCAPTION equ 2
+HTCLOSEBOX equ 3
+HTGROWBOX equ 4
+HTMENU equ 5
+HTHSCROLL equ 6
+HTVSCROLL equ 7
+
+;*--------------------------------------------------------------------------*
+;* Message Structures and Defines *
+;*--------------------------------------------------------------------------*
+
+;
+; Message Structure
+;
+MSG struc
+ msgHwnd dw ?
+ msgMessage dw ?
+ msgWParam dw ?
+ msgLParam dd ?
+ msgTime dd ?
+ msgPt dd ?
+MSG ends
+
+INTERNALMSG struc
+ imExtraMsgInfo dd ?
+ imMsg db size MSG dup (?)
+INTERNALMSG ends
+
+;
+; System Queue Message Structure
+;
+SYSMSG struc
+ smParamL dw ?
+ smMessage dw ?
+ smParamH dw ?
+ smTime dd ?
+SYSMSG ends
+
+INTERNALSYSMSG struc
+ ismExtraMsgInfo dd ?
+ ismMsg db size SYSMSG dup (?)
+INTERNALSYSMSG ends
+
+; GetQueueStatus bits.
+
+QS_KEY equ 0001h ; WM_KEY/SYSKEYUP/DOWN
+QS_MOUSEMOVE equ 0002h ; WM_MOUSEMOVE
+QS_MOUSEBUTTON equ 0004h ; WM_NC/L/R/MBUTTONUP/DOWN/DBLCLK
+QS_MOUSE equ (QS_MOUSEMOVE or QS_MOUSEBUTTON) ; Any mouse event
+QS_POSTMESSAGE equ 0008h ; Message posted with PostMessage()
+QS_TIMER equ 0010h ; WM_TIMER
+QS_PAINT equ 0020h ; WM_PAINT
+QS_SENDMESSAGE equ 0040h ; Pending SendMessage() calls from other app
+ifdef DISABLE
+QS_HOTKEYEVENT equ 0080h ; WM_HOTKEYEVENT (WIN 3.1 ONLY)
+endif
+
+; Internal values
+
+QS_SMRESULT equ 8000h
+QS_SMPARAMSFREE equ 4000h
+
+QS_INPUT equ (QS_MOUSEMOVE or QS_MOUSEBUTTON or QS_KEY)
+
+ifdef DISABLE
+QS_ALLINPUT equ (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT or QS_HOTKEYEVENT)
+else
+QS_ALLINPUT equ (QS_INPUT or QS_POSTMESSAGE or QS_TIMER or QS_PAINT)
+endif
+
+; Q flags field values
+
+QF_SEMWAIT equ 01h
+QF_INIT equ 02h
+QF_PALETTEAPP equ 04h
+
+;
+; Queue Structure
+;
+Q struc
+ qHqNext dw ?
+ qHTask dw ?
+ qCbEntry dw ?
+ qCMsgs dw ?
+ qPmsgRead dw ?
+ qPmsgWrite dw ?
+ qPmsgMax dw ?
+ qTimeLast dd ?
+ qPtLast dd ?
+ qIdLast dw ?
+ qdwExtraInfoLast dd ?
+ qUnused dw ?
+ qMsgLParam dd ?
+ qMsgWParam dw ?
+ qMsgMessage dw ?
+ qMsgHwnd dw ?
+ qResult dd ?
+
+ qCQuit dw ?
+ qExitCode dw ?
+ qFlags dw ?
+ qpMsgFilterChain dw ? ; Near Ptr to the head of the hook chain
+ qHDS dw ?
+ qWVersion dw ?
+ qHqSender dw ? ; New Input Stuff starts here
+ qHqSendList dw ?
+ qHqSendNext dw ?
+ qCPaintsReady dw ?
+ qCTimersReady dw ?
+ qChangeBits dw ?
+ qWakeBits dw ?
+ qWakeMask dw ?
+ qPResult dw ?
+ qPResultSend dw ?
+ qPResultReceive dw ?
+ qPhkCurrent dw ?
+ qRgphkHooks dw WH_CHOOKS dup (?)
+ qSemInput dd ?
+ qHqSemNext dw ?
+ qRgmsg db size INTERNALMSG dup (?)
+Q ends
+
+;
+; Timer Structure
+;
+TIMER struc
+ tmrHq dw ?
+ tmrHwnd dw ?
+ tmrID dw ?
+ tmrCount dw ?
+ tmrRate dw ?
+ tmrFSys db ?
+ tmrReady db ?
+ tmrLpfn dd ?
+TIMER ends
+
+CPUBLICTIMERS equ 32
+CSYSTEMTIMERS equ 2
+CTIMERSMAX equ CPUBLICTIMERS + CSYSTEMTIMERS
+
+ifndef WOW
+
+; GetSystemMetrics() codes.
+SM_CXSCREEN equ 0
+SM_CYSCREEN equ 1
+SM_CXVSCROLL equ 2
+SM_CYHSCROLL equ 3
+SM_CYCAPTION equ 4
+SM_CXBORDER equ 5
+SM_CYBORDER equ 6
+SM_CXDLGFRAME equ 7
+SM_CYDLGFRAME equ 8
+SM_CYVTHUMB equ 9
+SM_CXHTHUMB equ 10
+SM_CXICON equ 11
+SM_CYICON equ 12
+SM_CXCURSOR equ 13
+SM_CYCURSOR equ 14
+SM_CYMENU equ 15
+SM_CXFULLSCREEN equ 16
+SM_CYFULLSCREEN equ 17
+SM_CYKANJIWINDOW equ 18
+SM_MOUSEPRESENT equ 19
+SM_CYVSCROLL equ 20
+SM_CXHSCROLL equ 21
+SM_DEBUG equ 22
+SM_SWAPBUTTON equ 23
+SM_RESERVED1 equ 24
+SM_RESERVED2 equ 25
+SM_RESERVED3 equ 26
+SM_RESERVED4 equ 27
+SM_CXMIN equ 28
+SM_CYMIN equ 29
+SM_CXSIZE equ 30
+SM_CYSIZE equ 31
+SM_CXFRAME equ 32
+SM_CYFRAME equ 33
+SM_CXMINTRACK equ 34
+SM_CYMINTRACK equ 35
+SM_CXDOUBLECLK equ 36
+SM_CYDOUBLECLK equ 37
+SM_CXICONSPACING equ 38
+SM_CYICONSPACING equ 39
+SM_MENUDROPALIGNMENT equ 40
+SM_PENWINDOWS equ 41
+SM_DBCSENABLED equ 42
+SM_CMETRICSMAX equ 43
+
+IFNDEF NOCOLOR
+; System colors
+COLOR_SCROLLBAR = 0
+COLOR_BACKGROUND = 1
+COLOR_ACTIVECAPTION = 2
+COLOR_INACTIVECAPTION = 3
+COLOR_MENU = 4
+COLOR_WINDOW = 5
+COLOR_WINDOWFRAME = 6
+COLOR_MENUTEXT = 7
+COLOR_WINDOWTEXT = 8
+COLOR_CAPTIONTEXT = 9
+COLOR_ACTIVEBORDER = 10
+COLOR_INACTIVEBORDER = 11
+COLOR_APPWORKSPACE = 12
+COLOR_HIGHLIGHT = 13
+COLOR_HIGHLIGHTTEXT = 14
+COLOR_BTNFACE = 15
+COLOR_BTNSHADOW = 16
+COLOR_GRAYTEXT = 17
+COLOR_BTNTEXT = 18
+COLOR_INACTIVECAPTIONTEXT = 19
+COLOR_BTNHILIGHT = 20
+COLOR_MAX = 20
+
+ENDIF ;NOCOLOR
+
+; DrawFrame commands
+DF_SHIFT0 equ 0000h
+DF_SHIFT1 equ 0001h
+DF_SHIFT2 equ 0002h
+DF_SHIFT3 equ 0003h
+DF_PATCOPY equ 0000h
+DF_PATINVERT equ 0004h
+
+DF_SCROLLBAR equ (COLOR_SCROLLBAR * 8)
+DF_BACKGROUND equ (COLOR_BACKGROUND * 8)
+DF_ACTIVECAPTION equ (COLOR_ACTIVECAPTION * 8)
+DF_INACTIVECAPTION equ (COLOR_INACTIVECAPTION * 8)
+DF_MENU equ (COLOR_MENU * 8)
+DF_WINDOW equ (COLOR_WINDOW * 8)
+DF_WINDOWFRAME equ (COLOR_WINDOWFRAME * 8)
+DF_MENUTEXT equ (COLOR_MENUTEXT * 8)
+DF_WINDOWTEXT equ (COLOR_WINDOWTEXT * 8)
+DF_CAPTIONTEXT equ (COLOR_CAPTIONTEXT * 8)
+DF_ACTIVEBORDER equ (COLOR_ACTIVEBORDER * 8)
+DF_INACTIVEBORDER equ (COLOR_INACTIVEBORDER * 8)
+DF_APPWORKSPACE equ (COLOR_APPWORKSPACE * 8)
+DF_GRAY equ (DF_APPWORKSPACE + (1 * 8))
+endif ; !WOW
+
+ifndef NOEXTERNS
+;*--------------------------------------------------------------------------*
+;* Externs for the Interrupt Level Global Variables *
+;*--------------------------------------------------------------------------*
+
+; This file is included to access intrerrupt variables. It declares them in
+; the right segment, externs [csds], the variable that has the segment
+; that these variables will be in, and assumes ds to the CODE segment
+
+createSeg _INTDS, INTDS, BYTE, PUBLIC, DATA
+
+sBegin INTDS
+
+ifndef WOW
+ExternB fDontMakeAltUpASysKey
+ExternD hwEventHook
+ifdef userhimem
+ExternW fffedelta
+endif
+ExternW msgJournal
+ExternD dtJournal
+ExternD ptTrueCursor
+ExternD dwMouseMoveExtraInfo
+ExternD ptCursor
+ifdef DOS30
+ExternD lpSysProc
+endif
+ExternW hqActive
+ExternW hqCapture
+ExternW hqMouse
+ExternW hqKeyboard
+endif ; !WOW
+ExternW hqList
+ExternW hqSysQueue
+ExternW hqSysModal
+ExternW cQEntries
+ifndef WOW
+ExternW fMouseMoved
+;; ExternB fAltKeyUp
+ExternB rgbAsyncKeyState
+ExternW fEnableInput
+ExternW fSwapButtons
+endif ; !WOW
+ExternW hqCursor
+ifndef WOW
+ExternW cMsgRsrv
+ExternB vKeyDown
+ExternD timerInfo
+ExternB TimerTable
+ExternW TimerTableMax
+ExternW hSysTimer
+ExternD tSysTimer
+ExternW dtSysTimer
+ExternB fInScanTimers
+endif ; !WOW
+ExternW szDivZero
+ExternW szSysError
+ifndef WOW
+ExternW x_mickey_rate
+ExternW y_mickey_rate
+ExternW cur_x_mickey
+ExternW cur_y_mickey
+ExternW rcCursorClip
+ExternW cxScreenCS
+ExternW cyScreenCS
+ExternW MouseThresh1
+ExternW MouseThresh2
+ExternW MouseSpeed
+ifndef PMODE
+ExternD lpMouseStack
+ExternD prevSSSP
+ExternB NestCount
+endif
+ExternW hqSysLock
+ExternW idSysLock
+
+ExternW fJournalPlayback
+endif ; !WOW
+
+sEnd INTDS
+
+endif
+
+
+ifndef WOW
+;*--------------------------------------------------------------------------*
+;* OEM Inquire Structures for Timer, Keyboard, Mouse, and Cursor modules *
+;*--------------------------------------------------------------------------*
+
+STIMERINFO struc
+ tiResolution dd 0 ; #microseconds each timer tick
+STIMERINFO ends
+
+SKBINFO struc
+ kbBegin1 db 0 ; some range values for the Far East
+ kbEnd1 db 0
+ kbBegin2 db 0
+ kbEnd2 db 0
+ kbStateSize dw 0 ; #bytes of state info maintained by TOASCII
+SKBINFO ends
+
+SMOUSEINFO struc
+ msExists db 0 ; true => mouse exists
+ msRelative db 0 ; true => relative coordinate
+ msNumButtons dw 0 ; number of buttons on the mouse
+ msRate dw 0 ; maximum rate of mouse input events
+ msXThresh dw 0 ; threshold before acceleration
+ msYThresh dw 0 ;
+ msXRes dw 0 ; x resolution
+ msYRes dw 0 ; y resolution
+SMOUSEINFO ends
+
+SCURSORINFO struc
+ dpXRate dw 0 ; horizontal mickey/pixel ratio
+ dpYRate dw 0 ; vertical mickey/pixel ratio
+ dpXMask dw 0
+ dpYMask dw 0
+ dpXCurSize dw 0
+ dpYCurSize dw 0
+ dpXIcoSize dw 0
+ dpYIcoSize dw 0
+SCURSORINFO ends
+
+;
+; OEM Info Structures
+;
+
+OEMBITMAPINFO struc
+ oemhBitmap dw ?
+ oemwidth dw ?
+ oemheight dw ?
+OEMBITMAPINFO ends
+
+OEMSINFO struc
+ oembmFull db size OEMBITMAPINFO dup(?)
+ oembmUpArrow db size OEMBITMAPINFO dup(?)
+ oembmDnArrow db size OEMBITMAPINFO dup(?)
+ oembmRgArrow db size OEMBITMAPINFO dup(?)
+ oembmLfArrow db size OEMBITMAPINFO dup(?)
+ oembmReduce db size OEMBITMAPINFO dup(?)
+ oembmZoom db size OEMBITMAPINFO dup(?)
+ oembmRestore db size OEMBITMAPINFO dup(?)
+ oembmMenuArrow db size OEMBITMAPINFO dup(?)
+ oembmComboArrow db size OEMBITMAPINFO dup(?)
+ oembmReduceD db size OEMBITMAPINFO dup(?)
+ oembmZoomD db size OEMBITMAPINFO dup(?)
+ oembmRestoreD db size OEMBITMAPINFO dup(?)
+ oembmUpArrowD db size OEMBITMAPINFO dup(?)
+ oembmDnArrowD db size OEMBITMAPINFO dup(?)
+ oembmRgArrowD db size OEMBITMAPINFO dup(?)
+ oembmLfArrowD db size OEMBITMAPINFO dup(?)
+ oemcxHThumb dw ?
+ oemcyVVThumb dw ?
+ oemcxMin dw ?
+ oemcyMin dw ?
+ oemcxIconSlot dw ?
+ oemcyIconSlot dw ?
+ oemcxIcon dw ?
+ oemcyIcon dw ?
+ oemcxPixelsPerInc dw ?
+ oemcyPixelsPerInch dw ?
+ oemcxCursor dw ?
+ oemcyCursor dw ?
+ oemDispDrvExpWinVer dw ?
+ oemScreenBitCount dw ?
+ oemcSKanji dw ?
+ oemfMouse dw ?
+OEMSINFO ends
+
+OEMSINFOMONO struc
+ oembmAdjust db size OEMBITMAPINFO dup(?)
+ oembmSize db size OEMBITMAPINFO dup(?)
+ oembmCheck db size OEMBITMAPINFO dup(?)
+ oembmbtnbmp db size OEMBITMAPINFO dup(?)
+ oembmCorner db size OEMBITMAPINFO dup(?)
+ oemcxbmpChk dw ?
+ oemcybmpChk dw ?
+OEMSINFOMONO ends
+endif ; !WOW
+
+
+;*--------------------------------------------------------------------------*
+;* Debugging Defines *
+;*--------------------------------------------------------------------------*
+
+;
+; RIP codes
+;
+RIP_CHECKDC equ 0FFF2h ; decimal -14
+RIP_WLSINSEM equ 0FFF3h ; decimal -13
+RIP_CHECKSEM equ 0FFF4h ; decimal -12
+RIP_SENDMESSAGEINSEM equ 0FFF5h ; decimal -11
+RIP_SEMNOTINORDER equ 0FFF6h ; decimal -10
+RIP_RWLEAVEUNDERFLOW equ 0FFF7h ; decimal -9
+
+RIP_WINDOWLEFTLOCKED equ 0FFF9h ; decimal -7 ; hq->cLock !equ 0 in GetMessage.
+RIP_BADLOCKWINDOW equ 0FFFAh ; decimal -6 ; Window passed was NULL.
+RIP_LOCKUNDERFLOW equ 0FFFBh ; decimal -5 ; Too many UnlockWindows.
+RIP_INSEMAPHORE equ 0FFFCh ; decimal -4
+RIP_BADSEMCLEAR equ 0FFFDh ; decimal -3
+RIP_BADLOCKCOUNT equ 0FFFEh ; decimal -2
+RIP_MEMALLOC equ 1
+RIP_MEMREALLOC equ 2
+RIP_MEMFREE equ 3
+RIP_MEMLOCK equ 4
+RIP_MEMUNLOCK equ 5
+RIP_SENDMESSAGELOCK equ 6
+RIP_BADWINDOWHANDLE equ 7
+RIP_DCBUSY equ 8
+RIP_NODEFWINDOWPROC equ 9
+RIP_CLIPBOARDOPEN equ 000Ah
+RIP_DCCAHCHEFULL equ 000Bh
+RIP_INVALKEYBOARD equ 000Ch
+RIP_INVALMOUSE equ 000Dh
+RIP_INVALCURSOR equ 000Eh
+RIP_DSUNLOCKED equ 000Fh
+RIP_INVALLOCKSYSQ equ 0010h
+RIP_CARETBUSY equ 0011h
+RIP_GETCWRANGE equ 0012h
+RIP_HWNDOWNSDCS equ 0013h ; One hwnd owns all the DCs.
+RIP_BADHQ equ 0014h ; Operation on something of wrong task
+RIP_NOQUEUE equ 0019h ; GetAppVer() is called before queues are
+ ; created.
+RIP_BADHOOKHANDLE equ 001Bh
+RIP_BADHOOKID equ 001Ch
+RIP_BADHOOKPROC equ 001Dh
+RIP_BADHOOKMODULE equ 001Eh
+RIP_BADHOOKCODE equ 001Fh
+RIP_HOOKNOTALLOWED equ 0020h
+RIP_UNREMOVEDPROP equ 0021h
+RIP_BADPROPNAME equ 0022h
+
+RIP_BADTASKHANDLE equ 0025h
+
+RIP_GETSETINFOERR1 equ 0027h ; Bad negative index for Get/Set/Window etc.,
+RIP_GETSETINFOERR2 equ 0028h ; Bad Positive index for Get/Set/Window etc.,
+
+RIP_WINDOWIDNOTFOUND equ 002Ah ; Dialog control ID not found
+RIP_SYSTEMERRORBOXFAILED equ 002Bh ; Hard sys error box failed due to no hq
+RIP_INVALIDMENUHANDLE equ 002Ch ; Invalid menu handle
+
+RIP_MESSAGEBOXWITHNOQUEUE equ 002Eh ; Message box called with no message queue initialized
+RIP_DLGWINDOWEXTRANOTALLOCATED equ 002Fh ; DLGWINDOWEXTRA bytes not allocated for dlg box
+RIP_INTERTASKSENDMSGHANG equ 0030h ; Intertask send message with tasks locked
+RIP_INVALIDPARAM equ 0031h
+RIP_ASSERTFAILED equ 0032h
+RIP_INVALIDFUNCTIONCALLED equ 0033h
+RIP_LOCKINPUTERROR equ 0034h
+RIP_NULLWNDPROC equ 0035h ; SetWindowLong uses a NULL wnd proc
+RIP_BAD_UNHOOK equ 0036h ; SetWindowsHook is called to unhook.
+RIP_QUEUE_FULL equ 0037h ; PostMessage failed due to full queue.
+
+;
+; DebugErr() macro
+;
+ifdef DEBUG
+
+ifndef winmisc1
+externFP DebugOutput,<C>
+endif
+
+DebugErr macro flags,msg
+ local a,b
+ push cs
+ push offset a
+ push flags or DBF_USER
+ cCall DebugOutput
+ add sp,2+4 ; DebugOutput is cdecl!
+ jmp short b
+a:
+ db "USER: "
+ db msg
+ db 0
+b:
+endm
+
+else ; DEBUG
+
+DebugErr macro flags,msg
+endm
+
+endif ; DEBUG
+
+externFP LogError
+
+include LogError.inc
+
+UserLogError macro flags,errcode,msg
+ DebugErr <flags>,<msg>
+ push errcode
+ push 0
+ push 0
+ call LogError
+endm
+
+;
+; Fast, inline check for valid window.
+; NOTE: MUST BE USED INSIDE beg_fault_trap/end_fault_trap
+;
+FastIsWindow macro seg,reg
+ mov reg,seg:[reg].wndPcls
+ cmp seg:[reg].uclsMagic,CLS_MAGIC
+ endm
+
+;*--------------------------------------------------------------------------*
+;* Utility Macros *
+;*--------------------------------------------------------------------------*
+
+; Similar to LabelFP, except used for "validate in debug only" entry points.
+; Declares Iname if debug, name if
+;
+LabelVDO macro name
+ ifdef DEBUG
+ LabelFP <PUBLIC, I&name>
+ else
+ LabelFP <PUBLIC, I&name>
+ LabelFP <PUBLIC, name>
+ endif
+endm
+
+; Same as cProc, except used for "Validate in Debug Only" entry points.
+; Declares Iname if debug, name if retail.
+;
+cProcVDO macro name,opts,savelist
+ ifdef DEBUG
+ cProc <I&name>,<opts>,<savelist>
+ else
+ LabelFP <PUBLIC, I&name>
+ cProc <name>,<opts>,<savelist>
+ endif
+endm
+
+;
+; EatTwoBytes macro
+;
+EatTwoBytes macro
+ db 0A9h ;; Opcode for CMP AX,(immediate word)
+ endm
+
+;
+; Push DWORD macro
+;
+pushd macro d
+ push word ptr (d)+2
+ push word ptr (d)
+ endm
+;
+; Call an internal far entry point
+;
+wcall macro adr
+ push cs
+ call near ptr (adr)
+ endm
+
+;
+; Short jump macro
+;
+jmps macro adr
+ jmp short (adr)
+ endm
+
+;
+; XMOV macro
+;
+; Use instead of MOV ax,reg. Saves a byte.
+;
+xmov macro a,b
+ xchg a,b
+ endm
+
+ifndef WOW
+;----------------------------------------------------------------------------
+; New set of Critical Region Macros
+; The necessity for new set of macros is
+; 1. We need to avoid "cli" if it is already disabled (saves 300 cycles
+; under 386pmode because "cli" and "sti" are simulated by Windows).
+; 2. PostMessage() might be called with interrupts already disabled; so,
+; we should not blindly do a "sti" when we do LeaveCrit
+; WARNINGS:
+; 1. These two macros must be properly nested.
+;----------------------------------------------------------------------------
+; WARNINGS for NewEnterCrit:
+; (1) This trashes the zero flag.
+; (2) This trashes the register that is passed as the parameter;
+; (3) It pushes flags onto stack which will be popped up by NewLeaveCrit
+;----------------------------------------------------------------------------
+NewEnterCrit macro Reg
+ LOCAL SkipCli ;; Declare symbol for macro
+ pushf ;; Save flags on stack for the use of NewLeaveCrit
+ pushf
+ pop Reg ;; Load flags into BX register
+ test Reg, 0200h ;; see if interrupts are already disabled
+ jz SkipCli ;; Skip doing a "cli" and save 300 cycles!!!
+ FCLI ;; We have to clear the interrupts
+SkipCli:
+ endm
+;----------------------------------------------------------------------------
+; WARNINGS for NewLeaveCrit:
+; (1) This preserves the Z flag.
+; (2) This trashes the registers that are passed as the parameters;
+; (3) It pops the flags pushed by NewEnterCrit.
+; NOTE: It is much easier to use pushf and popf combination to preserve
+; the Z flag, but 286 processors have a bug which results in the
+; interrupts enabled irrespect of the state of the flag before and
+; after the popf; That is why we do not use popf anywhere in this
+; macro;
+;----------------------------------------------------------------------------
+NewLeaveCrit macro Reg, ZFlagReg
+ LOCAL SkipSti ;; Declare symbol for Macro
+ pushf ;; To save the Z flag
+ pop ZFlagReg ;; Save the Z flag
+ pop Reg ;; pop flags pushed by NewEnterCrit
+ test Reg, 0200h ;; see if interrupts were disabled even
+ ;; before entering the critical region
+ jz SkipSti ;; Skip doing a "sti".
+ FSTI
+SkipSti:
+ not ZFlagReg
+ test ZFlagReg, 0040h ;; Restore Z flag to the value before
+ ;; entering NewLeaveCrit
+ endm
+
+endif ; !WOW
+
+;
+; Old Critical Region macros
+;
+EnterCrit macro
+ FCLI
+ endm
+
+LeaveCrit macro
+ FSTI
+ endm
+
+
+ifndef WOW
+;
+; AllocP Macro
+;
+; Caution: You can not use ax regiter as a parameter for this Macro!
+;
+
+AllocP macro wType, cb
+ifdef DEBUG
+ifndef winmisc1
+ mov ax, wType
+ push ax
+endif
+endif
+ push LPTR
+ push cb
+ call LocalAlloc
+ endm
+
+
+;
+; AllocH Macro
+;
+; CAUTION: You can NOT use ax register as a parameter for this MACRO!
+;
+AllocH macro wType, cb
+ifdef DEBUG
+ifndef winmisc1
+ push wType
+endif
+endif
+ push LHND
+ push cb
+ call LocalAlloc
+ endm
+
+FreeP macro Ptr
+ push Ptr
+ call LocalFree
+ endm
+
+;
+; ReAllocH Macro
+;
+ReAllocH macro h, cb
+ push h
+ push cb
+ push LMEM_ZEROINIT
+ call LocalReAlloc
+ endm
+
+;
+; FreeH Macro
+;
+FreeH macro h
+ push h
+ call LocalFree
+ endm
+
+;
+; LockH is assumed to preserve all registers (except flags)
+;
+LockH macro h, p
+ inc byte ptr [h+3]
+ mov p,[h]
+ endm
+
+;
+; UnlockH is assumed to preserve all registers (except flags)
+;
+UnlockH macro h
+ dec byte ptr [h+3]
+ endm
+endif ; !WOW
+
+
+ifndef WOW
+;----------------------------------------------------------------------------
+; GetES
+; This macro gets the current value of USER's data segment and loads it
+; into ES register.
+; NOTE: This Macro might destroy the AX register.
+;----------------------------------------------------------------------------
+
+UserDStoES macro
+ mov ax,_DATA
+ mov es,ax
+ endm
+
+UserDStoDS macro
+ mov ax,_DATA
+ mov ds,ax
+ endm
+
+WF_PMODE = 0001h
+WF_CPU286 = 0002h
+WF_CPU386 = 0004h
+WF_WIN286 = 0010h
+WF_WIN386 = 0020h
+WF_LARGEFRAME = 0100h
+WF_SMALLFRAME = 0200h
+endif ; !WOW
+
+endif ; LAYER_INCLUDE
diff --git a/private/mvdm/wow16/user/user.rc b/private/mvdm/wow16/user/user.rc
new file mode 100644
index 000000000..f5e6f5eac
--- /dev/null
+++ b/private/mvdm/wow16/user/user.rc
@@ -0,0 +1,59 @@
+/****************************************************************************/
+/* */
+/* USER.RC - */
+/* */
+/* USER's Resource File */
+/* */
+/****************************************************************************/
+
+#include "strtable.h"
+#include "netdlg.h"
+
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+
+ STR_NETDRIVER "NETWORK.DRV"
+ STR_BOOT "boot"
+ STR_LANGDRIVER "LANGUAGE.DLL"
+ STR_SYSTEMINI "SYSTEM.INI"
+ STR_TASKMAN "TASKMAN.EXE"
+ STR_DRIVERS "DRIVERS"
+
+/* Strings used for device driver initialization which we don't want hanging
+ * around our ds.
+ */
+ STR_COMMMODULENAME, "COMM"
+ STR_COMMWRITESTRING, "COMMWRITESTRING"
+ STR_COMMREADSTRING, "READCOMMSTRING"
+ STR_COMMENABLENOTIFICATION "ENABLENOTIFICATION"
+
+/*---------------------------------------------------------------------------*/
+/* All strings above this line MUST NOT be localized. All strings below
+ * this line should be localized.
+ */
+ STR_NETCONNTTL "Error Restoring Network Connections"
+ STR_NETCONNMSG "Cannot connect to %s: %s"
+ STR_NETCRASHEDTITLE "Error Restoring Network Connections"
+ STR_NETCRASHEDMSG "Windows was restarted while restoring network connections. Retry establishing connections or cancel net connections for this session?"
+
+ STR_NETERRORS "Unexpected network error: 0x%4.4X"
+ STR_NETERRORS+1 "Network function not supported"
+ STR_NETERRORS+2 "Network error"
+ STR_NETERRORS+6 "Incorrect password"
+ STR_NETERRORS+7 "Access denied"
+ STR_NETERRORS+11 "Out of memory"
+ STR_NETERRORS+0x30 "Device not connected"
+ STR_NETERRORS+0x31 "Device has open files"
+ STR_NETERRORS+0x32 "Invalid network name"
+ STR_NETERRORS+0x33 "Invalid local device"
+ STR_NETERRORS+0x34 "Device already connected"
+ STR_NETERRORS+0x35 "Connection has gone down"
+ STR_NETERRORS+0x36 "Permanant connection not available"
+
+ STR_SYSERR, "System Error"
+ STR_DIVBYZERO, "Divide By Zero or Overflow Error"
+
+END
+
+#include "user.rcv"
diff --git a/private/mvdm/wow16/user/user.rcv b/private/mvdm/wow16/user/user.rcv
new file mode 100644
index 000000000..d38985b6a
--- /dev/null
+++ b/private/mvdm/wow16/user/user.rcv
@@ -0,0 +1,16 @@
+/********************************************************************/
+/* USER.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows User-interface core component"
+#define VER_INTERNALNAME_STR "USER"
+#define VER_ORIGINALFILENAME_STR "USER.EXE"
+
+
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/user/user1a.asm b/private/mvdm/wow16/user/user1a.asm
new file mode 100644
index 000000000..51baa59f0
--- /dev/null
+++ b/private/mvdm/wow16/user/user1a.asm
@@ -0,0 +1,88 @@
+;
+; USER1A.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER.ASM 9-Jun-92 by BobDay
+;
+;--
+
+ TITLE USER1A.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+externFP GetModuleHandle
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+ UserThunk DELETEMENU
+ UserThunk DESKTOPWNDPROC
+ DUserThunk DESTROYCARET,0
+ UserThunk DESTROYCURSOR
+ UserThunk DESTROYICON
+ UserThunk DESTROYMENU
+ UserThunk DESTROYWINDOW
+; UserThunk DIALOGBOX ; defined in fastres.c
+; UserThunk DIALOGBOXINDIRECT
+; UserThunk DIALOGBOXINDIRECTPARAM
+
+FUN_WOWDIALOGBOXPARAM EQU FUN_DIALOGBOXPARAM
+ DUserThunk WOWDIALOGBOXPARAM, %(size DIALOGBOXPARAM16)
+
+ DUserThunk DISABLEOEMLAYER
+ UserThunk DISPATCHMESSAGE
+ UserThunk DLGDIRLIST
+ UserThunk DLGDIRLISTCOMBOBOX
+ UserThunk DLGDIRSELECT
+ UserThunk DLGDIRSELECTCOMBOBOX
+ UserThunk DRAGDETECT
+ UserThunk DRAGOBJECT
+ UserThunk DRAWFOCUSRECT
+ UserThunk DRAWICON
+ UserThunk DRAWMENUBAR
+ UserThunk DRAWTEXT
+; DUserThunk DUMPICON ; LOCALAPI in rmload.c
+; UserThunk EDITWNDPROC ; LOCALAPI in wsubcls.c
+ DUserThunk EMPTYCLIPBOARD,0
+ DUserThunk ENABLEHARDWAREINPUT
+ DUserThunk ENABLEOEMLAYER
+ UserThunk ENABLEWINDOW
+ UserThunk ENDDEFERWINDOWPOS
+ UserThunk ENDDIALOG
+ DUserThunk ENDMENU
+ UserThunk ENDPAINT
+ UserThunk ENUMCHILDWINDOWS
+ DUserThunk ENUMCLIPBOARDFORMATS
+ UserThunk ENUMPROPS
+ UserThunk ENUMTASKWINDOWS
+ UserThunk ENUMWINDOWS
+;;; UserThunk EQUALRECT ; LOCALAPI in winrect.asm
+ UserThunk ESCAPECOMMFUNCTION
+ UserThunk EXCLUDEUPDATERGN
+ DUserThunk EXITWINDOWS
+
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/user/user2.asm b/private/mvdm/wow16/user/user2.asm
new file mode 100644
index 000000000..acaea78fe
--- /dev/null
+++ b/private/mvdm/wow16/user/user2.asm
@@ -0,0 +1,137 @@
+;
+; USER2.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER.ASM 9-Jun-92 by BobDay
+;
+;--
+
+ TITLE USER2.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+externFP GetModuleHandle
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+
+;*--------------------------------------------------------------------------*
+;*
+;* CheckDisplayHandle()
+;*
+;* Checks to see if the handle passed in is the handle for the DISPLAY
+;* driver. If that is the case then we change the parameter to NULL.
+;* This is to make applications like Winword 1.1a able to load cursors,icons
+;* and bitmaps from the 32 bit display driver.
+;*
+;*--------------------------------------------------------------------------*
+
+display DB 'DISPLAY',0
+
+cProc CheckDisplayHandle, <PUBLIC, NEAR>
+parmW hInstance ; Callers Parameters
+parmD lpName ; Callers
+parmD lpReturn ; Callers Return Address
+cBegin
+ pusha
+
+ push cs
+ push offset display
+ Call GetModuleHandle
+ cmp ax,hInstance
+ jnz @f
+
+ mov hInstance,0h ; Change Callers parameter to NULL
+@@:
+ popa
+
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+cEnd <nogen>
+
+
+
+ UserThunk FARCALLNETDRIVER
+ UserThunk FILEPORTDLGPROC
+ UserThunk FILLRECT
+ DUserThunk FILLWINDOW,8 ;Needs to be exposed in WIN32
+ DUserThunk FINALUSERINIT
+ UserThunk FINDWINDOW
+ UserThunk FLASHWINDOW
+ UserThunk FLUSHCOMM
+ UserThunk FRAMERECT
+ DUserThunk GETACTIVEWINDOW,0
+ DUserThunk GETASYNCKEYSTATE
+ DUserThunk GETCAPTURE,0
+ DUserThunk GETCARETBLINKTIME,0
+ DUserThunk GETCARETPOS
+ UserThunk GETCLASSINFO
+ UserThunk GETCLASSLONG
+ UserThunk GETCLASSWORD
+ DUserThunk GETCLIPBOARDDATA
+ UserThunk GETCLIPBOARDFORMATNAME
+ DUserThunk GETCLIPBOARDOWNER,0
+ DUserThunk GETCLIPBOARDVIEWER,0
+ UserThunk GETCOMMERROR
+ UserThunk GETCOMMEVENTMASK
+ UserThunk GETCOMMSTATE
+ DUserThunk GETCONTROLBRUSH
+ UserThunk GETDC
+ DUserThunk GETDIALOGBASEUNITS,0
+ UserThunk GETDLGCTRLID
+ UserThunk GETDLGITEMINT
+ UserThunk GETDLGITEMTEXT
+ DUserThunk GETDOUBLECLICKTIME,0
+ DUserThunk GETFILEPORTNAME
+ DUserThunk GETFOCUS,0
+ DUserThunk GETICONID
+ DUserThunk GETINPUTSTATE,0
+ DUserThunk GETINTERNALWINDOWPOS
+ UserThunk GETLASTACTIVEPOPUP
+ DUserThunk GETMENUCHECKMARKDIMENSIONS,0
+ UserThunk GETMENUSTRING
+ UserThunk GETMESSAGE
+ DUserThunk GETMESSAGE2
+ DUserThunk GETMESSAGEPOS,0
+ DUserThunk GETMESSAGETIME,0
+;;; DUserThunk GETMOUSEEVENTPROC ; local api in winmisc2.asm
+ UserThunk GETNEXTDLGGROUPITEM
+ UserThunk GETNEXTDLGTABITEM
+ UserThunk GETNEXTQUEUEWINDOW
+ UserThunk GETPRIORITYCLIPBOARDFORMAT
+ UserThunk GETPROP
+ UserThunk GETQUEUESTATUS
+ UserThunk GETSCROLLPOS
+ UserThunk GETSCROLLRANGE
+;;; DUserThunk GETSYSMODALWINDOW,0 ; local api in winmisc1.asm
+ UserThunk GETSYSTEMMENU
+ UserThunk GETTABBEDTEXTEXTENT
+ UserThunk GETTASKFROMHWND
+ DUserThunk GETTIMERRESOLUTION
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/user/user2a.asm b/private/mvdm/wow16/user/user2a.asm
new file mode 100644
index 000000000..6229374d7
--- /dev/null
+++ b/private/mvdm/wow16/user/user2a.asm
@@ -0,0 +1,124 @@
+;
+; USER2A.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER.ASM 9-Jun-92 by BobDay
+;
+;--
+
+ TITLE USER2A.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+externFP GetModuleHandle
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+ UserThunk GETUPDATERECT
+ UserThunk GETUPDATERGN
+ UserThunk GETWC2
+ UserThunk GETWINDOWDC
+ DUserThunk GETWINDOWLONG
+ UserThunk GETWINDOWTASK
+ EUserThunk GETWINDOWTEXT ;Use the empty buffer user thunk.
+ UserThunk GETWINDOWTEXTLENGTH
+ DUserThunk GETWINDOWWORD
+ DUserThunk GLOBALADDATOM
+ DUserThunk GLOBALDELETEATOM
+ UserThunk GLOBALFINDATOM
+ DUserThunk GLOBALGETATOMNAME
+ UserThunk GRAYSTRING
+ UserThunk HIDECARET
+ UserThunk HILITEMENUITEM
+ DUserThunk ICONSIZE ;;;;;;
+;;; UserThunk INFLATERECT ; LOCALAPI in winrect.asm
+;;; DUserThunk INITAPP ;LOCALAPI in user.asm
+ DUserThunk INSENDMESSAGE,0
+ UserThunk INSERTMENU
+;;; UserThunk INTERSECTRECT ; LOCALAPI in winrect.asm
+ UserThunk INVALIDATERECT
+ UserThunk INVALIDATERGN
+ UserThunk INVERTRECT
+
+ ; Hack to use original IDs. These functions have local implementations
+ ; that thunk to Win32 if the locale is other than U.S. English.
+
+ FUN_WIN32ISCHARALPHA equ FUN_ISCHARALPHA
+ FUN_WIN32ISCHARALPHANUMERIC equ FUN_ISCHARALPHANUMERIC
+ FUN_WIN32ISCHARLOWER equ FUN_ISCHARLOWER
+ FUN_WIN32ISCHARUPPER equ FUN_ISCHARUPPER
+
+ DUserThunk WIN32ISCHARALPHA, %(size ISCHARALPHA16)
+ DUserThunk WIN32ISCHARALPHANUMERIC, %(size ISCHARALPHANUMERIC16)
+ DUserThunk WIN32ISCHARLOWER, %(size ISCHARLOWER16)
+ DUserThunk WIN32ISCHARUPPER, %(size ISCHARUPPER16)
+
+ DUserThunk ISCLIPBOARDFORMATAVAILABLE
+ UserThunk ISDIALOGMESSAGE
+ UserThunk ISDLGBUTTONCHECKED
+;;; UserThunk ISRECTEMPTY ; LOCALAPI in winrect.asm
+ DUserThunk ISTWOBYTECHARPREFIX ;;;;;;
+ DUserThunk ISUSERIDLE
+ DUserThunk KILLSYSTEMTIMER ;;;;;
+ UserThunk KILLTIMER
+ UserThunk KILLTIMER2
+ UserThunk LBOXCARETBLINKER
+;;; UserThunk LBOXCTLWNDPROC ;LOCALAPI in wsubcls.c
+;;; UserThunk LOADACCELERATORS ; localapi in rmload.c
+
+FUN_WOWLOADBITMAP EQU FUN_LOADBITMAP
+ DUserThunk WOWLOADBITMAP, %(size LOADBITMAP16)
+
+FUN_WOWLOADCURSORICON EQU FUN_LOADCURSOR
+ DUserThunk WOWLOADCURSORICON, %(size LOADCURSOR16)
+
+ DUserThunk LOADCURSORICONHANDLER
+ DUserThunk LOADDIBCURSORHANDLER
+ DUserThunk LOADDIBICONHANDLER
+
+;FUN_WOWLOADICON EQU FUN_LOADICON
+; DUserThunk WOWLOADICON, %(size LOADICON16)
+
+ DUserThunk LOADICONHANDLER
+
+FUN_WOWLOADMENU EQU FUN_LOADMENU
+ DUserThunk WOWLOADMENU, %(size LOADMENU16)
+
+ UserThunk LOADMENUINDIRECT
+;;; UserThunk LOADSTRING ;LOCALAPI in rmload.c
+ DUserThunk LOCKMYTASK
+ DUserThunk LOOKUPMENUHANDLE
+
+ ; Hack to use original IDs. These functions have local implementations
+ ; that thunk to Win32 if the locale is other than U.S. English.
+ FUN_WIN32LSTRCMP equ FUN_LSTRCMP
+ FUN_WIN32LSTRCMPI equ FUN_LSTRCMPI
+
+ DUserThunk WIN32LSTRCMP, %(size LSTRCMP16)
+ DUserThunk WIN32LSTRCMPI, %(size LSTRCMPI16)
+
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/user/user3.asm b/private/mvdm/wow16/user/user3.asm
new file mode 100644
index 000000000..27a4240e3
--- /dev/null
+++ b/private/mvdm/wow16/user/user3.asm
@@ -0,0 +1,108 @@
+;
+; USER3.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER2.ASM 4-Dec-92 by barryb
+;
+;--
+
+ TITLE USER3.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+
+cProc TouchNotPresentSel, <PUBLIC, NEAR>
+parmD lpsz ; Callers parameter
+parmD lpReturn ; Callers Return Address
+cBegin
+ mov ax,es
+ mov es,word ptr lpsz+2 ; makes NP sel P
+ mov es,ax
+
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+cEnd <nogen>
+
+ UserThunk MAPDIALOGRECT
+ UserThunk MB_DLGPROC
+;;; UserThunk MDICLIENTWNDPROC ;LOCALAPI in wsubcls.c
+ UserThunk MENUITEMSTATE
+ DUserThunk MESSAGEBEEP
+ UserThunk MESSAGEBOX
+ UserThunk MODIFYMENU
+ UserThunk MOVEWINDOW
+;;; UserThunk OFFSETRECT ; LOCALAPI in winrect.asm
+;;; DUserThunk OLDEXITWINDOWS ; LOCALAPI in winutil.asm
+ UserThunk OPENCLIPBOARD
+
+FUN_WOWOPENCOMM EQU FUN_OPENCOMM
+ DUserThunk WOWOPENCOMM %(size OPENCOMM16)
+
+ UserThunk OPENICON
+ DUserThunk PAINTRECT
+ UserThunk PEEKMESSAGE
+ UserThunk POSTAPPMESSAGE
+ UserThunk POSTMESSAGE
+ UserThunk POSTMESSAGE2
+ DUserThunk POSTQUITMESSAGE
+;;; UserThunk PTINRECT ; LOCALAPI in winrect.asm
+
+ UserThunk READCOMM
+ UserThunk REALIZEPALETTE
+ UserThunk REGISTERCLASS
+ UserThunk REGISTERCLIPBOARDFORMAT
+ PDUserThunk REGISTERWINDOWMESSAGE, TouchNotPresentSel
+ DUserThunk RELEASECAPTURE,0
+ UserThunk RELEASEDC
+ UserThunk REMOVEMENU
+ UserThunk REMOVEPROP
+ DUserThunk REPAINTSCREEN
+ DUserThunk REPLYMESSAGE
+;;; UserThunk SBWNDPROC ;LOCALAPI in wsubcls.c
+ DUserThunk SCROLLCHILDREN
+ UserThunk SCROLLDC
+ UserThunk SCROLLWINDOW
+ UserThunk SELECTPALETTE
+ UserThunk SENDDLGITEMMESSAGE
+ UserThunk SENDMESSAGE
+ UserThunk SENDMESSAGE2
+ UserThunk SETACTIVEWINDOW
+ UserThunk SETCAPTURE
+ DUserThunk SETCARETBLINKTIME
+ DUserThunk SETCARETPOS
+ UserThunk SETCLASSLONG
+ UserThunk SETCLASSWORD
+
+FUN_WOWSETCLIPBOARDDATA EQU FUN_SETCLIPBOARDDATA
+ DUserThunk WOWSETCLIPBOARDDATA, %(size SETCLIPBOARDDATA16)
+
+ UserThunk SETCLIPBOARDVIEWER
+
+sEnd CODE
+
+end
+
diff --git a/private/mvdm/wow16/user/user3a.asm b/private/mvdm/wow16/user/user3a.asm
new file mode 100644
index 000000000..da5024e2b
--- /dev/null
+++ b/private/mvdm/wow16/user/user3a.asm
@@ -0,0 +1,228 @@
+;
+; USER3A.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER2.ASM 4-Dec-92 by barryb
+; Split off user3a.asm from user3.asm 2-May-95 davehart
+;
+;--
+
+ TITLE USER3A.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+;*--------------------------------------------------------------------------*
+;*
+;* CheckMsgForTranslate, CheckAccMsgForTranslate, CheckMDIAccMsgForTranslate
+;*
+;* Checks to see if the message number in the message is one of those
+;* that the system actually uses. If not, then the API just returns with
+;* a 0 in AX. This saves the 16-32-16 bit transition for most messages.
+;*
+;*--------------------------------------------------------------------------*
+
+ALIGN 16
+cProc CheckMsgForTranslate, <PUBLIC, NEAR>
+parmD lpMsg ; Callers parameter
+parmD lpReturn ; Callers Return Address
+;parmW wBP ; Thunk saved BP
+;parmW wDS ; Thunk saved DS
+cBegin
+ les bx,lpMsg ; load msg address into es:bx
+ mov ax,es:[bx+2] ; load message number
+; we are looking for ,WM_KEYDOWN, KEYUP, SYSKEYDOWN, SYSKEYUP
+; in other words, 100, 101, 104, amd 105 hex
+
+ and ax,0fffah ; wipe out 2 bits that are variable
+ xor ax, 0100h ; compensate for bit that must be on
+ jz @f
+
+; cmp ax,WM_KEYDOWN
+; jz @f
+; cmp ax,WM_KEYUP
+; jz @f
+; cmp ax,WM_SYSKEYDOWN
+; jz @f
+; cmp ax,WM_SYSKEYUP
+; jz @f
+
+
+ sub ax,ax ; flag not translated
+ pop bp
+ add sp,2 ; skip thunk IP
+ retf 4 ; lpMsg -- 4 bytes to pop
+
+@@:
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+cEnd <nogen>
+
+ALIGN 16
+cProc CheckAccMsgForTranslate, <PUBLIC, NEAR>
+parmW hWnd
+parmW hAccTbl
+parmD lpMsg ; Callers parameter
+parmD lpReturn ; Callers Return Address
+cBegin
+
+ test hWnd,0ffffh
+ jz SHORT t_not
+
+ les bx,lpMsg ; load msg address into es:bx
+ mov ax,es:[bx+2] ; load message number
+; we are looking for ,WM_KEYDOWN, CHAR, SYSKEYDOWN, SYSCHAR
+; in other words, 100, 102, 104, amd 106 hex
+
+ and ax,0fff9h ; wipe out 2 bits that are variable
+ xor ax, 0100h ; compensate for bit that must be on
+ jz @f
+
+; cmp ax,WM_KEYDOWN
+; jz @f
+; cmp ax,WM_CHAR
+; jz @f
+; cmp ax,WM_SYSKEYDOWN
+; jz @f
+; cmp ax,WM_SYSCHAR
+; jz @f
+
+t_not:
+ sub ax,ax ; flag not translated
+ pop bp
+ add sp,2 ; skip thunk IP
+ retf 8 ; 8 bytes to pop
+
+@@:
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+cEnd <nogen>
+
+ALIGN 16
+cProc CheckMDIAccMsgForTranslate, <PUBLIC, NEAR>
+parmD lpMsg ; Callers parameter
+parmD lpReturn ; Callers Return Address
+cBegin
+ les bx,lpMsg ; load msg address into es:bx
+ mov ax,es:[bx+2] ; load message number
+; we are looking for ,WM_KEYDOWN, SYSKEYDOWN
+; in other words, 100, 104
+
+ and ax,0fffbh ; wipe out 1 bit that is variable
+ xor ax, 0100h ; compensate for bit that must be on
+ jz @f
+
+; cmp ax,WM_KEYDOWN
+; jz @f
+; cmp ax,WM_KEYUP
+; jz @f
+; cmp ax,WM_SYSKEYDOWN
+; jz @f
+; cmp ax,WM_SYSKEYUP
+; jz @f
+ sub ax,ax ; flag not translated
+ pop bp
+ add sp,2 ; skip thunk IP
+ retf 6 ; 6 bytes to pop
+
+@@:
+ mov sp,bp ; Do cEnd without Ret count (leave parameters there)
+ pop bp
+ ret
+cEnd <nogen>
+
+
+ UserThunk SETCOMMBREAK
+ UserThunk SETCOMMEVENTMASK
+ UserThunk SETCOMMSTATE
+ UserThunk SETCURSOR
+ DUserThunk SETCURSORPOS
+ UserThunk SETDESKPATTERN
+ UserThunk SETDESKWALLPAPER
+ UserThunk SETDLGITEMINT
+ UserThunk SETDLGITEMTEXT
+ DUserThunk SETDOUBLECLICKTIME
+ UserThunk SETEVENTHOOK
+ UserThunk SETFOCUS
+ UserThunk SETGETKBDSTATE
+ UserThunk SETGRIDGRANULARITY
+ DUserThunk SETINTERNALWINDOWPOS
+ UserThunk SETKEYBOARDSTATE
+ UserThunk SETMENU
+ UserThunk SETMENUITEMBITMAPS
+ DUserThunk SETMESSAGEQUEUE
+ UserThunk SETPARENT
+ UserThunk SETPROP
+;;; UserThunk SETRECT ; LOCALAPI in winrect.asm
+;;; UserThunk SETRECTEMPTY ; LOCALAPI in winrect.asm
+ UserThunk SETSCROLLPOS
+ UserThunk SETSCROLLRANGE
+ UserThunk SETSYSCOLORS
+;;; UserThunk SETSYSMODALWINDOW ; local api in winmisc1.asm
+ UserThunk SETSYSTEMMENU
+ DUserThunk SETSYSTEMTIMER ;;;;;;;
+ UserThunk SETTIMER
+ UserThunk SETTIMER2
+ UserThunk SETWC2
+ UserThunk SETWINDOWLONG
+ UserThunk SETWINDOWPOS
+ DUserThunk SETWINDOWSHOOKINTERNAL
+ UserThunk SETWINDOWTEXT
+ UserThunk SETWINDOWWORD
+ UserThunk SHOWCARET
+ DUserThunk SHOWCURSOR
+ UserThunk SHOWOWNEDPOPUPS
+ UserThunk SHOWSCROLLBAR
+ UserThunk SHOWWINDOW
+ DUserThunk SIGNALPROC
+ UserThunk SNAPWINDOW
+;;; UserThunk STATICWNDPROC ;LOCALAPI in wsubcls.c
+;;; UserThunk STRINGFUNC ;LOCALAPI in winlang.asm
+ DUserThunk SWAPMOUSEBUTTON
+ DUserThunk SWITCHTOTHISWINDOW
+ UserThunk SWITCHWNDPROC
+ DUserThunk SYSERRORBOX
+ UserThunk TABBEDTEXTOUT
+ UserThunk TABTHETEXTOUTFORWIMPS
+ DUserThunk TILECHILDWINDOWS
+ UserThunk TITLEWNDPROC
+ UserThunk TRACKPOPUPMENU
+ PUserThunk TRANSLATEACCELERATOR,CheckAccMsgForTranslate
+ PUserThunk TRANSLATEMDISYSACCEL,CheckMDIAccMsgForTranslate
+ PUserThunk TRANSLATEMESSAGE,CheckMsgForTranslate
+ UserThunk TRANSMITCOMMCHAR
+ UserThunk UNGETCOMMCHAR
+ UserThunk UNHOOKWINDOWSHOOK
+;;; UserThunk UNIONRECT ; LOCALAPI in winrect.asm
+ UserThunk UNREGISTERCLASS
+ UserThunk UPDATEWINDOW
+ DUserThunk USERYIELD
+
+sEnd CODE
+
+end
+
diff --git a/private/mvdm/wow16/user/user4.asm b/private/mvdm/wow16/user/user4.asm
new file mode 100644
index 000000000..9a328d064
--- /dev/null
+++ b/private/mvdm/wow16/user/user4.asm
@@ -0,0 +1,139 @@
+;
+; USER4.ASM
+; More Win16 USER thunks
+;
+; History:
+;
+; Created 25-Jan-1991 by Jeff Parsons (jeffpar)
+; Added Win 31 thunks 22nd-March-1992 by Chandan S. Chauhan (ChandanC)
+; Split off from USER2.ASM 4-Dec-92 by barryb
+; Split off from USER3.ASM 26-May-93 by bobday
+;
+;--
+
+ TITLE USER4.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+
+ .list
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+ UserThunk VALIDATERECT
+ UserThunk VALIDATERGN
+ DUserThunk WAITMESSAGE,0
+ DUserThunk WINDOWFROMPOINT
+;;; UserThunk WINFARFRAME ;LOCALAPI in winstack.asm
+;;; UserThunk WINHELP
+ DUserThunk WINOLDAPPHACKOMATIC
+ DUserThunk WOWWORDBREAKPROC
+;;; UserThunk WNETADDCONNECTION
+;;; UserThunk WNETBROWSEDIALOG
+;;; UserThunk WNETCANCELCONNECTION
+;;; UserThunk WNETCANCELJOB
+;;; UserThunk WNETCLOSEJOB
+;;; UserThunk WNETDEVICEMODE
+;;; UserThunk WNETGETCAPS
+;;; UserThunk WNETGETCONNECTION
+;;; UserThunk WNETGETERROR
+;;; UserThunk WNETGETERRORTEXT
+;;; UserThunk WNETGETUSER
+;;; UserThunk WNETHOLDJOB
+;;; UserThunk WNETLOCKQUEUEDATA
+;;; UserThunk WNETOPENJOB
+;;; UserThunk WNETRELEASEJOB
+;;; UserThunk WNETSETJOBCOPIES
+;;; UserThunk WNETUNLOCKQUEUEDATA
+;;; UserThunk WNETUNWATCHQUEUE
+;;; UserThunk WNETWATCHQUEUE
+ UserThunk WRITECOMM
+;;; UserThunk WVSPRINTF ;LOCALAPI in wsprintf.c
+ UserThunk XCSTODS
+ DUserThunk _FFFE_FARFRAME
+;;; UserThunk _WSPRINTF ;LOCALAPI in wsprintf.c
+ UserThunk SETWINDOWSHOOKEX
+ UserThunk UNHOOKWINDOWSHOOKEX
+ UserThunk CALLNEXTHOOKEX
+
+;;;;;
+;;;;; Win 3.1 Thunks
+;;;;;
+
+ DUserThunk QUERYSENDMESSAGE
+ DUserThunk USERSEEUSERDO
+ DUserThunk LOCKINPUT
+; DUserThunk GETSYSTEMDEBUGSTATE, 0
+ UserThunk ENABLECOMMNOTIFICATION
+ UserThunk EXITWINDOWSEXEC
+ DUserThunk GETCURSOR, 0
+ DUserThunk GETOPENCLIPBOARDWINDOW, 0
+; UserThunk SENDDRIVERMESSAGE
+; UserThunk OPENDRIVER
+; UserThunk CLOSEDRIVER
+; UserThunk GETDRIVERMODULEHANDLE
+; UserThunk DEFDRIVERPROC
+; UserThunk GETDRIVERINFO
+; UserThunk GETNEXTDRIVER
+ UserThunk MAPWINDOWPOINTS
+ DUserThunk OLDSETDESKPATTERN
+ DUserThunk GETFREESYSTEMRESOURCES
+ DUserThunk OLDSETDESKWALLPAPER ;;;;;;
+ DUserThunk GETMESSAGEEXTRAINFO, 0
+;;; DUserThunk KEYBD_EVENT ; local API in winmisc2.asm
+ DUserThunk KEYBDEVENT
+ UserThunk REDRAWWINDOW
+ UserThunk LOCKWINDOWUPDATE
+;; DUserThunk MOUSE_EVENT ;; in winmisc2.asm
+ DUserThunk MOUSEEVENT
+;; DUserThunk MENUWINDOWPROC ;;;;;; in wclass.asm
+ UserThunk GETCLIPCURSOR
+ UserThunk SCROLLWINDOWEX
+ DUserThunk ISMENU
+ UserThunk GETDCEX
+;; UserThunk COPYICON ;;;; in rmcreate.c
+;; UserThunk COPYCURSOR ;;;; in rmcreate.c
+ UserThunk GETWINDOWPLACEMENT
+ UserThunk SETWINDOWPLACEMENT
+ UserThunk GETINTERNALICONHEADER
+;;; UserThunk SUBTRACTRECT ; LOCALAPI in winrect.asm
+ UserThunk DLGDIRSELECTEX
+ UserThunk DLGDIRSELECTCOMBOBOXEX
+ DUserThunk GETUSERLOCALOBJTYPE
+ DUserThunk HARDWARE_EVENT
+ UserThunk ENABLESCROLLBAR
+ UserThunk SYSTEMPARAMETERSINFO
+; UserThunk GP
+;;; DUserThunk WNETERRORTEXT
+;;; UserThunk WNETABORTJOB
+;;; DUserThunk WNETENABLE
+;;; DUserThunk WNETDISABLE
+;;; DUserThunk WNETRESTORECONNECTION
+;;; DUserThunk WNETWRITEJOB
+;;; DUserThunk WNETCONNECTDIALOG
+;;; DUserThunk WNETDISCONNECTDIALOG
+;;; DUserThunk WNETCONNECTIONDIALOG
+;;; DUserThunk WNETVIEWQUEUEDIALOG
+;;; DUserThunk WNETPROPERTYDIALOG
+;;; DUserThunk WNETGETDIRECTORYTYPE
+;;; DUserThunk WNETDIRECTORYNOTIFY
+;;; DUserThunk WNETGETPROPERTYTEXT
+ DUserThunk NOTIFYWOW
+ DUserThunk WOWGETIDFROMDIRECTORY
+sEnd CODE
+
+end
diff --git a/private/mvdm/wow16/user/usercli.asm b/private/mvdm/wow16/user/usercli.asm
new file mode 100644
index 000000000..672dc77b2
--- /dev/null
+++ b/private/mvdm/wow16/user/usercli.asm
@@ -0,0 +1,562 @@
+;---------------------------------------------------------------------------
+; Optimzed Code Path - on x86 builds effectively excecutes USER32 code.
+;
+; Created:
+; 16-DEC-93 nandurir
+;---------------------------------------------------------------------------
+ TITLE USER5.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include ks386p.inc
+ .286p
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include wow.inc
+ include wowusr.inc
+ ;;;;;include cmacros.inc
+ include user.inc
+
+ .list
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+externFP WowSetCompatHandle
+;---------------------------------------------------------------------------
+; Optimized thunks for x86 only
+;
+;
+;---------------------------------------------------------------------------
+
+ifndef PMODE32
+
+ USER16CLIENTTHUNK macro Iapi, api
+ sBegin CODE
+ &Iapi &api
+ sEnd CODE
+ endm
+
+else
+
+externFP OutputDebugString
+LOGARGS macro apiname
+ push dx
+ push ax
+ push cs
+ push OFFSET afterlog_&apiname
+ call OutputDebugString
+ pop ax
+ pop dx
+ jmp short afterlogname_&apiname
+afterlog_&apiname: DB 'USER: ','&apiname','()', 0dh, 0ah, 0
+afterlogname_&apiname:
+
+
+endm
+; flat selector values
+;
+
+FLATDS equ KGDT_R3_DATA OR RPL_MASK
+FLATFS equ KGDT_R3_TEB OR RPL_MASK
+
+; set flat ds and fs
+;
+
+SETFLATDSANDFS macro
+.386p
+ mov ax, FLATDS
+ mov ds, ax
+ mov ax, FLATFS
+ mov fs, ax
+endm
+
+externFP GetSelectorBase
+GETFLATADDRESS macro farpointer
+ ; check for null
+ xor dx, dx
+ mov ax, word ptr &farpointer+2
+ or ax, ax
+ jz @F
+ cCall GetSelectorBase, <ax>
+
+ ; check for base address 0
+
+ mov cx, ax
+ or cx, dx
+ jz @F
+
+ ; now its ok
+
+ add ax, word ptr &farpointer
+ adc dx, 0
+@@:
+endm
+
+; generates code like: parmW arg1
+;
+
+GENPARAM macro argtype, argname
+ parm&argtype &argname
+endm
+
+
+pushWORD_DWORD macro argname
+ movzx eax, &argname
+ push eax
+endm
+
+pushINT_LONG macro argname
+ movsx eax, &argname
+ push eax
+endm
+
+pushDWORD_DWORD macro argname
+ push dword ptr &argname
+endm
+
+pushPSZ_DWORD macro argname, apiname, argnumber
+
+ GETFLATADDRESS &argname
+ push dx
+ push ax
+
+ IFNB <apiname>
+ or ax, dx
+ jnz @F
+ add sp, argnumber * 4
+ xor eax, eax
+ jmp short FailCall_&apiname
+ @@:
+ ENDIF
+
+endm
+
+pushLPRECT_FLAT macro argname
+ push dword ptr -1 ; unreferenced parameter
+ ; effectively an assertion
+endm
+
+pushHHOOK_DWORD macro argname
+ push dword ptr -1 ; unreferenced parameter
+ ; effectively an assertion
+endm
+
+pushARG16 macro argname
+ push &argname
+endm
+
+CALLORDECLARE macro typestring, api32, totalbytes
+ &typestring api32&@&totalbytes
+endm
+
+TESTCALLSERVERCONDITION macro
+ mov edx, DWORD PTR _wow16CsrFlag
+ test BYTE PTR [edx], 1
+endm
+
+; assumes eax is pointer to the flag
+CLEARCALLSERVERCONDITION macro
+ mov BYTE PTR [edx], 0
+endm
+
+;--------------------------------------------------------------------------
+; Iapi = either DUserThunk or UserThunk
+; api = actual name
+; argtypeslist = list of argument 'types' like <WORD, INT, HWND>
+; api32 = this function is called instead of _Api
+; apispecificcode = flag indicating additional code needed for this api.
+; This is intended for handling 'compatibility'.
+;
+; If this argument is not blank, then there must exist a macro
+; APISPECIFICCODE_api, which expands to the desired code.
+; At present it is included just before the 'return' to
+; the app.
+;
+; callserver = flag indication that it may be necessary to actually call
+; USER32.
+;
+; If this argument is not blank, then there must exist a macro
+; CALLSERVERCONDITION_api which expands to the desired code and
+; clears or sets the zero flag. If ZF is clear, the actual
+; thunk gets called, else nop.
+;
+;
+; generates code similar to:
+;
+; externFP _Api OR Api32
+; sBegin CODE
+; if necessary
+; FUN_WOWApi equ FUN_Api
+; DUserThunk WOWApi, %(size Api16)
+; endif
+;
+; cProc Api, <PUBLIC, FAR, PASCAL>, <ds>
+; parmW arg1
+; cBegin
+; movzx, eax, arg1
+; push eax
+; call far ptr _Api OR Api32 (decorates the names)
+;
+; if necessary checks the callservercondtion
+; resets the callservercondition
+; push arg1
+; call WOWApi ; the actual thunk to wow32/server
+; @@:
+; endif
+;
+; if exists, includes code in apispecificcode_api
+; endif
+; cEnd
+; sEnd CODE
+;
+; - nanduri
+;--------------------------------------------------------------------------
+
+
+USER16CLIENTTHUNK macro Iapi, api, argtypeslist, returntype, api32, apispecificcode, callserver
+
+ ;*** declare api
+ ;
+
+ index = 0;
+ IRP argtype, <argtypeslist>
+ index = index + 1
+ ENDM
+
+ IFB <api32>
+ CALLORDECLARE <externFP>, _&api, %(index*4)
+ ELSE
+ CALLORDECLARE <externFP>, _&api32, %(index*4)
+ ENDIF
+
+ sBegin CODE ; _&api
+
+ ;*** create thunk to wow32
+ ;
+
+ IFNB <callserver>
+ FUN_WOW&api equ FUN_&api
+ DUserThunk WOW&api, %(size api&16)
+ ENDIF
+
+ ;*** create thea Api label
+ ;
+
+ IFNB <api>
+ IFIDNI <Iapi>, <DUSERTHUNK>
+ cProc &api, <PUBLIC, FAR, PASCAL>, <ds>
+ ELSE
+ cProc I&api, <PUBLIC, FAR, PASCAL>, <ds>
+ ENDIF
+ ENDIF
+
+ ;*** declare args
+ ;
+
+ nargcount = 0
+ IRP argtype, <argtypeslist>
+ nargcount = nargcount + 1
+ IFIDNI <argtype>, <WORD>
+ genparam W, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <INT>
+ genparam W, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <SHORT>
+ genparam W, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <DWORD>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <LONG>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <ULONG>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <PSZ>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <NONOPTPSZ>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <HWND>
+ genparam W, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <LPRECTO>
+ genparam D, arg%(nargcount)
+ ENDIF
+ IFIDNI <argtype>, <HHOOK>
+ genparam D, arg%(nargcount)
+ ENDIF
+ ENDM
+
+ ;*** begin body
+ ;
+
+ cBegin
+
+ ;*** set 32bit registers
+ ;
+
+ SETFLATDSANDFS
+
+ ;*** push args in reverse
+ ;
+
+ FailCall = 0
+ argtopush = nargcount
+ REPT nargcount
+ inputargindex = 0
+ IRP argtype, <argtypeslist>
+ inputargindex = inputargindex + 1
+ IFE argtopush - inputargindex
+ IFIDNI <argtype>, <WORD>
+ pushWORD_DWORD arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <INT>
+ pushINT_LONG arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <SHORT>
+ pushINT_LONG arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <DWORD>
+ pushDWORD_DWORD arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <LONG>
+ pushDWORD_DWORD arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <ULONG>
+ pushDWORD_DWORD arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <PSZ>
+ pushPSZ_DWORD arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <NONOPTPSZ>
+ FailCall = argtopush ; fails call if null
+ pushPSZ_DWORD arg%argtopush, &api, %argtopush
+ ENDIF
+ IFIDNI <argtype>, <HWND>
+ pushINT_LONG arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <LPRECTO>
+ pushLPRECT_FLAT arg%argtopush
+ ENDIF
+ IFIDNI <argtype>, <HHOOK>
+ pushHHOOK_DWORD arg%argtopush
+ ENDIF
+ ENDIF
+ ENDM
+ argtopush = argtopush - 1
+ ENDM
+
+ ;*** called user32/client api
+ ;
+
+ IFB <api32>
+ CALLORDECLARE <call>, _&api, %(nargcount*4)
+ ELSE
+ CALLORDECLARE <call>, _&api32, %(nargcount*4)
+ ENDIF
+
+ ;*** check if we ever need to call server
+ ;*** calls the real wow thunk
+
+ IFNB <callserver>
+ TESTCALLSERVERCONDITION
+ jz @F
+ CLEARCALLSERVERCONDITION
+ index = 0;
+ IRP argtype, <argtypeslist>
+ index = index + 1
+ pushARG16 arg%index
+ ENDM
+ call WOW&api
+ @@:
+ ENDIF
+
+ ;*** check for any api specific compatibility code to execute
+ ;
+
+ IFNB <apispecificcode>
+ APISPECIFICCODE_&api
+ ENDIF
+
+ IF FailCall
+ FailCall_&api:
+ ENDIF
+
+ IFNB <returntype>
+ IRP argtype, <dword, long, ulong>
+ IFIDNI <returntype>, <argtype>
+ mov edx, eax
+ shr edx, 16
+ EXITM
+ ENDIF
+ ENDM
+
+ IFIDNI <returntype>, <boolzero>
+ xor ax, ax
+ ENDIF
+
+ ENDIF
+
+ifdef DEBUG
+ ;LOGARGS &api
+endif
+
+ cEnd
+ ; end body
+
+ sEnd CODE ; _&api
+endm
+
+endif ; PMODE32
+
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+;;;;;;;;;;sBegin CODE ; macro will generate this
+
+COPYRECT macro lprect16, lprect32
+ les bx, &lprect16
+ mov ecx, [&lprect32].rclLeft
+ mov es:[bx].rcLeft, cx
+ mov ecx, [&lprect32].rclTop
+ mov es:[bx].rcTop, cx
+ mov ecx, [&lprect32].rclRight
+ mov es:[bx].rcRight, cx
+ mov ecx, [&lprect32].rclBottom
+ mov es:[bx].rcBottom, cx
+endm
+
+APISPECIFICCODE_GETCLIENTRECT macro
+ xor eax, eax
+endm
+
+APISPECIFICCODE_GETKEYSTATE macro
+ mov cl, ah
+ and cl, 080h
+ or al, cl
+endm
+
+APISPECIFICCODE_GETWINDOWRECT macro
+ or eax, eax
+ jz @F
+ COPYRECT arg2, eax
+ xor eax, eax
+@@:
+endm
+
+; The following call is only for a dBase for Windows 5.0 bug. Notice however, that this
+; means that the internal KERNEL api WowSetCompatHandle will be called for every
+; single invocation of GetDlgItem, no matter what app is running. This is bad, but
+; on X86 platforms we don't transition to WOW32, and the cost of testing for it
+; is just about as expensive as just saving it. Still, this should be removed as
+; soon as we are convinced that the dBase bug has been fixed. -NeilSa
+APISPECIFICCODE_GETDLGITEM macro
+ push ax
+ call WowSetCompatHandle
+endm
+
+public _wow16gpsi
+public _wow16CsrFlag
+
+sBegin CODE
+_wow16gpsi DD 0
+_wow16CsrFlag DD 0
+sEnd CODE
+
+ ; the following may end up calling wow32
+
+ USER16CLIENTTHUNK UserThunk, DEFHOOKPROC, <int, word, dword, hhook>, dword, WOW16DefHookProc,,srvcond
+ USER16CLIENTTHUNK UserThunk, ENABLEMENUITEM, <hwnd, word, word>, word,,,srvcond
+ USER16CLIENTTHUNK DUserThunk, GETKEYSTATE, <int>, int,, compatcode, srvcond
+ USER16CLIENTTHUNK UserThunk, GETKEYBOARDSTATE, <nonoptpsz>, boolzero,,,srvcond
+
+ ; the following are all thunked locally
+
+ USER16CLIENTTHUNK UserThunk, CLIENTTOSCREEN, <hwnd, psz>,boolzero
+ USER16CLIENTTHUNK UserThunk, GETCLASSNAME, <hwnd, psz, word>, word, GETCLASSNAMEA
+ USER16CLIENTTHUNK UserThunk, GETCLIENTRECT, <hwnd, psz>, bool,,compatcode
+ USER16CLIENTTHUNK UserThunk, GETCURSORPOS, <psz>, boolzero
+ USER16CLIENTTHUNK DUserThunk, GETDESKTOPHWND, <>, hwnd, GETDESKTOPWINDOW
+ USER16CLIENTTHUNK DUserThunk, GETDESKTOPWINDOW, <>, hwnd
+ USER16CLIENTTHUNK UserThunk, GETDLGITEM, <hwnd, word>, hwnd,,compatcode
+ USER16CLIENTTHUNK UserThunk, GETMENU, <hwnd>, hmenu
+ USER16CLIENTTHUNK UserThunk, GETMENUITEMCOUNT, <hwnd>, int
+ USER16CLIENTTHUNK UserThunk, GETMENUITEMID, <hwnd, int>, uint
+ USER16CLIENTTHUNK UserThunk, GETMENUSTATE, <hwnd, word, word>, uint
+ USER16CLIENTTHUNK DUserThunk, GETNEXTWINDOW, <hwnd, word>, hwnd, GETWINDOW
+ USER16CLIENTTHUNK UserThunk, GETPARENT, <hwnd>, hwnd
+ USER16CLIENTTHUNK UserThunk, GETSUBMENU, <hwnd, int>, hmenu
+ USER16CLIENTTHUNK UserThunk, GETSYSCOLOR, <int>, dword
+ USER16CLIENTTHUNK UserThunk, GETSYSTEMMETRICS, <int>, int
+ USER16CLIENTTHUNK UserThunk, GETTOPWINDOW, <hwnd>, hwnd
+ USER16CLIENTTHUNK UserThunk, GETWINDOW, <hwnd, word>, hwnd
+ USER16CLIENTTHUNK UserThunk, GETWINDOWRECT, <hwnd, lprectO>,bool,,compatcode
+ USER16CLIENTTHUNK DUserThunk, ISWINDOW, <hwnd>, bool
+ USER16CLIENTTHUNK UserThunk, SCREENTOCLIENT, <hwnd, psz>, boolzero
+ifdef DEBUG
+ USER16CLIENTTHUNK UserThunk, ISCHILD, <hwnd, hwnd>, bool
+ USER16CLIENTTHUNK UserThunk, ISICONIC, <hwnd>, bool
+ USER16CLIENTTHUNK UserThunk, ISWINDOWENABLED, <hwnd>, bool
+ USER16CLIENTTHUNK UserThunk, ISWINDOWVISIBLE, <hwnd>, bool
+ USER16CLIENTTHUNK UserThunk, ISZOOMED, <hwnd>, bool
+else
+ USER16CLIENTTHUNK DUserThunk, ISCHILD, <hwnd, hwnd>, bool
+ USER16CLIENTTHUNK DUserThunk, ISICONIC, <hwnd>, bool
+ USER16CLIENTTHUNK DUserThunk, ISWINDOWENABLED, <hwnd>, bool
+ USER16CLIENTTHUNK DUserThunk, ISWINDOWVISIBLE, <hwnd>, bool
+ USER16CLIENTTHUNK DUserThunk, ISZOOMED, <hwnd>, bool
+endif
+
+
+;;;;;;;;;sEnd CODE ; macro will generate this
+
+sBegin CODE
+
+ifndef PMODE32
+
+ DUserThunk GETTICKCOUNT
+ DUserThunk GETCURRENTTIME
+
+else
+
+labelFP <PUBLIC, GETTICKCOUNT>
+labelFP <PUBLIC, GETCURRENTTIME>
+
+ ; the TickCount is accessible from client address space.
+ ; refer sdk\inc\ntexapi.h
+ ; - nanduri
+
+.386p
+ ; set 32bit ds
+
+ push ds
+ mov ax, FLATDS
+ mov ds, ax
+
+ ; from sdk\inc\ntexapi.h NtGetTickCount - equivalent code
+
+ mov edx, MM_SHARED_USER_DATA_VA
+ mov eax, [edx].UsTickCountLow
+ mul dword ptr [edx].UsTickCountMultiplier
+ shrd eax,edx,24
+
+ mov edx, eax
+ shr edx, 010h
+ and ax, NOT GRAINYTIC_RES ; round off to lower 64 boundary
+ ;this is a cheap implemention of WOWCF_GRAINYTICS flag
+ pop ds
+ retf
+.286p
+
+endif
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/user/usermenu.inc b/private/mvdm/wow16/user/usermenu.inc
new file mode 100644
index 000000000..a23e40dbb
--- /dev/null
+++ b/private/mvdm/wow16/user/usermenu.inc
@@ -0,0 +1,93 @@
+;****************************************************************************
+;* *
+;* USERMENU.INC - *
+;* *
+;* Menu Structures and Defines *
+;* *
+;****************************************************************************
+
+;
+; mnFlags bits
+;
+FISPOPUP = 01h
+
+;
+; Resource template lastmenu bit
+;
+FENDMENU = 080h
+
+;
+; itmFlags bits and flags parameter values
+;
+MF_CHANGE = 0080h
+MF_INSERT = 0000h
+MF_APPEND = 0100h
+MF_DELETE = 0200h
+MF_BYPOSITION = 0400h
+MF_SEPARATOR = 0800h
+MF_REMOVE = 1000h
+MF_BYCOMMAND = 0000h
+MF_GRAYED = 0001h
+MF_DISABLED = 0002h
+MF_ENABLED = 0000h
+MF_BITMAP = 0004h
+MF_OWNERDRAW = 0100h
+MF_STRING = 0000h
+MF_CHECKED = 0008h
+MF_UNCHECKED = 0000h
+MF_POPUP = 0010h
+MF_MENUBARBREAK = 0020h
+MF_MENUBREAK = 0040h
+MF_HILITE = 0080h
+MF_UNHILITE = 0000h
+MF_HELP = 4000h
+MF_ALLSTATE = 00FFh
+
+TAB = 9
+PATCOPYL = 0021h
+PATCOPYH = 00F0h
+
+ITEM struc
+ itmFlags dw ?
+ itmCmdMenu dw ?
+ itmXItem dw ?
+ itmYItem dw ?
+ itmCxItem dw ?
+ itmCyItem dw ?
+ itmDxTab dw ?
+ itmCheckMarkOn dw ?
+ itmCheckMarkOff dw ?
+ itmHItem dw ?
+ strgX dw ?
+ strgWidth dw ?
+ len dw ?
+ITEM ends
+
+SIG_MENU equ ('M' + ('U' * 256))
+
+AMENU struc
+ mnPMenuNext dw ?
+ mnFlags dw ?
+ mnSignature dw ?
+ mnHqOwner dw ?
+ mnCxMenu dw ?
+ mnCyMenu dw ?
+ mnCItems dw ?
+ mnhwndNotify dw ?
+ mnRgItems dw ?
+ifdef JAPAN
+ mnMenuMode dw ?
+endif
+AMENU ends
+
+;
+; Menu string structure
+;
+if 0
+STRG struc
+ len dw ?
+ strgX dw ?
+ strgWidth dw ?
+ strgString dw ?
+STRG ends
+endif
diff --git a/private/mvdm/wow16/user/wclass.asm b/private/mvdm/wow16/user/wclass.asm
new file mode 100644
index 000000000..29e029dcd
--- /dev/null
+++ b/private/mvdm/wow16/user/wclass.asm
@@ -0,0 +1,396 @@
+ TITLE wsubcls.asm
+
+_TEXT SEGMENT WORD PUBLIC 'CODE'
+_TEXT ENDS
+
+_DATA SEGMENT WORD PUBLIC 'DATA'
+_DATA ENDS
+
+DGROUP GROUP _DATA
+
+EXTRN CALLWINDOWPROC:FAR
+EXTRN DEFDLGPROC:FAR
+
+_TEXT SEGMENT
+
+ ASSUME CS: _TEXT
+
+
+PUBLIC BUTTONWNDPROC
+PUBLIC COMBOBOXCTLWNDPROC
+PUBLIC EDITWNDPROC
+PUBLIC LBOXCTLWNDPROC
+PUBLIC SBWNDPROC
+PUBLIC STATICWNDPROC
+PUBLIC MDICLIENTWNDPROC
+PUBLIC TITLEWNDPROC
+PUBLIC MENUWINDOWPROC
+PUBLIC DEFDLGPROCTHUNK
+PUBLIC DESKTOPWNDPROC
+
+SUBCLASS_MAGIC equ 0534C4353h ; "SCLS" Sub-Class magic value */
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 2
+ dd 0
+
+BUTTONWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET BUTTONWNDPROC
+ mov dx,SEG BUTTONWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+BUTTONWNDPROC ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 3
+ dd 0
+
+COMBOBOXCTLWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET COMBOBOXCTLWNDPROC
+ mov dx,SEG COMBOBOXCTLWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+COMBOBOXCTLWNDPROC ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 4
+ dd 0
+
+
+EDITWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET EDITWNDPROC
+ mov dx,SEG EDITWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+EDITWNDPROC ENDP
+
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 5
+ dd 0
+
+LBOXCTLWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET LBOXCTLWNDPROC
+ mov dx,SEG LBOXCTLWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+LBOXCTLWNDPROC ENDP
+
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 7
+ dd 0
+
+SBWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET SBWNDPROC
+ mov dx,SEG SBWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+SBWNDPROC ENDP
+
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 8
+ dd 0
+
+STATICWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET STATICWNDPROC
+ mov dx,SEG STATICWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+STATICWNDPROC ENDP
+
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 6
+ dd 0
+
+MDICLIENTWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET MDICLIENTWNDPROC
+ mov dx,SEG MDICLIENTWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+MDICLIENTWNDPROC ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 0bh ; 11 decimal
+ dd 0
+
+TITLEWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET TITLEWNDPROC
+ mov dx,SEG TITLEWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+TITLEWNDPROC ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 0ch ; 12 decimal
+ dd 0
+
+MENUWINDOWPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET MENUWINDOWPROC
+ mov dx,SEG MENUWINDOWPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+MENUWINDOWPROC ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 0ah ; 10 decimal
+ dd 0
+
+
+DEFDLGPROCTHUNK PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR DEFDLGPROC
+ mov sp,bp
+ pop bp
+ dec bp
+ ret 10
+
+DEFDLGPROCTHUNK ENDP
+
+align 16
+
+ dd SUBCLASS_MAGIC
+ dd 9
+ dd 0
+
+
+DESKTOPWNDPROC PROC FAR
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ax,DGROUP
+ mov ds,ax
+ mov ax,OFFSET DESKTOPWNDPROC
+ mov dx,SEG DESKTOPWNDPROC
+ push dx
+ push ax
+ push WORD PTR [bp+14] ;hwnd
+ push WORD PTR [bp+12] ;message
+ push WORD PTR [bp+10] ;wParam
+ push WORD PTR [bp+8]
+ push WORD PTR [bp+6] ;lParam
+ call FAR PTR CALLWINDOWPROC
+ dec bp
+ dec bp
+ mov sp,bp
+ pop ds
+ pop bp
+ dec bp
+ ret 10
+
+DESKTOPWNDPROC ENDP
+
+
+_TEXT ENDS
+
+ END
diff --git a/private/mvdm/wow16/user/winhook.asm b/private/mvdm/wow16/user/winhook.asm
new file mode 100644
index 000000000..958db3a2c
--- /dev/null
+++ b/private/mvdm/wow16/user/winhook.asm
@@ -0,0 +1,134 @@
+title WINHOOK.ASM - SetWindowsHook() and friends
+
+ifdef WOW
+NOEXTERNS equ 1
+SEGNAME equ <TEXT>
+endif
+
+ .xlist
+ include user.inc
+ .list
+
+ swappro = 0
+
+; include NEW_SEG1 struc used in GetProcModule
+
+ include newexe.inc
+
+ExternFP <GetCodeInfo>
+ExternFP <GetExePtr>
+ExternFP <GetCurrentTask>
+ExternFP <SetWindowsHookInternal>
+
+createSeg _%SEGNAME,%SEGNAME,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+;===========================================================================
+
+sBegin %SEGNAME
+
+assumes CS,%SEGNAME
+assumes DS,DATA
+assumes ES,NOTHING
+
+;============================================================================
+;
+; HANDLE GetProcModule(FARPROC lpfn);
+;
+; This function returns the module handle corresponding to a given
+; hook proc address.
+;
+; CAUTION: This uses the undocumented feature of "GetCodeInfo()" that it
+; returns the module handle in ES register.
+;
+cProc GetProcModule, <PUBLIC, NEAR>
+ParmD lpfn
+LocalV seginfofromkernel, %size NEW_SEG1+2
+cBegin
+; Turns out GetCodeInfo
+;
+ pushd lpfn ; GetCodeInfo(lpfn, &seginfo)
+ lea ax,seginfofromkernel
+ push ss
+ push ax
+ call GetCodeInfo
+ or ax,ax ; AX is BOOL fSuccess (even though windows.h says void)
+ mov ax,es ; ES contains the module handle according
+ ; to David Weise...
+ jnz gpmexit ; We're ok
+
+ ; Sleazy hack from hell. Excel global allocs some memory, puts
+ ; code into it and passes it to us. The GetCodeInfo fails in this
+ ; case so we need to get the module handle for a globalalloced
+ ; chunk of memory.
+
+ push word ptr lpfn+2
+ call GetExePtr
+gpmexit:
+
+ifdef DEBUG
+ or ax,ax
+ jnz gpm900
+ DebugErr DBF_ERROR, "Invalid Hook Proc Addr"
+ xor ax,ax
+gpm900:
+endif
+cEnd
+
+
+;==============================================================================
+;
+; FARPROC FAR PASCAL SetWindowsHook(int idHook, FARPROC lpfn)
+; {
+; SetWindowsHookEx2(idHook,
+; (HOOKPROC)lpfn,
+; GetProcModule(lpfn),
+; (idHook == WH_MSGFILTER ? GetCurrentTask() : NULL));
+; }
+;
+cProc ISetWindowsHook,<FAR, PUBLIC, LOADDS>
+ParmW idHook
+ParmD lpfn
+LocalW hmodule
+LocalW htask
+cBegin
+ ; Check if some apps are trying to unhook a hook using SetWindowsHook()
+ mov bx, seg_lpfn
+ cmp bx, HHOOK_MAGIC
+ jz swhHookMagic
+
+ cmp idHook,WH_MSGFILTER
+ jnz swh10
+
+ call GetCurrentTask
+ jmp swhMakeCall
+
+swhHookMagic:
+ ; Now, it is clear that this app wants to unhook by calling SetWindowsHook()
+ ; All Micrographix apps do this trick to unhook their keyboard hooks.
+ ; Fix for Bug #7972 -- SANKAR -- 05/30/91 --
+ ; Let us unhook the node passed in thro lpfn;
+ifdef DEBUG
+ DebugErr <DBF_WARNING>, "SetWindowsHook called to unhook: use UnhookWindowsHook"
+endif
+ xor ax,ax
+ jmps swhMakeCall
+
+swh10:
+ pushd lpfn
+ call GetProcModule
+
+swhMakeCall:
+ push ax
+ push idHook
+ pushd lpfn
+
+ call SetWindowsHookInternal
+
+swhExit:
+cEnd
+
+sEnd %SEGNAME
+
+END
diff --git a/private/mvdm/wow16/user/winlang.asm b/private/mvdm/wow16/user/winlang.asm
new file mode 100644
index 000000000..477854a31
--- /dev/null
+++ b/private/mvdm/wow16/user/winlang.asm
@@ -0,0 +1,722 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINLANG.ASM
+; Win16 language-dependent string services
+;
+; History:
+;
+; Created 18-Jun-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16
+;--
+
+
+;****************************************************************************
+;* *
+;* WinLang.ASM - *
+;* *
+;* API calls to support different lanuages *
+;* *
+;****************************************************************************
+
+NOTEXT = 1
+
+.xlist
+include user.inc
+.list
+
+ExternFP AllocSelector
+ExternFP FreeSelector
+ExternFP PrestoChangoSelector
+
+ExternNP IAnsiPrev
+ExternNP IAnsiNext
+
+;****************************************************************************
+;* *
+;* WOW note: The implementations in this file are the US implementations *
+;* with all the language driver and DBCS stuff ripped out. *
+;* PatchUserStrRtnsToThunk, at the bottom of this file, is *
+;* called during startup of user16 if the locale is other *
+;* than U.S. English, or if forced to thunk by a registry key. *
+;* This routine patches each of the APIs implemented here to *
+;* simply jump to the thunk, with a name beginning "Win32". *
+;* *
+;* The StrRtnsPatchTable defined below controls the patching. *
+;* *
+;****************************************************************************
+
+ExternNP Win32lstrcmp
+ExternNP Win32lstrcmpi
+ExternNP Win32AnsiPrev
+ExternNP Win32AnsiNext
+ExternNP Win32AnsiUpper
+ExternNP Win32AnsiLower
+ExternNP Win32AnsiUpperBuff
+ExternNP Win32AnsiLowerBuff
+ExternNP Win32IsCharAlpha
+ExternNP Win32IsCharAlphaNumeric
+ExternNP Win32IsCharUpper
+ExternNP Win32IsCharLower
+
+sBegin DATA
+LabelW StrRtnsPatchTable
+
+; Location of patch Target of jmp patched in
+; ----------------- ------------------------
+ dw codeOffset Ilstrcmp, codeOffset Win32lstrcmp
+ dw codeOffset Ilstrcmpi, codeOffset Win32lstrcmpi
+;
+; These two functions need to be thunked only for DBCS builds
+;
+ifdef DBCS
+ dw codeOffset IAnsiPrev, codeOffset Win32AnsiPrev
+ dw codeOffset IAnsiNext, codeOffset Win32AnsiNext
+endif ; DBCS
+
+ dw codeOffset IAnsiUpper, codeOffset Win32AnsiUpper
+ dw codeOffset IAnsiLower, codeOffset Win32AnsiLower
+ dw codeOffset IAnsiUpperBuff, codeOffset Win32AnsiUpperBuff
+ dw codeOffset IAnsiLowerBuff, codeOffset Win32AnsiLowerBuff
+ dw codeOffset IsCharAlpha, codeOffset Win32IsCharAlpha
+ dw codeOffset IsCharAlphaNumeric, codeOffset Win32IsCharAlphaNumeric
+ dw codeOffset IsCharUpper, codeOffset Win32IsCharUpper
+ dw codeOffset IsCharLower, codeOffset Win32IsCharLower
+LabelW StrRtnsPatchTableEnd
+sEnd
+
+
+createSeg _TEXT, CODE, WORD, PUBLIC, CODE
+
+
+sBegin CODE
+assumes CS, CODE
+assumes DS, DATA
+
+ExternNP MyUpper
+ExternNP MyLower
+ExternNP MyAnsiUpper
+ExternNP MyAnsiLower
+
+
+
+;--------------------------------------------------------------------------
+;
+; The following table contains the primary and secondary weight info.
+;
+; For alphanumeric characters primary weight is equal to (Ascii + PrimeWt)
+; Secondary weight is either 0 or 1 (For all upper case letters zero and
+; lower case letters 1);
+;
+; For non-alphanumeric characters, primary weight is their ASCII value and
+; the secondary weight is zero.
+;
+; Note that the primary weight calculated with this table for the smallest
+; of the alpha-numeric character('0') is 100h (30h+D0h), which is more than
+; the primary weight of the highest non-alpha-numeric character FFh;
+; Thus all non-alpha-numeric characters will sort before any alpha-numeric
+; characters;
+;
+; Note that 'PrimeWt' field for lowercase letters is B0h instead of
+; D0h because when added with their ascii, it should become exactly
+; equal to the primary weights of their upper-case counterparts;
+;
+; IMPORTANT NOTE: On 01-17-90, we came across a bug in lstrcmpi() due to
+; the fact that we are not treating characters C0h to FEh as upper and
+; lower case alphas; So, I added some more ranges to the SortStruc table
+; to map the range C0h to D6h onto the range E0h to F6 and to map the
+; range D8h to DEh onto the range F8h to FEh. A value of 20h in the PrimeWt
+; field automatically takes care of this mapping because that is the diff
+; to be added to the uppercase letter to make it lowercase; The secondary
+; weights are as usual 0 for uppercase and 1 for lowercase;
+; --Fix for Bug #8222 --01-17-90-- SANKAR --
+;--------------------------------------------------------------------------
+SortStruct STRUC
+
+ StartAscii db ?
+ EndAscii db ?
+ PrimeWt db ?
+ SecondWt db ?
+
+SortStruct ENDS
+
+
+public SortTable
+LabelB SortTable
+
+ SortStruct <'0', '9', 0D0h, 0>
+ SortStruct <'A', 'Z', 0D0h, 0>
+ SortStruct <'a', 'z', 0B0h, 1>
+ SortStruct <0C0h, 0D6h, 20h, 0>
+ SortStruct <0D8h, 0DEh, 20h, 0>
+ SortStruct <0E0h, 0F6h, 0, 1>
+ SortStruct <0F8h, 0FEh, 0, 1>
+LabelB SortTableEnd
+
+;*----------------------------------------------------------------------*
+;* *
+;* GetWeightValues() *
+;* Input: *
+;* AL = character whose weight values are asked for *
+;* Output: *
+;* AX = Primary weight of the character *
+;* BL = Secondary weight of the character *
+;*----------------------------------------------------------------------*
+
+public GetWeightValues
+GetWeightValues PROC NEAR
+
+ xor ah, ah
+ xor bx, bx ; Index into the table
+ ; Enter the number of entries in the sort table.
+ mov cx, (SortTableEnd - SortTable)/(SIZE SortStruct)
+gwv_loop:
+ cmp al, byte ptr SortTable[bx].StartAscii
+ jb gwv_end
+ cmp al, byte ptr SortTable[bx].EndAscii
+ jbe gwv_GetWeights
+ add bx, SIZE SortStruct
+ loop gwv_loop
+ jmps gwv_end
+
+gwv_GetWeights:
+ add al, byte ptr SortTable[bx].PrimeWt
+ adc ah, 0
+ mov bl, byte ptr SortTable[bx].SecondWt
+
+gwv_end:
+ ret
+
+GetWeightValues ENDP
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* lstrcmp(String1, String2) - *
+;* *
+;* String1 and String2 are LPSTR's to null terminated strings. *
+;* *
+;* This function returns -1 if String1 sorts before String2, 0 if String1*
+;* and String2 have the same sorting and 1 if String2 sorts before *
+;* String1. *
+;* NOTE: This is case sensitive compare. *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32lstrcmp, aka WU32lstrcmp. *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc Ilstrcmp, <FAR, PUBLIC>, <SI, DI>
+; ^^^^^^^^ US_lstrcmp assumes SI, DI saved!
+
+ParmD lpStr1
+ParmD lpStr2
+LocalB SecWeight1 ; Locals used by US_lstrcmp
+LocalB SecWeight2
+LocalB LocSecWeight
+LocalB fCaseSensitive ; Flag indicating whether it is case sensitive or not.
+
+cBegin
+ mov byte ptr fCaseSensitive, 1 ; Yup! It is case sensitive
+ call US_lstrcmp
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* US_lstrcmp *
+;* US version of string sort(Case sensitive); *
+;* Uses locals defined by Ilstrcmp above.
+;* To understand the algorithm, read the comments for SortStruct *
+;* *
+;*----------------------------------------------------------------------*
+
+public US_lstrcmp
+US_lstrcmp PROC NEAR
+
+ push ds ; Save ds
+ ;Initialise the secondary wt values
+ mov byte ptr SecWeight1, 0
+ mov byte ptr SecWeight2, 0
+
+ ; Load both the strings
+ lds si, lpStr1
+ les di, lpStr2
+
+ss_loop:
+ ; Take one char from both the strings.
+ mov al, byte ptr ds:[si]
+ xor ah, ah ; make secondary wts zero
+ mov dl, byte ptr es:[di]
+ xor dh, dh
+
+ inc si ; Move to next character
+ inc di
+
+ cmp al, 0
+ jz ss_chkprimary ; Check if lpStr1 has ended
+
+ cmp dl, 0
+ jz ss_chkprimary ; Check if lpStr2 has ended
+
+ ; Let us compare the ASCII vaues
+ ; If the asciis are equal, then weights are equal
+ cmp al, dl
+ je ss_loop ; Goto next character
+
+ ; Now, the asciis differ. So, let us find the weights
+
+ ; Let us get the weights for the character of lpStr1 (in ax )
+
+ call GetWeightValues
+
+ ; ax contains the primary weight of char of lpStr1
+ ; bl contains the secondary weight of ditto
+ mov LocSecWeight, bl
+ xchg ax, dx
+ call GetWeightValues
+
+ ; compare primary weights
+ ; Primary weight of Str1 in DX and Str2 in AX
+ cmp ax, dx
+ jb CompareRetGT
+ ja CompareRetLT
+
+ ; Check if it is Case-Insensitive compare
+ mov bh, fCaseSensitive
+ or bh, bh
+ jz ss_loop ; It is case-insensitive; So, no need to consider
+ ; the secondary weightages. Goto next character.
+
+ ; Control comes here only if it is a case sensitive compare.
+ ; Now, primaries are equal. Compare secondaries
+ mov bh, LocSecWeight
+ cmp bh, bl
+ je ss_loop ; Secondaries are equal, Continue
+
+ ; Secondaries are not equal. Check if they are stored already
+ mov cl, SecWeight1
+ or cl, SecWeight2
+ jnz ss_loop ; Secondaries already exist, continue
+
+ ; Secondaries haven't been saved sofar.Save the secondaries
+ mov SecWeight1, bh
+ mov SecWeight2, bl
+ jmps ss_loop ; Process the next character
+
+ss_chkprimary:
+ ; al, dl contain the primary weights and at least one of them is
+ ; zero.
+ cmp al, 0
+ ja CompareRetGT
+ cmp dl, 0
+ ja CompareRetLT
+
+ ; both are zero; they are equal; So, check the secondary values
+ mov bl, SecWeight1
+ cmp bl, SecWeight2
+ ja CompareRetGT
+ jb CompareRetLT
+
+ ; They are identical with equal weightages
+ xor ax, ax
+ jmps CompareRet
+
+CompareRetGT:
+ mov ax, 1
+ jmps CompareRet
+
+CompareRetLT:
+ mov ax, -1
+
+CompareRet:
+ pop ds
+ ret
+
+US_lstrcmp ENDP
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* lstrcmpi(String1, String2) - *
+;* (Case Insensitive compare) *
+;* String1 and String2 are LPSTR's to null terminated strings. *
+;* *
+;* This function returns -1 if String1 sorts before String2, 0 if String1*
+;* and String2 have the same sorting and 1 if String2 sorts before *
+;* String1. *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32lstrcmpi, aka WU32lstrcmpi. *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc Ilstrcmpi, <FAR, PUBLIC>, <SI, DI>
+; ^^^^^^^^ US_lstrcmp assumes SI, DI saved!
+
+ParmD lpStr1
+ParmD lpStr2
+LocalB SecWeight1 ; Locals used by US_lstrcmp
+LocalB SecWeight2
+LocalB LocSecWeight
+LocalB fCaseSensitive ; Flag indicating whether it is case sensitive or not.
+
+cBegin
+ mov byte ptr fCaseSensitive, 0 ; FALSE => Case-Insensitive.
+ call US_lstrcmp
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiUpper implementation is from Win3.1 US_AnsiUpper() *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32AnsiUpper, aka WU32AnsiUpper. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IAnsiUpper, <FAR, PUBLIC, PASCAL>, <SI, DI>
+
+ParmD lpStr
+
+cBegin
+
+ les di,lpStr
+ mov cx,es
+ mov ax,di
+ call MyUpper ; if passed a char, just upper case it.
+ jcxz au1
+ inc cx ; take care of the stupid case of sign propagation
+ jz au1
+ dec cx
+ call MyAnsiUpper ; otherwise upper case the whole string
+ mov ax, word ptr lpStr ; Now, dx:ax points at original string
+au1: mov dx,es
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiLower implementation is from Win3.1 US_AnsiLower() *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32AnsiLower, aka WU32AnsiLower. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IAnsiLower, <FAR, PUBLIC, PASCAL>, <SI, DI>
+
+ParmD lpStr
+
+cBegin
+ les di,lpStr
+ mov cx,es
+ mov ax,di
+ call MyLower ; if passed a char, just lower case it.
+ jcxz al1
+ inc cx ; take care of the stupid case of sign propagation
+ jz al1
+ dec cx
+ call MyAnsiLower ; otherwise lower case the whole string
+ mov ax, word ptr lpStr ; dx:ax points at original string
+al1: mov dx,es
+
+cEnd
+
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiUpperBuff implemented from Win3.1 US_AnsiUpperBuff *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32AnsiUpperBuff, aka WU32AnsiUpperBuff. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IAnsiUpperBuff, <FAR, PUBLIC, PASCAL>, <SI, DI>
+
+ParmD lpStr
+ParmW iCount
+
+cBegin
+
+ cld
+ les di, lpStr
+ mov si, di
+ mov cx, iCount ; if iCount=0, the Buff size is 64K.
+ mov dx, iCount ; Preserve the length of Buffer
+su_begin:
+ lods byte ptr es:[si]
+ call MyUpper
+ stosb
+ loop su_begin
+su_over:
+ mov ax, dx ; Move the result to ax
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiLowerBuff implemented from Win3.1 US_AnsiLowerBuff *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32AnsiLowerBuff, aka WU32AnsiLowerBuff. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IAnsiLowerBuff, <FAR, PUBLIC, PASCAL>, <SI, DI>
+
+ParmD lpStr
+ParmW iCount
+
+cBegin
+
+ cld
+ les di, lpStr
+ mov si, di
+ mov cx, iCount ; If cx=0, the buff size is 64K
+ mov dx, cx ; Preserve the length in DX
+sl_begin:
+ lods byte ptr es:[si]
+ call MyLower
+ stosb
+ loop sl_begin
+sl_over:
+ mov ax, dx ; Move the result to ax
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* IsCharLower implemented with Win3.1 US_IsCharLower *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32IsCharLower, aka WU32IsCharLower. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IsCharLower, <FAR, PUBLIC, PASCAL>
+
+ParmB bChar
+
+cBegin
+
+ mov al, bChar
+ call Loc_Lower
+ jc icl_end
+
+ xor ax, ax ; Not lower. So, false
+icl_end:
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* IsCharUpper implemented with Win3.1 US_IsCharUpper *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32IsCharUpper, aka WU32IsCharUpper. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IsCharUpper, <FAR, PUBLIC, PASCAL>
+
+ParmB bChar
+
+cBegin
+
+ mov al, bChar
+ call Loc_Upper
+ jc icu_end
+
+ xor ax, ax
+icu_end:
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* IsCharAlphaNumeric implemented with Win3.1 US_IsCharAlphaNumeric *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32IsCharAlphaNumeric, aka WU32IsCharAlphaNumeric. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IsCharAlphaNumeric, <FAR, PUBLIC, PASCAL>
+
+ParmB bChar
+
+cBegin
+
+ mov al, bChar
+ call Loc_Numeric
+ jc ica_end
+
+ jmps ica_begin
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* IsCharAlpha implemented with Win3.1 US_IsCharAlpha *
+;* *
+;* Outside the U.S. English locale, this function is patched to be a *
+;* near jump to Win32IsCharAlpha, aka WU32IsCharAlpha. *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IsCharAlpha, <FAR, PUBLIC, PASCAL>
+
+ParmB bChar
+
+cBegin
+
+ mov al, bChar
+ica_begin:
+ call Loc_Lower
+ jc ica_end
+
+ call Loc_Upper
+ jc ica_end
+
+ xor ax, ax
+ica_end:
+
+cEnd
+
+
+;*----------------------------------------------------------------------*
+;* *
+;* Loc_Upper, LocLower, Loc_Numeric *
+;* *
+;* Used by IsCharXxx US implementations *
+;* *
+;* Input: *
+;* AL = character being tested *
+;* Output: *
+;* Carry flag set if TRUE *
+;* Carry flag cleared if FALSE *
+;*----------------------------------------------------------------------*
+
+public Loc_Upper
+LabelNP <Loc_Upper>
+
+ cmp al, 'A'
+ jb Loc_False
+
+ cmp al, 'Z'
+ jbe Loc_True
+
+ cmp al, 0C0h
+ jb Loc_False
+
+ cmp al, 0D7h ; This is multiply sign in Microsoft fonts, So, ignore;
+ je Loc_False ; Fix for Bug #1356; SANKAR --08-28-89--;
+
+ cmp al, 0DEh
+ jbe Loc_True
+ jmps Loc_False
+
+public Loc_Lower
+LabelNP <Loc_Lower>
+ ; 0xDF and 0xFF are Lower case. But they don't have an equivalent
+ ; upper case letters;
+ ; So, they are treated as special case chars here
+ ; Fix for Bug # 9799 --SANKAR-- 02-21-90 --
+ cmp al, 0DFh
+ je Loc_True
+
+ cmp al, 0FFh
+ je Loc_True
+
+ ; Fall thro to the next function
+ errnz ($-Loc_IsConvertibleToUpperCase)
+public Loc_IsConvertibleToUpperCase
+LabelNP <Loc_IsConvertibleToUpperCase>
+
+ cmp al, 'a'
+ jb Loc_False
+
+ cmp al, 'z'
+ jbe Loc_True
+
+ cmp al, 0E0h
+ jb Loc_False
+
+ cmp al, 0F7h ; This is divide sign in Microsoft fonts; So, ignore
+ je Loc_False; ; Fix for Bug #1356; SANKAR --08-28-89--;
+
+ cmp al, 0FEh
+ jbe Loc_True
+ jmps Loc_False
+
+LabelNP <Loc_Numeric>
+
+ cmp al, '0'
+ jb Loc_False
+
+ cmp al, '9'
+ ja Loc_False
+
+Loc_True:
+ stc ; Set carry to indicate true
+ jmps Loc_End
+
+Loc_False:
+ clc ; Clear carry to indicate false
+
+Loc_End:
+ ret
+
+;*----------------------------------------------------------------------*
+;* *
+;* PatchUserStrRtnsToThunk -- *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc PatchUserStrRtnsToThunk, <PUBLIC, FAR, PASCAL>, <SI,DI>
+
+cBegin
+ cCall AllocSelector, <0>
+ cCall PrestoChangoSelector, <cs, ax>
+ push ax
+ pop es
+
+ mov si, dataOffset StrRtnsPatchTable ; ds:si = StrRtnsPatchTable
+PatchLoop:
+ lodsw
+ mov di, ax ; di = offset of code to be patched
+ mov ax, 0E9h ; opcode for near jump w/2 byte diff.
+ stosb ; store jmp opcode
+ lodsw
+ sub ax, di ; difference between src and target
+ sub ax, 2 ; encoded difference is based on
+ ; address of next instruction
+ stosw ; store difference
+ cmp si, dataOffset StrRtnsPatchTableEnd
+ jb PatchLoop
+
+ xor ax, ax
+ push es ; for FreeSelector
+ push ax
+ pop es
+
+ call FreeSelector
+cEnd
+
+sEnd CODE
+
+end
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/user/winmisc2.asm b/private/mvdm/wow16/user/winmisc2.asm
new file mode 100644
index 000000000..579faa0b7
--- /dev/null
+++ b/private/mvdm/wow16/user/winmisc2.asm
@@ -0,0 +1,790 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINMISC2.ASM
+; Win16 misc. user services
+;
+; History:
+;
+; Created 28-May-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16
+;--
+
+;****************************************************************************
+;* *
+;* WINMISC2.ASM - *
+;* *
+;* Random stuff *
+;* *
+;****************************************************************************
+
+ifdef WOW
+SEGNAME equ <TEXT>
+endif
+
+.xlist
+include user.inc
+include vint.inc
+.list
+
+ExternFP <GlobalHandleNorip>
+ExternFP <MessageBox>
+ExternFP <SysErrorBox>
+
+
+ifndef WOW
+ExternFP <DoBeep>
+ExternFP <XCSTODS>
+ExternNP <rgbKeyState>
+ExternW <hwndCapture>
+ExternW <fBeep>
+ExternW <fMessageBox>
+ExternW <hwndDragIcon>
+
+ExternA <__WinFlags>
+
+ATOMTABLE STRUC
+at_prime DW ?
+at_hashTable DW ?
+ATOMTABLE ENDS
+
+ATOM STRUC
+a_chain DW ?
+a_usage DW ?
+a_len DB ?
+a_name DB ?
+ATOM ENDS
+
+LocalArena STRUC
+la_prev DW ? ; previous arena entry (first entry points to self)
+la_next DW ? ; next arena entry (last entry points to self)
+la_handle DW ? ; back link to handle table entry
+LocalArena ENDS
+
+sBegin DATA
+
+;
+; For GetSysMetrics - don't move this stuff. DS positioning is assumed.
+;
+SM_CMETRICS1 equ 24
+SM_CMETRICS2 equ 16
+
+public rgwSysMet
+rgwSysMet dw (SM_CMETRICS1) DUP(0)
+
+; These are 'variable metrics', conviently located the system metrics array.
+GlobalW hwndFullScrn, 0
+GlobalW iLevelCursor, 0
+
+; These are additions since 2.0
+ dw SM_CMETRICS2 DUP(0)
+
+
+sEnd DATA
+endif ;WOW
+
+createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE
+
+assumes cs,%SEGNAME
+assumes ds,DATA
+
+sBegin %SEGNAME
+
+ifndef WOW
+;*--------------------------------------------------------------------------*
+;* *
+;* GetSystemMetrics() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; int far GetSystemMetrics(iMetric)
+; int iMetric;
+
+LabelFP <PUBLIC, GetSystemMetrics>
+
+ pop ax ; Pop the FAR return
+ pop dx
+ pop bx ; BX = iMetric
+ push dx ; Restore the FAR return
+ push ax
+
+ xor ax,ax
+ cmp bx,SM_CMETRICSMAX ; Bigger than max?
+ jge gsmExit ; Yes, exit
+ shl bx,1 ; Convert to a byte index
+
+ifndef userhimem
+ mov es,WORD PTR cs:[cstods]
+else
+ push ax
+ push ds
+ call XCSTODS
+ mov es,ax
+ pop ds
+ pop ax
+endif
+
+assumes es,DATA
+ mov ax,es:[rgwSysMet+bx] ; Return the SysMetric value
+assumes es,NOTHING
+gsmExit:
+ retf
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* MessageBeep() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc MessageBeep, <FAR, PUBLIC>
+
+ParmW beep
+
+cBegin
+ cmp fBeep,0
+ je mbout ; No beeps today....
+ mov ax,beep
+ cmp fMessageBox,0 ; if we are in an INT24 box, let
+ je noint24 ; the sound driver know not to load
+ mov ax,-1 ; anything by passing -1.
+noint24:
+ push ax
+ call DoBeep ; Just call the sound driver guy
+mbout:
+
+cEnd
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* IsChild() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+LabelFP <PUBLIC, IsChild>
+;
+;ParmW hwnd
+;ParmW hwndChild
+;
+ pop ax ; pop return address
+ pop dx
+ pop bx ; bx = hwndChild
+ pop cx ; cx = hwnd
+ push dx ; push return address
+ push ax
+
+ push ds
+ UserDStoDS ; es = USER's DS
+
+ CheckHwnd cx ; checkhwnd will zero ax if failure
+ jz icexit
+ifdef DEBUG
+ CheckHwndNull bx ; only do check if debug since
+ jz icexit ; we never access anything off this
+ ; pointer
+endif
+ xor ax,ax ; Assume FALSE
+icloop:
+ or bx,bx ; while (hwndChild == NULL &&
+ jz icexit
+ mov dl,byte ptr [bx+WSTATE+WFTYPEMASK/256]
+ and dl,LOW(WFTYPEMASK) ; TestwndChild(hwndChild))
+ cmp dl,LOW(WFCHILD)
+ jne icexit
+ mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
+ cmp bx,cx ; if (hwnd == hwndChild)
+ jne icloop
+ inc al ; return(TRUE);
+icexit:
+ pop ds
+ retf
+
+; BOOL IsDescendant(hwndParent, hwndChild);
+;
+; Internal version of IsChild that is a bit faster and ignores the
+; WFCHILD business. MUST be called with DS == USER DS.
+;
+; Returns TRUE if hwndChild == hwndParent (IsChild doesn't)
+;
+; while (hwndChild != NULL)
+; {
+; if (hwndParent == hwndChild)
+; return TRUE;
+; hwndChild = hwndChild->hwndParent;
+; }
+;
+LabelFP <PUBLIC, IsDescendant>
+ pop ax ; pop off return address
+ pop dx
+ pop bx ; bx = hwndChild
+ pop cx ; cx = hwndParent
+ push dx ; replace return address
+ push ax
+
+ xor ax,ax ; assume FALSE
+idloop:
+ or bx,bx ; if at end, return FALSE
+ jz idexit
+ cmp bx,cx ; hwndChild == hwndParent?
+ mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
+ jnz idloop ; keep looping if we didn't find it...
+
+ inc al ; ax = TRUE
+idexit:
+ retf
+
+;--------------------------------------------------------------------------
+;
+; IsWindowVisible() -
+;
+;--------------------------------------------------------------------------
+;
+; BOOL FAR PASCAL IsWindowVisible(register HWND hwnd)
+; {
+; if (!CheckHwnd(hwnd))
+; return(FALSE);
+;
+; if (hwnd == hwndDragIcon)
+; return(TRUE);
+;
+; for ( ; hwnd != NULL; hwnd = hwnd->hwndParent)
+; {
+; if (!TestWF(hwnd, WFVISIBLE))
+; return FALSE;
+; }
+; return TRUE;
+; }
+;
+LabelFP <PUBLIC, IsWindowVisible>
+;ParmW hwnd
+ pop ax ; pop return address
+ pop dx
+ pop bx ; bx = hwnd
+ push dx ; push return address
+ push ax
+
+ push ds
+ UserDStoDS ; es = USER's DS
+
+ CheckHwnd bx ; checkhwnd will zero ax if failure
+ jz ivwexit
+
+ mov ax,TRUE ; assume TRUE
+
+; Check if this is the iconic window being moved around with a mouse */
+; If so, return a TRUE, though, strictly speaking, it is hidden. */
+; This helps the Tracer guys from going crazy! */
+; Fix for Bug #57 -- SANKAR -- 08-08-89 -- */
+;
+ cmp bx,hwndDragIcon ; hwnd == hwndDragIcon?
+ jz ivwexit ; yes: return TRUE.
+ivwloop:
+ or bx,bx ; while (hwndChild == NULL &&
+ jz ivwexit
+ TSTWF bx,WFVISIBLE
+ mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
+ jnz ivwloop ; if visible bit set, keep looping
+
+ xor ax,ax ; visible bit clear: return FALSE
+ivwexit:
+ pop ds
+ retf
+
+
+;=======================================================================
+;
+; Return whether or not a given window can be drawn in or not.
+;
+; BOOL FAR IsVisible(HWND hwnd, BOOL fClient)
+; {
+; HWND hwndT;
+;
+; for (hwndT = hwnd; hwndT != NULL; hwndT = hwndT->hwndParent)
+; {
+; // Invisible windows are always invisible
+; //
+; if (!TestWF(hwndT, WFVISIBLE))
+; return FALSE;
+;
+; if (TestWF(hwndT, WFICONIC))
+; {
+; // Children of icons are always invisible.
+; //
+; if (hwndT != hwnd)
+; return FALSE;
+;
+; // Client areas with class icons are always invisible.
+; //
+; if (fClient && hwndT->pcls->hIcon)
+; return FALSE;
+; }
+; }
+; return TRUE;
+; }
+;
+LabelFP <PUBLIC, IsVisible>
+ pop ax
+ pop dx
+ pop cx ; cx = fClient
+ pop bx ; bx = hwnd
+ push dx
+ push ax
+
+ mov dx,bx ; hwnd = dx, bx = hwndT
+ xor ax,ax ; assume FALSE return
+ jmps iv100 ; fall into loop...
+ivloop:
+ mov bx,[bx].wndPwndParent ; hwndChild = hwndChild->hwndParent
+iv100:
+ or bx,bx
+ jz ivtrue ; Reached the top: return TRUE
+
+ TSTWF bx,WFVISIBLE ; if not visible, get out of here.
+ jz ivfalse
+
+ TSTWF bx,WFMINIMIZED ; if not minimized, keep looping
+ jz ivloop
+
+ cmp bx,dx ; if (hwnd != hwndT)
+ jnz ivfalse ; return FALSE
+
+ jcxz ivloop ; if fClient == FALSE, keep going.
+
+ mov bx,[bx].wndPcls
+ mov bx,[bx].uclshIcon
+ or bx,bx
+ jnz ivfalse
+ mov bx,dx ; resume enumeration at bx
+ jmps ivloop ; keep looping...
+ivtrue:
+ inc al ; ax = TRUE
+ivfalse:
+ retf
+
+;*--------------------------------------------------------------------------*
+;* *
+;* GetMenu() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc GetMenu, <FAR, PUBLIC>,<si>
+
+ParmW hwnd
+
+cBegin
+ mov si,hwnd
+ CheckHwnd si
+ jz gmexit
+ mov ax,[si].wndhMenu
+gmexit:
+
+cEnd
+endif ;WOW
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SwapHandle() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Takes a far pointer to a word on the stack and converts it from a handle
+; into a segment address or vice-versa. Note that this function is a NO OP
+; in protect mode.
+
+ifndef PMODE
+cProc SwapHandle, <PUBLIC, FAR, NODATA, ATOMIC>
+
+ParmD lpHandle
+
+cBegin
+ifndef WOW
+ mov ax,__WinFlags
+ test ax,1
+ jnz sh200 ; SwapHandle is a no op in pmode.
+endif
+ ; Save the parameter.
+ mov bx,off_lpHandle
+ push bx
+
+ ; Get the handle/segment
+ mov ax,word ptr ss:[bx]+2
+ push ax ; Save it
+
+ ; Call GlobalHandleNorip which puts the proper handle in AX
+ ; and the corresponding segment address in DX.
+ push ax
+ call GlobalHandleNorip
+
+ ; Restore the original word.
+ pop bx
+
+ ; If DX==CS then we know we've converted a handle into a segment.
+ ; This prevents problems with the FFFE segment.
+ mov cx,cs
+ cmp dx,cx
+ je sh50
+
+ ; Was the original word a segment address?
+ test bl,1
+ jnz sh100 ; Yes, AX = handle, DX = segment
+
+sh50: xchg ax,dx ; Nope, AX = segment, DX = handle
+
+ ; Restore the pointer to the original word.
+sh100: pop bx
+
+ ; Skip if zero.
+ or ax,ax
+ jz sh200
+
+ ; Move the result into the original word pointed to.
+ mov word ptr ss:[bx]+2,ax
+sh200:
+cEnd
+endif ;PMODE
+
+ifndef WOW
+;*--------------------------------------------------------------------------*
+;* *
+;* SwapMouseButton() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; BOOL SwapMouseButton(fSwap)
+; BOOL fSwap;
+
+LabelFP <PUBLIC, SwapMouseButton>
+ mov ax,_INTDS
+ mov es,ax
+assumes es,INTDS
+ mov ax,es:fSwapButtons ; Return fSwapButtons' old value
+ pop cx ; Pop off the FAR return
+ pop dx
+ pop es:[fSwapButtons] ; fSwapButtons = fSwap
+
+ mov bx,es:[fSwapButtons]
+assumes es,NOTHING
+
+ mov es,WORD PTR cs:[cstods] ; Get user's ds
+assumes es,DATA
+ mov es:[rgwSysMet+SM_SWAPBUTTON*2],bx
+assumes es,NOTHING
+
+ push dx ; Restore the FAR return
+ push cx
+ retf
+assumes es,NOTHING
+
+endif; Not WOW
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* SetDivZero() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+LabelFP <PUBLIC, SetDivZero>
+ push ds
+ push cs ; Set DS == CS
+ pop ds
+ifndef userhimem
+ mov dx,Offset DivideByZero
+else
+ push ds
+ mov ax, _INTDS
+ mov ds,ax
+assumes ds,INTDS
+ mov ax,fffedelta
+ pop ds
+assumes ds,DATA
+ add ax,Offset DivideByZero
+ mov dx,ax
+endif
+sdzvector:
+ mov ax,2500h ; Use DOS to set interrupt zero
+ int 21h
+ pop ds
+ retf
+
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* DivideByZero() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+LabelFP <PUBLIC, DivideByZero>
+ FSTI
+ifdef DEBUG
+ pusha
+ push es
+endif
+
+ ; Put up the system modal message box.
+ mov cx,_INTDS
+ifdef WOW
+ ; Put up the SysErrorBox Directly
+ push cx
+ lea ax,szDivZero
+ push ax
+
+ push cx
+ lea ax,szSysError
+ push ax
+
+ifdef DEBUGlater
+
+ push SEB_CLOSE
+ push 0
+ push SEB_CANCEL
+ call SysErrorBox
+ cmp ax,SEB_BTN1
+ jz DBZ_Terminate
+
+ pop es
+ popa
+ DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
+ iret
+
+DBZ_Terminate:
+ pop es
+ popa
+else ; FREE Build
+ push 0 ; no button 1
+ push SEB_CLOSE ; only allow close
+ push 0 ; no button 3
+ call SysErrorBox
+endif; FREE Build
+ mov ax,4C00h ; Abort the task with a 0
+ int 21h
+
+else; Not WOW
+ xor ax,ax
+ push ax ; NULL hwnd
+ lea ax,szDivZero
+ push cx
+ push ax ; Message Text
+ lea ax,szSysError
+ push cx
+ push ax ; Caption Text
+ifdef DEBUG
+ mov ax,MB_SYSTEMMODAL OR MB_ICONHAND OR MB_OKCANCEL
+else
+ mov ax,MB_SYSTEMMODAL OR MB_ICONHAND
+endif
+ push ax
+ call MessageBox
+ifdef DEBUG
+ cmp ax,1 ; If OK Button clicked, terminate app
+ jz DBZ_Terminate
+
+ pop es
+ popa
+ DebugErr DBF_FATAL, "Divide by zero or divide overflow error: break and trace till IRET"
+ iret
+
+DBZ_Terminate:
+ pop es
+ popa
+endif
+endif; Not WOW
+ mov ax,4C00h ; Abort the task with a 0
+ int 21h
+
+ifndef WOW
+
+;-------------------------------------------------------------------------
+;
+; word FAR PASCAL GetUserLocalObjType(pObj)
+; Given a near pointer to an object in USER's local heap, this function
+; determines the type of the object and returns it;
+; It finds out if the given object is a non-tagged belonging to the atom
+; table; If not, it looks at the tag and returns the object type.
+;
+; WARNING: Because this function determines the type of the object by
+; the process of elimination, the results will be unpredictable if the
+; input in incorrect. i.e., no validation is done on the input value;
+; To validate if the input value is indeed an object in USER's heap would
+; warant a walk down the heap; This will be very costly, if done for
+; every call; Apps like HeapWalker are expected to walk down the USER's
+; local heap and make calls to this function for every object thay come
+; accross; So, a validation done here is duplication of effort and affect
+; the performance unnecessarily
+;
+;
+;-------------------------------------------------------------------------
+
+ifndef DEBUG
+; The following is in the RETAIL version of USER
+LabelFP <PUBLIC, GetUserLocalObjType>
+ xor ax, ax ; Return Unknown struct type
+ retf 2 ; Compensate for the WORD parameter
+else
+; The following is in the DEBUG version of USER
+
+cProc GetUserLocalObjType, <PUBLIC, FAR>, <si, di>
+
+ParmW pObj ; Near pointer to an OBJ in USER's heap
+
+cBegin
+ ; Now DS register is pointing to USER's DS
+ ;
+ ; Check if the object is a moveable object
+ mov bx, pObj
+ mov ax, [bx].la_prev
+ test ax, 01 ; is it a free object
+ jz FoundFreeObj
+ test ax, 02 ; Is it a moveable object
+ jz FoundFixedObj
+ ; Now, it is a moveable obj; So, we have the tags
+ mov al, byte ptr [bx + SIZE LocalArena]
+ xor ah, ah
+ jmps FoundObjType
+
+FoundFreeObj:
+ mov ax, ST_FREE
+ jmps FoundObjType
+
+FoundFixedObj:
+ ; Assume that the object belongs to atom table
+ mov ax, ST_ATOMS
+
+ ; Check if this object is the atom table itself
+ add bx, SIZE LocalArena - 2
+ cmp bx, ds:[8] ; pAtomTable is at this offset.
+ je FoundObjType
+
+ ; Check if this is possibly an atom string. If so, the first word
+ ; stored in this object is a ptr to the next string or NULL;
+ ; Check if the last two bits are zero; If they are not zero, then
+ ; this can not be an atom; If they are zero, this may or may not be
+ ; an atom;
+
+ mov cx, [bx]
+ and cx, 03h
+ jnz NotAnAtom
+
+ ; Now walk down the atom table and check each entry against the
+ ; given object
+
+ mov dx, bx ; save the near pointer to the object
+ mov bx, ds:[8] ; Get the pointer to the atom table pAtomTable
+ mov cx, [bx].at_prime ; Get the number of entries
+ ; Skip to the first entry in the atom table
+ errnz <at_hashtable - 2>
+AtomLoop2:
+ errnz <SIZE at_hashtable - 2>
+ add bx, 2 ;
+ errnz <a_chain>
+ mov si, [bx] ; Pointer to the next string
+AtomLoop:
+ or si, si
+ jz NextBucket ; Goto NextBucket
+
+ ;Check the new atom matches the given object
+ cmp si, dx
+ jz FoundObjType ; AX already has ST_ATOMS in it
+ mov si, [si].a_chain
+ jmps AtomLoop
+
+NextBucket:
+ loop AtomLoop2
+ mov bx, dx ; Make bx point to the first byte of the object
+
+NotAnAtom:
+ ; bx points to the tag byte of the object
+ xor ah, ah
+ mov al, byte ptr [bx]
+FoundObjType:
+ ; ax already contains the proper return value
+cEnd
+endif
+
+endif ;WOW
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* mouse_event() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Mouse interrupt event routine
+;
+; Entry: (ax) = flags:
+; 01h = mouse move
+; 02h = left button down
+; 04h = left button up
+; 08h = right button down
+; 10h = right button up
+; 20h = middle button down
+; 40h = middle button up
+; 8000h = absolute move
+; (bx) = dX
+; (cx) = dY
+; (dx) = # of buttons, which is assumed to be 2.
+; (si) = extra info loword (should be null if none)
+; (di) = extra info hiword (should be null if none)
+;
+; Exit: None
+;
+; Uses: All registers
+;
+
+ExternFP <MouseEvent> ; Thunk in user4.asm
+
+LabelFP <PUBLIC, mouse_event>
+ push si ; Preserve the same regs as Win3.1
+ regptr disi,di,si
+ cCall <FAR PTR MouseEvent>, <ax,bx,cx,dx,disi>
+ pop si
+ retf
+
+LabelFP <PUBLIC, GetMouseEventProc>
+ mov dx,cs
+ mov ax,offset mouse_event
+ retf
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* keybd_event() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Keyboard interrupt handler.
+;
+; ENTRY: AL = Virtual Key Code, AH = 80 (up), 00 (down)
+; BL = Scan Code
+; BH = 0th bit is set if it is an enhanced key(Additional return etc.,).
+; SI = LOWORD of ExtraInfo for the message
+; DI = HIWORD of ExtraInfo for the message
+;
+; NOTES: This routine must preserve all registers.
+
+ExternFP <KeybdEvent> ; Thunk in user4.asm
+
+LabelFP <PUBLIC, keybd_event>
+ push es ; Preserve the registers
+ push dx
+ push cx
+ push bx
+ push ax
+ regptr disi,di,si
+ cCall <FAR PTR KeybdEvent>, <ax,bx,disi>
+ pop ax
+ pop bx
+ pop cx
+ pop dx
+ pop es
+ retf
+
+sEnd %SEGNAME
+
+end
diff --git a/private/mvdm/wow16/user/winnet.asm b/private/mvdm/wow16/user/winnet.asm
new file mode 100644
index 000000000..c657d7893
--- /dev/null
+++ b/private/mvdm/wow16/user/winnet.asm
@@ -0,0 +1,501 @@
+;
+; WINNET.ASM
+;
+; Access to WINNET calls via user
+;
+;
+
+memS=1
+?WIN=1
+?PLM=1
+
+.xlist
+include cmacros.inc
+.list
+
+WN_SUCCESS equ 0
+WN_NOT_SUPPORTED equ 1 ; returned if no function exported
+
+;
+; Network information structure, containing the
+; list of driver entrypoints
+;
+netinfo struc
+
+ lpfnOpenJob dd ? ; @1
+ lpfnCloseJob dd ? ; @2
+ lpfnAbortJob dd ? ; @3
+ lpfnHoldJob dd ? ; @4
+ lpfnReleaseJob dd ? ; @5
+ lpfnCancelJob dd ? ; @6
+ lpfnSetJobCopies dd ? ; @7
+ lpfnWatchQueue dd ? ; @8
+ lpfnUnwatchQueue dd ? ; @9
+ lpfnLockQueueData dd ? ; @10
+ lpfnUnlockQueueData dd ? ; @11
+ lpfnGetConnection dd ? ; @12
+ lpfnGetCaps dd ? ; @13
+ lpfnDeviceMode dd ? ; @14
+ lpfnBrowseDialog dd ? ; @15
+ lpfnGetUser dd ? ; @16
+ lpfnAddConnection dd ? ; @17
+ lpfnCancelConnection dd ? ; @18
+ lpfnGetError dd ? ; @19
+ lpfnGetErrorText dd ? ; @20
+ lpfnEnable dd ? ; @21
+ lpfnDisable dd ? ; @22
+ lpfnRestoreConnection dd ? ; @23
+ lpfnWriteJob dd ? ; @24
+ lpfnConnectDialog dd ? ; @25
+ lpfnDisconnectDialog dd ? ; @26
+ lpfnConnectionDialog dd ? ; @27
+ lpfnViewQueueDialog dd ? ; @28
+ lpfnPropertyDialog dd ? ; @29
+ lpfnGetDirectoryType dd ? ; @30
+ lpfnDirectoryNotify dd ? ; @31
+ lpfnGetPropertyText dd ? ; @32
+
+netinfo ends
+
+createSeg _%SEGNAME,cd,word,public,CODE
+
+sBegin data
+
+pNetInfo dw 0 ; near pointer to network information
+public pNetInfo
+
+hWinnetDriver dw 0 ; handle to driver module
+public hWinnetDriver
+
+sEnd data
+
+
+sBegin cd
+assumes cs,cd
+assumes es,data
+
+;-----------------------
+; NetCall
+;
+; Move the offset of the function pointer in the net info structure, and
+; call the function which does the bulk of the work (near call). If the
+; call runs into an error, it will return, otherwise, it will not return,
+; it will pop the return address and jump to the net driver. No prologue
+; or epilogue needs to be generated. If CallNetDriver returns, though,
+; we need to pop the parameters off the stack. In cMacros, the size of
+; these parameters is stored in the ?po variable.
+;
+; ?po gets set to zero in order to avoid a WHOLE LOT of "possible invalid
+; use of nogen" warning messages.
+;
+; Realize that this is, after all, a hack, the purpose of which is to
+; reduce code.
+;
+NetCall macro lpfn
+
+__pop = ?po
+?po = 0
+
+&cBegin <nogen>
+
+ mov bx,lpfn
+ call CallNetDriver
+ ret __pop
+
+&cEnd <nogen>
+
+endm
+
+;--------------------------------------------------------------------------
+; CallNetDriver
+;
+; This function does all the work. For each entry point there is a small
+; piece of code which loads the offset of the function pointer in the net
+; info structure into SI and calls this function. This function verifies
+; that the net driver is loaded and calls the appropriate function
+;
+
+LabelFP <PUBLIC, FarCallNetDriver>
+CallNetDriver proc near
+
+ mov ax,_DATA
+ mov es,ax
+
+ cmp es:pNetInfo,0 ; net driver loaded?
+ jz cnd_error ; return error code
+
+ add bx,es:pNetInfo ; add the base of the table
+ cmp word ptr es:[bx+2],0 ; is there a segment there?
+ jz cnd_error ; NULL, return error code
+
+ pop ax ; remove near return address
+
+ jmp dword ptr es:[bx] ; jump into net driver
+
+cnd_error:
+ mov ax,WN_NOT_SUPPORTED ; return error code
+ ret ; return to entry point code
+
+CallNetDriver endp
+
+;--------------
+; WNetGetCaps
+;
+; This function returns a bitfield of supported functions rather than an
+; error code, so we return 0 (no functions supported) instead of an error
+; code if there is no driver GetCaps function to call. Also, hack to get
+; handle for index -1.
+;
+
+cProc WNetGetCaps2, <FAR,PUBLIC>
+
+ parmW nIndex
+
+cBegin <nogen>
+
+ mov bx,lpfnGetCaps
+ call CallNetDriver
+ xor ax,ax
+ ret ?po
+
+cEnd <nogen>
+
+if 0
+; this is now in C (net.c)
+assumes ds,data
+
+cProc IWNetGetCaps, <FAR,PUBLIC, NODATA>
+
+ parmW nIndex
+
+cBegin
+ cmp nIndex, 0FFFFh
+ jz gc_gethandle
+ cCall WNetGetCaps2, <nIndex>
+ jmp short gc_exit
+
+gc_gethandle:
+ mov ax, _DATA
+ mov es, ax
+assumes es, DATA
+ mov ax, es:hWinnetDriver
+assumes es, NOTHING
+
+gc_exit:
+cEnd
+
+assumes ds,nothing
+endif
+
+
+;--------------
+; IWNetGetUser
+;
+cProc IWNetGetUser, <FAR,PUBLIC, NODATA>
+
+ parmD szUser
+ parmD lpBufferSize
+
+NetCall lpfnGetUser
+
+
+;--------------------
+; IWNetAddConnection
+;
+cProc IWNetAddConnection , <FAR, PUBLIC, NODATA>
+
+ parmD szNetPath
+ parmD szPassword
+ parmD szLocalName
+
+NetCall lpfnAddConnection
+
+;-----------------------
+; IWNetCancelConnection
+;
+cProc IWNetCancelConnection , <FAR, PUBLIC, NODATA>
+
+ parmD szName
+ parmW fForce
+
+NetCall lpfnCancelConnection
+
+;---------------------
+; IWNetGetConnection
+;
+cProc IWNetGetConnection , <FAR, PUBLIC, NODATA>
+
+ parmD lpszLocalName
+ parmD lpszRemoteName
+ parmD lpcbBuffer
+
+NetCall lpfnGetConnection
+
+
+;--------------------
+; IWNetOpenJob
+;
+cProc IWNetOpenJob , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmD szJobTitle
+ parmW nCopies
+ parmD lpfh
+
+NetCall lpfnOpenJob
+
+;--------------------
+; IWNetCloseJob
+;
+cProc IWNetCloseJob , <FAR, PUBLIC, NODATA>
+
+ parmW fh
+ parmD lpidJob
+ parmD szQueue
+
+NetCall lpfnCloseJob
+
+;-----------------
+; IWNetHoldJob
+;
+cProc IWNetHoldJob , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmW idJob
+
+NetCall lpfnHoldJob
+
+;--------------------
+; IWNetReleaseJob
+;
+cProc IWNetReleaseJob , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmW idJob
+
+NetCall lpfnReleaseJob
+
+;---------------------
+; IWNetCancelJob
+;
+cProc IWNetCancelJob , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmW idJob
+
+NetCall lpfnCancelJob
+
+;--------------------
+; IWNetSetJobCopies
+;
+cProc IWNetSetJobCopies , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmW idJob
+ parmW nCopies
+
+NetCall lpfnSetJobCopies
+
+;--------------------
+; IWNetDeviceMode
+;
+cProc IWNetDeviceMode , <FAR, PUBLIC, NODATA>
+
+ parmW hwnd
+
+NetCall lpfnDeviceMode
+
+;--------------------
+; IWNetBrowseDialog
+;
+cProc IWNetBrowseDialog , <FAR, PUBLIC, NODATA>
+
+ parmW hwnd
+ parmW nFunction
+ parmD szPath
+ parmD lpnSize
+
+NetCall lpfnBrowseDialog
+
+;--------------------
+; IWNetWatchQueue
+;
+cProc IWNetWatchQueue , <FAR, PUBLIC, NODATA>
+
+ parmW hwnd
+ parmD szLocal
+ parmD szUsername
+ parmW wIndex
+
+NetCall lpfnWatchQueue
+
+;--------------------
+; IWNetUnwatchQueue
+;
+cProc IWNetUnwatchQueue , <FAR,PUBLIC, NODATA>
+
+ parmD szQueue
+
+NetCall lpfnUnwatchQueue
+
+;---------------------
+; IWNetLockQueueData
+;
+cProc IWNetLockQueueData , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+ parmD szUsername
+ parmD lplpQueue
+
+NetCall lpfnLockQueueData
+
+;------------------------
+; IWNetUnlockQueueData
+;
+cProc IWNetUnlockQueueData , <FAR, PUBLIC, NODATA>
+
+ parmD szQueue
+
+NetCall lpfnUnlockQueueData
+
+;------------------------
+; IWNetGetError
+;
+cProc IWNetGetError , <FAR, PUBLIC, NODATA>
+
+ parmD lpnError
+
+NetCall lpfnGetError
+
+;------------------------
+; IWNetGetErrorText
+;
+cProc IWNetGetErrorText , <FAR, PUBLIC, NODATA>
+
+ parmW nError
+ parmD lpBuffer
+ parmD lpnSize
+
+NetCall lpfnGetErrorText
+
+;----------------------
+; IWNetAbortJob
+;
+cProc IWNetAbortJob , <FAR, PUBLIC, NODATA>
+
+ parmD lpszQueue
+ parmW fh
+
+NetCall lpfnAbortJob
+
+;-----------------------
+; WNetEnable
+;
+cProc WNetEnable, <FAR, PUBLIC, EXPORTED>
+
+NetCall lpfnEnable
+
+;------------------------
+; WNetDisable
+;
+cProc WNetDisable, <FAR, PUBLIC, EXPORTED>
+
+NetCall lpfnDisable
+
+;-----------------------
+; WNetWriteJob
+;
+cProc WNetWriteJob , <FAR, PUBLIC, EXPORTED>
+
+ parmW hJob
+ parmD lpData
+ parmD lpcb
+
+NetCall lpfnWriteJob
+
+;-----------------------
+; WNetConnectDialog
+;
+cProc WNetConnectDialog, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmW iType
+
+NetCall lpfnConnectDialog
+
+;-----------------------
+; WNetDisconnectDialog
+;
+cProc WNetDisconnectDialog, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmW iType
+
+NetCall lpfnDisconnectDialog
+
+;-------------------------
+; WNetConnectionDialog
+;
+cProc WNetConnectionDialog, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmW iType
+
+NetCall lpfnConnectionDialog
+
+;---------------------------
+; WNetViewQueueDialog
+;
+cProc WNetViewQueueDialog, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmD lpdev
+
+NetCall lpfnViewQueueDialog
+
+;--------------------------
+; WNetGetPropertyText
+;
+cProc WNetGetPropertyText, <FAR, PUBLIC, EXPORTED>
+
+ parmW iDlg
+ parmD lpName
+ parmW cb
+
+NetCall lpfnGetPropertyText
+
+;--------------------------
+; WNetPropertyDialog
+;
+cProc WNetPropertyDialog, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmW iDlg
+ parmD lpfile
+
+NetCall lpfnPropertyDialog
+
+;---------------------------
+; WNetGetDirectoryType
+;
+cProc WNetGetDirectoryType, <FAR, PUBLIC, EXPORTED>
+
+ parmD lpdir
+ parmD lptype
+
+NetCall lpfnGetDirectoryType
+
+;--------------------------
+; WNetDirectoryNotify
+;
+cProc WNetDirectoryNotify, <FAR, PUBLIC, EXPORTED>
+
+ parmW hwnd
+ parmD lpdir
+ parmW wOper
+
+NetCall lpfnDirectoryNotify
+
+sEnd cd
+
+end
diff --git a/private/mvdm/wow16/user/winq.asm b/private/mvdm/wow16/user/winq.asm
new file mode 100644
index 000000000..b3a5a6d38
--- /dev/null
+++ b/private/mvdm/wow16/user/winq.asm
@@ -0,0 +1,1154 @@
+;;;;;;;;;;;;;;;;;;;;;; START OF SOURCE FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;
+COMMENT $ HEADER
+
+SOURCE FILE NAME: winq
+
+DESCRIPTIVE NAME: queue management module
+
+FUNCTION: This module contains routines for creating and
+ deleting queues and reading and writing messages
+ to queues. The circular queue data structure (struct Q
+ defined in user.h) consists of a header followed by a
+ sequence of messages
+
+ENTRY POINTS: InitSysQ, CreateQueue, DeleteQueue, WriteMessage, ReadMessage,
+ FQueueNotFull, DelQEntry, UnlinkQ
+$
+;;;;;;;;;;;;;;;;;;;;;; END OF SOURCE FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;
+
+
+;% MOVEDS - NK (no change)
+
+norasterops = 1
+notext = 1
+ .xlist
+ include user.inc
+ .list
+
+ExternFP <LocalAlloc, LocalFree>
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+assumes cs,CODE
+assumes ds,DATA
+
+;============================================================================
+
+sBegin DATA
+
+ifndef WOW
+ExternW idSysPeek ; id in sys queue of message being looked at.
+endif
+
+sEnd DATA
+
+;============================================================================
+
+ExternFP <GetSystemMsecCount>
+ExternFP <GetCurrentTask>
+ExternFP <SetTaskQueue>
+ExternFP <GlobalAlloc, GlobalFree>
+ExternFP <PostEvent>
+ExternFP <PostMessage>
+ExternFP <GetExeVersion>
+
+sBegin CODE
+
+; CS variables:
+ifndef WOW ; WOW doesn't use these
+ExternNP <CheckMsgFilter2>
+ExternNP <CheckHwndFilter2>
+ExternNP <SetWakeBit>
+ExternNP <WakeSomeone>
+ExternNP <SetWakeBit2>
+ExternNP <SkipSysMsg>
+ExternNP <PostMove>
+ExternNP <HqCur2ES, HqCur2DS>
+ExternFP <HqCurrent>
+else
+ExternFP <GetTaskQueueES>
+endif ; WOW doesn't use these
+
+ifdef WOW ; These functions stolen from winloop3.asm
+
+;*--------------------------------------------------------------------------*
+;* *
+;* HqCur2ES() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Get hqCurrent in ES.
+
+LabelNP <PUBLIC, HqCur2ES>
+ call GetTaskQueueES ; Another wonderful KERNEL routine
+ ret
+
+;*--------------------------------------------------------------------------*
+;* *
+;* HqCurrent() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Get handle of current queue and return in AX.
+
+LabelFP <PUBLIC, HqCurrent>
+ call HqCur2ES ; Code depends on both ES and AX
+ mov ax,es
+ or ax,ax ; Set flags
+ retf
+
+endif ; WOW These functions stolen from winloop3.asm
+
+
+ifndef WOW ; No InitSysQueue for WOW
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+InitSysQueue () - Create and initialize the system queue.
+
+LINKAGE: FAR PLM
+
+ENTRY: WORD cQEntries - number of entries in system queue
+
+EXIT: hSysQueue contains handle for system queue (Shared global object.)
+
+EFFECTS: all registers modified.
+
+INTERNAL: CreateQueue2
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Set up register linkage for CreateQueue2 and let it do the work.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc InitSysQueue,<PUBLIC,FAR>,<DS>
+cBegin
+ mov ax,_INTDS
+ mov ds,ax
+assumes ds,INTDS
+ mov ax,ds:[cQEntries] ; number of entries
+ push ax
+ mov ax,size INTERNALSYSMSG ; size of entry
+ push ax
+ call CreateQueue2 ; create system queue
+ mov ds:[hqSysQueue],ax
+assumes ds,NOTHING
+cEnd
+endif ; No InitSysQueue for WOW
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+CreateQueue (cMsgs) - Create a queue.
+
+Create a queue for the currently executing task and stick its handle
+in the task header and the queue list.
+
+LINKAGE: FAR PLM
+
+ENTRY: WORD cMsgs(parm1) - count of messages that can be stored in
+ queue
+
+EXIT: ax - handle to queue (shared global object.)
+
+ Newly created queue is linked to list of queues pointed
+ to by hqList.
+
+EXIT - ERROR: ax hqCurrent, hqCurrentShadow contain 0.
+
+EFFECTS: all registers modified.
+
+INTERNAL: CreateQueue2
+
+EXTERNAL: SetTaskQueue
+
+WARNINGS: Running out of memory when trying to CreateQueue will
+ init current queue to 0.
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Set up register linkage for CreateQueue2 and let it create the queue.
+ Then add to linked list and then SetTaskQueue(NULL, hqCreated).
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc CreateQueue,<PUBLIC, FAR>,<DS>
+ ParmW cMsgs
+cBegin
+ push cMsgs
+ mov ax,size INTERNALMSG
+ push ax
+ call CreateQueue2
+ or ax,ax
+ jz errexit ; CreateQueue2 failed
+
+ EnterCrit
+
+ mov es,ax
+ push ax
+ mov ax,_INTDS
+ mov ds,ax
+ pop ax
+assumes ds,INTDS
+ xchg ds:[hqList],ax ; Link us in and get old head of list
+ mov es:[qHqNext],ax ; store ptr to next queue
+ push es ; save hq for return
+
+ xor ax,ax ; SetTaskQueue(NULL, es)
+ push ax
+ push es ; push queue handle
+ call SetTaskQueue ; and ram it in there
+ pop ax ; return queue handle
+
+ LeaveCrit
+assumes ds,DATA
+errexit:
+cEnd
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ PRIVATE
+CreateQueue2 (cMsgs, cbEntry) - Create a queue.
+
+Allocate a shared global object and initialize the header for the Q
+Data structure.
+
+LINKAGE: NEAR PLM
+
+ENTRY: WORD cMsgs(parm1) - count of messages that can be stored in
+ queue
+
+ WORD cbEntry(parm2) - count of bytes in single message entry.
+
+EXIT: ax - handle to queue (shared global object.)
+
+
+EXIT - ERROR: ax contains 0
+
+EFFECTS: all registers except DI modified.
+ wAppVersion gets current exe version.
+
+INTERNAL:
+
+EXTERNAL: GlobalAlloc
+
+WARNINGS: cbEntry better not be less than 5.
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Allocate a shared global object, initialize header with following
+ fields: Current Task, cbEntry, cMsgs,pmsgRead, pmsgWrite,
+ pmsgRead = pmsgWrite = rgMsg,
+ pmsgMax = queue size
+ wVersion = GetExeVersion
+ WakeBits = QS_SMPARAMSFREE | (SYSQ empty ? QS_INPUT : 0).
+ lpfnMsgFilter = cs:OldMsgFilter
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc CreateQueue2,<PUBLIC, NEAR>,<DI>
+ ParmW cMsgs
+ ParmW cbEntry
+
+cBegin
+ call GetCurrentTask ; get current task
+ push ax ; and save it
+
+ mov ax,cMsgs
+ mov cx,cbEntry
+ mul cx
+ add ax,size Q - size INTERNALMSG
+ push ax ; save size of queue
+
+ ; Alloc(GPTR, cMsgs * size INTERNALMSG + size Q)
+ push GPTR+GMEM_SHAREALL
+ push 0 ; hi word == 0
+ push ax
+ call GlobalAlloc
+ mov es,ax ; stick hq in es
+
+ pop cx ; pop queue size
+ pop bx ; and task handle
+
+ or ax,ax ; error on alloc?
+ jz cqexit ; yes, quit
+ xchg bx,ax ; get task handle into ax
+
+ cld
+ mov di,qHTask ; point at hTask
+ stosw ; store task handle
+ errnz qHTask-2
+ mov ax,cbEntry ; store size of entry
+ stosw
+ errnz qCbEntry-4
+ inc di ; cMsgs = 0 (cleared by alloc)
+ inc di
+ errnz qCMsgs-6
+ mov ax,qRgmsg
+ stosw ; init read/write pointers
+ errnz qPmsgRead-8
+ stosw
+ errnz qPmsgWrite-10
+ mov ax,cx ; get size of queue (ptr to end)
+ stosw ; and store it
+ errnz qPmsgMax-12
+
+ push es ; save hq
+ call GetExeVersion ; returns sys version in dx, app in ax
+ pop es
+
+ mov es:[qWVersion],ax ; set up app version number
+ mov es:[qWakeBits],QS_SMPARAMSFREE ; default ON flags.
+ mov es:[qFlags],QF_INIT ; indicate initialization is in progress
+
+ mov ax,es ; Save hq in ax.
+ push ax
+ mov ax,_INTDS
+ mov es,ax
+ pop ax
+assumes es,INTDS
+ cmp es:[hqList],0 ; If we are the first queue and
+ jnz cq100 ; there is input waiting for us,
+
+ mov es:[hqCursor],ax ; Initialize this guy for WakeSomeone.
+ cmp es:[hqSysQueue],0 ; System queue set yet???
+ jz cq100 ; Nope, don't touch it
+ mov bx,es:[hqSysQueue] ; set the input flag.
+ or bx,bx
+ jz cq100
+ mov es,bx
+ cmp es:[qCMsgs],0 ; Any messages in the system queue?
+ mov es,ax
+ jz cq100 ; No messages.
+ or es:[qWakeBits],QS_INPUT ; Yes - tell the guy he has input.
+
+cq100:
+;
+; Return queue handle in ax.
+;
+cqexit:
+cEnd
+
+;============================================================================
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+DeleteQueue() - Remove current queue from queue list
+
+Unlink Queue from all lists, Delete the Q global object, then wake
+someone else.
+
+LINKAGE: NEAR PLM
+
+ENTRY:
+
+EFFECTS: current queue is removed from queue list and object is deleted.
+ New task wakes up.
+
+ hqSysLock = 0
+
+ all registers modified.
+
+INTERNAL: UnlinkQ, SetWakeBit, WakeSomeone
+
+EXTERNAL: GlobalFree,
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Unlink the queue from list of queues then unlink from all send lists.
+ Then set the result bit for every queue with sendmessage waiting on
+ this guy. Then free queue global object, and wakesomeone.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc DeleteQueue,<PUBLIC, NEAR>, <SI>
+cBegin
+ call HqCurrent
+ mov si,ax ; si = hqCurrent.
+
+ mov dx,_INTDS
+ push dx ; Save for later
+ mov ax,OFFSET hqList
+ push dx
+ push ax
+ push si
+ mov ax,qHqNext
+ push ax
+ call UnlinkQ ; UnlinkQ(lphqStart, hqCurrent, cbHqNext)
+ pop es ; get INTDS
+ jz dqexit ; if bad unlink, exit.
+ifndef WOW ; WOW doesn't have most USER16 structures to worry about.
+assumes es,INTDS
+ EnterCrit
+ xor bx,bx ; zero hqSysLock.
+ mov es:[hqSysLock],bx
+ mov es:[hqMouse],bx ; zero hqMouse.
+ mov es:[hqKeyboard],bx ; zero hqKeyboard.
+ mov bx,es:[hqList] ; Get the first guy in the list for
+ mov es:[hqCursor],bx ; hqCursor.
+ LeaveCrit
+;
+; Unlink this guy from everyone's hqSendList.
+;
+ mov cx,es:[hqList]
+assumes es,NOTHING
+dq100:
+ mov es,cx
+ jcxz dq200
+
+ push es:[qHqNext]
+ push cx ; Unlink this queue from all send
+ mov ax,qHqSendList ; lists.
+ push ax
+ push si
+ mov ax,qHqSendNext
+ push ax ; UnlinkQ(lphqStart, hqUnlink, cbLink)
+ call UnlinkQ
+
+ pop cx ; Get the next hq.
+ jmps dq100
+
+dq200:
+;
+; Now set the result bit of everyone waiting on a SendMsg response from
+; this guy.
+;
+ mov es,si ; es = hqCurrent.
+ mov cx,es:[qHqSendList]
+dq300:
+ mov es,cx
+ jcxz dq400 ; Are we at the end of the list?
+
+ push es:[qHqSendNext]
+
+ xor bx,bx
+ mov word ptr es:[qResult],bx ; Zero out the result.
+ mov word ptr es:[qResult+2],bx
+
+ mov ax,QS_SMRESULT ; Tell this guy to wake up and
+ call SetWakeBit2 ; get the result.
+
+ pop cx
+ jmps dq300
+
+endif ; WOW doesn't have most USER16 structures to worry about.
+
+dq400:
+ xor ax,ax
+ push ax
+ push ax ; Set NULL queue
+ call SetTaskQueue ; SetTaskQueue(NULL, NULL)
+
+ push si
+ call GlobalFree ; throw away the queue
+
+ xor cx,cx
+ifndef WOW ; No need - user32 takes care of this for WOW
+ call WakeSomeone ; wake someone up to process events
+endif ;WOW
+; if anyone jumps here, he better do it with ints enabled!
+dqexit:
+cEnd
+
+
+ifndef WOW ; WOW doesn't ever put anything in the 16-bit Queue
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+WriteMessage (hq, lParam, wParam, message, hwnd, dwExtra) - Write a message
+ to hq.
+
+If queue not full, Write message record at pmsgWrite, then advance pmsgWrite.
+SetWakeBit(hq) to tell him he has input.
+
+LINKAGE: NEAR PLM
+
+ENTRY: WORD hq handle to queue that gets message
+ DWORD lParam lParam of message
+ WORD wParam wParam of message
+ WORD message message
+ WORD hwnd associated window
+ DWORD dwExtra dwExtraMsgInfo of the message
+
+
+EXIT: zero flag not set
+ AX = pmsgWrite
+
+EXIT ERROR: zero flag set
+
+EFFECTS: Write pointer (pmsgWrite) to hq advanced to next message.
+ QS_POSTMESSAGE set for hq.
+
+ All registers changed
+
+INTERNAL: FQueueNotFull, SetWakeBit2
+
+EXTERNAL: none
+
+WARNINGS: the order of params on stack is assumed so we can do
+ a rep movsb
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Call FQueueNotFull which sets di = pmsgwrite if queue not full.
+ Blt message bytes to queue at di, advance the write pointer,
+ then SetWakeBit(hq, QS_POSTMESSAGE).
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc WriteMessage,<PUBLIC, NEAR>, <SI,DI,DS>
+ParmW hq
+ParmD lParam
+ParmW wParam
+ParmW message
+ParmW hwnd
+ParmD dwExtraInfo
+cBegin WriteMessage
+
+ NewEnterCrit ax ; This trashes ax register
+
+ push ds ; See if queue is full.
+ mov ax,hq
+ mov ds,ax
+ mov es,ax
+assumes ds,NOTHING
+assumes es,NOTHING
+ call FQueueNotFull ; Z flag set if FULL.
+ jz pmexit
+ push di ; Save Message pointer.
+
+pm30:
+ mov cx,ds:[qCbEntry] ; Copy message into queue.
+ shr cx,1
+
+ push ds
+
+ lea si,dwExtraInfo
+ push ss
+ pop ds
+ cld
+ errnz <size INTERNALSYSMSG - 7*2>
+ errnz msgTime-10
+ errnz imMsg-4
+ movsw
+ movsw
+ movsw
+ movsw
+ movsw ; Store away the message.
+ movsw
+ movsw
+
+ errnz <size INTERNALSYSMSG - 7*2>
+ errnz msgTime-10
+ errnz imMsg-4
+ sub cx,7
+ jcxz pm40 ; If have room, store time.
+
+ push es
+ call GetSystemMsecCount ; Tick count in dx:ax.
+ pop es
+
+ push ax
+ mov ax,_INTDS
+ mov ds,ax
+ pop ax
+assumes ds,INTDS
+ stosw
+ mov ax,dx
+ stosw
+
+ sub cx,2
+ jcxz pm40
+
+ mov ax,word ptr ds:[ptCursor] ; If have room, store pt.
+ stosw
+ mov ax,word ptr ds:[ptCursor+2]
+ stosw
+
+pm40:
+ pop ds
+assumes ds,DATA
+
+ pop bx ; reget ptr to msg
+ push bx
+ call rtestwrap ; advance pointer
+
+ mov ds:[qPmsgWrite],bx
+ inc ds:[qCMsgs] ; advance count
+
+ mov ax,QS_POSTMESSAGE
+ call SetWakeBit2 ; Tell this guy he has input.
+pm75:
+ pop ax ; get back message ID
+pmexit:
+ pop ds
+
+ NewLeaveCrit dx, cx ; This trashes dx and cx registers
+
+cEnd WriteMessage
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+FQueueNotFull - IsQueueFull?
+
+If queue not full, get pmsgWrite and return TRUE.
+otherwise return FALSE.
+
+LINKAGE: register
+
+ENTRY: WORD ax - hq
+
+EXIT: ax - non zero. zero flag clear
+ di - pmsgWrite (pointer to next write record.)
+
+EXIT ERROR: ax - 0; zero flag set
+
+EFFECTS: no other registers
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Advance write pointer. Error condition occurs only if
+ pmsgWrite == pmsgRead && cMsg != 0.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; FQueueNotFull - zero in ax and Z flag if FULL, else cMsgLeft in ax, NZ
+; flag set. Returns write pointer in di.
+; AX has DS on entry.
+;
+LabelNP <PUBLIC, FQueueNotFull>
+ push ds
+assumes ds,NOTHING
+ mov ds,ax
+ mov di,ds:[qPmsgWrite] ; get write pointer and advance
+ cmp di,ds:[qPmsgRead] ; if read == write, then we're either
+ jnz qfNotFull
+ xor ax,ax
+ cmp ax,ds:[qCMsgs] ; cMsgs != 0 if empty
+ jnz qfexit ; Jump if Full.
+qfNotFull:
+ push es
+ mov ax,_INTDS
+ mov es,ax
+assumes es,INTDS
+ mov ax,es:[cQEntries] ; See how many messages are left.
+assumes es,NOTHING
+ pop es
+ sub ax,ds:[qCMsgs] ; number of messages left
+qfexit:
+ or ax,ax
+ pop ds
+assumes ds,DATA
+ ret
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+ReadMessage (hq, lpMsg, hwndFilter, msgMinFilter, msgMaxFilter, fRemoveMsg)
+ Read a message from hq.
+
+If queue not empty, read message satisfying filter conditions from hq to *lpMsg.
+
+LINKAGE: FAR PLM
+
+ENTRY: WORD hq handle to queue to read from
+ MSG *lpMsg far pointer to message buffer
+ NOTE: This points to MSG struct and not INTERNALMSG.
+ WORD hwndFilter Window filter
+ WORD msgMinFilter min filter spec for message number
+ WORD msgMaxFilter max filter spec for message number
+ WORD fRemoveMsg Remove message if non-zero
+
+EXIT: zero flag not set
+ ax = Non-Zero - we have a message.
+ ax = 0 - we don't have a message.
+
+EXIT ERROR: zero flag set
+
+EFFECTS: All registers trashed
+ QS_POSTMESSAGE wakebit cleared if no msgs left in app queue.
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS:
+
+REVISION HISTORY:
+ SRL - 4/12 Fixed bug where if system queue was locked by someone else,
+ it was being unlocked.
+ SRL - 4/18 Fixed journalling.
+ SRL - 5/4 Changed system queue journalling to call ScanSysQueue.
+ (which used to be called FindMsgHq. It now does all the
+ message enumeration).
+
+IMPLEMENTATION:
+ If not quitting, look through the specified queue starting at pmsgRead
+ for message that matches filters. Blt message to lpmsg, advance the read
+ pointer. If out of queue messages, clear the input bit.
+ Message matches hwndFilter if hwndFilter == 0 or hwndFilter == msgHwnd.
+ Message matches msgMinFilter, msgMaxFilter if both are zero or
+ msgMinFilter <= msg <= msgMaxFilter.
+
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; ReadMessage(hq, lpMsg, hwndFilter, msgMinFilter, msgMaxFilter, fRemoveMsg)
+;
+; NOTE: lpMsg points to MSG structure and not INTERNALMSG.
+;
+cProc ReadMessage, <PUBLIC, FAR>, <SI, DI,DS>
+ParmW hq
+ParmD lpMsg
+ParmW hwndFilter
+ParmW msgMinFilter
+ParmW msgMaxFilter
+ParmW fRemoveMsg
+cBegin
+ push hq ; set ds to queue pointer
+ pop ds
+assumes ds,NOTHING
+
+ mov bx,fRemoveMsg ; pass this to rmquit
+ call rmquit ; Must we quit?
+ jnz rmexit ; Exit and be sure to leave the
+ ; QS_POSTMESSAGE bit still set.
+;
+; Run through the queue and find a message that matches the filters.
+;
+rm150:
+ xor ax,ax
+ cmp ds:[qCMsgs],ax
+ jz rm500 ; nothing in queue: exit
+
+ mov si,ds:[qPmsgRead] ; Get current read pointer.
+
+rm200:
+ call rmcheckappqueue ; Check the app queue for a message
+ jnz rm500 ; fitting the filters.
+
+rm400:
+ call rtestwrap ; increment pointer in bx and copy to si
+ mov si,bx
+ jnz rm200 ; at end of queue if Z set
+ xor ax,ax ; return FALSE
+rm500:
+ EnterCrit
+ cmp ds:[qCMsgs],0 ; If no messages left, and out the
+ jnz rm600 ; input bit.
+ cmp ds:[qCQuit],0 ; But only if not quitting
+ jnz rm600
+ and ds:[qWakeBits],NOT QS_POSTMESSAGE
+rm600:
+ LeaveCrit
+rmexit:
+assumes es,NOTHING
+assumes ds,DATA
+cEnd
+
+assumes ds,NOTHING
+
+ ; bx = fRemoveMsg
+rmquit:
+ mov ax,ds:[qCQuit] ; Are we in the middle of quiting?
+ or ax,ax ; if cQuit == 0, then continue
+ jz rmq200 ; return Z.
+
+; dec al ; if al == 2, then send quit msg
+; jnz rmq100
+ cmp ds:[qCMsgs],0 ; if queue not empty, don't send quit
+ jnz rmq200
+; inc ds:[qCQuit] ; set sticky quit & send quit msg
+ or bx,bx
+ jz rmq100 ; if PM_NOREMOVE, multiple WM_QUIT's
+ mov ds:[qCQuit],0 ; give only one WM_QUIT(raor)
+rmq100:
+ les bx,lpMsg
+ mov es:[bx].msgMessage,WM_QUIT ; send a WM_QUIT
+ mov es:[bx].msgHwnd,NULL ; null window handle
+ mov ax,ds:[qExitCode] ; stick the exit code in wParam
+ mov es:[bx].msgWParam,ax
+ or al,TRUE
+ ret
+rmq200:
+ xor ax,ax
+ ret
+;
+; If the hq is an app queue, we can filter immediately.
+;
+rmcheckappqueue:
+ mov bx,ds:[si].ismMsg.msgHwnd ; see if hwnd satisfies hwndFilter
+ mov cx,hwndFilter
+ call CheckHwndFilter2
+ mov bx,si ; copy read ptr into bx
+ jz rmc200 ; bad luck - try next one
+ mov ax,ds:[si].ismMsg.msgMessage ; see if msgMinFilter <= msg <= msgMaxFilter
+ mov cx,msgMinFilter ; cx = msgMinFilter
+ mov dx,msgMaxFilter ; dx = msgMaxFilter
+ call CheckMsgFilter2 ; Z if no message.
+ jz rmc200
+;
+; We've found a message -- read it into lpMsg
+;
+ les di,lpMsg ; get pointer to event block
+ mov cx,ds:[qCbEntry]
+ sub cx, size INTERNALMSG - size MSG
+ push si ; preserve ptr to ExtraMsgInfo
+ add si, size INTERNALMSG - size MSG
+ cld
+ rep movsb ; copy message structure & advance rd ptr
+;
+; save away time, id, and position of this event in queue header
+;
+; NOTE: this code doesn't work for the system queue, but that's ok since we
+; don't use the queue's time anyway.
+;
+ sub si,size MSG - msgTime ; point at saved time
+ mov di,qTimeLast ;
+ push ds ; copy into ES too
+ pop es
+ movsw ; copy time and position
+ movsw
+ errnz qPtLast-qTimeLast-4
+ movsw
+ movsw
+ mov ax,bx ; store position of msg in q header
+ stosw
+ errnz qIdLast-qPtLast-4
+ pop si ; Restore ptr to ExtraMsgInfo
+ errnz qdwExtraInfoLast-qIdLast-2
+ errnz <size INTERNALMSG - size MSG - 4>
+ movsw
+ movsw
+
+ cmp fRemoveMsg,0 ; are we supposed to yank the message?
+ jnz rmc100 ; yes: take it out
+ mov ds:[qIdLast],1 ; stick something random in qidLast
+ jmps rmc150 ; so we don't reply until it's yanked
+rmc100:
+ call DelQEntry ; delete queue entry & update ptrs
+rmc150:
+ mov ax,bx ; return ID value, TRUE, NZ.
+ or ax,ax
+rmc200:
+ ret
+
+assumes ds,DATA
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ PRIVATE
+DelQEntry - Delete a queue message entry.
+
+Delete message entry from queue. Adjust pmsgRead, pmsgWrite
+and cMsgs.
+
+LINKAGE: register
+
+ENTRY: WORD bx - pointer to entry to delete
+ WORD ds - hq
+
+EXIT: void
+
+EFFECTS: pmsgRead and pmsgWrite are adjusted, and part of rgMsg
+ is blt'ed to fill hole left by deleted message.
+
+ Trashes es, si, di
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ disable interrupts, change cMsgs, pmsgRead, pmsgWrite, then
+ rep movsb from bottom up.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+LabelNP <PUBLIC, DelQEntry>
+
+assumes DS,NOTHING
+
+ EnterCrit
+ push ds
+ pop es
+ dec ds:[qCMsgs] ; decrement count
+ mov ax,ds:[qCbEntry]
+ mov si,ds:[qPmsgRead]
+ mov di,ds:[qPmsgWrite]
+ cmp si,bx ; compare sptr to dptr
+ ja de500
+;
+; rptr < dptr: blt stuff below up
+; move(rptr, rptr+1, dptr-rptr)
+; rptr++;
+;
+ std ; blt backwards
+ mov cx,bx ; cb = dptr-rptr
+ sub cx,si
+ mov si,bx ; src = dptr
+ dec si ; point at first byte to copy
+ mov di,si ; dest = src + size(entry)
+ add di,ax
+ rep movsb ; copy those bytes
+ inc di ; readjust DI
+ cmp di,ds:[qPmsgMax] ; update read pointer
+ jb de200 ; checking for wraparound
+ mov di,qRgmsg
+de200:
+ mov ds:[qPmsgRead],di
+ cld
+ LeaveCrit
+ ret
+;
+; rptr > dptr: blt stuff above down
+; wptr--;
+; move(dptr + 1, dptr, wptr - dptr)
+;
+de500:
+ cld
+ mov si,bx ; src = dptr + size(entry)
+ add si,ax
+ mov cx,di ; cb = (wptr - (dptr + size(entry)))
+ sub cx,si
+ mov di,bx ; dest = dptr
+ rep movsb ; copy those bytes
+ mov ds:[qPmsgWrite],di ; update write pointer
+ LeaveCrit
+ ret
+;
+; increment read ptr in bx, testing for wraparound
+;
+LabelNP <PUBLIC, rtestwrap>
+ add bx,ds:[qCbEntry] ; advance pointer
+ cmp bx,ds:[qPmsgMax] ; wrap around if needed
+ jb tw50
+ mov bx,qRgmsg
+tw50:
+ cmp bx,ds:[qPmsgWrite] ; set CC's if end of queue
+ ret
+
+assumes ds,DATA
+
+endif ; WOW doesn't ever put anything in the 16-bit Queue
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+LinkQ (lphqStart, hqLink, ibLink) - Add Q to linked list.
+
+Add new queue entry to END of linked list starting at lphqStart and
+linked by ibLink. ibLink can be qHqNext or qHqSendNext.
+
+LINKAGE: NEAR PLM
+
+ENTRY: DWORD lphqStart (parm1) - far pointer to start of queue list
+ WORD hqLink (parm2) - handle of queue to be linked
+ WORD ibLink (parm3) - byte index to link to be used in
+ Q structure.
+
+EXIT: ax contains hqLink
+
+EFFECTS: all registers modified.
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Walk the linked list starting at lphqStart till hqNext is NULL indicating
+ end of list. Add new entry to list there.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+LabelNP <PUBLIC, LinkQ>
+; ret = 0+2 (saved si)
+; ibLink = 2+2
+; hqLink = 4+2
+; lpHqStart = 6+2
+;
+ push si
+ mov si,sp
+
+ EnterCrit
+
+ les bx,ss:[si+8] ; Get lpHqStart
+
+lnk100:
+ mov cx,word ptr es:[bx] ; Check for end of the list.
+ jcxz lnk200
+
+ mov es,cx ; Get Next Link.
+ mov bx,ss:[si+4] ; BX = ibLink.
+ jmps lnk100
+
+lnk200:
+ mov ax,ss:[si+6] ; Store hqLink at end of list.
+ mov word ptr es:[bx],ax
+
+ mov es,ax ; AX = hqLink.
+ mov bx,ss:[si+4]
+ mov word ptr es:[bx],cx ; CX = 0. Zero out pNext.
+
+ LeaveCrit
+ pop si
+ ret 8
+
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+UnlinkQ (lphqStart, hqLink, ibLink) - Unlink Q from list.
+
+Unlink queue specified by hqLink from linked list starting at lphqStart and
+linked by ibLink. ibLink can be qHqNext or qHqSendNext.
+
+LINKAGE: NEAR PLM
+
+
+ENTRY: DWORD lphqStart (parm1) - far pointer to start of queue list
+ WORD hqLink (parm2) - handle of queue to be unlinked
+ WORD ibLink (parm3) - byte index to link to be used in
+ Q structure.
+
+EXIT: ax contains handle of unlinked queue, zero flag clear
+
+EXIT ERROR - zero flag is set
+
+EFFECTS: all registers modified.
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Walk the linked list starting at lphqStart till hqLink is found and
+ unlink.
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+LabelNP <PUBLIC, UnlinkQ>
+;
+;
+; ret = 0+2+ (pushed si)
+; cbLink = 2+2
+; hq = 4+2
+; lpHqStart = 6+2
+;
+assumes ds,NOTHING
+ push si
+ mov si,sp
+ push di
+ push ds
+
+ EnterCrit
+
+ les di,ss:[si+8] ; Get lpHqStart.
+ mov bx,ss:[si+6] ; Get hqUnlink.
+
+ulq100:
+ mov cx,es:[di] ; Exit with zero if at end of list.
+ jcxz ulqExit
+
+ cmp cx,bx ; Have we found the guy that points
+ jz ulq200 ; to hqUnlink?
+
+ mov es,cx ; Point to the next guy and continue.
+ mov di,ss:[si+4]
+ jmps ulq100
+
+ulq200:
+ mov ds,bx ; Get the hq that hqUnlink points to.
+ mov bx,ss:[si+4]
+ mov bx,ds:[bx]
+
+ mov es:[di],bx ; Store in hqLinkNext of the guy
+ ; previous to hqUnlink.
+ulqExit:
+ LeaveCrit
+
+ or cx,cx
+ pop ds
+ pop di
+ pop si
+ ret 8
+assumes DS,DATA
+
+ifndef WOW ; WOW thunks SetMessageQueue
+;;;;;;;;;;;;;;;;;;;;;;;;;; START OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;
+COMMENT $ LOCAL
+BOOL SetMessageQueue(cMsg)
+
+ This function is available to the task that desires a larger message
+ queue than the default. This routine must be called from the
+ applications' WinMain routine as soon as possible. It must not be
+ called after any operation that could generate messages (such as
+ a CreateWindow). Any messages currently in the queue will be
+ destroyed. By default, the system creates a default queue with room
+ for 8 messages.
+
+LINKAGE: FAR PLM
+
+
+ENTRY: WORD cMsg - The size of the new queue in messages.
+
+EXIT: ax contains:
+ TRUE: If new queue is sucessfully created.
+ FALSE: If there was an error creating the new queue. In this case,
+ the application has no queue associated with it (since the
+ origional queue is deleted first). The application MUST
+ call SetMessageQueue with a smaller size until a TRUE is
+ returned (or the application may terminate itself).
+
+EFFECTS: SI, DI preserved.
+
+INTERNAL: none
+
+EXTERNAL: none
+
+WARNINGS: none
+
+REVISION HISTORY:
+
+IMPLEMENTATION:
+ Call DeleteQueue()
+ Call CreateQueue(cMsg)
+$
+;;;;;;;;;;;;;;;;;;;;;;;;;; END OF SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+cProc SetMessageQueue, <PUBLIC, FAR, EXPORTED>, <SI, DI>
+ParmW cMsg
+cBegin
+ call DeleteQueue
+ mov ax,cMsg
+ push ax
+ call CreateQueue
+cEnd
+
+endif ; WOW thunks SetMessageQueue
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/user/winrect.asm b/private/mvdm/wow16/user/winrect.asm
new file mode 100644
index 000000000..bef9dd270
--- /dev/null
+++ b/private/mvdm/wow16/user/winrect.asm
@@ -0,0 +1,842 @@
+TITLE - Converted Winrect.c to Assembler
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowusr.inc
+ include cmacros.inc
+NOEXTERNS=1 ; to suppress including most of the crap in user.inc
+ include user.inc
+ .list
+
+sBegin CODE
+
+assumes cs, CODE
+assumes ds, DATA
+
+;******************************************************************************
+; ORIGINAL C SOURCE
+;
+;*void FAR SetRect(pRect,left,top,right,bottom)
+;*LPRECT pRect;
+;*int top,left,bottom,right;
+;*{
+;* pRect->top = top;
+;* pRect->left = left;
+;* pRect->bottom = bottom;
+;* pRect->right = right;
+;*}
+;******************************************************************************
+
+cProcVDO SetRect,<FAR, PUBLIC, NODATA>
+;ParmD lprc
+;ParmW left
+;ParmW top
+;ParmW right
+;ParmW bottom
+cBegin nogen
+
+ mov bx,sp
+ mov cx,di
+beg_fault_trap sr_trap
+ cld
+ les di,ss:[bx]+4+2+2+2+2
+ mov ax,ss:[bx]+4+2+2+2
+ stosw
+ mov ax,ss:[bx]+4+2+2
+ stosw
+ mov ax,ss:[bx]+4+2
+ stosw
+ mov ax,ss:[bx]+4
+ stosw
+end_fault_trap
+sr_cont:
+ mov di,cx
+ retf 4+2+2+2+2
+
+cEnd nogen
+
+sr_trap:
+ fault_fix_stack
+ jmp short sr_cont
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*int FAR SetRectEmpty(pRect)
+;*LPRECT pRect;
+;*{
+;* LFillStruct(pRect,sizeof(RECT),0);
+;*}
+;*
+;******************************************************************************
+
+LabelVDO SetRectEmpty
+ pop ax
+ pop dx
+
+ pop bx
+ pop cx
+
+ push dx
+ push ax
+
+ xchg di,bx
+
+beg_fault_trap sre_trap
+ mov es,cx
+
+ xor ax,ax
+ cld
+ stosw
+ stosw
+ stosw
+ stosw
+end_fault_trap
+
+sre_cont:
+ mov di,bx
+ retf
+
+sre_trap:
+ fault_fix_stack
+ jmp short sre_cont
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*int FAR CopyRect(pDstRect,pSrcRect)
+;*LPRECT pSrcRect; /*ptr to source rect */
+;*LPRECT pDstRect; /*Ptr to dest rect */
+;*{
+;* LCopyStruct(pSrcRect,pDstRect,sizeof(RECT));
+;* /*copy from source to dest */
+;*}
+;*
+;******************************************************************************
+
+cProcVDO CopyRect, <FAR, PUBLIC, NODATA>, <ds, si, di>
+ parmD lpDstRect ;long pointer to DstRect
+ parmD lpSrcRect ;long pointer to SrcRect
+cBegin
+beg_fault_trap cr_trap
+ lds si, lpSrcRect ;mov into ds:si a far pointer to SrcRect
+ les di, lpDstRect ;mov into es:di far pointer to DstRect
+ cld ;clear direction flag for increment stuff
+ movsw
+ movsw
+ movsw
+ movsw
+end_fault_trap
+cr_cont:
+cEnd
+
+cr_trap:
+ fault_fix_stack
+ jmp short cr_cont
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*BOOL FAR IsRectEmpty(pRect)
+;*LPRECT pRect;
+;*{
+;* return(((pRect->right-pRect->left<=0)||(pRect->bottom-pRect->top<=0)) ? TRUE : FALSE);
+;*}
+;*
+;******************************************************************************
+
+LabelVDO IsRectEmpty
+ pop ax
+ pop dx
+
+ pop bx ; get lprc
+ pop cx
+
+ push dx
+ push ax
+
+beg_fault_trap ire_trap
+ mov es,cx
+ mov ax,TRUE
+ mov cx,es:[bx].rcRight
+ cmp cx,es:[bx].rcLeft
+ jle empty0
+ mov cx,es:[bx].rcBottom
+ cmp cx,es:[bx].rcTop
+ jle empty0
+ xor ax,ax
+end_fault_trap
+empty0:
+ retf
+
+ire_trap:
+ fault_fix_stack
+ jmp short empty0
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*BOOL FAR PtInRect(lprc, pt)
+;*LPRECT lprc;
+;*POINT pt;
+;*{
+;* return(pt.x >= lprc->left && pt.x < lprc->right &&
+;* pt.y >= lprc->top && pt.y < lprc->bottom);
+;*}
+;*
+;******************************************************************************
+
+cProcVDO PtInRect,<PUBLIC,FAR,NODATA>,<DS,SI>
+; parmD lpRect
+; parmD lpPoint
+cBegin nogen
+
+ mov bx,sp
+ push ds
+ push si
+
+ mov cx,ss:[bx+4] ; cx = pt.x
+ mov dx,ss:[bx+6] ; dx = pt.y
+
+beg_fault_trap pir_trap
+ lds si,ss:[bx+8] ; lpRect
+ cld
+ xor bx,bx ; Result = FALSE
+
+ lodsw ; AX = lpRect->left
+ cmp cx,ax ; xcoord < left?
+ jl PtNotInRect ; Yes, not in rectangle
+
+ lodsw ; AX = lpRect->top
+ cmp dx,ax ; ycoord < top?
+ jl PtNotInRect ; Yes, not in rectangle
+
+ lodsw ; AX = lpRect->right
+ cmp cx,ax ; xcoord >= right?
+ jge PtNotInRect ; Yes, not in rectangle
+
+ lodsw ; AX = lpRect->bottom
+ cmp dx,ax ; ycoord >= bottom?
+ jge PtNotInRect ; Yes, not in rectangle
+
+ inc bx ; Point in rectangle, result = TRUE
+end_fault_trap
+PtNotInRect:
+ mov ax,bx
+ pop si
+ pop ds
+ retf 8
+
+cEnd nogen
+
+pir_trap:
+ fault_fix_stack
+ jmp short PtNotInRect
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*int FAR OffsetRect(pRect, x, y)
+;*LPRECT pRect;
+;*int x;
+;*int y;
+;*{
+;* pRect->left += x;
+;* pRect->right += x;
+;* pRect->top += y;
+;* pRect->bottom += y;
+;*}
+;*
+;******************************************************************************
+
+cProcVDO OffsetRect,<FAR, PUBLIC, NODATA>,<DS>
+; parmD lpRect ;far pointer to struct type rect
+; parmW xDelta ;X delta
+; parmW yDelta ;Y Delta
+cBegin nogen
+ mov bx,sp
+ push ds
+beg_fault_trap or_trap
+ mov dx,ss:[bx+6] ; dx = dx
+ mov cx,ss:[bx+4] ; CX = dy
+ lds bx,ss:[bx+8] ; ds:bx = lprc
+ add [bx].rcLeft,dx
+ add [bx].rcTop,cx
+ add [bx].rcRight,dx
+ add [bx].rcBottom,cx
+end_fault_trap
+or_cont:
+ pop ds
+ retf 8
+cEnd
+or_trap:
+ fault_fix_stack
+ jmp short or_cont
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*int FAR InflateRect(pRect, x, y)
+;*LPRECT pRect;
+;*int x;
+;*int y;
+;*{
+;* pRect->left -= x;
+;* pRect->right += x;
+;* pRect->top -= y;
+;* pRect->bottom += y;
+;*}
+;*
+;******************************************************************************
+
+cProcVDO InflateRect,<FAR, PUBLIC, NODATA>,<DS>
+; parmD lpRect ;far pointer to struct type rect
+; parmW xOffset
+; parmW yOffset
+cBegin nogen
+ mov bx,sp
+ push ds
+
+beg_fault_trap ir_trap
+ mov dx,ss:[bx+6] ; dx = dx
+ mov cx,ss:[bx+4] ; CX = dy
+ lds bx,ss:[bx+8] ; ds:bx = lprc
+ sub [bx].rcLeft,dx
+ sub [bx].rcTop,cx
+ add [bx].rcRight,dx
+ add [bx].rcBottom,cx
+
+end_fault_trap
+ir_cont:
+ pop ds
+ retf 8
+cEnd
+
+ir_trap:
+ fault_fix_stack
+ jmp short ir_cont
+
+;-----------------------------------------------------------------
+;
+; IntersectRect(lprcDst, lprcSrc1, lprcSrc2);
+;
+cProcVDO IntersectRect,<PUBLIC, FAR, NODATA>,<SI, DI, DS>
+ParmD lprcDst
+ParmD lprcSrc1
+ParmD lprcSrc2
+cBegin
+beg_fault_trap irc_trap
+ lds si,lprcSrc1 ; point at source rects
+ les di,lprcSrc2
+
+ mov ax,[si].rcLeft ; new left = cx = max(rc1.left, rc2.left)
+ mov cx,es:[di].rcLeft
+ cmp ax,cx
+ jl ir100
+ xchg ax,cx
+ir100:
+ mov ax,[si].rcRight ; new right = dx = min(rc1.right, rc2.right)
+ mov dx,es:[di].rcRight
+ cmp ax,dx
+ jg ir200
+ xchg ax,dx
+ir200:
+ cmp cx,dx ; is left >= right?
+ jge irempty ; yes - return empty rect
+
+ mov ax,[si].rcTop ; new top = cx = max(rc1.top, rc2.top)
+ mov bx,es:[di].rcTop
+ cmp ax,bx
+ jl ir300
+ xchg ax,bx
+ir300:
+ mov ax,[si].rcBottom ; new bottom = dx = min(rc1.bottom, rc2.bottom)
+ mov di,es:[di].rcBottom
+ cmp ax,di
+ jg ir400
+ xchg ax,di
+ir400:
+ cmp bx,di ; is top >= bottom?
+ jge irempty ; no: store result
+
+ lds si,lprcDst ; store away new right & left
+ mov [si].rcLeft,cx
+ mov [si].rcTop,bx
+ mov [si].rcRight,dx
+ mov [si].rcBottom,di
+
+ mov al,TRUE ; return TRUE
+end_fault_trap
+irexit:
+
+cEnd
+
+irc_trap:
+ fault_fix_stack
+irempty:
+ les di,lprcDst ; point at dst rect
+ xor ax,ax ; set to (0, 0, 0, 0)
+ cld
+ stosw
+ stosw
+ stosw
+ stosw ; return FALSE
+ jmps irexit
+
+;=============================================================================
+;
+; BOOL UnionRect(lprcDest, lprcSrc1, lprcSrc2)
+; LPRECT lprcDest;
+; LPRECT lprcSrc1;
+; LPRECT lprcSrc2;
+;
+; Calculates *lprcDest as the minimum rectangle that bounds both
+; *lprcSrc1 and *lprcSrc2. If either rectangle is empty, lprcDest
+; is set to the other rectangle. Returns TRUE if the result is a non-empty
+; rectangle, FALSE otherwise.
+;
+;
+cProcVDO UnionRect,<FAR, PUBLIC, NODATA>,<SI, DI, DS>
+ParmD lprcDest
+ParmD lprcSrc1
+ParmD lprcSrc2
+LocalW wTemp
+cBegin
+beg_fault_trap ur_trap
+ lds si,lprcSrc1
+ les di,lprcSrc2
+
+ push es
+ push di
+ wcall IIsRectEmpty
+ push ax ; save result
+
+ ; IsRectEmpty trashes es....
+ push es
+
+ push ds
+ push si
+ wcall IIsRectEmpty
+
+ pop es ; restore it
+ pop cx
+
+ ;ax = IsRectEmpty(1), cx = IsRectEmpty(2)
+
+ or ax,ax
+ jnz URrc1empty
+ mov ax,TRUE ; return true, not both empty
+ or cx,cx
+ jz URnormalcase
+ jmps URrc2empty
+
+URrc1empty:
+ lds si,lprcSrc2
+ jcxz URrc2empty ; rc2 not empty, ax has true for return
+ xor ax,ax ; return false, both empty
+
+URrc2empty:
+ les di,lprcDest
+ cld
+ movsw
+ movsw
+ movsw
+ movsw
+ jmps URexit
+
+ ; src1 and src2 not empty
+
+URnormalcase:
+ mov ax,[si].rcLeft ; bx = min(Src1.left, Src2.left)
+ mov cx,es:[di].rcLeft
+ cmp ax,cx
+ jl URleft
+ xchg ax,cx
+URleft:
+ mov bx,ax
+
+ mov ax,[si].rcTop ; dx = min(Src1.top, Src2.top)
+ mov cx,es:[di].rcTop
+ cmp ax,cx
+ jl URtop
+ xchg ax,cx
+URtop:
+ mov dx,ax
+
+ mov ax,[si].rcRight ; wTemp = max(Src1.right, Src2.right)
+ mov cx,es:[di].rcRight
+ cmp ax,cx
+ jg URright
+ xchg ax,cx
+URright:
+ mov wTemp,ax
+
+ mov ax,[si].rcBottom ; ax = max(Src1.bottom, Src2.bottom)
+ mov cx,es:[di].rcBottom
+ cmp ax,cx
+ jg URbottom
+ xchg ax,cx
+URbottom:
+
+ les di,lprcDest ; fill into lprcDest
+ mov es:[di].rcLeft,bx
+ mov es:[di].rcTop,dx
+ mov es:[di].rcBottom,ax
+ mov ax,wTemp
+ mov es:[di].rcRight,ax
+end_fault_trap
+
+ur_true:
+ mov ax,TRUE ; return true, not both empty
+URexit:
+cEnd
+
+ur_trap:
+ fault_fix_stack
+ jmp ur_true
+
+
+;******************************************************************************
+;* ORIGINAL C SOURCE
+;*
+;*BOOL FAR EqualRect(lpRect1, lpRect2)
+;*LPRECT lpRect1;
+;*LPRECT lpRect2;
+;*{
+;* return lpRect1->left == lpRect2->left && lpRect1->top == lpRect2->top
+;* && lpRect1->right == lpRect1->right && lpRect1->bottom ==
+;* lpRect2->bottom;
+;*}
+;*
+;******************************************************************************
+
+cProcVDO EqualRect, <FAR, PUBLIC, NODATA>, <SI, DI, DS>
+ parmD lpRect1
+ parmD lpRect2
+cBegin
+ xor ax,ax ; assume FALSE
+beg_fault_trap er_trap
+ lds si,lpRect1
+ les di,lpRect2
+ mov cx,4
+ cld
+ repz cmpsw
+ jnz er10
+ inc al
+end_fault_trap
+er10:
+cEnd
+
+er_trap:
+ fault_fix_stack
+ jmp er10
+
+;****************************************************************************
+; The following Routine to subtract one rectangle from another is lifted
+; from PM and Modified by Sankar.
+;
+;****************************************************************************
+
+;** Public Routine ****************************************************-;
+; BOOL far SubtractRect(lprcDest, lprc1, lprc2)
+; LPRECT lprcDest;
+; LPRECT lprcSrc1;
+; LPRECT lprcSrc2;
+;
+; This function subtracts *lprc2 from *lprc1, returning the result
+; in *lprcDest. Returns TRUE if *lprcDest is non-empty, FALSE otherwise.
+;
+; Warning: Subtracting one rectangle from another may not
+; always result in a rectangular area; in this case
+; WinSubtractRect will return *lprc1 in *lprcDest.
+; For this reason, WinSubtractRect provides only an
+; approximation of subtraction. However, the area
+; described by *lprcDest will always be greater
+; than or equal to the "true" result of the
+; subtraction.
+;
+; History :
+; Added by Sankar on July 27, 1988
+;**********************************************************************-;
+
+cProcVDO SubtractRect, <PUBLIC, FAR, NODATA>, <SI, DI, DS>
+ ParmD lprcDest
+ ParmD lprc1
+ ParmD lprc2
+ LocalV rc,%size RECT
+cBegin
+;
+; First copy lprc1 into lprcDest.
+;
+beg_fault_trap sbr_trap
+ lds si,lprc1
+ les di,lprcDest
+ cld
+ movsw
+ movsw
+ movsw
+ movsw
+
+ lds si,lprcDest ; ds:[si] = lprcDest.
+ lea di,rc ; ss:[di] = &rc
+;
+; We're subtracting lprc2 from lprc1. Make sure they at least
+; intersect each other. If not, return TRUE.
+;
+ push ss ; pushd &rc
+ push di
+ push ds ; pushd lprcDest
+ push si
+ push seg_lprc2 ; pushd lprc2
+ push off_lprc2
+ wcall IIntersectRect
+
+ or ax,ax ; Did we intersect?
+ jz sr700 ; If no, skip to check empty rect
+;
+; Now make sure that we can subtract lprc2 from lprc1 and get a rect.
+;
+ errnz <rcLeft - 0>
+ errnz <rcTop - 2>
+ errnz <rcRight - 4>
+ errnz <rcBottom - 6>
+;
+; We make a loop that iterates twice - once for the x's and once for the
+; y's. We want at least 3 sides of lprc2 to be outside of 3 sides of lprc1.
+;
+ xor cx,cx
+ xor dx,dx
+ dec cx
+;
+; ds:si points to lprc1 (actually lprcDest)
+; ss:di points to rc on stack
+;
+sr100:
+ inc cx
+
+ mov bx,cx
+ shl bx,1 ; bx is a Word pointer
+
+ mov ax,ss:[di+bx].rcLeft ; if lprc2 left/top is > lprc1 l/t,
+ cmp ax,ds:[si+bx].rcLeft
+ jg sr200 ; then inside the rect.
+ inc dx
+sr200:
+ mov ax,ss:[di+bx].rcRight ; if lprc2 right/bottom is > lprc1 r/b,
+ cmp ax,ds:[si+bx].rcRight
+ jl sr300 ; then inside the rect.
+ inc dx
+sr300:
+ jcxz sr100 ; loop one more time...
+
+ cmp dx,3 ; Are 3 sides outside? If not,
+ jb sr700 ; skip to check empty rect code
+
+ cmp dx,4 ; Is rc1 completely inside rc2? If so,
+ jne sr350 ; empty lprcDest and return TRUE
+
+ pushd lprcDest ; empty that puppy
+ wcall ISetRectEmpty
+
+ xor ax,ax ; Go return FALSE.
+ jmps srExit
+
+sr350:
+;
+; Now we know that we can take lprc2 from lprc1 and leave a rect, so
+; now we perform the 'subtract rect'. Interate twice, again once for the
+; x's and once for the y's.
+;
+ xor cx,cx
+ dec cx
+
+sr400:
+ inc cx
+ mov bx,cx
+ shl bx,1 ; Make bx a Word pointer
+
+ mov dx,ss:[di+bx].rcLeft ; New right/Bottom border?
+ cmp dx,ds:[si+bx].rcLeft
+ jle sr500
+
+ mov ds:[si+bx].rcRight,dx
+ jmps sr600
+
+sr500:
+ mov dx,ss:[di+bx].rcRight ; New left/top border?
+ cmp dx,ds:[si+bx].rcRight
+ jge sr600
+
+ mov ds:[si+bx].rcLeft,dx
+
+sr600:
+ jcxz sr400
+
+sr700:
+ xor ax,ax ; Assume it is empty: FALSE
+
+ mov cx,ds:[si].rcRight
+ cmp cx,ds:[si].rcLeft
+ jle SrExit
+
+ mov cx,ds:[si].rcBottom
+ cmp cx,ds:[si].rcTop
+ jle SrExit
+
+ inc al ; Non-empty: return TRUE.
+end_fault_trap
+srExit:
+cEnd
+
+sbr_trap:
+ fault_fix_stack
+ xor ax,ax ; return FALSE
+ jmp srExit
+
+;****************************************************************************
+;
+; void FAR SplitRectangle(lprcRect, lprcRectArray, wcx, wcy)
+; LPRECT lprcRect
+; RECT lprcRectArray[4]
+;
+; This splits the given rectangular frame into four segments and stores
+; them in the given array
+;
+; Pseudo code:
+; -----------
+;
+; cxWidth = lprcRect -> rcRight - lprcRect -> rcLeft - wcx;
+; cyWidth = lprcRect -> rcBottom - lprcRect -> rcTop - wcy;
+;
+; A = -cyWidth;
+; B = -cxWidth;
+;
+; for (i = 0; i < 4; i++)
+; {
+; lprcRectArray[i][i] = lprcRect[i];
+; lprcRectArray[i][(i+1)&3] = lprcRect[(i+3)&3] + A;
+; lprcRectArray[i][(i+2)&3] = lprcRect[(i+2)&3] + B;
+; lprcRectArray[i][(i+3)&3] = lprcRect[(i+3)];
+;
+; TMP = A;
+; A = -B;
+; B = TMP;
+; }
+;
+; Note:
+; Value of i Value of A Value of B
+; ---------- ---------- ----------
+; 0 -cyWidth -cxWidth
+; 1 +cxWidth -cyWidth
+; 2 +cyWidth +cxWidth
+; 3 -cxWidth +cyWidth
+;
+;
+;***************************************************************************
+
+
+
+cProc SplitRectangle, <FAR, PUBLIC, NODATA>, <SI, DI, DS>
+
+ ParmD <lprcRect, lprcRectArray> ; Rect and Array
+ Parmw <wcx, wcy> ; Border widths
+
+cBegin
+
+ les di, lprcRectArray ; es:di => lprcRectArray
+ lds si, lprcRect ; ds:si => given rectangle
+
+; Calculate the value of -cxWidth
+
+ mov ax, [si].rcLeft
+ sub ax, [si].rcRight
+ add ax, wcx
+
+ push ax ; Save B on stack.
+
+; Calculate the value of -cyWidth
+
+ mov ax, [si].rcTop
+ sub ax, [si].rcBottom
+ add ax, wcy
+
+ push ax ; Save A on stack
+
+; Initialise the loop related variables
+
+ xor cx, cx ; Loop count
+ xor bx, bx ; Index into Rect Structure.
+
+LoopSt:
+; lprcRectArray[i][i] = lprcRect[i];
+
+ mov ax, [si+bx]
+ mov es:[di+bx], ax
+
+; lprcRectArray[i][(i+1)&3] = lprcRect[(i+3)&3] + A;
+
+ inc bx
+ inc bx ; Make it a word pointer
+ and bx, 6
+ push bx ; Save (i+1) tempoarily
+ add bx, 4 ; Calculate (i+3)
+ and bx, 6
+
+ mov ax, [si+bx] ; lprcRect[(i+3)] is taken
+ pop bx ; (i+1) is returned to bx
+
+ pop dx ; Value "A" is taken from stack
+ add ax, dx
+ mov es:[di+bx], ax
+
+ ; Swap A and B on stack. A is in DX
+
+ pop ax ; Value B from Stack.
+ push dx ; B = A;
+ Push ax ; A = B;
+
+ ; Now B is on top of stack and A is below it.
+
+
+ ; lprcRectArray[i][(i+2)&3] = lprcRect[(i+2)&3] + B;
+
+ inc bx
+ inc bx ; (i+2) is calculated
+ and bx, 6
+
+ mov ax, [si+bx]
+ pop dx ; pop B
+ add ax, dx
+
+ mov es:[di+bx], ax
+ neg dx ; make -B
+ push dx
+
+ ; lprcRectArray[i][(i+3)&3] = lprcRect[(i+3)];
+
+ inc bx
+ inc bx
+ and bx, 6 ; make [(i+3)&3]
+
+ mov ax, [si+bx]
+ mov es:[di+bx], ax
+
+ inc cx
+ cmp cx, 4
+ jge exit
+
+ mov bx, cx
+ shl bx, 1 ; Make it a word pointer
+ add di, size RECT ; Make it point to next rect in the array
+ jmp LoopSt
+exit:
+ ; A and B exist on stack. So,Pop them
+ add sp, 4
+
+cEnd
+
+
+sEnd TEXT
+end
diff --git a/private/mvdm/wow16/user/winstack.asm b/private/mvdm/wow16/user/winstack.asm
new file mode 100644
index 000000000..6a77e9a1d
--- /dev/null
+++ b/private/mvdm/wow16/user/winstack.asm
@@ -0,0 +1,634 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINSTACK.ASM
+; Win16 stack munging routines
+;
+; History:
+;
+; Created 18-Jun-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16
+;--
+
+;****************************************************************************
+;* *
+;* WINSTACK.ASM - *
+;* *
+;* Stack Frame setup routines *
+;* *
+;****************************************************************************
+
+ifdef WOW
+NOEXTERNS equ 1
+endif
+.xlist
+include user.inc
+.list
+
+;
+; Short jump macro
+;
+jmps macro adr
+ jmp short (adr)
+ endm
+
+;
+; XMOV macro
+;
+; Use instead of MOV ax,reg. Saves a byte.
+;
+xmov macro a,b
+ xchg a,b
+ endm
+
+ifdef WOWDEBUG
+sBegin DATA
+
+externW <pStackTop>
+externW <pStackMin>
+externW <pStackBot>
+
+sEnd
+
+ifdef DEBUG
+
+sBegin TEXT
+ExternFP <DivideByZero>
+sEnd
+
+endif
+endif ;WOWDEBUG
+
+createSeg _TEXT, TEXT, WORD, PUBLIC, CODE
+
+assumes CS,TEXT
+assumes SS,DATA
+
+sBegin TEXT
+
+ org 0 ; MUST be at the start of each segment
+ ; so that WinFarFrame can jump back
+ ; to the proper location.
+
+;*--------------------------------------------------------------------------*
+;* *
+;* _TEXT_NEARFRAME() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Call to _segname_NEARFRAME should be in following format:
+;
+; call _segname_NEARFRAME
+; db cbLocals (count of local words to be allocated)
+; db cbParams (count of argument words)
+
+LabelNP <PUBLIC, _TEXT_NEARFRAME>
+ push cs ; Save the current segment
+ jmps WinNearFrame ; Jump to the (only) NEARFRAME routine
+ nop
+ nop
+ nop
+
+nf2: push cs ; Save the CS (it may have changed!)
+ jmps WinNearFrame2 ; Jump to the second half of NEARFRAME
+ nop
+ nop
+ nop
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* _TEXT_FARFRAME() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Call to _segname_FARFRAME should be in following format:
+;
+; call _segname_FARFRAME
+; db cbLocals (count of local words to be allocated)
+; db cbParams (count of argument words)
+
+LabelNP <PUBLIC, _TEXT_FARFRAME>
+ push cs ; Save the current segment
+ jmps WinFarFrame ; Jump to the (only) FARFRAME routine
+ nop
+ nop
+ nop
+
+ifdef WOWDEBUG
+ff2: jmp near ptr WinFarFrame2 ; Jump to the second half of FARFRAME
+else
+ff2: jmp short near ptr WinFarFrame2
+endif
+
+
+ifdef WOWDEBUG
+;*--------------------------------------------------------------------------*
+;* *
+;* __astkovr1() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Stack Overflow checking routine
+
+;externFP <__astkovr>
+
+;__astkovr1: jmp __astkovr
+
+endif
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* WinNearFrame() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Sets up and dismantles the frame for a NEAR routine. This routine
+; is FAR JMPed to by _segname_NEARFRAME. It munges the stack so that a
+; NEAR RET returns to a JMP to WinNearFrame2 which dismantles the frame.
+;
+; CX must be is preserved in the first portion.
+
+LabelFP <PUBLIC, WinNearFrame>
+ pop es ; Get the caller's Code Segment
+ pop bx ; Get pointer to sizes of args and locals
+
+ push bp ; Update the BP chain
+ mov bp,sp
+
+ mov dx,word ptr es:[bx] ; Move the 2 parms in DX
+
+ xor ax,ax
+ mov al,dl ; Move the # of local words into AL
+ shl ax,1 ; Convert # of words into # of bytes
+
+ifdef WOWDEBUG
+ sub ax,sp
+; jae __astkovr1 ; Check for stack overflow in
+ neg ax ; debugging versions
+ cmp ss:[pStackTop],ax
+; ja __astkovr1
+ cmp ss:[pStackMin],ax
+ jbe nf100
+ mov ss:[pStackMin],ax
+nf100: xmov sp,ax
+
+else
+ sub sp,ax ; Reserve room for locals on stack
+endif
+
+ push si ; Save SI and DI
+ push di
+
+ xor ax,ax
+ mov al,dh ; Move the # of func args into AL
+ shl ax,1 ; Convert words to bytes
+ push ax ; Save on the stack
+
+ mov ax,offset nf2 ; Push the offset of the JMP to
+ push ax ; WinNearFrame2 for function's RET
+
+ inc bx ; Move pointer past the parms to the
+ inc bx ; actual function code
+
+ push es ; Jump back to the function via RETF
+ push bx
+
+ xor bx,bx ; insure ES is 0
+ mov es,bx
+
+ retf
+
+LabelFP <PUBLIC,WinNearFrame2>
+ ; NOTE: AX and DX must be preserved now since they contain the C
+ ; return value.
+ pop es ; Get the caller's CS
+ pop cx ; Get # of func args in CX
+
+ pop di ; Restore SI and DI
+ pop si
+
+ mov sp,bp ; Free the local variables
+ pop bp ; Restore BP
+
+ pop bx ; Get the caller's return address
+
+ add sp,cx ; Remove paramters from stack
+
+ push es ; Return to caller via RETF
+ push bx
+
+ xor bx,bx ; insure ES is 0
+ mov es,bx
+
+ retf
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* WinFarFrame() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Sets up and dismantles the frame for a FAR routine. This routine
+; is FAR JMPed to by _segname_NEARFRAME. It munges the stack so that a
+; NEAR RET returns to a JMP to WinFarFrame2 which dismantles the frame.
+;
+; CX must be is preserved in the first portion.
+
+LabelFP <PUBLIC, WinFarFrame>
+ mov ax,ds ; This is patched by the loader to become
+ nop ; mov ax,DSVAL
+
+ pop es ; Get the caller's CS
+
+ pop bx ; Get pointer to sizes of args and locals
+
+ inc bp ; Make BP odd to mark far frame
+ push bp ; Update the BP chain
+ mov bp,sp
+
+ push ds ; Save DS
+ mov dx,word ptr es:[bx] ; Move the 2 parms into DX
+
+ mov ds,ax ; Get the new DS from the loader patch
+
+ xor ax,ax
+ mov al,dl ; Move the # of local words into AL
+ shl ax,1 ; Convert # of words into # of bytes
+
+ifdef WOWDEBUG
+ sub ax,sp
+; jae __astkovr1 ; Check for stack overflow in
+ neg ax ; debugging versions
+ cmp ss:[pStackTop],ax
+; ja __astkovr1
+ cmp ss:[pStackMin],ax
+ jbe ff100
+ mov ss:[pStackMin],ax
+ff100: xmov sp,ax
+
+else
+ sub sp,ax ; Reserve room for locals on stack
+endif
+
+ push si ; Save SI and DI
+ push di
+
+ xor ax,ax
+ mov al,dh ; Move the # of func args into AL
+ shl ax,1 ; Convert words to bytes
+ push ax ; Save on the stack
+
+ mov ax,offset ff2 ; Push the offset of the JMP to
+ push ax ; WinFarFrame2 for function's RET
+
+ inc bx ; Move pointer past the parms to the
+ inc bx ; actual function code
+
+ push es ; Jump back to the function via RETF
+ push bx
+
+ xor bx,bx ; Ensure es is 0
+ mov es,bx
+ retf
+
+LabelFP <PUBLIC,WinFarFrame2>
+ ; NOTE: AX and DX must be preserved now since they contain the C
+ ; return value.
+ pop cx ; Get # of func args in CX
+
+ pop di ; Restore SI and DI
+ pop si
+
+if 0
+ sub bp,2 ; Point BP at the DS value
+ mov sp,bp ; Free the local variables
+ pop ds ; Restore DS
+ pop bp ; Restore BP
+ dec bp ; Make BP even again
+
+ pop bx ; Get the caller's return address
+ pop es
+
+ add sp,cx ; Remove paramters from stack
+
+ push es ; Return to caller via RETF
+ push bx
+
+ xor bx,bx ; Ensure es is 0
+ mov es,bx
+endif
+
+ mov ds,[bp-2] ; Restore DS
+ lea bx,[bp+2] ; get caller's return address
+ add bx,cx ; Where we want to put the old CS:IP
+ mov cx,[bp+4] ; get old CS
+ mov ss:[bx+2],cx ; move it up
+ mov cx,[bp+2] ; Get old IP
+ mov ss:[bx],cx ; move it up
+ mov bp,[bp] ; restore the old BP
+ dec bp ; make it even again
+ mov sp,bx ; point to the moved CS:IP
+ retf ; later dude
+
+ifdef WOWDEBUG
+
+ ORG 0cch
+ jmp far ptr DivideByZero
+endif
+
+sEnd TEXT
+
+ifndef WOW
+;==============================================================================
+; FFFE SEGMENT
+;==============================================================================
+
+createSeg _FFFE, FFFE, BYTE, PUBLIC, CODE
+
+assumes CS,_FFFE
+assumes SS,DATA
+
+sBegin FFFE
+
+ ORG 0 ; This segment must have a magic header
+ ; so that we know to move it up into
+ ; segment FFFE:0000 if possible
+; db 16 DUP ("AC")
+; db 16 DUP (0) ; Tony's sleazy zeros
+
+
+ifdef WOWDEBUG
+;*--------------------------------------------------------------------------*
+;* *
+;* __ffastkovr1() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Stack Overflow checking routine
+
+;__ffastkovr1: jmp __astkovr
+
+endif
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* _FFFE_NEARFRAME() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+LabelNP <PUBLIC, _FFFE_NEARFRAME>
+ pop bx ; Get pointer to sizes of args and locals
+
+ push bp ; Update the BP chain
+ mov bp,sp
+
+ mov dx,word ptr cs:[bx] ; Move the 2 parms in DX
+
+ xor ax,ax
+ mov al,dl ; Move the # of local words into AL
+ shl ax,1 ; Convert # of words into # of bytes
+
+ifdef WOWDEBUG
+ sub ax,sp
+; jae __ffastkovr1 ; Check for stack overflow in
+ neg ax ; debugging versions
+ cmp ss:[pStackTop],ax
+; ja __ffastkovr1
+ cmp ss:[pStackMin],ax
+ jbe ffnf100
+ mov ss:[pStackMin],ax
+ffnf100: xmov sp,ax
+
+else
+ sub sp,ax ; Reserve room for locals on stack
+endif
+
+ push si ; Save SI and DI
+ push di
+
+ xor ax,ax
+ mov al,dh ; Move the # of func args into AL
+ shl ax,1 ; Convert words to bytes
+ push ax ; Save on the stack
+
+ifndef userhimem
+ mov ax,offset FFFE_nf2 ; Munge the stack so the function
+else
+ push ds
+ mov ax, _INTDS
+ mov ds,ax
+assumes ds,INTDS
+ mov ax,fffedelta
+ pop ds
+assumes ds,DATA
+ add ax, OFFSET FFFE_nf2
+endif
+ push ax ; "returns" to FFFE_nf2
+
+ inc bx ; Move pointer past the parms to the
+ inc bx ; actual function code
+
+ push bx ; Jump back to the function
+ ret
+
+LabelFP <PUBLIC,FFFE_nf2>
+ ; NOTE: AX and DX must be preserved now since they contain the C
+ ; return value
+ pop cx ; Get # of func args in CX
+
+ pop di ; Restore SI and DI
+ pop si
+
+ mov sp,bp ; Free the local variables
+ pop bp ; Restore BP
+
+ pop bx ; Get the caller's return address
+
+ add sp,cx ; Remove paramters from stack
+
+ push bx ; Return to caller
+ ret
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* _FFFE_FARFRAME() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+LabelNP <PUBLIC, _FFFE_FARFRAME>
+ mov ax,ds ; This is patched by the loader to become
+ nop ; mov ax,DSVAL
+
+ pop bx ; Get pointer to sizes of args and locals
+
+ inc bp ; Make BP odd to mark far frame
+ push bp ; Update the BP chain
+ mov bp,sp
+
+ push ds ; Save DS
+ mov ds,ax ; Get the new DS from the loader patch
+
+ mov dx,word ptr cs:[bx] ; Move the 2 parms into DX
+
+ xor ax,ax
+ mov al,dl ; Move the # of local words into AL
+ shl ax,1 ; Convert # of words into # of bytes
+
+ifdef WOWDEBUG
+ sub ax,sp
+; jae __ffastkovr1 ; Check for stack overflow in
+ neg ax ; debugging versions
+ cmp ss:[pStackTop],ax
+; ja __ffastkovr1
+ cmp ss:[pStackMin],ax
+ jbe ffff100
+ mov ss:[pStackMin],ax
+ffff100: xmov sp,ax
+
+else
+ sub sp,ax ; Reserve room for locals on stack
+endif
+
+ push si ; Save SI and DI
+ push di
+
+ xor ax,ax
+ mov al,dh ; Move the # of func args into AL
+ shl ax,1 ; Convert words to bytes
+ push ax ; Save on the stack
+
+ifndef userhimem
+ mov ax,offset FFFE_ff2 ; Munge the stack so the function
+else
+ push ds
+ mov ax, _INTDS
+ mov ds,ax
+assumes ds,INTDS
+ mov ax,fffedelta
+ pop ds
+assumes ds,DATA
+ add ax,offset FFFE_ff2 ; Munge the stack so the function
+endif
+ push ax ; "returns" to FFFE_nf2
+
+ inc bx ; Move pointer past the parms to the
+ inc bx ; actual function code
+
+ push bx ; Jump back to the function
+ ret
+
+ ; NOTE: AX and DX must be preserved now since they contain the C
+ ; return value
+
+LabelFP <PUBLIC,FFFE_ff2>
+ pop cx ; Get # of func args in CX
+
+ pop di ; Restore SI and DI
+ pop si
+
+ sub bp,2 ; Point BP at the DS value
+ mov sp,bp ; Free the local variables
+ pop ds ; Restore DS
+ pop bp ; Restore BP
+ dec bp ; Make BP even again
+
+ pop bx ; Get the caller's return address
+ pop es
+
+ add sp,cx ; Remove paramters from stack
+
+ push es ; Return to caller via RETF
+ push bx
+
+ xor bx,bx ; Ensure es is 0
+ mov es,bx
+ retf
+
+sEnd FFFE
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* CreateFrame Macro - *
+;* *
+;*--------------------------------------------------------------------------*
+
+CreateFrame macro SegName
+
+createSeg _&SegName, SegName, BYTE, PUBLIC, CODE
+
+assumes CS,_&SegName
+assumes SS,DATA
+
+sBegin SegName
+
+ org 0 ; MUST be at the start of each segment
+ ; so that WinFarFrame can jump back
+ ; to the proper location.
+
+LabelNP <PUBLIC, _&SegName&_NEARFRAME>
+ push cs ; Save the current segment
+ jmp WinNearFrame ; Jump to the (only) NEARFRAME routine
+ push cs ; Save the CS (it may have changed!)
+ jmp WinNearFrame2 ; Jump to the second half of NEARFRAME
+
+LabelNP <PUBLIC, _&SegName&_FARFRAME>
+ push cs ; Save the current segment
+ jmp WinFarFrame ; Jump to the (only) FARFRAME routine
+ jmp WinFarFrame2 ; Jump to the second half of FARFRAME
+
+sEnd SegName
+
+ endm
+
+
+;==============================================================================
+; SEGMENT FRAMES
+;==============================================================================
+
+;CreateFrame INIT
+;CreateFrame MDKEY
+;CreateFrame MENUCORE
+;CreateFrame MENUAPI
+;CreateFrame MENUSTART
+;CreateFrame RUNAPP
+;CreateFrame DLGBEGIN
+;CreateFrame DLGCORE
+;CreateFrame SCRLBAR
+CreateFrame WMGR
+CreateFrame WMGR2
+;CreateFrame RARE
+;CreateFrame LBOX
+;CreateFrame LBOXAPI
+;CreateFrame LBOXDIR
+;CreateFrame LBOXMULTI
+;CreateFrame LBOXRARE
+;CreateFrame CLPBRD
+;CreateFrame COMDEV
+;CreateFrame ICON
+;CreateFrame SWITCH
+;CreateFrame MSGBOX
+;CreateFrame MDIWIN
+;CreateFrame MDIMENU
+;CreateFrame EDECRARE
+;CreateFrame EDSLRARE
+;CreateFrame EDMLONCE
+;CreateFrame EDMLRARE
+;CreateFrame WINCRTDST
+;CreateFrame WINUTIL
+;CreateFrame RESOURCE
+;CreateFrame WALLPAPER
+;CreateFrame WINSWP
+CreateFrame LANG
+
+endif ;WOW
+
+end
diff --git a/private/mvdm/wow16/user/winstr.asm b/private/mvdm/wow16/user/winstr.asm
new file mode 100644
index 000000000..12de6d83b
--- /dev/null
+++ b/private/mvdm/wow16/user/winstr.asm
@@ -0,0 +1,349 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINSTR.ASM
+; Win16 string services
+;
+; History:
+;
+; Created 18-Jun-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16
+;--
+
+
+;****************************************************************************
+;* *
+;* WinStr.ASM - *
+;* *
+;* String related API calls to support different lanuages *
+;* *
+;****************************************************************************
+
+ TITLE WinStr.ASM
+
+ifdef WOW
+NOEXTERNS equ 1
+endif
+NOTEXT = 1
+.xlist
+include user.inc
+.list
+
+sBegin DATA
+sEnd
+
+createSeg _TEXT, CODE, WORD, PUBLIC, CODE
+
+sBegin CODE
+
+assumes CS,CODE
+assumes DS,DATA
+
+ExternNP Loc_IsConvertibleToUpperCase
+ExternNP Loc_Upper
+ExternFP IAnsiUpper
+ExternFP IAnsiLower
+ExternFP Ilstrcmpi
+ifdef DBCS
+ExternFP IsDBCSLeadByte
+endif
+
+; Function codes for all the string functions in USER
+;
+ANSINEXT_ID equ 1
+ANSIPREV_ID equ 2
+ANSIUPPER_ID equ 3
+ANSILOWER_ID equ 4
+
+;--------------------------------------------------------------------------
+; The order of entries in the following table can not be changed
+; unless the *_ID codes are also changed in KERNEL also.
+; ((FunctionCode - 1) << 1) is used as the index into this table
+;
+; Function Codes:
+;
+; NOTE: If you change the entries in this table, kindly update the
+; *_ID statements above and also lString.asm of KERNEL.
+;
+;--------------------------------------------------------------------------
+LabelW StringFuncTable
+ dw codeOFFSET IAnsiNext
+ dw codeOFFSET IAnsiPrev
+ dw codeOFFSET IAnsiUpper
+ dw codeOFFSET IAnsiLower
+
+;*----------------------------------------------------------------------*
+;* StringFunc() *
+;* The string manipulation functions in kernel have been moved *
+;* into USER. *
+;* This is the common entry point in USER for all the string *
+;* manipulation functions Kernel wants to call. Kernel jumps to *
+;* this function with the function code in CX *
+;* *
+;* Input Parameters: *
+;* [CX] contains the Function code. *
+;* [sp] contains the FAR return address of the original caller of *
+;* the string manipulation functions in Kernel *
+;*----------------------------------------------------------------------*
+
+cProc StringFunc, <FAR, PUBLIC>
+cBegin nogen
+ xchg bx,cx ; move function code to BX
+ dec bx
+ shl bx, 1
+ jmp StringFuncTable[bx]
+ ; Control does not comeback here. It returns directly
+ ; to the caller
+cEnd nogen
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiPrev() *
+;* *
+;*----------------------------------------------------------------------*
+
+ifdef DBCS
+
+cProc IAnsiPrev,<PUBLIC,FAR>
+; parmD pFirst ; [bx+10] es:di
+; parmD pStr ; [bx+6] ds:si
+
+cBegin nogen
+ push bp
+ mov bp,sp
+
+ push ds
+ push si
+ push di
+
+ lds si,[bp+6]
+ les di,[bp+10]
+ regptr dssi,ds,si
+ regptr esdi,es,di
+ cld
+
+ cmp si,di ; pointer to first char?
+ jz ap5 ; yes, just quit
+
+ dec si ; backup once
+ cmp si,di ; pointer to first char?
+ jz ap5 ; yse, just quit
+
+ap1:
+ dec si ; backup once
+ mov al, [si] ; fetch a character
+ cCall IsDBCSLeadByte,<ax> ; DBCS lead byte candidate?
+ test ax,ax ;
+ jz ap2 ; jump if not.
+ cmp si,di ; backword exhausted?
+ jz ap3 ; jump if so
+ jmp ap1 ; repeat if not
+ap2:
+ inc si ; adjust pointer correctly
+ap3:
+ mov bx, [bp+6] ;
+ mov di, bx ; result in DI
+ dec di ;
+ sub bx, si ; how many characters backworded
+ test bx, 1 ; see even or odd...
+ jnz ap4 ; odd - previous char is SBCS
+ dec di ; make DI for DBCS
+ap4:
+ mov si, di ; final result in SI
+ap5:
+ mov ax,si
+ mov dx,ds
+
+ pop di
+ pop si
+ pop ds
+
+ pop bp
+ ret 8
+cEnd nogen
+
+else
+
+cProc IAnsiPrev,<PUBLIC,FAR>
+; parmD pFirst ; [bx+8] es:di
+; parmD pStr ; [bx+4] ds:si
+
+cBegin nogen
+ mov bx,sp
+
+ push ds
+ push si
+ push di
+
+ lds si,ss:[bx+4]
+ les di,ss:[bx+8]
+ regptr dssi,ds,si
+ regptr esdi,es,di
+ cld
+
+ cmp si,di ; pointer to first char?
+ jz ap3 ; yes, just quit
+;;ifdef DBCS
+;; xchg si,di
+;;ap1: mov dx,si
+;; lodsb ; get a char
+;; cCall IsDBCSLeadByte,<ax> ; is it kanji?
+;; cmp al,0
+;; je ap2 ; no, get next char
+;; inc si ; yes, inc past second part
+;;ap2: cmp si,di ; have we at or past end?
+;; jb ap1 ; no, keep going
+;; mov si,dx ; return previous pointer
+;;else
+ dec si ; assume easy case...
+;;endif ; DBCS
+ap3: mov ax,si
+ mov dx,ds
+
+ pop di
+ pop si
+ pop ds
+ ret 8
+cEnd nogen
+
+endif
+
+;*----------------------------------------------------------------------*
+;* *
+;* AnsiNext() *
+;* *
+;*----------------------------------------------------------------------*
+
+cProc IAnsiNext,<PUBLIC,FAR>
+; parmD pStr
+cBegin nogen
+ mov bx,sp
+ push di
+ les di,ss:[bx+4]
+ mov al,es:[di]
+ or al,al
+ jz an1
+ inc di
+ifdef DBCS
+ cCall IsDBCSLeadByte,<ax>
+ cmp al,0
+ je an1
+ inc di
+endif ; DBCS
+an1: mov ax,di
+ mov dx,es
+ pop di
+ ret 4
+cEnd nogen
+
+;-----------------------------------------------------------------------
+; MyAnsiUpper()
+; convert string at es:di to upper case
+;-----------------------------------------------------------------------
+ public MyAnsiUpper
+MyAnsiUpper:
+ cld
+ mov si,di
+mau1: lods byte ptr es:[si]
+
+ifdef DBCS
+ push ax
+ cCall IsDBCSLeadByte,<ax>
+ cmp ax,0
+ pop ax
+ je mau2
+ inc si
+ inc di
+ inc di
+ jmp short mau1
+endif
+
+mau2: call MyUpper
+ stosb
+ or al,al
+ jnz mau1
+ ret
+
+;-----------------------------------------------------------------------
+; MyAnsiLower()
+; convert string at es:di to lower case
+;-----------------------------------------------------------------------
+ public MyAnsiLower
+MyAnsiLower:
+ cld
+ mov si,di
+mal1: lods byte ptr es:[si]
+
+ifdef DBCS
+ push ax
+ cCall IsDBCSLeadByte,<ax> ; first byte of double byte?
+ cmp ax,0
+ pop ax
+ je mal2 ; no just do normal stuff
+ inc si ; skip the two bytes
+ inc di
+ inc di
+ jmp short mal1
+endif
+
+mal2: call MyLower
+ stosb
+ or al,al
+ jnz mal1
+ ret
+
+;-------------------------------------------------------------------------
+; MyUpper()
+; convert lower case to upper, must preserve es,di,cx
+;-------------------------------------------------------------------------
+ public MyUpper
+MyUpper:
+ call Loc_IsConvertibleToUpperCase ; Check if it is a lower case char
+ ; that has an uppercase equivalent
+ jnc myu1 ;
+ sub al,'a'-'A'
+myu1: ret
+
+ifdef KANJI
+#################### KANJI ###############################################
+ ; convert upper case to lower, must preserve es,di,cx
+ public MyLower
+MyLower:
+ cmp al,'A'
+ jb myl2
+ cmp al,'Z'
+ jbe myl1
+
+ push ds
+ SetKernelDS
+ cmp [fFarEast],1 ; this is a far east kbd 1/12/87 linsh
+ pop ds
+ UnSetKernelDS
+ jge myl2 ; yes do nothing to the 0C0H - 0DEH range
+
+ cmp al,0C0H ; this is lower case a with a back slash
+ jb myl2
+ cmp al,0DEH
+ ja myl2
+myl1: add al,'a'-'A'
+myl2: ret
+#################### KANJI ###############################################
+endif
+
+;--------------------------------------------------------------------------
+; MyLower()
+; convert upper case to lower, must preserve es,di,cx
+;--------------------------------------------------------------------------
+ public MyLower
+MyLower:
+ call Loc_Upper
+ jnc myl1
+ add al, 'a'-'A'
+myl1:
+ ret
+
+sEnd CODE
+end
diff --git a/private/mvdm/wow16/user/winutil.asm b/private/mvdm/wow16/user/winutil.asm
new file mode 100644
index 000000000..06fdadeb4
--- /dev/null
+++ b/private/mvdm/wow16/user/winutil.asm
@@ -0,0 +1,618 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINUTIL.ASM
+; Win16 general utility routines
+;
+; History:
+;
+; Created 28-May-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16.
+; At this time, all we want is MultDiv() and LCopyStruct(), which the
+; edit controls use.
+;--
+
+;****************************************************************************
+;* *
+;* WINUTIL.ASM - *
+;* *
+;* General Utility Routines *
+;* *
+;****************************************************************************
+
+ title WINUTIL.ASM - General Utility routines
+
+ifdef WOW
+NOEXTERNS equ 1
+SEGNAME equ <TEXT>
+endif
+.xlist
+include user.inc
+.list
+
+
+;*==========================================================================*
+;* *
+;* FFFE Segment Definition - *
+;* *
+;*==========================================================================*
+
+createSeg _%SEGNAME, %SEGNAME, WORD, PUBLIC, CODE
+
+assumes cs,%SEGNAME
+assumes ds,DATA
+
+ExternFP <GetStockObject>
+ExternFP <GetTextExtent>
+ExternFP <TextOut>
+
+ExternA <__WinFlags>
+
+ifdef DBCS ; **** April,26,1990 by KenjiK ****
+ExternFP IsDBCSLeadByte
+endif
+
+sBegin DATA
+sEnd DATA
+
+sBegin %SEGNAME
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* MultDiv() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Calc a * b / c, with 32-bit intermediate result
+
+cProc MultDiv, <PUBLIC, FAR>
+
+;ParmW a
+;ParmW b
+;ParmW c
+
+cBegin nogen
+ mov bx,sp
+ ; calc (a * b + c/2) / c
+ mov ax,ss:[bx+8] ; ax = a
+ mov cx,ss:[bx+4] ; cx = c
+ or cx,cx
+ jz mdexit ; just return A if we'll get divide by 0
+ mov dx,ss:[bx+6] ; dx=b
+ imul dx
+
+ mov bx,cx ; save a copy of c in bx for later
+ shr cx,1 ; add in cx/2 for rounding
+ add ax,cx
+ adc dx,0 ; add in carry if needed
+ ; get c from bx register since idev mem
+ idiv bx ; doesn't work on tandy 2000's
+mdexit:
+ retf 6
+cEnd nogen
+
+
+ifdef DISABLE
+
+;*--------------------------------------------------------------------------*
+;* *
+;* min() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc min, <FAR, PUBLIC>
+
+;ParmW a
+;ParmW b
+
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+6] ;ax = a
+ mov cx,ss:[bx+4] ;cx = b
+ cmp ax,cx
+ jl min10
+ mov ax,cx
+min10:
+ retf 4
+cEnd nogen
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* max() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc max, <FAR, PUBLIC>
+
+;ParmW a
+;ParmW b
+
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+6] ;ax = a
+ mov cx,ss:[bx+4] ;cx = b
+ cmp ax,cx
+ jg max10
+ mov ax,cx
+max10:
+ retf 4
+cEnd nogen
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* umin() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc umin, <FAR, PUBLIC>
+
+;ParmW a
+;ParmW b
+
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+6] ;ax = a
+ mov cx,ss:[bx+4] ;cx = b
+ cmp ax,cx
+ jb umin10
+ mov ax,cx
+umin10:
+ retf 4
+cEnd nogen
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* umax() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc umax, <FAR, PUBLIC>
+
+;ParmW a
+;ParmW b
+
+cBegin nogen
+ mov bx,sp
+ mov ax,ss:[bx+6] ;ax = a
+ mov cx,ss:[bx+4] ;cx = b
+ cmp ax,cx
+ ja umax10
+ mov ax,cx
+umax10:
+ retf 4
+cEnd nogen
+
+endif ; DISABLE
+
+;*--------------------------------------------------------------------------*
+;* *
+;* LFillStruct() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc LFillStruct, <PUBLIC, FAR, NODATA, ATOMIC>, <di>
+
+parmD lpStruct
+parmW cb
+parmW fillChar
+
+cBegin
+ les di,lpStruct
+ mov cx,cb
+ mov ax,fillChar
+ cld
+ rep stosb
+
+cEnd LFillStruct
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* LCopyStruct() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; LCopyStruct(pbSrc, pbDst, cb)
+
+cProc LCopyStruct, <FAR, PUBLIC>
+;ParmD pSrc
+;ParmD pDest
+;ParmW cb
+cBegin nogen
+ mov bx,sp
+
+ mov cx,ss:[bx+4] ; cx = cb
+ jcxz lcopynone ; Nothing to do if count == 0
+
+ push si
+ push di
+ mov dx,ds ; save ds
+
+ lds si,ss:[bx+4+2+4] ; ds:si = pSrc
+ les di,ss:[bx+4+2] ; es:di = pDst
+
+ cmp si,di ; Could they overlap?
+ jae lcopyok
+
+ mov ax,cx ; Yes: copy from the top down
+ dec ax
+ dec ax
+ add si,ax
+ add di,ax
+
+ std
+ shr cx,1
+ rep movsw
+ jnc @F ; an odd byte to blt?
+ inc si ; went one too far: back up.
+ inc di
+ movsb
+@@:
+ cld
+ jmps lcopydone
+
+lcopyok:
+ cld
+ shr cx,1
+ rep movsw
+ jnc @F ; an odd byte to blt?
+ movsb
+@@:
+
+lcopydone:
+ mov ds,dx
+ pop di
+ pop si
+lcopynone:
+ retf 4+4+2
+cEnd nogen
+
+
+ifndef WOW
+;*--------------------------------------------------------------------------*
+;* *
+;* The following routines are "Movable DS" equivalents of their normal *
+;* counterparts. The PS stands for "Pointer Safe." They prevent problems *
+;* which occur when an app passes in a pointer to an object in its DS *
+;* which we somehow cause to move. To prevent this problem, we copy what *
+;* the pointer points to into USER's DS and use a pointer to our copy *
+;* instead. *
+;* *
+;*--------------------------------------------------------------------------*
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* PSGetTextExtent() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+ifndef PMODE
+
+
+cProc PSGetTextExtent, <PUBLIC, FAR, NODATA>, <si,di>
+
+ParmW hdc
+ParmD lpch
+ParmW cch
+
+LocalV rgch, 128 ; max 128 chars
+
+cBegin
+ mov ax,__WinFlags
+ test al,WF_PMODE
+ errnz high(WF_PMODE)
+ jz PSGTE_RealMode
+
+ push hdc
+ pushd lpch
+ push cch
+ jmp short PSGTE_GetExtent
+
+PSGTE_RealMode:
+ lea di,rgch ; es:di = dest
+ push ss
+ pop es
+ lds si,lpch ; ds:si = src
+ mov cx,cch ; count = min(cch, 128)
+ mov ax,128
+ cmp cx,ax
+ jbe gte100
+ xchg ax,cx
+
+gte100: push hdc ; Push args before rep movsb destroys
+ push ss ; cx and di
+ push di
+ push cx
+
+ cld
+ rep movsb ; Copy string to local storage
+
+PSGTE_GetExtent:
+ call GetTextExtent
+
+cEnd PSGetTextExtent
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* PSTextOut() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; void PSTextOut(hdc, lpch, cch)
+
+cProc PSTextOut,<PUBLIC, FAR, NODATA>, <si, di>
+
+ParmW hdc
+ParmW x
+ParmW y
+ParmD lpch
+ParmW cch
+
+LocalV rgch, 255 ; max 255 chars
+
+cBegin
+ mov ax,__WinFlags
+ test al,WF_PMODE
+ errnz high(WF_PMODE)
+ jz PSTO_RealMode
+
+ push hdc
+ push x
+ push y
+ pushd lpch
+ push cch
+ jmp short PSTO_TextOut
+
+PSTO_RealMode:
+ lea di,rgch ; es:di = dest
+ push ss
+ pop es
+ lds si,lpch ; ds:si = src
+ mov cx,cch ; count = min(cch, 255)
+ mov ax,255
+ cmp cx,ax
+ jbe to100
+ xchg ax,cx
+
+to100: push hdc ; Push args before rep movsb destroys
+ push x ; cx and di
+ push y
+ push ss ; Push &rgch[0]
+ push di
+ push cx
+
+ cld
+ rep movsb ; copy string before we go
+
+PSTO_TextOut:
+ call TextOut
+
+cEnd PSTextOut
+
+endif ; ifndef PMODE
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* FindCharPosition() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; Finds position of char ch in string psz. If none, returns the length of
+; the string.
+
+cProc FindCharPosition, <FAR, PUBLIC, NODATA>, <si, ds>
+
+ParmD psz
+ParmB char
+
+cBegin
+ lds si,psz
+fcp100: lodsb ; get a byte
+ or al,al
+ jz fcp200
+ifdef DBCS ; **** April,26,1990 by KenjiK ****
+ sub ah,ah
+ push ax
+ cCall IsDBCSLeadByte,<ax> ; first byte of double byte?
+ test ax,ax
+ pop ax
+ jz fcp150 ; no just do normal stuff
+ lodsb ; skip second byte of double byte
+ jmps fcp100 ; and do again
+fcp150:
+endif
+ cmp al,char
+ jnz fcp100
+fcp200: xchg ax,si ; calc char index: pch - 1 - psz
+ dec ax
+ sub ax,off_psz
+
+cEnd FindCharPosition
+
+endif ;WOW
+
+sEnd %SEGNAME
+
+ifndef WOW
+;*==========================================================================*
+;* *
+;* RUNAPP Segment Definition - *
+;* *
+;*==========================================================================*
+
+createSeg _RUNAPP, RUNAPP, BYTE, PUBLIC, CODE
+
+sBegin RUNAPP
+
+assumes cs,RUNAPP
+assumes ds,DATA
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* CrunchX2() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+; This routine copies the pile of bits from the source pointer
+; to the dest pointer doing the integer crunch as it goes
+; it will favor black (0) to white (1) and will keep the destinations
+; widthbytes even.
+;
+; Assumptions: Neither source nor destination are greater than 64K
+; Either the two bitmaps, lpSrc and lpDst are disjoint
+; or lpDst <= lpSrc (i.e. we fill from the front)
+; WidthBytes is even
+
+cProc CrunchX2, <FAR, PUBLIC, NODATA>, <ds, si, di>
+
+parmD lpSrc
+parmD lpDst
+parmW WidthBytes
+parmW Height
+
+LocalW dwb ; destination width if not corrected
+LocalW destinc ; used to force dest width even each scan
+
+cBegin
+ cld
+ lds si,lpSrc
+ les di,lpDst
+ mov bx,Height
+
+ ; Compute destination widthbytes
+ mov ax,WidthBytes ; must be even
+ shr ax,1 ; widthbytes for the destination
+ mov dwb,ax
+ and ax,1 ; iff odd must inc dest pointer
+ mov destinc,ax ; at the end of each scan
+ sub di,ax
+
+NextSX: dec bx
+ jl exitX
+ mov cx,dwb
+ add di,destinc
+
+CrunchBX:
+ lodsw
+ mov dx,ax
+ rol ax,1
+ and dx,ax ; this and selects 0 in favor of 1
+ mov al,dl
+ shl ax,1
+ shl al,1
+ shl ax,1
+ shl al,1
+ shl ax,1
+ shl al,1
+ shl ax,1
+ mov al,dh
+ shl ax,1
+ shl al,1
+ shl ax,1
+ shl al,1
+ shl ax,1
+ shl al,1
+ shl ax,1
+ mov al,ah
+ stosb
+ loop CrunchBX
+ jmp NextSX
+exitX:
+
+cEnd CrunchX2
+
+
+;*--------------------------------------------------------------------------*
+;* *
+;* CrunchY() - *
+;* *
+;*--------------------------------------------------------------------------*
+
+cProc CrunchY, <FAR, PUBLIC, NODATA>, <ds, si, di>
+
+parmD lpSrc
+parmD lpDst
+parmW WidthBytes
+parmW Height
+parmW scale
+
+LocalW groupcount ;Height/scale
+LocalW groupinc ;WidthBytes * Height/Scale
+LocalW scancount ;counter of bytes in scan reset each group
+LocalW bytecount ;number of bytes joined = scale - 1
+
+cBegin
+ cld
+ lds si,lpSrc
+ les di,lpDst
+
+ ; Compute group count
+ mov bx,scale ; only scale positive
+ cmp bx,1
+ jle CopyBitmap
+ mov ax,Height
+ xor dx,dx
+ div bx
+ mov groupcount,ax ; Height/scale
+ mov cx,WidthBytes ; must be even
+ dec bx
+ mov bytecount,bx
+ mov ax,bx
+ mul cx
+ mov groupinc,ax ; WidthBytes * (scale - 1)
+ mov dx,cx
+ mov bx,si
+ sub bx,groupinc
+ dec bx
+ dec bx
+
+NextGroup:
+ dec groupcount
+ jl exitY
+ add bx,groupinc
+ mov ax,dx
+ shr ax,1
+ mov scancount,ax
+
+NextByte:
+ dec scancount
+ jl NextGroup
+ inc bx
+ inc bx
+ mov si,bx
+ mov ax,[si]
+ mov cx,bytecount
+
+CrunchBY:
+ add si,dx
+ and ax,[si]
+ loop CrunchBY
+ stosw
+ jmp NextByte
+
+CopyBitmap:
+ mov ax,Height
+ mul WidthBytes
+ shr ax,1
+ mov cx,ax
+ rep movsw
+
+exitY:
+cEnd CrunchY
+
+sEnd RUNAPP
+
+endif ;WOW
+
+ end
diff --git a/private/mvdm/wow16/user/wmsyserr.c b/private/mvdm/wow16/user/wmsyserr.c
new file mode 100644
index 000000000..4653677c1
--- /dev/null
+++ b/private/mvdm/wow16/user/wmsyserr.c
@@ -0,0 +1,1263 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WMSYSERR.C
+ * WOW16 system error box handling services
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+ * At this time, all we want is DrawFrame(), which the edit controls use.
+--*/
+
+/****************************************************************************/
+/* */
+/* WMSYSERR.C */
+/* */
+/* System error box handling routine */
+/* */
+/****************************************************************************/
+
+#include "user.h"
+
+#ifndef WOW
+VOID FAR PASCAL GetbackFocusFromWinOldAp(void);
+
+/* Private export from GDI for user. */
+HFONT FAR PASCAL GetCurLogFont(HDC);
+
+
+/* This array contins the state information for the three possible buttons in
+ * a SysErrorBox.
+ */
+
+SEBBTN rgbtn[3];
+
+/* The following arrays are used to map SEB_values to their respective
+ * accelerator keys and text strings.
+ */
+
+#define BTNTYPECOUNT 7
+
+static int rgStyles[BTNTYPECOUNT] =
+ { SEB_OK, SEB_CANCEL, SEB_YES, SEB_NO, SEB_RETRY,
+ SEB_ABORT, SEB_IGNORE };
+
+/* The following array is properly initialised by reading STR_ACCELERATORS
+ * string at LoadWindows time, which contains the accelerator keys
+ * corresponding to each button in the message box; Localizers must modify
+ * this string also. Because, this array will be filled by loading a
+ * string we must have one more space for the null terminator.
+ */
+char rgAccel[BTNTYPECOUNT+1];
+
+extern WORD wDefButton;
+
+int FAR PASCAL SoftModalMessageBox(HWND, LPSTR, LPSTR, WORD);
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* BltColor() - */
+/* */
+/* Modification done by SANKAR on 08-03-89: */
+/* The parameter hbm was used as a boolean only to determine whether to */
+/* use hdcBits or hdcGrey; Now hbm is replaced with hdcSrce, the source*/
+/* device context because, now hdcBits contains color bitmaps and */
+/* hdcMonoBits contains monochrome bitmaps; If hdcSrce is NULL, then */
+/* hdcGrey will be used, else whatever is passed thro hdcSrce will be */
+/* used as the source device context; */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FAR PASCAL BltColor(hdc, hbr, hdcSrce, xO, yO, cx, cy, xO1, yO1, fInvert)
+
+register HDC hdc;
+register HBRUSH hbr;
+HDC hdcSrce;
+int xO, yO;
+int cx, cy;
+int xO1, yO1;
+BOOL fInvert;
+
+{
+ HBRUSH hbrSave;
+ DWORD textColorSave;
+ DWORD bkColorSave;
+
+#ifdef DEBUG
+ if (!hdcGray && !hdcSrce) /* Only test hdcGray if it will be used */
+ FatalExit(RIP_BADDCGRAY);
+#endif
+
+ if (hbr == (HBRUSH)NULL)
+ hbr = sysClrObjects.hbrWindowText;
+
+ /*
+ * Set the Text and Background colors so that bltColor handles the
+ * background of buttons (and other bitmaps) properly.
+ * Save the HDC's old Text and Background colors. This causes problems with
+ * Omega (and probably other apps) when calling GrayString which uses this
+ * routine...
+ */
+ textColorSave = SetTextColor(hdc, 0x00000000L);
+ bkColorSave = SetBkColor(hdc, 0x00FFFFFFL);
+
+ hbrSave = SelectObject(hdc, hbr);
+
+ BitBlt(hdc, xO, yO, cx, cy, hdcSrce ? hdcSrce : hdcGray, xO1, yO1,
+ (fInvert ? 0x00B8074AL : 0x00E20746L));
+
+ SelectObject(hdc, hbrSave);
+
+ /* Restore saved colors */
+ SetTextColor(hdc, textColorSave);
+ SetBkColor(hdc, bkColorSave);
+}
+#endif // WOW
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* DrawFrame() - */
+/* */
+/*--------------------------------------------------------------------------*/
+#define DF_SHIFTMASK (DF_SHIFT0 | DF_SHIFT1 | DF_SHIFT2 | DF_SHIFT3)
+#define DF_ROPMASK (DF_PATCOPY | DF_PATINVERT)
+#define DF_HBRMASK ~(DF_SHIFTMASK | DF_ROPMASK)
+
+/* Command bits:
+ * 0000 0011 - (0-3): Shift count for cxBorder and cyBorder
+ * 0000 0100 - 0: PATCOPY, 1: PATINVERT
+ * 1111 1000 - (0-x): Brushes as they correspond to the COLOR_*
+ * indexes, with hbrGray thrown on last.
+ */
+
+void USERENTRY DrawFrame(hdc, lprc, clFrame, cmd)
+HDC hdc;
+LPRECT lprc;
+int clFrame;
+int cmd;
+{
+ register int x;
+ register int y;
+ int cx;
+ int cy;
+ int cxWidth;
+ int cyWidth;
+ int ibr;
+ HBRUSH hbrSave;
+ LONG rop;
+#ifdef WOW
+ DWORD rgbTemp;
+ static DWORD rgbPrev;
+ static HBRUSH hbrPrev;
+#endif
+
+ x = lprc->left;
+ y = lprc->top;
+
+ cxWidth = GetSystemMetrics(SM_CXBORDER) * clFrame;
+ cyWidth = GetSystemMetrics(SM_CYBORDER) * clFrame;
+
+ if (cmd == DF_ACTIVEBORDER || cmd == DF_INACTIVEBORDER)
+ {
+ /* We are drawing the inside colored part of a sizing border. We
+ * subtract 1 from the width and height because we come back and draw
+ * another frame around the inside. This avoids a lot of flicker when
+ * redrawing a frame that already exists.
+ */
+ cxWidth--;
+ cyWidth--;
+ }
+
+ cx = lprc->right - x - cxWidth;
+ cy = lprc->bottom - y - cyWidth;
+
+ rop = ((cmd & DF_ROPMASK) ? PATINVERT : PATCOPY);
+
+ ibr = (cmd & DF_HBRMASK) >> 3;
+#ifndef WOW
+ if (ibr == (DF_GRAY >> 3))
+ {
+ hbrSave = hbrGray;
+ }
+ else
+ {
+ hbrSave = ((HBRUSH *)&sysClrObjects)[ibr];
+ }
+#else
+ rgbTemp = GetSysColor(ibr);
+ if (!(hbrSave = hbrPrev) || rgbTemp != rgbPrev) {
+ /* Save time and space with black and white objects. */
+ if (rgbTemp == 0L)
+ hbrSave = GetStockObject(BLACK_BRUSH);
+ else if (rgbTemp == 0xFFFFFFL)
+ hbrSave = GetStockObject(WHITE_BRUSH);
+ else
+ hbrSave = CreateSolidBrush(rgbTemp);
+ if (hbrPrev)
+ DeleteObject(hbrPrev);
+ hbrPrev = hbrSave;
+ rgbPrev = rgbTemp;
+ }
+#endif
+
+ // We need to unrealize the object in order to ensure it gets realigned.
+ //
+ UnrealizeObject(hbrSave);
+ hbrSave = SelectObject(hdc, hbrSave);
+
+ /* Time to call the new driver supported fast draw frame stuff. */
+ if (lprc->top >= lprc->bottom ||
+ !FastWindowFrame(hdc, lprc, cxWidth, cyWidth, rop))
+ {
+ /* The driver can't do it so we have to. */
+ PatBlt(hdc, x, y, cxWidth, cy, rop); /* Left */
+ PatBlt(hdc, x + cxWidth, y, cx, cyWidth, rop); /* Top */
+ PatBlt(hdc, x, y + cy, cx, cyWidth, rop); /* Bottom */
+ PatBlt(hdc, x + cx, y + cyWidth, cxWidth, cy, rop); /* Right */
+ }
+
+ if (hbrSave)
+ SelectObject(hdc, hbrSave);
+}
+
+
+#ifndef WOW
+/*--------------------------------------------------------------------------*/
+/* DrawPushButton() - */
+/* */
+/* lprc : The rectangle of the button */
+/* style : Style of the push button */
+/* fInvert : FALSE if pushbutton is in NORMAL state */
+/* TRUE if it is to be drawn in the "down" or inverse state */
+/* hbrBtn : The brush with which the background is to be wiped out. */
+/* hwnd : NULL if no text is to be drawn in the button; */
+/* Contains window handle, if text and focus is to be drawn; */
+/* */
+/*--------------------------------------------------------------------------*/
+
+void FAR PASCAL DrawPushButton(hdc, lprc, style, fInvert, hbrBtn, hwnd)
+
+register HDC hdc;
+RECT FAR *lprc;
+WORD style;
+BOOL fInvert;
+HBRUSH hbrBtn;
+HWND hwnd;
+
+{
+ RECT rcInside;
+ HBRUSH hbrSave;
+ HBRUSH hbrShade = 0;
+ HBRUSH hbrFace = 0;
+ int iBorderWidth;
+ int i;
+ int dxShadow;
+ int cxShadow;
+ int cyShadow;
+
+
+ if (style == LOWORD(BS_DEFPUSHBUTTON))
+ iBorderWidth = 2;
+ else
+ iBorderWidth = 1;
+
+ hbrSave = SelectObject(hdc, hbrBtn);
+
+ CopyRect((LPRECT)&rcInside, lprc);
+ InflateRect((LPRECT)&rcInside, -iBorderWidth*cxBorder,
+ -iBorderWidth*cyBorder);
+
+ /* Draw a frame */
+ DrawFrame(hdc, lprc, iBorderWidth, (COLOR_WINDOWFRAME << 3));
+
+ /* Notch the corners (except don't do this for scroll bar thumb (-1) or
+ for combo box buttons (-2)) */
+ if (style != -1 && style != -2)
+ {
+ /* Cut four notches at the four corners */
+ /* Top left corner */
+ PatBlt(hdc, lprc->left, lprc->top, cxBorder, cyBorder, PATCOPY);
+ /* Top right corner */
+ PatBlt(hdc, lprc->right - cxBorder, lprc->top, cxBorder, cyBorder,
+ PATCOPY);
+ /* bottom left corner */
+ PatBlt(hdc, lprc->left, lprc->bottom - cyBorder, cxBorder, cyBorder,
+ PATCOPY);
+ /* bottom right corner */
+ PatBlt(hdc, lprc->right - cxBorder, lprc->bottom - cyBorder, cxBorder,
+ cyBorder, PATCOPY);
+ }
+
+ /* Draw the shades */
+ if (sysColors.clrBtnShadow != 0x00ffffff)
+ {
+ hbrShade = sysClrObjects.hbrBtnShadow;
+ if (fInvert)
+ {
+ /* Use shadow color */
+ SelectObject(hdc, hbrShade);
+ dxShadow = 1;
+ }
+ else
+ {
+ /* Use white */
+ SelectObject(hdc, GetStockObject(WHITE_BRUSH));
+ dxShadow = (style == -1 ? 1 : 2);
+ }
+
+ cxShadow = cxBorder * dxShadow;
+ cyShadow = cyBorder * dxShadow;
+
+ /* Draw the shadow/highlight in the left and top edges */
+ PatBlt(hdc, rcInside.left, rcInside.top, cxShadow,
+ (rcInside.bottom - rcInside.top), PATCOPY);
+ PatBlt(hdc, rcInside.left, rcInside.top,
+ (rcInside.right - rcInside.left), cyShadow, PATCOPY);
+
+ if (!fInvert)
+ {
+ /* Use shadow color */
+ SelectObject(hdc, hbrShade);
+
+ /* Draw the shade in the bottom and right edges */
+ rcInside.bottom -= cyBorder;
+ rcInside.right -= cxBorder;
+
+ for(i = 0; i <= dxShadow; i++)
+ {
+ PatBlt(hdc, rcInside.left, rcInside.bottom,
+ rcInside.right - rcInside.left + cxBorder, cyBorder,
+ PATCOPY);
+ PatBlt(hdc, rcInside.right, rcInside.top, cxBorder,
+ rcInside.bottom - rcInside.top, PATCOPY);
+ if (i == 0)
+ InflateRect((LPRECT)&rcInside, -cxBorder, -cyBorder);
+ }
+ }
+ }
+ else
+ {
+ /* Don't move text down if no shadows */
+ fInvert = FALSE;
+ /* The following are added as a fix for Bug #2784; Without these
+ * two lines, cxShadow and cyShadow will be un-initialised when
+ * running under a CGA resulting in this bug;
+ * Bug #2784 -- 07-24-89 -- SANKAR
+ */
+ cxShadow = cxBorder;
+ cyShadow = cyBorder;
+ }
+
+ /* Draw the button face color pad. If no clrBtnFace, use white to clear
+ it. */
+ /* if fInvert we don't subtract 1 otherwise we do because up above we
+ do an inflate rect if not inverting for the shadow along the bottom*/
+ rcInside.left += cxShadow - (fInvert ? 0 : cxBorder);
+ rcInside.top += cyShadow - (fInvert ? 0 : cyBorder);
+ if (sysColors.clrBtnFace != 0x00ffffff)
+ hbrFace = sysClrObjects.hbrBtnFace;
+ else
+ hbrFace = GetStockObject(WHITE_BRUSH);
+
+ SelectObject(hdc, hbrFace);
+ PatBlt(hdc, rcInside.left, rcInside.top, rcInside.right - rcInside.left,
+ rcInside.bottom - rcInside.top, PATCOPY);
+
+ if (hbrSave)
+ SelectObject(hdc, hbrSave);
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ * SEB_InitBtnInfo() -
+ * This function fills in the button info structure (SEBBTN) for the
+ * specified button.
+ *---------------------------------------------------------------------------
+ */
+void NEAR PASCAL SEB_InitBtnInfo(
+ HDC hdc, /* DC to be used in dispplaying the button */
+ unsigned int style, /* one of the SEB_* styles */
+ int xBtn,
+ int yBtn, /* center the button on this (x, y) pixel */
+ int cxBtn,
+ int cyBtn, /* make the button this size */
+ int index) /* index of the rgbtn entry to initialize */
+
+{
+ long Extent;
+ int i;
+ int temp1, temp2;
+#ifdef DEBUG
+ BOOL fFound = FALSE;
+#endif
+
+ rgbtn[index].finvert = FALSE;
+ if ((rgbtn[index].style = style) == NULL)
+ return;
+
+ /* Calc the button text and accelerator */
+ for (i = 0; i < MAX_MB_STRINGS; i++)
+ {
+ if (rgStyles[i] == (style & ~SEB_DEFBUTTON))
+ {
+ rgbtn[index].psztext = AllMBbtnStrings[i];
+ rgbtn[index].chaccel = rgAccel[i];
+#ifdef DEBUG
+ fFound = TRUE;
+#endif
+ break;
+ }
+ }
+#ifdef DEBUG
+ if (!fFound)
+ {
+ /* RIP city */
+ return;
+ }
+#endif
+
+ /* Calc the button rectangle */
+ SetRect((LPRECT)&rgbtn[index].rcbtn,
+ (temp1 = xBtn - (cxBtn >> 1)),
+ (temp2 = yBtn - (cyBtn >> 1)),
+ temp1 + cxBtn,
+ temp2 + cyBtn);
+
+ /* Calc the text position */
+ Extent = PSMGetTextExtent(hdc,
+ (LPSTR)rgbtn[index].psztext,
+ lstrlen((LPSTR)rgbtn[index].psztext));
+ rgbtn[index].pttext.x = xBtn - (LOWORD(Extent) >> 1);
+ rgbtn[index].pttext.y = yBtn - (HIWORD(Extent) >> 1);
+/* rgbtn[index].pttext.y = yBtn - (cySysFontAscent >> 1);*/
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * SEB_DrawFocusRect() -
+ * This function draws the Focus frame.
+ *---------------------------------------------------------------------------
+ */
+
+ void NEAR PASCAL SEB_DrawFocusRect(HDC hdc,
+ LPRECT lprcBtn,
+ LPSTR lpszBtnStr,
+ int iLen,
+ BOOL fPressed)
+
+ {
+ DWORD dwExtents;
+ RECT rc;
+
+ dwExtents = PSMGetTextExtent(hdc, (LPSTR)lpszBtnStr, iLen);
+
+ rc.left = lprcBtn->left + ((lprcBtn->right - lprcBtn->left - LOWORD(dwExtents)) >> 1) - (cxBorder << 1);
+ rc.right = rc.left + (cxBorder << 2) + LOWORD(dwExtents);
+ rc.top = lprcBtn->top + ((lprcBtn->bottom - lprcBtn->top - HIWORD(dwExtents)) >> 1) - cyBorder;
+ rc.bottom = rc.top + (cyBorder << 1) + HIWORD(dwExtents) + cyBorder;
+
+ if(fPressed)
+ OffsetRect(&rc, 1, 1);
+
+ /* NOTE: I know you will be tempted to use DrawFocusRect(); But this
+ * uses PatBlt() with PATINVERT! This causes instant death in int24
+ * SysErrBoxes! So, I am calling FrameRect() which calls PatBlt() with
+ * PATCOPY. This works fine in int24 cases also!
+ * --SANKAR--
+ */
+ FrameRect(hdc, (LPRECT)&rc, hbrGray);
+}
+
+
+
+/*
+ *---------------------------------------------------------------------------
+ * SEB_DrawButton() -
+ * This function draws the button specified. The pbtninfo parameter is
+ * a pointer to a structure of type SEBBTN.
+ *---------------------------------------------------------------------------
+ */
+void NEAR PASCAL SEB_DrawButton(HDC hdc, /* HDC to use for drawing */
+ int i) /* index of the rgbtn to draw */
+
+ {
+ DWORD colorSave;
+ int iLen;
+
+ if (rgbtn[i].style == NULL)
+ return;
+
+ /* DrawPushButton() wipes out the background also */
+ DrawPushButton(hdc,
+ (LPRECT)&rgbtn[i].rcbtn,
+ (WORD)((rgbtn[i].style & SEB_DEFBUTTON) ? BS_DEFPUSHBUTTON:
+ BS_PUSHBUTTON),
+ rgbtn[i].finvert,
+ GetStockObject(WHITE_BRUSH),
+ (HWND)NULL);
+ colorSave = SetTextColor(hdc, sysColors.clrBtnText);
+ SetBkMode(hdc, TRANSPARENT);
+ /* Preserve the button color for vga systems */
+ PSMTextOut(hdc,
+ rgbtn[i].pttext.x + (rgbtn[i].finvert ? 1 : 0),
+ rgbtn[i].pttext.y + (rgbtn[i].finvert ? 1 : 0),
+ (LPSTR)rgbtn[i].psztext,
+ (iLen = lstrlen((LPSTR)rgbtn[i].psztext)));
+ /* Only the default button can have the focus frame */
+ if(rgbtn[i].style & SEB_DEFBUTTON)
+ SEB_DrawFocusRect(hdc,
+ (LPRECT)&rgbtn[i].rcbtn,
+ (LPSTR)rgbtn[i].psztext,
+ iLen,
+ rgbtn[i].finvert);
+ SetTextColor(hdc, colorSave);
+ SetBkMode(hdc, OPAQUE);
+ }
+
+
+/*
+ *---------------------------------------------------------------------------
+ * SEB_BtnHit(pt)
+ * Return the index of the rgbtn that the point is in. If not in any button
+ * then return -1.
+ *---------------------------------------------------------------------------
+ */
+
+
+int NEAR SEB_BtnHit(int x, int y)
+{
+ POINT pt;
+ register int i;
+
+ pt.x = x;
+ pt.y = y;
+
+ for (i = 0; i <= 2; i++)
+ {
+ if (rgbtn[i].style != NULL)
+ if (PtInRect((LPRECT)&rgbtn[i].rcbtn, pt))
+ return(i);
+ }
+ return(-1);
+}
+
+
+
+/*
+ *---------------------------------------------------------------------------
+ * SysErrorBox()
+ *
+ * This function is used to display a system error type message box. No
+ * system resources (other than the stack) is used to display this box.
+ * Also, it is guarenteed that all code needed to complete this function
+ * will be memory at all times. This will allow the calling of this
+ * funtion by the INT24 handler.
+ *
+ * Paramerers:
+ * lpszText Text string of the message itself. This message is
+ * assumed to be only one line in length and short enough
+ * to fit in the box. The box will size itself horizontally
+ * to center the string, but will not be sized beyond the
+ * size of the physical screen.
+ *
+ * lpszCaption Text of the caption of the box. This caption will be
+ * displayed at the top of the box, centered. The same
+ * restrictions apply.
+ *
+ * Btn1
+ * Btn2
+ * Btn3 One of the following:
+ * NULL No button in this position.
+ * SEB_OK Button with "OK".
+ * SEB_CANCEL Button with "Cancel"
+ * SEB_YES Button with "Yes"
+ * SEB_NO Button with "No"
+ * SEB_RETRY Button with "Retry"
+ * SEB_ABORT Button with "Abort"
+ * SEB_IGNORE Button with "Ignore"
+ *
+ * Also, one of the parameters may have the value
+ * SEB_DEFBUTTON
+ * OR'ed with any of the SEB_* valued above. This draws
+ * this button as the default button and sets the initial
+ * "focus" to this button. Only one button should have
+ * this style. If no buttons have this style, the first
+ * button whose value is not NULL will be the default button.
+ *
+ * Return Value:
+ * This funtion returns one of the following values:
+ *
+ * SEB_BTN1 Button 1 was selected
+ * SEB_BTN2 Button 2 was selected
+ * SEB_BTN3 Button 3 was selected
+ *
+ *---------------------------------------------------------------------------
+ */
+
+
+
+/* Maximum number of lines allowed in a system error box.
+ */
+#define MAXSYSERRLINES 3
+/* Struct allocated on stack for max lines.
+ */
+typedef struct tagSysErr
+{
+ int iStart;
+ int cch;
+ int cxText;
+} SYSERRSTRUCT;
+
+int USERENTRY SysErrorBox(lpszText, lpszCaption, btn1, btn2, btn3)
+
+LPSTR lpszText;
+LPSTR lpszCaption;
+unsigned int btn1, btn2, btn3;
+
+{
+ register int cx, cy;
+ SYSERRSTRUCT sysErr[MAXSYSERRLINES];
+ int temp;
+ int cchCaption;
+ int cxText, cxCaption, cxButtons;
+ int cxCenter, cxQuarter;
+ int cxBtn, cyBtn;
+ int xBtn, yBtn;
+ int iTextLines;
+ HDC hdc;
+ RECT rcBox, rcTemp;
+ HRGN hrgn;
+ int far *pbtn;
+ int i;
+ MSG msg;
+ BOOL fBtnDown;
+ BOOL fKeyBtnDown = FALSE;
+ int BtnReturn;
+ int btnhit;
+ int defbtn;
+ HWND hwndFocusSave;
+ BOOL fMessageBoxGlobalOld = fMessageBox;
+ BOOL fOldHWInput;
+ HWND hwndSysModalBoxOld;
+ LPSTR lptemp;
+ RECT rcInvalidDesktop; /* Keep union of invalid desktop rects */
+
+
+
+ /* We have to determine if we are running Win386 in PMODE
+ * at the time of bringing up this SysErrBox. In this case we
+ * have to call Win386 to Set the screen focus to us so that
+ * the user can see the SYSMODAL error message that we display;
+ * Fix for Bug #5272 --SANKAR-- 10-12-89
+ */
+ if ((WinFlags & WF_WIN386) && (WinFlags & WF_PMODE))
+ GetbackFocusFromWinOldAp();
+
+
+
+ /* Set this global so that we don't over write our globals when kernel calls
+ * this routine directly. We need to save and restore the state of the
+ * fMessageBox flag. If SysErrorBox is called via HardSysModal, then this
+ * flag is set and we do proper processing in the message loop. However, if
+ * Kernel calls syserrorbox directly, then this flag wasn't being set and we
+ * could break...
+ */
+ fMessageBox = TRUE;
+
+ /* Save off the guy who was the old sys modal dialog box in case the int24
+ * box is put up when a sys modal box is up.
+ */
+ hwndSysModalBoxOld = hwndSysModal;
+
+
+ /* Clear this global so that if the mouse is down on an NC area we don't
+ * drop into the move/size code when we return. If we do, it thinks the
+ * mouse is down when it really isn't
+ */
+ fInt24 = TRUE;
+
+ /* Initialise the Global structure */
+ LFillStruct((LPSTR)rgbtn, 3*sizeof(SEBBTN), '\0');
+
+ /* Change the hq for the desktop to be the current task hq */
+ if (NEEDSPAINT(hwndDesktop))
+ DecPaintCount(hwndDesktop);
+
+ hwndDesktop->hq = HqCurrent();
+
+ if (NEEDSPAINT(hwndDesktop))
+ IncPaintCount(hwndDesktop);
+
+
+ hdc = GetScreenDC();
+
+ /*
+ * Calculate the extents of the error box. Then set the rectangle that
+ * we will use for drawing.
+ *
+ * The x extent of the box is the maximin of the the folowing items:
+ * - The text for the box (padded with 3 chars on each end).
+ * - The caption for the box (also padded).
+ * - 3 maximum sized buttons (szCANCEL).
+ *
+ * The y extent is 10 times the height of the system font.
+ *
+ */
+
+ cy = cySysFontChar * 10;
+
+ /* How many lines in the box text and their extents etc?
+ */
+ iTextLines = 0;
+ sysErr[0].iStart = 0;
+ sysErr[0].cch = 0;
+ sysErr[0].cxText = 0;
+ lptemp=lpszText;
+ cxText = 0; /* Max text length
+ */
+ while (lptemp)
+ {
+ if (*lptemp == '\n' || *lptemp==0)
+ {
+ sysErr[iTextLines].cxText = LOWORD(GetTextExtent(hdc,
+ (LPSTR)(lpszText+sysErr[iTextLines].iStart),
+ sysErr[iTextLines].cch));
+
+ /* Keep track of length of longest line
+ */
+ cxText = max(sysErr[iTextLines].cxText,cxText);
+ if (*lptemp && *(lptemp+1)!=0 && iTextLines < MAXSYSERRLINES)
+ {
+ /* Another line exists
+ */
+ iTextLines++;
+ sysErr[iTextLines].iStart = sysErr[iTextLines-1].iStart +
+ sysErr[iTextLines-1].cch+1;
+ sysErr[iTextLines].cch = 0;
+ sysErr[iTextLines].cxText = 0;
+
+ lptemp++;
+ }
+ else
+ break;
+ }
+ else
+ {
+ sysErr[iTextLines].cch++;
+ lptemp++;
+ }
+ }
+ cx = cxText + (6 * cxSysFontChar);
+
+ /* Get the extent of the box caption
+ */
+ cxCaption = LOWORD(GetTextExtent(hdc,
+ (LPSTR)lpszCaption,
+ (cchCaption = lstrlen(lpszCaption))));
+ temp = cxCaption + (6 * cxSysFontChar);
+
+ if (cx < temp)
+ cx = temp;
+
+ /* Get the extent of 3 maximum sized buttons */
+ cxBtn = wMaxBtnSize + (cySysFontChar << 1);
+ cxButtons = (cxBtn + (cySysFontChar << 2)) * 3;
+
+ if (cx < cxButtons)
+ cx = cxButtons;
+
+ /* Center the box on the screen. Bound to left edge if too big. */
+ rcBox.top = (cyScreen >> 1) - (cy >> 1);
+ rcBox.bottom = rcBox.top + cy;
+ rcBox.left = (cxScreen >> 1) - (cx >> 1);
+ if (rcBox.left < 0)
+ rcBox.left = 0;
+ rcBox.right = rcBox.left + cx;
+ cxCenter = (rcBox.left + rcBox.right) >> 1;
+
+ PatBlt(hdc, rcBox.left, rcBox.top, cx, cy, WHITENESS);
+
+ rcTemp = rcBox;
+
+ DrawFrame(hdc, &rcTemp, 1, DF_WINDOWFRAME);
+ InflateRect(&rcTemp, -(cxBorder * (CLDLGFRAMEWHITE + 1)),
+ -(cyBorder * (CLDLGFRAMEWHITE + 1)));
+ DrawFrame(hdc, &rcTemp, CLDLGFRAME, DF_ACTIVECAPTION);
+
+ TextOut(hdc,
+ cxCenter - (cxCaption >> 1),
+ rcBox.top + cySysFontChar,
+ (LPSTR)lpszCaption,
+ cchCaption);
+
+ i=0;
+ /* First line of text starts at what y offset ?
+ */
+ if (iTextLines == 0)
+ temp = (cySysFontChar << 2);
+ else
+ temp = (cySysFontChar << 1)+(cySysFontChar * (MAXSYSERRLINES-iTextLines));
+
+ while (i<=iTextLines)
+ {
+ TextOut(hdc,
+/* cxCenter - (cxText >> 1),*/
+ cxCenter - (sysErr[i].cxText >> 1),
+ rcBox.top + temp+(i*cySysFontChar),
+ (LPSTR)lpszText+sysErr[i].iStart,
+ sysErr[i].cch);
+
+ i++;
+ }
+
+ pbtn = &btn1;
+ xBtn = (cxQuarter = cx >> 2) + rcBox.left;
+ yBtn = rcBox.bottom - (cySysFontChar << 1);
+ cyBtn = cySysFontChar << 1;
+
+ for (i=0; i <= 2; i++, pbtn--)
+ {
+ SEB_InitBtnInfo(hdc, *pbtn, xBtn, yBtn, cxBtn, cyBtn, i);
+ SEB_DrawButton(hdc, i);
+ xBtn += cxQuarter;
+ }
+
+
+ Capture(hwndDesktop, CLIENT_CAPTURE);
+ SetSysModalWindow(hwndDesktop);
+
+ /*hCursOld =*/ SetCursor(hCursNormal);
+ /* Why are we doing this???? This is causing us to hit the disk to load some
+ * cursor resource during interrupt time... davidds
+ */
+ /* CallOEMCursor();*/
+ hwndFocusSave = hwndFocus;
+ hwndFocus = hwndDesktop;
+
+ fBtnDown = FALSE;
+ BtnReturn = 0;
+ btnhit = -1; /* -1 if not on a button, else index into rgbtn[] */
+ defbtn = -1;
+ for (i = 0; i <= 2; i++)
+ if (rgbtn[i].style & SEB_DEFBUTTON)
+ {
+ defbtn = i;
+ break;
+ }
+
+ /* Prevent other tasks from running because this is SysModal */
+ if (!fEndSession)
+ LockMyTask(TRUE);
+
+ /* Insure that hardware input is enabled */
+ fOldHWInput = EnableHardwareInput(TRUE);
+
+ /* Initially, only invalidate desktop where the sys error box was.
+ */
+ rcInvalidDesktop = rcBox;
+
+ while (BtnReturn == 0)
+ {
+ if (!PeekMessage((LPMSG)&msg, hwndDesktop, 0, 0, PM_REMOVE | PM_NOYIELD))
+ continue;
+
+#ifdef NEVER
+********* TranslateMessage() calls ToAscii() which refers to some tables
+ in a LoadOnCall segment; So, this is commented out here; We can not
+ look for WM_CHAR messages, but we still get WM_KEYDOWN messages!
+ --Sankar, April 17, 1989--
+
+ TranslateMessage((LPMSG)&msg);
+*********
+#endif
+
+ if (msg.hwnd == hwndDesktop)
+ {
+ switch (msg.message)
+ {
+ case WM_LBUTTONDOWN:
+ fBtnDown = TRUE;
+ if ((btnhit = SEB_BtnHit(LOWORD(msg.lParam),
+ HIWORD(msg.lParam))) != -1)
+ {
+ /* Move the default button to the next button.
+ */
+ if ((defbtn != -1) && (btnhit != defbtn))
+ {
+ /* Draw the current def button as not default.
+ */
+ rgbtn[defbtn].style &= ~SEB_DEFBUTTON;
+ SEB_DrawButton(hdc, defbtn);
+ /* Draw the new button as default.
+ */
+ defbtn = btnhit;
+ rgbtn[btnhit].style |= SEB_DEFBUTTON;
+ }
+ rgbtn[btnhit].finvert = TRUE;
+ SEB_DrawButton(hdc, btnhit);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ fBtnDown = FALSE;
+ /* Was the mouse hitting on a button? If so, terminate the
+ * loop and return the button index.
+ */
+ if (btnhit != -1)
+ BtnReturn = btnhit + 1;
+ break;
+
+ case WM_MOUSEMOVE:
+ /* Only look at mouse moves if the button is down.
+ */
+ if (fBtnDown)
+ {
+ /* Hitting on a button?
+ */
+ if ((i = SEB_BtnHit(LOWORD(msg.lParam), HIWORD(msg.lParam))) != -1)
+ {
+ /* Mouse moved and we are on a button. First test
+ * to see if we are on the same button as before.
+ */
+ if ((i != btnhit) && (btnhit != -1))
+ {
+ rgbtn[btnhit].finvert = FALSE;
+ SEB_DrawButton(hdc, btnhit);
+ }
+ /* Verify that the new button is
+ * inverted and that btnhit is current.
+ */
+ btnhit = i;
+ if (rgbtn[btnhit].finvert == FALSE)
+ {
+ rgbtn[btnhit].finvert = TRUE;
+ SEB_DrawButton(hdc, btnhit);
+ }
+ } else {
+ /* button down, but not hitting on a button. Check
+ * for drag off a button.
+ */
+ if (btnhit != -1)
+ {
+ rgbtn[btnhit].finvert = FALSE;
+ SEB_DrawButton(hdc, btnhit);
+ btnhit = -1;
+ }
+ }
+ }
+ break;
+ case WM_KEYUP:
+ if(fKeyBtnDown)
+ {
+ switch(msg.wParam)
+ {
+ case VERYBIGINTEGER:
+ /* Because this code gets moved into himem, we can't use jump
+ * tables; This VERYBIGINTEGER prevents C6.0 from using a jump
+ * table in the translation of Switch Statements;
+ */
+ break;
+
+ case VK_SPACE:
+ case VK_RETURN:
+ /* Select the current default button and return.
+ */
+ if (defbtn != -1)
+ BtnReturn = defbtn + 1;
+ break;
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ GetUpdateRect(msg.hwnd, &rcTemp, FALSE);
+ ValidateRect(msg.hwnd, NULL);
+ UnionRect(&rcInvalidDesktop, &rcInvalidDesktop, &rcTemp);
+ break;
+
+ case WM_SYSKEYDOWN:
+ /* Look for accelerator keys
+ */
+ for (i = 0; i <= 2; i++)
+ {
+ /* Convert to lower case and test for a match */
+ if (((BYTE)msg.wParam | 0x20) == rgbtn[i].chaccel)
+ {
+ BtnReturn = i + 1;
+ break;
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ switch (msg.wParam)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ /* Just keep the button pressed */
+ /* If already pressed, ignore the rest sothat we
+ * won't flicker horribly
+ */
+ if((defbtn != -1) && (!fKeyBtnDown))
+ {
+ fKeyBtnDown = TRUE;
+ rgbtn[defbtn].finvert = TRUE;
+ SEB_DrawButton(hdc, defbtn);
+ }
+ break;
+
+ case VK_TAB:
+ /* Move the default button to the next button.
+ */
+ if (defbtn != -1)
+ {
+ /* Draw the current def button as not default.
+ */
+ rgbtn[defbtn].style &= ~SEB_DEFBUTTON;
+ SEB_DrawButton(hdc, defbtn);
+ /* Calc the next def button. Inc defbtn, but
+ * wrap from btn 3 to btn 1. Also, don't stop
+ * on a button that isn't defined.
+ */
+ if (defbtn == 2)
+ defbtn = 0;
+ else
+ ++defbtn;
+ while (rgbtn[defbtn].style == NULL)
+ {
+ if (++defbtn > 2)
+ defbtn = 0;
+ }
+
+ /* Draw the new default button as default.
+ */
+ rgbtn[defbtn].style |= SEB_DEFBUTTON;
+ SEB_DrawButton(hdc, defbtn);
+ }
+ break;
+
+ case VK_ESCAPE:
+ /* See if there is a button with SEB_CANCEL. If there
+ * is, return it's id.
+ */
+ for (i = 0; i <= 2; i++)
+ {
+ if ((rgbtn[i].style & ~SEB_DEFBUTTON)
+ == SEB_CANCEL)
+ {
+ BtnReturn = ++i;
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ }
+ }
+ }
+
+ fMessageBox=fMessageBoxGlobalOld;
+
+ /* Insure that hardware input is put back the way it was */
+ EnableHardwareInput(fOldHWInput);
+
+ /* Allow other tasks to run. */
+ LockMyTask(FALSE);
+
+ /* Set sys modal box back to the guy who was up */
+ SetSysModalWindow(hwndSysModalBoxOld);
+
+ Capture(NULL, NO_CAP_CLIENT);
+
+#if 0
+ The old cursor may have been paged out. We can't do this.
+ SetCursor(hCursOld);
+#endif
+#if causetrouble
+ if (iLevelCursor < 0)
+ OEMSetCursor((LPSTR)NULL);
+#endif
+ hwndFocus = hwndFocusSave;
+
+ /* Set this flag indicating that another window was activate so that if we
+ * were in menu mode when the sys error box came up, we know we should get
+ * out because the actual mouse button/keyboard state may be different than
+ * what the menu state thinks it is.
+ */
+ fActivatedWindow = TRUE;
+
+ InternalReleaseDC(hdc);
+
+ /* Invalidate the invalid portions of the desktop.
+ */
+ InvalidateRect(hwndDesktop, &rcInvalidDesktop, FALSE);
+ hrgn = CreateRectRgn(rcInvalidDesktop.left, rcInvalidDesktop.top,
+ rcInvalidDesktop.right,rcInvalidDesktop.bottom);
+ InternalInvalidate(hwndDesktop, (hrgn ? hrgn : (HRGN) 1),
+ RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
+ if (hrgn)
+ DeleteObject(hrgn);
+// RedrawScreen();
+ return(BtnReturn);
+}
+
+
+
+int NEAR PASCAL HardSysModalMessageBox(LPSTR lpszText,
+ LPSTR lpszCaption,
+ WORD wBtnCnt,
+ WORD wType)
+{
+ WORD wBegBtn;
+ int iCurIndex;
+ int iCurButton;
+ WORD iButtonNo;
+ int iRetVal;
+ WORD wTemp;
+ struct
+ {
+ unsigned int InVal;
+ char RetVal;
+ }Param[3];
+
+ /* If we're trying to bring up a hard sys modal message box
+ * while another one is up, wait till the first one is through.
+ * This protects our static save globals. I'm not actually
+ * sure this can ever happen (at least under DOS 3).
+ */
+ if (fMessageBox)
+ Yield();
+
+ fMessageBox = TRUE;
+
+ wBegBtn = mpTypeIich[wType]; /* Index of Begining button */
+
+ Param[0].InVal = Param[1].InVal = Param[2].InVal = 0;
+
+ iCurIndex = 0;
+ for(iButtonNo = 0; iButtonNo < wBtnCnt; iButtonNo++)
+ {
+ iCurButton = iCurIndex;
+ switch(wBtnCnt)
+ {
+ case 1: /* One button; Put it in Param[1] */
+ Param[1].InVal = SEBbuttons[wBegBtn];
+ Param[1].RetVal = rgReturn[wBegBtn];
+ iCurButton = 1;
+ break;
+
+ case 2: /* 2 Buttons; Put them in Param[0] and Param[2] */
+ Param[iCurIndex].InVal = SEBbuttons[wTemp = wBegBtn + iButtonNo];
+ Param[iCurIndex].RetVal = rgReturn[wTemp];
+ iCurIndex += 2;
+ break;
+
+ case 3: /* 3 Buttons; Put them in Param[0], [1] and [2] */
+ Param[iCurIndex].InVal = SEBbuttons[wTemp = wBegBtn + iButtonNo];
+ Param[iCurIndex].RetVal = rgReturn[wTemp];
+ iCurIndex++;
+ break;
+ }
+
+ /* Check for the default button */
+ if(wDefButton == iButtonNo)
+ Param[iCurButton].InVal |= SEB_DEFBUTTON;
+ }
+
+ iRetVal = SysErrorBox(lpszText, lpszCaption, Param[0].InVal,
+ Param[1].InVal, Param[2].InVal);
+
+ fMessageBox = FALSE;
+
+ return((int)Param[iRetVal - SEB_BTN1].RetVal);
+}
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* MessageBox() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+int USERENTRY MessageBox(hwndOwner, lpszText, lpszCaption, wStyle)
+
+HWND hwndOwner;
+LPSTR lpszText;
+LPSTR lpszCaption;
+WORD wStyle;
+
+{
+ WORD wBtnCnt;
+ WORD wType;
+ WORD wIcon;
+
+#ifdef DEBUG
+ if (!GetTaskQueue(GetCurrentTask()))
+ {
+ /* There is no task queue. Not put up message boxes.
+ */
+ UserFatalExitSz(RIP_MESSAGEBOXWITHNOQUEUE,
+ "\n\rMessageBox failed - no message queue has been initialized yet. MessageBox not allowed.",
+ 0);
+ }
+#endif
+
+ /* If lpszCaption is NULL, then use "Error!" string as the caption
+ string */
+ if(!lpszCaption)
+ lpszCaption = (LPSTR)szERROR;
+
+ wBtnCnt = mpTypeCcmd[(wType = wStyle & MB_TYPEMASK)];
+
+ /* Set the default button value */
+ wDefButton = (wStyle & MB_DEFMASK) / (MB_DEFMASK & (MB_DEFMASK >> 3));
+
+ if(wDefButton >= wBtnCnt) /* Check if valid */
+ wDefButton = 0; /* Set the first button if error */
+
+ /* Check if this is a hard sys modal message box */
+ wIcon = wStyle & MB_ICONMASK;
+
+ if(((wStyle & MB_MODEMASK) == MB_SYSTEMMODAL) &&
+ ((wIcon == NULL) || (wIcon == MB_ICONHAND)))
+ {
+ /* It is a hard sys modal message box */
+ return(HardSysModalMessageBox(lpszText, lpszCaption, wBtnCnt, wType));
+ }
+ else
+ return(SoftModalMessageBox(hwndOwner, lpszText, lpszCaption, wStyle));
+}
+
+
+BOOL FAR PASCAL IsSystemFont(hdc)
+register HDC hdc;
+/* effects: Returns TRUE if font selected into DC is the system font else
+ returns false. This is called by interrupt time code so it needs to be
+ in the fixed code segment. */
+{
+ return(GetCurLogFont(hdc) == GetStockObject(SYSTEM_FONT));
+}
+
+BOOL FAR PASCAL IsSysFontAndDefaultMode(hdc)
+register HDC hdc;
+/* effects: Returns TRUE if font selected into DC is the system font AND
+ the current mapping mode of the DC is MM_TEXT (Default mode); else
+ returns false. This is called by interrupt time code so it needs to be
+ in the fixed code segment. */
+/* This function is the fix for Bug #8717 --02-01-90-- SANKAR */
+{
+ return(IsSystemFont(hdc) && (GetMapMode(hdc) == MM_TEXT));
+}
+
+
+int USERENTRY WEP(int i)
+{
+ return(1);
+}
+#endif // WOW
diff --git a/private/mvdm/wow16/user/wowasm.cmd b/private/mvdm/wow16/user/wowasm.cmd
new file mode 100644
index 000000000..678f4d39a
--- /dev/null
+++ b/private/mvdm/wow16/user/wowasm.cmd
@@ -0,0 +1,11 @@
+@echo off
+echo WOWASM.CMD : Generating wow.asm file from wowasm.asm
+sed -f wowasm.sed wowasm.asm > wow.asm
+echo WOWASM.CMD : making wow.obj to filter Jump out of range erorrs
+nmake /i wow.obj | qgrep -y a2053 > wowtmp1.sed
+sed -n -e s/^wow.[Aa][Ss][Mm].\([0-9][0-9]*\).*$/\1s\/SHORT\/\/p/p wowtmp1.sed > wowtmp2.sed
+sed -f wowtmp2.sed wow.asm > wowtmp3.sed
+copy wowtmp3.sed wow.asm
+del wowtmp?.sed
+@echo on
+
diff --git a/private/mvdm/wow16/user/wowasm.sed b/private/mvdm/wow16/user/wowasm.sed
new file mode 100644
index 000000000..db38ac0f4
--- /dev/null
+++ b/private/mvdm/wow16/user/wowasm.sed
@@ -0,0 +1,13 @@
+s/^if\(.*ersion.*510\)/if 1 ; \1/p
+s/\.model/; .model/p
+s/USE32/USE16/p
+s/NEAR/FAR/p
+s/\[ebp/\[bp/
+s/^FLAT/; FLAT/p
+s/FLAT/NOTHING/p
+s/\(push.\)\([0-9][0-9]*\)/\1dword ptr \2/p
+s/^\(EXTRN.*_GetAppCompatFlags@4:\)/; \1/p
+s/\(rep.movs\)d$/\1 dword ptr [edi], dword ptr [esi]/p
+s/\(rep.movs\)b$/\1 byte ptr [edi], byte ptr [esi]/p
+s/\(rep[a-z]*.scas\)b$/\1 byte ptr [edi]/p
+s/\(EXTRN.*_wow16.*DWORD\)/; \1/p
diff --git a/private/mvdm/wow16/user/wowasmc.cmd b/private/mvdm/wow16/user/wowasmc.cmd
new file mode 100644
index 000000000..8a722bb37
--- /dev/null
+++ b/private/mvdm/wow16/user/wowasmc.cmd
@@ -0,0 +1,16 @@
+@echo off
+echo WOWASMC.CMD : Generating wowc.asm file from wowasmc.asm
+cd c
+sed -f ..\wowasm.sed %1.asm > %2.asm
+echo WOWASMC.CMD : making wowc.obj to filter Jump out of range erorrs
+cd ..
+nmake /i c\%2.obj | qgrep -y a2053 > wowtmp1.sed
+del %2.obj
+sed -n -e s/^c\\%2.[Aa][Ss][Mm].\([0-9][0-9]*\).*$/\1s\/SHORT\/\/p/p wowtmp1.sed > wowtmp2.sed
+echo 1n>>wowtmp2.sed
+cd c
+sed -f ..\wowtmp2.sed %2.asm > wowtmp3.sed
+copy wowtmp3.sed %2.asm
+del wowtmp?.sed ..\wowtmp*.sed
+cd ..
+@echo on
diff --git a/private/mvdm/wow16/user/wowasmk.cmd b/private/mvdm/wow16/user/wowasmk.cmd
new file mode 100644
index 000000000..11707c67a
--- /dev/null
+++ b/private/mvdm/wow16/user/wowasmk.cmd
@@ -0,0 +1,16 @@
+@echo off
+echo WOWASMK.CMD : Generating %3\%2.asm file from %1.asm
+cd k\%3
+sed -f ..\..\wowasm.sed %1.asm > %2.asm
+echo WOWASMK.CMD : making %3\%2.obj to filter Jump out of range erorrs
+cd ..\..
+nmake /i k\%3\%2.obj | qgrep -y a2053 > wowtmp1.sed
+del k\%3\%2.obj
+sed -n -e s/^k\\%3\\%2.[Aa][Ss][Mm].\([0-9][0-9]*\).*$/\1s\/SHORT\/\/p/p wowtmp1.sed > wowtmp2.sed
+echo 1n>>wowtmp2.sed
+cd k\%3
+sed -f ..\..\wowtmp2.sed %2.asm > wowtmp3.sed
+copy wowtmp3.sed %2.asm
+del wowtmp?.sed ..\..\wowtmp*.sed
+cd ..\..
+@echo on
diff --git a/private/mvdm/wow16/user/wowcomm.c b/private/mvdm/wow16/user/wowcomm.c
new file mode 100644
index 000000000..8221f4c57
--- /dev/null
+++ b/private/mvdm/wow16/user/wowcomm.c
@@ -0,0 +1,60 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WOWCOMM.C
+ * WOW16 user resource services
+ *
+ * History:
+ *
+ * Created 28-Apr-1993 by Craig Jones (v-cjones)
+ *
+ * This file provides support for the Win 3.1 SetCommEventMask() API.
+ * SetCommEventMask() returns a 16:16 ptr to the app so it can monitor
+ * the event word & shadow MSR.
+ *
+--*/
+
+#include <windows.h>
+#include <wowcomm.h>
+
+int WINAPI WOWCloseComm(int idComDev, LPDWORD lpdwEvts);
+int WINAPI WOWOpenComm(LPCSTR lpszPort, UINT cbInQ, UINT cbOutQ, DWORD dwEvts);
+
+
+int WINAPI ICloseComm(int idComDev)
+{
+ int ret;
+ DWORD dwEvts = 0;
+
+ // we're really calling wu32CloseComm() here
+ ret = WOWCloseComm(idComDev, (LPDWORD)&dwEvts);
+
+ // free this 16:16 memory if it was alloc'd in IOpenComm()
+ if(dwEvts) {
+ GlobalDosFree((UINT)LOWORD(dwEvts));
+ }
+
+ return(ret);
+}
+
+
+int WINAPI IOpenComm(LPCSTR lpszPort, UINT cbInQ, UINT cbOutQ)
+{
+ int ret;
+ DWORD dwEvts;
+
+ dwEvts = GlobalDosAlloc((DWORD)sizeof(COMDEB16));
+
+ // we're really calling wu32OpenComm() here
+ ret = WOWOpenComm(lpszPort, cbInQ, cbOutQ, dwEvts);
+
+ // if OpenComm() failed - free the 16:16 memory
+ if((ret < 0) && (dwEvts)) {
+ GlobalDosFree((UINT)LOWORD(dwEvts));
+ }
+
+ return(ret);
+}
diff --git a/private/mvdm/wow16/user/wsphelp.asm b/private/mvdm/wow16/user/wsphelp.asm
new file mode 100644
index 000000000..6f0445cc9
--- /dev/null
+++ b/private/mvdm/wow16/user/wsphelp.asm
@@ -0,0 +1,140 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WSPHELP.ASM
+; Win16 wsprintf/wvsprintf helper services
+;
+; History:
+;
+; Created 28-May-1991 by Jeff Parsons (jeffpar)
+; Copied from WIN31 and edited (as little as possible) for WOW16
+;--
+
+;
+; WSPHELP.ASM
+;
+; Assembly language helper functions for wvsprintf(), primarily for
+; space optimization.
+;
+; History:
+; 2/15/89 craigc Initial
+;
+
+memS=1
+?PLM=1
+?WIN=1
+ifdef WOW
+SEGNAME equ <TEXT>
+endif
+
+.xlist
+include cmacros.inc
+.list
+
+createSeg _%SEGNAME,%SEGNAME,WORD,public,CODE
+
+sBegin %SEGNAME
+
+assumes cs,%SEGNAME
+
+;
+; SP_PutNumber
+;
+; Takes an unsigned long integer and places it into a buffer, respecting
+; a buffer limit, a radix, and a case select (upper or lower, for hex).
+;
+
+cProc SP_PutNumber, <NEAR,PUBLIC>, <si,di>
+
+ parmD lpb
+ parmD n
+ parmW limit
+ parmW radix
+ parmW case
+
+cBegin
+ mov al,'a'-'0'-10 ; figure out conversion offset
+ cmp case,0
+ jz pn_lower
+ mov al,'A'-'0'-10
+pn_lower:
+ mov byte ptr case,al
+
+ mov bx,word ptr n[0] ; bx:dx=number
+ mov dx,word ptr n[2]
+ mov cx,radix ; cx=radix
+ les di,lpb ; es:di->string
+ mov si,limit ; cchLimit
+;
+; following adapted from fultoa.asm
+;
+; dx:bx = unsigned number, cx = radix, es:di->output
+;
+
+divdown:
+ xchg ax,dx ; divide hi
+ xor dx,dx
+ or ax,ax
+ jz nohigh ; save a divide
+ div cx ; dx = rem, ax = hi div
+
+nohigh:
+ xchg ax,bx ; ax = lo, bx = hi div
+ div cx ; dx = rem, bx:ax = div
+ xchg ax,dx ; ax = rem, bx:dx = div
+ xchg dx,bx ; ax = rem, dx:bx = div (tight!!!!)
+ add al,'0'
+ cmp al,'9'
+ jbe isadig ; is a digit already
+ add al,byte ptr case ; convert to letter
+
+isadig:
+ dec si ; decrement cchLimit
+ jz pn_exit ; go away if end of string
+ stosb ; stick it in
+ mov ax,dx
+ or ax,bx
+ jnz divdown ; crack out next digit
+
+pn_exit:
+ mov ax,di
+ sub ax,word ptr lpb[0] ; find number of chars output
+
+cEnd
+
+;
+; SP_Reverse
+;
+; Reverses a string in place
+;
+cProc SP_Reverse,<NEAR,PUBLIC>,<si,di>
+ parmD lpFirst
+ parmD lpLast
+cBegin
+ push ds
+ lds si,lpFirst
+ les di,lpLast
+ mov cx,di ; number of character difference
+ sub cx,si
+ inc cx
+ shr cx,1 ; number of swaps required
+ jcxz spr_boring ; nuthin' to do
+spr100:
+ mov ah,es:[di]
+ mov al,[si] ; load the two characters
+ mov [si],ah
+ mov es:[di],al ; swap them
+ inc si
+ dec di ; adjust the pointers
+ loop spr100 ; ...until we've done 'em all
+spr_boring:
+ pop ds
+cEnd
+
+
+sEnd %SEGNAME
+
+end
diff --git a/private/mvdm/wow16/user/wsprintf.c b/private/mvdm/wow16/user/wsprintf.c
new file mode 100644
index 000000000..c7b759268
--- /dev/null
+++ b/private/mvdm/wow16/user/wsprintf.c
@@ -0,0 +1,339 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * WSPRINTF.C
+ * Win16 wsprintf/wvsprintf code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/*
+ *
+ * sprintf.c
+ *
+ * Implements Windows friendly versions of sprintf and vsprintf
+ *
+ * History:
+ * 2/15/89 craigc Initial
+ */
+
+#include "windows.h"
+#include "winexp.h"
+
+#define WSPRINTF_LIMIT 1024
+
+extern int near pascal SP_PutNumber(LPSTR, long, int, int, int);
+extern void near pascal SP_Reverse(LPSTR lp1, LPSTR lp2);
+
+#define out(c) if (--cchLimit) *lpOut++=(c); else goto errorout
+
+/*
+ * GetFmtValue
+ *
+ * reads a width or precision value from the format string
+ */
+
+LPCSTR near pascal SP_GetFmtValue(LPCSTR lpch,int FAR *lpw)
+{
+ register int i=0;
+
+ while (*lpch>='0' && *lpch<='9')
+ {
+ i *= 10;
+ i += (WORD)(*lpch-'0');
+ lpch++;
+ }
+
+ *lpw=i;
+
+ /* return the address of the first non-digit character */
+ return lpch;
+}
+
+/*
+ * wvsprintf()
+ *
+ * Windows version of vsprintf(). Does not support floating point or
+ * pointer types, and all strings are assumed to be FAR. Supports only
+ * the left alignment flag.
+ *
+ * Takes pointers to an output buffer, where the string is built, a
+ * pointer to an input buffer, and a pointer to a list of parameters.
+ *
+ * The cdecl function wsprintf() calls this function.
+ */
+
+int API Iwvsprintf(LPSTR lpOut, LPCSTR lpFmt, LPSTR lpParms)
+{
+ int left;
+ char prefix;
+ register int width;
+ register int prec;
+ char fillch;
+ int size;
+ int sign;
+ int radix;
+ int upper;
+ int cchLimit=WSPRINTF_LIMIT;
+ int cch;
+ LPSTR lpT;
+ union {
+ long l;
+ unsigned long ul;
+ char sz[sizeof(long)];
+ } val;
+
+ while (*lpFmt)
+ {
+ if (*lpFmt=='%')
+ {
+
+ /* read the flags. These can be in any order */
+ left=0;
+ prefix=0;
+ while (*++lpFmt)
+ {
+ if (*lpFmt=='-')
+ left++;
+ else if (*lpFmt=='#')
+ prefix++;
+ else
+ break;
+ }
+
+ /* find fill character */
+ if (*lpFmt=='0')
+ {
+ fillch='0';
+ lpFmt++;
+ }
+ else
+ fillch=' ';
+
+ /* read the width specification */
+ lpFmt=SP_GetFmtValue(lpFmt,&cch);
+ width=cch;
+
+ /* read the precision */
+ if (*lpFmt=='.')
+ {
+ lpFmt=SP_GetFmtValue(++lpFmt,&cch);
+ prec=cch;
+ }
+ else
+ prec=-1;
+
+ /* get the operand size */
+ if (*lpFmt=='l')
+ {
+ size=1;
+ lpFmt++;
+ }
+ else
+ {
+ size=0;
+ if (*lpFmt=='h')
+ lpFmt++;
+ }
+
+ upper=0;
+ sign=0;
+ radix=10;
+ switch (*lpFmt)
+ {
+ case 0:
+ goto errorout;
+
+ case 'i':
+ case 'd':
+ sign++;
+
+ case 'u':
+ /* turn off prefix if decimal */
+ prefix=0;
+donumeric:
+ /* special cases to act like MSC v5.10 */
+ if (left || prec>=0)
+ fillch=' ';
+
+ if (size)
+ val.l=*((long far *)lpParms)++;
+ else
+ if (sign)
+ val.l=(long)*((short far *)lpParms)++;
+ else
+ val.ul=(unsigned long)*((unsigned far *)lpParms)++;
+
+ if (sign && val.l<0L)
+ val.l=-val.l;
+ else
+ sign=0;
+
+ lpT=lpOut;
+
+ /* blast the number backwards into the user buffer */
+ cch=SP_PutNumber(lpOut,val.l,cchLimit,radix,upper);
+ if (!(cchLimit-=cch))
+ goto errorout;
+
+ lpOut+=cch;
+ width-=cch;
+ prec-=cch;
+ if (prec>0)
+ width-=prec;
+
+ /* fill to the field precision */
+ while (prec-->0)
+ out('0');
+
+ if (width>0 && !left)
+ {
+ /* if we're filling with spaces, put sign first */
+ if (fillch!='0')
+ {
+ if (sign)
+ {
+ sign=0;
+ out('-');
+ width--;
+ }
+
+ if (prefix)
+ {
+ out(prefix);
+ out('0');
+ prefix=0;
+ }
+ }
+
+ if (sign)
+ width--;
+
+ /* fill to the field width */
+ while (width-->0)
+ out(fillch);
+
+ /* still have a sign? */
+ if (sign)
+ out('-');
+
+ if (prefix)
+ {
+ out(prefix);
+ out('0');
+ }
+
+ /* now reverse the string in place */
+ SP_Reverse(lpT,lpOut-1);
+ }
+ else
+ {
+ /* add the sign character */
+ if (sign)
+ {
+ out('-');
+ width--;
+ }
+
+ if (prefix)
+ {
+ out(prefix);
+ out('0');
+ }
+
+ /* reverse the string in place */
+ SP_Reverse(lpT,lpOut-1);
+
+ /* pad to the right of the string in case left aligned */
+ while (width-->0)
+ out(fillch);
+ }
+ break;
+
+ case 'X':
+ upper++;
+ case 'x':
+ radix=16;
+ if (prefix)
+ if (upper)
+ prefix='X';
+ else
+ prefix='x';
+ goto donumeric;
+
+ case 'c':
+ val.sz[0]=*lpParms;
+ val.sz[1]=0;
+ lpT=val.sz;
+ cch = 1; // Length is one character.
+ // Fix for Bug #1862 --01/10/91-- SANKAR --
+ /* stack aligned to larger size */
+ lpParms+=sizeof(int);
+
+ goto putstring;
+
+ case 's':
+ lpT=*((LPSTR FAR *)lpParms)++;
+ cch=lstrlen(lpT);
+putstring:
+ if (prec>=0 && cch>prec)
+ cch=prec;
+ width -= cch;
+ if (left)
+ {
+ while (cch--)
+ out(*lpT++);
+ while (width-->0)
+ out(fillch);
+ }
+ else
+ {
+ while (width-->0)
+ out(fillch);
+ while (cch--)
+ out(*lpT++);
+ }
+ break;
+
+ default:
+normalch:
+#ifdef DBCS /* masas : 90-4-26 */
+ if( IsDBCSLeadByte(*lpFmt) )
+ out(*lpFmt++);
+#endif
+ out(*lpFmt);
+ break;
+
+ } /* END OF SWITCH(*lpFmt) */
+ } /* END OF IF(%) */
+ else
+ goto normalch; /* character not a '%', just do it */
+
+ /* advance to next format string character */
+ lpFmt++;
+ } /* END OF OUTER WHILE LOOP */
+
+errorout:
+ *lpOut=0;
+
+ return WSPRINTF_LIMIT-cchLimit;
+}
+
+
+/*
+ * wsprintf
+ *
+ * Windows version of sprintf
+ *
+ */
+
+int FAR cdecl wsprintf(LPSTR lpOut, LPCSTR lpFmt, LPSTR lpParms, ...)
+{
+ return wvsprintf(lpOut,lpFmt,(LPSTR)&lpParms);
+}
diff --git a/private/mvdm/wow16/user/wsubcls.c b/private/mvdm/wow16/user/wsubcls.c
new file mode 100644
index 000000000..e6689479b
--- /dev/null
+++ b/private/mvdm/wow16/user/wsubcls.c
@@ -0,0 +1,105 @@
+//****************************************************************************
+// SubClassing Support -
+//
+// Each standard window proc calls 'callwindowproc' withits own address.
+//
+//
+// History:
+//
+// 15-JAN-92 Nandurir Created.
+//
+//****************************************************************************
+
+#include "user.h"
+
+
+//****************************************************************************
+// Thunk for ButtonWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL ButtonWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)ButtonWndProc, hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for ComboBoxCtlWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL ComboBoxCtlWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)ComboBoxCtlWndProc, hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for EditWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL EditWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)EditWndProc, hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for LBoxCtlWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL LBoxCtlWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)LBoxCtlWndProc, hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for SBWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL SBWndProc(PSB hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)SBWndProc, (HWND)hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for StaticWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL StaticWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)StaticWndProc, hwnd, message, wParam, lParam);
+}
+
+
+
+//****************************************************************************
+// Thunk for MDIClientWndProc -
+//
+//****************************************************************************
+
+LONG FAR PASCAL MDIClientWndProc(HWND hwnd, WORD message, WORD wParam,
+ LONG lParam)
+{
+ return CallWindowProc((FARPROC)MDIClientWndProc, hwnd, message, wParam, lParam);
+}
+
+
diff --git a/private/mvdm/wow16/wfwnet/bseerr.h b/private/mvdm/wow16/wfwnet/bseerr.h
new file mode 100644
index 000000000..f0c76ad18
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/bseerr.h
@@ -0,0 +1,617 @@
+/****************************** Module Header ******************************\
+*
+* Module Name: BSEERR.H
+*
+* Copy of the Lanman BSEERR.H used for their base error codes.
+* Not used by anyone else.
+*
+\***************************************************************************/
+
+#ifndef BSEERR_INCLUDED
+#define BSEERR_INCLUDED
+
+#define NO_ERROR 0
+#define ERROR_INVALID_FUNCTION 1
+#define ERROR_FILE_NOT_FOUND 2
+#define ERROR_PATH_NOT_FOUND 3
+#define ERROR_TOO_MANY_OPEN_FILES 4
+#define ERROR_ACCESS_DENIED 5
+#define ERROR_INVALID_HANDLE 6
+#define ERROR_ARENA_TRASHED 7
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#define ERROR_INVALID_BLOCK 9
+#define ERROR_BAD_ENVIRONMENT 10
+#define ERROR_BAD_FORMAT 11
+#define ERROR_INVALID_ACCESS 12
+#define ERROR_INVALID_DATA 13
+/* 14 is reserved */
+#define ERROR_INVALID_DRIVE 15
+#define ERROR_CURRENT_DIRECTORY 16
+#define ERROR_NOT_SAME_DEVICE 17
+#define ERROR_NO_MORE_FILES 18
+#define ERROR_WRITE_PROTECT 19
+#define ERROR_BAD_UNIT 20
+#define ERROR_NOT_READY 21
+#define ERROR_BAD_COMMAND 22
+#define ERROR_CRC 23
+#define ERROR_BAD_LENGTH 24
+#define ERROR_SEEK 25
+#define ERROR_NOT_DOS_DISK 26
+#define ERROR_SECTOR_NOT_FOUND 27
+#define ERROR_OUT_OF_PAPER 28
+#define ERROR_WRITE_FAULT 29
+#define ERROR_READ_FAULT 30
+#define ERROR_GEN_FAILURE 31
+#define ERROR_SHARING_VIOLATION 32
+#define ERROR_LOCK_VIOLATION 33
+#define ERROR_WRONG_DISK 34
+#define ERROR_FCB_UNAVAILABLE 35
+#define ERROR_SHARING_BUFFER_EXCEEDED 36
+#define ERROR_NOT_SUPPORTED 50
+#define ERROR_REM_NOT_LIST 51 /* Remote computer not listening */
+#define ERROR_DUP_NAME 52 /* Duplicate name on network */
+#define ERROR_BAD_NETPATH 53 /* Network path not found */
+#define ERROR_NETWORK_BUSY 54 /* Network busy */
+#define ERROR_DEV_NOT_EXIST 55 /* Network device no longer exists */
+#define ERROR_TOO_MANY_CMDS 56 /* Net BIOS command limit exceeded */
+#define ERROR_ADAP_HDW_ERR 57 /* Network adapter hardware error */
+#define ERROR_BAD_NET_RESP 58 /* Incorrect response from network */
+#define ERROR_UNEXP_NET_ERR 59 /* Unexpected network error */
+#define ERROR_BAD_REM_ADAP 60 /* Incompatible remote adapter */
+#define ERROR_PRINTQ_FULL 61 /* Print queue full */
+#define ERROR_NO_SPOOL_SPACE 62 /* Not enough space for print file */
+#define ERROR_PRINT_CANCELLED 63 /* Print file was cancelled */
+#define ERROR_NETNAME_DELETED 64 /* Network name was deleted */
+#define ERROR_NETWORK_ACCESS_DENIED 65 /* Access denied */
+#define ERROR_BAD_DEV_TYPE 66 /* Network device type incorrect */
+#define ERROR_BAD_NET_NAME 67 /* Network name not found */
+#define ERROR_TOO_MANY_NAMES 68 /* Network name limit exceeded */
+#define ERROR_TOO_MANY_SESS 69 /* Net BIOS session limit exceeded */
+#define ERROR_SHARING_PAUSED 70 /* Sharing temporarily paused */
+#define ERROR_REQ_NOT_ACCEP 71 /* Network request not accepted */
+#define ERROR_REDIR_PAUSED 72 /* Print|disk redirection is paused*/
+#define ERROR_FILE_EXISTS 80
+#define ERROR_DUP_FCB 81
+#define ERROR_CANNOT_MAKE 82
+#define ERROR_FAIL_I24 83
+#define ERROR_OUT_OF_STRUCTURES 84
+#define ERROR_ALREADY_ASSIGNED 85
+#define ERROR_INVALID_PASSWORD 86
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_NET_WRITE_FAULT 88
+#define ERROR_NO_PROC_SLOTS 89 /* no process slots available */
+#define ERROR_NOT_FROZEN 90
+#define ERR_TSTOVFL 91 /* timer service table overflow */
+#define ERR_TSTDUP 92 /* timer service table duplicate */
+#define ERROR_NO_ITEMS 93 /* no items to operate upon */
+#define ERROR_INTERRUPT 95 /* interrupted system call */
+#define ERROR_DEVICE_IN_USE 99 /* Device in use by another thread */
+#define ERROR_TOO_MANY_SEMAPHORES 100
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101
+#define ERROR_SEM_IS_SET 102
+#define ERROR_TOO_MANY_SEM_REQUESTS 103
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104
+#define ERROR_SEM_OWNER_DIED 105 /* waitsem found owner died */
+#define ERROR_SEM_USER_LIMIT 106 /* too many procs have this sem */
+#define ERROR_DISK_CHANGE 107
+#define ERROR_DRIVE_LOCKED 108 /* drive locked by another process*/
+#define ERROR_BROKEN_PIPE 109 /* write on pipe with no reader */
+#define ERROR_OPEN_FAILED 110 /* open/created failed due to */
+ /* explicit fail command */
+#define ERROR_BUFFER_OVERFLOW 111 /* buffer passed to system call */
+ /* is too small to hold return */
+ /* data. */
+#define ERROR_DISK_FULL 112 /* not enough space on the disk */
+ /* (DOSNEWSIZE/w_NewSize) */
+#define ERROR_NO_MORE_SEARCH_HANDLES 113 /* can't allocate another search */
+ /* structure and handle. */
+ /* (DOSFINDFIRST/w_FindFirst) */
+#define ERROR_INVALID_TARGET_HANDLE 114 /* Target handle in DOSDUPHANDLE */
+ /* is invalid */
+#define ERROR_PROTECTION_VIOLATION 115 /* Bad user virtual address */
+#define ERROR_VIOKBD_REQUEST 116
+#define ERROR_INVALID_CATEGORY 117 /* Category for DEVIOCTL in not */
+ /* defined */
+#define ERROR_INVALID_VERIFY_SWITCH 118 /* invalid value passed for */
+ /* verify flag */
+#define ERROR_BAD_DRIVER_LEVEL 119 /* DosDevIOCTL looks for a level */
+ /* four driver. If the driver */
+ /* is not level four we return */
+ /* this code */
+#define ERROR_CALL_NOT_IMPLEMENTED 120 /* returned from stub api calls. */
+ /* This call will disappear when */
+ /* all the api's are implemented. */
+#define ERROR_SEM_TIMEOUT 121 /* Time out happened from the */
+ /* semaphore api functions. */
+#define ERROR_INSUFFICIENT_BUFFER 122 /* Some calls require the */
+ /* application to pass in a buffer */
+ /* filled with data. This error is */
+ /* returned if the data buffer is too */
+ /* small. For example: DosSetFileInfo */
+ /* requires 4 bytes of data. If a */
+ /* two byte buffer is passed in then */
+ /* this error is returned. */
+ /* error_buffer_overflow is used when */
+ /* the output buffer in not big enough.*/
+#define ERROR_INVALID_NAME 123 /* illegal character or malformed */
+ /* file system name */
+#define ERROR_INVALID_LEVEL 124 /* unimplemented level for info */
+ /* retrieval or setting */
+#define ERROR_NO_VOLUME_LABEL 125 /* no volume label found with */
+ /* DosQFSInfo command */
+#define ERROR_MOD_NOT_FOUND 126 /* w_getprocaddr,w_getmodhandle */
+#define ERROR_PROC_NOT_FOUND 127 /* w_getprocaddr */
+#define ERROR_WAIT_NO_CHILDREN 128 /* CWait finds to children */
+#define ERROR_CHILD_NOT_COMPLETE 129 /* CWait children not dead yet */
+#define ERROR_DIRECT_ACCESS_HANDLE 130 /* handle operation is invalid */
+ /* for direct disk access */
+ /* handles */
+#define ERROR_NEGATIVE_SEEK 131 /* application tried to seek */
+ /* with negitive offset */
+#define ERROR_SEEK_ON_DEVICE 132 /* application tried to seek */
+ /* on device or pipe */
+#define ERROR_IS_JOIN_TARGET 133
+#define ERROR_IS_JOINED 134
+#define ERROR_IS_SUBSTED 135
+#define ERROR_NOT_JOINED 136
+#define ERROR_NOT_SUBSTED 137
+#define ERROR_JOIN_TO_JOIN 138
+#define ERROR_SUBST_TO_SUBST 139
+#define ERROR_JOIN_TO_SUBST 140
+#define ERROR_SUBST_TO_JOIN 141
+#define ERROR_BUSY_DRIVE 142
+#define ERROR_SAME_DRIVE 143
+#define ERROR_DIR_NOT_ROOT 144
+#define ERROR_DIR_NOT_EMPTY 145
+#define ERROR_IS_SUBST_PATH 146
+#define ERROR_IS_JOIN_PATH 147
+#define ERROR_PATH_BUSY 148
+#define ERROR_IS_SUBST_TARGET 149
+#define ERROR_SYSTEM_TRACE 150 /* system trace error */
+#define ERROR_INVALID_EVENT_COUNT 151 /* DosMuxSemWait errors */
+#define ERROR_TOO_MANY_MUXWAITERS 152
+#define ERROR_INVALID_LIST_FORMAT 153
+#define ERROR_LABEL_TOO_LONG 154
+#define ERROR_TOO_MANY_TCBS 155
+#define ERROR_SIGNAL_REFUSED 156
+#define ERROR_DISCARDED 157
+#define ERROR_NOT_LOCKED 158
+#define ERROR_BAD_THREADID_ADDR 159
+#define ERROR_BAD_ARGUMENTS 160
+#define ERROR_BAD_PATHNAME 161
+#define ERROR_SIGNAL_PENDING 162
+#define ERROR_UNCERTAIN_MEDIA 163
+#define ERROR_MAX_THRDS_REACHED 164
+#define ERROR_MONITORS_NOT_SUPPORTED 165
+#define ERROR_UNC_DRIVER_NOT_INSTALLED 166
+
+/* The following error codes refer to demand loading segments */
+#define ERROR_LOCK_FAILED 167
+#define ERROR_SWAPIO_FAILED 168
+#define ERROR_SWAPIN_FAILED 169
+#define ERROR_BUSY 170
+
+#define ERROR_INVALID_SEGMENT_NUMBER 180
+#define ERROR_INVALID_CALLGATE 181
+#define ERROR_INVALID_ORDINAL 182
+#define ERROR_ALREADY_EXISTS 183
+#define ERROR_NO_CHILD_PROCESS 184
+#define ERROR_CHILD_ALIVE_NOWAIT 185
+#define ERROR_INVALID_FLAG_NUMBER 186
+#define ERROR_SEM_NOT_FOUND 187
+
+/* following error codes make loader error messages distinct */
+#define ERROR_INVALID_STARTING_CODESEG 188
+#define ERROR_INVALID_STACKSEG 189
+#define ERROR_INVALID_MODULETYPE 190
+#define ERROR_INVALID_EXE_SIGNATURE 191
+#define ERROR_EXE_MARKED_INVALID 192
+#define ERROR_BAD_EXE_FORMAT 193
+#define ERROR_ITERATED_DATA_EXCEEDS_64K 194
+#define ERROR_INVALID_MINALLOCSIZE 195
+#define ERROR_DYNLINK_FROM_INVALID_RING 196
+#define ERROR_IOPL_NOT_ENABLED 197
+#define ERROR_INVALID_SEGDPL 198
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202
+#define ERROR_ENVVAR_NOT_FOUND 203
+#define ERROR_NOT_CURRENT_CTRY 204
+#define ERROR_NO_SIGNAL_SENT 205
+#define ERROR_FILENAME_EXCED_RANGE 206 /* if filename > 8.3 */
+#define ERROR_RING2_STACK_IN_USE 207 /* for FAPI */
+#define ERROR_META_EXPANSION_TOO_LONG 208 /* if "*a" > 8.3 */
+#define ERROR_INVALID_SIGNAL_NUMBER 209
+#define ERROR_THREAD_1_INACTIVE 210
+#define ERROR_INFO_NOT_AVAIL 211
+#define ERROR_LOCKED 212
+#define ERROR_BAD_DYNALINK 213
+#define ERROR_TOO_MANY_MODULES 214
+#define ERROR_NESTING_NOT_ALLOWED 215
+#define ERROR_CANNOT_SHRINK 216 /* attempt to shrink ring 2 stack */
+#define ERROR_ZOMBIE_PROCESS 217
+#define ERROR_STACK_IN_HIGH_MEMORY 218
+#define ERROR_INVALID_EXITROUTINE_RING 219
+#define ERROR_GETBUF_FAILED 220
+#define ERROR_FLUSHBUF_FAILED 221
+#define ERROR_TRANSFER_TOO_LONG 222
+#define ERROR_NO_CHILDREN 228
+#define ERROR_INVALID_SCREEN_GROUP 229
+/*
+ * Error codes 230 - 249 are reserved
+ */
+#define ERROR_BAD_PIPE 230 /* Non-existant pipe or bad operation */
+#define ERROR_PIPE_BUSY 231 /* Pipe is busy */
+#define ERROR_NO_DATA 232 /* No data on non-blocking read */
+#define ERROR_PIPE_NOT_CONNECTED 233 /* Pipe was disconnected by server*/
+#define ERROR_MORE_DATA 234 /* More data is available */
+
+#define ERROR_VC_DISCONNECTED 240
+#define ERROR_CIRCULARITY_REQUESTED 250 /* When renaming a dir which */
+ /* would cause a circularity */
+#define ERROR_DIRECTORY_IN_CDS 251 /* When renaming a dir */
+ /* which is "in use" */
+#define ERROR_INVALID_FSD_NAME 252 /* when trying to access */
+ /* nonexistent FSD */
+#define ERROR_INVALID_PATH 253 /* bad pseudo device */
+#define ERROR_INVALID_EA_NAME 254 /* Illegal chars in name */
+#define ERROR_EA_LIST_INCONSISTENT 255 /* Size or some field bad */
+#define ERROR_EA_LIST_TOO_LONG 256 /* FEAlist > 64K-1 bytes */
+#define ERROR_NO_META_MATCH 257 /* string doesn't match expression*/
+#define ERROR_FINDNOTIFY_TIMEOUT 258 /* FindNotify request timeout */
+#define ERROR_NO_MORE_ITEMS 259 /* QFSAttach ordinal query */
+#define ERROR_SEARCH_STRUC_REUSED 260 /* 3xbox findfirst/next
+ search structure reused */
+#define ERROR_CHAR_NOT_FOUND 261 /* can not find character */
+#define ERROR_TOO_MUCH_STACK 262 /* Stack request exceeds sys limit*/
+#define ERROR_INVALID_ATTR 263 /* invalid FS_ATTRIBUTE */
+#define ERROR_INVALID_STARTING_RING 264
+#define ERROR_INVALID_DLL_INIT_RING 265
+#define ERROR_CANNOT_COPY 266 /* doscopy */
+#define ERROR_DIRECTORY 267 /* doscopy */
+#define ERROR_OPLOCKED_FILE 268
+#define ERROR_OPLOCK_THREAD_EXISTS 269
+
+/* error codes for DosFindNotify */
+#define ERROR_VOLUME_CHANGED 270
+#define ERROR_FINDNOTIFY_HANDLE_IN_USE 271
+#define ERROR_FINDNOTIFY_HANDLE_CLOSED 272
+#define ERROR_NOTIFY_OBJECT_REMOVED 273
+
+/* Error to indicate that ShutDown already done */
+#define ERROR_ALREADY_SHUTDOWN 274
+
+/* error code for DOSFINDFIRST2/NEXT */
+#define ERROR_EAS_DIDNT_FIT 275
+
+/* error codes for EA file format change */
+#define ERROR_EA_FILE_CORRUPT 276
+#define ERROR_EA_TABLE_FULL 277
+#define ERROR_INVALID_EA_HANDLE 278
+#define ERROR_NO_CLUSTER 279
+#define ERROR_CREATE_EA_FILE 280
+#define ERROR_CANNOT_OPEN_EA_FILE 281
+
+#define ERROR_INVALID_PROCID 303
+#define ERROR_INVALID_PDELTA 304
+#define ERROR_NOT_DESCENDANT 305
+#define ERROR_NOT_SESSION_MANAGER 306
+#define ERROR_INVALID_PCLASS 307
+#define ERROR_INVALID_SCOPE 308
+#define ERROR_INVALID_THREADID 309
+#define ERROR_DOSSUB_SHRINK 310
+#define ERROR_DOSSUB_NOMEM 311
+#define ERROR_DOSSUB_OVERLAP 312
+#define ERROR_DOSSUB_BADSIZE 313
+#define ERROR_DOSSUB_BADFLAG 314
+#define ERROR_DOSSUB_BADSELECTOR 315
+#define ERROR_MR_MSG_TOO_LONG 316
+#define ERROR_MR_MID_NOT_FOUND 317
+#define ERROR_MR_UN_ACC_MSGF 318
+#define ERROR_MR_INV_MSGF_FORMAT 319
+#define ERROR_MR_INV_IVCOUNT 320
+#define ERROR_MR_UN_PERFORM 321
+#define ERROR_TS_WAKEUP 322
+#define ERROR_TS_SEMHANDLE 323
+#define ERROR_TS_NOTIMER 324
+#define ERROR_TS_HANDLE 326
+#define ERROR_TS_DATETIME 327
+#define ERROR_SYS_INTERNAL 328
+#define ERROR_QUE_CURRENT_NAME 329
+#define ERROR_QUE_PROC_NOT_OWNED 330
+#define ERROR_QUE_PROC_OWNED 331
+#define ERROR_QUE_DUPLICATE 332
+#define ERROR_QUE_ELEMENT_NOT_EXIST 333
+#define ERROR_QUE_NO_MEMORY 334
+#define ERROR_QUE_INVALID_NAME 335
+#define ERROR_QUE_INVALID_PRIORITY 336
+#define ERROR_QUE_INVALID_HANDLE 337
+#define ERROR_QUE_LINK_NOT_FOUND 338
+#define ERROR_QUE_MEMORY_ERROR 339
+#define ERROR_QUE_PREV_AT_END 340
+#define ERROR_QUE_PROC_NO_ACCESS 341
+#define ERROR_QUE_EMPTY 342
+#define ERROR_QUE_NAME_NOT_EXIST 343
+#define ERROR_QUE_NOT_INITIALIZED 344
+#define ERROR_QUE_UNABLE_TO_ACCESS 345
+#define ERROR_QUE_UNABLE_TO_ADD 346
+#define ERROR_QUE_UNABLE_TO_INIT 347
+#define ERROR_VIO_INVALID_MASK 349
+#define ERROR_VIO_PTR 350
+#define ERROR_VIO_APTR 351
+#define ERROR_VIO_RPTR 352
+#define ERROR_VIO_CPTR 353
+#define ERROR_VIO_LPTR 354
+#define ERROR_VIO_MODE 355
+#define ERROR_VIO_WIDTH 356
+#define ERROR_VIO_ATTR 357
+#define ERROR_VIO_ROW 358
+#define ERROR_VIO_COL 359
+#define ERROR_VIO_TOPROW 360
+#define ERROR_VIO_BOTROW 361
+#define ERROR_VIO_RIGHTCOL 362
+#define ERROR_VIO_LEFTCOL 363
+#define ERROR_SCS_CALL 364
+#define ERROR_SCS_VALUE 365
+#define ERROR_VIO_WAIT_FLAG 366
+#define ERROR_VIO_UNLOCK 367
+#define ERROR_SGS_NOT_SESSION_MGR 368
+#define ERROR_SMG_INVALID_SGID 369
+#define ERROR_SMG_INVALID_SESSION_ID 369
+#define ERROR_SMG_NOSG 370
+#define ERROR_SMG_NO_SESSIONS 370
+#define ERROR_SMG_GRP_NOT_FOUND 371
+#define ERROR_SMG_SESSION_NOT_FOUND 371
+#define ERROR_SMG_SET_TITLE 372
+#define ERROR_KBD_PARAMETER 373
+#define ERROR_KBD_NO_DEVICE 374
+#define ERROR_KBD_INVALID_IOWAIT 375
+#define ERROR_KBD_INVALID_LENGTH 376
+#define ERROR_KBD_INVALID_ECHO_MASK 377
+#define ERROR_KBD_INVALID_INPUT_MASK 378
+#define ERROR_MON_INVALID_PARMS 379
+#define ERROR_MON_INVALID_DEVNAME 380
+#define ERROR_MON_INVALID_HANDLE 381
+#define ERROR_MON_BUFFER_TOO_SMALL 382
+#define ERROR_MON_BUFFER_EMPTY 383
+#define ERROR_MON_DATA_TOO_LARGE 384
+#define ERROR_MOUSE_NO_DEVICE 385
+#define ERROR_MOUSE_INV_HANDLE 386
+#define ERROR_MOUSE_INV_PARMS 387
+#define ERROR_MOUSE_CANT_RESET 388
+#define ERROR_MOUSE_DISPLAY_PARMS 389
+#define ERROR_MOUSE_INV_MODULE 390
+#define ERROR_MOUSE_INV_ENTRY_PT 391
+#define ERROR_MOUSE_INV_MASK 392
+#define NO_ERROR_MOUSE_NO_DATA 393
+#define NO_ERROR_MOUSE_PTR_DRAWN 394
+#define ERROR_INVALID_FREQUENCY 395
+#define ERROR_NLS_NO_COUNTRY_FILE 396
+#define ERROR_NLS_OPEN_FAILED 397
+#define ERROR_NLS_NO_CTRY_CODE 398
+#define ERROR_NO_COUNTRY_OR_CODEPAGE 398
+#define ERROR_NLS_TABLE_TRUNCATED 399
+#define ERROR_NLS_BAD_TYPE 400
+#define ERROR_NLS_TYPE_NOT_FOUND 401
+#define ERROR_VIO_SMG_ONLY 402
+#define ERROR_VIO_INVALID_ASCIIZ 403
+#define ERROR_VIO_DEREGISTER 404
+#define ERROR_VIO_NO_POPUP 405
+#define ERROR_VIO_EXISTING_POPUP 406
+#define ERROR_KBD_SMG_ONLY 407
+#define ERROR_KBD_INVALID_ASCIIZ 408
+#define ERROR_KBD_INVALID_MASK 409
+#define ERROR_KBD_REGISTER 410
+#define ERROR_KBD_DEREGISTER 411
+#define ERROR_MOUSE_SMG_ONLY 412
+#define ERROR_MOUSE_INVALID_ASCIIZ 413
+#define ERROR_MOUSE_INVALID_MASK 414
+#define ERROR_MOUSE_REGISTER 415
+#define ERROR_MOUSE_DEREGISTER 416
+#define ERROR_SMG_BAD_ACTION 417
+#define ERROR_SMG_INVALID_CALL 418
+#define ERROR_SCS_SG_NOTFOUND 419
+#define ERROR_SCS_NOT_SHELL 420
+#define ERROR_VIO_INVALID_PARMS 421
+#define ERROR_VIO_FUNCTION_OWNED 422
+#define ERROR_VIO_RETURN 423
+#define ERROR_SCS_INVALID_FUNCTION 424
+#define ERROR_SCS_NOT_SESSION_MGR 425
+#define ERROR_VIO_REGISTER 426
+#define ERROR_VIO_NO_MODE_THREAD 427
+#define ERROR_VIO_NO_SAVE_RESTORE_THD 428
+#define ERROR_VIO_IN_BG 429
+#define ERROR_VIO_ILLEGAL_DURING_POPUP 430
+#define ERROR_SMG_NOT_BASESHELL 431
+#define ERROR_SMG_BAD_STATUSREQ 432
+#define ERROR_QUE_INVALID_WAIT 433
+#define ERROR_VIO_LOCK 434
+#define ERROR_MOUSE_INVALID_IOWAIT 435
+#define ERROR_VIO_INVALID_HANDLE 436
+#define ERROR_VIO_ILLEGAL_DURING_LOCK 437
+#define ERROR_VIO_INVALID_LENGTH 438
+#define ERROR_KBD_INVALID_HANDLE 439
+#define ERROR_KBD_NO_MORE_HANDLE 440
+#define ERROR_KBD_CANNOT_CREATE_KCB 441
+#define ERROR_KBD_CODEPAGE_LOAD_INCOMPL 442
+#define ERROR_KBD_INVALID_CODEPAGE_ID 443
+#define ERROR_KBD_NO_CODEPAGE_SUPPORT 444
+#define ERROR_KBD_FOCUS_REQUIRED 445
+#define ERROR_KBD_FOCUS_ALREADY_ACTIVE 446
+#define ERROR_KBD_KEYBOARD_BUSY 447
+#define ERROR_KBD_INVALID_CODEPAGE 448
+#define ERROR_KBD_UNABLE_TO_FOCUS 449
+#define ERROR_SMG_SESSION_NON_SELECT 450
+#define ERROR_SMG_SESSION_NOT_FOREGRND 451
+#define ERROR_SMG_SESSION_NOT_PARENT 452
+#define ERROR_SMG_INVALID_START_MODE 453
+#define ERROR_SMG_INVALID_RELATED_OPT 454
+#define ERROR_SMG_INVALID_BOND_OPTION 455
+#define ERROR_SMG_INVALID_SELECT_OPT 456
+#define ERROR_SMG_START_IN_BACKGROUND 457
+#define ERROR_SMG_INVALID_STOP_OPTION 458
+#define ERROR_SMG_BAD_RESERVE 459
+#define ERROR_SMG_PROCESS_NOT_PARENT 460
+#define ERROR_SMG_INVALID_DATA_LENGTH 461
+#define ERROR_SMG_NOT_BOUND 462
+#define ERROR_SMG_RETRY_SUB_ALLOC 463
+#define ERROR_KBD_DETACHED 464
+#define ERROR_VIO_DETACHED 465
+#define ERROR_MOU_DETACHED 466
+#define ERROR_VIO_FONT 467
+#define ERROR_VIO_USER_FONT 468
+#define ERROR_VIO_BAD_CP 469
+#define ERROR_VIO_NO_CP 470
+#define ERROR_VIO_NA_CP 471
+#define ERROR_INVALID_CODE_PAGE 472
+#define ERROR_CPLIST_TOO_SMALL 473
+#define ERROR_CP_NOT_MOVED 474
+#define ERROR_MODE_SWITCH_INIT 475
+#define ERROR_CODE_PAGE_NOT_FOUND 476
+#define ERROR_UNEXPECTED_SLOT_RETURNED 477
+#define ERROR_SMG_INVALID_TRACE_OPTION 478
+#define ERROR_VIO_INTERNAL_RESOURCE 479
+#define ERROR_VIO_SHELL_INIT 480
+#define ERROR_SMG_NO_HARD_ERRORS 481
+#define ERROR_CP_SWITCH_INCOMPLETE 482
+#define ERROR_VIO_TRANSPARENT_POPUP 483
+#define ERROR_CRITSEC_OVERFLOW 484
+#define ERROR_CRITSEC_UNDERFLOW 485
+#define ERROR_VIO_BAD_RESERVE 486
+#define ERROR_INVALID_ADDRESS 487
+#define ERROR_ZERO_SELECTORS_REQUESTED 488
+#define ERROR_NOT_ENOUGH_SELECTORS_AVA 489
+#define ERROR_INVALID_SELECTOR 490
+#define ERROR_SMG_INVALID_PROGRAM_TYPE 491
+#define ERROR_SMG_INVALID_PGM_CONTROL 492
+#define ERROR_SMG_INVALID_INHERIT_OPT 493
+#define ERROR_VIO_EXTENDED_SG 494
+#define ERROR_VIO_NOT_PRES_MGR_SG 495
+#define ERROR_VIO_SHIELD_OWNED 496
+#define ERROR_VIO_NO_MORE_HANDLES 497
+#define ERROR_VIO_SEE_ERROR_LOG 498
+#define ERROR_VIO_ASSOCIATED_DC 499
+#define ERROR_KBD_NO_CONSOLE 500
+#define ERROR_MOUSE_NO_CONSOLE 501
+#define ERROR_MOUSE_INVALID_HANDLE 502
+#define ERROR_SMG_INVALID_DEBUG_PARMS 503
+#define ERROR_KBD_EXTENDED_SG 504
+#define ERROR_MOU_EXTENDED_SG 505
+#define ERROR_SMG_INVALID_ICON_FILE 506
+
+
+#define ERROR_USER_DEFINED_BASE 0xFF00
+
+#define ERROR_I24_WRITE_PROTECT 0
+#define ERROR_I24_BAD_UNIT 1
+#define ERROR_I24_NOT_READY 2
+#define ERROR_I24_BAD_COMMAND 3
+#define ERROR_I24_CRC 4
+#define ERROR_I24_BAD_LENGTH 5
+#define ERROR_I24_SEEK 6
+#define ERROR_I24_NOT_DOS_DISK 7
+#define ERROR_I24_SECTOR_NOT_FOUND 8
+#define ERROR_I24_OUT_OF_PAPER 9
+#define ERROR_I24_WRITE_FAULT 10
+#define ERROR_I24_READ_FAULT 11
+#define ERROR_I24_GEN_FAILURE 12
+#define ERROR_I24_DISK_CHANGE 13
+#define ERROR_I24_WRONG_DISK 15
+#define ERROR_I24_UNCERTAIN_MEDIA 16
+#define ERROR_I24_CHAR_CALL_INTERRUPTED 17
+#define ERROR_I24_NO_MONITOR_SUPPORT 18
+#define ERROR_I24_INVALID_PARAMETER 19
+#define ERROR_I24_DEVICE_IN_USE 20
+
+#define ALLOWED_FAIL 0x0001
+#define ALLOWED_ABORT 0x0002
+#define ALLOWED_RETRY 0x0004
+#define ALLOWED_IGNORE 0x0008
+#define ALLOWED_ACKNOWLEDGE 0x0010
+#define ALLOWED_DISPATCH 0x8000
+
+#define I24_OPERATION 0x01
+#define I24_AREA 0x06
+#define I24_CLASS 0x80
+
+/* Values for error CLASS */
+#define ERRCLASS_OUTRES 1 /* Out of Resource */
+#define ERRCLASS_TEMPSIT 2 /* Temporary Situation */
+#define ERRCLASS_AUTH 3 /* Permission problem */
+#define ERRCLASS_INTRN 4 /* Internal System Error */
+#define ERRCLASS_HRDFAIL 5 /* Hardware Failure */
+#define ERRCLASS_SYSFAIL 6 /* System Failure */
+#define ERRCLASS_APPERR 7 /* Application Error */
+#define ERRCLASS_NOTFND 8 /* Not Found */
+#define ERRCLASS_BADFMT 9 /* Bad Format */
+#define ERRCLASS_LOCKED 10 /* Locked */
+#define ERRCLASS_MEDIA 11 /* Media Failure */
+#define ERRCLASS_ALREADY 12 /* Collision with Existing Item */
+#define ERRCLASS_UNK 13 /* Unknown/other */
+#define ERRCLASS_CANT 14
+#define ERRCLASS_TIME 15
+
+/* Values for error ACTION */
+#define ERRACT_RETRY 1 /* Retry */
+#define ERRACT_DLYRET 2 /* Delay Retry, retry after pause */
+#define ERRACT_USER 3 /* Ask user to regive information */
+#define ERRACT_ABORT 4 /* abort with clean up */
+#define ERRACT_PANIC 5 /* abort immediately */
+#define ERRACT_IGNORE 6 /* ignore */
+#define ERRACT_INTRET 7 /* Retry after User Intervention */
+
+/* Values for error LOCUS */
+#define ERRLOC_UNK 1 /* No appropriate value */
+#define ERRLOC_DISK 2 /* Random Access Mass Storage */
+#define ERRLOC_NET 3 /* Network */
+#define ERRLOC_SERDEV 4 /* Serial Device */
+#define ERRLOC_MEM 5 /* Memory */
+
+/* Abnormal termination codes */
+#define TC_NORMAL 0
+#define TC_HARDERR 1
+#define TC_GP_TRAP 2
+#define TC_SIGNAL 3
+
+#define ERROR_SWAPPER_NOT_ACTIVE 32768
+#define ERROR_INVALID_SWAPID 32769
+#define ERROR_IOERR_SWAP_FILE 32770
+#define ERROR_SWAP_TABLE_FULL 32771
+#define ERROR_SWAP_FILE_FULL 32772
+#define ERROR_CANT_INIT_SWAPPER 32773
+#define ERROR_SWAPPER_ALREADY_INIT 32774
+#define ERROR_PMM_INSUFFICIENT_MEMORY 32775
+#define ERROR_PMM_INVALID_FLAGS 32776
+#define ERROR_PMM_INVALID_ADDRESS 32777
+#define ERROR_PMM_LOCK_FAILED 32778
+#define ERROR_PMM_UNLOCK_FAILED 32779
+#define ERROR_PMM_MOVE_INCOMPLETE 32780
+#define ERROR_UCOM_DRIVE_RENAMED 32781
+#define ERROR_UCOM_FILENAME_TRUNCATED 32782
+#define ERROR_UCOM_BUFFER_LENGTH 32783
+#define ERROR_MON_CHAIN_HANDLE 32784
+#define ERROR_MON_NOT_REGISTERED 32785
+#define ERROR_SMG_ALREADY_TOP 32786
+#define ERROR_PMM_ARENA_MODIFIED 32787
+#define ERROR_SMG_PRINTER_OPEN 32788
+#define ERROR_PMM_SET_FLAGS_FAILED 32789
+#define ERROR_INVALID_DOS_DD 32790
+#define ERROR_CPSIO_CODE_PAGE_INVALID 65026
+#define ERROR_CPSIO_NO_SPOOLER 65027
+#define ERROR_CPSIO_FONT_ID_INVALID 65028
+#define ERROR_CPSIO_INTERNAL_ERROR 65033
+#define ERROR_CPSIO_INVALID_PTR_NAME 65034
+#define ERROR_CPSIO_NOT_ACTIVE 65037
+#define ERROR_CPSIO_PID_FULL 65039
+#define ERROR_CPSIO_PID_NOT_FOUND 65040
+#define ERROR_CPSIO_READ_CTL_SEQ 65043
+#define ERROR_CPSIO_READ_FNT_DEF 65045
+#define ERROR_CPSIO_WRITE_ERROR 65047
+#define ERROR_CPSIO_WRITE_FULL_ERROR 65048
+#define ERROR_CPSIO_WRITE_HANDLE_BAD 65049
+#define ERROR_CPSIO_SWIT_LOAD 65074
+#define ERROR_CPSIO_INV_COMMAND 65077
+#define ERROR_CPSIO_NO_FONT_SWIT 65078
+
+#endif
diff --git a/private/mvdm/wow16/wfwnet/ints.asm b/private/mvdm/wow16/wfwnet/ints.asm
new file mode 100644
index 000000000..d605402ac
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/ints.asm
@@ -0,0 +1,145 @@
+include isvbop.inc
+
+.286
+.model medium,pascal
+
+_DATA segment word public 'DATA'
+
+Old2fHandler dd ?
+Old73Handler dd ?
+VddHandle dw -1
+
+DllName db "VWIPXSPX.DLL",0
+InitFunc db "VwInitialize",0
+DispFunc db "VwDispatcher",0
+
+_DATA ends
+
+INIT_TEXT segment byte public 'CODE'
+
+ assume cs:INIT_TEXT
+
+GrabInterrupts proc far
+ pusha
+ push ds
+ push es
+ push _DATA
+ pop ds
+ assume ds:_DATA
+ push ds
+ pop es
+ mov si,offset DllName ; ds:si = library name
+ mov di,offset InitFunc ; es:di = init function name
+ mov bx,offset DispFunc ; ds:bx = dispatcher function name
+ RegisterModule ; returns carry if problem
+ jc @f
+ mov VddHandle,ax
+ mov ax,352fh
+ int 21h
+ mov word ptr Old2fHandler,bx
+ mov word ptr Old2fHandler+2,es
+ mov ax,3573h
+ int 21h
+ mov word ptr Old73Handler,bx
+ mov word ptr Old73Handler+2,es
+ push seg PmIpx2fHandler
+ pop ds
+ assume ds:nothing
+ mov dx,offset PmIpx2fHandler
+ mov ax,252fh
+ int 21h
+ mov dx,offset PmIpx73Handler
+ mov ax,2573h
+ int 21h
+@@: pop es
+ pop ds
+ popa
+ ret
+GrabInterrupts endp
+
+INIT_TEXT ends
+
+_TEXT segment byte public 'CODE'
+
+ assume cs:_TEXT
+
+ public PmIpx2fHandler
+PmIpx2fHandler proc
+ cmp ax,1684h
+ jne @f
+ cmp bx,200h
+ jne @f
+ push cs
+ pop es
+ mov di,offset PmIpxEntryPoint
+ iret
+@@: push bp
+ mov bp,sp
+ push ax
+ push ds
+ mov ax,_DATA
+ mov ds,ax
+ assume ds:_DATA
+ push word ptr Old2fHandler+2
+ push word ptr Old2fHandler
+ mov ds,[bp-4]
+ mov ax,[bp-2]
+ mov bp,[bp]
+ retf 6
+PmIpx2fHandler endp
+
+ public PmIpx73Handler
+PmIpx73Handler proc
+ push ds
+ push es
+ pusha
+ mov bx,_DATA
+ mov ds,bx
+ assume ds:_DATA
+ mov ax,VddHandle
+ mov bx,-2
+ DispatchCall ; get ECB
+ jc @f
+ call dword ptr es:[si][4] ; branch to the ESR
+ mov al,20h
+ out 0a0h,al ; clear slave pic
+ out 20h,al ; " master "
+ popa
+ pop es
+ pop ds
+ assume ds:nothing
+ iret
+@@: popa
+ pop es
+ push bp
+ mov bp,sp
+ push _DATA
+ pop ds
+ assume ds:_DATA
+ push word ptr Old73Handler+2
+ push word ptr Old73Handler
+ mov ds,[bp+2]
+ assume ds:nothing
+ mov bp,[bp]
+ retf 4
+PmIpx73Handler endp
+
+ public PmIpxEntryPoint
+PmIpxEntryPoint proc
+ push bp
+ push ds
+ push _DATA
+ pop ds
+ assume ds:_DATA
+ mov bp,ax
+ mov ax,VddHandle
+ pop ds
+ assume ds:nothing
+ DispatchCall
+ pop bp
+ ret
+PmIpxEntryPoint endp
+
+_TEXT ends
+
+end
diff --git a/private/mvdm/wow16/wfwnet/lfn.c b/private/mvdm/wow16/wfwnet/lfn.c
new file mode 100644
index 000000000..a8996cb08
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/lfn.c
@@ -0,0 +1,162 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ lfn.c
+
+Abstract:
+
+ Provides entry points for the Long Name Functions from Win3.1
+ Network provider design.
+
+ All functions return WN_NOT_SUPPORTED
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+--*/
+
+#include <windows.h>
+#include <locals.h>
+
+
+WORD API LFNFindFirst(LPSTR p1,
+ WORD p2,
+ LPINT p3,
+ LPINT p4,
+ WORD p5,
+ PFILEFINDBUF2 p6)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ UNREFERENCED(p4) ;
+ UNREFERENCED(p5) ;
+ UNREFERENCED(p6) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNFindNext(HANDLE p1,
+ LPINT p2,
+ WORD p3,
+ PFILEFINDBUF2 p4)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ UNREFERENCED(p4) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNFindClose(HANDLE p1)
+{
+ UNREFERENCED(p1) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNGetAttributes(LPSTR p1,
+ LPINT p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNSetAttributes(LPSTR p1,
+ WORD p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNCopy(LPSTR p1,
+ LPSTR p2,
+ PQUERYPROC p3)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNMove(LPSTR p1,
+ LPSTR p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNDelete(LPSTR p1)
+{
+ UNREFERENCED(p1) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNMKDir(LPSTR p1)
+{
+ UNREFERENCED(p1) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNRMDir(LPSTR p1)
+{
+ UNREFERENCED(p1) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNGetVolumeLabel(WORD p1,
+ LPSTR p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNSetVolumeLabel(WORD p1,
+ LPSTR p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNParse(LPSTR p1,
+ LPSTR p2,
+ LPSTR p3)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API LFNVolumeType(WORD p1,
+ LPINT p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
diff --git a/private/mvdm/wow16/wfwnet/libentry.asm b/private/mvdm/wow16/wfwnet/libentry.asm
new file mode 100644
index 000000000..b75d0cb9e
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/libentry.asm
@@ -0,0 +1,83 @@
+PAGE,132
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;
+; LIBENTRY.ASM
+;
+; Windows dynamic link library entry routine
+;
+; This module generates a code segment called INIT_TEXT.
+; It initializes the local heap if one exists and then calls
+; the C routine LibMain() which should have the form:
+; BOOL FAR PASCAL LibMain(HANDLE hInstance,
+; WORD wDataSeg,
+; WORD cbHeap,
+; DWORD ignore); /* Always NULL - ignore */
+;
+; The result of the call to LibMain is returned to Windows.
+; The C routine should return TRUE if it completes initialization
+; successfully, FALSE if some error occurs.
+;
+; Note - The last parameter to LibMain is included for compatibility
+; reasons. Applications that wish to modify this file and remove the
+; parameter from LibMain may do so by simply removing the two
+; "push" instructions below marked with "****".
+;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+include cmacros.inc
+
+externFP <LibMain> ; the C routine to be called
+
+createSeg INIT_TEXT, INIT_TEXT, BYTE, PUBLIC, CODE
+sBegin INIT_TEXT
+assumes CS,INIT_TEXT
+
+?PLM=0 ; 'C'naming
+;externA <_acrtused> ; ensures that Win DLL startup code is linked
+
+?PLM=1 ; 'PASCAL' naming
+externFP <LocalInit> ; Windows heap init routine
+
+cProc LibEntry, <PUBLIC,FAR> ; entry point into DLL
+
+include CONVDLL.INC
+
+cBegin
+ push di ; handle of the module instance
+ push ds ; library data segment
+ push cx ; heap size
+ push es ; Always NULL **** May remove (see above)
+ push si ; Always NULL **** May remove (see above)
+
+ ; if we have some heap then initialize it
+ jcxz callc ; jump if no heap specified
+
+ ; call the Windows function LocalInit() to set up the heap
+ ; LocalInit((LPSTR)start, WORD cbHeap);
+
+ xor ax,ax
+ cCall LocalInit <ds, ax, cx>
+ or ax,ax ; did it do it ok ?
+ jz error ; quit if it failed
+
+ ; invoke the C routine to do any special initialization
+
+callc:
+ call LibMain ; invoke the 'C' routine (result in AX)
+ jmp short exit ; LibMain is responsible for stack clean up
+
+error:
+ pop si ; clean up stack on a LocalInit error
+ pop es
+ pop cx
+ pop ds
+ pop di
+
+exit:
+
+cEnd
+
+sEnd INIT_TEXT
+
+end LibEntry
+
diff --git a/private/mvdm/wow16/wfwnet/locals.h b/private/mvdm/wow16/wfwnet/locals.h
new file mode 100644
index 000000000..62c80808d
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/locals.h
@@ -0,0 +1,153 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ locals.h
+
+Abstract:
+
+ Provides the common definitions for this project.
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+
+--*/
+
+#define LFN 1
+#include <winnet.h>
+#include <wfwnet.h>
+#include <spl_wnt.h>
+#include <bseerr.h>
+
+/*
+ * global manifests
+ */
+
+//
+// used to figure out how to get the last error.
+//
+#define LAST_CALL_IS_LOCAL (0)
+#define LAST_CALL_IS_LANMAN_DRV (1)
+#define LAST_CALL_IS_WIN32 (2)
+
+//
+// the various DLLs we rely on to do the real work.
+//
+#define LANMAN_DRV "LANMAN.DRV"
+#define MPR_DLL "MPR.DLL"
+#define MPRUI_DLL "MPRUI.DLL"
+#define NTLANMAN_DLL "NTLANMAN.DLL"
+#define KERNEL32_DLL "KERNEL32.DLL"
+#define WINSPOOL_DRV "WINSPOOL.DRV"
+
+//
+// some convenient manifests for above so we dont need to
+// do strcmp()s all the time.
+//
+#define USE_MPR_DLL (0)
+#define USE_MPRUI_DLL (1)
+#define USE_NTLANMAN_DLL (2)
+#define USE_KERNEL32_DLL (3)
+#define USE_WINSPOOL_DRV (4)
+
+//
+// resource type expected by Win32 APIs
+//
+#define RESOURCETYPE_ANY 0x00000000
+#define RESOURCETYPE_DISK 0x00000001
+#define RESOURCETYPE_PRINT 0x00000002
+#define RESOURCETYPE_ERROR 0xFFFFFFFF
+
+//
+// errors unknown in 16bit world.
+//
+#define WIN32_EXTENDED_ERROR 1208L
+#define WIN32_WN_CANCEL 1223L
+
+//
+// misc convenient macros
+//
+#define UNREFERENCED(x) (void)x
+#define TO_HWND32(x) (0xFFFF0000 | (DWORD)x)
+
+
+/*
+ * various typedefs for the 16 bit functions we dynamically load
+ */
+typedef void (API *LPFN)();
+typedef WORD (API *LPWNETOPENJOB)(LPSTR,LPSTR,WORD,LPINT);
+typedef WORD (API *LPWNETCLOSEJOB)(WORD,LPINT,LPSTR);
+typedef WORD (API *LPWNETWRITEJOB)(HANDLE,LPSTR,LPINT);
+typedef WORD (API *LPWNETABORTJOB)(WORD,LPSTR);
+typedef WORD (API *LPWNETHOLDJOB)(LPSTR,WORD);
+typedef WORD (API *LPWNETRELEASEJOB)(LPSTR,WORD);
+typedef WORD (API *LPWNETCANCELJOB)(LPSTR,WORD);
+typedef WORD (API *LPWNETSETJOBCOPIES)(LPSTR,WORD,WORD);
+typedef WORD (API *LPWNETWATCHQUEUE)(HWND,LPSTR,LPSTR,WORD);
+typedef WORD (API *LPWNETUNWATCHQUEUE)(LPSTR);
+typedef WORD (API *LPWNETLOCKQUEUEDATA)(LPSTR,LPSTR,LPQUEUESTRUCT FAR *);
+typedef WORD (API *LPWNETUNLOCKQUEUEDATA)(LPSTR);
+typedef WORD (API *LPWNETQPOLL)(HWND,WORD,WORD,LONG);
+typedef WORD (API *LPWNETDEVICEMODE)(HWND);
+typedef WORD (API *LPWNETVIEWQUEUEDIALOG)(HWND,LPSTR);
+typedef WORD (API *LPWNETGETCAPS)(WORD);
+typedef WORD (API *LPWNETGETERROR)(LPINT);
+typedef WORD (API *LPWNETGETERRORTEXT)(WORD,LPSTR,LPINT);
+
+typedef WORD (API *LPLFNFINDFIRST)(LPSTR,WORD,LPINT,LPINT,WORD,PFILEFINDBUF2);
+typedef WORD (API *LPLFNFINDNEXT)(HANDLE,LPINT,WORD,PFILEFINDBUF2);
+typedef WORD (API *LPLFNFINDCLOSE)(HANDLE);
+typedef WORD (API *LPLFNGETATTRIBUTES)(LPSTR,LPINT);
+typedef WORD (API *LPLFNSETATTRIBUTES)(LPSTR,WORD);
+typedef WORD (API *LPLFNCOPY)(LPSTR,LPSTR,PQUERYPROC);
+typedef WORD (API *LPLFNMOVE)(LPSTR,LPSTR);
+typedef WORD (API *LPLFNDELETE)(LPSTR);
+typedef WORD (API *LPLFNMKDIR)(LPSTR);
+typedef WORD (API *LPLFNRMDIR)(LPSTR);
+typedef WORD (API *LPLFNGETVOLUMELABEL)(WORD,LPSTR);
+typedef WORD (API *LPLFNSETVOLUMELABEL)(WORD,LPSTR);
+typedef WORD (API *LPLFNPARSE)(LPSTR,LPSTR,LPSTR);
+typedef WORD (API *LPLFNVOLUMETYPE)(WORD,LPINT);
+
+/*
+ * other misc global data/functions
+ */
+extern WORD vLastCall ;
+extern WORD vLastError ;
+extern WORD wNetTypeCaps ;
+extern WORD wUserCaps ;
+extern WORD wConnectionCaps ;
+extern WORD wErrorCaps ;
+extern WORD wDialogCaps ;
+extern WORD wAdminCaps ;
+extern WORD wSpecVersion;
+extern WORD wDriverVersion;
+
+WORD API WNetGetCaps16(WORD p1) ;
+WORD API WNetGetError16(LPINT p1) ;
+WORD API WNetGetErrorText16(WORD p1, LPSTR p2, LPINT p3) ;
+
+DWORD API GetLastError32(VOID) ;
+
+WORD SetLastError(WORD err) ;
+
+DWORD MapWNType16To32(WORD nType) ;
+WORD MapWin32ErrorToWN16(DWORD err) ;
+WORD GetLanmanDrvEntryPoints(LPFN *lplpfn,
+ LPSTR lpName) ;
+//
+// we define this because the silly compiler chokes if we add yet
+// more to the include path to get to lmerr.h.
+//
+// this is not that bad since the value below will never change.
+//
+
+#define NERR_BASE 2100
+#define NERR_UseNotFound (NERR_BASE+150)
diff --git a/private/mvdm/wow16/wfwnet/makefile b/private/mvdm/wow16/wfwnet/makefile
new file mode 100644
index 000000000..6970c774f
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/makefile
@@ -0,0 +1,140 @@
+# wfwnet.drv makefile
+#
+# Copyright (c) 1991-1993 Microsoft Corporation
+#
+# History:
+# Created 25-Mar-1993 Chuck Y. Chan (ChuckC)
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .dll .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I. -I..\inc -I..\..\inc -I$(_NTBINDIR)\public\sdk\inc
+!endif
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS) -DBUILDDLL
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\snocrtd.lib
+
+!IF "$(QFE_BUILD)" != "1"
+CL16=cl16
+!ELSE
+CL16=cl
+!ENDIF
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ $(CL16) -c -nologo $(CW16) $*.c
+
+.c.lst:
+ $(CL16) -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 $(INCS) -r $*.rc
+
+
+all: wfwnet.drv wfwnet.sym
+ -binplace wfwnet.drv wfwnet.sym wfwnet.map
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+
+wfwnet.obj: wfwnet.c ..\..\inc\wow.inc ..\inc\winnet.h ..\inc\wfwnet.h \
+ .\locals.h .\bseerr.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+print.obj: print.c ..\..\inc\wow.inc ..\inc\winnet.h ..\inc\wfwnet.h \
+ ..\inc\spl_wnt.h .\locals.h .\bseerr.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+misc.obj: misc.c ..\..\inc\wow.inc ..\inc\winnet.h ..\inc\wfwnet.h \
+ .\locals.h .\bseerr.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+to32.obj: to32.c ..\..\inc\wow.inc ..\inc\winnet.h ..\inc\wfwnet.h \
+ .\locals.h .\bseerr.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+lfn.obj: lfn.c ..\..\inc\wow.inc ..\inc\winnet.h ..\inc\wfwnet.h \
+ .\locals.h .\bseerr.h
+ $(CL16) -c -nologo $(CW16) $*.c
+
+wfwnet.lrf: makefile
+ echo wfwnet.obj+ >wfwnet.lrf
+ echo to32.obj+ >>wfwnet.lrf
+ echo print.obj+ >>wfwnet.lrf
+ echo misc.obj+ >>wfwnet.lrf
+ echo lfn.obj+ >>wfwnet.lrf
+ echo libentry.obj+ >>wfwnet.lrf
+ echo ints.obj >>wfwnet.lrf
+ echo wfwnet.drv>>wfwnet.lrf
+ echo wfwnet $(LINK)>>wfwnet.lrf
+ echo ..\lib\libw.lib /nod>>wfwnet.lrf
+ echo wfwnet;>>wfwnet.lrf
+
+wfwnet.res: $*.rc $*.rcv ..\inc\common.ver
+
+wfwnet.drv: ints.obj libentry.obj wfwnet.obj to32.obj lfn.obj print.obj misc.obj wfwnet.lrf wfwnet.def wfwnet.res
+ link16 @wfwnet.lrf;
+ rc16 -t wfwnet.res wfwnet.drv
+
+!ENDIF
diff --git a/private/mvdm/wow16/wfwnet/misc.c b/private/mvdm/wow16/wfwnet/misc.c
new file mode 100644
index 000000000..def754915
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/misc.c
@@ -0,0 +1,265 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ misc.c
+
+Abstract:
+
+ Provides entry points for miscellaneous functions to match the WFW3.1
+ Network provider,
+
+ The majority of the functions are either no longer supported, or
+ call thru to other functions.
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+--*/
+#include <windows.h>
+#include <locals.h>
+
+
+WORD API WNetExitConfirm(HWND hwndOwner,
+ WORD iExitType)
+{
+ UNREFERENCED(hwndOwner) ;
+ UNREFERENCED(hwndOwner) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+BOOL API I_AutoLogon(HWND hwndOwner,
+ LPSTR lpszReserved,
+ BOOL fPrompt,
+ BOOL FAR *lpfLoggedOn)
+{
+ UNREFERENCED(hwndOwner) ;
+ UNREFERENCED(lpszReserved) ;
+ UNREFERENCED(fPrompt) ;
+ UNREFERENCED(lpfLoggedOn) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return FALSE ;
+}
+
+BOOL API I_Logoff(HWND hwndOwner,
+ LPSTR lpszReserved)
+{
+ UNREFERENCED(hwndOwner) ;
+ UNREFERENCED(lpszReserved) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return FALSE ;
+}
+
+VOID API I_ChangePassword(HWND hwndOwner)
+{
+ UNREFERENCED(hwndOwner) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+}
+
+VOID API I_ChangeCachePassword(HWND hwndOwner)
+{
+ UNREFERENCED(hwndOwner) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+}
+
+WORD API I_ConnectDialog(HWND hwndParent,
+ WORD iType)
+{
+ return WNetConnectDialog(hwndParent, iType) ;
+}
+
+WORD API I_ConnectionDialog(HWND hwndParent,
+ WORD iType)
+{
+ return WNetConnectDialog(hwndParent, iType) ;
+}
+
+WORD API WNetCachePassword(LPSTR pbResource,
+ WORD cbResource,
+ LPSTR pbPassword,
+ WORD cbPassword,
+ BYTE nType)
+{
+ UNREFERENCED(pbResource) ;
+ UNREFERENCED(cbResource) ;
+ UNREFERENCED(pbPassword) ;
+ UNREFERENCED(cbPassword) ;
+ UNREFERENCED(nType) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetCachedPassword(LPSTR pbResource,
+ WORD cbResource,
+ LPSTR pbPassword,
+ LPWORD pcbPassword,
+ BYTE nType)
+{
+ UNREFERENCED(pbResource) ;
+ UNREFERENCED(cbResource) ;
+ UNREFERENCED(pbPassword) ;
+ UNREFERENCED(pcbPassword) ;
+ UNREFERENCED(nType) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+
+WORD API WNetRemoveCachedPassword(LPSTR pbResource,
+ WORD cbResource,
+ BYTE nType)
+{
+ UNREFERENCED(pbResource) ;
+ UNREFERENCED(cbResource) ;
+ UNREFERENCED(nType) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetEnumCachedPasswords(LPSTR pbPrefix,
+ WORD cbPrefix,
+ BYTE nType,
+ CACHECALLBACK pfnCallback)
+{
+ UNREFERENCED(pbPrefix) ;
+ UNREFERENCED(cbPrefix) ;
+ UNREFERENCED(nType) ;
+ UNREFERENCED(pfnCallback) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetSharesDialog(HWND hwndParent,
+ WORD iType)
+{
+ UNREFERENCED(hwndParent) ;
+ UNREFERENCED(iType) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetSetDefaultDrive(WORD idriveDefault)
+{
+ UNREFERENCED(idriveDefault) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetShareCount(WORD iType)
+{
+ UNREFERENCED(iType) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetShareName(LPSTR lpszPath,
+ LPSTR lpszBuf,
+ WORD cbBuf)
+{
+ UNREFERENCED(lpszPath) ;
+ UNREFERENCED(lpszBuf) ;
+ UNREFERENCED(cbBuf) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetSharePath(LPSTR lpszName,
+ LPSTR lpszBuf,
+ WORD cbBuf)
+{
+ UNREFERENCED(lpszName) ;
+ UNREFERENCED(lpszBuf) ;
+ UNREFERENCED(cbBuf) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetLastConnection(WORD iType,
+ LPWORD lpwConnIndex)
+{
+ UNREFERENCED(iType) ;
+ UNREFERENCED(lpwConnIndex) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WORD API WNetGetError(LPINT p1)
+{
+ WORD err ;
+ WORD wLastErr ;
+
+ /*
+ * fake the last error capabilty. if last thing we talked to was Win32,
+ * the get the information from 32 bit system. ditto if it was a Win16
+ * call.
+ */
+ if (vLastCall == LAST_CALL_IS_WIN32)
+ {
+ err = (WORD) GetLastError32() ;
+ return err ;
+ }
+ else if (vLastCall == LAST_CALL_IS_LANMAN_DRV)
+ {
+ err = WNetGetError16(&wLastErr) ;
+ if (err != WN_SUCCESS)
+ return err ;
+ else
+ return wLastErr ;
+ }
+ else
+ {
+ return(vLastError) ;
+ }
+}
+
+WORD API WNetGetErrorText(WORD p1,LPSTR p2,LPINT p3)
+{
+ if (vLastCall == LAST_CALL_IS_WIN32)
+ {
+ *p2 = 0 ;
+ *p3 = 0 ;
+ return WN_NOT_SUPPORTED ;
+ }
+ else // use whatever lanman.drv gives us
+ {
+ return (WNetGetErrorText16(p1, p2, p3)) ;
+ }
+}
+
+WORD API WNetErrorText(WORD p1,LPSTR p2,WORD p3)
+{
+ WORD cbBuffer = p3 ;
+
+ return (WNetGetErrorText(p1, p2, &cbBuffer) == 0) ;
+}
+
+/*
+ * misc startup/shutdown routines. nothing interesting
+ */
+
+VOID FAR PASCAL Enable(VOID)
+{
+ return ;
+}
+
+VOID FAR PASCAL Disable(VOID)
+{
+ return ;
+}
+
+int far pascal WEP()
+{
+ return 0 ;
+}
+
diff --git a/private/mvdm/wow16/wfwnet/print.c b/private/mvdm/wow16/wfwnet/print.c
new file mode 100644
index 000000000..44efe5b15
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/print.c
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ print.c
+
+Abstract:
+
+ Provides entry points for the Print Functions from Win3.1
+ Network provider design.
+
+ All functions are obsolete. They either return WN_NOT_SUPPORTED
+ or FALSE.
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+--*/
+#include <windows.h>
+#include <locals.h>
+
+
+void API WNetPrintMgrSelNotify (BYTE p1,
+ LPQS2 p2,
+ LPQS2 p3,
+ LPJOBSTRUCT2 p4,
+ LPJOBSTRUCT2 p5,
+ LPWORD p6,
+ LPSTR p7,
+ WORD p8)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ UNREFERENCED(p4) ;
+ UNREFERENCED(p5) ;
+ UNREFERENCED(p6) ;
+ UNREFERENCED(p7) ;
+ UNREFERENCED(p8) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return ;
+}
+
+WNETERR API WNetPrintMgrPrinterEnum (LPSTR lpszQueueName,
+ LPSTR lpBuffer,
+ LPWORD pcbBuffer,
+ LPWORD cAvail,
+ WORD usLevel)
+{
+ UNREFERENCED(lpszQueueName) ;
+ UNREFERENCED(lpBuffer) ;
+ UNREFERENCED(pcbBuffer) ;
+ UNREFERENCED(cAvail) ;
+ UNREFERENCED(usLevel) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WNETERR API WNetPrintMgrChangeMenus(HWND p1,
+ HANDLE FAR *p2,
+ BOOL FAR *p3)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+WNETERR API WNetPrintMgrCommand (HWND p1,
+ WORD p2)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ return (SetLastError(WN_NOT_SUPPORTED)) ;
+}
+
+void API WNetPrintMgrExiting (void)
+{
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return ;
+}
+
+BOOL API WNetPrintMgrExtHelp (DWORD p1)
+{
+ UNREFERENCED(p1) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return FALSE ;
+}
+
+WORD API WNetPrintMgrMoveJob (HWND p1,
+ LPSTR p2,
+ WORD p3,
+ int p4)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ UNREFERENCED(p4) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return 0 ;
+}
+
+void API WNetPrintMgrStatusChange (LPSTR lpszQueueName,
+ LPSTR lpszPortName,
+ WORD wQueueStatus,
+ WORD cJobsLeft,
+ HANDLE hJCB,
+ BOOL fDeleted)
+{
+ UNREFERENCED(lpszQueueName) ;
+ UNREFERENCED(lpszPortName) ;
+ UNREFERENCED(wQueueStatus) ;
+ UNREFERENCED(cJobsLeft) ;
+ UNREFERENCED(hJCB) ;
+ UNREFERENCED(fDeleted) ;
+ vLastCall = LAST_CALL_IS_LOCAL ;
+ SetLastError(WN_NOT_SUPPORTED) ;
+ return ;
+}
+
diff --git a/private/mvdm/wow16/wfwnet/to32.c b/private/mvdm/wow16/wfwnet/to32.c
new file mode 100644
index 000000000..8192fc2de
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/to32.c
@@ -0,0 +1,1268 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ to32.c
+
+Abstract:
+
+ Provides entry points for the Functions from WFW3.1
+ Network provider design which are niw thunked to some
+ 32 bit equivalent.
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+--*/
+#include <windows.h>
+#include <locals.h>
+
+//
+// addresses to 32 bit entry points. note these cannot be
+// called directly. CallProc32W must be used,
+//
+LPVOID lpfnWNetAddConnection = NULL ;
+LPVOID lpfnWNetCancelConnection = NULL ;
+LPVOID lpfnWNetGetConnection = NULL ;
+LPVOID lpfnWNetRestoreConnection = NULL ;
+LPVOID lpfnWNetGetUser = NULL ;
+LPVOID lpfnWNetBrowseDialog = NULL ;
+LPVOID lpfnWNetConnectDialog = NULL ;
+LPVOID lpfnWNetDisconnectDialog = NULL ;
+LPVOID lpfnWNetConnectionDialog = NULL ;
+LPVOID lpfnWNetPropertyDialog = NULL ;
+LPVOID lpfnWNetGetPropertyText = NULL ;
+LPVOID lpfnWNetShareAsDialog = NULL ;
+LPVOID lpfnWNetStopShareDialog = NULL ;
+LPVOID lpfnWNetServerBrowseDialog = NULL ;
+LPVOID lpfnWNetGetDirectoryType = NULL ;
+LPVOID lpfnWNetDirectoryNotify = NULL ;
+LPVOID lpfnGetLastError32 = NULL ;
+LPVOID lpfnClosePrinter = NULL ;
+LPVOID lpfnConnectToPrinter = NULL ;
+
+//
+// forward declare
+//
+WORD Get32BitEntryPoints( LPVOID *lplpfn, DWORD dwDll, LPSTR lpProcName ) ;
+WORD API PrintConnectDialog(HWND p1) ;
+WORD GetAlignedMemory(LPVOID FAR *pAligned, HANDLE FAR *pHandle, WORD wSize) ;
+void FreeAlignedMemory(HANDLE handle) ;
+
+//
+// WNetAddConnection thunk to Win32
+//
+UINT API WNetAddConnection(LPSTR p1,LPSTR p2,LPSTR p3)
+{
+ WORD err ;
+ LPSTR aligned_p1 = NULL, aligned_p2 = NULL, aligned_p3 = NULL ;
+ HANDLE handle_p1 = NULL, handle_p2 = NULL, handle_p3 = NULL;
+
+ if (p1 == NULL || p3 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (p2 && (*p2 == '\0'))
+ p2 = NULL ;
+
+ if (!lpfnWNetAddConnection)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetAddConnection,
+ USE_MPR_DLL,
+ "WNetAddConnectionA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // make copy of parameters so that we are aligned (p1 & p3 wont be NULL)
+ //
+ if (err = GetAlignedMemory(&aligned_p1, &handle_p1, lstrlen(p1)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p1, p1) ;
+
+ if (err = GetAlignedMemory(&aligned_p3, &handle_p3, lstrlen(p3)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p3, p3) ;
+
+ if (p2)
+ {
+ if (err = GetAlignedMemory(&aligned_p2, &handle_p2, lstrlen(p2)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p2, p2) ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W(aligned_p1,
+ (DWORD)aligned_p2,
+ (DWORD)aligned_p3,
+ lpfnWNetAddConnection,
+ (DWORD)7,
+ (DWORD)3) ) ;
+ExitPoint:
+
+ FreeAlignedMemory(handle_p1) ;
+ FreeAlignedMemory(handle_p2) ;
+ FreeAlignedMemory(handle_p3) ;
+ return err ;
+}
+
+
+//
+// WNetCancelConnection thunk to Win32
+//
+UINT API WNetCancelConnection(LPSTR p1,BOOL p2)
+{
+ WORD err ;
+ LPSTR aligned_p1 = NULL ;
+ HANDLE handle_p1 = NULL ;
+
+ if (p1 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetCancelConnection)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetCancelConnection,
+ USE_MPR_DLL,
+ "WNetCancelConnectionA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // make copy of parameters so that we are aligned
+ //
+ if (err = GetAlignedMemory(&aligned_p1, &handle_p1, lstrlen(p1)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p1, p1) ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W(aligned_p1,
+ (DWORD)p2,
+ (DWORD)lpfnWNetCancelConnection,
+ (DWORD)2,
+ (DWORD)2) ) ;
+ExitPoint:
+
+ FreeAlignedMemory(handle_p1) ;
+ return err ;
+}
+
+//
+// WNetGetConnection thunk to Win32
+//
+UINT API WNetGetConnection(LPSTR p1,LPSTR p2, UINT FAR *p3)
+{
+ WORD err ;
+ LPSTR aligned_p1 = NULL, aligned_p2 = NULL ;
+ LPDWORD aligned_p3 = NULL ;
+ HANDLE handle_p1 = NULL, handle_p2 = NULL, handle_p3 = NULL;
+
+ if (p1 == NULL || p2 == NULL || p3 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetGetConnection)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetGetConnection,
+ USE_MPR_DLL,
+ "WNetGetConnectionA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // make copy of parameters so that we are aligned
+ //
+ if (err = GetAlignedMemory(&aligned_p1, &handle_p1, lstrlen(p1)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p1, p1) ;
+
+ if (err = GetAlignedMemory(&aligned_p2, &handle_p2, *p3 ? *p3 : 1))
+ goto ExitPoint ;
+
+ if (err = GetAlignedMemory(&aligned_p3, &handle_p3, sizeof(DWORD)))
+ goto ExitPoint ;
+ *aligned_p3 = *p3 ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W(aligned_p1,
+ (DWORD)aligned_p2,
+ (DWORD)aligned_p3,
+ lpfnWNetGetConnection,
+ (DWORD)7,
+ (DWORD)3) ) ;
+ lstrcpy(p2, aligned_p2) ;
+
+ if (err == WN_SUCCESS)
+ *p3 = lstrlen(p2) ;
+ else
+ *p3 = (UINT)*aligned_p3 ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_p1) ;
+ FreeAlignedMemory(handle_p2) ;
+ FreeAlignedMemory(handle_p3) ;
+ return err ;
+}
+
+UINT API WNetRestoreConnection(HWND p1,LPSTR p2)
+{
+ WORD err ;
+ LPSTR aligned_p2 = NULL ;
+ HANDLE handle_p2 = NULL ;
+
+ if (p2 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetRestoreConnection)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetRestoreConnection,
+ USE_MPRUI_DLL,
+ "WNetRestoreConnectionA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // guard against this weird case from Win3.0 days where -1
+ // means something special. NULL is close approximation -> ie all.
+ //
+ if (p2 == (LPSTR)-1)
+ p2 = NULL ;
+
+ if (p2)
+ {
+ if (err = GetAlignedMemory(&aligned_p2, &handle_p2, lstrlen(p2)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p2, p2) ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W((LPVOID)TO_HWND32(p1),
+ (DWORD)aligned_p2,
+ (DWORD)lpfnWNetRestoreConnection,
+ (DWORD)1,
+ (DWORD)2) ) ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_p2) ;
+ return err ;
+}
+
+WORD API WNetGetUser(LPSTR p1,LPINT p2)
+{
+ WORD err ;
+ LONG lTmp = *p2 ;
+ LPSTR aligned_p1 = NULL ;
+ LPINT aligned_p2 = NULL ;
+ HANDLE handle_p1 = NULL, handle_p2 = NULL ;
+
+ if (p1 == NULL || p2 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetGetUser)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetGetUser,
+ USE_MPR_DLL,
+ "WNetGetUserA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (err = GetAlignedMemory(&aligned_p1, &handle_p1, *p2))
+ goto ExitPoint ;
+
+ if (err = GetAlignedMemory(&aligned_p2, &handle_p2, sizeof(DWORD)))
+ goto ExitPoint ;
+ *aligned_p2 = *p2 ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W(NULL,
+ (DWORD)aligned_p1,
+ (DWORD)aligned_p2,
+ lpfnWNetGetUser,
+ (DWORD)7,
+ (DWORD)3) );
+ *p2 = (int) *aligned_p2 ;
+ lstrcpy(p1, aligned_p1) ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_p1) ;
+ FreeAlignedMemory(handle_p2) ;
+ return err ;
+}
+
+WORD API WNetBrowseDialog(HWND p1,WORD p2,LPSTR p3)
+{
+ WORD err ;
+ DWORD dwErr ;
+ LPSTR aligned_p3 = NULL ;
+ HANDLE handle_p3 = NULL ;
+
+ if (p3 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetBrowseDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetBrowseDialog,
+ USE_MPRUI_DLL,
+ "BrowseDialogA0" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note that the WFW API does not let user specify buffer size.
+ // we have a tmp buffer, and then copy over. this takes care
+ // data alignment, also make sure we dont fault on 32 bit side.
+ //
+ // the 128 is consistent with what their docs specs the buffer
+ // size should be.
+ //
+ if (err = GetAlignedMemory(&aligned_p3, &handle_p3, 128))
+ goto ExitPoint ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ dwErr = CallProc32W((LPVOID)TO_HWND32(p1),
+ (DWORD)MapWNType16To32(p2),
+ (DWORD)aligned_p3,
+ (DWORD)128,
+ lpfnWNetBrowseDialog,
+ (DWORD)2,
+ (DWORD)4) ;
+ if (dwErr == 0xFFFFFFFF)
+ err = WN_CANCEL ;
+ else
+ err = MapWin32ErrorToWN16( dwErr ) ;
+
+ if (!err)
+ lstrcpy(p3,aligned_p3) ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_p3) ;
+ return err ;
+}
+
+WORD API WNetConnectDialog(HWND p1,WORD p2)
+{
+ WORD err ;
+ DWORD dwErr ;
+
+ if (p2 == WNTYPE_PRINTER)
+ {
+ err = PrintConnectDialog(p1) ;
+ return err ;
+ }
+
+ if (!lpfnWNetConnectDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetConnectDialog,
+ USE_MPR_DLL,
+ "WNetConnectionDialog" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ dwErr = CallProc32W( (LPVOID)TO_HWND32(p1),
+ (DWORD)MapWNType16To32(p2),
+ (DWORD)lpfnWNetConnectDialog,
+ (DWORD) 0,
+ (DWORD) 2 ) ;
+ if (dwErr == 0xFFFFFFFF)
+ err = WN_CANCEL ;
+ else
+ err = MapWin32ErrorToWN16( dwErr ) ;
+ return err ;
+}
+
+
+WORD API WNetDisconnectDialog(HWND p1,WORD p2)
+{
+ WORD err ;
+ DWORD dwErr ;
+
+ if (!lpfnWNetDisconnectDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetDisconnectDialog,
+ USE_MPR_DLL,
+ "WNetDisconnectDialog" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ dwErr = CallProc32W( (LPVOID)TO_HWND32(p1),
+ (DWORD)MapWNType16To32(p2),
+ (DWORD)lpfnWNetDisconnectDialog,
+ (DWORD) 0,
+ (DWORD) 2 ) ;
+ if (dwErr == 0xFFFFFFFF)
+ err = WN_CANCEL ;
+ else
+ err = MapWin32ErrorToWN16( dwErr ) ;
+ return err ;
+}
+
+WORD API WNetConnectionDialog(HWND p1,WORD p2)
+{
+ return (WNetConnectDialog(p1,p2)) ;
+}
+
+WORD API PrintConnectDialog(HWND p1)
+{
+ WORD err ;
+ DWORD dwErr ;
+ DWORD handle ;
+
+ if (!lpfnClosePrinter)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnClosePrinter,
+ USE_WINSPOOL_DRV,
+ "ClosePrinter" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (!lpfnConnectToPrinter)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnConnectToPrinter,
+ USE_WINSPOOL_DRV,
+ "ConnectToPrinterDlg" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ err = WN_SUCCESS ;
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ handle = CallProc32W( (LPVOID)TO_HWND32(p1),
+ (DWORD) 0,
+ (DWORD)lpfnConnectToPrinter,
+ (DWORD) 0,
+ (DWORD) 2 ) ;
+ if (handle == 0)
+ err = WN_CANCEL ; // most likely reason
+ else
+ {
+ dwErr = MapWin32ErrorToWN16( CallProc32W((LPVOID)handle,
+ (DWORD)lpfnClosePrinter,
+ (DWORD)0,
+ (DWORD)1) );
+ // but ignore the error
+ }
+ return err ;
+}
+
+WORD API WNetPropertyDialog(HWND hwndParent,
+ WORD iButton,
+ WORD nPropSel,
+ LPSTR lpszName,
+ WORD nType)
+{
+ WORD err ;
+ LPSTR aligned_name = NULL ;
+ HANDLE handle_name = NULL ;
+
+ if (!lpfnWNetPropertyDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetPropertyDialog,
+ USE_MPR_DLL,
+ "WNetPropertyDialogA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (lpszName)
+ {
+ if (err = GetAlignedMemory(&aligned_name,
+ &handle_name,
+ lstrlen(lpszName)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_name, lpszName) ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W( (LPVOID)TO_HWND32(hwndParent),
+ (DWORD) iButton,
+ (DWORD) nPropSel,
+ (DWORD) aligned_name,
+ (DWORD) nType,
+ lpfnWNetPropertyDialog,
+ (DWORD)2,
+ (DWORD)5) ) ;
+ExitPoint:
+
+ FreeAlignedMemory(handle_name) ;
+ return err ;
+}
+
+WORD API WNetGetPropertyText(WORD iButton,
+ WORD nPropSel,
+ LPSTR lpszName,
+ LPSTR lpszButtonName,
+ WORD cbButtonName,
+ WORD nType)
+{
+ WORD err ;
+ LPSTR aligned_name = NULL, aligned_button_name = NULL ;
+ HANDLE handle_name = NULL, handle_button_name = NULL ;
+
+ if (lpszButtonName == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetGetPropertyText)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetGetPropertyText,
+ USE_MPR_DLL,
+ "WNetGetPropertyTextA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (lpszName)
+ {
+ if (err = GetAlignedMemory(&aligned_name,
+ &handle_name,
+ lstrlen(lpszName)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_name, lpszName) ;
+ }
+
+ if (err = GetAlignedMemory(&aligned_button_name,
+ &handle_button_name,
+ cbButtonName))
+ goto ExitPoint ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W( (LPVOID)iButton,
+ (DWORD) nPropSel,
+ (DWORD) aligned_name,
+ (DWORD) aligned_button_name,
+ (DWORD) cbButtonName,
+ (DWORD) nType,
+ lpfnWNetGetPropertyText,
+ (DWORD)12,
+ (DWORD)6) ) ;
+ if (err == WN_SUCCESS)
+ lstrcpy(lpszButtonName, aligned_button_name) ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_name) ;
+ FreeAlignedMemory(handle_button_name) ;
+ return err ;
+}
+
+WORD API WNetShareAsDialog(HWND hwndParent,
+ WORD iType,
+ LPSTR lpszPath)
+{
+ WORD err ;
+ LPSTR aligned_path = NULL ;
+ HANDLE handle_path = NULL ;
+
+ if (!lpfnWNetShareAsDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetShareAsDialog,
+ USE_NTLANMAN_DLL,
+ "ShareAsDialogA0" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (lpszPath)
+ {
+ if (err = GetAlignedMemory(&aligned_path,
+ &handle_path,
+ lstrlen(lpszPath)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_path, lpszPath) ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W( (LPVOID)TO_HWND32(hwndParent),
+ (DWORD) MapWNType16To32(iType),
+ (DWORD) aligned_path,
+ lpfnWNetShareAsDialog,
+ (DWORD)1,
+ (DWORD)3) ) ;
+ExitPoint:
+
+ FreeAlignedMemory(handle_path) ;
+ return err ;
+}
+
+WORD API WNetStopShareDialog(HWND hwndParent,
+ WORD iType,
+ LPSTR lpszPath)
+{
+ WORD err ;
+ LPSTR aligned_path = NULL ;
+ HANDLE handle_path = NULL ;
+
+ if (!lpfnWNetStopShareDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetStopShareDialog,
+ USE_NTLANMAN_DLL,
+ "StopShareDialogA0" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (lpszPath)
+ {
+ if (err = GetAlignedMemory(&aligned_path,
+ &handle_path,
+ lstrlen(lpszPath)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_path, lpszPath) ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W( (LPVOID)TO_HWND32(hwndParent),
+ (DWORD) MapWNType16To32(iType),
+ (DWORD) aligned_path,
+ lpfnWNetStopShareDialog,
+ (DWORD)1,
+ (DWORD)3) ) ;
+ExitPoint:
+
+ FreeAlignedMemory(handle_path) ;
+ return err ;
+}
+
+WORD API WNetServerBrowseDialog(HWND hwndParent,
+ LPSTR lpszSectionName,
+ LPSTR lpszBuffer,
+ WORD cbBuffer,
+ DWORD flFlags)
+{
+ WORD err ;
+ LPSTR aligned_buffer = NULL ;
+ HANDLE handle_buffer = NULL ;
+
+ UNREFERENCED(lpszSectionName) ;
+ UNREFERENCED(flFlags) ;
+
+ if (!lpfnWNetServerBrowseDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetServerBrowseDialog,
+ USE_NTLANMAN_DLL,
+ "ServerBrowseDialogA0" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (lpszBuffer)
+ {
+ if (err = GetAlignedMemory(&aligned_buffer, &handle_buffer, cbBuffer))
+ goto ExitPoint ;
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W( (LPVOID)TO_HWND32(hwndParent),
+ (DWORD) aligned_buffer,
+ (DWORD) cbBuffer,
+ lpfnWNetServerBrowseDialog,
+ (DWORD)2,
+ (DWORD)3) ) ;
+ if (err == WN_SUCCESS)
+ lstrcpy(lpszBuffer, aligned_buffer) ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_buffer) ;
+ return err ;
+}
+
+WORD API WNetGetDirectoryType(LPSTR p1,LPINT p2)
+{
+ WORD err ;
+ LPSTR aligned_p1 = NULL ;
+ LPDWORD aligned_p2 = NULL ;
+ HANDLE handle_p1 = NULL, handle_p2 = NULL ;
+
+ if (p1 == NULL || p2 == NULL)
+ return WN_BAD_POINTER ;
+
+ if (!lpfnWNetGetDirectoryType)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnWNetGetDirectoryType,
+ USE_MPR_DLL,
+ "WNetGetDirectoryTypeA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ if (err = GetAlignedMemory(&aligned_p1, &handle_p1, lstrlen(p1)+1))
+ goto ExitPoint ;
+ lstrcpy(aligned_p1, p1) ;
+
+ if (err = GetAlignedMemory(&aligned_p2, &handle_p2, sizeof(DWORD)))
+ goto ExitPoint ;
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ err = MapWin32ErrorToWN16( CallProc32W(aligned_p1,
+ (DWORD)aligned_p2,
+ (DWORD)TRUE,
+ lpfnWNetGetDirectoryType,
+ (DWORD)6,
+ (DWORD)3) ) ;
+ *p2 = (int) *aligned_p2 ;
+
+ExitPoint:
+
+ FreeAlignedMemory(handle_p1) ;
+ FreeAlignedMemory(handle_p2) ;
+ return err ;
+}
+
+WORD API WNetDirectoryNotify(HWND p1,LPSTR p2,WORD p3)
+{
+ UNREFERENCED(p1) ;
+ UNREFERENCED(p2) ;
+ UNREFERENCED(p3) ;
+ return WN_SUCCESS ;
+}
+
+DWORD API GetLastError32(VOID)
+{
+ WORD err ;
+ DWORD dwErr ;
+
+ if (!lpfnGetLastError32)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from 32 bit side
+ //
+ err = Get32BitEntryPoints( &lpfnGetLastError32,
+ USE_KERNEL32_DLL,
+ "GetLastError" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_WIN32 ;
+ dwErr = (UINT) CallProc32W((LPVOID)lpfnGetLastError32,
+ (DWORD)0,
+ (DWORD)0) ;
+ return (MapWin32ErrorToWN16(dwErr)) ;
+}
+
+/*
+ * Misc support routines
+ */
+
+/*******************************************************************
+
+ NAME: Get32BitEntryPoints
+
+ SYNOPSIS: Get the address of a 32 bit entry point that can
+ then be passed to CallProv32W. Will load the library
+ if it has not already been loaded.
+
+ ENTRY: lplpfn - used to return the address
+ dwDll - which dll to use (see locals.h defintions)
+ lpProcName - proc to load
+
+ EXIT:
+
+ RETURNS: error code
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+WORD Get32BitEntryPoints( LPVOID *lplpfn, DWORD dwDll, LPSTR lpProcName )
+{
+ static DWORD hmodKernel32 = NULL ;
+ static DWORD hmodNTLanman = NULL ;
+ static DWORD hmodMpr = NULL ;
+ static DWORD hmodMprUI = NULL ;
+ static DWORD hmodWinSpool = NULL ;
+ DWORD hmod = NULL ;
+
+ //
+ // if we havent loaded it appropriate DLL, load it now
+ //
+ switch (dwDll)
+ {
+ case USE_MPR_DLL:
+ if (hmodMpr == NULL)
+ {
+ hmodMpr = LoadLibraryEx32W(MPR_DLL, NULL, 0) ;
+ if (hmodMpr == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+ hmod = hmodMpr ;
+ break ;
+
+ case USE_MPRUI_DLL:
+ if (hmodMprUI == NULL)
+ {
+ hmodMprUI = LoadLibraryEx32W(MPRUI_DLL, NULL, 0) ;
+ if (hmodMprUI == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+ hmod = hmodMprUI ;
+ break ;
+
+ case USE_NTLANMAN_DLL:
+ if (hmodNTLanman == NULL)
+ {
+ hmodNTLanman = LoadLibraryEx32W(NTLANMAN_DLL, NULL, 0) ;
+ if (hmodNTLanman == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+ hmod = hmodNTLanman ;
+ break ;
+
+ case USE_KERNEL32_DLL:
+ if (hmodKernel32 == NULL)
+ {
+ hmodKernel32 = LoadLibraryEx32W(KERNEL32_DLL, NULL, 0) ;
+ if (hmodKernel32 == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+ hmod = hmodKernel32 ;
+ break ;
+
+ case USE_WINSPOOL_DRV:
+ if (hmodWinSpool == NULL)
+ {
+ hmodWinSpool = LoadLibraryEx32W(WINSPOOL_DRV, NULL, 0) ;
+ if (hmodWinSpool == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+ hmod = hmodWinSpool ;
+ break ;
+
+ default:
+ return ERROR_GEN_FAILURE ;
+ }
+
+ //
+ // get the procedure
+ //
+ *lplpfn = (LPVOID) GetProcAddress32W(hmod, lpProcName) ;
+ if (! *lplpfn )
+ return WN_NOT_SUPPORTED ;
+
+ return WN_SUCCESS ;
+}
+
+/*******************************************************************
+
+ NAME: MapWNType16To32
+
+ SYNOPSIS: map the 16 WNet types for DISK/PRINT, etc
+ to their 32 bit equivalents
+
+ ENTRY: nType - 16 bit type
+
+ EXIT:
+
+ RETURNS: the 32 bit type
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+DWORD MapWNType16To32(WORD nType)
+{
+ switch (nType)
+ {
+ case WNTYPE_DRIVE :
+ case WNTYPE_FILE :
+ return RESOURCETYPE_DISK ;
+ case WNTYPE_PRINTER :
+ return RESOURCETYPE_PRINT ;
+ case WNTYPE_COMM :
+ default :
+ return RESOURCETYPE_ERROR ;
+ }
+}
+
+/*******************************************************************
+
+ NAME: MapWin32ErrorToWN16
+
+ SYNOPSIS: maps a Win 32 error the old style WN_ 16 bit error.
+
+ ENTRY: err - Win32 error
+
+ EXIT:
+
+ RETURNS: Win 16 error
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+WORD MapWin32ErrorToWN16(DWORD err)
+{
+ switch (err)
+ {
+ case ERROR_NOT_SUPPORTED:
+ return WN_NOT_SUPPORTED ;
+
+ case WIN32_WN_CANCEL:
+ return WN_CANCEL ;
+
+ case WIN32_EXTENDED_ERROR :
+ case ERROR_UNEXP_NET_ERR:
+ return WN_NET_ERROR ;
+
+ case ERROR_MORE_DATA:
+ return WN_MORE_DATA ;
+
+ case ERROR_INVALID_PARAMETER:
+ return WN_BAD_VALUE ;
+
+ case ERROR_INVALID_PASSWORD:
+ return WN_BAD_PASSWORD ;
+
+ case ERROR_ACCESS_DENIED:
+ return WN_ACCESS_DENIED ;
+
+ case ERROR_NETWORK_BUSY:
+ return WN_FUNCTION_BUSY ;
+
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return WN_OUT_OF_MEMORY ;
+
+ case ERROR_BAD_NET_NAME:
+ case ERROR_BAD_NETPATH:
+ return WN_BAD_NETNAME ;
+
+ case ERROR_INVALID_DRIVE:
+ return WN_BAD_LOCALNAME ;
+
+ case ERROR_ALREADY_ASSIGNED:
+ return WN_ALREADY_CONNECTED ;
+
+ case ERROR_GEN_FAILURE:
+ return WN_DEVICE_ERROR ;
+
+ case NERR_UseNotFound:
+ return WN_NOT_CONNECTED ;
+
+ default:
+ return ( (WORD) err ) ;
+ }
+}
+
+/*******************************************************************
+
+ NAME: GetAlignedMemory
+
+ SYNOPSIS: global alloc some mem to make sure we have DWORD
+ aligned data. non x86 platforms may need this.
+
+ ENTRY: pAligned : used to return pointer to aligned memory allocated
+ pHandle : used to return handle of aligned memory allocated
+ wSize : bytes required
+
+ EXIT:
+
+ RETURNS: WN_SUCCESS or WN_OUT_OF_MEMORY
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 27-Feb-94 Created
+
+********************************************************************/
+WORD GetAlignedMemory(LPVOID FAR *pAligned, HANDLE FAR *pHandle, WORD wSize)
+{
+ *pAligned = NULL ;
+ *pHandle = NULL ;
+
+ if (!(*pHandle = GlobalAlloc(GMEM_ZEROINIT|GMEM_FIXED,wSize)))
+ {
+ return WN_OUT_OF_MEMORY ;
+ }
+
+ if (!(*pAligned = (LPVOID)GlobalLock(*pHandle)))
+ {
+ (void) GlobalFree(*pHandle) ;
+ *pHandle = NULL ;
+ return WN_OUT_OF_MEMORY ;
+ }
+
+ return WN_SUCCESS ;
+}
+
+/*******************************************************************
+
+ NAME: FreeAlignedMemory
+
+ SYNOPSIS: free global memory allocated by GetAlignedMemory.
+
+ ENTRY: Handle : handle of aligned memory to be freed
+
+ EXIT:
+
+ RETURNS: none
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 27-Feb-94 Created
+
+********************************************************************/
+void FreeAlignedMemory(HANDLE handle)
+{
+ if (handle)
+ {
+ (void) GlobalUnlock(handle) ;
+ (void) GlobalFree(handle) ;
+ }
+}
diff --git a/private/mvdm/wow16/wfwnet/wfwnet.c b/private/mvdm/wow16/wfwnet/wfwnet.c
new file mode 100644
index 000000000..0ffd7e509
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/wfwnet.c
@@ -0,0 +1,844 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ wfwnet.c
+
+Abstract:
+
+ Provides entry points for the functions that will be mapped
+ to LANMAN.DRV.
+
+Author:
+
+ Chuck Y Chan (ChuckC) 25-Mar-1993
+
+Revision History:
+
+
+--*/
+#include <windows.h>
+#include <locals.h>
+
+WORD vLastCall = LAST_CALL_IS_LOCAL ;
+WORD vLastError = 0 ;
+
+WORD wNetTypeCaps ; /* Current capabilities */
+WORD wUserCaps ;
+WORD wConnectionCaps ;
+WORD wErrorCaps ;
+WORD wDialogCaps ;
+WORD wAdminCaps ;
+WORD wSpecVersion = 0x0310 ;
+WORD wDriverVersion = 0x0300 ;
+
+void I_SetCapBits(void) ;
+
+//
+// global pointers to functions
+//
+LPWNETOPENJOB lpfnWNetOpenJob = NULL ;
+LPWNETCLOSEJOB lpfnWNetCloseJob = NULL ;
+LPWNETWRITEJOB lpfnWNetWriteJob = NULL ;
+LPWNETABORTJOB lpfnWNetAbortJob = NULL ;
+LPWNETHOLDJOB lpfnWNetHoldJob = NULL ;
+LPWNETRELEASEJOB lpfnWNetReleaseJob = NULL ;
+LPWNETCANCELJOB lpfnWNetCancelJob = NULL ;
+LPWNETSETJOBCOPIES lpfnWNetSetJobCopies = NULL ;
+LPWNETWATCHQUEUE lpfnWNetWatchQueue = NULL ;
+LPWNETUNWATCHQUEUE lpfnWNetUnwatchQueue = NULL ;
+LPWNETLOCKQUEUEDATA lpfnWNetLockQueueData = NULL ;
+LPWNETUNLOCKQUEUEDATA lpfnWNetUnlockQueueData = NULL ;
+LPWNETQPOLL lpfnWNetQPoll = NULL ;
+LPWNETDEVICEMODE lpfnWNetDeviceMode = NULL ;
+LPWNETVIEWQUEUEDIALOG lpfnWNetViewQueueDialog = NULL ;
+LPWNETGETCAPS lpfnWNetGetCaps16 = NULL ;
+LPWNETGETERROR lpfnWNetGetError16 = NULL ;
+LPWNETGETERRORTEXT lpfnWNetGetErrorText16 = NULL ;
+
+extern VOID FAR PASCAL GrabInterrupts(void);
+
+int FAR PASCAL LibMain(HINSTANCE hInstance,
+ WORD wDataSeg,
+ WORD cbHeapSize,
+ LPSTR lpszCmdLine) ;
+
+/*
+ * functions passed to LANMAN.DRV
+ */
+
+WORD API WNetOpenJob(LPSTR p1,LPSTR p2,WORD p3,LPINT p4)
+{
+ WORD err ;
+
+ if (!lpfnWNetOpenJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetOpenJob,
+ "WNETOPENJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetOpenJob)(p1,p2,p3,p4) ) ;
+}
+
+WORD API WNetCloseJob(WORD p1,LPINT p2,LPSTR p3)
+{
+ WORD err ;
+
+ if (!lpfnWNetCloseJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetCloseJob,
+ "WNETCLOSEJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetCloseJob)(p1,p2,p3) ) ;
+}
+
+WORD API WNetWriteJob(HANDLE p1,LPSTR p2,LPINT p3)
+{
+ WORD err ;
+
+ if (!lpfnWNetWriteJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetWriteJob,
+ "WNETWRITEJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetWriteJob)(p1,p2,p3) ) ;
+}
+
+WORD API WNetAbortJob(WORD p1,LPSTR p2)
+{
+ WORD err ;
+
+ if (!lpfnWNetAbortJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetAbortJob,
+ "WNETABORTJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetAbortJob)(p1,p2) ) ;
+}
+
+WORD API WNetHoldJob(LPSTR p1,WORD p2)
+{
+ WORD err ;
+
+ if (!lpfnWNetHoldJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetHoldJob,
+ "WNETHOLDJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetHoldJob)(p1,p2) ) ;
+}
+
+WORD API WNetReleaseJob(LPSTR p1,WORD p2)
+{
+ WORD err ;
+
+ if (!lpfnWNetReleaseJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetReleaseJob,
+ "WNETRELEASEJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetReleaseJob)(p1,p2) ) ;
+}
+
+WORD API WNetCancelJob(LPSTR p1,WORD p2)
+{
+ WORD err ;
+
+ if (!lpfnWNetCancelJob)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetCancelJob,
+ "WNETCANCELJOB" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetCancelJob)(p1,p2) ) ;
+}
+
+WORD API WNetSetJobCopies(LPSTR p1,WORD p2,WORD p3)
+{
+ WORD err ;
+
+ if (!lpfnWNetSetJobCopies)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetSetJobCopies,
+ "WNETSETJOBCOPIES" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetSetJobCopies)(p1,p2,p3) ) ;
+}
+
+WORD API WNetWatchQueue(HWND p1,LPSTR p2,LPSTR p3,WORD p4)
+{
+ WORD err ;
+
+ if (!lpfnWNetWatchQueue)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetWatchQueue,
+ "WNETWATCHQUEUE" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetWatchQueue)(p1,p2,p3,p4) ) ;
+}
+
+WORD API WNetUnwatchQueue(LPSTR p1)
+{
+ WORD err ;
+
+ if (!lpfnWNetUnwatchQueue)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetUnwatchQueue,
+ "WNETUNWATCHQUEUE" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetUnwatchQueue)(p1) ) ;
+}
+
+WORD API WNetLockQueueData(LPSTR p1,LPSTR p2,LPQUEUESTRUCT FAR *p3)
+{
+ WORD err ;
+
+ if (!lpfnWNetLockQueueData)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetLockQueueData,
+ "WNETLOCKQUEUEDATA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetLockQueueData)(p1,p2,p3) ) ;
+}
+
+WORD API WNetUnlockQueueData(LPSTR p1)
+{
+ WORD err ;
+
+ if (!lpfnWNetUnlockQueueData)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetUnlockQueueData,
+ "WNETUNLOCKQUEUEDATA" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetUnlockQueueData)(p1) ) ;
+}
+
+void API WNetQPoll(HWND hWnd, unsigned iMessage, WORD wParam, LONG lParam)
+{
+ WORD err ;
+
+ if (!lpfnWNetQPoll)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetQPoll,
+ "WNETQPOLL" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ (*lpfnWNetQPoll)(hWnd, iMessage, wParam, lParam) ;
+}
+
+WORD API WNetDeviceMode(HWND p1)
+{
+ WORD err ;
+
+ if (!lpfnWNetDeviceMode)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetDeviceMode,
+ "WNETDEVICEMODE" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetDeviceMode)(p1) ) ;
+}
+
+WORD API WNetViewQueueDialog(HWND p1,LPSTR p2)
+{
+ WORD err ;
+
+ if (!lpfnWNetViewQueueDialog)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetViewQueueDialog,
+ "WNETVIEWQUEUEDIALOG" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetViewQueueDialog)(p1,p2) ) ;
+}
+
+WORD API WNetGetCaps16(WORD p1)
+{
+ WORD err ;
+
+ if (!lpfnWNetGetCaps16)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetGetCaps16,
+ "WNETGETCAPS" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetGetCaps16)(p1) ) ;
+}
+
+WORD API WNetGetError16(LPINT p1)
+{
+ WORD err ;
+
+ if (!lpfnWNetGetError16)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetGetError16,
+ "WNETGETERROR" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetGetError16)(p1) ) ;
+}
+
+WORD API WNetGetErrorText16(WORD p1, LPSTR p2, LPINT p3)
+{
+ WORD err ;
+
+ if (!lpfnWNetGetErrorText16)
+ {
+ //
+ // start off as a our code until we get the entry point
+ //
+ vLastCall = LAST_CALL_IS_LOCAL ;
+
+ //
+ // get the entry point from LANMAN.DRV
+ //
+ err = GetLanmanDrvEntryPoints( (LPFN *)&lpfnWNetGetErrorText16,
+ "WNETGETERRORTEXT" ) ;
+ if (err)
+ {
+ SetLastError(err) ;
+ return err ;
+ }
+ }
+
+ //
+ // note it is no longer an error in our code. and call the API
+ //
+ vLastCall = LAST_CALL_IS_LANMAN_DRV ;
+ return ( (*lpfnWNetGetErrorText16)(p1,p2,p3) ) ;
+}
+
+WORD API WNetGetCaps(WORD nIndex)
+{
+ switch (nIndex)
+ {
+ case WNNC_SPEC_VERSION:
+ return wSpecVersion;
+
+ case WNNC_NET_TYPE:
+ return wNetTypeCaps;
+
+ case WNNC_DRIVER_VERSION:
+ return wDriverVersion;
+
+ case WNNC_USER:
+ return wUserCaps;
+
+ case WNNC_CONNECTION:
+ return wConnectionCaps;
+
+ case WNNC_PRINTING:
+ return (WNetGetCaps16(nIndex)) ;
+
+ case WNNC_DIALOG:
+ return wDialogCaps;
+
+ case WNNC_ADMIN:
+ return wAdminCaps;
+
+ case WNNC_ERROR:
+ return wErrorCaps;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * misc support functions
+ */
+
+/*******************************************************************
+
+ NAME: GetLanmanDrvEntryPoints
+
+ SYNOPSIS: gets the address of the named procedure
+ from LANMAN.DRV, will load library if first time.
+
+ ENTRY: lplpfn - used to receive the address
+ lpName - name of the procedure
+
+ EXIT:
+
+ RETURNS: 0 if success, error code otherwise.
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+WORD GetLanmanDrvEntryPoints(LPFN *lplpfn, LPSTR lpName)
+{
+ static HINSTANCE hModule = NULL ;
+
+ //
+ // if we havent loaded it, load it now
+ //
+ if (hModule == NULL)
+ {
+ hModule = LoadLibrary(LANMAN_DRV) ;
+ if (hModule == NULL)
+ return WN_NOT_SUPPORTED ;
+ }
+
+ //
+ // get the procedure
+ //
+ *lplpfn = (LPFN) GetProcAddress(hModule, lpName) ;
+ if (! *lplpfn )
+ return WN_NOT_SUPPORTED ;
+
+ return NO_ERROR ;
+}
+
+/*******************************************************************
+
+ NAME: SetLastError
+
+ SYNOPSIS: makes note of last error
+
+ ENTRY:
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+WORD SetLastError(WORD err)
+{
+ vLastError = err ;
+ return err ;
+}
+
+/*******************************************************************
+
+ NAME: LibMain
+
+ SYNOPSIS: dll init entry point. only thing we do here is init
+ the capability bits.
+
+ ENTRY:
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+
+#define NETWARE_DLL "NETWARE.DRV"
+
+int FAR PASCAL LibMain(HINSTANCE hInstance,
+ WORD wDataSeg,
+ WORD cbHeapSize,
+ LPSTR lpszCmdLine)
+{
+ OFSTRUCT ofStruct ;
+ int fh ;
+ BOOL fLoadNetware = FALSE ;
+ char IsInstalledString[16] ;
+
+ UNREFERENCED(hInstance) ;
+ UNREFERENCED(wDataSeg) ;
+ UNREFERENCED(cbHeapSize) ;
+ UNREFERENCED(lpszCmdLine) ;
+
+ I_SetCapBits() ;
+
+ if (GetProfileString("NWCS",
+ "NwcsInstalled",
+ "0",
+ IsInstalledString,
+ sizeof(IsInstalledString)))
+ {
+ fLoadNetware = (lstrcmp("1",IsInstalledString)==0) ;
+ }
+
+ //
+ // if enhanced mode, grab the interrupt for NWIPXSPX
+ //
+ if ((GetWinFlags() & WF_ENHANCED) && fLoadNetware) {
+ GrabInterrupts();
+ }
+
+ //
+ // if the file NETWARE.DRV exists, we load it. we dont really
+ // use it, but some Netware aware apps require that it is loaded.
+ //
+ if (fLoadNetware &&
+ ((fh = OpenFile(NETWARE_DLL, &ofStruct, OF_READ)) != -1))
+ {
+ _lclose(fh) ;
+
+ (void)WriteProfileString("Windows",
+ "NetWarn",
+ "0") ;
+
+ (void)LoadLibrary(NETWARE_DLL) ;
+ }
+
+ return 1 ;
+}
+
+
+/*******************************************************************
+
+ NAME: I_SetCapBits
+
+ SYNOPSIS: initernal routine to set the capability bits
+
+ ENTRY:
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES:
+
+ HISTORY:
+ ChuckC 25-Mar-93 Created
+
+********************************************************************/
+void I_SetCapBits(void)
+{
+ wNetTypeCaps = WNNC_NET_MultiNet |
+ WNNC_SUBNET_WinWorkgroups;
+
+ wUserCaps = WNNC_USR_GetUser;
+
+ wConnectionCaps = (WNNC_CON_AddConnection |
+ WNNC_CON_CancelConnection |
+ WNNC_CON_GetConnections |
+ WNNC_CON_AutoConnect |
+ WNNC_CON_BrowseDialog |
+ WNNC_CON_RestoreConnection ) ;
+
+ wErrorCaps = WNNC_ERR_GetError |
+ WNNC_ERR_GetErrorText;
+
+ wDialogCaps = (WNNC_DLG_DeviceMode |
+ WNNC_DLG_ShareAsDialog |
+ WNNC_DLG_PropertyDialog |
+ WNNC_DLG_ConnectionDialog |
+ WNNC_DLG_ConnectDialog |
+ WNNC_DLG_DisconnectDialog |
+ WNNC_DLG_BrowseDialog );
+
+ wAdminCaps = ( WNNC_ADM_GetDirectoryType |
+ WNNC_ADM_DirectoryNotify ) ;
+/* disable LFN for now
+ | WNNC_ADM_LongNames ) ;
+ */
+
+}
diff --git a/private/mvdm/wow16/wfwnet/wfwnet.def b/private/mvdm/wow16/wfwnet/wfwnet.def
new file mode 100644
index 000000000..f56d3456d
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/wfwnet.def
@@ -0,0 +1,102 @@
+LIBRARY WFWNET
+DESCRIPTION 'WOW REPLACEMENT WFWNET'
+EXETYPE WINDOWS
+STUB '..\BIN\WINSTUB.EXE'
+CODE PRELOAD MOVEABLE
+DATA PRELOAD MOVEABLE SINGLE
+HEAPSIZE 2048
+
+
+EXPORTS
+; standard network driver callouts
+ WNETOPENJOB @1
+ WNETCLOSEJOB @2
+ WNETABORTJOB @3
+ WNETHOLDJOB @4
+ WNETRELEASEJOB @5
+ WNETCANCELJOB @6
+ WNETSETJOBCOPIES @7
+ WNETWATCHQUEUE @8
+ WNETUNWATCHQUEUE @9
+ WNETLOCKQUEUEDATA @10
+ WNETUNLOCKQUEUEDATA @11
+ WNETGETCONNECTION @12
+ WNETGETCAPS @13
+ WNETDEVICEMODE @14
+ WNETBROWSEDIALOG @15
+ WNETGETUSER @16
+ WNETADDCONNECTION @17
+ WNETCANCELCONNECTION @18
+ WNETGETERROR @19
+ WNETGETERRORTEXT @20
+ ENABLE @21
+ DISABLE @22
+ WNETRESTORECONNECTION @23
+ WNETCONNECTDIALOG @25
+ WNETDISCONNECTDIALOG @26
+ WNETCONNECTIONDIALOG @27
+ WNETPROPERTYDIALOG @29
+ WNETGETDIRECTORYTYPE @30
+ WNETDIRECTORYNOTIFY @31
+ WNETGETPROPERTYTEXT @32
+
+; FMEXTENSIONPROC
+
+; Internal-only APIs
+ WNETQPOLL @520
+ I_AUTOLOGON @530
+ I_CHANGEPASSWORD @531
+ I_LOGOFF @532
+ I_CONNECTIONDIALOG @533
+ I_CHANGECACHEPASSWORD @534
+ I_CONNECTDIALOG @535
+
+; Long FileName support APIs
+
+ LFNFINDFIRST @100
+ LFNFINDNEXT @101
+ LFNFINDCLOSE @102
+ LFNGETATTRIBUTES @103
+ LFNSETATTRIBUTES @104
+ LFNCOPY @105
+ LFNMOVE @106
+ LFNDELETE @107
+ LFNMKDIR @108
+ LFNRMDIR @109
+ LFNGETVOLUMELABEL @110
+ LFNSETVOLUMELABEL @111
+ LFNPARSE @112
+ LFNVOLUMETYPE @113
+
+; Print Manager Extensions (not supported anymore)
+ WNETPRINTMGRCHANGEMENUS @130
+ WNETPRINTMGREXITING @131
+ WNETPRINTMGRCOMMAND @132
+ WNETPRINTMGRMOVEJOB @133
+ WNETPRINTMGRSELNOTIFY @134
+ WNETPRINTMGRPRINTERENUM @135
+ WNETPRINTMGREXTHELP @136
+ WNETPRINTMGRSTATUSCHANGE @137
+
+; New share dialog APIs for winfile
+
+ WNETSHARESDIALOG @140
+ WNETSHAREASDIALOG @141
+ WNETSTOPSHAREDIALOG @142
+ WNETSETDEFAULTDRIVE @143
+ WNETGETSHARECOUNT @144
+ WNETGETSHARENAME @145
+ WNETSERVERBROWSEDIALOG @146
+ WNETGETSHAREPATH @147
+ WNETGETLASTCONNECTION @148
+ WNETEXITCONFIRM @149
+
+; Password caching APIs (not supported)
+
+ WNETCACHEPASSWORD @150
+ WNETGETCACHEDPASSWORD @151
+ WNETREMOVECACHEDPASSWORD @152
+ WNETENUMCACHEDPASSWORDS @153
+
+ WEP @199 RESIDENTNAME
+
diff --git a/private/mvdm/wow16/wfwnet/wfwnet.rc b/private/mvdm/wow16/wfwnet/wfwnet.rc
new file mode 100644
index 000000000..3281cc82d
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/wfwnet.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* WFWNET.RC */
+/********************************************************************/
+#include "wfwnet.rcv"
diff --git a/private/mvdm/wow16/wfwnet/wfwnet.rcv b/private/mvdm/wow16/wfwnet/wfwnet.rcv
new file mode 100644
index 000000000..9d3061dd3
--- /dev/null
+++ b/private/mvdm/wow16/wfwnet/wfwnet.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* WFWNET.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows for Workgroups network driver"
+#define VER_INTERNALNAME_STR "WFWNET"
+#define VER_ORIGINALFILENAME_STR "WFWNET.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/win87em/87emstar.asm b/private/mvdm/wow16/win87em/87emstar.asm
new file mode 100644
index 000000000..67eb80142
--- /dev/null
+++ b/private/mvdm/wow16/win87em/87emstar.asm
@@ -0,0 +1,21 @@
+;-------------------------------------------------------
+;
+; pull in the Windows start up module;
+; pull in the Windows floating-point emulator;
+;
+; 9876h value is so that the symbol defined won't easily match
+; a constant value in the debugger.
+;
+public __acrtused
+ __acrtused = 9876h
+extrn __acrtused2:abs ; pull in winstart: ?winstar.obj or ?libstar.obj
+
+public __fptaskdata
+ __fptaskdata = 9876h ; stub out __fptaskdata so that
+ ; non-Windows emulator is not brought in
+
+extrn __fpmath:far ; force in Windows-emulator imports definition
+
+extrn __fpsignal:far ; force in Windows version of __fpsignal
+
+end
diff --git a/private/mvdm/wow16/win87em/apisim.asm b/private/mvdm/wow16/win87em/apisim.asm
new file mode 100644
index 000000000..a7fd1b054
--- /dev/null
+++ b/private/mvdm/wow16/win87em/apisim.asm
@@ -0,0 +1,118 @@
+ title OS2_STUB - OS/2 Simulation routines for DOS 3
+
+; These routines simulate family API routines for DOS 3
+;
+; Routines which are never called under DOS 3 just return
+; popping the parameters.
+;
+; 87/04/24 SKS DOSGETMACHINEMODE stores a Byte, not a Word!
+;
+
+
+memL=1 ; simulate large model for returns
+?PLM=1 ; pascal calling conventions
+?WIN=0 ; no Windows
+
+.xlist
+ include cmac_mrt.inc ; old, customized masm510 cmacros
+.list
+ include msdos.inc
+
+
+sBegin code
+assumes cs,code
+
+
+; __DOSDEVCONFIG - return 8087/80287 indicator
+
+cProc __DOSDEVCONFIG,<PUBLIC>,<ES,BX>
+
+ parmDP devinfo
+ parmW devitem
+ parmW reserved
+
+cbegin
+ les bx,devinfo
+ mov word ptr es:[bx],1 ; assume have 287
+ xor ax,ax ; return no error
+cend
+
+
+; __DOSGETMACHINEMODE - return real mode indicator
+
+cProc __DOSGETMACHINEMODE,<PUBLIC>,<ES,BX>
+
+ parmDP mode
+
+cbegin
+ les bx,mode
+ xor ax,ax ; ax = return code and mode
+ mov es:[bx],al ; set machine mode to real
+cend
+
+
+; __DOSSETVEC - never called under DOS 3.x
+
+cProc __DOSSETVEC,<PUBLIC>,<>
+
+ parmDP oldaddr
+ parmDP newaddr
+ parmW vecnum
+
+cbegin
+cend
+
+
+; __DOSCREATECSALIAS
+
+cProc __DOSCREATECSALIAS,<PUBLIC>,<ES,BX>
+
+ parmW dataseg
+ parmDP csalias
+
+cbegin
+ mov ax,dataseg
+ les bx,csalias
+ mov es:[bx],ax ; use dataseg value
+cend
+
+
+
+; __DOSFREESEG - never called from DOS 3.x
+
+cProc __DOSFREESEG,<PUBLIC>,<>
+
+ parmW dataseg
+
+cbegin
+cend
+
+; __DOSWRITE - stripped-down version called from emulator for no87 message
+; - note that there is no error detection in this version
+; - since the emulator doesn't check for write errors anyway
+
+cProc __DOSWRITE,<PUBLIC>,<ds> ; <di> commented out
+
+ parmW handle ; unsigned
+ parmD p_buffer ; char far *
+ parmW bytestowrite ; unsigned
+ parmD p_byteswritten ; unsigned far *
+ ; returns unsgined
+
+cbegin
+ mov cx,bytestowrite
+ mov bx,handle
+ lds dx,p_buffer
+ callos write
+; jc wrtret ; if write error, error code already in AX
+; ; if no error, set bytes written
+; les di,p_byteswritten
+; mov word ptr es:[di],ax
+ xor ax,ax ; if no error, clear return code
+;wrtret:
+cend
+
+
+sEnd code
+
+ end
diff --git a/private/mvdm/wow16/win87em/em386.asm b/private/mvdm/wow16/win87em/em386.asm
new file mode 100644
index 000000000..7e4dc57e1
--- /dev/null
+++ b/private/mvdm/wow16/win87em/em386.asm
@@ -0,0 +1,567 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl em386.asm - Main Entry Point and Address Calculation Procedure
+page
+;*********************************************************************;
+; ;
+; Main Entry Point and Address Calculation Procedure ;
+; ;
+; 80386 version ;
+; ;
+;*********************************************************************;
+;
+; This routine fetches the 8087 instruction, calculates memory address
+; if necessary into ES:ESI and calls a routine to emulate the instruction.
+; Most of the dispatching is done through tables. (see comments in CONST)
+;
+; The instruction dispatching is designed to favor the 386 addressing modes
+
+ifdef XENIX
+
+LDT_DATA= 02Fh ; emulator data LDT
+STACK_ALIAS= 027h ; 32 bit alias for stack selector
+
+endif ;XENIX
+
+;------------------------------------------------------------------------------
+;
+; emulation entry point
+;
+;------------------------------------------------------------------------------
+
+pub protemulation
+
+ cld ; clear direction flag forever
+
+ifdef XENIX
+ push ss ; save ss
+endif ;XENIX
+
+ push eax ; for common exit code (historical)
+
+ push ds ; save segment registers
+
+ifdef XENIX
+
+ push eax ; UNDONE - slow
+
+ mov ax,LDT_DATA ; load up emulator's data segment
+ mov ds,ax
+ cmp [Einstall],0 ; check if emulator is initialized
+ je installemulator ; no - go install it
+
+pub protemcont
+
+ pop eax ; UNDONE - slow
+
+endif ;XENIX
+
+ push es
+ push ss ; save SegOvr (bp forces SS override)
+
+ push edi ; save registers
+ push esi ; must be in this order for indexing
+ push ebp
+ push esp
+ push ebx
+ push edx
+ push ecx
+ push eax
+
+ifdef XENIX
+
+ mov ax,ss ; check for 286 using user SS
+ lar eax,ax ; load extended access bits
+ test eax,00400000h ; test BIG bit
+ jnz short prot386 ; 386 - ok
+
+ mov ax,STACK_ALIAS ; setup stack with 32 bit alias segment
+ mov ss,ax
+ movzx esp,sp ; clean up ESP
+; mov word ptr [esp].regEIP+2,0 ; clean up EIP
+
+pub prot386
+
+endif ;XENIX
+
+ mov ebp,esp ; set up frame pointer
+ add [ebp].regESP,regFlg-regESP ; adjust to original esp
+
+ mov eax,edi ; may use original DI to calc address
+ lds edi,fword ptr [ebp].regEIP ; ds:edi = 287 instruction address
+ mov cx,[edi] ; cx = esc 0-7 and opcode
+
+ cmp cl,09Bh ; UNDONE - check FWAIT's getting through
+ je sawFWAIT ; UNDONE - and ignore it
+
+ add edi,2 ; point to displacement
+ add cl,28h ; set carry if esc 0-7 (and cl = 0-7)
+ jnc short protSegOvr ; no carry - must be segment override
+
+ mov es,[ebp].regDS ; es = user data segment
+ mov edx,ebx ; may use original BX to calc address
+
+pub CommonDispatch
+ rol ch,2 ; rotate MOD field next to r/m field
+
+
+; UNDONE
+; UNDONE should check for instruction prefixes such as address size prefix
+; UNDONE
+
+ lar ebx,[ebp].regCS ; check if 286 or 386 segment
+ test ebx,00400000h ;
+ mov bl,ch ; get copy of operation
+ jz short Have286segment ; 286 segment - assume 286 addressing
+
+ and ebx,1FH ; Mask to MOD and r/m fields
+ jmp EA386Tab[4*ebx]
+
+pub Have286segment
+ and ebx,1FH ; Mask to MOD and r/m fields
+ jmp EA286Tab[4*ebx]
+
+
+; protect mode Segment override case
+
+glb <protSegOvrTab>
+
+protSegOvrTab label word
+
+ dd DSSegOvr ; 11
+ dd ESSegOvr ; 00
+ dd CSSegOvr ; 01
+ dd SSSegOvr ; 10
+
+
+pub protSegOvr
+ mov edx,ebx ; may use original BX to calc 286 address
+ mov bl,cl
+ shr bl,1
+ and ebx,0Ch ; bl = (seg+1) and 0Ch
+ inc edi ; point to displacement
+ mov cx,[edi-2] ; cx = esc 0-7 and opcode
+ jmp protSegOvrTab[ebx] ; process appropriate segment override
+
+
+pub DSSegOvr ; 00
+ mov es,[ebp].regDS ; set ES to EA segment
+ jmp short ESSegOvr
+
+pub CSSegOvr ; 10
+ push ds ; DS = caller's CS
+ pop es ; set ES to EA segment
+ jmp short ESSegOvr
+
+pub SSSegOvr ; 01
+ push ss ; SS = caller's SS
+ pop es ; set ES to EA segment
+
+pub ESSegOvr ; 11
+ mov [ebp].regSegOvr,es ; save for bp rel EAs
+ jmp CommonDispatch
+
+
+; 386 address modes
+
+; SIB does not handle SS overrides for ebp
+
+SIB macro modval
+ local SIBindex,SIBbase
+
+ xor ebx,ebx
+ mov bl,[edi] ; ebx = SIB field
+ inc edi ; bump past SIB field
+ mov eax,ebx
+ and al,7 ; mask down to base register
+
+if modval eq 0
+ cmp al,5 ; base = ebp
+ jne short SIBbase ; yes - get base register value
+ mov eax,[edi] ; eax = disp32
+ add edi,4 ; bump past displacement
+ jmp short SIBindex
+endif
+
+SIBbase:
+ mov eax,[ebp+4*eax] ; eax = base register value
+
+SIBindex:
+ mov [ebp].regESP,0 ; no esp indexing allowed
+ push ecx ; UNDONE - slow
+ mov cl,bl
+ shr cl,6 ; cl = scale factor
+ shr bl,1
+ and bl,1Ch ; ebx = 4 * index register
+ mov esi,[ebp+ebx] ; esi = index register value
+ shl esi,cl ; esi = scaled index register value
+ pop ecx ; UNDONE - slow
+ add esi,eax ; esi = SIB address value
+ endm
+
+
+pub SIB00
+ SIB 00 ; decode SIB field
+ jmp CommonMemory
+
+pub SIB01
+ SIB 01 ; decode SIB field
+ mov al,[edi]
+ inc edi
+ cbw ; ax = al
+ cwde ; eax = ax
+ add esi,eax
+ jmp short CommonMemory
+
+pub SIB10
+ SIB 10 ; decode SIB field
+ mov eax,[edi]
+ add edi,4
+ add esi,eax
+ jmp short CommonMemory
+
+
+; 386 single register addressing
+
+pub Exx00
+ and bl,1Ch ; mask off mod bits
+ mov esi,[ebp+ebx]
+ jmp short CommonMemory
+
+pub Exx01
+ and bl,1Ch ; mask off mod bits
+ mov esi,[ebp+ebx]
+ mov al,[edi]
+ inc edi
+ cbw ; ax = al
+ cwde ; eax = ax
+ add esi,eax
+ jmp short CommonMemory
+
+pub Exx10
+ and bl,1Ch ; mask off mod bits
+ mov esi,[ebp+ebx]
+ mov eax,[edi]
+ add edi,4
+ add esi,eax
+ jmp short CommonMemory
+
+
+; 386 direct addressing
+
+pub Direct386
+ mov esi,[edi]
+ add edi,4
+
+pub CommonMemory
+ MOV [ebp].regEIP,edi ; final return offset
+ mov ax,LDT_DATA
+ mov ds,ax
+ mov [CURerr],MemoryOperand ; clear current error, set mem. op bit
+
+; At this point ES:SI = memory address, CX = |Op|r/m|MOD|escape|MF|Arith|
+
+ shr ch,4 ; Move Op field to BX for Table jump
+ mov bl,ch
+ and ebx,0EH
+
+ test cl,1 ; Arith field set?
+ JZ short ArithmeticOpMem
+
+pub NonArithOpMem
+ CALL NonArithOpMemTab[2*ebx] ; is CH shl 4 needed?
+ JMP EMLFINISH
+
+pub ArithmeticOpMem
+ PUSH ebx ; Save Op while we load the argument
+ CALL eFLDsdri ; emulate proper load
+ POP ebx
+
+ mov ax,ds ; ES = DS = task data area
+ mov es,ax
+ MOV esi,[CURstk] ; address top of stack
+ MOV edi,esi
+ ChangeDIfromTOStoNOS
+ MOV [RESULT],edi ; Set up destination Pointer
+
+ JMP short DoArithmeticOpPop
+
+
+pub NoEffectiveAddress ; Either Register op or Miscellaneous
+
+ MOV [ebp].regEIP,edi ; final return offset
+
+ xor eax,eax
+ mov di,LDT_DATA
+ mov ds,di
+ mov es,di
+ mov [CURerr],ax ; clear current error, memory op bit
+
+; CX = |Op|r/m|MOD|escape|MF|Arith|
+
+ mov bl,ch
+ shr bl,4 ; Mov Op field to BX for jump
+ and ebx,0Eh
+
+ TEST CL,1 ; Arith field set?
+ JZ short ArithmeticOpReg
+
+pub NonArithOpReg
+ CALL NonArithOpRegTab[2*ebx]
+ JMP EMLFINISH
+
+
+; For register arithmetic operations, one operand is always the stack top.
+; The r/m field of the instruction is used to determine the address of
+; the other operand (ST(0) - ST(7))
+; CX = xxxRRRxxxxxxxxxx (x is don't care, RRR is relative register # 0-7)
+
+pub ArithmeticOpReg
+
+ call RegAddr ;di <= address of 2nd operand
+ ;carry set if invalid register
+ jc short InvalidOperand ;no, invalid operand, don't do operation
+
+ MOV [RESULT],esi ; Set destination to TOS
+ TEST CL,04H ; Unless Dest bit is set
+ JZ short DestIsSet ; in which case
+ MOV [RESULT],edi ; Set destination to DI
+
+pub DestIsSet
+ ; Need to Toggle Reverse bit for DIV or SUB
+ TEST BL,08H ; OP = 1xx for DIV and SUB; BX = |0000|OP|O|
+ JZ short SetUpPop
+ XOR BL,02H ; Toggle Reverse bit
+
+pub SetUpPop
+ TEST CL,02H
+ JZ short DoArithmeticOpNoPop
+
+pub DoArithmeticOpPop
+ CALL ArithmeticOpTab[2*ebx]
+
+ POPST
+ JMP short EMLFINISH
+
+pub DoArithmeticOpNoPop
+ CALL ArithmeticOpTab[2*ebx]
+ JMP short EMLFINISH
+
+
+;*** InvalidOperand - register operand does not exist
+;
+; RETURNS
+; sets Stack Underflow and Invalid bits in [CURerr]
+;
+; DESCRIPTION
+; a reference was made to a register that does not
+; exist on the stack. Set error bits and exit.
+
+pub InvalidOperand
+
+ call UnderStk ;indicate stack underflow error
+ or [CURerr],Invalid ;indicate invalid operand
+ jmp short EMLFINISH ;don't execute instruction
+
+
+;*** RegAddr - compute register address
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; r/m = register whose address is to be computed
+;
+; RETURNS
+; SI = address of top of stack
+; DI = address of requested register
+; PSW.C set if register is not valid
+; PSW.C reset if register is valid
+;
+; DESCRIPTION
+; multiply register number by 12 and subtract this from
+; [CURstk] (the address of TOS) to compute address of
+; register referenced by r/m.
+;
+; REGISTERS
+; modifies dx
+
+pub RegAddr
+ mov esi,[CURstk] ; address top of stack
+ mov edi,esi
+
+;set up address of 2nd operand based on r/m field of instruction
+
+ xor edx,edx
+ mov dl,ch ; dl <== byte containing reg#
+ and dl,01ch ; mask all but r/m field
+
+; Since r/m field contains the relative reg # in bits 2-4 of dl,
+; and bits 0-1 of dl are zero, dl now contains 4*(reg #). To compute
+; the memory location of this register, calculate 12*(reg #) and
+; subtract this from di, which contains the address of the TOS. reg #
+; is multiplied by 12 because that is the number of bytes in each stack
+; entry.
+
+ lea edx,[2*edx+edx] ; edx = 3 * (4 * reg #)
+ sub edi,edx ; di is address of second operand
+ cmp edi,[BASstk] ; is register in range?
+ clc ; assume valid register
+ jg short RAclc ; valid - skip next instruction
+ cmc ; set carry to indicate invalid register
+pub RAclc
+ ret
+
+
+pub CallUnused
+ CALL UNUSED ; Treat as unimpleminted
+ jmp short EMLFINISH
+
+
+; sawFWAIT - UNDONE - workaround for a 386 bug
+
+pub sawFWAIT
+ inc edi ; bump past FWAIT
+ MOV [ebp].regEIP,edi ; final return offset
+ xor eax,eax
+ mov di,LDT_DATA
+ mov ds,di
+ mov [CURerr],ax ; clear current error, memory op bit
+
+; return from routine; restore registers and return
+
+pub EMLFINISH
+ pop eax
+ pop ecx
+ pop edx
+ pop ebx
+ add esp,4 ; toss esp value
+ pop ebp
+ pop esi
+ pop edi
+ add esp,4 ; toss regSegOvr
+
+; check for errors
+
+ MOV AX,[CURerr] ; fetch errors
+ or [UserStatusWord],ax ; save all exception errors
+ OR [SWerr],AL ; set errors in sticky error flag
+ NOT AL ; make a zero mean an error
+ MOV AH,byte ptr [UserControlWord] ; get user's IEEE control word
+ OR AH,0C2H ; mask reserved, IEM and denormal bits
+ AND AH,03FH ; unmask invalid instruction,
+ ; stack overflow.
+ OR AL,AH ; mask for IEEE exceptions
+ NOT AL ; make a one mean an error
+ MOV AH,byte ptr (CURerr+1) ; get stack over/underflow flags
+ TEST AX,0FFFFh-MemoryOperand ; test for errors to report
+
+ pop es
+ pop ds
+
+
+ jnz short ExceptionsEmulator ; goto error handler
+
+pub errret
+ error_return noerror ; common exit sequence
+
+pub ExceptionsEmulator
+ JMP CommonExceptions
+
+
+;------------------------------------------------------------------------------
+;
+; 286 address modes (for XENIX only)
+;
+;------------------------------------------------------------------------------
+
+ifdef XENIX
+
+; In the address calculations below:
+; DX has BX original value
+; AX has DI original value
+; SI has SI original value
+; BP has BP original value
+; [EDI] is address of displacement bytes
+
+pub BXXI0D
+ MOV eax,edx ; use original BX index value
+pub DSDI0D
+ MOV esi,eax ; use alternate index value
+pub DSSI0D
+ JMP short ADRFIN ; have offset in SI
+
+pub BPXI1D
+ XOR eax,eax ; no index register
+pub BPDI1D
+ MOV esi,eax ; use alternate index value
+pub BPSI1D
+ ADD esi,[ebp].regEBP ; add original BP value
+ mov es,[ebp].regSegOvr ; ES = override segment (or SS if none)
+ JMP short DSSI1D ; go get one byte displacement
+
+pub BXSI1D
+ MOV eax,esi ; really will want SI, not DI
+pub BXDI1D
+ ADD edx,eax ; now DX is original BX plus index
+pub BXXI1D
+ MOV eax,edx ; use original BX index value
+pub DSDI1D
+ MOV esi,eax ; use alternate index value
+pub DSSI1D
+ MOV AL,[edi] ; get one byte displacement
+ CBW ; sign extend displacement
+ INC edi ; get past displacement byte
+ JMP short DISPAD ; go add AX to SI (time w/ ADD)
+
+pub BPXI2D
+ XOR eax,eax ; no index register
+pub BPDI2D
+ MOV esi,eax ; use alternate index value
+pub BPSI2D
+ ADD esi,[ebp].regEBP ; add original BP value
+ mov es,[ebp].regSegOvr ; ES = override segment (or SS if none)
+ JMP short DSSI2D ; go get two byte displacement
+
+pub BXSI2D
+ MOV eax,esi ; really will want SI, not DI
+pub BXDI2D
+ ADD edx,eax ; now DX is original BX plus index
+pub BXXI2D
+ MOV eax,edx ; use original BX index value
+pub DSDI2D
+ MOV esi,eax ; use alternate index value
+pub DSSI2D
+ MOV AX,[edi] ; get two byte displacement
+ INC edi ; get past displacement byte
+ INC edi ; get past displacement byte
+ JMP short DISPAD ; go add AX to SI (time w/ ADD)
+
+pub DSXI2D
+ MOV SI,[edi] ; get two byte displacement
+ INC edi ; get past displacement byte
+ INC edi ; get past displacement byte
+ JMP short ADRFIN ; have offset in AX
+
+pub BPSI0D
+ MOV eax,esi ; really will want SI, not DI
+pub BPDI0D
+ MOV edx,[ebp].regEBP ; really will want BP, not BX
+ mov es,[ebp].regSegOvr ; ES = override segment (or SS if none)
+pub BXDI0D
+ MOV esi,eax ; use alternate index value
+pub BXSI0D
+ MOV eax,edx ; use original BX (or BP) as base
+
+pub DISPAD
+ ADD esi,eax ; add original index value
+
+pub ADRFIN
+ movzx esi,si ; ES:ESI = user memory address
+ jmp CommonMemory
+
+endif ;XENIX
diff --git a/private/mvdm/wow16/win87em/emarith.asm b/private/mvdm/wow16/win87em/emarith.asm
new file mode 100644
index 000000000..4c52d65c5
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emarith.asm
@@ -0,0 +1,285 @@
+ page ,132
+ subttl emarith.asm - Arithmetic Operations
+;***
+;emarith.asm -
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Arithmetic Operations
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History: (Also see emulator.hst)
+;
+; 12/19/89 WAJ XORSIGN was not masking the sign bit correctly.
+;
+;*******************************************************************************
+
+;-----------------------------------------------;
+; ;
+; Double precision arithmetic ;
+; ;
+;-----------------------------------------------;
+
+; Inputs:
+; DI = (op1) NOS (Next on stack)
+; SI = (op2) TOS (Top of stack)
+;
+; Functions:
+; ADDRQQ - Addition RESULT <-- [DI] + [SI]
+; SUDRQQ - Subtract RESULT <-- [DI] - [SI]
+; MUDRQQ - Multiply RESULT <-- [DI] * [SI]
+; DIDRQQ - Division RESULT <-- [DI] / [SI]
+; SVDRQQ - Subtract Reversed RESULT <-- [SI] - [DI]
+; DRDRQQ - Division Reversed RESULT <-- [SI] / [DI]
+; Outputs:
+; Destination of result is in RESULT
+; Registers:
+; All except BP destroyed.
+
+; Understanding this code:
+;
+; Assign the symbol S to SI, assign the symbol D to DI.
+;
+; Upon entry: SI <-- S, DI <-- D , Performing D - S
+
+
+ProfBegin ARITH
+
+ even
+
+lab SVDRQQ ; Reverse Subtract
+ MOV DX,Sign*256 ; DH will be flag[SI], prepare to switch sign
+ JMP short DOADD
+
+ even
+
+lab SUDRQQ ; Normal Subtract
+ MOV DX,Sign ; DL will be flag[DI], prepare to switch sign
+ JMP short DOADD
+
+ even
+
+lab MUDRQQ ; Multiplication
+ xor idx,idx ; Do not change signs on entry
+ MOV ibx,offset MULJMPTAB
+ JMP short INITIL
+
+ even
+
+lab DIDRQQ ; Normal Division
+ xor idx,idx
+ XCHG isi,idi ; Make SI - Numerator, DI - Denominator
+ MOV ibx,offset DIVJMPTAB
+ JMP short INITIL
+
+ even
+
+lab DRDRQQ ; Reverse Division
+ xor idx,idx
+ MOV ibx,offset DIVJMPTAB
+ JMP short INITIL
+
+ even
+
+lab ADDRQQ ; Double Precision Add
+ xor idx,idx ; No signs get switched
+lab DOADD
+ MOV ibx,offset ADDJMPTAB
+
+lab INITIL
+ MOV AL,Tag[idi] ; Get tags to determine special cases.
+ SHL AL,1
+ SHL AL,1
+ OR AL,Tag[isi]
+ CBI
+ifdef i386
+ SHL iax,2
+else
+ SHL iax,1
+endif
+ ADD ibx,iax ; BX now points to address of proper routine.
+
+ XOR DH,Flag[idi] ; Sign A
+ XOR DL,Flag[isi] ; Sign B
+ MOV CX,Expon[idi] ; Exponent of operand A
+ MOV AX,Expon[isi] ; Exponent of operand B
+
+ JMP cs:[ibx] ; Go to appropriate routine.
+
+page
+;-----------------------------------------------------------;
+; ;
+; Special Case Routines for Arithmetic Functions ;
+; ;
+;-----------------------------------------------------------;
+
+lab DDD
+ mov isi,idi ;return DI with sign from Add/Subtract
+ mov dl,dh
+
+lab SSS ;Return SI with sign from Add/Subtract
+ call MOVresult
+ MOV Flag[idi],dl ;Overstore correct Sign from Add/Subtract
+ ret
+
+
+lab D0SSINV ;Return SI, set both Invalid and Zerodivide
+ OR [CURerr],ZeroDivide
+ JMP short SSINV
+
+lab DDINV ;Return DI and set Invalid exception
+ MOV isi,idi
+
+lab SSINV ;Return SI and set INVALID exception
+ OR [CURerr],Invalid
+ jmp short MOVresult
+
+
+lab ZEROS ;Return 0 with xor of signs
+ MOV isi,offset IEEEzero
+
+lab XORSIGN
+ XOR DH,DL
+ AND DH,80h ; Mask to just the sign.
+ CALL csMOVresult
+ OR Flag[idi],DH
+ RET
+
+lab DIV0 ;Set exception, Return Infinity signed
+ OR [CURerr],ZeroDivide
+
+lab INFS ;Return signed infinity
+ MOV isi,offset IEEEinfinity
+ JMP XORSIGN
+
+
+lab D0INDINV ;Set div 0 exception, Return Indefinate and Invalid
+ OR [CURerr],ZeroDivide
+
+lab INDINV
+ MOV isi,offset IEEEindefinite
+ OR [CURerr],Invalid
+
+lab csMOVresult
+ mov idi,[RESULT]
+
+lab csMOVRQQ ; as above for constants in CS
+ifdef i386
+ MOVS dword ptr es:[idi],dword ptr cs:[isi]
+ MOVS dword ptr es:[idi],dword ptr cs:[isi]
+ MOVS dword ptr es:[idi],dword ptr cs:[isi]
+else
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+ MOVS word ptr es:[idi],word ptr cs:[isi]
+endif
+ SUB idi,Reg87Len
+ SUB isi,Reg87Len
+ RET
+
+
+lab MOVresult
+ mov idi,[RESULT] ; move to result
+ cmp isi,idi
+ je short MOVret ; unless the same
+
+lab MOVRQQ
+ifdef i386
+ MOVS dword ptr es:[idi],dword ptr ds:[isi]
+ MOVS dword ptr es:[idi],dword ptr ds:[isi]
+ MOVS dword ptr es:[idi],dword ptr ds:[isi]
+else
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+ MOVS word ptr es:[idi],word ptr ds:[isi]
+endif
+ SUB idi,Reg87Len
+ SUB isi,Reg87Len
+
+lab MOVret
+ RET
+
+
+lab INFINF ; Addition of two infinities was attempted
+ TEST [CWcntl],InfinityControl ; Invalid if projective closure
+ JSZ INDINV
+ XOR DL,DH ; Invalid if signs are different
+ JSS INDINV
+ JMP DDD ; Otherwise Inf is the answer, already at DI
+
+lab BIGNAN ; Return the NAN with the Bigger mantissa
+ mov iax, isi
+ mov ibx, idi
+
+ add isi, MantissaByteCnt-2 ; UNDONE387: Convert SNAN to QNAN
+ add idi, MantissaByteCnt-2
+ mov icx, MantissaByteCnt/2
+ std
+ repe cmps word ptr ds:[isi], word ptr es:[idi]
+ cld
+ JSB DDNAN
+
+ mov isi, iax ; Greater NAN was in si
+ jmp SSINV
+
+lab DDNAN
+ mov isi, ibx ; Greater NAN was in di
+ jmp SSINV
+
+page
+
+if fastSP
+
+ifdef i386
+ BUG ; fastsp and i386 do not work together
+endif
+
+;Assumes DL = Flag[SI], DH = Flag[DI]. Will convert the mantissa on
+;stack to double if necessary by appending zeros.
+;Must not change AX, DX, SI, DI.
+
+lab CoerceToDouble
+ MOV BX,DX ; get to work reg
+ AND BX,Single + 256*Single ; mask to single flags only
+ JSNZ CheckDI
+
+lab CoerceToDoubleReturn
+ RET
+
+lab CheckDI
+ XOR BX,BX ; Prepare to zero out mantissa
+ XCHG AX,BX
+ TEST DH,Single
+ JSZ CheckSI
+ STOSW ; Zero out lower five bytes
+ STOSW
+ STOSB
+ SUB DI,5 ; Reset DI
+
+lab CheckSI
+ TEST DL,Single
+ JZ short ExitCoerceToDouble
+ XCHG DI,SI
+ STOSW ; Zero out lower five bytes
+ STOSW
+ STOSB
+ SUB DI,5 ; Reset DI
+ XCHG DI,SI
+
+lab ExitCoerceToDouble
+ XCHG AX,BX ; Reset AX
+ XOR BX,BX ; Set zero flag to indicate results now double
+ RET
+
+endif ;fastSP
+
+ProfEnd ARITH
diff --git a/private/mvdm/wow16/win87em/emconst.asm b/private/mvdm/wow16/win87em/emconst.asm
new file mode 100644
index 000000000..eab330073
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emconst.asm
@@ -0,0 +1,165 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986-88
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emconst.asm - Constants
+page
+;*********************************************************************;
+; ;
+; Constants ;
+; ;
+;*********************************************************************;
+
+; internally used constants
+
+ EVEN
+
+
+labelW IEEEzero
+ dw 0,0,0,0 ; Mantissa of 0
+ dw IexpMin - IexpBias ; Smallest Exponent
+ db 0 ; Sign positive, not single precision
+ db ZROorINF ; Number is ZERO
+
+
+labelW IEEEinfinity
+ dw 0,0,0,0 ; Mantissa of 0
+ dw IexpMax - IexpBias ; Largest exponent
+ db 0 ; Sign positive, not single precision
+ db Special + ZROorINF
+
+
+labelW IEEEindefinite
+ dw 0,0,0,0C000H ; MSB Turned on in mantissa
+ dw IexpMax - IexpBias ; Largest exponent
+ db 080H ; Sign negative, not single precision
+ db Special
+
+
+labelW IEEEbiggest
+ dw 0FFFFH,0FFFFH,0FFFFH,0FFFFH ; Turn on Mantissa
+ dw IexpMax - IexpBias - 1 ; Largest valid exponent
+ db 0 ; Sign positive, not single precision
+ db 0 ; Valid non-zero, non-special number
+
+
+
+labelW IEEEinfinityS
+ dw 0, 7f80h ; Sign 0, Exp 1's, Mantissa 0
+
+
+labelW IEEEbiggestS
+ dw 0ffffh, 7f7fh ; Sign 0, Exp Max - 1, Mantissa 1's
+
+
+labelW IEEEinfinityD
+ dw 0, 0, 0 ; Mantissa of 0
+ dw 7ff0h ; Largest exponent
+
+
+labelW IEEEbiggestD
+ dw 0ffffh, 0ffffh, 0ffffh ; Turn on Mantissa
+ dw 7fefh ; Largest exponent - 1
+
+
+; transcendental constants
+
+labelW cFLDZ
+ dw 00000h, 00000h, 00000h, 08000h, IexpMin-IexpBias, 00100h
+
+labelW cFLD1
+ dw 00000h, 00000h, 00000h, 08000h, 00000h, 00000h
+
+
+ifndef frontend
+ifndef SMALL_EMULATOR
+
+
+labelW TWOMRT3
+ dw 0B18AH,0F66AH,0A2F4H,08930H,0FFFEH,00000H
+
+labelW RT3
+ dw 0539EH,0C265H,0D742H,0DDB3H,00000H,00000H
+
+labelW PIBY6
+ dw 02C23H,06B9BH,091C1H,0860AH,0FFFFH,00000H
+
+labelW RT2
+ dw 06484H,0F9DEH,0F333H,0B504H,00000H,00000H
+
+labelW TWO
+ dw 00000H,00000H,00000H,08000H,00001H,00000H
+
+labelW cFLDPI
+ dw 0C235H,02168H,0DAA2H,0C90FH,00001H,00000H
+
+labelW cFLDL2T
+ dw 08AFEH,0CD1BH,0784BH,0D49AH,00001H,00000H
+
+labelW cFLDL2E
+ dw 0F0BCH,05C17H,03B29H,0B8AAH,00000H,00000H
+
+labelW cFLDLG2
+ dw 0F799H,0FBCFH,09A84H,09A20H,0FFFEH,00000H
+
+labelW cFLDLN2
+ dw 079ACH,0D1CFH,017F7H,0B172H,0FFFFH,00000H
+
+
+labelW TANRAT
+ dw 3
+ dw 07BD4H,0D85AH,05C3EH,08F69H,00005H,00080H
+ dw 04D37H,02CD7H,0D0F8H,0D6D4H,0000CH,00000H
+ dw 0DCD3H,06617H,0BBEEH,082BAH,00012H,00080H
+ dw 091CBH,05E58H,0868BH,0F506H,00014H,00000H
+ dw 3
+ dw 086E5H,00120H,00502H,09C79H,00009H,00080H
+ dw 06663H,088CFH,0B270H,0C939H,0000FH,00000H
+ dw 0FA96H,0C746H,00CFEH,0E4B7H,00013H,00080H
+ dw 091CBH,05E58H,0868BH,0F506H,00014H,00000H
+
+
+labelW ATNRAT
+ dw 4
+ dw 05B32H,0CF08H,0A4C9H,0A650H,0FFFDH,00000H
+ dw 0D1CEH,0D5CAH,0A84BH,0D0F0H,00002H,00000H
+ dw 0899FH,0E22BH,052A8H,09C4AH,00005H,00000H
+ dw 04265H,05550H,0E9CFH,090EFH,00006H,00000H
+ dw 04B90H,024ADH,0E5E6H,0A443H,00005H,00000H
+ dw 3
+ dw 08310H,05638H,04F0AH,0F062H,00003H,00000H
+ dw 0B4E7H,06D1EH,05190H,0EE50H,00005H,00000H
+ dw 0243BH,05B6DH,09020H,0AC50H,00006H,00000H
+ dw 04B90H,024ADH,0E5E6H,0A443H,00005H,00000H
+
+
+
+labelW EXPRAT
+ dw 2
+ dw 01898H,0F405H,006FCH,0F274H,00005H,00000H
+ dw 0AD08H,014E1H,03D54H,0EC9BH,0000EH,00000H
+ dw 05FAFH,0C3A3H,0D84AH,0FDF0H,00014H,00000H
+ dw 2
+ dw 0776FH,0387BH,0108BH,0DAA7H,0000AH,00000H
+ dw 0E85DH,09B7BH,0B182H,0A003H,00012H,00000H
+ dw 0837EH,0E709H,0F814H,0B72DH,00016H,00000H
+
+
+labelW LOGRAT
+ dw 3
+ dw 07704H,0C299H,057E2H,09B71H,0FFFEH,00000H
+ dw 04F9CH,0F631H,05E35H,0DE91H,00004H,00080H
+ dw 04B8AH,07AEAH,0C9EDH,0B2D3H,00008H,00000H
+ dw 028C9H,01D09H,0E42FH,08AC4H,0000AH,00080H
+ dw 2
+ dw 076BBH,03E70H,0025BH,08EACH,00005H,00080H
+ dw 0EF60H,0A933H,01FD0H,09C04H,00008H,00000H
+ dw 0BB96H,06C83H,0F4E0H,0C05FH,00009H,00080H
+
+
+endif ;not SMALL_EMULATOR
+endif ;frontend
diff --git a/private/mvdm/wow16/win87em/emdecode.asm b/private/mvdm/wow16/win87em/emdecode.asm
new file mode 100644
index 000000000..44a0d4433
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emdecode.asm
@@ -0,0 +1,256 @@
+ page ,132
+ subttl emdecode.asm - Instruction decoding
+;***
+;emdecode.asm - Instruction decoding
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Instruction decoding.
+; Further decoding of instructions done here.
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+ProfBegin DECODE
+
+ even
+
+pub eFLDsdri
+ MOV BX,CX ; Dispatch on MF
+ AND ebx,6H
+ifdef i386
+ JMP FLDsdriTab[2*ebx]
+else
+ JMP FLDsdriTab[ebx]
+endif
+
+pub eFSTsdri
+ MOV BX,CX ; Dispatch on MF
+ AND ebx,6H
+ifdef i386
+ JMP FSTsdriTab[2*ebx]
+else
+ JMP FSTsdriTab[ebx]
+endif
+
+ even
+
+pub eFSTPsdri
+ mov bx, cx ; Dispatch on MF
+ and ebx, 6h
+
+ifdef i386
+ call FSTsdriTab[2*ebx]
+else
+ call FSTsdriTab[ebx]
+endif
+ mov esi, [CURstk]
+ cmp esi, [BASstk] ; Do we have an empty stack?
+ jbe short FSTPSTUnder ; Yes, Underflow.
+FSTPSTOk:
+ sub esi, Reg87Len ; decrement SI to previous register
+ mov [CURstk], esi ; set current top of stack
+ ret
+
+FSTPSTUnder:
+ call UnderStk ; stack underflow error
+ jmp FSTPSTOk
+
+
+pub eFLDtempORcw
+ MOV BX,CX ; Dispatch on MF
+ AND ebx,6H
+ifdef i386
+ JMP FLDtempORcwTab[2*ebx]
+else
+ JMP FLDtempORcwTab[ebx]
+endif
+
+pub eFSTtempORcw
+ MOV BX,CX ; Dispatch on MF
+ AND ebx,6H
+ifdef i386
+ JMP FSTtempORcwTab[2*ebx]
+else
+ JMP FSTtempORcwTab[ebx]
+endif
+
+pub eFLDregOrFFREE ; We only emulate FLD ST (Duplicate TOS)
+;CX = |Op|r/m|MOD|esc|MF|Arith|
+
+ test cx,06h ; test MF. MF=01 is FFREE, MF=00 is FLD ST(i)
+ jnz short jmpeFFREE ; go emulate FFREE
+ jmp eFLDreg ; emulate FLD ST(i)
+jmpeFFREE:
+ jmp eFFREE ; emulate FFREE ST(i)
+
+pub eMISCELANEOUS ; We only emulate FCHS, FABS, FTST, & FXAM
+ ; FCLEX is emulated in non-IBM version
+ TEST CX,0806H ; We already have match on Op,MOD,&Arith
+ jz short MFzero ; MF = 0, must be FCHS, FABS, FTST or FXAM
+ ; check for FCLEX (cx = 8B03)
+ xor cx,00203h ; toggle low bit of MF and middle bit of r/m
+ test cx,00603h ; test for zero in MF and r/m fields
+
+ jnz short jnzUNUSED ; MF <> 01 and/or r/m <> 010 => unemulated
+
+ cmp cx,8104h ; check for FSTSW AX
+ je short eFSTSWAX ; yes
+
+ mov [StatusWord],0 ; FCLEX: clear status word
+ ret
+
+pub eFSTSWAX
+ifdef XENIX
+ xor eax,eax ; UNDONE - set to non-zero - cleanup code
+else
+ push sp ; test for 286 !!!
+ pop ax
+ cmp ax,sp
+endif
+pub jnzUNUSED
+ jnz UNUSED ; UNUSED if not 286
+
+ mov ax,[StatusWord] ; FSTSW AX: save status word in AX
+ mov [ebp].regAX,ax ; overwrite AX stack entry
+ ret
+
+MFzero:
+ TEST CX,1000H
+ JZ short FABSorFCHS
+ TEST CX,0400H ; r/m = 101 for FXAM
+ JNZ short JMPeFXAM ; r/m = 100 for FTST
+ JMP eFTST
+
+pub JMPeFXAM
+ JMP eFXAM
+
+pub FABSorFCHS
+ TEST CX,0400H ; r/m = 001 for FABS
+ JNZ short JMPeFABS ; r/m = 000 for FCHS
+ JMP eFCHS
+
+pub JMPeFABS
+ JMP eFABS
+
+pub eFLDconstants
+ MOV BL,CH ; Mov r/m field to BX for jump
+ SHR BL,1
+ AND ebx,0EH
+ifdef i386
+ JMP FLDconstantsTab[2*ebx]
+else
+ JMP FLDconstantsTab[ebx]
+endif
+
+pub eTranscendental
+ MOV BL,CH ; Mov r/m field to BX for jump
+ SHR BL,1
+ AND ebx,0EH
+ifdef i386
+ JMP TranscendentalTab[2*ebx]
+else
+ JMP TranscendentalTab[ebx]
+endif
+
+pub eVARIOUS
+ MOV BL,CH ; Mov r/m field to BX for jump
+ SHR BL,1
+ AND ebx,0EH
+ifdef i386
+ JMP VariousTab[2*ebx]
+else
+ JMP VariousTab[ebx]
+endif
+
+
+pub eFXCHGreg ; only valid FXCHG is with r/m = 001, MF = 00
+ TEST CX,06h ; only valid FXCHG is with MF = 0
+ JNZ short UNUSED ; unemulated
+ JMP eFXCHG ; emulate FXCH ST(i)
+
+
+pub eFSTPreg
+ xor cl,04h ; test for MF = 10, valid encoding of FSTP ST(x)
+ test cx,06h
+ jne short UNUSED ; MF <> 10, no such instruction
+ mov ax,1 ; indicate stack should be popped after xfer
+ jmp eFST_Preg ; emulate FSTP ST(x)
+
+
+;*** eFSTreg - decode FST ST(i),FNOP
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+;
+; DESCRIPTION
+; All parts of the instruction except MF and r/m have already
+; been decoded. If MF=0, the instruction is FNOP, which is
+; unemulated. Otherwise, clear AX to indicate FST ST(i), then
+; jump to eFST_Preg, the common emulator routine for
+; FST ST(i) and FSTP ST(i).
+;
+
+eFSTreg:
+ test cl,06h ;test for MF = 0
+ jz short UNUSED ;MF=0 ==> FNOP, which is unemulated
+ ;otherwise this is FST ST(i)
+ xor ax,ax ;clear ax to indicate FST ST(i), not FSTP ST(i)
+ jmp eFST_Preg ; emulate FSTP ST(x)
+
+
+; This sets the error flag indicating Unemulated functions
+
+eFXTRACT:
+eFDECSTP:
+eFINCSTP:
+
+
+ifdef frontend ; unused instructions for frontend version
+
+eFLDL2T:
+eFLDL2E:
+eFLDPI:
+eFLDLG2:
+eFLDLN2:
+
+eFPREM:
+eF2XM1:
+eFYL2X:
+eFPTAN:
+eFPATAN:
+eFYL2XP1:
+eFSQRT:
+
+endif ;frontend
+
+ifdef SMALL_EMULATOR
+
+eFLDL2T:
+eFLDL2E:
+eFLDPI:
+eFLDLG2:
+eFLDLN2:
+
+eFPREM:
+eF2XM1:
+eFYL2X:
+eFPTAN:
+eFPATAN:
+eFYL2XP1:
+eFSQRT:
+
+endif ;SMALL_EMULATOR
+
+
+pub UNUSED
+ OR [CURerr],Unemulated
+ RET
+
+ProfEnd DECODE
diff --git a/private/mvdm/wow16/win87em/emdisp.asm b/private/mvdm/wow16/win87em/emdisp.asm
new file mode 100644
index 000000000..304ce0390
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emdisp.asm
@@ -0,0 +1,356 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emdisp.asm - Dispatch Tables
+page
+;*********************************************************************;
+; ;
+; Dispatch Tables ;
+; ;
+;*********************************************************************;
+
+; dispatch tables
+
+; These tables are based upon the layout of the 8087 instructions
+;
+; 8087 instruction fields: |escape|MF|Arith|MOD|Op|r/m|disp1|disp2|
+; field length in bits: 5 2 1 2 3 3 8 8
+;
+; Disp1 and Disp2 are optional address bytes present only if MOD <> 11.
+; When (MOD <> 11) r/m describes which regs (SI,DI,BX,BP) are added to
+; Disp1 and Disp2 to calculate the effective address. This form
+; (memory format) is used for Loads, Stores, Compares, and Arithmetic
+; When using memory format MF determines the Type of the Memory operand
+; i.e. Single Real, Double real, Single Integer, or Double Integer
+; Arith is 0 for Arithmetic opetations (and compares), set to 1 otherwise
+; Op mostly determines which type of operation to do though when not in
+; memory format some of that is coded into MF and r/m
+; All of the tables are set up to do a jump based upon one or more of the
+; above fields. The outline for decoding instructions is:
+;
+; IF (memory format) THEN
+; Assemble Effective Address (using MOD and r/m and EffectiveAddressTab)
+; IF (Arith) THEN
+; Load to the stack (using MF and FLDsdriTab)
+; Do the Arithmetic Operation (using Op and ArithmeticOpTab)
+; ELSE (memory format non- arithmetic)
+; Do the operation (using Op and NonArithOpMemTab and
+; depending on the case MF and one of the FLD or FST Tabs)
+; ENDIF
+; ELSE (Register format)
+; IF (Arith) THEN
+; Test r/m for legit Stack reference
+; Do the Arithmetic Operation (using Op and ArithmeticOpTab)
+; ELSE (non-arithmetic register format)
+; Do the operation (using Op and NonArithOpRegTab and
+; depending on the case r/m and one of:
+; Constants, Miscellaneous, Transcendental, or Various Tabs)
+
+ EVEN
+
+glb <EA286Tab>
+
+eWORD EA286Tab ; Uses |r/m|MOD| for indexing
+ edw BXSI0D
+ edw BXSI1D
+ edw BXSI2D
+ edw NoEffectiveAddress
+ edw BXDI0D
+ edw BXDI1D
+ edw BXDI2D
+ edw NoEffectiveAddress
+ edw BPSI0D
+ edw BPSI1D
+ edw BPSI2D
+ edw NoEffectiveAddress
+ edw BPDI0D
+ edw BPDI1D
+ edw BPDI2D
+ edw NoEffectiveAddress
+ edw DSSI0D
+ edw DSSI1D
+ edw DSSI2D
+ edw NoEffectiveAddress
+ edw DSDI0D
+ edw DSDI1D
+ edw DSDI2D
+ edw NoEffectiveAddress
+ edw DSXI2D
+ edw BPXI1D
+ edw BPXI2D
+ edw NoEffectiveAddress
+ edw BXXI0D
+ edw BXXI1D
+ edw BXXI2D
+ edw NoEffectiveAddress
+
+
+ifdef i386
+
+glb <EA386Tab>
+
+eWORD EA386Tab ; Uses |r/m|MOD| for indexing
+
+ edw Exx00 ; eax
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw Exx00 ; ecx
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw Exx00 ; edx
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw Exx00 ; ebx
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw SIB00 ; esp (S-I-B follows)
+ edw SIB01
+ edw SIB10
+ edw NoEffectiveAddress
+ edw Direct386 ; ebp (00 = direct addressing)
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw Exx00 ; esi
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+ edw Exx00 ; edi
+ edw Exx01
+ edw Exx10
+ edw NoEffectiveAddress
+
+endif ;i386
+
+
+glb <ArithmeticOpTab>
+
+eWORD ArithmeticOpTab ; Uses |Op| for indexing
+ edw ADDRQQ ;FADD
+ edw MUDRQQ ;FMUL
+ edw eFCOM ;FCOM
+ edw eFCOMP ;FCOMP
+ edw SUDRQQ ;FSUB
+ edw SVDRQQ ;FSUBR
+ edw DIDRQQ ;FDIV
+ edw DRDRQQ ;FDIVR
+
+
+glb <NonArithOpMemTab>
+
+eWORD NonArithOpMemTab ; Uses |Op| for indexing
+ edw eFLDsdri ;load(single/double,real/integer)
+ edw UNUSED ;reserved
+ edw eFSTsdri ;Store(single/double,real/integer)
+ edw eFSTPsdri ;Store and POP (single/double,real/integer)
+ edw UNUSED ;reserved
+ edw eFLDtempORcw ;Load(TempReal or LongInteger), FLDCW
+ edw UNUSED ;reserved
+ edw eFSTtempORcw ;Store(TempReal or LongInteger), FSTCW ,FSTSW
+
+
+glb <NonArithOpRegTab>
+
+eWORD NonArithOpRegTab ; Uses |Op| for indexing
+ edw eFLDregOrFFREE ;load(register), FFREE
+ edw eFXCHGreg ;FXCHG
+ edw eFSTreg ;Store(register),FNOP
+ edw eFSTPreg ;Store and POP (register)
+ edw eMISCELANEOUS ;FCHS, FABS, FTST, FXAM, FINIT, FENI, FDISI, FCLEX
+ edw eFLDconstants ;FLD1, FLDL2T, FLDL2E, FLDPI, FLDLG2, FLDLN2, FLDZ
+ edw etranscendental ;F2XM1, FYL2X, FPTAN, FPATAN, FXTRACT, FDECSTP, FINCSTP
+ edw eVARIOUS ;FPREM, FYL2XP1, FSQRT, FRNDINT, FSCALE
+
+
+glb <FLDsdriTab>
+
+eWORD FLDsdriTab ; Uses |MF| for indexing
+ edw eFLDsr ;load single real
+ edw eFLDdi ;load double integer
+ edw eFLDdr ;load double real
+ edw eFLDsi ;load single integer
+
+
+glb <FSTsdriTab>
+
+eWORD FSTsdriTab ; Uses |MF| for indexing
+ edw eFSTsr ;store single real
+ edw eFSTdi ;store double integer
+ edw eFSTdr ;store double real
+ edw eFSTsi ;store single integer
+
+
+glb <FLDtempORcwTab>
+
+eWORD FLDtempORcwTab ; Uses |MF| for indexing
+ edw eFLDCW ;load control word
+ edw eFLDtemp ;load temp real
+ edw UNUSED ;reserved
+ edw eFLDlongint ;load long integer
+
+
+glb <FSTtempORcwTab>
+
+eWORD FSTtempORcwTab ; Uses |MF| for indexing
+ edw eFSTCW ;store control word
+ edw eFSTtemp ;store temp real
+ edw eFSTSW ;store status word
+ edw eFSTlongint ;store long integer
+
+
+glb <FLDconstantsTab>
+
+eWORD FLDconstantsTab ; Uses |r/m| for indexing
+ edw eFLD1
+ edw eFLDL2T
+ edw eFLDL2E
+ edw eFLDPI
+ edw eFLDLG2
+ edw eFLDLN2
+ edw eFLDZ
+ edw UNUSED ;reserved
+
+
+glb <TranscendentalTab>
+
+eWORD TranscendentalTab ; Uses |r/m| for indexing
+ edw eF2XM1
+ edw eFYL2X
+ edw eFPTAN
+ edw eFPATAN
+ edw eFXTRACT
+ edw UNUSED ;reserved
+ edw eFDECSTP
+ edw eFINCSTP
+
+
+glb <VariousTab>
+
+eWORD VariousTab ; Uses |r/m| for indexing
+ edw eFPREM
+ edw eFYL2XP1
+ edw eFSQRT
+ edw UNUSED ;reserved
+ edw eFRNDINT
+ edw eFSCALE
+ edw UNUSED ;reserved
+ edw UNUSED ;reserved
+
+
+glb <COMtab>
+
+eWORD COMtab ; SI DI
+ edw COMvalidvalid ; valid valid
+ edw COMsignSI ; valid zero
+ edw COMincomprable ; valid NAN
+ edw COMsignDIinf ; valid INF
+ edw COMsignDI ; zero valid
+ edw COMequal ; zero zero
+ edw COMincomprable ; zero NAN
+ edw COMsignDIinf ; zero INF
+ edw COMincomprable ; NAN valid
+ edw COMincomprable ; NAN zero
+ edw COMincomprable ; NAN NAN
+ edw COMincomprable ; NAN INF
+ edw COMsignSIinf ; INF valid
+ edw COMsignSIinf ; INF zero
+ edw COMincomprable ; INF NAN
+ edw COMinfinf ; INF INF
+
+
+glb <TSTtab>
+
+eWORD TSTtab
+ edw COMsignSI ; valid
+ edw COMequal ; zero
+ edw COMincomprable ; NAN
+ edw COMsignSIinf ; INF
+
+
+glb <ADDJMPTAB>
+
+eWORD ADDJMPTAB
+eWORD TAJRQQ
+ edw RADRQQ ; 0000 D Valid non-0, S Valid non-0
+ edw DDD ; 0001 D Valid non-0, S 0
+ edw SSINV ; 0010 D Valid non-0, S NAN
+ edw SSS ; 0011 D Valid non-0, S Inf
+ edw SSS ; 0100 D 0, S Valid non-0
+ edw DDD ; 0101 D 0, S 0
+ edw SSINV ; 0110 D 0, S NAN
+ edw SSS ; 0111 D 0, S Inf
+ edw DDINV ; 1000 D NAN, S Valid non-0
+ edw DDINV ; 1001 D NAN, S 0
+ edw BIGNAN ; 1010 D NAN, S NAN
+ edw DDINV ; 1011 D NAN, S Inf
+ edw DDD ; 1100 D Inf, S Valid non-0
+ edw DDD ; 1101 D Inf, S 0
+ edw SSINV ; 1110 D Inf, S NAN
+ edw INFINF ; 1111 D Inf, S Inf
+
+
+glb <MULJMPTAB>
+
+eWORD MULJMPTAB
+eWORD TMJRQQ
+ edw RMDRQQ ; 0000 D Valid non-0, S Valid non-0
+ edw ZEROS ; 0001 D Valid non-0, S 0
+ edw SSINV ; 0010 D Valid non-0, S NAN
+ edw INFS ; 0011 D Valid non-0, S Inf
+ edw ZEROS ; 0100 D 0, S Valid non-0
+ edw ZEROS ; 0101 D 0, S 0
+ edw SSINV ; 0110 D 0, S NAN
+ edw INDINV ; 0111 D 0, S Inf
+ edw DDINV ; 1000 D NAN, S Valid non-0
+ edw DDINV ; 1001 D NAN, S 0
+ edw BIGNAN ; 1010 D NAN, S NAN
+ edw DDINV ; 1011 D NAN, S Inf
+ edw INFS ; 1100 D Inf, S Valid non-0
+ edw INDINV ; 1101 D Inf, S 0
+ edw SSINV ; 1110 D Inf, S NAN
+ edw INFS ; 1111 D Inf, S Inf
+
+
+glb <DIVJMPTAB>
+
+eWORD DIVJMPTAB
+eWORD TDJRQQ
+ edw RDDRQQ ; 0000 D Valid non-0, S Valid non-0
+ edw ZEROS ; 0001 D Valid non-0, S 0
+ edw SSINV ; 0010 D Valid non-0, S NAN
+ edw INFS ; 0011 D Valid non-0, S Inf
+ edw DIV0 ; 0100 D 0, S Valid non-0
+ edw D0INDINV ; 0101 D 0, S 0
+ edw D0SSINV ; 0110 D 0, S NAN
+ edw DIV0 ; 0111 D 0, S Inf
+ edw DDINV ; 1000 D NAN, S Valid non-0
+ edw DDINV ; 1001 D NAN, S 0
+ edw BIGNAN ; 1010 D NAN, S NAN
+ edw DDINV ; 1011 D NAN, S Inf
+ edw ZEROS ; 1100 D Inf, S Valid non-0
+ edw ZEROS ; 1101 D Inf, S 0
+ edw SSINV ; 1110 D Inf, S NAN
+ edw INDINV ; 1111 D Inf, S Inf
+
+
+glb <XAMtab>
+
+ ; Tag Flag C3 C2 C1 C0 meaning
+XAMtab DB 04H ; 00 0 0 1 0 0 Positive Normal
+ DB 06H ; 00 1 0 1 1 0 Negative Normal
+ DB 40H ; 01 0 1 0 0 0 Positive Zero
+ DB 42H ; 01 1 1 0 1 0 Negative Zero
+ DB 01H ; 10 0 0 0 0 1 Positive NAN
+ DB 03H ; 10 1 0 0 1 1 Negative NAN
+ DB 05H ; 11 0 0 1 0 1 Positive Infinity
+ DB 07H ; 11 1 0 1 1 1 Negative Infinity
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/win87em/emdoc.asm b/private/mvdm/wow16/win87em/emdoc.asm
new file mode 100644
index 000000000..65052e563
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emdoc.asm
@@ -0,0 +1,83 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emdoc.asm - Documentation
+page
+;--------------------------------------------------------------------
+;
+; WARNING - This may not be accurate for the stand-alone emulator.
+;
+; Glossary:
+; TOS - top-of-stack (e.g. simulated 8087 register stack)
+; single - single precision real number in one of two formats:
+; memory (IEEE), internal (on stack, see below)
+; double - double precision real number in one of two formats:
+; memory (IEEE), internal (on stack, see below).
+;
+; This source is organized into the following sections:
+; 1. Introductory documentation of instructions and data structures
+; 2. External routines, data segment, and const segment definitions
+; 3. Startup and terminate, utility truncTOS
+; 4. User memory macros
+; 5. Macros and procedures for stack push and pop, error handling
+; 6. Main entry point and effective address calculation routine
+;
+; Assumptions about segment usage:
+; SS = user's stack
+; DS = user's emulator data segment (not user's DS)
+; ES = effective address segment for memory operands
+; = user's emulator data segment (all other times)
+;
+; BASstk is DS offset of the stack base
+; CURstk is DS offset of the current register (TOS).
+; LIMstk is DS offset of LAST reg in stack
+;
+; CURerr has internal exception flag byte (<>0 iff exception occured).
+; UserControlWord has user set values
+; ControlWord has remapped version of UserControlWord
+; CWcntl (high byte of ControlWord) has Rounding, precision, Inf modes
+;
+; Macros:
+; PUSHST allocates a new 12 byte register, and POPST frees one.
+; Both return an address in SI and save all other 8086 registers.
+;
+; Five macros handle all data movement between user memory and local
+; memory or registers.
+;
+; Note standard forms:
+;
+; Bits are counted from least significant; bit 0 is 1's, bit 7 is 128's.
+;
+; IEEE format is used, naturally, for values in user memory:
+;
+; IEEE single precision:
+; +0: least significant byte of mantissa
+; +1: next sig. byte of mant.
+; +2: bits 6..0: most sig. bits of mant.
+; +2: bit 7: low order bit of exponent
+; +3: bits 6..0: rest of exponent
+; +3: bit 7: sign bit
+; mantissa does not include "hidden bit".
+; with hidden bit, mantissa value is 1.0 to 2.0
+; exponent is in biased form, with bias of 127
+; exponent of all 0's means a value of zero
+; exponent of all 1's means a value of "indefinite"
+;
+; IEEE double precision:
+; +0: least significant byte of mantissa
+; +1..+5 next sig. bytes of mant.
+; +6: bits 3..0 (lo nibble): most sig. bits of mant.
+; +6: bits 7..4 (hi nibble): least sig. bits of exp.
+; +7: bits 6..0: most sig. bits of exponent
+; +7: bit 7: sign bit
+; mantissa does not include "hidden bit".
+; with hidden bit, mantissa value is 1.0 to 2.0
+; exponent is in biased form, with bias of 1023
+; exponent of all 0's means a value of zero or Denormal
+; exponent of all 1's means a value of NAN or Infinity
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/win87em/emdos.asm b/private/mvdm/wow16/win87em/emdos.asm
new file mode 100644
index 000000000..28ba034ea
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emdos.asm
@@ -0,0 +1,979 @@
+ page ,132
+ subttl emdos.asm - Initialization and Termination
+;***
+;emdos.asm - Initialization and Termination
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Initialization and Termination
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History: (Also see emulator.hst)
+;
+; 12-10-89 WAJ Added MTHREAD DS == 0 check.
+;
+;*******************************************************************************
+
+
+comment !
+
+DOS interfaces to emulator/8087 functions
+
+Certain emulator/8087 functions are performed by calling __fpmath
+with an function code and arguments.
+
+__fpmath general floating point math package interface used
+ by the emulator/8087 and float calls interfaces. This
+ is a far routine and must be far called.
+
+entry:
+
+ bx = 0 initialize floating point math
+ dx:ax = task data area (dx = segment , ax = size)
+ extra size is used to increase floating point stack
+ (can pass segmented address of __fptaskdata in dx:ax)
+ si = environment segment
+ returns:
+ ax = 0 if successful and using software floating point
+ 1 if successful and using 8087
+ negative if error
+
+ bx = 1 reset (FINIT)
+
+ bx = 2 terminate floating point math
+
+ bx = 3 set error signal address
+ dx:ax = segment:offset of user error handler
+
+ bx = 4 load user control word
+ (user should not use FLDCW instruction directly)
+ ax = user control word value
+
+ bx = 5 store user control word
+ returns:
+ ax = user control word value
+
+ bx = 6 truncate TOS to integer TOS
+ ax = user control word (only use round mode)
+
+ bx = 7 truncate TOS to 32-bit integer in DX:AX
+ ax = user control word (only use round mode)
+
+ bx = 8 store user status word
+ returns:
+ ax = user status word value
+
+ bx = 9 clear exceptions
+
+ bx = 10 return number of stack elements in ax
+
+ bx = 11 returns 1 if using 80x87, 0 if not
+
+ bx = 12 if ax = 0, turn off extended stack. if ax = 1, turn on e.s.
+
+QB3 version
+
+ bx = 0 init, ax = initCW, es = PSP
+ bx = 1 reset
+ bx = 2 term
+ bx = 3 set vectors
+ bx = 4 reset vectors
+
+!
+
+glb <functab>
+
+functab label word
+
+ dw initialization ; 0 - initialize emulator/8087
+ dw reset ; 1 - reset emulator/8087 stack
+ dw termination ; 2 - terminate emulator/8087
+
+ifdef QB3
+
+ dw set_vectors ; 3 - set interrupt vectors
+ dw rst_vectors ; 4 - reset interrupt vectors
+
+SizeJmpTab equ 4
+
+else ;not QB3
+ dw setsignal ; 3 - set error signal address
+
+ dw loadcontrolword ; 4 - load user control word
+ dw storecontrolword ; 5 - store user control word
+ dw truncateTOS ; 6 - truncate TOS to integer TOS
+ dw truncateTOSto32int ; 7 - truncate TOS to integer in DX:AX
+ dw storestatusword ; 8 - store user status word
+ dw clearexceptions ; 9 - clear execeptions
+ dw NumStack ; 10 - report number of elements in stack
+ dw ReturnHave8087 ; 11 - report if using coprocessor
+ dw SetExtendedStack ; 12 - turn on or off extended stack
+
+SizeJmpTab equ 12
+
+endif ;not QB3
+
+endfunc label word
+
+szfunctab= endfunc - functab
+
+
+
+ public __fpmath ; emulator entry point
+ ; (if linked with user program)
+
+__fpmath proc far
+
+ cmp bx, SizeJmpTab
+ ja RetFPErr
+
+ shl bx,1
+ push ds ; save DS
+
+ifdef QB3
+ push es
+ push ax
+ push cx
+ push dx
+ push si
+ push di
+endif
+
+ifdef MTHREAD
+ or bx,bx ; check for initialization
+ jz callfunc ; yes - skip set up of ds
+
+ push ax ; preserve AX = __fpmath argument
+ LOADthreadDS ; macro in emthread.asm
+ ; loads thread's DS; trashes AX
+ mov ax, ds
+ or ax, ax ; check for DS of zero.
+ pop ax
+ jz FPMathRet
+callfunc:
+
+else ;MTHREAD
+
+ifdef standalone
+ xor cx,cx
+ mov ds,cx
+ mov ds,ds:[TSKINT*4+2] ; point to task data area
+
+elseifdef _COM_
+ mov ds, [__EmDataSeg]
+
+else
+ mov cx, edataBASE
+ mov ds,cx
+endif ;standalone
+
+endif ;MTHREAD
+
+ call functab[bx]
+
+ifdef QB3
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop ax
+ pop es
+endif
+
+lab FPMathRet
+ pop ds ; restore DS
+
+pub emuret
+ ret
+
+RetFPErr:
+ or ax, -1
+ mov dx, ax
+ jmp emuret
+
+__fpmath endp
+
+
+ProfBegin DOS
+
+subttl emdos.asm - Initialization and Termination
+page
+;*********************************************************************;
+; ;
+; Initialization and Termination ;
+; ;
+;*********************************************************************;
+
+wastetime macro
+ push cx
+ mov cx,20 ;; wait for a short time
+ loop $
+ pop cx
+endm
+
+ifndef only87
+CHIPKEY db 'NO87='
+CHIPKEYLEN equ $ - CHIPKEY
+crlf db 13,10
+endif ;only87
+
+ifdef standalone
+Installed db 0 ; installation flag
+
+pub sizeerror
+ mov ax,-1 ; return size error
+ stc
+ ret
+endif ;standalone
+
+
+; initialization
+;
+; entry dx:ax = task data area (segment and size) for standalone
+; si = DOS environment segment for NO87 lookup
+
+pub initialization
+
+ifdef QB3
+ mov [initCW],ax ; save initial BASIC control word
+endif
+
+setstacklimits macro
+ mov di,offset BEGstk ; di = base of register stack
+ mov [BASstk],di ; initialize stack base
+ mov cx,Reg87Len ; cx = register length
+ xchg ax,dx ; ax = task data segment size
+ sub ax,di ; ax = number bytes for stack
+ cwd ; dx:ax = number of bytes
+ div cx ; ax = number of entries
+ mul cx ; ax = number of bytes
+ add ax,di ; ax = top of stack
+ sub ax,cx ; Leave room for one on overflow
+ mov [LIMstk],ax ; set top of stack
+endm
+
+
+ifdef standalone
+
+; check task data area sizes for correctness
+
+ cmp ax,offset __fptaskdata ; compare against minimum size
+ jb sizeerror ; too small
+ mov ds,dx ; set up task data segment
+ xchg dx,ax ; set up size
+ mov ax,25h*256 + TSKINT ; set TASK DATA pointer vector
+ int 21h
+
+ setstacklimits
+endif ;standalone
+
+ifdef MTHREAD
+ ALLOCthreadDS ; macro in emthread.asm
+ mov dx,(offset __fptaskdata)-cvtbufsize
+ ; set up size in dx
+ ; cvt buf not part of stack
+ setstacklimits
+endif ;MTHREAD
+
+
+ifdef QP
+ mov ax, edataOFFSET BEGstk ; initialize BASstk, CURstk, LIMstk
+ mov [BASstk], ax ; QuickPascal has no data initialization
+ mov [CURstk], ax
+
+ mov ax, edataOFFSET ENDstk
+ sub ax, 2*Reg87Len
+ mov [LIMstk], ax
+endif ;QP
+
+
+ifndef frontend
+ifdef DOS5
+ push ss ; current stack segment selector
+ push ds
+ mov ax,offset SSalias
+ push ax ; address of SSalias
+ os2call DOSCREATECSALIAS ; get SS alias for exception handling
+endif ;DOS5
+
+endif ;frontend
+
+ifdef DOS3and5
+ push ds
+ mov ax,offset protmode
+ push ax
+ os2call DOSGETMACHINEMODE ; get machine mode flag
+endif ;DOS3and5
+
+ifdef MTHREAD
+ mov ax,ds
+ cmp ax,EMULATOR_DATA ; check for thread 1
+ je initcheckenv ; yes - go look for NO87=
+
+
+; other threads should copy thread 1's Have8087 value
+; and then go to initfinish
+
+ push ds
+ mov ax,EMULATOR_DATA
+ mov ds,ax
+ mov al,[Have8087]
+ pop ds
+ mov [Have8087],al
+ jmp initfinish
+
+
+endif ;MTHREAD
+pub initcheckenv
+
+ifdef frontend
+ mov [Have8087],0 ; indicate no 8087
+else
+ifndef only87
+ push ds
+
+; Examine the environment looking for the NO87= switch
+
+ or si,si ; check for no environment passed in
+ je init1 ; don't look for NO87=
+
+ mov es,si ; ES = environment segment
+ push cs
+ pop ds
+ xor di,di ; DI -> 1st byte of environment
+ cld
+
+pub envstart
+ cmp byte ptr es:[di],0 ; 1st byte zero means end of env.
+ je init1 ; continue with initialization
+
+ mov cx,CHIPKEYLEN ; Length of key 'NO87='
+ mov si,offset CHIPKEY ; key string address
+
+ repe cmpsb
+
+ je envwrtmsg
+
+ mov cx,7FFFh ; Scan rest of environment
+ xor al,al ; for 0
+ repne scasb
+ je envstart ; yes - check next entry
+ jmp short init1 ; UNDONE - bad environment if here
+
+pub envwrtmsg
+ mov cx,7FFFh
+ mov al,' ' ; skip leading blanks
+ repe scasb
+ dec di
+ mov dl,es:[di] ; Get character of message
+ or dl,dl ; Do we have a null?
+ jz envmsgend ; If so we're done
+
+pub envwrtlp
+ xor ax,ax ;** vvv ; scan for a null byte
+ mov cx,7FFFh
+ mov bx,di ; save offset of string
+ repne scasb
+ dec di
+ sub di,bx
+ mov cx,di ; count of characters before null byte
+
+;
+; write out NO87= environment string to standard output
+;
+
+ifdef DOS5
+ mov di,bx ; restore offset of string
+ push ax
+ mov ax,sp ; allocate space for return count
+
+ mov bx,1
+ push bx ; file handle (standard output)
+ push es
+ push di ; address of buffer
+ push cx ; number of bytes to write
+ push ss
+ push ax ; address for return count
+ os2call DOSWRITE
+
+;
+; write out CR-LF pair to standard output
+;
+ mov ax,sp ; pointer to space for return count
+
+ mov bx,1
+ push bx ; file handle (standard output)
+ push cs
+ mov di,offset crlf
+ push di ; address of CR-LF pair
+ mov bx,2
+ push bx ; number of bytes to write: 2
+ push ss
+ push ax ; address for return count
+ os2call DOSWRITE
+ pop bx ;** ^^^ ; deallocate space for return count
+else
+ push es
+ pop ds
+ mov dx,bx ; ds:dx = string
+ mov bx,1 ; bx = file handle (1)
+ mov ah,40H
+ int 21h ; call DOS - write string
+
+ push cs
+ pop ds
+ mov dx,offset crlf ; ds:dx = CR/LF
+ mov cx,2 ; cx = 2 bytes
+ mov ah,40H
+ int 21h ; call DOS - write string
+endif
+
+pub envmsgend
+ pop ds ; restore user data area
+ mov [Have8087],0 ; indicate emulation
+ifdef _NO87INSTALL
+ jmp initinstallno87 ; go call __FPINSTALLNO87
+else ;_NO87INSTALL
+ jmp initvec ; initialize for emulation
+endif ;_NO87INSTALL
+
+pub init1
+ pop ds ; restore user data area
+
+endif ;only87
+
+
+; check if 8087/80287 is present
+
+ifdef DOS3and5
+ cmp [protmode],0 ; check for protect mode
+ jne prot287chk ; yes - check for 287
+endif ;DOS3and5
+
+ifdef DOS3
+
+; real mode 8087/80287 check
+
+ifdef PCDOS
+PCBIOSEQ equ 11H ; PC BIO's Equipment determination call.
+COPROCESSORMASK equ 2H ; Mask for Coprocessor sense switch.
+
+ int PCBIOSEQ ; PC-DOS Bios Equipment
+ and al,COPROCESSORMASK ; Coprocessor present?
+ shr al,1 ; al = 0 if no 8087/80287 , 1 = if yes
+ifdef only87
+ jz installerror ; error if no 8087/80287
+endif ;only87
+else
+ fninit ; Initialize the 8087.
+ wastetime
+ xor ax,ax ; Clean AX.
+ mov [statwd],ax ; Clear temporary.
+ fnstcw [statwd] ; have bits 033Fh set if 8087
+ wastetime
+ and [statwd],0F3Fh ; (was 1F3Fh, but now allows for 80387-A1 step)
+ cmp [statwd],033Fh
+ jnz realno87 ; no 8087 or 287
+
+; 80287 can fool you - also check for status word
+
+ fnstsw [statwd] ; save status word
+ wastetime
+ inc ax ; al = 1 (assume have an 80287)
+ test [statwd],0B8BFh ; should be off if present
+
+pub realno87
+ jz realhave87
+ifdef only87
+ jmp short installerror ; error if no 8087/80287
+else
+ xor ax,ax ; al = 0
+endif ;only87
+
+pub realhave87
+endif ;PCDOS
+
+ MOV [Have8087],al
+endif ;DOS3
+
+ifdef DOS3and5
+ jmp short initinstall
+endif ;DOS3and5
+
+ifdef DOS5
+
+; protect mode 80287 check
+
+pub prot287chk
+ push ds
+
+ .286
+ push offset Have8087 ; directly change Have8087
+ push 3 ; 3rd byte is coprocessor flag
+ push 0 ; reserved parameter
+
+ifndef DOS5only
+ .8086
+endif
+
+ os2call DOSDEVCONFIG
+ifdef only87
+ cmp [Have8087],0 ; error if no 87 present
+ je installerror
+endif ;only87
+endif ;DOS5
+
+endif ;frontend
+
+
+; check if floating point emulator/8087 already installed (device driver)
+
+pub initinstall
+
+ifndef QB3
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0 ; check for 8087/80287
+ifdef _NO87INSTALL
+ jne initcontinue
+pub initinstallno87
+ extrn __FPINSTALLNO87:near
+ call __FPINSTALLNO87
+ jmp initvec
+initcontinue:
+else ;_NO87INSTALL
+ je initvec ; no - don't install hardware
+endif ;_NO87INSTALL
+endif ;only87
+
+ifdef DOS3and5
+ cmp [protmode],0 ; check for protect mode
+ jne initprotinstall ; yes - don't install hardware
+endif ;DOS3and5
+ifdef DOS5only
+ jmp initprotinstall
+endif
+
+ifdef DOS3
+ifdef standalone
+ cmp [Installed],0 ; note - in code segment (not task)
+ jnz initvec ; installed - skip installation
+endif ;standalone
+
+ extrn __FPINSTALL87:near
+ call __FPINSTALL87 ; OEM installation
+ jnc initvec
+
+endif ;DOS3
+
+pub installerror
+ mov ax,-2 ; return installation error
+ stc
+ ret
+
+
+ifdef DOS5
+pub initprotinstall
+
+ .286
+ push 16 ; exception error
+ push cs
+ push offset protexception
+ push ds
+ push offset oldvec+4 ; address for old exception vector
+
+ifndef DOS5only
+ .8086
+endif
+ os2call DOSSETVEC
+endif ;DOS5
+endif ;frontend
+
+endif ;QB3
+
+; set up interrupt vectors for emulator or fixup-on-the-fly
+
+pub initvec
+
+ifdef DOS3and5
+ cmp [protmode],0
+ jne initvecprot ; yes - protect mode setup
+endif ;DOS3and5
+
+ifdef DOS3
+; real mode emulation and fixup on the fly vector setup
+
+ifndef QB3
+ call set_vectors
+endif
+
+
+endif ;DOS3
+ifdef DOS3and5
+ jmp short initfinish
+endif
+
+ifdef DOS5
+pub initvecprot
+ifndef only87
+ cmp [Have8087],0 ; emulation?
+ jne initfinish ; no - don't setup vector
+
+ .286
+ push 7 ; emulation
+ push cs
+ push offset protemulation
+ push ds
+ push offset oldvec ; address for old emulation vector
+
+ifndef DOS5only
+ .8086
+endif
+ os2call DOSSETVEC
+endif ;only87
+endif ;DOS5
+
+; finish initialization
+
+pub initfinish
+
+ call reset ; reset (0), FINIT if 8087 present
+
+ifdef QB3
+ mov ax,[initCW]
+else
+ mov ax,InitControlWord ; setup initial control word
+endif
+ call loadcontrolword
+
+ifndef QB3
+ xor ax,ax
+ mov word ptr [SignalAddress],ax ; clear SignalAddress
+ mov word ptr [SignalAddress+2],ax
+endif
+
+ifdef MTHREAD
+ mov [ExtendStack],1
+endif ;MTHREAD
+
+
+ifndef only87
+ifdef LOOK_AHEAD
+ifdef DOS3and5
+ mov ax, offset DOSLookAhead
+ cmp [protmode], 0
+ je SetLookAheadRoutine
+
+ mov ax, offset ProtLookAhead
+SetLookAheadRoutine:
+ mov [LookAheadRoutine], ax
+
+endif ;DOS3and5
+endif ;LOOK_AHEAD
+endif ;not only87
+
+
+ mov al,[Have8087]
+ cbw ; ax = 0 or 1 depending on 8087
+ ret
+
+ifdef MTHREAD
+lab LoadDS_EDI ; this is used from emds.asm
+ push bx
+ push cx
+ push dx
+
+ mov bx, DGROUP
+ mov ds, bx
+
+ call __FarGetTidTab
+ mov ds, dx
+ mov di, ax
+ add di, __fpds
+
+ pop dx
+ pop cx
+ pop bx
+
+ ret
+endif ;MTHREAD
+
+
+;------ termination ----------------------------------------------------
+
+pub termination
+
+ifdef DOS3and5
+ cmp [protmode],0 ; are we in protect mode?
+ jne termprot ; yes
+endif ;DOS3and5
+
+ifdef DOS3
+; real mode termination
+
+ifndef QB3
+ call rst_vectors
+endif
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0 ; Non zero if 8087 chip exists
+ifdef _NO87INSTALL
+ jne termcontinue
+ extrn __FPTERMINATENO87:near
+ call __FPTERMINATENO87
+ ret
+termcontinue:
+else ;_NO87INSTALL
+ je termrealdone
+endif ;_NO87INSTALL
+endif ;only87
+
+ FNINIT ; Clean up 8087.
+
+ifndef QB3
+ extrn __FPTERMINATE87:near
+ call __FPTERMINATE87 ; OEM 8087 cleanup routine
+endif
+
+endif ;frontend
+
+pub termrealdone
+ ret
+endif ;DOS3
+
+ifdef DOS5
+; protect mode termination
+
+pub termprot
+
+; UNDONE - don't do any cleanup - should be handled by DOS
+
+ifndef frontend ; UNDONE - should not be needed
+ push [SSalias]
+ os2call DOSFREESEG ; free up SSalias
+endif ;frontend
+
+ifdef MTHREAD
+ FREEthreadDS ; defined in emthread.asm
+ ; uses DOSFREESEG
+endif ;MTHREAD
+
+ ret
+endif ;DOS5
+
+
+
+subttl emdos.asm - reset and clearexceptions
+page
+;*********************************************************************;
+; ;
+; Reset and Clearexceptions ;
+; ;
+;*********************************************************************;
+
+pub reset
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0 ; Nonzero if 8087 chip exists
+ je noFINIT
+endif ;only87
+ FNINIT ; Initialize 8087.
+endif ;frontend
+
+pub noFINIT
+ mov ax,[BASstk]
+ mov [CURstk],ax ; reset stack to bottom
+
+; fall into clearexceptions
+
+
+pub clearexceptions
+
+ xor ax,ax
+ifndef frontend
+ifndef only87
+ cmp al,[Have8087] ; Nonzero if 8087 chip exists
+ je noFCLEX
+endif ;only87
+ FCLEX ; clear exceptions
+endif ;frontend
+
+pub noFCLEX
+ifndef only87
+ mov [StatusWord],ax ; clear status word
+endif ;only87
+ mov [UserStatusWord],ax ; clear exception status word
+
+ifdef QB3
+ mov ax,[initCW]
+ call loadcontrolword ; reload 8087 control word
+endif ;QB3
+
+ ret
+
+
+
+subttl emdos.asm - setsignal ---------------------------------
+page
+;*********************************************************************;
+; ;
+; Setsignal ;
+; ;
+;*********************************************************************;
+
+ifndef QB3
+
+pub setsignal
+ mov word ptr [SignalAddress],ax ; set offset
+ mov word ptr [SignalAddress+2],dx ; set segment
+ ret
+
+endif ;QB3
+
+
+ifdef DOS3
+
+pub set_vectors
+
+ mov cx,NUMVEC ; save old vectors under DOS 3
+ mov ax,35h*256 + BEGINT ; get vector
+ mov di,offset oldvec ; di = old vector table
+pub getvecs
+ int 21h
+ inc ax
+ mov [di],bx ; save old vector
+ mov [di+2],es
+ add di,4
+ loop getvecs
+
+ifndef only87
+ mov dx,offset DStrap ; assume emulator
+ mov si,offset SOtrap
+ mov di,offset FWtrap
+endif ;only87
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0 ; are we using 8087 ?
+ jz setvectors ; no - go ahead and set them
+endif ;only87
+
+ mov dx,offset DSFixUpOnFly ; set up for fixup-on-the-fly
+ mov si,offset SOFixUpOnFly
+ mov di,offset FWFixUpOnFly
+endif ;frontend
+
+pub setvectors
+ push ds
+
+ push cs
+ pop ds
+ mov ax,25h*256 + BEGINT
+ mov cx,8 ; 8 vectors for DStrap
+pub vecloop
+ int 21h ; set vector
+ inc ax ; bump to next one
+ loop vecloop
+
+ mov dx,si ; set Segtrap
+ int 21h
+ inc ax
+ mov dx,di ; set FWtrap
+ int 21h
+
+ pop ds ; restore task data area
+
+ ret
+
+
+pub rst_vectors
+
+ mov cx,NUMVEC
+ mov ax,25h*256 + BEGINT ; set vector
+ mov di,offset oldvec ; di = old vector table
+
+pub termresetvecs
+ push ds
+ lds dx,[di] ; get old vector value
+ int 21h
+ pop ds
+ inc ax
+ add di,4
+ loop termresetvecs
+
+ ret
+
+
+endif ;DOS3
+
+
+
+pub NumStack ; returns the number of stack elements in ax
+
+ xor dx, dx ; dx will count nonzero elements
+
+ifndef only87
+ cmp Have8087, 0
+ je CountEmulatorStack
+endif ;only87
+
+ sub sp, 14 ; need 14 bytes for fstenv
+ mov bx, sp
+ fstenv ss:[bx]
+ fldcw ss:[bx] ; reset control word
+ mov ax, ss:[bx+4] ; put tag word in ax
+ add sp, 14 ; reset stack
+
+ mov cx, 8
+pub NotEmptyLoop
+ mov bx, ax
+
+ shr ax, 1
+ shr ax, 1
+
+ and bx, 3
+ cmp bx, 3
+ je StackEntryEmpty
+
+ inc dx ; stack element was not empty
+pub StackEntryEmpty
+ loop NotEmptyLoop
+
+
+pub CountEmulatorStack
+
+ mov ax, CURstk
+ sub ax, BASstk
+
+ mov bl, Reg87Len
+
+ div bl
+
+ add ax, dx ; add elements on 80x87 stack
+
+ ret
+
+
+ReturnHave8087 proc near
+
+ mov al, [Have8087]
+ cbw
+
+ ret
+ReturnHave8087 endp
+
+
+SetExtendedStack proc near
+
+ mov [ExtendStack], ax
+
+ ret
+SetExtendedStack endp
+
+ProfEnd DOS
diff --git a/private/mvdm/wow16/win87em/emds.asm b/private/mvdm/wow16/win87em/emds.asm
new file mode 100644
index 000000000..493892592
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emds.asm
@@ -0,0 +1,54 @@
+ page ,132
+ title emds.asm - Defines __FPDSARRAY
+;***
+;emmain.asm - Defines __FPDSARRAY.
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Defines __FPDSARRAY
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+_DATA segment word public 'DATA'
+_DATA ends
+
+DGROUP group _DATA
+
+include os2supp.inc
+
+; __FPDSARRAY[0] = MAXTHREADID
+; __FPDSARRAY[i] = emulator DS for thread i, 1<=i<=MAXTHREADID
+
+
+_DATA segment word public 'DATA'
+
+public __FPDSARRAY
+__FPDSARRAY dw MAXTHREADID ; table size = MAXTHREADID
+ dw MAXTHREADID dup (0) ; array of per-thread DS's
+
+_DATA ends
+
+
+_TEXT segment word public 'CODE'
+assume cs:_TEXT
+
+extrn __gettidtab:near
+
+public __FarGetTidTab
+__FarGetTidTab:
+ call __gettidtab
+
+ retf
+
+_TEXT ends
+
+
+end
diff --git a/private/mvdm/wow16/win87em/emerror.asm b/private/mvdm/wow16/win87em/emerror.asm
new file mode 100644
index 000000000..96ef9fde3
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emerror.asm
@@ -0,0 +1,399 @@
+ page ,132
+ subttl emerror.asm - Emulator error handler
+;***
+;emerror.asm - Emulator error handler
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Emulator error handler
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin ERROR
+
+; error entry to check for unmasked errors
+
+
+error_return macro noerror
+ pop eax ; common exit code
+ifdef XENIX
+ifdef i386
+ pop ss ; pop stack selector
+endif
+ifnb <noerror>
+ iretd ; normal return
+else
+ int 0FFh ; special XENIX int for error
+endif
+else
+ iretd
+endif ;XENIX
+ endm
+
+
+TESTif macro nam
+ mov bl,err&nam ; default error number
+ IF (nam GE 100H)
+ test ah,nam/256
+ ELSE ;not (nam GE 100H)
+ test al,nam
+ ENDIF ;(nam GE 100H)
+ jnz short signalerror
+ endm
+
+pub CommonExceptions
+
+ifdef QB3
+
+ jmp $EM_INT ; jump to QB3 error handler
+
+else ;not QB3
+
+ push ds ; get address from task DS
+ push ebx
+
+ TESTif StackUnderflow ; Stack underflow
+ TESTif StackOverflow ; Stack overflow
+ TESTif SquareRootNeg ; Square root of negative number?
+ TESTif IntegerOverflow ; Would number not fit in integer?
+ TESTif Invalid ; indefinite error ?
+ TESTif ZeroDivide ; zero divide error ?
+ TESTif Overflow ; overflow error ?
+ TESTif Underflow ; underflow error ?
+; TESTif Denormal ; denormal error ? not yet implemented
+ TESTif Precision ; Precision error ?
+ TESTif Unemulated ; unemulated error ?
+
+; BL = error code value
+
+pub signalerror
+
+ifndef XENIX
+
+ifdef MTHREAD
+ LOADthreadDS ; macro in emthread.asm
+ ; load thread's DS; trash AX
+elseifdef standalone
+ xor ax,ax
+ mov ds,ax
+ mov ds,ds:[4*TSKINT+2]
+
+elseifdef _COM_
+ mov ds, [__EmDataSeg]
+
+else ;Default
+ mov ax, edataBASE
+ mov ds,ax
+endif ;Default
+
+
+ifdef MTHREAD
+ ; lock _SIGNAL_LOCK to guard SignalAddress (also used by signal func.)
+ mov ax,DGROUP
+ mov ds,ax ; establish DS == DGROUP for __lock
+ push _SIGNAL_LOCK
+ call __lockf
+ add sp,2
+ mov ax,EMULATOR_DATA ; use thread 1's data segment
+ mov ds,ax ; establish DS == EMULATOR_DATA
+ mov ax,word ptr [SignalAddress] ; check for nonzero address
+ or ax,word ptr [SignalAddress+2]
+ jnz short havehandler
+ ; go straight to DOSEXIT call below ...
+ ; don't bother cleaning up the stack or unlocking _SIGNAL_LOCK
+
+ ;pop bx ; don't bother tossing
+ ;pop ebx ; don't bother tossing
+ ;pop ds ; don't bother tossing
+ mov ax,1
+ push ax
+; BL = error code value
+ xchg ax,bx ; al = return code
+ xor ah,ah
+ push ax
+ os2call DOSEXIT ; DOSEXIT(1,return code) to terminate process
+
+elseifdef WINDOWS
+ push es
+ push bx
+
+ mov ax, DOS_getvector*256 + TSKINT
+ IntDOS
+
+ mov ax, es
+ or ax, bx
+
+ pop bx
+ pop es
+ jnz short havehandler
+
+else ;not MTHREAD or WINDOWS
+ mov ax,word ptr [SignalAddress]
+ or ax,word ptr [SignalAddress+2]
+ jnz short havehandler
+ ; UNDONE - why no "os2call DOSEXIT" for the DOS5 case?
+ ;pop bx ; don't bother tossing
+ ;pop ds ; don't bother tossing
+ xchg ax,bx ; al = return code
+ mov ah,04Ch
+ int 21h ; terminate process with fp error code
+
+endif ;not MTHREAD or WINDOWS
+
+pub havehandler
+
+ifdef MTHREAD
+; DS == EMULATOR_DATA ; Use thread 1's DS for SignalAddress.
+; BL = return code
+ xchg ax,bx ; al = return code
+ push word ptr [SignalAddress+2]
+ push word ptr [SignalAddress]
+
+ mov bx,DGROUP
+ mov ds,bx ; establish DS == DGROUP for __unlock
+
+ push _SIGNAL_LOCK ; unlock _SIGNAL_LOCK
+ call __unlockf
+ add sp,2
+
+ mov bx,sp ; SS:BX points to a copy of SignalAddress on the stack
+
+else ;not MTHREAD
+ ; bl = return code
+ xchg ax,bx ; al = return code
+
+ ; other error return info for recovery
+ pop ebx
+endif ;not MTHREAD
+
+; all registers are the original values except AX and DS
+;
+; al = error code (81h and up)
+;
+; if the signal routine is going to return to the user program, it can
+; just do a long ret. The users DS is sitting above the far return address
+
+
+ifdef POLLING ; new exception handling code
+ifndef frontend
+
+ifdef DOS3and5
+ cmp [protmode],0 ; check for protect mode
+ jne callsig ; yes - call signal now
+endif ;DOS3and5
+
+ifdef DOS3
+ cmp [have8087],0 ; check if emulating
+ je callsig ; yes - call signal now
+ cmp [errorcode],0 ; check if pending error
+ifdef WF
+ je ncs1
+ jmp nocallsig
+ncs1:
+else
+ jne nocallsig ; yes - just return
+endif
+
+ mov [errorcode],al ; save error code for later
+
+
+;*
+;* Set 80x87 exception occured flag.
+;*
+
+ifdef USE_IRET
+ mov byte ptr cs:[FWAITiret], iNOP ; nop out "iret"
+
+elseifdef WINDOWS
+ifdef WF
+ cmp [wfGoFast], 0
+ je WinSlow2
+
+ .286p
+; int 3
+ push bp ; bp[0], ds[2], ax[4], retip[6], retcs[8], retfl[10]
+ mov bp, sp ; faultip[12], faultcs[14]
+ push es
+ pusha
+ mov ax, REMLSW
+ mov [wfErr], ax
+
+ push cs ; if fault CS:IP == our int 3d handler
+ pop ax ; then we don't want to patch it, we just want
+ cmp [bp+14], ax ; to set the flag as if we had
+ jnz wfPatch
+ mov ax, offset wfFaultHere
+ cmp [bp+12], ax
+ jnz wfPatch
+ mov [wfInsn], 3dcdh
+ jmp short wfNoPatch
+wfPatch:
+
+ push [bp+14] ; copy faulting CS to data selector
+ push [wfSel]
+ call ChangeSelector
+
+ mov es, [wfSel] ; es:bx points to faulting insn
+ mov bx, [bp+12]
+
+ mov ax, es:[bx] ; save old insn value
+ mov [wfInsn], ax
+ mov es:[bx], 3dcdh ; put INT 3D at fault location
+wfNoPatch:
+ popa
+ pop es
+ pop bp
+ pop ds
+ pop ax
+ iret
+; fall through to old code
+WinSlow2:
+endif
+ mov [ExceptFlag], 1
+
+else ;DEFAULT
+ mov byte ptr cs:[FWAITRetF], iNOP ; nop out "retf 2"
+ mov word ptr cs:[FWAITRetF2], wNOP
+endif ;DEFAULT
+
+ jmp short nocallsig ; just return
+endif ;DOS3
+
+endif ;not frontend
+endif ;POLLING
+
+
+callsig:
+
+ifdef MTHREAD
+ call dword ptr ss:[bx] ; call thru thread 1's signal address
+ add sp, 4 ; remove address of signal handler from stack
+ pop ebx ; note that bx is restored after the call to the
+ ; SIGFPE signal handler, but the SIG_DFL, SIG_IGN, or
+ ; user-handler shouldn't care; in the event of SIG_IGN
+ ; or a user handler that actually returns instead of
+ ; doing longjump(), this pop instruction will restore bx
+
+elseifdef WINDOWS
+ mov REMLSW, ax ; save error code
+
+ pop ds
+ pop ax ; stack is now just an int stack frame
+
+ifdef WF0
+ .286p
+; int 3
+ push bp ; bp[0], retip[2], retcs[4], retfl[6]
+ mov bp, sp ; faultip[8], faultcs[10]
+ push ds
+ push es
+ pusha
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ cmp [wfGoFast], 1 ; if running Std Mode
+ jnz WinSlow2
+ mov ax, REMLSW
+ mov [wfErr], ax
+ push [bp+10] ; copy faulting CS to data selector
+ push [wfSel]
+ call ChangeSelector
+
+ mov es, [wfSel] ; es:bx points to faulting insn
+ mov bx, [bp+8]
+
+ mov ax, es:[bx] ; save old insn value
+ mov [wfInsn], ax
+
+ mov es:[bx], 3dcdh ; put INT 3D at fault location
+
+ popa
+ pop es
+ pop ds
+ pop bp
+ iret
+WinSlow2: ; can't do fast (non-poll) fp, so
+ popa ; restore stack and use old method
+ pop es
+ pop ds
+ pop bp
+; fall through to old code
+endif
+
+ inc bp
+ push bp
+ mov bp, sp
+ push ds
+
+ push ax ; save user's ax
+
+ push cs ; must set up another stack frame
+ mov ax, offset DummyReturn
+ push ax
+DummyReturn:
+
+ mov word ptr [bp-2], EMULATOR_DATA ; emulator's ds goes on first frame
+
+ inc bp
+ push bp
+ mov bp, sp
+ push ds ; push user's ds onto dummy stack frame
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+
+ push es ; if windows => setup SignalAddress for
+ push bx ; far call
+
+ mov ax, DOS_getvector*256 + TSKINT
+ IntDOS
+
+ mov word ptr [SignalAddress], bx
+ mov word ptr [SignalAddress+2], es
+
+ pop bx
+ pop es
+
+ mov ax, REMLSW ; al = error code
+
+ call [SignalAddress] ; execute signal routine
+
+ pop ds ; restore user's ds
+ add sp, 6 ; get rid of dummy stack frame
+ pop ax ; restore user's ax
+
+ add sp, 2 ; get rid of emulator ds on stack
+
+ pop bp
+ dec bp
+
+ iret ; return
+
+
+else ;not MTHREAD or WINDOWS
+ call [SignalAddress] ; execute signal routine
+endif ;not MTHREAD or WINDOWS
+
+nocallsig:
+
+ pop ds ; restore user DS
+ error_return noerror ; treat as if nothing happened
+
+else ;XENIX
+ pop ebx ; restore EBX and DS
+ pop ds
+ error_return ; error exit for XENIX
+
+endif ;XENIX
+
+
+endif ;not QB3
+
+ProfEnd ERROR
diff --git a/private/mvdm/wow16/win87em/emexcept.asm b/private/mvdm/wow16/win87em/emexcept.asm
new file mode 100644
index 000000000..6188f63dc
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emexcept.asm
@@ -0,0 +1,1411 @@
+ page ,132
+ subttl emexcept.asm - Microsoft exception handler
+;***
+;emexcept.asm - Microsoft exception handler
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Microsoft exception handler
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History: (Also see emulator.hst.)
+;
+; 12-08-89 WAJ Add fld tbyte ptr [mem] denormal check.
+;
+;*******************************************************************************
+
+
+;----------------------------------------------------------------------
+; Structure for FSTENV and FLDENV, Store and Load 8087 Environment
+;----------------------------------------------------------------------
+
+glb <ENV_ControlWord,ENV_StatusWord,ENV_TagWord,ENV_IP>
+glb <ENV_Opcode,ENV_OperandPointer,ENV_ControlMask>
+glb <ENV_CallOffset,ENV_CallSegment,ENV_CallFwait,ENV_Call8087Inst>
+glb <ENV_CallLongRet>
+
+ENV_DS EQU -4
+ENV_BX EQU -2
+
+ENV_ControlWord EQU 0
+ENV_StatusWord EQU 2
+ENV_TagWord EQU 4
+ENV_IP EQU 6
+ENV_Opcode EQU 8
+ENV_OperandPointer EQU 10
+ENV_ControlMask EQU 16
+
+ENV_Temp EQU 18 ; Note ENV_Temp occupies
+
+ENV_CallOffset EQU 18 ; the same space as ENV_Call*.
+ENV_CallSegment EQU 20 ; This is possible because there
+ENV_CallFwait EQU 22 ; is never simultaneous use of
+ENV_Call8087Inst EQU 23 ; this space
+ENV_CallLongRet EQU 25
+
+ENV_OldBP EQU 28
+ENV_OldAX EQU 30
+ENV_IRETadd EQU 32
+
+ENV_Size EQU 28
+
+; UNDONE 386 version is bad - 387 environment is longer
+
+PAGE
+;----------------------------------------------------------------------------
+;
+; 8087 EXCEPTION HANDLER - Fields 8087 stack over flow and under flow.
+;
+;----------------------------------------------------------------------------
+;
+; I. The 8087 state vector.
+;
+; Upon the execution of a FSAVE or FSTENV instruction the state of the
+; 8087 is saved in a user defined state vector. The first seven words
+; saved in the state vector by the two instructions are identical. The
+; definition of the words is:
+;
+; Word. Bits. Bytes. Function.
+; ----- ----- ------ ---------
+; 0 15..0 1..0 Control word.
+; 1 15..0 3..2 Status word. ( 8087 stack
+; pointer and condition codes.
+; 2 15..0 5..4 Tag word ( 8087 stack slot usage
+; flags ).
+; 3 15..0 7..6 Instruction pointer. Operator
+; segment offset.
+; 4 15..12 8 Operator paragraph bits ( (
+; bits 16..19 ) of address ).
+; 4 11 8 Always zero.
+; 4 10..8 8 Upper opcode bits ( major opcode ).
+; 4 7..0 9 Lower opcode bits ( minor opcode ).
+; 5 15..0 11..10 Operand Segment offset.
+; 6 15..12 12 Operand paragraph bits.
+; 6 11..0 Not used. Must be zero.
+;
+; II. Restarting instructions.
+;
+; Of interest in this handler is the necessity of restarting
+; 8087 instructions which fail because of 8087 stack overflow
+; and underflow. Even though the 8087 saves enough information
+; to restart an instruction, it is incapable of doing so. The
+; instruction restart must be done in software.
+;
+; There are two cases which must be considered after the stack
+; exception has been dealt with.
+;
+; 1. The faulting instruction deals with top of stack.
+; 2. The faulting instruction deals with memory.
+;
+; The first case is handled by changing the upper five bits (
+; 15..11 ) of vector word four ( 4 ) to "11011B". This changes
+; word four into an "escape opcode" 8087 instruction. The
+; modified opcode is placed in the interrupt code segment and
+; executed.
+;
+; The second case is handled by changing the upper five bits
+; ( 15..11 ) of vector word four ( 4 ) to "11011B", changing
+; the MOD of the opcode to "00B" ( 0 displacement ), loading
+; the operand address into DS:SI, and changing the RM field of
+; the opcode to "100B" (SI+DISP addressing). The faulting
+; instruction may be restarted as above.
+;
+; Instruction restart may also be accomplished by building an
+; instruction stream in the interrupt stack and calling the
+; instruction stream indirectly. This method is the preferred
+; method because it is reentrant.
+;
+; III. Data Segment Considerations.
+;
+; DS is restored from the task interrupt vector. DS is used for
+; stack overflow memory.
+;
+;
+; Documentation of the invalid exception handling code for the stand-alone
+; 8087/80287 emulator
+;
+; The emulator software is being enhanced for the cmerge 4.0 generation of
+; languages to support a larger subset of the numeric processor instruction
+; set. In addition to providing instructions which were not previously
+; emulated, the model for representing the numeric processor stack is also
+; being modified. The 4.0 languages and their predecessors are object compat-
+; ible so it will be possible for programs to be developed which will contain
+; code generated by the old model as well as the new model. For this reason
+; it is important to understand the characteristics of both models and how
+; the two models will interact.
+;
+; I. The Old Model: Infinite Stack
+;
+; The old model used an infinite stack model as the basis of its
+; emulation of the numeric processor. Only the classical stack form of
+; instructions with operands were emulated so only ST(0) (top of stack)
+; and ST(1) (next to top of stack) were referenced by any given instruction.
+; In addition, the stack was allowed to overflow beyond the eight registers
+; available on the chip into a memory stack overflow area. The code genera-
+; tor did not attempt to maintain all of its register data in the first eight
+; register slots but instead made use of this overflow area. In order to
+; maintain compatible behavior with or without the presence of the chip, this
+; model made it necessary to handle and recover from stack overflow exceptions
+; in the case where the chip is present as well as when it is being emulated.
+;
+; This stack overflow exception handling could in turn generate a recoverable
+; stack underflow exception since a situation could arise where a desired
+; operand had been pushed into the memory overflow area (during stack overflow)
+; and was not available in the on-chip register area when needed. This
+; scenario would signal an invalid exception due to stack underflow.
+; It is recoverable because the required operand is still available in the
+; overflow area and simply needs to be moved into a register on the chip.
+;
+; II. The New Model: Finite Stack
+;
+; The new model uses a finite stack model: only the eight registers on the
+; chip are available for use, so in the new model the invalid exception
+; would never be signalled due to stack overflow. In addition, it extends
+; the emulated instruction set to include the general register form of
+; instructions with operands (operands can be ST(i),ST or ST,ST(i)). Since
+; the new code generator is aware of how many items it has placed on the stack,
+; it does not allow stack overflow or stack underflow to occur. It can remove
+; items from the registers either by storing to memory (FST or FSTP), or by
+; using FFREE to mark the register as empty (this instruction is being added
+; to the emulated instruction set). The new model uses FFREE in a well-defined
+; manner: it will only free registers from the boundaries of the block of
+; registers it is using. For example, if the new code is using ST(0)-ST(6),
+; it must free the registers in the order ST(6),ST(5),ST(4),... and so on.
+; It cannot create gaps of free registers within the block of registers
+; it is using.
+;
+; III. The Hybrid Model: Combination of New and Old Code
+;
+; Due to the possibility of mixture of code generated using both of the above
+; models, the new exception handling and emulation software has to be able to
+; handle all situations which can arise as a result of the interaction of the
+; two models. The following summarizes the behavior of the two models and
+; restrictions placed on their interaction.
+;
+; New Code:
+;
+; 1. Cannot call anyone with any active entries on the stack.
+; The new model is always at a conceptual stack level of zero
+; when it makes external calls. Thus old code will never
+; incorrectly make use of register data that was placed on the
+; register stack by new code.
+;
+; 2. May create gaps of free registers in the register stack.
+; It will not create gaps in the memory stack overflow area.
+;
+; 3. Only causes stack overflow by pushing old code entries off of
+; the register stack and into the memory stack overflow area.
+; It will never overflow its own entries into the memory stack
+; overflow area.
+;
+; 4. Cannot cause stack underflow.
+;
+;
+; Old Code:
+;
+; 1. Can only reference ST(0), ST(1).
+;
+; 2. Can cause stack overflow by pushing too many entries onto the
+; register stack.
+;
+; 3. Can cause stack underflow in two situations:
+;
+; a. It is trying to get something that is in the memory stack
+; overflow area (stack overflow occurred previously).
+;
+; b. There are free entries on the chip. This situation could
+; arise if new code creates free entries then calls old code,
+; so this is a situation that could not have existed before
+; the new model was introduced.
+;
+; IV. Stack Overflow/Underflow Exception Handling
+;
+; The following algorithms will be used for detecting and recovering from
+; stack overflow and underflow conditions (signalled via the invalid
+; exception). All invalid exceptions are "before" exceptions so that
+; the instruction has to be reexecuted once the exception has been handled.
+;
+; A. Stack Overflow
+;
+; If ST(7) is used (possible stack overflow) then {
+; check for instructions which could cause stack overflow
+; (includes FLD,FPTAN,...)
+; if instruction could cause stack overflow then {
+; save ST(7) in stack overflow area at [CURstk]
+; mark ST(7) empty
+; if FLD ST(7) instruction then
+; FLD [CURstk] or rotate chip (clear exceptions)
+; else reexecute the instruction with ST(7) empty
+; }
+; }
+;
+; B. Stack Underflow
+;
+; If ST(0) is free then assume stack underflow since the stack
+; overflow case has already been handled (if the invalid
+; is due to a denormal exception, the exception will occur
+; again when the instruction is reexecuted):
+;
+; if chip has any registers in use (check the tag word) then {
+; rotate chip until ST(0) is not empty
+; rotate tag word to reflect state of chip
+; }
+; else (no registers in use)
+; if operand is in stack overflow area then {
+; load into ST(0) from stack overflow area
+; mark ST(0) full
+; }
+; else {
+; indicate true stack underflow
+; go print error
+; }
+; if ST(1) is empty then {
+; if any of ST(2) thru ST(7) are in use then {
+; rotate chip until ST(1) is not empty
+; (to share code with first chip rotation above:
+; store pop st(0) into temp
+; rotate chip until st(0) is not free
+; load st(0) back onto chip)
+; update tag word appropriately
+; }
+; else
+; load ST(1) from overflow area if there
+; }
+;
+; At this point, ST(0) and ST(1) have been filled if possible.
+; Now we must categorize the instructions to determine which
+; of these is required. Then we will either issue true stack
+; underflow or reexecute the instruction with the compressed
+; stack.
+;----------------------------------------------------------------------------
+;
+; References:
+; Intel 8086 Family Numerics Supplement. 121586-001 Rev A.
+; Intel iAPX 86,88 User's Manual.
+;
+;----------------------------------------------------------------------------
+
+;----------------------------------------------------------------------------
+;
+; All registers must be saved by __FPEXCEPTION87 except CS,IP,SS,SP.
+;
+;----------------------------------------------------------------------------
+
+
+ifdef WINDOWS
+; stack consists of IRET frame and status word before FCLEX
+;
+; Since the environment is different in protect mode, reconstruct
+; the opcode like in real mode.
+
+lab protiret
+ iret
+
+lab protexskipsegovr
+ inc bx ; bump past segment override
+ jmp short protexsegovr ; try again
+
+public __FPEXCEPTION87P
+__FPEXCEPTION87P:
+lab protexception
+ push eax ; save user ax
+ push ebp
+ sub esp,ENV_Size ; get Enough bytes for Environment
+ mov ebp,esp ; set up for rational offsets.
+ fstenv word ptr [ebp] ; save environment.
+
+ mov eax,offset protiret ; set up for near return address
+ xchg ax,[ebp+ENV_Size+4] ; swap status word and near ret addr
+ mov ENV_StatusWord[ebp],ax ; save status word into environment
+
+ push ebx
+ push ds ; save a few more registers
+
+ lds ebx,dword ptr ENV_IP[ebp] ; get address of instruction
+lab protexsegovr
+ mov ax,[ebx] ; get 1st 2 bytes of instruction
+ add al,28h ; add -(ESC 0)
+ jnc protexskipsegovr ; wasn't ESC - skip seg. override
+ xchg al,ah ; swap bytes to make real opcode
+ mov ENV_Opcode[ebp],ax ; save it in environment
+
+ sti
+ jmp short exceptionhandler
+endif ;WINDOWS
+
+
+
+ifdef DOS5
+; stack consists of IRET frame and status word before FCLEX
+;
+; Since the environment is different in protect mode, reconstruct
+; the opcode like in real mode.
+
+lab protiret
+ iret
+
+lab protexskipsegovr
+ inc bx ; bump past segment override
+ jmp short protexsegovr ; try again
+
+lab protexception
+ push eax ; save user ax
+ push ebp
+ sub esp,ENV_Size ; get Enough bytes for Environment
+ mov ebp,esp ; set up for rational offsets.
+ fstenv word ptr [ebp] ; save environment.
+
+ mov eax,offset protiret ; set up for near return address
+ xchg ax,[ebp+ENV_Size+4] ; swap status word and near ret addr
+ mov ENV_StatusWord[ebp],ax ; save status word into environment
+
+ push ebx
+ push ds ; save a few more registers
+
+ lds ebx,dword ptr ENV_IP[ebp] ; get address of instruction
+lab protexsegovr
+ mov ax,[ebx] ; get 1st 2 bytes of instruction
+ add al,28h ; add -(ESC 0)
+ jnc protexskipsegovr ; wasn't ESC - skip seg. override
+ xchg al,ah ; swap bytes to make real opcode
+ mov ENV_Opcode[ebp],ax ; save it in environment
+endif ;DOS5
+
+ifdef DOS3and5
+ jmp short exceptionhandler
+endif ;DOS3and5
+
+
+ifdef DOS3
+ public __FPEXCEPTION87
+
+__FPEXCEPTION87:
+ PUSH AX ; Save user's AX next to IRET
+ PUSH BP
+ SUB SP,ENV_Size ; Get Enough bytes for Environment
+ ; 8087 status.
+ MOV BP,SP ; Set up for rational offsets.
+
+ ;Caveat Programmer!
+ ;FSTENV does an implicit set of all exception masks.
+
+ FNSTENV WORD PTR [BP] ; Save environment.
+ FCLEX ; Clear exceptions.
+ STI ; Restore host interrupts.
+
+ PUSH BX
+ PUSH DS ; Need access to user data
+endif ;DOS3
+
+;----------------------------------------------------------------------------
+; In a multitasking environment one would not want to restore
+; interrupts at this point. One would wait until the 8087 had been
+; flushed and any operand data copied to a storage area.
+;----------------------------------------------------------------------------
+
+ ;---------------
+ ; Inside of the while exception loop and Redo8087Instruction
+ ; registers AX and BX must contain the values as described
+ ; below:
+
+ ; AL bit 0 = 1 indicates invalid exception
+ ; bit 1 = 1 indicates denormal exception
+ ; bit 2 = 1 indicates divide by zero exception
+ ; bit 3 = 1 indicates numeric overflow
+ ; bit 4 = 1 indicates numeric underflow
+ ; bit 5 = 1 indicates precision loss
+ ; bit 6 = unused by 8087
+ ; bit 7 = 1 indicates sqrt of negative number
+ ; (this flag is not from the NPX status word, but
+ ; is set after all other exceptions have been
+ ; handled if the opcode is FSQRT)
+
+ ; AH bit 0 = unused
+ ; bit 1 = 1 indicates stack overflow
+ ; bit 2 = 1 indicates stack underflow
+ ; bit 3 = unused
+ ; bit 4 = unused
+ ; bit 5 = 1 indicates memory operand
+ ; bit 6 = 1 indicates instruction was reexcuted
+ ; bit 7 = 1 indicates ST relative operand
+
+ ; BL = The complement of the exception masks copied from
+ ; UserControlWord altered so that Denormal and Invalid
+ ; exceptions are always unmasked, while the reserved
+ ; bits are masked.
+
+ ; BH bit 0 = 1 indicates 8087 only invalid handling complete
+ ; bit 1 = 1 indicates 8087 only denormal handling complete
+ ; bit 2 = 1 indicates 8087 only divide by zero handling complete
+ ; bit 3 = 1 indicates 8087 only numeric overflow handling complete
+ ; bit 4 = 1 indicates 8087 only numeric underflow handling complete
+ ; bit 5 = 1 indicates 8087 only precision loss handling complete
+ ; bit 6 = unused
+ ; bit 7 = unused
+ ;
+ ; Algorithm: Handle 8087 exceptions which do not occur in the
+ ; emulator and then jump to the common exception handling code.
+ ;
+ ; To handle 8087 only exceptions we must first determine if the
+ ; exception occured before the 8087 executed the instruction
+ ; or afterward. Invalid, denormal (except FLD) and divide by
+ ; zero exceptions all occur before 8087 instruction execution,
+ ; others occur afterward. "Before" exceptions must set the
+ ; "before" flag in AH and then reexecute the instruction. After
+ ; reexecution (while all exceptions are masked) all of the
+ ; exceptions resulting from the current 8087 instruction will
+ ; be known and can be handled as a group. "After" exceptions
+ ; are handled individually since reexecution of an already
+ ; executed instruction will destroy the validity of the 8087 stack.
+ ; A flag in AH is used by Redo8087instruction to avoid reexecuting
+ ; an instruction twice. At the beginning of Redo8087instruction
+ ; the flag is checked, and if it is set the instruction is not
+ ; redone.
+ ;
+ ; "Before" exceptions must be reexecuted because it is
+ ; difficult to determine stack over/underflow if reexecution
+ ; is not performed. Stack over/underflow is signaled by
+ ; an invalid exception. The current algorithm for stack over/
+ ; underflow detection is as follows:
+ ;
+ ; ...
+ ;
+ ;---------------
+
+ProfBegin EXCEPT
+
+lab exceptionhandler
+
+
+ifdef MTHREAD
+ LOADthreadDS ; macro in emthread.asm
+ ; loads thread's DS; trashes AX
+else ;MTHREAD
+
+ifdef standalone
+ XOR AX,AX ; Prepare to access vector, clear flags
+ MOV DS,AX
+ MOV DS,DS:[4*TSKINT+2] ; DS = emulator task data segment
+
+elseifdef _COM_
+ mov ds, [__EmDataSeg]
+ xor ax,ax
+
+else
+ mov ax, edataBASE
+ mov ds,ax
+ xor ax,ax
+endif
+
+endif ;MTHREAD
+
+ MOV AL,ENV_StatusWord[eBP] ; Get 8087 status flags.
+ XOR BH,BH ; Clear out 8087 handling flags
+
+;----------------------------------------------------------------------------
+;
+; Can the interrupt be serviced by this routine? Dispatch exceptional
+; conditions.
+;
+; Multi-pass algorithm
+; Handle exception and reexcute instruction if necessary
+; Loop back to WhileException and handle additional exceptions
+;
+; AX = status before exception handling
+; BX = flag indicating exception handled
+;
+;----------------------------------------------------------------------------
+
+ cmp [ExtendStack], 0 ; check if the extended stack was
+ jne WhileException ; turned off.
+
+ or bh, Invalid
+
+lab WhileException
+
+ifndef _NOSTKEXCHLR ; no stack overflow/underflow handler
+ TEST BH,Invalid ; stack over/underflow already handled?
+ JNZ short NotOverUnderflow ; Yes - forget stack over/underflow
+ TEST AL,Invalid ; Invalid exception?
+ JZ short NotOverUnderflow ; No - bypass over/underflow checking
+ OR BH,Invalid ; Indicate stack over/undeflow checked
+ JMP ProcessOverUnderflow ; See about stack over/underflow
+endif ;_NOSTKEXCHLR
+
+lab NotOverUnderflow
+
+; Either the exception was not an invalid or stack over/underflow has
+; already been handled.
+
+; check for denormal exception - completely resolved on pass 1
+
+ TEST AL,Denormal ; Denormal exception?
+ JZ short NotDenormal ; No - bypass denormal handling
+ JMP ProcessDenormal ; Process the denormal
+
+lab NotDenormal
+
+; check for zero divide exception
+
+ TEST BH,ZeroDivide ; Divide by zero already handled?
+ JNZ short NotZeroDivide ; Yes - bypass divide by zero handling
+ TEST AL,ZeroDivide ; Divide by zero exception?
+ JZ short NotZeroDivide ; No - bypass divide by zero handling
+ OR BH,ZeroDivide ; Indicate divide by zero handled
+
+ CALL ReDo8087Instruction ; Process divide by zero exception
+ JMP WhileException
+
+lab NotZeroDivide
+
+; check for numeric overflow exception
+
+ TEST BH,Overflow ; Overflow already handled?
+ JNZ short AllExceptionsHandled ; Yes - bypass overflow handling
+ TEST AL,Overflow ; Overflow exception?
+ JZ short AllExceptionsHandled ; No - bypass overflow handling
+ OR BH,Overflow ; Indicate overflow handled
+ JMP ProcessNumericOverflow ; Process numeric overflow
+
+
+lab AllExceptionsHandled
+
+; We have already handled any exceptions which require instruction
+; reexecution.
+; At this point 8087 instruction reexecution is done. We need
+; to extract a little more information for error message
+; generation.
+
+ MOV BL, BYTE PTR UserControlWord ; 8087 exception masks
+ OR BL, 0C0H ; Mask reserved
+
+ AND BL, 0FDH ; Unmask denormal. DON'T unmask invalid
+ ; here. (Otherwiae user has no way of
+ ; masking invalids.)
+
+ NOT BL ; complement
+ AND AL, BL ; eliminate all masked exceptions
+ ; from AL
+ TEST AL,Invalid ; Possibly square root of neg?
+ JZ short NotFLDshortorlongNaN ; No - don't set square root flag
+ PUSH AX ; ... Use AX as scratch ...
+ MOV AX,ENV_Opcode[eBP] ; Get the instruction op code
+ AND AH,7 ; Mask off the junk
+ CMP AX,001FAh ; Square root op code?
+ JNE short NotSquareRootError ; No - don't set square root flag
+ POP AX ; ... Restore AX ...
+ OR AL,SquareRootNeg ; Set the square root flag
+ JMP short NotFLDshortorlongNaN
+
+;-----------------------------------------------------------------------------
+; Test for invalid exception caused by an FLD of a NaN underflow or overflow.
+;-----------------------------------------------------------------------------
+lab NotSquareRootError ; Next check for FLD of a NaN
+ ; (only happens for SNaNs on
+ ; the 80387; not for 8087/287)
+ MOV AX,ENV_Opcode[eBP]
+ AND AX,0338h ; Mask off the inessential bits
+ CMP AX,0100h ; Check for possible FLD
+ ; of short/long real from memory.
+ ; We are assuming that an invalid
+ ; exception means FLD of a NaN
+ ; since stack over/under-flow
+ ; has already been dealt with.
+ ; (we don't handle FLD ST(n) or
+ ; FLD temp real in this way)
+ POP AX ; ... Restore AX ...
+ JNE short NotFLDshortorlongNaN
+
+ ;
+ ; (MOD==11 case: no special code)
+ ; We don't handle FLD ST(n) here since it isn't properly
+ ; handled in our stack overlow checking code either and
+ ; it doesn't generate an invalid in the case of an SNaN
+ ; without a stack overflow; FFREE ST(n) will not cause
+ ; an Invalid exception.
+ ;
+ ; FLD TBYTE PTR ... shouldn't cause an Invalid due to a NaN
+ ;
+
+ XOR AL,Invalid ; Turn off invalid exception.
+ ; There should be a NaN in ST(0);
+ ; we will just leave it there.
+
+lab NotFLDshortorlongNaN
+ FCLEX
+ FLDCW ENV_ControlWord[eBP] ; Restore original Control Word
+
+lab CleanUpHost
+ or [UserStatusWord],ax ; OR into user status word
+ POP DS
+ POP eBX
+ ADD eSP,ENV_Size ; Point to users BP
+ POP eBP
+ TEST AX,0FFFFh-Reexecuted ; exceptions?
+ JNZ Exceptions8087 ; Process other exceptions as emulator
+ POP eAX ; Now just IRET address on stack
+ ret ; return to OEM interrupt exit routine
+
+lab Exceptions8087
+; toss OEM routine return address
+
+ push eax
+ push ebx
+ mov ebx,esp
+
+; UNDONE - this does not work for 386
+
+ mov eax,ss:[ebx+4] ; get original AX
+ mov ss:[ebx+6],eax ; overwrite OEM routine return address
+ pop ebx
+ pop eax
+
+ifdef i386
+ add esp,4 ; remove original AX
+else
+ add sp,2 ; remove original AX
+endif
+ JMP CommonExceptions
+
+PAGE
+;-----------------------------------------------------------------------------
+; Test for stack underflow or overflow.
+;-----------------------------------------------------------------------------
+
+ ; There are eight sets of tag bits in the tag word. Each set
+ ; denotes the state of one of the 8087 stack elements.
+
+ ; 00 - normal
+ ; 01 - true zero
+ ; 10 - special: nan,infinity,unnormal
+ ; 11 - empty
+
+ ; If all are empty we have underflow, if all are full we have overflow
+
+ ; There was an invalid exception: check to see if it was stack
+ ; overflow or underflow.
+
+ ; Register usage in this code block:
+ ; BX = tag word, complemented
+ ; CL = NPX stack ptr
+
+ifndef _NOSTKEXCHLR ; no stack overflow/underflow handler
+lab ProcessOverUnderflow
+ PUSH eSI
+ PUSH eBX ; Make room for local temps
+ PUSH eCX
+ PUSH eDX
+ PUSH eDI
+
+ MOV BX,ENV_TagWord[eBP] ; Get tag word.
+ MOV CX,ENV_StatusWord[eBP] ; Get status word
+ NOT BX ; Tag zero means empty, else full
+ MOV CL,CH ; Get stack pointer into CL
+ AND CL,038h ; Mask to stack pointer
+ SHR CL,1
+ SHR CL,1 ; compute number of bits to shift
+ ROR BX,CL ; tag ST(0) in low BL.
+
+ ; To service stack overflow we must make sure there is an empty space
+ ; above the top of stack before the instruction is reexecuted. If
+ ; after reexecution we again get an invalid exception, then we
+ ; know there was something besides stack overflow causing the invalid
+ ; exception.
+
+ ; We check for stack overflow by seeing if ST(7) is empty. We make
+ ; the check by testing the complemented, rotated tag word in BX.
+
+ TEST BH,0C0h ; Possible stack overflow?
+ JZ short StackUnderflowCheck ; No - bypass offloading stack
+
+ ; ST(7) is not empty, so we may have stack overflow. We verify that
+ ; we have stack overflow by looking at the instruction to be sure
+ ; that it can generate stack overflow (i.e., it puts more stuff on
+ ; the stack than it removes).
+ ; Note that a subset of the 287 instruction set is being decoded
+ ; here; only those instructions which can generate invalid exceptions
+ ; get to this point in the code (see Table 2-14 in the Numeric
+ ; Supplement for list of instructions and possible exceptions).
+ ;
+ ; The instructions which can generate stack overflow are:
+ ; all memory FLDs,FILDs,FBLDs,constant instructions,
+ ; FPTAN and FXTRACT
+
+ MOV DX,ENV_Opcode[eBP] ; Get the instruction op code
+ XOR DX,001E0h ; Toggle arith, mod and special bits
+
+; Test for mod of 0,1, or 2 (indicates memory operand)
+
+ TEST DL,0C0h ; Memory operand instruction?
+ JNZ short MemoryFLDCheck ; Yes - go see what kind
+
+; Test bits 5 & 8 of instruction opcode: of remaining instructions, only those
+; with stack relative operands do NOT have both of these bits as 1 in the opcode
+; (remember these bits are toggled).
+
+ TEST DX,00120h ; ST Relative Op group?
+ JNZ short StackUnderflowCheck ; Yes - ST Relative Ops
+ ; cannot cause stack overflow
+
+; Test bit 4 of the instruction opcode: of remaining instructions, only the
+; transcendentals have this bit set.
+
+ TEST DL,010h ; Constant or arith instruction?
+ JNZ short TransCheck ; No - must be Transcendental
+
+; Test bit 3 of the instruction opcode: of remaining instructions, only the
+; constant instructions have this bit set.
+
+ TEST DL,008h ; Constant instruction?
+ JNZ short StackOverflowVerified ; Yes, can cause stack overflow
+
+; The instructions which get to this point are FCHS, FABS, FTST and FXAM.
+; None of these can cause stack overflow.
+
+ JMP StackUnderflowCheck ; so go check for stack underflow
+
+lab TransCheck
+
+; The instruction was a transcendental. Of the transcendentals, only
+; FPTAN and FXTRACT can cause stack overflow, so check for these.
+
+ CMP DL,012h ; is this FPTAN
+ JE short StackOverflowVerified ; yes, can cause stack overflow
+ CMP DL,014h ; is this FXTRACT
+ JE short StackOverflowVerified ; yes, can cause stack overflow
+ JMP StackUnderflowCheck ; not either one, won't cause overflow
+
+lab MemoryFLDCheck
+ TEST DX,00110h ; FLD memory instruction?
+ JNZ short StackUnderflowCheck ; no - go check for stack underflow
+
+lab StackOverflowVerified
+
+ ; ST(7) was not empty and the instruction can cause stack overflow.
+ ; To recover from stack overflow, move ST(7) contents to the
+ ; stack extension area, modifying the tag word appropriately.
+
+ AND BH,0FFh-0C0h ; Indicate 1st above TOS is free
+ PUSHST ; Let PUSHST make room for value.
+ FDECSTP ; Point to bottom stack element.
+ FSTP TBYTE PTR [eSI] ; Store out bottom stack element.
+ JMP InvalidReexecute ; No - reexecute instruction
+
+lab StackUnderflowCheck
+
+ ; To service stack underflow we must make sure all the operands the
+ ; instruction requires are placed on the stack before the instruction
+ ; is reexecuted. If after reexecution we again get an invalid
+ ; exception, then its due to something else.
+
+ TEST BL,003h ; Is ST(0) empty?
+ JZ short UFMemoryFLDcheck ; yes - first check for memory FLD
+ JMP ST1EmptyCheck ; No - Let's try to fill ST(1), too.
+ ; We may need it!
+
+ ;
+ ; This block of code is for making sure that FLD memory operand is not
+ ; among those instructions where stack underflow could occur; this is
+ ; so FLD of SNaN can be detected (under the AllExceptionsHandled
+ ; section) for the case of the 80387.
+ ;
+
+lab UFMemoryFLDcheck
+ MOV DX,ENV_Opcode[eBP] ; Get the instruction opcode
+ XOR DX,001E0h ; Toggle arith, mod and special bits
+ TEST DL,0C0h ; Memory operand instruction?
+ JZ ST0Empty ; No - continue underflow processing
+ ; Try to fill ST(0)
+ TEST DX,00110h ; FLD memory instruction?
+ JNZ ST0Empty ; No - continue underflow processing
+ ; Try to fill ST(0)
+ JMP ST1EmptyCheck ; Let's try to fill ST(1), too.
+ ; We may need it!
+
+ ; Formerly we did JMP InvalidReexecute here; but this caused
+ ; an "invalid" to be reported for instructions with two stack
+ ; operands. (Doing JMP ST1EMptyCheck fixes this bug:
+ ; Fortran 4.01 BCP #1767.)
+ ;
+ ; This fixes the underflow-handling case of instructions
+ ; needing both ST0 and ST1 under the conditions that ST0
+ ; is full but ST1 is empty.
+
+
+lab ST0Empty
+
+ ; assume stack underflow since ST(0) is empty and we did not have
+ ; stack overflow
+
+ OR BX,BX ; Are any registers on the chip in
+ ; use? (BX = 0 if not)
+ JZ short LoadST0FromMemory ; No, load ST(0) from memory stack
+ CALL RotateChip ; yes, then point ST(0) at first
+ ; valid register and update tag in BX
+ JMP ST1EmptyCheck ; go check if ST(1) is empty
+
+lab LoadST0FromMemory
+ MOV eSI,[CURstk] ; Get pointer to memory stack
+ CMP eSI,[BASstk] ; Anything in memory to load?
+ JNE short LoadST0 ; Yes, go load it
+ JMP TrueUnderflow ; No, go issue error
+
+lab LoadST0
+ OR BL,003h ; Indicate ST(0) is full
+ FINCSTP ; Avoid altering stack pointer.
+ FLD TBYTE PTR [eSI] ; Load value from memory.
+ POPST ; Let POPST decrement memory pointer.
+
+lab ST1EmptyCheck
+ TEST BL,00Ch ; Is ST(1) empty?
+ JNZ short EndST1EmptyCheck ; No - so don't load from memory
+
+ MOV SI,BX ; move tag word to SI
+ AND SI,0FFF0h ; mask off ST(0),ST(1)
+ OR SI,SI ; Are any of ST(2)-ST(7) in use?
+ ; (SI = 0 if not)
+ JZ short LoadST1FromMemory ; No, try to get ST(1) from memory
+ FSTP TBYTE PTR [REG8087ST0] ; offload ST(0) temporarily
+ SHR BX,1
+ SHR BX,1 ; ST(1) becomes ST(0) in tag word
+ CALL RotateChip ; get 1st in-use register into ST(1)
+ FLD TBYTE PTR [REG8087ST0] ; reload ST(0)
+ SHL BX,1
+ SHL BX,1 ; adjust tag word for reloaded ST(0)
+ OR BL,003h ; Indicate ST(0) is full
+ JMP SHORT EndST1EmptyCheck ; ST(0) and ST(1) are full
+
+lab LoadST1FromMemory
+ MOV eSI,[CURstk] ; Get pointer to memory stack
+ CMP eSI,[BASstk] ; Anything in memory to load?
+ JE short EndST1EmptyCheck ; No, so don't load it.
+
+ OR BL,00Ch ; Indicate ST(1) is full
+ FINCSTP ; Point to ST(1)
+ FINCSTP ; Point to ST(2)
+ FLD TBYTE PTR [eSI] ; Load value from memory into ST(1).
+ FDECSTP ; Point to ST(0)
+ POPST ; Let POPST decrement memory pointer.
+
+lab EndST1EmptyCheck
+
+; At this point we know that ST(0) is full. ST(1) may or may not be full
+; and may or may not be needed.
+; Now we look at the instruction opcode and begin categorizing instructions
+; to determine whether they can cause stack underflow and if so, whether
+; they require ST(0) only or ST(1) as well.
+
+ MOV DX,ENV_Opcode[eBP] ; Get the instruction op code
+ XOR DX,001E0h ; Toggle arith, mod, and special bits
+
+; Test for mod of 0,1, or 2 (indicates memory operand)
+
+ TEST DL,0C0h ; Memory operand instruction?
+ JNZ short StackUnderflowServiced ; Yes, then stack underflow cannot
+ ; be a problem since memory instructions
+ ; require at most one stack operand
+ ; and we know that ST(0) is full
+
+; Test bits 5 & 8 of instruction opcode: of remaining instructions, only those
+; with stack relative operands do NOT have both of these bits as 1 in the opcode
+; (remember these bits are toggled).
+
+ TEST DX,00120h ; ST Relative Op group?
+ JNZ short STRelativeOpGroup ; Yes - ST Relative Ops
+
+lab ConstOrTrans
+
+; Test bit 4 of the instruction opcode: of remaining instructions, only the
+; transcendentals have this bit set.
+
+ TEST DL,010h ; Constant or arith instruction?
+ JNZ short TranscendentalInst ; No - must be Transcendental
+
+; The instructions that get to here are the constant instructions and
+; FCHS, FABS, FTST and FXAM. The constant instructions do not have any
+; stack operands; the others require ST(0) which we know is valid.
+; Therefore, none of the remaining instructions can cause stack underflow.
+
+lab StackUnderflowServiced
+ JMP InvalidReexecute ; Stack underflow corrected
+ ; reexecute instruction
+
+lab TranscendentalInst
+; Transcendentals may require one or two stack elements as operands.
+; Here we decide whether or not ST(1) needs to be present.
+
+ MOV CL,DL ; Need low op code in CL
+ AND CL,00Fh ; Mask to low four bits
+
+; Read the next block of comments column-wise. It shows the transcendental
+; instructions represented by each bit in the constant loaded into DX below.
+; Note: as it turns out, of the instructions requiring two operands below,
+; only FSCALE and FPREM generate invalid exceptions when the second operand
+; is missing.
+ ; FFFFFRFFFFFRFFRR
+ ; 2YPPXEDIPYSERSEE
+ ; XLTATSENRLQSNCSS
+ ; M2ATRECCE2REDAEE
+ ; 1XNAARSSMXTRILRR
+ ; ...NCVTT.P.VNEVV
+ ; ....TEPP.1.ET.EE
+ ; .....D.....D..DD
+
+ MOV DX,0101000011000100b ; 1's for 2 operand instructions
+
+ SHL DX,CL ; Get corresponding bit into sign
+ JNS short StackUnderflowServiced ; If just ST(0) needed we're O.K.
+
+ TEST BL,00Ch ; ST(1) full?
+ JNZ short StackUnderflowServiced ; Yes - stack underflow no problem
+
+lab STRelativeOpGroup
+
+; The following code block handles the general operand ST(x) even though
+; the original code generator only uses ST(0) and ST(1) as operands.
+; The current code generator uses ST(x) but will never cause stack underflow
+; exceptions.
+
+ AND DX,00007h ; Mask to relative register number
+ SHL DL,1 ; Compute tag word shift amount
+ MOV CX,DX ; Get amount into CL
+ MOV DX,BX ; Get tag into DX
+ ROR DX,CL ; Shift operand tag into low DL
+ TEST DL,003h ; Is operand register empty?
+ JNZ short InvalidReexecute ; No - go reexecute
+
+; The following conditions could cause a true underflow error to be
+; erroneously generated at this point:
+; FST ST(x) signals an invalid because ST(0) is empty. ST(0) gets filled
+; by the stack underflow recovery code in this handler, but then
+; the instruction is classified as an STRelative instruction and the
+; above paragraph of code checks if ST(x) is empty. HOWEVER, FST ST(x) does
+; not require ST(x) to be empty so a true underflow error should not occur.
+; This code should be changed if this situation can ever occur.
+
+ JMP TrueUnderflow ; true stack underflow
+
+;*** RotateChip - rotate coprocessor registers
+;
+; ENTRY
+; BX: tag word, complemented
+; ST(0): empty
+; at least one other register on the chip is non-empty
+; (or else this routine will loop infinitely)
+;
+; RETURNS
+; BX: updated tag word, complemented
+; ST(0): non-empty
+;
+; DESCRIPTION
+; This routine rotates the registers on the coprocessor
+; until the first in-use register is in ST(0). This
+; will correct a stack underflow exception which has been
+; caused by old model code encountering a gap of free
+; registers created by new model code. The complemented
+; tag word is also updated appropriately.
+;
+lab RotateChip
+ ROR BX,1 ; Rotate tag word
+ ROR BX,1
+ FINCSTP ; Point to new ST(0)
+ TEST BX,00003h ; Is this register empty?
+ JZ short RotateChip ; No, go rotate again
+ RET
+
+lab TrueUnderflow
+ OR AH,StackUnderflow/256 ; indicate true stack underflow
+ MOV BYTE PTR ENV_StatusWord[eBP],0 ; Clear exceptions
+ FLDENV WORD PTR [eBP] ; Restore old environment.
+ POP eDI
+ POP eDX
+ POP eCX
+ POP eBX
+ POP eSI
+ JMP CleanUpHost ; Leave exception handler.
+
+lab InvalidReexecute
+ AND AL,0FFH-Invalid ; Reset invalid flag.
+ CALL ReDo8087Instruction ; Was invalid so redo instruction.
+
+ POP eDI
+ POP eDX
+ POP eCX
+ POP eBX
+ POP eSI
+ JMP WhileException
+endif ;_NOSTKEXCHLR
+
+;----------------------------------------------------------------------------
+
+PAGE
+lab ProcessDenormal
+
+ ; Correct 8087 bug. The FLD instruction signals a denormal
+ ; exception AFTER it has completed. Reexecuting FLD for a
+ ; denormal exception would thus mess up the 8087 stack. INTEL
+ ; documentation states denormal exceptions are BEFORE
+ ; exceptions, so there is a contradiction. To avoid reexecution
+ ; of FLD we do as follows: And op code with 138H to mask out
+ ; MOD, RM, ESC and memory format bits. Compare with 100H to
+ ; distinguish FLD from other instructions which could possibly
+ ; generate a denormal exception.
+
+ or byte ptr [UserStatusWord],Denormal ; set denorm bit
+ push ecx
+
+ mov cx,ENV_Opcode[eBP] ; see if we have a reg,reg operation
+ and cl, bMOD
+ cmp cl, bMOD ; if MOD = 11b then we have a reg,reg op
+ je notMemOpDenormal
+
+ mov cx,ENV_Opcode[eBP]
+ and cx, not (0fc00h or bMOD or bRM) ; remove escape, OpSizeBit, MOD and R/M
+
+ cmp cx,0008h ; check for FMUL real-memory
+ je short isMemOpDenormal
+
+ cmp cx,0010h ; check for FCOM real-memory
+ je short isMemOpDenormal
+
+ and cl,30h ; clear low opcode bit
+ cmp cx,0030h ; check for FDIV/FDIVR real-memory
+ jne short notMemOpDenormal
+
+; have FDIV/FDIVR real-memory
+; have FMUL real-memory
+; have FCOM real-memory
+;
+; do the following steps
+; 1. free ST(7) if not free to avoid stack overflow
+; 2. change instruction to FLD real-memory and redo
+; 3. normalize TOS
+; 4. change instruction to FMUL or FDIV[R]P ST(1),ST and redo
+
+lab isMemOpDenormal
+ TEST BH,0C0h ; 1. Possible stack overflow?
+ JZ short nostkovr ; No - bypass offloading stack
+ AND BH,0FFh-0C0h ; Indicate 1st above TOS is free
+ PUSHST ; Let PUSHST make room for value.
+ FDECSTP ; Point to bottom stack element.
+ FSTP TBYTE PTR [eSI] ; Store out bottom stack element.
+lab nostkovr
+
+ mov cx,ENV_Opcode[ebp] ; 2. get original instruction
+ push cx ; save it for later
+ and cx,0400h
+ add cx,0104h ; changed to FLD real DS:[SI]
+ mov ENV_Opcode[ebp],cx ; change for redo
+ call ReDoIt ; do FLD denormal
+
+ call normalize ; 3. normalize TOS
+
+ pop cx ; 4. restore original instruction
+ and cx,0038h ; reduce to operation
+ cmp cl,08h ; is it FMUL
+ je short isFMUL ; yes
+ cmp cl,10h ; is it FCOM
+ je short isFCOM ; yes
+
+ xor cl,08h ; must be FDIV[R] - flip R bit
+lab isFMUL
+ or cx,06C1h ; or to FoprP ST(1),ST
+ mov ENV_Opcode[ebp],cx ; change for redo
+ call ReDo8087Instruction ; do FDIV[R]P ST(1),ST
+ jmp short denormaldone ; done with FDIV[R] denormal
+
+lab notMemOpDenormal
+ MOV cx,ENV_Opcode[eBP]
+
+ and cx, 0738h
+ cmp cx, 0328h
+ je short noredo ; check for FLD long double
+
+ AND cx,0138H
+ CMP cx,0100H ; check for FLD float/double
+ JZ short noredo
+
+ CALL ReDo8087Instruction ; redo other instructions
+lab noredo
+ call normalize
+ jmp short denormaldone
+
+; FCOM is a little more complicated to recover because of status
+;
+; FCOM is like FDIV in that the operands need to be exchanged
+; and the value loaded onto the chip needs to be popped.
+;
+; This routine is like a mini ReDo8087Instruction
+
+lab isFCOM
+ OR AH,Reexecuted/256 ; Flag instruction reexecuted
+ FCLEX ; clear exceptions
+ FXCH ; swap ST(0) and ST(1)
+ FCOM ST(1) ; so that ST(1) is the "source"
+ FXCH
+ FSTP ST(0) ; toss stack entry
+ FSTSW [NewStatusWord] ; get status word
+ FWAIT
+ OR AL,BYTE PTR [NewStatusWord] ; Include new with unhandled exceptions
+
+lab denormaldone
+ pop ecx
+ AND AL,0FFh-Denormal ; clear denormal exception
+ jmp WhileException
+
+lab normalize
+ fstp tbyte ptr ENV_Temp[ebp] ; save denormal/unnormal
+ fwait
+
+ mov cx,ENV_Temp[ebp+8] ; get old exponent
+ test cx,07FFFh ; test for zero exponent
+ jz short isdenormal ; denormal temp real
+
+ test byte ptr ENV_Temp[ebp+7],80h ; test for unnormal
+ jnz short isnormal ; no - skip normalization
+
+ fild qword ptr ENV_Temp[ebp] ; load mantissa as integer*8
+ fstp tbyte ptr ENV_Temp[ebp] ; save mantissa
+ fwait
+
+ cmp word ptr ENV_Temp[ebp+8],0 ; check for 0.0
+ je short isdenormal ; yes - we had a pseudo-zero
+
+ sub cx,403Eh ; exponent adjust (3fff+3f)
+ add ENV_Temp[ebp+8],cx ; add to mantissa exponent
+
+lab isnormal
+ fld tbyte ptr ENV_Temp[ebp] ; reload normalized number
+ ret
+
+lab isdenormal
+ xor cx,cx ; make it into a zero
+ mov ENV_Temp[ebp],cx
+ mov ENV_Temp[ebp+2],cx
+ mov ENV_Temp[ebp+4],cx
+ mov ENV_Temp[ebp+6],cx
+ mov ENV_Temp[ebp+8],cx
+ jmp isnormal ; reload it as zero
+
+PAGE
+lab ProcessNumericOverflow
+
+ ; We must reexecute for numeric overflow only if the instruction
+ ; was an FST or FSTP. This is because only these instructions
+ ; signal the exception before the instruction is executed.
+ ; If we reexecute under other conditions the state of the 8087
+ ; will be destroyed. Only memory operand versions of FST and
+ ; FSTP can produce the Overflow exception, and of all the
+ ; non-arithmetic memory operand instructions, only FST and
+ ; FSTP produce overflow exceptions. Thus it is sufficient
+ ; to reexecute only in case of non-arithmetic memory operand
+ ; instructions. To check for these and the op code with 001C0H
+ ; to mask down to the arith and MOD fields, flip the arith
+ ; bit by xoring with 00100H and if the result is below 000C0H
+ ; then we have a non-arithmetic memory operand instruction.
+
+ PUSH eAX
+ MOV AX,ENV_Opcode[eBP]
+ AND AX,001C0H
+ XOR AH,001H
+ CMP AX,000C0H
+ POP eAX
+ JAE short NumericOverflowRet
+
+ CALL ReDo8087Instruction
+
+lab NumericOverflowRet
+ JMP WhileException
+
+PAGE
+;----------------------------------------------------------------------------
+; Reexecute aborted 8087 instruction, and include any exceptions in ENV [BP]
+;----------------------------------------------------------------------------
+
+ifdef WINDOWS
+lab ReDo8087InstructionRet
+ ret
+endif
+
+lab ReDo8087Instruction
+ TEST AH,Reexecuted/256 ; Already reexecuted?
+ JNZ short ReDo8087InstructionRet ; If so don't do it again
+ OR AH,Reexecuted/256 ; Flag instruction reexecuted
+
+lab ReDoIt
+ PUSH DS
+ PUSH eDI
+ PUSH eSI
+ PUSH eCX
+ PUSH eBX
+ FCLEX ; clear error summary flags
+
+
+ifdef WINDOWS
+ mov di, ss ; assume SS
+ mov bx, __WINFLAGS
+ test bx, WF_PMODE
+ jz SkipSSAlias
+
+ push es
+; push ax ; CHICAGO needs 32-bit register saves ...
+; push dx
+
+ push eax ; for CHICAGO
+ push ebx ; for CHICAGO
+ push ecx ; for CHICAGO
+ push edx ; for CHICAGO
+ push ebp ; for CHICAGO
+ push esi ; for CHICAGO
+ push edi ; for CHICAGO
+
+ push ss
+ call ALLOCDSTOCSALIAS
+
+ pop edi ; for CHICAGO
+ mov di, ax
+
+; pop dx ; CHICAGO needs 32-bit register restores
+; pop ax
+
+ pop esi ; for CHICAGO
+ pop ebp ; for CHICAGO
+ pop edx ; for CHICAGO
+ pop ecx ; for CHICAGO
+ pop ebx ; for CHICAGO
+ pop eax ; for CHICAGO
+ pop es
+
+ or di, di
+ jz ReExecuteRestoreRet
+lab SkipSSAlias
+
+else ;not WINDOWS
+
+ifdef DOS3and5
+ mov di,ss ; assume SS
+ cmp [protmode],0 ; check if protect mode
+ je noSSalias ; no - don't get SS alias
+endif ;DOS3and5
+
+ifdef DOS5
+
+ifdef SQL_EMMT
+ push ax
+
+ push ss ; The SQL server may have switched stacks
+ push ds ; so update SSalias.
+ mov ax,offset SSalias
+ push ax
+ os2call DOSCREATECSALIAS
+
+ pop ax
+endif ;SQL_EMMT
+
+ mov di,[SSalias] ; Get segment alias to stack
+endif ;DOS5
+
+endif ;not WINDOWS
+
+ifdef DOS3and5
+lab noSSalias
+endif ;DOS3and5
+
+ MOV CX,ENV_Opcode[eBP] ; Get aborted 8087 instruction.
+ MOV BX,CX ; Copy instruction.
+ AND CH,07H ; Clear upper 5 bits.
+ OR CH,0D8H ; "OR" in escape code.
+ AND BL,0C0H ; Mask to MOD field.
+ XOR BL,0C0H ; If MOD = "11" (no memory operand)
+ JZ short REEXECUTE ; then address mode modification code
+ ; must be bypassed.
+ AND CL,38H ; Clear MOD and RM fields,
+ OR CL,4H ; Turn on bits in MOD and RM fields
+ ; to force DS:[SI+0] addressing.
+ LDS SI,ENV_OperandPointer[eBP] ; DS:SI <-- operand address
+
+lab REEXECUTE
+ XCHG CH,CL ; convert to non-byte swapped
+ ; code format
+ ;
+ ; Stack restart method. Restart instruction in interrupt stack
+ ; frame. Code is reentrant.
+ ;
+
+ifdef WINDOWS
+ mov ENV_CallSegment[ebp],di ; Code segment alias to stack
+elseifdef DOS5
+ mov ENV_CallSegment[ebp],di ; Code segment alias to stack
+else
+ MOV ENV_CallSegment[eBP],SS ; Stack segment
+endif
+
+ LEA eDI,ENV_CallFwait[eBP] ; Offset to code in stack.
+ MOV ENV_CallOffset[BP],eDI
+ MOV BYTE PTR ENV_CallFwait[eBP],09BH ; FWAIT.
+ MOV ENV_Call8087Inst[eBP],CX ; 8087 instruction.
+ MOV BYTE PTR ENV_CallLongRet[eBP],0CBH ; Intra segment return.
+ CALL DWORD PTR ENV_CallOffset[eBP] ; Reexecute instruction.
+
+ifdef WINDOWS
+ mov bx, __WINFLAGS
+ test bx, WF_PMODE
+ jz ReExecuteRestoreRet
+
+ push es ; if in PMODE, free alias
+; push ax ; CHICAGO needs 32-bit register saves
+; push dx
+
+ push eax ; for CHICAGO
+ push ebx ; for CHICAGO
+ push ecx ; for CHICAGO
+ push edx ; for CHICAGO
+ push ebp ; for CHICAGO
+ push esi ; for CHICAGO
+ push edi ; for CHICAGO
+
+ push ENV_CallSegment[eBP]
+ call FREESELECTOR
+
+; pop dx ; CHICAGO needs 32-bit register restores
+; pop ax
+
+ pop edi ; for CHICAGO
+ pop esi ; for CHICAGO
+ pop ebp ; for CHICAGO
+ pop edx ; for CHICAGO
+ pop ecx ; for CHICAGO
+ pop ebx ; for CHICAGO
+ pop eax ; for CHICAGO
+ pop es
+endif ;WINDOWS
+
+
+lab ReExecuteRestoreRet
+ POP eBX
+ POP eCX
+ POP eSI
+ POP eDI
+ POP DS
+
+ifdef SQL_EMMT
+ push ax ; free the ss alias because we always
+ push [SSalias] ; get a new one for the SQL_EMMT
+ os2call DOSFREESEG
+ pop ax
+endif ;SQL_EMMT
+
+
+ FSTSW [NewStatusWord] ; 8/18/84 GFW need proper DS set
+ FWAIT
+ OR AL,BYTE PTR [NewStatusWord] ; Include new with unhandled exceptions
+
+ifndef WINDOWS
+lab ReDo8087InstructionRet
+endif
+ RET
+
+ProfEnd EXCEPT
diff --git a/private/mvdm/wow16/win87em/emfadd.asm b/private/mvdm/wow16/win87em/emfadd.asm
new file mode 100644
index 000000000..74a00e404
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfadd.asm
@@ -0,0 +1,251 @@
+ page ,132
+ subttl emfadd.asm - Addition and Subtraction
+;***
+;emfadd.asm - Addition and Subtraction
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Addition and Subtraction
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+;-----------------------------------------;
+; ;
+; Addition and Subtraction ;
+; ;
+;-----------------------------------------;
+
+ProfBegin FADD
+
+RABRQQ: ; Routine Add Both must see if we have two singles.
+
+if fastSP
+ MOV BX,DX
+ XOR BX,Single + 256*Single
+ TEST BX,Single + 256*Single
+ JNZ RADRQQ
+ MOV BX,OFFSET TASRQQ
+ JMP [BX]
+endif ;fastSP
+
+
+pub RADRQQ ; RoutineAddDouble SI & DI point to valid non-0 reals
+ ; AX CX are the exponents
+ ; DL DH are the signs
+if fastSP
+ CALL CoerceToDouble ; insure that both args are double
+endif ;fastSP
+
+ SUB AX,CX ; See which number is larger
+ JL short DIBIG
+ XCHG esi,edi ; Swap pointers to operands
+ XCHG DH,DL ; Swap signs
+ ADD CX,AX ; CX = larger exponent (Tentative result)
+ NEG AX
+pub DIBIG ; DI = larger, CX = expon, DH = sign
+ NEG AX
+ CMP AX,64+3 ; Is smaller argument significant?
+ JLE short SIGNIF
+
+ PUSH ebp ; Not signif so result is at DI except for
+ PUSH edx ; rounding. ROUND assumes old BP and Sign on
+ MOV SI,Expon[edi] ; stack. Exponent in SI
+ MOV BP,1 ; Other argument collapses into a sticky bit
+ XOR DL,DH ; if signs of operands differ bit is negative
+ JNS short GetOpMantissa
+ NEG BP
+pub GetOpMantissa
+ MOV DX,MB0[edi]
+ MOV CX,MB2[edi]
+ MOV BX,MB4[edi]
+ MOV DI,MB6[edi]
+ OR BP,BP
+ JS short NegativeStickyBit
+ JMP ROUND
+
+pub NegativeStickyBit
+ SUB DX,1 ; Must propagate negative sticky bit
+ SBB CX,0
+ SBB BX,0
+ SBB DI,0
+ JMP NODRQQ
+
+pub SIGNIF
+; Now things look like this:
+; SI has pointer to smaller operand
+; DI has pointer to larger operand
+; AX has exponent difference ( 0 <= CL <= 53 )
+; CX has exponent
+; DH has sign
+
+ PUSH ebp ; Need all the registers
+ PUSH edx ; Save sign
+ PUSH ecx ; Save exponent
+ XOR DL,DH ; Must eventually know whether signs are same
+ PUSHF
+
+ MOV BP,AX ; Need all 8-bit registers now
+
+; Load smaller operand
+
+ LODS word ptr ds:[esi]
+ MOV DX,AX
+ LODS word ptr ds:[esi]
+ MOV CX,AX
+ LODS word ptr ds:[esi]
+ MOV BX,AX
+ LODS word ptr ds:[esi]
+ XOR si,si ; BP Will be round,guard, & sticky bits (=0)
+ XCHG bp,si ; Done with Pointer to small. so SI = shift cnt
+
+; hi lo 0
+; Smaller operand now in AX:BX:CX:DX:BP with implied bit set, SI has shift count
+
+ OR si,si
+ JZ ALIGNED ; Alignment operations necessary?
+pub CHKALN
+ CMP si,14 ; Do shifts of 16 bits by word rotate
+ JL short BYTSHFT ; If not enough for word, go try byte
+ OR BP,BP ; See if we're shifting something off the end
+ JZ short NOSTIK
+ OR DX,1 ; Ensure sticky bit will be set
+pub NOSTIK
+ MOV BP,DX
+ MOV DX,CX
+ MOV CX,BX
+ MOV BX,AX
+ XOR AX,AX
+ SUB si,16 ; Counts for 16 bit shifts
+ JA short CHKALN ; If not enough, try again
+ JZ short ALIGNED ; Hit it exactly?
+ JB short SHFLEF ; Back up if too far
+
+pub BYTSHFT
+ CMP si,6 ; Can we do a byte shift?
+ JL short BITSHFT
+ XCHG BP,AX
+ OR AL,AL
+ JZ short NSTIK
+ OR AH,1
+pub NSTIK
+ MOV AL,AH
+ MOV AH,DL
+ XCHG BP,AX
+ MOV DL,DH
+ MOV DH,CL
+ MOV CL,CH
+ MOV CH,BL
+ MOV BL,BH
+ MOV BH,AL
+ MOV AL,AH
+ XOR AH,AH
+ SUB SI,8
+ JA short BITSHFT
+ JZ short ALIGNED
+
+; To get here, we must have used a byte shift when we needed to shift less than
+; 8 bits. Now we must correct by 1 or 2 left shifts.
+
+pub SHFLEF
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+ RCL AX,1
+ INC SI
+ JNZ SHFLEF ; Until DI is back to zero (from -1 or -2)
+ JMP SHORT ALIGNED
+
+pub BITSHFT
+ifdef i386
+ and esi,0FFFFh ; clear upper half of esi
+endif
+ XCHG ecx,esi ; Swap count into CX, lo3:lo4 into DI
+ TEST BP,3FH ; See if we're shifting stuff off the end
+ JZ short SHFRIG
+ OR BP,20H ; Set sticky bit if so
+pub SHFRIG
+ SHR AX,1
+ RCR BX,1
+ RCR SI,1
+ RCR DX,1
+ RCR BP,1
+ LOOP SHFRIG ; Do 1 to 5 64-bit right shifts
+ MOV CX,SI ; Get back CX = lo3:lo4
+pub ALIGNED
+ MOV esi,edi ; Address of larger operand
+ MOV DI,AX ; Now DI = msb:mid
+ TEST BP,3FFFH ; Collapse LSBs into sticky bit
+ JZ short GETSIGN
+ OR BP,1 ; Set sticky bit
+pub GETSIGN
+ POPF ; Recover XOR of signs
+ ; 80286 errata for POPF shouldn't
+ ; apply because interrupts should be
+ ; turned on in this context
+ POP eax ; Recover Exponent
+; Sign flag is XOR of signs
+
+ JS short SUBMAN ; Subtract mantissas if signs are different
+ ADD DX,[esi]
+ ADC CX,[esi+2]
+ ADC BX,[esi+4]
+ ADC DI,[esi+6]
+ JNC short JROUND ; Done if no overflow
+
+; Have a carry, so result must be shifted right and exponent incremented
+ RCR DI,1
+ RCR BX,1
+ RCR CX,1
+ RCR DX,1
+ RCR BP,1
+ JNC short STIKYOK
+ OR BP,1 ; Shifted out the sticky bit so reset it.
+pub STIKYOK
+ INC AX ; Bump exponent.
+; JMP JROUND ; and go round. (need not normalize)
+
+pub JROUND
+ MOV SI,AX ; We must have SI equal to exponent
+ JMP ROUND ; on our way to Round
+
+pub SUBMAN
+; Subtract mantissas since signs are different. We'll be subtracting larger
+; from smaller, so sign will be inverted first after the subtraction.
+
+ SUB DX,[esi]
+ SBB CX,[esi+2]
+ SBB BX,[esi+4]
+ SBB DI,[esi+6]
+ JNC short JNORM ; Won't carry if we mixed up larger and smaller
+
+; As expected, we got a carry which means we original sign was OK
+ XOR SI,SI ; We'll need a zero, so let's use SI
+ NOT DI
+ NOT BX
+ NOT CX
+ NOT DX
+ NEG BP ; Carry clear if zero
+ CMC ; Set CY
+ ADC DX,SI
+ ADC CX,SI ; Propagate carry
+ ADC BX,SI
+ ADC DI,SI
+ MOV SI,AX ; Get exponent to SI
+ JMP NODRQQ ; Go normalize
+
+pub JNORM
+ MOV SI,AX ; Exponent in SI
+ POP eax
+ XOR AH,SIGN ; invert sign bit (on top of stack)
+ PUSH eax
+ JMP NODRQQ ; and go normalize
+
+ProfEnd FADD
diff --git a/private/mvdm/wow16/win87em/emfcom.asm b/private/mvdm/wow16/win87em/emfcom.asm
new file mode 100644
index 000000000..2bdb990f4
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfcom.asm
@@ -0,0 +1,198 @@
+ page ,132
+ subttl emfcom.asm - Comparison instructions
+;***
+;emfcom.asm - Comparison instructions
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Comparison instructions
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Comparison instructions: FCOM,FCOMP,FCOMPP,FTST,FXAM ;
+; ;
+;*********************************************************************;
+
+ProfBegin FCOM
+
+
+pub eFCOMP
+ MOV DX,1 ; Counts number of POPs needed (0 or 1)
+ JMP short CommonCOM
+pub eFCOM
+ XOR DX,DX ; No extra POP needed at end
+
+pub CommonCOM ; SI points to ST, DI points to source
+ TEST WORD PTR [CURerr],MemoryOperand
+ JZ short ComSIandDIset
+ XCHG esi,edi ; Switch SI, DI for memory operands
+
+pub ComSIandDIset
+ MOV AL,Flag[esi] ; All comparisons are ST ? source
+ MOV AH,Flag[edi] ; Fetch signs
+ XOR ebx,ebx
+ MOV BL,Tag[esi]
+ SHL BL,1
+ SHL BL,1
+ OR BL,Tag[edi]
+ifdef i386
+ JMP COMtab[4*ebx]
+else
+ SHL BL,1
+ JMP COMtab[ebx]
+endif
+
+pub COMvalidvalid
+if fastSP
+ MOV BX,AX ; Keep copy of the Single Flags
+endif
+ XOR AH,AL ; Are signs different?
+ JS short COMsignSI ; if so then sign of SI will determine
+ OR AL,AL ; else signs are same. See if negative
+ JNS short CompareExponents ; If negative then reverse sense of compare
+ XCHG esi,edi ; by swapping the arguments
+ XCHG BL,BH ; Swap single flags
+
+pub CompareExponents
+ MOV AX,Expon[esi]
+ CMP AX,Expon[edi]
+ JL short COMless
+ JG short COMgreater
+
+pub CompareMantissas
+if fastSP
+ XOR BH,BL
+ TEST BH,Single ; Were both args the same length?
+ JNZ DifferentTypes
+ TEST BL,Single ; Args same type - Single?
+ JZ BothDouble
+ MOV ecx,3 ; Compare 3 bytes of mantissa
+DoCompare:
+ ADD esi,MB7 ; point to most significant byte
+ ADD edi,MB7
+ STD
+ REP CMPS word ptr es:[edi],word ptr ds:[esi]
+ CLD
+else
+ mov ecx,4 ; compare 4 words of mantissa
+ ADD esi,MB6 ; point to most significant word
+ ADD edi,MB6
+ STD
+ REP CMPS word ptr [edi],word ptr [esi]
+ CLD
+endif
+ JB short COMless
+ JA short COMgreater
+
+pub COMequal
+ MOV [SWcc],CCequal
+ JMP short COMexit
+
+if fastSP
+DifferentTypes:
+ TEST BL,Single
+ JNZ CoerceSI
+ MOV word ptr MB0[edi],0
+ MOV word ptr MB2[edi],0
+ MOV byte ptr MB4[edi],0
+ MOV ecx,8 ; Compare 8 bytes of mantissa
+ JMP DoCompare
+
+CoerceSI:
+ MOV word ptr MB0[esi],0
+ MOV word ptr MB2[esi],0
+ MOV byte ptr MB4[esi],0
+BothDouble:
+ MOV ecx,8 ; Compare 8 bytes of mantissa
+ JMP DoCompare
+endif
+
+pub COMless
+ MOV [SWcc],CCless
+ JMP short COMexit
+
+pub COMgreater
+ MOV [SWcc],CCgreater
+ JMP short COMexit
+
+pub COMincomprable
+ OR [CURerr],Invalid
+pub COMincompr0
+ MOV [SWcc],CCincomprable
+ JMP short COMexit
+
+pub COMsignSIinf ; if projective inf numbers are incomprable
+ TEST [CWcntl],InfinityControl
+ JZ COMincompr0
+pub COMsignSI ; sign of SI tells all (DI = 0)
+ AND AL,Sign
+ JS COMless
+ JMP COMgreater
+
+pub COMsignDIinf ; if projective inf numbers are incomprable
+ TEST [CWcntl],InfinityControl
+ JZ COMincompr0
+pub COMsignDI ; sign of DI tells all (SI = 0)
+ AND AH,Sign
+ JS COMgreater
+ JMP COMless
+
+pub COMinfinf
+ TEST [CWcntl],InfinityControl
+ JZ COMincompr0
+ XOR AH,AL ; Are signs the same?
+ AND AH,Sign
+ JZ COMequal ; yes - infinities are equal
+ JMP COMsignSI ; else SI negative implies it is less
+
+pub COMexit
+ OR DX,DX ; do we need to pop the stack?
+ JZ short COMreturn
+ POPST
+pub COMreturn
+ RET
+
+pub eFXAM
+ MOV esi,[CURstk]
+
+ mov al, 41h ; see if stack was empty
+ cmp esi,[BASstk]
+ je RetFXAM
+
+ MOV AX,Flag[esi] ; Sign in AH, Tag in AL
+ XCHG AL,AH
+ ROL AX,1
+ AND AL,7 ; Mask to Tag-Sign
+ MOV ebx,offset XAMTAB
+ XLAT byte ptr cs:[ebx] ; Convert to condition code
+
+pub RetFXAM
+ MOV [SWcc],AL ; Stuff into hi-byte of status word
+ RET
+
+pub eFTST
+ MOV esi,[CURstk]
+ MOV AL,Flag[esi]
+ AND AL,Sign ; Mask to sign only
+ XOR ebx,ebx
+ MOV edx,ebx ; DX 0 to indicate no POP in COMP
+ MOV BL,Tag[esi]
+ifdef i386
+ jmp TSTtab[4*ebx]
+else
+ SHL ebx,1
+ JMP TSTtab[ebx]
+endif
+
+ProfEnd FCOM
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/win87em/emfconst.asm b/private/mvdm/wow16/win87em/emfconst.asm
new file mode 100644
index 000000000..7d1a0faf0
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfconst.asm
@@ -0,0 +1,78 @@
+ page ,132
+ subttl emfconst.asm - Loading of 8087 on chip constants
+;***
+;emfconst.asm - Loading of 8087 on chip constants
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Loading of 8087 on chip constants
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+;-----------------------------------------;
+; ;
+; Constant Loading ;
+; ;
+;-----------------------------------------;
+
+;---------------------------------------------------
+; !
+; 8087 emulator constant loading !
+; !
+;---------------------------------------------------
+
+ProfBegin FCONST
+
+
+LoadConstantEntry MACRO cName,Position
+pub e&cName
+ mov ebx,offset c&cName
+ IFIDN <&Position>,<Last>
+ ELSE ;IFIDN <&Position>,<Last>
+ jmp short CommonConst
+ ENDIF ;IFIDN <&Position>,<Last>
+ ENDM
+
+ifndef frontend
+ifndef SMALL_EMULATOR
+
+LoadConstantEntry FLDPI,NotLast
+
+LoadConstantEntry FLDL2T,NotLast
+
+LoadConstantEntry FLDL2E,NotLast
+
+LoadConstantEntry FLDLG2,NotLast
+
+LoadConstantEntry FLDLN2,NotLast
+
+endif ;not SMALL_EMULATOR
+endif ;not frontend
+
+LoadConstantEntry FLDZ,NotLast
+
+LoadConstantEntry FLD1,Last
+
+pub CommonConst
+ PUSHST
+ MOV esi,ebx
+ MOV edi,[CURstk]
+ifdef i386
+ rept Reg87Len/4
+ MOVS dword ptr es:[edi], dword ptr cs:[esi]
+ endm
+else
+ rept Reg87Len/2
+ MOVS word ptr es:[edi], word ptr cs:[esi]
+ endm
+endif
+ RET
+
+ProfEnd FCONST
diff --git a/private/mvdm/wow16/win87em/emfdiv.asm b/private/mvdm/wow16/win87em/emfdiv.asm
new file mode 100644
index 000000000..aa9ba82aa
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfdiv.asm
@@ -0,0 +1,252 @@
+ page ,132
+ subttl emfdiv.asm - Division
+;***
+;emfdiv.asm - Division
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Division
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;-----------------------------------------;
+; ;
+; Division ;
+; ;
+;-----------------------------------------;
+
+ProfBegin FDIV
+
+RDBRQQ: ; Routine Div Both must see if we have two singles.
+
+if fastSP
+ MOV BX,DX
+ XOR BX,Single + 256*Single
+ TEST BX,Single + 256*Single
+ JNZ RDDRQQ
+ MOV bx,offset TDSRQQ
+ JMP [bx]
+endif ;fastSP
+
+
+pub RDDRQQ ; Routine Division Double
+; Now we have
+; SI --> numerator , AX - Expon , DL - Sign
+; DI --> denominator , CX - Expon , DH - Sign
+
+if fastSP
+ CALL CoerceToDouble ; insure that both args are double
+endif ;fastSP
+
+ STC ; exponent will be difference - 1
+ SBB AX,CX ; compute result exponent
+
+; AH has the (tentative) true exponent of the result. It is correct if the
+; result does not need normalizing. If normalizing is required, then this
+; must be incremented to give the correct result exponent
+
+ XOR DH,DL ; Compute sign
+ PUSH ebp
+ PUSH edx ; Save sign
+ PUSH esi
+ PUSH edi
+ ADD esi,6
+ ADD edi,6
+ MOV ecx,4
+ STD
+ REP CMPS word ptr [esi],word ptr [edi] ; compare numerator mantissa
+ CLD ; with denominator mantissa
+ POP edi
+ POP esi
+ PUSHF ; save the flags from the compare
+ MOV BP,AX ; save the exponent
+ LODS word ptr [esi] ; Load up numerator
+ MOV CX,AX
+ LODS word ptr [esi]
+ MOV BX,AX
+ LODS word ptr [esi]
+ MOV DX,AX
+ LODS word ptr [esi]
+ XCHG AX,DX
+
+; Move divisor to DAC so we can get at it easily.
+
+ MOV esi,edi ; Move divisor to DAC
+ MOV edi,offset DAC
+ifdef i386
+ MOVSD
+ MOVSD
+else
+ MOVSW
+ MOVSW
+ MOVSW
+ MOVSW
+endif
+
+; Now we're all set:
+; DX:AX:BX:CX has dividend
+; DAC has divisor (in normal format)
+; Both are 64 bits with zeros and have implied bit set.
+; Top of stack has sign and tentative exponent.
+
+ XOR DI,DI
+ POPF ; numerator mantissa < denominator?
+ ; 80286 errata for POPF shouldn't
+ ; apply because interrupts should be
+ ; turned on in this context
+ JB short DivNoShift ; if so bypass numerator shift
+ SHR DX,1 ; Make sure dividend is smaller than divisor
+ RCR AX,1 ; by dividing it by two
+ RCR BX,1
+ RCR CX,1
+ RCR DI,1
+ INC BP ; increment result exponent
+pub DivNoShift
+ PUSH ebp ; save result exponent
+ MOV [REMLSW],DI ; Save lsb of remainder
+ CALL DIV16 ; Get a quotient digit
+ PUSH edi
+ MOV [REMLSW],0 ; Turn off the shifted bit
+ CALL DIV16
+ PUSH edi
+ CALL DIV16
+ PUSH edi
+ CALL DIV16
+ MOV BP,8001H ; turn round and sticky on
+ SHL CX,1
+ RCL BX,1
+ RCL AX,1
+ RCL DX,1 ; multiply remainder by 2
+ JC short BPset ; if overflow, then round,sticky valid
+ MOV esi,offset DAC
+ CMP DX,[esi+6]
+ JNE short RemainderNotHalf
+ CMP AX,[esi+4]
+ JNE short RemainderNotHalf
+ CMP BX,[esi+2]
+ JNE short RemainderNotHalf
+ CMP CX,[esi] ; compare 2*remainder with denominator
+
+;Observe, oh wondering one, how you can assume the result of this last
+;compare is not equality. Use the following notation: n=numerator,
+;d=denominator,q=quotient,r=remainder,b=base(2^64 here). If
+;initially we had n < d then there was no shift and we will find q and r
+;so that q*d+r=n*b, if initially we had n >= d then there was a shift and
+;we will find q and r so that q*d+r=n*b/2. If we have equality here
+;then r=d/2 ==> n={possibly 2*}(2*q+1)*d/(2*b), since this can only
+;be integral if d is a multiple of b, but by definition b/2 <= d < b, we
+;have a contradiction. Equality is thus impossible at this point.
+
+pub RemainderNotHalf ; if 2*remainder > denominator
+ JAE short BPset ; then round and sticky are valid
+ OR AX,DX
+ OR AX,CX
+ OR AX,BX
+ OR AL,AH ; otherwise or sticky bits into AL
+ XOR AH,AH ; clear round bit
+ MOV BP,AX ; move round and sticky into BP
+pub BPset
+ MOV DX,DI ; get low 16 bits into proper location
+ POP ecx
+ POP ebx
+ POP edi
+ POP esi ; Now restore exponent
+
+ JMP ROUND ; Result is normalized, round it
+
+
+; Remainder in DX:AX:BX:CX:REMLSW
+
+pub DIV16
+ MOV SI,[DAC+6] ; Get high word of divisor
+ XOR DI,DI ; Initialize quotient digit to zero
+ CMP DX,SI ; Will we overflow?
+ JAE MAXQUO ; If so, go handle special
+ OR DX,DX ; Is dividend small?
+ JNZ short DDIV
+ CMP SI,AX ; Will divisor fit at all?
+ JA short ZERQUO ; No - quotient is zero
+
+pub DDIV
+ DIV SI ; AX is our digit "guess"
+ PUSH edx ; Save remainder -
+ PUSH ebx ; top 32 bits
+ XCHG AX,DI ; Quotient digit in DI
+ XOR BP,BP ; Initialize quotient * divisor
+ MOV SI,BP
+ MOV AX,[DAC]
+ OR AX,AX ; If zero, save multiply time
+ JZ short REM2
+ MUL DI ; Begin computing quotient * divisor
+ MOV SI,DX
+
+pub REM2
+ PUSH eax ; Save lowest word of quotient * divisor
+ MOV AX,[DAC+2]
+ OR AX,AX
+ JZ short REM3
+ MUL DI
+ ADD SI,AX
+ ADC BP,DX
+
+pub REM3
+ MOV AX,[DAC+4]
+ OR AX,AX
+ JZ short REM4
+ MUL DI
+ ADD BP,AX
+ ADC DX,0
+ XCHG AX,DX
+
+; Remainder - Quotient * divisor
+; [SP+4]:[SP+2]:CX:REMLSW - AX:BP:SI:[SP]
+
+pub REM4
+ MOV DX,[REMLSW] ; Low word of remainder
+ POP ebx ; Recover lowest word of quotient * divisor
+ SUB DX,BX
+ SBB CX,SI
+ POP ebx
+ SBB BX,BP
+ POP ebp ; Remainder from DIV
+ SBB BP,AX
+ XCHG AX,BP
+
+pub ZERQUO ; Remainder in AX:BX:CX:DX
+ XCHG AX,DX
+ XCHG AX,CX
+ XCHG AX,BX
+ JNC short DRET ; Remainder in DX:AX:BX:CX
+
+pub RESTORE
+ DEC DI ; Drop quotient since it didn't fit
+ ADD CX,[DAC] ; Add divisor back in until remainder goes +
+ ADC BX,[DAC+2]
+ ADC AX,[DAC+4]
+ ADC DX,[DAC+6]
+ JNC RESTORE ; Loop is performed at most twice
+
+pub DRET
+ RET
+
+pub MAXQUO
+ DEC DI ; DI=FFFF=2**16-1, DX:AX:BX:CX is remainder,
+ SUB CX,[DAC] ; DX = [DAC+6], d = divisor = [DAC]
+ SBB BX,[DAC+2]
+ SBB AX,[DAC+4] ; subtract 2^16*d from DX:AX:BX:CX:0000H
+ ADD CX,[DAC+2] ; (DX-[DAC+6] = 0 is implied)
+ ADC BX,[DAC+4]
+ ADC AX,DX ; add high 48 bits of d to AX:BX:CX:0000H
+ MOV DX,[DAC] ; add low 16 bits of d to zero giving DX
+ CMC ; DI should be FFFEH if no carry from add
+ JMP ZERQUO
+
+ProfEnd FDIV
diff --git a/private/mvdm/wow16/win87em/emfixfly.asm b/private/mvdm/wow16/win87em/emfixfly.asm
new file mode 100644
index 000000000..1a080fc1b
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfixfly.asm
@@ -0,0 +1,336 @@
+ page ,132
+ subttl emfixfly.asm - Fixup-on-the-fly routines
+;***
+;emfixfly.asm - Fixup-on-the-fly routines
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Fixup-on-the-fly routines
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*******************************************************************************
+; 03/29/85 - added 286 optimizations to change FWAITs to NOPs
+; 09/10/87 - added FWAIT's for BASIC error handling
+; 11/02/87 - changed FWFixUpOnFly to check for errors
+;*******************************************************************************
+
+
+ProfBegin FIXFLY
+
+
+ifdef DOS3
+
+pub SOFixUpOnFly
+ sti ; turn on interrupts
+ fwait ; For BASIC error handling
+ push ax
+ push bp
+ push ds
+ push si
+ mov bp,sp ; Point to stack
+ lds si,dword ptr 8[bp] ; Fetch ret address,(points to after instruction)
+ mov al,[si] ; get ESC byte
+ or byte ptr [si],0C0h ; turn back into ESC x byte
+ dec si ; Make SI point to start off instruction
+ dec si
+ mov 8[bp],si ; Change ret address to return to instruction
+ shr al,1 ; move 2 bits into correct position
+ shr al,1
+ shr al,1
+ not al ; negate them
+ and al,018h ; mask to middle 2 bits
+ or al,fES ; turn into correct segmented override
+ xchg al,ah ; into high half
+ mov al,fFWAIT ; low byte
+ mov [si],ax ; stuff it
+ push bx
+ mov bx,1 ; bx = 1 to skip segment override
+ifdef WF
+ jmp fixupdone
+else
+ jmp short fixupdone
+endif
+
+; new routine - don't back patch - check for error
+; UNDONE - need to change this for Windows - can't edit code
+; need to check errorcode
+
+pub FWFixUpOnFly
+ sti ; turn on interrupts
+ fwait ; For BASIC error handling
+
+
+ifdef WF
+wfFaultHere = $-1
+; int 3
+ push ds ; ds[18] retip[20] retcs[22] retfl[24]
+ push es ; es[16]
+ pusha ;
+ mov bp, sp ;
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ cmp [wfGoFast], 1
+ jnz WinSlow
+ push [bp+22] ; faulting CS - get data alias
+ push [wfSel]
+ call ChangeSelector
+ mov es, [wfSel]
+ sub word ptr [bp+20], 2
+ mov bx, [bp+20] ; point to faulting insn
+ xor ax, ax
+ xchg [wfInsn], ax
+ or ax, ax ; are we here due to fault?
+ je wfNoFault
+ mov es:[bx], ax ; yes - restore 'fake' INT 3d
+ xor ax,ax
+ xchg [errorcode],al ; get and reset errorcode
+ mov REMLSW, ax ; save error code
+
+ popa
+ pop es
+ pop ds
+ jmp WinFastContinue
+
+; mov ax, 353eh
+; int 21h
+; mov ax, es ; does app have a handler?
+; or ax, bx
+; jz wfDone
+;
+; mov ax, [wfErr]
+;
+; push cs ; return to wfDone
+; push offset wfDone
+;
+; push es ; call app handler
+; push bx
+;
+; retf
+
+FWAITNOP equ (iNOP + 256*fFWAIT)
+wfNoFault: ; this was a 'real' INT 3d,
+ mov es:[bx], FWAITNOP ; so we'll patch it to inline code
+
+wfDone:
+ popa
+ pop es
+ pop ds
+ iret
+
+WinSlow: ; can't use fast method, fall through
+ popa
+ pop es
+ pop ds ; fall through into old code
+endif
+
+ifdef POLLING ; new exception handling under POLLING
+
+ifdef USE_IRET
+FWAITiret:
+ iret ; Edit to nop if error occurs
+
+elseifdef WINDOWS
+
+ push ds
+ push ax
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+
+ cmp [ExceptFlag], 0 ; if not zero, 80x87 exception occured.
+
+ pop ax
+ pop ds
+
+ jnz PolledException
+
+ iret
+
+else ;DEFUALT
+
+FWAITRetF db bRETF ; Edit to 3 byte nop if error occurs
+FWAITRetF2 dw 2
+
+endif ;DEFAULT
+
+
+pub PolledException
+ push eax ; same frame as in emerror.asm
+ push ds ; get address from task DS
+
+ifdef standalone
+ xor ax,ax
+ mov ds,ax
+ mov ds,ds:[4*TSKINT+2]
+
+elseifdef _COM_
+ mov ds, [__EmDataSeg]
+
+else ;not standalone or _COM_
+ mov ax,EMULATOR_DATA
+ mov ds,ax
+endif ;not standalone or _COM_
+
+ ;*
+ ;* Reset fwait polling flag.
+ ;*
+
+ifdef USE_IRET
+ mov byte ptr cs:[FWAITiret], bIRET ; reset "iret"
+
+elseifdef WINDOWS
+ mov [ExceptFlag], 0
+
+else ;DEFAULT
+ mov [FWAITRetF], bRETF ; reset "retf 2"
+ mov [FWAITRetF2], 2
+endif ;DEFAULT
+
+
+ xor ax,ax
+ xchg [errorcode],al ; get and reset errorcode
+
+
+ifdef WINDOWS
+ mov REMLSW, ax ; save error code
+
+ pop ds
+ pop ax ; stack is now just an int stack frame
+WinFastContinue:
+ inc bp
+ push bp
+ mov bp, sp
+ push ds
+
+ push ax ; save user's ax
+
+ push cs ; must set up another stack frame
+ mov ax, offset FF_DummyReturn
+ push ax
+FF_DummyReturn:
+
+ mov word ptr [bp-2], EMULATOR_DATA ; emulator's ds goes on first frame
+
+ inc bp
+ push bp
+ mov bp, sp
+ push ds ; push user's ds onto dummy stack frame
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+
+ push es ; if windows => setup SignalAddress for
+ push bx ; far call
+
+ mov ax, DOS_getvector*256 + TSKINT
+ IntDOS
+
+ mov word ptr [SignalAddress], bx
+ mov word ptr [SignalAddress+2], es
+
+ pop bx
+ pop es
+
+ mov ax, REMLSW ; al = error code
+
+ call [SignalAddress] ; execute signal routine
+
+ pop ds ; restore user's ds
+ add sp, 6 ; get rid of dummy stack frame
+ pop ax ; restore user's ax
+
+ add sp, 2 ; get rid of emulator ds on stack
+
+ pop bp
+ dec bp
+
+ iret ; return
+
+else ;not WINDOWS
+
+ call [SignalAddress] ; execute signal routine
+
+ pop ds ; restore user DS
+ pop eax
+ iret
+
+endif ;not WINDOWS
+
+
+else ;not POLLING
+ push ax
+ mov ax,FIWRQQ ; isolated FWAIT fixup
+ jmp short FixUpOnFly
+endif ;not POLLING
+
+pub DSFixUpOnFly
+ sti ; turn on interrupts
+ fwait ; For BASIC error handling
+ push ax
+ mov ax,FIDRQQ ; DS segment fixup
+
+pub FixUpOnFly
+ PUSH BP
+ PUSH DS
+ PUSH SI
+ MOV BP,SP ; Point to stack
+ LDS SI,dword ptr 8[BP] ; Fetch ret address,(points to after instruction)
+ DEC SI ; Make SI point to instruction
+ DEC SI
+ MOV 8[BP],SI ; Change ret address to return to instruction
+ SUB [SI],ax ; Remove Fixup to convert to 8087 instruction
+ push bx
+ xor bx,bx ; bx = 0 for no segment override
+
+; For the 286 change FWAITs on numeric instructions to NOPs
+;
+; ds:si = FWAIT address
+; ds:(si+bx+1) = 8087/287 instruction
+
+pub fixupdone
+ push sp ; check for 286
+ pop ax
+ cmp ax,sp
+ jne fixupxit ; not 286
+
+ mov ax,[bx+si+1] ; get instruction
+ and ax,030FBh ; mask for FSTCW/FSTSW/FSTENV/FSAVE
+ cmp ax,030D9h ; underlying bits
+ jne fixcheck2 ; not one of the above
+ mov al,[bx+si+2] ; get 2nd byte of instruction again
+ cmp al,0F0h ; check if kernel functions
+ jb fixupxit ; no - exit
+
+pub fixcheck2
+ mov ax,[bx+si+1] ; get instruction
+ and ax,0FEFFh ; mask for FCLEX/FINIT
+ cmp ax,0E2DBh ; underlying bits
+ je fixupxit ; can't remove FWAIT
+
+ mov ax,[bx+si+1] ; get instruction
+ cmp ax,0E0DFh ; check for FSTSW AX
+ je fixupxit ; can't remove FWAIT
+
+ mov byte ptr [si],iNOP ; NOP the FWAIT
+
+pub fixupxit
+ pop bx
+ POP SI
+ POP DS
+ POP BP
+ pop ax
+ IRET
+
+
+endif ;DOS3
+
+ProfEnd FIXFLY
diff --git a/private/mvdm/wow16/win87em/emfmisc.asm b/private/mvdm/wow16/win87em/emfmisc.asm
new file mode 100644
index 000000000..ad5795440
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfmisc.asm
@@ -0,0 +1,101 @@
+ page ,132
+ subttl emfmisc.asm - Miscellaneous Operations
+;***
+;emfmisc.asm - Miscellaneous Operations
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Miscellaneous Operations: FABS, FCHS, DupTOS, FSCALE, FXCHG
+;
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin FMISC
+
+
+pub eFABS
+ MOV esi,[CURstk] ; point to TOS
+ AND byte ptr Flag[esi],0FFH - Sign ; mask off sign
+ RET
+
+pub eFCHS
+ MOV esi,[CURstk] ; point to TOS
+ XOR byte ptr Flag[esi],Sign ; toggle the sign
+ RET
+
+
+; FLDCW and FSTCW should only be used in a nested fashion
+; and should never change the denormal and invalid masks (in real 8087)
+;
+; FSTCW old
+; FLDCW new ; new and old have same denormal/invalid masks
+; ...
+; FLDCW old
+
+pub eFLDCW
+ LDUS2AX ; Fetch control word from user memory
+ MOV [ControlWord],AX ; Store in the emulated control word
+ MOV [UserControlWord],AX ; Store in the user control word
+ RET
+
+pub eFSTCW
+ MOV AX,[UserControlWord] ; Fetch user control word
+ MOV edi,esi
+ STAX2US ; Store into user memory
+ RET
+
+pub eFSTSW
+ MOV AX,[StatusWord] ; Fetch emulated Status word
+ MOV edi,esi
+ STAX2US ; Store into user memory
+ RET
+
+pub eFSCALE ; NOS is treated as short integer and TOS gets
+ MOV esi,[CURstk] ; its exponent bumped by that amount
+ MOV edi,esi
+ ChangeDIfromTOStoNOS
+ MOV CL,15
+ MOV AL,Expon[edi] ; Assume word integer
+ AND AL,0FH ; Assume exp is positive and in range
+ SUB CL,AL ; Generate shift count for mantissa
+ MOV AX,MB6[edi] ; MSW will contain the whole integer
+ SHR AX,CL ; AX is now the integer
+ MOV CL,Flag[edi] ; Get the sign for the integer
+ OR CL,CL
+ JNS short GotExponInc
+ NEG AX
+
+pub GotExponInc
+ ADD AX,Expon[esi]
+ JO short ExpOverflowed
+ CMP AX,IexpMax - IexpBias
+ JGE short ScaledToInfinity
+ CMP AX,IexpMin - IexpBias
+ JLE short ScaledToZero
+
+pub ScaleReturn
+ MOV Expon[esi],AX
+ RET
+
+pub ExpOverflowed
+ JNS short ScaledToZero
+
+pub ScaledToInfinity
+ MOV AX,IexpMax - IexpBias
+ MOV byte ptr Tag[esi],Special + ZROorINF
+ JMP short ScaleReturn
+
+pub ScaledToZero
+ MOV AX,IexpMin - IexpBias
+ MOV byte ptr Tag[esi],ZROorINF
+ JMP short ScaleReturn
+
+ProfEnd FMISC
diff --git a/private/mvdm/wow16/win87em/emfmul.asm b/private/mvdm/wow16/win87em/emfmul.asm
new file mode 100644
index 000000000..11711668c
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfmul.asm
@@ -0,0 +1,195 @@
+ page ,132
+ subttl emfmul.asm - Multiplication
+;***
+;emfmisc.asm - Multiplication
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Multiplication
+;
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;-----------------------------------------;
+; ;
+; Multiplication ;
+; ;
+;-----------------------------------------;
+
+; Perform multiply by summing partial products of 16x16 hardware multiply.
+; Before each multiply, the operands are checked for zero to see if it can be
+; skipped, since it's a slow operation on the 8086. The sum is kept in
+; registers as much as possible. Any insignificant bits lost are ORed together
+; and kept in a word on the top of the stack. This can be used for sticky bit
+; rounding. First we will need some macros.
+
+ProfBegin FMUL
+
+
+MULP MACRO SIOFFSET,DIOFFSET,NEXTLOC
+ ;Will multiply the words found at the given offsets if those words
+ ;are non-0. since we assume the numbers are normalized and the
+ ;most significant word has offset 6 we know that words with offset
+ ;6 are non-0 hence the conditional code in this macro.
+
+ MOV AX,SIOFFSET[esi]
+
+ IF SIOFFSET - 6 ;When SI offset is 6 it is most sig word hence not 0
+ OR AX,AX
+ JZ short NEXTLOC
+ ENDIF
+
+ IF DIOFFSET - 6
+ MOV DX,DIOFFSET[edi]
+ OR DX,DX
+ JZ short NEXTLOC
+ MUL DX
+ ELSE
+ MUL WORD PTR DIOFFSET[edi]
+ ENDIF
+
+ENDM
+
+ADDP MACRO HI,MID,LO
+ ;Will add the double word result of a multiply to the triple word
+ ; at HI:MID:LO using HI to record overflow
+
+ ADD LO,AX
+ ADC MID,DX
+ ADC HI,0
+ENDM
+
+STICKY MACRO R
+ ;R is the register containing the least significant word which
+ ;should be ORed to the sticky bit (kept on the stack) and then
+ ;cleared so the register can be reused
+
+ POP eax
+ OR AX,R
+ PUSH eax
+ XOR R,R
+ENDM
+
+page
+
+
+RMBRQQ: ; Routine MUL Both must see if we have two singles.
+
+if fastSP
+ MOV BX,DX
+ XOR BX,Single + 256*Single
+ TEST BX,Single + 256*Single
+ JNZ RMDRQQ
+ MOV BX,OFFSET TMSRQQ
+ JMP [BX]
+endif ;fastSP
+
+
+pub RMDRQQ ;RoutineMulDouble SI & DI point to valid non-0 reals
+ ; AX CX are the exponents
+ ; DL DH are the signs
+if fastSP
+ CALL CoerceToDouble ; insure that both args are double
+endif ;fastSP
+
+ PUSH ebp ; Must save BP
+ MOV BH,DH ; Save Single double flag
+ XOR DH,DL ; Get sign onto stack
+ PUSH edx
+ ADD AX,CX ; New exponent is sum of old plus 1
+ INC AX ; because of the normalize step
+ PUSH eax ; Save it while we Multiply
+ AND BH,DL
+
+pub PROD1
+ XOR BX,BX
+ MOV BP,BX
+ MOV CX,BX
+ MULP 0,0,PROD2
+ MOV BP,AX ; Save insignificant bits
+ MOV CX,DX
+pub PROD2
+ PUSH ebp ; Save Sticky bit on stack
+ xor ebp, ebp ; bp is now the working high word of bp:bx:cx
+ MULP 0,2,PROD3
+ ADDP BP,BX,CX
+pub PROD3
+ MULP 2,0,PROD4
+ ADDP BP,BX,CX
+
+pub PROD4
+ STICKY CX
+ MULP 0,4,PROD5
+ ADDP CX,BP,BX
+pub PROD5
+ MULP 2,2,PROD6
+ ADDP CX,BP,BX
+pub PROD6
+ MULP 4,0,PROD7
+ ADDP CX,BP,BX
+
+pub PROD7
+ STICKY BX
+ MULP 0,6,PROD8
+ ADDP BX,CX,BP
+pub PROD8
+ MULP 2,4,PROD9
+ ADDP BX,CX,BP
+pub PROD9
+ MULP 4,2,PROD10
+ ADDP BX,CX,BP
+pub PROD10
+ MULP 6,0,PROD11
+ ADDP BX,CX,BP
+
+pub PROD11
+ MOV DX,BP ; Everything but guard and round go to sticky
+ AND BP,03FFFH
+ STICKY BP
+ PUSH edx ; Save guard and round on stack
+ MULP 2,6,PROD12
+ ADDP BP,BX,CX
+pub PROD12
+ MULP 4,4,PROD13
+ ADDP BP,BX,CX
+pub PROD13
+ MULP 6,2,PROD14
+ ADDP BP,BX,CX
+
+pub PROD14
+ PUSH ecx ; Save LSW on stack (not enough registers)
+ XOR CX,CX
+ MULP 4,6,PROD15
+ ADDP CX,BP,BX
+pub PROD15
+ MULP 6,4,PROD16
+ ADDP CX,BP,BX
+
+pub PROD16
+ MULP 6,6,PROD17
+ ADD AX,BP
+ ADC DX,CX
+ POP ecx
+ POP ebp ; Result in DX:AX:BX:CX:BP Sticky on stack
+
+ MOV DI,DX
+ MOV DX,CX
+ MOV CX,BX
+ MOV BX,AX ; Result in DI:BX:CX:DX:BP
+ POP eax ; Merge Sticky bit into BP
+ OR AX,AX
+ JZ short STBITOK
+ OR BP,1
+pub STBITOK
+ POP esi ; Exponent in SI, Sign on Stack, Old BP on Stack
+ JMP NORMSHF ; Result must be normalized at most 1 bit
+
+ProfEnd FMUL
diff --git a/private/mvdm/wow16/win87em/emfprem.asm b/private/mvdm/wow16/win87em/emfprem.asm
new file mode 100644
index 000000000..69f484045
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfprem.asm
@@ -0,0 +1,386 @@
+ page ,132
+ subttl emfprem.asm - fprem
+;***
+;emfprem.asm - FPREM emulation
+;
+; Copyright (c) 1987, Microsoft Corporation
+;
+;Purpose:
+; To emulate the 8087/80287 FPREM instruction.
+;
+;Revision History:
+; 08-12-86 JMB Initial version
+;
+; 09-23-86 JMB Changed from unsigned (jnc) to signed branch
+; (jge) on lc < 0 comparison
+;
+; 10-24-86 BCM Fixed a problem with large quotients that
+; caused a signed comparison (cmp bp,2) to
+; behave in an undesired manner when bp (quotient)
+; becomes larger than 32767; we now use bigquot
+; to indicate a quotients overflowing an unsigned word
+; Also, the quotient is now enregistered in bp
+; through most of the FPREM algorithm.
+;
+; 11-14-86 BCM Fixed a problem with the 4-word comparison of
+; numerator and denominator mantissas by substituting
+; unsigned-compare jumps (JB and JA) for signed-compare
+; jumps (JL and JG).
+;
+; Also see emulator.hst
+;
+;*******************************************************************************
+
+; The following is a working C program which was used to simulate
+; floating point numbers and to test the algorithm used in the
+; fprem emulation.
+
+;#include <math.h>
+;#include <stdio.h>
+;
+;typedef struct floating {
+; unsigned long man;
+; unsigned int expo;
+; } FLOAT_NUM;
+;
+;double fprem(double,double,unsigned int *);
+;
+;#define normalize(n) while (n&0x8000==0) { \
+; if (lc == 0) \
+; return(ldexp((double)(num.man)/65536,den.expo)); \
+; n <<= 1; \
+; lc--; \
+; *pq <<=1; \
+; }
+;
+;
+;main() {
+; unsigned int qv,qt;
+; double n,d,rv,rt;
+; FILE *fpinp;
+;
+; fpinp = fopen("fprem.dat","r");
+; if (fpinp) {
+; while (fscanf(fpinp,"%E %E",&n,&d) != EOF) {
+; qv=(unsigned int)(n/d);
+; rv=n-(d*qv);
+; printf(" \nnumerator is %f\n denominator is %f",n,d);
+; printf(" \nquotient is %x\n remainder is %f",qv,rv);
+; rt = fprem(n,d,&qt);
+; printf(" \nquotient is %x\n remainder is %f\n\n",qt,rt);
+; }
+; fclose(fpinp);
+; }
+; else
+; printf(" \nerror opening fprem.dat");
+; }
+;
+;double fprem(n,d,pq)
+; double n,d;
+; unsigned int *pq; {
+; int lc;
+; FLOAT_NUM num;
+; FLOAT_NUM den;
+;
+; num.man = (unsigned long)(65536*frexp(n,&num.expo));
+; den.man = (unsigned long)(65536*frexp(d,&den.expo));
+;
+; printf(" \nnumerator mantissa: %lx",num.man);
+; printf(" \nnumerator exponent: %x",num.expo);
+; printf(" \ndenominator mantissa: %lx",den.man);
+; printf(" \ndenominator exponent: %x",den.expo);
+;
+; *pq=0;
+; lc = num.expo - den.expo;
+; if (lc < 0) { /* then the numerator is the remainder */
+; return(ldexp((double)(num.man)/65536,num.expo));
+; }
+; while(1) {
+; if (den.man <= num.man) { /* do subtraction */
+; num.man -= den.man;
+; (*pq)++;
+; if (lc == 0) {
+; /* normalize(num.man) */
+; return(ldexp((double)(num.man)/65536,den.expo));
+; }
+; normalize(num.man)
+; }
+; else { /* don't do the subtraction */
+; if (lc == 0) {
+; /* normalize(num.man) */
+; return(ldexp((double)(num.man)/65536,den.expo));
+; }
+;
+; num.man <<= 1;
+; lc--;
+; (*pq) <<= 1;
+;
+; num.man -= den.man;
+; (*pq)++;
+;
+; normalize(num.man)
+; }
+; }
+; }
+
+;***
+;eFPREM - entry point for FPREM emulation
+;Purpose:
+;
+;Entry:
+;
+;Exit:
+;
+;Uses:
+;
+;Exceptions:
+;*******************************************************************************
+
+ProfBegin FPREM
+
+
+pub eFPREM
+
+; NOTE: The C program excerpts interspersed below are from the C program
+; shown in its entirety above.
+;
+; The correspondence between the C variables and the assembly
+; language version is as follows:
+;
+; C version masm version
+; *pq bp (quotient)
+; lc loopct
+; num.expo Expon[di]
+; den.expo Expon[si]
+; num.man MB0[di],MB2[di],MB4[di],MB6[di]
+; den.man MB0[si],MB2[si],MB4[si],MB6[si]
+
+; *pq=0;
+; lc = num.expo - den.expo;
+
+ push ebp ;save bp; use bp as quotient
+
+ mov edi,[CURSTK] ;point to ST(0), the numerator
+ mov [RESULT],edi ;ST(0) is result (remainder)
+ xor bp,bp ;begin with quotient = 0
+ mov bigquot,0 ;quotient not > 65535 yet
+ mov esi,edi ;si points to ST(0)
+ sub esi,Reg87Len ;si points to ST(1), the denominator
+
+ mov ax,word ptr Expon[edi] ;ax <== numerator exponent
+ sub ax,word ptr Expon[esi] ;loopct = (num exponent - den exponent)
+
+ mov loopct,ax
+
+ mov dx,MB0[edi] ;move the mantissa of the
+ mov cx,MB2[edi] ;numerator into
+ mov bx,MB4[edi] ;ax:bx:cx:dx
+ mov ax,MB6[edi]
+
+; if (lc < 0) { /* then the numerator is the remainder */
+; return(ldexp((double)(num.man)/65536,num.expo));
+; }
+ jge short fpremLoop
+ mov si,Expon[edi]
+ jmp DoneEarly
+
+; while(1) {
+fpremLoop:
+
+; if (den.man <= num.man) { /* do subtraction */
+ cmp ax,MB6[esi] ;compare msw of num to msw of den
+ jb short NumLess ;numerator is less
+ ja short NumMore ;numerator is more
+ cmp bx,MB4[esi] ;compare word 2 of num to word 2 of den
+ jb short NumLess ;numerator is less
+ ja short NumMore ;numerator is more
+ cmp cx,MB2[esi] ;compare word 4 of num to word 4 of den
+ jb short NumLess ;numerator is less
+ ja short NumMore ;numerator is more
+ cmp dx,MB0[esi] ;compare lsw of num to lsw of den
+ jb short NumLess ;numerator is less
+
+; num.man -= den.man;
+; (*pq)++;
+; if (lc == 0) {
+; /* normalize(num.man) */
+; return(ldexp((double)(num.man)/65536,den.expo));
+; }
+
+NumMore:
+ call SubInc ;do subtraction, increment quotient
+ cmp loopct,0 ;is expon diff zero?
+ je short Done ;yes, then we're done
+
+; normalize(num.man)
+; }
+
+ call fpremNorm ;normalize the numerator
+ jnz fpremLoop ;do the next iteration
+ jmp short Done ;loop counter is zero; we're done
+
+; else { /* don't do the subtraction */
+; if (lc == 0) {
+; /* normalize(num.man) */
+; return(ldexp((double)(num.man)/65536,den.expo));
+; }
+NumLess:
+ cmp loopct,0 ;is expon diff zero?
+ je short Done ;yes, then all done
+
+;
+; num.man <<= 1;
+; lc--;
+; (*pq) <<= 1;
+ call ShiftDec ;shift quotient, numerator
+
+;
+; num.man -= den.man;
+; (*pq)++;
+ call SubInc ;do subtraction, increment quotient
+;
+; normalize(num.man)
+; }
+ call fpremNorm ;normalize for next iteration
+ jnz fpremLoop ;do next iteration
+ jmp short Done ;loop counter is zero; we're done
+
+; remainder: ax:bx:cx:dx is mantissa; Expon[si] is the exponent
+Done:
+
+;NOTE: the rounding routine wants the mantissa in di:bx:cx:dx:bp
+; the exponent in SI the sign and the old BP on the stack
+ mov si,Expon[esi] ; mov exponent to si
+
+DoneEarly:
+ mov di,Flag[edi] ; move sign of remainder to di
+ xchg di,ax ; di becomes high mantissa word
+ mov ah,al ; move sign to ah
+ push ax ; put sign on stack
+
+; Except for bp which gets zeroed out later,
+; everything is now set up the way it needs to be for the normalization
+; routine, NODRQQ. Before we go there we need to set up the status
+; word as it should be set by fprem. For simplicity we did a complete
+; reduction of the dividend in one pass, so we will always clear C2
+; to indicate that the reduction is complete.
+
+ mov ax,bp ; move quotient into ax
+ and bp,0FFFCh ; check if quotient mod 64K < 4
+ or bp,bigquot ; and quotient < 64K
+
+; bp is zero if and only if quotient < 4
+; (bp no longer holds the quotient itself)
+; al has low byte of quotient
+; ah will be for C0-C3 flags
+
+ mov ah,SWcc ; move status word to ah
+ and ah,not C2 ; clear C2 to indicate complete
+ test al,01h ; is low bit of quotient set?
+ jnz short SetC1 ; yes, go set C1
+ and ah,not C1 ; low bit off, turn off C1
+ jmp short DoC3 ; do the C3 bit
+SetC1:
+ or ah,C1 ; low bit on, turn on C1
+
+DoC3:
+ test al,02h ; is bit 1 of quotient set?
+ jnz short SetC3 ; yes, go set C3
+ or bp,bp ; is quotient less than 4?
+ jz short QuotL2 ; then quotient < 2 (bit 1 off)
+ ; so don't set c0 or c3 from quotient
+ ; else if quotient >= 4
+ and ah,not C3 ; bit 1 is off, so turn off C3
+ jmp short DoC0 ; do the C0 bit
+SetC3:
+ or ah,C3 ; bit 1 on, turn on C3
+
+DoC0:
+ test al,04h ; is bit 2 of quotient set?
+ jnz short SetC0 ; yes, go set C0
+ or bp,bp ; is quotient less than 4?
+ jz short QuotL4 ; yes, don't set c0 from quotient
+ ; else if quotient >= 4
+ and ah,not C0 ; bit 2 off, turn off C0
+ jmp short GoNormal ; we're done, go normalize
+
+SetC0:
+ or ah,C0 ; bit 1 on, turn on C0
+GoNormal:
+ mov SWcc,ah ; set new status word
+ xor bp,bp ; clear low mantissa word
+ jmp NODRQQ ; go normalize
+ ; (does pop ax, pop bp)
+
+; special case code if quotient is less than 2
+
+QuotL2:
+ mov al,SWcc ; get old status word
+ test al,C1 ; was C1 set
+ jnz short SetC3toC1 ; yes, set C3
+ and ah,not C3 ; clear C3
+ jmp short QuotL4
+
+SetC3toC1:
+ or ah,C3 ; set C3
+
+; special case code if quotient is less than 4
+
+QuotL4:
+ mov al,SWcc ; get old status word
+ test al,C3 ; was C3 set
+ jnz short SetC0toC3 ; yes, set C0
+ and ah,not C0 ; clear C0
+ jmp short GoNormal ; go normalize the result
+
+SetC0toC3:
+ or ah,C0 ; set C0
+ jmp short GoNormal ; go normalize the result
+
+;#define normalize(n) while (n&0x8000==0) { \
+; if (lc == 0) \
+; return(ldexp((double)(num.man)/65536,den.expo)); \
+; n <<= 1; \
+; lc--; \
+; *pq <<=1; \
+; }
+
+;Inputs: ah contains high byte of numerator mantissa
+;Outputs: zero flag set indicates the loop counter is zero so we're finished
+; zero flag clear indicates the number was already normalized
+fpremNorm:
+ test ah,80h ;is the numerator normalized?
+ jnz short fpremIsNorm ;yes
+ ;no, normalize it
+ cmp loopct,0 ;is expon diff zero?
+ je short fpremIsNorm ;yes, then we're done
+ call ShiftDec ;shift num, quotient
+ ;decrement loop ctr
+ jmp short fpremNorm
+
+fpremIsNorm:
+ ret
+
+ShiftDec:
+ shl dx,1 ;numerator*2
+ rcl cx,1
+ rcl bx,1
+ rcl ax,1
+ dec loopct ;reduce exponent diff by one
+ shl bp,1 ;quotient*2
+ jc short QuotLarge ;carry out on quotient shift
+ ret
+QuotLarge:
+ mov bigquot,1 ;indicate large quotient > 65535
+ ret
+
+SubInc:
+ sub dx,MB0[esi] ;subtract lsw of den from lsw of num
+ sbb cx,MB2[esi] ;subtract next word of den from num
+ sbb bx,MB4[esi] ;subtract next word of den from num
+ sbb ax,MB6[esi] ;subtract msw of den from msw of num
+ inc bp ;add one to quotient
+ ret
+
+
+ProfEnd FPREM
diff --git a/private/mvdm/wow16/win87em/emfrndi.asm b/private/mvdm/wow16/win87em/emfrndi.asm
new file mode 100644
index 000000000..2766ed8f4
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfrndi.asm
@@ -0,0 +1,224 @@
+ page ,132
+ subttl emfrndi.asm - Round to INT
+;***
+;emfrndi.asm - Round to INT
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Round to INT
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Round TOS to Integer ;
+; ;
+;*********************************************************************;
+
+ProfBegin FRNDI
+
+
+pub eFRNDINT
+ MOV esi,[CURstk] ; Point to TOS
+ MOV CX,Expon[esi] ; Get exponent
+ CMP CX,63 ; See if we have very large integer
+ JGE short DONERNDINT
+
+if fastSP
+ MOV BX,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ TEST byte ptr Flag[esi],Single
+ JZ RNDD
+ XOR BL,BL
+ MOV BP,BX
+ XOR BX,BX
+ MOV DX,BX
+RND:
+else
+ MOV BP,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+endif
+ CALL InternalToInteger
+
+ XOR AX,AX ; Test for zero
+ OR AX,DI
+ OR AX,BP
+ OR AX,BX
+ OR AX,DX
+ JZ short RoundIntToZero
+
+ MOV AX,63 ; What expon should be if no shifting
+
+ CALL IntegerToInternal
+
+pub DONERNDINT
+ RET
+
+if fastSP
+RNDD:
+ MOV BP,BX
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+ JMP RND
+endif
+
+pub RoundIntToZero
+ MOV Expon[esi],IexpMin - IexpBias
+ MOV MB0[esi],AX
+ MOV MB2[esi],AX
+ MOV MB4[esi],AX
+ MOV MB6[esi],AX
+ MOV byte ptr Tag[esi],ZROorINF
+ JMP DONERNDINT
+PAGE
+pub IntegerToInternal
+ ; On entry DI:BP:BX:DX is the integer (unsigned i.e. no longer in 2's
+ ; compliment) DS:SI points to TOS (the ultimate destination).
+ ; AX contains the Exponent (assuming that the number will require
+ ; no shifting. the routine will adjust it as it goes along)
+ ; On exit the mantissa and exponent will be put in TOS.
+ ; This routine is used to Load int16 and int32 also to round-to-int
+
+ XOR ecx,ecx
+
+pub SHIFTLEFT
+ SHL DX,1 ; Left justify number
+ RCL BX,1
+ RCL BP,1
+ RCL DI,1
+ JC short DONESHIFT
+ LOOP SHIFTLEFT ; CX will count number of shifts done
+
+pub DONESHIFT
+ RCR DI,1 ; We went one too far so reset
+ RCR BP,1
+ RCR BX,1
+ RCR DX,1
+
+ ADD AX,CX ; Adjust exponent
+ MOV Expon[esi],AX ; Store exponent
+ MOV MB0[esi],DX ; Store mantissa
+ MOV MB2[esi],BX
+ MOV MB4[esi],BP
+ MOV MB6[esi],DI
+ RET
+PAGE
+pub InternalToInteger
+ ; On entry DI:BP:BX:DX is the mantissa, CX is the Exponent, and
+ ; DS:SI points to TOS where the number came from. On exit
+ ; DI:BP:BX:DX is an integer (unsigned i.e. needs to be jiggled to
+ ; 2's compliment based upon the sign in TOS) rounded according to
+ ; Round control. This routine used to Store int16 and int32 also
+ ; by round-to-integer
+
+ifdef i386
+ movsx ecx,cx ; (ecx) = sign-extended cx
+endif
+ XOR AX,AX ; Clear Stickybit (AL) and roundbit (AH)
+ SUB ecx,63 ; Convert exponent to shift count
+ NEG ecx ; Shift will be done in 2 parts, 1st to get
+ DEC ecx ; sticky then 1 more to get round
+ifdef i386
+ JGE short NOTRUNCATE; Shift count Neg means num was large int.
+ JMP TRUNCATE
+NOTRUNCATE:
+ JE short GETROUND ; Zero shift means no sticky bit, only round
+else
+ JL short TRUNCATE ; Shift count Neg means num was large int.
+ JE short GETROUND ; Zero shift means no sticky bit, only round
+endif
+ CMP ecx,64 ; If big shift count then number is all sticky
+ JGE short STICKYNOROUND
+
+ cmp ecx,48 ; fast out for 16-bit ints
+ jle SHIFTRIGHT ; no
+
+ or dx,bx
+ or dx,bp ; dx = low 48 bits
+ jz nostick48 ; if 0 then no sticky bits
+ or al,1 ; set sticky bit
+nostick48:
+ mov dx,di ; move upper 16 to lower 16
+ xor di,di ; zero upper 48 bits
+ mov bp,di
+ mov bx,di
+ sub ecx,48 ; just like looping 48 times
+
+pub SHIFTRIGHT
+ SHR DI,1 ; Shift into sticky bit (lsb of AL)
+ RCR BP,1
+ RCR BX,1
+ RCR DX,1
+ JNC short LOOPEND
+ RCL AL,1
+
+pub LOOPEND
+ LOOP SHIFTRIGHT
+
+pub GETROUND
+ SHR DI,1 ; Shift into round
+ RCR BP,1
+ RCR BX,1
+ RCR DX,1
+ RCL AH,1 ; Shift round into lsb of AH
+
+pub GOTROUNDANDSTICKY
+ OR AX,AX ; Was number exact?
+ JZ short TRUNCATE
+ OR [CURerr],Precision
+ TEST [CWcntl],RCdown ; True if down or chop
+ JNZ short INTDNorCHP
+ TEST [CWcntl],RCup ; True if UP (or CHOP)
+ JNZ short INTUP
+
+pub INTNEAR
+ OR AL,DL ; In near mode inc if (sticky or lastbit) and Roundbit
+ AND AH,AL
+ SHR AH,1
+ JNC short TRUNCATE
+
+pub INCREMENT
+ XOR AX,AX
+ ADD DX,1
+ ADC BX,AX
+ ADC BP,AX
+ ADC DI,AX
+
+INTCHOP:
+pub TRUNCATE
+ RET
+
+pub STICKYNOROUND
+ MOV AL,1
+ XOR AH,AH
+ XOR DI,DI
+ MOV BP,DI
+ MOV BX,DI
+ MOV DX,DI
+ JMP GOTROUNDANDSTICKY
+
+pub INTDNorCHP
+ TEST [CWcntl],RCup ; True if UP or CHOP
+ JNZ INTCHOP
+
+pub INTDOWN
+ TEST byte ptr Flag[esi],Sign ; Truncate if round down and +
+ JNZ INCREMENT
+ JMP TRUNCATE
+
+pub INTUP
+ TEST byte ptr Flag[esi],Sign ; Truncate if round up and -
+ JNZ TRUNCATE
+ JMP INCREMENT
+
+ProfEnd FRNDI
diff --git a/private/mvdm/wow16/win87em/emfsqrt.asm b/private/mvdm/wow16/win87em/emfsqrt.asm
new file mode 100644
index 000000000..754132172
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emfsqrt.asm
@@ -0,0 +1,178 @@
+ page ,132
+ subttl emfsqrt.asm - Square root
+;***
+;emfsqrt.asm - Square root
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Square root
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;-----------------------------------------;
+; ;
+; Square root ;
+; ;
+;-----------------------------------------;
+
+ProfBegin FSQRT
+
+
+pub eFSQRT
+ MOV esi,[CURstk]
+ CALL $FSQRT
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator square root !
+; !
+;---------------------------------------------------
+
+; With 0<=x={TOS=[SI]}<infinity, $FSQRT performs {TOS=[SI]} <--
+; {TOS=[SI]}^.5. All registers except SI are destroyed. Roots
+; of negative numbers, infinities, and NAN's result in errors. The
+; square root of -0 is -0. Algorithm: x is initially adjusted
+; so that the exponent is even (when the exponent is odd the exponent
+; is incremented and the mantissa is shifted right one bit). The
+; exponent is then divided by two and resaved. A single word
+; estimate of y (the root of x) accurate to 5 bits is produced using
+; a wordlength implementation of a linear polynomial approximation
+; of sqrt x. Four Newton-Raphson iterations are then computed as
+; follows:
+;
+; 1) qa*ya+r1a=xa:0h,ya=(ya+qa)/2
+; 2) qa*ya+r1a=xa:xb,ya=(ya+qa)/2
+; 3) qa*ya+r1a=xa:xb,qb*ya+r2a=r1a:xc,ya:yb=(ya:yb+qa:qb)/2
+; *** iteration 4 implemented with standard divide ***
+; 4) qa*ya+r1a=xa:xb,p1a:p1b=qa*yb,
+; if p1a<r1a continue
+; if p1a=r1a
+; if p1b=xc continue else r1a=r1a+ya,qa=qa-1 endif,
+; else r1a=r1a+ya,qa=qa-1,p1a:p1b=p1a:p1b-yb endif,
+; r1a:r1b=r1a:xc-p1a:p1b,
+; qb:ya+r2a=r1a:r1b,p2a:p2b=qb*yb,
+; if p2a<r2a continue
+; if p2a=r2a
+; if p2b=xd continue else r2a=r2a+ya,qb=qb-1 endif,
+; else r2a=r2a+ya,qb=qb-1,p2a:p2b=p2a:p2b-yb endif,
+; r2a:r2b=r2a:xd-p2a:p2b,
+; qc*ya+r3a=r2a:r2b,p3a:p3b=qc*yb,
+; if p3a>=r3a then r3a=r3a+ya,qc=qc-1 endif,
+; r3a=r3a-p3a,qd*ya+r4a=r3a:0h,
+; ya:yb:yc:yd=(ya:yb:0h:0h+qa:qb:qc:qd)/2
+
+pub SQRTSPECIAL
+ RCR AH,1 ;if NAN
+ JNC short SETFLAG ; set invalid flag and return
+ RCL AL,1 ;if -infinity
+ JC short SQRTERROR ; return real indefinite
+ MOV AL,[CWcntl] ;get Infinity control
+ TEST AL,ICaffine ;if affine closure
+ JNZ short SQRTDONE ; return +infinity
+ JMP SHORT SQRTERROR ;else return real indefinite
+
+pub NOTPOSVALID
+ TEST AH,2 ;if special
+ JNZ SQRTSPECIAL ; process special
+ RCR AH,1 ;if zero
+ JC SHORT SQRTDONE ; return argument
+ ;otherwise -ve, return NAN
+
+pub SQRTERROR
+ MOV edi,esi
+ MOV esi,offset IEEEindefinite
+ CALL csMOVRQQ
+ MOV esi,edi ;return indefinite
+
+pub SETFLAG
+ OR [CURerr],Invalid+SquareRootNeg ;Set flag indicating invalid
+
+pub SQRTDONE
+ RET
+
+pub $FSQRT
+ MOV AX,[esi+Flag] ;get flags
+ TEST AX,00380H ;if Sign, Invalid or Zero
+ JNZ NOTPOSVALID ; perform special processing
+ PUSH esi ;save ptr to x
+ MOV edi,offset TEMP1 ;[DI]=y=temp
+ MOV word ptr [edi+Flag],0 ;clear flags in y
+ MOV AX,[esi+Expon] ;get exponent of x
+ DEC AX ;adjust for shift divide by 2
+ MOV BX,[esi+6]
+ MOV CX,[esi+4]
+ MOV DX,[esi+2] ;get first three mantissa words of x
+ TEST AL,1 ;if exponent is even
+ JZ short EXPEVEN ; bypass adjust
+ INC AX ;increment exponent
+ SHR BX,1
+ RCR CX,1
+ RCR DX,1 ;divide mantissa by 2
+
+pub EXPEVEN
+ SAR AX,1 ;divide exponent by 2
+ MOV [edi+Expon],AX ;store exponent of y
+ CMP BX,0FFFEH ;if mantissa < 0.FFFEh
+ JB short NOTNEARONE1 ; perform main root routine
+ STC ;otherwise x to become (1+x)/2
+ JMP SHORT SINGLEDONE ;single precision complete
+
+pub NOTNEARONE1
+ PUSH edx ;save third mantissa word
+ MOV AX,0B075H ;AX=.B075h
+ MUL BX ;DX=.B075h*x
+ MOV BP,057D8H ;BP=.57D8h
+ ADD BP,DX ;BP=.B075h*x+.57D8h
+ JNC short NORMEST ;if y is more than one
+ MOV BP,0FFFFH ; replace y with .FFFFh
+
+pub NORMEST
+ MOV DX,BX
+ XOR AX,AX ;load divide regs with xa:0h
+ DIV BP ;qa*ya+r1a=xa:0h
+ ADD BP,AX ;ya=ya+qa
+ RCR BP,1 ;ya=ya/2
+ MOV DX,BX
+ MOV AX,CX ;load divide regs with xa:xb
+ DIV BP ;qa*ya+r1a=xa:xb
+ STC ;add one to qa for better rounding
+ ADC BP,AX ;ya=ya+qa
+ RCR BP,1 ;ya=ya/2
+ MOV DX,BX
+ MOV AX,CX ;load divide regs with xa:xb
+ DIV BP ;qa*ya+r1a=xa:xb
+ MOV SI,AX ;save qa
+ POP eax ;load divide regs with r1a:xc
+ DIV BP ;qb*ya+r2a=r1a:xc
+ MOV BX,BP
+ MOV CX,AX ;move qa:qb
+ ADD CX,1 ;add one to qa:qb for better rounding
+ ADC BX,SI ;ya:yb=ya:0h+qa:qb
+
+pub SINGLEDONE
+ RCR BX,1
+ RCR CX,1 ;ya:yb=(ya:0h+qa:qb)/2
+ MOV word ptr [edi+6],BX
+ MOV word ptr [edi+4],CX
+ MOV word ptr [edi+2],0
+ MOV word ptr [edi],0 ;save ya:yb:0h:0h
+ MOV esi,edi ;[SI]=y
+ POP edi ;[DI]=x
+ MOV [RESULT],edi ;result=[DI]
+ CALL DIDRQQ ;[DI]=x/y
+ MOV esi,offset TEMP1 ;[SI]=y
+ CALL ADDRQQ ;[DI]=y+x/y
+ DEC word ptr [edi+Expon] ;[DI]=(y+x/y)/2=TOS
+ MOV esi,edi ;[SI]=sqrt(x)
+ RET
+
+ProfEnd FSQRT
diff --git a/private/mvdm/wow16/win87em/emftran.asm b/private/mvdm/wow16/win87em/emftran.asm
new file mode 100644
index 000000000..6f21e5381
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emftran.asm
@@ -0,0 +1,469 @@
+ page ,132
+ subttl emftran.asm - Transcendentals
+;***
+;emftran.asm - Transcendentals
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Transcendentals
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;-----------------------------------------;
+; ;
+; Transcendentals ;
+; ;
+;-----------------------------------------;
+
+ProfBegin FTRAN
+
+
+pub MoveCodeSItoDataSI
+ PUSH edi
+ MOV edi,offset COEFFICIENT
+ifdef i386
+ rept Reg87Len/4
+ MOVS dword ptr es:[edi],dword ptr cs:[esi]
+ endm
+else
+ rept Reg87Len/2
+ MOVS word ptr es:[edi],word ptr cs:[esi]
+ endm
+endif
+ MOV esi,offset COEFFICIENT
+ POP edi
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator transcendental utilities !
+; !
+;---------------------------------------------------
+
+; COMPcsSIDI is analogous to the 8086 CMP instruction with operands
+; cs:[SI],[DI]. All registers except CX and DX are left unaltered.
+; Zero and negative zero are determined to be unequal. NAN's and
+; infinities may not be compared with this routine.
+;
+; FRAT2X performs {TOS=[DI]} <-- {TOS=[SI]}*PNUM({TOS=[SI]}^2),
+; and program created {temp=[SI]} <-- PDEN({TOS=[SI]}^2). On input,
+; [BX] must contain the degree of PNUM, the coefficients of PNUM
+; in descending order, the degree-1 of PDEN and the coefficients
+; of PDEN in descending order. PDEN is evaluated assuming an implied
+; highest coefficient of one. [BX] is left unaltered, ARG2 is loaded
+; with {TOS}^2, DENORX is used, all registers are destroyed with
+; DI returning the value input in SI.
+
+pub BOTHZERO
+ CMP CH,CH ;set flags to equal
+ JMP short COMPDONE ;compare finished
+
+pub COMPcsSIDI
+ MOV CX,CS
+ MOV DS,CX
+ MOV CX,[esi+Flag] ;get sign byte of [SI]
+ AND CL,Sign ;mask for sign
+ MOV DX,ES:[edi+Flag] ;get sign byte of [DI]
+ AND DL,Sign ;mask for sign
+ CMP DL,CL ;compare signs
+ JNE short SIGNDIFF
+ PUSH ES
+ PUSH esi
+ PUSH edi ;save pointers
+ OR CL,CL ;if signs are +
+ JNS short BOTHPOS ; don't exchange pointers
+ PUSH DS
+ PUSH ES
+ POP DS
+ POP ES
+ XCHG esi,edi ;exchange pointers
+ XCHG CX,DX ;exchange flags
+
+pub BOTHPOS
+ AND CH,ZROorINF ;mask for zero
+ AND DH,ZROorINF ;mask for zero
+ CMP DH,CH ;if exactly one zero
+ JNE short COMPDONE ; then finished
+ OR CH,CH ;if both zero
+ JA BOTHZERO ; then done after flags set
+ MOV CX,[esi+Expon] ;get exponent of [SI]
+ ADD CX,IexpBias ;make it unbiased
+ MOV DX,ES:[edi+Expon] ;get exponent of [DI]
+ ADD DX,IexpBias ;make it unbiased
+ CMP CX,DX
+ JNE short COMPDONE ;compare exponents
+ ADD esi,MB6
+ ADD edi,MB6
+ STD
+ CMPS word ptr [edi],word ptr [esi]
+ JNE short COMPDONE
+ CMPS word ptr [edi],word ptr [esi]
+ JNE short COMPDONE
+ CMPS word ptr [edi],word ptr [esi]
+ JNE short COMPDONE
+ CMPS word ptr [edi],word ptr [esi] ;compare mantissas
+
+pub COMPDONE
+ CLD
+ POP edi
+ POP esi
+ POP ES
+
+pub SIGNDIFF
+ MOV CX,ES
+ MOV DS,CX
+ RET
+
+pub FRAT2X
+ MOV edi,offset DENORX ;[DI]=temp
+ CALL MOVRQQ ;[DI]=x=temp
+ PUSH edi ;save ptr to x=temp
+ PUSH esi ;save ptr to TOS
+ PUSH ebx ;save ptr to polynomials
+ MOV edi,offset ARG2 ;get ptr to space for x^2
+ CALL MOVRQQ ;copy x to space for x^2
+ MOV [RESULT],edi ;result=[DI]
+ CALL MUDRQQ ;ARG2 gets x^2
+ POP esi ;get ptr to numerator poly
+ifdef i386
+ xor ecx,ecx
+endif
+ LODS word ptr CS:[esi]
+ XCHG CX,AX ;CX=denominator degree-1
+ POP edi ;[DI]=TOS
+ CALL csMOVRQQ ;[DI]=first coeff=TOS
+ MOV [RESULT],edi ;result=[DI]
+
+pub POLYLOOPA
+ PUSH ecx ;save no. of terms left
+ PUSH esi ;save ptr to next coeff
+ MOV esi,offset ARG2 ;get ptr to x^2
+ CALL MUDRQQ ;multiply TOS by x^2
+ POP esi ;get pointer to coeff
+ ADD esi,Reg87Len ;point to next coeff
+ PUSH esi ;save pointer to coeff
+ CALL MoveCodeSItoDataSI
+ CALL ADDRQQ ;add coeff to TOS
+ POP esi ;get ptr to coeff
+ POP ecx ;get no. of terms remaining
+ LOOP POLYLOOPA ;loop until no terms left
+
+ MOV ebx,esi ;move poly ptr
+ POP esi ;[SI]=x=temp
+ PUSH esi ;save ptr to x
+ PUSH ebx ;save poly ptr
+ CALL MUDRQQ ;multiply poly by x
+ POP esi ;get ptr to poly
+ ADD esi,12 ;[SI]=denominator degree-1
+ifdef i386
+ xor ecx,ecx
+endif
+ LODS word ptr CS:[esi]
+ XCHG CX,AX ;CX=denominator degree-1
+ POP ebx ;[BX]=temp
+ PUSH edi ;save denominator ptr
+ MOV edi,ebx ;[DI]=temp
+ CALL csMOVRQQ ;move second coeff to temp
+ PUSH ecx ;save poly degree-1
+ PUSH esi ;save ptr to denominator poly
+ MOV esi,offset ARG2 ;get ptr to x^2
+ MOV [RESULT],edi ;result=[DI]
+ CALL ADDRQQ ;add x^2 to temp
+ POP esi ;get ptr to second coeff
+ POP ecx ;get poly degree-1
+
+pub POLYLOOPB
+ PUSH ecx ;save no. of terms left
+ ADD esi,Reg87Len ;point to next coeff
+ PUSH esi ;save ptr to next coeff
+ MOV esi,offset ARG2 ;get ptr to x^2
+ CALL MUDRQQ ;multiply temp by x^2
+ POP esi ;get pointer to coeff
+ PUSH esi ;save pointer to coeff
+ CALL MoveCodeSItoDataSI
+ CALL ADDRQQ ;add coeff to temp
+ POP esi ;get ptr to coeff
+ POP ecx ;get no. of terms remaining
+ LOOP POLYLOOPB ;loop until no terms left
+
+ MOV esi,edi ;[SI]=denominator=temp
+ POP edi ;[DI]=numerator=TOS
+ RET
+;-------------------------------------------------------------------------------
+
+pub eFPTAN
+ MOV esi,[CURstk]
+ CALL $FPTAN
+ PUSH esi
+ PUSHST
+ MOV edi,[CURstk]
+ POP esi
+ CALL MOVRQQ
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator partial tangent !
+; !
+;---------------------------------------------------
+
+; When 0<=x={TOS=[SI]}<=pi/4 then $FPTAN performs {TOS=[DI]} <--
+; numerator tangent ({TOS=[SI]}), system created {temp=[SI]} <--
+; denominator tangent ({TOS=[SI]). Every register except DI is
+; destroyed.
+
+pub $FPTAN
+ MOV ebx,offset TANRAT ;[BX]=rational function
+ CALL FRAT2X ;[DI]=numerator=TOS,
+ RET ; [SI]=denominator=temp
+;-------------------------------------------------------------------------------
+
+pub eFPATAN
+ MOV edi,[CURstk]
+ MOV esi,edi
+ MOV AX,Flag[esi]
+ SUB edi,Reg87Len
+
+pub CALLFPATAN
+ CALL $FPATAN
+ MOV esi,[CURstk]
+ POPST
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator arctangent !
+; !
+;---------------------------------------------------
+
+; When 0<y={[DI]=NOS}<=x={[SI]=TOS}<infinity then $FPATAN performs
+; {NOS=[DI]} <-- arctangent({NOS=[DI]}/{TOS=[SI]}), TOS is left
+; unaltered. All registers except DI are destroyed.
+
+pub $FPATAN
+ MOV [RESULT],edi ;result=[DI]
+ CALL DIDRQQ ;NOS=[DI] <-- [DI]/[SI]=x
+ MOV AL,0 ;flag reset
+ MOV esi,offset TWOMRT3 ;[SI]=2-3^.5
+ CALL COMPcsSIDI ;if 2-3^.5 >= x
+ JNB short ATNREDUCED ; then bypass arg reduction
+ MOV esi,edi ;[SI]=x=NOS
+ MOV edi,offset TEMP1 ;[DI]=temp
+ CALL MOVRQQ ;[DI]=x=temp
+ PUSH esi ;save NOS
+ MOV esi,offset RT3 ;[SI]=3^.5
+ CALL MoveCodeSItoDataSI
+ MOV [RESULT],edi ;result=[DI]
+ CALL MUDRQQ ;[DI]=3^.5*x=temp
+ MOV esi,offset cFLD1 ;[SI]=1
+ CALL MoveCodeSItoDataSI
+ CALL SUDRQQ ;[DI]=3^.5*x-1
+ POP esi ;get NOS
+ PUSH edi ;save ptr to 3^.5*x-1
+ MOV edi,esi ;DI gets NOS
+ MOV esi,offset RT3 ;[SI]=3^.5
+ CALL MoveCodeSItoDataSI
+ MOV [RESULT],edi ;result=[DI]
+ CALL ADDRQQ ;[DI]=x+3^.5=NOS
+ POP esi ;[SI]=3^.5*x-1
+ CALL DRDRQQ ;[DI]=(3^.5*x-1)/(x+3^.5)=NOS
+ MOV AL,1 ;flag set
+
+pub ATNREDUCED
+ PUSH eax ;save flag
+ MOV esi,edi ;[SI]=reduced x=NOS
+ MOV ebx,offset ATNRAT ;[BX]=rational function
+ CALL FRAT2X ;[DI]=numerator=NOS,
+ ; [SI]=denominator=temp
+ MOV [RESULT],edi ;result=[DI]
+ CALL DIDRQQ ;[DI]=arctan(reduced x)=NOS
+ POP eax ;get flag
+ OR AL,AL ;if flag=0
+ JZ short ATNCOMPLETE ; bypass adjust
+ MOV esi,offset PIBY6 ;[SI]=pi/6
+ CALL MoveCodeSItoDataSI
+ CALL ADDRQQ ;[DI]=arctan(x)=NOS
+
+pub ATNCOMPLETE
+ RET
+;-------------------------------------------------------------------------------
+
+pub eF2XM1
+ MOV esi,[CURstk]
+ CALL $F2XM1
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator exponential !
+; !
+;---------------------------------------------------
+
+; When 0<=x={TOS=[SI]}<=.5 then $F2XM1 performs {TOS=[SI]} <--
+; 2^{TOS=[SI]}-1. All registers except SI are destroyed.
+
+pub $F2XM1
+ MOV ebx,offset EXPRAT ;[BX]=rational function
+ CALL FRAT2X ;[DI]=numerator=TOS
+ PUSH edi ;save numerator=TOS
+ XCHG esi,edi ;[SI]=numerator, [DI]=denominator
+ MOV [RESULT],edi ;result=[DI]
+ CALL SUDRQQ ;[DI]=denominator-numerator
+ MOV esi,edi ;[SI]=denominator-numerator
+ POP edi ;[DI]=numerator=TOS
+ MOV [RESULT],edi ;result=[DI]
+ CALL DIDRQQ ;[DI]=(2^x-1)/2
+ INC word ptr [edi+Expon] ;[DI]=2^x-1
+ MOV esi,edi ;[SI]=2^x-1
+ RET
+;-------------------------------------------------------------------------------
+
+pub eFYL2X
+ MOV edi,[CURstk]
+ MOV esi,edi
+ MOV AX,Flag[esi]
+ SUB edi,Reg87Len
+
+pub CALLFYL2X
+ CALL $FYL2X
+ MOV esi,[CURstk]
+ POPST
+ RET
+
+
+;---------------------------------------------------
+; !
+; 8087 emulator multiple of logarithm !
+; !
+;---------------------------------------------------
+
+; When -infinity<y={NOS=[DI]}<infinity and 0<x={TOS=[SI]}<infinity
+; then $FYL2X performs {NOS=[DI]} <-- {NOS=[DI]}*log2({TOS=[SI]}).
+; TOS is left unaltered, all registers except DI are destroyed.
+
+pub $FYL2X
+ PUSH esi ;save ptr to x=TOS
+ MOV esi,edi ;[SI]=y=NOS
+ MOV edi,offset TEMP2 ;[DI]=temp2
+ CALL MOVRQQ ;[DI]=y=temp2
+ MOV edi,esi ;[DI]=y=NOS
+ POP esi ;[SI]=x=TOS
+ PUSH edi ;save ptr to y=NOS
+ MOV edi,offset TEMP3 ;[DI]=temp3
+ CALL MOVRQQ ;[DI]=x=temp3
+ MOV BX,[edi+Expon] ;BX=exponent of x
+ MOV word ptr [edi+Expon],0 ;set exponent of x to 0
+ MOV esi,offset RT2 ;[SI]=2^.5
+ CALL COMPcsSIDI ;if reduced x < 2^.5
+ JA short LOGREDUCED ; then bypass normalization
+ DEC word ptr [edi+Expon] ;otherwise make x < 2^.5
+ INC BX ;adjust exponent
+
+pub LOGREDUCED
+ PUSH ebx ;save exponent of x
+ MOV esi,offset cFLD1 ;[SI]=1
+ CALL MoveCodeSItoDataSI
+ MOV [RESULT],edi ;result=[DI]
+ CALL SUDRQQ ;[DI]=(reduced x)-1=temp3
+ MOV esi,edi ;[SI]=(reduced x)-1=temp3
+ POP ebx ;get exponent of x
+ POP edi ;[DI]=y=NOS
+ PUSH ebx ;save exponent of x
+ CALL $FYL2XP1 ;[DI]=y*log2(reduced x)=NOS
+ POP ebx ;get exponent of x
+ XOR AX,AX ;zero AX
+ OR BX,BX ;if exponent is zero
+ JZ short LOGRETURN ; then done
+ MOV DX,AX ;make sign +
+ JNS short EXPPOSITIVE ;if + then bypass adjust
+ MOV DL,Sign ;make sign -
+ NEG BX ;negate exponent
+
+pub EXPPOSITIVE
+ MOV CX,16 ;initialize bit count
+
+pub LOGLOOP
+ DEC CX ;decrement shift count
+ SHL BX,1 ;and shift exponent of x left
+ JNC LOGLOOP ;until carry detected
+ PUSH edi ;save ptr to y*log2(reduced x)=NOS
+ RCR BX,1 ;normalize exponent of x
+ MOV edi,offset TEMP3 ;[DI]=temp3
+ STOS word ptr es:[edi]
+ STOS word ptr es:[edi]
+ STOS word ptr es:[edi]
+ MOV AX,BX
+ STOS word ptr es:[edi]
+ MOV AX,CX
+ STOS word ptr es:[edi]
+ MOV AX,DX
+ STOS word ptr es:[edi] ;store exponent of x in temp3
+ MOV edi,offset TEMP2 ;[DI]=y=temp2
+ MOV esi,offset TEMP3 ;[SI]=exponent of x=temp3
+ MOV [RESULT],edi ;result=[DI]
+ CALL MUDRQQ ;[DI]=y*exponent of x=temp2
+ MOV esi,edi ;[SI]=y*exponent of x=temp2
+ POP edi ;[DI]=y*log2(reduced x)=NOS
+ MOV [RESULT],edi ;result=[DI]
+ CALL ADDRQQ ;[DI]=y*log2(x)=NOS
+
+pub LOGRETURN
+ RET
+;-------------------------------------------------------------------------------
+
+pub eFYL2XP1
+ MOV edi,[CURstk]
+ MOV esi,edi
+ MOV AX,Flag[esi]
+ SUB edi,Reg87Len
+
+pub CALLFYL2XP1
+ CALL $FYL2XP1
+ MOV esi,[CURstk]
+ POPST
+ RET
+
+;---------------------------------------------------
+; !
+; 8087 emulator add 1 multiple of logarithm !
+; !
+;---------------------------------------------------
+
+; When -infinity<y={[DI]=NOS}<infinity and
+; 2^-.5-1<=x={[SI]=TOS}<2^.5-1 then $FYL2XP1 performs {NOS=[DI]}
+; <-- {NOS=[DI]}*log2({TOS=[SI]}+1). TOS is left unaltered, all
+; registers except DI are destroyed.
+
+pub $FYL2XP1
+ PUSH edi ;save ptr to y
+ MOV edi,offset TEMP1 ;[DI]=temp
+ CALL MOVRQQ ;[DI]=x=temp
+ PUSH esi ;save ptr to x
+ MOV esi,offset TWO ;[SI]=2
+ CALL MoveCodeSItoDataSI
+ MOV [RESULT],edi ;result=[DI]
+ CALL ADDRQQ ;[DI]=x+2=temp
+ POP esi ;[SI]=x=TOS
+ CALL DRDRQQ ;[DI]=x/(x+2)=temp
+ INC word ptr [edi+Expon] ;[DI]=2x/(x+2)=temp
+ MOV esi,edi ;[SI]=2x/(x+2)=temp
+ MOV ebx,offset LOGRAT ;[BX]=rational function
+ CALL FRAT2X ;[DI]=numerator=temp,
+ ; [SI]=denominator=temp
+ MOV [RESULT],edi ;result=[DI]
+ CALL DIDRQQ ;[DI]=log2(x+1)=temp
+ MOV esi,edi ;[SI]=log2(x+1)=temp
+ POP edi ;get ptr to y=NOS
+ MOV [RESULT],edi ;result=[DI]
+ CALL MUDRQQ ;[DI]=y*log2(x+1)=NOS
+ RET
+
+ProfEnd FTRAN
diff --git a/private/mvdm/wow16/win87em/emintern.asm b/private/mvdm/wow16/win87em/emintern.asm
new file mode 100644
index 000000000..1d5aae80a
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emintern.asm
@@ -0,0 +1,275 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emintern.asm - Emulator Internal Format and Macros
+page
+;---------------------------------------------------------------------------
+;
+; Emulator Internal Format:
+;
+; +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11
+; .___.___.___.___.___.___.___.___.___.___.___.___.
+; ptr --> |___|___|___|___|___|___|___|___|___|___|___|___|
+; lsb msb exl exh flg tag
+; |<--- mantissa --->|exponent
+;
+; The mantissa contains the leading 1 before the decimal point in the hi
+; bit of the msb. The exponent is not biased i.e. it is a signed integer.
+; The flag and tag bytes are as below.
+;
+; bit: 7 6 5 4 3 2 1 0
+; .___.___.___.___.___.___.___.___.
+; Flag: |___|_X_|_X_|_X_|_X_|_X_|_X_|___| X = unused
+; ^ ^
+; SIGN SINGLE (=1 if single precision)
+;
+;
+; bit: 7 6 5 4 3 2 1 0
+; .___.___.___.___.___.___.___.___.
+; Tag: |_X_|_X_|_X_|_X_|_X_|_X_|___|___| X = unused
+; ^ ^
+; | |
+; Special (Set for NAN or Inf) ---+ |
+; ZROorINF (Set for 0 or Inf) -------+
+;
+PAGE
+; Data Structure Equates
+Lsb equ 0
+Msb equ 7
+ MB0 equ 0
+ MB1 equ 1
+ MB2 equ 2
+ MB3 equ 3
+ MB4 equ 4
+ MB5 equ 5
+ MB6 equ 6
+ MB7 equ 7
+
+Expon equ 8
+
+Flag equ 10
+ Sign equ 128
+if fastSP
+ Single equ 1
+endif
+
+Tag equ 11
+ Special equ 2
+ ZROorINF equ 1
+
+Reg87Len equ 12
+
+MantissaByteCnt equ Msb - Lsb + 1
+IexpBias equ 3FFFh ; 16,383
+IexpMax equ 7FFFh ; Biased Exponent for Infinity
+IexpMin equ 0 ; Biased Exponent for zero
+
+DexpBias equ 3FFh ; 1023
+DexpMax equ 7FFh ; Biased Exponent for Infinity
+DexpMin equ 0 ; Biased Exponent for zero
+
+SexpBias equ 07Fh ; 127
+SexpMax equ 0FFh ; Biased Exponent for Infinity
+SexpMin equ 0 ; Biased Exponent for zero
+
+; Control Word Format CWcntl
+InfinityControl equ 10h
+ ICaffine equ 10h
+ ICprojective equ 0
+
+RoundControl equ 0Ch
+ RCchop equ 0Ch
+ RCup equ 08h
+ RCdown equ 04h
+ RCnear equ 0
+
+PrecisionControl equ 03h
+ PC24 equ 0
+ PC53 equ 02h
+ PC64 equ 03h
+
+; Status Word Format SWcc
+ C0 equ 01h
+ C1 equ 02h
+ C2 equ 04h
+ C3 equ 40h
+ConditionCode equ C0 + C1 + C2+ C3
+ CCgreater equ 0
+ CCless EQU C0
+ CCequal equ C3
+ CCincomprable equ C3 + C2 + C0
+
+
+; Status Flags Format CURerr
+
+Invalid equ 1h ; chip status flags
+Denormal equ 2h
+ZeroDivide equ 4h
+Overflow equ 8h
+Underflow equ 10h
+Precision equ 20h
+
+Unemulated equ 40h ; soft status flags
+SquareRootNeg equ 80h
+IntegerOverflow equ 100h
+StackOverflow equ 200h
+StackUnderflow equ 400h
+
+UStatMask equ 1FFFh ; user status flags
+
+MemoryOperand equ 2000h ; special instruction flags
+Reexecuted equ 4000h
+
+
+; floating point error signals (also used as DOS return code)
+
+errInvalid equ 81h ; sorted as above
+errDenormal equ 82h
+errZeroDivide equ 83h
+errOverflow equ 84h
+errUnderflow equ 85h
+errPrecision equ 86h
+
+errUnemulated equ 87h
+errSquareRootNeg equ 88h
+errIntegerOverflow equ 89h
+errStackOverflow equ 8Ah
+errStackUnderflow equ 8Bh
+
+
+subttl emintern.asm - Emulator interrupt frame
+page
+
+; define emulator interrupt frame
+
+ifdef i386
+
+ifdef XENIX
+
+; 386 frame for XENIX
+
+frame struc ; emulator interrupt frame
+
+regEAX dd ? ; 386 registers
+regECX dd ?
+regEDX dd ?
+regEBX dd ?
+regESP dd ?
+regEBP dd ?
+regESI dd ?
+regEDI dd ?
+
+regSegOvr dw ?,? ; segment override for bp relative EAs
+regES dw ?,?
+regDS dw ?,?
+
+regAX dw ?,? ; original EAX - stuff area for FSTSW AX
+regSS dd ? ; need to save ss
+regEIP dd ?
+regCS dw ?,?
+regFlg dd ?
+
+frame ends
+
+else
+
+; 386 frame
+
+frame struc ; emulator interrupt frame
+
+regEAX dd ? ; 386 registers
+regECX dd ?
+regEDX dd ?
+regEBX dd ?
+regESP dd ?
+regEBP dd ?
+regESI dd ?
+regEDI dd ?
+
+regSegOvr dw ?,? ; segment override for bp relative EAs
+regES dw ?,?
+regDS dw ?,?
+
+regAX dw ?,? ; original EAX - stuff area for FSTSW AX
+regEIP dd ?
+regCS dw ?,?
+regFlg dd ?
+
+frame ends
+
+endif
+
+else
+
+; 286 frame
+
+frame struc ; emulator interrupt frame
+
+regBP dw ?
+regSegOvr dw ? ; segment override for bp relative EAs
+regBX dw ?
+regCX dw ?
+regDX dw ?
+regSI dw ?
+regDI dw ?
+regDS dw ?
+regES dw ?
+regAX dw ?
+regIP dw ?
+regCS dw ?
+regFlg dw ?
+
+frame ends
+
+endif ;i386
+
+
+subttl emintern.asm - User Memory Management Macros
+page
+;*********************************************************************;
+; ;
+; User Memory Management Macros ;
+; ;
+;*********************************************************************;
+
+; All user data access uses these five macros.
+
+; Load user memory word at (DS:)SI to AX register; smash AX only
+
+LDUS2AX MACRO
+ lods word ptr es:[esi] ; 12 move word from ES:SI to AX
+ ENDM
+
+
+; Store word from AX to user memory at (ES:)DI; smash AX only
+
+STAX2US MACRO
+ stos word ptr es:[edi] ; 10 move word from AX to ES:DI
+ ENDM
+
+
+; Move user memory word at (DS:)SI to local at (ES:)DI; smash AX only
+
+MVUS2DI MACRO
+ movs word ptr es:[edi],word ptr ds:[esi] ; 18 move word from DS:SI to ES:DI
+ ENDM
+
+
+; Move local word at (DS:)SI to user memory at (ES:)DI; smash AX only
+
+MVSI2US MACRO
+ movs word ptr es:[edi],word ptr ds:[esi] ; 18 move word from DS:SI to ES:DI
+ ENDM
+
+
+; Move local word at (CS:)SI to user memory at (ES:)DI; smash AX only
+
+csMVSI2US MACRO
+ movs word ptr es:[edi],word ptr cs:[esi]
+ ENDM
+
diff --git a/private/mvdm/wow16/win87em/emlsdbl.asm b/private/mvdm/wow16/win87em/emlsdbl.asm
new file mode 100644
index 000000000..327eff4bd
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emlsdbl.asm
@@ -0,0 +1,442 @@
+ page ,132
+ subttl emlsdbl.asm - Load/Store Double Precision Numbers
+;***
+;emlsdbl.asm - Load/Store Double Precision Numbers
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Load/Store Double Precision Numbers
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Load Double Real ;
+; ;
+;*********************************************************************;
+;
+; Subroutine pushes double internal with double IEEE format at ES:SI
+
+ProfBegin LSDBL
+
+
+FLDSTOver:
+ xchg edi, esi ; di = TOS, es:si = double in memory
+ call OverStk
+ xchg edi, esi ; di = TOS, es:si = double in memory
+ jmp short FLDSTOk
+
+ even
+
+pub eFLDdr
+ mov edi, [CURstk] ; Get current register
+ cmp edi, [LIMstk] ; Is current register the last register?
+ jae short FLDSTOver ; Then report overflow.
+
+FLDSTOk:
+ add edi, Reg87Len ; Move to next free register.
+ mov [CURstk], edi ; Update current top of stack
+
+ LDUS2AX
+ mov bp, ax
+ LDUS2AX
+ mov dx, ax
+ LDUS2AX
+ mov cx, ax
+ LDUS2AX ; get final 2 bytes of source
+
+ mov esi, edi ; ds:si = TOS
+
+ mov bx, ax ; Double in bx:cx:dx:bp
+
+ ; assume we have a valid non-zero number so normalize and store
+
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+
+ OR BL,80H ; Set leading bit of mantissa
+ MOV MB7[esi],BL
+ MOV MB5[esi],CX
+ MOV MB3[esi],DX
+ MOV MB1[esi],BP
+
+ OR CX,BP ; Will need to determine if number is 0 later
+ OR CX,DX ; so mash all the bits together
+ MOV DH,AH
+ AND DH,Sign ; Mask everything but sign
+ MOV Flag[esi],DH ; and store
+ XOR DH,DH ; Clear for Tag
+ MOV MB0[esi],DH ; Also clear out least significant byte
+ AND AH,7FH ; Remove sign from exponent
+ SHR AX,1 ; Adjust
+ SHR AX,1
+ SHR AX,1
+ SHR AX,1
+ CMP AX,DexpMax ; See if number is NAN or Inf
+ JE short DNANorInf
+ CMP AX,DexpMin ; See if number is Zero or Denormal
+ JE short DZeroorDenorm
+ SUB AX,DexpBias ; Unbias exponent
+
+pub DStoreExpnTag
+ MOV Expon[esi],AX
+ MOV Tag[esi],DH
+ RET
+
+pub DNANorInf
+ MOV AX,IexpMax - IexpBias ; Set exponent to internal max
+ MOV DH,Special ; Set Tag to show NAN or Inf
+ CMP BL,80H ; If anything other than leading bit
+ JNE short DStoreExpnTag ; is set number is NAN (not Inf)
+ OR CX,CX
+ JNE DStoreExpnTag
+ OR DH,ZROorINF ; Set Tag to show Inf
+ JMP DStoreExpnTag
+
+pub DZeroorDenorm
+ CMP BL,80H ; If anything other than leading bit
+ JNE short DDenormal ; is set number is Denormal
+ OR CX,CX
+ JNE short DDenormal
+ MOV AX,IexpMin - IexpBias ; Set exponent to internal min
+ MOV DH,ZROorINF ; Set Tag to show 0
+ JMP DStoreExpnTag
+
+pub DDenormal
+ OR [CURerr],Denormal ; Set Denormal Exception
+ SUB AX,DexpBias ; unbias the Exponent
+ MOV BP,MB0[esi] ; must refetch mantissa and normalize
+ MOV DX,MB2[esi]
+ MOV CX,MB4[esi]
+ MOV BX,MB6[esi]
+ INC AX ; Shift once if exp = expmin
+
+pub DNormalize
+ DEC AX ; Drop exponent
+ SHL BP,1 ; Shift mantissa
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+ OR BX,BX
+ JNS DNormalize
+
+ MOV MB0[esi],BP ; Store mantissa
+ MOV MB2[esi],DX
+ MOV MB4[esi],CX
+ MOV MB6[esi],BX
+ XOR DH,DH ; Clear Tag
+ JMP DStoreExpnTag
+
+page
+;*********************************************************************;
+; ;
+; Store Double Real ;
+; ;
+;*********************************************************************;
+;
+
+pub DSpecial
+ TEST CL,Special ; NAN or INF?
+ JNE short DDNANorINF
+ XOR AX,AX ; Number is zero
+ STAX2US
+ STAX2US
+ STAX2US
+ STAX2US
+ JMP DCommonExit
+
+pub DDNANorINF
+ TEST CL,ZROorINF
+ JNE short DInf
+ MOV DX,MB1[esi] ; Number is a NAN
+ MOV BX,MB3[esi] ; Fetch Mantissa
+ MOV AX,MB5[esi]
+ MOV CL,MB7[esi]
+
+ SHR CL,1 ; Shift into place
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ SHR CL,1
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ SHR CL,1
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ ; Now store the Mantissa
+
+ XCHG DX,AX
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ MOV AX,DX
+ STAX2US
+
+ MOV BH,Flag[esi] ; Pick up Sign
+ AND BH,Sign
+ MOV AX,DexpMax*16 ; Load shifted max exponent
+ OR AH,BH ; Merge in sign
+ OR AL,CL ; Merge in top bits of Mantissa
+ STAX2US
+ JMP DCommonExit
+
+pub DInf
+ MOV BL,Flag[esi]
+ AND BL,Sign
+ JMP DSignedInfinity
+
+pub JMPDOver
+ JMP DOver
+
+pub JMPDUnder
+ JMP DUnder
+
+pub JMPDSpecial
+ JMP DSpecial
+
+ even
+
+pub eFSTdr
+
+; internal TOS register at DS:SI to double IEEE in memory at ES:DI
+
+ MOV edi,esi ; 10 save target memory offset
+ MOV esi,[CURstk] ; 14 source offset is current TOS
+
+ MOV CL,Tag[esi] ; See if number is NAN, Inf, or 0
+ OR CL,CL
+ JNZ short JMPDSpecial
+ MOV CL,Flag[esi] ; Pick up sign
+if fastSP
+ TEST CL,Single
+ JZ DD1
+ MOV word ptr MB0[esi],0
+ MOV word ptr MB2[esi],0
+ MOV byte ptr MB4[esi],0
+DD1:
+endif
+ MOV BP,Expon[esi] ; See if we blatently over or under flow
+ CMP BP,DexpMax - DexpBias
+ JGE JMPDOver
+ CMP BP,DexpMin - DexpBias
+ JLE JMPDUnder
+
+ ;Since we won't have room to decide about rounding after we load
+ ;the mantissa we will determine the rounding style first
+
+ MOV AL,MB0[esi] ; Low byte becomes sticky bit ...
+ MOV DX,MB1[esi] ; when combined with lo 2 bits of next byte
+ OR AL,AL
+ JZ short NOSTK
+ OR DL,1
+
+pub NOSTK
+ TEST DL,7H ; See if anything will be chopped off in truncation
+ JZ short DTRUNC
+ OR [CURerr],Precision ; number is not exact so set flag and round
+ MOV AL,[CWcntl] ; Pick up rounding control
+
+ ; Mantissa gets incremented for rounding only on these conditions:
+ ; (UP and +) or (DOWN and -) or
+ ; (NEAR and Roundbit and (Sticky or Oddlastbit))
+
+ SHR AL,1
+ SHR AL,1
+ SHR AL,1
+ JC short StDOWNorCHOP53
+ SHR AL,1
+ JC short StUP53
+
+pub StNEAR53
+ TEST DL,4H ; 3rd bit over is round bit
+ JZ short DTRUNC
+ TEST DL,0BH ; 4th bit is last bit, 1st and 2nd are Sticky
+ JZ short DTRUNC
+
+pub DINC ; Know we must increment mantissa so
+ MOV BX,MB3[esi] ; Fetch mantissa
+ MOV AX,MB5[esi]
+ MOV CL,MB7[esi]
+ AND CL,7FH ; Mask off leading bit
+ ADD DX,8H ; Add 1 to what will be last bit after the shift
+
+ ADC BX,0
+ ADC AX,0
+ ADC CL,0
+ JNS short DShift
+
+ AND CL,7FH ; Mask off leading bit
+ INC BP ; Increment exponent
+ CMP BP,DexpMax - DexpBias
+ JL short DShift ; And test for the rare chance we went over
+ JMP short DOverReset
+
+ even
+
+pub StUP53
+ SHL CL,1 ; Test sign
+ JNC short DINC ; UP and + means inc
+ JMP SHORT DTRUNC
+
+pub StDOWNorCHOP53
+ SHR AL,1
+ JC short StCHOP53
+
+pub StDOWN53
+ SHL CL,1 ; Test sign
+ JC short DINC ; DOWN and - means inc
+
+StCHOP53:
+pub DTRUNC
+ MOV BX,MB3[esi] ; Fetch mantissa
+ MOV AX,MB5[esi]
+ MOV CL,MB7[esi]
+ AND CL,7FH ; Mask off leading bit
+
+pub DShift
+ SHR CL,1
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ SHR CL,1
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ SHR CL,1
+ RCR AX,1
+ RCR BX,1
+ RCR DX,1
+
+ ; Now store the Mantissa
+
+ XCHG DX,AX
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ MOV AX,DX
+ STAX2US
+
+ MOV AX,BP ; Merge in the exponent
+ ADD AX,DexpBias ; Bias exponent
+ SHL AX,1 ; Shift into position
+ SHL AX,1
+ SHL AX,1
+ SHL AX,1
+ OR AL,CL ; Merge in top bits of Mantissa
+ MOV CL,Flag[esi] ; Pick up sign
+ AND CL,Sign
+ OR AH,CL ; Merge in the sign
+ STAX2US
+
+pub DCommonExit
+ RET ; 8 return
+
+pub DOverReset ; We come here if we stored 6 bytes of mantissa
+ ; befor detecting overflow so must reset pointer
+ SUB edi,6 ; to double in memory
+
+pub DOver ; Here on overflow
+ OR [CURerr],Overflow + Precision
+ MOV BL,Flag[esi]
+ AND BL,Sign ; Mask to sign
+ MOV CL,[CWcntl] ; Determine rounding style
+ SHR CL,1
+ SHR CL,1
+ SHR CL,1
+ JC short StMOVDNorCHP53
+ SHR CL,1
+ JC short StMOVUP53
+
+StMOVNEAR53:
+pub DSignedInfinity
+ MOV esi,offset IEEEinfinityD
+pub DStore
+ csMVSI2US
+ csMVSI2US
+ csMVSI2US
+ LODS word ptr cs:[esi]
+ OR AH,BL ;Overstore correct sign
+ STAX2US
+ JMP DCommonExit
+
+pub StMOVDNorCHP53
+ SHR CL,1
+ JC short StMOVCHOP53
+
+pub StMOVDOWN53
+ OR BL,BL ; DOWN and + means biggest
+ JNZ short DSignedInfinity
+
+StMOVCHOP53:
+pub DSignedBiggest
+ MOV esi,offset IEEEbiggestD
+ JMP DStore
+
+pub StMOVUP53
+ OR BL,BL ; UP and - means biggest
+ JZ DSignedInfinity
+ JMP DSignedBiggest
+
+pub DUnder
+ OR [CURerr],Underflow+Precision ; Set flag
+ ADD BP,DexpBias ; Bias the exponent which was less than
+ NEG BP ; Min = 0 so convert to positive difference
+ifdef i386
+ movzx ecx,BP ; Convert to shift count
+else
+ MOV CX,BP ; Convert to shift count
+endif
+ ADD ecx,4 ; 3 for Double format 1 to expose hidden bit
+
+ MOV DH,Flag[esi] ; Need and exp of 0 for denormal
+ AND DH,Sign
+
+ MOV DL,MB7[esi]
+ MOV BX,MB5[esi]
+ MOV BP,MB3[esi]
+ MOV AX,MB1[esi]
+
+pub DshiftLoop
+ SHR DL,1
+ RCR BX,1
+ RCR BP,1
+ RCR AX,1
+ LOOP DshiftLoop
+
+ STAX2US
+ MOV AX,BP
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ MOV AX,DX
+ STAX2US
+ JMP DCommonExit
+
+ProfEnd LSDBL
diff --git a/private/mvdm/wow16/win87em/emlsint.asm b/private/mvdm/wow16/win87em/emlsint.asm
new file mode 100644
index 000000000..aadcaf853
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emlsint.asm
@@ -0,0 +1,284 @@
+ page ,132
+ subttl emlsint.asm - Load/Store 16/32-bit integers
+;***
+;emlsint.asm - Load/Store 16/32-bit integers
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Load/Store 16/32-bit integers
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Load Single (16 Bit) Integer ;
+; ;
+;*********************************************************************;
+
+; ES:SI: memory address of 16 bit integer
+
+ProfBegin LSINT
+
+
+pub eFLDsi
+ LDUS2AX ; Fetch the integer
+ MOV DI,AX ; into DI:BP:BX:DX
+ OR DI,DI
+ JZ short LoadZero
+ XOR BP,BP
+ MOV BX,BP
+ MOV DX,BX
+
+ MOV AX,15 ; Exponent would be 15 if no shifts needed
+ PUSHST ; Get a new TOS
+ XOR CL,CL
+ MOV Tag[esi],CL ; Tag number as valid non-zero
+ MOV CX,DI ; Sign of Integer to CH
+ AND CH,Sign
+if fastSP
+ OR CH,Single
+endif
+ JNS short SETFLAG16 ; If positive integer set the flag
+
+ NEG DI ; Otherwise compliment the number first
+
+pub SETFLAG16
+ MOV Flag[esi],CH
+ JMP IntegerToInternal
+
+pub LoadZero
+ PUSHST ; Get a new TOS
+ XOR AX,AX
+ MOV MB0[esi],AX
+ MOV MB2[esi],AX
+ MOV MB4[esi],AX
+ MOV MB6[esi],AX
+ MOV Expon[esi],IexpMin - IexpBias
+ MOV Flag[esi],AH
+ MOV AH,ZROorINF
+ MOV Tag[esi],AH
+ RET
+PAGE
+;*********************************************************************;
+; ;
+; Store Single (16 Bit) Integer ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 16 bit integer
+
+pub eFSTsi
+ PUSH esi ; Save memory address for store
+ MOV esi,[CURstk]
+ ; Test for special conditions
+ TEST byte ptr Tag[esi],Special ; If number is not in range it is overflow
+ JNZ short IntegerOverflow16
+ TEST byte ptr Tag[esi],ZROorINF
+ JNZ short StoreIntegerZero16
+ ; Fetch Exponent & test fo blatent overflow
+ MOV CX,Expon[esi]
+ CMP CX,15
+ JG short IntegerOverflow16
+
+if fastSP
+ MOV BX,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ TEST byte ptr Flag[esi],Single
+ JZ SSID
+ XOR BL,BL
+ MOV BP,BX
+ XOR BX,BX
+ MOV DX,BX
+SSI:
+else
+ MOV BP,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+endif
+ CALL InternalToInteger
+ ; Integer now in BX:DX (not yet 2's compliment)
+ OR BX,BX ; Test again for Overflow
+ JNZ short IntegerOverflow16
+ MOV AH,Flag[esi] ; See if we need to compliment
+ OR AH,AH
+ JNS short Int16in2sComp
+
+ NEG DX
+ JZ short Store16 ; Special case 0
+
+pub Int16in2sComp
+ XOR AX,DX ; If Signs agree we did not overflow
+ JS short IntegerOverflow16
+
+pub Store16
+ POP edi ; Restore Memory address
+ MOV AX,DX
+ STAX2US
+ RET
+
+if fastSP
+SSID:
+ MOV BP,BX
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+ JMP SSI
+endif
+
+pub StoreIntegerZero16
+ XOR DX,DX
+ JMP Store16
+
+pub IntegerOverflow16
+ OR [CURerr],Invalid
+ MOV DX,8000H ; Integer Indefinite
+ JMP Store16
+
+page
+;*********************************************************************;
+; ;
+; Load Double (32 Bit) Integer ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 32 bit integer
+
+pub eFLDdi
+ LDUS2AX ; Fetch the integer
+ MOV BP,AX ; into DI:BP:BX:DX
+ LDUS2AX
+ MOV DI,AX
+
+ OR AX,BP
+ JZ short JMPLoadZeroBecauseThisLanguageHasNoFarConditionalJump
+ XOR BX,BX
+ MOV DX,BX
+
+ MOV AX,31 ; Exponent would be 31 if no shifts needed
+ PUSHST ; Get a new TOS
+ XOR CL,CL
+ MOV Tag[esi],CL ; Tag number as valid non-zero
+ MOV CX,DI ; Sign of Integer to CH
+ AND CH,Sign
+ JNS short SETFLAG32 ; If positive integer set the flag
+
+ XOR DI,0FFFFH ; Otherwise compliment the number first
+ XOR BP,0FFFFH
+ ADD BP,1
+ ADC DI,0
+
+pub SETFLAG32
+ MOV Flag[esi],CH
+ OR DI,DI
+ JZ short SPEEDSHIFT32
+ JMP IntegerToInternal
+
+JMPLoadZeroBecauseThisLanguageHasNoFarConditionalJump:
+ JMP LoadZero
+
+pub SPEEDSHIFT32
+ MOV DI,BP
+ XOR BP,BP
+ SUB AX,16
+ JMP IntegerToInternal
+
+page
+;*********************************************************************;
+; ;
+; Store Double (32 Bit) Integer ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 32 bit integer
+
+pub eFSTdi
+ PUSH esi
+ call TOSto32int ; convert TOS to 32-bit integer
+ POP edi ; Restore Memory address
+ MOV AX,DX
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ RET
+
+
+pub TOSto32int
+ MOV esi,[CURstk]
+ ; Test for special conditions
+ TEST byte ptr Tag[esi],Special ; If number is not in range it is overflow
+ JNZ short IntegerOverflow32
+ TEST byte ptr Tag[esi],ZROorINF
+ JNZ short StoreIntegerZero32
+ ; Fetch Exponent & test fo blatent overflow
+ MOV CX,Expon[esi]
+ CMP CX,31
+ JG short IntegerOverflow32
+
+if fastSP
+ MOV BX,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ TEST byte ptr Flag[esi],Single
+ JZ SDID
+ XOR BL,BL
+ MOV BP,BX
+ XOR BX,BX
+ MOV DX,BX
+SDI:
+else
+ MOV BP,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+endif
+ CALL InternalToInteger
+ ; Integer in BP:BX:DX (not yet 2's compliment)
+ OR BP,BP ; Test again for Overflow
+ JNZ short IntegerOverflow32
+ MOV AH,Flag[esi] ; See if we need to compliment
+ OR AH,AH
+ JNS short Int32in2sComp
+
+ XOR BX,0FFFFH ; 2's Compliment of BX:DX
+ XOR DX,0FFFFH
+ ADD DX,1
+ ADC BX,0
+
+pub Int32in2sComp
+ XOR AX,BX ; If Signs agree we did not overflow
+ JS short IntOverOrZero32 ; Special case is -0 which we let pass
+
+pub Store32
+ ret
+
+if fastSP
+SDID:
+ MOV BP,BX
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+ JMP SDI
+endif
+
+pub StoreIntegerZero32
+ XOR DX,DX
+ MOV BX,DX
+ ret
+
+pub IntOverOrZero32
+ OR BX,DX
+ JZ Store32
+
+pub IntegerOverflow32
+ OR CURerr,Invalid
+ MOV BX,8000H ; Integer Indefinite
+ XOR DX,DX
+ ret
+
+ProfEnd LSINT
diff --git a/private/mvdm/wow16/win87em/emlsquad.asm b/private/mvdm/wow16/win87em/emlsquad.asm
new file mode 100644
index 000000000..285040ef7
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emlsquad.asm
@@ -0,0 +1,174 @@
+ page ,132
+ subttl emlsquad.asm - Load/Store 64-bit integers
+;***
+;emlsquad.asm - Load/Store 64-bit integers
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Load/Store 64-bit integers
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Load Quad (64 Bit) Integer ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 64 bit integer
+
+
+ProfBegin LSQUAD
+
+pub eFLDlongint
+ LDUS2AX ; Fetch the integer
+ MOV DX,AX ; into DI:BP:BX:DX
+ LDUS2AX
+ MOV BX,AX
+ LDUS2AX
+ MOV BP,AX
+ LDUS2AX
+ MOV DI,AX
+
+ OR AX,BP
+ OR AX,BX
+ OR AX,DX
+ JZ short Jmp2LoadZero
+
+ MOV AX,63 ; Exponent would be 63 if no shifts needed
+ PUSHST ; Get a new TOS
+ XOR CL,CL
+ MOV Tag[esi],CL ; Tag number as valid non-zero
+ MOV CX,DI ; Sign of Integer to CH
+ AND CH,Sign
+ JNS short SETFLAG64 ; If positive integer set the flag
+
+ call TwosComplement64; Otherwise complement the number first
+
+pub SETFLAG64
+ MOV Flag[esi],CH
+ OR DI,DI
+ JNZ Jmp2IntegerToInternal
+ OR BP,BP
+ JNZ Jmp2IntegerToInternal
+
+pub SPEEDSHIFT64
+ MOV DI,BX
+ MOV BP,DX
+ XOR BX,BX
+ XOR DX,DX
+ SUB AX,32
+Jmp2IntegerToInternal:
+ JMP IntegerToInternal
+
+Jmp2LoadZero:
+ JMP LoadZero
+
+
+page
+;*********************************************************************;
+; ;
+; Store Quad (64 Bit) Integer ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 64 bit integer
+
+pub eFSTlongint
+ PUSH esi
+ call TOSto64int ; convert TOS to 64-bit integer
+ ; in DI:BP:BX:DX
+ XCHG AX,DI
+ XCHG AX,DX ; now in DX:BP:BX:AX
+ POP edi ; Restore Memory address
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ MOV AX,BP
+ STAX2US
+ MOV AX,DX
+ STAX2US
+ RET
+
+
+pub TOSto64int
+ MOV esi,[CURstk]
+ ; Test for special conditions
+ TEST byte ptr Tag[esi],Special ; If number is not in range it is overflow
+ JNZ short IntegerOverflow64
+ TEST byte ptr Tag[esi],ZROorINF
+ JNZ short StoreIntegerZero64
+ ; Fetch Exponent & test fo blatent overflow
+ MOV CX,Expon[esi]
+ CMP CX,63
+ JG short IntegerOverflow64
+
+if fastSP
+ ;UNDONE - ????
+else
+ MOV BP,MB4[esi] ; Fetch mantissa to DI:BP:BX:DX
+ MOV DI,MB6[esi]
+ MOV DX,MB0[esi]
+ MOV BX,MB2[esi]
+endif
+ CALL InternalToInteger
+ ; Integer in DI:BP:BX:DX
+ ; (not yet 2's complement)
+ MOV AH,Flag[esi] ; See if we need to complement
+ OR AH,AH
+ JNS short Int64in2sComp
+ call TwosComplement64
+
+pub Int64in2sComp
+ XOR AX,DI ; If Signs agree we did not overflow
+ JS short IntOverOrZero64 ; Special case is -0 which we let pass
+
+pub Store64
+ POPSTsi ; store POP to long-integer
+ ret
+
+if fastSP
+ ;UNDONE ???
+endif
+
+pub StoreIntegerZero64
+ XOR DI,DI
+pub ZeroLower48
+ XOR BP,BP
+ MOV BX,BP
+ MOV DX,BP
+ JMP Store64
+
+pub IntOverOrZero64
+ OR DI,BP
+ OR DI,BX
+ OR DI,DX
+ JNZ IntegerOverflow64
+ JMP Store64 ; Return zero
+
+pub IntegerOverflow64
+ OR CURerr,Invalid
+ MOV DI,8000H ; Integer Indefinite
+ JMP short ZeroLower48
+
+pub TwosComplement64
+ NOT DI ; 2's Complement of DI:BP:BX:DX
+ NOT BP
+ NOT BX
+ NEG DX
+ CMC
+ ADC BX,0
+ ADC BP,0
+ ADC DI,0
+ ret
+
+
+ProfEnd LSQUAD
diff --git a/private/mvdm/wow16/win87em/emlssng.asm b/private/mvdm/wow16/win87em/emlssng.asm
new file mode 100644
index 000000000..a2db8e4de
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emlssng.asm
@@ -0,0 +1,333 @@
+ page ,132
+ subttl emlssng.asm - Load/Store Single Precision Numbers
+;***
+;emlssng.asm - Load/Store Single Precision Numbers
+;
+; Copyright (c) 1984-89, Microsoft Corporation
+;
+;Purpose:
+; Load/Store Single Precision Numbers
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin LSSNG
+
+;*********************************************************************;
+; ;
+; Load Single Real ;
+; ;
+;*********************************************************************;
+;
+; Subroutine converts single in regs to internal at ES:SI
+
+
+pub eFLDsr
+ LDUS2AX ; get lower mantissa part
+ MOV DI,AX ; 2 keep lower mantissa in DX
+ LDUS2AX ; get upper exponent/sign part
+ MOV DL,AL ; 2 copy most sig. mantissa byte
+ ROL AX,1 ; 2 sign to AL, exponent to AH
+ AND AL,1 ; 4 clear all flags except sign
+ ROR AL,1 ; 2 get sign in right position
+ XCHG AL,AH
+
+ ; AX, DI, DL: operand one
+
+ PUSHST ; 64 allocate another register
+
+pub SingleToInternal
+
+ OR DL,80H ; Set leading bit of mantissa
+ XOR DH,DH ; Set Tag to valid non-zero
+ CMP AL,SexpMax ; Is Number NAN or Inf?
+ JE short SNANorInf
+if fastSP
+ OR AH,Single ; Set single Precision flag
+endif
+ CMP AL,SexpMin ; Is Number Zero or Denormal
+ JE short SZeroOrDenorm
+ ; Otherwise number is valid non-zero
+ MOV Flag[esi],AH ; Store sign
+ SUB AL,SexpBias ; Unbias the exponent
+ CBW
+
+pub SStoreExpnTag
+ MOV Expon[esi],AX ; Store Exponent
+ MOV Tag[esi],DH ; Store Tag
+ MOV MB7[esi],DL ; Store Mantissa
+ MOV MB5[esi],DI
+ife fastSP
+ XOR AX,AX ; Clear low order bytes of Mantissa
+ MOV MB4[esi],AL
+ MOV MB2[esi],AX
+ MOV MB0[esi],AX
+endif
+ RET
+
+pub SNANorInf
+ MOV Flag[esi],AH ; Store sign
+ MOV AX,IexpMax - IexpBias ; Set exponent to internal max
+ MOV DH,Special ; Set Tag to show NAN or Inf
+ CMP DL,80H ; If anything other than leading bit
+ JNE short SStoreExpnTag ; is set number is NAN (not Inf)
+ OR DI,DI
+ JNE short SStoreExpnTag
+ OR DH,ZROorINF ; Set Tag to show Inf
+ JMP SStoreExpnTag
+
+pub SZeroorDenorm
+ MOV Flag[esi],AH ; Store sign
+ CMP DL,80H ; If anything other than leading bit
+ JNE short SDenormal ; is set number is Denormal
+ OR DI,DI
+ JNE short SDenormal
+ MOV AX,IexpMin - IexpBias ; Set exponent to internal min
+ OR DH,ZROorINF ; Set Tag to show 0
+ JMP SStoreExpnTag
+
+pub SDenormal
+ OR [CURerr],Denormal ; Set Denormal Exception
+ SUB AL,SexpBias ; unbias the Exponent
+ CBW
+ INC AX
+
+pub SNormalize
+ DEC AX
+ SHL DI,1
+ RCL DL,1
+ OR DL,DL
+ JNS SNormalize
+
+ JMP SStoreExpnTag
+
+page
+;************************************************************;
+; ;
+; Store Single Real ;
+; ;
+;************************************************************;
+
+pub SSpecial ; number is NAN or INF or Zero
+ TEST CL,Special ; NAN or INF?
+ JNE short SSNANorINF
+ XOR AX,AX ; Number is Zero
+ MOV BX,AX
+ JMP STRUNC
+
+pub SSNANorINF
+ TEST CL,ZROorINF
+ JNE short SInf
+ MOV BX,MB5[esi] ; Number is a NAN
+ MOV AL,MB7[esi]
+ MOV AH,Flag[esi] ; Pick up Sign
+ SHL AX,1 ; Destroy leading bit, Sign to CF
+ MOV AH,SexpMax
+ RCR AX,1
+ JMP STRUNC
+
+ pub SInf
+ MOV AH,Flag[esi]
+ JMP SSignedInfinity
+
+pub JMPSOver
+ JMP SOver
+
+pub JMPSUnder
+ JMP SUnder
+
+; ES:SI: memory address of single
+; stores and misc. operations; first setup register values as follows:
+; AX: TOS flags (for DOUB and SIGN flags)
+; SI: TOS address (offset)
+
+pub eFSTsr
+ mov edi,esi ; ES:DI = store address
+ MOV esi,[CURstk] ; 14 load TOS address
+ MOV AX,Flag[esi] ; 21 get TOS flags (sign, double)
+
+; convert internal at DS:SI to single
+; DS:SI = TOS, ES:DI = memory, CH = operation (POP), BP = old ES value
+
+ MOV CL,Tag[esi] ; See if number is NAN or Inf or Zero
+ OR CL,CL
+ JNZ short SSpecial
+ MOV CL,Flag[esi] ; Pick up sign & single precision flag
+
+ MOV AX,Expon[esi]
+ CMP AX,SexpMax - SexpBias
+ JGE short JMPSOver
+ CMP AX,SexpMin - SexpBias
+ JLE short JMPSUnder
+
+ ADD AL,SexpBias ; Bias the Exponent
+ MOV AH,MB7[esi] ; Pick up MSB of Mantissa
+ XCHG AH,AL
+ SHL AL,1 ; Shift mantissa to destroy leading integer bit
+ SHL CL,1 ; Get sign into CF
+ RCR AX,1 ; Pack sign, exp, & MSB
+if fastSP
+ TEST CL,Single*2 ; if number was single rounding is not needed
+ JZ SS1
+ MOV BX,MB5[esi]
+ JMP SHORT STRUNC
+SS1:
+endif
+ MOV DX,MB0[esi] ; DL Will be the sticky bit
+ OR DX,MB2[esi] ; DH will be round and the rest of sticky
+ OR DL,DH
+ XOR DH,DH
+ MOV BX,MB5[esi]
+ OR DX,MB3[esi]
+ JZ short STRUNC ; If no Round or Sticky result is exact
+ OR [CURerr],Precision
+
+pub SRound ; single in AX:BX:DX
+ MOV CL,[CWcntl] ; Need to know Rounding Control
+ SHR CL,1
+ SHR CL,1
+ SHR CL,1
+ JC short StDOWNorCHOP24
+ SHR CL,1
+ JC short StUP24
+
+pub StNEAR24
+ CMP DX,8000H ; How are round and sticky bits?
+ JB short STRUNC ; No round, so truncate
+ JA short SINC ; Round and sticky so round up
+ TEST BL,1 ; Round and no sticky, is last bit even?
+ JZ short STRUNC ; Yes, so truncate.
+
+pub SINC
+ MOV DL,AL ; Increment mantissa
+ ADD BX,1
+ ADC AX,0
+ XOR DL,AL ; See if we overflowed a bit into the exponent
+ JNS short STRUNC ; If not number is now correct so go store
+ MOV DX,AX ; Exponent was incremented, see if it overflowed
+ SHL DX,1
+ CMP DH,SexpMax
+ JE short SOver
+
+pub StCHOP24
+STRUNC:
+ XCHG AX,BX
+ STAX2US
+ MOV AX,BX
+ STAX2US
+
+pub SStoreExit
+ RET
+
+pub StDOWNorCHOP24
+ SHR CL,1
+ JC short StCHOP24
+
+pub StDOWN24
+ OR AH,AH ; Test the sign
+ JS short SINC
+ JMP short STRUNC
+
+pub StUP24
+ OR AH,AH ; Test the sign
+ JS short STRUNC
+ JMP short SINC
+
+pub SOver ; Number overflowed Single Precision range.
+ ; Result returned depends upon rounding control
+ OR [CURerr],Overflow + Precision
+ MOV CL,[CWcntl]
+ SHR CL,1
+ SHR CL,1
+ SHR CL,1
+ JC short StMOvDNorCHP24
+
+ SHR CL,1
+ JC short StMOvUP24
+
+StMOvNEAR24: ; Masked Overflow Near Rounding
+
+pub SSignedInfinity ; Return signed infinity
+ MOV BX,[IEEEinfinityS + 2]
+ AND AH,Sign ; Overstore the proper sign
+ OR BH,AH
+ MOV AX,[IEEEinfinityS]
+ STAX2US
+ MOV AX,BX
+ STAX2US
+ JMP SStoreExit
+
+pub StMOvDNorCHP24
+ SHR CL,1
+ JC short StMOvCHOP24
+
+pub StMOvDOWN24 ; Masked Overflow Down Rounding
+ TEST AH,Sign ; Positive goes to biggest
+ JNZ short SSignedInfinity
+
+StMOvCHOP24: ; Masked Overflow Chop Rounding
+pub SSignedBiggest
+ MOV BX,[IEEEbiggestS + 2]
+ AND AH,Sign ; Overstore the proper sign
+ OR AH,BH
+ MOV AL,BL
+ STAX2US
+ MOV AX,[IEEEbiggestS]
+ STAX2US
+ JMP SStoreExit
+
+pub StMOvUP24 ; Masked Overflow Up Rounding
+ TEST AH,Sign ; Negative goes to biggest
+ JZ short SSignedInfinity
+ JMP SSignedBiggest
+
+pub SUnder ; Masked Underflow - Try to denormalize
+ OR [CURerr],Underflow+Precision
+ NEG AX ; Convert exponent (which is too small)
+ ADD AX,SexpMin-SexpBias+1 ; To a positive shift count
+ CMP AX,24 ; Is shift more than mantissa precision
+ JGE short Szero
+ XCHG CX,AX
+ifdef i386
+ movzx ecx,cx ; (ecx) = zero-extended loop count
+endif
+ MOV DX,MB0[esi] ; Pick up Insignif bytes for sticky bit
+ OR DX,MB2[esi]
+ MOV AL,DL
+ OR AL,DH
+ MOV DX,MB4[esi]
+ MOV BX,MB6[esi]
+ OR AL,AL
+ JZ short SSHIFTR
+ OR DL,1 ; Set the sticky bit
+
+pub SSHIFTR
+ SHR BX,1
+ RCR DX,1
+ JNC short SSLOOP
+ OR DL,1
+pub SSLOOP
+ LOOP SSHIFTR
+
+ XCHG AH,CH ; Restore operation to CH
+ MOV AH,Flag[esi] ; Pick up sign
+ AND AH,Sign ; Mask to sign only
+ MOV AL,BH ; Biased exponent for a denormal is 0
+ MOV BH,BL
+ MOV BL,DH
+ MOV DH,DL
+ XOR DL,DL
+ JMP SRound
+
+pub Szero
+ XOR AX,AX
+ MOV BX,AX
+ JMP STRUNC ; Go store single and exit
+
+ProfEnd LSSNG
diff --git a/private/mvdm/wow16/win87em/emlstmp.asm b/private/mvdm/wow16/win87em/emlstmp.asm
new file mode 100644
index 000000000..e7a87b5c2
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emlstmp.asm
@@ -0,0 +1,183 @@
+ page ,132
+ subttl emlstmp.asm - Load/Store Temp Real Numbers
+;***
+;emlstmp.asm - Load/Store Temp Real Numbers
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Load/Store Temp Real Numbers
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin LSTMP
+
+;*********************************************************************;
+; ;
+; Load 80 Bit Temp Real ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 80 bit tempreal
+
+pub eFLDtemp
+ MOV edi,esi ; Get a new stack element and leave
+ PUSHST
+ XCHG edi,esi
+
+ mov ax,es
+ mov dx,ds
+ mov es,dx
+ mov ds,ax
+ MVUS2DI ; Move 8 bytes of mantissa to TOS
+ MVUS2DI
+ MVUS2DI
+ MVUS2DI
+ mov ax,es
+ mov dx,ds
+ mov es,dx
+ mov ds,ax
+ LDUS2AX ; Fetch exponent
+ SUB edi,8 ; Reset pointer to TOS
+ XCHG esi,edi ; Now DS:SI points to TOS
+
+ MOV DH,AH ; Exponent and Sign to DX
+ AND DH,Sign ; Mask to Sign only
+ MOV Flag[esi],DH
+ AND AH,7FH ; Mask out sign
+ XOR DH,DH ; Set Tag to valid non-zero
+ CMP AX,IexpMax
+ JE short TNANorInf
+ CMP AX,IexpMin
+ JE short TZeroOrDenorm
+ SUB AX,IexpBias
+
+pub TStoreExpnTag
+ MOV Expon[esi],AX
+ MOV Tag[esi],DH
+ RET
+
+pub TNANorInf
+ MOV AX,IexpMax - IexpBias
+ MOV DH,Special
+ CMP MB6[esi],8000H ; Test for Infinity
+ JNE short TStoreExpnTag
+ MOV BP,MB4[esi]
+ OR BP,MB2[esi]
+ OR BP,MB0[esi]
+ JNZ TStoreExpnTag
+ OR DH,ZROorINF
+ JMP TStoreExpnTag
+
+pub TZeroOrDenorm
+ MOV BP,MB6[esi]
+ OR BP,MB4[esi]
+ OR BP,MB2[esi]
+ OR BP,MB0[esi]
+ JNZ short TDenormal
+
+pub TZero
+ MOV AX,IexpMin - IexpBias
+ MOV DH,ZROorINF
+ JMP TStoreExpnTag
+
+pub TDenormal
+ OR [CURerr],Underflow+Precision ; Say it underflowed - set it to 0
+ XOR BP,BP
+ MOV MB0[esi],BP
+ MOV MB2[esi],BP
+ MOV MB4[esi],BP
+ MOV MB6[esi],BP
+ JMP TZero
+
+PAGE
+;*********************************************************************;
+; ;
+; Store 80 Bit Temp Real (& POP since only FSTP supported for temp) ;
+; ;
+;*********************************************************************;
+;
+; ES:SI: memory address of 80 bit tempreal
+
+pub TNANorINFST
+ TEST BH,ZROorINF
+ JNZ short TInfST
+
+pub TNANST
+ MVSI2US ; copy mantissa
+ MVSI2US
+ MVSI2US
+ MVSI2US
+ MOV AX,IexpMax ; Set maximum mantissa
+ OR AH,DH ; Overstore proper sign
+ STAX2US
+ POPST
+ RET
+
+pub TInfST
+ XOR AX,AX
+ STAX2US
+ STAX2US
+ STAX2US
+ MOV AX,8000H
+ STAX2US
+ MOV AX,IexpMax ; Set maximum mantissa
+ OR AH,DH ; Overstore proper sign
+ STAX2US
+ POPST
+ RET
+
+pub TSpecialST
+ TEST BH,Special
+ JNZ TNANorINFST
+
+pub TzeroST
+ XOR AX,AX
+ STAX2US
+ STAX2US
+ STAX2US
+ STAX2US
+ STAX2US
+ POPST
+ RET
+
+pub eFSTtemp
+ MOV edi,esi
+ MOV esi,[CURstk]
+
+ MOV AX,Expon[esi] ; Adjust exponent of TOS
+ ADD AX,IexpBias
+ MOV DH,Flag[esi]
+if fastSP
+ TEST DH,Single
+ JZ TD1
+ MOV word ptr MB0[esi],0
+ MOV word ptr MB2[esi],0
+ MOV byte ptr MB4[esi],0
+TD1:
+endif
+ AND DH,Sign ; Mask to sign only
+ OR AH,DH
+ MOV BH,Tag[esi] ; See if it is a special case
+ OR BH,BH
+ JNZ TSpecialST
+
+ MVSI2US ; Move Mantissa
+ MVSI2US
+ MVSI2US
+ MVSI2US
+ STAX2US ; Move Exponent & Sign
+
+ SUB esi,8 ; Reset pointer to TOS
+ POPSTsi
+
+ RET
+
+ProfEnd LSTMP
diff --git a/private/mvdm/wow16/win87em/emmain.asm b/private/mvdm/wow16/win87em/emmain.asm
new file mode 100644
index 000000000..d160479f1
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emmain.asm
@@ -0,0 +1,805 @@
+ page ,132
+ subttl emmain.asm - Main Entry Point and Address Calculation Procedure
+;***
+;emmain.asm - Main Entry Point and Address Calculation Procedure
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Main Entry Point and Address Calculation Procedure
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+;*********************************************************************;
+; ;
+; Main Entry Point and Address Calculation Procedure ;
+; ;
+;*********************************************************************;
+;
+; This routine fetches the 8087 instruction, calculates memory address
+; if necessary into ES:SI and calls a routine to emulate the instruction.
+; Most of the dispatching is done through tables. (see comments in CONST)
+
+
+ProfBegin MAIN
+
+ifdef XENIX
+
+ifdef i386
+LDT_DATA= 02Fh ; UNDONE - 386 emulator data LDT
+else
+LDT_DATA= 037h ; UNDONE - 286 emulator data LDT
+endif ;i386
+
+endif ;XENIX
+
+
+ifdef PROTECT
+; protect mode Segment override case
+
+glb <protSegOvrTab>
+
+protSegOvrTab label word
+
+ dw DSSegOvr ; 11
+ dw ESSegOvr ; 00
+ dw CSSegOvr ; 01
+ dw SSSegOvr ; 10
+endif ;PROTECT
+
+
+ifdef DOS3
+; isolated FWAIT
+
+
+ifdef WINDOWS
+pub FWtrap
+ cld ; this CLD is a nop.
+ iret
+
+else ;not WINDOWS
+pub FWtrap
+ PUSH BP ; fix up isolated FWAIT
+ PUSH DS
+ PUSH SI
+ MOV BP,SP ; Point to stack
+ LDS SI,DWORD PTR 6[BP] ; Fetch ret address,(points to after instruction)
+ DEC SI ; Make DI point to instruction
+ DEC SI
+ MOV 6[BP],SI ; Change ret address to return to instruction
+ mov word ptr [si],0C0h*256+89h ; change interrupt to mov ax,ax
+ POP SI
+ POP DS
+ POP BP
+ IRET ; interrupt return
+
+endif ;not WINDOWS
+; Segment override case
+
+glb <SegOvrTab>
+
+SegOvrTab label word
+
+ dw DSSegOvr
+ dw SSSegOvr
+ dw CSSegOvr
+ dw ESSegOvr
+
+pub SOtrap
+ STI ; re-enable interrupts
+ push ax
+ push es ; set up frame
+ push ds
+ push di
+ push si
+ push dx
+ push cx
+ push bx
+ sub sp,2 ; reserve for regSegOvr
+ push bp
+ mov bp,sp ; set up frame pointer
+ CLD ; clear direction flag forever
+
+; get address mode information, dispatch to address calculation
+
+ MOV DX,BX ; may use original BX to calc address
+ MOV AX,DI ; may use original DI to calc address
+ LDS DI,dword ptr [bp].regIP ; DS:DI is caller's CS:IP
+ INC DI ; increment past operation byte
+ INC DI ; increment past operation byte
+ MOV CX,[DI-2] ; get trap number, opcode (DS=caller CS)
+ mov bx,cx ; upper 2 bits indicate segment override
+ rol bl,1
+ rol bl,1
+ and bx,3
+ rol bx,1
+ jmp SegOvrTab[bx]
+endif ;DOS3
+
+
+pub DSSegOvr ; 00
+ mov es,[bp].regDS ; set ES to EA segment
+ jmp short ESSegOvr
+
+pub CSSegOvr ; 10
+ mov bx,ds ; DS = caller's CS
+ mov es,bx ; set ES to EA segment
+ jmp short ESSegOvr
+
+pub SSSegOvr ; 01
+ mov bx,ss ; SS = caller's SS
+ mov es,bx ; set ES to EA segment
+
+pub ESSegOvr ; 11
+ mov [bp].regSegOvr,es ; save for bp rel EAs
+ jmp short CommonDispatch
+
+
+ifdef PROTECT
+pub protSegOvr
+ mov dx,bx ; may use original BX to calc address
+ mov bl,cl
+
+ .286
+ shr bl,2
+
+ifndef DOS5only
+ .8086
+endif
+ and bx,6 ; bl = (seg+1) and 6
+ inc di ; point to displacement
+ mov cx,[di-2] ; cx = esc 0-7 and opcode
+ jmp protSegOvrTab[bx] ; process appropriate segment override
+
+
+ifdef XENIX
+pub jinstall
+ jmp installemulator
+endif ;XENIX
+
+
+pub protemulation
+ cld ; clear direction flag forever
+
+ifdef XENIX
+
+ push ax ; UNDONE - slow
+ push ds ; UNDONE - slow
+
+ mov ax,LDT_DATA ; load up emulator's data segment
+ mov ds,ax
+ cmp [Einstall],0 ; check if emulator is initialized
+ je jinstall ; no - go install it
+
+pub protemcont
+
+ pop ds ; UNDONE - slow
+ pop ax ; UNDONE - slow
+
+endif ;XENIX
+
+ push ax
+ push es ; set up frame
+ push ds
+ push di
+ push si
+ push dx
+ push cx
+ push bx
+ push ss ; save SegOvr (bp forces SS override)
+ push bp
+ mov bp,sp ; set up frame pointer
+ mov dx,ds ; save original DS for default case
+ mov ax,di ; may use original DI to calc address
+ lds di,dword ptr [bp].regIP ; ds:di = 287 instruction address
+ mov cx,[di] ; cx = esc 0-7 and opcode
+ add di,2 ; point to displacement
+ add cl,28h ; set carry if esc 0-7 (and cl = 0-7)
+ jnc protSegOvr ; no carry - must be segment override
+ mov es,dx ; es = user data segment
+ mov dx,bx ; may use original BX to calc address
+endif ;PROTECT
+
+ifdef DOS3and5
+ jmp short CommonDispatch
+endif ;DOS3and5
+
+
+ifdef DOS3
+; normal entry point for emulator interrupts
+
+ even
+
+pub DStrap
+ STI ; re-enable interrupts
+ push ax
+ push es ; set up frame
+ push ds
+ push di
+ push si
+ push dx
+ push cx
+ push bx
+ push ss ; save SegOvr (bp forces SS override)
+ push bp
+ mov bp,sp ; set up frame pointer
+ mov ax,ds
+ mov es,ax ; ES = caller's DS
+ CLD ; clear direction flag forever
+
+; get address mode information, dispatch to address calculation
+
+ MOV DX,BX ; may use original BX to calc address
+ MOV AX,DI ; may use original DI to calc address
+ LDS DI,dword ptr [bp].regIP ; DS:DI is caller's CS:IP
+ INC DI ; increment past operation byte
+ MOV CX,[DI-2] ; get trap number, opcode (DS=caller CS)
+; Otherwise, CL contains BEGINT + |MF|Arith| so we must unbias it
+ SUB CL,BEGINT
+endif ;DOS3
+
+
+; DS:DI = original CS:IP of displacement field
+; ES = Effective Address segment (original DS if no segment override)
+; DX = original BX
+; AX = original DI
+; SI = original SI
+; CX = (opcode,0-7 from ESC byte)
+; stack = saved register set
+
+pub CommonDispatch
+ ROL CH,1 ; rotate MOD field next to r/m field
+ ROL CH,1
+ MOV BL,CH ; get copy of operation
+ AND BX,1FH ; Mask to MOD and r/m fields
+ SHL BX,1 ; make into word offset
+ JMP EA286Tab[BX]
+
+
+OneByteDisp macro
+ mov al, [di] ;; get one byte displacement
+ cbw ;; sign extend displacement
+ inc di ;; get past displacement byte
+ add si, ax ;; add one byte displacement
+ endm
+
+TwoByteDisp macro
+ add si, [di] ;; add word displacement
+ add di, 2 ;; get past displacement word
+ endm
+
+
+ even
+
+pub BXXI0D
+ MOV SI,DX ; use original BX index value
+ JMP short ADRFIN ; have offset in SI
+
+pub DSDI0D
+ MOV SI,AX ; use alternate index value
+ JMP short ADRFIN ; have offset in SI
+
+ even
+
+pub BPXI1D
+ mov SI,[bp].regBP ; add original BP value
+ mov es,[bp].regSegOvr ; ES = override segment (or SS if none)
+ OneByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BPDI1D
+ MOV SI,AX ; use alternate index value
+pub BPSI1D
+ ADD SI,[bp].regBP ; add original BP value
+ mov es,[bp].regSegOvr ; ES = override segment (or SS if none)
+ OneByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BXSI1D
+ MOV AX,SI ; really will want SI, not DI
+pub BXDI1D
+ ADD DX,AX ; now DX is original BX plus index
+pub BXXI1D
+ MOV AX,DX ; use original BX index value
+pub DSDI1D
+ MOV SI,AX ; use alternate index value
+pub DSSI1D
+ OneByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BPXI2D
+ mov SI,[bp].regBP ; add original BP value
+ mov es,[bp].regSegOvr ; ES = override segment (or SS if none)
+ TwoByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BPDI2D
+ MOV SI,AX ; use alternate index value
+pub BPSI2D
+ ADD SI,[bp].regBP ; add original BP value
+ mov es,[bp].regSegOvr ; ES = override segment (or SS if none)
+ TwoByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BXSI2D
+ MOV AX,SI ; really will want SI, not DI
+pub BXDI2D
+ ADD DX,AX ; now DX is original BX plus index
+pub BXXI2D
+ MOV AX,DX ; use original BX index value
+pub DSDI2D
+ MOV SI,AX ; use alternate index value
+pub DSSI2D
+ TwoByteDisp
+ JMP short ADRFIN
+
+ even
+
+pub BPDI0D
+ MOV SI,AX ; use alternate index value
+pub BPSI0D
+ add si,[bp].regBP ; really will want BP, not BX
+ mov es,[bp].regSegOvr ; ES = override segment (or SS if none)
+ jmp short ADRFIN
+
+ even
+
+pub BXDI0D
+ MOV SI,AX ; si = regDI
+pub BXSI0D
+ add si,dx ; si = regSI+regBX
+ jmp short ADRFIN
+
+ even
+
+pub DSXI2D
+ MOV SI,[DI] ; get two byte displacement
+ INC DI ; get past displacement byte
+ INC DI ; get past displacement byte
+
+pub DSSI0D ; SI = EA (original SI for DSSI0D)
+
+pub ADRFIN
+ MOV [bp].regIP,DI ; final return offset
+
+ifdef LOOK_AHEAD
+ mov bl,[di] ; get byte of next instruction
+endif
+
+ifdef MTHREAD
+ LOADthreadDS ; macro in emthread.asm
+ ; loads thread's DS, trashes AX
+else ;not MTHREAD
+ ifdef standalone
+ xor ax,ax
+ mov ds,ax
+ mov ds,ds:[4*TSKINT+2] ; DS = emulator task data segment
+
+ elseifdef XENIX
+ mov ax,LDT_DATA
+ mov ds,ax
+
+ elseifdef _COM_
+ mov ds, [__EmDataSeg]
+
+ else
+ mov ax, edataBASE
+ mov ds,ax
+ endif
+endif ;not MTHREAD
+
+ifdef LOOK_AHEAD
+ mov [NextOpCode], bl ; save byte of next instruction
+endif
+
+ mov [CURerr],MemoryOperand ; clear current error, set mem. op bit
+
+; At this point ES:SI = memory address, CX = |Op|r/m|MOD|escape|MF|Arith|
+
+ SHR CH,1
+ SHR CH,1 ; Move Op field to BX for Table jump
+ SHR CH,1
+ SHR CH,1
+ MOV BL,CH
+ AND BX,0EH
+
+ TEST CL,1 ; Arith field set?
+ JZ ArithmeticOpMem
+
+pub NonArithOpMem
+ mov eax,offset EMLFINISH
+ push eax
+ jmp NonArithOpMemTab[BX]
+
+ even
+
+pub ArithmeticOpMem
+ PUSH BX ; Save Op while we load the argument
+ MOV BX,CX ; Dispatch on MF
+ AND ebx,6H
+ifdef i386
+ call FLDsdriTab[2*ebx] ; emulate proper load
+else
+ call FLDsdriTab[ebx] ; emulate proper load
+endif
+ POP BX
+
+ mov ax,ds ; ES = DS = task data area
+ mov es,ax
+ MOV SI,[CURstk] ; address top of stack
+ MOV DI,SI
+ ChangeDIfromTOStoNOS
+ MOV [RESULT],DI ; Set up destination Pointer
+
+ JMP short DoArithmeticOpPop
+
+
+ even
+
+pub NoEffectiveAddress ; Either Register op or Miscellaneous
+
+ MOV [bp].regIP,DI ; final return offset
+
+ifdef LOOK_AHEAD
+ mov bl, [di] ; get first byte of next instruction.
+endif
+
+ifdef MTHREAD
+ LOADthreadDS ; macro in emthread.asm
+ ; loads thread's DS; trashes AX
+ mov ax,ds
+ mov es,ax ; DS = ES = per-thread em. data area
+ xor ax,ax
+
+else ;not MTHREAD
+
+ xor ax,ax
+
+ ifdef standalone
+ mov ds,ax
+ mov di,ds:[4*TSKINT+2] ; DI = emulator task data segment
+
+ elseifdef XENIX
+ mov di,LDT_DATA
+
+ elseifdef _COM_
+ mov di, [__EmDataSeg]
+
+ else
+ mov di, edataBASE
+ endif
+
+ mov ds,di ; di = emulator data segment
+ mov es,di ; ax = 0
+endif ;not MTHREAD
+
+; ES = emulator data segment
+; DS = emulator data segment
+; AX = 0
+
+ifdef LOOK_AHEAD
+ mov [NextOpCode], bl ; save first byte of next instruction
+endif
+
+ mov [CURerr],ax ; clear current error, memory op bit
+
+; CX = |Op|r/m|MOD|escape|MF|Arith|
+
+ MOV BL,CH
+ SHR BL,1 ; Mov Op field to BX for jump
+ SHR BL,1
+ SHR BL,1
+ SHR BL,1
+ AND BX,0EH
+
+ TEST CL,1 ; Arith field set?
+ JZ ArithmeticOpReg
+
+pub NonArithOpReg
+ CALL NonArithOpRegTab[BX]
+ JMP EMLFINISH
+
+; For register arithmetic operations, one operand is always the stack top.
+; The r/m field of the instruction is used to determine the address of
+; the other operand (ST(0) - ST(7))
+; CX = xxxRRRxxxxxxxxxx (x is don't care, RRR is relative register # 0-7)
+
+ even
+
+pub ArithmeticOpReg
+
+ call RegAddr ;di <= address of 2nd operand
+ ;carry set if invalid register
+ jc InvalidOperand ;no, invalid operand, don't do operation
+
+ MOV [RESULT],SI ; Set destination to TOS
+ TEST CL,04H ; Unless Dest bit is set
+ JZ DestIsSet ; in which case
+ MOV [RESULT],DI ; Set destination to DI
+
+pub DestIsSet
+ ; Need to Toggle Reverse bit for DIV or SUB
+ TEST BL,08H ; OP = 1xx for DIV and SUB; BX = |0000|OP|O|
+ JZ SetUpPop
+ XOR BL,02H ; Toggle Reverse bit
+
+pub SetUpPop
+ TEST CL,02H
+ JZ DoArithmeticOpNoPop
+
+pub DoArithmeticOpPop
+ CALL ArithmeticOpTab[BX]
+ mov esi,[CURstk]
+ cmp esi,[BASstk] ; 15 was it last register in the chunk ?
+ jz short AOPstovr ; 16 yes, overflow
+AOPstok:
+ sub esi,Reg87Len ; 4 decrement SI to previous register
+ mov [CURstk],esi ; 15 set current top of stack
+ JMP short EMLFINISH
+
+AOPstovr:
+ call UnderStk ; stack underflow error
+ jmp AOPstok
+
+ even
+
+pub DoArithmeticOpNoPop
+ mov eax,offset EMLFINISH
+ push eax
+ jmp ArithmeticOpTab[BX]
+
+
+;*** InvalidOperand - register operand does not exist
+;
+; RETURNS
+; sets Stack Underflow and Invalid bits in [CURerr]
+;
+; DESCRIPTION
+; a reference was made to a register that does not
+; exist on the stack. Set error bits and exit.
+
+pub InvalidOperand
+ call UnderStk ;indicate stack underflow error
+ or [CURerr],Invalid ;indicate invalid operand
+ jmp short EMLFINISH ;don't execute instruction
+
+;*** RegAddr - compute register address
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; r/m = register whose address is to be computed
+;
+; RETURNS
+; SI = address of top of stack
+; DI = address of requested register
+; PSW.C set if register is not valid
+; PSW.C reset if register is valid
+;
+; DESCRIPTION
+; multiply register number by 12 and subtract this from
+; [CURstk] (the address of TOS) to compute address of
+; register referenced by r/m.
+;
+; REGISTERS
+; modifies dx
+
+pub RegAddr
+ MOV SI,[CURstk] ; address top of stack
+ MOV DI,SI
+;set up address of 2nd operand based on r/m field of instruction
+ mov dl,ch ; dl <== byte containing reg#
+ and dl,01ch ; mask all but r/m field
+
+; Since r/m field contains the relative reg # in bits 2-4 of dl,
+; and bits 0-1 of dl are zero, dl now contains 4*(reg #). To compute
+; the memory location of this register, calculate 12*(reg #) and
+; subtract this from di, which contains the address of the TOS. reg #
+; is multiplied by 12 because that is the number of bytes in each stack
+; entry.
+ mov dh,dl ; dh = dl = 4*(reg #)
+ shl dh,1 ; dh = 2*dh = 8*(reg #)
+ add dl,dh ; dl = 8*(reg #) + 4*(reg #) = 12*(reg #)
+ xor dh,dh ; zero out high byte of DX
+ sub di,dx ; di is address of second operand
+ cmp di,[BASstk] ; is register in range?
+ clc ; assume valid register
+ jg $+3 ; valid - skip next instruction
+ cmc ; set carry to indicate invalid register
+ ret
+
+
+pub CallUnused
+ CALL UNUSED ; Treat as unimpleminted
+ jmp EMLFINISH
+
+
+; out of line returns from emulator
+
+
+pub SawException
+ pop bp ; restore registers
+ add sp,2 ; toss regSegOvr
+ pop bx
+ pop cx
+ pop dx
+ pop si
+ pop di
+ pop ds
+ pop es
+
+pub ExceptionsEmulator
+ JMP CommonExceptions
+
+
+ifdef LOOK_AHEAD
+
+pub NoPipeLine
+
+ pop bp ; restore registers
+ add sp,2 ; toss regSegOvr
+ pop bx
+ pop cx
+ pop dx
+ pop si
+ pop di
+ pop ds
+ pop es
+
+pub errret
+ error_return noerror ; common exit sequence
+
+endif ;LOOK_AHEAD
+
+; return from routine; restore registers and return
+
+
+ even
+
+pub EMLFINISH
+
+ ; check for errors
+
+ MOV AX,[CURerr] ; fetch errors
+ or [UserStatusWord],ax ; save all exception errors
+ OR [SWerr],AL ; set errors in sticky error flag
+ NOT AL ; make a zero mean an error
+ MOV bh,byte ptr [UserControlWord] ; get user's IEEE control word
+ OR bh,0C2H ; mask reserved, IEM and denormal bits
+ AND bh,03FH ; unmask invalid instruction,
+ ; stack overflow.
+ OR AL,bh ; mask for IEEE exceptions
+ NOT AL ; make a one mean an error
+ TEST AX,0FFFFh-MemoryOperand ; test for errors to report
+
+ jnz SawException ; goto error handler
+
+ifndef LOOK_AHEAD
+ pop bp ; restore registers
+ add sp,2 ; toss regSegOvr
+ pop bx
+ pop cx
+ pop dx
+ pop si
+ pop di
+ pop ds
+ pop es
+
+pub errret
+ error_return noerror ; common exit sequence
+
+else ;LOOK_AHEAD
+
+
+ifdef DOS3and5
+ jmp [LookAheadRoutine]
+endif
+
+
+ifdef DOS3
+
+pub DOSLookAhead
+ cmp [NextOpcode], fINT ; Quick check. If first byte isn't
+ jne NoPipeLine ; an int instruction then exit.
+
+ ; can stay in the emulator - set up registers for CommonDispatch
+
+ mov bp, sp ; set up frame pointer
+ lds di, dword ptr [bp].regIP ; DS:DI = address of next instruction
+ add di, 3 ; skip 3 bytes to displacement field
+ mov cx, [di-2] ; CX = (opcode byte,0-7 from ESC)
+ sub cl, BEGINT
+
+ cmp cl, 7 ; Can't handle segment overrides with
+ ja NoPipeLine ; pipe lining.
+
+ mov ax, [bp].regDI ; ax = original di
+ mov dx, [bp].regBX ; dx = original bx
+ mov si, [bp].regSI ; si = original si
+ mov es, [bp].regDS ; es = original ds (no segment override)
+ mov [bp].regSegOvr, ss ; reset override segment
+
+ rol ch, 1 ; rotate MOD field next to r/m field
+ rol ch, 1
+ mov bl, ch ; get copy of operation
+ and bx, 1fh ; Mask to MOD and r/m fields
+ shl bx, 1 ; make into word offset
+ jmp EA286Tab[bx]
+
+endif ;DOS3
+
+
+ifdef PROTECT
+
+pub ProtLookAhead
+ mov cl, [NextOpcode]
+
+ cmp cl, fFWAIT
+ je CheckNextByte
+
+ cmp cl, iNOP
+ je CheckNextByte
+
+ xor cl, 20h ; See if this is a floating point instruction.
+ cmp cl, 0f8h
+jbNoPipeLine:
+ jb NoPipeLine
+
+ mov bp, sp ; set up frame pointer
+ lds di, dword ptr [bp].regIP ; ds:di = address of next instruction
+
+ jmp short CanDoPipeLine
+
+pub CheckNextByte
+ mov bp, sp ; set up frame pointer
+ lds di, dword ptr [bp].regIP ; ds:di = address of next instruction
+ inc di ; next instruction was NOP or FWAIT
+
+ mov cl, [di]
+ xor cl, 20h
+ cmp cl, 0f8h
+ jb jbNoPipeLine
+
+pub CanDoPipeLine
+ mov ch, [di+1] ; we already have first byte of next
+ add di, 2 ; instruction in cl
+
+ add cl, 8h ; clear out what's left of escape
+
+ mov ax, [bp].regDI ; ax = original di
+ mov dx, [bp].regBX ; dx = original bx
+ mov si, [bp].regSI ; si = original si
+ mov es, [bp].regDS ; es = original ds (no segment override)
+ mov [bp].regSegOvr, ss ; reset override segment
+
+ rol ch, 1 ; rotate MOD field next to r/m field
+ rol ch, 1
+ mov bl, ch ; get copy of operation
+ and bx, 1fh ; Mask to MOD and r/m fields
+ shl bx, 1 ; make into word offset
+ jmp EA286Tab[bx]
+
+endif ;PROTECT
+
+
+
+endif ;LOOK_AHEAD
+
+
+ProfEnd MAIN
diff --git a/private/mvdm/wow16/win87em/emnew.asm b/private/mvdm/wow16/win87em/emnew.asm
new file mode 100644
index 000000000..79eb199a9
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emnew.asm
@@ -0,0 +1,165 @@
+ page ,132
+ subttl emnew - emulator new instruction support
+;***
+;emnew.asm - emulator new instruction support
+;
+; Copyright (c) 1985-89, Microsoft Corporation
+;
+;Purpose:
+; Emulator new instruction support
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+ProfBegin NEW
+
+;*** eFFREE - emulate FFREE ST(i)
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; r/m is register to free
+;
+; DESCRIPTION
+; This routine assumes that the register being freed is
+; either at the top or the bottom of the floating point
+; stack. This is consistent with its use by the cmerge
+; compiler. If ST(i) is valid, all registers from ST(0)
+; to ST(i-1) are moved down one position in the stack,
+; eliminating ST(i). [CURstk] is moved to the new location
+; of ST(0).
+;
+; REGISTERS
+; modifies si,di,dx
+
+pub eFFREE
+ call RegAddr ; di <== address of ST(i)
+ ; carry set if invalid register
+ jnc short validSTi ; ok, continue
+ pop edx ; toss return address
+ jmp InvalidOperand ; set stack underflow/invalid and exit
+
+validSTi:
+ mov esi,edi ; si <== address of ST(i)
+MovLoop:
+ add esi,Reg87Len ; si <== address of ST(i-1)
+ cmp esi,[CURstk] ; source addr <= top of stack?
+ jg short SetCURstk ; set [CURstk] and exit
+ call MOVRQQ ; ST(j) <== ST(j-1)
+ add edi,Reg87Len ; move dest ptr to next stack entry
+ jmp short MovLoop ; continue moving register entries
+
+SetCURstk:
+ sub edi,Reg87Len ; di points to new location of ST(0)
+ mov [CURstk],edi ; set new top of stack ptr
+ ret
+
+;*** eFXCHG - emulate FXCH ST(i)
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; r/m is the source register
+;
+; DESCRIPTION
+; exchange ST(i) and ST(0) as follows:
+; temp <== ST(0); ST(0) <== ST(i); ST(i) <== temp
+; indicate stack underflow error if ST(i) does not exist
+;
+; REGISTERS
+; modifies ax,es,si,di,dx,cx,bx
+
+pub eFXCHG
+ test cx,01c00h ;test for ST(i) == ST(0)
+ jz short fxchRet ;fxch ST(0),ST(0) is a nop
+ mov ax,ds
+ mov es,ax ;set es == ds
+ call RegAddr ;di points to ST(i), si points to ST(0)
+ ;carry set if invalid register
+ jnc short okReg ;ok, continue
+ pop edx ; toss return address
+ jmp InvalidOperand ;give stack underflow/invalid error
+
+okReg:
+ mov ecx,6 ;loop counter
+WordSwap: ;exchange a word of ST(0) and ST(i)
+ mov ax,[esi] ;ax <== [si]
+ mov bx,[edi] ;bx <== [di]
+ stos word ptr es:[edi] ;[(di++)] <== ax
+ mov [esi],bx ;[si] <== bx
+ inc esi
+ inc esi ;si++
+ loop WordSwap ;exchange the six words of ST(0), ST(i)
+fxchRet:
+ ret
+
+;*** eFLDreg - emulate FLD ST(i)
+;
+; ARGUMENTS
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; r/m is the source register
+;
+; DESCRIPTION
+; allocate new ST(0) and copy ST(i) into it
+; indicate stack underflow error if ST(i) does not exist
+;
+; REGISTERS
+; modifies ax,di,si
+
+pub eFLDreg
+ call RegAddr ;di <== address of ST(i), si points to ST(0)
+ ;carry set if invalid register
+ jnc short okSTi ;yes, continue
+ pop edx ; toss return address
+ jmp InvalidOperand ;stack underflow, invalid operation
+
+okSTi:
+ PUSHST ;allocate new TOS
+ mov ax,ds
+ mov es,ax ;set ES == DS
+ xchg esi,edi ;si = source , di = destination
+ call MOVRQQ ;move ST(i) to new ST(0)
+ ret
+
+;*** eFST_Preg - emulate FST ST(i) and FSTP ST(i)
+;
+; ARGUMENTS
+; AX = 0 if FST ST(i)
+; 1 if FSTP ST(i)
+; CX = |Op|r/m|MOD|esc|MF|Arith|
+; (except bit 2 of cl is toggled)
+; r/m is the source register
+;
+; DESCRIPTION
+; move contents of ST(0) to ST(i). If ax <> 0 pop stack
+; after transfer.
+;
+; REGISTERS
+; modifies si,di,dx
+
+pub eFST_Preg
+ test cx,01c0h ;test for ST(i) == ST(0)
+ jz short FSTRet ;pop stack and return
+ call RegAddr ;di <== address of ST(i), si points to ST(0)
+ ;carry set if invalid register
+ jnc short ValidReg ;yes, continue
+ pop edx ; toss return address
+ jmp InvalidOperand ;no, indicate stack underflow/invalid
+
+ValidReg:
+ mov dx,ds
+ mov es,dx ;set es == ds
+ call MOVRQQ ;ST(i) <== ST(0)
+
+FSTRet:
+ or ax,ax ;FST ST(i) or FSTP ST(i)?
+ jz short NoPOP ;FST ST(i) - don't pop the stack
+ POPST ;pop the 8087 stack
+NoPOP:
+ ret
+
+
+ProfEnd NEW
diff --git a/private/mvdm/wow16/win87em/emnormal.asm b/private/mvdm/wow16/win87em/emnormal.asm
new file mode 100644
index 000000000..8358f30b6
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emnormal.asm
@@ -0,0 +1,374 @@
+ page ,132
+ subttl emnormal.asm - Normalize and Round
+;***
+;emnormal.asm - Normalize and Round
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Normalize and Round.
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin NORMAL
+
+;------------------------------------------;
+; ;
+; Double Precision Normalize and Round ;
+; ;
+;------------------------------------------;
+
+ even
+
+pub NODRQQ
+; Normalize the double precision number
+; All arithmetic operations exit through NODRQQ or RNDR7Q
+; Mantissa in DI:BX:CX:DX:BP, Exponent in SI, sign on Stack, old BP on Stack
+
+ MOV AL,4 ; Maximum of 4 word shifts, sign in AH(6)
+pub DNOR
+ OR DI,DI ; See if any bits on in high word
+ JNZ short HIBYT ; If so, go check high byte for zero
+ SUB SI,16 ; Drop exponent by shift count
+ DEC AL ; Bump count
+ JZ short NORZERO
+ MOV DI,BX
+ MOV BX,CX
+ MOV CX,DX
+ MOV DX,BP
+ XOR BP,BP
+ JMP DNOR
+
+pub NORZERO ; Here if result after normalization is zero
+ MOV esi,offset IEEEzero
+ MOV edi,[RESULT]
+ POP eax ; Throw out sign on stack
+ POP ebp ; Restore Old BP
+ JMP csMOVRQQ ; Move IEEE zero to TOS and return
+
+ even
+
+pub HIBYT
+ TEST DI,0FF00H ; See if high byte is zero
+ JNZ short NORMSHF2
+ SUB SI,8 ; Drop exponent by shift amount
+
+pub DN2
+ XCHG AX,DI
+ MOV AH,AL
+ MOV AL,BH
+ MOV BH,BL
+ MOV BL,CH
+ MOV CH,CL
+ MOV CL,DH
+ MOV DH,DL
+ XCHG AX,DI
+ XCHG AX,BP
+ MOV DL,AH
+ MOV AH,AL
+ XOR AL,AL
+ XCHG AX,BP
+
+ even
+
+pub NORMSHF2
+ TEST DI,8000H ; Normalization complete?
+ JNZ ROUND ; Normalization complete
+
+pub NORMLP ; Have to shift left
+ DEC SI ; Account for shift in exponent
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+ RCL DI,1
+ TEST DI,8000H ; Check for normalized result
+ JZ NORMLP ; Bit will be set when normalized
+ JMP short ROUND
+
+
+pub ROUND24 ; Round to 24 bits
+ OR DX,BP ; See if result fits exactly in 24 bits
+ OR CX,DX
+ OR CL,CH
+ MOV CH,BL
+ OR CX,CX
+ JZ short JEXACT
+ OR [CURerr],Precision ; Set flag on inexact result
+ SHR AL,1
+ JC short DOWNorCHOP24
+ SHR AL,1
+ JC short UP24
+
+pub NEAR24 ; Round to nearest or Even
+ CMP CX,8000H
+ JA short INC24 ; Remainder Bigger then .5 so Bump up
+ JB short MSK24 ; Remainder Less then .5 so Mask off
+ TEST BH,1 ; Remainder = .5 so see if even
+ JZ short MSK24 ; When even Mask
+ JMP short INC24 ; When odd Bump up
+
+pub UP24
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short MSK24 ; Trunc neg numbers to move toward + Inf
+ JMP short INC24
+
+pub DOWNorCHOP24
+ SHR AL,1
+ JC short CHOP24
+
+pub DOWN24
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short INC24
+ JMP short MSK24 ; Trunc Pos numbers to move toward - Inf
+
+pub INC24
+ ADD BH,1
+ ADC DI,0
+ JNC short MSK24
+ MOV DI,8000H ; Number overflowed from 1,111... to 10,000...
+ INC SI ; Bump up Exponent
+
+pub CHOP24
+MSK24: ; Mask off insignificant bits
+ XOR BP,BP
+ MOV DX,BP
+ MOV CX,DX
+ MOV BL,CL
+pub JEXACT
+ JMP EXACT
+
+
+ even
+
+pub NORMSHF ; from multiply only
+ TEST DI,8000H ; Normalization complete?
+ JNZ ROUND ; Normalization complete
+
+ DEC SI ; Account for shift in exponent
+ SHL BP,1
+ RCL DX,1
+ RCL CX,1
+ RCL BX,1
+ RCL DI,1
+
+ even
+ ; mantissa in DI:BX:CX:DX:BP
+
+pub ROUND ; Drop into ROUND when normalized
+ MOV AL,[CWcntl] ; Pick up hi byte of control word
+ SHR AL,1 ; Which has Rounding & Precision Control
+ jnc short ROUND53
+
+pub ROUND64 ; Round to 64 bits
+ SHR AL,1 ; Remove other bit of Precision control
+ OR BP,BP ; See if result fits exactly in 64 bits
+ JZ short EXACT
+ OR [CURerr],Precision ; Set flag on inexact result
+ SHR AL,1
+ JC short DOWNorCHOP64
+ SHR AL,1
+ JC short UP64
+
+pub NEAR64 ; Round to nearest or Even
+ CMP BP,8000H
+ JA short INC64 ; Remainder Bigger then .5 so Bump up
+ JB short MSK64 ; Remainder Less then .5 so Mask off
+ TEST DL,1 ; Remainder = .5 so see if even
+ JZ short MSK64 ; When even Mask
+
+pub INC64
+ XOR BP,BP ; Need a 0
+ ADD DX,1
+ ADC CX,BP
+ ADC BX,BP
+ ADC DI,BP
+ JNC short EXACT
+
+ MOV DI,8000H ; Number overflowed from 1,111... to 10,000...
+ INC SI ; Bump up Exponent
+
+ even
+
+CHOP64:
+MSK64: ; Mask off insignificant bits
+
+pub EXACT
+ MOV eax,[RESULT]
+ XCHG eax,edi
+ MOV MB0[edi],DX ; Save Mantissa
+ MOV MB2[edi],CX
+ MOV MB4[edi],BX
+ MOV MB6[edi],AX
+ POP eax ; Fetch Sign
+ POP ebp ; Fetch Old BP
+ AND AH,Sign ; Mask off single precision
+ MOV Flag[edi],AH
+
+ CMP SI,IexpMax - IexpBias ; Test for overflow
+ JGE short jOVER
+ CMP SI,IexpMin - IexpBias ; Test for Underflow
+ JLE short UNDER
+
+pub NORTAG
+ MOV Expon[edi],SI
+ MOV byte ptr Tag[edi],0 ; Number is in range and on TOS so ret
+ RET
+
+jOVER: jmp OVER
+
+pub UP64
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short MSK64 ; Trunc neg numbers to move toward + Inf
+ JMP short INC64
+
+pub DOWNorCHOP64
+ SHR AL,1
+ JC short CHOP64
+
+pub DOWN64
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short INC64
+ JMP short MSK64 ; Trunc Pos numbers to move toward - Inf
+
+
+jROUND24:
+ jmp ROUND24
+
+pub ROUND53 ; Round to 53 bits (or 24)
+ SHR AL,1
+ JNC short jROUND24
+
+ XCHG BP,AX ; See if result fits exactly in 53 bits
+ OR AL,AH
+ OR AL,DL
+ MOV AH,DH
+ AND AH,007H
+ AND DH,0F8H
+ XCHG BP,AX
+ OR BP,BP
+ JZ EXACT
+ OR [CURerr],Precision ; Set flag on inexact result
+ SHR AL,1
+ JC short DOWNorCHOP53
+ SHR AL,1
+ JC short UP53
+
+pub NEAR53 ; Round to nearest or Even
+ CMP BP,0400H
+ JA short INC53 ; Remainder Bigger then .5 so Bump up
+ JB short MSK53 ; Remainder Less then .5 so Mask off
+ TEST DH,08H ; Remainder = .5 so see if even
+ JZ short MSK53 ; When even Mask
+ JMP short INC53 ; When odd Bump up
+
+
+pub UNDER
+MUNDER: ; Masked Underflow
+ MOV esi,offset IEEEzero
+ CALL csMOVRQQ
+ MOV Flag[edi],AH ; Overstore correct sign
+ RET
+
+
+pub UP53
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short MSK53 ; Trunc neg numbers to move toward + Inf
+ JMP short INC53
+
+pub DOWNorCHOP53
+ SHR AL,1
+ JC short CHOP53
+
+pub DOWN53
+ POP eax ; Get the sign
+ PUSH eax
+ SHL AH,1
+ JC short INC53
+ JMP short MSK53 ; Trunc Pos numbers to move toward - Inf
+
+pub INC53
+ XOR BP,BP ; Need a 0
+ ADD DH,08H
+ ADC CX,BP
+ ADC BX,BP
+ ADC DI,BP
+ JNC short MSK53
+
+ MOV DI,8000H ; Number overflowed from 1,111... to 10,000...
+ INC SI ; Bump up Exponent
+
+pub CHOP53
+MSK53: ; Mask off insignificant bits
+ XOR BP,BP
+ XOR DL,DL ; Note: The garbage in DH was masked off at ROUND53
+ JMP EXACT
+
+PAGE
+
+pub OVER ; Here if number overflowed
+MOVER: ; The masked response to rounding depends on whether rounding
+ ; is directed or not. If it is then Overflow flag is not set
+ ; but precision is. Also the result is set to Inf or Biggest
+ ; If rounding is not directed then Overflow is set and result
+ ; is set to Inf.
+
+ OR [CURerr],Overflow
+ MOV AL,[CWcntl]
+ SHR AL,1
+ SHR AL,1
+ SHR AL,1
+ JC short MOvDNorCHP
+
+ SHR AL,1
+ JC short MOvUP
+
+MOvNEAR: ; Masked Overflow Near Rounding
+
+pub SignedInfinity ; Return signed infinity
+
+ MOV esi,offset IEEEinfinity
+ CALL csMOVRQQ
+ MOV Flag[edi],AH ; Overstore the proper sign
+ RET
+
+pub MOvDNorCHP
+ SHR AL,1
+ JC short MOvCHOP
+
+pub MOvDOWN ; Masked Overflow Down Rounding
+ OR [CURerr],Precision
+ TEST AH,Sign ; Positive goes to biggest
+ JNZ short SignedInfinity
+
+MOvCHOP: ; Masked Overflow Chop Rounding
+pub SignedBiggest
+ MOV esi,offset IEEEbiggest
+ CALL csMOVRQQ
+ MOV Flag[edi],AH ; Overstore the proper sign
+ RET
+
+pub MOvUP ; Masked Overflow Up Rounding
+ OR [CURerr],Precision
+ TEST AH,Sign ; Negative goes to biggest
+ JZ short SignedInfinity
+ JMP SignedBiggest
+
+ProfEnd NORMAL
diff --git a/private/mvdm/wow16/win87em/emoem.asm b/private/mvdm/wow16/win87em/emoem.asm
new file mode 100644
index 000000000..b73aeb2f7
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoem.asm
@@ -0,0 +1,536 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-92
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 80x87
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287/80387 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/80287/80387 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 80x87 interrupt handler
+; __FPTERMINATE87 deinstall 80x87 interrupt handler
+; __fpintreset reset OEM hardware if an 80x87 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287/80387 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 80x87 exception handler.
+;
+; For machines using 2 8259's to handle the 80x87 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 80x87
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 80x87 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 80x87 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 80x87
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 80x87 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+aoldIMR db 0 ; 1st 8259 original IMR value
+boldIMR db 0 ; 2nd 8259 original IMR value
+
+endif ;OEM
+
+statwd dw 0 ; Temporary for status word
+oldvec dd 0 ; Old value in 80x87 exception interrupt vector
+ifndef _NOCTRLC
+ctlc dd 0 ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 80x87.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 80x87 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [oldvec]
+ or ax, word ptr [oldvec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ mov dx,offset __fpinterrupt87 ; Load DX with 80x87 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 80x87 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 80x87 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[oldvec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 80x87 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 80x87 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 80x87
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+__fpinterrupt87:
+assume ds:nothing
+ nop
+ fnstsw [statwd] ; Store out exceptions
+ push cx ; waste time
+ mov cx,3
+self:
+ loop self
+ pop cx
+ test byte ptr [statwd],PENDINGBIT ; Test for 80x87 interrupt
+ jz not87int ; Not an 80x87 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 80x87 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 80x87 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ jmp [oldvec] ; We should never return from here.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 80x87 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [oldvec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[oldvec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoem.src b/private/mvdm/wow16/win87em/emoem.src
new file mode 100644
index 000000000..7348c8084
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoem.src
@@ -0,0 +1,448 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-92
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 80x87
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287/80387 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/80287/80387 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 80x87 interrupt handler
+; __FPTERMINATE87 deinstall 80x87 interrupt handler
+; __fpintreset reset OEM hardware if an 80x87 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287/80387 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ CTLCVEC EQU 23h
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+
+
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 80x87 exception handler.
+;
+; For machines using 2 8259's to handle the 80x87 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 80x87
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 80x87 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 80x87 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 80x87
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 80x87 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+aoldIMR db 0 ; 1st 8259 original IMR value
+boldIMR db 0 ; 2nd 8259 original IMR value
+
+endif ;OEM
+
+statwd dw 0 ; Temporary for status word
+oldvec dd 0 ; Old value in 80x87 exception interrupt vector
+ctlc dd 0 ; Old value of Control-C vector (INT 23h)
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 80x87.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 80x87 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [oldvec]
+ or ax, word ptr [oldvec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ mov dx,offset __fpinterrupt87 ; Load DX with 80x87 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+
+ifdef OEM
+
+; set up 8259's so that 80x87 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 80x87 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[oldvec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 80x87 exception handling on Control-C
+
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+
+page
+; __fpinterrupt87
+;
+; This is the 80x87 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 80x87
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+__fpinterrupt87:
+assume ds:nothing
+ nop
+ fnstsw [statwd] ; Store out exceptions
+ push cx ; waste time
+ mov cx,3
+self:
+ loop self
+ pop cx
+ test byte ptr [statwd],PENDINGBIT ; Test for 80x87 interrupt
+ jz not87int ; Not an 80x87 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 80x87 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 80x87 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ jmp [oldvec] ; We should never return from here.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemqb.asm b/private/mvdm/wow16/win87em/emoemqb.asm
new file mode 100644
index 000000000..12af518d8
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemqb.asm
@@ -0,0 +1,570 @@
+;
+;
+; Copyright (C) Microsoft Corporation, 1987
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;
+ page ,132
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft Quick BASIC 4.0 and later
+; Microsoft Quick BASIC (KANJI) 4.0 and later
+; Microsoft BASCOM 3.0
+; Microsoft BASCOMK 3.0
+; Microsoft BASCOM/2
+; Microsoft BASCOMK/2
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; This instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; For QuickBASIC, assemble as follows:
+;
+; masm -D_QB -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+ifndef _QB
+ _HOOK_CTRLC=1
+endif
+
+ifdef _HOOK_CTRLC
+if1
+ %out Non-QB version. Hooks Ctrl-C. Hooks INT 75h.
+endif
+else
+if1
+ %out QB version. Doesn't hook Ctrl-C. Hooks INT 75h.
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifdef _HOOK_CTRLC
+ CTLCVEC EQU 23h
+endif ;_HOOK_CTRLC
+
+EMULATOR_DATA segment public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+aoldIMR db 0 ; 1st 8259 original IMR value
+boldIMR db 0 ; 2nd 8259 original IMR value
+
+endif ;OEM
+
+statwd dw 0 ; Temporary for status word
+oldvec dd 0 ; Old value in 8087 exception interrupt vector
+ifdef _HOOK_CTRLC
+ctlc dd 0 ; Old value of Control-C vector (INT 23h)
+endif ;_HOOK_CTRLC
+ifndef OEM
+oldvec75 dd 0 ; Old value INT 75H interrupt vector
+INT75FLAGS DW 0 ; flags at INT 75 time
+INT75CS DW 0 ; CS at INT 75 time
+INT75IP DW 0 ; IP at INT 75 time
+INT75VEC DW OFFSET FPREALINT2 ; place INT 75 IRETs to
+endif ;OEM
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+ int OPSYS ; Call operating system.
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+else
+ mov ax,GETVECOP shl 8 + 75H ; get interrupt vector 75H
+ int OPSYS ; Call operating system.
+ mov word ptr [oldvec75],bx ; Squirrel away old vector.
+ mov word ptr [oldvec75+2],es;
+
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+ int OPSYS ; Call operating system.
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+endif ;OEM
+
+; Have operating system install interrupt vectors.
+
+ifdef OEM
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+ int OPSYS ; Install vector.
+else
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+ int OPSYS ; Install vector.
+
+ mov dx,offset __fpinterrupt75 ; Load DX with 8087 interrupt handler.
+ mov ax,SETVECOP shl 8 + 75H ; set interrupt vector 75
+ int OPSYS ; Install vector.
+endif ;OEM
+
+; Intercept Control-C vector to guarentee cleanup
+
+ifdef _HOOK_CTRLC ;
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_HOOK_CTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+ lds dx,[oldvec]
+ int OPSYS
+else
+ mov ax,SETVECOP shl 8 + 2
+ lds dx,[oldvec]
+ int OPSYS
+
+ mov ax,SETVECOP shl 8 + 75H ; restore int 75
+ lds dx,[oldvec75] ;
+ int OPSYS ;
+endif ;OEM
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+ifdef _HOOK_CTRLC
+; Forced cleanup of 8087 exception handling on Control-C
+
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_HOOK_CTRLC
+
+page
+;
+; __fpinterrupt75
+;
+; This is the "real" 80x87 interrupt routine for AT's and clones.
+; Entire routine added [2].
+;
+; We hook INT 75 in order to work around a DOS nuance that otherwise causes the
+; exception handler to get executed with the wrong stack segment.
+;
+; In PC's, a math exception is a simple INT 2, which since we hook, we recieve
+; unobstructed. On AT's, an INT 75H is generated, which is normally trapped by
+; the BIOS, which performs some hardware magic, and then executes an INT 2
+; instruction to simulate the PC's behaviour. Hooking INT 2 alone is sufficient
+; to handle these two cases.
+;
+; In MS-DOS (and PC-DOS) versions 3.2x, a stack swapping scheme is employed in
+; which the DOS actually allocates a new SS:SP before executing the interrupt
+; handler. If we do not hook INT 75H, then it gets a new SS:SP, and executes
+; the INT 2 with that stack, and we cannot look back on the stack for our
+; context, nor can we really know anything about the stack at the time of the
+; exception.
+;
+; The process used to over come this problem is, essentially, to allow the
+; INT 75H to execute, including it's embedded INT 2, but to do nothing in that
+; INT 2. We fake the INT 75H return, though, such that it returns to us, (with
+; the right stack to boot), and we can continue to process the exception.
+;
+; The steps invoved:
+;
+; 1) Hook BOTH INT 2 and INT 75H
+;
+; 2) On an INT 75, save the CS, IP and FLAGS of the return address, and REPLACE
+; THEM with values that will cause the INT 75H's IRET to return step 5,
+; below.
+;
+; 3) Just jump to the previous INT 75H handler.
+;
+; 4) On the subsequent INT 2, IF there is a CS as saved in step 1, then do
+; nothing. Just IRET. If there is not saved CS, then we have a plain old
+; INT 2 (running on an XT, most likely), and we just go to step 6.
+;
+; 5) On return from the INT 75H, we have the SS:SP at the time of the
+; exception. Just push the previously saved FLAGS, CS and IP of the
+; exception, clear the saved CS, and fall into....
+;
+; 6) A normal INT 2 handler.
+;
+ifndef OEM ;
+__fpinterrupt75:
+ASSUME DS:NOTHING
+
+ POP CS:[INT75IP] ;Squirel away exception address
+ POP CS:[INT75CS]
+ POP CS:[INT75FLAGS]
+ PUSHF ;Set up INT 75 to return to our code
+ PUSH CS
+ PUSH CS:[INT75VEC]
+ JMP [oldvec75] ;And execute original INT 75H
+endif ; ifndef OEM
+;
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+__fpinterrupt87:
+assume ds:nothing
+
+ nop
+ fnstsw [statwd] ; Store out exceptions
+ifndef OEM ;
+ TEST CS:[INT75CS],-1 ; has INT 75 ocurred?
+ JZ FPWASINT2 ; jump if not
+ IRET ; just return to original INT 75 handler
+
+FPREALINT2: ; INT 75 IRETs here
+ PUSH CS:[INT75FLAGS] ; fake up original exception
+ PUSH CS:[INT75CS] ;
+ PUSH CS:[INT75IP] ;
+ MOV CS:[INT75CS],0 ; and clear the INT75 occurred flag.
+
+FPWASINT2: ;
+endif ; ifndef OEM
+
+ push cx ; waste time
+ mov cx,3
+self:
+ loop self
+ pop cx
+ test byte ptr [statwd],PENDINGBIT ; Test for 8087 interrupt
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jz done8087 ; if not then return
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+else ;
+ iret ;
+endif ;OEM
+
+not87int:
+ jmp [oldvec] ; We should never return from here.
+
+
+ifdef OEM
+
+done8087:
+ iret
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemqp.asm b/private/mvdm/wow16/win87em/emoemqp.asm
new file mode 100644
index 000000000..c52854cac
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemqp.asm
@@ -0,0 +1,536 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+DATA segment word public
+assume ds:DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+DATA ends
+
+
+
+CODE segment word public
+assume cs:CODE
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+aoldIMR db 0 ; 1st 8259 original IMR value
+boldIMR db 0 ; 2nd 8259 original IMR value
+
+endif ;OEM
+
+statwd dw 0 ; Temporary for status word
+oldvec dd 0 ; Old value in 8087 exception interrupt vector
+ifndef _NOCTRLC
+ctlc dd 0 ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:CODE
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [oldvec]
+ or ax, word ptr [oldvec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[oldvec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:CODE
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:DATA
+ ret
+
+
+; Forced cleanup of 8087 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+__fpinterrupt87:
+assume ds:nothing
+ nop
+ fnstsw [statwd] ; Store out exceptions
+ push cx ; waste time
+ mov cx,3
+self:
+ loop self
+ pop cx
+ test byte ptr [statwd],PENDINGBIT ; Test for 8087 interrupt
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ jmp [oldvec] ; We should never return from here.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:CODE
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [oldvec],bx ; Squirrel away old vector.
+ mov word ptr [oldvec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [oldvec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:CODE
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[oldvec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+CODE ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemwin.asm b/private/mvdm/wow16/win87em/emoemwin.asm
new file mode 100644
index 000000000..cc6a0b6c5
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemwin.asm
@@ -0,0 +1,693 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-89
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+NULL_JMP macro
+ jmp $+2
+ endm
+
+WASTE_TIME macro count
+ local WasteLoop
+
+ push cx
+ifnb <count>
+ mov cx, count
+else
+ mov cx, 10h
+endif
+WasteLoop:
+ push ax
+ pop ax
+
+ loop WasteLoop
+ pop cx
+
+ endm
+
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+extrn __WINFLAGS:abs
+WF_PMODE equ 1
+WF_CPU286 equ 2
+WF_CPU386 equ 4
+WF_WIN286 equ 10h
+WF_WIN386 equ 20h
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+
+ifdef OEM
+extrn aoldIMR:byte ; 1st 8259 original IMR value
+extrn boldIMR:byte ; 2nd 8259 original IMR value
+endif ;OEM
+
+
+extrn OldNMIVec:dword ; Old value in 8087 exception interrupt vector
+
+ifndef _NOCTRLC
+extrn ctlc:dword ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+ extrn __FPEXCEPTION87P:near
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+endif ;OEM
+
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [OldNMIVec]
+ or ax, word ptr [OldNMIVec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ mov ax, __WINFLAGS
+ test ax, WF_PMODE
+ jz SkipSettingIRQ13
+
+ .286p
+ .287
+ fsetpm ; set PM just in case Windows didn't.
+ .8086
+ .8087
+
+ push cs
+ pop ds ; Move current CS to DS for opsys calls.
+assume ds:EMULATOR_TEXT
+ mov dx, offset __fpIRQ13 ; Load DX with IRQ 13 interrupt handler.
+ mov ax, SETVECOP shl 8 + 75h ; set interrupt vector 75h
+ int OPSYS ; Install vector.
+SkipSettingIRQ13:
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 8087 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+public __fpIRQ13
+__fpIRQ13:
+ cli
+
+ WASTE_TIME 70
+
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ mov al, 65h
+ NULL_JMP
+ out 0a0h, al ; EOI slave irq 5
+ NULL_JMP
+ mov al, 62h
+ NULL_JMP
+ out 20h, al ; EOI master irq 2
+ NULL_JMP
+ pop ax
+
+
+ sub sp, 2
+
+ push bp
+ mov bp, sp
+
+ fnstsw [bp+2]
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ pop bp
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ fnclex ;Now this is safe.
+ WASTE_TIME 70 ;Fix timing problem??
+
+ jmp __FPEXCEPTION87P
+
+
+public __fpinterrupt87
+__fpinterrupt87:
+assume ds:nothing
+ nop
+
+ push bp
+ mov bp, sp
+ sub sp, 2
+
+ fnstsw word ptr [bp-2] ; Store out exceptions
+
+ push cx ; waste time
+ mov cx, 3
+self:
+ loop self
+ pop cx
+
+ test byte ptr [bp-2],PENDINGBIT ; Test for 8087 interrupt
+
+ mov sp, bp
+ pop bp
+
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ sub sp, 4
+
+ push bp
+ mov bp, sp
+
+ push ds
+ push ax
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ assume ds:EMULATOR_DATA
+
+ mov ax, word ptr [OldNMIVec+2] ; segment of OldNMIVec
+ mov [bp+4], ax
+
+ mov ax, word ptr [OldNMIVec] ; offset of OldNMIVec
+ mov [bp+2], ax
+
+ pop ax
+ pop ds
+ mov sp, bp
+ pop bp
+
+ retf ; jmp [OldNMIVec]. We should not return.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:EMULATOR_TEXT r
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [OldNMIVec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemwin.std b/private/mvdm/wow16/win87em/emoemwin.std
new file mode 100644
index 000000000..7b77b7f39
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemwin.std
@@ -0,0 +1,692 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-89
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+NULL_JMP macro
+ jmp $+2
+ endm
+
+WASTE_TIME macro count
+ local WasteLoop
+
+ push cx
+ifnb <count>
+ mov cx, count
+else
+ mov cx, 10h
+endif
+WasteLoop:
+ push ax
+ pop ax
+
+ loop WasteLoop
+ pop cx
+
+ endm
+
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+extrn __WINFLAGS:abs
+WF_PMODE equ 1
+WF_CPU286 equ 2
+WF_CPU386 equ 4
+WF_WIN286 equ 10h
+WF_WIN386 equ 20h
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+
+ifdef OEM
+extrn aoldIMR:byte ; 1st 8259 original IMR value
+extrn boldIMR:byte ; 2nd 8259 original IMR value
+endif ;OEM
+
+
+extrn OldNMIVec:dword ; Old value in 8087 exception interrupt vector
+
+ifndef _NOCTRLC
+extrn ctlc:dword ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+ extrn __FPEXCEPTION87P:near
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+endif ;OEM
+
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [OldNMIVec]
+ or ax, word ptr [OldNMIVec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ mov ax, __WINFLAGS
+ test ax, WF_PMODE
+ jz SkipSettingIRQ13
+
+ .286p
+ .287
+ fsetpm ; set PM just in case Windows didn't.
+ .8086
+ .8087
+
+ push cs
+ pop ds ; Move current CS to DS for opsys calls.
+assume ds:EMULATOR_TEXT
+ mov dx, offset __fpIRQ13 ; Load DX with IRQ 13 interrupt handler.
+ mov ax, SETVECOP shl 8 + 75h ; set interrupt vector 75h
+ int OPSYS ; Install vector.
+SkipSettingIRQ13:
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 8087 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+public __fpIRQ13
+__fpIRQ13:
+ cli
+
+ WASTE_TIME 70
+
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ mov al, 65h
+ NULL_JMP
+ out 0a0h, al ; EOI slave irq 5
+ NULL_JMP
+ mov al, 62h
+ NULL_JMP
+ out 20h, al ; EOI master irq 2
+ NULL_JMP
+ pop ax
+
+
+ sub sp, 2
+
+ push bp
+ mov bp, sp
+
+ fnstsw [bp+2]
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ pop bp
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ fnclex ;Now this is safe.
+
+ jmp __FPEXCEPTION87P
+
+
+public __fpinterrupt87
+__fpinterrupt87:
+assume ds:nothing
+ nop
+
+ push bp
+ mov bp, sp
+ sub sp, 2
+
+ fnstsw word ptr [bp-2] ; Store out exceptions
+
+ push cx ; waste time
+ mov cx, 3
+self:
+ loop self
+ pop cx
+
+ test byte ptr [bp-2],PENDINGBIT ; Test for 8087 interrupt
+
+ mov sp, bp
+ pop bp
+
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ sub sp, 4
+
+ push bp
+ mov bp, sp
+
+ push ds
+ push ax
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ assume ds:EMULATOR_DATA
+
+ mov ax, word ptr [OldNMIVec+2] ; segment of OldNMIVec
+ mov [bp+4], ax
+
+ mov ax, word ptr [OldNMIVec] ; offset of OldNMIVec
+ mov [bp+2], ax
+
+ pop ax
+ pop ds
+ mov sp, bp
+ pop bp
+
+ retf ; jmp [OldNMIVec]. We should not return.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:EMULATOR_TEXT r
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [OldNMIVec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemwin.t1 b/private/mvdm/wow16/win87em/emoemwin.t1
new file mode 100644
index 000000000..1630bc00f
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemwin.t1
@@ -0,0 +1,692 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-89
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+NULL_JMP macro
+ jmp $+2
+ endm
+
+WASTE_TIME macro count
+ local WasteLoop
+
+ push cx
+ifnb <count>
+ mov cx, count
+else
+ mov cx, 10h
+endif
+WasteLoop:
+ push ax
+ pop ax
+
+ loop WasteLoop
+ pop cx
+
+ endm
+
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+extrn __WINFLAGS:abs
+WF_PMODE equ 1
+WF_CPU286 equ 2
+WF_CPU386 equ 4
+WF_WIN286 equ 10h
+WF_WIN386 equ 20h
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+
+ifdef OEM
+extrn aoldIMR:byte ; 1st 8259 original IMR value
+extrn boldIMR:byte ; 2nd 8259 original IMR value
+endif ;OEM
+
+
+extrn OldNMIVec:dword ; Old value in 8087 exception interrupt vector
+
+ifndef _NOCTRLC
+extrn ctlc:dword ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+ extrn __FPEXCEPTION87P:near
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+endif ;OEM
+
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [OldNMIVec]
+ or ax, word ptr [OldNMIVec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ mov ax, __WINFLAGS
+ test ax, WF_PMODE
+ jz SkipSettingIRQ13
+
+ .286p
+ .287
+ fsetpm ; set PM just in case Windows didn't.
+ .8086
+ .8087
+
+ push cs
+ pop ds ; Move current CS to DS for opsys calls.
+assume ds:EMULATOR_TEXT
+ mov dx, offset __fpIRQ13 ; Load DX with IRQ 13 interrupt handler.
+ mov ax, SETVECOP shl 8 + 75h ; set interrupt vector 75h
+ int OPSYS ; Install vector.
+SkipSettingIRQ13:
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 8087 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+public __fpIRQ13
+__fpIRQ13:
+ cli
+
+ WASTE_TIME 70
+
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ mov al, 65h
+ NULL_JMP
+ out 0a0h, al ; EOI slave irq 5
+ NULL_JMP
+ mov al, 62h
+ NULL_JMP
+ out 20h, al ; EOI master irq 2
+ NULL_JMP
+ pop ax
+
+
+ sub sp, 2
+
+ push bp
+ mov bp, sp
+
+ fnstsw [bp+2]
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ pop bp
+
+ fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+; fnclex ;Now this is safe.
+
+ jmp __FPEXCEPTION87P
+
+
+public __fpinterrupt87
+__fpinterrupt87:
+assume ds:nothing
+ nop
+
+ push bp
+ mov bp, sp
+ sub sp, 2
+
+ fnstsw word ptr [bp-2] ; Store out exceptions
+
+ push cx ; waste time
+ mov cx, 3
+self:
+ loop self
+ pop cx
+
+ test byte ptr [bp-2],PENDINGBIT ; Test for 8087 interrupt
+
+ mov sp, bp
+ pop bp
+
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ sub sp, 4
+
+ push bp
+ mov bp, sp
+
+ push ds
+ push ax
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ assume ds:EMULATOR_DATA
+
+ mov ax, word ptr [OldNMIVec+2] ; segment of OldNMIVec
+ mov [bp+4], ax
+
+ mov ax, word ptr [OldNMIVec] ; offset of OldNMIVec
+ mov [bp+2], ax
+
+ pop ax
+ pop ds
+ mov sp, bp
+ pop bp
+
+ retf ; jmp [OldNMIVec]. We should not return.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:EMULATOR_TEXT r
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [OldNMIVec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emoemwin.t2 b/private/mvdm/wow16/win87em/emoemwin.t2
new file mode 100644
index 000000000..cc6a0b6c5
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emoemwin.t2
@@ -0,0 +1,693 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987-89
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+title emoem.asm - OEM dependent code for 8087
+
+;--------------------------------------------------------------------
+;
+; OEM customization routines for 8087/80287 coprocessor
+;
+; This module is designed to work with the following
+; Microsoft language releases:
+;
+; Microsoft C 3.00 and later
+; Microsoft FORTRAN 77 3.30 and later
+; Microsoft Pascal 3.30 and later
+;
+; This module supersedes the OEMR7.ASM module used in earlier
+; versions of Microsoft FORTRAN 77 and Pascal. The documentation
+; provided with the FORTRAN and Pascal releases refers to the old
+; OEMR7.ASM module and is only slightly relevant to this module.
+;
+; The following routines need to be written to properly handle the
+; 8087/808287 installation, termination, and interrupt handler
+;
+; __FPINSTALL87 install 8087 interrupt handler
+; __FPTERMINATE87 deinstall 8087 interrupt handler
+; __fpintreset reset OEM hardware if an 8087 interrupt
+;
+; ***** NEW INSTRUCTIONS *****
+;
+; If you want a PC clone version, do nothing. The libraries are
+; setup for working on IBM PC's and clones.
+;
+; These instructions only need to be followed if a non-IBM PC
+; clone version is desired.
+;
+; This module should be assembled with the
+; Microsoft Macro Assembler Version 4.00 or later as follows:
+;
+; masm -DOEM -r emoem.asm;
+;
+; Most hardware handles the 8087/80287 in one of the following
+; three ways -
+;
+; 1. NMI - IBM PC and clones all handle the interrupt this way
+; 2. single 8259
+; 3. master/slave 8259
+;
+; Manufacturer specific initialization is supported for these 3
+; machine configurations either by modifying this file and replacing
+; the existing EMOEM module in the math libraries or by patching
+; the .LIB and .EXE files directly.
+;
+; LIB 87-+EMOEM;
+; LIB EM-+EMOEM;
+;
+;--------------------------------------------------------------------
+
+ifdef OEM
+if1
+ %out OEM version for non-clone support
+endif
+endif
+
+;---------------------------------------------------------------------
+; Assembly constants.
+;---------------------------------------------------------------------
+
+NULL_JMP macro
+ jmp $+2
+ endm
+
+WASTE_TIME macro count
+ local WasteLoop
+
+ push cx
+ifnb <count>
+ mov cx, count
+else
+ mov cx, 10h
+endif
+WasteLoop:
+ push ax
+ pop ax
+
+ loop WasteLoop
+ pop cx
+
+ endm
+
+
+; MS-DOS OS calls
+
+ OPSYS EQU 21H
+ SETVECOP EQU 25H
+ GETVECOP EQU 35H
+ DOSVERSION EQU 30h
+ifndef _NOCTRLC
+ CTLCVEC EQU 23h
+endif ;_NOCTRLC
+
+extrn __WINFLAGS:abs
+WF_PMODE equ 1
+WF_CPU286 equ 2
+WF_CPU386 equ 4
+WF_WIN286 equ 10h
+WF_WIN386 equ 20h
+
+EMULATOR_DATA segment para public 'FAR_DATA'
+assume ds:EMULATOR_DATA
+
+; User may place data here if DS is setup properly.
+; Recommend keeping the data items in the code segment.
+
+
+ifdef OEM
+extrn aoldIMR:byte ; 1st 8259 original IMR value
+extrn boldIMR:byte ; 2nd 8259 original IMR value
+endif ;OEM
+
+
+extrn OldNMIVec:dword ; Old value in 8087 exception interrupt vector
+
+ifndef _NOCTRLC
+extrn ctlc:dword ; Old value of Control-C vector (INT 23h)
+endif ;_NOCTRLC
+
+
+EMULATOR_DATA ends
+
+
+
+EMULATOR_TEXT segment para public 'CODE'
+assume cs:EMULATOR_TEXT
+
+ public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
+ public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
+
+ extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
+ extrn __FPEXCEPTION87P:near
+
+
+ifdef _NO87INSTALL ; install/terminate routines for NO87 case for QuickC
+
+ public __FPINSTALLNO87
+ public __FPTERMINATENO87
+
+endif ;_NO87INSTALL
+
+
+ifdef OEM
+
+;***********************************************************************
+;
+; Hardware dependent parameters in the 8087 exception handler.
+;
+; For machines using 2 8259's to handle the 8087 exception, be sure that
+; the slave 8259 is the 1st below and the master is the 2nd.
+;
+; The last 4 fields allow you to enable extra interrupt lines into the
+; 8259s. It should only be necessary to use these fields if the 8087
+; interrupt is being masked out by the 8259 PIC.
+;
+; The ocw2's (EOI commands) can be either non-specific (20H) or
+; specific (6xH where x=0 to 7). If you do not know which interrupt
+; request line on the 8259 the 8087 exception uses, then you should issue
+; the non-specific EOI (20H). Interrupts are off at this point in the
+; interrupt handler so a higher priority interrupt will not be seen.
+
+oeminfo struc
+oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
+intnum db 2 ; IBM PC clone interrupt number
+share db 0 ; nonzero if original vector should be taken
+a8259 dw 0 ; 1st 8259 (A0=0) port #
+aocw2 db 0 ; 1st 8259 (A0=0) EOI command
+b8259 dw 0 ; 2nd 8259 (A0=0) port #
+bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
+a8259m dw 0 ; 1st 8259 (A0=1) port #
+aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
+b8259m dw 0 ; 2nd 8259 (A0=1) port #
+bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
+oeminfo ends
+
+;-----------------------------------------------------------------------
+; OEM specific 8087 information
+;
+; If the OEM number returned from the DOS version call matches,
+; this information is automatically moved into the oem struc below.
+
+oemtab label byte ; Table of OEM specific values for 8087
+
+; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
+
+;TI Professional Computer
+TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
+
+ db 0 ; end of table
+
+; Unique pattern that can be searched for with the debugger so that
+; .LIB or .EXE files can be patched with the correct values.
+; If new values are patched into .LIB or .EXE files, care must be
+; taken in insure the values are correct. In particular, words and
+; bytes are intermixed in oeminfo structure. Remember words are
+; stored low byte - high byte in memory on the 8086 family.
+
+ db '<<8087>>' ; older versions used '<8087>'
+
+; Some manufacturer's machines can not be differentiated by the
+; OEM number returned by the MS-DOS version check system call.
+; For these machines it is necessary to replace the line below
+
+oem1 oeminfo <> ; default values for IBM PC & clones
+
+; with one of the following. If your machine has an 8087 capability
+; and it is not in the list below, you should contact your hardware
+; manufacturer for the necessary information.
+
+;ACT Apricot
+;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
+
+;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
+;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
+
+;---------------------------------------------------------------------
+
+endif ;OEM
+
+
+page
+
+;---------------------------------------------------------------------
+;
+; Perform OEM specific initialization of the 8087.
+;
+
+__FPINSTALL87:
+ push ds ; DS = EMULATOR_DATA
+
+
+ifdef OEM
+ push ds
+ pop es ; CS = DS = ES
+ mov ah,DOSVERSION
+ int OPSYS ; bh = OEM#
+ cld
+ mov si,offset oemtab ; start of OEM 8087 info table
+ mov di,offset oem1+1
+ mov cx,(size oem1)-1
+OEMloop:
+ lodsb ; get OEM#
+ or al,al
+ jz OEMdone ; OEM# = 0 - did not find OEM
+ cmp al,bh ; correct OEM#
+ je OEMfound
+ add si,cx ; skip over OEM information
+ jmp OEMloop
+
+OEMfound:
+ rep movsb ; move the information
+
+OEMdone: ; done with automatic customization
+endif ;OEM
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef WINDOWS
+ mov ax, word ptr [OldNMIVec]
+ or ax, word ptr [OldNMIVec+2]
+ jnz SetVector
+endif ;WINDOWS
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+SetVector:
+ push cs ; Move current CS to DS for opsys calls.
+ pop ds
+assume ds:EMULATOR_TEXT
+
+ mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ mov ax, __WINFLAGS
+ test ax, WF_PMODE
+ jz SkipSettingIRQ13
+
+ .286p
+ .287
+ fsetpm ; set PM just in case Windows didn't.
+ .8086
+ .8087
+
+ push cs
+ pop ds ; Move current CS to DS for opsys calls.
+assume ds:EMULATOR_TEXT
+ mov dx, offset __fpIRQ13 ; Load DX with IRQ 13 interrupt handler.
+ mov ax, SETVECOP shl 8 + 75h ; set interrupt vector 75h
+ int OPSYS ; Install vector.
+SkipSettingIRQ13:
+
+ifndef _NOCTRLC
+; Intercept Control-C vector to guarentee cleanup
+
+ mov ax,GETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ mov word ptr [ctlc],bx
+ mov word ptr [ctlc+2],es
+ mov dx,offset ctlcexit
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+endif ;_NOCTRLC
+
+ifdef OEM
+
+; set up 8259's so that 8087 interrupts are enabled
+
+ mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ; and only 1 8259
+ mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [aoldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+ mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
+ or ah,ah ; if 0, don't need to do this
+ jz installdone ;
+ mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
+ in al,dx ; read old IMR value
+ mov [boldIMR],al ; save it to restore at termination
+ and al,ah ; mask to enable interrupt
+ jmp short $+2 ; for 286's
+ out dx,al ; write out new mask value
+
+installdone:
+
+endif ;OEM
+
+assume ds:EMULATOR_DATA
+ pop ds
+ ret
+
+
+page
+; __FPTERMINATE87
+;
+; This routine should do the OEM 8087 cleanup. This routine is called
+; before the program exits.
+;
+; DS = EMULATOR_DATA
+
+__FPTERMINATE87:
+ push ds
+ push ax
+ push dx
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+ int OPSYS
+
+ifdef OEM
+
+; reset 8259 IMR's to original state
+
+ push cs
+ pop ds ; DS = CS
+assume ds:EMULATOR_TEXT
+ cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
+ je term2nd8259 ; no - check 2nd 8259
+ mov al,[aoldIMR] ; get old IMR
+ mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+term2nd8259:
+ cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
+ je terminatedone ; no
+ mov al,[boldIMR] ; get old IMR
+ mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
+ out dx,al ; restore IMR
+
+terminatedone:
+
+endif ;OEM
+
+ pop dx
+ pop ax
+ pop ds
+assume ds:EMULATOR_DATA
+ ret
+
+
+; Forced cleanup of 8087 exception handling on Control-C
+
+ifndef _NOCTRLC
+ctlcexit:
+ push ax
+ push dx
+ push ds
+ call __FPTERMINATE87 ; forced cleanup of exception handler
+ lds dx,[ctlc] ; load old control C vector
+ mov ax,SETVECOP shl 8 + CTLCVEC
+ int OPSYS
+ pop ds
+ pop dx
+ pop ax
+ jmp [ctlc] ; go through old vector
+endif ;_NOCTRLC
+
+page
+; __fpinterrupt87
+;
+; This is the 8087 exception interrupt routine.
+;
+; All OEM specific interrupt and harware handling should be done in
+; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
+; exception handler) may not return. __FPEXCEPTION87 also turns
+; interrupts back on.
+;
+
+PENDINGBIT= 80h ; Bit in status word for interrupt pending
+
+public __fpIRQ13
+__fpIRQ13:
+ cli
+
+ WASTE_TIME 70
+
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ mov al, 65h
+ NULL_JMP
+ out 0a0h, al ; EOI slave irq 5
+ NULL_JMP
+ mov al, 62h
+ NULL_JMP
+ out 20h, al ; EOI master irq 2
+ NULL_JMP
+ pop ax
+
+
+ sub sp, 2
+
+ push bp
+ mov bp, sp
+
+ fnstsw [bp+2]
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ pop bp
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+; fnclex ; 486 bug - must wait till after last
+ ; "out f0" to clear fp exceptions
+ ; or IGNNE# will be permanently active.
+ WASTE_TIME
+ push ax
+ xor al, al
+ NULL_JMP
+ out 0f0h, al ; reset busy line.
+ NULL_JMP
+ pop ax
+
+ fnclex ;Now this is safe.
+ WASTE_TIME 70 ;Fix timing problem??
+
+ jmp __FPEXCEPTION87P
+
+
+public __fpinterrupt87
+__fpinterrupt87:
+assume ds:nothing
+ nop
+
+ push bp
+ mov bp, sp
+ sub sp, 2
+
+ fnstsw word ptr [bp-2] ; Store out exceptions
+
+ push cx ; waste time
+ mov cx, 3
+self:
+ loop self
+ pop cx
+
+ test byte ptr [bp-2],PENDINGBIT ; Test for 8087 interrupt
+
+ mov sp, bp
+ pop bp
+
+ jz not87int ; Not an 8087 interrupt.
+
+ifdef OEM
+ call __fpintreset ; OEM interrupt reset routine
+endif ;OEM
+
+ call __FPEXCEPTION87 ; 8087 error handling - may not return
+ ; this routine turns interrupts back on
+
+ifdef OEM
+ cmp [oem1].share,0 ; Should we execute the old interrupt routine?
+ jnz not87int ; if so then do it
+ ; else return from interrupt
+
+; If you fall through here to do further hardware resetting, things
+; may not always work because __FPEXCEPTION87 does not always return
+; This only happens when the 8087 handler gets an exception that is
+; a fatal error in the language runtimes. I.e., divide by zero
+; is a fatal error in all the languages, unless the control word has
+; set to mask out divide by zero errors.
+
+endif ;OEM
+
+done8087:
+ iret
+
+not87int:
+ sub sp, 4
+
+ push bp
+ mov bp, sp
+
+ push ds
+ push ax
+
+ mov ax, EMULATOR_DATA
+ mov ds, ax
+ assume ds:EMULATOR_DATA
+
+ mov ax, word ptr [OldNMIVec+2] ; segment of OldNMIVec
+ mov [bp+4], ax
+
+ mov ax, word ptr [OldNMIVec] ; offset of OldNMIVec
+ mov [bp+2], ax
+
+ pop ax
+ pop ds
+ mov sp, bp
+ pop bp
+
+ retf ; jmp [OldNMIVec]. We should not return.
+
+
+ifdef OEM
+
+
+__fpintreset:
+ push ax
+ push dx
+ mov al,[oem1].aocw2 ; Load up EOI instruction.
+ or al,al ; Is there at least one 8259 to be reset?
+ jz Reset8259ret ; no
+ mov dx,[oem1].a8259
+ out dx,al ; Reset (master) 8259 interrupt controller.
+ mov al,[oem1].bocw2 ; Load up EOI instruction.
+ or al,al ; Is there a slave 8259 to be reset?
+ jz Reset8259ret
+ mov dx,[oem1].b8259
+ out dx,al ; Reset slave 8259 interrupt controller.
+
+Reset8259ret:
+ pop dx
+ pop ax
+ ret
+
+endif ;OEM
+
+ifdef _NO87INSTALL
+__FPINSTALLNO87:
+ push bx
+ push es
+ push ax
+ push dx
+ push ds
+
+ mov ax,cs ; Move current CS to DS for opsys calls.
+ mov ds,ax
+assume ds:EMULATOR_TEXT r
+
+; Save old interrupt vector.
+; Ask operating system for vector.
+
+ifdef OEM
+ mov al,[oem1].intnum ; Interrupt vector number.
+ mov ah,GETVECOP ; Operating system call interrupt.
+else
+ mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
+endif ;OEM
+ int OPSYS ; Call operating system.
+ mov word ptr [OldNMIVec],bx ; Squirrel away old vector.
+ mov word ptr [OldNMIVec+2],es
+
+; Have operating system install interrupt vectors.
+
+ mov dx,offset __fpinterruptno87 ; Load DX with fake 8087 interrupt handler.
+ifdef OEM
+ mov ah,SETVECOP ; Set interrupt vector code in AH.
+ mov al,[oem1].intnum ; Set vector number.
+else
+ mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
+endif ;OEM
+ int OPSYS ; Install vector.
+
+ pop ds
+assume ds:nothing
+ pop dx
+ pop ax
+ pop es
+ pop bx
+
+ ret
+
+__fpinterruptno87:
+ jmp [OldNMIVec] ; will use CS: override
+
+__FPTERMINATENO87:
+ push ds
+ push ax
+ push dx
+
+ mov ax,cs
+ mov ds,ax
+assume ds:EMULATOR_TEXT
+
+ifdef OEM
+ mov ah,SETVECOP
+ mov al,[oem1].intnum
+else
+ mov ax,SETVECOP shl 8 + 2
+endif ;OEM
+ lds dx,[OldNMIVec]
+assume ds:nothing
+ int OPSYS
+
+ pop dx
+ pop ax
+ pop ds
+
+ ret
+
+endif ;_NO87INSTALL
+
+EMULATOR_TEXT ends
+
+ end
diff --git a/private/mvdm/wow16/win87em/emspec.asm b/private/mvdm/wow16/win87em/emspec.asm
new file mode 100644
index 000000000..b6f5d61bf
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emspec.asm
@@ -0,0 +1,192 @@
+ page ,132
+ subttl emspec.asm - Special emulator functions for speed
+;***
+;emspec.asm - Special emulator functions for speed
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Special emulator functions for speed
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin SPEC
+
+
+pub loadcontrolword
+ifdef QB3
+ or al,2 ; mask denormal exceptions
+endif ;QB3
+ mov [UserControlWord],ax ; save user's version
+ and ax,0FF3CH ; Turn off reserved, IEM, Denormal
+ ; & invalid exception mask bits
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0 ; Non-0 if 8087 present
+ je EmulateFLDCW
+endif ;only87
+
+ mov [REMLSW],ax ; use this cell (not busy)
+ fnop ; fix for intel erratum #8
+ fldcw [REMLSW] ; 8087 gets new control word
+endif ;frontend
+
+pub EmulateFLDCW
+ mov [ControlWord],ax ; save internal control word
+ ret
+
+
+;-----------------------------------------------------------------------------
+
+ifndef QB3 ; rest not needed if QB 3
+
+pub storecontrolword
+ mov ax,[UserControlWord] ; get user's version
+ ret
+
+
+pub storestatusword
+ xor ax,ax
+ifndef frontend
+ cmp al,[Have8087]
+ je no87status
+ fstsw [NewStatusWord]
+ fwait
+ mov al,byte ptr [NewStatusWord] ; get exception summary
+ and al,03Fh ; only low 6 bits are wanted
+endif ;frontend
+
+pub no87status
+ or ax,[UserStatusWord] ; or with full status
+ and ax,UStatMask ; mask down to actual status bits
+ mov [UserStatusWord],ax ; update full status word
+ ret
+
+page
+
+; Procedure to truncate TOS to integer TOS
+
+; ax = new rounding control
+
+pub truncateTOS
+ and ax,RoundControl shl 8 ; mask to new rounding control
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0
+ je Emulatetruncate
+endif ;only87
+
+ FSTCW [ControlWord] ; get control word
+ FWAIT ; synchronize
+ MOV CX,[ControlWord] ; round mode saved
+ and ch,not RoundControl ; clear rounding control bits
+ OR ax,cx ; set new rounding
+ MOV [REMLSW],AX ; back to memory
+ FLDCW [REMLSW] ; reset rounding
+ FRNDINT ; "round" top of stack
+ FLDCW [ControlWord] ; restore rounding
+ RET ; simple return
+endif ;frontend
+
+ifndef only87
+pub Emulatetruncate
+ mov cx,[ControlWord]
+ push cx ; remember what control word was
+ and ch,not RoundControl ; clear rounding control bits
+ OR ah,ch ; set new rounding
+ MOV [CWcntl],ah ; flag new rounding mode
+ PUSH BP ; save BP
+ CALL eFRNDINT
+ POP BP ; restore BP
+ POP [ControlWord] ; set back to the way it was
+
+ call checktrunc ; check for truncation error
+
+ RET ; finished
+endif ;only87
+
+page
+
+; Procedure to truncate TOS to integer in DX:AX
+
+; ax = new rounding control
+
+pub truncateTOSto32int
+ and ax,RoundControl shl 8
+
+ifndef frontend
+ifndef only87
+ cmp [Have8087],0
+ je Emulatetruncateto32int
+endif ;only87
+
+ FSTCW [ControlWord] ; get control word
+ FWAIT ; synchronize
+ MOV CX,[ControlWord] ; round mode saved
+ and ch,not RoundControl ; clear rounding control bits
+ OR ax,cx ; set new rounding
+ MOV [REMLSW],AX ; back to memory
+ FLDCW [REMLSW] ; reset rounding
+ FISTP dword ptr [REMLSW] ; "round" top of stack
+ FLDCW [ControlWord] ; restore rounding
+ mov ax,[REMLSW]
+ mov dx,[REMLSW+2]
+ RET ; simple return
+endif ;frontend
+
+ifndef only87
+pub Emulatetruncateto32int
+ mov cx,[ControlWord]
+ push cx ; remember what control word was
+ and ch,not RoundControl ; clear rounding control bits
+ OR ah,ch ; set new rounding
+ MOV [CWcntl],ah ; flag new rounding mode
+ PUSH BP ; save BP
+ CALL TOSto32int ; convert to 32-bit int in BX:DX
+ POP BP ; restore BP
+ mov ax,dx
+ mov dx,bx
+
+ call checktrunc ; check for truncation error
+
+ POPST ; pop of current stack entry
+ POP [ControlWord] ; set back to the way it was
+
+pub truncerrOK ; (reuse RET for routine below)
+ RET ; finished
+
+; check for errors
+
+pub checktrunc ; !!! check emmain for same code
+ MOV cx,[CURerr] ; fetch errors
+ or [UserStatusWord],cx ; OR into user status word
+ OR [SWerr],cl ; set errors in sticky error flag
+ NOT cl ; make a zero mean an error
+ MOV ch,byte ptr [UserControlWord] ; get user's IEEE control word
+ OR ch,0C2H ; mask reserved, IEM and denormal bits
+ AND ch,03FH ; unmask invalid instruction,
+ ; stack overflow.
+ OR cl,ch ; mask for IEEE exceptions
+ NOT cl ; make a one mean an error
+ MOV ch,byte ptr (CURerr+1) ; get stack over/underflow flags
+ TEST cx,0FFFFh-MemoryOperand ; test for errors to report
+ jz truncerrOK ; error is masked
+
+ xchg ax,cx ; ax = exception
+ jmp CommonExceptions ; handle error (??? unclean stack)
+
+endif ;only87
+
+
+endif ;QB3
+
+
+ProfEnd SPEC
diff --git a/private/mvdm/wow16/win87em/emstack.asm b/private/mvdm/wow16/win87em/emstack.asm
new file mode 100644
index 000000000..027e61f44
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emstack.asm
@@ -0,0 +1,108 @@
+ page ,132
+ subttl emstack.asm - Emulator Stack Management Area
+;***
+;emstack.asm - Emulator Stack Management Area
+;
+; Copyright (c) 1986-89, Microsoft Corporation
+;
+;Purpose:
+; Emulator Stack Management Area
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+ProfBegin STACK
+
+
+;*********************************************************************;
+; ;
+; Emulator Stack Management Area ;
+; ;
+;*********************************************************************;
+
+; The emulator maintains an "finite" stack of 12 byte registers.
+
+; Stand-alone emulator has 1 chunk only.
+
+; This is done using a list of finite length stack chunks, each of
+; which has the following format:
+; +00 first (deepest) 12 byte register
+; +12 next 12 byte register
+; (and so on through last possible register)
+
+
+; MACROS used to manipulate the emulator/8087 memory stack
+
+
+; This macro allocates a new TOS register, returns SI with its address.
+
+PUSHST MACRO
+ local pushstok
+ mov esi,[CURstk] ; 14 get address of current register
+ cmp esi,[LIMstk] ; 15 is current register end of stack
+ jne short pushstok ; 16 no, still room in stack
+ call OverStk ; stack overflow error
+pushstok:
+ add esi,Reg87Len ; 4 increment SI to next free register
+ mov [CURstk],esi ; 15 set current top of stack
+ ENDM ; 64 total
+
+
+; This macro deallocates TOS register, returns SI with new TOS address.
+; Note: assumes SI contains TOS address, CURstk
+; BASstk converted back to a variable to enable macro use for 8087 stack
+; handling. Brad Verheiden, 4-13-84.
+
+POPSTsi MACRO
+ local popstok
+ cmp esi,[BASstk] ; 15 was it last register in the chunk ?
+ jnz short popstok ; 16 no, still room in current chunk
+ call UnderStk ; stack underflow error
+popstok:
+ sub esi,Reg87Len ; 4 decrement SI to previous register
+ mov [CURstk],esi ; 15 set current top of stack
+ ENDM ; 64 total
+
+POPST MACRO
+ mov esi,[CURstk]
+ POPSTsi
+ ENDM
+
+
+ChangeDIfromTOStoNOS MACRO
+ sub edi,Reg87Len
+ ENDM
+
+
+page
+; This area contains two procedures, OverStk and UnderStk,
+; which generate a stack overflow error.
+
+; OverStk: invoked within PUSHST macro
+; on entry, the stack is full
+; on return, SI contains address of base of stack
+
+; UnderStk: invoked within POPST macro
+; on entry, the stack is empty
+; on return, SI contains address of base of stack
+
+pub OverStk
+ OR byte ptr [CURerr+1],StackOverflow/256 ; raise stack overflow
+ CMP [Have8087],0 ; Is 8087 present
+ JZ short OverStkEnd ; No - don't touch AX
+ OR AH,StackOverflow/256 ; Indicate memory overflow for 8087
+
+pub OverStkEnd
+ RET ; finished
+
+pub UnderStk
+ OR byte ptr [CURerr+1],StackUnderflow/256 ; raise stack underflow
+ RET ; finished
+
+ProfEnd STACK
diff --git a/private/mvdm/wow16/win87em/emthread.asm b/private/mvdm/wow16/win87em/emthread.asm
new file mode 100644
index 000000000..8fa5a51dc
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emthread.asm
@@ -0,0 +1,176 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1987
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emthread.asm - Emulator multi-thread support for OS/2
+page
+
+
+thread1static=1 ; set DS = EMULATOR_DATA for thread 1
+ ; dynamically allocate data areas for other threads
+
+_DATA segment word public 'DATA'
+_DATA ends
+
+DGROUP group _DATA
+
+_DATA segment word public 'DATA'
+ extrn __FPDSARRAY:WORD
+
+ ifdef i386
+ extrn __threadid:FWORD ; far pointer to ???? thread id
+ else
+ extrn __threadid:DWORD ; far pointer to WORD thread id
+ endif
+_DATA ends
+
+dataoffset equ offset DGROUP:
+
+include os2dll.inc ; defines _SIGNAL_LOCK
+ ; and other lock values;
+ ; must be synchronized with
+ ; \clib\include\86\os2dll.inc
+ ; and \clib\include\os2dll.h
+extrn __lockf:FAR
+extrn __unlockf:FAR
+
+LOAD_DS_EDI macro
+ local TIDOk, LoadDone
+;
+; loads ds:edi with far pointer to thread's DS selector
+; (pointer into __FPDSARRAY)
+;
+; uses eax,edi,es,ds
+;
+; sets eax = 2 * (thread id)
+;
+
+ mov ax,DGROUP
+ mov ds,ax ; set DS = DGROUP temporarily
+ assume ds:DGROUP
+ les edi,[__threadid] ; ES:eDI = far pointer to thread id
+ mov ax,es:[edi] ; AX = thread id (far ptr to WORD)
+
+ cmp ax, MAXTHREADID
+ jbe TIDOk
+
+ push ax
+ call LoadDS_EDI
+ pop ax
+ shl ax, 1 ; thread id times 2
+ jmp short LoadDone
+
+TIDOk:
+ shl eax,1 ; thread id times 2
+ mov edi,dataoffset __FPDSARRAY
+ add edi,eax ; index into __FPDSARRAY
+LoadDone:
+ endm
+
+
+LOADthreadDS macro
+;
+; loads thread's DS from __FPDSARRAY indexed by thread id
+; preserves all registers except DS and eAX
+;
+; __FPDSARRAY[0] = MAXTHREAD
+; __FPDSARRAY[i] = emulator DS for thread i, 1<=i<=MAXTHREAD
+;
+ push edi ; save eDI
+ push es ; save ES
+
+ LOAD_DS_EDI ; get pointer (ds:edi) to thread's DS
+
+ mov ds,ds:[edi] ; set up DS to thread's data area
+ assume ds:EMULATOR_DATA ; or dynamically allocated copy
+
+ pop es
+ pop edi ; restore DI
+ endm
+
+ALLOCthreadDS macro
+pub allocperthread
+ LOAD_DS_EDI ; get pointer into __FPDSARRAY
+; eAX = 2 * (thread_id)
+ifdef thread1static
+;
+; for thread 1, use EMULATOR_DATA segment
+;
+ cmp eax,2 ; thread 1?
+ jnz allocds ; no - dynamically allocate DS
+ mov ax,EMULATOR_DATA ; yes - use static area
+ mov ds:[edi],ax ; store new DS into __FPDSARRAY
+ mov ds,ax
+ assume ds:EMULATOR_DATA ; or dynamically allocated copy
+ mov es,ax ; ES = DS = EMULATOR_DATA
+ jmp allocdone
+else
+ jmp allocds
+endif ;thread1static
+
+pub allocerror
+ mov ax,-3 ; return allocation error
+ stc
+ ret
+;
+ifdef thread1static
+; for threads other than thread 1, allocate new DS from the system
+else
+; for all threads, allocate new DS from the system
+endif
+;
+
+pub allocds
+ assume ds:DGROUP
+ push offset __fptaskdata ; size of per-thread data area
+ push ds ; ds:di = addr of thread's DS
+ push edi
+ push 0 ; non-shared segment
+ os2call DOSALLOCSEG
+
+ or ax,ax ; allocation error?
+ jnz allocerror ; yes - cause thread init to fail
+
+ mov di,ds:[edi] ; set ES = DS = thread's data selector
+ mov ds,di
+ mov es,di
+ assume ds:EMULATOR_DATA ; or dynamically allocated copy
+
+pub allocdone
+;
+; ES = DS = selector for emulator data area
+;
+ mov edx,offset __fptaskdata ; dx = size of emulator data area
+ sub edx,offset EMULATOR_DATA; jwm
+
+ xor ax,ax ; prepare to zero out data segment
+ xor edi,edi ; start at offset zero
+ mov edi,offset EMULATOR_DATA; jwm : begin at the beginning
+
+ mov ecx,edx ; cx = size of segment (even)
+ shr ecx,1 ; halve it
+ rep stosw ; zero it!
+ endm
+
+FREEthreadDS macro
+pub freeperthread
+ assume ds:EMULATOR_DATA ; or dynamically allocated copy
+ifdef thread1static
+ mov ax,ds
+ cmp ax,EMULATOR_DATA ; don't free thread 1's area
+ je nofreeseg
+endif ;thread1static
+
+ push ds
+ os2call DOSFREESEG ; free per-thread emulator data area
+
+nofreeseg:
+ LOAD_DS_EDI ; get pointer into __FPDSARRAY
+ mov word ptr ds:[edi],0 ; zero out __FPDSARRAY element
+ ; for the current thread
+ assume ds:EMULATOR_DATA
+ endm
diff --git a/private/mvdm/wow16/win87em/emu8087.asm b/private/mvdm/wow16/win87em/emu8087.asm
new file mode 100644
index 000000000..92266fa2e
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emu8087.asm
@@ -0,0 +1,14 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+only87 equ 1 ; no emulator
+
+include emulator.asm
+
+end
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/win87em/emulator.asm b/private/mvdm/wow16/win87em/emulator.asm
new file mode 100644
index 000000000..538c6e96d
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emulator.asm
@@ -0,0 +1,715 @@
+ page ,132
+ title emulator - 8087/287 emulator for MS-DOS, XENIX, OS/2, Windows
+;***
+;emulator.asm - 8087/287 emulator for MS-DOS, XENIX, OS/2, Windows
+;
+; Copyright (c) 1984-89, Microsoft Corporation
+;
+;Purpose:
+; 8087/287 emulator for MS-DOS, XENIX, OS/2, Windows
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+ include emulator.hst ; Emulator history file.
+
+
+major_ver equ 6
+minor_ver equ 0
+
+fastSP = 0 ; default to no fast single precision
+
+
+;*******************************************************************************
+;
+; Print out emulator version.
+;
+;*******************************************************************************
+
+
+OutMsg macro text
+ ifndef ?QUIET
+ %out text
+ endif
+ endm
+
+
+outver macro maj,tens,hunds
+ OutMsg <Emulator Version maj&.&tens&hunds>
+ endm
+
+
+if1
+
+ outver %major_ver,%(minor_ver/10),%(minor_ver mod 10)
+
+ ifdef WINDOWS
+ OutMsg <Windows 2.00 Emulator>
+ endif
+
+ ifdef QB3
+ OutMsg <QuickBASIC 3.00 Emulator>
+ endif
+
+ ifdef _NOSTKEXCHLR ; formerly called QB4
+ OutMsg <No stack overflow/underflow hadler.>
+ endif
+
+ ifdef PCDOS
+ OutMsg <IBM PC-DOS version - Uses int 11h BIOS equipment check.>
+ endif
+
+ ifdef MTHREAD
+ ifdef DOS5only
+ OutMsg <Reentrant multithread OS/2 emulator.>
+ else
+ %out *** Error: MTHREAD supported only if DOS5only defined.
+ endif
+ endif
+
+ ifdef SQL_EMMT
+ ifdef MTHREAD
+ OutMsg <Special SQL version.>
+ else
+ %out *** Error: SQL supported only if MTHREAD is defined.
+ endif
+ endif
+
+ ifdef _COM_
+ OutMsg <COM files supported.>
+ endif ;_COM_
+
+ ifdef XENIX
+ OutMsg <XENIX emulator.>
+ PROTECT = 1 ; XENIX is always protect mode
+
+ else ;not XENIX
+ ifdef DOS5only
+ OutMsg <DOS 5 only emulator.>
+ DOS5 = 1
+ PROTECT = 1 ; DOS 5 is always protect mode
+
+ else ;not DOS5only
+ DOS3= 1 ; DOS 3 support is default
+ ifdef DOS5
+ OutMsg <DOS 3 & 5 emulator.>
+ DOS3and5= 1
+ PROTECT = 1 ; DOS 5 is always protect mode
+
+ else ;not DOS5
+ OutMsg <DOS 3 only emulator.>
+ endif ;not DOS5
+
+ endif ;not DOS5only
+
+ ifdef standalone
+ OutMsg <Stand-alone version (uses task vector for DS).>
+ ifdef DOS5
+ %out *** Error: DOS 5 support not allowed.
+ .error
+ endif ;DOS5
+ endif ;standalone
+
+ ifdef frontend
+ OutMsg <Front-end version - No hardware and limited instructions.>
+ endif ;frontend
+
+ ifdef SMALL_EMULATOR
+ OutMsg <Small Emulator - Limited instructions.>
+ endif ;SMALL_EMULATOR
+
+ ifdef only87
+ OutMsg <8087 only version - No emulation.>
+ endif ;only87
+
+ ifdef POLLING
+ OutMsg <Exception handling uses polling FWAITs.>
+ endif
+
+ endif ;not XENIX
+
+ ifdef i386
+ OutMsg <386 version>
+ endif
+
+ if fastSP
+ %out Fast Single Precision version - Not supported.
+ endif ;fastSP
+
+ ifdef DEBUG
+ OutMsg <+++ Debug Version +++>
+ endif ;DEBUG
+
+ ifdef PROFILE
+ OutMsg <Profiling version.>
+ endif ;PROFILE
+
+endif ;if1
+
+
+;*******************************************************************************
+;
+; Include cmacros.inc
+;
+;*******************************************************************************
+
+?PLM = 1
+?WIN = 0
+?DF = 1
+
+?NOGLOBAL = 1
+?NOSTATIC = 1
+?NOEXTERN = 1
+?NODEF = 1
+?NOPTR = 1
+
+ include cmac_mrt.inc ; old, customized masm510 cmacros
+ include mrt386.inc
+
+ifdef MTHREAD
+ include os2supp.inc
+endif
+
+
+;*******************************************************************************
+;
+; Include emulator macros.
+;
+;*******************************************************************************
+
+ include emulator.inc
+
+
+;*******************************************************************************
+;
+; Processor setup.
+;
+;*******************************************************************************
+
+ifdef i386
+ .386p
+ .287
+
+elseifdef XENIX
+ .286c ; allow 286 instructions if XENIX
+ .287
+
+elseifdef DOS5only
+ .286c ; allow 286 instructions if DOS 5 only
+ .287
+
+else ;Default
+ .8086 ; otherwise only 8086 instructions
+ .8087 ; make sure there are fwaits before all instruction
+endif
+
+
+;*******************************************************************************
+;
+; Define segments.
+;
+;*******************************************************************************
+
+ifdef QB3
+
+ createSeg EMULATOR_DATA, edata, para, public, CODE, <>
+ createSeg EMULATOR_TEXT, ecode, para, public, CODE, <>
+
+elseifdef QP
+
+ createSeg DATA, edata, word, public,, <>
+ createSeg CODE, ecode, word, public,, <>
+
+else ;DEFAULT
+
+ createSeg EMULATOR_DATA, edata, para, public, FAR_DATA, <>
+ createSeg EMULATOR_TEXT, ecode, para, public, CODE, <>
+
+endif ;DEFAULT
+
+
+
+;*******************************************************************************
+;
+; Define Number of stack elements, BEGINT and TSKINT
+;
+;*******************************************************************************
+
+
+ifdef XENIX
+ Numlev equ 10 ; 10 levels minimum for floating point
+
+else ;not XENIX
+
+ ifdef QB3
+
+ extrn $EM_INT:far ; QB3 emulator error entry
+ BEGINT equ 084h ; MSDOS beginning interrupt
+ Numlev equ 10 ; 10 levels minimum for floating point
+
+ else ;not QB3
+
+ BEGINT equ 034h ; MSDOS beginning interrupt
+
+ ifdef _NOSTKEXCHLR
+ Numlev equ 10 ; 10 levels minimum for floating point
+
+ elseifdef MTHREAD
+ Numlev equ 16 ; 16 levels minimum for floating-point
+
+ else ;Default
+ Numlev equ 16 ; 16 levels minimum for floating point
+ endif ;Default
+
+ ifdef standalone
+ TSKINT equ BEGINT + 10 ; Task data pointer
+ endif
+
+ ifdef WINDOWS
+ TSKINT equ BEGINT + 10 ; SignalAddress pointer
+ endif
+
+ endif ;not QB3
+
+
+ ifdef WINDOWS
+
+ FIDRQQ equ (fINT + 256*(BEGINT + 0)) - (fFWAIT + 256*fESCAPE)
+ FIERQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fES)
+ FIWRQQ equ (fINT + 256*(BEGINT + 9)) - (iNOP + 256*fFWAIT)
+
+ FIARQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fDS)
+ FJARQQ equ 256*(((0 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+ FISRQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fSS)
+ FJSRQQ equ 256*(((1 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+ FICRQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fCS)
+ FJCRQQ equ 256*(((2 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+
+ elseifdef QP ; QuickPascal can't do absolutes
+
+ FIDRQQ equ (fINT + 256*(BEGINT + 0)) - (fFWAIT + 256*fESCAPE)
+ FIERQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fES)
+ FIWRQQ equ (fINT + 256*(BEGINT + 9)) - (iNOP + 256*fFWAIT)
+
+ FIARQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fDS)
+ FJARQQ equ 256*(((0 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+ FISRQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fSS)
+ FJSRQQ equ 256*(((1 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+ FICRQQ equ (fINT + 256*(BEGINT + 8)) - (fFWAIT + 256*fCS)
+ FJCRQQ equ 256*(((2 shl 6) or (fESCAPE and 03Fh)) - fESCAPE)
+
+ else ;not WINDOWS or QuickPascal
+
+ extrn FIWRQQ:abs, FIERQQ:abs, FIDRQQ:abs
+ extrn FISRQQ:abs, FJSRQQ:abs
+ extrn FIARQQ:abs, FJARQQ:abs
+ extrn FICRQQ:abs, FJCRQQ:abs
+
+ endif ;not WINDOWS or QuickPascal
+
+endif ;not XENIX
+
+
+;*******************************************************************************
+;
+; List external functions.
+;
+;*******************************************************************************
+
+
+ifdef WINDOWSP
+ extrn DOS3CALL:far
+endif
+
+ifdef WINDOWS
+ extrn __WINFLAGS:abs
+ extrn ALLOCDSTOCSALIAS:far
+ extrn FREESELECTOR:far
+ifdef WF
+ extrn ALLOCSELECTOR:far
+;if we are linking to LIBW from Win 3.0, CS isn't found, use PCS
+ CHANGESELECTOR equ <PRESTOCHANGOSELECTOR>
+ extrn CHANGESELECTOR:far
+endif
+endif
+
+
+ifdef DOS3and5
+ os2extrn DOSGETMACHINEMODE
+endif ;DOS3and5
+
+ifdef DOS5
+
+ ifndef frontend
+ ifndef only87
+ os2extrn DOSWRITE ; only needed to print out "NO87="
+ endif ;only87
+
+ os2extrn DOSCREATECSALIAS
+ os2extrn DOSFREESEG
+ os2extrn DOSDEVCONFIG
+
+ endif ;not frontend
+
+ os2extrn DOSSETVEC
+
+ ifdef MTHREAD
+ os2extrn DOSALLOCSEG
+ os2extrn DOSEXIT
+ extrn __FarGetTidTab:far
+ endif ;MTHREAD
+
+endif ;DOS5
+
+
+;*******************************************************************************
+;
+; Include some more macros and constants.
+;
+;*******************************************************************************
+
+
+ include emdoc.asm
+ include emintern.asm
+
+ifdef MTHREAD
+ include emthread.asm
+endif ;MTHREAD
+
+subttl emulator.asm - Emulator Task DATA Segment
+page
+;*********************************************************************;
+; ;
+; Emulator Task DATA Segment ;
+; ;
+;*********************************************************************;
+
+
+sBegin edata
+
+
+; eventually this needs to be a big struct
+
+glb <REMLSW,InitControlWord,CURerr>
+glb <UserControlWord,UserStatusWord,Have8087>
+glb <ControlWord,CWcntl,StatusWord,SWcc>
+glb <BASstk,CURstk,LIMstk>
+
+;*******************************************************************************
+;
+; Order of information here must not change (for CodeView debugging).
+; Check with CodeView guys before changing.
+;
+;*******************************************************************************
+
+
+ifndef i386
+glb <SignalAddress>
+nedd SignalAddress,<1 dup (?)> ; Error signal address
+endif
+
+Have8087 db 0 ; Is a real 8087 present (0 = no 8087)
+Einstall db 0 ; Emulator installed flag (XENIX sets to 1)
+
+UserControlWord dw ? ; User level control word
+UserStatusWord dw ? ; User level exception status word
+
+ControlWord label word
+ CWmask db ? ; exception masks
+ CWcntl db ? ; arithmetic control flags
+
+StatusWord label word
+ SWerr db ? ; Initially no exceptions (sticky flags)
+ SWcc db ? ; Condition codes from various operations
+
+
+ifdef XENIX
+ nedw BASstk,<?> ; init to BEGstk + 8*Have8087*Reg87Len
+ ; = start of memory (+ 8 regs if 8087)
+ nedw CURstk,<?> ; init to BASstk = start of stack
+ nedw LIMstk,<?> ; ENDstk - 1 reg = end of memory
+
+else ;not XENIX
+ nedw BASstk,<offset BEGstk> ; init to BEGstk + 8*Have8087*Reg87Len
+ ; = start of memory (+ 8 regs if 8087)
+ nedw CURstk,<?> ; init to BASstk = start of stack
+ nedw LIMstk,<offset ENDstk-(2*Reg87Len)> ; ENDstk - 1 reg = end of memory
+endif ;not XENIX
+
+;*******************************************************************************
+;
+; End of fixed area
+;
+;*******************************************************************************
+
+
+ifdef DOS3and5
+glb <protmode>
+protmode dw ? ; Protect mode flag (0 = real)
+endif ;DOS3and5
+
+ifdef POLLING ; used by new POLLING exception code
+ifdef DOS3
+glb <errorcode>
+errorcode db 0 ; error code
+ db 0
+endif ;DOS3
+endif ;POLLING
+
+ifdef QB3
+initCW dw ? ; QB3 initial control word
+endif
+
+InitControlWord equ 1332H ; Default - Affine, Round near,
+ ; 64 bits, all exceptions unmasked
+
+NewStatusWord label word ; space for status after reexecution
+CURerr dw ? ; initially 8087 exception flags clear
+ ; this is the internal flag reset after
+ ; each operation to detect per instruction
+ ; errors
+
+ifndef XENIX
+glb <env_seg>
+env_seg dw ? ; environment segment
+endif
+
+REMLSW dw ? ; sometimes used as a temp
+ dw ? ; (2 or 4 bytes)
+
+
+ifndef XENIX
+
+ ifdef DOS5only
+ NUMVEC= 2 ; coprocesser no present + exception
+ else
+ NUMVEC= 11 ; 8 DS + 1 segovr + 1 fwait + 1 task
+ endif ;DOS5only
+
+ glb <oldvec>
+ oldvec dd NUMVEC dup (0) ; old interrupt vector values
+
+endif
+
+
+;Transcendental working variables
+
+glb <Reg8087ST0,TEMP1>
+
+Reg8087ST0 label word
+TEMP1 dw Reg87Len/2 DUP (?)
+
+
+ifndef frontend
+ifdef DOS5
+SSalias dw ? ; SSalias for exception handler
+endif ;DOS5
+endif ;frontend
+
+ifdef DOS3
+ifndef frontend
+glb <statwd>
+statwd dw 0 ; Location for 8087 status/control word
+endif ;frontend
+endif ;DOS3
+
+ifndef only87
+glb <TEMP2,TEMP3,ARG2,DENORX,COEFFICIENT,RESULT,DAC>
+TEMP2 dw Reg87Len/2 DUP (?)
+TEMP3 dw Reg87Len/2 DUP (?)
+ARG2 dw Reg87Len/2 DUP (?)
+DENORX dw Reg87Len/2 DUP (?)
+COEFFICIENT dw Reg87Len/2 DUP (?)
+nedw RESULT,<?>
+DAC dw MantissaByteCnt/2 DUP (?)
+endif ;only87
+
+ifndef frontend
+ifndef SMALL_EMULATOR
+
+ loopct dw 0 ; data for FPREM emulation
+ bigquot dw 0 ; quotient > 65535 ?
+
+endif ;not SMALL_EMULATOR
+endif ;not frontend
+
+ExtendStack dw 1 ; 1 => extend 80x87 stack
+
+
+ifdef WINDOWS
+
+Installed dw 0 ; Installation flag
+
+ExceptFlag db 0 ; 80x87 exception flag for polling.
+ db 0
+
+ifdef WF
+wfInsn dw 0 ; instruction we overwrote with INT 3d
+wfSel dw 0 ; selector to use for alias
+wfErr dw 0 ; FP error code (YAEC)
+wfGoFast dw 0 ; 1 if we are Enhanced with coproc
+endif
+
+public OldNMIVec
+OldNMIVec dd 0 ; Old value in 8087 exception interrupt vector
+
+endif ;WINDOWS
+
+ifdef LOOK_AHEAD
+NextOpCode db 0 ; first byte of next instruction
+LookAheadRoutine dw 0
+endif
+
+
+
+; Emulator stack area
+
+glb <BEGstk,ENDstk>
+
+BEGstk db Numlev*Reg87Len dup (?) ; emulator stack area
+ENDstk label byte
+
+ifdef MTHREAD
+cvtbufsize= 349 ; see \clib\include\cvt.h
+cvtbuf db cvtbufsize dup (?) ; used by ecvt/fcvt
+ ; routines
+endif ;MTHREAD
+
+ public __fptaskdata
+
+__fptaskdata label byte ; task data pointer and size
+ ; (if linked with user program)
+
+sEnd edata
+
+
+
+subttl emulator.asm
+page
+;*********************************************************************;
+; ;
+; Start of Code Segment ;
+; ;
+;*********************************************************************;
+
+
+sBegin ecode
+
+assumes cs, ecode
+assumes ds, edata
+
+ public __fpemulatorbegin
+__fpemulatorbegin: ; emulator really starts here
+
+
+reservedspace: ; IMPORTANT: Must be EMULATOR_TEXT:0000
+
+ EMver ; IMPORTANT: Emulator version number
+ ; IMPORTANT: EBASIC needs this here!
+
+
+ db 'gfw...GW'
+
+ifdef _COM_
+extrn __EmDataSeg:word
+endif ;_COM_
+
+page
+
+
+ifdef XENIX
+ include emxenix.asm ; XENIX initialization
+
+elseifdef WINDOWS
+ include emwin.asm ; WINDOWS initialization
+
+else ;not XENIX or WINDOWS
+ include emdos.asm ; DOS initialization
+endif ;not XENIX or WINDOWS
+
+ include emstack.asm ; stack management macros
+
+ifndef QB3 ; no exception handling for QB3
+ifndef XENIX ; UNDONE - no exception handling for XENIX
+ifndef frontend
+ include emexcept.asm ; oem independent 8087 exception handling
+endif ;frontend
+endif ;XENIX ; UNDONE - at this time
+endif ;QB3
+
+ include emerror.asm ; error handler
+
+ifndef XENIX ; not used with XENIX
+
+ include emspec.asm ; special emulator/8087 functions
+
+ifndef frontend
+ include emfixfly.asm ; fixup on the fly
+endif ;not frontend
+
+endif ;not XENIX
+
+ifndef only87
+
+ public __fpemulator
+__fpemulator: ; emulator starts here
+
+ include emdisp.asm ; dispatch tables
+ include emconst.asm ; constants
+
+ifdef i386
+ include em386.asm ; 386 emulation/initialization entry
+else
+ include emmain.asm ; main entry and address calculation
+endif
+ include emdecode.asm ; instruction decoder
+
+ include emarith.asm ; arithmetic dispatcher
+ include emfadd.asm ; add and subtract
+ include emfmul.asm ; multiply
+ include emfdiv.asm ; division
+ include emnormal.asm ; normalize and round
+ include emlssng.asm ; load and store single
+ include emlsdbl.asm ; load and store double
+ include emlsint.asm ; load and store integer
+ include emlsquad.asm ; load and store quadword integer
+ include emfrndi.asm ; round to integer
+ include emlstmp.asm ; load and store temp real
+ include emfmisc.asm ; miscellaneous instructions
+ include emfcom.asm ; compare
+ include emfconst.asm ; constant loading
+ include emnew.asm ; new instructions: f<op> ST(i)
+
+ifndef frontend
+ifndef SMALL_EMULATOR
+
+ include emfprem.asm ; partial remainder
+ include emfsqrt.asm ; square root
+ include emftran.asm ; transcendentals
+
+endif ;not SMALL_EMULATOR
+endif ;not frontend
+
+
+endif ;not only87
+
+ public __fpemulatorend
+__fpemulatorend: ; emulator ends here
+
+sEnd ecode
+
+
+ifdef WINDOWS
+ EM_END equ <end LoadTimeInit>
+
+else
+ EM_END equ <end>
+endif
+
+
+EM_END
diff --git a/private/mvdm/wow16/win87em/emulator.hst b/private/mvdm/wow16/win87em/emulator.hst
new file mode 100644
index 000000000..d25235be2
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emulator.hst
@@ -0,0 +1,385 @@
+ subttl emulator.hst - Emulator history.
+;***
+;emulator.hst - Emulator history.
+;
+; Copyright (c) 1984-89, Microsoft Corporation
+;
+;Purpose:
+; Contains history comments for emulator.
+;
+;
+; Bob Wallace, Microsoft, July 1982
+; John Pollock, Microsoft, August 1982
+; Marlin Eller, Microsoft, December 1982
+; Greg Whitten, Microsoft, February 1984
+; Brad Verheiden, Microsoft, March 1984
+; Jamie Bariteau, Microsoft, September 1985
+; Barry McCord, Microsoft, October 1986
+;
+;
+; Revision History
+;
+; 02/07/84 Greg Whitten
+; new stand-alone version (major restructuring)
+; split up into small include files
+;
+; 02/17/84 Brad Verheiden
+; put transcendentals in same object file
+; fixed bug which always masked unemulated instruction
+;
+; 02/24/84 Greg Whitten
+; PASCAL naming convention is being slowly removed
+; adding initialization/termination code
+; code complete for initial standalone emulator
+;
+; 03/14/84 Greg Whitten
+; added a special truncate to 32-bit integer routine
+;
+; 03/15/84 Greg Whitten
+; fixed bug in FCOM ( cmpsw => cmpsb )
+;
+; 03/19/84 Greg Whitten
+; added code for all segment overrides
+;
+; 03/29/84 Greg Whitten
+; fixed segment override bug
+;
+; 04/05/84 Greg Whitten
+; removed fast SP code
+;
+; 04/09/84 Brad Verheiden
+; added 8087 support
+;
+; 05/23/84 Brad Verheiden
+; Added code to save SI in ProcessOverUnderflow
+;
+; 08/18/84 Greg Whitten
+; REEXECUTE stored the status word when DS was invalid
+; if reexecuting a memory operand
+; Terminate8087 bad if original INT 2 vector was 0
+; Changed call to fpsignal routine - now registers
+; except for AX are good. al = error code
+;
+; 08/23/84 Greg Whitten
+; corrected COMPSIDI (COMPcsSIDI)
+; affects routines using log and atan's
+;
+; 08/25/84 Greg Whitten
+; fixed bug with handling of denormals - not reloading
+; zero from the correct address
+;
+; 10/28/84 Greg Whitten
+; added environment segment to initialization for NO87
+; added code to save and restore interrupt vectors
+; 8087 only version
+;
+; 01/30/85 Greg Whitten
+; added OEM version check for automatic setup for 8087
+; this is not necessarily reliable
+;
+; 02/07/85 Greg Whitten
+; split OEM customization out into separate module
+; save and restore old interrupt vector values
+;
+; release C 3.00 and FORTRAN/Pascal 3.30
+;
+; 03/29/85 Greg Whitten
+; changed emulated FWAIT fixups to mov ax,ax
+; changed real 287 FWAIT on numeric instructions to NOPs
+;
+; release IBM C 1.0
+;
+; 08/13/85 Greg Whitten
+; changed fpmath trunc routines to check for errors
+;
+; 08/22/85 Greg Whitten
+; added PUB/GLB macros to define public symbols
+; for debugging
+;
+; 08/22/85 Greg Whitten
+; corrected a bug in denormalizing result with
+; zero mantissa and non-zero exponent
+; changed to zero exponent if mantissa is zero
+;
+; release FORTRAN/Pascal 3.31
+;
+; 09/02/85 Greg Whitten
+; completed adding PUB/GLB macros to define
+; public symbols for debugging
+;
+; 09/09/85 Greg Whitten
+; changed denormal exception handler for
+; faster normalization algorithm using 8087
+; FDIV[R] denormal memory operand
+;
+; 09/13/85 Jamie Bariteau
+; added comments to invalid processing in emexcept.asm
+; fixed bug in constant instruction decoding in emexcept
+; (stand-alone version only)
+;
+; 09/30/85 Jamie Bariteau
+; start of C and FORTRAN 4.0 changes
+; emulator.asm:
+; changed memory temp REG8087ST2 to REG8087ST0
+; since ST(2) is no longer saved to memory but
+; ST(0) is.
+; emexcept.asm:
+; rewrote invalid exception handling to deal with
+; new stack overflow/underflow model
+;
+; 10/30/85 Greg Whitten
+; 11/03/85 more C and FORTRAN 4.0 changes
+; embedded version information for debugger
+; reordered data area
+; deleted unused data items
+; added UserStatusWord for status reporting
+; added __fpmath call for returning status
+; changed denormal handler so precision is not lost
+; on FMUL denormal
+;
+; 11/18/85 Jamie Bariteau
+; more C and Fortran 4.0 changes
+; emulated new set of arithmetic register instructions:
+; f<op> ST,ST(x)
+; f<op> ST(x),ST
+; f<op>p ST,ST(x)
+;
+; 11/19/85 Greg Whitten
+; (hack) change temp real denormals into 0 in normalize
+; some temp real denormals will not be caught
+;
+; 02/11/86 Greg Whitten
+; changed around some conditionals and removed unused
+; conditionals (MSDOS and XENIX)
+;
+; 02/11/86 Greg Whitten
+; created frontend -only version of emulator
+; assumes no 8087 and limited instructions
+; (no transcendentals)
+;
+; 02/12/86 Greg Whitten
+; corrected bug in exception handler with user status
+;
+; 03/20/86 Greg Whitten
+; fixed special arithmetic returns to use RESULT
+;
+; Version 4.00C 4.0
+;
+; 07/15/86 Greg Whitten
+; added dual DOS 5.0 and DOS 3.x support
+; added standalone and DOS 5 conditionals
+;
+; 09/25/86 Greg Whitten
+; added FCOM denormal exception support
+; added pseudo-zero checking to denormal exceptions
+;
+; 10/14/86 Greg Whitten
+; 386 version of the emulator for XENIX
+; added XENIX and i386 conditionals
+;
+; 10/09/86 Jamie Bariteau
+; Changed initialization of LIMstk to allow
+; more space between the end of the emulator
+; stack and DGROUP. The emulator was trashing
+; DS:0 before aborting with fp stack overflow.
+;
+; 10/15/86 Barry McCord
+; fixed no87= message to use DOSWRITE for
+; the DOS3/5 version of the emulator
+;
+; 01/02/87 Barry McCord
+; added FPREM emulation into the DOS3/5 version
+; of the emulator
+;
+; 02/12/87 Barry McCord
+; changed coprocessor detection mask in
+; EMINIT.ASM from 1F3Fh to 0F3Fh to allow
+; for A1 stepping of 80387, in which bit
+; 1000h of the control word remains high.
+;
+; 03/03/87 Greg Whitten
+; added QB3 support (special hacked emulator)
+;
+; 04/01/87 Greg Whitten
+; merged sources for OS/2 and XENIX emulators
+; minor cleanup
+; - removed PCDOS switch
+;
+; Version 5.00
+;
+; 04/09/87 Barry McCord
+; added WINDOWS switch for Windows 2.00 support
+;
+; 05/01/87 Jamie Bariteau
+; moved FPREM data from emfprem.asm to emulator.asm
+; so that fptaskdata marks the end of the data area
+;
+; 05/04/87 Barry McCord
+; changed DOSWRITE to __DOSWRITE, etc.
+; for the DOS 3/5 emulator
+;
+; 05/05/87 Greg Whitten
+; XENIX 286/386 cleanup
+;
+; 05/14/87 Barry McCord
+; added exception handling support to "quiet"
+; the Invalid exception generated by fld (short/long
+; real operand) of an SNaN (only matters for 80387);
+; this was so that the compiler can do FLDs without
+; being concerned whether the (possibly stack-based)
+; floating-point variable has been initialized.
+;
+; 06/19/87 Barry McCord
+; Windows 2.00 support ready for Windows SDK Beta 1
+;
+; 06/24/87 Barry McCord
+; Bug fix (BCP #1767) for FORTRAN 4.01.
+; Exception handler wasn't loading ST(1) from
+; memory when ST(0) was full but ST(1) was not
+; (for instructions taking 2 stack operands).
+;
+; 08/24/87 Barry McCord
+; Added emulation of fild qword ptr
+; and fistp qword ptr for the purpose of supporting
+; unsigned-long-to-float and float-to-unsigned-long
+; conversions for C 5.00.
+;
+; release C 5.00 / QuickC 1.00 / QuickBASIC 4.00
+; 10/19/87
+;
+; Version 5.10
+;
+; 11/07/87 Greg Whitten
+; added PCDOS (ifdef-style) switch back in for IBM Japan
+; added polling-style interrupt handler to eliminate
+; interrupt problem in real mode
+;
+; 11/11/87 Barry McCord
+; Corrected FORTRAN bug fix (06/24/87 above)
+; by changing a JMP instruction in emexcept.asm.
+; Corrected DOS5only initialization in emdos.asm;
+; missing JMP caused CW not to be initialized.
+;
+; 11/12/87 Barry McCord
+; Added OS/2 support for a reentrant/dynalinkable
+; run-time (IBM/Dallas model). Used DOSALLOCSEG
+; to allocate per-thread emulator data areas. The
+; segment selectors are stored in an array and indexed
+; by thread ID.
+;
+; 12/08/87 Greg Whitten
+; put new exception handling code under POLLING switch
+;
+; 01/11/88 Barry McCord
+; eliminated assembler error in i386 version
+; of emfrndi.asm
+;
+; 01/21/88 Barry McCord
+; replaced QB4 switch with _NOSTKEXCHLR, since
+; QB4 updates no longer use the switch
+;
+; 03/16/89 WAJ
+; Fixed bug in emt.lib/87t.lib. __fpsignal was being
+; called with the wrong value.
+;
+; 03/24/89 WAJ
+; Fixed bug in emmt.lib/87mt.lib. In emerror.asm, the
+; address of user's FP signal handler was not being
+; removed from stack.
+;
+; 03/26/89 WAJ
+; Added ifdefs for the SMALL_EMULATOR for BASIC
+;
+; 04/02/89 WAJ
+; Added special emmtsql version that will let SQL
+; switch stacks with emmt.lib.
+;
+; 04/06/89 WAJ
+; Updated win87em.exe
+;
+; 04/07/89 WAJ
+; Moved history from emulator.asm into emulator.hst
+; Moved some macros into emulator.inc
+;
+;
+; 04/09/89 WAJ
+; Added standard header file to most of the emulator files.
+; Added ProfBegin and ProfEnd macros for profiling.
+;
+; 04/10/89 WAJ
+; Added code to emerror.asm and emfixfly.asm to handle EMS
+; segments in ds under Windows when calling the user's floating
+; point excpetion handler.
+;
+; 04/12/89 WAJ Added NOPs to ProfBegin and ProfEnd
+;
+; 04/12/89 WAJ Polling emulator now uses a "retf 2" instead of "iret"
+;
+; 04/27/89 WAJ Made several changes to Windows emulator to support
+; protected Win386. Removed all writes into code segments.
+;
+; 04/28/89 WAJ Added RESIDENTNAME to win87em.def.
+;
+; 04/30/89 WAJ Added several "even" statements to emarith.asm
+;
+; 05/02/89 WAJ Added instruction look ahead and several minor spead ups.
+;
+; 05/12/89 WAJ Added sti to "retf 2" in Windows emulator.
+;
+; 05/16/89 WAJ Fixed bug in look ahead code (emmain.asm). Segment override
+; followed by bp address would use the wrong segment.
+;
+; 05/39/89 WAJ Now includes cmacros.inc. Just used for segments at the
+; moment.
+;
+; 05/39/89 WAJ Added emqp.lib for Quick Pascal to build.
+;
+; 06/05/89 WAJ Fixed bug in BIGNAN (in emarith.asm). Wasn't returning
+; NAN with biggest mantissa.
+;
+; 06/06/89 WAJ "fldz" was not giving the same results as "fld [zero]"
+;
+; 06/12/89 WAJ Changed AllExceptionsHandled in emexcept.asm so that user
+; can mask invalid exceptions.
+;
+; 06/20/89 WAJ win87em.exe is now marked as a Windows 3.0 exe.
+; win87em2.exe is the Windows 2.0 version. win87em.def is
+; now used just to make the win87em.lib implib.
+;
+; 06/02/89 WAJ win87em.exe's version number is now 6.00.03
+;
+; 06/28/89 WAJ Added save/restore to emwin.asm for win87em.exe. Also,
+; added the file win87em.h.
+;
+; 07/05/89 WAJ Removed fixup externals from QuickPascal emulator.
+;
+; 07/18/89 WAJ Added __fpemulatorbegin and __fpemulatorend labels.
+;
+; 08/01/89 WAJ Added check for reg, reg operation to ProcessDenormal in
+; emexcept.asm
+;
+; 09/06/89 WAJ Fixed bug in emfmul.asm. Needed "xor ebp, ebp" after PROD2.
+;
+; 09/21/89 WAJ Started merging in 386 version.
+;
+; 01/22/90 WAJ win87em.dll now check __WINFLAGS to remove STI if pmode.
+; 01/22/90 WAJ win87em.dll version numbers is incremented to 6.00.04.
+;
+; 02/02/90 WAJ Changed "retf 2" in win87em.dll into iret.
+; 02/02/90 WAJ win87em.dll version numbers is incremented to 6.00.05.
+;
+; 02/02/90 WAJ In win87em.dll, skips sti if WF_PMODE and WF_WIN386.
+; 02/02/90 WAJ win87em.dll version numbers is incremented to 6.00.06.
+; 04/06/90 WAJ Fixed win87em.dll exception problems. Version 6.00.07.
+; 04/10/90 WAJ Added fsetpm to init. Added "out f0, 0". Version 6.00.08.
+; 04/11/90 WAJ Win exception handler could set ES=0. Added NUL_JMP.
+; Version 6.00.09.
+; 04/12/90 WAJ Win87em.dll now inits chip for each app. Now uses INT 11h.
+; Version 6.00.10
+; 04/17/90 WAJ Win87em.dll now uses protexception for 286/287 PS/2'ss.
+; Version 6.00.11
+; 05/14/92 JWM Added DonC's WINFAST code; changes to emulator.asm, emerror.asm
+; emfixfly.asm, emwin.asm; also added fwait to "reset" in
+; emwin.asm, to fix 80387 bug.
+;
+;*******************************************************************************
diff --git a/private/mvdm/wow16/win87em/emulator.inc b/private/mvdm/wow16/win87em/emulator.inc
new file mode 100644
index 000000000..f0f5ed7e6
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emulator.inc
@@ -0,0 +1,315 @@
+ subttl emulator.inc - Emulator macros.
+;***
+;emulator.inc - Emulator history.
+;
+; Copyright (c) 1989-89, Microsoft Corporation
+;
+;Purpose:
+; Defines macros for emulator.
+;
+;Revision History
+;
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+
+;*******************************************************************************
+;
+; EMver - defines version tag put in code segment.
+;
+;*******************************************************************************
+
+
+EMver macro
+ db 'MSEM87',major_ver,minor_ver
+ endm
+
+
+;*******************************************************************************
+;
+; Define pub and glb macros to make labels public for debugging.
+;
+;*******************************************************************************
+
+
+ifdef DEBUG
+
+ lab macro name
+ public name
+ name:
+ endm
+
+ pub macro name
+ public name
+ name:
+ endm
+
+ glb macro name
+ irp nm,<name>
+ public nm
+ endm
+ endm
+
+elseifdef WINDOWS ; If windows, make these public for the map file.
+
+ lab macro name
+ public name
+ name:
+ endm
+
+ pub macro name
+ public name
+ name:
+ endm
+
+ glb macro name
+ irp nm,<name>
+ public nm
+ endm
+ endm
+
+else ;DEFAULT
+ lab macro name
+ name:
+ endm
+
+ pub macro name
+ name:
+ endm
+
+ glb macro name
+ endm
+
+endif ;DEFAULT
+
+
+
+;*******************************************************************************
+;
+; Macros and register aliases to keep the 386/8086 versions close.
+;
+;*******************************************************************************
+
+ifdef i386
+
+eWORD macro nam ; 386 macros
+nam label dword
+ endm
+
+nedw macro nam,contents
+nam dd contents
+ endm
+
+nedd macro nam,contents
+nam df contents
+ endm
+
+edw macro contents
+ dd contents
+ endm
+
+edd macro contents
+ df contents
+ endm
+
+
+else ; not i386
+
+eWORD macro nam ; 286 macros
+nam label word
+ endm
+
+nedw macro nam,contents
+nam dw contents
+ endm
+
+nedd macro nam,contents
+nam dd contents
+ endm
+
+edw macro contents
+ dw contents
+ endm
+
+edd macro contents
+ dd contents
+ endm
+
+eax equ ax
+ecx equ cx
+edx equ dx
+ebx equ bx
+esp equ sp
+ebp equ bp
+esi equ si
+edi equ di
+
+iretd equ iret
+
+endif ;not i386
+
+
+;*******************************************************************************
+;
+; Processor opcode byte definitions.
+;
+;*******************************************************************************
+
+fINT equ 0cdh
+fFWAIT equ 9bh
+fESCAPE equ 0d8h
+
+iNOP equ 90h ; byte nop
+
+fES equ 26h ; segment prefix opcodes
+fCS equ 2eh
+fSS equ 36h
+fDS equ 3eh
+
+bIRET equ 0cfh ; "iret"
+
+bRETF equ 0cah ; first byte of "retf 2". Followed by word operand.
+wNOP equ 0c08bh ; word nop. "mov ax, ax"
+
+bEscMask equ 0f8h ; masks all bits but escape
+bMOD equ 0c0h ; MOD bits are the two highest bits
+bRM equ 7h ; R/M bits are the three lowest bits.
+
+
+;*******************************************************************************
+;
+; Define os2extrn and os2call for dual mode emulators
+;
+;*******************************************************************************
+
+
+ifdef DOS3and5
+
+ os2call macro name
+ call __&name
+ endm
+
+ os2extrn macro name
+ extrn __&name : far
+ endm
+
+endif ;DOS3and5
+
+ifdef DOS5only
+
+ os2call macro name
+ call name
+ endm
+
+ os2extrn macro name
+ extrn name : far
+ endm
+
+endif ;DOS5only
+
+
+;*******************************************************************************
+;
+; Define ProfBegin ProfEnd macros for when profiling emulator.
+;
+;*******************************************************************************
+
+ProfBegin macro name
+
+ifdef PROFILE
+ nop
+
+public EM_&name&_BEGIN
+EM_&name&_BEGIN label far
+endif
+ endm
+
+
+ProfEnd macro name
+
+ifdef PROFILE
+public EM_&name&_END
+EM_&name&_END label far
+
+ nop
+endif
+ endm
+
+
+;*******************************************************************************
+;
+; Define IntDOS macro for handling "int 21h" and "call DOS3CALL".
+;
+;*******************************************************************************
+
+
+IntDOS macro
+
+ifdef WINDOWSP
+ call DOS3CALL
+else
+ int 21h
+endif
+ endm
+
+
+;*******************************************************************************
+;
+; Define constants for DOS int 21h
+;
+;*******************************************************************************
+
+
+DOS_getvector equ 35H
+
+
+
+INT_GetEquipList equ 11h ; PC BIOS equipment list call.
+GEL_80x87 equ 2h ; Mask for Coprocessor sense switch.
+
+
+;*******************************************************************************
+;
+; Define structures for __WinInfo(), __WinSave(), and __WinRestore().
+;
+;*******************************************************************************
+
+WinInfoStruct struc
+
+ WI_Version dw ? ; High byte is major version.
+ WI_SizeSaveArea dw ? ; Size of save area.
+ WI_WinDataSeg dw ?
+ WI_WinCodeSeg dw ?
+ WI_Have80x87 dw ?
+ WI_Unused dw ? ; Coprocessor type will go here.
+
+WinInfoStruct ends
+
+
+Size80x87Area equ 94
+
+
+WinSaveArea struc
+
+ WSA_Save80x87 db Size80x87Area dup(?) ; Where 80x87 info will go.
+ WSA_SaveEm db ? ; Where emulator data will go.
+
+WinSaveArea ends
+
+
+
+;*******************************************************************************
+;
+; Define constants for checking "extrn __WINFLAGS:asb"
+;
+;*******************************************************************************
+
+
+WF_PMODE equ 1
+WF_CPU286 equ 2
+WF_CPU386 equ 4
+WF_WIN286 equ 10h
+WF_WIN386 equ 20h
+WF_80x87 equ 400h
diff --git a/private/mvdm/wow16/win87em/emwin.asm b/private/mvdm/wow16/win87em/emwin.asm
new file mode 100644
index 000000000..adadcb265
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emwin.asm
@@ -0,0 +1,745 @@
+ page ,132
+ subttl emwin.asm - Initialization and Termination for Windows
+;***
+;emwin.asm - Initialization and Termination for Windows
+;
+; Copyright (c) 1987-89, Microsoft Corporation
+;
+;Purpose:
+; Initialization and Termination for Windows
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+;Revision History:
+; See emulator.hst
+;
+;*******************************************************************************
+
+
+comment !
+
+Windows/DOS interfaces to emulator/8087 functions
+
+Certain emulator/8087 functions are performed by calling __fpmath
+with an function code and arguments.
+
+__fpmath general floating point math package interface used
+ by the emulator/8087 and float calls interfaces. This
+ is a far routine and must be far called.
+
+entry:
+
+ bx = 0 initialize floating point math (program startup)
+ dx, ax, si input values ignored in WINDOWS emulator
+ returns:
+ ax = 0 if successful and using software floating point
+ 1 if successful and using 8087
+ just terminates process if error
+
+ bx = 1 reset (FINIT) - finit ok even under WINDOWS;
+ typical usage will load control word afterward
+ so other tasks won't be hindered (as with _fpreset() call)
+
+ bx = 2 terminate floating point math (program termination)
+
+ bx = 3 set error signal address
+ dx:ax = segment:offset of user error handler
+
+ bx = 4 load user control word
+ (user should not use FLDCW instruction directly)
+ ax = user control word value
+
+ bx = 5 store user control word
+ returns:
+ ax = user control word value
+
+ bx = 6 truncate TOS to integer TOS
+ ax = user control word (only use round mode)
+
+ bx = 7 truncate TOS to 32-bit integer in DX:AX
+ ax = user control word (only use round mode)
+
+ bx = 8 store user status word
+ returns:
+ ax = user status word value
+
+ bx = 9 clear exceptions
+
+ bx = 10 return number of stack elements in ax
+
+ bx = 11 returns 1 if using 80x87, 0 if not
+
+ bx = 12 if ax = 0, turn off extended stack. if ax = 1, turn on e.s.
+
+!
+
+
+glb <functab>
+
+functab label word
+
+ dw initialization ; 0 - initialize emulator/8087
+ dw reset ; 1 - reset emulator/8087 stack
+ dw termination ; 2 - terminate emulator/8087
+ dw setsignal ; 3 - set error signal address
+ dw loadcontrolword ; 4 - load user control word
+ dw storecontrolword ; 5 - store user control word
+ dw truncateTOS ; 6 - truncate TOS to integer TOS
+ dw truncateTOSto32int ; 7 - truncate TOS to integer in DX:AX
+ dw storestatusword ; 8 - store user status word
+ dw clearexceptions ; 9 - clear execeptions
+ dw NumStack ; 10 - report number of elements in stack
+ dw ReturnHave8087 ; 11 - report if using coprocessor
+ dw SetExtendedStack ; 12 - turn on or off extended stack
+endfunc label word
+
+SizeJmpTab equ 12
+
+sEnd ecode
+
+
+sBegin ecode
+
+assumes cs, ecode
+assumes ds, edata
+
+
+
+public __fpmath
+
+__fpmath proc far
+
+ cmp bx, SizeJmpTab
+ ja RetFPErr
+
+ shl bx, 1
+ push ds ; save DS
+
+ mov cx, EMULATOR_DATA
+ mov ds, cx
+
+ call functab[bx]
+
+ pop ds ; restore DS
+
+EmuRet:
+ ret
+
+
+RetFPErr:
+ or ax, -1
+ cwd
+ jmp EmuRet
+
+__fpmath endp
+
+
+
+
+subttl emwin.asm - Initialization and Termination
+page
+;*********************************************************************;
+; ;
+; Initialization and Termination ;
+; ;
+;*********************************************************************;
+
+wastetime macro
+ push cx
+ mov cx,20 ;; wait for a short time
+ loop $
+ pop cx
+endm
+
+
+
+; program initialization
+;
+; entry dx:ax = task data area (segment and size) for standalone
+; si = DOS environment segment for NO87 lookup ???
+; DX,AX,SI - ignored in WINDOWS case
+; these register inputs are ignored for Windows app
+; program-time initialization
+
+pub initialization ; all initialization is done when loaded
+
+ifdef WF
+ cmp [Installed],0
+ jnz @F
+ .286p
+ push 0
+ call AllocSelector
+ mov [wfSel], ax ; Error checking??
+ mov ax, __WINFLAGS
+; int 3
+ test ax, WF_WIN386
+ jz wfSlow1
+ cmp [Have8087], 0
+ je wfSlow1
+ or [wfGoFast], 1 ; We can use fast if Enh Mode & FPU
+wfSlow1:
+@@:
+endif
+ inc [Installed] ; Installed will count number of apps
+ ; using the emulator.
+
+ cmp [Have8087], 0 ; check for 8087/80287
+ je NoInstall87
+
+ extrn __FPINSTALL87:near
+ call __FPINSTALL87 ; set NMI (int 2) for this instance
+NoInstall87:
+
+ call reset
+ xor ax, ax
+
+ ret
+
+
+
+
+ifdef standalone
+ mov di,offset BEGstk ; di = base of register stack
+ mov [BASstk],di ; initialize stack base
+ mov cx,Reg87Len ; cx = register length
+ xchg ax,dx ; ax = task data segment size
+ sub ax,di ; ax = number bytes for stack
+ cwd ; dx:ax = number of bytes
+ div cx ; ax = number of entries
+ mul cx ; ax = number of bytes
+ add ax,di ; ax = top of stack
+ sub ax,cx ; Leave room for one on overflow
+ mov [LIMstk],ax ; set top of stack
+endif ;standalone
+
+
+
+; check if floating point emulator/8087 already installed (device driver)
+
+
+
+ ; load time initialization
+
+pub LoadTimeInit
+
+ push di
+ push si
+ push ds
+ mov ax,EMULATOR_DATA
+ mov ds,ax
+
+ mov ax, __WINFLAGS
+ and ax, WF_80x87
+ cmp ax, WF_80x87
+ jz WinHave87
+
+ifdef only87
+ jmp loadiniterrorret
+endif
+ jmp WinSet87
+
+pub WinHave87
+ mov al,1
+
+pub WinSet87
+ mov [Have8087],al
+
+ ; real mode emulation and fixup on the fly vector setup
+
+pub initvec
+ call SaveVectors
+ call SetVectors
+
+
+pub loadinitfinish
+
+
+ ; finish initialization
+
+pub initfinish
+
+ mov [Installed], 0 ; Installed will count number of apps
+
+ call reset ; reset (0), FINIT if 8087 present and
+ ; set up default control word
+
+ mov ax, 1 ; return non zero result
+
+pub loadiniterrorret
+
+ pop ds
+ pop si
+ pop di
+ retf ; far return for dynalink lib entry pt.
+
+
+;*
+;* DLL termination routine.
+;*
+
+public WEP
+WEP label far
+
+ push ds
+ push ax
+
+ push si
+ push di
+
+ mov ax,EMULATOR_DATA
+ mov ds,ax
+
+ call reset
+ call RestoreVectors
+
+ pop di
+ pop si
+ pop ax
+ pop ds
+
+ retf 2 ; WEP functions are called with a word paramater.
+
+
+;------ program termination ----------------------------------------------------
+
+pub termination
+
+ call reset ; reset chip for other apps
+
+ dec [Installed] ; if Installed is not 0, someone is
+ jnz termrealdone ; still using the emulator.
+
+ifdef WF
+ xor ax, ax
+ xchg ax, [wfSel]
+ or ax, ax
+ jz @F
+ push ax
+ call FreeSelector
+@@:
+endif
+
+ifndef only87
+ cmp [Have8087],0 ; Non zero if 8087 chip exists
+ je termrealdone
+endif ;only87
+
+ extrn __FPTERMINATE87:near ; reset NMI (int 2) for this instance
+ call __FPTERMINATE87
+
+pub termrealdone
+ ret
+
+
+
+
+subttl emwin.asm - reset and clearexceptions
+page
+;*********************************************************************;
+; ;
+; Reset and Clearexceptions ;
+; ;
+;*********************************************************************;
+
+pub reset
+
+ifndef only87
+ cmp [Have8087],0 ; Nonzero if 8087 chip exists
+ je NoFINIT
+endif ;only87
+ fninit
+ fwait ; Workaround for 80387 bug.
+ fninit
+
+pub NoFINIT
+ mov ax, [BASstk]
+ mov [CURstk], ax ; reset stack to bottom
+
+ mov ax, InitControlWord ; setup initial control word
+ call loadcontrolword
+
+
+ ; fall into clearexceptions
+
+
+pub clearexceptions
+
+ xor ax, ax
+ifndef only87
+ cmp al, [Have8087] ; Nonzero if 8087 chip exists
+ je NoFCLEX
+endif ;only87
+ fclex ; clear exceptions
+
+pub NoFCLEX
+ifndef only87
+ mov [StatusWord], ax ; clear status word
+endif ;only87
+ mov [UserStatusWord], ax ; clear exception status word
+
+ ret
+
+
+
+subttl emwin.asm - setsignal ---------------------------------
+page
+;*********************************************************************;
+; ;
+; Setsignal ;
+; ;
+;*********************************************************************;
+
+
+pub setsignal
+
+ push ds
+
+ mov ds, dx ; set TSKINT to SignalAddress
+ mov dx, ax
+ mov ax, 25h*256 + TSKINT
+ IntDOS
+
+ pop ds
+ ret
+
+
+pub SaveVectors
+
+ mov cx, NUMVEC ; save old vectors under DOS 3
+ mov ax, 35h*256 + BEGINT ; get vector
+ mov di, offset oldvec ; di = old vector table
+
+pub getvecs
+ IntDOS
+ inc ax
+ mov [di], bx ; save old vector
+ mov [di+2], es
+ add di, 4
+ loop getvecs
+
+ ret
+
+pub SetVectors
+
+ifndef only87
+ mov dx, offset DStrap ; assume emulator
+ mov si, offset SOtrap
+ mov di, offset FWtrap
+ifdef WINDOWS
+ mov ax, __WINFLAGS ; if we are in PMODE & win386 increment all of
+ and ax, WF_PMODE or WF_WIN386 ; the handler address past the "sti".
+ cmp ax, WF_PMODE or WF_WIN386
+ jne NotPmode1
+
+ inc dx
+ inc si
+ inc di
+lab NotPmode1
+endif ;WINDOWS
+
+ cmp [Have8087], 0 ; are we using 8087 ?
+ jz SetEmVecs ; no - go ahead and set them
+endif ;only87
+
+ mov dx, offset DSFixUpOnFly ; set up for fixup-on-the-fly
+ mov si, offset SOFixUpOnFly
+ mov di, offset FWFixUpOnFly
+ifdef WINDOWS
+ mov ax, __WINFLAGS ; if we are in PMODE & win386 increment all of
+ and ax, WF_PMODE or WF_WIN386 ; the handler address past the "sti".
+ cmp ax, WF_PMODE or WF_WIN386
+ jne NotPmode2
+
+ inc dx
+ inc si
+ inc di
+lab NotPmode2
+endif ;WINDOWS
+
+pub SetEmVecs
+ push ds
+
+ push cs
+ pop ds
+ mov ax, 25h*256 + BEGINT
+ mov cx, 8 ; 8 vectors for DStrap
+
+pub SetDSLoop
+ IntDOS ; set vector
+ inc ax ; bump to next one
+ loop SetDSLoop
+
+ mov dx, si ; set Segtrap
+ IntDOS
+ inc ax
+ mov dx, di ; set FWtrap
+ IntDOS
+
+ pop ds ; restore task data area
+
+ ret
+
+
+pub RestoreVectors
+
+ mov cx, NUMVEC
+ mov ax, 25h*256 + BEGINT ; Dos set vector.
+ mov di, offset oldvec ; di = old vector table
+
+pub ResetVecLoop
+ push ds
+ lds dx, [di] ; get old vector value
+ IntDOS
+ pop ds
+ inc ax
+ add di,4
+
+ loop ResetVecLoop
+
+ ret
+
+
+
+pub NumStack ; returns the number of stack elements in ax
+
+ xor dx, dx ; dx will count nonzero elements
+
+ifndef only87
+ cmp Have8087, 0
+ je CountEmulatorStack
+endif ;only87
+
+ sub sp, 14 ; need 14 bytes for fstenv
+ mov bx, sp
+ fstenv ss:[bx]
+ fldcw ss:[bx] ; reset control word
+ mov ax, ss:[bx+4] ; put tag word in ax
+ add sp, 14 ; reset stack
+
+ mov cx, 8
+pub NotEmptyLoop
+ mov bx, ax
+
+ shr ax, 1
+ shr ax, 1
+
+ and bx, 3
+ cmp bx, 3
+ je StackEntryEmpty
+
+ inc dx ; stack element was not empty
+pub StackEntryEmpty
+ loop NotEmptyLoop
+
+
+pub CountEmulatorStack
+
+ mov ax, CURstk
+ sub ax, BASstk
+
+ mov bl, Reg87Len
+
+ div bl
+
+ add ax, dx ; add elements on 80x87 stack
+
+ ret
+
+
+ReturnHave8087 proc near
+
+ mov al, [Have8087]
+ cbw
+
+ ret
+ReturnHave8087 endp
+
+
+SetExtendedStack proc near
+
+ mov [ExtendStack], ax
+
+ ret
+SetExtendedStack endp
+
+
+
+;***
+;int far pascal __Win87EmInfo( WinInfoStruct far * p, int cb );
+;
+;Purpose:
+; returns information about win87em.exe to CodeView
+;
+;Entry:
+; WinInfoStruct far * p
+; int cb - size of WinInfoStruct
+;
+;Exit:
+; returns non zero if error.
+;
+;
+;Uses:
+;
+;Exceptions:
+;
+;*******************************************************************************
+
+
+cProc __WIN87EMINFO,<PUBLIC,FAR,PLM>,<ds>
+
+ parmD p
+ parmW cb
+
+cBegin
+ or ax, -1
+ cmp [cb], size WinInfoStruct
+ jb WIDone
+
+ mov ax, edataBASE
+ mov es, ax
+ assumes es, edata
+
+ lds bx, [p]
+ assumes ds, nothing
+
+ mov [bx.WI_Version], (major_ver shl 8) + minor_ver
+ mov [bx.WI_SizeSaveArea], Size80x87Area + edataOFFSET __fptaskdata
+ mov [bx.WI_WinDataSeg], es
+ mov [bx.WI_WinCodeSeg], cs
+
+ mov al, [Have8087]
+ cbw
+ mov [bx.WI_Have80x87], ax
+ assumes es, nothing
+
+ xor ax, ax ; return 0 if no error
+ mov [bx.WI_Unused], ax
+WIDone:
+cEnd
+
+
+;***
+;int far pascal __Win87EmSave( void far * p, int cb );
+;
+;Purpose:
+; saves win87em.exe info in p
+;
+;Entry:
+; void far * p - pointer to save area.
+; int cb - size of save area.
+;
+;Exit:
+; returns non zero if error.
+;
+;Uses:
+;
+;Exceptions:
+;
+;*******************************************************************************
+
+
+cProc __WIN87EMSAVE,<PUBLIC,FAR,PLM>,<ds,si,di>
+
+ parmD p
+ parmW cb
+
+cBegin
+ or ax, -1
+ cmp [cb], Size80x87Area + edataOFFSET __fptaskdata
+ jb WSDone
+
+ mov ax, edataBASE
+ mov ds, ax
+assumes ds, edata
+
+ les di, [p]
+assumes es, nothing
+
+ cmp [Have8087], 0
+ je NoSave80x87
+
+ fsave es:[di.WSA_Save80x87]
+NoSave80x87:
+
+ add di, (WSA_SaveEm - WSA_Save80x87)
+ xor si, si
+ mov cx, edataOFFSET __fptaskdata
+ shr cx, 1
+
+ rep movsw
+
+ jnc NoSaveLastByte
+ movsb
+NoSaveLastByte:
+
+ xor ax, ax ; return 0 if no error.
+
+WSDone:
+cEnd
+
+
+
+;***
+;int far pascal __Win87EmRestore( void far * p, int cb );
+;
+;Purpose:
+; retores win87em.exe info from p
+;
+;Entry:
+; void far * p - pointer to save area.
+; int cb - size of save area.
+;
+;Exit:
+; returns non zero if error.
+;
+;Uses:
+;
+;Exceptions:
+;
+;*******************************************************************************
+
+
+cProc __WIN87EMRESTORE,<PUBLIC,FAR,PLM>,<ds,si,di>
+
+ parmD p
+ parmW cb
+
+cBegin
+ or ax, -1
+ cmp [cb], Size80x87Area + edataOFFSET __fptaskdata
+ jb WRDone
+
+ mov ax, edataBASE
+ mov es, ax
+assumes es, edata
+
+ lds si, [p]
+assumes ds, nothing
+
+ add si, (WSA_SaveEm - WSA_Save80x87)
+ xor di, di
+ mov cx, edataOFFSET __fptaskdata
+ shr cx, 1
+
+ rep movsw
+
+ jnc NoRestoreLastByte
+ movsb
+NoRestoreLastByte:
+
+ mov si, [OFF_p] ; reset source pointer.
+
+ cmp [Have8087], 0
+ je NoRestore80x87
+
+ frstor [si.WSA_Save80x87]
+NoRestore80x87:
+
+ xor ax, ax ; return 0 if no error.
+
+WRDone:
+cEnd
+
+assumes ds, edata
+assumes es, nothing
diff --git a/private/mvdm/wow16/win87em/emxenix.asm b/private/mvdm/wow16/win87em/emxenix.asm
new file mode 100644
index 000000000..1fe2a55a0
--- /dev/null
+++ b/private/mvdm/wow16/win87em/emxenix.asm
@@ -0,0 +1,61 @@
+
+;
+;
+; Copyright (C) Microsoft Corporation, 1986
+;
+; This Module contains Proprietary Information of Microsoft
+; Corporation and should be treated as Confidential.
+;
+subttl emxenix.asm - XENIX function jump tables and Initialization
+page
+
+
+ public __eminit, __emulate, __87exception
+
+
+ org 10h
+
+__eminit: ; UNDONE - not used any more
+
+
+ org 15h
+
+__emulate:
+ jmp protemulation ; protect mode emulation
+
+
+ org 1Ah
+
+__87exception:
+ pop eax ; eax = error code
+ int 0FFh
+
+page
+;------------------------------------------------------------------------------
+;
+; install emulator (initial all data elements
+;
+; This routine is executed once for the 1st emulated instruction
+;
+;------------------------------------------------------------------------------
+
+
+pub installemulator
+
+ mov [Einstall],1 ; mark emulator as initialized
+
+ mov eax,offset BEGstk ; pointer to beginning of stack
+ mov [BASstk],eax ; set base of stack
+ mov [CURstk],eax ; set current stack element
+ mov eax,offset ENDstk-Reg87Len
+ mov [LIMstk],eax ; set end of stack
+
+ mov ax,InitControlWord
+ mov [UserControlWord],ax ; initialize control words
+ mov [ControlWord],ax
+
+ xor eax,eax
+ mov [UserStatusWord],ax ; initialize status words
+ mov [StatusWord],ax
+
+ jmp protemcont ; continue emulating 1st instruction
diff --git a/private/mvdm/wow16/win87em/key b/private/mvdm/wow16/win87em/key
new file mode 100644
index 000000000..a5d0d3a94
--- /dev/null
+++ b/private/mvdm/wow16/win87em/key
@@ -0,0 +1,22 @@
+Key to emulator lib naming convention
+-------------------------------------
+prefixes:
+ p - fwait POLLING (POLLING switch defined)
+ i - IBM clone version (PCDOS switch defined)
+ n - no ctl-C hooking (_NOCTRLC switch defined, formerly: _QC)
+ s - standalone version (standalone defined)
+ a - always set exc vector for QC, even if NO87 (_NO87INSTALL switch defined)
+ k - no stacK overflow/underflow exception handler (_NOSTKEXCHLR switch)
+ fe - compiler/codeview version (frontend switch defined)
+ qb3 - QuickBASIC 3.0 version (QB3 switch defined)
+
+root file:
+ em - emulator
+ 87 - coprocessor
+ emoem - real mode installation/termination (OEM-configurable)
+
+suffixes:
+ r - real mode (no special switches, for DOS only)
+ p - protected mode (DOS5only switch defined, for OS/2 only)
+ <none> - dual mode (DOS5 switch defined, for DOS and OS/2)
+ mt - multithread protected mode (MTHREAD, OS2only switches, for OS/2 only)
diff --git a/private/mvdm/wow16/win87em/makefile b/private/mvdm/wow16/win87em/makefile
new file mode 100644
index 000000000..a671172b5
--- /dev/null
+++ b/private/mvdm/wow16/win87em/makefile
@@ -0,0 +1,720 @@
+################################################################################
+#
+#
+# This is the makefile for all of the emulators.
+#
+#
+#Revision History:
+#
+# 03-26-89 WAJ Added small emulators and emfull.asm to build
+# 04-02-89 WAJ Added build for sepcial version of emmt.lib (emmtsql.lib) for SQL
+# 04-06-89 WAJ Added win87em.exe and win87em.lib to build.
+# 04-07-89 WAJ Added emulator.inc to EMASM list.
+# 04-14-89 WAJ Ifdefed MATHDIR.
+# 05-16-89 WAJ Added /nologo to $(LIB)
+# 05-16-89 WAJ Changed $(LIB) to $(LIBEXE)
+# 05-16-89 WAJ win87em.exe now made with $(LINK4)
+# 05-30-89 WAJ Added emqp.lib to makefile.
+# 05-02-89 WAJ Added $(AQ) to masm build line.
+# 06-20-89 WAJ Changed build to make Win 3.0 version of win87em.exe
+# 06-26-89 WAJ Removed emfull.obj from build.
+# 06-28-89 WAJ Changed name of Win2 win87em.exe map file to win87em.ma2
+# 04-20-90 WAJ Math project name is now mrt6.
+# 04-26-90 WAJ Math project name is now mrt7.
+# 10-16-90 WAJ Now use libw.lib not swinlibc.lib
+# 09/09/91 JCR Now builds emoem.src, OEM version of emoem.asm.
+# 05/14/92 JWM Added "WF" to WINFLAGS (DonC's WINFAST changes).
+# 06/29/92 JWM Now builds in DOS; math project name is now mrt8.
+# 03/19/94 JWM Links win87em.dll with /align:16, for Chicago
+# 03/31/94 JWM "WF" removed from WINFLAGS!!
+#
+################################################################################
+
+
+.SUFFIXES:
+
+
+!IFNDEF MATHDIR
+MATHDIR = \mrt8
+!ENDIF
+
+SRCDIR = .
+OBJDIR = .\objs
+TOOLDIR = ..\tools
+INCDIR = ..\include
+
+ASM = $(TOOLDIR)\masm510a -DLOOK_AHEAD $(AQ)
+
+IFSTRIP = $(TOOLDIR)\ifstrip
+LIBEXE = $(TOOLDIR)\lib /nologo
+LINK4 = $(TOOLDIR)\link4
+LINK = $(TOOLDIR)\link
+IMPLIB = $(TOOLDIR)\implib
+RC = $(TOOLDIR)\rc -x
+
+
+all: em 87 piem pi87 pem p87 emmt frontend basici basicij qc emt 87t pisem \
+ psem emoem
+
+
+basic: piem pi87 basici pisem
+basicj: pem p87 basicij psem
+
+win: win87em
+
+###############################################################################
+#
+# These are the emulator's asm files
+#
+###############################################################################
+
+
+
+EMASM = \
+ $(SRCDIR)\emulator.inc \
+ $(SRCDIR)\apisim.asm \
+ $(SRCDIR)\em386.asm \
+ $(SRCDIR)\emarith.asm \
+ $(SRCDIR)\emconst.asm \
+ $(SRCDIR)\emdecode.asm \
+ $(SRCDIR)\emdisp.asm \
+ $(SRCDIR)\emdoc.asm \
+ $(SRCDIR)\emdos.asm \
+ $(SRCDIR)\emds.asm \
+ $(SRCDIR)\emerror.asm \
+ $(SRCDIR)\emexcept.asm \
+ $(SRCDIR)\emfadd.asm \
+ $(SRCDIR)\emfcom.asm \
+ $(SRCDIR)\emfconst.asm \
+ $(SRCDIR)\emfdiv.asm \
+ $(SRCDIR)\emfixfly.asm \
+ $(SRCDIR)\emfmisc.asm \
+ $(SRCDIR)\emfmul.asm \
+ $(SRCDIR)\emfprem.asm \
+ $(SRCDIR)\emfrndi.asm \
+ $(SRCDIR)\emfsqrt.asm \
+ $(SRCDIR)\emftran.asm \
+ $(SRCDIR)\emintern.asm \
+ $(SRCDIR)\emlsdbl.asm \
+ $(SRCDIR)\emlsint.asm \
+ $(SRCDIR)\emlsquad.asm \
+ $(SRCDIR)\emlssng.asm \
+ $(SRCDIR)\emlstmp.asm \
+ $(SRCDIR)\emmain.asm \
+ $(SRCDIR)\emnew.asm \
+ $(SRCDIR)\emnormal.asm \
+ $(SRCDIR)\emoem.asm \
+ $(SRCDIR)\emoemqb.asm \
+ $(SRCDIR)\emspec.asm \
+ $(SRCDIR)\emstack.asm \
+ $(SRCDIR)\emthread.asm \
+ $(SRCDIR)\emu8087.asm \
+ $(SRCDIR)\emulator.asm \
+ $(SRCDIR)\emwin.asm \
+ $(SRCDIR)\emxenix.asm
+
+
+
+
+###############################################################################
+#
+#
+# This is how to build the normal emulators
+# ie no fwait polling
+# no IBM bios checks
+#
+###############################################################################
+
+em: $(OBJDIR)\em.lib $(OBJDIR)\emr.lib $(OBJDIR)\emp.lib
+
+87: $(OBJDIR)\87.lib $(OBJDIR)\87r.lib $(OBJDIR)\87p.lib
+
+
+$(OBJDIR)\em.lib: $(OBJDIR)\em.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\em.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\emr.lib: $(OBJDIR)\emr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\emp.lib: $(OBJDIR)\emp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emp.obj;
+
+
+$(OBJDIR)\87.lib: $(OBJDIR)\87.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\87r.lib: $(OBJDIR)\87r.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87r.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\87p.lib: $(OBJDIR)\87p.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87p.obj;
+
+
+$(OBJDIR)\em.obj: $(EMASM)
+ $(ASM) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\emr.obj: $(EMASM)
+ $(ASM) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\emp.obj: $(EMASM)
+ $(ASM) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\87.obj: $(EMASM)
+ $(ASM) -DDOS5 $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\87r.obj: $(EMASM)
+ $(ASM) $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\87p.obj: $(EMASM)
+ $(ASM) -DDOS5only $(SRCDIR)\emu8087.asm, $@;
+
+
+$(OBJDIR)\emoem.obj: $(SRCDIR)\emoem.asm
+ $(ASM) $(SRCDIR)\emoem.asm, $@;
+
+
+
+
+###############################################################################
+#
+#
+# This is how to build the IBM emulators
+# ie with fwait polling
+# with IBM bios checks
+#
+###############################################################################
+
+
+IBMFLAGS =-DPOLLING -DPCDOS
+
+piem: $(OBJDIR)\piem.lib $(OBJDIR)\piemr.lib $(OBJDIR)\piemp.lib
+
+pi87: $(OBJDIR)\pi87.lib $(OBJDIR)\pi87r.lib $(OBJDIR)\pi87p.lib
+
+
+$(OBJDIR)\piem.lib: $(OBJDIR)\piem.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\piem.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\piemr.lib: $(OBJDIR)\piemr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\piemr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\piemp.lib: $(OBJDIR)\piemp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\piemp.obj;
+
+
+$(OBJDIR)\pi87.lib: $(OBJDIR)\pi87.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pi87.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pi87r.lib: $(OBJDIR)\pi87r.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pi87r.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pi87p.lib: $(OBJDIR)\pi87p.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pi87p.obj;
+
+
+$(OBJDIR)\piem.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\piemr.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\piemp.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\pi87.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) -DDOS5 $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\pi87r.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\pi87p.obj: $(EMASM)
+ $(ASM) $(IBMFLAGS) -DDOS5only $(SRCDIR)\emu8087.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build the multi thread version of the emulator
+#
+###############################################################################
+
+
+MTFLAGS = -DMTHREAD -DDOS5only
+
+emmt: $(OBJDIR)\emmt.lib $(OBJDIR)\87mt.lib
+
+
+
+$(OBJDIR)\emmt.lib: $(OBJDIR)\emmt.obj $(OBJDIR)\emds.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emmt.obj + $(OBJDIR)\emds.obj;
+
+$(OBJDIR)\87mt.lib: $(OBJDIR)\87mt.obj $(OBJDIR)\emds.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87mt.obj + $(OBJDIR)\emds.obj;
+
+
+$(OBJDIR)\emmt.obj: $(EMASM)
+ $(ASM) $(MTFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\87mt.obj: $(EMASM)
+ $(ASM) $(MTFLAGS) $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\emds.obj: $(SRCDIR)\emds.asm
+ $(ASM) $(SRCDIR)\emds.asm, $@;
+
+
+
+
+
+###############################################################################
+#
+#
+# This is how to build the front end emulators
+#
+###############################################################################
+
+
+FRONTENDFLAGS = -Dfrontend
+
+frontend: $(OBJDIR)\feemr.obj $(OBJDIR)\feem.obj $(OBJDIR)\feemp.obj
+
+
+$(OBJDIR)\feem.obj: $(EMASM)
+ $(ASM) $(FRONTENDFLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\feemr.obj: $(EMASM)
+ $(ASM) $(FRONTENDFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\feemp.obj: $(EMASM)
+ $(ASM) $(FRONTENDFLAGS) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build fwait polling versions of the emulators
+# ie with fwait polling
+# no IBM bios check
+#
+#
+###############################################################################
+
+
+POLLINGFLAGS = -DPOLLING
+
+pem: $(OBJDIR)\pem.lib $(OBJDIR)\pemr.lib $(OBJDIR)\pemp.lib
+p87: $(OBJDIR)\p87.lib $(OBJDIR)\p87r.lib $(OBJDIR)\p87p.lib
+
+
+$(OBJDIR)\pem.lib: $(OBJDIR)\pem.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pem.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pemr.lib: $(OBJDIR)\pemr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pemr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pemp.lib: $(OBJDIR)\pemp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pemp.obj;
+
+
+$(OBJDIR)\p87.lib: $(OBJDIR)\p87.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\p87.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\p87r.lib: $(OBJDIR)\p87r.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\p87r.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\p87p.lib: $(OBJDIR)\p87p.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\p87p.obj;
+
+
+$(OBJDIR)\pem.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\pemr.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\pemp.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\p87.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) -DDOS5 $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\p87r.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\p87p.obj: $(EMASM)
+ $(ASM) $(POLLINGFLAGS) -DDOS5only $(SRCDIR)\emu8087.asm, $@;
+
+
+
+
+###############################################################################
+#
+#
+# This is how to build the QC emulator
+# ie stand alone
+# no control c hooking
+#
+###############################################################################
+
+
+QCFLAGS = -DSTANDALONE -D_NO87INSTALL -D_NOCTRLC
+
+qc: $(OBJDIR)\sanemr.lib
+
+
+$(OBJDIR)\sanemr.lib: $(OBJDIR)\saemr.obj $(OBJDIR)\anemoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\saemr.obj + $(OBJDIR)\anemoem.obj;
+
+
+
+$(OBJDIR)\saemr.obj: $(EMASM)
+ $(ASM) $(QCFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\anemoem.obj: $(SRCDIR)\emoem.asm
+ $(ASM) $(QCFLAGS) $(SRCDIR)\emoem.asm, $@;
+
+
+###############################################################################
+#
+#
+# This is how to build the BASIC interpreter's emulators
+# ie fwait polling
+# IBM bios check
+# no control c hooking
+#
+# Note. Basic also uses the piem?.lib and pi87?.lib
+#
+###############################################################################
+
+
+BASICINTFLAGS = -D_NOCTRLC
+
+basici: $(OBJDIR)\pinemr.lib $(OBJDIR)\pin87r.lib
+
+
+$(OBJDIR)\pinemr.lib: $(OBJDIR)\piemr.obj $(OBJDIR)\nemoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\piemr.obj + $(OBJDIR)\nemoem.obj;
+
+$(OBJDIR)\pin87r.lib: $(OBJDIR)\pi87r.obj $(OBJDIR)\nemoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pi87r.obj + $(OBJDIR)\nemoem.obj;
+
+
+$(OBJDIR)\nemoem.obj: $(SRCDIR)\emoem.asm
+ $(ASM) $(BASICINTFLAGS) $(SRCDIR)\emoem.asm, $@;
+
+
+
+
+###############################################################################
+#
+#
+# This is how to build the BASICJ interpreter's emulators
+# ie fwait polling
+# no control c hooking
+#
+# Note. Basicj also uses the pem?.lib and p87?.lib
+#
+###############################################################################
+
+
+basicij: $(OBJDIR)\pnemr.lib $(OBJDIR)\pn87r.lib
+
+
+$(OBJDIR)\pnemr.lib: $(OBJDIR)\pemr.obj $(OBJDIR)\nemoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pemr.obj + $(OBJDIR)\nemoem.obj;
+
+$(OBJDIR)\pn87r.lib: $(OBJDIR)\p87r.obj $(OBJDIR)\nemoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\p87r.obj + $(OBJDIR)\nemoem.obj;
+
+
+###############################################################################
+#
+#
+# This is how to build fwait polling versions of the small emulators
+# with limited instructions. (for BASIC)
+#
+# ie with fwait polling
+# with limited instructions
+# no IBM bios check
+#
+#
+###############################################################################
+
+
+SMALL_POLLING_FLAGS = -DPOLLING -DSMALL_EMULATOR
+
+psem: $(OBJDIR)\psem.lib $(OBJDIR)\psemr.lib $(OBJDIR)\psemp.lib
+
+
+$(OBJDIR)\psem.lib: $(OBJDIR)\psem.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\psem.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\psemr.lib: $(OBJDIR)\psemr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\psemr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\psemp.lib: $(OBJDIR)\psemp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\psemp.obj;
+
+
+$(OBJDIR)\psem.obj: $(EMASM)
+ $(ASM) $(SMALL_POLLING_FLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\psemr.obj: $(EMASM)
+ $(ASM) $(SMALL_POLLING_FLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\psemp.obj: $(EMASM)
+ $(ASM) $(SMALL_POLLING_FLAGS) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build fwait polling versions of the small emulators
+# with limited instructions and IBM bios checks. (for BASIC)
+#
+# ie with fwait polling
+# with limited instructions
+# with IBM bios check
+#
+#
+###############################################################################
+
+
+SMALL_IBM_FLAGS = -DPOLLING -DPCDOS -DSMALL_EMULATOR
+
+pisem: $(OBJDIR)\pisem.lib $(OBJDIR)\pisemr.lib $(OBJDIR)\pisemp.lib
+
+
+$(OBJDIR)\pisem.lib: $(OBJDIR)\pisem.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pisem.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pisemr.lib: $(OBJDIR)\pisemr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pisemr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\pisemp.lib: $(OBJDIR)\pisemp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\pisemp.obj;
+
+
+$(OBJDIR)\pisem.obj: $(EMASM)
+ $(ASM) $(SMALL_IBM_FLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\pisemr.obj: $(EMASM)
+ $(ASM) $(SMALL_IBM_FLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\pisemp.obj: $(EMASM)
+ $(ASM) $(SMALL_IBM_FLAGS) -DDOS5only $(SRCDIR)\emulator.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build the emulators with .com file support (or tiny model)
+# ie .com support
+# no fwait polling
+# no IBM bios checks
+#
+###############################################################################
+
+TINYFLAGS = -D_COM_
+
+
+emt: $(OBJDIR)\emt.lib $(OBJDIR)\emtr.lib
+
+87t: $(OBJDIR)\87t.lib $(OBJDIR)\87tr.lib
+
+
+$(OBJDIR)\emt.lib: $(OBJDIR)\emt.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emt.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\emtr.lib: $(OBJDIR)\emtr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emtr.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\87t.lib: $(OBJDIR)\87t.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87t.obj + $(OBJDIR)\emoem.obj;
+
+$(OBJDIR)\87tr.lib: $(OBJDIR)\87tr.obj $(OBJDIR)\emoem.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\87tr.obj + $(OBJDIR)\emoem.obj;
+
+
+
+$(OBJDIR)\emt.obj: $(EMASM)
+ $(ASM) $(TINYFLAGS) -DDOS5 $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\emtr.obj: $(EMASM)
+ $(ASM) $(TINYFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\87t.obj: $(EMASM)
+ $(ASM) $(TINYFLAGS) -DDOS5 $(SRCDIR)\emu8087.asm, $@;
+
+$(OBJDIR)\87tr.obj: $(EMASM)
+ $(ASM) $(TINYFLAGS) $(SRCDIR)\emu8087.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build the special verison of emmt.lib for SQL. The only
+# difference between the normal emmt.lib is that this verison always gets
+# a new CS alias to the stack segment when an exception occurs. This lets
+# the SQL swap stacks.
+#
+###############################################################################
+
+
+MT_SQL_FLAGS = -DMTHREAD -DDOS5only -DSQL_EMMT
+
+emmtsql: $(OBJDIR)\emmtsql.lib
+
+
+$(OBJDIR)\emmtsql.lib: $(OBJDIR)\emmtsql.obj $(OBJDIR)\emds.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emmtsql.obj + $(OBJDIR)\emds.obj;
+
+
+$(OBJDIR)\emmtsql.obj: $(EMASM)
+ $(ASM) $(MT_SQL_FLAGS) $(SRCDIR)\emulator.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build the Windows emulator.
+#
+###############################################################################
+
+
+WINFLAGS = -DPOLLING -DWINDOWS -D_NOCTRLC -DPCDOS
+
+
+win87em: $(OBJDIR)\win87em.dll $(OBJDIR)\win87em.lib
+
+
+$(OBJDIR)\win87em.ex2: $(OBJDIR)\win87em.obj $(OBJDIR)\emoemwin.obj \
+ $(SRCDIR)\libw.lib $(SRCDIR)\win87em2.def
+ $(LINK) /noi/nod @<<
+$(OBJDIR)\win87em.obj+
+$(OBJDIR)\emoemwin.obj+
+
+$(OBJDIR)\win87em.ex2
+$(OBJDIR)\win87em.ma2/map
+$(SRCDIR)\libw.lib+
+
+$(SRCDIR)\win87em2.def;
+<<
+
+
+$(OBJDIR)\win87em.dll: $(OBJDIR)\win87em.obj $(OBJDIR)\emoemwin.obj \
+ $(SRCDIR)\libw.lib $(SRCDIR)\win87em3.def
+ $(LINK) /align:16 /noi/nod @<<
+$(OBJDIR)\win87em.obj+
+$(OBJDIR)\emoemwin.obj+
+
+$(OBJDIR)\win87em.dll
+$(OBJDIR)\win87em.map/map
+$(SRCDIR)\libw.lib+
+
+$(SRCDIR)\win87em3.def;
+<<
+ $(RC) $@
+
+
+$(OBJDIR)\win87em.lib: $(SRCDIR)\win87em.def $(OBJDIR)\87emstar.obj \
+ $(OBJDIR)\wfpsig.obj $(OBJDIR)\wfpinit.obj
+ $(IMPLIB) $@ $(SRCDIR)\win87em.def
+ $(LIBEXE) $@ + $(OBJDIR)\87emstar.obj + $(OBJDIR)\wfpsig.obj + $(OBJDIR)\wfpinit.obj;
+ erase $(@R).bak
+
+$(OBJDIR)\win87em.obj: $(EMASM)
+ $(ASM) $(WINFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\emoemwin.obj: $(SRCDIR)\emoemwin.asm
+ $(ASM) $(WINFLAGS) $(SRCDIR)\emoemwin.asm, $@;
+
+$(OBJDIR)\87emstar.obj: $(SRCDIR)\87emstar.asm
+ $(ASM) $(WINFLAGS) $(SRCDIR)\87emstar.asm, $@;
+
+$(OBJDIR)\wfpsig.obj: $(SRCDIR)\wfpsig.asm
+ $(ASM) $(WINFLAGS) $(SRCDIR)\wfpsig.asm, $@;
+
+$(OBJDIR)\wfpinit.obj: $(SRCDIR)\wfpinit.asm
+ $(ASM) $(WINFLAGS) $(SRCDIR)\wfpinit.asm, $@;
+
+
+
+###############################################################################
+#
+#
+# This is how to build the Quick Pascal emulators.
+#
+###############################################################################
+
+QPASCALFLAGS = -DQP
+
+
+emqp: $(OBJDIR)\emqp.lib
+
+
+$(OBJDIR)\emqp.lib: $(OBJDIR)\emqp.obj $(OBJDIR)\emoemqp.obj
+ if exist $@ erase $@
+ $(LIBEXE) $@ + $(OBJDIR)\emqp.obj + $(OBJDIR)\emoemqp.obj;
+
+
+
+$(OBJDIR)\emqp.obj: $(EMASM)
+ $(ASM) $(QPASCALFLAGS) $(SRCDIR)\emulator.asm, $@;
+
+$(OBJDIR)\emoemqp.obj: $(SRCDIR)\emoemqp.asm
+ $(ASM) $(QPASCALFLAGS) $(SRCDIR)\emoemqp.asm, $@;
+
+
+###############################################################################
+#
+# This is how to build emoem.src, the OEM version of emoem.asm.
+#
+###############################################################################
+
+
+emoem: $(SRCDIR)\emoem.src
+
+$(SRCDIR)\emoem.src: $(SRCDIR)\emoem.asm
+ $(IFSTRIP) -w -xsrc -f $(SRCDIR)\switch.src $(SRCDIR)\emoem.asm
diff --git a/private/mvdm/wow16/win87em/switch.an b/private/mvdm/wow16/win87em/switch.an
new file mode 100644
index 000000000..e3448e400
--- /dev/null
+++ b/private/mvdm/wow16/win87em/switch.an
@@ -0,0 +1,5 @@
+_NOCTRLC
+_NO87INSTALL
+-
+-
+OEM
diff --git a/private/mvdm/wow16/win87em/switch.n b/private/mvdm/wow16/win87em/switch.n
new file mode 100644
index 000000000..9df863240
--- /dev/null
+++ b/private/mvdm/wow16/win87em/switch.n
@@ -0,0 +1,5 @@
+_NOCTRLC
+-
+_NO87INSTALL
+-
+OEM
diff --git a/private/mvdm/wow16/win87em/switch.src b/private/mvdm/wow16/win87em/switch.src
new file mode 100644
index 000000000..a2c5852b1
--- /dev/null
+++ b/private/mvdm/wow16/win87em/switch.src
@@ -0,0 +1,5 @@
+-
+_NOCTRLC
+_NO87INSTALL
+-
+OEM
diff --git a/private/mvdm/wow16/win87em/wfpinit.asm b/private/mvdm/wow16/win87em/wfpinit.asm
new file mode 100644
index 000000000..2c4bb7948
--- /dev/null
+++ b/private/mvdm/wow16/win87em/wfpinit.asm
@@ -0,0 +1,121 @@
+ page ,132
+ title wfpinit - Functions for initializing win87em.exe from a DLL
+;***
+;wfpinit.asm - Functions for initializing win87em.exe from a DLL
+;
+; Copyright (c) 1988-1989, Microsoft Corporation. All rights reserved.
+;
+;Purpose:
+; Defines the initialization and termination routines for the Windows
+; emulator (used in DLLs).
+;
+;Revision History:
+; 04/14/88 WAJ Initial version.
+; 04/06/89 WAJ Cleaned up source.
+; 04/12/90 WAJ Will now work in protected mode.
+;
+;*******************************************************************************
+
+
+memL = 1
+?PLM = 1 ; Pascal names.
+?WIN = 1 ; Windows calling sequence
+
+.xlist
+ include cmac_mrt.inc ; old, customized masm510 cmacros
+.list
+
+TSKINT equ 3eh ; int 3e is used for the Signal handler
+OPSYS equ 21h
+SETVECOP equ 25h
+GETVECOP equ 35h
+
+
+externFP __fpmath
+externFP __fpsignal
+
+sBegin data
+DefaultFPSignal dd __fpsignal ; want to a thunk for this function
+sEnd data
+
+sBegin code
+
+assumes cs, code
+assumes ds, data
+
+
+;***
+; _FPInit -
+;
+;Purpose: Initializes the Windows emulator.
+;
+;Entry:
+;
+;Exit: returns the old signal handler
+;
+;Uses:
+;
+;Exceptions: none
+;
+;*******************************************************************************
+
+cProc _FPINIT,<PUBLIC,FAR>,<>
+
+cBegin
+ xor bx, bx ; initialize Emulator/Coprocessor
+ call __fpmath
+
+
+ push ds
+ mov ax,GETVECOP shl 8 + TSKINT ; get interrupt vector TSKINT
+ int OPSYS ; Call operating system.
+ pop ds
+
+ push es ; save previous FP signal handler on
+ push bx ; stack
+
+ mov ax, word ptr [DefaultFPSignal]
+ mov dx, word ptr [DefaultFPSignal+2]
+
+ mov bx, 3 ; 3 => set SignalAddress
+ call __fpmath
+
+ pop ax ; get previous FP signal handler off
+ pop dx ; stack
+cEnd
+
+
+
+;***
+; _FPTerm -
+;
+;Purpose: terminates Windows emulator
+;
+;Entry: old floating point signal handler
+;
+;Exit: none
+;
+;Uses:
+;
+;Exceptions: none
+;
+;*******************************************************************************
+
+cProc _FPTERM,<PUBLIC,FAR>,<>
+
+ parmD DefaultSignalHandler
+
+cBegin
+ mov ax, [OFF_DefaultSignalHandler]
+ mov dx, [SEG_DefaultSignalHandler]
+
+ mov bx, 3 ; 3 => set SignalAddress
+ call __fpmath
+
+ mov bx, 2 ; 2 => terminate FP
+ call __fpmath
+cEnd
+
+sEnd code
+
+end
diff --git a/private/mvdm/wow16/win87em/wfpsig.asm b/private/mvdm/wow16/win87em/wfpsig.asm
new file mode 100644
index 000000000..a0ef901ad
--- /dev/null
+++ b/private/mvdm/wow16/win87em/wfpsig.asm
@@ -0,0 +1,57 @@
+ page ,132
+ title wfpinit - Functions for initializing win87em.exe from a DLL
+;***
+;wfoinit.asm - Functions for initializing win87em.exe from a DLL
+;
+; Copyright (c) 1988-89, Microsoft Corporation
+;
+;Purpose:
+; Functions for initializing win87em.exe from a DLL
+;
+;Revision History:
+; 04/06/89 WAJ Added this header.
+; 04/06/89 WAJ Cleaned up source, Save more registers in __fpsignal
+;
+;*******************************************************************************
+
+
+ memL = 1
+
+ ?PLM = 1 ; Pascal naming
+ ?WIN = 1 ; Windows calling convention
+
+.xlist
+ include cmac_mrt.inc ; old, customized masm510 cmacros
+.list
+
+
+externFP POSTQUITMESSAGE
+
+
+sBegin code
+
+assumes cs,code
+assumes ds,data
+
+;
+; Windows floating-point emulator error routine
+; (replaces CFPSIG.ASM in regular C math runtime)
+;
+; The behavior is to die with error code.
+; (Calling POSTQUITMESSAGE doesn't cause immediate termination of
+; the Windows "task", but sends a WM_QUIT message
+; to the application queue of the current Windows app.)
+;
+
+cProc __fpsignal,<PUBLIC,FAR>,<es,bx,cx,dx>
+
+cBegin
+ sub ah, ah
+
+ push ax
+ call POSTQUITMESSAGE
+cEnd
+
+sEnd code
+
+end
diff --git a/private/mvdm/wow16/win87em/win87em.def b/private/mvdm/wow16/win87em/win87em.def
new file mode 100644
index 000000000..fc61f5777
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87em.def
@@ -0,0 +1,19 @@
+LIBRARY win87em
+
+DESCRIPTION 'This .def file is just used to create an implib for __fpmath'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+DATA NONE
+
+SEGMENTS
+ EMULATOR_TEXT CLASS 'CODE' PRELOAD FIXED NONDISCARDABLE
+ EMULATOR_DATA CLASS 'FAR_DATA' PRELOAD FIXED NONDISCARDABLE
+
+
+HEAPSIZE 0
+
+EXPORTS
+ __fpmath @1
diff --git a/private/mvdm/wow16/win87em/win87em.h b/private/mvdm/wow16/win87em/win87em.h
new file mode 100644
index 000000000..cfab1d302
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87em.h
@@ -0,0 +1,40 @@
+/***
+*win87em.h - definitions/declarations for win87em.exe exports.
+*
+* Copyright (c) 1989-1989, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* This file defines the structures, values, macros, and functions
+* exported from win87em.exe
+*
+*Revision History:
+*
+* 06-26-89 WAJ Initial version.
+*
+****/
+
+
+typedef struct _Win87EmInfoStruct {
+ unsigned Version;
+ unsigned SizeSaveArea;
+ unsigned WinDataSeg;
+ unsigned WinCodeSeg;
+ unsigned Have80x87;
+ unsigned Unused;
+ } Win87EmInfoStruct;
+
+#define SIZE_80X87_AREA 94
+
+/*
+ * The Win87EmSaveArea loks like this:
+ *
+ * typedef struct _Win87EmSaveArea {
+ * unsigned char Save80x87Area[SIZE_80X87_AREA];
+ * unsigned char SaveEmArea[];
+ * } Win87EmSaveArea;
+ */
+
+
+int far pascal __Win87EmInfo( Win87EmInfoStruct far * pWIS, int cbWin87EmInfoStruct );
+int far pascal __Win87EmSave( void far * pWin87EmSaveArea, int cbWin87EmSaveArea );
+int far pascal __Win87EmRestore( void far * pWin87EmSaveArea, int cbWin87EmSaveArea );
diff --git a/private/mvdm/wow16/win87em/win87em2.def b/private/mvdm/wow16/win87em/win87em2.def
new file mode 100644
index 000000000..9479af2c1
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87em2.def
@@ -0,0 +1,22 @@
+LIBRARY win87em
+
+DESCRIPTION 'Microsoft Windows (2) Coprocessor/Emulator Library 6.00.03'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+DATA NONE
+
+SEGMENTS
+ EMULATOR_TEXT CLASS 'CODE' PRELOAD FIXED NONDISCARDABLE
+ EMULATOR_DATA CLASS 'FAR_DATA' PRELOAD FIXED NONDISCARDABLE
+
+
+HEAPSIZE 0
+
+EXPORTS
+ __FPMATH = __fpmath @1RESIDENTNAME
+ __WIN87EMINFO
+ __WIN87EMSAVE
+ __WIN87EMRESTORE
diff --git a/private/mvdm/wow16/win87em/win87em3.def b/private/mvdm/wow16/win87em/win87em3.def
new file mode 100644
index 000000000..3c50d8cbd
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87em3.def
@@ -0,0 +1,26 @@
+LIBRARY win87em
+
+DESCRIPTION 'Microsoft Windows 3.1 Coprocessor/Emulator Library 7.00.00'
+
+EXETYPE WINDOWS 4.0
+
+STUB 'WINSTUB.EXE'
+
+DATA NONE
+
+SEGMENTS
+ EMULATOR_TEXT CLASS 'CODE' PRELOAD FIXED NONDISCARDABLE
+ EMULATOR_DATA CLASS 'FAR_DATA' PRELOAD FIXED NONDISCARDABLE
+
+
+HEAPSIZE 0
+
+IMPORTS
+ KERNEL.__WINFLAGS
+
+EXPORTS
+ __FPMATH = __fpmath @1RESIDENTNAME
+ WEP
+ __WIN87EMINFO
+ __WIN87EMSAVE
+ __WIN87EMRESTORE
diff --git a/private/mvdm/wow16/win87em/win87hdr.txt b/private/mvdm/wow16/win87em/win87hdr.txt
new file mode 100644
index 000000000..addf3d5fc
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87hdr.txt
@@ -0,0 +1,65 @@
+
+Microsoft (R) EXE File Header Utility Version 2.01
+Copyright (C) Microsoft Corp 1985-1990. All rights reserved.
+
+.EXE size (bytes) 3200
+Magic number: 5a4d
+Bytes on last page: 00a3
+Pages in file: 0018
+Relocations: 0000
+Paragraphs in header: 0020
+Extra paragraphs needed: 0000
+Extra paragraphs wanted: ffff
+Initial stack location: 0004:0100
+Word checksum: eb10
+Entry point: 0000:0000
+Relocation table address: 0040
+Reserved words:
+ 0000 0000 0000 0000 0000 0000 0000 0000
+ 0000 0000 0000 0000 0000
+New .EXE header address: 00000400
+Memory needed: 12K
+
+Library: WIN87EM
+Description: Microsoft Windows 3.1 Coprocessor/Emulator Library 7.00.00
+Operating system: Microsoft Windows
+Data: NONE
+Initialization: Global
+Initial CS:IP: seg 1 offset 0058
+Initial SS:SP: seg 0 offset 0000
+Linker version: 5.01
+32-bit Checksum: 00b41495
+Segment Table: 00000440 length 0010 (16)
+Resource Table: 00000450 length 0000 (0)
+Resident Names Table: 00000450 length 004f (79)
+Module Reference Table: 0000049f length 0002 (2)
+Imported Names Table: 000004a1 length 0013 (19)
+Entry Table: 000004b4 length 0015 (21)
+Non-resident Names Table: 000004c9 length 003e (62)
+Movable entry points: 0
+Segment sector size: 512
+Application type: WINDOWAPI
+Other module flags:
+no. type address file mem flags
+ 1 CODE 00000800 02763 02763 EXECUTEREAD, PRELOAD, NONCONFORMING, NOIOPL,
+ relocs, (fixed), (nondiscardable), (nonshared)
+ 2 DATA 00003000 00170 00170 READWRITE, SHARED, PRELOAD, NOEXPANDDOWN, NOIOPL,
+ (fixed), (nondiscardable)
+
+
+Exports:
+ord seg offset name
+ 2 1 0089 WEP exported
+ 1 1 002a __FPMATH exported
+ 3 1 01ab __WIN87EMINFO exported
+ 4 1 0220 __WIN87EMRESTORE exported
+ 5 1 01e3 __WIN87EMSAVE exported
+
+ 1 type offset target
+ OFFSET 2692 imp KERNEL.__WINFLAGS
+ PTR 0613 imp KERNEL.171
+ PTR 0665 imp KERNEL.176
+ BASE 0e0a seg 2 offset 016f
+ BASE 274d seg 2 offset 0170
+ 5 relocations
+
diff --git a/private/mvdm/wow16/win87em/win87std.def b/private/mvdm/wow16/win87em/win87std.def
new file mode 100644
index 000000000..8e77c2b4f
--- /dev/null
+++ b/private/mvdm/wow16/win87em/win87std.def
@@ -0,0 +1,26 @@
+LIBRARY win87em
+
+DESCRIPTION 'Microsoft Windows 3.1 Coprocessor/Emulator Library 7.00.00'
+
+EXETYPE WINDOWS
+
+STUB 'WINSTUB.EXE'
+
+DATA NONE
+
+SEGMENTS
+ EMULATOR_TEXT CLASS 'CODE' PRELOAD FIXED NONDISCARDABLE
+ EMULATOR_DATA CLASS 'FAR_DATA' PRELOAD FIXED NONDISCARDABLE
+
+
+HEAPSIZE 0
+
+IMPORTS
+ KERNEL.__WINFLAGS
+
+EXPORTS
+ __FPMATH = __fpmath @1RESIDENTNAME
+ WEP
+ __WIN87EMINFO
+ __WIN87EMSAVE
+ __WIN87EMRESTORE
diff --git a/private/mvdm/wow16/winoldap/makefile b/private/mvdm/wow16/winoldap/makefile
new file mode 100644
index 000000000..77016a9c2
--- /dev/null
+++ b/private/mvdm/wow16/winoldap/makefile
@@ -0,0 +1,111 @@
+# winoldap makefile
+#
+# Copyright (c) 1993, Microsoft Corporation
+#
+# History:
+# 30-Nov-1993 Dave Hart (davehart) Created from wowexec makefile
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+AOBJ = -W2 -DSEGNAME=COMMAND $(INCS)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG $(INCS)
+!else
+CW16 = -AS -G2sw -Os -W2 -Zp $(INCS)
+!endif
+
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /stack:5120 /align:16
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\snocrt.lib ..\lib\libw.lib
+
+
+.h.inc:
+ h2inc -t $*.h -o $*.inc
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+
+all: winoldap.mod winoldap.sym
+ binplace winoldap.mod winoldap.map winoldap.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.def del *.def
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+
+winoldap.lrf: makefile
+ echo winoldap.obj >winoldap.lrf
+ echo winoldap.mod $(LINK) >>winoldap.lrf
+ echo winoldap >>winoldap.lrf
+ echo $(W16LIBS) /nod >>winoldap.lrf
+ echo winoldap.def; >>winoldap.lrf
+
+winoldap.def: makefile
+ echo name winoldap >winoldap.def
+ echo exetype windows >>winoldap.def
+ echo stub '..\bin\winstub.exe' >>winoldap.def
+ echo code preload moveable discardable >>winoldap.def
+ echo data preload moveable multiple >>winoldap.def
+ echo heapsize 512 >>winoldap.def
+ echo exports >>winoldap.def
+
+
+winoldap.mod: winoldap.obj winoldap.lrf winoldap.def winoldap.res
+ link16 @winoldap.lrf;
+ rc16 -t winoldap.res winoldap.mod
+
+winoldap.res: $*.rc $*.rcv ..\inc\common.ver
diff --git a/private/mvdm/wow16/winoldap/winoldap.c b/private/mvdm/wow16/winoldap/winoldap.c
new file mode 100644
index 000000000..efc93fef2
--- /dev/null
+++ b/private/mvdm/wow16/winoldap/winoldap.c
@@ -0,0 +1,47 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ winoldap.c
+
+Abstract:
+
+ This module is a Win16 "stub" run by the WOW kernel when invoking
+ non-Win16 applications. It calls WowLoadModule to wait for the
+ non-win16 app to terminate, and then exits
+
+ This makes WINOLDAP a strange Windows program, since it doesn't
+ create a window or pump messages.
+
+ The binary is named WINOLDAP.MOD for historic reasons.
+
+Author:
+
+ 04-Apr-1995 Jonle , created
+
+Environment:
+
+ Win16 (WOW)
+
+Revision History:
+
+--*/
+
+#include <windows.h>
+
+HINSTANCE WINAPI WowLoadModule(LPCSTR, LPVOID, LPCSTR);
+
+//
+// WinMain
+//
+
+int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
+ LPSTR lpszCmdLine, int nCmdShow)
+{
+ return (int) WowLoadModule(NULL, // no module name
+ NULL, // no parameterblock
+ lpszCmdLine // pass along cmd line
+ );
+}
diff --git a/private/mvdm/wow16/winoldap/winoldap.rc b/private/mvdm/wow16/winoldap/winoldap.rc
new file mode 100644
index 000000000..7e286ce7d
--- /dev/null
+++ b/private/mvdm/wow16/winoldap/winoldap.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* WINOLDAP.RC */
+/********************************************************************/
+#include "winoldap.rcv"
diff --git a/private/mvdm/wow16/winoldap/winoldap.rcv b/private/mvdm/wow16/winoldap/winoldap.rcv
new file mode 100644
index 000000000..59cd25dd0
--- /dev/null
+++ b/private/mvdm/wow16/winoldap/winoldap.rcv
@@ -0,0 +1,9 @@
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows NT Non-Win16 application shell"
+#define VER_INTERNALNAME_STR "WINOLDAP"
+#define VER_ORIGINALFILENAME_STR "WINOLDAP.MOD"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/winsock/makefile b/private/mvdm/wow16/winsock/makefile
new file mode 100644
index 000000000..aaeda13a9
--- /dev/null
+++ b/private/mvdm/wow16/winsock/makefile
@@ -0,0 +1,107 @@
+# mmsystem16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# Created 02-Oct-1992 David Treadwell (davidtr)
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .dll .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\sdllcew.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 $(INCS) -r $*.rc
+
+all: winsock.dll winsock.sym
+ -binplace winsock.dll winsock.map winsock.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.dll del *.dll
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+winsock.obj: $*.asm ..\..\inc\wow.inc ..\..\inc\wowwsock.inc
+ masm $(AOBJ) $*;
+
+winsock.lrf: makefile
+ echo $*.obj >$@
+ echo $*.dll>>$@
+ echo $* $(LINK)>>$@
+ echo ..\lib\libw.lib /nod>>$@
+ echo $*;>>$@
+
+winsock.dll: $*.obj $*.lrf $*.def $*.res
+ link16 @$*.lrf;
+ rc16 -t $*.res $@
+
+winsock.res: $*.rc $*.rcv ..\inc\common.ver
+
+!ENDIF
diff --git a/private/mvdm/wow16/winsock/winsock.asm b/private/mvdm/wow16/winsock/winsock.asm
new file mode 100644
index 000000000..132dee0ea
--- /dev/null
+++ b/private/mvdm/wow16/winsock/winsock.asm
@@ -0,0 +1,115 @@
+ TITLE WINSOCK.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; MMSYSTEM.ASM
+; Thunks in 16-bit space to route Winsock API calls to WOW32
+;
+; History:
+; 02-Oct-1992 David Treadwell (davidtr)
+; Created.
+;
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowwsock.inc
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+WINSOCK_Identifier db 'WINSOCK16 Data Segment'
+
+sEnd
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+cProc WINSOCK16,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+
+ cBegin <nogen>
+ mov ax,1
+ ret
+ cEnd <nogen>
+
+assumes DS,NOTHING
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+assumes DS,NOTHING
+
+ WinsockThunk ACCEPT
+ WinsockThunk BIND
+ WinsockThunk CLOSESOCKET
+ WinsockThunk CONNECT
+ WinsockThunk GETPEERNAME
+ WinsockThunk GETSOCKNAME
+ WinsockThunk GETSOCKOPT
+ WinsockThunk HTONL
+ WinsockThunk HTONS
+ WinsockThunk INET_ADDR
+ WinsockThunk INET_NTOA
+ WinsockThunk IOCTLSOCKET
+ WinsockThunk LISTEN
+ WinsockThunk NTOHL
+ WinsockThunk NTOHS
+ WinsockThunk RECV
+ WinsockThunk RECVFROM
+ WinsockThunk SELECT
+ WinsockThunk SEND
+ WinsockThunk SENDTO
+ WinsockThunk SETSOCKOPT
+ WinsockThunk SHUTDOWN
+ WinsockThunk SOCKET
+ WinsockThunk GETHOSTBYADDR
+ WinsockThunk GETHOSTBYNAME
+ WinsockThunk GETPROTOBYNAME
+ WinsockThunk GETPROTOBYNUMBER
+ WinsockThunk GETSERVBYNAME
+ WinsockThunk GETSERVBYPORT
+ WinsockThunk GETHOSTNAME
+ WinsockThunk WSAASYNCSELECT
+ WinsockThunk WSAASYNCGETHOSTBYADDR
+ WinsockThunk WSAASYNCGETHOSTBYNAME
+ WinsockThunk WSAASYNCGETPROTOBYNUMBER
+ WinsockThunk WSAASYNCGETPROTOBYNAME
+ WinsockThunk WSAASYNCGETSERVBYPORT
+ WinsockThunk WSAASYNCGETSERVBYNAME
+ WinsockThunk WSACANCELASYNCREQUEST
+ WinsockThunk WSASETBLOCKINGHOOK
+ WinsockThunk WSAUNHOOKBLOCKINGHOOK
+ WinsockThunk WSAGETLASTERROR
+ WinsockThunk WSASETLASTERROR
+ WinsockThunk WSACANCELBLOCKINGCALL
+ WinsockThunk WSAISBLOCKING
+ WinsockThunk WSASTARTUP
+ WinsockThunk WSACLEANUP
+ WinsockThunk __WSAFDISSET
+
+; End of additions
+
+sEnd CODE
+
+end WINSOCK16
diff --git a/private/mvdm/wow16/winsock/winsock.def b/private/mvdm/wow16/winsock/winsock.def
new file mode 100644
index 000000000..4d034f4f0
--- /dev/null
+++ b/private/mvdm/wow16/winsock/winsock.def
@@ -0,0 +1,81 @@
+;
+; File: winsock.def
+; System: MS-Windows 3.x
+; Summary: Module definition file for WinSockAPI DLL.
+;
+
+LIBRARY WINSOCK ; Application's module name
+
+DESCRIPTION 'BSD Socket API for Windows'
+
+EXETYPE WINDOWS ; required for all windows applications
+
+;STUB 'WINSTUB.EXE' ; generates error message if application
+; ; is run without Windows
+
+;CODE can be FIXED in memory because of potential upcalls
+CODE PRELOAD FIXED
+
+;DATA must be SINGLE and at a FIXED location since this is a DLL
+DATA PRELOAD FIXED SINGLE
+
+HEAPSIZE 1024
+
+; All functions that will be called by any Windows routine
+; must be exported
+
+EXPORTS
+ accept @1
+ bind @2
+ closesocket @3
+ connect @4
+ getpeername @5
+ getsockname @6
+ getsockopt @7
+ htonl @8
+ htons @9
+ inet_addr @10
+ inet_ntoa @11
+ ioctlsocket @12
+ listen @13
+ ntohl @14
+ ntohs @15
+ recv @16
+ recvfrom @17
+ select @18
+ send @19
+ sendto @20
+ setsockopt @21
+ shutdown @22
+ socket @23
+
+ gethostbyaddr @51
+ gethostbyname @52
+ getprotobyname @53
+ getprotobynumber @54
+ getservbyname @55
+ getservbyport @56
+ gethostname @57
+
+ WSAAsyncSelect @101
+ WSAAsyncGetHostByAddr @102
+ WSAAsyncGetHostByName @103
+ WSAAsyncGetProtoByNumber @104
+ WSAAsyncGetProtoByName @105
+ WSAAsyncGetServByPort @106
+ WSAAsyncGetServByName @107
+ WSACancelAsyncRequest @108
+ WSASetBlockingHook @109
+ WSAUnhookBlockingHook @110
+ WSAGetLastError @111
+ WSASetLastError @112
+ WSACancelBlockingCall @113
+ WSAIsBlocking @114
+ WSAStartup @115
+ WSACleanup @116
+
+ __WSAFDIsSet @151
+
+ WEP @500 RESIDENTNAME
+
+;eof
diff --git a/private/mvdm/wow16/winsock/winsock.rc b/private/mvdm/wow16/winsock/winsock.rc
new file mode 100644
index 000000000..784b25f20
--- /dev/null
+++ b/private/mvdm/wow16/winsock/winsock.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* WINSOCK.RC */
+/********************************************************************/
+#include "winsock.rcv"
diff --git a/private/mvdm/wow16/winsock/winsock.rcv b/private/mvdm/wow16/winsock/winsock.rcv
new file mode 100644
index 000000000..bc4a6e353
--- /dev/null
+++ b/private/mvdm/wow16/winsock/winsock.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* WINSOCK.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "16-bit Windows Sockets API for Windows NT"
+#define VER_INTERNALNAME_STR "WINSOCK"
+#define VER_ORIGINALFILENAME_STR "WINSOCK.DLL"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/winspool/makefile b/private/mvdm/wow16/winspool/makefile
new file mode 100644
index 000000000..89d9c974a
--- /dev/null
+++ b/private/mvdm/wow16/winspool/makefile
@@ -0,0 +1,108 @@
+# WINSPOOL16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 17-OCT-1991 Matt Felton (MattFe)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, 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
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\sdllcew.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 $(INCS) -r $*.rc
+
+
+all: winspool.exe winspool.sym
+ -binplace winspool.exe winspool.map winspool.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+winspool.obj: winspool.asm ..\..\inc\wow.inc
+ masm -l $(AOBJ) winspool;
+
+winspool.lrf: makefile
+ echo winspool.obj >winspool.lrf
+ echo winspool.exe>>winspool.lrf
+ echo winspool $(LINK)>>winspool.lrf
+ echo ..\lib\libw.lib /nod>>winspool.lrf
+ echo winspool;>>winspool.lrf
+
+winspool.exe winspool.map: winspool.obj winspool.lrf winspool.def winspool.res
+ link16 @winspool.lrf;
+ rc16 -t winspool.res winspool.exe
+
+winspool.res: $*.rc $*.rcv ..\inc\common.ver
+
+!ENDIF
diff --git a/private/mvdm/wow16/winspool/winspool.asm b/private/mvdm/wow16/winspool/winspool.asm
new file mode 100644
index 000000000..24d4dfdbc
--- /dev/null
+++ b/private/mvdm/wow16/winspool/winspool.asm
@@ -0,0 +1,80 @@
+ TITLE WINSPOOL.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; WINSPOOL.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 17-OCT-1991 Matt Felton (mattfe)
+; Created.
+;
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowgdi.inc
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+WINSPOOL_Identifier db 'WINSPOOL16 Data Segment'
+public _iLogLevel
+_iLogLevel dw 0
+public _iBreakLevel
+_iBreakLevel dw 0
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+cProc WINSPOOL16,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+ cBegin <nogen>
+ mov ax,1 ;always indicate success
+ ret
+ cEnd <nogen>
+
+assumes DS,NOTHING
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+assumes DS,DATA
+
+assumes DS,NOTHING
+
+ DGDIThunk DEVICEMODE
+ DGDIThunk EXTDEVICEMODE
+ DGDIThunk DEVICECAPABILITIES
+
+cProc ExtTextOut,<PUBLIC,FAR>
+cBegin
+ int 3
+cEnd
+
+
+sEnd CODE
+
+end WINSPOOL16
diff --git a/private/mvdm/wow16/winspool/winspool.def b/private/mvdm/wow16/winspool/winspool.def
new file mode 100644
index 000000000..45c9eb0ca
--- /dev/null
+++ b/private/mvdm/wow16/winspool/winspool.def
@@ -0,0 +1,13 @@
+LIBRARY WINSPOOL
+DESCRIPTION 'WOW WINSPOOL DRIVER'
+EXETYPE WINDOWS
+STUB '..\BIN\WINSTUB.EXE'
+CODE PRELOAD MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+HEAPSIZE 2048
+EXPORTS
+ WEP @1 RESIDENTNAME
+DEVICEMODE @13 ;
+EXTDEVICEMODE @90 ;
+EXTTEXTOUT @14 ;
+DEVICECAPABILITIES @91
diff --git a/private/mvdm/wow16/winspool/winspool.rc b/private/mvdm/wow16/winspool/winspool.rc
new file mode 100644
index 000000000..47e826c63
--- /dev/null
+++ b/private/mvdm/wow16/winspool/winspool.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* WINSPOOL.RC */
+/********************************************************************/
+#include "winspool.rcv"
diff --git a/private/mvdm/wow16/winspool/winspool.rcv b/private/mvdm/wow16/winspool/winspool.rcv
new file mode 100644
index 000000000..4831f4b50
--- /dev/null
+++ b/private/mvdm/wow16/winspool/winspool.rcv
@@ -0,0 +1,13 @@
+/********************************************************************/
+/* WINSPOOL.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows NT WOW 16-bit Psuedo Printer Driver (loaded as WINSPOOL.DRV)"
+#define VER_INTERNALNAME_STR "WINSPOOL"
+#define VER_ORIGINALFILENAME_STR "WINSPOOL.EXE"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/wowdeb/makefile b/private/mvdm/wow16/wowdeb/makefile
new file mode 100644
index 000000000..f2f375c7f
--- /dev/null
+++ b/private/mvdm/wow16/wowdeb/makefile
@@ -0,0 +1,120 @@
+# wowdeb makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Matt Felton (mattfe) Created.
+# 21-Mar-1992 Matt Felton Code from win 3.1 progman
+# 17-Nov-1992 Bob Day (bobday) Code from WOWEXEC
+#
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\inc -I..\..\inc
+!endif
+
+AOBJ = -W2 -DSEGNAME=COMMAND $(INCS)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+!IF "$(OLD_WOW_BUILD)" != ""
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG -DOLD_WOW_BUILD $(INCS)
+!ELSE
+CW16 = -AS -G2sw -Os -W2 -Zp -DDEBUG $(INCS)
+!ENDIF
+!else
+!IF "$(OLD_WOW_BUILD)" != ""
+CW16 = -AS -G2sw -Os -W2 -Zp -DOLD_WOW_BUILD $(INCS)
+!ELSE
+CW16 = -AS -G2sw -Os -W2 -Zp $(INCS)
+!ENDIF
+!endif
+
+CW16L = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /stack:8192 /align:16
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\lib\snocrt.lib ..\lib\libw.lib
+
+
+.h.inc:
+ h2inc -t $*.h -o $*.inc
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+all: wowdeb.exe wowdeb.sym
+ -binplace wowdeb.exe wowdeb.map wowdeb.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.def del *.def
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+wowdeb.lrf: makefile
+ echo wowdeb.obj>wowdeb.lrf
+ echo wowdeb $(LINK)>>wowdeb.lrf
+ echo wowdeb>>wowdeb.lrf
+ echo $(W16LIBS) /nod>>wowdeb.lrf
+ echo wowdeb;>>wowdeb.lrf
+
+wowdeb.def: makefile
+ echo name wowdeb>wowdeb.def
+ echo exetype windows>>wowdeb.def
+ echo stub '..\bin\winstub.exe'>>wowdeb.def
+ echo code preload moveable discardable>>wowdeb.def
+ echo data preload moveable multiple>>wowdeb.def
+ echo heapsize 4096>>wowdeb.def
+ echo.>>wowdeb.def
+ echo imports>>wowdeb.def
+ echo WOWKILLREMOTETASK = KERNEL.511>>wowdeb.def
+
+wowdeb.res: wowdeb.rc wowdeb.rcv ..\inc\common.ver
+
+wowdeb.exe: wowdeb.obj wowdeb.lrf wowdeb.def wowdeb.res
+ link16 @wowdeb.lrf;
+ rc16 -t wowdeb.res wowdeb.exe
diff --git a/private/mvdm/wow16/wowdeb/wowdeb.c b/private/mvdm/wow16/wowdeb/wowdeb.c
new file mode 100644
index 000000000..39efa2809
--- /dev/null
+++ b/private/mvdm/wow16/wowdeb/wowdeb.c
@@ -0,0 +1,202 @@
+#include <windows.h> /* required for all Windows applications */
+
+#define MAX_COMMUNICATION_BLOCK_SIZE 4096
+#define DEAD_VALUE 0xFEFEFEFEL
+
+#include <dbginfo.h>
+
+extern BOOL FAR PASCAL WowKillRemoteTask( LPSTR lpBuffer );
+
+int PASCAL WinMain(HANDLE hInstance,
+ HANDLE hPrevInstance, LPSTR lpszCmdLine, int iCmd )
+{
+ HANDLE hCommunicationBlock;
+ LPSTR lpCommunicationBlock;
+ BOOL b;
+ LPCOM_HEADER lphead;
+ WORD wArgsPassed;
+ WORD wArgsSize;
+ WORD wSuccess;
+ DWORD dwReturnValue;
+ LPSTR lpModuleName;
+ LPSTR lpEntryName;
+ HANDLE hModule;
+ DWORD (FAR PASCAL *lpfn)();
+ BOOL fFailed;
+ LPWORD lpw;
+
+ // We only want 1 instance of WOWDEB
+ if ( hPrevInstance != NULL ) {
+ return( FALSE );
+ }
+
+ hCommunicationBlock = GlobalAlloc(GMEM_FIXED, MAX_COMMUNICATION_BLOCK_SIZE);
+ if ( hCommunicationBlock == (HANDLE)0 ) {
+ OutputDebugString("Failed to allocate memory block\n");
+ return( FALSE );
+ }
+
+ lpCommunicationBlock = GlobalLock(hCommunicationBlock);
+ if ( lpCommunicationBlock == NULL ) {
+ OutputDebugString("Failed to lock memory block\n");
+ return( FALSE );
+ }
+
+ /*
+ ** Just make sure that TOOLHELP is loaded before we remotely kill
+ ** ourselves.
+ */
+ hModule = LoadLibrary( "TOOLHELP.DLL" );
+
+ dwReturnValue = DEAD_VALUE;
+ wSuccess = (WORD)FALSE;
+
+ do {
+ /*
+ ** Initialize the communications block
+ */
+ lphead = (LPCOM_HEADER)lpCommunicationBlock;
+
+ lphead->dwBlockAddress = (DWORD)lpCommunicationBlock;
+ lphead->dwReturnValue = dwReturnValue;
+ lphead->wArgsPassed = 0;
+ lphead->wArgsSize = 0;
+ lphead->wBlockLength = MAX_COMMUNICATION_BLOCK_SIZE;
+ lphead->wSuccess = (WORD)wSuccess;
+
+ b = WowKillRemoteTask( lpCommunicationBlock );
+
+ if ( !b ) {
+ break;
+ }
+
+ wSuccess = (WORD)FALSE;
+ dwReturnValue = 0;
+
+ /*
+ ** Unpacketize the information and execute it
+ ** Note: The below statements expect the contents of the structures
+ ** to change after the above "WowKillRemoteTask" API call. If the
+ ** compiler attempts to optimize the references below, it will get
+ ** the wrong values.
+ */
+ wArgsPassed = lphead->wArgsPassed;
+ wArgsSize = lphead->wArgsSize;
+ lpModuleName = lpCommunicationBlock + sizeof(COM_HEADER) + wArgsSize;
+ lpEntryName = lpModuleName + lstrlen(lpModuleName) + 1;
+
+ hModule = LoadLibrary( lpModuleName );
+ if ( hModule == 0 ) {
+#ifdef DEBUG
+ OutputDebugString("Failed to load library\n");
+#endif
+ continue;
+ }
+
+ lpfn = (DWORD (FAR PASCAL *)())GetProcAddress( hModule, lpEntryName );
+ if ( lpfn == NULL ) {
+#ifdef DEBUG
+ OutputDebugString("Failed to get proc address\n");
+#endif
+ continue;
+ }
+
+ // Now copy the right number of bytes onto the stack and call the
+ // function.
+ lpw = (LPWORD)(lpCommunicationBlock + sizeof(COM_HEADER));
+ fFailed = FALSE;
+
+ // Cheesy way of putting a variable number of arguments on the stack
+ // for a pascal call.
+ switch( wArgsPassed ) {
+ case 0:
+ dwReturnValue = (* lpfn)();
+ break;
+ case 2:
+ dwReturnValue = (* lpfn)( lpw[ 0] );
+ break;
+ case 4:
+ dwReturnValue = (* lpfn)( lpw[ 1], lpw[ 0] );
+ break;
+ case 6:
+ dwReturnValue = (* lpfn)( lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 8:
+ dwReturnValue = (* lpfn)( lpw[ 3], lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 10:
+ dwReturnValue = (* lpfn)( lpw[ 4], lpw[ 3], lpw[ 2], lpw[ 1],
+ lpw[ 0] );
+ break;
+ case 12:
+ dwReturnValue = (* lpfn)( lpw[ 5], lpw[ 4], lpw[ 3], lpw[ 2],
+ lpw[ 1], lpw[ 0] );
+ break;
+ case 14:
+ dwReturnValue = (* lpfn)( lpw[ 6], lpw[ 5], lpw[ 4], lpw[ 3],
+ lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 16:
+ dwReturnValue = (* lpfn)( lpw[ 7], lpw[ 6], lpw[ 5], lpw[ 4],
+ lpw[ 3], lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 18:
+ dwReturnValue = (* lpfn)( lpw[ 8], lpw[ 7], lpw[ 6], lpw[ 5],
+ lpw[ 4], lpw[ 3], lpw[ 2], lpw[ 1],
+ lpw[ 0] );
+ break;
+ case 20:
+ dwReturnValue = (* lpfn)( lpw[ 9], lpw[ 8], lpw[ 7], lpw[ 6],
+ lpw[ 5], lpw[ 4], lpw[ 3], lpw[ 2],
+ lpw[ 1], lpw[ 0] );
+ case 22:
+ dwReturnValue = (* lpfn)( lpw[10], lpw[ 9], lpw[ 8], lpw[ 7],
+ lpw[ 6], lpw[ 5], lpw[ 4], lpw[ 3],
+ lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 24:
+ dwReturnValue = (* lpfn)( lpw[11], lpw[10], lpw[ 9], lpw[ 8],
+ lpw[ 7], lpw[ 6], lpw[ 5], lpw[ 4],
+ lpw[ 3], lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 26:
+ dwReturnValue = (* lpfn)( lpw[12], lpw[11], lpw[10], lpw[ 9],
+ lpw[ 8], lpw[ 7], lpw[ 6], lpw[ 5],
+ lpw[ 4], lpw[ 3], lpw[ 2], lpw[ 1],
+ lpw[ 0] );
+ break;
+ case 28:
+ dwReturnValue = (* lpfn)( lpw[13], lpw[12], lpw[11], lpw[10],
+ lpw[ 9], lpw[ 8], lpw[ 7], lpw[ 6],
+ lpw[ 5], lpw[ 4], lpw[ 3], lpw[ 2],
+ lpw[ 1], lpw[ 0] );
+ break;
+ case 30:
+ dwReturnValue = (* lpfn)( lpw[14], lpw[13], lpw[12], lpw[11],
+ lpw[10], lpw[ 9], lpw[ 8], lpw[ 7],
+ lpw[ 6], lpw[ 5], lpw[ 4], lpw[ 3],
+ lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ case 32:
+ dwReturnValue = (* lpfn)( lpw[15], lpw[14], lpw[13], lpw[12],
+ lpw[11], lpw[10], lpw[ 9], lpw[ 8],
+ lpw[ 7], lpw[ 6], lpw[ 5], lpw[ 4],
+ lpw[ 3], lpw[ 2], lpw[ 1], lpw[ 0] );
+ break;
+ default:
+#ifdef DEBUG
+ OutputDebugString("Wrong number of parameters\n");
+#endif
+ fFailed = TRUE;
+ break;
+ }
+ if ( fFailed ) {
+ continue;
+ }
+
+ wSuccess = (WORD)TRUE;
+
+ } while( TRUE );
+
+ return( 1 );
+}
diff --git a/private/mvdm/wow16/wowdeb/wowdeb.rc b/private/mvdm/wow16/wowdeb/wowdeb.rc
new file mode 100644
index 000000000..b16d83763
--- /dev/null
+++ b/private/mvdm/wow16/wowdeb/wowdeb.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* WOWDEB.RC */
+/********************************************************************/
+#include "wowdeb.rcv"
diff --git a/private/mvdm/wow16/wowdeb/wowdeb.rcv b/private/mvdm/wow16/wowdeb/wowdeb.rcv
new file mode 100644
index 000000000..cc05d901f
--- /dev/null
+++ b/private/mvdm/wow16/wowdeb/wowdeb.rcv
@@ -0,0 +1,21 @@
+/********************************************************************/
+/* WOWDEB.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows NT Win16 Debugging Helper"
+#define VER_INTERNALNAME_STR "WOWDEB"
+#define VER_ORIGINALFILENAME_STR "WOWDEB.EXE"
+
+/* Change product name from Windows to Windows NT */
+
+#undef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows NT(TM) Operating System\0"
+
+#undef VER_LEGALTRADEMARKS_STR
+#define VER_LEGALTRADEMARKS_STR \
+"Microsoft\256 is a registered trademark of Microsoft Corporation. Windows NT(TM) is a trademark of Microsoft Corporation.\0"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/write/8514btns.bmp b/private/mvdm/wow16/write/8514btns.bmp
new file mode 100644
index 000000000..86b08826e
--- /dev/null
+++ b/private/mvdm/wow16/write/8514btns.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/8514mrks.bmp b/private/mvdm/wow16/write/8514mrks.bmp
new file mode 100644
index 000000000..97a0a1969
--- /dev/null
+++ b/private/mvdm/wow16/write/8514mrks.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/aaa.c b/private/mvdm/wow16/write/aaa.c
new file mode 100644
index 000000000..fae608a9d
--- /dev/null
+++ b/private/mvdm/wow16/write/aaa.c
@@ -0,0 +1,11 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* aaa.c -- special bogus module to substitute dummy function(s)
+ for c library stuff which is never called but gets pulled in anyway. */
+
+
+_malloc()
+{
+}
diff --git a/private/mvdm/wow16/write/addprm.c b/private/mvdm/wow16/write/addprm.c
new file mode 100644
index 000000000..3ebb6e3c2
--- /dev/null
+++ b/private/mvdm/wow16/write/addprm.c
@@ -0,0 +1,432 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* AddPrm.c -- Routines to add prms and sprms to docs */
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSMETRICS
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOPEN
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCTLMGR
+#define NOWNDCLASS
+#define NODRAWTEXT
+#define NOFONT
+#define NOGDI
+#define NOHDC
+#define NOMB
+#define NOMENUS
+#define NOMETAFILE
+#define NOMSG
+#define NOTEXTMETRIC
+#define NOSOUND
+#define NOSCROLL
+#define NOCOMM
+/* no everything except MEMMGR */
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "code.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "str.h"
+#include "prmdefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#include "stcdefs.h"
+#include "fkpdefs.h"
+#include "macro.h"
+#include "dispdefs.h"
+
+/* E X T E R N A L S */
+
+extern int docCur;
+extern struct SEL selCur;
+extern struct DOD (**hpdocdod)[];
+extern struct UAB vuab;
+extern int vfSysFull;
+extern CHAR dnsprm[];
+extern struct CHP vchpSel;
+extern typeCP vcpLimParaCache;
+extern typeCP cpMacCur;
+extern typeCP CpLimNoSpaces();
+extern int ferror;
+
+/* G L O B A L S */
+
+struct FPRM fprmCache = { 0 };
+struct PRM prmCache = {0,0,0,0};
+
+
+/* A D D O N E S P R M */
+/* applies sprm at psprm to the current selection. Take care of
+undoing, invalidation, special endmark cases, and extension of selection
+to paragraph boundaries */
+void AddOneSprm(psprm, fSetUndo)
+CHAR *psprm;
+int fSetUndo; /* True if we need to set up the undo buffer */
+{
+ int cch;
+ int fParaSprm = fFalse;
+ typeCP cpFirst, cpLim, dcp;
+
+ if (!FWriteOk( fwcNil ))
+ return;
+
+ if ((dnsprm[*psprm] & ESPRM_sgc) != sgcChar)
+ {
+ typeCP dcpExtraPara = cp0;
+
+ cpFirst = CpFirstSty( selCur.cpFirst, styPara );
+ CachePara( docCur, CpMax( selCur.cpLim - 1, selCur.cpFirst ) );
+ cpLim = vcpLimParaCache;
+
+ dcp = cpLim - cpFirst;
+
+ /* Check for para following selection that has no Eol */
+
+ if (cpLim < cpMacCur)
+ {
+ /* Note that in this case only, dcp (the # of cp's affected
+ by the change) does not equal (cpLim - cpFirst)
+ (the # of cp's to which the sprm should apply) */
+ CachePara( docCur, cpLim );
+ dcpExtraPara = vcpLimParaCache - cpLim;
+ }
+
+ if (cpFirst + dcp + dcpExtraPara > cpMacCur)
+ { /* Last para affected has no Eol -- add one */
+ struct SEL selSave;
+
+ dcp += dcpExtraPara;
+ Assert( cpFirst + dcp == cpMacCur + (typeCP) ccpEol);
+
+ if (fSetUndo)
+ {
+ SetUndo( uacReplNS, docCur, cpFirst, dcp,
+ docNil, cpNil, dcp - ccpEol, 0 );
+ fSetUndo = fFalse;
+ }
+ /* Add an eol. Save the current selection so
+ it does not get adjusted */
+ selSave = selCur;
+ InsertEolInsert(docCur,cpMacCur);
+ selCur = selSave;
+ }
+ }
+ else
+ { /* Char sprm -- eliminate trailing spaces from the
+ affected region, so we don't underline spaces after words. */
+ cpFirst = selCur.cpFirst;
+ cpLim = CpLimNoSpaces(selCur.cpFirst, selCur.cpLim);
+ dcp = cpLim - cpFirst;
+ if (dcp == 0)
+ { /* Doing character looks to the insert point... */
+ if (fSetUndo)
+ SetUndo(uacReplNS, docCur, cpFirst, cp0,
+ docNil, cp0, cp0, 0);
+ DoSprm(&vchpSel, 0, *psprm, psprm + 1);
+ return;
+ }
+ }
+
+ if (fSetUndo)
+ SetUndo(uacReplNS, docCur, cpFirst, dcp, docNil, cpNil, dcp, 0);
+
+ if (ferror) /* not enough memory to store info for undo operation */
+ {
+ NoUndo();
+ return;
+ }
+
+ AddSprmCps(psprm, docCur, cpFirst, cpLim);
+ AdjustCp( docCur, cpFirst, dcp, dcp );
+}
+
+/* E X P A N D C U R S E L */
+ExpandCurSel(pselSave)
+struct SEL *pselSave;
+{
+ *pselSave = selCur;
+
+ selCur.cpFirst = CpFirstSty(selCur.cpFirst, styPara);
+ CachePara(docCur, CpMax(selCur.cpLim - 1, selCur.cpFirst));
+ selCur.cpLim = vcpLimParaCache;
+}
+
+/* E N D L O O K S E L */
+EndLookSel(pselSave, fPara)
+struct SEL *pselSave; BOOL fPara;
+ {
+ typeCP cpLim, cpFirst, dcp;
+ dcp = (cpLim = selCur.cpLim) - (cpFirst = selCur.cpFirst);
+ if (fPara)
+ {
+ TrashCache();
+ if (cpLim <= cpMacCur)
+ {
+ CachePara(docCur, selCur.cpLim);
+ if (vcpLimParaCache > cpMacCur) /* Last (partial) paragraph */
+ dcp = cpMacCur - cpFirst + 1;
+ }
+ }
+ AdjustCp(docCur, cpFirst, dcp, dcp);
+
+ selCur = *pselSave;
+ }
+
+
+
+/* A D D S P R M */
+
+AddSprm(psprm)
+CHAR *psprm;
+{ /* Add a single property modifier to the pieces contained in selCur. */
+ AddSprmCps(psprm, docCur, selCur.cpFirst, selCur.cpLim);
+}
+
+
+/* A D D S P R M C P S */
+AddSprmCps(char *psprm, int doc, typeCP cpFirst, typeCP cpLim)
+{
+ struct PCTB **hpctb;
+ int ipcdFirst, ipcdLim, ipcd;
+ struct DOD *pdod;
+ int cch;
+ struct PCD *ppcd;
+
+/* First get address of piece table and split off desired pieces. */
+ pdod = &(**hpdocdod)[doc];
+ hpctb = pdod->hpctb;
+ pdod->fFormatted = fTrue;
+ ipcdFirst = IpcdSplit(hpctb, cpFirst);
+ ipcdLim = IpcdSplit(hpctb, cpLim);
+ if (ferror)
+ /* Ran out of memory trying to expand piece table */
+ return;
+
+/* Now just add this sprm to the pieces. */
+ FreezeHp();
+ for (ipcd = ipcdFirst, ppcd = &(**hpctb).rgpcd[ipcdFirst];
+ ipcd < ipcdLim && !vfSysFull; ++ipcd, ++ppcd)
+ ppcd->prm = PrmAppend(ppcd->prm, psprm);
+ MeltHp();
+}
+
+/* P R M A P P E N D */
+
+struct PRM PrmAppend(struct PRM prm, CHAR *psprm)
+{ /* Append <sprm, val> to the chain of sprm's in prm. Return new prm. */
+ struct FPRM *pfprmOld;
+ CHAR *pfsprm;
+ CHAR *pfsprmOld;
+ int sprm = *psprm;
+ int sprmOld;
+ register int esprm = dnsprm[sprm];
+ register int esprmOld;
+ int cchNew = (esprm & ESPRM_cch);
+ int cchOld;
+ int sgc = (esprm & ESPRM_sgc);
+ int spr = (esprm & ESPRM_spr);
+ int fSame = (esprm & ESPRM_fSame);
+ int fClobber = (esprm & ESPRM_fClobber);
+ int dval = 0;
+ int cch;
+ int cchT;
+ typeFC fcPrm;
+
+ struct FPRM fprm;
+
+ if (cchNew == 0) cchNew = CchPsprm(psprm);
+
+ pfsprm = fprm.grpfsprm;
+
+ if (prm.fComplex)
+ { /* Get the old list of sprm's from scratch file; copy it to fprm. */
+ pfprmOld = (struct FPRM *) PchFromFc(fnScratch,
+ //(typeFC)(unsigned)(((struct PRMX *) &prm)->bfprm << 1), &cch);
+ fcSCRATCHPRM(prm), &cch);
+ pfsprmOld = pfprmOld->grpfsprm;
+ cchT = cch = pfprmOld->cch;
+ while (cchT)
+ { /* Copy grpsprm, removing ones which we will clobber */
+ sprmOld = *pfsprmOld;
+ esprmOld = dnsprm[sprmOld];
+ if ((cchOld = (esprmOld & ESPRM_cch)) == 0)
+ cchOld = CchPsprm(pfsprmOld);
+#ifdef DEBUG
+ if (cchOld == 0)
+ panic();
+#endif
+ if (sprmOld == sprm && fSame ||
+ (esprmOld & ESPRM_sgc) == sgc &&
+ (esprmOld & ESPRM_spr) <= spr && fClobber)
+ {
+ /* make sure we properly coalesce change
+ size prms */
+ if (sprm == sprmOld && sprm == sprmCChgHps)
+ dval += *(pfsprmOld + 1);
+ cch -= cchOld;
+ }
+ /* CHps overrides CChgHps */
+ else if (sprmOld == sprmCChgHps && sprm == sprmCHps)
+ {
+ cch -= cchOld;
+ }
+ else
+ pfsprm = (CHAR *)bltbyte(pfsprmOld, pfsprm, cchOld);
+ pfsprmOld += cchOld;
+ cchT -= cchOld;
+ }
+ }
+ else
+ { /* No file entry yet; convert simple prm to fsprm */
+ int valOld = prm.val;
+ sprmOld = prm.sprm;
+ esprmOld = dnsprm[sprmOld];
+
+ if (bPRMNIL(prm) ||
+ sprmOld == sprm && fSame ||
+ (esprmOld & ESPRM_sgc) == sgc &&
+ (esprmOld & ESPRM_spr) <= spr && fClobber)
+ {
+ /* make sure we are combinning consecutive sprmCChgHps */
+ if (sprm == sprmOld && sprm == sprmCChgHps)
+ dval += valOld;
+ cch = 0;
+ }
+ /* CHps overrides CChgHps */
+ else if (sprmOld == sprmCChgHps && sprm == sprmCHps)
+ {
+ cch = 0;
+ }
+ else
+ { /* Save old sprm */
+ *pfsprm++ = sprmOld;
+ if ((cch = (esprmOld & ESPRM_cch)) == 2)
+ *pfsprm++ = valOld;
+ }
+ }
+/* we have: cch = length of old prm after removal of clobbered/etc. entries.
+cchNew: length of the entry to be appended.
+dval: correction for 2nd byte of new entry
+pfsprm: where 1st byte of new entry will go
+*/
+ bltbyte((CHAR *) psprm, pfsprm, imin(cchNew, cchMaxGrpfsprm - cch));
+ *(pfsprm + 1) += dval;
+
+ if (cch == 0 && cchNew <= 2)
+ { /* Pack sprm and val into a prm word. */
+ struct PRM prmT;
+ prmT.dummy=0;
+ bltbyte(pfsprm, (CHAR *) &prmT, cchNew);
+ prmT.fComplex = false;
+ prmT.sprm = *pfsprm;
+ return (prmT);
+ }
+
+ if ((cch += cchNew) > cchMaxGrpfsprm)
+ {
+ int fSave = ferror;
+ Error(IDPMT2Complex);
+ ferror = fSave;
+ return (prm);
+ }
+ if (vfSysFull)
+ return prm; /* Assume disk full message already given */
+
+ fprm.cch = cch;
+
+/* Check newly created prm to see if same as previous */
+ if (CchDiffer(&fprmCache, &fprm, cch + 1) == 0)
+ return prmCache;
+ bltbyte(&fprm, &fprmCache, cch + 1);
+
+ AlignFn(fnScratch, cch = ((cch >> 1) + 1) << 1, fTrue);
+ prm.fComplex = fTrue;
+
+ //((struct PRMX)prm).bfprm = FcWScratch((CHAR *) &fprm, cch) >> 1;
+
+ fcPrm = FcWScratch((CHAR *) &fprm, cch) >> 1;
+ ((struct PRMX *)&prm)->bfprm_hi = (fcPrm >> 16) & 0x7F;
+ ((struct PRMX *)&prm)->bfprm_low = fcPrm & 0xFFFF;
+
+ prmCache = prm;
+ return prm;
+}
+
+
+/* A P P L Y C L O O K S */
+/* character looks. val is a 1 char value */
+ApplyCLooks(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+{
+/* Assemble sprm */
+ CHAR rgbSprm[1 + cchINT];
+ CHAR *pch = &rgbSprm[0];
+ *pch++ = sprm;
+ *pch = val;
+
+ if (pchp == 0)
+ {
+ /* apply looks to current selection */
+ AddOneSprm(rgbSprm, fTrue);
+ vuab.uac = uacChLook;
+ SetUndoMenuStr(IDSTRUndoLook);
+ }
+ else
+ {
+ /* apply looks to pchp */
+ DoSprm(pchp, 0, sprm, pch);
+ }
+}
+
+
+/* A P P L Y L O O K S P A R A S */
+/* val is a char value */
+ApplyLooksParaS(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+ {
+ int valT = 0;
+ CHAR *pch = (CHAR *)&valT;
+ *pch = val;
+/* all the above is just to prepare bltbyte later gets the right byte order */
+ ApplyLooksPara(pchp, sprm, valT);
+ }
+
+
+/* A P P L Y L O O K S P A R A */
+/* val is an integer value. Char val's must have been bltbyte'd into val */
+ApplyLooksPara(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+{
+
+if (FWriteOk(fwcNil)) /* Check for out-of-memory/ read-only */
+ {
+ CHAR rgbSprm[1 + cchINT];
+ CHAR *pch = &rgbSprm[0];
+
+ *pch++ = sprm;
+ bltbyte(&val, pch, cchINT);
+ AddOneSprm(rgbSprm, fTrue);
+ vuab.uac = uacChLook;
+ SetUndoMenuStr(IDSTRUndoLook);
+ }
+}
diff --git a/private/mvdm/wow16/write/bitmaps.h b/private/mvdm/wow16/write/bitmaps.h
new file mode 100644
index 000000000..3c39a97ec
--- /dev/null
+++ b/private/mvdm/wow16/write/bitmaps.h
@@ -0,0 +1,21 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* These are defines for the different-sized, conditionally-loaded Ruler
+ bitmaps. See header of WRITE.RC and also FCreateRuler() ..pault */
+
+
+#define idBmBtns 100 /* Ruler Buttons */
+#define idBmBtnsCGA 100
+#define idBmBtnsEGA 101
+#define idBmBtnsVGA 102
+#define idBmBtns8514 103
+#define idBmBtnsMax 104
+
+#define idBmMarks 200 /* Ruler Marks */
+#define idBmMarksCGA 200
+#define idBmMarksEGA 201
+#define idBmMarksVGA 202
+#define idBmMarks8514 203
+#define idBmMarksMax 204
diff --git a/private/mvdm/wow16/write/cache.c b/private/mvdm/wow16/write/cache.c
new file mode 100644
index 000000000..010242af5
--- /dev/null
+++ b/private/mvdm/wow16/write/cache.c
@@ -0,0 +1,708 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* cache.c -- Paragraph attribute fetching and caching for WRITE */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSCOMMANDS
+#define NOCREATESTRUCT
+#define NOATOM
+#define NOMETAFILE
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOPEN
+#define NOBITMAP
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOMM
+#define NOMB
+#define NOMSG
+#define NOOPENFILE
+#define NORESOURCE
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#include <windows.h>
+
+#include "mw.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "fmtdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "prmdefs.h"
+#include "debug.h"
+
+extern int vfDiskError;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeFC fcMacPapIns;
+extern struct FCB (**hpfnfcb)[];
+extern struct FKPD vfkpdParaIns;
+extern int ichInsert;
+extern CHAR rgchInsert[];
+extern int vdocExpFetch;
+extern int vdocSectCache;
+extern typeCP vcpFirstSectCache;
+extern typeCP vcpLimSectCache;
+extern int vdocPageCache;
+extern typeCP vcpMinPageCache;
+extern typeCP vcpMacPageCache;
+extern typeCP cpMinCur;
+
+extern struct PAP vpapAbs;
+extern struct PAP *vppapNormal;
+extern struct DOD (**hpdocdod)[];
+extern struct FLI vfli;
+extern int vdxaPaper;
+extern int vdyaPaper;
+extern typePN PnFkpFromFcScr();
+
+
+extern int vdocParaCache;
+extern int visedCache;
+extern int vdocPageCache;
+
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern struct SEP vsepNormal;
+
+extern int ctrCache;
+extern int itrFirstCache;
+extern int itrLimCache;
+extern typeCP cpCacheHint;
+
+CHAR *PchFromFc();
+CHAR *PchGetPn();
+
+CachePara(doc, cp)
+int doc;
+typeCP cp;
+{ /* Make the para containing <doc, cp> the currently cached para */
+struct PCD *ppcd, *ppcdBase;
+typeCP cpMac, cpGuess;
+struct DOD *pdod;
+int dty;
+struct PCTB *ppctb;
+
+if (vdocParaCache == doc && vcpFirstParaCache <= cp &&
+ cp < vcpLimParaCache)
+ return; /* That's what the cache is for */
+
+Assert(cp >= cp0);
+
+pdod = &(**hpdocdod)[doc];
+dty = pdod->dty;
+if (cp >= pdod->cpMac)
+ { /* Use normal para for end mark and beyond */
+#ifdef ENABLE /* Occasionally this is not true (but it should be) */
+ Assert( cp == pdod->cpMac );
+#endif
+
+ if (cp > cpMinCur)
+ { /* this piece of code treats the case when the whole document
+ is a non-empty semi-paragraph (chars but no EOL's) */
+ CachePara( doc, cp - 1 ); /* Recursion will not happen */
+ if ( vcpLimParaCache > cp )
+ {
+ vcpLimParaCache = pdod->cpMac + ccpEol;
+ return;
+ }
+ }
+ vdocParaCache = doc;
+ vcpLimParaCache = (vcpFirstParaCache = pdod->cpMac) + ccpEol;
+ DefaultPaps( doc );
+ return;
+ }
+
+FreezeHp();
+ppctb = *pdod->hpctb;
+ppcdBase = &ppctb->rgpcd [ IpcdFromCp( ppctb, cpGuess = cp ) ];
+
+if (vdocParaCache == doc && cp == vcpLimParaCache)
+ vcpFirstParaCache = cp;
+else
+ { /* Search backward to find para start */
+ for (ppcd = ppcdBase; ; --ppcd)
+ { /* Beware heap movement! */
+ typeCP cpMin = ppcd->cpMin;
+ int fn = ppcd->fn;
+ if (! ppcd->fNoParaLast)
+ { /* Don't check if we know there's no para end */
+ typeFC fcMin = ppcd->fc;
+ typeFC fc;
+
+ if ((fc = FcParaFirst(fn,
+ fcMin + cpGuess - cpMin, fcMin)) != fcNil)
+ { /* Found para begin */
+ vcpFirstParaCache = cpMin + (fc - fcMin);
+ break;
+ }
+ }
+ /* Now we know there's no para end from cpMin to cpGuess. */
+ /* If original piece, may be one after cp */
+#ifdef BOGUSBL
+ /* vfInsertMode protects against a critical section in insert */
+ /* when the CR is already inserted but the supporting PAP structure */
+ /* is not in place yet */
+
+ if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
+#else /* Insert CR works differently now, above test slows us down
+ by forcing many calls to FcParaLim */
+ if (cp != cpGuess)
+#endif
+ ppcd->fNoParaLast = true; /* Save some work next time */
+ if (cpMin == cp0)
+ { /* Beginning of doc is beginning of para */
+ vcpFirstParaCache = cpMinCur;
+ break;
+ }
+
+ /** Some low memory error conditions may cause ppctb to be
+ screwed up **/
+ if (ppcd == ppctb->rgpcd)
+ {
+ Assert(0);
+ vcpFirstParaCache = cp0; // hope for divine grace
+ break;
+ }
+
+ cpGuess = cpMin;
+ }
+ }
+
+vdocParaCache = doc;
+/* Now go forward to find the cpLimPara */
+cpMac = pdod->cpMac;
+cpGuess = cp;
+
+for (ppcd = ppcdBase; ; ++ppcd)
+ {
+ typeCP cpMin = ppcd->cpMin;
+ typeCP cpLim = (ppcd + 1)->cpMin;
+ typeFC fc;
+ int fn = ppcd->fn;
+
+ if (! ppcd->fNoParaLast)
+ { /* Don't check if we know there's no para end */
+ typeFC fcMin = ppcd->fc;
+ if ((fc = FcParaLim(fn, fcMin + cpGuess - cpMin,
+ fcMin + (cpLim - cpMin), &vpapAbs)) != fcNil)
+ { /* Found para end */
+ vcpLimParaCache = cpMin + (fc - fcMin);
+ /* Under Write, FcParaLim can't set the correct rgtbd */
+ /* That's because tabs are a DOCUMENT property */
+ /* We set it here instead */
+ GetTabsForDoc( doc );
+ break;
+ }
+ }
+ /* Now we know there's no para end. */
+#ifdef BOGUSBL
+ /* The check for vfInsertMode is necessary because of a critical */
+ /* section in insertion between the insertion of a CR and the call */
+ /* to AddRunScratch */
+ if (cp != cpGuess && fn != fnInsert && !vfInsertMode)
+#else /* Insert CR has changed, we no longer try to pretend that
+ the CR is not in the scratch file piece before the run is
+ added. This new approach gains us speed, especially during backspace */
+ if (cp != cpGuess)
+#endif
+ ppcd->fNoParaLast = true; /* Save some work next time */
+ if (cpLim == cpMac)
+ { /* No EOL at end of doc */
+ vcpLimParaCache = cpMac + ccpEol;
+ MeltHp();
+ DefaultPaps( doc );
+ return;
+ }
+ /** Some low memory error conditions may cause ppctb to be
+ screwed up **/
+ else if ((cpLim > cpMac) || (ppcd == (ppctb->rgpcd + ppctb->ipcdMac - 1)))
+ {
+ Assert(0);
+ vcpLimParaCache = cpMac + ccpEol; // hope for divine grace
+ MeltHp();
+ DefaultPaps( doc );
+ return;
+ }
+ cpGuess = cpLim;
+ }
+
+/* Don't bother with properties for buffers */
+#ifdef ENABLE /* No buffers or styles in MEMO */
+if (dty != dtyBuffer || pdod->docSsht != docNil)
+#endif
+ {
+ struct PRM prm = ppcd->prm;
+ if (!bPRMNIL(prm))
+ DoPrm((struct CHP *) 0, &vpapAbs, prm);
+#ifdef STYLES
+ blt(vpapCache.fStyled ? PpropXlate(doc, &vpapCache, &vpapCache) :
+ &vpapCache, &vpapAbs, cwPAP);
+#endif /* STYLES */
+ }
+
+/* This little piece of code is necessary to provide compatibility between Word
+and Memo documents. It compresses the entire range of line spacing into single
+spacing, one and one-half spacing, and double spacing. */
+if (vpapAbs.dyaLine <= czaLine)
+ {
+ vpapAbs.dyaLine = czaLine;
+ }
+else if (vpapAbs.dyaLine >= 2 * czaLine)
+ {
+ vpapAbs.dyaLine = 2 * czaLine;
+ }
+else
+ {
+ vpapAbs.dyaLine = (vpapAbs.dyaLine + czaLine / 4) / (czaLine / 2) *
+ (czaLine / 2);
+ }
+
+MeltHp();
+}
+
+
+
+
+DefaultPaps( doc )
+int doc;
+{
+typeCP cpFirstSave, cpLimSave;
+struct TBD (**hgtbd)[];
+
+if (vcpFirstParaCache > cpMinCur)
+ { /* Get pap from previous paragraph */
+ cpFirstSave = vcpFirstParaCache;
+ cpLimSave = vcpLimParaCache;
+ CachePara(doc, cpFirstSave - 1); /* Recursion should not happen */
+ vpapAbs.fGraphics = false; /* Don't make last para a picture */
+ vpapAbs.rhc = 0; /* Don't make last para a running head */
+ vcpLimParaCache = cpLimSave;
+ vcpFirstParaCache = cpFirstSave;
+ return;
+ }
+#ifdef CASHMERE
+blt(vppapNormal, &vpapAbs, cwPAPBase+cwTBD);
+#else /* For MEMO, the default PAPS have the document's tab table */
+blt(vppapNormal, &vpapAbs, cwPAPBase);
+GetTabsForDoc( doc );
+#endif
+
+#ifdef STYLES
+blt(&vpapNormal, &vpapCache, cwPAP);
+blt(PpropXlate(doc, &vpapNormal, &vpapStd), &vpapAbs, cwPAP);
+#endif
+}
+
+
+
+
+GetTabsForDoc( doc )
+int doc;
+{ /* Get tab table for passed document into vpapAbs.rgtbd */
+struct TBD (**hgtbd)[];
+
+hgtbd = (**hpdocdod)[doc].hgtbd;
+if (hgtbd==0)
+ bltc( vpapAbs.rgtbd, 0, cwTBD * itbdMax );
+else
+ blt( *hgtbd, vpapAbs.rgtbd, cwTBD * itbdMax );
+}
+
+
+
+#ifdef CASHMERE
+CacheSect(doc, cp)
+int doc;
+typeCP cp;
+{
+struct SETB **hsetb, *psetb;
+struct SED *psed;
+CHAR *pchFprop;
+int cchT;
+struct DOD *pdod;
+
+if (doc == vdocSectCache && cp >= vcpFirstSectCache && cp < vcpLimSectCache)
+ return;
+
+if ( vdocSectCache != doc && cp != cp0 )
+ CacheSect( doc, cp0 ); /* Changing docs, assure vsepPage is accurate */
+
+vdocSectCache = doc;
+visedCache = iNil;
+blt(&vsepNormal, &vsepAbs, cwSEP);
+
+if ((hsetb = HsetbGet(doc)) == 0)
+ {
+ vcpFirstSectCache = cp0;
+ vcpLimSectCache = (pdod = &(**hpdocdod)[doc])->cpMac + 1;
+ blt(&vsepAbs, &vsepPage, cwSEP); /* set up page info */
+ return;
+ }
+
+psetb = *hsetb;
+psed = psetb->rgsed;
+
+FreezeHp();
+psed += (visedCache = IcpSearch(cp + 1, psed, cchSED, bcpSED, psetb->csed));
+
+Assert( (visedCache >= 0) && (visedCache < psetb->csed) );
+
+vcpFirstSectCache = (visedCache == 0) ? cp0 : (psed - 1)->cp;
+vcpLimSectCache = psed->cp;
+
+if (psed->fc != fcNil)
+ {
+ pchFprop = PchFromFc(psed->fn, psed->fc, &cchT);
+ if (*pchFprop != 0)
+ bltbyte(pchFprop + 1, &vsepAbs, *pchFprop);
+ }
+
+if (vcpFirstSectCache == cp0)
+ blt(&vsepAbs, &vsepPage, cwSEP);
+else
+ RecalcSepText(); /* Since this is not the first section of a document,
+ the margins could be wrong and must be recalculated */
+MeltHp();
+}
+#endif /* CASHMERE */
+
+
+
+CacheSect(doc, cp)
+int doc;
+typeCP cp;
+{ /* Get current section properties into vsepAbs; section
+ limits into vcpFirstSectCache, vcpLimSectCache
+ MEMO VERSION: one section per document */
+ struct DOD *pdod;
+
+ if (doc == vdocSectCache)
+ return;
+
+ vdocSectCache = doc;
+ pdod = &(**hpdocdod)[doc];
+
+ if ( pdod->hsep )
+ blt( *pdod->hsep, &vsepAbs, cwSEP );
+ else
+ blt( &vsepNormal, &vsepAbs, cwSEP );
+
+ vcpFirstSectCache = cp0;
+ vcpLimSectCache = pdod->cpMac;
+ blt(&vsepAbs, &vsepPage, cwSEP);
+}
+
+
+
+
+RecalcSepText()
+{
+/* calculate value to be changed because of change in page dimensions */
+int xaRight, dxaText, cColumns;
+int yaBottom, dyaText;
+
+xaRight = vsepPage.xaMac - vsepPage.cColumns * vsepPage.dxaText -
+ vsepPage.xaLeft - vsepPage.dxaGutter -
+ (vsepPage.cColumns - 1) * vsepPage.dxaColumns;
+dxaText = vdxaPaper - xaRight - vsepPage.xaLeft;
+cColumns = vsepAbs.cColumns;
+vsepAbs.dxaText = max(dxaMinUseful,
+ ((dxaText-vsepPage.dxaGutter-(cColumns-1)*vsepAbs.dxaColumns)/cColumns));
+vsepAbs.xaMac = vdxaPaper;
+
+ /* Calculate bottom margin, correct */
+yaBottom = vsepPage.yaMac - vsepPage.yaTop - vsepPage.dyaText;
+vsepAbs.dyaText = max(dyaMinUseful, vdyaPaper - vsepPage.yaTop - yaBottom);
+vsepAbs.yaMac = vdyaPaper;
+}
+
+
+
+
+InvalidateCaches(doc)
+int doc;
+{
+if (doc == vfli.doc) /* Invalidate current formatted line */
+ vfli.doc = docNil;
+if (doc == vdocExpFetch)
+ vdocExpFetch = docNil;
+if (doc == vdocParaCache)
+ vdocParaCache = docNil;
+if (doc == vdocSectCache)
+ vdocSectCache = docNil;
+
+/* When the current doc is equal to the cached doc, it is unnecessary */
+/* to invalidate the page cache when the vcpMinPageCache is 0 and the */
+/* vcpMacPageCache is cpMax, since this indicates that all characters in */
+/* the document are on page 1. */
+if ((doc == vdocPageCache) &&
+ (!(vcpMinPageCache == cp0 && vcpMacPageCache == cpMax)))
+ vdocPageCache = docNil;
+}
+
+
+
+
+TrashCache()
+{ /* Invalidate scrolling cache */
+ctrCache = 0;
+cpCacheHint = cp0;
+itrFirstCache = itrLimCache = 0;
+}
+
+
+
+
+typeFC FcParaFirst(fn, fc, fcMin)
+int fn;
+typeFC fc, fcMin;
+{ /* Return the fc after the latest para end before fc.
+ if there is no para end in [fcMin, fc), return fcNil. */
+struct FCB *pfcb;
+
+if ((fn == fnInsert) || (fc == fcMin))
+ return fcNil;
+
+if (fn == fnScratch && fc >= fcMacPapIns)
+ return (fcMin <= fcMacPapIns) ? fcMacPapIns : fcNil;
+
+pfcb = &(**hpfnfcb)[fn];
+if (!pfcb->fFormatted)
+ { /* Unformatted file; scan for an EOL */
+ typePN pn;
+ typeFC fcFirstPage;
+
+#ifdef p2bSector
+ fcFirstPage = (fc - 1) & ~(cfcPage - 1);
+ pn = fcFirstPage / cfcPage;
+#else
+ pn = (fc - 1) / cfcPage;
+ fcFirstPage = pn * cfcPage;
+#endif
+
+ while (fc > fcMin)
+ {
+ CHAR *pch;
+ int cchT;
+
+ pch = PchGetPn( fn, pn--, &cchT, false ) + (fc - fcFirstPage);
+ if (fcMin > fcFirstPage)
+ fcFirstPage = fcMin;
+ while (fc > fcFirstPage)
+ {
+ if (*(--pch) == chEol)
+ {
+ return fc;
+ }
+ fc--;
+ }
+ fcFirstPage -= cfcPage;
+ }
+ return fcNil;
+ }
+else
+ { /* Formatted file; get info from para run */
+ struct FKP *pfkp;
+ typeFC fcFirst, fcLim;
+ int cchT;
+
+ pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
+ PnFkpFromFcScr(&vfkpdParaIns, fc) :
+ pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
+ if (vfDiskError)
+ return fcNil;
+ BFromFc(pfkp, fc, &fcFirst, &fcLim);
+ return (fcMin < fcFirst) ? fcFirst : fcNil;
+ }
+}
+
+
+
+
+typeFC FcParaLim(fn, fc, fcMac, ppap)
+int fn;
+typeFC fc, fcMac;
+struct PAP *ppap;
+{ /* Return the fc after the first para end after or at fc.
+ if there is no para end in [fc, fcMac), return fcNil. */
+/* Also return paragraph properties in ppap */
+ struct FCB *pfcb;
+
+/* Start out by feeding caller the normal pap */
+#ifdef CASHMERE
+ blt(vppapNormal, ppap, cwPAPBase + cwTBD);
+#else
+ blt(vppapNormal, ppap, cwPAPBase);
+#endif
+
+ if ( (fn == fnInsert) || ((fn == fnScratch) && (fc >= fcMacPapIns)) )
+ return fcNil;
+
+ if (!(pfcb = &(**hpfnfcb) [fn])->fFormatted)
+ { /* Unformatted file; scan for EOL */
+ typePN pn;
+ typeFC fcFirstPage;
+
+#ifdef p2bSector
+ fcFirstPage = fc & ~(cfcPage - 1);
+ pn = fcFirstPage / cfcPage;
+#else
+ pn = fc / cfcPage;
+ fcFirstPage = pn * cfcPage;
+#endif
+
+ while (fc < fcMac)
+ {
+ CHAR *pch;
+ int cchT;
+
+ pch = PchGetPn( fn, pn++, &cchT, false ) + (fc - fcFirstPage);
+
+ if ((fcFirstPage += cfcPage) > fcMac)
+ fcFirstPage = fcMac;
+ while (fc < fcFirstPage)
+ {
+ fc++;
+ if (*pch++ == chEol)
+ return fc;
+ }
+ }
+ return fcNil;
+ }
+else
+ { /* Formatted file; get info from para run */
+ struct FKP *pfkp;
+ struct FPAP *pfpap;
+ int bfpap;
+ typeFC fcLim;
+ int cchT;
+
+ pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
+ PnFkpFromFcScr(&vfkpdParaIns, fc) :
+ pfcb->pnPara + IFromFc(**pfcb->hgfcPap, fc), &cchT, false);
+ if (vfDiskError)
+ { /* Recover from severe disk error reading formatting info */
+ blt(vppapNormal, ppap, cwPAP);
+ return (fcMac == pfcb->fcMac) ? fcMac : fcNil;
+ }
+
+ { /* In-line, fast substitute for BFromFc */
+ register struct RUN *prun = (struct RUN *) pfkp->rgb;
+
+ while (prun->fcLim <= fc)
+ prun++;
+
+ fcLim = prun->fcLim;
+ bfpap = prun->b;
+ }
+
+ if (fcLim <= fcMac)
+ {
+ if (bfpap != bNil)
+ { /* Non-standard para */
+ pfpap = (struct FPAP *) &pfkp->rgb[bfpap];
+ bltbyte(pfpap->rgchPap, ppap, pfpap->cch);
+ }
+ return fcLim;
+ }
+ return fcNil;
+ }
+}
+
+
+/* B F R O M FC */
+int BFromFc( pfkp, fc, pfcFirst, pfcLim )
+struct FKP *pfkp;
+typeFC fc;
+typeFC *pfcFirst, *pfcLim;
+{ /* Return the base offset & bounds for the first run with fcLim > fc. */
+ /* Short table, linear search */
+ register struct RUN *prun = (struct RUN *) pfkp->rgb;
+
+ while (prun->fcLim <= fc)
+ prun++;
+
+ *pfcFirst = ((prun == (struct RUN *)pfkp->rgb) ?
+ pfkp->fcFirst : (prun - 1)->fcLim);
+ *pfcLim = prun->fcLim;
+ return prun->b;
+}
+
+
+
+/* I F R O M F C */
+int IFromFc(pfcLim, fc)
+register typeFC *pfcLim;
+typeFC fc;
+{ /* Return the index of the first fcLim > fc. */
+int ifc = 0;
+
+/* Probably a small table, so linear search? */
+while (*pfcLim++ <= fc)
+ ++ifc;
+return ifc;
+}
+
+
+
+
+
+#ifdef BOGUSBL
+/* B F R O M F C */
+int BFromFc(pfkp, fc, pfcFirst, pfcLim)
+struct FKP *pfkp;
+typeFC fc;
+typeFC *pfcFirst, *pfcLim;
+{ /* Return the base offset & bounds for the first run with fcLim > fc. */
+struct RUN *prun, *rgrun;
+int ifcMin, ifcLim;
+
+ifcMin = 0;
+ifcLim = pfkp->crun;
+rgrun = (struct RUN *)pfkp->rgb;
+
+#ifdef INEFFICIENT
+ifc = IcpSearch(fc + 1, pfkp->rgb, cchRUN, bfcRUN, pfkp->crun);
+#endif
+
+while (ifcMin + 1 < ifcLim)
+ {
+ int ifcGuess = (ifcMin + ifcLim - 1) >> 1;
+ if (rgrun[ifcGuess].fcLim <= fc)
+ ifcMin = ifcGuess + 1;
+ else
+ ifcLim = ifcGuess + 1;
+ }
+
+prun = &rgrun[ifcMin];
+*pfcLim = prun->fcLim;
+*pfcFirst = (ifcMin == 0 ? pfkp->fcFirst : (prun - 1)->fcLim);
+return prun->b;
+}
+#endif /* BOGUSBL */
diff --git a/private/mvdm/wow16/write/center.bms b/private/mvdm/wow16/write/center.bms
new file mode 100644
index 000000000..1f6608762
--- /dev/null
+++ b/private/mvdm/wow16/write/center.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/cgabtns.bmp b/private/mvdm/wow16/write/cgabtns.bmp
new file mode 100644
index 000000000..cd0d85d9c
--- /dev/null
+++ b/private/mvdm/wow16/write/cgabtns.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/cgamarks.bmp b/private/mvdm/wow16/write/cgamarks.bmp
new file mode 100644
index 000000000..bf3f42f84
--- /dev/null
+++ b/private/mvdm/wow16/write/cgamarks.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/ch.h b/private/mvdm/wow16/write/ch.h
new file mode 100644
index 000000000..92002edae
--- /dev/null
+++ b/private/mvdm/wow16/write/ch.h
@@ -0,0 +1,216 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file defines the characters used by Windows Word. */
+/* You must include windows.h to get virtual key definitions */
+
+#define chNil (-1)
+
+/* Characters in files */
+
+#define chDelPrev 0x08
+#define chTab 0x09
+#define chEol 0x0A
+#define chNewLine 0x0B
+#define chSect 0x0C
+#define chReturn 0x0D
+#define chNRHFile 0x1F /* Non-required hyphen */
+
+#ifndef NOKCCODES
+/* Keyboard Characters */
+/* A high bit of 1 means that this is a command character */
+/* For Windows, a command character it one that is processed through */
+/* the virtual key mechanism (WM_KEYBOARD) instead of translated (WM_CHAR) */
+
+#define wKcCommandMask 0x8000 /* mask that tells if command */
+#define FIsCommandKc(kc) ((int)(kc) < 0) /* or, test it this way */
+
+#define kcDelPrev (wKcCommandMask | VK_BACK)
+#define kcDelNext (wKcCommandMask | VK_DELETE)
+#define kcInsert (wKcCommandMask | VK_INSERT)
+#define kcTab (wKcCommandMask | VK_TAB )
+#define kcReturn (wKcCommandMask | VK_RETURN)
+#define kcLeft (wKcCommandMask | VK_LEFT)
+#define kcUp (wKcCommandMask | VK_UP)
+#define kcRight (wKcCommandMask | VK_RIGHT)
+#define kcDown (wKcCommandMask | VK_DOWN)
+#define kcPageUp (wKcCommandMask | VK_PRIOR)
+#define kcPageDown (wKcCommandMask | VK_NEXT)
+#define kcBeginLine (wKcCommandMask | VK_HOME)
+#define kcEndLine (wKcCommandMask | VK_END)
+#define kcGoto (wKcCommandMask | VK_CLEAR)
+
+/* Special for windows: we must handle these key codes & update shift state */
+
+#define kcShift (wKcCommandMask | VK_SHIFT)
+#define kcControl (wKcCommandMask | VK_CONTROL)
+#define kcAlt (wKcCommandMask | VK_MENU)
+#define kcCapsLock (wKcCommandMask | VK_CAPITAL)
+
+/* Phony Keyboard Characters, used to force actions */
+
+#define kcNextPara 0xFFFE /* Generated from GOTO-DOWN */
+#define kcPrevPara 0xFFFD /* Generated from GOTO-UP */
+/* #define kcAlphaVirtual 0xFFFC Defined below, outside ifdef */
+
+/* Keys that affect the look of the current selection (char or para) */
+
+#define kcLookMin 0x8001 /* As of now, no look keys */
+#define kcLookMax 0x8000
+
+/* These control keys are processed as WM_CHAR ASCII codes */
+
+#define kcLFld (wKcCommandMask | ('[' & 0x1F)) /* Print-Merge <<>> */
+#define kcRFld (wKcCommandMask | (']' & 0x1F)) /* CTRL-[ and CTRL-] */
+
+/* Keyboard Kontrol (CTRL) codes -- a key message word is interpreted
+ as a kk instead of a kc, if the CTRL key is down */
+
+#define kkUpScrollLock (kcUp)
+#define kkDownScrollLock (kcDown)
+#define kkTopDoc (wKcCommandMask | VK_HOME)
+#define kkEndDoc (wKcCommandMask | VK_END)
+#define kkTopScreen (wKcCommandMask | VK_PRIOR)
+#define kkEndScreen (wKcCommandMask | VK_NEXT)
+#define kkWordLeft (wKcCommandMask | VK_LEFT)
+#define kkWordRight (wKcCommandMask | VK_RIGHT)
+#define kkCopy (wKcCommandMask | VK_INSERT)
+#define kkDelPrev (wKcCommandMask | VK_BACK)
+
+#if WINVER < 0x300
+#define kkNonReqHyphen (wKcCommandMask | VK_MINUS)
+#else
+/* I don't know how the above EVER worked so I'm changing
+ it to use the return value from VkKeyScan(). See routines
+ KcAlphaKeyMessage() and FNonAlphaKeyMessage() ..pault */
+
+#define kkNonReqHyphen (wKcCommandMask | vkMinus)
+#endif
+
+#ifdef CASHMERE /* These keys not supported by MEMO */
+#define kkNonBrkSpace (wKcCommandMask | (unsigned) ' ')
+#define kkNLEnter (wKcCommandMask | VK_RETURN) /* EOL w/o end Para */
+#endif
+
+/* CTRL-shifted keys */
+
+#define kksPageBreak (wKcCommandMask | VK_RETURN)
+
+#ifdef DEBUG
+#define kksEatWinMemory (wKcCommandMask | 'H') /* Hog Windows Heap */
+#define kksFreeWinMemory (wKcCommandMask | 'R') /* Release Windows heap */
+#define kksEatMemory (wKcCommandMask | 'E') /* Eat WRITE Heap Space */
+#define kksFreeMemory (wKcCommandMask | 'F') /* Free WRITE Heap Space */
+#define kksTest (wKcCommandMask | VK_ESCAPE)
+#endif
+
+/* Transformation from kk && kks codes to a unique kc code */
+
+#define KcFromKk(kk) ( (kk) + 0x100 )
+#define KcFromKks(kks) ( (kks) + 0x200 )
+
+/* new style ctrl-key accelerators (7.22.91) v-dougk */
+#define kkNewCopy (wKcCommandMask | 'C')
+#define kkNewUndo (wKcCommandMask | 'Z')
+#define kkNewPaste (wKcCommandMask | 'V')
+#define kkNewCut (wKcCommandMask | 'X')
+
+/* Kc codes for CTRL-keys that are processed at the virtual key level */
+
+#define kcNewCopy KcFromKk( kkNewCopy )
+#define kcNewUndo KcFromKk( kkNewUndo )
+#define kcNewPaste KcFromKk( kkNewPaste )
+#define kcNewCut KcFromKk( kkNewCut )
+#define kcTopDoc KcFromKk( kkTopDoc )
+#define kcEndDoc KcFromKk( kkEndDoc )
+#define kcTopScreen KcFromKk( kkTopScreen )
+#define kcEndScreen KcFromKk( kkEndScreen )
+#define kcWordLeft KcFromKk( kkWordLeft )
+#define kcWordRight KcFromKk( kkWordRight )
+#define kcCut KcFromKk( kkCut )
+#define kcPaste KcFromKk( kkPaste )
+#define kcCopy KcFromKk( kkCopy )
+#define kcClear KcFromKk( kkClear )
+#define kcUndo KcFromKk( kkUndo )
+#define kcUpScrollLock KcFromKk( kkUpScrollLock )
+#define kcDownScrollLock KcFromKk( kkDownScrollLock )
+
+#ifdef DEBUG /* kc codes for Debugging control keys */
+#define kcEatWinMemory KcFromKks(kksEatWinMemory)
+#define kcFreeWinMemory KcFromKks(kksFreeWinMemory)
+#define kcEatMemory KcFromKks(kksEatMemory)
+#define kcFreeMemory KcFromKks(kksFreeMemory)
+#define kcTest (KcFromKks(kksTest))
+#endif /* DEBUG */
+
+/* A special case: kcPageBreak is a CTRL-SHIFT key that is processed in
+ AlphaMode */
+#define kcPageBreak KcFromKks( kksPageBreak )
+
+#define kcNonReqHyphen KcFromKk( kkNonReqHyphen )
+
+#ifdef CASHMERE /* These keys not supported by MEMO */
+#define kcNonBrkSpace KcFromKk( kkNonBrkSpace )
+#define kcNLEnter KcFromKk( kkNLEnter )
+#endif
+
+#endif /* #ifndef NOKCCODES */
+
+ /* Outside #ifdef because these are return codes from Kc funcs */
+ /* Also defined in mmw.c because of compiler stack overflow problems */
+#define kcNil 0xFFFF
+#define kcAlphaVirtual 0xFFFC /* Means "Virtual Key, must translate it" */
+
+/* Display & text-processing characters. These are real characters in the ANSI
+character set as opposed to characters that appear in the file. */
+
+#define chSpace ' '
+#define chHyphen '-'
+
+#ifndef DBCS
+/* we defined them in kanji.h */
+#define chStatPage (CHAR)'\273'
+#define chStatRH '>'
+#define chEMark (CHAR)'\244'
+#endif
+
+#define chSplat '.'
+#define chSectSplat ':'
+#define chDot '.'
+#define chDecimal '.'
+#define chBang '!'
+#define chQMark '?'
+#define chQuote '"'
+#define chFldSep ','
+#define chLParen '('
+#define chRParen ')'
+#define chStar '*'
+#define chLFldFile (CHAR)'\253'
+#define chRFldFile (CHAR)'\273'
+#define chNBH (CHAR)'\255' /* Non-breaking hyphen */
+#define chNBSFile (CHAR)'\240' /* Non-breaking space */
+
+
+/* The following are "special" characters that are essentially macros for longer
+strings. */
+
+#define schPage (CHAR)'\001'
+#define schFootnote (CHAR)'\005'
+#define schInclude (CHAR)'\006'
+
+/* Characters in Search patterns */
+#define chPrefixMatch '^'
+#define chMatchAny '?'
+#define chMatchWhite 'w'
+#define chMatchTab 't'
+#define chMatchEol 'p'
+#define chMatchNewLine 'n'
+#define chMatchSect 'd'
+#define chMatchNBSFile 's'
+#define chMatchNRHFile '-'
+
+/* ANSI block character, see FWriteExtTextScrap! ..pault */
+
+#define chBlock 0x7f
+
diff --git a/private/mvdm/wow16/write/chlook.c b/private/mvdm/wow16/write/chlook.c
new file mode 100644
index 000000000..bc51e668e
--- /dev/null
+++ b/private/mvdm/wow16/write/chlook.c
@@ -0,0 +1,382 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* chlook.c -- modify format from the keyboard or directly from dropdown */
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOGDICAPMASKS
+#define NOWINSTYLES
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "editdefs.h"
+#include "str.h"
+#include "prmdefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#include "dispdefs.h"
+#include "menudefs.h"
+
+/* E X T E R N A L S */
+extern HMENU vhMenu;
+extern int vfVisiMode;
+extern int vfInsLast;
+extern int vfSeeSel;
+extern int fGrayChar;
+extern struct UAB vuab;
+#ifdef ENABLE /* myMenus and mpifntfont not used */
+extern MENUHANDLE myMenus[];
+extern int mpifntfont[];
+#endif
+extern int vifntMac;
+extern int vifntApplication;
+
+#define keyDownMask 8
+
+CHAR rgbAgain[1 + cchINT]; /* holds last sprm with value for Again key */
+
+/* D O C H L O O K */
+/* decode ch and apply looks to pchp (or to current sel if pchp == 0) */
+DoChLook(ch, pchp)
+int ch;
+struct CHP *pchp;
+{
+#ifdef ENABLE /* DoChLook not implemented yet */
+ typeCP cpFirst, cpLim;
+ int val;
+ int sprm;
+ int enbSave;
+
+ vfSeeSel = vfInsLast = fTrue;
+ if (ch == chAgain)
+ {
+ AddOneSprm(rgbAgain, fTrue);
+ vuab.uac = uacChLook;
+ SetUndoMenuStr(IDSTRUndoLook);
+ return;
+ }
+
+ val = fTrue;
+ switch(ChUpper(ch & 0377))
+ {
+ default:
+/*---- Error(IDPMTBadLook);----*/
+ beep();
+ return;
+ case chLookStd & 0377:
+ sprm = sprmCPlain;
+ val = stcNormal;
+ goto LApplyCLook;
+ case chLookItalic & 0377:
+ sprm = sprmCItalic;
+ goto LApplyCLook;
+ case chLookBold & 0377:
+ sprm = sprmCBold;
+ goto LApplyCLook;
+ case chLookUline & 0377:
+ sprm = sprmCUline;
+ goto LApplyCLook;
+ case chLookShadow & 0377:
+ sprm = sprmCShadow;
+ goto LApplyCLook;
+ case chLookOutline & 0377:
+ sprm = sprmCOutline;
+ goto LApplyCLook;
+ case chLookSuper & 0377:
+ sprm = sprmCPos;
+ val = ypSubSuper;
+ goto LApplyCLook;
+ case chLookSub & 0377:
+ sprm = sprmCPos;
+ val = -ypSubSuper;
+ goto LApplyCLook;
+ case chLookSmCaps & 0377:
+ sprm = sprmCCsm;
+ val = csmSmallCaps;
+ goto LApplyCLook;
+ case chLookHpsBig & 0377:
+ sprm = sprmCChgHps;
+ val = 1;
+ goto LApplyCLook;
+ case chLookHpsSmall & 0377:
+ sprm = sprmCChgHps;
+ val = -1;
+ goto LApplyCLook;
+ case chLookFont & 0377:
+/* Disable eject disk/ print image key handlers */
+#define SCRDMPENB (0x2f8L)
+ enbSave = LDBI(SCRDMPENB);
+ STBI(0, SCRDMPENB);
+ ch = ChInpWait();
+ STBI(enbSave, SCRDMPENB);
+ if (ch < '0' || ch > '9')
+ {
+/*---- Error(IDPMTBadLook);----*/
+ beep();
+ return;
+ }
+ sprm = sprmCChgFtc;
+ val = ch - '0';
+/* Map from font index to system font code */
+ val = val >= vifntMac ? vifntApplication & 0377: mpifntfont[val];
+ goto LApplyCLook;
+
+ /* Paragraph looks */
+ case chLookGeneral & 0377:
+ sprm = sprmPNormal;
+ /*val = 0;*/
+ break;
+ case chLookLeft & 0377:
+ sprm = sprmPJc;
+ val = jcLeft;
+ break;
+ case chLookRight & 0377:
+ sprm = sprmPJc;
+ val = jcRight;
+ break;
+ case chLookJust & 0377:
+ sprm = sprmPJc;
+ val = jcBoth;
+ break;
+ case chLookCenter & 0377:
+ sprm = sprmPJc;
+ val = jcCenter;
+ break;
+ case chLookIndent & 0377:
+ val = czaInch/2;
+ sprm = sprmPFIndent;
+ goto LApplyPLook;
+ case chLookDouble & 0377:
+ val = czaLine * 2;
+ sprm = sprmPDyaLine;
+ goto LApplyPLook;
+ case chLookOpen & 0377:
+ val = czaLine;
+ sprm = sprmPDyaBefore;
+ goto LApplyPLook;
+ case chLookNest & 0377:
+ sprm = sprmPNest;
+ /*val = 0;*/
+ break;
+ case chLookUnNest & 0377:
+ sprm = sprmPUnNest;
+ /*val = 0;*/
+ break;
+ case chLookHang & 0377:
+ sprm = sprmPHang;
+ /*val = 0;*/
+ break;
+ }
+/* apply look with 1 char value */
+ ApplyLooksParaS(pchp, sprm, val);
+ return;
+/* apply look with cchInt char value */
+LApplyPLook:
+ ApplyLooksPara(pchp, sprm, val);
+ return;
+
+LApplyCLook:
+ ApplyCLooks(pchp, sprm, val);
+ return;
+#endif /* ENABLE */
+}
+
+/* A P P L Y C L O O K S */
+/* character looks. val is a 1 char value */
+ApplyCLooks(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+{
+/* Assemble sprm */
+ CHAR *pch = rgbAgain;
+ *pch++ = sprm;
+ *pch = val;
+
+ if (pchp == 0)
+ {
+/* apply looks to current selection */
+ AddOneSprm(rgbAgain, fTrue);
+ vuab.uac = uacChLook;
+ SetUndoMenuStr(IDSTRUndoLook);
+ }
+ else
+/* apply looks to pchp */
+ DoSprm(pchp, 0, sprm, pch);
+}
+
+/* A P P L Y L O O K S P A R A S */
+/* val is a char value */
+ApplyLooksParaS(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+ {
+ int valT = 0;
+ CHAR *pch = (CHAR *)&valT;
+ *pch = val;
+/* all the above is just to prepare bltbyte later gets the right byte order */
+ ApplyLooksPara(pchp, sprm, valT);
+ }
+
+/* A P P L Y L O O K S P A R A */
+/* val is an integer value. Char val's must have been bltbyte'd into val */
+ApplyLooksPara(pchp, sprm, val)
+struct CHP *pchp;
+int sprm, val;
+{
+
+#ifdef ENABLE /* related to footnote */
+if (FWriteCk(fwcNil)) /* Just check for illegal action in footnote */
+#endif
+ {
+/* set Again stuff since we may have been called from the menu */
+ CHAR *pch = rgbAgain;
+ *pch++ = sprm;
+ bltbyte(&val, pch, cchINT);
+ AddOneSprm(rgbAgain, fTrue);
+ vuab.uac = uacChLook;
+ SetUndoMenuStr(IDSTRUndoLook);
+ }
+return;
+}
+
+
+#ifdef ENABLE /* fnChar/fnPara */
+/* F N C H A R P L A I N */
+void fnCharPlain()
+{
+ ApplyCLooks(0, sprmCPlain, 0);
+}
+
+/* F N C H A R B O L D */
+void fnCharBold()
+{
+ ApplyCLooks(0, sprmCBold, FMenuUnchecked(imiBold));
+}
+
+void fnCharItalic()
+{
+ ApplyCLooks(0, sprmCItalic, FMenuUnchecked(imiItalic));
+}
+
+void fnCharUnderline()
+{
+ ApplyCLooks(0, sprmCUline, FMenuUnchecked(imiUnderline));
+}
+
+void fnCharSuperscript()
+{
+ ApplyCLooks(0, sprmCPos, FMenuUnchecked(imiSuper) ? ypSubSuper : 0);
+}
+
+void fnCharSubscript()
+{
+ ApplyCLooks(0, sprmCPos, FMenuUnchecked(imiSub) ? -ypSubSuper : 0);
+}
+
+void fnParaNormal()
+{
+extern int vfPictSel;
+
+ ApplyLooksParaS(0, sprmPNormal, 0);
+ if (vfPictSel)
+ CmdUnscalePic();
+}
+
+void fnParaLeft()
+{
+ ApplyLooksParaS(0, sprmPJc, jcLeft);
+}
+
+void fnParaCentered()
+{
+ ApplyLooksParaS(0, sprmPJc, jcCenter);
+}
+
+void fnParaRight()
+{
+ ApplyLooksParaS(0, sprmPJc, jcRight);
+}
+
+void fnParaJustified()
+{
+ ApplyLooksParaS(0, sprmPJc, jcBoth);
+}
+
+void fnParaOneandhalfspace()
+{
+ ApplyLooksPara(0, sprmPDyaLine, czaLine * 3 / 2);
+}
+
+void fnParaDoublespace()
+{
+ ApplyLooksPara(0, sprmPDyaLine, czaLine * 2);
+}
+
+void fnParaSinglespace()
+{
+ ApplyLooksPara(0, sprmPDyaLine, czaLine);
+}
+
+int
+FMenuUnchecked(imi)
+int imi;
+{ /* Return true if there is NO check mark in front of menu */
+int flag;
+
+ if (fGrayChar)
+ return true;
+ flag = CheckMenuItem(vhMenu, imi, MF_CHECKED);
+ CheckMenuItem(vhMenu, imi, flag); /* back to original status */
+ return(flag == MF_UNCHECKED ? true : false);
+
+#ifdef SAND
+ GetItemMark(myMenus[CHARACTER - 1], imi, &ch);
+/***** WRONG COMMENT BELOW! *****/
+ return (ch != 18); /* Return true is there is a check mark in front of menu */
+#endif /* SAND */
+}
+#endif
+
+
+int ChInpWait()
+{
+#ifdef ENABLE /* CpInpWait not implemented yet */
+EVENT event;
+int i;
+for (i = 0; i < 15000; i++)
+ {
+ if(GetNextEvent(keyDownMask, &event))
+ return (event.message.wl & 0x007f);
+ }
+return -1; /* Will cause a beep if the user times out */
+#endif /* ENABLE */
+}
+
+#ifdef CASHMERE /* smcap, overstrike, dbline, open para, visible mode */
+fnCharSmallcaps()
+{
+ ApplyCLooks(0, sprmCCsm, FMenuUnchecked(7) ? csmSmallCaps : csmNormal);
+}
+fnCharOutline()
+{
+ ApplyCLooks(0, sprmCOutline, FMenuUnchecked(5));
+}
+
+fnCharShadow()
+{
+ ApplyCLooks(0, sprmCShadow, FMenuUnchecked(6));
+}
+fnParaOpenspace()
+{
+ ApplyLooksPara(0, sprmPDyaBefore, czaLine);
+}
+fnVisiMode()
+{
+ vfVisiMode = !vfVisiMode;
+ TrashAllWws();
+}
+#endif /* CASHMERE */
diff --git a/private/mvdm/wow16/write/chngwin.c b/private/mvdm/wow16/write/chngwin.c
new file mode 100644
index 000000000..382f8cdbc
--- /dev/null
+++ b/private/mvdm/wow16/write/chngwin.c
@@ -0,0 +1,336 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOCLIPBOARD
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NORESOURCE
+#define NODRAWTEXT
+#define NOSOUND
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "winddefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+#include "docdefs.h"
+#include "debug.h"
+
+extern HWND vhWnd;
+extern HWND vhWndSizeBox;
+extern HWND vhWndRuler;
+extern HWND vhWndPageInfo;
+extern HWND vhWndCancelPrint;
+extern HDC vhDCPrinter;
+extern HFONT vhfPageInfo;
+extern HCURSOR vhcArrow;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcBarCur;
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern HANDLE hMmwModInstance; /* handle to own module instance */
+extern int vfShiftKey;
+extern int vfCommandKey;
+extern int vfOptionKey;
+extern int vfDoubleClick;
+extern struct SEL selCur;
+extern long rgbBkgrnd;
+extern long rgbText;
+extern HBRUSH hbrBkgrnd;
+extern long ropErase;
+extern int vfIconic;
+extern int vfLargeSys;
+extern int dxpRuler;
+extern HMENU vhMenu;
+
+#ifdef JAPAN // Indicate whether to show IME convert window
+extern BOOL ConvertEnable;
+#endif
+
+
+
+void MmwSize(hWnd, cxpNew, cypNew, code)
+HWND hWnd;
+int cxpNew;
+int cypNew;
+WORD code;
+{
+ if (code == SIZEICONIC)
+ {
+#ifdef NOT_RECOMMENDED
+/* This should already be done by Windows itself!
+ Moving here could cause confusion */
+
+ /* Resize the document window. */
+ if (wwdCurrentDoc.wwptr != NULL)
+ MoveWindow(wwdCurrentDoc.wwptr, 0, 0, 0, 0, FALSE);
+#endif
+
+ /* Deselect our fonts so that they can move if necessary. */
+ ResetFont(FALSE);
+ if (vhWndCancelPrint == NULL)
+ {
+ /* Reset the printer font iff we are not printing or repaginating.
+ */
+ ResetFont(TRUE);
+ }
+ if (!vfLargeSys && vhfPageInfo != NULL)
+ {
+ DeleteObject(SelectObject(GetDC(vhWndPageInfo),
+ GetStockObject(SYSTEM_FONT)));
+ vhfPageInfo = NULL;
+ }
+
+ vfIconic = TRUE;
+ }
+ else
+ {
+ int dxpBorder = GetSystemMetrics(SM_CXBORDER);
+ int dypBorder = GetSystemMetrics(SM_CYBORDER);
+ int xpMac = cxpNew - dxpScrlBar + dxpBorder;
+ int ypMac = cypNew - dypScrlBar + dypBorder;
+ int dypOverlap = 0;
+
+ /* If we are coming back from being iconic, then reestablish the printer
+ DC. */
+ if (vfIconic && vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ }
+
+ /* Reposition all of the windows. */
+ MoveWindow(wwdCurrentDoc.hVScrBar, xpMac, -dypBorder, dxpScrlBar, ypMac
+ + (dypBorder << 1), TRUE);
+ MoveWindow(wwdCurrentDoc.hHScrBar, dxpInfoSize, ypMac, cxpNew -
+ dxpInfoSize - dxpScrlBar + (dxpBorder << 1), dypScrlBar, TRUE);
+#ifndef NOMORESIZEBOX
+ MoveWindow(vhWndSizeBox, xpMac, ypMac, dxpScrlBar, dypScrlBar, TRUE);
+#endif
+ MoveWindow(vhWndPageInfo, 0, ypMac, dxpInfoSize, dypScrlBar, TRUE);
+ if (vhWndRuler != NULL)
+ {
+ dypOverlap = dypRuler - (wwdCurrentDoc.ypMin - 1);
+ MoveWindow(vhWndRuler, 0, 0, xpMac, dypRuler, TRUE);
+ }
+
+ /* Resize the document window. */
+ if (wwdCurrentDoc.wwptr != NULL)
+ {
+ MoveWindow(wwdCurrentDoc.wwptr, 0, dypOverlap, xpMac, ypMac -
+ dypOverlap, FALSE);
+
+ /* Validate the area of the document window that is overlapped by
+ the ruler if necessary. */
+ if (vhWndRuler != (HWND)NULL)
+ {
+ RECT rc;
+
+ rc.left = rc.top = 0;
+ rc.right = dxpRuler;
+ rc.bottom = wwdCurrentDoc.ypMin;
+ ValidateRect(wwdCurrentDoc.wwptr, (LPRECT)&rc);
+ }
+
+ }
+
+ vhMenu = GetMenu(hWnd); // kludge patch cause Write does its own
+ // accelerator handling (6.24.91) v-dougk
+ vfIconic = FALSE;
+ }
+}
+
+
+
+
+void MdocSize(hWnd, cxpNew, cypNew, code)
+HWND hWnd;
+int cxpNew;
+int cypNew;
+WORD code;
+{
+extern int wwCur;
+extern int vfSeeSel;
+extern int vfInitializing;
+
+ typeCP cp;
+ struct EDL *pedl;
+
+ /* Let's start thing off with a couple of assumptions. */
+ Assert( code == SIZENORMAL || code == SIZEFULLSCREEN );
+ Assert( wwdCurrentDoc.wwptr == hWnd );
+
+#ifdef ENABLE /* We repaint completely on resize */
+ if (cypNew > wwdCurrentDoc.ypMac)
+ /* We are growing vertically, mark exposed area invalid
+ so UpdateWw does not try to recycle a partial line
+ at the bottom of the window. */
+ InvalBand( &wwdCurrentDoc, wwdCurrentDoc.ypMac, cypNew );
+#endif
+ if (wwCur != wwNil)
+ TrashWw( wwCur );
+
+ /* Mark the window dirty so that dlMac gets reset according to the new
+ window size */
+ wwdCurrentDoc.fDirty = TRUE;
+
+ wwdCurrentDoc.xpMac = cxpNew;
+ wwdCurrentDoc.ypMac = cypNew;
+
+ /* If minimizing the window, we are done */
+ if ((cxpNew == 0) && (cypNew == 0))
+ return;
+
+ /* If the selection was visible before, so shall it be hereafter */
+ if ( ((cp = CpEdge()) >= wwdCurrentDoc.cpFirst) &&
+ (wwdCurrentDoc.dlMac > 0) &&
+ (cp < (pedl =
+ &(**wwdCurrentDoc.hdndl)[wwdCurrentDoc.dlMac - 1])->cpMin +
+ pedl->dcpMac))
+ {
+ /* Normally, we would just set vfSeeSel and wait for Idle to
+ put the selection in view. However, we can be resized even
+ when we are not the current app, and in that case Idle will not
+ get called soon enough. So, we scroll the selection into view here */
+
+ if (!vfInitializing)
+ { /* Avoid the peril of trying to do this operation too early */
+ extern int wwCur;
+
+ UpdateWw( wwCur, FALSE ); /* To lock in the new dlMac */
+ PutCpInWwVert( cp );
+ UpdateWw( wwCur, FALSE );
+ }
+ }
+}
+
+
+
+FreeMemoryDC( fPrinterToo )
+BOOL fPrinterToo;
+{
+extern HDC vhMDC;
+extern int dxpbmMDC;
+extern int dypbmMDC;
+extern HBITMAP hbmNull;
+
+/* Delete the memory DC if necessary. */
+if ( vhMDC != NULL )
+ {
+ /* Delete the old bitmap if necessary. */
+ if (dxpbmMDC != 0 || dypbmMDC != 0)
+ {
+ DeleteObject( SelectObject( vhMDC, hbmNull ) );
+ dxpbmMDC = dypbmMDC = 0;
+ }
+ /* Discard the screen fonts. */
+ FreeFonts( TRUE, FALSE );
+
+ /* Delete the memory DC. */
+ DeleteDC( vhMDC );
+ vhMDC = NULL;
+ }
+
+/* Also, delete the DC for the printer width, if necessary. */
+if ( fPrinterToo )
+ {
+ FreePrinterDC();
+ }
+}
+
+
+FreePrinterDC()
+{
+extern int vdocBitmapCache;
+extern HDC vhDCPrinter;
+extern BOOL vfPrinterValid;
+extern HWND hParentWw;
+
+/* Delete the printer DC if necessary. */
+if ( vhDCPrinter != NULL )
+ {
+ /* Discard the printer fonts. */
+ FreeFonts( FALSE, TRUE );
+
+ if ( vfPrinterValid )
+ {
+ /* This is a real printer DC; delete it. */
+ DeleteDC( vhDCPrinter );
+ }
+ else
+ {
+ /* This is really the screen DC; it must be released. */
+ ReleaseDC( hParentWw, vhDCPrinter );
+ }
+ vhDCPrinter = NULL;
+
+ /* Free the cached bitmap because it was stretched for the display to
+ reflect its appearance on the printer. */
+ if (vdocBitmapCache != docNil)
+ FreeBitmapCache();
+ }
+}
+
+
+void MdocGetFocus(hWnd, hWndPrevFocus)
+HWND hWnd;
+HWND hWndPrevFocus;
+{
+extern int vfInsertOn;
+extern int vfFocus;
+
+ if (!vfFocus)
+ {
+ vfFocus = TRUE;
+ /* Start up a timer event to blink the caret */
+ /* MdocWndProc gets notified with a message of WM_TIMER */
+ /* every wCaretBlinkTime milliseconds */
+ SetTimer( hWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL );
+
+ /* Set the caret on right away, for looks */
+ if (!vfInsertOn)
+ MdocTimer( hWnd, tidCaret );
+
+ /* Update globals that tell us the state of the lock/shift keys */
+ SetShiftFlags();
+ }
+#ifdef JAPAN
+ ConvertEnable = TRUE;
+ IMEManage( FALSE );
+#endif
+}
+
+
+
+void MdocLoseFocus(hWnd, hWndNewFocus)
+HWND hWnd;
+HWND hWndNewFocus;
+{
+ extern int vfFocus;
+
+ if (vfFocus)
+ {
+ extern int vfGotoKeyMode;
+
+ /* Cancel caret blink timer event & clear the caret */
+ KillTimer( hWnd, tidCaret );
+ ClearInsertLine();
+ /* Free up the memory DC */
+ /* We interpret the loss of focus as a signal that */
+ /* some other app will be using resources */
+ vfFocus = FALSE;
+ vfGotoKeyMode = FALSE; /* Cancel GOTO key modifier */
+ /* Close all files on removable media in case the guy swaps disks */
+ CloseEveryRfn( FALSE );
+ }
+#ifdef JAPAN
+ ConvertEnable = FALSE;
+ IMEManage( TRUE );
+#endif
+}
+
diff --git a/private/mvdm/wow16/write/clipbord.c b/private/mvdm/wow16/write/clipbord.c
new file mode 100644
index 000000000..e47a18d8d
--- /dev/null
+++ b/private/mvdm/wow16/write/clipbord.c
@@ -0,0 +1,887 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* clipbord.c -- Cut/Paste to clipboard */
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCTLMGR
+#define NOFONT
+#define NOPEN
+#define NOBRUSH
+#define NOSCROLL
+#define NOCOMM
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+#include "docdefs.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "editdefs.h"
+#include "winddefs.h"
+#include "filedefs.h"
+#include "wwdefs.h"
+#include "prmdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#include "debug.h"
+
+extern struct SEL selCur; /* Current selection (i.e., sel in current ww */
+extern int docCur; /* Document in current ww */
+
+extern int docUndo;
+extern int docScrap;
+extern int vfSeeSel;
+extern struct DOD (**hpdocdod)[];
+extern struct PAP vpapAbs;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFirstParaCache;
+extern int vfPictSel;
+extern HCURSOR vhcIBeam;
+extern int vfScrapIsPic;
+extern struct UAB vuab;
+extern int ferror;
+extern struct FCB (**hpfnfcb)[];
+extern struct WWD rgwwd[];
+
+/* THESE ARE LOCAL TO THIS MODULE */
+#if defined(OLE)
+int NEAR PASCAL CopyScrapToTmp(void);
+#endif
+
+ /* fn we created during the last non-local cut of MEMO rich text */
+int fnLastCut=fnNil;
+ /* Local communication between ChangeClipboard() and MdocDestroyClip() */
+int fDontDestroyClip=FALSE;
+
+
+FMdocClipboardMsg( message, wParam, lParam )
+unsigned message;
+WORD wParam;
+LONG lParam;
+{ /* Process WRITE clipboard messages sent to MdocWndproc.
+ return TRUE if a message was processed, FALSE otherwise */
+
+ switch (message)
+ {
+ default:
+ return FALSE;
+
+ /*-------DATA INTERCHANGE COMMANDS-----------*/
+ case WM_CUT:
+ fnCutEdit();
+ break;
+
+ case WM_COPY:
+ fnCopyEdit();
+ break;
+
+ case WM_PASTE:
+#if defined(OLE)
+ vbObjLinkOnly = FALSE;
+#endif
+ fnPasteEdit();
+ break;
+
+ case WM_CLEAR:
+ fnClearEdit(OBJ_DELETING);
+ break;
+
+ case WM_UNDO:
+ fnUndoEdit();
+ break;
+
+ /*---------------CLIPBOARD INTERACTION-------------*/
+
+ case WM_DESTROYCLIPBOARD:
+ /* A notification that we are about to lose the ownership
+ of the clipboard. We should free any resources that are
+ holding the contents of the clipboard */
+ MdocDestroyClip();
+ break;
+
+ case WM_RENDERFORMAT:
+ /* A request to render the contents of the clipboard
+ in the data format specified. Reception of this message
+ implies that the receiver is the current owner of the
+ clipboard. See clipbord.c */
+ MdocRenderFormat( wParam );
+ break;
+
+ /*-------CLIPBOARD DISPLAY---------------------*/
+
+ case WM_PAINTCLIPBOARD:
+ /* A request to paint the clipboard contents.
+ wParam is a handle to the clipboard window
+ LOWORD( lParam ) is a handle to a PAINTSTRUCT giving
+ a DC and RECT for the area to repaint */
+
+ MdocPaintClipboard( wParam, LOWORD(lParam) );
+ break;
+
+ case WM_VSCROLLCLIPBOARD:
+ /* A request to vertically scroll the clipboard contents.
+ wParam is a handle to the clipboard window
+ LOWORD( lParam ) is the scroll type (SB_)
+ HIWORD( lParam ) is the new thumb position (if needed) */
+
+ MdocVscrollClipboard( wParam, LOWORD(lParam), HIWORD(lParam) );
+ break;
+
+ case WM_HSCROLLCLIPBOARD:
+ /* A request to horizontally scroll the clipboard contents.
+ wParam is a handle to the clipboard window
+ LOWORD( lParam ) is the scroll type (SB_)
+ HIWORD( lParam ) is the new thumb position (if needed) */
+
+ MdocHscrollClipboard( wParam, LOWORD(lParam), HIWORD(lParam) );
+ break;
+
+ case WM_SIZECLIPBOARD:
+ /* A notification that the clipboard window is being re-sized.
+ wParam is a handle to the clipboard window
+ LOWORD(lParam) is a handle to a RECT giving the new size */
+
+ MdocSizeClipboard( wParam, LOWORD(lParam) );
+ break;
+
+ case WM_ASKCBFORMATNAME:
+ /* A request for the name of the CF_OWNERDISPLAY clip format.
+ wParam is the max. # of chars to store (including terminator)
+ lParam is a long pointer to a buffer in which to store the name */
+
+ MdocAskCBFormatName( (LPCH) lParam, wParam );
+ break;
+ }
+
+ return TRUE;
+}
+
+
+
+
+fnCopyEdit()
+{ /* COPY command: copy selection to clipboard */
+ extern int vfOwnClipboard;
+ typeCP cpFirst;
+ typeCP dcp;
+
+ StartLongOp();
+
+ cpFirst = selCur.cpFirst;
+ SetUndo( uacReplScrap, docCur, cpFirst, dcp = selCur.cpLim - cpFirst,
+ docNil, cpNil, cp0, 0);
+ SetUndoMenuStr(IDSTRUndoEdit);
+
+ ClobberDoc(docScrap, docCur, cpFirst, dcp);
+
+#ifdef DCLIP
+ {
+ char rgch[100];
+ wsprintf(rgch,"fnCopyEdit: cpFirst %lu, dcp %lu \n\r", cpFirst, dcp);
+ CommSz(rgch);
+ }
+#endif
+
+ if (ferror)
+ NoUndo();
+ else
+ {
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ MakeScrapUnRunning();
+ vfScrapIsPic = vfPictSel;
+ }
+
+#ifdef STYLES
+(**hpdocdod)[docScrap].docSsht = (**hpdocdod)[docCur].docSsht;
+#endif
+
+
+#if defined(OLE)
+ ObjEnumInDoc(docScrap,ObjCloneObjectInDoc);
+#endif
+
+ChangeClipboard(); /* Force repaint of clipboard display & Set ownership */
+
+ EndLongOp(vhcIBeam);
+}
+
+
+MakeScrapUnRunning()
+{ /* If the 1st para of docScrap is a running head,
+ apply a sprm to the whole of docScrap that gives it an rhc code of 0.
+ This is to avoid pasting running head stuff into the main part of a doc */
+
+ CHAR rgb [2];
+ typeCP cpMacScrap = (**hpdocdod) [docScrap].cpMac;
+
+ if (cpMacScrap != cp0 )
+ {
+ CachePara( docScrap, cp0 );
+ if (vpapAbs.rhc != 0)
+ {
+ rgb [0] = sprmPRhc;
+ rgb [1] = 0;
+ AddSprmCps( rgb, docScrap, cp0, cpMacScrap );
+ }
+ }
+}
+
+
+
+
+fnCutEdit()
+{ /* CUT command: copy selection to clipboard & delete it */
+ extern int vfOwnClipboard;
+ typeCP cpFirst, cpLim, dcp;
+
+ ClearInsertLine(); /* Since we will be affecting cp's */
+
+ if (!FWriteOk( fwcDelete ))
+ /* Not OK to write on this doc */
+ return;
+
+ cpFirst = selCur.cpFirst;
+ cpLim = selCur.cpLim;
+
+ if (!ObjDeletionOK(OBJ_CUTTING))
+ return;
+
+ StartLongOp();
+
+ SetUndo( uacDelScrap, docCur, cpFirst, dcp = cpLim - cpFirst, docNil,
+ cpNil, cp0, 0);
+ ClobberDoc(docScrap, docCur, cpFirst, dcp);
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ MakeScrapUnRunning();
+
+
+ if (!ferror) /* Don't stomp document if Clobber Doc failed */
+ {
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ MakeScrapUnRunning();
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ }
+else
+ NoUndo(); /* undo would be invalid */
+
+#ifdef STYLES
+(**hpdocdod)[docScrap].docSsht = (**hpdocdod)[docCur].docSsht;
+#endif
+
+ vfScrapIsPic = vfPictSel;
+ vfPictSel = false;
+
+ ChangeClipboard(); /* Force repaint of clipboard display, get ownership */
+
+#if 0
+#if defined(OLE)
+ ObjEnumInDoc(docScrap,ObjCloneObjectInDoc);
+#endif
+#endif
+
+ EndLongOp(vhcIBeam);
+}
+
+
+fnPasteEdit()
+{
+ /* PASTE command: replace selection with clipboard contents */
+ extern CHAR szDocClass[];
+ extern int vfScrapIsPic;
+ extern HWND vhWnd;
+ HWND hWndClipOwner;
+ int fUnFormattedText = FALSE;
+ typeCP cpFirst = selCur.cpFirst;
+ BOOL bClearScrap=FALSE;
+
+ StartLongOp();
+
+ if ( (hWndClipOwner = GetClipboardOwner()) != vhWnd )
+ { /* Clipboard owner is not this instance of memo */
+ if ( (hWndClipOwner == NULL) ||
+ !FSameClassHwndSz( hWndClipOwner, szDocClass ))
+ { /* Clipboard owner is not MEMO -- process standard CF_ formats */
+ if ( !FReadExtScrap() )
+ goto PasteErr;
+
+ bClearScrap = TRUE;
+ fUnFormattedText = !vfScrapIsPic;
+ }
+ else
+ { /* Clipboard owner is another instance of MEMO */
+ if (!FGrabExtMemoScrap())
+ goto PasteErr;
+ }
+ }
+
+ /* Replace the selection with the scrap document */
+ CmdInsScrap( fUnFormattedText );
+
+ if (ferror)
+ goto PasteErr;
+
+#if defined(OLE)
+ if (!bClearScrap) // then we're keeping scrap, need to clone
+ {
+ if (ObjEnumInDoc(docScrap,ObjCloneObjectInDoc) < 0)
+ goto PasteErr;
+ }
+
+ else // then we're not keeping scrap (came from clipboard)
+ {
+ /*
+ We don't need contents anymore, and if it contains an object,
+ then its got to go because its been inserted into the doc and not cloned
+ and we don't want a duplicate around.
+
+ Also gotta mark the object in docCur as no longer reusable (if
+ it gets copied later we will need to clone it).
+ */
+ typeCP cpLim = cpFirst+CpMacText(docScrap);
+ ClobberDoc(docScrap,docNil,cp0,cp0);
+ ObjEnumInRange(docCur,cpFirst,cpLim,ObjFromCloneInDoc);
+ }
+#endif
+
+ EndLongOp(vhcIBeam);
+ return;
+
+PasteErr:
+ NoUndo();
+ EndLongOp(vhcIBeam);
+ _beep();
+}
+
+
+
+MdocRenderFormat( wCf )
+int wCf;
+{ /* Render clipboard data in format specified by wCf */
+ typeCP cpMac=CpMacText( docScrap );
+ struct PICINFOX picInfo;
+
+#if defined(OLE)
+ if (vfScrapIsPic)
+ {
+ GetPicInfo( cp0, cpMac, docScrap, &picInfo );
+
+ if ((picInfo.mfp.mm == MM_OLE) && (wCf != CF_OWNERDISPLAY))
+ goto Render;
+ }
+#endif
+
+ switch (wCf) {
+
+ case CF_OWNERDISPLAY:
+ /* Render rich text to another MEMO instance */
+ FPutExtMemoScrap();
+ break;
+
+ case CF_TEXT:
+ /* Remove formatting from scrap; put bare text out to clipboard */
+ goto Render;
+
+ case CF_BITMAP:
+ if (picInfo.mfp.mm == MM_BITMAP)
+ {
+ goto Render;
+ }
+ break;
+
+ case CF_METAFILEPICT:
+ /* We can supply this if the scrap is a metafile picture */
+ if (picInfo.mfp.mm != MM_BITMAP)
+ {
+ Render:
+ if (!FWriteExtScrap())
+ Error( IDPMTClipLarge );
+ }
+ break;
+
+ }
+
+}
+
+
+
+
+MdocDestroyClip()
+{ /* Handles WM_DESTROYCLIPBOARD message. We are being notified that
+ the clipboard is being emptied & we don't need to keep its
+ contents around anymore. */
+
+ extern int vfOwnClipboard;
+ extern HWND vhWnd;
+
+ if (fDontDestroyClip)
+ return;
+
+ vfOwnClipboard = FALSE;
+
+ /* Clear out the scrap document */
+ ClobberDoc( docScrap, docNil, cp0, cp0 );
+
+ /* Disable UNDO operations that require the clipboard */
+ switch (vuab.uac) {
+ case uacDelScrap:
+ case uacUDelScrap:
+ case uacReplScrap:
+ case uacUReplScrap:
+ NoUndo();
+ break;
+ }
+
+ /* Remove all records of the file we generated in FPutExtMemoScrap
+ from the hpfnfcb array. Note that we assume that no document
+ in this instance has pieces of fn. */
+
+if ( fnLastCut != fnNil )
+ {
+ FreeFn( fnLastCut );
+ fnLastCut = fnNil;
+ }
+
+ /* If we made a wwd entry for the display of the clipboard,
+ remove it now. We test here to avoid bringing in the
+ CLIPDISP module if we never did any display. */
+ {
+ if (wwClipboard != wwNil)
+ FreeWw( wwClipboard );
+ }
+}
+
+
+
+
+int FPutExtMemoScrap()
+{ /* Write docScrap to a new file; send the normalized name
+ of the file to the clipboard as data handle for rich text type.
+ Assumes clipboard is open for SetClipboardData call. On exit,
+ the file written has an fn, but no document (including docScrap)
+ has pieces that point to it. This allows us to relinquish
+ ownership of the fn to the pasting instance.
+ RETURN: TRUE == OK, FALSE == ERROR
+ */
+ int fn;
+ CHAR szT[ cchMaxFile ];
+ HANDLE hMem;
+ LPCH lpch;
+ int cch;
+#if defined(OLE)
+ int docTemp;
+#endif
+
+ /* Create a new, formatted file with a unique name */
+ szT [0] = '\0'; /* Create it on a temp drive in the root */
+ if ((fn = FnCreateSz( szT, cp0, dtyNetwork ))== fnNil )
+ {
+ return FALSE;
+ }
+
+ fnLastCut = fn; /* Save in a static so we can relinquish it later */
+
+ /* Save scrap document to file. Note that FWriteFn does NOT modify
+ the piece table of docScrap, so no document has pieces pointing
+ to fn. This is important because we don't want local pastes
+ to generate pieces pointing to this fn; we want to be able to cleanly
+ transfer ownership of the fn to another instance */
+
+#if defined(OLE)
+ if ((docTemp = CopyScrapToTmp()) == docNil)
+ {
+ FDeleteFn( fn ); /* This will free the fn even if deleting the file
+ fails */
+ return FALSE;
+ }
+#endif
+
+ if (!FWriteFn( fn, docTemp, TRUE ))
+ {
+ FDeleteFn( fn ); /* This will free the fn even if deleting the file
+ fails */
+ return FALSE;
+ }
+
+
+#if defined(OLE)
+ if (docTemp != docScrap)
+ KillDoc (docTemp);
+#endif
+
+ /* Make a global handle containing the name of the file; send it to the
+ clipboard as the rendering of the rich text format */
+
+ if ( ((hMem = GlobalAlloc( GMEM_MOVEABLE, (LONG)(cch=CchSz( szT ))))== NULL ) ||
+ ((lpch = GlobalLock( hMem )) == NULL) )
+ {
+ return FALSE;
+ }
+ bltbx( (LPCH)szT, lpch, cch );
+ GlobalUnlock( hMem );
+
+ SetClipboardData( CF_OWNERDISPLAY, hMem );
+
+ return TRUE;
+}
+
+
+
+
+int FGrabExtMemoScrap()
+{
+/* We get here on a PASTE if the clipboard contains rich text from a
+ MEMO instance other than this one. This routine requests the contents of
+ the clipboard from the other instance, and places the contents into docScrap.
+ The contents of the clipboard are passed in a MEMO formatted file, whose
+ filename is contained in the clipboard's handle. The instance that owns
+ the clipboard does not keep any references to the fn for the clipboard
+ file (once we EmptyClipboard). After pasting, this routine arrogates
+ the ownership of the clipboard to this instance.
+ returns FALSE=error, true=OK */
+
+ extern int vfOwnClipboard;
+ extern HWND vhWnd;
+
+ LPCH lpch;
+ CHAR szT [cchMaxFile];
+ int fn;
+ typeFC dfc;
+ HANDLE hData;
+ int fOK=false;
+
+ /* Open Clipboard to lock out contenders */
+
+ if ( !OpenClipboard( vhWnd ))
+ {
+ return FALSE;
+ }
+
+ /* Grab clipboard data handle contents: it is a normalized
+ filename string referring to a formatted file containing
+ the rich text. The GetClipboardData call actually initiates
+ a WM_RENDERFORMAT message to which MdocRenderFormat responds */
+
+ if ( ((hData = GetClipboardData( CF_OWNERDISPLAY )) == NULL ) ||
+ ((lpch = GlobalLock( hData )) == NULL ) )
+ {
+ goto GrabErr;
+ }
+
+ bltszx( lpch, (LPCH)szT );
+ GlobalUnlock( hData ); /* handle will be freed in EmptyClipboard sequence */
+
+ /* Open the file; replace the contents of the scrap document
+ with the contents of the file */
+
+ if ((fn = FnOpenSz( szT, dtyNormal, FALSE )) == fnNil)
+ { /* Unfortunately, if this fails, the file that the other
+ instance created will "float", with noone holding an fn
+ for it, and it will not get deleted at the end of the session.
+ On the bright side, if the reason for the failure was that
+ the file never got created anyway, we have done exactly right */
+ goto GrabErr;
+ }
+
+ { /* Opened file OK */
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ struct FFNTB **hffntb;
+ struct FFNTB **HffntbCreateForFn();
+ int wUnused;
+
+ pfcb->fDelete = TRUE;
+ dfc = pfcb->fFormatted ? cfcPage : fc0;
+ Replace( docScrap,
+ cp0,
+ (**hpdocdod)[docScrap].cpMac,
+ fn,
+ dfc,
+ pfcb->fcMac - dfc );
+
+ /* give the scrap the correct font table */
+ FreeFfntb((**hpdocdod)[docScrap].hffntb);
+ if (FNoHeap(hffntb = HffntbCreateForFn(fn, &wUnused)))
+ hffntb = 0;
+ (**hpdocdod)[docScrap].hffntb = hffntb;
+ }
+
+#if defined(OLE)
+ /* if there are any objects in there, Load 'em */
+ if (ObjEnumInDoc(docScrap,ObjLoadObjectInDoc) < 0)
+ fOK = FALSE;
+ else
+#endif
+ fOK = !ferror; /* All is well if we didn't run out of memory */
+
+ /* Take over ownership of the clipboard. This results in a
+ WM_DESTROYCLIPBOARD message being sent to the other instance,
+ which will delete its fn entry for the file so we are the
+ exclusive owners */
+
+GrabErr:
+ CloseClipboard();
+ ChangeClipboard();
+ return fOK;
+}
+
+
+
+
+ChangeClipboard()
+{ /* Mark clipboard as changed. If we are not the owner of the clipboard, */
+ /* make us the owner (via EmptyClipboard). The EmptyClipboard call */
+ /* will result in a WM_DESTROYCLIPBOARD message being sent to the */
+ /* owning instance. The CloseClipboard call will result in a */
+ /* WM_DRAWCLIPBOARD message being sent to the clipboard viewer. */
+ /* If the clipboard viewer is CLIP.EXE, we will get a WM_PAINTCLIPBOARD */
+ /* message */
+ /* Added 10/8/85 by BL: If docScrap is empty, relinquish ownership */
+ /* of the clipboard */
+
+ extern int vfOwnClipboard;
+ extern HWND vhWnd;
+ int cf;
+ struct PICINFOX picInfo;
+ typeCP cpMacScrap = (**hpdocdod) [docScrap].cpMac;
+
+ if (!OpenClipboard( vhWnd ))
+ { /* Couldn't open the clipboard, wipe out contents & disable UNDO */
+ MdocDestroyClip();
+ return;
+ }
+
+ /* We want to clear out previous data formats in the clipboard.
+ Unfortunately, the only way to do this is to call EmptyClipboard(),
+ which has the side effect of calling us with a WM_MDOCDESTROYCLIP
+ message. We use this primitive global comunication to prevent
+ docScrap from being wiped out in MdocDestroyClip() */
+
+ fDontDestroyClip = TRUE;
+ EmptyClipboard();
+ fDontDestroyClip = FALSE;
+
+ /* Re-validate vfScrapIsPic (in case a docScrap edit changed what it should be */
+
+ CachePara( docScrap, cp0 );
+ vfScrapIsPic = (vpapAbs.fGraphics && vcpLimParaCache == cpMacScrap);
+
+ if (!vfScrapIsPic)
+ cf = CF_TEXT;
+ else
+ {
+ GetPicInfo( cp0, cpMacScrap, docScrap, &picInfo );
+ switch(picInfo.mfp.mm)
+ {
+ case MM_BITMAP:
+ cf = CF_BITMAP;
+ break;
+
+ case MM_OLE:
+ cf = 0;
+ break;
+
+ default:
+ cf = CF_METAFILEPICT;
+ break;
+ }
+ }
+
+ vfOwnClipboard = (cpMacScrap != cp0);
+ if (vfOwnClipboard)
+ { /* only set handles if we really have something in docScrap */
+ SetClipboardData( CF_OWNERDISPLAY, NULL );
+ if ((cf != CF_TEXT) && (picInfo.mfp.mm == MM_OLE))
+ {
+ while (cf = OleEnumFormats(lpOBJ_QUERY_OBJECT(&picInfo),cf))
+ {
+ if (cf == vcfLink)
+ SetClipboardData( vcfOwnerLink, NULL );
+ else
+ SetClipboardData( cf, NULL );
+ //if (cf == vcfNative)
+ //SetClipboardData( vcfOwnerLink, NULL );
+ }
+ }
+ else
+ SetClipboardData( cf, NULL );
+ }
+
+ CloseClipboard();
+}
+
+
+
+CmdInsScrap( fUnFormattedText )
+int fUnFormattedText;
+{ /* Insert the scrap into the document at the current point (PASTE) */
+ /* If fUnFormattedText is TRUE, the scrap is treated as unformatted */
+ /* text; that is, the characters are put into the document with the */
+ /* formatting that is active at the selection */
+extern struct CHP vchpSel;
+typeCP cp, dcp;
+int cchAddedEol=0;
+struct CHP chpT;
+
+if (!FWriteOk( fwcInsert ))
+ return;
+
+if ((dcp = CpMacText(docScrap)) == cp0)
+ return;
+
+ClearInsertLine();
+
+if (fnClearEdit(OBJ_INSERTING))
+ return;
+
+chpT = vchpSel;
+cp = selCur.cpFirst;
+
+CachePara( docScrap, cp0 );
+if (vpapAbs.fGraphics && cp > cp0)
+ { /* Special case for inserting a picture paragraph */
+ /* Must put an Eol in front of the picture unless we're
+ inserting it at the start of the document or one is there already */
+
+ Assert( !fUnFormattedText );
+ (**hpdocdod)[docCur].fFormatted = fTrue;
+ CachePara(docCur, cp - 1);
+ if (vcpLimParaCache != cp)
+ {
+ cchAddedEol = ccpEol;
+
+ InsertEolPap(docCur, cp, &vpapAbs);
+ dcp += (typeCP)ccpEol;
+ }
+ }
+
+SetUndo( uacInsert, docCur, cp, dcp, docNil, cpNil, cp0, 0 );
+
+SetUndoMenuStr(IDSTRUndoEdit);
+ReplaceCps(docCur, cp + (typeCP)cchAddedEol, cp0, docScrap, cp0,
+ dcp - (typeCP)cchAddedEol);
+if (ferror) /* Not enough memory to do replace operation */
+ NoUndo(); /* should not be able to undo what never took place */
+else
+ {
+ typeCP cpSel=CpFirstSty( cp + dcp, styChar );
+
+ if (vfScrapIsPic && vuab.uac == uacReplNS)
+ /* Special UNDO code for picture paste */
+ vuab.uac = uacReplPic;
+
+ if (fUnFormattedText)
+ { /* If pasting unformatted text, give it the props at the selection */
+ CHAR rgch[ cchCHP + 1 ];
+
+ rgch [0] = sprmCSame;
+ bltbyte( &chpT, &rgch [1], cchCHP );
+ AddSprmCps( rgch, docCur, cp, cp + dcp );
+ }
+ Select( cpSel, cpSel );
+ vchpSel = chpT; /* Preserve insert point props across this operation */
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ { /* If running head/foot, remove chSects & set para props */
+ MakeRunningCps( docCur, cp, dcp );
+ }
+ if (ferror)
+ NoUndo();
+ }
+
+vfSeeSel = true; /* Tell Idle() to scroll the selection into view */
+}
+
+
+#if defined(OLE)
+int NEAR PASCAL CopyScrapToTmp(void)
+/*
+ If scrap doesn't contain OLE objects, return docScrap. Else
+ create docTemp and copy docScrap into it. Make sure objects
+ all have their data and have their lpObjInfos NULL'd out.
+*/
+{
+ extern typeCP cpMinCur, cpMacCur, cpMinDocument;
+ typeCP cpMinCurT = cpMinCur,
+ cpMacCurT = cpMacCur,
+ cpMinDocumentT = cpMinDocument;
+ int docTemp = docNil,
+ docReturn = docNil;
+
+ /* are there any objects? */
+ switch (ObjEnumInDoc(docScrap,NULL))
+ {
+ case -1: // error
+ return docNil;
+ case 0: // no objects in scrap
+ return docScrap;
+ }
+
+ /* Create copy of document */
+ if ((docTemp = DocCreate(fnNil, HszCreate(""), dtyNormal)) == docNil)
+ return docNil;
+
+ /* copy scrap to docTemp */
+ ClobberDoc(docTemp, docScrap, cp0, CpMacText(docScrap));
+
+ if (ferror)
+ goto error;
+
+ /* now save objects to make sure their data is present */
+ {
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docTemp,cp0,CpMacText(docTemp),&cpPicInfo);
+ )
+ {
+ OBJINFO ObjInfoSave;
+ typeCP cpRetval;
+
+ if (picInfo.lpObjInfo == NULL)
+ continue;
+
+ ObjInfoSave = *picInfo.lpObjInfo;
+
+ cpRetval = ObjSaveObjectToDoc(&picInfo,docTemp,cpPicInfo);
+
+ /*
+ Do this just in case saving the object to docTemp changes the
+ object's state. We don't want the object to appear clean
+ or saved when in fact it isn't or hasn't been except in docTemp,
+ which will be deleted by the calling routine.
+ */
+ *picInfo.lpObjInfo = ObjInfoSave;
+
+ if (cpRetval == cp0) // save failed
+ goto error;
+
+ /* so pasting instance will reload object */
+ picInfo.lpObjInfo = NULL;
+ ObjSetPicInfo(&picInfo,docTemp,cpPicInfo);
+ }
+ }
+
+ /* success */
+ docReturn = docTemp;
+
+ error:
+
+ if ((docReturn == docNil) && (docTemp != docNil))
+ KillDoc(docTemp);
+
+ /* Restore cpMinCur, cpMacCur */
+ cpMinCur = cpMinCurT;
+ cpMacCur = cpMacCurT;
+ cpMinDocument = cpMinDocumentT; /* destroyed possibly by DocCreate */
+
+ return docReturn;
+}
+#endif
diff --git a/private/mvdm/wow16/write/clipbrd2.c b/private/mvdm/wow16/write/clipbrd2.c
new file mode 100644
index 000000000..9afff1f18
--- /dev/null
+++ b/private/mvdm/wow16/write/clipbrd2.c
@@ -0,0 +1,926 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Clipbrd2.c -- less frequently used clipboard routines */
+
+#define NOWINMESSAGES
+#define NOGDICAPMASKS
+#define NOWINSTYLES
+#define NOVIRTUALKEYCODES
+#define NOMENUS
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOOPENFILE
+#define NOSOUND
+#define NOCOMM
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOWH
+#define NOSCROLL
+#define NOPEN
+#include <windows.h>
+
+#include "mw.h"
+#define NOKCCODES
+#include "ch.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "winddefs.h"
+#include "fmtdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#if defined(JAPAN) & defined(DBCS_IME)
+#include "prmdefs.h" /* IME: use sprmCSame in CmdInsIRString() */
+#else
+#define NOSTRMERGE
+#define NOSTRUNDO
+#endif
+
+#include "str.h"
+
+#define NOIDISAVEPRINT
+#define NOIDIFORMATS
+#include "dlgdefs.h"
+#include "wwdefs.h"
+#include "debug.h"
+
+extern struct WWD rgwwd[];
+extern int wwMac;
+extern struct DOD (**hpdocdod)[];
+extern int docCur; /* Document in current ww */
+extern int docMac;
+extern int ferror;
+extern int docScrap;
+
+#if defined(JAPAN) & defined(DBCS_IME) /* Document for IRSTRING */
+extern int docIRString;
+#endif
+
+extern struct PAP vpapAbs;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern struct PAP *vppapNormal;
+extern struct CHP vchpNormal;
+extern int vfScrapIsPic;
+extern typeCP vcpLimParaCache;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int vfOwnClipboard;
+extern struct FLI vfli;
+
+
+
+#if WINVER >= 0x300
+/* We can copy more than 64k in the clipboard and need to
+ correctly handle when we cross segment boundaries. See
+ note in bltbh() ..pault */
+void bltbh(HPCH, HPCH, int);
+#define bltbx(from,to,count) bltbh(from,to,count)
+#define LPCHCLIP HPCH
+#else
+#define LPCHCLIP LPCH
+#endif /* if-else-WINVER */
+
+
+FRenderAll()
+{ /* WRITE is going away, and we are the owners of the clipboard.
+ Render the contents of the clipboard in as many formats as
+ we know. Prompt the user if the save will use more than 1000
+ cp's; this is to avoid massive inadvertant gobbling of global
+ heap space. */
+ extern int vfOwnClipboard;
+ extern HANDLE hMmwModInstance;
+ extern HANDLE hParentWw;
+ extern FARPROC lpDialogConfirm;
+ typeCP cpMac=CpMacText( docScrap );
+
+
+ if ( (cpMac == cp0) || !vfOwnClipboard)
+ { /* We are not the clipboard owner OR the scrap is empty:
+ no actions required */
+ return TRUE;
+ }
+#ifdef ENABLE /* By popular demand, this dialog box is removed */
+ else if (cpMac > 1000L)
+ {
+ /* Clipboard contents (docScrap) are > 1000 bytes; ask the user to confirm
+ that it should be saved away in a global handle */
+
+ switch ( OurDialogBox( hMmwModInstance, MAKEINTRESOURCE( dlgSaveScrap ),
+ hParentWw, lpDialogConfirm ) )
+ {
+ default:
+ case idiCancel: /* [CANCEL] Abort exit sequence */
+ return FALSE;
+ case idiNo: /* [DISCARD] Discard large clipboard */
+ return TRUE;
+ case idiOk: /* [SAVE] Save large clipboard */
+ break;
+ }
+ }
+
+ /* Believe it or not, we have to check the vfOwnClipboard flag AGAIN.
+ A user as sneaky as gaben might have gone into another app and
+ copied to the clipboard while our dialog is up. */
+
+if (!vfOwnClipboard)
+ /* We have to check the vfOwnClipboard flag AGAIN.
+ A user might have gone into another app and
+ copied to the clipboard while our dialog was up. */
+ return TRUE;
+#endif /* ENABLE */
+
+ /* Render the clipboard contents */
+if (OpenClipboard( wwdCurrentDoc.wwptr ))
+ {
+ int f;
+
+ f = FWriteExtScrap();
+ CloseClipboard();
+ if (f)
+ return TRUE;
+ else
+ { /* Failed to write scrap contents -- report error */
+
+ extern HWND hParentWw;
+ CHAR *PchFillPchId( CHAR *, int, int );
+ CHAR sz[ 256 ];
+
+ PchFillPchId( sz, IDPMTClipQuest, sizeof(sz) );
+
+ switch ( IdPromptBoxSz( hParentWw, sz,
+ MB_OKCANCEL | MB_ICONHAND | MB_SYSTEMMODAL ) )
+ {
+ default:
+ break;
+ case IDOK:
+ return TRUE;
+ }
+ }
+ }
+return FALSE;
+}
+
+
+
+
+FWriteExtScrap()
+{ /* Write the scrap document into the external scrap */
+ /* This means: Write the clipboard contents to the clipboard */
+ /* in the standard Windows CF_TEXT format, or, if a picture, */
+ /* in CF_BITMAP or CF_METAFILEPICT, whichever it was originally. */
+ /* We get here in response to a WM_RENDERFORMAT or WM_RENDERALLFORMATS */
+ /* message. The clipboard is assumed to be already OPEN, and is left open */
+ /* Returns TRUE if all is well, FALSE if an error occurs. The caller
+ /* is responsible for reporting errors. */
+
+int NEAR FWriteExtTextScrap();
+typeCP cpNow;
+typeCP cpMac=(**hpdocdod) [docScrap].cpMac;
+unsigned long cbScrap;
+struct PICINFOX picInfo;
+HANDLE hScrapDescriptor=NULL;
+HANDLE hScrap;
+
+if (!vfScrapIsPic)
+ { /* Text */
+ return FWriteExtTextScrap();
+ }
+
+GetPicInfo( cp0, cpMac, docScrap, &picInfo );
+
+#if defined(OLE)
+ if (picInfo.mfp.mm == MM_OLE)
+ return ObjWriteToClip(&picInfo);
+#endif
+
+ /* Prime the loop */
+FetchCp(docScrap, cpNow = (typeCP)picInfo.cbHeader, 0, fcmChars + fcmNoExpand);
+if ((hScrap = GlobalAlloc( GMEM_MOVEABLE, cbScrap = (LONG)vccpFetch )) == NULL)
+ goto SetFailed;
+
+while (cpNow < cpMac)
+ {
+ LPCHCLIP lpch;
+ HANDLE hScrapT;
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch,"FWES:cpNow %lu cpMac %lu vccpFetch %d \n\r", cpNow, cpMac, vccpFetch);
+ CommSz(rgch);
+ }
+#endif
+
+ /* Add bytes from scrap document to global handle */
+
+ if ((lpch = GlobalLock( hScrap )) == NULL)
+ goto SetFailed;
+ bltbx( (LPCHCLIP) vpchFetch, lpch + (cbScrap - vccpFetch), vccpFetch );
+ GlobalUnlock( hScrap );
+
+ /* Fetch the next run and expand the handle */
+
+ if ((cpNow += vccpFetch) >= cpMac)
+ break;
+ FetchCp( docScrap, cpNow, 0, fcmChars + fcmNoExpand );
+ /* the above fetchcp should probably be converted to use the speed-
+ hack in fetchcp which passes docnil cpnil to get the next series
+ of chars ..pault */
+
+ hScrapT = hScrap;
+ hScrap = GlobalReAlloc( hScrap, cbScrap += vccpFetch, GMEM_MOVEABLE );
+ if (hScrap == NULL)
+ { /* Could not grow the handle; bail out */
+ hScrap = hScrapT; /* So it gets freed */
+ goto SetFailed;
+ }
+ }
+
+/* Now we have the whole of docScrap in a windows Global handle */
+/* See whether we have a bitmap or a metafile picture */
+
+switch(picInfo.mfp.mm)
+{
+ case MM_BITMAP:
+ { /* Bitmap */
+ LPCHCLIP lpch;
+
+ if ( ((lpch=GlobalLock( hScrap ))==NULL) ||
+ (picInfo.bm.bmBits=lpch,
+ ((hScrapDescriptor=
+ CreateBitmapIndirect((LPBITMAP)&picInfo.bm))==NULL)))
+ {
+ if (lpch != NULL)
+ GlobalUnlock( hScrap );
+ goto SetFailed;
+ }
+ else
+ {
+ /* Tell the clipboard about the "goal size" for this guy */
+ SetBitmapDimension( hScrapDescriptor, picInfo.mfp.xExt,
+ picInfo.mfp.yExt );
+ SetClipboardData( CF_BITMAP, hScrapDescriptor );
+ }
+
+ GlobalUnlock( hScrap );
+ GlobalFree( hScrap ); /* Bitmap was copied by CreateBitmapIndirect,
+ don't need it anymore */
+ hScrap = NULL;
+ }
+ break;
+
+ default:
+ { /* Metafile Picture */
+ LPCHCLIP lpch;
+ Diag(CommSzNum("FWES: sizeof(metafilepict) ==",sizeof(METAFILEPICT)));
+
+ if ( ((hScrapDescriptor=GlobalAlloc(GMEM_MOVEABLE,
+ (long)sizeof(METAFILEPICT) ))==NULL) ||
+ ((lpch=GlobalLock( hScrapDescriptor ))==NULL))
+ {
+ goto SetFailed;
+ }
+ else
+ {
+ picInfo.mfp.hMF = hScrap;
+ bltbx( (LPCHCLIP) &picInfo.mfp, lpch, sizeof(METAFILEPICT) );
+ GlobalUnlock( hScrapDescriptor );
+ SetClipboardData( CF_METAFILEPICT, hScrapDescriptor );
+ }
+ }
+ break;
+}
+
+return true;
+
+SetFailed:
+ if (hScrapDescriptor != NULL)
+ GlobalFree( hScrapDescriptor );
+ if (hScrap != NULL)
+ GlobalFree( hScrap );
+ return false; /* Caller should report errors */
+}
+
+
+
+
+int NEAR FWriteExtTextScrap()
+{ /* Create ASCII text in a global Windows handle corresponding
+ to the contents of docScrap. Add CR-LF combinations at the
+ points at which text would wrap on the display.
+ Set the handle into the clipboard if successful, as type CF_TEXT.
+ Returns the handle built up, or NULL if we ran out of memory */
+
+long lcchHandle = 0L;
+HANDLE h=GlobalAlloc( GMEM_MOVEABLE, (long) 1 );
+LPCHCLIP lpch;
+typeCP cpNow=cp0;
+typeCP cpMac=(**hpdocdod) [docScrap].cpMac;
+HANDLE hT;
+#if WINVER < 0x300
+int cLine = 0;
+#endif
+
+Assert( !vfScrapIsPic );
+Assert( vfOwnClipboard );
+
+if (h==NULL)
+ goto Failed;
+
+while (cpNow < cpMac)
+ {
+ int ich;
+ int dcpLine;
+
+ /* Check for picture para */
+
+ /** Is this syntax intentional???!!! (1.28.91) D. Kent **/
+ if (CachePara( docScrap, cpNow ), vpapAbs.fGraphics )
+ {
+ cpNow = vcpLimParaCache;
+ continue;
+ }
+
+ /* Format a line of text for the screen */
+
+ FormatLine( docScrap, cpNow, 0, cpMac, flmSandMode );
+ dcpLine = vfli.ichReal;
+
+ /* Special: Check for NULLs */
+ /* This is a last-minute workaround for a WRITE */
+ /* bug in which FormatLine sometimes returns a NULL in vfli.rgch */
+
+ for ( ich = 0; ich < vfli.ichReal; ich++ )
+ {
+ if (vfli.rgch [ich] == '\0')
+ {
+#ifdef DCLIP
+ CommSzNum("Oddity in FormatLine: returned a zero in rgch at ich==",ich);
+#endif
+
+#if WINVER < 0x300
+ dcpLine = ich;
+ break;
+#else
+ /* Rather than assign the string a zero length if there is
+ just one block character in the selection, we make it the
+ ansi block char! This fixes WINBUG #8150..pault 1/16/90 */
+ vfli.rgch [ich] = chBlock;
+#endif
+ }
+ }
+
+ /* Put the chars + a CRLF into the handle */
+
+#define cbNeeded (lcchHandle + dcpLine + 2)
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch,"FWETS:cbNeeded %lu (lcchHandle %lu, dcpLine %d) \n\r",
+ cbNeeded, lcchHandle, dcpLine);
+ CommSz(rgch);
+ }
+#endif
+
+ hT = h;
+ if ((h=GlobalReAlloc( h, (LONG) cbNeeded, GMEM_MOVEABLE ))==NULL)
+ { /* Could not expand handle */
+ h = hT; /* So it gets freed */
+ goto Failed;
+ }
+
+ if ((lpch=GlobalLock( h )) == NULL)
+ goto Failed;
+
+ if (vfli.cpMac > cpMac)
+ /* Do not cut the endmark character (but alloc for it to allow
+ space for zero-terminating the clipboard string) */
+#ifdef DBCS
+/* We use double byte charactor for END Mark,So we have to go back 2 byte */
+ dcpLine -= 2;
+#else
+ dcpLine--;
+#endif
+
+ bltbx( (LPCHCLIP) vfli.rgch, lpch + lcchHandle, dcpLine );
+
+ lpch [lcchHandle += dcpLine] = 0x0D;
+ lpch [++lcchHandle] = 0x0A;
+#if WINVER < 0x300
+ cLine++;
+#endif
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch," cpNow %lu cpMac %lu lcchHandle %lu dcpLine %d \n\r",
+ cpNow, cpMac, lcchHandle+1, dcpLine);
+ CommSz(rgch);
+ }
+#endif
+
+ ++lcchHandle;
+ cpNow = vfli.cpMac;
+ GlobalUnlock( h );
+ }
+
+ /* SUCCEEDED! NULL-terminate the string before returning the handle */
+#if WINVER >= 0x300
+ /* This means we must alloc one more byte at the end ..pault 1/11/90 */
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch,"FWETS:cbNeeded to fit in sz %lu \n\r", lcchHandle+1);
+ CommSz(rgch);
+ }
+#endif
+ hT = h;
+ if ((h=GlobalReAlloc( h, (LONG) lcchHandle+1, GMEM_MOVEABLE ))==NULL)
+ { /* Could not expand handle */
+ h = hT; /* So it gets freed */
+ goto Failed;
+ }
+#endif
+
+ if ((lpch = GlobalLock( h )) == NULL)
+ goto Failed;
+
+#if WINVER >= 0x300
+/* It turns out that we're not really representing the contents of the
+ selection correctly. The user should really ONLY end up at the start
+ of a new line (that is, the last thing "pasted in" was a CRLF sequence)
+ if they were really at the end of a line! (Especially a problem when
+ pasting 3 lines of text into the CALENDAR Scratchpad) 12/3/89..pault */
+
+ if (cpMac < vfli.cpMac)
+#else
+ if (cLine == 1) /* Special case: < 1 line, do not terminate w/ CRLF */
+#endif
+ /* Back up over crlf already written */
+ lcchHandle = max(0, lcchHandle-2);
+
+ lpch [lcchHandle] = '\0';
+ GlobalUnlock( h );
+ SetClipboardData( CF_TEXT, h );
+ return TRUE;
+
+Failed:
+
+ if (h != NULL)
+ GlobalFree( h );
+ return FALSE;
+}
+
+
+
+int FReadExtScrap()
+{ /* Transfer the external scrap to the scrap document. This means:
+ read the contents of the clipboard into docScrap, using whatever
+ available standard format we can process. Return FALSE=ERR, TRUE=OK */
+
+ extern int vfSysFull;
+ extern BOOL fError;
+ extern HWND vhWnd;
+ extern int vfOwnClipboard;
+ int fOk = FALSE;
+ struct PICINFOX picInfo;
+
+ Assert( !vfOwnClipboard );
+
+ vfScrapIsPic = false;
+ ClobberDoc( docScrap, docNil, cp0, cp0 );
+
+ if ( !OpenClipboard( vhWnd ) )
+ return FALSE;
+
+ /* Get the handle for the highest-priority type available in the clipboard */
+
+ /* if !(PasteLink or (PasteSpecial and not CF_TEXT)) */
+ if (!(vbObjLinkOnly || vObjPasteLinkSpecial ||
+ (cfObjPasteSpecial && (cfObjPasteSpecial != CF_TEXT)))) // no text handler yet
+ /* try to use text format */
+ {
+ WORD wFormat=0;
+ typeCP cp=cp0;
+ unsigned long cb;
+ struct PAP *ppap = NULL;
+ CHAR rgch[256];
+ HANDLE hClipboard; /* Handle that was being kept in the clipboard */
+ LPCHCLIP lpch;
+
+ while (wFormat = EnumClipboardFormats(wFormat))
+ /* enumerate to see whether text precedes native. If so, take it */
+ {
+ if (wFormat == CF_TEXT) // take it
+ {
+ if ((hClipboard = GetClipboardData( wFormat )) == NULL)
+ goto done;
+
+ cb = GlobalSize( hClipboard );
+ lpch = MAKELP(hClipboard,0);
+
+ while (cb > 0)
+ { /* Copy bytes from lpch to docScrap's cp stream */
+ #define ulmin(a,b) (((a) < (b)) ? a : b)
+
+ unsigned cch=ulmin(cb,255); /* <= 255 bytes per pass */
+ int fEol;
+
+ if ((cch = CchReadLineExt((LPCHCLIP) lpch, cch, rgch, &fEol))==0)
+ /* Reached terminator */
+ {
+ fOk = TRUE;
+ goto done;
+ }
+
+ if (fEol)
+ ppap = vppapNormal;
+
+ InsertRgch( docScrap, cp, rgch, cch, &vchpNormal, ppap );
+
+ if (fError) /* an error was reported mid-copy */
+ goto done;
+
+ cb -= cch;
+ cp += (typeCP) cch;
+ lpch += cch;
+ }
+ Assert(0); // shouldn't get here
+ }
+ else if ((cfObjPasteSpecial != CF_TEXT) &&
+ (wFormat == vcfNative)) // make an object
+ /* NOTE: if pastespecial and the format == CF_TEXT, then
+ we look for the text format regardless of presence of
+ native */
+ break;
+ }
+ }
+
+ /* Fell through to here, so didn't find or don't want text,
+ see whether can make an object (static included) */
+
+ if (!ObjCreateObjectInClip(&picInfo))
+ goto done;
+
+ vfScrapIsPic = true;
+
+ /* save new picinfo to doc */
+ CachePara(docScrap,cp0);
+ if (ObjSaveObjectToDoc(&picInfo,docScrap,cp0) == cp0)
+ {
+ OleDelete(lpOBJ_QUERY_OBJECT(&picInfo));
+ goto done;
+ }
+
+ /* this'll force paste to reuse rather than clone */
+ if (ObjToCloneInDoc(&picInfo,docScrap,cp0) == cp0)
+ {
+ OleDelete(lpOBJ_QUERY_OBJECT(&picInfo));
+ goto done;
+ }
+
+ fOk = TRUE;
+
+ done:
+
+ CloseClipboard();
+ if (vfSysFull || (!fOk && (picInfo.mfp.mm == MM_OLE)))
+ { /* Filled the scratch file trying to bring in the object */
+ ClobberDoc(docScrap, docNil, cp0, cp0);
+ fOk = FALSE;
+ }
+
+ return fOk;
+}
+
+#if defined(JAPAN) & defined(DBCS_IME)
+// We know that this special routine is particularly useful for Japanese IME
+
+CmdInsIRString(int doc)
+{
+extern struct CHP vchpSel;
+typeCP cp, dcp;
+int cchAddedEol=0;
+struct CHP chpT;
+extern struct SEL selCur; /* Current Selection */
+extern int vfSeeSel;
+
+if (!FWriteOk(fwcInsert))
+ return;
+
+if ((dcp = CpMacText(doc)) == cp0)
+ return;
+
+NoUndo(); /* So the Undo doesn't get combined with previous ops */
+
+/* Stomp the current selection, if any */
+if (selCur.cpLim > selCur.cpFirst)
+ DeleteSel();
+
+chpT = vchpSel;
+cp = selCur.cpFirst;
+
+CachePara( doc, cp0 );
+
+SetUndo( uacInsert, docCur, cp, dcp, docNil, cpNil, cp0, 0 );
+
+SetUndoMenuStr(IDSTRUndoEdit);
+ReplaceCps(docCur, cp , cp0, docIRString, cp0, dcp);
+
+if (ferror) /* Not enough memory to do replace operation */
+ NoUndo(); /* should not be able to undo what never took place */
+else
+ {
+ CHAR rgch[ cchCHP + 1 ];
+
+ typeCP cpSel=CpFirstSty( cp + dcp, styChar );
+
+ rgch [0] = sprmCSame;
+ bltbyte( &chpT, &rgch [1], cchCHP );
+ AddSprmCps( rgch, docCur, cp, cp + dcp );
+
+ Select( cpSel, cpSel );
+ vchpSel = chpT; /* Preserve insert point props across this operation */
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ { /* If running head/foot, remove chSects & set para props */
+ MakeRunningCps( docCur, cp, dcp );
+ }
+ if (ferror)
+ NoUndo();
+ }
+
+vfSeeSel = true; /* Tell Idle() to scroll the selection into view */
+}
+
+
+PutImeString( hWnd, hIME )
+HWND hWnd;
+HANDLE hIME;
+{
+ LPCHCLIP lpch;
+ CHAR rgch[256];
+ unsigned long cb;
+ typeCP cp = cp0;
+ extern BOOL fError;
+ extern int vfSysFull;
+ int fUnFormattedText = FALSE;
+ extern void ForceImeBlock();
+
+ ForceImeBlock(hWnd, TRUE);
+ //StartLongOp();
+ ClearInsertLine();
+
+ vfScrapIsPic = false;
+ ClobberDoc( docIRString, docNil, cp0, cp0 );
+ cb = GlobalSize( hIME );
+ if (lpch = GlobalLock( hIME )) {
+ while(cb > 0) {
+ unsigned cch = ulmin(cb, 255);
+ int fEol;
+ struct PAP *ppap = NULL;
+
+ if ((cch = CchReadLineExt((LPCHCLIP)lpch,cch,rgch,&fEol)) == 0)
+ break;
+ if (fEol)
+ ppap = vppapNormal;
+ InsertRgch(docIRString, cp, rgch, cch, &vchpNormal, ppap );
+ if (fError) {
+ break;
+ }
+ cb -= cch;
+ cp += (typeCP) cch;
+ lpch += cch;
+ }
+ GlobalUnlock( hIME );
+ }
+ if (vfSysFull) {
+ ClobberDoc( docIRString, docNil, cp0, cp0 );
+ }
+ fUnFormattedText = !vfScrapIsPic;
+ CmdInsIRString(docIRString);
+ //EndLongOp();
+ ForceImeBlock(hWnd, FALSE);
+}
+#endif // JAPAN & DBCS_IME
+
+
+
+
+CchReadLineExt( lpch, cbRead, rgch, pfEol)
+LPCHCLIP lpch;
+int cbRead;
+CHAR rgch[];
+int *pfEol;
+{ /* Read from lpch to the next eol or null terminator, whichever comes first */
+/* Return number of bytes read (max is 255) and whether there is a eol at end */
+/* The count does not include the null terminator, but does include the eol */
+
+CHAR *pch;
+extern CHAR *index();
+
+Assert(cbRead <= 255);
+bltbx( lpch, (LPCHCLIP) rgch, cbRead );
+rgch[ cbRead ] = 0; /* Null terminate the string (so index will work) */
+
+if (*pfEol = ((pch=index(rgch,chEol)) != NULL))
+ { /* FOUND EOL */
+ return (pch - rgch + 1);
+ }
+else
+ { /* NO EOL */
+ return CchSz(rgch) - 1;
+ }
+}
+
+
+
+
+FComputePictSize( pmfp, pdxa, pdya )
+register METAFILEPICT *pmfp;
+int *pdxa;
+int *pdya;
+{ /* Compute an initial size, in twips, for the picture described by the
+ passed metafile picture structure. Return the size through
+ parameters. Return FALSE if the metafile picture structure
+ contained bad information, TRUE otherwise */
+
+#ifdef SCALE_FOR_SCREEN
+#define hDCBasis wwdCurrentDoc.hDC
+#define dxaConvert czaInch
+#define dxpConvert dxpLogInch
+#define dyaConvert czaInch
+#define dypConvert dypLogInch
+#else /* Scale for printer */
+ extern int dxaPrPage, dxpPrPage, dyaPrPage, dypPrPage;
+ extern HDC vhDCPrinter;
+#define hDCBasis vhDCPrinter
+#define dxaConvert dxaPrPage
+#define dxpConvert dxpPrPage
+#define dyaConvert dyaPrPage
+#define dypConvert dypPrPage
+#endif
+
+ int mm = pmfp->mm;
+ int dxp, dyp;
+ int xres;
+ int yres;
+ int xsiz;
+ int ysiz;
+
+#if defined(OLE)
+ if (mm == MM_OLE)
+ return ObjQueryObjectBounds((struct PICINFOX FAR *)pmfp, vhDCPrinter, pdxa, pdya);
+ else
+#endif
+
+{
+ xres = GetDeviceCaps( hDCBasis, HORZRES );
+ yres = GetDeviceCaps( hDCBasis, VERTRES );
+ xsiz = GetDeviceCaps( hDCBasis, HORZSIZE );
+ ysiz = GetDeviceCaps( hDCBasis, VERTSIZE );
+
+ switch (mm) {
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ if (! ((pmfp->xExt > 0) && (pmfp->yExt > 0)))
+ { /* No "Suggested Size" given */
+ /* Use 3" vertically, 3" or as dictated by */
+ /* aspect ratio horizontally */
+ dyp = PxlConvert( MM_LOENGLISH, 300, yres, ysiz );
+ dxp = ((pmfp->xExt == 0) && (pmfp->yExt == 0)) ?
+ /* No aspect ratio info given -- use 3" horizontal */
+ PxlConvert( MM_LOENGLISH, 300, xres, xsiz ) :
+ /* Info has neg #'s; use to compute aspect ratio */
+ ((long)((long)dyp * (long)(iabs(pmfp->xExt)))) /
+ (long) (iabs(pmfp->yExt));
+ break;
+ }
+ else
+ mm = MM_HIMETRIC;
+ /* FALL THROUGH TO COMPUTE "SUGGESTED SIZE" */
+ default:
+ dxp = PxlConvert( mm, pmfp->xExt, xres, xsiz );
+ dyp = PxlConvert( mm, pmfp->yExt, yres, ysiz );
+ break;
+ }
+}
+
+if ((dxp == 0) || (dyp == 0))
+ /* bogus info or unknown map mode */
+ return FALSE;
+
+*pdxa = MultDiv( dxp, dxaConvert, dxpConvert );
+*pdya = MultDiv( dyp, dyaConvert, dypConvert );
+return TRUE;
+}
+
+
+HbmMonoFromHbmColor( hbmSrc )
+HBITMAP hbmSrc;
+{ /* Return a monochrome copy of the passed bitmap. Return NULL
+ if an error occurred. Assumes that the passed bitmap can be
+ selected into a memory DC which is compatible with the doc DC. */
+
+extern long rgbBkgrnd;
+extern long rgbText;
+extern HWND vhWnd;
+
+BITMAP bm;
+HBITMAP hbmMono=NULL;
+HDC hMDCSrc = NULL;
+HDC hMDCDst = NULL;
+
+/* Create memory DC for source, set colors, select in passed bitmap */
+
+ if ((hMDCSrc = CreateCompatibleDC( wwdCurrentDoc.hDC )) == NULL)
+ goto Error;
+
+#ifdef BOGUS
+ /* We can't assume that every window out there has the same window colors that
+ we have. In fact, we have no way to figure out how to convert this color
+ bitmap; so white will map to white and everything else will map to black. */
+ SetBkColor( hMDCSrc, rgbBkgrnd );
+ SetTextColor( hMDCSrc, rgbText );
+#endif /* BOGUS */
+
+ if (SelectObject( hMDCSrc, hbmSrc ) == NULL)
+ goto Error;
+
+ /* Create memory DC for destination, select in a new monochrome bitmap */
+
+ if ( ((hMDCDst = CreateCompatibleDC( wwdCurrentDoc.hDC )) == NULL) ||
+ ((GetObject( hbmSrc, sizeof (BITMAP), (LPSTR) &bm ) == 0)) ||
+ ((hbmMono = CreateBitmap( bm.bmWidth, bm.bmHeight,
+ 1, 1, (LPSTR) NULL )) == NULL) ||
+ (SelectObject( hMDCDst, hbmMono ) == NULL) )
+ {
+ goto Error;
+ }
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch,"HMFH: (dst) bmWidthB %lu * bmHeight %lu bmPlanes %lu\n\r",
+ (unsigned long) bm.bmWidthBytes, (unsigned long) bm.bmHeight,
+ (unsigned long) bm.bmPlanes );
+ CommSz(rgch);
+ }
+#endif
+
+ /* Now blt the bitmap contents. The screen driver in the source will
+ "do the right thing" in copying color to black-and-white. */
+
+ if (!BitBlt( hMDCDst, 0, 0, bm.bmWidth, bm.bmHeight, hMDCSrc, 0, 0, SRCCOPY ))
+ goto Error;
+
+ DeleteDC( hMDCSrc );
+ DeleteDC( hMDCDst );
+ return hbmMono;
+
+Error:
+
+ if (hMDCSrc != NULL) /* ORDER IS IMPORTANT: DC's before */
+ DeleteDC( hMDCSrc ); /* objects selected into them */
+ if (hMDCDst != NULL)
+ DeleteDC( hMDCDst );
+ if (hbmMono != NULL)
+ DeleteObject( hbmMono );
+ return NULL;
+}
+
+
+#if WINVER >= 0x300
+ /* Since copying more than 64k to the clipboard is now a real
+ possibility under protect mode, we really need a good assembler
+ bltbh(). We don't copy more than 64k at a time but we do
+ need to properly handle crossing segment boundaries. For now
+ the clipboard is the only place we need this so this C routine
+ will suffice for now ..pault */
+
+void bltbh(HPCH hpchFrom, HPCH hpchTo, int cch)
+ {
+ HPCH hpchFromLim;
+
+ for (hpchFromLim = hpchFrom + cch;
+ hpchFrom < hpchFromLim;
+ *(hpchTo++) = *(hpchFrom++))
+ ;
+ }
+#endif
+
diff --git a/private/mvdm/wow16/write/clipdisp.c b/private/mvdm/wow16/write/clipdisp.c
new file mode 100644
index 000000000..21770eb2d
--- /dev/null
+++ b/private/mvdm/wow16/write/clipdisp.c
@@ -0,0 +1,281 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* clipdisp.c -- Clipboard display routines */
+/* This module only gets called in when the clipboard view window is up */
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCTLMGR
+#include "windows.h"
+
+#include "mw.h"
+#include "docdefs.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "editdefs.h"
+#include "winddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#define SCRIBBLE
+#include "debug.h"
+
+extern int docCur; /* Document in current ww */
+extern int docScrap;
+extern struct WWD rgwwd [];
+
+
+int NEAR FGetClipboardDC( void );
+int NEAR SetupClipboardDC( void );
+int NEAR ReleaseClipboardDC( void );
+
+
+MdocPaintClipboard( hWnd, hPS )
+HWND hWnd;
+HANDLE hPS;
+{ /* Paint portion of clipboard window indicated by hPS */
+ LPPAINTSTRUCT lpps;
+
+ if (wwClipboard == wwNil)
+ return;
+
+ /* Must set the scroll bar range each time we get a PAINT message;
+ CLIPBRD.EXE resets it when it gets WM_DRAWCLIPBOARD */
+
+ SetScrollRange( wwdClipboard.wwptr, SB_VERT, 0, drMax-1, FALSE );
+ SetScrollRange( wwdClipboard.wwptr, SB_HORZ, 0, xpRightLim, FALSE );
+
+ if ( (lpps = (LPPAINTSTRUCT)GlobalLock( hPS )) != NULL )
+ { /* Paint the clipboard */
+ wwdClipboard.hDC = lpps->hdc;
+ SetupClipboardDC();
+ NewCurWw( wwClipboard, TRUE );
+ InvalBand( &wwdClipboard, lpps->rcPaint.top, lpps->rcPaint.bottom - 1 );
+ UpdateWw( wwClipboard, FALSE );
+ NewCurWw( wwDocument, TRUE );
+ GlobalUnlock( hPS );
+ }
+
+ /* Since the DC is no longer good, we'll set it to NULL */
+ wwdClipboard.hDC = NULL;
+
+#if 0
+#if defined(OLE)
+ /* gotta delete objects loaded from scrap document */
+ ObjEnumInDoc(docScrap,ObjDeleteObjectInDoc);
+#endif
+#endif
+}
+
+
+
+
+MdocSizeClipboard( hWnd, hRC )
+HWND hWnd;
+HANDLE hRC;
+{ /* Set clipboard window to be the rect in hRC */
+ /* If rectangle is 0 units high or wide, this means we're losing the
+ necessity for display until the next size message */
+ LPRECT lprc;
+ int dypRect;
+
+ if ( (lprc = (LPRECT)GlobalLock( hRC )) == NULL )
+ return;
+
+ if ( (dypRect = lprc->bottom - lprc->top) <= 0 )
+ { /* NULL rect, means lose display until we get a nonnull size */
+ if (wwClipboard != wwNil)
+ FreeWw( wwClipboard );
+ }
+ else if ( (wwClipboard != wwNil) ||
+ ((wwClipboard=WwAlloc( hWnd, docScrap )) != wwNil))
+ { /* Have WWD entry for clipboard, set its size */
+
+ wwdClipboard.wwptr = hWnd; /* Just in case clipboard
+ was closed, then re-opened */
+ wwdClipboard.xpMin = lprc->left;
+ wwdClipboard.xpMac = lprc->right;
+ wwdClipboard.ypMin = lprc->top;
+ wwdClipboard.ypMac = lprc->bottom;
+#ifdef WIN30
+ SetScrollPos(hWnd, SB_HORZ, 0, TRUE); /* suggested by sankar */
+#endif
+ }
+
+ GlobalUnlock( hRC );
+}
+
+
+
+
+MdocVScrollClipboard( hWnd, sbMessage, wNewThumb )
+HWND hWnd;
+int sbMessage;
+int wNewThumb;
+{
+ if ( hWnd != wwdClipboard.wwptr || wwClipboard == wwNil)
+ {
+ Assert( FALSE );
+ return;
+ }
+
+ if (!FGetClipboardDC())
+ /* Unable to create clipboard device context */
+ return;
+
+ NewCurWw( wwClipboard, TRUE );
+
+switch ( sbMessage )
+{
+case SB_THUMBPOSITION:
+ {
+ extern typeCP cpMacCur;
+
+ DirtyCache( wwdClipboard.cpFirst = (cpMacCur - wwdClipboard.cpMin) *
+ wNewThumb / (drMax - 1) + wwdClipboard.cpMin);
+ wwdClipboard.ichCpFirst = 0;
+ wwdClipboard.fCpBad = TRUE;
+ TrashWw( wwClipboard );
+ break;
+ }
+
+case SB_LINEUP:
+ ScrollUpCtr( 1 );
+ break;
+case SB_LINEDOWN:
+ ScrollDownCtr( 1 );
+ break;
+case SB_PAGEUP:
+ ScrollUpDypWw();
+ break;
+case SB_PAGEDOWN:
+ ScrollDownCtr( 100 ); /* 100 > tr's in a page */
+ break;
+}
+
+UpdateWw( wwClipboard, FALSE );
+
+NewCurWw( wwDocument, TRUE ); /* Frees the memory DC */
+ReleaseClipboardDC();
+}
+
+
+
+
+MdocHScrollClipboard( hWnd, sbMessage, wNewThumb )
+HWND hWnd;
+int sbMessage;
+int wNewThumb;
+{
+ if ( hWnd != wwdClipboard.wwptr || wwClipboard == wwNil)
+ {
+ Assert( FALSE );
+ return;
+ }
+
+ if (!FGetClipboardDC())
+ /* Unable to create clipboard device context */
+ return;
+
+ NewCurWw( wwClipboard, TRUE );
+
+ switch (sbMessage)
+ {
+ case SB_LINEUP: /* line left */
+ ScrollRight(xpMinScroll);
+ break;
+ case SB_LINEDOWN: /* line right */
+ ScrollLeft(xpMinScroll);
+ break;
+ case SB_PAGEUP: /* page left */
+ ScrollRight(wwdClipboard.xpMac - xpSelBar);
+ break;
+ case SB_PAGEDOWN: /* page right */
+ ScrollLeft(wwdClipboard.xpMac - xpSelBar);
+ break;
+ case SB_THUMBPOSITION:
+ /* position to posNew */
+ AdjWwHoriz( wNewThumb - wwdClipboard.xpMin );
+ break;
+ }
+
+UpdateWw( wwClipboard, FALSE );
+
+NewCurWw( wwDocument, TRUE ); /* Frees the memory DC */
+ReleaseClipboardDC();
+}
+
+
+
+
+MdocAskCBFormatName( lpchName, cchNameMax )
+LPCH lpchName;
+int cchNameMax;
+{ /* Copy the format name for the current contents of the clipboard
+ (of which we are the owner) to lpchName, copying no more than
+ cchNameMax characters */
+
+extern int vfOwnClipboard;
+extern int vfScrapIsPic;
+extern CHAR szWRITEText[];
+int cchCopy;
+
+Assert( vfOwnClipboard );
+
+/* Don't give a format name for pictures; the name is covered by the
+ standard types */
+
+if (!vfScrapIsPic)
+ {
+ if ( (cchCopy=CchSz( szWRITEText )) > cchNameMax )
+ {
+ lpchName[ cchCopy = cchNameMax - 1 ] = '\0';
+ }
+
+ bltbx( (LPSTR)szWRITEText, (LPSTR)lpchName, cchCopy );
+ }
+
+}
+
+
+
+
+int NEAR FGetClipboardDC()
+{ /* Get a DC for the clipboard window. Leave it in rgwwd [wwClipboard].
+ Call SetupClipboardDC to set up proper colors */
+
+ if ((wwdClipboard.hDC = GetDC( wwdClipboard.wwptr )) == NULL )
+ return FALSE;
+
+ SetupClipboardDC();
+ return TRUE;
+}
+
+int NEAR SetupClipboardDC()
+{ /* Select in the background brush for appropriate color behavior. */
+
+ extern long rgbBkgrnd;
+ extern long rgbText;
+ extern HBRUSH hbrBkgrnd;
+
+SelectObject( wwdClipboard.hDC, hbrBkgrnd );
+SetBkColor( wwdClipboard.hDC, rgbBkgrnd );
+SetTextColor( wwdClipboard.hDC, rgbText );
+}
+
+
+
+int NEAR ReleaseClipboardDC()
+{
+ReleaseDC( wwdClipboard.wwptr, wwdClipboard.hDC );
+wwdClipboard.hDC = NULL; /* Mark clipboard DC as invalid */
+}
diff --git a/private/mvdm/wow16/write/cmacros2.inc b/private/mvdm/wow16/write/cmacros2.inc
new file mode 100644
index 000000000..366db0265
--- /dev/null
+++ b/private/mvdm/wow16/write/cmacros2.inc
@@ -0,0 +1,1236 @@
+comment $
+cmacros - assembly macros for interfacing to hhls
+(C)Copyright Microsoft Corp. 1984-1988
+$
+.xcref
+.xcref ??_out
+??_out macro t
+ifndef ?QUIET
+%out t
+endif
+endm
+outif macro name,defval,onmsg,offmsg
+ifndef name
+ifb <defval>
+name=0
+else
+name=defval
+endif
+endif
+if name
+name=1
+ifnb <onmsg>
+??_out <! onmsg>
+endif
+else
+ifnb <offmsg>
+??_out <! offmsg>
+endif
+endif
+endm
+.xcref ??error
+??error macro msg
+e r r o r ----- msg
+.err
+endm
+.xcref ASMpass
+.xcref memS,memM,memL,memC,memH,memMOD,sizec,sized
+if1
+ASMpass=1
+ifdef ?SMALL
+memS=1
+endif
+ifdef ?MEDIUM
+memM=1
+endif
+ifdef ?COMPACT
+memC=1
+endif
+ifdef ?LARGE
+memL=1
+endif
+ifdef ?HUGE
+memH=1
+endif
+??_out <cMacros Version 5.20 - Copyright (c) Microsoft Corp. 1984-1988>
+outif memS,0,<Small model>
+outif memM,0,<Medium model>
+outif memL,0,<Large model>
+outif memC,0,<Compact model>
+outif memH,0,<Huge model>
+memMOD= memS + memM + memL + memC + memH
+if memMOD ne 1
+if memMOD eq 0
+memS = 1
+else
+??error <more than 1 memory model selected>
+endif
+endif
+sizec= memM + memL + memH
+sized= memL + memC + (memH*2)
+outif ?DF,0,<No segments or groups will be defined>
+outif ?TF,0,<Epilog sequences assume valid SP>
+outif ?WIN,1,<Windows support>
+if ?WIN eq 1
+outif ?PLM,1,<>
+else
+outif ?PLM,1,<PL/M calling convention>
+endif
+ifndef ?NODATA
+?nodata1=0
+else
+?nodata1=1
+??_out <! NODATA module>
+endif
+ifndef ?CHKSTK
+?chkstk1=0
+else
+?chkstk1=1
+ifdef ?CHKSTKPROC
+??_out <! Private stack checking enabled>
+else
+??_out <! Stack checking enabled>
+endif
+endif
+ifndef DOS5
+?DOS5=0
+else
+?DOS5=1
+??_out <! DOS5 module>
+endif
+ifdef ?PROFILE
+??_out <! Native profiling enabled>
+endif
+else
+ASMpass=2
+endif
+.xcref ?n,?ax,?ah,?al,?bx,?bh
+.xcref ?bl,?cx,?ch,?cl,?dx,?dh
+.xcref ?dl,?si,?di,?es,?ds,?bp
+.xcref ?sp,?ss,?cs
+.xcref ?rsl,?cpd,?argl,?argc,?ba
+.xcref ?acb,???,?po
+.xcref ?pas,?pc
+.xcref uconcat,mpush,mpop
+.xcref ?ri,?pp,?pp1,?al1
+.xcref ?ad,?ap,?atal,?dd,?dd1,?dd2
+.xcref ?pg,?pg1,?aloc,?cs1,?cs2
+.xcref ?DF,?TF,?ff,?PLM,?WIN,?ia,?pu,?adj
+.xcref ?uf,?rp,?nx,?nd,?nodata1,?chkstk1,?DOS5
+.xcref ?wfp,arg,cCall,cProc,assumes,?cs3,?cs2,?cs1
+.xcref defgrp,addseg,createSeg
+.xcref save,outif,errnz,errn$,errnz1
+.xcref ?PLMPrevParm,?gcc
+.xcref ?cCall1,?pcc
+?rsl = 0
+?cpd = 0
+?argl = 0
+?argc = 0
+?ba = 0
+?acb = 0
+??? = 0
+?po = 0
+?pas = 0
+?pc = 0
+?ia = 0
+?pu = 0
+?adj = 0
+?rp = 0
+?uf = 0
+?nd = 0
+?nx = 0
+?wfp = 0
+?ff = 0
+?dd2 = 0
+?cCall1 = 0
+?pcc = 0
+?PLMPrevParm = 0
+.xcref ?casen
+if1
+?casen = 0
+endif
+?n = 0000000000000000b
+?ax = 0000000000000011b
+?ah = 0000000000000001b
+?al = 0000000000000010b
+?bx = 0000000000001100b
+?bh = 0000000000000100b
+?bl = 0000000000001000b
+?cx = 0000000000110000b
+?ch = 0000000000010000b
+?cl = 0000000000100000b
+?dx = 0000000011000000b
+?dh = 0000000001000000b
+?dl = 0000000010000000b
+?si = 0000000100000000b
+?di = 0000001000000000b
+?es = 0000010000000000b
+?ds = 0000100000000000b
+?bp = 0001000000000000b
+?sp = 0010000000000000b
+?ss = 0100000000000000b
+?cs = 1000000000000000b
+.cref
+uconcat macro a,b,c,d,e,f,g
+a&b c&d e&f&g
+endm
+mpush macro r
+irp x,<ax,bx,cx,dx,si,di,es,ds,bp,sp,ss,cs>
+if (r and ?&&x)
+ push x
+endif
+endm
+endm
+mpop macro r
+irp x,<cs,ss,sp,bp,ds,es,di,si,dx,cx,bx,ax>
+if (r and ?&&x)
+ pop x
+endif
+endm
+endm
+save macro r
+?rsl=0
+?ri ?rsl,<r>
+endm
+?ri macro n,r
+irp x,<r>
+ifdef ?&&x
+n=n or ?&&x
+endif
+endm
+endm
+.xcref
+.xcref parmB,parmW,parmD,parmQ,parmT,parmCP,parmDP
+.cref
+parmB macro n
+?pp <n>,<byte>,2,1
+endm
+parmW macro n
+?pp <n>,<word>,2,2
+endm
+parmD macro n
+ife ?PLM
+irp x,<n>
+?pp <&&x>,<dword>,0,4
+?pp <off_&&x>,<word>,2,2
+?pp <seg_&&x>,<word>,2,2
+endm
+else
+irp x,<n>
+?pp <seg_&&x>,<word>,2,2
+?pp <off_&&x>,<word>,2,2
+?pp <&&x>,<dword>,0,4
+endm
+endif
+endm
+parmQ macro n
+?pp <n>,<qword>,8,8
+endm
+parmT macro n
+?pp <n>,<tbyte>,10,10
+endm
+if sizec
+parmCP macro n
+parmD <n>
+endm
+else
+parmCP macro n
+parmW <n>
+endm
+endif
+if sized
+parmDP macro n
+parmD <n>
+endm
+else
+parmDP macro n
+parmW <n>
+endm
+endif
+?pp macro n,t,l,s
+if ?cpd
+.xcref
+irp x,<n>
+.xcref ?t&&x
+?t&&x=s
+ife ?PLM
+?pp1 x,<t>,,,%(?po+?adj)
+?po=?po+l
+else
+?PLMPrevParm=?PLMPrevParm+1
+?po=?po+l
+?pp1 x,<t>,%?po,%?adj,,%?PLMPrevParm,%(?PLMPrevParm-1)
+endif
+endm
+.cref
+else
+??error <parm(s) "&n" declared outside proc def>
+endif
+endm
+?pp1 macro n,t,o,a,b,cpc,ppc
+ife ?PLM
+n equ (t ptr [bp+b])
+else
+.xcref
+.xcref ?PLMParm&cpc
+.cref
+?PLMParm&cpc &macro po
+uconcat <n>,,<equ>,,<(t ptr [bp+>,%(a+po-o),<])>
+?PLMParm&ppc po
+purge ?PLMParm&cpc
+&endm
+endif
+endm
+ifndef ?NOPARMR
+.xcref
+.xcref ?pr,parmR
+.cref
+parmR macro n,r,r2
+?pr n,r,r2,%?rp,%(?ia+2)
+endm
+?pr macro n,r,r2,i,o
+.xcref
+ifnb <r2>
+parmR seg_&n,r
+parmR off_&n,r2
+n equ (dword ptr [bp-o-2])
+.xcref ?t&n
+?t&n=4
+else
+.xcref ?rp&i
+?rp&i=0
+ifdef ?&r
+?rp&i=?&r
+endif
+if ??? or (?cpd eq 0) or (?rp&i eq 0)
+??error <invalid parmR encountered: &n,&r>
+exitm
+endif
+n equ (word ptr [bp-o])
+?t&n=2
+irp x,<bh,ch,dh,bl,cl,dl,ah,al>
+if ?&&x eq ?&r
+n equ (byte ptr [bp-o])
+?t&n=1
+exitm
+endif
+endm
+?ia=?ia+2
+?rp=?rp+1
+endif
+.cref
+endm
+endif
+.xcref
+.xcref localB,localW,localD,localQ,localT,localCP,localDP,localV
+.cref
+localB macro n
+?aloc <n>,<byte ptr>,1,1,0
+endm
+localW macro n
+?aloc <n>,<word ptr>,2,2,1
+endm
+localD macro n
+irp x,<n>
+?aloc <seg_&&x>,<word ptr>,2,2,1
+?aloc <off_&&x>,<word ptr>,2,2,1
+?aloc <&&x>,<dword ptr>,0,4,1
+endm
+endm
+localQ macro n
+?aloc <n>,<qword ptr>,8,8,1
+endm
+localT macro n
+?aloc <n>,<tbyte ptr>,10,10,1
+endm
+if sizec
+localCP macro n
+localD <n>
+endm
+else
+localCP macro n
+localW <n>
+endm
+endif
+if sized
+localDP macro n
+localD <n>
+endm
+else
+localDP macro n
+localW <n>
+endm
+endif
+localV macro n,a
+?aloc <n>,,%(a),0,1
+endm
+?aloc macro n,t,l,s,a
+if ?cpd
+.xcref
+irp x,<n>
+???=???+l
+if a
+???=((??? + 1) and 0fffeh)
+endif
+?al1 x,<t>,%(???+?ia)
+.xcref ?t&&x
+?t&&x=s
+endm
+.cref
+else
+??error <locals "&n" declared outside procedure def>
+endif
+endm
+?al1 macro n,t,o
+n equ (t [bp-o])
+endm
+?gcc macro s,i,cc
+s = i
+ifnb <cc>
+ifidn <cc>,<C>
+s=0
+endif
+ifidn <cc>,<PLM>
+s=1
+endif
+ifidn <cc>,<PASCAL>
+s=1
+endif
+endif
+endm
+ifndef ?NOGLOBAL
+.xcref
+.xcref globalB,globalW,globalD,globalQ,globalT,globalCP,globalDP
+.cref
+globalB macro n,i,s,c
+?ad <n>,1
+?dd n,1,<byte>,<db>,<i>,<s>,<c>
+endm
+globalW macro n,i,s,c
+?ad <n>,2
+?dd n,1,<word>,<dw>,<i>,<s>,<c>
+endm
+globalD macro n,i,s,c
+?ad <n>,4
+?dd n,1,<dword>,<dd>,<i>,<s>,<c>
+off_&n equ n
+seg_&n equ n[2]
+endm
+globalQ macro n,i,s,c
+?ad <n>,8
+?dd n,1,<qword>,<dq>,<i>,<s>,<c>
+endm
+globalT macro n,i,s,c
+?ad <n>,10
+?dd n,1,<tbyte>,<dt>,<i>,<s>,<c>
+endm
+if sizec
+globalCP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalCP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+if sized
+globalDP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalDP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+endif
+ifndef ?NOSTATIC
+.xcref
+.xcref staticB,staticW,staticD,staticQ,staticT,staticCP,staticDP
+.cref
+staticB macro n,i,s
+?ad <n>,1
+?dd n,0,<byte>,<db>,<i>,<s>,<PLM>
+endm
+staticW macro n,i,s
+?ad <n>,2
+?dd n,0,<word>,<dw>,<i>,<s>,<PLM>
+endm
+staticD macro n,i,s
+?ad <n>,4
+?dd n,0,<dword>,<dd>,<i>,<s>,<PLM>
+endm
+staticQ macro n,i,s
+?ad <n>,8
+?dd n,0,<qword>,<dq>,<i>,<s>,<PLM>
+endm
+staticT macro n,i,s
+?ad <n>,10
+?dd n,0,<tbyte>,<dt>,<i>,<s>,<PLM>
+endm
+if sizec
+staticCP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticCP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+if sized
+staticDP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticDP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+endif
+?dd macro n,p,t,d,i,s,c
+?gcc ?dd2,%?PLM,<c>
+ife ?dd2
+n label t
+?dd1 _&n,p,<d>,<i>,<s>
+else
+?dd1 n,p,<d>,<i>,<s>
+endif
+endm
+?dd1 macro n,p,d,i,s
+if p
+public n
+endif
+ifb <s>
+n d i
+else
+ifb <i>
+n d s dup (?)
+else
+n d s dup (i)
+endif
+endif
+endm
+ifndef ?NOEXTERN
+.xcref
+.xcref ?ex1,?ex2,externB,externW,externD,externQ,externT
+.xcref externNP,externFP,externP,externCP,externDP,externA
+.cref
+?ex2 = 0
+externA macro n,c
+?ex1 <n>,40h,<abs>,<c>,<>
+endm
+externB macro n,c
+?ex1 <n>,1,<byte>,<c>,<>
+endm
+externW macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+externD macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+externQ macro n,c
+?ex1 <n>,8,<qword>,<c>,<>
+endm
+externT macro n,c
+?ex1 <n>,10,<tbyte>,<c>,<>
+endm
+externNP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+externFP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+if sizec
+externP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+else
+externP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+endif
+if sizec
+externCP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externCP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+if sized
+externDP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externDP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+?ex1 macro n,s,d,c,scv
+?gcc ?ex2,%?PLM,<c>
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?ex2
+extrn _&&x:&d
+x equ _&&x
+else
+extrn x:&d
+endif
+ifidn <scv>,<cc>
+.xcref
+.xcref ?CC&&x
+.cref
+?CC&&x=?ex2
+endif
+endm
+endm
+endif
+ifndef ?NOLABEL
+.xcref
+.xcref ?lb1,?lblpu,?lb2
+.xcref labelB,labelW,labelD,labelQ,labelT
+.xcref labelNP,labelFP,labelP,labelCP,labelDP
+.cref
+?lblpu = 0
+?lb2 = 0
+labelB macro n,c
+?lb1 <n>,1,<byte>,<c>
+endm
+labelW macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+labelD macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+labelQ macro n,c
+?lb1 <n>,8,<qword>,<c>
+endm
+labelT macro n,c
+?lb1 <n>,10,<tbyte>,<c>
+endm
+labelNP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+labelFP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+if sizec
+labelP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+else
+labelP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+endif
+if sizec
+labelCP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelCP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+if sized
+labelDP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelDP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+?lb1 macro n,s,d,c
+?gcc ?lb2,%?PLM,<c>
+?lblpu=0
+irp x,<n>
+ifidn <x>,<PUBLIC>
+?lblpu=1
+else
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?lb2
+if ?lblpu
+public _&&x
+endif
+_&&x label &d
+x equ _&&x
+else
+if ?lblpu
+public x
+endif
+x label &d
+endif
+endif
+endm
+endm
+endif
+ifndef ?NODEF
+.xcref
+.xcref defB,defW,defD,defQ,defT,defCP,defDP
+.cref
+defB macro n
+?ad <n>,1
+endm
+defW macro n
+?ad <n>,2
+endm
+defD macro n
+?ad <n>,4
+endm
+defQ macro n
+?ad <n>,8
+endm
+defT macro n
+?ad <n>,10
+endm
+if sizec
+defCP macro n
+defD <n>
+endm
+else
+defCP macro n
+defW <n>
+endm
+endif
+if sized
+defDP macro n
+defD <n>
+endm
+else
+defDP macro n
+defW <n>
+endm
+endif
+endif
+?ad macro n,s
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+endm
+endm
+ifndef ?NOPTR
+.xcref
+.xcref regPtr,farPtr
+.cref
+regPtr macro n,s,o
+farPtr n,s,o
+endm
+farPtr macro n,s,o
+.xcref
+.xcref ?t&n
+.cref
+n &macro
+ push s
+ push o
+&endm
+?t&n=80h
+endm
+endif
+arg macro a
+irp x,<a>
+?argc=?argc+1
+?atal <x>,%?argc
+endm
+endm
+?atal macro n,i
+.xcref
+.xcref ?ali&i
+.cref
+?ali&i &macro
+?ap n
+&endm
+endm
+?ap macro n
+?argl=?argl+2
+ifdef ?t&n
+ife ?t&n-1
+ push word ptr (n)
+exitm
+endif
+ife ?t&n-2
+ push n
+exitm
+endif
+ife ?t&n-4
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+2
+exitm
+endif
+ife ?t&n-8
+ push word ptr (n)[6]
+ push word ptr (n)[4]
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+6
+exitm
+endif
+if ?t&n and 80h
+n
+?argl=?argl+2
+exitm
+endif
+ife ?t&n
+ push word ptr (n)
+exitm
+endif
+endif
+ push n
+endm
+cCall macro n,a,c
+ifnb <a>
+arg <a>
+endif
+mpush %?rsl
+ifdef ?CC&n
+?cCall1=?CC&n
+else
+?cCall1=?PLM
+endif
+ifnb <c>
+?gcc ?cCall1,%?cCall1,<c>
+endif
+?argl=0
+ife ?cCall1
+?acb=?argc
+else
+?acb=1
+endif
+rept ?argc
+uconcat <?ali>,%?acb
+uconcat <purge>,,<?ali>,%?acb
+ife ?cCall1
+?acb=?acb-1
+else
+?acb=?acb+1
+endif
+endm
+ call n
+if ((?cCall1 eq 0) and (?argl ne 0))
+ add sp,?argl
+endif
+mpop %?rsl
+?rsl=0
+?argc= 0
+?argl= 0
+endm
+cProc macro n,cf,a
+if ?cpd
+?utpe
+endif
+?cpd=1
+???=0
+?argc=0
+?ba=0
+?po=0
+?pu=0
+?ia=0
+?adj=4
+?rp=0
+?uf=0
+?wfp=?WIN
+?ff=0
+?pas=0
+?pcc=?PLM
+ifnb <a>
+?ri ?pas,<a>
+endif
+?pc=sizec
+?nd=?nodata1
+?nx=0
+irp x,<cf>
+ifidn <x>,<FAR>
+?pc=1
+endif
+ifidn <x>,<NEAR>
+?pc=0
+endif
+ifidn <x>,<PUBLIC>
+?pu=1
+endif
+ifidn <x>,<SMALL>
+?uf=1
+endif
+ifidn <x>,<DATA>
+?nd=0
+endif
+ifidn <x>,<NODATA>
+?nd=1
+endif
+ifidn <x>,<ATOMIC>
+?nx=1
+endif
+ifidn <x>,<C>
+?pcc=0
+endif
+ifidn <x>,<PLM>
+?pcc=1
+endif
+ifidn <x>,<PASCAL>
+?pcc=1
+endif
+ifidn <x>,<WIN>
+?wfp=1
+endif
+ifidn <x>,<NONWIN>
+?wfp=0
+endif
+endm
+if ?pcc
+?PLMPrevParm=0
+.xcref
+.xcref ?PLMParm0
+.cref
+?PLMParm0 &macro
+purge ?PLMParm0
+&endm
+endif
+.xcref
+.xcref ?CC&n
+.cref
+?CC&n=?pcc
+if (?nx eq 1) and (?nd eq 0)
+?nx = 0
+??error <ATOMIC specified without NODATA - ATOMIC ignored>
+endif
+if ?pc
+if ?wfp
+ife ?nx
+?ia=2
+?pas = ?pas and (not ?ds)
+endif
+endif
+?adj=?adj+2
+else
+?wfp=0
+endif
+?pas = ?pas and (not (?sp+?cs+?ss))
+if ?uf
+?pas = ?pas and (not (?bp+?si+?di))
+endif
+ife ?pcc
+?pg <_&n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+else
+?pg <n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+endif
+endm
+?pg macro n,p,c,a,w,nnu,cc
+.xcref
+if ?uf
+if ?nd
+??error <NODATA encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+.xcref cBegin
+cBegin &macro g
+.xcref
+if cc
+uconcat <?PLMParm>,%?PLMPrevParm,%?po
+endif
+if ?uf
+if ?rp
+??error <parmR encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+?pg1 <n>,c,a,%?po,w,%?uf,%?nd,%?rp,cc
+?cpd=0
+?argc=0
+?ba=1
+???=(???+1) and 0fffeh
+if p
+public n
+endif
+ife c
+n proc near
+else
+n proc far
+endif
+ife cc
+nnu equ n
+endif
+ifidn <g>,<nogen>
+if ???+?po+a+?rp
+??_out <cBegin - possible invalid use of nogen>
+endif
+else
+if ?uf
+?mf c,%???,%?po
+mpush a
+else
+if w
+ife ?nd
+ mov ax,ds
+ nop
+endif
+ife ?nx
+ife ?DOS5
+ inc bp
+endif
+ push bp
+ mov bp,sp
+ push ds
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+ife ?nd
+ mov ds,ax
+endif
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+if ?rp
+?uf=0
+rept ?rp
+uconcat mpush,,?rp,%?uf
+?uf=?uf+1
+endm
+endif
+if ???
+if ?chkstk1
+ifdef ?CHKSTKPROC
+?CHKSTKPROC %???
+else
+ mov ax,???
+ife cc
+ call _chkstk
+else
+ call chkstk
+endif
+endif
+else
+ sub sp,???
+endif
+endif
+mpush a
+endif
+ifdef ?PROFILE
+if c
+ call StartNMeas
+endif
+endif
+endif
+.cref
+purge cBegin
+&endm
+.xcref ?utpe
+?utpe &macro
+??error <unterminated procedure definition: "&n">
+&endm
+.cref
+endm
+?pg1 macro n,c,a,o,w,f,d,r,cc
+.xcref
+.xcref cEnd
+cEnd &macro g
+.xcref
+?ba=0
+ifidn <g>,<nogen>
+if o+a+r
+??_out <cEnd - possible invalid use of nogen>
+endif
+else
+ifdef ?PROFILE
+if c
+call StopNMeas
+endif
+endif
+mpop a
+if f
+ db 0c3h
+else
+if w
+ife ?nx
+if (?TF eq 0) or (???+?rp)
+ lea sp,-2[bp]
+endif
+ pop ds
+ pop bp
+ife ?DOS5
+ dec bp
+endif
+else
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+if ???+?po+?rp
+ pop bp
+endif
+endif
+else
+if ?ff+???+?po+?rp
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+ pop bp
+endif
+endif
+ife cc
+ ret
+else
+ ret o
+endif
+endif
+endif
+n endp
+.cref
+purge cEnd
+&endm
+.cref
+endm
+assumes macro s,ln
+ifndef ln&_assumes
+assume s:ln
+else
+ln&_assumes s
+endif
+endm
+createSeg macro n,ln,a,co,cl,grp
+ifnb <grp>
+addseg grp,n
+else
+ln&OFFSET equ offset n:
+ln&BASE equ n
+?cs3 <ln>,<n>
+endif
+ifnb <cl>
+n segment a co '&cl'
+else
+n segment a co
+endif
+n ends
+?cs1 <ln>,<n>
+endm
+addseg macro grp,seg
+.xcref
+.xcref grp&_def
+.cref
+ifndef grp&_def
+grp&_def=0
+endif
+if grp&_def ne ASMpass
+.xcref
+.xcref grp&_add
+.cref
+grp&_add &macro s
+grp&_in <seg>,s
+&endm
+.xcref
+.xcref grp&_in
+.cref
+grp&_in &macro sl,s
+ifb <s>
+grp group sl
+else
+grp&_add &macro ns
+grp&_in <sl,s>,ns
+&endm
+endif
+&endm
+grp&_def=ASMpass
+else
+grp&_add seg
+endif
+endm
+defgrp macro grp,ln
+addseg grp
+ifnb <ln>
+irp x,<ln>
+?cs3 <&x>,<grp>
+x&&OFFSET equ offset grp:
+x&&BASE equ grp
+endm
+endif
+endm
+?cs1 macro ln,n
+.xcref
+.xcref ln&_sbegin
+.cref
+ln&_sbegin &macro
+.xcref
+.xcref ?mf
+.cref
+?mf &&macro c,l,p
+if c
+ extrn n&_FARFRAME:near
+ call n&_FARFRAME
+else
+ extrn n&_NEARFRAME:near
+ call n&_NEARFRAME
+endif
+ db l shr 1
+ db p shr 1
+&&endm
+?cs2 <ln>,<n>
+n segment
+&endm
+endm
+?cs2 macro ln,n
+.xcref
+.xcref sEnd
+.cref
+sEnd &macro
+n ends
+purge ?mf
+purge sEnd
+&endm
+endm
+?cs3 macro ln,n
+.xcref
+.xcref ln&_assumes
+.cref
+ln&_assumes &macro s
+assume s:&n
+&endm
+endm
+.xcref
+.xcref sBegin
+.cref
+sBegin macro ln
+ln&_sbegin
+endm
+ife ?DF
+createSeg FILE_TEXT,Code,word,public,CODE
+ife ?nodata1
+createSeg _DATA,Data,word,public,DATA,DGROUP
+defgrp DGROUP,Data
+endif
+if ?chkstk1
+ifndef ?CHKSTKPROC
+externp <chkstk>
+endif
+endif
+endif
+errnz macro x
+if2
+if x
+errnz1 <x>,%(x)
+endif
+endif
+endm
+errnz1 macro x1,x2
+= *errnz* x1 = x2
+.err
+endm
+errn$ macro l,x
+errnz <offset $ - offset l x>
+endm
+ifdef ?PROFILE
+externFP <StartNMeas,StopNMeas>
+endif
diff --git a/private/mvdm/wow16/write/cmacros3.inc b/private/mvdm/wow16/write/cmacros3.inc
new file mode 100644
index 000000000..a6b9b487d
--- /dev/null
+++ b/private/mvdm/wow16/write/cmacros3.inc
@@ -0,0 +1,1236 @@
+comment $
+cmacros - assembly macros for interfacing to hhls
+(C)Copyright Microsoft Corp. 1984-1988
+$
+.xcref
+.xcref ??_out
+??_out macro t
+ifndef ?QUIET
+%out t
+endif
+endm
+outif macro name,defval,onmsg,offmsg
+ifndef name
+ifb <defval>
+name=0
+else
+name=defval
+endif
+endif
+if name
+name=1
+ifnb <onmsg>
+??_out <! onmsg>
+endif
+else
+ifnb <offmsg>
+??_out <! offmsg>
+endif
+endif
+endm
+.xcref ??error
+??error macro msg
+e r r o r ----- msg
+.err
+endm
+.xcref ASMpass
+.xcref memS,memM,memL,memC,memH,memMOD,sizec,sized
+if1
+ASMpass=1
+ifdef ?SMALL
+memS=1
+endif
+ifdef ?MEDIUM
+memM=1
+endif
+ifdef ?COMPACT
+memC=1
+endif
+ifdef ?LARGE
+memL=1
+endif
+ifdef ?HUGE
+memH=1
+endif
+??_out <cMacros Version 5.20 - Copyright (c) Microsoft Corp. 1984-1988>
+outif memS,0,<Small model>
+outif memM,0,<Medium model>
+outif memL,0,<Large model>
+outif memC,0,<Compact model>
+outif memH,0,<Huge model>
+memMOD= memS + memM + memL + memC + memH
+if memMOD ne 1
+if memMOD eq 0
+memS = 1
+else
+??error <more than 1 memory model selected>
+endif
+endif
+sizec= memM + memL + memH
+sized= memL + memC + (memH*2)
+outif ?DF,0,<No segments or groups will be defined>
+outif ?TF,0,<Epilog sequences assume valid SP>
+outif ?WIN,1,<Windows support>
+if ?WIN eq 1
+outif ?PLM,1,<>
+else
+outif ?PLM,1,<PL/M calling convention>
+endif
+ifndef ?NODATA
+?nodata1=0
+else
+?nodata1=1
+??_out <! NODATA module>
+endif
+ifndef ?CHKSTK
+?chkstk1=0
+else
+?chkstk1=1
+ifdef ?CHKSTKPROC
+??_out <! Private stack checking enabled>
+else
+??_out <! Stack checking enabled>
+endif
+endif
+ifndef DOS5
+?DOS5=0
+else
+?DOS5=1
+??_out <! DOS5 module>
+endif
+ifdef ?PROFILE
+??_out <! Native profiling enabled>
+endif
+else
+ASMpass=2
+endif
+.xcref ?n,?ax,?ah,?al,?bx,?bh
+.xcref ?bl,?cx,?ch,?cl,?dx,?dh
+.xcref ?dl,?si,?di,?es,?ds,?bp
+.xcref ?sp,?ss,?cs
+.xcref ?rsl,?cpd,?argl,?argc,?ba
+.xcref ?acb,???,?po
+.xcref ?pas,?pc
+.xcref uconcat,mpush,mpop
+.xcref ?ri,?pp,?pp1,?al1
+.xcref ?ad,?ap,?atal,?dd,?dd1,?dd2
+.xcref ?pg,?pg1,?aloc,?cs1,?cs2
+.xcref ?DF,?TF,?ff,?PLM,?WIN,?ia,?pu,?adj
+.xcref ?uf,?rp,?nx,?nd,?nodata1,?chkstk1,?DOS5
+.xcref ?wfp,arg,cCall,cProc,assumes,?cs3,?cs2,?cs1
+.xcref defgrp,addseg,createSeg
+.xcref save,outif,errnz,errn$,errnz1
+.xcref ?PLMPrevParm,?gcc
+.xcref ?cCall1,?pcc
+?rsl = 0
+?cpd = 0
+?argl = 0
+?argc = 0
+?ba = 0
+?acb = 0
+??? = 0
+?po = 0
+?pas = 0
+?pc = 0
+?ia = 0
+?pu = 0
+?adj = 0
+?rp = 0
+?uf = 0
+?nd = 0
+?nx = 0
+?wfp = 0
+?ff = 0
+?dd2 = 0
+?cCall1 = 0
+?pcc = 0
+?PLMPrevParm = 0
+.xcref ?casen
+if1
+?casen = 0
+endif
+?n = 0000000000000000b
+?ax = 0000000000000011b
+?ah = 0000000000000001b
+?al = 0000000000000010b
+?bx = 0000000000001100b
+?bh = 0000000000000100b
+?bl = 0000000000001000b
+?cx = 0000000000110000b
+?ch = 0000000000010000b
+?cl = 0000000000100000b
+?dx = 0000000011000000b
+?dh = 0000000001000000b
+?dl = 0000000010000000b
+?si = 0000000100000000b
+?di = 0000001000000000b
+?es = 0000010000000000b
+?ds = 0000100000000000b
+?bp = 0001000000000000b
+?sp = 0010000000000000b
+?ss = 0100000000000000b
+?cs = 1000000000000000b
+.cref
+uconcat macro a,b,c,d,e,f,g
+a&b c&d e&f&g
+endm
+mpush macro r
+irp x,<ax,bx,cx,dx,si,di,es,ds,bp,sp,ss,cs>
+if (r and ?&&x)
+ push x
+endif
+endm
+endm
+mpop macro r
+irp x,<cs,ss,sp,bp,ds,es,di,si,dx,cx,bx,ax>
+if (r and ?&&x)
+ pop x
+endif
+endm
+endm
+save macro r
+?rsl=0
+?ri ?rsl,<r>
+endm
+?ri macro n,r
+irp x,<r>
+ifdef ?&&x
+n=n or ?&&x
+endif
+endm
+endm
+.xcref
+.xcref parmB,parmW,parmD,parmQ,parmT,parmCP,parmDP
+.cref
+parmB macro n
+?pp <n>,<byte>,2,1
+endm
+parmW macro n
+?pp <n>,<word>,2,2
+endm
+parmD macro n
+ife ?PLM
+irp x,<n>
+?pp <&&x>,<dword>,0,4
+?pp <off_&&x>,<word>,2,2
+?pp <seg_&&x>,<word>,2,2
+endm
+else
+irp x,<n>
+?pp <seg_&&x>,<word>,2,2
+?pp <off_&&x>,<word>,2,2
+?pp <&&x>,<dword>,0,4
+endm
+endif
+endm
+parmQ macro n
+?pp <n>,<qword>,8,8
+endm
+parmT macro n
+?pp <n>,<tbyte>,10,10
+endm
+if sizec
+parmCP macro n
+parmD <n>
+endm
+else
+parmCP macro n
+parmW <n>
+endm
+endif
+if sized
+parmDP macro n
+parmD <n>
+endm
+else
+parmDP macro n
+parmW <n>
+endm
+endif
+?pp macro n,t,l,s
+if ?cpd
+.xcref
+irp x,<n>
+.xcref ?t&&x
+?t&&x=s
+ife ?PLM
+?pp1 x,<t>,,,%(?po+?adj)
+?po=?po+l
+else
+?PLMPrevParm=?PLMPrevParm+1
+?po=?po+l
+?pp1 x,<t>,%?po,%?adj,,%?PLMPrevParm,%(?PLMPrevParm-1)
+endif
+endm
+.cref
+else
+??error <parm(s) "&n" declared outside proc def>
+endif
+endm
+?pp1 macro n,t,o,a,b,cpc,ppc
+ife ?PLM
+n equ (t ptr [bp+b])
+else
+.xcref
+.xcref ?PLMParm&cpc
+.cref
+?PLMParm&cpc &macro po
+uconcat <n>,,<equ>,,<(t ptr [bp+>,%(a+po-o),<])>
+?PLMParm&ppc po
+purge ?PLMParm&cpc
+&endm
+endif
+endm
+ifndef ?NOPARMR
+.xcref
+.xcref ?pr,parmR
+.cref
+parmR macro n,r,r2
+?pr n,r,r2,%?rp,%(?ia+2)
+endm
+?pr macro n,r,r2,i,o
+.xcref
+ifnb <r2>
+parmR seg_&n,r
+parmR off_&n,r2
+n equ (dword ptr [bp-o-2])
+.xcref ?t&n
+?t&n=4
+else
+.xcref ?rp&i
+?rp&i=0
+ifdef ?&r
+?rp&i=?&r
+endif
+if ??? or (?cpd eq 0) or (?rp&i eq 0)
+??error <invalid parmR encountered: &n,&r>
+exitm
+endif
+n equ (word ptr [bp-o])
+?t&n=2
+irp x,<bh,ch,dh,bl,cl,dl,ah,al>
+if ?&&x eq ?&r
+n equ (byte ptr [bp-o])
+?t&n=1
+exitm
+endif
+endm
+?ia=?ia+2
+?rp=?rp+1
+endif
+.cref
+endm
+endif
+.xcref
+.xcref localB,localW,localD,localQ,localT,localCP,localDP,localV
+.cref
+localB macro n
+?aloc <n>,<byte ptr>,1,1,0
+endm
+localW macro n
+?aloc <n>,<word ptr>,2,2,1
+endm
+localD macro n
+irp x,<n>
+?aloc <seg_&&x>,<word ptr>,2,2,1
+?aloc <off_&&x>,<word ptr>,2,2,1
+?aloc <&&x>,<dword ptr>,0,4,1
+endm
+endm
+localQ macro n
+?aloc <n>,<qword ptr>,8,8,1
+endm
+localT macro n
+?aloc <n>,<tbyte ptr>,10,10,1
+endm
+if sizec
+localCP macro n
+localD <n>
+endm
+else
+localCP macro n
+localW <n>
+endm
+endif
+if sized
+localDP macro n
+localD <n>
+endm
+else
+localDP macro n
+localW <n>
+endm
+endif
+localV macro n,a
+?aloc <n>,,%(a),0,1
+endm
+?aloc macro n,t,l,s,a
+if ?cpd
+.xcref
+irp x,<n>
+???=???+l
+if a
+???=((??? + 1) and 0fffeh)
+endif
+?al1 x,<t>,%(???+?ia)
+.xcref ?t&&x
+?t&&x=s
+endm
+.cref
+else
+??error <locals "&n" declared outside procedure def>
+endif
+endm
+?al1 macro n,t,o
+n equ (t [bp-o])
+endm
+?gcc macro s,i,cc
+s = i
+ifnb <cc>
+ifidn <cc>,<C>
+s=0
+endif
+ifidn <cc>,<PLM>
+s=1
+endif
+ifidn <cc>,<PASCAL>
+s=1
+endif
+endif
+endm
+ifndef ?NOGLOBAL
+.xcref
+.xcref globalB,globalW,globalD,globalQ,globalT,globalCP,globalDP
+.cref
+globalB macro n,i,s,c
+?ad <n>,1
+?dd n,1,<byte>,<db>,<i>,<s>,<c>
+endm
+globalW macro n,i,s,c
+?ad <n>,2
+?dd n,1,<word>,<dw>,<i>,<s>,<c>
+endm
+globalD macro n,i,s,c
+?ad <n>,4
+?dd n,1,<dword>,<dd>,<i>,<s>,<c>
+off_&n equ n
+seg_&n equ n[2]
+endm
+globalQ macro n,i,s,c
+?ad <n>,8
+?dd n,1,<qword>,<dq>,<i>,<s>,<c>
+endm
+globalT macro n,i,s,c
+?ad <n>,10
+?dd n,1,<tbyte>,<dt>,<i>,<s>,<c>
+endm
+if sizec
+globalCP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalCP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+if sized
+globalDP macro n,i,s,c
+globalD n,<i>,<s>,<c>
+endm
+else
+globalDP macro n,i,s,c
+globalW n,<i>,<s>,<c>
+endm
+endif
+endif
+ifndef ?NOSTATIC
+.xcref
+.xcref staticB,staticW,staticD,staticQ,staticT,staticCP,staticDP
+.cref
+staticB macro n,i,s
+?ad <n>,1
+?dd n,0,<byte>,<db>,<i>,<s>,<PLM>
+endm
+staticW macro n,i,s
+?ad <n>,2
+?dd n,0,<word>,<dw>,<i>,<s>,<PLM>
+endm
+staticD macro n,i,s
+?ad <n>,4
+?dd n,0,<dword>,<dd>,<i>,<s>,<PLM>
+endm
+staticQ macro n,i,s
+?ad <n>,8
+?dd n,0,<qword>,<dq>,<i>,<s>,<PLM>
+endm
+staticT macro n,i,s
+?ad <n>,10
+?dd n,0,<tbyte>,<dt>,<i>,<s>,<PLM>
+endm
+if sizec
+staticCP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticCP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+if sized
+staticDP macro n,i,s
+staticD n,<i>,<s>
+endm
+else
+staticDP macro n,i,s
+staticW n,<i>,<s>
+endm
+endif
+endif
+?dd macro n,p,t,d,i,s,c
+?gcc ?dd2,%?PLM,<c>
+ife ?dd2
+n label t
+?dd1 _&n,p,<d>,<i>,<s>
+else
+?dd1 n,p,<d>,<i>,<s>
+endif
+endm
+?dd1 macro n,p,d,i,s
+if p
+public n
+endif
+ifb <s>
+n d i
+else
+ifb <i>
+n d s dup (?)
+else
+n d s dup (i)
+endif
+endif
+endm
+ifndef ?NOEXTERN
+.xcref
+.xcref ?ex1,?ex2,externB,externW,externD,externQ,externT
+.xcref externNP,externFP,externP,externCP,externDP,externA
+.cref
+?ex2 = 0
+externA macro n,c
+?ex1 <n>,40h,<abs>,<c>,<>
+endm
+externB macro n,c
+?ex1 <n>,1,<byte>,<c>,<>
+endm
+externW macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+externD macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+externQ macro n,c
+?ex1 <n>,8,<qword>,<c>,<>
+endm
+externT macro n,c
+?ex1 <n>,10,<tbyte>,<c>,<>
+endm
+externNP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+externFP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+if sizec
+externP macro n,c
+?ex1 <n>,4,<far>,<c>,<cc>
+endm
+else
+externP macro n,c
+?ex1 <n>,2,<near>,<c>,<cc>
+endm
+endif
+if sizec
+externCP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externCP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+if sized
+externDP macro n,c
+?ex1 <n>,4,<dword>,<c>,<>
+endm
+else
+externDP macro n,c
+?ex1 <n>,2,<word>,<c>,<>
+endm
+endif
+?ex1 macro n,s,d,c,scv
+?gcc ?ex2,%?PLM,<c>
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?ex2
+extrn _&&x:&d
+x equ _&&x
+else
+extrn x:&d
+endif
+ifidn <scv>,<cc>
+.xcref
+.xcref ?CC&&x
+.cref
+?CC&&x=?ex2
+endif
+endm
+endm
+endif
+ifndef ?NOLABEL
+.xcref
+.xcref ?lb1,?lblpu,?lb2
+.xcref labelB,labelW,labelD,labelQ,labelT
+.xcref labelNP,labelFP,labelP,labelCP,labelDP
+.cref
+?lblpu = 0
+?lb2 = 0
+labelB macro n,c
+?lb1 <n>,1,<byte>,<c>
+endm
+labelW macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+labelD macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+labelQ macro n,c
+?lb1 <n>,8,<qword>,<c>
+endm
+labelT macro n,c
+?lb1 <n>,10,<tbyte>,<c>
+endm
+labelNP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+labelFP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+if sizec
+labelP macro n,c
+?lb1 <n>,4,<far>,<c>
+endm
+else
+labelP macro n,c
+?lb1 <n>,2,<near>,<c>
+endm
+endif
+if sizec
+labelCP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelCP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+if sized
+labelDP macro n,c
+?lb1 <n>,4,<dword>,<c>
+endm
+else
+labelDP macro n,c
+?lb1 <n>,2,<word>,<c>
+endm
+endif
+?lb1 macro n,s,d,c
+?gcc ?lb2,%?PLM,<c>
+?lblpu=0
+irp x,<n>
+ifidn <x>,<PUBLIC>
+?lblpu=1
+else
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+ife ?lb2
+if ?lblpu
+public _&&x
+endif
+_&&x label &d
+x equ _&&x
+else
+if ?lblpu
+public x
+endif
+x label &d
+endif
+endif
+endm
+endm
+endif
+ifndef ?NODEF
+.xcref
+.xcref defB,defW,defD,defQ,defT,defCP,defDP
+.cref
+defB macro n
+?ad <n>,1
+endm
+defW macro n
+?ad <n>,2
+endm
+defD macro n
+?ad <n>,4
+endm
+defQ macro n
+?ad <n>,8
+endm
+defT macro n
+?ad <n>,10
+endm
+if sizec
+defCP macro n
+defD <n>
+endm
+else
+defCP macro n
+defW <n>
+endm
+endif
+if sized
+defDP macro n
+defD <n>
+endm
+else
+defDP macro n
+defW <n>
+endm
+endif
+endif
+?ad macro n,s
+irp x,<n>
+.xcref
+.xcref ?t&&x
+.cref
+?t&&x=s
+endm
+endm
+ifndef ?NOPTR
+.xcref
+.xcref regPtr,farPtr
+.cref
+regPtr macro n,s,o
+farPtr n,s,o
+endm
+farPtr macro n,s,o
+.xcref
+.xcref ?t&n
+.cref
+n &macro
+ push s
+ push o
+&endm
+?t&n=80h
+endm
+endif
+arg macro a
+irp x,<a>
+?argc=?argc+1
+?atal <x>,%?argc
+endm
+endm
+?atal macro n,i
+.xcref
+.xcref ?ali&i
+.cref
+?ali&i &macro
+?ap n
+&endm
+endm
+?ap macro n
+?argl=?argl+2
+ifdef ?t&n
+ife ?t&n-1
+ push word ptr (n)
+exitm
+endif
+ife ?t&n-2
+ push n
+exitm
+endif
+ife ?t&n-4
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+2
+exitm
+endif
+ife ?t&n-8
+ push word ptr (n)[6]
+ push word ptr (n)[4]
+ push word ptr (n)[2]
+ push word ptr (n)
+?argl=?argl+6
+exitm
+endif
+if ?t&n and 80h
+n
+?argl=?argl+2
+exitm
+endif
+ife ?t&n
+ push word ptr (n)
+exitm
+endif
+endif
+ push n
+endm
+cCall macro n,a,c
+ifnb <a>
+arg <a>
+endif
+mpush %?rsl
+ifdef ?CC&n
+?cCall1=?CC&n
+else
+?cCall1=?PLM
+endif
+ifnb <c>
+?gcc ?cCall1,%?cCall1,<c>
+endif
+?argl=0
+ife ?cCall1
+?acb=?argc
+else
+?acb=1
+endif
+rept ?argc
+uconcat <?ali>,%?acb
+uconcat <purge>,,<?ali>,%?acb
+ife ?cCall1
+?acb=?acb-1
+else
+?acb=?acb+1
+endif
+endm
+ call n
+if ((?cCall1 eq 0) and (?argl ne 0))
+ add sp,?argl
+endif
+mpop %?rsl
+?rsl=0
+?argc= 0
+?argl= 0
+endm
+cProc macro n,cf,a
+if ?cpd
+?utpe
+endif
+?cpd=1
+???=0
+?argc=0
+?ba=0
+?po=0
+?pu=0
+?ia=0
+?adj=4
+?rp=0
+?uf=0
+?wfp=?WIN
+?ff=0
+?pas=0
+?pcc=?PLM
+ifnb <a>
+?ri ?pas,<a>
+endif
+?pc=sizec
+?nd=?nodata1
+?nx=0
+irp x,<cf>
+ifidn <x>,<FAR>
+?pc=1
+endif
+ifidn <x>,<NEAR>
+?pc=0
+endif
+ifidn <x>,<PUBLIC>
+?pu=1
+endif
+ifidn <x>,<SMALL>
+?uf=1
+endif
+ifidn <x>,<DATA>
+?nd=0
+endif
+ifidn <x>,<NODATA>
+?nd=1
+endif
+ifidn <x>,<ATOMIC>
+?nx=1
+endif
+ifidn <x>,<C>
+?pcc=0
+endif
+ifidn <x>,<PLM>
+?pcc=1
+endif
+ifidn <x>,<PASCAL>
+?pcc=1
+endif
+ifidn <x>,<WIN>
+?wfp=1
+endif
+ifidn <x>,<NONWIN>
+?wfp=0
+endif
+endm
+if ?pcc
+?PLMPrevParm=0
+.xcref
+.xcref ?PLMParm0
+.cref
+?PLMParm0 &macro
+purge ?PLMParm0
+&endm
+endif
+.xcref
+.xcref ?CC&n
+.cref
+?CC&n=?pcc
+if (?nx eq 1) and (?nd eq 0)
+?nx = 0
+??error <ATOMIC specified without NODATA - ATOMIC ignored>
+endif
+if ?pc
+if ?wfp
+ife ?nx
+?ia=2
+?pas = ?pas and (not ?ds)
+endif
+endif
+?adj=?adj+2
+else
+?wfp=0
+endif
+?pas = ?pas and (not (?sp+?cs+?ss))
+if ?uf
+?pas = ?pas and (not (?bp+?si+?di))
+endif
+ife ?pcc
+?pg <_&n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+else
+?pg <n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
+endif
+endm
+?pg macro n,p,c,a,w,nnu,cc
+.xcref
+if ?uf
+if ?nd
+??error <NODATA encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+.xcref cBegin
+cBegin &macro g
+.xcref
+if cc
+uconcat <?PLMParm>,%?PLMPrevParm,%?po
+endif
+if ?uf
+if ?rp
+??error <parmR encountered in &n - user frame ignored>
+?uf=0
+endif
+endif
+?pg1 <n>,c,a,%?po,w,%?uf,%?nd,%?rp,cc
+?cpd=0
+?argc=0
+?ba=1
+???=(???+1) and 0fffeh
+if p
+public n
+endif
+ife c
+n proc near
+else
+n proc far
+endif
+ife cc
+nnu equ n
+endif
+ifidn <g>,<nogen>
+if ???+?po+a+?rp
+??_out <cBegin - possible invalid use of nogen>
+endif
+else
+if ?uf
+?mf c,%???,%?po
+mpush a
+else
+if w
+ife ?nd
+ mov ax,ds
+ nop
+endif
+ife ?nx
+ife ?DOS5
+ inc bp
+endif
+ push bp
+ mov bp,sp
+ push ds
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+ife ?nd
+ mov ds,ax
+endif
+else
+if ?ff+???+?po+?rp
+ push bp
+ mov bp,sp
+endif
+endif
+if ?rp
+?uf=0
+rept ?rp
+uconcat mpush,,?rp,%?uf
+?uf=?uf+1
+endm
+endif
+if ???
+if ?chkstk1
+ifdef ?CHKSTKPROC
+?CHKSTKPROC %???
+else
+ mov ax,???
+ife cc
+ call _chkstk
+else
+ call chkstk
+endif
+endif
+else
+ sub sp,???
+endif
+endif
+mpush a
+endif
+ifdef ?PROFILE
+if c
+ call StartNMeas
+endif
+endif
+endif
+.cref
+purge cBegin
+&endm
+.xcref ?utpe
+?utpe &macro
+??error <unterminated procedure definition: "&n">
+&endm
+.cref
+endm
+?pg1 macro n,c,a,o,w,f,d,r,cc
+.xcref
+.xcref cEnd
+cEnd &macro g
+.xcref
+?ba=0
+ifidn <g>,<nogen>
+if o+a+r
+??_out <cEnd - possible invalid use of nogen>
+endif
+else
+ifdef ?PROFILE
+if c
+call StopNMeas
+endif
+endif
+mpop a
+if f
+ db 0c3h
+else
+if w
+ife ?nx
+if (?TF eq 0) or (???+?rp)
+ lea sp,-2[bp]
+endif
+ pop ds
+ pop bp
+ife ?DOS5
+ dec bp
+endif
+else
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+if ???+?po+?rp
+ pop bp
+endif
+endif
+else
+if ?ff+???+?po+?rp
+if (?TF eq 0) or (???+?rp)
+ mov sp,bp
+endif
+ pop bp
+endif
+endif
+ife cc
+ ret
+else
+ ret o
+endif
+endif
+endif
+n endp
+.cref
+purge cEnd
+&endm
+.cref
+endm
+assumes macro s,ln
+ifndef ln&_assumes
+assume s:ln
+else
+ln&_assumes s
+endif
+endm
+createSeg macro n,ln,a,co,cl,grp
+ifnb <grp>
+addseg grp,n
+else
+ln&OFFSET equ offset n:
+ln&BASE equ n
+?cs3 <ln>,<n>
+endif
+ifnb <cl>
+n segment a co '&cl'
+else
+n segment a co
+endif
+n ends
+?cs1 <ln>,<n>
+endm
+addseg macro grp,seg
+.xcref
+.xcref grp&_def
+.cref
+ifndef grp&_def
+grp&_def=0
+endif
+if grp&_def ne ASMpass
+.xcref
+.xcref grp&_add
+.cref
+grp&_add &macro s
+grp&_in <seg>,s
+&endm
+.xcref
+.xcref grp&_in
+.cref
+grp&_in &macro sl,s
+ifb <s>
+grp group sl
+else
+grp&_add &macro ns
+grp&_in <sl,s>,ns
+&endm
+endif
+&endm
+grp&_def=ASMpass
+else
+grp&_add seg
+endif
+endm
+defgrp macro grp,ln
+addseg grp
+ifnb <ln>
+irp x,<ln>
+?cs3 <&x>,<grp>
+x&&OFFSET equ offset grp:
+x&&BASE equ grp
+endm
+endif
+endm
+?cs1 macro ln,n
+.xcref
+.xcref ln&_sbegin
+.cref
+ln&_sbegin &macro
+.xcref
+.xcref ?mf
+.cref
+?mf &&macro c,l,p
+if c
+ extrn n&_FARFRAME:near
+ call n&_FARFRAME
+else
+ extrn n&_NEARFRAME:near
+ call n&_NEARFRAME
+endif
+ db l shr 1
+ db p shr 1
+&&endm
+?cs2 <ln>,<n>
+n segment
+&endm
+endm
+?cs2 macro ln,n
+.xcref
+.xcref sEnd
+.cref
+sEnd &macro
+n ends
+purge ?mf
+purge sEnd
+&endm
+endm
+?cs3 macro ln,n
+.xcref
+.xcref ln&_assumes
+.cref
+ln&_assumes &macro s
+assume s:&n
+&endm
+endm
+.xcref
+.xcref sBegin
+.cref
+sBegin macro ln
+ln&_sbegin
+endm
+ife ?DF
+createSeg UTIL_TEXT,Code,word,public,CODE
+ife ?nodata1
+createSeg _DATA,Data,word,public,DATA,DGROUP
+defgrp DGROUP,Data
+endif
+if ?chkstk1
+ifndef ?CHKSTKPROC
+externp <chkstk>
+endif
+endif
+endif
+errnz macro x
+if2
+if x
+errnz1 <x>,%(x)
+endif
+endif
+endm
+errnz1 macro x1,x2
+= *errnz* x1 = x2
+.err
+endm
+errn$ macro l,x
+errnz <offset $ - offset l x>
+endm
+ifdef ?PROFILE
+externFP <StartNMeas,StopNMeas>
+endif
diff --git a/private/mvdm/wow16/write/cmd.c b/private/mvdm/wow16/write/cmd.c
new file mode 100644
index 000000000..a6151ab14
--- /dev/null
+++ b/private/mvdm/wow16/write/cmd.c
@@ -0,0 +1,718 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* cmd.c -- key handling for WRITE */
+
+#define NOCTLMGR
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOHDC
+#define NOBRUSH
+#define NOPEN
+#define NOFONT
+#define NOWNDCLASS
+#define NOCOMM
+#define NOSOUND
+#define NORESOURCE
+#define NOOPENFILE
+#define NOWH
+#define NOCOLOR
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "code.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "debug.h"
+#include "fmtdefs.h"
+#include "winddefs.h"
+#include "propdefs.h"
+#include "wwdefs.h"
+#include "menudefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifdef KOREA
+#include <ime.h>
+#endif
+
+int vfAltKey;
+extern int vfPictSel;
+extern int vfCommandKey;
+extern int vfShiftKey;
+extern int vfGotoKeyMode;
+extern int vfInsertOn;
+extern struct WWD rgwwd[];
+extern struct SEL selCur; /* Current selection (i.e., sel in current ww) */
+extern int vkMinus;
+
+int fnCutEdit();
+int fnCopyEdit();
+int fnPasteEdit();
+int fnUndoEdit();
+
+
+FCheckToggleKeyMessage( pmsg )
+register MSG *pmsg;
+{ /* If the passed message is an up- or down- transition of a
+ keyboard toggle key (e.g. shift), update our global flags & return
+ TRUE; if not, return FALSE */
+
+ switch ( pmsg->message ) {
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ switch( pmsg->wParam ) {
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ SetShiftFlags();
+ return TRUE;
+
+#if 0
+ #ifdef DEBUG
+ default:
+ {
+ char msg[100];
+ wsprintf(msg,"%s\t0x%x\n\r",(LPSTR)((pmsg->message == WM_KEYDOWN) ?
+ "keydown" : "keyup"), pmsg->wParam);
+ OutputDebugString(msg);
+ }
+ #endif
+#endif
+ }
+ }
+return FALSE;
+}
+
+
+
+
+SetShiftFlags()
+{
+extern int vfShiftKey; /* Whether shift is down */
+extern int vfCommandKey; /* Whether ctrl key is down */
+
+MSG msg;
+
+PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
+
+vfShiftKey = GetKeyState( VK_SHIFT ) < 0;
+vfCommandKey = GetKeyState( VK_CONTROL ) < 0;
+vfAltKey = GetKeyState( VK_MENU ) < 0;
+#if 0
+#ifdef DEBUG
+{
+ char msg[100];
+ wsprintf(msg,"%s\t%s\t%s\n\r",
+ (LPSTR)(vfShiftKey ? "Shift":"OFF"),
+ (LPSTR)(vfCommandKey ? "Control":"OFF"),
+ (LPSTR)(vfAltKey ? "Alt":"OFF"));
+ OutputDebugString(msg);
+}
+#endif
+#endif
+}
+
+
+
+
+KcAlphaKeyMessage( pmsg )
+register MSG *pmsg;
+{ /* If the passed message is a key-down transition for a key
+ that is processed by the Alpha Mode loop, return a kc
+ code for it. If not, return kcNil.
+ If the key is a virtual key that must be translated,
+ return kcAlphaVirtual */
+ int kc;
+
+
+ if (pmsg->hwnd != wwdCurrentDoc.wwptr)
+ return kcNil;
+
+ kc = pmsg->wParam;
+ switch (pmsg->message) {
+ default:
+ break;
+ case WM_KEYDOWN:
+#ifdef DINPUT
+ { char rgch[100];
+ wsprintf(rgch," KcAlphaKeyMessage(WM_KEYDOWN) kc=pmsg->wParam==%X\n\r",kc);
+ CommSz(rgch);
+ }
+#endif
+
+ if (vfAltKey)
+ return kcAlphaVirtual;
+
+ if (vfCommandKey)
+ { /* Alpha mode control keys */
+ if (vfShiftKey && kc == (kkNonReqHyphen & ~wKcCommandMask))
+ return kcNonReqHyphen;
+ else if (kc == (kksPageBreak & ~wKcCommandMask))
+ return KcFromKks( kksPageBreak );
+ }
+
+ else
+ { /* There are two classes of Alpha Mode virtual keys:
+ (1) Keys that can successfully be filtered out
+ and processed at the virtual key level
+ (2) Keys that must be translated first
+
+ We assume here that there is NOT a third class of key
+ that will cause synchronous messages to be sent to our
+ window proc when TranslateMessage is called. */
+
+ switch (kc) {
+ default:
+ return kcAlphaVirtual;
+
+ case VK_F1: /* THIS IS A COPY OF THE ACCELERATOR TABLE, */
+ /* AND MUST BE UPDATED IN SYNC WITH THE TABLE */
+ case VK_F2:
+ case VK_F3:
+ case VK_F4:
+ case VK_F5:
+ case VK_F6:
+ case VK_F7:
+ case VK_F8:
+ return kcNil;
+
+ case kcDelNext & ~wKcCommandMask:
+ /* If selection, return kcNil, else return kcDelNext */
+ return (selCur.cpFirst < selCur.cpLim) ? kcNil : kcDelNext;
+
+ case kcDelPrev & ~wKcCommandMask:
+ /* New standard for Win 3.0... Backspace key deletes
+ the selection if there is one (implemented by faking
+ a Delete keypress) ..pault 6/20/89 */
+ if (selCur.cpFirst < selCur.cpLim)
+ {
+ pmsg->wParam = (kcDelNext & ~wKcCommandMask);
+ return(kcNil);
+ }
+ /* else process as before... */
+
+ case kcTab & ~wKcCommandMask:
+ case kcReturn & ~wKcCommandMask:
+ return kc | wKcCommandMask;
+ }
+ }
+ break;
+
+#ifdef KOREA /* interim support by sangl 90.12.23 */
+ case WM_INTERIM:
+#endif
+ case WM_CHAR:
+#ifdef DINPUT
+ { char rgch[100];
+ wsprintf(rgch," KcAlphaKeyMessage(WM_CHAR) returning kc==%X\n\r",kc);
+ CommSz(rgch);
+ }
+#endif
+#ifdef PRINTMERGE
+ if (kc < ' ')
+ /* CTRL-key. The print merge brackets are treated as commands,
+ since they require special handling in AlphaMode().
+ All others are directly inserted. */
+ switch ( kc ) {
+ case kcLFld & ~wKcCommandMask:
+ case kcRFld & ~wKcCommandMask:
+ kc |= wKcCommandMask;
+ break;
+ }
+#endif
+ return kc;
+ } /* end switch (msg.message) */
+
+#ifdef DINPUT
+ CommSz(" KcAlphaKeyMessage(not WM_CHAR or WM_KEYDOWN) returning kc==kcNil"));
+#endif
+ return kcNil;
+}
+#ifdef KOREA
+CHAR chDelete;
+typeCP cpConversion;
+extern int docCur;
+extern CHAR *vpchFetch;
+extern int IsInterim;
+extern typeCP cpMacCur;
+#endif
+
+
+
+
+FNonAlphaKeyMessage( pmsg, fAct )
+register MSG *pmsg;
+int fAct; /* Whether to act on the passed key */
+{
+extern HMENU vhMenu;
+extern HWND hParentWw;
+int kc;
+int message;
+
+
+ if (pmsg->hwnd != wwdCurrentDoc.wwptr)
+ return FALSE;
+
+ message = pmsg->message;
+ kc = pmsg->wParam | wKcCommandMask;
+
+ /* Check for Alt-Bksp */
+ if ((message == WM_SYSKEYDOWN) && (kc == (VK_BACK | wKcCommandMask)))
+ /* Alt-Backspace = UNDO */
+ {
+ if (fAct)
+ PhonyMenuAccelerator( EDIT, imiUndo, fnUndoEdit );
+ return TRUE;
+ }
+
+ /* Only look at key down messages */
+
+ if (message != WM_KEYDOWN)
+ return FALSE;
+
+#ifdef DINPUT
+ { char rgch[100];
+ wsprintf(rgch," FNonAlphaKeyMessage(keydown) kc==%X\n\r",kc);
+ CommSz(rgch);
+ }
+#endif
+
+ /* Translate CTRL keys by mapping valid kk & kks codes to valid kc codes */
+
+ if ( vfCommandKey )
+ {
+ if (vfShiftKey)
+ switch ( kc ) { /* Handle CTRL-SHIFT keys */
+ default:
+ goto CtrlKey;
+#if 0
+#ifdef DEBUG
+ case kksTest:
+ case kksEatWinMemory:
+ case kksFreeWinMemory:
+ case kksEatMemory:
+ case kksFreeMemory:
+ kc = KcFromKks( kc );
+ break;
+#endif
+#endif
+ }
+ else /* Handle CTRL keys */
+ {
+CtrlKey:
+ switch ( kc ) {
+ case kkUpScrollLock:
+ case kkDownScrollLock:
+ case kkTopDoc:
+ case kkEndDoc:
+ case kkTopScreen:
+ case kkEndScreen:
+ case kkCopy:
+#ifdef CASHMERE /* These keys not supported by MEMO */
+ case kkNonReqHyphen:
+ case kkNonBrkSpace:
+ case kkNLEnter:
+#endif
+ case kkWordLeft:
+ case kkWordRight:
+ kc = KcFromKk( kc ); /* Translate control code */
+#ifdef DINPUT
+ { char rgch[100];
+ wsprintf(rgch," FNonAlphaKeyMessage, translated kc %X\n\r",kc);
+ CommSz(rgch);
+ }
+#endif
+ break;
+
+ default:
+#ifdef DINPUT
+ CommSz(" FNonAlphaKeyMessage returning false, nonsupported kc\n\r");
+#endif
+ return FALSE;
+ }
+ }
+ } /* end of if (vfCommandKey) */
+
+
+ /* Act on valid kc codes */
+
+#ifdef DINPUT
+ CommSz(" FNonAlphaKeyMessage processing valid kc codes\n\r");
+#endif
+ switch ( kc ) {
+ /* ---- CURSOR KEYS ---- */
+ case kcEndLine:
+ case kcBeginLine:
+ case kcLeft:
+ case kcRight:
+ case kcWordRight:
+ case kcWordLeft:
+ if (fAct)
+ {
+ ClearInsertLine();
+ MoveLeftRight( kc );
+ }
+ break;
+
+ case kcUp:
+ case kcDown:
+ case kcUpScrollLock:
+ case kcDownScrollLock:
+ case kcPageUp:
+ case kcPageDown:
+ case kcTopDoc:
+ case kcEndDoc:
+ case kcEndScreen:
+ case kcTopScreen:
+ if (fAct)
+ {
+ ClearInsertLine();
+ MoveUpDown( kc );
+ }
+ break;
+
+ case kcGoto: /* Modifies next cursor key */
+ if (!fAct)
+ break;
+ vfGotoKeyMode = true;
+ goto NoClearGoto;
+
+ /* Phony Menu Accelerator Keys */
+
+ case kcNewUndo:
+ {
+ if (fAct)
+ PhonyMenuAccelerator( EDIT, imiUndo, fnUndoEdit );
+ return TRUE;
+ }
+
+ case kcCopy:
+ case kcNewCopy:
+ if (fAct)
+ PhonyMenuAccelerator( EDIT, imiCopy, fnCopyEdit );
+ break;
+
+ case kcNewPaste:
+ case VK_INSERT | wKcCommandMask:
+ if (fAct && (vfShiftKey || (kc == kcNewPaste)))
+ {
+#if defined(OLE)
+ vbObjLinkOnly = FALSE;
+#endif
+ PhonyMenuAccelerator( EDIT, imiPaste, fnPasteEdit );
+ }
+ break;
+
+ case kcNewCut:
+ case VK_DELETE | wKcCommandMask:
+ if (vfShiftKey || (kc == kcNewCut))
+ { /* SHIFT-DELETE = Cut */
+ if (fAct)
+ PhonyMenuAccelerator( EDIT, imiCut, fnCutEdit );
+ }
+ else
+ { /* DELETE = Clear */
+ if (fAct)
+ fnClearEdit(FALSE);
+ }
+ break;
+
+ case VK_ESCAPE | wKcCommandMask:
+ /* The ESC key does: if editing a running head or foot, return to doc
+ else beep */
+ if (!fAct)
+ break;
+
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ { /* Return to document from editing header/footer */
+ extern HWND vhDlgRunning;
+
+ SendMessage( vhDlgRunning, WM_CLOSE, 0, (LONG) 0 );
+ return TRUE;
+ }
+ else
+ _beep();
+ break;
+
+#ifdef KOREA
+ case VK_HANJA | wKcCommandMask:
+
+ if(IsInterim) break;
+
+ if (selCur.cpFirst == cpMacCur) {
+ _beep();
+ break;
+ }
+ cpConversion = selCur.cpFirst;
+ FetchCp( docCur, cpConversion, 0, fcmChars );
+ chDelete = *vpchFetch;
+ { HANDLE hKs;
+ LPIMESTRUCT lpKs;
+ LPSTR lp;
+
+ hKs = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE,(LONG)sizeof(IMESTRUCT));
+ lpKs = (LPIMESTRUCT)GlobalLock(hKs);
+ lpKs->fnc = IME_HANJAMODE;
+ lpKs->wParam = IME_REQUEST_CONVERT;
+ lpKs->dchSource = (WORD)( &(lpKs->lParam1) );
+ lp = lpSource( lpKs );
+ *lp++ = *vpchFetch++;
+ *lp++ = *vpchFetch;
+ *lp++ = '\0';
+ GlobalUnlock(hKs);
+ if(SendIMEMessage (hParentWw, MAKELONG(hKs,0)))
+ selCur.cpLim = selCur.cpFirst + 2;
+
+ GlobalFree(hKs);
+ }
+ break;
+#endif /* KOREA */
+
+#if 0
+#ifdef DEBUG
+ case kcEatWinMemory:
+ if (!fAct)
+ break;
+ CmdEatWinMemory();
+ break;
+ case kcFreeWinMemory:
+ if (!fAct)
+ break;
+ CmdFreeWinMemory();
+ break;
+ case kcEatMemory:
+ {
+ if (!fAct)
+ break;
+ CmdEatMemory();
+ break;
+ }
+ case kcFreeMemory:
+ if (!fAct)
+ break;
+ CmdFreeMemory();
+ break;
+ case kcTest:
+ if (!fAct)
+ break;
+ fnTest();
+ break;
+#endif
+#endif
+ default:
+ return FALSE;
+ } /* end of switch (kc) */
+
+ vfGotoKeyMode = false;
+NoClearGoto:
+ return TRUE;
+}
+
+
+
+
+
+#ifdef DEBUG
+ScribbleHex( dch, wHex, cDigits )
+int dch; /* Screen position at which to show Last digit (see fnScribble) */
+unsigned wHex; /* hex # to show*/
+int cDigits; /* # of digits to show */
+{
+ extern fnScribble( int dchPos, CHAR ch );
+
+ for ( ; cDigits--; wHex >>= 4 )
+ {
+ int i=wHex & 0x0F;
+
+ fnScribble( dch++, (i >= 0x0A) ? i + ('A' - 0x0A) : i + '0' );
+ }
+}
+#endif /* DEBUG */
+
+
+
+
+
+
+#ifdef DEBUG
+#ifdef OURHEAP
+CHAR (**vhrgbDebug)[] = 0;
+int vrgbSize = 0;
+#else
+#define iHandleMax 100
+HANDLE rgHandle[ iHandleMax ];
+int iHandleMac;
+unsigned cwEaten = 0;
+#endif
+
+CmdEatMemory()
+{ /* For debugging purposes, eat up memory */
+#ifdef OURHEAP /* Restore this with a LocalCompact when are
+ operational under the Windows heap */
+int **HAllocate();
+int cwEat = cwHeapFree > 208 ? cwHeapFree - 208 : 20;
+
+if (vrgbSize == 0)
+ vhrgbDebug = (CHAR (**)[])HAllocate(cwEat);
+else
+ FChngSizeH(vhrgbDebug, cwEat + vrgbSize, true);
+vrgbSize += cwEat;
+CmdShowMemory();
+#endif /* OURHEAP */
+}
+
+CmdFreeMemory()
+{ /* Free up the memory we stole */
+#ifdef OURHEAP
+if (vhrgbDebug != 0)
+ FreeH(vhrgbDebug);
+vhrgbDebug = (CHAR (**)[]) 0;
+vrgbSize = 0;
+CmdShowMemory();
+#endif
+}
+
+extern CHAR szMode[];
+extern int docMode;
+extern int vfSizeMode;
+
+#ifdef OURHEAP
+CmdShowMemory()
+#else
+CmdShowMemory(cw)
+int cw;
+#endif
+{
+
+extern CHAR szFree[];
+
+CHAR *pch = szMode;
+
+#ifdef OURHEAP
+/* cch = */ ncvtu( cwHeapFree, &pch );
+#else
+ncvtu(cw, &pch);
+#endif
+
+blt( szFree, pch, CchSz( szFree ));
+vfSizeMode = true;
+/* docMode = -1; */
+DrawMode();
+}
+
+
+
+
+CmdEatWinMemory()
+{
+#ifndef OURHEAP
+unsigned cwEat;
+int cPage;
+int fThrowPage = TRUE;
+
+extern int cPageMinReq;
+extern int ibpMax;
+
+while (true)
+ {
+ while ((cwEat = ((unsigned)LocalCompact((WORD)0) / sizeof(int))) > 0 &&
+ iHandleMac < iHandleMax)
+ {
+ if ((rgHandle [iHandleMac] = (HANDLE)HAllocate(cwEat)) == hOverflow)
+ goto AllocFail;
+ else
+ {
+ ++iHandleMac;
+ cwEaten += cwEat;
+ CmdShowMemory(cwEaten);
+ }
+
+ if (iHandleMac >= iHandleMax)
+ goto AllocFail;
+
+ if ((rgHandle [iHandleMac] = (HANDLE)HAllocate(10)) == hOverflow)
+ goto AllocFail;
+ else
+ {
+ ++iHandleMac;
+ cwEaten += 10;
+ CmdShowMemory(cwEaten);
+ }
+ }
+
+ if (iHandleMac >= iHandleMax)
+ goto AllocFail;
+
+ cPage = cPageUnused();
+ Assert(cPage + 2 < ibpMax);
+ if (fThrowPage)
+ {
+ /* figure out how many bytes we need to invoke the situation
+ where we need to throw some pages out to get the space */
+ cwEat = ((cPage+2) * 128) / sizeof(int);
+ cPageMinReq = ibpMax - cPage - 2;
+ }
+ else
+ {
+ cwEat = ((cPage-2) * 128) / sizeof(int);
+ cPageMinReq = ibpMax - cPage;
+ }
+
+ if ((rgHandle[ iHandleMac++ ] = (HANDLE)HAllocate(cwEat)) == hOverflow)
+ {
+ iHandleMac--;
+ break;
+ }
+ cwEaten += cwEat;
+ CmdShowMemory(cwEaten);
+ }
+
+AllocFail: /* Allocation failed, or we ran out of slots */
+ CmdShowMemory( cwEaten );
+#endif
+}
+
+
+
+
+CmdFreeWinMemory()
+{
+#ifndef OURHEAP
+unsigned cwFree = 0;
+
+Assert(iHandleMac <= iHandleMax);
+
+while (iHandleMac > 0)
+ {
+ HANDLE h = rgHandle[ iHandleMac - 1];
+
+ if ( (h != NULL) && (h != hOverflow))
+ {
+ cwFree += (unsigned)LocalSize(h) / sizeof(int);
+ FreeH( h );
+ }
+ iHandleMac--;
+ }
+
+cwEaten = 0;
+CmdShowMemory(cwFree);
+#endif
+}
+#endif /* DEBUG */
diff --git a/private/mvdm/wow16/write/cmddefs.h b/private/mvdm/wow16/write/cmddefs.h
new file mode 100644
index 000000000..6c8cfca4d
--- /dev/null
+++ b/private/mvdm/wow16/write/cmddefs.h
@@ -0,0 +1,148 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define cchInsBlock 32 /* Length of quick insert block */
+
+struct SEL
+ {
+ typeCP cpFirst;
+ typeCP cpLim;
+ unsigned fForward : 1; /* Only needs 1 bit */
+ unsigned fEndOfLine : 1;
+ };
+
+#define cwSEL (sizeof (struct SEL) / sizeof (int))
+#define cbSEL (sizeof (struct SEL))
+
+#define styNil 0
+#define styChar 1
+#define styWord 2
+#define stySent 3
+#define styPara 4
+#define styLine 5
+#define styDoc 6
+
+#ifndef NOUAC
+/* UNDO Action Codes: */
+#define uacNil 0 /* Nothing to UNDO */
+#define uacInsert 1 /* Insert text <--> UInsert */
+#define uacReplNS 2 /* Replace text, no scrap <--> UReplNS */
+#define uacDelNS 3 /* Delete text, no scrap <--> UDelNS */
+#define uacMove 4 /* Move text <--> Move */
+#define uacDelScrap 5 /* Delete to scrap <--> UDelScrap */
+#define uacUDelScrap 6 /* Undo of Delete <--> DelScrap */
+#define uacReplScrap 7 /* Replace with del to scrap
+ <--> UReplScrap */
+#define uacUReplScrap 8 /* Undo of ReplScrap <--> ReplScrap */
+#define uacDelBuf 9 /* Delete to buffer <--> UDelBuf */
+#define uacUDelBuf 10 /* Undo of DelBuf <--> DelBuf */
+#define uacReplBuf 11 /* Replace with del to buf <--> UReplBuf */
+#define uacUReplBuf 12 /* Undo of ReplBuf <--> ReplBuf */
+#define uacCopyBuf 13 /* Copy to buf <--> UCopyBuf */
+#define uacUInsert 14 /* undo of Insert <--> Insert */
+#define uacUDelNS 15 /* undo of DelNS <--> DelNS */
+#define uacUReplNS 16 /* undo of ReplNS <--> ReplNS */
+#define uacUCopyBuf 17 /* Undo of CopyBuf <--> CopyBuf */
+#define uacReplGlobal 18
+#define uacFormatCStyle 19
+#define uacChLook 20
+#define uacChLookSect 21
+#define uacFormatChar 22
+#define uacFormatPara 23
+#define uacGalFormatChar 24
+#define uacGalFormatPara 25
+#define uacFormatSection 26
+#define uacGalFormatSection 27
+#define uacFormatPStyle 28
+#define uacFormatSStyle 29
+#define uacFormatRHText 30
+#define uacLookCharMouse 31
+#define uacLookParaMouse 32
+#define uacClearAllTab 33
+#define uacFormatTabs 34
+#define uacClearTab 35
+#define uacOvertype 36
+#define uacPictSel 37
+#define uacInsertFtn 38
+#define uacReplPic 39
+#define uacUReplPic 40
+
+#ifndef CASHMERE
+#define uacRulerChange 41
+#define uacRepaginate 42
+#endif /* not CASHMERE */
+#endif /* NOUAC */
+
+#if defined(OLE)
+#define uacObjUpdate 43
+#define uacUObjUpdate 44
+#endif
+
+/* Units */
+#define utInch 0
+#define utCm 1
+#define utP10 2
+#define utP12 3
+#define utPoint 4
+#define utLine 5
+#define utMax 6
+
+#define czaInch 1440
+#define czaP10 144
+#define czaPoint 20
+#define czaCm 567
+#define czaP12 120
+
+#define czaLine 240
+
+#define ZaFromMm(mm) (unsigned)MultDiv(mm, 14400, 254);
+
+#ifdef KOREA /* Dum Write doesn't accept it's default value!! 90.12.29 */
+#define FUserZaLessThanZa(zaUser, za) ((zaUser) + (7 * czaInch) / 1000 < (za))
+#else
+#define FUserZaLessThanZa(zaUser, za) ((zaUser) + (5 * czaInch) / 1000 < (za))
+#endif
+
+/* Modes -- see menu.mod */
+#define ifldEdit 0
+#define ifldGallery 1
+
+#define ecrSuccess 1
+#define ecrCancelled 2
+#define ecrMouseKilled 4
+
+typeCP CpFirstSty(), CpLastStyChar();
+
+#define psmNil 0
+#define psmCopy 1
+#define psmMove 2
+#define psmLookChar 3
+#define psmLookPara 4
+#define psmLooks 3
+
+#define crcAbort 0
+#define crcNo 1
+#define crcYes 2
+
+/* FWrite checks */
+#define fwcNil 0
+#define fwcInsert 1
+#define fwcDelete 2
+#define fwcReplace 3
+#define fwcEMarkOK 4 /* Additive -- must be a bit */
+
+/* Dialog item parsing variants */
+#define wNormal 0x1
+#define wBlank 0x2
+#ifdef AUTO_SPACING
+#define wAuto 0x4
+#endif /* AUTO_SPACING */
+#define wDouble 0x8
+ /* wSpaces means treat string of all spaces as a null string */
+#define wSpaces 0x10
+
+/* page bound */
+#define pgnMin 1
+#define pgnMax 32767
+
diff --git a/private/mvdm/wow16/write/code.h b/private/mvdm/wow16/write/code.h
new file mode 100644
index 000000000..39e57c7ab
--- /dev/null
+++ b/private/mvdm/wow16/write/code.h
@@ -0,0 +1,9 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* code.h */
+typedef struct {
+ int *fNew;
+ int bpc, cwFrame;
+} ENV;
diff --git a/private/mvdm/wow16/write/commdlg.c b/private/mvdm/wow16/write/commdlg.c
new file mode 100644
index 000000000..8051489da
--- /dev/null
+++ b/private/mvdm/wow16/write/commdlg.c
@@ -0,0 +1,420 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+#include <windows.h>
+#include "mw.h"
+#include "menudefs.h"
+#include "str.h"
+#include <commdlg.h>
+#include "filedefs.h"
+#include <dlgs.h>
+#include "doslib.h"
+#include "obj.h"
+
+extern HANDLE hMmwModInstance;
+extern CHAR szAppName[];
+extern HWND vhWndMsgBoxParent,hParentWw,vhWnd;
+static OPENFILENAME OFN;
+static bSave;
+FARPROC lpfnOFNHook=NULL;
+BOOL FAR PASCAL fnOFNHook(HWND hDlg, unsigned msg, WORD wParam, LONG lParam) ;
+
+#define hINSTANCE hMmwModInstance
+
+#define hDOCWINDOW vhWnd
+#define hMAINWINDOW hParentWw
+#define hPARENTWINDOW ((vhWndMsgBoxParent == NULL) ? \
+ hParentWw : vhWndMsgBoxParent)
+
+#define CBPATHMAX cchMaxFile
+#define CFILTERMAX 6 /* Max # filters */
+#define CBFILTERSIZE 40
+#define CBFILTERMAX (CBFILTERSIZE * CFILTERMAX) /* Max # chars/filter */
+#define CBMESSAGEMAX 80
+
+static char fDefFileType;
+#define SA_WORDTEXT 0
+#define SA_TEXTONLY 1
+#define SA_WORD 2
+#define SA_OLDWRITE 3
+#define SA_WRITE 4
+
+static char *szDefExtensions[6];
+static int nTextOnly,nWordText,nWord,nOldWrite; // position in filterspec list box
+static char szNull[1] = "";
+static char szWild[3] = "*.";
+static char szOpenFile[CBMESSAGEMAX];
+static char szSaveFile[CBMESSAGEMAX];
+static char szFileName[CBPATHMAX];
+static char szLastDir[CBPATHMAX];
+static char szDefWriExtension[CBMESSAGEMAX];
+static char szDefDocExtension[CBMESSAGEMAX];
+static char szDefTxtExtension[CBMESSAGEMAX];
+static char szWriDescr[CBMESSAGEMAX];
+static char szDocDescr[CBMESSAGEMAX];
+static char szTxtDescr[CBMESSAGEMAX];
+static char szAllFilesDescr[CBMESSAGEMAX];
+static char szDocTxtDescr[CBMESSAGEMAX];
+static char szOldWriteDescr[CBMESSAGEMAX];
+static char szFilterSpec[CBFILTERMAX];
+static char szCustFilterSpec[CBFILTERSIZE];
+
+static MakeFilterString(int iWhichOper);
+int InitCommDlg(int iWhichOper);
+
+int InitCommDlg(int iWhichOper)
+{
+ OFN.lpstrDefExt = NULL;
+ OFN.lpstrFile = szFileName;
+ OFN.lpstrFilter = szFilterSpec;
+ OFN.lpstrCustomFilter = szCustFilterSpec;
+
+ switch(iWhichOper)
+ {
+ case 0: // beginning of Write session
+ OFN.lStructSize = sizeof(OPENFILENAME);
+ OFN.hInstance = hINSTANCE;
+ OFN.lCustData = NULL;
+ OFN.lpTemplateName = NULL;
+ OFN.lpstrFileTitle = NULL;
+ OFN.nMaxFileTitle = 0;
+ OFN.nMaxFile = CBPATHMAX;
+ OFN.lpstrInitialDir = NULL;
+ OFN.nMaxCustFilter = CBFILTERSIZE;
+
+ LoadString(hINSTANCE, IDSTROpenfile, szOpenFile, sizeof(szOpenFile));
+ LoadString(hINSTANCE, IDSTRSavefile, szSaveFile, sizeof(szSaveFile));
+ LoadString(hINSTANCE, IDSTRDefWriExtension, szDefWriExtension, sizeof(szDefWriExtension));
+ LoadString(hINSTANCE, IDSTRDefDocExtension, szDefDocExtension, sizeof(szDefDocExtension));
+ LoadString(hINSTANCE, IDSTRDefTxtExtension, szDefTxtExtension, sizeof(szDefTxtExtension));
+ LoadString(hINSTANCE, IDSTRWriDescr, szWriDescr, sizeof(szWriDescr));
+ LoadString(hINSTANCE, IDSTRDocDescr, szDocDescr, sizeof(szDocDescr));
+ LoadString(hINSTANCE, IDSTRTxtDescr, szTxtDescr, sizeof(szTxtDescr));
+ LoadString(hINSTANCE, IDSTRDocTextDescr, szDocTxtDescr, sizeof(szDocTxtDescr));
+ LoadString(hINSTANCE, IDSTRAllFilesDescr, szAllFilesDescr, sizeof(szAllFilesDescr));
+ LoadString(hINSTANCE, IDSTROldWriteDescr, szOldWriteDescr, sizeof(szOldWriteDescr));
+
+ return FALSE;
+
+ case imiOpen:
+ if ((lpfnOFNHook = MakeProcInstance(fnOFNHook, hINSTANCE)) == NULL)
+ return TRUE;
+
+ OFN.hwndOwner = hPARENTWINDOW;
+ OFN.Flags = OFN_ENABLEHOOK|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
+ OFN.lpfnHook = lpfnOFNHook;
+ lstrcpy(szFileName,szWild);
+ lstrcat(szFileName,szDefWriExtension);
+ OFN.lpstrTitle = szOpenFile;
+ szCustFilterSpec[0] = '\0';
+
+ fDefFileType = SA_WRITE; /* see MakeFilterSpec */
+ MakeFilterString(iWhichOper);
+
+ return FALSE;
+
+ case imiSaveAs:
+ /* read only will become the backup check box */
+ if ((lpfnOFNHook = MakeProcInstance(fnOFNHook, hINSTANCE)) == NULL)
+ return TRUE;
+
+ OFN.hwndOwner = hPARENTWINDOW;
+ OFN.Flags = OFN_ENABLEHOOK|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
+ OFN.lpfnHook = lpfnOFNHook;
+ OFN.lpstrTitle = szSaveFile;
+ szCustFilterSpec[0] = '\0';
+ MakeFilterString(iWhichOper);
+
+ return FALSE;
+ }
+
+}
+
+int DoCommDlg(int iWhichOper)
+/* returns whether file was retrieved */
+/* iWhichOper is the imi* code from the menu */
+{
+ int iRetval;
+
+ bSave = iWhichOper == imiSaveAs;
+
+ iRetval = !InitCommDlg(iWhichOper);
+
+ if (!iRetval)
+ goto end;
+
+ LockData(0);
+ switch(iWhichOper)
+ {
+ case imiOpen:
+ iRetval = GetOpenFileName((LPOPENFILENAME)&OFN);
+ break;
+ case imiSaveAs:
+ iRetval = GetSaveFileName((LPOPENFILENAME)&OFN);
+ break;
+ }
+ UnlockData(0);
+
+ if (CommDlgExtendedError())
+ {
+ iRetval = FALSE;
+ Error(IDPMTNoMemory);
+ }
+
+ end:
+
+ if (iRetval)
+ {
+ lstrcpy(szLastDir,szFileName);
+ szLastDir[OFN.nFileOffset] = 0;
+ OFN.lpstrInitialDir = szLastDir;
+ }
+
+ switch(iWhichOper)
+ {
+ case imiOpen:
+ case imiSaveAs:
+ if (lpfnOFNHook)
+ FreeProcInstance(lpfnOFNHook);
+ lpfnOFNHook = NULL;
+ break;
+ }
+
+ return iRetval;
+}
+
+#include "docdefs.h"
+
+BOOL FAR PASCAL fnOFNHook(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ static unsigned wmListBoxChange;
+ static unsigned wmCheckShare;
+ extern int docCur;
+ extern struct DOD (**hpdocdod)[];
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (bSave)
+ {
+ char szTitle[CBMESSAGEMAX];
+
+ LoadString(hINSTANCE, IDSTRBackup, szTitle, sizeof(szTitle));
+ SetDlgItemText(hDlg,chx1,szTitle);
+
+ CheckDlgButton(hDlg,chx1,OFN.Flags&OFN_READONLY);
+ if (szFileName[0] == 0)
+ SetDlgItemText(hDlg,edt1,"");
+ }
+ else // open
+ wmCheckShare = RegisterWindowMessage(SHAREVISTRING);
+ wmListBoxChange = RegisterWindowMessage(LBSELCHSTRING);
+
+ break;
+
+ case WM_COMMAND:
+ if (bSave)
+ switch (wParam)
+ {
+ case chx1:
+ /* handle checking the readonly button (I forget what does this do??)
+ (we've changed readonly to be a "Backup" button) */
+ return TRUE;
+ break;
+ }
+ break;
+
+ default:
+ if ((msg == wmListBoxChange) && (wParam == cmb1))
+ /* file type selected, set the default extension */
+ OFN.lpstrDefExt = szDefExtensions[LOWORD(lParam)];
+ else if ((msg == wmCheckShare) && !bSave)
+ /* we want to be able to reopen current document */
+ {
+ if (!lstrcmpi((LPSTR)(**((**hpdocdod)[docCur].hszFile)),(LPSTR)lParam))
+ return OFN_SHAREFALLTHROUGH;
+ else
+ return OFN_SHAREWARN;
+ }
+ break;
+
+ }
+ return FALSE;
+}
+
+
+static MakeFilterString(int iWhichOper)
+/* Construct the filter string for the Open, Save dialogs */
+/* assume fDefFileType is set */
+{
+ LPSTR lpStr = szFilterSpec;
+ char **ppstr = szDefExtensions;
+ int nCount=1;
+
+ /* WRI */
+ lstrcpy(lpStr, szWriDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, szDefWriExtension);
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = szDefWriExtension;
+ ++nCount;
+
+ if (iWhichOper == imiSaveAs)
+ {
+ /* Old WRI (without objects) */
+ vcObjects = ObjEnumInDoc(docCur,NULL);
+
+ if (vcObjects > 0)
+ {
+ lstrcpy(lpStr, szOldWriteDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, szDefWriExtension);
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = szDefWriExtension;
+ nOldWrite = nCount;
+ ++nCount;
+ }
+ else if (fDefFileType == SA_OLDWRITE)
+ fDefFileType = SA_WRITE;
+ }
+
+ /* DOC */
+ lstrcpy(lpStr, szDocDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, szDefDocExtension);
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = szDefDocExtension;
+ nWord = nCount;
+ ++nCount;
+
+ /* DOC, Text only */
+ if (iWhichOper == imiSaveAs)
+ {
+ lstrcpy(lpStr, szDocTxtDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, szDefDocExtension);
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = szDefDocExtension;
+ nWordText = nCount;
+ ++nCount;
+ }
+
+ /* Text only */
+ lstrcpy(lpStr, szTxtDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, szDefTxtExtension);
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = szDefTxtExtension;
+ nTextOnly = nCount;
+ ++nCount;
+
+ /* All files */
+ lstrcpy(lpStr, szAllFilesDescr);
+ lpStr += lstrlen(lpStr)+1;
+ lstrcpy(lpStr, szWild);
+ lstrcat(lpStr, "*");
+ lpStr += lstrlen(lpStr)+1;
+ *ppstr++ = NULL;
+ ++nCount;
+
+ *lpStr = 0;
+
+ switch(fDefFileType)
+ {
+ case SA_WORDTEXT:
+ OFN.nFilterIndex = nWordText;
+ break;
+ case SA_TEXTONLY:
+ OFN.nFilterIndex = nTextOnly;
+ break;
+ case SA_WORD :
+ OFN.nFilterIndex = nWord;
+ break;
+ case SA_OLDWRITE:
+ OFN.nFilterIndex = nOldWrite;
+ break;
+ case SA_WRITE :
+ OFN.nFilterIndex = 1;
+ break;
+ }
+ OFN.lpstrDefExt = szDefExtensions[OFN.nFilterIndex - 1];
+}
+
+
+DoOpenFilenameGet(LPSTR lpstrFilenameBuf)
+/* returns whether filename retrieved */
+{
+ int nRetval;
+
+ if (nRetval = DoCommDlg(imiOpen))
+ lstrcpy(lpstrFilenameBuf,(LPSTR)szFileName);
+
+ return nRetval;
+}
+
+DoSaveAsFilenameGet(LPSTR lpstrDefault,LPSTR lpstrFilenameBuf,int *fBackup,int *fTextOnly,int *fWordFmt,int *fOldWriteFmt)
+/* Returns whether filename retrieved. Returns filename. If readonly is checked,
+ returns if readonly is checked in fBackup. Returns file type selected in fTextOonly and
+ fWordFmt. */
+{
+ int nRetval;
+
+ lstrcpy(szFileName,lpstrDefault);
+
+ /* see MakeFilterSpec */
+ if (*fTextOnly && *fWordFmt)
+ fDefFileType = SA_WORDTEXT;
+ else if (*fTextOnly)
+ fDefFileType = SA_TEXTONLY;
+ else if (*fWordFmt)
+ fDefFileType = SA_WORD;
+ else if (*fOldWriteFmt)
+ fDefFileType = SA_OLDWRITE;
+ else
+ fDefFileType = SA_WRITE;
+
+ /* check or uncheck backup prompt */
+ OFN.Flags |= (*fBackup) ? OFN_READONLY : 0;
+
+ if (nRetval = DoCommDlg(imiSaveAs))
+ {
+ lstrcpy(lpstrFilenameBuf,(LPSTR)szFileName);
+
+ if (OFN.nFilterIndex == 1)
+ {
+ *fTextOnly = *fWordFmt = FALSE;
+ *fOldWriteFmt = FALSE;
+ }
+ else if (OFN.nFilterIndex == nOldWrite)
+ {
+ *fTextOnly = *fWordFmt = FALSE;
+ *fOldWriteFmt = TRUE;
+ }
+ else if (OFN.nFilterIndex == nWord)
+ {
+ *fTextOnly = *fOldWriteFmt = FALSE;
+ *fWordFmt = TRUE;
+ }
+ else if (OFN.nFilterIndex == nWordText)
+ {
+ *fTextOnly = *fWordFmt = TRUE;
+ *fOldWriteFmt = FALSE;
+ }
+ else if (OFN.nFilterIndex == nTextOnly)
+ {
+ *fTextOnly = TRUE;
+ *fWordFmt = *fOldWriteFmt = FALSE;
+ }
+
+ *fBackup = OFN.Flags & OFN_READONLY;
+ }
+
+ return nRetval;
+}
+
+
diff --git a/private/mvdm/wow16/write/createww.c b/private/mvdm/wow16/write/createww.c
new file mode 100644
index 000000000..600de62d8
--- /dev/null
+++ b/private/mvdm/wow16/write/createww.c
@@ -0,0 +1,964 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* CreateWw.c -- WRITE window & document creation */
+
+
+
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+//#define NOATOM
+#define NOBITMAP
+#define NOPEN
+#define NODRAWTEXT
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOHDC
+#define NOMB
+#define NOMETAFILE
+#define NOMSG
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOWH
+#define NOWINOFFSETS
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NORESOURCE
+#include <windows.h>
+
+#include "mw.h"
+#include "dispdefs.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "fontdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#define NOSTRUNDO
+#define NOSTRMERGE
+#include "str.h"
+#include "code.h"
+#include "prmdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+#define PAGEONLY
+#include "printdef.h" /* printdefs.h */
+/*
+#include "dlgdefs.h"
+*/
+
+#ifdef KOREA
+#include <ime.h>
+#endif
+
+ /* These defines replace dlgdefs.h to combat compiler heap overflows */
+#define idiYes IDOK
+#define idiNo 3
+#define idiCancel IDCANCEL
+
+ /* These defines replace heapdefs.h and heapdata.h for the same
+ irritating reason */
+#define cwSaveAlloc (128)
+#define cwHeapMinPerWindow (50)
+#define cwHeapSpaceMin (60)
+
+/* E X T E R N A L S */
+
+extern CHAR (**vhrgbSave)[];
+extern HANDLE hParentWw;
+extern HANDLE hMmwModInstance;
+extern struct WWD rgwwd[];
+extern int wwMac;
+extern struct FCB (**hpfnfcb)[];
+extern struct DOD (**hpdocdod)[];
+extern int docMac;
+extern struct WWD *pwwdCur;
+extern int fnMac;
+extern CHAR stBuf[];
+
+/* *** Following declarations used by ValidateHeaderFooter */
+ /* Min, Max cp's for header, footer */
+extern typeCP cpMinHeader;
+extern typeCP cpMacHeader;
+extern typeCP cpMinFooter;
+extern typeCP cpMacFooter;
+extern typeCP cpMinDocument;
+extern typeCP vcpLimParaCache;
+extern struct PAP vpapAbs;
+ /* Current allowable cp range for display/edit/scroll */
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+ /* cpFirst and selection are saved in these during header/footer edit */
+extern typeCP cpFirstDocSave;
+extern struct SEL selDocSave;
+
+
+short WCompSzC();
+CHAR (**HszCreate())[];
+struct FNTB **HfntbCreate();
+#ifdef CASHMERE
+struct SETB **HsetbCreate();
+#else
+struct SEP **HsepCreate();
+#endif
+struct PGTB **HpgtbCreate();
+
+
+CHAR *PchFromFc( int, typeFC, CHAR * );
+CHAR *PchGetPn( int, typePN, int *, int );
+typeFC FcMacFromUnformattedFn( int );
+int CchReadAtPage( int, typePN, CHAR *, int, int );
+
+
+/* W W N E W */
+/* allocates and initializes a new wwd structure at wwMac.
+ypMin, ypMax are estimates of the height of window used to allocate dl's.
+wwMac++ is returned.
+Errors: message is made and wwNil is returned.
+remains to be initialized: xp, yp. Many fields must be reset if lower pane.
+*/
+WwNew(doc, ypMin, ypMax)
+int doc, ypMin, ypMax;
+{
+ extern CHAR szDocClass[];
+ struct EDL (**hdndl)[];
+ register struct WWD *pwwd = &rgwwd[wwMac];
+ int dlMax = (ypMax - ypMin) / dypAveInit;
+ int cwDndl = dlMax * cwEDL;
+
+#ifdef CASHMERE /* WwNew is only called once in MEMO */
+ if (wwMac >= wwMax)
+ {
+ Error(IDPMT2ManyWws);
+ return wwNil;
+ }
+#endif
+
+ bltc(pwwd, 0, cwWWDclr);
+
+ if (!FChngSizeH( vhrgbSave,
+ cwSaveAlloc + wwMac * cwHeapMinPerWindow, false ) ||
+ FNoHeap( pwwd->hdndl = (struct EDL (**)[]) HAllocate( cwDndl )) )
+ { /* Could not alloc addtl save space or dl array */
+ return wwNil;
+ }
+ else
+ bltc( *pwwd->hdndl, 0, cwDndl );
+
+#ifdef SPLITTERS
+ pwwd->ww = wwNil;
+#endif /* SPLITTERS */
+
+ /* contents of hdndl are init to 0 when allocated */
+ pwwd->dlMac = pwwd->dlMax = dlMax;
+ pwwd->ypMin = ypMin;
+ pwwd->doc = doc;
+ pwwd->wwptr = CreateWindow(
+ (LPSTR)szDocClass,
+ (LPSTR)"",
+ (WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE),
+ 0, 0, 0, 0,
+ (HWND)hParentWw,
+ (HMENU)NULL, /* use class menu */
+ (HANDLE)hMmwModInstance, /* handle to window instance */
+ (LPSTR)NULL); /* no params to pass on */
+ if (pwwd->wwptr == NULL)
+ return wwNil;
+
+/* inefficient
+ pwwd->cpFirst = cp0;
+ pwwd->ichCpFirst = 0;
+ pwwd->dcpDepend = 0;
+ pwwd->fCpBad = false;
+ pwwd->xpMin = 0;
+ pwwd->xpMac = 0;
+ pwwd->ypMac = 0;
+ pwwd->fFtn = false;
+ pwwd->fSplit= false;
+ pwwd->fLower = false;
+ pwwd->cpMin = cp0;
+ pwwd->drElevator = 0;
+ pwwd->fRuler = false;
+ pwwd->sel.CpFirst = cp0;
+ pwwd->sel.CpFirst = cp0;
+*/
+
+ pwwd->sel.fForward = true;
+ pwwd->fDirty = true;
+ pwwd->fActive = true;
+ pwwd->cpMac = CpMacText(doc);
+/* this is to compensate for the "min" in InvalBand */
+ pwwd->ypFirstInval = ypMaxAll;
+
+ return wwMac++;
+
+#ifdef KOREA /* for level 3, 90.12.12 by Sangl */
+ { HANDLE hKs;
+ LPIMESTRUCT lpKs;
+
+ hKs = GlobalAlloc (GMEM_MOVEABLE|GMEM_DDESHARE,(LONG)sizeof(IMESTRUCT));
+ lpKs = (LPIMESTRUCT)GlobalLock(hKs);
+ lpKs->fnc = IME_SETLEVEL;
+ lpKs->wParam = 3;
+ GlobalUnlock(hKs);
+ SendIMEMessage (pwwd->wwptr, MAKELONG(hKs,0));
+ GlobalFree(hKs);
+ }
+#endif
+} /* end of W w N e w */
+
+
+
+
+ChangeWwDoc( szDoc )
+CHAR szDoc[];
+{ /* Set up wwd fields for a new document to be held in wwdCurrentDoc.
+ docCur is used as the document */
+ extern HANDLE hParentWw;
+ extern int docCur;
+ extern struct SEL selCur;
+ extern typeCP cpMinDocument;
+ extern int vfInsEnd;
+ extern int vfPrPages;
+ extern int vfDidSearch;
+ extern typeCP cpWall;
+
+ register struct WWD *pwwd = &rgwwd[wwDocument];
+
+ pwwd->fDirty = true;
+
+ ValidateHeaderFooter( docCur );
+
+ pwwd->doc = docCur;
+ pwwd->drElevator = 0;
+ pwwd->ichCpFirst = 0;
+ pwwd->dcpDepend = 0;
+ pwwd->cpMin = pwwd->cpFirst = selCur.cpLim = selCur.cpFirst = cpMinDocument;
+ selCur.fForward = TRUE;
+ selCur.fEndOfLine = vfInsEnd = FALSE;
+ pwwd->cpMac = CpMacText(docCur);
+ TrashWw( wwDocument );
+
+ SetScrollPos( pwwd->hVScrBar, pwwd->sbVbar,
+ pwwd->drElevator = 0, TRUE);
+ SetScrollPos( pwwd->hHScrBar, pwwd->sbHbar,
+ pwwd->xpMin = 0, TRUE);
+
+ NewCurWw(0, true);
+ TrashCache(); /* Invalidate Scrolling cache */
+
+ vfPrPages = FALSE;
+
+ if (pwwd->fRuler)
+ {
+ ResetTabBtn();
+ }
+
+ SetTitle(szDoc);
+
+/* Since we are changing document, ensure that we don't use parameters
+ set by a search in a previous window by setting flag false */
+ vfDidSearch = FALSE;
+ cpWall = selCur.cpLim;
+}
+
+
+
+
+/* F N C R E A T E S Z */
+int FnCreateSz(szT, cpMac, dty )
+CHAR *szT;
+typeCP cpMac;
+int dty;
+{ /* Create & Open a new file of the specified type. */
+ /* If cpMac != cpNil, write an FIB to the file */
+ /* if dty==dtyNetwork, generate a unique name in the current
+ directory and copy it to szT */
+ /* WARNING: dty != dtyNetwork SUPPORT HAS BEEN REMOVED */
+
+ int fn;
+ struct FCB *pfcb; /* Be VERY careful of heap movement when using pfcb */
+ struct FIB fib;
+ CHAR (**hsz)[];
+ CHAR sz[cchMaxFile];
+
+ bltsz(szT, sz);
+ sz[cchMaxFile - 1] = 0;
+
+ if ((fn = FnAlloc()) == fnNil)
+ return fnNil;
+
+ pfcb = &(**hpfnfcb)[fn];
+ pfcb->mdExt = pfcb->dty = dtyNormal;
+ pfcb->mdFile = mdBinary;
+
+ Assert( dty == dtyNetwork );
+
+ if (!FCreateFile( sz, fn )) /* Sets pfcb->hszFile, pfcb->rfn */
+ return fnNil;
+
+ FreezeHp();
+ pfcb = &(**hpfnfcb)[fn];
+
+ /* Copy unique filename to parm */
+ bltsz( **pfcb->hszFile, szT );
+
+#ifdef INEFFICIENT
+ pfcb->fcMac = fc0;
+ pfcb->pnMac = pn0;
+#endif
+
+ if (cpMac == cpNil)
+ { /* Unformatted file */
+#ifdef INEFFICIENT
+ pfcb->fFormatted = false;
+#endif
+ MeltHp();
+ }
+ else
+ { /* Formatted file; write FIB */
+ bltbc(&fib, 0, cchFIB);
+ pfcb->fFormatted = true;
+#ifdef INEFFICIENT
+ pfcb->pnChar = pfcb->pnPara = pfcb->pnFntb =
+ pfcb->pnSep = pfcb->pnSetb = pfcb->pnBftb = pn0;
+#endif
+ MeltHp();
+ fib.wIdent = wMagic;
+ fib.dty = dtyNormal;
+ fib.wTool = wMagicTool;
+ fib.fcMac = cpMac + cfcPage;
+ WriteRgch(fn, &fib, (int)cfcPage);
+ }
+ return fn;
+} /* end of F n C r e a t e S z */
+
+
+
+
+
+int DocCreate(fn, hszFile, dty)
+int fn, dty;
+CHAR (**hszFile)[];
+{ /* Create a document */
+extern int vfTextOnlySave;
+struct FNTB **HfntbCreate();
+struct TBD (**HgtbdCreate())[];
+int doc;
+int fFormatted, fOldWord;
+
+struct DOD *pdod;
+struct SEP **hsep = (struct SEP **)0; /* MEMO only; for CASHMERE, use hsetb */
+struct PGTB **hpgtb=(struct PGTB **)0;
+struct FFNTB **hffntb=(struct FFNTB **)0;
+struct TBD (**hgtbd)[]=(struct TBD (**)[])0;
+struct FNTB **hfntb = (struct FNTB **) 0;
+CHAR (**hszSsht)[];
+
+fFormatted = (fn == fnNil) || (**hpfnfcb)[fn].fFormatted;
+fOldWord = FALSE;
+
+if ((doc = DocAlloc()) == docNil || /* HEAP MOVEMENT */
+ !FInitPctb(doc, fn)) /* HEAP MOVEMENT */
+ return docNil;
+
+pdod = &(**hpdocdod)[doc];
+
+pdod->fReadOnly = (fn != fnNil) && ((**hpfnfcb)[fn].mdFile == mdBinRO);
+pdod->cref = 1;
+pdod->fFormatted = fFormatted;
+pdod->dty = dty;
+pdod->fBackup = false; /* Default: don't automatically make backup */
+pdod->fDisplayable = TRUE;
+
+switch(dty)
+ { /* HEAP MOVEMENT */
+case dtyHlp:
+ if (FNoHeap(hpgtb = HpgtbCreate(fn)))
+ goto ErrFree;
+ if (FNoHeap(hffntb = HffntbCreateForFn(fn, &fOldWord)))
+ goto ErrFree;
+ break;
+
+case dtyNormal:
+ if (fn != fnNil && fFormatted)
+ {
+#ifdef FOOTNOTES
+ if (FNoHeap(hfntb = HfntbCreate(fn)))
+ goto ErrFree;
+#endif
+ if (FNoHeap(hsep = HsepCreate(fn)))
+ goto ErrFree;
+ if (FNoHeap(hpgtb = HpgtbCreate(fn)))
+ goto ErrFree;
+ if (FNoHeap(hgtbd = HgtbdCreate(fn)))
+ goto ErrFree;
+ }
+ if (FNoHeap(hffntb = HffntbCreateForFn(fn, &fOldWord)))
+ goto ErrFree;
+ break;
+case dtySsht:
+ goto DtyCommon;
+case dtyBuffer:
+ if (fn != fnNil)
+ {
+#ifdef FOOTNOTES
+ if (FNoHeap(hfntb = HfntbCreate(fn)))
+ goto ErrFree;
+#endif
+ if (FNoHeap(hsep = HsepCreate(fn)))
+ goto ErrFree;
+ if (FNoHeap(hgtbd = HgtbdCreate(fn)))
+ goto ErrFree;
+ }
+DtyCommon:
+ hpgtb = 0;
+ }
+
+pdod = &(**hpdocdod)[doc];
+
+pdod->hszFile = hszFile;
+pdod->docSsht = docNil;
+pdod->hfntb = hfntb;
+pdod->hsep = hsep;
+pdod->hpgtb = hpgtb;
+pdod->hffntb = hffntb;
+pdod->hgtbd = hgtbd;
+if (fOldWord)
+ if (!FApplyOldWordSprm(doc))
+ goto ErrFree;
+
+ApplyRHMarginSprm( doc );
+vfTextOnlySave = !fFormatted;
+return doc;
+
+ErrFree:
+ FreeH( hsep );
+ FreeFfntb( hffntb );
+ FreeH(hgtbd);
+ FreeH(hpgtb);
+#ifdef FOOTNOTES
+ FreeH(hfntb);
+#endif
+ FreeH((**hpdocdod)[doc].hpctb);
+ (**hpdocdod)[doc].hpctb = 0;
+
+return docNil;
+} /* end of D o c C r e a t e */
+
+
+
+
+ApplyRHMarginSprm( doc )
+int doc;
+{ /* Apply a sprm to adjust paper-relative running head indents to
+ be margin-relative */
+extern typeCP cpMinDocument;
+extern struct SEP vsepNormal;
+
+ValidateHeaderFooter( doc );
+if (cpMinDocument != cp0)
+ { /* Doc has running head/foot, apply sprm */
+ CHAR rgb[ 2 + (2 * sizeof( int )) ];
+ struct SEP **hsep = (**hpdocdod) [doc].hsep;
+ struct SEP *psep = (hsep == NULL) ? &vsepNormal : *hsep;
+
+ rgb[0] = sprmPRhcNorm;
+ rgb[1] = 4;
+ *((int *) (&rgb[2])) = psep->xaLeft;
+ *((int *) (&rgb[2 + sizeof(int)])) = psep->xaMac -
+ (psep->xaLeft + psep->dxaText);
+ AddSprmCps( rgb, doc, cp0, cpMinDocument );
+ }
+}
+
+
+
+
+int DocAlloc()
+{
+int doc;
+struct DOD *pdod = &(**hpdocdod)[0];
+struct DOD *pdodMac = pdod + docMac;
+
+for (doc = 0; pdod < pdodMac; ++pdod, ++doc)
+ if (pdod->hpctb == 0)
+ return doc;
+if (!FChngSizeH((int **)hpdocdod, cwDOD * ++docMac, false))
+ {
+ --docMac;
+ return docNil;
+ }
+return docMac - 1;
+} /* end of D o c A l l o c */
+
+FInitPctb(doc, fn)
+int doc, fn;
+{ /* Initialize the piece table for a doc, given its initial fn */
+struct PCTB **hpctb;
+struct DOD *pdod;
+struct PCTB *ppctb;
+struct PCD *ppcd;
+typeFC dfc;
+typeCP cpMac;
+
+hpctb = (struct PCTB **)HAllocate(cwPCTBInit); /* HM */
+if (FNoHeap(hpctb))
+ return false;
+pdod = &(**hpdocdod)[doc];
+ppctb = *(pdod->hpctb = hpctb); /* Beware hp mvmt above */
+ppcd = ppctb->rgpcd;
+dfc = (fn != fnNil && (**hpfnfcb)[fn].fFormatted ? cfcPage : fc0);
+cpMac = (fn == fnNil ? cp0 : (**hpfnfcb)[fn].fcMac - dfc);
+
+ppctb->ipcdMax = cpcdInit;
+ppctb->ipcdMac = (cpMac == cp0 ) ? 1 : 2; /* One real piece and one end piece */
+ppcd->cpMin = cp0;
+
+if ((pdod->cpMac = cpMac) != cp0)
+ {
+ ppcd->fn = fn;
+ ppcd->fc = dfc;
+ SETPRMNIL(ppcd->prm);
+ ppcd->fNoParaLast = false;
+ (++ppcd)->cpMin = cpMac;
+ }
+
+ppcd->fn = fnNil;
+SETPRMNIL(ppcd->prm);
+ppcd->fNoParaLast = true;
+
+pdod->fDirty = false;
+return true;
+} /* end of F I n i t P c t b */
+
+int FnAlloc()
+{ /* Allocate an fn number */
+int fn;
+struct FCB *pfcb;
+
+for (fn = 0 ; fn < fnMac ; fn++)
+ if ((**hpfnfcb)[fn].rfn == rfnFree)
+ goto DoAlloc;
+if (!FChngSizeH(hpfnfcb, (fnMac + 1) * cwFCB, false))
+ return fnNil;
+fn = fnMac++;
+
+DoAlloc:
+bltc(pfcb = &(**hpfnfcb)[fn], 0, cwFCB);
+pfcb->rfn = rfnFree;
+return fn;
+} /* end of F n A l l o c */
+
+
+
+fnNewFile()
+{ /* Open a new, fresh, untitled document in our MEMO window */
+ /* Offer confirmation if the current doc is dirty & permit save */
+ extern HANDLE hMmwModInstance;
+ extern HANDLE hParentWw;
+ extern int docCur;
+ extern struct SEL selCur;
+ extern typeCP cpMinDocument;
+ extern int vfTextOnlySave, vfBackupSave;
+ extern CHAR szUntitled[];
+
+ if (FConfirmSave()) /* Allow the user to save if docCur is dirty */
+ {
+
+#if defined(OLE)
+ if (ObjClosingDoc(docCur,szUntitled))
+ return;
+#endif
+
+ KillDoc( docCur );
+
+ docCur = DocCreate( fnNil, HszCreate( "" ), dtyNormal );
+ Assert( docCur != docNil );
+ ChangeWwDoc( "" );
+
+#if defined(OLE)
+ ObjOpenedDoc(docCur); // very unlikely to fail, not fatal if it does
+#endif
+
+#ifdef WIN30
+ FreeUnreferencedFns();
+#endif
+ }
+} /* end of f n N e w F i l e */
+
+
+
+
+
+
+
+struct FFNTB **HffntbCreateForFn(fn, pfOldWord)
+/* returns heap copy of ffntb (font names) for fn */
+
+int fn, *pfOldWord;
+{
+struct FFNTB **hffntb;
+typePN pn;
+struct FCB *pfcb;
+typePN pnMac;
+#ifdef NEWFONTENUM
+BOOL fCloseAfterward;
+#endif
+
+if (FNoHeap(hffntb = HffntbAlloc()))
+ return(hffntb);
+pfcb = &(**hpfnfcb)[fn];
+pn = pfcb->pnFfntb;
+if (fn == fnNil || !pfcb->fFormatted)
+ {
+#if WINVER >= 0x300
+ /* WINBUG 8992: Clean up so don't lose alloc'd memory! ..pault 2/12/90 */
+ FreeFfntb(hffntb);
+#endif
+ hffntb = HffntbNewDoc(FALSE);
+ }
+else if (pn != (pnMac=pfcb->pnMac))
+ { /* "normal" memo file - has a font table */
+ CHAR *pch;
+ int cch;
+ int iffn;
+ int iffnMac;
+
+ /* Read the first page:
+ bytes 0..1 iffnMac
+ 0..n sections of:
+ bytes 0..1 cbFfn
+ bytes 2..cbFfn+2 Ffn
+ bytes x..x+1 0xFFFF (end of page)
+ OR bytes x..x+1 0x0000 (end of font table) */
+
+ pch = PchGetPn( fn, pn, &cch, FALSE );
+ if (cch != cbSector)
+ goto Error;
+ iffnMac = *( (int *) pch);
+ pch += sizeof (int);
+#ifdef NEWFONTENUM
+ /* Since we now support multiple charsets, but write 2 and write 1
+ documents did not save these in their ffntb's, we have to do an
+ extra step now in order to "infer" the proper charset values. We
+ enumerate all the possible fonts, and then as we read in each new
+ document font we try to match it up with what the system knows
+ about ..pault 10/18/89 */
+ fCloseAfterward = FInitFontEnum(docNil, 32767, FALSE);
+#endif
+
+ for ( iffn = 0; ; )
+ {
+ /* Add ffn entries from one disk page to the font table */
+
+ while ( TRUE )
+ {
+ int cb = *((int *) pch);
+
+ if (cb == 0)
+ goto LRet; /* Reached end of table */
+ else if (cb == -1)
+ break; /* Reached end of disk page */
+ else
+ {
+#ifdef NEWFONTENUM
+ /* Having added the chs field to the (RAM) FFN structure,
+ we now get screwed reading FFN's from the document
+ directly. And because Write was designed very early
+ without regard to variable charsets, we can't store
+ the charset value along with the fontname, so we have
+ to infer it! ..pault */
+ CHAR rgbFfn[ibFfnMax];
+ struct FFN *pffn = (struct FFN *)rgbFfn;
+ pch += sizeof(int);
+
+ bltsz(pch + sizeof(BYTE), pffn->szFfn);
+ pffn->ffid = *((FFID *) pch);
+ pffn->chs = ChsInferred(pffn);
+ if (FtcAddFfn(hffntb, pffn) == ftcNil)
+#else
+ if (FtcAddFfn( hffntb, pch += sizeof(int) ) == ftcNil)
+#endif
+ {
+Error:
+#ifdef NEWFONTENUM
+ if (fCloseAfterward)
+ EndFontEnum();
+#endif
+ FreeFfntb( hffntb );
+ return (struct FFNTB **) hOverflow;
+ }
+ iffn++;
+ if (iffn >= iffnMac)
+ /* Reached last item in table, by count */
+ /* This is so we can read old WRITE files, */
+ /* in which the table was not terminated by 0 */
+ goto LRet;
+ pch += cb;
+ }
+ } /* end while */
+
+ /* Read the next page from the file. Page format is like the first
+ ffntb page (see above) but without the iffnMac */
+
+ if (++pn >= pnMac)
+ break;
+ pch = PchGetPn( fn, pn, &cch, FALSE );
+ if (cch != cbSector)
+ goto Error;
+ } /* end for */
+ }
+else
+ {
+ /* word file - create a simple font table that we can map word's
+ fonts onto */
+
+ /* temporarily we map them all onto one font - soon we'll have a set */
+#if WINVER >= 0x300
+ /* WINBUG 8992: Clean up so don't lose alloc'd memory! ..pault 2/12/90 */
+ FreeFfntb(hffntb);
+#endif
+ hffntb = HffntbNewDoc(TRUE);
+ *pfOldWord = TRUE;
+ }
+
+LRet:
+#ifdef NEWFONTENUM
+ if (fCloseAfterward)
+ EndFontEnum();
+#endif
+return(hffntb);
+}
+
+
+
+struct FFNTB **HffntbNewDoc(fFullSet)
+/* creates a font table with the default font for this doc */
+
+int fFullSet;
+{
+struct FFNTB **hffntb;
+
+hffntb = HffntbAlloc();
+if (FNoHeap(hffntb))
+ return(hffntb);
+
+/* make sure we at least have a "standard" font */
+#ifdef KOREA /* ROMAN as family of standard font(myoungjo). sangl 91.4.17 */
+if (!FEnsurePffn(hffntb, PffnDefault(FF_ROMAN)))
+#else
+if (!FEnsurePffn(hffntb, PffnDefault(FF_DONTCARE)))
+#endif
+ {
+ goto BadAdd;
+ }
+
+if (fFullSet)
+ /* we need a full set of fonts for word ftc mapping */
+ if (!FEnsurePffn(hffntb, PffnDefault(FF_MODERN)) ||
+#ifdef KOREA
+ !FEnsurePffn(hffntb, PffnDefault(FF_DONTCARE)) ||
+#else
+ !FEnsurePffn(hffntb, PffnDefault(FF_ROMAN)) ||
+#endif
+ !FEnsurePffn(hffntb, PffnDefault(FF_SWISS)) ||
+ !FEnsurePffn(hffntb, PffnDefault(FF_SCRIPT)) ||
+ !FEnsurePffn(hffntb, PffnDefault(FF_DECORATIVE)))
+ BadAdd:
+ {
+ FreeFfntb(hffntb);
+ hffntb = (struct FFNTB **)hOverflow;
+ }
+
+return(hffntb);
+}
+
+
+
+CHAR * PchBaseNameInUpper(szName)
+CHAR *szName;
+{
+ CHAR * pchStart = szName;
+#ifdef DBCS
+ CHAR * pchEnd = AnsiPrev( pchStart, pchStart + CchSz(szName) );
+#else
+ CHAR * pchEnd = pchStart + CchSz(szName) - 1;
+#endif
+
+ while (pchEnd >= pchStart)
+ {
+#ifdef DBCS
+ if (*pchEnd == '\\' || *pchEnd == ':')
+ break;
+ else if (!IsDBCSLeadByte(*pchEnd))
+ *pchEnd = ChUpper(*pchEnd);
+ {
+ LPSTR lpstr = AnsiPrev( pchStart, pchEnd );
+ if( pchEnd == lpstr )
+ break;
+ pchEnd = lpstr;
+ }
+#else
+ if (*pchEnd == '\\' || *pchEnd == ':')
+ break;
+ else
+ *pchEnd = ChUpper(*pchEnd);
+ pchEnd--;
+#endif
+ }
+#ifdef DBCS
+ return(AnsiUpper(pchEnd));
+#else
+ return(pchEnd+1);
+#endif
+}
+
+
+SetTitle(szSource)
+CHAR *szSource;
+{
+extern CHAR szUntitled[];
+extern int vfIconic;
+extern CHAR szAppName[];
+extern CHAR szSepName[];
+
+CHAR *pch = stBuf;
+CHAR szDocName[cchMaxFile];
+
+ pch += CchCopySz((PCH)szAppName, stBuf);
+ pch += CchCopySz((PCH)szSepName, pch);
+
+ if (szSource[0] == '\0')
+ {
+ CchCopySz( szUntitled, pch );
+ }
+ else
+ { /* get the pointer to the base file name and convert to upper case */
+ CchCopySz(szSource, szDocName);
+ CchCopySz(PchBaseNameInUpper(szDocName), pch);
+ }
+ SetWindowText(hParentWw, (LPSTR)stBuf);
+}
+
+
+
+ValidateHeaderFooter( doc )
+{ /* Look for a MEMO-style running header and/or footer in the document.
+ We scan from the beginning of the document, taking the first
+ contiguous sequence of running head paragraphs as the running
+ head region, and the first contiguous sequence of running foot
+ paragraphs as the running foot region. We break the process
+ at the first non-running paragraph or when we have both runs
+ Update values of cpMinDocument, cpMinFooter, cpMacFooter,
+ cpMinHeader, cpMacHeader.
+ These ranges INCLUDE the EOL (and Return, if CRLF) at the end of the
+ header/footer
+ If we are currently editing a header or footer in the passed doc,
+ adjust the values of cpFirstDocSave, selDocSave to reflect the
+ change */
+
+ extern int docScrap;
+ extern typeCP vcpFirstParaCache;
+ extern typeCP vcpLimParaCache;
+
+#define fGot 0
+#define fGetting 1
+#define fNotGot 2
+
+ int fGotHeader=fNotGot;
+ int fGotFooter=fNotGot;
+ typeCP cpMinDocT=cpMinDocument;
+ typeCP cpMinCurT = cpMinCur;
+ typeCP cpMacCurT = cpMacCur;
+ typeCP cp;
+
+ if (doc == docNil || doc == docScrap)
+ return;
+
+ /* Want access to the entire doc cp range for this operation */
+
+ cpMinCur = cp0;
+ cpMacCur = (**hpdocdod) [doc].cpMac;
+
+ cpMinDocument = cpMinFooter = cpMacFooter = cpMinHeader = cpMacHeader = cp0;
+
+ for ( cp = cp0;
+ (cp < cpMacCur) && (CachePara( doc, cp ), vpapAbs.rhc);
+ cp = vcpLimParaCache )
+ {
+ int fBottom=vpapAbs.rhc & RHC_fBottom;
+
+ if (fBottom)
+ {
+ if (fGotHeader == fGetting)
+ fGotHeader = fGot;
+ switch (fGotFooter) {
+ case fGot:
+ /* Already have footer from earlier footer run */
+ return;
+ case fNotGot:
+ cpMinFooter = vcpFirstParaCache;
+ fGotFooter = fGetting;
+ /* FALL THROUGH */
+ case fGetting:
+ cpMacFooter = cpMinDocument = vcpLimParaCache;
+ break;
+ }
+ }
+ else
+ {
+ if (fGotFooter == fGetting)
+ fGotFooter = fGot;
+ switch (fGotHeader) {
+ case fGot:
+ /* Already have header from earlier header run */
+ return;
+ case fNotGot:
+ cpMinHeader = vcpFirstParaCache;
+ fGotHeader = fGetting;
+ /* FALL THROUGH */
+ case fGetting:
+ cpMacHeader = cpMinDocument = vcpLimParaCache;
+ break;
+ }
+ }
+ } /* end of for loop through paras */
+
+ /* Restore saved cpMacCur, cpMinCur */
+ cpMinCur = cpMinCurT;
+ cpMacCur = cpMacCurT;
+
+ /* Adjust saved cp's that refer to the document to reflect
+ header/footer changes */
+ if ((wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter) &&
+ wwdCurrentDoc.doc == doc )
+ {
+ typeCP dcpAdjust=cpMinDocument - cpMinDocT;
+
+ if (dcpAdjust != (typeCP) 0)
+ {
+ selDocSave.cpFirst += dcpAdjust;
+ selDocSave.cpLim += dcpAdjust;
+ cpFirstDocSave += dcpAdjust;
+ }
+ }
+}
+
diff --git a/private/mvdm/wow16/write/curskeys.c b/private/mvdm/wow16/write/curskeys.c
new file mode 100644
index 000000000..b10e5e194
--- /dev/null
+++ b/private/mvdm/wow16/write/curskeys.c
@@ -0,0 +1,526 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* curskeys.c-- cursor key movement subroutines */
+/* Oct 4, 1984, KJS */
+
+#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOSYSMETRICS
+#define NOATOM
+#define NOSYSCOMMANDS
+#define NOCOMM
+#define NOSOUND
+#define NOMENUS
+#define NOGDI
+#define NOPEN
+#define NOBRUSH
+#define NOFONT
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "debug.h"
+#include "fmtdefs.h"
+#include "printdef.h"
+
+struct DOD (**hpdocdod)[];
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct PAP vpapAbs;
+extern int vfSeeSel;
+extern int vfShiftKey;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern int wwCur;
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur; /* Current window descriptor */
+extern int docCur;
+extern typeCP vcpSelect;
+extern int vfSelAtPara;
+extern int vfLastCursor;
+extern int vfMakeInsEnd;
+extern CHAR *vpchFetch;
+
+int vfSeeEdgeSel=FALSE; /* Whether Idle() should show edge of selection
+ even if selection is partially visible */
+
+ /* Absolute x-position to try to achieve on up-down motions;
+ used in this module only */
+int vxpCursor;
+
+
+
+
+MoveLeftRight( kc )
+int kc;
+{ /* Move or drag selection in left or right directions */
+extern int vfInsEnd;
+typeCP CpEdge();
+
+extern int vfGotoKeyMode;
+extern int xpRightLim;
+int fDrag = vfShiftKey ;
+int fFwdKey = FALSE;
+int fForward = selCur.fForward;
+int sty;
+typeCP cp;
+
+MSG msg;
+
+PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
+
+vfGotoKeyMode |= (GetKeyState( kcGoto & ~wKcCommandMask) < 0);
+
+switch( kc ) {
+ int dl;
+ int xp;
+ int xpJunk;
+
+ default:
+ Assert( FALSE );
+ return;
+ case kcNextPara:
+ fFwdKey = TRUE;
+ case kcPrevPara:
+ sty = styPara;
+ break;
+ case kcWordRight:
+ fFwdKey = TRUE;
+ case kcWordLeft:
+ sty = styWord;
+ break;
+ case kcEndLine:
+ if (vfGotoKeyMode)
+ {
+ MoveUpDown( kcEndDoc );
+ return;
+ }
+ xp = xpRightLim;
+ goto GoDlXp;
+
+ case kcBeginLine:
+ if (vfGotoKeyMode)
+ {
+ MoveUpDown( kcTopDoc );
+ return;
+ }
+ xp = xpSelBar - wwdCurrentDoc.xpMin;
+GoDlXp:
+
+ if (CpBeginLine( &dl, CpEdge() ) == selCur.cpFirst &&
+ selCur.cpFirst > cpMinCur && vfInsEnd )
+ {
+ CpBeginLine( &dl, selCur.cpFirst - 1);
+ }
+ vcpSelect = cpNil;
+ vfSelAtPara = false;
+ SelectDlXp( dl, xp, styChar, fDrag );
+ goto SeeSel;
+ case kcRight:
+ fFwdKey = TRUE;
+ case kcLeft:
+ sty = (vfGotoKeyMode) ? stySent : styChar;
+ break;
+ }
+
+ /* Find cp to start extension from */
+if (selCur.cpLim == selCur.cpFirst || fDrag)
+ cp = fForward ? selCur.cpLim : selCur.cpFirst;
+else
+ cp = fFwdKey ? selCur.cpLim - 1 : selCur.cpFirst + 1;
+
+/* Catch attempts to run off the document start or end */
+
+if (fFwdKey)
+ {
+ if (cp == cpMacCur)
+ {
+ _beep();
+ return;
+ }
+ }
+else if (cp == cpMinCur)
+ {
+ _beep();
+ return;
+ }
+
+if (fFwdKey)
+ {
+ if (cp >= cpMacCur)
+ /* If at end, stay at end. */
+ cp = cpMacCur;
+ else
+ {
+ cp = CpLimSty( cp, sty );
+ }
+ }
+ else
+ {
+ if (cp > cpMinCur)
+ /* So we go back to the PREVIOUS sty unit */
+ cp--;
+ cp = CpFirstSty( cp, sty );
+ }
+
+if (fDrag)
+ { /* Drag selection edge to new bound. */
+/* If selection flips, keep one sty unit selected EXCEPT if it's styChar;
+ when dragging by char, the selection can become an insertion point */
+
+ ChangeSel( cp, sty == styChar ? styNil : sty );
+ }
+else
+ {
+ Select(cp, cp);
+ if (!fFwdKey)
+ selCur.fForward = false;
+ }
+
+SeeSel:
+
+vfSeeSel = true; /* Tell Idle to scroll the selection into view */
+vfSeeEdgeSel = true; /* And the edge of it even if it's already partly visible */
+return;
+}
+
+
+
+
+/* M O V E U P D O W N */
+MoveUpDown(kc)
+int kc;
+{ /* Move the selection in direction of kc, in up or down directions */
+
+ /* Our goal with up-and-down motions is to keep (if applicable) an */
+ /* absolute x-position to which the cursor tends to go if there is */
+ /* text on the line at that position. We set this position (vxpCursor) */
+ /* when we process the first up/down key, and hang onto it thereafter */
+ /* A global flag, vfLastCursor, tells us whether we should use the */
+ /* last calculated setting of vxpCursor or generate a new one. vxpCursor */
+ /* is set below and cleared in Select() and AlphaMode() */
+
+extern int vfGotoKeyMode;
+int fDrag = vfShiftKey;
+int dl;
+typeCP cpT;
+struct EDL (**hdndl)[] = wwdCurrentDoc.hdndl;
+register struct EDL *pedl;
+int dipgd;
+int xpNow;
+
+MSG msg;
+
+PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
+
+vfGotoKeyMode |= (GetKeyState( kcGoto & ~wKcCommandMask) < 0);
+
+ /* Compute dl, vxpCursor for selection starting point */
+
+ switch (kc)
+ {
+ default:
+ Assert( FALSE );
+ break;
+ case kcUp:
+ if (vfGotoKeyMode)
+ { /* GOTO-UP is Prev Para */
+ MoveLeftRight( kcPrevPara );
+ return;
+ }
+ case kcPageUp:
+ case kcUpScrollLock:
+ case kcTopScreen:
+ case kcTopDoc:
+ cpT = selCur.fForward && fDrag ? selCur.cpLim : selCur.cpFirst;
+ break;
+ case kcDown:
+ if (vfGotoKeyMode)
+ { /* GOTO-DOWN is Next Para */
+ MoveLeftRight( kcNextPara );
+ return;
+ }
+ case kcPageDown:
+ case kcDownScrollLock:
+ case kcEndScreen:
+ case kcEndDoc:
+ cpT = selCur.fForward || !fDrag ? selCur.cpLim : selCur.cpFirst;
+ break;
+ }
+
+ CpToDlXp( cpT, &dl, (vfLastCursor) ? &xpNow : &vxpCursor );
+
+
+ /* HACK: If the guy is dragging up/down and is on the first/last line of
+ the doc but not right at the start/end of the doc, extend him to
+ the start/end of the doc */
+
+ if (fDrag && !vfGotoKeyMode)
+ {
+ switch (kc) {
+ case kcUp:
+ /* Special fix for dragging upward: if we are seeking up to a position
+ that is equivalent in cp space to where we are now, force a decrement
+ of the source dl so we really go up a line */
+
+ if (vfLastCursor && xpNow <= xpSelBar && vxpCursor > xpSelBar &&
+ cpT > cpMinCur)
+ {
+ CpToDlXp( CpFirstSty( cpT - 1, styChar), &dl, &xpNow );
+ }
+ case kcPageUp:
+ case kcUpScrollLock:
+ if (wwdCurrentDoc.cpFirst == cpMinCur && cpT > cpMinCur)
+ if (dl == 0 || kc == kcPageUp)
+ {
+ MoveUpDown( kcTopDoc );
+ return;
+ }
+ break;
+ case kcPageDown:
+ case kcDown:
+ case kcDownScrollLock:
+ {
+ typeCP cpLimDl;
+
+ pedl = &(**hdndl) [dl];
+ cpLimDl = pedl->cpMin + pedl->dcpMac;
+ if (cpLimDl >= cpMacCur && cpT >= pedl->cpMin && cpT < cpMacCur)
+ {
+ MoveUpDown( kcEndDoc );
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Do the cursor movement, scrolling if necessary */
+ switch (kc)
+ {
+ case kcPageUp:
+ if (vfGotoKeyMode)
+ { /* Go to previous printed page */
+ extern int vipgd;
+ extern int rgval[];
+ struct PGTB **hpgtb;
+ int ipgd;
+
+ dipgd = -1;
+
+ CachePage( docCur, selCur.cpFirst );
+ if (vipgd != iNil)
+ {
+ hpgtb = (**hpdocdod) [docCur].hpgtb;
+ if ((**hpgtb).rgpgd [vipgd].cpMin != selCur.cpFirst)
+ /* Not at page start; go there first */
+ dipgd++;
+ }
+
+GoPage: CachePage( docCur, selCur.cpFirst ); /*validate vipgd*/
+ hpgtb = (**hpdocdod)[docCur].hpgtb;
+ if ((vipgd == iNil) ||
+ ((ipgd = vipgd + dipgd) < 0) ||
+ (ipgd >= (**hpgtb).cpgd))
+ { /*Whole doc on one page || run off either end*/
+ _beep();
+ }
+ else
+ {
+ rgval [0] = (**hpgtb).rgpgd[ipgd].pgn;
+ CmdJumpPage(); /* rgval [0] is a parm to CmdJumpPage */
+ }
+ return;
+ }
+ ScrollUpDypWw();
+ break;
+ case kcPageDown:
+ if (vfGotoKeyMode)
+ { /* Go to next printed page */
+ dipgd = 1;
+ goto GoPage;
+ }
+
+ /* Special case for extending selection one page down from the
+ top line of the ww -- extend to the NEXT line so we don't
+ end up without any part of the selection on the screen */
+
+ ScrollDownCtr( 100 ); /* 100 > tr's in a page */
+ vcpSelect = cpNil;
+ vfSelAtPara = false;
+ SelectDlXp( dl, (**hdndl)[dl].fGraphics ? 0 : vxpCursor, styChar, fDrag );
+ if (fDrag && (dl == 0) && selCur.cpLim == wwdCurrentDoc.cpFirst)
+ {
+ MoveUpDown( kcDown );
+ }
+ goto DontSelect;
+
+ case kcUpScrollLock:
+ case kcUp:
+ UpdateWw(wwCur, false);
+
+ pedl = &(**hdndl) [dl];
+
+ if ( fDrag && (selCur.fForward ? selCur.cpLim : selCur.cpFirst) ==
+ pedl->cpMin && pedl->cpMin > cpMinCur)
+ { /* Up into picture == left */
+ CachePara( docCur, pedl->cpMin - 1 );
+ if (vpapAbs.fGraphics)
+ {
+ MoveLeftRight( kcLeft );
+ return;
+ }
+ }
+
+ if ((pedl->cpMin == cpMinCur) && (pedl->ichCpMin == 0))
+ { /* At beginning of doc or area */
+ int xpT;
+
+ _beep();
+ CpToDlXp(cpMinCur, &dl, &xpT);
+ goto DoSelect;
+ }
+ else if ( (dl == 0) || (kc == kcUpScrollLock) )
+ { /* At top of screen OR keep posn */
+ ScrollUpCtr( 1 );
+ UpdateWw(wwCur, false);
+ }
+ else
+ {
+ --dl;
+ }
+ break;
+
+ case kcDownScrollLock:
+ case kcDown:
+ UpdateWw(wwCur, false);
+ pedl = &(**hdndl)[dl];
+ {
+ int xpT;
+ typeCP cp;
+
+ cp = pedl->cpMin + pedl->dcpMac;
+
+ if (selCur.cpFirst < selCur.cpLim && selCur.fForward &&
+ pedl->cpMin == selCur.cpLim &&
+ cp < cpMacCur &&
+ (!fDrag ||
+ ((vxpCursor > pedl->xpLeft + xpSelBar) &&
+ (pedl->dcpMac > ccpEol))))
+ { /* In this case, it thinks we are at the start of the
+ next line; incrementing/scrolling is unnecessary */
+ goto DoSelect;
+ }
+
+ if (pedl->fGraphics)
+ { /* Special for pictures */
+ MoveLeftRight( kcRight );
+
+ if (!fDrag)
+ {
+ extern struct PAP vpapAbs;
+
+ CachePara( docCur, selCur.cpFirst );
+ if (vpapAbs.fGraphics)
+ {
+ vfShiftKey = TRUE;
+ MoveLeftRight( kcRight );
+ SetShiftFlags();
+ }
+ }
+ goto DontSelect;
+ }
+
+ if (cp > cpMacCur)
+ {
+ if (selCur.cpLim == selCur.cpFirst || selCur.cpLim == cpMacCur)
+ /* test is because CpToDlXp cannot account for
+ selection extending to end of next-to-last line */
+ _beep();
+ CpToDlXp(cpMacCur, &dl, &xpT);
+ goto DoSelect;
+ }
+ if ( (dl >= wwdCurrentDoc.dlMac - 2) || (kc == kcDownScrollLock) )
+ { /* within one line of window end */
+ ScrollDownCtr( 1 );
+ UpdateWw(wwCur, false);
+ }
+ else
+ dl++;
+ }
+ break;
+
+ case kcTopScreen:
+ dl = 0;
+ break;
+ case kcEndScreen:
+ dl = wwdCurrentDoc.dlMac - 1;
+ if ( dl > 0 && (**wwdCurrentDoc.hdndl) [dl].yp >= wwdCurrentDoc.ypMac)
+ { /* Back up if last (and not only) dl is partially clipped */
+ dl--;
+ }
+ break;
+ case kcTopDoc:
+ CpToDlXp(cpMinCur, &dl, &vxpCursor);
+ break;
+ case kcEndDoc:
+ CpToDlXp(cpMacCur, &dl, &vxpCursor);
+ break;
+
+ default:
+ return;
+ }
+
+DoSelect: /* select at/to position vxpCursor on line dl */
+ vcpSelect = cpNil;
+ vfSelAtPara = false;
+ SelectDlXp( dl, (**hdndl)[dl].fGraphics ? 0 : vxpCursor, styChar, fDrag );
+DontSelect:
+ vfLastCursor = true; /* don't recalc vxpCursor next time */
+}
+
+
+
+
+/* C P T O D L X P */
+CpToDlXp(cp, pdl, pxp)
+typeCP cp;
+int *pdl, *pxp;
+{ /* Transform cp into cursor coordinates */
+extern int vfInsEnd;
+typeCP cpBegin;
+int dcp;
+int xp;
+
+ if (!vfInsEnd)
+ PutCpInWwHz(cp);
+
+ cpBegin = CpBeginLine(pdl, cp);
+ ClearInsertLine();
+ if ( (cp == selCur.cpFirst) && (cp == selCur.cpLim) && vfInsEnd &&
+ cp > cpMinCur)
+ { /* cp indicates we are at line beginning, but we are really
+ kludged at the end of the previous line */
+ CpToDlXp( cp - 1, pdl, pxp );
+ PutCpInWwHz( cp - 1 );
+ return;
+ }
+
+ dcp = (int) (cp - cpBegin);
+ FormatLine(docCur, cpBegin, 0, cpMacCur, flmSandMode);
+ xp = DxpDiff(0, dcp, &xp) + vfli.xpLeft;
+ *pxp = xp + (xpSelBar - wwdCurrentDoc.xpMin);
+}
diff --git a/private/mvdm/wow16/write/d_disp.c b/private/mvdm/wow16/write/d_disp.c
new file mode 100644
index 000000000..03834951b
--- /dev/null
+++ b/private/mvdm/wow16/write/d_disp.c
@@ -0,0 +1,1816 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* disp.c -- MW display routines */
+
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOWINSTYLES
+//#define NOVIRTUALKEYCODES
+
+#ifndef DBCS
+#define NOSYSMETRICS
+#endif
+
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NOWH
+#define NOWINOFFSETS
+#define NOMETAFILE
+
+#ifndef DBCS
+#define NOMB
+#endif
+
+#define NODRAWTEXT
+#include <windows.h>
+
+#define NOUAC
+#include "mw.h"
+#include "debug.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES /* Removes all kc code defines */
+#include "ch.h"
+#include "docdefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "macro.h"
+#include "printdef.h"
+#include "fontdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifdef DBCS
+#include "dbcs.h"
+#include "kanji.h"
+#endif
+
+#ifdef DBCS_IME
+#include <ime.h>
+
+#ifdef JAPAN
+BOOL ConvertEnable = FALSE;
+BOOL bClearCall = TRUE;
+#endif /* JAPAN */
+#endif /* DBCS_IME */
+
+#ifdef CASHMERE /* No VisiMode in WinMemo */
+extern int vfVisiMode;
+#endif /* CASHMERE */
+
+extern int vcchBlted;
+extern int vidxpInsertCache;
+extern int vdlIns;
+extern int vfInsLast;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern int rgval[];
+extern struct DOD (**hpdocdod)[];
+extern typeCP cpMacCur;
+extern int vfSelHidden;
+extern struct WWD rgwwd[];
+extern int wwCur, wwMac;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern struct WWD *pwwdCur;
+extern int docCur;
+extern struct CHP (**vhgchpFormat)[];
+extern int vichpFormat;
+extern typeCP cpMinCur;
+extern typeCP cpMinDocument;
+extern int vfInsertOn;
+extern int vfTextBltValid;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern unsigned vpgn;
+extern struct SEP vsepAbs;
+extern CHAR stBuf[];
+extern typeCP CpEdge();
+extern typeCP CpMacText();
+extern int vdocPageCache;
+extern int vfPictSel;
+extern int vfAwfulNoise;
+extern int vfSkipNextBlink;
+extern int dypMax;
+extern HDC vhMDC;
+extern HWND vhWndPageInfo;
+extern struct FMI vfmiScreen;
+extern int docScrap;
+extern long rgbBkgrnd;
+extern long ropErase;
+extern BOOL vfMonochrome;
+extern int dxpbmMDC;
+extern int dypbmMDC;
+extern HBITMAP hbmNull;
+extern int vfOutOfMemory;
+extern int vfSeeSel;
+extern int vfInsEnd; /* Is insert point at end-of-line? */
+extern int vipgd;
+extern typeCP vcpMinPageCache;
+extern typeCP vcpMacPageCache;
+/* actual position of the cursor line */
+extern int vxpCursLine;
+extern int vypCursLine;
+
+extern int vdypCursLine;
+extern int vfScrollInval; /* means scroll did not take and UpdateWw must be repeated */
+extern BOOL vfDead;
+extern HRGN vhrgnClip;
+
+
+/* G L O B A L S
+int dlsMac = 0;*/
+#ifdef DBCS
+int donteat = 0; /* propagate not to eat message */
+#endif
+
+
+/* D I S P L A Y F L I */
+/* Display formatted line in window ww at line dl */
+
+
+DisplayFli(ww, dl, fDontDisplay)
+int ww;
+int dl;
+int fDontDisplay; /* True if we set up dl info but don't display */
+ {
+ typeCP dcp;
+ typeCP dcpMac;
+ struct WWD *pwwd = &rgwwd[ww];
+ HDC hDC = pwwd->hDC;
+ int xp; /* Current xp to write text */
+ int yp; /* Current yp to write text */
+ int xpMin = pwwd->xpMin; /* Minimum xp in window */
+ int xpMac = pwwd->xpMac; /* Maximum xp in window */
+ int ypLine; /* Screen yp for current line */
+ int dxp; /* Width of current run */
+ int dyp; /* Line height */
+ int dxpExtra; /* Width of pad for each space */
+ typeCP cpMin;
+ typeCP cpMac;
+ int xpSel; /* xp of the start of the selection */
+ int dxpSel = 0; /* Width of the selection. */
+ CHAR chMark = '\0'; /* style character */
+ struct CHP *pchp;
+ BOOL fTabsKludge = (vfli.ichLastTab >= 0);
+ BOOL fInsertOn = FALSE;
+ int cBreakRun; /* break characters in run (no relation to Dick or Jane) */
+
+#ifdef SMFONT
+ RECT rcOpaque;
+#endif /* SMFONT */
+
+#ifdef DDISP
+ CommSzNumNum(" DisplayFli: dl/fDontDisplay ", dl, fDontDisplay);
+#endif
+ Assert(ww >= 0 && ww < wwMax);
+#ifdef SMFONT
+ Assert(!fDontDisplay || vfli.fGraphics)
+#endif /* SMFONT */
+ Scribble(5,'D');
+
+ /* Fill up EDL and set some useful locals */
+ {
+ register struct EDL *pedl = &(**pwwd->hdndl)[dl];
+
+ if (dl == vdlIns)
+ {
+ /* Overwriting chars blted during fast insert; reset blt count */
+ vcchBlted = 0;
+ vidxpInsertCache = -1;
+ }
+
+ pedl->xpLeft = vfli.xpLeft;
+ pedl->xpMac = vfli.xpReal;
+ cpMin = pedl->cpMin = vfli.cpMin;
+ pedl->dcpMac = (cpMac = vfli.cpMac) - cpMin;
+ dyp = pedl->dyp = vfli.dypLine;
+ pedl->ichCpMin = vfli.ichCpMin;
+ pedl->dcpDepend = (cpMin == cpMac) ? 0xff : vfli.dcpDepend;
+ pedl->fValid = TRUE;
+ pedl->fGraphics = vfli.fGraphics;
+ pedl->fSplat = vfli.fSplat;
+
+ /* The position of current line equals the position of the previous line
+ + height of this line. */
+#ifdef SMFONT
+ pedl->yp = rcOpaque.bottom = dyp + (ypLine = rcOpaque.top = (dl == 0 ?
+ pwwd->ypMin : (pedl - 1)->yp));
+#else /* not SMFONT */
+ pedl->yp = dyp + (ypLine = (dl == 0 ? pwwd->ypMin :
+ (pedl - 1)->yp));
+#endif /* SMFONT */
+
+ if (pedl->fIchCpIncr = (vfli.ichCpMac != 0))
+ {
+ /* Look at final text column */
+ ++cpMac;
+
+ /* Since this is true, we can compress pedl->ichCpMac to 1 bit. */
+ Assert(vfli.ichCpMac == pedl->ichCpMin + 1);
+ }
+ }
+
+ if (vfli.doc == docNil)
+ {
+ /* This is the space beyond the end mark. */
+ PatBlt(hDC, 0, ypLine, xpMac, dyp, ropErase);
+ goto Finished;
+ }
+
+ /* Is there a character in the "style bar"? */
+ if (cpMin != cpMac)
+ {
+
+#ifdef CASHMERE
+ /* This line is not completely empty (not after the end mark); check for
+ painting marks on the style bar. */
+ if (cpMin == vcpFirstParaCache && vpapAbs.rhc != 0)
+ {
+ /* This is a running-head. */
+ chMark = chStatRH;
+ }
+ else if ((**hpdocdod)[vfli.doc].hpgtb != 0)
+#else /* not CASHMERE */
+ if (vpapAbs.rhc == 0 && (**hpdocdod)[vfli.doc].hpgtb != 0)
+#endif /* CASHMERE */
+
+ {
+ if (vdocPageCache != vfli.doc || cpMac > vcpMacPageCache || cpMac <=
+ vcpMinPageCache)
+ {
+ CachePage(vfli.doc, cpMac - 1);
+ }
+
+ /* We are now guaranteed that cpMac is within the cached page. */
+ if (cpMin <= vcpMinPageCache && (!vfli.fGraphics || vfli.ichCpMin ==
+ 0))
+ {
+ /* This is the first line of new page; show page mark. */
+ chMark = chStatPage;
+ }
+ }
+ }
+
+#ifdef SMFONT
+#ifdef DDISP
+ /* black out this line to test how efficiently/correctly we
+ overwrite pixels from previously-resident lines of text */
+ PatBlt(hDC, 0, ypLine, xpMac, dyp, BLACKNESS);
+ { long int i; for (i=0; i < 500000; i++) ; }
+#endif
+
+ /* Calculate dcpMac now, so we might be able to know how much to erase. */
+ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
+
+ /* Erase any character that might be in the style bar. */
+ dxp = xpSelBar + 1;
+ if (!vfli.fGraphics)
+ {
+ dxp = xpMac; // clear the whole line
+ }
+ PatBlt(hDC, 0, ypLine, dxp, dyp, ropErase);
+
+ /* If this is graphics then go draw any characters in the style bar. */
+ if (vfli.fGraphics)
+ {
+ goto DrawMark;
+ }
+
+ /* If there are no "real" characters on this line then we can skip alot of
+ this. */
+ if (dcpMac == 0)
+ {
+ goto EndLine2;
+ }
+#else /* not SMFONT */
+ if (vfli.fGraphics || fDontDisplay)
+ {
+ /* Erase any character that might be in the style bar. */
+ PatBlt(hDC, 0, ypLine, xpSelBar, dyp, ropErase);
+ goto DrawMark;
+ }
+#endif /* SMFONT */
+
+ ValidateMemoryDC();
+ if (vhMDC == NULL)
+ {
+Error:
+ /* Notify the user that an error has occured and simply erase this line.
+ */
+ WinFailure();
+ PatBlt(hDC, xpSelBar, ypLine, xpMac - xpSelBar, dyp, ropErase);
+ goto Finished;
+ }
+
+#ifndef SMFONT
+ /* Create a new bitmap for the memory DC if the current bitmap is not big
+ enough. */
+ if (xpMac > dxpbmMDC || dyp > dypbmMDC)
+ {
+ HBITMAP hbm;
+
+ /* If there is an old bitmap, then delete it. */
+ if (dxpbmMDC != 0 || dypbmMDC != 0)
+ {
+ DeleteObject(SelectObject(vhMDC, hbmNull));
+ }
+
+ /* Create the new bitmap and select it in. */
+ if ((hbm = CreateBitmap(dxpbmMDC = xpMac, dypbmMDC = dyp, 1, 1,
+ (LPSTR)NULL)) == NULL)
+ {
+ /* There should be a graceful way to recover if the bitmap is ever
+ NULL (e.g we don't have enough memory for it). */
+ dxpbmMDC = dypbmMDC = 0;
+ goto Error;
+ }
+ SelectObject(vhMDC, hbm);
+ }
+
+ /* Erase the are of the bitmap we are going to use. */
+ PatBlt(vhMDC, xpSelBar, 0, xpMac, dyp, vfMonochrome ? ropErase : WHITENESS);
+#endif /* not SMFONT */
+
+ /* Initialize some of the variables we'll need. */
+ pchp = &(**vhgchpFormat)[0];
+#ifdef SMFONT
+ xp = rcOpaque.left = rcOpaque.right = vfli.xpLeft + xpSelBar - xpMin + 1;
+#else /* not SMFONT */
+ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
+ xp = vfli.xpLeft + xpSelBar - xpMin + 1;
+#endif /* SMFONT */
+ dxpExtra = fTabsKludge ? 0 : vfli.dxpExtra;
+
+#ifdef SMFONT
+ /* If we are horizontally scrolled, then set the clip area to the area
+ outside of the selection bar. */
+ if (xpMin != 0)
+ {
+ IntersectClipRect(hDC, xpSelBar, rcOpaque.top, xpMac, rcOpaque.bottom);
+ }
+#endif /* SMFONT */
+
+ for (dcp = 0; dcp < dcpMac; pchp++)
+ {
+ /* For all runs do: */
+ int ichFirst; /* First character in the current run */
+ int cchRun; /* Number of characters in the current run */
+
+ dcp = ichFirst = pchp->ichRun;
+ dcp += pchp->cchRun;
+ if (dcp > dcpMac)
+ {
+ dcp = dcpMac;
+ }
+ cchRun = dcp - ichFirst;
+
+ /* Compute dxp = sum of width of characters in current run (formerly
+ DxaFromIcpDcp). */
+ {
+ register int *pdxp;
+ register int cchT = cchRun;
+ PCH pch = vfli.rgch + ichFirst;
+
+ dxp = cBreakRun = 0;
+ pdxp = &vfli.rgdxp[ichFirst];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+#ifdef DDISP
+ CommSzNum(" dxp=",dxp);
+#endif
+ }
+
+ if (dxp > 0)
+ {
+ int cchDone;
+ PCH pch = &vfli.rgch[ichFirst];
+
+ LoadFont(vfli.doc, pchp, mdFontScreen);
+ yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos <
+ hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) -
+ vfmiScreen.dypBaseline;
+
+ /* Note: tabs and other special characters are guaranteed to come at
+ the start of a run. */
+ SetTextJustification(vhMDC, dxpExtra * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ cchDone = 0;
+ while (cchDone < cchRun)
+ {
+ int cch;
+
+ /* Does the wide-space zone begin in this run? */
+ if (vfli.fAdjSpace && (vfli.ichFirstWide < ichFirst + cchRun) &&
+ (ichFirst + cchDone <= vfli.ichFirstWide))
+ {
+ int cchDoneT = cchDone;
+
+ /* Is this the beginning of the wide-space zone? */
+ if (ichFirst + cchDone == vfli.ichFirstWide)
+ {
+ /* Reset the width of the spaces. */
+ SetTextJustification(vhMDC, ++dxpExtra * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ cch = cchRun - cchDone;
+ cchDone = cchRun;
+ }
+ else
+ {
+ cchDone = cch = vfli.ichFirstWide - ichFirst;
+ }
+
+ /* This run is cut short because of a wide space, so we need
+ to calculate a new width. */
+ {
+ register int *pdxp;
+ register int cchT = cch;
+ PCH pch = &vfli.rgch[ichFirst + cchDoneT];
+
+ dxp = 0;
+ pdxp = &vfli.rgdxp[ichFirst + cchDoneT];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+ }
+ }
+ else
+ {
+ cchDone = cch = cchRun;
+ }
+
+ while (cch > 0)
+ {
+ switch (*pch)
+ {
+ CHAR ch;
+ int dxpT;
+
+ case chTab:
+
+#ifdef CASHMERE
+ /* chLeader contains tab leader character (see
+ FormatLine) */
+ if ((ch = pchp->chLeader) != chSpace)
+ {
+ int cxpTab;
+ CHAR rgch[32];
+ int dxpLeader = CharWidth(ch);
+ int xpT = xp;
+ int iLevelT = SaveDC(vhMDC);
+
+ SetBytes(&rgch[0], ch, 32);
+ dxpT = vfli.rgdxp[ichFirst];
+ cxpTab = ((dxpT + dxpLeader - 1) / dxpLeader + 31)
+ >> 5;
+
+ xp += dxpT;
+
+ while (cxpTab-- > 0)
+ {
+ TextOut(vhMDC, xpT, yp, (LPSTR)rgch, 32);
+ xpT += dxpLeader << 5;
+ }
+ RestoreDC(vhMDC, iLevelT);
+ }
+ else
+#endif /* CASHMERE */
+
+ {
+#ifdef SMFONT
+ /* Expand the opaque rectangle to include the tab.
+ */
+ rcOpaque.right += vfli.rgdxp[ichFirst];
+#endif /* SMFONT */
+ xp += vfli.rgdxp[ichFirst];
+ }
+
+ if (fTabsKludge && ichFirst >= vfli.ichLastTab)
+ {
+ SetTextJustification(vhMDC, (dxpExtra =
+ vfli.dxpExtra) * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ fTabsKludge = FALSE;
+ }
+ dxp -= vfli.rgdxp[ichFirst];
+ pch++;
+ cch--;
+ goto EndLoop;
+
+#ifdef CASHMERE
+ case schPage:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpPgn(&stBuf[1], vpgn, vsepAbs.nfcPgn,
+ flmSandMode, ichMaxLine);
+ goto DrawSpecial;
+
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpFtn(&stBuf[1], cpMin + ichFirst,
+ flmSandMode, ichMaxLine);
+DrawSpecial:
+#else /* not CASHMERE */
+ case schPage:
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = *pch == schPage && (wwdCurrentDoc.fEditHeader
+ || wwdCurrentDoc.fEditFooter) ? CchExpPgn(&stBuf[1],
+ vpgn, 0, flmSandMode, ichMaxLine) :
+ CchExpUnknown(&stBuf[1], flmSandMode, ichMaxLine);
+#endif /* not CASHMERE */
+
+#ifdef SMFONT
+ /* Calculate the opaque rectangle. */
+ rcOpaque.right += vfli.rgdxp[ichFirst] +
+ vfmiScreen.dxpOverhang;
+
+ TextOut(hDC, xp, ypLine+yp, &stBuf[1], stBuf[0]);
+#else /* not SMFONT */
+ TextOut(vhMDC, xp, yp, (LPSTR)&stBuf[1], stBuf[0]);
+#endif /* SMFONT */
+ break;
+
+#ifdef DBCS
+ case chMark1:
+ if(*(pch+1) == chEMark)
+ { /* This run only contains EndMark */
+ rcOpaque.right += dxp + vfmiScreen.dxpOverhang;
+ ExtTextOut(hDC, xp, (yp>0?(ypLine+yp):ypLine),
+ 2, (LPRECT)&rcOpaque,(LPSTR)pch, cch, (LPSTR)NULL);
+ pch += cch;
+ cch = 0;
+ xp += dxp;
+ rcOpaque.left
+ = (rcOpaque.right = xp) + vfmiScreen.dxpOverhang;
+ }
+ /* else fall through */
+#endif
+ default:
+ goto EndLoop;
+ }
+
+ dxp -= vfli.rgdxp[ichFirst];
+#ifdef SMFONT
+ /* End the line if no more will fit into the window. */
+ if ((xp += vfli.rgdxp[ichFirst++]) >= xpMac) {
+ goto EndLine;
+ }
+ rcOpaque.left = (rcOpaque.right = xp) +
+ vfmiScreen.dxpOverhang;
+#else /* not SMFONT */
+ xp += vfli.rgdxp[ichFirst++];
+#endif /* SMFONT */
+ pch++;
+ cch--;
+ }
+EndLoop:
+
+#ifdef SMFONT
+ if (cch == 0)
+ {
+ Assert(dxp == 0);
+ }
+ else
+ {
+ /* Calculate the opaque rectangle. */
+ rcOpaque.right += dxp + vfmiScreen.dxpOverhang;
+
+#if 0
+ {
+ char msg[180];
+ wsprintf(msg,"putting out %d characters\n\r",cch);
+ OutputDebugString(msg);
+ }
+#endif
+ /* Output cch characters starting at pch */
+ TextOut(hDC, xp, ypLine+yp, pch, cch);
+
+ /* End the line if no more will fit into the window. */
+ if ((xp += dxp) >= xpMac)
+ {
+ goto EndLine;
+ }
+ rcOpaque.left = (rcOpaque.right = xp) +
+ vfmiScreen.dxpOverhang;
+ pch += cch;
+ }
+#else /* not SMFONT */
+ /* Output cch characters starting at pch */
+ TextOut(vhMDC, xp, yp, (LPSTR)pch, cch);
+ xp += dxp;
+ pch += cch;
+#endif /* SMFONT */
+ } /* end while (cchDone<cchRun) */
+ } /* end if (dxp>0) */
+ } /* end for dcp=0..dcpMac */
+
+#ifdef SMFONT
+EndLine:
+ /* Restore the clip region if need be. */
+ if (xpMin != 0)
+ {
+ SelectClipRgn(hDC, NULL);
+ }
+EndLine2:
+#endif /* SMFONT */
+
+#ifdef CASHMERE
+ if (vfVisiMode)
+ {
+ AddVisiSpaces(ww, &(**pwwd->hdndl)[dl], vfli.dypBase, vfli.dypAfter +
+ vfli.dypFont);
+ }
+#endif /* CASHMERE */
+
+ vfTextBltValid = FALSE;
+
+ if ((ww == wwCur) && (pwwd->doc != docScrap) && !vfSelHidden &&
+ (selCur.cpLim >= cpMin))
+ {
+ if (selCur.cpFirst <= cpMac)
+ {
+ /* Show selection */
+ int xpFirst;
+ int xpLim;
+
+#ifdef ENABLE
+ if (vfli.fSplatNext && selCur.cpFirst == selCur.cpLim &&
+ selCur.cpFirst == cpMac)
+ {
+ vfInsEnd = TRUE;
+ ClearInsertLine();
+ }
+ vfInsertOn = FALSE;
+#endif /* ENABLE */
+
+ if (selCur.cpFirst <= cpMin && selCur.cpLim >= cpMac)
+ {
+ xpFirst = vfli.xpLeft;
+ xpLim = vfli.xpReal;
+ }
+ else if (selCur.cpFirst < cpMac || (selCur.cpLim == cpMac &&
+ vfInsEnd))
+ {
+ typeCP cpBegin = CpMax(cpMin, selCur.cpFirst);
+ typeCP cpEnd = CpMin(cpMac, selCur.cpLim);
+
+ dxp = DxpDiff((int)(cpBegin - cpMin), (int)(cpEnd - cpBegin),
+ &xpFirst);
+ xpLim = min(xpMin + vfli.xpReal, xpFirst + dxp);
+ }
+ else
+ {
+ goto DidntHighlight;
+ }
+
+ xpSel = xpSelBar + max(xpFirst - xpMin, 0);
+ if (xpLim > xpFirst)
+ {
+ /* Set highlighting at desired screen position. */
+ dxpSel = max(xpLim - max(xpFirst, xpMin), 0);
+ }
+ else if (selCur.cpFirst == selCur.cpLim && ((selCur.cpLim != cpMac)
+ ^ vfInsEnd))
+ {
+ vfInsertOn = FALSE; /* Because we redisplayed insert pt line */
+
+#ifdef CASHMERE
+ vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
+ vypCursLine = ypLine + dyp - vfli.dypAfter;
+#else /* not CASHMERE */
+
+#ifdef DBCS // Some double byte fonts have bigger character
+ // face than the line hight.
+ vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
+#else
+ vdypCursLine = vfli.dypFont;
+#endif
+
+ vypCursLine = ypLine + dyp;
+#endif /* not CASHMERE */
+
+ vxpCursLine = xpSel;
+
+ /* Start blinking in a while */
+ vfSkipNextBlink = TRUE;
+
+ fInsertOn = xpFirst >= xpMin;
+ }
+
+DidntHighlight:;
+ }
+ }
+
+#ifdef SMFONT
+ /* Invert the selection */
+ if (dxpSel != 0) {
+ PatBlt(hDC, xpSel, ypLine, dxpSel, dyp, DSTINVERT);
+ }
+#else /* not SMFONT */
+ /* Blt the line of text onto the screen. */
+ PatBlt(vhMDC, 0, 0, xpSelBar, dyp, vfMonochrome ? ropErase : WHITENESS);
+ if (dxpSel == 0)
+ {
+ BitBlt(hDC, 0, ypLine, xpMac, dyp, vhMDC, 0, 0, SRCCOPY);
+ }
+ else
+ {
+ BitBlt(hDC, 0, ypLine, xpSel, dyp, vhMDC, 0, 0, SRCCOPY);
+ BitBlt(hDC, xpSel, ypLine, dxpSel, dyp, vhMDC, xpSel, 0, NOTSRCCOPY);
+ xpSel += dxpSel;
+ BitBlt(hDC, xpSel, ypLine, xpMac - xpSel, dyp, vhMDC, xpSel, 0,
+ SRCCOPY);
+ }
+#endif /* SMFONT */
+
+ /* Draw the insertion bar if necessary. */
+ if (fInsertOn)
+ {
+ DrawInsertLine();
+ }
+#if defined(JAPAN) & defined(DBCS_IME) // Set a flag for IME management.
+ else
+ {
+ bClearCall = TRUE;
+ }
+#endif
+
+DrawMark:
+ /* Draw the character in the style bar if necessary. */
+ if (chMark != '\0')
+ {
+#ifdef SYSENDMARK
+
+#ifdef DBCS // prepare buf for double-byte end mark.
+ CHAR rgch[cchKanji];
+#endif
+
+ struct CHP chpT;
+ extern struct CHP vchpNormal;
+
+ blt(&vchpNormal, &chpT, cwCHP);
+ chpT.ftc = ftcSystem;
+ chpT.ftcXtra = 0;
+ chpT.hps = hpsDefault;
+
+ /* Draw the style character in the standard font. */
+ LoadFont(vfli.doc, &chpT, mdFontScreen);
+
+#ifdef DBCS // we use double byte end mark.
+ rgch[0] = chMark1;
+ rgch[1] = chMark;
+
+ rcOpaque.left = 0;
+ rcOpaque.right = DxpFromCh(chMark1,FALSE);
+ rcOpaque.top = ypLine;
+ rcOpaque.bottom = ypLine+dyp;
+
+ /* When this line string is lower than system font,it remains dust,
+ so we must clip this mark. */
+ ExtTextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
+ ETO_CLIPPED, (LPRECT)&rcOpaque,(LPSTR)rgch, cchKanji, (LPSTR)NULL);
+#else
+
+ TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
+ (LPSTR)&chMark, 1);
+#endif /* DBCS */
+
+#else /* ifdef SYSENDMARK */
+ /* Draw the style character in the standard font. */
+ LoadFont(vfli.doc, NULL, mdFontScreen);
+ TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
+ (LPSTR)&chMark, 1);
+#endif /* if-else-def SYSENDMARK */
+ }
+
+ if (vfli.fGraphics)
+ {
+ DisplayGraphics(ww, dl, fDontDisplay);
+ }
+
+Finished:
+ Scribble(5,' ');
+ }
+
+
+/* D X P D I F F */
+DxpDiff(dcpFirst, dcp, pdxpFirst)
+int dcpFirst;
+int dcp;
+int *pdxpFirst;
+{
+#if 1
+ register int *pdxp = &vfli.rgdxp[0];
+ register int cch;
+ int dxp = vfli.xpLeft;
+#ifdef ENABLE /* Not used */
+ int ichLim = dcpFirst + dcp;
+#endif
+
+
+ if (dcp > vfli.ichMac - dcpFirst)
+ { /* This should not be, but is when we have a CR */
+ //Assert( dcpFirst < vfli.ichMac );
+ dcp = vfli.ichMac - dcpFirst;
+ }
+
+ for (cch = 0; cch < dcpFirst; ++cch)
+ {
+ dxp += *pdxp++;
+ }
+ *pdxpFirst = dxp;
+ dxp = 0;
+ for (cch = 0; cch < dcp; ++cch)
+ {
+ dxp += *pdxp++;
+ }
+ return dxp;
+#else
+
+ int dxp;
+ if (dcp > vfli.ichMac - dcpFirst)
+ { /* This should not be, but is when we have a CR */
+ Assert( dcpFirst < vfli.ichMac );
+ dcp = vfli.ichMac - dcpFirst;
+ }
+
+ /* first get space up to first character */
+ *pdxpFirst = LOWORD(GetTextExtent(hDC,vfli.rgch,dcpFirst)) + vfli.xpLeft;
+
+ /* now get space between first and first+dcp */
+ dxp = LOWORD(GetTextExtent(hDC,vfli.rgch+dcpFirst,dcp));
+ return dxp;
+#endif
+}
+
+
+UpdateDisplay(fAbortOK)
+int fAbortOK;
+{
+ int ww;
+
+ if (wwMac <= 0)
+ {
+ return;
+ }
+
+#ifdef CASHMERE
+ for (ww = 0; ww < wwMac; ww++)
+ if ( rgwwd[ww].doc != docScrap )
+ {
+ UpdateWw(ww, fAbortOK);
+ if (rgwwd[ww].fDirty || vfOutOfMemory)
+ {
+ return; /* update has been interrupted */
+ }
+ }
+#else /* not CASHMERE */
+ UpdateWw(wwDocument, fAbortOK);
+ if (wwdCurrentDoc.fDirty || vfOutOfMemory)
+ {
+ /* Update has been interrupted */
+ return;
+ }
+#endif /* not CASHMERE */
+
+ if (wwdCurrentDoc.fRuler)
+ {
+ UpdateRuler();
+ }
+}
+
+
+/* U P D A T E W W */
+UpdateWw(ww, fAbortOK)
+int ww, fAbortOK;
+{ /* Redisplay ww as necessary */
+ extern int vfWholePictInvalid;
+ register struct WWD *pwwd = &rgwwd[ww];
+ int dlMac;
+ int dlOld, dlNew;
+ int doc;
+ int ichCp;
+ struct EDL *pedlNew;
+ register struct EDL *pedl;
+ struct EDL (**hdndl)[]=pwwd->hdndl;
+ int dypDiff;
+ int ypTop;
+ int ypFirstInval;
+ int dr;
+ int fLastNotShown;
+ typeCP cp, cpMacWw;
+
+ if (!pwwd->fDirty)
+ {
+ return;
+ }
+
+ if (!((**hpdocdod)[pwwd->doc].fDisplayable))
+ return;
+
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+#if 0 // how to get first and last cp's in invalid rect?
+#if defined(OLE)
+ /*
+ Load visible objects. Do it now rather than in DisplayGraphics()
+ because here it has less chance of disrupting the state variables
+ upon which UpdateWw depends.
+ */
+ ObjEnumInRange(docCur,cpMinCur,cpMacCur,ObjLoadObjectInDoc);
+#endif
+#endif
+
+ dlMac = pwwd->dlMac;
+ ypTop = pwwd->ypMin;
+
+ Assert( ww >= 0 && ww < wwMax );
+ vfli.doc = docNil; /* An aid to Fast Insert */
+
+ UpdateInvalid(); /* InvalBand for what Windows considers to be invalid */
+ ypFirstInval = pwwd->ypFirstInval;
+
+#ifndef CASHMERE
+ Assert( ww == wwCur ); /* A MEMO-only assumption */
+#endif /* CASHMERE */
+
+ Scribble(5, 'U');
+
+ ValidateMemoryDC(); /* to do any update, we need a good memory DC */
+ if (vhMDC == NULL)
+ {
+ WinFailure();
+ return;
+ }
+
+ doc = pwwd->doc;
+ vfli.doc = docNil;
+
+ if (pwwd->fCpBad)
+ {
+/* cp first displayed has not been blessed */
+
+#ifdef CASHMERE /* Must do this if ww != wwCur assertion is FALSE */
+ int wwT = wwCur;
+ if (ww != wwCur && wwCur >= 0)
+/* CtrBackTrs cache is only good for wwCur. Treat != case */
+ {
+ if (pwwdCur->fDirty) /* Do wwCur first, saving cache */
+ UpdateWw(wwCur, fAbortOK);
+
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+ ChangeWw(ww, false);
+ CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
+ ChangeWw(wwT, false);
+ }
+ else
+#endif /* CASHMERE */
+
+ {
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+ CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
+ }
+ }
+
+/* check for cpMin accessible in this ww */
+RestartUpdate:
+ vfWholePictInvalid = fTrue; /* Tells DisplayGraphics to
+ abandon accumulated partial pict rect */
+ fLastNotShown = fFalse;
+ cp = CpMax(pwwd->cpMin, pwwd->cpFirst);
+ cpMacWw = pwwd->cpMac;
+ ichCp = pwwd->ichCpFirst;
+
+ /* Note test for dlNew==0 that guarantees that there will be at least
+ one dl -- this was added for WRITE because we do not have
+ the ability to enforce a minimum window size */
+
+ for (dlNew = dlOld = 0; ypTop < pwwd->ypMac || (dlNew == 0) ; dlNew++)
+ /* we have: cp, ichCP: pints to text desired on the coming line dlNew
+ ypTop: desired position for top of dlNew -1
+ dlOld: next line to be considered for re-use
+ */
+ /* check for having to extend dndl array */
+ {
+ if (dlNew >= (int)pwwd->dlMax)
+ {
+/* extend the array with uninitialized dl's, increment max, break if no space.
+We assume that dlMac(Old) was <= dlMax, so the dl's will not be looked at
+but used only to store new lines */
+#define ddlIncr 5
+
+ if (!FChngSizeH(hdndl, (pwwd->dlMax + ddlIncr) * cwEDL, fFalse))
+ break;
+ pwwd->dlMax += ddlIncr;
+ }
+/* discard unusable dl's */
+ for (; dlOld < dlMac; dlOld++)
+ { /* Set dlOld and pedl to the next good dl */
+ int ypTopOld, ypOld;
+
+ /* Re-entrant Heap Movement */
+ if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
+ goto RetInval;
+
+ pedl = &(**hdndl)[dlOld];
+ ypOld = pedl->yp;
+
+/* loop if: invalid, passed over in cp space, passed over in dl space,
+passed over in yp space,
+in invalid band, passed over in ich space */
+ if (!pedl->fValid || dlOld < dlNew || pedl->cpMin < cp
+ || (ypTopOld = (ypOld - pedl->dyp)) < ypTop
+ || (ypOld >= ypFirstInval && ypTopOld <= pwwd->ypLastInval)
+ || (pedl->cpMin == cp && pedl->ichCpMin < ichCp))
+ continue;
+/* now we have dlOld, an acceptable if not necessarily useful dl.
+now compute dlNew either from scratch or by re-using dlOld. To be
+re-useable, dlOld must have right cp/ichCp pair, plus be totally on screen
+or, if it is a partial line, it must stay still or move down - not up */
+ if (pedl->cpMin == cp && pedl->ichCpMin == ichCp &&
+ (ypOld <= pwwd->ypMac || ypTopOld <= ypTop))
+ {
+/* Re-use this dl */
+ int yp = ypTop;
+ if (fLastNotShown)
+ {
+ /* HEAP MOVEMENT */
+ DisplayFli(ww, dlNew - 1, fLastNotShown = fFalse);
+ pedl = &(**hdndl)[dlOld];
+ }
+
+ cp = pedl->cpMin + pedl->dcpMac;
+ ichCp = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0;
+ ypTop += pedl->dyp;
+ if (dlOld != dlNew || ypTopOld != yp)
+ {
+ DypScroll(ww, dlOld, dlNew - dlOld, yp);
+ if (vfScrollInval)
+ {
+ /* There was a popup; invalid region might have changed */
+ /* fLastNotShown test is for interrupting picture display */
+ /* before we've really displayed it */
+
+ (**hdndl) [dlOld].fValid = fFalse;
+ goto Restart1;
+ }
+ dlMac += dlNew - dlOld;
+ }
+ dlOld = dlNew + 1;
+ goto NextDlNew;
+ }
+ break;
+ }
+/* cpMin > cp, the line is not anywhere so it will have to be formatted
+from scratch */
+
+ if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
+ goto RetInval;
+
+ FormatLine(doc, cp, ichCp, cpMacWw, flmSandMode); /* Creates vfli */
+
+ if (vfOutOfMemory)
+ goto RetInval;
+
+ ichCp = vfli.ichCpMac;
+ cp = vfli.cpMac;
+/* advance invalid band so that update can resume after an interruption */
+ pwwd->ypFirstInval = (ypTop += vfli.dypLine);
+ pedl = &(**hdndl)[dlOld];
+ if (dlOld < dlMac && pedl->cpMin == cp && pedl->ichCpMin == ichCp)
+ {
+ int dlT = dlOld;
+
+/* line at dlOld is a valid, existing line that will abutt the line just about
+to be displayed. */
+ if (dlOld == dlNew && pedl->yp - pedl->dyp <= ypTop)
+/* the line about to be overwritten will be re-used in the next loop.
+Hence, it is worthwhile to save this line and its dl */
+ DypScroll(ww, dlOld++, 1, ypTop);
+ else
+/* Move the next line to its abutting position. We know that it has not yet been
+overwritten (yp, dlOld all > than ypTop, dlNew) */
+ DypScroll(ww, dlOld, 0, ypTop);
+
+ if (vfScrollInval)
+ {
+ /* There was a popup; invalid region might have changed */
+ /* fLastNotShown test is for interrupting picture display */
+ /* before we've really displayed it */
+
+ (**hdndl) [dlT].fValid = fFalse;
+Restart1:
+ if (fLastNotShown)
+ {
+ pwwd->ypFirstInval = pwwd->ypMin;
+ }
+
+ ypFirstInval = pwwd->ypFirstInval;
+ ypTop = pwwd->ypMin;
+ goto RestartUpdate;
+ }
+ }
+
+/* true in 3rd param means put off picture redisplay till later */
+/* condition: graphics & not last in picture & not last in y space and
+not in front of a invalid or valid transition in the picture */
+ DisplayFli(ww, dlNew, fLastNotShown =
+ (vfli.fGraphics && vfli.ichCpMac!=0 && ypTop < pwwd->ypMac));
+NextDlNew:;
+ }
+Break1:
+ pwwd->dlMac = dlNew;
+
+#ifdef CASHMERE
+/* condition is here to avoid swapping */
+ if (pwwd->fSplit && rgwwd[pwwd->ww].fFtn)
+ CalcFtnLimits(pwwd);
+#endif /* CASHMERE */
+
+ SetCurWwVScrollPos(); /* Set Scroll bar position */
+ vfTextBltValid = false;
+
+/* reset invalid indications */
+ pwwd->fDirty = false;
+ pwwd->ypFirstInval = ypMaxAll;
+ pwwd->ypLastInval = 0; /* so that max in InvalBand will work */
+ Scribble(5, ' ');
+ goto Validate;
+
+/* Before returning from an interrupt, invalidate lines that were overwritten
+within the present update. */
+RetInval:
+ Scribble(5, ' ');
+ for (; dlOld < dlMac; dlOld++)
+ {
+ pedl = &(**hdndl)[dlOld];
+ if ((pedl->yp - pedl->dyp) < ypTop)
+ pedl->fValid = fFalse;
+ else
+ break;
+ }
+Validate: ;
+
+#ifdef ENABLE /* We will let UpdateInvalid handle this in case
+ further invalidation occurred during the update */
+
+ { /* Tell Windows that the part we updated is valid */
+ RECT rc;
+
+ rc.left = 0;
+ rc.top = pwwd->ypMin;
+ rc.right = pwwd->xpMac;
+ rc.bottom = imin( pwwd->ypMac, ypTop );
+ ValidateRect( pwwd->wwptr, (LPRECT)&rc );
+ }
+#endif
+}
+
+
+
+
+/* D Y P S C R O L L */
+DypScroll(ww, dlFirst, ddl, ypTo)
+int ww, dlFirst, ddl, ypTo;
+{
+/* Scroll dl's in a window, from dlFirst to end, down ddl lines (or up -ddl).
+Bitmap is moved from top of dlFirst to ypTo. The yp's of the dl's are updated.
+Returns the amount scrolled. (positive means down). */
+
+ register struct WWD *pwwd = &rgwwd[ww];
+ int dlMac;
+ int dlT;
+ int ypFrom;
+ int dypChange;
+ int cdlBelow;
+ struct EDL *pedl;
+ struct EDL *pedlT;
+
+ /* Do not call procedures while dndl is loaded up to avoid heap movement */
+ struct EDL *dndl = &(**(pwwd->hdndl))[0];
+
+ Assert( ww >= 0 && ww < wwMax );
+
+ vfScrollInval = fFalse;
+
+ /* Number of dl's below (and including) the first one to be scrolled */
+ cdlBelow = pwwd->dlMac - dlFirst;
+ pwwd->dlMac = min(pwwd->dlMac + ddl, pwwd->dlMax);
+ cdlBelow = max(0, min(cdlBelow, pwwd->dlMac - ddl - dlFirst));
+
+ pedlT = &dndl[dlFirst];
+ ypFrom = pedlT->yp - pedlT->dyp;
+
+ /* Length of area to be moved */
+ dypChange = ypTo - ypFrom;
+
+ if (cdlBelow > 0)
+ {
+ int dlTo = dlFirst + ddl;
+ int ypMac = pwwd->ypMac;
+
+ pedlT = &dndl[dlTo];
+ if (ddl != 0)
+ {
+ blt(&dndl[dlFirst], pedlT, cwEDL * cdlBelow);
+ }
+
+ for (dlT = dlTo; dlT < pwwd->dlMac; ++dlT, ++pedlT)
+ {
+ if (dypChange < 0 && pedlT->yp > ypMac)
+ {
+ /* Invalidate dl's that are pulled in from the ozone below ypMac
+ */
+ pedlT->fValid = fFalse;
+ }
+ else
+ {
+ pedlT->yp += dypChange;
+ }
+ }
+ }
+
+ if (dypChange != 0)
+ {
+ RECT rc;
+
+ SetRect( (LPRECT)&rc, 0, min(ypFrom, ypTo),
+ pwwd->xpMac, pwwd->ypMac );
+ Assert( ww == wwCur ); /* A MEMO-only assumption */
+ ScrollCurWw( &rc, 0, dypChange );
+ }
+
+ return dypChange;
+}
+
+
+
+
+FImportantMsgPresent()
+{
+ /* If the next message is important enough to interrupt a screen update, we
+ return TRUE; if it can wait, we return FALSE */
+
+ BOOL fToggledKey;
+ extern MSG vmsgLast;
+
+#ifdef DEBUG
+ unsigned wHeapVal = *(pLocalHeap + 1);
+
+ Assert( wHeapVal == 0 ); /* Heap should not be frozen */
+#endif
+
+#ifdef DBCS
+ if( donteat )
+ return TRUE;
+#endif
+
+while (PeekMessage((LPMSG) &vmsgLast, NULL, NULL, NULL, PM_NOREMOVE))
+ {
+#if defined(JAPAN) & defined(DBCS_IME)
+/* If IME Cnv window open,we have to avoid ourselves to get into AlphaMode.
+** So we do getmessage here to fill vmsgLast with app queue message.
+*/
+ extern BOOL bImeCnvOpen;
+
+ if( bImeCnvOpen ) {
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+ donteat = TRUE;
+ return TRUE;
+ }
+#endif
+ /* Filter uninteresting or easily handled events */
+ if (fToggledKey = FCheckToggleKeyMessage(&vmsgLast) ||
+ (vmsgLast.message == WM_KEYUP && vmsgLast.hwnd == wwdCurrentDoc.wwptr))
+ {
+
+ if (((vmsgLast.wParam == VK_MENU) || (vmsgLast.wParam == VK_CONTROL)))
+ return TRUE;
+
+ /* This is so the Windows keyboard interface mechanism will see toggle
+ key and key-up transitions */
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+#ifdef WIN30
+ /* PeekMessage has been changed in Win 3.0 so that GetKeyState()
+ called from FCheckToggleKeyMessage() is really only valid if
+ you've done a PeekMessage(...,PM_REMOVE) or GetMessage() first.
+ That is, while the FCheckToggleKeyMessage() call might succeed
+ above, it will NOT have set the vfShiftKey/vfCommandKey flags
+ correctly -- so we do it here ..pault */
+ if (fToggledKey)
+ FCheckToggleKeyMessage(&vmsgLast);
+#endif
+ if (vmsgLast.hwnd != wwdCurrentDoc.wwptr)
+ {
+ /* Just in case a modeless dialog's window proc cares */
+ TranslateMessage((LPMSG)&vmsgLast);
+ DispatchMessage((LPMSG)&vmsgLast);
+ }
+#ifdef DBCS /* I hate it */
+ if (vmsgLast.message == WM_CHAR
+#ifdef JAPAN
+ // We've been reported by one of OEM about LED not disapearing
+ // problem.
+ // they know it is bug of write. So I added this code from win2.x
+ // write source. 27 sep 91 Yutakan
+ || (vmsgLast.message == WM_KEYUP && vmsgLast.wParam == VK_KANA)
+#endif
+#ifdef KOREA
+ || vmsgLast.message == WM_INTERIM
+#endif
+ || vmsgLast.message == WM_KEYDOWN) {
+
+ donteat = TRUE;
+ return( TRUE );
+ } /* else Ok, you are KEYUP message. do normal */
+#endif
+ }
+ else
+ {
+ switch (vmsgLast.message)
+ {
+ case WM_MOUSEMOVE:
+#ifdef KOREA
+ case WM_NCMOUSEMOVE:
+#endif
+ /* Process mouse move messages immediately; they are not really
+ important. NOTE: This assumes that we have not captured all mouse
+ events; in which case, they are important. */
+ DispatchMessage((LPMSG)&vmsgLast);
+
+ case WM_TIMER:
+ case WM_SYSTIMER:
+ /* Remove timer and mouse move messages from the queue. */
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+ break;
+
+ default:
+ Assert( *(pLocalHeap+1) == 0 ); /* Heap should still not be frozen */
+ return (TRUE);
+ }
+ }
+ }
+
+
+Assert( *(pLocalHeap + 1) == 0 ); /* Heap should still not be frozen */
+return (FALSE);
+}
+
+
+/* C P B E G I N L I N E */
+typeCP CpBeginLine(pdl, cp)
+int *pdl;
+typeCP cp;
+ { /* return the cp and dl containing cp */
+ int dlMin, dlLim;
+ typeCP cpGuess;
+ struct EDL *dndl;
+
+ do
+ {
+ UpdateWw(wwCur, false);
+ PutCpInWwVert(cp); /* Ensure cp on screen */
+ } while (pwwdCur->fDirty && !vfOutOfMemory);
+
+ dndl = &(**(pwwdCur->hdndl))[0];
+ dlMin = 0;
+ dlLim = pwwdCur->dlMac;
+ while (dlMin + 1 < dlLim)
+ { /* Binary search the ww */
+ int dlGuess = (dlMin + dlLim) >> 1;
+ struct EDL *pedl = &dndl[dlGuess];
+ if ((cpGuess = pedl->cpMin) <= cp && (cpGuess != cp || pedl->ichCpMin == 0))
+ { /* guess is low or right */
+ dlMin = dlGuess;
+ if (cp == cpGuess && pedl->cpMin + pedl->dcpMac != cp)
+ break; /* Got it right */
+ }
+ else /* Guess is high */
+ dlLim = dlGuess;
+ }
+ *pdl = dlMin;
+ return dndl[dlMin].cpMin;
+}
+
+
+
+
+/* T O G G L E S E L */
+ToggleSel(cpFirst, cpLim, fOn)
+typeCP cpFirst, cpLim; /* selection bounds */
+int fOn;
+{ /* Flip selection highlighting on and off */
+ extern int vfPMS;
+ struct EDL *pedl;
+ int dlT;
+ int xpMin;
+ int dxpRoom;
+ int xpFirst;
+ int xpLim;
+ int fInsertPoint = (cpFirst == cpLim);
+
+ if (vfSelHidden || cpFirst > cpLim || cpLim < /*cp0*/ cpMinCur || vfDead)
+ return;
+
+ if ( vfPictSel && vfPMS &&
+ (CachePara( docCur, cpFirst ), vpapAbs.fGraphics) &&
+ (vcpLimParaCache == cpLim) )
+ { /* Don't show inversion if we're moving or sizing a picture */
+ return;
+ }
+
+ dxpRoom = pwwdCur->xpMac - xpSelBar;
+ xpMin = pwwdCur->xpMin;
+
+ for (dlT = 0; dlT < pwwdCur->dlMac; dlT++)
+ {
+ typeCP cpMin, cpMac; /* line bounds */
+ pedl = &(**(pwwdCur->hdndl))[dlT];
+ if (!pedl->fValid)
+ continue;
+ cpMin = pedl->cpMin;
+ if (cpMin > cpLim || cpMin > cpMacCur || (cpMin == cpLim && cpLim != cpFirst))
+ break;
+ cpMac = cpMin + pedl->dcpMac;
+ if (cpFirst <= cpMin && cpLim >= cpMac)
+ {
+/* entire line is highlighted */
+ xpFirst = pedl->xpLeft;
+ if (pedl->fGraphics && cpLim == cpMac && cpMin == cpMac)
+ /* Special kludge for graphics paras */
+ xpLim = xpFirst;
+ else
+ xpLim = pedl->xpMac;
+ }
+ else if (fInsertPoint && cpFirst == cpMac && vfInsEnd)
+ { /* Special kludge for an insert point at the end of a line */
+ xpLim = xpFirst = pedl->xpMac;
+ }
+ else if (cpFirst < cpMac)
+ {
+ /* Bite the bullet */
+ int dxp;
+ typeCP cpBegin = CpMax(cpMin, cpFirst);
+ typeCP cpEnd = CpMin(cpMac, cpLim);
+
+ FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
+ dxp = DxpDiff((int) (cpBegin - cpMin),
+ (int) (cpEnd - cpBegin), &xpFirst);
+ xpLim = xpFirst + dxp;
+/* reload pedl because procedures were called */
+ pedl = &(**(pwwdCur->hdndl))[dlT];
+ }
+ else
+ continue;
+/* now we have: pedl valid, xpFirst, xpLast describe highlight */
+ /* xpFirst = max(xpFirst, xpMin); */
+ xpLim = min(xpLim, xpMin + pedl->xpMac);
+ if (xpLim > xpFirst)
+ {
+ if (xpLim > xpMin)
+ {
+ RECT rc;
+ rc.top = pedl->yp - pedl->dyp;
+ rc.left = xpSelBar + max(xpFirst - xpMin, 0);
+ rc.bottom = pedl->yp;
+ rc.right = xpSelBar + xpLim - xpMin;
+ InvertRect( wwdCurrentDoc.hDC, (LPRECT)&rc);
+ }
+ }
+/* ToggleSel modified 7/28/85 -- added explicit check for fInsertPoint, since
+ the xpLim == xpFirst test sometimes succeeded bogusly when a selection
+ was extended backwards. BL */
+ else if (fInsertPoint && (xpLim == xpFirst)) /* Insertion point */
+ {
+ /* vfli should usually be cached already, so will be fast. */
+ int yp = pedl->yp;
+ FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
+ if (fOn ^ vfInsertOn)
+ {
+ if (!vfInsertOn)
+ {
+ vxpCursLine = xpSelBar + xpFirst - xpMin;
+ vypCursLine = yp - vfli.dypAfter;
+ vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
+
+ /* Start blinking in a while */
+ vfSkipNextBlink = TRUE;
+ }
+ DrawInsertLine();
+ }
+ return;
+ }
+ }
+}
+
+
+
+
+/* T R A S H W W */
+TrashWw(ww)
+{ /* Invalidate all dl's in ww */
+ Assert( ww >= 0 && ww < wwMax );
+ InvalBand(&rgwwd[ww], 0, ypMaxAll);
+}
+
+
+
+
+/* I N V A L B A N D */
+/* invalidate the band ypFirst, ypLast inclusive */
+InvalBand(pwwd, ypFirst, ypLast)
+struct WWD *pwwd; int ypFirst, ypLast;
+ {
+/* this covers some peculiar rects received from update event after a
+window resize by 1 pixel. CS */
+ if (ypLast < 0 || ypFirst == ypLast) return;
+
+ pwwd->fDirty = true;
+ pwwd->ypFirstInval = min(pwwd->ypFirstInval, ypFirst);
+ pwwd->ypLastInval = max(ypLast, pwwd->ypLastInval);
+ }
+
+
+
+
+/* T R A S H A L L W W S */
+TrashAllWws()
+{ /* trash them all */
+ int ww;
+
+#ifdef CASHMERE
+ for (ww = 0; ww < wwMac; ++ww)
+ TrashWw(ww);
+#else
+ TrashWw( wwDocument );
+#endif
+ vfli.doc = docNil; /* Mark vfli invalid */
+}
+
+
+/* T U R N O F F S E L */
+TurnOffSel()
+{ /* Remove sel highlighting from screen */
+/* HideSel has no effect */
+ if (!vfSelHidden)
+ {
+ ToggleSel(selCur.cpFirst, selCur.cpLim, false);
+ vfSelHidden = true;
+ }
+}
+
+#ifdef JAPAN
+ /* We handle IME convert window. */
+
+int FontHeight = 0;
+BOOL bGetFocus = FALSE;
+// Handle to the IME communication block - 061491 Yukini
+HANDLE hImeMem = NULL;
+
+// to prevent unwanted caret traveling - 061591 Yukini
+BOOL bForceBlock = FALSE;
+// To avoid ilreagal setting for IME rectangle
+static BOOL bResetIMERect=FALSE;
+
+/*
+ * ForceImeBlock controls IME input display to the screen.
+ * When Write program is writing string to the screen, the caret
+ * doesn't move with string. After completing text display,
+ * then caret is moved to appropriate position. During this
+ * period, if user type something by using IME, char is displayed on the
+ * screen. This makes mixing ugly result. This routine will
+ * prevent this. Yukini
+ */
+void ForceImeBlock( hWnd, bFlag )
+HWND hWnd;
+BOOL bFlag;
+{
+ WORD x, y;
+ LPIMESTRUCT lpmem;
+
+ if (bForceBlock = bFlag) {
+ if (lpmem = (LPIMESTRUCT)GlobalLock(hImeMem)) {
+ /* Move bounding rectangle to out of the world */
+ lpmem->fnc = IME_MOVECONVERTWINDOW;
+ x = GetSystemMetrics(SM_CXSCREEN);
+ y = GetSystemMetrics(SM_CYSCREEN);
+ lpmem->wParam = MCW_SCREEN | MCW_RECT;
+ lpmem->lParam1 = (DWORD)MAKELONG(x+1,y+1);
+ lpmem->lParam2 = (DWORD)MAKELONG(x+1,y+1);
+ lpmem->lParam3 = (DWORD)MAKELONG(x*2,y*2);
+ GlobalUnlock(hImeMem);
+ SendIMEMessage(hWnd,MAKELONG(hImeMem,NULL));
+ bResetIMERect = FALSE;
+ }
+ }
+}
+
+/* use these veriables to optimize IME call. This will prevent task switching
+ * overhead. - Yukini
+ */
+static RECT rcOldRect = {-1, -1, -1, -1};
+static DWORD dwCurpos = -1;
+
+
+
+
+
+
+void SetIMEConvertWindow(hWnd,x,y,bFlag)
+HWND hWnd;
+int x,y;
+BOOL bFlag;
+{
+LPIMESTRUCT lpmem;
+//Yukini:HANDLE hIMEBlock;
+DWORD dwXY = MAKELONG(x,y);
+RECT rcRect;
+extern BOOL bImeCnvOpen; // Yutakan:08/06/91
+
+ /* Do nothing if in text drawing to the screen */
+ if (bForceBlock)
+ return;
+
+ /* we allocate the Ime communication area. freeing of this
+ * area will be done by wrap up routine MmwDestroy() of Quit.C.
+ * This will improve the performance than previous code. - Yukini
+ */
+ if (hImeMem == NULL) {
+ if ((hImeMem = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE|GMEM_LOWER,
+ (DWORD)sizeof(IMESTRUCT))) == NULL)
+ return; // something wrong
+ }
+//Yukini: /* Get comunication area with IME */
+//Yukini: hIMEBlock=GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_LOWER,
+//Yukini: (DWORD)sizeof(IMESTRUCT));
+//Yukini: if(!hIMEBlock) return;
+
+ if(!bGetFocus) bFlag = FALSE;
+
+ GetWindowRect(hWnd,&rcRect);
+
+// [yutakan:08/06/91] IF out of Window Rect, force MCW_DEFAULT.
+// if(rcRect.top > y || rcRect.bottom < y) bFlag = TRUE;
+//
+ if (bFlag) {
+
+/* Add ResetIMERect check . If we've not done MOVECONVERTWINDOW after
+** ForceIMEblock(), don't pass by SendIMEMessage to avoid ilreagal setting
+** for bounding rectangle. [Yutakan.]
+*/
+ // bResetIMERect FALSE when just after ForceImeBlock()
+ if ( bResetIMERect == TRUE
+ && dwCurpos == dwXY && EqualRect(&rcRect, &rcOldRect)){
+ //OutputDebugString("Write:optimized\r\n");
+ return;
+ }
+ } else
+ dwCurpos = -1; // invalidate cache
+//Yukini: lpmem = (LPIMESTRUCT)GlobalLock(hIMEBlock);
+//Yukini: lpmem->fnc = IME_MOVECONVERTWINDOW;
+//Yukini: lpmem->wParam = bFlag?MCW_WINDOW:MCW_DEFAULT;
+//Yukini: lpmem->lParam1 = (DWORD)MAKELONG(x,y);
+//Yukini: GlobalUnlock(hIMEBlock);
+//Yukini: SendIMEMessage(hWnd,MAKELONG(hIMEBlock,NULL));
+//Yukini: GlobalFree(hIMEBlock);
+ if (lpmem = (LPIMESTRUCT)GlobalLock(hImeMem)) {
+ lpmem->fnc = IME_MOVECONVERTWINDOW;
+ if ((lpmem->wParam = bFlag ? MCW_WINDOW : MCW_DEFAULT) == MCW_WINDOW) {
+ /* update previous state */
+ dwCurpos = dwXY;
+
+ CopyRect(&rcOldRect, &rcRect);
+ lpmem->lParam1 = dwXY;
+ }
+ GlobalUnlock(hImeMem);
+ SendIMEMessage(hWnd,MAKELONG(hImeMem,NULL));
+ bResetIMERect = TRUE; // yutakan:08/06/91
+ }
+}
+
+void
+IMEManage( bFlag )
+BOOL bFlag; /* Flag to indicate real default or virtual default in case
+ of requesting IME convert line to be default. Real default
+ (value TRUE) is selected when I am loosing the focus. In
+ this case, IME convert line will be default. Virtual
+ default (value FALSE) is selected when I lost a caret
+ position. In this case, IME convert line will be out of
+ the screen. You can type characters, but not displayed
+ to the screen correctly. Yukini
+ */
+{
+int x,y;
+BOOL bCE = ConvertEnable;
+
+ if(!FontHeight)
+ {
+ TEXTMETRIC tm;
+ GetTextMetrics(wwdCurrentDoc.hDC,&tm);
+ FontHeight = tm.tmHeight;
+ }
+
+ x = vxpCursLine;
+ y = vypCursLine-(vdypCursLine+FontHeight)/2;
+
+ if (x < 0 || y < 0)
+ bCE = FALSE; /* Sometime caret position will be
+ less than zero. Do no set IME
+ window in this case. Yukini */
+
+ if (bCE == FALSE && bFlag == FALSE && bForceBlock == FALSE) {
+ // get out of the world, babe.
+ ForceImeBlock( wwdCurrentDoc.wwptr, TRUE );
+ bForceBlock = FALSE;
+// yutakan:08/16/91 dwCurpos = 1; // invalidate optimize cache
+ dwCurpos = -1;
+ } else
+ SetIMEConvertWindow(wwdCurrentDoc.wwptr,
+ x,y,bCE);
+}
+
+
+#endif // JAPAN
+
+/* D R A W I N S E R T L I N E */
+DrawInsertLine()
+{ /* Draw (in Xor mode) a vertical bar at screen position v*CursLine */
+ /* Toggles both the display and the vfInsertOn flag */
+ /* Adjustments in cursor draw must be reflected in DisplayFli, above */
+
+ /* Last-minute correction for a bug: assure that the insert line
+ does not extend above ypMin */
+ if (!vfInsertOn && vdypCursLine > vypCursLine - wwdCurrentDoc.ypMin)
+ vdypCursLine = vypCursLine - wwdCurrentDoc.ypMin;
+
+ /* Tell GDI to invert the caret line */
+ PatBlt( wwdCurrentDoc.hDC, vxpCursLine, vypCursLine - vdypCursLine,
+ 2, vdypCursLine , DSTINVERT );
+ vfInsertOn = 1 - vfInsertOn;
+}
+
+
+
+
+/* C L E A R I N S E R T L I N E */
+ClearInsertLine()
+{
+#if defined(JAPAN) & defined(DBCS_IME)
+/* So we do some IME manage when clearning the line */
+
+ if((vxpCursLine<0) || (vxpCursLine>=wwdCurrentDoc.xpMac)
+ || (vypCursLine<0) || (vypCursLine>=wwdCurrentDoc.ypMac)) {
+ ConvertEnable = FALSE;
+ //OutputDebugString("ClearInsertLine\r\n");
+ }
+
+ bClearCall = FALSE;
+
+ if ( vfInsertOn) DrawInsertLine();
+ else IMEManage( FALSE );
+
+ bClearCall = TRUE;
+
+#else
+ if ( vfInsertOn) DrawInsertLine();
+#endif
+}
+
diff --git a/private/mvdm/wow16/write/d_form1.c b/private/mvdm/wow16/write/d_form1.c
new file mode 100644
index 000000000..f3f9acdf7
--- /dev/null
+++ b/private/mvdm/wow16/write/d_form1.c
@@ -0,0 +1,2452 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*--- Module not really used, just the idea behind FORMAT.ASM ---*/
+
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOCLIPBOARD
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#include <windows.h>
+/* #include "wwsmall.h" */
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "ffdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "dispdefs.h"
+#include "scrndefs.h"
+#include "macro.h"
+#include "debug.h"
+#include "fontdefs.h"
+#include "str.h"
+#include "wwdefs.h"
+#ifdef DBCS
+#include "dbcs.h"
+/* We move several hard code Kanji code table from this source file
+ to kanji.h as external variables. Define CODE_TABLE will define
+ those variables */
+#define CODE_TABLE
+
+#include "kanji.h"
+#endif
+
+#ifdef DFLI
+#define Dfli(x) x /* Enable debug-format-line info */
+#else
+#define Dfli(x)
+#endif
+
+#ifdef CASHMERE
+#define cchSmcapMax 16
+#endif /* CASHMERE */
+
+static int ichpFormat;
+
+#ifdef CASHMERE
+static CHAR mptlcch[] = " .-_";
+#endif /* CASHMERE */
+
+extern int docHelp;
+extern struct FLI vfli;
+extern struct CHP (**vhgchpFormat)[];
+extern int ichpMacFormat;
+extern struct CHP vchpAbs;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern struct CHP vchpNormal;
+extern struct DOD (**hpdocdod)[];
+extern typeCP vcpLimSectCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFetch;
+extern int vichFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern int vcchFetch;
+extern int vftc;
+extern int ypSubSuper;
+extern int ypSubSuperPr;
+extern HDC vhMDC;
+extern HDC vhDCPrinter;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern int dypMax;
+extern struct FMI vfmiScreen, vfmiPrint;
+extern int vfOutOfMemory;
+extern CHAR vchDecimal; /* "decimal point" character */
+extern int vzaTabDflt; /* width of default tab */
+#ifdef CASHMERE
+extern int vfVisiMode;
+#endif /* CASHMERE */
+
+
+/* F O R M A T L I N E */
+FormatLine(doc, cp, ichCp, cpMac, flm)
+int doc;
+typeCP cp;
+int ichCp;
+typeCP cpMac;
+int flm;
+ {
+ /* Fills up vfli with a line of text */
+
+ int near Justify(struct IFI *, unsigned, int);
+ int near FGrowFormatHeap(void);
+ int near FFirstIch(int);
+
+#ifdef DBCS
+ BOOL near FAdmitCh1(CHAR);
+ BOOL near FAdmitCh2(CHAR, CHAR);
+ BOOL near FOptAdmitCh1(CHAR);
+ BOOL near FOptAdmitCh2(CHAR, CHAR);
+ int DBCSDxpFromCh(int,int,int);
+#endif
+
+ struct IFI ifi;
+ struct TBD *ptbd;
+ struct CHP chpLocal;
+ int xpTab;
+
+#ifdef CASHMERE
+ int dypBefore;
+#endif /* CASHMERE */
+
+ int dypAscent;
+ int dypDescent;
+ int dypAscentMac;
+ int dypDescentMac;
+ unsigned xaLeft;
+ unsigned xaRight;
+ struct PAP *ppap;
+ struct SEP *psep;
+ int fFlmPrinting = flm & flmPrinting;
+ int dxaFormat;
+ int dyaFormat;
+ int dxpFormat;
+ int dypFormat;
+ int ypSubSuperFormat;
+ int fTruncated = false; /* if the run was truncated */
+ int ichpNRH;
+
+#ifdef DBCS
+ int dichSpaceAdjust;
+ int dypLeading;
+ int dypIntLeading;
+ int dypPAscent; /* Pure Ascent */
+ int dypLeadingMac;
+ int dypIntLeadingMac;
+ int dypPAscentMac;
+ BOOL fKanjiBreakOppr = false;
+ BOOL fKanjiPrevious = false;
+ /* true iff we already have a hanging character on the line. */
+ BOOL fKanjiHanging = false;
+ /* true iff the first and second bytes of a kanji character
+ were in two different runs. */
+ BOOL fOddBoundary = false;
+ typeCP cpFetchSave;
+ typeCP cpSeqFetch;
+ int ichFetchSave;
+ int cchUsedSave;
+
+ extern int utCur;
+ extern int dxaAdjustPer5Ch;
+ extern unsigned cxaCh;
+#endif /* ifdef DBCS */
+
+
+#ifdef CASHMERE
+ struct FNTB **hfntb;
+ int fVisiMode;
+#endif /* CASHMERE */
+
+ /* Check for fli current */
+ if (vfli.doc == doc && vfli.cpMin == cp && vfli.ichCpMin == ichCp &&
+ vfli.flm == flm)
+ {
+ /* Just did this one */
+ return;
+ }
+
+ Scribble(5, 'F');
+ bltc(&vfli, 0, cwFLIBase);
+ /* This means:
+ vfli.fSplat = false;
+ vfli.dcpDepend = 0;
+ vfli.ichCpMac = 0;
+ vfli.dypLine = 0;
+ vfli.dypAfter = 0;
+ vfli.dypFont = 0;
+ vfli.dypBase = 0;
+ */
+
+ /* vfSplatNext = FALSE; No longer used. */
+
+ /* Rest of format loads up cache with current data */
+ vfli.doc = doc;
+ vfli.cpMin = cp;
+ vfli.ichCpMin = ichCp;
+ vfli.flm = flm;
+
+ if (cp > cpMac)
+ {
+ /* Space after the endmark. Reset the cache because the footnotes come
+ at the same cp in the footnote window */
+ vfli.doc = docNil;
+ vfli.cpMac = cp;
+ vfli.rgdxp[0] = 0;
+
+ /* Line after end mark is taller than screen */
+
+#ifdef CASHMERE
+ vfli.dypBase = vfli.dypFont = vfli.dypAfter = ((vfli.dypLine = dypMax)
+ >> 1);
+#else /* not CASHMERE */
+ vfli.dypBase = vfli.dypFont = ((vfli.dypLine = dypMax) >> 1);
+#endif /* not CASHMERE */
+
+ Scribble(5, ' ');
+ return;
+ }
+
+ /* Initialize run tables */
+ ichpFormat = 0;
+
+ /* Cache section and paragraph properties */
+
+#ifdef CASHMERE
+ hfntb = (**hpdocdod)[doc].hfntb;
+ if (hfntb == 0 || cp < (**hfntb).rgfnd[0].cpFtn)
+ {
+ /* Normal text */
+ CacheSect(doc, cp);
+ }
+ else
+ {
+ /* Footnote section properties come from the section of the footnote
+ reference. */
+ CacheSect(doc, CpRefFromFtn(doc, cp));
+ }
+#else /* not CASHMERE */
+ CacheSect(doc, cp);
+#endif /* not CASHMERE */
+
+ psep = &vsepAbs;
+
+ CachePara(doc, cp);
+ ppap = &vpapAbs;
+
+ /* Now we have:
+ ppap paragraph properties
+ psep division properties
+ */
+
+ if (ppap->fGraphics)
+ {
+ /* Format a picture paragraph in a special way (see picture.c) */
+ FormatGraphics(doc, cp, ichCp, cpMac, flm);
+ Scribble(5, ' ');
+ return;
+ }
+
+ /* Assure we have a good memory DC for font stuff */
+ ValidateMemoryDC();
+ if (vhMDC == NULL || vhDCPrinter == NULL)
+ {
+ Scribble(5, ' ');
+ return;
+ }
+
+#ifdef CASHMERE
+ /* When printing, don't show visible characters */
+ fVisiMode = vfVisiMode && !fFlmPrinting;
+#endif /* CASHMERE */
+
+ bltc(&ifi, 0, cwIFI);
+ /* This means:
+ ifi.ich = 0;
+ ifi.ichPrev = 0;
+ ifi.ichFetch = 0;
+ ifi.cchSpace = 0;
+ ifi.ichLeft = 0;
+ */
+
+ ifi.jc = jcTabLeft;
+ ifi.fPrevSpace = true;
+
+ /* Set up some variables that have different value depending on whether we
+ are printing or not. */
+ if (fFlmPrinting)
+ {
+ dxaFormat = dxaPrPage;
+ dyaFormat = dyaPrPage;
+ dxpFormat = dxpPrPage;
+ dypFormat = dypPrPage;
+ ypSubSuperFormat = ypSubSuperPr;
+ }
+ else
+ {
+ dxaFormat = dyaFormat = czaInch;
+ dxpFormat = dxpLogInch;
+ dypFormat = dypLogInch;
+ ypSubSuperFormat = ypSubSuper;
+ }
+
+ /* Calculate line height and width measures. Compute
+ xaLeft left indent 0 means at left margin
+ xaRight width of column measured from left margin (not from left
+ indent).
+ */
+ xaLeft = ppap->dxaLeft;
+
+ /* If this is the first line of a paragraph, adjust xaLeft for the first
+ line indent. (Also, set dypBefore, since its handy.) */
+ if (cp == vcpFirstParaCache)
+ {
+ xaLeft += ppap->dxaLeft1;
+
+#ifdef CASHMERE
+ dypBefore = MultDiv(ppap->dyaBefore, dypLogInch, czaInch);
+#endif /* CASHMERE */
+
+ }
+
+#ifdef CASHMERE
+ else
+ {
+ dypBefore = 0;
+ }
+#endif /* CASHMERE */
+
+ /* Now, set xaRight (width measured in twips). */
+
+#ifdef CASHMERE
+ xaRight = (ppap->rhc ? vsepPage.xaMac - vsepPage.dxaGutter :
+ psep->dxaText) - ppap->dxaRight;
+#else /* not CASHMERE */
+ xaRight = psep->dxaText - ppap->dxaRight;
+#endif /* not CASHMERE */
+
+
+ /* Do necessary checks on xaLeft and xaRight */
+ if (xaRight > xaRightMax)
+ {
+ xaRight = xaRightMax;
+ }
+ if (xaLeft > xaRightMax)
+ {
+ xaLeft = xaRightMax;
+ }
+ if (xaLeft < 0)
+ {
+ xaLeft = 0;
+ }
+ if (xaRight < xaLeft)
+ {
+ xaRight = xaLeft + 1;
+ }
+
+ vfli.xpLeft = ifi.xp = ifi.xpLeft = MultDiv(xaLeft, dxpFormat, dxaFormat);
+ vfli.xpMarg = ifi.xpRight = MultDiv(xaRight, dxpFormat, dxaFormat);
+ ifi.xpPr = MultDiv(xaLeft, dxpPrPage, dxaPrPage);
+ ifi.xpPrRight = MultDiv(xaRight, dxpPrPage, dxaPrPage);
+
+#ifdef DBCS /* was in JAPAN */
+/* at least one kanji is displayed */
+/* DxpFromCh() --> DBCSDxpFromCh() 03 Oct 1991 YutakaN */
+ {
+ int dxpPr;
+ if ( ifi.xpPrRight - ifi.xpPr < (dxpPr = DBCSDxpFromCh(bKanjiSpace1,bKanjiSpace2, TRUE) ) )
+ {
+ ifi.xpPrRight = ifi.xpPr + dxpPr + 1;
+ }
+ }
+#endif
+
+ /* Get a pointer to the tab-stop table. */
+ ptbd = ppap->rgtbd;
+
+ /* Turn off justification. */
+ SetTextJustification(fFlmPrinting ? vhDCPrinter : vhMDC, 0, 0);
+
+ /* Initialize the line height information. */
+ dypAscentMac = dypDescentMac = 0;
+
+ /* To tell if there were any tabs */
+ ifi.ichLeft = -1;
+
+ /* Get the first run, and away we go... */
+ FetchCp(doc, cp, ichCp, fcmBoth + fcmParseCaps);
+ goto FirstCps;
+
+ for ( ; ; )
+ {
+ int iichNew;
+ int xpPrev;
+ int dxp;
+ int dxpPr;
+
+ /* The number of characters to process (usually vcchFetch) */
+ int cch;
+
+ /* The number of characters in current run already used */
+ int cchUsed;
+
+ /* A pointer to the current list of characters (usually vpchFetch) */
+ CHAR *pch;
+
+#ifdef CASHMERE
+ CHAR rgchSmcap[cchSmcapMax];
+#endif /* CASHMERE */
+
+ if (ifi.ichFetch == cch)
+ {
+ /* End of a run */
+ int dich;
+ BOOL fSizeChanged;
+
+ if (ifi.ich >= ichMaxLine)
+ /* End of run because of line length limit has been reached. */
+ {
+ goto DoBreak;
+ }
+
+ if (fTruncated)
+ {
+ cchUsed += cch;
+ pch = vpchFetch + cchUsed;
+ cch = vcchFetch - cchUsed;
+ fTruncated = false;
+ goto OldRun; /* use the rest of the old run */
+ }
+
+NullRun:
+#ifdef DBCS
+ if (!fOddBoundary)
+ {
+ /* The last fetch did not screw up a sequential access. */
+ FetchCp(docNil, cpNil, 0, fcmBoth + fcmParseCaps);
+ }
+ else
+ {
+ /* Previous fetch was an odd one. Set it up again. */
+ FetchCp(doc, cpSeqFetch, 0, fcmBoth + fcmParseCaps);
+ }
+ fOddBoundary = false;
+#else
+ FetchCp(docNil, cpNil, 0, fcmBoth + fcmParseCaps);
+#endif
+
+FirstCps:
+
+ cchUsed = 0;
+
+ /* Continue fetching runs until a run is found with a nonzero
+ length. */
+ if ((cch = vcchFetch) == 0)
+ {
+ goto NullRun;
+ }
+
+ pch = vpchFetch;
+ if (vcpFetch >= cpMac || (!fFlmPrinting && *pch == chSect))
+ {
+#ifdef SYSENDMARK
+ /* Force end mark and section mark to be in standard system
+ font. */
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ vchpAbs.ftc = ftcSystem;
+ vchpAbs.ftcXtra = 0;
+ vchpAbs.hps = hpsDefault;
+#else
+#ifdef REVIEW
+ /* The following comment is absolutely misleading! Ftc==0
+ doesn't give you a system font. It gives you the first
+ entry in the font table. */
+#endif /* REVIEW */
+ /* Force end mark and section mark to be in standard system
+ font. */
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ vchpAbs.ftc = 0;
+ vchpAbs.ftcXtra = 0;
+ vchpAbs.hps = hpsDefault;
+#endif /* if-else-def KANJI */
+ }
+
+#ifdef CASHMERE
+ /* Adjust the size of the font for "small capitals". */
+ if (vchpAbs.csm == csmSmallCaps)
+ {
+ vchpAbs.hps = HpsAlter(vchpAbs.hps, -1);
+ }
+#endif /* CASHMERE */
+
+ /* Now we have:
+ ichpFormat index into gchp table
+ vcpFetch first cp of current run
+ vfli.cpMin first cp of line
+ ifi.ich ???
+ */
+
+ /* since LoadFont could change vchpAbs, and we don't want
+ that to happen, we copy vchpAbs into vchpLocal and use
+ vchpLocal in place of vchpAbs hereafter. Note that vchpAbs
+ is intentionally used above for handling the endmark. */
+
+ blt(&vchpAbs, &chpLocal, cwCHP);
+
+
+ if (fFlmPrinting)
+ {
+ LoadFont(doc, &chpLocal, mdFontPrint);
+ dypAscent = vfmiPrint.dypAscent + vfmiPrint.dypLeading;
+ dypDescent = vfmiPrint.dypDescent;
+#ifdef DBCS /* was in JAPAN */
+ dypPAscent = vfmiPrint.dypAscent;
+ dypLeading = vfmiPrint.dypLeading;
+ dypIntLeading = vfmiPrint.dypIntLeading;
+#endif
+ }
+ else
+ {
+ LoadFont(doc, &chpLocal, mdFontJam);
+ dypAscent = vfmiScreen.dypAscent + vfmiScreen.dypLeading;
+ dypDescent = vfmiScreen.dypDescent;
+#ifdef DBCS /* was in JAPAN */
+ dypPAscent = vfmiScreen.dypAscent;
+ dypLeading = vfmiScreen.dypLeading;
+ dypIntLeading = vfmiScreen.dypIntLeading;
+#endif
+ }
+
+#ifdef ENABLE /* BRYANL 8/27/87: New philosophy for handling
+ font selection failures is: font selection
+ ALWAYS succeeds. This prevents FormatLine
+ returns that do not advance. */
+ /* Bail out if there is a memory failure. */
+ if (vfOutOfMemory)
+ {
+ goto DoBreak;
+ }
+#endif /* ENABLE */
+
+ /* Floating line size algorithm */
+ if (chpLocal.hpsPos != 0)
+ {
+ /* Modify font for subscript/superscript */
+ if (chpLocal.hpsPos < hpsNegMin)
+ {
+ dypAscent += ypSubSuperFormat;
+#ifdef DBCS /* was in JAPAN */
+ dypPAscent += ypSubSuperFormat;
+#endif
+ }
+ else
+ {
+ dypDescent += ypSubSuperFormat;
+ }
+ }
+
+ /* Update the maximum ascent and descent of the line. */
+ fSizeChanged = FALSE;
+ if (dypDescentMac < dypDescent)
+ {
+ dypDescentMac = dypDescent;
+ fSizeChanged = TRUE;
+ }
+ if (dypAscentMac < dypAscent)
+ {
+ dypAscentMac = dypAscent;
+ fSizeChanged = TRUE;
+ }
+#ifdef DBCS /* was in JAPAN */
+ if (dypPAscentMac < dypPAscent)
+ {
+ dypPAscentMac = dypPAscent;
+ fSizeChanged = TRUE;
+ }
+ if (dypIntLeadingMac < dypIntLeading)
+ {
+ dypIntLeadingMac = dypIntLeading;
+ fSizeChanged = TRUE;
+ }
+ if (dypLeadingMac < dypLeading)
+ {
+ dypLeadingMac = dypLeading;
+ fSizeChanged = TRUE;
+ }
+#endif
+
+
+ if (fSizeChanged)
+ {
+
+#ifdef AUTO_SPACING
+ /* This is the original Mac Word code that assumed line spacing
+ of 0 in a PAP meant auto line spacing. PC Word defaults to 1
+ line invalidating this assumption. */
+ if (ppap->dyaLine == 0)
+ {
+
+#ifdef CASHMERE
+ ifi.dypLineSize = dypDescentMac + dypAscentMac + dypBefore;
+#else /* not CASHMERE */
+ ifi.dypLineSize = dypDescentMac + dypAscentMac;
+#endif /* not CASHMERE */
+
+ }
+ else
+ {
+
+#ifdef CASHMERE
+ ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
+ dyaFormat) + dypBefore, dypBefore + 1);
+#else /* not CASHMERE */
+ ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
+ dyaFormat), 1);
+#endif /* not CASHMERE */
+
+ }
+#else /* not AUTO_SPACING */
+ /* This code forces auto line spacing except in the case where
+ the user specifies a line spacing greater than the auto line
+ spacing. */
+ {
+#ifdef DBCS /* was in JAPAN */
+#ifdef TAIWAN
+ register int dypAuto = dypDescentMac + dypAscentMac;
+ if (ppap->dyaLine > czaLine)
+ {
+ register int dypUser = imax(MultDiv(ppap->dyaLine,
+ dypFormat, dyaFormat), 1);
+
+ ifi.dypLineSize = max(dypAuto, dypUser);
+ }
+ else
+ {
+ ifi.dypLineSize = dypAuto;
+ }
+#else /* TAIWAN */
+ register int dypAuto = dypDescentMac + dypAscentMac;
+ int cHalfLine;
+ int dypSingle = dypPAscentMac + dypDescentMac;
+
+ cHalfLine = (ppap->dyaLine + (czaLine / 4)) / (czaLine / 2);
+ ifi.dypLineSize = (cHalfLine == 3) ? (dypSingle*3)/2 :
+ ((cHalfLine <= 2) ?
+ dypSingle :
+ (dypSingle * 2));
+#endif /* TAIWAN */
+#else // DBCS
+#ifdef CASHMERE
+ register int dypAuto = dypDescentMac + dypAscentMac +
+ dypBefore;
+#else /* not CASHMERE */
+ register int dypAuto = dypDescentMac + dypAscentMac;
+#endif /* not CASHMERE */
+
+ if (ppap->dyaLine > czaLine)
+ {
+#ifdef CASHMERE
+ register int dypUser = imax(MultDiv(ppap->dyaLine,
+ dypFormat, dyaFormat) + dypBefore, dypBefore + 1);
+#else /* not CASHMERE */
+ register int dypUser = imax(MultDiv(ppap->dyaLine,
+ dypFormat, dyaFormat), 1);
+#endif /* not CASHMERE */
+
+ ifi.dypLineSize = max(dypAuto, dypUser);
+ }
+ else
+ {
+ ifi.dypLineSize = dypAuto;
+ }
+#endif /* DBCS */
+ }
+#endif /* not AUTO_SPACING */
+
+ }
+
+OldRun:
+ /* Calculate length of the run but no greater than 256 */
+ iichNew = (int)(vcpFetch - vfli.cpMin);
+ if (iichNew >= ichMaxLine)
+ {
+ iichNew = ichMaxLine - 1;
+ }
+ dich = iichNew - ifi.ich;
+
+ /* Ensure that all tab and non-required hyphen characters start at
+ beginning of run */
+ if (ichpFormat <= 0 || dich > 0 || CchDiffer(&chpLocal,
+ &(**vhgchpFormat)[ichpFormat - 1], cchCHPUsed) != 0 || *pch ==
+ chTab || *pch == chNRHFile)
+ {
+#ifdef DFLI
+ if (*pch == chNRHFile)
+ CommSz("CHNRHFILE at beginning of run");
+#endif
+ if (ichpFormat != ichpMacFormat || FGrowFormatHeap())
+ {
+ register struct CHP *pchp = &(**vhgchpFormat)[ichpFormat -
+ 1];
+
+ if (ichpFormat > 0)
+ {
+ pchp->cchRun = ifi.ich - ifi.ichPrev;
+ pchp->ichRun = ifi.ichPrev;
+ }
+ blt(&chpLocal, ++pchp, cwCHP);
+
+#ifdef ENABLE /* font codes */
+ pchp->ftc = vftc;
+ pchp->ftcXtra = (vftc & 0x01c0) >> 6;
+ pchp->hps = vhps;
+#endif /* ENABLE */
+
+ pchp->cchRun = ichMaxLine;
+ if (dich <= 0)
+ {
+ pchp->ichRun = ifi.ich;
+ }
+ else
+ {
+ /* Q&D insert */
+ bltc(&vfli.rgdxp[ifi.ich], 0, dich);
+ bltbc(&vfli.rgch[ifi.ich], 0, dich);
+ pchp->ichRun = ifi.ich = iichNew;
+ }
+ ifi.ichPrev = ifi.ich;
+ ichpFormat++;
+ }
+ }
+
+ if (vcpFetch >= cpMac)
+ {
+ /* End of doc reached */
+ if (!ifi.fPrevSpace || vcpFetch == cp)
+ {
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ if (!fFlmPrinting && (doc != docHelp))
+ {
+#ifdef DBCS /* was in JAPAN */
+ /* We use Double byte character to chEMark in Japan */
+ if (ifi.ich + cchKanji > ichMaxLine) {
+ /* vfli.rgch has no room for the two-byte
+ end mark. Too bad do the break and
+ wait for the next time around. */
+ goto DoBreak;
+ }
+ vfli.rgch[ifi.ich] = chMark1;
+#ifdef KOREA /* for variable width, 90.12.26, by sangl */
+ { unsigned int wd;
+ wd = (chMark1 << 8) + chEMark;
+ vfli.xpReal += (vfli.rgdxp[ifi.ich++] = DxpFromCh(wd,false));
+ }
+#else
+ vfli.xpReal += (vfli.rgdxp[ifi.ich++] = DxpFromCh(chMark1,
+ false));
+#endif /* KOREA */
+ vfli.rgch[ifi.ich] = chEMark;
+ vfli.rgdxp[ifi.ich++] = 0;
+
+#ifndef TAIWAN
+ ifi.dypLineSize += 2;
+#endif
+
+#else /* DBCS */
+ vfli.rgch[ifi.ich] = chEMark;
+ vfli.xpReal += (vfli.rgdxp[ifi.ich++] = DxpFromCh(chEMark,
+ false));
+#endif
+ }
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypBase = dypDescentMac;
+ vfli.dypFont = dypAscentMac + dypDescentMac;
+ vfli.ichMac = vfli.ichReal = ifi.ich;
+ vfli.cpMac = cpMac + 1;
+ goto JustEol; /* dcpDepend == 0 */
+ }
+
+ /* Here we have ifi.ich, cch */
+ if (ifi.ich + cch > ichMaxLine)
+ /* If this run would put the line over 255, truncate it and set a
+ flag. */
+ {
+ cch = ichMaxLine - ifi.ich;
+ fTruncated = true;
+ }
+
+ ifi.ichFetch = 0;
+
+#ifdef CASHMERE
+ if (chpLocal.csm != csmNormal)
+ {
+ int ich;
+ CHAR *pchT = &rgchSmcap[0];
+
+ /* We can handle only a run of cchSmcapMax small capital
+ characters. If the run is larger then truncate. */
+ if (cch > cchSmcapMax)
+ {
+ cch = cchSmcapMax;
+ fTruncated = true;
+ }
+
+ /* Raise the case of the characters. */
+ for (ich = 0 ; ich < cch ; ich++)
+ {
+ *pchT++ = ChUpper(*pch++);
+ }
+ pch = &rgchSmcap[0];
+ }
+#endif /* CASHMERE */
+
+ /* Do "special" characters here */
+ if (chpLocal.fSpecial)
+ {
+ if (!FFormatSpecials(&ifi, flm, vsepAbs.nfcPgn))
+ {
+ if (ifi.chBreak == 0) /* No breaks in this line */
+ {
+ goto Unbroken;
+ }
+ else
+ {
+ vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
+ goto JustBreak;
+ }
+ }
+ }
+
+ continue;
+ }
+
+ /* End of new run treatment. We are back in the "for every character"
+ section. */
+ {
+ register int ch = pch[ifi.ichFetch++];
+
+NormChar:
+#ifdef DBCS
+ /* Unless it is a kanji space, we only need to adjust
+ by 1 byte. */
+ dichSpaceAdjust = 1;
+#endif
+
+ if (ch == chSpace)
+ {
+ /* Speed kludge for spaces */
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp =
+ fFlmPrinting ? vfmiPrint.dxpSpace : vfmiScreen.dxpSpace);
+ ifi.xpPr += (dxpPr = vfmiPrint.dxpSpace);
+ vfli.rgch[ifi.ich++] = chSpace;
+#ifdef DFLI
+ {
+ char rgch[100];
+
+ wsprintf(rgch," chSpace , xp==%d/%d, xpPr==%d/%d",
+ ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif
+ goto BreakOppr;
+ }
+
+#ifndef KOREA
+ /* If the printer width is not in the printer width table, then get
+ it. */
+ if (ch < chFmiMin || ch >= chFmiMax || (dxpPr =
+ vfmiPrint.mpchdxp[ch]) == dxpNil)
+ {
+#ifdef DBCS
+ /* Don't pass to DxpFromCh() DBCS LeadByte except for '8140H'.
+ ** Because the function can make elleagal ShiftJIS and pass it
+ ** to GetTextExtent(). GetTextExtent might return SBC space
+ ** when the code is undefined. this will cause win-hang-up at
+ ** formatting line. yutakan
+ */
+ dxpPr=DBCSDxpFromCh(ch,pch[ifi.ichFetch],TRUE);
+#else
+ dxpPr = DxpFromCh(ch, TRUE);
+#endif
+ }
+
+ if (fFlmPrinting)
+ {
+ /* If we are printing, then there is no need to bother with the
+ screen width. */
+ dxp = dxpPr;
+ }
+ else if (ch < chFmiMin || ch >= chFmiMax ||
+ (dxp = vfmiScreen.mpchdxp[ch]) == dxpNil)
+#ifdef DBCS
+// yutakan:
+ dxp = DBCSDxpFromCh(ch,pch[ifi.ichFetch],FALSE);
+#else
+ dxp = DxpFromCh(ch, FALSE);
+#endif /* ifdef DBCS */
+
+#endif /* ifndef KOREA */
+#ifdef DBCS /* was in JAPAN */
+ if (IsDBCSLeadByte(ch)) {
+ CHAR ch2;
+
+ if (ifi.ich + 1 >= ichMaxLine) {
+ /* It's full. Do the break without this kanji character. */
+#ifndef KOREA
+ ifi.ich--;
+#endif
+ ifi.ichFetch--; /* We don't want to skip the first byte. */
+#ifndef KOREA
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+#endif
+lblFull2: /* new label of line full case ( for kanji and kana ) */
+
+ goto DoBreak;
+ }
+
+ /* Now all is well. Get the second byte of the kanji
+ character of interest from the current run. */
+ /* Get the second byte of the kanji character from
+ the current run. If we run of the current run,
+ use FetchRgch() to staple us over. */
+#ifdef KOREA /* for variable width, 90.12.26 by sangl */
+ vfli.rgch[ifi.ich++] = ch;
+#endif
+ if (ifi.ichFetch == cch)
+ {
+ if (fTruncated)
+ {
+ cchUsed += cch;
+ pch = vpchFetch + cchUsed;
+ cch = vcchFetch - cchUsed;
+ fTruncated = false;
+ ch2 = vfli.rgch[ifi.ich] = pch[ifi.ichFetch++];
+ }
+ else {
+ int cchFetch;
+
+ /* Save parameters needed for the re-fetch. */
+ cpFetchSave = vcpFetch;
+ ichFetchSave = vichFetch;
+ cchUsedSave = cchUsed;
+ cpSeqFetch = vcpFetch + cch + 1;
+
+ FetchRgch(&cchFetch, &ch2, docNil, cpNil,
+ vcpFetch + cch + 1, 1);
+ fOddBoundary = true;
+ Assert(cchFetch != 0); /* Better fetched something for us. */
+
+ /* Now, let's settle related parameters. */
+ pch = &ch2;
+ cch = cchFetch;
+ ifi.ichFetch = 1; /* == cch */
+ cchUsed = 0;
+
+ vfli.rgch[ifi.ich] = ch2;
+ }
+ }
+ else
+ {
+ ch2 = vfli.rgch[ifi.ich] = pch[ifi.ichFetch++];
+ }
+#ifdef KOREA /* For variable width, 90.12.26 by sangl */
+ { unsigned int wd;
+ wd = (ch<<8) + ch2;
+ dxpPr = DxpFromCh(wd, TRUE);
+ if (fFlmPrinting) /* if we are printing, then there is */
+ /* no need to bother with the screen width */
+ dxp = dxpPr;
+ else
+ dxp = DxpFromCh(wd, FALSE);
+ ifi.xp += (vfli.rgdxp[ifi.ich-1] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgdxp[ifi.ich++] = 0;
+ }
+#else
+ vfli.rgdxp[ifi.ich++] = 0; /* The second byte has 0 width. */
+#endif /* KOREA */
+ if (FKanjiSpace(ch, ch2)) {
+ fKanjiPrevious = true;
+ fKanjiBreakOppr = false; /* Treat it like a regular space. */
+ dichSpaceAdjust = cchKanji;
+
+ goto BreakOppr;
+ }
+ if (ifi.xpPr > ifi.xpPrRight) {
+ fKanjiBreakOppr = false; /* Reset the flag */
+ if (FAdmitCh2(ch, ch2) ||
+ (fKanjiPrevious && FOptAdmitCh2(ch, ch2))) {
+ /* We do a line break including this odd character. */
+ /* Make sure non-printables won't start a new line. */
+ /* If we already have a hanging character on the */
+ /* line, we don't want to treat this character as */
+ /* a hanging one. */
+ if (!fKanjiHanging) {
+ fKanjiHanging = TRUE;
+ ch = chHyphen;
+ goto BreakOppr;
+ }
+ }
+
+ ifi.ich--;
+ /* If this run was the result of an odd boundary run,
+ re-fetch. */
+ if (fOddBoundary && ifi.ichFetch == 1)
+ {
+ FetchCp(doc, cpFetchSave, ichFetchSave,
+ fcmBoth + fcmParseCaps);
+ /* This fetch is guaranteed to result to non-null run. */
+ fOddBoundary = false;
+ pch = vpchFetch;
+ ifi.ichFetch = cch = vcchFetch;
+ cchUsed = cchUsedSave;
+ }
+ else
+ {
+ ifi.ichFetch--;
+ }
+ /* ifi.xp and ifi.xpPr hasn't changed yet. */
+ goto lblFull2;
+#ifdef KOREA /* 90.12.26 : For variable width, 90.12.26 by sangl */
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+#endif /* KOREA */
+ }
+ /* Record the line break opportunity while processing
+ it as a regular character at the same time. */
+ fKanjiBreakOppr = true;
+ fKanjiPrevious = true;
+ /* Go through the break opprotunity processing, then the
+ default character processing. */
+ goto BreakOppr;
+ }
+ else {
+#ifdef JAPAN
+ if (FKana(ch)) {
+ /* If it is a 1-byte kana letter, we want to treat it
+ in the same way as a kanji letter. */
+ if (ifi.xpPr > ifi.xpPrRight) {
+ fKanjiBreakOppr = false; /* Reset the flag */
+ if (FAdmitCh1(ch)) {
+ /* Make sure non-printables won't start a new line. */
+ /* If we already have a hanging character on the */
+ /* line, we don't want to treat this character as */
+ /* a hanging one. */
+ if (!fKanjiHanging) {
+ fKanjiHanging = TRUE;
+ ch = chHyphen;
+ goto BreakOppr;
+ }
+ }
+ goto lblFull2;
+ }
+ fKanjiPrevious = true;
+ fKanjiBreakOppr = true;
+ /* Go through the break opprotunity processing, then the
+ default character processing. */
+ goto BreakOppr;
+ }
+ else {
+#endif /* JAPAN */
+#ifdef KOREA /* For variable width by sangl 90.12.26 */
+ if (ch < chFmiMin || ch >= chFmiMax || (dxpPr =
+ vfmiPrint.mpchdxp[ch]) == dxpNil)
+ {
+ dxpPr = DxpFromCh(ch, TRUE);
+ }
+ if (fFlmPrinting)
+ {
+ /* If we are printing, then there is no need to bother
+ with the screen width */
+ dxp = dxpPr;
+ }
+ else if (ch < chFmiMin || ch >= chFmiMax ||
+ (dxp = vfmiScreen.mpchdxp[ch]) == dxpNil)
+ dxp = dxpFromCh(ch, FALSE);
+
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = ch;
+#endif /* KOREA */
+ if (fKanjiPrevious && FOptAdmitCh1(ch)) {
+ fKanjiPrevious = false;
+ if (ifi.xpPr > ifi.xpPrRight) {
+ fKanjiBreakOppr = false;
+ /* If we already have a hanging character past the
+ margin, we don't want to treat this as a
+ hanging character. */
+ if (!fKanjiHanging) {
+ fKanjiHanging = true;
+ ch = chHyphen;
+ goto BreakOppr;
+ }
+ }
+ else {
+ /* We can treat this character as though a Kanji
+ punctuation, as far as line breaking is
+ is concerned. */
+ fKanjiBreakOppr = true;
+ goto BreakOppr;
+ }
+ }
+ else {
+ /* Just go on with a regular English formatting. */
+ fKanjiBreakOppr = false;
+ fKanjiPrevious = false;
+ }
+ }
+#ifdef JAPAN
+ }
+#endif
+
+#else /* DBCS */
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = ch;
+#endif
+
+ /* special case "normal characters" above hyphen */
+
+ if (ch > chHyphen)
+ goto DefaultCh;
+
+ switch (ch)
+ {
+
+#ifdef CRLF
+ case chReturn:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+ continue;
+#endif /* CRLF */
+
+ case chNRHFile:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ ichpNRH = ichpFormat - 1;
+#ifdef DFLI
+ {
+ char rgch[100];
+
+ wsprintf(rgch," OptHyph: width==%d, xpPr==%d/%d\n\r",
+ DxpFromCh(chHyphen,true), ifi.xpPr,ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif
+ if (ifi.xpPr + DxpFromCh(chHyphen, true) > ifi.xpPrRight)
+ {
+ /* Won't fit, force a break */
+ goto DoBreak;
+ }
+
+#ifdef CASHMERE
+ else if (fVisiMode)
+ {
+ /* Treat just like a normal hyphen */
+ ch = chHyphen;
+ goto NormChar;
+ }
+#endif /* CASHMERE */
+
+ xpPrev = ifi.xp;
+ vfli.rgch[ifi.ich] = chTab;
+ goto Tab0;
+
+ case chSect:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ vfli.dypFont = vfli.dypLine = (dypAscentMac + (vfli.dypBase
+ = dypDescentMac));
+ vfli.cpMac = vcpFetch + ifi.ichFetch;
+ if (FFirstIch(ifi.ich))
+ {
+ /* Beginning of line; return a splat */
+ vfli.fSplat = true;
+
+ if (!fFlmPrinting)
+ {
+
+#ifdef CASHMERE
+ int chT = vfli.cpMac == vcpLimSectCache ?
+ chSectSplat : chSplat;
+#else /* not CASHMERE */
+ int chT = chSplat;
+#endif /* not CASHMERE */
+
+ int dxpCh = DxpFromCh(chT, false);
+
+ /* Set the width of the splat to be about 8.5" */
+ int cch = min((dxpLogInch * 17 / 2) / dxpCh,
+ ichMaxLine - 32);
+
+ bltbc(&vfli.rgch[ifi.ich], chT, cch);
+ bltc(&vfli.rgdxp[ifi.ich], dxpCh, cch);
+ vfli.ichMac = cch + ifi.ich;
+ vfli.xpReal = LOWORD(GetTextExtent(vhMDC,
+ (LPSTR)vfli.rgch, cch));
+ vfli.xpLeft = 0;
+ }
+ else
+ {
+ vfli.ichMac = 0;
+ }
+ goto EndFormat;
+ }
+
+ /* The section character is in the middle of a line, the
+ line will terminate in front of the character. */
+ /* vfSplatNext = TRUE; No longer used*/
+ vfli.cpMac += cchUsed - 1;
+ vfli.dcpDepend = 1;
+ if (!ifi.fPrevSpace)
+ {
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ vfli.ichMac = ifi.ich;
+ vfli.dypLine = ifi.dypLineSize;
+ goto JustBreak;
+
+ case chTab:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ if (ifi.xpPr < ifi.xpPrRight)
+ {
+ register struct CHP *pchp;
+ unsigned xaPr;
+ unsigned xaTab;
+
+ if (!ifi.fPrevSpace)
+ {
+ /* Remember number of spaces to left and number of
+ real chars in line for justification */
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ ifi.xpReal = ifi.xp;
+ }
+
+ if (ifi.jc != jcTabLeft)
+ {
+ Justify(&ifi, xpTab, flm);
+ }
+ xpPrev = ifi.xp;
+
+ /* Now get info about this tab */
+ xaPr = MultDiv(ifi.xpPr, dxaPrPage, dxpPrPage);
+ while ((xaTab = ptbd->dxa) != 0)
+ {
+#ifdef DBCS /* was in JAPAN */
+ if (xaTab >= xaRight)
+#else
+ if (xaTab > xaRight)
+#endif
+ {
+ /* Don't let tabs extend past right margin. */
+#ifdef DBCS /* was in JAPAN */
+ break; // Stop to examin next tab-stop
+#else
+ xaTab = xaRight;
+#endif
+ }
+
+ if (xaTab >= xaPr)
+ {
+ /* Use tab stop information */
+
+#ifdef CASHMERE
+ ifi.tlc = ptbd->tlc;
+#endif /* CASHMERE */
+
+ ifi.jc = jcTabMin + (ptbd++)->jc;
+
+#ifdef ENABLE /* we do the mapping in HgtbdCreate */
+ if (ifi.jc != jcTabDecimal)
+ {
+ ifi.jc = jcTabLeft;
+ }
+#endif
+ goto TabFound;
+ }
+ ptbd++;
+ }
+
+ /* Out of set tabs; go to next nth column */
+ xaTab = (xaPr / (vzaTabDflt) + 1) * (vzaTabDflt);
+
+#ifdef CASHMERE
+ ifi.tlc = tlcWhite;
+#endif /* CASHMERE */
+
+ ifi.jc = jcTabLeft;
+
+TabFound:
+ xpTab = imax(MultDiv(xaTab, dxpFormat, dxaFormat),
+ ifi.xp);
+
+ /* Do left-justified tabs immediately */
+ if (ifi.jc == jcTabLeft)
+ {
+ ifi.xp = xpTab;
+ ifi.xpPr = MultDiv(xaTab, dxpPrPage, dxaPrPage);
+ }
+ ifi.xpLeft = ifi.xp;
+ ifi.ichLeft = ifi.ich;
+ ifi.cchSpace = 0;
+ ifi.chBreak = 0;
+Tab0:
+ ifi.fPrevSpace = false;
+ vfli.ichMac = ifi.ich;
+ vfli.xpReal = ifi.xp;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypBase = dypDescentMac;
+ vfli.dypFont = dypAscentMac + dypDescentMac;
+
+ if (ifi.ichFetch != 1 && (ichpFormat != ichpMacFormat
+ || FGrowFormatHeap()))
+ {
+ /* Probably in real trouble if FGrowFormatHeap fails
+ at this point */
+ pchp = &(**vhgchpFormat)[ichpFormat - 1];
+ if (ichpFormat > 0)
+ {
+ /* Finish off previous run */
+ pchp->ichRun = ifi.ichPrev;
+ pchp->cchRun = ifi.ich - ifi.ichPrev;
+ }
+
+ blt(&chpLocal, ++pchp, cwCHP);
+ ichpFormat++;
+ }
+ else
+ {
+ pchp = &(**vhgchpFormat)[ichpFormat - 1];
+ }
+ pchp->ichRun = ifi.ich;
+ pchp->cchRun = ichMaxLine;
+
+#ifdef CASHMERE
+ pchp->chLeader = mptlcch[ifi.tlc];
+#endif /* CASHMERE */
+
+ vfli.rgdxp[ifi.ichPrev = ifi.ich++] = ifi.xp - xpPrev;
+
+ if (ch != chTab)
+ {
+ /* This character is a non-required hyphen. */
+ Dfli(CommSz("ch is really OptHyph "));
+ goto BreakOppr;
+ }
+
+ continue;
+ }
+ else
+ {
+ ch = chNBSFile;
+ goto NormChar;
+ }
+
+ case chHyphen:
+ if (ifi.xpPr > ifi.xpPrRight)
+ {
+ goto DoBreak;
+ }
+
+BreakOppr:
+ Dfli(CommSz(" BKOPPR\n\r"));
+ /* this case never used in switch - always goto here */
+ /* case chSpace: */
+ if (ifi.ich >= ichMaxLine)
+ {
+ Dfli(CommSzNum(" Unbroken, ich>ichMaxLine\n\r"));
+ goto Unbroken;
+ }
+
+ case chEol:
+ case chNewLine:
+ ifi.chBreak = ch;
+ vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch;
+ vfli.xpReal = ifi.xp;
+ vfli.ichMac = ifi.ich;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ Dfli(CommSzNumNum(" vfli.xpReal, ichMac ",vfli.xpReal,vfli.ichMac));
+#ifdef DBCS /* was in JAPAN */
+ /* We recorded the kanji break opportunity, go default
+ character processing. */
+ if (fKanjiBreakOppr) {
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ goto DefaultCh;
+ }
+#endif
+
+
+ if (ch == chHyphen || ch == chNRHFile)
+ {
+ Dfli(CommSz(" chHyph/OptHyph catch \n\r"));
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ else
+ {
+ if (!ifi.fPrevSpace)
+ {
+ Dfli(CommSz("!fPrevSpace \n\r"));
+ ifi.cBreak = ifi.cchSpace;
+#ifdef DBCS /* was in JAPAN */
+ vfli.ichReal = ifi.ich - dichSpaceAdjust;
+ dichSpaceAdjust = 1;
+#else
+ vfli.ichReal = ifi.ich - 1;
+#endif
+ ifi.xpReal = (vfli.xpReal = ifi.xp) - dxp;
+ }
+ if (ch == chEol || ch == chNewLine)
+ {
+
+#ifdef CASHMERE
+ if (hfntb != 0 && vfli.cpMac ==
+ (**hfntb).rgfnd[0].cpFtn)
+ {
+ /* End of footnote */
+ if (!fFlmPrinting)
+ {
+ vfli.rgch[ifi.ich - 1] = chEMark;
+ vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
+ DxpFromCh(chEMark, false)) - dxp;
+ vfli.ichReal++; /* show this guy */
+ }
+ }
+ else
+#endif /* CASHMERE */
+ {
+
+#ifdef CASHMERE
+ int chT = fVisiMode ? ChVisible(ch) : chSpace;
+#else /* not CASHMERE */
+ int chT = chSpace;
+#endif /* not CASHMERE */
+
+ int dxpNew = DxpFromCh(chT, fFlmPrinting);
+
+ vfli.rgch[ifi.ich - 1] = chT;
+ vfli.rgdxp[ifi.ich - 1] = dxpNew;
+
+ vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
+ dxpNew) - dxp;
+
+
+ if (!ifi.fPrevSpace)
+ {
+ vfli.xpReal += dxpNew - dxp;
+#ifdef CASHMERE
+ vfli.ichReal =
+ fVisiMode ? ifi.ich : ifi.ich - 1;
+#else /* not CASHMERE */
+ vfli.ichReal = ifi.ich - 1;
+#endif /* not CASHMERE */
+ }
+ }
+
+
+ if (ch == chEol)
+ {
+JustEol:
+ if (fFlmPrinting)
+ {
+ vfli.ichMac = vfli.ichReal;
+ }
+ if (ifi.jc != jcTabLeft)
+ {
+ /* Handle last tab's text */
+ Justify(&ifi, xpTab, flm);
+ }
+ else if ((ifi.jc = ppap->jc) != jcBoth &&
+ ifi.jc != jcLeft)
+ {
+ /* Do line justification */
+ Justify(&ifi, ifi.xpRight, flm);
+ }
+ vfli.xpRight = ifi.xpRight;
+ goto EndFormat;
+ }
+ else
+ {
+ /* Handle a line break */
+ goto JustBreak;
+ }
+ }
+ ++ifi.cchSpace;
+ ifi.fPrevSpace = true;
+ }
+ break;
+
+DefaultCh:
+
+ default:
+
+#ifdef DFLI
+ {
+ char rgch[100];
+ wsprintf(rgch," DefaultCh: %c, xp==%d/%d, xpPr==%d/%d\n\r",
+ ch, ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif /* ifdef DFLI */
+#ifdef DBCS /* was in JAPAN */
+ /* Reset the flag for the next character. */
+ fKanjiBreakOppr = false;
+#endif
+
+ if (ifi.xpPr > ifi.xpPrRight)
+DoBreak:
+ {
+ Dfli(CommSz(" BREAK!\n\r"));
+ if (ifi.chBreak == 0)
+Unbroken:
+ {
+ /* Admit first character to the line, even if margin
+ is crossed. First character at ifi.ich - 1 may be
+ preceded by 0 width characters. */
+#ifdef DBCS
+ if (IsDBCSLeadByte(ch))
+ {
+ if (FFirstIch(ifi.ich-2) && ifi.ich<ichMaxLine)
+ goto PChar;
+ vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-2;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 2;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - (dxp * 2);
+ }
+ else
+ {
+ if (FFirstIch(ifi.ich-1) && ifi.ich<ichMaxLine)
+ goto PChar;
+ vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-1;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 1;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
+ }
+#else
+ if (FFirstIch(ifi.ich - 1) && ifi.ich < ichMaxLine)
+ {
+ goto PChar;
+ }
+ vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch - 1;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 1;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
+#endif
+ goto DoJustify;
+ }
+
+ vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
+JustBreak:
+ if (ifi.chBreak == chNRHFile)
+ {
+ /* Append a non-required hyphen to the end of the
+ line. (Replace zero length tab previously
+ inserted) */
+
+ Dfli(CommSz(" Breaking line at OptHyphen\n\r"));
+ ifi.xpReal += (vfli.rgdxp[vfli.ichReal - 1] =
+ DxpFromCh(chHyphen, fFlmPrinting));
+ vfli.xpRight = vfli.xpReal = ifi.xpReal;
+ vfli.rgch[vfli.ichReal - 1] = chHyphen;
+ vfli.ichMac = vfli.ichReal;
+ if (ichpNRH < ichpFormat - 1)
+ {
+ register struct CHP *pchp =
+ &(**vhgchpFormat)[ichpNRH];
+
+ pchp->cchRun++;
+ if (pchp->ichRun >= vfli.ichMac)
+ {
+ pchp->ichRun = vfli.ichMac - 1;
+ }
+ }
+ }
+
+ if (fFlmPrinting)
+ {
+ vfli.ichMac = vfli.ichReal;
+ }
+ if (ifi.jc != jcTabLeft)
+ {
+ Justify(&ifi, xpTab, flm);
+ }
+ else
+ {
+DoJustify:
+ if ((ifi.jc = ppap->jc) != jcLeft)
+ {
+ Dfli(CommSzNum(" DoJustify: xpRight ",ifi.xpRight));
+ Justify(&ifi, ifi.xpRight, flm);
+ }
+ }
+ vfli.xpRight = ifi.xpRight;
+EndFormat:
+ vfli.ichLastTab = ifi.ichLeft;
+
+#ifdef CASHMERE
+ if (vfli.cpMac == vcpLimParaCache)
+ {
+ vfli.dypAfter = vpapAbs.dyaAfter / DyaPerPixFormat;
+ vfli.dypLine += vfli.dypAfter;
+ vfli.dypBase += vfli.dypAfter;
+ }
+#endif /* CASHMERE */
+
+ Scribble(5, ' ');
+ return;
+ }
+ else
+ {
+PChar:
+ /* A printing character */
+ ifi.fPrevSpace = false;
+ }
+ break;
+
+ } /* Switch */
+#ifdef DBCS /* was in KKBUGFIX */
+//
+// [yutakan:04/02/91]
+//
+ if(vfOutOfMemory == TRUE)
+ return;
+#endif
+ }
+ } /* for ( ; ; ) */
+
+ Scribble(5, ' ');
+ }
+
+
+/* J U S T I F Y */
+near Justify(pifi, xpTab, flm)
+struct IFI *pifi;
+unsigned xpTab;
+int flm;
+ {
+ int dxp;
+ int ichT;
+ int xpLeft;
+
+#ifdef JAPAN
+ /* In the Kanji Write, there is no justified paragraph. */
+ if (pifi->jc == jcBoth)
+ {
+ /* Assert(FALSE); */
+ pifi->jc = jcLeft;
+ dxp = 0; /* by yutakan / 08/03/91 */
+ }
+#endif /* ifdef JAPAN */
+
+
+ xpLeft = pifi->xpLeft;
+ switch (pifi->jc)
+ {
+ CHAR *pch;
+ unsigned *pdxp;
+
+#ifdef CASHMERE
+ case jcTabLeft:
+ case jcLeft:
+ return;
+
+ case jcTabRight:
+ dxp = xpTab - pifi->xpReal;
+ break;
+
+ case jcTabCenter:
+ dxp = (xpTab - xpLeft) - ((pifi->xpReal - xpLeft + 1) >> 1);
+ break;
+#endif /* CASHMERE */
+
+ case jcTabDecimal:
+ dxp = xpTab - xpLeft;
+ for (ichT = pifi->ichLeft + 1; ichT < vfli.ichReal &&
+ vfli.rgch[ichT] != vchDecimal; ichT++)
+ {
+ dxp -= vfli.rgdxp[ichT];
+ }
+ break;
+
+ case jcCenter:
+ if ((dxp = xpTab - pifi->xpReal) <= 0)
+ {
+ return;
+ }
+ dxp = dxp >> 1;
+ break;
+
+ case jcRight:
+ dxp = xpTab - pifi->xpReal;
+ break;
+
+ case jcBoth:
+ if (pifi->cBreak == 0)
+ {
+ /* Ragged edge forced */
+ return;
+ }
+
+ if ((dxp = xpTab - pifi->xpReal) <= 0)
+ {
+ /* There is nothing to do. */
+ return;
+ }
+
+ pifi->xp += dxp;
+ vfli.xpReal += dxp;
+ vfli.dxpExtra = dxp / pifi->cBreak;
+
+ /* Rounding becomes a non-existant issue due to brilliant
+ re-thinking.
+ "What a piece of work is man
+ How noble in reason
+ In form and movement,
+ how abject and admirable..."
+
+ Bill "Shake" Spear [describing Sand Word] */
+ {
+ register CHAR *pch = &vfli.rgch[vfli.ichReal];
+ register int *pdxp = &vfli.rgdxp[vfli.ichReal];
+ int dxpT = dxp;
+ int cBreak = pifi->cBreak;
+ int cxpQuotient = (dxpT / cBreak) + 1;
+ int cWideSpaces = dxpT % cBreak;
+
+ vfli.fAdjSpace = fTrue;
+
+ for ( ; ; )
+ {
+ /* Widen blanks */
+ --pch;
+ --pdxp;
+ if (*pch == chSpace)
+ {
+ if (cWideSpaces-- == 0)
+ {
+ int *pdxpT = pdxp + 1;
+
+ while (*pdxpT == 0)
+ {
+ pdxpT++;
+ }
+ vfli.ichFirstWide = pdxpT - vfli.rgdxp;
+ cxpQuotient--;
+ }
+ *pdxp += cxpQuotient;
+ if ((dxpT -= cxpQuotient) <= 0)
+ {
+ if (pifi->cBreak > 1)
+ {
+ int *pdxpT = pdxp + 1;
+
+ while (*pdxpT == 0)
+ {
+ pdxpT++;
+ }
+ vfli.ichFirstWide = pdxpT - vfli.rgdxp;
+ }
+ return;
+ }
+ pifi->cBreak--;
+ }
+ }
+ }
+ } /* Switch */
+
+ if (dxp <= 0)
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ pifi->xp += dxp;
+
+ if (flm & flmPrinting)
+ {
+ pifi->xpPr += dxp;
+ }
+ else
+ {
+ /* This statememt might introduce rounding errors in pifi->xpPr, but
+ with luck, they will be small. */
+ pifi->xpPr += MultDiv(MultDiv(dxp, czaInch, dxpLogInch), dxpPrPage,
+ dxaPrPage);
+ }
+
+ if (pifi->ichLeft < 0)
+ {
+ /* Normal justification */
+ vfli.xpLeft += dxp;
+ }
+ else
+ {
+ /* Tab justification */
+ vfli.rgdxp[pifi->ichLeft] += dxp;
+ }
+ vfli.xpReal += dxp;
+ }
+
+
+/* F G R O W F O R M A T H E A P */
+int near FGrowFormatHeap()
+ {
+ /* Grow vhgchpFormat by 20% */
+ int cchpIncr = ichpMacFormat / 5 + 1;
+
+#ifdef WINHEAP
+ if (!LocalReAlloc((HANDLE)vhgchpFormat, (ichpMacFormat + cchpIncr) * cchCHP,
+ NONZEROLHND))
+#else /* not WINHEAP */
+ if (!FChngSizeH(vhgchpFormat, (ichpMacFormat + cchpIncr) * cwCHP, false))
+#endif /* not WINHEAP */
+
+ {
+ /* Sorry, charlie */
+ return false;
+ }
+ ichpMacFormat += cchpIncr;
+ return true;
+ }
+
+
+/* #define DBEMG */
+/* D X P F R O M C H */
+#ifdef DBCS
+/* DxpFromCh() assumes that ch passed is the first byte of a DBCS character
+ if it is a part of such character. */
+#endif
+int DxpFromCh(ch, fPrinter)
+int ch;
+int fPrinter;
+ {
+ int *pdxp; // changed to int (7.23.91) v-dougk
+ int dxpDummy; // changed to int (7.23.91) v-dougk
+
+ extern int dxpLogCh;
+ extern struct FCE *vpfceScreen;
+
+ /* If the width is not in the width table, then get it. */
+ if (ch < chFmiMin)
+ {
+ switch (ch)
+ {
+ case chTab:
+ case chEol:
+ case chReturn:
+ case chSect:
+ case chNewLine:
+ case chNRHFile:
+ /* the width for these characters aren't really important */
+ pdxp = (CHAR *)(fPrinter ? &vfmiPrint.dxpSpace : &vfmiScreen.dxpSpace);
+ break;
+ default:
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ break;
+ }
+ }
+ else if (ch >= chFmiMax)
+ {
+ /* outside the range we hold in our table - kludge it */
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ }
+ else
+ {
+ /* inside our table */
+ pdxp = (fPrinter ? vfmiPrint.mpchdxp : vfmiScreen.mpchdxp) + ch;
+ }
+
+#ifdef DBCS
+ if (*pdxp == dxpNil && IsDBCSLeadByte(ch) )
+ {
+ int dxp;
+#else
+ if (*pdxp == dxpNil)
+ {
+ int dxp;
+#endif
+
+#ifdef DBCS
+ struct FMI *pfmi;
+ int rgchT[cchDBCS]; // changed to int (7.23.91) v-dougk
+ int dxpT;
+ int dxpDBCS;
+
+ pfmi = fPrinter ? (&vfmiPrint) : (&vfmiScreen);
+ Assert(pfmi->bDummy == dxpNil);
+ if (pfmi->dxpDBCS == dxpNil)
+ {
+#ifdef KOREA /* 90.12.26 For variable width by sangl */
+ rgchT[0] = HIBYTE(ch);
+ rgchT[1] = LOBYTE(ch);
+#else
+ /* Get the width from GDI. */
+ rgchT[0] = rgchT[1] = ch;
+#endif
+ dxpDBCS = (fPrinter ?
+ LOWORD(GetTextExtent(vhDCPrinter,
+ (LPSTR) rgchT, cchDBCS)) :
+ LOWORD(GetTextExtent(vhMDC,
+ (LPSTR) rgchT, cchDBCS)));
+#ifndef KOREA /* For variable width by sangl 90.12.26 */
+ /* Store in fmi, if it fits. */
+ if (0 <= dxpDBCS && dxpDBCS < dxpNil)
+ pfmi->dxpDBCS = (BYTE) dxpDBCS;
+#endif
+ return (dxpDBCS - pfmi->dxpOverhang);
+ }
+ else
+ return (pfmi->dxpDBCS - pfmi->dxpOverhang);
+ }
+ else {
+ int dxp;
+#endif /* DBCS */
+ /* get width from GDI */
+ dxp = fPrinter ? LOWORD(GetTextExtent(vhDCPrinter, (LPSTR)&ch, 1)) -
+ vfmiPrint.dxpOverhang : LOWORD(GetTextExtent(vhMDC, (LPSTR)&ch, 1)) -
+ vfmiScreen.dxpOverhang;
+#ifdef DBEMG
+ CommSzNum("Get this.... ", dxp);
+#endif
+ //(7.24.91) v-dougk if (dxp >= 0 && dxp < dxpNil)
+ {
+ /* only store dxp's that fit in a byte */
+ *pdxp = dxp;
+ }
+
+#ifdef DBEMG
+ {
+ char szT[10];
+ CommSzSz("fPrinter: ", (fPrinter ? "Printer" : "Screen"));
+ if (ch == 0x0D) {
+ szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
+ }
+ else if (ch == 0x0A) {
+ szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
+ }
+ else if (32 <= ch && ch <= 126) {
+ szT[0] = ch; szT[1] ='\0';
+ }
+ else if (FKanji1(ch)) {
+ szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
+ szT[4] = 'I'; szT[5] = '\0';
+ }
+ else {
+ szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
+ }
+ CommSzSz("Character: ", szT);
+ CommSzNum("Dxp: ", (int) dxp);
+ CommSzNum("OverHang: ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
+ }
+#endif
+ return(dxp);
+ }
+
+#ifdef DBEMG
+ {
+ char szT[10];
+ CommSzSz("fPrinter: ", (fPrinter ? "Printer" : "Screen"));
+ if (ch == 0x0D) {
+ szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
+ }
+ else if (ch == 0x0A) {
+ szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
+ }
+ else if (32 <= ch && ch <= 126) {
+ szT[0] = ch; szT[1] ='\0';
+ }
+ else if (FKanji1(ch)) {
+ szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
+ szT[4] = 'I'; szT[5] = '\0';
+ }
+ else {
+ szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
+ }
+ CommSzSz("Character: ", szT);
+ CommSzNum("Dxp: ", (int) *pdxp);
+ CommSzNum("OverHang: ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
+ }
+#endif
+ return(*pdxp);
+ }
+
+#ifdef DBCS
+//
+// DxpFromCh for DBCS
+// yutakan, 03 Oct 1991
+
+int DBCSDxpFromCh(ch, ch2, fPrinter)
+int ch;
+int ch2;
+int fPrinter;
+{
+ CHAR *pdxp;
+ CHAR dxpDummy;
+
+ extern int dxpLogCh;
+ extern struct FCE *vpfceScreen;
+ /* If the width is not in the width table, then get it. */
+ if (ch < chFmiMin)
+ {
+ switch (ch)
+ {
+ case chTab:
+ case chEol:
+ case chReturn:
+ case chSect:
+ case chNewLine:
+ case chNRHFile:
+ /* the width for these characters aren't really important */
+ pdxp = (CHAR *)(fPrinter ? &vfmiPrint.dxpSpace : &vfmiScreen.dxpSpace);
+ break;
+ default:
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ break;
+ }
+ }
+ else if (ch >= chFmiMax)
+ {
+ /* outside the range we hold in our table - kludge it */
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ }
+ else
+ {
+ /* inside our table */
+ pdxp = (fPrinter ? vfmiPrint.mpchdxp : vfmiScreen.mpchdxp) + ch;
+ }
+
+
+ if (*pdxp == dxpNil )
+ {
+ int dxp;
+ if( IsDBCSLeadByte(ch) ) {
+
+ struct FMI *pfmi;
+ CHAR rgchT[cchDBCS];
+ int dxpT;
+ int dxpDBCS;
+
+ pfmi = fPrinter ? (&vfmiPrint) : (&vfmiScreen);
+ Assert(pfmi->bDummy == dxpNil);
+
+ if(pfmi->dxpDBCS == dxpNil)
+ {
+ /* Get the width from GDI. */
+ rgchT[0] = ch;
+ rgchT[1] = ch2;
+ dxpDBCS = (fPrinter ?
+ LOWORD(GetTextExtent(vhDCPrinter,
+ (LPSTR) rgchT, cchDBCS)) :
+ LOWORD(GetTextExtent(vhMDC,
+ (LPSTR) rgchT, cchDBCS)));
+ /* Store in fmi, if it fits. */
+ if (0 <= dxpDBCS && dxpDBCS < dxpNil)
+ pfmi->dxpDBCS = (BYTE) dxpDBCS;
+
+ return (dxpDBCS - pfmi->dxpOverhang);
+ }
+ else
+ return (pfmi->dxpDBCS - pfmi->dxpOverhang);
+ }
+ else {
+ /* get width from GDI */
+ dxp = fPrinter ? LOWORD(GetTextExtent(vhDCPrinter, (LPSTR)&ch, 1)) -
+ vfmiPrint.dxpOverhang : LOWORD(GetTextExtent(vhMDC, (LPSTR)&ch, 1)) -
+ vfmiScreen.dxpOverhang;
+ }
+
+ if (dxp >= 0 && dxp < dxpNil)
+ {
+ /* only store dxp's that fit in a byte */
+ *pdxp = dxp;
+ }
+
+ return(dxp);
+ }
+
+
+ return(*pdxp);
+ }
+
+#endif
+
+
+/* F F I R S T I C H */
+int near FFirstIch(ich)
+int ich;
+ {
+ /* Returns true iff ich is 0 or preceded only by 0 width characters */
+ register int ichT;
+ register int *pdxp = &vfli.rgdxp[0];
+
+ for (ichT = 0; ichT < ich; ichT++)
+ {
+ if (*pdxp++)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ValidateMemoryDC()
+ {
+ /* Attempt to assure that vhMDC and vhDCPrinter are valid. If we have not
+ already run out of memory, then vhDCPrinter is guaranteed, but vhMDC may
+ fail due to out of memory -- it is the callers responsibility to check for
+ vhMDC == NULL. */
+
+ extern int vfOutOfMemory;
+ extern HDC vhMDC;
+ extern BOOL vfMonochrome;
+ extern long rgbText;
+ extern struct WWD *pwwdCur;
+
+ /* If we are out of memory, then we shouldn't try to gobble it up by getting
+ DC's. */
+ if (!vfOutOfMemory)
+ {
+ if (vhMDC == NULL)
+ {
+ /* Create a memory DC compatible with the screen if necessary. */
+ vhMDC = CreateCompatibleDC(pwwdCur->hDC);
+
+ /* Callers are responsible for checking for vhMDC == NULL case */
+ if (vhMDC != NULL)
+ {
+ /* Put the memory DC in transparent mode. */
+ SetBkMode(vhMDC, TRANSPARENT);
+
+ /* If the display is a monochrome device, then set the text
+ color for the memory DC. Monochrome bitmaps will not be
+ converted to the foreground and background colors in this case,
+ we must do the conversion. */
+ if (vfMonochrome = (GetDeviceCaps(pwwdCur->hDC, NUMCOLORS) ==
+ 2))
+ {
+ SetTextColor(vhMDC, rgbText);
+ }
+ }
+ }
+
+ /* If the printer DC is NULL then we need to reestablish it. */
+ if (vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ /* GetPrinterDC has already called SetMapperFlags() on vhDCPrinter. */
+ }
+ }
+ }
+
+#ifdef DBCS
+/* The following two functions are used to determine if a given kanji
+ (two byte) character (or 1 byte kana letters) should be admitted
+ to the current line without causing the line break though it is
+ passed the right margin.
+
+ The table below shows which letters are admitted as a hanging character
+ on a line. The table below should be updated in sync with the code
+ itself.
+
+ Kanji (2-byte) characters
+
+ letter first byte second byte half width
+ hiragana small a 82 9F
+ i 82 A1
+ u 82 A3
+ e 82 A5
+ o 82 A7
+ tsu 82 C1
+ ya 82 E1
+ yu 82 E3
+ yo 82 E5
+ katakana small a 83 40 85 A5
+ i 83 42 85 A6
+ u 83 44 85 A7
+ e 83 46 85 A8
+ o 83 48 85 A9
+ tsu 83 62 85 AD
+ ya 83 83 85 AA
+ yu 83 85 85 AB
+ yo 83 87 85 AC
+ wa 83 8E
+ ka 83 95
+ ke 83 96
+ blank 81 40
+ horizontal bar (long) 81 5B 85 AE
+ (med) 81 5C
+ (short) 81 5D
+ touten
+ (Japanese comma) 81 41 85 A2
+ kuten
+ (Japanese period) 81 42 85 9F
+ handakuten 81 4B 85 DD
+ dakuten 81 4A 85 DC
+ kagikakko
+ (closing Japanese parenthesis)
+ 81 76 85 A1
+ " (2-byte) 81 68 85 41
+ ' (2-byte) 81 66 85 46
+ } (2-byte) 81 70 85 9D
+ ] (2-byte) 81 6E 85 7C
+ ) (2-byte) 81 6A 85 48
+ . (at the center) 81 45 85 A3
+ ... 81 63
+ .. 81 64
+ closing angle bracket 81 72
+ closing double angled bracket
+ 81 74
+ closing double kagikakko
+ 81 78
+ closing inversed ) 81 7A
+ closing half angled bracket
+ 81 6C
+ thinner ' 81 8C
+ thinner " 81 8D
+
+ 1-byte kana characters
+
+ letter byte
+ katakana small a A7
+ i A8
+ u A9
+ e AA
+ o AB
+ tsu AF
+ ya AC
+ yu AD
+ yo AE
+ touten
+ (Japanese comma) A4
+ kuten
+ (Japanese period) A1
+ handakuten DF
+ dakuten DE
+ kagikakko
+ (closing Japanese parenthesis)
+ A3
+ . (at the center) A5
+
+ The following 1 or 2 byte characters are treated as a hanging character
+ if the previous character is a 2-byte kanji character.
+
+ letter byte
+ " 22
+ ' 27
+ } 7D
+ ] 5D
+ ) 29
+ . 2E
+ , 2C
+ ; 3B
+ : 3A
+ ? 3F
+ ! 21
+
+ byte 1 byte 2
+ . 81 44
+ , 81 43
+ ; 81 47
+ : 81 46
+ ? 81 48
+ ! 81 49
+
+
+ . 85 4D
+ , 85 4B
+ ; 85 4A
+ : 85 49
+ ? 85 5E
+ ! 85 40
+
+*/
+
+BOOL near FSearchChRgch(ch, rgch, ichLim)
+ CHAR ch;
+ CHAR *rgch;
+ int ichLim;
+{
+ int ichMin;
+ BOOL fFound;
+
+ fFound = FALSE;
+ ichMin = 0;
+
+ while (!fFound && ichMin <= ichLim) {
+ int ichMid;
+ CHAR chMid;
+
+ /* Save on the dereferencing. */
+ chMid = rgch[ichMid = (ichMin + ichLim) >> 1];
+ if (ch == chMid) {
+ fFound = TRUE;
+ }
+ else if (ch < chMid) {
+ ichLim = ichMid - 1;
+ }
+ else {
+ ichMin = ichMid + 1;
+ }
+ }
+ return (fFound);
+}
+
+/* FAdmitCh1() returns true if and only if the given ch is a one-byte
+ kana code for those letters that can appear beyond the right margin. */
+
+BOOL near FAdmitCh1(ch)
+ CHAR ch;
+{
+#ifdef JAPAN
+ return (
+ (ch == 0xA1) ||
+ ((0xA3 <= ch) && (ch <= 0xA5)) ||
+ ((0xA7 <= ch) && (ch <= 0xAF)) ||
+ ((0xDE <= ch) && (ch <= 0xDF))
+ );
+#else
+ return(FALSE);
+#endif
+}
+
+/* FOptAdmitCh1() returns true if and only if the given ch is a
+ one-byte character that can be admitted to the end of a line
+ beyond the right margin, if it appears after a kanji character. */
+
+BOOL near FOptAdmitCh1(ch)
+ CHAR ch;
+{
+ static CHAR rgchOptAdmit1[]
+ = {0x21, 0x22, 0x27, 0x29, 0x2C, 0x2E, 0x3A, 0x3B,
+ 0x3F, 0x5D, 0x7D};
+ return (FSearchChRgch(ch, rgchOptAdmit1,
+ (sizeof(rgchOptAdmit1) / sizeof(CHAR)) - 1));
+}
+
+/* FAdmitCh2() returns true if and only if the given (ch1, ch2) combination
+ represents a kanji (2-byte) letter that can appear beyond the right
+ margin. */
+
+BOOL near FAdmitCh2(ch1, ch2)
+ CHAR ch1, ch2;
+{
+ int dch=0;
+
+ while((dch < MPDCHRGCHIDX_MAC) && (ch1 != mpdchrgchIdx[dch]))
+ dch++;
+ if (dch < MPDCHRGCHIDX_MAC) {
+ return (FSearchChRgch(ch2, mpdchrgch[dch], mpdchichMax[dch] - 1));
+ }
+ else {
+ return (FALSE);
+ }
+}
+
+/* FOptAdmitCh2() returns true if and only if the given (ch1, ch2) is a
+ two-byte character combination that can be admitted to the end of a line
+ beyond the right margin, provided it appears after a kanji character. */
+
+BOOL near FOptAdmitCh2(ch1, ch2)
+ CHAR ch1, ch2;
+{
+ int i=0;
+ while ((i < OPTADMIT2IDX_MAC) && (ch1 != OptAdmit2Idx[i]))
+ i++;
+ if (i < OPTADMIT2IDX_MAC){
+ return (FSearchChRgch(ch2, mpdchrgchOptAdmit2[i], OptAdmit2ichMax[i]));
+ }
+ else {
+ return (FALSE);
+ }
+}
+
+
+/* FOptAdmitCh() returns TRUE if and only if the given (ch1, ch2) can
+ be a hanging letter at the end of a line. Otherwise, FALSE. If ch1
+ is equal to '\0', ch2 is treated as a 1-byte character code. */
+
+BOOL FOptAdmitCh(ch1, ch2)
+ CHAR ch1, ch2;
+{
+ if (ch1 == '\0') {
+ return ((ch2 == chSpace) || FAdmitCh1(ch2) || FOptAdmitCh1(ch2));
+ }
+ else {
+ return (FKanjiSpace(ch1, ch2) || FAdmitCh2(ch1, ch2) ||
+ FOptAdmitCh2(ch1, ch2));
+ }
+}
+#endif /* ifdef DBCS */
+
+
+
diff --git a/private/mvdm/wow16/write/d_selec2.c b/private/mvdm/wow16/write/d_selec2.c
new file mode 100644
index 000000000..8e5bdb089
--- /dev/null
+++ b/private/mvdm/wow16/write/d_selec2.c
@@ -0,0 +1,684 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Select2.c -- Less-frequently-used selection routines */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOWNDCLASS
+#define NOICON
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOBITMAP
+#define NOBRUSH
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOMB
+#define NOPOINT
+#define NOMSG
+#include <windows.h>
+#include "mw.h"
+#include "toolbox.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "ch.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+
+#ifdef DBCS
+#include "kanji.h"
+#endif
+
+extern int vfSeeSel;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int docCur;
+extern struct FLI vfli;
+extern struct WWD rgwwd[];
+extern int vfSelHidden;
+extern int wwCur;
+extern struct CHP vchpFetch;
+extern struct PAP vpapAbs;
+extern struct WWD *pwwdCur;
+extern int vfInsEnd;
+extern typeCP CpBeginLine();
+extern int vfPictSel;
+extern int vfSizeMode;
+extern struct CHP vchpNormal;
+extern int vfInsertOn;
+extern struct CHP vchpSel; /* Holds the props when the selection
+ is an insert point */
+extern int vfMakeInsEnd;
+extern typeCP vcpSelect;
+extern int vfSelAtPara;
+/* true iff the last selection was made by an Up/Down cursor key */
+extern int vfLastCursor;
+
+
+#ifndef DBCS /* US version */
+/* C P L I M S T Y S P E C I A L */
+typeCP CpLimStySpecial(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp which is not part of the same sty unit */
+ int wb, ch, ich;
+ struct EDL *pedl;
+
+ /* Other cases covered in CpLimSty, our only caller */
+
+ Assert( cp < cpMacCur );
+ Assert( cp >= cpMinCur );
+ Assert( sty == styWord || sty == stySent );
+
+/* Special kludge for picture paragraphs */
+ CachePara(docCur, cp);
+ if (vpapAbs.fGraphics)
+ return vcpLimParaCache;
+
+ FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
+
+ Assert(vccpFetch != 0);
+
+ /* Must be word or sentence */
+ wb = WbFromCh(ch = vpchFetch[ich = 0]);
+#ifdef CRLF
+ if (ch == chReturn)
+ return vcpFetch + 2;
+#endif
+ if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab)
+ /* EOL is its own unit */
+ return vcpFetch + 1;
+
+ if (wb == wbWhite && sty == stySent)
+ { /* Might be between sentences; go back to text */
+ FetchCp(docCur, CpFirstSty(cp, styWord), 0, fcmChars + fcmNoExpand);
+ wb = WbFromCh(ch = vpchFetch[ich = 0]);
+ }
+
+ for (;;)
+ {
+ if (++ich >= vccpFetch)
+ { /* Get next line and set up */
+ FetchCp(docNil, cpNil, 0, fcmChars);
+ if (vcpFetch == cpMacCur)
+ return cpMacCur; /* End of doc */
+ ich = 0;
+ }
+ if (sty == stySent)
+ switch (ch)
+ {
+ case chDot:
+ case chBang:
+ case chQMark:
+ sty = styWord;
+ wb = wbPunct;
+ }
+ switch (ch = vpchFetch[ich])
+ {
+ case chTab:
+ case chEol:
+ case chSect:
+ case chNewLine:
+#ifdef CRLF
+ case chReturn:
+#endif
+ goto BreakFor;
+ }
+ if (sty == styWord)
+ { /* Word ends after white space or on text/punct break */
+ int wbT = WbFromCh(ch);
+ if (wb != wbT && (wb = wbT) != wbWhite)
+ break;
+ }
+ }
+ BreakFor:
+ return vcpFetch + ich;
+}
+
+
+
+/* C P F I R S T S T Y S P E C I A L */
+typeCP CpFirstStySpecial(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp of this sty unit. */
+ typeCP cpBegin;
+ int wb, ch, dcpChunk;
+ typeCP cpSent;
+ CHAR rgch[dcpAvgSent];
+ int ich;
+ typeCP cpT;
+
+ /* Other cases were covered by CpFirstSty, our only caller */
+
+ Assert( cp > cpMinCur );
+ Assert( sty == stySent || sty == styWord );
+
+ if (cp >= cpMacCur)
+ cpT = cp = cpMacCur;
+ else
+ cpT = cp++;
+
+ CachePara(docCur, cpT );
+ if ((vcpFirstParaCache == cpT) || vpapAbs.fGraphics)
+ return vcpFirstParaCache;
+
+ dcpChunk = (sty == styWord) ? dcpAvgWord : dcpAvgSent;
+ cpBegin = (cp > dcpChunk) ? cp - dcpChunk : cp0;
+
+ FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
+ wb = WbFromCh(ch = rgch[--ich]);
+
+#ifdef CRLF
+ if(cpBegin + ich == 0)
+ return cp0;
+
+ if (ch == chEol && rgch[ich-1] == chReturn) /* EOL is its own unit */
+ return cpBegin + ich - 1;
+ if (ch == chEol || ch == chReturn || ch == chSect || ch == chNewLine || ch == chTab)
+ return cpBegin + ich;
+#else /* not CRLF */
+ if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab) /* EOL is its own unit */
+ return cpBegin + ich;
+#endif /* CRLF */
+
+ if (wb == wbText)
+ cpSent = cpBegin + ich;
+ else
+ cpSent = cpNil;
+
+ for (;;)
+ {
+ if (ich == 0)
+ {
+ if (cpBegin == cpMinCur)
+ return cpMinCur; /* beginning of doc */
+ cpBegin = (cpBegin > dcpChunk) ? cpBegin - dcpChunk : cp0;
+ FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
+ }
+ ch = rgch[--ich];
+ CachePara( docCur, cpBegin + ich ); /* Needed for pictures */
+ if (ch == chEol || ch == chSect || ch == chNewLine ||
+ ch == chTab || vpapAbs.fGraphics )
+ break; /* EOL Always ends a unit */
+ if (sty == styWord)
+ {
+ if (wb != wbWhite)
+ {
+ if (WbFromCh(ch) != wb)
+ break;
+ }
+ else
+ wb = WbFromCh(ch);
+ }
+ else
+ { /* Test for sentence. */
+ switch (ch)
+ {
+ case chDot:
+ case chBang:
+ case chQMark:
+ if (cpSent != cpNil)
+ return cpSent;
+ }
+ switch (WbFromCh(ch))
+ {
+ case wbText:
+ cpSent = cpBegin + ich;
+ wb = wbText;
+ break;
+ case wbPunct:
+ switch (wb)
+ {
+ case wbWhite:
+ wb = wbPunct;
+ break;
+ case wbText:
+ cpSent = cpBegin + ich;
+ }
+ break;
+ case wbWhite:
+ if (wb == wbPunct)
+ cpSent = cpBegin + ich + 1;
+ wb = wbWhite;
+ break;
+ }
+ }
+ }
+ return cpBegin + ich + 1;
+}
+
+#else /* DBCS version */
+
+typeCP CpLimStySpecial(cp, sty)
+ typeCP cp;
+ int sty;
+{
+ CHAR rgch[cchKanji];
+ int ch, ch2;
+ int ich, wb;
+ typeCP cpLim, cpT;
+
+ /* Other cases covered in CpLimSty, our only caller */
+ Assert(cp < cpMacCur);
+ Assert(cp >= cpMinCur);
+ Assert(sty == styWord || sty == stySent);
+
+ /* Picture paragraph? */
+ CachePara(docCur, cp);
+ if (vpapAbs.fGraphics) {
+ return vcpLimParaCache;
+ }
+
+ cpLim = vcpLimParaCache;
+ if (vcpLimParaCache > cpMacCur) {
+ /* No EOL at end of doc */
+ cpLim = cpMacCur;
+ }
+
+ FetchRgch(&ich, rgch, docCur, cp,
+ ((cpT = cp + cchKanji) < cpLim) ? cpT : cpLim, cchKanji);
+ ch = rgch[0];
+#ifdef CRLF
+ if (ch == chReturn) {
+ return (cp + 2);
+ }
+#endif /* CRLF */
+ if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab) {
+ /* EOL is its own unit. */
+ return (cp + 1);
+ }
+#ifdef KOREA
+ wb=WbFromCh(ch);
+#else
+
+ if (FKanji1(ch)) {
+ wb = WbFromKanjiChCh(ch, (int) rgch[1]);
+ if (sty == styWord && wb == wbKanjiText) {
+ return (CpLimSty(cp, styChar));
+ }
+ else {
+ if (wb == wbKanjiText) {
+ wb = wbKanjiTextFirst;
+ }
+ }
+ }
+ else {
+ if (sty == styWord && FKanaText(ch)) {
+ return (CpLimSty(cp, styChar));
+ }
+ wb = WbFromCh(ch);
+ }
+#endif
+
+ for (; cp < cpLim;) {
+ int wbT;
+
+ if (sty == stySent) {
+ if (FKanji1(ch)) {
+ CHAR ch2;
+
+ ch2 = rgch[1];
+ if (FKanjiKuten(ch, ch2) ||
+ FKanjiQMark(ch, ch2) ||
+ FKanjiBang(ch, ch2) ||
+ FKanjiPeriod(ch, ch2)) {
+ sty = styWord;
+ wb = wbPunct;
+ goto lblNextFetch;
+ }
+ }
+ else {
+ switch (ch) {
+#ifndef KOREA
+ case bKanjiKuten:
+#endif
+ case chDot:
+ case chBang:
+ case chQMark:
+ sty = styWord;
+ wb = wbPunct;
+ goto lblNextFetch;
+ }
+ }
+ }
+
+ switch (ch) {
+ case chTab:
+ case chEol:
+ case chSect:
+ case chNewLine:
+#ifdef CRLF
+ case chReturn:
+#endif /* CRLF */
+ return cp;
+ }
+
+ if (sty == styWord) {
+#ifdef KOREA
+ wbT = WbFromCh(ch);
+#else
+ if (FKanji1(ch)) {
+ wbT = WbFromKanjiChCh(ch, (int) rgch[1]);
+ }
+ else {
+ wbT = WbFromCh(ch);
+ }
+#endif
+
+ if (wb != wbT && (wb = wbT) != wbWhite) {
+ return (cp);
+ }
+ }
+
+lblNextFetch:
+ cp = CpLimSty(cp, styChar);
+ if (cp < cpLim) {
+ /* Save some time and an untimely demise.... */
+ FetchRgch(&ich, rgch, docCur, cp,
+ ((cpT = cp + cchKanji) < cpLim) ? cpT : cpLim, cchKanji);
+ ch = rgch[0];
+ }
+ }
+ return (cpLim);
+}
+
+typeCP CpFirstStySpecial(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp of this sty unit. */
+ typeCP cpT, cpLim, cpFirstPara,
+ cpFirstLastSent; /* cpFirst of the last possible sentence boundary */
+ CHAR rgch[cchKanji];
+ int ch;
+ int wb;
+ int ich;
+
+ /* Other cases were covered by CpFirstSty, our only caller */
+
+ Assert( cp > cpMinCur );
+ Assert(CpFirstSty(cp, styChar) == cp); /* cp is on a char boundary */
+ Assert( sty == stySent || sty == styWord );
+
+ cpT = cp;
+ if (cp >= cpMacCur) {
+ cpT = cp = cpMacCur;
+ }
+
+ CachePara(docCur, cpT );
+ cpFirstPara = vcpFirstParaCache;
+ if ((vcpFirstParaCache == cpT) || vpapAbs.fGraphics) {
+ return vcpFirstParaCache;
+ }
+
+
+#ifdef CRLF
+ /* CR-LF is assumed. */
+ Assert(TRUE);
+#else
+ Assert(FALSE);
+#endif /* CRLF */
+ FetchRgch(&ich, rgch, docCur, cp,
+ ((cpT = cp + cchKanji) < cpMacCur) ? cpT : cpMacCur, cchKanji);
+ ch = rgch[0];
+ if (ich == cchKanji && ch == chReturn && rgch[1] == chEol) {
+ /* EOL is its own unit */
+ return cp;
+ }
+ if (ch == chEol || ch == chReturn || ch == chSect ||
+ ch == chNewLine || ch == chTab) {
+ return cp;
+ }
+
+ cpFirstLastSent = cpNil;
+
+#ifdef KOREA
+ wb = WbFromCh(ch);
+#else
+ if (FKanji1(ch)) {
+ wb = WbFromKanjiChCh(ch, (int) rgch[1]);
+ if (sty == styWord && wb == wbKanjiText) {
+ return (CpFirstSty(cp, styChar));
+ }
+ else {
+ if (wb == wbKanjiText) {
+ wb = wbKanjiTextFirst;
+ }
+ }
+ }
+ else {
+ if (sty == styWord && FKanaText(ch)) {
+ return (CpFirstSty(cp, styChar));
+ }
+ wb = WbFromCh(ch);
+ }
+#endif
+
+ for (; cpFirstPara < cp; ) {
+ typeCP cpTemp;
+ int wbT;
+
+ cpTemp = CpFirstSty(cp - 1, styChar);
+ FetchRgch(&ich, rgch, docCur, cpTemp,
+ ((cpT = cpTemp + cchKanji) < cpMacCur) ? cpT : cpMacCur, cchKanji);
+ ch = rgch[0];
+#ifdef KOREA
+ wbT = WbFromCh(ch);
+#else
+ if (FKanji1(ch)) {
+ wbT = WbFromKanjiChCh(ch, (int) rgch[1]);
+ }
+ else {
+ wbT = WbFromCh(ch);
+ }
+#endif
+ if (wb == wbWhite) {
+#ifdef KOREA
+ wb=wbT;
+#else
+ wb = (wbT == wbKanjiText) ? wbKanjiTextFirst : wbT;
+#endif
+ }
+ else if (wb != wbT) {
+ if (sty == styWord) {
+ return (cp);
+ }
+ else /* sty == stySent */ {
+ /* wb != wbWhite */
+ /* wb != wbT */
+ if (wbT == wbWhite || wbT == wbPunct) {
+ cpFirstLastSent = cp;
+ wb = wbWhite;
+ }
+ }
+ }
+
+ if (sty == stySent) { /* for the sentence */
+ if (FKanji1(ch)) {
+ int ch2;
+ ch2 = rgch[1];
+ if (FKanjiKuten(ch, ch2) ||
+ FKanjiQMark(ch, ch2) ||
+ FKanjiBang(ch, ch2) ||
+ FKanjiPeriod(ch, ch2)) {
+ if (cpFirstLastSent != cpNil) {
+ return (cpFirstLastSent);
+ }
+ else {
+ cpFirstLastSent = cp;
+ }
+ }
+ }
+ else {
+ switch(ch) {
+#ifndef KOREA
+ case bKanjiKuten:
+#endif
+ case chDot:
+ case chBang:
+ case chQMark:
+ if (cpFirstLastSent != cpNil) {
+ return (cpFirstLastSent);
+ }
+ else {
+ cpFirstLastSent = cp;
+ }
+ }
+ }
+
+ }
+
+ cp = cpTemp;
+ }
+ return (cpFirstPara);
+}
+#endif /* DBCS */
+
+/* W B F R O M C H */
+int WbFromCh(ch)
+int ch;
+{ /* Return word-breakness of ch */
+
+#if defined(DBCS) & !defined(KOREA) /* was in JAPAN; KenjiK '90-10-29 */
+ /* Brought from WIN2 source. */
+ if (FKanaPunct(ch)) {
+ return wbPunct;
+ }
+ else if (FKanaText(ch)) {
+ return wbKanjiText;
+ }
+#endif
+
+ switch (ch)
+ {
+ case chSpace:
+ case chEol:
+#ifdef CRLF
+ case chReturn:
+#endif
+ case chSect:
+ case chTab:
+ case chNewLine:
+ case chNBSFile:
+ return wbWhite;
+ case chNRHFile:
+ return wbText;
+ default: /* we are using the ANSI char set that windows used */
+#ifdef KOREA
+ return ((isalpha(ch) || isdigit(ch) || ((ch>0xa1)&&(ch<0xfe)))? wbText : wbPunct);
+#else
+ return ((isalpha(ch) || isdigit(ch))? wbText : wbPunct);
+#endif
+ }
+}
+
+#ifdef DBCS /* was in JAPAN; KenjiK '90-10-29 */
+ /* Brought from WIN2 source. */
+int WbFromKanjiChCh(ch1, ch2)
+ int ch1, ch2;
+{
+ if (ch1 == chReturn && ch2 == chEol) {
+ return wbWhite;
+ }
+ else if (FKanjiSpace(ch1, ch2)) {
+ return wbWhite;
+ }
+ else
+
+#ifdef JAPAN
+ {
+ switch (ch1) {
+ case 0x81:
+ if (0x57 <= ch2 && ch2 <= 0x59) {
+ return wbKanjiText;
+ }
+ else {
+ return wbPunct;
+ }
+ case 0x85:
+ if ((0x40 <= ch2 && ch2 <= 0x4E) ||
+ (0x59 <= ch2 && ch2 <= 0x5F) ||
+ (0x7A <= ch2 && ch2 <= 0x7E) ||
+ (0x9B <= ch2 && ch2 <= 0xA3) ||
+ (0xDC <= ch2 && ch2 <= 0xDD)) {
+ return wbPunct;
+ }
+ else {
+ return wbKanjiText;
+ }
+ case 0x86:
+ return wbPunct;
+ case 0x87:
+ return ((ch2 >= 0x90) ? wbPunct : wbKanjiText);
+ default:
+ return wbKanjiText;
+ }
+ }
+#endif
+#ifdef KOREA
+ {
+ switch (ch1) {
+ case 0xa2:
+ if (0xde <= ch2 && ch2 <= 0xe5) {
+ return wbKanjiText;
+ }
+ else {
+ return wbPunct;
+ }
+ case 0xa3:
+ if ((0xa1 <= ch2 && ch2 <= 0xaf) ||
+ (0xba <= ch2 && ch2 <= 0xc0) ||
+ (0xdb <= ch2 && ch2 <= 0xe0) ||
+ (0xfb <= ch2 && ch2 <= 0xfe)) {
+ return wbPunct;
+ }
+ else {
+ return wbKanjiText;
+ }
+ default:
+ return wbKanjiText;
+ }
+ }
+#endif
+#ifdef TAIWAN
+ {
+ switch (ch1) {
+ case 0xA1:
+ if (0x41 <= ch2 && ch2 <= 0xAC) {
+ return wbPunct;
+ }
+ else {
+ return wbKanjiText;
+ }
+ default:
+ return wbKanjiText;
+ }
+ }
+#endif
+
+}
+#endif
+
+
diff --git a/private/mvdm/wow16/write/dbcs.h b/private/mvdm/wow16/write/dbcs.h
new file mode 100644
index 000000000..345df002d
--- /dev/null
+++ b/private/mvdm/wow16/write/dbcs.h
@@ -0,0 +1,13 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+#ifdef DBCS
+
+#define cchDBCS 2
+#define fkNonDBCS ((CHAR) 0)
+#define fkDBCS1 ((CHAR) 1)
+#define fkDBCS2 ((CHAR) 2)
+
+#define MAKEWORD(_bHi, _bLo) ((((WORD) _bHi) << 8) | ((WORD) _bLo))
+
+#endif
diff --git a/private/mvdm/wow16/write/debug.c b/private/mvdm/wow16/write/debug.c
new file mode 100644
index 000000000..e919f2266
--- /dev/null
+++ b/private/mvdm/wow16/write/debug.c
@@ -0,0 +1,376 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* DEBUG.C -- Diagnostic routines for WRITE */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOATOM
+#define NODRAWTEXT
+#define NOMETAFILE
+#define NOOPENFILE
+#define NOWH
+#define NOWINOFFSETS
+#define NOOPENFILE
+#define NORECT
+#define NOSOUND
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include "prmdefs.h"
+#include "editdefs.h"
+#include "docdefs.h"
+
+extern struct WWD rgwwd[];
+
+
+extern beep();
+extern toggleProf();
+
+#ifdef DEBUG
+
+BOOL fDebugOut = TRUE;
+
+fnTest()
+{
+beep();
+TestFormat();
+beep();
+beep();
+dbgWait(); /* for use by symdeb to check variables */
+}
+
+TestFormat()
+{
+ //toggleProf();
+}
+
+dbgWait()
+{
+}
+
+
+/* --- Integrity check for all piece tables in all docs --- */
+
+CheckPctb()
+{
+extern int fnMac;
+extern int fPctbCheck;
+extern struct DOD (**hpdocdod) [];
+extern struct FCB (**hpfnfcb) [];
+extern int docMac;
+int doc;
+struct PCTB **hpctb;
+struct PCTB *ppctb;
+struct DOD *pdod;
+struct PCD *ppcd;
+int ipcd;
+
+if (!fPctbCheck)
+ return;
+
+for ( doc = 0, pdod = &(**hpdocdod) [0] ; doc < docMac; doc++, pdod++ )
+ if ((hpctb = pdod->hpctb) != 0)
+ { /* Doc entry is nonempty -- check it */
+ ppctb = *hpctb;
+
+ /* # pieces used does not exceed # allocated */
+ Assert( ppctb->ipcdMac <= ppctb->ipcdMax );
+ Assert( ppctb->ipcdMac >= 1 );
+
+#ifndef OURHEAP
+ /* handle contains enough space for pieces */
+ Assert( LocalSize( (HANDLE)hpctb ) >= sizeof (struct PCTB) +
+ (sizeof (struct PCD) * (ppctb->ipcdMax - cpcdInit)));
+#endif
+
+ /* Now check the contents of the pieces */
+
+ {
+
+ /* cpMin of first piece is always 0 for nonnull piece table */
+ Assert( ppctb->rgpcd [0].cpMin == cp0 || ppctb->rgpcd [0].fn == fnNil);
+
+ for ( ipcd = 0, ppcd = &(ppctb->rgpcd [0]); ipcd < ppctb->ipcdMac;
+ ipcd++, ppcd++ )
+ {
+ int fn = ppcd->fn;
+ typeFC fc = ppcd->fc;
+ unsigned sprm;
+ struct FCB *pfcb;
+
+ if (fn == fnNil)
+ { /* end piece */
+
+ /* first piece with fnNil is in fact the end piece */
+ /* Assert( ipcd == ppctb->ipcdMac - 1 ); */
+ /* end piece is intact */
+ Assert( bPRMNIL(ppcd->prm) );
+ break;
+ }
+
+ if (ipcd > 0)
+ /* Pieces are in ascending cp order */
+ Assert(ppcd->cpMin > (ppcd-1)->cpMin);
+
+ /* fn is valid */
+ Assert( (fn >= 0 && fn < fnMac) || fn == fnInsert );
+ pfcb = &(**hpfnfcb) [fn];
+ /* fn does not point to an unallocated fcb entry */
+ Assert( pfcb->rfn != rfnFree );
+ /* fc is reasonable for the fn */
+ Assert( fc >= 0 );
+ Assert( fc + (ppcd+1)->cpMin - ppcd->cpMin <= pfcb->fcMac );
+
+ /* prm is a valid value */
+ Assert( bPRMNIL(ppcd->prm) ||
+ (((struct PRM *) &ppcd->prm)->fComplex) ||
+ ((sprm = ((struct PRM *) &ppcd->prm)->sprm) > 0 &&
+ sprm < sprmMax) );
+ }
+ }
+
+ }
+}
+
+
+
+/* COMM Output routines */
+
+#define cchSzCommMax 100
+
+static CHAR szCRLF[] = "\r\n";
+BOOL vfCommDebug = fTrue; /* True for AUX, False for LPT */
+
+#if WINVER < 0x300
+/* This method isn't quite working under Win 3.0 ..pault */
+void CommSz( CHAR * ); /* Main string output, defined in doslib.asm */
+#else
+void CommSz( psz )
+register CHAR *psz;
+{
+ CHAR szT[512];
+ char *pszT;
+
+ if (fDebugOut)
+ {
+ /* The following loops essentially copies psz to szT
+ but with the addition that chars > 127 are changed
+ to a representation readable on a dumb terminal, i.e.
+ ASCII 164 shows up as '{164}' ..pault */
+
+ for (pszT = szT; ; psz++)
+ {
+ if (*psz < 128)
+ *(pszT++) = *psz;
+ else
+ {
+ *(pszT++) = '{';
+ ncvtu((int) *psz, &pszT);
+ *(pszT++) = '}';
+ }
+ if (*psz == '\0') /* finally copied null terminator */
+ break;
+ }
+
+ OutputDebugString( (LPSTR) szT );
+ }
+}
+#endif
+
+
+CommSzNum( sz, num )
+CHAR *sz;
+int num;
+{
+CHAR szBuf[ cchSzCommMax ];
+CHAR *pch = szBuf;
+
+Assert( CchSz( sz ) <= cchSzCommMax );
+
+pch = &szBuf[ CchCopySz( sz, szBuf ) ];
+ncvtu( num, &pch );
+
+CchCopySz( szCRLF, pch );
+
+CommSz( szBuf );
+}
+
+
+/* This is extremely useful when displaying coordinates
+ when the values are not in contiguous locations */
+CommSzNumNum( sz, num, num2 )
+CHAR *sz;
+int num, num2;
+{
+CHAR szBuf[ cchSzCommMax ];
+CHAR *pch = szBuf;
+
+Assert( CchSz( sz ) <= cchSzCommMax );
+
+pch = &szBuf[ CchCopySz( sz, szBuf ) ];
+ncvtu( num, &pch );
+*(pch++) = ' ';
+ncvtu( num2, &pch );
+
+CchCopySz( szCRLF, pch );
+
+CommSz( szBuf );
+}
+
+
+CommSzRgNum( sz, rgw, cw)
+CHAR *sz;
+int *rgw;
+int cw;
+{
+CHAR szBuf[ cchSzCommMax ];
+CHAR *pch = szBuf;
+
+Assert( CchSz( sz ) <= cchSzCommMax );
+
+pch = &szBuf[ CchCopySz( sz, szBuf ) ];
+for ( ; cw > 0; cw--)
+ {
+ ncvtu( *(rgw++), &pch );
+ *(pch++) = ' ';
+ }
+
+CchCopySz( szCRLF, pch );
+
+CommSz( szBuf );
+}
+
+
+CommSzSz( sz1, sz2 )
+CHAR *sz1, *sz2;
+{
+CHAR szBuf[ cchSzCommMax ];
+int cch;
+
+Assert( CchSz( sz1 ) + CchSz( sz2 ) - 1 <= cchSzCommMax );
+
+cch = CchCopySz( sz1, szBuf );
+cch += CchCopySz( sz2, &szBuf[ cch ] );
+CchCopySz( szCRLF, &szBuf[ cch ] );
+
+CommSz( szBuf );
+}
+
+
+
+/* ASSERT */
+
+Do_Assert(pch, line, f)
+PCH pch;
+int line;
+BOOL f;
+{
+ extern HWND vhWndMsgBoxParent;
+ extern FARPROC lpDialogAlert;
+ static CHAR szAssert[] = "Assertion failure in ";
+ static CHAR szLine[] = " at line ";
+
+
+if (f)
+ return;
+ else
+ {
+#ifdef OURHEAP
+ extern int cHpFreeze;
+ int cHpFreezeT = cHpFreeze;
+#endif
+ CHAR szAlertMsg[50];
+ PCH pchtmp;
+ int cch;
+ int idi;
+ HWND hWndParent = (vhWndMsgBoxParent == NULL) ?
+ wwdCurrentDoc.wwptr : vhWndMsgBoxParent;
+
+ bltbc((PCH)szAlertMsg, 0, 50);
+ bltbyte((PCH)szAssert, (PCH)szAlertMsg, 21);
+ pchtmp = (PCH)&szAlertMsg[21];
+ bltbyte((PCH)pch, pchtmp, (cch = CchSz(pch) - 1));
+ pchtmp += cch;
+ bltbyte((PCH)szLine, pchtmp, 9);
+ pchtmp += 9;
+ ncvtu(line, (PCH)&pchtmp) - 1;
+#ifdef OURHEAP
+ cHpFreeze = 0; /* So we don't panic in MdocLoseFocus */
+#endif
+
+ do
+ {
+ idi = MessageBox( hWndParent, (LPSTR) szAlertMsg,
+ (LPSTR)"Assert",
+ MB_ABORTRETRYIGNORE | MB_SYSTEMMODAL);
+ switch (idi) {
+ default:
+ case IDABORT:
+ case IDCANCEL:
+ FatalExit( line );
+ break;
+
+ case IDIGNORE:
+#ifdef OURHEAP
+ cHpFreeze = cHpFreezeT;
+#endif
+ return;
+ case IDRETRY:
+ break;
+ }
+ } while (idi == IDRETRY);
+ } /* end else */
+} /* end of _Assert */
+
+
+ShowDocPcd(szID, doc)
+ CHAR *szID;
+ int doc;
+{
+ struct PCTB **hpctb;
+ struct PCD *ppcdCur, *ppcdMac;
+ extern struct DOD (**hpdocdod)[];
+
+ hpctb = (**hpdocdod)[doc].hpctb;
+ ppcdCur = &(**hpctb).rgpcd[0];
+ ppcdMac = &(**hpctb).rgpcd[(**hpctb).ipcdMac];
+ for (; ppcdCur < ppcdMac; ppcdCur++)
+ {
+ ShowPpcd(szID, ppcdCur);
+ }
+}
+
+
+ShowPpcd(szID, ppcd)
+ CHAR *szID;
+ struct PCD *ppcd;
+{
+ /* Dump a given piece descriptor on COM1: along with a
+ given an ID string. */
+ CommSz(szID);
+ CommSz("\r\n");
+
+ CommSzNum("ppcd: ", (int) ppcd);
+ CommSzNum("cpMin: ", (int) (ppcd->cpMin));
+ CommSzSz("fNoParaLast: ", (ppcd->fNoParaLast) ? "TRUE" : "FALSE");
+ CommSzNum("fn: ", (int) (ppcd->fn));
+ CommSzNum("fc: ", (int) (ppcd->fc));
+ CommSzNum("prm: ", (int) *((int *) &(ppcd->prm)));
+}
+
+
+
+#endif /* DEBUG */
diff --git a/private/mvdm/wow16/write/debug.h b/private/mvdm/wow16/write/debug.h
new file mode 100644
index 000000000..936f7285c
--- /dev/null
+++ b/private/mvdm/wow16/write/debug.h
@@ -0,0 +1,15 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#ifdef DEBUG
+
+#ifdef SCRIBBLE
+#define Scribble(a, b) fnScribble(a, b)
+#else /* not SCRIBBLE */
+#define Scribble(a, b)
+#endif /* not SCRIBBLE */
+
+#else /* not DEBUG */
+#define Scribble(a, b)
+#endif /* not DEBUG */
diff --git a/private/mvdm/wow16/write/diaalert.c b/private/mvdm/wow16/write/diaalert.c
new file mode 100644
index 000000000..d53880d7f
--- /dev/null
+++ b/private/mvdm/wow16/write/diaalert.c
@@ -0,0 +1,830 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOSCALABLEFONT
+#define NOSYSPARAMSINFO
+#define NODBCS
+#define NODRIVERS
+#define NODEFERWINDOWPOS
+#define NOPROFILER
+#define NOHELP
+#define NOKEYSTATES
+#define NOWINMESSAGES
+#define NOATOM
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCOMM
+#define NODRAWTEXT
+#define NOGDI
+#define NOGDIOBJ
+#define NOGDICAPMASKS
+#define NOBITMAP
+#define NOKEYSTATE
+#define NOMENUS
+#define NOMETAFILE
+#define NOPEN
+#define NOOPENFILE
+#define NORASTEROPS
+#define NORECT
+#define NOSCROLL
+#define NOSHOWWINDOW
+#define NOSOUND
+#define NOSYSCOMMANDS
+#define NOSYSMETRICS
+#define NOTEXTMETRIC
+#define NOVIRTUALKEYCODES
+#define NOWH
+#define NOWINOFFSETS
+#define NOWINSTYLES
+#define NOUAC
+#define NOIDISAVEPRINT
+#define NOSTRUNDO
+#define NOCTLMGR
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "code.h"
+#include "debug.h"
+#include "dlgdefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "wwdefs.h"
+
+extern struct WWD rgwwd[];
+extern int utCur;
+extern int vfInitializing;
+extern CHAR szAppName[];
+extern struct FCB (**hpfnfcb)[];
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern typeTS tsMruBps;
+extern int vfSysFull;
+extern int ferror;
+extern int vfnWriting;
+extern int vibpWriting;
+extern HANDLE hMmwModInstance;
+extern HWND vhWndMsgBoxParent;
+extern int vfMemMsgReported;
+extern int vfDeactByOtherApp;
+extern MSG vmsgLast;
+extern HWND vhDlgFind;
+extern HWND vhDlgChange;
+extern HWND vhDlgRunningHead;
+extern HANDLE hParentWw;
+
+
+HANDLE hszNoMemory = NULL;
+HANDLE hszDirtyDoc = NULL;
+HANDLE hszCantPrint = NULL;
+HANDLE hszPRFAIL = NULL;
+HANDLE hszCantRunM = NULL;
+HANDLE hszCantRunF = NULL;
+HANDLE hszWinFailure = NULL;
+BOOL vfWinFailure = FALSE;
+#ifdef INEFFLOCKDOWN
+FARPROC lpDialogBadMargins;
+#endif
+
+#define FInModeless(hWnd) (hWnd == vhDlgFind || hWnd == vhDlgChange || \
+ hWnd == vhDlgRunningHead)
+
+CHAR *PchFillPchId( CHAR *, int, int );
+NEAR WaitBeforePostMsg(int);
+
+#ifdef CANCELMSG /* During debug, permit an abort for stack traces */
+#define MB_MESSAGE (MB_OKCANCEL | MB_APPLMODAL | MB_ICONASTERISK)
+#define MB_ERROR (MB_OKCANCEL | MB_APPLMODAL | MB_ICONEXCLAMATION)
+#define MB_TROUBLE (MB_OKCANCEL | MB_APPLMODAL | MB_ICONHAND)
+#else
+#define MB_MESSAGE (MB_OK | MB_APPLMODAL | MB_ICONASTERISK)
+#define MB_ERROR (MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION)
+#define MB_TROUBLE (MB_OK | MB_APPLMODAL | MB_ICONHAND)
+#endif
+#define MB_DEFYESQUESTION (MB_YESNOCANCEL | MB_APPLMODAL | MB_ICONHAND)
+#define MB_DEFNOQUESTION (MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_APPLMODAL | MB_ICONHAND)
+
+
+ErrorLevel(IDPMT idpmt)
+{
+
+/* A long story. But to fix Winbug #1097, we need to take special
+ exception for this error message -- when this is displayed in a
+ low mem situation, this must be system modal (match params used
+ in FRenderAll() ...pault */
+if (idpmt == IDPMTClipLarge)
+ return(MB_OK | MB_SYSTEMMODAL | MB_ICONHAND);
+
+else
+ switch (idpmt & MB_ERRMASK)
+ {
+ case MB_ERRASTR: /* * level */
+ return(MB_MESSAGE);
+ case MB_ERREXCL: /* ! level */
+ return(MB_ERROR);
+ case MB_ERRQUES: /* ? level */
+ return(MB_DEFYESQUESTION);
+ case MB_ERRHAND: /* HAND level */
+ return(MB_TROUBLE);
+ default:
+ Assert(FALSE);
+ }
+}
+
+
+int far Abort(response)
+int response;
+{
+ for( ; ; );
+}
+
+#ifdef DEBUG
+ErrorWithMsg(IDPMT idpmt, CHAR *szMessage)
+{
+#ifdef REALDEBUG
+ extern int vfOutOfMemory;
+ CHAR szBuf[cchMaxSz];
+ int errlevel = ErrorLevel(idpmt);
+ BOOL fDisableParent = FALSE;
+ register HWND hWndParent = (vhWndMsgBoxParent == NULL) ?
+ hParentWw : vhWndMsgBoxParent;
+
+ Assert(IsWindow(hWndParent));
+
+ if (idpmt == IDPMTNoMemory)
+ {
+ vfOutOfMemory = TRUE;
+ if (vfMemMsgReported)
+ {
+ return;
+ }
+ vfMemMsgReported = TRUE;
+ }
+ if (ferror)
+ return;
+
+ ferror = TRUE;
+
+ if (vfInitializing)
+ return;
+
+ CchCopySz( szMessage, PchFillPchId( szBuf, idpmt, sizeof(szBuf) ) );
+ if (vfDeactByOtherApp && !InSendMessage())
+ WaitBeforePostMsg(errlevel);
+
+/* force user to answer the error msg */
+ if (hWndParent != NULL && FInModeless(hWndParent))
+ {
+ EnableExcept(hWndParent, FALSE);
+ }
+ else
+ {
+ if (hWndParent != NULL && !IsWindowEnabled(hWndParent))
+ {
+ EnableWindow(hWndParent, TRUE);
+ fDisableParent = TRUE;
+ }
+ EnableOtherModeless(FALSE);
+ }
+
+ if (MessageBox(hWndParent, (LPSTR)szBuf,
+ (LPSTR)NULL, errlevel) == IDCANCEL)
+ /* A debugging feature -- show stack trace if he hit "cancel" */
+ FatalExit( 0 );
+
+ if (hWndParent != NULL && FInModeless(hWndParent))
+ {
+ EnableExcept(hWndParent, TRUE);
+ }
+ else
+ {
+ if (fDisableParent)
+ {
+ EnableWindow(hWndParent, FALSE);
+ }
+ EnableOtherModeless(TRUE);
+ }
+#else
+ Error( idpmt );
+#endif
+}
+#endif /* DEBUG */
+
+void Error(IDPMT idpmt)
+{
+ extern int vfOutOfMemory;
+ CHAR szBuf [cchMaxSz];
+ HANDLE hMsg;
+ LPCH lpch;
+ static int nRecurse=0;
+ int errlevel = ErrorLevel(idpmt);
+ register HWND hWndParent = (vhWndMsgBoxParent == NULL) ? hParentWw :
+ vhWndMsgBoxParent;
+
+ if (nRecurse)
+ return;
+
+ ++nRecurse;
+
+ Assert((hWndParent == NULL) || IsWindow(hWndParent));
+
+ if (idpmt == IDPMTNoMemory)
+ {
+ vfOutOfMemory = TRUE;
+ if (vfMemMsgReported)
+ {
+ goto end;
+ }
+ vfMemMsgReported = TRUE;
+ }
+
+ if (!ferror && !vfInitializing)
+ {
+ CloseEveryRfn( FALSE );
+ switch (idpmt)
+ {
+ case IDPMTNoMemory:
+ hMsg = hszNoMemory;
+GetMsg:
+ if (hMsg == NULL || (lpch = GlobalLock(hMsg)) == NULL)
+ {
+ goto end;
+ }
+ bltbx(lpch, (LPCH)szBuf, LOWORD(GlobalSize(hMsg)));
+ GlobalUnlock(hMsg);
+ break;
+ case IDPMTCantPrint:
+ hMsg = hszCantPrint;
+ goto GetMsg;
+ case IDPMTPRFAIL:
+ hMsg = hszPRFAIL;
+ goto GetMsg;
+ case IDPMTCantRunM:
+ hMsg = hszCantRunM;
+ goto GetMsg;
+ case IDPMTCantRunF:
+ hMsg = hszCantRunF;
+ goto GetMsg;
+ case IDPMTWinFailure:
+ hMsg = hszWinFailure;
+ goto GetMsg;
+ default:
+ PchFillPchId( szBuf, idpmt, sizeof(szBuf) );
+ break;
+ }
+ if (vfDeactByOtherApp && !InSendMessage())
+ {
+ WaitBeforePostMsg(errlevel);
+ }
+
+#ifdef CANCELMSG
+ if (IdPromptBoxSz( hWndParent, szBuf, errlevel ) == IDCANCEL)
+ {
+ /* A debugging feature -- show stack trace if he hit "cancel" */
+ FatalExit( 100 );
+ }
+#else
+ IdPromptBoxSz( hWndParent, szBuf, errlevel );
+#endif
+ }
+
+ if (errlevel != MB_MESSAGE)
+ {
+ ferror = TRUE;
+ }
+
+ end:
+ --nRecurse;
+}
+/* end of E r r o r */
+
+
+IdPromptBoxSz( hWndParent, sz, mb )
+HWND hWndParent;
+CHAR sz[];
+int mb;
+{ /* Put up a message box with string sz. mb specifies buttons to display,
+ "level" of message (HAND, EXCL, etc.).
+ hWndParent is the parent of the message box.
+ Returns the id of the button selected by the user */
+
+ int id;
+ BOOL fDisableParent = FALSE;
+ extern int wwMac;
+ int wwMacSave=wwMac;
+
+ Assert((hWndParent == NULL) || IsWindow(hWndParent));
+
+ if ((mb == MB_ERROR) || (mb == MB_TROUBLE))
+ {
+ extern int ferror;
+ extern int vfInitializing;
+
+ if (ferror)
+ return;
+ ferror = TRUE;
+ if (vfInitializing)
+ return;
+ }
+
+ CloseEveryRfn( FALSE ); /* Protect against disk swap while in message box */
+
+ /* don't allow painting doc, it may be in an unpaintable state (5.8.91) v-dougk */
+ if (mb == MB_TROUBLE)
+ wwMac=0;
+
+ /* force user to answer the msg */
+ if (hWndParent != NULL && FInModeless(hWndParent))
+ {
+ EnableExcept(hWndParent, FALSE);
+ }
+ else
+ {
+ if (hWndParent != NULL && !IsWindowEnabled(hWndParent))
+ {
+ EnableWindow(hWndParent, TRUE);
+ fDisableParent = TRUE;
+ }
+ EnableOtherModeless(FALSE);
+ }
+
+ /* We almost ALWAYS want the parent window to be passed to MessageBox
+ except in a couple RARE cases where even Write's main text window
+ hasn't yet gotten displayed. In that case we'll rip out of Windows
+ if we DO tell MessageBox about it... so NULL is the prescribed hwnd
+ to pass ..pault */
+
+ id = MessageBox((hWndParent == hParentWw && !IsWindowVisible(hWndParent)) ?
+ NULL : hWndParent, (LPSTR)sz, (LPSTR)szAppName, mb);
+
+ if (hWndParent != NULL && FInModeless(hWndParent))
+ {
+ EnableExcept(hWndParent, TRUE);
+ }
+ else
+ {
+ if (fDisableParent)
+ {
+ EnableWindow(hWndParent, FALSE);
+ }
+ EnableOtherModeless(TRUE);
+ }
+
+ wwMac = wwMacSave;
+ return id;
+}
+
+
+
+
+WinFailure()
+{
+ /* Windows has run out of memory. All we can do is discard all of our
+ Windows objects and pray the problem goes away. At the very worst, the
+ might be stuck with a saved document and unable to edit. */
+ /* FM 9/4/87 - Take out the call to FreeMemoryDC, hopefully to allow
+ Write to continue formatting lines. */
+
+ extern int vfOutOfMemory;
+
+ vfOutOfMemory = TRUE;
+ if (!vfWinFailure)
+ {
+ Error(IDPMTWinFailure);
+ vfWinFailure = TRUE;
+ }
+}
+
+
+#ifdef DEBUG
+DiskErrorWithMsg(idpmt, szMessage)
+IDPMT idpmt;
+CHAR *szMessage;
+#else
+DiskError(idpmt)
+IDPMT idpmt;
+#endif
+{ /* Description: Given an error message descriptor,
+ outputs an Alert Box. If the message indicates a serious disk
+ error, all files are closed and a flag set so that
+ the user will be restricted to the "Save" option only.
+ Returns: nothing
+ */
+ extern HWND hParentWw;
+ extern int vfDiskError;
+ extern int vfInitializing;
+ int errlevel = ErrorLevel( idpmt );
+ CHAR rgch[cchMaxSz];
+ CHAR *pch, *PchFillPchId();
+ register HWND hWndParent = (vhWndMsgBoxParent == NULL) ? hParentWw : vhWndMsgBoxParent;
+
+ Assert( (hWndParent == NULL) || IsWindow(hWndParent));
+
+ if (idpmt == IDPMTSDE || idpmt == IDPMTSDE2)
+ /* Serious disk error, put the guy in "SAVE-ONLY" state */
+ if (!vfDiskError)
+ {
+ vfDiskError = TRUE;
+ CloseEveryRfn( TRUE );
+ }
+
+ if (ferror || vfInitializing)
+ /* Only report one error per operation */
+ /* Don't report errors during inz; FInitWinInfo handles them */
+ return;
+
+ CloseEveryRfn( FALSE ); /* Close floppy files so the guy can change
+ disks while in the message box. */
+ pch = PchFillPchId( rgch, idpmt, sizeof(rgch) );
+
+#ifdef REALDEBUG /* Only enable extra message if really debugging */
+ CchCopySz( szMessage, pch );
+#endif
+ if (vfDeactByOtherApp && !InSendMessage())
+ WaitBeforePostMsg(errlevel);
+
+#ifdef CANCELMSG
+ if (IdPromptBoxSz( hWndParent, rgch, errlevel ) == IDCANCEL)
+ /* A debugging feature -- show stack trace if he hit "cancel" */
+ FatalExit( 0 );
+#else
+ IdPromptBoxSz( hWndParent, rgch, errlevel );
+#endif
+ ferror = TRUE;
+}
+/* end of D i s k E r r o r */
+
+
+ErrorBadMargins(hWnd, xaLeft, xaRight, yaTop, yaBottom)
+HWND hWnd;
+unsigned xaLeft;
+unsigned xaRight;
+unsigned yaTop;
+unsigned yaBottom;
+ {
+ /* Warn the user that the margins for this page must be xaLeft, xaRight,
+ yaTop, and yaBottom. */
+
+ extern CHAR *vpDlgBuf;
+ extern HANDLE hMmwModInstance;
+ extern int vfDeactByOtherApp;
+
+ unsigned rgzaMargin[4];
+#ifndef INEFFLOCKDOWN
+ extern BOOL far PASCAL DialogBadMargins(HWND, unsigned, WORD, LONG);
+ FARPROC lpDialogBadMargins;
+
+ if (!(lpDialogBadMargins = MakeProcInstance(DialogBadMargins, hMmwModInstance)))
+ {
+ WinFailure();
+ return;
+ }
+#endif
+
+ /* These values are kept on the stact to cut down on static variables. */
+ rgzaMargin[0] = xaLeft;
+ rgzaMargin[1] = xaRight;
+ rgzaMargin[2] = yaTop;
+ rgzaMargin[3] = yaBottom;
+ vpDlgBuf = (CHAR *)&rgzaMargin[0];
+
+ if (vfDeactByOtherApp && !InSendMessage())
+ WaitBeforePostMsg(MB_ERROR);
+
+ /* Create the "error" dialog box. */
+ DialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgBadMargins), hWnd,
+ lpDialogBadMargins);
+
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogBadMargins);
+#endif
+ }
+
+
+BOOL far PASCAL DialogBadMargins(hDlg, message, wParam, lParam)
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine handles the messages for the Bad Margins dialog box. */
+
+ extern CHAR *vpDlgBuf;
+ extern HWND vhWndMsgBoxParent;
+
+ int idi;
+ unsigned *prgzaMargin = (unsigned *)vpDlgBuf;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ /* Disable modeless dialog boxes. */
+ EnableOtherModeless(FALSE);
+
+ /* Set the values of the margins on the dialog box. */
+ for (idi = idiBMrgLeft; idi <= idiBMrgBottom; idi++, prgzaMargin++)
+ {
+ CHAR szT[cchMaxNum];
+ CHAR *pch = &szT[0];
+
+ CchExpZa(&pch, *prgzaMargin, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idi, (LPSTR)szT);
+ }
+ return (TRUE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ if (wParam == idiOk)
+ {
+ /* Destroy the tabs dialog box and enable any existing modeless
+ dialog boxes.*/
+ OurEndDialog(hDlg, NULL);
+ return (TRUE);
+ }
+ }
+ return (FALSE);
+ }
+
+
+/******************* ERROR SITUATION ROUTINES **************************/
+
+
+
+
+FGrowRgbp(cbp)
+int cbp;
+{
+#ifdef CKSM
+#ifdef DEBUG
+extern unsigned (**hpibpcksm) [];
+extern int ibpCksmMax;
+#endif
+#endif
+extern CHAR (*rgbp)[cbSector];
+extern CHAR *rgibpHash;
+extern int fIbpCheck;
+extern int vcCount;
+
+int ibpMaxNew = ibpMax + cbp;
+int iibpHashMaxNew;
+int cbNew;
+extern int ibpMaxFloat;
+
+if (ibpMaxNew > ibpMaxFloat)
+ return(FALSE);
+
+iibpHashMaxNew = ibpMaxNew * 2 + 1;
+cbNew = ibpMaxNew * cbSector * sizeof(CHAR) +
+ ((iibpHashMaxNew * sizeof(CHAR) + sizeof(int) - 1) & ~1) +
+ ((ibpMaxNew * sizeof(struct BPS) + sizeof(int) - 1) & ~1);
+
+if (LocalReAlloc((HANDLE)rgbp, cbNew, LPTR) == (HANDLE)NULL
+#ifdef CKSM
+#ifdef DEBUG
+ || !FChngSizeH( hpibpcksm, ibpMaxNew, FALSE )
+#endif
+#endif
+ )
+ {
+ if (cbp == 1)
+ {
+#ifdef CHIC
+ CommSzNum("Can't grow any more, current ibpMax = ", ibpMax);
+#endif
+ vcCount = 1024; /* so that we wait for a longer period before attemp again */
+ }
+ return(FALSE);
+ }
+else
+ {
+ int cbRgbpTotalNew = ibpMaxNew * cbSector;
+ int cbHashOrg = (iibpHashMax * sizeof(CHAR) + sizeof(int) - 1) & ~1;
+ int cbHashTotalNew = (iibpHashMaxNew * sizeof(CHAR) + sizeof(int) - 1) & ~1;
+ int cbBpsOrg = (ibpMax * sizeof(struct BPS) + sizeof(int) - 1) & ~1;
+ int ibp;
+ struct BPS *pbps;
+ CHAR *pNew;
+
+ /* blt tail end stuff first, in the following order --
+ mpibpbps, rgibpHash */
+
+ pNew = (CHAR *)rgbp + cbRgbpTotalNew + cbHashTotalNew;
+ bltbyte((CHAR*)mpibpbps, pNew, cbBpsOrg);
+ mpibpbps = (struct BPS *)pNew;
+
+ pNew = (CHAR *)rgbp + cbRgbpTotalNew;
+ bltbyte((CHAR *)rgibpHash, pNew, cbHashOrg);
+ rgibpHash = pNew;
+
+ for (ibp = 0, pbps = &mpibpbps[0]; ibp < ibpMaxNew; ibp++, pbps++)
+ {
+ if (ibp >= ibpMax)
+ {
+ /* initialize new bps */
+ pbps->fn = fnNil;
+ pbps->ts = tsMruBps - (ibpMax * 4);
+ }
+ pbps->ibpHashNext = ibpNil;
+ }
+ ibpMax = ibpMaxNew;
+ iibpHashMax = iibpHashMaxNew;
+#ifdef CKSM
+#ifdef DEBUG
+ ibpCksmMax = ibpMax;
+#endif
+#endif
+ RehashRgibpHash();
+#ifdef CHIC
+ CommSzNum("ibpMax = ", ibpMax);
+#endif
+ return(TRUE);
+ }
+}
+
+
+FStillOutOfMemory()
+{
+/* Return FALSE if there is enough memory available to pop us out of the "out of
+memory" state; TRUE otherwise */
+
+extern HANDLE vhReservedSpace;
+
+/* If we have had to give up our reserved space block, re-establish it BEFORE
+testing memory availability */
+
+ //return vfWinFailure;
+
+if (vhReservedSpace == NULL && (vhReservedSpace = LocalAlloc(LHND, cbReserve))
+ == NULL)
+ {
+ /* Nothing we can do. */
+ return (TRUE);
+ }
+
+/* OK, we have our reserve block, but do we have any other memory? (The use of
+cbReserve here is abritrary.) */
+if (LocalCompact(0) < cbReserve)
+ {
+ HANDLE hBuf = LocalAlloc(LMEM_MOVEABLE, cbReserve);
+
+ if (hBuf == NULL)
+ {
+ return(TRUE);
+ }
+ else
+ {
+ LocalFree(hBuf);
+ if (GlobalCompact(0) < cbReserve)
+ {
+ HANDLE hBuf = GlobalAlloc(GMEM_MOVEABLE, cbReserve);
+
+ if (hBuf == NULL)
+ {
+ return(TRUE);
+ }
+ else
+ {
+ GlobalFree(hBuf);
+ return(FALSE);
+ }
+ }
+ }
+ }
+
+
+return(FALSE);
+}
+
+
+
+IbpFindSlot(fn)
+int fn;
+{ /*
+ Description: Called from IbpEnsureValid (file.c) when a disk
+ full error is generated while trying to write out
+ scratch file records. A buffer slot for a piece of
+ file fn must be found
+ which is either non-dirty or is dirty but does
+ not contain scratch file information. We search
+ for the least recently used slot with the above
+ requirements.
+ If fn == fnScratch, we are trying to find a buffer
+ slot for a scratch file page. We may not put it in
+ the beginning cbpMustKeep slots.
+ Returns: ibp (slot #).
+ */
+ int ibpOuterLoop;
+ int ibpNextTry;
+ int ibpStart;
+ typeTS ts, tsLastTry = 0;
+ int ibp;
+
+#ifdef DEBUG
+ Assert(vfSysFull);
+#endif
+ if (fn == fnScratch) ibpStart = cbpMustKeep;
+ else ibpStart = 0;
+
+ /* In LRU timestamp order, we are looking for any slot */
+ /* which is non dirty or is dirty but is not part of the */
+ /* scratch file. */
+ for (ibpOuterLoop = ibpStart; ibpOuterLoop < ibpMax; ibpOuterLoop++)
+ {
+ struct BPS *pbps = &mpibpbps[ibpStart];
+ typeTS tsNextTry = -1;/* largest possible timestamp */
+ for(ibp = ibpStart; ibp < ibpMax; ibp++, pbps++)
+ {
+ ts = pbps->ts - (tsMruBps + 1);
+ if ((ts <= tsNextTry) && (ts > tsLastTry))
+ {
+ tsNextTry = ts;
+ ibpNextTry = ibp;
+ }
+ }
+ if (mpibpbps[ibpNextTry].fDirty == fFalse) break;
+ if (mpibpbps[ibpNextTry].fn != fnScratch)
+ {
+ FFlushFn(mpibpbps[ibpNextTry].fn);
+ /* We need not check a return value.
+ If the flush failed, vfDiskFull
+ will get set */
+ break;
+ }
+ else tsLastTry = tsNextTry;
+ }
+
+ if (ibpOuterLoop < ibpMax)
+ {
+ if (fn == vfnWriting) vibpWriting = ibpNextTry;
+ return(ibpNextTry);
+ }
+#ifdef DEBUG
+ Assert(FALSE); /* there just had to be some slot available */
+ /* not used by the scratch file */
+#endif
+} /* end IbpFindSlot */
+
+
+NEAR WaitBeforePostMsg(errlevel)
+int errlevel;
+{
+extern int flashID;
+extern HWND hwndWait;
+BOOL fParentEnable = IsWindowEnabled(hParentWw) || hwndWait;
+
+ MessageBeep(errlevel);
+
+ Diag(CommSzNum("WAITBEFOREPOSTMSG: vfDeactByOtherApp==",vfDeactByOtherApp));
+ if (!fParentEnable)
+ EnableWindow(hParentWw, TRUE); /* make sure parent window is enabled
+ to let the user click in it */
+ flashID = SetTimer(hParentWw, NULL, 500, (FARPROC)NULL);
+ while (vfDeactByOtherApp)
+ {
+ if (PeekMessage((LPMSG)&vmsgLast, (HWND)NULL, NULL, NULL, PM_REMOVE))
+ {
+ if (vfDeactByOtherApp)
+ {
+ TranslateMessage( (LPMSG)&vmsgLast);
+ DispatchMessage((LPMSG)&vmsgLast);
+ }
+ }
+ }
+
+ if (!fParentEnable)
+ EnableWindow(hParentWw, FALSE); /* reset */
+}
+
+
+EnableExcept(hWnd, fEnable)
+HWND hWnd;
+BOOL fEnable;
+{ /* Enable hParentWw and all modeless except hWnd according to fEnable */
+extern HWND vhDlgChange;
+extern HWND vhDlgFind;
+extern HWND vhDlgRunningHead;
+extern HWND hParentWw;
+
+ if (hWnd != vhDlgChange && IsWindow(vhDlgChange))
+ {
+ EnableWindow(vhDlgChange, fEnable);
+ }
+ if (hWnd != vhDlgFind && IsWindow(vhDlgFind))
+ {
+ EnableWindow(vhDlgFind, fEnable);
+ }
+ if (hWnd != vhDlgRunningHead && IsWindow(vhDlgRunningHead))
+ {
+ EnableWindow(vhDlgRunningHead, fEnable);
+ }
+ EnableWindow(hParentWw, fEnable);
+}
diff --git a/private/mvdm/wow16/write/diachgpr.c b/private/mvdm/wow16/write/diachgpr.c
new file mode 100644
index 000000000..284508ed5
--- /dev/null
+++ b/private/mvdm/wow16/write/diachgpr.c
@@ -0,0 +1,517 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1990 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the routines for the change printer dialog box. */
+
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCLIPBOARD
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMETAFILE
+#define NOWH
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOLOR
+#define NOSCROLL
+#define NOCOMM
+#include <windows.h>
+#ifdef EXTDEVMODESUPPORT
+#include <drivinit.h> /* new for win 3.0 and extdevicemode pr.drv. calls */
+#endif
+#include "mw.h"
+#include "dlgdefs.h"
+#include "cmddefs.h"
+#include "machdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "printdef.h"
+#include "str.h"
+
+extern CHAR szExtDrv[];
+extern CHAR szDeviceMode[];
+extern CHAR szNone[];
+extern HWND vhWnd;
+#ifdef EXTDEVMODESUPPORT
+extern CHAR szExtDevMode[];
+extern HANDLE hDevmodeData;
+#endif
+
+BOOL far PASCAL DialogPrinterSetup( hDlg, message, wParam, lParam )
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ extern CHAR *vpDlgBuf;
+ extern HWND hParentWw;
+ extern CHAR szDevices[];
+ extern CHAR stBuf[];
+ extern HDC vhDCPrinter;
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+ extern BOOL vfPrinterValid;
+ extern HANDLE hMmwModInstance;
+ extern BOOL vfPrDefault;
+ extern int vfCursorVisible;
+ extern HCURSOR vhcArrow;
+ extern HCURSOR vhcIBeam;
+ extern HWND vhWndMsgBoxParent;
+
+ void BuildPrSetupSz(CHAR *, CHAR *, CHAR *);
+
+ CHAR (***phszPr)[] = (CHAR (***)[])vpDlgBuf;
+ BOOL *pfOkEnabled = (BOOL *)(phszPr + 3);
+ CHAR stKeyName[cchMaxIDSTR];
+ CHAR szPrinters[cchMaxProfileSz];
+ CHAR *pchPrinters;
+ CHAR szDevSpec[cchMaxProfileSz];
+ CHAR szListEntry[cchMaxProfileSz];
+ CHAR *pchPort;
+ CHAR *pchDriver;
+ CHAR chNull = '\0';
+ int iPrinter;
+ BOOL fSingleClick;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ /* Disable any modeless dialog boxes. */
+ EnableOtherModeless(FALSE);
+
+ /* Save away the heap strings that describe the current printer. */
+ *phszPr++ = hszPrinter;
+ *phszPr++ = hszPrDriver;
+ *phszPr = hszPrPort;
+
+ /* Get a string that holds all of the printer names. */
+ GetProfileString((LPSTR)szDevices, (LPSTR)NULL, (LPSTR)&chNull,
+ (LPSTR)szPrinters, cchMaxProfileSz);
+
+ /* There must be two nulls at the end of the list. */
+ szPrinters[cchMaxProfileSz - 1] = szPrinters[cchMaxProfileSz - 2] =
+ '\0';
+
+ /* Parse out the names of the printers. */
+ pchPrinters = &szPrinters[0];
+ while (*pchPrinters != '\0')
+ {
+ /* Get the corresponding printer driver and port. */
+ GetProfileString((LPSTR)szDevices, (LPSTR)pchPrinters,
+ (LPSTR)&chNull, (LPSTR)szDevSpec, cchMaxProfileSz);
+ szDevSpec[cchMaxProfileSz - 1] = '\0';
+
+ /* If there is no driver for this printer, then it cannot be added
+ to the list. */
+ if (szDevSpec[0] != '\0')
+ {
+ /* Parse the ports and the driver. */
+ int cPort = ParseDeviceSz(szDevSpec, &pchPort, &pchDriver);
+ int iPort;
+
+ for (iPort = 0; iPort < cPort; iPort++)
+ {
+ /* Contruct the list box entry. */
+ BuildPrSetupSz(szListEntry, pchPrinters, pchPort);
+
+ /* Put the string in the list box
+ provided printer is not on "None" */
+
+ if (!FSzSame(pchPort, szNone))
+ SendDlgItemMessage(hDlg, idiPrterName, LB_ADDSTRING,
+ 0, (LONG)(LPSTR)szListEntry);
+
+ /* Bump the pointer to the next port in the list. */
+ pchPort += CchSz(pchPort);
+ }
+ }
+
+ /* Skip to the next printer in the list. */
+ while (*pchPrinters++) ;
+ }
+
+ /* Select the current printer. */
+ if (!(*pfOkEnabled = hszPrinter != NULL && hszPrPort != NULL &&
+ (BuildPrSetupSz(szListEntry, &(**hszPrinter)[0], &(**hszPrPort)[0]),
+ SendDlgItemMessage(hDlg, idiPrterName, LB_SELECTSTRING, -1,
+ (LONG)(LPSTR)szListEntry) >= 0)))
+ {
+ EnableWindow(GetDlgItem(hDlg, idiOk), FALSE);
+ }
+ return(fTrue); /* we processed the message */
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ {
+ EndLongOp(vhcArrow);
+ }
+ break; /* to return false below */
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ {
+ ShowCursor(wParam);
+ }
+ break; /* to return false below */
+
+ case WM_COMMAND:
+ fSingleClick = FALSE;
+ switch (wParam)
+ {
+ case idiPrterName:
+ if (HIWORD(lParam) == 1) /* remember single mouse clicks */
+ {
+ fSingleClick = fTrue;
+ }
+ else if (HIWORD(lParam) != 2) /* 2 is a double mouse click */
+ break; /* LBNmsg (listbox notification) we don't handle */
+
+ case idiPrterSetup:
+ case idiOk:
+ /* If none of the printers is currently selected... */
+ if ((iPrinter = SendDlgItemMessage(hDlg, idiPrterName, LB_GETCURSEL,
+ 0, 0L)) == -1)
+ {
+ /* Disable the "OK" button. */
+ if (*pfOkEnabled)
+ {
+ EnableWindow(GetDlgItem(hDlg, idiOk), FALSE);
+ *pfOkEnabled = FALSE;
+ }
+ return(fTrue); /* we processed the message */
+ }
+ else
+ {
+ CHAR *index(CHAR *, int);
+ CHAR *bltbyte(CHAR *, CHAR *, int);
+
+ CHAR *pch;
+ CHAR szDriver[cchMaxFile];
+ HANDLE hDriver;
+ FARPROC lpfnDevMode;
+#ifdef EXTDEVMODESUPPORT
+ BOOL fExtDevModeSupport = fTrue; /* assume until told otherwise */
+#endif
+ int cwsz;
+
+ if (fSingleClick)
+ {
+ /* If this is just a single mouse-click, then just update the
+ status of the "OK" button. */
+ if (!*pfOkEnabled)
+ {
+ EnableWindow(GetDlgItem(hDlg, idiOk), TRUE);
+ *pfOkEnabled = TRUE;
+ }
+ return(fTrue); /* we processed the message */
+ }
+
+ /* Let the user know that this may take a while. */
+ StartLongOp();
+
+ /* Get the printer's name, it's port, and it's driver. */
+ SendDlgItemMessage(hDlg, idiPrterName, LB_GETTEXT, iPrinter,
+ (LONG)(LPSTR)szListEntry);
+
+ /* Parse the port name out of the list entry. */
+ pchPort = &szListEntry[0] + CchSz(szListEntry) - 1;
+ while (*(pchPort - 1) != ' ')
+ {
+ pchPort--;
+ }
+
+ /* Parse the name of the printer out of the list entry. */
+ pch = &szListEntry[0];
+ FillStId(stBuf, IDSTROn, sizeof(stBuf));
+ for ( ; ; )
+ {
+ if ((pch = index(pch, ' ')) != 0 && FRgchSame(pch,
+ &stBuf[1], stBuf[0]))
+ {
+ *pch = '\0';
+ break;
+ }
+ pch++;
+ }
+
+ /* Get the driver name for this printer. */
+ GetProfileString((LPSTR)szDevices, (LPSTR)szListEntry,
+ (LPSTR)&chNull, (LPSTR)szDevSpec, cchMaxProfileSz);
+ ParseDeviceSz(szDevSpec, &pch, &pchDriver);
+
+ /* Update the heap strings describing the printer. */
+ if (hszPrinter != *phszPr)
+ {
+ FreeH(hszPrinter);
+ }
+ if (FNoHeap(hszPrinter = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(szListEntry)))))
+ {
+ hszPrinter = NULL;
+Error:
+ EndLongOp(vhcIBeam);
+ goto DestroyDlg;
+ }
+ blt(szListEntry, *hszPrinter, cwsz);
+ if (hszPrDriver != *(phszPr + 1))
+ {
+ FreeH(hszPrDriver);
+ }
+ if (FNoHeap(hszPrDriver = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(pchDriver)))))
+ {
+ hszPrDriver = NULL;
+ goto Error;
+ }
+ blt(pchDriver, *hszPrDriver, cwsz);
+ if (hszPrPort != *(phszPr + 2))
+ {
+ FreeH(hszPrPort);
+ }
+ if (FNoHeap(hszPrPort = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(pchPort)))))
+ {
+ hszPrPort = NULL;
+ goto Error;
+ }
+ blt(pchPort, *hszPrPort, cwsz);
+
+ /* Get the name of the driver, complete with extension. */
+ bltbyte(szExtDrv,
+ bltbyte(pchDriver, szDriver, CchSz(pchDriver) - 1),
+ CchSz(szExtDrv));
+
+ /* That's all we need for Setup ..pault */
+ if (wParam != idiPrterSetup)
+ goto LSetupDone;
+
+ /* The driver is not resident; attempt to load it. */
+ if ((hDriver = LoadLibrary((LPSTR)szDriver)) <= 32)
+ {
+ if (hDriver != 2)
+ {
+ /* If hDriver is 2, then the user has cancelled a dialog
+ box; there's no need to put up another. */
+ Error(IDPMTBadPrinter);
+ }
+Abort:
+ EndLongOp(vhcArrow);
+ return (TRUE); /* True means we processed the message */
+ }
+
+#ifdef EXTDEVMODESUPPORT
+ /* First see if ExtDeviceMode is supported (Win 3.0 drivers) */
+ if ((lpfnDevMode = GetProcAddress(hDriver,
+ (LPSTR)szExtDevMode)) == NULL)
+ {
+ fExtDevModeSupport = fFalse;
+#else
+ {
+#endif
+ /* Otherwise get the driver's DeviceMode() entry. */
+ if ((lpfnDevMode = GetProcAddress(hDriver,
+ (LPSTR)szDeviceMode)) == NULL)
+ {
+ /* No can do, eh? */
+ Error(IDPMTBadPrinter);
+LUnloadAndAbort:
+ FreeLibrary(hDriver);
+ goto Abort;
+ }
+ }
+
+#ifdef EXTDEVMODESUPPORT
+ /* Actual calls to the device modes setup.
+ Much of this new ExtDevModeSupport stuff
+ borrowed from MULTIPAD ..pault */
+
+ if (fExtDevModeSupport)
+ {
+ int cb;
+ int wId;
+ HANDLE hT;
+ LPDEVMODE lpOld, lpNew;
+ BOOL flag; /* devmode mode param */
+
+ /* pop up dialog for user */
+ flag = DM_PROMPT|DM_COPY;
+
+ if (hDevmodeData != NULL)
+ {
+ NPDEVMODE npOld;
+
+ /* Modify the user's last print settings */
+
+ flag |= DM_MODIFY;
+ lpOld = (LPDEVMODE)(npOld = (NPDEVMODE)LocalLock(hDevmodeData));
+
+ /* Check to see if they're using the same printer
+ driver as last time. If so, let them modify all
+ of their previous settings. If not, we tell
+ ExtDevMode to save as many of the hardware-
+ independent settings as it can (e.g. copies) */
+
+ if (!FSzSame(szListEntry, npOld->dmDeviceName))
+ {
+ npOld->dmDriverVersion = NULL;
+ npOld->dmDriverExtra = NULL;
+ bltsz(szListEntry, npOld->dmDeviceName);
+ }
+ }
+ else
+ /* We haven't done a printer setup yet this session */
+ lpOld = NULL;
+
+ /* how much space do we need for the data? */
+ cb = (*lpfnDevMode)(hDlg, hDriver, (LPSTR)NULL,
+ (LPSTR)szListEntry, (LPSTR)pchPort,
+ (LPDEVMODE)NULL, (LPSTR)NULL, 0);
+
+ if ((hT = LocalAlloc(LHND, cb)) == NULL)
+ goto LUnloadAndAbort;
+ lpNew = (LPDEVMODE)LocalLock(hT);
+
+ /* post the device mode dialog. 0 flag iff user hits OK button */
+ wId = (*lpfnDevMode)(hDlg, hDriver, (LPDEVMODE)lpNew,
+ (LPSTR)szListEntry, (LPSTR)pchPort,
+ (LPDEVMODE)lpOld, (LPSTR)NULL, flag);
+ if (wId == IDOK)
+ flag = 0;
+
+ /* unlock the input structures */
+ LocalUnlock(hT);
+ if (hDevmodeData != NULL)
+ LocalUnlock(hDevmodeData);
+
+ /* if the user hit OK and everything worked, free the original init
+ * data and retain the new one. Otherwise, toss the new buffer
+ */
+ if (flag != 0)
+ {
+ LocalFree(hT);
+ goto LUnloadAndAbort;
+ }
+ else
+ {
+ if (hDevmodeData != NULL)
+ LocalFree(hDevmodeData);
+ hDevmodeData = hT;
+ }
+ }
+
+ else /* older Win 2.0 driver, make DeviceMode call */
+ {
+ if (hDevmodeData != NULL)
+ {
+ /* We'd opened a Win3 printer driver before; now discard */
+ LocalFree(hDevmodeData);
+ hDevmodeData = NULL;
+ }
+#else /* ifdef EXTDEVMODESUPPORT */
+ {
+#endif /* else-def-EXTDEVMODESUPPORT */
+ if (!(*lpfnDevMode)(hDlg, hDriver, (LPSTR)szListEntry,
+ (LPSTR)pchPort))
+ goto LUnloadAndAbort;
+ }
+ FreeLibrary(hDriver);
+LSetupDone:
+ /* Let the user know the waiting is over. */
+ EndLongOp(vhcIBeam);
+
+ /* Printer setup should take us back to printer choices! */
+ if (wParam == idiPrterSetup)
+ {
+ return (TRUE); /* True means we processed the message */
+ }
+
+ /* Previously we freed these guys before returning
+ and that fouled up our heap ..pault */
+ FreeH(*phszPr++);
+ FreeH(*phszPr++);
+ FreeH(*phszPr);
+
+ vfPrDefault = FALSE;
+
+#ifdef WIN30
+ /* Need to indicate to FormatLine and Friends here
+ that we (may) have a different font pool to work
+ with and we should look at the new ones! Invalidating
+ the window will cause FormatLine to be called, and
+ when it hits the null printer dc it'll force a call
+ to GetPrinterDC ..pault */
+
+ FreePrinterDC();
+ InvalidateRect(vhWnd, (LPRECT) NULL, fFalse);
+#endif
+
+ goto DestroyDlg;
+ }
+
+ case idiCancel:
+ hszPrinter = *phszPr++;
+ hszPrDriver = *phszPr++;
+ hszPrPort = *phszPr;
+
+DestroyDlg:
+ /* Close the dialog box and enable any modeless dialog boxes. */
+ OurEndDialog(hDlg, NULL);
+ return(fTrue); /* we processed the message */
+ }
+ }
+
+ return(fFalse); /* if we got here we didn't process the message */
+ }
+
+
+void BuildPrSetupSz(szPrSetup, szPrinter, szPort)
+CHAR *szPrSetup;
+CHAR *szPrinter;
+CHAR *szPort;
+ {
+ /* This routine pieces together the string for the Change Printers list box.
+ szPrinter is the name of the printer, and szPort, the name of the port. It
+ is assumed that the setup string, szPrSetup, is large enough to hold the
+ string created by this routine. */
+
+ extern CHAR stBuf[];
+ extern CHAR szNul[];
+
+ CHAR *bltbyte(CHAR *, CHAR *, int);
+ CHAR ChUpper(CHAR);
+
+ register CHAR *pch;
+
+ pch = bltbyte(szPrinter, szPrSetup, CchSz(szPrinter) - 1);
+ FillStId(stBuf, IDSTROn, sizeof(stBuf));
+ pch = bltbyte(&stBuf[1], pch, stBuf[0]);
+
+ /* If the port name is not "None", then raise the port name to all capitals.
+ */
+ bltbyte(szPort, pch, CchSz(szPort));
+ if (WCompSz(pch, szNul) != 0)
+ {
+ while (*pch != '\0')
+ {
+ *pch++ = ChUpper(*pch);
+ }
+ }
+ }
+
+
diff --git a/private/mvdm/wow16/write/diadiv.c b/private/mvdm/wow16/write/diadiv.c
new file mode 100644
index 000000000..799a52007
--- /dev/null
+++ b/private/mvdm/wow16/write/diadiv.c
@@ -0,0 +1,628 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "mw.h"
+#include "dlgdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "docdefs.h"
+#include "str.h"
+#include "printdef.h"
+
+
+extern HCURSOR vhcArrow;
+extern int vfCursorVisible;
+
+extern int utCur; /* current conversion unit */
+
+
+BOOL far PASCAL DialogTabs(hDlg, message, wParam, lParam)
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine handles input to the Tabs dialog box. */
+
+ extern struct DOD (**hpdocdod)[];
+ extern int docCur;
+ extern int vdocParaCache;
+ extern HWND vhWndMsgBoxParent;
+ extern int ferror;
+
+ struct TBD (**hgtbd)[];
+ int idi;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ /* Disable modeless dialog boxes. */
+ EnableOtherModeless(FALSE);
+
+ /* Set up the fields for each of the tabs. */
+ hgtbd = (**hpdocdod)[docCur].hgtbd;
+ if (hgtbd != NULL)
+ {
+ struct TBD *ptbd;
+ unsigned dxa;
+ CHAR szT[cchMaxNum];
+ CHAR *pch;
+
+ for (ptbd = &(**hgtbd)[0], idi = idiTabPos0; (dxa = ptbd->dxa) != 0;
+ ptbd++, idi++)
+ {
+ pch = &szT[0];
+ CchExpZa(&pch, dxa, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idi, (LPSTR)szT);
+ CheckDlgButton(hDlg, idi + (idiTabDec0 - idiTabPos0), ptbd->jc
+ == (jcTabDecimal - jcTabMin));
+ }
+ }
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ struct TBD rgtbd[itbdMax];
+ struct TBD *ptbdLast;
+
+ case idiOk:
+ /* Sort the new tab descriptors. */
+ bltc(rgtbd, 0, itbdMax * cwTBD);
+ ptbdLast = &rgtbd[itbdMax - 1];
+ for (idi = idiTabPos0; idi <= idiTabPos11; idi++)
+ {
+ unsigned dxa;
+ unsigned dxaTab;
+ struct TBD *ptbd;
+
+ /* If an invalid position was entered, then punt. */
+ if (!FPdxaPosBIt(&dxa, hDlg, idi))
+ {
+ ferror = FALSE;
+ return (TRUE);
+ }
+
+ /* Ignore blank tabs or tabs at zero. */
+ if (dxa == valNil || dxa == 0)
+ {
+ continue;
+ }
+
+ for (ptbd = &rgtbd[0]; (dxaTab = ptbd->dxa) != 0; ptbd++)
+ {
+ /* If there is already a tab at this position, then ignore
+ the new tab. */
+ if (dxa == dxaTab)
+ {
+ goto GetNextTab;
+ }
+
+ /* If the new tab position is smaller than the current tab,
+ then make room for the new tab. */
+ if (dxa < dxaTab)
+ {
+ bltbyte(ptbd, ptbd + 1, (unsigned)ptbdLast - (unsigned)ptbd);
+ break;
+ }
+ }
+
+ /* Put the tab into rgtbd. */
+ ptbd->dxa = dxa;
+ ptbd->jc = (IsDlgButtonChecked(hDlg, idi + (idiTabDec0 -
+ idiTabPos0)) ? jcTabDecimal : jcTabLeft) - jcTabMin;
+GetNextTab:;
+ }
+
+ /* Set up the undo stuff. */
+ SetUndo(uacFormatTabs, docCur, cp0, cp0, docNil, cpNil, cpNil, 0);
+
+ /* Ensure that this document has a tab-stop table. */
+ if ((hgtbd = (**hpdocdod)[docCur].hgtbd) == NULL)
+ {
+ if (FNoHeap(hgtbd = (struct TBD (**)[])HAllocate(itbdMax *
+ cwTBD)))
+ {
+ goto DestroyDlg;
+ }
+ (**hpdocdod)[docCur].hgtbd = hgtbd;
+ }
+ blt(rgtbd, &(**hgtbd)[0], itbdMax * cwTBD);
+
+ /* Changing the tabs makes everything dirty. */
+ (**hpdocdod)[docCur].fDirty = TRUE;
+ vdocParaCache = docNil;
+ TrashAllWws();
+
+ case idiCancel:
+DestroyDlg:
+ /* Destroy the tabs dialog box and enable any existing modeless
+ dialog boxes.*/
+ OurEndDialog(hDlg, NULL);
+ break;
+
+ case idiTabClearAll:
+ /* Clear all of the tabs. */
+ for (idi = idiTabPos0; idi <= idiTabPos11; idi++)
+ {
+ SetDlgItemText(hDlg, idi, (LPSTR)"");
+ CheckDlgButton(hDlg, idi + (idiTabDec0 - idiTabPos0), FALSE);
+ }
+ break;
+
+ case idiTabDec0:
+ case idiTabDec1:
+ case idiTabDec2:
+ case idiTabDec3:
+ case idiTabDec4:
+ case idiTabDec5:
+ case idiTabDec6:
+ case idiTabDec7:
+ case idiTabDec8:
+ case idiTabDec9:
+ case idiTabDec10:
+ case idiTabDec11:
+ CheckDlgButton(hDlg, wParam, !IsDlgButtonChecked(hDlg, wParam));
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+ goto DestroyDlg;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/* end of DialogTabs */
+
+
+BOOL far PASCAL DialogDivision(hDlg, message, wParam, lParam)
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine handles input to the Division dialog box. */
+
+ extern struct DOD (**hpdocdod)[];
+ extern int docCur;
+ extern struct SEP vsepNormal;
+ extern int vdocSectCache;
+ extern BOOL vfPrinterValid;
+ extern int dxaPrOffset;
+ extern int dyaPrOffset;
+ extern int dxaPrPage;
+ extern int dyaPrPage;
+ extern HWND vhWndMsgBoxParent;
+ extern typeCP cpMinDocument;
+ extern int ferror;
+
+ struct SEP **hsep = (**hpdocdod)[docCur].hsep;
+ register struct SEP *psep;
+ CHAR szT[cchMaxNum];
+ CHAR *pch = &szT[0];
+
+#ifdef KINTL /* Kanji/International version */
+static int iRBDown;
+static int utInit;
+#endif
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+
+#ifdef KINTL /* Kanji/International version */
+ /* base initial setting on value in utCur */
+
+ utInit = utCur; /* for testing at ok */
+ if (utCur == utCm)
+ iRBDown = idiDivCm;
+ else
+ iRBDown = idiDivInch;
+
+ CheckDlgButton(hDlg, iRBDown, TRUE);
+
+#endif
+
+
+ EnableOtherModeless(FALSE);
+
+ /* Get a pointer to the section properties. */
+ psep = (hsep == NULL) ? &vsepNormal : *hsep;
+
+ /* Initialize the starting page number. */
+ if (psep->pgnStart != pgnNil)
+ {
+ szT[ncvtu(psep->pgnStart, &pch)] = '\0';
+ SetDlgItemText(hDlg, idiDivPNStart, (LPSTR)szT);
+ pch = &szT[0];
+ }
+ else
+ {
+ SetDlgItemText(hDlg, idiDivPNStart, (LPSTR)"1");
+ }
+ SelectIdiText(hDlg, idiDivPNStart);
+
+ /* Initialize the margins. */
+#ifdef DMARGINS
+ CommSzNum("Left Twips: ", psep->xaLeft);
+ CommSzNum("Right Twips: ", psep->xaMac - psep->dxaText - psep->xaLeft);
+ CommSzNum("Top Twips: ", psep->yaTop);
+ CommSzNum("Bottom Twips: ", psep->yaMac - psep->dyaText - psep->yaTop);
+#endif /* DEBUG */
+
+#ifdef KOREA
+ if (vfPrinterValid)
+ CchExpZa(&pch, imax(psep->xaLeft, dxaPrOffset), utCur,cchMaxNum);
+ else
+ CchExpZa(&pch, psep->xaLeft, utCur, cchMaxNum);
+#else
+ CchExpZa(&pch, psep->xaLeft, utCur, cchMaxNum);
+#endif
+
+ SetDlgItemText(hDlg, idiDivLMarg, (LPSTR)szT);
+ pch = &szT[0];
+#ifdef KOREA /* 90.12.29 sangl */
+ if ( vfPrinterValid )
+ CchExpZa (&pch, imax(psep->xaMac - psep->dxaText - psep->xaLeft,
+ vsepNormal.xaMac - dxaPrOffset - dxaPrPage), utCur, cchMaxNum);
+ else
+ CchExpZa(&pch, psep->xaMac - psep->dxaText - psep->xaLeft, utCur,
+ cchMaxNum);
+#else
+ CchExpZa(&pch, psep->xaMac - psep->dxaText - psep->xaLeft, utCur,
+ cchMaxNum);
+#endif
+
+ SetDlgItemText(hDlg, idiDivRMarg, (LPSTR)szT);
+ pch = &szT[0];
+#ifdef KOREA /* 90.12.29 sangl */
+ if (vfPrinterValid)
+ CchExpZa(&pch, imax( psep->yaTop, dyaPrOffset), utCur, cchMaxNum);
+ else
+ CchExpZa(&pch, psep->yaTop, utCur, cchMaxNum);
+#else
+ CchExpZa(&pch, psep->yaTop, utCur, cchMaxNum);
+#endif
+
+ SetDlgItemText(hDlg, idiDivTMarg, (LPSTR)szT);
+ pch = &szT[0];
+#ifdef KOREA /* 90.12.29 sangl */
+ if (vfPrinterValid)
+ CchExpZa(&pch, imax(psep->yaMac - psep->dyaText - psep->yaTop,
+ vsepNormal.yaMac - dyaPrOffset - dyaPrPage), utCur, cchMaxNum);
+ else
+ CchExpZa(&pch, psep->yaMac - psep->dyaText - psep->yaTop, utCur,
+ cchMaxNum);
+#else
+ CchExpZa(&pch, psep->yaMac - psep->dyaText - psep->yaTop, utCur,
+ cchMaxNum);
+#endif
+
+ SetDlgItemText(hDlg, idiDivBMarg, (LPSTR)szT);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ int pgn;
+ int iza;
+ int za[4];
+ int zaMin[4];
+ int dza;
+ int *pza;
+ int dxaMax;
+ int dyaMax;
+
+ case idiOk:
+ /* Is the page number valid? */
+ if (!WPwFromItW3Id(&pgn, hDlg, idiDivPNStart, pgnMin, pgnMax,
+ wNormal, IDPMTNPI))
+ {
+ ferror = FALSE; /* minor error, stay in dialog */
+ break;
+ }
+
+ /* Determine the minimum margins of the page. */
+ if (vfPrinterValid)
+ {
+ zaMin[0] = dxaPrOffset;
+ zaMin[1] = imax(0, vsepNormal.xaMac - dxaPrOffset - dxaPrPage);
+ zaMin[2] = dyaPrOffset;
+ zaMin[3] = imax(0, vsepNormal.yaMac - dyaPrOffset - dyaPrPage);
+ }
+ else
+ {
+ zaMin[0] = zaMin[1] = zaMin[2] = zaMin[3] = 0;
+ }
+
+ /* Are the margins valid? */
+ for (iza = 0; iza < 4; iza++)
+ {
+ /* Is the margin a positive measurement? */
+ if (!FPdxaPosIt(&za[iza], hDlg, iza + idiDivLMarg
+ ))
+ {
+ ferror = FALSE; /* minor error, stay in dialog */
+ return (TRUE);
+ }
+
+ /* Is it less than the minimum? */
+ if (FUserZaLessThanZa(za[iza], zaMin[iza]))
+ {
+ ErrorBadMargins(hDlg, zaMin[0], zaMin[1], zaMin[2],
+ zaMin[3]);
+ SelectIdiText(hDlg, iza + idiDivLMarg);
+ SetFocus(GetDlgItem(hDlg, iza + idiDivLMarg));
+ return (TRUE);
+ }
+ }
+#ifdef DMARGINS
+ CommSzNum("New Left Twips: ", za[0]);
+ CommSzNum("New Right Twips: ", za[1]);
+ CommSzNum("New Top Twips: ", za[2]);
+ CommSzNum("New Bottom Twips: ", za[3]);
+#endif /* DEBUG */
+
+ /* Ensure that this document has a valid section property
+ descriptor. */
+ if (hsep == NULL)
+ {
+ if (FNoHeap(hsep = (struct SEP **)HAllocate(cwSEP)))
+ {
+ goto DestroyDlg;
+ }
+ blt(&vsepNormal, *hsep, cwSEP);
+ (**hpdocdod)[docCur].hsep = hsep;
+ }
+ psep = *hsep;
+
+ /* Are the combined margins longer or wider than the page? */
+ pza = &za[0];
+ dxaMax = psep->xaMac - dxaMinUseful;
+ dyaMax = psep->yaMac - dyaMinUseful;
+ if ((dza = *pza) > dxaMax || (dza += *(++pza)) > dxaMax ||
+ (dza = *(++pza)) > dyaMax || (dza += *(++pza)) > dyaMax)
+ {
+ Error(IDPMTMTL);
+ ferror = FALSE; /* minor error, stay in dialog */
+ SelectIdiText(hDlg, (int)(idiDivLMarg + (pza - &za[0])));
+ SetFocus(GetDlgItem(hDlg, (int)(idiDivLMarg + (pza - &za[0]))));
+ return (FALSE);
+ }
+
+ /* If the margins have changed, then set the new values. */
+ if (psep->pgnStart != pgn || psep->xaLeft != za[0] || psep->dxaText
+ != psep->xaMac - za[0] - za[1] || psep->yaTop != za[2] ||
+ psep->dyaText != psep->yaMac - za[2] - za[3])
+ {
+ /* Set up the undo stuff. */
+ SetUndo(uacFormatSection, docCur, cp0, cp0, docNil, cpNil,
+ cpNil, 0);
+
+ /* Reset psep in case some heap movement has taken place. */
+ psep = *hsep;
+
+ if (psep->pgnStart != pgn)
+ {
+ /* Renumber the page table. */
+ extern int docMode;
+ register struct PGTB **hpgtb = (**hpdocdod)[docCur].hpgtb;
+ register struct PGD *ppgd;
+ int ipgd;
+ int cpgdMac;
+
+ /* Initialize page table if it does not already exist. */
+ if (hpgtb == NULL)
+ {
+ if (FNoHeap(hpgtb =
+ (struct PGTB **)HAllocate(cwPgtbBase + cpgdChunk *
+ cwPGD)))
+ {
+ NoUndo();
+ return(TRUE);
+ }
+ (**hpgtb).cpgdMax = cpgdChunk;
+ (**hpgtb).cpgd = 1;
+ (**hpgtb).rgpgd[0].cpMin = cpMinDocument;
+
+ /* Reset psep because of heap movement. */
+ psep = *hsep;
+ }
+
+ /* Save the starting page number in the section properties.
+ */
+ psep->pgnStart = pgn;
+
+ /* Update the page table with the new starting page number.
+ */
+ for (ipgd = 0, cpgdMac = (**hpgtb).cpgd, ppgd =
+ &((**hpgtb).rgpgd[0]) ; ipgd < cpgdMac; ipgd++, ppgd++)
+ {
+ ppgd->pgn = pgn++;
+ }
+
+ /* Force the page info window to be repainted. */
+ docMode = docNil;
+ }
+
+ /* Set the new section properties. */
+ psep->dxaText = psep->xaMac - (psep->xaLeft = za[0]) - za[1];
+ psep->dyaText = psep->yaMac - (psep->yaTop = za[2]) - za[3];
+
+ /* Invalidate the section cache. */
+ vdocSectCache = docNil;
+ TrashAllWws();
+
+ /* Mark the document as dirty. */
+ (**hpdocdod)[docCur].fDirty = TRUE;
+ }
+
+#ifdef KINTL /* Kanji/International version */
+ /* redraw ruler if visible and units changed */
+ if (utInit != utCur) {
+ ReframeRuler();
+ }
+#endif
+
+ goto DestroyDlg;
+
+ case idiCancel:
+
+#ifdef KINTL /* International version */
+ utCur = utInit; /* restore units at actual cancel */
+#endif /* KINTL */
+
+DestroyDlg:
+ OurEndDialog(hDlg, TRUE);
+ break;
+
+#ifdef KINTL /* International version */
+ {
+ int margin;
+
+/* Maximum number of characters in the edit control */
+#define cchMaxEditText 64
+
+ case idiDivInch:
+ utCur = utInch;
+ goto SetUnits;
+ case idiDivCm:
+ utCur = utCm;
+ /* measurment button fall into this code */
+SetUnits:
+ /* set up buttons appropriately */
+#ifdef INTL
+ CheckRadioButton(hDlg, idiDivInch, idiDivCm, wParam);
+#else /* KANJI */
+ CheckRadioButton(hDlg, idiDivInch, idiDivCch, wParam);
+#endif
+
+ if (wParam != iRBDown) {
+ /* reevaluate margin values based on new units */
+ iRBDown = wParam;
+
+ /* want most recently entered value from screen into
+ twips, then convert using current unit scale */
+
+ szT[0] = GetDlgItemText(hDlg, idiDivLMarg,
+ (LPSTR) &szT[1], cchMaxNum);
+ if (FZaFromSs (&margin, szT+1, *szT, utCur))
+ {
+ pch = &szT[0];
+ CchExpZa(&pch, margin, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idiDivLMarg, (LPSTR)szT);
+ }
+
+ szT[0] = GetDlgItemText(hDlg, idiDivRMarg,
+ (LPSTR) &szT[1], cchMaxNum);
+ if (FZaFromSs (&margin, szT+1, *szT, utCur))
+ {
+ pch = &szT[0];
+ CchExpZa(&pch, margin, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idiDivRMarg, (LPSTR)szT);
+ }
+
+ szT[0] = GetDlgItemText(hDlg, idiDivTMarg,
+ (LPSTR) &szT[1], cchMaxNum);
+ if (FZaFromSs (&margin, szT+1, *szT, utCur))
+ {
+ pch = &szT[0];
+ CchExpZa(&pch, margin, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idiDivTMarg, (LPSTR)szT);
+ }
+
+ szT[0] = GetDlgItemText(hDlg, idiDivBMarg,
+ (LPSTR) &szT[1], cchMaxNum);
+ if (FZaFromSs (&margin, szT+1, *szT, utCur))
+ {
+ pch = &szT[0];
+ CchExpZa(&pch, margin, utCur, cchMaxNum);
+ SetDlgItemText(hDlg, idiDivBMarg, (LPSTR)szT);
+ }
+ }
+
+ break;
+ }
+#endif /* KINTL */
+
+
+ default:
+ return (FALSE);
+ }
+ break;
+
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+} /* end of DialogDivision */
+
diff --git a/private/mvdm/wow16/write/diapara.c b/private/mvdm/wow16/write/diapara.c
new file mode 100644
index 000000000..368055fa1
--- /dev/null
+++ b/private/mvdm/wow16/write/diapara.c
@@ -0,0 +1,458 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* DiaPara.c -- Paragraph Format dialog box specific routines */
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCOMM
+#define NOSOUND
+#define NOSCROLL
+#define NOCOLOR
+#define NOBITMAP
+#define NOFONT
+#define NODRAWTEXT
+#define NOMSG
+#define NOWNDCLASS
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOGDI
+#define NOBRUSH
+#define NOPEN
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "prmdefs.h"
+#include "propdefs.h"
+#include "editdefs.h"
+#include "dlgdefs.h"
+#include "dispdefs.h"
+#include "str.h"
+#include "wwdefs.h"
+
+extern struct WWD *pwwdCur;
+extern HANDLE hParentWw;
+extern struct PAP vpapAbs;
+extern struct PAP *vppapNormal;
+extern int rgval[];
+extern typeCP cpMacCur;
+extern int utCur;
+extern struct SEL selCur; /* Current selection (i.e., sel in current ww */
+extern int docCur; /* Document in current ww */
+extern CHAR stBuf[];
+extern HWND vhWndMsgBoxParent;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+
+#ifdef RULERALSO /* enable out because no need to bring ruler up when tab or indents is invoked */
+extern int docRulerSprm;
+extern struct TBD rgtbdRuler[];
+extern HWND vhDlgIndent;
+extern BOOL vfDisableMenus;
+extern int vfTabsChanged;
+extern int vfTempRuler;
+extern struct WWD rgwwd[];
+#endif
+
+
+#ifdef CASHMERE
+/* D O F O R M A T P A R A */
+DoFormatPara(rgval)
+VAL rgval[];
+ /* add para sprms */
+
+ int val, ival;
+ int *pval;
+ int sprm;
+ struct PAP *ppap;
+ typeCP dcp;
+ typeCP cpFirst, cpLim;
+ struct SEL selSave;
+/* this temp array is used to assemble sprm values */
+ CHAR rgb[cchTBD * itbdMax + 2/* >> cwPAPBase */];
+ int rgw[cwPAPBase];
+ ppap = (struct PAP *)&rgw[0];
+
+ if (!FWriteCk(fwcNil))
+ return; /* Check for munging end mark in footnote window */
+
+ if (docRulerSprm != docNil) ClearRulerSprm();
+ ExpandCurSel(&selSave);
+
+ dcp = (cpLim = selCur.cpLim) - (cpFirst = selCur.cpFirst);
+ if (cpLim > cpMacCur)
+ {
+ SetUndo(uacReplNS, docCur, cpFirst, dcp,
+ docNil, cpNil, dcp - ccpEol, 0);
+ InsertEolInsert(docCur, cpMacCur);
+ }
+ else
+ SetUndo(uacReplNS, docCur, cpFirst, dcp,
+ docNil, cpNil, dcp, 0);
+/* reset adjusted selCur */
+ selCur.cpFirst = cpFirst;
+ selCur.cpLim = cpLim;
+
+
+/* any gray fields ? */
+ for (ival = 0; ival <= 8; ival++)
+ if (rgval[ival] == valNil)
+ {
+/* yes. generate sprms for any that are not gray */
+ for (ival = 0; ival <= 8; ival++)
+ if ((val = rgval[ival]) != valNil)
+ {
+ switch(ival)
+ {
+ case 0:
+ sprm = sprmPJc;
+ goto LPara1;
+ case 1:
+ val = !val;
+ sprm = sprmPKeep;
+ goto LPara1;
+ case 2:
+ sprm = sprmPLMarg;
+ break;
+ case 3:
+ sprm = sprmPFIndent;
+ break;
+ case 4:
+ sprm = sprmPRMarg;
+ break;
+ case 5:
+ sprm = sprmPDyaLine;
+ break;
+ case 6:
+ sprm = sprmPDyaBefore;
+ break;
+ case 7:
+ sprm = sprmPDyaAfter;
+ break;
+ case 8:
+ val = !val;
+ sprm = sprmPKeepFollow;
+ goto LPara1;
+ }
+/* we come here with one word value */
+ bltbyte(&val, &rgb[1], cchINT);
+ goto LPara2;
+/* we come here with one char value */
+LPara1: rgb[1] = val;
+LPara2: rgb[0] = sprm;
+ AddSprm(rgb);
+ }
+ goto ParaCommon;
+ }
+/* otherwise generate a sprm that applies all properties except the tabs */
+ blt(vppapNormal, ppap, cwPAPBase);
+ pval = &rgval[0];
+ ppap->jc = *pval++;
+ ppap->fKeep = !*pval++;
+ ppap->dxaLeft = *pval++;
+ ppap->dxaLeft1 = *pval++;
+ ppap->dxaRight = *pval++;
+ ppap->dyaLine = *pval++;
+ ppap->dyaBefore = *pval++;
+ ppap->dyaAfter = *pval++;
+ ppap->fKeepFollow = !*pval++;
+ bltbyte(ppap, &rgb[2], cwPAPBase * cchINT);
+ rgb[1] = cwPAPBase * cchINT;
+/* we have: sprm, rgb[1 - n] set up */
+ rgb[0] = sprmPSame;
+ CachePara(docCur, selCur.cpFirst);
+ if (CchDiffer(&vpapAbs, ppap, cwPAPBase * cchINT))
+ AddSprm(rgb);
+ParaCommon: ;
+ if (vfTabsChanged)
+ {
+ int itbd;
+ int cchRgtbd;
+/* some tab changes were also made in the ruler */
+ for (itbd = 0; rgtbdRuler[itbd].dxa != 0; itbd++);
+ bltbyte((CHAR *)rgtbdRuler, &rgb[2], cchRgtbd = cwTBD * cchINT * itbd);
+ rgb[1] = cchRgtbd;
+ rgb[0] = sprmPRgtbd;
+ AddSprm(rgb);
+ }
+ EndLookSel(&selSave, fTrue);
+ SetRgvalAgain(rgval, uacFormatPara);
+}
+
+#else /* MEMO, not CASHMERE */
+
+/* D O F O R M A T P A R A */
+DoFormatPara(rgval)
+VAL rgval[];
+{
+ /* add para sprms */
+
+ int val, ival;
+ int *pval;
+ int sprm;
+ struct PAP *ppap;
+ typeCP dcp;
+ typeCP cpFirst, cpLim;
+ struct SEL selSave;
+/* this temp array is used to assemble sprm values */
+ CHAR rgb[cchTBD * itbdMax + 2/* >> cwPAPBase */];
+ int rgw[cwPAPBase];
+ ppap = (struct PAP *)&rgw[0];
+
+ if (!FWriteOk( fwcNil ))
+ return;
+
+#ifdef ENABLE /* no ClearRulerSprm yet */
+ if (docRulerSprm != docNil) ClearRulerSprm();
+#endif
+ ExpandCurSel(&selSave);
+
+ dcp = (cpLim = selCur.cpLim) - (cpFirst = selCur.cpFirst);
+ if (cpLim > cpMacCur)
+ {
+ SetUndo(uacReplNS, docCur, cpFirst, dcp,
+ docNil, cpNil, dcp - ccpEol, 0);
+ InsertEolInsert(docCur, cpMacCur);
+ }
+ else
+ SetUndo(uacReplNS, docCur, cpFirst, dcp,
+ docNil, cpNil, dcp, 0);
+/* reset adjusted selCur */
+ selCur.cpFirst = cpFirst;
+ selCur.cpLim = cpLim;
+
+ for (ival = 0; ival <= 2; ival++)
+ if ((val = rgval[ival]) != valNil)
+ {
+ switch(ival)
+ {
+ case 0:
+ sprm = sprmPLMarg;
+ break;
+ case 1:
+ sprm = sprmPFIndent;
+ break;
+ case 2:
+ sprm = sprmPRMarg;
+ break;
+ }
+/* we come here with one word value */
+ bltbyte(&val, &rgb[1], cchINT);
+ rgb[0] = sprm;
+ AddSprm(rgb);
+ }
+
+#ifdef RULERALSO /* tabs in format para dialog box */
+ if (vfTabsChanged)
+ {
+ int itbd;
+ int cchRgtbd;
+/* some tab changes were also made in the ruler */
+ for (itbd = 0; rgtbdRuler[itbd].dxa != 0; itbd++);
+ bltbyte((CHAR *)rgtbdRuler, &rgb[2], cchRgtbd = cwTBD * cchINT * itbd);
+ rgb[1] = cchRgtbd;
+ rgb[0] = sprmPRgtbd;
+ AddSprm(rgb);
+ }
+#endif
+
+ EndLookSel(&selSave, fTrue);
+#ifdef ENABLE
+ SetRgvalAgain(rgval, uacFormatPara);
+#endif
+} /* end of DoFormatPara */
+#endif /* MEMO, not CASHMERE */
+
+
+/* P U T P A R A N U M */
+/* convert n according to unit ut, and leave result in stBuf */
+PutParaNum(n, ut)
+int n, ut;
+ {
+ CHAR *pch = &stBuf[1];
+ stBuf[0] = CchExpZa(&pch, n, ut, cchMaxNum);
+ }
+
+
+BOOL far PASCAL DialogParaFormats( hDlg, message, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+ /* This routine handles input to the Paragraph Formats dialog box. */
+ extern struct SEP vsepNormal;
+ extern int ferror;
+ unsigned dxaText;
+ int wLowLim;
+ int i;
+ TSV rgtsv[itsvchMax]; /* gets attributes and gray flags from CHP */
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+#ifdef RULERALSO /* enable out because no need to bring ruler up */
+ InitSpecialDialog(&vhDlgIndent, hDlg);
+#else
+ EnableOtherModeless(FALSE);
+#endif
+ GetRgtsvPapSel(rgtsv); /* get paragraph properties */
+
+ /* note the following loop assumes that the
+ itsv Indent codes are in the same order as
+ the idiPar Indent codes */
+
+ for (i = 0; i < 3; i++)
+ if (rgtsv[itsvLIndent + i].fGray == 0)
+ {
+ PutParaNum(rgtsv[itsvLIndent + i].wTsv, utCur);
+ SetDlgItemText(hDlg, (idiParLfIndent + i),
+ (LPSTR)&stBuf[1]);
+ }
+
+ SelectIdiText(hDlg, idiParLfIndent);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus right */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiOk:
+ /* Get xaLeft, First line, and xaRight */
+ if (!WPdxaFromItDxa2WId(&rgval[0], hDlg, idiParLfIndent, 0, dxaText = vsepNormal.dxaText,
+ wBlank | wSpaces, IDPMTNOTDXA))
+ {
+ ferror = FALSE; /* minor error, stay in dialog */
+ break;
+ }
+ if (rgval[0] == valNil)
+ wLowLim = 0;
+ else
+ wLowLim = (int) -rgval[0];
+ if (!WPdxaFromItDxa2WId(&rgval[1], hDlg, idiParFirst, wLowLim, dxaText,
+ wBlank | wSpaces, IDPMTNOTDXA) ||
+ !WPdxaFromItDxa2WId(&rgval[2], hDlg, idiParRtIndent, 0, dxaText,
+ wBlank | wSpaces, IDPMTNOTDXA))
+ {
+ ferror = FALSE; /* minor error, stay in dialog */
+ break;
+ }
+/* we have in rgval:
+ 0 xaLeft
+ 1 xaLeft1
+ 2 xaRight */
+ DoFormatPara(rgval);
+ /* FALL THROUGH */
+ case idiCancel:
+#ifdef RULERALSO /* enable out because no need to bring up ruler */
+ CancelSpecialDialog(&vhDlgIndent);
+#else
+ OurEndDialog(hDlg, TRUE);
+#endif
+ break;
+ default:
+ return(FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+#ifdef RULERALSO /* enable out because no need to bring up ruler */
+ CancelSpecialDialog(&vhDlgIndent);
+#else
+ OurEndDialog(hDlg, TRUE);
+#endif
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/* end of DialogParaFormats */
+
+
+#ifdef RULERALSO/* no need to bring up ruler when tab or indent dialog box was invoked */
+InitSpecialDialog(phDlg, hDlg)
+HANDLE *phDlg;
+HANDLE hDlg;
+{
+/* Special dialog box is a modal dialog box that needs to invoke a ruler if
+ not already there. Since the ruler is a child window, the parent has to
+ be enabled and other children except the ruler and/or modeless dialog
+ boxes has to be disabled. Top level menu and the system menu have to
+ be locked.
+
+ phDlg : address of the global handle to store the special
+ dialog created (ptr to either vhDlgIndent or vhDlgTab)
+ Ruler relies on these global handle to see if need to
+ update any dialog's items when tabs or indents are moved.
+ hDlg : handle to the special dialog box created.
+*/
+
+ *phDlg = hDlg;
+ EnableOtherModeless(FALSE); /* disable other modeless dialogs */
+ EnableWindow(hParentWw, TRUE);
+ EnableWindow(wwdCurrentDoc.wwptr, FALSE);
+ if (!pwwdCur->fRuler)
+ {
+ vfTempRuler = TRUE;
+ pwwdCur->fRuler = TRUE;
+ CreateRuler();
+ }
+ else
+ UpdateRuler();
+ vfTabsChanged = FALSE;
+ vfDisableMenus = TRUE;
+} /* InitSpecialDialog */
+
+
+CancelSpecialDialog(phDlg)
+HANDLE * phDlg;
+{
+/* Destroy the special dialog box involves destroying the ruler if it is
+ invoked by the creation of the dialog box, then enable the children
+ and/or any modeless dialogs that were disabled in InitSpecialDialog.
+ System menu and the top level menu has to be unlocked.
+ The last thing is to reset the global dialog handle (vhDlgTab or
+ vhDlgIndent). Ruler relies on these global handle to see if need to
+ update any dialog's items when tabs or indents are moved.
+
+ phDlg : address of the global handle that stores the special
+ dialog created (ptr to either vhDlgIndent or vhDlgTab)
+*/
+HANDLE hDlg = *phDlg;
+
+ if (vfTempRuler)
+ {
+ DestroyRuler();
+ vfTempRuler = FALSE;
+ pwwdCur->fRuler = FALSE;
+ }
+ else
+ UpdateRuler();
+ EndDialog(hDlg, TRUE);
+ EnableWindow(wwdCurrentDoc.wwptr, TRUE);
+ EnableOtherModeless(TRUE); /* enable other modeless dialogs */
+ *phDlg = (HANDLE)NULL;
+ vfDisableMenus = FALSE;
+
+} /* CancelSpecialDialog */
+#endif /* RULERALSO -- no need to bring up ruler when tab or indent dialog box is invoked */
diff --git a/private/mvdm/wow16/write/diaprint.c b/private/mvdm/wow16/write/diaprint.c
new file mode 100644
index 000000000..9b1c8936c
--- /dev/null
+++ b/private/mvdm/wow16/write/diaprint.c
@@ -0,0 +1,427 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1990 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the dialog box routines for the print dialog box and the
+printer initialization code. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCLIPBOARD
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOWH
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOLOR
+#define NOSCROLL
+#define NOCOMM
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "dlgdefs.h"
+#include "str.h"
+#include "printdef.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+
+
+fnPrPrinter()
+ {
+ /* This routine is the outside world's interface to the print code. */
+
+ extern HWND hParentWw;
+ extern HANDLE hMmwModInstance;
+ extern CHAR *vpDlgBuf;
+ extern int docCur;
+ CHAR rgbDlgBuf[sizeof(int) + 2 * sizeof(BOOL)];
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpDialogPrint;
+#else
+ BOOL far PASCAL DialogPrint(HWND, unsigned, WORD, LONG);
+ FARPROC lpDialogPrint;
+ if (!(lpDialogPrint = MakeProcInstance(DialogPrint, hMmwModInstance)))
+ {
+ WinFailure();
+ return;
+ }
+#endif
+
+ vpDlgBuf = &rgbDlgBuf[0];
+ switch (OurDialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgPrint), hParentWw,
+ lpDialogPrint))
+ {
+ case idiOk:
+ /* Force all of the windows to clean up their act. */
+ DispatchPaintMsg();
+
+ /* At this point, we have the following :
+ vfPrPages = true if print page range else print all pages
+ vpgnBegin = starting page number (if vfPrPages)
+ vpgnEnd = ending page number (if vfPrPages)
+ vcCopies = number of copies to print */
+ PrintDoc(docCur, TRUE);
+ break;
+
+ case -1:
+ /* We didn't even have enough memory to create the dialog box. */
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ break;
+ }
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogPrint);
+#endif
+ }
+
+
+BOOL far PASCAL DialogPrint( hDlg, message, wParam, lParam )
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine handles input to the Print dialog box. */
+ extern CHAR *vpDlgBuf;
+ extern int vfPrPages; /* true if print page range */
+ extern int vpgnBegin; /* starting page number to print */
+ extern int vpgnEnd; /* ending page number to print */
+ extern int vcCopies; /* nubmer of copies to print */
+ extern BOOL vfPrinterValid;
+ extern HDC vhDCPrinter;
+ extern int vfDraftMode;
+ extern HWND vhWndMsgBoxParent;
+ extern ferror;
+ extern HCURSOR vhcArrow;
+ extern int vfCursorVisible;
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+
+ int *pidiRBDown = (int *)vpDlgBuf;
+ BOOL *pfDraftMode = (BOOL *)(vpDlgBuf + sizeof(int));
+ BOOL *pfDraftSupport = (BOOL *)(vpDlgBuf + sizeof(int) + sizeof(BOOL));
+ int iEscape;
+ CHAR szPrDescrip[cchMaxProfileSz];
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ BuildPrSetupSz(szPrDescrip, &(**hszPrinter)[0], &(**hszPrPort)[0]);
+ SetDlgItemText(hDlg, idiPrtDest, (LPSTR)szPrDescrip);
+ SetDlgItemText(hDlg, idiPrtCopies, (LPSTR)"1");
+ SelectIdiText(hDlg, idiPrtCopies);
+ if (vfPrPages)
+ {
+ *pidiRBDown = idiPrtFrom;
+ SetDlgItemInt(hDlg, idiPrtPageFrom, vpgnBegin, TRUE);
+ SetDlgItemInt(hDlg, idiPrtPageTo, vpgnEnd, TRUE);
+ }
+ else
+ {
+ *pidiRBDown = idiPrtAll;
+ }
+
+ iEscape = DRAFTMODE;
+ if (*pfDraftSupport = vfPrinterValid && vhDCPrinter &&
+ Escape(vhDCPrinter, QUERYESCSUPPORT, sizeof(int),
+ (LPSTR)&iEscape, (LPSTR)NULL))
+ {
+ CheckDlgButton(hDlg, idiPrtDraft, *pfDraftMode = vfDraftMode);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hDlg, idiPrtDraft), FALSE);
+ if (!vhDCPrinter) /* we've got a timing thing whereby they
+ managed to get into the print dialog
+ inbetween the time printer.setup had
+ unhooked the old printer and the hookup
+ of the new one! ..pault */
+ EnableWindow(GetDlgItem(hDlg, idiOk), FALSE);
+ }
+
+ CheckDlgButton(hDlg, *pidiRBDown, TRUE);
+ EnableOtherModeless(FALSE);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ {
+ EndLongOp(vhcArrow);
+ }
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ {
+ ShowCursor(wParam);
+ }
+ return (FALSE);
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ BOOL fPages;
+ int pgnBegin;
+ int pgnEnd;
+ int cCopies;
+
+ case idiOk:
+ if (fPages = (*pidiRBDown == idiPrtFrom))
+ {
+ /* Get the range of pages to print. */
+ if (!WPwFromItW3Id(&pgnBegin, hDlg, idiPrtPageFrom,
+ pgnMin, pgnMax, wNormal, IDPMTNPI))
+ {
+ /* Reset error condition, so as to report any further error.
+ */
+ ferror = FALSE;
+ return(TRUE);
+ }
+ if (!WPwFromItW3Id(&pgnEnd, hDlg, idiPrtPageTo,
+ pgnMin, pgnMax, wNormal, IDPMTNPI))
+ {
+ /* Reset error condition, so as to report any further error.
+ */
+ ferror = FALSE;
+ return(TRUE);
+ }
+ }
+
+ /* Get the number of copies to print. */
+ if (!WPwFromItW3IdFUt(&cCopies, hDlg, idiPrtCopies, 1, 32767,
+ wNormal, IDPMTNPI, FALSE, 0
+ ))
+ {
+ /* Reset error condition, so as to report any further error. */
+ ferror = FALSE;
+ return(TRUE);
+ }
+
+ /* If we have gotten this far, then everything must be okey-dokey.
+ */
+ vfDraftMode = *pfDraftSupport ? *pfDraftMode : FALSE;
+ if (vfPrPages = fPages)
+ {
+ vpgnBegin = pgnBegin;
+ vpgnEnd = pgnEnd;
+ }
+ vcCopies = cCopies;
+
+ case idiCancel:
+ OurEndDialog(hDlg, wParam);
+ break;
+
+ case idiPrtPageFrom:
+ case idiPrtPageTo:
+ if (HIWORD(lParam) == EN_CHANGE)
+ {
+ if (SendMessage(LOWORD(lParam), WM_GETTEXTLENGTH, 0, 0L) &&
+ *pidiRBDown != idiPrtFrom)
+ {
+ CheckDlgButton(hDlg, *pidiRBDown, FALSE);
+ CheckDlgButton(hDlg, *pidiRBDown = idiPrtFrom, TRUE);
+ }
+ return(TRUE);
+ }
+ return(FALSE);
+
+ case idiPrtAll:
+ case idiPrtFrom:
+ CheckDlgButton(hDlg, *pidiRBDown, FALSE);
+ CheckDlgButton(hDlg, *pidiRBDown = wParam, TRUE);
+
+ // set focus to the edit field automatically
+
+ if (wParam == idiPrtFrom)
+ SetFocus(GetDlgItem(hDlg, idiPrtPageFrom));
+
+ break;
+
+ case idiPrtDraft:
+ CheckDlgButton(hDlg, wParam, *pfDraftMode = !(*pfDraftMode));
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+
+BOOL FInitHeaderFooter(fHeader, ppgn, phrgpld, pcpld)
+BOOL fHeader;
+unsigned *ppgn;
+struct PLD (***phrgpld)[];
+int *pcpld;
+ {
+ /* This routine initializes the array of print line descriptors used in
+ positioning the header/footer on the printed page. FALSE is returned if an
+ error occurs; TRUE otherwise. */
+
+ extern typeCP cpMinHeader;
+ extern typeCP cpMacHeader;
+ extern typeCP cpMinFooter;
+ extern typeCP cpMacFooter;
+ extern int docCur;
+ extern struct PAP vpapAbs;
+ extern struct SEP vsepAbs;
+ extern int dxaPrOffset;
+ extern int dyaPrOffset;
+ extern int dxpPrPage;
+ extern int dxaPrPage;
+ extern int dypPrPage;
+ extern int dyaPrPage;
+ extern struct FLI vfli;
+ extern int vfOutOfMemory;
+
+ typeCP cpMin;
+ typeCP cpMac;
+
+ /* Get the cpMin and the cpMac for the header/footer. */
+ if (fHeader)
+ {
+ cpMin = cpMinHeader;
+ cpMac = cpMacHeader;
+ }
+ else
+ {
+ cpMin = cpMinFooter;
+ cpMac = cpMacFooter;
+ }
+
+ /* Is there a header/footer. */
+ if (cpMac - cpMin > ccpEol)
+ {
+ int cpld = 0;
+ int cpldReal = 0;
+ int cpldMax;
+ int xp;
+ int yp;
+ int ichCp = 0;
+ typeCP cpMacDoc = CpMacText(docCur);
+
+ /* Compute the page number of the start of the headers/footers. */
+ CacheSect(docCur, cpMin);
+ if ((*ppgn = vsepAbs.pgnStart) == pgnNil)
+ {
+ *ppgn = 1;
+ }
+
+ /* Does the header/footer appear on the first page. */
+ CachePara(docCur, cpMin);
+ if (!(vpapAbs.rhc & RHC_fFirst))
+ {
+ (*ppgn)++;
+ }
+
+ /* Calculate the bounds of the header/footer in pixels. */
+ xp = MultDiv(vsepAbs.xaLeft - dxaPrOffset, dxpPrPage, dxaPrPage);
+ yp = fHeader ? MultDiv(vsepAbs.yaRH1 - dyaPrOffset, dypPrPage,
+ dyaPrPage) : 0;
+
+ /* Initialize the array of print line descriptors for the header/footer.
+ */
+ if (FNoHeap(*phrgpld = (struct PLD (**)[])HAllocate((cpldMax = cpldRH) *
+ cwPLD)))
+ {
+ *phrgpld = NULL;
+ return (FALSE);
+ }
+
+ /* We now have to calculate the array of print line descriptors for the
+ header/footer. */
+ cpMac -= ccpEol;
+ while (cpMin < cpMac)
+ {
+ /* Format this line of the header/footer for the printer. */
+ FormatLine(docCur, cpMin, ichCp, cpMacDoc, flmPrinting);
+
+ /* Bail out if an error occurred. */
+ if (vfOutOfMemory)
+ {
+ return (FALSE);
+ }
+
+ /* Is the array of print line descriptors big enough? */
+ if (cpld >= cpldMax && !FChngSizeH(*phrgpld, (cpldMax += cpldRH) *
+ cwPLD, FALSE))
+ {
+ return (FALSE);
+ }
+
+ /* Fill the print line descriptor for this line. */
+ {
+ register struct PLD *ppld = &(***phrgpld)[cpld++];
+
+ ppld->cp = cpMin;
+ ppld->ichCp = ichCp;
+ ppld->rc.left = xp + vfli.xpLeft;
+ ppld->rc.right = xp + vfli.xpReal;
+ ppld->rc.top = yp;
+ ppld->rc.bottom = yp + vfli.dypLine;
+ }
+
+ /* Keep track of the non-blank lines in the header/footer */
+ if ((vfli.ichReal > 0) || vfli.fGraphics)
+ {
+ cpldReal = cpld;
+ }
+
+ /* Bump the counters. */
+ cpMin = vfli.cpMac;
+ ichCp = vfli.ichCpMac;
+ yp += vfli.dypLine;
+ }
+
+ /* If this is a footer, then we have to move the positions of the lines
+ around so that the footer ends where the user has requested. */
+ if (!fHeader && cpldReal > 0)
+ {
+ register struct PLD *ppld = &(***phrgpld)[cpldReal - 1];
+ int dyp = MultDiv(vsepAbs.yaRH2 - dyaPrOffset, dypPrPage, dyaPrPage)
+ - ppld->rc.bottom;
+ int ipld;
+
+ for (ipld = cpldReal; ipld > 0; ipld--, ppld--)
+ {
+ ppld->rc.top += dyp;
+ ppld->rc.bottom += dyp;
+ }
+ }
+
+ /* Record the number of non-blank lines in the head/footer. */
+ *pcpld = cpldReal;
+ }
+ else
+ {
+ /* Indicate there is no header/footer. */
+ *ppgn = pgnNil;
+ *phrgpld = NULL;
+ *pcpld = 0;
+ }
+ return (TRUE);
+ }
diff --git a/private/mvdm/wow16/write/diarepag.c b/private/mvdm/wow16/write/diarepag.c
new file mode 100644
index 000000000..e78d79928
--- /dev/null
+++ b/private/mvdm/wow16/write/diarepag.c
@@ -0,0 +1,584 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the dialog routines for the repagination code. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOFONT
+#define NOGDI
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "editdefs.h"
+#include "printdef.h"
+#include "docdefs.h"
+#include "dlgdefs.h"
+#include "propdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "str.h"
+
+#ifndef INEFFLOCKDOWN
+BOOL far PASCAL DialogRepaginate(HWND, unsigned, WORD, LONG);
+BOOL far PASCAL DialogSetPage(HWND, unsigned, WORD, LONG);
+BOOL far PASCAL DialogPageMark(HWND, unsigned, WORD, LONG);
+#endif
+
+fnRepaginate()
+ {
+ extern HWND hParentWw;
+ extern HANDLE hMmwModInstance;
+ extern CHAR *vpDlgBuf;
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpDialogRepaginate;
+#else
+ FARPROC lpDialogRepaginate = MakeProcInstance(DialogRepaginate, hMmwModInstance);
+#endif
+ extern BOOL vfPrErr;
+ extern int vfRepageConfirm;
+ extern struct SEL selCur;
+ extern int docCur;
+ extern int vfSeeSel;
+ extern int vfOutOfMemory;
+
+ CHAR rgbDlgBuf[sizeof(BOOL)];
+ struct SEL selSave;
+
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogRepaginate)
+ {
+ WinFailure();
+ return;
+ }
+#endif
+ /* Create the repaginate dialog box. */
+ vpDlgBuf = &rgbDlgBuf[0];
+ switch (OurDialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgRepaginate),
+ hParentWw, lpDialogRepaginate))
+ {
+ case idiOk:
+ /* Use the print code to repaginate a document. */
+ DispatchPaintMsg();
+
+ /* If memory failure occurred, then punt. */
+ if (!vfOutOfMemory)
+ {
+ if (vfRepageConfirm)
+ {
+ /* Save the selection so we can restore it if an error occurs.
+ */
+ bltbyte(&selCur, &selSave, sizeof(struct SEL));
+
+ /* Set up the undo block. */
+ SetUndo(uacRepaginate, docCur, cp0, CpMacText(docCur), docNil,
+ cpNil, cpNil, 0);
+ }
+
+ /* Repaginate the document. */
+ PrintDoc(docCur, FALSE);
+
+ if (vfRepageConfirm && vfPrErr)
+ {
+ /* An error occurred; therefore, set the world back to the way
+ we found it. */
+ CmdUndo();
+
+ /* Reset the selection. */
+ ClearInsertLine();
+ Select(selSave.cpFirst, selSave.cpLim);
+ vfSeeSel = TRUE;
+
+ /* Sorry, but docUndo has been clobbered and there is no way to
+ reset it. */
+ NoUndo();
+ }
+ }
+ break;
+
+ case -1:
+ /* We didn't even have enough memory to create the dialog box. */
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ break;
+ }
+#ifndef INEFFLOCKDOWN
+ if (lpDialogRepaginate)
+ FreeProcInstance(lpDialogRepaginate);
+#endif
+ }
+
+
+BOOL far PASCAL DialogRepaginate(hDlg, code, wParam, lParam)
+HWND hDlg;
+unsigned code;
+WORD wParam;
+LONG lParam;
+ {
+ extern CHAR *vpDlgBuf;
+ extern BOOL vfRepageConfirm;
+ extern HWND vhWndMsgBoxParent;
+ extern int vfCursorVisible;
+ extern HCURSOR vhcArrow;
+
+ BOOL *pfConfirm = (BOOL *)vpDlgBuf;
+
+ switch (code)
+ {
+ case WM_INITDIALOG:
+ EnableOtherModeless(FALSE);
+ CheckDlgButton(hDlg, idiRepageConfirm, *pfConfirm = vfRepageConfirm);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ {
+ EndLongOp(vhcArrow);
+ }
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ {
+ ShowCursor(wParam);
+ }
+ return(FALSE);
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiOk:
+ vfRepageConfirm = IsDlgButtonChecked(hDlg, idiRepageConfirm);
+ case idiCancel:
+ OurEndDialog(hDlg, wParam);
+ break;
+
+ case idiRepageConfirm:
+ CheckDlgButton(hDlg, idiRepageConfirm, *pfConfirm = !*pfConfirm);
+ break;
+
+ default:
+ return(FALSE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+
+BOOL FSetPage()
+ {
+ /* This routine prompts the user for a new position for each page break.
+ The variable ipldCur is set to point to the print line the user wants as
+ the first line of the next page. TRUE is returned if the user hits the
+ "Confirm" button on the dialog box; FALSE if the "Cancel" button is hit. */
+
+ extern HWND hParentWw;
+ extern HANDLE hMmwModInstance;
+ extern CHAR *vpDlgBuf;
+ extern int docCur;
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpDialogSetPage;
+#else
+ FARPROC lpDialogSetPage = MakeProcInstance(DialogSetPage, hMmwModInstance);
+#endif
+ extern int vfOutOfMemory;
+ extern int vfPrErr;
+
+ struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+ typeCP cp;
+
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogSetPage)
+ goto LSPErr;
+#endif
+
+ /* Show the user where we think the page break should be. The AdjustCp()
+ call is a kludge to force the redisplay of the first line of the page. */
+ AdjustCp(docCur, cp = (**ppdb->hrgpld)[ppdb->ipldCur].cp, (typeCP)1,
+ (typeCP)1);
+ ClearInsertLine();
+ Select(cp, CpLimSty(cp, styLine));
+ PutCpInWwHz(cp);
+ if (vfOutOfMemory)
+ {
+Abort:
+ /* If memory failure occurred, then punt. */
+ vfPrErr = TRUE;
+ return (FALSE);
+ }
+
+ /* Now, we can create the Set Page dialog box. */
+ if (DialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgSetPage), hParentWw,
+ lpDialogSetPage) == -1)
+ {
+ /* We didn't even have enough memory to create the dialog box. */
+LSPErr:
+ Error(IDPMTPRFAIL);
+ goto Abort;
+ }
+
+#ifndef INEFFLOCKDOWN
+ if (lpDialogSetPage)
+ FreeProcInstance(lpDialogSetPage);
+#endif
+
+ /* Make sure all the windows have been refreshed. */
+ DispatchPaintMsg();
+
+ StartLongOp();
+ if (vfOutOfMemory)
+ {
+ goto Abort;
+ }
+
+ /* If the user wishes to cancel the repagination, then the flag fCancel was
+ set by the routine handling the message for the dialog box. */
+ return (!ppdb->fCancel);
+ }
+
+
+BOOL far PASCAL DialogSetPage(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine processes message sent to the Set Page dialog box. The only
+ messages that are processed are up and down buttons, and confirm and cancel
+ commands. */
+
+ extern CHAR *vpDlgBuf;
+ extern int docCur;
+ extern typeCP vcpFirstParaCache;
+ extern struct PAP vpapAbs;
+ extern HWND hParentWw;
+ extern HWND vhWndMsgBoxParent;
+ extern int vfCursorVisible;
+ extern HCURSOR vhcArrow;
+
+ register struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+ typeCP cp;
+
+ switch (message)
+ {
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiRepUp:
+ /* Move the page mark towards the beginning of the document one
+ line, if possible. */
+ if (ppdb->ipldCur == 1)
+ {
+ beep();
+ return (TRUE);
+ }
+ else
+ {
+ ppdb->ipldCur--;
+ goto ShowMove;
+ }
+
+ case idiRepDown:
+ /* Move the page mark towards the end of the document one line, if
+ possible. */
+ if (ppdb->ipldCur == ppdb->ipld)
+ {
+ beep();
+ }
+ else
+ {
+ ppdb->ipldCur++;
+ShowMove:
+ /* Reflect the movement of the page on the screen. */
+ cp = (**ppdb->hrgpld)[ppdb->ipldCur].cp;
+ Select(cp, CpLimSty(cp, styLine));
+ PutCpInWwHz(cp);
+ }
+ break;
+
+ case idiCancel:
+CancelDlg:
+ /* Let the repaginate routine know that the user wishes to cancel
+ it. */
+ ppdb->fCancel = TRUE;
+
+ case idiOk:
+ /* Take down the dialog box. */
+ EnableWindow(hParentWw, TRUE);
+ EndDialog(hWnd, NULL);
+ EnableWindow(hParentWw, FALSE);
+ vhWndMsgBoxParent = (HWND)NULL;
+ EndLongOp(vhcArrow);
+
+ /* Save the changes made by the user. */
+ if (!ppdb->fCancel && ppdb->ipldCur != ppdb->ipld)
+ {
+ /* The user has moved the page break; therefore, insert a new
+ page break. */
+ CHAR rgch[1];
+
+ rgch[0] = chSect;
+ CachePara(docCur, cp = (**ppdb->hrgpld)[ppdb->ipldCur].cp++);
+ InsertRgch(docCur, cp, rgch, 1, NULL, cp == vcpFirstParaCache ?
+ &vpapAbs : NULL);
+
+ /* Erase the old page mark from the screen. */
+ AdjustCp(docCur, (**ppdb->hrgpld)[ppdb->ipld].cp, (typeCP)1,
+ (typeCP)1);
+
+ /* Ensure that the page table is correct. */
+ (**ppdb->hpgtb).rgpgd[ppdb->ipgd].cpMin = cp + 1;
+ }
+
+ /* Change the selection to an insertion bar. */
+ cp = (**ppdb->hrgpld)[ppdb->ipldCur].cp;
+ Select(cp, cp);
+ break;
+ }
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ {
+ EndLongOp(vhcArrow);
+ }
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hWnd;
+ }
+ if (vfCursorVisible)
+ {
+ ShowCursor(wParam);
+ }
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_INITDIALOG:
+ return (TRUE);
+
+ case WM_CLOSE:
+ goto CancelDlg;
+ }
+
+ return (FALSE);
+ }
+
+
+BOOL FPromptPgMark(cp)
+typeCP cp;
+ {
+ /* This routine prompts the user to either remove or keep the page mark at
+ cp. The flag fRemove is set to TRUE if the user wishes to remove the mark;
+ FALSE if he wishes to keep it. FALSE is returned if the user decides to
+ cancel the repagination; TRUE if he does not. */
+
+ extern HWND hParentWw;
+ extern HANDLE hMmwModInstance;
+ extern CHAR *vpDlgBuf;
+ extern int docCur;
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpDialogPageMark;
+#else
+ FARPROC lpDialogPageMark = MakeProcInstance(DialogPageMark, hMmwModInstance);
+#endif
+ extern int vfOutOfMemory;
+ extern int vfPrErr;
+
+ struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogPageMark)
+ goto LPPMErr;
+#endif
+
+ /* This is a kludge to remove a possible page indicator on the line after
+ the page mark. */
+ AdjustCp(docCur, cp + 1, (typeCP)1, (typeCP)1);
+
+ /* Show the user the page mark in question. */
+ ClearInsertLine();
+ Select(cp, cp + 1);
+ PutCpInWwHz(cp);
+ if (vfOutOfMemory)
+ {
+Abort:
+ /* If memory failure occurred, then punt. */
+ vfPrErr = TRUE;
+#ifndef INEFFLOCKDOWN
+ if (lpDialogPageMark)
+ FreeProcInstance(lpDialogPageMark);
+#endif
+ return (FALSE);
+ }
+
+ /* Now, we can create the Page Mark dialog box. */
+ if (DialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgPageMark), hParentWw,
+ lpDialogPageMark) == -1)
+ {
+LPPMErr:
+ /* We didn't even have enough memory to create the dialog box. */
+ Error(IDPMTPRFAIL);
+ goto Abort;
+ }
+ StartLongOp();
+
+ /* Make sure all the windows have been refreshed. */
+ DispatchPaintMsg();
+ if (vfOutOfMemory)
+ {
+ goto Abort;
+ }
+
+ /* Make the change requested by the user. */
+ if (!ppdb->fCancel)
+ {
+ if (ppdb->fRemove)
+ {
+ /* Remove the page mark as the user has requested. */
+ Replace(docCur, cp, (typeCP)1, fnNil, fc0, fc0);
+ }
+ else
+ {
+ /* This is a kludge to force the first line after the page mark to
+ be redisplayed. */
+ AdjustCp(docCur, cp + 1, (typeCP)1, (typeCP)1);
+
+ /* Change the selection to a insertion bar. */
+ Select(cp, cp);
+ }
+ }
+
+#ifndef INEFFLOCKDOWN
+ if (lpDialogPageMark)
+ FreeProcInstance(lpDialogPageMark);
+#endif
+ /* If the user wishes to cancel the repagination, then the flag fCancel was
+ set by the routine handling the message for the dialog box. */
+ return (!ppdb->fCancel);
+ }
+
+
+BOOL far PASCAL DialogPageMark(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* The routine handles messages sent to the Page Mark dialog box. The only
+ meassages of interest are when either the "Cancel", "Keep", or "Remove"
+ buttons are hit. */
+
+ extern CHAR *vpDlgBuf;
+ extern HWND hParentWw;
+ extern HWND vhWndMsgBoxParent;
+ extern int vfCursorVisible;
+ extern HCURSOR vhcArrow;
+
+ struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+
+ switch (message)
+ {
+ case WM_SETVISIBLE:
+ if (wParam)
+ {
+ EndLongOp(vhcArrow);
+ }
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hWnd;
+ }
+ if (vfCursorVisible)
+ {
+ ShowCursor(wParam);
+ }
+ return(FALSE);
+
+ case WM_INITDIALOG:
+ return(TRUE);
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiCancel:
+ ppdb->fCancel = TRUE;
+ break;
+
+ case idiKeepPgMark:
+ ppdb->fRemove = FALSE;
+ break;
+
+ case idiRemovePgMark:
+ ppdb->fRemove = TRUE;
+ break;
+
+ default:
+ return (FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+ ppdb->fCancel = TRUE;
+ break;
+
+ default:
+ return (FALSE);
+ }
+
+ /* Take down the dialog box. */
+ EnableWindow(hParentWw, TRUE);
+ EndDialog(hWnd, NULL);
+ EnableWindow(hParentWw, FALSE);
+ vhWndMsgBoxParent = (HWND)NULL;
+ EndLongOp(vhcArrow);
+ return (TRUE);
+ }
diff --git a/private/mvdm/wow16/write/diasubs.c b/private/mvdm/wow16/write/diasubs.c
new file mode 100644
index 000000000..f6ed2c43c
--- /dev/null
+++ b/private/mvdm/wow16/write/diasubs.c
@@ -0,0 +1,606 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NORASTEROPS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDI
+#define NOSCROLL
+#define NOOPENFILE
+#define NOWNDCLASS
+#define NOSYSMETRICS
+#define NOTEXTMETRIC
+#define NOICON
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOPEN
+#define NOBRUSH
+#define NODRAWTEXT
+#define NOFONT
+#define NOMETAFILE
+#define NOSOUND
+#define NOCOLOR
+#define NOCOMM
+
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "editdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "dlgdefs.h"
+
+/*extern int idstrUndoBase;*/
+extern struct UAB vuab;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+
+
+#ifdef BOGUS /* use WPwFromItW3Id */
+BOOL FValidIntFromDlg(hDlg, idi, fSigned, wMin, wMax, pw, idpmt)
+HANDLE hDlg; /* handle to dialog box */
+int idi; /* id of control in dialog box */
+BOOL fSigned; /* check for sign if true */
+int wMin, wMax; /* range of valid integer value */
+int * pw; /* location to put the int */
+int idpmt; /* error message number */
+{
+ REG1 int wVal;
+ BOOL fValOk;
+
+ *pw = wVal = GetDlgItemInt(hDlg, idi, (BOOL far *)&fValOk, fSigned);
+ if (fValOk)
+ { /* check range */
+ if ((wVal < wMin) || (wVal > wMax))
+ fValOk = false;
+ }
+ if (!fValOk)
+ {
+ Error(idpmt);
+ SelectIdiText(hDlg, idi);
+ SetFocus(GetDlgItem(hDlg, idi));
+ }
+ return fValOk;
+} /* FValidIntFromDlg */
+#endif
+
+
+FPwPosIt(pw, hDlg, it)
+HWND hDlg; /* handle to desired dialog box */
+int *pw;
+int it;
+{
+ /*-------------------------------------------------------------------
+ Purpose: Positive integer dialog item.
+ --------------------------------------------------------------mck--*/
+ return(WPwFromItW3IdFUt(pw, hDlg, it, 0, 32767, wNormal, IDPMTNPI, fFalse, 0));
+}
+
+
+WPwFromItW3Id(pw, hDlg, it, wMin, wMax, wMask, id)
+HWND hDlg; /* handle to desired dialog box */
+int *pw; /* Return value */
+int it; /* Item number */
+int wMin; /* Smallest and largest allowed values */
+int wMax;
+int wMask; /* Bit mask for allowed variations */
+int id; /* Id of error string if bad */
+{
+ /*-------------------------------------------------------------------
+ Purpose: General integer dialog item.
+ --------------------------------------------------------------mck--*/
+ return(WPwFromItW3IdFUt(pw, hDlg, it, wMin, wMax, wMask, id, fFalse, 0));
+}
+
+FPdxaPosIt(pdxa, hDlg, it)
+HWND hDlg; /* handle to desired dialog box */
+int *pdxa;
+int it;
+{
+ /*-------------------------------------------------------------------
+ Purpose: Positive dxa dialog item.
+ --------------------------------------------------------------mck--*/
+ extern int utCur;
+
+ return(WPwFromItW3IdFUt(pdxa, hDlg, it, 0, 32767, wNormal, IDPMTNPDXA, fTrue, utCur));
+}
+
+FPdxaPosBIt(pdxa, hDlg, it)
+HWND hDlg; /* handle to desired dialog box */
+int *pdxa;
+int it;
+{
+ /*-------------------------------------------------------------------
+ Purpose: Positive dxa dialog item (blank allowed).
+ --------------------------------------------------------------mck--*/
+ extern int utCur;
+
+ return(WPwFromItW3IdFUt(pdxa, hDlg, it, 0, 32767, wBlank | wSpaces, IDPMTNPDXA, fTrue, utCur));
+}
+
+WPdxaFromItDxa2WId(pdxa, hDlg, it, dxaMin, dxaMax, wMask, id)
+HWND hDlg; /* handle to desired dialog box */
+int *pdxa; /* Return value */
+int it; /* Dialog item number */
+int dxaMin; /* Range of allowable measurements */
+int dxaMax;
+int wMask; /* Bit mask for allowed variations */
+int id; /* Error id */
+{
+ /*-------------------------------------------------------------------
+ Purpose: General dxa dialog item.
+ --------------------------------------------------------------mck--*/
+ extern int utCur;
+
+ return(WPwFromItW3IdFUt(pdxa, hDlg, it, dxaMin, dxaMax, wMask, id, fTrue, utCur));
+}
+
+WPwFromItW3IdFUt(pw, hDlg, it, wMin, wMax, wMask, id, fDxa, ut)
+int *pw; /* Return value */
+HWND hDlg; /* handle to desired dialog box */
+int it; /* Item number */
+int wMin; /* Smallest and largest allowed values */
+int wMax;
+int wMask; /* Bit mask for allowed variations */
+int id; /* Id of error string if out of range */
+int fDxa; /* Parse as dxa (otherwise int) */
+int ut; /* Units to use as default if fDxa */
+{
+ /*-------------------------------------------------------------------
+ Purpose: Parse the item in the current dialog. Must be a valid
+ integer or dxa in the given range.
+ Method: - Get the text string.
+ - Try parse as "".
+ - Try parse as string of all spaces
+ - Parse as a int/dxa (generic error if can't).
+ - Test for ".5".
+ - Compare with min and max.
+ - Try parse as "Auto".
+ - If out of bounds, use id to put up specific error
+ (with strings of min and max as parameters).
+ Returns: The return value may be used as a boolean or as a word.
+ fFalse (0) -> not parsed
+ wNormal (1) -> parsed normally
+ wBlank (2) -> parsed a null line
+ (*pw is valNil)
+ wAuto (4) -> parsed as "Auto" (*pw is 0)
+ wSpaces (16) -> parsed a line of all
+ spaces (*pw is valNil)
+
+ !fDxa only:
+ wDouble (8) -> parsed with ".5" trailing
+
+ Note: The interval [wMin..wMax] is closed.
+ Note: Return value is doubld the parsed value when wDouble.
+ Note: When wDouble, 2*wMin and 2*wMax must be valid ints.
+ Note: Numbers ending in .5 may have no trailing spaces.
+ History:
+ 6/18/86: Adapted for trailing kanji spaces --- yxy
+ 07/03/85: Added wSpaces return
+ 10/23/84: Fixed wAuto to return with *pw == 0.
+ 10/ 5/84: Added ut parameter.
+ 10/ 5/84: Added wMask and combined dxa and w parsing.
+ 9/26/84: Created.
+ --------------------------------------------------------------mck--*/
+
+ CHAR *pch; /* Parse pointer */
+ CHAR *pchEnd; /* End of buffer */
+ CHAR *pchError; /* Position of parse error */
+ int fParsed; /* Parses as number/dxa */
+ int fOverflow = fFalse; /* True if the number is parsed but it overflow */
+ int wGood = wNormal;/* return after good range check */
+ CHAR stItem[32];
+#ifdef AUTO_SPACING
+ CHAR szAuto[32]; /* Hold "Auto" string */
+#endif
+
+ /* Get the dialog text */
+ stItem[0] = GetDlgItemText(hDlg, it, (LPSTR)&stItem[1], sizeof(stItem)-1);
+
+ /* See if blank (null line) */
+ if (wMask & wBlank && stItem[0] == 0)
+ {
+ *pw = valNil;
+ return(wBlank);
+ }
+
+ pch = &stItem[1];
+
+ /* See if all spaces */
+ if (wMask & wBlank && wMask & wSpaces)
+ {
+ int fAllSpaces = fTrue;
+
+ while (*pch != 0)
+ if (*pch++ != ' ')
+ {
+ fAllSpaces = fFalse;
+ break;
+ }
+ if (fAllSpaces == fTrue)
+ {
+ *pw = valNil;
+ return(wSpaces);
+ }
+ }
+
+ pch = &stItem[1];
+ pchEnd = pch + stItem[0];
+
+ /* It parses as a number ... */
+ fParsed = fDxa ? FZaFromSs(pw, stItem+1, *stItem, ut)
+ : FPwParsePpchPch(pw, &pch, pchEnd, &fOverflow);
+
+ if (!fDxa && wMask & wDouble)
+ {
+ (*pw) *= 2;
+ wMin *= 2;
+ wMax *= 2;
+ if (!fParsed)
+ {
+ /* Check if ".5" was reason for bad parse. */
+ if (pch != pchEnd && *pch == '.')
+ {
+ pch++;
+ /* Allow "ddddd.0*" */
+ pchError = pch;
+ if (FAllZeroPpchPch(&pchError, pchEnd))
+ fParsed = fTrue;
+ /* Allow "ddddd.50*" */
+ else if (pch != pchEnd && *pch == '5' &&
+ (pch++, FAllZeroPpchPch(&pch, pchEnd)))
+ {
+ (*pw)++;
+ fParsed = fTrue;
+ wGood = wDouble;
+ }
+ /* Mark furthest error condition */
+ else if (pchError > pch)
+ pch = pchError;
+ }
+ }
+ }
+
+ if (fParsed && !fOverflow)
+ {
+ /* ... and in range */
+ if (*pw >= wMin && *pw <= wMax)
+ return(wGood);
+#ifdef ENABLE
+ /* ... but out of range - no matter what, we will use the supplied
+ id for the error message to be consistant */
+ else
+ {
+ SelectIdiText(hDlg, it);
+ SetFocus(GetDlgItem(hDlg, it));
+ Error(id);
+ return(fFalse);
+ }
+#endif /* ENABLE */
+ }
+
+#ifdef AUTO_SPACING
+ /* Invariant: Field does not parse as a number */
+
+ /* Try "Auto" */
+ if (wMask & wAuto)
+ {
+ pch = PchFillPchId(szAuto, IDSTRVaries, sizeof(szAuto));
+ *pch = '\0';
+ stItem[stItem[0]+1] = '\0';
+ if (WCompSz(szAuto, &stItem[1]) == 0)
+ {
+ *pw = 0;
+ return(wAuto);
+ }
+ }
+#endif /* AUTO_SPACING */
+
+ /* All attempts failed - show user where he went wrong vis the attempted
+ number parse. */
+ {
+ unsigned cchStart = fParsed ? 0 : pch - &stItem[1];
+ unsigned cchEnd = 32767;
+ int idError = fDxa ? IDPMTNOTDXA : IDPMTNOTNUM;
+
+ if (fParsed)
+ idError = id; /* reset idError if we just overflow or fail the range test */
+ SendDlgItemMessage(hDlg, it, EM_SETSEL, (WORD)NULL, MAKELONG(cchStart, cchEnd));
+ SetFocus(GetDlgItem(hDlg, it));
+ Error(idError);
+ return(fFalse);
+ }
+}
+
+FAllZeroPpchPch(ppch, pchMax)
+CHAR **ppch; /* Bound of character buffer */
+CHAR *pchMax;
+{
+ /*-------------------------------------------------------------------
+ Purpose: Make sure all characters in buffer are spaces or 0's.
+ Returns: *ppch contains first bad character if fFalse returned.
+ History:
+ 6/18/86: Adapted for Kanji chars --- yxy
+ 10/ 9/84: Created.
+ --------------------------------------------------------------mck--*/
+ CHAR *pch = *ppch;
+
+ while (pch < pchMax) {
+ if (*pch == '0' || *pch == ' ')
+ pch++;
+ else {
+ *ppch = pch;
+ return(fFalse);
+ }
+ }
+ return(fTrue);
+}
+
+FPwParsePpchPch(pw, ppch, pchMax, pfOverflow)
+int *pw;
+CHAR **ppch;
+CHAR *pchMax;
+int *pfOverflow;
+{
+ /*-------------------------------------------------------------------
+ Purpose: Parse a number in the given buffer.
+ Method: Scan for digits and ignore white space.
+ Returns: Character pointer past last one read in *ppch.
+ Number parsed is returned. Note that if only a prefix is
+ a valid number we return false, with *ppch set to the
+ first offending character.
+ Modification History:
+ 06/18/86 ---- Adapted for a kanji space char. --- yxy
+ --------------------------------------------------------------mck--*/
+#define smInit 0
+#define smDig 1
+#define smBody 2
+
+ CHAR *pch = *ppch; /* Local buffer pointer */
+ unsigned int ch; /* Character being examined */
+ int fNeg = fFalse;
+ DWORD dwNum = 0L;
+ int fError = fFalse;
+ int sm = smInit;
+
+ *pfOverflow = fFalse;
+ while (!fError && !(*pfOverflow) && pch < pchMax) {
+ ch = *pch;
+ if (ch == chSpace)
+ pch++;
+ else
+ switch (sm) {
+ case smInit:
+ if (ch == '-') {
+ fNeg = fTrue;
+ pch++;
+ }
+ sm = smDig;
+ break;
+ case smDig:
+ if (isdigit(ch))
+ sm = smBody;
+ else
+ fError = fTrue;
+ break;
+ case smBody:
+ if (isdigit(ch)) {
+ /* Overflow? */
+ if ((dwNum = 10*dwNum + WFromCh(ch)) > 0x7FFF)
+ *pfOverflow = fTrue;
+ else
+ pch++;
+ }
+ else
+ fError = fTrue;
+ break;
+ }
+ }
+
+ *ppch = pch;
+ *pw = (int)(fNeg ? -dwNum : dwNum);
+ return(!fError);
+}
+
+
+EnableOtherModeless(fEnable)
+BOOL fEnable;
+{
+extern HWND vhDlgChange;
+extern HWND vhDlgFind;
+extern HWND vhDlgRunningHead;
+
+/* Disable or enable other modeless dialog boxes according to fEnable */
+
+if (IsWindow(vhDlgFind))
+ {
+ EnableWindow(vhDlgFind, fEnable);
+ }
+if (IsWindow(vhDlgChange))
+ {
+ EnableWindow(vhDlgChange, fEnable);
+ }
+if (IsWindow(vhDlgRunningHead))
+ {
+ EnableWindow(vhDlgRunningHead, fEnable);
+ }
+}
+
+
+SelectIdiText(hDlg, idi)
+HWND hDlg;
+int idi;
+{ /* For the dialog box with handle hDlg, highlight the text of the control
+ with ID idi */
+ unsigned cchStart = 0;
+ unsigned cchEnd = 0x7fff;
+ SendDlgItemMessage(hDlg, idi, EM_SETSEL, (WORD)NULL, MAKELONG(cchStart, cchEnd));
+} /* end of SelectIdiText */
+
+
+#ifdef ENABLE
+SetRgvalAgain(rgvalLocal, uac)
+VAL rgvalLocal[];
+int uac;
+ {
+ extern VAL rgvalAgain[];
+
+ blt(rgvalLocal, rgvalAgain, ivalMax * cwVal);
+ switch (vuab.uac = uac)
+ {
+ case uacFormatPara:
+ case uacFormatChar:
+ case uacFormatSection:
+/* idstrUndoBase = IDSTRUndoBase;*/
+/* SetUndoMenuStr(IDSTRUndoCom);*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ break;
+ }
+ }
+#endif
+
+
+#ifdef CASHMERE
+PushRadioButton(hDlg, idiFirst, idiLast, idiPushed)
+HWND hDlg;
+int idiFirst, idiLast, idiPushed;
+{
+ /*
+ Push radio button idiPushed and unpush all others in the radio group
+ bounded by idiFirst and idiLast.
+ */
+ int idi;
+
+ for (idi = idiFirst; idi <= idiLast; idi++)
+ CheckDlgButton(hDlg, idi, idi == idiPushed);
+}
+
+
+SetRadValue(hDlg, idiFirst, idiLast, idiRad)
+HWND hDlg;
+int idiFirst, idiLast, idiRad;
+{
+ /*
+ Set the (zero-based) idiRad'th item in the radio group
+ bounded by idiFirst and idiLast.
+ */
+ PushRadioButton(hDlg, idiFirst, idiLast, idiFirst + idiRad);
+}
+
+#endif /* CASHMERE */
+
+
+#ifdef ENABLE
+BOOL far PASCAL DialogConfirm(hDlg, message, wParam, lParam)
+HWND hDlg;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This is the Dialog function for all dialog boxes with only "Yes", "No",
+ and "Cancel" boxes; this includes: Save Large Scrap */
+
+ extern HWND vhWndMsgBoxParent;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ EnableOtherModeless(FALSE);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ /* The default button is NO, make sure the call routine realized
+ that idiOk should be treated as idiNo. */
+ case idiOk:
+ case idiCancel:
+ case idiYes:
+ case idiNo:
+ OurEndDialog(hDlg, wParam);
+ break;
+ default:
+ Assert(FALSE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+ } /* end of DialogConfirm */
+#endif /* ENABLE */
+
+
+#ifndef WIN30
+/* DialogBox has been fixed so it automatically brings up the hourglass! */
+
+OurDialogBox(hInst, lpstr, hWndParent, lpProc)
+HANDLE hInst;
+LPSTR lpstr;
+HWND hWndParent;
+FARPROC lpProc;
+{
+StartLongOp();
+return(DialogBox(hInst, lpstr, hWndParent, lpProc));
+}
+#endif
+
+
+OurEndDialog(hDlg, wParam)
+ {
+ /* This routine does the same standard things Write does everytime it closes
+ a dialog box. */
+
+ extern HWND hParentWw;
+ extern long ropErase;
+ extern HWND vhWndMsgBoxParent;
+ extern HCURSOR vhcIBeam;
+
+ RECT rc;
+ POINT pt;
+
+#ifdef NO_NEW_CALL
+ /* Close down the dialog box and erase it from the screen. We tried to let
+ Windows do the erasing, but... Its a long story. */
+ GetWindowRect(hDlg, (LPRECT)&rc);
+ pt.x = pt.y = 0;
+ ClientToScreen(hParentWw, (LPPOINT)&pt);
+#endif
+
+ EndDialog(hDlg, wParam);
+
+#ifdef NO_NEW_CALL
+ PatBlt(GetDC(hParentWw), rc.left - pt.x, rc.top - pt.y, rc.right - rc.left,
+ rc.bottom - rc.top, ropErase);
+#endif
+
+ /* Enable any existing dialog boxes and indicate that any error messages
+ belong to the document window. */
+ EnableOtherModeless(TRUE);
+ vhWndMsgBoxParent = (HWND)NULL;
+#ifndef WIN30
+ EndLongOp(vhcIBeam); /* See StartLongOp() above */
+#endif
+ }
diff --git a/private/mvdm/wow16/write/disp.c b/private/mvdm/wow16/write/disp.c
new file mode 100644
index 000000000..e3af738dd
--- /dev/null
+++ b/private/mvdm/wow16/write/disp.c
@@ -0,0 +1,1536 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* disp.c -- MW display routines */
+
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOWINSTYLES
+//#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NOWH
+#define NOWINOFFSETS
+#define NOMETAFILE
+#define NOMB
+#define NODRAWTEXT
+#include <windows.h>
+
+#define NOUAC
+#include "mw.h"
+#include "debug.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES /* Removes all kc code defines */
+#include "ch.h"
+#include "docdefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "macro.h"
+#include "printdef.h"
+#include "fontdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+#ifdef DBCS
+#include "dbcs.h"
+#endif
+
+#ifdef CASHMERE /* No VisiMode in WinMemo */
+extern int vfVisiMode;
+#endif /* CASHMERE */
+
+extern int vcchBlted;
+extern int vidxpInsertCache;
+extern int vdlIns;
+extern int vfInsLast;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern int rgval[];
+extern struct DOD (**hpdocdod)[];
+extern typeCP cpMacCur;
+extern int vfSelHidden;
+extern struct WWD rgwwd[];
+extern int wwCur, wwMac;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern struct WWD *pwwdCur;
+extern int docCur;
+extern struct CHP (**vhgchpFormat)[];
+extern int vichpFormat;
+extern typeCP cpMinCur;
+extern typeCP cpMinDocument;
+extern int vfInsertOn;
+extern int vfTextBltValid;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern unsigned vpgn;
+extern struct SEP vsepAbs;
+extern CHAR stBuf[];
+extern typeCP CpEdge();
+extern typeCP CpMacText();
+extern int vdocPageCache;
+extern int vfPictSel;
+extern int vfAwfulNoise;
+extern int vfSkipNextBlink;
+extern int dypMax;
+extern HDC vhMDC;
+extern HWND vhWndPageInfo;
+extern struct FMI vfmiScreen;
+extern int docScrap;
+extern long rgbBkgrnd;
+extern long ropErase;
+extern BOOL vfMonochrome;
+extern int dxpbmMDC;
+extern int dypbmMDC;
+extern HBITMAP hbmNull;
+extern int vfOutOfMemory;
+extern int vfSeeSel;
+extern int vfInsEnd; /* Is insert point at end-of-line? */
+extern int vipgd;
+extern typeCP vcpMinPageCache;
+extern typeCP vcpMacPageCache;
+/* actual position of the cursor line */
+extern int vxpCursLine;
+extern int vypCursLine;
+
+extern int vdypCursLine;
+extern int vfScrollInval; /* means scroll did not take and UpdateWw must be repeated */
+extern BOOL vfDead;
+extern HRGN vhrgnClip;
+
+
+/* G L O B A L S
+int dlsMac = 0;*/
+#ifdef DBCS
+int donteat = 0; /* propagate not to eat message */
+#endif
+
+
+/* D I S P L A Y F L I */
+/* Display formatted line in window ww at line dl */
+
+
+DisplayFli(ww, dl, fDontDisplay)
+int ww;
+int dl;
+int fDontDisplay; /* True if we set up dl info but don't display */
+ {
+ typeCP dcp;
+ typeCP dcpMac;
+ struct WWD *pwwd = &rgwwd[ww];
+ HDC hDC = pwwd->hDC;
+ int xp; /* Current xp to write text */
+ int yp; /* Current yp to write text */
+ int xpMin = pwwd->xpMin; /* Minimum xp in window */
+ int xpMac = pwwd->xpMac; /* Maximum xp in window */
+ int ypLine; /* Screen yp for current line */
+ int dxp; /* Width of current run */
+ int dyp; /* Line height */
+ int dxpExtra; /* Width of pad for each space */
+ typeCP cpMin;
+ typeCP cpMac;
+ int xpSel; /* xp of the start of the selection */
+ int dxpSel = 0; /* Width of the selection. */
+ CHAR chMark = '\0'; /* style character */
+ struct CHP *pchp;
+ BOOL fTabsKludge = (vfli.ichLastTab >= 0);
+ BOOL fInsertOn = FALSE;
+ int cBreakRun; /* break characters in run (no relation to Dick or Jane) */
+
+#ifdef SMFONT
+ RECT rcOpaque;
+#endif /* SMFONT */
+
+#ifdef DDISP
+ CommSzNumNum(" DisplayFli: dl/fDontDisplay ", dl, fDontDisplay);
+#endif
+ Assert(ww >= 0 && ww < wwMax);
+#ifdef SMFONT
+ Assert(!fDontDisplay || vfli.fGraphics)
+#endif /* SMFONT */
+ Scribble(5,'D');
+
+ /* Fill up EDL and set some useful locals */
+ {
+ register struct EDL *pedl = &(**pwwd->hdndl)[dl];
+
+ if (dl == vdlIns)
+ {
+ /* Overwriting chars blted during fast insert; reset blt count */
+ vcchBlted = 0;
+ vidxpInsertCache = -1;
+ }
+
+ pedl->xpLeft = vfli.xpLeft;
+ pedl->xpMac = vfli.xpReal;
+ cpMin = pedl->cpMin = vfli.cpMin;
+ pedl->dcpMac = (cpMac = vfli.cpMac) - cpMin;
+ dyp = pedl->dyp = vfli.dypLine;
+ pedl->ichCpMin = vfli.ichCpMin;
+ pedl->dcpDepend = (cpMin == cpMac) ? 0xff : vfli.dcpDepend;
+ pedl->fValid = TRUE;
+ pedl->fGraphics = vfli.fGraphics;
+ pedl->fSplat = vfli.fSplat;
+
+ /* The position of current line equals the position of the previous line
+ + height of this line. */
+#ifdef SMFONT
+ pedl->yp = rcOpaque.bottom = dyp + (ypLine = rcOpaque.top = (dl == 0 ?
+ pwwd->ypMin : (pedl - 1)->yp));
+#else /* not SMFONT */
+ pedl->yp = dyp + (ypLine = (dl == 0 ? pwwd->ypMin :
+ (pedl - 1)->yp));
+#endif /* SMFONT */
+
+ if (pedl->fIchCpIncr = (vfli.ichCpMac != 0))
+ {
+ /* Look at final text column */
+ ++cpMac;
+
+ /* Since this is true, we can compress pedl->ichCpMac to 1 bit. */
+ Assert(vfli.ichCpMac == pedl->ichCpMin + 1);
+ }
+ }
+
+ if (vfli.doc == docNil)
+ {
+ /* This is the space beyond the end mark. */
+ PatBlt(hDC, 0, ypLine, xpMac, dyp, ropErase);
+ goto Finished;
+ }
+
+ /* Is there a character in the "style bar"? */
+ if (cpMin != cpMac)
+ {
+
+#ifdef CASHMERE
+ /* This line is not completely empty (not after the end mark); check for
+ painting marks on the style bar. */
+ if (cpMin == vcpFirstParaCache && vpapAbs.rhc != 0)
+ {
+ /* This is a running-head. */
+ chMark = chStatRH;
+ }
+ else if ((**hpdocdod)[vfli.doc].hpgtb != 0)
+#else /* not CASHMERE */
+ if (vpapAbs.rhc == 0 && (**hpdocdod)[vfli.doc].hpgtb != 0)
+#endif /* CASHMERE */
+
+ {
+ if (vdocPageCache != vfli.doc || cpMac > vcpMacPageCache || cpMac <=
+ vcpMinPageCache)
+ {
+ CachePage(vfli.doc, cpMac - 1);
+ }
+
+ /* We are now guaranteed that cpMac is within the cached page. */
+ if (cpMin <= vcpMinPageCache && (!vfli.fGraphics || vfli.ichCpMin ==
+ 0))
+ {
+ /* This is the first line of new page; show page mark. */
+ chMark = chStatPage;
+ }
+ }
+ }
+
+#ifdef SMFONT
+#ifdef DDISP
+ /* black out this line to test how efficiently/correctly we
+ overwrite pixels from previously-resident lines of text */
+ PatBlt(hDC, 0, ypLine, xpMac, dyp, BLACKNESS);
+ { long int i; for (i=0; i < 500000; i++) ; }
+#endif
+
+ /* Calculate dcpMac now, so we might be able to know how much to erase. */
+ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
+
+ /* Erase any character that might be in the style bar. */
+ dxp = xpSelBar + 1;
+ if (!vfli.fGraphics)
+ {
+ dxp = xpMac; // clear the whole line
+ }
+ PatBlt(hDC, 0, ypLine, dxp, dyp, ropErase);
+
+ /* If this is graphics then go draw any characters in the style bar. */
+ if (vfli.fGraphics)
+ {
+ goto DrawMark;
+ }
+
+ /* If there are no "real" characters on this line then we can skip alot of
+ this. */
+ if (dcpMac == 0)
+ {
+ goto EndLine2;
+ }
+#else /* not SMFONT */
+ if (vfli.fGraphics || fDontDisplay)
+ {
+ /* Erase any character that might be in the style bar. */
+ PatBlt(hDC, 0, ypLine, xpSelBar, dyp, ropErase);
+ goto DrawMark;
+ }
+#endif /* SMFONT */
+
+ ValidateMemoryDC();
+ if (vhMDC == NULL)
+ {
+Error:
+ /* Notify the user that an error has occured and simply erase this line.
+ */
+ WinFailure();
+ PatBlt(hDC, xpSelBar, ypLine, xpMac - xpSelBar, dyp, ropErase);
+ goto Finished;
+ }
+
+#ifndef SMFONT
+ /* Create a new bitmap for the memory DC if the current bitmap is not big
+ enough. */
+ if (xpMac > dxpbmMDC || dyp > dypbmMDC)
+ {
+ HBITMAP hbm;
+
+ /* If there is an old bitmap, then delete it. */
+ if (dxpbmMDC != 0 || dypbmMDC != 0)
+ {
+ DeleteObject(SelectObject(vhMDC, hbmNull));
+ }
+
+ /* Create the new bitmap and select it in. */
+ if ((hbm = CreateBitmap(dxpbmMDC = xpMac, dypbmMDC = dyp, 1, 1,
+ (LPSTR)NULL)) == NULL)
+ {
+ /* There should be a graceful way to recover if the bitmap is ever
+ NULL (e.g we don't have enough memory for it). */
+ dxpbmMDC = dypbmMDC = 0;
+ goto Error;
+ }
+ SelectObject(vhMDC, hbm);
+ }
+
+ /* Erase the are of the bitmap we are going to use. */
+ PatBlt(vhMDC, xpSelBar, 0, xpMac, dyp, vfMonochrome ? ropErase : WHITENESS);
+#endif /* not SMFONT */
+
+ /* Initialize some of the variables we'll need. */
+ pchp = &(**vhgchpFormat)[0];
+#ifdef SMFONT
+ xp = rcOpaque.left = rcOpaque.right = vfli.xpLeft + xpSelBar - xpMin + 1;
+#else /* not SMFONT */
+ dcpMac = vfli.fSplat ? vfli.ichMac : vfli.ichReal;
+ xp = vfli.xpLeft + xpSelBar - xpMin + 1;
+#endif /* SMFONT */
+ dxpExtra = fTabsKludge ? 0 : vfli.dxpExtra;
+
+#ifdef SMFONT
+ /* If we are horizontally scrolled, then set the clip area to the area
+ outside of the selection bar. */
+ if (xpMin != 0)
+ {
+ IntersectClipRect(hDC, xpSelBar, rcOpaque.top, xpMac, rcOpaque.bottom);
+ }
+#endif /* SMFONT */
+
+ for (dcp = 0; dcp < dcpMac; pchp++)
+ {
+ /* For all runs do: */
+ int ichFirst; /* First character in the current run */
+ int cchRun; /* Number of characters in the current run */
+
+ dcp = ichFirst = pchp->ichRun;
+ dcp += pchp->cchRun;
+ if (dcp > dcpMac)
+ {
+ dcp = dcpMac;
+ }
+ cchRun = dcp - ichFirst;
+
+ /* Compute dxp = sum of width of characters in current run (formerly
+ DxaFromIcpDcp). */
+ {
+ register int *pdxp;
+ register int cchT = cchRun;
+ PCH pch = vfli.rgch + ichFirst;
+
+ dxp = cBreakRun = 0;
+ pdxp = &vfli.rgdxp[ichFirst];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+#ifdef DDISP
+ CommSzNum(" dxp=",dxp);
+#endif
+ }
+
+ if (dxp > 0)
+ {
+ int cchDone;
+ PCH pch = &vfli.rgch[ichFirst];
+
+ LoadFont(vfli.doc, pchp, mdFontScreen);
+ yp = (dyp - (vfli.dypBase + (pchp->hpsPos != 0 ? (pchp->hpsPos <
+ hpsNegMin ? ypSubSuper : -ypSubSuper) : 0))) -
+ vfmiScreen.dypBaseline;
+
+ /* Note: tabs and other special characters are guaranteed to come at
+ the start of a run. */
+ SetTextJustification(vhMDC, dxpExtra * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ cchDone = 0;
+ while (cchDone < cchRun)
+ {
+ int cch;
+
+ /* Does the wide-space zone begin in this run? */
+ if (vfli.fAdjSpace && (vfli.ichFirstWide < ichFirst + cchRun) &&
+ (ichFirst + cchDone <= vfli.ichFirstWide))
+ {
+ int cchDoneT = cchDone;
+
+ /* Is this the beginning of the wide-space zone? */
+ if (ichFirst + cchDone == vfli.ichFirstWide)
+ {
+ /* Reset the width of the spaces. */
+ SetTextJustification(vhMDC, ++dxpExtra * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ cch = cchRun - cchDone;
+ cchDone = cchRun;
+ }
+ else
+ {
+ cchDone = cch = vfli.ichFirstWide - ichFirst;
+ }
+
+ /* This run is cut short because of a wide space, so we need
+ to calculate a new width. */
+ {
+ register int *pdxp;
+ register int cchT = cch;
+ PCH pch = &vfli.rgch[ichFirst + cchDoneT];
+
+ dxp = 0;
+ pdxp = &vfli.rgdxp[ichFirst + cchDoneT];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+ }
+ }
+ else
+ {
+ cchDone = cch = cchRun;
+ }
+
+ while (cch > 0)
+ {
+ switch (*pch)
+ {
+ CHAR ch;
+ int dxpT;
+
+ case chTab:
+
+#ifdef CASHMERE
+ /* chLeader contains tab leader character (see
+ FormatLine) */
+ if ((ch = pchp->chLeader) != chSpace)
+ {
+ int cxpTab;
+ CHAR rgch[32];
+ int dxpLeader = CharWidth(ch);
+ int xpT = xp;
+ int iLevelT = SaveDC(vhMDC);
+
+ SetBytes(&rgch[0], ch, 32);
+ dxpT = vfli.rgdxp[ichFirst];
+ cxpTab = ((dxpT + dxpLeader - 1) / dxpLeader + 31)
+ >> 5;
+
+ xp += dxpT;
+
+ while (cxpTab-- > 0)
+ {
+ TextOut(vhMDC, xpT, yp, (LPSTR)rgch, 32);
+ xpT += dxpLeader << 5;
+ }
+ RestoreDC(vhMDC, iLevelT);
+ }
+ else
+#endif /* CASHMERE */
+
+ {
+#ifdef SMFONT
+ /* Expand the opaque rectangle to include the tab.
+ */
+ rcOpaque.right += vfli.rgdxp[ichFirst];
+#endif /* SMFONT */
+ xp += vfli.rgdxp[ichFirst];
+ }
+
+ if (fTabsKludge && ichFirst >= vfli.ichLastTab)
+ {
+ SetTextJustification(vhMDC, (dxpExtra =
+ vfli.dxpExtra) * cBreakRun, cBreakRun);
+#ifdef SMFONT
+ SetTextJustification(hDC, dxpExtra * cBreakRun, cBreakRun);
+#endif /* SMFONT */
+ fTabsKludge = FALSE;
+ }
+ dxp -= vfli.rgdxp[ichFirst];
+ pch++;
+ cch--;
+ goto EndLoop;
+
+#ifdef CASHMERE
+ case schPage:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpPgn(&stBuf[1], vpgn, vsepAbs.nfcPgn,
+ flmSandMode, ichMaxLine);
+ goto DrawSpecial;
+
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpFtn(&stBuf[1], cpMin + ichFirst,
+ flmSandMode, ichMaxLine);
+DrawSpecial:
+#else /* not CASHMERE */
+ case schPage:
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = *pch == schPage && (wwdCurrentDoc.fEditHeader
+ || wwdCurrentDoc.fEditFooter) ? CchExpPgn(&stBuf[1],
+ vpgn, 0, flmSandMode, ichMaxLine) :
+ CchExpUnknown(&stBuf[1], flmSandMode, ichMaxLine);
+#endif /* not CASHMERE */
+
+#ifdef SMFONT
+ /* Calculate the opaque rectangle. */
+ rcOpaque.right += vfli.rgdxp[ichFirst] +
+ vfmiScreen.dxpOverhang;
+
+ TextOut(hDC, xp, ypLine+yp, &stBuf[1], stBuf[0]);
+#else /* not SMFONT */
+ TextOut(vhMDC, xp, yp, (LPSTR)&stBuf[1], stBuf[0]);
+#endif /* SMFONT */
+ break;
+
+ default:
+ goto EndLoop;
+ }
+
+ dxp -= vfli.rgdxp[ichFirst];
+#ifdef SMFONT
+ /* End the line if no more will fit into the window. */
+ if ((xp += vfli.rgdxp[ichFirst++]) >= xpMac) {
+ goto EndLine;
+ }
+ rcOpaque.left = (rcOpaque.right = xp) +
+ vfmiScreen.dxpOverhang;
+#else /* not SMFONT */
+ xp += vfli.rgdxp[ichFirst++];
+#endif /* SMFONT */
+ pch++;
+ cch--;
+ }
+EndLoop:
+
+#ifdef SMFONT
+ if (cch == 0)
+ {
+ Assert(dxp == 0);
+ }
+ else
+ {
+ /* Calculate the opaque rectangle. */
+ rcOpaque.right += dxp + vfmiScreen.dxpOverhang;
+
+#if 0
+ {
+ char msg[180];
+ wsprintf(msg,"putting out %d characters\n\r",cch);
+ OutputDebugString(msg);
+ }
+#endif
+ /* Output cch characters starting at pch */
+ TextOut(hDC, xp, ypLine+yp, pch, cch);
+
+ /* End the line if no more will fit into the window. */
+ if ((xp += dxp) >= xpMac)
+ {
+ goto EndLine;
+ }
+ rcOpaque.left = (rcOpaque.right = xp) +
+ vfmiScreen.dxpOverhang;
+ pch += cch;
+ }
+#else /* not SMFONT */
+ /* Output cch characters starting at pch */
+ TextOut(vhMDC, xp, yp, (LPSTR)pch, cch);
+ xp += dxp;
+ pch += cch;
+#endif /* SMFONT */
+ } /* end while (cchDone<cchRun) */
+ } /* end if (dxp>0) */
+ } /* end for dcp=0..dcpMac */
+
+#ifdef SMFONT
+EndLine:
+ /* Restore the clip region if need be. */
+ if (xpMin != 0)
+ {
+ SelectClipRgn(hDC, NULL);
+ }
+EndLine2:
+#endif /* SMFONT */
+
+#ifdef CASHMERE
+ if (vfVisiMode)
+ {
+ AddVisiSpaces(ww, &(**pwwd->hdndl)[dl], vfli.dypBase, vfli.dypAfter +
+ vfli.dypFont);
+ }
+#endif /* CASHMERE */
+
+ vfTextBltValid = FALSE;
+
+ if ((ww == wwCur) && (pwwd->doc != docScrap) && !vfSelHidden &&
+ (selCur.cpLim >= cpMin))
+ {
+ if (selCur.cpFirst <= cpMac)
+ {
+ /* Show selection */
+ int xpFirst;
+ int xpLim;
+
+#ifdef ENABLE
+ if (vfli.fSplatNext && selCur.cpFirst == selCur.cpLim &&
+ selCur.cpFirst == cpMac)
+ {
+ vfInsEnd = TRUE;
+ ClearInsertLine();
+ }
+ vfInsertOn = FALSE;
+#endif /* ENABLE */
+
+ if (selCur.cpFirst <= cpMin && selCur.cpLim >= cpMac)
+ {
+ xpFirst = vfli.xpLeft;
+ xpLim = vfli.xpReal;
+ }
+ else if (selCur.cpFirst < cpMac || (selCur.cpLim == cpMac &&
+ vfInsEnd))
+ {
+ typeCP cpBegin = CpMax(cpMin, selCur.cpFirst);
+ typeCP cpEnd = CpMin(cpMac, selCur.cpLim);
+
+ dxp = DxpDiff((int)(cpBegin - cpMin), (int)(cpEnd - cpBegin),
+ &xpFirst);
+ xpLim = min(xpMin + vfli.xpReal, xpFirst + dxp);
+ }
+ else
+ {
+ goto DidntHighlight;
+ }
+
+ xpSel = xpSelBar + max(xpFirst - xpMin, 0);
+ if (xpLim > xpFirst)
+ {
+ /* Set highlighting at desired screen position. */
+ dxpSel = max(xpLim - max(xpFirst, xpMin), 0);
+ }
+ else if (selCur.cpFirst == selCur.cpLim && ((selCur.cpLim != cpMac)
+ ^ vfInsEnd))
+ {
+ vfInsertOn = FALSE; /* Because we redisplayed insert pt line */
+
+#ifdef CASHMERE
+ vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
+ vypCursLine = ypLine + dyp - vfli.dypAfter;
+#else /* not CASHMERE */
+ vdypCursLine = vfli.dypFont;
+ vypCursLine = ypLine + dyp;
+#endif /* not CASHMERE */
+
+ vxpCursLine = xpSel;
+
+ /* Start blinking in a while */
+ vfSkipNextBlink = TRUE;
+
+ fInsertOn = xpFirst >= xpMin;
+ }
+
+DidntHighlight:;
+ }
+ }
+
+#ifdef SMFONT
+ /* Invert the selection */
+ if (dxpSel != 0) {
+ PatBlt(hDC, xpSel, ypLine, dxpSel, dyp, DSTINVERT);
+ }
+#else /* not SMFONT */
+ /* Blt the line of text onto the screen. */
+ PatBlt(vhMDC, 0, 0, xpSelBar, dyp, vfMonochrome ? ropErase : WHITENESS);
+ if (dxpSel == 0)
+ {
+ BitBlt(hDC, 0, ypLine, xpMac, dyp, vhMDC, 0, 0, SRCCOPY);
+ }
+ else
+ {
+ BitBlt(hDC, 0, ypLine, xpSel, dyp, vhMDC, 0, 0, SRCCOPY);
+ BitBlt(hDC, xpSel, ypLine, dxpSel, dyp, vhMDC, xpSel, 0, NOTSRCCOPY);
+ xpSel += dxpSel;
+ BitBlt(hDC, xpSel, ypLine, xpMac - xpSel, dyp, vhMDC, xpSel, 0,
+ SRCCOPY);
+ }
+#endif /* SMFONT */
+
+ /* Draw the insertion bar if necessary. */
+ if (fInsertOn)
+ {
+ DrawInsertLine();
+ }
+
+DrawMark:
+ /* Draw the character in the style bar if necessary. */
+ if (chMark != '\0')
+ {
+#ifdef SYSENDMARK
+ struct CHP chpT;
+ extern struct CHP vchpNormal;
+
+ blt(&vchpNormal, &chpT, cwCHP);
+ chpT.ftc = ftcSystem;
+ chpT.ftcXtra = 0;
+ chpT.hps = hpsDefault;
+
+ /* Draw the style character in the standard font. */
+ LoadFont(vfli.doc, &chpT, mdFontScreen);
+
+ TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
+ (LPSTR)&chMark, 1);
+#else /* ifdef SYSENDMARK */
+ /* Draw the style character in the standard font. */
+ LoadFont(vfli.doc, NULL, mdFontScreen);
+ TextOut(hDC, 0, ypLine + dyp - vfli.dypBase - vfmiScreen.dypBaseline,
+ (LPSTR)&chMark, 1);
+#endif /* if-else-def SYSENDMARK */
+ }
+
+ if (vfli.fGraphics)
+ {
+ DisplayGraphics(ww, dl, fDontDisplay);
+ }
+
+Finished:
+ Scribble(5,' ');
+ }
+
+
+/* D X P D I F F */
+DxpDiff(dcpFirst, dcp, pdxpFirst)
+int dcpFirst;
+int dcp;
+int *pdxpFirst;
+{
+#if 1
+ register int *pdxp = &vfli.rgdxp[0];
+ register int cch;
+ int dxp = vfli.xpLeft;
+#ifdef ENABLE /* Not used */
+ int ichLim = dcpFirst + dcp;
+#endif
+
+
+ if (dcp > vfli.ichMac - dcpFirst)
+ { /* This should not be, but is when we have a CR */
+ //Assert( dcpFirst < vfli.ichMac );
+ dcp = vfli.ichMac - dcpFirst;
+ }
+
+ for (cch = 0; cch < dcpFirst; ++cch)
+ {
+ dxp += *pdxp++;
+ }
+ *pdxpFirst = dxp;
+ dxp = 0;
+ for (cch = 0; cch < dcp; ++cch)
+ {
+ dxp += *pdxp++;
+ }
+ return dxp;
+#else
+
+ int dxp;
+ if (dcp > vfli.ichMac - dcpFirst)
+ { /* This should not be, but is when we have a CR */
+ Assert( dcpFirst < vfli.ichMac );
+ dcp = vfli.ichMac - dcpFirst;
+ }
+
+ /* first get space up to first character */
+ *pdxpFirst = LOWORD(GetTextExtent(hDC,vfli.rgch,dcpFirst)) + vfli.xpLeft;
+
+ /* now get space between first and first+dcp */
+ dxp = LOWORD(GetTextExtent(hDC,vfli.rgch+dcpFirst,dcp));
+ return dxp;
+#endif
+}
+
+
+UpdateDisplay(fAbortOK)
+int fAbortOK;
+{
+ int ww;
+
+ if (wwMac <= 0)
+ {
+ return;
+ }
+
+#ifdef CASHMERE
+ for (ww = 0; ww < wwMac; ww++)
+ if ( rgwwd[ww].doc != docScrap )
+ {
+ UpdateWw(ww, fAbortOK);
+ if (rgwwd[ww].fDirty || vfOutOfMemory)
+ {
+ return; /* update has been interrupted */
+ }
+ }
+#else /* not CASHMERE */
+ UpdateWw(wwDocument, fAbortOK);
+ if (wwdCurrentDoc.fDirty || vfOutOfMemory)
+ {
+ /* Update has been interrupted */
+ return;
+ }
+#endif /* not CASHMERE */
+
+ if (wwdCurrentDoc.fRuler)
+ {
+ UpdateRuler();
+ }
+}
+
+
+/* U P D A T E W W */
+UpdateWw(ww, fAbortOK)
+int ww, fAbortOK;
+{ /* Redisplay ww as necessary */
+ extern int vfWholePictInvalid;
+ register struct WWD *pwwd = &rgwwd[ww];
+ int dlMac;
+ int dlOld, dlNew;
+ int doc;
+ int ichCp;
+ struct EDL *pedlNew;
+ register struct EDL *pedl;
+ struct EDL (**hdndl)[]=pwwd->hdndl;
+ int dypDiff;
+ int ypTop;
+ int ypFirstInval;
+ int dr;
+ int fLastNotShown;
+ typeCP cp, cpMacWw;
+
+ if (!pwwd->fDirty)
+ {
+ return;
+ }
+
+ if (!((**hpdocdod)[pwwd->doc].fDisplayable))
+ return;
+
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+#if 0 // how to get first and last cp's in invalid rect?
+#if defined(OLE)
+ /*
+ Load visible objects. Do it now rather than in DisplayGraphics()
+ because here it has less chance of disrupting the state variables
+ upon which UpdateWw depends.
+ */
+ ObjEnumInRange(docCur,cpMinCur,cpMacCur,ObjLoadObjectInDoc);
+#endif
+#endif
+
+ dlMac = pwwd->dlMac;
+ ypTop = pwwd->ypMin;
+
+ Assert( ww >= 0 && ww < wwMax );
+ vfli.doc = docNil; /* An aid to Fast Insert */
+
+ UpdateInvalid(); /* InvalBand for what Windows considers to be invalid */
+ ypFirstInval = pwwd->ypFirstInval;
+
+#ifndef CASHMERE
+ Assert( ww == wwCur ); /* A MEMO-only assumption */
+#endif /* CASHMERE */
+
+ Scribble(5, 'U');
+
+ ValidateMemoryDC(); /* to do any update, we need a good memory DC */
+ if (vhMDC == NULL)
+ {
+ WinFailure();
+ return;
+ }
+
+ doc = pwwd->doc;
+ vfli.doc = docNil;
+
+ if (pwwd->fCpBad)
+ {
+/* cp first displayed has not been blessed */
+
+#ifdef CASHMERE /* Must do this if ww != wwCur assertion is FALSE */
+ int wwT = wwCur;
+ if (ww != wwCur && wwCur >= 0)
+/* CtrBackTrs cache is only good for wwCur. Treat != case */
+ {
+ if (pwwdCur->fDirty) /* Do wwCur first, saving cache */
+ UpdateWw(wwCur, fAbortOK);
+
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+ ChangeWw(ww, false);
+ CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
+ ChangeWw(wwT, false);
+ }
+ else
+#endif /* CASHMERE */
+
+ {
+ if (fAbortOK && FImportantMsgPresent())
+ return;
+
+ CtrBackDypCtr( 0, 0 ); /* Validate pwwdCur->cpFirst */
+ }
+ }
+
+/* check for cpMin accessible in this ww */
+RestartUpdate:
+ vfWholePictInvalid = fTrue; /* Tells DisplayGraphics to
+ abandon accumulated partial pict rect */
+ fLastNotShown = fFalse;
+ cp = CpMax(pwwd->cpMin, pwwd->cpFirst);
+ cpMacWw = pwwd->cpMac;
+ ichCp = pwwd->ichCpFirst;
+
+ /* Note test for dlNew==0 that guarantees that there will be at least
+ one dl -- this was added for WRITE because we do not have
+ the ability to enforce a minimum window size */
+
+ for (dlNew = dlOld = 0; ypTop < pwwd->ypMac || (dlNew == 0) ; dlNew++)
+ /* we have: cp, ichCP: pints to text desired on the coming line dlNew
+ ypTop: desired position for top of dlNew -1
+ dlOld: next line to be considered for re-use
+ */
+ /* check for having to extend dndl array */
+ {
+ if (dlNew >= (int)pwwd->dlMax)
+ {
+/* extend the array with uninitialized dl's, increment max, break if no space.
+We assume that dlMac(Old) was <= dlMax, so the dl's will not be looked at
+but used only to store new lines */
+#define ddlIncr 5
+
+ if (!FChngSizeH(hdndl, (pwwd->dlMax + ddlIncr) * cwEDL, fFalse))
+ break;
+ pwwd->dlMax += ddlIncr;
+ }
+/* discard unusable dl's */
+ for (; dlOld < dlMac; dlOld++)
+ { /* Set dlOld and pedl to the next good dl */
+ int ypTopOld, ypOld;
+
+ /* Re-entrant Heap Movement */
+ if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
+ goto RetInval;
+
+ pedl = &(**hdndl)[dlOld];
+ ypOld = pedl->yp;
+
+/* loop if: invalid, passed over in cp space, passed over in dl space,
+passed over in yp space,
+in invalid band, passed over in ich space */
+ if (!pedl->fValid || dlOld < dlNew || pedl->cpMin < cp
+ || (ypTopOld = (ypOld - pedl->dyp)) < ypTop
+ || (ypOld >= ypFirstInval && ypTopOld <= pwwd->ypLastInval)
+ || (pedl->cpMin == cp && pedl->ichCpMin < ichCp))
+ continue;
+/* now we have dlOld, an acceptable if not necessarily useful dl.
+now compute dlNew either from scratch or by re-using dlOld. To be
+re-useable, dlOld must have right cp/ichCp pair, plus be totally on screen
+or, if it is a partial line, it must stay still or move down - not up */
+ if (pedl->cpMin == cp && pedl->ichCpMin == ichCp &&
+ (ypOld <= pwwd->ypMac || ypTopOld <= ypTop))
+ {
+/* Re-use this dl */
+ int yp = ypTop;
+ if (fLastNotShown)
+ {
+ /* HEAP MOVEMENT */
+ DisplayFli(ww, dlNew - 1, fLastNotShown = fFalse);
+ pedl = &(**hdndl)[dlOld];
+ }
+
+ cp = pedl->cpMin + pedl->dcpMac;
+ ichCp = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0;
+ ypTop += pedl->dyp;
+ if (dlOld != dlNew || ypTopOld != yp)
+ {
+ DypScroll(ww, dlOld, dlNew - dlOld, yp);
+ if (vfScrollInval)
+ {
+ /* There was a popup; invalid region might have changed */
+ /* fLastNotShown test is for interrupting picture display */
+ /* before we've really displayed it */
+
+ (**hdndl) [dlOld].fValid = fFalse;
+ goto Restart1;
+ }
+ dlMac += dlNew - dlOld;
+ }
+ dlOld = dlNew + 1;
+ goto NextDlNew;
+ }
+ break;
+ }
+/* cpMin > cp, the line is not anywhere so it will have to be formatted
+from scratch */
+
+ if (fAbortOK && !fLastNotShown && FImportantMsgPresent())
+ goto RetInval;
+
+ FormatLine(doc, cp, ichCp, cpMacWw, flmSandMode); /* Creates vfli */
+
+ if (vfOutOfMemory)
+ goto RetInval;
+
+ ichCp = vfli.ichCpMac;
+ cp = vfli.cpMac;
+/* advance invalid band so that update can resume after an interruption */
+ pwwd->ypFirstInval = (ypTop += vfli.dypLine);
+ pedl = &(**hdndl)[dlOld];
+ if (dlOld < dlMac && pedl->cpMin == cp && pedl->ichCpMin == ichCp)
+ {
+ int dlT = dlOld;
+
+/* line at dlOld is a valid, existing line that will abutt the line just about
+to be displayed. */
+ if (dlOld == dlNew && pedl->yp - pedl->dyp <= ypTop)
+/* the line about to be overwritten will be re-used in the next loop.
+Hence, it is worthwhile to save this line and its dl */
+ DypScroll(ww, dlOld++, 1, ypTop);
+ else
+/* Move the next line to its abutting position. We know that it has not yet been
+overwritten (yp, dlOld all > than ypTop, dlNew) */
+ DypScroll(ww, dlOld, 0, ypTop);
+
+ if (vfScrollInval)
+ {
+ /* There was a popup; invalid region might have changed */
+ /* fLastNotShown test is for interrupting picture display */
+ /* before we've really displayed it */
+
+ (**hdndl) [dlT].fValid = fFalse;
+Restart1:
+ if (fLastNotShown)
+ {
+ pwwd->ypFirstInval = pwwd->ypMin;
+ }
+
+ ypFirstInval = pwwd->ypFirstInval;
+ ypTop = pwwd->ypMin;
+ goto RestartUpdate;
+ }
+ }
+
+/* true in 3rd param means put off picture redisplay till later */
+/* condition: graphics & not last in picture & not last in y space and
+not in front of a invalid or valid transition in the picture */
+ DisplayFli(ww, dlNew, fLastNotShown =
+ (vfli.fGraphics && vfli.ichCpMac!=0 && ypTop < pwwd->ypMac));
+NextDlNew:;
+ }
+Break1:
+ pwwd->dlMac = dlNew;
+
+#ifdef CASHMERE
+/* condition is here to avoid swapping */
+ if (pwwd->fSplit && rgwwd[pwwd->ww].fFtn)
+ CalcFtnLimits(pwwd);
+#endif /* CASHMERE */
+
+ SetCurWwVScrollPos(); /* Set Scroll bar position */
+ vfTextBltValid = false;
+
+/* reset invalid indications */
+ pwwd->fDirty = false;
+ pwwd->ypFirstInval = ypMaxAll;
+ pwwd->ypLastInval = 0; /* so that max in InvalBand will work */
+ Scribble(5, ' ');
+ goto Validate;
+
+/* Before returning from an interrupt, invalidate lines that were overwritten
+within the present update. */
+RetInval:
+ Scribble(5, ' ');
+ for (; dlOld < dlMac; dlOld++)
+ {
+ pedl = &(**hdndl)[dlOld];
+ if ((pedl->yp - pedl->dyp) < ypTop)
+ pedl->fValid = fFalse;
+ else
+ break;
+ }
+Validate: ;
+
+#ifdef ENABLE /* We will let UpdateInvalid handle this in case
+ further invalidation occurred during the update */
+
+ { /* Tell Windows that the part we updated is valid */
+ RECT rc;
+
+ rc.left = 0;
+ rc.top = pwwd->ypMin;
+ rc.right = pwwd->xpMac;
+ rc.bottom = imin( pwwd->ypMac, ypTop );
+ ValidateRect( pwwd->wwptr, (LPRECT)&rc );
+ }
+#endif
+}
+
+
+
+
+/* D Y P S C R O L L */
+DypScroll(ww, dlFirst, ddl, ypTo)
+int ww, dlFirst, ddl, ypTo;
+{
+/* Scroll dl's in a window, from dlFirst to end, down ddl lines (or up -ddl).
+Bitmap is moved from top of dlFirst to ypTo. The yp's of the dl's are updated.
+Returns the amount scrolled. (positive means down). */
+
+ register struct WWD *pwwd = &rgwwd[ww];
+ int dlMac;
+ int dlT;
+ int ypFrom;
+ int dypChange;
+ int cdlBelow;
+ struct EDL *pedl;
+ struct EDL *pedlT;
+
+ /* Do not call procedures while dndl is loaded up to avoid heap movement */
+ struct EDL *dndl = &(**(pwwd->hdndl))[0];
+
+ Assert( ww >= 0 && ww < wwMax );
+
+ vfScrollInval = fFalse;
+
+ /* Number of dl's below (and including) the first one to be scrolled */
+ cdlBelow = pwwd->dlMac - dlFirst;
+ pwwd->dlMac = min(pwwd->dlMac + ddl, pwwd->dlMax);
+ cdlBelow = max(0, min(cdlBelow, pwwd->dlMac - ddl - dlFirst));
+
+ pedlT = &dndl[dlFirst];
+ ypFrom = pedlT->yp - pedlT->dyp;
+
+ /* Length of area to be moved */
+ dypChange = ypTo - ypFrom;
+
+ if (cdlBelow > 0)
+ {
+ int dlTo = dlFirst + ddl;
+ int ypMac = pwwd->ypMac;
+
+ pedlT = &dndl[dlTo];
+ if (ddl != 0)
+ {
+ blt(&dndl[dlFirst], pedlT, cwEDL * cdlBelow);
+ }
+
+ for (dlT = dlTo; dlT < pwwd->dlMac; ++dlT, ++pedlT)
+ {
+ if (dypChange < 0 && pedlT->yp > ypMac)
+ {
+ /* Invalidate dl's that are pulled in from the ozone below ypMac
+ */
+ pedlT->fValid = fFalse;
+ }
+ else
+ {
+ pedlT->yp += dypChange;
+ }
+ }
+ }
+
+ if (dypChange != 0)
+ {
+ RECT rc;
+
+ SetRect( (LPRECT)&rc, 0, min(ypFrom, ypTo),
+ pwwd->xpMac, pwwd->ypMac );
+ Assert( ww == wwCur ); /* A MEMO-only assumption */
+ ScrollCurWw( &rc, 0, dypChange );
+ }
+
+ return dypChange;
+}
+
+
+
+
+FImportantMsgPresent()
+{
+ /* If the next message is important enough to interrupt a screen update, we
+ return TRUE; if it can wait, we return FALSE */
+
+ BOOL fToggledKey;
+ extern MSG vmsgLast;
+
+#ifdef DEBUG
+ unsigned wHeapVal = *(pLocalHeap + 1);
+
+ Assert( wHeapVal == 0 ); /* Heap should not be frozen */
+#endif
+
+#ifdef DBCS
+ if( donteat )
+ return TRUE;
+#endif
+
+while (PeekMessage((LPMSG) &vmsgLast, NULL, NULL, NULL, PM_NOREMOVE))
+ {
+
+ if (((vmsgLast.wParam == VK_MENU) || (vmsgLast.wParam == VK_CONTROL)))
+ {
+ if (vmsgLast.wParam == VK_CONTROL)
+ {
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+ SetShiftFlags();
+ }
+ return TRUE;
+ }
+ /* Filter uninteresting or easily handled events */
+ else if (fToggledKey = FCheckToggleKeyMessage(&vmsgLast) ||
+ (vmsgLast.message == WM_KEYUP && vmsgLast.hwnd == wwdCurrentDoc.wwptr))
+ {
+
+ /* This is so the Windows keyboard interface mechanism will see toggle
+ key and key-up transitions */
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+#ifdef WIN30
+ /* PeekMessage has been changed in Win 3.0 so that GetKeyState()
+ called from FCheckToggleKeyMessage() is really only valid if
+ you've done a PeekMessage(...,PM_REMOVE) or GetMessage() first.
+ That is, while the FCheckToggleKeyMessage() call might succeed
+ above, it will NOT have set the vfShiftKey/vfCommandKey flags
+ correctly -- so we do it here ..pault */
+ if (fToggledKey)
+ FCheckToggleKeyMessage(&vmsgLast);
+#endif
+ if (vmsgLast.hwnd != wwdCurrentDoc.wwptr)
+ {
+ /* Just in case a modeless dialog's window proc cares */
+ TranslateMessage((LPMSG)&vmsgLast);
+ DispatchMessage((LPMSG)&vmsgLast);
+ }
+#ifdef DBCS
+ if (vmsgLast.message == WM_CHAR || vmsgLast.message == WM_KEYDOWN ) {
+ donteat = TRUE;
+ return( TRUE );
+ } /* else Ok, you are KEYUP message. do normal */
+#endif
+ }
+ else
+ {
+ switch (vmsgLast.message)
+ {
+ case WM_MOUSEMOVE:
+ /* Process mouse move messages immediately; they are not really
+ important. NOTE: This assumes that we have not captured all mouse
+ events; in which case, they are important. */
+ DispatchMessage((LPMSG)&vmsgLast);
+
+ case WM_TIMER:
+ case WM_SYSTIMER:
+ /* Remove timer and mouse move messages from the queue. */
+ GetMessage((LPMSG) &vmsgLast, NULL, NULL, NULL);
+ break;
+
+ default:
+ Assert( *(pLocalHeap+1) == 0 ); /* Heap should still not be frozen */
+ return (TRUE);
+ }
+ }
+ }
+
+
+Assert( *(pLocalHeap + 1) == 0 ); /* Heap should still not be frozen */
+return (FALSE);
+}
+
+
+/* C P B E G I N L I N E */
+typeCP CpBeginLine(pdl, cp)
+int *pdl;
+typeCP cp;
+ { /* return the cp and dl containing cp */
+ int dlMin, dlLim;
+ typeCP cpGuess;
+ struct EDL *dndl;
+
+ do
+ {
+ UpdateWw(wwCur, false);
+ PutCpInWwVert(cp); /* Ensure cp on screen */
+ } while (pwwdCur->fDirty && !vfOutOfMemory);
+
+ dndl = &(**(pwwdCur->hdndl))[0];
+ dlMin = 0;
+ dlLim = pwwdCur->dlMac;
+ while (dlMin + 1 < dlLim)
+ { /* Binary search the ww */
+ int dlGuess = (dlMin + dlLim) >> 1;
+ struct EDL *pedl = &dndl[dlGuess];
+ if ((cpGuess = pedl->cpMin) <= cp && (cpGuess != cp || pedl->ichCpMin == 0))
+ { /* guess is low or right */
+ dlMin = dlGuess;
+ if (cp == cpGuess && pedl->cpMin + pedl->dcpMac != cp)
+ break; /* Got it right */
+ }
+ else /* Guess is high */
+ dlLim = dlGuess;
+ }
+ *pdl = dlMin;
+ return dndl[dlMin].cpMin;
+}
+
+
+
+
+/* T O G G L E S E L */
+ToggleSel(cpFirst, cpLim, fOn)
+typeCP cpFirst, cpLim; /* selection bounds */
+int fOn;
+{ /* Flip selection highlighting on and off */
+ extern int vfPMS;
+ struct EDL *pedl;
+ int dlT;
+ int xpMin;
+ int dxpRoom;
+ int xpFirst;
+ int xpLim;
+ int fInsertPoint = (cpFirst == cpLim);
+
+ if (vfSelHidden || cpFirst > cpLim || cpLim < /*cp0*/ cpMinCur || vfDead)
+ return;
+
+ if ( vfPictSel && vfPMS &&
+ (CachePara( docCur, cpFirst ), vpapAbs.fGraphics) &&
+ (vcpLimParaCache == cpLim) )
+ { /* Don't show inversion if we're moving or sizing a picture */
+ return;
+ }
+
+ dxpRoom = pwwdCur->xpMac - xpSelBar;
+ xpMin = pwwdCur->xpMin;
+
+ for (dlT = 0; dlT < pwwdCur->dlMac; dlT++)
+ {
+ typeCP cpMin, cpMac; /* line bounds */
+ pedl = &(**(pwwdCur->hdndl))[dlT];
+ if (!pedl->fValid)
+ continue;
+ cpMin = pedl->cpMin;
+ if (cpMin > cpLim || cpMin > cpMacCur || (cpMin == cpLim && cpLim != cpFirst))
+ break;
+ cpMac = cpMin + pedl->dcpMac;
+ if (cpFirst <= cpMin && cpLim >= cpMac)
+ {
+/* entire line is highlighted */
+ xpFirst = pedl->xpLeft;
+ if (pedl->fGraphics && cpLim == cpMac && cpMin == cpMac)
+ /* Special kludge for graphics paras */
+ xpLim = xpFirst;
+ else
+ xpLim = pedl->xpMac;
+ }
+ else if (fInsertPoint && cpFirst == cpMac && vfInsEnd)
+ { /* Special kludge for an insert point at the end of a line */
+ xpLim = xpFirst = pedl->xpMac;
+ }
+ else if (cpFirst < cpMac)
+ {
+ /* Bite the bullet */
+ int dxp;
+ typeCP cpBegin = CpMax(cpMin, cpFirst);
+ typeCP cpEnd = CpMin(cpMac, cpLim);
+
+ FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
+ dxp = DxpDiff((int) (cpBegin - cpMin),
+ (int) (cpEnd - cpBegin), &xpFirst);
+ xpLim = xpFirst + dxp;
+/* reload pedl because procedures were called */
+ pedl = &(**(pwwdCur->hdndl))[dlT];
+ }
+ else
+ continue;
+/* now we have: pedl valid, xpFirst, xpLast describe highlight */
+ /* xpFirst = max(xpFirst, xpMin); */
+ xpLim = min(xpLim, xpMin + pedl->xpMac);
+ if (xpLim > xpFirst)
+ {
+ if (xpLim > xpMin)
+ {
+ RECT rc;
+ rc.top = pedl->yp - pedl->dyp;
+ rc.left = xpSelBar + max(xpFirst - xpMin, 0);
+ rc.bottom = pedl->yp;
+ rc.right = xpSelBar + xpLim - xpMin;
+ InvertRect( wwdCurrentDoc.hDC, (LPRECT)&rc);
+ }
+ }
+/* ToggleSel modified 7/28/85 -- added explicit check for fInsertPoint, since
+ the xpLim == xpFirst test sometimes succeeded bogusly when a selection
+ was extended backwards. BL */
+ else if (fInsertPoint && (xpLim == xpFirst)) /* Insertion point */
+ {
+ /* vfli should usually be cached already, so will be fast. */
+ int yp = pedl->yp;
+ FormatLine(docCur, cpMin, pedl->ichCpMin, cpMacCur, flmSandMode);
+ if (fOn ^ vfInsertOn)
+ {
+ if (!vfInsertOn)
+ {
+ vxpCursLine = xpSelBar + xpFirst - xpMin;
+ vypCursLine = yp - vfli.dypAfter;
+ vdypCursLine = min(vfli.dypFont, vfli.dypLine - vfli.dypAfter);
+
+ /* Start blinking in a while */
+ vfSkipNextBlink = TRUE;
+ }
+ DrawInsertLine();
+ }
+ return;
+ }
+ }
+}
+
+
+
+
+/* T R A S H W W */
+TrashWw(ww)
+{ /* Invalidate all dl's in ww */
+ Assert( ww >= 0 && ww < wwMax );
+ InvalBand(&rgwwd[ww], 0, ypMaxAll);
+}
+
+
+
+
+/* I N V A L B A N D */
+/* invalidate the band ypFirst, ypLast inclusive */
+InvalBand(pwwd, ypFirst, ypLast)
+struct WWD *pwwd; int ypFirst, ypLast;
+ {
+/* this covers some peculiar rects received from update event after a
+window resize by 1 pixel. CS */
+ if (ypLast < 0 || ypFirst == ypLast) return;
+
+ pwwd->fDirty = true;
+ pwwd->ypFirstInval = min(pwwd->ypFirstInval, ypFirst);
+ pwwd->ypLastInval = max(ypLast, pwwd->ypLastInval);
+ }
+
+
+
+
+/* T R A S H A L L W W S */
+TrashAllWws()
+{ /* trash them all */
+ int ww;
+
+#ifdef CASHMERE
+ for (ww = 0; ww < wwMac; ++ww)
+ TrashWw(ww);
+#else
+ TrashWw( wwDocument );
+#endif
+ vfli.doc = docNil; /* Mark vfli invalid */
+}
+
+
+/* T U R N O F F S E L */
+TurnOffSel()
+{ /* Remove sel highlighting from screen */
+/* HideSel has no effect */
+ if (!vfSelHidden)
+ {
+ ToggleSel(selCur.cpFirst, selCur.cpLim, false);
+ vfSelHidden = true;
+ }
+}
+
+
+/* D R A W I N S E R T L I N E */
+DrawInsertLine()
+{ /* Draw (in Xor mode) a vertical bar at screen position v*CursLine */
+ /* Toggles both the display and the vfInsertOn flag */
+ /* Adjustments in cursor draw must be reflected in DisplayFli, above */
+
+ /* Last-minute correction for a bug: assure that the insert line
+ does not extend above ypMin */
+ if (!vfInsertOn && vdypCursLine > vypCursLine - wwdCurrentDoc.ypMin)
+ vdypCursLine = vypCursLine - wwdCurrentDoc.ypMin;
+
+ /* Tell GDI to invert the caret line */
+ PatBlt( wwdCurrentDoc.hDC, vxpCursLine, vypCursLine - vdypCursLine,
+ 2, vdypCursLine , DSTINVERT );
+ vfInsertOn = 1 - vfInsertOn;
+}
+
+
+
+
+/* C L E A R I N S E R T L I N E */
+ClearInsertLine()
+{
+ if ( vfInsertOn) DrawInsertLine();
+}
diff --git a/private/mvdm/wow16/write/dispdefs.h b/private/mvdm/wow16/write/dispdefs.h
new file mode 100644
index 000000000..15e63769f
--- /dev/null
+++ b/private/mvdm/wow16/write/dispdefs.h
@@ -0,0 +1,76 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Originally, this file contained nothing but screen constants, but these
+constants had to become variables to account for all different display devices.
+*/
+
+/* size of lines for dnMax estimation purposes */
+extern int dypAveInit;
+
+/* width of the selection bar area to the left of lines */
+extern int xpSelBar;
+
+extern int dxpScrlBar;
+extern int dypScrlBar;
+extern int dxpInfoSize;
+
+#define xaRightMax 31680
+extern int xpRightMax;
+extern int xpMinScroll;
+extern int xpRightLim;
+
+/* these define the initial window size and amount of white space above
+the first line */
+extern int ypMaxWwInit;
+
+/* should be > than largest window height + height of blank line after
+the endmark */
+extern int ypMaxAll; /* used for invalidation */
+extern int dypWwInit;
+
+extern int dypBand; /* formerly dpxyLineSizeMin */
+
+extern int dypRuler;
+
+extern int ypSubSuper;
+
+/* number of quanta in elevator control */
+#define drMax 256
+
+#define ctcAuto 10
+#define ctrAuto 4
+
+#define cxpAuto 72
+
+
+/* DL structure revised, 3 Sept KJS, CS */
+/* 14 Nov 89 ..pault (changed dcpMac from int to
+ typeCP because we experienced
+ wraparound when sizing large
+ graphics objects) */
+struct EDL
+ {
+ unsigned char dcpDepend : 8;
+ unsigned char ichCpMin : 8;
+ unsigned fValid : 1;
+#ifdef CASHMERE
+ unsigned fStyleInfo : 1;
+#else
+ unsigned fSplat: 1;
+#endif
+ unsigned fGraphics : 1;
+ unsigned fIchCpIncr : 1;
+ unsigned xpLeft : 12;
+ typeCP dcpMac; /* representing cpMac */
+ typeCP cpMin;
+ int xpMac;
+ int dyp; /* height of the dl */
+ int yp; /* position of the dl */
+ };
+
+#define cchEDL (sizeof (struct EDL))
+#define cwEDL (cchEDL / sizeof(int))
+
+#define cedlInit 20
diff --git a/private/mvdm/wow16/write/dlgdefs.h b/private/mvdm/wow16/write/dlgdefs.h
new file mode 100644
index 000000000..adc68039a
--- /dev/null
+++ b/private/mvdm/wow16/write/dlgdefs.h
@@ -0,0 +1,182 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the definition of the numerical indexes to the dialog
+items (idi) used by Windows Memo. */
+/* IDOK and IDCANCEL are defined in windows.h
+ windows dialog manager returns :
+ IDOK if the <Return> key is hit
+ IDCANCEL if the <ESC> key is hit
+ As a rule, the default button should be assigned idiOk
+*/
+
+#define idiNil -1
+
+#define idiOk IDOK
+#define idiCancel IDCANCEL
+#define idiYes IDYES
+#define idiNo IDNO
+
+#ifndef NOIDISAVEPRINT /* Another tool to avoid compiler heap overflow */
+#define idiAbort idiOk
+#define idiRetry 3
+#define idiIgnore idiCancel
+#define idiMessage 4
+
+#define idiSavDir 3
+#define idiSavFile 4
+#define idiSavBackup 5
+#define idiSavTextOnly 6
+#define idiSavWordFmt 7
+#define idiSavDirLB 8
+
+#define idiOpenDir 3
+#define idiOpenFile 4
+#define idiOpenFileLB 5
+#define idiOpenDirLB 6
+
+#define idiPrterName 3
+#define idiPrterSetup 4
+#define idiRepageConfirm 3
+
+#define idiGtoPage 3
+
+#define idiPrtAll 6
+#define idiPrtFrom 7
+#define idiPrtPageFrom 8
+#define idiPrtPageTo 9
+#define idiPrtCopies 10
+#define idiPrtDraft 11
+#define idiPrtDest 12
+
+#define idiPrCancelName 100 /* For the filename in CancelPrint dlg */
+
+/* interactive repaginating */
+#define idiKeepPgMark idiOk
+#define idiRemovePgMark 4
+#define idiRepUp 5
+#define idiRepDown 6
+
+#endif /* NOIDISAVEPRINT */
+
+#ifndef NOIDIFORMATS
+#define idiChrFontName 3
+#define idiChrLBFontName 4
+#define idiChrFontSize 5
+#define idiChrLBFontSize 6
+
+#define idiParLfIndent 3
+#define idiParFirst 4
+#define idiParRtIndent 5
+/*#define idiParLineSp 6
+#define idiParSpBefore 7
+#define idiParSpAfter 8
+#define idiParLeft 9
+#define idiParCentered 10
+#define idiParRight 11
+#define idiParJustified 12
+#define idiParKeepNext 13
+#define idiParKeepTogether 14 */
+
+#define idiTabClearAll 3
+#define idiTabPos0 4
+#define idiTabPos1 5
+#define idiTabPos2 6
+#define idiTabPos3 7
+#define idiTabPos4 8
+#define idiTabPos5 9
+#define idiTabPos6 10
+#define idiTabPos7 11
+#define idiTabPos8 12
+#define idiTabPos9 13
+#define idiTabPos10 14
+#define idiTabPos11 15
+#define idiTabDec0 16
+#define idiTabDec1 17
+#define idiTabDec2 18
+#define idiTabDec3 19
+#define idiTabDec4 20
+#define idiTabDec5 21
+#define idiTabDec6 22
+#define idiTabDec7 23
+#define idiTabDec8 24
+#define idiTabDec9 25
+#define idiTabDec10 26
+#define idiTabDec11 27
+
+#define idiRHInsertPage 3
+#define idiRHClear 4
+#define idiRHDx 5
+#define idiRHFirst 6
+#define idiRHDxText 7
+#define idiRHLines 8
+
+#define idiDivPNStart 3
+#define idiDivLMarg 4
+#define idiDivRMarg 5
+#define idiDivTMarg 6
+#define idiDivBMarg 7
+
+#ifdef INTL
+
+#define idiDivInch 8
+#define idiDivCm 9
+
+#endif /* INTERNATIONAL */
+
+
+#endif /* NOIDIFORMATS */
+
+#define idiFind 7
+#define idiChangeThenFind 9
+#define idiChange 3
+#define idiChangeAll 4
+#define idiWholeWord 5
+#define idiMatchCase 6
+#define idiFindNext idiOk
+#define idiChangeTo 8
+
+#define idiHelp 3
+#define idiHelpTopics 3
+#define idiHelpNext 4
+#define idiHelpPrev 5
+#define idiHelpName 6
+#define idiMemFree 7
+#define idiHelpScroll 8
+
+#define idiBMrgLeft 3
+#define idiBMrgRight 4
+#define idiBMrgTop 5
+#define idiBMrgBottom 6
+
+#define idiConvertPrompt 99
+
+/* Dialog Box ID's (substitite for Template Name strings) */
+
+#define dlgOpen 1
+#define dlgSaveAs 2
+/* #define dlgSaveScrap 3 */
+
+ /* dlgWordCvt takes the position of the commented out Save Scrap box */
+#define dlgWordCvt 3
+
+#define dlgHelp 4
+#define dlgHelpInner 22
+#define dlgPrint 5
+#define dlgCancelPrint 6
+#define dlgRepaginate 7
+#define dlgCancelRepage 8
+#define dlgSetPage 9
+#define dlgPageMark 10
+#define dlgPrinterSetup 11
+#define dlgFind 12
+#define dlgChange 13
+#define dlgGoTo 14
+#define dlgCharFormats 15
+#define dlgParaFormats 16
+#define dlgRunningHead 17
+#define dlgFooter 18
+#define dlgTabs 19
+#define dlgDivision 20
+#define dlgBadMargins 21
diff --git a/private/mvdm/wow16/write/doc.c b/private/mvdm/wow16/write/doc.c
new file mode 100644
index 000000000..56966aa24
--- /dev/null
+++ b/private/mvdm/wow16/write/doc.c
@@ -0,0 +1,409 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* doc.c -- MW document processing routines (non-resident) */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOFONT
+#define NOGDI
+#define NOHDC
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "editdefs.h"
+#include "docdefs.h"
+#include "fontdefs.h"
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "stcdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "macro.h"
+
+
+extern struct DOD (**hpdocdod)[];
+extern int docMac;
+extern int docScrap;
+extern int docUndo;
+#ifdef STYLES
+#ifdef SAND
+extern CHAR szSshtEmpty[];
+#else
+extern CHAR szSshtEmpty[];
+#endif
+#endif
+
+/* E X T E R N A L S */
+extern int docRulerSprm;
+extern int vfSeeSel;
+extern struct SEP vsepNormal;
+extern struct CHP vchpNormal;
+extern int docCur;
+extern struct FLI vfli;
+extern int vdocParaCache;
+extern struct FCB (**hpfnfcb)[];
+extern struct UAB vuab;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int vdocExpFetch;
+extern CHAR (**hszSearch)[];
+extern typeCP vcpFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern struct CHP vchpFetch;
+#ifdef STYLES
+extern struct PAP vpapCache;
+extern CHAR mpusgstcBase[];
+#endif
+extern int vrefFile;
+
+
+struct PGTB **HpgtbCreate();
+
+
+#ifdef ENABLE /* This is never called */
+int DocFromSz(sz, dty)
+CHAR sz[];
+/* Return doc if one with that name exists already */
+{
+int doc;
+struct DOD *pdod = &(**hpdocdod)[0];
+struct DOD *pdodMac = pdod + docMac;
+
+if (sz[0] == 0)
+ return docNil;
+
+for (doc = 0; pdod < pdodMac; ++pdod, ++doc)
+ if (pdod->hpctb != 0 && pdod->dty == dty &&
+ FSzSame(sz, **pdod->hszFile)
+#ifdef SAND
+ && (pdod->vref == vrefFile)
+#endif
+ )
+ {
+ ++pdod->cref;
+ return doc;
+ }
+return docNil;
+}
+#endif
+
+
+KillDoc(doc)
+int doc;
+{ /* Wipe this doc, destroying any changes since last save */
+extern int vdocBitmapCache;
+
+if (doc == docScrap)
+ return; /* Can't be killed no-how */
+
+if (--(**hpdocdod)[doc].cref == 0)
+ {
+ struct FNTB **hfntb;
+#ifdef CASHMERE
+ struct SETB **hsetb;
+#else
+ struct SEP **hsep;
+#endif
+ struct FFNTB **hffntb;
+ struct TBD (**hgtbd)[];
+ CHAR (**hsz)[];
+ int docSsht;
+
+ SmashDocFce( doc );
+
+ /* Kill style sheet doc if there is one. */
+ if ((docSsht = (**hpdocdod)[doc].docSsht) != docNil)
+ KillDoc(docSsht);
+
+ /* Free piece table, filename, and footnote (or style) table */
+ FreeH((**hpdocdod)[doc].hpctb);
+ (**hpdocdod)[doc].hpctb = 0; /* To show doc free */
+ if ((hsz = (**hpdocdod)[doc].hszFile) != 0)
+ FreeH(hsz);
+ if ((hfntb = (**hpdocdod)[doc].hfntb) != 0)
+ FreeH(hfntb);
+#ifdef CASHMERE
+ if ((hsetb = (**hpdocdod)[doc].hsetb) != 0)
+ FreeH(hsetb);
+#else
+ if ((hsep = (**hpdocdod)[doc].hsep) != 0)
+ FreeH(hsep);
+#endif
+
+ if ((hgtbd = (**hpdocdod)[doc].hgtbd) != 0)
+ FreeH( hgtbd );
+ if ((hffntb = (**hpdocdod)[doc].hffntb) != 0)
+ FreeFfntb(hffntb);
+
+ if (doc == vdocBitmapCache)
+ FreeBitmapCache();
+
+ InvalidateCaches(doc);
+ if (docCur == doc)
+ docCur = docNil;
+ if (docRulerSprm == doc)
+ docRulerSprm = docNil;
+ if (vuab.doc == doc || vuab.doc2 == doc)
+ NoUndo();
+ }
+}
+
+
+
+#ifdef STYLES
+struct SYTB **HsytbCreate(doc)
+int doc;
+{ /* Create a map from stc to cp for a style sheet */
+typeCP cp, *pcp;
+struct SYTB **hsytb;
+typeCP cpMac;
+int stc, usg, stcBase, stcMin;
+int ch, cch, cchT;
+int *pbchFprop, *mpstcbchFprop;
+CHAR *pchFprop, *grpchFprop;
+int iakd, iakdT, cakd, cakdBase;
+struct AKD *rgakd, *pakd;
+#ifdef DEBUG
+int cakdTotal;
+#endif
+
+CHAR rgch[3];
+CHAR mpchcakc[chMaxAscii];
+typeCP mpstccp[stcMax];
+
+/* First, clear out the stc-->cp map by filling with cpNil. */
+for (stc = 0, pcp = &mpstccp[0]; stc < stcMax; stc++, pcp++)
+ *pcp = cpNil;
+bltbc(mpchcakc, 0, chMaxAscii);
+
+/* Now go through all entries in the style sheet. In this pass,
+ check for duplicates (and return 0 if in gallery mode), fill
+ mpstccp with appropriate entries for all defined stc's, and
+ count the length of all the styles so we can allocate the heap
+ block later. */
+cpMac = (**hpdocdod)[doc].cpMac;
+for (cp = 0, cch = 0, cakd = 1, cakdBase = 1; cp < cpMac; cp += ccpSshtEntry)
+ {
+ FetchRgch(&cchT, rgch, doc, cp, cpMac, 3);
+ stc = rgch[0]; /* stc is first cp of entry */
+#ifdef DEBUG
+ Assert(stc < stcMax);
+#endif
+ if (mpstccp[stc] != cpNil && doc == docCur)
+ { /* Repeated entry */
+ Error(IDPMTStcRepeat);
+ goto ErrRet;
+ }
+ mpstccp[stc] = cp;
+ if (stc < stcSectMin)
+ {
+ FetchCp(doc, cp, 0, fcmProps);
+ cch += CchDiffer(&vchpFetch, &vchpNormal, cchCHP) + 1;
+ }
+ if (stc >= stcParaMin)
+ {
+ CachePara(doc, cp);
+ if (stc >= stcSectMin)
+ cch += CchDiffer(&vpapCache, &vsepNormal, cchSEP) + 1;
+ else
+ cch += CchDiffer(&vpapCache, &vpapStd, cchPAP) + 1;
+ }
+ ch = rgch[1];
+ if (ch != ' ')
+ { /* Define an alt-key code for this style */
+ ++cakd;
+ if (rgch[2] == ' ')
+ {
+ if (mpchcakc[ch]-- != 0)
+ {
+ Error(IDPMTAkcRepeat);
+ goto ErrRet;
+ }
+ ++cakdBase;
+ }
+ else
+ {
+ ++mpchcakc[ch]; /* increment before switch to avoid
+ the increment being taken
+ as for an int. */
+ switch (mpchcakc[ch])
+ {
+ case 0:
+ Error(IDPMTAkcRepeat);
+ goto ErrRet;
+ case 1:
+ ++cakdBase;
+ ++cakd;
+ }
+ }
+ }
+ }
+
+/* Now allocate the heap block, using the total we got above. */
+/* HEAP MOVEMENT */
+hsytb = (struct SYTB **) HAllocate(cwSYTBBase + cwAKD * cakd +
+ CwFromCch(cch));
+
+if (FNoHeap(hsytb))
+ return hOverflow;
+
+/* Now go through the stc-->cp map, filling in the stc-->fprop map
+ in the sytb. For each stc that isn't defined, determine which
+ stc to alias it to (either the first of the usage or, if that
+ one isn't defined, the first one of the first usage). Copy the
+ actual CHP's, PAP's, and SEP's into grpchFprop. */
+mpstcbchFprop = (**hsytb).mpstcbchFprop;
+rgakd = (struct AKD *) (grpchFprop = (**hsytb).grpchFprop);
+pchFprop = (CHAR *) &rgakd[cakd];
+pcp = &mpstccp[0];
+pbchFprop = &mpstcbchFprop[0];
+*pbchFprop = bNil;
+#ifdef DEBUG
+cakdTotal = cakd;
+#endif
+for (stc = 0, usg = 0, stcBase = 0, stcMin = 0, iakd = 0;
+ stc < stcMax;
+ stc++, pcp++, pbchFprop++)
+ {
+ if (stc >= mpusgstcBase[usg + 1])
+ { /* Crossed a usage or class boundary */
+ *pbchFprop = bNil;
+ stcBase = mpusgstcBase[++usg];
+ if (stcBase == stcParaMin || stcBase == stcSectMin)
+ { /* Update the base; make std if none defined */
+ stcMin = stcBase;
+ }
+ }
+ if ((cp = *pcp) == cpNil)
+ { /* No style defined; take first for usg or, failing
+ that, first style of this class. */
+ if ((*pbchFprop = mpstcbchFprop[stcBase]) == bNil)
+ *pbchFprop = mpstcbchFprop[stcMin];
+ }
+ else
+ { /* New style; copy the looks and bump the pointers */
+ /* Char stc's have just FCHP; para has FPAP followed by
+ FCHP; sect has FSEP. */
+ *pbchFprop = pchFprop - grpchFprop;
+ if (stc >= stcParaMin)
+ { /* Para or sect */
+ CachePara(doc, cp);
+ if (stc >= stcSectMin)
+ cchT = CchDiffer(&vpapCache, &vsepNormal, cchSEP);
+ else
+ cchT = CchDiffer(&vpapCache, &vpapStd, cchPAP);
+ if ((*pchFprop++ = cchT) != 0)
+ bltbyte(&vpapCache, pchFprop, cchT);
+ pchFprop += cchT;
+ }
+ if (stc < stcSectMin)
+ { /* Char or para */
+ FetchCp(doc, cp, 0, fcmProps);
+ cchT = CchDiffer(&vchpFetch, &vchpNormal, cchCHP);
+ if ((*pchFprop++ = cchT) != 0)
+ bltbyte(&vchpFetch, pchFprop, cchT);
+ pchFprop += cchT;
+ }
+ /* Insert element in akd table */
+ FetchRgch(&cchT, rgch, doc, cp, cpMac, 3);
+ if ((ch = rgch[1]) == ' ')
+ continue;
+ if (rgch[2] == ' ')
+ { /* Single-key akc */
+ pakd = &rgakd[iakd++];
+ pakd->ch = ch;
+ pakd->fMore = false;
+ pakd->ustciakd = stc;
+ }
+ else
+ { /* Two-char akc */
+ for (iakdT = 0; iakdT < iakd; iakdT++)
+ if (rgakd[iakdT].ch == ch)
+ {
+ pakd = &rgakd[rgakd[iakdT].ustciakd +
+ --mpchcakc[ch]];
+ pakd->ch = rgch[2];
+ pakd->fMore = true;
+ pakd->ustciakd = stc;
+ do
+ if ((++pakd)->ch == rgch[2])
+ {
+ Error(IDPMTAkcRepeat);
+ FreeH(hsytb);
+ goto ErrRet;
+ }
+ while (pakd->fMore);
+ goto NextStc;
+ }
+ pakd = &rgakd[iakd++];
+ pakd->ch = ch;
+ pakd->fMore = true;
+ pakd->ustciakd = (cakd -= mpchcakc[ch]);
+ pakd = &rgakd[cakd + --mpchcakc[ch]];
+ pakd->ch = rgch[2];
+ pakd->fMore = false;
+ pakd->ustciakd = stc;
+ }
+ }
+NextStc: ;
+ }
+
+pakd = &rgakd[iakd++];
+pakd->ch = ' ';
+pakd->fMore = false;
+pakd->ustciakd = stcNormal;
+
+#ifdef DEBUG
+Assert(grpchFprop + cchAKD * cakdTotal + cch == pchFprop && iakd == cakd);
+#endif
+return hsytb;
+
+ErrRet:
+Select(cp, cp + ccpSshtEntry);
+vfSeeSel = true;
+return 0;
+}
+#endif /* STYLES */
+
diff --git a/private/mvdm/wow16/write/docdefs.h b/private/mvdm/wow16/write/docdefs.h
new file mode 100644
index 000000000..8927d7fe4
--- /dev/null
+++ b/private/mvdm/wow16/write/docdefs.h
@@ -0,0 +1,86 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+//#define prmNil 0
+#define docNil (-1)
+#define cpNil ((typeCP) -1)
+#define cpMax ((typeCP) 2147483647)
+#define fcNil ((typeFC) -1)
+#define cp0 ((typeCP) 0)
+#define fnNil (32767)
+#define fc0 ((typeFC) 0)
+#define tcMax 255
+
+#ifdef SAND
+#define xaMax 9500
+#endif
+
+#define pn0 ((typePN) 0)
+
+#define cdocInit 4
+#define cwExpand 256
+#define cchMaxExpand (cwExpand * sizeof (int))
+
+/* FetchCp Modes */
+#define fcmChars 1
+#define fcmProps 2
+#define fcmBoth (fcmChars + fcmProps)
+#define fcmNoExpand 4
+#define fcmParseCaps 8 /* Return separate runs for U&lc if sm. caps*/
+
+/* Document types -- two bits only */
+#define dtyNormal 0
+#define dtyBuffer 1
+#define dtySsht 2
+#define dtyPrd 3
+#define dtySystem 4 /* Never written; smashed to dtyNormal */
+#define dtyHlp 5 /* Never written */
+#define dtyNormNoExt 6 /* Never written */
+
+#ifdef INTL /* international version */
+#define dtyWordDoc 6 /* when saving in Word format */
+#endif /* international version */
+
+#define dtyNetwork 7 /* Never written; smashed to dtyNormal */
+
+#define dtyAny 0
+
+
+struct DOD
+ { /* Document descriptor */
+ struct PCTB **hpctb; /* Piece table */
+ typeCP cpMac; /* Number of lexemes in doc */
+
+ unsigned fFormatted : 1; /* Default save is formatted */
+ unsigned fDirty : 1; /* Document has been edited */
+ unsigned fAbsLooks : 1; /* Absolute looks applied */
+ unsigned fBackup : 1; /* Make auto backup of file? */
+ unsigned fReadOnly: 1; /* Read only doc (no edits allowed)? */
+ unsigned fDisplayable : 1;
+ unsigned : 4;
+ unsigned dty : 2; /* Document type */
+ unsigned cref : 4; /* Reference count */
+
+ CHAR (**hszFile)[]; /* Document name */
+ struct FNTB **hfntb; /* Footnote table */
+#ifdef CASHMERE
+ struct SETB **hsetb; /* Section table */
+#else
+ struct SEP **hsep; /* Section properties */
+#endif
+ int docSsht; /* Style sheet if dty == dtySsht */
+ struct PGTB **hpgtb; /* Page table (for Jump Page) */
+ struct FFNTB **hffntb; /* font name table */
+
+ struct TBD (**hgtbd)[]; /* Table of tab stops */
+
+#ifdef SAND
+ int vref; /* Volume that this document is on */
+#endif /* SAND */
+ };
+
+#define cwDOD (sizeof (struct DOD) / sizeof (int))
+#define cbDOD (sizeof (struct DOD))
+
+struct FNTB **HfntbGet();
diff --git a/private/mvdm/wow16/write/doprm.c b/private/mvdm/wow16/write/doprm.c
new file mode 100644
index 000000000..6fbc4b036
--- /dev/null
+++ b/private/mvdm/wow16/write/doprm.c
@@ -0,0 +1,417 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* doprm.c -- MW Property modifying routines */
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSCOMMANDS
+#define NOCREATESTRUCT
+#define NOATOM
+#define NOMETAFILE
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOPEN
+#define NOBITMAP
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOMM
+#define NOMB
+#define NOMSG
+#define NOOPENFILE
+#define NORESOURCE
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "prmdefs.h"
+#include "fkpdefs.h"
+#include "docdefs.h"
+#include "macro.h"
+#include "dispdefs.h"
+#include "fontdefs.h"
+
+/* E X T E R N A L S */
+extern int rgxaRulerSprm[];
+extern struct PAP *vppapNormal;
+extern struct CHP vchpNormal;
+extern CHAR dnsprm[];
+extern struct CHP vchpNormal;
+extern struct SEP vsepStd;
+extern struct SEP vsepNormal;
+
+#ifdef CASHMERE
+extern struct TBD rgtbdRulerSprm[];
+#endif
+
+/* List of approved font sizes, in half points */
+#ifdef INTL
+int rghps[csizeApprovedMax] = {8, 12, 16, 20, 24, 28, 36, 48, 60, 72, 96, 144, 254};
+#else
+int rghps[csizeApprovedMax] = {8, 12, 16, 20, 24, 32, 40, 48, 60, 72, 96, 144, 254};
+#endif /* if-else-def INTL */
+
+CHAR *PchFromFc();
+
+
+/* D O P R M */
+DoPrm(struct CHP *pchp, struct PAP *ppap, struct PRM prm)
+ { /* Apply prm to char and para properties */
+ if (bPRMNIL(prm))
+ return;
+ if (((struct PRM *) &prm)->fComplex)
+ {
+ int cch;
+ CHAR *pfsprm;
+ struct FPRM *pfprm = (struct FPRM *) PchFromFc(fnScratch,
+ fcSCRATCHPRM(prm), &cch);
+
+ cch = pfprm->cch;
+ pfsprm = pfprm->grpfsprm;
+
+ while (cch > 0)
+ {
+ int cchT;
+ int sprm;
+
+ DoSprm(pchp, ppap, sprm = *pfsprm, pfsprm + 1);
+ if ((cchT = (dnsprm[sprm] & ESPRM_cch)) == 0)
+ cchT = CchPsprm(pfsprm);
+ cch -= cchT;
+ pfsprm += cchT;
+ }
+ }
+ else
+/* Simple prm; single sprm */
+ DoSprm(pchp, ppap, ((struct PRM *) &prm)->sprm,
+ &((struct PRM *) &prm)->val);
+}
+
+/* D O S P R M */
+/* Apply a single property modifier to para/char prop */
+DoSprm(pchp, ppap, sprm, pval)
+struct CHP *pchp;
+struct PAP *ppap;
+int sprm;
+CHAR *pval;
+ {
+ int *pvalTo;
+ int val = *pval;
+
+#ifdef DEBUG
+ Assert(sprm > 0 && sprm < sprmMax);
+#endif
+ if ((dnsprm[sprm] & ESPRM_sgc) != sgcChar)
+ {
+ if (ppap != 0)
+ {
+ struct TBD *ptbd;
+ int rhc;
+ int fGraphics;
+
+ ppap->fStyled = fFalse;
+ switch (sprm)
+ {
+ case sprmPLMarg:
+ pvalTo = &ppap->dxaLeft;
+ break;
+ case sprmPRMarg:
+ pvalTo = &ppap->dxaRight;
+ break;
+ case sprmPFIndent:
+ pvalTo = &ppap->dxaLeft1;
+ break;
+ case sprmPJc:
+ ppap->jc = val;
+ return;
+#ifdef CASHMERE
+ case sprmPRuler:
+/* Ruler and Ruler1 rely on the fact that rgxaRulerSprm and PAP both
+align R, L, L1 in that order.
+Ruler: apply the current state of the ruler */
+ blt(&rgxaRulerSprm[0], &ppap->dxaRight, 3);
+ blt(&rgtbdRulerSprm[0], ppap->rgtbd, itbdMax * cwTBD);
+ return;
+ case sprmPRuler1:
+/* as Ruler, except information is at pval+1 and pval+"7" */
+ bltbyte((CHAR *)(pval + 1), &ppap->dxaRight, 3 * cchINT);
+/* append terminating 0 word to tab table */
+ bltc(bltbyte((CHAR *)(pval + 1 + (3 * cchINT)), ppap->rgtbd,
+ val - (3 * cchINT)), 0, cchINT);
+ return;
+ case sprmPRgtbd:
+ bltc(bltbyte(pval + 1, ppap->rgtbd,
+ val), 0, cchINT);
+ return;
+ case sprmPKeep:
+ ppap->fKeep = val;
+ return;
+ case sprmPKeepFollow:
+ ppap->fKeepFollow = val;
+ return;
+#endif
+ case sprmPDyaLine:
+ pvalTo = &ppap->dyaLine;
+ break;
+#ifdef CASHMERE
+ case sprmPDyaBefore:
+ pvalTo = &ppap->dyaBefore;
+ break;
+ case sprmPDyaAfter:
+ pvalTo = &ppap->dyaAfter;
+ break;
+#endif
+ case sprmPRhc:
+ ppap->rhc = val;
+ return;
+ case sprmPRhcNorm:
+ /* (int) dxaLeftAdj + (int) dxaRightAdj */
+ Assert(*pval == 4);
+ pval++; /* skip over cch */
+ ppap->dxaLeft = imax( 0,
+ ppap->dxaLeft - *(int *) pval);
+ ppap->dxaRight = imax( 0,
+ ppap->dxaRight - *((int *) pval + 1));
+ return;
+ case sprmPNormal:
+ rhc = ppap->rhc;
+ fGraphics = ppap->fGraphics;
+ blt(vppapNormal, ppap, cwPAPBase);
+ goto LSame;
+ case sprmPSame:
+ rhc = ppap->rhc;
+ fGraphics = ppap->fGraphics;
+/* note: tab terminating 0 MUST be part of value if tab table is to be changed */
+ bltbyte(pval + 1, ppap, val - 1);
+LSame: ppap->rhc = rhc;
+ ppap->fGraphics = fGraphics;
+ return;
+#ifdef CASHMERE
+ case sprmPNest:
+ if (ppap->rgtbd[0].dxa != 0 &&
+ ppap->rgtbd[0].dxa == ppap->dxaLeft &&
+ ppap->rgtbd[1].dxa == 0)
+ ppap->rgtbd[0].dxa += dxaNest;
+ ppap->dxaLeft += dxaNest;
+ return;
+ case sprmPUnNest:
+ if (ppap->rgtbd[0].dxa != 0 &&
+ ppap->rgtbd[0].dxa == ppap->dxaLeft &&
+ ppap->rgtbd[1].dxa == 0)
+ ppap->rgtbd[0].dxa -= dxaNest;
+ ppap->dxaLeft = max(0, (int)(ppap->dxaLeft - dxaNest));
+ return;
+ case sprmPHang:
+ ppap->dxaLeft = umin(ppap->dxaLeft + cxaInch, xaRightMax - cxaInch);
+ ppap->dxaLeft1 = -cxaInch;
+ ptbd = &ppap->rgtbd[0];
+ SetWords(ptbd, 0, cwTBD * 2);
+ ptbd->dxa = ppap->dxaLeft;
+ /* Inefficient:
+ ptbd->tlc = tlcWhite;
+ ptbd->jc = jcLeft;
+ ++ptbd->dxa = 0 */
+ return;
+#endif
+ default:
+ Assert(FALSE);
+ return;
+ }
+ /* common portion for those transferring a single word */
+ bltbyte(pval, pvalTo, cchINT);
+ }
+ return;
+ }
+ else
+ {
+ if (pchp != 0)
+ {
+ int fSpecial;
+ int ftc, hps;
+
+ pchp->fStyled = fFalse;
+ switch (sprm)
+ {
+ /* CHARACTER sprm's */
+ case sprmCBold:
+ pchp->fBold = val;
+ return;
+ case sprmCItalic:
+ pchp->fItalic = val;
+ return;
+ case sprmCUline:
+ pchp->fUline = val;
+ return;
+#ifdef CASHMERE
+ case sprmCOutline:
+ pchp->fOutline = val;
+ return;
+ case sprmCShadow:
+ pchp->fShadow = val;
+ return;
+ case sprmCCsm:
+ pchp->csm = val;
+ return;
+#endif
+ case sprmCPos:
+ /* If going in or out of sub/superscript, alter font size */
+ if (pchp->hpsPos == 0 && val != 0)
+ pchp->hps = HpsAlter(pchp->hps, -1);
+ else if (pchp->hpsPos != 0 && val == 0)
+ pchp->hps = HpsAlter(pchp->hps, 1);
+ pchp->hpsPos = val;
+ return;
+ case sprmCFtc:
+ case sprmCChgFtc:
+ pchp->ftc = val & 0x003f;
+ pchp->ftcXtra = (val & 0x00c0) >> 6;
+ return;
+ case sprmCHps:
+ pchp->hps = val;
+ return;
+ case sprmCChgHps:
+ pchp->hps = HpsAlter(pchp->hps,
+ val >= 128 ? val - 256 : val); /* sign extend from char to int */
+ return;
+ case sprmCSame:
+ fSpecial = pchp->fSpecial;
+ bltbyte(pval, pchp, cchCHP);
+ pchp->fSpecial = fSpecial;
+ return;
+ case sprmCPlain:
+ fSpecial = pchp->fSpecial;
+ ftc = FtcFromPchp(pchp);
+ hps = pchp->hps;
+ /* If we used to be sub/superscript, increase font size */
+ if (pchp->hpsPos != 0)
+ hps = HpsAlter(hps, 1);
+ blt(&vchpNormal, pchp, cwCHP);
+ pchp->fSpecial = fSpecial;
+ pchp->ftc = ftc & 0x003f;
+ pchp->ftcXtra = (ftc & 0x00c0) >> 6;
+ pchp->hps = hps;
+ return;
+ case sprmCMapFtc:
+ /* val is ftcMac for mapping */
+ /* pval+1 points to ftcMac mapping bytes */
+ ftc = pchp->ftc + (pchp->ftcXtra << 6);
+ Assert(ftc < val);
+ ftc = *(pval + 1 + ftc);
+ pchp->ftc = ftc & 0x003f;
+ pchp->ftcXtra = (ftc & 0x00c0) >> 6;
+ return;
+ case sprmCOldFtc:
+ ftc = pchp->ftc + (pchp->ftcXtra << 6);
+ ftc = FtcMapOldFtc(ftc, pval);
+ pchp->ftc = ftc & 0x003f;
+ pchp->ftcXtra = (ftc & 0x00c0) >> 6;
+ return;
+ default:
+ Assert(FALSE);
+ return;
+ }
+ }
+ }
+}
+
+/* C C H P S P R M */
+/* returns length of sprm's that are of variable or large size.
+(cch = (esprm & ESPRM_cch)) == 0 must be checked before calling.*/
+CchPsprm(psprm)
+CHAR *psprm;
+{
+ return (*psprm == sprmCSame ? cchCHP + 1 :
+/* PSame, PRgtbd, PRuler1, CMapFtc, COldFtc: */
+ *(psprm + 1) + 2);
+}
+
+int HpsAlter(hps, ialter)
+int hps, ialter;
+{ /* Return the hps of the approved font size that is ialter steps
+ away from the given size. I.e.: if ialter is -1, then return
+ the next smaller size. If alter is 0, return hps. */
+ /* return 0 if request exceeds limits (11.15.91) v-dougk */
+int isize;
+
+if (ialter == 0)
+ return hps;
+
+/* Find the size just larger than the given size. */
+if (ialter > 0)
+ {
+ for (isize = 0; isize < csizeApprovedMax - 1; ++isize)
+ if (rghps[isize] > hps) break;
+ isize = min(csizeApprovedMax - 1, isize + ialter - 1);
+ return max(hps, rghps[isize]);
+ }
+else
+ {
+ for (isize = 0; isize < csizeApprovedMax; ++isize)
+ if (rghps[isize] >= hps) break;
+ isize = max(0, isize + ialter);
+ return min(hps, rghps[isize]);
+ }
+}
+
+BOOL CanChangeFont(int howmuch)
+{
+ extern struct CHP vchpSel;
+ extern struct SEL selCur;
+ int hps;
+
+ if (selCur.cpFirst != selCur.cpLim)
+ return TRUE;
+
+ hps = HpsAlter(vchpSel.hps, howmuch);
+ return ((hps <= rghps[csizeApprovedMax-1]) &&
+ (hps >= rghps[0]));
+}
+
+FtcMapOldFtc(ftc, ftctb)
+/* maps an old word font code into one of our selection */
+
+int ftc;
+CHAR *ftctb;
+{
+#ifdef WIN30
+int iftc = iftcSwiss; /* Default to SOMEthing! ..pault */
+#else
+int iftc ;
+#endif
+
+if (ftc == 8)
+ /* helvetica */
+ iftc = iftcSwiss;
+else if (ftc < 16)
+ iftc = iftcModern;
+else if (ftc < 32)
+ iftc = iftcRoman;
+else if (ftc < 40)
+ iftc = iftcScript;
+else if (ftc < 48)
+ iftc = iftcDecorative;
+Assert(iftc < *ftctb);
+return(*(ftctb + 1 + iftc));
+}
diff --git a/private/mvdm/wow16/write/doslib.asm b/private/mvdm/wow16/write/doslib.asm
new file mode 100644
index 000000000..b50161149
--- /dev/null
+++ b/private/mvdm/wow16/write/doslib.asm
@@ -0,0 +1,555 @@
+ TITLE doslib - DOS access library routines
+
+; Windows Write, Copyright 1985-1992 Microsoft Corporation
+; =====================================================================
+; This file contains DOS access routines.
+; These routines are general, simple calls to DOS and
+; are likely to be generally useful. They assume /PLM calling
+; is used.
+; FAR calls are used throughout
+;
+;
+; NOTE: DOSLIB.H CONTAINS A C HEADER DEFINING THE FUNCTIONS IN THIS
+; MODULE. IT MUST BE UPDATED WHENEVER A FUNCTION IS ADDED OR AN INTERFACE
+; CHANGES
+; =====================================================================
+
+
+; =====================================================================
+; cmacros2.inc is a special version of cmacros.inc in which the only
+; difference is that it defines the segment for assembly code to
+; be FILE_TEXT instead of _TEXT.
+; This is done so that functions in FILE.C will
+; not call intermodule and subject themselves to possible file closure
+; when calling DOS functions.
+; =====================================================================
+include cmacros2.inc
+
+sBegin DATA
+ifdef DEBUG
+EXTRN vfCommDebug:WORD
+endif
+sEnd DATA
+
+
+cchMaxFile EQU 128
+EXTRN ANSITOOEM:FAR
+
+sBegin CODE
+ assumes CS,CODE
+
+; ---------------------------------------------------------------------
+; int FAR CchCurSzPath( szPath, bDrive )
+; PSTR szPath;
+; int bDrive;
+;
+; Copy the current path name for the current drive into szPath
+; szPath must have 67 bytes of storage
+;
+; bDrive is 0=default, 1=A, 2=B,...
+;
+; Returned cch includes the terminating '\0'
+; Form of returned string is e.g. "C:\WINDOWS\BIN\" (0-terminated)
+; String is guaranteed to: (1) Include the drive letter, colon, and leading "\"
+; (2) End with a backslash
+;
+; 0 = an error occurred, nonzero = success
+; the path string will be NULL if an error occurred
+; An error should really not be possible, since the default drive ought to be
+; valid
+; ---------------------------------------------------------------------
+
+cProc CchCurSzPath, <FAR, PUBLIC>, <SI>
+parmDP <szPath>
+parmB <bDrive>
+cBegin CchCurSzPath
+
+ mov al,bDrive
+ mov dl,al
+ cmp al,0
+ jz cspDFLTDRV ; default drive
+ dec al
+ jmp cspGOTDRV ; not default drive
+
+cspDFLTDRV:
+ mov ah,19h ; Get current drive
+ int 21h
+
+ ; now we have al: 0=A, 1=B, ....
+ ; dl: 0=default, 1=A, 2=B
+
+cspGOTDRV: ; Put "X:\" at front of szPath
+ add al,'A'
+ mov si,szPath
+ mov [si],al
+ mov BYTE PTR [si+1],':'
+ mov BYTE PTR [si+2],'\' ; Leave si pointing at szPath
+
+ add si,3 ; Rest of path goes at SzPath+3
+ mov ah,47h
+ int 21h
+ mov si,szPath
+ jc cspERR ; error -- return negative of err code in AX
+
+ dec si ; Path was OK - find null terminator
+cspLOOP: inc si
+ cmp al,[si]
+ jnz cspLOOP
+
+ cmp BYTE PTR [si-1],'\' ; Append backslash if needed
+ jz cspSTROK ; not needed, string is already OK
+ mov BYTE PTR [si],'\'
+ inc si
+ mov BYTE PTR [si],0
+cspSTROK: ; now we are guaranteed a good string
+ mov ax,si ; determine string length
+ sub ax,szPath
+ inc ax
+ jmp cspRET
+
+cspERR: mov BYTE PTR [si],0 ; error -- NULL path string
+ neg ax
+cspRET:
+cEnd CchCurSzPath
+
+
+ifdef ENABLE
+;-----------------------------------------------------------------------------
+; DOSHND FAR WCreateNewSzFfname( szFfname, attrib )
+;
+; Create specified file, leave open for read/write, return handle
+; filename is an ffname, with drive and path. Uses the NEW
+; DOS 3.0 CREATE call which fails if the file exists. Caller has
+; responsibility for assuring DOS version number sufficiently high
+;
+; returned handle is negative if there was an error
+; the value will be the negative of the error code returned in AX
+;-----------------------------------------------------------------------------
+
+cProc WCreateNewSzFfname, <FAR, PUBLIC>
+parmDP <szFfname>
+parmW <attrib>
+cBegin WCreateNewSzFfname
+
+ mov dx,szFfname
+ mov cx,attrib
+ mov ah,5bh
+ int 21h
+ jnc cnsfdone
+ neg ax ; error - return the negative of the error code
+cnsfdone:
+cEnd WCreateNewSzFfname
+
+;-----------------------------------------------------------------------------
+; DOSHND FAR WCreateSzFfname( szFfname, attrib )
+;
+; Create specified file, leave open for read/write, return handle
+; filename is an ffname, with drive and path
+;
+; returned handle is negative if there was an error
+; the value will be the negative of the error code returned in AX
+;-----------------------------------------------------------------------------
+
+cProc WCreateSzFfname, <FAR, PUBLIC>
+parmDP <szFfname>
+parmW <attrib>
+cBegin WCreateSzFfname
+
+ mov dx,szFfname
+ mov cx,attrib
+ mov ah,3ch
+ int 21h
+ jnc csfdone
+ neg ax ; error - return the negative of the error code
+csfdone:
+cEnd WCreateSzFfname
+endif
+
+;-----------------------------------------------------------------------------
+; int DosxError()
+;
+; Return a DOS extended error code
+;-----------------------------------------------------------------------------
+
+cProc DosxError, <FAR, PUBLIC>
+cBegin DosxError
+ mov ah,59h
+ mov bx,0 ; bug fix, 10/2/86, BryanL
+ int 21h
+cEnd DosxError
+
+
+;-----------------------------------------------------------------------------
+; WORD WDosVersion()
+;
+; Return a word indicating DOS version, major in low 8 bits, minor in high 8
+;-----------------------------------------------------------------------------
+
+cProc WDosVersion, <FAR, PUBLIC>
+cBegin WDosVersion
+ mov ah,30h
+ int 21h
+cEnd WDosVersion
+
+
+;-----------------------------------------------------------------------------
+; WORD DaGetFileModeSz(sz)
+;
+; Return a word indicating attributes of file sz (EXPECTED IN ANSI);
+; 0xFFFF if it fails.
+;-----------------------------------------------------------------------------
+
+cProc DaGetFileModeSz, <FAR, PUBLIC>
+parmDP <sz>
+localV <szOem>,cchMaxFile
+
+cBegin DaGetFileModeSz
+ ; Convert filename from ANSI set to OEM Set
+
+ push ds
+ push sz
+ push ds
+ lea ax,szOem
+ push ax
+ call ANSITOOEM
+
+ lea dx,szOem
+ mov ax,4300h
+
+ int 21h
+ mov ax, cx
+ jnc daNoErr
+ mov ax, 0ffffh ; error -- return 0xFFFF
+daNoErr:
+cEnd DaGetFileModeSz
+
+; WRITE uses OpenFile instead
+ifdef ENABLE
+;-----------------------------------------------------------------------------
+; DOSHND FAR WOpenSzFfname( szFfname, openmode )
+;
+; Open specified file in specified mode, return a handle or
+; the negative of an error code if the open failed
+;-----------------------------------------------------------------------------
+
+cProc WOpenSzFfname, <FAR, PUBLIC>
+parmDP <szFfname>
+parmB <openmode>
+cBegin WOpenSzFfname
+
+ mov dx,szFfname
+ mov al,openmode
+ mov ah,3dh
+
+ int 21h
+ jnc osfdone
+ neg ax ; error - return the negative of the error code
+osfdone:
+cEnd WOpenSzFfname
+
+endif
+
+;-----------------------------------------------------------------------------
+; int FAR FCloseDoshnd( doshnd )
+;
+; Close file given DOS handle, return 0 = error, nonzero = no error
+;-----------------------------------------------------------------------------
+
+cProc FCloseDoshnd, <FAR, PUBLIC>
+parmW <doshnd>
+cBegin FCloseDoshnd
+
+ mov bx,doshnd
+ mov ah,3eh
+
+ int 21h
+ mov ax,0000
+ jc cdhskip ; error, leave a zero in ax
+ inc ax
+cdhskip:
+cEnd FCloseDoshnd
+
+;-----------------------------------------------------------------------------
+; int FAR FpeDeleteSzFfname( szFfname )
+;
+; Delete specified file, return < 0=failure, 0=success
+;-----------------------------------------------------------------------------
+
+cProc FpeDeleteSzFfname, <FAR, PUBLIC>
+parmDP <szFfname>
+
+localV <szOem>,cchMaxFile
+
+cBegin FpeDeleteSzFfname
+
+ ; Convert filename from ANSI set to OEM Set
+
+ push ds
+ push szFfname
+ push ds
+ lea ax,szOem
+ push ax
+ call ANSITOOEM
+
+ lea dx,szOem
+ mov ah,41h
+
+ int 21h
+ jc dsfskip ; error - return the negative of the error code
+ mov ax,0ffffh
+dsfskip:
+ neg ax
+cEnd FpeDeleteSzFfname
+
+;-----------------------------------------------------------------------------
+; int FAR FpeRenameSzFfname( szCur, szNew )
+;
+; Rename file szCur to szNew, return < 0=failure, 0=success
+;-----------------------------------------------------------------------------
+
+cProc FpeRenameSzFfname, <FAR, PUBLIC>, <ES,DI>
+parmDP <szCur>
+parmDP <szNew>
+
+localV <szCurOem>,cchMaxFile
+localV <szNewOem>,cchMaxFile
+
+cBegin FpeRenameSzFfname
+
+ ; Convert filenames to Oem char set
+
+ push ds
+ push szCur
+ push ds
+ lea ax,szCurOem
+ push ax
+ call ANSITOOEM
+ push ds
+ push szNew
+ push ds
+ lea ax, szNewOem
+ push ax
+ call ANSITOOEM
+
+ lea dx,szCurOem ; old filename in ds:dx
+ push ds ; new filename in es:di
+ pop es
+ lea di,szNewOem
+ mov ah,56h
+
+ int 21h
+ jc rnfskip ; error - return the negative of the error code
+ mov ax,0ffffh
+rnfskip:
+ neg ax
+cEnd FpeRenameSzFfname
+
+;-----------------------------------------------------------------------------
+; int CchReadDoshnd ( doshnd, lpchBuffer, bytes )
+;
+; Read bytes from an open file, place into buffer
+; Returns # of bytes read (should be == bytes unless EOF or error)
+; If an error occurs, returns the negative of the error code
+;-----------------------------------------------------------------------------
+
+cProc CchReadDoshnd, <FAR, PUBLIC>, <DS>
+parmW <doshnd>
+parmD <lpchBuffer>
+parmW <bytes>
+cBegin CchReadDoshnd
+
+ mov bx,doshnd
+ lds dx,lpchBuffer
+ mov cx,bytes
+ mov ah,3fh
+
+ int 21h
+ jnc crdone
+
+ neg ax ; error - return value is the negative of the error code
+crdone:
+cEnd CchReadDoshnd
+
+
+
+
+;-----------------------------------------------------------------------------
+; int CchWriteDoshnd ( doshnd, lpchBuffer, bytes )
+;
+; Write bytes from an open file, place into buffer
+; Returns # of bytes read (should be == bytes unless EOF or error)
+; If an error occurs, returns the negative of the error code
+; Disk full is not an "error"; detect it by return code != bytes
+;-----------------------------------------------------------------------------
+
+cProc CchWriteDoshnd, <FAR, PUBLIC>,<DS>
+parmW <doshnd>
+parmD <lpchBuffer>
+parmW <bytes>
+cBegin CchWriteDoshnd
+
+ mov bx,doshnd
+ lds dx,lpchBuffer
+ mov cx,bytes
+ mov ah,40h
+
+ int 21h
+ jnc cwdone
+
+ neg ax ; error: return the negative of the error code
+cwdone:
+
+cEnd CchWriteDoshnd
+
+
+
+
+;-----------------------------------------------------------------------------
+; long DwSeekDw ( doshnd, dwSeekpos, bSeekfrom )
+;
+; Seek to requested position in file
+; bSeekfrom is: 0 = seek relative to beginning of file
+; 1 = seek relative to current pointer location
+; 2 = seek relative to end of file
+;
+; Returns the new location of the read/write pointer (a long)
+; If an error occurs, returns the negative of the error code (long)
+;-----------------------------------------------------------------------------
+
+cProc DwSeekDw, <FAR, PUBLIC>
+parmW <doshnd>
+parmD <dwSeekpos>
+parmB <bSeekfrom>
+cBegin DwSeekDw
+
+ mov bx,doshnd
+ mov cx,SEG_dwSeekpos
+ mov dx,OFF_dwSeekpos
+ mov al,bSeekfrom
+ mov ah,42h
+
+ int 21h
+ jnc seekdone
+
+ neg ax ; Error: return the negative of the error code
+ mov dx,0ffffH
+
+seekdone:
+
+cEnd DwSeekDw
+
+
+; WRITE does not use these currently
+
+ifdef ENABLE
+;-----------------------------------------------------------------------------
+; int FAR FFirst(pb, szFileSpec, attrib)
+; Get first directory entry, place in buffer at pb. (buffer must contain
+; 43 bytes of storage)
+; attrib specifies attribute per MSDOS spec.
+; szFileSpec is filename specification
+; Returns 0=no error, nonzero = error
+;-----------------------------------------------------------------------------
+
+cProc FFirst, <FAR, PUBLIC>, <SI, DI>
+parmDP <pb, szFileSpec>
+parmW <attrib>
+cBegin FFirst
+
+ mov dx,pb ; set dta to pb
+ mov ah,1ah
+ int 21h
+
+ mov cx,attrib ; get first directory record, place in *pb
+ mov dx,szFileSpec
+ mov ah,4eh
+ int 21h
+ jc ffdone
+ xor ax,ax
+
+ffdone:
+cEnd FFirst
+
+
+;-----------------------------------------------------------------------------
+; int FAR FNext(pb)
+; Get next directory entry, place in buffer at pb.
+; Return 0= found match OK, nonzero = error or no more matches
+;-----------------------------------------------------------------------------
+
+cProc FNext, <FAR, PUBLIC>, <SI, DI>
+parmDP <pb>
+cBegin FFirst
+
+ mov dx,pb ; set dta to pb
+ mov ah,1ah
+ int 21h
+
+ mov ah,4fh
+ int 21h
+ jc fndone
+ xor ax,ax
+
+fndone:
+cEnd FNext
+
+endif
+
+ifdef OLDDEBUG
+ /* This method isn't quite working under Win 3.0 ..pault */
+;-----------------------------------------------------------------------------
+; void CommSz( sz ) - put out string to AUX device
+;
+; For debugging
+;-----------------------------------------------------------------------------
+
+cProc CommSz, <FAR, PUBLIC>
+parmDP <sz>
+cBegin CommSz
+
+CommSz1:
+ mov bx, sz ; if ((dl = *(sz++)) == 0) goto CommSz2
+ inc sz
+ mov dl, [bx]
+ cmp dl, 0
+ jz CommSz2
+
+ call DebugOutput ; Output dl to AUX or LPT device
+
+ jmp CommSz1
+
+CommSz2:
+
+cEnd CommSz
+
+;-----------------------------------------------------------------------------
+; static void DebugOutput - put character to AUX or LPT device
+; if (vfCommDebug)
+; output to AUX port
+; else output to LPT port
+; input: dl = character
+; output: none. Uses ah
+;
+;-----------------------------------------------------------------------------
+
+ assumes ds,DATA
+DebugOutput PROC NEAR
+
+ mov ah,4 ; Assume AUX device
+ test vfCommDebug,0ffh
+ jnz DebugOut1
+ inc ah ; Change to LPT device
+DebugOut1:
+ int 21h ; Output character
+ ret
+
+DebugOutput ENDP
+
+endif ;DEBUG
+
+sEnd CODE
+
+
+
+ END
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/doslib.h b/private/mvdm/wow16/write/doslib.h
new file mode 100644
index 000000000..bc5f48554
--- /dev/null
+++ b/private/mvdm/wow16/write/doslib.h
@@ -0,0 +1,94 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Include file with headers for functions in DOSLIB.ASM */
+
+typedef unsigned DOSHND; /* DOS handle */
+typedef DOSHND typeOSFN; /* General WRITE type for OS file handle */
+struct TIM { /* Time structure returned by OsTime */
+ CHAR minutes, hour, hsec, sec;
+ };
+
+int CchCurSzPath( CHAR *, CHAR );
+
+#ifdef ENABLE /* We are not currently using these */
+int FFirst( CHAR near *, PSTR, int );
+int FNext( CHAR near * );
+DOSHND WOpenSzFfname( CHAR *, int );
+#endif
+
+WORD DaGetFileModeSz(CHAR *);
+void OsTime( struct TIM * ); /* NOTE: function moved to lib.asm */
+DOSHND WCreateNewSzFfname( CHAR *, int );
+DOSHND WCreateSzFfname( CHAR *, int );
+int CchReadDoshnd( DOSHND, CHAR FAR *, int );
+int CchWriteDoshnd( DOSHND, CHAR FAR *, int );
+int FCloseDoshnd( DOSHND );
+WORD WDosVersion( void );
+int DosxError( void );
+long DwSeekDw( DOSHND, long, int );
+int FpeDeleteSzFfname( CHAR * );
+int FpeRenameSzFfname( CHAR *, CHAR * );
+
+
+#define DA_NORMAL 0x00 /* DOS File Attribute */
+#define DA_READONLY 0x01 /* DOS File Attribute for read-only file */
+#define DA_NIL 0xFFFF /* Error DA */
+#define dosxSharing 32 /* Extended error code for sharing viol. */
+#define nErrNoAcc 5 /* OpenFile error code for Access Denied */
+#define nErrFnf 2 /* OpenFile error code for File Not Found */
+#define bSHARE_DENYRDWR 0x10 /* Sharing Open mode for exclusive use */
+
+/* Error condition returned by "CCH" returning DOS functions, e.g. read */
+
+#define FIsErrCchDisk(cch) ((int)(cch) < 0)
+
+#define cchDiskHardError -1 /* Bogus error code, not returned by DOS */
+#define fpeHardError -1 /* also */
+
+/* Error condition returned by functions that return DOS handles */
+
+#define FIsErrDoshnd(doshnd) ((int)(doshnd) < 0)
+
+/* DOS Error codes */
+/* These are the negative of the codes returned in AX by DOS functions */
+#define fpeFnfError -2 /* File Not Found */
+#define fpeBadPathError -3 /* Bad Path (path not found) */
+#define fpeNoHndError -4 /* No Handles Available */
+#define fpeNoAccError -5 /* Access Denied */
+#define fpeBadHndError -6 /* Bad handle passed in */
+#define fpeNoDriveError -15 /* Non-existent drive passed in */
+#define fpeExistError -80 /* File exists */
+
+/* Seek-from type codes passed to DOS function 42H */
+
+#define SF_BEGINNING 0 /* Seek from beginning of file */
+#define SF_CURRENT 1 /* Seek from current file pointer */
+#define SF_END 2 /* Seek from end of file */
+
+/* Error test for seek position */
+
+#define FIsErrDwSeek(dw) ((long)(dw) < (long)0)
+
+/* Error test for fpe-returning functions */
+
+#define FIsErrFpe(fpe) ((int)(fpe) < 0)
+
+/* Tests whether an error is a hardware error. Hardware errors are caught
+ and prompted for by Windows, so we should not duplicate those prompts.
+ Chrisp says these DOS 3.0 error codes are generated by Windows for all
+ supported versions of DOS
+ fpe is WRITE's error type; ofe is the unadulturated error returned by
+ DOS or OpenFile */
+
+#define ofeCaughtFirst 19
+#define ofeCaughtLast 27
+
+#define FIsCaughtOfe(ofe) (((ofe)>=ofeCaughtFirst)&&((ofe)<=ofeCaughtLast))
+#define FIsCaughtFpe(fpe) FIsCaughtOfe(-(fpe))
+#define FIsCaughtDwSeekErr(dw) FIsCaughtFpe((int)(dw))
+
+#define FpeFromCchDisk(cch) (cch)
+
+#define fpeNoErr 0
diff --git a/private/mvdm/wow16/write/double.bms b/private/mvdm/wow16/write/double.bms
new file mode 100644
index 000000000..f983f4a9f
--- /dev/null
+++ b/private/mvdm/wow16/write/double.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/dtabbtn.bms b/private/mvdm/wow16/write/dtabbtn.bms
new file mode 100644
index 000000000..4a511772c
--- /dev/null
+++ b/private/mvdm/wow16/write/dtabbtn.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/dtabmark.bms b/private/mvdm/wow16/write/dtabmark.bms
new file mode 100644
index 000000000..a5c408a67
--- /dev/null
+++ b/private/mvdm/wow16/write/dtabmark.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/edit.c b/private/mvdm/wow16/write/edit.c
new file mode 100644
index 000000000..318db0ecd
--- /dev/null
+++ b/private/mvdm/wow16/write/edit.c
@@ -0,0 +1,1278 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* edit.c -- MW editing routines */
+
+#define NOVIRTUALKEYCODES
+#define NOCTLMGR
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+//#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "debug.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+#include "editdefs.h"
+#include "str.h"
+#include "prmdefs.h"
+#include "printdef.h"
+#include "fontdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+/* E X T E R N A L S */
+extern int vfOutOfMemory;
+extern struct DOD (**hpdocdod)[];
+extern typeCP vcpFirstSectCache;
+extern struct UAB vuab;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int docCur;
+extern struct WWD rgwwd[];
+extern int wwMac;
+extern int wwCur;
+extern typeCP vcpLimSectCache;
+/*extern int idstrUndoBase;*/
+extern int docScrap;
+extern int docUndo;
+extern int vfSeeSel;
+extern struct PAP vpapAbs;
+extern int vfPictSel;
+extern int ferror;
+
+/* the following used to be defined here */
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+/* this is a global parameter to AdjustCp; if false, no invalidation will
+take place */
+extern BOOL vfInvalid;
+
+#ifdef ENABLE
+extern struct SEL selRulerSprm;
+#endif
+
+extern int docRulerSprm;
+extern struct EDL *vpedlAdjustCp;
+
+struct PCD *PpcdOpen();
+
+
+
+
+/* R E P L A C E */
+Replace(doc, cp, dcp, fn, fc, dfc)
+int doc, fn;
+typeCP cp, dcp;
+typeFC fc, dfc;
+{ /* Replace cp through (cp+dcp-1) in doc by fc through (fc+dfc-1) in fn */
+
+ if (ferror) return;
+#ifdef ENABLE
+ if (docRulerSprm != docNil) ClearRulerSprm();
+#endif
+ /* if (fn == fnNil) we are infact deleting text by replacing text
+ with nil. Thus, the memory space check is unnecessary.*/
+#ifdef BOGUS /* No longer have cwHeapFree available */
+ if ((fn != fnNil) && (cwHeapFree < 3 * cpcdMaxIncr * cwPCD))
+ {
+#ifdef DEBUG
+ ErrorWithMsg(IDPMTNoMemory, " edit#1");
+#else
+ Error(IDPMTNoMemory);
+#endif
+ return;
+ }
+#else
+ if (vfOutOfMemory)
+ {
+ ferror = 1;
+ return;
+ }
+#endif
+
+ if (dcp != cp0)
+ {
+ AdjParas(doc, cp, doc, cp, dcp, fTrue); /* Check for del EOL */
+ DelFtns(doc, cp, cp + dcp); /* Delete any footnotes */
+ }
+
+ Repl1(doc, cp, dcp, fn, fc, dfc);
+ if (ferror)
+ return;
+ AdjustCp(doc, cp, dcp, dfc);
+
+ /* Special kludge for graphics paragraphs */
+ if (dfc != dcp)
+ CheckGraphic(doc, cp + dfc);
+
+}
+
+
+
+
+/* C H E C K G R A P H I C */
+CheckGraphic(doc, cp)
+int doc; typeCP cp;
+{
+#if defined(OLE)
+extern BOOL bNoEol;
+#endif
+
+#ifdef CASHMERE /* No docBuffer in MEMO */
+extern int docBuffer; /* Don't need extra paragraph mark in txb document */
+ if (cp == ((**hpdocdod)[doc]).cpMac || doc == docBuffer)
+ return;
+#else
+ if (cp == ((**hpdocdod)[doc]).cpMac)
+ return;
+ CachePara(doc, cp);
+ /* !!! this has a bug. There are cases when you don't want to insert
+ EOL. Ex1: place cursor in front of bitmap and press
+ backspace. Ex2: OleSaveObjectToDoc deletes an object and
+ insert new one (Eol gets inserted too). (4.10.91) v-dougk
+ */
+ if (vpapAbs.fGraphics && vcpFirstParaCache != cp)
+#if defined(OLE)
+ if (!bNoEol)
+#endif
+ InsertEolInsert(doc, cp);
+#endif
+}
+
+
+
+
+int IpcdSplit(hpctb, cp)
+struct PCTB **hpctb;
+typeCP cp;
+{ /* Ensure cp is the beginning of a piece. Return index of that piece.
+ return ipcdNil on error (extern int ferror will be set in that case) */
+register struct PCD *ppcd = &(**hpctb).rgpcd[IpcdFromCp(*hpctb, cp)];
+typeCP dcp = cp - ppcd->cpMin;
+
+if (dcp != cp0)
+ {
+ ppcd = PpcdOpen(hpctb, ppcd + 1, 1); /* Insert a new piece */
+ if (ppcd == NULL)
+ return ipcdNil;
+ ppcd->cpMin = cp;
+ ppcd->fn = (ppcd - 1)->fn;
+ ppcd->fc = (ppcd - 1)->fc + dcp;
+ ppcd->prm = (ppcd - 1)->prm;
+ ppcd->fNoParaLast = (ppcd - 1)->fNoParaLast;
+ }
+/* NOTE CASTS: For piece tables with rgpcd > 32Kbytes */
+/* return ppcd - (*hpctb)->rgpcd; */
+
+return ((unsigned)ppcd - (unsigned)((*hpctb)->rgpcd)) / sizeof (struct PCD);
+}
+
+
+
+
+/* P P C D O P E N */
+struct PCD *PpcdOpen(hpctb, ppcd, cpcd)
+struct PCTB **hpctb;
+struct PCD *ppcd;
+int cpcd;
+{ /* Insert or delete cpcd pieces */
+register struct PCTB *ppctb = *hpctb;
+
+/* NOTE CASTS: For piece tables with rgpcd > 32Kbytes */
+/* int ipcd = ppcd - ppctb->rgpcd; */
+int ipcd = ((unsigned)ppcd - (unsigned)(ppctb->rgpcd)) / sizeof (struct PCD);
+int ipcdMac, ipcdMax;
+
+ipcdMac = ppctb->ipcdMac + cpcd;
+ipcdMax = ppctb->ipcdMax;
+
+if (cpcd > 0)
+ { /* Inserting pieces; check for pctb too small */
+ if (ipcdMac > ipcdMax)
+ { /* Enlarge piece table */
+ int cpcdIncr = umin(cpcdMaxIncr, ipcdMac / cpcdChunk);
+
+ if (!FChngSizeH((int **) hpctb, (int) (cwPCTBInit + cwPCD *
+ ((ipcdMax = ipcdMac + cpcdIncr) - cpcdInit)), false))
+ {
+#ifdef DEBUG
+ ErrorWithMsg(IDPMTNoMemory, " edit#3");
+#else
+ Error(IDPMTNoMemory);
+#endif
+ return (struct PCD *)NULL;
+ }
+
+ /* Successfully expanded piece table */
+
+ ppctb = *hpctb;
+ ppcd = &ppctb->rgpcd [ipcd];
+ ppctb->ipcdMax = ipcdMax;
+ }
+ ppctb->ipcdMac = ipcdMac;
+ blt(ppcd, ppcd + cpcd, cwPCD * (ipcdMac - (ipcd + cpcd)));
+ }
+else if (cpcd < 0)
+ { /* Deleting pieces; check for pctb obscenely large */
+ ppctb->ipcdMac = ipcdMac;
+ blt(ppcd - cpcd, ppcd, cwPCD * (ipcdMac - ipcd));
+ if (ipcdMax > cpcdInit && ipcdMac * 2 < ipcdMax)
+ { /* Shrink piece table */
+#ifdef DEBUG
+ int f =
+#endif
+ FChngSizeH((int **) hpctb, (int) (cwPCTBInit + cwPCD *
+ ((ppctb->ipcdMax = umax(cpcdInit,
+ ipcdMac + ipcdMac / cpcdChunk)) - cpcdInit)), true);
+
+ Assert( f );
+
+ return &(**hpctb).rgpcd[ipcd];
+ }
+ }
+return ppcd;
+}
+
+
+
+
+/* R E P L 1 */
+/* core of replace except for checking and Adjust */
+Repl1(doc, cp, dcp, fn, fc, dfc)
+int doc, fn;
+typeCP cp, dcp;
+typeFC fc, dfc;
+{ /* Replace pieces with an optional new piece */
+ struct PCTB **hpctb;
+ int ipcdFirst;
+ int cpcd;
+ typeCP dcpAdj = dfc - dcp;
+ register struct PCD *ppcd;
+ struct PCD *ppcdMac;
+ struct PCTB *ppctb;
+ struct PCD *ppcdPrev;
+ struct PCD *ppcdLim=NULL;
+
+ hpctb = (**hpdocdod)[doc].hpctb;
+ ipcdFirst = IpcdSplit(hpctb, cp);
+
+ if (dcp == cp0)
+ cpcd = 0;
+ else
+ cpcd = IpcdSplit( hpctb, cp + dcp ) - ipcdFirst;
+
+ if (ferror)
+ return;
+
+ ppctb = *hpctb;
+ ppcdPrev = &ppctb->rgpcd[ipcdFirst - 1];
+
+ if ( dfc == fc0 ||
+ (ipcdFirst > 0 && ppcdPrev->fn == fn && bPRMNIL(ppcdPrev->prm) &&
+ ppcdPrev->fc + (cp - ppcdPrev->cpMin) == fc) ||
+ ((ppcdLim=ppcdPrev + (cpcd + 1))->fn == fn &&
+ bPRMNIL(ppcdLim->prm) && (ppcdLim->fc == fc + dfc)))
+ { /* Cases: (1) No insertion,
+ (2) Insertion is appended to previous piece
+ (3) Insertion is prepended to this piece */
+
+ ppcd = PpcdOpen( hpctb, ppcdPrev + 1, -cpcd );
+ if (ppcd == NULL)
+ return;
+
+ if (dfc != fc0)
+ { /* Cases 2 & 3 */
+ if (ppcdLim != NULL)
+ /* Case 3 */
+ (ppcd++)->fc = fc;
+
+ /* If extending, say we might have inserted EOL */
+ (ppcd - 1)->fNoParaLast = false;
+ }
+ }
+ else
+ { /* Insertion */
+ ppcd = PpcdOpen( hpctb, ppcdPrev + 1, 1 - cpcd );
+ if (ppcd == NULL)
+ return;
+ ppcd->cpMin = cp;
+ ppcd->fn = fn;
+ ppcd->fc = fc;
+ SETPRMNIL(ppcd->prm);
+ ppcd->fNoParaLast = false; /* Don't know yet */
+ ++ppcd;
+ }
+ ppcdMac = &(*hpctb)->rgpcd[(*hpctb)->ipcdMac];
+ if (dcpAdj !=0)
+ while (ppcd < ppcdMac)
+ (ppcd++)->cpMin += dcpAdj;
+}
+
+
+
+
+/* A D J U S T C P */
+/* note global parameter vfInvalid */
+/* sets global vpedlAdjustCp to pedl of line containing cpFirst, if any */
+AdjustCp(doc, cpFirst, dcpDel, dcpIns)
+int doc;
+typeCP cpFirst, dcpDel, dcpIns;
+{
+ /* Adjust all cp references in doc to conform to the deletion of
+ dcpDel chars and the insertion of dcpIns chars at cpFirst.
+ Mark display lines (dl's) dirty for all lines in all windows
+ displaying doc that are affected by the insertion & deletion
+ */
+extern int vdocBitmapCache;
+extern typeCP vcpBitmapCache;
+int ww;
+typeCP cpLim = cpFirst + dcpDel;
+typeCP dcpAdj = dcpIns - dcpDel;
+#ifdef DEBUG
+Scribble(2,'A');
+#endif
+
+{ /* Range in which pdod belongs in a register */
+register struct DOD *pdod = &(**hpdocdod)[doc];
+
+#ifdef STYLES
+/* If inserting or deleting in style sheet, invalidates rest of doc */
+if (pdod->dty == dtySsht && dcpAdj != cp0)
+ cpLim = pdod->cpMac;
+#endif
+pdod->cpMac += dcpAdj;
+/* Change for sand to support separate footnote windows: Make sure that edit
+ was within the current cpMacCur */
+/* note <= (CS) */
+if (doc == docCur && cpFirst <= cpMacCur)
+ cpMacCur += dcpAdj;
+
+#ifdef STYLES
+if (dcpAdj != cp0 && pdod->dty != dtySsht)
+#else
+if (dcpAdj != cp0)
+#endif
+ {
+#ifdef FOOTNOTES
+ if (pdod->hfntb != 0)
+ { /* Adjust footnotes */
+ struct FNTB *pfntb = *pdod->hfntb;
+ int cfnd = pfntb->cfnd;
+ struct FND *pfnd = &pfntb->rgfnd[cfnd];
+ AdjRg(pfnd, cchFND, bcpRefFND, cfnd, cpFirst, dcpAdj);
+ AdjRg(pfnd, cchFND, bcpFtnFND, cfnd, cpFirst + 1, dcpAdj);
+ }
+#endif
+#ifdef CASHMERE
+ if (pdod->hsetb != 0)
+ { /* Adjust sections */
+ struct SETB *psetb = *pdod->hsetb;
+ int csed = psetb->csed;
+ AdjRg(&psetb->rgsed[csed], cchSED, bcpSED, csed, cpFirst + 1,
+ dcpAdj);
+ }
+#endif
+ if (pdod->dty == dtyNormal && pdod->hpgtb != 0)
+ { /* Adjust page table */
+ struct PGTB *ppgtb = *pdod->hpgtb;
+ int cpgd = ppgtb->cpgd;
+ AdjRg(&ppgtb->rgpgd[cpgd], cchPGD, bcpPGD, cpgd, cpFirst + 1,
+ dcpAdj);
+ }
+ }
+
+#ifdef ENABLE
+/* invalidate selection which contains the sprm Ruler1. When AdjustCp is
+called in behalf of DragTabs, this invalidation will be undone by the caller
+*/
+if (doc == docRulerSprm && cpFirst >= selRulerSprm.cpFirst)
+ docRulerSprm = docNil;
+#endif
+} /* End of pdod belongs in a register */
+
+/* Adjust or invalidate bitmap cache as appropriate */
+
+if (doc == vdocBitmapCache)
+ {
+ if (vcpBitmapCache >= cpFirst)
+ {
+ if (vcpBitmapCache < cpFirst + dcpDel)
+ FreeBitmapCache();
+ else
+ vcpBitmapCache += dcpAdj;
+ }
+ }
+
+for (ww = 0; ww < wwMac; ww++)
+ {
+ register struct WWD *pwwd;
+ if ((pwwd = &rgwwd[ww])->doc == doc)
+ { /* This window may be affected */
+ int dlFirst = 0;
+ int dlLim = pwwd->dlMac;
+ struct EDL *pedlFirst;
+ struct EDL *pedlLast;
+ register struct EDL *pedl;
+ typeCP cpFirstWw = pwwd->cpFirst;
+ struct SEL *psel = (ww == wwCur) ? &selCur : &pwwd->sel;
+
+ if (pwwd->cpMac >= cpLim)
+ {
+ pwwd->cpMac += dcpAdj;
+ if (pwwd->cpMin > cpLim || pwwd->cpMac < pwwd->cpMin)
+ {
+ pwwd->cpMin += dcpAdj;
+ if (ww == wwCur)
+ cpMinCur = pwwd->cpMin;
+ }
+ }
+
+#ifndef BOGUSCS
+ if (dcpAdj != cp0 && psel->cpLim >= cpFirst)
+#else
+ if (dcpAdj != cp0 && psel->cpLim > cpFirst)
+#endif
+ { /* Adjust selection */
+ if (psel->cpFirst >= cpLim)
+ { /* Whole sel is after edit */
+ psel->cpFirst += dcpAdj;
+ psel->cpLim += dcpAdj;
+ }
+ else
+ { /* Part of sel is in edit */
+ typeCP cpLimNew = (dcpIns == 0) ?
+ CpFirstSty( cpFirst, styChar ) :
+ cpFirst + dcpIns;
+#ifdef BOGUSCS
+ if (ww == wwCur)
+ TurnOffSel();
+#endif
+ psel->cpFirst = cpFirst;
+ psel->cpLim = cpLimNew;
+ }
+ }
+
+ pedlFirst = &(**(pwwd->hdndl))[0];
+ pedl = pedlLast = &pedlFirst[ dlLim - 1];
+
+ while (pedl >= pedlFirst && (pedl->cpMin > cpLim
+ /* || (dcpAdj < 0 && pedl->cpMin == cpLim) */))
+ { /* Adjust dl's after edit */
+ pedl->cpMin += dcpAdj;
+ pedl--;
+ }
+
+ /* Invalidate dl's containing edit */
+ while (pedl >= pedlFirst && (pedl->cpMin + pedl->dcpMac > cpFirst ||
+ (pedl->cpMin + pedl->dcpMac == cpFirst && pedl->fIchCpIncr)))
+ {
+ if (vfInvalid)
+ pedl->fValid = false;
+ if (ww == wwCur) vpedlAdjustCp = pedl;
+ pedl--;
+ }
+
+ if (pedl == pedlLast)
+ continue; /* Entire edit below ww */
+
+ if (vfInvalid)
+ pwwd->fDirty = fTrue; /* Say ww needs updating */
+
+ if (pedl < pedlFirst)
+ { /* Check for possible cpFirstWw change */
+ if (cpFirstWw > cpLim) /* Edit above ww */
+ pwwd->cpFirst = cpFirstWw + dcpAdj;
+ else if (cpFirstWw + pwwd->dcpDepend > cpFirst)
+ /* Edit includes hot spot at top of ww */
+ {
+ if (cpFirst + dcpIns < cpFirstWw)
+ {
+ pwwd->cpFirst = cpFirst;
+ pwwd->ichCpFirst = 0;
+ }
+ }
+ else /* Edit doesn't affect cpFirstWw */
+ continue;
+
+ pwwd->fCpBad = true; /* Say cpFirst inaccurate */
+ DirtyCache(cpFirst); /* Say cache inaccurate */
+ }
+ else do
+ { /* Invalidate previous line if necessary */
+ if (pedl->cpMin + pedl->dcpMac + pedl->dcpDepend > cpFirst)
+ {
+ pedl->fValid = fFalse;
+ pwwd->fDirty = fTrue;
+ }
+ else
+ break;
+ } while (pedl-- > pedlFirst);
+ }
+ } /* end for */
+
+#if defined(OLE)
+ ObjAdjustCps(doc,cpLim,dcpAdj);
+#endif
+
+ InvalidateCaches(doc);
+ Scribble(2,' ');
+}
+
+
+
+
+ReplaceCps(docDest, cpDel, dcpDel, docSrc, cpIns, dcpIns)
+int docDest, docSrc;
+typeCP cpDel, dcpDel, cpIns, dcpIns;
+{ /* General replace routine */
+/* Replace dcpDel cp's starting at cpDel in docDest with
+ dcpIns cp's starting at cpIns in docSrc. */
+register struct PCTB **hpctbDest;
+struct PCTB **hpctbSrc;
+int ipcdFirst, ipcdLim, ipcdInsFirst, ipcdInsLast;
+register struct PCD *ppcdDest;
+struct PCD *ppcdIns, *ppcdMac;
+typeCP dcpFile, dcpAdj;
+int cpcd;
+
+if (ferror) return;
+#ifdef ENABLE
+if (docRulerSprm != docNil) ClearRulerSprm();
+#endif
+
+if (dcpIns == cp0) /* This is just too easy . . . */
+ {
+ Replace(docDest, cpDel, dcpDel, fnNil, fc0, fc0);
+ return;
+ }
+
+#ifdef DEBUG
+Assert(docDest != docSrc);
+#endif /* DEBUG */
+
+/* Keep the heap handles, because IpcdSplit & PpcdOpen move heap */
+hpctbDest = (**hpdocdod)[docDest].hpctb;
+hpctbSrc = (**hpdocdod)[docSrc].hpctb;
+
+/* Get the first and last pieces for insertion */
+ipcdInsFirst = IpcdFromCp(*hpctbSrc, cpIns);
+ipcdInsLast = IpcdFromCp(*hpctbSrc, cpIns + dcpIns - 1);
+
+#ifdef BOGUS /* No longer have cwHeapFree */
+if (cwHeapFree < (ipcdInsLast - ipcdInsFirst + cpcdMaxIncr + 1) * cwPCD + 10)
+ {
+#ifdef DEBUG
+ ErrorWithMsg(IDPMTNoMemory, " edit#2");
+#else
+ Error(IDPMTNoMemory);
+#endif
+ return;
+ }
+#else
+if (vfOutOfMemory)
+ {
+ ferror = TRUE;
+ return;
+ }
+#endif
+
+if (docDest == docCur)
+ HideSel(); /* Take down sel before we mess with cp's */
+
+if (dcpDel != cp0)
+ { /* Check for deleting EOL */
+ AdjParas(docDest, cpDel, docDest, cpDel, dcpDel, fTrue);
+ DelFtns(docDest, cpDel, cpDel + dcpDel); /* Remove footnotes */
+ }
+
+if (dcpIns != cp0)
+ AdjParas(docDest, cpDel, docSrc, cpIns, dcpIns, fFalse);
+
+/* Get the limiting pieces for deletion (indices because hp moves ) */
+ipcdFirst = IpcdSplit(hpctbDest, cpDel);
+ipcdLim = (dcpDel == cp0) ? ipcdFirst : IpcdSplit(hpctbDest, cpDel + dcpDel);
+if (ferror)
+ return;
+
+/* Adjust pctb size; get pointer to the first new piece, ppcdDest, and to the
+ first piece we are inserting. No more heap movement! */
+ppcdDest = PpcdOpen(hpctbDest, &(**hpctbDest).rgpcd[ipcdFirst],
+ ipcdFirst - ipcdLim + ipcdInsLast - ipcdInsFirst + 1);
+ppcdIns = &(**hpctbSrc).rgpcd[ipcdInsFirst];
+
+if (ferror)
+ /* Ran out of memory expanding piece table */
+ return;
+
+/* Fill first new piece */
+blt(ppcdIns, ppcdDest, cwPCD);
+ppcdDest->cpMin = cpDel;
+ppcdDest->fc += (cpIns - ppcdIns->cpMin);
+
+dcpFile = cpDel - cpIns;
+dcpAdj = dcpIns - dcpDel;
+
+/* Fill in rest of inserted pieces */
+if ((cpcd = ipcdInsLast - ipcdInsFirst) != 0)
+ {
+ blt((ppcdIns + 1), (ppcdDest + 1), cwPCD * cpcd);
+ while (cpcd--)
+ (++ppcdDest)->cpMin += dcpFile;
+ }
+
+/* Adjust rest of pieces in destination doc */
+ppcdMac = &(**hpctbDest).rgpcd[(**hpctbDest).ipcdMac];
+while (++ppcdDest < ppcdMac)
+ ppcdDest->cpMin += dcpAdj;
+#ifdef DEBUG
+/* ShowDocPcd("From ReplaceCps: ", docDest); */
+#endif
+
+/* And inform anyone else who cares */
+AdjustCp(docDest, cpDel, dcpDel, dcpIns);
+/* Copy any footnotes along with their reference marks */
+
+#ifdef FOOTNOTES
+{
+/* If there are any footnotes call AddFtns */
+struct FNTB **hfntbSrc;
+if ((hfntbSrc = HfntbGet(docSrc)) != 0)
+ AddFtns(docDest, cpDel, docSrc, cpIns, cpIns + dcpIns, hfntbSrc);
+}
+#endif /* FOOTNOTES */
+
+#ifdef CASHMERE
+{
+/* If there are any sections call AddSects */
+struct SETB **hsetbSrc;
+if ((hsetbSrc = HsetbGet(docSrc)) != 0)
+ AddSects(docDest, cpDel, docSrc, cpIns, cpIns + dcpIns, hsetbSrc);
+}
+#endif
+
+/* Special kludge for graphics paragraphs */
+if (dcpIns != dcpDel)
+ CheckGraphic(docDest, cpDel + dcpIns);
+
+if (dcpIns != cp0)
+ {
+ /* may have to merge in font tables */
+ MergeFfntb(docSrc, docDest, cpDel, cpDel + dcpIns);
+ }
+
+#ifdef DEBUG
+/* ShowDocPcd("From ReplaceCps End: ", docDest); */
+#endif
+}
+
+
+
+
+/* A D J P A R A S */
+AdjParas(docDest, cpDest, docSrc, cpFirstSrc, dcpLimSrc, fDel)
+int docDest, docSrc, fDel;
+typeCP cpDest, cpFirstSrc, dcpLimSrc;
+{ /* Mark display lines showing the section/paragraph containing cpDest
+ in docDest as invalid if the range cpFirstSrc through cpLimSrc-1
+ in docSrc contains end-of-section/end-of-paragraph marks */
+
+
+ typeCP cpFirstPara, cpFirstSect;
+ typeCP cpLimSrc = cpFirstSrc + dcpLimSrc;
+
+#ifdef CASHMERE /* In WRITE, the document is one big section */
+ CacheSect(docSrc, cpFirstSrc);
+ if (cpLimSrc >= vcpLimSectCache)
+ { /* Sel includes sect mark */
+ typeCP dcp;
+ CacheSect(docDest, cpDest);
+ dcp = cpDest - vcpFirstSectCache;
+ AdjustCp(docDest, vcpFirstSectCache, dcp, dcp);
+ }
+#endif
+
+ CachePara(docSrc, cpFirstSrc);
+ if (cpLimSrc >= vcpLimParaCache)
+ { /* Diddling with a para return */
+ typeCP dcp, cpLim;
+ typeCP cpMacT = (**hpdocdod)[docDest].cpMac;
+ typeCP cpFirst;
+
+ if ((cpDest == cpMacT) && (cpMacT != cp0))
+ {
+ CachePara(docDest, cpDest-1);
+ cpLim = cpMacT + 1;
+ }
+ else
+ {
+ CachePara(docDest, cpLim = cpDest);
+ }
+ cpFirst = vcpFirstParaCache;
+/* invalidate at least from cpFirst to cpLim */
+
+/* cpFirst is start of disturbed para in destination doc */
+/* next few lines check for effect of the edit on the semi-paragraph after
+the last paragraph mark in the document.
+Note: cpLimSrc is redefined as the point of insertion if !fDel.
+If fDel, Src and Dest documents are the same.
+*/
+ if (!fDel)
+ cpLimSrc = cpFirstSrc;
+ if (cpLimSrc <= cpMacT)
+ {
+/* if a paragraph exists at the end of the disturbance, is it the last
+semi-paragraph? */
+ CachePara(docDest, cpLimSrc);
+ if (vcpLimParaCache > cpMacT)
+/* yes, extend invalidation over the semi-para */
+ cpLim = cpMacT + 1;
+ }
+ else
+ cpLim = cpMacT + 1;
+ dcp = cpLim - cpFirst;
+ AdjustCp(docDest, cpFirst, dcp, dcp);
+ }
+}
+
+
+
+
+
+
+int IcpSearch(cp, rgfoo, cchFoo, bcp, ifooLim)
+typeCP cp;
+CHAR rgfoo[];
+unsigned cchFoo;
+unsigned bcp;
+unsigned ifooLim;
+{ /* Binary search a table for cp; return index of 1st >= cp */
+unsigned ifooMin = 0;
+
+while (ifooMin + 1 < ifooLim)
+ {
+ int ifooGuess = (ifooMin + ifooLim - 1) >> 1;
+ typeCP cpGuess;
+ if ((cpGuess = *(typeCP *) &rgfoo[cchFoo * ifooGuess + bcp]) < cp)
+ ifooMin = ifooGuess + 1;
+ else if (cpGuess > cp)
+ ifooLim = ifooGuess + 1;
+ else
+ return ifooGuess;
+ }
+return ifooMin;
+} /* end of I c p S e a r c h */
+
+
+
+
+
+DelFtns(doc, cpFirst, cpLim)
+typeCP cpFirst, cpLim;
+int doc;
+{ /* Delete all footnote text corresponding to refs in [cpFirst:cpLim) */
+/* Also delete SED's for section marks. */
+struct FNTB **hfntb;
+
+struct SETB **hsetb;
+
+struct PGTB **hpgtb;
+
+struct DOD *pdod;
+
+#ifdef FOOTNOTES
+if ((hfntb = HfntbGet(doc)) != 0)
+ RemoveDelFtnText(doc, cpFirst, cpLim, hfntb);
+#endif /* FOOTNOTES */
+
+#ifdef CASHMERE
+if ((hsetb = HsetbGet(doc)) != 0)
+ RemoveDelSeds(doc, cpFirst, cpLim, hsetb);
+#endif
+
+pdod = &(**hpdocdod)[doc];
+if (pdod->dty == dtyNormal && (hpgtb = pdod->hpgtb) != 0)
+ RemoveDelPgd(doc, cpFirst, cpLim, hpgtb);
+
+}
+
+
+
+AdjRg(pfoo, cchFoo, bcp, ccp, cp, dcpAdj)
+register CHAR *pfoo;
+int cchFoo, bcp, ccp;
+typeCP cp, dcpAdj;
+{ /* Adjust cp's in an array */
+pfoo += bcp;
+while (ccp-- && *(typeCP *)((pfoo -= cchFoo)) >= cp)
+ *(typeCP *)(pfoo) += dcpAdj;
+}
+
+
+
+
+DeleteSel()
+{ /* Delete a selection */
+typeCP cpFirst;
+typeCP cpLim;
+typeCP dcp;
+
+cpFirst = selCur.cpFirst;
+cpLim = selCur.cpLim;
+
+NoUndo(); /* We don't want any combining of adjacents for this operation */
+SetUndo(uacDelNS, docCur, cpFirst, dcp = cpLim - cpFirst,
+ docNil, cpNil, cp0, 0);
+Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+vfSeeSel = true;
+vfPictSel = false;
+return ferror;
+}
+
+
+
+
+FWriteOk( fwc )
+int fwc;
+{ /* Test whether the edit operation specified by fwc is acceptable.
+ Assume the operation is to be performed on selCur in docCur.
+ Return TRUE if the operation is acceptable; FALSE otherwise */
+extern int vfOutOfMemory;
+
+return !vfOutOfMemory;
+}
+
+
+
+
+/* S E T U N D O */
+SetUndo(uac, doc, cp, dcp, doc2, cp2, dcp2, itxb)
+int uac, doc, doc2;
+typeCP cp, dcp, cp2, dcp2;
+short itxb;
+{/* Set up the UNDO structure, vuab, in response to an editing operation */
+ struct DOD *pdod, *pdodUndo;
+
+ /* Group delete operations together with adjacent deletes or replaces */
+ /* WRITE needs the replace case since AlphaMode is treated as a big */
+ /* replace operation */
+
+ if (uac == uacDelNS && doc == vuab.doc)
+ {
+ if ((vuab.uac == uacDelNS) || (vuab.uac == uacReplNS))
+ {
+ typeCP cpUndoAdd;
+
+ if (cp == vuab.cp)
+ {
+ cpUndoAdd = CpMacText( docUndo );
+ goto UndoAdd;
+ }
+ else if (cp + dcp == vuab.cp)
+ {
+ cpUndoAdd = cp0;
+UndoAdd: ReplaceCps( docUndo, cpUndoAdd, cp0, doc, cp, dcp );
+ if (vuab.uac == uacDelNS)
+ vuab.dcp += dcp;
+ else
+ vuab.dcp2 += dcp;
+ goto SURet;
+ }
+ else if (vuab.uac == uacReplNS && cp == vuab.cp + vuab.dcp)
+ { /* Special case for combining insertions --
+ do not start a new undo operation if a null
+ deletion is done at the end of an existing replace */
+ if (dcp == cp0)
+ return;
+ }
+ }
+ }
+
+ /* Group insertions together with adjacent ins's and replaces */
+
+ if (uac == uacInsert && doc == vuab.doc)
+ {/* check for adjacent inserts */
+ /* Because we can be popped out of Alpha Mode so easily
+ in WRITE, we try to be smarter about combining adjacent
+ insert operations */
+ if (vuab.uac == uacInsert || vuab.uac == uacReplNS)
+ {
+ if (cp == vuab.cp + vuab.dcp)
+ {
+ vuab.dcp += dcp;
+ goto SURet;
+ }
+ }
+ else if (cp == vuab.cp)
+ switch(vuab.uac)
+ {
+ default:
+ break;
+ case uacDelNS:
+ vuab.dcp2 = vuab.dcp;
+ vuab.uac = uacReplNS;
+ goto repl;
+ case uacDelBuf:
+ vuab.uac = uacReplBuf;
+ goto repl;
+ case uacDelScrap:
+ vuab.uac = uacReplScrap;
+ repl:
+ vuab.dcp = dcp;
+ SetUndoMenuStr(IDSTRUndoEdit);
+ goto SURet;
+ }
+ }
+
+#ifndef CASHMERE
+ /* The use of vuab.itxb is a kludge to determine if the undo block is
+ for a ruler change or an undone ruler change. */
+ if (uac == uacRulerChange && vuab.uac == uacRulerChange && doc ==
+ vuab.doc && cp == vuab.cp && vuab.itxb == 0)
+ {
+ /* The undo action block for the ruler change is already set. */
+ vuab.dcp = CpMax(dcp, vuab.dcp);
+ goto SURet;
+ }
+#endif /* not CASHMERE */
+
+ vuab.doc = doc;
+ vuab.cp = cp;
+ vuab.dcp = dcp;
+ vuab.doc2 = doc2;
+ vuab.cp2 = cp2;
+ vuab.dcp2 = dcp2;
+ vuab.itxb = itxb;
+ /*idstrUndoBase = IDSTRUndoBase;*/
+ switch (vuab.uac = uac)
+ { /* Save deleted text if necessary */
+ default:
+ SetUndoMenuStr(IDSTRUndoEdit);
+ break;
+ case uacDelScrap:
+ case uacReplScrap:
+ /* Two-level edit; save scrap */
+ {
+ extern int vfOwnClipboard;
+
+ if ( vfOwnClipboard )
+ {
+ ClobberDoc( docUndo, docScrap, cp0,
+ CpMacText( docScrap ) );
+ }
+ else
+ ClobberDoc(docUndo, docNil, cp0, cp0);
+
+ SetUndoMenuStr(IDSTRUndoEdit);
+/* SetUndoMenuStr(uac == uacDelScrap ? IDSTRUndoCut :*/
+/* IDSTRUndoPaste);*/
+ break;
+ }
+ case uacDelNS:
+ /* One-level edit; save deleted text */
+ ClobberDoc(docUndo, doc, cp, dcp);
+ SetUndoMenuStr(IDSTRUndoEdit);
+/* SetUndoMenuStr(IDSTRUndoCut);*/
+ break;
+ case uacReplNS:
+ /* One-level edit; save deleted text */
+ ClobberDoc(docUndo, doc, cp, dcp2);
+ SetUndoMenuStr(IDSTRUndoEdit);
+/* SetUndoMenuStr(IDSTRUndoPaste);*/
+ break;
+ case uacPictSel:
+ ClobberDoc(docUndo, doc, cp, dcp);
+ SetUndoMenuStr(IDSTRUndoEdit);
+/* SetUndoMenuStr(IDSTRUndoPict);*/
+ break;
+ case uacChLook:
+ case uacChLookSect:
+ SetUndoMenuStr(IDSTRUndoLook);
+ break;
+
+#ifndef CASHMERE
+ case uacFormatTabs:
+ ClobberDoc(docUndo, doc, cp, dcp);
+ SetUndoMenuStr(IDSTRUndoBase);
+ break;
+ case uacRepaginate:
+ case uacFormatSection:
+ ClobberDoc(docUndo, doc, cp, dcp);
+ if ((**hpdocdod)[doc].hpgtb)
+ { /* copy page table over if there is one */
+ int cw = cwPgtbBase + (**(**hpdocdod)[doc].hpgtb).cpgdMax * cwPGD;
+ CopyHeapTableHandle(hpdocdod,
+ (sizeof(struct DOD) * doc) + BStructMember(DOD, hpgtb),
+ (sizeof(struct DOD) * docUndo) + BStructMember(DOD, hpgtb),
+ cw);
+ }
+ SetUndoMenuStr(IDSTRUndoBase);
+ break;
+ case uacRulerChange:
+ ClobberDoc(docUndo, doc, cp, dcp2);
+ SetUndoMenuStr(IDSTRUndoLook);
+/* SetUndoMenuStr(IDSTRUndoRuler);*/
+ break;
+#endif /* not CASHMERE */
+
+#ifdef UPDATE_UNDO
+#if defined(OLE)
+ case uacObjUpdate:
+ ClobberDoc(docUndo, docNil, cp0, cp0);
+ SetUndoMenuStr(IDSTRObjUndo);
+ break;
+#endif
+#endif
+ }
+
+ if (doc != docNil)
+ {
+ pdod = &(**hpdocdod)[doc];
+ pdodUndo = &(**hpdocdod)[docUndo];
+ pdodUndo->fDirty = pdod->fDirty;
+ pdodUndo->fFormatted = pdod->fFormatted;
+ if (uac != uacReplScrap)
+ /* If SetUndo is called with uacReplScrap, = COPY SCRAP */
+ pdod->fDirty = true;
+ }
+#ifdef BOGUSCS
+ if (uac == uacMove)
+ CheckMove();
+#endif
+SURet:
+ if (ferror) NoUndo();
+
+ return;
+}
+
+
+
+
+/* C L O B B E R D O C */
+ClobberDoc(docDest, docSrc, cp, dcp)
+int docDest, docSrc;
+typeCP cp, dcp;
+{ /* Replace contents of docDest with docSrc[cp:dcp] */
+
+extern int docScrap;
+extern int vfOwnClipboard;
+struct FFNTB **hffntb;
+struct SEP **hsep;
+struct TBD (**hgtbd)[];
+
+register int bdodDest=sizeof(struct DOD)*docDest;
+register int bdodSrc=sizeof(struct DOD)*docSrc;
+
+#define dodDest (*((struct DOD *)(((CHAR *)(*hpdocdod))+bdodDest)))
+#define dodSrc (*((struct DOD *)(((CHAR *)(*hpdocdod))+bdodSrc)))
+
+ /* clear out dest doc's font table - it will get a copy of source's */
+ hffntb = HffntbGet(docDest);
+ dodDest.hffntb = 0;
+
+ /* this does nothing if hffntb is NULL (5.15.91) v-dougk */
+ FreeFfntb(hffntb);
+
+ SmashDocFce(docDest); /* font cache entries can't refer to it by doc
+ any more */
+
+ /* this does nothing (code stubbed out) (5.15.91) v-dougk */
+ ZeroFtns(docDest); /* So ReplaceCps doesn't worry about them */
+
+ ReplaceCps(docDest, cp0, dodDest.cpMac, docSrc, cp, dcp);
+
+ /* Copy section properties and tab table, both of which are
+ document properties in MEMO */
+ CopyHeapTableHandle( hpdocdod,
+ ((docSrc == docNil) ? -1 :
+ bdodSrc + BStructMember( DOD, hsep )),
+ bdodDest + BStructMember( DOD, hsep ),
+ cwSEP );
+ CopyHeapTableHandle( hpdocdod,
+ ((docSrc == docNil) ? -1 :
+ bdodSrc + BStructMember( DOD, hgtbd )),
+ bdodDest + BStructMember( DOD, hgtbd ),
+ cwTBD * itbdMax );
+}
+
+
+
+
+CopyHeapTableHandle( hBase, bhSrc, bhDest, cwHandle )
+CHAR **hBase;
+register int bhSrc;
+register int bhDest;
+int cwHandle;
+{ /* Copy cwHandle words of contents from a handle located at
+ offset (in bytes) bhSrc from the beginning of heap object
+ hBase to a handle located at bhDest from the same base. If the
+ destination handle is non-NULL, free it first.
+ If bhSrc is negative, free the destination, but do not copy */
+
+int **hT;
+
+#define hSrc (*((int ***) ((*hBase)+bhSrc)))
+#define hDest (*((int ***) ((*hBase)+bhDest)))
+
+if (hDest != NULL)
+ {
+ FreeH( hDest );
+ hDest = NULL;
+ }
+
+if ( (bhSrc >= 0) && (hSrc != NULL) &&
+ !FNoHeap( hT = (int **)HAllocate( cwHandle )))
+ {
+ blt( *hSrc, *hT, cwHandle );
+ hDest = hT;
+ }
+
+#undef hSrc
+#undef hDest
+}
+
+
+
+ZeroFtns(doc)
+{ /* Remove all footnote & section references from doc */
+struct FNTB **hfntb;
+struct SETB **hsetb;
+
+#ifdef FOOTNOTES
+ if ((hfntb = HfntbGet(doc)) != 0)
+ {
+ FreeH(hfntb);
+ (**hpdocdod)[doc].hfntb = 0;
+ }
+#endif /* FOOTNOTES */
+#ifdef CASHMERE
+ if ((hsetb = HsetbGet(doc)) != 0)
+ {
+ FreeH(hsetb);
+ (**hpdocdod)[doc].hsetb = 0;
+ }
+#endif
+}
+
+
+
+fnClearEdit(int nInsertingOver)
+
+{ /* CLEAR command entry point: Delete the current selection */
+
+/**
+ NOTE: as of this comment, this is used:
+ 1) when typing over a selection (AlphaMode() in insert.c)
+ 2) when Pasting over a selection (fnPasteEdit in clipboard.c)
+ 3) when pressing the delete key
+ 4) for InsertObject (obj3.c)
+ 5) for DragDrop (obj3.c)
+ 6) Clear header/footer (running.c)
+
+ A similar sequence occurs when cutting to the clipboard
+ (fnCutEdit in clipbord.c).
+
+ Also see copying to clipboard (fnCopyEdit in clipbord.c).
+
+ (8.29.91) v-dougk
+**/
+
+ if (!FWriteOk( fwcDelete ))
+ return TRUE;
+
+ if (selCur.cpFirst < selCur.cpLim)
+ {
+#if defined(OLE)
+
+ /* this'll prevent us from deleting open embeds */
+ if (!ObjDeletionOK(nInsertingOver))
+ return TRUE;
+
+ /* close open links */
+ ObjEnumInRange(docCur,selCur.cpFirst,selCur.cpLim,ObjCloseObjectInDoc);
+#endif
+
+ return DeleteSel();
+ }
+ return FALSE;
+}
+
+
+
+MergeFfntb(docSrc, docDest, cpMin, cpLim)
+/* determines if the two docs font tables differ to the extent that we need
+ to apply a mapping sprm to the specified cp's */
+
+int docSrc, docDest;
+typeCP cpMin, cpLim;
+{
+struct FFNTB **hffntb;
+int cftcDiffer, ftc, iffn;
+struct FFN *pffn;
+CHAR rgbSprm[2 + 256];
+CHAR rgbFfn[ibFfnMax];
+
+hffntb = HffntbGet(docSrc);
+if (hffntb != 0)
+ {
+ cftcDiffer = 0;
+ for (iffn = 0; iffn < (*hffntb)->iffnMac; iffn++)
+ {
+ pffn = *(*hffntb)->mpftchffn[iffn];
+ bltbyte(pffn, rgbFfn, CbFromPffn(pffn));
+ ftc = FtcChkDocFfn(docDest, rgbFfn);
+ if (ftc != iffn)
+ cftcDiffer++;
+ rgbSprm[2+iffn] = ftc;
+ if (ftc == ftcNil)
+ /* we're stuck! */
+ return;
+ }
+
+ if (cftcDiffer == 0)
+ /* new font table is a superset, & all the old font table's
+ ftc's matched exactly - no need to do anything */
+ return;
+
+ rgbSprm[0] = sprmCMapFtc;
+ rgbSprm[1] = (*hffntb)->iffnMac;
+
+ /* here goes - apply the mapping */
+ AddSprmCps(rgbSprm, docDest, cpMin, cpLim);
+ }
+}
+
diff --git a/private/mvdm/wow16/write/editdefs.h b/private/mvdm/wow16/write/editdefs.h
new file mode 100644
index 000000000..615f96abd
--- /dev/null
+++ b/private/mvdm/wow16/write/editdefs.h
@@ -0,0 +1,52 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define ipcdNil -1 /* Error return from IpcdSplit */
+
+#define cpcdChunk 5
+#define cpcdInit 5
+#define cpcdMaxIncr 10
+
+#define dcpAvgWord 10
+#define dcpAvgSent 100
+
+#include "prmdefs.h"
+
+struct PCD
+ {
+ typeCP cpMin;
+ unsigned fNoParaLast : 1;
+ unsigned fn : 15;
+ typeFC fc;
+ struct PRM prm;
+ };
+
+#define cwPCD (sizeof (struct PCD) / sizeof (int))
+#define cbPCD (sizeof (struct PCD))
+#define bcpPCD 0
+
+struct PCTB
+ {
+ unsigned ipcdMax;
+ unsigned ipcdMac;
+ struct PCD rgpcd[cpcdInit];
+ };
+
+#define cwPCTBInit (sizeof (struct PCTB) / sizeof (int))
+#define cbPCTBInit (sizeof (struct PCTB))
+
+struct UAB
+ { /* UNDO Action Block */
+ int uac; /* UNDO Action Code (see cmddefs.h) */
+ int doc;
+ typeCP cp;
+ typeCP dcp;
+ int doc2;
+ typeCP cp2;
+ typeCP dcp2;
+ short itxb;
+ };
+
+
+struct PCD *PpcdFromCp();
diff --git a/private/mvdm/wow16/write/editftn.c b/private/mvdm/wow16/write/editftn.c
new file mode 100644
index 000000000..1c923f9c1
--- /dev/null
+++ b/private/mvdm/wow16/write/editftn.c
@@ -0,0 +1,241 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+/*#include "toolbox.h"*/
+#include "mw.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "debug.h"
+
+extern struct DOD (**hpdocdod)[];
+extern struct FCB (**hpfnfcb)[];
+extern int wwMac;
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern int **HAllocate();
+extern int docCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int ferror;
+
+
+
+
+
+#ifdef FOOTNOTES
+AddFtns(docDest, cpDest, docSrc, cpFirst, cpLim, hfntbSrc)
+int docDest, docSrc;
+typeCP cpDest, cpFirst, cpLim;
+struct FNTB **hfntbSrc;
+{ /* Add footnote text to coppespond with inserted references */
+/* Called after inserting docSrc[cpFirst:cpLim) into docDest@cpDest */
+struct FNTB *pfntbSrc, **hfntbDest, *pfntbDest;
+struct FND *pfndSrc, *pfndDest;
+int cfndDest, ifndSrc, cfndIns, ifndDest;
+typeCP cpFtnSrc, dcpFtn, cpFtnDest;
+typeCP dcp;
+
+if ((pfndSrc = &(pfntbSrc = *hfntbSrc)->rgfnd[0])->cpFtn <= cpFirst)
+ return; /* No footnotes or source text is inside ftns */
+
+pfndSrc += (ifndSrc = IcpSearch(cpFirst, pfndSrc,
+ cchFND, bcpRefFND, pfntbSrc->cfnd));
+cpFtnSrc = pfndSrc->cpFtn;
+
+/* Find all references in inserted area. */
+for (cfndIns = 0; pfndSrc->cpRef < cpLim; pfndSrc++, cfndIns++)
+ ;
+
+if (cfndIns != 0)
+ { /* Insert footnote text and fnd's. */
+ dcpFtn = pfndSrc->cpFtn - cpFtnSrc; /* Length of ftn texts */
+
+ /* Ensure destination fntb large enough */
+ /* HEAP MOVEMENT */
+ if (FNoHeap(hfntbDest = HfntbEnsure(docDest, cfndIns)))
+ return;
+ if ((pfndDest = &(pfntbDest = *hfntbDest)->rgfnd[0])->cpFtn <= cpDest)
+ { /* Inserting refs inside footnotes? No way! */
+ Error(IDPMTFtnLoad);
+ return;
+ }
+
+ /* Find ifnd to insert new fnd's */
+ ifndDest = IcpSearch(cpDest, pfndDest,
+ cchFND, bcpRefFND, cfndDest = pfntbDest->cfnd);
+
+ /* Insert new footnote text */
+ /* HEAP MOVEMENT */
+ ReplaceCps(docDest, cpFtnDest = (pfndDest + ifndDest)->cpFtn, cp0,
+ docSrc, cpFtnSrc, dcpFtn);
+ if (ferror)
+ return;
+
+ /* Insert new fnd's */
+ pfndSrc = &(pfntbSrc = *hfntbSrc)->rgfnd[ifndSrc];
+ pfndDest = &(pfntbDest = *hfntbDest)->rgfnd[ifndDest];
+ pfntbDest->cfnd += cfndIns; /* Update fnd count */
+ pfndDest->cpFtn += dcpFtn; /* AdjustCp considers the insertion to be
+ part of this footnote; correct it. */
+ blt(pfndDest, pfndDest + cfndIns,
+ cwFND * (cfndDest - ifndDest)); /* Open up fntb */
+ while (cfndIns--)
+ { /* Copy fnd's */
+ pfndDest->cpRef = cpDest + pfndSrc->cpRef - cpFirst;
+ (pfndDest++)->cpFtn =
+ cpFtnDest + (pfndSrc++)->cpFtn - cpFtnSrc;
+ }
+ /* Invalidate dl's of later ftn refs */
+ dcp = (**hfntbDest).rgfnd[0].cpFtn - ccpEol - cpDest;
+ AdjustCp(docDest, cpDest, dcp, dcp);
+ RecalcWwCps();
+ }
+}
+#endif /* FOOTNOTES */
+
+
+
+
+#ifdef FOOTNOTES
+/* R E M O V E D E L F T N T E X T */
+RemoveDelFtnText(doc, cpFirst, cpLim, hfntb)
+int doc;
+typeCP cpFirst,cpLim;
+struct FNTB **hfntb;
+/* Remove the text of footnotes that are contained in the selection that is
+ delimited by cpFirst and CpLim */
+{
+ struct FNTB *pfntb;
+ struct FND *pfnd, *pfndT;
+ int cfnd, ifnd, cfndDel;
+
+ if ((pfnd = &(pfntb = *hfntb)->rgfnd[0])->cpFtn > cpFirst)
+ {
+ pfnd += (ifnd =
+ IcpSearch(cpFirst, pfnd, cchFND, bcpRefFND, cfnd = pfntb->cfnd));
+
+ /* Find all references in deleted area. */
+ for (pfndT = pfnd, cfndDel = 0; pfndT->cpRef < cpLim; pfndT++, cfndDel++)
+ ;
+
+#ifdef DEBUG
+ Assert(ifnd + cfndDel < cfnd);
+#endif
+
+ if (cfndDel != 0)
+ { /* Delete footnote text and close up fntb. */
+ typeCP cpDel = pfnd->cpFtn;
+ blt(pfndT, pfnd, cwFND * ((cfnd -= cfndDel) - ifnd));
+ (*hfntb)->cfnd = cfnd;
+ /* HEAP MOVEMENT */
+ Replace(doc, cpDel, pfnd->cpFtn - cpDel, fnNil, fc0, fc0);
+ if (cfnd == 1)
+ {
+
+ Replace(doc, (**hpdocdod)[doc].cpMac - ccpEol,
+ (typeCP) ccpEol, fnNil, fc0, fc0);
+ FreeH((**hpdocdod)[doc].hfntb);
+ (**hpdocdod)[doc].hfntb = 0;
+/* fix selCur twisted by AdjustCp. Another AdjustCp still pending. */
+ if (doc == docCur && !pwwdCur->fFtn)
+ {
+ selCur.cpFirst = selCur.cpLim = cpLim;
+ cpMacCur = (**hpdocdod)[doc].cpMac;
+ }
+ }
+ else
+ { /* Invalidate dl's of later ftn refs */
+ typeCP dcp = (**hfntb).rgfnd[0].cpFtn -
+ ccpEol - cpLim;
+ AdjustCp(doc, cpLim, dcp, dcp);
+ }
+ }
+ }
+}
+#endif /* FOOTNOTES */
+
+
+
+#ifdef FOOTNOTES
+struct FNTB **HfntbCreate(fn)
+int fn;
+{ /* Create a footnote table from a formatted file */
+struct FNTB *pfntbFile;
+typePN pn;
+int cchT;
+
+int cfnd;
+struct FNTB **hfntb;
+int *pwFntb;
+int cw;
+
+#ifdef DEBUG
+Assert(fn != fnNil && (**hpfnfcb)[fn].fFormatted);
+#endif
+if ((pn = (**hpfnfcb)[fn].pnFntb) == (**hpfnfcb)[fn].pnSep)
+ return 0;
+pfntbFile = (struct FNTB *) PchGetPn(fn, pn, &cchT, false);
+if ((cfnd = pfntbFile->cfnd) == 0)
+ return (struct FNTB **)0;
+
+hfntb = (struct FNTB **) HAllocate(cw = cwFNTBBase + cfnd * cwFND);
+if (FNoHeap(hfntb))
+ return (struct FNTB **)hOverflow;
+
+pwFntb = (int *) *hfntb;
+
+blt(pfntbFile, pwFntb, min(cwSector, cw));
+
+while ((cw -= cwSector) > 0)
+ { /* Copy the fnd's to heap */
+ blt(PchGetPn(fn, ++pn, &cchT, false), pwFntb += cwSector,
+ min(cwSector, cw));
+ }
+
+(*hfntb)->cfndMax = cfnd;
+return hfntb;
+}
+#endif /* FOOTNOTES */
diff --git a/private/mvdm/wow16/write/editpgtb.c b/private/mvdm/wow16/write/editpgtb.c
new file mode 100644
index 000000000..050001afa
--- /dev/null
+++ b/private/mvdm/wow16/write/editpgtb.c
@@ -0,0 +1,87 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NOHDC
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "debug.h"
+
+extern struct FCB (**hpfnfcb)[];
+int **HAllocate();
+
+
+
+
+RemoveDelPgd(doc, cpFirst, cpLim, hpgtb)
+int doc;
+typeCP cpFirst, cpLim;
+struct PGTB **hpgtb;
+{
+struct PGTB *ppgtb;
+struct PGD *ppgd, *ppgdT;
+int ipgd, cpgd, cpgdDel;
+
+ {
+ ppgtb = *hpgtb;
+ ppgd = &ppgtb->rgpgd[0];
+ ppgd += (ipgd =
+ IcpSearch(cpFirst + 1, ppgd, cwPGD * sizeof(int),
+ bcpPGD, cpgd = ppgtb->cpgd));
+
+ if (ppgd->cpMin > cpFirst) /* Ensure not past last page */
+ { /* Find all page breaks in deleted area. */
+ for (ppgdT = ppgd, cpgdDel = 0;
+ ipgd + cpgdDel < cpgd && ppgdT->cpMin <= cpLim;
+ ppgdT++, cpgdDel++)
+ continue;
+
+ if (cpgdDel != 0)
+ { /* Close up pgtb. */
+ blt(ppgdT, ppgd, cwPGD * ((cpgd -= cpgdDel) - ipgd));
+ (*hpgtb)->cpgd = cpgd;
+ }
+ }
+ }
+} /* end of R e m o v e D e l P g d */
diff --git a/private/mvdm/wow16/write/editsect.c b/private/mvdm/wow16/write/editsect.c
new file mode 100644
index 000000000..ac43d99f2
--- /dev/null
+++ b/private/mvdm/wow16/write/editsect.c
@@ -0,0 +1,182 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+
+#include <windows.h>
+
+/*#include "toolbox.h"*/
+#include "mw.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "debug.h"
+
+extern int docMode;
+extern struct FCB (**hpfnfcb)[];
+
+int **HAllocate();
+
+
+
+#ifdef CASHMERE /* Only if we support multiple sections */
+AddSects(docDest, cpDest, docSrc, cpFirst, cpLim, hsetbSrc)
+int docDest, docSrc;
+typeCP cpDest, cpFirst, cpLim;
+struct SETB **hsetbSrc;
+{ /* Add SED's to correspond with inserted section marks */
+/* Called after inserting docSrc[cpFirst:cpLim) into docDest@cpDest */
+struct SETB *psetbSrc, **hsetbDest, *psetbDest;
+struct SED *psedSrc, *psedDest;
+int csedDest, isedSrc, csedIns, isedDest;
+
+
+psedSrc = &(psetbSrc = *hsetbSrc)->rgsed[0];
+psedSrc += (isedSrc = IcpSearch(cpFirst + 1, psedSrc,
+ cchSED, bcpSED, psetbSrc->csed));
+
+/* Find all section marks in inserted area. */
+for (csedIns = 0; psedSrc->cp <= cpLim; psedSrc++, csedIns++)
+ ;
+
+if (csedIns != 0)
+ { /* Insert sed's. */
+ /* Ensure destination setb large enough */
+ /* HEAP MOVEMENT */
+ if (FNoHeap(hsetbDest = HsetbEnsure(docDest, csedIns)))
+ return;
+ psedDest = &(psetbDest = *hsetbDest)->rgsed[0];
+
+ /* Find ised to insert new sed's */
+ psedDest += (isedDest = IcpSearch(cpDest + 1, psedDest,
+ cchSED, bcpSED, csedDest = psetbDest->csed));
+
+ /* Insert new sed's */
+ psedSrc = &(psetbSrc = *hsetbSrc)->rgsed[isedSrc];
+ psetbDest->csed += csedIns; /* Update sed count */
+ blt(psedDest, psedDest + csedIns,
+ cwSED * (csedDest - isedDest)); /* Open up setb */
+ blt(psedSrc, psedDest, cwSED * csedIns);
+ while (csedIns--)
+ (psedDest++)->cp = cpDest + (psedSrc++)->cp - cpFirst;
+ }
+} /* end of A d d S e c t s */
+#endif /* CASHMERE */
+
+
+
+#ifdef CASHMERE /* Only if we support separate sections */
+RemoveDelSeds(doc, cpFirst, cpLim, hsetb)
+int doc;
+typeCP cpFirst, cpLim;
+struct SETB **hsetb;
+{
+struct SETB *psetb;
+struct SED *psed, *psedT;
+int ised, csed, csedDel;
+
+ {
+ psetb = *hsetb;
+ psed = &psetb->rgsed[0];
+ psed += (ised =
+ IcpSearch(cpFirst + 1, psed, cchSED, bcpSED, csed = psetb->csed));
+
+ /* Find all section marks in deleted area. */
+ for (psedT = psed, csedDel = 0; psedT->cp <= cpLim; psedT++, csedDel++)
+ ;
+
+ Assert(ised + csedDel < csed);
+
+ if (csedDel != 0)
+ { /* Close up setb. */
+ blt(psedT, psed, cwSED * ((csed -= csedDel) - ised));
+ (*hsetb)->csed = csed;
+ docMode = docNil;
+ }
+ }
+} /* end of R e m o v e D e l S e d s */
+#endif /* CASHMERE */
+
+
+
+#ifdef CASHMERE /* This loads a complete section table */
+struct SETB **HsetbCreate(fn)
+int fn;
+{ /* Create a section table from a formatted file */
+
+struct SETB *psetbFile;
+typePN pn;
+int cchT;
+int csed, ised;
+struct SETB **hsetb;
+int *pwSetb;
+int cw;
+struct SED *psed;
+
+Assert(fn != fnNil && (**hpfnfcb)[fn].fFormatted);
+
+if ((pn = (**hpfnfcb)[fn].pnSetb) == (**hpfnfcb)[fn].pnBftb)
+ return (struct SETB **) 0;
+psetbFile = (struct SETB *) PchGetPn(fn, pn, &cchT, false);
+if ((csed = psetbFile->csed) == 0)
+ return (struct SETB **)0;
+
+hsetb = (struct SETB **) HAllocate(cw = cwSETBBase + csed * cwSED);
+if (FNoHeap(hsetb))
+ return (struct SETB **)hOverflow;
+pwSetb = (int *) *hsetb;
+
+blt(psetbFile, pwSetb, min(cwSector, cw));
+
+while ((cw -= cwSector) > 0)
+ { /* Copy the sed's to heap */
+ blt(PchGetPn(fn, ++pn, &cchT, false), pwSetb += cwSector,
+ min(cwSector, cw));
+ }
+
+for (ised = 0, psed = &(**hsetb).rgsed[0]; ised < csed; ised++, psed++)
+ psed->fn = fn;
+
+(**hsetb).csedMax = csed;
+return hsetb;
+} /* end of H s e t b C r e a t e */
+#endif /* CASHMERE */
diff --git a/private/mvdm/wow16/write/edm.edm b/private/mvdm/wow16/write/edm.edm
new file mode 100644
index 000000000..71cefe638
--- /dev/null
+++ b/private/mvdm/wow16/write/edm.edm
@@ -0,0 +1,597 @@
+ch.h:#ifdef KANJI
+ch.h:#endif /* if-else-def KANJI */
+ch.h:#ifndef KANJI
+ch.h:#endif /* not KANJI */
+cmddefs.h:#ifdef KANJI
+cmddefs.h:#endif /* if-else-def KANJI */
+cmddefs.h:#ifdef KANJI
+cmddefs.h:#endif /* ifdef KANJI */
+dlgdefs.h:#ifdef KANJI
+dlgdefs.h:#endif /* ifdef KANJI */
+dlgdefs.h:#ifdef KANJI
+dlgdefs.h:#endif /* ifdef KANJI */
+dlgdefs.h:#ifndef KANJI
+dlgdefs.h:#endif /* not KANJI */
+docdefs.h:#ifdef KANJI /* Kanji Write */
+docdefs.h:#endif /* KANJI */
+fmtdefs.h:#ifdef KANJI
+fmtdefs.h:#endif /* KANJI */
+fontdefs.h:#ifdef KANJI
+fontdefs.h:#endif /* KANJI */
+fontdefs.h:#ifdef KANJI
+fontdefs.h:#ifdef KANJI
+fontdefs.h:#endif /* ifdef KANJI */
+fontdefs.h:#ifdef KANJI
+fontdefs.h:#endif /* if-else-def KANJI */
+globdefs.h:#ifdef KANJI
+globdefs.h:#endif /* if-else-def KANJI */
+globdefs.h:#ifdef KANJI
+globdefs.h:#endif /* KANJI */
+globdefs.h:#ifdef KANJI
+globdefs.h:#endif /* ifdef KANJI */
+globdefs.h:#ifdef KANJI
+globdefs.h:#endif /* ifdef KANJI */
+kanji.h:#ifdef KANJI
+kanji.h:#define KANJI_CHARSET 128
+kanji.h:#endif /* KANJI */
+menudefs.h:#ifdef KANJI
+menudefs.h:#endif /* if-else-def KANJI */
+mw.h:#ifdef KANJI
+mw.h:#ifdef KANJI
+propdefs.h:#ifdef KANJI
+propdefs.h:#endif /* if-else-def KANJI */
+rulerdef.h:#ifdef KANJI
+rulerdef.h:#endif /* if-else-def KANJI */
+str.h:#ifdef KANJI
+str.h:#endif /* KANJI */
+chngwin.c:#define NOKANJI
+clipbord.c:#ifdef KANJI
+clipbord.c:#endif /* KANJI */
+clipbord.c:#ifdef KANJI
+clipbord.c:#endif /* KANJI */
+clipbrd2.c:#define NOKANJI
+clipbrd2.c:#ifdef KANJI
+clipbrd2.c:#endif /* if-else-def KANJI */
+clipbrd2.c:#ifdef KANJI
+clipbrd2.c:#endif /* KANJI */
+clipbrd2.c:#ifdef KANJI
+clipbrd2.c:#endif /* KANJI */
+clipbrd2.c:#ifdef KANJI
+clipbrd2.c:#endif /* KANJI */
+clipdisp.c:#ifdef KANJI
+clipdisp.c:#endif /* if-else-def KANJI */
+cmd.c:#define NOKANJI
+cmd.c:#ifdef KANJI
+createww.c:#define NOKANJI
+createww.c:#ifdef KANJI
+createww.c:#ifdef KANJI
+createww.c:#endif /* KANJI */
+createww.c:#ifdef KANJI
+createww.c:#endif /* if-else-def KANJI */
+curskeys.c:#define NOKANJI
+debug.c:#ifdef KANJI
+debug.c:#ifdef KANJI
+diaalert.c:#define NOKANJI
+diaalert.c:#ifdef KANJI
+diaalert.c:#endif /* if-else-def KANJI */
+diachgpr.c:#define NOKANJI
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI /* Kanji version */
+diadiv.c:#ifdef KANJIOLD
+diadiv.c:#endif /* ifdef KANJIOLD */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* KANJI */
+diadiv.c:#ifdef KANJIOLD
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* ifdef KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* ifdef KANJI */
+diadiv.c:#ifdef KANJIOLD
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* KANJI */
+diadiv.c:#else /* KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diadiv.c:#ifdef KANJI
+diadiv.c:#endif /* if-else-def KANJI */
+diapara.c:#ifdef KANJI
+diapara.c:#endif /* if-else-def KANJI */
+diapara.c:#ifdef KANJI
+diapara.c:#endif /* if-else-def KANJI */
+diapara.c:#ifdef KANJI
+diapara.c:#endif /* if-else-def KANJI */
+diaprint.c:#define NOKANJI
+diaprint.c:#ifdef KANJI
+diaprint.c:#endif /* KANJI */
+diarepag.c:#define NOKANJI
+diasubs.c:#define NOKANJI
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* if-else-def KANJI */
+diasubs.c:#ifdef KANJI
+diasubs.c:#endif /* ifdef KANJI */
+disp.c:#define NOKANJI
+disp.c:#ifdef KANJI
+disp.c:#endif /* if-else-def KANJI */
+doc.c:#define NOKANJI
+doprm.c:#ifdef KANJI
+doprm.c:#endif /* if-else-def KANJI */
+file.c:#define NOKANJI
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* if-else-def KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* if-else-def KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* ifdef KANJI */
+fileutil.c:#ifdef KANJI
+fileutil.c:#endif /* if-else-def KANJI */
+fontdlg.c:#define NOKANJI
+fontenum.c:#define NOKANJI
+fontenum.c:#ifdef KANJI
+fontenum.c:#endif /* if-else-def KANJI */
+fontenum.c:#ifdef KANJI
+fontenum.c: if (lptm->tmCharSet != KANJI_CHARSET || (lptm->tmPitchAndFamily & 0x6)
+fontenum.c:#endif /* if-else-def KANJI */
+fontenum.c:#ifdef KANJI
+fontenum.c: return (lptm->tmCharSet == KANJI_CHARSET
+fontenum.c:#endif /* if-else-def KANJI */
+fontenum.c:#ifdef KANJI
+fontenum.c:#endif /* if-else-def KANJI */
+fontenum.c:#ifdef KANJI
+fontenum.c:#endif /* ifdef KANJI */
+fontenum.c:#ifdef KANJI
+fontenum.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#ifdef KANJIOLD
+form1.c:#endif /* ifdef KANJIOLD */
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJIOLD
+form1.c:#endif /* ifdef KANJIOLD */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* if-else-def KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* if-else-def KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* if-else-def KANJI */
+form1.c:#ifdef KANJI
+form1.c:#ifdef KANJI
+form1.c:#ifdef KANJIOLD
+form1.c:#endif /* KANJIOLD */
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* if-else-def KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+form1.c:#ifdef KANJI
+form1.c:#endif /* ifdef KANJI */
+format2.c:#ifdef KANJI
+format2.c:#endif /* KANJI */
+format2.c:#ifdef KANJI
+format2.c:#endif /* if-else-def KANJI */
+format2.c:#ifdef KANJI
+format2.c:#endif /* if-else-def KANJI */
+help.c:#ifdef KANJI
+help.c:#endif /* if-else-def KANJI */
+initmmw.c:#ifdef KANJI
+initmmw.c:#endif /* ifdef KANJI
+initmmw.c:#ifdef KANJI
+initmmw.c:#endif /* if-else-def KANJI */
+initmmw.c:#ifdef KANJI
+initmmw.c:#endif /* if-else-def KANJI */
+initmmw.c:#ifdef KANJIOLD
+initmmw.c:#endif /* ifdef KANJIOLD */
+initmmw.c:#ifdef KANJI
+initmmw.c:#endif /* KANJI */
+initwin.c:#define NOKANJI
+initwin.c:#ifdef KANJI
+initwin.c:#endif /* if-else-def KANJI */
+insert.c:#ifndef KANJI
+insert.c:#endif /* not KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* not KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#else /* not KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* ifdef KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* if-else-def KANJI */
+insert.c:#ifdef KANJI
+insert.c:#endif /* KANJI */
+loadfnt2.c:#ifdef KANJI
+loadfnt2.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c: lf.lfCharSet = KANJI_CHARSET;
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /*if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* ifdef KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#else /* not KANJI */
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* if-else-def KANJI */
+loadfont.c:#ifdef KANJI
+loadfont.c:#endif /* KANJI */
+menu.c:#ifdef KANJI
+menu.c:#endif /* if-else-def KANJI */
+menu.c:#ifdef KANJI
+menu.c:#endif /* if-else-def KANJI */
+menu.c:#ifdef KANJI
+menu.c:#endif /* ifdef KANJI */
+menu.c:#ifndef KANJI
+menu.c:#endif /* not KANJI */
+menu.c:#ifdef KANJI
+menu.c:#endif /* if-else-def KANJI */
+menu.c:#ifndef KANJI
+menu.c:#endif /* not KANJI */
+mglobal2.c:#ifdef KANJI
+mglobal2.c:#endif /* KANJI */
+mglobals.c:#ifdef KANJI
+mglobals.c:#endif /* KANJI */
+mglobals.c:#ifdef KANJI
+mglobals.c:#endif /* if-else-def KANJI */
+mglobals.c:#ifdef KANJI
+mglobals.c:#endif /* KANJI */
+mglobals.c:#ifdef KANJI
+mglobals.c:#ifdef KANJI
+mglobals.c:#ifdef KANJIOLD
+mglobals.c:#endif /* ifdef KANJIOLD */
+mglobals.c:#endif /* ifdef KANJI */
+mglobals.c:#ifdef KANJI
+mglobals.c:#endif /* ifdef KANJI */
+mmw.c:#define NOKANJI
+mouse.c:#define NOKANJI
+open.c:#define NOKANJI
+pageinfo.c:#ifdef KANJI
+pageinfo.c: lf.lfCharSet = KANJI_CHARSET;
+pageinfo.c:#endif /* ifdef KANJI */
+pictdrag.c:#define NOKANJI
+print.c:#define NOKANJI
+print2.c:#ifdef KANJI
+quit.c:#define NOKANJI
+rare.c:#define NOKANJI
+ruler.c:#define NOKANJI
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#ifdef KANJIOLD
+ruler.c:#endif /* ifdef KANJIOLD */
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJIOLD
+ruler.c:#ifdef KANJI
+ruler.c: lf.lfCharSet = KANJI_CHARSET;
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* if-else-def KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* if-else-def KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#endif /* if-else-def KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJI
+ruler.c:#endif /* ifdef KANJI */
+ruler.c:#ifdef KANJIOLD
+ruler.c:#endif /* ifdef KANJIOLD */
+ruler.c:#ifdef KANJI
+ruler.c: lf.lfCharSet = KANJI_CHARSET;
+ruler.c:#endif /* ifdef KANJI */
+ruler2.c:#ifdef KANJI
+ruler2.c:#endif /* if-else-def KANJI */
+ruler2.c:#ifdef KANJI
+ruler2.c:#endif /* if-else-def KANJI */
+running.c:#ifdef KANJI
+running.c:#endif /* if-else-def KANJI */
+running.c:#ifdef KANJI
+running.c:#endif /* if-else-def KANJI */
+running.c:#ifdef KANJI
+running.c:#endif /* if-else-def KANJI */
+scrnchng.c:#define NOKANJI
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* ifdef KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* ifdef KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* ifdef KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* if-else-def KANJI */
+scrnchng.c:#ifdef KANJI
+scrnchng.c:#endif /* KANJI */
+search.c:#define NOKANJI
+search.c:#ifdef KANJI
+search.c:#ifndef KANJI
+search.c:#endif /* KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* KANJI */
+search.c:#ifdef KANJI
+search.c:#ifdef KANJI
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* ifdef KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifndef KANJI
+search.c:#endif /* not KANJI */
+search.c:#ifndef KANJI
+search.c:#endif /* not KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifndef KANJI
+search.c:#endif /* not KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* if-else-def KANJI */
+search.c:#ifndef KANJI
+search.c:#endif /* not KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* KANJI */
+search.c:#ifdef KANJI
+search.c:#endif /* KANJI */
+search.c:#ifdef KANJI
+select.c:#ifdef KANJI
+select.c:#endif /* if-else-def KANJI */
+select.c:#ifdef KANJI
+select.c:#ifdef KANJI
+select.c:#endif /* KANJI */
+select.c:#ifdef KANJI
+select.c:#endif /* ifdef KANJI */
+select.c:#ifdef KANJI
+select.c:#endif /* KANJI */
+select.c:#ifdef KANJI
+select.c:#endif /* if-else-def KANJI */
+select2.c:#ifdef KANJI
+select2.c:#endif /* if-else-def KANJI */
+select2.c:#ifdef KANJI
+select2.c:#endif /* if-else-def KANJI */
+select2.c:#ifdef KANJI
+select2.c:#endif /* ifdef KANJI */
+select2.c:#ifdef KANJI
+select2.c:#endif /* ifdef KANJI */
+trans2.c:#ifdef KANJI
+trans2.c:#endif /* KANJI */
+trans2.c:#ifdef KANJI
+trans2.c:#endif /* if-else-def KANJI */
+trans3.c:#define NOKANJI
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* ifdef KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* ifdef KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* ifdef KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* ifdef KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+trans3.c:#ifdef KANJI
+trans3.c:#endif /* if-else-def KANJI */
+util.c:#define NOKANJI
+util.c:#ifdef KANJI
+util.c:#endif /* if-else-def KANJI */
+util.c:#ifdef KANJI
+util.c:#endif /* if-else-def KANJI */
+util.c:#ifdef KANJI
+util.c:#endif /* if-else-def KANJI */
+util.c:#ifdef KANJI
+util.c:#endif /* ifdef KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* ifdef KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* ifdef KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#ifndef KANJI
+util2.c:#endif /* not KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* ifdef KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* ifdef KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
+util2.c:#ifdef KANJI
+util2.c:#endif /* if-else-def KANJI */
diff --git a/private/mvdm/wow16/write/egabtns.bmp b/private/mvdm/wow16/write/egabtns.bmp
new file mode 100644
index 000000000..2ae3e9569
--- /dev/null
+++ b/private/mvdm/wow16/write/egabtns.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/egamarks.bmp b/private/mvdm/wow16/write/egamarks.bmp
new file mode 100644
index 000000000..89b9e99a7
--- /dev/null
+++ b/private/mvdm/wow16/write/egamarks.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/fetch.c b/private/mvdm/wow16/write/fetch.c
new file mode 100644
index 000000000..2354f3c56
--- /dev/null
+++ b/private/mvdm/wow16/write/fetch.c
@@ -0,0 +1,490 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* fetch.c -- MW routines for obtaining attributes associated with cp's */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSCOMMANDS
+#define NOCREATESTRUCT
+#define NOATOM
+#define NOMETAFILE
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOPEN
+#define NOBITMAP
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOMM
+#define NOMB
+#define NOMSG
+#define NOOPENFILE
+#define NORESOURCE
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#include <windows.h>
+
+#include "mw.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "docdefs.h"
+#include "cmddefs.h"
+#include "filedefs.h"
+/*
+#include "code.h"
+*/
+#include "ch.h"
+#include "fkpdefs.h"
+#include "prmdefs.h"
+/*
+#include "stcdefs.h"
+*/
+
+static SetChp(struct CHP *pchp, int *pcfcChp, int fn, typeFC fc, struct PRM prm);
+
+extern typeCP vcpFetch;
+extern int vichFetch;
+extern int vdocFetch;
+extern int vccpFetch;
+extern int vcchFetch;
+extern CHAR *vpchFetch;
+extern struct CHP vchpFetch;
+extern CHAR (**hgchExpand)[];
+extern int vdocExpFetch;
+extern struct CHP vchpAbs;
+
+
+extern int vfDiskError;
+#ifdef CASHMERE
+extern int docBuffer;
+#endif
+extern struct PAP vpapAbs;
+extern struct CHP vchpNormal;
+extern struct DOD (**hpdocdod)[];
+extern CHAR rgchInsert[];
+extern int ichInsert;
+extern struct CHP vchpInsert;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern struct PAP vpapCache;
+extern struct FCB (**hpfnfcb)[];
+extern struct FKPD vfkpdCharIns;
+extern typeFC fcMacChpIns;
+
+typePN PnFkpFromFcScr();
+CHAR *PchFromFc();
+
+#ifdef BOGUS
+#ifdef DEBUG
+typeCP cpExpFetch;
+CHAR *pchExpFetch;
+int cchExpFetch;
+int ccpExpFetch;
+#endif /* DEBUG */
+#endif
+
+
+FetchCp(doc, cp, ich, fcm)
+int doc, ich, fcm;
+typeCP cp;
+{ /*
+ Inputs:
+ doc
+ Starting cp
+ ich within cp (for cp's which can cross line boundaries)
+ fcm tells whether to get chars, props, or both
+ Outputs:
+ (in vcpFetch) starting cp
+ (in vichFetch) starting ich within expanded cp
+ (in vdocFetch) doc
+ (in vccpFetch) number of cp's fetched (0 if expanded cp)
+ (in vcchFetch) number of ch's fetched
+ (in vpchFetch) characters fetched
+ (in vchpFetch) char prop of fetched chars
+ */
+struct PCD *ppcd;
+
+static int fn;
+static typeFC fc;
+static struct PRM prm;
+static typeCP ccpChp, ccpPcd, ccpFile;
+static int ipcd;
+static typeCP cpExpFetch;
+static CHAR *pchExpFetch;
+static int cchExpFetch;
+static int ccpExpFetch;
+
+
+
+if (doc == docNil)
+ { /* Sequential call to FetchCp */
+ /* If last piece was Q&D insert, skip remainder of piece */
+ if (fn == fnInsert && (fc + vccpFetch) >= ichInsert)
+ vccpFetch = ccpPcd; /* Use whole piece */
+ vcpFetch += vccpFetch; /* Go to where we left off */
+ if (vccpFetch == 0)
+ vichFetch += vcchFetch;
+ else
+ vichFetch = 0;
+ fc += vccpFetch;
+ }
+else
+ { /* Random-access call */
+ vcpFetch = cp;
+ vichFetch = ich;
+ vdocFetch = doc;
+ ccpChp = ccpPcd = ccpFile = 0;
+ }
+
+if (vcpFetch >= (**hpdocdod)[vdocFetch].cpMac)
+ { /* Use std looks for end mark */
+ vccpFetch = 0;
+
+ /* vcchFetch == 0 should not be used for endmark indications because of
+ empty QD runs. */
+ vcchFetch = 1;
+
+ if (fcm & fcmProps)
+ {
+ blt(&vchpNormal, &vchpFetch, cwCHP);
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ }
+ return;
+ }
+
+#ifdef STYLES
+if ((fcm & (fcmChars + fcmNoExpand)) == fcmChars &&
+ (**hpdocdod)[vdocFetch].dty == dtySsht)
+ { /* Style sheet; expand encoded text */
+ if (fcm & fcmProps)
+ {
+ blt(&vchpNormal, &vchpFetch, cwCHP);
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ }
+ if (vdocExpFetch == vdocFetch && vcpFetch == cpExpFetch + ccpExpFetch)
+ { /* Give back the last EOL in the expansion */
+ vccpFetch = vcchFetch = 1;
+ vpchFetch = &(**hgchExpand)[cchExpFetch];
+ return;
+ }
+ else if (vdocExpFetch != vdocFetch || cpExpFetch != vcpFetch)
+ { /* New expansion */
+ int ich = vichFetch;
+
+ vdocExpFetch = vdocFetch;
+ cpExpFetch = vcpFetch;
+ pchExpFetch = PchExpStyle(&cchExpFetch, &ccpExpFetch, vdocFetch,
+ vcpFetch); /* Uses FetchCp, so better save v's */
+ vcpFetch = cpExpFetch; /* Got changed by PchExpStyle */
+ vichFetch = ich; /* Ditto */
+ if (fcm & fcmProps) /* Ditto */
+ {
+ blt(&vchpNormal, &vchpFetch, cwCHP);
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ }
+ }
+ if (vichFetch >= cchExpFetch)
+ { /* End of expansion; skip cp's */
+ vccpFetch = ccpExpFetch;
+ vcchFetch = 0;
+ ccpPcd = ccpFile = ccpChp = 0;
+ }
+ else
+ {
+ vccpFetch = 0;
+ vcchFetch = cchExpFetch - vichFetch;
+ }
+ vpchFetch = pchExpFetch + vichFetch;
+ return;
+ }
+#endif /* STYLES */
+
+
+if (ccpPcd > vccpFetch)
+ ccpPcd -= vccpFetch;
+else
+ {
+ struct PCTB *ppctb = *(**hpdocdod)[vdocFetch].hpctb;
+
+ if (doc == docNil)
+ ++ipcd; /* Save some work on sequential call */
+ else
+ { /* Search for piece and remember index for next time */
+ ipcd = IpcdFromCp(ppctb, vcpFetch);
+ }
+
+ ppcd = &ppctb->rgpcd[ipcd];
+ ccpPcd = (ppcd + 1)->cpMin - vcpFetch;
+ ccpChp = ccpFile = 0; /* Invalidate everything; new piece */
+ fc = ppcd->fc + vcpFetch - ppcd->cpMin;
+ if ((fn = ppcd->fn) == fnInsert)
+ { /* Special quick and dirty insert mode */
+ vpchFetch = rgchInsert + fc;
+ ccpChp = ccpFile = vccpFetch = max(0, ichInsert - (int) fc);
+ if (fcm & fcmProps)
+ {
+ ccpChp = vccpFetch;
+ blt(&vchpInsert, &vchpFetch, cwCHP);
+#ifdef STYLES
+ blt(PpropXlate(vdocFetch, &vchpFetch, &vpapAbs), &vchpAbs,
+ cwCHP);
+#else
+ blt(&vchpFetch, &vchpAbs, cwCHP);
+#endif
+ goto ParseCaps;
+ }
+ return;
+ }
+ prm = ppcd->prm;
+ }
+
+/* No monkeying with files after this statement, or we may page out */
+if (fcm & fcmChars)
+ {
+#ifdef ENABLE /* In WRITE, we cannot assume that vpchFetch will remain
+ valid, because we do our reading in multi-page chunks;
+ also, rgbp can move */
+
+ if (ccpFile > vccpFetch)
+ {
+ ccpFile -= vccpFetch;
+ vpchFetch += vccpFetch;
+ }
+ else
+#endif
+ {
+ int ccpT;
+ vpchFetch = PchFromFc(fn, fc, &ccpT); /* Read in buffer */
+ ccpFile = ccpT;
+ }
+ }
+
+if (fcm & fcmProps)
+ { /* There must be enough page buffers so that this will not
+ page out vpchFetch! */
+ if (ccpChp > vccpFetch)
+ ccpChp -= vccpFetch;
+ else
+ { /* CachePara must have been called prior to FetchCp */
+ int ccpT;
+ SetChp(&vchpFetch, &ccpT, fn, fc, prm);
+ ccpChp = ccpT;
+#ifdef CASHMERE /* no docBuffer in WRITE */
+ if(vdocFetch != docBuffer)
+#endif
+#ifdef STYLES
+ blt(PpropXlate(vdocFetch, &vchpFetch, &vpapAbs), &vchpAbs,
+ cwCHP);
+#else
+ blt(&vchpFetch, &vchpAbs, cwCHP);
+#endif
+ }
+ }
+
+/* Set vccpFetch to minimum of various restraining ccp's */
+vccpFetch = (ccpPcd >= 32767) ? 32767 : ccpPcd;
+if ((fcm & fcmChars) && ccpFile < vccpFetch) vccpFetch = ccpFile;
+if ((fcm & fcmProps) && ccpChp < vccpFetch) vccpFetch = ccpChp;
+
+ParseCaps:
+
+#ifdef CASHMERE
+if ((fcm & fcmParseCaps) != 0)
+ {
+ CHAR *pch;
+ int cch;
+
+ /* Brodie says this will not work for style sheet */
+ if (vchpFetch.csm == csmSmallCaps)
+ { /* Parse small caps into runs */
+ pch = &vpchFetch[0];
+ cch = vccpFetch - 1;
+ /* This either */
+ blt(&vchpFetch, &vchpAbs, cwCHP); /* because vchpAbs could be modified */
+ if (islower(*pch++))
+ {
+ while ((islower(*pch) || *pch == chSpace)
+ && cch-- != 0)
+ pch++;
+#ifndef SAND
+ vchpAbs.hps =
+ max(1, (vchpAbs.hps * 4 + 2) / 5);
+#endif
+ }
+ else
+ {
+ while (!islower(*pch) && cch-- != 0)
+ pch++;
+ vchpAbs.csm = csmNormal;
+ }
+ vccpFetch = min((int)ccpChp, pch - vpchFetch);
+ }
+ }
+#endif /* CASHMERE */
+
+vcchFetch = vccpFetch;
+} /* end of F e t c h C p */
+
+
+FetchRgch(pcch, pch, doc, cp, cpMac, cchMax)
+int *pcch, doc, cchMax;
+CHAR *pch;
+typeCP cp, cpMac;
+{
+int cch = 0;
+
+FetchCp(doc, cp, 0, fcmChars + fcmNoExpand);
+
+while (cch < cchMax && vcpFetch < cpMac)
+ {
+#ifdef INEFFICIENT
+ int ccp = (int) CpMin((typeCP) min(cchMax - cch, vccpFetch),
+ cpMac - vcpFetch);
+#endif
+ int ccp = cchMax - cch;
+ if (ccp > vccpFetch)
+ ccp = vccpFetch;
+ if (ccp > cpMac - vcpFetch)
+ ccp = cpMac - vcpFetch;
+
+ bltbyte(vpchFetch, pch, ccp);
+ pch += ccp;
+ cch += ccp;
+
+ if (ccp < vccpFetch)
+ break; /* Save some work */
+ FetchCp(docNil, cpNil, 0, fcmChars + fcmNoExpand);
+ }
+*pcch = cch;
+} /* end of F e t c h R g c h */
+
+
+int IpcdFromCp(ppctb, cp)
+struct PCTB *ppctb;
+typeCP cp;
+{ /* Binary search piece table for cp; return index */
+int ipcdLim = ppctb->ipcdMac;
+int ipcdMin = 0;
+struct PCD *rgpcd = ppctb->rgpcd;
+
+while (ipcdMin + 1 < ipcdLim)
+ {
+ int ipcdGuess = (ipcdMin + ipcdLim) >> 1;
+ typeCP cpGuess;
+ if ((cpGuess = rgpcd[ipcdGuess].cpMin) <= cp)
+ {
+ ipcdMin = ipcdGuess;
+ if (cp == cpGuess)
+ break; /* Hit it on the nose! */
+ }
+ else
+ ipcdLim = ipcdGuess;
+ }
+return ipcdMin;
+} /* end of I p c d F r o m C p */
+
+
+static SetChp(struct CHP *pchp, int *pcfcChp, int fn, typeFC fc, struct PRM prm)
+{ /* Fill pchp with char props; return length of run in *pcfcChp */
+struct FKP *pfkp;
+struct FCHP *pfchp;
+typeFC cfcChp;
+struct FCB *pfcb;
+
+pfcb = &(**hpfnfcb)[fn];
+cfcChp = pfcb->fcMac - fc;
+FreezeHp();
+
+if (fn == fnScratch && fc >= fcMacChpIns)
+ {
+ blt(&vchpInsert, pchp, cwCHP);
+ }
+else
+ {
+ if (pfcb->fFormatted)
+ { /* Copy necessary amt of formatting info over std CHP */
+ typeFC fcMac;
+ int cchT;
+ int bfchp;
+
+ blt(&vchpNormal, pchp, cwCHP);
+ pfkp = (struct FKP *) PchGetPn(fn, fn == fnScratch ?
+ PnFkpFromFcScr(&vfkpdCharIns, fc) :
+ pfcb->pnChar + IFromFc(**pfcb->hgfcChp, fc),
+ &cchT, false);
+ if (vfDiskError)
+ /* Serious disk error -- use default props */
+ goto DefaultCHP;
+
+ { /* In-line, fast substitute for BFromFc */
+ register struct RUN *prun = (struct RUN *) pfkp->rgb;
+
+ while (prun->fcLim <= fc)
+ prun++;
+
+ fcMac = prun->fcLim;
+ bfchp = prun->b;
+ }
+
+ if (bfchp != bNil)
+ {
+ pfchp = (struct FCHP *) &pfkp->rgb[bfchp];
+ bltbyte(pfchp->rgchChp, pchp, pfchp->cch);
+ }
+ cfcChp = fcMac - fc;
+ }
+ else
+ {
+DefaultCHP:
+ blt(&vchpNormal, pchp, cwCHP);
+ /* in case default size is different "normal" (which is
+ used for encoding our bin files */
+ pchp->hps = hpsDefault;
+ }
+ }
+
+if (!bPRMNIL(prm))
+ DoPrm(pchp, (struct PAP *) 0, prm);
+if (cfcChp > 32767)
+ *pcfcChp = 32767;
+else
+ *pcfcChp = cfcChp;
+MeltHp();
+} /* end of S e t C h p */
+
+
+typePN PnFkpFromFcScr(pfkpd, fc)
+struct FKPD *pfkpd;
+typeFC fc;
+{ /* Return page number in scratch file with props for char at fc. */
+struct BTE *pbte = **pfkpd->hgbte;
+int ibte = pfkpd->ibteMac;
+
+/* A short table, linear search? */
+while (ibte--)
+ if (pbte->fcLim > fc)
+ return pbte->pn;
+ else
+ pbte++;
+
+return pfkpd->pn; /* On current page. */
+} /* end of P n F k p F r o m F c S c r */
diff --git a/private/mvdm/wow16/write/ffdefs.h b/private/mvdm/wow16/write/ffdefs.h
new file mode 100644
index 000000000..52e85e716
--- /dev/null
+++ b/private/mvdm/wow16/write/ffdefs.h
@@ -0,0 +1,30 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+struct IFI
+ {
+ int xp;
+ int xpLeft;
+ int xpRight;
+ int xpReal;
+ int xpPr;
+ int xpPrRight;
+ int ich;
+ int ichLeft;
+ int ichPrev;
+ int ichFetch;
+ int dypLineSize;
+ int cchSpace;
+ int cBreak;
+ int chBreak;
+ int jc;
+
+#ifdef CASHMERE
+ int tlc;
+#endif /* CASHMERE */
+
+ int fPrevSpace;
+ };
+
+#define cwIFI (sizeof (struct IFI) / sizeof (int))
diff --git a/private/mvdm/wow16/write/file.c b/private/mvdm/wow16/write/file.c
new file mode 100644
index 000000000..d41de5d63
--- /dev/null
+++ b/private/mvdm/wow16/write/file.c
@@ -0,0 +1,1486 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* file.c -- WRITE file interface functions */
+/* It is important that the external interface to this module be entirely
+ at the level of "fn's", not "osfn's" and/or "rfn's". An intermodule call
+ may cause our files to be closed, and this is the only module internally
+ capable of compensating for this */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSMETRICS
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOFONT
+#define NOGDI
+#define NOHDC
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMSG
+#define NOPEN
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#define NOSTRUNDO
+#include "str.h"
+#include "debug.h"
+
+
+extern int vfDiskFull;
+extern int vfSysFull;
+extern int vfnWriting;
+extern CHAR (*rgbp)[cbSector];
+extern typeTS tsMruRfn;
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern struct FCB (**hpfnfcb)[];
+extern typeTS tsMruBps;
+extern struct ERFN dnrfn[rfnMax];
+extern int iibpHashMax;
+extern CHAR *rgibpHash;
+extern int rfnMac;
+extern int ferror;
+extern CHAR szWriteDocPrompt[];
+extern CHAR szScratchFilePrompt[];
+extern CHAR szSaveFilePrompt[];
+
+
+#ifdef CKSM
+#ifdef DEBUG
+extern unsigned (**hpibpcksm) [];
+extern int ibpCksmMax;
+#endif
+#endif
+
+
+#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax
+
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#define ErrorWithMsg( idpmt, szModule ) Error( idpmt )
+#define DiskErrorWithMsg( idpmt, szModule ) DiskError( idpmt )
+#endif
+
+
+#define osfnNil (-1)
+
+STATIC int near RfnGrab( void );
+STATIC int near FpeSeekFnPn( int, typePN );
+STATIC typeOSFN near OsfnEnsureValid( int );
+STATIC typeOSFN near OsfnReopenFn( int );
+STATIC CHAR *(near SzPromptFromFn( int ));
+
+/* The following debug flags are used to initiate, during debug, specific
+ low-level disk errors */
+
+#ifdef DEBUG
+int vfFakeReadErr = 0;
+int vfFakeWriteErr = 0;
+int vfFakeOpenErr = 0;
+#endif
+
+
+#ifdef CKSM
+#ifdef DEBUG
+unsigned CksmFromIbp( ibp )
+int ibp;
+{
+ int cb = mpibpbps [ibp].cch;
+ unsigned cksm = 0;
+ CHAR *pb;
+
+ Assert( ibp >= 0 && ibp < ibpCksmMax );
+ Assert( mpibpbps [ibp].fn != fnNil );
+ Assert( !mpibpbps [ibp].fDirty );
+
+ pb = rgbp [ibp];
+ while (cb-- > 0)
+ cksm += *(pb++);
+
+ return cksm;
+}
+#endif
+#endif
+
+
+
+typeFC FcMacFromUnformattedFn( fn )
+int fn;
+{ /* Obtain fcMac for passed unformatted fn by seeking to the file's end.
+ If it fails, return -1
+ If it succeeds, return the fcMac */
+ typeFC fcMac;
+ typeOSFN osfn;
+
+ Assert( (fn != fnNil) && (!(**hpfnfcb) [fn].fFormatted) );
+
+ if ((osfn = OsfnEnsureValid( fn )) == osfnNil)
+ return (typeFC) -1;
+ else
+ {
+ if ( FIsErrDwSeek( fcMac=DwSeekDw( osfn, 0L, SF_END )))
+ {
+ if (fcMac == fpeBadHndError)
+ { /* Windows closed the file for us */
+ if ( ((osfn = OsfnReopenFn( fn )) != osfnNil) &&
+ !FIsErrDwSeek( fcMac = DwSeekDw( osfn, 0L, SF_END )) )
+ /* Successfully re-opened file */
+ return fcMac;
+ }
+ if (FIsCaughtDwSeekErr( fcMac ))
+ /* Suppress reporting of error -- Windows did it */
+ ferror = TRUE;
+ DiskErrorWithMsg(IDPMTSDE, " FcMacFromUnformattedFn");
+ return (typeFC) -1;
+ }
+ }
+
+return fcMac;
+}
+
+
+
+
+IbpLru(ibpStarting)
+int ibpStarting;
+/*
+ Description: Find least recently used BPS (Buffer page) starting
+ at slot ibpStarting.
+ Returns: Number of the least recently used buffer slot.
+*/
+{
+ int ibp, ibpLru = 0;
+ typeTS ts, tsLru;
+ struct BPS *pbps = &mpibpbps[ibpStarting];
+
+ tsLru = -1; /* Since time stamps are unsigned ints, -1 */
+ /* is largest time stamp. */
+ for(ibp = ibpStarting; ibp < ibpMax; ibp++, pbps++)
+ {
+ ts = pbps->ts - (tsMruBps + 1);
+ /* The time stamp can conceivably wrap around and thus a */
+ /* simple < or > comparison between time stamps cannot be */
+ /* used to determine which is more or less recently used. */
+ /* The above statement normalizes time stamps so that the */
+ /* most recently used is FFFF and the others fall between */
+ /* 0 and FFFE. This method makes the assumption that */
+ /* time stamps older than 2^16 clicks of the time stamp */
+ /* counter have long since disappeared. Otherwise, such */
+ /* ancients would appear to be what they are not. */
+ if (ts <= tsLru) {tsLru = ts; ibpLru = ibp;}
+ }
+ return(ibpLru);
+}
+
+
+
+
+int IbpMakeValid(fn, pn)
+int fn;
+typePN pn;
+{ /*
+ Description: Get page pn of file fn into memory.
+ Assume not already in memory.
+ Returns: Bp index (buffer slot #) where the page resides
+ in memory.
+ */
+#define cbpClump 4
+
+#define cpnAlign 4
+#define ALIGN
+
+int ibpT, cbpRead;
+int ibp, iibpHash, ibpPrev;
+typePN pnT;
+register struct BPS *pbps;
+int ibpNew;
+int cch;
+int fFileFlushed;
+#ifdef ALIGN
+int dibpAlign;
+#endif
+
+#ifdef DEBUG
+ int cbpReadT;
+ CheckIbp();
+#endif /* DEBUG */
+ Assert(fn != fnNil);
+
+/* page is not currently in memory */
+
+/* We will try to read in cbpClump Buffer Pages beginning with the
+ least recently used */
+
+ /* Pick best starting slot for read based on a least-recently-used scheme */
+
+ if (vfnWriting != fnNil)
+ /* Currently saving file, favor adjacent slots for fn being written */
+ ibpNew = IbpWriting( fn );
+ else
+ /* If reading from the scratch file, do not use the first
+ cpbMustKeep slots. This is necessary to prevent a disk full
+ condition from being catastrophic. */
+ ibpNew = IbpLru( (fn == fnScratch) ? cbpMustKeep : 0 );
+
+
+ /* Empty the slots by flushing out ALL buffers holding pieces of their fn's */
+ /* Compute cbpRead */
+ pbps = &mpibpbps[ ibpNew ];
+ for ( cbpRead = 0; cbpRead < min( cbpClump, ibpMax - ibpNew );
+ cbpRead++, pbps++ )
+ {
+#ifdef CKSM
+#ifdef DEBUG
+ int ibpT = pbps - mpibpbps;
+
+ if (!pbps->fDirty && pbps->fn != fnNil)
+ Assert( (**hpibpcksm) [ibpT] == CksmFromIbp( ibpT ) );
+#endif
+#endif
+ if (pbps->fDirty && pbps->fn != fnNil)
+ if (!FFlushFn( pbps->fn ))
+ break;
+ }
+
+ /* If a flush failed, cbpRead was reduced. If it was reduced to 0, this
+ is serious. If the file was not fnScratch, we can consider it flushed
+ even though the flush failed, because upper-level procedures will detect
+ the error and cancel the operation. If it was fnScratch, we must obtain
+ a new slot for the page we are trying to read */
+ if (cbpRead == 0)
+ {
+ if (pbps->fn == fnScratch)
+ ibpNew = IbpFindSlot( fn );
+ cbpRead++;
+ }
+ else
+ { /* Restrict cbpRead according to the following:
+ (1) If we are reading in the text area, we don't want to
+ free pages for stuff past the end of the text area
+ that we know CchPageIn won't give us
+ (2) If we are reading in the properties area, we only want to
+ read one page, because FetchCp depends on us not trashing
+ the MRU page */
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+
+ if (pfcb->fFormatted && fn != fnScratch && pn >= pfcb->pnChar)
+ cbpRead = 1;
+ else
+ {
+ typePN cbpValid = (pfcb->fcMac - (pn * cfcPage)) / cfcPage;
+
+ cbpRead = min( cbpRead, max( 1, cbpValid ) );
+ }
+ }
+
+#ifdef ALIGN
+ /* Align the read request on an even sector boundary, for speed */
+ dibpAlign = (pn % cpnAlign);
+ if (cbpRead > dibpAlign)
+ /* We are reading enough pages to cover the desired one */
+ pn -= dibpAlign;
+ else
+ dibpAlign = 0;
+#endif
+
+ /* Remove flushed slots from their hash chains */
+ for ( pbps = &mpibpbps[ ibpT = ibpNew + cbpRead - 1 ];
+ ibpT >= ibpNew;
+ ibpT--, pbps-- )
+ if (pbps->fn != fnNil)
+ FreeBufferPage( pbps->fn, pbps->pn );
+
+ /* Free slots holding any existing copies of pages to be read */
+#ifdef DBCS /* was in KKBUGFIX */
+/* In #else code ,If pn= 8000H(= -32768), pnT can not be littler than pn */
+ for ( pnT = pn + cbpRead; pnT > pn; pnT-- ) // Assume cbpRead > 0
+#else
+ for ( pnT = pn + cbpRead - 1; (int)pnT >= (int)pn; pnT-- )
+#endif
+
+ FreeBufferPage( fn, pnT );
+
+ /* Read contents of file page(s) into buffer slot(s) */
+ cch = CchPageIn( fn, pn, rgbp[ibpNew], cbpRead );
+
+#ifdef DEBUG
+ cbpReadT = cbpRead;
+#endif
+
+ /* Fill in bps records for as many bytes as were read, but always
+ at least one record (to support PnAlloc). If we reached the end of the
+ file, the unfilled bps slots are left free */
+ pbps = &mpibpbps[ ibpT = ibpNew ];
+ do
+ {
+ pbps->fn = fn;
+ pbps->pn = pn;
+ pbps->ts = ++tsMruBps; /* mark page as MRUsed */
+ pbps->fDirty = false;
+ pbps->cch = min( cch, cbSector );
+ pbps->ibpHashNext = ibpNil;
+
+ cch = max( cch - cbSector, 0 );
+
+ /* put in new hash table entry for fn,pn */
+ iibpHash = IibpHash(fn, pn);
+ ibp = rgibpHash[iibpHash];
+ ibpPrev = ibpNil;
+ while (ibp != ibpNil)
+ {
+ ibpPrev = ibp;
+ ibp = mpibpbps[ibp].ibpHashNext;
+ }
+ if (ibpPrev == ibpNil)
+ rgibpHash[iibpHash] = ibpT;
+ else
+ mpibpbps[ibpPrev].ibpHashNext = ibpT;
+
+ pn++; ibpT++; pbps++;
+
+ } while ( (--cbpRead > 0) && (cch > 0) );
+
+#ifdef CKSM
+#ifdef DEBUG
+ /* Compute checksums for newly read pages */
+
+ {
+ int ibp;
+
+ for ( ibp = ibpNew; ibp < ibpNew + cbpReadT; ibp++ )
+ if (mpibpbps [ibp].fn != fnNil && !mpibpbps [ibp].fDirty)
+ (**hpibpcksm) [ibp] = CksmFromIbp( ibp );
+ }
+ CheckIbp();
+#endif /* DEBUG */
+#endif
+
+#ifdef ALIGN
+ return (ibpNew + dibpAlign);
+#else
+ return (ibpNew);
+#endif
+} /* end of I b p M a k e V a l i d */
+
+
+
+
+FreeBufferPage( fn, pn )
+int fn;
+int pn;
+{ /* Free buffer page holding page pn of file fn if there is one */
+ /* Flushes fn if page is dirty */
+ int iibp = IibpHash( fn, pn );
+ int ibp = rgibpHash[ iibp ];
+ int ibpPrev = ibpNil;
+
+ Assert( fn != fnNil );
+ while (ibp != ibpNil)
+ {
+ struct BPS *pbps=&mpibpbps[ ibp ];
+
+ if ( (pbps->fn == fn) && (pbps->pn == pn ) )
+ { /* Found it. Remove this page from the chain & mark it free */
+
+ if (pbps->fDirty)
+ FFlushFn( fn );
+#ifdef CKSM
+#ifdef DEBUG
+ else /* Page has not been trashed while in memory */
+ {
+ Assert( (**hpibpcksm) [ibp] == CksmFromIbp( ibp ) );
+ }
+#endif
+#endif
+
+ if (ibpPrev == ibpNil)
+ /* First entry in hash chain */
+ rgibpHash [ iibp ] = pbps->ibpHashNext;
+ else
+ mpibpbps[ ibpPrev ].ibpHashNext = pbps->ibpHashNext;
+
+ pbps->fn = fnNil;
+ pbps->fDirty = FALSE;
+ /* Mark the page not recently used */
+ pbps->ts = tsMruBps - (ibpMax * 4);
+ /* Mark pages that are on even clump boundaries a bit less recently
+ used so they are favored in new allocations */
+ if (ibp % cbpClump == 0)
+ --(pbps->ts);
+ pbps->ibpHashNext = ibpNil;
+ }
+ ibpPrev = ibp;
+ ibp = pbps->ibpHashNext;
+ }
+#ifdef DEBUG
+ CheckIbp();
+#endif
+}
+
+
+
+
+int CchPageIn(fn, pn, rgbBuf, cpnRead)
+int fn;
+typePN pn;
+CHAR rgbBuf[];
+int cpnRead;
+{ /*
+ Description: Read a cpnRead pages of file fn from disk into rgbBuf.
+ Have already determined that page is not resident
+ in the buffer.
+ Returns: Number of valid chars read (zero or positive #).
+ */
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ typeFC fcMac = pfcb->fcMac;
+ typeFC fcPage = pn * cfcPage;
+ int dfc;
+ int fCharFormatInfo; /* if reading Format info part of */
+ /* file then = TRUE, text part of */
+ /* file then = FALSE; */
+
+ /* No reads > 32767 bytes, so dfc can be int */
+ Assert( cpnRead <= 32767 / cbSector );
+
+ /* Don't try to read beyond pnMac */
+ if (cpnRead > pfcb->pnMac - pn)
+ cpnRead = pfcb->pnMac - pn;
+
+ dfc = cpnRead * (int)cfcPage;
+
+ if (pn >= pfcb->pnMac) /* are we trying to read beyond eof? */
+ {
+ return 0; /* Nothing to read */
+ }
+ else if (pfcb->fFormatted && fn != fnScratch
+ && fn != vfnWriting /* Since pnChar is zero in this case */
+ && pn >= pfcb->pnChar)
+ { /* reading character format info portion of file */
+ fCharFormatInfo = TRUE;
+ }
+ else /* reading text portion of file */
+ { /* get dfc (cch) from fcMac */
+ typeFC dfcT = fcMac - fcPage;
+
+ fCharFormatInfo = FALSE;
+ if (dfcT < dfc)
+ dfc = (int) dfcT;
+ else if (dfc <= fc0) /* Nothing to read, so let's avoid disk access. */
+ {
+ return 0;
+ }
+ }
+
+ return CchReadAtPage( fn, pn, rgbBuf, (int)dfc, fCharFormatInfo );
+}
+
+
+
+
+CchReadAtPage( fn, pn, rgb, dfc, fSeriousErr )
+int fn;
+typePN pn;
+CHAR rgb[];
+int dfc;
+int fSeriousErr;
+{ /*
+ Description: Read dfc bytes of file fn starting at page pn
+ into rgb
+ Returns: Number of valid chars read (zero or positive #)
+ Errors: Returns # of chars read; ferror & vfDiskFull are
+ set (in DiskError) if an error occurs.
+ Notes: Caller is responsible for assuring that the page
+ range read is reasonable wrt the fn
+ */
+
+ typeOSFN osfn;
+ int fpeSeek;
+ int fpeRead;
+ int fCaught; /* Whether error was reported by DOS */
+
+#ifdef DEBUG
+
+ if (vfFakeReadErr)
+ {
+ dfc = 0;
+ goto ReportErr;
+ }
+#endif
+
+ if (!FIsErrFpe( fpeSeek = FpeSeekFnPn( fn, pn )))
+ {
+ osfn = OsfnEnsureValid( fn );
+
+#ifdef DEBUG
+#ifdef DFILE
+ CommSzSz( "Read from file: ", &(**(**hpfnfcb)[fn].hszFile)[0] );
+#endif
+#endif
+
+ if ((fpeRead = CchReadDoshnd( osfn, (CHAR FAR *)rgb, dfc )) == dfc)
+ { /* Read succeeded */
+ return dfc;
+ }
+ else
+ {
+ /* Should be guaranteed that file was not closed because of seek */
+ Assert( fpeRead != fpeBadHndError );
+
+ fCaught = FIsCaughtFpe( fpeRead );
+ }
+ }
+ else
+ fCaught = FIsCaughtFpe( fpeSeek );
+
+ /* unable to set position or read */
+ if ((fn == fnScratch) || (fSeriousErr))
+ { /* unrecoverable error: either can't read from scratch */
+ /* file or unable to read format info (FIB or format pages) part of */
+ /* of some file. */
+ dfc = 0;
+ goto ReportErr;
+ }
+ else /* serious disk error on file (recoverable).*/
+ {
+ int cchRead = (FIsErrFpe(fpeSeek) || FIsErrFpe(fpeRead)) ? 0 : fpeRead;
+ CHAR *pch = &rgb[cchRead];
+ int cch = dfc - cchRead;
+
+ /* If the positioning failed or the read failed
+ for a reason other than disk full, completely
+ fill the buffer with 'X's. Otherwise, just
+ fill the disputed portion (diff between #char
+ requested and #char read) with 'X's */
+
+ while (cch-- > 0)
+ *pch++ = 'X';
+
+ReportErr:
+ if (fCaught)
+ /* Suppress reporting of the error -- Windows reported it */
+ ferror = TRUE;
+
+ if (pn != 0)
+ /* Report error if not reading FIB */
+ DiskErrorWithMsg(IDPMTSDE, " CchReadAtPage");
+
+ return (int)dfc;
+ /* recovery is accomplished: 1) Upper level procedures do not
+ see any change in the world, 2) the worst thing that
+ happens is that the user sees some 'X's on the screen. */
+ }
+}
+
+
+
+
+AlignFn(fn, cch, fEven)
+int fn, cch;
+{ /* Make sure we have cch contiguous chars in fn */
+/* if fEven, make sure fcMac is even */
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ typeFC fcMac = pfcb->fcMac;
+ typePN pn;
+ typeFC fcFirstPage;
+
+ pn = fcMac / cfcPage;
+ fcFirstPage = (pn + 1) * cfcPage;
+
+ Assert(cch <= cfcPage);
+
+ if (fEven && (fcMac & 1) != 0)
+ ++cch;
+
+ if (fcFirstPage - fcMac < cch)
+ {
+ struct BPS *pbps = &mpibpbps[IbpEnsureValid(fn, pn++)];
+ pbps->cch = cfcPage;
+ pbps->fDirty = true;
+ fcMac = pfcb->fcMac = fcFirstPage;
+ }
+
+ if (fEven && (fcMac & 1) != 0)
+ {
+ struct BPS *pbps = &mpibpbps[IbpEnsureValid(fn, pn)];
+ pbps->cch++;
+ pbps->fDirty = true;
+ pfcb->fcMac++;
+ }
+} /* end of A l i g n F n */
+
+
+
+
+/*** OsfnEnsureValid - ensure that file fn is open
+ *
+ *
+ */
+
+STATIC typeOSFN near OsfnEnsureValid(fn)
+int fn;
+{ /*
+ Description: Ensure that file fn is open (really)
+ Returns: operating system file number (osfnNil if error)
+ */
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ int rfn = pfcb->rfn;
+
+ if (rfn == rfnNil)
+ { /* file doesn't have a rfn - ie. it is not opened */
+#ifdef DEBUG
+#ifdef DFILE
+ CommSzSz( pfcb->fOpened ? "Re-opening file " :
+ "Opening file", **pfcb->hszFile );
+#endif
+ if (vfFakeOpenErr || !FAccessFn( fn, dtyNormal ))
+#else
+ if (!FAccessFn( fn, dtyNormal ))
+#endif
+ { /* unrecoverable error - unable to open file */
+ DiskErrorWithMsg(IDPMTSDE, " OsfnEnsureValid");
+ return osfnNil;
+ }
+ rfn = pfcb->rfn;
+ Assert( (rfn >= 0) && (rfn < rfnMac) );
+ }
+ return dnrfn[rfn].osfn;
+}
+/* end of O s F n E n s u r e V a l i d */
+
+
+
+
+STATIC int near FpeSeekFnPn( fn, pn )
+int fn;
+typePN pn;
+{ /* Seek to page pn of file fn
+ return err code on failure, fpeNoErr on success
+ Leaves file open (if no error occurs)
+ Recovers from the case in which windows closed the file for us
+ */
+ typeOSFN osfn;
+ long dwSeekReq;
+ long dwSeekAct;
+
+#ifdef DEBUG
+#ifdef DFILE
+ CommSzSz( "Seeking within file ", **(**hpfnfcb)[fn].hszFile );
+#endif
+#endif
+
+ //osfn = OsfnEnsureValid( fn );
+ if ((osfn = OsfnEnsureValid( fn )) == osfnNil)
+ return fpeNoAccError;
+ dwSeekReq = (long) pn * (long) cbSector;
+ dwSeekAct = DwSeekDw( osfn, dwSeekReq, SF_BEGINNING);
+
+ if ( ((int) dwSeekAct) == fpeBadHndError )
+ { /* Windows closed the file for us -- must reopen it */
+ if ((osfn = OsfnReopenFn( fn )) == osfnNil)
+ return fpeNoAccError;
+ else
+ dwSeekAct = DwSeekDw( osfn, dwSeekReq, SF_BEGINNING );
+ }
+
+ return (dwSeekAct >= 0) ? fpeNoErr : (int) dwSeekAct;
+}
+
+
+
+
+int FFlushFn(fn)
+int fn;
+{ /*
+ Description: Write all dirty pages of fn to disk.
+ Sets vfSysFull = TRUE if disk full error occurred
+ while flushing fnScratch. Otherwise, a disk full
+ error causes vfDiskFull = TRUE.
+ Serious disk errors cause vfDiskError = TRUE
+ Only the pages which actually made it to disk are
+ marked as non-dirty.
+ Returns: TRUE if successful, FALSE if Disk full error
+ while writing pages to disk. Any other error
+ is unrecoverable, ie. go back to main loop.
+ To avoid extraneous error messages, the following
+ two entry conditions cause FFlush to immediately
+ return FALSE:
+ - If vfSysFull = TRUE and fn = fnScratch
+ - If vfDiskFull = TRUE and fn = vfnWriting
+ */
+int ibp;
+typeOSFN osfn;
+int fpe;
+int cchWritten;
+int cchAskWrite;
+struct BPS *pbps;
+
+Assert( fn != fnNil );
+
+if ((vfSysFull) && (fn == fnScratch)) return (FALSE);
+if ((vfDiskFull) && (fn == vfnWriting)) return (FALSE);
+
+for (ibp = 0, pbps = mpibpbps; ibp < ibpMax; )
+ {
+ if (pbps->fn == fn && pbps->fDirty)
+ {
+ typePN pn = pbps->pn;
+ int cbp = 0;
+ CHAR *pch = (CHAR *)rgbp[ibp];
+ struct BPS *pbpsStart = &mpibpbps[ibp];
+
+
+ /* Coalesce all consecutive pages for a single write */
+ do
+ {
+ /* taken out 11/7/84 - can't mark scratch file
+ page as non dirty if chance that it will never
+ get written out (write fails - disk full)
+ pbps->fDirty = false; mark page as clean */
+ ++ibp, ++cbp, ++pbps;
+ } while (ibp < ibpMax && pbps->fn == fn && pbps->pn == pn + cbp);
+
+ /* Now do the write, checking for out of disk space */
+ Scribble(3, 'W');
+
+ cchAskWrite = (int)cbSector * (cbp - 1) + (pbps - 1)->cch;
+ cchWritten = cchDiskHardError; /* assure hard error if seek fails */
+
+#ifdef DEBUG
+ if (vfFakeWriteErr)
+ goto SeriousError;
+ else
+#endif
+ if ( FIsErrFpe( FpeSeekFnPn( fn, pn )) ||
+ ((osfn = OsfnEnsureValid( fn )) == osfnNil) ||
+#ifdef DEBUG
+#ifdef DFILE
+ (CommSzSz( "Writing to file: ", &(**(**hpfnfcb)[fn].hszFile)[0] ),
+#endif
+#endif
+ (( cchWritten = CchWriteDoshnd( osfn, (CHAR FAR *)pch,
+ cchAskWrite )) != cchAskWrite))
+#ifdef DEBUG
+#ifdef DFILE
+ )
+#endif
+#endif
+ {
+ /* Should be guaranteed that windows did not close the file
+ since we have not called intermodule since the seek */
+ Assert( cchWritten != fpeBadHndError );
+
+ /* Seek or Write error */
+ if ( !FIsErrCchDisk(cchWritten) )
+ { /* serious but recoverable disk error */
+ /* Ran out of disk space; write failed */
+ if (fn == fnScratch)
+ vfSysFull = fTrue;
+ vfDiskFull = fTrue;
+ DiskErrorWithMsg(IDPMTDFULL, " FFlushFn");
+ return(FALSE);
+ }
+ else /* cause of error is not disk full */
+ { /* unrecov. disk error */
+#ifdef DEBUG
+SeriousError:
+#endif
+ DiskErrorWithMsg(IDPMTSDE2, " FFlushFn");
+ return FALSE;
+ }
+ }
+ Diag(CommSzNumNum(" cchWritten, cchAskWrite ",cchWritten,cchAskWrite));
+
+ /* ---- write was successful ---- */
+ Scribble(3, ' ');
+ while (cbp-- > 0)
+ { /* mark pages actually copied to disk as non dirty */
+ (pbpsStart++)->fDirty = false;
+#ifdef CKSM
+#ifdef DEBUG
+ {
+ int ibpT = pbpsStart - 1 - mpibpbps;
+ /* Recompute checksums for pages which are now clean */
+ (**hpibpcksm) [ibpT] = CksmFromIbp( ibpT );
+ }
+#endif
+#endif
+ }
+ }
+ else
+ {
+ ++ibp;
+ ++pbps;
+ }
+ }
+return (TRUE);
+}
+
+
+#ifdef DEBUG
+CheckIbp()
+ {
+ /* Walk through the rgibpHash and the mpibpbps structure to make sure all of
+ the links are right. */
+
+ /* 10/11/85 - Added extra Assert ( FALSE ) so we get the messages instead
+ of a freeze-up on systems not connected to a COM port.
+ Ignoring the assertion will produce the RIP with the ibp info */
+ extern int fIbpCheck;
+ int rgfibp[255];
+ int ibp;
+ int ibpHash;
+ int iibp;
+ static BOOL bAsserted=FALSE;
+
+ if (fIbpCheck && !bAsserted)
+ {
+ if (!(ibpMax < 256))
+ {
+ Assert(0);
+ bAsserted=TRUE;
+ return;
+ }
+
+ bltc(rgfibp, false, ibpMax);
+
+ /* Are there any circular links in mpibpbps? */
+ for (iibp = 0; iibp < iibpHashMax; iibp++)
+ {
+ if ((ibpHash = rgibpHash[iibp]) != ibpNil)
+ {
+ if (!(ibpHash < ibpMax))
+ {
+ Assert(0);
+ bAsserted=TRUE;
+ return;
+ }
+ if (rgfibp[ibpHash])
+ {
+ /* Each entry in rgibpHash should point to an unique chain.
+ */
+ Assert(0);
+ bAsserted=TRUE;
+#if DUGSTUB
+ FatalExit(0x100 | ibp);
+#endif
+ return;
+ }
+ else
+ {
+ rgfibp[ibpHash] = true;
+ while ((ibpHash = mpibpbps[ibpHash].ibpHashNext) != ibpNil)
+ {
+ if (!(ibpHash < ibpMax))
+ {
+ Assert(0);
+ bAsserted=TRUE;
+ return;
+ }
+ if (rgfibp[ibpHash])
+ {
+ /* The chain should be non-circular and unique. */
+ Assert( FALSE );
+ bAsserted=TRUE;
+#if DUGSTUB
+ FatalExit(0x200 | ibpHash);
+#endif
+ return;
+ }
+ rgfibp[ibpHash] = true;
+ }
+ }
+ }
+ }
+
+ /* All chains not pointed to by rgibpHash should be nil. */
+ for (ibp = 0; ibp < ibpMax; ibp++)
+ {
+ if (!rgfibp[ibp])
+ {
+ if (mpibpbps[ibp].fn != fnNil)
+ {
+ Assert( FALSE );
+ bAsserted=TRUE;
+#if DUGSTUB
+ FatalExit(0x400 | mpibpbps[ibp].fn);
+#endif
+ return;
+ }
+ if (mpibpbps[ibp].ibpHashNext != ibpNil)
+ {
+ Assert( FALSE );
+ bAsserted=TRUE;
+#if DUGSTUB
+ FatalExit(0x300 | ibp);
+#endif
+ return;
+ }
+ }
+ }
+ }
+ }
+#endif /* DEBUG */
+
+
+/* Formerly fileOC.c -- file open and close routines */
+
+
+/*** SetRfnMac - set usable # of rfn slots
+ *
+ * ENTRY: crfn - desired # of rfn slots
+ * EXIT: (global) rfnMac - set to crfn, if possible
+ *
+ * The ability to adjust the usable # of rfn slots is a new addition in
+ * Windows Word. The two things that it accomplishes are:
+ *
+ * (1) Gives the ability for Word to scale back its need for
+ * DOS file handles if not enough are available
+ * (2) Permits Word to attempt to grab more file handles than usual
+ * when this would help performance (in particular, during
+ * Transfer Save, when the original, scratch, and write files
+ * are most commonly open)
+ *
+ */
+
+SetRfnMac( crfn )
+int crfn;
+{
+ int rfn;
+
+ Assert( (crfn > 0) && (crfn <= rfnMax) );
+ Assert( (sizeof (struct ERFN) & 1) == 0); /* ERFN must be even for blt */
+
+ if (crfn > rfnMac)
+ { /* Add rfn slots */
+
+ for ( rfn = rfnMac; rfn < crfn; rfn++ )
+ dnrfn [rfn].fn = fnNil; /* These will get used next (see RfnGrab)*/
+ rfnMac = crfn;
+ }
+
+ else /* Lose Rfn slots (keep the most recently used one(s)) */
+ while ( rfnMac > crfn )
+ {
+ int rfnLru=RfnGrab();
+ int fn;
+
+ if ( (rfnLru != --rfnMac) && ((fn = dnrfn [rfnMac].fn) != fnNil) )
+ {
+ extern int fnMac;
+
+ Assert( fn >= 0 && fn < fnMac );
+ (**hpfnfcb) [fn].rfn = rfnLru;
+ blt( &dnrfn [rfnMac], &dnrfn [rfnLru],
+ sizeof(struct ERFN)/sizeof(int) );
+ }
+ }
+}
+
+
+
+
+
+/*========================================================*/
+STATIC int near RfnGrab()
+{ /*
+ Description: Allocate the least recently used rfn (real file #)
+ slot for a new file.
+ Returns: rfn slot number. */
+
+ int rfn = 0, rfnLru = 0;
+ typeTS ts, tsLru;
+ struct ERFN *perfn = &dnrfn[rfn];
+
+ /* Time stamp algorithm akin to method used with Bps. */
+ /* See IbpLru in file.c for comments. */
+
+ tsLru = -1; /* max unsigned number */
+ for ( rfn = 0; rfn < rfnMac ; rfn++, perfn++ )
+ {
+ ts = perfn->ts - (tsMruRfn + 1);
+ if (perfn->fn == fnNil)
+ ts = ts - rfnMac;
+
+ /* cluge: If slot is unused, give it a lower ts. */
+ /* This ensures that an occupied slot can never be */
+ /* swapped out if a empty one exists. */
+ if (ts <= tsLru)
+ {
+ tsLru = ts;
+ rfnLru = rfn;
+ }
+ }
+
+ if (dnrfn [rfnLru].fn != fnNil)
+ CloseRfn( rfnLru );
+ return rfnLru;
+}
+
+
+
+
+CloseFn( fn )
+int fn;
+{ /* Close file fn if it is currently open */
+ int rfn;
+
+ if (fn == fnNil)
+ return;
+
+ if (((rfn = (**hpfnfcb)[fn].rfn) != rfnNil) && (rfn != rfnFree))
+ CloseRfn( rfn );
+}
+
+
+
+
+OpenEveryHardFn()
+{ /* For each fn representing a file on nonremoveable media,
+ try to open it. It is not guaranteed that any or all such files
+ will be open on return from this routine -- we are merely attempting
+ to assert our ownership of these files on a network by keeping them open */
+
+ extern int fnMac;
+ int fn;
+ struct FCB *pfcb;
+
+#ifdef DFILE
+extern int docCur;
+CommSzNum("OpenEveryHardFn: docCur ", docCur);
+#endif
+
+ for ( fn = 0, pfcb = &(**hpfnfcb) [0] ; fn < fnMac; fn++, pfcb++ )
+ {
+/* Bryanl 3/26/87: only call FAccessFn if rfn == rfnNil, to prevent
+ multiple opens of the same file, which fail if the sharer is loaded */
+#ifdef DFILE
+ {
+ char rgch[100];
+ if (pfcb->rfn == rfnNil && ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk)
+ {
+ wsprintf(rgch," fn %d, hszFile %s \n\r",fn,(LPSTR)(**pfcb->hszFile));
+ CommSz(rgch);
+ wsprintf(rgch," OFSTR %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
+ CommSz(rgch);
+ }
+ else
+ {
+ wsprintf(rgch," fn %d, not accessing, sz %s\n\r", fn, (LPSTR) (LPSTR)(**pfcb->hszFile));
+ CommSz(rgch);
+ wsprintf(rgch," OFSTR %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
+ CommSz(rgch);
+ }
+ }
+#endif
+ if (pfcb->rfn == rfnNil && ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk)
+ { /* fn refers to a file on nonremoveable media */
+ FAccessFn( fn, dtyNormal );
+ }
+ }
+}
+
+
+
+
+STATIC typeOSFN near OsfnReopenFn( fn )
+int fn;
+{ /* Reopen file fn after it was automatically closed by Windows due
+ to disk swap. State is: fn has an rfn but rfn's osfn has been
+ made a "bad handle" */
+
+ struct FCB *pfcb = &(**hpfnfcb) [fn];
+ int rfn = pfcb->rfn;
+ typeOSFN osfn;
+ WORD wOpen;
+
+ Assert( fn != fnNil );
+ Assert( rfn != rfnNil );
+ Assert( pfcb->fOpened);
+
+ /* Only files on floppies are automatically closed */
+ Assert( ! ((POFSTRUCT)(pfcb->rgbOpenFileBuf))->fFixedDisk );
+
+#ifdef DEBUG
+#ifdef DFILE
+ CommSzSz( "Opening after WINDOWS close: ", **pfcb->hszFile );
+#endif
+#endif
+
+ wOpen = OF_REOPEN | OF_PROMPT | OF_CANCEL | OF_SHARE_DENY_WRITE |
+ ((pfcb->mdFile == mdBinary) ? OF_READWRITE : OF_READ );
+
+ SetErrorMode(1);
+ osfn = OpenFile( (LPSTR) SzPromptFromFn( fn ),
+ (LPOFSTRUCT) pfcb->rgbOpenFileBuf, wOpen );
+ SetErrorMode(0);
+
+ if (osfn == -1)
+ return osfnNil;
+ else
+ {
+ dnrfn[ rfn ].osfn = osfn;
+ }
+ return osfn;
+}
+
+
+
+
+FAccessFn( fn, dty)
+int fn;
+int dty;
+{ /* Description: Access file which is not currently opened.
+ Open file and make an appropriate entry in the
+ rfn table. Put the rfn into (**hpfnfcb)[fn].rfn.
+ Returns: TRUE on success, FALSE on failure
+ */
+extern int vwDosVersion;
+extern HANDLE hParentWw;
+extern HWND vhWndMsgBoxParent;
+
+int rfn;
+register struct FCB *pfcb = &(**hpfnfcb)[fn];
+typeOSFN osfn;
+int wOpen;
+
+#ifdef DEBUG
+int junk;
+
+ Assert(FValidFile(**pfcb->hszFile, CchSz(**pfcb->hszFile)-1, &junk));
+
+#ifdef DFILE
+ {
+ char rgch[100];
+
+ CommSzSz("FAccessFn: ", pfcb->fOpened ? SzPromptFromFn( fn ) : &(**pfcb->hszFile)[0]);
+ wsprintf(rgch, " * OFSTR before %s \n\r", (LPSTR)(((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName));
+ CommSz(rgch);
+ }
+#endif
+#endif /*DEBUG*/
+
+ if ((**pfcb->hszFile)[0] == 0) /* if file name field is blank, */
+ return FALSE; /* unable to open file */
+
+ wOpen = /*OF_PROMPT + OF_CANCEL + (6.21.91) v-dougk bug #6910 */
+ (((pfcb->mdFile == mdBinary) ?
+ OF_READWRITE : OF_READ) |
+ OF_SHARE_DENY_WRITE);
+ if (pfcb->fOpened)
+ wOpen += OF_REOPEN;
+ else if (pfcb->fSearchPath)
+ wOpen += OF_VERIFY;
+
+ if ((vwDosVersion & 0x7F) >= 2)
+ {
+ WORD da;
+
+ if ((vwDosVersion & 0x7F) >= 3)
+ /* Above DOS 3, set attributes to deny access if the sharer is in */
+ wOpen += bSHARE_DENYRDWR;
+
+ if ( ( (pfcb->mdFile == mdBinary) && (!pfcb->fOpened)) &&
+ ((da = DaGetFileModeSz( &(**pfcb->hszFile) [0] )) != DA_NIL) &&
+ (da & DA_READONLY) )
+ { /* This is here because the Novell net does not allow us to test
+ for read-only files by opening in read/write mode -- it lets
+ us open them anyway! */
+ goto TryReadOnly;
+ }
+ }
+
+ for ( ;; )
+ {
+ /* OpenFile's first parm is a filename when opening for the
+ first time, a prompt on successive occasions (OF_REOPEN) */
+
+ SetErrorMode(1);
+ osfn = OpenFile( pfcb->fOpened ?
+ (LPSTR) SzPromptFromFn( fn ) :
+ (LPSTR) &(**pfcb->hszFile)[0],
+ (LPOFSTRUCT) &pfcb->rgbOpenFileBuf[0],
+ wOpen );
+ SetErrorMode(0);
+
+ if (osfn != -1) /* Note != -1: osfn is unsigned */
+ { /* Opened file OK */
+#ifdef DFILE
+ {
+ char rgch[100];
+ wsprintf(rgch, " * OFSTR now %s \n\r", (LPSTR)(((POFSTRUCT)(**hpfnfcb) [fn].rgbOpenFileBuf)->szPathName));
+ CommSz(rgch);
+ }
+#endif
+
+ if (!pfcb->fOpened)
+ { /* First time through: OpenFile may have given us a
+ different name for the file */
+
+ CHAR szT [cchMaxFile];
+ CHAR (**hsz) [];
+
+#if WINVER >= 0x300
+ /* Currently: FNormSzFile *TAKES* an OEM sz, and
+ *RETURNS* an ANSI sz ..pault */
+#endif
+
+ if (FNormSzFile( szT, ((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName,
+ dty ) &&
+ WCompSz( szT, &(**pfcb->hszFile) [0] ) != 0 &&
+ FnFromSz( szT ) == fnNil &&
+ !FNoHeap( hsz = HszCreate( szT )))
+ {
+ /* Yes, indeed, the name OpenFile gave us was different.
+ Put the normalized version into the fcb entry */
+
+ FreeH( (**hpfnfcb) [fn].hszFile ); /* HEAP MOVEMENT */
+ (**hpfnfcb) [fn].hszFile = hsz;
+ }
+ }
+ break; /* We succeeded; break out of the loop */
+ }
+ else
+ { /* Open failed -- try read-only; don't prompt this time */
+ if ( (pfcb->mdFile == mdBinary) && (!pfcb->fOpened) )
+ { /* Failed as read/write; try read-only */
+
+ /* Check for sharing violation */
+
+ if (((vwDosVersion & 0x7F) >= 3) &&
+ (((POFSTRUCT) pfcb->rgbOpenFileBuf)->nErrCode == nErrNoAcc))
+ {
+ if ( DosxError() == dosxSharing )
+ {
+ extern int vfInitializing;
+ int fT = vfInitializing;
+
+ vfInitializing = FALSE; /* Report this err, even during inz */
+ {
+ char szMsg[cchMaxSz];
+ MergeStrings (IDPMTCantShare, **pfcb->hszFile, szMsg);
+ IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw, szMsg, MB_OK|MB_ICONEXCLAMATION);
+ }
+ vfInitializing = fT;
+ return FALSE;
+ }
+ }
+
+TryReadOnly:
+ pfcb->mdFile = mdBinRO;
+ wOpen = OF_READ;
+ if (pfcb->fOpened)
+ wOpen += OF_REOPEN;
+#ifdef ENABLE
+ else if (pfcb->fSearchPath)
+ wOpen += OF_VERIFY;
+#endif
+ }
+ else
+ {
+ if ((**hpfnfcb)[fn].fDisableRead)
+ /* already reported */
+ {
+ ferror = TRUE;
+ return FALSE;
+ }
+ else
+ { /* Could not find file in place specified */
+ char szMsg[cchMaxSz];
+ extern int ferror;
+ extern int vfInitializing;
+ int fT = vfInitializing;
+ BOOL bRetry=TRUE;
+ extern struct DOD (**hpdocdod)[];
+ extern int docCur;
+
+ /* get user to put file back */
+ MergeStrings (IDPMTFileNotFound, **pfcb->hszFile, szMsg);
+
+ vfInitializing = FALSE; /* Report this err, even during inz */
+
+ /*
+ This is frippin insidious. MessageBox yields and allows us to get
+ into here again before it has even been issued!
+ */
+
+ (**hpdocdod)[docCur].fDisplayable = FALSE; // block redraws
+
+ /* if we're being called from a message box, then use it
+ as the parent window, otherwise use main write window */
+ if (IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw,
+ szMsg, MB_OKCANCEL | MB_ICONEXCLAMATION | MB_APPLMODAL)
+ == IDCANCEL)
+ {
+ vfInitializing = fT;
+ (**hpfnfcb)[fn].fDisableRead = TRUE;
+ ferror = TRUE; /* need to flag */
+ bRetry = FALSE;
+ }
+
+ (**hpdocdod)[docCur].fDisplayable = TRUE; // unblock redraws
+
+ vfInitializing = fT;
+
+ if (!bRetry)
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ pfcb->fOpened = TRUE;
+
+ rfn = RfnGrab();
+ {
+ struct ERFN *perfn = &dnrfn [rfn];
+
+ perfn->osfn = osfn;
+ perfn->fn = fn;
+ perfn->ts = ++tsMruRfn; /* mark Rfn as MRused */
+ }
+ (**hpfnfcb) [fn].rfn = rfn;
+ (**hpfnfcb) [fn].fDisableRead = FALSE;
+ return TRUE;
+}
+
+
+
+FCreateFile( szFile, fn ) /* returns szFile in ANSI ..pault */
+CHAR *szFile;
+int fn;
+{ /* Create a new, unique file.
+ Return the name in szFile.
+ Returns TRUE on success, FALSE on failure.
+ Leaves the filename in (**hpfnfcb)[fn].hszFile (if successful),
+ the rfn in (**hpfnfcb)[fn].rfn.
+ If szFile begins "X:...", creates the file on the specified drive;
+ otherwise, creates the file on a drive of Windows' choice */
+
+ extern CHAR szExtDoc[];
+ CHAR (**hsz)[];
+ CHAR szFileT [cchMaxFile];
+
+ if (!GetTempFileName(szFile[0] | ((szFile[1] == ':') ? TF_FORCEDRIVE : 0),
+ (LPSTR)(szExtDoc+1), 0, (LPSTR)szFileT) )
+ { /* can't create file */
+ DiskErrorWithMsg( IDPMTSDE, " RfnCreate" );
+
+ /* recovery is accomplished: only FnCreateSz calls FCreateFile.
+ FnCreateSz returns nil if FCreateFile returns FALSE. All of
+ FnCreateSz's callers check for nil */
+ return FALSE;
+
+ }
+
+ /* Succeeded in creating file */
+
+ FNormSzFile( szFile, szFileT, dtyNormal );
+
+ if ( FNoHeap( hsz = HszCreate( (PCH)szFile )))
+ return FALSE;
+
+ (**hpfnfcb) [fn].hszFile = hsz;
+
+ if ( !FAccessFn( fn, dtyNormal ) )
+ return FALSE;
+
+ return TRUE;
+} /* end of F C r e a t e F i l e */
+
+
+
+FEnsureOnLineFn( fn )
+int fn;
+{ /* Ensure that file fn is on line (i.e. on a disk that is accessible).
+ Return TRUE if we were able to guarantee this, FALSE if not */
+ int rfn;
+
+ Assert( fn != fnNil );
+
+ if ( ((POFSTRUCT)(**hpfnfcb) [fn].rgbOpenFileBuf)->fFixedDisk )
+ /* If it's on nonremovable media, we know it's on line */
+ return TRUE;
+
+ /* If it's open, must close and re-open, cause windows might have closed it */
+ if ((rfn = (**hpfnfcb) [fn].rfn) != rfnNil)
+ CloseRfn( rfn );
+
+ return FAccessFn( fn, dtyNormal );
+}
+
+
+
+
+typePN PnAlloc(fn)
+int fn;
+{ /* Allocate the next page of file fn */
+ typePN pn;
+ struct BPS *pbps;
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+
+ AlignFn(fn, (int)cfcPage, false);
+ pn = pfcb->fcMac / cfcPage;
+ pbps = &mpibpbps[IbpEnsureValid(fn, pn)];
+ pbps->cch = cfcPage;
+ pbps->fDirty = true;
+ pfcb->fcMac += cfcPage;
+ pfcb->pnMac = pn + 1;
+ return pn;
+}
+
+
+
+
+STATIC CHAR *(near SzPromptFromFn( fn ))
+int fn;
+{
+ extern int vfnSaving;
+ CHAR *pch;
+
+ Assert( fn != fnNil );
+
+ if (fn == vfnSaving)
+ pch = szSaveFilePrompt;
+ else if (fn == fnScratch)
+ pch = szScratchFilePrompt;
+ else
+ pch = szWriteDocPrompt;
+
+ return pch;
+}
+
+
diff --git a/private/mvdm/wow16/write/filedefs.h b/private/mvdm/wow16/write/filedefs.h
new file mode 100644
index 000000000..6b1d309ea
--- /dev/null
+++ b/private/mvdm/wow16/write/filedefs.h
@@ -0,0 +1,124 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#include "machdefs.h"
+
+#define cfcPage ((typeFC)cbSector)
+#define ibpNil 255
+#define lruMax ((unsigned) 65535)
+#define fnMax 5
+#define fnInsert (fnNil - 1)
+#define fnScratch 0
+#define osfnNil (-1)
+#define rfnNil rfnMax /* Stored in 7 bits */
+#define rfnFree (rfnMax + 1)
+#define wMW ('M' + ('W' << 8))
+#define wSY ('S' + ('Y' << 8))
+#define wHP ('H' + ('P' << 8))
+#define cwSector (cbSector / sizeof (int))
+#define cbpMustKeep 6 /* assume no bp will be dislodged for this
+ many calls to IbpEnsureValid */
+#define cbOpenFileBuf 128
+
+#ifdef SAND
+#define wMagic 0177062
+#define wMagicOld 0137061
+#else /* not SAND */
+#define wMagic 0137061
+#endif /* not SAND */
+
+#define wMagicTool ((0253 << 8) + 0)
+
+#define fcMax ((typeFC) 2147483647)
+
+#define fpeNoSuch (-5)
+#define fpeDiskFull (-7)
+
+struct BPS
+ {
+ typePN pn;
+ int fn;
+ typeTS ts; /* time stamp - used in LRU algorithm */
+ unsigned fDirty : 1;
+ unsigned cch : 15;
+ CHAR ibpHashNext; /* link for external chained hashing
+ collision resolution */
+ };
+
+
+struct FCB
+ {
+ typeFC fcMac; /* includes FIB, but not FKP's */
+ unsigned char fFormatted : 1;
+ unsigned char fDelete : 1;
+ unsigned char fReferenced : 1;
+ unsigned char dty : 4;
+ unsigned char fOpened: 1; /* Whether file has been opened before */
+ unsigned char rfn : 7;
+ unsigned char fSearchPath: 1; /* Search path when first opened */
+ int mdExt;
+ int mdFile;
+ typePN pnChar;
+ typePN pnPara;
+ typePN pnFntb;
+ typePN pnSep;
+ typePN pnSetb;
+ typePN pnBftb;
+ typePN pnFfntb; /* font family name table offset */
+ typePN pnMac; /* # of pages actually in existence */
+ typeFC (**hgfcChp)[];
+ typeFC (**hgfcPap)[];
+ CHAR (**hszFile)[];
+ CHAR (**hszSsht)[];
+ CHAR rgbOpenFileBuf[ cbOpenFileBuf ]; /* OpenFile's work space */
+
+#ifdef SAND
+ int version; /* version byte */
+ int vref; /* volume reference number */
+#endif /* SAND */
+
+ unsigned int fDisableRead: 1; /* disable reading of file */
+ };
+
+#define cbFCB (sizeof (struct FCB))
+#define cwFCB (sizeof (struct FCB) / sizeof (int))
+
+struct ERFN
+ { /* Real file (opened in os) */
+ int osfn;
+ int fn;
+ typeTS ts; /* time stamp - used in LRU algorithm */
+ };
+
+
+#define cchToolHeader 14
+
+struct FIB
+ {
+ int wIdent; /* Word-specific magic number */
+ int dty;
+ int wTool;
+ int cReceipts; /* Number of external receipts allowed */
+ int cbReceipt; /* Length of each receipt */
+ int bReceipts; /* One word offset from beginning of file
+ to beginning of receipts */
+ int isgMac; /* Number of code segments included */
+ /* End of Multi-Tool standard header */
+ typeFC fcMac;
+ typePN pnPara;
+ typePN pnFntb;
+ typePN pnSep;
+ typePN pnSetb;
+ typePN pnBftb; /* Also pnPgtb */
+ typePN pnFfntb; /* font family name table */
+ CHAR szSsht[66]; /* Style sheet name */
+ typePN pnMac;
+ CHAR rgbJunk[cbSector - (cchToolHeader + sizeof (typeFC)
+ + 7 * sizeof (typePN) + 66)];
+ };
+
+#define cchFIB (sizeof (struct FIB))
+
+#define CONVFROMWORD (TRUE + 2) /* used by FWriteFn to convert Word file
+ characters to Write ANSI set */
diff --git a/private/mvdm/wow16/write/fileres.c b/private/mvdm/wow16/write/fileres.c
new file mode 100644
index 000000000..c25a274d7
--- /dev/null
+++ b/private/mvdm/wow16/write/fileres.c
@@ -0,0 +1,321 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* fileres.c -- functions from file.c that are usually resident */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOSYSCOMMANDS
+#define NOATOM
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOMETAFILE
+#define NOMSG
+#define NOHDC
+#define NOGDI
+#define NOMB
+#define NOFONT
+#define NOPEN
+#define NOBRUSH
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOMM
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "debug.h"
+
+
+extern int vfDiskFull;
+extern int vfSysFull;
+extern int vfnWriting;
+extern CHAR (*rgbp)[cbSector];
+extern typeTS tsMruRfn;
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern struct FCB (**hpfnfcb)[];
+extern typeTS tsMruBps;
+extern struct ERFN dnrfn[rfnMax];
+extern int iibpHashMax;
+extern CHAR *rgibpHash;
+extern int rfnMac;
+extern int ferror;
+extern CHAR szWriteDocPrompt[];
+extern CHAR szScratchFilePrompt[];
+extern CHAR szSaveFilePrompt[];
+
+
+#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax
+
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#define ErrorWithMsg( idpmt, szModule ) Error( idpmt )
+#define DiskErrorWithMsg( idpmt, szModule ) DiskError( idpmt )
+#endif
+
+#define osfnNil (-1)
+
+
+CHAR *PchFromFc(fn, fc, pcch)
+int fn;
+typeFC fc;
+int *pcch;
+{ /*
+ Description: Reads from a file, starting at virtual character
+ position fc. Reads until end of buffer page.
+ Returns: Pointer to char buffer starting at fc.
+ The number of characters read is returned in *pcch.
+ */
+int dfc;
+CHAR *pch;
+typePN pn;
+int ibp;
+struct BPS *pbps;
+
+ dfc = (int) (fc % cfcPage);
+ pn = (typePN) (fc / cfcPage);
+
+ ibp = IbpEnsureValid(fn, pn);
+ pbps = &mpibpbps[ibp];
+ *pcch = pbps->cch - dfc;
+ return &rgbp[ibp][dfc];
+}
+/* end of P c h F r o m F c */
+
+
+
+
+/*** PchGetPn - Assure file page loaded, return pointer
+ *
+ */
+
+CHAR *PchGetPn(fn, pn, pcch, fWrite)
+int fn;
+typePN pn;
+int *pcch;
+BOOL fWrite; // missing before?? (2.11.91) D. Kent
+{ /*
+ Description: Get char pointer to page buffer, option to mark
+ page as dirty.
+ Returns: Pointer to buffer.
+ cch in *pcch
+ */
+
+ int ibp = IbpEnsureValid(fn, pn);
+ struct BPS *pbps = &mpibpbps[ibp];
+
+ *pcch = pbps->cch;
+ pbps->fDirty |= fWrite;
+ return rgbp[ibp];
+} /* end of P c h G e t P n */
+
+
+
+
+int IbpEnsureValid(fn, pn)
+int fn;
+typePN pn;
+{ /*
+ Description: Get page pn of file fn into memory.
+ If already in memory, return.
+ Returns: Bp index (buffer slot #) where the page resides
+ in memory.
+ */
+
+int ibp;
+register struct BPS *pbps;
+
+#ifdef DEBUG
+ CheckIbp();
+#endif /* DEBUG */
+
+/* Is the page currently in memory? */
+ ibp = rgibpHash[IibpHash(fn,pn)];
+ /* ibp is the first in a linked list of possible matches */
+ /* resident in memory */
+
+ Scribble(3,'V');
+
+ while (ibp != ibpNil) /* while not end of linked list */
+ { /* check if any buffers in memory match */
+ pbps = &mpibpbps[ibp];
+ if (pbps->fn == fn && pbps->pn == pn)
+ { /* Found it */
+ pbps->ts = ++tsMruBps; /* mark page as MRUsed */
+ Scribble(3,' ');
+ return ibp;
+ }
+ ibp = pbps->ibpHashNext;
+ }
+
+/* page is not currently in memory */
+
+ return IbpMakeValid( fn, pn );
+} /* end of I b p E n s u r e V a l i d */
+
+
+
+
+CloseEveryRfn( fHardToo )
+{ /* Close all files we have open. Close only files on removable media
+ if fHardToo is FALSE; ALL files if fHardToo is TRUE */
+int rfn;
+
+for (rfn = 0; rfn < rfnMac; rfn++)
+ {
+ int fn = dnrfn [rfn].fn;
+
+ if (fn != fnNil)
+ if ( fHardToo ||
+ !((POFSTRUCT)((**hpfnfcb)[fn].rgbOpenFileBuf))->fFixedDisk )
+ {
+ CloseRfn( rfn );
+ }
+ }
+}
+
+
+
+typeFC FcWScratch(pch, cch)
+CHAR *pch;
+int cch;
+{ /*
+ Description: Write chars at end of scratch file.
+ Returns: first fc written.
+ */
+ typeFC fc = (**hpfnfcb)[fnScratch].fcMac;
+#if 0
+ extern BOOL bNo64KLimit;
+
+ if ((!bNo64KLimit) && (((long) fc) + ((long) cch) > 65536L)) /* scratch file to big */
+ {
+ DiskErrorWithMsg(IDPMTSFER, " FcWScratch"); /* session too long */
+
+ vfSysFull = fTrue;
+ /* recovery is accomplished: all that happens is that a few
+ characters do not get written to the scratch file - the
+ user loses only a little bit of his work. */
+ }
+ else
+#endif
+ WriteRgch(fnScratch, pch, cch);
+ return fc;
+}
+
+
+
+
+WriteRgch(fn, pch, cch)
+int fn;
+CHAR *pch;
+int cch;
+{ /*
+ Description: Writes char string pch, length cch, to end of
+ file fn.
+ Returns: nothing
+ */
+ extern vfDiskError;
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ typePN pn = (typePN) (pfcb->fcMac / cfcPage);
+#ifdef WIN30
+ /* Error checking was horrendous in these early days, right?
+ Ha. It still is. In any case, don't know WHAT we can do
+ if the page number has gotten too large, so just fake a
+ disk error so that IbpEnsureValid() doesn't go off into
+ never-never land! This catch effectively limits us to
+ 4M files ..pault 11/1/89 */
+
+ if (pn > pgnMax)
+#ifdef DEBUG
+ DiskErrorWithMsg(IDPMTSDE2, "writergch");
+#else
+ DiskError(IDPMTSDE2);
+#endif
+ else
+#endif
+
+ while (cch > 0)
+ { /* One page at a time */
+ int ibp = IbpEnsureValid(fn, pn++);
+ struct BPS *pbps = &mpibpbps[ibp];
+ int cchBp = pbps->cch;
+ int cchBlt = min((int)cfcPage - cchBp, cch);
+
+ Assert( vfDiskError ||
+ cchBp == pfcb->fcMac - (pn - 1) * cfcPage);
+
+ bltbyte(pch, &rgbp[ibp][cchBp], cchBlt);
+ pbps->cch += cchBlt;
+ pbps->fDirty = true;
+ pfcb->fcMac += cchBlt;
+ pfcb->pnMac = pn;
+ pch += cchBlt;
+ cch -= cchBlt;
+ }
+} /* end of W r i t e R g c h */
+
+
+
+
+CloseRfn( rfn )
+int rfn;
+{/*
+ Description: Close a file and delete its Rfn entry
+ Returns: nothing
+ */
+ struct ERFN *perfn = &dnrfn[rfn];
+ int fn = perfn->fn;
+
+ Assert (rfn >= 0 &&
+ rfn < rfnMac &&
+ perfn->osfn != osfnNil &&
+ fn != fnNil);
+
+#ifdef DEBUG
+#ifdef DFILE
+ CommSzSz( "Closing file: ", &(**(**hpfnfcb)[fn].hszFile)[0] );
+#endif
+#endif
+ /* Close may fail if windows already closed the file for us,
+ but that's OK */
+ FCloseDoshnd( perfn->osfn );
+
+ { /* Just like the statement below, but 28 bytes less
+ under CMERGE V13 */
+ REG1 struct FCB *pfcb = &(**hpfnfcb) [fn];
+ pfcb->rfn = rfnNil;
+ }
+ /* (**hpfnfcb)[fn].rfn = rfnNil; */
+
+
+ perfn->fn = fnNil;
+}
diff --git a/private/mvdm/wow16/write/filespec.wri b/private/mvdm/wow16/write/filespec.wri
new file mode 100644
index 000000000..4c6a956dd
--- /dev/null
+++ b/private/mvdm/wow16/write/filespec.wri
Binary files differ
diff --git a/private/mvdm/wow16/write/fileutil.c b/private/mvdm/wow16/write/fileutil.c
new file mode 100644
index 000000000..02f19f218
--- /dev/null
+++ b/private/mvdm/wow16/write/fileutil.c
@@ -0,0 +1,485 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* fileutil.c -- WRITE file-related utilities */
+#define NOVIRTUALKEYCODES
+#define NOCTLMGR
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCOMM
+#define NOSOUND
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "str.h"
+#include "machdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "docdefs.h"
+#include "debug.h"
+#include "editdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES
+#include "ch.h"
+
+
+
+/*** FNormSzFile - Normalize MSDOS filename
+ *
+ * Converts a MSDOS filename into an unambiguous representation
+ *
+ * ENTRY: szFile - a filename; drive, path, and extension
+ * are optional
+ * dty - the type of the document file (used to determine
+ * extensions)
+ * EXIT: szNormal - A normalized filename
+ * RETURNS: FALSE - Errors found in filename (szNormal left undefined)
+ * TRUE - No errors found in filename ( but there may be some
+ * that we didn't find )
+ *
+ * The form of the filename on entry is:
+ *
+ * { <drive-letter>: }{ <amb-path> }<filename>{.<extension>}
+ *
+ * The form of the normalized filename is:
+ *
+ * <drive-letter>:<unamb-path><filename>.<extension>
+ *
+ * Where all alphabetics in the normalized name are in upper case
+ * and <unamb-path> contains no "." or ".." uses nor any forward
+ * slashes.
+ *
+ * All attributes required in the normalized filename and not
+ * provided in the szFile are taken from the defaults:
+ * drive - current (DOS)
+ * path - current (DOS)
+ * extension - derived from the passed dty
+ *
+ * It is permissible to call this routine with szFile containing a path
+ * name instead of a filename. The resulting szNormal will be backslash
+ * terminated if szFile was, not if szFile was not.
+ * "" is converted into the current path
+ *
+ * WARNING: The paths "." and ".." will produce errors
+ * (but ".\" and "..\" are OK)
+ *
+ ******
+ *NOTE* szFile is expected in OEM; szNormal is returned as ANSI!
+ ******
+ *
+ */
+
+FNormSzFile( szNormal, szFile, dty )
+CHAR *szNormal;
+CHAR *szFile;
+int dty;
+{
+/* Treat separators like terminators */
+
+#define FIsTermCh( ch ) ((ch) == '\0' || (ch) == ',' || (ch == ' ') || \
+ (ch) == '+' || (ch) == '\011')
+extern CHAR *mpdtyszExt [];
+
+ CHAR szPath [cchMaxFile];
+ CHAR szFileT[cchMaxFile];
+
+ int cchPath;
+ CHAR *pchFileEye=&szFileT[0]; /* We read szFile with the Eye */
+ CHAR *pchNormPen; /* and write szNormal with the Pen */
+ CHAR *pchNormPath;
+ CHAR *pchPath;
+
+/* Assert( CchSz( szFile ) <= cchMaxFile );*/
+ if (CchSz(szFile) > cchMaxFile)
+ return(FALSE);
+
+#if WINVER >= 0x300
+ /* Convert input filename, which is passed in OEM,
+ to ANSI so entire return pathname will be ANSI */
+ OemToAnsi((LPSTR) szFile, (LPSTR) szFileT);
+#endif
+
+#ifdef DBCS
+ /* Get current (DOS) path: "X:\...\...\" */
+ if( IsDBCSLeadByte(*szFileT) )
+ cchPath = CchCurSzPath(szPath, 0 );
+ else
+ cchPath = CchCurSzPath(szPath, szFileT [1]==':' ?
+ (pchFileEye+=2,(ChUpper(szFileT [0])-('A'-1))):0 );
+ if( cchPath < 3 )
+#else
+ /* Get current (DOS) path: "X:\...\...\" */
+ if ((cchPath = CchCurSzPath(&szPath [0], szFileT [1]==':' ?
+ (pchFileEye+=2,(ChUpper(szFileT [0])-('A'-1))):0 )) < 3)
+#endif
+ { /* Hardcore error -- could not get path */
+ extern int ferror;
+
+ if (FpeFromCchDisk(cchPath) == fpeNoDriveError)
+ Error( IDPMTNoPath );
+
+ ferror = TRUE; /* Windows already reported this one */
+ return FALSE;
+ }
+
+#if WINVER >= 0x300
+ {
+ CHAR szT[cchMaxFile];
+
+ /* CchCurSzPath returns OEM; we should only be dealing
+ with ANSI filenames at this level! ..pault 1/11/90 */
+
+ bltsz(szPath, szT);
+ OemToAnsi((LPSTR) szT, (LPSTR) szPath);
+ }
+#endif
+
+ /* Write Drive Letter and colon */
+ CopyChUpper( &szPath [0], &szNormal [0], 2 );
+
+ pchNormPen = pchNormPath = &szNormal [2];
+ pchPath = &szPath [2];
+ cchPath -= 2;
+
+ /* Now we have pchNormPen, pchPath, pchFileEye pointing at their path names */
+
+ /* Write path name */
+ if ( (*pchFileEye == '\\') || (*pchFileEye =='/') )
+ { /* "\....." -- basis is root */
+ *pchFileEye++;
+ *(pchNormPen++) = '\\';
+ }
+ else
+ { /* ".\" OR "..\" OR <text> -- basis is current path */
+ CopyChUpper( pchPath, pchNormPen, cchPath );
+ pchNormPen += cchPath - 1;
+ }
+
+ for ( ;; )
+ { /* Loop until we have built the whole szNormal */
+ register CHAR ch=*(pchFileEye++);
+ register int cch;
+
+ Assert( *(pchNormPen - 1) == '\\' );
+ Assert( (pchNormPen > pchNormPath) &&
+ (pchNormPen <= &szNormal [cchMaxFile]));
+
+ if ( FIsTermCh( ch ) )
+ /* We get here if there is no filename portion */
+ /* This means we have produced a path name */
+ {
+ *pchNormPen = '\0';
+ break;
+ }
+
+ if ( ch == '.' )
+ if ( ((ch = *(pchFileEye++)) == '\\') || (ch == '/') )
+ /* .\ and ./ do nothing */
+ continue;
+ else if ( ch == '.' )
+ if ( ((ch = *(pchFileEye++)) == '\\') || (ch == '/') )
+ { /* ..\ and ../ back up by one directory */
+ for ( pchNormPen-- ; *(pchNormPen-1) != '\\' ; pchNormPen-- )
+ if ( pchNormPen <= pchNormPath )
+ /* Can't back up, already at root */
+ return FALSE;
+ continue;
+ }
+ else
+ /* ERROR: .. not followed by slash */
+ return FALSE;
+ else
+ /* Legal file and path names do not begin with periods */
+ return FALSE;
+
+ /* Filename or Path -- copy ONE directory or file name */
+
+ for ( cch = 1; !FIsTermCh(ch) && ( ch != '\\') && ( ch != '/' ) ; cch++ )
+#ifdef DBCS
+ {
+ if(IsDBCSLeadByte(ch))
+ {
+ pchFileEye++;
+ cch++;
+ }
+ ch = *(pchFileEye++);
+ }
+#else
+ ch = *(pchFileEye++);
+#endif
+
+ /* Check if filename too long or if full pathname will be too long ..pt */
+ if ( cch > cchMaxLeaf || cch+cchPath >= cchMaxFile)
+ /* Directory or file name too long */
+ return FALSE;
+
+ CopyChUpper( pchFileEye - cch, pchNormPen, cch );
+ pchNormPen += cch;
+ if ( ch == '/' )
+ *(pchNormPen-1) = '\\';
+ else if ( FIsTermCh( ch ) )
+ { /* Filename looks good, add extension & exit */
+ *(pchNormPen-1) = '\0';
+
+ /* kludge alert: if dtyNormNoExt then don't add extension unless
+ there's one already there to be overwritten. (6.21.91) v-dougk */
+ if ((dty != dtyNormNoExt) ||
+ index(szNormal,'.'))
+ AppendSzExt( &szNormal [0],
+ mpdtyszExt [ (dty == dtyNormNoExt) ? dtyNormal : dty ],
+ FALSE );
+ break;
+ }
+ } /* Endfor (loop to build szNormal) */
+
+ /* If there is anything but whitespace after the filename, then it is illegal */
+
+ pchFileEye--; /* Point at the terminator */
+ Assert( FIsTermCh( *pchFileEye ));
+
+ for ( ;; )
+ {
+#ifdef DBCS
+ CHAR ch = *(pchFileEye=AnsiNext(pchFileEye));
+#else
+ CHAR ch = *(pchFileEye++);
+#endif
+
+ if (ch == '\0')
+ break;
+ else if ((ch != ' ') && (ch != '\011'))
+ /* Non-whitespace after filename; return failure */
+ return FALSE;
+ }
+
+ Assert( CchSz(szNormal) <= cchMaxFile );
+ return TRUE;
+}
+
+
+
+/* Parses the cch chars stored in rgch. Returns true if string is a valid
+filename. If the string is not a valid name, pichError is updated to have
+ich of first illegal Char in the name. */
+/* NOTE: this routine is tuned for ASCII on MS-DOS */
+
+BOOL
+FValidFile(rgch, ichMax, pichError) /* filename presumed to be ANSI */
+register char rgch[];
+int ichMax;
+int *pichError;
+ {
+ int ich;
+ register int ichStart;
+ CHAR ch;
+ int cchBase;
+ int ichDot = iNil;
+
+ for (ichStart = 0; ichStart < ichMax;)
+ {
+ /* Does the file name begin with ".\" or "..\"? */
+ if (rgch[ichStart] == '.' &&
+ (rgch[ichStart + 1] == '\\' || rgch[ichStart + 1] == '/'))
+ {
+ ichStart += 2;
+ }
+ else if (rgch[ichStart] == '.' && rgch[ichStart + 1] == '.' &&
+ (rgch[ichStart + 2] == '\\' || rgch[ichStart + 2] == '/'))
+ {
+ ichStart += 3;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ cchBase = ichStart;
+
+ if (ichStart >= ichMax)
+ {
+ ich = ichStart;
+ goto badchar;
+ }
+
+ /* Are all characters legal? */
+ for(ich = ichStart; ich < ichMax; ich++)
+ {
+ ch = rgch[ich];
+ /* range check */
+
+#ifndef DBCS
+ if ((unsigned char)ch >= 0x80)
+ /* To allow international filenames, pass everything above 128 */
+ continue;
+ if (ch < '!' || ch > '~')
+ goto badchar;
+#endif
+ switch(ch)
+ {
+ default:
+#ifdef DBCS
+ goto CheckDBCS;
+#else
+ continue;
+#endif
+ case '.':
+ if (ichDot != iNil || ich == cchBase)
+ /* More than one dot in the name */
+ /* Or null filename */
+ goto badchar;
+ ichDot = ich;
+#ifdef DBCS
+ goto CheckDBCS;
+#else
+ continue;
+#endif
+ case ':':
+ if ( ich != 1 || !(isalpha(rgch[0])))
+ goto badchar;
+ /* fall through */
+ case '\\':
+ case '/':
+ /* note end of the drive or path */
+ if (ich + 1 == ichMax)
+ goto badchar;
+ cchBase = ich+1;
+ ichDot = iNil;
+#ifdef DBCS
+ goto CheckDBCS;
+#else
+ continue;
+#endif
+ case '"':
+#ifdef WRONG
+ /* This IS a legal filename char! ..pault 10/26/89 */
+ case '#':
+#endif
+ case '*':
+ case '+':
+ case ',':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '[':
+ case ']':
+ case '|':
+ goto badchar;
+ }
+#ifdef DBCS
+CheckDBCS:
+ if(IsDBCSLeadByte(ch)) ich++;
+#endif /* DBCS */
+ }
+
+ /* Are there no more than eight chars before the '.'? */
+ if(((ichDot == -1) ? ichMax : ichDot) - cchBase > 8)
+ {
+ ich = 8+cchBase;
+ goto badchar;
+ }
+ /* If there is no '.' we are fine */
+ if(ichDot == iNil)
+ return true;
+ /* Are there no more than three chars after the '.'? */
+ if(ichMax - ichDot - 1 > 3)
+ {
+ ich = ichDot + 3 + 1;
+ goto badchar;
+ }
+ return true;
+
+badchar:
+ *pichError += ich;
+ return false;
+ }
+
+
+
+
+
+
+
+#ifdef DBCS
+CopyChUpper( szSource, szDest, cch )
+register CHAR *szSource;
+register CHAR *szDest;
+int cch;
+{
+ while(cch){
+ if( IsDBCSLeadByte( *szSource ) ){
+ *szDest++ = *szSource++;
+ *szDest++ = *szSource++;
+ cch--;
+ } else
+ *szDest++ = ChUpper( *szSource++ );
+ cch--;
+ }
+}
+#else
+CopyChUpper( szSource, szDest, cch )
+CHAR *szSource;
+CHAR *szDest;
+register int cch;
+{
+ register CHAR ch;
+
+ while (cch--)
+ {
+ ch = *(szSource++);
+ *(szDest++) = ChUpper( ch );
+ }
+}
+#endif
+
+
+/*** AppendSzExt - append extension to filename
+ *
+ * Append extension (assumed to contain the ".") to passed filename.
+ * Assumes call allocated enough string space for the append
+ * if fOverride is TRUE, overrides any existing extension
+ * if fOverride is FALSE, appends extension only if szFile has
+ * no current extension
+ */
+
+AppendSzExt( szFile, szExt, fOverride )
+CHAR *szFile;
+CHAR *szExt;
+int fOverride;
+{
+#define cchMaxExt 3
+ CHAR *pch=NULL;
+ int cch;
+ register int cchT;
+ register int chT;
+
+ /* pch <-- pointer to the '.' for szFile's extension (if any) */
+ cch = cchT = CchSz( szFile ) - 1;
+ while (--cchT > cch - (cchMaxExt + 2))
+ if ((chT=szFile[ cchT ]) == '.')
+ {
+ pch = &szFile[ cchT ];
+ break;
+ }
+ else if ((chT == '\\') || (chT == '/'))
+ /* Catches the weird case: szFile == "C:\X.Y\J" */
+ break;
+
+ if (pch == NULL)
+ /* No explicit extension: APPEND */
+ CchCopySz( szExt, szFile + CchSz( szFile ) - 1 );
+
+ else if ( fOverride )
+ /* Override explicit extension */
+ CchCopySz( szExt, pch );
+}
+
diff --git a/private/mvdm/wow16/write/fkpdefs.h b/private/mvdm/wow16/write/fkpdefs.h
new file mode 100644
index 000000000..60e03bbd4
--- /dev/null
+++ b/private/mvdm/wow16/write/fkpdefs.h
@@ -0,0 +1,122 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* fkpdefs.h -- mw formatted disk page definitions */
+/* #include filedefs.h, propdefs.h first */
+
+
+#define ifcMacInit 10
+
+#define cbFkp (cbSector - sizeof (typeFC) - 1)
+
+#define cchMaxGrpfsprm cbSector
+#define cchMaxFsprm 2
+
+struct FKP
+ { /* Formatted disK Page */
+ typeFC fcFirst; /* First fc which has formatting info here */
+ CHAR rgb[cbFkp];
+ CHAR crun;
+ };
+
+
+struct RUN
+ { /* Char or para run descriptor */
+ typeFC fcLim; /* last fc of run */
+ int b; /* Byte offset from page start; if -1, standard props */
+ };
+
+#define cchRUN (sizeof (struct RUN))
+#define bfcRUN 0
+
+struct FCHP
+ { /* File CHaracter Properties */
+ CHAR cch; /* Number of bytes stored in chp (rest are vchpStd) */
+ /* Must not be 0. */
+ CHAR rgchChp[sizeof (struct CHP)];
+ };
+
+
+struct FPAP
+ { /* File ParagrAph Properties */
+ CHAR cch; /* Number of bytes stored in pap (rest are vpapStd) */
+ /* Must not be 0. */
+ CHAR rgchPap[sizeof (struct PAP)];
+ };
+
+
+
+struct FPRM
+ { /* File PropeRty Modifiers (stored in scratch file) */
+ CHAR cch;
+ CHAR grpfsprm[cchMaxGrpfsprm + cchMaxFsprm]; /* + for overflow */
+ };
+
+
+struct FKPD
+ { /* FKP Descriptor (used for maintaining insert properties) */
+ int brun; /* offset to next run to add */
+ int bchFprop; /* offset to byte after last unused byte */
+ typePN pn; /* pn of working FKP in scratch file */
+ struct BTE (**hgbte)[]; /* pointer to bin table */
+ int ibteMac; /* Number of bin table entries */
+ };
+
+
+struct BTE
+ { /* Bin Table Entry */
+ typeFC fcLim;
+ typePN pn;
+ };
+#define cwBTE (sizeof(struct BTE)/sizeof(int))
+
+struct FND
+ { /* Footnote descriptor */
+ typeCP cpRef; /* Or fcRef (cp of ftn reference) */
+ typeCP cpFtn; /* Or fc... (first cp of text) */
+ };
+
+#define cchFND (sizeof (struct FND))
+#define cwFND (cchFND / sizeof (int))
+#define bcpRefFND 0
+#define bcpFtnFND (sizeof (typeCP))
+#define cwFNTBBase 2
+#define ifndMaxFile ((cbSector - cwFNTBBase * sizeof (int)) / cchFND)
+
+struct FNTB
+ { /* Footnote table */
+ int cfnd; /* Number of entries (sorted ascending) */
+ int cfndMax; /* Heap space allocated */
+ struct FND rgfnd[ifndMaxFile]; /* Size varies */
+ };
+
+
+
+struct FNTB **HfntbEnsure(), **HfntbGet();
+
+#define HsetbGet(doc) ((**hpdocdod)[doc].hsetb)
+
+struct SED
+ { /* Section descriptor */
+ typeCP cp;
+ int fn;
+ typeFC fc;
+ };
+
+#define cchSED (sizeof (struct SED))
+#define cwSED (cchSED / sizeof (int))
+#define bcpSED 0
+#define cwSETBBase 2
+#define isedMaxFile ((cbSector - cwSETBBase * sizeof (int)) / cchSED)
+
+
+struct SETB
+ { /* Section table */
+ int csed;
+ int csedMax;
+ struct SED rgsed[isedMaxFile]; /* Size varies */
+ };
+
+
+struct SETB **HsetbCreate(), **HsetbEnsure();
diff --git a/private/mvdm/wow16/write/fmtdefs.h b/private/mvdm/wow16/write/fmtdefs.h
new file mode 100644
index 000000000..1ebd13f4a
--- /dev/null
+++ b/private/mvdm/wow16/write/fmtdefs.h
@@ -0,0 +1,85 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define ichMaxLine 255
+#define cpMaxTl (ichMaxLine + cchInsBlock)
+#define ichpMacInitFormat 10 /* Initial mac of char runs in a line */
+#define dypBaselineMin 2
+
+#define wbWhite 0 /* Word break types */
+#define wbText 1
+#define wbPunct 2
+#define wbAny 3 /* used when searching with wildcards */
+
+#ifdef DBCS /* was in JAPAN, changed it to DBCS */
+ /* brought from WIN2. */
+#define wbKanjiText 4
+#define wbKanjiTextFirst 5
+#endif /* DBCS */
+
+#define dxpTab 40
+
+/* Formatted line structure.
+ Reorganized KJS, CS Sept 3
+ Shuffled for word alignment bz, 6/11/85 */
+
+/* booleans in bytes to simplify machine code */
+struct FLI
+ {
+ typeCP cpMin;
+ int ichCpMin;
+ typeCP cpMac;
+ int ichCpMac;
+ int ichMac;
+ int dcpDepend;
+ unsigned fSplat : 8;
+/* First character in region where spaces have additional pixel */
+ unsigned ichFirstWide : 8;
+/* ichMac, with trailing blanks excluded */
+ int ichReal;
+ int doc;
+
+ int xpLeft;
+ int xpRight;
+/* xpRight, with trailing blanks excluded */
+ int xpReal;
+/* the right margin where insert will have to break the line */
+ int xpMarg;
+
+ unsigned fGraphics : 8;
+ unsigned fAdjSpace : 8; /* Whether you adjust the spaces */
+
+ unsigned dxpExtra;
+/* the interesting positions in order from top to bottom are:
+ top: yp+dypLine
+ top of ascenders: yp+dypAfter+dypFont
+ base line: yp+dypBase
+ bottom of descenders: yp+dypAfter
+ bottom of line: yp
+distances between the points can be determined by algebraic subtraction.
+e.g. space before = yp+dypLine - (yp+dypAfter+dypFont)
+*/
+ int dypLine;
+ int dypAfter;
+ int dypFont;
+ int dypBase;
+ int fSplatNext; /* Splat on following line? */
+
+ int ichLastTab;
+ int flm;
+ int rgdxp[ichMaxLine]; /* NOTE this differs from fce.rgdxp==CHAR! */
+ CHAR rgch[ichMaxLine];
+ };
+
+
+
+#define cwFLI (sizeof(struct FLI) / sizeof(int))
+#define cwFLIBase (cwFLI - ichMaxLine - (ichMaxLine / sizeof (int)))
+
+
+#define flmPrinting 1
+#define flmCharMode 2
+#define flmNoMSJ 4
+#define flmSandMode 8
+
diff --git a/private/mvdm/wow16/write/fontdefs.h b/private/mvdm/wow16/write/fontdefs.h
new file mode 100644
index 000000000..fc0b2e6ed
--- /dev/null
+++ b/private/mvdm/wow16/write/fontdefs.h
@@ -0,0 +1,367 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* fontdefs.h -- MW definitions for fonts */
+
+#ifdef PRDFILES
+struct PRDD
+ { /* printer description file descriptor */
+ int cfcdMac, /* count of fonts defined for this printer */
+ cxInch, /* pixels per inch, horizontal */
+ dyaMin, /* " " " " y " */
+ pid, /* printer identification number */
+ pe, /* print element */
+ fNoMSJ, /* microspace justification flag */
+ fSpecial, /* special flags */
+ pn, /* serial interface word */
+ bfcdBase, /* byte address of start of FCDs */
+ cttBase, /* byte address of start of CTT */
+ bpcdBase, /* byte address of start of PCDs */
+ bpcsBase, /* byte address of start of PCSs */
+ bprdMax; /* end of PRD file */
+
+ CHAR (**hrgbprdf)[]; /* block that contains the FCDs and WTs */
+ int (**hmpiftcfcd)[]; /* double entry table: consists of 2 word
+ entries, 1st is the font code of this font,
+ 2nd is heap offset to FCD for this font.
+ There are exactly cfcdMac sets of these */
+ CHAR (**hrgbctt)[]; /* character translation table */
+ CHAR (**hprcc)[]; /* printer control sequences */
+/* CHAR szFile[cchMaxFile]; /* file name for printer desc. file */
+ };
+
+#define cchPRDDFile 26
+#define cwPRDD (sizeof (struct PRDD) / sizeof(int))
+
+/* prd file byte offsets */
+#define bPrdData1 (typeFC)64
+#define bPrdData2 (typeFC)128
+
+#define cpsMax 10
+#define dxaDefault ((unsigned) 144)
+
+#ifdef SAND
+#define wpcPica 0 /* Daisy wheel pitch codes */
+#define wpcElite 1
+#define wpcMicron 2
+#define wpcProportional 3
+
+#define wpPica 10 /* Pitches */
+#define wpElite 12
+#define wpMicron 15
+#define wpProportional 10 /* Bogus */
+
+#define psPica 12 /* point Sizes */
+#define psElite 10
+#define psMicron 8
+#define psProportional 12 /* Bogus */
+
+#define convWpPs 120 /* conversion between wheel pitch and
+ Point Size */
+
+/* IMPORTANT-- the following font codes (20, 21, 22, 23) random numbers
+ we will have to be assigned permanent font codes by Apple */
+
+#define ftcPrintFONT 20
+#define ftcPrintFWID 21
+#define ftcPrintPSFONT 22
+#define ftcPrintPSFWID 23
+#endif /* SAND */
+
+struct FAD
+ { /* Font Address Descriptor */
+ unsigned wtp; /* multi purpose word */
+ };
+
+struct PCSD1
+ { /* printer control sequence descriptor */
+ int bprcc; /* byte offset of start of control sequence */
+ CHAR bMod; /* modification byte */
+ CHAR cch; /* length of control sequence */
+ };
+
+#define cwPCSD1 (sizeof(struct PCSD1) / sizeof(int))
+
+struct PSD
+ { /* Printer Size Descriptor */
+ int hps; /* size available in half points */
+ struct FAD fad,
+ fadI,
+ fadB,
+ fadIB;
+ struct PCSD1 pcsdBegin,
+ pcsdEnd;
+ };
+
+struct FCD
+ { /* Font Code Description */
+ int ctp; /* character translation table pointer (a la wtp) */
+ int cpsd; /* count of sizes available */
+ struct PSD rgpsd[cpsMax]; /* psds for each size available */
+ CHAR rgchFntName[32];/* font name (null terminated) */
+ };
+
+#define pnfSerial 0100000
+#define pnfETX 040000
+#define pnfXON 020000
+
+#define MSJ_fNone 1
+#define MSJ_fChars 2
+#define MSJ_fPSCorrect 4
+
+#define SPC_fNoBSCtt 1
+
+#ifdef GENERIC_MSDOS
+#ifdef HP150
+#define cPortMac 3
+#define cchPort 4
+#else /* not HP150 */
+#define cPortMac 2
+#define cchPort 4
+#endif /* not HP150 */
+#else /* not GENERIC_MSDOS */
+#define cPortMac 5
+#define cchPort 5
+#endif /* GENERIC_MSDOS */
+
+#define fntMax 6
+
+struct PCSD
+ { /* printer control sequence descriptor */
+ int bprcc; /* byte offset of start of control sequence */
+ CHAR bMod; /* modification byte */
+ CHAR cch; /* length of control sequence */
+ CHAR bMagic; /* magic number */
+ CHAR bMax; /* max value of parameter */
+ };
+#endif /* PRDFILES */
+
+#define hpsMin 8
+#define hpsMax 256
+#define cchFontSize 4
+#define iszSizeMax 32
+#define iffnEnumMax 64
+#define psFontMin 4
+#define psFontMax 127
+
+/* macros used to get/put pitch and font family info in windows data structs */
+#define bitPitch 0x01
+#define grpbitFamily 0xf0
+
+typedef CHAR FFID; /* font family ID */
+
+#define iftcRoman 0
+#define iftcModern 1
+#define iftcScript 2
+#define iftcDecorative 3
+#define iftcSwiss 4
+
+#ifdef SYSENDMARK
+#define ftcSystem 0x3E
+#define bitFtcChp 0x3E
+#endif /* KANJI */
+#define ftcNil 255
+#define cchFfnMin 1
+#define chGhost '\003'
+
+#define iffnProfMax 5 /* # of fonts described in win.ini list */
+
+#define LocalFaceSize 32
+#ifndef LF_FACESIZE
+/* this is gross, but so's our compiler! */
+#define LF_FACESIZE LocalFaceSize
+#endif
+
+#ifdef NEWFONTENUM
+#define ibFfnMax (LF_FACESIZE + sizeof(FFID) + sizeof(BYTE) + 1 /* to make it a max */)
+#else
+#define ibFfnMax (LF_FACESIZE + sizeof(FFID) + 1)
+#endif
+#define CbFfn(cch) (sizeof(struct FFN) - cchFfnMin + (cch))
+
+/* Added 5/5/89: insure we only touch memory to which we're entitled ..pault */
+#define CbFromPffn(pffn) (sizeof(FFID)+sizeof(BYTE)+CchSz((pffn)->szFfn))
+
+/* NOTE: If this structure is changed, CbFromPffn() above must be updated! */
+typedef struct FFN /* Font Family Name */
+ {
+#ifdef NEWFONTENUM
+ BYTE chs; /* The charset associated with this facename
+ (ANSI, OEM, Symbol, etc). We've kludged the
+ way that FFN's are written out in documents
+ so see HffntbForNewDoc() ..pault */
+#endif
+ FFID ffid;
+ /* really a variable length string */
+ CHAR szFfn[cchFfnMin];
+ };
+
+/* 255 ffn's lets us map ftc's in a single byte, with one nil value */
+#define iffnMax 255
+#define cffnMin 1
+typedef struct FFNTB /* font table */
+ {
+ unsigned int iffnMac: 15;
+ unsigned int fFontMenuValid: 1; /* Used for names on CHAR dropdown */
+ struct FFN **mpftchffn[cffnMin];
+ };
+
+struct FFNTB **HffntbCreateForFn();
+struct FFNTB **HffntbNewDoc();
+struct FFNTB **HffntbAlloc();
+struct FFN *PffnDefault();
+#define HffntbGet(doc) ((**hpdocdod)[(doc)].hffntb)
+
+/* following structures support font information caching */
+
+#define fcidNil 0xffffffffL
+
+typedef union FCID /* font cache identifier */
+ {
+ long lFcid;
+ struct
+ {
+ unsigned ftc : 8;
+ unsigned hps : 8;
+ unsigned doc : 4;
+ unsigned wFcid : 12;
+ } strFcid;
+ };
+
+/* bits set in wFcid */
+#define grpbitPsWidthFcid 0x007f
+#define bitFixedPitchFcid 0x0080
+#define bitUlineFcid 0x0100
+#define bitBoldFcid 0x0200
+#define bitItalicFcid 0x0400
+#define bitPrintFcid 0x0800
+
+#define psWidthMax 127
+
+typedef struct FMI /* font metric information */
+ {
+ int *mpchdxp; /* pointer to width table */
+ /* NOTE - we actually point chDxpMin entries
+ before the start of the table, so
+ that the valid range begins at the
+ start of the actual table */
+ int dxpSpace; /* width of a space */
+ int dxpOverhang; /* overhang for italic/bold chars */
+ int dypAscent; /* ascent */
+ int dypDescent; /* descent */
+ int dypBaseline; /* difference from top of cell to baseline */
+ int dypLeading; /* accent space plus recommended leading */
+#ifdef DBCS
+ int dypIntLeading; /* internal leading */
+ BYTE dxpDBCS; /* width of a DBCS character. */
+ /* WARNING - This assumes a kanji character
+ is fixed pitch. */
+ BYTE bDummy; /* To guarantee that this addition
+ increases the amount by 1 word. */
+#endif /* DBCS */
+ };
+
+#define chFmiMin 0x20
+#ifdef WIN30
+ /* Why are we not asking for widths of all characters? We should. */
+#ifdef KOREA
+#define chFmiMax 0x80
+#else
+#define chFmiMax 0x100
+#endif
+
+#else
+#define chFmiMax 0x80
+#endif
+
+#define dxpNil 0xFFFF
+
+typedef struct FCE /* font cache entry */
+ {
+ struct FCE *pfceNext; /* next entry in lru list */
+ struct FCE *pfcePrev; /* prev entry in lru list */
+ union FCID fcidRequest; /* request this entry satisfied */
+ union FCID fcidActual; /* what this entry really contains */
+ struct FFN **hffn; /* font family name */
+ struct FMI fmi; /* helpful metric information for this entry */
+ HFONT hfont; /* windows' font object */
+ int rgdxp[chFmiMax - chFmiMin]; /* width table proper */
+ };
+
+#define ifceMax 16
+struct FCE *PfceLruGet();
+struct FCE *PfceFcidScan();
+
+/* values to be passed to LoadFont() directing it's actions */
+#define mdFontScreen 0 /* sets font for random screen chars */
+#define mdFontChk 1 /* sets font as constrained by printer avail */
+#define mdFontJam 2 /* like mdFontChk, but jams props into chp */
+#define mdFontPrint 3 /* like mdFontScreen, but for the printer */
+
+#ifdef SAND
+typedef struct { /* structure of a Macintosh font. See Font Manager */
+ int frFontType; /* fr was prepended to each element to */
+ int frFirstChar; /* prevent "name collision" with the */
+ int frLastChar; /* elements of FONTINFO */
+ int frWidMax;
+ int frKernMax;
+ int frNDescent;
+ int frFRectMax;
+ int frChHeight;
+ int frOwTLoc;
+ int frAscent;
+ int frDescent;
+ int frLeading;
+ int frRowWords;
+ } FONTREC;
+
+#define woFrOwTLoc 8 /* The word offset of the owTLoc from the beginning */
+#define wdthTabFrOwTLoc 4 /* The frOwTLoc for a width table */
+
+typedef struct {
+ int family;
+ int size;
+ int face;
+ int needBits;
+ int device;
+ POINT numer;
+ POINT denom;
+ } FMINPUT;
+
+typedef struct {
+ int errNum;
+ HANDLE fontHandle;
+ CHAR bold;
+ CHAR italic;
+ CHAR ulOffset;
+ CHAR ulShadow;
+ CHAR ulThick;
+ CHAR shadow;
+ CHAR extra;
+ CHAR ascent;
+ CHAR descent;
+ CHAR widMax;
+ CHAR leading;
+ CHAR unused;
+ POINT numer;
+ POINT denom;
+ } FMOUTPUT;
+
+#define qFMOUTPUT ((FMOUTPUT far *) 0x998)
+#endif /* SAND */
+
+#define enumFaceNames 0
+#define enumFindAspectRatio 1
+#define enumSizeList 2
+#define enumCheckFont 3
+#define enumQuickFaces 4
+
+#ifdef NEWFONTENUM
+#define psApprovedMax 48 /* don't know why we don't go up to 64 here; spose
+ that's for "the big boy word processors" ..pault */
+#endif
+
+/* Used in DOPRM.C and FONTENUM.C */
+#define csizeApprovedMax 13
+
diff --git a/private/mvdm/wow16/write/fontdlg.c b/private/mvdm/wow16/write/fontdlg.c
new file mode 100644
index 000000000..bb06e2743
--- /dev/null
+++ b/private/mvdm/wow16/write/fontdlg.c
@@ -0,0 +1,206 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Fontdlg.c -- WRITE font dialog routines */
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "dlgdefs.h"
+#include "propdefs.h"
+#include "fontdefs.h"
+#include "prmdefs.h"
+#include "str.h"
+#include "docdefs.h"
+#include <commdlg.h>
+
+extern HDC vhDCPrinter;
+extern struct DOD (**hpdocdod)[];
+extern HANDLE hMmwModInstance;
+extern HANDLE hParentWw;
+extern int vfSeeSel;
+extern int docCur;
+extern HWND vhWndMsgBoxParent;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+
+extern int iszSizeEnum;
+extern int iszSizeEnumMac;
+extern int iszSizeEnumMax;
+extern int iffnEnum;
+extern int vfFontEnumFail;
+extern struct FFNTB **hffntbEnum;
+
+
+BOOL NEAR FValidateEnumFfid(struct FFN *);
+
+
+
+int FAR PASCAL NewFont(HWND hwnd)
+{
+ TSV rgtsv[itsvchMax]; /* gets attributes and gray flags from CHP */
+ int ftc;
+ int fSetUndo;
+ CHAR rgb[2];
+ CHOOSEFONT cf;
+ LOGFONT lf;
+ HDC hdc;
+
+ if (!vhDCPrinter)
+ return FALSE;
+
+ GetRgtsvChpSel(rgtsv);
+
+ bltbc(&lf, 0, sizeof(LOGFONT));
+ bltbc(&cf, 0, sizeof(CHOOSEFONT));
+
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = hwnd;
+ cf.lpLogFont = &lf;
+ cf.hDC = vhDCPrinter;
+ cf.nSizeMin = 4;
+ cf.nSizeMax = 127;
+ cf.Flags = CF_NOSIMULATIONS| CF_PRINTERFONTS | CF_INITTOLOGFONTSTRUCT | CF_LIMITSIZE;
+
+ // check for multiple sizes selected
+ if (rgtsv[itsvSize].fGray) {
+ cf.Flags |= CF_NOSIZESEL;
+ } else {
+ hdc = GetDC(NULL);
+ lf.lfHeight = -MulDiv(rgtsv[itsvSize].wTsv / 2, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(NULL, hdc);
+ }
+
+ // check for multiple faces selected
+ if (rgtsv[itsvFfn].fGray) {
+ cf.Flags |= CF_NOFACESEL;
+ lf.lfFaceName[0] = 0;
+ } else {
+ struct FFN **hffn;
+ /* then, font name */
+
+ /* note that the value stored in rgtsv[itsvFfn].wTsv
+ is the font name handle, rather than the ftc */
+
+ hffn = (struct FFN **)rgtsv[itsvFfn].wTsv;
+ lstrcpy(lf.lfFaceName, (*hffn)->szFfn);
+ }
+
+ // check for multiple styles selected
+ if (rgtsv[itsvBold].fGray || rgtsv[itsvItalic].fGray) {
+ cf.Flags |= CF_NOSTYLESEL;
+ } else {
+ lf.lfWeight = rgtsv[itsvBold].wTsv ? FW_BOLD : FW_NORMAL;
+ lf.lfItalic = rgtsv[itsvItalic].wTsv;
+ }
+
+ if (!ChooseFont(&cf))
+ return FALSE;
+
+ fSetUndo = TRUE;
+
+ if (!(cf.Flags & CF_NOFACESEL))
+ {
+ CHAR rgbFfn[ibFfnMax];
+ struct FFN *pffn = (struct FFN *)rgbFfn;
+
+ lstrcpy(pffn->szFfn, lf.lfFaceName);
+ pffn->ffid = lf.lfPitchAndFamily & grpbitFamily;
+ pffn->chs = lf.lfCharSet;
+
+ FValidateEnumFfid(pffn);
+
+ ftc = FtcChkDocFfn(docCur, pffn);
+
+ if (ftc != ftcNil) {
+ rgb[0] = sprmCFtc;
+ rgb[1] = ftc;
+ AddOneSprm(rgb, fSetUndo);
+ }
+ }
+
+ if (!(cf.Flags & CF_NOSIZESEL)) {
+ /* we got a value */
+ rgb[0] = sprmCHps;
+ rgb[1] = cf.iPointSize / 10 * 2; /* KLUDGE alert */
+ AddOneSprm(rgb, fSetUndo);
+ fSetUndo = FALSE;
+ }
+
+ if (!(cf.Flags & CF_NOSTYLESEL)) {
+ ApplyCLooks(0, sprmCBold, lf.lfWeight > FW_NORMAL);
+ ApplyCLooks(0, sprmCItalic, lf.lfItalic ? 1 : 0);
+ }
+
+ return TRUE;
+}
+
+
+
+BOOL NEAR FValidateEnumFfid(pffn)
+/* if the described ffn is in the enumeration table, then make sure we have
+ a good family number for it */
+
+struct FFN *pffn;
+ {
+ int ftc;
+ struct FFN *pffnAlready;
+
+ ftc = FtcScanFfn(hffntbEnum, pffn);
+ if (ftc != ftcNil)
+ {
+ pffnAlready = *((*hffntbEnum)->mpftchffn[ftc]);
+#if JAPAN
+ // Few fonts would be enumnrated with FF_DONTCARE in JAPAN
+ // we won't check ffid here.
+#else
+ if (pffnAlready->ffid != FF_DONTCARE)
+#endif
+ {
+ pffn->ffid = pffnAlready->ffid;
+#ifdef NEWFONTENUM
+ pffn->chs = pffnAlready->chs;
+#endif
+ return(TRUE);
+ }
+ }
+ return(FALSE);
+ }
+
+
+
+
diff --git a/private/mvdm/wow16/write/fontenum.c b/private/mvdm/wow16/write/fontenum.c
new file mode 100644
index 000000000..1a9a5e71b
--- /dev/null
+++ b/private/mvdm/wow16/write/fontenum.c
@@ -0,0 +1,547 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Fonts.c -- WRITE font routines */
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "dlgdefs.h"
+#include "propdefs.h"
+#include "fontdefs.h"
+#include "prmdefs.h"
+#include "str.h"
+#include "docdefs.h"
+
+#ifdef DBCS
+#include "kanji.h"
+#endif
+
+extern struct DOD (**hpdocdod)[];
+extern HANDLE hMmwModInstance;
+extern HANDLE hParentWw;
+extern int vfSeeSel;
+extern int docCur;
+extern HWND vhWndMsgBoxParent;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+
+
+int iszSizeEnum;
+int iszSizeEnumMac;
+int iszSizeEnumMax;
+extern CHAR szSystem[];
+
+#ifdef DBCS_VERT
+extern CHAR szAtSystem[]; // Use for '@' fontface checking.
+#endif
+
+int iffnEnum;
+int vfFontEnumFail;
+struct FFNTB **hffntbEnum = NULL;
+
+#ifdef NEWFONTENUM
+/* Changed because it is INCORRECT to filter out all non-ANSI
+ character sets. Also we've removed this aspect-ratio checking
+ stuff ..pault */
+
+#define FCheckFont(lptm) (1)
+#else
+BOOL FCheckFont(lptm)
+LPTEXTMETRIC lptm;
+ {
+ /* This routine returns TRUE iff the character set for this font is the
+ ANSI set and either this is a vector font or the aspect ratio is correct. */
+
+ extern int aspectXFont;
+ extern int aspectYFont;
+
+ return (
+#ifdef DBCS
+ lptm->tmCharSet == KANJI_CHARSET
+#else
+ lptm->tmCharSet == ANSI_CHARSET
+#endif
+ && ((lptm->tmPitchAndFamily & 0x6) == 0x2
+ || (lptm->tmDigitizedAspectX == aspectXFont
+ && lptm->tmDigitizedAspectY == aspectYFont)));
+ }
+#endif /* else-def-NEWFONTENUM */
+
+
+
+/* FontFaceEnum used to be called for a number of reasons so it used
+ rg[] to pass in parameters to get it to do different things including
+ aspect-ratio filtering. I've simplified this a great deal so Write
+ will allow more things (this can be good or bad) ..pault */
+
+BOOL far PASCAL FontFaceEnum(lplf, lptm, fty, lParam)
+LPLOGFONT lplf;
+LPTEXTMETRIC lptm;
+int fty; /* font type, passed through from the EnumFonts call: */
+ /* fty & RASTER_FONTTYPE == fRasterFont */
+ /* fty & DEVICE_FONTTYPE == fDeviceFont */
+long lParam;
+ {
+ /* Callback routine to record all of the appropriate face names for the
+ current printer. "appropriate" is based on the params as follows:
+
+ * rgw[0]=0 normal mode,
+ =enumQuickFaces indicates "streamlined mode"
+ (i.e. ignore all the following params in this case), and
+ =
+ * rgw[1]=RASTER_FONTTYPE if only raster fonts are to be enumerated,
+ * =DEVICE_FONTTYPE if only device fonts are to be enumerated,
+ * =TRUETYPE_FONTTYPE if only TRUE_TYPE fonts are to be enumerated,
+ * rgw[2]=desired font family code (e.g. we start out
+ only wanting swiss, and later expand that)
+ * rgw[3] indicates whether or not we must match rgw[2]
+ * rgw[4]=max number of fonts we have room for
+
+ ..pault 10/12/89*/
+
+ int *rgw = (int *)LOWORD(lParam);
+
+ /* Stop enumerating if we have enough fonts */
+
+ if ((*hffntbEnum)->iffnMac >= rgw[4])
+ /* we have all we need */
+ return(FALSE);
+
+#ifdef DENUMF
+ {
+ char rgch[100];
+ wsprintf(rgch,"FFEn: %s, devicebit %d rasterbit %d ",lplf->lfFaceName,
+ fty&DEVICE_FONTTYPE, fty&RASTER_FONTTYPE);
+ CommSz(rgch);
+ }
+#endif
+
+ if ((rgw[0] == enumQuickFaces) ||
+ /* Is this the right type of font? */
+ ((fty & rgw[1]) &&
+ /* Does this font belong to the correct family? Well
+ when rgw[3] says: NEEDN'T MATCH then of course it does, and
+ when rgw[3] says: MATCH then we check to see! */
+ ((rgw[3] == 0)||((lptm->tmPitchAndFamily&grpbitFamily) == rgw[2]))))
+ {
+ CHAR rgb[ibFfnMax];
+ struct FFN *pffn = (struct FFN *)rgb;
+
+ bltbx(lplf->lfFaceName, (LPSTR)pffn->szFfn,
+ umin(LF_FACESIZE, IchIndexLp((LPCH)lplf->lfFaceName, '\0')+1));
+ pffn->chs = lplf->lfCharSet; /* save this setting */
+
+ /* We're interested in this one */
+ if (FCheckFont(lptm) && (*hffntbEnum)->iffnMac < iffnEnumMax)
+ {
+ pffn->ffid = lplf->lfPitchAndFamily & grpbitFamily;
+#ifdef DENUMF
+ CommSz("(adding)");
+#endif
+ if (!FAddEnumFont(pffn))
+ {
+ /* Couldn't add it to the table. */
+ vfFontEnumFail = TRUE;
+ return(FALSE);
+ }
+ }
+ }
+#ifdef DENUMF
+ CommSz("\n\r");
+#endif
+
+ return(TRUE);
+ }
+
+FInitFontEnum(doc, cffnInteresting, fOrder)
+/* sets up for a font enumeration, where caller cares about
+ 'cffnInteresting' fonts, and special stuff is done iff 'fOrder'
+ (to help us pick good default font(s) on startup */
+
+int doc, cffnInteresting, fOrder;
+ {
+ extern HDC vhDCPrinter;
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpFontFaceEnum;
+#else
+ FARPROC lpFontFaceEnum = NULL;
+#endif
+
+ int iffn, iffnMac;
+ struct FFNTB **hffntb;
+ struct FFN *pffn, **hffn;
+ struct FFN ffn;
+ CHAR rgb[ibFfnMax];
+ int rgw[5];
+
+ vfFontEnumFail = FALSE;
+
+ if (hffntbEnum != NULL)
+ {
+ return(FALSE);
+ }
+
+ if (FNoHeap(hffntbEnum = HffntbAlloc()))
+ {
+ hffntbEnum = NULL;
+ return(FALSE);
+ }
+
+ /* First we list all the fonts used in the current doc's ffntb */
+
+#ifdef DENUMF
+ CommSzNumNum("FINITFONTENUM: cffnInteresting,fOrder ",cffnInteresting,fOrder);
+#endif
+ if (doc != docNil)
+ {
+ hffntb = HffntbGet(doc);
+ iffnMac = imin((*hffntb)->iffnMac, iffnEnumMax);
+ pffn = (struct FFN *)rgb;
+ for (iffn = 0; iffn < iffnMac; iffn++)
+ {
+ hffn = (*hffntb)->mpftchffn[iffn];
+ bltbyte((*hffn), pffn, CbFromPffn(*hffn));
+ if (!FAddEnumFont(pffn))
+ goto InitFailure;
+ }
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ {
+ goto HaveCffnInteresting;
+ }
+ }
+
+#if 0
+ /* Include the fonts from WIN.INI in the enumeration */
+ if (!FAddProfileFonts())
+ {
+ goto InitFailure;
+ }
+#endif
+
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting;
+
+ if (vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ Assert(vhDCPrinter);
+ }
+
+#ifndef INEFFLOCKDOWN
+ if (!(lpFontFaceEnum = MakeProcInstance(FontFaceEnum, hMmwModInstance)))
+ {
+ WinFailure();
+ goto InitFailure;
+ }
+#endif
+
+ /* See what the system knows about!
+ If order ISN'T significant, we'll examine all fonts at once. */
+
+ if (!fOrder)
+ {
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(all) \n\r");
+#endif
+ rgw[0] = enumQuickFaces; // means igonre the rest
+#if 0
+ rgw[1] = RASTER_FONTTYPE; // ignored, why set?
+ rgw[2] = FF_SWISS; // ignored, why set?
+ rgw[3] = TRUE; // ignored, why set?
+ rgw[4] = cffnInteresting; // ignored, why set?
+#endif
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ else
+ goto HaveCffnInteresting; /* got what we needed */
+ }
+
+ /* Ahh... but since we now know order IS significant, i.e. we are
+ trying to pick good default fonts for startup, we'll try in steps:
+
+ #1--any good TrueType fonts in the Swiss font family?
+ #2--any good TrueType fonts in the non-Swiss?
+ #3--any good device-based fonts in the Swiss font family?
+ #4-- " " " " non-Swiss?
+ #5--any non device-based fonts in the Swiss font family?
+ #6-- " " " " non-Swiss? */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(Swiss truetype) \n\r");
+#endif
+ rgw[0] = enumFaceNames;
+ rgw[1] = TRUETYPE_FONTTYPE;
+ rgw[2] = FF_SWISS;
+ rgw[3] = TRUE; /* match swiss! */
+ rgw[4] = 32767;
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting; /* got what we needed */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(nonSwiss truetype) \n\r");
+#endif
+ rgw[3] = FALSE; /* need not match swiss! */
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting; /* got what we needed */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(Swiss device) \n\r");
+#endif
+ rgw[1] = DEVICE_FONTTYPE;
+ rgw[3] = TRUE; /* match swiss! */
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting; /* got what we needed */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(nonSwiss device) \n\r");
+#endif
+ rgw[3] = FALSE; /* need not match swiss */
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting; /* got what we needed */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(Swiss nondevice) \n\r");
+#endif
+ rgw[1] = RASTER_FONTTYPE;
+ rgw[3] = TRUE; /* match swiss! */
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+ if ((*hffntbEnum)->iffnMac >= cffnInteresting)
+ goto HaveCffnInteresting; /* got what we needed */
+
+#ifdef DENUMF
+ CommSz("FINITFONTENUM: EnumFonts(Swiss nondevice) \n\r");
+#endif
+ rgw[3] = FALSE; /* need not match swiss */
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ if (vfFontEnumFail)
+ goto InitFailure;
+
+HaveCffnInteresting:
+ iffnEnum = 0;
+#ifndef INEFFLOCKDOWN
+ if (lpFontFaceEnum)
+ FreeProcInstance(lpFontFaceEnum);
+#endif
+ return(TRUE);
+
+InitFailure:
+ FreeFfntb(hffntbEnum);
+ hffntbEnum = NULL;
+#ifndef INEFFLOCKDOWN
+ if (lpFontFaceEnum)
+ FreeProcInstance(lpFontFaceEnum);
+#endif
+ return(FALSE);
+ }
+
+void ResetFontTables(void)
+{
+ /*
+ Free the pfce's. LoadFont will reallocate them with new information
+ obtained below.
+ */
+ FreeFonts(TRUE,TRUE);
+
+ /* This is a clumsy method that takes advantage of side effect of
+ resetting the data stored in the font tables */
+ FInitFontEnum(docNil, 32767, FALSE);
+ EndFontEnum();
+}
+
+CHAR * (NEAR PchSkipSpacesPch( CHAR * ));
+
+int WFromSzNumber( ppch )
+CHAR **ppch;
+{ /* Given an ASCII string containing a (base 10) number, return the number
+ represented. Ignores leading and trailing spaces.
+ Does not accept negative numbers. */
+ /* 10/12/89 ..pault
+ Now increments the pointer to just past last digit converted */
+
+ unsigned w = 0;
+ CHAR ch;
+
+ *ppch = PchSkipSpacesPch( *ppch );
+ while ( ((ch = (*(*ppch)++)) >= '0') && (ch <= '9') )
+ {
+ w = (w * 10) + (ch - '0');
+ }
+
+ (*ppch)--; /* bumped one too far */
+ return w;
+}
+
+
+CHAR * (NEAR PchSkipSpacesPch( pch ))
+CHAR *pch;
+{ /* Return a pointer to the first character in the string
+ at pch that is either null or non-whitespace */
+
+ for ( ;; ) {
+#ifdef DBCS
+ /* DB Char space must be checked */
+ if (FKanjiSpace(*pch, *(pch + 1))) {
+ pch += cchKanji;
+ continue;
+ }
+#endif /* DBCS */
+ switch (*pch) {
+ default:
+ return pch;
+ case ' ':
+ case 0x09:
+ pch++;
+ break;
+ }
+ }
+}
+
+
+BOOL FEnumFont(pffn)
+/* returns the next font entry through pffn. Returns FALSE if no more */
+
+struct FFN *pffn;
+ {
+ int cb;
+ struct FFN **hffn;
+
+ if (iffnEnum >= (*hffntbEnum)->iffnMac)
+ {
+ return(FALSE);
+ }
+
+ hffn = (*hffntbEnum)->mpftchffn[iffnEnum];
+#ifdef DEBUG
+ cb = CchSz( (*hffn)->szFfn );
+ Assert( cb <= LF_FACESIZE );
+ cb = CbFfn( cb );
+#else
+ cb = CbFfn(CchSz((*hffn)->szFfn));
+#endif
+ bltbyte(*hffn, pffn, cb);
+ iffnEnum++;
+ return(TRUE);
+ }
+
+
+EndFontEnum()
+/* cleans up after a font enumeration */
+ {
+ FreeFfntb(hffntbEnum);
+ hffntbEnum = NULL;
+ }
+
+
+FAddEnumFont(pffn)
+/* code factoring for adding described font to enumeration table - filters
+ out "ghost fonts" and system font */
+
+struct FFN *pffn;
+ {
+#ifdef JAPAN
+// It is required to do vertical writing with system font in JAPAN.
+ if ( pffn->szFfn[0] == chGhost)
+#else
+ if (WCompSz(pffn->szFfn, szSystem) == 0 || pffn->szFfn[0] == chGhost)
+#endif
+ return(TRUE);
+ return(FEnsurePffn(hffntbEnum, pffn));
+ }
+
+
+
+#ifdef NEWFONTENUM
+/* This stuff added for Win3 because we have to be able to determine
+ with which character set a font in a particular document is associated,
+ since our file format does not store it. Naturally, WinWord added that
+ to their file format! ..pault */
+
+/* Look through the list of fonts sitting out there [i.e. FInitFontEnum
+ must have been called, and it is from HffntbForFn()] and make our best
+ guess as to what CharSet it's supposed to have, since we don't store
+ these in the doc font table! */
+
+int ChsInferred( pffn )
+struct FFN *pffn;
+ {
+ struct FFN *pffnCheck;
+ char *sz = pffn->szFfn;
+#ifdef DBCS
+ int chs = KANJI_CHARSET;
+#else
+ int chs = 0;
+#endif
+ int i, iMac = (*hffntbEnum)->iffnMac;
+
+ for (i = 0; i < iMac; i++)
+ {
+ pffnCheck = *(struct FFN **) ((*hffntbEnum)->mpftchffn[i]);
+ if (WCompSz(pffnCheck->szFfn, sz) == 0)
+ {
+#ifdef DIAG
+ if (pffnCheck->ffid != pffn->ffid)
+ {
+ CommSzSz("ChsInferred: matched fontname ",sz);
+ CommSzNumNum(" but enum->ffid / doc->ffid", pffnCheck->ffid,pffn->ffid);
+ }
+#endif
+ Assert(pffnCheck->ffid == pffn->ffid);
+ chs = pffnCheck->chs;
+ break;
+ }
+ }
+ return(chs);
+ }
+#endif /* NEWFONTENUM */
+
+
diff --git a/private/mvdm/wow16/write/fontutil.c b/private/mvdm/wow16/write/fontutil.c
new file mode 100644
index 000000000..d0d4b6745
--- /dev/null
+++ b/private/mvdm/wow16/write/fontutil.c
@@ -0,0 +1,262 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* FontUtil.c -- font table management routines */
+
+#define NOVIRTUALKEYCODES
+#define NOCTLMGR
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "debug.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+#include "editdefs.h"
+#include "str.h"
+#include "prmdefs.h"
+#include "printdef.h"
+#include "fontdefs.h"
+
+extern struct DOD (**hpdocdod)[];
+
+
+struct FFNTB **HffntbAlloc()
+/* returns empty ffntb */
+{
+struct FFNTB **hffntb;
+int cwAlc;
+
+cwAlc = CwFromCch(sizeof(struct FFNTB) - cffnMin * sizeof(struct FFN **));
+if (!FNoHeap(hffntb = (struct FFNTB **)HAllocate(cwAlc)))
+ {
+ (*hffntb)->iffnMac = 0;
+ (*hffntb)->fFontMenuValid = FALSE;
+ }
+return(hffntb);
+}
+
+
+
+FtcAddDocFfn(doc, pffn)
+/* adds the described ffn to the ffntb for this doc - returns ftcNil if the
+ allocation failed */
+
+int doc;
+struct FFN *pffn;
+{
+struct FFNTB **hffntb;
+
+hffntb = HffntbGet(doc);
+if (hffntb == 0)
+ {
+ hffntb = HffntbAlloc();
+ if (FNoHeap(hffntb))
+ return(ftcNil);
+ (**hpdocdod)[doc].hffntb = hffntb;
+ }
+
+return(FtcAddFfn(hffntb, pffn));
+}
+
+
+
+int FtcAddFfn(hffntb, pffn)
+/* adds the described ffn to hffntb. returns ftcNil if it fails */
+struct FFNTB **hffntb;
+struct FFN *pffn;
+
+{
+unsigned cb;
+int cwAlloc, iffnMac, ftc;
+FFID ffid;
+struct FFN **hffn;
+
+(*hffntb)->fFontMenuValid = FALSE; /* so fonts on char dropdown get updated */
+ftc = ftcNil;
+ffid = pffn->ffid;
+
+cb = CchSz( pffn->szFfn );
+if (cb > LF_FACESIZE)
+ {
+ Assert( FALSE ); /* If we get here, the doc's font tables are prob. bad */
+ cb = LF_FACESIZE;
+ }
+Assert( cb > 0 );
+
+cwAlloc = CwFromCch( CbFfn( cb ) );
+if (!FNoHeap(hffn = (struct FFN **)HAllocate(cwAlloc)))
+ {
+ blt(pffn, *hffn, cwAlloc);
+ (*hffn)->szFfn[ cb - 1 ] = '\0'; /* In case of font name too big */
+
+ iffnMac = (*hffntb)->iffnMac + 1;
+ cwAlloc = CwFromCch(sizeof(struct FFNTB) +
+ (iffnMac - cffnMin) * sizeof(struct FFN **));
+ if (FChngSizeH(hffntb, cwAlloc, FALSE))
+ {
+ ftc = iffnMac - 1; /* ?! pault */
+ (*hffntb)->mpftchffn[ftc] = hffn;
+ (*hffntb)->iffnMac = iffnMac;
+ }
+ else
+ {
+ FreeH(hffn);
+ }
+ }
+
+return(ftc);
+}
+
+
+
+FEnsurePffn(hffntb, pffn)
+/* return TRUE if we were able to add the described font to the table - this
+ routine is just a convenience, the other pieces aren't that complex to
+ call. */
+
+struct FFNTB **hffntb;
+struct FFN *pffn;
+{
+if (FtcScanFfn(hffntb, pffn) != ftcNil ||
+ FtcAddFfn(hffntb, pffn) != ftcNil)
+ return(TRUE);
+return(FALSE);
+}
+
+
+
+FtcScanDocFfn(doc, pffn)
+/* looks for described font in docs ffntb - returns ftcNil if not found */
+
+int doc;
+struct FFN *pffn;
+{
+int ftc;
+struct FFNTB **hffntb;
+
+ftc = ftcNil;
+hffntb = HffntbGet(doc);
+if (hffntb != 0)
+ ftc = FtcScanFfn(hffntb, pffn);
+
+return(ftc);
+}
+
+
+
+FtcScanFfn(hffntb, pffn)
+struct FFNTB **hffntb;
+struct FFN *pffn;
+
+{
+int iffn, iffnMac;
+struct FFN ***mpftchffn;
+
+mpftchffn = (*hffntb)->mpftchffn;
+iffnMac = (*hffntb)->iffnMac;
+for (iffn = 0; iffn < iffnMac; iffn++)
+ {
+ if (WCompSz(pffn->szFfn, (*mpftchffn[iffn])->szFfn) == 0)
+ {
+ /* found it */
+ if (pffn->ffid != FF_DONTCARE)
+ {
+ /* maybe we discovered a family for this font? */
+ (*mpftchffn[iffn])->ffid = pffn->ffid;
+ (*mpftchffn[iffn])->chs = pffn->chs;
+ }
+ return(iffn);
+ }
+ }
+return(ftcNil);
+}
+
+
+
+FtcChkDocFfn(doc, pffn)
+/* Adds described font to doc's ffntb if it's not already there - ftcNil is
+ returned if it wasn't there and couldn't be added */
+
+int doc;
+struct FFN *pffn;
+{
+int ftc;
+
+ftc = FtcScanDocFfn(doc, pffn);
+if (ftc == ftcNil)
+ ftc = FtcAddDocFfn(doc, pffn);
+
+return(ftc);
+}
+
+
+
+FreeFfntb(hffntb)
+struct FFNTB **hffntb;
+{
+int iffn, iffnMac;
+
+if ((hffntb == 0) || FNoHeap(hffntb))
+ /* nothing to do */
+ return;
+
+iffnMac = (*hffntb)->iffnMac;
+for (iffn = 0; iffn < iffnMac; iffn++)
+ FreeH((*hffntb)->mpftchffn[iffn]);
+FreeH(hffntb);
+}
+
+
+
+SmashDocFce(doc)
+/* the font table for this doc has scrambled, so we need to disassociate
+ the corresponding cache entries from the doc */
+int doc;
+
+ {
+ extern int vifceMac;
+ extern union FCID vfcidScreen;
+ extern union FCID vfcidPrint;
+ extern struct FCE rgfce[ifceMax];
+ int ifce;
+
+ for (ifce = 0; ifce < vifceMac; ifce++)
+ if (rgfce[ifce].fcidRequest.strFcid.doc == doc)
+ rgfce[ifce].fcidRequest.strFcid.ftc = ftcNil;
+ vfcidScreen.strFcid.ftc = ftcNil;
+ vfcidPrint.strFcid.ftc = ftcNil;
+ }
diff --git a/private/mvdm/wow16/write/form1.c b/private/mvdm/wow16/write/form1.c
new file mode 100644
index 000000000..442c99cf2
--- /dev/null
+++ b/private/mvdm/wow16/write/form1.c
@@ -0,0 +1,1691 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*--- Module not really used, just the idea behind FORMAT.ASM ---*/
+
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOCLIPBOARD
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#include <windows.h>
+/* #include "wwsmall.h" */
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "ffdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "dispdefs.h"
+#include "scrndefs.h"
+#include "macro.h"
+#include "debug.h"
+#include "fontdefs.h"
+#include "str.h"
+#include "wwdefs.h"
+#ifdef DBCS
+#include "dbcs.h"
+#endif
+
+#ifdef DFLI
+#define Dfli(x) x /* Enable debug-format-line info */
+#else
+#define Dfli(x)
+#endif
+
+#ifdef CASHMERE
+#define cchSmcapMax 16
+#endif /* CASHMERE */
+
+static int ichpFormat;
+
+#ifdef CASHMERE
+static CHAR mptlcch[] = " .-_";
+#endif /* CASHMERE */
+
+extern int docHelp;
+extern struct FLI vfli;
+extern struct CHP (**vhgchpFormat)[];
+extern int ichpMacFormat;
+extern struct CHP vchpAbs;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern struct CHP vchpNormal;
+extern struct DOD (**hpdocdod)[];
+extern typeCP vcpLimSectCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFetch;
+extern int vichFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern int vcchFetch;
+extern int vftc;
+extern int ypSubSuper;
+extern int ypSubSuperPr;
+extern HDC vhMDC;
+extern HDC vhDCPrinter;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern int dypMax;
+extern struct FMI vfmiScreen, vfmiPrint;
+extern int vfOutOfMemory;
+extern CHAR vchDecimal; /* "decimal point" character */
+extern int vzaTabDflt; /* width of default tab */
+#ifdef CASHMERE
+extern int vfVisiMode;
+#endif /* CASHMERE */
+
+
+/* F O R M A T L I N E */
+FormatLine(doc, cp, ichCp, cpMac, flm)
+int doc;
+typeCP cp;
+int ichCp;
+typeCP cpMac;
+int flm;
+ {
+ /* Fills up vfli with a line of text */
+
+ int near Justify(struct IFI *, unsigned, int);
+ int near FGrowFormatHeap(void);
+ int near FFirstIch(int);
+
+ struct IFI ifi;
+ struct TBD *ptbd;
+ struct CHP chpLocal;
+ int xpTab;
+
+#ifdef CASHMERE
+ int dypBefore;
+#endif /* CASHMERE */
+
+ int dypAscent;
+ int dypDescent;
+ int dypAscentMac;
+ int dypDescentMac;
+ unsigned xaLeft;
+ unsigned xaRight;
+ struct PAP *ppap;
+ struct SEP *psep;
+ int fFlmPrinting = flm & flmPrinting;
+ int dxaFormat;
+ int dyaFormat;
+ int dxpFormat;
+ int dypFormat;
+ int ypSubSuperFormat;
+ int fTruncated = false; /* if the run was truncated */
+ int ichpNRH;
+
+
+
+#ifdef CASHMERE
+ struct FNTB **hfntb;
+ int fVisiMode;
+#endif /* CASHMERE */
+
+ /* Check for fli current */
+ if (vfli.doc == doc && vfli.cpMin == cp && vfli.ichCpMin == ichCp &&
+ vfli.flm == flm)
+ {
+ /* Just did this one */
+ return;
+ }
+
+ Scribble(5, 'F');
+ bltc(&vfli, 0, cwFLIBase);
+ /* This means:
+ vfli.fSplat = false;
+ vfli.dcpDepend = 0;
+ vfli.ichCpMac = 0;
+ vfli.dypLine = 0;
+ vfli.dypAfter = 0;
+ vfli.dypFont = 0;
+ vfli.dypBase = 0;
+ */
+
+ /* vfSplatNext = FALSE; No longer used. */
+
+ /* Rest of format loads up cache with current data */
+ vfli.doc = doc;
+ vfli.cpMin = cp;
+ vfli.ichCpMin = ichCp;
+ vfli.flm = flm;
+
+ if (cp > cpMac)
+ {
+ /* Space after the endmark. Reset the cache because the footnotes come
+ at the same cp in the footnote window */
+ vfli.doc = docNil;
+ vfli.cpMac = cp;
+ vfli.rgdxp[0] = 0;
+
+ /* Line after end mark is taller than screen */
+
+#ifdef CASHMERE
+ vfli.dypBase = vfli.dypFont = vfli.dypAfter = ((vfli.dypLine = dypMax)
+ >> 1);
+#else /* not CASHMERE */
+ vfli.dypBase = vfli.dypFont = ((vfli.dypLine = dypMax) >> 1);
+#endif /* not CASHMERE */
+
+ Scribble(5, ' ');
+ return;
+ }
+
+ /* Initialize run tables */
+ ichpFormat = 0;
+
+ /* Cache section and paragraph properties */
+
+#ifdef CASHMERE
+ hfntb = (**hpdocdod)[doc].hfntb;
+ if (hfntb == 0 || cp < (**hfntb).rgfnd[0].cpFtn)
+ {
+ /* Normal text */
+ CacheSect(doc, cp);
+ }
+ else
+ {
+ /* Footnote section properties come from the section of the footnote
+ reference. */
+ CacheSect(doc, CpRefFromFtn(doc, cp));
+ }
+#else /* not CASHMERE */
+ CacheSect(doc, cp);
+#endif /* not CASHMERE */
+
+ psep = &vsepAbs;
+
+ CachePara(doc, cp);
+ ppap = &vpapAbs;
+
+ /* Now we have:
+ ppap paragraph properties
+ psep division properties
+ */
+
+ if (ppap->fGraphics)
+ {
+ /* Format a picture paragraph in a special way (see picture.c) */
+ FormatGraphics(doc, cp, ichCp, cpMac, flm);
+ Scribble(5, ' ');
+ return;
+ }
+
+ /* Assure we have a good memory DC for font stuff */
+ ValidateMemoryDC();
+ if (vhMDC == NULL || vhDCPrinter == NULL)
+ {
+ Scribble(5, ' ');
+ return;
+ }
+
+#ifdef CASHMERE
+ /* When printing, don't show visible characters */
+ fVisiMode = vfVisiMode && !fFlmPrinting;
+#endif /* CASHMERE */
+
+ bltc(&ifi, 0, cwIFI);
+ /* This means:
+ ifi.ich = 0;
+ ifi.ichPrev = 0;
+ ifi.ichFetch = 0;
+ ifi.cchSpace = 0;
+ ifi.ichLeft = 0;
+ */
+
+ ifi.jc = jcTabLeft;
+ ifi.fPrevSpace = true;
+
+ /* Set up some variables that have different value depending on whether we
+ are printing or not. */
+ if (fFlmPrinting)
+ {
+ dxaFormat = dxaPrPage;
+ dyaFormat = dyaPrPage;
+ dxpFormat = dxpPrPage;
+ dypFormat = dypPrPage;
+ ypSubSuperFormat = ypSubSuperPr;
+ }
+ else
+ {
+ dxaFormat = dyaFormat = czaInch;
+ dxpFormat = dxpLogInch;
+ dypFormat = dypLogInch;
+ ypSubSuperFormat = ypSubSuper;
+ }
+
+ /* Calculate line height and width measures. Compute
+ xaLeft left indent 0 means at left margin
+ xaRight width of column measured from left margin (not from left
+ indent).
+ */
+ xaLeft = ppap->dxaLeft;
+
+ /* If this is the first line of a paragraph, adjust xaLeft for the first
+ line indent. (Also, set dypBefore, since its handy.) */
+ if (cp == vcpFirstParaCache)
+ {
+ xaLeft += ppap->dxaLeft1;
+
+#ifdef CASHMERE
+ dypBefore = MultDiv(ppap->dyaBefore, dypLogInch, czaInch);
+#endif /* CASHMERE */
+
+ }
+
+#ifdef CASHMERE
+ else
+ {
+ dypBefore = 0;
+ }
+#endif /* CASHMERE */
+
+ /* Now, set xaRight (width measured in twips). */
+
+#ifdef CASHMERE
+ xaRight = (ppap->rhc ? vsepPage.xaMac - vsepPage.dxaGutter :
+ psep->dxaText) - ppap->dxaRight;
+#else /* not CASHMERE */
+ xaRight = psep->dxaText - ppap->dxaRight;
+#endif /* not CASHMERE */
+
+
+ /* Do necessary checks on xaLeft and xaRight */
+ if (xaRight > xaRightMax)
+ {
+ xaRight = xaRightMax;
+ }
+ if (xaLeft > xaRightMax)
+ {
+ xaLeft = xaRightMax;
+ }
+ if (xaLeft < 0)
+ {
+ xaLeft = 0;
+ }
+ if (xaRight < xaLeft)
+ {
+ xaRight = xaLeft + 1;
+ }
+
+ vfli.xpLeft = ifi.xp = ifi.xpLeft = MultDiv(xaLeft, dxpFormat, dxaFormat);
+ vfli.xpMarg = ifi.xpRight = MultDiv(xaRight, dxpFormat, dxaFormat);
+ ifi.xpPr = MultDiv(xaLeft, dxpPrPage, dxaPrPage);
+ ifi.xpPrRight = MultDiv(xaRight, dxpPrPage, dxaPrPage);
+
+ /* Get a pointer to the tab-stop table. */
+ ptbd = ppap->rgtbd;
+
+ /* Turn off justification. */
+ SetTextJustification(fFlmPrinting ? vhDCPrinter : vhMDC, 0, 0);
+
+ /* Initialize the line height information. */
+ dypAscentMac = dypDescentMac = 0;
+
+ /* To tell if there were any tabs */
+ ifi.ichLeft = -1;
+
+ /* Get the first run, and away we go... */
+ FetchCp(doc, cp, ichCp, fcmBoth + fcmParseCaps);
+ goto FirstCps;
+
+ for ( ; ; )
+ {
+ int iichNew;
+ int xpPrev;
+ int dxp;
+ int dxpPr;
+
+ /* The number of characters to process (usually vcchFetch) */
+ int cch;
+
+ /* The number of characters in current run already used */
+ int cchUsed;
+
+ /* A pointer to the current list of characters (usually vpchFetch) */
+ CHAR *pch;
+
+#ifdef CASHMERE
+ CHAR rgchSmcap[cchSmcapMax];
+#endif /* CASHMERE */
+
+ if (ifi.ichFetch == cch)
+ {
+ /* End of a run */
+ int dich;
+ BOOL fSizeChanged;
+
+ if (ifi.ich >= ichMaxLine)
+ /* End of run because of line length limit has been reached. */
+ {
+ goto DoBreak;
+ }
+
+ if (fTruncated)
+ {
+ cchUsed += cch;
+ pch = vpchFetch + cchUsed;
+ cch = vcchFetch - cchUsed;
+ fTruncated = false;
+ goto OldRun; /* use the rest of the old run */
+ }
+
+NullRun:
+ FetchCp(docNil, cpNil, 0, fcmBoth + fcmParseCaps);
+FirstCps:
+
+ cchUsed = 0;
+
+ /* Continue fetching runs until a run is found with a nonzero
+ length. */
+ if ((cch = vcchFetch) == 0)
+ {
+ goto NullRun;
+ }
+
+ pch = vpchFetch;
+ if (vcpFetch >= cpMac || (!fFlmPrinting && *pch == chSect))
+ {
+#ifdef SYSENDMARK
+ /* Force end mark and section mark to be in standard system
+ font. */
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ vchpAbs.ftc = ftcSystem;
+ vchpAbs.ftcXtra = 0;
+ vchpAbs.hps = hpsDefault;
+#else
+#ifdef REVIEW
+ /* The following comment is absolutely misleading! Ftc==0
+ doesn't give you a system font. It gives you the first
+ entry in the font table. */
+#endif /* REVIEW */
+ /* Force end mark and section mark to be in standard system
+ font. */
+ blt(&vchpNormal, &vchpAbs, cwCHP);
+ vchpAbs.ftc = 0;
+ vchpAbs.ftcXtra = 0;
+ vchpAbs.hps = hpsDefault;
+#endif /* if-else-def KANJI */
+ }
+
+#ifdef CASHMERE
+ /* Adjust the size of the font for "small capitals". */
+ if (vchpAbs.csm == csmSmallCaps)
+ {
+ vchpAbs.hps = HpsAlter(vchpAbs.hps, -1);
+ }
+#endif /* CASHMERE */
+
+ /* Now we have:
+ ichpFormat index into gchp table
+ vcpFetch first cp of current run
+ vfli.cpMin first cp of line
+ ifi.ich ???
+ */
+
+ /* since LoadFont could change vchpAbs, and we don't want
+ that to happen, we copy vchpAbs into vchpLocal and use
+ vchpLocal in place of vchpAbs hereafter. Note that vchpAbs
+ is intentionally used above for handling the endmark. */
+
+ blt(&vchpAbs, &chpLocal, cwCHP);
+
+
+ if (fFlmPrinting)
+ {
+ LoadFont(doc, &chpLocal, mdFontPrint);
+ dypAscent = vfmiPrint.dypAscent + vfmiPrint.dypLeading;
+ dypDescent = vfmiPrint.dypDescent;
+ }
+ else
+ {
+ LoadFont(doc, &chpLocal, mdFontJam);
+ dypAscent = vfmiScreen.dypAscent + vfmiScreen.dypLeading;
+ dypDescent = vfmiScreen.dypDescent;
+ }
+
+#ifdef ENABLE /* BRYANL 8/27/87: New philosophy for handling
+ font selection failures is: font selection
+ ALWAYS succeeds. This prevents FormatLine
+ returns that do not advance. */
+ /* Bail out if there is a memory failure. */
+ if (vfOutOfMemory)
+ {
+ goto DoBreak;
+ }
+#endif /* ENABLE */
+
+ /* Floating line size algorithm */
+ if (chpLocal.hpsPos != 0)
+ {
+ /* Modify font for subscript/superscript */
+ if (chpLocal.hpsPos < hpsNegMin)
+ {
+ dypAscent += ypSubSuperFormat;
+ }
+ else
+ {
+ dypDescent += ypSubSuperFormat;
+ }
+ }
+
+ /* Update the maximum ascent and descent of the line. */
+ fSizeChanged = FALSE;
+ if (dypDescentMac < dypDescent)
+ {
+ dypDescentMac = dypDescent;
+ fSizeChanged = TRUE;
+ }
+ if (dypAscentMac < dypAscent)
+ {
+ dypAscentMac = dypAscent;
+ fSizeChanged = TRUE;
+ }
+
+
+ if (fSizeChanged)
+ {
+
+#ifdef AUTO_SPACING
+ /* This is the original Mac Word code that assumed line spacing
+ of 0 in a PAP meant auto line spacing. PC Word defaults to 1
+ line invalidating this assumption. */
+ if (ppap->dyaLine == 0)
+ {
+
+#ifdef CASHMERE
+ ifi.dypLineSize = dypDescentMac + dypAscentMac + dypBefore;
+#else /* not CASHMERE */
+ ifi.dypLineSize = dypDescentMac + dypAscentMac;
+#endif /* not CASHMERE */
+
+ }
+ else
+ {
+
+#ifdef CASHMERE
+ ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
+ dyaFormat) + dypBefore, dypBefore + 1);
+#else /* not CASHMERE */
+ ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
+ dyaFormat), 1);
+#endif /* not CASHMERE */
+
+ }
+#else /* not AUTO_SPACING */
+ /* This code forces auto line spacing except in the case where
+ the user specifies a line spacing greater than the auto line
+ spacing. */
+ {
+#ifdef CASHMERE
+ register int dypAuto = dypDescentMac + dypAscentMac +
+ dypBefore;
+#else /* not CASHMERE */
+ register int dypAuto = dypDescentMac + dypAscentMac;
+#endif /* not CASHMERE */
+
+ if (ppap->dyaLine > czaLine)
+ {
+
+#ifdef CASHMERE
+ register int dypUser = imax(MultDiv(ppap->dyaLine,
+ dypFormat, dyaFormat) + dypBefore, dypBefore + 1);
+#else /* not CASHMERE */
+ register int dypUser = imax(MultDiv(ppap->dyaLine,
+ dypFormat, dyaFormat), 1);
+#endif /* not CASHMERE */
+
+ ifi.dypLineSize = max(dypAuto, dypUser);
+ }
+ else
+ {
+ ifi.dypLineSize = dypAuto;
+ }
+ }
+#endif /* not AUTO_SPACING */
+
+ }
+
+OldRun:
+ /* Calculate length of the run but no greater than 256 */
+ iichNew = (int)(vcpFetch - vfli.cpMin);
+ if (iichNew >= ichMaxLine)
+ {
+ iichNew = ichMaxLine - 1;
+ }
+ dich = iichNew - ifi.ich;
+
+ /* Ensure that all tab and non-required hyphen characters start at
+ beginning of run */
+ if (ichpFormat <= 0 || dich > 0 || CchDiffer(&chpLocal,
+ &(**vhgchpFormat)[ichpFormat - 1], cchCHPUsed) != 0 || *pch ==
+ chTab || *pch == chNRHFile)
+ {
+#ifdef DFLI
+ if (*pch == chNRHFile)
+ CommSz("CHNRHFILE at beginning of run");
+#endif
+ if (ichpFormat != ichpMacFormat || FGrowFormatHeap())
+ {
+ register struct CHP *pchp = &(**vhgchpFormat)[ichpFormat -
+ 1];
+
+ if (ichpFormat > 0)
+ {
+ pchp->cchRun = ifi.ich - ifi.ichPrev;
+ pchp->ichRun = ifi.ichPrev;
+ }
+ blt(&chpLocal, ++pchp, cwCHP);
+
+#ifdef ENABLE /* font codes */
+ pchp->ftc = vftc;
+ pchp->ftcXtra = (vftc & 0x01c0) >> 6;
+ pchp->hps = vhps;
+#endif /* ENABLE */
+
+ pchp->cchRun = ichMaxLine;
+ if (dich <= 0)
+ {
+ pchp->ichRun = ifi.ich;
+ }
+ else
+ {
+ /* Q&D insert */
+ bltc(&vfli.rgdxp[ifi.ich], 0, dich);
+ bltbc(&vfli.rgch[ifi.ich], 0, dich);
+ pchp->ichRun = ifi.ich = iichNew;
+ }
+ ifi.ichPrev = ifi.ich;
+ ichpFormat++;
+ }
+ }
+
+ if (vcpFetch >= cpMac)
+ {
+ /* End of doc reached */
+ if (!ifi.fPrevSpace || vcpFetch == cp)
+ {
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ if (!fFlmPrinting && (doc != docHelp))
+ {
+ vfli.rgch[ifi.ich] = chEMark;
+ vfli.xpReal += (vfli.rgdxp[ifi.ich++] = DxpFromCh(chEMark,
+ false));
+ }
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypBase = dypDescentMac;
+ vfli.dypFont = dypAscentMac + dypDescentMac;
+ vfli.ichMac = vfli.ichReal = ifi.ich;
+ vfli.cpMac = cpMac + 1;
+ goto JustEol; /* dcpDepend == 0 */
+ }
+
+ /* Here we have ifi.ich, cch */
+ if (ifi.ich + cch > ichMaxLine)
+ /* If this run would put the line over 255, truncate it and set a
+ flag. */
+ {
+ cch = ichMaxLine - ifi.ich;
+ fTruncated = true;
+ }
+
+ ifi.ichFetch = 0;
+
+#ifdef CASHMERE
+ if (chpLocal.csm != csmNormal)
+ {
+ int ich;
+ CHAR *pchT = &rgchSmcap[0];
+
+ /* We can handle only a run of cchSmcapMax small capital
+ characters. If the run is larger then truncate. */
+ if (cch > cchSmcapMax)
+ {
+ cch = cchSmcapMax;
+ fTruncated = true;
+ }
+
+ /* Raise the case of the characters. */
+ for (ich = 0 ; ich < cch ; ich++)
+ {
+ *pchT++ = ChUpper(*pch++);
+ }
+ pch = &rgchSmcap[0];
+ }
+#endif /* CASHMERE */
+
+ /* Do "special" characters here */
+ if (chpLocal.fSpecial)
+ {
+ if (!FFormatSpecials(&ifi, flm, vsepAbs.nfcPgn))
+ {
+ if (ifi.chBreak == 0) /* No breaks in this line */
+ {
+ goto Unbroken;
+ }
+ else
+ {
+ vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
+ goto JustBreak;
+ }
+ }
+ }
+
+ continue;
+ }
+
+ /* End of new run treatment. We are back in the "for every character"
+ section. */
+ {
+ register int ch = pch[ifi.ichFetch++];
+
+NormChar:
+
+ if (ch == chSpace)
+ {
+ /* Speed kludge for spaces */
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp =
+ fFlmPrinting ? vfmiPrint.dxpSpace : vfmiScreen.dxpSpace);
+ ifi.xpPr += (dxpPr = vfmiPrint.dxpSpace);
+ vfli.rgch[ifi.ich++] = chSpace;
+#ifdef DFLI
+ {
+ char rgch[100];
+
+ wsprintf(rgch," chSpace , xp==%d/%d, xpPr==%d/%d",
+ ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif
+ goto BreakOppr;
+ }
+
+ /* If the printer width is not in the printer width table, then get
+ it. */
+ if (ch < chFmiMin || ch >= chFmiMax || (dxpPr =
+ vfmiPrint.mpchdxp[ch]) == dxpNil)
+ {
+ dxpPr = DxpFromCh(ch, TRUE);
+ }
+
+ if (fFlmPrinting)
+ {
+ /* If we are printing, then there is no need to bother with the
+ screen width. */
+ dxp = dxpPr;
+ }
+ else if (ch < chFmiMin || ch >= chFmiMax ||
+ (dxp = vfmiScreen.mpchdxp[ch]) == dxpNil)
+ dxp = DxpFromCh(ch, FALSE);
+
+#ifdef DBCS
+ if (IsDBCSLeadByte(ch))
+ {
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = ch;
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = pch[ifi.ichFetch++];
+ }
+ else
+ {
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = ch;
+ }
+#else
+ ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
+ ifi.xpPr += dxpPr;
+ vfli.rgch[ifi.ich++] = ch;
+#endif
+
+ /* special case "normal characters" above hyphen */
+
+ if (ch > chHyphen)
+ goto DefaultCh;
+
+ switch (ch)
+ {
+
+#ifdef CRLF
+ case chReturn:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+ continue;
+#endif /* CRLF */
+
+ case chNRHFile:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ ichpNRH = ichpFormat - 1;
+#ifdef DFLI
+ {
+ char rgch[100];
+
+ wsprintf(rgch," OptHyph: width==%d, xpPr==%d/%d\n\r",
+ DxpFromCh(chHyphen,true), ifi.xpPr,ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif
+ if (ifi.xpPr + DxpFromCh(chHyphen, true) > ifi.xpPrRight)
+ {
+ /* Won't fit, force a break */
+ goto DoBreak;
+ }
+
+#ifdef CASHMERE
+ else if (fVisiMode)
+ {
+ /* Treat just like a normal hyphen */
+ ch = chHyphen;
+ goto NormChar;
+ }
+#endif /* CASHMERE */
+
+ xpPrev = ifi.xp;
+ vfli.rgch[ifi.ich] = chTab;
+ goto Tab0;
+
+ case chSect:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ vfli.dypFont = vfli.dypLine = (dypAscentMac + (vfli.dypBase
+ = dypDescentMac));
+ vfli.cpMac = vcpFetch + ifi.ichFetch;
+ if (FFirstIch(ifi.ich))
+ {
+ /* Beginning of line; return a splat */
+ vfli.fSplat = true;
+
+ if (!fFlmPrinting)
+ {
+
+#ifdef CASHMERE
+ int chT = vfli.cpMac == vcpLimSectCache ?
+ chSectSplat : chSplat;
+#else /* not CASHMERE */
+ int chT = chSplat;
+#endif /* not CASHMERE */
+
+ int dxpCh = DxpFromCh(chT, false);
+
+ /* Set the width of the splat to be about 8.5" */
+ int cch = min((dxpLogInch * 17 / 2) / dxpCh,
+ ichMaxLine - 32);
+
+ bltbc(&vfli.rgch[ifi.ich], chT, cch);
+ bltc(&vfli.rgdxp[ifi.ich], dxpCh, cch);
+ vfli.ichMac = cch + ifi.ich;
+ vfli.xpReal = LOWORD(GetTextExtent(vhMDC,
+ (LPSTR)vfli.rgch, cch));
+ vfli.xpLeft = 0;
+ }
+ else
+ {
+ vfli.ichMac = 0;
+ }
+ goto EndFormat;
+ }
+
+ /* The section character is in the middle of a line, the
+ line will terminate in front of the character. */
+ /* vfSplatNext = TRUE; No longer used*/
+ vfli.cpMac += cchUsed - 1;
+ vfli.dcpDepend = 1;
+ if (!ifi.fPrevSpace)
+ {
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ vfli.ichMac = ifi.ich;
+ vfli.dypLine = ifi.dypLineSize;
+ goto JustBreak;
+
+ case chTab:
+ /* Undo damage */
+ ifi.ich--;
+ ifi.xp -= dxp;
+ ifi.xpPr -= dxpPr;
+
+ if (ifi.xpPr < ifi.xpPrRight)
+ {
+ register struct CHP *pchp;
+ unsigned xaPr;
+ unsigned xaTab;
+
+ if (!ifi.fPrevSpace)
+ {
+ /* Remember number of spaces to left and number of
+ real chars in line for justification */
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ ifi.xpReal = ifi.xp;
+ }
+
+ if (ifi.jc != jcTabLeft)
+ {
+ Justify(&ifi, xpTab, flm);
+ }
+ xpPrev = ifi.xp;
+
+ /* Now get info about this tab */
+ xaPr = MultDiv(ifi.xpPr, dxaPrPage, dxpPrPage);
+ while ((xaTab = ptbd->dxa) != 0)
+ {
+ if (xaTab > xaRight)
+ {
+ /* Don't let tabs extend past right margin. */
+ xaTab = xaRight;
+ }
+
+ if (xaTab >= xaPr)
+ {
+ /* Use tab stop information */
+
+#ifdef CASHMERE
+ ifi.tlc = ptbd->tlc;
+#endif /* CASHMERE */
+
+ ifi.jc = jcTabMin + (ptbd++)->jc;
+
+#ifdef ENABLE /* we do the mapping in HgtbdCreate */
+ if (ifi.jc != jcTabDecimal)
+ {
+ ifi.jc = jcTabLeft;
+ }
+#endif
+ goto TabFound;
+ }
+ ptbd++;
+ }
+
+ /* Out of set tabs; go to next nth column */
+ xaTab = (xaPr / (vzaTabDflt) + 1) * (vzaTabDflt);
+
+#ifdef CASHMERE
+ ifi.tlc = tlcWhite;
+#endif /* CASHMERE */
+
+ ifi.jc = jcTabLeft;
+
+TabFound:
+ xpTab = imax(MultDiv(xaTab, dxpFormat, dxaFormat),
+ ifi.xp);
+
+ /* Do left-justified tabs immediately */
+ if (ifi.jc == jcTabLeft)
+ {
+ ifi.xp = xpTab;
+ ifi.xpPr = MultDiv(xaTab, dxpPrPage, dxaPrPage);
+ }
+ ifi.xpLeft = ifi.xp;
+ ifi.ichLeft = ifi.ich;
+ ifi.cchSpace = 0;
+ ifi.chBreak = 0;
+Tab0:
+ ifi.fPrevSpace = false;
+ vfli.ichMac = ifi.ich;
+ vfli.xpReal = ifi.xp;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypBase = dypDescentMac;
+ vfli.dypFont = dypAscentMac + dypDescentMac;
+
+ if (ifi.ichFetch != 1 && (ichpFormat != ichpMacFormat
+ || FGrowFormatHeap()))
+ {
+ /* Probably in real trouble if FGrowFormatHeap fails
+ at this point */
+ pchp = &(**vhgchpFormat)[ichpFormat - 1];
+ if (ichpFormat > 0)
+ {
+ /* Finish off previous run */
+ pchp->ichRun = ifi.ichPrev;
+ pchp->cchRun = ifi.ich - ifi.ichPrev;
+ }
+
+ blt(&chpLocal, ++pchp, cwCHP);
+ ichpFormat++;
+ }
+ else
+ {
+ pchp = &(**vhgchpFormat)[ichpFormat - 1];
+ }
+ pchp->ichRun = ifi.ich;
+ pchp->cchRun = ichMaxLine;
+
+#ifdef CASHMERE
+ pchp->chLeader = mptlcch[ifi.tlc];
+#endif /* CASHMERE */
+
+ vfli.rgdxp[ifi.ichPrev = ifi.ich++] = ifi.xp - xpPrev;
+
+ if (ch != chTab)
+ {
+ /* This character is a non-required hyphen. */
+ Dfli(CommSz("ch is really OptHyph "));
+ goto BreakOppr;
+ }
+
+ continue;
+ }
+ else
+ {
+ ch = chNBSFile;
+ goto NormChar;
+ }
+
+ case chHyphen:
+ if (ifi.xpPr > ifi.xpPrRight)
+ {
+ goto DoBreak;
+ }
+
+BreakOppr:
+ Dfli(CommSz(" BKOPPR\n\r"));
+ /* this case never used in switch - always goto here */
+ /* case chSpace: */
+ if (ifi.ich >= ichMaxLine)
+ {
+ Dfli(CommSzNum(" Unbroken, ich>ichMaxLine\n\r"));
+ goto Unbroken;
+ }
+
+ case chEol:
+ case chNewLine:
+ ifi.chBreak = ch;
+ vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch;
+ vfli.xpReal = ifi.xp;
+ vfli.ichMac = ifi.ich;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ Dfli(CommSzNumNum(" vfli.xpReal, ichMac ",vfli.xpReal,vfli.ichMac));
+
+
+ if (ch == chHyphen || ch == chNRHFile)
+ {
+ Dfli(CommSz(" chHyph/OptHyph catch \n\r"));
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich;
+ vfli.xpReal = ifi.xpReal = ifi.xp;
+ }
+ else
+ {
+ if (!ifi.fPrevSpace)
+ {
+ Dfli(CommSz("!fPrevSpace \n\r"));
+ ifi.cBreak = ifi.cchSpace;
+ vfli.ichReal = ifi.ich - 1;
+ ifi.xpReal = (vfli.xpReal = ifi.xp) - dxp;
+ }
+ if (ch == chEol || ch == chNewLine)
+ {
+
+#ifdef CASHMERE
+ if (hfntb != 0 && vfli.cpMac ==
+ (**hfntb).rgfnd[0].cpFtn)
+ {
+ /* End of footnote */
+ if (!fFlmPrinting)
+ {
+ vfli.rgch[ifi.ich - 1] = chEMark;
+ vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
+ DxpFromCh(chEMark, false)) - dxp;
+ vfli.ichReal++; /* show this guy */
+ }
+ }
+ else
+#endif /* CASHMERE */
+ {
+
+#ifdef CASHMERE
+ int chT = fVisiMode ? ChVisible(ch) : chSpace;
+#else /* not CASHMERE */
+ int chT = chSpace;
+#endif /* not CASHMERE */
+
+ int dxpNew = DxpFromCh(chT, fFlmPrinting);
+
+ vfli.rgch[ifi.ich - 1] = chT;
+ vfli.rgdxp[ifi.ich - 1] = dxpNew;
+
+ vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
+ dxpNew) - dxp;
+
+
+ if (!ifi.fPrevSpace)
+ {
+ vfli.xpReal += dxpNew - dxp;
+#ifdef CASHMERE
+ vfli.ichReal =
+ fVisiMode ? ifi.ich : ifi.ich - 1;
+#else /* not CASHMERE */
+ vfli.ichReal = ifi.ich - 1;
+#endif /* not CASHMERE */
+ }
+ }
+
+
+ if (ch == chEol)
+ {
+JustEol:
+ if (fFlmPrinting)
+ {
+ vfli.ichMac = vfli.ichReal;
+ }
+ if (ifi.jc != jcTabLeft)
+ {
+ /* Handle last tab's text */
+ Justify(&ifi, xpTab, flm);
+ }
+ else if ((ifi.jc = ppap->jc) != jcBoth &&
+ ifi.jc != jcLeft)
+ {
+ /* Do line justification */
+ Justify(&ifi, ifi.xpRight, flm);
+ }
+ vfli.xpRight = ifi.xpRight;
+ goto EndFormat;
+ }
+ else
+ {
+ /* Handle a line break */
+ goto JustBreak;
+ }
+ }
+ ++ifi.cchSpace;
+ ifi.fPrevSpace = true;
+ }
+ break;
+
+DefaultCh:
+
+ default:
+
+#ifdef DFLI
+ {
+ char rgch[100];
+ wsprintf(rgch," DefaultCh: %c, xp==%d/%d, xpPr==%d/%d\n\r",
+ ch, ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
+ CommSz(rgch);
+ }
+#endif /* ifdef DFLI */
+
+ if (ifi.xpPr > ifi.xpPrRight)
+DoBreak:
+ {
+ Dfli(CommSz(" BREAK!\n\r"));
+ if (ifi.chBreak == 0)
+Unbroken:
+ {
+ /* Admit first character to the line, even if margin
+ is crossed. First character at ifi.ich - 1 may be
+ preceded by 0 width characters. */
+#ifdef DBCS
+ if (IsDBCSLeadByte(ch))
+ {
+ if (FFirstIch(ifi.ich-2) && ifi.ich<ichMaxLine)
+ goto PChar;
+ vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-2;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 2;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - (dxp * 2);
+ }
+ else
+ {
+ if (FFirstIch(ifi.ich-1) && ifi.ich<ichMaxLine)
+ goto PChar;
+ vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-1;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 1;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
+ }
+#else
+ if (FFirstIch(ifi.ich - 1) && ifi.ich < ichMaxLine)
+ {
+ goto PChar;
+ }
+ vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch - 1;
+ vfli.ichReal = vfli.ichMac = ifi.ich - 1;
+ vfli.dypLine = ifi.dypLineSize;
+ vfli.dypFont = dypAscentMac + (vfli.dypBase =
+ dypDescentMac);
+ vfli.dcpDepend = 1;
+ vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
+#endif
+ goto DoJustify;
+ }
+
+ vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
+JustBreak:
+ if (ifi.chBreak == chNRHFile)
+ {
+ /* Append a non-required hyphen to the end of the
+ line. (Replace zero length tab previously
+ inserted) */
+
+ Dfli(CommSz(" Breaking line at OptHyphen\n\r"));
+ ifi.xpReal += (vfli.rgdxp[vfli.ichReal - 1] =
+ DxpFromCh(chHyphen, fFlmPrinting));
+ vfli.xpRight = vfli.xpReal = ifi.xpReal;
+ vfli.rgch[vfli.ichReal - 1] = chHyphen;
+ vfli.ichMac = vfli.ichReal;
+ if (ichpNRH < ichpFormat - 1)
+ {
+ register struct CHP *pchp =
+ &(**vhgchpFormat)[ichpNRH];
+
+ pchp->cchRun++;
+ if (pchp->ichRun >= vfli.ichMac)
+ {
+ pchp->ichRun = vfli.ichMac - 1;
+ }
+ }
+ }
+
+ if (fFlmPrinting)
+ {
+ vfli.ichMac = vfli.ichReal;
+ }
+ if (ifi.jc != jcTabLeft)
+ {
+ Justify(&ifi, xpTab, flm);
+ }
+ else
+ {
+DoJustify:
+ if ((ifi.jc = ppap->jc) != jcLeft)
+ {
+ Dfli(CommSzNum(" DoJustify: xpRight ",ifi.xpRight));
+ Justify(&ifi, ifi.xpRight, flm);
+ }
+ }
+ vfli.xpRight = ifi.xpRight;
+EndFormat:
+ vfli.ichLastTab = ifi.ichLeft;
+
+#ifdef CASHMERE
+ if (vfli.cpMac == vcpLimParaCache)
+ {
+ vfli.dypAfter = vpapAbs.dyaAfter / DyaPerPixFormat;
+ vfli.dypLine += vfli.dypAfter;
+ vfli.dypBase += vfli.dypAfter;
+ }
+#endif /* CASHMERE */
+
+ Scribble(5, ' ');
+ return;
+ }
+ else
+ {
+PChar:
+ /* A printing character */
+ ifi.fPrevSpace = false;
+ }
+ break;
+
+ } /* Switch */
+ }
+ } /* for ( ; ; ) */
+
+ Scribble(5, ' ');
+ }
+
+
+/* J U S T I F Y */
+near Justify(pifi, xpTab, flm)
+struct IFI *pifi;
+unsigned xpTab;
+int flm;
+ {
+ int dxp;
+ int ichT;
+ int xpLeft;
+
+
+ xpLeft = pifi->xpLeft;
+ switch (pifi->jc)
+ {
+ CHAR *pch;
+ unsigned *pdxp;
+
+#ifdef CASHMERE
+ case jcTabLeft:
+ case jcLeft:
+ return;
+
+ case jcTabRight:
+ dxp = xpTab - pifi->xpReal;
+ break;
+
+ case jcTabCenter:
+ dxp = (xpTab - xpLeft) - ((pifi->xpReal - xpLeft + 1) >> 1);
+ break;
+#endif /* CASHMERE */
+
+ case jcTabDecimal:
+ dxp = xpTab - xpLeft;
+ for (ichT = pifi->ichLeft + 1; ichT < vfli.ichReal &&
+ vfli.rgch[ichT] != vchDecimal; ichT++)
+ {
+ dxp -= vfli.rgdxp[ichT];
+ }
+ break;
+
+ case jcCenter:
+ if ((dxp = xpTab - pifi->xpReal) <= 0)
+ {
+ return;
+ }
+ dxp = dxp >> 1;
+ break;
+
+ case jcRight:
+ dxp = xpTab - pifi->xpReal;
+ break;
+
+ case jcBoth:
+ if (pifi->cBreak == 0)
+ {
+ /* Ragged edge forced */
+ return;
+ }
+
+ if ((dxp = xpTab - pifi->xpReal) <= 0)
+ {
+ /* There is nothing to do. */
+ return;
+ }
+
+ pifi->xp += dxp;
+ vfli.xpReal += dxp;
+ vfli.dxpExtra = dxp / pifi->cBreak;
+
+ /* Rounding becomes a non-existant issue due to brilliant
+ re-thinking.
+ "What a piece of work is man
+ How noble in reason
+ In form and movement,
+ how abject and admirable..."
+
+ Bill "Shake" Spear [describing Sand Word] */
+ {
+ register CHAR *pch = &vfli.rgch[vfli.ichReal];
+ register int *pdxp = &vfli.rgdxp[vfli.ichReal];
+ int dxpT = dxp;
+ int cBreak = pifi->cBreak;
+ int cxpQuotient = (dxpT / cBreak) + 1;
+ int cWideSpaces = dxpT % cBreak;
+
+ vfli.fAdjSpace = fTrue;
+
+ for ( ; ; )
+ {
+ /* Widen blanks */
+ --pch;
+ --pdxp;
+ if (*pch == chSpace)
+ {
+ if (cWideSpaces-- == 0)
+ {
+ int *pdxpT = pdxp + 1;
+
+ while (*pdxpT == 0)
+ {
+ pdxpT++;
+ }
+ vfli.ichFirstWide = pdxpT - vfli.rgdxp;
+ cxpQuotient--;
+ }
+ *pdxp += cxpQuotient;
+ if ((dxpT -= cxpQuotient) <= 0)
+ {
+ if (pifi->cBreak > 1)
+ {
+ int *pdxpT = pdxp + 1;
+
+ while (*pdxpT == 0)
+ {
+ pdxpT++;
+ }
+ vfli.ichFirstWide = pdxpT - vfli.rgdxp;
+ }
+ return;
+ }
+ pifi->cBreak--;
+ }
+ }
+ }
+ } /* Switch */
+
+ if (dxp <= 0)
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ pifi->xp += dxp;
+
+ if (flm & flmPrinting)
+ {
+ pifi->xpPr += dxp;
+ }
+ else
+ {
+ /* This statememt might introduce rounding errors in pifi->xpPr, but
+ with luck, they will be small. */
+ pifi->xpPr += MultDiv(MultDiv(dxp, czaInch, dxpLogInch), dxpPrPage,
+ dxaPrPage);
+ }
+
+ if (pifi->ichLeft < 0)
+ {
+ /* Normal justification */
+ vfli.xpLeft += dxp;
+ }
+ else
+ {
+ /* Tab justification */
+ vfli.rgdxp[pifi->ichLeft] += dxp;
+ }
+ vfli.xpReal += dxp;
+ }
+
+
+/* F G R O W F O R M A T H E A P */
+int near FGrowFormatHeap()
+ {
+ /* Grow vhgchpFormat by 20% */
+ int cchpIncr = ichpMacFormat / 5 + 1;
+
+#ifdef WINHEAP
+ if (!LocalReAlloc((HANDLE)vhgchpFormat, (ichpMacFormat + cchpIncr) * cchCHP,
+ NONZEROLHND))
+#else /* not WINHEAP */
+ if (!FChngSizeH(vhgchpFormat, (ichpMacFormat + cchpIncr) * cwCHP, false))
+#endif /* not WINHEAP */
+
+ {
+ /* Sorry, charlie */
+ return false;
+ }
+ ichpMacFormat += cchpIncr;
+ return true;
+ }
+
+
+/* #define DBEMG */
+/* D X P F R O M C H */
+#ifdef DBCS
+/* DxpFromCh() assumes that ch passed is the first byte of a DBCS character
+ if it is a part of such character. */
+#endif
+int DxpFromCh(ch, fPrinter)
+int ch;
+int fPrinter;
+ {
+ int *pdxp; // changed to int (7.23.91) v-dougk
+ int dxpDummy; // changed to int (7.23.91) v-dougk
+
+ extern int dxpLogCh;
+ extern struct FCE *vpfceScreen;
+
+ /* If the width is not in the width table, then get it. */
+ if (ch < chFmiMin)
+ {
+ switch (ch)
+ {
+ case chTab:
+ case chEol:
+ case chReturn:
+ case chSect:
+ case chNewLine:
+ case chNRHFile:
+ /* the width for these characters aren't really important */
+ pdxp = (CHAR *)(fPrinter ? &vfmiPrint.dxpSpace : &vfmiScreen.dxpSpace);
+ break;
+ default:
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ break;
+ }
+ }
+ else if (ch >= chFmiMax)
+ {
+ /* outside the range we hold in our table - kludge it */
+ pdxp = &dxpDummy;
+ *pdxp = dxpNil;
+ }
+ else
+ {
+ /* inside our table */
+ pdxp = (fPrinter ? vfmiPrint.mpchdxp : vfmiScreen.mpchdxp) + ch;
+ }
+
+#ifdef DBCS
+ if (*pdxp == dxpNil && IsDBCSLeadByte(ch) )
+ {
+ int dxp;
+#else
+ if (*pdxp == dxpNil)
+ {
+ int dxp;
+#endif
+
+#ifdef DBCS
+ struct FMI *pfmi;
+ int rgchT[cchDBCS]; // changed to int (7.23.91) v-dougk
+ int dxpT;
+ int dxpDBCS;
+
+ pfmi = fPrinter ? (&vfmiPrint) : (&vfmiScreen);
+ Assert(pfmi->bDummy == dxpNil);
+ if (pfmi->dxpDBCS == dxpNil)
+ {
+ /* Get the width from GDI. */
+ rgchT[0] = rgchT[1] = ch;
+ dxpDBCS = (fPrinter ?
+ LOWORD(GetTextExtent(vhDCPrinter,
+ (LPSTR) rgchT, cchDBCS)) :
+ LOWORD(GetTextExtent(vhMDC,
+ (LPSTR) rgchT, cchDBCS)));
+ /* Store in fmi, if it fits. */
+ if (0 <= dxpDBCS && dxpDBCS < dxpNil)
+ pfmi->dxpDBCS = (BYTE) dxpDBCS;
+ return (dxpDBCS - pfmi->dxpOverhang);
+ }
+ else
+ return (pfmi->dxpDBCS - pfmi->dxpOverhang);
+ }
+ else {
+ int dxp;
+#endif /* DBCS */
+ /* get width from GDI */
+ dxp = fPrinter ? LOWORD(GetTextExtent(vhDCPrinter, (LPSTR)&ch, 1)) -
+ vfmiPrint.dxpOverhang : LOWORD(GetTextExtent(vhMDC, (LPSTR)&ch, 1)) -
+ vfmiScreen.dxpOverhang;
+#ifdef DBEMG
+ CommSzNum("Get this.... ", dxp);
+#endif
+ //(7.24.91) v-dougk if (dxp >= 0 && dxp < dxpNil)
+ {
+ /* only store dxp's that fit in a byte */
+ *pdxp = dxp;
+ }
+
+#ifdef DBEMG
+ {
+ char szT[10];
+ CommSzSz("fPrinter: ", (fPrinter ? "Printer" : "Screen"));
+ if (ch == 0x0D) {
+ szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
+ }
+ else if (ch == 0x0A) {
+ szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
+ }
+ else if (32 <= ch && ch <= 126) {
+ szT[0] = ch; szT[1] ='\0';
+ }
+ else if (FKanji1(ch)) {
+ szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
+ szT[4] = 'I'; szT[5] = '\0';
+ }
+ else {
+ szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
+ }
+ CommSzSz("Character: ", szT);
+ CommSzNum("Dxp: ", (int) dxp);
+ CommSzNum("OverHang: ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
+ }
+#endif
+ return(dxp);
+ }
+
+#ifdef DBEMG
+ {
+ char szT[10];
+ CommSzSz("fPrinter: ", (fPrinter ? "Printer" : "Screen"));
+ if (ch == 0x0D) {
+ szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
+ }
+ else if (ch == 0x0A) {
+ szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
+ }
+ else if (32 <= ch && ch <= 126) {
+ szT[0] = ch; szT[1] ='\0';
+ }
+ else if (FKanji1(ch)) {
+ szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
+ szT[4] = 'I'; szT[5] = '\0';
+ }
+ else {
+ szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
+ }
+ CommSzSz("Character: ", szT);
+ CommSzNum("Dxp: ", (int) *pdxp);
+ CommSzNum("OverHang: ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
+ }
+#endif
+ return(*pdxp);
+ }
+
+
+/* F F I R S T I C H */
+int near FFirstIch(ich)
+int ich;
+ {
+ /* Returns true iff ich is 0 or preceded only by 0 width characters */
+ register int ichT;
+ register int *pdxp = &vfli.rgdxp[0];
+
+ for (ichT = 0; ichT < ich; ichT++)
+ {
+ if (*pdxp++)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ValidateMemoryDC()
+ {
+ /* Attempt to assure that vhMDC and vhDCPrinter are valid. If we have not
+ already run out of memory, then vhDCPrinter is guaranteed, but vhMDC may
+ fail due to out of memory -- it is the callers responsibility to check for
+ vhMDC == NULL. */
+
+ extern int vfOutOfMemory;
+ extern HDC vhMDC;
+ extern BOOL vfMonochrome;
+ extern long rgbText;
+ extern struct WWD *pwwdCur;
+
+ /* If we are out of memory, then we shouldn't try to gobble it up by getting
+ DC's. */
+ if (!vfOutOfMemory)
+ {
+ if (vhMDC == NULL)
+ {
+ /* Create a memory DC compatible with the screen if necessary. */
+ vhMDC = CreateCompatibleDC(pwwdCur->hDC);
+
+ /* Callers are responsible for checking for vhMDC == NULL case */
+ if (vhMDC != NULL)
+ {
+ /* Put the memory DC in transparent mode. */
+ SetBkMode(vhMDC, TRANSPARENT);
+
+ /* If the display is a monochrome device, then set the text
+ color for the memory DC. Monochrome bitmaps will not be
+ converted to the foreground and background colors in this case,
+ we must do the conversion. */
+ if (vfMonochrome = (GetDeviceCaps(pwwdCur->hDC, NUMCOLORS) ==
+ 2))
+ {
+ SetTextColor(vhMDC, rgbText);
+ }
+ }
+ }
+
+ /* If the printer DC is NULL then we need to reestablish it. */
+ if (vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ /* GetPrinterDC has already called SetMapperFlags() on vhDCPrinter. */
+ }
+ }
+ }
+
+
+
diff --git a/private/mvdm/wow16/write/format.asm b/private/mvdm/wow16/write/format.asm
new file mode 100644
index 000000000..631adb452
--- /dev/null
+++ b/private/mvdm/wow16/write/format.asm
@@ -0,0 +1,2995 @@
+;* ****************************************************************************
+;*
+;* COPYRIGHT (C) 1985-1992 MICROSOFT
+;*
+;* ****************************************************************************
+;
+ TITLE Format.asm line formatting routines for windows Write
+; Module: format.asm
+; contains native code versions of FormatLine, Justify, FGrowFormatHeap,
+; FFirstIch, DxpFromCh, and ValidateMemoryDC
+;
+;*
+;* REVISION HISTORY
+;*
+;* Date Who Rel Ver Remarks
+;* 5/23/85 bz initial translation from c
+;* 6/21/85 bl Set ?WIN == 0 for windows header
+;* 7/09/85 pnt Call WinFailure() if vhMDC == NULL
+;* 7/16/85 pnt Truncate tabs at right margin
+;* 7/21/85 pnt Treat running heads like normal paragraphs
+;* 7/30/85 bl Fixed bug in FFirstIch -- change scasb to scasw
+;* 8/05/85 pnt Added ValidateMemoryDC()
+;* 8/05/85 pnt DxpFromCh returns dxpSpace if ch < space
+;* 8/07/85 pnt cchCHPUsed changed from 9 to 7
+;* 8/09/85 pnt Ensure there tabs don't back up on the screen
+;* 8/14/85 pnt Map center and right tabs to left tabs
+;* 8/27/85 pnt Single spacing changed to font leading only
+;* 8/29/85 pnt Lines with no breaks can be right, center flush
+;* 10/01/85 pnt Forced section mark to be in stardard font
+;* 10/07/85 pnt DxpFromCh returns dxpSpace iff width unimportant
+;* 10/10/85 pnt Validity of vfli cache depends on flm
+;* 10/10/85 pnt fPrevSpace not set for null runs
+;* 10/30/89 pault set code to use SYSENDMARK code in FORM1.C
+;* (7.23.91) v-dougk changed dxp char arrays to int arrays
+SYSENDMARK EQU 1
+;*
+;* ************************************************************************* */
+
+;* ************************************************************************* */
+; Naming conventions used here
+;
+; rxx_name register variable - reg is xx. This may be a temporary naming
+; of a register (e.g. rax_ichT)
+; c_name defined constant in c program (e.g. c_false)
+;
+;* ************************************************************************* */
+ subttl Conditional variables and cmacros
+ page
+
+; *************** Conditional variables *************************
+; ***** These variables should be defined using the -D command line
+; ***** option in masm. They are only checked for being defined, not
+; ***** for a particular value
+;
+; DEBUG define with -DDEBUG ; ** controls ASSERT code **
+; SCRIBBLE define with -DSCRIBBLE ; ** controls SCRIBBLE code **
+; CASHMERE ; ** code taken out for Write, to be used for Cashmere **
+;
+; *************** End conditional variables *************************
+
+ memM = 1 ; medium model for cmacros
+ ?WIN = 1 ; windows header used here
+ .xlist
+ include cmacros.inc
+ page
+ .list
+ ;.sall
+ createSeg FORM1_TEXT,FORM1_TEXT,BYTE,PUBLIC,CODE
+
+ ASSUME CS: FORM1_TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
+
+ subttl Public definitions
+ page
+;
+; Public definitions for this module
+;
+PUBLIC DxpFromCh
+PUBLIC FormatLine
+PUBLIC Justify
+PUBLIC FGrowFormatHeap
+PUBLIC FFirstIch
+PUBLIC ValidateMemoryDC
+
+;
+; External procedures referenced from this module
+;
+
+EXTRN IMAX:FAR
+EXTRN CCHDIFFER:FAR
+EXTRN CACHESECT:FAR
+EXTRN FCHNGSIZEH:FAR
+EXTRN CACHEPARA:FAR
+EXTRN FORMATGRAPHICS:FAR
+EXTRN FFORMATSPECIALS:FAR
+EXTRN MULTDIV:FAR
+EXTRN FETCHCP:FAR
+EXTRN SETTEXTJUSTIFICATION:FAR
+EXTRN GETTEXTEXTENT:FAR
+EXTRN LOADFONT:FAR
+EXTRN WINFAILURE:FAR
+EXTRN GETDEVICECAPS:FAR
+EXTRN SETBKMODE:FAR
+EXTRN SETTEXTCOLOR:FAR
+EXTRN CREATECOMPATIBLEDC:FAR
+EXTRN GETPRINTERDC:FAR
+
+ ; **** Debugging code **********
+IFDEF DEBUG
+IFDEF SCRIBBLE
+EXTRN FNSCRIBBLE:FAR
+ENDIF
+ENDIF
+
+
+ subttl External definitions
+ page
+;
+; External definitions referenced from this module
+;
+ sBegin DATA
+
+EXTRN PLOCALHEAP:WORD
+;EXTRN DOCHELP:WORD
+EXTRN VFLI:BYTE
+EXTRN VHGCHPFORMAT:WORD
+EXTRN ICHPMACFORMAT:WORD
+EXTRN VCHPABS:BYTE
+EXTRN VPAPABS:BYTE
+EXTRN VSEPABS:BYTE
+EXTRN VSEPPAGE:BYTE
+EXTRN VCHPNORMAL:BYTE
+EXTRN VCPFIRSTPARACACHE:DWORD
+EXTRN VCPFETCH:DWORD
+EXTRN YPSUBSUPER:WORD
+EXTRN VPCHFETCH:WORD
+EXTRN VCCHFETCH:WORD
+EXTRN YPSUBSUPERPR:WORD
+EXTRN VHMDC:WORD
+EXTRN VHDCPRINTER:WORD
+EXTRN DXPLOGINCH:WORD
+EXTRN DYPLOGINCH:WORD
+EXTRN DXAPRPAGE:WORD
+EXTRN DYAPRPAGE:WORD
+EXTRN DXPPRPAGE:WORD
+EXTRN DYPPRPAGE:WORD
+EXTRN DYPMAX:WORD
+EXTRN VFMISCREEN:BYTE
+EXTRN VFMIPRINT:BYTE
+EXTRN VFOUTOFMEMORY:WORD
+EXTRN VFMONOCHROME:WORD
+EXTRN RGBTEXT:DWORD
+EXTRN PWWDCUR:WORD
+EXTRN VCHDECIMAL:BYTE
+EXTRN VZATABDFLT:BYTE
+ sEnd DATA
+
+ ;sBegin BSS
+ sBegin DATA
+$S784_ichpFormat DB 02H DUP (?)
+ EVEN
+ sEnd DAT
+ ;sEnd BSS
+
+ subttl Macros
+ page
+; ********************************************************************
+; macros done here for speed, rather than doing far procedure call
+
+;-----------------------------------------------------------------------------
+; bltc (pTo, wFill, cw) - fills cw words of memory starting at pTo with wFill.
+;-----------------------------------------------------------------------------
+; macro bltc destroys ax,es,cx
+
+bltc MACRO pTo,wFill,cw
+ push di
+ mov ax,ds ; we are filling in the data segment
+ mov es,ax
+ mov di,pTo ; get the destination, constant, and count
+ mov ax,wFill
+ mov cx,cw
+ cld ; the operation is forward
+ rep stosw ; fill memory
+ pop di
+ ENDM
+
+;-----------------------------------------------------------------------------
+; bltbc (pTo, bFill, cb) - fills cb bytes of memory starting at pTo with
+; bFill.
+;-----------------------------------------------------------------------------
+
+; macro bltbc destroys ax,es,cx
+
+bltbc MACRO pTo,bFill,cb
+ push di
+ mov ax,ds ; we are filling in the data segment
+ mov es,ax
+ mov di,pTo ; get the destination, constant, and count
+ mov al,bFill
+ mov cx,cb
+ cld ; the operation is forward
+ rep stosb ; fill memory
+ pop di
+ ENDM
+
+;------------------------------------------------------------------------------
+; blt (pFrom, pTo, cw) - a block transfer of wFills from pFrom to pTo;
+; The size of the block is cw wFills. This blt() handles the case of
+; overlapping source and destination. blt() returns a pointer to the
+; end of the destination buffer (pTo + cw). NOTE - use this blt() to
+; to transfer within the current DS only--use the bltx for FAR blts.
+;-----------------------------------------------------------------------------
+
+; macro blt destroys ax,bx,cx,es
+
+blt MACRO pFrom,pTo,cw
+ local blt1
+ push si
+ push di
+ mov si,pFrom ; get pointers and length of blt
+ mov di,pTo
+ mov cx,cw
+ mov ax,ds ; set up segment registers
+ mov es,ax
+ mov ax,di ; calculate return value
+ mov bx,cx
+ shl bx,1
+ add ax,bx
+ cmp si,di ; reverse direction of the blt if
+ jae blt1 ; necessary
+
+ dec bx
+ dec bx
+ add si,bx
+ add di,bx
+ std
+blt1:
+ rep movsw
+ cld
+ pop di
+ pop si
+ ENDM
+
+
+ subttl C structures Used in this module
+ page
+;
+; *** The following structure definitions were used when this module
+; *** was being developed:
+;
+;struct IFI
+ ;{
+ ;int xp;
+ ;int xpLeft;
+ ;int xpRight;
+ ;int xpReal;
+ ;int xpPr;
+ ;int xpPrRight;
+ ;int ich;
+ ;int ichLeft;
+ ;int ichPrev;
+ ;int ichFetch;
+ ;int dypLineSize;
+ ;int cchSpace;
+ ;int cBreak;
+ ;int chBreak;
+ ;int jc;
+
+;#ifdef CASHMERE
+ ;int tlc;
+;#endif /* CASHMERE */
+
+ ;int fPrevSpace;
+ ;};
+; ***************************************************************************
+; ***** Equates for IFI structure ifi offsets ****************
+
+ IFI_STRUC STRUC
+ xp DW ?
+ xpLeft_Ifi DW ?
+ xpRight_Ifi DW ?
+ xpReal_Ifi DW ?
+ xpPr DW ?
+ xpPrRight DW ?
+ ich_Ifi DW ?
+ ichLeft DW ?
+ ichPrev DW ?
+ ichFetch DW ?
+ dypLineSize DW ?
+ cchSpace DW ?
+ cBreak_Ifi DW ?
+ chBreak DW ?
+ _jc DW ? ; (2.27.91) D. Kent
+ fPrevSpace DW ?
+ IFI_STRUC ENDS
+
+ oIfi_xp EQU 0
+ oIfi_xpLeft EQU 2
+ oIfi_xpRight EQU 4
+ oIfi_xpReal EQU 6
+ oIfi_xpPr EQU 8
+ oIfi_xpPrRight EQU 10
+ oIfi_ich EQU 12
+ oIfi_ichLeft EQU 14
+ oIfi_ichPrev EQU 16
+ oIfi_ichFetch EQU 18
+ oIfi_dypLineSize EQU 20
+ oIfi_cchSpace EQU 22
+ oIfi_cBreak EQU 24
+ oIfi_chBreak EQU 26
+ oIfi_jc EQU 28
+ oIfi_fPrevSpace EQU 30
+
+ page
+; ***************************************************************************
+
+;/* Formatted line structure.
+;Reorganized KJS, CS Sept 3 */
+;/* booleans in bytes to simplify machine code */
+;struct FLI
+ ;{
+ ;typeCP cpMin;
+ ;int ichCpMin;
+ ;typeCP cpMac;
+ ;int ichCpMac;
+ ;int ichMac;
+ ;int dcpDepend;
+ ;unsigned fSplat : 8;
+;/* First character in region where spaces have additional pixel */
+ ;unsigned ichFirstWide : 8;
+;/* ichMac, with trailing blanks excluded */
+ ;int ichReal;
+ ;int doc;
+
+ ;int xpLeft;
+ ;int xpRight;
+;/* xpRight, with trailing blanks excluded */
+ ;int xpReal;
+;/* the right margin where insert will have to break the line */
+ ;int xpMarg;
+;
+ ;unsigned fGraphics : 8;
+ ;unsigned fAdjSpace : 8; /* Whether you adjust the spaces */
+
+ ;unsigned dxpExtra;
+;/* the interesting positions in order from top to bottom are:
+ ;top: yp+dypLine
+ ;top of ascenders: yp+dypAfter+dypFont
+ ;base line: yp+dypBase
+ ;bottom of descenders: yp+dypAfter
+ ;bottom of line: yp
+;distances between the points can be determined by algebraic subtraction.
+;e.g. space before = yp+dypLine - (yp+dypAfter+dypFont)
+;*/
+ ;int dypLine;
+ ;int dypAfter;
+ ;int dypFont;
+ ;int dypBase;
+
+ ;int ichLastTab;
+ ;int rgdxp[ichMaxLine];
+ ;CHAR rgch[ichMaxLine];
+ ;};
+; ***************************************************************************
+ichMaxLine EQU 255
+dxpNil EQU 0FFFFH
+
+ FLI STRUC
+ cpMin_OFF DW ?
+ cpMin_SEG DW ?
+ ichCpMin DW ?
+ cpMac_OFF DW ?
+ cpMac_SEG DW ?
+ ichCpMac DW ?
+ ichMac DW ?
+ dcpDepend DW ?
+ fSplat DB ?
+ ichFirstWide DB ?
+ ichReal DW ?
+ doc_Fli DW ?
+ xpLeft_Fli DW ?
+ xpRight DW ?
+ xpReal_Fli DW ?
+ xpMarg DW ?
+ fGraphics_Fli DB ?
+ fAdjSpace DB ?
+ dxpExtra DW ?
+ dypLine DW ?
+ dypAfter DW ?
+ dypFont DW ?
+ dypBase DW ?
+ fSplatNext DW ?
+ ichLastTab DW ?
+ flm_Fli DW ?
+ rgdxp DW ichMaxLine DUP (?)
+ rgch DB ichMaxLine DUP (?)
+ FLI ENDS
+
+ page
+
+; **************************************************************************
+;struct TBD /* Tab Descriptor */
+ ;{
+ ;unsigned dxa; /* distance from left margin of tab stop */
+ ;unsigned char jc : 3; /* justification code */
+ ;unsigned char tlc : 3; /* leader dot code */
+ ;unsigned char opcode : 2; /* operation code for Format Tabs */
+ ;CHAR chAlign; /* ASCII code of char to align on
+ ;if jcTab=3, or 0 to align on '.' */
+ ;};
+; ***************************************************************************
+; ***** Equates for TBD structure offsets ****************
+ TBD STRUC
+ dxa DW ?
+ jc_Tbd DB ? ; 3 bits
+ chAlign DB ? ;char
+ TBD ENDS
+
+ ;/* bit field equates in TBD structure */
+ tlc EQU jc_Tbd ; 3 bits
+ opcode EQU jc_Tbd ; 2 bits
+
+ page
+; **************************************************************************
+;struct PAP /* Paragraph properties */
+ ;{
+ ;unsigned fStyled : 1; /* BYTE 0 */
+ ;unsigned stc : 7;
+ ;unsigned jc : 2; /* BYTE 1 */
+ ;unsigned fKeep : 1;
+ ;unsigned fKeepFollow : 1;
+ ;unsigned : 4;
+ ;unsigned stcNormChp : 7; /* BYTE 2 */
+ ;unsigned : 9; /* BYTE 3 */
+ ;unsigned dxaRight; /* BYTE 4-5 */
+ ;unsigned dxaLeft; /* BYTE 6-7 */
+ ;unsigned dxaLeft1; /* BYTE 8-9 */
+ ;unsigned dyaLine; /* 10-11 */
+ ;unsigned dyaBefore; /* 12-13 */
+ ;unsigned dyaAfter; /* 14-15 */
+ ;unsigned rhc : 4; /* Running hd code */
+ ;unsigned fGraphics : 1; /* Graphics bit */
+ ;unsigned wUnused1 : 11;
+ ;int wUnused2;
+ ;int wUnused3;
+ ;struct TBD rgtbd[itbdMaxWord];
+ ;};
+
+; ***************************************************************************
+; ***** Equates for PAP structure offsets ****************
+
+ PAP STRUC
+ fStyled DB ? ;1 bit /* BYTE 0 */
+ jc_Pap DB ? ;2 bits /* BYTE 1 */
+ rmChp DB ? ;7 bits /* BYTE 2 */
+ unused9 DB ? ;9 bits /* BYTE 3 */
+ dxaRight DW ? ;/* BYTE 4-5 */
+ dxaLeft DW ? ;/* BYTE 6-7 */
+ dxaLeft1 DW ? ;/* BYTE 8-9 */
+ dyaLine DW ? ;/* 10-11 */
+ dyaBefore DW ? ;/* 12-13 */
+ dyaAfter DW ? ;/* 14-15 */
+ ;/* BYTE 16-17 */
+ rhc DW ? ;4 bits /* Running hd code */
+ wUnused2 DW ? ;/* BYTE 18-19 */
+ wUnused3 DW ? ;/* BYTE 20-21 */
+ rgtbd DW ? ;/* BYTE 23-23 */
+ PAP ENDS
+ ;/* bit field equates in PAP structure */
+ stc_Pap EQU fStyled ;7 bits
+ fKeep EQU jc_Pap ;1 bit
+ fKeepFollow EQU jc_Pap ;1 bit
+ unused4 EQU jc_Pap ;4 bits
+ fGraphics_Pap EQU rhc ;1 bits /* Graphics bit */
+ wUnused1 EQU rhc ;11 bits
+ page
+
+; **************************************************************************
+;struct SEP
+; { /* Section properties */
+; unsigned fStyled : 1; /* BYTE 0 */
+; unsigned stc : 7;
+; unsigned bkc : 3; /* Break code */ /* BYTE 1 */
+; unsigned nfcPgn : 3; /* Pgn format code */
+; unsigned :2;
+; unsigned yaMac; /* Page height */ /* BYTE 2-3 */
+; unsigned xaMac; /* Page width */ /* BYTE 4-5 */
+; unsigned pgnStart; /* Starting pgn */ /* BYTE 6-7 */
+; unsigned yaTop; /* Start of text */ /* BYTE 8-9 */
+; unsigned dyaText; /* Height of text */ /* 10-11 */
+; unsigned xaLeft; /* Left text margin */ /* 12-13 */
+; unsigned dxaText; /* Width of text */ /* 14-15 */
+; unsigned rhc : 4; /* *** RESERVED *** */ /* 16 */
+; /* (Must be same as PAP) */
+; unsigned : 2;
+; unsigned fAutoPgn : 1; /* Print pgns without hdr */
+; unsigned fEndFtns : 1; /* Footnotes at end of doc */
+; unsigned cColumns : 8; /* # of columns */ /* BYTE 17 */
+; unsigned yaRH1; /* Pos of top hdr */ /* 18-19 */
+; unsigned yaRH2; /* Pos of bottom hdr */ /* 20-21 */
+; unsigned dxaColumns; /* Intercolumn gap */ /* 22-23 */
+; unsigned dxaGutter; /* Gutter width */ /* 24-25 */
+; unsigned yaPgn; /* Y pos of page nos */ /* 26-27 */
+; unsigned xaPgn; /* X pos of page nos */ /* 28-29 */
+; CHAR rgbJunk[cchPAP - 30]; /* Pad to cchPAP */
+; };
+
+; ***************************************************************************
+; ***** Equates for SEP structure offsets ****************
+ SEP STRUC
+ fStyled_Sep DB ? ;1 bit /* BYTE 0 */
+ bkc DB ? ;3 bits /* BYTE 1 */
+ yaMac DW ? ; /* Page height */ /* BYTE 2-3 */
+ xaMac DW ? ;/* Page width */ /* BYTE 4-5 */
+ pgnStart DW ? ; /* Starting pgn */ /* BYTE 6-7 */
+ yaTop DW ? ; /* Start of text */ /* BYTE 8-9 */
+ dyaText DW ? ; /* Height of text */ /* 10-11 */
+ xaLeft_Sep DW ? ; /* Left text margin */ /* 12-13 */
+ dxaText DW ? ; /* Width of text */ /* 14-15 */
+ rhc_Sep DB ? ;4 bits /* 16 */
+ ; /* (Must be same as PAP) */
+ cColumns DB ? ; /* # of columns */ /* BYTE 17 */
+ yaRH1 DW ? ; /* Pos of top hdr */ /* 18-19 */
+ yaRH2 DW ? ; /* Pos of bottom hdr */ /* 20-21 */
+ dxaColumns DW ? ;/* Intercolumn gap */ /* 22-23 */
+ dxaGutter DW ? ; /* Gutter width */ /* 24-25 */
+ yaPgn DW ? ; /* Y pos of page nos */ /* 26-27 */
+ xaPgn DW ? ; /* X pos of page nos */ /* 28-29 */
+ rgbJunk DW ? ; /* Pad to cchPAP */
+ SEP ENDS
+
+ ;/* bit field equates in SEP structure */
+
+ stc_Sep EQU fStyled_Sep ;7 bits
+ nfcPgn EQU bkc ; 3 bits /* Pgn format code */
+ junk1_Sep EQU bkc ; 2 bits
+ junk2_Sep EQU rhc_Sep ;2 bits
+ fAutoPgn EQU rhc_Sep ;1 bit /* Print pgns without hdr */
+ fEndFtns EQU rhc_Sep ;1 bit /* Footnotes at end of doc */
+
+
+ page
+
+; **************************************************************************
+;typedef struct FMI /* font metric information */
+ ;{
+ ;int *mpchdxp; /* pointer to width table */
+ ;/* NOTE - we actually point chDxpMin entries
+ ;before the start of the table, so
+ ;that the valid range begins at the
+ ;start of the actual table */
+ ;int dxpSpace; /* width of a space */
+ ;int dxpOverhang; /* overhang for italic/bold chars */
+ ;int dypAscent; /* ascent */
+ ;int dypDescent; /* descent */
+ ;int dypBaseline; /* difference from top of cell to baseline */
+ ;int dypLeading; /* accent space plus recommended leading */
+ ;};
+
+; ***************************************************************************
+; ***** Equates for FMI structure offsets ****************
+ FMI STRUC
+ mpchdxp DW ?
+ dxpSpace DW ?
+ dxpOverhang DW ?
+ dypAscent_Fmi DW ?
+ dypDescent_Fmi DW ?
+ dypBaseline DW ?
+ dypLeading DW ?
+ FMI ENDS
+ page
+
+; **************************************************************************
+;struct CHP /* Character properties */
+ ;{
+ ;unsigned fStyled : 1; /* BYTE 0 */
+ ;unsigned stc : 7; /* style */
+ ;unsigned fBold : 1; /* BYTE 1 */
+ ;unsigned fItalic : 1;
+ ;unsigned ftc : 6; /* Font code */
+ ;unsigned hps : 8; /* Size in half pts */ /* BYTE 2 */
+ ;unsigned fUline : 1; /* BYTE 3 */
+ ;unsigned fStrike : 1;
+ ;unsigned fDline: 1;
+ ;unsigned fOverset : 1;
+ ;unsigned csm : 2; /* Case modifier */
+ ;unsigned fSpecial : 1;
+ ;unsigned : 1;
+ ;unsigned ftcXtra : 3; /* BYTE 4 */
+ ;unsigned fOutline : 1;
+ ;unsigned fShadow : 1;
+ ;unsigned : 3;
+ ;unsigned hpsPos : 8; /* BYTE 5 */
+ ;unsigned fFixedPitch : 8; /* used internally only */
+ ;unsigned chLeader : 8;
+ ;unsigned ichRun : 8;
+ ;unsigned cchRun : 8;
+ ;};
+
+; ***************************************************************************
+; ***** Equates for CHP structure offsets ****************
+ CHP STRUC
+ fStyled_Chp DB ? ;1 bit /* BYTE 0 */
+ fBold DB ? ;1 bit /* BYTE 1 */
+ hps DB ? ;8 bits /* BYTE 2 */
+ fUline DB ? ;1 bit /* BYTE 3 */
+ ftcXtra DB ? ;3 bits /* BYTE 4 */
+ hpsPos DB ? ;8 bits /* BYTE 5 */
+ fFixedPitch DB ? ;8 bits /* BYTE 6 */
+ chLeader DB ? ;8 bits /* BYTE 7 */
+ ichRun DB ? ;8 bits /* BYTE 8 */
+ cchRun DB ? ;8 bits /* BYTE 9 */
+ CHP ENDS
+
+ ;/* bit field equates in CHP structure */
+ stc_Chp EQU fStyled_Chp ;7 bits /* style */
+ fItalic EQU fBold ;1 bit
+ ftc EQU fBold ;6 bits
+ fStrike EQU fUline ;1 bit
+ fDline EQU fUline ;1 bit
+ fOverset EQU fUline ;1 bit
+ csm EQU fUline ;2 bits /* Case modifier */
+ fSpecial EQU fUline ;1 bit
+ chp_unused1 EQU fUline ;1 bit
+ fOutline EQU ftcXtra ;1 bit
+ fShadow EQU ftcXtra ;1 bit
+ chp_unused2 EQU ftcXtra ;3 bits
+
+; **************************************************************************
+ subttl Bit masks
+ page
+
+ mask_0001 EQU 1
+ mask_0010 EQU 2
+ mask_0011 EQU 3
+ mask_0100 EQU 4
+ mask_0101 EQU 5
+ mask_0110 EQU 6
+ mask_0111 EQU 7
+ mask_1000 EQU 8
+ mask_1001 EQU 9
+ mask_1010 EQU 10
+ mask_1011 EQU 11
+ mask_1100 EQU 12
+ mask_1101 EQU 13
+ mask_1110 EQU 14
+ mask_1111 EQU 15
+ mask_0001_0000 EQU 16
+ mask_1111_1111 EQU 65535
+ mask_0100_0000 EQU 64
+
+ subttl Defined C Constants
+
+ c_True EQU 1
+ c_False EQU 0
+ c_hpsDefault EQU 20
+ c_cwFLIBase EQU 22
+ c_cwIFI EQU 16
+ c_cwCHP EQU 5
+ c_docNil EQU -1
+ c_cpNil EQU -1
+ c_czaInch EQU 1440
+ c_czaLine EQU 240
+ c_xaRightMax EQU 31680
+ c_hpsNegMin EQU 128
+ ;/* Justification codes: must agree with menu.mod */
+ c_jcLeft EQU 0
+ c_jcCenter EQU 1
+ c_jcRight EQU 2
+ c_jcBoth EQU 3
+
+ c_jcTabMin EQU 4
+ c_jcTabLeft EQU 4
+ c_jcTabCenter EQU 5
+ c_jcTabRight EQU 6
+ c_jcTabDecimal EQU 7
+
+ ;/* Tab leader codes: must agree with menu.mod */
+ c_tlcWhite EQU 0
+ c_tlcDot EQU 1
+ c_tlcHyphen EQU 2
+ c_tlcUline EQU 3
+
+ c_chEmark EQU 164
+
+ c_chNil EQU -1
+ c_chDelPrev EQU 8
+ c_chTab EQU 9
+ c_chEol EQU 10
+ c_chNewLine EQU 11
+ c_chSect EQU 12
+ c_chReturn EQU 13
+ c_chNRHFile EQU 31
+ c_chSpace EQU 32
+ c_chSplat EQU 46
+ c_chHyphen EQU 45
+
+
+ subttl FormatLine()
+ page
+; **************************************************************************
+ sBegin FORM1_TEXT
+;***
+;
+; FormatLine(doc, cp, ichCp, cpMac, flm)
+; int doc;
+; typeCP cp;
+; int ichCp;
+; typeCP cpMac;
+; int flm;
+;
+; This procedure fills up vfli with a line of text. It is very large
+; and called often - each time a character is typed, at least.
+;
+;***
+ cProc FormatLine,<PUBLIC,FAR>,<di,si>
+ parmW doc
+ parmD cp
+ parmW ichCp
+ parmD cpMac
+ parmW flm
+; Line 79
+
+ localW dyaFormat
+ localW fFlmPrinting
+ localDP psep
+ localW xaRight
+ localW dypAscentMac
+ localW ichpNRH
+ localW ypSubSuperFormat
+ localW dxpFormat
+ localW dypFormat
+ localDP ppap
+ localW dypAscent
+
+ localV ifi,%(size IFI_STRUC)
+
+ localW xpTab
+ localW fTruncated
+ localW xaLeft
+ localW dypDescentMac
+ localDP ptbd
+ localW dypDescent
+ localW dxaFormat
+ localW dxp
+ localW cch
+ localDP pch
+ localW xpPrev
+ localW iichNew
+ localW dxpPr
+ localW cchUsed
+ localW dich
+ localW fSizeChanged
+ localW chT
+ localW cch2
+ localW dxpCh
+ localW xaTab
+ localW xaPr
+ localW chT2
+ localW dxpNew
+
+ localV chpLocal,%(size CHP)
+
+ cBegin FormatLine
+
+; Line 107
+ mov ax,flm
+ and ax,1
+ mov fFlmPrinting,ax
+; Line 113
+ mov fTruncated,0
+
+ ;** Check for fli current */
+; Line 122
+ mov ax,WORD PTR VFLI.doc_Fli
+ cmp doc,ax
+ jne $I845
+ mov ax,WORD PTR VFLI.cpMin_OFF
+ mov dx,WORD PTR VFLI.cpMin_SEG
+ cmp SEG_cp,dx
+ jne $I845
+ cmp OFF_cp,ax
+ jne $I845
+ mov ax,WORD PTR VFLI.ichCpMin
+ cmp ichCp,ax
+ jne $I845
+ mov ax,WORD PTR VFLI.flm_Fli
+ cmp flm,ax
+ jne $I845
+
+ ;* Just did this one */
+
+ jmp $RetFormat ; *** return ****
+; Line 125
+$I845:
+IFDEF DEBUG
+IFDEF SCRIBBLE
+ mov ax,5
+ push ax
+ mov ax,70
+ push ax
+ call FAR PTR FNSCRIBBLE
+ENDIF
+ENDIF
+; Line 129
+ ;*
+ ;* This means:
+ ;* vfli.fSplat = false;
+ ;* vfli.dcpDepend = 0;
+ ;* vfli.ichCpMac = 0;
+ ;* vfli.dypLine = 0;
+ ;* vfli.dypAfter = 0;
+ ;* vfli.dypFont = 0;
+ ;* vfli.dypBase = 0;
+ ;*
+ ; *** macro bltc destroys ax,es,cx
+ bltc <OFFSET VFLI>,0,c_cwFLIBase
+ mov WORD PTR VFLI.fSplatNext, 0
+; Line 141
+ ;* Rest of FormatLine loads up cache with current data *****
+
+ mov ax,doc
+ mov WORD PTR VFLI.doc_Fli,ax
+ mov ax,flm
+ mov WORD PTR VFLI.flm_Fli,ax
+; Line 142
+; *********** Register variables ********************
+ rax_OFF_cp EQU ax
+ rdx_SEG_cp EQU dx
+; ****************************************************
+ mov rax_OFF_cp,OFF_cp
+ mov rdx_SEG_cp,SEG_cp
+ mov WORD PTR VFLI.cpMin_OFF,rax_OFF_cp
+ mov WORD PTR VFLI.cpMin_SEG,rdx_SEG_cp
+; Line 143
+ mov cx,ichCp
+ mov WORD PTR VFLI.ichCpMin,cx
+; Line 145
+ ; *** if (cp > cpMac)
+ cmp rdx_SEG_cp,SEG_cpMac
+ jl $initRunTbl
+ jg $spAftEnd
+ cmp rax_OFF_cp,OFF_cpMac
+ jbe $initRunTbl
+$spAftEnd:
+ ;/* Space after the endmark. Reset the cache because the footnotes come
+ ;at the same cp in the footnote window */
+; Line 149
+ mov WORD PTR VFLI.doc_Fli,c_docNil
+; Line 150
+ mov WORD PTR VFLI.cpMac_OFF,rax_OFF_cp
+ mov WORD PTR VFLI.cpMac_SEG,rdx_SEG_cp
+; Line 151
+ mov WORD PTR VFLI.rgdxp,0
+; Line 159
+ ; /* Line after end mark is taller than screen */
+ mov ax,DYPMAX
+ mov WORD PTR VFLI.dypLine,ax
+ sar ax,1
+ mov WORD PTR VFLI.dypFont,ax
+ mov WORD PTR VFLI.dypBase,ax
+ jmp $ScribRet ; Scribble and return
+;
+; *************** EXIT POINT **********************************************
+;
+
+
+$initRunTbl:
+ ;/* Initialize run tables */
+ mov WORD PTR $S784_ichpFormat,0
+; Line 185
+ ;/* Cache section and paragraph properties */
+ push doc
+ push SEG_cp
+ push OFF_cp
+ call FAR PTR CACHESECT
+; Line 188
+ mov psep,OFFSET VSEPABS
+; Line 190
+ push doc
+ push SEG_cp
+ push OFF_cp
+ call FAR PTR CACHEPARA
+; Line 191
+ mov ppap,OFFSET VPAPABS
+
+ ;/* Now we have:
+ ;ppap paragraph properties
+ ;psep division properties
+ ;*/
+
+; Line 198
+ ; *** if (ppap->fGraphics)
+ mov bx,ppap
+ test WORD PTR [bx].fGraphics_Pap,mask_0001_0000
+ je $I851
+; Line 201
+ ;*** Format a picture paragraph in a special way (see picture.c)
+ push doc
+ push SEG_cp
+ push OFF_cp
+ push ichCp
+ push SEG_cpMac
+ push OFF_cpMac
+ push flm
+ call FAR PTR FORMATGRAPHICS
+ jmp $ScribRet ; Scribble and return
+;
+; *************** EXIT POINT **********************************************
+;
+$I851:
+ ; *** /* Assure we have a good memory DC for font stuff */
+ call FAR PTR VALIDATEMEMORYDC
+ cmp VHMDC,0
+ je $L20000
+ cmp VHDCPRINTER,0
+ jne $L20001
+$L20000:
+ call FAR PTR WINFAILURE
+ jmp $ScribRet ; Scribble and return
+;
+; *************** EXIT POINT **********************************************
+;
+$L20001:
+
+; Line 216
+ ; *** bltc(&ifi, 0, cwIFI);
+ ; ***/* This means:
+ ; ***ifi.ich = 0;
+ ; ***ifi.ichPrev = 0;
+ ; ***ifi.ichFetch = 0;
+ ; ***ifi.cchSpace = 0;
+ ; ***ifi.ichLeft = 0;
+ ; ****/
+
+ ; *** macro bltc destroys ax,es,cx
+ lea dx,ifi
+ bltc dx,0,c_cwIFI
+; Line 225
+ mov ifi._jc,c_jcTabLeft
+; Line 226
+ mov ifi.fPrevSpace,c_True
+; Line 230
+ ; *** /* Set up some variables that have different value depending on
+ ; *** whether we are printing or not */
+
+ ; *** if (fFlmPrinting)
+
+ cmp fFlmPrinting,0
+ je $NoPrint
+; Line 232
+ mov ax,DXAPRPAGE
+ mov dxaFormat,ax
+; Line 233
+ mov ax,DYAPRPAGE
+ mov dyaFormat,ax
+; Line 234
+ mov ax,DXPPRPAGE
+ mov dxpFormat,ax
+; Line 235
+ mov ax,DYPPRPAGE
+ mov dypFormat,ax
+; Line 236
+ mov ax,YPSUBSUPERPR
+ jmp SHORT $CalcHgt
+
+$NoPrint:
+; Line 240
+ mov ax,c_czaInch
+ mov dyaFormat,ax
+ mov dxaFormat,ax
+; Line 241
+ mov ax,DXPLOGINCH
+ mov dxpFormat,ax
+; Line 242
+ mov ax,DYPLOGINCH
+ mov dypFormat,ax
+; Line 243
+ mov ax,YPSUBSUPER
+
+$CalcHgt:
+ mov ypSubSuperFormat,ax
+
+ ; *** /* Calculate line height and width measures. Compute
+ ; *** xaLeft left indent 0 means at left margin
+ ; *** xaRight width of column measured from left
+ ; *** margin (not from left indent).
+ ; *** */
+ ; *** xaLeft = ppap->dxaLeft;
+
+; Line 251
+; *********** Register variables ********************
+ rbx_ppap EQU bx
+; ****************************************************
+ mov rbx_ppap,ppap
+ mov ax,[rbx_ppap].dxaLeft
+ mov xaLeft,ax
+; Line 255
+
+ ; *** /* If this is the first line of a paragraph,
+ ; *** adjust xaLeft for the first
+ ; *** line indent. (Also, set dypBefore, since its handy.) */
+ ; *** if (cp == vcpFirstParaCache)
+
+ mov ax,WORD PTR VCPFIRSTPARACACHE
+ mov dx,WORD PTR VCPFIRSTPARACACHE+2
+ cmp SEG_cp,dx
+ jne $setMargins
+ cmp OFF_cp,ax
+ jne $setMargins
+; Line 257
+ mov ax,[rbx_ppap].dxaLeft1
+ add xaLeft,ax
+; Line 273
+$setMargins:
+; Line 274
+ ; *** /* Now, set xaRight (width measured in twips). */
+
+IFDEF CASHMERE
+ test WORD PTR [rbx_ppap].rhc,15
+ je $L20005
+ mov ax,WORD PTR VSEPPAGE.xaMac
+ sub ax,WORD PTR VSEPPAGE.dxaGutter
+ jmp SHORT $L20006
+$L20005:
+ENDIF
+
+ mov si,psep
+ mov ax,[si].dxaText
+$L20006:
+ sub ax,[rbx_ppap].dxaRight
+ mov xaRight,ax
+; Line 277
+ ; *** /* Do necessary checks on xaLeft and xaRight */
+
+; *********** Register variables ********************
+ rcx_xaRightMax EQU cx
+; ****************************************************
+ mov rcx_xaRightMax,c_xaRightMax
+ cmp ax,rcx_xaRightMax
+ jbe $I859
+; Line 279
+ mov xaRight,rcx_xaRightMax
+; Line 281
+$I859:
+; *********** Register variables ********************
+ rax_xaLeft EQU ax
+; ****************************************************
+ mov rax_xaLeft,xaLeft
+ cmp rax_xaLeft,rcx_xaRightMax
+ jbe $I861
+; Line 283
+ mov xaLeft,rcx_xaRightMax
+; Line 285
+$I861:
+ cmp rax_xaLeft,0
+ jge $I863
+; Line 287
+ xor rax_xaLeft,rax_xaLeft
+ mov xaLeft,rax_xaLeft
+; Line 289
+$I863:
+ cmp xaRight,rax_xaLeft
+ jae $I865
+; Line 291
+ inc rax_xaLeft
+ mov xaRight,rax_xaLeft
+; Line 294
+$I865:
+ push xaLeft
+ push dxpFormat
+ push dxaFormat
+ call FAR PTR MULTDIV
+ mov ifi.xpLeft_Ifi,ax
+ mov ifi.xp,ax
+ mov WORD PTR VFLI.xpLeft_Fli,ax
+; Line 295
+ push xaLeft
+ push DXPPRPAGE
+ push DXAPRPAGE
+ call FAR PTR MULTDIV
+ mov ifi.xpPr,ax
+; Line 296
+ push xaRight
+ push dxpFormat
+ push dxaFormat
+ call FAR PTR MULTDIV
+ mov ifi.xpRight_Ifi,ax
+ mov WORD PTR VFLI.xpMarg,ax
+; Line 297
+ push xaRight
+ push DXPPRPAGE
+ push DXAPRPAGE
+ call FAR PTR MULTDIV
+ mov ifi.xpPrRight,ax
+; Line 300
+ ; *** /* Get a pointer to the tab-stop table. */
+ mov ax,ppap
+ add ax,rgtbd
+ mov ptbd,ax
+; Line 303
+ ; *** /* Turn off justification. */
+ cmp fFlmPrinting,0
+ je $L20007
+ mov ax,VHDCPRINTER
+ jmp SHORT $L20008
+$L20007:
+ mov ax,VHMDC
+$L20008:
+ push ax
+ xor ax,ax
+ push ax
+ push ax
+ call FAR PTR SETTEXTJUSTIFICATION
+; Line 306
+ ; *** /* Initialize the line height information. */
+ xor ax,ax
+ mov dypDescentMac,ax
+ mov dypAscentMac,ax
+; Line 309
+ ; *** /* To tell if there were any tabs */
+ mov ifi.ichLeft,65535
+; Line 312
+ ; *** /* Get the first run, and away we go... */
+ push doc
+ push SEG_cp
+ push OFF_cp
+ push ichCp
+ jmp SHORT $L20037
+
+$NullRun:
+; Line 357
+ mov ax,c_cpNil
+ push ax
+ push ax ; high word of cpNil
+ push ax
+ xor ax,ax
+ push ax
+$L20037:
+ mov ax,11
+ push ax
+ call FAR PTR FETCHCP
+$FirstCps:
+; Line 360
+ mov cchUsed,0
+; Line 364
+ ; *** /* Continue fetching runs until a run is found with a nonzero
+ ; *** length */
+ mov ax,VCCHFETCH
+ mov cch,ax
+ or ax,ax
+ je $NullRun
+ mov ax,VPCHFETCH
+ mov pch,ax
+; Line 371
+ mov ax,WORD PTR VCPFETCH
+ mov dx,WORD PTR VCPFETCH+2
+ cmp SEG_cpMac,dx
+ jg $I886
+ jl $L20009
+ cmp OFF_cpMac,ax
+ jbe $L20009
+ cmp fFlmPrinting,0
+ jne $I886
+ mov bx,pch
+ cmp BYTE PTR [bx],c_chSect
+ jne $I886
+$L20009:
+; Line 374
+ ; *** /* Force end mark to be in standard system font */
+; *** macro blt destroys ax,bx,cx,es
+ blt <OFFSET VCHPNORMAL>,<OFFSET VCHPABS>,c_cwCHP
+; Line 375
+IFDEF SYSENDMARK
+ ; *** vchpAbs.ftc = ftcSystem;
+ mov BYTE PTR VCHPABS.ftc,248 ; 0x3e << 2 == 0xF8 == 248
+ELSE
+ ; *** vchpAbs.ftc = 0;
+ and BYTE PTR VCHPABS.ftc,3
+ENDIF
+; Line 376
+ ; *** vchpAbs.ftcXtra = 0;
+ and BYTE PTR VCHPABS.ftcXtra,248
+
+ ; *** vchpAbs.hps = hpsDefault;
+ mov BYTE PTR VCHPABS.hps,c_hpsDefault
+; Line 394
+$I886:
+ ; *** not from original c code: copy VCHPABS into chpLocal
+ ; *** and use chpLocal hereafter ***********
+; *** macro blt destroys ax,bx,cx,es
+ lea dx,chpLocal
+ blt <OFFSET VCHPABS>,dx,c_cwCHP
+; Line 375
+ ; *** vchpAbs.ftc = 0;
+ cmp fFlmPrinting,0
+ je $I888
+; Line 396
+ push doc
+ lea ax,chpLocal
+ push ax
+ mov ax,3
+ push ax
+ call FAR PTR LOADFONT
+; Line 397
+ mov ax,WORD PTR VFMIPRINT.dypAscent_Fmi
+ add ax,WORD PTR VFMIPRINT.dypLeading
+ mov dypAscent,ax
+; Line 398
+ mov ax,WORD PTR VFMIPRINT.dypDescent_Fmi
+ jmp SHORT $L20038
+$I888:
+; Line 402
+ push doc
+ lea ax,chpLocal
+ push ax
+ mov ax,2
+ push ax
+ call FAR PTR LOADFONT
+; Line 403
+ mov ax,WORD PTR VFMISCREEN.dypAscent_Fmi
+ add ax,WORD PTR VFMISCREEN.dypLeading
+ mov dypAscent,ax
+; Line 404
+ mov ax,WORD PTR VFMISCREEN.dypDescent_Fmi
+$L20038:
+ mov dypDescent,ax
+
+ifdef ENABLE /* BRYANL 8/27/27; see comment in C source */
+ ; *** /* Bail out if there is a memory failure. */
+ cmp VFOUTOFMEMORY,0
+ je $I889
+ jmp $DoBreak
+$I889:
+endif ; ENABLE
+
+; Line 408
+ ; lines 408-417 removed
+; Line 418
+ ; *** /* Floating line size algorithm */
+ ; *** if (chpLocal.hpsPos != 0)
+
+ test BYTE PTR chpLocal.hpsPos,-1
+ je $I895
+; Line 421
+ ; *** /* Modify font for subscript/superscript */
+ ; *** if (chpLocal.hpsPos < hpsNegMin)
+
+ mov al,BYTE PTR chpLocal.hpsPos
+ cmp al,c_hpsNegMin
+ jae $I894
+; Line 423
+ mov ax,ypSubSuperFormat
+ add dypAscent,ax
+; Line 425
+ jmp SHORT $I895
+$I894:
+; Line 427
+ mov ax,ypSubSuperFormat
+ add dypDescent,ax
+; Line 428
+$I895:
+ ; *** /* Update the maximum ascent and descent of the line. */
+; Line 432
+ mov fSizeChanged,0
+; Line 433
+ mov ax,dypDescent
+ cmp dypDescentMac,ax
+ jge $I896
+; Line 435
+ mov dypDescentMac,ax
+; Line 436
+ mov fSizeChanged,1
+; Line 438
+$I896:
+ mov ax,dypAscent
+ cmp dypAscentMac,ax
+ jge $I897
+; Line 440
+ mov dypAscentMac,ax
+; Line 441
+ mov fSizeChanged,1
+; Line 444
+; dypUser EQU bp-88
+; dypAuto EQU bp-90
+; *********** Register variables ********************
+ rsi_dypAuto EQU si
+ rdi_dypUser EQU di
+; ****************************************************
+$I897:
+ cmp fSizeChanged,0
+ je $OldRun
+; Line 485
+ mov rsi_dypAuto,dypDescentMac
+ add rsi_dypAuto,dypAscentMac
+; Line 487
+ mov bx,ppap
+ mov ax,WORD PTR [bx].dyaLine
+ cmp ax,c_czaLine
+ jle $I898
+ push ax
+ push dypFormat
+ push dyaFormat
+ call FAR PTR MULTDIV
+ push ax
+ mov ax,1
+ push ax
+ call FAR PTR IMAX
+ mov rdi_dypUser,ax
+; Line 490
+ cmp rsi_dypAuto,rdi_dypUser
+ jle $L20011
+$I898:
+ mov ifi.dypLineSize,rsi_dypAuto
+ jmp SHORT $L20012
+$L20011:
+ mov ifi.dypLineSize,rdi_dypUser
+$L20012:
+; Line 496
+$OldRun:
+; Line 498
+ ; *** /* Calculate length of the run but no greater than 256 */
+ mov ax,WORD PTR VCPFETCH
+ sub ax,WORD PTR VFLI
+; Line 499
+ cmp ax,255
+ jl $I902
+; Line 501
+ mov ax,254
+; Line 503
+$I902:
+ mov iichNew,ax
+ sub ax,ifi.ich_Ifi
+ mov dich,ax
+; Line 509
+ ; *** /* Ensure that all tab and non-required
+ ; *** hyphen characters start at
+ ; *** beginning of run */
+ cmp WORD PTR $S784_ichpFormat,0
+ jle $L20013
+ or ax,ax
+ jg $L20013
+ lea ax,chpLocal
+ push ax
+ mov ax,10
+ imul WORD PTR $S784_ichpFormat
+ mov bx,VHGCHPFORMAT
+ add ax,[bx]
+ sub ax,10
+ push ax
+ mov ax,7
+ push ax
+ call FAR PTR CCHDIFFER
+ or ax,ax
+ jne $L20013
+ mov bx,pch
+ cmp BYTE PTR [bx],9
+ je $L20013
+ cmp BYTE PTR [bx],31
+ je $+5
+ jmp $I905
+; pchp EQU bp-92
+; register si=pchp
+$L20013:
+; Line 511
+ mov ax,ICHPMACFORMAT
+ cmp WORD PTR $S784_ichpFormat,ax
+ jne $L20014
+ call FGrowFormatHeap
+ or ax,ax
+ jne $+5
+ jmp $I905
+$L20014:
+; Line 514
+; *********** Register variables ********************
+ rsi_pchp EQU si
+; ****************************************************
+ mov ax,10
+ imul WORD PTR $S784_ichpFormat
+ mov rsi_pchp,ax
+ sub rsi_pchp,10
+ mov bx,VHGCHPFORMAT
+ add rsi_pchp,[bx] ; si = pch
+; Line 516
+ cmp WORD PTR $S784_ichpFormat,0
+ jle $I907
+; Line 518
+ mov ax,ifi.ich_Ifi
+ sub ax,ifi.ichPrev
+ mov BYTE PTR [rsi_pchp].cchRun,al
+; Line 519
+ mov al,BYTE PTR (ifi.ichPrev)
+ mov BYTE PTR [rsi_pchp].ichRun,al
+; Line 521
+$I907:
+ add rsi_pchp,10
+; *** macro blt destroys ax,bx,cx,es
+ mov dx,rsi_pchp
+ lea ax,chpLocal ; ax not destroyed in blt until after value used
+ blt ax,dx,c_cwCHP
+
+; Line 529
+ or BYTE PTR [rsi_pchp].cchRun,255
+; Line 530
+ cmp dich,0
+ jg $I908
+; Line 532
+ mov al,BYTE PTR (ifi.ich_Ifi)
+ jmp SHORT $L20048
+$I908:
+; Line 537
+ ; *** bltc (&vfli.rgdxp[ifi.ich],0,dich)
+
+ mov dx,ifi.ich_Ifi
+ shl dx,1
+ add dx,OFFSET VFLI.rgdxp
+ ; *** macro bltc destroys ax,es,cx
+ bltc dx,0,dich
+; Line 538
+ ; *** bltbc (&vfli.rgch[ifi.ich],0,dich)
+ mov dx,ifi.ich_Ifi
+ add dx,OFFSET VFLI.rgch
+ ;*** macro bltbc destroys ax,es,cx
+ bltbc dx,0,dich
+
+; Line 539
+ mov ax,iichNew
+ mov ifi.ich_Ifi,ax
+$L20048:
+ mov BYTE PTR [rsi_pchp].ichRun,al
+; Line 541
+ mov ax,ifi.ich_Ifi
+ mov ifi.ichPrev,ax
+; Line 542
+ inc WORD PTR $S784_ichpFormat
+; Line 544
+$I905:
+; Line 546
+ mov ax,WORD PTR VCPFETCH
+ mov dx,WORD PTR VCPFETCH+2
+ cmp SEG_cpMac,dx
+ jle $+5
+ jmp $I911
+ jl $L20016
+ cmp OFF_cpMac,ax
+ jbe $+5
+ jmp $I911
+$L20016:
+; Line 549
+ cmp ifi.fPrevSpace,0
+ je $L20015
+ ; *** note ax:dx still holds vcpFetch
+ cmp SEG_cp,dx
+ jne $I912
+ cmp OFF_cp,ax
+ jne $I912
+$L20015:
+; Line 551
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichReal,ax
+; Line 552
+ mov ax,ifi.xp
+ mov ifi.xpReal_Ifi,ax
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 554
+$I912:
+ cmp fFlmPrinting,0
+ jne $I913
+ ;mov ax,DOCHELP
+ ;cmp doc,ax
+ ;je $I913
+; Line 556
+ mov bx,ifi.ich_Ifi
+ mov BYTE PTR VFLI.rgch[bx],c_chEmark
+; Line 558
+ mov ax,c_chEmark
+ push ax
+ xor ax,ax
+ push ax
+ call FAR PTR DxpFromCh
+ mov bx,ifi.ich_Ifi
+ inc ifi.ich_Ifi
+ shl bx,1
+ mov WORD PTR VFLI.rgdxp[bx],ax
+ add WORD PTR VFLI.xpReal_Fli,ax
+; Line 560
+$I913:
+ mov ax,ifi.dypLineSize
+ mov WORD PTR VFLI.dypLine,ax
+; Line 561
+ mov ax,dypDescentMac
+ mov WORD PTR VFLI.dypBase,ax
+; Line 562
+ mov ax,dypAscentMac
+ add ax,dypDescentMac
+ mov WORD PTR VFLI.dypFont,ax
+; Line 563
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichReal,ax
+ mov WORD PTR VFLI.ichMac,ax
+; Line 564
+ mov ax,OFF_cpMac
+ mov dx,SEG_cpMac
+ add ax,1
+ adc dx,0
+ mov WORD PTR VFLI.cpMac_OFF,ax
+ mov WORD PTR VFLI.cpMac_SEG,dx
+; Line 565
+ jmp $JustEol
+$I911:
+ mov ax,ifi.ich_Ifi
+ add ax,cch
+ cmp ax,255
+ jle $I916
+; Line 573
+ mov ax,255
+ sub ax,ifi.ich_Ifi
+ mov cch,ax
+; Line 574
+ mov fTruncated,1
+; Line 577
+$I916:
+ mov ifi.ichFetch,0
+; Line 603
+ ; *** if (chpLocal.fSpecial)
+ test BYTE PTR chpLocal.fSpecial,mask_0100_0000
+ jne $+5
+ jmp $GetCh
+; Line 605
+ lea ax,ifi
+ push ax
+ push flm
+ mov ax,WORD PTR VSEPABS
+ mov cl,11
+ shr ax,cl
+ and ax,7
+ push ax
+ call FAR PTR FFORMATSPECIALS
+ or ax,ax
+ je $+5
+ jmp $GetCh
+; Line 607
+ cmp ifi.chBreak,0
+ jne $+5
+ jmp $Unbroken
+$I986:
+ mov ax,ifi.ichFetch
+ sub ax,WORD PTR VFLI.cpMac_OFF
+ add ax,WORD PTR VCPFETCH
+ mov WORD PTR VFLI.dcpDepend,ax
+; Line 1026
+$JustBreak:
+; Line 1027
+ cmp WORD PTR ifi.chBreak,31
+ je $+5
+ jmp $I992
+; Line 1032
+ mov ax,45
+ push ax
+ push fFlmPrinting
+ call FAR PTR DxpFromCh ; *** ax will have width of hyphen
+
+ ; **** up to line 1036 rearranged bz
+ mov bx,WORD PTR VFLI.ichReal
+; Line 1035
+ mov WORD PTR VFLI.ichMac,bx ; ** ichMac = ichReal
+
+ dec bx ; ichReal - 1
+ mov BYTE PTR VFLI.rgch[bx],45 ; ** rgch[ichReal-1] = "-
+
+ shl bx,1
+ mov WORD PTR VFLI.rgdxp[bx],ax
+ add ifi.xpReal_Ifi,ax
+; Line 1033
+ mov ax,ifi.xpReal_Ifi
+ mov WORD PTR VFLI.xpReal_Fli,ax
+ mov WORD PTR VFLI.xpRight,ax
+
+
+; Line 1036
+ mov ax,WORD PTR $S784_ichpFormat
+ dec ax
+ cmp ichpNRH,ax
+ jge $I992
+; pchp EQU bp-112
+; *********** Register variables ********************
+ rdi_pchp EQU di
+; ****************************************************
+; register di=pchp
+; =-114
+; =-116
+; Line 1039
+ ; ** register struct CHP *pchp=&(**vhgchpFormat)[ichpNRH]
+ mov ax,10
+ imul ichpNRH
+ mov rdi_pchp,ax
+ mov bx,VHGCHPFORMAT
+ add rdi_pchp,[bx]
+; Line 1041
+ ; ** pchp->cchRun++;
+ inc BYTE PTR [rdi_pchp].cchRun
+; Line 1042
+ ; ** if (pchp->ichRun >= vfli.ichMac)
+ mov dx,WORD PTR VFLI.ichMac
+ cmp BYTE PTR [rdi_pchp].ichRun,dl
+ jb $I992
+; Line 1044
+ ; ** pchp->ichRun = vfli.ichMac - 1;
+ dec dx
+ mov BYTE PTR [rdi_pchp].ichRun,dl
+; Line 1046
+$I992:
+; Line 1049
+ cmp fFlmPrinting,0
+ je $I993
+; Line 1051
+ mov ax,WORD PTR VFLI.ichReal
+ mov WORD PTR VFLI.ichMac,ax
+; Line 1057
+$I993:
+ cmp ifi._jc,c_jcTabLeft
+ jne $+5
+ jmp $I994
+; Line 1061
+$L20051:
+ lea ax,ifi
+ push ax
+ push xpTab
+ jmp $L20046
+; ch=-94
+; *********** Register variables ********************
+ rsi_ch EQU si
+; ****************************************************
+; register si=ch
+$I877:
+; Line 625
+ mov bx,ifi.ichFetch
+ inc ifi.ichFetch
+ mov di,pch
+ mov al,[bx][di]
+ sub ah,ah
+ mov rsi_ch,ax
+; Line 627
+$NormChar:
+; Line 628
+ cmp rsi_ch,c_chSpace
+ jne $NotSpace
+; Line 632
+ cmp fFlmPrinting,0
+ je $L20017
+ mov ax,WORD PTR VFMIPRINT+2
+ jmp SHORT $L20018
+$L20017:
+ mov ax,WORD PTR VFMISCREEN+2
+$L20018:
+ mov dxp,ax
+ mov bx,ifi.ich_Ifi
+ shl bx,1
+ mov WORD PTR VFLI.rgdxp[bx],ax
+ add ifi.xp,ax
+; Line 633
+ mov ax,WORD PTR VFMIPRINT+2
+ mov dxpPr,ax
+ add ifi.xpPr,ax
+; Line 634
+ mov bx,ifi.ich_Ifi
+ inc ifi.ich_Ifi
+ mov BYTE PTR VFLI.rgch[bx],c_chSpace
+
+; Line 635
+ jmp $BreakOppr
+
+$NotSpace:
+; Line 641
+ cmp rsi_ch,c_chSpace
+ jl $L20019
+ cmp rsi_ch,128
+ jge $L20019
+ mov bx,WORD PTR VFMIPRINT
+ shl rsi_ch,1
+ mov ax,WORD PTR [bx][rsi_ch]
+ shr rsi_ch,1
+ mov dxpPr,ax
+ cmp ax,dxpNil
+ jne $I928
+$L20019:
+; Line 643
+ push rsi_ch
+ mov ax,1
+ push ax
+ call FAR PTR DxpFromCh
+ mov dxpPr,ax
+; Line 646
+$I928:
+ cmp fFlmPrinting,0
+ je $I929
+; Line 650
+ mov ax,dxpPr
+ jmp SHORT $L20045
+$I929:
+; Line 653
+ cmp rsi_ch,c_chSpace
+ jl $L20020
+ cmp rsi_ch,128
+ jge $L20020
+ mov bx,WORD PTR VFMISCREEN
+ shl rsi_ch,1
+ mov ax,WORD PTR [bx][rsi_ch]
+ shr rsi_ch,1
+ mov dxp,ax
+ cmp ax,dxpNil
+ jne $I931
+$L20020:
+; Line 654
+ push rsi_ch
+ xor ax,ax
+ push ax
+ call FAR PTR DxpFromCh
+$L20045:
+ mov dxp,ax
+; Line 656
+$I931:
+ mov bx,ifi.ich_Ifi
+ shl bx,1
+ ; *** here ax = dxp from above
+ mov WORD PTR VFLI.rgdxp[bx],ax
+ add ifi.xp,ax
+; Line 657
+ mov ax,dxpPr
+ add ifi.xpPr,ax
+; Line 658
+ mov bx,ifi.ich_Ifi
+ inc ifi.ich_Ifi
+ mov ax,rsi_ch
+ mov BYTE PTR VFLI.rgch[bx],al
+; Line 662
+ cmp rsi_ch,45
+ jle $SwitchCh
+; Line 1001
+$DefaultCh:
+; Line 1002
+ mov ax,ifi.xpPrRight
+ cmp ifi.xpPr,ax
+ jle $PChar
+; Line 1003
+$DoBreak:
+; Line 1005
+ cmp ifi.chBreak,0
+ je $+5
+ jmp $I986
+; Line 1006
+$Unbroken:
+; Line 1011
+ mov ax,ifi.ich_Ifi
+ dec ax
+ push ax
+ call FFirstIch
+ or ax,ax
+ jne $+5
+ jmp $I987
+ cmp ifi.ich_Ifi,255
+ jl $+5
+ jmp $I987
+; Line 1013
+$PChar:
+; Line 1087
+ mov ifi.fPrevSpace,0
+; Line 1089
+ jmp SHORT $GetCh
+
+ ; ***** end for default case **************
+$SwitchCh:
+ mov ax,rsi_ch
+ cmp ax,c_chSect
+ jne $+5
+ jmp $SC942
+ jle $+5
+ jmp $L20028
+ cmp ax,c_chTab
+ jne $+5
+ jmp $SC951
+ cmp ax,c_chEol
+ jl $DefaultCh
+ cmp ax,c_chNewLine
+ jg $+5
+ jmp $SC971
+ jmp SHORT $DefaultCh
+$SC938:
+; Line 671
+ dec ifi.ich_Ifi
+; Line 672
+ mov ax,dxp
+ sub ifi.xp,ax
+; Line 673
+ mov ax,dxpPr
+ sub ifi.xpPr,ax
+
+ page
+; Line 674
+$GetCh: ; ****** START of main FOR loop ********************
+; Line 335
+ mov ax,cch
+ cmp ifi.ichFetch,ax
+ je $+5
+ jmp $I877
+; Line 341
+ cmp ifi.ich_Ifi,255
+ jge $DoBreak
+; Line 344
+ cmp fTruncated,0
+ jne $+5
+ jmp $NullRun
+; Line 349
+ add cchUsed,ax
+; Line 350
+ mov ax,cchUsed
+ add ax,VPCHFETCH
+ mov pch,ax
+; Line 351
+ mov ax,VCCHFETCH
+ sub ax,cchUsed
+ mov cch,ax
+; Line 352
+ mov fTruncated,0
+; Line 353
+ jmp $OldRun
+$SC939:
+; Line 679
+ dec ifi.ich_Ifi
+; Line 680
+ mov ax,dxp
+ sub ifi.xp,ax
+; Line 681
+ mov ax,dxpPr
+ sub ifi.xpPr,ax
+; Line 683
+ mov ax,WORD PTR $S784_ichpFormat
+ dec ax
+ mov ichpNRH,ax
+; Line 684
+ mov ax,c_chHyphen
+ push ax
+ mov ax,1
+ push ax
+ call FAR PTR DxpFromCh
+ add ax,ifi.xpPr
+ cmp ax,ifi.xpPrRight
+ jle $+5
+ jmp $DoBreak
+; Line 687
+ mov ax,ifi.xp
+ mov xpPrev,ax
+; Line 700
+ mov bx,ifi.ich_Ifi
+ mov BYTE PTR VFLI.rgch[bx],c_chTab
+; Line 701
+ jmp $Tab0
+$SC942:
+; Line 705
+ dec ifi.ich_Ifi
+; Line 706
+ mov ax,dxp
+ sub ifi.xp,ax
+; Line 707
+ mov ax,dxpPr
+ sub ifi.xpPr,ax
+; Line 710
+ mov ax,dypDescentMac
+ mov WORD PTR VFLI.dypBase,ax
+ add ax,dypAscentMac
+ mov WORD PTR VFLI.dypLine,ax
+ mov WORD PTR VFLI.dypFont,ax
+; Line 711
+ mov ax,ifi.ichFetch
+ cwd
+ add ax,WORD PTR VCPFETCH
+ adc dx,WORD PTR VCPFETCH+2
+ mov WORD PTR VFLI.cpMac_OFF,ax
+ mov WORD PTR VFLI.cpMac_SEG,dx
+; Line 712
+ push ifi.ich_Ifi
+ call FFirstIch
+ or ax,ax
+ jne $+5
+ jmp $I943
+; Line 715
+ mov ax,WORD PTR VFLI.fSplat
+ mov al,1
+ mov WORD PTR VFLI.fSplat,ax
+; Line 716
+ cmp fFlmPrinting,0
+ je $+5
+ jmp $I944
+ ;chT EQU bp-96
+ ;cch EQU bp-98
+ ;dxpCh EQU bp-100
+; Line 723
+ mov chT,c_chSplat
+; Line 726
+ push chT
+ xor ax,ax
+ push ax
+ call FAR PTR DxpFromCh
+ mov dxpCh,ax
+; Line 730
+ mov ax,17
+ imul DXPLOGINCH
+ cwd
+ sub ax,dx
+ sar ax,1
+ cwd
+ mov cx,dxpCh
+ idiv cx
+ cmp ax,223
+ jge $L20021
+ jmp SHORT $L20022
+$L20021:
+ mov ax,223
+$L20022:
+ mov cch2,ax
+; Line 732
+ ; *** bltbc(&vfli.rgch[ifi.ich], chT, cch);
+ mov dx,ifi.ich_Ifi
+ add dx,OFFSET VFLI.rgch
+ ;*** macro bltbc destroys ax,es,cx
+ bltbc dx,<BYTE PTR (chT)>,cch2
+; Line 733
+ ; *** bltc(&vfli.rgdxp[ifi.ich], dxpCh, cch);
+ mov dx,ifi.ich_Ifi
+ shl dx,1
+ add dx,OFFSET VFLI.rgdxp
+ ; *** macro bltc destroys ax,es,cx
+ bltc dx,dxpCH,cch2
+; Line 734
+ mov ax,ifi.ich_Ifi
+ add ax,cch2
+ mov WORD PTR VFLI.ichMac,ax
+; Line 736
+ push VHMDC
+ mov ax,OFFSET VFLI.rgch
+ push ds
+ push ax
+ push cch2
+ call FAR PTR GETTEXTEXTENT
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 737
+ mov WORD PTR VFLI.xpLeft_Fli,0
+; Line 739
+ jmp $EndFormat
+$I944:
+; Line 741
+ mov WORD PTR VFLI.ichMac,0
+; Line 743
+ jmp $EndFormat
+$I943:
+ mov WORD PTR VFLI.fSplatNext, 1
+
+ mov ax,cchUsed
+ dec ax
+ cwd
+ add WORD PTR VFLI.cpMac_OFF,ax
+ adc WORD PTR VFLI.cpMac_SEG,dx
+; Line 749
+ mov WORD PTR VFLI.dcpDepend,1
+; Line 750
+ cmp ifi.fPrevSpace,0
+ jne $I950
+; Line 752
+ mov ax,ifi.cchSpace
+ mov ifi.cBreak_Ifi,ax
+; Line 753
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichReal,ax
+; Line 754
+ mov ax,ifi.xp
+ mov ifi.xpReal_Ifi,ax
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 756
+$I950:
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichMac,ax
+; Line 757
+ mov ax,ifi.dypLineSize
+ mov WORD PTR VFLI.dypLine,ax
+; Line 758
+ jmp $JustBreak
+$SC951:
+; Line 762
+ dec ifi.ich_Ifi
+; Line 763
+ mov ax,dxp
+ sub ifi.xp,ax
+; Line 764
+ mov ax,dxpPr
+ sub ifi.xpPr,ax
+ ;xaTab EQU bp-102
+ ;xaPr EQU bp-104
+; pchp EQU bp-106
+; register di=pchp
+; Line 766
+ mov ax,ifi.xpPrRight
+ cmp ifi.xpPr,ax
+ jl $+5
+ jmp $I952
+; Line 772
+ cmp ifi.fPrevSpace,0
+ jne $I956
+; Line 776
+ mov ax,ifi.cchSpace
+ mov ifi.cBreak_Ifi,ax
+; Line 777
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichReal,ax
+; Line 778
+ mov ax,ifi.xp
+ mov ifi.xpReal_Ifi,ax
+; Line 781
+$I956:
+ cmp ifi._jc,c_jcTabLeft
+ je $I957
+; Line 783
+ lea ax,ifi
+ push ax
+ push xpTab
+ push flm
+ call Justify
+; Line 785
+$I957:
+ mov ax,ifi.xp
+ mov xpPrev,ax
+; Line 788
+ push ifi.xpPr
+ push DXAPRPAGE
+ push DXPPRPAGE
+ call FAR PTR MULTDIV
+ mov xaPr,ax
+; Line 789
+ jmp SHORT $L20041
+$WC958:
+ mov ax,xaRight
+ cmp xaTab,ax
+ jb $I959
+ mov xaTab,ax
+$I959:
+; Line 791
+ mov ax,xaPr
+ cmp xaTab,ax
+ jb $I960
+; Line 799
+ add ptbd,4
+ mov al, [bx].jc_Tbd
+ sub ah,ah
+ and ax,7
+ add ax,c_jcTabMin
+;#ifdef ENABLE /* we do the mapping in HgtbdCreate */
+; cmp ax,c_jcTabDecimal
+; je $I1958
+; mov ax,c_jcTabLeft
+;#endif
+$I1958:
+ mov ifi._jc,ax
+; Line 800
+ jmp SHORT $TabFound
+$I960:
+ add ptbd,4
+; Line 803
+$L20041:
+ mov bx,ptbd
+ mov ax,[bx]
+ mov xaTab,ax
+ or ax,ax
+ jne $WC958
+; Line 806
+ mov ax,xaPr
+ sub dx,dx
+ mov cx,WORD PTR VZATABDFLT
+ div cx
+ mul cx
+ add ax,cx
+ mov xaTab,ax
+; Line 812
+ mov ifi._jc,c_jcTabLeft
+; Line 814
+$TabFound:
+; Line 815
+ push xaTab
+ push dxpFormat
+ push dxaFormat
+ call FAR PTR MULTDIV
+ cmp ifi.xp,ax
+ jle $I1961
+ mov ax,ifi.xp
+$I1961:
+ mov xpTab,ax
+; Line 822
+ cmp ifi._jc,c_jcTabLeft
+ jne $I962
+; Line 825
+ mov ifi.xp,ax
+; Line 826
+ push xaTab
+ push DXPPRPAGE
+ push DXAPRPAGE
+ call FAR PTR MULTDIV
+ mov ifi.xpPr,ax
+; Line 828
+$I962:
+ mov ax,ifi.xp
+ mov ifi.xpLeft_Ifi,ax
+; Line 829
+ mov ax,ifi.ich_Ifi
+ mov ifi.ichLeft,ax
+; Line 830
+ mov ifi.cchSpace,0
+; Line 831
+ mov ifi.chBreak,0
+; Line 832
+$Tab0:
+; Line 833
+ mov ifi.fPrevSpace,0
+; Line 834
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichMac,ax
+; Line 835
+ mov ax,ifi.xp
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 836
+ mov ax,ifi.dypLineSize
+ mov WORD PTR VFLI.dypLine,ax
+; Line 837
+ mov ax,dypDescentMac
+ mov WORD PTR VFLI.dypBase,ax
+; Line 838
+ mov ax,dypAscentMac
+ add ax,dypDescentMac
+ mov WORD PTR VFLI.dypFont,ax
+; Line 841
+ cmp ifi.ichFetch,1
+ je $I963
+ mov ax,ICHPMACFORMAT
+ cmp WORD PTR $S784_ichpFormat,ax
+ jne $L20023
+ call FGrowFormatHeap
+ or ax,ax
+ je $I963
+$L20023:
+; Line 845
+; *********** Register variables ********************
+; rdi_pchp EQU di
+; ****************************************************
+; register di=pchp
+ mov ax,10
+ imul WORD PTR $S784_ichpFormat
+ mov rdi_pchp,ax
+ sub rdi_pchp,10
+ mov bx,VHGCHPFORMAT
+ add rdi_pchp,[bx]
+; Line 846
+ cmp WORD PTR $S784_ichpFormat,0
+ jle $I964
+; Line 849
+ mov al,BYTE PTR (ifi.ichPrev)
+ mov BYTE PTR [rdi_pchp].ichRun,al
+; Line 850
+ mov ax,ifi.ich_Ifi
+ sub ax,ifi.ichPrev
+ mov BYTE PTR [rdi_pchp].cchRun,al
+; Line 853
+$I964:
+ add rdi_pchp,10 ; ** ++pchp
+ lea ax,chpLocal ; ax not destroyed in blt until after value used
+ ;*** macro blt destroys ax,bx,cx,es
+ blt ax,rdi_pchp,c_cwCHP
+
+; Line 854
+ inc WORD PTR $S784_ichpFormat
+; Line 856
+ jmp SHORT $I965
+$I963:
+; Line 858
+ mov ax,10
+ imul WORD PTR $S784_ichpFormat
+ mov rdi_pchp,ax
+ sub rdi_pchp,10
+ mov bx,VHGCHPFORMAT
+ add rdi_pchp,[bx]
+; Line 859
+$I965:
+; Line 860
+ mov al,BYTE PTR (ifi.ich_Ifi)
+ mov BYTE PTR [rdi_pchp].ichRun,al
+; Line 861
+ or BYTE PTR [rdi_pchp].cchRun,255
+
+; Line 867
+ mov bx,ifi.ich_Ifi
+ inc ifi.ich_Ifi
+ mov ifi.ichPrev,bx
+ shl bx,1
+ mov ax,ifi.xp
+ sub ax,xpPrev
+ mov WORD PTR VFLI.rgdxp[bx],ax
+; Line 869
+ cmp rsi_ch,c_chTab
+ jne $BreakOppr
+ jmp $GetCh
+$I952:
+; Line 878
+ mov rsi_ch,160
+; Line 879
+ jmp $NormChar
+$SC968:
+; Line 883
+ mov ax,ifi.xpPrRight
+ cmp ifi.xpPr,ax
+ jle $+5
+ jmp $DoBreak
+; Line 885
+$BreakOppr:
+; Line 891
+ cmp ifi.ich_Ifi,255
+ jl $+5
+ jmp $Unbroken
+; Line 893
+$SC971:
+; Line 898
+ mov ifi.chBreak,rsi_ch
+; Line 899
+ mov ax,ifi.ichFetch
+ add ax,cchUsed
+ cwd
+ add ax,WORD PTR VCPFETCH
+ adc dx,WORD PTR VCPFETCH+2
+ mov WORD PTR VFLI.cpMac_OFF,ax
+ mov WORD PTR VFLI.cpMac_SEG,dx
+; Line 900
+ mov ax,ifi.xp
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 901
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichMac,ax
+; Line 902
+ mov ax,ifi.dypLineSize
+ mov WORD PTR VFLI.dypLine,ax
+; Line 904
+ mov ax,dypDescentMac
+ mov WORD PTR VFLI.dypBase,ax
+ add ax,dypAscentMac
+ mov WORD PTR VFLI.dypFont,ax
+; Line 906
+ cmp rsi_ch,45
+ je $L20024
+ cmp rsi_ch,31
+ jne $I972
+$L20024:
+; Line 908
+ mov ax,ifi.cchSpace
+ mov ifi.cBreak_Ifi,ax
+; Line 909
+ mov ax,ifi.ich_Ifi
+ mov WORD PTR VFLI.ichReal,ax
+; Line 910
+ mov ax,ifi.xp
+ mov ifi.xpReal_Ifi,ax
+ mov WORD PTR VFLI.xpReal_Fli,ax
+; Line 912
+ jmp $GetCh
+$I972:
+; Line 914
+ cmp ifi.fPrevSpace,0
+ jne $I974
+; Line 916
+ mov ax,ifi.cchSpace
+ mov ifi.cBreak_Ifi,ax
+; Line 917
+ mov ax,ifi.ich_Ifi
+ dec ax
+ mov WORD PTR VFLI.ichReal,ax
+; Line 918
+ mov ax,ifi.xp
+ mov WORD PTR VFLI.xpReal_Fli,ax
+ sub ax,dxp
+ mov ifi.xpReal_Ifi,ax
+; Line 920
+ ;chT EQU bp-108
+ ;dxpNew EQU bp-110
+$I974:
+ cmp rsi_ch,10
+ je $L20025
+ cmp rsi_ch,11
+ jne $I975
+$L20025:
+; Line 943
+ mov chT2,c_chSpace
+; Line 946
+ push chT2
+ push fFlmPrinting
+ call FAR PTR DxpFromCh
+ ; *** ax will contain dxpNew at this point ****
+; Line 948
+ mov bx,ifi.ich_Ifi
+ mov dl,BYTE PTR (chT2)
+ mov BYTE PTR VFLI.rgch[bx-1],dl
+; Line 950
+ shl bx,1
+ ;** difference was -1 in c - shifted to get -2
+ mov WORD PTR VFLI.rgdxp[bx-2],ax ; ax has dxpNew
+
+ cmp ifi.fPrevSpace,0 ; only reset vfli.xp/ich real if not prev sp
+ jne $TestEol
+
+ sub ax,dxp
+ add WORD PTR VFLI.xpReal_Fli,ax
+; Line 956
+ mov ax,ifi.ich_Ifi
+ dec ax
+ mov WORD PTR VFLI.ichReal,ax
+; Line 961
+$TestEol:
+ cmp rsi_ch,10
+ je $+5
+ jmp $JustBreak
+; Line 963
+$JustEol:
+; Line 964
+ cmp fFlmPrinting,0
+ je $I979
+; Line 966
+ mov ax,WORD PTR VFLI.ichReal
+ mov WORD PTR VFLI.ichMac,ax
+; Line 972
+$I979:
+ cmp ifi._jc,c_jcTabLeft
+ je $+5
+ jmp $L20051
+; Line 980
+ mov bx,ppap
+ mov al,BYTE PTR [bx].jc_Pap
+ and ax,3 ; pick up low 2 bits in ax
+ mov ifi._jc,ax
+ cmp ax,3
+ je $I996
+ jmp SHORT $L20050
+$I975:
+ inc ifi.cchSpace
+; Line 995
+ mov ifi.fPrevSpace,1
+; Line 1093
+ jmp $GetCh
+$I987:
+ mov ax,ifi.ichFetch
+ add ax,cchUsed
+ cwd
+ add ax,WORD PTR VCPFETCH
+ adc dx,WORD PTR VCPFETCH+2
+ sub ax,1
+ sbb dx,0
+ mov WORD PTR VFLI.cpMac_OFF,ax
+ mov WORD PTR VFLI.cpMac_SEG,dx
+; Line 1016
+ mov ax,ifi.ich_Ifi
+ dec ax
+ mov WORD PTR VFLI.ichMac,ax
+ mov WORD PTR VFLI.ichReal,ax
+; Line 1017
+ mov ax,ifi.dypLineSize
+ mov WORD PTR VFLI.dypLine,ax
+; Line 1019
+ mov ax,dypDescentMac
+ mov WORD PTR VFLI.dypBase,ax
+ add ax,dypAscentMac
+ mov WORD PTR VFLI.dypFont,ax
+; Line 1020
+ mov WORD PTR VFLI.dcpDepend,1
+; Line 1021
+ mov ax,ifi.xp
+ sub ax,dxp
+ mov ifi.xpReal_Ifi,ax
+ mov WORD PTR VFLI.xpReal_Fli,ax
+$I994:
+ mov bx,ppap
+ mov al,BYTE PTR [bx].jc_Pap
+ and ax,3
+ mov ifi._jc,ax
+$L20050:
+ or ax,ax
+ je $I996
+; Line 1065
+ lea ax,ifi
+ push ax
+ push ifi.xpRight_Ifi
+$L20046:
+ push flm
+ call Justify
+; Line 1067
+$I996:
+ mov ax,ifi.xpRight_Ifi
+$L20043:
+ mov WORD PTR VFLI.xpRight,ax
+; Line 1068
+$EndFormat:
+; Line 1069
+ mov ax,ifi.ichLeft
+ mov WORD PTR VFLI.ichLastTab,ax
+ jmp SHORT $ScribRet ; Scribble and return
+$L20028:
+ cmp ax,13
+ jne $+5
+ jmp $SC938
+ cmp ax,31
+ jne $+5
+ jmp $SC939
+ cmp ax,45
+ jne $+5
+ jmp $SC968
+ jmp $DefaultCh
+$ScribRet:
+IFDEF DEBUG
+IFDEF SCRIBBLE
+ mov ax,5
+ push ax
+ mov ax,c_chSpace
+ push ax
+ call FAR PTR FNSCRIBBLE
+ENDIF
+ENDIF
+; Line 1096
+$RetFormat:
+ cEnd FormatLine
+
+ subttl Justify()
+ page
+; ***
+; Function Justify
+;
+; near Justify(pifi, xpTab, flm)
+; struct IFI *pifi;
+; unsigned xpTab;
+; int flm;
+;
+; ***
+
+; Line 1101
+ cProc Justify,<PUBLIC,NEAR>,<di,si>
+ parmDP pifi
+ parmW xpTab
+ parmW flm
+
+ LocalW cWideSpaces
+ LocalW cxpQuotient
+; *********** Register variables ********************
+ rbx_pifi EQU bx
+ rdx_dxp EQU dx
+; ****************************************************
+ cBegin Justify
+; Line 1109
+ mov rbx_pifi,pifi
+; Line 1110
+ mov ax,[rbx_pifi]._jc
+ cmp ax,c_jcBoth
+ je $JcBothCase
+ cmp ax,c_jcCenter
+ je $JcCenterCase
+ cmp ax,c_jcRight
+ je $JcRightCase
+ cmp ax,c_jcTabDecimal
+ jne $JustCaseBrk
+; Line 1130
+JcTabDecCase:
+; *********** Register variables ********************
+ rsi_ichT EQU si
+; ****************************************************
+ mov rdx_dxp,xpTab
+ sub rdx_dxp,[rbx_pifi].xpLeft_Ifi
+; Line 1132
+ mov rsi_ichT,[rbx_pifi].ichLeft
+ inc rsi_ichT
+$TabDecFor:
+ cmp rsi_ichT,WORD PTR VFLI.ichReal
+ jge $JustCaseBrk
+ mov al,VCHDECIMAL
+ cmp BYTE PTR VFLI.rgch[rsi_ichT],al
+ je $JustCaseBrk
+; Line 1134
+ shl rsi_ichT,1
+ sub rdx_dxp,WORD PTR VFLI.rgdxp[rsi_ichT]
+ shr rsi_ichT,1
+; Line 1135
+ inc rsi_ichT
+ jmp SHORT $TabDecFor
+
+$JcCenterCase:
+; Line 1139
+ mov rdx_dxp,xpTab
+ sub rdx_dxp,[rbx_pifi].xpReal_Ifi
+ or rdx_dxp,rdx_dxp
+ jg $+5
+ jmp $JustifyRet
+ ; **** EXIT POINT *****************************
+; Line 1141
+ sar rdx_dxp,1
+; Line 1144
+
+$JustCaseBrk:
+; Line 1212
+ cmp rdx_dxp,0
+ jle $+5
+ jmp $JustCleanup
+; Line 1215
+ jmp $JustifyRet
+ ; **** EXIT POINT *****************************
+
+$JcRightCase:
+; Line 1147
+ mov rdx_dxp,xpTab
+ sub rdx_dxp,[rbx_pifi].xpReal_Ifi
+; Line 1148
+ jmp SHORT $JustCaseBrk
+
+$JcBothCase:
+; *********** Register variables ********************
+ rdi_pch EQU di
+ rsi_pdxp EQU si
+; ***************************************************
+ ; **** NOTE: the only way out of this section of code
+ ; **** is through a RETURN of function Justify
+; Line 1151
+ cmp WORD PTR [rbx_pifi].cBreak_Ifi,0
+ jne $+5
+ jmp $JustifyRet
+ ; **** EXIT POINT *****************************
+; Line 1154
+ mov rdx_dxp,xpTab
+ sub rdx_dxp,[rbx_pifi].xpReal_Ifi
+ or rdx_dxp,rdx_dxp
+ jg $+5
+ jmp $JustifyRet
+ ; **** EXIT POINT *****************************
+; Line 1160
+ add [rbx_pifi].xp,rdx_dxp
+; Line 1164
+ add WORD PTR VFLI.xpReal_Fli,rdx_dxp
+; Line 1165
+; Line 1176
+ ; register CHAR *pch = &vfli.rgch[vfli.ichReal]
+ ; register int *pdxp = &vfli.rgdxp[vfli.ichReal]
+
+ mov rdi_pch,WORD PTR VFLI.ichReal
+ mov rsi_pdxp,rdi_pch
+
+ add rdi_pch,OFFSET VFLI.rgch
+
+ shl rsi_pdxp,1
+ add rsi_pdxp,OFFSET VFLI.rgdxp
+
+ ; ************ dx /(dxp) will be wiped out and restored here !!!!!!!!!!!!!!!
+ push dx ; save for use as dxpT
+
+ mov ax,dx ; ** set up division
+ cwd
+ mov cx,[rbx_pifi].cBreak_Ifi
+ idiv cx
+ mov WORD PTR VFLI.dxpExtra,ax
+ ; ** at this point:
+ ; ** ax = quotient, dx = remainder, cx = cbreak
+ inc ax
+
+; *********** Register variables ********************
+ rdx_dxpT EQU dx
+; ***************************************************
+
+ mov cxpQuotient,ax
+ mov cWideSpaces,dx
+
+ pop dx ; restore for use as dxpT
+
+; Line 1183
+ mov BYTE PTR VFLI.fAdjSpace,c_True
+; Line 1185
+ ; ***** NOTE: the only way out of this loop is via a RETURN out of
+ ; ***** function Justify
+ ; * the immediately following loop accomplishes about the same thing as
+; ** Loop:
+ ; dec rdi_pch
+ ; sub rsi_pdxp,2
+ ; cmp BYTE PTR [rdi_pch],c_chSpace
+ ; jne Loop
+ ; * it should be faster for strings of > 2 characters.
+
+ dec rdi_pch ; since predecrement to start pch correctly
+ mov ax,ds
+ mov es,ax ; set up for string instruction
+ std ; use reverse direction for decrementing di
+$JstForLoop:
+ mov cx,-1 ; counter set up 1 below (trick)
+ mov al,c_chSpace ; comparison value
+ repnz scasb ; dec di while not = space
+ inc cx ; restore from original -1
+ shl cx,1 ; si is a word ptr - double offset
+ add rsi_pdxp,cx
+ ; at this point, pch points 1 below
+ ; the character containing the space,
+ ; pdxp points to the entry for the space char
+; Line 1192
+ mov ax,cWideSpaces
+ dec cWideSpaces
+ or ax,ax
+ jne $I1032
+; Line 1194
+ dec cxpQuotient
+; Line 1195
+ push rsi_pdxp ; find first nonzero ich after pch
+ cld
+$FindIch1:
+ inc rsi_pdxp
+ inc rsi_pdxp
+ cmp WORD PTR [rsi_pdxp],0
+ je $FindIch1
+ mov ax,rsi_pdxp
+ sub ax,OFFSET VFLI + rgdxp
+ shr ax,1
+ std
+ pop rsi_pdxp
+
+ mov BYTE PTR VFLI.ichFirstWide,al
+
+; Line 1197
+$I1032:
+ mov ax,cxpQuotient
+ add [rsi_pdxp],ax
+; Line 1198
+ sub rdx_dxpT,ax
+ cmp rdx_dxpT,0
+ jg $I1033
+; Line 1200
+ cmp WORD PTR [rbx_pifi].cBreak_Ifi,1
+ jle $JustifyRet
+ ; **** EXIT POINT *****************************
+; Line 1202
+ push rsi_pdxp ; find first nonzero ich after pch
+ cld
+$FindIch2:
+ inc rsi_pdxp
+ inc rsi_pdxp
+ cmp WORD PTR [rsi_pdxp],0
+ je $FindIch2
+ mov ax,rsi_pdxp
+ sub ax,OFFSET VFLI + rgdxp
+ shr ax,1
+ pop rsi_pdxp
+
+ mov BYTE PTR VFLI.ichFirstWide,al
+; Line 1204
+ jmp SHORT $JustifyRet
+ ; **** EXIT POINT *****************************
+$I1033:
+ dec WORD PTR [rbx_pifi].cBreak_Ifi
+; Line 1208
+ jmp SHORT $JstForLoop ; *** end of for loop **********
+
+
+; *********** Register variables ********************
+ rbx_pifi EQU bx
+ rdx_dxp EQU dx
+; ****************************************************
+
+$JustCleanup:
+ add [rbx_pifi],rdx_dxp
+ mov ax,rdx_dxp
+; Line 1220
+ test flm,1 ;* if (flm & flmPrinting)
+ jne $L20052
+; Line 1228
+ push rdx_dxp ; save - wiped out by multiply
+
+ push rdx_dxp
+ mov ax,c_czaInch
+ push ax
+ push DXPLOGINCH
+ call FAR PTR MULTDIV
+ push ax
+ push DXPPRPAGE
+ push DXAPRPAGE
+ call FAR PTR MULTDIV
+
+ mov rbx_pifi,pifi ; restore in case multdiv wipes out bx
+ pop rdx_dxp ; restore - wiped out by multdiv
+$L20052:
+ add [rbx_pifi].xpPr,ax
+; Line 1231
+ cmp WORD PTR [rbx_pifi].ichLeft,0
+ jge $I1038
+; Line 1234
+ add WORD PTR VFLI.xpLeft_Fli,rdx_dxp
+; Line 1236
+ jmp SHORT $I1039
+$I1038:
+; Line 1239
+ mov bx,[rbx_pifi].ichLeft ; *** here, bx is no longer pifi ****
+ shl bx,1
+ add WORD PTR VFLI.rgdxp[bx],rdx_dxp
+; Line 1240
+$I1039:
+; Line 1241
+ add WORD PTR VFLI.xpReal_Fli,rdx_dxp
+; Line 1242
+$JustifyRet:
+ cld ; reset to be nice to later routines
+ cEnd Justify
+
+
+; Line 1247
+ subttl FGrowFormatHeap()
+ page
+
+; ***
+; Function FGrowFormatHeap
+;
+; int near FGrowFormatHeap()
+; /* Grow vhgchpFormat by 20% */
+;
+; ***
+
+ cProc FGrowFormatHeap,<PUBLIC,NEAR>
+ cBegin FGrowFormatHeap
+
+; *********** Register variables ********************
+ rsi_cchpIncr EQU si
+; ****************************************************
+
+; Line 1249
+ mov ax,ICHPMACFORMAT
+ cwd
+ mov cx,5
+ idiv cx
+ inc ax
+ mov rsi_cchpIncr,ax
+; Line 1255
+ push VHGCHPFORMAT
+ add ax,ICHPMACFORMAT
+ imul cx
+ push ax
+ xor ax,ax
+ push ax
+ call FAR PTR FCHNGSIZEH
+ or ax,ax
+ jne $I1043
+; Line 1260
+ xor ax,ax
+ jmp SHORT $EX1040
+$I1043:
+ add ICHPMACFORMAT,rsi_cchpIncr
+; Line 1263
+ mov ax,1
+$EX1040:
+ cEnd FGrowFormatHeap
+
+
+; Line 1269
+ subttl DxpFromCh()
+ page
+
+; ***
+; Function DxpFromCh
+;
+; int DxpFromCh(ch, fPrinter)
+; int ch;
+; int fPrinter;
+;
+; ***
+
+
+ cProc DxpFromCh,<PUBLIC,FAR>
+ parmW chIn
+ parmW fPrinter
+
+ LocalW dxpDummy
+ LocalW dxp
+ cBegin DxpFromCh
+
+; *********** Register variables ********************
+ rbx_pdxp EQU bx
+; ****************************************************
+
+; Line 1276
+ cmp chIn,c_chSpace
+ jg $L20029
+ cmp chIn,c_chNRHFile
+ jge $L20026
+ cmp chIn,c_chTab
+ jl $L2029A
+ cmp chIn,c_chReturn
+ jg $L2029A
+$L20026:
+ cmp fPrinter,0
+ je $L20027
+ mov rbx_pdxp,OFFSET VFMIPRINT+2
+ jmp SHORT $I1050
+$L20027:
+ mov rbx_pdxp,OFFSET VFMISCREEN+2
+ jmp SHORT $I1050
+$L20029:
+ cmp chIn,256 ; prev 128 (chFmiMax) ..pault
+ ; We now make sure the whole character set width
+ ; table is queried initially via GetCharWidth()
+ jl $I1049
+; Line 1279
+$L2029A:
+ lea rbx_pdxp,dxpDummy
+; Line 1280
+ mov WORD PTR [rbx_pdxp],dxpNil
+; Line 1282
+ jmp SHORT $I1050
+$I1049:
+; Line 1285
+ cmp fPrinter,0
+ je $L20030
+ mov rbx_pdxp,WORD PTR VFMIPRINT
+ jmp SHORT $L20031
+$L20030:
+ mov rbx_pdxp,WORD PTR VFMISCREEN
+$L20031:
+ mov ax,chIn
+ shl ax,1
+ add rbx_pdxp,ax
+; Line 1286
+$I1050:
+; Line 1288
+ cmp WORD PTR [rbx_pdxp],dxpNil
+ jne $I1051
+; Line 1295
+ push bx ; save pdxp
+
+ cmp fPrinter,0
+ je $L20032
+ push VHDCPRINTER
+ lea ax,chIn
+ push ss
+ push ax
+ mov ax,1
+ push ax
+ call FAR PTR GETTEXTEXTENT
+ sub ax,WORD PTR VFMIPRINT+4
+ jmp SHORT $L20033
+$L20032:
+ push VHMDC
+ lea ax,chIn
+ push ss
+ push ax
+ mov ax,1
+ push ax
+ call FAR PTR GETTEXTEXTENT
+ sub ax,WORD PTR VFMISCREEN+4
+$L20033:
+ pop bx ; restore pdxp
+; Line 1297
+ ;or ax,ax ; ax == dxp
+ ;jl $I1053
+ ;cmp ax,dxpNil
+ ;jge $I1053
+; Line 1300
+ mov [rbx_pdxp],ax
+; Line 1303
+$I1053:
+ jmp SHORT $DxpRet
+$I1051:
+ mov ax,WORD PTR [rbx_pdxp]
+$DxpRet:
+ cEnd DxpFromCh
+
+ subttl FFirstIch()
+ page
+; Line 1312
+
+; ***
+; Function FFirstIch
+;
+; int near FFirstIch(ich)
+; int ich;
+; {
+; /* Returns true iff ich is 0 or preceded only by 0 width characters */
+;
+; REGISTER USAGE ******************************
+; uses and restores: di
+; uses and destroys: ax, cx, es
+; ax = temp, return
+; cx = ich
+; di = pdxp
+;
+; Note: this implements, in a different manner, the c code:
+;
+; for (ichT = 0; ichT < ich; ichT++)
+; {
+; if (*pdxp++)
+; return false
+; }
+; return true;
+; ***
+
+ cProc FFirstIch,<PUBLIC,NEAR>,<di>
+ parmW ich
+
+ cBegin FFirstIch
+
+; *********** Register variables ********************
+ rdi_pdxp EQU di
+ rcx_ich EQU cx
+; ****************************************************
+; Line 1316
+ mov ax,ds ; set es=ds for string ops
+ mov es,ax
+
+ mov rdi_pdxp,OFFSET VFLI.rgdxp
+ mov rcx_ich,ich ; loop count in cx
+ cld
+
+ xor ax,ax ; this does 3 things:
+ ; - sets up the compare value for scasb
+ ; - sets a 0 (false) default return value
+ ; - sets the zero flag on. This will allow
+ ; a zero value of ich to correctly return
+ ; true. This instruction MUST immediately
+ ; precede the repz scasw instruction.
+ repz scasw ; test *pdxp = 0
+ jnz $FFRet ; non zero char found - return false
+ inc ax ; return TRUE if all 0 or ich = 0
+$FFRet:
+ cEnd FFirstIch
+
+
+ subttl ValidateMemoryDC()
+ page
+
+; ValidateMemoryDC()
+
+ cProc ValidateMemoryDC,<PUBLIC,FAR>
+ cBegin ValidateMemoryDC
+
+; /* Attempt to assure that vhMDC and vhDCPrinter are valid. If we have not
+; already run out of memory, then vhDCPrinter is guaranteed, but vhMDC may
+; fail due to out of memory -- it is the callers responsibility to check for
+; vhMDC == NULL. */
+
+; /* If we are out of memory, then we shouldn't try to gobble it up by getting
+; DC's. */
+ cmp VFOUTOFMEMORY,0
+ jne $I862
+ cmp VHMDC,0
+ jne $I858
+ mov bx,PWWDCUR
+ push WORD PTR [bx+50]
+ call FAR PTR CREATECOMPATIBLEDC
+ mov VHMDC,ax
+; /* Callers are responsible for checking for vhMDC == NULL case */
+ or ax,ax
+ je $I858
+; /* Put the memory DC in transparent mode. */
+ push ax
+ mov ax,1
+ push ax
+ call FAR PTR SETBKMODE
+; /* If the display is a monochrome device, then set the text color for the
+; memory DC. Monochrome bitmaps will not be converted to the foreground and
+; background colors in this case, we must do the conversion. */
+ mov bx,PWWDCUR
+ push WORD PTR [bx+50]
+ mov ax,24
+ push ax
+ call FAR PTR GETDEVICECAPS
+ cmp ax,2
+ jne $I854
+ mov ax,1
+ jmp SHORT $I856
+$I854:
+ xor ax,ax
+$I856:
+ mov VFMONOCHROME,ax
+ or ax,ax
+ je $I858
+ push VHMDC
+ push WORD PTR RGBTEXT+2
+ push WORD PTR RGBTEXT
+ call FAR PTR SETTEXTCOLOR
+$I858:
+; /* If the printer DC is NULL then we need to restablish it. */
+ cmp VHDCPRINTER,0
+ jne $I862
+ xor ax,ax
+ push ax
+ call FAR PTR GETPRINTERDC
+$I862:
+ cEnd ValidateMemoryDC
+
+ sEnd FORM1_TEXT
+END
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/format2.c b/private/mvdm/wow16/write/format2.c
new file mode 100644
index 000000000..71cd2cc50
--- /dev/null
+++ b/private/mvdm/wow16/write/format2.c
@@ -0,0 +1,312 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* format2.c -- MW formatting routines */
+/* Less used subroutines */
+
+
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "editdefs.h"
+#include "cmddefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "ffdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "printdef.h"
+#include "str.h"
+#include "wwdefs.h"
+
+extern struct FLI vfli;
+extern struct SEP vsepAbs;
+extern typeCP vcpFirstSectCache;
+extern typeCP vcpFetch;
+extern int vcchFetch;
+extern CHAR *vpchFetch;
+extern int vpgn;
+extern CHAR stBuf[];
+extern struct DOD (**hpdocdod)[];
+extern struct WWD rgwwd[];
+extern typeCP cpMinDocument;
+
+
+int CchExpPgn(pch, pgn, nfc, flm, cchMax)
+CHAR *pch;
+unsigned pgn, cchMax;
+int nfc, flm;
+{
+
+#ifdef CASHMERE
+static CHAR rgchUCRoman[] = "IVIIIXLXXXCDCCCMMM???";
+static CHAR rgchLCRoman[] = "iviiixlxxxcdcccmmm???";
+#define cchRgchDigit 5
+#endif /* CASMERE */
+
+if (flm & flmPrinting)
+ {
+
+#ifdef CASHMERE
+ switch (nfc)
+ {
+ int cch, ich, chLetter;
+ case nfcArabic:
+ if (cchMax < cchMaxNum)
+ return 0;
+ return ncvtu(pgn, &pch);
+ case nfcUCRoman:
+ return CchStuffRoman(&pch, pgn, rgchUCRoman, cchMax);
+ case nfcLCRoman:
+ return CchStuffRoman(&pch, pgn, rgchLCRoman, cchMax);
+ case nfcUCLetter:
+ case nfcLCLetter:
+ if ((cch = (pgn - 1) / 26 + 1) > cchMax)
+ return 0;
+ chLetter = (pgn - 1) % 26 + (nfc == nfcUCLetter ? 'A' : 'a');
+ for (ich = 0; ich < cch; ich++)
+ pch[ich] = chLetter;
+ return cch;
+ }
+#else /* not CASHMERE */
+ if (cchMax < cchMaxNum)
+ return 0;
+ return ncvtu(pgn, &pch);
+ }
+#endif /* not CASHMERE */
+
+else
+ {
+ int cch;
+ cch = CchChStuff(&pch, chLParen, cchMax);
+ cch += CchStuffIdstr(&pch, IDSTRChPage, cchMax - cch);
+ cch += CchChStuff(&pch, chRParen, cchMax - cch);
+ return cch;
+ }
+}
+
+
+/* C C H S T U F F I D S T R */
+int CchStuffIdstr(ppch, idstr, cchMax)
+CHAR **ppch;
+IDSTR idstr;
+int cchMax;
+{
+ int cch;
+ CHAR st[cchMaxExpand]; /* note: we assume no individual idstr
+ will have a length > cchMaxExpand */
+
+ FillStId(st, idstr, sizeof(st));
+ cch = max(0, min(cchMax, st[0]));
+ bltbyte(&st[1], *ppch, cch);
+ (*ppch) += cch;
+ return cch;
+}
+
+/* C C H C H S T U F F */
+int CchChStuff(ppch, ch, cchMax)
+CHAR **ppch;
+CHAR ch;
+int cchMax;
+{
+ if(cchMax > 0)
+ {
+ **ppch = ch;
+ (*ppch)++;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+#ifdef CASHMERE
+int CchStuffRoman(ppch, u, rgch, cchMax)
+CHAR **ppch, *rgch;
+unsigned u, cchMax;
+ {
+ static CHAR mpdgcch[10] =
+ { 0, 1, 2, 3, 2, 1, 2, 3, 4, 2 };
+ static CHAR mpdgich[10] =
+ { 0, 0, 2, 2, 0, 1, 1, 1, 1, 4 };
+ int cch, cchDone;
+
+ cchDone = 0;
+ if (u >= 10)
+ {
+ cchDone = CchStuffRoman(ppch, u / 10, rgch + cchRgchDigit, cchMax);
+ cchMax -= cchDone;
+ u %= 10;
+ }
+
+ cch = mpdgcch[u];
+ if (cch > cchMax || cch == 0)
+ return cchDone;
+ bltbyte(&rgch[mpdgich[u]], *ppch, cch);
+ *ppch += cch;
+ return cch + cchDone;
+ }
+#endif /* CASHMERE */
+
+
+int FFormatSpecials(pifi, flm, nfc)
+struct IFI *pifi;
+int flm;
+int nfc;
+{ /* A run of special characters was encountered; format it */
+/* Return true unless wordwrap required */
+int cch;
+int cchPr;
+int ich;
+int dxp;
+int dxpPr;
+int sch;
+CHAR *pchPr;
+
+while (pifi->ichFetch < vcchFetch && pifi->xpPr <= pifi->xpPrRight)
+ {
+
+#ifdef CASHMERE
+ switch (sch = vpchFetch[pifi->ichFetch++])
+ {
+ case schPage:
+ cch = CchExpPgn(&vfli.rgch[pifi->ich], vpgn, nfc, flm,
+ ichMaxLine - pifi->ich);
+ break;
+
+ case schFootnote:
+ cch = CchExpFtn(&vfli.rgch[pifi->ich], vcpFetch +
+ pifi->ichFetch - 1, flm, ichMaxLine - pifi->ich);
+ break;
+
+ default:
+ cch = CchExpUnknown(&vfli.rgch[pifi->ich], flm, ichMaxLine -
+ pifi->ich);
+ break;
+ }
+#else /* not CASHMERE */
+ pchPr = &vfli.rgch[pifi->ich];
+ if ((sch = vpchFetch[pifi->ichFetch]) == schPage &&
+ (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter || ((flm &
+ flmPrinting) && vcpFetch + (typeCP)pifi->ichFetch < cpMinDocument)))
+ {
+ cch = CchExpPgn(pchPr, vpgn, nfc, flm, ichMaxLine - pifi->ich);
+ if (flm & flmPrinting)
+ {
+ cchPr = cch;
+ }
+ else
+ {
+ /* Assume that vsepAbs has been set up by FormatLine(). */
+ cchPr = CchExpPgn(pchPr = &stBuf[0], vsepAbs.pgnStart == pgnNil
+ ? 1 : vsepAbs.pgnStart, nfc, flmPrinting, ichMaxLine -
+ pifi->ich);
+ }
+ }
+ else
+ {
+ cch = cchPr = CchExpUnknown(pchPr, flm, ichMaxLine - pifi->ich);
+ }
+ pifi->ichFetch++;
+#endif /* not CASHMERE */
+
+ dxpPr = 0;
+ for (ich = 0; ich < cchPr; ++ich, ++pchPr)
+ {
+ dxpPr += DxpFromCh(*pchPr, true);
+ }
+ pifi->xpPr += dxpPr;
+ if (flm & flmPrinting)
+ {
+ dxp = dxpPr;
+ }
+ else
+ {
+ dxp = 0;
+ for (ich = pifi->ich; ich < pifi->ich + cch; ++ich)
+ {
+ dxp += DxpFromCh(vfli.rgch[ich], false);
+ }
+ }
+ vfli.rgch[pifi->ich] = sch;
+ pifi->xp += (vfli.rgdxp[pifi->ich++] = dxp);
+
+ if (pifi->xpPr > pifi->xpPrRight)
+ {
+ return (vcpFetch == vfli.cpMin);
+ }
+ }
+
+pifi->fPrevSpace = false;
+return true;
+}
+
+
+int CchExpUnknown(pch, flm, cchMax)
+CHAR *pch;
+int flm, cchMax;
+{
+int cch;
+
+#ifdef CASHMERE
+cch = CchChStuff(&pch, chLParen, cchMax);
+cch += CchChStuff(&pch, chQMark, cchMax - cch);
+cch += CchChStuff(&pch, chRParen, cchMax - cch);
+#else /* not CASHMERE */
+cch = CchChStuff(&pch, chStar, cchMax);
+#endif /* not CASHMERE */
+
+return cch;
+}
+
+
+#ifdef CASHMERE
+int CchExpFtn(pch, cp, flm, cchMax)
+CHAR *pch;
+typeCP cp;
+int flm, cchMax;
+{
+int doc = vfli.doc;
+if (cchMax < cchMaxNum)
+ return 0;
+if (cp >= CpMacText(doc))
+ cp = CpRefFromFtn(doc, cp);
+CacheSect(doc, cp);
+return ncvtu(IfndFromCp(doc, cp) - IfndFromCp(doc, vcpFirstSectCache) + 1,
+ &pch);
+}
+#endif /* CASHMERE */
diff --git a/private/mvdm/wow16/write/globdefs.h b/private/mvdm/wow16/write/globdefs.h
new file mode 100644
index 000000000..1cbb13839
--- /dev/null
+++ b/private/mvdm/wow16/write/globdefs.h
@@ -0,0 +1,126 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* ****************************************************************************
+**
+** COPYRIGHT (C) 1985 MICROSOFT
+**
+** ****************************************************************************
+*
+* Module: globdefs.h - text for static arrays and other uses. Change this
+* module when internationalizing.
+*
+* Functions included: none
+*
+**
+** REVISIONS
+**
+** Date Who Rel Ver Remarks
+** 10/20/89 fgd Win 3.0. Some defines have been moved to write.rc
+** 07/08/86 yy addition of reverse string for unit parsing.
+** 11/20/85 bz initial version
+**
+** ***************************************************************************/
+
+/* NOTE NOTE NOTE
+Win 3.0. In order to easy the localization of Write, some string defines
+have been removed from here and placed into write.rc
+*/
+
+#define utDefault utCm /* used to set utCur - may be utInch or utCm */
+#define vzaTabDfltDef (czaInch / 2) /* width of default tab in twips */
+ /* note that czaCm is also available */
+
+
+
+#define szExtWordDocDef ".DOC"
+#define szExtWordBakDef ".BAK"
+#define szExtDrvDef ".drv"
+#define szExtGlsDef ".GLS"
+
+
+#ifdef KINTL
+#define szExtDocDef ".WRI" /* this and next extension should be the same */
+#define szExtSearchDef "\\*.WRI" /* store default search spec */
+#define szExtBackupDef ".BKP"
+#else
+#define szExtDocDef ".DOC" /* This and next extension should be the same */
+#define szExtSearchDef "\\*.DOC" /* Store default search spec. */
+#define szExtBackupDef ".BAK"
+#endif /* if-else-def INTL */
+
+
+#define szWriteProductDef "MSWrite" /* WIN.INI: our app entry */
+#define szFontEntryDef "Fontx" /* WIN.INI: our font list */
+#define szSepNameDef " - " /* Separates AppName from file name in header */
+
+#ifdef STYLES
+#define szSshtEmpty "NORMAL.STY"
+#endif /* STYLES */
+
+
+/* Strings for parsing the user profile. */
+#define szWindowsDef "windows"
+#define szDeviceDef "Device"
+#define szDevicesDef "devices"
+#define szBackupDef "Backup"
+
+ /* used to get decimal point character from user profile */
+#define szIntlDef "intl"
+#define szsDecimalDef "sDecimal"
+#define szsDecimalDefaultDef "."
+#define sziCountryDef "iCountry"
+ /* see msdos manual for meaning of codes */
+
+/* Strings for our window classes (MUST BE < 39 CHARS) */
+
+#define szParentClassDef "MSWRITE_MENU"
+#define szDocClassDef "MSWRITE_DOC"
+#define szRulerClassDef "MSWRITE_RULER"
+#define szPageInfoClassDef "MSWRITE_PAGEINFO"
+
+#ifdef ONLINEHELP
+#define szHelpDocClassDef "MSWRITE_HELPDOC"
+#endif
+
+ /* used in fileutil.c - name of temp file */
+#ifdef INTL
+#define szMWTempDef "~WRI0000.TMP"
+#else
+#define szMWTempDef "~DOC0000.TMP"
+#endif
+
+ /* used in fontenum.c */
+#define szSystemDef "System"
+
+#ifdef DBCS_VERT /* was in JAPAN, changed it to DBCS */
+// Vertical orientation systemfont facename [yutakan:08/09/91]
+#define szAtSystemDef "@System"
+#endif
+
+ /* used in initwin.c */
+
+#define szMw_acctbDef "mw_acctb"
+#define szNullPortDef "NullPort"
+#define szMwloresDef "mwlores"
+#define szMwhiresDef "mwhires"
+#define szMw_iconDef "mw_icon"
+#define szMw_menuDef "mw_menu"
+#define szScrollBarDef "ScrollBar"
+
+ /* used in pictdrag.c */
+#define szPmsCurDef "pmscur"
+
+
+ /* used in screen.c - available font family names */
+#define szModernDef "Modern"
+#define szRomanDef "Roman"
+#define szSwissDef "Swiss"
+#define szScriptDef "Script"
+#define szDecorativeDef "Decorative"
+
+ /* used in util2.c abbreviations for units */
+
+
+
diff --git a/private/mvdm/wow16/write/globdefs.itl b/private/mvdm/wow16/write/globdefs.itl
new file mode 100644
index 000000000..54b162822
--- /dev/null
+++ b/private/mvdm/wow16/write/globdefs.itl
@@ -0,0 +1,186 @@
+/* ****************************************************************************
+**
+** COPYRIGHT (C) 1985 MICROSOFT
+**
+** ****************************************************************************
+*
+* Module: globdefs.h - text for static arrays and other uses. Change this
+* module when internationalizing.
+*
+* Functions included: none
+*
+**
+** REVISIONS
+**
+** Date Who Rel Ver Remarks
+** 07/08/86 yy addition of reverse string for unit parsing.
+** 11/20/85 bz initial version
+**
+** ***************************************************************************/
+
+
+#ifdef KANJI
+#define utDefault utCch /* used to set utCur - may be utInch, utCm or utCch */
+#else
+#define utDefault utCm /* used to set utCur - may be utInch or utCm */
+#endif /* if-else-def KANJI */
+#define vzaTabDfltDef (czaInch / 2) /* width of default tab in twips */
+ /* note that czaCm is also available */
+
+
+#define szModeDef "Page 1" /* buffer for "Page nnn" message */
+
+#define szExtWordDocDef ".DOC"
+#define szExtWordBakDef ".BAK"
+#define szExtDrvDef ".drv"
+#define szExtGlsDef ".GLS"
+
+
+#ifdef KINTL
+#define szExtDocDef ".WRI" /* this and next extension should be the same */
+#define szExtSearchDef "\\*.WRI" /* store default search spec */
+#define szExtBackupDef ".BKP"
+#ifdef KANJI
+#define szExtTxtOnly ".TXT" /* Text only document. */
+#endif /* KANJI */
+#else
+#define szExtDocDef ".DOC" /* This and next extension should be the same */
+#define szExtSearchDef "\\*.DOC" /* Store default search spec. */
+#define szExtBackupDef ".BAK"
+#endif /* if-else-def INTL */
+
+
+#define szWriteProductDef "MSWrite" /* WIN.INI: our app entry */
+#define szFontEntryDef "Fontx" /* WIN.INI: our font list */
+#define szWriteDocPromptDef "Write Document" /* OpenFile prompts */
+#define szScratchFilePromptDef "Write Program"
+#define szSaveFilePromptDef "Write Save"
+#define szAppNameDef "Write" /* For message box headings */
+#define szUntitledDef "(Untitled)" /* Unnamed doc */
+#define szSepNameDef " - " /* Separates AppName from file name in header */
+
+#ifdef STYLES
+#define szSshtEmpty "NORMAL.STY"
+#endif /* STYLES */
+
+
+/* Strings for parsing the user profile. */
+#define szWindowsDef "windows"
+#define szDeviceDef "Device"
+#define szDevicesDef "devices"
+#define szBackupDef "Backup"
+
+ /* used to get decimal point character from user profile */
+#define szIntlDef "intl"
+#define szsDecimalDef "sDecimal"
+#define szsDecimalDefaultDef "."
+#define sziCountryDef "iCountry"
+#define sziCountryDefaultDef "001" /* default country is USA */
+ /* see msdos manual for meaning of codes */
+
+/* Strings for our window classes (MUST BE < 39 CHARS) */
+
+#define szParentClassDef "MSWRITE_MENU"
+#define szDocClassDef "MSWRITE_DOC"
+#define szRulerClassDef "MSWRITE_RULER"
+#define szPageInfoClassDef "MSWRITE_PAGEINFO"
+
+#ifdef ONLINEHELP
+#define szHelpDocClassDef "MSWRITE_HELPDOC"
+#endif
+
+ /* used in clipdisp.c */
+#define szWRITETextDef "WRITE Formatted Text"
+
+ /* used in cmd.c */
+#define szFreeDef " words"
+
+ /* used in diachgpr.c */
+#define szDeviceModeDef "DEVICEMODE" /* windows device mode */
+
+ /* used in fileutil.c - name of temp file */
+#ifdef INTL
+#define szMWTempDef "~WRI0000.TMP"
+#else
+#define szMWTempDef "~DOC0000.TMP"
+#endif
+
+ /* used in fontenum.c */
+#define szSystemDef "System"
+
+ /* used in initwin.c */
+
+#define szMw_acctbDef "mw_acctb"
+#define szNullPortDef "NullPort"
+#define szNoneDef "None"
+#define szMwloresDef "mwlores"
+#define szMwhiresDef "mwhires"
+#define szMw_iconDef "mw_icon"
+#define szMw_menuDef "mw_menu"
+#define szScrollBarDef "ScrollBar"
+
+ /* used in menu.c */
+#define szShEscDef " \tSh Esc"
+
+ /* used in pictdrag.c */
+#define szPmsCurDef "pmscur"
+
+ /* used in ruler.c */
+#define szBtnDef "rbutton"
+#define szMarkDef "rmark"
+
+ /* used in running.c */
+#define szHeaderDef "HEADER"
+#define szFooterDef "FOOTER"
+
+ /* used in screen.c - available font family names */
+#define szModernDef "Modern"
+#define szRomanDef "Roman"
+#define szSwissDef "Swiss"
+#define szScriptDef "Script"
+#define szDecorativeDef "Decorative"
+
+ /* used in trans.c */
+#define szLoadFileDef "Loading File..."
+#define szCvtLoadFileDef "Converting and Loading File..."
+
+ /* used in util2.c abbreviations for units */
+
+#define szInchDef "\""
+#define szCmDef " cm"
+#define szP10Def " p10"
+#define szP12Def " p12"
+#define szPointDef " pt"
+#define szLineDef " li"
+#ifdef KANJI
+#define szKanjiLineDef " \215\163"
+#define szKanjiChDef " \216\232"
+#endif /* ifdef KANJI */
+
+#ifdef KANJI
+ /* used in util2.c. Unit names spelled in reverse. */
+
+#define szUtInch "ni" /* in */
+#define szUtInchQ "\"" /* a double quote */
+#ifdef CASHMERE
+#define szUtP10 "01p" /* p10 */
+#define szUtP12 "21p" /* p12 */
+#define szUtLine "il" /* li */
+#define szUtPt "tp" /* pt */
+#endif /* CASHMERE */
+#define szUtCm "mc" /* cm */
+#define szUtCch1 "ij" /* Roma-ji spelling. */
+#define szUtCch2 "\232\216" /* Kanji "ji" */
+#define szUtCch3 "\127\203" /* katakana "ji" */
+#define szUtCch4 "\266\202" /* hiragana "ji" */
+#define szUtCch5 "\334\205\272\205" /* half-width kataknak shi followed by */
+ /* half-width daku-on. */
+#define szUtCch6 "\336\274" /* System katakana shi followed by system */
+ /* daku-on */
+#define szUtLn1 "uoyg" /* Roma-ji spelling. */
+#define szUtLn2 "\163\215" /* Kanji "gyou" */
+#define szUtLn3 "\244\202\345\202\254\202" /* hiragana "gyou" */
+#define szUtLn4 "\105\203\207\203\255\203" /* katakana "gyou" */
+#define szUtLn5 "\263\256\336\267" /* 1-byte katakana "gyou" */
+#define szUtLn6 "\261\205\254\205\334\205\265\205" /* half-width katakana "gyou" */
+#endif /* ifdef KANJI */
diff --git a/private/mvdm/wow16/write/globdefs.knj b/private/mvdm/wow16/write/globdefs.knj
new file mode 100644
index 000000000..115891e3e
--- /dev/null
+++ b/private/mvdm/wow16/write/globdefs.knj
@@ -0,0 +1,187 @@
+/* ****************************************************************************
+**
+** COPYRIGHT (C) 1985 MICROSOFT
+**
+** ****************************************************************************
+*
+* Module: globdefs.h - text for static arrays and other uses. Change this
+* module when internationalizing.
+*
+* Functions included: none
+*
+**
+** REVISIONS
+**
+** Date Who Rel Ver Remarks
+** 10/21/86 yy translation
+** 07/08/86 yy addition of reverse string for unit parsing.
+** 11/20/85 bz initial version
+**
+** ***************************************************************************/
+
+
+#ifdef KANJI
+#define utDefault utCch /* used to set utCur - may be utInch, utCm or utCch */
+#else
+#define utDefault utCm /* used to set utCur - may be utInch or utCm */
+#endif /* if-else-def KANJI */
+#define vzaTabDfltDef (czaInch / 2) /* width of default tab in twips */
+ /* note that czaCm is also available */
+
+
+#define szModeDef "ページ 1" /* buffer for "Page nnn" message */
+
+#define szExtWordDocDef ".DOC"
+#define szExtWordBakDef ".BAK"
+#define szExtDrvDef ".drv"
+#define szExtGlsDef ".GLS"
+
+
+#ifdef KINTL
+#define szExtDocDef ".WRI" /* this and next extension should be the same */
+#define szExtSearchDef "\\*.WRI" /* store default search spec */
+#define szExtBackupDef ".BKP"
+#ifdef KANJI
+#define szExtTxtOnly ".TXT" /* Text only document. */
+#endif /* KANJI */
+#else
+#define szExtDocDef ".DOC" /* This and next extension should be the same */
+#define szExtSearchDef "\\*.DOC" /* Store default search spec. */
+#define szExtBackupDef ".BAK"
+#endif /* if-else-def INTL */
+
+
+#define szWriteProductDef "MSWrite" /* WIN.INI: our app entry */
+#define szFontEntryDef "Fontx" /* WIN.INI: our font list */
+#define szWriteDocPromptDef "ライト用文書" /* OpenFile prompts */
+#define szScratchFilePromptDef "ライトのプログラム"
+#define szSaveFilePromptDef "ライトのセーブ用ディスク"
+#define szAppNameDef "ライト" /* For message box headings */
+#define szUntitledDef "(無題)" /* Unnamed doc */
+#define szSepNameDef " - " /* Separates AppName from file name in header */
+
+#ifdef STYLES
+#define szSshtEmpty "NORMAL.STY"
+#endif /* STYLES */
+
+
+/* Strings for parsing the user profile. */
+#define szWindowsDef "windows"
+#define szDeviceDef "Device"
+#define szDevicesDef "devices"
+#define szBackupDef "Backup"
+
+ /* used to get decimal point character from user profile */
+#define szIntlDef "intl"
+#define szsDecimalDef "sDecimal"
+#define szsDecimalDefaultDef "."
+#define sziCountryDef "iCountry"
+#define sziCountryDefaultDef "001" /* default country is USA */
+ /* see msdos manual for meaning of codes */
+
+/* Strings for our window classes (MUST BE < 39 CHARS) */
+
+#define szParentClassDef "MSWRITE_MENU"
+#define szDocClassDef "MSWRITE_DOC"
+#define szRulerClassDef "MSWRITE_RULER"
+#define szPageInfoClassDef "MSWRITE_PAGEINFO"
+
+#ifdef ONLINEHELP
+#define szHelpDocClassDef "MSWRITE_HELPDOC"
+#endif
+
+ /* used in clipdisp.c */
+#define szWRITETextDef "ライト書式のテキスト"
+
+ /* used in cmd.c */
+#define szFreeDef " 語"
+
+ /* used in diachgpr.c */
+#define szDeviceModeDef "DEVICEMODE" /* windows device mode */
+
+ /* used in fileutil.c - name of temp file */
+#ifdef INTL
+#define szMWTempDef "~WRI0000.TMP"
+#else
+#define szMWTempDef "~DOC0000.TMP"
+#endif
+
+ /* used in fontenum.c */
+#define szSystemDef "System"
+
+ /* used in initwin.c */
+
+#define szMw_acctbDef "mw_acctb"
+#define szNullPortDef "NullPort"
+#define szNoneDef "None"
+#define szMwloresDef "mwlores"
+#define szMwhiresDef "mwhires"
+#define szMw_iconDef "mw_icon"
+#define szMw_menuDef "mw_menu"
+#define szScrollBarDef "ScrollBar"
+
+ /* used in menu.c */
+#define szShEscDef " \tSh Esc"
+
+ /* used in pictdrag.c */
+#define szPmsCurDef "pmscur"
+
+ /* used in ruler.c */
+#define szBtnDef "rbutton"
+#define szMarkDef "rmark"
+
+ /* used in running.c */
+#define szHeaderDef "ヘッダー"
+#define szFooterDef "フッター"
+
+ /* used in screen.c - available font family names */
+#define szModernDef "Modern"
+#define szRomanDef "Roman"
+#define szSwissDef "Swiss"
+#define szScriptDef "Script"
+#define szDecorativeDef "Decorative"
+
+ /* used in trans.c */
+#define szLoadFileDef "ファイルをロード中"
+#define szCvtLoadFileDef "ファイルを変換、ロード中"
+
+ /* used in util2.c abbreviations for units */
+
+#define szInchDef "\""
+#define szCmDef " cm"
+#define szP10Def " p10"
+#define szP12Def " p12"
+#define szPointDef " pt"
+#define szLineDef " li"
+#ifdef KANJI
+#define szKanjiLineDef " \215\163"
+#define szKanjiChDef " \216\232"
+#endif /* ifdef KANJI */
+
+#ifdef KANJI
+ /* used in util2.c. Unit names spelled in reverse. */
+
+#define szUtInch "ni" /* in */
+#define szUtInchQ "\"" /* a double quote */
+#ifdef CASHMERE
+#define szUtP10 "01p" /* p10 */
+#define szUtP12 "21p" /* p12 */
+#define szUtLine "il" /* li */
+#define szUtPt "tp" /* pt */
+#endif /* CASHMERE */
+#define szUtCm "mc" /* cm */
+#define szUtCch1 "ij" /* Roma-ji spelling. */
+#define szUtCch2 "\232\216" /* Kanji "ji" */
+#define szUtCch3 "\127\203" /* katakana "ji" */
+#define szUtCch4 "\266\202" /* hiragana "ji" */
+#define szUtCch5 "\334\205\272\205" /* half-width kataknak shi followed by */
+ /* half-width daku-on. */
+#define szUtCch6 "\336\274" /* System katakana shi followed by system */
+ /* daku-on */
+#define szUtLn1 "uoyg" /* Roma-ji spelling. */
+#define szUtLn2 "\163\215" /* Kanji "gyou" */
+#define szUtLn3 "\244\202\345\202\254\202" /* hiragana "gyou" */
+#define szUtLn4 "\105\203\207\203\255\203" /* katakana "gyou" */
+#define szUtLn5 "\263\256\336\267" /* 1-byte katakana "gyou" */
+#define szUtLn6 "\261\205\254\205\334\205\265\205" /* half-width katakana "gyou" */
+#endif /* ifdef KANJI */
diff --git a/private/mvdm/wow16/write/heapdata.h b/private/mvdm/wow16/write/heapdata.h
new file mode 100644
index 000000000..79dfdddfb
--- /dev/null
+++ b/private/mvdm/wow16/write/heapdata.h
@@ -0,0 +1,65 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#ifdef OURHEAP
+/*
+ heapData.h - include file for the share data of the heap modules.
+*/
+
+extern HH *phhMac;
+extern int *pHeapFirst;
+extern FGR *rgfgr;
+extern FGR *pfgrMac;
+extern FGR *pfgrFree;
+extern HH *phhFree;
+extern int *pmemMax;
+#ifdef DEBUG
+extern int fStoreCheck, fNoShake;
+#endif
+ /* CONSTANTS */
+#define bhh (-1) /* finds hunk given hh */
+#define cfgrBlock 10
+#define ifgrInit 60 /* defines the initial number of finger
+ pointers. */
+#define cwHunkMin cwof(HH) /* minimum number of words in a hunk */
+ /* including the header (1 word) */
+#define cwReqMin (cwHunkMin - 1) /* how small a request can be */
+
+extern int cwHeapMac;
+extern unsigned cbTot, cbTotQuotient, cwHeapFree;
+#endif /* OURHEAP */
+extern int *memory;
+
+
+#define cwSaveAlloc (128) /* A buffer (vhrgbSave) of this size is */
+ /* allocated off of */
+ /* the heap in init. It is freed during */
+ /* the save operation so we have enough */
+ /* heap space to complete the save */
+ /* operation. After the save is complete, */
+ /* we try to reclaim this space so the next */
+ /* save operation will have a fighting */
+ /* chance to complete. */
+#define cwHeapMinPerWindow 50 /* We expand the vhrgbSave buffer by this */
+ /* amount every time we open a new window. */
+ /* The theory is that for every additional */
+ /* window, we can conceivable require an */
+ /* additional save operation which may eat */
+ /* up space. A save operation may require */
+ /* space for an fcb and new run table. */
+ /* On the other hand, the save operation */
+ /* reduces the size of the piece table and*/
+ /* thus frees some space. Whether this will*/
+ /* free enough space for the save operation */
+ /* is impossible to tell at the time we */
+ /* open the window.*/
+
+
+#define cwHeapSpaceMin (60) /* once heap space is below this amount,
+ the main loop will disable all menu
+ commands except save, saveas, and quit. */
+
+
+#define ibpMaxSmall (30) /* pages in rgbp if we were in a tight memory environment */
+#define ibpMaxBig (60) /* pages in rgbp if we were in a bigger memory environment */
diff --git a/private/mvdm/wow16/write/heapdefs.h b/private/mvdm/wow16/write/heapdefs.h
new file mode 100644
index 000000000..c0bc9e0ac
--- /dev/null
+++ b/private/mvdm/wow16/write/heapdefs.h
@@ -0,0 +1,108 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*
+ heapDefs.h - include file for the storage allocator.
+
+*/
+
+#if 0
+ Storage allocation
+ NULL
+ |
+ | pHeapFirst
+ | ________________
+ | |_____cw________| hh
+ | | block | *Fgr <----------------------\
+ | | of | |
+ | | words | |
+ | |_______________| |
+ phhFree---->______cw______| hh |
+ |--|------phhNext____| |
+ | |____phhPrev--------------| |
+ | | | | |
+ | | | | |
+ | | | | |
+ | | block | | |
+ | | of | | |
+ | | words | | |
+ | |_______________| | |
+ | |_____cw________| | |
+ | | . | *Fgr<---|-------------------|-\
+ | |---------------| | | |
+ | |_____cw________|<--------/ | |
+ |-----phhNext_____| | |
+ | phhPrev---------| | |
+ | | | | |
+ | | NULL | |
+ |_______________| | |
+ |___shake_word__| (if needed) <-----phhMac | |
+ rgfgr--->|_____________--|-----------------------------/ |
+ pfgrFree->|___________----|--\ |
+ |_____________--|--|----------------------------/
+ /--|--_____________|<-/
+ \->|_____________--|-->NULL
+
+
+
+ rgfgr can be indexed as an array with ifgrMac elements.
+ The finger table slots are each one word in size.
+ Putting the finger table at the high end of memory relies on the coding of
+ of the CompactHeap routine; it moves the allocated blocks to low memory.
+ The free list is threaded with addresses, NOT indexes.
+ cw for a hunk includes size of header
+ cw for a free hunk is negative the size of the hunk
+ pfgr user's pointer to finger
+ fgr pointer to hunk of whatever
+ phh pointer to hunk header
+ phhPrevs move toward the bottom of the free list
+ phhNexts move toward the top
+ phhFree should always have a phhNext of NULL (i.e. the list is just double,
+ not circular).
+ _________________
+ |______cw_______|
+ pph -----> ph ----------->| . |
+ (FGR *) (FGR) | . |
+ | . |
+ |_______________|
+
+
+ _________________
+ phh ----->|______cw_______|
+ |___phhNext_____|
+ |___phhPrev_____|
+ | . |
+ | . |
+ | . |
+ |_______________|
+
+#endif
+
+typedef int *FGR; /* definitions for finger-related stuff. */
+typedef int **PFGR;
+
+/* storage allocator related stuff */
+struct _HH
+ {
+ int cw;
+ struct _HH *phhNext;
+ struct _HH *phhPrev;
+ };
+typedef struct _HH HH;
+
+
+#ifdef OURHEAP
+ /* MACROS */
+#define CwOfPfgr(pFgr) (*(*(pFgr) + bhh))
+#define CwOfPhh(phh) ((phh)->cw)
+#ifdef DEBUG
+#define fPointsFgrTbl(pfgr) (((FGR *)(pfgr) >= rgfgr) && ((FGR *)(pfgr) < pfgrMac))
+#endif
+
+FGR *PfgrAllocate();
+FGR *PfgrCopy();
+extern ENV envMem;
+#define cwof(i) ((sizeof(i)+sizeof(int)-1)/sizeof(int))
+
+#endif /* OURHEAP */
diff --git a/private/mvdm/wow16/write/heapinit.c b/private/mvdm/wow16/write/heapinit.c
new file mode 100644
index 000000000..e22dc5e80
--- /dev/null
+++ b/private/mvdm/wow16/write/heapinit.c
@@ -0,0 +1,192 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCTLMGR
+#define NOCLIPBOARD
+#define NOMSG
+#define NOGDI
+#define NOMB
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOBRUSH
+#define NOFONT
+#define NOWNDCLASS
+#include <windows.h>
+#include "mw.h"
+
+#ifdef OURHEAP
+/*
+ heapInit.c - one routine to calculate the proper information for
+ heap management.
+*/
+
+#include "code.h"
+#include "heapDefs.h"
+#include "heapData.h"
+#include "str.h"
+#ifdef ENABLE
+#include "memDefs.h"
+#endif
+
+/* heap specific data */
+HH *phhMac; /* May change if grow heap */
+int cwHeapMac; /* " " " " " " " " */
+int *pHeapFirst; /* change if the finger table rgfgr expands */
+FGR *rgfgr; /* Declared as a pointer, but also used as an array. */
+FGR *pfgrMac; /* Initially equal to &rgfgr[ifgrInit]; */
+FGR *pfgrFree; /* Singly linked with a trailing NULL pointer. */
+HH *phhFree; /* May be NULL along the way. */
+ENV envMem;
+int fMemFailed;
+int cwInitStorage;
+
+
+
+
+FExpandFgrTbl()
+
+/* Will expand the finger table. This routines depends upon the fact
+that the CompactHeap routine moves the allocated blocks to the
+low end of memory. The new space from the finger table comes from
+the tail end of the (only) free block left after a compaction.
+The finger is expanded by at most 'cfgrNewMax' and at least 1.
+If there is no room to expand the finger table, then nothing is
+changed. To expand the table, several pointers and integers are
+decreamented to reflect the reallocation of the storage. Then
+we recalculate the memory totals so the user
+will have an acurate display of the percent free and total bytes
+available. The new fingers are linked so that the finger at the
+low end of the table is at the end of the list.
+(To expand the finger table there must be no fingers available.)
+*/
+
+{
+FGR *pfgr;
+int cfgrNew = cfgrBlock;
+register HH *phhNew;
+
+#ifdef DEBUG
+ if (pfgrFree != NULL)
+ panicH(34);
+#endif
+
+ if (!FCwInMem(cfgrNew + cwReqMin + 1))
+ {
+ /* couldn't get a block's worth - could we get one? */
+ cfgrNew = 1;
+ if (!FCwInMem(cfgrNew))
+ /* no way to help this guy */
+ return(FALSE);
+ }
+
+ phhNew = (HH *)pHeapFirst;
+ if (phhNew->cw > 0 || !FHhFound(phhNew, cfgrNew))
+ {
+ /* we tried but failed to find an adequate free
+ block at start of heap */
+ CompactHeap();
+ MoveFreeBlock(pHeapFirst);
+ }
+
+ if (!FPhhDoAssign(phhNew, cfgrNew))
+ return(FALSE);
+
+/* we have a block which is FIRST in the heap - let's steal it */
+ cfgrNew = phhNew->cw; /* in case it was more than we
+ asked for */
+ pHeapFirst = pHeapFirst + cfgrNew;
+ pfgrMac += cfgrNew;
+ cwHeapMac -= cfgrNew;
+
+/* do some initialization if pfgrFree is not NULL and you
+want the new fingers at the very end of the free finger list */
+ for (pfgr = pfgrMac - cfgrNew; pfgr < pfgrMac; pfgr++)
+ {
+ *pfgr = (FGR)pfgrFree;
+ pfgrFree = pfgr;
+ }
+
+/* do we need this anymore? (cwInitStorage = cwHeapMac - cwHeapFree)
+ cbTot = (cwHeapMac - cwInitStorage) * sizeof(int);
+ cbTotQuotient = (cbTot>>1)/100;
+*/
+ return(TRUE);
+
+} /* End of FExpandFgrTbl () */
+
+
+
+CompactHeap()
+ /* moves all allocated hunks */
+ /* toward beginning of pHeapFirst. Free hunks */
+ {
+ HH *phh, *phhSrc, *phhDest; /* are combined into one hunk */
+ FGR *pfgr;
+ int cwActual;
+
+#ifdef DEBUG
+ StoreCheck();
+#endif
+
+ /* set up for compaction by placing cw of hunk in rgfgr and an
+ index into rgfgr in the hunk */
+ for (pfgr = rgfgr; pfgr < pfgrMac; pfgr++)
+ {
+ if (FPointsHeap(*pfgr))
+ /* if rgfgr[ifgr] points to heap... */
+ {
+ phh = (HH *)(*pfgr + bhh);
+ /* find header */
+ *pfgr = (FGR)phh->cw;
+ /* coerce so it fits, force the shift */
+ phh->cw = (int)(((unsigned)pfgr - (unsigned)rgfgr)/2);
+ }
+ }
+ /* now we have cw in rgfgr and ifgr in phh */
+ phhSrc = (HH *) pHeapFirst;
+ phhDest = phhSrc;
+ while (phhSrc < phhMac)
+ {
+ if (phhSrc->cw < 0)
+ /* free hunk, don't recopy */
+ phhSrc = (HH *)((int *) phhSrc - phhSrc->cw);
+ else
+ {
+ pfgr = &rgfgr[phhSrc->cw];
+ /* find h */
+ cwActual = phhSrc->cw = (int) *pfgr;
+ /* restore cw */
+ *pfgr = ((FGR) phhDest - bhh);
+ /* update ha */
+ blt((int *)phhSrc, (int *)phhDest, (unsigned)cwActual);
+ /* unless ptrs are = */
+ phhDest = (HH *) ((int *) phhDest + cwActual);
+ phhSrc = (HH *) ((int *) phhSrc + cwActual);
+ }
+ }
+
+#ifdef DEBUG
+ if ((int *)phhDest + cwHeapFree - cwHunkMin >= (int *)phhMac)
+ panicH(35);
+#endif
+ phhFree = phhDest;
+ phhFree->cw = -cwHeapFree;
+ phhFree->phhNext = phhFree->phhPrev = phhFree;
+#ifdef DEBUG
+ StoreCheck();
+#endif
+ }
+
+#endif /* NOT WINHEAP */
diff --git a/private/mvdm/wow16/write/heapmain.c b/private/mvdm/wow16/write/heapmain.c
new file mode 100644
index 000000000..e11851c2e
--- /dev/null
+++ b/private/mvdm/wow16/write/heapmain.c
@@ -0,0 +1,153 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCTLMGR
+#define NOCLIPBOARD
+#define NOMSG
+#define NOGDI
+#define NOMB
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOBRUSH
+#define NOFONT
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+/*
+ HeapManage.c - several routines to manage the heap, including changing
+ the finger table, compacting the heap in general, and checking the
+ heap for consistency.
+ It also contains the routines which were once in heapNew.
+*/
+#include "code.h"
+#include "heapDefs.h"
+#include "heapData.h"
+#define NOSTRUNDO
+#define NOSTRMERGE
+#include "str.h"
+#include "macro.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "docdefs.h"
+
+
+extern CHAR (*rgbp)[cbSector];
+extern CHAR *rgibpHash;
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern int iibpHashMax;
+extern int cwInitStorage;
+extern typeTS tsMruBps;
+
+
+FTryGrow(unsigned);
+
+
+PFGR HAllocate(cwRequest)
+unsigned cwRequest;
+{
+unsigned cb = cwRequest * sizeof(int);
+HANDLE hTemp;
+
+ Assert(*(pLocalHeap+1) == 0);
+
+ if (cwRequest >= 0x8000)
+ {
+#ifdef DEBUG
+ Assert(0);
+ ErrorWithMsg(IDPMTRottenFile, " heapMan#1");
+#else
+ Error(IDPMTRottenFile);
+#endif
+ return((PFGR)hOverflow);
+ }
+
+ hTemp = LocalAlloc(LHND, cb);
+ if (hTemp != NULL)
+ return((PFGR)hTemp);
+ else if (FTryGrow(cb))
+ {
+ return((PFGR)LocalAlloc(LHND, cb));
+ }
+ else
+ {
+#ifdef DEBUG
+ ErrorWithMsg(IDPMTNoMemory, " heapMan#1");
+#else
+ Error(IDPMTNoMemory);
+#endif
+ return((PFGR)hOverflow);
+ }
+}
+
+FChngSizeH(pfgrChng, cwRequest, fShrink)
+PFGR pfgrChng;
+int cwRequest, fShrink;
+{
+unsigned cb = cwRequest * sizeof(int);
+#ifdef DEBUG
+PFGR pfgrNew;
+#endif
+
+ Assert(*(pLocalHeap+1) == 0); /* Check for frozen heap */
+ Assert(cwRequest >= 0);
+
+ if ((
+#ifdef DEBUG
+ pfgrNew =
+#endif
+ (PFGR)LocalReAlloc( (HANDLE)pfgrChng, cb, LHND)) != NULL)
+ {
+ Assert( pfgrNew == pfgrChng ); /* Windows guarantees this for
+ movable objects */
+ return( TRUE );
+ }
+ else if (FTryGrow(cb))
+ {
+#ifdef DEBUG
+ pfgrNew =
+#endif
+ (PFGR)LocalReAlloc( (HANDLE)pfgrChng, cb, LHND);
+ Assert( pfgrNew != (PFGR)NULL );
+ Assert( pfgrNew == pfgrChng );
+ return( TRUE );
+ }
+ else
+ {
+#ifdef DEBUG
+ ErrorWithMsg( IDPMTNoMemory, " heapMan#2" );
+#else
+ Error( IDPMTNoMemory );
+#endif
+ return( FALSE );
+ }
+}
+
+
+
+CHAR (**HszCreate(sz))[]
+CHAR sz[];
+{ /* Creates a heap block containing sz */
+CHAR (**hsz)[];
+int cch = CchSz(sz);
+hsz = (CHAR (**)[]) HAllocate(CwFromCch(cch));
+if (FNoHeap(hsz))
+ return (CHAR (**)[])hOverflow;
+bltbyte(sz, **hsz, cch);
+return hsz;
+}
+
diff --git a/private/mvdm/wow16/write/heaprare.c b/private/mvdm/wow16/write/heaprare.c
new file mode 100644
index 000000000..f52ff5e94
--- /dev/null
+++ b/private/mvdm/wow16/write/heaprare.c
@@ -0,0 +1,266 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCTLMGR
+#define NOCLIPBOARD
+#define NOMSG
+#define NOGDI
+#define NOMB
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOBRUSH
+#define NOFONT
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+/*
+ HeapManage.c - several routines to manage the heap, including changing
+ the finger table, compacting the heap in general, and checking the
+ heap for consistency.
+ It also contains the routines which were once in heapNew.
+*/
+#include "code.h"
+#include "heapDefs.h"
+#include "heapData.h"
+#define NOSTRUNDO
+#define NOSTRMERGE
+#include "str.h"
+#include "macro.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "docdefs.h"
+
+#ifdef DEBUG
+int cPageMinReq = 15;
+#else
+#define cPageMinReq (15)
+#endif
+
+
+/* the following statics are used when growing both heap and rgbp etc. */
+static int cwRealRequest; /* heap is grow in blocks, this is the actual request */
+static int cPageIncr; /* count of page buffers to increase */
+static int cwRgbpIncr; /* cw in rgbp to be increment */
+static int cwHashIncr; /* cw in rgibpHash to be increment */
+static int cwBPSIncr; /* cw in mpibpbps to be increment */
+static int cwHeapIncr; /* cw in heap increment */
+
+
+extern CHAR (*rgbp)[cbSector];
+extern CHAR *rgibpHash;
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern int iibpHashMax;
+extern int cwInitStorage;
+extern typeTS tsMruBps;
+
+NEAR FGiveupFreeBps(unsigned, int *);
+NEAR FThrowPages(int);
+NEAR GivePages(int);
+NEAR CompressRgbp();
+
+FTryGrow(cb)
+unsigned cb;
+{
+int cPage;
+
+#define cPageRemain (int)(ibpMax - cPage)
+
+ if (FGiveupFreeBps(cb, &cPage) &&
+ (cPageRemain >= cPageMinReq))
+ {
+ /* we have enough free pages to give */
+ GivePages(cPage);
+ }
+ else if ((cPageRemain >= cPageMinReq) && FThrowPages(cPage))
+ {
+ GivePages(cPage);
+ }
+ else
+ {
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+NEAR FGiveupFreeBps(cb, pCPage)
+unsigned cb;
+int *pCPage;
+{
+/* Return true if we can simply give up certain free pages from rgbp to
+ the heap. Return false if all free pages from rgbp still cannot satisfy
+ the request
+ In any case, pCPage contains the count of pages required */
+
+register struct BPS *pbps;
+register int cPage = 0;
+int ibp;
+
+#define cbTotalFreed ((cPage*cbSector)+(2*cPage*sizeof(CHAR))+(cPage*sizeof(struct BPS)))
+
+ for (ibp = 0, pbps = &mpibpbps[0]; ibp < ibpMax; ibp++, pbps++)
+ {
+ if (pbps->fn == fnNil)
+ cPage++;
+ }
+
+ if (cb > cbTotalFreed )
+ {
+ /* free pages are not enough, find out exactly how many
+ pages do we need */
+ cPage++;
+ while (cb > cbTotalFreed)
+ cPage++;
+ *pCPage = cPage;
+ return(FALSE);
+ }
+
+/* there are enough free pages to give, find out exactly how many */
+ while (cb <= cbTotalFreed)
+ cPage--;
+ cPage++;
+ *pCPage = cPage;
+ return(TRUE);
+} /* end of FGiveupFreeBps */
+
+
+NEAR FThrowPages(cPage)
+int cPage;
+{
+int i;
+register struct BPS *pbps;
+
+ Assert(cPage > 0);
+
+ for (i = 0; i < cPage; i++)
+ {
+ pbps = &mpibpbps[IbpLru(0)];
+ if (pbps->fn != fnNil)
+ {
+ if (pbps->fDirty && !FFlushFn(pbps->fn))
+ return(FALSE);
+
+ /* delete references to old bps in hash table */
+ FreeBufferPage(pbps->fn, pbps->pn);
+ }
+ pbps->ts = ++tsMruBps; /* so that it would not be picked up again as the LRUsed */
+ }
+ return(TRUE);
+} /* end of FThrowPages */
+
+
+NEAR GivePages(cPage)
+int cPage;
+{
+register struct BPS *pbpsCur = &mpibpbps[0];
+struct BPS *pbpsUsable = pbpsCur;
+int ibp;
+unsigned cbBps;
+unsigned cbRgbp;
+unsigned cbTotalNew;
+
+ for (ibp = 0; ibp < ibpMax; pbpsCur++, ibp++)
+ {
+/* compressed so that non empty bps are at the low end,
+store ibp in ibpHashNext field (this is important for
+CompressRgbp relies on that), since ibpHashNext is invalid
+after the compress anyway */
+ if (pbpsCur->fn != fnNil)
+ {
+ if (pbpsCur != pbpsUsable)
+ {
+ bltbyte((CHAR *)pbpsCur, (CHAR *)pbpsUsable,
+ sizeof(struct BPS));
+ /* reinitialized */
+ SetBytes((CHAR*)pbpsCur, 0, sizeof(struct BPS));
+ pbpsCur->fn = fnNil;
+ pbpsCur->ibpHashNext = ibpNil;
+ }
+ pbpsUsable->ibpHashNext = ibp;
+ pbpsUsable++;
+ }
+ } /* end of for */
+
+ /* compressed rgbp, result -- all used pages at the low end */
+ CompressRgbp();
+
+ /* decrease the size of the hash table */
+ ibpMax -= cPage;
+ iibpHashMax = ibpMax * 2 + 1;
+ cbRgbp = ibpMax * cbSector;
+
+ rgibpHash = (CHAR *)((unsigned)rgbp + cbRgbp);
+ /* contents of rgibpHash should be all ibpNil, that is
+ taken care in RehashRgibpHash */
+
+ cbBps = (ibpMax * sizeof(struct BPS) + 1) & ~1;
+ bltbyte((CHAR *)mpibpbps, (CHAR *)(mpibpbps = (struct BPS *)
+ (((unsigned)rgibpHash + iibpHashMax + 1) & ~1)), cbBps);
+
+ RehashRgibpHash();
+
+ cbTotalNew = cbRgbp + cbBps + ((iibpHashMax + 1) & ~1);
+
+ LocalReAlloc((HANDLE)rgbp, cbTotalNew, LPTR);
+
+ Assert(rgbp != NULL);
+
+} /* end of GivePages */
+
+
+NEAR CompressRgbp()
+{
+/* compressed so that all non empty pages are moved towards the low end of
+ rgbp */
+
+register struct BPS *pbps = &mpibpbps[0];
+struct BPS *pbpsLim = &mpibpbps[ibpMax];
+int ibp;
+
+ for (ibp = 0; pbps < pbpsLim; ibp++, pbps++)
+ {
+ if (pbps->fn == fnNil)
+ continue;
+ if (pbps->ibpHashNext != ibp)
+ {
+ /* find out the location of pages (stored in ibpHashNext field) */
+ bltbyte((CHAR *)rgbp[pbps->ibpHashNext], (CHAR *)rgbp[ibp], cbSector);
+ }
+ pbps->ibpHashNext = ibpNil;
+ }
+} /* end of CompressRgbp */
+
+
+#ifdef DEBUG
+cPageUnused()
+{
+int ibp;
+struct BPS *pbps;
+int cPage = 0;
+
+ for (ibp = 0, pbps = &mpibpbps[0]; ibp < ibpMax; ibp++, pbps++)
+ {
+ if (pbps->fn == fnNil)
+ cPage++;
+ }
+ return(cPage);
+}
+#endif
+
+
diff --git a/private/mvdm/wow16/write/help.c b/private/mvdm/wow16/write/help.c
new file mode 100644
index 000000000..b4e973d07
--- /dev/null
+++ b/private/mvdm/wow16/write/help.c
@@ -0,0 +1,885 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* help.c -- MEMO Help handler */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCOMM
+#define NOSOUND
+#define NOMINMAX
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "stdlib.h"
+#include "docdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "dispdefs.h"
+#include "fmtdefs.h"
+#include "bitmaps.h"
+
+#define NOIDISAVEPRINT
+#define NOIDIFORMATS
+#include "dlgdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#define NOSTRMERGE
+#define NOSTRUNDO
+#include "str.h"
+
+extern HWND vhWndMsgBoxParent;
+extern struct WWD rgwwd[];
+extern struct DOD (**hpdocdod)[];
+extern int vcchFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern typeCP vcpLimParaCache;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+extern struct FLI vfli;
+
+int docHelp=docNil; /* this can be taken out if no online help */
+
+#ifndef ONLINEHELP
+#if 0
+BOOL far PASCAL DialogHelp( hDlg, code, wParam, lParam )
+HWND hDlg;
+unsigned code;
+WORD wParam;
+LONG lParam;
+{
+ switch(code)
+ {
+ case WM_INITDIALOG:
+ EnableOtherModeless(FALSE);
+ return(TRUE);
+
+#if WINVER >= 0x300
+ case WM_PAINT:
+ if (vfli.rgdxp[1] == 0xFFFD)
+ FnSpecial(hDlg);
+ break;
+#endif
+
+ case WM_COMMAND:
+ if ((wParam == idiOk) || (wParam == idiCancel))
+ {
+ OurEndDialog(hDlg, TRUE);
+#if WINVER >= 0x300
+ if (vfli.rgdxp[1] == 0xFFFD)
+ vfli.rgdxp[1] = NULL;
+#endif
+ return(TRUE);
+ }
+ break;
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ }
+ return(FALSE);
+}
+
+FnSpecial(hDlg)
+{
+#define randTo(x) (rand() / (32767/x))
+
+ HDC hDC = NULL;
+ HDC hMDC = NULL;
+ HFONT hFont, hFontPrev;
+ int c, cmode;
+ int x, y, x2, y2, s;
+ HPEN hPen, hPenPrev;
+ PAINTSTRUCT ps;
+ RECT rc;
+ BITMAPINFO DIBInfo;
+
+ srand((int) GetMessageTime());
+ cmode = randTo(3);
+ GetClientRect(hDlg, &rc);
+ if ((hDC = BeginPaint(hDlg, &ps)) == NULL)
+ goto LDone;
+ if ((hMDC = CreateCompatibleDC(hDC)) == NULL)
+ goto LDone;
+
+ for (c = 1; c < 100; c++)
+ {
+ int r, g, b, x, y;
+ x = randTo(rc.right)+50;
+ y = randTo(rc.bottom)+50;
+ switch(cmode)
+ {
+ case 0:
+ r = randTo(255);
+ g = randTo(100)+100;
+ b = 0;
+ break;
+ case 1:
+ g = randTo(255);
+ b = randTo(100)+100;
+ r = 0;
+ break;
+ default:
+ b = randTo(255);
+ r = randTo(100)+100;
+ g = 0;
+ break;
+ }
+
+ s = 3 + 4*randTo(10);
+ if ((hPen = CreatePen(PS_SOLID, s, RGB(r,g,b))) == NULL)
+ hPen = GetStockObject(BLACK_PEN);
+ hPenPrev = SelectObject(hDC, hPen);
+ Ellipse(hDC, x-50, y-50, x-50+s, y-50+s);
+ SelectObject(hDC, hPenPrev);
+ DeleteObject(hPen);
+ }
+ SetTextColor(hDC, RGB(255,255,255));
+ switch (cmode)
+ {
+ case 0:
+ SetBkColor(hDC, RGB(255,0,0));
+ break;
+ case 1:
+ SetBkColor(hDC, RGB(0,255,0));
+ break;
+ default:
+ SetBkColor(hDC, RGB(0,0,255));
+ break;
+ }
+ hFont = GetStockObject(ANSI_VAR_FONT);
+ hFontPrev = SelectObject(hDC, hFont);
+ if (vfli.rgch[2] == 0x30)
+ for (c = vfli.rgch[1]-1; c >= 0; c--)
+ vfli.rgch[c+2] -= 0x10;
+ TextOut(hDC, 6, rc.bottom-15, &vfli.rgch[2], vfli.rgch[1]);
+ SelectObject(hDC, hFontPrev);
+
+ DeleteDC(hMDC);
+LDone:
+ EndPaint(hDlg, &ps);
+}
+#endif
+
+#else /* ONLINE HELP */
+
+#define cchMaxTopicName 80
+
+#ifndef DEBUG
+#define STATIC static
+#else
+#define STATIC
+#endif
+
+STATIC int fnHelpFile;
+STATIC int iTopicChoice=-1;
+STATIC int cTopic;
+STATIC struct PGTB **hpgtbHelp=0;
+STATIC HWND hwndHelpDoc;
+
+
+NEAR CleanUpHelpPopUp( void );
+NEAR CloseHelpDoc( void );
+NEAR FOpenHelpDoc( void );
+NEAR MoveHelpCtl( HWND, int, int, int, int, int );
+
+fnHelp()
+{
+extern HANDLE hMmwModInstance;
+extern HWND hParentWw;
+extern FARPROC lpDialogHelp;
+extern FARPROC lpDialogHelpInner;
+int idi;
+
+Assert( hpgtbHelp == 0 );
+
+/* Loop until the user exits the "Help on this topic/Return to Topics" loop */
+
+ClearInsertLine(); /* Because we use MdocSize, which sets vfInsertOn */
+
+if (!FOpenHelpDoc())
+ {
+ CloseHelpDoc();
+ Error( IDPMTNoHelpFile );
+ return;
+ }
+while (TRUE)
+ {
+
+ idi = DialogBox( hMmwModInstance, MAKEINTRESOURCE(dlgHelp), hParentWw,
+ lpDialogHelp );
+ if (idi == -1)
+ {
+ Error(IDPMTNoMemory);
+ return;
+ }
+
+ if ((idi == idiOk) && (iTopicChoice >= 0))
+ { /* Help file was read OK & user chose a topic */
+ Assert( hpgtbHelp != 0);
+ if ( iTopicChoice + 1 < (**hpgtbHelp).cpgd )
+ {
+ idi = DialogBox( hMmwModInstance, MAKEINTRESOURCE(dlgHelpInner),
+ hParentWw, lpDialogHelpInner );
+ if (idi == -1)
+ {
+ Error(IDPMTNoMemory);
+ break;
+ }
+ if ( idi != idiHelpTopics )
+ break;
+
+ }
+ /* Not Enough Topics supplied in the help file */
+ else
+ {
+ Error( IDPMTNoHelpFile );
+ CloseHelpDoc();
+ break;
+ }
+ }
+ else
+ break;
+ }
+iTopicChoice = -1;
+DrawInsertLine();
+CloseHelpDoc();
+}
+
+
+
+
+FInzHelpPopUp( hDlg )
+HWND hDlg;
+{ /* Build the Help popup Window */
+extern CHAR szHelpDocClass[];
+extern HANDLE hMmwModInstance;
+extern int dxpScrlBar;
+
+typedef struct { int yp, dyp; } VD; /* Vertical Dimension */
+typedef struct { int xp, dxp; } HD; /* Horizontal Dimension */
+
+ HD hdUsable;
+ HD hdPopUp;
+ VD vdPopUp, vdTopic, vdHelpDoc, vdButton;
+
+ HDC hdcPopUp=NULL;
+
+#define RectToHdVd( rc, hd, vd ) (hd.dxp=(rc.right - (hd.xp=rc.left)), \
+ vd.dyp=(rc.bottom - (vd.yp=rc.top)))
+ RECT rcPopUp;
+ RECT rcHelpDoc;
+ extern int dypMax; /* Screen Size */
+ int dxpMax=GetDeviceCaps( wwdCurrentDoc.hDC, HORZRES );
+ TEXTMETRIC tm;
+ unsigned dypChar;
+ unsigned xpButton;
+ unsigned dxpButton;
+ register struct WWD *pwwdHelp;
+
+#define cButton 4 /* # of buttons across the bottom of the Dialog */
+ int rgidiButton[ cButton ];
+ int iidiButton;
+
+ rgidiButton [0] = idiHelpTopics;
+ rgidiButton [1] = idiHelpNext;
+ rgidiButton [2] = idiHelpPrev;
+ rgidiButton [3] = idiCancel;
+
+#define dxpMargin (dxpMax/100)
+#define dypMargin (dypMax/100)
+
+ Assert( docHelp != docNil );
+
+ /* Make a wwd entry for the Help document & initialize it */
+ if ((wwHelp=WwAlloc( (HWND)NULL, docHelp )) == wwNil)
+ goto ErrRet;
+ pwwdHelp = &rgwwd[ wwHelp ];
+
+ SetHelpTopic( hDlg, iTopicChoice );
+
+ /* Dialog box is centered and
+ 2/3 of the size of the screen, plus the scroll bar width
+ This sizing method permits us to guarantee that the help document
+ display area width is at least some fixed percentage of the width
+ of the screen (currently 64.66 %) */
+ hdPopUp.dxp = ((dxpMax * 2) / 3) + dxpScrlBar;
+ hdPopUp.xp = (dxpMax - hdPopUp.dxp) / 2;
+ vdPopUp.dyp = dypMax - ((vdPopUp.yp = dypMax / 6) * 2);
+ MoveWindow( hDlg, hdPopUp.xp, vdPopUp.yp, hdPopUp.dxp, vdPopUp.dyp, TRUE );
+
+ /* Get Standard text height so we know how much space to allow
+ for Topic Name */
+ if ( ((hdcPopUp=GetDC( hDlg ))==NULL) ||
+ (SelectObject( hdcPopUp, GetStockObject( ANSI_FIXED_FONT ) )==0))
+ goto ErrRet;
+ GetTextMetrics( hdcPopUp, (LPTEXTMETRIC)&tm );
+ ReleaseDC( hDlg, hdcPopUp );
+ hdcPopUp = NULL;
+ dypChar = tm.tmHeight + tm.tmExternalLeading;
+
+ /* Obtain heights of button area, help doc display, and Topic Area by
+ splitting up Dialog Box client rect */
+ GetClientRect( hDlg, &rcPopUp );
+ RectToHdVd( rcPopUp, hdPopUp, vdPopUp );
+ vdButton.dyp = vdPopUp.dyp / 7;
+ vdButton.yp = vdPopUp.yp + vdPopUp.dyp - vdButton.dyp;
+ vdTopic.yp = vdPopUp.yp + dypMargin;
+ vdTopic.dyp = dypMargin + dypChar;
+ vdHelpDoc.yp = vdTopic.yp + vdTopic.dyp;
+ vdHelpDoc.dyp = vdButton.yp - vdHelpDoc.yp;
+ Assert( vdHelpDoc.dyp > dypChar + 2 );
+
+ /* Obtain usable horiz area within dialog box */
+ hdUsable.xp = hdPopUp.xp + dxpMargin;
+ hdUsable.dxp = hdPopUp.dxp - (2 * dxpMargin);
+
+ /* Create the Help Doc Window */
+ if ((hwndHelpDoc =
+ CreateWindow( (LPSTR)szHelpDocClass, (LPSTR) "",
+ WS_CHILD | WS_BORDER,
+ hdUsable.xp, vdHelpDoc.yp,
+ hdUsable.dxp - dxpScrlBar, vdHelpDoc.dyp,
+ hDlg, /* PARENT */
+ NULL, /* Help Document Window ID */
+ hMmwModInstance,
+ (LONG) 0)) == NULL)
+ /* Error Creating Help Document Window */
+ goto ErrRet;
+ pwwdHelp->wwptr = pwwdHelp->hHScrBar = hwndHelpDoc;
+
+ /* OK to GetDc and hang onto it since Help doc window class has ownDC */
+ if ((pwwdHelp->hDC = GetDC( hwndHelpDoc ))==NULL)
+ goto ErrRet;
+
+ /* Set up scroll bar control window */
+ SetScrollRange( pwwdHelp->hVScrBar = GetDlgItem( hDlg, idiHelpScroll ),
+ pwwdHelp->sbVbar = SB_CTL,
+ 0, drMax-1, FALSE );
+ SetScrollPos( pwwdHelp->hVScrBar, SB_CTL, 0, FALSE );
+ MoveHelpCtl( hDlg, idiHelpScroll,
+ hdUsable.xp + hdUsable.dxp - dxpScrlBar, vdHelpDoc.yp,
+ dxpScrlBar, vdHelpDoc.dyp );
+
+ /* Move Button windows into place */
+ xpButton = hdUsable.xp;
+ dxpButton = (hdUsable.dxp - (dxpMargin*(cButton-1))) / cButton;
+ vdButton.yp += dypMargin;
+ vdButton.dyp -= (2 * dypMargin);
+ for ( iidiButton = 0; iidiButton < cButton; iidiButton++ )
+ {
+ MoveHelpCtl( hDlg, rgidiButton[ iidiButton ],
+ xpButton, vdButton.yp, dxpButton, vdButton.dyp );
+ xpButton += dxpButton + dxpMargin;
+ }
+
+ /* Move static text window into place */
+ MoveHelpCtl( hDlg, idiHelpName, hdUsable.xp, vdTopic.yp,
+ hdUsable.dxp, vdTopic.dyp );
+
+ /* The "real, final" size of the help doc window goes in rgwwd */
+ GetClientRect( hwndHelpDoc, (LPRECT) &rcHelpDoc );
+ pwwdHelp->xpMin = rcHelpDoc.left;
+ pwwdHelp->ypMin = rcHelpDoc.top;
+ pwwdHelp->xpMac = rcHelpDoc.right;
+ pwwdHelp->ypMac = rcHelpDoc.bottom;
+
+ /* Finally, we display the whole dialog box */
+ ShowWindow( hDlg, SHOW_OPENWINDOW );
+ ShowWindow( hwndHelpDoc, SHOW_OPENWINDOW );
+ return TRUE;
+
+ErrRet:
+ if (hdcPopUp != NULL)
+ ReleaseDC( hDlg, hdcPopUp );
+ CleanUpHelpPopUp();
+ CloseHelpDoc();
+
+ return FALSE;
+}
+
+
+
+
+NEAR MoveHelpCtl( hDlg, id, left, top, right, bottom )
+HWND hDlg;
+int id;
+int left, top, right, bottom;
+{
+ MoveWindow( (HWND) GetDlgItem( hDlg, id ), left, top, right, bottom, TRUE );
+}
+
+
+
+
+SetHelpTopic( hDlg, iTopic )
+HWND hDlg;
+int iTopic;
+{ /* Inz wwHelp entry in rgwwd for pending display of topic iTopic,
+ which means "printed page" iTopic, the way we handle help files.
+ We map iTopic==0 to "printed page 2", iTopic 1 to 3, etc.
+ This skips the first printed page, which is the list of topics.
+ Set the topic name of iTopic as the text for the idiHelpName
+ static text control in the hDlg dialog box */
+
+ extern typeCP cpMinCur, cpMacCur;
+ extern struct SEL selCur;
+ extern int wwCur;
+
+ int ipgd = iTopic + 1;
+ register struct WWD *pwwd=&rgwwd[ wwHelp ];
+ typeCP cpFirstTopic = (**hpgtbHelp).rgpgd [ ipgd ].cpMin;
+ typeCP cpLimTopic = (ipgd == (**hpgtbHelp).cpgd - 1) ?
+ CpMacText( docHelp ) :
+ (**hpgtbHelp).rgpgd [ ipgd + 1 ].cpMin;
+ typeCP cp;
+ int iTopicT;
+ typeCP cpLimParaCache;
+ RECT rc;
+
+ Assert( wwHelp != wwNil && docHelp != docNil );
+
+ cpLimTopic--; /* Ignore end-of-page char at the end of each page */
+
+ if (ipgd >= (**hpgtbHelp).cpgd)
+ {
+ Assert( FALSE );
+
+ pwwd->cpMin = pwwd->cpMac = cp0;
+ }
+ else
+ {
+ pwwd->cpMin = cpFirstTopic;
+ pwwd->cpMac = cpLimTopic;
+ }
+ pwwd->cpFirst = pwwd->cpMin;
+ /* So no selection shows */
+ pwwd->sel.cpFirst = pwwd->sel.cpLim = cpLimTopic + 1;
+
+ if (wwCur == wwHelp)
+ {
+ cpMinCur = pwwd->cpMin;
+ cpMacCur = pwwd->cpMac;
+ selCur = pwwd->sel;
+ }
+
+ TrashCache();
+ TrashWw( wwHelp );
+ GetClientRect( pwwd->wwptr, (LPRECT) &rc );
+ InvalidateRect( pwwd->wwptr, (LPRECT) &rc, TRUE );
+
+ /* Set Help Topic name into dialog box */
+
+ for ( iTopicT = 0, cp = (**hpgtbHelp).rgpgd [0].cpMin;
+ cp < (**hpgtbHelp).rgpgd [1].cpMin;
+ cp = cpLimParaCache, iTopicT++ )
+ {
+ int cch;
+ int cchTopicMac;
+ CHAR rgchTopic[ cchMaxTopicName ];
+
+ CachePara( docHelp, cp );
+ cpLimParaCache = vcpLimParaCache;
+
+ if (iTopicT == iTopic)
+ { /* Found the topic we want */
+ cchTopicMac = imin( (int)(vcpLimParaCache - cp) - ccpEol,
+ cchMaxTopicName );
+
+ /* Build up a topic name string */
+
+ cch = 0;
+ while (cch < cchTopicMac)
+ {
+ int cchT;
+
+ FetchCp( docHelp, cp, 0, fcmChars );
+ cp += vccpFetch;
+ cchT = imin( vcchFetch, cchTopicMac - cch );
+ Assert( cchT > 0);
+ bltbyte( vpchFetch, rgchTopic + cch, cchT );
+ cch += cchT;
+ }
+ if ((cch == 0) || rgchTopic [0] == chSect)
+ /* End of Topics */
+ break;
+
+ rgchTopic[ cch ] = '\0';
+
+ SetDlgItemText( hDlg, idiHelpName, (LPSTR) rgchTopic );
+ return;
+ } /* end if */
+ } /* end for */
+ /* Not enough topic names */
+ Assert( FALSE );
+}
+
+
+
+
+NEAR CleanUpHelpPopUp()
+{
+extern int wwCur;
+
+ if (wwCur != wwDocument)
+ NewCurWw( wwDocument, TRUE );
+
+ if (wwHelp != wwNil)
+ FreeWw( wwHelp );
+ }
+
+
+
+
+NEAR CloseHelpDoc()
+{
+ if (docHelp != docNil)
+ KillDoc( docHelp );
+
+ if (hpgtbHelp != 0)
+ {
+ FreeH( hpgtbHelp );
+ hpgtbHelp = 0;
+ }
+
+ if (fnHelpFile != fnNil)
+ FreeFn( fnHelpFile );
+ docHelp = docNil;
+ fnHelpFile = fnNil;
+}
+
+
+NEAR FOpenHelpDoc()
+{
+ CHAR szHelpFile[ cchMaxFile ];
+ CHAR (**hszHelpFile)[];
+
+ /* This call to fnOpenSz is the one time that we don't normalize
+ a filename before calling FnOpenSz. The reason for this is
+ that OpenFile (called in RfnAccess) will only search the path
+ if the filename passed to it has no path. We also get a side
+ benefit: if the sneaky user has WRITE.HLP open as a document,
+ it will get a different fn from FnOpenSz because the strings
+ will not match. */
+
+return ( PchFillPchId( szHelpFile, IDSTRHELPF ) &&
+ ((fnHelpFile=FnOpenSz( szHelpFile, dtyHlp, TRUE ))!=fnNil) &&
+ !FNoHeap(hszHelpFile=HszCreate( szHelpFile )) &&
+ ((docHelp=DocCreate( fnHelpFile, hszHelpFile, dtyHlp )) != docNil) &&
+ (**hpdocdod)[ docHelp ].fFormatted);
+}
+
+/* Window Proc for Help document child window */
+
+long FAR PASCAL HelpDocWndProc( hwnd, message, wParam, lParam )
+HWND hwnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+extern struct WWD *pwwdCur;
+extern int wwCur;
+
+ PAINTSTRUCT ps;
+
+ switch (message)
+ {
+ case WM_SIZE:
+ /* Window's size is changing. lParam contains the width
+ ** and height, in the low and high words, respectively.
+ ** wParam contains SIZENORMAL for "normal" size changes,
+ ** SIZEICONIC when the window is being made iconic, and
+ ** SIZEFULLSCREEN when the window is being made full screen. */
+ Assert( wParam == SIZENORMAL || wParam == SIZEFULLSCREEN );
+ if (lParam)
+ { /* Not a NULL size request */
+ rgwwd[ wwHelp ].xpMac = LOWORD( lParam );
+ rgwwd[ wwHelp ].ypMac = HIWORD( lParam );
+ }
+ break;
+
+ case WM_PAINT:
+ /* Time for the window to draw itself. */
+ {
+ RECT rcSave;
+
+ /* To allow UpdateWw to refresh ALL parts of the screen it */
+ /* deems necessary, not just what Windows is telling us to */
+ /* paint, we invoke it AFTER the call to EndPaint so that */
+ /* the Vis region is not restricted. The only reason we call */
+ /* BeginPaint/EndPaint is to get the repaint rectangle */
+ BeginPaint(hwnd, (LPPAINTSTRUCT)&ps);
+ bltbyte( &ps.rcPaint, &rcSave, sizeof( RECT ) );
+ EndPaint(hwnd, (LPPAINTSTRUCT)&ps);
+ NewCurWw( wwHelp, TRUE );
+ InvalBand( pwwdCur, rcSave.top, rcSave.bottom );
+ UpdateWw( wwCur, FALSE );
+ NewCurWw( wwDocument, TRUE );
+ break;
+ }
+
+ default:
+
+ /* Everything else comes here. This call MUST exist
+ ** in your window proc. */
+
+ return(DefWindowProc(hwnd, message, wParam, lParam));
+ break;
+ }
+
+ /* A window proc should always return something */
+ return(0L);
+}
+
+
+/* Dialog Box function for Inner Help box (shows the topic text) */
+
+BOOL far PASCAL DialogHelpInner( hDlg, code, wParam, lParam )
+HWND hDlg;
+unsigned code;
+WORD wParam;
+LONG lParam;
+{
+extern int wwCur;
+
+ switch (code)
+ {
+ case WM_VSCROLL: /* Scroll in help document */
+ NewCurWw( wwHelp, TRUE );
+ MmwVertScroll( hwndHelpDoc, wParam, (int) lParam );
+ UpdateWw( wwCur, FALSE );
+ NewCurWw( wwDocument, TRUE );
+ break;
+
+ case WM_CLOSE:
+ goto Cancel;
+ case WM_INITDIALOG:
+ if (!FInzHelpPopUp( hDlg ))
+ {
+ goto Cancel;
+ }
+ EnableOtherModeless(FALSE);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ default:
+ break;
+ case idiHelpNext:
+ if (++iTopicChoice >= cTopic)
+ {
+ iTopicChoice--;
+ beep();
+ }
+ else
+ SetHelpTopic( hDlg, iTopicChoice );
+
+ break;
+ case idiHelpPrev:
+ if (iTopicChoice == 0)
+ beep();
+ else
+ SetHelpTopic( hDlg, --iTopicChoice );
+ break;
+
+ case idiOk:
+ wParam = idiHelpTopics;
+ case idiHelpTopics:
+ CleanUpHelpPopUp();
+ goto Endit;
+
+ case idiCancel:
+Cancel:
+ CleanUpHelpPopUp();
+ CloseHelpDoc();
+Endit:
+ EndDialog(hDlg, wParam);
+ EnableOtherModeless(TRUE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+
+
+
+BOOL far PASCAL DialogHelp( hDlg, code, wParam, lParam )
+HWND hDlg;
+unsigned code;
+WORD wParam;
+LONG lParam;
+{
+ HWND hwndListBox;
+
+ switch (code)
+ {
+ case WM_INITDIALOG:
+ if (!FSetHelpList( hwndListBox=GetDlgItem( hDlg, idiHelp ) ))
+ {
+ Error( IDPMTNoHelpFile );
+ CloseHelpDoc();
+ goto EndIt;
+ }
+
+ /* Come up with the first string in the list box selected */
+ SendMessage( hwndListBox, LB_SETCURSEL, (WORD) 0, (LONG) 0);
+
+ { /* Compute % of free memory, set that into dialog box */
+ extern cwHeapFree, cbTotQuotient, cbTot;
+ extern int vfOutOfMemory;
+ int pctHeapFree=0;
+ CHAR rgchPct[ 4 ];
+ int cchPct;
+ CHAR *pchT=&rgchPct[ 0 ];
+
+ if (!vfOutOfMemory)
+ {
+ pctHeapFree = cwHeapFree / cbTotQuotient;
+ if (pctHeapFree > 99)
+ pctHeapFree = (cwHeapFree*sizeof(int) == cbTot) ? 100 : 99;
+ }
+ cchPct = ncvtu( pctHeapFree, &pchT );
+ Assert( cchPct < 4);
+ rgchPct[ cchPct ] = '\0';
+ SetDlgItemText( hDlg, idiMemFree, (LPSTR) rgchPct );
+ }
+
+ EnableOtherModeless(FALSE);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiHelp:
+ /* This is received as part of the LBS_NOTIFY style */
+ /* whenever the user mouses up over a string */
+ /* LOWORD( lParam ) is the window handle of the list box */
+ /* HIWORD( lParam ) is 1 for single click, 2 for doubleclick */
+
+ switch( HIWORD( lParam ) ) {
+ default:
+ break;
+ case 1: /* SINGLE CLICK */
+ EnableWindow( GetDlgItem( hDlg, idiOk ),
+ SendMessage( (HWND)GetDlgItem( hDlg,
+ idiHelp ),
+ LB_GETCURSEL,
+ 0,
+ (LONG) 0 ) >= 0 );
+ break;
+ case 2: /* DOUBLE CLICK */
+ wParam = idiOk;
+ goto Okay;
+ }
+ break;
+
+ case idiOk:
+Okay:
+ iTopicChoice = SendMessage( (HWND)GetDlgItem( hDlg, idiHelp ),
+ LB_GETCURSEL, 0, (LONG) 0 );
+ goto EndIt;
+
+ case idiCancel:
+ /* Cancelled, get rid of Help Document info */
+ CloseHelpDoc();
+EndIt:
+ EndDialog(hDlg, wParam);
+ EnableOtherModeless(TRUE);
+ break;
+ }
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+ } /* end of DialogHelp */
+
+
+
+FSetHelpList( hWndListBox )
+HWND hWndListBox;
+{ /* Open the MEMO Help File as a MEMO Document. Set docHelp, fnHelpFile.
+ Read the strings for the list box as the contents of the first
+ "printed" page (i.e. use the page table) and send them to the
+ list box with the passed window handle */
+
+ CHAR szTopicBuf[ cchMaxTopicName ];
+ typeCP cp;
+ typeCP cpLimParaCache;
+ int cch;
+ struct PGTB **hpgtbT;
+
+ Assert( docHelp != docNil );
+
+ cTopic = 0;
+
+ if ((hpgtbT=(**hpdocdod)[ docHelp ].hpgtb) != 0)
+ {
+ hpgtbHelp = hpgtbT;
+ (**hpdocdod)[ docHelp ].hpgtb = 0;
+ }
+
+ Assert( (hpgtbHelp != 0) && ((**hpgtbHelp).cpgd > 1) );
+
+ /* List of topics starts on the first page, 1 para per topic */
+ /* For each topic (paragraph), build a string and send it to the list box */
+
+ for ( cp = (**hpgtbHelp).rgpgd [0].cpMin;
+ cp < (**hpgtbHelp).rgpgd [1].cpMin;
+ cp = cpLimParaCache )
+ {
+ int cchTopicMac;
+
+ CachePara( docHelp, cp );
+ cpLimParaCache = vcpLimParaCache;
+
+ cchTopicMac = imin( (int)(vcpLimParaCache - cp) - ccpEol,
+ cchMaxTopicName );
+
+ /* Build up a topic name string */
+ cch = 0;
+ while (cch < cchTopicMac)
+ {
+ int cchT;
+
+ FetchCp( docHelp, cp, 0, fcmChars );
+ cp += vccpFetch;
+ cchT = imin( vcchFetch, cchTopicMac - cch );
+ Assert( cchT > 0);
+ bltbyte( vpchFetch, szTopicBuf + cch, cchT );
+ cch += cchT;
+ }
+ if ((cch == 0) || szTopicBuf [0] == chSect)
+ /* End of Topics */
+ break;
+
+ szTopicBuf[ cch ] = '\0';
+ SendMessage( hWndListBox, LB_INSERTSTRING, -1, (LONG)(LPSTR)szTopicBuf);
+ cTopic++;
+ } /* end for */
+
+ return (cTopic > 0);
+}
+#endif /* ONLINEHELP */
+
diff --git a/private/mvdm/wow16/write/indent.bms b/private/mvdm/wow16/write/indent.bms
new file mode 100644
index 000000000..6c43f3c32
--- /dev/null
+++ b/private/mvdm/wow16/write/indent.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/initmmw.c b/private/mvdm/wow16/write/initmmw.c
new file mode 100644
index 000000000..8bbcca332
--- /dev/null
+++ b/private/mvdm/wow16/write/initmmw.c
@@ -0,0 +1,968 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* initialization codes for internal memory, page buffers, etc. */
+#define NOKEYSTATE
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOSYSCOMMANDS
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSHOWWINDOW
+#define NOBITMAP
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NORESOURCE
+#define NOMETAFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOWH
+#define NOWINOFFSETS
+/* need gdi, hdc, memmgr */
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "fmtdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "stcdefs.h"
+#ifdef CASHMERE
+#include "txb.h"
+#endif /* CASHMERE */
+#include "fontdefs.h"
+#include "code.h"
+#include "heapdefs.h"
+#include "heapdata.h"
+#include "str.h"
+#include "ch.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/* E X T E R N A L S */
+extern int ypMaxWwInit;
+extern int dypWwInit;
+extern int *memory;
+extern int *pmemMax;
+extern CHAR *pmemStart;
+extern unsigned vcbMemTotal;
+extern HWND hParentWw;
+extern HDC vhDCPrinter;
+extern int rfnMac;
+extern CHAR (*rgbp)[cbSector];
+extern int fnMac;
+extern typeTS tsMruRfn;
+extern struct ERFN dnrfn[];
+extern CHAR *rgibpHash;
+extern struct BPS *mpibpbps;
+extern typeTS tsMruBps;
+extern struct CHP vchpNormal;
+extern struct PAP *vppapNormal;
+extern struct SEP vsepNormal;
+extern struct CHP (**vhgchpFormat)[];
+extern int ichpMacFormat;
+extern struct CHP vchpInsert;
+extern struct CHP vchpSel;
+extern struct FCB (**hpfnfcb)[];
+extern struct FKPD vfkpdCharIns;
+extern struct FKPD vfkpdParaIns;
+extern struct PAP vpapPrevIns;
+extern struct FLI vfli;
+extern int docMac;
+extern struct DOD (**hpdocdod)[];
+extern int docScrap;
+extern int docUndo;
+#ifdef CASHMERE /* No docBuffer in WRITE */
+extern int docBuffer;
+#endif
+extern int docCur;
+extern CHAR (**hszSearch)[];
+extern CHAR (**hszReplace)[];
+extern CHAR (**hszFlatSearch)[];
+extern CHAR stBuf[];
+extern int vrefSystem;
+extern CHAR (**vhrgbSave)[];
+extern int vdxaPaper;
+extern int vdyaPaper;
+extern struct SEL selCur;
+extern BOOL vfPrinterValid;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern int dxaPrOffset;
+extern int dyaPrOffset;
+extern HCURSOR vhcArrow;
+#ifdef UNUSED
+extern int vfCanPrint;
+#endif
+
+/* G L O B A L S -- used only in here */
+int rgwPapNormal[cwPAPBase + cwTBD] = {0};
+
+
+#ifdef STATICPAGES
+#ifdef MACHA
+#define ibpMaxStatic 79
+#define iibpHashMaxStatic 163
+#else /* not MACHA */
+#define ibpMaxStatic 7
+#define iibpHashMaxStatic 17
+#endif /* MACHA */
+CHAR rgbpStatic[ibpMaxStatic][cbSector];
+#endif /* STATICPAGES */
+
+extern typePN PnAlloc();
+
+STATIC int NEAR FInitDocs( void );
+STATIC int NEAR FInitProps( void );
+STATIC int NEAR FInitFiles( void );
+WORD wWinVer,fPrintOnly=FALSE;
+
+int FInitMemory()
+{
+extern HANDLE vhReservedSpace;
+int i;
+
+#ifdef UNUSED
+/* Initially assume that it is not possible to print */
+/* Formerly InitPrint was called here */
+ vfCanPrint = false;
+#endif
+
+ /** This is a glitch so that the fixed array for storing relocation
+ information will be created immediately */
+ wWinVer = (WORD)(GetVersion() & 0x0000FFFFL);
+ if (((wWinVer & 0xFF) >= 3) && ((wWinVer & 0xFF00) >= 0x0A00))
+ /* Windows Version >= 3.10 */
+ {
+ FARPROC LHandleDelta = GetProcAddress(GetModuleHandle((LPSTR)"KERNEL"),(LPSTR)0x136L);
+ i = LHandleDelta(0);
+ LHandleDelta(i*5); /* make a big finger table */
+ vhReservedSpace = LocalAlloc(LHND, cbReserve);
+ LocalFree(vhReservedSpace);
+ LHandleDelta(i); /* resume to a smaller finger table if needed more */
+ }
+ else
+ /* Windows Version < 3.10 */
+ {
+ /**
+ This is heaping kludge upon kludge in the effort to be backwards
+ compatible with past kludges. This is the old macro which with
+ Win31 has become a function call. (3.11.91) D. Kent
+ **/
+#define LocalHandleDelta(d) ((d) ? (*(pLocalHeap+9) = (d)) : *(pLocalHeap+9))
+ i = LocalHandleDelta(0);
+ LocalHandleDelta(i*5); /* make a big finger table */
+ vhReservedSpace = LocalAlloc(LHND, cbReserve);
+ LocalFree(vhReservedSpace);
+ LocalHandleDelta(i); /* resume to a smaller finger table if needed more */
+ }
+
+#ifdef OURHEAP
+/* reserve 1K for windows's memory manager for creating dialog boxes */
+ vhReservedSpace = LocalAlloc(LPTR, cbReserve);
+
+ CreateHeapI(); /* create heap first */
+ if (!FCreateRgbp()) /* rgbp are expandable */
+ return FALSE;
+
+/* now free the reserved space after our memory is set up. */
+/* hopefully we will get all the fixed objects created by
+ dialog manager be placed above our memory chunk, so we can still
+ expand our heap while a dialog box is up. */
+ LocalFree(vhReservedSpace);
+#else
+ if (!FCreateRgbp())
+ return FALSE;
+ vhReservedSpace = LocalAlloc(LHND, cbReserve); /* this is to make
+ discardable when we are out of memory and try to bring up the
+ save dialog box */
+#endif
+
+ if (vhReservedSpace == NULL)
+ return FALSE;
+
+/* formerly CreateHpfnfcb */
+ hpfnfcb = (struct FCB (**)[])HAllocate(cwFCB * fnMax);
+ if (FNoHeap(hpfnfcb))
+ return FALSE;
+ fnMac = fnMax;
+ for (i = 0; i < fnMac; i++)
+ (**hpfnfcb)[i].rfn = rfnFree;
+/* end of CreateHpfnfcb */
+
+ if (!FSetScreenConstants())
+ return FALSE;
+
+ if ( !FInitDocs() ||
+#ifdef CASHMERE /* No glossary in MEMO */
+ !FInitBufs() ||
+#endif /* CASHMERE */
+ !FInitProps() ||
+ !FInitFiles() )
+ return FALSE;
+
+/* allocate emergency space for save operations */
+ if (FNoHeap(vhrgbSave = (CHAR (**)[])HAllocate(cwSaveAlloc)))
+ return FALSE;
+
+ return TRUE;
+}
+/* end of F I n i t M e m o r y */
+
+
+
+
+int FInitArgs(sz)
+CHAR *sz;
+{ /* Set extern int docCur to be a new doc, containing
+ the file (if any) specified on the command line (sz).
+
+ Initialize a wwd (window descriptor) structure for the document
+ and set an appropriate title into the title bar.
+
+ Set selCur to be an insertion point before the first char of the doc,
+ and set vchpSel to be the char properties of the insertion point.
+
+ Return TRUE if all is well, FALSE if something went wrong.
+ A return of FALSE means that initialization should not continue.
+ */
+
+ extern typeCP cpMinDocument;
+ extern struct WWD rgwwd[];
+ extern int vfDiskError;
+ extern int vfSysFull;
+ extern int ferror;
+ extern BOOL vfWarnMargins;
+
+ int fn, doc;
+ RECT rcCont;
+ CHAR szT [ cchMaxFile ];
+ register CHAR *pch;
+ CHAR ch;
+ int fEmptyLine = TRUE;
+ CHAR (**hsz) [];
+ int iT, cbsz;
+
+#ifdef INTL /* International version */
+ int fWordDoc = FALSE;
+#endif /* International version */
+
+ /* Decide whether we have anything but white space on the command line */
+
+ for ( pch = sz; (ch = *pch) != '\0'; pch++ )
+ if ((ch != ' ') && (ch != '\011'))
+ {
+ fEmptyLine = FALSE;
+ break;
+ }
+
+ if (fEmptyLine)
+ /* No filename; start with (Untitled) */
+ goto Untitled;
+
+ cbsz = CchSz (sz ) - 1;
+ /* remove trailing spaces from sz */
+ for ( pch = sz + cbsz - 1; pch >= sz; pch-- )
+ if (*pch != ' ')
+ break;
+ else
+ {
+ *pch = '\0'; /* replace with null */
+ cbsz--;
+ }
+
+ /* check for /p option (6.26.91) v-dougk */
+ if ((sz[0] == '/') && (sz[1] == 'p'))
+ {
+ sz += 2;
+ cbsz -= 2;
+ fPrintOnly = TRUE;
+ for (; *sz; sz++, cbsz-- ) // get to filename
+ if ((*sz != ' ') && (*sz != '\011'))
+ break;
+
+ if (!*sz) /* No filename, abort */
+ return FALSE;
+ }
+
+ /* convert to OEM */
+ AnsiToOem(sz, sz);
+
+ if (!FValidFile( sz, cbsz, &iT ) ||
+ !FNormSzFile( szT, sz, dtyNormal ))
+ { /* Bad filename -- it could not be normalized */
+ extern int vfInitializing;
+ char szMsg[cchMaxSz];
+ char *pch;
+ extern HWND vhWndMsgBoxParent;
+ extern HANDLE hParentWw;
+
+ vfInitializing = FALSE; /* Do not suppress reporting this err */
+ MergeStrings (IDPMTBadFileName, sz, szMsg);
+ /* if we're being called from a message box, then use it
+ as the parent window, otherwise use main write window */
+ IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw,
+ szMsg, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
+ ferror = TRUE; /* need to flag */
+ vfInitializing = TRUE;
+ goto Untitled;
+ }
+
+ if ((fn = FnOpenSz( szT, dtyNormal,
+ index( szT, '/' ) == NULL &&
+ index( szT,':') == NULL && index( szT, '\\') == NULL )) != fnNil)
+ /* Opened file OK -- prefetch file contents into rgbp */
+ {
+
+#ifdef INTL /* Kanji / International version */
+ /* **************************************
+ * added check for international version to
+ do Word format conversion. If Word format,
+ bring up another dialog box.
+ * ************************************** */
+
+ /* TestWordCvt return values:
+
+ -1 means dialog box failed (error already sent)
+ or cancel without conversion.
+ FALSE means not a word document.
+ TRUE means convert this word document.
+ vfBackupSave is changed to reflect whether
+ save is done with backup.
+ */
+
+ if ((fWordDoc = TestWordCvt (fn, (HWND)NULL)) == -1)
+ goto Untitled;
+ /* if fWordDoc is true, will convert later */
+#endif /* International version */
+
+
+ StartLongOp();
+ ReadFilePages( fn );
+ EndLongOp(vhcArrow);
+ }
+ else /* Could not open file */
+ {
+ if (fPrintOnly)
+ return FALSE;
+ else
+ { /* use (Untitled) */
+Untitled:
+ fn = fnNil;
+ sz [0] = '\0';
+ szT [0] = '\0';
+ }
+ }
+
+ if (vfDiskError || vfSysFull)
+ /* Serious disk error OR disk holding scratch file is full --
+ bail out */
+ return FALSE;
+
+ if (fn != fnNil)
+ { /* Opened file OK -- must account for the case when OpenFile
+ returned a filename that differed from the one given it */
+
+ bltsz( &(**(**hpfnfcb) [fn].hszFile) [0], szT );
+ }
+
+ if (FNoHeap(hsz=HszCreate( (PCH) szT )) ||
+ (doc=DocCreate( fn, hsz, dtyNormal )) == docNil)
+ { /* Could not create a doc */
+ return FALSE;
+ }
+ if (WwNew(doc, dypWwInit, ypMaxWwInit) == wwNil)
+ return FALSE;
+ NewCurWw(0, true);
+ if (fn != fnNil)
+ {
+ vfWarnMargins = TRUE;
+ SetPageSize();
+ vfWarnMargins = FALSE;
+ }
+ wwdCurrentDoc.cpFirst = selCur.cpLim = selCur.cpFirst = cpMinDocument;
+ selCur.fForward = true;
+ GetInsPtProps(selCur.cpFirst);
+
+#ifdef OURHEAP
+ {
+ extern int cwInitStorage;
+/* save this amount of heap as "100% free" */
+/* formerly CalcTot(true) */
+ cwInitStorage = cwHeapMac - cwHeapFree;
+ cbTot = (cwHeapMac - cwInitStorage) * sizeof(int);
+ cbTotQuotient = (cbTot>>1)/100;
+ }
+#endif
+
+#ifdef STYLES
+/* Set up scrap document to have a valid style sheet on start up. */
+ (**hpdocdod)[docScrap].docSsht = (**hpdocdod)[docCur].docSsht;
+#endif /* STYLES */
+
+#ifdef INTL /* International version */
+ /* if a word document to be converted, save
+ it doing conversion. */
+
+ if (fWordDoc == TRUE)
+ {
+ /* save file in write format. */
+ ConvertFromWord();
+ }
+#endif /* International version */
+
+ SetTitle(szT);
+
+#if defined(OLE)
+ ObjOpenedDoc(doc);
+#endif
+ return TRUE;
+}
+/* end of F I n i t A r g s */
+
+
+
+
+#ifdef OURHEAP
+CreateHeapI()
+{
+FGR *pfgr, *pfgrLim;
+#ifdef WINBUG
+unsigned cb = (unsigned)GlobalCompact((DWORD)0);
+#endif
+
+ ibpMax = ibpMaxSmall;
+ if (cb > 0x4fff /* about 20K */)
+ {
+ HANDLE hTemp;
+ /* we can start with a bigger page buffer */
+ vcbMemTotal = (unsigned)LocalCompact((WORD)0);
+ pmemStart = (CHAR *)LocalAlloc(LPTR, vcbMemTotal);
+ /* get all we have and force a reallocation */
+ hTemp = LocalReAlloc((HANDLE)pmemStart, 0x4fff, LPTR);
+ if (hTemp != NULL)
+ {
+ LocalFree(hTemp);
+ ibpMax = ibpMaxBig;
+ }
+ else
+ {
+ /* somehow we failed and went back to the small system */
+ LocalFree((HANDLE)pmemStart);
+ }
+ }
+
+ vcbMemTotal = (unsigned)LocalCompact((WORD)0);
+
+/* memory always bumped to point to the next available slot
+ for allocation */
+/* take all the space as one chunk and do our own memory management */
+ pmemStart = (CHAR *)LocalAlloc(LPTR, vcbMemTotal);
+ memory = (int *)pmemStart;
+ vcbMemTotal = (unsigned)LocalSize((HANDLE)pmemStart); /* in case
+ we got more than we asked */
+ pmemMax = (int *)((CHAR *)memory + vcbMemTotal);
+
+/* take half of heap space for page buffers
+ ibpMax = (vcbMemTotal>>1)/cbSector;*/
+ iibpHashMax = ibpMax * 2 + 1;
+
+/* Set finger table to low end of heap */
+ rgfgr = (PFGR)memory;
+ memory += ifgrInit;
+ memory = (int *)(((unsigned) memory + 1) & ~1); /* word boundary */
+
+/* Here is our heap */
+ pHeapFirst = (int *)memory;
+
+ cwHeapMac = /* cwtotal */
+ (((unsigned)pmemMax - (unsigned)pHeapFirst +
+ sizeof(int) - 1) / sizeof(int)) -
+ /* cw in rgibpHash */
+ ((iibpHashMax * sizeof(CHAR) +
+ sizeof(int) - 1) / sizeof(int)) -
+ /* cw in mpibpbps */
+ ((ibpMax * sizeof(struct BPS) +
+ sizeof(int) - 1) / sizeof(int)) -
+ /* cw in rgbp */
+ ((ibpMax * cbSector * sizeof(CHAR) +
+ sizeof(int) - 1) / sizeof(int));
+
+ memory += cwHeapMac;
+
+#ifdef DEBUG
+ cwHeapMac -= 16; /* Need spare words for shaking */
+ /* This space is above the finger table */
+#endif
+ cwHeapFree = cwHeapMac;
+ phhMac = (HH *)(pHeapFirst + cwHeapMac);
+/* if DEBUG, then phhMac will point at the shake word;
+ otherwise it will point to 1 cell after the heap */
+
+ phhFree = (HH *) pHeapFirst;
+ phhFree->cw = -cwHeapMac; /* whobj.heap is free */
+ phhFree->phhNext = phhFree;
+ phhFree->phhPrev = phhFree;
+
+ pfgrMac = &rgfgr[ifgrInit];
+ pfgrLim = pfgrMac - 1;
+
+/* thread the free fingers */
+ for (pfgr = rgfgr; pfgr < pfgrLim; pfgr++)
+ *pfgr = (FGR)(pfgr + 1);
+ *pfgrLim = NULL; /* last free finger */
+ pfgrFree = rgfgr;
+}
+/* end of C r e a t e H e a p I */
+#endif /* OURHEAP */
+
+
+
+STATIC int NEAR FInitDocs()
+{ /* Initialize hpdocdod */
+ struct DOD *pdod, *pdodLim;
+ hpdocdod = (struct DOD (**)[])HAllocate(cwDOD * (docMac = cdocInit));
+ if (FNoHeap(hpdocdod))
+ return FALSE;
+
+ pdod = &(**hpdocdod)[0];
+ pdodLim = pdod + cdocInit;
+ while (pdod < pdodLim)
+ pdod++->hpctb = 0; /* Mark all doc entries as free */
+ docScrap = DocCreate(fnNil, HszCreate((PCH)""), dtyBuffer); /* HM */
+ docUndo = DocCreate(fnNil, HszCreate((PCH)""), dtyBuffer); /* HM */
+#ifdef CASHMERE
+ docBuffer = DocCreate(fnNil, HszCreate((PCH)""), dtyBuffer); /* HM */
+#endif
+
+ docCur = docNil;
+ NoUndo();
+ hszSearch = HszCreate((PCH)""); /* No initial search string */
+ hszReplace = HszCreate((PCH)""); /* No initial replace string */
+ hszFlatSearch = HszCreate((PCH)""); /* No initial flattenned search string */
+ if (docScrap == docNil || docUndo == docNil ||
+#ifdef CASHMERE
+ docBuffer == docNil ||
+#endif
+ FNoHeap(hszFlatSearch))
+ return FALSE;
+ return TRUE;
+}
+/* end of F I n i t D o c s */
+
+
+
+
+#ifdef CASHMERE /* No glossary in MEMO */
+FInitBufs()
+{
+/* Initializes structures and data used in named buffer management.
+Allocates space for hgtxb, initializes itxbMac */
+
+ struct TXB *ptxb;
+ extern struct TXB (**hgtxb)[];
+ extern short itxbMac;
+
+ if (FNoHeap(hszGlosFile = HszCreate((PCH)"")))
+ return FALSE;
+ if (FNoHeap(hgtxb = (struct TXB (**)[])HAllocate(cwTxb)))
+ return FALSE;
+ ptxb = &(**hgtxb)[0];
+ ptxb->hszName = hszNil;
+ itxbMac = 0;
+ return TRUE;
+}
+/* end of F I n i t B u f s */
+#endif /* CASHMERE */
+
+
+
+STATIC int NEAR FInitProps()
+{ /* Initialize your basic properties */
+
+#ifndef FIXED_PAGE
+ unsigned dxaRightMin;
+ unsigned dyaBottomMin;
+#endif /* not FIXED_PAGE */
+
+ vchpNormal.hps = hpsNormal; /* NOTE - this is the size we use for
+ incremental encoding, the "default"
+ size may differ */
+ vchpNormal.ftc = 0; /* will be whatever the standard modern font is */
+ vchpNormal.ftcXtra = 0;
+
+ vchpNormal.fStyled = true;
+ /* vchpNormal.stc = stcNormal; */
+
+ vppapNormal = (struct PAP *)rgwPapNormal;
+
+ /* vppapNormal->fStyled = false; */
+ /* vppapNormal->stc = 0; */
+ vppapNormal->stcNormChp = stcParaMin;
+ /* vppapNormal->dxaRight = 0; */
+ /* vppapNormal->dxaLeft = 0; */
+ /* vppapNormal->dxaLeft1 = 0; */
+ /* vppapNormal->jc = jcLeft; */
+ /* vppapNormal->dyaBefore = 0; */
+ /* vppapNormal->dtaAfter = 0; */
+
+ vppapNormal->fStyled = true;
+ vppapNormal->stc = stcParaMin;
+ vppapNormal->dyaLine = czaLine;
+
+ Assert(cwPAP == cwSEP);
+
+ /* vsepNormal.fStyled = false; */
+ /* vsepNormal.stc = 0; */
+ vsepNormal.bkc = bkcPage;
+ /* vsepNormal.nfcPgn = nfcArabic; */
+
+#ifdef FIXED_PAGE
+ /* The "normal" page size is fixed at 8-1/2 by 11 inches. */
+ vsepNormal.xaMac = cxaInch * 8 + cxaInch / 2;
+ vsepNormal.xaLeft = cxaInch * 1 + cxaInch / 4;
+ vsepNormal.dxaText = cxaInch * 6;
+ vsepNormal.yaMac = cyaInch * 11;
+ vsepNormal.yaTop = cyaInch * 1;
+ vsepNormal.dyaText = cyaInch * 9;
+ vsepNormal.yaRH1 = cyaInch * 3 / 4;
+ vsepNormal.yaRH2 = cyaInch * 10 + cyaInch / 4;
+#else /* not FIXED_PAGE */
+ /* The page size is determined by inquiring it from the printer. Then,
+ other measurements can be derived from it. */
+ Assert(vhDCPrinter);
+ if (vfPrinterValid && vhDCPrinter != NULL)
+ {
+ POINT pt;
+
+ /* Get the page size of the printer. */
+ if (Escape(vhDCPrinter, GETPHYSPAGESIZE, 0, (LPSTR)NULL,
+ (LPSTR)&pt))
+ {
+ vsepNormal.xaMac = MultDiv(pt.x, dxaPrPage, dxpPrPage);
+ vsepNormal.yaMac = MultDiv(pt.y, dyaPrPage, dypPrPage);
+ }
+ else
+ {
+ /* The printer won't tell us it page size; we'll have to settle
+ for the printable area. */
+ vsepNormal.xaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter,
+ HORZSIZE));
+ vsepNormal.yaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter,
+ VERTSIZE));
+ }
+
+ /* The page size cannot be smaller than the printable area. */
+ if (vsepNormal.xaMac < dxaPrPage)
+ {
+ vsepNormal.xaMac = dxaPrPage;
+ }
+ if (vsepNormal.yaMac < dyaPrPage)
+ {
+ vsepNormal.yaMac = dyaPrPage;
+ }
+
+ /* Determine the offset of the printable area on the page. */
+ if (Escape(vhDCPrinter, GETPRINTINGOFFSET, 0, (LPSTR)NULL,
+ (LPSTR)&pt))
+ {
+ dxaPrOffset = MultDiv(pt.x, dxaPrPage, dxpPrPage);
+ dyaPrOffset = MultDiv(pt.y, dyaPrPage, dypPrPage);
+ }
+ else
+ {
+ /* The printer won't tell us what the offset is; assume the
+ printable area is centered on the page. */
+ dxaPrOffset = (vsepNormal.xaMac - dxaPrPage) >> 1;
+ dyaPrOffset = (vsepNormal.yaMac - dyaPrPage) >> 1;
+ }
+
+ /* Determine the minimum margins. */
+ dxaRightMin = imax(0, vsepNormal.xaMac - dxaPrOffset - dxaPrPage);
+ dyaBottomMin = imax(0, vsepNormal.yaMac - dyaPrOffset - dyaPrPage);
+ }
+ else
+ {
+ /* We have no printer; so, the page is 8-1/2" by 11" for now. */
+ vsepNormal.xaMac = 8 * czaInch + czaInch / 2;
+ vsepNormal.yaMac = 11 * czaInch;
+
+ /* Assume the entire page can be printed. */
+ dxaPrOffset = dyaPrOffset = dxaRightMin = dyaBottomMin = 0;
+ }
+
+ /* Ensure that the "normal" margins are larger than the minimum. */
+ vsepNormal.xaLeft = umax(cxaInch * 1 + cxaInch / 4, dxaPrOffset);
+ vsepNormal.dxaText = vsepNormal.xaMac - vsepNormal.xaLeft - umax(cxaInch
+ * 1 + cxaInch / 4, dxaRightMin);
+ vsepNormal.yaTop = umax(cyaInch * 1, dyaPrOffset);
+ vsepNormal.dyaText = vsepNormal.yaMac - vsepNormal.yaTop - umax(cyaInch
+ * 1, dyaBottomMin);
+
+ /* Position the running-heads and the page numbers. */
+ vsepNormal.yaRH1 = umax(cyaInch * 3 / 4, dyaPrOffset);
+ vsepNormal.yaRH2 = vsepNormal.yaMac - umax(cyaInch * 3 / 4,
+ dyaBottomMin);
+ vsepNormal.xaPgn = vsepNormal.xaMac - umax(cxaInch * 1 + cxaInch / 4,
+ dxaRightMin);
+ vsepNormal.yaPgn = umax(cyaInch * 3 / 4, dyaPrOffset);
+#endif /* not FIXED_PAGE */
+
+ vsepNormal.pgnStart = pgnNil;
+ /* vsepNormal.fAutoPgn = false; */
+ /* vsepNormal.fEndFtns = false; */
+ vsepNormal.cColumns = 1;
+ vsepNormal.dxaColumns = cxaInch / 2;
+ /* vsepNormal.dxaGutter = 0; */
+
+ vdxaPaper = vsepNormal.xaMac;
+ vdyaPaper = vsepNormal.yaMac;
+
+ vfli.doc = docNil; /* Invalidate vfli */
+ ichpMacFormat = ichpMacInitFormat;
+ vhgchpFormat = (struct CHP (**)[])HAllocate(ichpMacInitFormat * cwCHP);
+ if (FNoHeap(vhgchpFormat))
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+/* end of F I n i t P r o p s */
+
+
+
+
+
+STATIC int NEAR FInitFiles()
+{
+ extern WORD vwDosVersion;
+
+ int fn;
+ int cchT;
+ struct FKP *pfkp;
+ struct FCB *pfcb;
+ int osfnExtra;
+ CHAR sz [cchMaxFile];
+
+ rfnMac = rfnMacEdit;
+
+ /* Set DOS version we're running under */
+
+ vwDosVersion = WDosVersion();
+
+ InitBps();
+
+#ifdef CKSM
+#ifdef DEBUG
+ {
+ extern int ibpMax, ibpCksmMax;
+ extern unsigned (**hpibpcksm) [];
+
+ hpibpcksm = (unsigned (**) [])HAllocate( ibpMax );
+ if (FNoHeap( hpibpcksm ))
+ return FALSE;
+ ibpCksmMax = ibpMax;
+ }
+#endif
+#endif
+
+ /* sz <-- name of new, unique file which will be fnScratch */
+ sz[ 0 ] = '\0'; /* Create it in the root on a temp drive */
+ if ((fn=FnCreateSz( sz, cpNil, dtyNetwork )) == fnNil )
+ /* Couldn't create scratch file: fail */
+ return FALSE;
+
+ Assert(fn == fnScratch); /* fnScratch hardwired to 0 for efficiency */
+ FreezeHp();
+ pfcb = &(**hpfnfcb)[fnScratch];
+ pfcb->fFormatted = true; /* Sort of a formatted file */
+ pfcb->fDelete = true; /* Kill this file when we quit */
+ MeltHp();
+ vfkpdParaIns.brun = vfkpdCharIns.brun = 0;
+ vfkpdParaIns.bchFprop = vfkpdCharIns.bchFprop = cbFkp;
+ vfkpdParaIns.pn = PnAlloc(fnScratch);
+ ((struct FKP *) PchGetPn(fnScratch, vfkpdParaIns.pn, &cchT, true))->fcFirst =
+ fc0;
+ vfkpdCharIns.pn = PnAlloc(fnScratch);
+ ((struct FKP *) PchGetPn(fnScratch, vfkpdCharIns.pn, &cchT, true))->fcFirst =
+ fc0;
+
+ /* The following can really be allocated 0 words, but why push our luck? */
+ vfkpdParaIns.hgbte = (struct BTE (**)[]) HAllocate(cwBTE);
+ vfkpdCharIns.hgbte = (struct BTE (**)[]) HAllocate(cwBTE);
+ vfkpdParaIns.ibteMac = vfkpdCharIns.ibteMac = 0;
+ if (FNoHeap(vfkpdParaIns.hgbte) || FNoHeap(vfkpdCharIns.hgbte))
+ return FALSE;
+
+ blt(&vchpNormal, &vchpInsert, cwCHP);
+ blt(&vchpNormal, &vchpSel, cwCHP);
+ blt(vppapNormal, &vpapPrevIns, cwPAPBase + cwTBD);
+ return TRUE;
+}
+/* end of F I n i t F i l e s */
+
+
+
+
+InitBps()
+{
+/* called from initfiles to set up the tables */
+ int ibp, iibp;
+ int rfn;
+ int fn;
+
+/* In order impliment a LRU page swap strategy, a time stamp(TS) scheme is */
+/* used. Associated with each buffer slot is a time stamp. The least */
+/* recently used slot is found by locating the slot with the smallest time */
+/* stamp. Every time a new page is brought into the buffer, it TS is set */
+/* equal to the value of a incrimented global TS counter (tsMru...). */
+/* Initially, the time stamps are set so that they increase as we move */
+/* toward the end of the table. Thus, even though the entire buffer pool */
+/* is initially empty, slots at the beginning of the table will be */
+/* allocated first. */
+
+ {
+ register struct ERFN *perfn = &dnrfn [0];
+
+ for (rfn = 0; rfn < rfnMac; rfn++, perfn++)
+ {
+ perfn->fn = fnNil;
+ perfn->ts = rfn;
+ }
+ tsMruRfn = rfnMac /* + ? */;
+ }
+
+ for (iibp = 0; iibp < iibpHashMax; iibp++)
+ rgibpHash[iibp] = ibpNil;
+ {
+ register struct BPS *pbps=&mpibpbps [0];
+
+ for (ibp = 0; ibp < ibpMax; ++ibp, pbps++)
+ {
+ pbps->fn = fnNil;
+ pbps->fDirty = false;
+ pbps->ts = ibp;
+ pbps->ibpHashNext = ibpNil;
+ }
+ tsMruBps = ibpMax + cbpMustKeep;
+ }
+ /* In IbpEnsureValid (file.c) we may not want to use the least */
+ /* recently used slot for certain reasons. But, we do want to */
+ /* be assured that we do not clobber the 'cbpMustKeep' most */
+ /* recently used slots. Our check consists of making sure */
+ /* (tsMruBps - ts_in_question) < cbpMustKeep. By the above */
+ /* statement, we are assured that non of the empty slots satisfy */
+ /* this condition. */
+
+ /* Allocate initial checksum array */
+
+
+
+}
+/* end of I n i t B p s */
+
+
+
+#ifdef OURHEAP
+FCreateRgbp()
+{
+ rgbp = (CHAR (*)[cbSector])memory;
+ memory = (int *)((unsigned)memory + (unsigned)(ibpMax)
+ * cbSector);
+ memory = (int *)(((unsigned) memory + 1) & ~1); /* word boundary */
+ rgibpHash = (CHAR *)memory;
+ memory = (int *)((unsigned)memory +
+ (unsigned)(iibpHashMax * sizeof(CHAR)));
+ memory = (int *)(((unsigned) memory + 1) & ~1); /* word boundary */
+ mpibpbps = (struct BPS *)memory;
+ memory = (int *)((unsigned)memory +
+ (unsigned)(ibpMax * sizeof(struct BPS)));
+ memory = (int *)(((unsigned) memory + 1) & ~1);
+ return (memory <= pmemMax);
+}
+/* end of F C r e a t e R g b p */
+#else /* use windows' memory manager */
+FCreateRgbp()
+{
+extern int vfLargeSys;
+
+long lcbFree;
+unsigned cb;
+
+ ibpMax = ibpMaxSmall;
+ lcbFree = GlobalCompact((DWORD)0);
+ if (lcbFree > 0x00030D40 /* 200K */)
+ {
+ /* we can start with a bigger page buffer */
+ ibpMax = ibpMaxBig;
+ vfLargeSys = TRUE;
+ }
+
+ iibpHashMax = ibpMax * 2 + 1;
+
+ cb = ((ibpMax * cbSector * sizeof(CHAR) + 1) & ~1) /* rgbp */
+ + ((iibpHashMax * sizeof(CHAR) + 1) & ~1) /* rgibpHash */
+ + ((ibpMax * sizeof(struct BPS) + 1) & ~1); /* mpibpbps */
+
+ memory = (int *)LocalAlloc(LPTR, cb);
+
+ if (memory == NULL)
+ {
+ ibpMax = ibpMaxSmall;
+ iibpHashMax = ibpMax * 2 + 1;
+ cb = ((ibpMax * cbSector * sizeof(CHAR) + 1) & ~1) /* rgbp */
+ + ((iibpHashMax * sizeof(CHAR) + 1) & ~1) /* rgibpHash */
+ + ((ibpMax * sizeof(struct BPS) + 1) & ~1); /* mpibpbps */
+ memory = (int *)LocalAlloc(LPTR, cb);
+ }
+
+ if (memory == NULL)
+ return FALSE;
+
+ rgbp = (CHAR (*)[cbSector])memory;
+ memory = (int *)((unsigned)memory + (unsigned)(ibpMax)
+ * cbSector);
+ memory = (int *)(((unsigned) memory + 1) & ~1); /* word boundary */
+ rgibpHash = (CHAR *)memory;
+ memory = (int *)((unsigned)memory +
+ (unsigned)(iibpHashMax * sizeof(CHAR)));
+ memory = (int *)(((unsigned) memory + 1) & ~1); /* word boundary */
+ mpibpbps = (struct BPS *)memory;
+
+/*
+ memory = (int *)((unsigned)memory +
+ (unsigned)(ibpMax * sizeof(struct BPS)));
+ memory = (int *)(((unsigned) memory + 1) & ~1);*/
+
+ return TRUE;
+}
+#endif
+
diff --git a/private/mvdm/wow16/write/initwin.c b/private/mvdm/wow16/write/initwin.c
new file mode 100644
index 000000000..6414d0bce
--- /dev/null
+++ b/private/mvdm/wow16/write/initwin.c
@@ -0,0 +1,887 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+
+#define NOVIRTUALKEYCODES
+#define NOKEYSTATE
+#define NOCREATESTRUCT
+#define NOICON
+//#define NOATOM
+//#define NOMEMMGR
+#define NOPEN
+#define NOREGION
+#define NODRAWTEXT
+#define NOMB
+#define NOWINOFFSETS
+#define NOOPENFILE
+#define NOMETAFILE
+#define NOWH
+//#define NOCLIPBOARD
+#define NOSYSCOMMANDS
+#define NOWINMESSAGES
+#define NOSOUND
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+
+
+#define NOUAC
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "menudefs.h"
+#include "str.h"
+#include "fontdefs.h"
+#include "printdef.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+#include <commdlg.h>
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+ /* static string arrays found in mglobals.c */
+extern CHAR szMw_acctb[];
+extern CHAR szNullPort[];
+extern CHAR szNone[15];
+extern CHAR szMwlores[];
+extern CHAR szMwhires[];
+extern CHAR szMw_icon[];
+extern CHAR szMw_menu[];
+extern CHAR szScrollBar[];
+extern CHAR szIntl[];
+extern CHAR szsDecimal[];
+extern CHAR szsDecimalDefault[];
+
+#ifdef INTL /* International version */
+extern CHAR sziCountry[];
+extern CHAR sziCountryDefault[5];
+#endif /* International version */
+
+extern CHAR vchDecimal; /* decimal point character */
+extern int viDigits; /* digits after decimal point */
+extern BOOL vbLZero; /* leading zero before decimal */
+
+extern struct WWD rgwwd[];
+extern CHAR stBuf[256];
+extern int vifceMac;
+extern union FCID vfcidScreen;
+extern union FCID vfcidPrint;
+extern struct FCE rgfce[ifceMax];
+extern struct FCE *vpfceMru;
+extern HCURSOR vhcHourGlass;
+
+#ifdef PENWIN // for PenWindows (5/21/91) patlam
+#include <penwin.h>
+
+extern HCURSOR vhcPen;
+
+extern int (FAR PASCAL *lpfnProcessWriting)(HWND, LPRC);
+extern VOID (FAR PASCAL *lpfnPostVirtualKeyEvent)(WORD, BOOL);
+extern VOID (FAR PASCAL *lpfnTPtoDP)(LPPOINT, int);
+extern BOOL (FAR PASCAL *lpfnCorrectWriting)(HWND, LPSTR, int, LPRC, DWORD, DWORD);
+extern BOOL (FAR PASCAL *lpfnSymbolToCharacter)(LPSYV, int, LPSTR, LPINT);
+#endif
+
+extern WORD fPrintOnly;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcArrow;
+extern HCURSOR vhcBarCur;
+extern HANDLE hMmwModInstance;
+extern HWND hParentWw;
+extern HWND vhWndSizeBox;
+extern HWND vhWndPageInfo;
+extern HWND vhWnd;
+extern HMENU vhMenu;
+extern HANDLE vhAccel;
+extern long rgbBkgrnd;
+extern long rgbText;
+extern HBRUSH hbrBkgrnd;
+extern HDC vhMDC;
+extern int vfInitializing;
+extern int vfMouseExist;
+extern int ferror;
+extern CHAR szWindows[];
+extern CHAR szNul[];
+extern CHAR szWriteProduct[];
+extern CHAR szBackup[];
+extern int vfBackupSave;
+extern HANDLE hszNoMemory;
+extern HANDLE hszDirtyDoc;
+extern HANDLE hszCantPrint;
+extern HANDLE hszPRFAIL;
+extern HANDLE hszCantRunM;
+extern HANDLE hszCantRunF;
+extern HANDLE hszWinFailure;
+extern HDC vhDCPrinter;
+
+int vkMinus;
+
+extern int utCur;
+
+ /* Regrettably, we are not permitted to signal in WM_CREATE message
+ handlers that we have failed -- instead, we resort to
+ ugly global communication via this variable */
+#ifdef WIN30
+ /* Note that we now CAN return a -1L from MmwCreate and cause the
+ CreateWindow to fail, but changing this now wouldn't accomplish us
+ very much (besides saving a bunch of checks of a global) ..pault */
+#endif
+STATIC int fMessageInzFailed = FALSE;
+
+STATIC BOOL NEAR FRegisterWnd( HANDLE );
+#ifdef INEFFLOCKDOWN
+STATIC int NEAR FInitFarprocs( HANDLE );
+#endif
+STATIC HANDLE NEAR HszCreateIdpmt( int );
+
+BOOL InitIntlStrings( HANDLE );
+
+
+#define cchCmdLineMax 64 /* Longest command line accepted */
+
+
+
+/* FInitWinInfo */
+/* Main MS-WINDOWS initialization entry point for write */
+/* Actions:
+ Loads all mouse cursors & sets global handles to cursors (vhc's)
+ Loads the menu key accelerator table vhAccel
+ Registers all of WRITE's myriad window classes
+ Sets up global hMmwModInstance, our instance handle
+ Puts "DOC = WRITE.EXE ^.DOC" into WIN.INI if not already there
+ Generates thunks for all exported procedures
+ Creates a parent window for this instance (the menu window, NOT
+ the document window)
+ Sets the right colors for the window
+*/
+/* Returns FALSE if the initailization failed, TRUE if it succeeded */
+
+int FInitWinInfo( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
+HANDLE hInstance, hPrevInstance;
+LPSTR lpszCmdLine;
+int cmdShow;
+{
+ extern VOID (FAR PASCAL *lpfnRegisterPenApp)(WORD, BOOL);
+ extern CHAR szParentClass[];
+ extern int vfDiskError, vfDiskFull, vfSysFull;
+ extern PRINTDLG PD;
+
+ CHAR rgchCmdLine[ cchCmdLineMax ];
+ CHAR bufT[3]; /* to hold decimal point string */
+ CHAR *pch = bufT;
+ BOOL fRetVal;
+
+#if defined(OLE)
+ /*
+ The only place I'm worrying about this is when we open a file which
+ contains objects. Probably thats not enough, but its something.
+ Alas for users of real mode.
+ */
+ fOleEnabled = GetWinFlags() & WF_PMODE; /* Are we in real mode today? */
+#endif
+
+ /* Save the command line in a DS variable so we can pass a NEAR pointer */
+ bltszx( lpszCmdLine, (LPSTR)rgchCmdLine );
+
+ /* First thing, put up the hourglass cursor. */
+ if ((vhcHourGlass = LoadCursor( NULL, IDC_WAIT )) == NULL)
+ {
+ /* We don't even have enough memory to tell the user we don't have
+ enough memory. */
+ return (FALSE);
+ }
+
+ vfMouseExist = GetSystemMetrics(SM_MOUSEPRESENT);
+
+ /* Next, save the out of memory messages. */
+ hMmwModInstance = hInstance;
+ if ((hszCantRunM = HszCreateIdpmt( IDPMTCantRunM )) == NULL ||
+ (hszCantRunF = HszCreateIdpmt( IDPMTCantRunF )) == NULL ||
+ (hszWinFailure = HszCreateIdpmt( IDPMTWinFailure )) == NULL ||
+ (hszNoMemory = HszCreateIdpmt( IDPMTNoMemory )) == NULL ||
+ (hszDirtyDoc = HszCreateIdpmt( IDPMTDirtyDoc )) == NULL ||
+ (hszCantPrint = HszCreateIdpmt( IDPMTCantPrint )) == NULL ||
+ (hszPRFAIL = HszCreateIdpmt( IDPMTPRFAIL )) == NULL)
+ {
+ goto InzFailed;
+ }
+
+#if defined(INTL) && defined(WIN30)
+/* Initializaton of multi/intl strings. This is done before anything
+ else because many are defaults used for GetProfileString, etc. */
+
+ if (!FInitIntlStrings(hInstance))
+ goto InzFailed;
+#endif
+
+ /* Set up the standard cursors. */
+ if ( ((vhcIBeam = LoadCursor( NULL, IDC_IBEAM )) == NULL) ||
+ ((vhcArrow = LoadCursor( NULL, IDC_ARROW )) == NULL))
+ goto InzFailed;
+
+#ifdef PENWIN // for PenWindows (5/21/91) patlam
+ vhcPen =vhcIBeam;
+#endif
+
+
+ /* Set up the menu accelerator key table. */
+ if ((vhAccel = LoadAccelerators( hMmwModInstance, (LPSTR)szMw_acctb )) ==
+ NULL)
+ goto InzFailed;
+
+ /* Get whether to make backups during save from the user profile. */
+ vfBackupSave = GetProfileInt((LPSTR)szWriteProduct, (LPSTR)szBackup, 0) == 0
+ ? FALSE : TRUE;
+
+ /* Get the name of the null port from the user profile. */
+
+ GetProfileString((LPSTR)szWindows, (LPSTR)szNullPort, (LPSTR)szNone,
+ (LPSTR)szNul, cchMaxIDSTR);
+
+#ifdef INTL /* International version */
+ /* Get the country code. If US or UK, set utCur to be inches, else set
+ to cm */
+ {
+#if 0
+ /* codes from MSDOS country codes */
+#define USA (1)
+#define UK (44)
+
+ int iCountry;
+
+ GetProfileString((LPSTR)szIntl, (LPSTR)sziCountry, (LPSTR)sziCountryDefault,
+ (LPSTR)bufT, 4);
+ iCountry = WFromSzNumber (&pch);
+ if ((iCountry == USA) || (iCountry == UK))
+ utCur = utInch;
+#else
+ if (GetProfileInt((LPSTR)szIntl, (LPSTR)"iMeasure", 1) == 1)
+ utCur = utInch;
+ else
+ utCur = utCm;
+#endif
+ }
+
+#endif /* International version */
+
+ /* Get the decimal point character from the user profile. */
+ GetProfileString((LPSTR)szIntl, (LPSTR)szsDecimal, (LPSTR)szsDecimalDefault,
+ (LPSTR)bufT, 2);
+ vchDecimal = *bufT;
+
+ viDigits = GetProfileInt((LPSTR)szIntl, (LPSTR)"iDigits", 2);
+ vbLZero = GetProfileInt((LPSTR)szIntl, (LPSTR)"iLZero", 0);
+
+ MergeInit(); /* get message merge characters from resource file */
+
+#ifdef FONT_KLUDGE
+ AddFontResource( (LPSTR)"helv.fon" );
+#endif /* FONT_KLUDGE */
+
+ if (!hPrevInstance)
+ {
+ /* First time loaded; register the Write Windows. */
+ if (!FRegisterWnd( hMmwModInstance ))
+ {
+ return ( FALSE );
+ }
+
+ /* Get the Memo specific cursor. */
+ if ((vhcBarCur = LoadCursor( hMmwModInstance,
+ (GetSystemMetrics( SM_CXICON ) < 32) ||
+ (GetSystemMetrics( SM_CYICON ) < 32) ?
+ (LPSTR) szMwlores : (LPSTR) szMwhires )) == NULL)
+ goto InzFailed;
+ }
+ else /* not first time loaded; get data from previous instance */
+ {
+ if (!GetInstanceData( hPrevInstance,
+ (PSTR)&vhcBarCur, sizeof( vhcBarCur ) ))
+ goto InzFailed;
+ }
+
+#ifdef INEFFLOCKDOWN
+ /* Now initialize the pointers to far procedures (thunks). */
+ if (!FInitFarprocs( hMmwModInstance ))
+ goto InzFailed;
+#endif
+
+ /* Create our parent (tiled) window */
+ /* CreateWindow call generates a call to MmwCreate via message */
+ {
+ int cxFrame = GetSystemMetrics( SM_CXFRAME );
+ int cxBorder = GetSystemMetrics( SM_CXBORDER );
+ int cyBorder = GetSystemMetrics( SM_CYBORDER );
+ int x = ((cxFrame + 7) & 0xfff8) - cxFrame;
+
+ if ( CreateWindow(
+ (LPSTR)szParentClass,
+ (LPSTR)rgchCmdLine, /* don't pass lpszCmdLine; it will change! ..pault 2/22/90 */
+ WS_TILEDWINDOW,
+#ifdef WIN30
+/* This makes for nicer cascading of Write.exe invocations ..pault */
+ CW_USEDEFAULT, /* x */
+ CW_USEDEFAULT, /* y */
+ CW_USEDEFAULT, /* dx */
+ CW_USEDEFAULT, /* dy */
+#else
+ x, /* x */
+ x * cyBorder / cxBorder, /* y */
+ CW_USEDEFAULT, /* dx */
+ NULL, /* dy */
+#endif
+ (HWND)NULL, /* no parent */
+ (HMENU)NULL, /* use class menu */
+ (HANDLE)hInstance, /* handle to window instance */
+ (LPSTR)NULL /* no params to pass on */
+ ) == NULL)
+ /* Could not create window */
+ goto InzFailed;
+ }
+ if (fMessageInzFailed)
+ /* The create itself did not fail, but something in MmwCreate did
+ and it signals us via this global */
+ goto InzFailed;
+
+ Assert( hParentWw != NULL ); /* MmwCreate should have assured this */
+
+#if WINVER >= 0x300
+ vkMinus = VkKeyScan('-');
+#endif
+
+ /* Record the window foreground and background colors. */
+
+#ifdef DEBUG
+ {
+ int f =
+#endif
+
+ FSetWindowColors();
+
+#ifdef DEBUG
+ Assert (f);
+ }
+#endif
+
+ /* Select the background brush into the parent window. */
+
+ SelectObject( GetDC( hParentWw ), hbrBkgrnd );
+
+ /* Commdlg stuff (3.7.91) D. Kent */
+ if (InitCommDlg(0))
+ goto InzFailed;
+
+#ifdef PENWIN
+ if (lpfnRegisterPenApp = GetProcAddress(GetSystemMetrics(SM_PENWINDOWS),
+ "RegisterPenApp"))
+ {
+ (*lpfnRegisterPenApp)((WORD)1, fTrue); // be Pen-Enhanced
+ }
+
+ {
+ // This assumes no edit controls created in FInitWinInfo
+ HANDLE hLib;
+
+ if (lpfnProcessWriting = GetProcAddress(hLib = GetSystemMetrics(SM_PENWINDOWS),
+ "ProcessWriting"))
+ {
+ lpfnPostVirtualKeyEvent = GetProcAddress(hLib, "PostVirtualKeyEvent");
+ lpfnTPtoDP = GetProcAddress(hLib, "TPtoDP");
+ lpfnCorrectWriting = GetProcAddress(hLib, "CorrectWriting");
+ lpfnSymbolToCharacter = GetProcAddress(hLib, "SymbolToCharacter");
+
+ if ((vhcPen = LoadCursor( NULL, IDC_PEN )) == NULL)
+ goto InzFailed;
+ }
+ }
+
+#endif
+
+ /* init fields of the PRINTDLG structure (not used yet) */
+ PD.lStructSize = sizeof(PRINTDLG);
+ PD.hwndOwner = hParentWw;
+ // PD.hDevMode is already initialized
+ PD.hDevNames = NULL;
+ PD.hDC = NULL;
+ PD.Flags = PD_ALLPAGES; /* disable "pages" and "Selection" radiobuttons */
+ PD.nFromPage = 1;
+ PD.nToPage = 1;
+ PD.nMinPage = pgnMin; /* constant 1 */
+ PD.nMaxPage = pgnMax; /* largest integer */
+ PD.nCopies = 1;
+
+ /* initialize OLE stuff (1-23-91 dougk) */
+ if (!ObjInit(hInstance))
+ goto InzFailed;
+
+ /* Parse command line; load document & create an "mdoc" child window */
+
+ if (!FInitArgs(rgchCmdLine) || fMessageInzFailed)
+ /* Serious error -- bail out */
+ goto InzFailed;
+
+ /* Create a memory DC for the child window, to test that it works */
+
+ ValidateMemoryDC();
+ if (vhMDC == NULL)
+ goto InzFailed;
+
+ /* Make parent window visible after the child gets created; the order is
+ important and that the parent window is created without the visible bit on,
+ so that no size message is sent before child gets created */
+
+ //if (!fPrintOnly)
+ ShowWindow(hParentWw, cmdShow);
+
+ Diag(CommSz("---------------------------------------------------------------------------\n\r"));
+ vfInitializing = FALSE;
+ fRetVal = TRUE;
+
+FreeMsgs:
+ if (hszCantRunM != NULL)
+ GlobalFree( hszCantRunM );
+ if (hszCantRunF != NULL)
+ GlobalFree( hszCantRunF );
+ return fRetVal;
+
+InzFailed:
+ FreeMemoryDC( TRUE );
+ if (vhDCPrinter != NULL)
+ DeleteDC( vhDCPrinter);
+
+ if (hszWinFailure != NULL)
+ GlobalFree( hszWinFailure );
+ if (hszNoMemory != NULL)
+ GlobalFree( hszNoMemory );
+ if (hszDirtyDoc != NULL)
+ GlobalFree( hszDirtyDoc );
+ if (hszCantPrint != NULL)
+ GlobalFree( hszCantPrint );
+ if (hszPRFAIL != NULL)
+ GlobalFree( hszPRFAIL );
+
+ ferror = vfInitializing = FALSE; /* So the error report is not suppressed */
+ if (vfDiskFull || vfSysFull || vfDiskError)
+ Error(IDPMTCantRunF);
+ else
+ Error(IDPMTCantRunM);
+
+ fRetVal = FALSE;
+ goto FreeMsgs;
+}
+
+
+
+
+STATIC BOOL NEAR FRegisterWnd(hInstance)
+HANDLE hInstance;
+ {
+ /* This routine registers all of the window classes. TRUE is returned if
+ all of the windows classes were successfully registered; FALSE otherwise. */
+
+ extern CHAR szParentClass[];
+ extern CHAR szDocClass[];
+ extern CHAR szRulerClass[];
+ extern CHAR szPageInfoClass[];
+#ifdef ONLINEHELP
+ extern CHAR szHelpDocClass[];
+#endif
+
+ extern long FAR PASCAL MmwWndProc(HWND, unsigned, WORD, LONG);
+ extern long FAR PASCAL MdocWndProc(HWND, unsigned, WORD, LONG);
+ extern long FAR PASCAL RulerWndProc(HWND, unsigned, WORD, LONG);
+ extern long FAR PASCAL PageInfoWndProc(HWND, unsigned, WORD, LONG);
+
+#ifdef ONLINEHELP
+ extern long FAR PASCAL HelpDocWndProc(HWND, unsigned, WORD, LONG);
+#endif /* ONLINEHELP */
+
+ WNDCLASS Class;
+
+ /* Register our Window Proc */
+ bltbc( (PCH)&Class, 0, sizeof( WNDCLASS ) );
+ Class.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNCLIENT;
+ Class.lpfnWndProc = MmwWndProc;
+ Class.hInstance = hInstance;
+ Class.hCursor = vhcArrow;
+ Class.hIcon = LoadIcon( hInstance, (LPSTR)szMw_icon );
+ Class.lpszMenuName = (LPSTR)szMw_menu;
+ Class.lpszClassName = (LPSTR)szParentClass;
+ Class.hbrBackground = COLOR_WINDOW+1;
+
+ /* register the parent menu class with WINDOWS */
+ if (!RegisterClass( (LPWNDCLASS)&Class ) )
+ return FALSE; /* Initialization failed */
+
+ /* register memo document child window class */
+ bltbc( (PCH)&Class, 0, sizeof( WNDCLASS ) );
+ Class.style = CS_OWNDC | CS_DBLCLKS;
+ Class.lpfnWndProc = MdocWndProc;
+ Class.hInstance = hInstance;
+ Class.lpszClassName = (LPSTR)szDocClass;
+ if (!RegisterClass( (LPWNDCLASS)&Class ) )
+ return FALSE; /* Initialization failed */
+
+ /* register ruler child window class */
+ bltbc( (PCH)&Class, 0, sizeof( WNDCLASS ) );
+ Class.style = CS_OWNDC | CS_DBLCLKS;
+ Class.lpfnWndProc = RulerWndProc;
+ Class.hInstance = hInstance;
+ Class.hCursor = vhcArrow;
+ Class.lpszClassName = (LPSTR)szRulerClass;
+ if (!RegisterClass( (LPWNDCLASS)&Class ) )
+ return FALSE; /* Initialization failed */
+
+#ifdef ONLINEHELP
+ /* register Help document child window class */
+ bltbc( (PCH)&Class, 0, sizeof( WNDCLASS ) );
+ Class.style = CS_OWNDC;
+ Class.lpfnWndProc = HelpDocWndProc;
+ Class.hInstance = hInstance;
+ Class.lpszClassName = (LPSTR)szHelpDocClass;
+ if (!RegisterClass( (LPWNDCLASS)&Class ) )
+ return FALSE; /* Initialization failed */
+#endif /* ONLINE HELP */
+
+ /* register page info child window class */
+ bltbc( (PCH)&Class, 0, sizeof( WNDCLASS ) );
+ Class.style = CS_OWNDC;
+ Class.lpfnWndProc = PageInfoWndProc;
+ Class.hInstance = hInstance;
+ Class.hCursor = vhcArrow;
+ Class.lpszClassName = (LPSTR)szPageInfoClass;
+ if (!RegisterClass( (LPWNDCLASS)&Class ) )
+ return FALSE; /* Initialization failed */
+
+ return TRUE;
+ }
+
+
+#ifdef INEFFLOCKDOWN
+/* I've removed this for Windows 3.0 because (unless reasons come up
+ proving otherwise) it is inefficient for a Win program to lock-down
+ so many procedures like this for the entire time the app is running.
+ Originally thought to lock down the entire procedure; now understood only
+ to lock down the thunk. The principle still applies..pault 10/26/89 */
+
+STATIC int NEAR FInitFarprocs( hInstance )
+HANDLE hInstance;
+ {
+ /* This routine initializes all of the far pointer to procedures. */
+
+ extern FARPROC lpDialogOpen;
+ extern FARPROC lpDialogSaveAs;
+ extern FARPROC lpDialogConfirm;
+ extern FARPROC lpDialogPrinterSetup;
+ extern FARPROC lpDialogPrint;
+ extern FARPROC lpDialogRepaginate;
+ extern FARPROC lpDialogSetPage;
+ extern FARPROC lpDialogPageMark;
+ extern FARPROC lpDialogCancelPrint;
+ extern FARPROC lpDialogHelp;
+#ifdef ONLINEHELP
+ extern FARPROC lpDialogHelpInner;
+#endif /* ONLINEHELP */
+ extern FARPROC lpDialogGoTo;
+ extern FARPROC lpDialogFind;
+ extern FARPROC lpDialogChange;
+ extern FARPROC lpDialogCharFormats;
+ extern FARPROC lpDialogParaFormats;
+ extern FARPROC lpDialogRunningHead;
+ extern FARPROC lpDialogTabs;
+ extern FARPROC lpDialogDivision;
+ extern FARPROC lpDialogBadMargins;
+ extern FARPROC lpFontFaceEnum;
+ extern FARPROC lpFPrContinue;
+
+#ifdef INTL /* International version */
+ extern FARPROC lpDialogWordCvt;
+ extern BOOL far PASCAL DialogWordCvt(HWND, unsigned, WORD, LONG);
+#endif /* International version */
+
+ extern BOOL far PASCAL DialogOpen(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogSaveAs(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogPrinterSetup(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogPrint(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogCancelPrint(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogRepaginate(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogSetPage(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogPageMark(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogHelp(HWND, unsigned, WORD, LONG);
+#ifdef ONLINEHELP
+ extern BOOL far PASCAL DialogHelpInner(HWND, unsigned, WORD, LONG);
+#endif /* ONLINEHELP */
+ extern BOOL far PASCAL DialogGoTo(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogFind(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogChange(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogCharFormats(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogParaFormats(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogRunningHead(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogTabs(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogDivision(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogConfirm(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL DialogBadMargins(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL FontFaceEnum(LPLOGFONT, LPTEXTMETRIC, int, long);
+ extern BOOL far PASCAL FPrContinue(HDC, int);
+
+ if (
+ ((lpDialogPrinterSetup = MakeProcInstance(DialogPrinterSetup, hInstance))
+ == NULL) ||
+ ((lpDialogPrint = MakeProcInstance(DialogPrint, hInstance)) == NULL) ||
+ ((lpDialogSetPage = MakeProcInstance(DialogSetPage, hInstance)) == NULL)||
+ ((lpDialogRepaginate = MakeProcInstance(DialogRepaginate, hInstance))
+ == NULL) ||
+ ((lpDialogPageMark = MakeProcInstance(DialogPageMark, hInstance))
+ == NULL) ||
+ ((lpDialogCancelPrint = MakeProcInstance(DialogCancelPrint, hInstance))
+ == NULL) ||
+ ((lpDialogHelp = MakeProcInstance(DialogHelp, hInstance)) == NULL) ||
+#ifdef ONLINEHELP
+ ((lpDialogHelpInner = MakeProcInstance(DialogHelpInner, hInstance))
+ == NULL) ||
+#endif /* ONLINEHELP */
+ ((lpDialogGoTo = MakeProcInstance(DialogGoTo, hInstance)) == NULL) ||
+ ((lpDialogFind = MakeProcInstance(DialogFind, hInstance)) == NULL) ||
+ ((lpDialogChange = MakeProcInstance(DialogChange, hInstance)) == NULL) ||
+ ((lpDialogCharFormats = MakeProcInstance(DialogCharFormats, hInstance))
+ == NULL) ||
+ ((lpDialogParaFormats = MakeProcInstance(DialogParaFormats, hInstance))
+ == NULL) ||
+ ((lpDialogRunningHead = MakeProcInstance(DialogRunningHead, hInstance))
+ == NULL) ||
+ ((lpDialogTabs = MakeProcInstance(DialogTabs, hInstance)) == NULL) ||
+ ((lpDialogDivision = MakeProcInstance(DialogDivision, hInstance))
+ == NULL) ||
+ ((lpDialogConfirm = MakeProcInstance(DialogConfirm, hInstance)) == NULL)||
+ ((lpDialogBadMargins = MakeProcInstance(DialogBadMargins, hInstance))
+ == NULL) ||
+ ((lpFontFaceEnum = MakeProcInstance(FontFaceEnum, hInstance)) == NULL) ||
+ ((lpFPrContinue = MakeProcInstance(FPrContinue, hInstance)) == NULL)
+
+#ifdef INTL /* International version */
+ || ((lpDialogWordCvt = MakeProcInstance(DialogWordCvt, hInstance)) == NULL)
+#endif /* International version */
+ )
+ return FALSE;
+ return TRUE;
+ }
+#endif /* ifdef-INEFFLOCKDOWN */
+
+
+void MmwCreate(hWnd, lParam)
+HWND hWnd;
+LONG lParam;
+{
+ extern CHAR szPageInfoClass[];
+ HANDLE hSysMenu;
+ HDC hDC;
+ HBRUSH hbr;
+
+ Assert( hMmwModInstance != NULL ); /* Should have set up instance handle */
+
+ hParentWw = hWnd;
+ if ((vhMenu = GetMenu(hWnd)) == NULL)
+ goto Error;
+
+ /* set up font cache */
+ /* RgfceInit() placed in line for speed */
+ {
+ int ifce;
+ struct FCE *pfce;
+
+ for (ifce = 0; ifce < vifceMac; ifce++)
+ {
+ pfce = &rgfce[ifce];
+ pfce->pfceNext = &rgfce[(ifce + 1) % vifceMac];
+ pfce->pfcePrev = &rgfce[(ifce + vifceMac - 1) % vifceMac];
+ pfce->fmi.mpchdxp = pfce->rgdxp - chFmiMin;
+ pfce->fcidRequest.lFcid = fcidNil;
+ }
+
+ Assert(sizeof(rgfce[0].fcidRequest.lFcid)
+ == sizeof(rgfce[0].fcidRequest.strFcid));
+ vpfceMru = &rgfce[0];
+ vfcidScreen.lFcid = vfcidPrint.lFcid = fcidNil;
+ }
+
+/* set up page buffer, internal data structures, heap etc. */
+ if (!FInitMemory())
+ goto Error;
+
+ /* Create the horizontal scroll bar. The size is initialized to zero
+ because it will be reset later. */
+
+ if ((wwdCurrentDoc.hHScrBar = CreateWindow((LPSTR)szScrollBar, (LPSTR)NULL,
+ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_HORZ, 0, 0, 0, 0, hWnd,
+ NULL, hMmwModInstance, (LPSTR)NULL)) == NULL)
+ {
+ goto Error;
+ }
+ wwdCurrentDoc.sbHbar = SB_CTL;
+
+ /* Create the vertical scroll bar. The size is initialized to zero
+ because again it will be reset later. */
+
+ if ((wwdCurrentDoc.hVScrBar = CreateWindow((LPSTR)szScrollBar, (LPSTR)NULL,
+ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0, hWnd,
+ NULL, hMmwModInstance, (LPSTR)NULL)) == NULL)
+ {
+ goto Error;
+ }
+ wwdCurrentDoc.sbVbar = SB_CTL;
+
+#ifndef NOMORESIZEBOX
+ /* Create the size box. The size is initialized to zero because again it
+ will be reset later. */
+ if ((vhWndSizeBox = CreateWindow((LPSTR)szScrollBar, (LPSTR)NULL,
+ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBS_SIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL,
+ hMmwModInstance, (LPSTR)NULL)) == NULL)
+ {
+ goto Error;
+ }
+#endif
+
+ /* Create the page info window. Again, we'll worry about the sizing later.
+ */
+ if ((vhWndPageInfo = CreateWindow((LPSTR)szPageInfoClass, (LPSTR)NULL,
+ WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 0, 0, hWnd, NULL,
+ hMmwModInstance, (LPSTR)NULL)) == NULL)
+ {
+ goto Error;
+ }
+
+ /* Initialize the page info window. */
+ if ((hDC = GetDC(vhWndPageInfo)) == NULL || (hbr =
+ CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) == NULL)
+ {
+ goto Error;
+ }
+ if (SelectObject(hDC, hbr) == NULL)
+ {
+ DeleteObject(hbr);
+ goto Error;
+ }
+ SetBkMode(hDC, TRANSPARENT);
+#ifdef WIN30
+ /* If the user has their colors set with a TextCaption color of
+ black then this becomes hard to read! We just hardcode this
+ to be white since the background defaults to being black */
+ SetTextColor(hDC, (DWORD) -1);
+#else
+ SetTextColor(hDC, GetSysColor(COLOR_CAPTIONTEXT));
+#endif
+
+ /* Get the height and width of the scroll bars. */
+ dypScrlBar = GetSystemMetrics(SM_CYHSCROLL);
+ dxpScrlBar = GetSystemMetrics(SM_CXVSCROLL);
+
+ /* Set the ranges of the horizontal and vertical scroll bars. */
+ SetScrollRange(wwdCurrentDoc.hHScrBar, SB_CTL, 0, xpRightLim, TRUE);
+ SetScrollRange(wwdCurrentDoc.hVScrBar, SB_CTL, 0, drMax - 1, TRUE);
+
+ return;
+Error:
+ fMessageInzFailed = TRUE;
+}
+
+
+
+
+void MdocCreate(hWnd, lParam)
+register HWND hWnd;
+LONG lParam;
+{
+ vhWnd = wwdCurrentDoc.wwptr = hWnd;
+ wwdCurrentDoc.hDC = GetDC( hWnd );
+ if ( wwdCurrentDoc.hDC == NULL )
+ {
+ fMessageInzFailed = TRUE;
+ return;
+ }
+
+ /* Set the DC to transparent mode. */
+ SetBkMode( wwdCurrentDoc.hDC, TRANSPARENT );
+
+ /* Set the background and foreground colors. */
+ SetBkColor( wwdCurrentDoc.hDC, rgbBkgrnd );
+ SetTextColor( wwdCurrentDoc.hDC, rgbText );
+
+ /* Set the background brush. */
+ SelectObject( wwdCurrentDoc.hDC, hbrBkgrnd );
+
+}
+
+
+STATIC HANDLE NEAR HszCreateIdpmt(idpmt)
+int idpmt;
+{
+ /* Create a heap string and fill it with a string from the resource file. */
+ char szTmp[cchMaxSz];
+
+ return (LoadString(hMmwModInstance, idpmt, (LPSTR)szTmp, sizeof(szTmp)) == 0 ? NULL :
+ HszGlobalCreate(szTmp));
+}
+
+
+#if defined(INTL) && defined(WIN30)
+/* Routine to load some strings from write.rc. These strings
+ used to be placed in globdefs.h. fernandd 10/20/89 */
+
+BOOL FInitIntlStrings(hInstance)
+HANDLE hInstance;
+ {
+ extern CHAR szMode[30];
+ extern CHAR szWriteDocPrompt[25];
+ extern CHAR szScratchFilePrompt[25];
+ extern CHAR szSaveFilePrompt[25];
+ extern CHAR szAppName[10];
+ extern CHAR szUntitled[20];
+ extern CHAR sziCountryDefault[5];
+ extern CHAR szWRITEText[30];
+ extern CHAR szFree[15];
+ extern CHAR szNone[15];
+ extern CHAR szHeader[15];
+ extern CHAR szFooter[15];
+ extern CHAR szLoadFile[25];
+ extern CHAR szCvtLoadFile[45];
+ extern CHAR szAltBS[15];
+ extern CHAR *mputsz[];
+
+ if (LoadString(hInstance, IDSTRModeDef, (LPSTR)szMode, sizeof(szMode)) &&
+ LoadString(hInstance, IDSTRWriteDocPromptDef, (LPSTR)szWriteDocPrompt, sizeof(szWriteDocPrompt)) &&
+ LoadString(hInstance, IDSTRScratchFilePromptDef, (LPSTR)szScratchFilePrompt, sizeof(szScratchFilePrompt)) &&
+ LoadString(hInstance, IDSTRSaveFilePromptDef, (LPSTR)szSaveFilePrompt, sizeof(szSaveFilePrompt)) &&
+ LoadString(hInstance, IDSTRAppNameDef, (LPSTR)szAppName, sizeof(szAppName)) &&
+ LoadString(hInstance, IDSTRUntitledDef, (LPSTR)szUntitled, sizeof(szUntitled)) &&
+ LoadString(hInstance, IDSTRiCountryDefaultDef, (LPSTR)sziCountryDefault, sizeof(sziCountryDefault)) &&
+ LoadString(hInstance, IDSTRWRITETextDef, (LPSTR)szWRITEText, sizeof(szWRITEText)) &&
+ LoadString(hInstance, IDSTRFreeDef, (LPSTR)szFree, sizeof(szFree)) &&
+ LoadString(hInstance, IDSTRNoneDef, (LPSTR)szNone, sizeof(szNone)) &&
+ LoadString(hInstance, IDSTRHeaderDef, (LPSTR)szHeader, sizeof(szHeader)))
+ {
+ if (LoadString(hInstance, IDSTRFooterDef, (LPSTR)szFooter, sizeof(szFooter)) &&
+ LoadString(hInstance, IDSTRLoadFileDef, (LPSTR)szLoadFile, sizeof(szLoadFile)) &&
+ LoadString(hInstance, IDSTRCvtLoadFileDef, (LPSTR)szCvtLoadFile, sizeof(szCvtLoadFile)) &&
+ LoadString(hInstance, IDSTRAltBSDef, (LPSTR)szAltBS, sizeof(szAltBS)) &&
+ LoadString(hInstance, IDSTRInchDef, (LPSTR)mputsz[0], 6) &&
+ LoadString(hInstance, IDSTRCmDef, (LPSTR)mputsz[1], 6) &&
+ LoadString(hInstance, IDSTRP10Def, (LPSTR)mputsz[2], 6) &&
+ LoadString(hInstance, IDSTRP12Def, (LPSTR)mputsz[3], 6) &&
+ LoadString(hInstance, IDSTRPointDef, (LPSTR)mputsz[4], 6) &&
+ LoadString(hInstance, IDSTRLineDef, (LPSTR)mputsz[5], 6))
+ return(fTrue);
+ }
+ /* else */
+ return(fFalse);
+ }
+#endif
+
diff --git a/private/mvdm/wow16/write/insert.c b/private/mvdm/wow16/write/insert.c
new file mode 100644
index 000000000..adc7d6922
--- /dev/null
+++ b/private/mvdm/wow16/write/insert.c
@@ -0,0 +1,1729 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* insert.c -- MW insertion routines */
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOHDC
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+//#define NOATOM
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#define NOSTRERRORS
+#include "str.h"
+#include "propdefs.h"
+#include "fmtdefs.h"
+#include "fkpdefs.h"
+#include "ch.h"
+#include "winddefs.h"
+#include "fontdefs.h"
+#include "debug.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+#ifdef DBCS
+#include "dbcs.h"
+#endif
+
+/* E X T E R N A L S */
+
+extern HWND vhWnd; /* WINDOWS: Handle of the current document display window*/
+extern MSG vmsgLast; /* WINDOWS: last message gotten */
+extern HWND hParentWw; /* WINDOWS: Handle for parent (MENU) window */
+
+extern int vfSysFull;
+extern int vfOutOfMemory;
+extern int vxpIns;
+extern int vdlIns;
+extern struct PAP vpapAbs;
+extern struct UAB vuab;
+extern struct CHP vchpNormal;
+extern int vfSeeSel;
+extern int vfInsLast;
+extern struct FCB (**hpfnfcb)[];
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP CpMax();
+extern typeCP CpMin();
+extern CHAR rgchInsert[cchInsBlock]; /* Temporary insert buffer */
+extern typeCP cpInsert; /* Beginning cp of insert block */
+extern int ichInsert; /* Number of chars used in rgchInsert */
+extern struct CHP vchpInsert;
+extern int vfSelHidden;
+extern struct FKPD vfkpdParaIns;
+extern struct FKPD vfkpdCharIns;
+extern struct PAP vpapPrevIns;
+extern typeFC fcMacPapIns;
+extern typeFC fcMacChpIns;
+extern struct CHP vchpSel;
+extern struct FLI vfli;
+extern struct PAP *vppapNormal;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int docCur;
+extern struct WWD rgwwd[];
+extern struct DOD (**hpdocdod)[];
+extern int wwCur;
+extern struct CHP vchpFetch;
+extern struct SEP vsepAbs;
+extern int vfCommandKey;
+extern int vfShiftKey;
+extern int vfOptionKey;
+extern int vfInsEnd;
+extern typeCP cpWall;
+extern int vfDidSearch;
+extern int vdocParaCache;
+extern typeCP vcpFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern struct CHP vchpFetch;
+extern int ferror;
+extern BOOL vfInvalid;
+extern int docUndo;
+extern struct EDL *vpedlAdjustCp;
+extern int wwMac;
+extern int vfFocus;
+extern int vkMinus;
+
+#ifdef CASHMERE
+extern int vfVisiMode; /* Whether "show fmt marks" mode is on */
+extern int vwwCursLine; /* Window containing cursor */
+#endif
+
+extern int vfLastCursor; /* Whether up/down arrow xp goal position is valid */
+
+
+/* state of the cursor line */
+extern int vxpCursLine;
+extern int vypCursLine;
+extern int vdypCursLine;
+extern int vfInsertOn;
+
+/* G L O B A L S */
+/* The following used to be defined here */
+
+extern int vcchBlted; /* # chars blted to screen, before line update */
+extern int vidxpInsertCache; /* current index of insertion into char width cache */
+extern int vdlIns;
+extern int vxpIns;
+extern int vfTextBltValid;
+extern int vfSuperIns;
+extern int vdypLineSize;
+extern int vdypCursLineIns;
+extern int vdypBase;
+extern int vypBaseIns;
+extern int vxpMacIns;
+extern int vdypAfter;
+extern struct FMI vfmiScreen;
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/* Used in this module only */
+
+typeCP cpStart; /* Start cp of the replacement operation that an Insert is */
+typeCP cpLimInserted; /* Last cp inserted */
+typeCP cpLimDeleted; /* Last cp deleted */
+
+/* Enumerated type telling what to update */
+/* Ordering is such that larger numbers mean that there is more to update */
+
+#define mdInsUpdNothing 0
+#define mdInsUpdNextChar 1
+#define mdInsUpdOneLine 2
+#define mdInsUpdLines 3
+#define mdInsUpdWhole 4
+
+void NEAR FormatInsLine();
+void NEAR DelChars( typeCP, int );
+void NEAR EndInsert();
+int NEAR XpValidateInsertCache( int * );
+int NEAR FBeginInsert();
+
+#ifdef DBCS
+CHAR near GetDBCSsecond();
+BOOL FOptAdmitCh(CHAR, CHAR);
+int NEAR MdInsUpdInsertW( WORD, WORD, RECT *);
+#else
+int NEAR MdInsUpdInsertCh( CHAR, CHAR, RECT *);
+#endif /* ifdef DBCS */
+
+#ifdef KOREA
+int IsInterim, WasInterim;
+#endif
+
+
+#ifdef DEBUG
+int vTune = 0;
+#endif
+
+
+
+
+/* AlphaMode -- Handler for insertion, backspace, and forward delete
+
+ Alpha mode works by inserting a block of cchInsBlock cp's at the
+insertion point. The inserted piece has fn == fnInsert, cpMin == 0.
+We AdjustCp for this block as though it contained cchInsBlock cp's,
+even though it is initially "empty".
+
+ When a character is typed, it is inserted at rgchInsert[ ichInsert++ ].
+When rgchInsert is full, it is written to the scratch file, and
+Replace'd with a new insertion block.
+
+ AlphaMode exits when it encounters a key or event that it cannot handle
+(e.g. cursor keys, mouse hits). It then cleans up, writing the insertion
+block to the scratch file, and returns
+
+ "Fast Insert" is achieved by writing characters directly to the screen
+and scrolling the rest of the line out of the way. The line is not updated
+until it is necessary (or until we fall through the delay in KcInputNextKey).
+
+ During "Fast Insert" (or fast backspace or fast delete), it is important
+that ValidateTextBlt will usually NOT be called unless the line containing
+the insertion point has been made valid. Otherwise, ValidateTextBlt will
+fail to find a valid vdlIns, and call CpBeginLine, which forces an
+update of the entire screen.
+*/
+
+#ifdef KOREA /* global to MdUpIns 90.12.28 */
+int dxpCh;
+#endif
+
+
+/* A L P H A M O D E */
+AlphaMode( kc )
+int kc; /* Keyboard Character */
+{
+ int rgdxp[ ichMaxLine ];
+ int chShow, dlT, fGraphics;
+ int mdInsUpd;
+ int fDocDirty = (**hpdocdod) [docCur].fDirty;
+ register struct EDL *pedl;
+ int xpInsLineMac;
+
+ int fGotKey = fFalse;
+ int kcNext;
+ int fScrollPending = fFalse;
+ int dxpPending;
+ int fDelPending = fFalse;
+ typeCP cpPending;
+ int cchPending;
+ int mdInsUpdPending = mdInsUpdNothing;
+
+#ifdef DBCS
+ BOOL fResetMdInsUpd = TRUE; /* To avoid the blinking cursor at beg. doc or eod. */
+ CHAR chDBCS2 = '\0'; /* Used to hold the second byte of a DBCS character */
+#endif /* DBCS */
+
+#ifdef DBCS /* was in JAPAN */
+ if( kc == 0x000d )
+ kc = 0x000a;
+#endif
+
+ if (!FWriteOk( fwcReplace ))
+ { /* Not OK to write on docCur (read-only OR out of memory) */
+ _beep();
+ return;
+ }
+
+/* Shut down the caret blink timer -- we don't want its messages or its cost */
+
+#ifndef DBCS /* was in JAPAN */
+ KillTimer( vhWnd, tidCaret );
+#endif
+
+#ifdef OLDBACKSPACE
+/* Backspace in Win 3.0 has been changed to function
+ identically like the Delete key ..pault 6/20/89 */
+
+/* Handle BACKSPACE when there's a selection. DELETE with selection has already
+ been filtered out by KcAlphaKeyMessage */
+if (kc == kcDelPrev)
+ /* Make a selection at selection-start preparatory to deleting previous
+ char, which is accomplished in the loop. */
+ Select( selCur.cpFirst, selCur.cpFirst );
+#endif
+
+ /* Set up initial limits for UNDO */
+ cpStart = selCur.cpFirst; /* Starting cp for insertion */
+ cpLimDeleted = selCur.cpLim; /* Last cp Deleted */
+
+/* Delete the selection, and make an insert point selection in its stead */
+/* Insert point selection inherits the properties of the deleted text */
+ if (selCur.cpFirst < selCur.cpLim)
+ {
+ struct CHP chp;
+ typeCP cpT;
+
+ fDocDirty = TRUE;
+ cpT = selCur.cpFirst;
+ /* Get properties of the deleted text */
+ FetchCp(docCur, cpT, 0, fcmProps);
+ blt( &vchpFetch, &chp, cwCHP );
+ if (fnClearEdit(OBJ_INSERTING))
+ goto Abort;
+ UpdateWw( wwCur, FALSE );
+ if (ferror)
+ goto Abort;
+ Select(cpT, cpT);
+ blt( &chp, &vchpSel, cwCHP );
+ }
+ else
+ { /* Current selection is 0 chars wide, no need to delete */
+ /* Set up UNDO */
+ noUndo:
+ NoUndo(); /* Don't combine adjacent operations or
+ vuab.cp = cp in DelChars will be wrong */
+ SetUndo( uacDelNS, docCur, cpStart, cp0, docNil, cpNil, cp0, 0);
+ }
+
+ fGraphics = FBeginInsert();
+
+ Scribble( 7, (vfSuperIns ? 'S' : 'I') );
+
+ vfSelHidden = false;
+ vfTextBltValid = FALSE;
+
+ if (ferror)
+ /* Ran out of memory trying to insert */
+ goto Abort;
+
+ if (fGraphics)
+ {
+ selCur.cpFirst = selCur.cpLim = cpInsert + cchInsBlock;
+/* this is to display the paragraph that has been automatically inserted
+by edit in FBeginInsert */
+ UpdateWw(wwCur, fFalse);
+ if (kc == kcReturn)
+ kc = kcNil;
+ }
+
+ for ( ; ; (fGotKey ? (fGotKey = fFalse, kc = kcNext) : (kc = KcInputNextKey())) )
+ { /* Loop til we get a command key we can't handle */
+ /* KcInputNextKey will return kcNil if a nonkey */
+ /* event occurs */
+ RECT rc;
+#ifndef KOREA /* has been defined globally */
+ int dxpCh;
+#endif
+
+ typeCP cpFirstEdit=cpInsert + ichInsert;
+
+ chShow = kc;
+ mdInsUpd = mdInsUpdNothing;
+
+ /* Force exit from loop if out of heap or disk space */
+ if (vfSysFull || vfOutOfMemory)
+ kc = kcNil;
+
+#ifdef DBCS
+ if (kc != kcDelPrev && kc != kcDelNext) {
+ fResetMdInsUpd = TRUE;
+ }
+#endif /* DBCS */
+
+ if (!vfTextBltValid)
+ ValidateTextBlt();
+ Assert( vdlIns >= 0 );
+ pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
+ FreezeHp();
+
+ SetRect( (LPRECT)&rc, vxpIns+1, pedl->yp - pedl->dyp,
+ wwdCurrentDoc.xpMac,
+ min(pedl->yp, wwdCurrentDoc.ypMac));
+
+ vfli.doc = docNil;
+
+/* this is a speeder-upper of the switch below */
+ if (kc <= 0)
+ switch (kc)
+ {
+/*********************************************************************
+ ********** START OF BACKSPACE/FORWARD DELETE CODE *******************
+ *********************************************************************/
+ CHAR chDelete; /* Variables for Backspace/Delete */
+ typeCP cpDelete;
+ int cchDelete;
+ int idxpDelete;
+ int fCatchUp;
+#ifdef DBCS
+ typeCP cpT;
+
+ case kcDelNext: /* Delete following character */
+ cpT = selCur.cpFirst;
+ if (fDelPending) {
+ cpT += cchPending;
+ }
+ if (cpT >= cpMacCur) {
+ _beep();
+ MeltHp();
+ if (fResetMdInsUpd) {
+ mdInsUpd = mdInsUpdOneLine;
+ fResetMdInsUpd = FALSE;
+ }
+ goto DoReplace; /* Clean up pending replace ops */
+ }
+
+ cpDelete = CpFirstSty(cpT, styChar);
+ cchDelete = CpLimSty(cpDelete, styChar) - cpDelete;
+ goto DeleteChars;
+
+ case kcDelPrev: /* Delete previous char */
+ /* To reflect the state of cpPending and cchPending so that */
+ /* CpFirstSty( , styChar) is called with a proper cp. */
+ cpT = cpFirstEdit - 1;
+ if (fDelPending) {
+ cpT -= cchPending;
+ }
+ if (cpT < cpMinCur) {
+ _beep();
+ MeltHp();
+ if (fResetMdInsUpd) {
+ mdInsUpd = mdInsUpdOneLine;
+ fResetMdInsUpd = FALSE;
+ }
+ goto DoReplace;
+ }
+
+ cpDelete = CpFirstSty(cpT, styChar);
+ cchDelete = CpLimSty(cpDelete, styChar) - cpDelete;
+
+
+#else
+ case kcDelNext: /* Delete following character */
+ cpDelete = selCur.cpFirst;
+ if (fDelPending)
+ cpDelete += cchPending;
+
+ if (cpDelete >= cpMacCur)
+ {
+ _beep();
+ MeltHp();
+ goto DoReplace; /* Clean up pending replace ops */
+ }
+ FetchCp( docCur, cpDelete, 0, fcmChars );
+ chDelete = *vpchFetch;
+ cchDelete = 1;
+#ifdef CRLF
+ if ((chDelete == chReturn) && (*(vpchFetch+1) == chEol) )
+ {
+ cchDelete++;
+ chDelete = chEol;
+ }
+#endif
+ goto DeleteChars;
+
+ case kcDelPrev: /* Delete previous char */
+ /* Decide what char, cp we're deleting */
+ cpDelete = cpFirstEdit - 1;
+ if (fDelPending)
+ cpDelete -= cchPending;
+
+ if (cpDelete < cpMinCur)
+ {
+ _beep();
+ MeltHp();
+ goto DoReplace; /* Clean up pending replace ops */
+ }
+ FetchCp( docCur, cpDelete, 0, fcmChars );
+ chDelete = *vpchFetch;
+ cchDelete = 1;
+#ifdef CRLF
+ if ( (chDelete == chEol) && (cpDelete > cpMinCur) )
+ {
+ FetchCp( docCur, cpDelete - 1, 0, fcmChars );
+ if (*vpchFetch == chReturn)
+ {
+ cchDelete++;
+ cpDelete--;
+ }
+ }
+#endif
+#endif /* DBCS */
+
+DeleteChars:
+#ifdef DBCS
+ /* They expect chDelete as well as cpDelete and cchDelete */
+ FetchCp(docCur, cpDelete, 0, fcmChars);
+ chDelete = *vpchFetch;
+#endif
+
+ /* Here we have cpDelete, cchDelete */
+ /* Also cchPending and cpPending if fDelPending is TRUE */
+ /* Also dxpPending if fScrollPending is TRUE */
+
+ if ( CachePara( docCur, cpDelete ), vpapAbs.fGraphics)
+ { /* Trying to del over picture, illegal case */
+ _beep();
+ MeltHp();
+ goto DoReplace; /* Clean up pending replace ops */
+ }
+
+ /* Insert properties are now the properties of the
+ deleted char(s) */
+
+ FetchCp( docCur, cpDelete, 0, fcmProps );
+ vchpFetch.fSpecial = FALSE;
+ NewChpIns( &vchpFetch );
+
+ /* Pending replace operation <-- union of any pending
+ replace operations with the current one */
+
+ if (fDelPending)
+ {
+ if (cpPending >= cchDelete)
+ {
+ cchPending += cchDelete;
+ if (kc == kcDelPrev)
+ cpPending -= cchDelete;
+ }
+ else
+ Assert( FALSE );
+ }
+ else
+ {
+ cpPending = cpDelete;
+ cchPending = cchDelete;
+ fDelPending = TRUE;
+ }
+
+ /* Determine whether the screen update for the current
+ deletion can be accomplished by scrolling.
+ We can scroll if:
+ (1) we are still on the line vdlIns,
+ (2) we are not deleting eol or chsect,
+ (3) our width cache is good OR vdlIns is valid, so we can
+ validate the cache w/o redisplaying the line
+ */
+
+ mdInsUpd = mdInsUpdOneLine;
+ if ((idxpDelete = (int) (cpDelete - pedl->cpMin)) < 0)
+ {
+ mdInsUpd = mdInsUpdLines;
+ }
+ else if ((chDelete != chEol) && (chDelete != chSect) &&
+ (vidxpInsertCache != -1 || pedl->fValid) &&
+ (mdInsUpdPending < mdInsUpdOneLine))
+ { /* OK to scroll -- do all pending scrolls */
+ int fDlAtEndMark;
+ int fCatchUp;
+
+ MeltHp();
+ /* Re-entrant heap movement */
+ fCatchUp = FImportantMsgPresent();
+
+ if (vidxpInsertCache == -1)
+ { /* Width cache is invalid, update it */
+ xpInsLineMac = XpValidateInsertCache( rgdxp ); /* HM */
+ }
+
+ pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
+ FreezeHp();
+
+ /* Obtain display width of character to delete */
+
+ if ((vcchBlted > 0) && (kc == kcDelPrev))
+ { /* Deleted char was blted in superins mode
+ onto a line that has not been updated */
+ vcchBlted--;
+ /* Because chDelete is always 1 byte quantity
+ by itself or the 1st byte of the DBCS character
+ it is OK. */
+ dxpCh = DxpFromCh( chDelete, FALSE );
+ }
+ else
+ {
+ int idxpT = idxpDelete + cchDelete;
+
+#ifdef DBCS
+ /* For the following segment of code to work,
+ an element in rgdxp corresponding to the second
+ byte of a DBCS character must contain 0. */
+ int *pdxpT;
+ int cchT;
+
+ for (dxpCh = 0, pdxpT = &rgdxp[idxpDelete], cchT = 0;
+ cchT < cchDelete;
+ dxpCh += *pdxpT++, cchT++);
+#else
+ dxpCh = rgdxp[ idxpDelete ];
+#endif
+
+ /* Adjust the character width cache to eliminate
+ width entries for deleted chars */
+
+ if ((vidxpInsertCache >= 0) &&
+ (idxpDelete >= 0) &&
+ (idxpT <= pedl->dcpMac) )
+ {
+ blt( &rgdxp[ idxpT ], &rgdxp[ idxpDelete ],
+ ichMaxLine - idxpT );
+
+ if (vidxpInsertCache > idxpDelete)
+ /* Deleted behind insert point, adjust index */
+ vidxpInsertCache -= cchDelete;
+ }
+ else
+ vidxpInsertCache = -1;
+ }
+
+ /* pending scroll op <-- current scroll op merged
+ with pending scroll op */
+ if (fScrollPending)
+ {
+ dxpPending += dxpCh;
+ }
+ else
+ {
+ dxpPending = dxpCh;
+ fScrollPending = fTrue;
+ }
+
+ /* See if we should postpone the scroll */
+
+ if (fCatchUp)
+ {
+ MeltHp();
+ Assert( !fGotKey );
+ fGotKey = TRUE;
+ if ((kcNext = KcInputNextKey()) == kc)
+ { /* Next key is same as this key, process NOW */
+ continue;
+ }
+ FreezeHp();
+ }
+
+ /* Perform all pending scrolls */
+
+ fScrollPending = fFalse;
+ if (dxpPending > 0)
+ {
+ ClearInsertLine();
+ if (kc == kcDelPrev)
+ { /* Backspace */
+ vxpCursLine = (vxpIns -= dxpPending);
+ rc.left -= dxpPending;
+ }
+ ScrollCurWw( &rc, -dxpPending, 0 );
+ DrawInsertLine();
+ xpInsLineMac -= dxpPending;
+ }
+
+ /* See if we can get away without updating the screen
+ (and without invalidating the insert cache) */
+
+#define cchGetMore 4
+#define dxpGetMore ((unsigned)dxpCh << 3)
+
+ /* Check for running out of chars ahead of the cursor */
+
+ fDlAtEndMark = (pedl->cpMin + pedl->dcpMac >= cpMacCur);
+
+ if ( (kc != kcDelNext && fDlAtEndMark) ||
+ ((idxpDelete + cchGetMore < pedl->dcpMac) &&
+ ( (int) (xpInsLineMac - vxpIns) > dxpGetMore) ))
+ {
+ mdInsUpd = mdInsUpdNothing;
+ }
+
+ /* Special check to avoid two end marks: see if the
+ dl after the ins line is dirty and beyond the
+ doc's end */
+
+ if (fDlAtEndMark &&
+ (vdlIns < wwdCurrentDoc.dlMac - 1) &&
+ !(pedl+1)->fValid)
+ {
+ mdInsUpd = mdInsUpdLines;
+ }
+ } /* End of "if OK to scroll" */
+
+ /* See if we should postpone the replace */
+
+ MeltHp();
+ /* Re-entrant Heap Movement */
+ if (FImportantMsgPresent() && !fGotKey)
+ {
+ fGotKey = TRUE;
+ if ((kcNext = KcInputNextKey()) == kc)
+ { /* Next key is same as this key, process NOW */
+ if (mdInsUpd > mdInsUpdPending)
+ {
+ /* Mark screen update as pending */
+ mdInsUpdPending = mdInsUpd;
+ vidxpInsertCache = -1;
+ }
+ continue;
+ }
+ }
+
+ /* Handle actual replacement of chars */
+
+DoReplace: if (fDelPending)
+ {
+ DelChars( cpPending, cchPending ); /* HM */
+ fDelPending = fFalse;
+ }
+
+ /* Set up screen update based on present & pending needs */
+
+ if (mdInsUpdPending > mdInsUpd)
+ mdInsUpd = mdInsUpdPending;
+
+ if (mdInsUpd >= mdInsUpdOneLine)
+ /* If we're updating at least a line, assume we're
+ handling all necessary pending screen update */
+ mdInsUpdPending = mdInsUpdNothing;
+
+ /* Adjust vdlIns's dcpMac. vdlIns is invalid anyway,
+ and this allows us to catch the case
+ in which we run out of visible characters to scroll
+ in the forward delete case. See update test after
+ the scroll above */
+ (**wwdCurrentDoc.hdndl) [vdlIns].dcpMac -= cchPending;
+
+ /* this is here to compensate for RemoveDelFtnText */
+
+ selCur.cpFirst = selCur.cpLim = cpInsert + (typeCP)cchInsBlock;
+ cpFirstEdit = cpPending;
+
+ goto LInvalIns; /* Skip ahead to update the screen */
+/*********************************************************************
+ ************ END OF BACKSPACE/FORWARD DELETE CODE *******************
+ *********************************************************************/
+
+ case kcReturn: /* Substitute EOL for return key */
+ /* Also add a return if CRLF is on */
+ MeltHp();
+#ifdef CRLF
+#ifdef DBCS
+ MdInsUpdInsertW( MAKEWORD(0, chReturn),
+ MAKEWORD(0, chReturn), &rc );
+#else
+ MdInsUpdInsertCh( chReturn, chReturn, &rc );
+#endif /* DBCS */
+#endif
+ FreezeHp();
+ kc = chEol;
+ break;
+#ifdef CASHMERE /* These key codes are omitted from MEMO */
+ case kcNonReqHyphen: /* Substitute for non-required hyphen */
+ kc = chNRHFile;
+ chShow = chHyphen;
+ break;
+ case kcNonBrkSpace: /* Substitute for non-breaking space */
+ kc = chNBSFile;
+ chShow = chSpace;
+ break;
+ case kcNLEnter: /* Substitute for non-para return */
+ kc = chNewLine;
+ break;
+#endif
+#ifdef PRINTMERGE
+ case kcLFld: /* Substitite for Left PRINT MERGE bracket */
+ chShow = kc = chLFldFile;
+ break;
+ case kcRFld: /* Substitute for Right PRINT MERGE bracket */
+ chShow = kc = chRFldFile;
+ break;
+#endif
+ case kcPageBreak:
+ kc = chSect; /* Page break (no section) */
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ { /* Page breaks prohibited in header/footer */
+BadKey: _beep();
+ MeltHp();
+ continue;
+ }
+ break;
+ case kcTab: /* Tab */
+ kc = chTab;
+ break;
+ default:
+#if WINVER >= 0x300
+ if (kc == kcNonReqHyphen) /* Substitute for non-required hyphen */
+ {
+ /* no longer a const so can't be directly in switch */
+ kc = chNRHFile;
+ chShow = chHyphen;
+ break;
+ }
+#endif
+ /* AlphaMode Exit point: Found key or event
+ that we don't know how to handle */
+ MeltHp();
+ goto EndAlphaMode;
+ } /* end of if kc < 0 switch (kc) */
+ MeltHp();
+
+#ifdef DBCS
+ if (IsDBCSLeadByte(kc)) {
+ /* We are dealing with the first byte of the DBCS character. */
+ /* In case of DBCS letter, wInsert is equal to wShow. */
+
+ if ((chDBCS2 = GetDBCSsecond()) != '\0')
+ mdInsUpd = MdInsUpdInsertW( MAKEWORD(kc, chDBCS2),
+ MAKEWORD(kc, chDBCS2), &rc );
+ } else
+ mdInsUpd = MdInsUpdInsertW( MAKEWORD(0, kc), MAKEWORD(0, chShow), &rc);
+#else
+/* Insert character kc into the document. Show character chShow (which is
+equal to kc except for cases such as non-breaking space, etc. */
+ mdInsUpd = MdInsUpdInsertCh( kc, chShow, &rc );
+#endif /* DBCS */
+
+/* common for insert and backspace: invalidate line and previous line if
+dependency warrants it */
+/* have vdlIns from ValidateTextBlt */
+LInvalIns:
+ pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
+ pedl->fValid = fFalse;
+ wwdCurrentDoc.fDirty = fTrue;
+
+ Assert( vdlIns >= 0 );
+ if ((dlT = vdlIns) == 0)
+ { /* Editing in first line of window */
+ if ( wwdCurrentDoc.fCpBad ||
+ (wwdCurrentDoc.cpFirst + wwdCurrentDoc.dcpDepend > cpFirstEdit) )
+ { /* Edit affects ww's first cp; recompute it */
+ CtrBackDypCtr( 0, 0 );
+ (**wwdCurrentDoc.hdndl) [vdlIns].cpMin = CpMax( wwdCurrentDoc.cpMin,
+ wwdCurrentDoc.cpFirst );
+ mdInsUpd = mdInsUpdLines;
+ }
+ }
+ else
+ { /* If the edit affects the line prior to vdlIns, invalidate it */
+ --pedl;
+#ifdef DBCS
+ if (!IsDBCSLeadByte(kc)) {
+ chDBCS2 = kc;
+ kc = '\0';
+ }
+#endif /* DBCS */
+ if ((pedl->cpMin + pedl->dcpMac + pedl->dcpDepend > cpFirstEdit))
+ {
+ pedl->fValid = fFalse;
+ dlT--;
+ }
+#ifdef DBCS /* was in JAPAN; KenjiK '90-11-03 */
+ // deal with the character beyond end of the line.
+ else
+#ifdef KOREA /* protect from displaying picture abnormally */
+ if(((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2))
+ && !pedl->fGraphics)
+#else
+ if ((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2))
+#endif
+ {
+ /* We do exactly the same as above, except setting
+ mdInsUpd, because the one returned by MdInsUpdInsertW()
+ does not reflect this condition. */
+ pedl->fValid = fFalse;
+ dlT--;
+ mdInsUpd = mdInsUpdOneLine;
+ }
+#endif
+ else
+ pedl++;
+ }
+#ifdef ENABLE /* We now support end-of-line cursor while inserting because of
+ typing before splats */
+ if (vfInsEnd)
+ { /* forget about special end-of-line cursor */
+ vfInsEnd = fFalse;
+ ClearInsertLine();
+ }
+#endif
+
+#ifdef KOREA /* 90.12.28 sangl */
+{
+BOOL UpNext=FALSE;
+screenup:
+#endif
+
+ switch (mdInsUpd) {
+
+ default:
+ case mdInsUpdNothing:
+ case mdInsUpdNextChar:
+ break;
+ case mdInsUpdLines:
+ case mdInsUpdOneLine:
+ ClearInsertLine();
+ if ( FUpdateOneDl( dlT ) )
+ { /* Next line affected */
+ struct EDL *pedl;
+
+ if ( (mdInsUpd == mdInsUpdLines) ||
+ /* Re-entrant heap movement */
+ !FImportantMsgPresent() ||
+ (pedl = &(**wwdCurrentDoc.hdndl) [dlT],
+ (selCur.cpFirst >= pedl->cpMin + pedl->dcpMac)))
+ {
+ FUpdateOneDl( dlT + 1 );
+ }
+ }
+#ifdef KOREA /* 90.12.28 sangl */
+ else if (UpNext && ((dlT+1) < wwdCurrentDoc.dlMac))
+ FUpdateOneDl(dlT + 1);
+#endif
+ ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue);
+ break;
+
+ case mdInsUpdWhole:
+ ClearInsertLine();
+ UpdateWw(wwCur, fFalse);
+ ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue);
+ break;
+ } /* end switch (mdInsUpd) */
+#ifdef KOREA /* 90.12.28 sangl */
+ if (IsInterim) {
+ if (mdInsUpd>=mdInsUpdOneLine) {
+ ClearInsertLine();
+ vxpCursLine -= dxpCh;
+ DrawInsertLine();
+ }
+ while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) );
+ chDBCS2 = GetDBCSsecond();
+ mdInsUpd = MdInsUpdInsertW(MAKEWORD(kc, chDBCS2),
+ MAKEWORD(kc, chDBCS2), &rc);
+ if (vfSuperIns)
+ goto LInvalIns; /* This is for large size, when 1st interim
+ becomes final (ex, consonants) */
+ else {
+ UpNext = TRUE; /* For italic, try to FUpdateOneDl for
+ current line */
+ goto screenup; /* 90.12.28 sangl */
+ }
+ } /* ex: all consonants */
+} /* For screenup: 90.12.28 sangl */
+ if (WasInterim)
+ { MSG msg;
+ int wp;
+
+ if (PeekMessage ((LPMSG)&msg, vhWnd, WM_KEYDOWN, WM_KEYUP, PM_NOYIELD | PM_NOREMOVE) )
+ { if( msg.message==WM_KEYDOWN &&
+ ( (wp=msg.wParam)==VK_LEFT || wp==VK_UP || wp==VK_RIGHT ||
+ wp==VK_DOWN || wp==VK_DELETE) )
+ goto EndAlphaMode;
+ }
+ WasInterim = 0;
+ }
+#endif /* KOREA */
+ } /* end for */
+
+EndAlphaMode:
+
+ Scribble( 7, 'N' );
+ EndInsert(); /* Clean Up Insertion Block */
+#ifdef CASHMERE
+ UpdateOtherWws(fFalse);
+#endif
+
+ if (cpLimInserted != cpStart)
+ { /* We inserted some characters */
+ SetUndo( uacInsert, docCur, cpStart,
+ cpLimInserted - cpStart, docNil, cpNil, cp0, 0 );
+ SetUndoMenuStr(IDSTRUndoTyping);
+ }
+ else if (cpLimDeleted == cpStart)
+ /* This AlphaMode invocation had no net effect */
+ {
+Abort:
+ NoUndo();
+ if (!fDocDirty)
+ /* The doc was clean when we started, & we didn't change it, so
+ it's still clean */
+ (**hpdocdod) [docCur].fDirty = FALSE;
+ }
+
+ vfLastCursor = fFalse; /* Tells MoveUpDown to recalc its xp seek position */
+ if (vfFocus)
+ {
+ /* Restore the caret blink timer */
+ SetTimer( vhWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL );
+ }
+ else
+ {
+ ClearInsertLine();
+ }
+
+ /* Backspaces/deletes may have changed vchpSel -- update it */
+
+ blt( &vchpInsert, &vchpSel, cwCHP );
+
+#ifdef KOREA
+ if (WasInterim)
+ { MoveLeftRight(kcLeft);
+ WasInterim = 0;
+ vfSeeSel = TRUE;
+ }
+ else
+ vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
+#else
+ vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
+#endif
+}
+
+
+
+/* F B E G I N I N S E R T */
+/* Prepare for start of insertion */
+/* returns true iff inserting in front of a pic */
+int NEAR FBeginInsert()
+{
+ int fGraphics;
+ typeCP cp = selCur.cpFirst;
+ typeCP cpFirstPara;
+ cpInsert = cp;
+
+/* We expect the caller to have deleted the selection already */
+
+ Assert (selCur.cpLim == selCur.cpFirst);
+
+/* Use super-fast text insertion unless we are inserting italics */
+ CachePara(docCur, cp);
+ cpFirstPara = vcpFirstParaCache;
+ fGraphics = vpapAbs.fGraphics;
+ vfSuperIns = !vchpSel.fItalic;
+ vchpSel.fSpecial = fFalse;
+ NewChpIns(&vchpSel);
+
+ ichInsert = 0; /* Must Set this BEFORE calling Replace */
+
+/* Insert the speeder-upper QD insert block. Note: we invalidate since there
+will be a character inserted anyway, plus to make sure that the line
+length gets updated ("Invalidate" refers to the choice of Replace() over
+the Repl1/AdjustCp/!vfInvalid mechanism used in EndInsert, in which the
+insert dl is not made invalid). It would be possible to optimize
+by NOT invalidating here (thus being able to blt the first char typed),
+but one would have to account for the case in which the cpMin of the
+insert dl is changed by AdjustCp, or FUpdateOneDl will get messed up.
+Currently this case is covered by an implicit UpdateWw, which occurs
+in AlphaMode->ValidateTextBlt->CpBeginLine because we have invalidated vdlIns. */
+
+ Replace(docCur, cpInsert, cp0, fnInsert, fc0, (typeFC) cchInsBlock);
+ cpLimInserted = cpInsert + cchInsBlock;
+
+ vidxpInsertCache = -1; /* Char width cache for insert line is initially empty */
+
+ /* Blank the mouse cursor so it doesn't make the display look ugly
+ or slow us down trying to keep it up to date */
+ SetCursor( (HANDLE) NULL );
+ return fGraphics;
+}
+
+
+
+
+/* E N D I N S E R T */
+void NEAR EndInsert()
+{ /* Clean up from quick insert mode */
+ int dcp = cchInsBlock - ichInsert;
+ typeFC fc;
+
+#ifdef CASHMERE
+ UpdateOtherWws(fTrue);
+#endif
+
+ fc = FcWScratch(rgchInsert, ichInsert);
+#if WINVER >= 0x300
+ if (!vfSysFull)
+ /* The "tape dispenser bug replication method" has shown that
+ holding down a key for 64k presses will cause FcWScratch()
+ to run out of scratch-file space and fail. If we go ahead
+ with the Replacement we'll corrupt the piece table, so we
+ delicately avoid that problem 3/14/90..pault */
+#endif
+ {
+ Repl1(docCur, cpInsert, (typeCP) cchInsBlock, fnScratch, fc, (typeFC) ichInsert);
+ cpLimInserted -= (cchInsBlock - ichInsert);
+/* adjust separately, since first ichInsert characters have not changed at all */
+ vfInvalid = fFalse;
+ vpedlAdjustCp = (struct EDL *)0;
+ AdjustCp(docCur, cpInsert + ichInsert, (typeCP) dcp, (typeFC) 0);
+/* if the line is not made invalid, the length of the line
+must be maintained.
+*/
+ if (vpedlAdjustCp)
+ vpedlAdjustCp->dcpMac -= dcp;
+ }
+
+ vfInvalid = fTrue;
+
+ cpWall = selCur.cpLim;
+ vfDidSearch = fFalse;
+
+ if (!vfInsertOn)
+ DrawInsertLine();
+}
+
+
+
+
+
+/* N E W C H P I N S */
+NewChpIns(pchp)
+struct CHP *pchp;
+{ /* Make forthcoming inserted characters have the look in pchp */
+
+ if (CchDiffer(&vchpInsert, pchp, cchCHP) != 0)
+ { /* Add the run for the previous insertion; our looks differ. */
+ typeFC fcMac = (**hpfnfcb)[fnScratch].fcMac;
+
+ if (fcMac != fcMacChpIns)
+ {
+ AddRunScratch(&vfkpdCharIns, &vchpInsert, &vchpNormal, cchCHP, fcMac);
+ fcMacChpIns = fcMac;
+ }
+ blt(pchp, &vchpInsert, cwCHP);
+ }
+}
+
+
+
+#ifdef DBCS
+int NEAR MdInsUpdInsertW(wInsert, wShow, prcScroll)
+ WORD wInsert; /* Char or 2 char's to insert into document */
+ WORD wShow; /* Char or 2 char's to be shown on screen (SuperIns mode only) */
+ RECT *prcScroll; /* Rect to scroll for SuperIns */
+#else
+int NEAR MdInsUpdInsertCh( chInsert, chShow, prcScroll )
+CHAR chInsert; /* Char to insert into document */
+CHAR chShow; /* Char to show on screen (SuperIns mode only) */
+RECT *prcScroll; /* Rect to scroll for SuperIns */
+#endif /* DBCS */
+{ /* Insert character ch into the document. Show char chShow. */
+ /* Flush the insert buffer to the scratch file if it fills up */
+ /* Return: mdInsUpdWhole - Must do an UpdateWw
+ mdInsUpdNextChar - Update not mandatory, char waiting
+ mdInsUpdLines - Must update vdlIns and maybe following
+ mdInsUpdNothing - No update needed & no char waiting
+ mdInsUpdOneLine - Update vdlIns; only update following
+ if there's no char waiting
+ */
+extern int vfInsFontTooTall;
+void NEAR FlushInsert();
+int mdInsUpd;
+
+#ifndef KOREA /* has been defined globally */
+int dxpCh;
+#endif
+
+int dl;
+
+#ifdef DBCS
+CHAR chInsert;
+CHAR chShow;
+BOOL fDBCSChar;
+int ichInsertSave;
+int dcchBlted;
+#endif /* DBCS */
+
+#ifdef KOREA
+ if (IsInterim)
+ ichInsert -= 2;
+#endif
+
+#ifdef DIAG
+{
+char rgch[200];
+wsprintf(rgch, "MdInsUpdInsertCh: ichInsert %d cpInsert %lu\n\r ",ichInsert, cpInsert);
+CommSz(rgch);
+}
+#endif
+
+ Assert(ichInsert <= cchInsBlock);
+ if (ichInsert >= cchInsBlock) /* Should never be >, but... */
+ FlushInsert();
+
+#ifdef DBCS
+ ichInsertSave = ichInsert;
+ if (HIBYTE(wInsert) != '\0') {
+ fDBCSChar = TRUE;
+
+#ifdef KOREA /* 90.12.28 sangl */
+ if (LOBYTE(HIWORD(vmsgLast.lParam)) == 0xF0)
+ {
+ dxpCh = DxpFromCh( wInsert, FALSE );
+ IsInterim ++;
+ }
+ else
+ {
+ WasInterim = IsInterim;
+ IsInterim = 0;
+ }
+#endif
+
+ if (ichInsert + 1 >= cchInsBlock) { /* Not enough room in the insertion block */
+ FlushInsert();
+#ifdef KOREA
+ ichInsertSave = ichInsert; /* After flush, need to init ichInsertSave */
+#endif
+ }
+ rgchInsert[ichInsert++] = chInsert = HIBYTE(wInsert);
+ chShow = HIBYTE(wShow);
+ }
+ else {
+ fDBCSChar = FALSE;
+ chInsert = LOBYTE(wInsert);
+ chShow = LOBYTE(wShow);
+ }
+ rgchInsert [ ichInsert++ ] = LOBYTE(wInsert);
+#else
+ rgchInsert [ ichInsert++ ] = chInsert;
+#endif /* DBCS */
+
+ /* NOTE: we only affect the para cache if the char inserted is Eol/chSect.
+ We explicitly invalidate in this case below; otherwise, no invalidation
+ is necessary */
+
+ /* The following test works because chEol and chSect is not in
+ the DBCS range. */
+
+ if ( (chInsert == chEol) || (chInsert == chSect) )
+ { /* Add a paragraph run to the scratch file */
+ struct PAP papT;
+
+ /* Must invalidate the caches */
+ vdocParaCache = vfli.doc = docNil;
+
+#ifdef DBCS
+ Assert(!fDBCSChar); /* Of course, you can't be too careful */
+#endif /* DBCS */
+ /* Get props for new para mark */
+ /* NOTE: Under the new world, CachePara does not expect to ever */
+ /* see an Eol in the insertion piece */
+ ichInsert--;
+ CachePara( docCur, cpInsert + cchInsBlock );
+ papT = vpapAbs;
+ ichInsert++;
+
+#ifdef DEBUG
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ {
+ Assert( papT.rhc != 0 );
+ }
+#endif
+
+ /* Write insert buf out to the scratch file */
+ EndInsert();
+
+ /* Add run for new para properties to the scratch file */
+ AddRunScratch( &vfkpdParaIns,
+ &papT,
+ vppapNormal,
+ ((CchDiffer( &papT, &vpapPrevIns, cchPAP ) == 0) &&
+ (vfkpdParaIns.brun != 0)) ? -cchPAP : cchPAP,
+ fcMacPapIns = (**hpfnfcb)[fnScratch].fcMac );
+ blt( &papT, &vpapPrevIns, cwPAP );
+
+ /* Add a new insertion piece to the doc and we're ready to go again */
+ InvalidateCaches( docCur );
+ FBeginInsert();
+ mdInsUpd = mdInsUpdWhole; /* Must update the whole screen */
+ }
+ else if ( vfSuperIns && (chInsert != chNewLine) && (chInsert != chTab) &&
+ (chInsert != chNRHFile ) && (chInsert != chReturn) &&
+ !vfInsFontTooTall )
+ { /* We can do a superfast insert of this char */
+ ClearInsertLine();
+
+#ifdef DBCS
+ /* Because chShow contains the first byte of a DBCS character,
+ even when it is a DBCS character, the following call
+ to DxpFromCh() is OK. */
+
+#ifdef KOREA
+ if (fDBCSChar)
+ dxpCh = DxpFromCh(wShow, FALSE);
+ else
+ dxpCh = DxpFromCh(chShow, FALSE);
+#else
+ dxpCh = DxpFromCh( chShow, FALSE );
+#endif
+
+ if( dxpCh > 0 ){
+ dxpCh *= IsDBCSLeadByte(chShow) ? 2 : 1;
+ ScrollCurWw( prcScroll, dxpCh, 0 );
+ }
+
+ TextOut( wwdCurrentDoc.hDC,
+ vxpIns + 1,
+ vypBaseIns - vfmiScreen.dypBaseline,
+ (LPSTR) &rgchInsert[ichInsertSave],
+ dcchBlted = fDBCSChar ? 2 : 1 );
+#ifdef KOREA /* 90.12.28 sangl */
+ if ( IsInterim )
+ { unsigned kc;
+ int dxpdiff;
+ SetBkMode( wwdCurrentDoc.hDC, 2); /* Set to OPAQUR mode */
+ do { DrawInsertLine();
+ while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) );
+ rgchInsert[ichInsertSave] = kc;
+ rgchInsert[ichInsertSave+1] = GetDBCSsecond();
+ ClearInsertLine();
+ wShow = (kc<<8) + rgchInsert[ichInsertSave+1];
+ prcScroll->left += dxpCh; /* New left start of rect */
+ dxpdiff = -dxpCh; /* Save last dxpCh to go back */
+ dxpCh = DxpFromCh(wShow, FALSE); /* Get dxpCh of curr interim */
+ dxpdiff += dxpCh;
+ if (dxpdiff < 0)
+ prcScroll->left += dxpdiff;
+ ScrollCurWw(prcScroll, dxpdiff, 0);
+ TextOut( wwdCurrentDoc.hDC,
+ vxpIns + 1,
+ vypBaseIns - vfmiScreen.dypBaseline,
+ (LPSTR)&rgchInsert[ichInsertSave], 2);
+ } while (LOBYTE(HIWORD(vmsgLast.lParam))==0xF0); /* End of If Hangeul */
+ WasInterim = 1;
+ IsInterim = 0;
+ SetBkMode(wwdCurrentDoc.hDC, 1); /* Reset to TRANS mode */
+ }
+#endif /* KOREA */
+
+ vcchBlted += dcchBlted;
+#else
+ /* Because chShow contains the first byte of a DBCS character,
+ even when it is a DBCS character, the following call
+ to DxpFromCh() is OK. */
+
+ if ((dxpCh = DxpFromCh( chShow, FALSE )) > 0)
+ ScrollCurWw( prcScroll, dxpCh, 0 );
+
+ TextOut( wwdCurrentDoc.hDC,
+ vxpIns + 1,
+ vypBaseIns - vfmiScreen.dypBaseline,
+ (LPSTR) &chShow,
+ 1 );
+ vcchBlted++;
+#endif /* DBCS */
+
+ vxpCursLine = (vxpIns += dxpCh);
+ DrawInsertLine();
+
+ /* Decide whether we have affected the next dl with this insertion */
+
+ if ( vxpIns >= vxpMacIns )
+ mdInsUpd = mdInsUpdLines;
+ else if (!FImportantMsgPresent())
+ { /* No chars waiting; check for optional line update (word wrap) */
+ if ((dl = vdlIns) < wwdCurrentDoc.dlMac - 1)
+ {
+ vfli.doc = docNil;
+ FormatInsLine(); /* Update vfli for vdlIns */
+
+ mdInsUpd = (vfli.cpMac != (**wwdCurrentDoc.hdndl) [dl + 1].cpMin) ?
+ (FImportantMsgPresent() ? mdInsUpdNextChar : mdInsUpdOneLine) :
+ mdInsUpdNothing;
+ }
+ }
+ else
+ /* Don't update; pay attention to the next character */
+ mdInsUpd = mdInsUpdNextChar;
+ }
+ else if (vfSuperIns)
+ { /* In SuperInsMode but have a char we can't handle in SuperIns mode */
+ mdInsUpd = (vfInsFontTooTall) ? mdInsUpdWhole : mdInsUpdLines;
+ }
+ else
+ { /* Non-superfast insertion; update line if we have to */
+ vfli.doc = docNil;
+ FormatInsLine(); /* Update vfli for vdlIns */
+
+ /* Do the update only if: (1) the selection is no longer on
+ the current line OR (2) No char is waiting */
+#ifdef KOREA
+ mdInsUpd = mdInsUpdLines;
+#else
+ mdInsUpd = ( (selCur.cpFirst < vfli.cpMin) ||
+ (selCur.cpFirst >= vfli.cpMac) ||
+ !FImportantMsgPresent() ) ? mdInsUpdLines : mdInsUpdNextChar;
+#endif
+ }
+
+ Scribble( 10, mdInsUpd + '0' );
+ return mdInsUpd;
+}
+
+
+
+
+void NEAR FlushInsert()
+{ /* Flush the insert buffer to the scratch file. Insert a piece (ahead of
+ the QD insertion piece) that points to the characters flushed to the
+ scratch file. Adjust CP's for the addition of the new scratch file
+ piece. */
+
+#ifdef DBCS
+ /* The DBCS version of FlushInsert() is almost identical to the regular
+ version, except it allows to insert an insertion block with one byte
+ less than full. This allows us to assume that the piece boundary aligns
+ with the DBCS boundary. */
+ typeFC fc = FcWScratch( rgchInsert, ichInsert );
+ int dcpDel;
+
+#if WINVER >= 0x300
+ if (!vfSysFull)
+ /* The "tape dispenser bug replication method" has shown that
+ holding down a key for 64k presses will cause FcWScratch()
+ to run out of scratch-file space and fail. If we go ahead
+ with the Replacement we'll corrupt the piece table, so we
+ delicately avoid that problem 3/14/90..pault */
+#endif
+ {
+ Assert( cchInsBlock - ichInsert <= 1);
+ Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) ichInsert );
+
+ cpLimInserted += ichInsert;
+
+ vfInvalid = fFalse;
+ vpedlAdjustCp = (struct EDL *) 0;
+ AdjustCp( docCur, cpInsert += ichInsert, (typeCP) (dcpDel = cchInsBlock - ichInsert),
+ (typeCP) cchInsBlock );
+ if (vpedlAdjustCp)
+ vpedlAdjustCp->dcpMac += (cchInsBlock - dcpDel);
+ }
+#else
+ typeFC fc = FcWScratch( rgchInsert, cchInsBlock );
+
+#if WINVER >= 0x300
+ if (!vfSysFull)
+ /* The "tape dispenser bug replication method" has shown that
+ holding down a key for 64k presses will cause FcWScratch()
+ to run out of scratch-file space and fail. If we go ahead
+ with the Replacement we'll corrupt the piece table, so we
+ delicately avoid that problem 3/14/90..pault */
+#endif
+ {
+ Assert( ichInsert == cchInsBlock );
+ Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) cchInsBlock );
+
+ cpLimInserted += cchInsBlock;
+
+ vfInvalid = fFalse;
+ vpedlAdjustCp = (struct EDL *) 0;
+ AdjustCp( docCur, cpInsert += cchInsBlock, (typeCP) 0, (typeFC) cchInsBlock );
+ if (vpedlAdjustCp)
+ vpedlAdjustCp->dcpMac += cchInsBlock;
+ }
+#endif /* DBCS */
+
+ vfInvalid = fTrue;
+ ichInsert = 0;
+}
+
+
+
+
+int NEAR XpValidateInsertCache( rgdxp )
+int *rgdxp;
+{ /* Validate the contents of the insert width cache, consisting of:
+ (parm) rgdxp: table of widths of chars on the current insert
+ line (vdlIns) as last DisplayFli'd
+ (global) vidxpInsertCache: -1 if invalid, index of current
+ insert point otherwise
+ (return value) xpMac: Mac pixel used on the insert line
+ */
+ int xpMac;
+
+ Assert( vidxpInsertCache == -1 );
+
+ vfli.doc = docNil; /* Force FormatLine to act */
+
+ /* Assert that FormatLine results will match screen contents */
+ Assert( (**wwdCurrentDoc.hdndl)[vdlIns].fValid );
+
+ /* Build vfli from insert line, extract cache info */
+
+ FormatInsLine();
+ blt( vfli.rgdxp, rgdxp, ichMaxLine );
+ xpMac = umin( vfli.xpRight + xpSelBar, wwdCurrentDoc.xpMac );
+ Assert( vcchBlted == 0);
+ vidxpInsertCache = (int) (cpInsert + ichInsert - vfli.cpMin);
+
+ Assert( vidxpInsertCache >= 0 && vidxpInsertCache < vfli.cpMac - vfli.cpMin);
+ return xpMac;
+}
+
+
+
+void NEAR DelChars( cp, cch )
+typeCP cp;
+int cch;
+{ /* Delete cch characters at cp in docCur.
+
+ We expect the request to be as results from repeated backspaces
+ or forward deletes (not both); that is, the whole range extends
+ backwards from (cpInsert + ichInsert) (non-inclusive) or forward from
+ (cpInsert + cchInsBlock) (inclusive).
+
+ We do not mark the vfli cache invalid, for speed.
+ The Fast insert stuff will mark it invalid when it needs to.
+ */
+
+ int cchNotInQD;
+ typeCP cpUndoAdd;
+ int cchNewDel=0;
+
+ Assert( (cp == cpInsert + cchInsBlock) || /* Fwd Deletes */
+ (cp + cch == cpInsert + ichInsert)); /* Backsp */
+
+ cchNotInQD = cch - ichInsert;
+ if (cp + cchNotInQD == cpInsert)
+ { /* BACKSPACE */
+
+ if (cchNotInQD <= 0)
+ { /* All deleted chars were in the QD buffer */
+ ichInsert -= cch;
+
+ /* Do not mark the para cache invalid -- we have not affected
+ the para cache world, since there are never chSect/chEol in
+ the QD buffer, and we have not adjusted cp's */
+ return;
+ }
+ else
+ { /* Backspacing before the QD buffer */
+ ichInsert = 0;
+
+ if (cpStart > cp)
+ {
+ cpUndoAdd = cp0;
+ cchNewDel = cpStart - cp;
+
+ vuab.cp = cpStart = cp;
+
+ /* cpStart has moved, and the count of cp's inserted has not
+ changed -- we must adjust cpLimInserted */
+
+ cpLimInserted -= cchNewDel;
+ }
+
+ cpInsert -= cchNotInQD;
+ }
+ } /* End of if backspacing */
+ else
+ { /* FORWARD DELETE */
+ typeCP dcpFrontier = (cp + cch - cpLimInserted);
+
+ if (dcpFrontier > 0)
+ {
+ cpUndoAdd = CpMacText( docUndo );
+ cchNewDel = (int) dcpFrontier;
+ cpLimDeleted += dcpFrontier;
+ }
+ cchNotInQD = cch;
+ }
+
+ /* Now we have: cchNewDel - chars deleted beyond previous limits
+ (cpStart to cpLimDeleted)
+ cpUndoAdd - where to add deleted chars to Undo doc
+ (only set if cchNewDel > 0)
+ cchNotInQD - chars deleted outside QD buffer */
+
+ if (cchNotInQD > cchNewDel)
+ /* Deleting chars previously inserted during this AlphaMode session */
+ cpLimInserted -= (cchNotInQD - cchNewDel);
+
+ /* Add the newly deleted stuff to the UNDO document.
+ We find the { fn, fc } of the deleted char(s)
+ so we can take advantage of Replace's optimizations
+ wrt combining adjacent pieces (if the deletion is all one piece).
+ */
+ if (cchNewDel > 0)
+ {
+ struct PCTB **hpctb=(**hpdocdod)[ docCur ].hpctb;
+ int ipcd=IpcdFromCp( *hpctb, cp );
+ struct PCD *ppcd=&(*hpctb)->rgpcd [ipcd];
+ int fn=ppcd->fn;
+ typeFC fc=ppcd->fc;
+
+ Assert( ppcd->fn != fnNil && (ppcd+1)->cpMin >= cp );
+
+ if (bPRMNIL(ppcd->prm) && (cchNewDel <= (ppcd+1)->cpMin - cp))
+ { /* Deletion is all within one piece */
+ Replace( docUndo, cpUndoAdd, cp0, fn, fc + (cp - ppcd->cpMin),
+ (typeFC) cchNewDel );
+ }
+ else
+ {
+ ReplaceCps( docUndo, cpUndoAdd, cp0, docCur, cp,
+ (typeCP) cchNewDel );
+ }
+
+ switch ( vuab.uac ) {
+ default:
+ Assert( FALSE );
+ break;
+ case uacDelNS:
+ vuab.dcp += cchNewDel;
+ break;
+ case uacReplNS:
+ vuab.dcp2 += cchNewDel;
+ break;
+ }
+ }
+
+ /* Remove deleted chars from the doc */
+ Replace( docCur, cp, (typeCP) cchNotInQD, fnNil, fc0, fc0 );
+}
+
+
+
+
+FUpdateOneDl( dl )
+int dl;
+{ /* Update the display line dl. Mark dl+1 as invalid if, in the process
+ formatting dl, we discover that there is not a clean cp or
+ yp transition between the two lines (i.e. the ending yp or cp of dl
+ do not match the starting ones of dl+1).
+ Return TRUE iff we marked dl+1 invalid; FALSE otherwise
+ Starting cp & yp of dl+1 are adjusted as necessary */
+
+ register struct EDL *pedl=&(**(wwdCurrentDoc.hdndl))[dl];
+ int fUpdate=fFalse;
+ RECT rc;
+
+ vfli.doc = docNil;
+ FormatLine(docCur, pedl->cpMin, 0, wwdCurrentDoc.cpMac, flmSandMode);
+
+ pedl = &(**wwdCurrentDoc.hdndl) [dl + 1];
+
+/* next line is invalid if it exists (<dlMac) and
+ not following in cp space or not following in yp space
+*/
+
+ if ( (dl + 1 < wwdCurrentDoc.dlMac) &&
+ (!pedl->fValid || (pedl->cpMin != vfli.cpMac) ||
+ (pedl->yp - pedl->dyp != (pedl-1)->yp)))
+ {
+ pedl->fValid = fFalse;
+ pedl->cpMin = vfli.cpMac;
+ pedl->yp = (pedl-1)->yp + pedl->dyp;
+ fUpdate = fTrue;
+ }
+ else
+ {
+/* state is clean. Do not clear window dirty because more than one line may
+have been made invalid earlier */
+ /* Tell Windows we made this region valid */
+
+#if WINVER >= 0x300
+ /* Only actually USE pedl if it's be valid! ..pault 2/21/90 */
+ if (dl + 1 < wwdCurrentDoc.dlMac)
+#endif
+ {
+ SetRect( (LPRECT) &rc, 0, wwdCurrentDoc.xpMac,
+ pedl->yp - pedl->dyp, pedl->yp );
+ ValidateRect( wwdCurrentDoc.wwptr, (LPRECT) &rc );
+ }
+
+ (--pedl)->fValid = fTrue;
+ }
+ DisplayFli(wwCur, dl, fFalse);
+ return fUpdate;
+}
+
+
+
+void NEAR FormatInsLine()
+{ /* Format line containing insertion point, using vdlIns as a basis
+ Assume vdlIns's cpMin has not changed */
+
+ FormatLine( docCur, (**wwdCurrentDoc.hdndl) [vdlIns].cpMin, 0,
+ wwdCurrentDoc.cpMac, flmSandMode );
+
+ /* Compensate for LoadFont calls in FormatLine so we don't have to set
+ vfTextBltValid to FALSE */
+ LoadFont( docCur, &vchpInsert, mdFontChk );
+}
+
+
+#ifdef DBCS
+/* Get the second byte of a DBCS character using a busy loop. */
+CHAR near GetDBCSsecond()
+{
+ int kc;
+ CHAR chDBCS2;
+ BOOL fGotKey;
+
+ extern MSG vmsgLast;
+
+ fGotKey = FALSE;
+ do {
+ if ( FImportantMsgPresent() ) {
+ fGotKey = TRUE;
+ if ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil) {
+ chDBCS2 = kc;
+ if (vmsgLast.message == WM_KEYDOWN) {
+ switch (kc) {
+ default:
+ GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
+ break;
+ case kcAlphaVirtual:
+ /* This means we can't anticipate the key's meaning
+ before translation */
+ chDBCS2 = '\0';
+ if (!FNonAlphaKeyMessage(&vmsgLast, FALSE)) {
+ GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 );
+ TranslateMessage( &vmsgLast );
+ }
+ break;
+ }
+ }
+ else {
+ if (kc < 0) {
+ chDBCS2 = '\0';
+ }
+ GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
+ }
+ }
+ else {
+ chDBCS2 = '\0';
+ }
+ }
+ } while (!fGotKey);
+
+ /* As long as we go through the DBCS conversion window, this
+ should not happen. */
+ Assert(chDBCS2 != '\0');
+ return chDBCS2;
+}
+#endif /* DBCS */
+
diff --git a/private/mvdm/wow16/write/insert.tmp b/private/mvdm/wow16/write/insert.tmp
new file mode 100644
index 000000000..ce3791d64
--- /dev/null
+++ b/private/mvdm/wow16/write/insert.tmp
@@ -0,0 +1,18 @@
+54:#ifdef DBCS
+177:#ifdef DBCS
+240:#ifdef DBCS
+336:#ifdef DBCS
+366:#ifdef DBCS
+462:#ifdef DBCS
+555:#ifdef DBCS
+716:#ifdef DBCS
+776:#ifdef DBCS
+815:#ifdef DBCS
+1030:#ifdef DBCS
+1056:#ifdef DBCS
+1076:#ifdef DBCS
+1110:#ifdef DBCS
+1151:#ifdef DBCS
+1237:#ifdef DBCS
+1521:#ifdef DBCS
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/insert2.c b/private/mvdm/wow16/write/insert2.c
new file mode 100644
index 000000000..1ea3f60a3
--- /dev/null
+++ b/private/mvdm/wow16/write/insert2.c
@@ -0,0 +1,653 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* insert2.c - MW insertion routines */
+
+#define NOGDICAPMASKS
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOWINSTYLES
+
+#ifndef KOREA
+#define NOSYSMETRICS
+#endif
+
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOFONT
+#define NOCLIPBOARD
+#define NODRAWTEXT
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOMB
+#define NOOPENFILE
+#define NOSOUND
+#define NOCOMM
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "propdefs.h"
+#include "dispdefs.h"
+#include "fmtdefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "winddefs.h"
+#include "fontdefs.h"
+#include "debug.h"
+
+#ifdef DEBUG
+extern int vTune;
+#endif
+
+#ifdef KOREA /* Use in KcInputNext..., 90.12.27 sangl */
+extern int IsInterim;
+#endif
+
+extern int vdlIns;
+extern int vxpIns;
+extern int vfTextBltValid;
+extern int vdypCursLineIns;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern int vdypBase;
+extern int vypBaseIns;
+extern int vxpMacIns;
+extern int vdypAfter;
+extern typeCP cpInsert; /* Beginning cp of insert block */
+extern int ichInsert; /* Number of chars used in rgchInsert */
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern int docCur;
+extern struct CHP vchpInsert;
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern int wwCur;
+extern int wwMac;
+extern int vfSeeSel;
+extern int vfFocus;
+#ifdef DBCS
+extern int donteat; /* see disp.c */
+#endif
+
+
+unsigned WHsecGetTime()
+{ /* Get the time (in hundredths of seconds) into a normalized word */
+ /* Ignore current hour, just minutes/seconds/hundredths */
+ struct TIM tim;
+
+ OsTime( &tim );
+ return ( (unsigned)tim.minutes * 6000 +
+ (unsigned)tim.sec * 100 +
+ (unsigned)tim.hsec );
+}
+
+
+
+
+/* V A L I D A T E T E X T B L T */
+ValidateTextBlt()
+{ /* Validate info sufficient for TextOut and ScrollCurWw calls in Insert */
+ /* In particular: vdlIns, vxpIns, vdypBase, vdypFont */
+
+ int NEAR FCpInsertInDl( typeCP, struct EDL * );
+ extern int vfInsFontTooTall;
+ extern struct FMI vfmiScreen;
+ extern int ferror;
+ extern int vfInsEnd;
+
+ int dypFontAscent;
+ int dypFontDescent;
+ register struct EDL *pedl;
+ int yp;
+ typeCP cpBegin;
+
+ /* Routine assumes ww == wwDocument */
+
+ Assert( pwwdCur == &wwdCurrentDoc );
+
+ { /* Look for a valid dl containing selCur.cpFirst */
+ /* We should usually be able to find one */
+ int dlGuess = vdlIns;
+ struct EDL *dndl=&(**wwdCurrentDoc.hdndl)[0];
+
+ if ( (dlGuess < wwdCurrentDoc.dlMac) &&
+ FCpInsertInDl( selCur.cpFirst, pedl = &dndl[ dlGuess ] ))
+ { /* vdlIns is already correct */
+ cpBegin = pedl->cpMin;
+ }
+ else
+ { /* Search for valid dl containing insertion point */
+ /* Use linear search, all dl's may not be valid */
+ int dl;
+
+ for ( pedl = dndl, dl = 0; dl < wwdCurrentDoc.dlMac; dl++, pedl++ )
+ {
+ if ( FCpInsertInDl( selCur.cpFirst, pedl ) )
+ { /* Found it */
+ vdlIns = dl;
+ cpBegin = pedl->cpMin;
+ break;
+ }
+ }
+ if (dl >= wwdCurrentDoc.dlMac)
+ { /* No valid dl contains the cp -- must update whole screen */
+ cpBegin = CpBeginLine( &vdlIns, selCur.cpFirst );
+ }
+ }
+ }
+
+ /* Special case for splat: locate insert point at end of previous line */
+
+ pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
+ if (pedl->fSplat && (vdlIns > 0) && selCur.cpFirst == pedl->cpMin)
+ { /* Splat on current line */
+ /* Check for pedl->cpMin above is necessary for the special case */
+ /* in which the QD buffer is at the beginning of the splat line */
+ pedl--;
+ if (pedl->fValid && !pedl->fSplat)
+ { /* Locate cursor at end of previous line */
+ vdlIns--;
+ cpBegin = pedl->cpMin;
+
+ ClearInsertLine();
+ selCur.fEndOfLine = TRUE;
+ vfInsEnd = TRUE;
+ ToggleSel( selCur.cpFirst, selCur.cpLim, TRUE );
+ }
+ else
+ {
+ pedl++;
+ goto CheckEnd;
+ }
+ }
+ else
+ { /* Eliminate end of line cursor if not before a splat */
+CheckEnd:
+ if (selCur.fEndOfLine)
+ {
+ ClearInsertLine();
+ selCur.fEndOfLine = FALSE;
+ vfInsEnd = FALSE;
+ ToggleSel( selCur.cpFirst, selCur.cpLim, TRUE );
+ }
+ }
+
+ /* Assure we obtained a good vdlIns */
+
+ Assert( vdlIns < wwdCurrentDoc.dlMac );
+ Assert( ((selCur.cpFirst >= pedl->cpMin) &&
+ (selCur.cpFirst <= pedl->cpMin + pedl->dcpMac)));
+
+ FormatLine(docCur, cpBegin, 0, cpMacCur, flmSandMode);
+ vxpIns = DxpDiff(0, (int) (selCur.cpFirst - cpBegin), &vxpIns) + vfli.xpLeft +
+ xpSelBar - wwdCurrentDoc.xpMin;
+ vdypBase = vfli.dypBase;
+ vdypAfter = vfli.dypAfter;
+ vdypCursLineIns = min(vfli.dypFont, vfli.dypLine - vdypAfter);
+
+ vxpMacIns = vfli.xpMarg;
+
+ LoadFont(docCur, &vchpInsert, mdFontChk);
+ ferror = FALSE; // running out of memory here is OK. Must clear this
+ // or important calls will needlessly fail.
+ // (8.6.91) D. Kent
+
+
+ vypBaseIns = (**wwdCurrentDoc.hdndl) [vdlIns].yp - vdypBase;
+ dypFontAscent = vfmiScreen.dypAscent + vfmiScreen.dypLeading;
+ dypFontDescent = vfmiScreen.dypDescent;
+
+ if (vchpInsert.hpsPos)
+ {
+ if (vchpInsert.hpsPos < hpsNegMin)
+ {
+ vypBaseIns -= ypSubSuper; /* Superscript */
+ dypFontAscent += ypSubSuper;
+ }
+ else
+ {
+ vypBaseIns += ypSubSuper; /* Subscript */
+ dypFontDescent += ypSubSuper;
+ }
+ }
+
+ /* Set if current font is too tall to display on insert line */
+ vfInsFontTooTall = (imax( dypFontAscent, vfli.dypLine - vfli.dypBase ) +
+ imax( dypFontDescent, vfli.dypBase )) > vfli.dypLine;
+
+ vfTextBltValid = true;
+}
+
+
+
+int NEAR FCpInsertInDl( cp, pedl )
+typeCP cp;
+register struct EDL *pedl;
+{ /* Return TRUE if insert point cp is in dl & dl is valid, FALSE otherwise */
+
+if ( (pedl->fValid) && (cp >= pedl->cpMin) )
+ { /* dl is valid & cp is at or below starting cp of dl */
+ if ( (cp < pedl->cpMin + pedl->dcpMac) ||
+ ((cp == cpMacCur) && (cp == pedl->cpMin + pedl->dcpMac)) )
+ { /* cp is on line dl */
+ if (pedl->yp <= wwdCurrentDoc.ypMac)
+ { /* dl is complete, i.e. not cut off at bottom of window */
+ return TRUE;
+ }
+ }
+ }
+return FALSE;
+}
+
+
+
+
+#ifdef FOOTNOTES
+/* F E D I T F T N */
+int FEditFtn(cpFirst, cpLim)
+typeCP cpFirst, cpLim;
+{ /* Return true if edit includes an end of footnote mark */
+ struct FNTB **hfntb;
+ typeCP cp;
+
+ if ((hfntb = HfntbGet(docCur)) == 0 ||
+ cpLim < (cp = (*hfntb)->rgfnd[0].cpFtn))
+ return false;
+
+ if (cpFirst < cp ||
+ CpRefFromFtn(docCur, cpFirst) != CpRefFromFtn(docCur, cpLim))
+ {
+ Error(IDPMTFtnLoad);
+ return fTrue;
+ }
+ return fFalse;
+}
+#endif /* FOOTNOTES */
+
+
+
+
+/* U P D A T E O T H E R W W S */
+#ifdef CASHMERE
+UpdateOtherWws(fInval)
+BOOL fInval;
+{
+ int ww = 0;
+ struct WWD *pwwd = rgwwd;
+ {{
+ while (ww < wwMac)
+ {
+ if (ww != wwCur && (pwwd++)->doc == docCur)
+ {{
+ typeCP cpI = cpInsert + ichInsert;
+ typeCP cpH = CpMax(cpI, cpInsLastInval);
+ typeCP cpL = CpMin(cpInsLastInval, cpI);
+ typeCP dcp;
+ if ((dcp = cpH - cpL) != cp0 || fInval)
+ AdjustCp(docCur, cpL, dcp, dcp);
+ cpInsLastInval = cpI;
+ return;
+ }}
+ ww++;
+ }
+ }}
+}
+#endif /* CASHMERE */
+
+
+
+
+/* K C I N P U T N E X T K E Y */
+KcInputNextKey()
+{ /* Get next available key/event from Windows */
+ /* Returns key code or kcNil if a non-key event */
+ /* Updates the screen if there is time before events arrive */
+extern HWND vhWnd; /* WINDOWS: Handle of the current document display window*/
+extern MSG vmsgLast; /* WINDOWS: last message gotten */
+extern int vfInsLast;
+extern int vfCommandKey;
+extern int vfShiftKey;
+extern int vfAwfulNoise;
+
+ int i;
+ int kc;
+
+ for ( ;; )
+ {
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+/* No events waiting -- if none show up for a while, update the screen */
+
+#ifdef CASHMERE
+ UpdateOtherWws( FALSE );
+#endif
+
+ { /* Dawdle for a time, looking for keys, before updating the screen */
+ unsigned WHsecGetTime();
+ unsigned wHsec;
+
+ wHsec = WHsecGetTime();
+ do
+ {
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+ } while ( WHsecGetTime() - wHsec < dwHsecKeyDawdle );
+ }
+
+#ifdef DEBUG
+ if (vTune)
+ continue; /* Bag background update while debugging to see how we fare */
+#endif
+
+ Scribble( 8, 'U' );
+ ClearInsertLine();
+ UpdateWw(wwCur, fTrue);
+ ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue);
+ Scribble( 8, ' ' );
+
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+ vfAwfulNoise = FALSE;
+ PutCpInWwHz( selCur.cpFirst );
+
+ EndLongOp( NULL );
+
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+ if ( !vfTextBltValid )
+ ValidateTextBlt();
+
+ /* Nothing has happened for a while, let's blink the cursor */
+
+ {
+ unsigned WHsecGetTime();
+ unsigned wHsecBlink = GetCaretBlinkTime() / 10;
+ unsigned wHsecLastBlink=WHsecGetTime() + wHsecBlink/2;
+
+ for ( ;; )
+ {
+ unsigned wHsecT;
+
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+ /* Another app may have stolen the focus away from us while we called
+ PeekMessage(), in which case we should end Alpha mode. */
+ if (!vfFocus)
+ return kcNil;
+
+ UpdateDisplay( TRUE );
+ if ( (wHsecT = WHsecGetTime()) - wHsecLastBlink >= wHsecBlink )
+ {
+ DrawInsertLine();
+ wHsecLastBlink = wHsecT;
+ }
+ }
+ }
+
+ continue;
+
+GotMessage:
+#ifdef DBCS
+
+#ifdef KOREA /* Need to GetMessage for F-Key during Interim,90.12.27 sangl */
+ if ( ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil) || IsInterim)
+#else
+ if ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil)
+#endif
+ {
+ if (vmsgLast.wParam == VK_EXECUTE)
+ return( kcNil );
+ if (vmsgLast.message == WM_KEYDOWN)
+ {
+ switch (kc) {
+ default:
+ break;
+ case kcAlphaVirtual:
+ /* This means we can't anticipate the key's meaning
+ before translation */
+#ifdef KOREA /* Need GetMesssage for direc keys, etc during interim 90.12.26 sangl */
+ if ( FNonAlphaKeyMessage( &vmsgLast, FALSE ) && !IsInterim)
+#else
+ if ( FNonAlphaKeyMessage( &vmsgLast, FALSE ) )
+#endif
+ /* This is a non-alpha key message */
+ return kcNil;
+ if ( !donteat ) {
+ GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 );
+ }
+ else {
+ /* not eat message because FimportantMsgPresent has
+ ** eaten KEY_DOWN message
+ */
+ donteat = FALSE;
+ }
+ /*
+ ** When KKAPP window open, this message is offten wrong.
+ ** we must check it is really WM_KEYDOWN
+ */
+#ifdef KOREA /* for level 3, 90.12.26 sangl */
+ if ((vmsgLast.message == WM_CHAR) || (vmsgLast.message == WM_INTERIM)) {
+#else
+ if ( vmsgLast.message == WM_CHAR ) {
+#endif
+ return vmsgLast.wParam;
+ }
+ if ( vmsgLast.message != WM_KEYDOWN ) {
+ return kcNil;
+ }
+ TranslateMessage( &vmsgLast );
+ continue;
+ } /* switch kc */
+ } /* if keydown */
+ if ( !donteat ) {
+ GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
+#ifdef KOREA /* for level 3, 91.1.21 by Sangl */
+ if ( (vmsgLast.message==WM_CHAR)||(vmsgLast.message==WM_INTERIM) ) {
+#else
+ if ( vmsgLast.message == WM_CHAR ) {
+#endif
+ return vmsgLast.wParam;
+ }
+ } /* dont eat */
+ else {
+ donteat = FALSE;
+ }
+ } /* if kc != kcNil */
+#else
+ if ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil)
+ {
+ if (vmsgLast.message == WM_KEYDOWN)
+ {
+ switch (kc) {
+ default:
+ break;
+ case kcAlphaVirtual:
+ /* This means we can't anticipate the key's meaning
+ before translation */
+ if ( FNonAlphaKeyMessage( &vmsgLast, FALSE ) )
+ /* This is a non-alpha key message */
+ return kcNil;
+
+ GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 );
+ TranslateMessage( &vmsgLast );
+ continue;
+ }
+ }
+ GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
+ }
+#endif
+ return kc;
+ } /* End of for ( ;; ) loop to process messages */
+}
+
+#ifdef KOREA /* 90.12.29 sangl */
+KcInputNextHan()
+{ /* Get next available key/event from Windows */
+ /* Returns key code or kcNil if a non-key event */
+ /* Updates the screen if there is time before events arrive */
+extern HWND vhWnd; /* WINDOWS: Handle of the current document display window*/
+extern MSG vmsgLast; /* WINDOWS: last message gotten */
+extern int vfInsLast;
+extern int vfCommandKey;
+extern int vfShiftKey;
+extern int vfAwfulNoise;
+
+ int i;
+ int kc;
+ int tmp;
+
+tmp = vfInsLast;
+tmp = vfCommandKey;
+tmp = vfShiftKey;
+tmp = vfAwfulNoise;
+tmp = vmsgLast.message;
+tmp = vmsgLast.wParam;
+
+ for ( ;; )
+ {
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+/* No events waiting -- if none show up for a while, update the screen */
+
+ { /* Dawdle for a time, looking for keys, before updating the screen */
+ unsigned WHsecGetTime();
+ unsigned wHsec;
+
+ wHsec = WHsecGetTime();
+ do
+ {
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+ } while ( WHsecGetTime() - wHsec < dwHsecKeyDawdle );
+ }
+
+#ifdef DEBUG
+ if (vTune)
+ continue; /* Bag background update while debugging to see how we fare */
+#endif
+
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+/* vfAwfulNoise = FALSE;
+ PutCpInWwHz( selCur.cpFirst );
+
+ EndLongOp( NULL );*/
+
+ if ( FImportantMsgPresent() )
+ goto GotMessage;
+
+
+ /* Nothing has happened for a while, let's blink the cursor */
+
+ {
+ unsigned WHsecGetTime();
+ unsigned wHsecBlink = GetCaretBlinkTime() / 10;
+ unsigned wHsecLastBlink=WHsecGetTime() + wHsecBlink/2;
+ KillTimer( vhWnd, tidCaret );
+ for ( ;; )
+ {
+ unsigned wHsecT;
+
+ if ( FImportantMsgPresent() ) {
+ SetTimer( vhWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL );
+ goto GotMessage;
+ }
+
+ /* Another app may have stolen the focus away from us while we called
+ PeekMessage(), in which case we should end Alpha mode. */
+ if (!vfFocus) {
+ SetTimer( vhWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL );
+ return kcNil;
+ }
+
+ if ( (wHsecT = WHsecGetTime()) - wHsecLastBlink >= wHsecBlink )
+ {
+ DrawInsertLine();
+ wHsecLastBlink = wHsecT;
+ }
+ }
+ }
+
+ continue;
+
+GotMessage:
+ if( vmsgLast.wParam == VK_EXECUTE )
+ vmsgLast.wParam = VK_RETURN;
+/* To GetMessage for Func/Ctrl/direc keys, 90.4.4, Sang-Weon */
+ if ( ((kc=KcAlphaKeyMessage(&vmsgLast))!=kcNil) || IsInterim )
+ {
+if( vmsgLast.wParam == VK_EXECUTE )
+ return kcNil;
+
+ if (vmsgLast.message == WM_KEYDOWN)
+ {
+ switch (kc) {
+ default:
+ break;
+ case kcAlphaVirtual:
+ /* This means we can't anticipate the key's meaning
+ before translation */
+ if ( FNonAlphaKeyMessage(&vmsgLast, FALSE) && !IsInterim )
+ /* This is a non-alpha key message */
+ return kcNil;
+ if ( !donteat ) {
+ GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 );
+ }
+ else {
+ /* not eat message because FimportantMsgPresent has
+ ** eaten KEY_DOWN message
+ */
+ donteat = FALSE;
+ }
+ /*
+ ** When KKAPP window open, this message is offten wrong.
+ ** we must check it is really WM_KEYDOWN
+ */
+ if ( (vmsgLast.message==WM_CHAR)||(vmsgLast.message==WM_INTERIM) ) {
+ return vmsgLast.wParam;
+ }
+ if ( vmsgLast.message != WM_KEYDOWN ) {
+ return kcNil;
+ }
+ TranslateMessage( &vmsgLast );
+ continue;
+ } /* switch kc */
+ } /* if keydown */
+ if ( !donteat ) {
+ GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
+ if ( (vmsgLast.message==WM_CHAR)||(vmsgLast.message==WM_INTERIM) ) {
+ return vmsgLast.wParam;
+ }
+ } /* dont eat */
+ else {
+ donteat = FALSE;
+ }
+ } /* if kc != kcNil */
+ return kc;
+ } /* End of for ( ;; ) loop to process messages */
+}
+#endif /* ifdef KOREA */
+
diff --git a/private/mvdm/wow16/write/insertco.c b/private/mvdm/wow16/write/insertco.c
new file mode 100644
index 000000000..0ab3a06e8
--- /dev/null
+++ b/private/mvdm/wow16/write/insertco.c
@@ -0,0 +1,335 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOWINSTYLES
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOGDI
+#define NOKEYSTATE
+#define NOHDC
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "prmdefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#include "stcdefs.h"
+#include "fkpdefs.h"
+#include "editdefs.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+
+/* E X T E R N A L S */
+extern struct WWD rgwwd[];
+extern int docCur;
+extern struct CHP vchpFetch;
+extern struct CHP vchpInsert;
+extern struct CHP vchpSel;
+extern struct CHP vchpNormal;
+extern struct FKPD vfkpdParaIns;
+extern typeFC fcMacPapIns;
+extern struct PAP *vppapNormal;
+extern struct PAP vpapPrevIns;
+extern struct FCB (**hpfnfcb)[];
+extern struct BPS *mpibpbps;
+extern CHAR (*rgbp)[cbSector];
+
+extern typePN PnAlloc();
+
+
+InsertRgch(doc, cp, rgch, cch, pchp, ppap)
+int doc, cch;
+typeCP cp;
+CHAR rgch[];
+struct CHP *pchp;
+struct PAP *ppap;
+{ /* Insert cch characters from rgch into doc before cp */
+ typeFC fc;
+ struct CHP chp;
+
+ /* First finish off the previous CHAR run if necessary */
+ if (pchp == 0)
+ { /* Make looks be those of PREVIOUS character */
+ CachePara(doc,cp);
+ FetchCp(doc, CpMax(cp0, cp - 1), 0, fcmProps);
+ blt(&vchpFetch, &chp, cwCHP);
+ chp.fSpecial = false;
+ pchp = &chp;
+ }
+ NewChpIns(pchp);
+
+ /* Now write the characters to the scratch file */
+ fc = FcWScratch(rgch, cch);
+
+ /* Now insert a paragraph run if we inserted an EOL */
+ if (ppap != 0)
+ { /* Inserting EOL--must be last character of rgch */
+ AddRunScratch(&vfkpdParaIns, ppap, vppapNormal,
+ FParaEq(ppap, &vpapPrevIns) &&
+ vfkpdParaIns.brun != 0 ? -cchPAP : cchPAP,
+ fcMacPapIns = (**hpfnfcb)[fnScratch].fcMac);
+ blt(ppap, &vpapPrevIns, cwPAP);
+ }
+
+ /* Finally, insert the piece into the document */
+ Replace(doc, cp, cp0, fnScratch, fc, (typeFC) cch);
+}
+
+
+
+
+
+InsertEolInsert(doc,cp)
+int doc;
+typeCP cp;
+{
+struct PAP papT;
+struct CHP chpT;
+CHAR rgch[2];
+
+/* (MEMO) Here's the problem: When we insert or paste into a running head or
+ foot, we expect all paras to have a non-0 rhc. This gets called from
+ Replace to put in an Eol when we are inserting or pasting in front of
+ a picture. It needs, therefore, to have running head properties when
+ appropriate. In a future world, cpMinDocument, cpMinHeader, cpMacHeader,
+ cpMinFooter, and cpMacFooter will be document attributes instead of
+ globals, and will be duly adjusted by AdjustCp. Then, we can trash the
+ somewhat kludgy check for doc==docCur and editing header/footer,
+ and instead check for cp within header/footer bounds for doc. */
+
+papT = *vppapNormal;
+if (doc==docCur)
+ if (wwdCurrentDoc.fEditHeader)
+ papT.rhc = RHC_fOdd + RHC_fEven;
+ else if (wwdCurrentDoc.fEditFooter)
+ papT.rhc = RHC_fBottom + RHC_fOdd + RHC_fEven;
+
+#ifdef CRLF
+ rgch[0] = chReturn;
+ rgch[1] = chEol;
+ chpT = vchpSel;
+ chpT.fSpecial = fFalse;
+ InsertRgch(doc, cp, rgch, 2, &chpT, &papT);
+#else
+ rgch[0] = chEol;
+ chpT = vchpSel;
+ chpT.fSpecial = fFalse;
+ InsertRgch(doc, cp, rgch, 1, &chpT, &papT);
+#endif
+}
+
+
+
+
+
+InsertEolPap(doc, cp, ppap)
+int doc;
+typeCP cp;
+struct PAP *ppap;
+{
+extern struct CHP vchpAbs;
+struct CHP chpT;
+#ifdef CRLF
+CHAR rgch [2];
+#else
+CHAR rgch [1];
+#endif
+
+ /* We must get props here instead of using vchpNormal because of the
+ "10-point kludge". We don't want to change the default font
+ just because we have to insert a new pap */
+
+FetchCp( doc, cp, 0, fcmProps );
+chpT = vchpAbs;
+chpT.fSpecial = fFalse;
+
+#ifdef CRLF
+rgch [0] = chReturn;
+rgch [1] = chEol;
+InsertRgch(doc, cp, rgch, 2, &chpT, ppap);
+#else
+InsertRgch(doc, cp, rgch, 1, &chpT, ppap);
+#endif
+}
+
+
+
+
+AddRunScratch(pfkpd, pchProp, pchStd, cchProp, fcLim)
+struct FKPD *pfkpd;
+CHAR *pchProp, *pchStd;
+int cchProp;
+typeFC fcLim;
+{ /* Add a CHAR or para run to the scratch file FKP (see FAddRun) */
+struct FKP *pfkp;
+CHAR *pchFprop;
+struct RUN *prun;
+int ibp;
+
+pfkp = (struct FKP *) rgbp[ibp = IbpEnsureValid(fnScratch, pfkpd->pn)];
+pchFprop = &pfkp->rgb[pfkpd->bchFprop];
+prun = (struct RUN *) &pfkp->rgb[pfkpd->brun];
+
+
+while (!FAddRun(fnScratch, pfkp, &pchFprop, &prun, pchProp, pchStd, cchProp,
+ fcLim))
+ { /* Go to a new page; didn't fit. */
+ int ibte = pfkpd->ibteMac;
+ struct BTE (**hgbte)[] = pfkpd->hgbte;
+
+ /* Create new entry in bin table for filled page */
+ if (!FChngSizeH(hgbte, ((pfkpd->ibteMac = ibte + 1) * sizeof (struct BTE)) / sizeof (int),
+ false))
+ return;
+ (**hgbte)[ibte].fcLim = (prun - 1)->fcLim;
+ (**hgbte)[ibte].pn = pfkpd->pn;
+
+ /* Allocate new page */
+ pfkpd->pn = PnAlloc(fnScratch);
+ pfkpd->brun = 0;
+ pfkpd->bchFprop = cbFkp;
+
+ if (cchProp < 0) /* New page, so force output of fprop */
+ cchProp = -cchProp;
+
+ /* Reset pointers and fill in fcFirst */
+ pfkp = (struct FKP *) rgbp[ibp = IbpEnsureValid(fnScratch, pfkpd->pn)];
+ pfkp->fcFirst = (prun - 1)->fcLim;
+ pchFprop = &pfkp->rgb[pfkpd->bchFprop];
+ prun = (struct RUN *) &pfkp->rgb[pfkpd->brun];
+ }
+
+mpibpbps[ibp].fDirty = true;
+pfkpd->brun = (CHAR *) prun - &pfkp->rgb[0];
+pfkpd->bchFprop = pchFprop - &pfkp->rgb[0];
+}
+
+
+
+
+int FAddRun(fn, pfkp, ppchFprop, pprun, pchProp, pchStd, cchProp, fcLim)
+int fn, cchProp;
+struct FKP *pfkp;
+CHAR **ppchFprop, *pchProp, *pchStd;
+struct RUN **pprun;
+typeFC fcLim;
+{ /* Add a run and FCHP/FPAP to the current FKP. */
+ /* Make a new page if it won't fit. */
+ /* If cchProp < 0, don't make new fprop if page not full */
+int cch;
+
+/* If there's not even enough room for a run, force new fprop */
+if (cchProp < 0 && (CHAR *) (*pprun + 1) > *ppchFprop)
+ cchProp = -cchProp;
+
+if (cchProp > 0)
+ { /* Make a new fprop */
+ /* Compute length of FPAP/FCHP */
+ if (cchProp == cchPAP)
+ {
+/* compute difference from vppapNormal */
+ if (((struct PAP *)pchProp)->rgtbd[0].dxa != 0)
+ {
+ int itbd;
+/* find end of tab table */
+ for (itbd = 1; itbd < itbdMax; itbd++)
+ if (((struct PAP *)pchProp)->rgtbd[itbd].dxa == 0)
+ {
+ cch = cwPAPBase * cchINT + (itbd + 1) * cchTBD;
+ goto HaveCch;
+ }
+ }
+ cchProp = cwPAPBase * cchINT;
+ }
+ cch = CchDiffer(pchProp, pchStd, cchProp);
+HaveCch:
+ if (cch > 0)
+ ++cch;
+
+ /* Determine whether info will fit on this page */
+ if ((CHAR *) (*pprun + 1) > *ppchFprop - cch)
+ { /* Go to new page; this one is full */
+ if (fn == fnScratch)
+ return false; /* Let AddRunScratch handle this */
+ WriteRgch(fn, pfkp, cbSector);
+ pfkp->fcFirst = (*pprun - 1)->fcLim;
+ *ppchFprop = &pfkp->rgb[cbFkp];
+ *pprun = (struct RUN *) pfkp->rgb;
+ }
+
+ /* If new FPAP is needed, make it */
+ if (cch > 0)
+ {
+ (*pprun)->b = (*ppchFprop -= cch) - pfkp->rgb;
+ **ppchFprop = --cch;
+ bltbyte(pchProp, *ppchFprop + 1, cch);
+ }
+ else /* Use standard props */
+ (*pprun)->b = bNil;
+ }
+else /* Point to previous fprop */
+ (*pprun)->b = (*pprun - 1)->b;
+
+ /* Replaced old sequence (see below) */
+(*pprun)->fcLim = fcLim;
+pfkp->crun = ++(*pprun) - (struct RUN *) pfkp->rgb;
+
+/* Used to be like this, but CMERGE -Oa (assume no aliasing)
+ option made it not work -- "*pprun" is an alias for the
+ postincremented value of *pprun */
+/*(*pprun)++->fcLim = fcLim;
+pfkp->crun = *pprun - (struct RUN *) pfkp->rgb; */
+
+return true;
+}
+
+
+/* F P A R A E Q */
+/* compares two PAP structures. Problem: tab tables are not fixed length
+but are terminated by 0 dxa. */
+FParaEq(ppap1, ppap2)
+struct PAP *ppap1, *ppap2;
+ {
+ struct TBD *ptbd1 = ppap1->rgtbd, *ptbd2 = ppap2->rgtbd;
+ while (ptbd1->dxa == ptbd2->dxa)
+ {
+ if (ptbd1->dxa == 0)
+ return CchDiffer(ppap1, ppap2, cchPAP) == 0;
+ if (*(long *)ptbd1 != *(long *)ptbd2) break;
+ ptbd1++; ptbd2++;
+ }
+ return fFalse;
+ }
diff --git a/private/mvdm/wow16/write/jumppage.c b/private/mvdm/wow16/write/jumppage.c
new file mode 100644
index 000000000..8a2a7521e
--- /dev/null
+++ b/private/mvdm/wow16/write/jumppage.c
@@ -0,0 +1,192 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOSCROLL
+#define NOMB
+#include <windows.h>
+
+#include "mw.h"
+#include "dlgdefs.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "str.h"
+#include "propdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "docdefs.h"
+
+
+extern int rgval[];
+extern struct WWD *pwwdCur;
+extern struct DOD (**hpdocdod)[];
+extern int docCur; /* Document in current ww */
+extern struct SEL selCur; /* Current selection (i.e., sel in current ww */
+extern struct SEP vsepNormal;
+extern HWND vhWndMsgBoxParent;
+extern int vfCursorVisible;
+extern HCURSOR vhcArrow;
+
+
+
+BOOL far PASCAL DialogGoTo( hDlg, message, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+ /* This routine handles input to the Go To dialog box. */
+ /*RECT rc;*/
+ struct SEP **hsep = (**hpdocdod)[docCur].hsep;
+ struct SEP *psep;
+ CHAR szT[cchMaxNum];
+ CHAR *pch = &szT[0];
+ extern ferror;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ EnableOtherModeless(false);
+ /* Get a pointer to the section properties. */
+ psep = (hsep == NULL) ? &vsepNormal : *hsep;
+
+ /* Initialize the starting page number. */
+ if (psep->pgnStart != pgnNil)
+ {
+ szT[ncvtu(psep->pgnStart, &pch)] = '\0';
+ SetDlgItemText(hDlg, idiGtoPage, (LPSTR)szT);
+ SelectIdiText(hDlg, idiGtoPage);
+ }
+ else
+ {
+ SetDlgItemText(hDlg, idiGtoPage, (LPSTR)"1");
+ SelectIdiText(hDlg, idiGtoPage);
+ }
+ break;
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiOk:
+ if (!WPwFromItW3Id(&rgval[0], hDlg, idiGtoPage, pgnMin, pgnMax, wNormal, IDPMTNPI))
+ {
+ ferror = FALSE; /* reset error condition, so as to report any
+ further error */
+ break;
+ }
+ OurEndDialog(hDlg, TRUE); /* So we take down the dialog box and
+ only screen update ONCE ..pault */
+ CmdJumpPage();
+ if (pwwdCur->fRuler)
+ UpdateRuler();
+ break;
+
+ case idiCancel:
+CancelDlg:
+ OurEndDialog(hDlg, TRUE);
+ break;
+ default:
+ return(FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+ goto CancelDlg;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/* end of DialogGoTo */
+
+
+/* C M D J U M P P A G E */
+CmdJumpPage()
+ { /* JUMP PAGE:
+ 0 page number
+ */
+
+ extern typeCP cpMinCur;
+
+ int ipgd;
+ int cpgd;
+ register struct PGD *ppgd;
+ struct PGTB **hpgtb = (**hpdocdod)[docCur].hpgtb;
+ BOOL fWrap = FALSE;
+ typeCP cpTarget;
+
+
+ ClearInsertLine();
+
+ if (hpgtb == NULL)
+ {
+ goto SelFirstPage;
+ }
+
+ cpgd = (**hpgtb).cpgd;
+
+TryAgain:
+ for (ipgd = 0, ppgd = &(**hpgtb).rgpgd[0]; ipgd < cpgd; ipgd++, ppgd++)
+ {
+ if (ppgd->pgn == rgval[0] && (fWrap || ipgd + 1 == cpgd ||
+ (ppgd + 1)->cpMin > selCur.cpFirst))
+ {
+ cpTarget = ppgd->cpMin;
+ goto ShowPage;
+ }
+ }
+ if (!fWrap)
+ {
+ fWrap = TRUE;
+ goto TryAgain;
+ }
+
+ /* If rgval[0] > last page number jump to last page */
+ if ((ppgd = &(**hpgtb).rgpgd[cpgd - 1])->pgn < rgval[0])
+ {
+ cpTarget = ppgd->cpMin;
+ }
+ else if (rgval[0] == 1)
+ {
+
+SelFirstPage:
+ cpTarget = cpMinCur;
+ }
+ else
+ {
+ Error(IDPMTNoPage);
+ return;
+ }
+
+ShowPage:
+ /* Position first char of page on the first dl */
+ DirtyCache(pwwdCur->cpFirst = cpTarget);
+ pwwdCur->ichCpFirst = 0;
+ CtrBackDypCtr(0, 0);
+
+ /* In this case, CpFirstSty() will update the screen. */
+ cpTarget = CpFirstSty(cpTarget, styLine);
+ Select(cpTarget, cpTarget);
+ }
diff --git a/private/mvdm/wow16/write/just.bms b/private/mvdm/wow16/write/just.bms
new file mode 100644
index 000000000..1551d6524
--- /dev/null
+++ b/private/mvdm/wow16/write/just.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/kanji.h b/private/mvdm/wow16/write/kanji.h
new file mode 100644
index 000000000..3b97df4e9
--- /dev/null
+++ b/private/mvdm/wow16/write/kanji.h
@@ -0,0 +1,286 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* kanji.h ----- kanji primitives forward declaration. */
+
+#ifdef KANJI
+
+/***** common definition for Korea, Japan and Taiwan *****/
+
+/* CHLS (c of half line spacing) used to indicate the default
+ line spacing. Used in createww.c and initmmw.c */
+#define chlsSingle 2
+#define chlsOneHalf 3
+#define chlsDouble 4
+
+#define chlsDefault chlsOneHalf
+
+
+/* HDC KanjiGetDC(HWND); */
+/* void FAR PASCAL SetMapperFlags(HDC, long); */
+/* And the kludge value to be used. */
+#define NEC_HACK ((long) 0x04)
+
+
+/* struct DNUT is used to map a unit annotation to ut. */
+struct DNUT {
+ char *szUnit;
+ int ut;
+ };
+
+#ifdef CASHMERE
+#define IDNUTMAX 19
+#else
+#define IDNUTMAX 15
+#endif /* CASHMERE */
+
+
+/* Function type declarations. */
+int HpsFromDya(unsigned);
+unsigned DyaFromHps(int);
+
+BOOL FPasteTooLarge(unsigned long);
+
+/* For copy command, we now use the "COPY" key. */
+#ifndef NONECKEYBOARD
+#define VK_COPY 0x2C
+#else
+#ifndef NOVIRTUALKEYCODES
+#define VK_COPY VK_F2
+#endif /* not NOVIRTUALKEYCODES */
+#endif /* if-else-def NONECKEYBOARD */
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif /* DEBUG */
+
+/* Kanji flag ---- used in CpFirstSty() */
+#define fkNonKanji ((CHAR) 0)
+#define fkKanji1 ((CHAR) 1)
+#define fkKanji2 ((CHAR) 2)
+
+#define cchKanji 2
+
+#define MAKEWORD(_bHi, _bLo) ((((WORD) _bHi) << 8) | ((WORD) _bLo))
+
+#define dxp0 0
+
+/******* KOREA specific definitons *******/
+
+#ifdef KOREA
+/* Used in GetKanjiMeasurement */
+#define bKanji1Min 0xA1
+/* First byte of a kanji space. */
+#define bKanjiSpace1 0xA1
+/* Second byte of a kanji space. */
+#define bKanjiSpace2 0xA1
+/* 1 byte kanji period. */
+#define bKanjiKuten 0xA1
+
+#define FKanji1(_ch) (((int) (_ch))>=0x00A1 && ((int) (_ch))<=0x00FE)
+
+#define FKanjiSpace(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x00A1)
+#define FKanjiQMark(_ch1, _ch2) (((int) (_ch1)) == 0x00A3 && \
+ ((int) (_ch2)) == 0x00AF)
+#define FKanjiPeriod(_ch1, _ch2) (((int) (_ch1)) == 0x00A3 && \
+ ((int) (_ch2)) == 0x00AE)
+#define FKanjiBang(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x00A1)
+#define FKanjiKuten(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x00A3)
+
+#define KANJI_CHARSET HANGEUL_CHARSET
+
+
+/* Since the higher half of 1-byte character codes are used for
+ kanas and the first byte of a kanji character, we will use
+ kanji characters for our markers. */
+#define chMark1 ((CHAR) 0xA1)
+#define chEMark ((CHAR) 0xDF)
+#define chStatPage ((CHAR) 0xB7)
+#define chStatRH ((CHAR) 0xB5)
+
+#ifdef CODE_TABLE
+/* The following tables defines those characters which can be display
+ beyond the right margin.
+ Refer to FAdmitCh2 function in d_FORM1.c */
+
+#define MPDCHRGCHIDX_MAC 4
+static CHAR mpdchrgchIdx[4] = {0xA1, 0xA3, 0xAA, 0xAB};
+static int mpdchichMax[4] = {19, 4, 9, 12};
+
+static CHAR mpdchrgch[4][19] = {
+ /* A1 */ {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA9, 0xAA, 0xAF,
+ 0xB1, 0xB3, 0xB5, 0xB7, 0xB9, 0xBB, 0xBD, 0xC6, 0xC7, 0xC8},
+ /* A3 */ {0xA2, 0xA9, 0xDD, 0xFD},
+ /* AA */ {0xA1, 0xA3, 0xA5, 0xA7, 0xA9, 0xC3, 0xE3, 0xE5, 0xE7},
+ /* AB */ {0xA1, 0xA3, 0xA5, 0xA7, 0xA9, 0xC3, 0xE3, 0xE5,
+ 0xE7, 0xEE, 0xF5, 0xF6}
+ };
+
+/* The followin tables specify characters which can exist beyond the
+ right margin provided there is a kanji character on its left side
+ Refer to FOptAdmitCh2 in d_FORM1.c on how to use them */
+
+#define OPTADMIT2IDX_MAC 1
+static CHAR OptAdmit2Idx[1] = {0xA3};
+static int OptAdmit2ichMax[1] = {6};
+static CHAR mpdchrgchOptAdmit2[1][6] = {
+ {0xA1, 0xAC, 0xAE, 0xBA, 0xBB, 0xBF}
+ };
+#endif /* CODE_TABLE */
+
+#endif /* Korea */
+
+/******* JAPAN specific definitons *******/
+
+#ifdef JAPAN
+/* Used in GetKanjiMeasurement */
+#define bKanji1Min 0x81
+/* First byte of a kanji space. */
+#define bKanjiSpace1 0x81
+/* Second byte of a kanji space. */
+#define bKanjiSpace2 0x40
+/* 1 byte kanji period. */
+#define bKanjiKuten 0xA1
+
+#define FKanji1(_ch) ((((int) (_ch))>=0x0081 && ((int) (_ch))<=0x009f) \
+ || (((int) (_ch))>=0x00e0 && ((int) (_ch))<=0x00fc))
+#define FKana(_ch) (0xA0 <= ((int) (_ch)) && ((int) (_ch)) <= 0xdf)
+/* Excludes any kana punctuations. */
+#define FKanaText(_ch) (0xA6 <= ((int) (_ch)) && ((int) (_ch)) <= 0xDD)
+#define FKanaPunct(_ch) ((0xA0 <= ((int) (_ch)) && ((int) (_ch)) <= 0xA5) || \
+ (0xDE <= ((int) (_ch)) && ((int) (_ch)) <= 0xDF))
+
+#define FKanjiSpace(_ch1, _ch2) (((int) (_ch1)) == 0x0081 && \
+ ((int) (_ch2)) == 0x0040)
+#define FKanjiQMark(_ch1, _ch2) (((int) (_ch1)) == 0x0081 && \
+ ((int) (_ch2)) == 0x0048)
+#define FKanjiPeriod(_ch1, _ch2) (((int) (_ch1)) == 0x0081 && \
+ ((int) (_ch2)) == 0x0044)
+#define FKanjiBang(_ch1, _ch2) (((int) (_ch1)) == 0x0081 && \
+ ((int) (_ch2)) == 0x0049)
+#define FKanjiKuten(_ch1, _ch2) (((int) (_ch1)) == 0x0081 && \
+ ((int) (_ch2)) == 0x0042)
+
+#define KANJI_CHARSET SHIFTJIS_CHARSET
+
+
+/* Since the higher half of 1-byte character codes are used for
+ kanas and the first byte of a kanji character, we will use
+ kanji characters for our markers. */
+#define chMark1 ((CHAR) 0x81)
+#define chEMark ((CHAR) 0x9F)
+#define chStatPage ((CHAR) 0x74)
+#define chStatRH ((CHAR) 0x72)
+
+#ifdef CODE_TABLE
+/* The following tables defines those characters which can be display
+ beyond the right margin.
+ Refer to FAdmitCh2 function in d_FORM1.c */
+
+#define MPDCHRGCHIDX_MAC 4
+static CHAR mpdchrgchIdx[4] = {0x81, 0x82, 0x83, 0x85};
+static int mpdchichMax[4] = {24, 9, 12, 20};
+
+static CHAR mpdchrgch[4][24] = {
+ /* 0x81 */ {0x40, 0x41, 0x42, 0x45, 0x4A, 0x4B, 0x5B, 0x5C,
+ 0x5D, 0x63, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E,
+ 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x8C, 0x8D},
+ /* 0x82 */ {0x9F, 0xA1, 0xA3, 0xA5, 0xA7, 0xC1, 0xE1, 0xE3,
+ 0xE5},
+ /* 0x83 */ {0x40, 0x42, 0x44, 0x46, 0x48, 0x62, 0x83, 0x85,
+ 0x87, 0x8E, 0x95, 0x96},
+ /* 0x85 */ {0x41, 0x46, 0x48, 0x7C, 0x9D, 0x9F, 0xA1, 0xA2,
+ 0xA3, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
+ 0xAC, 0xAD, 0xDC, 0xDD}
+ };
+/* The followin tables specify characters which can exist beyond the
+ right margin provided there is a kanji character on its left side
+ Refer to FOptAdmitCh2 in d_FORM1.c on how to use them */
+
+#define OPTADMIT2IDX_MAC 2
+static CHAR OptAdmit2Idx[2] = {0x81, 0x85};
+static int OptAdmit2ichMax[2] = {6,6};
+static CHAR mpdchrgchOptAdmit2[2][6] = {
+ {0x43, 0x44, 0x46, 0x47, 0x48, 0x49},
+ {0x40, 0x49, 0x4A, 0x4B, 0x4D, 0x5E}
+ };
+#endif /* CODE_TABLE */
+
+#endif /* Japan */
+
+/******* TAIWAN specific definitons *******/
+
+#ifdef TAIWAN
+/* Used in GetKanjiMeasurement */
+#define bKanji1Min 0xA1
+/* First byte of a kanji space. */
+#define bKanjiSpace1 0xA1
+/* Second byte of a kanji space. */
+#define bKanjiSpace2 0x40
+/* 1 byte kanji period. */
+#define bKanjiKuten 0x7F
+
+#define FKanji1(_ch) (((int) (_ch))>=0x00A1 && ((int) (_ch))<=0x00FE)
+/* Excludes any kana punctuations. */
+#define FKanaText(_ch) (0xA4 <= ((int) (_ch)) && ((int) (_ch)) <= 0xFE)
+#define FKanaPunct(_ch) (0xA1 <= ((int) (_ch)) && ((int) (_ch)) <= 0xA3)
+
+#define FKanjiSpace(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x0040)
+#define FKanjiQMark(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x0048)
+#define FKanjiPeriod(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x0044)
+#define FKanjiBang(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x0049)
+#define FKanjiKuten(_ch1, _ch2) (((int) (_ch1)) == 0x00A1 && \
+ ((int) (_ch2)) == 0x0042)
+
+#define KANJI_CHARSET CHINESEBIG5_CHARSET
+
+
+/* Since the higher half of 1-byte character codes are used for
+ kanas and the first byte of a kanji character, we will use
+ kanji characters for our markers. */
+#define chMark1 ((CHAR) 0xA1)
+#define chEMark ((CHAR) 0xBB)
+#define chStatPage ((CHAR) 0x6E)
+#define chStatRH ((CHAR) 0x72)
+
+#ifdef CODE_TABLE
+/* The following tables defines those characters which can be display
+ beyond the right margin.
+ Refer to FAdmitCh2 function in d_FORM1.c */
+
+#define MPDCHRGCHIDX_MAC 1
+static CHAR mpdchrgchIdx[1] = {0xA1};
+static int mpdchichMax[1] = {24};
+
+static CHAR mpdchrgch[1][24] = {
+ {0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x4D, 0x4E, 0x51, 0x52, 0x53, 0x54, 0x62,
+ 0x66, 0x6A, 0x77, 0x7B, 0x7E, 0xA2, 0xA4, 0xA8}
+ };
+
+/* The followin tables specify characters which can exist beyond the
+ right margin provided there is a kanji character on its left side
+ Refer to FOptAdmitCh2 in d_FORM1.c on how to use them */
+
+#define OPTADMIT2IDX_MAC 1
+static CHAR OptAdmit2Idx[1] = {0xA1};
+static int OptAdmit2ichMax[1] = {6};
+static CHAR mpdchrgchOptAdmit2[1][6] = {
+ 0x43, 0x44, 0x46, 0x47, 0x48, 0x49,
+ };
+#endif /* CODE_TABLE */
+
+#endif /* Taiwan */
+
+#endif /* Kanji */
+
diff --git a/private/mvdm/wow16/write/kmake.bat b/private/mvdm/wow16/write/kmake.bat
new file mode 100644
index 000000000..a13ee8082
--- /dev/null
+++ b/private/mvdm/wow16/write/kmake.bat
@@ -0,0 +1,56 @@
+rem echo off
+set include=.
+set lib=.\tools;.;
+set path=.\tools
+if exist debug goto origin
+rem ****** command /c kmakend %1 %2 %3 %4 %5
+rem ****** goto realfinis
+:origin
+rem ****** if not exist e:sccs.chk goto noshort
+rem ****** set include=c:\lib
+rem ****** set lib=c:\lib
+rem ****** path=c:\dos;c:\wbin;c:\tools;c:\editors;c:\lint
+:noshort
+if "%1"=="-u" goto update
+if "%1"=="-e" goto doecho
+if "%1"=="-k" goto nobreak
+if "%1"=="" goto breakok
+echo usage: kmake {-u}{-e}{-k}
+goto finis
+:update
+rem ****** if exist e:sccs.chk goto realupd
+rem ****** echo *** Net not active, Update Skipped
+rem ****** goto nonetfile
+:realupd
+echo *** Updating From Net
+rem ****** upd /n d:\wow c:\wbin *.c *.asm *.def *.h *.ico *.cur *.rc makefile.* *.bmp
+ssync
+echo *** Update Complete
+:nonetfile
+shift
+goto origin
+:nobreak
+del z-.msg
+ren z.msg z-.msg
+echo *** Starting Make. Make will not stop for compiler errors (DEBUG ON)
+make -k "DFLAGS = -DKANJI -DCRLF -u" "DEBUGDEF = -DDEBUG" >z.msg
+goto finis
+:doecho
+echo *** Starting Make. Make will not stop for compiler errors (DEBUG ON)
+make -k "DFLAGS = -DKANJI -DCRLF -u" "DEBUGDEF = -DDEBUG"
+goto realfinis
+:breakok
+del z-.msg
+ren z.msg z-.msg
+echo *** Starting Make. MAKE WILL STOP FOR ALL ERRORS (DEBUG ON)
+make "DFLAGS = -DKANJI -DCRLF -u" "DEBUGDEF = -DDEBUG" >z.msg
+:finis
+:realfinis
+if ERRORLEVEL 1 goto badend
+echoerr *** Make complete.
+goto theend
+:badend
+echo *** Errors found during make. 
+:theend
+..\..\setenv
+
diff --git a/private/mvdm/wow16/write/kmakend.bat b/private/mvdm/wow16/write/kmakend.bat
new file mode 100644
index 000000000..9648ee96e
--- /dev/null
+++ b/private/mvdm/wow16/write/kmakend.bat
@@ -0,0 +1,42 @@
+echo off
+:origin
+:noshort
+if "%1"=="-u" goto update
+if "%1"=="-e" goto doecho
+if "%1"=="-k" goto nobreak
+if "%1"=="" goto breakok
+echo usage: kmake {-u}{-e}{-k}
+goto finis
+:update
+:realupd
+echo *** Updating From Net
+ssync
+echo *** Update Complete
+:nonetfile
+shift
+goto origin
+:nobreak
+del z-.msg
+ren z.msg z-.msg
+echo *** Starting Make. Make will not stop for compiler errors (DEBUG OFF)
+make -k "AINC = c:\lib" "CLIB = c:\lib" "DFLAGS = -DKANJI -DCRLF -UMSDOS -UM_I86MM -UM_I86" >z.msg
+goto finis
+:doecho
+echo *** Starting Make. Make will not stop for compiler errors (DEBUG OFF)
+make -k "AINC = c:\lib" "CLIB = c:\lib" "DFLAGS = -DKANJI -DCRLF -UMSDOS -UM_I86MM -UM_I86"
+echo on
+goto realfinis
+:breakok
+del z-.msg
+ren z.msg z-.msg
+echo *** Starting Make. MAKE WILL STOP FOR ALL ERRORS (DEBUG OFF)
+make "AINC = c:\lib" "CLIB = c:\lib" "DFLAGS = -DKANJI -DCRLF -UMSDOS -UM_I86MM -UM_I86" >z.msg
+:finis
+echo on
+:realfinis
+if ERRORLEVEL 1 goto badend
+echo *** Make complete.
+goto theend
+:badend
+echo *** Errors found during make. 
+:theend
diff --git a/private/mvdm/wow16/write/left.bms b/private/mvdm/wow16/write/left.bms
new file mode 100644
index 000000000..7acce26ff
--- /dev/null
+++ b/private/mvdm/wow16/write/left.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/lib.asm b/private/mvdm/wow16/write/lib.asm
new file mode 100644
index 000000000..c6322a770
--- /dev/null
+++ b/private/mvdm/wow16/write/lib.asm
@@ -0,0 +1,474 @@
+ TITLE lib - various C library routines
+
+; Windows Write, Copyright 1985-1992 Microsoft Corporation
+;=============================================================================
+; This file contains various C library functions (and a few other
+; functions) with the PL/M calling conventions. These routines
+; may some day make their way into a real library of some kind, but
+; until then, you'll just have to link this file in with the rest
+; of your code.
+;=============================================================================
+
+?PLM = 1
+?WIN = 1
+
+;*** See note about cmacros2.inc in DOSLIB.ASM
+include cmacros3.inc
+
+;
+;createSeg _MMP2, code, byte, public, CODE
+;
+
+sBegin CODE
+; assumes CS,_MMP2
+ assumes CS,CODE
+
+;------------------------------------------------------------------------------
+; bltbyte (pbFrom, pbTo, cb) - a block transfer of bytes from pbFrom to
+; pbTo. The size of the block is cb bytes. This bltbyte() handles the
+; case of overlapping source and destination. bltbyte() returns a pointer
+; to the end of the destination buffer (pbTo + cb). NOTE - use this
+; bltbyte to transfer within the current DS only--use the bltbx for
+; FAR blts.
+;-----------------------------------------------------------------------------
+
+cProc bltbyte, <FAR, PUBLIC>, <SI, DI>
+parmDP <pbFrom, pbTo>
+parmW <cb>
+cBegin bltbyte
+ mov si,pbFrom ; get pointers and length of blt
+ mov di,pbTo
+ mov cx,cb
+ mov ax,di ; calculate return value
+ add ax,cx
+ push ds ; set up segment registers
+ pop es
+ cmp si,di ; reverse direction of the blt if
+ jae bltb1 ; necessary
+ add si,cx
+ add di,cx
+ dec si
+ dec di
+ std
+bltb1:
+ rep movsb
+ cld
+cEnd bltbyte
+
+;-----------------------------------------------------------------------------
+; bltbx (qbFrom, qbTo, cb) - same as bltbyte above except everything is
+; handled as FAR pointers.
+;-----------------------------------------------------------------------------
+
+cProc bltbx, <FAR, PUBLIC>, <SI, DI, DS>
+parmD <qbFrom, qbTo>
+parmW <cb>
+cBegin bltbx
+ les di,qbTo
+ lds si,qbFrom
+ mov cx,cb
+ mov ax,di
+ add ax,cx
+ cmp si,di
+ jae bltbx1
+ add si,cx
+ add di,cx
+ dec si
+ dec di
+ std
+bltbx1:
+ rep movsb
+ cld
+ mov dx,es
+cEnd bltbx
+
+
+;------------------------------------------------------------------------------
+; blt (pFrom, pTo, cw) - a block transfer of wFills from pFrom to pTo;
+; The size of the block is cw wFills. This blt() handles the case of
+; overlapping source and destination. blt() returns a pointer to the
+; end of the destination buffer (pTo + cw). NOTE - use this blt() to
+; to transfer within the current DS only--use the bltx for FAR blts.
+;-----------------------------------------------------------------------------
+
+cProc blt, <FAR, PUBLIC>, <SI, DI>
+parmDP <pFrom, pTo>
+parmW <cw>
+cBegin blt
+ mov si,pFrom ; get pointers and length of blt
+ mov di,pTo
+ mov cx,cw
+ mov ax,di ; calculate return value
+ mov bx,cx
+ shl bx,1
+ add ax,bx
+ push ds ; set up segment registers
+ pop es
+ cmp si,di ; reverse direction of the blt if
+ jae blt1 ; necessary
+ dec bx
+ dec bx
+ add si,bx
+ add di,bx
+ std
+blt1:
+ rep movsw
+ cld
+cEnd blt
+
+;-----------------------------------------------------------------------------
+; bltx (qFrom, qTo, cw) - same as blt() above except everything is
+; handled as FAR pointers.
+;-----------------------------------------------------------------------------
+
+cProc bltx, <FAR, PUBLIC>, <si, di, ds>
+parmD <qFrom, qTo>
+parmW <cw>
+cBegin bltx
+ les di,qTo
+ lds si,qFrom
+ mov cx,cw
+ mov ax,di
+ mov bx,cx
+ shl bx,1
+ add ax,bx
+ cmp si,di
+ jae bltx1
+ dec bx
+ dec bx
+ add si,bx
+ add di,bx
+ std
+bltx1:
+ rep movsw
+ cld
+ mov dx,es
+cEnd bltx
+
+;-----------------------------------------------------------------------------
+; bltc (pTo, wFill, cw) - fills cw words of memory starting at pTo with wFill.
+;-----------------------------------------------------------------------------
+
+cProc bltc, <FAR, PUBLIC>, <DI>
+parmDP <pTo>
+parmW <wFill, cw>
+cBegin bltc
+ mov ax,ds ; we are filling in the data segment
+ mov es,ax
+ mov di,pTo ; get the destination, constant, and count
+ mov ax,wFill
+ mov cx,cw
+ cld ; the operation is forward
+ rep stosw ; fill memory
+cEnd bltc
+
+;-----------------------------------------------------------------------------
+; bltcx (qTo, wFill, cw) - fills cw words of memory starting at FAR location
+; qTo with wFill.
+;-----------------------------------------------------------------------------
+
+cProc bltcx, <FAR, PUBLIC>, <DI>
+parmD <qTo>
+parmW <wFill, cw>
+cBegin bltcx
+ les di,qTo ; get the destination, constant, and count
+ mov ax,wFill
+ mov cx,cw
+ cld ; the operation is forward
+ rep stosw ; fill memory
+cEnd bltcx
+
+;-----------------------------------------------------------------------------
+; bltbc (pTo, bFill, cb) - fills cb bytes of memory starting at pTo with
+; bFill.
+;-----------------------------------------------------------------------------
+
+cProc bltbc, <FAR, PUBLIC>, <DI>
+parmDP <pTo>
+parmB <bFill>
+parmW <cb>
+cBegin bltbc
+ mov ax,ds ; we are filling in the data segment
+ mov es,ax
+ mov di,pTo ; get the destination, constant, and count
+ mov al,bFill
+ mov cx,cb
+ cld ; the operation is forward
+ rep stosb ; fill memory
+cEnd bltbc
+
+;-----------------------------------------------------------------------------
+; bltbcx (qTo, bFill, cb) - fills cb bytes of memory starting at FAR location
+; qTo with bFill.
+;-----------------------------------------------------------------------------
+
+cProc bltbcx, <FAR, PUBLIC>, <DI>
+parmD <qTo>
+parmB <bFill>
+parmW <cb>
+cBegin bltbcx
+ les di,qTo ; get the destination, constant, and count
+ mov al,bFill
+ mov cx,cb
+ cld ; the operation is forward
+ rep stosb ; fill memory
+cEnd bltbcx
+
+
+
+;-----------------------------------------------------------------------------
+; MultDiv(w, Numer, Denom) returns (w * Numer) / Denom rounded to the nearest
+; integer. A check is made so that division by zero is not attempted.
+;-----------------------------------------------------------------------------
+
+cProc MultDiv, <FAR, PUBLIC>
+parmW <w, Numer, Denom>
+cBegin MultDiv
+ mov bx,Denom ; get the demoninator
+ mov cx,bx ; cx holds the final sign
+ or bx,bx ; ensure the denominator is positive
+ jns md1
+ neg bx
+md1:
+ mov ax,w ; get the word we are multiplying
+ xor cx,ax ; make cx reflect any sign change
+ or ax,ax ; ensure this word is positive
+ jns md2
+ neg ax
+md2:
+ mov dx,Numer ; get the numerator
+ xor cx,dx ; make cx reflect any sign change
+ or dx,dx ; ensure the numerator is positive
+ jns md3
+ neg dx
+md3:
+ mul dx ; multiply
+ mov cl,bl ; get half of the demoninator to adjust for rounding
+ sar bx,1
+ add ax,bx ; adjust for possible rounding error
+ adc dx,0 ; this is really a long addition
+ sal bx,1 ; restore the demoninator
+ or bl,cl
+ cmp dx,bx ; check for overflow
+ jae md5
+ div bx ; divide
+ or ax,ax ; if sign is set, then overflow occured
+ js md5
+ or cx,cx ; put the sign on the result
+ jns md4
+ neg ax
+md4:
+
+cEnd MultDiv
+
+md5:
+ mov ax,7FFFh ; return the largest integer
+ or cx,cx ; with the correct sign
+ jns md4
+ neg ax
+ jmp md4
+
+;-----------------------------------------------------------------------------
+; FSzSame (szOne, szTwo) - Compare strings, return 1=Same, 0=different
+; Both strings in DS
+;-----------------------------------------------------------------------------
+
+cProc FSzSame, <FAR, PUBLIC>, <SI>
+parmDP <szOne>
+parmDP <szTwo>
+cBegin FszSame
+
+ mov bx,szOne
+ mov si,szTwo
+
+fszloop:
+ mov al,[bx]
+ cmp al,[si]
+ jnz notequal ; found inequality - return FALSE
+ inc bx
+ inc si
+ test al,al
+ jnz fszloop ; didn't reach a zero-terminator compare next char
+
+ mov ax,1
+ jmp fszend
+notequal:
+ xor ax,ax
+fszend:
+
+cEnd FszSame
+
+
+;-----------------------------------------------------------------------------
+; CchDiffer (rgch1,rgch2,cch) - compare 2 strings, returning cch of
+; shortest prefix leaving a common remainder
+; implementation of the following C code
+; note rather odd return values: 0 if =, # of unmatched chars +1 otherwise.
+; note comparison is from end of string
+;** int CchDiffer(rgch1, rgch2, cch)
+;** register CHAR *rgch1, *rgch2;
+;** int cch;
+;** {{ /* Return cch of shortest prefix leaving a common remainder */
+;** int ich;
+
+;** for (ich = cch - 1; ich >= 0; ich--)
+ ;** if (rgch1[ich] != rgch2[ich])
+ ;** break;
+;** return ich + 1;
+;** }}
+;-----------------------------------------------------------------------------
+
+ cProc CchDiffer, <FAR, PUBLIC>, <SI,DI>
+ parmDP <rgch1>
+ parmDP <rgch2>
+ parmW <cch>
+ cBegin CchDiffer
+ mov ax,ds ; set es=ds for string ops
+ mov es,ax
+
+ mov si,rgch1
+ mov di,rgch2
+ mov cx,cch ; loop count in cx
+ mov ax,cx ; compare from end of string down
+ dec ax
+ add si,ax
+ add di,ax
+ std
+ repz cmpsb ; compare strings
+ jz DiffRet ; return 0 if strings =
+ inc cx ; else increment return value
+DiffRet:
+ mov ax,cx ; return # of unmatched chars
+ cld ; restore to be nice
+ cEnd CchDiffer
+
+
+ifdef DEBUG
+
+;-----------------------------------------------------------------------------
+; toggleProf () - toggles winprof (windows profiler) profiling on or off.
+; this calls to hard coded locations that both symdeb and winprof know
+; about - see Lyle Kline for an actual explanation.
+;-----------------------------------------------------------------------------
+
+cProc toggleProf, <FAR, PUBLIC>
+cBegin toggleProf
+
+ ; ** the following strings are stored by the profiler starting at
+ ; ** 100h of the loaded segment. This routine checks that the 1st
+ ; ** 3 letters of each string are in the proper location to determine
+ ; ** whether the profiler is already loaded.
+
+; **** segname db "SEGDEBUG",0
+; **** db "PROFILER",0
+
+ push es
+ push di
+ push si
+ xor ax,ax
+ mov es,ax
+ mov ax,es:[14] ;Get segment down there.
+ mov es,ax
+ mov di,0100h ;See if Profiler in memory.
+
+ cmp Byte Ptr es:[di],'S'
+ jnz $0001
+
+ cmp Byte Ptr es:[di+1],'E'
+ jnz $0001
+
+ cmp Byte Ptr es:[di+2],'G'
+ jnz $0001
+
+ cmp Byte Ptr es:[di+9],'P'
+ jnz $0001
+
+ cmp Byte Ptr es:[di+10],'R'
+ jnz $0001
+
+ mov ax,30 ;Type of call.
+ push ax
+
+ mov di,00FCh
+ call Dword Ptr es:[di] ; call to profiler toggle routine.
+ add sp,2 ; winprof uses normal c conventions
+
+$0001:
+ pop si
+ pop di
+ pop es
+
+cEnd toggleProf
+
+endif
+
+;-----------------------------------------------------------------------------
+; void OsTime( pTime )
+;
+; pTime is a pointer to a structure of the form:
+; struct {
+; char min; Minutes (0-59)
+; char hour; Hours (0-23)
+; char hsec; Hundredths of seconds (0-99)
+; char sec; Seconds (0-59)
+;
+; Get current time into structure
+; DOS-specific
+;-----------------------------------------------------------------------------
+
+cProc OsTime, <FAR, PUBLIC>
+parmDP <pTime>
+cBegin OsTime
+
+ mov ah,2ch
+ int 21h
+
+ mov bx,pTime
+ mov WORD PTR [bx], cx
+ mov WORD PTR [bx+2], dx
+
+cEnd OsTime
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Added by PaulT 3/23/89, borrowed from PC Word 5:
+;
+; IchIndexLp(lpsz, ch)
+; char far *lpsz;
+; int ch;
+; Searches for ch in lpsz and returns the index (-1 if not found)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+cProc IchIndexLp,<FAR, PUBLIC>
+ parmD lpsz
+ parmB chT
+cBegin
+ mov dx, di ; Save di
+ les di, lpsz
+ mov ah, chT
+ xor al,al
+ mov bx, di ; Save initial pointer
+ ; **** Can't access parms anymore
+
+ mov cx,-1
+ repnz scasb ; Must have '\0'
+ or ax, ax
+ jz LDoneILI
+ mov al, ah ; al = chT
+ not cx
+ dec cx
+ mov di, bx
+ repnz scasb
+ jz LDoneILI
+ mov di, bx
+LDoneILI:
+ mov ax, di
+ sub ax, bx
+ dec ax ; ax = return value
+ mov di, dx ; Restore di
+cEnd IchIndexLp
+
+
+sEnd CODE
+
+ END
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/lmargin.bms b/private/mvdm/wow16/write/lmargin.bms
new file mode 100644
index 000000000..41fde338f
--- /dev/null
+++ b/private/mvdm/wow16/write/lmargin.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/loadfnt2.c b/private/mvdm/wow16/write/loadfnt2.c
new file mode 100644
index 000000000..dcc7b195f
--- /dev/null
+++ b/private/mvdm/wow16/write/loadfnt2.c
@@ -0,0 +1,155 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* loadfnt2.c - MW font support code */
+
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOWINSTYLES
+#define NOCTLMGR
+#define NOCLIPBOARD
+#include <windows.h>
+
+#include "mw.h"
+#include "macro.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "fontdefs.h"
+#include "docdefs.h"
+
+
+extern int vifceMac;
+extern union FCID vfcidScreen;
+extern union FCID vfcidPrint;
+extern struct FCE rgfce[ifceMax];
+extern struct FCE *vpfceMru;
+extern struct FCE *vpfceScreen;
+extern struct FCE *vpfcePrint;
+extern struct DOD (**hpdocdod)[];
+
+
+struct FCE * (PfceLruGet(void));
+struct FCE * (PfceFcidScan(union FCID *));
+
+
+struct FCE * (PfceLruGet())
+/* tosses out the LRU cache entry's information */
+
+ {
+ struct FCE *pfce;
+
+ pfce = vpfceMru->pfcePrev;
+ FreePfce(pfce);
+ return(pfce);
+ }
+
+
+FreePfce(pfce)
+/* frees the font objects for this cache entry */
+struct FCE *pfce;
+
+ {
+ int ifce;
+ HFONT hfont;
+
+ if (pfce->fcidRequest.lFcid != fcidNil)
+ {
+ hfont = pfce->hfont;
+
+ /* see if we're about to toss the screen or printer's current font */
+ if (pfce == vpfceScreen)
+ {
+ ResetFont(FALSE);
+ }
+ else if (pfce == vpfcePrint)
+ {
+ ResetFont(TRUE);
+ }
+
+#ifdef DFONT
+ CommSzNum("Deleting font: ", hfont);
+#endif /* DFONT */
+
+ if (hfont != NULL)
+ {
+ DeleteObject(hfont);
+ pfce->hfont = NULL;
+ }
+
+ if (pfce->hffn != 0)
+ {
+ FreeH(pfce->hffn);
+ }
+
+ pfce->fcidRequest.lFcid = fcidNil;
+ }
+ }
+
+
+FreeFonts(fScreen, fPrinter)
+/* frees up the font objects for the screen, and the printer */
+
+int fScreen, fPrinter;
+ {
+ int ifce, bit;
+
+ for (ifce = 0; ifce < vifceMac; ifce++)
+ {
+ bit = (rgfce[ifce].fcidRequest.strFcid.wFcid & bitPrintFcid) != 0;
+ if (bit && fPrinter || !bit && fScreen)
+ FreePfce(&rgfce[ifce]);
+ }
+ }
+
+
+struct FCE * (PfceFcidScan(pfcid))
+union FCID *pfcid;
+
+/* look for this font the "hard way" in the LRU list */
+ {
+ struct FFN **hffn, **hffnT;
+ register struct FCE *pfce;
+ struct FFN **MpFcidHffn();
+
+ hffn = MpFcidHffn(pfcid);
+ pfce = vpfceMru;
+ do
+ {
+ hffnT = pfce->hffn;
+ if (hffnT != NULL)
+ if (WCompSz((*hffn)->szFfn, (*hffnT)->szFfn) == 0 &&
+ pfcid->strFcid.hps == pfce->fcidRequest.strFcid.hps &&
+ pfcid->strFcid.wFcid == pfce->fcidRequest.strFcid.wFcid)
+ {
+ pfce->fcidRequest.strFcid.doc = pfcid->strFcid.doc;
+ pfce->fcidRequest.strFcid.ftc = pfcid->strFcid.ftc;
+ return(pfce);
+ }
+ pfce = pfce->pfceNext;
+ }
+ while (pfce != vpfceMru);
+
+ return(NULL);
+ }
+
+
+
+struct FFN **MpFcidHffn(pfcid)
+/* makes sure we use a font code that exists in the table - this is insurance
+ against out of memory problems */
+
+union FCID *pfcid;
+ {
+ int ftc;
+ struct FFNTB **hffntb;
+
+ ftc = pfcid->strFcid.ftc;
+ hffntb = HffntbGet(pfcid->strFcid.doc);
+ if (ftc >= (*hffntb)->iffnMac)
+ ftc = 0;
+
+ return((*hffntb)->mpftchffn[ftc]);
+ }
diff --git a/private/mvdm/wow16/write/loadfont.c b/private/mvdm/wow16/write/loadfont.c
new file mode 100644
index 000000000..18ac854d7
--- /dev/null
+++ b/private/mvdm/wow16/write/loadfont.c
@@ -0,0 +1,1063 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* loadfont.c - MW font support code */
+
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOWINSTYLES
+#define NOCTLMGR
+#define NOCLIPBOARD
+#include <windows.h>
+
+#include "mw.h"
+#include "propdefs.h"
+#include "macro.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "fontdefs.h"
+#include "docdefs.h"
+
+#ifdef DBCS
+#include "dbcs.h"
+#include "kanji.h"
+#endif
+
+extern HDC vhMDC;
+extern HDC vhDCPrinter;
+extern struct CHP vchpNormal;
+extern int vifceMac;
+extern union FCID vfcidScreen;
+extern union FCID vfcidPrint;
+extern struct FCE rgfce[ifceMax];
+extern struct FCE *vpfceMru;
+extern struct FCE *vpfceScreen;
+extern struct FCE *vpfcePrint;
+extern struct FMI vfmiScreen;
+extern struct FMI vfmiPrint;
+#ifdef SYSENDMARK
+extern struct FMI vfmiSysScreen;
+#endif /* KANJI */
+
+
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern int ypSubSuperPr;
+extern BOOL vfPrinterValid;
+
+
+#ifdef DEBUG
+BOOL NEAR DogoneTrashTest(HDC hdc, struct FCE *pfce, BOOL fPrint);
+#endif
+
+NEAR LoadFcid(union FCID *, struct CHP *);
+void NEAR SelectWriteFont(int, HFONT *);
+struct FCE * (PfceFcidScan(union FCID *));
+struct FCE * (PfceLruGet(void));
+#ifdef SMFONT
+void NEAR FillWidthTable(HDC, int [], TEXTMETRIC *);
+#endif /* SMFONT */
+
+
+LoadFont( doc, pchp, mdFont )
+/* loads the font specified in pchp for this doc. mdFont tells us how the
+ font will be used (printer, screen, screen modulo printer,... */
+
+int doc;
+register struct CHP *pchp;
+int mdFont;
+
+ {
+ register int wFcid;
+ struct CHP *pchpT;
+ union FCID fcid;
+
+ Assert(doc != docNil);
+
+ pchpT = pchp;
+ if (pchp == NULL)
+ pchp = &vchpNormal;
+
+ fcid.strFcid.hps = pchp->hps;
+ fcid.strFcid.ftc = pchp->ftc;
+ fcid.strFcid.doc = doc;
+#ifdef ENABLE
+ wFcid = pchp->psWidth;
+ wFcid |= bitPrintFcid;
+ if (pchp->fItalic)
+ wFcid |= bitItalicFcid;
+ if (pchp->fBold)
+ wFcid |= bitBoldFcid;
+ if (pchp->fUline)
+ wFcid |= bitUlineFcid;
+ if (pchp->fFixedPitch)
+ wFcid |= bitFixedPitchFcid;
+ fcid.strFcid.wFcid = wFcid;
+#else
+ /* Super-nitpick-optimization (but worth it because LoadFont can take
+ 10% of display refresh time): bits being cleared is more
+ common than set, and a "jump not taken" plus an "or di, xxxx" is 8
+ cycles, vs the above "jump taken" which is 16 */
+
+ wFcid = pchp->psWidth + bitPrintFcid + bitItalicFcid + bitBoldFcid +
+ bitUlineFcid + bitFixedPitchFcid;
+ if (!pchp->fItalic)
+ wFcid &= ~bitItalicFcid;
+ if (!pchp->fBold)
+ wFcid &= ~bitBoldFcid;
+ if (!pchp->fUline)
+ wFcid &= ~bitUlineFcid;
+ if (!pchp->fFixedPitch)
+ wFcid &= ~bitFixedPitchFcid;
+ fcid.strFcid.wFcid = wFcid;
+#endif
+
+ switch (mdFont)
+ {
+ /* fall throughs are intentional! */
+
+ default:
+ break;
+
+ case mdFontChk: /* sets font as constrained by printer avail */
+ case mdFontPrint: /* like mdFontScreen, but for the printer */
+ /* don't want to jam the chp props back */
+ pchpT = NULL;
+
+ case mdFontJam: /* like mdFontChk, but jams props into chp */
+
+ /* get printer font loaded */
+ LoadFcid(&fcid, pchpT);
+
+ if (mdFont == mdFontPrint)
+ /* don't need screen font */
+ return;
+
+ case mdFontScreen: /* sets font for random screen chars */
+ /* get screen font loaded */
+ fcid.strFcid.wFcid &= ~bitPrintFcid;
+ LoadFcid(&fcid, (struct CHP *)NULL);
+ }
+ }
+
+
+NEAR LoadFcid(pfcid, pchp)
+/* loads described font and associates it with the appropriate dc's */
+
+union FCID *pfcid;
+struct CHP *pchp;
+ {
+ register struct FCE *pfce;
+ int fPrint;
+ int fTouchAndGo;
+ int fGetMetrics;
+ int fNewFont;
+ struct FFN **hffnSave;
+ LOGFONT lf;
+
+#ifdef SYSENDMARK
+ fPrint = pfcid->strFcid.wFcid & bitPrintFcid;
+
+ /* Since this ftc came from CHP, we have lost the first 2 bits. */
+ if (pfcid->strFcid.ftc == (bitFtcChp & ftcSystem)) {
+ /* If vpfceScreen == NULL already, the standard system font
+ has already been selected. So, save some time here. */
+ if (vpfceScreen != NULL) {
+ /* Gives you the standard system font for the screen. */
+ ResetFont(FALSE);
+ }
+ bltbyte(&vfmiSysScreen, &vfmiScreen, sizeof(struct FMI));
+#if defined(KANJI) && defined(DFONT)
+ /* CommSz("System Font!\r\n"); */
+ KTS();
+#endif
+ return;
+ }
+ else if (fPrint)
+#else
+ if ((fPrint = pfcid->strFcid.wFcid & bitPrintFcid))
+#endif /* if-else-def KANJI */
+ {
+ if (pfcid->lFcid == vfcidPrint.lFcid)
+ {
+ pfce = vpfcePrint;
+ fTouchAndGo = TRUE;
+ goto EstablishFont;
+ }
+ }
+ else
+ {
+ if (pfcid->lFcid == vfcidScreen.lFcid)
+ {
+ pfce = vpfceScreen;
+ fTouchAndGo = TRUE;
+ goto EstablishFont;
+ }
+ }
+
+ /* failed at the "trivial" comparisons - look through list */
+ fTouchAndGo = FALSE;
+ pfce = vpfceMru;
+ do
+ {
+ if (pfce->fcidRequest.lFcid == pfcid->lFcid)
+ {
+ /* found a match */
+ fGetMetrics = FALSE;
+ goto EstablishFont;
+ }
+ pfce = pfce->pfceNext;
+ }
+ while (pfce != vpfceMru);
+
+ /* failed at the "easy" search - look for name text & property match */
+ fGetMetrics = TRUE;
+ if (fNewFont = (pfce = PfceFcidScan(pfcid)) == NULL)
+ {
+ /* this font isn't in our list - we have to create it */
+ int wFcid = pfcid->strFcid.wFcid;
+ int dyaHeight;
+ int cwAlloc;
+ int ich;
+ struct FFN **hffnT;
+ struct FFN **MpFcidHffn();
+
+ pfce = PfceLruGet(); /* disposes of a font to make room */
+
+ bltbc(&lf, 0, sizeof(LOGFONT));
+ dyaHeight = pfcid->strFcid.hps * (czaPoint / 2);
+ if (fPrint)
+ {
+ lf.lfHeight = -MultDiv(dyaHeight, dypPrPage, dyaPrPage);
+ }
+ else
+ {
+ /* In the Z version we have tried the idea of using a
+ positive value for selection based on cell height
+ rather than character height because of weirdness
+ with the Courier screen font -- but it seemed to
+ screw too many things up (like make all other fonts
+ a bit too small and it didn't always make Courier
+ work right). I believe Win Word *is* using this
+ trick but only when selecting Courier fonts. It
+ seems to me like there has got to be a different
+ cause of this anamoly. ..pault 9/22/89 */
+
+ lf.lfHeight = -MultDiv(dyaHeight, dypLogInch, czaInch);
+ if (wFcid & grpbitPsWidthFcid)
+ {
+ //lf.lfWidth = MultDiv((wFcid & grpbitPsWidthFcid) * czaPoint,
+ //dxpLogInch, czaInch);
+ lf.lfWidth = 0;
+ }
+ }
+
+ if (wFcid & bitItalicFcid)
+ {
+ lf.lfItalic = 1;
+ }
+ if (wFcid & bitUlineFcid)
+ {
+ lf.lfUnderline = 1;
+ }
+ lf.lfWeight = wFcid & bitBoldFcid ? FW_BOLD : FW_NORMAL;
+
+ hffnSave = MpFcidHffn(pfcid);
+
+#ifdef JAPAN
+// When we need system font, we want rather variable pitch than fixed,
+// since fixed pitch system font is probably same as terminal font.
+// So we specify VARIABLE_PITCH especialy for system font.
+
+{
+ extern char szSystem[];
+ extern char szAtSystem[];
+
+ if( WCompSz(szSystem,(*hffnSave)->szFfn) == 0
+ || WCompSz(szAtSystem,(*hffnSave)->szFfn) == 0 )// Add '@'systemfont
+ lf.lfPitchAndFamily = (*hffnSave)->ffid | VARIABLE_PITCH ;
+ else
+ lf.lfPitchAndFamily
+ = ((*hffnSave)->ffid) | ((wFcid & bitPrintFcid) ?
+ DEFAULT_PITCH : ((wFcid & bitFixedPitchFcid) ? FIXED_PITCH :
+ VARIABLE_PITCH));
+}
+#else
+ lf.lfPitchAndFamily = ((*hffnSave)->ffid) | ((wFcid & bitPrintFcid) ?
+ DEFAULT_PITCH : ((wFcid & bitFixedPitchFcid) ? FIXED_PITCH :
+ VARIABLE_PITCH));
+#endif
+
+#if defined(NEWFONTENUM) && !defined(KANJI)
+ lf.lfCharSet = (*hffnSave)->chs; /* pass the character set that
+ enumfonts told us this fontname
+ was associated with ..pault */
+#endif
+
+ ich = 0;
+ if ((*hffnSave)->szFfn[0] == chGhost)
+ {
+ ich++;
+ }
+ bltszLimit(&(*hffnSave)->szFfn[ich], lf.lfFaceName, LF_FACESIZE);
+
+#ifdef KOREA
+ if ( (*hffnSave)->szFfn[ich] > 0xA0 ||
+ ( (*hffnSave)->szFfn[ich]=='@' && (*hffnSave)->szFfn[ich+1] > 0xA0 ) ||
+ ( WCompSz(lf.lfFaceName,"terminal")==0 ) ||
+ ( WCompSz(lf.lfFaceName,"@terminal")==0 ) ||
+ ( WCompSz(lf.lfFaceName,"system")==0 ) ||
+ ( WCompSz(lf.lfFaceName,"@system")==0 ) )
+
+ lf.lfCharSet = HANGEUL_CHARSET;
+#endif
+
+#if defined(DFONT) || defined (PRDRVTEST)
+ {
+ char rgch[100];
+ wsprintf(rgch, "Creating %s font: %s,\t\th %d, w %d, charset %d\n\r",
+ (LPSTR)(fPrint ? "prt" : "scr"), (LPSTR)lf.lfFaceName,
+ lf.lfHeight, lf.lfWidth, (int)(lf.lfCharSet));
+ CommSz(rgch);
+
+ CommSzNum(" Requested weight: ", lf.lfWeight);
+ CommSzNum(" Requested italics: ", lf.lfItalic);
+ CommSzNum(" Requested underline: ", lf.lfUnderline);
+ CommSzNum(" Requested family: ", lf.lfPitchAndFamily >> 4);
+ CommSzNum(" Requested pitch: ", lf.lfPitchAndFamily & 3);
+ }
+#endif /* DFONT */
+
+ if ((pfce->hfont = CreateFontIndirect((LPLOGFONT)&lf)) == NULL)
+ {
+ pfce->hfont = GetStockObject( fPrint && vfPrinterValid ?
+ DEVICE_DEFAULT_FONT : SYSTEM_FONT );
+ Assert( pfce->hfont );
+ /* if the above fails, I don't know what we can do */
+
+ WinFailure(); /* report the failure so we give the user notice
+ for weird behavior to follow */
+ }
+
+#ifdef DFONT
+ CommSzNum("Font handle: ", pfce->hfont);
+#endif /* DFONT */
+
+ pfce->fcidRequest = *pfcid;
+ cwAlloc = CwFromCch(CbFfn(CchSz((*hffnSave)->szFfn)));
+ if (FNoHeap(hffnT = (struct FFN **)HAllocate(cwAlloc)))
+ {
+ FreePfce(pfce);
+ return;
+ }
+ else
+ {
+ blt((*hffnSave), (*hffnT), cwAlloc);
+ }
+ pfce->hffn = hffnT;
+ }
+
+EstablishFont:
+ if ((pfce != vpfceMru) && (pfce != vpfceMru->pfceNext))
+ {
+ /* make this the mru font cache entry */
+ /* Only do it if pfce is not already one of the first 2 mru fonts */
+ /* since we generally ask for the things in groups of 2 */
+
+ /* pull it out of its current place */
+ pfce->pfceNext->pfcePrev = pfce->pfcePrev;
+ pfce->pfcePrev->pfceNext = pfce->pfceNext;
+
+ /* insert it at mru position */
+ pfce->pfceNext = vpfceMru;
+ pfce->pfcePrev = vpfceMru->pfcePrev;
+ pfce->pfceNext->pfcePrev = pfce;
+ pfce->pfcePrev->pfceNext = pfce;
+ vpfceMru = pfce;
+
+#ifndef DISCARDABLE_FONTS
+ /* KLUDGE ALERT: To accomodate Windows inability to make synthesized
+ fonts discardable, we will now throw out the third font in the LRU chain
+ if it is taller than 16 points. (Ain't this a doozey...) */
+ {
+ register struct FCE *pfceThird = vpfceMru->pfceNext->pfceNext;
+
+ if (pfceThird->fcidRequest.lFcid != fcidNil &&
+#ifdef OLD
+ pfceThird->fcidActual.strFcid.hps > 32)
+#else
+ pfceThird->fcidActual.strFcid.hps > 48)
+#endif /* if-else-def OLD */
+ {
+ /* Free this particular font. */
+ FreePfce(pfceThird);
+ }
+ }
+#endif /* not DISCARDABLE_FONTS */
+
+ }
+
+ if (!fTouchAndGo)
+ {
+ /* we have this font in our cache, but we need to select it */
+ SelectWriteFont(fPrint, &pfce->hfont);
+
+ /**
+ I wish I knew why this is needed, but I don't want to spend
+ more time on it. For some reason the font width table
+ (pfce->rgdxp) is getting either trashed or is simply
+ incorrect when first obtained. I suspect it is a GDI bug
+ because it only happens the first time you use certain fonts
+ (at least in Write) during a given session of Windows.
+ The DogoneTrashTest detects the problem and fixes it.
+ It is slow though, unfortunately.
+ (7.25.91) v-dougk.
+ **/
+
+#ifdef DEBUG
+ if (!fGetMetrics)
+ DogoneTrashTest(fPrint ? vhDCPrinter : vhMDC, pfce, fPrint);
+#endif
+
+ if (fGetMetrics)
+ {
+ register union FCID *pfcidT = &pfce->fcidActual;
+ HDC hDCMetrics = fPrint ? vhDCPrinter : vhMDC;
+ TEXTMETRIC tm;
+
+ Assert(hDCMetrics);
+ if (hDCMetrics == NULL)
+ return;
+
+ GetTextMetrics(hDCMetrics, (LPTEXTMETRIC)&tm);
+ if (fNewFont)
+ {
+ /* We need all of the metrics for this guy. */
+ CHAR szFace[LF_FACESIZE];
+ int wFcid;
+ int dypHeight;
+ int dxpch;
+
+#if defined(DFONT) || defined(PRDRVTEST)
+ {
+ char rgch[100];
+ GetTextFace(hDCMetrics, LF_FACESIZE, (LPSTR)szFace);
+ wsprintf(rgch, " Actual fname: %s,\t\th %d, w %d, charset %d\n\r",
+ (LPSTR)szFace, tm.tmHeight-tm.tmInternalLeading,
+ tm.tmAveCharWidth, (int)(tm.tmCharSet));
+ CommSz(rgch);
+ }
+ CommSzNum(" Actual width: ", tm.tmAveCharWidth);
+ CommSzNum(" Actual leading: ", tm.tmInternalLeading +
+ tm.tmExternalLeading);
+ CommSzNum(" Actual weight: ", tm.tmWeight);
+ CommSzNum(" Actual italics: ", tm.tmItalic);
+ CommSzNum(" Actual underline: ", tm.tmUnderlined);
+ CommSzNum(" Actual font family: ", tm.tmPitchAndFamily >>
+ 4);
+ CommSzNum(" Actual pitch: ", tm.tmPitchAndFamily & 1);
+#endif /* DFONT */
+
+ SetTextJustification(hDCMetrics, 0, 0);
+ pfce->fmi.dxpOverhang = tm.tmOverhang;
+ pfce->fmi.dxpSpace = LOWORD(GetTextExtent(hDCMetrics,
+ (LPSTR)" ", 1)) - tm.tmOverhang;
+#ifdef PRDRVTEST
+ {
+ /* Just so no printers or printer driver manufacturers
+ get funky on us! ..pault */
+ int dxpSpace = pfce->fmi.dxpSpace + tm.tmOverhang;
+
+ CommSzNum(" GetTextExtent(space) ", LOWORD(GetTextExtent(hDCMetrics, (LPSTR)" ", 1)));
+ if (dxpSpace < 1 || dxpSpace > tm.tmMaxCharWidth+tm.tmOverhang)
+ {
+ pfce->fmi.dxpSpace = tm.tmAveCharWidth;
+ CommSzNum(" ...resetting to ",pfce->fmi.dxpSpace);
+ }
+ }
+#endif
+ pfce->fmi.dypAscent = tm.tmAscent;
+ pfce->fmi.dypDescent = tm.tmDescent;
+ pfce->fmi.dypBaseline = tm.tmAscent;
+ pfce->fmi.dypLeading = tm.tmExternalLeading;
+#ifdef DBCS
+ pfce->fmi.dypIntLeading = tm.tmInternalLeading;
+#ifdef KOREA
+ if (tm.tmPitchAndFamily & 1) /* Is variable pitch ? */
+ pfce->fmi.dxpDBCS = dxpNil;
+ else
+#endif
+ {
+ CHAR rgchT[cchDBCS];
+ int dxpDBCS;
+
+ rgchT[0] = rgchT[1] = bKanji1Min;
+
+ dxpDBCS = LOWORD(GetTextExtent(hDCMetrics,
+ (LPSTR) rgchT, cchDBCS));
+ pfce->fmi.dxpDBCS =
+ (BYTE) ((0 <= dxpDBCS && dxpDBCS < dxpNil) ? dxpDBCS : dxpNil);
+ }
+#endif
+
+#ifdef SMFONT
+ FillWidthTable(hDCMetrics, pfce->rgdxp, &tm);
+#ifdef DEBUG
+ if (DogoneTrashTest(hDCMetrics, pfce, fPrint))
+ OutputDebugString("That was an immediate check\n\r");
+#endif
+
+#else /* not SMFONT */
+ /* Fill the width table. If this is a fixed font and the width
+ fits in a byte, then go ahead and fill the width table with the
+ width; otherwise, put dxpNil in the table. */
+ dxpch = (tm.tmPitchAndFamily & 1 || tm.tmAveCharWidth >= dxpNil)
+ ? dxpNil : tm.tmAveCharWidth;
+ bltc(pfce->rgdxp, dxpch, chFmiMax - chFmiMin);
+#endif /* SMFONT */
+
+ if ((*hffnSave)->ffid == FF_DONTCARE && (tm.tmPitchAndFamily &
+ grpbitFamily) != FF_DONTCARE)
+ {
+ /* Hey! maybe we've discovered a family for this orphan
+ font? */
+ GetTextFace(hDCMetrics, LF_FACESIZE, (LPSTR)szFace);
+ if (WCompSz((*hffnSave)->szFfn, szFace) == 0)
+ {
+ /* name matches - jam family in */
+ (*hffnSave)->ffid = tm.tmPitchAndFamily & grpbitFamily;
+ }
+ }
+
+ /* jam back the properties we found */
+ dypHeight = tm.tmHeight - tm.tmInternalLeading;
+ if (fPrint)
+ {
+ /* Save the height of this font. */
+ pfcidT->strFcid.hps = umin((MultDiv(dypHeight, dyaPrPage,
+ dypPrPage) + (czaPoint / 4)) / (czaPoint / 2), 0xff);
+
+#ifdef APLLW
+ /* Save the width of this font if it is a fixed pitch
+ device font. */
+ wFcid = ((tm.tmPitchAndFamily & 0x09) == 0x08) ?
+#else
+ /* Save the width of this font if it is a device font. */
+#ifdef KOREA /* give width info for all (like excel) to select DuBae shape */
+ wFcid = (1==1) ?
+#else
+ wFcid = (tm.tmPitchAndFamily & 0x08) ?
+#endif
+
+#endif /* if-else-def APLLW */
+ umin((MultDiv(tm.tmAveCharWidth, dxaPrPage, dxpPrPage) +
+ (czaPoint / 2)) / czaPoint, psWidthMax) : 0;
+ wFcid |= bitPrintFcid;
+ }
+ else
+ {
+ pfcidT->strFcid.hps = umin((MultDiv(dypHeight, czaInch,
+ dypLogInch) + (czaPoint / 4)) / (czaPoint / 2), 0xff);
+ wFcid = 0;
+ }
+
+ if (tm.tmWeight > (FW_NORMAL + FW_BOLD) / 2)
+ {
+ wFcid |= bitBoldFcid;
+ }
+
+ if (tm.tmItalic)
+ {
+ wFcid |= bitItalicFcid;
+ }
+
+ if (tm.tmUnderlined)
+ {
+ wFcid |= bitUlineFcid;
+ }
+
+ if ((tm.tmPitchAndFamily & bitPitch) == 0)
+ {
+ wFcid |= bitFixedPitchFcid;
+ }
+
+ pfcidT->strFcid.wFcid = wFcid;
+ }
+
+ /* Set the document and the font code. */
+ pfcidT->strFcid.doc = pfce->fcidRequest.strFcid.doc;
+ if (fPrint)
+ {
+ CHAR rgb[ibFfnMax];
+ struct FFN *pffn = (struct FFN *)&rgb[0];
+
+ /* Get the font code for this font. */
+ GetTextFace(vhDCPrinter, LF_FACESIZE, (LPSTR)pffn->szFfn);
+ if (WCompSz(pffn->szFfn, (*pfce->hffn)->szFfn) == 0)
+ {
+ /* The face name is the same as what we requested; so, the
+ font code should be the same. */
+ pfcidT->strFcid.ftc = pfce->fcidRequest.strFcid.ftc;
+ }
+ else
+ {
+ /* Well, we've got to go hunting for the font code. */
+ int ftc;
+
+ pffn->ffid = tm.tmPitchAndFamily & grpbitFamily;
+#ifdef NEWFONTENUM
+ pffn->chs = tm.tmCharSet;
+#endif
+ ftc = FtcScanDocFfn(pfcidT->strFcid.doc, pffn);
+ if (ftc == ftcNil)
+ {
+ /* Make the first character of the face name a sentinal
+ to mark that this font was not requested by the user. */
+ bltszLimit(pffn->szFfn, &pffn->szFfn[1], LF_FACESIZE);
+ pffn->szFfn[0] = chGhost;
+ ftc = FtcChkDocFfn(pfcidT->strFcid.doc, pffn);
+ }
+ pfcidT->strFcid.ftc = ftc;
+ }
+ }
+ else
+ {
+ pfcidT->strFcid.ftc = pfce->fcidRequest.strFcid.ftc;
+ }
+ }
+
+ if (fPrint)
+ {
+ vpfcePrint = pfce;
+ vfcidPrint = pfce->fcidRequest;
+ bltbyte(&pfce->fmi, &vfmiPrint, sizeof(struct FMI));
+ }
+ else
+ {
+ vpfceScreen = pfce;
+ vfcidScreen = pfce->fcidRequest;
+ bltbyte(&pfce->fmi, &vfmiScreen, sizeof(struct FMI));
+ }
+ }
+
+ if (pfce->fcidRequest.lFcid != pfce->fcidActual.lFcid)
+ {
+ /* all's not as we asked for - feed properties back to caller */
+ pfcid->lFcid = pfce->fcidActual.lFcid;
+ if (pchp != NULL)
+ { /* JamChpFcid(pchp, pfcid) bring in line for speed */
+ register struct CHP *pchpT = pchp;
+ int wFcid = pfcid->strFcid.wFcid;
+
+ pchpT->ftc = pfcid->strFcid.ftc;
+ pchpT->hps = pfcid->strFcid.hps;
+ pchpT->psWidth = wFcid & grpbitPsWidthFcid;
+
+ pchpT->fBold = pchpT->fItalic = pchpT->fUline = pchpT->fFixedPitch =
+ FALSE;
+
+ if (wFcid & bitBoldFcid)
+ {
+ pchpT->fBold = TRUE;
+ }
+ if (wFcid & bitItalicFcid)
+ {
+ pchpT->fItalic = TRUE;
+ }
+ if (wFcid & bitUlineFcid)
+ {
+ pchpT->fUline = TRUE;
+ }
+ if (wFcid & bitFixedPitchFcid)
+ {
+ pchpT->fFixedPitch = TRUE;
+ }
+ }
+ }
+ }
+
+
+void NEAR SelectWriteFont(fPrint, phfont)
+int fPrint;
+HFONT *phfont;
+ {
+ extern HWND hParentWw;
+ extern int wwMac;
+ extern struct WWD rgwwd[];
+
+ if (fPrint)
+ {
+
+#ifdef DFONT
+ CommSzNum("Selecting printer font: ", *phfont);
+#endif /* DFONT */
+
+ /* The printer DC should be valid. */
+ if (vhDCPrinter == NULL)
+ {
+/* This case can occur from ResetFont when closing */
+ return;
+ }
+ else
+ {
+ /* Establish the font with the printer DC. */
+ if (SelectObject(vhDCPrinter, *phfont) == NULL)
+ {
+ if (SelectObject(vhDCPrinter, GetStockObject(vfPrinterValid ?
+ DEVICE_DEFAULT_FONT : SYSTEM_FONT)) == NULL)
+ {
+ if (vfPrinterValid)
+ {
+ /* This is a real printer DC; delete it. */
+ DeleteDC(vhDCPrinter);
+ }
+ else
+ {
+ /* This is really the screen DC; it must be released. */
+ ReleaseDC(hParentWw, vhDCPrinter);
+ }
+ vhDCPrinter = NULL;
+ }
+ WinFailure();
+ if (vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ }
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* Establish it with screen and memory DC's. */
+ register int ww;
+ register struct WWD *pwwd;
+
+#ifdef DFONT
+ CommSzNum("Selecting screen font: ", *phfont);
+#endif /* DFONT */
+
+ /* The current memory DC had best be active. */
+ if (vhMDC == NULL)
+ {
+/* this case occurs from ResetFont when Write is closed */
+ return;
+ }
+ else
+ {
+ /* Select the font into the memory DC. */
+ if (SelectObject(vhMDC, *phfont) == NULL)
+ {
+
+ Assert(*phfont != GetStockObject(SYSTEM_FONT));
+ *phfont = GetStockObject(SYSTEM_FONT);
+ Assert( *phfont );
+#ifdef DEBUG
+ Assert( SelectObject( vhMDC, *phfont ) );
+#else /* not DEBUG */
+ SelectObject(vhMDC, *phfont );
+#endif /* not DEBUG */
+
+ WinFailure();
+ }
+ }
+
+ /* Select the font into all of the window DC's. */
+ for (ww = 0, pwwd = &rgwwd[0]; ww < wwMac; ww++, pwwd++)
+ {
+ if (pwwd->hDC != NULL)
+ {
+ if (SelectObject(pwwd->hDC, *phfont) == NULL)
+ {
+ HFONT hSysFont = GetStockObject(SYSTEM_FONT);
+ int wwT;
+ struct WWD *pwwdT;
+
+#ifdef DEBUG
+ Assert(*phfont != hSysFont);
+ Assert(SelectObject(vhMDC, hSysFont) != NULL);
+#else /* not DEBUG */
+ SelectObject(vhMDC, hSysFont);
+#endif /* not DEBUG */
+ *phfont = hSysFont;
+
+ for (wwT = 0, pwwdT = &rgwwd[0]; wwT <= ww; wwT++, pwwdT++)
+ {
+ if (pwwdT->hDC != NULL)
+ {
+
+#ifdef DEBUG
+ Assert(SelectObject(pwwdT->hDC, hSysFont) != NULL);
+#else /* not DEBUG */
+ SelectObject(pwwdT->hDC, hSysFont);
+#endif /* not DEBUG */
+
+ }
+ }
+
+ WinFailure();
+ }
+ }
+ }
+ }
+ }
+
+
+ResetFont(fPrint)
+BOOL fPrint;
+ {
+ /* This routine sets to NULL the currently selected printer or screen font,
+ depending on the value of fPrint. */
+
+ extern HFONT vhfSystem;
+ HFONT hfont;
+
+#ifdef DFONT
+ CommSzSz("Resetting the ", (fPrint ? "printer font." : "screen font."));
+#endif /* DEBUG */
+
+ hfont = GetStockObject(fPrint && vfPrinterValid ?
+ DEVICE_DEFAULT_FONT : SYSTEM_FONT);
+
+ SelectWriteFont( fPrint, &hfont );
+ if (fPrint)
+ {
+ vpfcePrint = NULL;
+ vfcidPrint.lFcid = fcidNil;
+ }
+ else
+ {
+ vpfceScreen = NULL;
+ vfcidScreen.lFcid = fcidNil;
+ }
+ }
+
+
+
+
+BOOL OurGetCharWidth(hdc, chFirst, chLast, lpw)
+HDC hdc;
+CHAR chFirst, chLast;
+LPINT lpw;
+ {
+ int i;
+ BYTE b;
+ for (i = chFirst; i <= chLast; i++)
+ {
+ b = i;
+ *(lpw++) = LOWORD(GetTextExtent(hdc, (LPSTR)&b, 1));
+ }
+ return(fTrue);
+ }
+
+
+#ifdef SMFONT
+/* Note: we put widths in here that represent true char widths,
+ not considering bold/italics Overhang. This is because of the
+ following formula for string widths:
+
+ strwidth = overhang +
+ summation [ (gettextextent_or_getcharwidth - overhang) ]
+
+ ..pault 9/22/89 */
+
+void NEAR FillWidthTable(hdc, rgdxp, ptm)
+HDC hdc;
+int rgdxp[];
+TEXTMETRIC *ptm;
+ {
+ int rgWidth[chFmiMax - chFmiMin];
+
+ if ((ptm->tmPitchAndFamily & 1) == 0)
+ {
+#ifdef PRDRVTEST
+ CommSzNum(" * Fixed pitch font! tmAveCharWidth==",ptm->tmMaxCharWidth);
+#endif
+
+#ifdef DBCS /* was in JAPAN */
+ bltc(rgdxp, dxpNil, chFmiMax - chFmiMin);
+#else
+ bltc(rgdxp, (WORD)ptm->tmAveCharWidth, chFmiMax - chFmiMin);
+#endif
+ }
+
+ /* Attempt to get the width table from the DC. */
+ else
+ {
+ int *pdxpMax = &rgdxp[chFmiMax - chFmiMin];
+ register int *pWidth;
+ register int *pdxp;
+ int dxpOverhang = ptm->tmOverhang;
+
+#ifdef DBCS /* was in JAPAN; KenjiK '90-11-26 */
+ if(OurGetCharWidth(hdc, chFmiMin, chFmiMax - 1, (LPINT)rgWidth))
+#else
+ if (GetCharWidth(hdc, chFmiMin, chFmiMax - 1, (LPINT)rgWidth))
+#endif
+
+ {
+
+#ifdef PRDRVTEST
+ CommSz(" * GetCharWidth() supported\n\r");
+#endif
+
+ /* Remove the overhang factor from individual char widths
+ (see formula for widths of character strings above) */
+ for (pWidth = &rgWidth[0], pdxp = &rgdxp[0];
+ pdxp != pdxpMax; pWidth++, pdxp++)
+ {
+#ifdef DBCS /* was in JAPAN */
+ if(*pWidth == dxpNil)
+ *pdxp = (CHAR)dxpNil;
+ else
+#endif
+ *pdxp = (*pWidth - dxpOverhang);
+ }
+ }
+ else
+ {
+ /* There is no easy way, put dxpNil in the table. It looks like each
+ char has a bogus width but FormatLine will make individual calls to
+ GetTextExtent() and replace the dxpNil on an as-needed basis ..pault */
+
+#ifdef PRDRVTEST
+ CommSz(" * GetCharWidth() not supported!\n\r");
+#endif
+ bltc(rgdxp, (WORD)dxpNil, chFmiMax - chFmiMin);
+ }
+ }
+
+#ifdef PRDRVTEST
+/* Take a quick look through to see if this printer is returning any
+ char widths that seem bogus -- report those suckers! This should
+ end my searching for WRITE problems which are really caused by bad
+ printer-driver return values! */
+ {
+ BOOL fReported = fFalse;
+ int rgch[cchMaxSz];
+ int i,w;
+ BYTE b;
+ for (i = chFmiMin; i < chFmiMax; i++)
+ {
+ b = i;
+ w = LOWORD(GetTextExtent(hdc, (LPSTR)&b, 1));
+ if (w < 1)
+ {
+ wsprintf(rgch," GetTextExtent(ascii %d) return value %d is invalid\n\r",b,(int)w);
+ CommSz(rgch);
+ if (!fReported)
+ {
+ CommSz("");
+ fReported = fTrue;
+ }
+ }
+ else if (w > (ptm->tmMaxCharWidth + ptm->tmOverhang))
+ {
+ wsprintf(rgch," GetTextExtent(ascii %d) return value %d exceeds tmMaxCharWidth %d\n\r",
+ b,(int)w,(int)(ptm->tmMaxCharWidth + ptm->tmOverhang));
+ CommSz(rgch);
+ if (!fReported)
+ {
+ CommSz("");
+ fReported = fTrue;
+ }
+ }
+ else if ((rgdxp[i] != dxpNil) && (rgdxp[i] > (ptm->tmMaxCharWidth + ptm->tmOverhang)))
+ {
+ wsprintf(rgch," GetCharWidth(ascii %d) return value %d questionable, exceeds tmMaxCW %d\n\r",
+ b, (int)(rgdxp[i]), (int)(ptm->tmMaxCharWidth + ptm->tmOverhang));
+ CommSz(rgch);
+ if (!fReported)
+ {
+ CommSz("");
+ fReported = fTrue;
+ }
+ }
+ }
+ }
+#endif /* PRDRVTEST */
+
+ }
+#endif /* SMFONT */
+
+#ifdef DEBUG
+BOOL NEAR DogoneTrashTest(HDC hdc, struct FCE *pfce, BOOL fPrint)
+{
+#if 1
+ int i,width;
+ int *pdxpMax = pfce->rgdxp + chFmiMax - chFmiMin;
+ int dxpOverhang = pfce->fmi.dxpOverhang;
+ register int *rgdxp;
+ int rgdxpNew[chFmiMax - chFmiMin];
+ register int *dxpNew;
+
+ return 0;
+ for (i=chFmiMin,
+ rgdxp = pfce->rgdxp;
+ i < chFmiMax; rgdxp++, ++i)
+ {
+ width = LOWORD(GetTextExtent(hdc,&i,1));
+ if (*rgdxp != (width - dxpOverhang))
+ {
+#ifdef DEBUG
+ {
+ char msg[120];
+ wsprintf(msg,"widths have changed! Getting new width. (%s)\n\r",
+ (LPSTR)(fPrint ? "PrinterDc" : "ScreenDC"));
+ OutputDebugString(msg);
+ }
+#endif
+ GetCharWidth(hdc, chFmiMin, chFmiMax - 1, (LPINT)rgdxpNew);
+ for (dxpNew = rgdxpNew,
+ rgdxp = pfce->rgdxp;
+ rgdxp != pdxpMax; dxpNew++, rgdxp++)
+ *rgdxp = (*dxpNew - dxpOverhang);
+ return TRUE;
+ }
+ }
+#else
+ int rgdxpNew[chFmiMax - chFmiMin];
+ int *pdxpMax = pfce->rgdxp + chFmiMax - chFmiMin;
+ int dxpOverhang = pfce->fmi.dxpOverhang;
+ register int *dxpNew;
+ register int *rgdxp;
+ if (GetCharWidth(hdc, chFmiMin, chFmiMax - 1, (LPINT)rgdxpNew))
+ {
+ /* Remove the overhang factor from individual char widths
+ (see formula for widths of character strings above) */
+ for (dxpNew = rgdxpNew,
+ rgdxp = pfce->rgdxp;
+ rgdxp != pdxpMax; dxpNew++, rgdxp++)
+ {
+ if (*rgdxp != (*dxpNew - dxpOverhang))
+ {
+#ifdef DEBUG
+ {
+ char msg[120];
+ wsprintf(msg,"widths have changed! Getting new width. (%s)\n\r",
+ (LPSTR)(fPrint ? "PrinterDc" : "ScreenDC"));
+ OutputDebugString(msg);
+ }
+#endif
+ for (dxpNew = rgdxpNew,
+ rgdxp = pfce->rgdxp;
+ rgdxp != pdxpMax; dxpNew++, rgdxp++)
+ *rgdxp = (*dxpNew - dxpOverhang);
+ return TRUE;
+ }
+ }
+ }
+#endif
+return FALSE;
+}
+#endif
+
+
diff --git a/private/mvdm/wow16/write/looks.h b/private/mvdm/wow16/write/looks.h
new file mode 100644
index 000000000..aafe600c1
--- /dev/null
+++ b/private/mvdm/wow16/write/looks.h
@@ -0,0 +1,39 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the definitions of the various codes returned from the
+"looks" expert keys in Windows Word. */
+
+#define fLooks 0x4000
+
+#define fCharLooks 0x0100
+#define fParaLooks 0x0200
+#define fSectLooks 0x0400
+#define fUserDefined 0x0800
+
+#define ilkNil 0x4fff
+
+/* Character looks */
+#define ilkStd 0x4100
+#define ilkBold 0x4101
+#define ilkItalic 0x4102
+#define ilkUline 0x4103
+#define ilkSuper 0x4104
+#define ilkSub 0x4105
+#define ilkSmCaps 0x4106
+#define ilkHpsSmall 0x4107
+#define ilkHpsBig 0x4108
+#define ilkFont 0x4109
+
+/* Paragraph looks */
+#define ilkGeneral 0x4200
+#define ilkLeft 0x4201
+#define ilkRight 0x4202
+#define ilkCenter 0x4203
+#define ilkJust 0x4204
+#define ilkOpen 0x4205
+#define ilkIndent 0x4206
+#define ilkNest 0x4207
+#define ilkUnnest 0x4208
+#define ilkHang 0x4209
diff --git a/private/mvdm/wow16/write/ltabbtn.bms b/private/mvdm/wow16/write/ltabbtn.bms
new file mode 100644
index 000000000..a60c802f8
--- /dev/null
+++ b/private/mvdm/wow16/write/ltabbtn.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/ltabmark.bms b/private/mvdm/wow16/write/ltabmark.bms
new file mode 100644
index 000000000..49365ba38
--- /dev/null
+++ b/private/mvdm/wow16/write/ltabmark.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/machdefs.h b/private/mvdm/wow16/write/machdefs.h
new file mode 100644
index 000000000..e2d8c7193
--- /dev/null
+++ b/private/mvdm/wow16/write/machdefs.h
@@ -0,0 +1,115 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define MACHA
+ /* definition of macha moved here by bz instead of on command
+ like to compiler to allow other command line args */
+
+/* cbSector -- Number of bytes in sector */
+/* p2bSector -- Power of two of bytes in sector (iff cbSector==2^n) */
+/* cbPad -- Difference between real sector size and our sector size. (Used
+ only if the real sector size is odd) */
+/* cbWorkspace -- Number of bytes needed by interpreter for file overhead */
+
+
+#ifdef SAND
+#define cbSector 128
+#define p2bSector 7
+#define cbPad 0
+#define cbWorkspace 0
+#define rfnMax 5
+#define pnMaxScratch (1 << (16 - p2bSector))
+
+#else
+
+#ifdef MACHA /* IBM PC, PC-XT, OR PC-AT */
+#define cbSector 128
+#define p2bSector 7
+#define cbPad 0
+#define cbWorkspace 1
+
+#define rfnMacEdit 9 /* # of rfn's to use during editing */
+#define rfnMacSave 10 /* # of rfn's to use during saving */
+#define rfnMax 10 /* Allocated # of rfn slots */
+
+#define pnMaxScratch (1 << (16 - p2bSector))
+
+
+/* -------------------------------------------------------------------- */
+/* Added conditional compilation for long filename support under OS/2 */
+/* t-carlh - August, 1990 */
+/* -------------------------------------------------------------------- */
+#ifdef OS2
+#define cchMaxLeaf 260 /* Largest filename (w/ ext, w/o drv,path) */
+#define cchMaxFile 260 /* Largest filename (w/ ext, drv, path) */
+#else /* OS2 */
+#define cchMaxLeaf 13 /* Largest filename (w/ ext, w/o drv,path) */
+#define cchMaxFile 128 /* Largest filename (w/ ext, drv, path) */
+#endif /* OS2 */
+
+#endif
+
+#ifdef MACHB
+#define cbSector 252
+#define cbPad 1
+#define cbWorkspace (64+253)
+#endif
+
+#ifdef MACHC
+#define cbSector 512
+#define p2bSector 9
+#define cbPad 0
+#define cbWorkspace 20
+#endif
+
+#ifdef MACHD
+#define cbSector 256
+#define p2bSector 8
+#define cbPad 0
+#define cbWorkspace (31+256)
+#endif
+
+#ifdef MACHE
+#define cbSector 512
+#define p2bSector 9
+#define cbPad 0
+#define cbWorkspace 0
+#define rfnMax 2
+#endif
+
+#ifdef MACHF
+#define cbSector 512
+#define p2bSector 9
+#define cbPad 0
+#define cbWorkspace 38
+#endif
+#endif /* SAND */
+
+
+#define EOF (-1)
+
+#ifdef SAND
+#define mdRandom 0
+#define mdRanRO 0100000 /* Read only random file */
+#define mdBinary 1
+#define mdBinRO 0100001 /* Read only binary save file */
+#define mdText 2
+#define mdTxtRO 0100002 /* Read only text file */
+#define mdPrint 3
+#endif
+
+#ifdef MACHA
+#define mdRandom 0x0002
+#define mdBinary mdRandom
+#define mdText mdRandom
+#define mdRanRO 0x0000
+#define mdBinRO mdRanRO
+#define mdTxtRO mdRanRO
+
+#define mdExtMax 5 /* # chars in an extension, including the . */
+
+#endif
+
+extern int ibpMax;
+extern int iibpHashMax;
diff --git a/private/mvdm/wow16/write/macro.h b/private/mvdm/wow16/write/macro.h
new file mode 100644
index 000000000..364825fbf
--- /dev/null
+++ b/private/mvdm/wow16/write/macro.h
@@ -0,0 +1,23 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains some useful macros. */
+
+#define FillBuf(pb, cb, ch) bltbc((pb), (CHAR)(ch), cb)
+
+#define FSzSame(sz1, sz2) (WCompSz(sz1, sz2) == 0)
+
+#define SetWords(pw, w, cw) bltc((CHAR *)(pw), (unsigned)(w), cw)
+
+#define SetBytes(pb, b, cb) bltbc((CHAR *)(pb), (CHAR)(b), cb)
+
+#define NMultDiv(w1, w2, w3) MultDiv(w1, w2, w3)
+
+/* Theses macros are used by Windows Word to facilitate the conversion form
+Mac Word. */
+
+#define SetSpaceExtra(dxp) SetTextJustification(vhMDC, dxp, 1)
+
+#define TextWidth(rgch, w, cch) LOWORD(GetTextExtent(vhMDC, (LPSTR)rgch, cch))
+
diff --git a/private/mvdm/wow16/write/mainloop.c b/private/mvdm/wow16/write/mainloop.c
new file mode 100644
index 000000000..58b2b3427
--- /dev/null
+++ b/private/mvdm/wow16/write/mainloop.c
@@ -0,0 +1,711 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* MainLoop.c -- WRITE's main message loop */
+
+#define NOGDICAPMASKS
+//#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOOPENFILE
+#define NOPEN
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#define NOFONT
+#define NOGDI
+#define NOBRUSH
+#define NOATOM
+#define NOSCROLL
+#define NOCOLOR
+#include <windows.h>
+
+#define NOUAC
+#include "mw.h"
+#include "cmddefs.h"
+#include "ch.h"
+#include "docdefs.h"
+#include "fmtdefs.h"
+#include "dispdefs.h"
+#include "printdef.h"
+#include "wwdefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#define NOSTRUNDO
+#define NOSTRERRORS
+#include "str.h"
+#include "preload.h"
+
+
+extern CHAR (*rgbp)[cbSector];
+extern CHAR *rgibpHash;
+extern struct BPS *mpibpbps;
+extern int ibpMax;
+extern int iibpHashMax;
+extern struct DOD (**hpdocdod)[];
+extern int docCur;
+extern int visedCache;
+extern typeCP cpMinDocument;
+extern struct WWD rgwwd[];
+extern int wwCur;
+extern struct FLI vfli;
+extern struct WWD *pwwdCur;
+extern int docMode;
+extern CHAR stMode[];
+extern int isedMode;
+extern int vdocPageCache;
+extern typeCP vcpMinPageCache;
+extern typeCP vcpMacPageCache;
+extern int vipgd;
+extern int vfInsLast;
+extern struct SEP vsepAbs;
+extern struct DOD (**hpdocdod)[];
+extern int vfSelHidden;
+extern struct SEL selCur;
+extern int vfAwfulNoise;
+extern HWND vhWndPageInfo;
+extern int vfSeeSel;
+extern int vipgd;
+extern int vfInsEnd; /* Is insert point at end-of-line? */
+extern int vfModeIsFootnote; /* true when szMode contains string "Footnote" */
+/* used by ShowMode */
+extern int docMode;
+static int isedMode = iNil;
+static int ipgdMode = iNil;
+extern CHAR szMode[];
+extern HCURSOR vhcIBeam;
+#ifdef DBCS
+extern int donteat; /* disp.c : if TRUE vmsgLast has msg */
+#endif
+static int vfSizeMode = false;
+int vcCount = 1; /* count to be decremented until 0 before trying to grow rgbp */
+
+
+
+
+
+NEAR FNeedToGrowRgbp(void);
+
+
+
+MainLoop()
+{
+ extern int vfIconic;
+ extern int vfDead;
+ extern int vfDeactByOtherApp;
+ extern MSG vmsgLast;
+ extern int vfDiskFull;
+ extern int ferror;
+ extern HWND hParentWw;
+ extern HANDLE vhAccel; /* handle to accelerator table */
+ extern HWND vhDlgFind, vhDlgRunningHead, vhDlgChange;
+
+ while (TRUE)
+ {
+ if (!vfDeactByOtherApp && !vfIconic && !vfDead &&
+ !FImportantMsgPresent())
+ { /* Neither an icon nor a dying ember -- perform background
+ tasks like screen update, showing selection, etc. */
+ Idle();
+ }
+
+ /* We are done Idling or there's a message waiting for us */
+#ifdef DBCS
+ if ( donteat ) {
+ /* We have already get message */
+ donteat = FALSE;
+ }
+ else {
+ if (!GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 ))
+ {
+ /* Terminating the app; return from WinMain */
+LTerm:
+ break;
+ }
+ }
+#else
+ if (!GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 ))
+ {
+ /* Terminating the app; return from WinMain */
+LTerm:
+ break;
+ }
+#endif
+
+ /* Reset disk full error flag */
+ vfDiskFull = false;
+ ferror = false;
+
+#if WINVER >= 0x300
+ if (hParentWw == NULL)
+ /* Odd shut-down condition where we've hParentWw has been
+ invalidated without our genuine knowledge and thus RIP's */
+ goto LTerm;
+#endif
+
+ /* Handle modeless dialog box messages thru IsDialogMessage. */
+ if (
+ !(vhDlgFind != NULL && IsDialogMessage(vhDlgFind, &vmsgLast))
+ && !(vhDlgChange != NULL && IsDialogMessage(vhDlgChange, &vmsgLast))
+ && !(vhDlgRunningHead != NULL && IsDialogMessage(vhDlgRunningHead,&vmsgLast))
+ && !(TranslateAccelerator(hParentWw, vhAccel, &vmsgLast))
+ )
+ {
+ int kc;
+
+ /* Even if we process the toggle key, still want to translate it */
+ if (FCheckToggleKeyMessage( &vmsgLast ))
+ {
+ goto Translate;
+ }
+
+ if ( ((kc = KcAlphaKeyMessage( &vmsgLast )) != kcNil) &&
+ (kc != kcAlphaVirtual) )
+ {
+#ifdef CYCLESTOBURN
+ PreloadCodeTsk( tskInsert );
+#endif
+ AlphaMode( kc );
+ }
+ else if (!FNonAlphaKeyMessage( &vmsgLast, TRUE ))
+ {
+Translate:
+ TranslateMessage( (LPMSG)&vmsgLast);
+ DispatchMessage((LPMSG)&vmsgLast);
+ }
+ }
+ } /* end while (TRUE) */
+}
+
+
+/* I D L E */
+#ifdef DEBUG
+int vfValidateCode;
+#endif
+
+Idle()
+{ /* Idle routine -- do background processing things */
+ extern int vfOutOfMemory;
+ extern int ibpMaxFloat;
+ extern int vfLargeSys;
+ extern int vfDeactByOtherApp;
+ typeCP cpEdge;
+ int cdr;
+
+#ifdef DEBUG
+ extern int fIbpCheck;
+ extern int fPctbCheck;
+ int fIbpT=fIbpCheck;
+ int fPctbT=fPctbCheck;
+
+ fIbpT = fIbpCheck;
+ fPctbT = fPctbCheck;
+ fPctbCheck = fIbpCheck = TRUE;
+ CheckIbp();
+ CheckPctb();
+ fIbpCheck = fIbpT;
+ fPctbCheck = fPctbT;
+#endif
+
+ vfAwfulNoise = false; /* Re-enable beep */
+
+ /* Here is where we attempt to recognize that we have
+ regained memory and are no longer in an error state */
+ if (vfOutOfMemory)
+ {
+ extern int vfMemMsgReported;
+
+ if (FStillOutOfMemory())
+ {
+ return;
+ }
+ else
+ {
+ /* Hooray! We recovered from out-of-memory */
+ vfOutOfMemory = vfMemMsgReported = FALSE;
+ }
+ if (FImportantMsgPresent())
+ return;
+ }
+
+ /* Make sure we repaint what Windows considers to be invalid */
+ UpdateInvalid();
+ UpdateDisplay(true);
+ if (wwdCurrentDoc.fDirty)
+ /* Update was interrupted */
+ return;
+
+ Assert( wwCur >= 0 );
+
+ {
+ extern int vfSeeEdgeSel;
+ int dlMac = pwwdCur->dlMac;
+ struct EDL *pedl = &(**(pwwdCur->hdndl))[dlMac - 1];
+
+ cpEdge = CpEdge();
+
+ if ( vfSeeSel &&
+ (vfSeeEdgeSel || (selCur.cpFirst == selCur.cpLim) ||
+ (selCur.cpLim <= pwwdCur->cpFirst) ||
+ (selCur.cpFirst >= pedl->cpMin + pedl->dcpMac)) )
+ {
+ extern int vfInsEnd;
+
+ if (vfInsEnd)
+ /* Adjust for insert point at end of line */
+ cpEdge--;
+ cpEdge = max(0, cpEdge); /* make sure cpEdge is at least 0 */
+
+ if (selCur.cpFirst == selCur.cpLim)
+ ClearInsertLine();
+ PutCpInWwHz(cpEdge);
+ if (FImportantMsgPresent())
+ return;
+ }
+ vfSeeSel = vfInsLast = vfSeeEdgeSel = false;
+
+
+#ifdef DEBUG
+ if (vfValidateCode)
+ ValidateCodeSegments(); /* Special kernel call to test checksums */
+#endif
+
+ if (vfSelHidden && !vfDeactByOtherApp)
+ { /* Turn on selection highlight */
+ vfInsEnd = selCur.fEndOfLine;
+ vfSelHidden = false;
+ ToggleSel(selCur.cpFirst, selCur.cpLim, true);
+ if (FImportantMsgPresent())
+ return;
+ }
+
+ if (!vfSizeMode)
+ {
+ CheckMode();
+ if (FImportantMsgPresent())
+ return;
+ }
+ }
+
+#define cbpIncr 5
+
+ if (--vcCount == 0)
+ {
+#ifdef DEBUG
+ dummy(); /* So Chi-Chuen can set a breakpoint here */
+#endif
+ UnlockData(0);
+ if ( GlobalCompact((DWORD)0) >= (DWORD)LCBAVAIL )
+ {
+ vfLargeSys = TRUE;
+ ibpMaxFloat = 255; /* about 32K for rgbp */
+ }
+ else
+ {
+ vfLargeSys = FALSE;
+ ibpMaxFloat = 75; /* about 10K for rgbp */
+ }
+ LockData(0);
+ /* after adjustment, ibpMaxFloat may be smaller than current ibpMax
+ but we will not grow rgbp anymore and rgbp will be reduced eventually
+ when we need more heap space */
+ if ( ibpMax < ibpMaxFloat && FNeedToGrowRgbp() )
+ if (!FGrowRgbp(cbpIncr))
+ FGrowRgbp(1);
+ if (FImportantMsgPresent())
+ return;
+ }
+
+ CloseEveryRfn( FALSE ); /* Close files on removable media */
+
+#ifdef CYCLESTOBURN
+ if (vfLargeSys)
+ { /* Large system, preload code for as much as possible */
+ int tsk;
+
+ for ( tsk = tskMin; tsk < tskMax; tsk++ )
+ PreloadCodeTsk( tsk );
+ }
+ else
+ /* Small system, preload code for insert only */
+ PreloadCodeTsk( tskInsert );
+#endif
+
+ EndLongOp(vhcIBeam);
+}
+
+
+#ifdef DEBUG
+dummy()
+{
+}
+#endif
+
+
+UpdateInvalid()
+{ /* Find out what Windows considers to be the invalid range of
+ the current window. Mark it invalid in WRITE's data structures &
+ blank the area on the screen */
+
+extern HWND hParentWw;
+extern long ropErase;
+extern int vfDead;
+
+RECT rc;
+
+if ( (pwwdCur->wwptr != NULL) &&
+ /* Getting the update rect for the parent is essentially the same as
+ processing any WM_ERASEBKGND messages that might be out there for the
+ parent. */
+ (GetUpdateRect( hParentWw, (LPRECT) &rc, TRUE ),
+ GetUpdateRect( pwwdCur->wwptr, (LPRECT) &rc, TRUE )) &&
+ /* Check for vfDead is so we don't repaint after we have
+ officially closed. Check is AFTER GetUpdateRect call so
+ we DO clear the background and validate the border */
+ !vfDead )
+ {
+ int ypTop = rc.top;
+
+ if (ypTop < pwwdCur->ypMin)
+ { /* Repaint area includes stripe above ypMin -- validate it,
+ since erasure is the only repaint necessary */
+ ypTop = pwwdCur->ypMin; /* Only invalidate below ypMin */
+
+ /* The above is NOT ensuring that the upper 4 pixel rows
+ in the text window get cleared, so we use brute force ..pault */
+ PatBlt(GetDC(pwwdCur->wwptr), 0, 0, pwwdCur->xpMac, pwwdCur->ypMin,
+ ropErase);
+ }
+
+ if (ypTop < rc.bottom)
+ {
+ InvalBand( pwwdCur, ypTop, rc.bottom );
+ }
+
+ /* Since we have found out the invalid rect, and marked it invalid
+ in our structures, we don't want to hear about it again,
+ so we tell windows that we have made everything valid */
+ ValidateRect( pwwdCur->wwptr, (LPRECT) NULL );
+ }
+}
+
+
+
+/* C H E C K M O D E */
+CheckMode()
+{
+ typeCP cp;
+ int pgn;
+ struct PGTB **hpgtb;
+ CHAR st[30];
+ CHAR *pch;
+
+#ifdef BOGUS
+ /* The mode is driven off of the first cp in the window. */
+ cp = pwwdCur->cpFirst;
+#else /* not BOGUS */
+ /* The mode is driven off of the last cp of the first line in the window. */
+ {
+ register struct EDL *pedl = &(**pwwdCur->hdndl)[0];
+
+ cp = CpMax(pedl->cpMin + pedl->dcpMac - 1, cp0);
+ }
+#endif /* not BOGUS */
+
+#ifdef CASHMERE
+ if (cp > CpMacText(docCur)) /* in footnote and running head */
+ {
+ SetModeToFootnote();
+ return;
+ }
+#endif /* CASHMERE */
+
+ CacheSect(docCur, cp);
+
+ /* If the doc has changed since the last time we entered, or the current cp
+ is not in the last page that was cached, then cache the current page. */
+ if (!(vdocPageCache == docCur && cp >= vcpMinPageCache && cp <
+ vcpMacPageCache))
+ {
+ CachePage(docCur, cp);
+ }
+
+ /* If the current doc, ised, and ipgd have not changed then the page number
+ is the same, so return. */
+ if (docMode == docCur && isedMode == visedCache && ipgdMode == vipgd)
+ {
+ return;
+ }
+
+ /* szMode is going to be set to "Page nnn" or "Pnnn Dnnn". */
+ vfModeIsFootnote = false;
+
+ /* Record the current doc, ised and ipgd. */
+ docMode = docCur;
+ isedMode = visedCache;
+ ipgdMode = vipgd;
+
+ /* Retrieve the current page number. */
+ hpgtb = (**hpdocdod)[docMode].hpgtb;
+ pgn = (vipgd == iNil) ? ((vsepAbs.pgnStart == pgnNil) ? 1 : vsepAbs.pgnStart)
+ : (**hpgtb).rgpgd[vipgd].pgn;
+
+#ifdef CASHMERE
+ /* If the document has multiple sections and we had to set szMode to "Pnnn
+ Dnnn", then return. */
+ if ((isedMode != iNil) && (FSetModeForSection(pgn)))
+ {
+ return;
+ }
+#endif /* CASHMERE */
+
+ /* Place "Page nnn" in szMode and output to mode field of window. */
+ FillStId(st, IDSTRChPage, sizeof(st));
+ st[1] = ChUpper(st[1]);
+ bltbyte(&st[1], szMode, st[0]);
+ pch = &szMode[st[0]];
+ *pch++ = chSpace;
+ ncvtu(pgn, &pch);
+ *pch = '\0';
+ DrawMode();
+} /* end CheckMode */
+
+
+NEAR FNeedToGrowRgbp()
+{ /* return true iif page buffers are all used up */
+register struct BPS *pbps;
+struct BPS *pbpsMax = &mpibpbps[ibpMax];
+extern int ibpMaxFloat;
+
+vcCount = 512;
+
+if (ibpMax + 1 > ibpMaxFloat)
+ return(FALSE); /* don't even try if adding one more page will exceed limit */
+
+for (pbps = &mpibpbps[0]; pbps < pbpsMax; pbps++)
+ {
+ /* any unused page? */
+ if (pbps->fn == fnNil)
+ {
+ return(FALSE);
+ }
+ }
+return(TRUE);
+}
+
+
+CachePage(doc,cp)
+int doc;
+typeCP cp;
+ {
+ struct PGTB **hpgtb;
+ int cpgd;
+ typeCP cpMacPage;
+
+ vdocPageCache = doc;
+ hpgtb = (**hpdocdod)[doc].hpgtb;
+
+ if (hpgtb == 0 || (**hpgtb).cpgd == 0)
+ {
+ vcpMinPageCache = cp0;
+ vcpMacPageCache = cpMax;
+ vipgd = -1;
+ return;
+ }
+
+ /* Get index to beginning of NEXT page */
+ cpgd = (**hpgtb).cpgd;
+ vipgd = IcpSearch(cp+1, &((**hpgtb).rgpgd[0]), sizeof(struct PGD),
+ bcpPGD, cpgd);
+ cpMacPage = (**hpgtb).rgpgd[vipgd].cpMin;
+ if (cp >= cpMacPage)
+ { /* Last page */
+ vcpMinPageCache = cpMacPage;
+ vcpMacPageCache = (**hpdocdod)[doc].cpMac + 1;
+ }
+ else
+ {
+ vcpMinPageCache = (vipgd == 0) ? cpMinDocument : (**hpgtb).rgpgd[vipgd - 1].cpMin;
+ vcpMacPageCache = cpMacPage;
+ vipgd -= 1; /* so that ShowMode can get correct pgn */
+ }
+ }
+
+
+
+#ifdef CASHMERE
+/* A D D V I S I S P A C E S */
+AddVisiSpaces(ww, pedl, dypBaseline, dypFontSize)
+int ww;
+struct EDL *pedl; /* Do no heap movement in this subroutine */
+int dypBaseline, dypFontSize;
+ {
+ /* Put a centered dot in each space character, and show all tabs */
+ int ich;
+ struct WWD *pwwd = &rgwwd[ww];
+ int xpPos = vfli.xpLeft + xpSelBar - pwwd->xpMin;
+ int ypPos;
+ WORDPTR bitsDest = pwwd->wwptr + (long)STRUCIDX(portBits);
+ RECT rcDest;
+ int xpRightReal = vfli.xpRight - pwwd->xpMin;
+ extern BITPAT patVisiTab;
+ BITMAP bmap;
+
+ ypPos = pedl->yp - dypBaseline - dypFontSize / 4;
+ rcDest.bottom = ypPos + 4;
+ rcDest.top = rcDest.bottom - 8;
+
+ SetRect(&bmap.bounds, 8, 0, 16, 8);
+ bmap.rowBytes = 2;
+ bmap.baseAddr = MPLP(&patVisiTab);
+
+ PenSize(1, 1);
+ PenMode(patXor);
+
+ for (ich = 0; ich < vfli.ichMac; ++ich)
+ {
+ switch(vfli.rgch[ich])
+ {
+ case chSpace:
+ MoveTo(xpPos + vfli.rgdxp[ich] / 2, ypPos);
+ Line(0, 0);
+ break;
+ case chTab:
+ rcDest.left = xpPos - 1;
+ rcDest.right = rcDest.left + 8;
+ CopyBits(MPLP(&bmap), bitsDest, &(bmap.bounds),
+ &rcDest, srcXor, 0l);
+ }
+ xpPos += vfli.rgdxp[ich];
+ }
+ }
+#endif /* CASHMERE */
+
+
+#ifdef ENABLE
+/* F S E T M O D E F O R S E C T I O N */
+FSetModeForSection(pgn)
+int pgn; /* pgn is the current page number */
+ {
+ struct SETB *psetb;
+ struct SED *psed;
+ int cch, sectn;
+ CHAR *pch;
+
+#ifdef DEBUG
+ Assert(HsetbGet(docMode) != 0);
+#endif /* DEBUG*/
+
+ psetb = *HsetbGet(docMode);
+ psed = psetb->rgsed;
+
+ /* Decide if a mode string of the form "Pnnn Dnnn" needs to be */
+ /* displayed. If no, just return. If yes, derive the section # */
+
+ if(psed->cp == CpMacText(docMode))
+ return(FALSE);
+ else
+ {
+ if (psetb->csed <= 1)
+ return(FALSE);
+ sectn = isedMode + 1;
+ }
+
+ /* Place "Pnnn Dnnn" in stMode and output to window */
+ pch = &stMode[1];
+ *pch++ = chPnMode;
+ ncvtu(pgn,&pch);
+ *pch++ = chSpace;
+ *pch++ = chDivMode;
+ ncvtu(sectn,&pch);
+ stMode[0] = pch - stMode - 1;
+ DrawMode();
+ return(TRUE);
+ }
+#endif /* ENABLE */
+
+
+#ifdef CASHMERE
+Visify(pch, pcch)
+CHAR *pch;
+int *pcch;
+{ /* Transform chars to "Visible font" */
+CHAR *pchT = pch;
+int cch = *pcch;
+
+while (cch--)
+ {
+ if ((*pchT = ChVisible(*pch++)) != 0)
+ pchT++;
+ else
+ --(*pcch);
+ }
+}
+#endif /* CASHMERE */
+
+
+
+#ifdef CASHMERE
+int ChVisible(ch)
+int ch;
+{ /* Return "visible font" for ch */
+switch (ch)
+ {
+#ifdef CRLF
+case chReturn:
+ return 0; /* chNil won't fit into a byte */
+#endif
+case chNRHFile: return chHyphen;
+case chNewLine: return chVisNewLine;
+case chEol: return chVisEol;
+case chTab: return chVisTab;
+case chSect: return chVisSect;
+default:
+ return ch;
+ }
+}
+#endif /* CASHMERE */
+
+
+
+
+#ifdef CYCLESTOBURN
+void PreloadCodeTsk( tsk )
+int tsk;
+{
+switch (tsk) {
+
+ case tskInsert:
+ LoadF( IbpMakeValid ); /* FILE.C */
+ LoadF( MoveLeftRight ); /* CURSKEYS.C */
+ LoadF( CtrBackDypCtr ); /* SCROLLVT.C */ /* Sometimes */
+ LoadF( PutCpInWwHz ); /* SCROLLHZ.C */
+ LoadF( ValidateTextBlt ); /* INSERT2.C */
+ LoadF( InsertEolInsert ); /* INSERTCO.C */
+ LoadF( Replace ); /* EDIT.C */
+ LoadF( AlphaMode ); /* INSERT.C */
+ break;
+ case tskFormat:
+ LoadF( DoPrm ); /* DOPRM.C */
+ LoadF( AddSprmCps ); /* ADDPRM.C */
+ LoadF( SetUndo ); /* EDIT.C */
+ LoadF( FInitFontEnum ); /* FONTS.C */
+ LoadF( SetAppMenu ); /* MENU.C */
+ break;
+ case tskScrap:
+ LoadWindowsF( SetClipboardData ); /* USER!WINCLIP */
+ LoadF( Replace ); /* EDIT.C */
+ LoadF( fnCutEdit ); /* CLIPBORD.C */
+ LoadF( SetAppMenu ); /* MENU.C */
+ break;
+ }
+}
+#endif
diff --git a/private/mvdm/wow16/write/makefile b/private/mvdm/wow16/write/makefile
new file mode 100644
index 000000000..e9384c246
--- /dev/null
+++ b/private/mvdm/wow16/write/makefile
@@ -0,0 +1,405 @@
+##############################################################################
+#### ####
+#### Microsoft Windows 3.0 WRITE make file ####
+#### For use with the MS-DOS version of the UNIX make utility ####
+#### ####
+##############################################################################
+
+WINLIB=..\lib
+INCLUDE=-I..\inc -I..\..\inc
+
+#International mods
+# NOTE: INTL_SRC, INTL_EXE and LANG are external macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!IFDEF DBCS
+RES_DIR=.\messages\$(DBCS)
+!ENDIF
+!ELSE
+RES_DIR=$(INTL_SRC)\$(LANG)\apps\write
+EXE_DIR=$(INTL_EXE)
+!ENDIF
+
+APP = write
+
+DEBUGDEF =
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+CDEBUG = /Zd
+ADEBUG = -Zd
+LDEBUG = /LI
+!ENDIF
+
+!ifdef OS2
+CFLAGS = /AM /G2sw /Os /Zpe /PLM /DOS2 $(INCLUDE)
+DFLAGS =
+LFLAGS = /ALIGN:16 /Map /NOD
+AFLAGS = -Mx $(INCLUDE)
+RCFLAGS = -DOS2 $(INCLUDE)
+!else
+!ifdef CVW
+CFLAGS = /AM /G2sw /Odi /Zipe /W3 /PLM /DWIN31 $(INCLUDE)
+LFLAGS = /ALIGN:16 /Map /NOD
+AFLAGS = -Mx -Zi $(INCLUDE)
+!else
+CFLAGS = /AM /G2sw /Os /Zpe /PLM /DWIN31 $(INCLUDE) $(CDEBUG)
+LFLAGS = /ALIGN:16 /MAP /NOD $(LDEBUG)
+AFLAGS = -Mx $(INCLUDE) $(ADEBUG)
+!endif
+DFLAGS =
+RCFLAGS = $(INCLUDE)
+!endif
+
+# To make a debug version, you can set this variable from the command line:
+#
+# MAKE "DFLAGS=-DDEBUG -Zid" = turns on general debug code/Codeview
+#
+# Additional parameters/defines that can be used:
+#
+# -DCKSM = enables document checksum test code
+# -DDFONT = enables font stats and info dump
+# -DDFILE = enables file read/write info dump
+# -DDPRINT = enables print info dump
+# -DDDISP = enables any display tests we might add
+# -DBEMG = ?
+# -DDFLI = enables FormatLine debug info
+# (only when form1.c used rather than format.asm)
+# -DPRDRVTEST = enables some diagnostic code to test character
+# widths returned by the printer
+# -DDINPUT = enables diagnostic code in mouse/keyboard
+# input areas
+# -DDCLIP = enables clipboard measurement diag output
+# -DDMARGINS =
+# -DDIAG = turns on comm. port diagnostic output
+# [for use with Diag() macro]
+#
+
+Res = write.ico mwlores.cur mwhires.cur pmscur.cur
+ResH = menudefs.h dlgdefs.h str.h
+ResB = cgabtns.bmp egabtns.bmp vgabtns.bmp 8514btns.bmp \
+ cgamarks.bmp egamarks.bmp vgamarks.bmp 8514mrks.bmp
+
+OBJ1 = addprm.obj cache.obj chngwin.obj clipbord.obj \
+ clipbrd2.obj clipdisp.obj cmd.obj createww.obj curskeys.obj \
+ debug.obj diaalert.obj printdlg.obj diadiv.obj diapara.obj \
+ diarepag.obj diasubs.obj disp.obj doc.obj doprm.obj \
+
+OBJ2 = doslib.obj edit.obj editpgtb.obj \
+ fetch.obj file.obj fileres.obj fileutil.obj fontdlg.obj fontenum.obj \
+ fontutil.obj format.obj \
+ format2.obj heapmain.obj heaprare.obj jumppage.obj \
+
+OBJ3 = initmmw.obj initwin.obj insert.obj insert2.obj insertco.obj \
+ lib.obj loadfont.obj loadfnt2.obj mainloop.obj \
+ mdoc.obj menu.obj mglobals.obj mmw.obj \
+ mouse.obj open.obj \
+ pageinfo.obj pictdrag.obj picture.obj picture2.obj print.obj \
+
+OBJ4 = print2.obj print3.obj quit.obj \
+ rare.obj ruler.obj ruler2.obj ruler3.obj running.obj \
+ screen.obj scrnchng.obj scrollhz.obj scrollvt.obj search.obj \
+ select.obj select2.obj selectsp.obj \
+
+OBJ5 = transfer.obj trans2.obj trans3.obj trans4.obj transbuf.obj \
+ undo.obj util.obj util2.obj wwactde.obj \
+
+OBJ6 = obj.obj obj2.obj obj3.obj objreg.obj commdlg.obj objpsp.obj objmini.obj
+
+!IFDEF DBCS
+# use FORM1.C(need to link with HELP.C) instead of FORMAT.ASM
+OBJ_DBCS=help.obj
+!ENDIF
+
+.asm.obj:
+ masm $(AFLAGS) $(DEBUGDEF) $*.asm;
+
+.c.obj:
+ cl16 -c $(CFLAGS) $(DFLAGS) $(DEBUGDEF) $*.c
+
+#International mods
+!IFNDEF LANG
+all: write.exe
+!ELSE
+all: write.$(LANG)
+!ENDIF
+
+clean: cleanup all
+
+cleanup:
+ del *.res
+ del *.rc
+ del *.rcv
+ del *.dlg
+ del *.obj
+ del *.sym
+ del *.map
+
+!IFDEF DBCS
+$(APP).exe: $(APP).res $(OBJ_DBCS) $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(OBJ5) $(OBJ6) $(APP).def $(APP).lnk
+!ELSE
+$(APP).exe: $(APP).res $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(OBJ5) $(OBJ6) $(APP).def $(APP).lnk
+!ENDIF
+#$(APP).exe: $(APP).res $(OBJ6) $(APP).def $(APP).lnk
+# ilink /E "link @$(APP).lnk;rc $(RCFLAGS) $(APP).res $(APP).exe" $(APP)
+ link16 @$(APP).lnk
+ rc16 $(RCFLAGS) $(APP).res $(APP).exe
+!ifndef CVW
+ mapsym $(APP)
+ copy write.exe write16.exe
+ copy write.map write16.map
+ copy write.sym write16.sym
+ binplace write16.exe write16.map write16.sym
+!endif
+! ifdef OS2
+ exehdr /newfiles notepad.exe
+! endif
+
+doslib.obj: doslib.asm
+
+!IFDEF DBCS
+format.obj: d_form1.c
+ cl16 -c $(CFLAGS) $(DFLAGS) $(DEBUGDEF) -Foformat.obj d_form1.c
+!ELSE
+format.obj: format.asm
+!ENDIF
+
+lib.obj: lib.asm
+
+msseqds.obj: msseqds.asm
+
+aaa.obj: aaa.c
+
+addprm.obj: addprm.c
+
+cache.obj: cache.c
+
+chlook.obj: chlook.c
+
+chngwin.obj: chngwin.c
+
+clipbord.obj: clipbord.c
+
+clipbrd2.obj: clipbrd2.c
+
+clipdisp.obj: clipdisp.c
+
+cmd.obj: cmd.c
+
+createww.obj: createww.c
+
+curskeys.obj: curskeys.c
+
+debug.obj: debug.c
+
+diaalert.obj: diaalert.c
+
+printdlg.obj: printdlg.c
+
+diadiv.obj: diadiv.c
+
+diapara.obj: diapara.c
+
+diarepag.obj: diarepag.c
+
+diasubs.obj: diasubs.c
+
+!IFDEF DBCS
+disp.obj: d_disp.c
+ cl16 -c $(CFLAGS) $(DFLAGS) $(DEBUGDEF)-Fodisp.obj d_disp.c
+!ELSE
+disp.obj: disp.c
+!ENDIF
+
+doc.obj: doc.c
+
+doprm.obj: doprm.c
+
+edit.obj: edit.c
+
+editftn.obj: editftn.c
+
+editpgtb.obj: editpgtb.c
+
+editsect.obj: editsect.c
+
+fetch.obj: fetch.c
+
+file.obj: file.c
+
+fileres.obj: fileres.c
+
+fileutil.obj: fileutil.c
+
+fontdlg.obj: fontdlg.c
+
+fontenum.obj: fontenum.c
+
+fontutil.obj: fontutil.c
+
+form1.obj: form1.c
+
+format2.obj: format2.c
+
+heapinit.obj: heapinit.c
+
+heapmain.obj: heapmain.c
+
+heaprare.obj: heaprare.c
+
+help.obj: help.c
+
+initmmw.obj: initmmw.c
+
+initwin.obj: initwin.c
+
+insert.obj: insert.c
+
+insert2.obj: insert2.c
+
+insertco.obj: insertco.c
+
+jumppage.obj: jumppage.c
+
+loadfnt2.obj: loadfnt2.c
+
+loadfont.obj: loadfont.c
+
+mainloop.obj: mainloop.c
+
+mdoc.obj: mdoc.c
+
+menu.obj: menu.c
+
+mglobals.obj: mglobals.c
+
+mmw.obj: mmw.c
+
+mouse.obj: mouse.c
+
+open.obj: open.c
+
+ole.obj: ole.c
+
+pageinfo.obj: pageinfo.c
+
+pictdrag.obj: pictdrag.c
+
+picture.obj: picture.c
+
+picture2.obj: picture2.c
+
+print.obj: print.c
+
+print2.obj: print2.c
+
+print3.obj: print3.c
+
+quit.obj: quit.c
+
+rare.obj: rare.c
+
+ruler.obj: ruler.c
+
+ruler2.obj: ruler2.c
+
+ruler3.obj: ruler3.c
+
+running.obj: running.c
+
+screen.obj: screen.c
+
+scrnchng.obj: scrnchng.c
+
+scrollhz.obj: scrollhz.c
+
+scrollvt.obj: scrollvt.c
+
+search.obj: search.c
+
+select.obj: select.c
+
+!IFDEF DBCS
+select2.obj: d_selec2.c
+ cl16 -c $(CFLAGS) $(DFLAGS) $(DEBUGDEF)-Foselect2.obj d_selec2.c
+!ELSE
+select2.obj: select2.c
+!ENDIF
+
+selectsp.obj: selectsp.c
+
+trans2.obj: trans2.c
+
+trans3.obj: trans3.c
+
+trans4.obj: trans4.c
+
+transbuf.obj: transbuf.c
+
+transfer.obj: transfer.c
+
+undo.obj: undo.c
+
+util.obj: util.c
+
+util2.obj: util2.c
+
+wwactde.obj: wwactde.c
+
+#International mods
+!IFNDEF LANG
+$(APP).rc: $(RES_DIR)\$(APP).rc
+ copy $(RES_DIR)\$(APP).rc
+
+$(APP).rcv: $(RES_DIR)\$(APP).rcv
+ copy $(RES_DIR)\$(APP).rcv
+
+$(APP).dlg: $(RES_DIR)\$(APP).dlg
+ copy $(RES_DIR)\$(APP).dlg
+
+ole.dlg: $(RES_DIR)\ole.dlg
+ copy $(RES_DIR)\ole.dlg
+
+$(APP).res: $(APP).rc $(APP).rcv $(APP).dlg ..\inc\common.ver ..\inc\version.h ..\inc\ver.h ole.dlg $(Res) $(ResH) $(ResB)
+ rc16 $(RCFLAGS) -r $(APP).rc
+!ELSE
+$(APP).res: $(RES_DIR)\$(APP).res
+ copy $(RES_DIR)\$(APP).res
+!ENDIF
+
+$(APP).lnk: MAKEFILE $(APP).sed
+ sed -n -f $(APP).sed MAKEFILE > $(APP).lnk
+!IFDEF DBCS
+ sed "s/format\.obj/format\.obj help\.obj/" $(APP).lnk > $(DBCS).lnk
+ copy $(DBCS).lnk $(APP).lnk
+ del $(DBCS).lnk
+!ENDIF
+ echo $(APP) $(LFLAGS) >> $(APP).lnk
+ echo $(APP) >> $(APP).lnk
+!IFDEF DBCS
+ echo $(WINLIB)\winnls.lib $(WINLIB)\mlibcew.lib $(WINLIB)\libw.lib $(WINLIB)\olecli.lib $(WINLIB)\commdlg.lib $(WINLIB)\shell.lib >> $(APP).lnk
+!ELSE
+ echo $(WINLIB)\mlibcew.lib $(WINLIB)\libw.lib $(WINLIB)\olecli.lib $(WINLIB)\commdlg.lib $(WINLIB)\shell.lib >> $(APP).lnk
+!ENDIF
+ echo $(APP).def >> $(APP).lnk
+
+#International mods
+clean: cleanup all
+
+cleanup:
+ del *.res
+ del *.rc
+ del *.dlg
+
+$(APP).$(LANG): $(APP).res ..\inc\common.ver ..\inc\version.h ..\inc\ver.h
+ copy $(EXE_DIR)\$(APP).exe $(APP).$(LANG)
+ rc16 -t $(RCFLAGS) $(APP).res $(APP).$(LANG)
+ copy $(app).$(LANG) write16.exe
+ copy write.sym write16.sym
+ -binplace write16.exe write16.sym
diff --git a/private/mvdm/wow16/write/mdoc.c b/private/mvdm/wow16/write/mdoc.c
new file mode 100644
index 000000000..487449742
--- /dev/null
+++ b/private/mvdm/wow16/write/mdoc.c
@@ -0,0 +1,1001 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOOPENFILE
+#define NORESOURCE
+#include <windows.h>
+
+#include "mw.h"
+#include "winddefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+#include "docdefs.h"
+#include "debug.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifdef PENWIN
+#define WM_PENWINFIRST 0x0380 // Remove when #define WIN31
+
+#include <penwin.h>
+int vcFakeMessage = 0;
+
+extern HCURSOR vhcPen; /* handle to pen cursor */
+extern int (FAR PASCAL *lpfnProcessWriting)(HWND, LPRC);
+extern VOID (FAR PASCAL *lpfnPostVirtualKeyEvent)(WORD, BOOL);
+extern VOID (FAR PASCAL *lpfnTPtoDP)(LPPOINT, int);
+extern BOOL (FAR PASCAL *lpfnCorrectWriting)(HWND, LPSTR, int, LPRC, DWORD, DWORD);
+extern BOOL (FAR PASCAL *lpfnSymbolToCharacter)(LPSYV, int, LPSTR, LPINT);
+
+
+VOID NEAR PASCAL PostCharacter(WORD wch);
+VOID NEAR PASCAL SendVirtKeyShift(WORD wVk, BYTE bFlags);
+VOID NEAR PASCAL SetSelection(HWND hWnd, LPPOINT lpPtFirst, LPPOINT lpPtLast, WORD wParam);
+int NEAR PASCAL WGetClipboardText(HWND hwndOwner, LPSTR lpsz, int cbSzSize);
+VOID NEAR PASCAL ClearAppQueue(VOID);
+
+#define VKB_SHIFT 0x01
+#define VKB_CTRL 0x02
+#define VKB_ALT 0x04
+#endif
+
+extern HWND vhWnd;
+extern HCURSOR vhcArrow;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcBarCur;
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern HANDLE hMmwModInstance; /* handle to own module instance */
+extern int vfShiftKey;
+extern int vfCommandKey;
+extern int vfOptionKey;
+extern int vfDoubleClick;
+extern struct SEL selCur;
+extern long rgbBkgrnd;
+extern long rgbText;
+extern HBRUSH hbrBkgrnd;
+extern long ropErase;
+
+int vfCancelPictMove = FALSE;
+BOOL vfEraseWw = FALSE;
+
+long FAR PASCAL MdocWndProc(HWND, unsigned, WORD, LONG);
+void MdocCreate(HWND, LONG);
+void MdocSize(HWND, int, int, WORD);
+void MdocGetFocus(HWND, HWND);
+void MdocLoseFocus(HWND, HWND);
+void MdocMouse(HWND, unsigned, WORD, POINT);
+void MdocTimer(HWND, WORD);
+
+#if defined(JAPAN) & defined(DBCS_IME)
+#include <ime.h>
+extern BOOL bGetFocus;
+// for Non_PeekMessage mode in 'FImportantMsgPresent()'. [yutakan]
+BOOL bImeCnvOpen;
+BOOL GetIMEOpen(HWND, BOOL *);
+#endif
+
+
+
+
+#ifdef PENWIN
+// Helper routines to get events into system. Would be better (more efficient) if
+// could just call routines to set selection, copy, etc,
+// but this is the easiest way without touching any internals
+
+// Minics penwin internal routine, exception messages are posted instead
+// of sent since Write does a lot of peek ahead
+
+VOID NEAR PASCAL SetSelection(HWND hWnd,
+ LPPOINT lpPtFirst, LPPOINT lpPtLast, WORD wParam)
+ {
+ static LONG lFirst = 0L;
+
+ if (lpPtFirst)
+ {
+ (*lpfnTPtoDP)(lpPtFirst, 1);
+ ScreenToClient(hWnd, lpPtFirst);
+ }
+ if (lpPtLast != NULL)
+ {
+ (*lpfnTPtoDP)(lpPtLast, 1);
+ ScreenToClient(hWnd, lpPtLast);
+ }
+
+ if (lpPtFirst)
+ {
+ lFirst = MAKELONG(lpPtFirst->x, lpPtFirst->y);
+ PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lFirst);
+ if (lpPtLast)
+ {
+ LONG lLast = MAKELONG(lpPtLast->x, lpPtLast->y);
+
+ PostMessage(hWnd, WM_MOUSEMOVE, wParam, lLast);
+ vcFakeMessage++;
+ PostMessage(hWnd, WM_LBUTTONUP, wParam, lLast);
+ }
+ else
+ {
+ PostMessage(hWnd, WM_LBUTTONUP, wParam, lFirst);
+ vcFakeMessage++;
+ }
+ }
+ else // doubleclick
+ {
+ PostMessage(hWnd, WM_LBUTTONDBLCLK, wParam, lFirst);
+ vcFakeMessage++;
+ PostMessage(hWnd, WM_LBUTTONUP, wParam, lFirst);
+ vcFakeMessage++;
+ }
+ }
+
+
+
+
+/*
+PURPOSE: Map a symbol value to a set of virtual keystrokes and then
+ send the virtual keystrokes.
+ TODO: Add real mapping of symbol values instead of assuming ANSI values
+ Right now, this routine is worthless
+RETURN:
+GLOBALS:
+CONDITIONS: Kanji is not handled now, but could be.
+*/
+VOID NEAR PASCAL PostCharacter(WORD wch)
+ {
+ int iVk = VkKeyScan(LOBYTE(wch));
+ WORD wVk = (WORD)LOBYTE(iVk);
+ char bFl = HIBYTE(iVk);
+
+ if ((wVk != -1))
+ SendVirtKeyShift(wVk, bFl);
+ }
+
+
+/*--------------------------------------------------------------------------
+PURPOSE: Send an optionally shifted key sequence as system events
+RETURN: nothing
+GLOBALS:
+CONDITIONS: see flags in mspen.h
+*/
+VOID NEAR PASCAL SendVirtKeyShift(WORD wVk, BYTE bFlags)
+ {
+ // send DOWN events:
+ if (bFlags & VKB_SHIFT)
+ (*lpfnPostVirtualKeyEvent)(VK_SHIFT, fFalse);
+ if (bFlags & VKB_CTRL)
+ (*lpfnPostVirtualKeyEvent)(VK_CONTROL, fFalse);
+ if (bFlags & VKB_ALT)
+ (*lpfnPostVirtualKeyEvent)(VK_MENU, fFalse);
+ (*lpfnPostVirtualKeyEvent)(wVk, fFalse);
+
+ // send UP events (in opposite order):
+ (*lpfnPostVirtualKeyEvent)(wVk, fTrue);
+ if (bFlags & VKB_ALT)
+ (*lpfnPostVirtualKeyEvent)(VK_MENU, fTrue);
+ if (bFlags & VKB_CTRL)
+ (*lpfnPostVirtualKeyEvent)(VK_CONTROL, fTrue);
+ if (bFlags & VKB_SHIFT)
+ (*lpfnPostVirtualKeyEvent)(VK_SHIFT, fTrue);
+ }
+
+
+/* Fill buffer with contents of clipboard
+*/
+int NEAR PASCAL WGetClipboardText(HWND hwndOwner, LPSTR lpsz, int cbSzSize)
+ {
+ HANDLE hClip;
+ int wLen = 0;
+
+ OpenClipboard(hwndOwner);
+ if (hClip = GetClipboardData(CF_TEXT))
+ {
+ LPSTR lpszClip = (LPSTR)GlobalLock(hClip);
+
+ if (lpsz && cbSzSize > 0)
+ {
+ wLen = lstrlen(lpszClip);
+ if (wLen > cbSzSize)
+ lpszClip[cbSzSize-1] = 0;
+ lstrcpy(lpsz, lpszClip);
+ }
+ GlobalUnlock(hClip);
+ }
+ CloseClipboard();
+ return wLen;
+ }
+
+
+/*--------------------------------------------------------------------------
+PURPOSE: Dispatches any messages currently pending in our queue
+RETURN: nothing
+GLOBALS:
+CONDITIONS:
+*/
+VOID NEAR PASCAL ClearAppQueue(VOID)
+ {
+ MSG msg;
+
+ while (PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+#endif
+
+
+
+static RECT rSaveInv;
+
+long FAR PASCAL MdocWndProc(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+extern int vfCloseFilesInDialog;
+extern BOOL fPrinting;
+long lReturn=0L;
+#ifdef PENWIN
+static cCharSent;
+#endif
+
+
+#ifdef PENWIN
+ if (message < WM_CUT || message == WM_RCRESULT)
+#else
+ if (message < WM_CUT )
+#endif
+
+ {
+ switch (message)
+ {
+ default:
+ goto DefaultProc;
+
+ /* For each of following mouse window messages, wParam contains
+ ** bits indicating whether or not various virtual keys are down,
+ ** and lParam is a POINT containing the mouse coordinates. The
+ ** keydown bits of wParam are: MK_LBUTTON (set if Left Button is
+ ** down); MK_RBUTTON (set if Right Button is down); MK_SHIFT (set
+ ** if Shift Key is down); MK_ALTERNATE (set if Alt Key is down);
+ ** and MK_CONTROL (set if Control Key is down). */
+
+ case WM_LBUTTONDBLCLK:
+#ifdef PENWIN
+ if (vcFakeMessage > 0)
+ vcFakeMessage--;
+ // fall through
+#endif
+ case WM_LBUTTONUP:
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ MdocMouse(hWnd, message, wParam, MAKEPOINT(lParam));
+ break;
+
+
+
+#ifdef PENWIN
+ case WM_RCRESULT:
+ {
+ LPRCRESULT lpr = (LPRCRESULT)lParam;
+ LPPOINT lpPntHot;
+ LPPOINT lpPntHot2;
+
+ if( (lpr->wResultsType&(RCRT_ALREADYPROCESSED|RCRT_NOSYMBOLMATCH))!=0 || lpr->lpsyv==NULL
+ || lpr->cSyv == 0)
+ return( FALSE );
+
+ if (lpr->wResultsType&RCRT_GESTURE)
+ {
+ SYV syv = *(lpr->lpsyv);
+
+ vcFakeMessage = 0;
+
+ lpPntHot = lpr->syg.rgpntHotSpots;
+ lpPntHot2 = lpr->syg.cHotSpot > 1 ? lpr->syg.rgpntHotSpots + 1: NULL;
+
+ switch ( LOWORD(syv))
+ {
+ case LOWORD( SYV_EXTENDSELECT ):
+ SetSelection(hWnd, lpPntHot, NULL, MK_SHIFT); // extend sel
+ break;
+
+ case LOWORD( SYV_CLEARWORD ): // dbl click & drag
+ if (lpPntHot2)
+ {
+ SetSelection(hWnd, lpPntHot, NULL, 0);
+ SetSelection(hWnd, NULL, NULL, 0); // dblclick selects word
+ }
+ SendVirtKeyShift(VK_DELETE, 0);
+ break;
+
+ case LOWORD( SYV_COPY):
+ case LOWORD( SYV_CLEAR ):
+ case LOWORD( SYV_CUT ):
+ if ( selCur.cpFirst == selCur.cpLim && (lpr->wResultsType&RCRT_GESTURETRANSLATED)==0)
+ {
+ SetSelection(hWnd, lpPntHot, NULL, 0);
+ if (syv != SYV_CLEAR)
+ SetSelection(hWnd, NULL, NULL, 0); // dblclick
+ }
+
+ switch ( LOWORD(syv))
+ {
+ case LOWORD( SYV_COPY):
+ SendVirtKeyShift(VK_INSERT, VKB_CTRL);
+ break;
+
+ case LOWORD( SYV_CLEAR ):
+ SendVirtKeyShift(VK_DELETE, 0);
+ break;
+
+ case LOWORD( SYV_CUT ):
+ SendVirtKeyShift(VK_DELETE, VKB_SHIFT);
+ break;
+ }
+
+ break;
+
+
+ case LOWORD( SYV_PASTE ):
+ if ((lpr->wResultsType&RCRT_GESTURETRANSLATED)==0)
+ SetSelection(hWnd, lpPntHot, NULL, 0);
+ SendVirtKeyShift(VK_INSERT, VKB_SHIFT);
+ break;
+
+ case LOWORD( SYV_UNDO):
+ SendVirtKeyShift(VK_BACK, VKB_ALT);
+ break;
+
+ case LOWORD(SYV_BACKSPACE):
+ case LOWORD(SYV_SPACE):
+ case LOWORD(SYV_RETURN):
+ case LOWORD(SYV_TAB):
+ SetSelection(hWnd, lpPntHot, NULL, 0);
+ PostCharacter(LOWORD(*(lpr->lpsyv))&0x00ff);
+ break;
+
+ case LOWORD( SYV_CORRECT ):
+ {
+ WORD wLen;
+ HANDLE hMem = NULL;
+ LPSTR lpstr;
+ LPSTR lpsz;
+ BOOL fDoubleClickSent = fFalse;
+ #define cbCorrectMax 128
+
+ // Strategy: If no selection, send in a double click to
+ // select a word. Then copy selection to clipboard
+ // read off of clipboard. Call CorrectWriting, and
+ // but changed text in clipboard and then paste
+ // from clipboard.
+ if ( selCur.cpFirst == selCur.cpLim )
+ {
+ // No selection so send double click
+ SetSelection(hWnd, lpPntHot, NULL, 0); // set caret
+ SetSelection(hWnd, NULL, NULL, 0); // dblclick
+ fDoubleClickSent = fTrue;
+ ClearAppQueue();
+ }
+
+ SendMessage(hWnd, WM_COPY, 0, 0L);
+
+ if (IsClipboardFormatAvailable(CF_TEXT))
+ {
+ hMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)cbCorrectMax);
+ if (hMem == NULL || (lpsz = (LPSTR)GlobalLock(hMem)) == NULL)
+ return 1; // Just bag out for now: should add error message
+ if (WGetClipboardText(hWnd, lpsz, cbCorrectMax) < cbCorrectMax)
+ {
+ // Only bring up corrector if selection wasn't too big
+ if ((*lpfnCorrectWriting)(hWnd, lpsz, cbCorrectMax, NULL, 0, 0))
+ {
+ if (*lpsz==0)
+ {
+ // User deleted all text in correction
+ SendVirtKeyShift(VK_DELETE, 0);
+ }
+ else
+ {
+ GlobalUnlock(hMem);
+ OpenClipboard(GetParent(hWnd)); // Use parent as
+ // owner to circumvent write's short check
+ // cuts if it is owner of clipboard
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, hMem);
+ CloseClipboard();
+ hMem = NULL;
+ SendMessage(hWnd, WM_PASTE, 0, 0L);
+ UpdateWindow(hWnd);
+ }
+ }
+ else if (fDoubleClickSent)
+ {
+ // Need to clear bogus selection. Just send in a tap.
+ SetSelection(hWnd, lpPntHot, NULL, 0);
+ }
+
+
+ }
+
+ if (hMem) // may never have been alloc'd if user canceled
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ }
+ }
+ }
+ break;
+
+
+ default:
+ return( FALSE );
+ }
+ }
+ else // Not a gesture,see if normal characters
+ {
+#define cbTempBufferSize 128
+ char rgch[cbTempBufferSize+2];
+ int cb=0;
+ int cbT;
+ LPSTR lpstr = (LPSTR)lpr->lpsyv;
+ typeCP cp=cp0;
+ LPSYV lpsyv;
+ LPSYV lpsyvEnd;
+
+ extern int docScrap;
+ extern int vfScrapIsPic;
+ extern struct PAP *vppapNormal;
+ extern struct CHP vchpNormal;
+
+ vfScrapIsPic = fFalse;
+ ClobberDoc( docScrap, docNil, cp0, cp0 );
+
+ // Replace CR with LF's These are treated as EOLs
+ // by CchReadLineExt. Then, before inserting
+ // buffer, change all LFs to CR LFs as write expects
+ // Will work for Kanji
+
+ for (lpsyv=lpr->lpsyv, lpsyvEnd=&lpr->lpsyv[lpr->cSyv+1];
+ lpsyv<lpsyvEnd; lpsyv++)
+ {
+ if (*lpsyv == SyvCharacterToSymbol(0xD))
+ {
+ *lpstr++ = 0xd;
+ *lpstr++ = 0xa;
+ cb+=2;
+ }
+ else
+ {
+ (*lpfnSymbolToCharacter)(lpsyv, 1, lpstr, &cbT);
+ lpstr += cbT;
+ cb += cbT;
+ }
+ }
+ lpstr = (LPSTR)lpr->lpsyv;
+ Assert(cb>0 && lpstr[cb-1] == 0);
+
+ // This code is abstracted for FReadExtScrap where it copies
+ // text from clipboard into the scrap document. We do similar.
+ // copy result into scrap and then insert scrap with
+ // no formating.
+ while (cb > 0)
+ {
+ struct PAP *ppap=NULL;
+ int fEol;
+ unsigned cch=min(cb, cbTempBufferSize);
+
+ if ((cch = CchReadLineExt((LPCH) lpstr, cch, rgch, &fEol))==0)
+ /* Reached terminator */
+ break;
+
+ if (fEol)
+ ppap = vppapNormal;
+
+ InsertRgch(docScrap, cp, rgch, cch, &vchpNormal, ppap);
+
+ cb -= cch;
+ cp += (typeCP) cch;
+ lpstr += cch;
+ }
+
+ CmdInsScrap(fTrue);
+ }
+ }
+ return TRUE;
+
+#endif // PENWIN
+
+#if defined(OLE)
+ case WM_DROPFILES:
+ /* We got dropped on, so bring ourselves to the top */
+ BringWindowToTop(hParentWw);
+ ObjGetDrop(wParam,FALSE);
+ break;
+#endif
+
+ case WM_TIMER:
+ /* Timer message. wParam contains the timer ID value */
+ MdocTimer(hWnd, wParam);
+ break;
+
+ case WM_CREATE:
+ /* Window's being created; lParam contains lpParam field
+ ** passed to CreateWindow */
+ SetRectEmpty(&rSaveInv);
+ MdocCreate(hWnd, lParam);
+ break;
+
+ case WM_SIZE:
+ /* Window's size is changing. lParam contains the height
+ ** and width, in the low and high words, respectively.
+ ** wParam contains SIZENORMAL for "normal" size changes,
+ ** SIZEICONIC when the window is being made iconic, and
+ ** SIZEFULLSCREEN when the window is being made full screen. */
+ MdocSize(hWnd, LOWORD(lParam), HIWORD(lParam), wParam);
+ break;
+
+ case WM_PAINT:
+#if defined(OLE)
+ if (nBlocking || fPrinting)
+ // this'll reduce async problems
+ {
+ PAINTSTRUCT Paint;
+ RECT rTmp=rSaveInv;
+
+ BeginPaint(hWnd,&Paint);
+ UnionRect(&rSaveInv,&rTmp,&Paint.rcPaint);
+ EndPaint(hWnd,&Paint);
+ break;
+ }
+#endif
+ /* Time for the window to draw itself. */
+ UpdateInvalid();
+ UpdateDisplay( FALSE );
+
+ break;
+
+ case WM_SETFOCUS:
+ /* The window is getting the focus. wParam contains the window
+ ** handle of the window that previously had the focus. */
+
+#if defined(JAPAN) & defined(DBCS_IME)
+
+// If we're getting input focus, we have to get current status of IME convert
+// window, and initialize 'bImeCnvOpen'. [yutakan:07/15/91]
+//
+ if(!GetIMEOpen(hWnd,&bImeCnvOpen))
+ /* If err return, supporse IME is not enalble.
+ */
+ bImeCnvOpen = FALSE;
+ bGetFocus = TRUE;
+#endif
+ MdocGetFocus(hWnd, (HWND)wParam);
+ break;
+
+ case WM_KILLFOCUS:
+ /* The window is losing the focus. wParam contains the window
+ ** handle of the window about to get the focus, or NULL. */
+
+#if defined(JAPAN) & defined(DBCS_IME)
+
+/* If we're losing input focus, we have to clear OpenStatus of convertwindow,
+** 'bImeCnvOpen'. [yutakan:07/15/91]
+*/
+ bImeCnvOpen = FALSE;
+ bGetFocus = FALSE;
+#endif
+ MdocLoseFocus(hWnd, (HWND)wParam);
+ /* Since we might be moving/sizing a picture, set flag to
+ ** cancel this. */
+ vfCancelPictMove = TRUE;
+ break;
+
+#if defined(JAPAN) & defined(DBCS_IME)
+ case WM_IME_REPORT:
+ /* if IME convert window has been opened,
+ ** we're getting into Non PeekMessage
+ ** Mode at 'FImportantMsgPresent()'
+ */
+ if(wParam == IR_OPENCONVERT || wParam == IR_CHANGECONVERT)
+ bImeCnvOpen = TRUE;
+ else if(wParam == IR_CLOSECONVERT)
+ bImeCnvOpen = FALSE;
+
+ if (wParam == IR_STRING) {
+ // Do nothing with IR_STRING // Yutakan
+ break;
+ /* put string from KKC to scrap */
+// PutImeString(hWnd, LOWORD(lParam)); // need more bug fix.
+// return 1L;
+ }
+ if (wParam == IR_STRINGSTART) {
+ HANDLE hMem;
+ LPSTR lpText;
+ if (hMem = GlobalAlloc(GMEM_MOVEABLE, 512L)) {
+ if (lpText = GlobalLock(hMem)) {
+ if (EatString(hWnd, (LPSTR)lpText, 512)) {
+ PutImeString( hWnd, hMem );
+ }
+ GlobalUnlock(hMem);
+ }
+ GlobalFree(hMem);
+ }
+ }
+ goto DefaultProc;
+#endif
+ }
+
+ }
+ else if (message < WM_USER)
+ { /* Clipboard messages */
+ if (!FMdocClipboardMsg( message, wParam, lParam ))
+ goto DefaultProc;
+ }
+ else
+ { /* Private WRITE messages */
+ switch (message)
+ {
+ default:
+ goto DefaultProc;
+
+#if defined(OLE)
+ case WM_WAITFORSERVER:
+ {
+ extern int vfDeactByOtherApp;
+ if (!hwndWait && !vfDeactByOtherApp)
+ {
+ vbCancelOK = TRUE;
+ ((LPOBJINFO)lParam)->fCanKillAsync = wParam;
+ ((LPOBJINFO)lParam)->fCompleteAsync = TRUE;
+ DialogBoxParam(hMmwModInstance, (LPSTR)"DTWAIT", hParentWw, lpfnWaitForObject, ((LPOBJINFO)lParam)->lpobject);
+ }
+ }
+ break;
+
+ case WM_OBJUPDATE:
+ ObjObjectHasChanged(wParam,(LPOLEOBJECT)lParam);
+ break;
+
+ case WM_OBJERROR:
+ ObjReleaseError(wParam);
+ break;
+
+ case WM_OBJBADLINK:
+ ObjHandleBadLink(wParam,(LPOLEOBJECT)lParam);
+ break;
+
+ case WM_OBJDELETE:
+ ObjDeleteObject((LPOBJINFO)lParam,wParam);
+ break;
+#endif
+
+ case wWndMsgDeleteFile:
+ /* wParam is a global handle to the file to be deleted */
+ /* Return code: TRUE - Ok to delete
+ FALSE - don't delete */
+ lReturn = (LONG)FDeleteFileMessage( wParam );
+ break;
+
+ case wWndMsgRenameFile:
+ /* wParam is a global handle to the file being renamed */
+ /* LOWORD( lParam ) is a global handle to the new name */
+ /* No return code */
+ RenameFileMessage( wParam, LOWORD( lParam ) );
+ break;
+ }
+ }
+
+ goto Ret;
+
+DefaultProc: /* All messages not processed come here. */
+
+ lReturn = DefWindowProc(hWnd, message, wParam, lParam);
+Ret:
+ if (vfCloseFilesInDialog)
+ CloseEveryRfn( FALSE );
+
+ return lReturn;
+}
+
+
+
+
+void MdocMouse(hWnd, message, wParam, pt)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+POINT pt;
+{
+extern int vfFocus;
+extern int vfDownClick;
+extern int vfMouseExist;
+extern HCURSOR vhcHourGlass;
+extern int vfInLongOperation;
+
+MSG msg;
+
+ if (vfInLongOperation)
+ {
+ SetCursor(vhcHourGlass);
+ return;
+ }
+
+ if (message == WM_MOUSEMOVE)
+ {
+ if (vfMouseExist)
+ {
+ HCURSOR hc;
+
+ /* All we do on move moves is set the cursor. */
+
+ if (pt.y < wwdCurrentDoc.ypMin)
+ {
+ hc = vhcArrow;
+ }
+ else
+ {
+#ifdef PENWIN
+ hc = (pt.x > xpSelBar ) ? vhcPen : vhcBarCur;
+
+#else
+ hc = (pt.x > xpSelBar) ? vhcIBeam : vhcBarCur;
+#endif
+ }
+ SetCursor( hc );
+ }
+ return;
+ }
+
+ /* Save the state of the shift keys. */
+ vfShiftKey = wParam & MK_SHIFT;
+ vfCommandKey = wParam & MK_CONTROL;
+ /* high bit returned from GetKeyState is 1 when the key is down, else
+ it is up, the low bit is 1 if it is toggled */
+
+ PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
+
+ vfOptionKey = GetKeyState(VK_MENU) < 0 ? true : false;
+ vfDoubleClick = (message == WM_LBUTTONDBLCLK);
+
+ if (message == WM_LBUTTONUP)
+ {
+ /* Windows demands this */
+ if (vfDownClick && !vfFocus)
+ {
+ SetFocus( hWnd );
+ vfDownClick = FALSE;
+ }
+ }
+ else
+ {
+ extern int vfGotoKeyMode;
+
+ vfGotoKeyMode = FALSE;
+ /* WM_LBUTTONDOWN or WM_LBUTTONDBLCLK */
+ vfDownClick = TRUE;
+
+#ifdef PENWIN
+ if( lpfnProcessWriting == NULL ||
+ vfDoubleClick ||
+ pt.x < xpSelBar ||
+ (*lpfnProcessWriting)( hWnd, NULL ) < 0
+ )
+ //Normal mouse processing
+ DoContentHit(pt);
+#else
+ DoContentHit(pt);
+#endif
+ }
+}
+
+
+
+void MdocTimer(hWnd, id)
+HWND hWnd;
+WORD id;
+{
+extern int vfSkipNextBlink;
+extern int vfInsertOn;
+extern int vfFocus;
+
+#if defined(OLE)
+ ++nGarbageTime;
+#endif
+
+ /* A timer event has occurred with ID id. Process it here. */
+ Assert( id == tidCaret ); /* Caret blink is the only timer event we know */
+
+ if ( ( vhWnd != hWnd ) || /* Document window is not current */
+ ( !vfFocus ) || /* Don't have the focus */
+ ( wwdCurrentDoc.fDirty) ) /* dl's are not up to date */
+ return;
+
+ if ( vfSkipNextBlink )
+ { /* We have been warned not to blank the cursor this time around */
+ vfSkipNextBlink = FALSE;
+ if ( vfInsertOn )
+ return;
+ }
+
+#if defined(OLE)
+ if (nGarbageTime > GARBAGETIME)
+ ObjCollectGarbage();
+#endif
+
+ if ( selCur.cpFirst == selCur.cpLim )
+ {
+ /* We must use ToggleSel instead of DrawInsertLine because the */
+ /* insert cp might not be on the screen & ToggleSel can */
+ /* figure this out */
+
+ extern int vypCursLine;
+ extern int vdypCursLine;
+
+ /* The following condition may not be true if we get a timer message
+ after a size message but before a paint message; ypMac will
+ have been adjusted but dlMac does not get adjusted to reflect
+ the change until UpdateDisplay is called. We have violated the
+ Windows dictate that ALL size-related calculations must occur
+ in the Size proc and we must compensate here */
+
+ if ( vypCursLine - vdypCursLine < wwdCurrentDoc.ypMac )
+ {
+ ToggleSel( selCur.cpFirst, selCur.cpFirst, !vfInsertOn );
+ vfSkipNextBlink = FALSE;
+ }
+ }
+}
+
+
+void CatchupInvalid(HWND hWnd)
+{
+ if (!nBlocking && !IsRectEmpty(&rSaveInv))
+ {
+ InvalidateRect(hWnd,&rSaveInv,FALSE);
+ SetRectEmpty(&rSaveInv);
+ }
+}
+
+#if defined(JAPAN) & defined(DBCS_IME)
+
+/*
+** We want to get 'IME ConvertWindow OpenStatus' but IME_GETOPEN
+** subfunction.
+** now does not support 'wCount' in IMESTRUCT (will support in future).
+** So this function will always return FALSE since wCount is always 0
+** as we set it before do SendIMEMessage(). [yutakan:07/16/91]
+*/
+
+BOOL GetIMEOpen(HWND hwnd, BOOL *pFlag)
+{
+ LPIMESTRUCT lpmem;
+ HANDLE hIMEBlock;
+ int wRet;
+
+ /* Get comunication area with IME */
+ hIMEBlock=GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_LOWER,
+ (DWORD)sizeof(IMESTRUCT));
+ if(!hIMEBlock) return FALSE;
+
+ lpmem = (LPIMESTRUCT)GlobalLock(hIMEBlock);
+ lpmem->fnc = IME_GETOPEN;
+ lpmem->wCount = 0;
+
+ GlobalUnlock(hIMEBlock);
+ if(!SendIMEMessage(hwnd,MAKELONG(hIMEBlock,NULL))){
+ wRet = FALSE; /* Error */
+ }
+ else
+ wRet = TRUE; /* Success */
+
+ lpmem = (LPIMESTRUCT)GlobalLock(hIMEBlock);
+ *pFlag = lpmem->wParam && lpmem->wCount;
+ GlobalUnlock(hIMEBlock);
+ GlobalFree(hIMEBlock);
+ return wRet;
+}
+
+/* routine to retrieve WM_CHAR from the message queue associated with hwnd.
+ * this is called by EatString.
+ */
+WORD NEAR PASCAL EatOneCharacter(hwnd)
+register HWND hwnd;
+{
+ MSG msg;
+ register int i = 10;
+
+ while(!PeekMessage((LPMSG)&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)) {
+ if (--i == 0)
+ return -1;
+ Yield();
+ }
+ return msg.wParam & 0xFF;
+}
+
+/* This routine is called when the MSWRITE_DOC class receives WM_IME_REPORT
+ * with IR_STRINGSTART message. The purpose of this function is to eat
+ * all strings between IR_STRINGSTART and IR_STRINGEND.
+ */
+BOOL EatString(hwnd, lpSp, cchLen)
+register HWND hwnd;
+LPSTR lpSp;
+WORD cchLen;
+{
+ MSG msg;
+ int i = 10;
+ int w;
+
+ *lpSp = '\0';
+ if (cchLen < 4)
+ return NULL; // not enough
+ cchLen -= 2;
+
+ while(i--) {
+ while(PeekMessage((LPMSG)&msg, hwnd, NULL, NULL, PM_REMOVE)) {
+ i = 10;
+ switch(msg.message) {
+ case WM_CHAR:
+ *lpSp++ = (BYTE)msg.wParam;
+ cchLen--;
+ if (IsDBCSLeadByte((BYTE)msg.wParam)) {
+ if ((w = EatOneCharacter(hwnd)) == -1) {
+ /* Bad DBCS sequence - abort */
+ lpSp--;
+ goto WillBeDone;
+ }
+ *lpSp++ = (BYTE)w;
+ cchLen--;
+ }
+ if (cchLen <= 0)
+ goto WillBeDone; // buffer exhausted
+ break;
+ case WM_IME_REPORT:
+ if (msg.wParam == IR_STRINGEND) {
+ if (cchLen <= 0)
+ goto WillBeDone; // no more room to stuff
+ if ((w = EatOneCharacter(hwnd)) == -1)
+ goto WillBeDone;
+ *lpSp++ = (BYTE)w;
+ if (IsDBCSLeadByte((BYTE)w)) {
+ if ((w = EatOneCharacter(hwnd)) == -1) {
+ /* Bad DBCS sequence - abort */
+ lpSp--;
+ goto WillBeDone;
+ }
+ *lpSp++ = (BYTE)w;
+ }
+ goto WillBeDone;
+ }
+ /* Fall through */
+ default:
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ break;
+ }
+ }
+ }
+ /* We don't get WM_IME_REPORT + IR_STRINGEND
+ * But received string will be OK
+ */
+
+WillBeDone:
+
+ *lpSp = '\0';
+ return TRUE;
+}
+
+#endif /* JAPAN */
+
diff --git a/private/mvdm/wow16/write/menu.c b/private/mvdm/wow16/write/menu.c
new file mode 100644
index 000000000..9b17c596f
--- /dev/null
+++ b/private/mvdm/wow16/write/menu.c
@@ -0,0 +1,1292 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* menu.c -- WRITE menu handling routines */
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCTLMGR
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NORASTEROPS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMETAFILE
+#define NOSOUND
+#define NOSCROLL
+#define NOWH
+#define NOOPENFILE
+#define NOCOMM
+#define NOMSG
+#define NOREGION
+#define NORECT
+
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "prmdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "editdefs.h"
+#include "menudefs.h"
+#include "str.h"
+#include "fontdefs.h"
+#include "dlgdefs.h"
+#include "dispdefs.h"
+#include <shellapi.h>
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+extern int FAR PASCAL ShellAbout(HWND hWnd, LPSTR szApp, LPSTR szOtherStuff, HICON hIcon);
+
+extern typeCP cpMinCur, cpMacCur;
+extern struct WWD rgwwd[];
+extern CHAR stBuf[];
+extern int docCur;
+extern struct DOD (**hpdocdod)[];
+extern struct SEL selCur;
+extern int vfOutOfMemory;
+extern BOOL vfWinFailure;
+extern int vfSysFull;
+extern int vfDiskError;
+extern struct CHP vchpAbs;
+extern struct PAP vpapAbs;
+extern struct CHP vchpFetch;
+extern struct CHP vchpSel;
+extern int vfSeeSel;
+extern typeCP vcpFetch;
+extern int vccpFetch;
+extern typeCP cpMacCur;
+extern typeCP vcpLimParaCache;
+extern HMENU vhMenu; /* global handle to the top level menu */
+extern HANDLE hParentWw;
+extern HCURSOR vhcHourGlass;
+extern HANDLE hMmwModInstance;
+extern HANDLE vhDlgFind;
+extern HANDLE vhDlgChange;
+extern HANDLE vhDlgChange;
+extern CHAR (**hszSearch)[]; /* Default search string */
+#ifdef CASHMERE
+extern int vfVisiMode;
+extern HWND vhWndGlos;
+extern HWND vhWndScrap;
+#endif /* CASHMERE */
+
+#ifdef ONLINEHELP
+extern fnHelp(void);
+#endif /* ONLINEHELP */
+
+/* These values are comprised of one bit for each menu item in the
+ applicable menu (for example, there are bitcount(0xfff)==12 menu
+ items under Character) ..pault */
+
+static int rgmfAllItems[CMENUS] = {
+ 0x01ff, /* FILE */
+ 0x003f, /* EDIT */
+ 0x000f, /* FIND */
+ 0x01ff, /* CHARACTER */
+ 0x01ff, /* PARA */
+ 0x001f, /* DOCU */
+ 0x000f /* HELP */
+};
+
+
+/* When we're editing a running header or footer, use this */
+static int rgmfRunning[CMENUS] = {
+ 0x0020, /* FILE -- enable printer-setup only */
+ 0x003F, /* EDIT -- everything */
+ 0x0007, /* FIND -- enable find/again and change */
+ 0x01FF, /* CHARACTER -- everything */
+ 0x01FF, /* PARAGRAPH -- everything */
+ 0x001F, /* DOCUMENT -- everything */
+ 0x000f /* HELP -- everything */
+};
+
+
+int viffnMenuMac;
+
+NEAR PutSzUndoInMenu(void);
+NEAR GetChpVals (struct CHP *, TSV *);
+NEAR GetPapVals (struct PAP *, TSV *);
+NEAR GetHffn (struct CHP *, TSV *);
+NEAR SetChUndef(TSV *, struct CHP *, int *);
+NEAR SetParaUndef(TSV *, struct PAP *, int *);
+NEAR FNoSearchStr(HWND);
+
+
+
+SetAppMenu(hMenu, index)
+HMENU hMenu; /* handle to popup menu */
+int index; /* index to popup menu */
+{
+/* Mark greying and checks on menus as appropriate to current state. */
+extern BOOL vfPrinterValid;
+extern CHAR (**hszPrPort)[];
+extern CHAR szNul[];
+extern int vfPictSel;
+extern int vfOwnClipboard;
+extern int docScrap;
+extern struct UAB vuab;
+extern HWND vhWnd;
+typeCP CpMacText();
+
+register int rgmfT[CMENUS]; /* Our workspace for menu greying */
+int imi;
+int imiMin = 0;
+int imiMax = 0;
+int *pflags;
+TSV rgtsv[itsvchMax]; /* gets attributes and gray flags from CHP, PAP */
+unsigned wPrintBitPos = ~(0x0001 << (imiPrint - imiFileMin));
+
+
+/* If we are out of memory or the disk is full, then... */
+if (vfOutOfMemory || vfSysFull || vfDiskError || vfWinFailure)
+ {
+ bltc( rgmfT, 0, CMENUS );
+#if WINVER >= 0x300
+ /* Disable the print stuff, but leave New/Open/Save/SaveAs/Exit */
+ rgmfT[FILE] = 0x008f;
+#else
+ /* Disable everything except Save & SaveAs */
+ rgmfT[FILE] = 0x0018;
+#endif
+ }
+else
+ {
+ /* Start with all items or subset if editing running head/foot */
+ blt( (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter) ? rgmfRunning
+ : rgmfAllItems, rgmfT, CMENUS );
+ }
+
+pflags = &rgmfT[index];
+
+switch (index)
+ {
+ case FILE:
+ imiMin = imiFileMin;
+ imiMax = imiFileMax;
+
+ /* Disallow print, if the printer or the port is not valid. */
+ if (!vfPrinterValid || hszPrPort == NULL ||
+ WCompSz( *hszPrPort, szNul ) == 0)
+ *pflags &= wPrintBitPos;
+ break;
+
+ case EDIT:
+ imiMin = imiEditMin;
+ imiMax = imiEditMax;
+ /* Disallow cut, copy if the selection is empty */
+ if (selCur.cpFirst == selCur.cpLim)
+ {
+ *pflags &= 0xfff9;
+ }
+ /* Move and Size picture are only allowed if a picture is selected */
+ if (!vfPictSel)
+ *pflags &= 0xFFCF;
+ /* Disallow Paste if we can determine that the scrap is empty.
+ Regrettably, we can be fooled into thinking it is not by
+ another instance of MEMO that is the clipboard owner and has
+ an empty scrap. */
+
+ /* Disallow UNDO if appropriate; set UNDO string into menu */
+ {
+ if ((vuab.uac == uacNil) || vfOutOfMemory)
+ {
+ /* Gray out undo */
+ *pflags &= 0xfffe;
+ }
+ PutSzUndoInMenu();
+ }
+ break;
+
+ case FIND:
+ imiMin = imiFindMin;
+ imiMax = imiFindMax;
+ if ((GetActiveWindow() == hParentWw && CchSz(**hszSearch) == 1) ||
+ (!vhDlgFind && !vhDlgChange && (CchSz(**hszSearch) == 1)) ||
+ (vhDlgFind && FNoSearchStr(vhDlgFind)) ||
+ (vhDlgChange && FNoSearchStr(vhDlgChange)))
+ *pflags &= 0xfffd; /* disable find again */
+
+ if (CpMacText( docCur ) == cp0)
+ *pflags &= 0xfff0; /* disable find, search, change, goto page */
+ break;
+
+ case CHARACTER:
+ imiMin = imiCharMin;
+ imiMax = imiCharMax;
+
+ if (!(vfOutOfMemory || vfWinFailure))
+ {
+ int iffn, iffnCurFont, fSetFontList;
+ struct FFN **hffn, *pffn;
+ union FCID fcid;
+ extern struct FFN **MpFcidHffn();
+
+ /* GetRgtsvChpSel() fills up rgtsv */
+ GetRgtsvChpSel(rgtsv);
+
+ CheckMenuItem(hMenu, imiBold,
+ (rgtsv[itsvBold].fGray == 0 && rgtsv[itsvBold].wTsv != 0) ?
+ MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiItalic,
+ (rgtsv[itsvItalic].fGray == 0 && rgtsv[itsvItalic].wTsv != 0) ?
+ MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiUnderline,
+ (rgtsv[itsvUline].fGray == 0 && rgtsv[itsvUline].wTsv != 0) ?
+ MF_CHECKED : MF_UNCHECKED);
+
+ /* note that the value stored in rgtsv[itsvPosition].wTsv
+ is really a signed integer, so we can just check for
+ 0, > 0, and < 0 */
+
+ CheckMenuItem(hMenu, imiSuper,
+ (rgtsv[itsvPosition].fGray == 0
+ && (int)(rgtsv[itsvPosition].wTsv) > 0) ?
+ MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiSub,
+ (rgtsv[itsvPosition].fGray == 0
+ && (int)(rgtsv[itsvPosition].wTsv) < 0) ?
+ MF_CHECKED : MF_UNCHECKED);
+
+#if 0
+ /* SetFontMenuItems() pulled on line */
+ {
+ /* make sure that the right font names are on the character dropdown */
+
+ /* These two lines avoid calculating bdodCur twice */
+ unsigned int bdodCur = docCur * sizeof (struct DOD);
+#define pdodCur ( (struct DOD *) ( (CHAR *)(&(**hpdocdod) [0]) + bdodCur))
+
+ fSetFontList = !(*(pdodCur->hffntb))->fFontMenuValid;
+ if (fSetFontList)
+ {
+ /* need to get the current list */
+ viffnMenuMac = 0;
+ if (FInitFontEnum(docCur, 3, TRUE))
+ {
+ for (iffn = 0; iffn < 3; iffn++)
+ {
+ if (!FEnumFont((struct FFN *)rgffnFontMenu[iffn]))
+ break;
+ viffnMenuMac++;
+ }
+ EndFontEnum();
+ (*(pdodCur->hffntb))->fFontMenuValid = TRUE;
+ }
+ }
+
+ /* make sure the current font is on the list - ok, so it's kind of
+ a hack */
+ mfFonts = 0xffff; /* template to mask "no font" entries */
+ iffnCurFont = -1;
+ hffn = (struct FFN **)rgtsv[itsvFfn].wTsv;
+ for (iffn = 0; iffn < 3; iffn++)
+ {
+ if (iffn >= viffnMenuMac)
+ mfFonts ^= (0x0040 << iffn); /* disable this entry */
+ else if (iffnCurFont < 0 && !rgtsv[itsvFfn].fGray)
+ {
+ pffn = (struct FFN *)rgffnFontMenu[iffn];
+ if (WCompSz((*hffn)->szFfn, pffn->szFfn) == 0)
+ iffnCurFont = iffn;
+ }
+ }
+
+ if (!rgtsv[itsvFfn].fGray && iffnCurFont < 0)
+ {
+ /* no match for this font - ram it in */
+ if (viffnMenuMac < 3)
+ viffnMenuMac++;
+ iffnCurFont = viffnMenuMac - 1;
+ bltbyte(*hffn, rgffnFontMenu[iffnCurFont],
+ CbFfn(CchSz((*hffn)->szFfn)));
+
+ mfFonts |= (0x0040 << iffnCurFont); /* enable this entry */
+
+ /* invalidate cache since we're messing it up */
+ (*pdodCur->hffntb)->fFontMenuValid = FALSE;
+ fSetFontList = TRUE;
+ }
+
+ if (fSetFontList)
+ /* font name cache has changed - update the menu dropdown */
+ for (iffn = 0; iffn < 3; iffn++)
+ {
+ int imi;
+#ifdef KOREA
+ int i;
+ CHAR rgb[LF_FACESIZE + 8];
+#else
+ CHAR rgb[LF_FACESIZE + 4];
+#endif
+
+ if (iffn < viffnMenuMac)
+ {
+#ifdef KOREA /* sangl 91.6.19 */
+ i = CchCopySz(((struct FFN *)rgffnFontMenu [iffn])->szFfn,
+ &rgb [0]);
+ rgb[i] = '(';
+ rgb[i+1] = '\036';
+ rgb[i+2] = '1' + iffn;
+ rgb[i+3] = '\037';
+ rgb[i+4] = '」';
+ rgb[i+5] = 'ア' + iffn;
+ rgb[i+6] = ')';
+ rgb[i+7] = '\0';
+#else
+ rgb[0] = '&';
+ rgb[1] = '1' + iffn;
+ rgb[2] = '.';
+ rgb[3] = ' ';
+ CchCopySz(((struct FFN *)rgffnFontMenu [iffn])->szFfn,
+ &rgb [4]);
+#endif
+ }
+ else
+ {
+ /* empty font name -- don't display it */
+ rgb [0] = '\0';
+ }
+
+ /* Set the menu */
+ imi = imiFont1 + iffn;
+ ChangeMenu( vhMenu, imi, (LPSTR)rgb, imi, MF_CHANGE );
+ }
+ }
+
+ *pflags &= mfFonts;
+
+ /* see which (if any) fonts apply */
+ /* note that the value stored in rgtsv[itsvFfn].wTsv
+ is the font name handle, rather than the ftc */
+ for (iffn = 0; iffn < 3; iffn++)
+ {
+ CheckMenuItem(hMenu, imiFont1 + iffn,
+ iffn == iffnCurFont ? MF_CHECKED : MF_UNCHECKED);
+ }
+#endif
+ }
+ break;
+
+ case PARA:
+ imiMin = imiParaMin;
+ imiMax = imiParaMax;
+
+ if (!(vfOutOfMemory || vfWinFailure))
+ {
+ int jc;
+
+ /* GetRgtsvPapSel() fills up rgtsv with paragraph properties */
+ GetRgtsvPapSel(rgtsv);
+
+ /* if gray, set jc to invalid value */
+ jc = (rgtsv[itsvJust].fGray == 0) ? rgtsv[itsvJust].wTsv : jcNil;
+
+ CheckMenuItem(hMenu, imiParaNormal, MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiLeft, jc == jcLeft ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiCenter, jc == jcCenter ? MF_CHECKED :
+ MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiRight, jc == jcRight ? MF_CHECKED :
+ MF_UNCHECKED);
+ CheckMenuItem(hMenu, imiJustified, jc == jcBoth ? MF_CHECKED :
+ MF_UNCHECKED);
+
+
+ CheckMenuItem(hMenu, imiSingleSpace,
+ (rgtsv[itsvSpacing].fGray == 0
+ && rgtsv[itsvSpacing].wTsv == czaLine) ?
+ MF_CHECKED : MF_UNCHECKED);
+
+ CheckMenuItem(hMenu, imiOneandhalfSpace,
+ (rgtsv[itsvSpacing].fGray == 0
+ && rgtsv[itsvSpacing].wTsv == (3 * czaLine / 2)) ?
+ MF_CHECKED : MF_UNCHECKED);
+
+ CheckMenuItem(hMenu, imiDoubleSpace,
+ (rgtsv[itsvSpacing].fGray == 0
+ && rgtsv[itsvSpacing].wTsv == (2 * czaLine)) ?
+ MF_CHECKED : MF_UNCHECKED);
+ }
+ break;
+
+ case DIV:
+ imiMin = imiDocuMin;
+ imiMax = imiDocuMax;
+
+ if (wwdCurrentDoc.fEditHeader)
+ *pflags &= ~2; /* disable footer */
+ else if (wwdCurrentDoc.fEditFooter)
+ *pflags &= ~1; /* disable header */
+ break;
+
+ default:
+ break;
+ } /* end of switch */
+
+ { /* enable or gray menu items */
+ register WORD wFlagMask = 1;
+
+ for (imi = imiMin; imi < imiMax; imi++)
+ {
+ EnableMenuItem(hMenu, imi, (*pflags & wFlagMask ? MF_ENABLED :
+ MF_GRAYED));
+ wFlagMask <<= 1;
+ }
+ }
+
+#if defined(OLE)
+ if (index == EDIT)
+ ObjUpdateMenu(hMenu);
+#endif
+}
+
+
+
+
+NEAR PutSzUndoInMenu()
+{
+/* Put the proper string for the current undo into the EDIT menu.
+idstrCurrentUndo gives the resource id for the current undo string. An
+idstrCurrentUndo value of -1 means use the last value loaded.
+This routine caches Undo strings so resource loads are needed only
+when the string changes. */
+
+extern struct UAB vuab;
+extern int idstrCurrentUndo; /* Current UNDO's string ID */
+extern CHAR szAltBS[];
+
+static CHAR szUndo[ cchSzUndo ];
+static int idstrUndoCache = -1;
+
+if (vuab.uac == uacNil)
+ {
+ idstrCurrentUndo = IDSTRUndoBase;
+ }
+
+if (idstrCurrentUndo < 0)
+ {
+ /* This means we should use the last Undo string */
+ Assert(idstrUndoCache > 0);
+
+ idstrCurrentUndo = idstrUndoCache;
+ }
+
+if (idstrCurrentUndo != idstrUndoCache)
+ {
+ /* Cached string is no good, build another */
+
+ CHAR *PchFillPchId();
+ CHAR *pch = szUndo;
+
+ pch += LoadString(hMmwModInstance, IDSTRUndoBase, (LPSTR)szUndo,
+ cchSzUndo);
+ if (idstrCurrentUndo != IDSTRUndoBase)
+ {
+ /* need the tail part */
+ pch = PchFillPchId(pch, idstrCurrentUndo,
+ (int)(szUndo + sizeof(szUndo) - pch));
+ }
+ CchCopySz((PCH)szAltBS, pch);
+
+ /* Set the menu */
+ ChangeMenu( vhMenu, imiUndo, (LPSTR)szUndo, imiUndo, MF_CHANGE );
+
+ /* Set cache for next time */
+ idstrUndoCache = idstrCurrentUndo;
+ }
+}
+
+
+GetRgtsvChpSel (prgtsv)
+TSV *prgtsv;
+{
+/* Return properties for the character menu. */
+
+typeCP cpLim;
+typeCP cpStartRun;
+struct CHP chp;
+int cchGray = 0; /* number of undefined (grayed) character attributes */
+int ccpFetch = 0; /* number of calls made to FetchCp */
+ /* max number of calls to FetchCp */
+#define ccpFetchMax 50
+
+#ifndef SAND
+if (selCur.cpLim > cpMacCur)
+ {
+ bltbc(prgtsv, 1, (cchTSV * itsvchMax)); /* turn all grays on */
+ return;
+ }
+#endif /* NOT SAND */
+
+bltbc(prgtsv, 0, (cchTSV * itsvchMax)); /* initializw rgtsv */
+CachePara(docCur, selCur.cpFirst);
+if (selCur.cpFirst == selCur.cpLim)
+ {
+ GetChpVals (&vchpSel,prgtsv); /* load up chp values */
+ GetHffn (&vchpSel,prgtsv); /* load up handle for font name */
+ }
+else
+ {
+ typeCP CpLimNoSpaces(typeCP, typeCP);
+
+ cpLim = CpLimNoSpaces(selCur.cpFirst, selCur.cpLim);
+ FetchCp(docCur, selCur.cpFirst, 0, fcmProps);
+ blt(&vchpFetch, &chp, cwCHP); /* CHP for use in comparisons */
+ GetChpVals (&vchpFetch,prgtsv); /* load up chp values */
+
+ while ((vcpFetch + vccpFetch) < cpLim && ++ccpFetch <= ccpFetchMax)
+ {
+ /* Indicate which attributes should be grayed */
+ FetchCp(docNil, cpNil, 0, fcmProps);
+ chp.fSpecial = vchpFetch.fSpecial;
+ if (CchDiffer (&chp, &vchpFetch, cchCHP) != 0)
+ {
+ SetChUndef(prgtsv, &vchpFetch, &cchGray);
+ if (cchGray == itsvchMax) /* all gray - don't bother */
+ break;
+ }
+ }
+ if (ccpFetch > ccpFetchMax)
+ {
+ /* never finished - make everything gray */
+ bltbc(prgtsv, 1, (cchTSV * itsvchMax));
+ }
+ else
+ GetHffn (&chp,prgtsv); /* load up handle for font name */
+ }
+}
+
+
+GetRgtsvPapSel (prgtsv)
+TSV *prgtsv;
+{
+/* Return properties for the paragraph menu. */
+
+/* Using selCur, the current para props are left in vpapAbs and the paragraph
+ attributes in rgtsv are set to gray if that attribute differs from that
+ in the previous paragraph. Up to cparaMax paragraphs will be checked */
+
+
+int cparaGray = 0; /* number of undefined (grayed) paragraph attributes */
+ /* max number of calls to CachePara */
+#define cparaMax 50
+
+int cpara = 0;
+struct PAP pap;
+
+CachePara(docCur, selCur.cpFirst);
+
+#ifdef ENABLE /* we will show defaults even if the cursor is next to endmark */
+if (selCur.cpFirst == cpMacCur)
+ {
+ bltbc(prgtsv, 1, (cchTSV * itsvparaMax)); /* turn all grays on */
+ return;
+ }
+#endif
+
+bltbc(prgtsv, 0, (cchTSV * itsvparaMax)); /* initializw rgtsv */
+
+blt(&vpapAbs, &pap, cwPAP); /* save 1st paragraph for compares */
+GetPapVals (&pap,prgtsv); /* load rgtsv with pap values */
+
+while (vcpLimParaCache < selCur.cpLim && ++cpara <= cparaMax)
+ {
+ /* If any props are different, set appropriate flags */
+ CachePara(docCur, vcpLimParaCache);
+ if (CchDiffer(&pap, &vpapAbs, (cwPAPBase * cchINT)) != 0)
+ {
+ SetParaUndef(prgtsv, &vpapAbs, &cparaGray);
+ if (cparaGray == itsvparaMax) /* all gray - don't bother */
+ break;
+ }
+ }
+
+if (cpara > cparaMax)
+ /* never finished - make everything gray */
+ bltbc(prgtsv, 1, (cchTSV * itsvparaMax));
+}
+
+
+NEAR GetChpVals (pchp,prgtsv) /* load chp values into rgtsv */
+register struct CHP *pchp;
+register TSV *prgtsv;
+{
+
+ (prgtsv+itsvBold)->wTsv = pchp->fBold;
+ (prgtsv+itsvItalic)->wTsv = pchp->fItalic;
+ (prgtsv+itsvUline)->wTsv = pchp->fUline;
+
+ (prgtsv+itsvFfn)->wTsv = pchp->ftc;
+ (prgtsv+itsvSize)->wTsv = pchp->hps;
+
+ /* sub/superscripts - note that value is stored
+ as a signed integer, so we can just check for
+ the value relative to 0 */
+
+ (int)((prgtsv+itsvPosition)->wTsv) = (char)pchp->hpsPos;
+}
+
+NEAR GetPapVals (ppap,prgtsv) /* load pap values into rgtsv */
+register struct PAP *ppap;
+register TSV *prgtsv;
+{
+
+ (prgtsv+itsvJust)->wTsv = ppap->jc;
+ (prgtsv+itsvSpacing)->wTsv = ppap->dyaLine;
+ (prgtsv+itsvLIndent)->wTsv = ppap->dxaLeft;
+ (prgtsv+itsvFIndent)->wTsv = ppap->dxaLeft1;
+ (prgtsv+itsvRIndent)->wTsv = ppap->dxaRight;
+
+}
+
+NEAR GetHffn (pchp,prgtsv) /* load font name handle into rgtsv */
+register struct CHP *pchp;
+register TSV *prgtsv;
+{
+union FCID fcid;
+extern struct FFN **MpFcidHffn();
+ /* store handle for font name in font name entry */
+ Assert(sizeof(struct FFN **) == sizeof(prgtsv->wTsv));
+
+ fcid.strFcid.doc = docCur;
+ fcid.strFcid.ftc = pchp->ftc + (pchp->ftcXtra << 6);
+ (struct FFN **)((prgtsv+itsvFfn)->wTsv) = MpFcidHffn(&fcid);
+}
+
+
+NEAR SetChUndef(prgtsv, pchp, pcchGray)
+register TSV *prgtsv;
+register struct CHP *pchp;
+int *pcchGray;
+{
+
+ /* compare chp to values stored in rgtsv and set undefined
+ flags for differing fields of interest. */
+ /* BOLD */
+ if ((prgtsv+itsvBold)->fGray == 0)
+ if (pchp->fBold != (prgtsv+itsvBold)->wTsv)
+ {
+ (prgtsv+itsvBold)->fGray = 1;
+ (*pcchGray)++;
+ }
+ /* ITALIC */
+ if ((prgtsv+itsvItalic)->fGray == 0)
+ if (pchp->fItalic != (prgtsv+itsvItalic)->wTsv)
+ {
+ (prgtsv+itsvItalic)->fGray = 1;
+ (*pcchGray)++;
+ }
+ /* UNDERLINE */
+ if ((prgtsv+itsvUline)->fGray == 0)
+ if (pchp->fUline != (prgtsv+itsvUline)->wTsv)
+ {
+ (prgtsv+itsvUline)->fGray = 1;
+ (*pcchGray)++;
+ }
+ /* Position (SUBSCRIPT OR SUPERSCRIPT) */
+ /* if different: gray both sub and superscript.
+ The properties are really mutually exclusive,
+ even though they appear on the menu as separate
+ items. Also, for Write, off and gray are the
+ same, so if either is grayed, the other must be
+ either off or gray, so the appearance is the
+ same. */
+
+ if ((prgtsv+itsvPosition)->fGray == 0)
+ if (pchp->hpsPos != (prgtsv+itsvPosition)->wTsv)
+ {
+ (prgtsv+itsvPosition)->fGray = 1;
+ (*pcchGray)++;
+ }
+
+ /* FONT NAME */
+ if ((prgtsv+itsvFfn)->fGray == 0)
+ if (pchp->ftc != (prgtsv+itsvFfn)->wTsv)
+ {
+ (prgtsv+itsvFfn)->fGray = 1;
+ (*pcchGray)++;
+ }
+
+ /* FONT SIZE */
+ if ((prgtsv+itsvSize)->fGray == 0)
+ if (pchp->hps != (prgtsv+itsvSize)->wTsv)
+ {
+ (prgtsv+itsvSize)->fGray = 1;
+ (*pcchGray)++;
+ }
+
+}
+
+NEAR SetParaUndef(prgtsv, ppap, pcparaGray)
+register TSV *prgtsv;
+register struct PAP *ppap;
+int *pcparaGray;
+{
+
+ /* compare pap to values stored in rgtsv and set undefined
+ flags for differing fields of interest. */
+ /* JUSTIFICATION */
+ if ((prgtsv+itsvJust)->fGray == 0)
+ if (ppap->jc != (prgtsv+itsvJust)->wTsv)
+ {
+ (prgtsv+itsvJust)->fGray = 1;
+ (*pcparaGray)++;
+ }
+ /* LINE SPACING */
+ if ((prgtsv+itsvSpacing)->fGray == 0)
+ if (ppap->dyaLine != (prgtsv+itsvSpacing)->wTsv)
+ {
+ (prgtsv+itsvSpacing)->fGray = 1;
+ (*pcparaGray)++;
+ }
+ /* LEFT INDENT */
+ if ((prgtsv+itsvLIndent)->fGray == 0)
+ if (ppap->dxaLeft != (prgtsv+itsvLIndent)->wTsv)
+ {
+ (prgtsv+itsvLIndent)->fGray = 1;
+ (*pcparaGray)++;
+ }
+ /* FIRST LINE INDENT */
+ if ((prgtsv+itsvFIndent)->fGray == 0)
+ if (ppap->dxaLeft1 != (prgtsv+itsvFIndent)->wTsv)
+ {
+ (prgtsv+itsvFIndent)->fGray = 1;
+ (*pcparaGray)++;
+ }
+ /* RIGHT INDENT */
+ if ((prgtsv+itsvRIndent)->fGray == 0)
+ if (ppap->dxaRight != (prgtsv+itsvRIndent)->wTsv)
+ {
+ (prgtsv+itsvRIndent)->fGray = 1;
+ (*pcparaGray)++;
+ }
+
+}
+
+
+
+/* C P L I M N O S P A C E S */
+typeCP CpLimNoSpaces(cpFirst, cpLim)
+typeCP cpFirst, cpLim;
+{
+/* Truncate trailing spaces unless only spaces are in sel. */
+
+int cch;
+typeCP cpLimOrig;
+CHAR rgch[cchMaxSz];
+
+cpLimOrig = cpLim;
+
+FetchRgch(&cch, rgch, docCur, CpMax(cpFirst + cchMaxSz, cpLim) - cchMaxSz,
+ cpLim, cchMaxSz);
+while (cch-- > 0 && rgch[cch] == chSpace)
+ {
+ --cpLim;
+ }
+return cch < 0 ? cpLimOrig : cpLim;
+} /* end of CpLimNoSpaces */
+
+
+
+
+NEAR FNoSearchStr(hDlg)
+HWND hDlg;
+{
+CHAR szBuf[255];
+HWND hWndFrom = GetActiveWindow();
+
+if (hDlg == hWndFrom || hDlg == (HANDLE)GetWindowWord(hWndFrom, GWW_HWNDPARENT))
+ {
+ if (GetDlgItemText(hDlg, idiFind, (LPSTR)szBuf, 255) == 0)
+ return(TRUE);
+ }
+return(FALSE);
+}
+
+
+
+
+PhonyMenuAccelerator( menu, imi, lpfn )
+int menu;
+int imi;
+FARPROC lpfn;
+{
+ HMENU hSubmenu = GetSubMenu(vhMenu,menu);
+
+ SetAppMenu( hSubmenu , menu );
+
+ if (FIsMenuItemEnabled( hSubmenu , imi ))
+ {
+ HiliteMenuItem( hParentWw, vhMenu, menu, MF_BYPOSITION | MF_HILITE );
+ (*lpfn) ();
+ HiliteMenuItem( hParentWw, vhMenu, menu, MF_BYPOSITION );
+ }
+}
+
+
+
+
+FIsMenuItemEnabled (HMENU hMenu , int id )
+{ /* Find out if a menu item in vhMenu is enabled. */
+ return !(GetMenuState(hMenu, id, MF_BYCOMMAND ) & (MF_DISABLED|MF_GRAYED));
+}
+
+
+int FAR PASCAL NewFont(HWND hwnd);
+
+void MmwCommand(hWnd, wParam, hWndCtl, codeCtl)
+HWND hWnd;
+WORD wParam;
+HWND hWndCtl;
+WORD codeCtl;
+{
+#ifdef INEFFLOCKDOWN
+extern FARPROC lpDialogHelp;
+extern FARPROC lpDialogGoTo;
+extern FARPROC lpDialogCharFormats;
+extern FARPROC lpDialogParaFormats;
+extern FARPROC lpDialogTabs;
+extern FARPROC lpDialogDivision;
+extern FARPROC lpDialogPrinterSetup;
+#else
+extern BOOL far PASCAL DialogPrinterSetup(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogHelp(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogGoTo(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogCharFormats(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogParaFormats(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogTabs(HWND, unsigned, WORD, LONG);
+extern BOOL far PASCAL DialogDivision(HWND, unsigned, WORD, LONG);
+#endif
+extern int vfPictSel;
+extern CHAR *vpDlgBuf;
+
+int DialogOk = 0;
+int fQuit = fFalse;
+
+
+ if (wParam & fMenuItem)
+ {
+ switch (wParam & MENUMASK)
+ {
+ case FILEMENU:
+ switch(wParam)
+ {
+ case imiNew:
+ fnNewFile();
+ break;
+ case imiOpen:
+ fnOpenFile((LPSTR)NULL);
+ break;
+ case imiSave:
+#if defined(OLE)
+ if (CloseUnfinishedObjects(TRUE) == FALSE)
+ return;
+#endif
+ fnSave();
+ break;
+ case imiSaveAs:
+#if defined(OLE)
+ if (CloseUnfinishedObjects(TRUE) == FALSE)
+ return;
+#endif
+ fnSaveAs();
+ break;
+ case imiPrint:
+ fnPrPrinter();
+ break;
+ case imiPrintSetup:
+ /* Bring up the Change Printer dialog box. */
+ PrinterSetupDlg(FALSE);
+ break;
+ case imiRepaginate:
+ fnRepaginate();
+ break;
+ case imiQuit:
+ fnQuit(hWnd);
+ fQuit = fTrue;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case EDITMENU:
+ switch(wParam)
+ {
+ case imiUndo:
+ CmdUndo();
+ break;
+ case imiCut:
+ fnCutEdit();
+ break;
+ case imiCopy:
+ fnCopyEdit();
+ break;
+ case imiPaste:
+#if defined(OLE)
+ vbObjLinkOnly = FALSE;
+#endif
+ fnPasteEdit();
+ break;
+#if defined(OLE)
+ case imiPasteSpecial:
+ vbObjLinkOnly = FALSE;
+ fnObjPasteSpecial();
+ break;
+ case imiPasteLink:
+ vbObjLinkOnly = TRUE;
+ fnPasteEdit();
+ break;
+ case imiInsertNew:
+ fnObjInsertNew();
+ break;
+#endif
+ case imiMovePicture:
+ fnMovePicture();
+ break;
+ case imiSizePicture:
+ fnSizePicture();
+ break;
+#if defined(OLE)
+ case imiProperties:
+ fnObjProperties();
+ break;
+#endif
+ default:
+ break;
+ }
+ break;
+
+#if defined(OLE)
+ case VERBMENU:
+ fnObjDoVerbs(wParam);
+ break;
+#endif
+
+ case FINDMENU:
+ if (wParam != imiGoTo && wParam != imiFindAgain)
+ StartLongOp();
+ switch(wParam)
+ {
+ case imiFind:
+ fnFindText();
+ break;
+ case imiFindAgain:
+ fnFindAgain();
+ break;
+ case imiChange:
+ fnReplaceText();
+ break;
+ case imiGoTo:
+ {
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogGoTo = MakeProcInstance(DialogGoTo, hMmwModInstance);
+ if (!lpDialogGoTo)
+ goto LNotEnufMem;
+#endif
+ DialogOk = OurDialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgGoTo),
+ hParentWw, lpDialogGoTo);
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogGoTo);
+#endif
+
+/* the following block has been commentted out because
+ the corresponding file(DISP.C) doesn't inlcude MmwCatSt
+ routine anymore */
+#if 0
+#ifdef JAPAN
+ {
+ extern void far MmwCatSt( HWND, BOOL );
+ MmwCatSt(hParentWw, FALSE);
+ }
+#endif
+#endif /* comment out */
+
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case CHARMENU:
+ if (wParam != imiCharFormats)
+ StartLongOp();
+ {
+ /* rgtsv gets attributes and gray flags from CHP */
+ TSV rgtsv[itsvchMax];
+ CHAR rgbDlgBuf[sizeof(BOOL)];
+ void NEAR fnCharSelectFont(int);
+
+ /* GetRgtsvChpSel() fills up rgtsv */
+ GetRgtsvChpSel(rgtsv);
+ switch(wParam)
+ {
+ case imiCharNormal:
+ ApplyCLooks(0, sprmCPlain, 0);
+ break;
+ case imiBold:
+ ApplyCLooks(0, sprmCBold, (rgtsv[itsvBold].fGray != 0) ? TRUE :
+ !rgtsv[itsvBold].wTsv);
+ break;
+ case imiItalic:
+ ApplyCLooks(0, sprmCItalic, (rgtsv[itsvItalic].fGray != 0) ?
+ TRUE : !rgtsv[itsvItalic].wTsv);
+ break;
+ case imiUnderline:
+ ApplyCLooks(0, sprmCUline, (rgtsv[itsvUline].fGray != 0) ? TRUE
+ : !rgtsv[itsvUline].wTsv);
+ break;
+ case imiSuper:
+ /* Note that the value stored in rgtsv[itsvPosition].wTsv is
+ really a signed integer, so we can just check for 0, > 0, and <
+ 0. */
+ ApplyCLooks(0, sprmCPos, !(rgtsv[itsvPosition].fGray == 0 &&
+ (int)rgtsv[itsvPosition].wTsv > 0) ? ypSubSuper : 0);
+ break;
+ case imiSub:
+ ApplyCLooks(0, sprmCPos, !(rgtsv[itsvPosition].fGray == 0 &&
+ (int)rgtsv[itsvPosition].wTsv < 0) ? -ypSubSuper : 0);
+ break;
+#if 0
+ case imiFont1:
+ fnCharSelectFont(0);
+ break;
+ case imiFont2:
+ fnCharSelectFont(1);
+ break;
+ case imiFont3:
+ fnCharSelectFont(2);
+ break;
+#endif
+ case imiSmFont:
+ if (CanChangeFont(-1))
+ {
+ ApplyCLooks(0, sprmCChgHps, -1);
+ vfSeeSel = TRUE;
+ }
+ break;
+ case imiLgFont:
+ if (CanChangeFont(1))
+ {
+ ApplyCLooks(0, sprmCChgHps, 1);
+ vfSeeSel = TRUE;
+ }
+ break;
+ case imiCharFormats:
+ {
+#if 0
+
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogCharFormats = MakeProcInstance(DialogCharFormats, hMmwModInstance);
+ if (!lpDialogCharFormats)
+ goto LNotEnufMem;
+#endif
+ vpDlgBuf = &rgbDlgBuf[0];
+ DialogOk = OurDialogBox(hMmwModInstance,
+ MAKEINTRESOURCE(dlgCharFormats),
+ hParentWw, lpDialogCharFormats);
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogCharFormats);
+#endif
+
+#else
+ DialogOk = NewFont(hParentWw);
+#endif
+
+break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+
+ case PARAMENU:
+ switch(wParam)
+ {
+ case imiParaNormal:
+ ApplyLooksParaS(0, sprmPNormal, 0);
+ if (vfPictSel)
+ {
+ CmdUnscalePic();
+ }
+ break;
+ case imiLeft:
+ ApplyLooksParaS(0, sprmPJc, jcLeft);
+ break;
+ case imiCenter:
+ ApplyLooksParaS(0, sprmPJc, jcCenter);
+ break;
+ case imiRight:
+ ApplyLooksParaS(0, sprmPJc, jcRight);
+ break;
+ case imiJustified:
+ ApplyLooksParaS(0, sprmPJc, jcBoth);
+ break;
+ case imiSingleSpace:
+ ApplyLooksPara(0, sprmPDyaLine, czaLine);
+ break;
+ case imiOneandhalfSpace:
+ ApplyLooksPara(0, sprmPDyaLine, czaLine * 3 / 2);
+ break;
+ case imiDoubleSpace:
+ ApplyLooksPara(0, sprmPDyaLine, czaLine * 2);
+ break;
+ case imiParaFormats:
+ {
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogParaFormats = MakeProcInstance(DialogParaFormats, hMmwModInstance);
+ if (!lpDialogParaFormats)
+ goto LNotEnufMem;
+#endif
+ DialogOk = OurDialogBox(hMmwModInstance,
+ MAKEINTRESOURCE(dlgParaFormats),
+ hParentWw, lpDialogParaFormats);
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogParaFormats);
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case DOCUMENU:
+ switch(wParam)
+ {
+ case imiFooter:
+ case imiHeader:
+ fnEditRunning(wParam);
+ break;
+ case imiShowRuler:
+ fnShowRuler();
+ break;
+ case imiTabs:
+ {
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogTabs = MakeProcInstance(DialogTabs, hMmwModInstance);
+ if (!lpDialogTabs)
+ goto LNotEnufMem;
+#endif
+ DialogOk = OurDialogBox(hMmwModInstance, MAKEINTRESOURCE(dlgTabs),
+ hParentWw, lpDialogTabs);
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogTabs);
+#endif
+ break;
+ }
+ case imiDivFormats:
+ {
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogDivision = MakeProcInstance(DialogDivision, hMmwModInstance);
+ if (!lpDialogDivision)
+ goto LNotEnufMem;
+#endif
+ DialogOk = OurDialogBox(hMmwModInstance,
+ MAKEINTRESOURCE(dlgDivision),
+ hParentWw, lpDialogDivision);
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogDivision);
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case HELPMENU:
+ {
+ int wHelpCode;
+ extern WORD wWinVer;
+ CHAR sz[ cchMaxFile ];
+LDefaultHelp:
+ PchFillPchId( sz, IDSTRHELPF, sizeof(sz) );
+ switch(wParam)
+ {
+ case imiIndex:
+ WinHelp(hParentWw, (LPSTR)sz, HELP_INDEX, NULL);
+ break;
+ case imiHelpSearch:
+ WinHelp(hParentWw, (LPSTR)sz, HELP_PARTIALKEY, (DWORD)(LPSTR)"");
+ break;
+ case imiUsingHelp:
+ WinHelp(hParentWw, (LPSTR)NULL, HELP_HELPONHELP, NULL);
+ break;
+ default:
+ case imiAbout:
+ if (((wWinVer & 0xFF) >= 3) && ((wWinVer & 0xFF00) >= 0x0A00))
+ {
+ extern CHAR szMw_icon[];
+ extern CHAR szAppName[];
+ ShellAbout(hParentWw, szAppName, "",
+ LoadIcon( hMmwModInstance, (LPSTR)szMw_icon ));
+ }
+ break;
+ }
+ break;
+ }
+
+ default:
+ if (wParam == imiHelp)
+ {
+#ifdef WIN30
+ wParam = imiIndex; /* For all Win3 applets, pressing F1
+ should bring up the Help Index */
+#endif
+ goto LDefaultHelp;
+ }
+ }
+ if (DialogOk == -1)
+ {
+LNotEnufMem:
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+ }
+
+ if (!fQuit)
+ UpdateInvalid(); /* To be sure we update the area behind dialogs */
+}
+
+
+
+
+#if 0
+void NEAR fnCharSelectFont(iffn)
+/* select the specified font from the three listed on char dropdown */
+
+int iffn;
+ {
+ struct FFN *pffn;
+ int ftc;
+
+ extern CHAR rgffnFontMenu[3][ibFfnMax];
+ extern int docCur;
+
+ pffn = (struct FFN *)rgffnFontMenu[iffn];
+
+ ftc = FtcChkDocFfn(docCur, pffn);
+ if (ftc != ftcNil)
+ ApplyCLooks(0, sprmCFtc, ftc);
+ vfSeeSel = TRUE;
+ }
+#endif
+
diff --git a/private/mvdm/wow16/write/menudefs.h b/private/mvdm/wow16/write/menudefs.h
new file mode 100644
index 000000000..6e23c7c2a
--- /dev/null
+++ b/private/mvdm/wow16/write/menudefs.h
@@ -0,0 +1,162 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*
+This file contains the definitions of the numerical indexes to the menu
+items (imi) used by Windows WRITE.
+Each imi should be unique and be continuous within the same
+menu. The middle 2 bytes of imi are masked against MENUMASK to
+provide the submenu index.
+IF any of the menu item order has changed, menu.c has
+to be modified also -- rgmfAllItem, rgmfScrap, SetMenuFlags etc.
+*/
+
+/* number of pulldown submenus */
+#define CMENUS 7
+
+/* menu index */
+#define FILE 0
+#define EDIT 1
+#define FIND 2
+#define CHARACTER 3
+#define PARA 4
+#define DIV 5
+#define HELP 6
+
+#define MENUMASK 0x0ff0
+#define FILEMENU 0x0000
+#define EDITMENU 0x0010
+#define FINDMENU 0x0020
+#define CHARMENU 0x0040
+#define PARAMENU 0x0080
+#define DOCUMENU 0x0100
+#define HELPMENU 0x0200
+#define VERBMENU 0x0400
+
+#define fMenuItem 0x1000
+
+#define imiNil 0x1fff
+#define imiHelp 0xf2f0
+
+/* Menu items */
+/* #define imiAbout 0x1000 */
+#define imiNew 0x1001
+#define imiOpen 0x1002
+#define imiSave 0x1003
+#define imiSaveAs 0x1004
+#define imiPrint 0x1005
+#define imiPrintSetup 0x1006
+#define imiRepaginate 0x1007
+#define imiQuit 0x1008
+#define imiFileMin (imiNew)
+#define imiFileMax (imiQuit + 1)
+
+#define imiUndo 0x1010
+#define imiCut 0x1011
+#define imiCopy 0x1012
+#define imiPaste 0x1013
+#define imiMovePicture 0x1014
+#define imiSizePicture 0x1015
+#if defined(OLE)
+#if !defined(SMALL_OLE_UI)
+#define imiPasteLink 0x1016
+#define imiProperties 0x1017
+#endif
+#define imiInsertNew 0x1018
+#define imiPasteSpecial 0x1019
+#endif
+#define imiEditMin (imiUndo)
+/* note imiEditMax intentionally doesn't include OLE menu items. (1.25.91) D. Kent */
+#define imiEditMax (imiSizePicture + 1)
+
+#if defined(OLE)
+/* verbs */
+#define imiVerb 0x1400
+#define imiVerbEdit 0x1401
+#define imiVerbPlay 0x1402
+#define imiVerbMax 0x14FF
+#endif
+
+
+#define imiFind 0x1020
+#define imiFindAgain 0x1021
+#define imiChange 0x1022
+#define imiGoTo 0x1023
+#define imiFindMin (imiFind)
+#define imiFindMax (imiGoTo + 1)
+
+#if defined(OLE)
+/* these aren't really menu items, but we'll associate them with
+ WM_COMMAND messages like cardfile does. 01/24/91 -- dougk */
+#define imiActivate 1030
+#define imiUpdate 1031
+#define imiFreeze 1032
+#define imiClone 1033
+#define imiCopyfromlink 1034
+#endif
+
+#define imiCharNormal 0x1040
+#define imiBold 0x1041
+#define imiItalic 0x1042
+#define imiUnderline 0x1043
+#define imiSuper 0x1044
+#define imiSub 0x1045
+#if 0
+#define imiFont1 0x1046
+#define imiFont2 0x1047
+#define imiFont3 0x1048
+#endif
+#define imiSmFont 0x1046
+#define imiLgFont 0x1047
+#define imiCharFormats 0x1048
+#define imiCharMin (imiCharNormal)
+#define imiCharMax (imiCharFormats + 1)
+
+/* special accelerator key
+#define imiAccelBold 0x104c
+#define imiAccelItalic 0x104d
+#define imiAccelUnderline 0x104e*/
+
+#define imiParaNormal 0x1080
+#define imiLeft 0x1081
+#define imiCenter 0x1082
+#define imiRight 0x1083
+#define imiJustified 0x1084
+#define imiSingleSpace 0x1085
+#define imiOneandhalfSpace 0x1086
+#define imiDoubleSpace 0x1087
+#define imiParaFormats 0x1088
+#define imiParaMin (imiParaNormal)
+#define imiParaMax (imiParaFormats + 1)
+
+#define imiHeader 0x1100
+#define imiFooter 0x1101
+#define imiShowRuler 0x1102
+#define imiTabs 0x1103
+#define imiDivFormats 0x1104
+#define imiDocuMin (imiHeader)
+#define imiDocuMax (imiDivFormats + 1)
+
+#define imiIndex 0x1200
+#define imiHelpSearch 0x1201
+#define imiUsingHelp 0x1202
+#define imiAbout 0x1203
+#define imiHelpMin (imiIndex)
+#define imiHelpMax (imiAbout + 1)
+
+#ifdef CASHMERE
+#define imiFootnote
+#define imiPreferences
+#endif
+
+#ifdef ENABLE /* CFILE, CEDIT ... */
+/* number of items in each submenu */
+#define CFILE (imiFileMax - imiFileMin)
+#define CEDIT (imiEditMax - imiEditMin)
+#define CFIND (imiFindMax - imiFindMin)
+#define CCHAR (imiCharMax - imiCharMin)
+#define CPARA (imiParaMax - imiParaMin)
+#define CDOCU (imiDocuMax - imiDocuMin)
+#define CHELP (imiHelpMax - imiHelpMin)
+#endif
diff --git a/private/mvdm/wow16/write/mergedef.h b/private/mvdm/wow16/write/mergedef.h
new file mode 100644
index 000000000..9366b364b
--- /dev/null
+++ b/private/mvdm/wow16/write/mergedef.h
@@ -0,0 +1,16 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#ifdef SAND
+#define ihszMax 127 /* max fields */
+#else /* not SAND */
+#define ihszMax 255 /* max fields */
+#endif /* not SAND */
+
+#define cchMaxMName 128 /* max field name length */
+#define levNil (-1)
+#define cIncludesMax 64 /* max number of nested include files */
+#define typeNumMaxOver10 (214748364L)
+
+typedef long typeNum;
diff --git a/private/mvdm/wow16/write/messages/usa/ole.dlg b/private/mvdm/wow16/write/messages/usa/ole.dlg
new file mode 100644
index 000000000..3f696e64f
--- /dev/null
+++ b/private/mvdm/wow16/write/messages/usa/ole.dlg
@@ -0,0 +1,98 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+/*
+ * Dialog for LINK Properties...
+ */
+DTPROP DIALOG LOADONCALL MOVEABLE DISCARDABLE 12, 34, 291, 97
+FONT 8 "Helv"
+CAPTION "Links"
+STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | WS_VISIBLE | DS_MODALFRAME | WS_POPUP
+BEGIN
+ CONTROL "&Edit", IDD_EDIT, "button", BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 249, 63, 37, 14
+
+ /* List box full of links and objects */
+ CONTROL "&Links:", -1, "static", SS_LEFT | WS_CHILD, 6, 4, 30, 9
+ CONTROL "", IDD_LISTBOX, "listbox", LBS_EXTENDEDSEL | LBS_MULTIPLESEL
+ | WS_TABSTOP | LBS_NOTIFY | LBS_USETABSTOPS | WS_BORDER | WS_CHILD | WS_VSCROLL, 5, 15, 234, 40
+
+ /* Automatic and manual link options */
+ CONTROL "Update:", -1, "static", SS_LEFT | WS_CHILD, 8, 60, 30, 9
+ CONTROL "Au&tomatic", IDD_AUTO, "button", BS_RADIOBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD, 39, 58, 46, 14
+ CONTROL "&Manual", IDD_MANUAL, "button", BS_RADIOBUTTON | WS_TABSTOP | WS_CHILD, 89, 58, 42, 14
+
+ /* Push buttons at the bottom of the dialog */
+ CONTROL "&Update Now", IDD_UPDATE, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 26, 75, 58, 14
+ CONTROL "Ca&ncel Link", IDD_FREEZE, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 91, 75, 58, 14
+ CONTROL "C&hange Link...", IDD_CHANGE, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 156, 75, 58, 14
+
+ /* Push buttons on the side of the dialog */
+ CONTROL "OK", IDOK, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 249, 6, 37, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 249, 25, 37, 14
+ CONTROL "&Activate", IDD_PLAY, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 249, 44, 37, 14
+END
+
+DTINVALIDLINK DIALOG LOADONCALL MOVEABLE DISCARDABLE 99, 50, 151, 49
+CAPTION "Write"
+STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | DS_MODALFRAME | WS_POPUP
+BEGIN
+ CONTROL "Linked document is unavailable.", -1, "static", SS_CENTER | WS_CHILD, 28, 10, 119, 15
+ CONTROL "&Links...", IDD_CHANGE, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 90, 28, 45, 14
+ CONTROL "OK", IDOK, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 35, 28, 45, 14
+ CONTROL 32515, -1, "static", SS_ICON | WS_CHILD, 7, 11, 16, 21
+END
+
+DTINVALIDLINKS DIALOG LOADONCALL MOVEABLE DISCARDABLE 75, 49, 180, 55
+CAPTION "Write"
+STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | DS_MODALFRAME | WS_POPUP
+BEGIN
+ CONTROL "Some linked documents were unavailable and could not be updated.", -1, "static", SS_CENTER | WS_CHILD, 30, 7, 144, 21
+ CONTROL "&Links...", IDD_CHANGE, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 110, 31, 45, 14
+ CONTROL "OK", IDOK, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 54, 31, 45, 14
+ CONTROL 32515, -1, "static", SS_ICON | WS_CHILD, 10, 13, 16, 21
+END
+
+
+DTCREATE DIALOG LOADONCALL MOVEABLE DISCARDABLE 82, 56, 180, 62
+FONT 8 "Helv"
+CAPTION "Insert Object"
+STYLE DS_MODALFRAME | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | WS_VISIBLE | WS_POPUP
+BEGIN
+ CONTROL "", IDD_LISTBOX, "listbox", WS_TABSTOP | LBS_STANDARD | LBS_NOTIFY | LBS_SORT | WS_BORDER | WS_VSCROLL | WS_CHILD, 6, 14, 125, 40
+ CONTROL "OK", IDOK, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 139, 6, 35, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 139, 28, 35, 14
+ CONTROL "&Object Type:", -1, "static", SS_LEFT | WS_CHILD, 7, 3, 50, 9
+END
+
+
+DTWAIT DIALOG LOADONCALL MOVEABLE DISCARDABLE 26, 26, 193, 78
+CAPTION "Write"
+FONT 8, "Helv"
+STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_VISIBLE | DS_MODALFRAME | WS_POPUP
+BEGIN
+ CONTROL "&Switch To...", IDD_SWITCH, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 45, 55, 50, 14
+ CONTROL "&Retry", IDOK, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 111, 55, 37, 14
+ CONTROL "This action cannot be completed because the application needed by the object is busy.", -1, "static", SS_LEFT | WS_CHILD, 35, 9, 149, 21
+ CONTROL "You may 'Switch to' the object's application and try to correct the problem.", -1, "static", SS_LEFT | WS_CHILD, 35, 31, 145, 22
+ CONTROL 32515, -1, "static", SS_ICON | WS_CHILD, 7, 15, 18, 26
+END
+
+PASTESPECIAL DIALOG LOADONCALL MOVEABLE DISCARDABLE 87, 52, 171, 77
+FONT 8 "Helv"
+CAPTION "Paste Special"
+STYLE DS_MODALFRAME | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | WS_POPUP
+BEGIN
+ CONTROL "&Paste", IDD_PASTE, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 119, 9, 46, 14
+ CONTROL "Paste &Link", IDD_PASTELINK, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 119, 32, 46, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 119, 55, 46, 14
+ CONTROL "Source:", IDD_SOURCE, "static", SS_LEFT | WS_CHILD, 5, 6, 27, 8
+ CONTROL "", IDD_CLIPOWNER, "static", SS_LEFT | WS_CHILD, 35, 6, 77, 9
+ CONTROL "", IDD_ITEM, "static", SS_LEFT | WS_CHILD, 12, 15, 95, 16
+ CONTROL "&Data Type:", -1, "static", SS_LEFT | WS_CHILD, 4, 32, 50, 9
+ CONTROL "", IDD_LISTBOX, "listbox", LBS_NOTIFY | WS_TABSTOP | WS_BORDER | WS_VSCROLL | WS_CHILD, 3, 43, 110, 36
+END
+
+
+
+
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/messages/usa/write.dlg b/private/mvdm/wow16/write/messages/usa/write.dlg
new file mode 100644
index 000000000..4bb0ccf5d
--- /dev/null
+++ b/private/mvdm/wow16/write/messages/usa/write.dlg
@@ -0,0 +1,347 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+/* Dialog Boxes */
+
+
+#define WS_TABONLY (WS_TABSTOP | WS_GROUP) /* only tab can get to the item */
+
+#define WDialog DIALOG MOVEABLE
+#define WStyle STYLE DS_MODALFRAME|WS_SYSMENU|
+
+
+ /* note this may be a child of dlgOpen, so its start is based on its parent */
+dlgWordCvt WDialog 22, 22, 220, 60
+WStyle WS_DLGFRAME | WS_POPUP
+FONT 8 "Helv"
+CAPTION "Write"
+ begin
+ icon DI_EXCLAMATION, idiNil, 15, 8, 0, 0
+ ctext "", idiConvertPrompt, 35, 14, 180, 20
+ defpushbutton "&Convert", idiOk, 25, 39, 48, 14, WS_TABONLY
+ pushbutton "&No Conversion", idiNo, 81, 39, 65, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 155, 39, 40, 14, WS_TABONLY
+ end
+
+#ifdef ONLINEHELP
+dlgHelp DIALOG 30, 20, 280, 120
+ STYLE WS_POPUP | WS_DLGFRAME | WS_VISIBLE
+ begin
+ ltext "Windows Write V0.53", idiNil, 180, 10, 90, 12
+ ltext "June 19, 1985", idiNil, 180, 20, 90, 12
+ ltext "", idiMemFree, 180, 30, 16, 12
+ ltext "% free memory", idiNil, 200, 30, 70, 12
+ listbox idiHelp, 5, 5, 160, 112, LBS_NOTIFY | WS_VSCROLL | WS_VISIBLE | WS_TABSTOP | WS_BORDER
+ defpushbutton "&Help", idiOk, 180, 90, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 230, 90, 40, 14, WS_TABONLY
+ end
+
+/* The real size of this dialog box and its children is calculated in help. c */
+
+dlgHelpInner DIALOG 30, 40, 110, 80
+ STYLE WS_POPUP | WS_BORDER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+ caption "About Windows Write"
+ begin
+ ltext "", idiHelpName, 5, 5, 1, 1
+ control "", idiHelpScroll, "ScrollBar",
+ WS_TABONLY | SBS_VERT, 1,1,1,1
+ defpushbutton "Topics", idiHelpTopics, 1, 1, 1, 1, WS_TABONLY
+ pushbutton "Next", idiHelpNext, 2, 2, 1, 1, WS_TABONLY
+ pushbutton "Previous", idiHelpPrev, 3, 3, 1, 1, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 4, 4, 1, 1, WS_TABONLY
+ end
+
+#else
+dlgHelp WDialog 30, 20, 160, 100
+WStyle WS_POPUP | WS_DLGFRAME
+FONT 8 "Helv"
+CAPTION "About Write"
+ begin
+#ifdef OS2
+ ctext "Microsoft OS/2", idiNil, 41, 10, 78, 8
+ ctext "Version 2.0", idiNil, 60, 44, 40, 8
+#else
+ ctext "Microsoft Windows", idiNil, 41, 10, 78, 8
+ ctext "Version 3.0", idiNil, 60, 44, 40, 8
+#endif
+ ctext "Write", idiNil, 70, 20, 20, 8
+ ctext "Copyright \0251 1985-1990 Microsoft Corp." idiNil, 12, 56, 136, 8
+ icon "mw_icon", idiNil, 12, 24, 0, 0
+ defpushbutton "OK", idiOk, 60, 75, 40, 14, WS_TABONLY
+ end
+#endif
+
+dlgCancelPrint WDialog 20,20,90, 64
+WStyle WS_BORDER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+FONT 8 "Helv"
+CAPTION "Write"
+ begin
+ ctext "Now Printing", -1, 0, 8, 90, 8
+ ctext "", idiPrCancelName, 0, 18, 90, 8, SS_NOPREFIX
+ defpushbutton "Cancel", idiCancel, 29, 44, 32, 14, WS_TABONLY
+ end
+
+dlgRepaginate WDialog 90, 100, 155, 45
+WStyle WS_DLGFRAME | WS_POPUP
+FONT 8 "Helv"
+CAPTION "Repaginate Document"
+ begin
+ checkbox "Confirm Page &Breaks", idiRepageConfirm, 5, 15, 100, 12, WS_TABONLY
+ defpushbutton "OK", idiOk, 110, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 110, 25, 40, 14, WS_TABONLY
+ end
+
+dlgCancelRepage WDialog 15, 50, 94, 50
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+FONT 8 "Helv"
+CAPTION "Write"
+ begin
+ ctext "Repaginating", idiNil, 5, 5, 84, 8
+ ctext "document", idiNil, 5, 14, 84, 8
+ defpushbutton "Cancel", idiCancel, 27, 28, 40, 14, WS_TABONLY
+ end
+
+dlgSetPage WDialog 90, 120, 192, 50
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+FONT 8 "Helv"
+CAPTION "Repaginating Document"
+ begin
+ ltext "Use up and down buttons", idiNil, 5, 5, 92, 8
+ ltext "to move page break", idiNil, 5, 14, 72, 8
+ ltext "if necessary,", idiNil, 5, 23, 52, 8
+ ltext "then confirm.", idiNil, 5, 32, 52, 8
+ pushbutton "&Up", idiRepUp, 102, 8, 40, 14, WS_TABONLY
+ pushbutton "&Down", idiRepDown, 102, 28, 40, 14, WS_TABONLY
+ defpushbutton "&Confirm", idiOk, 147, 8, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 147, 28, 40, 14, WS_TABONLY
+ end
+
+dlgPageMark WDialog 90, 100, 135, 58
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+FONT 8 "Helv"
+CAPTION "Repaginating Document"
+ begin
+ icon DI_EXCLAMATION, idiNil, 5, 5, 0, 0
+ ltext "Would you like to keep", idiNil, 30, 7, 92, 12
+ ltext "this existing page break?", idiNil, 30, 19, 100, 12
+ pushbutton "Cancel", idiCancel, 7, 35, 35, 14, WS_TABONLY
+ defpushbutton "&Keep", idiKeepPgMark, 49, 35, 35, 14, WS_TABONLY
+ pushbutton "&Remove", idiRemovePgMark, 91, 35, 35, 14, WS_TABONLY
+ end
+
+dlgFind DIALOG LOADONCALL MOVEABLE DISCARDABLE
+30, 73, 236, 62
+CAPTION "Find"
+STYLE WS_BORDER | WS_CAPTION | DS_MODALFRAME | WS_POPUP | WS_SYSMENU | WS_VISIBLE
+FONT 8, "Helv"
+BEGIN
+ CONTROL "Fi&nd What:", idiNil, "static", SS_LEFT | WS_CHILD,
+ 4, 8, 42, 8
+ CONTROL "", idiFind, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER | WS_GROUP |
+ WS_TABSTOP | WS_CHILD | WS_BORDER,
+ 47, 7, 128, 12
+
+ CONTROL "Match &Whole Word Only", idiWholeWord, "button", WS_TABSTOP | WS_CHILD | WS_GROUP | BS_CHECKBOX,
+ 4, 26, 100, 12
+ CONTROL "Match &Case", idiMatchCase, "button", WS_TABSTOP | WS_CHILD | BS_CHECKBOX,
+ 4, 42, 64, 12
+
+ CONTROL "&Find Next", idiFindNext, "button", BS_DEFPUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 182, 5, 50, 14
+ CONTROL "Cancel", idiCancel, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 182, 23, 50, 14
+END
+
+
+dlgChange DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 44, 257, 80
+CAPTION "Replace"
+STYLE WS_BORDER | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME | WS_POPUP | WS_VISIBLE
+FONT 8, "Helv"
+BEGIN
+ CONTROL "Fi&nd What:", idiNil, "static", SS_LEFT | WS_CHILD,
+ 4, 9, 48, 8
+ CONTROL "", idiFind, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 54, 7, 114, 12
+ CONTROL "Re&place With:", idiNil, "static", SS_LEFT | WS_CHILD,
+ 4, 26, 48, 8
+ CONTROL "", idiChangeTo, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD | WS_GROUP,
+ 54, 24, 114, 12
+
+ CONTROL "Match &Whole Word Only", idiWholeWord, "button", WS_TABSTOP | WS_CHILD | WS_GROUP | BS_CHECKBOX,
+ 5, 46, 104, 12
+ CONTROL "Match &Case", idiMatchCase, "button", WS_TABSTOP | BS_CHECKBOX | WS_CHILD,
+ 5, 62, 59, 12
+
+ CONTROL "&Find Next", idiFindNext, "button", BS_DEFPUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 4, 77, 14
+ CONTROL "&Replace", idiChangeThenFind, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 21, 77, 14
+ CONTROL "Replace &All", idiChangeAll, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 38, 77, 14
+ CONTROL "C&lose", idiCancel, "button", BS_PUSHBUTTON | WS_CHILD |
+ WS_TABSTOP | WS_GROUP,
+ 174, 55, 77, 14
+END
+
+dlgGoTo WDialog 87, 63, 95, 40
+WStyle WS_POPUP | WS_DLGFRAME
+FONT 8 "Helv"
+CAPTION "Go To"
+ begin
+ ltext "&Page Number:", idiNil, 5, 7, 55, 12
+ edittext idiGtoPage, 69, 5, 21, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "OK", idiOk, 5, 22, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 50, 22, 40, 14, WS_TABONLY
+ end
+
+dlgCharFormats WDialog 80, 36, 180, 100
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+FONT 8 "Helv"
+CAPTION "Fonts"
+ begin
+ ltext "Font &Name:", idiNil, 5, 5, 45, 12
+ edittext idiChrFontName, 5, 16, 125, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&Fonts:", idiNil, 5, 33, 24, 12
+ listbox idiChrLBFontName, 5, 47, 105, 48, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ ltext "&Sizes:", idiNil, 115, 41, 24, 12
+ listbox idiChrLBFontSize, 115, 55, 24, 40, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ ltext "&Point", idiNil, 144, 61, 20, 12
+ edittext idiChrFontSize, 144, 83, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Size:", idiNil, 144, 70, 20, 12
+ defpushbutton "OK", idiOk, 135, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 135, 25, 40, 14, WS_TABONLY
+ end
+
+dlgParaFormats WDialog 28, 36, 150, 52
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+FONT 8 "Helv"
+CAPTION "Indents"
+ begin
+ ltext "&Left Indent:", idiNil, 3, 7, 48, 12
+ edittext idiParLfIndent, 56, 5, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&First Line:", idiNil, 3, 22, 44, 12
+ edittext idiParFirst, 56, 20, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&Right Indent:", idiNil, 3, 37, 52, 12
+ edittext idiParRtIndent, 56, 35, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "OK", idiOk, 105, 8, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 105, 27, 40, 14, WS_TABONLY
+ end
+
+dlgRunningHead WDialog 80, 110, 228, 42
+WStyle WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+FONT 8 "Helv"
+CAPTION "Page Header"
+ begin
+ ltext "&Distance from Top:", idiNil, 5, 7, 70, 12
+ edittext idiRHDx, 85, 5, 33, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "&Print on First Page", idiRHFirst, 133, 5, 90, 12, WS_TABONLY
+ pushbutton "&Insert Page #", idiRHInsertPage, 12, 22, 64, 14, WS_TABONLY
+ pushbutton "&Clear", idiRHClear, 88, 22, 30, 14, WS_TABONLY
+ defpushbutton "&Return to Document", idiOk, 130, 22, 85, 14, WS_TABONLY
+ end
+
+dlgFooter WDialog 80, 110, 228, 42
+WStyle WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+FONT 8 "Helv"
+CAPTION "Page Footer"
+ begin
+ ltext "&Distance from Bottom:", idiNil, 5, 7, 80, 12
+ edittext idiRHDx, 95, 5, 33, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "&Print on First Page", idiRHFirst, 133, 5, 90, 12, WS_TABONLY
+ pushbutton "&Insert Page #", idiRHInsertPage, 12, 22, 64, 14, WS_TABONLY
+ pushbutton "&Clear", idiRHClear, 88, 22, 30, 14, WS_TABONLY
+ defpushbutton "&Return to Document", idiOk, 130, 22, 85, 14, WS_TABONLY
+ end
+
+dlgTabs WDialog 26, 41, 278, 97
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+FONT 8 "Helv"
+CAPTION "Tabs"
+ begin
+ ltext "&Positions:", idiNil, 3, 7, 40, 12
+ edittext idiTabPos0, 45, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "&Decimal:", idiNil, 3, 22, 40, 12
+ checkbox ".", idiTabDec0, 51, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos1, 83, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec1, 89, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos2, 121, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec2, 127, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos3, 159, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec3, 165, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos4, 197, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec4, 203, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos5, 235, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec5, 241, 20, 18, 12, WS_TABONLY
+
+ ltext "&Positions:", idiNil, 3, 42, 40, 12
+ edittext idiTabPos6, 45, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "&Decimal:", idiNil, 3, 57, 40, 12
+ checkbox ".", idiTabDec6, 51, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos7, 83, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec7, 89, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos8, 121, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec8, 127, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos9, 159, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec9, 165, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos10, 197, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec10, 203, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos11, 235, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec11, 241, 55, 18, 12, WS_TABONLY
+ defpushbutton "OK", idiOk, 20, 75, 50, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 90, 75, 50, 14, WS_TABONLY
+ pushbutton "Clear &All", idiTabClearAll, 160, 75, 50, 14, WS_TABONLY
+ end
+
+
+dlgDivision WDialog 26, 30, 180, 110
+WStyle WS_POPUP | WS_DLGFRAME
+FONT 8 "Helv"
+CAPTION "Page Layout"
+ begin
+ ltext "&Start Page Numbers At:", idiNil, 5, 7, 88, 12
+ edittext idiDivPNStart, 95, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Margins:", idiNil, 5, 33, 40, 12
+ ltext "&Left:", idiNil, 12, 48, 20, 12
+ edittext idiDivLMarg, 35, 46, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&Right:", idiNil, 85, 48, 30, 12
+ edittext idiDivRMarg, 117, 46, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&Top:", idiNil, 12, 65, 20, 12
+ edittext idiDivTMarg, 35, 63, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "&Bottom:", idiNil, 85, 65, 30, 12
+ edittext idiDivBMarg, 117, 63, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Measurements:", idiNil, 5, 84, 63, 12
+ radiobutton "&inch", idiDivInch, 12, 94, 27, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "&cm", idiDivCm, 44, 94, 26, 12
+ defpushbutton "OK", idiOk, 135, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 135, 23, 40, 14, WS_TABONLY
+ end
+
+dlgBadMargins WDialog 50, 20, 235, 65
+WStyle WS_POPUP | WS_BORDER | WS_CAPTION
+FONT 8 "Helv"
+CAPTION "Write"
+ begin
+ icon DI_EXCLAMATION, idiNil, 5, 5, 0, 0
+ ltext "Current printer cannot print outside these margins", idiNil, 30, 5, 200, 12
+ ltext "Left:", idiNil, 30, 17, 20, 12
+ ltext "", idiBMrgLeft, 60, 17, 40, 12
+ ltext "Right:", idiNil, 130, 17, 24, 12
+ ltext "", idiBMrgRight, 168, 17, 40, 12
+ ltext "Top:", idiNil, 30, 29, 16, 12
+ ltext "", idiBMrgTop, 60, 29, 40, 12
+ ltext "Bottom:", idiNil, 130, 29, 28, 12
+ ltext "", idiBMrgBottom, 168, 29, 40, 12
+ defpushbutton "OK", idiOk, 97, 44, 40, 14, WS_TABSTOP
+ end
+
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/messages/usa/write.rc b/private/mvdm/wow16/write/messages/usa/write.rc
new file mode 100644
index 000000000..93fa5b2a1
--- /dev/null
+++ b/private/mvdm/wow16/write/messages/usa/write.rc
@@ -0,0 +1,452 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This is the source file for the resource file for Windows Write. The
+resource file is generated by running this file through the resouce compiler
+RC.EXE. */
+
+/* Version Stamping */
+#include "write.rcv"
+
+#include "bitmaps.h"
+
+mw_icon ICON write.ico
+
+mwlores CURSOR mwlores.cur
+mwhires CURSOR mwhires.cur
+pmscur CURSOR pmscur.cur
+
+idBmBtnsCGA BITMAP cgabtns.bmp
+idBmBtnsEGA BITMAP egabtns.bmp
+idBmBtnsVGA BITMAP vgabtns.bmp
+idBmBtns8514 BITMAP 8514btns.bmp
+
+idBmMarksCGA BITMAP cgamarks.bmp
+idBmMarksEGA BITMAP egamarks.bmp
+idBmMarksVGA BITMAP vgamarks.bmp
+idBmMarks8514 BITMAP 8514mrks.bmp
+
+
+/* ONLINEHELP was the define for the (never-implemented) Write 2.x help system */
+#define INTL /* International version */
+
+#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#define OLE /* also defined in mw.h 01/24/91 -- dougk */
+#define PENWIN /* pen windows: also defined in mw.h (6.21.91) v-dougk */
+
+#include "menudefs.h"
+
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#include "dlgdefs.h"
+#include "str.h"
+#define DI_QUESTION 32514 /* have to match windows.h MAKEINTRESOURCE(n) */
+#define DI_EXCLAMATION 32515 /* have to match windows.h MAKEINTRESOURCE(n) */
+
+
+STRINGTABLE BEGIN
+
+/* Note IDSTR's below must be <= cchMaxIDSTR chars! */
+
+IDS_MERGE1 "%s" /* relocatable message symbol */
+
+/* Menu and Undo strings */
+/* WARNING: The length of the longest UNDO string is kept as a constant
+ in str.h. This constant must be updated along with the strings */
+IDSTRUndoBase,"&Undo "
+IDSTRUndoEdit,"Editing"
+IDSTRUndoLook,"Formatting"
+IDSTRUndoTyping,"Typing"
+IDSTRShowRuler,"&Ruler On"
+IDSTRHideRuler,"&Ruler Off"
+IDSTREdit "Edit"
+
+/*
+ For localizing Edit.Object menu item: 'v'erb, 'c'lass, 'o'bject.
+ You can omit any word in the menu string by omitting the
+ character from the control string. Both control strings *must* be
+ defined because each is used in different circumstances (single and
+ popup cases). Any characters besides v,c, and o are interpreted
+ literally and are inserted into the menu string (spaces, hyphens, etc).
+*/
+IDSTRSingleVerb "v c o"
+IDSTRPopupVerbs "c o"
+
+IDSTRCancel "&Cancel"
+
+#ifdef ONLINEHELP
+IDSTRAbout, "About...\tF1"
+#else /* not ONLINEHELP */
+IDSTRAbout, "About..."
+#endif /* not ONLINEHELP */
+
+IDSTRHELPF "WRITE.HLP"
+
+/* Backup button in commdlg */
+IDSTRBackup "&Backup"
+
+/* clipboard format names */
+IDSTRBitmap "Bitmap"
+IDSTRPicture "Picture"
+IDSTRDIB "Device Independent Bitmap"
+IDSTRText "Text"
+
+/* OLE strings */
+#if defined(OLE)
+IDSTRMenuVerb, "&Object"
+IDSTRMenuVerbP, "&Objects"
+IDSTRObject, "Object" /* paste special list box */
+IDSTRAuto, "Automatic"
+IDSTRManual, "Manual"
+IDSTRFrozen, "Unavailable"
+IDSTRAllFilter, "All Files (*.*)"
+IDSTRUpdate, "The selected links to %s have been updated; %s contains additional links to %s.\n\nDo you want to update these additional links now?"
+IDSTRRename, "The selected links to %s have been changed; %s contains additional links to %s.\n\nDo you want to change these additional links now?"
+IDSTRChangelink , "Change Link"
+IDSTRLoading, "Loading..."
+#endif
+
+/* commdlg strings */
+IDSTROpenfile , "Open"
+IDSTRSavefile , "Save As"
+IDSTRDefWriExtension , "WRI"
+IDSTRDefDocExtension , "DOC"
+IDSTRDefTxtExtension , "TXT"
+IDSTRTxtDescr , "Text Files (*.TXT)"
+IDSTRWriDescr , "Write Files (*.WRI)"
+IDSTRDocDescr , "Word for DOS (*.DOC)"
+IDSTRDocTextDescr , "Word for DOS/Txt Only (*.DOC)"
+IDSTRAllFilesDescr , "All Files (*.*)"
+IDSTROldWriteDescr , "3.0 Write (*.WRI)"
+
+/* Search/Change strings */
+IDSTRChangeSel,"Replace &Selection"
+IDSTRChangeAll,"Replace &All"
+
+/* String for "(page)" and "Page nnnn" */
+IDSTRChPage,"page"
+
+IDSTROn, " on "
+IDSTRReplaceFile,"Replace Existing %s?"
+
+/* '%d' is for the number of characters saved to a file. Total length
+ with %d (counting '\0') should be <= 30!!!! Assume 7 chars in %d
+ (in English). */
+IDSTRChars, "%ld Chars."
+
+IDSTRSearching, "Finding..."
+IDSTRConvertText, "Text document"
+IDSTRConvertWord, "Microsoft Word for DOS document"
+
+/***** FOLLOWING MESSAGES ARE "*" LEVEL MESSAGES */
+
+IDPMTSearchDone,"Search operation complete."
+IDPMTNotFound,"Text not found."
+IDPMTNoReplace,"No replacements were made."
+IDPMTCancelSearch, "Search operation cancelled."
+
+/***** FOLLOWING MESSAGES ARE "?" LEVEL MESSAGES */
+
+IDPMTTruncateSz, "Can only search on text containing no more than 255 characters.\n\nSearch for the first 255 characters entered?"
+IDPMTConvert, "%s\nDo you want to convert this file to Write format?"
+
+/***** FOLLOWING MESSAGES ARE "!" LEVEL MESSAGES */
+
+IDPMTRottenFile,"This document is corrupt and cannot be accessed."
+IDPMTBadFileName,"%s\nThis filename is not valid."
+IDPMTBadFile,"The document you are opening may be damaged. Write may not run correctly if this document is opened.\n\nDo you want open this document?"
+IDPMTCantOpen,"%s\nFile not found.\n\nPlease verify that the correct path and filename are given."
+IDPMTCantShare,"%s\nThis file is in use.\n\nUse a new filename or close the file in use by another application."
+IDPMTFileNotFound, "%s\nCannot find this file.\n\nEither something has happened to the network or possibly the file has been renamed or moved. Do you want to try again?"
+IDPMTDirtyDoc,"%s\nThis document has changed.\n\nSave current changes?"
+IDPMTCantRunM,"Not enough memory for Write to complete this operation.\n\nQuit one or more applications to increase available memory, and then try again."
+IDPMTCantRunF,"Not enough disk space for Write to complete this operation.\n\nDelete one or more files to increase available disk space, and then try again."
+IDPMTNoPath,"Path does not exist.\n\nPlease verify that the correct path is given."
+//IDPMTOverwrite,"%s\nThis file already exists.\n\nReplace existing file?"
+IDPMTReadOnly,"The file is read-only.\n\nUse a different filename."
+IDPMTCantRead,"%s\nCannot read this file.\n\nEither something has happened to the network or possibly the file has been renamed or moved."
+IDPMTDelObjects, "If you save this document in the Write 3.0 format, the linked or embedded objects will be deleted from the saved file.\n\nDo you want to save this document in Write 3.0 format?"
+IDPMTDelPicture, "If you save this document in this format no pictures, including linked or embedded objects, will be saved.\n\nDo you want to save?"
+
+#if defined(OLE)
+ /* New OLE error messages */
+ IDPMTOLEError "Problem with object/link."
+ IDPMTFailedToFreeze,"Not enough memory to cancel the link.\n\nQuit one or more applications to increase available memory, and then try again."
+ IDPMTFailedToDeleteObject "Failed to delete object."
+ IDPMTFailedToUpdate "Failed to update object."
+ IDPMTServerBusy "The action cannot be completed because the application needed by the object is busy.\n\nSwitch to the unavailable application and complete or cancel the action that is causing it to be unavailable."
+ IDPMTFailedToCreateObject "Failed to create object."
+ IDPMTFailedToCommWithServer "Failed to communicate with the source application."
+ IDPMTFailedToLaunchServer "The server application cannot be found.\n\nMake sure that the application is properly installed, or exists in your DOS path, and that it has not been deleted, moved, or renamed."
+ IDPMTFailedToUpdateLink "Failed to update link information."
+ IDPMTFailedToActivate "Failed to edit/play object."
+ IDPMTFailedToLoadObject "Failed to load object.\n\nClose other applications to free memory, then reopen this document."
+ IDPMTFailedToDraw "Problem drawing or printing object."
+
+
+ IDSTRUpdateObject "This document contains links to other documents.\n\nDo you want to update links now?"
+ IDPMTLinkUnavailable "The source document cannot be found.\n\nMake sure that the object still exists in the source document, the link has not been corrupted or the source document has not been deleted, moved, or renamed."
+ IDPMTFormat "The contents of the Clipboard have changed and the format you selected is no longer available. Use the Clipboard Viewer to see what is currently there."
+ IDPMTStatic "This is not an embedded or linked object. You cannot activate it."
+
+ /* only from OLEQueryReleaseError(): */
+ IDPMTFailedToReadObject "Failed to read object."
+ IDPMTGetFromClipboardFailed "Failed to paste object. Possibly there is not enough memory to complete this operation.\n\nQuit one or more applications to increase available memory, and then try again."
+ IDPMTImproperLinkOptionsError "Failed to change link update options."
+
+ IDPMTDeleteOpenEmb "This selection contains open embedded objects that will be deleted."
+ IDPMTCutOpenEmb "This selection contains open embedded objects that will be closed."
+ IDPMTSaveOpenEmb "This document contains open embedded objects that may need updating.\n\nDo you want to update open embedded objects before saving?"
+ IDPMTExitOpenEmb "This document contains open embedded objects that may need updating.\n\nDo you want to update open embedded objects before closing?"
+ IDPMTInsertOpenEmb "You are inserting over a selection that contains open embedded objects.\n\nClose the open embedded objects by quitting the server application, and then try again."
+#endif
+
+/* Dialog field errors */
+
+IDPMTNoPage,"No such page."
+IDPMTNOTNUM,"Not a valid number."
+IDPMTBFS,"You can only specify a font size between 4 and 127 points."
+IDPMTNPI,"You can only specify a whole number between 1 and 32767."
+IDPMTNOTDXA,"Measurement not in expected range.\n\nPlease enter a valid positive number."
+IDPMTNPDXA,"Measurement must be a number larger than zero."
+IDPMTMTL,"The margin values are too large and don't fit the dimensions of the page.\n\nEnter a smaller number to decrease the margins."
+
+IDPMTBadMove,"Cannot move text to that position."
+IDPMTDFULL,"Not enough disk space to complete this operation.\n\nDelete one or more files to increase available disk space and then try again."
+IDPMTPRFAIL, "Not enough memory to repaginate or print this document.\n\nQuit one or more applications to increase available memory, and then try again."
+IDPMTClipLarge,"Not enough memory to increase the contents of the Clipboard.\n\nEither quit one or more applications to free up memory or copy information to the Clipboard in smaller pieces."
+IDPMTClipQuest,"There is not enough memory available for the contents of the Clipboard.\n\nQuit one or more applications to increase available memory, and then try again."
+IDPMTCantPrint, "Cannot print.\n\nBe sure that your printer is connected properly, and use the Printers option in Control Panel to verify that the printer is configured properly."
+IDPMTRenameFail, "%s\nCannot rename this file.\n\nEither something has happened to the network or possibly the file has been renamed or moved."
+IDPMTPrPictErr, "Cannot print picture. Picture will be ignored."
+IDPMTPrDiskErr, "Not enough disk space to print this document.\n\nDelete one or more files to increase available disk space, and then try again."
+
+
+/***** FOLLOWING MESSAGES ARE "<hand>" LEVEL MESSAGES */
+
+IDPMTSDE,"Cannot operate on file.\n\nMake sure the file or disk is not damaged or write-protected."
+IDPMTNoMemory,"Not enough memory to complete this operation.\n\nSave your document to increase available memory."
+IDPMTWinFailure, "Low on memory.\n\nQuit one or more applications to increase available memory, and then try again."
+IDPMTSDE2,"Cannot save file.\n\nMake sure that the file or disk is not damaged."
+
+/***** FOLLOWING MESSAGES ARE EX-GLOBDEFS.H MESSAGES */
+/***** Win 3.0. This has been moved here to make localization easier */
+
+IDSTRModeDef, "Page 1" /* buffer for "Page nnn" message */
+
+IDSTRWriteDocPromptDef , "Write Document" /* OpenFile prompts */
+IDSTRScratchFilePromptDef , "Write Program"
+IDSTRSaveFilePromptDef , "Write Save"
+IDSTRAppNameDef , "Write" /* For message box headings */
+IDSTRUntitledDef , "(Untitled)" /* Unnamed doc */
+
+IDSTRiCountryDefaultDef, "001" /* default country is USA */
+ /* see msdos manual for meaning of codes */
+
+ /* used in clipdisp.c */
+IDSTRWRITETextDef , "WRITE Formatted Text"
+
+ /* used in cmd.c */
+IDSTRFreeDef, " words"
+
+ /* used in menu.c */
+IDSTRAltBSDef, " \tCtrl+Z"
+
+ /* used in initwin.c */
+IDSTRNoneDef, "None"
+
+ /* used in running.c */
+IDSTRHeaderDef , "HEADER"
+IDSTRFooterDef , "FOOTER"
+
+ /* used in trans.c */
+IDSTRLoadFileDef, "Loading file..."
+IDSTRCvtLoadFileDef, "Converting and loading file..."
+
+ /* used in util2.c abbreviations for units */
+IDSTRInchDef, """"
+IDSTRCmDef, " cm"
+IDSTRP10Def, " p10"
+IDSTRP12Def, " p12"
+IDSTRPointDef, " pt"
+IDSTRLineDef, " li"
+
+
+END
+
+
+/* Windows Write accelerator table */
+
+/* WARNING: The Accelerator table is duplicated in a switch statement in
+cmd.c. If the accelerator table is changed, the switch statement must
+be changed */
+mw_acctb ACCELERATORS
+BEGIN
+#ifndef NOHELP
+ VK_F1, imiHelp, VIRTKEY
+#endif
+ VK_F2, imiCopy, VIRTKEY
+ VK_F3, imiFindAgain, VIRTKEY
+ VK_F4, imiGoTo, VIRTKEY
+ VK_F5, imiCharNormal, VIRTKEY
+ VK_F6, imiBold, VIRTKEY
+ VK_F7, imiItalic, VIRTKEY
+ VK_F8, imiUnderline, VIRTKEY
+ "^B", imiBold
+ "^I", imiItalic
+ "^U", imiUnderline
+ "^Z", imiUndo
+ "^X", imiCut
+ "^C", imiCopy
+ "^V", imiPaste
+END
+
+/* Windows Write Command Menu */
+
+mw_menu MENU
+ begin
+ popup "&File"
+ begin
+ menuitem "&New", imiNew
+ menuitem "&Open...", imiOpen
+ menuitem "&Save", imiSave
+ menuitem "Save &As...", imiSaveAs
+ menuitem SEPARATOR
+ menuitem "&Print...", imiPrint
+ menuitem "P&rint Setup...", imiPrintSetup
+ menuitem "R&epaginate...", imiRepaginate
+ menuitem SEPARATOR
+ menuitem "E&xit", imiQuit
+ end
+
+ popup "&Edit"
+ begin
+
+ menuitem "&Undo\tCtrl+Z", imiUndo
+ menuitem SEPARATOR
+ menuitem "Cu&t\tCtrl+X", imiCut
+ menuitem "&Copy\tCtrl+C", imiCopy
+ menuitem "&Paste\tCtrl+V", imiPaste
+#if defined(OLE)
+ menuitem "Paste Sp&ecial...", imiPasteSpecial
+#if !defined(SMALL_OLE_UI)
+ menuitem "Paste &Link", imiPasteLink
+#endif
+ MENUITEM SEPARATOR
+#if !defined(SMALL_OLE_UI)
+ MENUITEM "Lin&ks...", imiProperties
+#endif
+ MENUITEM "&Object...", imiVerb
+ MENUITEM "&Insert Object...", imiInsertNew
+#endif
+ menuitem SEPARATOR
+ menuitem "&Move Picture", imiMovePicture
+ menuitem "&Size Picture", imiSizePicture
+ end
+
+ popup "Fi&nd"
+ begin
+ menuitem "&Find...", imiFind
+ menuitem "Repeat &Last Find\tF3", imiFindAgain
+ menuitem "R&eplace...", imiChange
+ menuitem SEPARATOR
+ menuitem "&Go To Page...\tF4", imiGoTo
+ end
+
+ popup "&Character"
+ begin
+ menuitem "Re&gular\tF5", imiCharNormal
+ menuitem SEPARATOR
+ menuitem "&Bold\tCtrl+B", imiBold
+ menuitem "&Italic\tCtrl+I", imiItalic
+ menuitem "&Underline\tCtrl+U", imiUnderline
+ menuitem "Su&perscript", imiSuper
+ menuitem "Subs&cript", imiSub
+ menuitem SEPARATOR
+ menuitem "&Reduce Font", imiSmFont
+ menuitem "&Enlarge Font", imiLgFont
+ menuitem SEPARATOR
+ menuitem "&Fonts...", imiCharFormats
+ end
+
+ popup "&Paragraph"
+ begin
+ menuitem "&Normal", imiParaNormal
+ menuitem SEPARATOR
+ menuitem "&Left", imiLeft
+ menuitem "&Centered", imiCenter
+ menuitem "&Right", imiRight
+ menuitem "&Justified", imiJustified
+ menuitem SEPARATOR
+ menuitem "&Single Space", imiSingleSpace
+ menuitem "&1 1/2 Space", imiOneandhalfSpace
+ menuitem "&Double Space", imiDoubleSpace
+ menuitem SEPARATOR
+ menuitem "&Indents...", imiParaFormats
+ end
+
+ popup "&Document"
+ begin
+ menuitem "&Header...", imiHeader
+ menuitem "&Footer...", imiFooter
+ menuitem SEPARATOR
+ menuitem "&Ruler On", imiShowRuler
+ menuitem "&Tabs...", imiTabs
+ menuitem SEPARATOR
+ menuitem "&Page Layout...", imiDivFormats
+ end
+
+#ifndef NOHELP
+ popup "&Help"
+ begin
+ menuitem "&Contents", imiIndex
+ menuitem "&Search for Help on...", imiHelpSearch
+ menuitem "&How to Use Help", imiUsingHelp
+ menuitem SEPARATOR
+ menuitem "&About Write...", imiAbout
+ end
+#else
+ popup "&Info"
+ begin
+ menuitem "&About Write...", imiAbout
+ end
+#endif /*NOHELP*/
+ end
+
+rcinclude write.dlg
+#if defined(OLE)
+rcinclude ole.dlg /* OLE */
+#endif
diff --git a/private/mvdm/wow16/write/messages/usa/write.rcv b/private/mvdm/wow16/write/messages/usa/write.rcv
new file mode 100644
index 000000000..ed7bb6733
--- /dev/null
+++ b/private/mvdm/wow16/write/messages/usa/write.rcv
@@ -0,0 +1,17 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1995 Microsoft Corporation */
+/************************************************************/
+
+/********************************************************************/
+/* WRITE.RCV */
+/* Version control data generated from layouts.dat */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Windows Write application file"
+#define VER_INTERNALNAME_STR "write"
+#define VER_ORIGINALFILENAME_STR "WRITE.EXE"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/write/mglobals.c b/private/mvdm/wow16/write/mglobals.c
new file mode 100644
index 000000000..e6cbff3af
--- /dev/null
+++ b/private/mvdm/wow16/write/mglobals.c
@@ -0,0 +1,817 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* WRITE Globals */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "fmtdefs.h" /* formatdefs.h */
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "printdef.h" /* printdefs.h */
+#include "wwdefs.h"
+#include "prmdefs.h"
+#include "rulerdef.h"
+#include "editdefs.h"
+#define NOSTRERRORS
+#include "str.h"
+#include "fontdefs.h"
+#include "globdefs.h" /* text for static strings */
+
+VAL rgval [ivalMax]; /* General purpose parm-passing array */
+#ifdef ENABLE
+VAL rgvalAgain[ivalMax];
+#endif
+
+CHAR vchDecimal = '?'; /* "decimal point" character
+ real value set in initwin.c */
+
+int vzaTabDflt = vzaTabDfltDef; /* width of default tab in twips */
+
+/* pen windows */
+VOID (FAR PASCAL *lpfnRegisterPenApp)(WORD, BOOL) = NULL;
+
+/* page buffers stuff */
+CHAR *rgibpHash;
+int iibpHashMax;
+struct BPS *mpibpbps;
+int ibpMax;
+int ibpMaxFloat = 128;
+typeTS tsMruBps;
+CHAR (*rgbp)[cbSector];
+struct ERFN dnrfn[rfnMax];
+int rfnMac;
+typeTS tsMruRfn;
+int vfBuffersDirty = FALSE;
+
+/* doc stuff */
+struct DOD (**hpdocdod)[];
+int docCur; /* current doc */
+int docMac;
+int docScrap;
+#ifdef CASHMERE /* No docBuffer in WRITE */
+int docBuffer;
+#endif
+int docUndo;
+
+#if defined(JAPAN) & defined(DBCS_IME) /* Doc for Insert IR_STRING from IME [yutakan]*/
+int docIRString;
+#endif
+
+int docRulerSprm;
+int docMode = docNil; /* doc with "Page nnn" message */
+int vpgn; /* current page number of document */
+typeCP cpMinCur;
+typeCP cpMacCur;
+
+/* file stuff */
+struct FCB (**hpfnfcb)[];
+int fnMac;
+int ferror;
+int errIO; /* i/o error code */
+int versFile = 0;
+int vrefFile = 0;
+int vrefSystem = 0;
+
+#ifdef DBCS_VERT
+CHAR szAtSystem [] = szAtSystemDef; // for vertical-sysfont
+#endif
+
+WORD vwDosVersion; /* Current DOS version, maj in lo 8, minor in hi */
+int vfInitializing = TRUE; /* TRUE during inz, FALSE thereafter */
+int vfDiskFull = FALSE; /* Disk full error, fn != fnScratch */
+int vfSysFull = FALSE; /* Disk holding fnScratch is full */
+int vfDiskError = FALSE; /* Serious Disk Error has occurred */
+int vfLargeSys = FALSE;
+int vfMemMsgReported = FALSE;
+int vfCloseFilesInDialog = FALSE; /* Set inside OPEN, SAVE dialog */
+int vfSizeMode;
+int vfPictSel;
+int vfPMS = FALSE; /* Currently doing picture move/size */
+int vfnWriting = fnNil; /* fn that gets written to disk */
+int vfnSaving = fnNil; /* Like above, but longer lifetime */
+int vibpWriting;
+CHAR (**vhrgbSave)[]; /* emergency space for save events */
+struct FPRM fprmCache; /* scratch file property modifiers */
+
+/* global boolean flags */
+int vfTextOnlySave = FALSE; /* reset by each new/open, use by save as */
+int vfBackupSave; /* use by save as box */
+int vfOutOfMemory = FALSE;
+int vfOvertype = FALSE; /* still using this ? */
+int vfPrintMode = FALSE; /* TRUE if format to printer mode on screen */
+int vfDraftMode = FALSE; /* TRUE if the user choose the draft mode option */
+int vfRepageConfirm = FALSE; /* repaginate confirm page break option */
+int vfVisiMode = FALSE; /* TRUE if visible char mode on */
+int vfModeIsFootnote; /* TRUE when szMode contains string "Footnote" */
+int vfNoIdle = FALSE;
+int vfDeactByOtherApp = FALSE; /* TRUE if we are deactivated by another app */
+int vfDownClick = FALSE; /* TRUE when we received a down click in our window */
+int vfCursorVisible = FALSE; /* TRUE if want to show the cursor in a mouseless
+ system */
+int vfMouseExist = FALSE; /* TRUE if mouse hardware is installed */
+int vfInLongOperation = FALSE; /* TRUE if we are still in a long operation
+ so that the cursor should stay hourglass */
+int vfScrapIsPic = FALSE; /* Whether docScrap contains picture */
+BOOL fDestroyOK;
+
+int fGrayChar; /* TRUE if selection consists of mixed char properties */
+int fGrayPara; /* TRUE if selection consists of mixed para properties */
+
+int vfPrPages = FALSE; /* TRUE if print page range */
+int vpgnBegin; /* starting page number to print */
+int vpgnEnd; /* ending page number to print */
+int vcCopies = 1; /* nubmer of copies to print */
+BOOL vfPrErr = FALSE; /* TRUE iff a printing error occurred */
+BOOL vfPrDefault = TRUE; /* TRUE iff Write chose printer */
+BOOL vfWarnMargins = FALSE; /* TRUE if we should warn user about bad margins */
+
+/* Show that Print, Help, and Glossary processing is uninitialized */
+int vfPrintIsInit = FALSE;
+int vfHelpIsInit = FALSE;
+int vfGlyIsInit = FALSE;
+
+int vfInsEnd = false; /* Is insert point at end-of-line? */
+int vfInsertOn;
+int vfMakeInsEnd;
+int vfSelAtPara;
+int vfSeeSel = FALSE;
+int vfLastCursor; /* TRUE iff the last selection was made
+ by an Up/Down cursor key */
+int vfGotoKeyMode = FALSE; /* Apply GOTO meta mode to next cursor
+ key */
+#ifdef SAND
+int vftcDaisyPS = -1;
+int vftcDaisyNoPS = -1;
+int vfDaisyWheel = FALSE;
+int vifntApplication;
+int vifntMac;
+#endif /* SAND */
+
+#ifdef UNUSED
+int vfCanPrint;
+#endif
+
+int vchInch;
+int vfMouse;
+typeCP vcpSelect;
+
+#ifdef DEBUG
+int fIbpCheck = TRUE;
+int fPctbCheck = TRUE;
+#ifdef CKSM
+unsigned (**hpibpcksm) []; /* Checksums for buffer page contents */
+unsigned ibpCksmMax; /* Alloc limit for cksm array */
+#endif
+#endif /* DEBUG */
+
+int vWordFmtMode = FALSE; /* used during saves. If false, no conversion is
+ done. True is convert to Word format,CVTFROMWORD
+ is translate chars from Word character set at
+ save */
+
+/* **************************************************************** */
+/* strings, predefined file names - definitions stored in globdefs.h */
+/* */
+/* NOTE NOTE NOTE Win 3.0 */
+/* */
+/* Some of these strings have now been moved from globdefs.h */
+/* to write.rc. This was done to easy localization. */
+/* */
+/* **************************************************************** */
+
+CHAR (**hszTemp)[];
+CHAR (**hszGlosFile)[];
+CHAR (**hszXfOptions)[];
+CHAR szMode[30]; /* buffer for "Page nnn" message */
+
+CHAR szEmpty[] = "";
+CHAR szExtDoc[] = szExtDocDef;
+CHAR szExtWordDoc[] = szExtWordDocDef;
+CHAR szExtGls[] = szExtGlsDef;
+CHAR szExtDrv[] = szExtDrvDef;
+ /* for Intl added szExtWordDoc entry */
+CHAR *mpdtyszExt [] = { szExtDoc, szExtGls, szEmpty, szEmpty,
+ szEmpty, szEmpty,
+ szExtWordDoc };
+CHAR szExtBackup[] = szExtBackupDef;
+CHAR szExtWordBak[] = szExtWordBakDef;
+ /* WIN.INI: our app entry */
+CHAR szWriteProduct[] = szWriteProductDef;
+CHAR szFontEntry[] = szFontEntryDef; /* WIN.INI: our font list */
+CHAR szWriteDocPrompt[25]; /* OpenFile prompts */
+CHAR szScratchFilePrompt[25];
+CHAR szSaveFilePrompt[25];
+CHAR szAppName[10]; /* For message box headings */
+CHAR szUntitled[20]; /* Unnamed doc */
+CHAR szSepName[] = szSepNameDef; /* separator between product
+ name and file name in header */
+
+#ifdef STYLES
+CHAR szSshtEmpty[] = szSshtEmptyDef;
+#endif /* STYLES */
+
+/* Strings for parsing the user profile. */
+CHAR szWindows[] = szWindowsDef;
+CHAR szDevice[] = szDeviceDef;
+CHAR szDevices[] = szDevicesDef;
+CHAR szBackup[] = szBackupDef;
+
+/* Strings for our window classes (MUST BE < 39 CHARS) */
+
+CHAR szParentClass[] = szParentClassDef;
+CHAR szDocClass[] = szDocClassDef;
+CHAR szRulerClass[] = szRulerClassDef;
+CHAR szPageInfoClass[] = szPageInfoClassDef;
+#ifdef ONLINEHELP
+CHAR szHelpDocClass[] = szHelpDocClassDef;
+#endif
+
+CHAR szWRITEText[30];
+CHAR szFree[15];
+CHAR szMWTemp [] = szMWTempDef;
+CHAR szSystem [] = szSystemDef;
+
+CHAR szMw_acctb[] = szMw_acctbDef;
+CHAR szNullPort[] = szNullPortDef;
+CHAR szNone[15];
+CHAR szMwlores[] = szMwloresDef;
+CHAR szMwhires[] = szMwhiresDef;
+CHAR szMw_icon[] = szMw_iconDef;
+CHAR szMw_menu[] = szMw_menuDef;
+CHAR szScrollBar[] = szScrollBarDef;
+CHAR szAltBS[20];
+CHAR szPmsCur[] = szPmsCurDef;
+CHAR szHeader[15];
+CHAR szFooter[15];
+
+CHAR szModern[] = szModernDef;
+CHAR szRoman[] = szRomanDef;
+CHAR szSwiss[] = szSwissDef;
+CHAR szScript[] = szScriptDef;
+CHAR szDecorative[] = szDecorativeDef;
+
+CHAR szExtSearch[] = szExtSearchDef; /* store default search spec */
+CHAR szLoadFile[25];
+CHAR szCvtLoadFile[45];
+
+CHAR szIntl[] = szIntlDef;
+CHAR szsDecimal[] = szsDecimalDef;
+CHAR szsDecimalDefault[] = szsDecimalDefaultDef;
+CHAR sziCountry[] = sziCountryDef;
+CHAR sziCountryDefault[5];
+
+/* table of unit names from util2.c - Must agree with cmddefs.h */
+CHAR *mputsz[utMax] =
+ {
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ };
+
+
+/* For convenience, we reserves Mac's st concept, the difference is that
+cch stored in the first byte of the array includes the '\0' so that we
+can use it as a sz by chopping the 1st byte */
+CHAR stBuf[256];
+
+CHAR szCaptionSave[cchMaxFile]; /* save the caption text */
+/* insert stuff */
+CHAR rgchInsert[cchInsBlock]; /* temporary insert buffer */
+typeCP cpInsert; /* beginning cp of insert block */
+int ichInsert; /* number of chars used in rgchInsert */
+typeFC fcMacPapIns = fc0;
+typeFC fcMacChpIns = fc0;
+struct FKPD vfkpdCharIns;
+struct FKPD vfkpdParaIns;
+int vdlIns; /* Display line for current insert */
+int vcchBlted=0; /* # of chars blted onto vdlIns */
+int vidxpInsertCache=-1; /* Current position in vfli.rgdxp
+ during fast insert */
+int vfInsFontTooTall; /* Ins chr will be too tall for line */
+struct EDL *vpedlAdjustCp;
+int vfSuperIns; /* whether in super-fast insert mode */
+typeCP cpInsLastInval;
+int vdypCursLineIns;
+int vdypBase;
+int vdypAfter;
+int vxpIns;
+int vxpMacIns;
+int vypBaseIns;
+int vfTextBltValid;
+typeCP cpWall = cp0;
+int vfInsLast;
+
+/* Keyboard shift/lock flags */
+int vfShiftKey = FALSE; /* whether Shift is down */
+int vfCommandKey = FALSE; /* whether Ctrl key is down */
+int vfOptionKey = FALSE; /* whether Alt key is down */
+
+/* cache stuff */
+CHAR *vpchFetch;
+CHAR (**hgchExpand)[];
+int vichFetch;
+int vdocFetch;
+int vccpFetch;
+int vcchFetch;
+int visedCache;
+int vdocExpFetch;
+int vdocParaCache = docNil;
+int vdocPageCache;
+int vdocSectCache;
+typeCP vcpFetch;
+typeCP vcpFirstParaCache;
+typeCP vcpLimParaCache;
+typeCP vcpMinPageCache;
+typeCP vcpMacPageCache;
+typeCP vcpLimSectCache;
+typeCP vcpFirstSectCache;
+
+/* cache stuff for display purpose */
+int ctrCache = 0;
+int itrFirstCache = 0;
+int itrLimCache = itrMaxCache;
+int dcpCache = 0;
+typeCP cpCacheHint = cp0;
+
+/* The picture bitmap cache */
+
+int vdocBitmapCache = docNil;
+typeCP vcpBitmapCache;
+HBITMAP vhbmBitmapCache = NULL;
+BOOL vfBMBitmapCache;
+
+/* style property stuff */
+int ichpMacFormat;
+struct CHP vchpNormal;
+struct CHP vchpAbs;
+struct CHP vchpInsert;
+struct CHP vchpFetch;
+struct CHP vchpSel; /* Holds the props when the selection is
+ an insert point */
+struct CHP *pchpDefault;
+struct CHP (**vhgchpFormat)[];
+struct PAP vpapPrevIns;
+struct PAP vpapAbs;
+struct PAP *vppapNormal;
+struct SEP vsepNormal;
+struct SEP vsepAbs;
+struct SEP vsepStd;
+struct SEP vsepPage;
+
+#define ESPRM(cch, sgc, spr, fSame, fClobber) \
+ (cch + (ESPRM_sgcMult * sgc) + (ESPRM_spr * spr) + \
+ (ESPRM_fSame * fSame) + (ESPRM_fClobber * fClobber))
+
+/* ESPRM fields are:
+ cch 2 bits of length, 0 means determined by procedure
+ sgc 2 bits of group: char, para, or running head
+ spr 1 bit priority, fClobber sprms clobber sprms in same group with
+ priority less than or equal
+ fSame means overrides previous instance of same sprm
+ fClobber see spr
+*/
+
+#define ESPRMChar ESPRM(2,0,0,1,0)
+#define ESPRMPara ESPRM(2,1,1,1,0)
+#define ESPRMParaLong ESPRM(3,1,1,1,0)
+
+/* This table corresponds to sprm's in prmdefs.h */
+CHAR dnsprm[sprmMax] = {
+/* 0 */ 0, /* */
+ ESPRMParaLong, /* PLMarg */
+/* 2 */ ESPRMParaLong, /* PRMarg */
+ ESPRMParaLong, /* PFIndent */
+/* 4 */ ESPRMPara, /* PJc */
+ ESPRM(1,1,1,1,0), /* Ruler */
+/* 6 */ ESPRM(0,1,1,1,0), /* Ruler1 */
+ ESPRMPara, /* PKeep */
+/* 8 */ ESPRM(2,1,1,1,1), /* PNormal (formerly Pstyle) */
+ ESPRM(2,2,0,1,0), /* PRhc running head code */
+/* 10 */ ESPRM(0,1,0,1,1), /* PSame, clobbers all tabs but related ones */
+ ESPRMParaLong, /* PDyaLine */
+/* 12 */ ESPRMParaLong, /* PDyaBefore */
+ ESPRMParaLong, /* PDyaAfter */
+/* 14 */ ESPRM(1,1,1,0,0), /* PNest */
+ ESPRM(1,1,1,0,0), /* PUnNest */
+/* 16 */ ESPRM(1,1,1,0,0), /* PHang - hanging indent */
+ ESPRM(0,1,1,1,0), /* PRgtbd */
+/* 18 */ ESPRMPara, /* PKeepFollow */
+ ESPRM(1,1,0,1,1), /* PCAll - NUSED */
+/* 20 */ ESPRMChar, /* CBold */
+ ESPRMChar, /* CItalic */
+/* 22 */ ESPRMChar, /* CUline */
+ ESPRMChar, /* CPos */
+/* 24 */ ESPRMChar, /* CFtc */
+ ESPRMChar, /* CHps */
+/* 26 */ ESPRM(0,0,0,1,1), /* CSame */
+ ESPRMChar, /* CChgFtc */
+/* 28 */ ESPRMChar, /* CChgHps */
+ ESPRM(2,0,0,1,0), /* CPlain */
+/* 30 */ ESPRMChar, /* CShadow */
+ ESPRMChar, /* COutline */
+/* 32 */ ESPRMChar, /* CCsm - case modification. */
+
+ /* The following sprms are unused as of 10/10/84: */
+ ESPRMChar, /* CStrike */
+/* 34 */ ESPRMChar, /* DLine - ? */
+ ESPRMChar, /* CPitch - obs. */
+/* 36 */ ESPRMPara, /* COverset */
+ ESPRM(2,0,0,1,1), /* CStc Style */
+ /* The preceding sprms are unused as of 10/10/84: */
+
+/* 38 */ ESPRM(0,0,0,0,0), /* CMapFtc */
+ ESPRM(0,0,0,0,0), /* COldFtc */
+/* 40 */ ESPRM(0,1,1,1,0) /* PRhcNorm -- cch is 4 */
+};
+
+/* ruler stuff */
+int mprmkdxa[rmkMARGMAX]; /* stores dxa of indents on ruler */
+int rgxaRulerSprm[3];
+
+/* This is a global parameter to AdjustCp; if FALSE, no invalidation will
+take place. */
+BOOL vfInvalid = TRUE; /* if FALSE, no invalidation will take place
+ in AdjustCp */
+
+int viDigits = 2;
+BOOL vbLZero = FALSE;
+int utCur = utDefault; /* may be inch or cm depending on value
+ in globdefs.h */
+
+short itxbMac;
+struct TXB (**hgtxb)[];
+struct UAB vuab;
+
+/* search stuff */
+CHAR (**hszFlatSearch)[];
+CHAR (**hszSearch)[];
+CHAR (**hszReplace)[];
+CHAR (**hszRealReplace)[]; /* used for building replacement text */
+CHAR (**hszCaseReplace)[]; /* used for building replacement text with
+ appropriate capitalization. */
+CHAR *szSearch;
+BOOL fReplConfirm = TRUE;
+BOOL fSearchCase = FALSE;
+BOOL fSearchWord = FALSE;
+BOOL fSpecialMatch;
+BOOL fMatchedWhite = FALSE;
+BOOL fParaReplace = FALSE;
+/*BOOL fSearchForward = TRUE;*/
+typeCP cpMatchLim;
+int vfDidSearch = FALSE;
+
+/* Strings for printer selection */
+CHAR (**hszPrinter)[]; /* name of the current printer */
+CHAR (**hszPrDriver)[]; /* name of the current printer driver */
+CHAR (**hszPrPort)[]; /* name of the current printer port */
+CHAR szNul[cchMaxIDSTR]; /* name of the null device */
+BOOL vfPrinterValid = TRUE; /* FALSE iff the above strings do not
+ describe the printer DC */
+
+/* global dxa/dya stuff */
+int vdxaPaper;
+int vdyaPaper;
+int vdxaTextRuler; /* from section props used to calculate right margin */
+
+int dxpLogInch;
+int dypLogInch;
+int dxpLogCm;
+int dypLogCm;
+int dxaPrPage;
+int dyaPrPage;
+int dxpPrPage;
+int dypPrPage;
+int ypSubSuperPr;
+
+#ifdef KINTL
+int dxaAdjustPerCm; /* The amount of kick-back to be added to xa per cm in
+ XaQuantize() to offset a round-off error. */
+#endif /* ifdef KINTL */
+
+/* actual position of the cursor line */
+int vxpCursLine;
+int vypCursLine;
+int vdypCursLine;
+int vfScrollInval; /* means scroll did not take and UpdateWw must be repeated */
+
+/* selection stuff */
+int vfSelHidden = FALSE;
+struct SEL selCur; /* current selection (i.e. sel in current ww) */
+
+/* window stuff */
+struct WWD rgwwd[wwMax];
+int wwMac = 0;
+int wwCur = wwNil;
+#ifdef ONLINEHELP
+int wwHelp=wwNil; /* Help Window */
+#endif
+int wwClipboard=wwNil; /* Clipboard Display Window */
+struct WWD *pwwdCur = &rgwwd[0]; /* current window descriptor */
+int vipgd = -1; /* page number displayed in lower corner */
+int xpAlpha;
+int ypAlpha;
+RECT rectParent;
+struct FLI vfli =
+ {
+ cp0, 0, cp0, 0, 0, 0, FALSE, 0, 0, 0, 0, 0, 0, 0,
+ FALSE, FALSE, 0, 0, 0, 0, 0, FALSE, 0, 0,
+ /* rgdxp */
+ 0x0000, 0xFFFE, 0xffff, 0xffff, 0xe0ff, 0xff3f, 0x00ff, 0xff07,
+ 0x00fe, 0xff03, 0x00f8, 0xff00, 0x0ff0, 0x7f80, 0x3fe0, 0x3fe0,
+ 0x7fc0, 0x1ff0, 0xffc0, 0x1ff8, 0xff81, 0x0ffc, 0xff83, 0x0ffe,
+ 0xff87, 0x0fff, 0x8f07, 0x071f, 0x060f, 0x870f, 0x060f, 0x870f,
+ 0x8f0f, 0x871f, 0xff0f, 0x87ff, 0xff0f, 0x87ff, 0xff0f, 0x87ff,
+ 0x1f0f, 0x878f, 0x0f0f, 0x870f, 0x0007, 0x070f, 0x8087, 0x0f1f,
+ 0xe083, 0x0f7e, 0xff81, 0x0ffc, 0xffc0, 0x1ff8, 0x7fc0, 0x1ff0,
+ 0x1fe0, 0x3fc0, 0x00f0, 0x7f00, 0x00fc, 0xff01, 0x00fe, 0xff03,
+ 0xe0ff, 0xff3f, 0x8BEC, 0xFC46, 0xF8D1, 0x4689, 0x2BEA, 0x8BFF,
+ 0xEBF7, 0xFF55, 0x0A76, 0x468B, 0x2BEC, 0x50C6, 0x8B57, 0x085E,
+ 0x5FFF, 0xFF08, 0x0A76, 0x8B56, 0xEA46, 0xC703, 0x8B50, 0x085E,
+ 0x5FFF, 0xFF0C, 0x0A76, 0x468B, 0x03EC, 0x50C6, 0x8B57, 0x085E,
+ 0x5FFF, 0xFF08, 0x0A76, 0x468B, 0x2BFA, 0x50C6, 0x468B, 0x03EA,
+ 0x50C7, 0x5E8B, 0xFF08, 0x0C5F, 0x468B, 0xB1FA, 0xD306, 0x03F8,
+ 0x8BF0, 0xFC46, 0xF8D3, 0xF803, 0x7639, 0x7DEC, 0x5EA6, 0x835F,
+ 0x02ED, 0xE58B, 0x5D1F, 0xCA4D, 0x0008, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* rgch */
+ 0x11, 0x30, 0x5c, 0x71, 0x84, 0x75, 0x83, 0x84,
+ 0x30, 0x72, 0x89, 0x30, 0x60, 0x71, 0x85, 0x7c,
+ 0x64, 0x30, 0x7A, 0x7D, 0x77, 0x7C, 0x64, 0x60,
+ 0x33, 0x44, 0x61, 0x7A, 0x67, 0x76, 0x33, 0x7B,
+ 0x72, 0x60, 0x33, 0x71, 0x76, 0x76, 0x7D, 0x33,
+ 0x71, 0x61, 0x7C, 0x66, 0x74, 0x7B, 0x67, 0x33,
+ 0x67, 0x7C, 0x33, 0x6A, 0x7C, 0x66, 0x33, 0x71,
+ 0x6A, 0x33, 0x51, 0x7C, 0x71, 0x3F, 0x33, 0x51,
+ 0x7C, 0x71, 0x3F, 0x33, 0x51, 0x61, 0x6A, 0x72,
+ 0x7D, 0x3F, 0x33, 0x50, 0x7B, 0x7A, 0x3E, 0x50,
+ 0x7B, 0x66, 0x76, 0x7D, 0x3F, 0x33, 0x72, 0x7D,
+ 0x77, 0x33, 0x43, 0x72, 0x67, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+/* Screen dependent measurements */
+int DxaPerPix; /* number of twips per xp */
+int DyaPerPix; /* number of twips per yp */
+
+int xpInch; /* number of xp's per inch */
+int xpMaxUser;
+int xpSelBar; /* width of the selection bar in xp's */
+
+int dxpScrlBar; /* width of the scroll bar in xp's */
+int dypScrlBar; /* height of the scroll bar in xp's */
+int dxpInfoSize; /* width of the page info area */
+
+int xpRightMax;
+int xpMinScroll;
+int xpRightLim;
+
+int ypMaxWwInit;
+int ypMaxAll;
+
+int dypMax;
+int dypAveInit;
+int dypWwInit;
+int dypBand;
+int dypRuler = 0;
+int dypSplitLine;
+int ypSubSuper; /* adjustment from base line for sub/super */
+
+/* idstr stuff */
+int idstrCurrentUndo = IDSTRUndoBase;
+
+/* the following two may eventually be deleted -- check usage in ruler.c */
+int vfTabsChanged = FALSE; /* TRUE if any tabs are changed from the ruler */
+int vfMargChanged = FALSE; /* TRUE if any indents are changed from the ruler */
+
+#ifdef CASHMERE
+struct TBD rgtbdRulerSprm[itbdMax];
+#endif /* CASHMERE */
+
+#ifdef RULERALSO
+BOOL vfDisableMenus = FALSE;/* TRUE if top level menus (including
+ the system menu are to be disabled */
+int vfTempRuler; /* TRUE if ruler is created because of dialog box creation */
+HWND vhDlgTab = (HWND)NULL;
+HWND vhDlgIndent = (HWND)NULL;
+struct TBD rgtbdRuler[itbdMax];
+#endif /* RULERALSO */
+
+int flashID = 0; /* timer ID for flashing before we put up a messagebox when we are not the active app */
+
+
+
+/*-----------------------------------------------------*/
+/* Merged MGLOBALS.C and MGLOBALS2.C ..pault 10/26/89 */
+/*-----------------------------------------------------*/
+
+
+/* internal memory stuff */
+int *memory; /* ptr to beginning of free space, get incremented after
+ allocating chunks from memory */
+#ifdef OURHEAP
+int *pmemMax;/* ptr to max of memory */
+CHAR * pmemStart; /* point to start of memory after global data */
+unsigned vcbMemTotal; /* total number of free memory bytes */
+unsigned cbTotQuotient;/* for calculating % of free space */
+unsigned cbTot; /* for calculating % of free space */
+#endif
+unsigned cwHeapFree; /* number of free heap space in words */
+
+/* MS-WINDOWS related variables */
+
+HWND hParentWw = NULL; /* handle to parent ww (created in
+ interface module) */
+HANDLE hMmwModInstance = NULL; /* handle to memory module instance */
+HANDLE vhReservedSpace; /* space reserved for control manger */
+long rgbBkgrnd = -1L; /* rgb color of the background */
+long rgbText = -1L; /* rgb color of the text */
+HBRUSH hbrBkgrnd = NULL; /* handle to background brush */
+long ropErase = WHITENESS; /* raster op to erase the screen */
+BOOL vfMonochrome = FALSE; /* TRUE iff display is monochrome */
+
+HMENU vhMenu = NULL; /* handle to top level menu */
+
+CHAR *vpDlgBuf; /* pointer to buffer for dialog boxes */
+
+#ifdef INEFFLOCKDOWN /* SEE NOTE IN FINITFARPROCS() */
+/* far pointers to dialog functions exported to WINDOWS */
+FARPROC lpDialogOpen;
+FARPROC lpDialogSaveAs;
+FARPROC lpDialogPrinterSetup;
+FARPROC lpDialogPrint;
+FARPROC lpDialogCancelPrint;
+FARPROC lpDialogRepaginate;
+FARPROC lpDialogSetPage;
+FARPROC lpDialogPageMark;
+FARPROC lpDialogHelp;
+
+#ifdef ONLINEHELP
+FARPROC lpDialogHelpInner;
+#endif /* ONLINEHELP */
+
+FARPROC lpDialogGoTo;
+FARPROC lpDialogFind;
+FARPROC lpDialogChange;
+FARPROC lpDialogCharFormats;
+FARPROC lpDialogParaFormats;
+FARPROC lpDialogRunningHead;
+FARPROC lpDialogTabs;
+FARPROC lpDialogDivision;
+FARPROC lpDialogAlert;
+FARPROC lpDialogConfirm;
+FARPROC lpFontFaceEnum;
+FARPROC lpFPrContinue;
+FARPROC lpDialogWordCvt;
+#endif /* ifdef INEFFLOCKDOWN */
+
+/* Mouse status flags and cursors */
+int vfDoubleClick = FALSE; /* whether click is double click */
+HCURSOR vhcHourGlass; /* handle to hour glass cursor */
+HCURSOR vhcIBeam; /* handle to i-beam cursor */
+HCURSOR vhcArrow; /* handle to arrow cursor */
+HCURSOR vhcBarCur; /* handle to back arrow cursor */
+
+#ifdef PENWIN // for PenWindows (5/21/91) patlam
+#include <penwin.h>
+HCURSOR vhcPen; /* handle to pen cursor */
+int (FAR PASCAL *lpfnProcessWriting)(HWND, LPRC) = NULL;
+VOID (FAR PASCAL *lpfnPostVirtualKeyEvent)(WORD, BOOL) = NULL;
+VOID (FAR PASCAL *lpfnTPtoDP)(LPPOINT, int) = NULL;
+BOOL (FAR PASCAL *lpfnCorrectWriting)(HWND, LPSTR, int, LPRC, DWORD, DWORD) = NULL;
+BOOL (FAR PASCAL *lpfnSymbolToCharacter)(LPSYV, int, LPSTR, LPINT) = NULL;
+#endif
+
+/* MS-WINDOWS stuff */
+HANDLE vhSysMenu;
+HDC vhMDC = NULL; /* memory DC compatible with the screen */
+int dxpbmMDC = 0; /* width of the bitmap attatched to vhMDC */
+int dypbmMDC = 0; /* height of the bitmap attatched to vhMDC */
+HBITMAP hbmNull; /* handle to an empty bitmap */
+HDC vhDCPrinter = NULL; /* DC for the printer */
+HWND vhWnd; /* handle to document window */
+HANDLE vhAccel; /* handle to menu key accelerator table */
+
+/* modeless dialog handles */
+HWND vhDlgRunningHead = (HWND)NULL;
+HWND vhDlgFind = (HWND)NULL;
+ /* handle to modeless Find dialog box */
+HWND vhDlgChange = (HWND)NULL;
+ /* handle to modeless Change dialog box */
+
+HWND vhWndRuler = (HWND)NULL;
+HWND vhWndCancelPrint = (HWND)NULL;
+ /* handle to modeless Cancel Print dialog box */
+#ifndef NOMORESIZEBOX
+HWND vhWndSizeBox; /* handle to the size box */
+#endif
+HWND vhWndPageInfo; /* handle to the page info window */
+HWND vhWndMsgBoxParent = (HWND)NULL; /* parent of the message box */
+
+int vfSkipNextBlink = FALSE;
+ /* skip next timed off-transition of caret */
+int vfFocus = FALSE; /* Whether we have the input focus */
+int vfOwnClipboard = FALSE;
+ /* Whether we are the owner of the clipboard */
+MSG vmsgLast; /* last message received */
+
+HFONT vhfPageInfo = NULL; /* handle to the font for the page info */
+int ypszPageInfo; /* y position in window to write page info */
+
+/* font related variables */
+int vifceMac = ifceMax;
+union FCID vfcidScreen;
+union FCID vfcidPrint;
+struct FCE rgfce[ifceMax];
+struct FCE *vpfceMru;
+struct FCE *vpfceScreen;
+struct FCE *vpfcePrint;
+struct FMI vfmiScreen;
+struct FMI vfmiPrint;
+
+#ifndef NEWFONTENUM
+int aspectXFont;
+int aspectYFont;
+#endif
+
+
+#ifdef SYSENDMARK
+HFONT vhfSystem = NULL; /* handle to the standard system font for
+ chEMark. */
+struct FMI vfmiSysScreen; /* to keep the metrics info for the system
+ font. */
+int vrgdxpSysScreen[chFmiMax - chFmiMin];
+ /* Used by vfmiSysScreen. */
+#endif /* KANJI */
+
diff --git a/private/mvdm/wow16/write/mlink.sed b/private/mvdm/wow16/write/mlink.sed
new file mode 100644
index 000000000..2778df8be
--- /dev/null
+++ b/private/mvdm/wow16/write/mlink.sed
@@ -0,0 +1,5 @@
+/^MALL\.OBJ = /,/[^\\]$/{s/^.ALL\.OBJ = //
+s/^ //
+s/\\$/+/
+p
+}
diff --git a/private/mvdm/wow16/write/mmw.c b/private/mvdm/wow16/write/mmw.c
new file mode 100644
index 000000000..04b5216eb
--- /dev/null
+++ b/private/mvdm/wow16/write/mmw.c
@@ -0,0 +1,661 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+//#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOMM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOGDICAPMASKS
+#define NOICON
+#define NOKEYSTATE
+#define NOMB
+#define NOMEMMGR
+//#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+//#define NOSHOWWINDOW
+#define NOSOUND
+#define NOSYSCOMMANDS
+#define NOSYSMETRICS
+#define NOVIRTUALKEYCODES
+#define NOWH
+#define NOWINOFFSETS
+#define NOWINSTYLES
+#define NOWNDCLASS
+#include <windows.h>
+
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#define NOSTRUNDO
+#include "str.h"
+#include "menudefs.h"
+#include "prmdefs.h"
+#include "propdefs.h"
+#include "debug.h"
+#include "fontdefs.h"
+#include "preload.h"
+#include "winddefs.h"
+#define NOIDISAVEPRINT
+#define NOIDIFORMATS
+#include "dlgdefs.h"
+
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+static void DrawResizeHole(HWND hWnd, HDC hDC);
+
+extern HANDLE hMmwModInstance; /* handle to it's own module instance */
+extern HWND hParentWw; /* handle to parent's window */
+extern HWND vhWndMsgBoxParent;
+extern HCURSOR vhcHourGlass;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcArrow;
+extern HMENU vhMenu;
+extern MSG vmsgLast;
+extern FARPROC lpDialogHelp;
+
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern int wwCur;
+extern int vfInitializing;
+extern int vfInsertOn;
+extern int vfSeeSel;
+extern int vfSelHidden;
+extern int vfDeactByOtherApp;
+extern int vfDownClick;
+extern int vfCursorVisible;
+extern int vfMouseExist;
+extern int flashID;
+extern int ferror;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern CHAR stBuf[];
+extern HBITMAP hbmNull;
+extern CHAR szWindows[];
+extern CHAR szDevices[];
+extern CHAR szIntl[];
+extern WORD fPrintOnly;
+
+#ifdef RULERALSO
+extern BOOL vfDisableMenus;
+#endif /* RULERALSO */
+
+#ifdef DEBUG
+#define STATIC
+#else /* not DEBUG */
+#define STATIC static
+#endif /* not DEBUG */
+
+CHAR **hszDevmodeChangeParam = NULL;
+BOOL vfDevmodeChange = fFalse;
+int wWininiChange = 0;
+
+BOOL vfDead = FALSE;
+BOOL vfIconic = FALSE;
+/*int vcActiveCount = 0; 0 or 1 for active/deactive count */
+
+
+void MmwCreate(HWND, LONG);
+void NEAR MmwPaint(HWND);
+void MmwSize(HWND, int, int, WORD);
+void MmwCommand(HWND, WORD, HWND, WORD);
+void MmwVertScroll(HWND, WORD, int);
+void NEAR MmwHorzScroll(HWND, WORD, int);
+
+
+int PASCAL WinMain( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
+HANDLE hInstance, hPrevInstance;
+LPSTR lpszCmdLine;
+int cmdShow;
+{
+ /* Set up all manner of windows-related data; create parent (menu)
+ window and child (document) window */
+
+ if (!FInitWinInfo( hInstance, hPrevInstance, lpszCmdLine, cmdShow ))
+ /* Could not initialize; WRITE fails */
+ {
+ return FALSE;
+ }
+
+ if (fPrintOnly)
+ {
+ UpdateDisplay(FALSE);
+ fnPrPrinter();
+ FMmwClose( hParentWw );
+ DeleteObject( hbmNull );
+ _exit( vmsgLast.wParam );
+ }
+ else
+ MainLoop();
+
+ DeleteObject( hbmNull );
+ _exit( vmsgLast.wParam );
+}
+
+
+long FAR PASCAL MmwWndProc(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+ extern int vfCloseFilesInDialog;
+ extern long ropErase;
+ extern int vfLargeSys;
+ extern HDC vhDCPrinter;
+ extern HWND vhWndCancelPrint;
+ extern HWND vhWndPageInfo;
+ extern HFONT vhfPageInfo;
+ extern BOOL vfWinFailure;
+ CHAR szT[cchMaxSz];
+ long lReturn = 0L;
+
+ switch (message)
+ {
+ case WM_MENUSELECT:
+ SetShiftFlags();
+ break;
+
+ case WM_CREATE:
+ /* Window's being created; lParam contains lpParam field
+ ** passed to CreateWindow */
+ MmwCreate(hWnd, lParam);
+ break;
+
+ case WM_PAINT:
+ /* Time to repaint this window. */
+ MmwPaint(hWnd);
+ break;
+
+#if defined(OLE)
+ case WM_DROPFILES:
+ /* We got dropped on, so bring ourselves to the top */
+ BringWindowToTop(hWnd);
+#ifdef DEBUG
+ OutputDebugString("Dropping on main window\r\n");
+#endif
+ ObjGetDrop(wParam,TRUE);
+ break;
+#endif
+
+ case WM_INITMENU:
+ /* setup the pull down menu before being drawn */
+ /* wParam is the top level menu handle */
+ vhMenu = (HMENU)wParam;
+ break;
+
+ case WM_INITMENUPOPUP:
+ /* setup the pull down menu before being drawn */
+ /* wParam is the popup menu handle */
+ /* LOWORD(lParam) = index of popup in main menu */
+ /* HIWORD(lParam) = 1 if system menu, 0 if application main menu */
+ EndLongOp(vhcArrow);
+ if (HIWORD(lParam) == 0)
+ { /* we care for the application main menu only */
+#ifdef CYCLESTOBURN
+ switch (LOWORD(lParam)) {
+ default:
+ break;
+ case EDIT:
+ PreloadCodeTsk( tskScrap );
+ case CHARACTER:
+ PreloadCodeTsk( tskFormat );
+ break;
+ }
+#endif
+ SetAppMenu((HMENU)wParam, LOWORD(lParam));
+ }
+ /* Turn on the cursor so we can see where it is */
+ if (!vfInsertOn && selCur.cpFirst == selCur.cpLim)
+ ToggleSel( selCur.cpFirst, selCur.cpFirst, TRUE );
+ break;
+
+ case WM_ACTIVATE:
+ /* We are becoming the active window iff wParam is non-0 */
+ /* HIWORD( lParam ) is true iff the window is iconic */
+ if (wParam && !HIWORD(lParam)
+#if 0
+#if defined(OLE)
+ && !nBlocking
+#endif
+#endif
+ && IsWindowEnabled(wwdCurrentDoc.wwptr))
+ {
+ SetFocus( wwdCurrentDoc.wwptr );
+ vhWndMsgBoxParent = hParentWw;
+ }
+ if (wParam)
+ {
+ vfDeactByOtherApp = FALSE; /* this is to conquer a windows' bug */
+ }
+
+ /* did we receive a devmode/winini change that we should process now? */
+ if (wWininiChange != 0)
+ {
+ Assert(wWininiChange > 0 && wWininiChange < wWininiChangeMax);
+ PostMessage( hWnd, wWndMsgSysChange, WM_WININICHANGE, (LONG) wWininiChange );
+ }
+
+ if (vfDevmodeChange)
+ {
+ Assert(hszDevmodeChangeParam != NULL);
+ PostMessage( hWnd, wWndMsgSysChange, WM_DEVMODECHANGE, (LONG) 0 );
+ vfDevmodeChange = fFalse;
+ }
+
+ if (!vfInitializing && vfCursorVisible)
+ ShowCursor(wParam);
+ break;
+
+ case WM_ACTIVATEAPP:
+ /* We are activated or deactivated by another application */
+ if (wParam == 0) /* being deactivated */
+ {
+ vfDeactByOtherApp = TRUE;
+ vfDownClick = FALSE;
+ /* hide selection if needed */
+ if (!vfSelHidden)
+ {
+ UpdateWindow(hParentWw);
+ ToggleSel(selCur.cpFirst, selCur.cpLim, FALSE);
+ vfSelHidden = TRUE;
+ }
+
+ /* Deselect our fonts so that they can move if necessary. */
+ ResetFont(FALSE);
+ if (vhWndCancelPrint == NULL)
+ {
+ /* Reset the printer font iff we are not printing or
+ repaginating. */
+ ResetFont(TRUE);
+ }
+ if (!vfLargeSys && vhfPageInfo != NULL)
+ {
+ DeleteObject(SelectObject(GetDC(vhWndPageInfo),
+ GetStockObject(SYSTEM_FONT)));
+ vhfPageInfo = NULL;
+ }
+ }
+ else /* being activated */
+ {
+ vfDeactByOtherApp = vfWinFailure = FALSE;
+
+#ifndef WIN30
+ /* We get into a recursive loop in the situation where we
+ have a bad/invalid/nonexistent printer driver because
+ GetPrinterDC() calls CreateIC() which will end up sending
+ another WM_ACTIVATEAPP! I think the machinery in Write
+ work just fine with a null vhDCPrinter, and will retry
+ again when it needs to do so ..pault 9/28/89 */
+
+ /* get a DC for the current printer if necessary */
+ if (vhDCPrinter == NULL)
+ {
+ GetPrinterDC(FALSE);
+ }
+#endif
+
+ /* hilight selection if needed */
+ if (vfSelHidden)
+ {
+ UpdateWindow(hParentWw);
+ /* Turn on selection highlight
+ vfInsEnd = selCur.fEndOfLine;*/
+ vfSelHidden = FALSE;
+ ToggleSel(selCur.cpFirst, selCur.cpLim, TRUE);
+ }
+ }
+ break;
+
+ case WM_TIMER:
+ /* the only timer event for the parent window is flashID */
+ /* the blinking insertion point is for the doc window */
+ if (vfDeactByOtherApp)
+ {
+ FlashWindow(hParentWw, TRUE);
+ }
+ else
+ {
+ KillTimer(hParentWw, flashID);
+ flashID = 0;
+ FlashWindow(hParentWw, FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+ /* The user has selected "Close" on the system menu */
+ /* Failure to process this message means that DefWindowProc */
+ /* Will send us a Destroy message */
+ /* A return value of TRUE says "don't close" */
+ /* Calling DestroyWindow means "Go ahead and close" */
+
+ lReturn = (LONG) !FMmwClose( hWnd );
+ break;
+
+ case WM_QUERYENDSESSION:
+ /* User has selected "End Session" from the MS-DOS window */
+ /* Return TRUE if willing to quit, else return FALSE */
+ lReturn = (LONG) FConfirmSave();
+ break;
+
+ case WM_ENDSESSION:
+ /* if wParam is TRUE, Windows is shutting down and we should */
+ /* delete temp files */
+ /* if wParam is FALSE, then an "End session" has been aborted */
+ if (wParam)
+ {
+ KillTempFiles( TRUE );
+ }
+ break;
+
+ case WM_DESTROY:
+ /* Window's being destroyed. */
+ MmwDestroy();
+ lReturn = (LONG) TRUE;
+ break;
+
+ case WM_SIZE:
+ /* Window's size is changing. lParam contains the height
+ ** and width, in the low and high words, respectively.
+ ** wParam contains SIZENORMAL for "normal" size changes,
+ ** SIZEICONIC when the window is being made iconic, and
+ ** SIZEFULLSCREEN when the window is being made full screen. */
+ MmwSize(hWnd, MAKEPOINT(lParam).x, MAKEPOINT(lParam).y, wParam);
+ //if (wParam == SIZEICONIC)
+ lReturn = DefWindowProc(hWnd, message, wParam, lParam);
+ break;
+
+ case WM_COMMAND:
+ /* A menu item has been selected, or a control is notifying
+ ** its parent. wParam is the menu item value (for menus),
+ ** or control ID (for controls). For controls, the low word
+ ** of lParam has the window handle of the control, and the hi
+ ** word has the notification code. For menus, lParam contains
+ ** 0L. */
+
+#ifdef RULERALSO
+ if (!vfDisableMenus)
+#endif /* RULERALSO */
+
+ {
+ MmwCommand(hWnd, wParam, (HWND)LOWORD(lParam), HIWORD(lParam));
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ /* system command */
+
+#ifdef RULERALSO
+ if (!vfDisableMenus)
+#endif /* RULERALSO */
+ {
+ lReturn = DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ break;
+
+ case WM_VSCROLL:
+ /* Vertical scroll bar input. wParam contains the
+ ** scroll code. For the thumb movement codes, the low
+ ** word of lParam contain the new scroll position.
+ ** Possible values for wParam are: SB_LINEUP, SB_LINEDOWN,
+ ** SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION, SB_THUMBTRACK */
+ MmwVertScroll(hWnd, wParam, (int)lParam);
+ break;
+
+ case WM_HSCROLL:
+ /* Horizontal scroll bar input. Parameters same as for
+ ** WM_HSCROLL. UP and DOWN should be interpreted as LEFT
+ ** and RIGHT, respectively. */
+ MmwHorzScroll(hWnd, wParam, (int)lParam);
+ break;
+
+ case WM_WININICHANGE:
+ /* We first save away the string passed in lParam,
+ then return because WM_ACTIVATE will cause our
+ wWndMsgSysChange message to get posted ..pault */
+
+ if (lParam != NULL)
+ {
+ bltszx((LPSTR) lParam, (LPSTR) szT);
+
+ /* Here we only care about [devices], [windows] or [intl] changes */
+
+ if (WCompSz(szT, szWindows) == 0)
+ wWininiChange |= wWininiChangeToWindows;
+
+#ifdef DBCS /* was in JAPAN */
+ // We have to respond WININICHANGE immediately to deal with
+ // dispatch driver. For deleting printer DC, dispatch driver
+ // must be available. If do not so, syserr box comes up from
+ // GDI module.
+
+ if (WCompSz(szT, szDevices) == 0) {
+ if( vhWndCancelPrint == NULL ) {
+ MmwWinSysChange(WM_WININICHANGE);
+ wWininiChange = 0; // reset
+ }
+ else
+ wWininiChange |= wWininiChangeToDevices;
+ }
+#else
+ if (WCompSz(szT, szDevices) == 0)
+ wWininiChange |= wWininiChangeToDevices;
+#endif
+
+ if (WCompSz(szT, szIntl) == 0)
+ wWininiChange |= wWininiChangeToIntl;
+
+ lReturn = TRUE;
+ }
+ break;
+ case WM_DEVMODECHANGE:
+ /* See WM_WININICHANGE above */
+
+ if (lParam != NULL)
+ {
+ CHAR (**HszCreate())[];
+ bltszx((LPSTR) lParam, (LPSTR) szT);
+
+ /* was there another change before this? */
+ if (hszDevmodeChangeParam != NULL)
+ FreeH(hszDevmodeChangeParam);
+ hszDevmodeChangeParam = HszCreate(szT);
+ vfDevmodeChange = fTrue;
+ lReturn = TRUE;
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ case WM_FONTCHANGE:
+ /* Post this message to handle soon */
+ PostMessage( hWnd, wWndMsgSysChange, message, (LONG) 0 );
+ lReturn = TRUE;
+ break;
+
+ case wWndMsgSysChange:
+ /* Handle postponed message from windows */
+
+#ifdef DEBUG
+ if (wWininiChange != 0)
+ Assert(wWininiChange > 0 && wWininiChange < wWininiChangeMax);
+#endif
+ MmwWinSysChange( wParam );
+ wWininiChange = 0; /* reset */
+ lReturn = TRUE;
+ break;
+
+ default:
+ /* Everything else comes here. This call MUST exist
+ ** in your window proc. */
+ lReturn = DefWindowProc(hWnd, message, wParam, lParam);
+ break;
+ }
+
+ if (vfCloseFilesInDialog)
+ CloseEveryRfn( FALSE );
+
+ return lReturn;
+}
+
+
+void NEAR MmwPaint(hWnd)
+HWND hWnd;
+{
+ /* This window is completely covered by it's children; so, there is
+ no painting of this window to do. */
+
+ extern HWND vhWndRuler;
+ extern HWND vhWndSizeBox;
+ extern HWND vhWndPageInfo;
+ PAINTSTRUCT ps;
+ HDC hDC;
+
+ hDC = BeginPaint(hWnd, &ps); // this is causing nested BeginPaint calls,
+ DrawResizeHole(hWnd,hDC);
+
+ /* Paint the ruler if necessary. */
+ if (vhWndRuler != NULL)
+ {
+ UpdateWindow(vhWndRuler);
+ }
+
+ /* Paint the scroll bar controls. */
+ UpdateWindow(wwdCurrentDoc.hVScrBar);
+ UpdateWindow(wwdCurrentDoc.hHScrBar);
+ UpdateWindow(vhWndPageInfo);
+
+ /* Paint the document window. */
+ if (wwdCurrentDoc.wwptr != NULL)
+ {
+ UpdateWindow(wwdCurrentDoc.wwptr);
+ }
+
+ EndPaint(hWnd, &ps);
+}
+
+
+void MmwVertScroll(hWnd, code, posNew)
+HWND hWnd;
+WORD code;
+int posNew;
+{
+extern int vfSeeSel;
+extern int vfSeeEdgeSel;
+
+ /* There's nothing to do if we are just tracking the thumb. */
+ if (code == SB_THUMBTRACK)
+ {
+ return;
+ }
+
+ vfSeeSel = vfSeeEdgeSel = FALSE; /* So Idle doesn't override the scroll */
+
+ if (code == SB_THUMBPOSITION)
+ {
+ /* Position to posNew; we rely upon Idle() to redraw the screen. */
+ if (posNew != pwwdCur->drElevator)
+ {
+ ClearInsertLine();
+ DirtyCache(pwwdCur->cpFirst = (cpMacCur - pwwdCur->cpMin) * posNew
+ / (drMax - 1) + pwwdCur->cpMin);
+ pwwdCur->ichCpFirst = 0;
+ pwwdCur->fCpBad = TRUE;
+ TrashWw(wwCur);
+ }
+ }
+ else
+ {
+ switch (code)
+ {
+ case SB_LINEUP:
+ ScrollUpCtr( 1 );
+ break;
+ case SB_LINEDOWN:
+ ScrollDownCtr( 1 );
+ break;
+ case SB_PAGEUP:
+ ScrollUpDypWw();
+ break;
+ case SB_PAGEDOWN:
+ ScrollDownCtr( 100 ); /* 100 > tr's in a page */
+ break;
+ }
+ UpdateWw(wwDocument, fFalse);
+ }
+}
+
+
+void near MmwHorzScroll(hWnd, code, posNew)
+HWND hWnd;
+WORD code;
+int posNew;
+{
+extern int vfSeeSel;
+extern int vfSeeEdgeSel;
+
+ /* There's nothing to do if we are just tracking the thumb. */
+ if (code == SB_THUMBTRACK)
+ {
+ return;
+ }
+
+ vfSeeSel = vfSeeEdgeSel = FALSE; /* So Idle doesn't override the scroll */
+
+ switch (code)
+ {
+ case SB_LINEUP: /* line left */
+ ScrollRight(xpMinScroll);
+ break;
+ case SB_LINEDOWN: /* line right */
+ ScrollLeft(xpMinScroll);
+ break;
+ case SB_PAGEUP: /* page left */
+ ScrollRight(wwdCurrentDoc.xpMac - xpSelBar);
+ break;
+ case SB_PAGEDOWN: /* page right */
+ ScrollLeft(wwdCurrentDoc.xpMac - xpSelBar);
+ break;
+ case SB_THUMBPOSITION:
+ /* position to posNew */
+ AdjWwHoriz(posNew - wwdCurrentDoc.xpMin);
+ break;
+ }
+}
+
+static void DrawResizeHole(HWND hWnd, HDC hDC)
+/* There's now a hole in the bottom right corner where
+ the size box used to be, so need to fill it in! */
+{
+ RECT rcSB,rcClient;
+ HBRUSH hbr, hbrPrev;
+
+ GetClientRect(hWnd,&rcClient);
+
+ rcSB.left = rcClient.right - dxpScrlBar;
+ rcSB.right = rcClient.right;
+ rcSB.top = rcClient.bottom - dypScrlBar;
+ rcSB.bottom = rcClient.bottom;
+
+ if ((hbr = CreateSolidBrush(GetSysColor(COLOR_SCROLLBAR))) == NULL)
+ hbr = GetStockObject(GRAY_BRUSH);
+ hbrPrev = SelectObject(hDC, hbr);
+ FillRect(hDC, (LPRECT)&rcSB, hbr);
+
+ SelectObject(hDC, hbrPrev);
+ DeleteObject(hbr);
+}
+
+
+
diff --git a/private/mvdm/wow16/write/mouse.c b/private/mvdm/wow16/write/mouse.c
new file mode 100644
index 000000000..73797cbc8
--- /dev/null
+++ b/private/mvdm/wow16/write/mouse.c
@@ -0,0 +1,436 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* The routines in this file roughly correspond to the routines in the original
+Mac Word file, sand.c. But since that name is confusing, and most of these
+routine deal with the mouse, the name was changed to protect the innocent. */
+
+#define NOGDICAPMASKS
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+//#define NOMETAFILE
+#include <windows.h>
+#include "mw.h"
+#include "dispdefs.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+
+#if defined(OLE)
+#include "obj.h"
+#include "winddefs.h"
+#include "str.h"
+#endif
+
+/* cpNil is defined in docdefs.h, but to include the whole file will cause the
+symbol table to overflow, so it is redefined here. */
+#define cpNil ((typeCP) -1)
+
+
+extern struct WWD rgwwd[];
+extern struct WWD *pwwdCur;
+extern int wwCur;
+extern struct SEL selCur;
+extern int docCur;
+extern int vfShiftKey;
+extern int vfOptionKey;
+extern int vfCommandKey;
+extern int vfDoubleClick;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern struct PAP vpapAbs;
+extern typeCP cpWall;
+extern int vfDidSearch;
+extern typeCP vcpSelect;
+extern int vfSelAtPara;
+extern int vfPictSel;
+extern long tickOld;
+
+#ifdef PENWIN
+extern int vcFakeMessage;
+extern LONG FAR PASCAL GetMessageExtraInfo( void ); // Defined in Win 3.1
+#endif
+
+/* G L O B A L S */
+
+int vfSelecting = false;
+int vstyCur;
+int vpsmCur;
+int vfObjOpen=0,vfObjProps=0,vfObjSel=0;
+int vfAwfulNoise = false;
+struct SEL selPend;
+
+/* MB_STANDARD is the same as in diaalert.c */
+#define MB_STANDARD (MB_OK | MB_SYSTEMMODAL | MB_ICONEXCLAMATION)
+
+/* _ B E E P */
+_beep()
+ {
+ /* Beeps once */
+ if (!vfAwfulNoise)
+ {
+ beep();
+ vfAwfulNoise = true;
+ }
+ }
+
+
+
+beep()
+ {
+ MessageBeep(MB_STANDARD);
+ }
+
+
+
+/* D O C O N T E N T H I T */
+DoContentHit(pt)
+POINT pt;
+ {
+
+ /* This routine process everything from a mouse-down click to the
+ corresponding mouse-up click. */
+
+ int dlMouse;
+
+ /* Ignore mouse hits in the page area & above the first line*/
+ if ( (pt.y >= wwdCurrentDoc.ypMac) ||
+ (pt.y < wwdCurrentDoc.ypMin) )
+ return;
+
+ /* Check for a special selection, i.e. move, copy or format text. */
+ if (FSetPsm())
+ {
+ blt(&selCur, &selPend, cwSEL);
+ vfDoubleClick = vfCommandKey = vfShiftKey = false;
+ vstyCur = vpsmCur != psmLooks ? StyFromPt(pt) : styChar;
+ }
+ else
+ {
+ vstyCur = StyFromPt(pt);
+ }
+
+ dlMouse = DlFromYp(pt.y, pwwdCur);
+ vcpSelect = cpNil;
+ vfSelAtPara = false;
+
+#ifdef ENABLE
+ if (vfPictSel)
+ {
+ /* Check for a picture modification (moving, sizing). */
+ if (FHitPictFrame(dlMouse, pt))
+ {
+ return;
+ }
+
+ /* Remove the picture frame */
+ ToggleSel(selCur.cpFirst, selCur.cpLim, false);
+ vfPictSel = false;
+ ToggleSel(selCur.cpFirst, selCur.cpLim, true);
+ }
+#endif
+
+ vfSelecting = true;
+ SelectDlXp(dlMouse, pt.x, vstyCur, vfShiftKey);
+
+ /* Now we sit in a loop processing all mouse events in all windows until a
+ mouse-up click. */
+ SetCapture(wwdCurrentDoc.wwptr);
+ while( FStillDown( &pt ) )
+ {
+ /* If the mouse is above or below the window, then scroll the window and
+ pretend the mouse is in the window. */
+ if (pt.y > (int)wwdCurrentDoc.ypMac)
+ {
+ ScrollDownCtr( 1 );
+ goto DoCont1;
+ }
+ else if (pt.y < (int)wwdCurrentDoc.ypMin)
+ {
+ ScrollUpCtr( 1 );
+DoCont1: UpdateWw(wwCur, false);
+ }
+
+ /* Get a valid dl and xp. */
+ dlMouse = DlFromYp(pt.y, pwwdCur);
+ if (pt.x < 0)
+ pt.x = 0;
+ else if (pt.x > wwdCurrentDoc.xpMac)
+ pt.x = wwdCurrentDoc.xpMac;
+
+ /* Update the selection. */
+ if (vfOptionKey)
+ {
+ vcpSelect = cpNil;
+ }
+ SelectDlXp(dlMouse, pt.x, vstyCur, !vfOptionKey);
+ } /* End of for ( ; ; ) */
+
+ /* Release all of the mouse events. */
+ ReleaseCapture();
+
+ /* Process Mouse Up */
+ DoContentHitEnd( pt );
+ SetFocus( wwdCurrentDoc.wwptr );
+
+ /* If the selection is an insertion bar, start it flashing. */
+ if (selCur.cpFirst == selCur.cpLim)
+ {
+ extern int vfSkipNextBlink;
+ vfSkipNextBlink = true;
+ }
+
+#if defined(OLE)
+ if (ObjQueryCpIsObject(docCur,selCur.cpFirst) && (vfObjProps || vfObjOpen))
+ /* doubleclick and maybe alt key */
+ {
+ /* set whether link or emb selected */
+ ObjSetSelectionType(docCur,selCur.cpFirst,selCur.cpLim);
+ if (vfObjProps)
+ /* alt + double click */
+ {
+ switch(OBJ_SELECTIONTYPE)
+ {
+#if 0 // do nothing if embedded
+ case EMBEDDED:
+ {
+ struct PICINFOX picInfo;
+ GetPicInfo(selCur.cpFirst,selCur.cpLim, docCur, &picInfo);
+ ObjEditObjectInDoc(&picInfo, docCur, vcpFirstParaCache);
+ }
+ break;
+#endif
+
+ case LINK:
+ /* bring up properties dlg */
+ fnObjProperties();
+ break;
+ }
+ CachePara(docCur,selCur.cpFirst);
+ }
+ else if (vfObjOpen) // edit object
+ /* double click */
+ {
+ if (OBJ_SELECTIONTYPE == STATIC)
+ Error(IDPMTStatic);
+ else
+ {
+ struct PICINFOX picInfo;
+ GetPicInfo(selCur.cpFirst,selCur.cpLim, docCur, &picInfo);
+ ObjPlayObjectInDoc(&picInfo, docCur, vcpFirstParaCache);
+ }
+ }
+ }
+#endif
+
+ }
+
+
+/* D O C O N T E N T H I T E N D */
+DoContentHitEnd(pt)
+POINT pt;
+ {
+ int dlMouse;
+ int cch;
+
+ dlMouse = DlFromYp(min(pt.y, wwdCurrentDoc.ypMac), pwwdCur);
+ SelectDlXp(dlMouse, pt.x, vstyCur, vpsmCur == psmNil);
+
+ switch (vpsmCur)
+ {
+ default:
+ case psmNil:
+ break;
+
+ case psmLooks:
+ LooksMouse();
+ break;
+
+ case psmCopy:
+ #if defined(OLE)
+ /* we'll disable CopyMouse if any objects are in dest */
+ vfObjSel = ObjQueryCpIsObject(docCur,selCur.cpFirst);
+
+ if (!vfObjSel)
+ // !!! disable because for objects this
+ // interferes with Alt-DoubleClick (2.20.91) D. Kent
+ #endif
+ CopyMouse();
+ break;
+
+ case psmMove:
+ MoveMouse();
+ break;
+ }
+
+#ifdef ENABLE
+ CachePara(docCur, selCur.cpFirst);
+
+ if (vpapAbs.fGraphics && selCur.cpLim == vcpLimParaCache)
+ {
+ /* Selected a picture, do special selection stuff. */
+ Assert(selCur.cpFirst == vcpFirstParaCache);
+
+ /* Turn off the selection, indicate that it is a picture, then turn it
+ back on. */
+ ToggleSel(selCur.cpFirst, selCur.cpLim, false);
+ vfPictSel = true;
+ ToggleSel(selCur.cpFirst, selCur.cpLim, true);
+ }
+ else
+ {
+ vfPictSel = false;
+ }
+#endif
+
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ vfSelecting = false;
+ }
+
+
+/* S T Y F R O M P T */
+int StyFromPt(pt)
+POINT pt;
+ {
+ /* Return the style code associated with the selection made at point pt. */
+ if (pt.x > xpSelBar)
+ {
+ return vfCommandKey ? stySent : (vfDoubleClick ? styWord : styChar);
+ }
+ else
+ {
+ return vfCommandKey ? styDoc : (vfDoubleClick ? styPara : styLine);
+ }
+ }
+
+
+/* F S E T P S M */
+int FSetPsm()
+ {
+ /* Sets vpsmCur according to the states of the shift, commad, and option
+ keys. True is returned if vpsmCur is not nil; false otherwise. */
+
+ vpsmCur = psmNil;
+
+ if (vfOptionKey)
+ {
+ if (vfShiftKey && !vfCommandKey)
+ {
+ vpsmCur = psmMove;
+ }
+ else if (vfCommandKey && !vfShiftKey)
+ {
+ vpsmCur = psmLooks;
+ }
+ else if (!vfCommandKey && !vfShiftKey)
+ {
+ vfObjProps = vfDoubleClick;
+ vfObjOpen = FALSE;
+ vpsmCur = psmCopy;
+ }
+ }
+ else
+ {
+ vfObjOpen = vfDoubleClick;
+ vfObjProps = FALSE;
+ }
+ return (vpsmCur != psmNil);
+ }
+
+
+/* D L F R O M Y P */
+int DlFromYp(yp, pwwd)
+int yp;
+struct WWD *pwwd;
+ {
+ /* Return the dl that contains yp */
+ int dlT;
+ int ypSum;
+ struct EDL *pedl;
+ int dlMac;
+
+ /* Clean up a dirty window. */
+ if (pwwd->fDirty)
+ {
+ UpdateWw(pwwd - &rgwwd[0] /* = ww; grr.. */, false);
+ }
+
+ /* Loop throught the EDLs summing up the heights utill the sum is greater
+ than yp. */
+ ypSum = pwwd->ypMin;
+ pedl = &(**(pwwd->hdndl))[0];
+ dlMac = pwwd->dlMac;
+
+ for (dlT = 0; dlT < dlMac; ++dlT, pedl++)
+ {
+ ypSum += pedl->dyp;
+ if (ypSum > yp)
+ {
+ return dlT;
+ }
+ }
+
+ return dlMac - 1;
+ }
+
+
+FStillDown( ppt )
+POINT *ppt;
+{ /* This is roughly equivalent to a Mac routine that returns whether
+ the mouse button is down. We look for one mouse message from our
+ window's queue, and return FALSE if it is a BUTTONUP. We return the
+ point at which the mouse event occurred through a pointer. If no
+ message occurred, we return TRUE and do not store into the pointer */
+ MSG msg;
+
+retry_peek:
+
+ if ( PeekMessage( (LPMSG)&msg, (HWND)NULL, NULL, NULL, PM_REMOVE ) )
+ {
+ extern WORD wWinVer;
+ switch (msg.message) {
+ default:
+ TranslateMessage( (LPMSG)&msg );
+ DispatchMessage( (LPMSG)&msg );
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDOWN:
+#ifdef PENWIN
+ if (((wWinVer & 0xFF) >= 3) && ((wWinVer & 0xFF00) >= 0x0A00))
+ /* Windows Version >= 3.10 */
+ if( vcFakeMessage > 0 )
+ {
+ static FARPROC MessageExtraInfo = NULL;
+
+ if (MessageExtraInfo == NULL)
+ MessageExtraInfo = GetProcAddress(GetModuleHandle((LPSTR)"USER"),(LPSTR)288L);
+
+ if( MessageExtraInfo() != 0 )
+ goto retry_peek;
+ vcFakeMessage--;
+ }
+#endif
+ /* A Mouse Move, Mouse Down, or Mouse Up is waiting */
+ ppt->x = MAKEPOINT(msg.lParam).x;
+ ppt->y = MAKEPOINT(msg.lParam).y;
+
+ return (msg.message != WM_LBUTTONUP);
+ }
+ }
+ else
+ return GetKeyState( VK_LBUTTON ) < 0;
+
+ return TRUE;
+}
+
diff --git a/private/mvdm/wow16/write/mouse.h b/private/mvdm/wow16/write/mouse.h
new file mode 100644
index 000000000..21d738ae4
--- /dev/null
+++ b/private/mvdm/wow16/write/mouse.h
@@ -0,0 +1,131 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the mouse definitions used by Windows Word. The verbosity
+of this file is due to the fact that although the resource compiler will accept
+include files, it will do no algerbraic simplification. */
+
+#define cMouseButton 1
+
+#define fMouseKey 0x2000
+
+#define fUp 0
+#define fDown 1
+#define fCommand 2
+#define fOption 4
+#define fShift 8
+
+#define imbMove 0x2000
+
+#if cMouseButton > 0
+ #define fMouseButton1 0x2100
+ #define imb1Up 0x2100 /* fMouseButton1 | fUp */
+ #define imb1Dn 0x2101 /* fMouseButton1 | fDown */
+ #define imb1ComUp 0x2102 /* fMouseButton1 | fCommand | fUp */
+ #define imb1ComDn 0x2103 /* fMouseButton1 | fCommand | fDown */
+ #define imb1OptUp 0x2104 /* fMouseButton1 | fOption | fUp */
+ #define imb1OptDn 0x2105 /* fMouseButton1 | fOption | fDown */
+ #define imb1ShfUp 0x2108 /* fMouseButton1 | fShift | fUp */
+ #define imb1ShfDn 0x2109 /* fMouseButton1 | fShift | fDown */
+ #define imb1ComOptUp 0x2106 /* fMouseButton1 | fCommand | fOption |
+ fUp */
+ #define imb1ComOptDn 0x2107 /* fMouseButton1 | fCommand | fOption |
+ fDown */
+ #define imb1ComShfUp 0x210a /* fMouseButton1 | fCommand | fShift |
+ fUp */
+ #define imb1ComShfDn 0x210b /* fMouseButton1 | fCommand | fShift |
+ fDown */
+ #define imb1OptShfUp 0x210c /* fMouseButton1 | fOption | fShift |
+ fUp */
+ #define imb1OptShfDn 0x210d /* fMouseButton1 | fOption | fShift |
+ fDown */
+ #define imb1ComOptShfUp 0x210e /* fMouseButton1 | fCommand | fOption |
+ fShift | fUp */
+ #define imb1ComOptShfDn 0x210f /* fMouseButton1 | fCommand | fOption |
+ fShift | fDown */
+#endif /* cMouseButtonButton > 0 */
+
+#if cMouseButton > 1
+ #define fMouseButton2 0x2200
+ #define imb2Up 0x2200 /* fMouseButton2 | fUp */
+ #define imb2Dn 0x2201 /* fMouseButton2 | fDown */
+ #define imb2ComUp 0x2202 /* fMouseButton2 | fCommand | fUp */
+ #define imb2ComDn 0x2203 /* fMouseButton2 | fCommand | fDown */
+ #define imb2OptUp 0x2204 /* fMouseButton2 | fOption | fUp */
+ #define imb2OptDn 0x2205 /* fMouseButton2 | fOption | fDown */
+ #define imb2ShfUp 0x2208 /* fMouseButton2 | fShift | fUp */
+ #define imb2ShfDn 0x2209 /* fMouseButton2 | fShift | fDown */
+ #define imb2ComOptUp 0x2206 /* fMouseButton2 | fCommand | fOption |
+ fUp */
+ #define imb2ComOptDn 0x2207 /* fMouseButton2 | fCommand | fOption |
+ fDown */
+ #define imb2ComShfUp 0x220a /* fMouseButton2 | fCommand | fShift |
+ fUp */
+ #define imb2ComShfDn 0x220b /* fMouseButton2 | fCommand | fShift |
+ fDown */
+ #define imb2OptShfUp 0x220c /* fMouseButton2 | fOption | fShift |
+ fUp */
+ #define imb2OptShfDn 0x220d /* fMouseButton2 | fOption | fShift |
+ fDown */
+ #define imb2ComOptShfUp 0x220e /* fMouseButton2 | fCommand | fOption |
+ fShift | fUp */
+ #define imb2ComOptShfDn 0x220f /* fMouseButton2 | fCommand | fOption |
+ fShift | fDown */
+#endif /* cMouseButton > 1 */
+
+#if cMouseButton > 2
+ #define fMouseButton3 0x2400
+ #define imb3Up 0x2400 /* fMouseButton3 | fUp */
+ #define imb3Dn 0x2401 /* fMouseButton3 | fDown */
+ #define imb3ComUp 0x2402 /* fMouseButton3 | fCommand | fUp */
+ #define imb3ComDn 0x2403 /* fMouseButton3 | fCommand | fDown */
+ #define imb3OptUp 0x2404 /* fMouseButton3 | fOption | fUp */
+ #define imb3OptDn 0x2405 /* fMouseButton3 | fOption | fDown */
+ #define imb3ShfUp 0x2408 /* fMouseButton3 | fShift | fUp */
+ #define imb3ShfDn 0x2409 /* fMouseButton3 | fShift | fDown */
+ #define imb3ComOptUp 0x2406 /* fMouseButton3 | fCommand | fOption |
+ fUp */
+ #define imb3ComOptDn 0x2407 /* fMouseButton3 | fCommand | fOption |
+ fDown */
+ #define imb3ComShfUp 0x240a /* fMouseButton3 | fCommand | fShift |
+ fUp */
+ #define imb3ComShfDn 0x240b /* fMouseButton3 | fCommand | fShift |
+ fDown */
+ #define imb3OptShfUp 0x240c /* fMouseButton3 | fOption | fShift |
+ fUp */
+ #define imb3OptShfDn 0x240d /* fMouseButton3 | fOption | fShift |
+ fDown */
+ #define imb3ComOptShfUp 0x240e /* fMouseButton3 | fCommand | fOption |
+ fShift | fUp */
+ #define imb3ComOptShfDn 0x240f /* fMouseButton3 | fCommand | fOption |
+ fShift | fDown */
+#endif /* cMouseButton > 2 */
+
+#if cMouseButton > 3
+ #define fMouseButton4 0x2800
+ #define imb4Up 0x2800 /* fMouseButton4 | fUp */
+ #define imb4Dn 0x2801 /* fMouseButton4 | fDown */
+ #define imb4ComUp 0x2802 /* fMouseButton4 | fCommand | fUp */
+ #define imb4ComDn 0x2803 /* fMouseButton4 | fCommand | fDown */
+ #define imb4OptUp 0x2804 /* fMouseButton4 | fOption | fUp */
+ #define imb4OptDn 0x2805 /* fMouseButton4 | fOption | fDown */
+ #define imb4ShfUp 0x2808 /* fMouseButton4 | fShift | fUp */
+ #define imb4ShfDn 0x2809 /* fMouseButton4 | fShift | fDown */
+ #define imb4ComOptUp 0x2806 /* fMouseButton4 | fCommand | fOption |
+ fUp */
+ #define imb4ComOptDn 0x2807 /* fMouseButton4 | fCommand | fOption |
+ fDown */
+ #define imb4ComShfUp 0x280a /* fMouseButton4 | fCommand | fShift |
+ fUp */
+ #define imb4ComShfDn 0x280b /* fMouseButton4 | fCommand | fShift |
+ fDown */
+ #define imb4OptShfUp 0x280c /* fMouseButton4 | fOption | fShift |
+ fUp */
+ #define imb4OptShfDn 0x280d /* fMouseButton4 | fOption | fShift |
+ fDown */
+ #define imb4ComOptShfUp 0x280e /* fMouseButton4 | fCommand | fOption |
+ fShift | fUp */
+ #define imb4ComOptShfDn 0x280f /* fMouseButton4 | fCommand | fOption |
+ fShift | fDown */
+#endif /* cMouseButton > 3 */
diff --git a/private/mvdm/wow16/write/msseqds.asm b/private/mvdm/wow16/write/msseqds.asm
new file mode 100644
index 000000000..acb4843fd
--- /dev/null
+++ b/private/mvdm/wow16/write/msseqds.asm
@@ -0,0 +1,201 @@
+ title Special Export call locations for DS == SS conversion.
+
+; Windows Write, Copyright 1985-1992 Microsoft Corporation
+
+?DF = 1 ; Dont generate default segment definitions
+?PLM = 1
+ .XLIST
+ include cmacros.inc
+ .LIST
+
+ subttl Define Windows Groups
+ page
+
+MGROUP group HEADER,EXPORTS,IMPORTS,IMPORTEND,ENDHEADER
+IGROUP group _TEXT,_INITTEXT,_ENDTEXT
+DGROUP group _DATA,DATA,CDATA,CONST,_BSS,c_common,_INITDATA,_ENDDATA,STACK
+HEADER segment para 'MODULE'
+HEADER ENDS
+EXPORTS segment byte 'MODULE'
+EXPORTS ENDS
+IMPORTS segment byte public 'MODULE'
+IMPORTS ENDS
+IMPORTEND segment byte 'MODULE'
+IMPORTEND ENDS
+ENDHEADER segment para 'MODULE'
+ENDHEADER ENDS
+_TEXT segment byte public 'CODE'
+_TEXT ENDS
+_INITTEXT segment para public 'CODE'
+_INITTEXT ends
+_ENDTEXT segment para 'CODE'
+_ENDTEXT ends
+
+_DATA segment para public 'DATA'
+
+STACKSIZE = 2048
+
+$$STACK dw STACKSIZE dup (?)
+$$STACKTOP label word
+ dw 0
+
+_DATA ends
+
+DATA segment para public 'DATA'
+DATA ends
+CDATA segment word common 'DATA' ; C globals end up here
+CDATA ends
+CONST segment word public 'CONST'
+CONST ends
+_BSS segment para public 'BSS'
+_BSS ends
+c_common segment para common 'BSS' ; C globals end up here
+c_common ends
+_INITDATA segment para public 'BSS'
+_INITDATA ends
+_ENDDATA segment para 'BSS'
+_ENDDATA ends
+
+STACK segment para stack 'STACK'
+ DB 0 ; Force link to write entire DGROUP
+STACK ends
+
+ subttl ENTRYPOINT definition
+ page
+
+ENTRYPOINT MACRO name, cwArgs
+ extrn x&name:far
+ public name
+name proc far
+ mov ax,ds ; we have to include all this code
+ nop ; or exe2mod chokes
+ inc bp
+ push bp
+ mov bp,sp
+ push ds
+ mov ds,ax
+
+ mov cx,cwArgs * 2
+ mov dx,offset igroup:x&name
+ jmp SetLocStack
+name endp
+
+ ENDM
+
+ subttl external->local stack switcher
+ page
+
+_TEXT segment byte public 'CODE'
+ assume cs:igroup, ds:dgroup, es:dgroup, ss:nothing
+
+;
+; SetLocStack
+;
+; Purpose: To switch to a seperate stack located in the
+; Modules Data Segment.
+;
+; Inputs: AX = module's DS
+; SS, SP, BP = caller's stack stuff
+; DS = "true" entry point addr
+; cx = no. of bytes of parameters on caller's stack
+;
+SetLocStack proc near
+ mov bx,ss ; get copy of current segment
+ cmp ax,bx ; see if we're already in local stack
+ je inlocal ; we are - fall into existing code
+
+ mov cs:SESPat,cx ; save arg byte count for return
+
+ mov ss,ax
+ mov sp,offset dgroup:$$STACKTOP
+
+ push bx ; save old ss
+ sub bp,2 ; point at the pushed ds
+ push bp ; and old sp
+ push si ; save si
+
+ jcxz argdone
+
+ mov ds,bx
+ lea si,[bp + 8 - 2] ; point past ds, bp, far addr to args
+ add si,cx ; point at top of args for backward move
+
+ std
+ shr cx,1 ; divide byte count by two
+ jcxz argdone
+argloop:
+ lodsw
+ push ax
+ loop argloop
+ cld
+
+argdone:
+ push cs
+ mov ax,offset igroup:SetExtStack ; push setextstack return addr
+ push ax
+
+ mov ax,ss ; get new ds into ds and ax
+ mov ds,ax
+
+ push dx ; jump to true entry point via RET
+ ret
+
+inlocal:
+ add dx,10 ; point past prolog code
+ push dx ; jump into middle of prolog code
+ ret
+
+SetLocStack endp
+
+SetExtStack proc near
+ pop si ; get back saved si
+ pop bp ; get old sp
+ pop bx ; and old ss
+
+ mov ss,bx
+ mov sp,bp ; now set up the suckers
+
+ pop ds ; standard epilog stuff
+ pop bp
+ dec bp
+
+ db 0cah ;RETF n instruction
+SESPat dw 0
+
+SetExtStack endp
+
+ subttl Entry point definitions
+ page
+;
+; mp module entry points
+;
+ENTRYPOINT MMpNew, 3
+ENTRYPOINT MMpLoad, 2
+ENTRYPOINT MMpFree, 2
+;
+; routines called by interface module
+;
+ENTRYPOINT MRgchVal, 6
+ENTRYPOINT Mdecode, 2
+ENTRYPOINT MEnter, 1
+ENTRYPOINT Fill, 1
+ENTRYPOINT Clear, 0
+ENTRYPOINT Format, 1
+ENTRYPOINT MCellsContract, 0
+ENTRYPOINT MInsertBents, 8
+ENTRYPOINT MSheetCut, 0
+ENTRYPOINT MSheetCopy, 0
+ENTRYPOINT MSheetPaste, 1
+ENTRYPOINT MExeCut, 0
+ENTRYPOINT MExePaste, 0
+ENTRYPOINT CheckRecalc, 0
+ENTRYPOINT recalc, 1
+ENTRYPOINT MLoadSheet, 2
+ENTRYPOINT MSaveSheet, 3
+ENTRYPOINT MSortDialog, 4
+
+
+_TEXT ENDS
+
+ end
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/mw.h b/private/mvdm/wow16/write/mw.h
new file mode 100644
index 000000000..42451d21c
--- /dev/null
+++ b/private/mvdm/wow16/write/mw.h
@@ -0,0 +1,212 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* MW.H -- Main header file for Windows Write */
+
+
+/* some defines that used to be done in the makefile...
+ (started exceeding command line length!) */
+
+#define OLE /* Object Linking and Embedding 01/23/91 -- dougk
+ Also defined in write.rc. */
+
+#define PENWIN /* pen windows: also defined in write.rc (6.21.91) v-dougk */
+
+#define WIN30
+/* #define WINVER 310 */ /* First convention was to use WIN30 defined above,
+ but later switched to use of WINVER so it will be
+ easier next time we change either the Windows or
+ Write products 12/3/89..pault */
+
+#define INTL /* This MUST be turned on (even for the Z version now) */
+#define CRLF /* MS-DOS defines the carriage-return/line-feed sequence */
+
+/* Major intermodule defines */
+
+#define SMFONT /* SmartFont? */
+#define NOMORESIZEBOX /* The CUA spec has changed for Win30 and
+ we no longer have a special size box in
+ the lower-right corner of the Write window */
+#define NEWFONTENUM /* So many problems have come up that I'm
+ revamping a large part of the font enumeration
+ code and it'll be marked by this. Among others:
+ -- removed font filtering based on aspect ratio,
+ -- don't disallow fonts not in ANSI_CHARSET, etc.
+ ..pault */
+#define SYSENDMARK /* This enables code for putting the end mark
+ in the system font -- previously Kanji only */
+#ifndef NEWFONTENUM
+ #define INEFFLOCKDOWN
+#endif
+
+#undef MSDOS
+#undef M_I86MM
+#undef M_I86
+
+#ifndef SAND
+#define REG1 register
+#define REG2 register
+#endif /* not SAND */
+
+#define true 1
+#define false 0
+#define fTrue true
+#define fFalse false
+
+#ifdef SAND
+/* already defined in windows.h */
+#define NULL 0
+#endif /* SAND */
+
+#define LNULL 0L
+
+#define bNil (-1)
+#define iNil (-1)
+#define valNil (-1)
+
+#define cchINT (sizeof (int))
+
+#define BStructMember( s, field ) ((unsigned)&(((struct s *)(0))->field))
+
+
+#define hOverflow (-1)
+
+#define ivalMax 24
+#define mrgNil (-32766)
+
+#define cchMaxSz 350
+typedef long typeCP;
+typedef long typeFC;
+typedef unsigned typePN;
+typedef unsigned typeTS; /* TS = time stamp */
+
+#ifdef CRLF
+#define ccpEol 2
+#else /* not CRLF */
+#define ccpEol 1
+#endif /* not CRLF */
+
+#ifdef SAND
+typedef char CHAR;
+#else /* not SAND */
+typedef unsigned char CHAR;
+#endif /* not SAND */
+
+typedef CHAR *PCH;
+typedef CHAR far *LPCH;
+#if WINVER >= 0x300
+typedef CHAR huge *HPCH; /* this is a far but C generates extra code
+ to make sure segment arithmetic is done
+ correctly, esp. important in protect mode.
+ added for handling >64k clipboard text.
+ apologies re apparently odd hungarian ..pault */
+#endif
+
+#ifdef SAND
+/* ifdef out because typedef unsigned char BYTE in windows.h */
+#define BYTE unsigned char
+#endif /* SAND */
+
+#define VAL int
+#define MD int
+#define BOOL int
+#define IDFLD int
+#define IDSTR int
+#define IDPMT int
+#define CC int
+
+#ifdef WIN30
+/* DialogBox has been fixed so it automatically brings up the hourglass! */
+
+#ifdef DBCS /* was in KKBUGFIX */
+ // [yutakan:05/17/91] 'c' can be null at initialize.
+#define OurDialogBox(a,b,c,d) DialogBox(a,b,((c==(HWND)NULL)?hParentWw:c),d)
+#else
+#define OurDialogBox(a,b,c,d) DialogBox(a,b,c,d)
+#endif /* DBCS */
+
+#endif
+
+/* bltsz: copy only up to terminator, inclusive
+ 4/20/89 NOTE: using CchCopySz kills previously returned value of a psz! */
+#define bltsz(pFrom, pTo) CchCopySz((pFrom), (pTo))
+
+/* bltszx: far version of above */
+#define bltszx(lpFrom, lpTo) \
+ bltbx((LPCH) (lpFrom), (LPCH) (lpTo), IchIndexLp((LPCH) (lpFrom), '\0')+1)
+
+/* bltszLimit: added 4/20/89 to assure safe copying of strings which just
+ might not have fit the terminating zero within their buffer space ..pt */
+#define bltszLimit(pFrom, pTo, cchMax) \
+ bltbyte((pFrom), (pTo), min(cchMax, CchSz(pFrom)))
+
+/* Extra-verbose diagnostic debugging output... */
+
+#ifdef DIAG
+#define Diag(s) s
+#else
+#define Diag(s)
+#endif
+
+#define cwVal (1)
+
+#define CwFromCch(cch) (((cch) + sizeof (int) - 1) / sizeof (int))
+#define FNoHeap(h) ((int)(h) == hOverflow)
+#define iabs(w) ((w) < 0 ? (-(w)) : (w))
+#define low(ch) ((ch) & 0377)
+#define walign(pb) {if ((unsigned)(pb) & 1) \
+ (*((unsigned *)&(pb)))++;}
+#define FtcFromPchp(pchp) (((pchp)->ftcXtra << 6) | (pchp)->ftc)
+#define WFromCh(ch) ((ch) - '0')
+
+#ifndef OURHEAP
+#define FreezeHp() LocalFreeze(0)
+#define MeltHp() LocalMelt(0)
+#else
+#ifdef DEBUG
+#define FreezeHp() { extern int cHpFreeze; ++cHpFreeze; }
+#define MeltHp() { extern int cHpFreeze; --cHpFreeze; }
+#else /* not DEBUG */
+#define FreezeHp()
+#define MeltHp()
+#endif /* not DEBUG */
+#endif
+
+
+#define HideSel()
+
+typeCP CpMacText(), CpFirstFtn(), CpRefFromFtn(), CpFromDlTc(),
+ CpBeginLine(), CpInsertFtn(), CpRSearchSz(),
+ CpLimSty(), CpFirstSty(), CpGetCache(), CpHintCache(),
+ CpEdge(), CpMax(), CpMin();
+
+typeFC FcParaFirst(), FcParaLim(), FcWScratch(), FcNewSect();
+typeFC (**HgfcCollect())[];
+CHAR (**HszCreate())[];
+
+
+#ifndef OURHEAP
+#define FreeH(h) ((FNoHeap(h) || ((int)h == 0)) ? NULL : LocalFree((HANDLE)h))
+#endif
+
+#ifdef DEBUG
+#define Assert(f) _Assert(__FILE__, __LINE__, f)
+#define panic() Assert(false)
+extern _Assert(PCH pch, int line, BOOL f);
+#else /* not DEBUG */
+#define Assert(f)
+#endif /* DEBUG */
+
+#define cbReserve (1024) /* reserved in our local heap */
+ /* for windows to create dialog boxes */
+
+/* The flag KINTL is used to share some code between the international
+ and the kanji Write. */
+
+#ifdef INTL
+#define KINTL
+#endif
+
+extern void Error(IDPMT idpmt);
+
diff --git a/private/mvdm/wow16/write/mwhires.cur b/private/mvdm/wow16/write/mwhires.cur
new file mode 100644
index 000000000..1f5668cb8
--- /dev/null
+++ b/private/mvdm/wow16/write/mwhires.cur
Binary files differ
diff --git a/private/mvdm/wow16/write/mwlores.cur b/private/mvdm/wow16/write/mwlores.cur
new file mode 100644
index 000000000..ab1bcdfec
--- /dev/null
+++ b/private/mvdm/wow16/write/mwlores.cur
Binary files differ
diff --git a/private/mvdm/wow16/write/obj.c b/private/mvdm/wow16/write/obj.c
new file mode 100644
index 000000000..42af71056
--- /dev/null
+++ b/private/mvdm/wow16/write/obj.c
@@ -0,0 +1,2388 @@
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*
+ Some comments on how the Obj subsystem for handling OLE objects
+ is herein implemented.
+
+ Written (2.14.92) by v-dougk (Doug Kent)
+
+ Metafile and bitmaps have always been described in the Write
+ file format (and in memory) by a PICINFOX structure. For OLE
+ objects the PICINFOX structure is replaced by the OBJPICINFO
+ structure of the same size.
+
+ OBJPICINFO has a field (lpObjInfo) which is a pointer to another
+ structure (OBJINFO) which is globally allocated. This structure contains
+ info about the object which doesn't need to be stored in the file
+ with the object data.
+
+ The object data as obtained from OleSaveToStream() is stored in the
+ Write file format immediately following the OBJPICINFO structure.
+ Object data is not actually written to the file until the user
+ does a File.Save. For a newly-created object, the OBJPICINFO structure
+ is the only data saved until that point. If the object is an
+ unfinished one from an Insert.Object operation, then not even the
+ OBJPICINFO structure is saved. In that case the object is solely
+ represented by the OBJINFO structure until an OLE_CHANGED or OLE_SAVED
+ is received. Then an OBJPICINFO structure is saved to the file.
+
+ The OBJINFO structures are allocated for all objects when the file
+ is opened. This involves writing new OBJPICINFO data to the doc
+ (with the new lpObjInfo values) on open. This makes the doc dirty,
+ but we reset the doc dirty flag to make it undirty.
+
+ The lpObjInfo pointers are passed to the OLE create functions for the
+ lpClient value. This is a crucial aspect of the implementation as
+ the CallBack function passes back this pointer, allowing us to identify
+ the object, and query and set its state without having to access
+ the file on disk. As I was not aware of the importance (or existence)
+ of this feature until late, it was patched in. It is not perfectly
+ implemented and could use some polishing.
+
+ As much as I tried to seamlessly integrate objects into the existing
+ Write architecture, there have been glitches:
+
+ 1) Writing into the doc as the visible page is being drawn
+ (See ObjLoadObjectInDoc() in DisplayGraphics() in picture.c)
+ tends to screw things up. The drawing code (namely
+ UpdateWw(), expects certain state variables (like the
+ pedls and the pwwds) to be constant during a single call
+ to UpdateWw(). Writing into the doc alters those variables.
+ Workaround uses vfInvalid in ObjSetPicInfo().
+ 2) Write does not expect data to be entered other than in data
+ currently being displayed on the screen, whereas we
+ frequently operate on objects all over the doc (ObjEnumInDoc()).
+ Workaround is to use ObjCachePara() instead of CachePara().
+ 3) Asynchronicity wreaks havoc on Write. Since every action
+ in Write is affected by the current state, if an action
+ occurs out of normal sequence, i.e., occurs in an improper
+ state, then blamo big trouble. When events happen
+ recursively state variables cannot be restored without a
+ state 'Pushing and Popping' mechanism.
+
+ This is especially true for 'cp' variables. cp's are pointers
+ into the document and global cp state variables are ubiguitous.
+ Global cp variables include the selection and undo variables
+ mentioned above, plus many others. See ObjPopParms() and
+ ObjPushParms().
+
+ While waiting for an object to release (see WMsgLoop()) we
+ stub out WM_PAINT message responses using the nBlocking variable.
+ Between document opening and closing we set the doc fDisplayable
+ flag to FALSE. NOTE: we ought to do something like this in
+ IDPromptBoxSz() -- many of the asynchronicity problems occur
+ when calling MessageBox() (which yields).
+
+ Hopefully OLE 2.0 will implement an OleBlockClient() mechanism.
+
+
+ Notes on Asynchronicity: Ole calls that require communication with the
+ server may be asynchronous. The following rules apply:
+
+ 1) Only one asynchronous call at a time may be made for a given object.
+ 2) The OleCreate* calls must complete before some synchronous
+ calls such as OleGetData().
+ 3) All asynchronous activity must be complete before calling
+ OleRevokeClientDoc.
+
+ Asynchronous calls return OLE_WAIT_FOR_RELEASE. You don't know
+ that an asynchronous call has completed until the CallBack function
+ receives an OLE_RELEASE message for that object. If you ignore this
+ and issue an offending call for the object, the call will
+ return OLE_BUSY.
+
+ We deal with these rules by calling OleQueryReleaseStatus to
+ determine whether an object is busy before making any Ole call
+ (see ObjWaitForObject()). If the object is busy then we spin until the
+ object is not busy. After 6 seconds we put up a msg box which, depending
+ on the flags we set, may allow the user to stop waiting and cancel the
+ operation (see notes in fnObjWait()).
+
+ Note that the OleCreate calls can fail in 3 different ways that aren't
+ documented (not at this point anyway).
+
+ 1) The call returns error immediately. In this case you mustn't depend
+ on the returned lpObject to be NULL. If it is not NULL, ignore
+ it -- it needn't be deleted.
+
+ 2) The call returns OLE_WAIT_FOR_RELEASE and eventually you get an
+ OLE_RELEASE and OleQueryReleaseError() is != OLE_OK. In
+ this case you gotta delete the lpObject that was returned by
+ the original call.
+
+ 3) The call completes, but you receive OLE_CLOSED on the object
+ without receiving OLE_CHANGED. This indicates that for some
+ reason the native data could not be obtained from the server.
+ The object must be deleted in this case. Write currently
+ handles this properly for Insert.Object (OleCreate), but not
+ for other cases (OleCreateFromFile,...).
+
+ The Links dialog should be optimized so that it doesn't require that all
+ links be loaded at once. The Printing process could use the same
+ optimization.
+
+ Cutting, copying and pasting works as follows. Any object that exists
+ in docScrap (where clipboard contents are stored) must be a unique
+ object. Thus when we copy we clone any objects in the selection.
+ When we cut we needn't clone since the objects have been deleted
+ from the document. When we paste we clone.
+
+ Deleted objects and cut objects that get purged from docScrap (and
+ therefore become effectively deleted), are not actually deleted right
+ away. These objects get shovelled into docUndo for access by the
+ Undo function. Even when the objects get purged from docUndo
+ (by another undoable operation), they are still not deleted. These
+ objects never finally get deleted until ObjCollectGarbage() is
+ called. This function is called on a timer about every 5 minutes.
+ It enumerates all documents and deletes any objects not found.
+
+ The reason for not deleting objects right away is that it would've
+ hurt performance to check the contents of docUndo and docScrap
+ every time they change. It also would've been a nasty programming job
+ since those change points are not localized physically or logically.
+*/
+
+#include "windows.h"
+#include "mw.h"
+#include "winddefs.h"
+#include "obj.h"
+#include "menudefs.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "objreg.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include <shellapi.h>
+#include <stdlib.h>
+
+extern struct FCB (**hpfnfcb)[];
+HANDLE hlpObjInfo = NULL; // array of allocated ObjInfos
+LPLPOBJINFO lplpObjInfo = NULL; // array of allocated ObjInfos
+static BOOL bSavedDoc=FALSE;
+static BOOL bDontFix=FALSE;
+int vcObjects=0; // count in doc. Note limit of 32K!!!
+BOOL fOleEnabled=FALSE;
+BOOL bKillMe=FALSE;
+OLECLIENTVTBL clientTbl = {NULL};
+OLESTREAMVTBL streamTbl;
+//LPOLECLIENT lpclient = NULL;
+LPOLESTREAM lpStream = NULL;
+OLECLIPFORMAT vcfLink = 0;
+OLECLIPFORMAT vcfOwnerLink = 0;
+OLECLIPFORMAT vcfNative = 0;
+int cOleWait = 0;
+HWND hwndWait=NULL;
+BOOL vbObjLinkOnly;
+int vObjVerb;
+OBJECTTYPE votObjSelType;
+ATOM aNewName=NULL;
+ATOM aOldName=NULL;
+LHCLIENTDOC lhClientDoc=NULL;
+BOOL bLinkProps=FALSE;
+FARPROC lpfnLinkProps=NULL;
+FARPROC lpfnInvalidLink=NULL;
+FARPROC lpfnInsertNew=NULL;
+FARPROC lpfnWaitForObject=NULL;
+FARPROC lpfnPasteSpecial=NULL;
+static BOOL WMsgLoop ( BOOL fExitOnIdle, BOOL fIgnoreInput, BOOL bOK2Cancel, LPOLEOBJECT lpObject);
+BOOL ObjFreeAllObjInfos();
+static BOOL ObjUpdateAllOpenObjects(void);
+
+int nBlocking=0; // block WM_PAINTS if > 0
+static int nWaitingForObject=0; // in ObjWaitForObject()
+int nGarbageTime=0;
+
+extern struct UAB vuab;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcHourGlass;
+extern int docUndo;
+extern struct PAP vpapAbs;
+extern struct DOD (**hpdocdod)[];
+extern struct WWD rgwwd[];
+extern BOOL ferror;
+extern int vfDeactByOtherApp;
+extern HCURSOR vhcArrow;
+extern HANDLE hStdTargetDevice;
+extern typeCP cpMinCur,cpMacCur;
+
+BOOL fPropsError=FALSE;
+static HANDLE hobjStream = NULL;
+char szOPropMenuStr[21];
+char szPPropMenuStr[21];
+int ObjPlayEdit=OLEVERB_PRIMARY;
+
+int FAR PASCAL CallBack(LPOLECLIENT, OLE_NOTIFICATION, LPOLEOBJECT);
+
+/****************************************************************/
+/******************** STARTUP/SHUTDOWN **************************/
+/****************************************************************/
+BOOL ObjInit(HANDLE hInstance)
+{
+ int bRetval=TRUE;
+
+ vcfLink = RegisterClipboardFormat("ObjectLink");
+ vcfNative = RegisterClipboardFormat("Native");
+ vcfOwnerLink = RegisterClipboardFormat("OwnerLink");
+
+ if ((clientTbl.CallBack = MakeProcInstance(CallBack, hInstance)) == NULL)
+ goto error;
+
+ if ((hobjStream = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(OLESTREAM))) == NULL)
+ goto error;
+
+ ObjSetTargetDevice(FALSE);
+
+ if((lpStream = (LPOLESTREAM)(GlobalLock(hobjStream))) == NULL)
+ goto error;
+ else
+ {
+ lpStream->lpstbl = (LPOLESTREAMVTBL)&streamTbl;
+ lpStream->lpstbl->Get = MakeProcInstance( (FARPROC)BufReadStream, hInstance );
+ lpStream->lpstbl->Put = MakeProcInstance( (FARPROC)BufWriteStream, hInstance);
+ //lpStream->lpstbl->Seek = MakeProcInstance( (FARPROC)BufPosStream, hInstance);
+ }
+
+ /* Initialize the registration database */
+ RegInit(hINSTANCE);
+
+ /* commdlg stuff */
+ OfnInit(hInstance);
+
+ /* dragdrop */
+ DragAcceptFiles(hMAINWINDOW,TRUE);
+
+ if ((hlpObjInfo = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(LPOBJINFO))) == NULL)
+ goto error;
+
+ if ((lplpObjInfo = (LPLPOBJINFO)GlobalLock(hlpObjInfo)) == NULL)
+ goto error;
+
+ if (LoadString(hInstance, IDSTRMenuVerb, szOPropMenuStr, sizeof(szOPropMenuStr)) == NULL)
+ goto error;
+
+ if (LoadString(hInstance, IDSTRMenuVerbP, szPPropMenuStr, sizeof(szPPropMenuStr)) == NULL)
+ goto error;
+
+#if !defined(SMALL_OLE_UI)
+ lpfnLinkProps = MakeProcInstance(fnProperties, hInstance);
+#endif
+ lpfnInvalidLink = MakeProcInstance(fnInvalidLink, hInstance);
+ lpfnInsertNew = MakeProcInstance(fnInsertNew, hInstance);
+ lpfnWaitForObject = MakeProcInstance(fnObjWait, hInstance);
+ lpfnPasteSpecial = MakeProcInstance(fnPasteSpecial, hInstance);
+
+ goto end;
+
+ error:
+ bRetval = FALSE;
+ ObjShutDown();
+
+ end:
+ return bRetval;
+}
+
+void ObjShutDown(void)
+{
+ extern HANDLE vhMenu;
+
+ if (vhMenu)
+ DeleteMenu(GetSubMenu(vhMenu,EDIT), EDITMENUPOS, MF_BYPOSITION);
+
+ if (hobjStream)
+ {
+ if (lpStream)
+ if (lpStream->lpstbl)
+ {
+ if (lpStream->lpstbl->Get)
+ FreeProcInstance((FARPROC)(lpStream->lpstbl->Get));
+ if (lpStream->lpstbl->Put)
+ FreeProcInstance((FARPROC)(lpStream->lpstbl->Put));
+ }
+
+ GlobalUnlock(hobjStream);
+ if (lpStream)
+ GlobalFree(hobjStream);
+ }
+
+ if (hStdTargetDevice)
+ GlobalFree(hStdTargetDevice);
+
+ if (clientTbl.CallBack)
+ FreeProcInstance(clientTbl.CallBack);
+
+ if (lpfnLinkProps)
+ FreeProcInstance(lpfnLinkProps);
+ if (lpfnInvalidLink)
+ FreeProcInstance(lpfnInvalidLink);
+ if (lpfnInsertNew)
+ FreeProcInstance(lpfnInsertNew);
+ if (lpfnWaitForObject)
+ FreeProcInstance(lpfnWaitForObject);
+ if (lpfnPasteSpecial)
+ FreeProcInstance(lpfnPasteSpecial);
+
+ RegTerm();
+
+ /* dragdrop */
+ DragAcceptFiles(hMAINWINDOW,FALSE);
+
+ /* make sure all OInfo structures are freed */
+ ObjFreeAllObjInfos();
+
+ if (hlpObjInfo)
+ GlobalFree(hlpObjInfo);
+}
+
+#if 0
+BOOL ObjFreeObjInfo(OBJPICINFO *pPicInfo)
+/* return whether an error */
+{
+ LPLPOBJINFO lplpObjTmp;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return FALSE;
+
+ /* find slot in lplpObjInfo and NULL it out */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ if (*lplpObjTmp == lpOBJ_QUERY_INFO(pPicInfo))
+ {
+ lpOBJ_QUERY_INFO(pPicInfo) = NULL;
+
+ return ObjDeleteObjInfo(*lplpObjTmp);
+ }
+
+ Assert(0); // make sure we found it
+ return TRUE;
+}
+#endif
+
+BOOL ObjUpdateFromObjInfo(OBJPICINFO *pPicInfo)
+/* update picinfo from objinfo */
+{
+ char *pdumb;
+ szOBJNAME szObjName;
+ LPOBJINFO lpObjInfo = lpOBJ_QUERY_INFO(pPicInfo);
+
+ if (lpObjInfo == NULL)
+ return TRUE;
+
+ /* we won't do data size, that'll get set in SaveObjectToDoc */
+
+ /* object name */
+ if (lpObjInfo->aObjName)
+ {
+ GetAtomName(lpObjInfo->aObjName,szObjName,sizeof(szObjName));
+ pPicInfo->dwObjNum = strtoul(szObjName,&pdumb,16);
+ }
+
+ /* object type */
+ pPicInfo->objectType = lpObjInfo->objectType;
+
+ return FALSE;
+}
+
+BOOL ObjUpdateFromPicInfo(OBJPICINFO *pPicInfo,szOBJNAME szObjName)
+/* update objinfo from picInfo, return szObjName */
+{
+ char *pdumb;
+ LPOBJINFO lpObjInfo = lpOBJ_QUERY_INFO(pPicInfo);
+ szOBJNAME szTmp;
+
+ if (lpObjInfo == NULL)
+ return TRUE;
+
+ /* object name */
+ wsprintf(szTmp, "%lx", dwOBJ_QUERY_OBJECT_NUM(pPicInfo));
+ lpObjInfo->aObjName = AddAtom(szTmp);
+
+ if (szObjName)
+ lstrcpy(szObjName,szTmp);
+
+ /* object type */
+ lpObjInfo->objectType = pPicInfo->objectType;
+
+ return FALSE;
+}
+
+BOOL ObjFreeObjInfoWithObject(LPOLEOBJECT lpObject)
+/**
+ Given lpObject, find lpObjInfo for that object and free the ObjInfo.
+ Return whether an error.
+ This deletes objects if not already deleted.
+ **/
+{
+ LPLPOBJINFO lplpObjTmp;
+
+ /* find slot in lplpObjInfo, free it and NULL it out */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if ((*lplpObjTmp)->lpobject == lpObject)
+ return ObjDeleteObjInfo(*lplpObjTmp);
+ }
+
+#ifdef DEBUG
+ OutputDebugString("No OInfo for object\n\r");
+#endif
+ return TRUE;
+}
+
+BOOL ObjDeleteObjInfo(LPOBJINFO lpOInfo)
+{
+ WORD wSegment;
+ HANDLE hInfo;
+ LPLPOBJINFO lplpObjTmp;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Nulling objinfo slot.\n\r");
+#endif
+
+ /* find slot in lplpObjInfo, free it and NULL it out */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if (*lplpObjTmp == lpOInfo)
+ break;
+ }
+
+ if (lplpObjTmp == NULL) // hmmm, shouldn't happen
+ {
+ Assert(0);
+ return NULL;
+ }
+
+ if ((*lplpObjTmp)->aName)
+ DeleteAtom((*lplpObjTmp)->aName);
+ if ((*lplpObjTmp)->aObjName)
+ DeleteAtom((*lplpObjTmp)->aObjName);
+ wSegment = HIWORD(((DWORD)*lplpObjTmp));
+
+ *lplpObjTmp = NULL;
+
+ hInfo = GlobalHandle(wSegment) & 0xFFFFL;
+ return (BOOL)GlobalFree(hInfo);
+}
+
+LPOBJINFO ObjGetObjInfo(szOBJNAME szObjName)
+/* allocate objinfo, return szObjName if !NULL */
+{
+ HANDLE hObjInfo=NULL;
+ DWORD dwCount,dwCountSave;
+ LPLPOBJINFO lplpObjTmp;
+ LPOBJINFO lpObjInfoNew=NULL;
+
+ if (lplpObjInfo == NULL)
+ return NULL;
+
+ if ((hObjInfo = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, sizeof(OBJINFO))) == NULL)
+ {
+ /* gotta recover better here !!! (7.5.91) v-dougk */
+ Error(IDPMTCantRunM);
+ return NULL;
+ }
+
+ if ((lpObjInfoNew = (LPOBJINFO)GlobalLock(hObjInfo)) == NULL)
+ {
+ /* gotta recover better here !!! (7.5.91) v-dougk */
+ Error(IDPMTCantRunM);
+ GlobalFree(hObjInfo);
+ return NULL;
+ }
+
+ /* now add to lplpObjInfo array */
+ dwCount = dwCountSave = GlobalSize(hlpObjInfo) / sizeof(LPLPOBJINFO);
+
+ /* find if any NULL slots */
+ for (lplpObjTmp = lplpObjInfo; dwCount ; --dwCount, ++lplpObjTmp)
+ if (*lplpObjTmp == NULL)
+ break;
+
+ if (dwCount) // then found a NULL slot
+ {
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Adding objinfo to empty slot.\n\r");
+#endif
+ *lplpObjTmp = lpObjInfoNew;
+ }
+ else // gotta reallocate
+ {
+ ++dwCountSave;
+ if ((hlpObjInfo = GlobalRealloc(hlpObjInfo,dwCountSave * sizeof(LPLPOBJINFO),GMEM_MOVEABLE|GMEM_ZEROINIT)) == NULL)
+ {
+ /* gotta recover better here !!! (7.5.91) v-dougk */
+ GlobalFree(hObjInfo);
+ lplpObjInfo = NULL;
+ Error(IDPMTCantRunM);
+ return NULL;
+ }
+ if ((lplpObjInfo = (LPLPOBJINFO)GlobalLock(hlpObjInfo)) == NULL)
+ {
+ /* gotta recover better here !!! (7.5.91) v-dougk */
+ GlobalFree(hObjInfo);
+ Error(IDPMTCantRunM);
+ return NULL;
+ }
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Adding objinfo to new slot.\n\r");
+#endif
+ /* put new gal in last slot */
+ lplpObjInfo[dwCountSave-1] = lpObjInfoNew;
+ }
+
+ if (szObjName)
+ /* make object's unique name */
+ ObjMakeObjectName(lpObjInfoNew, szObjName);
+ else
+ lpObjInfoNew->aObjName = NULL;
+
+ /* this is a requirement of the OLECLIENT structure */
+ lpObjInfoNew->lpvtbl = (LPOLECLIENTVTBL)&clientTbl;
+
+ return lpObjInfoNew;
+}
+
+BOOL ObjAllocObjInfo(OBJPICINFO *pPicInfo, typeCP cpParaStart, OBJECTTYPE ot, BOOL bInitPicinfo, szOBJNAME szObjName)
+/* return whether an error */
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) = ObjGetObjInfo(NULL))
+ {
+ //cpOBJ_QUERY_WHERE(pPicInfo) = cpParaStart;
+
+ if (bInitPicinfo)
+ /* new object, make a new szObjName, use passed-in ot */
+ {
+ /* get new values and put into ObjInfo */
+ if (szObjName)
+ ObjMakeObjectName(lpOBJ_QUERY_INFO(pPicInfo), szObjName);
+
+ lpOBJ_QUERY_INFO(pPicInfo)->objectType = ot;
+
+ /* this'll take values from ObjInfo and put into PicInfo */
+ return GimmeNewPicinfo(pPicInfo,lpOBJ_QUERY_INFO(pPicInfo));
+ }
+ else // picInfo already has values. Put 'em into ObjInfo
+ {
+ ObjUpdateFromPicInfo(pPicInfo,szObjName);
+ return FALSE;
+ }
+ }
+ else
+ return TRUE;
+
+}
+
+
+BOOL ObjCloneObjInfo(OBJPICINFO *pPicInfo, typeCP cpParaStart, szOBJNAME szObjName)
+/* clone pPicInfo->lpObjInfo */
+{
+ if (ObjCopyObjInfo(lpOBJ_QUERY_INFO(pPicInfo),
+ &lpOBJ_QUERY_INFO(pPicInfo),
+ szObjName))
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ObjCopyObjInfo(LPOBJINFO lpOldObjInfo,
+ LPLPOBJINFO lplpNewObjInfo,
+ szOBJNAME szObjName)
+/* lpobject field is NULL'd! Atoms are cloned, new unique object name */
+{
+ char szTmp[180];
+
+ if (lplpObjInfo == NULL)
+ return TRUE;
+
+ if ((*lplpNewObjInfo = ObjGetObjInfo(NULL)) == NULL)
+ return TRUE;
+
+ /* copy old stuff over to new */
+ /* note new will inherit old lpclone if there is one */
+ **lplpNewObjInfo = *lpOldObjInfo;
+
+ (*lplpNewObjInfo)->lpobject = NULL;
+
+ /* clone the utility (class or whatever) name */
+ if (lpOldObjInfo->aName)
+ {
+ GetAtomName(lpOldObjInfo->aName,szTmp,sizeof(szTmp));
+ (*lplpNewObjInfo)->aName = AddAtom(szTmp);
+ }
+
+ /* make a new ObjName if requested */
+ if (szObjName)
+ /* make object's unique name */
+ ObjMakeObjectName(*lplpNewObjInfo, szObjName);
+ else
+ (*lplpNewObjInfo)->aObjName = NULL;
+
+ return FALSE;
+}
+
+BOOL ObjFreeAllObjInfos()
+/**
+ Return whether an error.
+ **/
+{
+ WORD wSegment;
+ HANDLE hInfo;
+ DWORD dwCount;
+ LPLPOBJINFO lplpObjTmp;
+
+ if (lplpObjInfo == NULL)
+ return FALSE;
+
+ /* find slot in lplpObjInfo, free it and NULL it out */
+ dwCount = GlobalSize(hlpObjInfo) / sizeof(LPLPOBJINFO);
+ for (lplpObjTmp = lplpObjInfo; dwCount ; --dwCount, ++lplpObjTmp)
+ {
+ if (*lplpObjTmp)
+ {
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Nulling objinfo slot (from object).\n\r");
+#endif
+ /** Delete info about this object. This assumes picinfo will not
+ be reused unless via file.open. **/
+ if ((*lplpObjTmp)->aName)
+ DeleteAtom((*lplpObjTmp)->aName);
+ if ((*lplpObjTmp)->aObjName)
+ DeleteAtom((*lplpObjTmp)->aObjName);
+ wSegment = HIWORD(((DWORD)*lplpObjTmp));
+ *lplpObjTmp = NULL;
+ hInfo = GlobalHandle(wSegment) & 0xFFFF;
+ GlobalFree(hInfo);
+ }
+ }
+ return FALSE;
+}
+
+LPLPOBJINFO EnumObjInfos(LPLPOBJINFO lplpObjInfoPrev)
+{
+ LPLPOBJINFO lplpOIMax;
+
+ if (lplpObjInfo == NULL)
+ return NULL;
+
+ if (lplpObjInfoPrev == NULL) // starting out
+ lplpObjInfoPrev = lplpObjInfo;
+ else
+ ++lplpObjInfoPrev;
+
+ lplpOIMax = (LPLPOBJINFO)((LPSTR)lplpObjInfo + GlobalSize(hlpObjInfo));
+
+ for ( ; lplpObjInfoPrev < lplpOIMax ; ++lplpObjInfoPrev)
+ {
+ if (*lplpObjInfoPrev == NULL)
+ continue;
+ else
+ return lplpObjInfoPrev;
+ }
+ return NULL;
+}
+
+
+void ObjCollectGarbage()
+{
+ LPLPOBJINFO lplpObjTmp;
+ int nObjCount=0,doc;
+
+ if (nBlocking)
+ return;
+
+ StartLongOp();
+
+#ifdef DEBUG
+ OutputDebugString("Collecting Garbage...\n\r");
+#endif
+
+ ObjPushParms(docCur);
+
+ /* mark all as not in doc */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ ++nObjCount;
+ (*lplpObjTmp)->fInDoc = FALSE;
+ }
+
+ if (nObjCount == 0)
+ goto end;
+
+ /* mark in doc if in */
+ /* go through all the docs */
+ for (doc = 0; doc < docMac; doc++)
+ {
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+
+ if ((doc != docNil) && (**hpdocdod)[doc].hpctb)
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cp0,CpMacText(doc),&cpPicInfo);
+ )
+ {
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ continue;
+
+ fOBJ_INDOC(&picInfo) = TRUE;
+ }
+ }
+
+
+ /* if not in doc delete */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if (!(*lplpObjTmp)->fInDoc)
+ ObjDeleteObject(*lplpObjTmp,TRUE);
+ }
+
+ end:
+
+ /* 'til next time... */
+ nGarbageTime=0;
+
+ ObjPopParms(TRUE);
+
+ EndLongOp(vhcArrow);
+}
+
+/****************************************************************/
+/********************** OLE DOCUMENT FUNCTIONS ******************/
+/****************************************************************/
+BOOL ObjClosingDoc(int docOld,LPSTR szNewDocName)
+/**
+ Clone objects in docScrap from docOld into szNewDocName.
+ Release all objects in docOld.
+ Return whether an error occurred. Error indicates to caller that
+ a new document cannot be opened. No error indicates to caller
+ that a new document *must* be reopened via ObjOpenedDoc() (because
+ all lpObjInfos have been deleted).
+ If szNewDocName is NULL then don't make a new doc.
+ Important point to remember is that for objects whose data has never
+ been saved, there is no recovery from release/delete in an error
+ condition. There is no state to which we can recover in an
+ error condition. This function should not be allowed to exit
+ on the basis of a busy object.
+ **/
+{
+ char szTitle[120];
+ BOOL bRetval=FALSE;
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ extern int vfScrapIsPic;
+ extern int docScrap;
+ extern int vfOwnClipboard;
+ extern CHAR szUntitled[];
+ LPOBJINFO lpObjInfo;
+ LPOLEOBJECT lpObject;
+ LHCLIENTDOC lhNewClientDoc=NULL;
+ OLESTATUS olestat;
+ LPLPOBJINFO lplpObjTmp;
+
+ if (!lhClientDoc)
+ return FALSE;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Closing Doc\n\r");
+#endif
+
+ /* ensure all async ops are complete */
+ if (FinishAllAsyncs(TRUE))
+ {
+ UPDATE_INVALID();
+ return TRUE;
+ }
+
+ ++nBlocking; // inhibit repaints
+
+ /* drag drop */
+ DragAcceptFiles(hDOCWINDOW,FALSE);
+
+ if (szNewDocName)
+ /* then we'll be opening another doc soon, so plan ahead */
+ {
+ if (!szNewDocName[0])
+ lstrcpy((LPSTR)szTitle,(LPSTR)szUntitled);
+ else
+ lstrcpy((LPSTR)szTitle,szNewDocName);
+
+ if (ObjError(OleRegisterClientDoc(szDOCCLASS,szTitle,0L,&lhNewClientDoc)))
+ {
+ lhNewClientDoc = NULL; // just in case OLE flatlined
+ goto error;
+ }
+
+ /**
+ Clone any objects from docScrap into new doc. Since this
+ requires knowing the name of the new doc you
+ would think it should go into ObjOpeningDoc, but it can't.
+ You have to do it *before* releasing the objects below!
+ (Because OleEnumObjects keys off of the lhClientDoc).
+ **/
+ ObjCloneScrapToNewDoc(lhNewClientDoc);
+
+ /* ensure all async ops are complete */
+ if (FinishAllAsyncs(FALSE))
+ goto error;
+ }
+
+
+ /* release objects in docOld (assume not busy) */
+ if ((**hpdocdod)[docOld].fFormatted)
+ {
+ /* objects are being released/deleted, don't allow display */
+ (**hpdocdod)[docOld].fDisplayable = FALSE;
+
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docOld,cp0,CpMacText(docOld),&cpPicInfo);
+ )
+ {
+ lpObjInfo=lpOBJ_QUERY_INFO(&picInfo);
+
+ if (lpObjInfo == NULL)
+ continue;
+
+ if (lpObjInfo->lpobject == NULL)
+ continue;
+
+ #ifdef DEBUG
+ OutputDebugString( (LPSTR) "Releasing object\n\r");
+ #endif
+
+ switch (olestat = OleRelease(lpObjInfo->lpobject))
+ {
+ case OLE_OK:
+ lpObjInfo->lpobject = NULL;
+ break;
+ case OLE_WAIT_FOR_RELEASE:
+ lpObjInfo->fCompleteAsync = TRUE;
+ /* No cancel allowed! */
+ if (ObjWaitForObject(lpObjInfo,FALSE))
+ goto error;
+ else
+ lpObjInfo->lpobject = NULL;
+ break;
+ }
+ }
+ }
+
+ if (FinishAllAsyncs(FALSE)) // necessary?
+ goto error;
+
+ /* delete remaining objects in lhClientDoc (assume not busy) */
+ lpObject=NULL;
+ do
+ {
+ lpObject=NULL;
+ OleEnumObjects(lhClientDoc,&lpObject);
+ if (lpObject)
+ {
+ lpObjInfo = GetObjInfo(lpObject);
+ switch (olestat = OleDelete(lpObject))
+ {
+ case OLE_OK:
+ if (lpObjInfo)
+ lpObjInfo->lpobject = NULL;
+ break;
+ case OLE_WAIT_FOR_RELEASE:
+ if (lpObjInfo)
+ {
+ lpObjInfo->fCompleteAsync = TRUE;
+ /* no cancel allowed! */
+ if (ObjWaitForObject(lpObjInfo,FALSE))
+ goto error;
+ else
+ lpObjInfo->lpobject = NULL;
+ }
+ else
+ FinishUp();
+ break;
+ default:
+ ObjError(olestat);
+ goto error;
+ }
+ }
+ }
+ while (lpObject);
+
+ /* say goodbye to old doc if there was one */
+ if (!bSavedDoc)
+ {
+ ObjRevertedDoc();
+ bSavedDoc=FALSE;
+ }
+
+#ifdef DEBUG
+ OutputDebugString("Revoking doc\n\r");
+#endif
+
+ if (ObjError(OleRevokeClientDoc(lhClientDoc)))
+ goto error;
+
+ lhClientDoc = lhNewClientDoc;
+
+ /**
+ Delete all the lpObjInfos having NULL lpobjects (non-NULLs
+ belong to docScrap). Make damn sure that ObjOpenedDoc is
+ called if this doc is reopened. This is the point of no return.
+ **/
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ if ((*lplpObjTmp)->lpobject == NULL)
+ ObjDeleteObjInfo(*lplpObjTmp);
+
+ goto end;
+
+ error:
+ bRetval = TRUE;
+
+ if (lhNewClientDoc)
+ {
+ OleRevokeClientDoc(lhNewClientDoc);
+ /**
+ If any objects are in the scrap, they must be made to belong to
+ lhClientDoc, or be deleted.
+ **/
+ ObjCloneScrapToNewDoc(lhClientDoc);
+ }
+
+ end:
+
+ --nBlocking; // reenable repaints
+ UPDATE_INVALID(); // let WM_PAINTS get through now that we're no longer blocking
+
+ return bRetval;
+}
+
+BOOL ObjOpenedDoc(int doc)
+/*
+ Return whether error that precludes continuing with opening this doc.
+ If an error, then a new doc *must* be opened via ObjOpenedDoc(). We
+ will clean this doc up to closed state if couldn't open it (ie,
+ delete all objects and lpObjInfos).
+*/
+{
+ BOOL bRetval=FALSE,bLinkError=FALSE;
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ BOOL bPrompted=FALSE;
+ char szMsg[cchMaxSz];
+ extern CHAR szUntitled[];
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Opened Doc\n\r");
+#endif
+
+ /* prevent display until done updating */
+ ++nBlocking;
+
+ StartLongOp();
+
+ /* start collection timer all over */
+ nGarbageTime=0;
+
+ /* in case contains any picInfos left over from previous doc */
+ ClobberDoc(docUndo,docNil,cp0,cp0);
+
+ /* drag drop */
+ DragAcceptFiles(hDOCWINDOW,TRUE);
+
+ if (!lhClientDoc)
+ if (ObjError(OleRegisterClientDoc(szDOCCLASS,szUntitled,0L,&lhClientDoc)))
+ goto error;
+
+ /* Do this first because much code assumes every picInfo has an
+ lpObjInfo associated with it */
+ if ((**hpdocdod)[doc].fFormatted)
+ {
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cp0,CpMacText(doc),&cpPicInfo);
+ )
+ {
+ if (ObjAllocObjInfo(&picInfo,cpPicInfo,picInfo.objectType,FALSE,NULL))
+ goto error; // this is a real problem condition
+
+ /* note this makes doc dirty right off the bat, but gotta do it because
+ we gotta save ObjInfo handle in doc. (8.20.91) v-dougk */
+ if (ObjSetPicInfo(&picInfo, doc, cpPicInfo))
+ goto error;
+ }
+
+ /* OK to display. Any error hereafter is not fatal. */
+ (**hpdocdod)[doc].fDisplayable = TRUE;
+
+#if !defined(SMALL_OLE_UI)
+
+ /**** Now see if links need updating ****/
+ bDontFix=TRUE; // don't bring up change links on release error
+
+ if ((**hpdocdod)[doc].fFormatted)
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cp0,CpMacText(doc),&cpPicInfo);
+ )
+ {
+ if (otOBJ_QUERY_TYPE(&picInfo) == LINK)
+ if (ObjLoadObjectInDoc(&picInfo, doc, cpPicInfo) != cp0)
+ {
+ OLESTATUS olestat;
+
+ if (!bPrompted)
+ {
+ LoadString(hINSTANCE, IDSTRUpdateObject, szMsg, sizeof(szMsg));
+ if (MessageBox(hPARENTWINDOW, (LPSTR)szMsg, (LPSTR)szAppName, MB_YESNO|MB_ICONEXCLAMATION) == IDYES)
+ bPrompted = TRUE;
+ else
+ break; // no updating requested
+ }
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Updating link\n\r");
+#endif
+ if (ObjError(OleUpdate(lpOBJ_QUERY_OBJECT(&picInfo))))
+ {
+ bLinkError = TRUE;
+ fOBJ_BADLINK(&picInfo) = TRUE; // in case didn't get release, gotta set
+ ferror = FALSE; // to reenable error messages
+ }
+ }
+ else /* if load object failed, then give up */
+ {
+ bLinkError = FALSE; /* Don't put up Links dialog */
+ goto end; /* Not fatal, though they need to reopen doc
+ after freeing memory */
+ }
+ }
+ bDontFix=FALSE;
+#endif
+ }
+ else /* OK to display. */
+ (**hpdocdod)[doc].fDisplayable = TRUE;
+
+ goto end;
+
+ error:
+ bRetval = TRUE;
+
+ end:
+
+ if (bLinkError)
+ /* fix 'em */
+ {
+ if (DialogBox(hINSTANCE, "DTINVALIDLINKS",
+ hPARENTWINDOW, lpfnInvalidLink) == IDD_CHANGE)
+ fnObjProperties();
+ }
+
+ --nBlocking;
+ EndLongOp(vhcArrow);
+
+ UPDATE_INVALID(); // let WM_PAINTS get through now that we're no longer blocking
+
+ return bRetval;
+}
+
+
+BOOL ObjSavingDoc(BOOL bFormatted)
+/* return whether there was an error */
+{
+ /* drag drop */
+ DragAcceptFiles(hDOCWINDOW,FALSE);
+
+ /* update any other objects */
+
+ vcObjects = 0;
+ if (bFormatted)
+ vcObjects = ObjEnumInDoc(docCur,ObjSaveObjectToDoc);
+
+ return (vcObjects < 0); // return whether error
+}
+
+void ObjSavedDoc(void)
+{
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Saved Doc\n\r");
+#endif
+
+ if (lhClientDoc)
+ ObjError(OleSavedClientDoc(lhClientDoc));
+ bSavedDoc=TRUE;
+
+ /* drag drop */
+ DragAcceptFiles(hDOCWINDOW,TRUE);
+}
+
+static BOOL ObjUpdateAllOpenObjects(void)
+/* Update all open embedded objects. Return whether successful.
+ Called on file.close. */
+{
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ BOOL bRetval=TRUE;
+
+ StartLongOp();
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docCur,cp0,CpMacText(docCur),&cpPicInfo);
+ )
+ {
+ if (((otOBJ_QUERY_TYPE(&picInfo) == NONE) ||
+ (otOBJ_QUERY_TYPE(&picInfo) == EMBEDDED)) &&
+ (OleQueryOpen(lpOBJ_QUERY_OBJECT(&picInfo)) == OLE_OK))
+ {
+ fnObjUpdate(lpOBJ_QUERY_INFO(&picInfo));
+ }
+ }
+
+ end:
+
+ /* To make sure we've gotten all messages relevant to calling
+ ObjObjectHasChanged() and setting doc dirty. */
+ if (FinishAllAsyncs(TRUE))
+ bRetval = FALSE;
+
+ EndLongOp(vhcArrow);
+ UPDATE_INVALID(); // let WM_PAINTS get through now that we're no longer blocking
+ return bRetval;
+}
+
+
+BOOL CloseUnfinishedObjects(BOOL bSaving)
+/**
+ Used with File.Save or File.Exit.
+ Return TRUE whether should proceed with Save/Exit.
+ **/
+{
+ char szMsg[cchMaxSz];
+
+ if (ObjContainsOpenEmb(docCur, cp0, CpMacText(docCur),TRUE))
+ {
+ if (bSaving)
+ LoadString(hINSTANCE, IDPMTSaveOpenEmb, szMsg, sizeof(szMsg));
+ else
+ LoadString(hINSTANCE, IDPMTExitOpenEmb, szMsg, sizeof(szMsg));
+
+ switch (MessageBox(hPARENTWINDOW, (LPSTR)szMsg, (LPSTR)szAppName, MB_YESNOCANCEL))
+ {
+ case IDYES:
+ return ObjUpdateAllOpenObjects();
+ case IDNO:
+ default:
+ return TRUE;
+ case IDCANCEL:
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void ObjRenamedDoc(LPSTR szNewName)
+{
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Renamed Doc\n\r");
+#endif
+ if (lhClientDoc)
+ ObjError(OleRenameClientDoc(lhClientDoc,szNewName));
+
+ /* don't need to do all docs since objects can only be active in docCur */
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docCur,cp0,CpMacText(docCur),&cpPicInfo);
+ )
+ /* ignore return value on purpose */
+ ObjSetHostNameInDoc(&picInfo,docCur,cpPicInfo);
+}
+
+void ObjRevertedDoc()
+{
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Reverted Doc\n\r");
+#endif
+ if (lhClientDoc)
+ ObjError(OleRevertClientDoc(lhClientDoc));
+}
+
+/****************************************************************/
+/*********************** ERROR HANDLING *************************/
+/****************************************************************/
+BOOL FAR
+ObjError(OLESTATUS olestat)
+{
+ register HWND hWndParent = hPARENTWINDOW;
+
+ switch (olestat) {
+ case OLE_WAIT_FOR_RELEASE:
+ case OLE_OK:
+ return FALSE;
+ }
+
+ ferror = FALSE; // to enable error message
+
+ switch (olestat) {
+ case OLE_ERROR_LAUNCH:
+ Error(IDPMTFailedToLaunchServer);
+ break;
+
+ case OLE_ERROR_COMM:
+ Error(IDPMTFailedToCommWithServer);
+ break;
+
+ case OLE_ERROR_MEMORY:
+ Error(IDPMTWinFailure);
+ break;
+
+ case OLE_BUSY:
+ Error(IDPMTServerBusy);
+ break;
+
+ case OLE_ERROR_FORMAT:
+ Error(IDPMTFormat);
+ break;
+
+ case OLE_ERROR_DRAW:
+ Error(IDPMTFailedToDraw);
+ break;
+
+ default:
+#ifdef DEBUG
+ ObjPrintError(olestat,FALSE);
+#endif
+
+ Error(IDPMTOLEError);
+ break;
+ }
+ return TRUE;
+}
+
+void
+ObjReleaseError(OLE_RELEASE_METHOD rm)
+/*
+ There's an async problem here, in that the posted message
+ that invokes this routine may be allowed through by Error() which
+ isn't reentrant (or at least causes problems when called recursively).
+*/
+{
+ register HWND hWndParent = hPARENTWINDOW;
+
+ switch (rm) {
+
+ case OLE_DELETE:
+ Error(IDPMTFailedToDeleteObject);
+ break;
+
+ case OLE_LOADFROMSTREAM:
+ Error(IDPMTFailedToReadObject);
+ break;
+
+ case OLE_LNKPASTE:
+ case OLE_EMBPASTE:
+ Error(IDPMTGetFromClipboardFailed);
+ break;
+
+ case OLE_ACTIVATE:
+ Error(IDPMTFailedToLaunchServer);
+ break;
+
+ case OLE_UPDATE:
+ Error(IDPMTFailedToUpdate);
+ break;
+
+ case OLE_CREATE:
+ case OLE_CREATELINKFROMFILE:
+ case OLE_CREATEFROMFILE:
+ Error(IDPMTFailedToCreateObject);
+ break;
+
+ case OLE_SETUPDATEOPTIONS:
+ Error(IDPMTImproperLinkOptionsError);
+ break;
+
+ default:
+ Error(IDPMTOLEError);
+ break;
+ }
+#ifdef DEBUG
+ ObjPrintError(rm,TRUE);
+#endif
+}
+
+#ifdef DEBUG
+void ObjPrintError(WORD olestat, BOOL bRelease)
+{
+ #define szMsgMax 100
+ char szError[szMsgMax];
+ if (!bRelease)
+ wsprintf(szError, "***Ole Error #%d\n\r",olestat);
+ else
+ wsprintf(szError, "***Ole Release Error on Method #%d\n\r",olestat);
+ OutputDebugString(szError);
+}
+#endif
+
+/****************************************************************/
+/***************** ASYNCRONICITY HANDLING ***********************/
+/****************************************************************/
+int FAR PASCAL
+CallBack(LPOLECLIENT lpclient,
+ OLE_NOTIFICATION flags,
+ LPOLEOBJECT lpObject)
+{
+ extern int vdocParaCache;
+ LPOBJINFO lpOInfo = (LPOBJINFO)lpclient;
+
+ switch(flags)
+ {
+ case OLE_SAVED:
+ case OLE_CLOSED:
+ case OLE_CHANGED:
+ /**
+ Post a message instead of process here because we have to return from
+ CallBack before making any other OLE calls.
+ **/
+#ifdef DEBUG
+ OutputDebugString(flags == OLE_CHANGED ? "received OLE_CHANGED\n\r" :
+ flags == OLE_SAVED ? "received OLE_SAVED\n\r" :
+ "received OLE_CLOSED\n\r");
+#endif
+ PostMessage(hDOCWINDOW,WM_OBJUPDATE,flags,(DWORD)lpOInfo);
+ break;
+
+ case OLE_RELEASE:
+ {
+ OLE_RELEASE_METHOD ReleaseMethod = OleQueryReleaseMethod(lpObject);
+
+ if (!CheckPointer((LPSTR)lpOInfo,1))
+ return FALSE;
+
+ lpOInfo->fKillMe = FALSE; // pending async is dead
+
+ if (lpOInfo->fDeleteMe && (ReleaseMethod != OLE_DELETE)) // not dead enough
+ {
+ PostMessage(hDOCWINDOW,WM_OBJDELETE,1,(DWORD)lpOInfo);
+ return FALSE; // error message will already have been given
+ }
+
+ if (lpOInfo->fReleaseMe && (ReleaseMethod != OLE_DELETE)) // not dead enough
+ {
+ PostMessage(hDOCWINDOW,WM_OBJDELETE,0,(DWORD)lpOInfo);
+ return FALSE; // error message will already have been given
+ }
+
+ if (lpOInfo->fFreeMe && (ReleaseMethod == OLE_DELETE)) // on OLE_DELETE release
+ {
+ ObjDeleteObjInfo(lpOInfo);
+ return FALSE;
+ }
+
+ if (OleQueryReleaseError(lpObject) == OLE_OK)
+ {
+ switch (ReleaseMethod)
+ {
+ case OLE_SETUPDATEOPTIONS:
+ {
+ if (bLinkProps) // we're in Link Properties dialog
+ {
+ PostMessage(hPARENTWINDOW, WM_UPDATELB, 0, 0L);
+ PostMessage(hPARENTWINDOW, WM_COMMAND, IDD_REFRESH, (DWORD)lpOInfo);
+ }
+ }
+ break;
+
+ case OLE_UPDATE:
+ ObjInvalidateObj(lpObject);
+ break;
+
+ case OLE_DELETE: // get this for delete and release
+ lpOInfo->lpobject = NULL;
+ break;
+ }
+ }
+ else // release error != OLE_OK
+ {
+#ifdef DEBUG
+ PostMessage(hDOCWINDOW,WM_OBJERROR,ReleaseMethod,0L);
+#endif
+
+ switch(ReleaseMethod)
+ {
+ case OLE_CREATE:
+ case OLE_CREATELINKFROMFILE:
+ case OLE_CREATEFROMFILE:
+ /*
+ OleQueryReleaseError won't help us after callback returns
+ so this is how we tell that the object wasn't created.
+ */
+ lpOInfo->fDeleteMe = TRUE;
+ // creator should ObjDeleteObject and issue error message
+ break;
+
+ default:
+ switch (OleQueryReleaseError(lpObject))
+ {
+ case OLE_ERROR_OPEN:
+ case OLE_ERROR_ADVISE_NATIVE:
+ case OLE_ERROR_ADVISE_PICT:
+ case OLE_ERROR_REQUEST_NATIVE:
+ case OLE_ERROR_REQUEST_PICT:
+ /**
+ Post a message instead of process here because we have to return from
+ CallBack before making any other OLE calls.
+ **/
+ if (lpOInfo->objectType == LINK)
+ lpOInfo->fBadLink = TRUE;
+ if (bLinkProps)
+ fPropsError = TRUE; // so linkprops knows there was a problem
+ else if (!bDontFix && (lpOInfo->objectType == LINK))
+ PostMessage(hDOCWINDOW,WM_OBJBADLINK,OleQueryReleaseMethod(lpObject),(DWORD)lpObject);
+ break;
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case OLE_QUERY_RETRY:
+ {
+ Assert(CheckPointer((LPSTR)lpOInfo,1));
+
+ if (lpOInfo->fKillMe)
+ {
+ lpOInfo->fKillMe = FALSE;
+ return FALSE;
+ }
+ else if (hwndWait)
+ PostMessage(hwndWait,WM_UKANKANCEL,0,0L);
+ else if (nWaitingForObject == 0)
+ PostMessage(hDOCWINDOW,WM_WAITFORSERVER,TRUE,(DWORD)lpOInfo);
+
+ return TRUE;
+ }
+ break;
+
+ case OLE_QUERY_PAINT:
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+void ObjObjectHasChanged(int flags, LPOBJINFO lpObjInfo)
+{
+ typeCP cpParaStart,
+ cpParaCache = vcpFirstParaCache;
+ int docCache = vdocParaCache;
+ OBJPICINFO picInfo;
+ LPOLEOBJECT lpObject = lpObjInfo->lpobject;
+
+ /**
+ For Embeds (including InsertObject objects):
+ OLE_SAVED is sent with server File.Update
+ (set undo if not NONE)
+ OLE_CHANGED is sent with server File.Save or File.Close (?)
+ with update (set undo if not NONE), or when OleSetData()
+ causes a change in the presentation of the object.
+ OLE_CLOSED is sent when doc closes in server (clear undo if set)
+ For Links:
+ OLE_SAVED is sent with server File.Save (As?) if update_options
+ == update_on_save (that never happens)
+ OLE_CHANGED is sent when something in the server doc changes
+ OLE_CLOSED is never sent
+ **/
+
+ Assert(lpObjInfo != NULL);
+
+ if (lpObjInfo == NULL)
+ return;
+
+ if (lpObjInfo->objectType == NONE) // result of InsertObject
+ {
+ cpParaStart=lpObjInfo->cpWhere; // note only used here!
+
+ if (flags == OLE_CLOSED) // delete object
+ {
+ if (lpObject) /* may already be released or deleted */
+ ObjDeleteObject(lpObjInfo,TRUE);
+ NoUndo();
+ BringWindowToTop(hMAINWINDOW);
+ }
+ else
+ {
+ extern int vfSeeSel;
+
+ (**hpdocdod)[docCur].fFormatted = fTrue;
+
+ /* insert EOL if needed */
+ if (cpParaStart > cp0)
+ {
+ ObjCachePara(docCur, cpParaStart - 1);
+ if (vcpLimParaCache != cpParaStart)
+ {
+ InsertEolPap(docCur, cpParaStart, &vpapAbs);
+ cpParaStart += ccpEol;
+ }
+ }
+
+ GimmeNewPicinfo(&picInfo, lpObjInfo);
+ ObjCachePara(docCur,cpParaStart);
+ /* this'll clear selection. */
+ if (ObjSaveObjectToDoc(&picInfo,docCur,cpParaStart) == cp0)
+ Error(IDPMTFailedToCreateObject);
+ NoUndo();
+ ObjInvalidatePict(&picInfo,cpParaStart);
+ vfSeeSel = true; /* Tell Idle() to scroll the selection into view */
+ (**hpdocdod) [docCur].fDirty = TRUE;
+ }
+ }
+ else if (ObjGetPicInfo(lpObject,docCur,&picInfo,&cpParaStart))
+ {
+ BOOL bSizeChanged;
+
+ //GetPicInfo(cpParaStart,cpParaStart + cchPICINFOX, docCur, &picInfo);
+
+ /* invalidate rect before updating size (cause invalidate
+ needs to know old pic size) */
+ ObjInvalidatePict(&picInfo,cpParaStart);
+
+ bSizeChanged = ObjUpdatePicSize(&picInfo,cpParaStart);
+
+ if ((flags == OLE_CHANGED) ||
+ (flags == OLE_SAVED) && (otOBJ_QUERY_TYPE(&picInfo) == EMBEDDED))
+ {
+ NoUndo();
+#ifdef DEBUG
+ if (!fOBJ_QUERY_DIRTY_OBJECT(&picInfo))
+ OutputDebugString( (LPSTR) "Marking object dirty\n\r");
+#endif
+ fOBJ_QUERY_DIRTY_OBJECT(&picInfo) = TRUE;
+#ifdef DEBUG
+ if (!(**hpdocdod) [docCur].fDirty)
+ OutputDebugString( (LPSTR) "Marking doc dirty\n\r");
+#endif
+ (**hpdocdod) [docCur].fDirty = TRUE;
+ }
+
+ if (bSizeChanged)
+ if (ObjSetPicInfo(&picInfo,docCur,cpParaStart))
+ Error(IDPMTFailedToUpdate);
+
+ if (otOBJ_QUERY_TYPE(&picInfo) == EMBEDDED)
+ {
+ if (flags == OLE_CLOSED)
+ {
+ //if (fOBJ_QUERY_DIRTY_OBJECT(&picInfo))
+ BringWindowToTop(hMAINWINDOW);
+#ifdef UPDATE_UNDO
+ ObjClearUpdateUndo(&picInfo,docCur,cpParaStart);
+#endif
+ }
+#ifdef UPDATE_UNDO
+ else if (flags == OLE_SAVED)
+ {
+ ObjSetUpdateUndo(&picInfo,docCur,cpParaStart);
+ SetUndo(uacObjUpdate,docCur,cpParaStart,cp0,docNil,cp0,cp0,0);
+ }
+#endif
+ }
+ }
+
+ ObjCachePara(docCache,cpParaCache); // reset state
+}
+
+BOOL ObjUpdatePicSize(OBJPICINFO *pPicInfo, typeCP cpParaStart)
+/* returns whether size changed */
+{
+int xSize,ySize;
+BOOL bUpdate = FALSE;
+
+ /* object may have changed size */
+ if (!FComputePictSize(pPicInfo, &xSize, &ySize ))
+ Error(IDPMTFailedToUpdate);
+ else
+ bUpdate = (xSize != pPicInfo->dxaSize) ||
+ (ySize != pPicInfo->dyaSize);
+
+ if (bUpdate)
+ {
+ int yOldSize = pPicInfo->dyaSize;
+
+ pPicInfo->dxaSize = xSize;
+ pPicInfo->dyaSize = ySize;
+
+ if (yOldSize < pPicInfo->dyaSize)
+ { /* If the picture height was increased, make sure proper EDLs are
+ invalidated. */
+ typeCP dcp = CpMacText(docCur) - cpParaStart + (typeCP) 1;
+ ObjPushParms(docCur);
+ AdjustCp(docCur, cpParaStart, dcp, dcp); // major async problems here?
+ ObjPopParms(TRUE);
+ }
+ }
+ return bUpdate;
+}
+
+void ObjHandleBadLink(OLE_RELEASE_METHOD rm, LPOLEOBJECT lpObject)
+{
+ switch (rm)
+ {
+ case OLE_ACTIVATE:
+ case OLE_UPDATE:
+ {
+ typeCP cpParaStart,cpParaCache = vcpFirstParaCache;
+ int docCache = vdocParaCache;
+ OBJPICINFO picInfo;
+
+ /* don't need to do all docs since objects can only be active in docCur */
+ if (!ObjGetPicInfo(lpObject,docCur,&picInfo,&cpParaStart))
+ {
+ /* maybe in scrap, just ignore */
+ ObjCachePara(docCache,cpParaCache); // reset state
+ return;
+ }
+
+ ObjCachePara(docCur,cpParaStart);
+ if (FixInvalidLink(&picInfo,docCur,cpParaStart))
+ switch (rm)
+ {
+ case OLE_ACTIVATE:
+ StartLongOp();
+ ObjError(OleActivate(lpObject,
+ fOBJ_QUERY_PLAY(&picInfo),
+ TRUE,
+ TRUE,
+ hDOCWINDOW,
+ NULL));
+ EndLongOp(vhcArrow);
+ break;
+ case OLE_UPDATE:
+ StartLongOp();
+ ObjError(OleUpdate(lpObject));
+ EndLongOp(vhcArrow);
+ break;
+ }
+ ObjCachePara(docCache,cpParaCache); // reset state
+ }
+ break;
+ }
+}
+
+BOOL ObjWaitForObject(LPOBJINFO lpObjInfo, BOOL bOK2Cancel)
+{
+ HCURSOR hCursor = NULL;
+ BOOL bRetval;
+ /**
+ WMsgLoop allows WM_PAINT messages which wreak havoc. Try to
+ recover from the insult.
+ **/
+ typeCP cpParaCache = vcpFirstParaCache;
+ int docCache = vdocParaCache;
+ LPOLEOBJECT lpObject;
+
+ if (lpObjInfo == NULL) // shouldn't happen
+ {
+ Assert(0);
+ return FALSE;
+ }
+
+ /* Since ObjPicEnumInRange returns unloaded picinfo's this is a
+ valid possibility, but we shouldn't be getting called!!! */
+ Assert(lpObjInfo->lpobject != NULL);
+
+ Assert (CheckPointer((LPSTR)lpObjInfo,1));
+
+ lpObject = lpObjInfo->lpobject;
+
+ if (!ObjIsValid(lpObject))
+ {
+ Assert (0);
+ return FALSE;
+ }
+
+ hCursor = SetCursor(vhcHourGlass);
+ StartLongOp();
+ bRetval = WMsgLoop(TRUE,TRUE,bOK2Cancel,lpObject);
+ if (hCursor)
+ EndLongOp(hCursor);
+
+ ObjCachePara(docCache,cpParaCache); // reset state
+
+ /* problem here is that we may have been waiting for a release or delete */
+ if (ObjIsValid(lpObject))
+ {
+ lpObjInfo->fCancelAsync = FALSE; // clear after use
+ lpObjInfo->fCompleteAsync = FALSE; // clear after use
+ lpObjInfo->fCanKillAsync = FALSE;
+ }
+
+ UPDATE_INVALID(); // let WM_PAINTS get through now that we're no longer blocking
+ return bRetval;
+}
+
+
+#if 0
+BOOL ObjObjectSync(LPOBJINFO lpObjInfo, OLESTATUS (FAR PASCAL *lpProc)(LPOLEOBJECT lpObject), BOOL bOK2Cancel)
+/*
+ This makes an asynchronous call synchronous. lpProc must have only
+ lpObject as argument. This will block if operation cannot be completed
+ or cancelled.
+*/
+{
+ /* caller has set or not set CancelAsync flag for object */
+ if (ObjWaitForObject(lpObjInfo,bOK2Cancel))
+ return TRUE;
+
+ switch((*lpProc)(lpObjInfo->lpobject))
+ {
+ case OLE_WAIT_FOR_RELEASE:
+ {
+ /* cancel button should only be enabled if this operation
+ can be cancelled. */
+ lpObjInfo->fCancelAsync = FALSE; // don't cancel automatically
+ lpObjInfo->fCompleteAsync = TRUE; // this op must complete or be cancelled
+
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return TRUE;
+
+ /* the trouble with this is that lpObject may now be released
+ (and thus invalid):
+ return ObjError(OleQueryReleaseError(lpObjInfo->lpobject));
+ */
+
+ return FALSE;
+ }
+ case OLE_OK:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+#endif
+
+#define WM_NCMOUSEFIRST 0x00A0
+#define WM_NCMOUSELAST 0x00A9
+
+static BOOL WMsgLoop
+(
+BOOL fExitOnIdle, // if true, return as soon as no messages to process
+ // (not used, assumed FALSE).
+BOOL fIgnoreInput, // if true, ignore keyboard and mouse input
+BOOL bOK2Cancel,
+LPOLEOBJECT lpObject
+)
+ {
+ MSG msg;
+ DWORD GetCurrentTime();
+ DWORD cTime=GetCurrentTime();
+ BOOL bRetval=FALSE,bBeeped=FALSE;
+ int fParentEnable;
+ extern int flashID;
+
+#ifdef DEBUG
+ if (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
+ OutputDebugString("waiting for object\n\r");
+#endif
+
+ ++nBlocking;
+
+ ferror = FALSE;
+
+ ++nWaitingForObject;
+
+ StartLongOp();
+
+ while (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
+ {
+ /* put up wait dialog after 6 seconds */
+ if ((GetCurrentTime() - cTime) > 6000L)
+ {
+ // bring up wait dialog.
+ if (!hwndWait)
+ {
+ if (vfDeactByOtherApp)
+ {
+ if (!bBeeped) // flash until we're activated
+ {
+ fParentEnable = IsWindowEnabled(hMAINWINDOW);
+ //MessageBeep(0);
+ bBeeped = TRUE;
+
+ if (!fParentEnable)
+ EnableWindow(hMAINWINDOW, TRUE); /* make sure parent window is enabled
+ to let the user click in it */
+ flashID = 1234; // arbitrary ID
+ SetTimer(hMAINWINDOW, flashID, 500, (FARPROC)NULL);
+ // this'll cause flashing, see mmw.c
+ }
+ }
+ else // Write is active app
+ {
+ if (bBeeped)
+ /* then we've regained the activation */
+ {
+ if (!fParentEnable)
+ EnableWindow(hMAINWINDOW, FALSE); /* reset */
+ bBeeped = FALSE;
+ KillTimer(hMAINWINDOW, flashID);
+ flashID = 0;
+ FlashWindow(hMAINWINDOW, FALSE);
+ }
+
+ if (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
+ {
+ /* this'll set hwndWait */
+ vbCancelOK = bOK2Cancel;
+ bRetval = DialogBoxParam(hINSTANCE, (LPSTR)"DTWAIT", hPARENTWINDOW, lpfnWaitForObject, (DWORD)lpObject);
+ break;
+ }
+ }
+ }
+ else
+ {
+ bRetval = TRUE;
+ break;
+ }
+ }
+
+ if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ /* No messages, do Idle processing */
+ /* this is where we'd use ExitOnIdle */
+ }
+ else
+ {
+ /* The following code will put the app into a
+ sleeping state if the fIgnoreInput flag is set
+ to TRUE. It will allow Quit, DDE, and any
+ other non input messages to be passed along
+ and dispatched but will prohibit the user from
+ interacting with the app. The user can
+ Alt-(sh)Tab, Alt-(sh)Esc, and Ctrl-Esc away from the
+ app as well as use any Windows hot keys to
+ activate other apps */
+
+ /* if we pass this test, then the message may be one we can ignore */
+ if ((fIgnoreInput) &&
+ (!(vfDeactByOtherApp &&
+ (msg.message == WM_NCLBUTTONDOWN))) &&
+ ((msg.message >= WM_NCMOUSEFIRST &&
+ msg.message <= WM_NCMOUSELAST) ||
+ (msg.message >= WM_KEYFIRST &&
+ msg.message <= WM_KEYLAST) ||
+ (msg.message >= WM_MOUSEFIRST &&
+ msg.message <= WM_MOUSELAST)))
+ {
+ static BOOL fAltCtl = FALSE;
+
+ if (msg.message != WM_SYSKEYDOWN)
+ continue; // ignore
+
+ if (msg.wParam == VK_MENU)
+ fAltCtl = TRUE;
+ else if (fAltCtl && msg.wParam != VK_SHIFT)
+ {
+ fAltCtl = FALSE;
+ if (msg.wParam != VK_TAB && msg.wParam != VK_ESCAPE)
+ continue; // ignore
+ }
+ }
+
+
+ if ((vfDeactByOtherApp &&
+ (msg.message == WM_NCLBUTTONDOWN)))
+ BringWindowToTop(hwndWait ? hwndWait : msg.hwnd);
+ else
+ {
+ TranslateMessage ((LPMSG) &msg);
+ DispatchMessage ((LPMSG) &msg);
+ }
+ }
+ }
+
+ Assert(hwndWait == NULL);
+
+ if (bBeeped) // then beeped but done before received activation
+ {
+ if (!fParentEnable)
+ EnableWindow(hMAINWINDOW, FALSE); /* reset */
+ KillTimer(hMAINWINDOW, flashID);
+ flashID = 0;
+ FlashWindow(hMAINWINDOW, FALSE);
+ }
+
+ --nBlocking;
+ --nWaitingForObject;
+
+ EndLongOp(vhcArrow);
+
+ Assert(nBlocking >= 0);
+ return bRetval;
+}
+
+void FinishUp(void)
+/* let all pending messages through and return */
+/*
+ !!! Note that we may accumulate WM_PAINTS. Caller is responsible for
+ calling UPDATE_INVALID() to catch up on them!!!
+*/
+{
+ MSG msg;
+
+ /* now allow through all messages posted from callback */
+ ++nBlocking; // block WM_PAINTS
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage ((LPMSG) &msg);
+ DispatchMessage ((LPMSG) &msg);
+ }
+ --nBlocking;
+
+ return FALSE;
+}
+
+BOOL FinishAllAsyncs(BOOL bAllowCancel)
+/*
+ !!! Note that we may accumulate WM_PAINTS. Caller is responsible for
+ calling UPDATE_INVALID() to catch up on them!!! (see FinishUp())
+*/
+{
+ LPOLEOBJECT lpObject;
+ LPOBJINFO lpObjInfo;
+
+ /* first make sure all async ops are complete */
+ lpObject=NULL;
+ do
+ {
+ OleEnumObjects(lhClientDoc,&lpObject);
+ if (lpObject)
+ {
+ lpObjInfo = GetObjInfo(lpObject);
+
+ if (lpObjInfo)
+ {
+ /* cancel takes us outa here. Pending asyncs will block us. */
+ if (ObjWaitForObject(lpObjInfo,bAllowCancel))
+ return TRUE;
+ }
+ else // shouldn't happen, but don't assume for now
+ {
+ Assert(0);
+ if (WMsgLoop(TRUE,TRUE,bAllowCancel,lpObject))
+ return TRUE;
+ }
+
+ if (!ObjIsValid(lpObject)) // then got deleted
+ lpObject = NULL; // start over
+ }
+ }
+ while (lpObject);
+
+ /* let all messages posted from callback get through */
+ FinishUp();
+
+ return FALSE;
+}
+
+static typeCP cpPPSave;
+static int docPPSave;
+static struct SEL selPPSave;
+static int nPushed=FALSE;
+
+ObjPushParms(int doc)
+/* Save selCur and Cache info to reset with Pop after writing to
+ doc. Assumes aren't changing size of doc.
+*/
+{
+ if (nPushed) // prevent recursion
+ {
+#ifdef DEBUG
+ OutputDebugString("Unmatched ObjPushParms\n\r");
+#endif
+ return;
+ }
+ ++nPushed;
+
+ cpPPSave = vcpFirstParaCache;
+ docPPSave = vdocParaCache;
+
+ selPPSave = selCur;
+ Select(selCur.cpFirst,selCur.cpFirst); // this caches para
+ CachePara(docPPSave,cpPPSave);
+}
+
+ObjPopParms(BOOL bCache)
+{
+ typeCP cpMac = (**hpdocdod) [docPPSave].cpMac;
+
+ if (!nPushed) // unmatched push/pops
+ {
+#ifdef DEBUG
+ OutputDebugString("Unmatched ObjPopParms\n\r");
+#endif
+ return;
+ }
+ --nPushed;
+
+ if (docPPSave == docCur)
+ {
+ if (selPPSave.cpLim > cpMac)
+ selPPSave.cpLim = cpMac;
+ if (cpPPSave > cpMac)
+ cpPPSave = cpMac;
+ }
+
+ Select(selPPSave.cpFirst,selPPSave.cpLim); // this caches para
+ if (bCache)
+ CachePara(docPPSave,cpPPSave);
+ //(**hpdocdod) [docPPSave].fDirty = TRUE; /* why? */
+}
+
+
+void ObjCachePara(int doc, typeCP cp)
+{
+ typeCP cpMac = (**hpdocdod) [doc].cpMac;
+ typeCP cpMacCurSave = cpMacCur,
+ cpMinCurSave = cpMinCur;
+
+ if (doc == docNil)
+ return;
+
+ /**
+ cpMinCur and cpMacCur are the min and mac value for whatever is
+ currently docCur. Their values will be different for the header,
+ footer and regular docs. OBJ code doesn't distinguish. Async
+ operations can happen on any and all cps at once. Gotta set so
+ CachePara wil understand that.
+ **/
+ cpMinCur = cp0;
+ cpMacCur = cpMac;
+
+ if (cp >= cpMac)
+ cp = cpMac;
+ else if (cp < cp0)
+ cp = cp0;
+
+ CachePara(doc,cp);
+
+ cpMinCur = cpMinCurSave;
+ cpMacCur = cpMacCurSave;
+}
+
+#if 0
+void ObjWriteFixup(int doc, BOOL bStart, typeCP cpStart)
+/* note this must not be called recursively!! It is for use where size of
+ doc may change between bStart=TRUE and bStart=FALSE. */
+{
+ static typeCP dcp,cpLim;
+ static struct SEL selSave;
+ typeCP cpMac;
+
+ /* reset selection accounting for change in size if any */
+ if (bStart)
+ {
+ cpLim = CpMacText(doc);
+ selSave=selCur;
+ if ((selCur.cpFirst != selCur.cpLim) && (doc == docCur))
+ Select(selCur.cpFirst,selCur.cpFirst); /* Take down sel before we mess with cp's */
+ /* select undoes cache */
+ ObjCachePara(doc,cpStart);
+ }
+ else
+ {
+ cpMac = CpMacText(doc);
+
+ dcp = cpMac-cpLim; /* change in size of doc */
+
+ if (doc == docCur)
+ {
+ if (selSave.cpFirst <= cpStart)
+ {
+ if ((selSave.cpLim) > cpStart)
+ selSave.cpLim += dcp;
+ }
+ else if (selSave.cpFirst > cpStart)
+ /* selection proceeds object */
+ {
+ selSave.cpFirst += dcp;
+ selSave.cpLim += dcp;
+ }
+
+ if (selSave.cpFirst > cpMac)
+ selSave.cpFirst = selSave.cpLim = cpMac;
+ else if (selSave.cpLim > cpMac)
+ selSave.cpLim = cpMac;
+
+ /* this'll cache first para in selection */
+ if (selSave.cpFirst != selSave.cpLim)
+ Select(selSave.cpFirst,selSave.cpLim);
+ }
+
+ ObjCachePara(doc,cpStart);
+
+ /* Fixup Undo pointers */
+ if (vuab.doc == docCur)
+ {
+ if (doc == docUndo) /* operating on docUndo, cpStart is irrelevant */
+ vuab.dcp += dcp;
+ else if (doc == docCur)
+ {
+ if (vuab.cp <= cpStart)
+ {
+ /* undo encloses object */
+ if ((vuab.cp+vuab.dcp) > cpStart)
+ vuab.dcp += dcp;
+ }
+ else if (vuab.cp > cpStart)
+ /* undo proceeds object */
+ vuab.cp += dcp;
+ }
+ }
+
+ if (vuab.doc2 == docCur)
+ {
+ if (doc == docUndo) /* operating on docUndo, cpStart is irrelevant */
+ vuab.dcp += dcp;
+ else if (doc == docCur)
+ {
+ if (vuab.cp2 <= cpStart)
+ {
+ /* undo encloses object */
+ if ((vuab.cp2+vuab.dcp2) > cpStart)
+ vuab.dcp2 += dcp;
+ }
+ else if (vuab.cp2 > cpStart)
+ /* undo proceeds object */
+ vuab.cp2 += dcp;
+ }
+ }
+ }
+}
+#endif
+
+void ObjWriteClearState(int doc)
+/** Call this before writing asynchronously to doc. In practise, this is
+ being called in synchronous times as well, so higher level code
+ must take care of resetting selection and undo after writing to doc.
+**/
+{
+ typeCP cpSave=vcpFirstParaCache;
+ int docSave=vdocParaCache;
+
+ if (doc == docCur)
+ {
+ Select(selCur.cpFirst,selCur.cpFirst); /* Take down sel before we mess with cp's */
+ /* select undoes cache */
+ ObjCachePara(docSave,cpSave);
+ }
+ //NoUndo(); /** Higher level code must SetUndo *after* calling **/
+}
+
+LPOBJINFO GetObjInfo(LPOLEOBJECT lpObject)
+{
+ LPLPOBJINFO lplpObjTmp;
+
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ if ((*lplpObjTmp)->lpobject == lpObject)
+ return *lplpObjTmp;
+
+ Assert(0);
+ return NULL;
+}
+
+
+BOOL ObjIsValid(LPOLEOBJECT lpobj)
+{
+ if (!CheckPointer((LPSTR)lpobj, 1))
+ return FALSE;
+
+ if (OleQueryReleaseStatus(lpobj) == OLE_ERROR_OBJECT)
+ return FALSE;
+
+#if 0 // can't depend on this in future version of OLE
+ if (!(((LPRAWOBJECT)lpobj)->objId[0] == 'L' && ((LPRAWOBJECT)lpobj)->objId[1] == 'E'))
+ return FALSE;
+#endif
+
+ return TRUE;
+}
+
+#if 0 // these should work, but not using them now
+LPOBJINFO ObjGetClientInfo(LPOLEOBJECT lpobj)
+{
+ LPOBJINFO lpObjInfo;
+
+ if (!CheckPointer((LPSTR)lpobj, 1))
+ {
+ Assert(0);
+ return NULL;
+ }
+
+#if 0 // can't depend on this in future versions of OLE
+ if (!CheckPointer((LPSTR)(((LPRAWOBJECT)lpobj)->lpclient), 1))
+ {
+ Assert(0);
+ return NULL;
+ }
+ else
+ return (LPOBJINFO)(((LPRAWOBJECT)lpobj)->lpclient);
+#endif
+
+ if (*(lpObject->lpvtbl->ObjectLong)(lpObject,OF_GET,(LPLONG)&lpObjInfo) == OLE_OK)
+ return lpClient;
+ else
+ return NULL;
+}
+
+BOOL ObjSetClientInfo(LPOBJINFO lpObjInfoNew, LPOLEOBJECT lpobj)
+/* return if error */
+{
+ if (!CheckPointer((LPSTR)lpobj, 0))
+ {
+ Assert(0);
+ return TRUE;
+ }
+
+ if (*(lpObject->lpvtbl->ObjectLong)(lpObject,OF_SET,(LPLONG)&lpObjInfoNew) == OLE_OK)
+ return FALSE;
+ else
+ {
+ Assert(0);
+ return TRUE;
+ }
+}
+#endif
+
+#if 0
+int ObjMarkInDoc(int doc)
+/* mark as 'InDoc' all objects located in docScrap, all others are marked
+ as not 'InDoc'. Return count of objects in doc. */
+{
+ LPLPOBJINFO lplpObjTmp;
+ int nObjCount=0,doc;
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+
+ /* mark all as not in doc */
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ ++nObjCount;
+ (*lplpObjTmp)->fInDoc = FALSE;
+ }
+
+ if (nObjCount == 0)
+ return 0;
+
+ for (cpPicInfo = cpNil,nObjCount=0;
+ ObjPicEnumInRange(&picInfo,doc,cp0,CpMacText(doc),&cpPicInfo);
+ )
+ {
+ if (lpOBJ_QUERY_INFO(&picInfo))
+ {
+ fOBJ_INDOC(&picInfo) = TRUE;
+ ++nObjCount;
+ }
+ }
+ return nObjCount;
+}
+
+BOOL AllocObjInfos()
+/* return whether error */
+{
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ int doc;
+
+ for (doc = 0; doc < docMac; doc++)
+ {
+ if ((doc != docNil) && (**hpdocdod)[doc].hpctb)
+ {
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cp0,CpMacText(doc),&cpPicInfo);
+ )
+ {
+ if (picInfo.lpObjInfo)
+ continue;
+
+ if (ObjAllocObjInfo(&picInfo,cpPicInfo,picInfo.objectType,FALSE,NULL))
+ return TRUE;
+
+ /* note this makes doc dirty right off the bat, but gotta do it because
+ we gotta save ObjInfo handle in doc. (8.20.91) v-dougk */
+ ObjWriteFixup(doc,TRUE,cpPicInfo);
+ if (ObjSetPicInfo(&picInfo, doc, cpPicInfo))
+ return TRUE;
+ ObjWriteFixup(doc,FALSE,cpPicInfo);
+ }
+ }
+ }
+}
+#endif
+
+BOOL ObjCloneScrapToNewDoc(LHCLIENTDOC lhNewClientDoc)
+/* return whether an error */
+{
+ szOBJNAME szObjName;
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ int nCount=0;
+ extern int docScrap;
+
+
+
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docScrap,cp0,CpMacText(docScrap),&cpPicInfo);
+ )
+ {
+ szOBJNAME szObjName;
+ LPOBJINFO lpObjInfo = lpOBJ_QUERY_INFO(&picInfo);
+ LPOLEOBJECT lpObject = lpObjInfo->lpobject;
+ OBJPICINFO NewPicInfo = picInfo;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Cloning object in scrap\n\r");
+#endif
+
+ if (ObjCloneObjInfo(&NewPicInfo, cpPicInfo, szObjName))
+ goto error;
+
+ if (ObjError(OleClone(lpObject,
+ (LPOLECLIENT)lpOBJ_QUERY_INFO(&NewPicInfo),
+ lhNewClientDoc,szObjName,
+ &lpOBJ_QUERY_OBJECT(&NewPicInfo))))
+ goto error;
+
+ if (ObjSetPicInfo(&NewPicInfo, docScrap, cpPicInfo))
+ goto error;
+
+ ObjDeleteObject(lpObjInfo,TRUE);
+
+ ++nCount;
+ }
+
+ goto end;
+
+ error:
+
+ /* cleanup after failure by deleting docScrap objects */
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docScrap,cp0,CpMacText(docScrap),&cpPicInfo);
+ )
+ {
+ ObjDeleteObject(lpOBJ_QUERY_INFO(&picInfo),TRUE);
+ }
+
+ ClobberDoc(docScrap,docNil,cp0,cp0);
+
+ nCount = -1;
+
+ end:
+
+ if (nCount) // docScrap has changed
+ NoUndo();
+
+ return nCount;
+}
+
+
diff --git a/private/mvdm/wow16/write/obj.h b/private/mvdm/wow16/write/obj.h
new file mode 100644
index 000000000..4c573015b
--- /dev/null
+++ b/private/mvdm/wow16/write/obj.h
@@ -0,0 +1,414 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+#ifndef OLEH
+#define OLEH
+#include <ole.h>
+
+//#define SMALL_OLE_UI
+
+/*
+ * Constant IDs used in the Object Properties... dialog
+ */
+#define IDD_WHAT 0x0100
+#define IDD_CLASSID 0x0101
+#define IDD_AUTO 0x0102
+#define IDD_MANUAL 0x0103
+#define IDD_EDIT imiActivate
+#define IDD_FREEZE imiFreeze
+#define IDD_UPDATE imiUpdate
+#define IDD_CHANGE 0x106
+#define IDD_LINK 0x107
+#define IDD_LINKDONE 0x108
+#define IDD_LISTBOX 0x109
+#define IDD_EMBEDDED 0x110
+#define IDD_PLAY 0x111
+#define IDD_UNDO 0x112
+#define IDD_REFRESH 0x113
+#define IDD_UPDATEOTHER 0x114
+#define IDD_WAIT 0x115
+#define IDD_MESSAGE 0x116
+#define IDD_CLIPOWNER 0x117
+#define IDD_ITEM 0x118
+#define IDD_PASTE 0x119
+#define IDD_PASTELINK 0x11a
+#define IDD_SOURCE 0x11b
+#define IDD_SWITCH 0x11c
+
+typedef enum { NONE, STATIC, EMBEDDED, LINK } OBJECTTYPE;
+
+#define UPDATE_INVALID() CatchupInvalid(hDOCWINDOW)
+
+#define PROTOCOL ((LPSTR)"StdFileEditing")
+#define SPROTOCOL ((LPSTR)"Static")
+#if OBJ_EMPTY_OBJECT_FRAME
+#define nOBJ_BLANKOBJECT_X 0x480
+#define nOBJ_BLANKOBJECT_Y 0x480
+#else
+#define nOBJ_BLANKOBJECT_X 0x0
+#define nOBJ_BLANKOBJECT_Y 0x0
+#endif
+
+#define wOleMagic 0137062 // for ole file headers (wMagic+1)
+#define OBJ_PLAYEDIT ObjPlayEdit
+#if !defined(SMALL_OLE_UI)
+#define EDITMENUPOS 9
+#else
+#define EDITMENUPOS 7
+#endif
+
+/* number of timer ticks between garbage collection */
+#define GARBAGETIME 200
+extern int nGarbageTime;
+
+/* properties list flags */
+#define OUT 0
+#define IN 1
+#define DELETED 2
+
+/* for ObjDeletionOK and fnClearEdit */
+#define OBJ_DELETING 0
+#define OBJ_INSERTING 1
+#define OBJ_CUTTING 2
+
+#define UNDO_EVERY_UPDATE
+#undef UPDATE_UNDO
+
+typedef char szOBJNAME[9];
+
+/* object information that needn't be stored in file. This is also used as
+ the OLECLIENT structure passed to the OLE object creation API's. It is
+ passed as an argument into the Callback proc. */
+struct _OBJINFO
+{
+ LPOLECLIENTVTBL lpvtbl;
+ unsigned fTooBig : 1; // see LoadObject
+ unsigned fWasUpdated : 1; // Links diaog crappola
+ unsigned fPropList : 2; // Links diaog crappola
+ unsigned fDirty : 1; // changed size or got updated
+ unsigned fDontSaveData : 1; // see ObjSaveObject
+ unsigned fBadLink : 1; // Links dialog
+ unsigned fKillMe : 1; // means return FALSE for QUERYRETRY
+ unsigned fDeleteMe : 1; // means this object is deleted on OLE_RELEASE
+ // (set if can't call OleDelete)
+ unsigned fReleaseMe : 1; // means this object is released on OLE_RELEASE
+ // (set if can't call OleDelete)
+ unsigned fFreeMe : 1; // free ObjInfo on OLE_RELEASE
+ unsigned fReuseMe : 1;
+ unsigned fInDoc : 1; // see CollectGarbage
+
+ /* waiting for server dialog flags */
+ unsigned fCancelAsync : 1; // means cancel pending async if possible
+ unsigned fCompleteAsync : 1; // means must complete pending async to allow cancel
+ unsigned fCanKillAsync : 1; // like CompleteAsync, indicates cancel is possible
+
+ int OlePlay;
+ LPOLEOBJECT lpobject;
+ ATOM aName; // docname for links, server class for unfinished insertnew objects,
+ ATOM aObjName; // unique object name
+
+ struct _OBJINFO FAR *lpclone; // clone used for link properties cancel
+ typeCP cpWhere; /* cp where picinfo is to be found (only used in ObjHasChanged! for NONE objects) */
+ OLECLIPFORMAT objectType; /* dup of what's in picInfo (so can get type
+ for unfinished objects not yet stored in a picinfo)
+ */
+
+ unsigned fCantDisplay : 1;
+} ;
+typedef struct _OBJINFO OBJINFO;
+typedef OBJINFO FAR * LPOBJINFO ;
+typedef LPOBJINFO FAR * LPLPOBJINFO;
+
+/* the following return OBJINFO pointers */
+#define lpOBJ_QUERY_UPDATE_UNDO(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->lpUndoUpdate)
+#if defined(UNDO_EVERY_UPDATE)
+#define lpOBJ_QUERY_UPDATE_UNDO2(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->lpUndoUpdate2)
+#endif
+#define lpOBJ_QUERY_CLONE(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->lpclone)
+#define lpOBJ_QUERY_INFO(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo)
+
+/* the following return stuff from lpPicInfo */
+#define dwOBJ_QUERY_OBJECT_NUM(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->dwObjNum)
+#define dwOBJ_QUERY_DATA_SIZE(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->dwDataSize)
+#define bOBJ_QUERY_IS_OBJECT(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->mm == MM_OLE)
+
+/* the following return stuff from lpPicInfo->lpObjInfo */
+#define otOBJ_QUERY_TYPE(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->objectType)
+#define docOBJ_QUERY_DOC(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->doc)
+#define cpOBJ_QUERY_WHERE(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->cpWhere)
+#define lpOBJ_QUERY_CLONE_OBJECT(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->lpclone->lpobject)
+//#define uoiFLAGS(lpObjInfo) (*((unsigned FAR *)((LPSTR)lpObjInfo + sizeof(LPOLECLIENTVTBL))))
+#define bOBJ_REUSE_ME(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fReuseMe)
+#define fOBJ_INDOC(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fInDoc)
+#define fOBJ_BADLINK(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fBadLink)
+#define bOBJ_QUERY_DONT_SAVE_DATA(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fDontSaveData)
+#define bOBJ_QUERY_DATA_INVALID(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fDataInvalid)
+#define bOBJ_QUERY_TOO_BIG(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fTooBig)
+#define bOBJ_WAS_UPDATED(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fWasUpdated)
+//#define aOBJ_QUERY_SERVER_CLASS(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->aName)
+#define aOBJ_QUERY_DOCUMENT_LINK(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->aName)
+#define lpOBJ_QUERY_OBJECT(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->lpobject)
+#define fOBJ_QUERY_DIRTY_OBJECT(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fDirty)
+#define fOBJ_QUERY_IN_PROP_LIST(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->fPropList)
+#define fOBJ_QUERY_PLAY(lpPicInfo) (((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->OlePlay)
+#define cfOBJ_QUERY_CLIPFORMAT(lpPicInfo) ( \
+ ((((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->objectType) == EMBEDDED) ? vcfNative : \
+ ((((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->objectType) == LINK) ? vcfLink : \
+ ((((lpOBJPICINFO)(lpPicInfo))->lpObjInfo->objectType) == STATIC) ? vcfOwnerLink : NULL)
+
+
+
+/* this coerces the PICINFO structure: */
+typedef struct
+{
+ /* overlay METAFILEPICT structure: */
+ int mm; // mfp.mm (MM_OLE if an object)
+ WORD xExt; // not used
+ WORD yExt; // not used
+ OLECLIPFORMAT objectType; // mfp.hMF
+
+ /* real PICINFO stuff we won't mess with: */
+ int dxaOffset;
+ int dxaSize;
+ int dyaSize;
+ WORD cbOldSize; // not used
+
+ /* overlay the BITMAP structure: */
+ DWORD dwDataSize; // bmType,bmWidth, this supercedes cbSize
+ WORD bmHeight; // not used
+ WORD bmWidthBytes; // not used
+ DWORD dwObjNum; // bmPlanes,bmBitsPixel, 2 bytes of bmBits
+ WORD bmBits; // two bytes of it, not used
+ /**
+ If you want to add more fields here, don't wipe out the cbHeader,
+ mx and my fields because they are being used.
+ **/
+ unsigned cbHeader;
+ LPOBJINFO lpObjInfo; // cbSize
+ unsigned mx, my;
+} OBJPICINFO, FAR *lpOBJPICINFO;
+
+extern LPLPOBJINFO lplpObjInfo;
+extern LHCLIENTDOC lhClientDoc;
+extern BOOL fOleEnabled;
+extern LPOLESTREAM lpStream;
+extern OLESTREAMVTBL streamTbl;
+extern OLECLIENTVTBL clientTbl;
+//extern LPOLECLIENT lpclient;
+extern OBJECTTYPE votObjSelType;
+
+extern HWND hwndLinkWait;
+extern FARPROC lpfnLinkProps;
+extern FARPROC lpfnObjProps;
+extern FARPROC lpfnWaitForObject;
+extern FARPROC lpfnInvalidLink;
+extern FARPROC lpfnInsertNew;
+extern FARPROC lpfnPasteSpecial;
+extern BOOL vbObjLinkOnly;
+extern BOOL vObjPasteLinkSpecial;
+extern WORD cfObjPasteSpecial;
+//extern int vcEmbeds;
+extern int cObjWait; /* Count of "open" OLE transactions */
+extern OLECLIPFORMAT vcfNative;
+extern OLECLIPFORMAT vcfLink;
+extern OLECLIPFORMAT vcfOwnerLink;
+extern ATOM aNewName;
+extern ATOM aOldName;
+extern BOOL bLinkProps;
+extern int vcObjects; // count in doc. Note limit of 32K!!!
+extern int ObjPlayEdit;
+extern int nBlocking;
+extern int vcVerbs;
+extern BOOL vbCancelOK;
+extern HWND hwndWait;
+
+void CatchupInvalid(HWND hWnd);
+extern int FAR PASCAL fnPasteSpecial(HWND hDlg, unsigned message, WORD wParam, LONG lParam);
+extern int FAR PASCAL fnInsertNew(HWND hDlg, unsigned msg, WORD wParam, LONG lParam) ;
+extern BOOL FAR PASCAL fnObjWait(HWND hDlg, unsigned msg, WORD wParam, LONG lParam);
+extern int far PASCAL fnProperties();
+extern int far PASCAL fnInvalidLink();
+extern void fnObjDoVerbs(WORD wVerb);
+extern void fnObjProperties(void);
+extern void fnObjInsertNew(void);
+extern BOOL fnObjFreeze(LPOLEOBJECT far *lplpObject, szOBJNAME szObjName);
+extern BOOL fnObjActivate(LPOLEOBJECT lpObject);
+extern BOOL fnObjUpdate(LPOBJINFO lpObjInfo);
+extern void fnObjPasteSpecial(void);
+extern ATOM MakeLinkAtom(LPOBJINFO lpObjInfo);
+
+
+#ifdef DEBUG
+extern void ObjPrintError(WORD stat,BOOL bRelease);
+#endif
+
+extern BOOL ObjUpdateFromPicInfo(OBJPICINFO *pPicInfo,szOBJNAME szObjName);
+extern BOOL ObjUpdateFromObjInfo(OBJPICINFO *pPicInfo);
+void FinishUp(void);
+BOOL FinishAllAsyncs(BOOL bAllowCancel);
+BOOL FAR ObjError(OLESTATUS olestat) ;
+extern BOOL ObjDeletionOK(int nMode);
+//extern BOOL ObjContainsUnfinished(int doc, typeCP cpFirst, typeCP cpLim);
+extern BOOL ObjContainsOpenEmb(int doc, typeCP cpFirst, typeCP cpLim, BOOL bLookForUnfinished);
+extern BOOL ObjSetTargetDeviceForObject(LPOBJINFO lpObjInfo);
+extern void ObjSetTargetDevice(BOOL bSetObjects);
+extern BOOL ObjSetClientInfo(LPOBJINFO lpObjInfoNew, LPOLEOBJECT lpobj);
+extern WORD _cdecl CheckPointer (LPSTR lp, WORD access);
+extern LPOBJINFO ObjGetClientInfo(LPOLEOBJECT lpobj);
+extern BOOL ObjIsValid(LPOLEOBJECT lpobj);
+extern BOOL ObjFreeObjInfoWithObject(LPOLEOBJECT lpObject);
+extern BOOL ObjAllocObjInfo(OBJPICINFO *,typeCP,OBJECTTYPE,BOOL,szOBJNAME);
+extern BOOL ObjFreeObjInfo(OBJPICINFO *pPicInfo);
+extern LONG FAR PASCAL BufReadStream(LPOLESTREAM lpStream, char huge *lpstr, DWORD cb) ;
+extern LONG FAR PASCAL BufWriteStream(LPOLESTREAM lpStream, char huge *lpstr, DWORD cb) ;
+extern BOOL ObjUpdatePicSize(OBJPICINFO *pPicInfo, typeCP cpParaStart);
+extern BOOL ObjSetPicInfo(OBJPICINFO *pSrcPicInfo, int doc, typeCP cpParaStart);
+extern void ObjCachePara(int doc, typeCP cp);
+extern void ObjUpdateMenu(HMENU hMenu);
+extern void ObjUpdateMenuVerbs( HMENU hMenu );
+extern void ObjShutDown(void);
+extern BOOL ObjInit(HANDLE hInstance);
+extern BOOL ObjCreateObjectInClip(OBJPICINFO *pPicInfo);
+extern BOOL ObjWriteToClip(OBJPICINFO FAR *lpPicInfo);
+extern BOOL ObjDisplayObjectInDoc(OBJPICINFO FAR *lpPicInfo, int doc, typeCP cpParaStart, HDC hDC, LPRECT lpBounds);
+extern BOOL ObjQueryObjectBounds(OBJPICINFO FAR *lpPicInfo, HDC hDC,
+ int *pdxa, int *pdya);
+extern ObjGetPicInfo(LPOLEOBJECT lpObject, int doc, OBJPICINFO *pPicInfo, typeCP *pcpParaStart);
+extern BOOL ObjQueryNewLinkName(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern BOOL CloseUnfinishedObjects(BOOL bSaving);
+extern BOOL ObjOpenedDoc(int doc);
+extern BOOL ObjClosingDoc(int docOld,LPSTR szNewDocName);
+extern BOOL ObjSavingDoc(BOOL bFormatted);
+extern void ObjSavedDoc(void);
+extern void ObjRenamedDoc(LPSTR szNewName);
+extern void ObjRevertedDoc();
+extern void ObjObjectHasChanged(int flags, LPOBJINFO lpObjInfo);
+extern void ObjGetObjectName(LPOBJINFO lpObjInfo, szOBJNAME szObjName);
+extern void ObjMakeObjectName(LPOBJINFO lpObjInfo, LPSTR lpstr);
+extern void ObjHandleBadLink(OLE_RELEASE_METHOD rm, LPOLEOBJECT lpObject);
+extern void ObjQueryInvRect(OBJPICINFO FAR *lpPicInfo, RECT *rc, typeCP cp);
+extern void ObjReleaseError(OLE_RELEASE_METHOD rm);
+extern char *ObjGetServerName(LPOLEOBJECT lpObject, char *szServerName);
+extern void ObjGetDrop(HANDLE hDrop, BOOL bOpenFile);
+extern LPOBJINFO GetObjInfo(LPOLEOBJECT lpObject);
+extern BOOL ObjDeleteObjInfo(LPOBJINFO lpOInfo);
+
+/* enumeration functions */
+extern LPLPOBJINFO EnumObjInfos(LPLPOBJINFO lpObjInfoPrev);
+extern ObjPicEnumInRange(OBJPICINFO *pPicInfo,int doc, typeCP cpFirst, typeCP cpLim, typeCP *cpCur);
+typedef typeCP (FAR PASCAL *cpFARPROC)();
+extern int ObjEnumInDoc(int doc, cpFARPROC lpFunc);
+extern int ObjEnumInAllDocs(cpFARPROC lpFunc);
+extern int ObjEnumInRange(int doc, typeCP cpStart, typeCP cpEnd, cpFARPROC lpFunc);
+extern typeCP ObjSaveObjectToDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjReleaseObjectInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjLoadObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjNullObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjDeleteObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjCloneObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjCheckObjectTypes (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjChangeLinkInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjFreezeObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjUpdateObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjUpdateLinkInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjMakeUniqueInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjPlayObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjEditObjectInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjSetNoUpdate (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjToCloneInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjFromCloneInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjClearCloneInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjUseCloneInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjBackupInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjNewDocForObject (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjSetHostNameInDoc (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjSetUpdateUndo (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjClearUpdateUndo (OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart);
+extern typeCP ObjCloseObjectInDoc(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart);
+
+extern BOOL ObjCreateObjectInDoc (int doc,typeCP cpParaStart);
+extern void ObjDoUpdateUndo(int doc,typeCP cpParaStart);
+extern BOOL ObjSetData(OBJPICINFO far *lpPicInfo, OLECLIPFORMAT cf, HANDLE hData);
+extern OLESTATUS ObjGetData(LPOBJINFO lpObjInfo, OLECLIPFORMAT cf, HANDLE far *lphData);
+extern void UpdateOtherLinks(int doc);
+extern void ChangeOtherLinks(int doc, BOOL bChange, BOOL bPrompt);
+extern BOOL ObjSetUpdateOptions(OBJPICINFO *pPicInfo, WORD wParam, int doc, typeCP cpParaStart) ;
+extern OLEOPT_UPDATE ObjGetUpdateOptions(OBJPICINFO far *lpPicInfo);
+extern BOOL ObjWaitForObject(LPOBJINFO lpObjInfo,BOOL bCancelOK);
+extern BOOL ObjObjectSync(LPOBJINFO lpObjInfo, OLESTATUS (FAR PASCAL *lpProc)(LPOLEOBJECT lpObject),BOOL bCancelOK);
+extern int ObjSetSelectionType(int doc, typeCP cpFirst, typeCP cpLim);
+extern BOOL ObjQueryCpIsObject(int doc,typeCP cpFirst);
+extern FixInvalidLink(OBJPICINFO far *lpPicInfo,int doc, typeCP cpParaStart);
+extern void OfnInit(HANDLE hInst);
+extern ObjPushParms(int doc);
+extern ObjPopParms(BOOL bCache);
+void ObjWriteClearState(int doc);
+extern void ObjInvalidateObj(LPOLEOBJECT lpObject);
+extern void ObjInvalidatePict(OBJPICINFO *pPicInfo, typeCP cp);
+extern BOOL ObjDeletePrompt(int doc,typeCP cpFirst,typeCP cpLim);
+extern BOOL ObjSetHostName(LPOBJINFO lpOInfo, int doc);
+extern void ObjTryToKill(OBJPICINFO *pPicInfo);
+extern BOOL ObjCloneObjInfo(OBJPICINFO *pPicInfo, typeCP cpParaStart, szOBJNAME szObjName);
+extern LPOBJINFO ObjGetObjInfo(szOBJNAME szObjName);
+extern BOOL ObjCopyObjInfo(LPOBJINFO lpOldObjInfo, LPLPOBJINFO lplpNewObjInfo, szOBJNAME szObjName);
+extern BOOL ObjDeleteObject(LPOBJINFO lpObjInfo,BOOL bDelete);
+extern void ObjAdjustCps(int doc,typeCP cpLim, typeCP dcpAdj);
+extern void ObjAdjustCpsForDeletion(int doc);
+extern BOOL GimmeNewPicinfo(OBJPICINFO *pPicInfo, LPOBJINFO lpObjInfo);
+extern BOOL ObjMakeObjectReady(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart);
+extern BOOL ObjInitServerInfo(LPOBJINFO lpObjInfo);
+
+extern CHAR szAppName[10];
+extern HWND vhWndMsgBoxParent,hParentWw,vhWnd;
+extern HANDLE hMmwModInstance;
+extern int vdocParaCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern int docCur;
+extern struct SEL selCur;
+extern int docMac;
+
+#define WM_UPDATELB (WM_USER+0x100)
+#define WM_UPDATEBN (WM_USER+0x101)
+#define WM_OBJUPDATE (WM_USER+0x102)
+#define WM_OBJERROR (WM_USER+0x103)
+#define WM_OBJBADLINK (WM_USER+0x104)
+#define WM_DOLINKSCOMMAND (WM_USER+0x105)
+#define WM_UPDATE_INVALID (WM_USER+0x106)
+#define WM_OBJDELETE (WM_USER+0x107)
+#define WM_DIESCUMSUCKINGPIG (WM_USER+0x108)
+#define WM_RUTHRUYET (WM_USER+0x109)
+#define WM_UKANKANCEL (WM_USER+0x10a)
+#define WM_WAITFORSERVER (WM_USER+0x10b)
+
+#define szDOCCLASS "WINWRITE"
+#define hINSTANCE hMmwModInstance
+#define hDOCWINDOW vhWnd
+#define hMAINWINDOW hParentWw
+#define hPARENTWINDOW ((vhWndMsgBoxParent == NULL) ? \
+ hParentWw : vhWndMsgBoxParent)
+
+#define OBJ_SELECTIONTYPE (votObjSelType)
+
+typedef struct {
+ WORD deviceNameOffset;
+ WORD driverNameOffset;
+ WORD portNameOffset;
+ WORD extDevmodeOffset;
+ WORD extDevmodeSize;
+ WORD environmentOffset;
+ WORD environmentSize;
+} STDTARGETDEVICE;
+typedef STDTARGETDEVICE FAR *LPSTDTARGETDEVICE;
+
+#if 0
+typedef struct _RAWOLEOBJECT {
+ LPOLEOBJECTVTBL lpvtbl;
+ char objId[2];
+ HOBJECT hobj;
+ LPOLECLIENT lpclient;
+ } RAWOBJECT;
+typedef RAWOBJECT FAR *LPRAWOBJECT;
+#endif
+
+#endif
diff --git a/private/mvdm/wow16/write/obj2.c b/private/mvdm/wow16/write/obj2.c
new file mode 100644
index 000000000..132b37a4f
--- /dev/null
+++ b/private/mvdm/wow16/write/obj2.c
@@ -0,0 +1,1851 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#include "windows.h"
+#include "mw.h"
+#include "winddefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "cmddefs.h"
+#include "obj.h"
+#include "str.h"
+#include "objreg.h"
+#include <commdlg.h>
+#include <stdlib.h> // for strtoul()
+
+extern struct CHP vchpNormal;
+extern struct DOD (**hpdocdod)[];
+extern BOOL ferror;
+extern struct PAP vpapAbs;
+extern struct PAP vpapPrevIns;
+extern struct PAP *vppapNormal;
+extern int vdocParaCache;
+extern struct UAB vuab;
+extern int vfOutOfMemory,vfSysFull;
+extern int docUndo;
+extern struct FCB (**hpfnfcb)[];
+extern HCURSOR vhcArrow;
+
+/* intercepted stream functions work with this buffer */
+static typeCP cpObjectDataCurLoc=cp0, cpObjectDataBase=cp0;
+static DWORD cObjectData=0L,dwDataMax;
+static int docStream;
+static struct CHP *pchpStream;
+static struct PAP *ppapStream;
+
+static OPENFILENAME OFN;
+
+static void GetChp(struct CHP *pchp, typeCP cp, int doc);
+static BOOL ObjParaDup(int doc, typeCP cpFirst, typeCP cpLim);
+static BOOL bUniqueData(int doc, typeCP cpFirst, typeCP cpLim);
+static ObjOpenStreamIO(typeCP cpParaStart, int doc, struct CHP *pchp, struct PAP *ppapGraph, DWORD dwObjectSize);
+static void ObjCloseStreamIO(void);
+static typeCP ObjWriteDataToDoc( LPOLEOBJECT lpObject);
+static HANDLE OfnGetNewLinkName(HWND hwnd, HANDLE hData);
+static void Normalize(LPSTR lpstrFile) ;
+static HANDLE ObjMakeNewLinkName(HANDLE hData, ATOM atom) ;
+static char szCustFilterSpec[CBFILTERMAX];
+static char szFileName[CBPATHMAX];
+//static char szFilterSpec[CBFILTERMAX];
+//static char szLastDir[CBPATHMAX];
+static char szLinkCaption[cchMaxSz];
+static char szTemplateName[CBPATHMAX];
+static BOOL fUpdateAll = FALSE;
+static BOOL ObjStop=FALSE;
+static BOOL vbChangeOther;
+BOOL bNoEol=FALSE;
+
+#define ulmin(a,b) ((DWORD)(a) < (DWORD)(b) ? \
+ (WORD)(a) : (WORD)(b))
+
+
+/****************************************************************/
+/**************** OLE ENUMERATION FUNCTIONS *********************/
+/****************************************************************/
+
+#if 0 // good, just not used
+int
+ObjEnumInAllDocs(cpFARPROC lpFunc)
+{
+ int doc,count=0;
+ for (doc = 0; doc < docMac; doc++)
+ {
+ int nRetval;
+
+ nRetval = ObjEnumInDoc(doc, lpFunc);
+
+ if (nRetval < 0)
+ return -1;
+ else
+ count += nRetval;
+ }
+ return count;
+}
+#endif
+
+int
+ObjEnumInDoc(int doc, cpFARPROC lpFunc)
+{
+ typeCP cpMac = (**hpdocdod) [doc].cpMac;
+
+ return ObjEnumInRange(doc, cp0, cpMac, lpFunc);
+}
+
+
+int
+ObjEnumInRange(int doc, typeCP cpStart, typeCP cpEnd, cpFARPROC lpFunc)
+/* Call lpFunc for each OLE object.
+ lpFunc takes the following args:
+ a far pointer to a PICINFOX struct (can be NULL).
+ an int for the doc we're operating on.
+ a typeCP that gives the cp position of the PICINFOX struct.
+ lpFunc returns the cp of the paragraph following the PICINFO struct
+ if OK, or cp0 if error.
+ Enumeration quits if error returned from FARPROC.
+ Return number of objects operated on, or -1 if error.
+*/
+{
+ typeCP cpNow, cpLimPara;
+ int count;
+
+ /* Loop on paras */
+
+ for ( count = 0, cpNow = cpStart; cpNow < cpEnd; cpNow = cpLimPara )
+ {
+
+ Assert(cpEnd <= (**hpdocdod) [doc].cpMac);
+
+ /* this shouldn't happen */
+ if (cpEnd > (**hpdocdod) [doc].cpMac)
+ goto done;
+
+ ObjCachePara( doc, cpNow );
+
+ if (vpapAbs.fGraphics)
+ {
+ /* get PICINFO struct and see if its an object */
+ OBJPICINFO picInfo;
+ GetPicInfo(vcpFirstParaCache,vcpFirstParaCache + cchPICINFOX, doc, &picInfo);
+ if (bOBJ_QUERY_IS_OBJECT(&picInfo))
+ {
+ typeCP cpOldLimPara = vcpLimParaCache;
+
+ if (!lpFunc)
+ cpLimPara = vcpLimParaCache;
+ else
+ if ((cpLimPara = (*lpFunc)(&picInfo,doc,vcpFirstParaCache)) == 0)
+ goto error;
+
+ ++count;
+
+ /* amount para has grown ( < 0 if shrunk, 0 if none )*/
+ cpEnd += cpLimPara - cpOldLimPara;
+
+ continue;
+ }
+ }
+
+ cpLimPara = vcpLimParaCache;
+ }
+
+ /* success */
+ goto done;
+
+ error:
+ count = -1;
+
+ done:
+
+ return count;
+}
+
+ObjPicEnumInRange(OBJPICINFO *pPicInfo,int doc, typeCP cpFirst, typeCP cpLim, typeCP *cpCur)
+/*
+ Enumerate over PicInfos between cpFirst and cpLim in doc. If
+ cpCur == cpNil, then start at cpFirst, else start at *cpCur.
+ Return 0 if done, 1 otherwise.
+ Calls ObjCachePara() at picInfo.
+*/
+{
+ /* static typeCP cpCur;
+ used to use static, but that prevented being able to recursively
+ call this function, and its almost impossible to prevent with
+ asynchronicity rampant.
+ */
+
+ typeCP cpMac = (**hpdocdod) [doc].cpMac;
+
+ if (cpFirst >= cpMac)
+ return 0;
+
+ if (cpLim > cpMac)
+ cpLim = cpMac;
+
+ /* initialize cpCur */
+ if (*cpCur == cpNil)
+ /* then starting afresh */
+ *cpCur = cpFirst;
+ else
+ {
+ ObjCachePara(doc,*cpCur); // cache the previous para
+ *cpCur = vcpLimParaCache; // get next para
+ }
+
+ /* pull in next para */
+ do
+ {
+ if (*cpCur >= cpLim)
+ {
+ /* all done */
+ *cpCur = vcpFirstParaCache; // we want to point to last para hit
+ return 0;
+ }
+
+ ObjCachePara(doc,*cpCur);
+
+ if (vpapAbs.fGraphics)
+ {
+ GetPicInfo(*cpCur,*cpCur + cchPICINFOX, doc, pPicInfo);
+ if (bOBJ_QUERY_IS_OBJECT(pPicInfo))
+ return 1;
+ }
+ *cpCur = vcpLimParaCache;
+ }
+ while (1);
+}
+
+typeCP ObjSaveObjectToDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/*
+ Assumes para is cached.
+ In some cases we only write the picinfo. In others we write the
+ object data after the picinfo. We assume that the latter case
+ only occurs when the file is being saved.
+*/
+{
+ typeCP cpRetval; // cp of next byte in doc after what we just wrote
+ static BOOL bMyRecurse=FALSE;
+ DWORD dwObjectSize;
+ OLESTATUS olestat;
+ struct CHP chp;
+ struct PAP papGraph;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if (lpOBJ_QUERY_OBJECT(pPicInfo) == NULL)
+ return(vcpLimParaCache);
+
+ /* we don't save nothing if it ain't dirty and has data */
+ if (!fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) &&
+ dwOBJ_QUERY_DATA_SIZE(pPicInfo) != 0L)
+ return(vcpLimParaCache);
+
+ if (vfOutOfMemory || vfSysFull /*|| ObjStop*/)
+ return cp0;
+
+ olestat = OleQuerySize(lpOBJ_QUERY_OBJECT(pPicInfo),&dwObjectSize);
+
+ if (olestat == OLE_ERROR_BLANK)
+ dwObjectSize = 0L;
+ else if (ObjError(olestat))
+ return cp0;
+
+ /** don't let this function recurse (in CallBack) **/
+ if (bMyRecurse)
+ {
+ Assert(0); // this has never happened yet (8.21.91) v-dougk
+ return cp0;
+ }
+ bMyRecurse = TRUE;
+
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = FALSE;
+
+ /**
+ If docUndo will want to undo some region that contains this
+ object, and if saving the object changes the size of that
+ region, then vuab will become obsolete.
+ **/
+
+ ObjWriteClearState(doc);
+
+ GetChp(&chp, cpParaStart, doc);
+
+ if (dwOBJ_QUERY_DATA_SIZE(pPicInfo) != 0xFFFFFFFF)
+ /* then has been saved before */
+ {
+ /* zap the entire existing object */
+ papGraph = vpapAbs;
+ Replace(doc, cpParaStart, (vcpLimParaCache - vcpFirstParaCache), fnNil, fc0, fc0);
+ }
+ else // new object
+ {
+ ObjCachePara(doc,cpParaStart-1); // use previous PAP
+ papGraph = vpapAbs;
+ papGraph.fGraphics = TRUE;
+ ObjCachePara(doc,cpParaStart);
+ }
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) == NONE)
+ {
+ if (dwObjectSize)
+ /*
+ Insert New has culminated in a new baby object!
+ */
+ {
+ otOBJ_QUERY_TYPE(pPicInfo) = EMBEDDED; // do this first
+ if (!FComputePictSize(pPicInfo, &(pPicInfo->dxaSize), &(pPicInfo->dyaSize)))
+ {
+ cpRetval = cp0;
+ goto end;
+ }
+#if 0
+ DeleteAtom(aOBJ_QUERY_SERVER_CLASS(pPicInfo));
+ aOBJ_QUERY_SERVER_CLASS(pPicInfo) = NULL;
+#endif
+ }
+ else // don't save empty object
+ {
+ Assert(0);
+ goto end;
+ }
+ }
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Saving object\n\r");
+#endif
+
+ /*
+ Insert PICINFO struct. There is a problem here which is a
+ bug in Write (CheckGraphic()). EOL gets inserted when we are
+ replacing an object which is immediately in front of
+ another object. Kludge is to set this flag to inhibit.
+ */
+ bNoEol = TRUE;
+
+ if (bOBJ_QUERY_DONT_SAVE_DATA(pPicInfo))
+ /* only save picinfo until user does File.Save */
+ {
+ ObjUpdateFromObjInfo(pPicInfo);
+
+ bOBJ_QUERY_DONT_SAVE_DATA(pPicInfo) = FALSE;
+ dwOBJ_QUERY_DATA_SIZE(pPicInfo) = 0L;
+
+ pPicInfo->mm |= MM_EXTENDED; /* Extended file format */
+ InsertRgch( doc, cpParaStart, pPicInfo, sizeof(OBJPICINFO), &chp, &papGraph);
+ pPicInfo->mm &= ~MM_EXTENDED;
+
+ ObjCachePara(doc,cpParaStart);
+ cpRetval = vcpLimParaCache;
+ }
+ else
+ {
+ dwOBJ_QUERY_DATA_SIZE(pPicInfo) = dwObjectSize;
+ ObjUpdateFromObjInfo(pPicInfo);
+
+ pPicInfo->mm |= MM_EXTENDED; /* Extended file format */
+ InsertRgch( doc, cpParaStart, pPicInfo, sizeof(OBJPICINFO), &chp, NULL );
+ pPicInfo->mm &= ~MM_EXTENDED;
+
+ /* insert object data into doc */
+ ObjOpenStreamIO(cpParaStart + cchPICINFOX, doc, &chp, &papGraph, dwObjectSize);
+ cpRetval = ObjWriteDataToDoc(lpOBJ_QUERY_OBJECT(pPicInfo));
+ ObjCloseStreamIO();
+ }
+
+ bNoEol = FALSE;
+
+ end:
+
+ ObjCachePara(doc,cpParaStart);
+
+ bMyRecurse = FALSE;
+ return ((cpRetval == cp0) ? cp0 : vcpLimParaCache);
+}
+
+typeCP ObjLoadObjectInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/*
+ Do an OleLoad from object data in doc. Set lpobject in PICINFO struct.
+ Assumes para is cached.
+ This is a *synchronous* function.
+*/
+{
+ typeCP cpRetval = vcpLimParaCache;
+ szOBJNAME szObjName;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ {
+ if (ObjAllocObjInfo(pPicInfo,cpParaStart,pPicInfo->objectType,FALSE,NULL))
+ return(cp0);
+
+ if (ObjSetPicInfo(pPicInfo, doc, cpParaStart))
+ return(cp0);
+ }
+
+ else if (lpOBJ_QUERY_OBJECT(pPicInfo)) // already loaded
+ return(vcpLimParaCache);
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) == NONE)
+ return(vcpLimParaCache);
+
+ if (bOBJ_QUERY_TOO_BIG(pPicInfo)) // ObjLoadObject previously failed
+ return(cp0);
+
+ if ((dwOBJ_QUERY_DATA_SIZE(pPicInfo) == 0L) ||
+ (dwOBJ_QUERY_DATA_SIZE(pPicInfo) == 0xFFFFFFFFL))
+ /* then has no data */
+ return(cp0);
+
+ if (vfOutOfMemory || vfSysFull /*|| ObjStop*/)
+ return cp0;
+
+ StartLongOp();
+
+ ObjGetObjectName(lpOBJ_QUERY_INFO(pPicInfo),szObjName);
+
+ Assert(szObjName[0]);
+
+ ObjOpenStreamIO(cpParaStart + cchPICINFOX, doc, NULL, NULL, 0L);
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Loading object\n\r");
+#endif
+
+ if (ObjError(OleLoadFromStream(lpStream,
+ otOBJ_QUERY_TYPE(pPicInfo) == STATIC ? SPROTOCOL : PROTOCOL,
+ (LPOLECLIENT)lpOBJ_QUERY_INFO(pPicInfo),
+ lhClientDoc,szObjName,&lpOBJ_QUERY_OBJECT(pPicInfo))))
+ {
+ /* mark as unloadable to prevent infinite LoadObject loops */
+ bOBJ_QUERY_TOO_BIG(pPicInfo) = TRUE;
+ lpOBJ_QUERY_OBJECT(pPicInfo) = NULL; // just in case (OLE ain't good about this)
+ ferror = FALSE; // be sure to issue this message
+ Error(IDPMTFailedToLoadObject);
+ cpRetval = cp0;
+ goto end;
+ }
+
+ if (ObjInitServerInfo(lpOBJ_QUERY_INFO(pPicInfo)))
+ {
+ ferror = FALSE; // be sure to issue this message
+ Error(IDPMTOLEError);
+ goto end;
+ }
+
+ if (ObjUpdatePicSize(pPicInfo,cpParaStart))
+ if (ObjSetPicInfo(pPicInfo, doc, cpParaStart))
+ goto end;
+
+ ObjCachePara(doc,cpParaStart); // just in case
+
+ cpRetval = vcpLimParaCache;
+
+ end:
+ ObjCloseStreamIO();
+ EndLongOp(vhcArrow);
+ return cpRetval;
+}
+
+typeCP ObjEditObjectInDoc(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart)
+{
+ typeCP cpRetval;
+ OBJ_PLAYEDIT = OLEVERB_PRIMARY+1;
+ cpRetval = ObjPlayObjectInDoc(pPicInfo, doc, cpParaStart);
+ OBJ_PLAYEDIT = OLEVERB_PRIMARY; // the default
+ return cpRetval;
+}
+
+typeCP ObjPlayObjectInDoc(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart)
+{
+ OLESTATUS olestat;
+ LPOBJINFO lpOInfo=lpOBJ_QUERY_INFO(pPicInfo);
+
+ if ((otOBJ_QUERY_TYPE(pPicInfo) == STATIC) ||
+ (otOBJ_QUERY_TYPE(pPicInfo) == NONE))
+ return(vcpLimParaCache);
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ goto err;
+
+ fOBJ_QUERY_PLAY(pPicInfo) = OBJ_PLAYEDIT;
+
+ do
+ {
+#ifdef DEBUG
+ OutputDebugString( "Opening Object\n\r");
+#endif
+
+ StartLongOp();
+ olestat = OleActivate(lpOBJ_QUERY_OBJECT(pPicInfo),
+ OBJ_PLAYEDIT,
+ TRUE,
+ TRUE,
+ hDOCWINDOW,
+ NULL);
+ EndLongOp(vhcArrow);
+
+ switch (olestat)
+ {
+ /* check for bad link */
+ case OLE_ERROR_OPEN:
+ case OLE_ERROR_ADVISE_NATIVE:
+ case OLE_ERROR_ADVISE_PICT:
+ case OLE_ERROR_REQUEST_NATIVE:
+ case OLE_ERROR_REQUEST_PICT:
+
+ fOBJ_BADLINK(pPicInfo) = TRUE;
+ if (bLinkProps)
+ {
+ Error(IDPMTLinkUnavailable);
+ goto err;
+ }
+ else
+ {
+ ObjCachePara(doc,cpParaStart);
+ if (!FixInvalidLink(pPicInfo,doc,cpParaStart))
+ goto err;
+ olestat = OLE_OK;
+ lpOInfo->fCompleteAsync = TRUE; // cancel OleSetData (FixInvalid) as well
+ if (ObjWaitForObject(lpOInfo,TRUE))
+ goto err;
+ }
+ break;
+ }
+
+ if (ObjError(olestat))
+ goto err;
+ else
+ break;
+ }
+ while (1);
+
+ fOBJ_BADLINK(pPicInfo) = FALSE; // can't be bad if succeeded
+ //(**hpdocdod) [doc].fDirty = TRUE; // assume dirty is opened.
+ ObjCachePara(doc,cpParaStart); // just in case
+ return(vcpLimParaCache);
+
+ err:
+ Error(IDPMTFailedToActivate);
+ return cp0;
+}
+
+typeCP ObjUpdateObjectInDoc(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart)
+{
+ int xSize,ySize;
+ BOOL bUpdate = FALSE;
+ OLESTATUS olestat;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if ((otOBJ_QUERY_TYPE(pPicInfo) == STATIC) ||
+ (otOBJ_QUERY_TYPE(pPicInfo) == NONE))
+ return(vcpLimParaCache);
+
+ if (bLinkProps && bOBJ_WAS_UPDATED(pPicInfo))
+ return(vcpLimParaCache);
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ goto err;
+
+ do
+ {
+#ifdef DEBUG
+ OutputDebugString( "Updating Object\n\r");
+#endif
+
+ StartLongOp();
+ olestat = OleUpdate(lpOBJ_QUERY_OBJECT(pPicInfo));
+ EndLongOp(vhcArrow);
+
+ switch (olestat)
+ {
+ /* check for bad link */
+ case OLE_ERROR_OPEN:
+ case OLE_ERROR_ADVISE_NATIVE:
+ case OLE_ERROR_ADVISE_PICT:
+ case OLE_ERROR_REQUEST_NATIVE:
+ case OLE_ERROR_REQUEST_PICT:
+
+ fOBJ_BADLINK(pPicInfo) = TRUE;
+ if (bLinkProps)
+ {
+ Error(IDPMTLinkUnavailable);
+ goto err;
+ }
+ else
+ {
+ ObjCachePara(doc,cpParaStart);
+ if (!FixInvalidLink(pPicInfo,doc,cpParaStart))
+ goto err;
+ olestat = OLE_OK;
+ lpOBJ_QUERY_INFO(pPicInfo)->fCompleteAsync = TRUE; // cancel OleSetData (FixInvalid) as well
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ goto err;
+ }
+ break;
+ }
+
+ if (ObjError(olestat))
+ goto err;
+ else
+ break;
+ }
+ while (1);
+
+ ObjCachePara(doc,cpParaStart); // just in case
+
+ fOBJ_BADLINK(pPicInfo) = FALSE; // can't be bad if succeeded
+
+ if (bLinkProps)
+ {
+ bOBJ_WAS_UPDATED(pPicInfo) = TRUE;
+ }
+
+ return(vcpLimParaCache);
+
+ err:
+ Error(IDPMTFailedToUpdate);
+ return cp0;
+}
+
+typeCP ObjFreezeObjectInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+ szOBJNAME szObjName;
+ OBJPICINFO NewPicInfo = *pPicInfo;
+
+ if ((otOBJ_QUERY_TYPE(pPicInfo) == STATIC) ||
+ (otOBJ_QUERY_TYPE(pPicInfo) == NONE))
+ return(vcpLimParaCache);
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ goto err;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Freezing object\n\r");
+#endif
+
+ if (ObjCloneObjInfo(&NewPicInfo, cpParaStart, szObjName))
+ return cp0;
+
+ /* Make the object static. Note side effect of changing lpObject!! */
+ if (ObjError(OleObjectConvert(lpOBJ_QUERY_OBJECT(pPicInfo), SPROTOCOL,
+ (LPOLECLIENT)lpOBJ_QUERY_INFO(&NewPicInfo),
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(&NewPicInfo))))
+ goto err;
+
+ /* now delete original */
+ ObjDeleteObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE);
+
+ *pPicInfo = NewPicInfo;
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = TRUE;
+ otOBJ_QUERY_TYPE(pPicInfo) = STATIC;
+
+ /* we got a new name to save */
+ if (ObjSetPicInfo(pPicInfo, doc, cpParaStart))
+ goto err;
+
+ return(vcpLimParaCache);
+
+ err:
+ ObjDeleteObjInfo(lpOBJ_QUERY_INFO(&NewPicInfo));
+ Error(IDPMTFailedToFreeze);
+ return cp0;
+}
+
+typeCP ObjCloneObjectInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/* note we are *not* deleting the cloned object! Note side effect that
+ *pPicInfo gets altered to new clone values. */
+{
+ BOOL fDirty;
+ szOBJNAME szObjName;
+ OBJPICINFO NewPicInfo = *pPicInfo;
+ LPOLEOBJECT lpObject;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if (bOBJ_REUSE_ME(pPicInfo))
+ /* assume that the original picInfo will be deleted!!! */
+ {
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Reusing object\n\r");
+#endif
+ bOBJ_REUSE_ME(pPicInfo) = FALSE;
+ return(vcpLimParaCache);
+ }
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ goto err;
+
+ lpObject = lpOBJ_QUERY_OBJECT(pPicInfo);
+
+ /* clone it. This assumes the one we're cloning from is still in use
+ (shouldn't be deleted). */
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Cloning object\n\r");
+#endif
+
+ if (ObjCloneObjInfo(&NewPicInfo, cpParaStart, szObjName))
+ return cp0;
+
+ if (ObjError(OleClone(lpObject,
+ (LPOLECLIENT)lpOBJ_QUERY_INFO(&NewPicInfo),
+ lhClientDoc,szObjName,
+ &lpOBJ_QUERY_OBJECT(&NewPicInfo))))
+ goto err;
+
+
+ lpOBJ_QUERY_INFO(&NewPicInfo)->fCompleteAsync = TRUE;
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(&NewPicInfo),TRUE))
+ goto err;
+
+ if (lpOBJ_QUERY_INFO(&NewPicInfo)->fDeleteMe)
+ /* this is how we know it failed asynchronously */
+ goto err;
+
+ /**
+ Save object name and objinfo that we just got.
+ **/
+ *pPicInfo = NewPicInfo;
+
+ if (ObjSetPicInfo(pPicInfo, doc, cpParaStart))
+ goto err;
+
+ return(vcpLimParaCache);
+
+ err:
+ ObjDeleteObjInfo(lpOBJ_QUERY_INFO(&NewPicInfo));
+ Error(IDPMTFailedToCreateObject);
+ return cp0;
+}
+
+typeCP ObjToCloneInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Marking object reusable\n\r");
+#endif
+
+ bOBJ_REUSE_ME(pPicInfo) = TRUE;
+
+ return(vcpLimParaCache);
+}
+
+typeCP ObjFromCloneInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Marking object not reusable\n\r");
+#endif
+
+ bOBJ_REUSE_ME(pPicInfo) = FALSE;
+
+ return(vcpLimParaCache);
+}
+
+typeCP ObjBackupInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/* !!! used by link properties only !!!. Object guaranteed loaded */
+{
+ szOBJNAME szObjName;
+ LPOBJINFO lpCloneInfo=NULL;
+
+ if (lpOBJ_QUERY_CLONE(pPicInfo) == NULL) // then clone it
+ {
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Backing up object\n\r");
+#endif
+
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ return cp0;
+
+ if (ObjCopyObjInfo(lpOBJ_QUERY_INFO(pPicInfo),
+ &lpOBJ_QUERY_CLONE(pPicInfo),
+ szObjName))
+ return(cp0);
+
+ if (ObjError(OleClone(lpOBJ_QUERY_OBJECT(pPicInfo),
+ (LPOLECLIENT)lpOBJ_QUERY_CLONE(pPicInfo),
+ lhClientDoc,szObjName,&(lpOBJ_QUERY_CLONE(pPicInfo)->lpobject))))
+ return cp0;
+ }
+
+ return(vcpLimParaCache);
+}
+
+typeCP ObjClearCloneInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/* !!! used by link properties only !!! Object guaranteed loaded */
+/* delete clone, don't use it */
+{
+ if (lpOBJ_QUERY_CLONE(pPicInfo))
+ {
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Deleting clone\n\r");
+#endif
+ ObjDeleteObject(lpOBJ_QUERY_CLONE(pPicInfo),TRUE);
+ lpOBJ_QUERY_CLONE(pPicInfo) = NULL;
+ }
+
+ return(vcpLimParaCache);
+}
+
+typeCP ObjUseCloneInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/* !!! used by link properties only !!! */
+{
+ szOBJNAME szObjName;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if (lpOBJ_QUERY_CLONE(pPicInfo))
+ {
+ extern int FAR _cdecl sscanf(const char FAR *, const char FAR *, ...);
+ LPOBJINFO lpClone = lpOBJ_QUERY_CLONE(pPicInfo);
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "using clone\n\r");
+#endif
+
+ ObjDeleteObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE);
+
+ lpOBJ_QUERY_INFO(pPicInfo) = lpClone;
+ lpOBJ_QUERY_CLONE(pPicInfo) = NULL;
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = TRUE; // wanna save clone information
+ // just in case
+
+ /* might've been frozen, used by LoadObject (this is what is unique
+ in the context of link properties) */
+ otOBJ_QUERY_TYPE(pPicInfo) = LINK;
+
+ if (ObjSetPicInfo(pPicInfo, doc, cpParaStart))
+ return cp0;
+ }
+
+ return(vcpLimParaCache);
+}
+
+
+typeCP ObjSetNoUpdate(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Set no update for object\n\r");
+#endif
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) == LINK)
+ {
+ bOBJ_WAS_UPDATED(pPicInfo) = FALSE;
+ }
+
+ return(vcpLimParaCache);
+}
+
+
+typeCP ObjCheckObjectTypes(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+#ifdef DEBUG
+ //OutputDebugString( (LPSTR) "Checking Object Type\n\r");
+#endif
+
+ /* Result returned in OBJ_SELECTIONTYPE is highest object type which
+ exists at cpParaStart relative to current value of OBJ_SELECTIONTYPE.
+ */
+ switch(otOBJ_QUERY_TYPE(pPicInfo))
+ {
+ case STATIC:
+ if (OBJ_SELECTIONTYPE < STATIC)
+ OBJ_SELECTIONTYPE = STATIC;
+ //OBJ_CEMBEDS = 0;
+ return(vcpLimParaCache);
+
+ case LINK:
+ OBJ_SELECTIONTYPE = LINK;
+ //OBJ_CEMBEDS = 0;
+ return(vcpLimParaCache);
+
+ case NONE:
+ if (OBJ_SELECTIONTYPE < NONE)
+ OBJ_SELECTIONTYPE = NONE;
+ //OBJ_CEMBEDS = 0;
+ return(vcpLimParaCache);
+
+ case EMBEDDED:
+ if (OBJ_SELECTIONTYPE < EMBEDDED)
+ OBJ_SELECTIONTYPE = EMBEDDED;
+ //++OBJ_CEMBEDS;
+ return(vcpLimParaCache);
+
+ default:
+ Assert(0);
+ return cp0;
+ }
+}
+
+typeCP ObjSetHostNameInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if (lpOBJ_QUERY_OBJECT(pPicInfo) == NULL)
+ return(vcpLimParaCache); // dont care if not loaded
+
+ if ((otOBJ_QUERY_TYPE(pPicInfo) != EMBEDDED) &&
+ (otOBJ_QUERY_TYPE(pPicInfo) != NONE))
+ return(vcpLimParaCache);
+
+ //if (OleQueryOpen(lpOBJ_QUERY_OBJECT(pPicInfo)) != OLE_OK)
+ //return(vcpLimParaCache);
+
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ return cp0;
+
+ if (ObjSetHostName(lpOBJ_QUERY_INFO(pPicInfo),doc))
+ return(cp0);
+
+ return(vcpLimParaCache);
+}
+
+typeCP ObjChangeLinkInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/* assumes aNewName is set */
+{
+ HANDLE hData,hNewData=NULL;
+ typeCP cpRetval=cp0;
+ OLESTATUS olestat=OLE_OK;
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) != LINK)
+ return(vcpLimParaCache);
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ return cp0;
+
+ /* Change the link information */
+ /* if theres a newname, then use it. Else get a new name from user */
+ olestat = ObjGetData(lpOBJ_QUERY_INFO(pPicInfo), vcfLink, &hData);
+
+ if ((olestat == OLE_WARN_DELETE_DATA) || (olestat == OLE_OK))
+ {
+ if (!(hNewData = ObjMakeNewLinkName(hData, aNewName))
+ || !ObjSetData(pPicInfo, vcfLink, hNewData))
+ goto end;
+
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ /* this may not be necessary any more, check carefully. */
+ if (ObjUpdateObjectInDoc(pPicInfo,doc,cpParaStart) == cp0)
+ goto end;
+
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = TRUE;
+ fOBJ_BADLINK(pPicInfo) = FALSE;
+
+ cpRetval = vcpLimParaCache;
+ }
+
+ end:
+ if (hNewData)
+ GlobalFree(hNewData);
+ return cpRetval;
+}
+
+typeCP ObjUpdateLinkInDoc(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/**
+ Change or update link to aNewName if == aOldName. Assumes vbChangeOther
+ has been initialized.
+**/
+{
+ HANDLE hData;
+ char szRename[cchMaxSz];
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) != LINK)
+ return(vcpLimParaCache);
+
+ if (aOBJ_QUERY_DOCUMENT_LINK(pPicInfo) == aOldName)
+ /* Change the link information */
+ {
+ if (bLinkProps && bOBJ_WAS_UPDATED(pPicInfo))
+ return(vcpLimParaCache);
+
+ if (!fUpdateAll)
+ {
+ char szTmp[sizeof(szRename) + 90];
+ char szLink[30],szDocName[30];
+ CHAR szDocPath[ cchMaxFile ];
+ CHAR szFullPath[ cchMaxFile ];
+
+ SplitSzFilename( (**((**hpdocdod)[doc].hszFile)), szDocPath, szDocName );
+
+ GetAtomName(aOBJ_QUERY_DOCUMENT_LINK(pPicInfo),szFullPath,sizeof(szFullPath));
+ SplitSzFilename( szFullPath, szDocPath, szLink );
+
+ if (!szDocName[0])
+ LoadString(hINSTANCE, IDSTRUntitledDef, szDocName, sizeof(szDocName));
+
+ /* Ask the user if they want to update the links */
+ if (vbChangeOther)
+ LoadString(hINSTANCE, IDSTRRename, szRename, sizeof(szRename));
+ else // update other
+ LoadString(hINSTANCE, IDSTRUpdate, szRename, sizeof(szRename));
+
+ /* cast cause compiler is screwing up */
+ wsprintf((LPSTR)szTmp,(LPSTR)szRename,(LPSTR)szLink,(LPSTR)szDocName,(LPSTR)szLink);
+
+ if (MessageBox(hPARENTWINDOW, szTmp, szAppName,
+ MB_YESNO|MB_ICONEXCLAMATION) == IDNO)
+ return cp0;
+
+ ObjCachePara(doc,cpParaStart); // MessageBox screws things up
+ fUpdateAll = TRUE;
+ }
+
+ if (vbChangeOther)
+ {
+ if (ObjBackupInDoc(pPicInfo,doc,cpParaStart))
+ return ObjChangeLinkInDoc(pPicInfo,doc,cpParaStart);
+ }
+ else
+ {
+ if (ObjBackupInDoc(pPicInfo,doc,cpParaStart))
+ return ObjUpdateObjectInDoc(pPicInfo,doc,cpParaStart);
+ }
+ }
+
+ return(vcpLimParaCache);
+}
+
+
+typeCP ObjCloseObjectInDoc(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart)
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(cp0);
+
+ if (lpOBJ_QUERY_OBJECT(pPicInfo) == NULL)
+ return(vcpLimParaCache);
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) == STATIC) // nothing to close
+ return(vcpLimParaCache);
+
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ return cp0;
+
+ /*
+ Note that if this is an unfinished object, then the OLE_CLOSE
+ (whenever it happens to arrive) will cause the picinfo to be
+ deleted.
+ */
+ if (ObjError(OleClose(lpOBJ_QUERY_OBJECT(pPicInfo))))
+ return(cp0);
+
+ return(vcpLimParaCache);
+}
+
+/****************************************************************/
+/****************** OLE OBJECT DATA I/O *************************/
+/****************************************************************/
+static typeCP ObjWriteDataToDoc(LPOLEOBJECT lpObject)
+/*
+ Return cp after end of paragraph we've created or 0 if error.
+ Assume ObjStream is initialized.
+*/
+{
+ BOOL fSaveError = ferror;
+
+ if (vfOutOfMemory || vfSysFull /*|| ObjStop*/)
+ return cp0;
+
+ Assert(!ferror);
+
+ ferror = FALSE; /* so we can still call Replace(). */
+
+ if (ObjError(OleSaveToStream(lpObject,lpStream)))
+ {
+ if (ferror)
+ /* uh oh, hope we can clean up enough to look clean */
+ {
+ /* delete what we inserted if possible */
+ ferror = FALSE;
+ Replace(docStream, cpObjectDataBase - cchPICINFOX, cpObjectDataCurLoc - cpObjectDataBase + cchPICINFOX, fnNil, fc0, fc0);
+ ferror = TRUE;
+ return cp0;
+ }
+ }
+
+ /* is this call necessary? Important to do if InsertRgch doesn't. */
+ ObjCachePara(docStream,cpObjectDataBase - cchPICINFOX);
+
+ ferror = fSaveError || ferror;
+
+ return vcpLimParaCache; // cp after para we just inserted
+}
+
+
+/****************************************************************/
+/******************** OLE STREAM I/O ****************************/
+/****************************************************************/
+
+static
+ObjOpenStreamIO(typeCP cpParaStart, int doc, struct CHP *pchp, struct PAP *ppapGraph, DWORD dwObjectSize)
+{
+ if (cpObjectDataCurLoc)
+ ObjCloseStreamIO();
+
+ cpObjectDataBase = cpObjectDataCurLoc = cpParaStart;
+ cObjectData = 0L;
+ dwDataMax = dwObjectSize;
+ docStream = doc;
+ pchpStream = pchp;
+ ppapStream = ppapGraph;
+}
+
+static void
+ObjCloseStreamIO(void)
+{
+ cpObjectDataBase = cpObjectDataCurLoc = cp0;
+}
+
+LONG FAR PASCAL BufReadStream(LPOLESTREAM lpStream, char huge *lpstr, DWORD cb)
+{
+ DWORD dwRetval;
+ typeCP cpMac = vcpLimParaCache;
+ int cchRun;
+
+ if ((cb + cpObjectDataCurLoc) > cpMac) // reading past end of para
+ {
+ Assert(0);
+ return 0L;
+ }
+
+ for ( dwRetval = 0L;
+ cb;
+ cb -= cchRun,
+ cObjectData += cchRun,
+ cpObjectDataCurLoc += (typeCP) cchRun,
+ dwRetval += cchRun)
+ {
+ CHAR rgch[ 255 ];
+ register char *chT;
+ register unsigned cchT;
+ unsigned cch = ulmin(cb, 255L);
+
+ FetchRgch( &cchRun, rgch, docStream, cpObjectDataCurLoc, cpMac, cch);
+
+ if (ferror)
+ return -dwRetval;
+
+ for(chT = rgch,cchT=cchRun; cchT--; )
+ *lpstr++ = *chT++;
+ }
+
+ return dwRetval;
+}
+
+
+LONG FAR PASCAL BufWriteStream(LPOLESTREAM lpStream, char huge *lpstr, DWORD cb)
+{
+ DWORD dwRetval;
+ char *chT;
+ unsigned cchT;
+ CHAR rgch[255];
+ unsigned cch;
+ struct PAP *ppap=NULL;
+
+ for ( dwRetval = 0L;
+ dwRetval < cb;
+ cpObjectDataCurLoc += (typeCP) cch,
+ cObjectData += cch,
+ dwRetval += cch)
+ {
+ cch = ulmin(cb - dwRetval, 255L);
+
+ for(chT = rgch,cchT=cch; cchT--;)
+ *chT++ = *lpstr++;
+
+ if ((cObjectData + cch) == dwDataMax)
+ ppap = ppapStream;
+
+ InsertRgch( docStream, cpObjectDataCurLoc, rgch, cch, pchpStream, ppap);
+
+ if (ferror)
+ return 0L;
+ }
+
+ return dwRetval;
+}
+
+ObjGetPicInfo(LPOLEOBJECT lpObject, int doc, OBJPICINFO *pPicInfo, typeCP *pcpParaStart)
+/* get picInfo that has lpObject */
+/* !!! since writing this it has occurred to me that a quicker way to do
+ this would be to keep a list of pieces that point to objects. Pieces
+ never */
+{
+ OBJPICINFO picInfoT;
+ typeCP cpStart,cpMac= CpMacText(doc);
+
+ for (cpStart = cpNil; ObjPicEnumInRange(&picInfoT,doc,cp0,cpMac,&cpStart); )
+ {
+ if (lpOBJ_QUERY_INFO(&picInfoT) == NULL)
+ continue;
+
+ if (lpOBJ_QUERY_OBJECT(&picInfoT) == lpObject) // bingo
+ {
+ if (pPicInfo)
+ *pPicInfo = picInfoT;
+ if (pcpParaStart)
+ *pcpParaStart = cpStart;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL vfObjDisplaying=FALSE;
+BOOL ObjSetPicInfo(OBJPICINFO *pSrcPicInfo, int doc, typeCP cpParaStart)
+{
+/*
+ NOTE that you only gotta call this when you change the OBJPICINFO fields:
+ mm,
+ objecttype,
+ dwDataSize,
+ dwObjNum, or
+ lpObjInfo.
+*/
+ BOOL bError = FALSE;
+ typeFC fcT;
+ extern BOOL vfInvalid;
+ BOOL vfSaveInvalid = vfInvalid;
+ BOOL docDirty = (**hpdocdod) [doc].fDirty;
+
+ ObjPushParms(doc);
+
+ ObjCachePara(doc,cpParaStart);
+
+ if (vfObjDisplaying)
+ vfInvalid = FALSE; // this'll suppress things that mess up UpdateWw()
+ bNoEol = TRUE;
+
+ if (dwOBJ_QUERY_DATA_SIZE(pSrcPicInfo) == 0L)
+ /* is this ever executed? */
+ {
+ struct CHP chp;
+
+ /* problem is to retain graphics property of picinfo structure */
+ GetChp(&chp, cpParaStart, doc); // calls CachePara
+ NewChpIns(&chp);
+ ObjUpdateFromObjInfo(pSrcPicInfo);
+ pSrcPicInfo->mm |= MM_EXTENDED;
+ InsertRgch( doc, cpParaStart + (typeCP)cchPICINFOX, pSrcPicInfo,
+ (unsigned)cchPICINFOX, &chp, &vpapAbs );
+ pSrcPicInfo->mm &= ~MM_EXTENDED;
+
+ if (ferror)
+ return TRUE;
+
+ /* delete old pieces (in front) that pointed to duped data */
+ Replace(doc, cpParaStart, (typeCP)cchPICINFOX, fnNil, fc0, fc0);
+ }
+ else
+ {
+ ObjUpdateFromObjInfo(pSrcPicInfo);
+ pSrcPicInfo->mm |= MM_EXTENDED;
+ fcT = FcWScratch( pSrcPicInfo, cchPICINFOX );
+ pSrcPicInfo->mm &= ~MM_EXTENDED;
+
+ if (ferror)
+ return TRUE;
+ Replace( doc, cpParaStart, (typeCP)cchPICINFOX,
+ fnScratch, fcT, (typeFC)cchPICINFOX);
+ }
+
+ if (ferror)
+ return TRUE;
+
+ bNoEol = FALSE;
+ if (vfObjDisplaying)
+ vfInvalid = vfSaveInvalid;
+
+ /* don't want this to affect docDirty flag */
+ (**hpdocdod) [doc].fDirty = docDirty;
+
+ ObjPopParms(TRUE);
+
+ return bError;
+}
+
+
+void ChangeOtherLinks(int doc, BOOL bChange, BOOL bPrompt)
+/** For any items == aOldName, set to aNewName. Query user if OK first.
+ Assumes aOldName and aNewName are set. (See FixInvalidLink() and
+ ObjChangeLinkInDoc()).
+ bChange is TRUE if ChangeLink, FALSE if UpdateObject.
+ bPrompt is TRUe if prompt user for change.
+ **/
+{
+ fUpdateAll = !bPrompt;
+
+ vbChangeOther = bChange; // TRUE to change links, FALSE to update links
+ ObjEnumInDoc(doc,ObjUpdateLinkInDoc);
+
+}
+
+BOOL ObjQueryNewLinkName(OBJPICINFO *pPicInfo,int doc,typeCP cpParaStart)
+/** Return whether obtained new link name from user. Set aOldName
+ and aNewName. **/
+{
+ HANDLE hData,hNewData=NULL;
+ LPSTR lpdata=NULL;
+ BOOL bRetval = FALSE;
+ OLESTATUS olestat=OLE_OK;
+
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return(FALSE);
+
+ if (otOBJ_QUERY_TYPE(pPicInfo) != LINK)
+ return(FALSE);
+
+ if (ObjMakeObjectReady(pPicInfo,doc,cpParaStart))
+ return(FALSE);
+
+ /* query user for new name */
+ olestat = ObjGetData(lpOBJ_QUERY_INFO(pPicInfo), vcfLink, &hData);
+ if ((olestat == OLE_WARN_DELETE_DATA) || (olestat == OLE_OK))
+ if (!(hNewData = OfnGetNewLinkName(hPARENTWINDOW, hData)))
+ goto end;
+
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ aOldName = aOBJ_QUERY_DOCUMENT_LINK(pPicInfo);
+
+ lpdata=MAKELP(hNewData,0);
+
+ while (*lpdata++);
+
+ aNewName = AddAtom(lpdata);
+
+ bRetval = TRUE;
+
+ end:
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ if (hNewData)
+ GlobalFree(hNewData);
+
+ return bRetval;
+}
+
+FixInvalidLink(OBJPICINFO far *lpPicInfo, int doc, typeCP cpParaStart)
+/* returns FALSE if couldn't or wouldn't do anything, RETRY if reset link */
+{
+
+ fOBJ_BADLINK(lpPicInfo) = TRUE;
+ if (DialogBox(hINSTANCE, "DTINVALIDLINK",
+ hPARENTWINDOW, lpfnInvalidLink) == IDD_CHANGE)
+#if !defined(SMALL_OLE_UI)
+ fnObjProperties();
+#else
+ ObjChangeLinkInDoc(lpPicInfo,doc,cpParaStart);
+#endif
+ return FALSE;
+}
+
+/* ObjMakeNewLinkName() - Constructs a new link name from an atom.
+ */
+static HANDLE ObjMakeNewLinkName(HANDLE hData, ATOM atom)
+{
+ BOOL fSuccess = FALSE;
+ HANDLE hData2 = NULL;
+ HANDLE hData3 = NULL;
+ LPSTR lpstrData = NULL;
+ LPSTR lpstrLink = NULL;
+ LPSTR lpstrTemp;
+ char szFile[CBPATHMAX];
+
+ if (!GetAtomName(atom, szFile, CBPATHMAX)
+ || !(lpstrData = (LPSTR)GlobalLock(hData))
+ || !(hData2 = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, CBPATHMAX * 2))
+ || !(lpstrLink = lpstrTemp = (LPSTR)GlobalLock(hData2)))
+ goto Error;
+
+ /* ... copy the server name */
+ while (*lpstrTemp++ = *lpstrData++);
+
+ /* ... copy the document name */
+ lstrcpy(lpstrTemp, szFile);
+ lpstrTemp += lstrlen(lpstrTemp) + 1;
+ lpstrData += lstrlen(lpstrData) + 1;
+
+ /* ... copy the item name */
+ while (*lpstrTemp++ = *lpstrData++);
+ *lpstrTemp = 0;
+
+ /* ... and compress the memory block to minimal size */
+ GlobalUnlock(hData2);
+ hData3 = GlobalReAlloc(hData2, (DWORD)(lpstrTemp - lpstrLink + 1), 0);
+
+ if (!hData3)
+ hData3 = hData2;
+
+ fSuccess = TRUE;
+
+Error:
+ if (!fSuccess) {
+ if (lpstrLink)
+ GlobalUnlock(hData2);
+ if (hData2)
+ GlobalFree(hData2);
+ hData3 = NULL;
+ }
+
+ if (lpstrData)
+ GlobalUnlock(hData);
+
+ return hData3;
+}
+
+char *ObjGetServerName(LPOLEOBJECT lpObject, char *szServerName)
+{
+ LPSTR lpstrData;
+ HANDLE hData;
+ LONG otobject;
+ OLESTATUS olestat;
+
+ /** NOTE: OleGetData can return OLE_BUSY. Because of how
+ ObjGetServerName is used, we're not going to wait for the
+ object here, we'll just return if its busy **/
+
+ if (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
+ return NULL;
+
+ if (ObjError(OleQueryType(lpObject,&otobject)))
+ return NULL;
+
+ olestat = OleGetData(lpObject,
+ otobject == OT_LINK ? vcfLink : vcfOwnerLink,
+ &hData);
+
+ if ((olestat != OLE_WARN_DELETE_DATA) && (olestat != OLE_OK))
+ {
+ ObjError(olestat);
+ return NULL;
+ }
+
+ lpstrData = MAKELP(hData,0);
+ RegGetClassId(szServerName, lpstrData);
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ return szServerName;
+}
+
+/* OfnInit() - Initializes the standard file dialog OFN structure.
+ */
+void OfnInit(HANDLE hInst) {
+ LPSTR lpstr;
+
+ OFN.lStructSize = sizeof(OPENFILENAME);
+ OFN.hInstance = hInst;
+ OFN.nMaxCustFilter = CBFILTERMAX;
+ OFN.nMaxFile = CBPATHMAX;
+ OFN.Flags = OFN_HIDEREADONLY;
+ OFN.lCustData = NULL;
+ OFN.lpfnHook = NULL;
+ OFN.lpTemplateName = NULL;
+ OFN.lpstrDefExt = NULL;
+ OFN.lpstrFileTitle = NULL;
+
+ LoadString(hInst, IDSTRChangelink, szLinkCaption, sizeof(szLinkCaption));
+}
+
+/* OfnGetNewLinkName() - Sets up the "Change Link..." dialog box
+ */
+static HANDLE OfnGetNewLinkName(HWND hwnd, HANDLE hData)
+{
+ BOOL fSuccess = FALSE;
+ HANDLE hData2 = NULL;
+ HANDLE hData3 = NULL;
+ LPSTR lpData2 = NULL;
+ LPSTR lpstrData = NULL;
+ LPSTR lpstrFile = NULL;
+ LPSTR lpstrLink = NULL;
+ LPSTR lpstrPath = NULL;
+ LPSTR lpstrTemp = NULL;
+ char szDocFile[CBPATHMAX];
+ char szDocPath[CBPATHMAX];
+ HANDLE hServerFilter=NULL;
+
+ /* Get the link information */
+ if (!(lpstrData = GlobalLock(hData)))
+ goto Error;
+
+ /* Figure out the link's path name and file name */
+ lpstrTemp = lpstrData;
+ while (*lpstrTemp++);
+ lpstrPath = lpstrFile = lpstrTemp;
+ while (*(lpstrTemp = AnsiNext(lpstrTemp)))
+ if (*lpstrTemp == '\\')
+ lpstrFile = lpstrTemp + 1;
+
+ /* Copy the document name */
+ lstrcpy(szDocFile, lpstrFile);
+ *(lpstrFile - 1) = 0;
+
+ /* Copy the path name */
+ lstrcpy(szDocPath, ((lpstrPath != lpstrFile) ? lpstrPath : ""));
+ if (lpstrPath != lpstrFile) /* Restore the backslash */
+ *(lpstrFile - 1) = '\\';
+ while (*lpstrFile != '.' && *lpstrFile) /* Get the extension */
+ lpstrFile++;
+
+ /* Make a filter that respects the link's class name */
+ OFN.hwndOwner = hwnd;
+
+ OFN.nFilterIndex = RegMakeFilterSpec(lpstrData, lpstrFile, &hServerFilter);
+ if (OFN.nFilterIndex == -1)
+ goto Error;
+ OFN.lpstrFilter = (LPSTR)MAKELP(hServerFilter,0);
+
+ Normalize(szDocFile);
+ OFN.lpstrFile = (LPSTR)szDocFile;
+ OFN.lpstrInitialDir = (LPSTR)szDocPath;
+ OFN.lpstrTitle = (LPSTR)szLinkCaption;
+ OFN.lpstrCustomFilter = (LPSTR)szCustFilterSpec;
+
+
+ /* If we get a file... */
+ if (GetOpenFileName((LPOPENFILENAME)&OFN))
+ {
+ if (!(hData2 = GlobalAlloc(GMEM_DDESHARE | GMEM_ZEROINIT, CBPATHMAX * 2))
+ || !(lpstrLink = lpstrTemp = GlobalLock(hData2)))
+ goto Error;
+
+ /* ... copy the server name */
+ while (*lpstrTemp++ = *lpstrData++);
+
+ /* ... copy the document name */
+ lstrcpy(lpstrTemp, szDocFile);
+ lpstrTemp += lstrlen(lpstrTemp) + 1;
+ lpstrData += lstrlen(lpstrData) + 1;
+
+ /* ... copy the item name */
+ while (*lpstrTemp++ = *lpstrData++);
+ *lpstrTemp = 0;
+
+ /* ... and compress the memory block to minimal size */
+ GlobalUnlock(hData2);
+ hData3 = GlobalReAlloc(hData2, (DWORD)(lpstrTemp - lpstrLink + 1), 0);
+
+ if (!hData3)
+ hData3 = hData2;
+
+ fSuccess = TRUE;
+ }
+
+Error:
+ if (!fSuccess)
+ {
+ if (lpstrLink)
+ GlobalUnlock(hData2);
+ if (hData2)
+ GlobalFree(hData2);
+ hData3 = NULL;
+ }
+
+ if (lpstrData)
+ GlobalUnlock(hData);
+
+ if (hServerFilter)
+ GlobalFree(hServerFilter);
+
+ return hData3;
+}
+
+/* Normalize() - Removes the path specification from the file name.
+ *
+ * Note: It isn't possible to get "<drive>:<filename>" as input because
+ * the path received will always be fully qualified.
+ */
+static void Normalize(LPSTR lpstrFile)
+{
+ LPSTR lpstrBackslash = NULL;
+ LPSTR lpstrTemp = lpstrFile;
+
+ while (*lpstrTemp) {
+ if (*lpstrTemp == '\\')
+ lpstrBackslash = lpstrTemp;
+
+ lpstrTemp = AnsiNext(lpstrTemp);
+ }
+ if (lpstrBackslash)
+ lstrcpy(lpstrFile, lpstrBackslash + 1);
+}
+
+/* ObjSetUpdateOptions() - Sets the update options of the object.
+ *
+ * Returns: TRUE iff the command completed successfully
+ */
+BOOL ObjSetUpdateOptions(OBJPICINFO *pPicInfo, WORD wParam, int doc, typeCP cpParaStart)
+/* !!! Used by Link Properties only!!! Object guaranteed loaded */
+{
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ {
+ Error(IDPMTFailedToUpdateLink);
+ return FALSE;
+ }
+
+ if (ObjError(OleSetLinkUpdateOptions(lpOBJ_QUERY_OBJECT(pPicInfo),
+ (wParam == IDD_AUTO) ? oleupdate_always : oleupdate_oncall)))
+ {
+ Error(IDPMTFailedToUpdateLink);
+ return FALSE;
+ }
+
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = TRUE;
+
+ return TRUE;
+}
+
+/* ObjGetUpdateOptions() - Retrieves the update options of the object.
+ */
+OLEOPT_UPDATE ObjGetUpdateOptions(OBJPICINFO far *lpPicInfo)
+/* !!! Used by Link Properties only!!! Object guaranteed loaded */
+{
+ BOOL fSuccess = FALSE;
+ OLEOPT_UPDATE fUpdate;
+
+ if (otOBJ_QUERY_TYPE(lpPicInfo) == LINK)
+ {
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(lpPicInfo),TRUE))
+ return FALSE;
+
+ fSuccess = !ObjError(OleGetLinkUpdateOptions(lpOBJ_QUERY_OBJECT(lpPicInfo), &fUpdate));
+ }
+ return (fSuccess ? fUpdate : oleupdate_onsave);
+}
+
+OLESTATUS ObjGetData(LPOBJINFO lpObjInfo, OLECLIPFORMAT cf, HANDLE far *lphData)
+/*
+ Return olestat.
+ Put handle to data into lphData.
+ Assumes object is loaded.
+*/
+{
+ HANDLE hData;
+ OLESTATUS olestat;
+
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return OLE_BUSY;
+
+ olestat = OleGetData(lpObjInfo->lpobject, cf, lphData);
+ if ((olestat != OLE_WARN_DELETE_DATA) && (olestat != OLE_OK))
+ ObjError(olestat);
+ return olestat;
+}
+
+/* ObjSetData() - Set the object's (link) information
+ Sets DOCUMENT_LINK ATOM in pPicInfo
+ */
+BOOL ObjSetData(OBJPICINFO far *lpPicInfo, OLECLIPFORMAT cf, HANDLE hData)
+/* assumes object is loaded */
+{
+ HANDLE hitem;
+ LPSTR lpdata;
+
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(lpPicInfo),TRUE))
+ return FALSE;
+
+ if (ObjError(OleSetData(lpOBJ_QUERY_OBJECT(lpPicInfo), cf, hData)))
+ return FALSE;
+
+ /* If we have a link, update the document name */
+ if (cf == vcfLink && (lpdata = GlobalLock(hData)))
+ {
+ ATOM aSaveOld = aOBJ_QUERY_DOCUMENT_LINK(lpPicInfo);
+
+ while (*lpdata++);
+
+ aOBJ_QUERY_DOCUMENT_LINK(lpPicInfo) = AddAtom(lpdata);
+
+ if (aSaveOld)
+ DeleteAtom(aSaveOld);
+
+ GlobalUnlock(hData);
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+int ObjSetSelectionType(int doc, typeCP cpFirst, typeCP cpLim)
+{
+ /* set whether link or emb selected */
+ OBJ_SELECTIONTYPE = NONE; // this'll be set by ObjCheckObjectTypes()
+ //OBJ_CEMBEDS = 0; // this'll be set by ObjCheckObjectTypes()
+ return ObjEnumInRange(doc,cpFirst,cpLim,ObjCheckObjectTypes);
+}
+
+BOOL ObjQueryCpIsObject(int doc,typeCP cpFirst)
+{
+ OBJPICINFO picInfo;
+
+ /* assume its cached already! */
+ //ObjCachePara(doc,cpFirst); /* NOTE side effect of caching */
+
+ if (!vpapAbs.fGraphics)
+ return FALSE;
+
+ if (cpFirst >= CpMacText(doc))
+ return FALSE;
+
+ GetPicInfo(cpFirst,cpFirst + cchPICINFOX, doc, &picInfo);
+ return bOBJ_QUERY_IS_OBJECT(&picInfo);
+}
+
+
+ATOM MakeLinkAtom(LPOBJINFO lpObjInfo)
+{
+ HANDLE hData;
+ LPSTR lpdata;
+ ATOM aRetval=NULL;
+ OLESTATUS olestat=OLE_OK;
+
+ olestat = ObjGetData(lpObjInfo, vcfLink, &hData);
+
+ if ((olestat == OLE_WARN_DELETE_DATA) || (olestat == OLE_OK))
+ {
+ lpdata = MAKELP(hData,0);
+ while (*lpdata++);
+ aRetval = AddAtom(lpdata);
+
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+ }
+ return aRetval;
+}
+
+#include <time.h>
+void ObjGetObjectName(LPOBJINFO lpObjInfo, szOBJNAME szObjName)
+/* put object name from ObjInfo into szObjName */
+{
+ if (szObjName && lpObjInfo)
+ GetAtomName(lpObjInfo->aObjName,szObjName,sizeof(szObjName));
+}
+
+void ObjMakeObjectName(LPOBJINFO lpObjInfo, LPSTR lpstr)
+{
+ szOBJNAME szObjName;
+
+ time_t lTime;
+ time(&lTime);
+ wsprintf(szObjName, "%lx", lTime);
+
+ if (lpObjInfo)
+ lpObjInfo->aObjName = AddAtom(szObjName);
+
+ if (lpstr)
+ lstrcpy(lpstr,szObjName);
+}
+
+static void GetChp(struct CHP *pchp, typeCP cp, int doc)
+{
+ /**
+ Return chp at cp in *pchp.
+ Resets Cache to cp when done.
+ We assume that we're always inserting after an EOL or at beginning of
+ document.
+ **/
+
+extern struct CHP vchpAbs;
+
+if (cp == cp0) // beginning of doc
+{
+ typeCP cpMac = CpMacText(doc);
+ if (cpMac == cp0) // empty doc
+ {
+ /* force default character properties, font size to be 10 point */
+ *pchp = vchpNormal;
+ pchp->hps = hpsDefault;
+ return;
+ }
+ else // get next char props
+ {
+ ObjCachePara(doc,cp+1); // to reset
+ FetchCp( doc, cp+1, 0, fcmProps );
+ }
+}
+else
+{
+ ObjCachePara(doc,cp-1); // to reset
+ FetchCp( doc, cp-1, 0, fcmProps ); // previous paragraph's chp
+}
+
+*pchp = vchpAbs;
+
+if (pchp->fSpecial && pchp->hpsPos != 0)
+ { /* if this char is a footnote or page marker, then ignore */
+ pchp->hpsPos = 0; /* super/subscript stuff. */
+ pchp->hps = HpsAlter(pchp->hps, 1);
+ }
+
+pchp->fSpecial = fFalse;
+
+ObjCachePara(doc,cp); // to reset
+}
+
+BOOL ObjSetHostName(LPOBJINFO lpOInfo, int doc)
+/* TRUE if error */
+/* we assume object ain't busy!!! */
+{
+ extern CHAR szUntitled[20];
+ CHAR *PchStartBaseNameSz(),*szTitle= **((**hpdocdod)[doc].hszFile);
+
+ if (szTitle[0])
+ szTitle = PchStartBaseNameSz(szTitle);
+ else
+ szTitle = szUntitled;
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Setting host name\n\r");
+#endif
+
+ /*
+ Note that OleSetHostNames can return OLE_BUSY!!! So you
+ better call ObjWaitForObject() first.
+ */
+
+ if (ObjError(OleSetHostNames(lpOInfo->lpobject,szAppName,szTitle)))
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ObjMakeObjectReady(OBJPICINFO *pPicInfo, int doc, typeCP cpParaStart)
+/* Load object, complete async. Return whether an error. */
+{
+ if (lpOBJ_QUERY_INFO(pPicInfo) == NULL)
+ return TRUE;
+
+ if (lpOBJ_QUERY_OBJECT(pPicInfo) == NULL)
+ {
+ if (ObjLoadObjectInDoc(pPicInfo,doc,cpParaStart) == cp0)
+ return TRUE;
+ }
+ else if (ObjWaitForObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE))
+ return TRUE;
+
+ ObjCachePara(doc, cpParaStart);
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow16/write/obj3.c b/private/mvdm/wow16/write/obj3.c
new file mode 100644
index 000000000..91de04f37
--- /dev/null
+++ b/private/mvdm/wow16/write/obj3.c
@@ -0,0 +1,1972 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+#include "windows.h"
+#include "mw.h"
+#include "winddefs.h"
+#include "obj.h"
+#include "menudefs.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "objreg.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include "shellapi.h"
+#include <commdlg.h>
+
+extern BOOL ferror;
+extern HCURSOR vhcArrow;
+extern HCURSOR vhcIBeam;
+extern struct DOD (**hpdocdod)[];
+extern struct PAP vpapAbs;
+extern struct UAB vuab;
+extern struct WWD rgwwd[];
+extern BOOL bKillMe;
+extern BOOL fPropsError;
+extern int docScrap;
+extern int docUndo;
+extern PRINTDLG PD;
+
+static BOOL DoLinksCommand(WORD wParam, DWORD lParam, HWND hDlg, BOOL *bError);
+
+/****************************************************************/
+/*********************** OLE DISPLAY HANDLING *******************/
+/****************************************************************/
+BOOL ObjDisplayObjectInDoc(OBJPICINFO far *lpPicInfo,
+ int doc, typeCP cpParaStart,
+ HDC hDC, LPRECT lpBounds)
+{
+ BOOL bSuccess;
+
+
+ if (lpOBJ_QUERY_INFO(lpPicInfo) == NULL)
+ return(FALSE);
+
+ if (lpOBJ_QUERY_INFO(lpPicInfo)->fCantDisplay)
+ return(FALSE);
+
+ if (otOBJ_QUERY_TYPE(lpPicInfo) == NONE)
+ switch(otOBJ_QUERY_TYPE(lpPicInfo))
+ {
+ case NONE:
+ {
+#if OBJ_EMPTY_OBJECT_FRAME
+ extern DrawBlank(HDC hDC, RECT FAR *rc);
+ DrawBlank(hDC,lpBounds);
+#else
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Displaying empty object\n\r");
+#endif
+#endif
+ return TRUE;
+ }
+ }
+
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Displaying object\n\r");
+#endif
+
+ bSuccess = !ObjError(OleDraw(lpOBJ_QUERY_OBJECT(lpPicInfo),hDC,lpBounds,NULL,NULL));
+ if (!bSuccess)
+ lpOBJ_QUERY_INFO(lpPicInfo)->fCantDisplay = TRUE;
+ return bSuccess;
+}
+
+BOOL ObjQueryObjectBounds(OBJPICINFO far *lpPicInfo, HDC hDC,
+ int *pdxa, int *pdya)
+/* return bounds in twips */
+{
+ RECT bounds;
+ BOOL bRetval;
+ OLESTATUS olestat;
+ int mmOld;
+ POINT pt;
+
+ if (otOBJ_QUERY_TYPE(lpPicInfo) == NONE)
+ {
+ /* set to default */
+ *pdxa = nOBJ_BLANKOBJECT_X;
+ *pdya = nOBJ_BLANKOBJECT_Y;
+ return TRUE;
+ }
+
+ if ((olestat = OleQueryBounds(lpOBJ_QUERY_OBJECT(lpPicInfo),&bounds))
+ == OLE_ERROR_BLANK)
+ {
+ Assert(0);
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(lpPicInfo),TRUE))
+ return FALSE;
+ olestat = OleQueryBounds(lpOBJ_QUERY_OBJECT(lpPicInfo),&bounds);
+ }
+
+ if (ObjError(olestat))
+ return FALSE;
+
+ pt.x = bounds.right - bounds.left;
+ pt.y = -(bounds.bottom - bounds.top);
+#ifdef DEBUG
+ {
+ char szMsg[180];
+ wsprintf(szMsg,"Object HIMETRIC width: %d height: %d\n\r",pt.x,-pt.y);
+ OutputDebugString(szMsg);
+ }
+#endif
+ mmOld = SetMapMode(hDC,MM_HIMETRIC);
+ LPtoDP(hDC,&pt,1);
+
+ SetMapMode(hDC,MM_TWIPS);
+ DPtoLP(hDC,&pt,1);
+
+ SetMapMode(hDC,mmOld);
+ *pdxa = pt.x;
+ *pdya = pt.y;
+
+ return TRUE;
+}
+
+void ObjInvalidatePict(OBJPICINFO *pPicInfo, typeCP cp)
+{
+ struct EDL *pedl;
+ RECT rc;
+ extern int wwCur;
+
+ ObjPushParms(docCur);
+
+ ObjCachePara(docCur,cp);
+ Select(vcpFirstParaCache,vcpLimParaCache);
+
+ FreezeHp();
+ if (FGetPictPedl(&pedl)) // find pedl at selCur.cpFirst;
+ {
+ ComputePictRect( &rc, pPicInfo, pedl, wwCur );
+ InvalidateRect(hDOCWINDOW, &rc, FALSE);
+ }
+ MeltHp();
+
+ ObjPopParms(TRUE);
+ UPDATE_INVALID();
+}
+
+void ObjInvalidateObj(LPOLEOBJECT lpObject)
+{
+ typeCP cp;
+ OBJPICINFO picInfo;
+
+ ObjPushParms(docCur);
+ if (ObjGetPicInfo(lpObject,docCur,&picInfo,&cp))
+ ObjInvalidatePict(&picInfo,cp);
+ ObjPopParms(TRUE);
+}
+
+/****************************************************************/
+/*********************** OLE CLIPBOARD *************************/
+/****************************************************************/
+BOOL ObjCreateObjectInClip(OBJPICINFO *pPicInfo)
+{
+ LONG otobject;
+ szOBJNAME szObjName;
+ OLESTATUS olestat;
+ BOOL bRetval = FALSE;
+
+ Assert (lhClientDoc != NULL);
+
+ if (ObjAllocObjInfo(pPicInfo,selCur.cpFirst,NONE,TRUE,szObjName))
+ goto error;
+
+ if (vbObjLinkOnly)
+ {
+ if (ObjError(OleCreateLinkFromClip(PROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(pPicInfo),
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(pPicInfo), olerender_draw, 0)))
+ {
+ lpOBJ_QUERY_OBJECT(pPicInfo) = NULL;
+ goto error;
+ }
+ }
+ else if (vObjPasteLinkSpecial)
+ {
+ if (ObjError(OleCreateLinkFromClip(PROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(pPicInfo),
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(pPicInfo), olerender_format, cfObjPasteSpecial)))
+ {
+ lpOBJ_QUERY_OBJECT(pPicInfo) = NULL;
+ goto error;
+ }
+ }
+ else
+ {
+ WORD cfClipFormat=0;
+ OLEOPT_RENDER orRender = olerender_draw;
+
+ if (cfObjPasteSpecial && (cfObjPasteSpecial != vcfOwnerLink))
+ /* from PasteSpecial. There's a format on clipboard that
+ user wants to paste and its not the embedded object format.
+ So we'll do it as a static object. */
+ {
+ cfClipFormat = cfObjPasteSpecial;
+ orRender = olerender_format;
+ olestat = OLE_ERROR_CLIPBOARD; // force get static object
+ }
+ else // try for embedded
+ olestat = OleCreateFromClip(PROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(pPicInfo),
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(pPicInfo), orRender, cfClipFormat);
+
+ switch(olestat)
+ {
+ case OLE_ERROR_CLIPBOARD:
+ /* try static protocol */
+ olestat = OleCreateFromClip(SPROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(pPicInfo),
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(pPicInfo), orRender, cfClipFormat);
+ switch(olestat)
+ {
+ case OLE_ERROR_CLIPBOARD:
+ goto error;
+
+ case OLE_WAIT_FOR_RELEASE:
+ case OLE_OK:
+ break;
+
+ default:
+ lpOBJ_QUERY_OBJECT(pPicInfo) = NULL;
+ goto error;
+ }
+ break;
+
+ case OLE_WAIT_FOR_RELEASE:
+ case OLE_OK:
+ break;
+
+ default:
+ ObjError(olestat);
+ goto error;
+ }
+ }
+
+ /* Figure out what kind of object we have */
+ if (ObjError(OleQueryType(lpOBJ_QUERY_OBJECT(pPicInfo),&otobject)))
+ goto error;
+
+ switch(otobject)
+ {
+ case OT_LINK:
+ otOBJ_QUERY_TYPE(pPicInfo) = LINK;
+ break;
+ case OT_EMBEDDED:
+ otOBJ_QUERY_TYPE(pPicInfo) = EMBEDDED;
+ break;
+ default:
+ otOBJ_QUERY_TYPE(pPicInfo) = STATIC;
+ break;
+ }
+
+ if (ObjInitServerInfo(lpOBJ_QUERY_INFO(pPicInfo)))
+ goto error;
+
+ if (!FComputePictSize(pPicInfo, &(pPicInfo->dxaSize),
+ &(pPicInfo->dyaSize) ))
+ goto error;
+
+ return TRUE;
+
+ error:
+ if (lpOBJ_QUERY_INFO(pPicInfo))
+ ObjDeleteObject(lpOBJ_QUERY_INFO(pPicInfo),TRUE);
+ Error(IDPMTFailedToCreateObject);
+ return FALSE;
+}
+
+BOOL ObjWriteToClip(OBJPICINFO FAR *lpPicInfo)
+/* return TRUE if OK, FALSE if not */
+{
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Copying Object to Clipboard\n\r");
+#endif
+
+ if (otOBJ_QUERY_TYPE(lpPicInfo) == NONE)
+ return FALSE;
+
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(lpPicInfo),TRUE))
+ return FALSE;
+ return (!ObjError(OleCopyToClipboard(lpOBJ_QUERY_OBJECT(lpPicInfo))));
+}
+
+/****************************************************************/
+/*********************** OLE MENU HANDLING **********************/
+/****************************************************************/
+void ObjUpdateMenu(HMENU hMenu)
+/* this *MUST* be called *AFTER* paste menuitem has already been enabled
+ according to presence of non-object contents of the clipboard!!! (1.25.91) D. Kent */
+{
+ int mfPaste = MF_GRAYED;
+#if !defined(SMALL_OLE_UI)
+ int mfPasteLink = MF_GRAYED;
+ int mfLinks = MF_GRAYED;
+#endif
+ int mfPasteSpecial = MF_GRAYED;
+ int mfInsertNew = MF_GRAYED;
+ WORD cfFormat = NULL;
+ BOOL bIsEmbed=FALSE,bIsLink=FALSE;
+ extern BOOL vfOutOfMemory;
+ extern int vfOwnClipboard;
+
+ if (!vfOutOfMemory)
+ {
+ if (vfOwnClipboard)
+ {
+ if (CpMacText( docScrap ) != cp0) // something in scrap
+ mfPaste = MF_ENABLED;
+ }
+ else
+ {
+ if (OleQueryCreateFromClip(PROTOCOL, olerender_draw, 0) == OLE_OK)
+ mfPaste = MF_ENABLED, bIsEmbed=TRUE;
+ else if (OleQueryCreateFromClip(SPROTOCOL, olerender_draw, 0) == OLE_OK)
+ mfPaste = MF_ENABLED;
+
+ // Enable "Paste Link" if there is a link-able object in the clipboard
+ if (OleQueryLinkFromClip(PROTOCOL, olerender_draw, 0) == OLE_OK)
+ {
+ bIsLink=TRUE;
+#if !defined(SMALL_OLE_UI)
+ mfPasteLink = MF_ENABLED;
+#endif
+ }
+ }
+
+ /* There's no point in putting up pastespecial if there are no
+ alternate clip formats to choose from. */
+
+#if defined(SMALL_OLE_UI)
+ /* except to get paste link */
+#endif
+
+ if (OpenClipboard( hPARENTWINDOW ) )
+ {
+ int ncfCount=0;
+ while (cfFormat = EnumClipboardFormats(cfFormat))
+ switch (cfFormat)
+ {
+ case CF_TEXT:
+ mfPaste = MF_ENABLED;
+ case CF_BITMAP:
+ case CF_METAFILEPICT:
+ case CF_DIB:
+ ++ncfCount;
+ break;
+ }
+ CloseClipboard();
+
+ if (bIsLink || bIsEmbed)
+ {
+#if !defined(SMALL_OLE_UI)
+ if (ncfCount >= 1)
+#endif
+ mfPasteSpecial = MF_ENABLED;
+ }
+ else if (ncfCount > 1)
+ mfPasteSpecial = MF_ENABLED;
+ }
+
+#if !defined(SMALL_OLE_UI)
+ mfLinks = MF_ENABLED;
+#endif
+
+ // Insert_New is always enabled?
+ mfInsertNew = MF_ENABLED;
+ }
+
+ ObjUpdateMenuVerbs( hMenu );
+ EnableMenuItem(hMenu, imiPaste, mfPaste);
+#if !defined(SMALL_OLE_UI)
+ EnableMenuItem(hMenu, imiPasteLink, mfPasteLink);
+ EnableMenuItem(hMenu, imiProperties, mfLinks);
+#endif
+ EnableMenuItem(hMenu, imiPasteSpecial, mfPasteSpecial);
+ EnableMenuItem(hMenu, imiInsertNew, mfInsertNew);
+}
+
+
+/****************************************************************/
+/*********************** OLE DIALOG PROCS ***********************/
+/****************************************************************/
+#if !defined(SMALL_OLE_UI)
+/* Properties... dialog */
+BOOL FAR PASCAL fnProperties(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ ATOM aDocName = 0;
+ ATOM aCurName = 0;
+ static int idButton = 0;
+ OBJPICINFO picInfo;
+ BOOL bSelected;
+ int cSelected = 0;
+ int iListItem = 0;
+ HWND vhwndObjListBox = GetDlgItem(hDlg, IDD_LISTBOX);
+ extern HWND vhWndMsgBoxParent;
+ static BOOL bDidSomething;
+
+ switch (msg) {
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ break;
+
+ case WM_UPDATELB: /* Redrawing listbox contents */
+ SendMessage(vhwndObjListBox, WM_SETREDRAW, 0, 0L);
+
+ case WM_UPDATEBN: /* Updating Buttons only */
+ case WM_INITDIALOG: {
+ HANDLE hData = NULL;
+ LPSTR lpstrData = NULL;
+ LPSTR lpstrTemp;
+ char szType[40];
+ char szFull[cchMaxSz];
+ typeCP cpPicInfo;
+ struct SEL selSave;
+ OLESTATUS olestat;
+
+ idButton = 0;
+
+ /* Reset the list box */
+ if (msg == WM_INITDIALOG) // see fall through above
+ {
+ SendMessage(vhwndObjListBox, LB_RESETCONTENT, 0, 0L);
+ EnableOtherModeless(FALSE);
+ selSave=selCur;
+ //ObjWriteFixup(docCur,TRUE,cp0);
+ bLinkProps = TRUE;
+ bDidSomething = FALSE;
+ ObjSetSelectionType(docCur, selSave.cpFirst, selSave.cpLim);
+ }
+
+ /* Insert all the items in list box */
+ cpPicInfo = cpNil;
+ while (ObjPicEnumInRange(&picInfo,docCur,cp0,CpMacText(docCur),&cpPicInfo))
+ {
+ if (otOBJ_QUERY_TYPE(&picInfo) != LINK)
+ {
+ if (msg == WM_UPDATEBN)
+ continue; // object ain't in list box
+
+ if (msg == WM_INITDIALOG)
+ fOBJ_QUERY_IN_PROP_LIST(&picInfo) = OUT;
+ else if (fOBJ_QUERY_IN_PROP_LIST(&picInfo) == IN)
+ /** then this is an object which was in the list and
+ has been frozen */
+ {
+ fOBJ_QUERY_IN_PROP_LIST(&picInfo) = DELETED;
+ SendMessage(vhwndObjListBox, LB_DELETESTRING, iListItem, 0L);
+ }
+ else
+ continue; // object ain't in list box
+
+ continue;
+ }
+ else if (msg == WM_INITDIALOG)
+ {
+ fOBJ_QUERY_IN_PROP_LIST(&picInfo) = IN;
+
+ /**
+ This flag causes object to be cloned if any changes
+ are made to it. Clone will be used for cancel button.
+ **/
+
+ if (ObjLoadObjectInDoc(&picInfo,docCur,cpPicInfo) == cp0)
+ goto onOut;
+ }
+
+
+ if (msg == WM_INITDIALOG) // select in list if selected in doc
+ {
+ if (OBJ_SELECTIONTYPE == LINK)
+ bSelected = (cpPicInfo >= selSave.cpFirst &&
+ cpPicInfo < selSave.cpLim);
+ else // no selection, select first item
+ bSelected = iListItem == 0;
+
+ /* OR if its a bad link, take the liberty of selecting it */
+ if (fOBJ_BADLINK(&picInfo))
+ bSelected = TRUE;
+ }
+ else // select in list if already selected in list
+ bSelected = SendMessage(vhwndObjListBox, LB_GETSEL, iListItem, 0L);
+
+ /* Get the update options */
+ if (fOBJ_BADLINK(&picInfo))
+ {
+ LoadString(hINSTANCE, IDSTRFrozen, szType, sizeof(szType));
+ if (bSelected)
+ idButton = -1;
+ }
+ else switch (ObjGetUpdateOptions(&picInfo))
+ {
+ case oleupdate_always:
+ LoadString(hINSTANCE, IDSTRAuto, szType, sizeof(szType));
+ if (bSelected)
+ switch (idButton) {
+ case 0: idButton = IDD_AUTO; break;
+ case IDD_MANUAL: idButton = -1; break;
+ default: break;
+ }
+ break;
+ case oleupdate_oncall:
+ LoadString(hINSTANCE, IDSTRManual, szType, sizeof(szType));
+ if (bSelected)
+ switch (idButton) {
+ case 0: idButton = IDD_MANUAL; break;
+ case IDD_AUTO: idButton = -1; break;
+ default: break;
+ }
+ break;
+
+ default:
+ LoadString(hINSTANCE, IDSTRFrozen, szType, sizeof(szType));
+ if (bSelected)
+ idButton = -1;
+
+ /* Disable the change link button, can't change frozen link */
+ aCurName = -1;
+ }
+
+ /* Retrieve the server name */
+ olestat = ObjGetData(lpOBJ_QUERY_INFO(&picInfo), vcfLink, &hData);
+
+ if ((olestat != OLE_WARN_DELETE_DATA) && (olestat != OLE_OK))
+ return TRUE;
+
+ lpstrData = MAKELP(hData,0);
+
+ /* The link format is: "szClass0szDocument0szItem00" */
+
+ /* Retrieve the server's class ID */
+ RegGetClassId(szFull, lpstrData);
+ lstrcat(szFull, "\t");
+
+ /* Display the Document and Item names */
+ while (*lpstrData++);
+
+ /* Get this document name */
+ aDocName = AddAtom(lpstrData);
+
+ /* Make sure only one document selected for Change Link */
+ if (bSelected)
+ switch (aCurName) {
+ case 0:
+ aCurName = aDocName;
+ break;
+ case -1:
+ break;
+ default:
+ if (aCurName != aDocName)
+ aCurName = -1;
+ break;
+ }
+
+ DeleteAtom(aDocName);
+
+ /* Strip off the path name and drive letter */
+ lpstrTemp = lpstrData;
+ while (*lpstrTemp)
+ {
+ if (*lpstrTemp == '\\' || *lpstrTemp == ':')
+ lpstrData = lpstrTemp + 1;
+ lpstrTemp++;
+ }
+
+ /* Append the file name */
+ lstrcat(szFull, lpstrData);
+ lstrcat(szFull, "\t");
+
+ /* Append the item name */
+ while (*lpstrData++);
+ lstrcat(szFull, lpstrData);
+ lstrcat(szFull, "\t");
+
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ /* Append the type of link */
+ lstrcat(szFull, szType);
+
+ switch (msg)
+ {
+ case WM_UPDATELB:
+ SendMessage(vhwndObjListBox, LB_DELETESTRING, iListItem, 0L);
+ // fall through...
+
+ case WM_INITDIALOG:
+ SendMessage(vhwndObjListBox, LB_INSERTSTRING, iListItem, (DWORD)(LPSTR)szFull);
+ SendMessage(vhwndObjListBox, LB_SETSEL, bSelected, (DWORD)iListItem);
+ break;
+
+ }
+
+ if (bSelected)
+ cSelected++;
+
+ iListItem++;
+ }
+
+ /* Uncheck those buttons that shouldn't be checked */
+ CheckDlgButton(hDlg, IDD_AUTO, idButton == IDD_AUTO);
+ CheckDlgButton(hDlg, IDD_MANUAL, idButton == IDD_MANUAL);
+
+ /* Gray the Change Link... button, as appropriate */
+ EnableWindow(GetDlgItem(hDlg, IDD_CHANGE), (aCurName && aCurName != -1));
+ EnableWindow(GetDlgItem(hDlg, IDD_EDIT), cSelected);
+ EnableWindow(GetDlgItem(hDlg, IDD_PLAY), cSelected);
+ EnableWindow(GetDlgItem(hDlg, IDD_UPDATE), cSelected);
+ EnableWindow(GetDlgItem(hDlg, IDD_FREEZE), cSelected);
+ EnableWindow(GetDlgItem(hDlg, IDD_AUTO), cSelected);
+ EnableWindow(GetDlgItem(hDlg, IDD_MANUAL), cSelected);
+
+ if (msg == WM_UPDATELB)
+ {
+ /* WM_UPDATELB case: Redraw the list box */
+ InvalidateRect(vhwndObjListBox, NULL, TRUE);
+ SendMessage(vhwndObjListBox, WM_SETREDRAW, 1, 0L);
+ }
+
+ return TRUE;
+ }
+
+ case WM_SYSCOMMAND:
+ switch(wParam & 0xFFF0)
+ {
+ case SC_CLOSE:
+ goto onOut;
+ break;
+ }
+ break;
+
+ case WM_DOLINKSCOMMAND:
+ {
+ BOOL bError;
+ bDidSomething |= DoLinksCommand(wParam,lParam,hDlg,&bError);
+ switch (wParam)
+ {
+ case IDD_PLAY:
+ case IDD_EDIT:
+ InvalidateRect(hDOCWINDOW, NULL, TRUE);
+ if (!bError) // don't leave if there was an error
+ goto onOut;
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ if (bDidSomething)
+ {
+ SendMessage(hDlg,WM_DOLINKSCOMMAND,IDD_UNDO,0L);
+ InvalidateRect(hDOCWINDOW, NULL, TRUE);
+ bDidSomething = FALSE; // cause its undone now
+ }
+ // fall through...
+
+ case IDOK:
+ onOut:
+ if (bDidSomething)
+ {
+ ObjEnumInDoc(docCur,ObjClearCloneInDoc);
+ }
+ NoUndo();
+ bLinkProps = FALSE;
+ //ObjWriteFixup(docCur,FALSE,cp0);
+ OurEndDialog(hDlg, TRUE);
+ UpdateWindow(hDOCWINDOW); // cause we may have lost activation
+ return TRUE;
+
+ default:
+ /** posting message avoids some weird asynchronicities when
+ waiting for objects before returning after pressing a
+ button **/
+ PostMessage(hDlg,WM_DOLINKSCOMMAND,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL DoLinksCommand(WORD wParam, DWORD lParam, HWND hDlg, BOOL *bError)
+{
+ int cItems;
+ int i;
+ HANDLE hSelected=NULL;
+ int far *lpSelected;
+ typeCP cpSuccess;
+ typeCP cpPicInfo;
+ BOOL bFirst=TRUE;
+ OBJPICINFO picInfo;
+ BOOL bDidSomething=FALSE;
+ HWND vhwndObjListBox = GetDlgItem(hDlg, IDD_LISTBOX);
+
+ StartLongOp();
+
+ *bError = FALSE;
+
+ switch (wParam)
+ {
+ case IDD_REFRESH:
+ /** update a link if its been set to AUTOMATIC update */
+ {
+ OLEOPT_UPDATE UpdateOpt;
+ if (!ObjError(OleGetLinkUpdateOptions(((LPOBJINFO)lParam)->lpobject,&UpdateOpt)))
+ if (UpdateOpt == oleupdate_always)
+ fnObjUpdate((LPOBJINFO)lParam);
+ goto SkipIt;
+ }
+ break;
+ case IDD_LISTBOX:
+ switch (HIWORD(lParam))
+ {
+ case LBN_SELCHANGE:
+ PostMessage(hDlg, WM_UPDATEBN, 0, 0L); // fall through
+ default:
+ goto SkipIt;
+ }
+ break;
+
+ case IDD_CHANGE:
+ aNewName = aOldName = 0;
+ // fall through...
+
+ case IDD_UPDATE:
+ ObjEnumInDoc(docCur,ObjSetNoUpdate);
+ break;
+
+ case IDD_AUTO:
+ case IDD_MANUAL:
+ if (IsDlgButtonChecked(hDlg,wParam))
+ goto SkipIt;
+ /* work around for bug #8280 */
+ CheckDlgButton(hDlg,wParam,TRUE);
+ break;
+ }
+
+
+ /**
+ Everything after here is done for each item selected in
+ links list box *
+ **/
+
+ /* If nothing is selected, quit! */
+ if (wParam != IDD_UNDO)
+ {
+ if ((cItems = SendMessage(vhwndObjListBox, LB_GETSELCOUNT, 0, 0L)) <= 0)
+ goto SkipIt;
+
+ if ((hSelected = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
+ cItems * sizeof(int))) == NULL)
+ {
+ Error(IDPMTNoMemory);
+ goto SkipIt;
+ }
+
+ if ((lpSelected = (int far *)GlobalLock(hSelected)) == NULL)
+ {
+ Error(IDPMTNoMemory);
+ goto SkipIt;
+ }
+
+ /* Retrieve the selected items (in sorted order) */
+ SendMessage(vhwndObjListBox, LB_GETSELITEMS,
+ cItems, (DWORD)lpSelected);
+ }
+
+
+ for (i = 0, cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,docCur,cp0,CpMacText(docCur),&cpPicInfo);)
+ {
+ /**
+ For IDD_UNDO we do all. Dirty flag will filter in the ones
+ we've operated on. Assumes Saved before calling (see
+ fnObjProperties())
+ **/
+ if (fOBJ_QUERY_IN_PROP_LIST(&picInfo)) // is or was in list
+ {
+ if (wParam == IDD_UNDO)
+ {
+ cpSuccess = ObjUseCloneInDoc(&picInfo,docCur,cpPicInfo);
+ if ((cpSuccess == cp0) || ferror || fPropsError)
+ break; // there was an error
+ }
+ else if (fOBJ_QUERY_IN_PROP_LIST(&picInfo) == IN)
+ {
+ /** We're enumerating all objects, not just
+ ones in list box **/
+ if (*lpSelected == i) // selected item
+ {
+ ObjCachePara(docCur,cpPicInfo);
+ switch(wParam)
+ {
+ case IDD_AUTO: /* Change the (link) update options */
+ case IDD_MANUAL:
+ if (!fOBJ_BADLINK(&picInfo))
+ {
+ cpSuccess = ObjBackupInDoc(&picInfo,docCur,cpPicInfo);
+ if (cpSuccess)
+ cpSuccess = (typeCP)ObjSetUpdateOptions(&picInfo, wParam, docCur, cpPicInfo);
+
+ }
+ break;
+
+ case IDD_CHANGE:
+ if (bFirst)
+ {
+ if (!ObjQueryNewLinkName(&picInfo,docCur,cpPicInfo))
+ // then didn't get new link name
+ goto SkipIt;
+
+ bFirst=FALSE;
+ }
+
+ cpSuccess = ObjBackupInDoc(&picInfo,docCur,cpPicInfo);
+
+ if (cpSuccess)
+ cpSuccess = ObjChangeLinkInDoc(&picInfo,docCur,cpPicInfo);
+
+ /* must do this because we don't want to put up
+ ChangeOtherLinks dialog until we know the first
+ change was a success */
+ if (cpSuccess)
+ {
+ lpOBJ_QUERY_INFO(&picInfo)->fCompleteAsync = TRUE;
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(&picInfo),TRUE))
+ cpSuccess = cp0;
+ else if (ferror || fPropsError)
+ cpSuccess = cp0;
+ }
+ break;
+
+ case IDD_PLAY:
+ cpSuccess = ObjPlayObjectInDoc(&picInfo,docCur,cpPicInfo);
+ break;
+
+ case IDD_EDIT:
+ cpSuccess = ObjEditObjectInDoc(&picInfo,docCur,cpPicInfo);
+ break;
+
+ case IDD_UPDATE:
+
+ cpSuccess = ObjBackupInDoc(&picInfo,docCur,cpPicInfo);
+
+ if (cpSuccess)
+ cpSuccess = ObjUpdateObjectInDoc(&picInfo,docCur,cpPicInfo);
+
+ /* must do this because we don't want to put up
+ ChangeOtherLinks dialog until we know the first
+ change was a success */
+ if (cpSuccess)
+ {
+ lpOBJ_QUERY_INFO(&picInfo)->fCompleteAsync = TRUE;
+ if (ObjWaitForObject(lpOBJ_QUERY_INFO(&picInfo),TRUE))
+ cpSuccess = cp0;
+ else if (ferror || fPropsError)
+ cpSuccess = cp0;
+ }
+ break;
+ case IDD_UPDATEOTHER:
+ aOldName = aOBJ_QUERY_DOCUMENT_LINK(&picInfo);
+ if (cpSuccess)
+ ChangeOtherLinks(docCur,FALSE,TRUE);
+ aOldName=0;
+ break;
+ case IDD_FREEZE:
+ cpSuccess = ObjBackupInDoc(&picInfo,docCur,cpPicInfo);
+
+ if (cpSuccess)
+ cpSuccess = ObjFreezeObjectInDoc(&picInfo,docCur,cpPicInfo);
+ break;
+ }
+ if ((cpSuccess == cp0) || ferror || fPropsError)
+ break; // there was an error
+ lpSelected++;
+ }
+ i++; // counting all objects in list box
+ } // end if IN
+ }
+ }
+
+ /*** Handle error conditions ***/
+ if ((cpSuccess == cp0) || ferror || fPropsError)
+ {
+ *bError = TRUE;
+ if (!ferror) // issue error message
+ {
+ switch (wParam)
+ {
+ case IDD_UPDATE:
+ case IDD_CHANGE:
+ Error(IDPMTLinkUnavailable);
+ break;
+ default:
+ Error(IDPMTOLEError);
+ break;
+ }
+ }
+
+ if (wParam != IDD_UNDO)
+ {
+ /** so we can continue calling Replace(), etc */
+ ferror = FALSE;
+
+ /* undo whatever we tried to do that failed */
+ ObjCachePara(docCur,cpPicInfo); // for use clone
+ ObjUseCloneInDoc(&picInfo,docCur,cpPicInfo);
+ lpOBJ_QUERY_INFO(&picInfo)->fCompleteAsync = TRUE;
+ ObjWaitForObject(lpOBJ_QUERY_INFO(&picInfo),TRUE);
+ ObjInvalidatePict(&picInfo,cpPicInfo);
+ PostMessage(hDlg,WM_UPDATELB,0,0L);
+
+ ferror = FALSE; // again
+ }
+
+ fPropsError = FALSE;
+ }
+
+ switch (wParam)
+ {
+ /* Dismiss the dialog on Open */
+ case IDD_UPDATEOTHER:
+ UPDATE_INVALID();
+ break;
+
+ case IDD_PLAY:
+ case IDD_EDIT:
+ case IDD_UNDO:
+ break;
+
+ case IDD_UPDATE:
+ if (cpSuccess)
+ SendMessage(hDlg,WM_COMMAND,IDD_UPDATEOTHER,0L);
+ bDidSomething = TRUE;
+ break;
+
+ case IDD_CHANGE:
+ if (cpSuccess)
+ {
+ /** aOldName and aNewName are now set, change other links having
+ aOldName */
+ /** if first change is bad, don't change others */
+ ChangeOtherLinks(docCur,TRUE,TRUE);
+ UPDATE_INVALID();
+ }
+
+ aOldName=0;
+ aNewName=0;
+
+ // fall through....
+
+ case IDD_FREEZE:
+ case IDD_AUTO:
+ case IDD_MANUAL:
+ PostMessage(hDlg,WM_UPDATELB,0,0L);
+ bDidSomething = TRUE;
+ break;
+ }
+
+ SkipIt:
+
+ if (hSelected)
+ GlobalFree(hSelected);
+
+ EndLongOp(vhcArrow);
+
+ return bDidSomething;
+}
+#else
+// cause I don't wanna change def file yet...
+BOOL FAR PASCAL fnProperties(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ hDlg;
+}
+#endif
+
+/* Invalid Link dialog */
+int FAR PASCAL fnInvalidLink(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+#if 0
+ {
+ char lpString[120];
+
+ LoadString(hINSTANCE, (WORD)lParam, lpString, sizeof(lpString));
+ SetDlgItemText(hDlg,IDD_MESSAGE,lpString);
+ }
+#endif
+ break;
+
+ case WM_SYSCOMMAND:
+ switch(wParam & 0xFFF0)
+ {
+ case SC_CLOSE:
+ EndDialog(hDlg, IDOK);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ case IDD_CHANGE:
+ EndDialog(hDlg, wParam);
+ }
+ }
+ return FALSE;
+}
+
+/* Insert New... dialog */
+int FAR PASCAL fnInsertNew(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ HWND hwndList = GetDlgItem(hDlg, IDD_LISTBOX);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ if (!RegGetClassNames(hwndList))
+ OurEndDialog(hDlg, IDCANCEL);
+
+ EnableOtherModeless(FALSE);
+ SendMessage(hwndList, LB_SETCURSEL, 0, 0L);
+ break;
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ break;
+
+ case WM_SYSCOMMAND:
+ switch(wParam & 0xFFF0)
+ {
+ case SC_CLOSE:
+ OurEndDialog(hDlg, IDCANCEL);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case IDD_LISTBOX:
+ if (HIWORD(lParam) != LBN_DBLCLK)
+ break;
+
+ case IDOK:
+ StartLongOp();
+ if (!RegCopyClassName(hwndList, (LPSTR)szClassName))
+ wParam = IDCANCEL;
+ // fall through ...
+
+ case IDCANCEL:
+ OurEndDialog(hDlg, wParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+BOOL vbCancelOK=FALSE;
+
+/* Waiting for object dialog */
+BOOL FAR PASCAL fnObjWait(HWND hDlg, unsigned msg, WORD wParam, LONG lParam)
+{
+ static LPOLEOBJECT lpObject;
+ static LPOBJINFO lpOInfo;
+ static BOOL bCanCancel;
+ extern HWND hwndWait;
+ extern int vfDeactByOtherApp;
+ extern int flashID;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ /**
+ NOTE: the key idea in setting these options is that the cancel
+ button must cancel what the user thinks is the current operation.
+
+ vbCancelOK == TRUE,
+ cancel button may be enabled, depending on other flags
+ vbCancelOK is set in WMsgLoop.
+
+ lpOInfo->fCancelAsync == TRUE,
+ Cancel is enabled if vbCancelOK
+ Cancel button cancels dialog without regard to pending async.
+ Pending async is killed quietly in CallBack if possible.
+ Generally use if the pending async is not part of the operation
+ being cancelled, and:
+ 1) You're about to make a very important call which justifies
+ silently killing any pending operation.
+ Note: this one is weird if you're trying to release or delete, because
+ the pending async could itself be a release or delete.
+
+ lpOInfo->fCompleteAsync == TRUE,
+ Cancel is enabled only if pending async can be cancelled.
+ Cancel button cancels pending async.
+ Generally use if the pending async *is* part of the operation
+ being cancelled, and:
+ 1) You're in a sequence of async calls and cancelling
+ would require cancelling the previous async in the
+ sequence, or
+ 2) You have just made an async call which you want to make
+ synchronous but don't mind if the user cancels it.
+
+ lpOInfo->fCanKillAsync == TRUE,
+ Use with lpOInfo->fCompleteAsync.
+ Indicates that we already know that the async can be cancelled,
+ so Cancel button can be enabled immediately.
+ **/
+
+ hwndWait = hDlg;
+ lpObject = (LPOLEOBJECT)lParam;
+
+ Assert (lpObject != NULL);
+
+ lpOInfo = GetObjInfo(lpObject);
+
+ Assert(lpOInfo != NULL);
+
+ bCanCancel=FALSE;
+ if (vbCancelOK && (!lpOInfo->fCompleteAsync || lpOInfo->fCanKillAsync))
+ SendMessage(hDlg,WM_UKANKANCEL,0,0L);
+
+ if (lpOInfo->fCancelAsync)
+ /* we'll cancel async in CallBack if get a QUERY_RETRY */
+ lpOInfo->fKillMe = TRUE;
+
+ SetTimer(hDlg, 1234, 250, (FARPROC)NULL);
+
+ return TRUE;
+ }
+ break;
+
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ break;
+
+ case WM_RUTHRUYET:
+ case WM_TIMER:
+ /* this is a lot easier than making this modeless */
+ /* we gotta check this because if server dies we don't get
+ an OLE_RELEASE (the 'normal way this dialog is knocked off),
+ rather OleQueryReleaseStatus will return OLE_OK */
+ if (OleQueryReleaseStatus(lpObject) != OLE_BUSY)
+ PostMessage(hDlg,WM_DIESCUMSUCKINGPIG,0,0L);
+ break;
+
+ case WM_UKANKANCEL:
+ /* we got a QUERY_RETRY or are initing */
+ if (!bCanCancel && vbCancelOK)
+ {
+ char szMsg[20];
+
+ LoadString(hINSTANCE, IDSTRCancel, szMsg, sizeof(szMsg));
+ SetDlgItemText(hDlg,IDOK,szMsg);
+ bCanCancel=TRUE;
+ }
+ break;
+
+ case WM_DIESCUMSUCKINGPIG:
+ hwndWait = NULL;
+
+ KillTimer(hDlg, 1234);
+
+ /* clear flags */
+ if (CheckPointer(lpOInfo,1))
+ {
+ lpOInfo->fCompleteAsync =
+ lpOInfo->fCancelAsync =
+ lpOInfo->fCanKillAsync = FALSE;
+ }
+
+ /* wParam is TRUE if error */
+ OurEndDialog(hDlg,wParam);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case IDOK:
+ if (bCanCancel) // pressed cancel button
+ {
+ if (lpOInfo->fCompleteAsync)
+ lpOInfo->fKillMe = TRUE; // cancel async asynchronously
+ else if (lpOInfo->fCancelAsync)
+ lpOInfo->fKillMe = FALSE; // had a chance to kill, user doesn't care anymore
+ PostMessage(hDlg,WM_DIESCUMSUCKINGPIG,1,0L);
+ }
+ else
+ {
+ /* retry */
+ if (OleQueryReleaseStatus(lpObject) != OLE_BUSY)
+ PostMessage(hDlg,WM_DIESCUMSUCKINGPIG,0,0L);
+ }
+ break;
+
+ case IDD_SWITCH:
+ /* bring up task list */
+ DefWindowProc(hDlg,WM_SYSCOMMAND,SC_TASKLIST,0L);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+
+/****************************************************************/
+/*********************** VARIOUS OLE FUNCTIONS ******************/
+/****************************************************************/
+void fnObjInsertNew(void)
+{
+ OBJPICINFO picInfo;
+ typeCP cpNext=selCur.cpFirst;
+
+ if (!FWriteOk( fwcInsert ))
+ return;
+
+ /* this'll set global szClassName */
+ if (OurDialogBox(hINSTANCE, "DTCREATE" ,hMAINWINDOW, lpfnInsertNew) == IDCANCEL)
+ return;
+
+ StartLongOp();
+
+ ObjCachePara( docCur, cpNext);
+
+ if (!ObjCreateObjectInDoc(docCur, cpNext))
+ {
+ ClearInsertLine();
+ fnClearEdit(OBJ_INSERTING);
+ NoUndo();
+ }
+ EndLongOp(vhcIBeam);
+}
+
+
+BOOL ObjCreateObjectInDoc(int doc,typeCP cpParaStart)
+/* assumes szClassName is set to server class */
+/* called only for InsertObject */
+/* return whether error */
+{
+ szOBJNAME szObjName;
+ LPOBJINFO lpObjInfo=NULL;
+
+ if ((lpObjInfo = ObjGetObjInfo(szObjName)) == NULL)
+ goto err;
+
+ if (ObjError(OleCreate(PROTOCOL, (LPOLECLIENT)lpObjInfo,
+ (LPSTR)szClassName,
+ lhClientDoc, szObjName, &(lpObjInfo->lpobject), olerender_draw, 0)))
+ {
+ /* will free memory later */
+ lpObjInfo->lpobject = NULL;
+ goto err;
+ }
+
+ /* normally set in ObjAllocObjInfo, but for unfinished objects we need it now! */
+ lpObjInfo->cpWhere = cpParaStart;
+
+ lpObjInfo->objectType = NONE;
+
+ //lpObjInfo->aName = AddAtom(szClassName);
+
+ if (ObjInitServerInfo(lpObjInfo))
+ goto err;
+
+ return FALSE;
+
+ err:
+ if (lpObjInfo)
+ ObjDeleteObject(lpObjInfo,TRUE);
+ Error(IDPMTFailedToCreateObject);
+ return TRUE;
+}
+
+#define DRAG_EMBED 0 /* nothing */
+#define DRAG_LINK 6 /* Ctrl + Shift + Drag */
+#define DRAG_MULTIPLE 4 /* Shift + Drag */
+
+void ObjGetDrop(HANDLE hDrop, BOOL bOpenFile)
+{
+ int nNumFiles,count;
+ char szFileName[cchMaxFile];
+ extern struct CHP vchpSel;
+ struct CHP chpT;
+ BYTE bKeyState = 0;
+ typeCP cpFirst=selCur.cpFirst, dcp = 0;
+ int cchAddedEol=0;
+ typeCP cpNext=selCur.cpFirst,cpPrev=selCur.cpFirst,cpSel;
+ OBJPICINFO picInfo;
+ BOOL bError=FALSE;
+ static char szPackage[] = "Package";
+ MSG msg;
+
+ if (!FWriteOk( fwcInsert ))
+ return;
+
+ /* get number of files dropped */
+ nNumFiles = DragQueryFile(hDrop,0xFFFF,NULL,0);
+
+ /* See what the user wants us to do */
+ PeekMessage(&msg, (HWND)NULL, NULL, NULL, PM_NOREMOVE);
+ bKeyState = ((((GetKeyState(VK_SHIFT) < 0) << 2)
+ | ((GetKeyState(VK_CONTROL) < 0) << 1)));
+
+ if ((nNumFiles == 0) ||
+ ((bKeyState != DRAG_EMBED) && (bKeyState != DRAG_LINK) && (bKeyState != DRAG_MULTIPLE)) ||
+ (bOpenFile && (bKeyState != DRAG_EMBED) && (bKeyState != DRAG_MULTIPLE)))
+ {
+ DragFinish(hDrop);
+ return;
+ }
+
+ if (bOpenFile)
+ {
+ DragQueryFile(hDrop,0,szFileName,sizeof(szFileName));
+ fnOpenFile((LPSTR)szFileName);
+ DragFinish(hDrop);
+ return;
+ }
+
+ ClearInsertLine();
+
+ if (fnClearEdit(OBJ_INSERTING))
+ return;
+
+ StartLongOp();
+
+ chpT = vchpSel;
+
+ (**hpdocdod)[docCur].fFormatted = fTrue;
+
+ if (cpFirst > cp0)
+ {
+ ObjCachePara(docCur, cpFirst - 1);
+ if (vcpLimParaCache != cpFirst)
+ {
+ cchAddedEol = ccpEol;
+ InsertEolPap(docCur, selCur.cpFirst, &vpapAbs);
+ cpNext += (typeCP)ccpEol;
+ }
+ }
+
+ ObjCachePara( docCur, cpNext );
+
+ /* create object for each file dropped */
+ for (count=0; count < nNumFiles; ++count)
+ {
+ szOBJNAME szObjName;
+ typeCP cpTmp;
+
+ /* get the filename */
+ DragQueryFile(hDrop,count,szFileName,sizeof(szFileName));
+
+ if (ObjAllocObjInfo(&picInfo,cpNext,EMBEDDED,TRUE,szObjName))
+ {
+ bError=TRUE;
+ goto end;
+ }
+
+ if ((bKeyState == DRAG_LINK))
+ {
+ if (ObjError(OleCreateLinkFromFile(PROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(&picInfo),
+ szPackage,
+ szFileName, NULL,
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(&picInfo), olerender_draw, 0)))
+ {
+ bError=TRUE;
+ lpOBJ_QUERY_OBJECT(&picInfo) = NULL;
+ goto end;
+ }
+ }
+ else // if ((bKeyState == DRAG_EMBED))
+ {
+ if (ObjError(OleCreateFromFile(PROTOCOL, (LPOLECLIENT)lpOBJ_QUERY_INFO(&picInfo),
+ szPackage,
+ szFileName,
+ lhClientDoc, szObjName,
+ &lpOBJ_QUERY_OBJECT(&picInfo), olerender_draw, 0)))
+ {
+ bError=TRUE;
+ lpOBJ_QUERY_OBJECT(&picInfo) = NULL;
+ goto end;
+ }
+ }
+
+ if (ObjInitServerInfo(lpOBJ_QUERY_INFO(&picInfo)))
+ {
+ bError=TRUE;
+ goto end;
+ }
+
+ if (!FComputePictSize(&picInfo, &(picInfo.dxaSize),
+ &(picInfo.dyaSize)))
+ {
+ bError=TRUE;
+ goto end;
+ }
+
+ ObjCachePara(docCur,cpNext);
+ if ((cpTmp = ObjSaveObjectToDoc(&picInfo,docCur,cpNext)) == cp0)
+ {
+ bError=TRUE;
+ goto end;
+ }
+
+ cpNext = cpTmp;
+ }
+
+ end:
+
+ dcp = cpNext-cpFirst;
+ if (dcp)
+ {
+ cpSel=CpFirstSty(cpFirst + dcp, styChar );
+
+ SetUndo( uacInsert, docCur, cpFirst, dcp, docNil, cpNil, cp0, 0 );
+ SetUndoMenuStr(IDSTRUndoEdit);
+
+ if (vuab.uac == uacReplNS)
+ /* Special UNDO code for picture paste */
+ vuab.uac = uacReplPic;
+
+ Select(cpSel, cpSel);
+ vchpSel = chpT; /* Preserve insert point props across this operation */
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ { /* If running head/foot, remove chSects & set para props */
+ MakeRunningCps( docCur, cpFirst, dcp );
+ }
+ if (ferror)
+ NoUndo();
+ }
+
+ if (bError)
+ {
+ Error(IDPMTFailedToCreateObject);
+ ObjDeleteObject(lpOBJ_QUERY_INFO(&picInfo),TRUE);
+ }
+
+ EndLongOp(vhcIBeam);
+ DragFinish(hDrop);
+}
+
+int vcVerbs;
+void fnObjDoVerbs(WORD wVerb)
+{
+ NoUndo();
+
+ if ((wVerb == imiVerb) // more than one object selected
+ || (vcVerbs == 1)) // one verb
+ OBJ_PLAYEDIT = OLEVERB_PRIMARY;
+ else
+ OBJ_PLAYEDIT = (int)(wVerb - imiVerb - 1);
+ ObjEnumInRange(docCur,selCur.cpFirst,selCur.cpLim,ObjPlayObjectInDoc);
+ OBJ_PLAYEDIT = OLEVERB_PRIMARY;
+}
+
+void fnObjProperties(void)
+{
+ int nRetval;
+
+ if (nRetval != -1)
+ OurDialogBox(hINSTANCE, "DTPROP", hMAINWINDOW, lpfnLinkProps);
+}
+
+BOOL fnObjUpdate(LPOBJINFO lpObjInfo)
+{
+ BOOL bRetval;
+#ifdef DEBUG
+ OutputDebugString( (LPSTR) "Updating object\n\r");
+#endif
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return TRUE;
+
+ StartLongOp();
+ if ((bRetval = ObjError(OleUpdate(lpObjInfo->lpobject))))
+ Error(IDPMTFailedToUpdate);
+ EndLongOp(vhcArrow);
+ return bRetval;
+}
+
+
+BOOL ObjDeleteObject(LPOBJINFO lpObjInfo, BOOL bDelete)
+/** Delete object as well as objinfo. Note this must be synchronous.
+ Return whether an error.
+**/
+{
+ LPOLEOBJECT lpObject;
+
+ Assert(lpObjInfo != NULL);
+
+ if (!CheckPointer((LPSTR)lpObjInfo,1))
+ return FALSE; // already deleted
+
+ lpObject = lpObjInfo->lpobject;
+
+ if (lpObject == NULL)
+ {
+ ObjDeleteObjInfo(lpObjInfo);
+ return FALSE;
+ }
+
+ /* make sure not already deleted */
+ if (!ObjIsValid(lpObject))
+ {
+ ObjDeleteObjInfo(lpObjInfo);
+ return FALSE;
+ }
+
+ /** asynchronous deletion **/
+ if (OleQueryReleaseStatus(lpObject) != OLE_BUSY)
+ {
+ OLESTATUS olestat;
+
+ if (bDelete)
+ olestat = OleDelete(lpObject);
+ else
+ olestat = OleRelease(lpObject);
+
+ switch (olestat)
+ {
+ case OLE_OK:
+ ObjDeleteObjInfo(lpObjInfo);
+ break;
+ case OLE_WAIT_FOR_RELEASE:
+ lpObjInfo->fFreeMe = TRUE;
+ break;
+ }
+ }
+ else if (bDelete)
+ lpObjInfo->fDeleteMe = TRUE; // delete on OLE_RELEASE
+ else
+ lpObjInfo->fReleaseMe = TRUE; // release on OLE_RELEASE
+
+ return FALSE;
+}
+
+
+#include <print.h>
+HANDLE hStdTargetDevice=NULL;
+
+void ObjSetTargetDevice(BOOL bSetObjects)
+{
+ extern PRINTDLG PD; /* Common print dlg structure, initialized in the init code */
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+ LPSTDTARGETDEVICE lpStdTargetDevice;
+ WORD nCount;
+ DEVMODE FAR *lpDevmodeData;
+ char FAR *lpData;
+ LPOLEOBJECT lpObject;
+ STDTARGETDEVICE stdT;
+
+ if (!PD.hDevMode)
+ /* then get for default printer */
+ {
+ if (hszPrinter == NULL || hszPrDriver == NULL || hszPrPort == NULL)
+ return;
+
+ if (**hszPrinter == '\0' || **hszPrDriver == '\0' || **hszPrPort == '\0')
+ return;
+
+ if (fnPrGetDevmode())
+ return;
+ }
+
+ lpDevmodeData = MAKELP(PD.hDevMode,0);
+
+ /* get the offsets */
+ stdT.deviceNameOffset = 0;
+ nCount = CchSz(*hszPrinter);
+
+ stdT.driverNameOffset = nCount;
+ nCount += CchSz(*hszPrDriver);
+
+ stdT.portNameOffset = nCount;
+ nCount += CchSz(*hszPrPort);
+
+ stdT.extDevmodeOffset = nCount;
+ nCount += (stdT.extDevmodeSize = lpDevmodeData->dmSize);
+
+ stdT.environmentOffset = nCount;
+ nCount += (stdT.environmentSize = lpDevmodeData->dmSize);
+
+ /* alloc the buffer */
+ if (hStdTargetDevice == NULL)
+ {
+ if ((hStdTargetDevice = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,nCount+sizeof(STDTARGETDEVICE))) == NULL)
+ return;
+ }
+ else
+ {
+ if ((hStdTargetDevice =
+ GlobalReAlloc(hStdTargetDevice,
+ nCount+sizeof(STDTARGETDEVICE),GMEM_MOVEABLE|GMEM_ZEROINIT)) == NULL)
+ {
+ return;
+ }
+ }
+
+ lpStdTargetDevice = (LPSTDTARGETDEVICE)GlobalLock(hStdTargetDevice);
+ GlobalUnlock(hStdTargetDevice);
+
+ /* copy stdT into lpStdTargetDevice */
+ bltbx((LPSTR)&stdT, lpStdTargetDevice, sizeof(STDTARGETDEVICE));
+
+ /* get temporary pointer to the end of StdTargetDevice (the data buffer) */
+ lpData = ((LPSTR)lpStdTargetDevice) + sizeof(STDTARGETDEVICE);
+
+ /* now fill the buffer */
+ nCount = lpStdTargetDevice->driverNameOffset;
+ bltbx((LPSTR)*hszPrinter, lpData, nCount);
+ lpData += nCount;
+
+ nCount = lpStdTargetDevice->portNameOffset -
+ lpStdTargetDevice->driverNameOffset;
+ bltbx((LPSTR)*hszPrDriver, lpData, nCount);
+ lpData += nCount;
+
+ nCount = lpStdTargetDevice->extDevmodeOffset -
+ lpStdTargetDevice->portNameOffset;
+ bltbx((LPSTR)*hszPrPort, lpData, nCount);
+ lpData += nCount;
+
+ nCount = lpStdTargetDevice->extDevmodeSize;
+ bltbx(lpDevmodeData, (LPSTR)lpData, nCount);
+ lpData += nCount;
+
+ /* environment info is the same as the devmode info */
+ bltbx(lpDevmodeData, (LPSTR)lpData, nCount);
+
+ /* now set all the objects to this printer */
+ if (bSetObjects)
+ {
+ lpObject=NULL;
+ do
+ {
+ OleEnumObjects(lhClientDoc,&lpObject);
+ if (lpObject)
+ {
+#ifdef DEBUG
+ OutputDebugString("Setting Target Device\n\r");
+#endif
+
+ OleSetTargetDevice(lpObject,hStdTargetDevice);
+ }
+ }
+ while (lpObject);
+ }
+}
+
+BOOL ObjSetTargetDeviceForObject(LPOBJINFO lpObjInfo)
+/* return whether error */
+/* we assume object ain't busy!! */
+{
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+
+ if (lpObjInfo == NULL)
+ {
+ Assert(0);
+ return TRUE;
+ }
+ if (lpObjInfo->lpobject == NULL)
+ {
+ Assert(0);
+ return TRUE;
+ }
+
+ if (lpObjInfo->objectType == STATIC)
+ return FALSE;
+
+ if (hszPrinter == NULL || hszPrDriver == NULL || hszPrPort == NULL)
+ return FALSE;
+
+ if (**hszPrinter == '\0' || **hszPrDriver == '\0' || **hszPrPort == '\0')
+ return FALSE;
+
+ if (PD.hDevMode == NULL)
+ ObjSetTargetDevice(FALSE);
+
+ if (PD.hDevMode == NULL)
+ {
+ return FALSE; // punt, couldn't get extdevmode structure.
+ // device doesn't support it
+ }
+
+#ifdef DEBUG
+ OutputDebugString("Setting Target Device\n\r");
+#endif
+
+ return (ObjError(OleSetTargetDevice(lpObjInfo->lpobject,hStdTargetDevice)));
+}
+
+#if 0
+BOOL ObjContainsUnfinished(int doc, typeCP cpFirst, typeCP cpLim)
+{
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ BOOL bRetval=FALSE;
+
+ StartLongOp();
+
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cpFirst,cpLim,&cpPicInfo);
+ )
+ {
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ continue;
+
+ if (otOBJ_QUERY_TYPE(&picInfo) == NONE)
+ {
+ bRetval = TRUE;
+ break;
+ }
+ }
+
+ EndLongOp(vhcArrow);
+ return bRetval;
+}
+#endif
+
+BOOL ObjContainsOpenEmb(int doc, typeCP cpFirst, typeCP cpLim, BOOL bLookForUnfinished)
+{
+ OBJPICINFO picInfo;
+ typeCP cpPicInfo;
+ BOOL bRetval=FALSE;
+ LPLPOBJINFO lplpObjTmp;
+
+ StartLongOp();
+
+ for (cpPicInfo = cpNil;
+ ObjPicEnumInRange(&picInfo,doc,cpFirst,cpLim,&cpPicInfo);
+ )
+ {
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ continue;
+
+ if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL)
+ continue;
+
+#if 0 // see new check below (NONEs are no longer saved to doc)
+ if (otOBJ_QUERY_TYPE(&picInfo) == NONE)
+ {
+ bRetval = TRUE;
+ break;
+ }
+#endif
+
+ if ((otOBJ_QUERY_TYPE(&picInfo) == EMBEDDED) &&
+ OleQueryOpen(lpOBJ_QUERY_OBJECT(&picInfo)) == OLE_OK)
+ {
+ bRetval = TRUE;
+ break;
+ }
+ }
+
+ if (bLookForUnfinished)
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if (((*lplpObjTmp)->objectType == NONE) &&
+ ((*lplpObjTmp)->cpWhere >= cpFirst) &&
+ ((*lplpObjTmp)->cpWhere <= cpLim))
+ {
+ bRetval = TRUE;
+ break;
+ }
+ }
+
+ EndLongOp(vhcArrow);
+ return bRetval;
+}
+
+BOOL ObjDeletionOK(int nMode)
+/**
+ Return whether OK to delete objects in current selection.
+ We don't worry about unfinished objects because they are just floating around in space
+ (ie, no picinfo has been yet saved to the doc),
+ and we don't allow the user to delete them until they are finished or the
+ document is abandonded.
+ **/
+{
+ if (ObjContainsOpenEmb(docCur, selCur.cpFirst, selCur.cpLim,FALSE))
+ {
+ switch (nMode)
+ {
+ case OBJ_INSERTING:
+ Error(IDPMTInsertOpenEmb);
+ return FALSE;
+ break;
+ case OBJ_CUTTING:
+ case OBJ_DELETING:
+ {
+ char szMsg[cchMaxSz];
+
+ LoadString(hINSTANCE,
+ nMode == OBJ_DELETING ? IDPMTDeleteOpenEmb : IDPMTCutOpenEmb,
+ szMsg, sizeof(szMsg));
+
+ if (MessageBox(hPARENTWINDOW, (LPSTR)szMsg, (LPSTR)szAppName, MB_OKCANCEL) == IDCANCEL)
+ return FALSE;
+
+ if (ObjEnumInRange(docCur,selCur.cpFirst,selCur.cpLim,ObjCloseObjectInDoc) < 0)
+ return FALSE;
+
+ /* handle any unfinished objects in selection region */
+ ObjAdjustCpsForDeletion(docCur);
+
+ return TRUE;
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* handle any unfinished objects in selection region */
+ ObjAdjustCpsForDeletion(docCur);
+ return TRUE;
+ }
+}
+
+void ObjAdjustCps(int doc,typeCP cpLim, typeCP dcpAdj)
+/* for every picinfo after cpLim, adjust the cp value in its objinfo */
+{
+ LPLPOBJINFO lplpObjTmp;
+ typeCP cpMac = CpMacText(doc);
+
+ if (dcpAdj == cp0)
+ return;
+
+ if (doc != docCur)
+ return;
+
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if (((*lplpObjTmp)->objectType == NONE) &&
+ ((*lplpObjTmp)->cpWhere >= cpLim))
+ {
+ typeCP cpNew = (*lplpObjTmp)->cpWhere + dcpAdj;
+ if (cpNew > cpMac)
+ cpNew = cpMac;
+ else if (cpNew < cp0)
+ cpNew = cp0;
+ (*lplpObjTmp)->cpWhere = cpNew;
+ }
+ }
+}
+
+void ObjAdjustCpsForDeletion(int doc)
+/* for every picinfo in selCur, set cpWhere to selCur.cpFirst (presumably
+ selCur is about to be deleted) */
+{
+ LPLPOBJINFO lplpObjTmp;
+
+ if (selCur.cpFirst == selCur.cpLim)
+ return;
+
+ if (doc != docCur)
+ return;
+
+ for (lplpObjTmp = NULL; lplpObjTmp = EnumObjInfos(lplpObjTmp) ;)
+ {
+ if (((*lplpObjTmp)->objectType == NONE) &&
+ ((*lplpObjTmp)->cpWhere >= selCur.cpFirst) &&
+ ((*lplpObjTmp)->cpWhere <= selCur.cpLim))
+ (*lplpObjTmp)->cpWhere = selCur.cpFirst;
+ }
+}
+
+#include <stdlib.h>
+
+BOOL GimmeNewPicinfo(OBJPICINFO *pPicInfo, LPOBJINFO lpObjInfo)
+/* assume lpObjInfo already is filled out */
+/* return whether error */
+{
+ szOBJNAME szObjName;
+ char *pdumb;
+
+ if (lpObjInfo == NULL)
+ return TRUE;
+
+ bltbc( pPicInfo, 0, cchPICINFOX );
+
+ /* objinfo */
+ lpOBJ_QUERY_INFO(pPicInfo) = lpObjInfo;
+
+ /* so Save'll save */
+ fOBJ_QUERY_DIRTY_OBJECT(pPicInfo) = TRUE;
+
+ /* only save picinfo until File.Save */
+ bOBJ_QUERY_DONT_SAVE_DATA(pPicInfo) = TRUE;
+
+ ObjUpdateFromObjInfo(pPicInfo);
+
+ /* data size */
+ dwOBJ_QUERY_DATA_SIZE(pPicInfo) = 0xFFFFFFFF; // to indicate brand new object
+
+ pPicInfo->mx = mxMultByOne;
+ pPicInfo->my = myMultByOne;
+ pPicInfo->cbHeader = cchPICINFOX;
+ pPicInfo->dxaOffset = 0;
+ pPicInfo->mm = MM_OLE;
+ pPicInfo->dxaSize = nOBJ_BLANKOBJECT_X;
+ pPicInfo->dyaSize = nOBJ_BLANKOBJECT_Y;
+ return FALSE;
+}
+
+BOOL ObjInitServerInfo(LPOBJINFO lpObjInfo)
+/* this is called right after creating an object */
+/* return whether error */
+{
+ lpObjInfo->fCompleteAsync = TRUE; // kill prev async (OleCreate...)
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return TRUE;
+
+ /* make sure Create succeeded */
+ if (lpObjInfo->fDeleteMe)
+ /* this is how we know it failed asynchronously */
+ return TRUE;
+
+ if ((lpObjInfo->objectType == EMBEDDED) ||
+ (lpObjInfo->objectType == NONE))
+ {
+ if (ObjSetHostName(lpObjInfo,docCur))
+ return TRUE;
+
+ lpObjInfo->fCompleteAsync = TRUE; // kill SetHostName if Cancel
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return TRUE;
+ }
+
+ if (ObjSetTargetDeviceForObject(lpObjInfo))
+ return TRUE;
+
+ if (lpObjInfo->aName == NULL)
+ if (lpObjInfo->objectType == LINK)
+ {
+ lpObjInfo->fCompleteAsync = TRUE; // kill SetTarget if Cancel
+ if (ObjWaitForObject(lpObjInfo,TRUE))
+ return TRUE;
+ if ((lpObjInfo->aName = MakeLinkAtom(lpObjInfo)) == NULL)
+ return TRUE;
+ }
+
+ /* note: Caller needs to handle getting the size of object. */
+
+ return FALSE;
+}
diff --git a/private/mvdm/wow16/write/objmini.asm b/private/mvdm/wow16/write/objmini.asm
new file mode 100644
index 000000000..210364a78
--- /dev/null
+++ b/private/mvdm/wow16/write/objmini.asm
@@ -0,0 +1,64 @@
+ ;\
+ ; obj.asm
+ ;
+ ; Copyright (C) 1992, MicroSoft Corporation
+ ;
+ ; Contains pointer validation routine
+ ;
+ ; History: sriniK 02/01/1991 original
+ ; (8.20.91) v-dougk made into far proc
+ ;/
+
+.286p
+.MODEL MEDIUM
+.CODE
+
+;**************************** _CheckPointer ****************************
+;
+; WORD _CheckPointer (lp, access)
+;
+; Args:
+; lp pointer to be verified
+; access 0 test the pointer for read access
+; 1 test the pointer for write access
+; returns:
+; FALSE invalid pointer
+; TRUE valid pointer
+;
+;
+;
+ public _CheckPointer
+
+_CheckPointer proc
+
+ push bp
+ mov bp, sp
+
+ xor ax, ax ; assume an error
+ and word ptr [bp+0AH], -1
+ jnz check_write_access
+
+ verr word ptr [bp+8] ; check selector for read access
+ jnz error
+ jmp short check_offset
+
+check_write_access:
+ verw word ptr [bp+8] ; check selector for write access
+ jnz error
+
+check_offset:
+ lsl bx, word ptr [bp+8] ; segment limit gets copied into BX
+ jnz error
+ cmp [bp+6], bx
+ ja error
+ or ax, -1
+error:
+ pop bp
+ ret
+
+_CheckPointer endp
+
+
+ end
+
+ \ No newline at end of file
diff --git a/private/mvdm/wow16/write/objpsp.c b/private/mvdm/wow16/write/objpsp.c
new file mode 100644
index 000000000..011eccbc0
--- /dev/null
+++ b/private/mvdm/wow16/write/objpsp.c
@@ -0,0 +1,354 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#include "windows.h"
+#include "mw.h"
+#include "winddefs.h"
+#include "obj.h"
+#include "objreg.h"
+#include "str.h"
+
+static BOOL GetClipObjectInfo(LPSTR szClass, LPSTR szItem);
+BOOL QueryPasteFromClip(OLEOPT_RENDER lpRender, OLECLIPFORMAT lpFormat);
+BOOL QueryLinkFromClip(OLEOPT_RENDER lpRender, OLECLIPFORMAT lpFormat);
+static int FillListFormat(HWND hwndList, BOOL bObjAvail);
+static WORD GetFormatClip(int i);
+static BOOL IsFormatAvailable(WORD cfFormat);
+
+WORD cfObjPasteSpecial;
+BOOL vObjPasteLinkSpecial;
+WORD rgchFormats[5];
+int irgchFormats = 0;
+
+void fnObjPasteSpecial(void)
+{
+ if (OurDialogBox(hINSTANCE, "PasteSpecial", hMAINWINDOW, lpfnPasteSpecial))
+ fnPasteEdit();
+ cfObjPasteSpecial = 0; // clear it for next time
+ vbObjLinkOnly = vObjPasteLinkSpecial = FALSE;
+}
+
+int FAR PASCAL fnPasteSpecial(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
+{
+ extern HWND vhWndMsgBoxParent;
+ static BOOL bLinkAvail,bObjAvail;
+ extern BOOL ferror;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ char szClassName[KEYNAMESIZE];
+ char szItemName[CBPATHMAX];
+ int nWhichToSelect;
+
+ HWND hwndList = GetDlgItem(hDlg,IDD_LISTBOX);
+
+ szClassName[0] = szItemName[0] = '\0';
+ irgchFormats = 0; //always start with 0
+ vObjPasteLinkSpecial = vbObjLinkOnly = FALSE;
+
+ bObjAvail = OleQueryCreateFromClip(PROTOCOL, olerender_draw, 0) == OLE_OK;
+ bLinkAvail = OleQueryLinkFromClip(PROTOCOL, olerender_draw, 0) == OLE_OK;
+
+ if (bObjAvail || bLinkAvail)
+ {
+ GetClipObjectInfo(szClassName, szItemName);
+ SetWindowText(GetDlgItem(hDlg,IDD_CLIPOWNER), szClassName);
+ SetWindowText(GetDlgItem(hDlg,IDD_ITEM), szItemName);
+ }
+ else
+ ShowWindow(GetDlgItem(hDlg,IDD_SOURCE), SW_HIDE);
+
+ if (bObjAvail || bLinkAvail)
+ /* then there's an object on clipboard */
+ {
+ char szListItem[CBMESSAGEMAX]; // hope this is big enough!
+ char szTmp[CBMESSAGEMAX];
+
+ LoadString(hINSTANCE, IDSTRObject, szTmp, sizeof(szTmp));
+ wsprintf(szListItem,"%s %s",(LPSTR)szClassName,(LPSTR)szTmp);
+ SendMessage(hwndList, LB_INSERTSTRING, irgchFormats, (DWORD)(LPSTR)szListItem);
+ if (bObjAvail)
+ rgchFormats[irgchFormats++] = vcfOwnerLink;
+ else
+ rgchFormats[irgchFormats++] = vcfLink;
+ }
+
+ nWhichToSelect = FillListFormat(hwndList,bObjAvail || bLinkAvail);
+
+ /* select what Write would normally take */
+ SendMessage(hwndList, LB_SETCURSEL, nWhichToSelect, 0L);
+
+ EnableWindow(GetDlgItem(hDlg, IDD_PASTELINK), bLinkAvail &&
+ rgchFormats[nWhichToSelect] != CF_TEXT);
+
+ if (!bObjAvail && bLinkAvail)
+ /* then we've got the object format in the list box, but don't want to
+ enable paste if its selected */
+ EnableWindow(GetDlgItem(hDlg, IDD_PASTE), nWhichToSelect != 0);
+
+ return TRUE;
+ }
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ break;
+
+ case WM_SYSCOMMAND:
+ switch(wParam & 0xFFF0)
+ {
+ case SC_CLOSE:
+ OurEndDialog(hDlg, FALSE);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDD_LISTBOX:
+ switch (HIWORD(lParam))
+ {
+ case LBN_DBLCLK:
+ SendMessage(hDlg,WM_COMMAND,IDD_PASTE,0L);
+ return TRUE;
+ case LBN_SELCHANGE:
+ if (!bObjAvail && bLinkAvail)
+ /* then we've got the object format in the list box, but don't want to
+ enable paste if its selected */
+ EnableWindow(GetDlgItem(hDlg, IDD_PASTE),
+ SendMessage(LOWORD(lParam), LB_GETCURSEL, 0, 0L) != 0);
+
+ EnableWindow(GetDlgItem(hDlg, IDD_PASTELINK),
+ bLinkAvail &&
+ (GetFormatClip(SendMessage(LOWORD(lParam), LB_GETCURSEL, 0, 0L)) != CF_TEXT));
+ return TRUE;
+ }
+ break;
+
+
+ case IDD_PASTE:
+ case IDD_PASTELINK:
+ {
+ int i;
+
+ if (LB_ERR == (i = (WORD)SendMessage(GetDlgItem(hDlg, IDD_LISTBOX), LB_GETCURSEL, 0, 0L)))
+ break;
+
+ cfObjPasteSpecial = GetFormatClip(i);
+
+ if (!IsFormatAvailable(cfObjPasteSpecial))
+ /* somebody changed clip contents while in dialog */
+ {
+ Error(IDPMTFormat);
+ ferror=FALSE; // reenable error messages
+ SendMessage(GetDlgItem(hDlg,IDD_LISTBOX), LB_RESETCONTENT, 0, 0L);
+ SendMessage(hDlg, WM_INITDIALOG, 0, 0L);
+ break;
+ }
+
+
+ if (wParam == IDD_PASTELINK)
+ if (i > 0)
+ vObjPasteLinkSpecial = TRUE;
+ else
+ vbObjLinkOnly = TRUE;
+
+ OurEndDialog(hDlg, TRUE);
+ }
+ break;
+
+ case IDCANCEL:
+ OurEndDialog(hDlg, FALSE);
+ break;
+ }
+ break;
+
+ }
+ return FALSE;
+}
+
+static int FillListFormat(HWND hwndList, BOOL bObjAvail)
+ /* fill hwndList with all the formats available on clipboard */
+ /* return index of which format Write would normally take */
+{
+ WORD cfFormat = NULL;
+ int nDefFormat= -1;
+ char szFormat[cchMaxSz];
+ BOOL bFoundDefault = FALSE;
+
+ OpenClipboard(hDOCWINDOW);
+
+ /** priority order:
+ if (bObjAvail)
+ If text comes before native, then text is default.
+ else object is default
+ else no object available
+ if text is there it is the default,
+ else default is first come first server of bitmap, metafile or DIB
+ **/
+
+ while (cfFormat = EnumClipboardFormats(cfFormat))
+ switch(cfFormat)
+ {
+ case CF_BITMAP:
+ LoadString(hINSTANCE, IDSTRBitmap, szFormat, sizeof(szFormat));
+ SendMessage(hwndList, LB_INSERTSTRING, irgchFormats, (DWORD)(LPSTR)szFormat);
+
+ if (!bObjAvail)
+ if (!bFoundDefault)
+ {
+ nDefFormat = irgchFormats;
+ bFoundDefault = TRUE;
+ }
+
+ rgchFormats[irgchFormats++] = cfFormat;
+ break;
+
+ case CF_METAFILEPICT:
+ LoadString(hINSTANCE, IDSTRPicture, szFormat, sizeof(szFormat));
+ SendMessage(hwndList, LB_INSERTSTRING, irgchFormats, (DWORD)(LPSTR)szFormat);
+
+ if (!bObjAvail)
+ if (!bFoundDefault)
+ {
+ nDefFormat = irgchFormats;
+ bFoundDefault = TRUE;
+ }
+
+ rgchFormats[irgchFormats++] = cfFormat;
+ break;
+
+ case CF_DIB:
+ LoadString(hINSTANCE, IDSTRDIB, szFormat, sizeof(szFormat));
+ SendMessage(hwndList, LB_INSERTSTRING, irgchFormats, (DWORD)(LPSTR)szFormat);
+
+ if (!bObjAvail)
+ if (!bFoundDefault)
+ {
+ nDefFormat = irgchFormats;
+ bFoundDefault = TRUE;
+ }
+
+ rgchFormats[irgchFormats++] = cfFormat;
+ break;
+
+ case CF_TEXT:
+ LoadString(hINSTANCE, IDSTRText, szFormat, sizeof(szFormat));
+ SendMessage(hwndList, LB_INSERTSTRING, irgchFormats, (DWORD)(LPSTR)szFormat);
+ if (bObjAvail)
+ {
+ if (!bFoundDefault)
+ /* then found text before native */
+ nDefFormat = irgchFormats;
+ }
+ else
+ nDefFormat = irgchFormats;
+
+ rgchFormats[irgchFormats++] = cfFormat;
+ bFoundDefault = TRUE;
+
+ break;
+
+ default:
+ if (!bFoundDefault && (cfFormat == vcfNative))
+ {
+ bFoundDefault = TRUE;
+ nDefFormat = 0;
+ }
+ break;
+ } //end switch
+
+ CloseClipboard();
+ if (nDefFormat == -1)
+ nDefFormat = 0;
+ return nDefFormat;
+}
+
+static WORD GetFormatClip(int i)
+{
+ return rgchFormats[i];
+}
+
+
+static BOOL GetClipObjectInfo(LPSTR szClass, LPSTR szItem)
+/* get the classname, item name for the owner of the clipboard */
+/* return TRUE if error */
+/* only gets ownerlink class, assumes its available */
+{
+ HANDLE hData=NULL;
+ LPSTR lpData=NULL;
+ BOOL bRetval = TRUE;
+ char szFullItem[CBPATHMAX],*pch;
+
+ OpenClipboard( hDOCWINDOW );
+
+ if ((hData = GetClipboardData(vcfOwnerLink)) == NULL)
+ if ((hData = GetClipboardData(vcfLink)) == NULL)
+ {
+ bRetval = TRUE;
+ goto end;
+ }
+
+ if ((lpData = GlobalLock(hData)) == NULL)
+ goto end;
+
+ /**** get szClass ****/
+ RegGetClassId(szClass,lpData);
+
+ /**** get szName ****/
+ while(*lpData++); // skip class key
+
+ pch = szFullItem;
+
+ /* first doc name */
+ do
+ *pch++ = *lpData;
+ while(*lpData++);
+
+ /* second item name (if there) */
+ if (*lpData)
+ {
+ *(pch-1) = ' ';
+ do
+ *pch++ = *lpData;
+ while(*lpData++);
+ }
+
+ /* get rid of path. pch now points to \0 */
+ --pch;
+ while (pch != szFullItem)
+ if ((*(pch-1) == '\\') || (*(pch-1) == ':'))
+ break;
+ else
+ --pch;
+
+ lstrcpy(szItem,(LPSTR)pch);
+
+ bRetval = FALSE;
+
+ end:
+ if (lpData)
+ GlobalUnlock(hData);
+
+ CloseClipboard();
+
+ return bRetval;
+}
+
+static BOOL IsFormatAvailable(WORD cfFormat)
+{
+ BOOL bRetval;
+
+ OpenClipboard(hDOCWINDOW);
+
+ bRetval = IsClipboardFormatAvailable(cfFormat);
+
+ CloseClipboard();
+
+ return bRetval;
+}
+
diff --git a/private/mvdm/wow16/write/objreg.c b/private/mvdm/wow16/write/objreg.c
new file mode 100644
index 000000000..5d57f2c95
--- /dev/null
+++ b/private/mvdm/wow16/write/objreg.c
@@ -0,0 +1,447 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+/* register.c - Handles the Win 3.1 registration library.
+ *
+ * Created by Microsoft Corporation.
+ */
+
+#define LSTRING // for lstrcat etc
+#include <windows.h>
+#include <shellapi.h>
+#include "objreg.h"
+#include "mw.h"
+#include "winddefs.h"
+#include "obj.h"
+#include "str.h" /* Needed for string resource id */
+#include "menudefs.h"
+#include "cmddefs.h"
+
+char szClassName[CBPATHMAX];
+
+HKEY hkeyRoot = NULL;
+
+void NEAR PASCAL MakeMenuString(char *szCtrl, char *szMenuStr, char *szVerb, char *szClass, char *szObject);
+
+/* RegInit() - Prepare the registration database for calls.
+ */
+void FAR RegInit(HANDLE hInst)
+{
+ /* this seems to speed up registration operations immensely, but serves
+ no other purpose */
+ //RegOpenKey(HKEY_CLASSES_ROOT,NULL,&hkeyRoot);
+}
+
+/* RegTerm() - Clean up and terminate the registration library.
+ */
+void FAR RegTerm(void)
+{
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+}
+
+/* RegGetClassId() - Retrieves the string name of a class.
+ *
+ * Note: Classes are guaranteed to be in ASCII, but should
+ * not be used directly as a rule because they might
+ * be meaningless if running non-English Windows.
+ */
+void FAR RegGetClassId(LPSTR lpstrName, LPSTR lpstrClass) {
+ DWORD dwSize = KEYNAMESIZE;
+
+ if (RegQueryValue(HKEY_CLASSES_ROOT, lpstrClass, (LPSTR)lpstrName, &dwSize))
+ lstrcpy(lpstrName, lpstrClass);
+}
+
+/* RegMakeFilterSpec() - Retrieves class-associated default extensions.
+ *
+ * This function returns a filter spec, to be used in the "Change Link"
+ * standard dialog box, which contains all the default extensions which
+ * are associated with the given class name. Again, the class names are
+ * guaranteed to be in ASCII.
+ *
+ * Returns: The index nFilterIndex stating which filter item matches the
+ * extension, or 0 if none is found or -1 if error.
+ ** *hFilterSpec is allocated and must be freed by caller.
+ */
+int FAR RegMakeFilterSpec(LPSTR lpstrClass, LPSTR lpstrExt, HANDLE *hFilterSpec)
+{
+ DWORD dwSize;
+ LPSTR lpstrFilterSpec;
+ char szClass[KEYNAMESIZE];
+ char szName[KEYNAMESIZE];
+ char szString[KEYNAMESIZE];
+ unsigned int i;
+ int idWhich = 0;
+ int idFilterIndex = 0;
+
+ if (*hFilterSpec == NULL)
+ {
+ if ((*hFilterSpec = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,KEYNAMESIZE+16)) == NULL)
+ return -1;
+ lpstrFilterSpec = MAKELP(*hFilterSpec,0);
+ }
+
+ RegOpenKey(HKEY_CLASSES_ROOT,NULL,&hkeyRoot);
+ for (i = 0; !RegEnumKey(HKEY_CLASSES_ROOT, i++, szName, KEYNAMESIZE); )
+ {
+ if (*szName == '.' /* Default Extension... */
+
+ /* ... so, get the class name */
+ && (dwSize = KEYNAMESIZE)
+ && !RegQueryValue(HKEY_CLASSES_ROOT, szName, szClass, &dwSize)
+
+ /* ... and if the class name matches (null class is wildcard) */
+ && (!lpstrClass || !lstrcmpi(lpstrClass, szClass))
+
+ /* ... get the class name string */
+ && (dwSize = KEYNAMESIZE)
+ && !RegQueryValue(HKEY_CLASSES_ROOT, szClass, szString, &dwSize))
+ {
+ int offset;
+
+ idWhich++;
+
+ /* If the extension matches, save the filter index */
+ if (lpstrExt && !lstrcmpi(lpstrExt, szName))
+ idFilterIndex = idWhich;
+
+ offset = lpstrFilterSpec - MAKELP(*hFilterSpec,0);
+
+ if ((GlobalSize(*hFilterSpec) - offset) <
+ (lstrlen(szString) + 16))
+ {
+ if ((*hFilterSpec = GlobalReAlloc(*hFilterSpec,GlobalSize(*hFilterSpec)+KEYNAMESIZE+16,
+ GMEM_MOVEABLE|GMEM_ZEROINIT)) == NULL)
+ {
+ GlobalFree(*hFilterSpec);
+ *hFilterSpec = NULL;
+ idFilterIndex = -1;
+ break;
+ }
+ lpstrFilterSpec = (LPSTR)MAKELP(*hFilterSpec,0) + offset;
+ }
+
+ /* Copy over "<Class Name String> (*<Default Extension>)"
+ * e.g. "Server Picture (*.PIC)"
+ */
+ lstrcpy(lpstrFilterSpec, szString);
+ lstrcat(lpstrFilterSpec, " (*");
+ lstrcat(lpstrFilterSpec, szName);
+ lstrcat(lpstrFilterSpec, ")");
+ lpstrFilterSpec += lstrlen(lpstrFilterSpec) + 1;
+
+ /* Copy over "*<Default Extension>" (e.g. "*.PIC") */
+ lstrcpy(lpstrFilterSpec, "*");
+ lstrcat(lpstrFilterSpec, szName);
+ lpstrFilterSpec += lstrlen(lpstrFilterSpec) + 1;
+ }
+ }
+
+ /* Add another NULL at the end of the spec (+ 16 accounts for this) */
+ if (idFilterIndex > -1)
+ *lpstrFilterSpec = 0;
+
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+
+ return idFilterIndex;
+}
+
+/* RegCopyClassName() - Returns the ASCII class id from the listbox.
+ */
+BOOL FAR RegCopyClassName(HWND hwndList, LPSTR lpstrClassName) {
+ BOOL fSuccess = FALSE;
+ DWORD dwSize = 0L;
+ HKEY hkeyTemp;
+ char szClass[KEYNAMESIZE];
+ char szExec[KEYNAMESIZE];
+ char szKey[KEYNAMESIZE];
+ char szName[KEYNAMESIZE];
+ int i;
+ int iWhich;
+
+ iWhich = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0L);
+ SendMessage(hwndList, LB_GETTEXT, iWhich, (DWORD)(LPSTR)szKey);
+
+ RegOpenKey(HKEY_CLASSES_ROOT,NULL,&hkeyRoot);
+ for (i = 0; !fSuccess && !RegEnumKey(HKEY_CLASSES_ROOT, i++, szClass, KEYNAMESIZE); )
+ if (*szClass != '.') { /* Not default extension... */
+
+ /* See if this class really refers to a server */
+ dwSize = 0;
+ hkeyTemp = NULL;
+ lstrcpy(szExec, szClass);
+ lstrcat(szExec, "\\protocol\\StdFileEditing\\server");
+
+ if (!RegOpenKey(HKEY_CLASSES_ROOT, szExec, &hkeyTemp)) {
+ /* ... get the class name string */
+ dwSize = KEYNAMESIZE;
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, szClass, szName, &dwSize)
+ && !lstrcmp(szName, szKey))
+ fSuccess = TRUE;
+
+ RegCloseKey(hkeyTemp);
+ }
+ }
+
+ if (fSuccess)
+ lstrcpy(lpstrClassName, szClass);
+
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+
+ return fSuccess;
+}
+
+/* RegGetClassNames() - Fills the list box with possible server names.
+ */
+BOOL FAR RegGetClassNames(HWND hwndList) {
+ BOOL fSuccess = FALSE;
+ DWORD dwSize = 0L;
+ HKEY hkeyTemp;
+ char szClass[KEYNAMESIZE];
+ char szExec[KEYNAMESIZE];
+ char szName[KEYNAMESIZE];
+ int i;
+
+ SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
+
+ RegOpenKey(HKEY_CLASSES_ROOT,NULL,&hkeyRoot);
+ for (i = 0; !RegEnumKey(HKEY_CLASSES_ROOT, i++, szClass, KEYNAMESIZE); )
+ if (*szClass != '.') { /* Not default extension... */
+
+ /* See if this class really refers to a server */
+ dwSize = 0;
+ hkeyTemp = NULL;
+ lstrcpy(szExec, szClass);
+ lstrcat(szExec, "\\protocol\\StdFileEditing\\server");
+
+ if (!RegOpenKey(HKEY_CLASSES_ROOT, szExec, &hkeyTemp)) {
+ /* ... get the class name string */
+ dwSize = KEYNAMESIZE;
+ if (!RegQueryValue(HKEY_CLASSES_ROOT, szClass, szName, &dwSize)) {
+ SendMessage(hwndList, LB_ADDSTRING, 0, (DWORD)(LPSTR)szName);
+ fSuccess = TRUE;
+ }
+ RegCloseKey(hkeyTemp);
+ }
+ }
+
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+ return fSuccess;
+}
+
+
+void ObjUpdateMenuVerbs( HMENU hMenu )
+{
+ int cObjects;
+ extern struct SEL selCur;
+ extern char szOPropMenuStr[];
+ extern char szPPropMenuStr[];
+ extern BOOL vfOutOfMemory;
+ char szBuffer[cchMaxSz];
+ char szWordOrder2[10], szWordOrder3[10];
+
+ if (vfOutOfMemory)
+ {
+ EnableMenuItem(hMenu, EDITMENUPOS, MF_GRAYED|MF_BYPOSITION);
+ return;
+ }
+
+ LoadString(hINSTANCE, IDSTRPopupVerbs, szWordOrder2, sizeof(szWordOrder2));
+ LoadString(hINSTANCE, IDSTRSingleVerb, szWordOrder3, sizeof(szWordOrder3));
+
+ DeleteMenu(hMenu, EDITMENUPOS, MF_BYPOSITION);
+
+/** Cases:
+ 0) 0 objects selected
+ 1) 1 object selected
+ a) object supports 0 verbs "Edit <Object Class> Object"
+ b) object supports more than 1 verb "<Object Class> Object" => verbs
+ 2) more than 1 object selected "Objects"
+
+ Use the VerbMenu strings to determine the order in which these words
+ should appear in the menu string (for localization).
+**/
+
+ /* how many objects are selected? */
+ cObjects = ObjSetSelectionType(docCur,selCur.cpFirst, selCur.cpLim);
+
+ /* must be only an object, not text in selection */
+ if (cObjects == 1)
+ {
+ ObjCachePara(docCur,selCur.cpFirst);
+ if (!ObjQueryCpIsObject(docCur,selCur.cpFirst))
+ cObjects = 0;
+ }
+
+ if ((cObjects == -1) // error
+ || (cObjects == 0)
+ || (cObjects > 1))
+ {
+ wsprintf(szBuffer, "%s", (LPSTR)((cObjects > 1) ? szPPropMenuStr : szOPropMenuStr));
+ InsertMenu(hMenu, EDITMENUPOS, MF_BYPOSITION,imiVerb,szBuffer);
+
+ /*
+ Spec says if > 1 then optionally should enable if all servers
+ are of the same class. I'm opting not to implement. (9.27.91) v-dougk
+ */
+ EnableMenuItem(hMenu, EDITMENUPOS, MF_GRAYED | MF_BYPOSITION);
+
+#if 0
+ else // > 1
+ {
+ EnableMenuItem(hMenu, EDITMENUPOS,
+ (((OBJ_SELECTIONTYPE == EMBEDDED) || (OBJ_SELECTIONTYPE == LINK))
+ ? MF_ENABLED : MF_GRAYED) | MF_BYPOSITION);
+ }
+#endif
+ return;
+ }
+ else // 1 object selected
+ {
+ OBJPICINFO picInfo;
+
+ /** CASES:
+ object supports 0 verbs "Edit <Object Class> Object"
+ object supports more than 1 verb "<Object Class> Object" => verbs
+ **/
+
+ RegOpenKey(HKEY_CLASSES_ROOT,NULL,&hkeyRoot);
+
+ GetPicInfo(selCur.cpFirst,selCur.cpFirst + cchPICINFOX, docCur, &picInfo);
+
+ if ((otOBJ_QUERY_TYPE(&picInfo) == EMBEDDED) ||
+ (otOBJ_QUERY_TYPE(&picInfo) == LINK))
+ {
+ HANDLE hData=NULL;
+ LPSTR lpstrData;
+ OLESTATUS olestat;
+
+ olestat = OleGetData(lpOBJ_QUERY_OBJECT(&picInfo),
+ otOBJ_QUERY_TYPE(&picInfo) == LINK? vcfLink: vcfOwnerLink,
+ &hData);
+
+ if ((olestat == OLE_WARN_DELETE_DATA) || (olestat == OLE_OK))
+ {
+ HKEY hKeyVerb;
+ DWORD dwSize = KEYNAMESIZE;
+ char szClass[KEYNAMESIZE];
+ char szVerb[KEYNAMESIZE];
+ HANDLE hPopupNew=NULL;
+
+ lpstrData = MAKELP(hData,0);
+
+ /* Both link formats are: "szClass0szDocument0szItem00" */
+
+ /* get real language class of object in szClass for menu */
+ if (RegQueryValue(HKEY_CLASSES_ROOT, lpstrData, szClass, &dwSize))
+ lstrcpy(szClass, lpstrData); /* if above call failed */
+
+ if (olestat == OLE_WARN_DELETE_DATA)
+ GlobalFree(hData);
+
+ /* append class key */
+ for (vcVerbs=0; ;++vcVerbs)
+ {
+ dwSize = KEYNAMESIZE;
+ wsprintf(szBuffer, "%s\\protocol\\StdFileEditing\\verb\\%d", (LPSTR)lpstrData,vcVerbs);
+ if (RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szVerb, &dwSize))
+ break;
+
+ if (hPopupNew == NULL)
+ hPopupNew = CreatePopupMenu();
+
+ InsertMenu(hPopupNew, -1, MF_BYPOSITION, imiVerb+vcVerbs+1, szVerb);
+ }
+
+ if (vcVerbs == 0)
+ {
+ LoadString(hINSTANCE, IDSTREdit, szVerb, sizeof(szVerb));
+ MakeMenuString(szWordOrder3, szBuffer, szVerb, szClass, szOPropMenuStr);
+ InsertMenu(hMenu, EDITMENUPOS, MF_BYPOSITION, imiVerbPlay, szBuffer);
+ }
+ else if (vcVerbs == 1)
+ {
+ MakeMenuString(szWordOrder3, szBuffer, szVerb, szClass, szOPropMenuStr);
+ InsertMenu(hMenu, EDITMENUPOS, MF_BYPOSITION, imiVerbPlay, szBuffer);
+ DestroyMenu(hPopupNew);
+ }
+ else // > 1 verbs
+ {
+ MakeMenuString(szWordOrder2, szBuffer, NULL, szClass, szOPropMenuStr);
+ InsertMenu(hMenu, EDITMENUPOS, MF_BYPOSITION | MF_POPUP,
+ hPopupNew, szBuffer);
+ }
+ EnableMenuItem(hMenu, EDITMENUPOS, MF_ENABLED|MF_BYPOSITION);
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+ return;
+ }
+ else
+ ObjError(olestat);
+ }
+ }
+
+ /* error if got to here */
+ wsprintf(szBuffer, "%s", (LPSTR)szOPropMenuStr);
+ InsertMenu(hMenu, EDITMENUPOS, MF_BYPOSITION,NULL,szBuffer);
+ EnableMenuItem(hMenu, EDITMENUPOS, MF_GRAYED|MF_BYPOSITION);
+ if (hkeyRoot)
+ {
+ RegCloseKey(hkeyRoot);
+ hkeyRoot = NULL;
+ }
+}
+
+void NEAR PASCAL MakeMenuString(char *szCtrl, char *szMenuStr, char *szVerb, char *szClass, char *szObject)
+{
+ char *pStr;
+ register char c;
+
+ while (c = *szCtrl++)
+ {
+ switch(c)
+ {
+ case 'c': // class
+ case 'C': // class
+ pStr = szClass;
+ break;
+ case 'v': // class
+ case 'V': // class
+ pStr = szVerb;
+ break;
+ case 'o': // object
+ case 'O': // object
+ pStr = szObject;
+ break;
+ default:
+ *szMenuStr++ = c;
+ *szMenuStr = '\0'; // just in case
+ continue;
+ }
+
+ if (pStr) // should always be true
+ {
+ lstrcpy(szMenuStr,pStr);
+ szMenuStr += lstrlen(pStr); // point to '\0'
+ }
+ }
+}
diff --git a/private/mvdm/wow16/write/objreg.h b/private/mvdm/wow16/write/objreg.h
new file mode 100644
index 000000000..c76898878
--- /dev/null
+++ b/private/mvdm/wow16/write/objreg.h
@@ -0,0 +1,26 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+/* olereg.h - Contains the header for registration database related calls.
+ *
+ * Created by Microsoft Corporation.
+ */
+/* Constants */
+#define CBPATHMAX 250
+#define KEYNAMESIZE 300 /* Maximum registration key length */
+#define CLASSES ((LPSTR)".classes") /* Classes root key */
+#define CFILTERMAX 20 /* Max # filters */
+#define CFILTERLEN 30 /* Max length of one filters */
+#define CBFILTERMAX (CFILTERLEN * CFILTERMAX) /* Max # chars/filter */
+#define CBMESSAGEMAX 80
+
+/* Function prototypes */
+BOOL FAR RegCopyClassName(HWND hwndList, LPSTR lpstrClassName);
+void FAR RegGetClassId(LPSTR lpstrName, LPSTR lpstrClass);
+BOOL FAR RegGetClassNames(HWND hwndList);
+void FAR RegInit(HANDLE hInst);
+int FAR RegMakeFilterSpec(LPSTR lpstrClass, LPSTR lpstrExt, HANDLE *hFilterSpec);
+void FAR RegTerm(void);
+
+extern char szClassName[CBPATHMAX];
+
diff --git a/private/mvdm/wow16/write/open.c b/private/mvdm/wow16/write/open.c
new file mode 100644
index 000000000..85b8c171f
--- /dev/null
+++ b/private/mvdm/wow16/write/open.c
@@ -0,0 +1,606 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Open.c -- WRITE document opening */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+//#define NOATOM
+#define NOBITMAP
+#define NOPEN
+#define NODRAWTEXT
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOHDC
+#define NOMETAFILE
+#define NOMSG
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOWH
+#define NOWINOFFSETS
+#define NOSOUND
+#define NOCOMM
+#define NORESOURCE
+#include <windows.h>
+#include "mw.h"
+#include "doslib.h"
+#include "dispdefs.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "fontdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#define NOSTRUNDO
+#define NOSTRMERGE
+#include "str.h"
+#include "code.h"
+#include "prmdefs.h"
+#include "obj.h"
+#define PAGEONLY
+#include "printdef.h" /* printdefs.h */
+/*
+#include "dlgdefs.h"
+*/
+
+ /* These defines replace dlgdefs.h to combat compiler heap overflows */
+#define idiYes IDOK
+#define idiNo 3
+#define idiCancel IDCANCEL
+
+ /* These defines replace heapdefs.h and heapdata.h for the same
+ irritating reason */
+#define cwSaveAlloc (128)
+#define cwHeapMinPerWindow (50)
+#define cwHeapSpaceMin (60)
+
+/* E X T E R N A L S */
+
+extern CHAR (**vhrgbSave)[];
+extern HANDLE hParentWw;
+extern HANDLE hMmwModInstance;
+extern struct WWD rgwwd[];
+extern int wwMac;
+extern struct FCB (**hpfnfcb)[];
+extern struct DOD (**hpdocdod)[];
+extern int docMac;
+extern struct WWD *pwwdCur;
+extern int fnMac;
+extern CHAR stBuf[];
+#if WINVER >= 0x300
+extern BOOL fError;
+#endif
+
+
+short WCompSzC();
+CHAR (**HszCreate())[];
+struct FNTB **HfntbCreate();
+#ifdef CASHMERE
+struct SETB **HsetbCreate();
+#else
+struct SEP **HsepCreate();
+#endif
+struct PGTB **HpgtbCreate();
+
+
+CHAR *PchFromFc( int, typeFC, int * );
+CHAR *PchGetPn( int, typePN, int *, int );
+typeFC FcMacFromUnformattedFn( int );
+int CchReadAtPage( int, typePN, CHAR *, int, int );
+
+
+
+
+
+struct TBD (**HgtbdCreate(fn))[]
+int fn;
+{ /* Create a MEMO tab table by reading the properties of the first
+ para of the passed fn and returning a handle. The handle returned will
+ be 0 if the tab table is not present or null */
+struct TBD (**hgtbd)[] = 0;
+struct PAP pap;
+
+Assert( (fn != fnNil) && (**hpfnfcb)[fn].fFormatted );
+
+bltc((int *)&pap, 0, cwPAP); /* else we will have garbage tabs */
+FcParaLim( fn, (typeFC)cfcPage, (**hpfnfcb)[fn].fcMac, &pap );
+if (pap.rgtbd[0].dxa && !FNoHeap( hgtbd = (struct TBD (**)[])HAllocate( cwTBD *
+ itbdMax )))
+ {
+ register struct TBD *ptbd = &pap.rgtbd[0];
+ pap.rgtbd[itbdMax - 1].dxa = 0; /* just in case a WORD document has more
+ than 12 tabs */
+
+/* overwrite tabs and leading tab char that WRITE does not support */
+ for ( ; ptbd->dxa != 0; ptbd++)
+ {
+ ptbd->tlc = tlcWhite;
+ ptbd->opcode = 0;
+ ptbd->chAlign = 0;
+ if (ptbd->jc == jcCenter)
+ ptbd->jc = jcLeft;
+ else if (ptbd->jc == jcRight)
+ ptbd->jc = jcBoth;
+ }
+ blt( &pap.rgtbd[0], *hgtbd, cwTBD * itbdMax );
+ }
+return hgtbd;
+}
+
+
+
+struct SEP **HsepCreate(fn)
+int fn;
+{ /* Given an fn for a formatted file, return a handle to an SEP
+ giving section properties for the file. Returns NULL if
+ standard properties should be used. If the file has a section
+ table, the properties from the first section in the table are used */
+extern struct SEP vsepNormal;
+
+
+struct SETB *psetbFile;
+typePN pn;
+struct SEP **hsep;
+struct SED *psed;
+CHAR *pchFprop;
+int cch;
+
+Assert(fn != fnNil && (**hpfnfcb)[fn].fFormatted);
+
+if ((pn = (**hpfnfcb)[fn].pnSetb) == (**hpfnfcb)[fn].pnBftb)
+ return (struct SEP **) 0;
+psetbFile = (struct SETB *) PchGetPn(fn, pn, &cch, false);
+if (psetbFile->csed == 0)
+ return (struct SEP **)0;
+
+ /* File has a section table; copy properties from first SEP */
+hsep = (struct SEP **) HAllocate( cwSEP );
+if (FNoHeap( hsep ))
+ return (struct SEP **) hOverflow;
+blt( &vsepNormal, *hsep, cwSEP );
+psed = &psetbFile->rgsed [0];
+if (psed->fc == fcNil)
+ return (struct SEP **)0;
+pchFprop = PchFromFc( fn, psed->fc, &cch );
+if (*pchFprop != 0)
+ {
+ struct SEP *psep = *hsep;
+
+ bltbyte( pchFprop+1, psep, *pchFprop );
+
+#ifndef FIXED_PAGE
+ /* Some of the section properties must be adjusted to the current page size
+ (stored in vsepNormal). */
+ if (psep->xaMac != vsepNormal.xaMac)
+ {
+ int dxa = vsepNormal.xaMac - psep->xaMac;
+
+ psep->xaMac += dxa;
+ psep->dxaText = max(psep->dxaText + dxa, dxaMinUseful);
+ psep->xaPgn += dxa;
+ }
+ if (psep->yaMac != vsepNormal.yaMac)
+ {
+ int dya = vsepNormal.yaMac - psep->yaMac;
+
+ psep->yaMac += dya;
+ psep->dyaText = max(psep->dyaText + dya, dyaMinUseful);
+ psep->yaRH2 += dya;
+ }
+#endif /* not FIXED_PAGE */
+
+ }
+return hsep;
+} /* end of H s e p C r e a t e */
+
+
+
+
+struct PGTB **HpgtbCreate(fn)
+int fn;
+{ /* Create a page table from a formatted file */
+struct PGTB *ppgtbFile;
+typePN pn;
+int cchT;
+int cpgd;
+struct PGTB **hpgtb;
+int *pwPgtb;
+int cw;
+
+Assert(fn != fnNil && (**hpfnfcb)[fn].fFormatted);
+
+if ((pn = (**hpfnfcb)[fn].pnBftb) == (**hpfnfcb)[fn].pnFfntb)
+ return (struct PGTB **)0;
+ppgtbFile = (struct PGTB *) PchGetPn(fn, pn, &cchT, false);
+if ((cpgd = ppgtbFile->cpgd) == 0)
+ return (struct PGTB **)0;
+
+hpgtb = (struct PGTB **) HAllocate(cw = cwPgtbBase + cpgd * cwPGD);
+if (FNoHeap(hpgtb))
+ return (struct PGTB **)hOverflow;
+
+pwPgtb = (int *) *hpgtb;
+
+blt(ppgtbFile, pwPgtb, min(cwSector, cw));
+
+while ((cw -= cwSector) > 0)
+ { /* Copy the pgd's to heap */
+ blt(PchGetPn(fn, ++pn, &cchT, false), pwPgtb += cwSector,
+ min(cwSector, cw));
+ }
+
+(*hpgtb)->cpgdMax = cpgd;
+return hpgtb;
+} /* end of H p g t b C r e a t e */
+
+
+
+
+int FnFromSz( sz ) /* filename is expected as ANSI */
+CHAR *sz;
+{
+int fn;
+struct FCB *pfcb;
+
+if (sz[0] == 0)
+ return fnNil;
+
+/* Mod for Sand: Only return fn if it is on the "current" volume (disk) */
+for (fn = 0; fn < fnMac; fn++)
+ if ((pfcb = &(**hpfnfcb)[fn])->rfn != rfnFree && (WCompSzC((PCH)sz, (PCH)**pfcb->hszFile) == 0)
+#ifdef SAND
+ && (pfcb->vref == vrefFile)
+#endif /* SAND */
+ )
+ return fn;
+return fnNil;
+} /* end of F n F r o m S z */
+
+
+
+
+int FnOpenSz( szT, dty, fSearchPath ) /* filename is expected as ANSI */
+CHAR *szT;
+int dty;
+int fSearchPath;
+{ /* Open an existing file. Returns fnNil if not found */
+int fn;
+struct FIB fib;
+
+struct FCB *pfcb;
+CHAR (**hsz)[];
+
+CHAR sz[cchMaxFile];
+
+bltsz( szT, sz );
+sz[cchMaxFile - 1] = 0;
+
+#ifdef DFILE
+CommSzSz("FnOpenSz: sz presumed ANSI = ",sz);
+#endif
+
+if (sz[0]=='\0')
+ return fnNil;
+
+if ((fn = FnFromSz(sz)) != fnNil)
+ { /* File is already open -- re-open it, in case it was changed by
+ another app */
+ FreeFn( fn );
+ }
+
+if ((fn = FnAlloc()) == fnNil)
+ return fnNil;
+
+if (FNoHeap((hsz = HszCreate((PCH)sz))))
+ return fnNil;
+
+pfcb = &(**hpfnfcb)[fn];
+Assert( !pfcb->fSearchPath );
+if (fSearchPath)
+ pfcb->fSearchPath = TRUE;
+pfcb->mdFile = mdBinary; /* Try R/W first, will be smashed to RO if needed */
+pfcb->dty = pfcb->mdExt = (dty == dtyNormNoExt) ? dtyNormal : dty;
+pfcb->hszFile = hsz;
+
+{
+OFSTRUCT of;
+SetErrorMode(1);
+if (OpenFile(sz, (LPOFSTRUCT) &of, OF_EXIST) == -1)
+/* this is much cleaner than FAccessFn() for check existance */
+{
+ char szMsg[cchMaxSz];
+ extern int vfInitializing;
+ int fT = vfInitializing;
+
+ vfInitializing = FALSE; /* Report this err, even during inz */
+ MergeStrings ((of.nErrCode == dosxSharing) ? IDPMTCantShare:IDPMTCantOpen, sz, szMsg);
+ IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw, szMsg, MB_OK|MB_ICONEXCLAMATION);
+ vfInitializing = fT;
+ FreeH( (**hpfnfcb) [fn].hszFile);
+ return fnNil;
+}
+}
+
+/* dtyNormNoExt is directed at this call */
+if (!FAccessFn( fn, dty )) /* HM if error */
+ {
+ FreeH( (**hpfnfcb) [fn].hszFile);
+ return fnNil;
+ }
+
+/* stupid kludge management (6.21.91) v-dougk */
+dty = (dty == dtyNormNoExt) ? dtyNormal : dty;
+
+Assert( (sizeof (struct FIB) == cfcPage) && (cfcPage == cbSector) );
+Assert( pfcb == &(**hpfnfcb) [fn] ); /* No HM if FAccessFn succeeds */
+
+if ( (CchReadAtPage( fn, (typePN) 0,
+ (CHAR *) &fib, cbSector, TRUE ) != cbSector) ||
+ (fib.wTool != wMagicTool) )
+
+ { /* Not a formatted file */
+ typeFC fcMac = fc0;
+ int cfc;
+
+ if (dty != dtyNormal)
+ {
+ char szMsg[cchMaxSz];
+ PchFillPchId( szMsg, IDPMTBadFile, sizeof(szMsg) );
+ if (MessageBox(hPARENTWINDOW, (LPSTR)szMsg,
+ (LPSTR)szAppName, MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON2) == IDNO)
+ goto ErrRet;
+ }
+ pfcb->fFormatted = false;
+
+ /* Obtain file size by seeking to end-of-file */
+ if ((pfcb->fcMac = fcMac = FcMacFromUnformattedFn( fn )) == (typeFC) -1)
+ /* Serious error while seeking to file's end */
+ goto ErrRet;
+ pfcb->pnMac = (fcMac + cfcPage - 1) / cfcPage;
+ }
+else
+ { /* File is formatted; use stored fcMac, create run table */
+
+ if ((((fib.wIdent != wMagic) && (fib.wIdent != wOleMagic)) ||
+ (fib.dty != dty)) ||
+ // some bigwig media guy sent us a Write file whose fcMac was
+ // trashed (all else was OK). We gotta try to detect this obsure
+ // potentiality.
+ (fib.fcMac >= (typeFC)fib.pnPara*128 ) ||
+ (fib.fcMac > FcMacFromUnformattedFn( fn ))
+ )
+ { /* Wrong type of file or corrupted file */
+ char szMsg[cchMaxSz];
+ PchFillPchId( szMsg, IDPMTBadFile, sizeof(szMsg) );
+ if (MessageBox(hPARENTWINDOW, (LPSTR)szMsg,
+ (LPSTR)szAppName, MB_ICONEXCLAMATION|MB_YESNO|MB_DEFBUTTON2) == IDNO)
+ goto ErrRet;
+ }
+
+ if ((fib.wIdent == wOleMagic) && !fOleEnabled)
+ Error(IDPMTFileContainsObjects);
+
+ if (fib.pnMac == (typePN)0)
+ /* KLUDGE to load word files, which don't have ffntb entries. */
+ fib.pnMac = fib.pnFfntb;
+
+ pfcb->fFormatted = true;
+ pfcb->fcMac = fib.fcMac;
+#ifdef p2bSector
+ pfcb->pnChar = (fib.fcMac + cfcPage - 1) / cfcPage;
+#else
+ pfcb->pnChar = (fib.fcMac + cfcPage - 1) / cfcPage;
+#endif
+ pfcb->pnPara = fib.pnPara;
+ pfcb->pnFntb = fib.pnFntb;
+ pfcb->pnSep = fib.pnSep;
+
+ pfcb->pnSetb = fib.pnSetb;
+ pfcb->pnBftb = fib.pnBftb;
+ pfcb->pnFfntb = fib.pnFfntb;
+ pfcb->pnMac = fib.pnMac;
+ if (dty != dtyPrd)
+ {
+ if (FNoHeap(hsz = HszCreate((PCH)fib.szSsht)))
+ goto ErrRet;
+ (**hpfnfcb)[fn].hszSsht = hsz;
+ if (!FMakeRunTables(fn))
+ goto ErrRet;
+ }
+ }
+
+return fn;
+
+ErrRet:
+(pfcb = &(**hpfnfcb)[fn])->rfn = rfnFree;
+FreeH(pfcb->hszFile);
+return fnNil;
+} /* end of F n O p e n S z */
+
+
+
+
+
+
+/*---------------------------------------------------------------------------
+-- Routine: WCompSzC(psz1,psz2)
+-- Description and Usage:
+ Alphabetically compares the two null-terminated strings psz1 and psz2.
+ Upper case alpha characters are mapped to lower case.
+ Comparison of non-alpha characters is by ascii code.
+ Returns 0 if they are equal, a negative number if psz1 precedes psz2, and
+ a non-zero positive number if psz2 precedes psz1.
+-- Arguments:
+ psz1, psz2 - pointers to two null-terminated strings to compare
+-- Returns:
+ a short - 0 if strings are equal, negative number if psz1 precedes psz2,
+ and non-zero positive number if psz2 precedes psz1.
+-- Side-effects: none
+-- Bugs:
+-- History:
+ 3/14/83 - created (tsr)
+----------------------------------------------------------------------------*/
+short
+WCompSzC(psz1,psz2)
+PCH psz1;
+PCH psz2;
+{
+ int ch1;
+ int ch2;
+
+ for(ch1=ChLowerC(*psz1++),ch2=ChLowerC(*psz2++);
+ ch1==ch2;
+ ch1=ChLowerC(*psz1++),ch2=ChLowerC(*psz2++))
+ {
+ if(ch1 == '\0')
+ return(0);
+ }
+ return(ch1-ch2);
+} /* end of W C o m p S z C */
+
+/*---------------------------------------------------------------------------
+-- Routine: ChLowerC(ch)
+-- Description and Usage:
+ Converts its argument to lower case iff its argument is upper case.
+ Returns the de-capitalized character or the initial char if it wasn't caps.
+-- Arguments:
+ ch - character to be de-capitalized
+-- Returns:
+ a character - initial character, de-capitalized if needed.
+-- Side-effects:
+-- Bugs:
+-- History:
+ 3/14/83 - created (tsr)
+----------------------------------------------------------------------------*/
+int
+ChLowerC(ch)
+register CHAR ch;
+{
+ if(isupper(ch))
+ return(ch + ('a' - 'A')); /* foreign is taken care of */
+ else
+ return ch;
+} /* end of C h L o w e r C */
+
+#ifdef JAPAN
+// Compare ch with halfsize-KANA code range, then return whether it is or not.
+BOOL IsKanaInDBCS(int ch)
+{
+ ch &= 0x00ff;
+ if(ch>=0xA1 && ch <= 0xDF) return TRUE;
+ else return FALSE;
+}
+#endif
+
+
+
+
+
+typeFC (**HgfcCollect(fn, pnFirst, pnLim))[]
+typePN pnFirst, pnLim;
+{ /* Create a table indexing fc's by fkp number */
+ typeFC fcMac;
+ typePN pn;
+ int ifcMac, ifc;
+ typeFC (**hgfc)[];
+
+ struct FKP fkp;
+
+ fcMac = (**hpfnfcb)[fn].fcMac;
+ pn = pnFirst + 1;
+ ifcMac = ifcMacInit; /* Length of table */
+ hgfc = (typeFC (**)[])HAllocate((ifcMacInit * sizeof(typeFC)) / sizeof(int));
+ if (FNoHeap(hgfc))
+ return (typeFC (**)[])hOverflow;
+
+ for (ifc = 0; ; ++ifc, ++pn)
+ { /* Put first fcLim of each fkp in table */
+ if (ifc >= ifcMac)
+ { /* Must grow table */
+ int cw = ((ifcMac += ifcMacInit) * sizeof (typeFC)) / sizeof(int);
+ if (!FChngSizeH(hgfc, cw, false))
+ {
+LHFGCErrRet:
+ FreeH(hgfc);
+ return (typeFC (**)[])hOverflow;
+ }
+ }
+ if (pn < pnLim)
+ { /* Get fcLimFkb from fcFirst of next page */
+ int cch;
+
+ cch = CchReadAtPage( fn, pn, (CHAR *) &fkp, cbSector, TRUE );
+ if (cch != cfcPage)
+ goto LHFGCErrRet;
+ (**hgfc)[ifc] = fkp.fcFirst;
+ }
+ else
+ { /* fcLimFkb is fcMac + 1 */
+ (**hgfc)[ifc] = fcMac + 1;
+ if (!FChngSizeH(hgfc, ((ifc + 1) * sizeof(typeFC)) / sizeof(int), true))
+ {
+ /* Previously ignored bad return value here ..pault 11/3/89 */
+ goto LHFGCErrRet;
+ }
+ return hgfc;
+ }
+ }
+} /* end of H g f c C o l l e c t */
+
+
+
+
+/* F M A K E R U N T A B L E S */
+int FMakeRunTables(fn)
+{ /* Create two tables of fc-dpn pairs, one for chr's and one for par's */
+ typeFC (**hgfc)[];
+
+ if (FNoHeap(hgfc = HgfcCollect(fn, (**hpfnfcb)[fn].pnChar, (**hpfnfcb)[fn].pnPara)))
+ return false;
+ (**hpfnfcb)[fn].hgfcChp = hgfc;
+ if (FNoHeap(hgfc = HgfcCollect(fn, (**hpfnfcb)[fn].pnPara, (**hpfnfcb)[fn].pnFntb)))
+ {
+ FreeH( (**hpfnfcb) [fn].hgfcChp );
+ return false;
+ }
+ (**hpfnfcb)[fn].hgfcPap = hgfc;
+ return true;
+} /* end of F M a k e R u n T a b l e */
+
+
+
+FApplyOldWordSprm(doc)
+/* applies a sprm to this doc which causes all "old word" fonts to be remapped
+ into new windows ones */
+{
+CHAR rgbSprm[7];
+extern int vfSysFull;
+
+/* set up the OldFtc sprm mapping */
+rgbSprm[0] = sprmCOldFtc;
+rgbSprm[1] = 5;
+
+rgbSprm[2 + iftcModern] = FtcScanDocFfn(doc, PffnDefault(FF_MODERN));
+rgbSprm[2 + iftcRoman] = FtcScanDocFfn(doc, PffnDefault(FF_ROMAN));
+rgbSprm[2 + iftcScript] = FtcScanDocFfn(doc, PffnDefault(FF_SCRIPT));
+rgbSprm[2 + iftcDecorative] = FtcScanDocFfn(doc, PffnDefault(FF_DECORATIVE));
+rgbSprm[2 + iftcSwiss] = FtcScanDocFfn(doc, PffnDefault(FF_SWISS));
+
+AddSprmCps(rgbSprm, doc, (typeCP)0, (**hpdocdod)[doc].cpMac);
+return(vfSysFull == 0);
+}
+
diff --git a/private/mvdm/wow16/write/pageinfo.c b/private/mvdm/wow16/write/pageinfo.c
new file mode 100644
index 000000000..56309f156
--- /dev/null
+++ b/private/mvdm/wow16/write/pageinfo.c
@@ -0,0 +1,156 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the window proc for the page info window. */
+
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "fmtdefs.h"
+#include "wwdefs.h"
+
+#ifdef DBCS
+#include "kanji.h"
+#endif
+
+/* D R A W M O D E */
+DrawMode()
+ {
+ /* This routine forces the repainting of the page info window. */
+
+ extern HWND vhWndPageInfo;
+
+ InvalidateRect(vhWndPageInfo, (LPRECT)NULL, FALSE);
+ UpdateWindow(vhWndPageInfo);
+ }
+
+
+
+
+long FAR PASCAL PageInfoWndProc(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ extern HFONT vhfPageInfo;
+ extern int ypszPageInfo;
+ extern CHAR szMode[];
+ extern int dypScrlBar;
+ extern struct FLI vfli;
+ extern struct WWD rgwwd[];
+
+ if (message == WM_PAINT)
+ {
+ PAINTSTRUCT ps;
+
+ /* Initialize the DC. */
+ BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
+
+ if (vhfPageInfo == NULL)
+ {
+ extern char szSystem[];
+ LOGFONT lf;
+ TEXTMETRIC tm;
+
+ /* Load a font that will fit in the info "window". */
+ bltbc(&lf, 0, sizeof(LOGFONT));
+#ifdef WIN30
+ /* Don't default to ANY ol' typeface ..pault */
+ bltsz(szSystem, lf.lfFaceName);
+#ifdef DBCS /* was in JAPAN; KenjiK ' 90-10-25 */
+ /* We use Double Byte Character string,so using font must be
+ able to show them. */
+ lf.lfCharSet = KANJI_CHARSET;
+#endif /* DBCS */
+
+#endif
+ lf.lfHeight = -(dypScrlBar - (GetSystemMetrics(SM_CYBORDER) << 1));
+ if ((vhfPageInfo = CreateFontIndirect((LPLOGFONT)&lf)) == NULL)
+ {
+ goto BailOut;
+ }
+ if (SelectObject(ps.hdc, vhfPageInfo) == NULL)
+ {
+ DeleteObject(vhfPageInfo);
+ vhfPageInfo = NULL;
+ goto BailOut;
+ }
+
+ /* Figure out where to draw the string. */
+ GetTextMetrics(ps.hdc, (LPTEXTMETRIC)&tm);
+ ypszPageInfo = ((dypScrlBar - (tm.tmHeight - tm.tmInternalLeading) +
+ 1) >> 1) - tm.tmInternalLeading;
+ }
+
+ /* Draw the "Page nnn" (no longer at the VERY left) */
+ PatBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right -
+ ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, PATCOPY);
+ TextOut(ps.hdc, GetSystemMetrics(SM_CXBORDER)+5, ypszPageInfo,
+ (LPSTR)szMode, CchSz(szMode) - 1);
+
+BailOut:
+ EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
+ return(0L);
+ }
+ else if (message == WM_RBUTTONDOWN && vfli.rgdxp[1] == 0xFFFE &&
+ wParam & MK_CONTROL )
+ {
+ (vfli.rgdxp[1])--;
+ return(0L);
+ }
+ else
+ {
+ /* All we are interested in here are paint messages. */
+ return(DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ }
+
+
+#ifdef SPECIAL
+fnSpecial(hWnd, hDC, rgfp, sz)
+HWND hWnd;
+HDC hDC;
+FARPROC rgfp[];
+CHAR sz[];
+ {
+ RECT rc;
+ RECT rcText;
+ int dxpLine;
+ int dypLine;
+
+ {
+ register CHAR *pch = &sz[0];
+
+ while (*pch != '\0')
+ {
+ *pch = *pch ^ 0x13;
+ pch++;
+ }
+ }
+ (*rgfp[0])(hWnd, (LPRECT)&rc);
+ rc.right &= 0xFF80;
+ rc.bottom &= 0xFF80;
+ rcText.right = rc.right - (rcText.left = (rc.right >> 2) + (rc.right >> 3));
+ rcText.bottom = rc.bottom - (rcText.top = rc.bottom >> 2);
+ (*rgfp[1])(hDC, (LPSTR)sz, -1, (LPRECT)&rcText, DT_CENTER | DT_WORDBREAK);
+ dxpLine = rc.right >> 1;
+ dypLine = rc.bottom >> 1;
+ {
+ register int dxp;
+ register int dyp;
+
+ for (dxp = dyp = 0; dxp <= dxpLine; dxp += rc.right >> 6, dyp +=
+ rc.bottom
+ >> 6)
+ {
+ (*rgfp[2])(hDC, dxpLine - dxp, dyp);
+ (*rgfp[3])(hDC, dxp, dyp + dypLine);
+ (*rgfp[2])(hDC, dxpLine + dxp, dyp);
+ (*rgfp[3])(hDC, rc.right - dxp, dyp + dypLine);
+ }
+ }
+ }
+#endif /* SPECIAL */
+
diff --git a/private/mvdm/wow16/write/pictdrag.c b/private/mvdm/wow16/write/pictdrag.c
new file mode 100644
index 000000000..e1ac3c8ed
--- /dev/null
+++ b/private/mvdm/wow16/write/pictdrag.c
@@ -0,0 +1,1137 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* pictdrag.c -- Routines for Move Picture and Size Picture */
+
+//#define NOGDICAPMASKS
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOFONT
+#define NOHDC
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include "editdefs.h"
+#include "prmdefs.h"
+#include "winddefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+extern struct DOD (**hpdocdod)[];
+extern typeCP cpMacCur;
+extern int docCur;
+extern int wwCur;
+extern struct SEL selCur;
+extern struct WWD *pwwdCur;
+extern struct WWD rgwwd[];
+extern typeCP vcpFirstParaCache;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int vfPictSel;
+extern int vfPMS;
+extern int vfCancelPictMove;
+
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+STATIC NEAR ModifyPicInfoDxa( int, int, int, unsigned, unsigned, BOOL );
+STATIC NEAR ModifyPicInfoDxp( int, int, int, unsigned, unsigned );
+STATIC NEAR ShowPictMultipliers( void );
+
+
+#define dxpPicSizeMin dypPicSizeMin
+
+/* Type for possible positions of the "size box" icon while
+ moving/sizing a picture */
+/* WARNING: fnSizePicture relies on mdIconCenterFloat == 0 */
+
+#define mdIconCenterFloat 0 /* In Center of picture; icon may float */
+#define mdIconLeft 1 /* On Left Border */
+#define mdIconRight 2 /* On Right Border */
+#define mdIconCenterFix 3 /* In center of picture; border moves w/icon */
+#define mdIconXMask 3 /* Masks left/right */
+#define mdIconBottom 4 /* On bottom border */
+#define mdIconSetCursor 8 /* Force set of mouse cursor position */
+#define mdIconLL (mdIconLeft | mdIconBottom)
+#define mdIconLR (mdIconRight | mdIconBottom)
+
+
+/* "PMS" means "Picture Move or Size" */
+
+HCURSOR vhcPMS=NULL; /* Handle to "size box" cursor */
+STATIC RECT rcPicture; /* Rectangle containing picture */
+STATIC RECT rcClip; /* Window clip box (may intersect above) */
+STATIC int ilevelPMS; /* Level for DC save */
+STATIC RECT rcInverted; /* Rectangle for last border drawn */
+STATIC int fIsRcInverted=FALSE; /* Whether border is on */
+STATIC int dxpKeyMove=8; /* # of pixels to move per arrow key (X) */
+STATIC int dypKeyMove=4; /* # of pixels to move per arrow key (Y) */
+
+STATIC int dxpPicMac; /* Rightmost edge (enforced for move only) */
+STATIC int dypPicMac; /* Max. picture bottom edge */
+STATIC int fPictModified; /* Set to TRUE if pic gets changed */
+
+/* Special statics for resizing bitmaps with multipliers */
+
+STATIC unsigned mxCurrent; /* Current Multipliers while resizing */
+STATIC unsigned myCurrent;
+STATIC int fSizing; /* TRUE for sizing, FALSE for moving */
+STATIC int dxpOrig; /* Object's original size in pixels */
+STATIC int dypOrig; /* used as a basis for computing multipliers */
+
+STATIC unsigned cxpPrinterPixel; /* For scaling devices, expand the 64K */
+STATIC unsigned cypPrinterPixel; /* Limit */
+
+int NEAR FStartPMS( int );
+void NEAR EndPMS( void );
+void NEAR DrawPMSFrameIcon( int, POINT );
+void NEAR GetCursorClientPos( POINT * );
+void NEAR SetCursorClientPos( POINT );
+void NEAR InvertPMSFrame( void );
+void NEAR SetupDCForPMS( void );
+
+
+
+
+CmdUnscalePic()
+{ /* Restore picture to the size that it originally was on import */
+struct PICINFOX picInfo;
+int dxa, dya;
+
+GetPicInfo(selCur.cpFirst, selCur.cpLim, docCur, &picInfo);
+if (FComputePictSize( &picInfo.mfp, &dxa, &dya ))
+ ModifyPicInfoDxa( 0, dxa, dya, mxMultByOne, myMultByOne, FALSE );
+}
+
+
+
+fnMovePicture()
+{ /* Handle the "Move Picture" command in the EDIT dropdown. */
+ MSG msg;
+ int mdIcon=mdIconCenterFix;
+ POINT pt;
+
+ Assert( vfPictSel );
+
+ vfCancelPictMove = FALSE;
+ if (!FStartPMS(FALSE))
+ return;
+
+ GetCursorClientPos( &pt );
+
+ while (TRUE)
+ {
+ /*
+ * If the main window proc was sent a kill focus message,
+ * then we should cancel this move.
+ */
+ if (vfCancelPictMove)
+ {
+ fPictModified = FALSE;
+ goto SkipChange;
+ }
+
+ /*
+ * Otherwise, continue normal processing for a picture move.
+ */
+
+ if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE ))
+ { /* No message waiting -- scroll if we're above or below window */
+ mdIcon &= ~mdIconSetCursor;
+ goto MoveFrame;
+ }
+ else
+ { /* Absorb all messages, only process: left & right arrows,
+ RETURN and ESC, mouse move & mouse down (left button) */
+
+ GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 );
+
+ switch (msg.message) {
+ default:
+ break;
+ case WM_KEYDOWN:
+ mdIcon |= mdIconSetCursor;
+ GetCursorClientPos( &pt );
+ pt.y = rcInverted.top +
+ (unsigned)(rcInverted.bottom - rcInverted.top) / 2;
+ switch (msg.wParam) {
+ case VK_RETURN:
+ goto MakeChange;
+ case VK_ESCAPE:
+ goto SkipChange;
+ case VK_LEFT:
+ pt.x -= dxpKeyMove;
+ goto MoveFrame;
+ case VK_RIGHT:
+ pt.x += dxpKeyMove;
+ goto MoveFrame;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ mdIcon &= ~mdIconSetCursor;
+ pt = MAKEPOINT( msg.lParam );
+MoveFrame:
+ DrawPMSFrameIcon( mdIcon, pt );
+ break;
+ case WM_LBUTTONDOWN:
+ goto MakeChange;
+ break;
+ }
+ } /* end else */
+ } /* end while */
+
+MakeChange:
+ ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin, -1, -1,
+ -1, -1 );
+SkipChange:
+ EndPMS();
+}
+
+
+
+
+fnSizePicture()
+{ /* Handle the "Size Picture" command in the EDIT dropdown. */
+ MSG msg;
+ int mdIcon=mdIconCenterFloat;
+ POINT pt;
+ int fFirstMouse=TRUE; /* A workaround hack bug fix */
+
+
+ vfCancelPictMove = FALSE;
+ if (!FStartPMS(TRUE))
+ return;
+ ShowPictMultipliers();
+
+ GetCursorClientPos( &pt );
+
+ while (TRUE)
+ {
+ /*
+ * If the main window proc was sent a killfocus message,
+ * then we should cancel this sizing.
+ */
+ if (vfCancelPictMove)
+ {
+ fPictModified = FALSE;
+ goto SkipChange;
+ }
+
+ /*
+ * Otherwise, continue normal processing for a picture size.
+ */
+ if (!PeekMessage( (LPMSG) &msg, (HWND) NULL, 0, 0, PM_NOREMOVE ))
+ { /* No message waiting -- scroll if we're above or below window */
+ mdIcon &= ~mdIconSetCursor;
+ goto MoveFrame;
+ }
+ else
+ { /* Absorb all messages, only process: left & right arrows,
+ RETURN and ESC, mouse move & mouse down (left button) */
+
+ GetMessage( (LPMSG) &msg, (HWND) NULL, 0, 0 );
+
+ switch (msg.message) {
+ default:
+ break;
+ case WM_KEYDOWN:
+ GetCursorClientPos( &pt );
+ mdIcon |= mdIconSetCursor;
+ switch (msg.wParam) {
+ case VK_RETURN:
+ goto MakeChange;
+ case VK_ESCAPE:
+ goto SkipChange;
+ case VK_RIGHT:
+ switch (mdIcon & mdIconXMask) {
+ default:
+ pt.x = rcInverted.right;
+ mdIcon |= mdIconRight;
+ break;
+ case mdIconRight:
+ case mdIconLeft:
+ pt.x += dxpKeyMove;
+ break;
+ }
+ goto MoveFrame;
+ case VK_LEFT:
+ switch (mdIcon & mdIconXMask) {
+ default:
+ pt.x = rcInverted.left;
+ mdIcon |= mdIconRight;
+ break;
+ case mdIconRight:
+ case mdIconLeft:
+ pt.x -= dxpKeyMove;
+ break;
+ }
+ goto MoveFrame;
+ case VK_UP:
+ if ( mdIcon & mdIconBottom )
+ pt.y -= dypKeyMove;
+ else
+ {
+ pt.y = rcInverted.bottom;
+ mdIcon |= mdIconBottom;
+ }
+ goto MoveFrame;
+ case VK_DOWN:
+ if ( mdIcon & mdIconBottom )
+ pt.y += dypKeyMove;
+ else
+ {
+ pt.y = rcInverted.bottom;
+ mdIcon |= mdIconBottom;
+ }
+ goto MoveFrame;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ mdIcon &= ~mdIconSetCursor;
+ if (fFirstMouse)
+ { /* We sometimes get 1 bogus mouse message, so skip it */
+ fFirstMouse = FALSE;
+ break;
+ }
+
+ pt = MAKEPOINT( msg.lParam );
+
+ /* Trap "breaking through" a border with a mouse */
+
+ if ( !(mdIcon & mdIconXMask) )
+ { /* Haven't broken through left or right */
+ if (pt.x >= rcInverted.right)
+ mdIcon |= mdIconRight;
+ else if (pt.x <= rcInverted.left)
+ mdIcon |= mdIconLeft;
+ }
+ if ( !(mdIcon & mdIconBottom) )
+ { /* Haven't broken through bottom */
+ if (pt.y >= rcInverted.bottom)
+ mdIcon |= mdIconBottom;
+ }
+MoveFrame:
+
+ /* Trap border crossings */
+
+ switch (mdIcon & mdIconXMask) {
+ default:
+ break;
+ case mdIconLeft:
+ if (pt.x >= rcInverted.right)
+ { /* Moving left icon right, crossed right border */
+ mdIcon = (mdIcon & ~mdIconXMask) | mdIconRight;
+ goto WholePic;
+ }
+ break;
+ case mdIconRight:
+ if (pt.x <= rcInverted.left)
+ { /* Moving right icon left, crossed border */
+ mdIcon = (mdIcon & ~mdIconXMask) | mdIconLeft;
+WholePic:
+ if (fIsRcInverted)
+ InvertPMSFrame();
+ rcInverted = rcPicture;
+ }
+ break;
+ }
+
+ DrawPMSFrameIcon( mdIcon, pt );
+ break;
+ case WM_LBUTTONDOWN:
+ goto MakeChange;
+ break;
+ }
+ } /* end else */
+ } /* end while */
+
+MakeChange:
+
+ {
+ unsigned NEAR MxRoundMx( unsigned );
+ /* Round multipliers if near an even multiple */
+ unsigned mx = MxRoundMx( mxCurrent );
+ unsigned my = MxRoundMx( myCurrent );
+
+ /* Assert must be true for above call to work for an my */
+ Assert( mxMultByOne == myMultByOne );
+
+ ModifyPicInfoDxp( rcInverted.left - xpSelBar + wwdCurrentDoc.xpMin,
+ rcInverted.right - rcInverted.left,
+ rcInverted.bottom - rcInverted.top,
+ mx, my );
+ }
+
+SkipChange:
+ EndPMS();
+}
+
+
+unsigned NEAR MxRoundMx( mx )
+unsigned mx;
+{ /* If mx is near an "interesting" multiple, round it to be exactly that
+ multiple. Interesting multiples are:
+ 1 (m=mxMultByOne), 2 (m=2 * mxMultByOne), 3 , ...
+ 0.5 (m = .5 * mxMultByOne)
+ This routine works for my, too, as long as mxMultByOne == myMultByOne */
+
+ /* This means close enough to round (1 decimal place accuracy) */
+#define dmxRound (mxMultByOne / 20)
+
+ unsigned mxRemainder;
+
+ if (mx >= mxMultByOne - dmxRound)
+ { /* Multiplier > 1 -- look for rounding to integer multiple */
+ if ((mxRemainder = mx % mxMultByOne) < dmxRound)
+ mx -= mxRemainder;
+ else if (mxRemainder >= mxMultByOne - dmxRound)
+ mx += (mxMultByOne - mxRemainder);
+ }
+ else
+ { /* Multiplier < 1 -- look for multiplication by 1/2 */
+ if ((mxRemainder = mx % (mxMultByOne >> 1)) < dmxRound)
+ mx -= mxRemainder;
+ else if (mxRemainder >= ((mxMultByOne >> 1) - dmxRound))
+ mx += (mxMultByOne >> 1) - mxRemainder;
+ }
+
+ return mx;
+}
+
+
+
+
+int NEAR FStartPMS( fSize )
+int fSize;
+{ /* Initialization for Picture Move/Size */
+extern HCURSOR vhcHourGlass;
+extern HWND hParentWw;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern HDC vhDCPrinter;
+
+ struct PICINFOX picInfo;
+ struct EDL *pedl;
+ RECT rc;
+ HDC hdcT;
+ POINT pt;
+
+ Assert(vhDCPrinter);
+ fSizing = fSize;
+
+ UpdateWw( wwCur, FALSE ); /* Screen must be up-to-date */
+
+ /* Set the rect that defines our display area */
+ SetRect( (LPRECT) &rcClip, xpSelBar, wwdCurrentDoc.ypMin,
+ wwdCurrentDoc.xpMac, wwdCurrentDoc.ypMac );
+
+ GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo );
+
+ if (fSize)
+ {
+ if (BStructMember( PICINFOX, my ) >= picInfo.cbHeader )
+ { /* OLD file format (no multipliers), scaling not supported */
+ return FALSE;
+ }
+ }
+
+/* Set multiplier factor used by the printer (will be { 1, 1 } if
+ the printer is not a scaling device; greater if it is.)
+ This info is used for the 64K limit test of picture growth. */
+
+ if (!(GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_BITMAP64))
+ /* doesn't support > 64K bitmaps */
+ {
+ if (GetDeviceCaps( vhDCPrinter, RASTERCAPS ) & RC_SCALING)
+ {
+ POINT pt;
+
+ pt.x = pt.y = 0; /* Just in case */
+ Escape( vhDCPrinter, GETSCALINGFACTOR, 0, (LPSTR) NULL,
+ (LPSTR) (LPPOINT) &pt );
+ cxpPrinterPixel = 1 << pt.x;
+ cypPrinterPixel = 1 << pt.y;
+ }
+ else
+ {
+ cxpPrinterPixel = cypPrinterPixel = 1;
+ }
+ }
+ else
+ {
+ cxpPrinterPixel = cypPrinterPixel = 0xFFFF;
+ }
+
+ /* Compute picture's original (when pasted) size in
+ screen pixels {dxpOrig, dypOrig}.
+ These numbers are the bases for computing the multiplier. */
+
+ switch(picInfo.mfp.mm)
+ {
+ case MM_BITMAP:
+ GetBitmapSize( &dxpOrig, &dypOrig, &picInfo, FALSE );
+
+ /* Compensate for effects of existing multipliers */
+
+ dxpOrig = MultDiv( dxpOrig, mxMultByOne, picInfo.mx );
+ dypOrig = MultDiv( dypOrig, myMultByOne, picInfo.my );
+ break;
+
+ default: // OLE and META
+ {
+ int dxa, dya;
+
+ if (!FComputePictSize( &picInfo.mfp, &dxa, &dya ))
+ return FALSE;
+
+ dxpOrig = DxpFromDxa( dxa, FALSE );
+ dypOrig = DypFromDya( dya, FALSE );
+ }
+ break;
+ }
+
+ if (!FGetPictPedl( &pedl ))
+ /* Picture must be on the screen */
+ return FALSE;
+ ComputePictRect( &rcPicture, &picInfo, pedl, wwCur );
+ rcInverted = rcPicture; /* Initial grey box is the size of the picture */
+
+ vfPMS = TRUE; /* So ToggleSel knows not to invert the pict */
+ fPictModified = FALSE;
+
+ /* Amt to move for arrow keys is derived from size of fixed font */
+
+ if ( ((hdcT=GetDC( hParentWw ))!=NULL) &&
+ (SelectObject( hdcT, GetStockObject( ANSI_FIXED_FONT ) )!=0))
+ {
+ TEXTMETRIC tm;
+
+ GetTextMetrics( hdcT, (LPTEXTMETRIC) &tm );
+ ReleaseDC( hParentWw, hdcT );
+ dxpKeyMove = tm.tmAveCharWidth;
+ dypKeyMove = (tm.tmHeight + tm.tmExternalLeading) / 2;
+ }
+
+ SetupDCForPMS(); /* Save DC and select in a grey brush for border drawing */
+
+ /* Assure that the "size box" mouse cursor is loaded */
+ if (vhcPMS == NULL)
+ {
+ extern HANDLE hMmwModInstance;
+ extern CHAR szPmsCur[];
+
+ vhcPMS = LoadCursor( hMmwModInstance, (LPSTR) szPmsCur );
+ }
+
+ /* Compute maximum allowable area for picture to roam
+ (relative to para left edge, picture top) */
+ CacheSectPic( docCur, selCur.cpFirst );
+ dxpPicMac = imax(
+ DxpFromDxa( vsepAbs.dxaText, FALSE ),
+ rcPicture.right - xpSelBar + wwdCurrentDoc.xpMin );
+ dypPicMac = DypFromDya( vsepAbs.yaMac, FALSE );
+
+ /* Since the picture is selected, need to un-invert it */
+ InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture );
+
+ SetCapture( wwdCurrentDoc.wwptr ); /* Hog all mouse actions */
+
+ /* Draw initial size box icon in the center of the picture */
+
+ pt.x = rcInverted.left + (unsigned)(rcInverted.right - rcInverted.left)/2;
+ pt.y = rcInverted.top + (unsigned)(rcInverted.bottom - rcInverted.top)/2;
+ DrawPMSFrameIcon( mdIconCenterFix | mdIconSetCursor, pt );
+
+ SetCursor( vhcPMS ); /* Make the mouse cursor a size box */
+ ShowCursor( TRUE ); /* So cursor appears even on mouseless systems */
+
+ return TRUE;
+}
+
+
+
+
+void NEAR SetupDCForPMS()
+{ /* Save current document DC & set it up for picture move/sizing:
+ - A gray background brush for drawing the border
+ - A drawing area resricted to rcClip */
+
+ ilevelPMS = SaveDC( wwdCurrentDoc.hDC );
+ SelectObject( wwdCurrentDoc.hDC, GetStockObject( GRAY_BRUSH ) );
+ IntersectClipRect( wwdCurrentDoc.hDC,
+ rcClip.left, rcClip.top, rcClip.right, rcClip.bottom );
+}
+
+
+
+
+void NEAR EndPMS()
+{ /* Leaving Picture Move/Size */
+extern int docMode;
+struct PICINFOX picInfo;
+
+ vfPMS = FALSE;
+ ReleaseCapture(); /* Allow other windows to receive mouse events */
+ SetCursor( NULL );
+
+ docMode = docNil;
+ CheckMode(); /* Compensate for multiplier display */
+
+ if (fIsRcInverted)
+ InvertPMSFrame();
+
+ if (!fPictModified && !vfCancelPictMove)
+ { /* Picture did not change, restore inversion to show selection */
+ /* Must do this BEFORE RestoreDC so excess above ypMin is clipped */
+ InvertRect( wwdCurrentDoc.hDC, (LPRECT) &rcPicture );
+ }
+
+ RestoreDC( wwdCurrentDoc.hDC, ilevelPMS );
+
+ ShowCursor( FALSE ); /* Decrement cursor ref cnt (blanks if no mouse) */
+
+ /* Since we've been ignoring messages, make sure our key flags are OK */
+ SetShiftFlags();
+}
+
+
+
+void NEAR DrawPMSFrameIcon( mdIcon, pt )
+int mdIcon;
+POINT pt;
+{ /* Draw Picture Move/Size frame and icon, with the icon at position
+ pt. The icon type is given by mdIcon.
+
+ Scrolls the correct part of the picture into view if necessary.
+
+ Uses statics: rcPicture, rcClip, rcInverted, fIsRcInverted
+ */
+#define FEqualRect( r1, r2 ) ((r1.left==r2.left)&&(r1.right==r2.right)&&\
+ (r1.top==r2.top)&&(r1.bottom==r2.bottom))
+
+ extern int vfAwfulNoise;
+ int xpCntr;
+ int dxpCntr = ((unsigned)(rcInverted.right - rcInverted.left)) / 2;
+ RECT rcT;
+
+ rcT = rcInverted;
+
+ /* Set pt.y so it does not exceed limits */
+
+ if (mdIcon & mdIconBottom)
+ {
+ if (pt.y - rcInverted.top > dypPicMac)
+ {
+ pt.y = rcInverted.top + dypPicMac; /* max y-size is 1 page */
+ }
+ else if (pt.y < rcInverted.top + 1)
+ pt.y = rcInverted.top + 1; /* min y-size is 1 pixel */
+
+ /* Restrict pt.x as necessary to keep printer bitmap < 64K */
+
+ if ((pt.y > rcInverted.bottom) && (cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF))
+ { /* Really sizing in y */
+ unsigned dxpScreen = imax (imax(pt.x,rcInverted.right)-rcInverted.left,
+ dxpPicSizeMin);
+ unsigned dxpPrinter = DxpFromDxa(DxaFromDxp( dxpScreen, FALSE ), TRUE);
+ unsigned dypLast = 0xFFFF / (dxpPrinter / 8);
+ unsigned dyp = DypFromDya( DyaFromDyp( pt.y - rcInverted.top , FALSE),
+ TRUE );
+
+ if (dyp / (cxpPrinterPixel * cypPrinterPixel) > dypLast )
+ { /* Bitmap would overflow 64K boundary */
+ pt.y = rcInverted.top +
+ DypFromDya( DyaFromDyp( dypLast, TRUE ), FALSE );
+ }
+ }
+ }
+ else if (pt.y < rcInverted.top)
+ pt.y = rcInverted.top; /* Can't go above picture top */
+ else if (pt.y > rcInverted.bottom)
+ pt.y = rcInverted.bottom; /* Necessary? */
+
+ /* Set pt.x so it does not execeed limits */
+
+ switch (mdIcon & mdIconXMask) {
+ case mdIconCenterFloat:
+ case mdIconRight:
+
+ /* Restrict pt.x as necessary to keep printer bitmap < 64K */
+ if ((cxpPrinterPixel < 0xFFFF) && (cypPrinterPixel < 0xFFFF))
+ {
+ unsigned dyp = DypFromDya( DyaFromDyp( imax( pt.y - rcInverted.top,
+ dypPicSizeMin), FALSE ), TRUE );
+ unsigned dxpLast = 0xFFFF / (dyp / 8);
+ unsigned dxp = DxpFromDxa( DxaFromDxp( pt.x - rcInverted.left,
+ FALSE ), TRUE );
+
+ if (dxp / (cxpPrinterPixel * cypPrinterPixel) > dxpLast )
+ { /* Printer bitmap would overflow 64K boundary */
+ pt.x = rcInverted.left +
+ DxpFromDxa( DxaFromDxp( dxpLast, TRUE ), FALSE );
+ }
+ }
+
+ default:
+ break;
+ case mdIconLeft:
+ if ((pt.x < rcClip.left) && (wwdCurrentDoc.xpMin == 0))
+ pt.x = rcClip.left; /* Reached left scroll limit */
+ break;
+ case mdIconCenterFix:
+ if ( (pt.x - dxpCntr < rcClip.left) && (wwdCurrentDoc.xpMin == 0))
+ pt.x = rcClip.left + dxpCntr; /* Reached left scroll limit */
+ else if (pt.x - xpSelBar + wwdCurrentDoc.xpMin + dxpCntr > dxpPicMac)
+ /* Move Picture only: can't move past margins */
+ pt.x = dxpPicMac + xpSelBar - wwdCurrentDoc.xpMin - dxpCntr;
+ break;
+ }
+
+ /* Check for pt outside of clip rectangle; scroll/bail out as needed */
+
+ if (!PtInRect( (LPRECT)&rcClip, pt ))
+ {
+ int dxpHalfWidth = (unsigned)(rcClip.right - rcClip.left) / 2;
+ int dypHalfHeight = (unsigned)(rcClip.bottom - rcClip.top) / 2;
+ int dxpScroll=0;
+ int dypScroll=0;
+
+ if (pt.x < rcClip.left)
+ {
+ if (wwdCurrentDoc.xpMin == 0)
+ {
+ _beep(); /* Reached left-hand scroll limit */
+ pt.x = rcClip.left;
+ }
+ else
+ { /* SCROLL LEFT */
+ dxpScroll = imax( -wwdCurrentDoc.xpMin,
+ imin( -dxpHalfWidth, pt.x - rcClip.left ) );
+ }
+ }
+ else if (pt.x > rcClip.right)
+ {
+ if (wwdCurrentDoc.xpMin + rcClip.right - rcClip.left >= xpRightLim )
+ {
+ _beep();
+ pt.x = rcClip.right; /* Reached right-hand scroll limit */
+ }
+ else
+ { /* SCROLL RIGHT */
+ dxpScroll = imin( xpRightLim - wwdCurrentDoc.xpMin +
+ rcClip.right - rcClip.left,
+ imax( dxpHalfWidth, pt.x - rcClip.right ) );
+ }
+ }
+
+ if (pt.y < rcClip.top)
+ {
+ struct EDL *pedl = &(**wwdCurrentDoc.hdndl)[wwdCurrentDoc.dlMac - 1];
+
+ if ( (rcInverted.top >= rcClip.top) ||
+ /* May not scroll all of the original picture off the screen */
+ (wwdCurrentDoc.dlMac <= 1) ||
+ ( (pedl->cpMin == selCur.cpFirst) &&
+ ( ((pedl-1)->cpMin != pedl->cpMin) || !(pedl-1)->fGraphics)))
+ {
+ _beep();
+ pt.y = rcClip.top;
+ }
+ else
+ { /* SCROLL UP */
+ dypScroll = rcInverted.top - rcClip.top;
+ }
+ }
+ else if (pt.y > rcClip.bottom)
+ {
+ struct EDL *pedl=&(**wwdCurrentDoc.hdndl)[0];
+
+ /* May not scroll all of the original picture off the screen */
+ if ( (wwdCurrentDoc.dlMac <= 1) ||
+ ( (pedl->cpMin == selCur.cpFirst) &&
+ ( ((pedl+1)->ichCpMin == 0) || !(pedl+1)->fGraphics) ))
+ {
+ _beep(); /* Reached downward scroll limit */
+ pt.y = rcClip.bottom; /* Must have at least 1 picture dl visible */
+ }
+ else
+ dypScroll = 1; /* SCROLL DOWN */
+ }
+
+ if (dxpScroll || dypScroll)
+ { /* SCROLL */
+ struct EDL *pedl;
+ struct PICINFOX picInfo;
+ int xpMinT = wwdCurrentDoc.xpMin;
+ int ypTopT = rcPicture.top;
+ int dxpAdjust, dypAdjust;
+
+ if (dxpScroll && dypScroll)
+ /* Did not need to truncate coordinates; re-enable beep */
+ vfAwfulNoise = FALSE;
+
+ if (fIsRcInverted)
+ InvertPMSFrame();
+
+ /* Scroll by the appropriate amount:
+ dxpScroll in x-direction; one line in y-direction */
+
+ RestoreDC( wwdCurrentDoc.hDC, ilevelPMS ); /* Use orig DC props */
+ if (dxpScroll)
+ AdjWwHoriz( dxpScroll );
+ if (dypScroll > 0)
+ ScrollDownCtr( 1 );
+ else if (dypScroll < 0)
+ ScrollUpCtr( 1 );
+ UpdateWw( wwCur, FALSE );
+ SetupDCForPMS(); /* Compensate for RestoreDC */
+
+ /* Update rcPicture to reflect new scroll position */
+
+ GetPicInfo( selCur.cpFirst, selCur.cpLim, docCur, &picInfo );
+ if (!FGetPictPedl( &pedl ))
+ {
+ Assert (FALSE); /* If we get here, we're in trouble */
+ _beep();
+ return;
+ }
+ ComputePictRect( &rcPicture, &picInfo, pedl, wwCur );
+
+ /* Adjust rcT, pt relative to the amount we actually scrolled */
+
+ dxpAdjust = xpMinT - wwdCurrentDoc.xpMin;
+ dypAdjust = rcPicture.top - ypTopT;
+ OffsetRect( (LPRECT) &rcT, dxpAdjust, dypAdjust );
+ pt.x += dxpAdjust;
+ pt.y += dypAdjust;
+
+ goto Display; /* Dont let rcInverted be edited until we have
+ scrolled the icon into view */
+ }
+ }
+
+ /* Compute effect of new icon position and/or type on rcInverted */
+
+ switch (mdIcon & mdIconXMask) {
+ case mdIconCenterFix:
+ if (!fSizing)
+ {
+ xpCntr = rcInverted.left + dxpCntr;
+ OffsetRect( (LPRECT) &rcT, pt.x - xpCntr, 0 );
+ }
+ break;
+ case mdIconLeft:
+ rcT.left = pt.x;
+ goto ComputeY;
+ case mdIconRight:
+ rcT.right = pt.x;
+ default:
+ case mdIconCenterFloat:
+ComputeY:
+ if (mdIcon & mdIconBottom)
+ rcT.bottom = pt.y;
+ break;
+ }
+
+Display:
+
+ /* If redrawing the border is necessary, do it */
+
+ if (!FEqualRect( rcT, rcInverted ) || (mdIcon & mdIconSetCursor))
+ {
+ if (fIsRcInverted)
+ InvertPMSFrame();
+ rcInverted = rcT;
+ InvertPMSFrame();
+ }
+ if (mdIcon & mdIconSetCursor)
+ {
+ SetCursorClientPos( pt );
+ SetCursor( vhcPMS );
+ }
+
+ /* If the multipliers have changed, redisplay them */
+
+ if (fSizing)
+ {
+ unsigned mx, my;
+
+ mx = MultDiv( rcInverted.right - rcInverted.left, mxMultByOne, dxpOrig );
+ my = MultDiv( rcInverted.bottom - rcInverted.top, myMultByOne, dypOrig );
+
+ if (mx != mxCurrent || my != myCurrent)
+ { /* Multipliers have changed */
+ mxCurrent = mx;
+ myCurrent = my;
+ ShowPictMultipliers();
+ }
+ }
+}
+
+
+
+
+void NEAR InvertPMSFrame()
+{ /* Draw a frame for rcInverted in XOR mode, update fIsRcInverted */
+ int dxpSize=rcInverted.right - rcInverted.left - 1;
+ int dypSize=rcInverted.bottom - rcInverted.top - 1;
+
+ PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top,
+ dxpSize, 1, PATINVERT );
+ PatBlt( wwdCurrentDoc.hDC, rcInverted.right - 1, rcInverted.top,
+ 1, dypSize, PATINVERT );
+ PatBlt( wwdCurrentDoc.hDC, rcInverted.left + 1, rcInverted.bottom - 1,
+ dxpSize, 1, PATINVERT );
+ PatBlt( wwdCurrentDoc.hDC, rcInverted.left, rcInverted.top + 1,
+ 1, dypSize, PATINVERT );
+
+ fIsRcInverted ^= -1;
+}
+
+
+
+
+void NEAR GetCursorClientPos( ppt )
+POINT *ppt;
+{ /* Get current mouse cursor coordinates (window-relative) */
+GetCursorPos( (LPPOINT) ppt );
+ScreenToClient( wwdCurrentDoc.wwptr, (LPPOINT) ppt );
+}
+
+
+
+
+void NEAR SetCursorClientPos( pt )
+POINT pt;
+{ /* Set current mouse cursor coordinates (window-relative) */
+ClientToScreen( wwdCurrentDoc.wwptr, (LPPOINT) &pt );
+SetCursorPos( pt.x, pt.y );
+}
+
+
+
+STATIC NEAR ModifyPicInfoDxp( xpOffset, xpSize, ypSize, mx, my )
+int xpOffset, xpSize, ypSize;
+unsigned mx, my;
+{ /* Modify the currently selected picture by adjusting its offset and
+ size to the pixel values specified. Negative values mean don't
+ set that value.
+ Added 9/23/85: mx and my parms give the multiplier, redundant
+ info used for scaling bitmaps. */
+
+ int xaOffset, xaSize, yaSize;
+
+ xaOffset = xaSize = yaSize = -1;
+
+ if (xpSize >= 0)
+ xaSize = DxaFromDxp( umax( xpSize, dxpPicSizeMin ), FALSE );
+ if (ypSize >= 0)
+ yaSize = DyaFromDyp( umax( ypSize, dypPicSizeMin ), FALSE );
+ if (xpOffset >= 0)
+ xaOffset = DxaFromDxp( xpOffset, FALSE );
+ ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, TRUE );
+}
+
+
+
+
+/* M O D I F Y P I C I N F O D X A */
+STATIC NEAR ModifyPicInfoDxa( xaOffset, xaSize, yaSize, mx, my, fSetUndo )
+int xaOffset, xaSize, yaSize;
+unsigned mx, my;
+BOOL fSetUndo;
+{ /* Modify the currently selected picture by adjusting its offset and
+ size to the twip values specified. Negative values mean don't
+ set that value.
+ Added 9/23/85: mx, my are size "multipliers", used for
+ bitmaps only */
+
+typeFC fcT;
+struct PICINFOX picInfo;
+typeCP cp = selCur.cpFirst;
+int dyaSizeOld;
+int fBitmap,fObj;
+
+fPictModified = TRUE;
+FreeBitmapCache();
+
+GetPicInfo(cp, cpMacCur, docCur, &picInfo);
+fBitmap = (picInfo.mfp.mm == MM_BITMAP);
+fObj = (picInfo.mfp.mm == MM_OLE);
+
+dyaSizeOld = picInfo.dyaSize;
+
+if (fBitmap || fObj)
+ {
+ if ((int)mx > 0 && (int)my > 0)
+ {
+ picInfo.mx = mx;
+ picInfo.my = my;
+ }
+ }
+else
+ {
+ if (xaSize >= 0)
+ picInfo.dxaSize = xaSize;
+
+ if (yaSize >= 0)
+ picInfo.dyaSize = yaSize;
+ }
+
+if (xaOffset >= 0)
+ picInfo.dxaOffset = xaOffset;
+
+if (picInfo.cbHeader > cchOldPICINFO)
+ /* Extended picture format, set extended format bit */
+ picInfo.mfp.mm |= MM_EXTENDED;
+
+if (!fObj)
+ fcT = FcWScratch( &picInfo, picInfo.cbHeader );
+
+picInfo.mfp.mm &= ~MM_EXTENDED;
+
+/* Right or center justify becomes invalid if the picture is moved
+ without being sized */
+
+CachePara(docCur, cp);
+if ( (xaSize < 0 && yaSize < 0) &&
+ (vpapAbs.jc == jcRight || vpapAbs.jc == jcCenter))
+ {
+ CHAR rgb[2];
+
+ if (fSetUndo)
+ SetUndo(uacPictSel, docCur, cp, selCur.cpLim - selCur.cpFirst,
+ docNil, cpNil, cpNil, 0);
+ TrashCache();
+ rgb[0] = sprmPJc;
+ rgb[1] = jcLeft;
+ AddSprm(&rgb[0]);
+ }
+else
+ {
+ if (fSetUndo)
+ SetUndo( uacPictSel, docCur, cp, (typeCP) picInfo.cbHeader,
+ docNil, cpNil, cpNil, 0);
+ }
+
+if (fObj)
+ ObjSetPicInfo(&picInfo, docCur, cp);
+else
+ Replace( docCur, cp, (typeCP) picInfo.cbHeader,
+ fnScratch, fcT, (typeFC) picInfo.cbHeader);
+
+if ( ((fBitmap || fObj) && (my > myMultByOne)) ||
+ (!fBitmap && (dyaSizeOld < picInfo.dyaSize)))
+ { /* If the picture height was increased, make sure proper EDLs are
+ invalidated. */
+ typeCP dcp = cpMacCur - cp + (typeCP) 1;
+ AdjustCp(docCur, cp, dcp, dcp);
+ }
+}
+
+
+
+
+STATIC NEAR ShowPictMultipliers( )
+{ /* Display the current multipliers (mxCurrent, myCurrent) in the page info
+ window in the form "n.nX/n.nY". */
+
+CHAR *PchCvtMx( unsigned, CHAR * );
+extern CHAR szMode[];
+
+CHAR *pch = szMode;
+
+pch = PchCvtMx( mxCurrent, pch );
+*(pch++) = 'X';
+*(pch++) = '/';
+Assert( mxMultByOne == myMultByOne ); /* Necessary for below to work w/ my */
+pch = PchCvtMx( myCurrent, pch );
+*(pch++) = 'Y';
+*pch = '\0';
+
+DrawMode();
+}
+
+
+CHAR *PchCvtMx( mx, pch )
+CHAR *pch;
+unsigned mx;
+{ /* Convert the passed multiplier word to a string representation.
+ Number is based on a mxMultByOne === 1 scale
+ (e.g. mx == .9 * mxMultByOne yields "0.9")
+ String always has at least one digit before the decimal point,
+ and exactly one after.
+ Examples of return strings: "10.5", "0.0", "5.5" */
+
+ int nTenths;
+ int nWholes;
+ int cch;
+ extern CHAR vchDecimal;
+ extern BOOL vbLZero;
+ extern int viDigits;
+
+ /* Round up to nearest single decimal place */
+
+ if (mx % (mxMultByOne / 10) >= mxMultByOne / 20)
+ mx += mxMultByOne / 20;
+
+ /* Write digit(s) before decimal place */
+
+ if (((nWholes = mx / mxMultByOne) == 0) && vbLZero)
+ *(pch++) = '0';
+ else
+ ncvtu( nWholes, &pch );
+
+ /* Write Decimal Point and following digit */
+
+ *(pch++) = vchDecimal;
+
+ if (viDigits > 0)
+ *(pch++) = ((mx % mxMultByOne) / (mxMultByOne / 10)) + '0';
+
+ *pch = '\0';
+
+ return pch;
+}
diff --git a/private/mvdm/wow16/write/picture.c b/private/mvdm/wow16/write/picture.c
new file mode 100644
index 000000000..19b4b9f87
--- /dev/null
+++ b/private/mvdm/wow16/write/picture.c
@@ -0,0 +1,798 @@
+/************************************************************/
+
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* picture.c -- MW format and display routines for pictures */
+
+//#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+//#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOFONT
+#define NOMB
+#define NOMENUS
+#define NOOPENFILE
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "fmtdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "stcdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include "editdefs.h"
+/* #include "str.h" */
+#include "prmdefs.h"
+/* #include "fkpdefs.h" */
+/* #include "macro.h" */
+#include "winddefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+extern typeCP cpMacCur;
+extern int docCur;
+extern int vfSelHidden;
+extern struct WWD rgwwd[];
+extern int wwCur;
+extern int wwMac;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern struct WWD *pwwdCur;
+extern struct PAP vpapCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern int vfPictSel;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern struct DOD (**hpdocdod)[];
+extern unsigned cwHeapFree;
+extern int vfInsertOn;
+extern int vfPMS;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern HBRUSH hbrBkgrnd;
+extern long ropErase;
+extern int vdocBitmapCache;
+extern typeCP vcpBitmapCache;
+extern HBITMAP vhbmBitmapCache;
+extern BOOL vfBMBitmapCache;
+extern HCURSOR vhcIBeam;
+extern BOOL vfMonochrome;
+
+
+/* Used in this module only */
+#ifdef DEBUG
+#define STATIC static
+#else
+#define STATIC
+#endif
+
+STATIC RECT rcPictInvalid; /* Rectangle (in window coords) that needs refresh */
+int vfWholePictInvalid = TRUE;
+
+
+FreeBitmapCache()
+{
+ vdocBitmapCache = docNil;
+ if (vhbmBitmapCache != NULL)
+ {
+ DeleteObject( vhbmBitmapCache );
+ vhbmBitmapCache = NULL;
+ }
+}
+
+
+
+
+MarkInvalidDlPict( ww, dlPict )
+int ww;
+int dlPict;
+{ /* Mark the passed dl (presumed to be part of a picture) as requiring
+ eventual update, when DisplayGraphics is called */
+
+ register struct WWD *pwwd = &rgwwd [ww];
+ struct EDL (**hdndl)[] = pwwd->hdndl;
+ struct EDL *pedl = &(**hdndl)[ dlPict ];
+ RECT rcDl;
+
+ SetRect( (LPRECT) &rcDl, 0, pedl->yp - pedl->dyp,
+ pwwd->xpMac, pedl->yp );
+
+ if (vfWholePictInvalid)
+ {
+ CopyRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcDl );
+ vfWholePictInvalid = FALSE;
+ }
+ else
+ {
+ RECT rcT;
+
+ rcT = rcPictInvalid; /* Necessary? i.e. can UnionRect handle
+ source == destination */
+ UnionRect( (LPRECT) &rcPictInvalid, (LPRECT) &rcT, (LPRECT) &rcDl );
+ }
+}
+
+
+
+
+DisplayGraphics( ww, dl, fDontDisplay )
+int ww;
+int dl;
+int fDontDisplay;
+{ /* Display a line of graphics info */
+ struct WWD *pwwd = &rgwwd[ww];
+ struct EDL *pedl;
+ typeCP cpPictStart;
+ typeCP cp;
+ typeCP cpMac = (**hpdocdod)[vfli.doc].cpMac;
+ struct PICINFOX picInfo;
+ RECT rcEnclose;
+ RECT rcPict;
+ HANDLE hBits=NULL;
+ HDC hMDC=NULL;
+ HDC hMDCCache=NULL;
+ HANDLE hbm=NULL;
+ HDC hDC=pwwd->hDC;
+ int cchRun;
+ unsigned long cbPict=0;
+ int dxpOrig; /* Size of picture in the original */
+ int dypOrig;
+ int dxpDisplay; /* Size of picture as we want to show it */
+ int dypDisplay;
+ int fBitmap;
+ int ilevel=0;
+
+ /* THIS ROUTINE COULD USE SOME GDI-CALL ERROR CHECKING! ..pault */
+
+ int fDrew=false;
+
+ /* In the case of monochrome devices, this raster op will map white in
+ the bitmap to the background color and black to the foreground color. */
+ #define ropMonoBm 0x00990066
+
+ Assert( dl >= 0 && dl < pwwd->dlMax );
+
+ MarkInvalidDlPict( ww, dl );
+
+ if (fDontDisplay)
+ {
+ return;
+ }
+
+ Diag(CommSz("DisplayGraphics: \n\r"));
+
+ FreezeHp();
+ pedl = &(**(pwwd->hdndl))[dl];
+ cpPictStart=pedl->cpMin;
+
+ GetPicInfo( cpPictStart, cpMac, vfli.doc, &picInfo );
+
+ /* Compute desired display size of picture (in device pixels) */
+
+ ComputePictRect( &rcPict, &picInfo, pedl, ww );
+ dxpDisplay = rcPict.right - rcPict.left;
+ dypDisplay = rcPict.bottom - rcPict.top;
+
+ /* Compute original size of picture (in device pixels) */
+ /* MM_ANISOTROPIC and MM_ISOTROPIC pictures have no original size */
+
+ switch ( picInfo.mfp.mm ) {
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ break;
+ case MM_BITMAP:
+ dxpOrig = picInfo.bm.bmWidth;
+ dypOrig = picInfo.bm.bmHeight;
+ break;
+#if defined(OLE)
+ case MM_OLE:
+ {
+ extern BOOL vfObjDisplaying;
+
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ goto DontDraw;
+
+ /* just to be safe */
+ if (!CheckPointer(lpOBJ_QUERY_INFO(&picInfo),1))
+ goto DontDraw;
+
+ if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL)
+ {
+ typeCP cpRet;
+
+ /* this can require memory, so unlock heap */
+ MeltHp();
+ vfObjDisplaying = TRUE;
+
+ cpRet = ObjLoadObjectInDoc(&picInfo,vfli.doc,cpPictStart);
+
+ vfObjDisplaying = FALSE;
+ FreezeHp();
+ pedl = &(**(pwwd->hdndl))[dl];
+
+ if (cpRet == cp0)
+ goto DontDraw;
+ }
+ }
+ break;
+#endif
+ default:
+ dxpOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.xExt,
+ GetDeviceCaps( hDC, HORZRES ),
+ GetDeviceCaps( hDC, HORZSIZE ) );
+ dypOrig = PxlConvert( picInfo.mfp.mm, picInfo.mfp.yExt,
+ GetDeviceCaps( hDC, VERTRES ),
+ GetDeviceCaps( hDC, VERTSIZE ) );
+ if (! (dxpOrig && dypOrig) )
+ {
+ goto DontDraw;
+ }
+ break;
+ }
+
+ /* Save DC as a guard against DC attribute alteration by a metafile */
+#ifdef WINDOWS_BUG_FIXED /* Currently 0 is a valid level for Own DC's */
+ if ((ilevel=SaveDC( hDC )) == 0)
+ goto DontDraw;
+#endif
+ ilevel = SaveDC( hDC );
+ SetStretchBltMode( hDC, BLACKONWHITE );
+
+ /* Clip out top bar, selection bar */
+
+ IntersectClipRect( hDC, ((wwCur == wwClipboard) ? 0 : xpSelBar),
+ pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
+
+ if (!vfWholePictInvalid)
+ /* Repainting less than the whole picture; clip out
+ what we're not drawing */
+ IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top,
+ rcPictInvalid.right, rcPictInvalid.bottom );
+
+ /* Build rcEnclose, a rect enclosing the picture that
+ includes the "space before" and "space after" fields */
+
+ rcEnclose.left = xpSelBar;
+ if ((rcEnclose.top = rcPict.top -
+ DypFromDya( vpapAbs.dyaBefore, FALSE )) < pwwd->ypMin)
+ rcEnclose.top = pwwd->ypMin;
+ rcEnclose.right = pwwd->xpMac;
+ if ((rcEnclose.bottom = rcPict.bottom +
+ DypFromDya( vpapAbs.dyaAfter, FALSE )) > pwwd->ypMac)
+ rcEnclose.bottom = pwwd->ypMac;
+
+ /* White out enclosing rect */
+
+ PatBlt( hDC, rcEnclose.left, rcEnclose.top,
+ rcEnclose.right - rcEnclose.left,
+ rcEnclose.bottom - rcEnclose.top, ropErase );
+
+ /* If we have it cached, do display the easy way */
+
+ if (pwwd->doc == vdocBitmapCache && cpPictStart == vcpBitmapCache)
+ {
+ Assert( pwwd->doc != docNil && vhbmBitmapCache != NULL);
+
+ if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) &&
+ SelectObject( hMDC, vhbmBitmapCache ))
+ {
+ Diag(CommSz("DisplayGraphics: BitBlt\n\r"));
+ BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay, dypDisplay,
+ hMDC, 0, 0, vfMonochrome && vfBMBitmapCache ?
+ ropMonoBm : SRCCOPY );
+ fDrew = TRUE;
+ goto DontDraw;
+ }
+ else
+ { /* Using the cache failed -- empty it
+ (SelectObject will fail if bitmap was discarded) */
+ FreeBitmapCache();
+ }
+ }
+
+ StartLongOp(); /* Put up an hourglass */
+
+ /* Build up all bytes associated with the picture (except the header)
+ into the global Windows handle hBits */
+
+ if ( picInfo.mfp.mm != MM_OLE)
+ {
+ if ((hBits=GlobalAlloc( GMEM_MOVEABLE, (long)picInfo.cbSize )) == NULL)
+ { /* Not enough global heap space to load bitmap/metafile */
+ goto DontDraw;
+ }
+
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch,"DisplayGraphics: picinfo.cbSize %lu \n\r", picInfo.cbSize);
+ CommSz(rgch);
+ }
+#endif
+
+ for ( cbPict = 0, cp = cpPictStart + picInfo.cbHeader;
+ cbPict < picInfo.cbSize;
+ cbPict += cchRun, cp += (typeCP) cchRun )
+ {
+ CHAR rgch[ 256 ];
+#if WINVER >= 0x300
+ HPCH lpch;
+#else
+ LPCH lpch;
+#endif
+
+#define ulmin(a,b) ((unsigned long)(a) < (unsigned long)(b) ? \
+ (unsigned long)(a) : (unsigned long)(b))
+
+ FetchRgch( &cchRun, rgch, vfli.doc, cp, cpMac,
+ (int) ulmin( picInfo.cbSize - cbPict, 256 ) );
+ if ((lpch=GlobalLock( hBits )) != NULL)
+ {
+#ifdef DCLIP
+ {
+ char rgch[200];
+ wsprintf(rgch," copying %d bytes from %lX to %lX \n\r",cchRun,(LPSTR)rgch,lpch+cbPict);
+ CommSz(rgch);
+ }
+
+ {
+ char rgchT[200];
+ int i;
+ for (i = 0; i< min(20,cchRun); i++,i++)
+ {
+ wsprintf(rgchT,"%X ",* (int *) &(rgch[i]));
+ CommSz(rgchT);
+ }
+ CommSz("\n\r");
+ }
+#endif
+#if WINVER >= 0x300
+ bltbh( (LPSTR)rgch, lpch+cbPict, cchRun );
+#else
+ bltbx( (LPSTR)rgch, lpch+cbPict, cchRun );
+#endif
+ GlobalUnlock( hBits );
+ }
+ else
+ {
+ goto DontDraw;
+ }
+ }
+ }
+
+
+ /* Display the picture */
+
+ MeltHp();
+
+#if defined(OLE)
+ /* CASE 0: OLE */
+ if (picInfo.mfp.mm == MM_OLE)
+ {
+ Diag(CommSz("Case 0:\n\r"));
+ if (ObjDisplayObjectInDoc(&picInfo, vfli.doc, cpPictStart,
+ hDC, &rcPict) == FALSE)
+ goto DontDraw;
+ fDrew = true;
+ }
+ else
+#endif
+ /* CASE 1: Bitmap */
+ if (fBitmap = (picInfo.mfp.mm == MM_BITMAP))
+ {
+ Diag(CommSz("Case 1: \n\r"));
+ if ( ((hMDC = CreateCompatibleDC( hDC )) != NULL) &&
+ ((picInfo.bm.bmBits = GlobalLock( hBits )) != NULL) &&
+ ((hbm=CreateBitmapIndirect((LPBITMAP)&picInfo.bm))!=NULL))
+ {
+ picInfo.bm.bmBits = NULL;
+ GlobalUnlock( hBits );
+ GlobalFree( hBits ); /* Free handle to bits to allow max room */
+ hBits = NULL;
+ SelectObject( hMDC, hbm );
+
+ goto CacheIt;
+ }
+ }
+
+ /* Case 2: non-scalable metafile pictures which we are, for
+ user interface consistency, scaling by force using StretchBlt */
+
+ else if ( ((dxpDisplay != dxpOrig) || (dypDisplay != dypOrig)) &&
+ (picInfo.mfp.mm != MM_ISOTROPIC) &&
+ (picInfo.mfp.mm != MM_ANISOTROPIC) )
+ {
+
+ Diag(CommSz("Case 2: \n\r"));
+ if (((hMDC=CreateCompatibleDC( hDC)) != NULL) &&
+ ((hbm=CreateCompatibleBitmap( hDC, dxpOrig, dypOrig ))!=NULL) &&
+ SelectObject( hMDC, hbm ) && SelectObject( hMDC, hbrBkgrnd ))
+ {
+ extern int vfOutOfMemory;
+
+ PatBlt( hMDC, 0, 0, dxpOrig, dypOrig, ropErase );
+ SetMapMode( hMDC, picInfo.mfp.mm );
+ /* To cover StretchBlt calls within the metafile */
+ SetStretchBltMode( hMDC, BLACKONWHITE );
+ PlayMetaFile( hMDC, hBits );
+ /* Because we pass pixels to StretchBlt */
+ SetMapMode( hMDC, MM_TEXT );
+
+CacheIt: Assert( hbm != NULL && hMDC != NULL );
+
+ if (vfOutOfMemory)
+ goto NoCache;
+#ifndef NOCACHE
+ FreeBitmapCache();
+ /* Among other things, this code caches the current picture.
+ Notice that there are two assumptions: (1) all bitmaps are
+ monochrome, and (2) a newly created memory DC has a monochrome
+ bitmap selected in. */
+ if ( ((hMDCCache = CreateCompatibleDC( hDC )) != NULL) &&
+ ((vhbmBitmapCache = CreateDiscardableBitmap(
+ fBitmap ? hMDCCache : hDC, dxpDisplay, dypDisplay )) !=
+ NULL) &&
+ SelectObject( hMDCCache, vhbmBitmapCache ))
+ {
+ if (!StretchBlt( hMDCCache, 0, 0, dxpDisplay,
+ dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, SRCCOPY ))
+ { /* may get here if memory is low */
+ DeleteDC( hMDCCache );
+ hMDCCache = NULL;
+ DeleteObject( vhbmBitmapCache );
+ vhbmBitmapCache = NULL;
+ goto NoCache;
+ }
+
+#ifdef DCLIP
+ if (vfMonochrome && fBitmap)
+ CommSzNum("BitBlt using ropMonoBm == ",ropMonoBm);
+#endif
+
+ BitBlt( hDC, rcPict.left, rcPict.top, dxpDisplay,
+ dypDisplay, hMDCCache, 0, 0, vfMonochrome && fBitmap ?
+ ropMonoBm : SRCCOPY );
+
+ /* Cached bitmap OK, make cache valid */
+ vdocBitmapCache = pwwd->doc;
+ vcpBitmapCache = cpPictStart;
+ vfBMBitmapCache = fBitmap;
+ }
+ else
+#endif /* ndef NOCACHE */
+ {
+NoCache:
+ StretchBlt( hDC, rcPict.left, rcPict.top,
+ dxpDisplay, dypDisplay,
+ hMDC, 0, 0, dxpOrig, dypOrig, vfMonochrome &&
+ fBitmap ? ropMonoBm : SRCCOPY );
+ }
+ fDrew = TRUE;
+ }
+ }
+
+ /* Case 3: A metafile picture which can be directly scaled
+ or does not need to be because its size has not changed */
+ else
+ {
+ fDrew = true;
+ Diag(CommSz("Case 3:\n\r"));
+ SetMapMode( hDC, picInfo.mfp.mm );
+
+ SetViewportOrg( hDC, rcPict.left, rcPict.top );
+ switch( picInfo.mfp.mm ) {
+ case MM_ISOTROPIC:
+ if (picInfo.mfp.xExt && picInfo.mfp.yExt)
+ /* So we get the correct shape rectangle when
+ SetViewportExt gets called */
+ SetWindowExt( hDC, picInfo.mfp.xExt, picInfo.mfp.yExt );
+ /* FALL THROUGH */
+ case MM_ANISOTROPIC:
+ /** (9.17.91) v-dougk
+ Set the window extent in case the metafile is bad
+ and doesn't call it itself. This will prevent
+ possible gpfaults in GDI
+ **/
+ SetWindowExt( hDC, dxpDisplay, dypDisplay );
+
+ SetViewportExt( hDC, dxpDisplay, dypDisplay );
+ break;
+ }
+
+ PlayMetaFile( hDC, hBits );
+ }
+DontDraw:
+
+ /* Clean up */
+ if ( *(pLocalHeap+1) )
+ MeltHp();
+
+ if (ilevel > 0)
+ RestoreDC( hDC, ilevel );
+ if (hMDCCache != NULL)
+ DeleteDC( hMDCCache );
+ if (hMDC != NULL)
+ DeleteDC( hMDC );
+ if (hbm != NULL)
+ DeleteObject( hbm );
+ if (hBits != NULL)
+ {
+ if (fBitmap && picInfo.bm.bmBits != NULL)
+ GlobalUnlock( hBits );
+ GlobalFree( hBits );
+ }
+
+ if (!fDrew)
+ {
+ void DrawBlank(HDC hDC, RECT FAR *rc);
+ DrawBlank(hDC,&rcPict);
+ }
+
+ /* Invert the selection */
+ if (ww == wwDocument && !vfSelHidden && !vfPMS)
+ {
+ extern int vypCursLine;
+
+ ilevel = SaveDC( hDC ); /* Because of clip calls below */
+
+ if (!vfWholePictInvalid)
+ /* Repainting less than the whole picture; clip out
+ what we're not drawing */
+ IntersectClipRect( hDC, rcPictInvalid.left, rcPictInvalid.top,
+ rcPictInvalid.right, rcPictInvalid.bottom );
+
+ /* Clip out top bar, selection bar */
+
+ IntersectClipRect( hDC, xpSelBar,
+ pwwdCur->ypMin, pwwdCur->xpMac, pwwdCur->ypMac );
+
+ if (selCur.cpLim > cpPictStart && selCur.cpFirst <= cpPictStart)
+ { /* Take into account 'space before' field */
+ rcEnclose.left = rcPict.left;
+ rcEnclose.right = rcPict.right;
+ InvertRect( hDC, (LPRECT) &rcEnclose );
+ }
+ else if ((selCur.cpLim == selCur.cpFirst) &&
+ (selCur.cpFirst == cpPictStart) &&
+ (vfWholePictInvalid || rcPictInvalid.top < vypCursLine))
+ { /* We erased the insert point */
+ vfInsertOn = fFalse;
+ }
+ RestoreDC( hDC, ilevel );
+ }
+
+ vfWholePictInvalid = TRUE; /* Next picture, start invalidation anew */
+ {
+ extern int vfPMS;
+ extern HCURSOR vhcPMS;
+
+
+ EndLongOp( vfPMS ? vhcPMS : vhcIBeam );
+ }
+}
+
+
+#ifdef ENABLE /* Don't use this anymore */
+int
+FPointInPict(pt)
+POINT pt;
+{ /* Return true if point is within the picture frame */
+struct EDL *pedl;
+struct PICINFOX picInfo;
+RECT rcPict;
+
+GetPicInfo(selCur.cpFirst, cpMacCur, docCur, &picInfo);
+
+if (!FGetPictPedl(&pedl))
+ return false;
+
+ComputePictRect( &rcPict, &picInfo, pedl, wwCur );
+
+return PtInRect( (LPRECT)&rcPict, pt );
+}
+#endif /* ENABLE */
+
+
+/* C O M P U T E P I C T R E C T */
+ComputePictRect( prc, ppicInfo, pedl, ww )
+RECT *prc;
+register struct PICINFOX *ppicInfo;
+struct EDL *pedl;
+int ww;
+{ /* Compute rect containing picture indicated by passed ppicInfo,
+ pedl, in the indicated ww. Return the computed rect through
+ prc. picInfo structure is not altered. */
+
+ int dypTop, xaLeft;
+ struct WWD *pwwd = &rgwwd[ww];
+ int xaStart;
+ int dxaText, dxa;
+ int dxpSize, dypSize;
+ int dxaSize, dyaSize;
+
+ CacheSectPic(pwwd->doc, pedl->cpMin);
+
+ if (ppicInfo->mfp.mm == MM_BITMAP && ((ppicInfo->dxaSize == 0) ||
+ (ppicInfo->dyaSize == 0)))
+ {
+ GetBitmapSize( &dxpSize, &dypSize, ppicInfo, FALSE );
+ dxaSize = DxaFromDxp( dxpSize, FALSE );
+ dyaSize = DyaFromDyp( dypSize, FALSE );
+ }
+#if defined(OLE)
+ else if (ppicInfo->mfp.mm == MM_OLE)
+ {
+ dxpSize = DxpFromDxa(ppicInfo->dxaSize, FALSE );
+ dypSize = DypFromDya(ppicInfo->dyaSize, FALSE );
+ dxpSize = MultDiv( dxpSize, ppicInfo->mx, mxMultByOne );
+ dypSize = MultDiv( dypSize, ppicInfo->my, myMultByOne );
+ dxaSize = DxaFromDxp( dxpSize, FALSE );
+ dyaSize = DyaFromDyp( dypSize, FALSE );
+ }
+#endif
+ else
+ {
+
+ dxpSize = DxpFromDxa( dxaSize = ppicInfo->dxaSize, FALSE );
+ dypSize = DypFromDya( dyaSize = ppicInfo->dyaSize, FALSE );
+ }
+
+ dypTop = pedl->dcpMac != 0 ?
+ /* Last line of picture */
+ DypFromDya( dyaSize + vpapAbs.dyaAfter, FALSE ) :
+ (pedl->ichCpMin + 1) * dypPicSizeMin;
+ dypTop = pedl->yp - dypTop;
+
+ xaStart = DxaFromDxp( xpSelBar - (int) pwwd->xpMin, FALSE );
+ dxaText = vsepAbs.dxaText;
+ switch (vpapAbs.jc)
+ {
+ case jcBoth:
+ case jcLeft:
+ dxa = ppicInfo->dxaOffset;
+ break;
+ case jcCenter:
+ dxa = (dxaText - (int)vpapAbs.dxaRight + (int)vpapAbs.dxaLeft -
+ dxaSize) / 2;
+ break;
+ case jcRight:
+ dxa = dxaText - (int)vpapAbs.dxaRight - dxaSize;
+ break;
+ }
+
+ xaLeft = xaStart + max( (int)vpapAbs.dxaLeft, dxa );
+
+ prc->right = (prc->left = DxpFromDxa( xaLeft, FALSE )) + dxpSize;
+ prc->bottom = (prc->top = dypTop) + dypSize;
+}
+
+FGetPictPedl(ppedl)
+struct EDL **ppedl;
+{
+int dlLim = pwwdCur->dlMac;
+int dl;
+typeCP cpFirst = selCur.cpFirst;
+struct EDL *pedl;
+
+//Assert(vfPictSel);
+
+if (!vfPictSel)
+ return FALSE;
+
+pedl = &(**(pwwdCur->hdndl)[0]);
+
+for (dl = 0; dl < dlLim; ++dl, ++pedl)
+ {
+ //if (!pedl->fValid)
+ //return false;
+
+ if (pedl->cpMin == cpFirst)
+ break;
+ }
+if (dl >= dlLim)
+ return false; /* No part of picture is on screen */
+
+*ppedl = pedl;
+return true;
+}
+
+
+
+
+/* C P W I N G R A P H I C */
+typeCP CpWinGraphic(pwwd)
+struct WWD *pwwd;
+ {
+ int cdlPict, dl;
+ struct EDL *dndl = &(**(pwwd->hdndl))[0];
+
+ Assert( !pwwd->fDirty ); /* So we can rely on dl info */
+ CachePara(pwwd->doc, dndl->cpMin);
+ for (dl = 0; (dl < pwwd->dlMac - 1 && dndl[dl].fIchCpIncr); ++dl)
+ ;
+ Assert(dndl[dl].fGraphics);
+ cdlPict = dndl[dl].ichCpMin + 1;
+ return (dndl[0].cpMin +
+ (vcpLimParaCache - vcpFirstParaCache) * dndl[0].ichCpMin / cdlPict);
+ }
+
+
+
+
+CacheSectPic(doc, cp)
+int doc;
+typeCP cp;
+{ /* Cache section and para props, taking into account that footnotes take props
+ from the reference point */
+#ifdef FOOTNOTES
+struct DOD *pdod = &(**hpdocdod)[doc];
+struct FNTB (**hfntb) = pdod->hfntb;
+#endif
+
+CachePara(doc, cp);
+
+#ifdef FOOTNOTES
+if ( (hfntb != 0) && (cp >= (**hfntb).rgfnd[0].cpFtn) )
+ CacheSect( doc, CpRefFromFtn( doc, cp ) )
+else
+#endif
+ CacheSect(doc, cp); /* Normal text */
+}
+
+
+void DrawBlank(HDC hDC, RECT FAR *rc)
+{ /* To tell us when the draw tried but failed */
+ int xpMid=rc->left + (rc->right-rc->left)/2;
+ int ypMid=rc->top + (rc->bottom - rc->top)/2;
+ int dxpQ=(rc->right-rc->left)/4;
+ int dypQ=(rc->bottom-rc->top)/4;
+ HPEN hOldPen;
+ HBRUSH hOldBrush;
+
+ hOldPen = SelectObject( hDC, GetStockObject( BLACK_PEN ) );
+ hOldBrush = SelectObject( hDC, GetStockObject( WHITE_BRUSH ) );
+ Rectangle(hDC,rc->left,rc->top,rc->right,rc->bottom);
+ MoveTo( hDC, rc->left, rc->top );
+ LineTo( hDC, rc->right, rc->bottom );
+ MoveTo( hDC, rc->left, rc->bottom );
+ LineTo( hDC, rc->right, rc->top );
+ MoveTo( hDC, xpMid, rc->top );
+ LineTo( hDC, xpMid, rc->bottom );
+ MoveTo( hDC, rc->left, ypMid );
+ LineTo( hDC, rc->right, ypMid );
+ Ellipse( hDC,
+ xpMid-dxpQ, ypMid-dypQ,
+ xpMid+dxpQ, ypMid+dypQ );
+ SelectObject( hDC, hOldPen );
+ SelectObject( hDC, hOldBrush );
+}
+
diff --git a/private/mvdm/wow16/write/picture2.c b/private/mvdm/wow16/write/picture2.c
new file mode 100644
index 000000000..7a8495b32
--- /dev/null
+++ b/private/mvdm/wow16/write/picture2.c
@@ -0,0 +1,549 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* picture2.c -- MW format and display routines for pictures */
+
+//#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+//#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOFONT
+#define NOMB
+#define NOMENUS
+#define NOOPENFILE
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "fmtdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "stcdefs.h"
+#include "wwdefs.h"
+#include "filedefs.h"
+#include "editdefs.h"
+/* #include "str.h" */
+#include "prmdefs.h"
+/* #include "fkpdefs.h" */
+/* #include "macro.h" */
+#include "winddefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+extern typeCP cpMacCur;
+extern int docCur;
+extern int vfSelHidden;
+extern struct WWD rgwwd[];
+extern int wwCur;
+extern int wwMac;
+extern struct FLI vfli;
+extern struct SEL selCur;
+extern struct WWD *pwwdCur;
+extern struct PAP vpapCache;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern int vfPictSel;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEP vsepPage;
+extern struct DOD (**hpdocdod)[];
+extern unsigned cwHeapFree;
+extern int vfInsertOn;
+extern int vfPMS;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxaPrPage;
+extern int dyaPrPage;
+extern int dxpPrPage;
+extern int dypPrPage;
+extern HBRUSH hbrBkgrnd;
+extern long ropErase;
+extern int vdocBitmapCache;
+extern typeCP vcpBitmapCache;
+extern HBITMAP vhbmBitmapCache;
+extern HCURSOR vhcIBeam;
+
+
+/* Used in this module only */
+#ifdef DEBUG
+#define STATIC static
+#else
+#define STATIC
+#endif
+
+
+/* (windows naming convention for func name, not Hung.) */
+
+long GetBitmapMultipliers( hDC, dxpOrig, dypOrig, dxmmIdeal, dymmIdeal )
+HDC hDC;
+int dxpOrig, dypOrig;
+int dxmmIdeal, dymmIdeal;
+{ /* Return the "best" integer bit-multiples to use when displaying a bitmap
+ of size { dxpOrig, dypOrig } (in pixels) on device DC hDC.
+ The "ideal size" of the bitmap is { dxmmIdeal, dymmIdeal } (in 0.1mm units);
+ this conveys the desired aspect ratio as well.
+ Returns the y-multiplier in the hi word, the x-multiplier in the lo word.
+ Default/error value returned is { 1, 1 }. */
+
+ typedef unsigned long ul;
+
+ long lT;
+ int cx, cy;
+ int cxBest, cyBest;
+ int dcx=1, dcy=1;
+ int dxpT, dypT;
+ int dxmmOrig, dymmOrig;
+ int dxmmDevice = GetDeviceCaps( hDC, HORZSIZE ) * 10;
+ int dymmDevice = GetDeviceCaps( hDC, VERTSIZE ) * 10;
+ int dxpDevice = GetDeviceCaps( hDC, HORZRES );
+ int dypDevice = GetDeviceCaps( hDC, VERTRES );
+ int cxMac, cyMac;
+ int pctAspectBest, pctSizeBest;
+
+ /* Compute scale factor (dcx, dcy, our minimum scale multiple) */
+
+ if (GetDeviceCaps( hDC, RASTERCAPS ) & RC_SCALING)
+ {
+ POINT pt;
+
+ pt.x = pt.y = 0; /* Just in case */
+ Escape( hDC, GETSCALINGFACTOR, 0, (LPSTR) NULL, (LPSTR) (LPPOINT) &pt );
+ dcx = 1 << pt.x;
+ dcy = 1 << pt.y;
+ }
+
+ /* Compute size of unscaled picture on hDC in 0.1 mm units */
+
+ if (dxpDevice <= 0 || dypDevice <= 0)
+ goto Error;
+
+ dxmmOrig = MultDiv( dxpOrig, dxmmDevice, dxpDevice );
+ dymmOrig = MultDiv( dypOrig, dymmDevice, dypDevice );
+
+ /* Ideal size not supplied; return 1,1 (times device multipliers) */
+
+ if (dxmmIdeal <= 0 || dymmIdeal <= 0)
+ {
+ goto Error;
+ }
+
+ /* Compute absolute maximums for cx, cy */
+ /* 2nd term of min restricts search space by refusing to consider
+ more tham one size above the ideal */
+
+ if (dxmmOrig <= 0 || dymmOrig <= 0)
+ goto Error;
+
+ cxMac = min ( (dxmmDevice / dxmmOrig) + 1, (dxmmIdeal / dxmmOrig) + 2 );
+ cyMac = min ( (dymmDevice / dymmOrig) + 1, (dymmIdeal / dymmOrig) + 2 );
+
+ /* Search all possible multiplies to see what would be best */
+
+ cxBest = dcx;
+ cyBest = dcy;
+ pctAspectBest = pctSizeBest = 32767;
+
+ for ( cx = dcx ; cx < cxMac; cx += dcx )
+ for ( cy = dcy ; cy < cyMac; cy += dcy )
+ {
+ int dxmm = dxmmOrig * cx;
+ int dymm = dymmOrig * cy;
+ int pctAspect = PctDiffUl( (ul) dxmmIdeal * (ul) dymm,
+ (ul) dymmIdeal * (ul) dxmm );
+ int pctSize = PctDiffUl( (ul) dxmmIdeal * (ul) dymmIdeal,
+ (ul)dxmm * (ul)dymm );
+
+ /* ??? Strategy for loss on one, gain on the other ??? */
+
+ if (pctAspect <= pctAspectBest && pctSize <= pctSizeBest )
+ {
+ cxBest = cx;
+ cyBest = cy;
+ pctAspectBest = pctAspect;
+ pctSizeBest = pctSize;
+ }
+ }
+
+ Assert( cxBest > 0 && cyBest > 0 );
+
+ return MAKELONG( cxBest, cyBest );
+
+Error:
+ return MAKELONG( dcx, dcy );
+}
+
+
+
+int PctDiffUl( ul1, ul2 )
+unsigned long ul1, ul2;
+{ /* Return a number that is proportional to the percentage
+ of difference between the two numbers */
+ /* Will not work for > 0x7fffffff */
+
+#define dulMaxPrec 1000 /* # of "grains" of response possible */
+
+unsigned long ulAvg = (ul1 >> 1) + (ul2 >> 1);
+unsigned long ulDiff = (ul1 > ul2) ? ul1 - ul2 : ul2 - ul1;
+
+if (ulAvg == 0)
+ return (ul1 == ul2) ? 0 : dulMaxPrec;
+
+if (ulDiff > 0xFFFFFFFF / dulMaxPrec)
+ return dulMaxPrec;
+
+return (int) ((ulDiff * dulMaxPrec) / ulAvg);
+}
+
+
+int PxlConvert( mm, val, pxlDeviceRes, milDeviceRes )
+int mm;
+int val;
+int pxlDeviceRes;
+int milDeviceRes;
+{ /* Return the # of pixels spanned by val, a measurement in coordinates
+ appropriate to mapping mode mm. pxlDeviceRes gives the resolution
+ of the device in pixels, along the axis of val. milDeviceRes gives
+ the same resolution measurement, but in millimeters.
+ returns 0 on error */
+ typedef unsigned long ul;
+
+ ul ulMaxInt = 32767L; /* Should be a constant, but as of 7/12/85,
+ CMERGE generates incorrect code for the
+ ul division if we use a constant */
+ ul ulPxl;
+ ul ulDenom;
+ unsigned wMult=1;
+ unsigned wDiv=1;
+
+
+ if (milDeviceRes == 0)
+ { /* to make sure we don't get divide-by-0 */
+ return 0;
+ }
+
+ switch ( mm ) {
+ case MM_LOMETRIC:
+ wDiv = 10;
+ break;
+ case MM_HIMETRIC:
+ wDiv = 100;
+ break;
+ case MM_TWIPS:
+ wMult = 25;
+ wDiv = 1440;
+ break;
+ case MM_LOENGLISH:
+ wMult = 25;
+ wDiv = 100;
+ break;
+ case MM_HIENGLISH:
+ wMult = 25;
+ wDiv = 1000;
+ break;
+ case MM_BITMAP:
+ case MM_OLE:
+ case MM_TEXT:
+ return val;
+ default:
+ Assert( FALSE ); /* Bad mapping mode */
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ /* These picture types have no original size */
+ return 0;
+ }
+
+/* Add Denominator - 1 to Numerator, to avoid rounding down */
+
+ ulDenom = (ul) wDiv * (ul) milDeviceRes;
+ ulPxl = ((ul) ((ul) wMult * (ul) val * (ul) pxlDeviceRes) + ulDenom - 1) /
+ ulDenom;
+
+ return (ulPxl > ulMaxInt) ? 0 : (int) ulPxl;
+}
+
+
+
+
+/* F O R M A T G R A P H I C S */
+FormatGraphics(doc, cp, ichCp, cpMac, flm)
+int doc;
+typeCP cp;
+int ichCp;
+typeCP cpMac;
+int flm;
+{ /* Format a line of graphics */
+ CHAR rgch[10];
+ int cch;
+ int dypSize;
+ int dxpSize;
+ int dxaText;
+ int dxa;
+ struct PICINFOX picInfo;
+ int fPrinting = flm & flmPrinting;
+
+ GetPicInfo(cp, cpMac, doc, &picInfo);
+
+ /* Compute the size of the pict in device pixels */
+
+ if (picInfo.mfp.mm == MM_BITMAP && ((picInfo.dxaSize == 0) ||
+ (picInfo.dyaSize == 0)))
+ {
+ GetBitmapSize( &dxpSize, &dypSize, &picInfo, fPrinting);
+ }
+#if defined(OLE)
+ else if (picInfo.mfp.mm == MM_OLE)
+ {
+ dxpSize = DxpFromDxa( picInfo.dxaSize, fPrinting );
+ dypSize = DypFromDya( picInfo.dyaSize, fPrinting );
+ dxpSize = MultDiv( dxpSize, picInfo.mx, mxMultByOne );
+ dypSize = MultDiv( dypSize, picInfo.my, myMultByOne );
+ }
+#endif
+ else
+ {
+ dxpSize = DxpFromDxa( picInfo.dxaSize, fPrinting );
+ dypSize = DypFromDya( picInfo.dyaSize, fPrinting );
+ }
+
+ if (fPrinting)
+ {
+ /* If we are printing, then the picture consists of a single
+ band. */
+ vfli.cpMac = vcpLimParaCache;
+ vfli.ichCpMac = 0;
+ vfli.dypLine = dypSize;
+ }
+ else if ((ichCp + 2) * dypPicSizeMin > dypSize)
+ {
+ /* Last band of picture. NOTE: last band is always WIDER than
+ dypPicSizeMin */
+ vfli.cpMac = vcpLimParaCache;
+ vfli.ichCpMac = 0;
+
+#ifdef CASHMERE
+ vfli.dypLine = dypSize - max(0, dypSize / dypPicSizeMin - 1) *
+ dypPicSizeMin + DypFromDya( vpapAbs.dyaAfter, FALSE );
+#else /* not CASHMERE */
+ vfli.dypLine = dypSize - max(0, dypSize / dypPicSizeMin - 1) *
+ dypPicSizeMin;
+#endif /* not CASHMERE */
+
+ }
+ else
+ {
+ vfli.ichCpMac = vfli.ichCpMin + 1;
+ vfli.cpMac = vfli.cpMin;
+ vfli.dypLine = dypPicSizeMin;
+ }
+
+#ifdef CASHMERE
+ if (ichCp == 0) /* Add in the 'space before' field. */
+ {
+ vfli.dypLine += DypFromDya( vpapAbs.dyaBefore, fPrinting );
+ }
+#endif /* CASHMERE */
+
+ vfli.dypFont = vfli.dypLine;
+
+ dxaText = vsepAbs.dxaText;
+
+ switch (vpapAbs.jc)
+ {
+ case jcLeft:
+ case jcBoth:
+ dxa = picInfo.dxaOffset;
+ break;
+ case jcCenter:
+ dxa = (dxaText - (int)vpapAbs.dxaRight + (int)vpapAbs.dxaLeft -
+ DxaFromDxp( dxpSize, fPrinting )) >> 1;
+ break;
+ case jcRight:
+ dxa = dxaText - (int)vpapAbs.dxaRight -
+ DxaFromDxp( dxpSize, fPrinting );
+ break;
+ }
+
+ vfli.xpLeft = DxpFromDxa( max( (int)vpapAbs.dxaLeft, dxa ), fPrinting );
+#ifdef BOGUSBL
+ vfli.xpReal = imin( dxpSize + vfli.xpLeft,
+ DxpFromDxa( dxaText - vpapAbs.dxaRight, fPrinting );
+#else /* Don't crunch the picture to fit the margins */
+ vfli.xpReal = dxpSize + vfli.xpLeft;
+#endif
+ vfli.fGraphics = true;
+}
+
+GetPicInfo(cp, cpMac, doc, ppicInfo)
+typeCP cp, cpMac;
+int doc;
+struct PICINFOX *ppicInfo;
+{ /* Fetch the header structure for a picture at cp into *ppicInfo.
+ Supports the OLD file format (which used cbOldSize); always returns
+ the NEW PICINFO structure. */
+int cch;
+
+FetchRgch(&cch, ppicInfo, doc, cp, cpMac, cchPICINFOX);
+
+if (ppicInfo->mfp.mm & MM_EXTENDED)
+ {
+ ppicInfo->mfp.mm &= ~MM_EXTENDED;
+ }
+ else
+ { /* Old file format -- fill out extended fields */
+ ppicInfo->cbSize = ppicInfo->cbOldSize;
+ ppicInfo->cbHeader = cchOldPICINFO;
+ }
+
+ /* Fill in defaults for extended fields that are not present in the file */
+ /* These are: mx, my Added 9/19/85 by bryanl */
+
+ if (BStructMember( PICINFOX, my ) >= ppicInfo->cbHeader )
+ { /* Scaling multipliers not present */
+ ppicInfo->mx = mxMultByOne;
+ ppicInfo->my = myMultByOne;
+ }
+
+ if (ppicInfo->dyaSize < 0)
+ /* 3.1 beta III bug, wrote negative height values */
+{
+ ppicInfo->dyaSize = -ppicInfo->dyaSize;
+#ifdef DEBUG
+ OutputDebugString("Negative object height found!\n\r");
+#endif
+}
+}
+
+
+
+
+GetBitmapSize( pdxp, pdyp, ppicInfo, fPrinting )
+int *pdxp, *pdyp;
+struct PICINFOX *ppicInfo;
+int fPrinting;
+{ /* Compute the appropriate display or printing (depending on fPrinting)
+ size of the bitmap described by the passed PICINFOX structure.
+ The interesting fields are:
+
+ ppicInfo->bm.bmWidth, bmHeight Bitmap size in pixels
+ ppicInfo->mfp.xExt, yExt Desired size in 0.1 mm
+ Return the results through *pdxp, *pdyp. */
+
+ long GetBitmapMultipliers();
+ extern HDC vhDCPrinter;
+ extern int dxaPrPage, dxpPrPage, dyaPrPage, dypPrPage;
+
+ long lT;
+ int cx, cy;
+ int dxpT, dypT;
+ int dxpOrig = ppicInfo->bm.bmWidth;
+ int dypOrig = ppicInfo->bm.bmHeight;
+ int dxmmIdeal = ppicInfo->mfp.xExt;
+ int dymmIdeal = ppicInfo->mfp.yExt;
+ Assert(vhDCPrinter);
+
+ /* Scale for printer */
+
+ lT = GetBitmapMultipliers( vhDCPrinter, dxpOrig, dypOrig, dxmmIdeal, dymmIdeal );
+ cx = LOWORD( lT );
+ cy = HIWORD( lT );
+ dxpT = cx * dxpOrig;
+ dypT = cy * dypOrig;
+
+ if (!fPrinting)
+ { /* Re-scale for screen */
+ dxpT = DxpFromDxa( DxaFromDxp( dxpT, TRUE ), FALSE );
+ dypT = DypFromDya( DyaFromDyp( dypT, TRUE ), FALSE );
+ }
+
+ /* apply the user's "ideal multiple" of the computed size */
+
+ dxpT = MultDiv( dxpT, ppicInfo->mx, mxMultByOne );
+ dypT = MultDiv( dypT, ppicInfo->my, myMultByOne );
+
+ *pdxp = dxpT;
+ *pdyp = dypT;
+ return;
+}
+
+
+int DxpFromDxa( dxa, fPrinter )
+int dxa;
+int fPrinter;
+{ /* Given twips for an x-axis measurement, return printer
+ or logical screen pixels */
+ extern int dxpPrPage, dxaPrPage;
+ extern int dxpLogInch;
+
+ if (fPrinter)
+ return MultDiv( dxa, dxpPrPage, dxaPrPage );
+ else
+ return MultDiv( dxa, dxpLogInch, czaInch );
+}
+
+
+
+
+int DxaFromDxp( dxp, fPrinter )
+int dxp;
+int fPrinter;
+{ /* Given printer or logical screen pixels for an x-axis measurement,
+ return twips */
+ extern int dxpPrPage, dxaPrPage;
+ extern int dxpLogInch;
+
+ if (fPrinter)
+ return MultDiv( dxp, dxaPrPage, dxpPrPage );
+ else
+ return MultDiv( dxp, czaInch, dxpLogInch );
+}
+
+
+int DypFromDya( dya, fPrinter )
+int dya;
+int fPrinter;
+{ /* Given twips for a y-axis measurement, return printer or logical screen
+ pixels */
+ extern int dypPrPage, dyaPrPage;
+ extern int dypLogInch;
+
+ if (fPrinter)
+ return MultDiv( dya, dypPrPage, dyaPrPage );
+ else
+ return MultDiv( dya, dypLogInch, czaInch );
+}
+
+int DyaFromDyp( dyp, fPrinter )
+int dyp;
+int fPrinter;
+{ /* Given printer or logical screen pixels for a y-axis measurement,
+ return twips */
+ extern int dypPrPage, dyaPrPage;
+ extern int dypLogInch;
+
+ if (fPrinter)
+ return MultDiv( dyp, dyaPrPage, dypPrPage );
+ else
+ return MultDiv( dyp, czaInch, dypLogInch );
+}
+
diff --git a/private/mvdm/wow16/write/pmscur.cur b/private/mvdm/wow16/write/pmscur.cur
new file mode 100644
index 000000000..fe6845ded
--- /dev/null
+++ b/private/mvdm/wow16/write/pmscur.cur
Binary files differ
diff --git a/private/mvdm/wow16/write/preload.h b/private/mvdm/wow16/write/preload.h
new file mode 100644
index 000000000..031c81552
--- /dev/null
+++ b/private/mvdm/wow16/write/preload.h
@@ -0,0 +1,23 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*----------------TASK ENUMERATED TYPE FOR CODE PRELOAD-----------------*/
+
+#define tskMin 0
+#define tskMax 3
+
+#define tskInsert 0 /* Insert, backspace, cursoring */
+#define tskFormat 1 /* Char dropdown, formatting, fonts */
+#define tskScrap 2 /* Edit dropdown, cut/paste, clipboard */
+
+/*----------------------------------------------------------------------*/
+
+void PreloadCodeTsk( int );
+
+/* Macros for function preloading */
+
+#define LoadWindowsF(f) GetCodeHandle( (FARPROC) f )
+#define LoadF(f) { int f(); GetCodeHandle( (FARPROC) f ); }
+
+#define LCBAVAIL 0x00030D40 /* 200K */
diff --git a/private/mvdm/wow16/write/print.c b/private/mvdm/wow16/write/print.c
new file mode 100644
index 000000000..df2dcdfa3
--- /dev/null
+++ b/private/mvdm/wow16/write/print.c
@@ -0,0 +1,998 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the printing routines. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOFONT
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "printdef.h"
+#include "fmtdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "dlgdefs.h"
+#include "debug.h"
+#include "fontdefs.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifdef INEFFLOCKDOWN
+ extern FARPROC lpDialogCancelPrint;
+ extern FARPROC lpFPrContinue;
+#else
+ extern BOOL far PASCAL DialogCancelPrint(HWND, unsigned, WORD, LONG);
+ extern BOOL far PASCAL FPrContinue(HDC, int);
+ FARPROC lpFPrContinue;
+#endif
+
+BOOL fPrinting;
+
+PrintDoc(doc, fPrint)
+int doc;
+BOOL fPrint;
+ {
+ /* This routine formats the document, doc, for printing and prints it if
+ fPrint is TRUE. */
+
+ BOOL FInitHeaderFooter(BOOL, unsigned *, struct PLD (***)[], int *);
+ BOOL FSetPage(void);
+ BOOL FPromptPgMark(typeCP);
+ BOOL FPrintBand(int, struct PLD (**)[], int, PRECT);
+
+ extern BOOL vbCollate;
+ extern HDC vhDCPrinter;
+ extern HWND hParentWw;
+ extern HANDLE hMmwModInstance;
+ extern struct DOD (**hpdocdod)[];
+ extern int vpgn;
+ extern struct SEP vsepAbs;
+ extern typeCP vcpFirstParaCache;
+ extern typeCP vcpLimParaCache;
+ extern typeCP cpMinCur;
+ extern typeCP cpMinDocument;
+ extern struct FLI vfli;
+ extern int wwCur;
+ extern int docMode;
+ extern int vdocPageCache;
+ extern int dxaPrPage;
+ extern int dyaPrPage;
+ extern int dxpPrPage;
+ extern int dypPrPage;
+ extern int dxaPrOffset;
+ extern int dyaPrOffset;
+ extern CHAR szMode[30];
+ extern int vfRepageConfirm;
+ extern int vfPrPages; /* true if print page range */
+ extern int vpgnBegin; /* starting page number to print */
+ extern int vpgnEnd; /* ending page number to print */
+ extern int vcCopies; /* nubmer of copies to print */
+ extern int vfOutOfMemory;
+ extern BOOL vfPrinterValid;
+ extern BOOL vfPrErr;
+ extern BOOL vfDraftMode;
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+ extern CHAR *vpDlgBuf;
+ extern HWND vhWndCancelPrint;
+ extern HCURSOR vhcArrow;
+ extern HCURSOR vhcIBeam;
+
+ LONG lHolder;
+ int CopyIncr; /* number of copies the printer can print at a time */
+ typeCP cp;
+ typeCP cpMin;
+ typeCP cpMac;
+ int ichCp;
+ struct PGD *ppgd;
+ struct PGTB **hpgtbOld;
+ int cpld;
+ unsigned pgnFirst;
+ unsigned pgnFirstHeader;
+ unsigned pgnFirstFooter;
+ int ypTop;
+ int ypBottom;
+ int xpLeft;
+ struct PLD (**hrgpldHeader)[];
+ struct PLD (**hrgpldFooter)[];
+ int cpldHeader;
+ int cpldFooter;
+ int cCopies,cCollateCopies;
+ BOOL fConfirm = !fPrint && vfRepageConfirm;
+ BOOL fSplat;
+ CHAR stPage[cchMaxIDSTR];
+ struct PDB pdb;
+ int iEscape;
+#ifndef INEFFLOCKDOWN
+ FARPROC lpDialogCancelPrint = MakeProcInstance(DialogCancelPrint, hMmwModInstance);
+ lpFPrContinue = MakeProcInstance(FPrContinue, hMmwModInstance);
+
+ if (!lpDialogCancelPrint || !lpFPrContinue)
+ goto MemoryAbort;
+#endif
+
+ Assert(vhDCPrinter != NULL);
+
+ /* If we are out of memory, we better bail out now. */
+ if (vfOutOfMemory || vhDCPrinter == NULL)
+ {
+ return;
+ }
+
+ /* Disable all other windows. */
+ EnableWindow(hParentWw, FALSE);
+ EnableOtherModeless(FALSE);
+
+ fPrinting = fPrint;
+
+ /* Set some flags associated with printing. */
+ vfPrErr = pdb.fCancel = FALSE;
+
+ /* Set up the print dialog buffer for the repagination or cancellation
+ dialog boxes. */
+ vpDlgBuf = (CHAR *)&pdb;
+
+ if (fConfirm)
+ {
+ /* Reassure the user that we haven't crashed. */
+ StartLongOp();
+ }
+ else
+ {
+ /* Bring up the dialog box telling the user how to cancel printing or
+ repagination. */
+ if ((vhWndCancelPrint = CreateDialog(hMmwModInstance, fPrint ?
+ MAKEINTRESOURCE(dlgCancelPrint) : MAKEINTRESOURCE(dlgCancelRepage),
+ hParentWw, lpDialogCancelPrint)) == NULL)
+ {
+MemoryAbort:
+ /* Inform the user we cannot print because of a memory failure. */
+ Error(IDPMTPRFAIL);
+ vfPrErr = TRUE;
+ goto Abort;
+ }
+
+ /* Immediately halt if the user requests. */
+ if (!(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto Abort;
+ }
+ }
+
+ if (fPrint)
+ {
+ /* Get the latest printer DC, in case it has changed. */
+ FreePrinterDC();
+ GetPrinterDC(TRUE);
+ if (!vfPrinterValid)
+ {
+ goto MemoryAbort;
+ }
+ }
+
+ /* If we are printing or repaginating without confirmation, then
+ immediately halt if the user requests. */
+ if (!fConfirm && !(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto Abort;
+ }
+
+#if defined(OLE)
+ /*
+ Load all OLE objects now because loading them
+ can cause changes in doc layout.
+ */
+ {
+ OBJPICINFO picInfo;
+ typeCP cpStart=cpNil,cpMac= CpMacText(doc);
+ struct SEL selSave = selCur;
+ BOOL bAbort=FALSE,bSetMode=FALSE;
+
+ while (ObjPicEnumInRange(&picInfo,doc,cpMinDocument, cpMac, &cpStart))
+ {
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ {
+ Error(IDPMTCantPrint);
+ bAbort=TRUE;
+ break;
+ }
+
+ if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL)
+ {
+ /* put message in status window */
+ if (!bSetMode)
+ {
+ LoadString(hMmwModInstance, IDSTRLoading, szMode, sizeof(szMode));
+ DrawMode();
+ bSetMode=TRUE;
+ }
+
+ if (ObjLoadObjectInDoc(&picInfo,doc,cpStart) == cp0)
+ {
+ bAbort=TRUE;
+ break;
+ }
+ }
+
+ if (!(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ bAbort=TRUE;
+ break;
+ }
+ }
+ Select(selSave.cpFirst,selCur.cpLim); // reset
+ if (bAbort)
+ {
+ /* Invalidate the mode so will redraw */
+ docMode = docNil;
+ goto Abort;
+ }
+ }
+#endif
+ /* Initialize the array of print line descriptors. */
+ if (FNoHeap(pdb.hrgpld = (struct PLD (**)[])HAllocate((cpld = cpldInit) *
+ cwPLD)))
+ {
+ goto MemoryAbort;
+ }
+
+ /* Get the document properties and set up some local variables. */
+ CacheSect(doc, cpMin = cpMinDocument);
+ cpMac = CpMacText(doc);
+ ypTop = MultDiv(vsepAbs.yaTop - dyaPrOffset, dypPrPage, dyaPrPage);
+ ypBottom = MultDiv(vsepAbs.yaTop + vsepAbs.dyaText - dyaPrOffset, dypPrPage,
+ dyaPrPage);
+ xpLeft = MultDiv(vsepAbs.xaLeft - dxaPrOffset, dxpPrPage, dxaPrPage);
+ vdocPageCache = docNil;
+
+ /* Initialize the page table. */
+ if (FNoHeap(pdb.hpgtb = (struct PGTB **)HAllocate(cwPgtbBase + cpgdChunk *
+ cwPGD)))
+ {
+ /* Not enough memory for page table; time to bail out. */
+ FreeH(pdb.hpgtb);
+ goto MemoryAbort;
+ }
+ (**pdb.hpgtb).cpgdMax = cpgdChunk;
+ (**pdb.hpgtb).cpgd = 1;
+ ppgd = &((**pdb.hpgtb).rgpgd[0]);
+ ppgd->cpMin = cpMin;
+ if ((pgnFirst = vsepAbs.pgnStart) == pgnNil)
+ {
+ pgnFirst = 1;
+ }
+ ppgd->pgn = pgnFirst;
+
+ /* Ensure that szMode says "Page ". */
+ FillStId(stPage, IDSTRChPage, sizeof(stPage));
+ stPage[1] = ChUpper(stPage[1]);
+ stPage[stPage[0] + 1] = ' ';
+ bltbyte(&stPage[1], szMode, ++stPage[0]);
+
+ /* Attatch the new page table to the document. */
+ {
+ register struct DOD *pdod = &(**hpdocdod)[doc];
+
+ hpgtbOld = pdod->hpgtb;
+ pdod->hpgtb = pdb.hpgtb;
+ }
+
+ /* Set cpMinCur to cp0 for the duration of the print. */
+ Assert(cpMinCur == cpMinDocument);
+ cpMinCur = cp0;
+
+ /* If we are printing or repaginating without confirmation, then
+ immediately halt if the user requests. */
+ if (!fConfirm && !(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto ErrorNoAbort;
+ }
+
+ if (fPrint)
+ {
+ CHAR stTitle[cchMaxIDSTR];
+
+ /* Set up the variables that describe the header. */
+ if (!FInitHeaderFooter(TRUE, &pgnFirstHeader, &hrgpldHeader,
+ &cpldHeader))
+ {
+ Error(IDPMTPRFAIL);
+ goto ErrorNoAbort;
+ }
+
+ /* Set up the variables that describe the footer. */
+ if (!FInitHeaderFooter(FALSE, &pgnFirstFooter, &hrgpldFooter,
+ &cpldFooter))
+ {
+ Error(IDPMTPRFAIL);
+ goto ErrorNoAbort;
+ }
+
+ /* Set the name of the function called to query whether the print should
+ be aborted. */
+ Escape(vhDCPrinter, SETABORTPROC, sizeof(FARPROC), (LPSTR)lpFPrContinue,
+ (LPSTR)NULL);
+
+ /* Set the printer into draft mode if necessary. */
+ if (vfDraftMode)
+ {
+ Escape(vhDCPrinter, DRAFTMODE, sizeof(BOOL), (LPSTR)&vfDraftMode,
+ (LPSTR)NULL);
+ }
+
+ /* Inform the spooler that we are about to print. */
+ stTitle[0] = GetWindowText(hParentWw, (LPSTR)&stTitle[1],
+ sizeof(stTitle) - 1) + 1;
+ if ((iEscape = Escape(vhDCPrinter, STARTDOC, stTitle[0],
+ (LPSTR)&stTitle[1], (LPSTR)NULL)) < 0)
+ {
+ErrorSwitch:
+ switch (iEscape)
+ {
+ default:
+ if ((iEscape & SP_NOTREPORTED) == 0)
+ {
+ break;
+ }
+ case SP_ERROR:
+ Error(IDPMTCantPrint);
+ break;
+
+ case SP_APPABORT:
+ case SP_USERABORT:
+ break;
+
+ case SP_OUTOFDISK:
+ Error(IDPMTPrDiskErr);
+ break;
+
+ case SP_OUTOFMEMORY:
+ Error(IDPMTPRFAIL);
+ break;
+ }
+ goto ErrorNoAbort;
+ }
+ }
+#ifdef DPRINT
+CommSzSz("Start doc", "");
+#endif
+
+ /* If we are printing or repaginating without confirmation, then
+ immediately halt if the user requests. */
+ if (!fConfirm && !(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto Error;
+ }
+
+ // vcCopies is how many times to print each page
+ // cCollateCopies is how many times to print the doc
+ if (vbCollate && fPrint)
+ {
+ cCollateCopies = vcCopies;
+ vcCopies = 1;
+ }
+ else
+ cCollateCopies = 1;
+
+ /* And away we go... */
+ while (cCollateCopies--)
+ {
+ cCopies = 0;
+ /*------------------------------------------------*/
+ /* Tell the driver how many copies we want */
+ /*------------------------------------------------*/
+ lHolder = SETCOPYCOUNT;
+ /* Set number of copies the printer can print */
+ CopyIncr = vcCopies;
+ if (Escape(vhDCPrinter, QUERYESCSUPPORT, 2, (LPSTR) &lHolder, NULL))
+ Escape(vhDCPrinter, SETCOPYCOUNT, 2, (LPSTR) &CopyIncr, (LPSTR) &CopyIncr);
+ else
+ CopyIncr = 1;
+
+ do
+ {
+ /* Initalize the counters to the beginning of the document. */
+ cp = cpMin;
+ ichCp = 0;
+ vpgn = pgnFirst;
+
+ /* Step through the document, formatting a page and then printing a
+ page. */
+ while (cp < cpMac)
+ {
+ register struct PLD *ppld;
+ CHAR *pch;
+ int yp = ypTop;
+ BOOL fPageAdj = FALSE;
+
+ /* If only a range of pages are being printed, then stop when the
+ last of the pages are printed. */
+ if (fPrint && vfPrPages && vpgn > vpgnEnd)
+ {
+ goto DocFinished;
+ }
+
+ /* Show the page number we are formatting and printing. */
+ pch = &szMode[stPage[0]];
+ ncvtu(vpgn, &pch);
+ *pch = '\0';
+ DrawMode();
+
+ /* Let's go through the document page by page. */
+ pdb.ipld = 0;
+ while (cp < cpMac)
+ {
+ /* If we are printing or repaginating without confirmation, then
+ immediately halt if the user requests. */
+ if (!fConfirm && !(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto Error;
+ }
+
+ /* We have reached the end of the line descriptors; try to
+ increase its size. */
+ if (pdb.ipld >= cpld && !FChngSizeH(pdb.hrgpld, (cpld +=
+ cpldChunk) * cwPLD, FALSE))
+ {
+ goto Error;
+ }
+
+PrintFormat:
+ /* Format this line. */
+ FormatLine(doc, cp, ichCp, cpMac, flmPrinting);
+
+ /* Abort if a memory error has occurred. */
+ if (vfOutOfMemory)
+ {
+ goto Error;
+ }
+
+ /* If this line is a splat, we have to decide if we really want
+ it or not. */
+ if (fSplat = vfli.fSplat)
+ {
+ /* Next, we are going to format either the next line (cp and
+ ichCp) or this line after the page has been removed (cpT and
+ ichCpT). */
+ typeCP cpT = cp;
+ int ichCpT = ichCp;
+
+ cp = vfli.cpMac;
+ ichCp = vfli.ichCpMac;
+
+ if (fConfirm)
+ {
+ /* The user must be prompted if he wants to keep this
+ page break. */
+ if (FPromptPgMark(cpT))
+ {
+ if (pdb.fRemove)
+ {
+ /* The page mark was removed, set cp and ichCp
+ to point to the start of the next line. */
+ cp = cpT;
+ ichCp = ichCpT;
+ cpMac--;
+ goto PrintFormat;
+ }
+ }
+ else
+ {
+ if (vfPrErr)
+ {
+ /* Something went wrong; punt. */
+ goto Error;
+ }
+ else
+ {
+ /* Well, the user wishes to cancel repagination.
+ */
+ goto CancelRepage;
+ }
+ }
+ }
+
+ /* Set the print line descriptor for the line after a splat.
+ */
+ ppld = &(**pdb.hrgpld)[pdb.ipld];
+ ppld->cp = cp;
+ ppld->ichCp = ichCp;
+ ppld->rc.left = ppld->rc.top = ppld->rc.right =
+ ppld->rc.bottom = 0;
+
+ /* Force a page break here with no widow and orphan
+ control. */
+ goto BreakPage;
+ }
+
+ /* Set the value for the current print line descriptor. */
+ ppld = &(**pdb.hrgpld)[pdb.ipld];
+ ppld->cp = cp;
+ ppld->ichCp = ichCp;
+ ppld->rc.left = xpLeft + vfli.xpLeft;
+ ppld->rc.right = xpLeft + vfli.xpReal;
+ ppld->rc.top = yp;
+ ppld->rc.bottom = yp + vfli.dypLine;
+ ppld->fParaFirst = (cp == vcpFirstParaCache && ichCp == 0 &&
+ vfli.cpMac != vcpLimParaCache);
+
+ /* If this line is not the first line and it won't fit on the
+ page, then force a page break, and prompt the user for input.
+ NOTE: At least one line is printed on each page. */
+ if (yp + vfli.dypLine > ypBottom && pdb.ipld > 0)
+ {
+ /* If the first line on the next page is the last line of a
+ paragraph, an orphan, then put the last line of this page on
+ the next page. */
+ if (vfli.cpMac == vcpLimParaCache && (cp !=
+ vcpFirstParaCache || ichCp != 0) && pdb.ipld > 1)
+ {
+ pdb.ipld--;
+ fPageAdj = TRUE;
+ }
+
+ /* If the last line on this page is the first line of a
+ paragraph, a widow, then put it on the next page. */
+ if (pdb.ipld > 1 && (**pdb.hrgpld)[pdb.ipld - 1].fParaFirst)
+ {
+ pdb.ipld--;
+ fPageAdj = TRUE;
+ }
+
+BreakPage:
+ /* Add an entry into the page table (only during the first
+ copy of the document). */
+ if (cCopies == 0)
+ {
+ if ((pdb.ipgd = (**pdb.hpgtb).cpgd++) + 1 >=
+ (**pdb.hpgtb).cpgdMax)
+ {
+ if (!FChngSizeH(pdb.hpgtb, cwPgtbBase +
+ ((**pdb.hpgtb).cpgdMax += cpgdChunk) * cwPGD,
+ FALSE))
+ {
+ /* Not enough memory to expand the page table;
+ time to bail out. */
+ goto ErrorMsg;
+ }
+ }
+ ppgd = &((**pdb.hpgtb).rgpgd[pdb.ipgd]);
+ ppgd->cpMin = (**pdb.hrgpld)[pdb.ipld].cp;
+ ppgd->pgn = vpgn + 1;
+ vdocPageCache = docNil;
+ }
+
+ /* Now go ask the user for his opinion. */
+ if (fConfirm)
+ {
+ if (!fSplat)
+ {
+ pdb.ipldCur = pdb.ipld;
+ if (FSetPage())
+ {
+ if (pdb.ipld != pdb.ipldCur)
+ {
+ /* The user has decided to move the page
+ break. */
+ pdb.ipld = pdb.ipldCur;
+ cpMac++;
+ fPageAdj = TRUE;
+ }
+ }
+ else
+ {
+ if (vfPrErr)
+ {
+ /* Something went wrong; punt. */
+ goto Error;
+ }
+ else
+ {
+ /* Well, the user wishes to cancel
+ repagination. */
+ goto CancelRepage;
+ }
+ }
+ }
+
+ /* After repaginating interactively, make certain the
+ screen reflects the current page break. */
+ UpdateWw(wwCur, FALSE);
+ }
+
+ /* This page has finished formatting, reset the cp and ichCp
+ pair to the top of the next page if necessary and get out of
+ this loop. */
+ if (fPageAdj)
+ {
+ ppld = &(**pdb.hrgpld)[pdb.ipld];
+ cp = ppld->cp;
+ ichCp = ppld->ichCp;
+ }
+ break;
+ }
+
+ /* Set the cp and ichCp to the start of the next line. */
+ cp = vfli.cpMac;
+ ichCp = vfli.ichCpMac;
+ yp += vfli.dypLine;
+ pdb.ipld++;
+ }
+
+ /* Now that we have figured out which lines fit on the page, its
+ time to print them. */
+ if (fPrint && (!vfPrPages || (vpgn >= vpgnBegin && vpgn <=
+ vpgnEnd)))
+ {
+ BOOL fFirstBand = TRUE;
+
+ /* This loop is executed for each band (once for non-banding
+ devices). */
+ for ( ; ; )
+ {
+ RECT rcBand;
+
+ /* Abort the print if the user so desires. */
+ if (!(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ goto Error;
+ }
+
+ /* Get the next band. */
+ if ((iEscape = Escape(vhDCPrinter, NEXTBAND, 0,
+ (LPSTR)NULL, (LPSTR)&rcBand)) < 0)
+ {
+ goto ErrorSwitch;
+ }
+#ifdef DPRINT
+CommSzSz("Next band", "");
+#endif
+
+ /* If the band is empty then we are finished with this
+ page. */
+ if (rcBand.top >= rcBand.bottom || rcBand.left >=
+ rcBand.right)
+ {
+ /* Reset the currently selected font. */
+ ResetFont(TRUE);
+ break;
+ }
+
+ /* The printer DC gets wiped clean at the start of each
+ page. It must be reinitialized. */
+ if (fFirstBand)
+ {
+ /* Set the printer into transparent mode. */
+ SetBkMode(vhDCPrinter, TRANSPARENT);
+
+ /* Reset the currently selected font. */
+ ResetFont(TRUE);
+
+ fFirstBand = FALSE;
+ }
+
+ /* First, print the header, if there is one. */
+ if (vpgn >= pgnFirstHeader && !FPrintBand(doc,
+ hrgpldHeader, cpldHeader, &rcBand))
+ {
+ goto Error;
+ }
+
+ /* Print that part of the document that lies in the
+ band. */
+ if (!FPrintBand(doc, pdb.hrgpld, pdb.ipld, &rcBand))
+ {
+ goto Error;
+ }
+
+ /* Lastly, print the footer, if it exists. */
+ if (vpgn >= pgnFirstFooter && !FPrintBand(doc,
+ hrgpldFooter, cpldFooter, &rcBand))
+ {
+ goto Error;
+ }
+ }
+ }
+
+ /* Finally, bump the page counter. */
+ vpgn++;
+ }
+DocFinished:;
+ }
+ while (fPrint && (cCopies += CopyIncr) < vcCopies);
+ }
+
+ /* If a range of pages is being printed then we reattatch the old page table
+ to the document. */
+ if (fPrint && vfPrPages)
+ {
+ goto RestorePgtb;
+ }
+
+CancelRepage:
+ /* If the page table has changed, then mark the document as dirty. */
+ if (!(**hpdocdod)[doc].fDirty)
+ {
+ (**hpdocdod)[doc].fDirty = (hpgtbOld == NULL) || ((**pdb.hpgtb).cpgd !=
+ (**hpgtbOld).cpgd) || !FRgchSame((**pdb.hpgtb).rgpgd,
+ (**hpgtbOld).rgpgd, (**pdb.hpgtb).cpgd * cchPGD);
+ }
+
+ /* Delete the old page table. */
+ if (hpgtbOld != NULL)
+ {
+ FreeH(hpgtbOld);
+ }
+
+ /* Printing and non-interactive repagination can't be undone. */
+ if (!fConfirm)
+ {
+ NoUndo();
+ }
+
+ErrorLoop:
+ /* Delete the array of line descriptors. */
+ FreeH(pdb.hrgpld);
+
+ if (fPrint)
+ {
+ BOOL fResetMode = FALSE;
+
+ /* Delete the descriptors for the header and footer. */
+ if (hrgpldHeader != NULL)
+ {
+ FreeH(hrgpldHeader);
+ }
+ if (hrgpldFooter != NULL)
+ {
+ FreeH(hrgpldFooter);
+ }
+
+ /* Tell the spooler that we are finished printing. */
+ if (!vfPrErr)
+ {
+ Escape(vhDCPrinter, ENDDOC, 0, (LPSTR)NULL, (LPSTR)NULL);
+#ifdef DPRINT
+CommSzSz("End doc", "");
+#endif
+ }
+
+ /* Reset the printer from draft mode if necessary. */
+ if (vfDraftMode)
+ {
+ Escape(vhDCPrinter, DRAFTMODE, sizeof(BOOL), (LPSTR)&fResetMode,
+ (LPSTR)NULL);
+ }
+ }
+
+ /* Reset the value of cpMinCur. */
+ cpMinCur = cpMin;
+
+ /* Invalidate the mode and page caches. */
+ docMode = vdocPageCache = docNil;
+
+ /* Since this might have changed the page breaks, dirty the windows so that
+ UpdateDisplay() will show them. */
+ TrashAllWws();
+
+Abort:
+ if (fPrint)
+ {
+ /* Create a new IC for the printer. */
+ ResetFont(TRUE);
+ FreePrinterDC();
+ GetPrinterDC(FALSE);
+ }
+
+ /* Enable all other windows. */
+ EnableWindow(hParentWw, TRUE);
+ EnableOtherModeless(TRUE);
+
+ if (fConfirm)
+ {
+ /* Let the user know that we are finished repaginating. */
+ EndLongOp(vhcIBeam);
+ }
+ else if (vhWndCancelPrint != NULL)
+ {
+ /* Get rid of the dialog box telling the user how to cancel printing or
+ repagination. */
+ DestroyWindow(vhWndCancelPrint);
+ vhWndCancelPrint = NULL;
+ DispatchPaintMsg();
+ }
+
+#ifndef INEFFLOCKDOWN
+ if (lpDialogCancelPrint)
+ FreeProcInstance(lpDialogCancelPrint);
+ if (lpFPrContinue)
+ FreeProcInstance(lpFPrContinue);
+ lpDialogCancelPrint = lpFPrContinue = NULL;
+#endif
+
+ fPrinting = FALSE;
+
+#if defined(OLE)
+ UPDATE_INVALID(); /* WM_PAINTS blocked while printing, repaint when done */
+#endif
+
+ /* Here is the exit point for this routine. */
+ return;
+
+ErrorMsg:
+ /* Give the user an error message before aborting the print/repagination. */
+ Error(IDPMTPRFAIL);
+
+Error:
+ /* Abort the print job if necessary. */
+ if (fPrint)
+ {
+ Escape(vhDCPrinter, ABORTDOC, 0, (LPSTR)NULL, (LPSTR)NULL);
+#ifdef DPRINT
+CommSzSz("Abort doc", "");
+#endif
+ }
+
+ErrorNoAbort:
+ /* Indicate that an error has occurred. (Cancellation is an error.) */
+ vfPrErr = TRUE;
+
+RestorePgtb:
+ /* Reconnect to old page table to the document, and then delete the new
+ page table. */
+ (**hpdocdod)[doc].hpgtb = hpgtbOld;
+ FreeH(pdb.hpgtb);
+
+ goto ErrorLoop;
+ }
+
+
+BOOL far PASCAL FPrContinue(hDC, iCode)
+HDC hDC;
+int iCode;
+ {
+ /* This routine returns TRUE if the user has not aborted the print; FALSE
+ otherwise. */
+
+ extern CHAR *vpDlgBuf;
+ extern HWND vhWndCancelPrint;
+ extern BOOL vfPrErr;
+ extern int vfOutOfMemory;
+
+ struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+ MSG msg;
+
+
+#if 0
+ /* If a printer error has occurred, that is the same as an abort. */
+ if (vfPrErr || vfOutOfMemory || (iCode < 0 && iCode != SP_OUTOFDISK))
+ {
+ return (FALSE);
+ }
+
+ /* If we have been called by the spooler then just return TRUE.
+ (Calling PeekMessage() at this point might be death.) */
+
+ if (iCode != wNotSpooler)
+ {
+ Assert(iCode == 0 || iCode == SP_OUTOFDISK);
+ if (iCode == 0)
+ return (TRUE);
+ /* else fall through to wait -- we're getting called by GDI while
+ the spooler frees up some temp files. this is NOT a genuine
+ error yet! 12/20/89 ..pault */
+ }
+#else
+ if (vfPrErr || vfOutOfMemory)
+ return FALSE;
+#endif
+
+ /* If there are any messages waiting the Cancel Print window, then send them
+ to the window messages handling routine. */
+ while (!ppdb->fCancel && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!IsDialogMessage(vhWndCancelPrint, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ /* If one of the messages was a cancel print meassge, then the value of
+ fCancel has been set. */
+ return !(vfPrErr = ppdb->fCancel || vfOutOfMemory);
+ }
+
+
+BOOL far PASCAL DialogCancelPrint(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine is supposed to process messages to the Cancel Print dialog
+ box, but, in reality, the sole responsiblity of this routine is to set the
+ flag fCancel if the user wishes to cancel printing. */
+
+ extern CHAR *vpDlgBuf;
+ extern HWND vhWndMsgBoxParent;
+
+ struct PDB *ppdb = (struct PDB *)vpDlgBuf;
+
+ if ((message == WM_COMMAND && (wParam == idiCancel || wParam == idiOk)) ||
+ (message == WM_CLOSE))
+ {
+ ppdb->fCancel = TRUE;
+ return (TRUE);
+ }
+ if (message == WM_INITDIALOG)
+ {
+ extern int docCur;
+ extern char szUntitled[];
+ extern struct DOD (**hpdocdod)[];
+ extern char * PchStartBaseNameSz();
+ struct DOD *pdod = &(**hpdocdod)[docCur];
+ CHAR *psz = &(**(pdod->hszFile))[0];
+
+ SetDlgItemText(hWnd, idiPrCancelName,
+ (LPSTR)(*psz ? PchStartBaseNameSz(psz) : szUntitled));
+ return(TRUE);
+ }
+ if (message == WM_ACTIVATE)
+ {
+ vhWndMsgBoxParent = wParam == 0 ? (HWND)NULL : hWnd;
+ }
+ return (FALSE);
+ }
+
+
+DispatchPaintMsg()
+ {
+ /* This routine looks for and dispatches any outstanding paint messages for
+ Write (like after an EndDialog() call). */
+
+ extern int vfOutOfMemory;
+
+ MSG msg;
+
+ while (!vfOutOfMemory && PeekMessage((LPMSG)&msg, NULL, WM_PAINT, WM_PAINT,
+ PM_REMOVE))
+ {
+ DispatchMessage((LPMSG)&msg);
+ }
+ }
diff --git a/private/mvdm/wow16/write/print2.c b/private/mvdm/wow16/write/print2.c
new file mode 100644
index 000000000..d91ef5432
--- /dev/null
+++ b/private/mvdm/wow16/write/print2.c
@@ -0,0 +1,352 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* These routines are the guts of the text print code. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOMB
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "mw.h"
+#include "printdef.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#include "fontdefs.h"
+#include "docdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "debug.h"
+#include "str.h"
+
+
+BOOL FPrintBand(doc, hrgpld, cpld, prcBand)
+int doc;
+struct PLD (**hrgpld)[];
+int cpld;
+PRECT prcBand;
+ {
+ /* This routine prints the lines in document doc that any part of which fall
+ in the rectange *prcBand. The first cpld print line descriptors in hrgpld
+ describe the current page in the document that will be printed. TRUE is
+ returned if the band is printed, FALSE otherwise. */
+
+ void PrintGraphics(int, int);
+ void near PrintFli(int, int);
+
+ extern struct DOD (**hpdocdod)[];
+ extern struct FLI vfli;
+ extern int vfOutOfMemory;
+ extern FARPROC lpFPrContinue;
+
+ int ipld;
+ typeCP cpMac = (**hpdocdod)[doc].cpMac;
+
+ for (ipld = 0; ipld < cpld; ipld++)
+ {
+ register struct PLD *ppld;
+
+ /* Check for user cancellation. */
+ if (!(*lpFPrContinue)(NULL, wNotSpooler))
+ {
+ return (FALSE);
+ }
+
+ /* Is this line within the band? */
+ ppld = &(**hrgpld)[ipld];
+ if (ppld->rc.top < prcBand->bottom && ppld->rc.bottom > prcBand->top &&
+ ppld->rc.left < prcBand->right && ppld->rc.right > prcBand->left)
+ {
+ /* Format this line for the printer. */
+ FormatLine(doc, ppld->cp, ppld->ichCp, cpMac, flmPrinting);
+
+ /* If memory failure occurred, then punt. */
+ if (vfOutOfMemory)
+ {
+ return (FALSE);
+ }
+
+ /* Reset the pointer to the print line descriptors (possible heap
+ movement in FormatLine()). */
+ ppld = &(**hrgpld)[ipld];
+
+ /* Print this line. */
+ if (vfli.fGraphics)
+ {
+ PrintGraphics(ppld->rc.left, ppld->rc.top);
+ }
+ else
+ {
+ PrintFli(ppld->rc.left, ppld->rc.top);
+ }
+ }
+ }
+ return (TRUE);
+ }
+
+
+void near PrintFli(xpPrint, ypPrint)
+int xpPrint;
+int ypPrint;
+ {
+ /* This routine prints the line of text stored in the vfli structure at
+ position (xpPrint, ypPrint). */
+
+ extern HDC vhDCPrinter;
+ extern struct FLI vfli;
+ extern struct DOD (**hpdocdod)[];
+ extern struct CHP (**vhgchpFormat)[];
+ extern int dxpPrPage;
+ extern int dypPrPage;
+ extern int ypSubSuperPr;
+ extern CHAR stBuf[];
+ extern struct FMI vfmiPrint;
+ extern typeCP cpMinDocument;
+ extern int vpgn;
+
+ int dcp;
+ int dxp; /* Width of current run */
+ int dxpExtra; /* Width of pad for each space */
+ int yp; /* Y-coordinate to print at. */
+ struct CHP *pchp; /* CHP associated with the current run */
+ BOOL fTabsKludge = (vfli.ichLastTab >= 0);
+ int cBreakRun; /* break characters in run (no relation to Dick or Jane) */
+
+ Scribble(5,'P');
+ Assert(vhDCPrinter);
+
+ pchp = &(**vhgchpFormat)[0];
+ dxpExtra = fTabsKludge ? 0 : vfli.dxpExtra;
+
+ for (dcp = 0; dcp < vfli.ichReal; pchp++)
+ {
+ /* For all runs do: */
+ int ichFirst; /* First character in the current run */
+ int cchRun; /* Number of characters in the current run */
+
+ dcp = ichFirst = pchp->ichRun;
+ dcp += pchp->cchRun;
+ if (dcp > vfli.ichReal)
+ {
+ dcp = vfli.ichReal;
+ }
+ cchRun = dcp - ichFirst;
+
+ /* Compute dxp = sum of width of characters in current run (formerly
+ DxpFromIcpDcp). */
+ {
+ register int *pdxp;
+ register int cchT = cchRun;
+ PCH pch = vfli.rgch + ichFirst;
+
+ dxp = cBreakRun = 0;
+ pdxp = &vfli.rgdxp[ichFirst];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+ }
+
+ if (dxp > 0)
+ {
+ int cchDone;
+ PCH pch = &vfli.rgch[ichFirst];
+
+ LoadFont(vfli.doc, pchp, mdFontPrint);
+ yp = ypPrint + vfli.dypLine - vfli.dypBase - (pchp->hpsPos != 0 ?
+ (pchp->hpsPos < hpsNegMin ? ypSubSuperPr : -ypSubSuperPr) : 0) -
+ vfmiPrint.dypBaseline;
+
+ /* Note: tabs and other special characters are guaranteed to come at
+ the start of a run. */
+ SetTextJustification(vhDCPrinter, dxpExtra * cBreakRun, cBreakRun);
+ cchDone = 0;
+ while (cchDone < cchRun)
+ {
+ int cch;
+
+ /* Does the wide-space zone begin in this run? */
+ if (vfli.fAdjSpace && (vfli.ichFirstWide < ichFirst + cchRun) &&
+ (ichFirst + cchDone <= vfli.ichFirstWide))
+ {
+ int cchDoneT = cchDone;
+
+ /* Is this the beginning of the wide-space zone? */
+ if (ichFirst + cchDone == vfli.ichFirstWide)
+ {
+ /* Reset the width of the spaces. */
+ SetTextJustification(vhDCPrinter, ++dxpExtra * cBreakRun, cBreakRun);
+ cch = cchRun - cchDone;
+ cchDone = cchRun;
+ }
+ else
+ {
+ cchDone = cch = vfli.ichFirstWide - ichFirst;
+ }
+
+ /* This run is cut short because of a wide space, so we need
+ to calculate a new width. */
+ {
+ register int *pdxp;
+ register int cchT = cch;
+ PCH pch = &vfli.rgch[ichFirst + cchDoneT];
+
+ dxp = 0;
+ pdxp = &vfli.rgdxp[ichFirst + cchDoneT];
+ while (cchT-- > 0)
+ {
+ dxp += *pdxp++;
+ if (*pch++ == chSpace)
+ ++cBreakRun;
+ }
+ }
+ }
+ else
+ {
+ cchDone = cch = cchRun;
+ }
+
+ while (cch > 0)
+ {
+ switch (*pch)
+ {
+ CHAR ch;
+ int dxpT;
+
+ case chTab:
+
+#ifdef CASHMERE
+ /* chLeader contains tab leader character (see
+ FormatLine) */
+ if ((ch = pchp->chLeader) != chSpace)
+ {
+ int cxpTab;
+ CHAR rgch[32];
+ int dxpLeader = DxpFromCh(ch, TRUE);
+ int xp = xpPrint;
+ int iLevelT = SaveDC(vhDCPrinter);
+
+ SetBytes(&rgch[0], ch, 32);
+ dxpT = vfli.rgdxp[ichFirst];
+ cxpTab = ((dxpT + dxpLeader - 1) / dxpLeader + 31)
+ >> 5;
+#ifdef CLIP
+ IntersectClipRect(vhDCPrinter, xpPrint, 0, xpPrint +
+ dxpT, vfli.dypLine);
+#endif
+
+ while (cxpTab-- > 0)
+ {
+ TextOut(vhDCPrinter, xp, yp, (LPSTR)rgch,
+ 32);
+ xp += dxpLeader << 5;
+ }
+ RestoreDC(vhDCPrinter, iLevelT);
+ xpPrint += dxpT;
+ }
+ else
+#endif /* CASHMERE */
+
+ {
+ xpPrint += vfli.rgdxp[ichFirst];
+ }
+
+ if (fTabsKludge && ichFirst >= vfli.ichLastTab)
+ {
+ SetTextJustification(vhDCPrinter, (dxpExtra =
+ vfli.dxpExtra) * cBreakRun, cBreakRun);
+ fTabsKludge = FALSE;
+ }
+ dxp -= vfli.rgdxp[ichFirst];
+ pch++;
+ cch--;
+ goto EndLoop;
+
+#ifdef CASHMERE
+ case schPage:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpPgn(&stBuf[1], vpgn, vsepAbs.nfcPgn,
+ flmPrinting, ichMaxLine);
+ goto DrawSpecial;
+
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = CchExpFtn(&stBuf[1], cpMin + ichFirst,
+ flmPrinting, ichMaxLine);
+DrawSpecial:
+#else /* not CASHMERE */
+ case schPage:
+ case schFootnote:
+ if (!pchp->fSpecial)
+ {
+ goto EndLoop;
+ }
+ stBuf[0] = *pch == schPage && vfli.cpMin + ichFirst <
+ cpMinDocument ? CchExpPgn(&stBuf[1], vpgn, 0,
+ flmPrinting, ichMaxLine) : CchExpUnknown(&stBuf[1],
+ flmPrinting, ichMaxLine);
+#endif /* not CASHMERE */
+
+ TextOut(vhDCPrinter, xpPrint, yp, (LPSTR)&stBuf[1],
+ stBuf[0]);
+ break;
+
+ default:
+ goto EndLoop;
+ }
+ dxp -= vfli.rgdxp[ichFirst];
+ xpPrint += vfli.rgdxp[ichFirst++];
+ pch++;
+ cch--;
+ }
+EndLoop:
+
+ /* Output cch characters starting at pch */
+#if 0
+ {
+ char msg[180];
+ wsprintf(msg,"putting out %d characters\n\r",cch);
+ OutputDebugString(msg);
+ }
+#endif
+ TextOut(vhDCPrinter, xpPrint, yp, (LPSTR)pch, cch);
+ xpPrint += dxp;
+ pch += cch;
+ }
+ }
+ }
+
+ Scribble(5,' ');
+ }
diff --git a/private/mvdm/wow16/write/print3.c b/private/mvdm/wow16/write/print3.c
new file mode 100644
index 000000000..abbecc0ab
--- /dev/null
+++ b/private/mvdm/wow16/write/print3.c
@@ -0,0 +1,293 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* These routines are the guts of the graphics print code. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOMB
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "mw.h"
+#include "printdef.h"
+#include "fmtdefs.h"
+#include "docdefs.h"
+#define NOKCCODES
+#include "winddefs.h"
+#include "debug.h"
+#include "str.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+PrintGraphics(xpPrint, ypPrint)
+int xpPrint;
+int ypPrint;
+ {
+ /* This routine prints the picture in the vfli structure at position
+ (xpPrint, ypPrint). */
+
+ extern HDC vhDCPrinter;
+ extern struct FLI vfli;
+ extern struct DOD (**hpdocdod)[];
+ extern int dxpPrPage;
+ extern int dypPrPage;
+ extern FARPROC lpFPrContinue;
+
+ typeCP cp;
+ typeCP cpMac = (**hpdocdod)[vfli.doc].cpMac;
+ struct PICINFOX picInfo;
+ HANDLE hBits = NULL;
+ HDC hMDC = NULL;
+ HBITMAP hbm = NULL;
+ LPCH lpBits;
+ int cchRun;
+ unsigned long cbPict = 0;
+ int dxpOrig; /* Size of picture in the original */
+ int dypOrig;
+ int dxpDisplay; /* Size of picture as we want to show it */
+ int dypDisplay;
+ BOOL fRescale;
+ BOOL fBitmap;
+ BOOL fPrint = FALSE;
+ int iLevel = 0;
+ RECT bounds;
+
+ Assert(vhDCPrinter);
+ GetPicInfo(vfli.cpMin, cpMac, vfli.doc, &picInfo);
+
+ /* Compute desired display size of picture (in device pixels) */
+ dxpDisplay = vfli.xpReal - vfli.xpLeft;
+ dypDisplay = vfli.dypLine;
+
+ /* Compute original size of picture (in device pixels) */
+ /* MM_ANISOTROPIC and MM_ISOTROPIC pictures have no original size */
+
+ fRescale = FALSE;
+ switch (picInfo.mfp.mm)
+ {
+ case MM_ISOTROPIC:
+ case MM_ANISOTROPIC:
+ break;
+
+#if defined(OLE)
+ case MM_OLE:
+ if (lpOBJ_QUERY_INFO(&picInfo) == NULL)
+ goto DontDraw;
+
+ if (lpOBJ_QUERY_OBJECT(&picInfo) == NULL)
+ goto DontDraw;
+ break;
+#endif
+
+ case MM_BITMAP:
+ dxpOrig = picInfo.bm.bmWidth;
+ dypOrig = picInfo.bm.bmHeight;
+ break;
+
+ default:
+ dxpOrig = PxlConvert(picInfo.mfp.mm, picInfo.mfp.xExt, dxpPrPage,
+ GetDeviceCaps(vhDCPrinter, HORZSIZE));
+ dypOrig = PxlConvert(picInfo.mfp.mm, picInfo.mfp.yExt, dypPrPage,
+ GetDeviceCaps(vhDCPrinter, VERTSIZE));
+ if (dxpOrig == 0 || dypOrig == 0)
+ {
+#ifdef DPRINT
+ CommSz("PrintGraphics: nodraw because dxpOrig==0 | dypOrig==0\r\n");
+#endif
+ goto DontDraw;
+ }
+ fRescale = (dxpOrig != dxpDisplay) || (dypOrig != dypDisplay);
+ break;
+ }
+
+ /* Get a handle to a global object large enough to hold the picture. */
+ if (picInfo.mfp.mm != MM_OLE)
+ {
+ if ((hBits = GlobalAlloc(GMEM_MOVEABLE, (long)picInfo.cbSize)) == NULL)
+ {
+ /* Not enough global heap space to load bitmap/metafile */
+#ifdef DPRINT
+ CommSz("PrintGraphics: nodraw because not enough mem to alloc\r\n");
+#endif
+ goto DontDraw;
+ }
+
+ /* Build up all bytes associated with the picture (except the header) into
+ the global handle hBits */
+ for (cbPict = 0, cp = vfli.cpMin + picInfo.cbHeader; cbPict <
+ picInfo.cbSize; cbPict += cchRun, cp += cchRun)
+ {
+ CHAR rgch[256];
+ LPCH lpch;
+
+ #define ulmin(a,b) ((a) < (b) ? (a) : (b))
+
+ FetchRgch(&cchRun, rgch, vfli.doc, cp, cpMac, (int)ulmin(picInfo.cbSize
+ - cbPict, 256));
+
+ if ((lpch = GlobalLock(hBits)) == NULL)
+ {
+#ifdef DPRINT
+ CommSz("PrintGraphics: nodraw because couldn't lock\r\n");
+#endif
+ goto DontDraw;
+ }
+
+ bltbx((LPSTR)rgch, lpch + cbPict, cchRun);
+ GlobalUnlock(hBits);
+ }
+ }
+
+ /* Save the printer DC as a guard against DC attribute alteration by a
+ metafile */
+ iLevel = SaveDC(vhDCPrinter);
+
+ fBitmap = picInfo.mfp.mm == MM_BITMAP;
+
+#if defined(OLE)
+ /* CASE 0: OLE */
+ if (picInfo.mfp.mm == MM_OLE)
+ {
+ RECT rcPict;
+
+ rcPict.left = xpPrint;
+ rcPict.top = ypPrint;
+ rcPict.right = rcPict.left + dxpDisplay;
+ rcPict.bottom = rcPict.top + dypDisplay;
+ SetMapMode(vhDCPrinter, MM_TEXT);
+ //SetViewportOrg( vhDCPrinter, xpPrint, ypPrint);
+ fPrint = ObjDisplayObjectInDoc(&picInfo, vfli.doc, vfli.cpMin, vhDCPrinter, &rcPict);
+ }
+ else
+#endif
+ if (fBitmap)
+ {
+ if (((hMDC = CreateCompatibleDC(vhDCPrinter)) != NULL) &&
+ ((picInfo.bm.bmBits = GlobalLock(hBits)) != NULL) && ((hbm =
+ CreateBitmapIndirect((LPBITMAP)&picInfo.bm)) != NULL))
+ {
+ picInfo.bm.bmBits = NULL;
+ GlobalUnlock(hBits);
+ if (SelectObject(hMDC, hbm) != NULL)
+ {
+ fPrint = StretchBlt(vhDCPrinter, xpPrint, ypPrint, dxpDisplay,
+ dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, SRCCOPY);
+#ifdef DPRINT
+ CommSzNum("PrintGraphics: after StretchBlt1, fPrint==", fPrint);
+#endif
+ }
+ }
+ }
+
+ /* Case 2: a non-scalable picture which we are nevertheless scaling by force
+ using StretchBlt */
+ else if (fRescale)
+ {
+ if (((hMDC = CreateCompatibleDC(vhDCPrinter)) != NULL) && ((hbm =
+ CreateCompatibleBitmap(vhDCPrinter, dxpOrig, dypOrig)) != NULL))
+ {
+ if (SelectObject(hMDC, hbm) && PatBlt(hMDC, 0, 0, dxpOrig, dypOrig,
+ WHITENESS) && SetMapMode(hMDC, picInfo.mfp.mm) &&
+ PlayMetaFile(hMDC, hBits))
+ {
+ /* Successfully played metafile */
+ SetMapMode(hMDC, MM_TEXT);
+ fPrint = StretchBlt(vhDCPrinter, xpPrint, ypPrint, dxpDisplay,
+ dypDisplay, hMDC, 0, 0, dxpOrig, dypOrig, SRCCOPY);
+#ifdef DPRINT
+ CommSzNum("PrintGraphics: after StretchBlt2, fPrint==", fPrint);
+#endif
+ }
+ }
+ }
+
+ /* Case 3: A metafile picture which can be directly scaled or does not
+ need to be because its size has not changed */
+ else
+ {
+ SetMapMode(vhDCPrinter, picInfo.mfp.mm);
+
+ SetViewportOrg(vhDCPrinter, xpPrint, ypPrint);
+ switch (picInfo.mfp.mm)
+ {
+ case MM_ISOTROPIC:
+ if (picInfo.mfp.xExt && picInfo.mfp.yExt)
+ {
+ /* So we get the correct shape rectangle when SetViewportExt
+ gets called */
+ SetWindowExt(vhDCPrinter, picInfo.mfp.xExt, picInfo.mfp.yExt);
+ }
+
+ /* FALL THROUGH */
+ case MM_ANISOTROPIC:
+ /** (9.17.91) v-dougk
+ Set the window extent in case the metafile is bad
+ and doesn't call it itself. This will prevent
+ possible gpfaults in GDI
+ **/
+ SetWindowExt( vhDCPrinter, dxpDisplay, dypDisplay );
+
+ SetViewportExt(vhDCPrinter, dxpDisplay, dypDisplay);
+ break;
+ }
+
+ fPrint = PlayMetaFile(vhDCPrinter, hBits);
+#ifdef DPRINT
+ CommSzNum("PrintGraphics: after PlayMetaFile, fPrint==", fPrint);
+#endif
+ }
+
+DontDraw:
+ /* We've drawn all we are going to draw; now its time to clean up. */
+ if (iLevel > 0)
+ {
+ RestoreDC(vhDCPrinter, iLevel);
+ }
+ if (hMDC != NULL)
+ {
+ DeleteDC(hMDC);
+ }
+ if (hbm != NULL)
+ {
+ DeleteObject(hbm);
+ }
+ if (hBits != NULL)
+ {
+ if (fBitmap && picInfo.bm.bmBits != NULL)
+ {
+ GlobalUnlock(hBits);
+ }
+ GlobalFree(hBits);
+ }
+
+ /* If we couldn't print the picture, warn the user. */
+ if (!fPrint)
+ {
+ Error(IDPMTPrPictErr);
+ }
+ }
diff --git a/private/mvdm/wow16/write/printdef.h b/private/mvdm/wow16/write/printdef.h
new file mode 100644
index 000000000..964553178
--- /dev/null
+++ b/private/mvdm/wow16/write/printdef.h
@@ -0,0 +1,59 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* printdefs.h */
+
+#ifndef PAGEONLY /* ifdef for page table declarations only */
+
+#define wNotSpooler 12741 /* an infamous number */
+
+#define cchMaxProfileSz 256
+#define cchMaxIDSTR 30
+
+struct PLD
+ { /* print line descriptor */
+ typeCP cp;
+ int ichCp;
+ RECT rc;
+ BOOL fParaFirst;
+ };
+
+#define cwPLD (sizeof(struct PLD) / sizeof(int))
+#define cpldInit 25
+#define cpldChunk 10
+#define cpldRH 5
+
+#endif /* PAGEONLY */
+
+#define ipgdMaxFile 2
+
+struct PGD
+ {
+ int pgn;
+ typeCP cpMin;
+ };
+
+#define bcpPGD 2
+#define cchPGD (sizeof(struct PGD))
+#define cwPGD (sizeof(struct PGD) / sizeof(int))
+#define cpgdChunk 10
+#define cwPgtbBase 2
+
+struct PGTB
+ { /* Page table */
+ int cpgd; /* Number of entries (sorted ascending) */
+ int cpgdMax; /* Heap space allocated */
+ struct PGD rgpgd[ipgdMaxFile]; /* Size varies */
+ };
+
+struct PDB
+ { /* Print dialog buffer */
+ struct PLD (**hrgpld)[];
+ int ipld;
+ int ipldCur;
+ struct PGTB **hpgtb;
+ int ipgd;
+ BOOL fCancel;
+ BOOL fRemove;
+ };
diff --git a/private/mvdm/wow16/write/printdlg.c b/private/mvdm/wow16/write/printdlg.c
new file mode 100644
index 000000000..deff777dc
--- /dev/null
+++ b/private/mvdm/wow16/write/printdlg.c
@@ -0,0 +1,588 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1990 Microsoft Corporation */
+/************************************************************/
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCLIPBOARD
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMETAFILE
+#define NOWH
+#define NOWNDCLASS
+#define NOSOUND
+#define NOCOLOR
+#define NOSCROLL
+#define NOCOMM
+
+#include <windows.h>
+#include "mw.h"
+#include "dlgdefs.h"
+#include "cmddefs.h"
+#include "machdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "printdef.h"
+#include "str.h"
+#include "fmtdefs.h"
+#include <commdlg.h>
+#include <cderr.h>
+#include <print.h>
+#include <stdlib.h>
+
+extern CHAR (**hszPrinter)[];
+extern CHAR (**hszPrDriver)[];
+extern CHAR (**hszPrPort)[];
+extern BOOL vfPrDefault;
+
+BOOL vbCollate = TRUE;
+
+static void GetPrNames(BOOL bPrDialog);
+PRINTDLG PD = {0,0,0,0,0}; /* Common print dlg structure, initialized in the init code */
+
+void PrinterSetupDlg(BOOL bGetDevmodeOnly /* not used */)
+{
+ extern HWND vhWnd;
+ BOOL bDevMode = PD.hDevMode ? TRUE : FALSE;
+
+ PD.Flags |= PD_PRINTSETUP;
+ PD.Flags &= ~PD_RETURNDEFAULT;
+
+ if (vfPrDefault && !PD.hDevNames)
+ if (PD.hDevMode)
+ {
+ /*
+ So dlg will show that default is selected. Its a pity
+ to do this because hDevMode is perfectly good. Alternative
+ is to build a DevNames structure which we could do, but
+ that would just allocate a new devmode anyways.
+ */
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = 0;
+ }
+
+TryPrnSetupAgain:
+ if (!PrintDlg(&PD))
+ {
+ /* Bug #11531: When PrintDlg returns 0, it could me we gave it garbage in
+ * the DevNames or DevMode structures, perhaps due to the user making
+ * changes through Control Panel that we don't monitor. Clean out the
+ * appropriate structure and try again. Note that these errors can't be
+ * returned to us again after cleaning out the structure.
+ * 23 August 1991 Clark R. Cyr
+ */
+ switch (CommDlgExtendedError())
+ {
+ case PDERR_PRINTERNOTFOUND:
+ case PDERR_DNDMMISMATCH:
+ if (PD.hDevNames)
+ {
+ GlobalFree(PD.hDevNames);
+ PD.hDevNames = 0;
+ }
+
+ if (PD.hDevMode)
+ {
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = 0;
+ }
+ goto TryPrnSetupAgain;
+
+ default:
+ return;
+ }
+ }
+
+ PD.Flags &= ~PD_PRINTSETUP;
+
+ GetPrNames(FALSE); // this gets new PrinterDC
+
+ ResetFontTables();
+
+#if defined(OLE)
+ ObjSetTargetDevice(TRUE);
+#endif
+
+ InvalidateRect(vhWnd, (LPRECT)NULL, fFalse);
+
+ return;
+}
+
+void fnPrPrinter(
+ void)
+{
+ /* This routine is the outside world's interface to the print code. */
+ extern int docCur;
+ extern int vfPrPages, vpgnBegin, vpgnEnd, vcCopies;
+ extern WORD fPrintOnly;
+ extern CHAR (**hszPrPort)[];
+ HANDLE hPort=NULL;
+ LPDEVNAMES lpDevNames;
+ int Len3;
+ char szPort[cchMaxFile];
+ extern struct SEL selCur;
+ BOOL bDevMode = PD.hDevMode ? TRUE : FALSE;
+
+ PD.Flags &= ~(PD_RETURNDEFAULT|PD_PRINTSETUP|PD_SELECTION); /*turn off PRINTSETUP flag */
+ if (vbCollate)
+ PD.Flags |= PD_COLLATE;
+ else
+ PD.Flags &= ~PD_COLLATE;
+
+ if (selCur.cpFirst == selCur.cpLim) // no selection
+ PD.Flags |= PD_NOSELECTION;
+ else
+ PD.Flags &= ~PD_NOSELECTION;
+
+ if (vfPrDefault && !PD.hDevNames)
+ if (PD.hDevMode)
+ {
+ /*
+ So dlg will show that default is selected. Its a pity
+ to do this beause hDevMode is perfectly good. Alternative
+ is to build a DevNames structure.
+ */
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = 0;
+ }
+
+TryPrintAgain:
+ if (!PrintDlg(&PD))
+ {
+ switch (CommDlgExtendedError())
+ {
+ case PDERR_PRINTERNOTFOUND:
+ case PDERR_DNDMMISMATCH:
+ if (PD.hDevNames)
+ {
+ GlobalFree(PD.hDevNames);
+ PD.hDevNames = 0;
+ }
+
+ if (PD.hDevMode)
+ {
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = 0;
+ }
+ goto TryPrintAgain;
+
+ default:
+ if (!bDevMode && PD.hDevMode)
+ {
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = 0;
+ }
+ return;
+ }
+ }
+
+ if (PD.Flags & PD_PAGENUMS) /* Page Range specified? */
+ {
+ vfPrPages = TRUE;
+ if (PD.nFromPage)
+ vpgnBegin = PD.nFromPage;
+ if (PD.nToPage)
+ vpgnEnd = PD.nToPage;
+ if (vpgnEnd < vpgnBegin)
+ {
+ int temp = vpgnBegin;
+
+ vpgnBegin = vpgnEnd;
+ vpgnEnd = temp;
+ }
+ }
+ else /* No, print all pages */
+ vfPrPages = FALSE;
+
+ vcCopies = PD.nCopies;
+ vbCollate = PD.Flags & PD_COLLATE;
+
+ GetPrNames(TRUE);
+
+ /** At this point, we have the following :
+
+ vfPrPages = true if print page range else print all pages
+ vpgnBegin = starting page number (if vfPrPages)
+ vpgnEnd = ending page number (if vfPrPages)
+ vcCopies = number of copies to print
+ vbCollate = whuddya think?
+ **/
+
+#if defined(OLE)
+ ObjSetTargetDevice(TRUE);
+#endif
+
+ if (PD.Flags & PD_SELECTION)
+ {
+ int docTmp;
+ BOOL bIssueError;
+ extern WORD ferror;
+ extern typeCP cpMinCur, cpMacCur, cpMinDocument;
+ extern struct DOD (**hpdocdod)[];
+ typeCP cpMinCurT = cpMinCur;
+ typeCP cpMacCurT = cpMacCur;
+ typeCP cpMinDocumentT = cpMinDocument;
+
+ docTmp = DocCreate(fnNil, HszCreate(""), dtyNormal);
+ if (docTmp != docNil)
+ {
+ ClobberDoc( docTmp, docCur, selCur.cpFirst, selCur.cpLim-selCur.cpFirst );
+
+ if (!ferror)
+ {
+ cpMinCur = cp0;
+ cpMacCur = (**hpdocdod) [docTmp].cpMac;
+ PrintDoc(docTmp, TRUE);
+ cpMinCur = cpMinCurT;
+ cpMacCur = cpMacCurT;
+ }
+
+ }
+
+ cpMinDocument = cpMinDocumentT; /* destroyed possibly by DocCreate */
+
+ bIssueError = ferror;
+
+ if (ferror)
+ ferror = FALSE; // to enable the following:
+
+ if (docTmp != docNil)
+ KillDoc (docTmp); // do this first to free memory to assist messagebox if necessary
+
+ if (bIssueError)
+ Error(IDPMTPRFAIL);
+ }
+ else
+ PrintDoc(docCur, TRUE);
+}
+
+BOOL FInitHeaderFooter(fHeader, ppgn, phrgpld, pcpld)
+BOOL fHeader;
+unsigned *ppgn;
+struct PLD (***phrgpld)[];
+int *pcpld;
+ {
+ /* This routine initializes the array of print line descriptors used in
+ positioning the header/footer on the printed page. FALSE is returned if an
+ error occurs; TRUE otherwise. */
+
+ extern typeCP cpMinHeader;
+ extern typeCP cpMacHeader;
+ extern typeCP cpMinFooter;
+ extern typeCP cpMacFooter;
+ extern int docCur;
+ extern struct PAP vpapAbs;
+ extern struct SEP vsepAbs;
+ extern int dxaPrOffset;
+ extern int dyaPrOffset;
+ extern int dxpPrPage;
+ extern int dxaPrPage;
+ extern int dypPrPage;
+ extern int dyaPrPage;
+ extern struct FLI vfli;
+ extern int vfOutOfMemory;
+
+ typeCP cpMin;
+ typeCP cpMac;
+
+ /* Get the cpMin and the cpMac for the header/footer. */
+ if (fHeader)
+ {
+ cpMin = cpMinHeader;
+ cpMac = cpMacHeader;
+ }
+ else
+ {
+ cpMin = cpMinFooter;
+ cpMac = cpMacFooter;
+ }
+
+ /* Is there a header/footer. */
+ if (cpMac - cpMin > ccpEol)
+ {
+ int cpld = 0;
+ int cpldReal = 0;
+ int cpldMax;
+ int xp;
+ int yp;
+ int ichCp = 0;
+ typeCP cpMacDoc = CpMacText(docCur);
+
+ /* Compute the page number of the start of the headers/footers. */
+ CacheSect(docCur, cpMin);
+ if ((*ppgn = vsepAbs.pgnStart) == pgnNil)
+ {
+ *ppgn = 1;
+ }
+
+ /* Does the header/footer appear on the first page. */
+ CachePara(docCur, cpMin);
+ if (!(vpapAbs.rhc & RHC_fFirst))
+ {
+ (*ppgn)++;
+ }
+
+ /* Calculate the bounds of the header/footer in pixels. */
+ xp = MultDiv(vsepAbs.xaLeft - dxaPrOffset, dxpPrPage, dxaPrPage);
+ yp = fHeader ? MultDiv(vsepAbs.yaRH1 - dyaPrOffset, dypPrPage,
+ dyaPrPage) : 0;
+
+ /* Initialize the array of print line descriptors for the header/footer.
+ */
+ if (FNoHeap(*phrgpld = (struct PLD (**)[])HAllocate((cpldMax = cpldRH) *
+ cwPLD)))
+ {
+ *phrgpld = NULL;
+ return (FALSE);
+ }
+
+ /* We now have to calculate the array of print line descriptors for the
+ header/footer. */
+ cpMac -= ccpEol;
+ while (cpMin < cpMac)
+ {
+ /* Format this line of the header/footer for the printer. */
+ FormatLine(docCur, cpMin, ichCp, cpMacDoc, flmPrinting);
+
+ /* Bail out if an error occurred. */
+ if (vfOutOfMemory)
+ {
+ return (FALSE);
+ }
+
+ /* Is the array of print line descriptors big enough? */
+ if (cpld >= cpldMax && !FChngSizeH(*phrgpld, (cpldMax += cpldRH) *
+ cwPLD, FALSE))
+ {
+ return (FALSE);
+ }
+
+ /* Fill the print line descriptor for this line. */
+ {
+ register struct PLD *ppld = &(***phrgpld)[cpld++];
+
+ ppld->cp = cpMin;
+ ppld->ichCp = ichCp;
+ ppld->rc.left = xp + vfli.xpLeft;
+ ppld->rc.right = xp + vfli.xpReal;
+ ppld->rc.top = yp;
+ ppld->rc.bottom = yp + vfli.dypLine;
+ }
+
+ /* Keep track of the non-blank lines in the header/footer */
+ if ((vfli.ichReal > 0) || vfli.fGraphics)
+ {
+ cpldReal = cpld;
+ }
+
+ /* Bump the counters. */
+ cpMin = vfli.cpMac;
+ ichCp = vfli.ichCpMac;
+ yp += vfli.dypLine;
+ }
+
+ /* If this is a footer, then we have to move the positions of the lines
+ around so that the footer ends where the user has requested. */
+ if (!fHeader && cpldReal > 0)
+ {
+ register struct PLD *ppld = &(***phrgpld)[cpldReal - 1];
+ int dyp = MultDiv(vsepAbs.yaRH2 - dyaPrOffset, dypPrPage, dyaPrPage)
+ - ppld->rc.bottom;
+ int ipld;
+
+ for (ipld = cpldReal; ipld > 0; ipld--, ppld--)
+ {
+ ppld->rc.top += dyp;
+ ppld->rc.bottom += dyp;
+ }
+ }
+
+ /* Record the number of non-blank lines in the head/footer. */
+ *pcpld = cpldReal;
+ }
+ else
+ {
+ /* Indicate there is no header/footer. */
+ *ppgn = pgnNil;
+ *phrgpld = NULL;
+ *pcpld = 0;
+ }
+ return (TRUE);
+ }
+
+
+
+static void GetPrNames(BOOL bPrDialog)
+{
+ HANDLE hPrinter = NULL, hDriver = NULL, hPort = NULL;
+ LPDEVNAMES lpDevNames;
+ char szPrinter[cchMaxFile], szDriver[cchMaxFile], szPort[cchMaxFile];
+ int Len1, Len2, Len3; /* count of words in each string */
+
+ hPrinter = NULL;
+ hDriver = NULL;
+ hPort = NULL;
+
+ lpDevNames = MAKELP(PD.hDevNames,0);
+
+ if (lpDevNames == NULL)
+ /* we're screwed */
+ return;
+
+ lstrcpy(szPrinter, (LPSTR)lpDevNames+lpDevNames->wDeviceOffset);
+ lstrcpy(szDriver, (LPSTR)lpDevNames+lpDevNames->wDriverOffset);
+
+ if (bPrDialog && (PD.Flags & PD_PRINTTOFILE))
+ lstrcpy(szPort, (LPSTR)"FILE:");
+ else
+ lstrcpy(szPort, (LPSTR)lpDevNames+lpDevNames->wOutputOffset);
+
+ vfPrDefault = lpDevNames->wDefault & DN_DEFAULTPRN;
+
+ if (FNoHeap((hPrinter = (CHAR (**)[])HAllocate(Len1 =
+ CwFromCch(CchSz(szPrinter))))))
+ goto err;
+ if (FNoHeap((hDriver = (CHAR (**)[])HAllocate(Len2 =
+ CwFromCch(CchSz(szDriver))))))
+ goto err;
+ if (FNoHeap((hPort = (CHAR (**)[])HAllocate(Len3 =
+ CwFromCch(CchSz(szPort))))))
+ goto err;
+
+ /* Free old printer, driver and port handles */
+ if (hszPrinter)
+ FreeH(hszPrinter);
+ if (hszPrDriver)
+ FreeH(hszPrDriver);
+ if (hszPrPort)
+ FreeH(hszPrPort);
+ /* Set printer, driver and port handles */
+ hszPrinter = hPrinter;
+ hszPrDriver = hDriver;
+ hszPrPort = hPort;
+
+ /* copy strings into the memory corresponding to the new handles */
+ blt(szPrinter, *hszPrinter, Len1);
+ blt(szDriver, *hszPrDriver, Len2);
+ blt(szPort, *hszPrPort, Len3);
+
+ FreePrinterDC();
+ GetPrinterDC(FALSE);
+ return;
+
+ err:
+ if (FNoHeap(hPrinter))
+ FreeH(hPrinter);
+ if (FNoHeap(hDriver))
+ FreeH(hDriver);
+ if (FNoHeap(hPort))
+ FreeH(hPort);
+}
+
+BOOL fnPrGetDevmode(void)
+/* Set the devmode structure for the currently-selected printer,
+ Assumes all needed values are correctly initialized!
+ Return whether an error. */
+{
+ int nCount;
+ HANDLE hDevice=NULL;
+ FARPROC lpfnDevMode;
+ BOOL bRetval=FALSE;
+ char szDrvName[_MAX_PATH];
+
+ if (PD.hDevMode) // then already set (why called?)
+ return FALSE;
+ else if (PD.hDevNames) // then device is not extended
+ return TRUE;
+
+ if (hszPrinter == NULL || hszPrDriver == NULL || hszPrPort == NULL)
+ return TRUE;
+
+ if (**hszPrinter == '\0' || **hszPrDriver == '\0' || **hszPrPort == '\0')
+ return TRUE;
+
+ /* is this necessary for GetModuleHandle? For sure if calling LoadLibrary(). */
+ wsprintf((LPSTR)szDrvName, (LPSTR)"%s%s", (LPSTR)*hszPrDriver, (LPSTR)".DRV");
+
+#if 1
+ SetErrorMode(1); /* No kernel error dialogs */
+ if ((hDevice = LoadLibrary((LPSTR)szDrvName)) < 32)
+ {
+ bRetval = TRUE;
+ goto end;
+ }
+#else
+ hDevice = GetModuleHandle((LPSTR)szDrvName);
+#endif
+
+
+ if ((lpfnDevMode = GetProcAddress(hDevice, (LPSTR)"ExtDeviceMode")) == NULL)
+ {
+#ifdef DEBUG
+ OutputDebugString("Unable to get extended device\n\r");
+#endif
+
+ bRetval = TRUE;
+ goto end;
+ }
+
+ /* get sizeof devmode structure */
+ nCount = (*lpfnDevMode)(NULL,
+ hDevice,
+ (LPSTR)NULL,
+ (LPSTR)(*hszPrinter),
+ (LPSTR)(*hszPrPort),
+ (LPSTR)NULL,
+ (LPSTR)NULL,
+ NULL);
+
+ if ((PD.hDevMode =
+ GlobalAlloc(GMEM_MOVEABLE,(DWORD)nCount)) == NULL)
+ {
+ bRetval = TRUE;
+ goto end;
+ }
+
+ if ((*lpfnDevMode)( NULL,
+ hDevice,
+ MAKELP(PD.hDevMode,0),
+ (LPSTR)(*hszPrinter),
+ (LPSTR)(*hszPrPort),
+ (LPSTR)NULL,
+ (LPSTR)NULL,
+ DM_COPY) != IDOK)
+ {
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = NULL;
+ bRetval = TRUE;
+ goto end;
+ }
+
+ end:
+
+#if 1
+ if (hDevice >= 32)
+ FreeLibrary(hDevice);
+#endif
+
+ SetErrorMode(0); /* reset kernel error dialogs */
+
+ /* can't allow hDevNames to be out of sync with hDevmode */
+ if (PD.hDevNames)
+ {
+ GlobalFree(PD.hDevNames);
+ PD.hDevNames = NULL;
+ }
+
+ return bRetval;
+}
+
diff --git a/private/mvdm/wow16/write/prmdefs.h b/private/mvdm/wow16/write/prmdefs.h
new file mode 100644
index 000000000..d949fad17
--- /dev/null
+++ b/private/mvdm/wow16/write/prmdefs.h
@@ -0,0 +1,102 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Single property modifiers */
+
+/* *** MUST agree with dnsprm in mglobals.c *** */
+
+#ifndef PRMDEFSH
+#define PRMDEFSH
+
+/* Paragraph */
+#define sprmPLMarg 1 /* Left margin */
+#define sprmPRMarg 2 /* Right margin */
+#define sprmPFIndent 3 /* First line indent (from LM) */
+#define sprmPJc 4 /* Justification code */
+#define sprmPRuler 5 /* Ruler (formerly Clear tab) */
+#define sprmPRuler1 6 /* Ruler1 (formerly Set tab) */
+#define sprmPKeep 7 /* Keep */
+#define sprmPNormal 8 /* Normal para (formerly Style, overrides all others) */
+#define sprmPRhc 9 /* Running head code */
+#define sprmPSame 10 /* Everything (overrides all others) */
+#define sprmPDyaLine 11 /* Line height */
+#define sprmPDyaBefore 12 /* Space before */
+#define sprmPDyaAfter 13 /* Space after */
+#define sprmPNest 14 /* Nest para */
+#define sprmPUnNest 15 /* Un-nest para */
+#define sprmPHang 16 /* Hanging indent */
+#define sprmPRgtbd 17 /* add a range of tabs */
+#define sprmPKeepFollow 18 /* Keep follow */
+/*#define sprmPCAll 19 /* Clear all tabs */
+
+/* Character */
+#define sprmCBold 20 /* Bold */
+#define sprmCItalic 21 /* Italic */
+#define sprmCUline 22 /* Underline */
+#define sprmCPos 23 /* Super/subscript */
+#define sprmCFtc 24 /* Font code */
+#define sprmCHps 25 /* Half-point size */
+#define sprmCSame 26 /* Whole CHP */
+#define sprmCChgFtc 27 /* Alter Font code */
+#define sprmCChgHps 28 /* Alter point size */
+#define sprmCPlain 29 /* Change to plain text (preserve font) */
+#define sprmCShadow 30 /* Shadow text attribute */
+#define sprmCOutline 31 /* Outline text attribute */
+#define sprmCCsm 32 /* case modification */
+
+#define sprmCStrike 33 /* Strikeout */ /* unused */
+#define sprmCDline 34 /* Double underline */ /* unused */
+/*#define sprmCPitch 35 /* Pitch */
+/*#define sprmCOverset 36 /* Margin overset */
+/*#define sprmCStc 37 /* Style (overrides all others) */
+#define sprmCMapFtc 38 /* Defines font code mapping */
+#define sprmCOldFtc 39 /* Defines procedural font code mapping
+ for old WORD files */
+
+#define sprmPRhcNorm 40 /* Normalize rhc indent to be margin-relatve */
+#define sprmMax 41 /* UPDATE WHEN ADDING SPRMS */
+
+struct PRM
+ { /* PropeRty Modifier -- 2 bytes only
+ (now 4 bytes so scratch file can be >64K (7.12.91) v-dougk)
+ Couldn't be 3 bytes because Heap mgmt in Write assumes
+ word sizes of memory requests . Don't know what would take
+ to change that. */
+ unsigned char fComplex : 1; /* If fComplex == false . . . */
+ unsigned char sprm : 7;
+ CHAR val;
+ WORD dummy;
+ };
+
+struct PRMX
+ { /* PropeRty Modifier, part 2 */
+ unsigned int fComplex : 1; /* if fComplex == true */
+ unsigned int bfprm_hi : 15;
+ unsigned int bfprm_low ;
+ };
+
+extern struct PRM PrmAppend(struct PRM prm, CHAR *psprm);
+extern DoPrm(struct CHP *pchp, struct PAP *ppap, struct PRM prm);
+
+#define fcSCRATCHPRM(prm) (((((typeFC)(((struct PRMX *)&(prm))->bfprm_hi )) << 16) + \
+ (((typeFC)(((struct PRMX *)&(prm))->bfprm_low)) )) << 1)
+#define bPRMNIL(prm) (!((prm).fComplex) && !((prm).sprm) && !((prm).val))
+#define SETPRMNIL(prm) ((prm).fComplex = (prm).sprm = (prm).val = (prm).dummy = 0)
+
+/* Definitions for ESPRM */
+#define ESPRM_cch 000003 /* Mask for cch of sprm */
+#define ESPRM_sgcMult 000004 /* Sgc multiplier */
+#define ESPRM_sgc 000014 /* Sprm Group Code mask */
+#define ESPRM_spr 000040 /* Sprm priority mask */
+#define ESPRM_fClobber 000100 /* Overrides sprms with same sgc and <= spr */
+#define ESPRM_fSame 000200 /* Overrides another instance of same sprm */
+
+#define sgcChar (0 * ESPRM_sgcMult)
+#define sgcPara (1 * ESPRM_sgcMult)
+#define sgcParaSpec (2 * ESPRM_sgcMult)
+
+#define hpsSuperSub 12
+
+#define dxaTabDelta 50
+#endif
diff --git a/private/mvdm/wow16/write/propdefs.h b/private/mvdm/wow16/write/propdefs.h
new file mode 100644
index 000000000..3d77e0881
--- /dev/null
+++ b/private/mvdm/wow16/write/propdefs.h
@@ -0,0 +1,234 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* propdefs.h - MW defsfor char/para properties */
+
+#define hpsNegMin 128
+/* NOTE - "hpsNormal" is used for incremental encoding/decoding of chps in doc
+ files, hpsDefault is the size the guy starts typing into a new doc with */
+#define hpsNormal 24
+
+#ifdef KOREA
+#define hpsDefault 24
+#else
+#define hpsDefault 20
+#endif
+
+struct TBD /* Tab Descriptor */
+ {
+ unsigned dxa; /* distance from left margin of tab stop */
+ unsigned char jc : 3; /* justification code */
+ unsigned char tlc : 3; /* leader dot code */
+ unsigned char opcode : 2; /* operation code for Format Tabs */
+ CHAR chAlign; /* ASCII code of char to align on
+ if jcTab=3, or 0 to align on '.' */
+ };
+
+#define cchTBD (sizeof (struct TBD))
+#define cwTBD (sizeof (struct TBD) / sizeof (int))
+#define itbdMax 13
+#define itbdMaxWord 20
+#define cchMaxNum 10
+
+struct CHP /* Character properties */
+ {
+ unsigned fStyled : 1; /* BYTE 0 */
+ unsigned stc : 7; /* style */
+ unsigned fBold : 1; /* BYTE 1 */
+ unsigned fItalic : 1;
+ unsigned ftc : 6; /* Font code */
+ unsigned hps : 8; /* Size in half pts */ /* BYTE 2 */
+ unsigned fUline : 1; /* BYTE 3 */
+ unsigned fStrike : 1;
+ unsigned fDline: 1;
+ unsigned fOverset : 1;
+ unsigned csm : 2; /* Case modifier */
+ unsigned fSpecial : 1;
+ unsigned : 1;
+ unsigned ftcXtra : 3; /* BYTE 4 */
+ unsigned fOutline : 1;
+ unsigned fShadow : 1;
+ unsigned : 3;
+ unsigned hpsPos : 8; /* BYTE 5 */
+ unsigned fFixedPitch : 1; /* used internally only */
+ unsigned psWidth : 7;
+ unsigned chLeader : 8;
+ unsigned ichRun : 8;
+ unsigned cchRun : 8;
+ };
+
+#define cchCHP (sizeof (struct CHP))
+#define cwCHP (cchCHP / sizeof (int))
+#define cchCHPUsed (cchCHP - 3)
+
+
+#define csmNormal 0
+#define csmUpper 1
+#define csmSmallCaps 3
+
+
+/* Justification codes: must agree with menu.mod */
+#define jcLeft 0
+#define jcCenter 1
+#define jcRight 2
+#define jcBoth 3
+
+#define jcTabMin 4
+#define jcTabLeft 4
+#define jcTabCenter 5
+#define jcTabRight 6
+#define jcTabDecimal 7
+ /* nice, safe invalid jc value */
+#define jcNil -1
+
+/* Tab leader codes: must agree with menu.mod */
+#define tlcWhite 0
+#define tlcDot 1
+#define tlcHyphen 2
+#define tlcUline 3
+
+
+struct PAP /* Paragraph properties */
+ {
+ unsigned fStyled : 1; /* BYTE 0 */
+ unsigned stc : 7;
+ unsigned jc : 2; /* BYTE 1 */
+ unsigned fKeep : 1;
+ unsigned fKeepFollow : 1;
+ unsigned : 4;
+ unsigned stcNormChp : 7; /* BYTE 2 */
+ unsigned : 9; /* BYTE 3 */
+ unsigned dxaRight; /* BYTE 4-5 */
+ unsigned dxaLeft; /* BYTE 6-7 */
+ unsigned dxaLeft1; /* BYTE 8-9 */
+ unsigned dyaLine; /* 10-11 */
+ unsigned dyaBefore; /* 12-13 */
+ unsigned dyaAfter; /* 14-15 */
+ unsigned rhc : 4; /* Running hd code */
+ unsigned fGraphics : 1; /* Graphics bit */
+ unsigned wUnused1 : 11;
+ int wUnused2;
+ int wUnused3;
+ struct TBD rgtbd[itbdMaxWord];
+ };
+
+#define cchPAP (sizeof (struct PAP))
+#define cwPAP (cchPAP / sizeof (int))
+#define cwPAPBase (cwPAP - cwTBD * itbdMaxWord)
+
+struct SEP
+ { /* Section properties */
+ unsigned fStyled : 1; /* BYTE 0 */
+ unsigned stc : 7;
+ unsigned bkc : 3; /* Break code */ /* BYTE 1 */
+ unsigned nfcPgn : 3; /* Pgn format code */
+ unsigned :2;
+ unsigned yaMac; /* Page height */ /* BYTE 2-3 */
+ unsigned xaMac; /* Page width */ /* BYTE 4-5 */
+ unsigned pgnStart; /* Starting pgn */ /* BYTE 6-7 */
+ unsigned yaTop; /* Start of text */ /* BYTE 8-9 */
+ unsigned dyaText; /* Height of text */ /* 10-11 */
+ unsigned xaLeft; /* Left text margin */ /* 12-13 */
+ unsigned dxaText; /* Width of text */ /* 14-15 */
+ unsigned rhc : 4; /* *** RESERVED *** */ /* 16 */
+ /* (Must be same as PAP) */
+ unsigned : 2;
+ unsigned fAutoPgn : 1; /* Print pgns without hdr */
+ unsigned fEndFtns : 1; /* Footnotes at end of doc */
+ unsigned cColumns : 8; /* # of columns */ /* BYTE 17 */
+ unsigned yaRH1; /* Pos of top hdr */ /* 18-19 */
+ unsigned yaRH2; /* Pos of bottom hdr */ /* 20-21 */
+ unsigned dxaColumns; /* Intercolumn gap */ /* 22-23 */
+ unsigned dxaGutter; /* Gutter width */ /* 24-25 */
+ unsigned yaPgn; /* Y pos of page nos */ /* 26-27 */
+ unsigned xaPgn; /* X pos of page nos */ /* 28-29 */
+ CHAR rgbJunk[cchPAP - 30]; /* Pad to cchPAP */
+ };
+
+
+#define cchSEP (sizeof (struct SEP))
+#define cwSEP (cchSEP / sizeof (int))
+
+
+struct PROP
+ { /* A CHP, PAP, or SEP. */
+ unsigned char fStyled : 1;
+ unsigned char stc : 7;
+ CHAR rgb[cchPAP - 1]; /* Variable size */
+ };
+
+
+#define cchPROP (sizeof (struct PROP))
+
+typedef struct
+ { /* tri-state value for character/paragraph properties */
+ unsigned wTsv; /* 16 bit value */
+ unsigned char fGray;
+ }TSV;
+
+
+#define cchTSV (sizeof (TSV))
+#define itsvMax 6
+#define itsvchMax 6
+#define itsvparaMax 5
+
+ /* character index values */
+#define itsvBold 0
+#define itsvItalic 1
+#define itsvUline 2
+#define itsvPosition 3 /* 0 = normal; >0 = superscript; <0 = subscript */
+#define itsvFfn 4 /* font name and family */
+#define itsvSize 5 /* font size */
+ /* paragraph index values */
+#define itsvJust 0 /* justification (left, center, right, both) */
+#define itsvSpacing 1
+#define itsvLIndent 2 /* left indent */
+#define itsvFIndent 3 /* first line indent */
+#define itsvRIndent 4 /* right indent */
+
+
+
+
+
+#define cyaInch czaInch
+#define cxaInch czaInch
+#define cyaTl czaLine
+#define dxaNest 720
+
+extern int cxaTc;
+
+#define yaNil 0xffff
+#define xaNil 0xffff
+
+#define ypNil 0xffff
+#define xpNil 0xffff
+
+#define dyaMinUseful cyaInch
+#define dxaMinUseful (cxaInch / 2)
+#define cColumnsMax (10)
+
+#define bkcLine 0
+#define bkcColumn 1
+#define bkcPage 2
+#define bkcRecto 3
+#define bkcVerso 4
+
+#define nfcArabic 0
+#define nfcUCRoman 1
+#define nfcLCRoman 2
+#define nfcUCLetter 3
+#define nfcLCLetter 4
+
+#define pgnNil (-1)
+
+struct PROP *PpropXlate();
+
+/* Running head codes */
+#define RHC_fBottom 1
+#define RHC_fOdd 2
+#define RHC_fEven 4
+#define RHC_fFirst 8
+
+#define rhcDefault (RHC_fOdd + RHC_fEven)
+
diff --git a/private/mvdm/wow16/write/quit.c b/private/mvdm/wow16/write/quit.c
new file mode 100644
index 000000000..e2fcd6168
--- /dev/null
+++ b/private/mvdm/wow16/write/quit.c
@@ -0,0 +1,354 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Quit.c -- MW quit commands (non-resident) */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOFONT
+#define NOHDC
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMINMAX
+//#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "str.h"
+#include "cmddefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "filedefs.h"
+#include "wwdefs.h"
+#include "propdefs.h"
+#include "dlgdefs.h"
+#include "commdlg.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#include "debug.h"
+
+extern PRINTDLG PD; /* Common print dlg structure, initialized in the init code */
+extern struct FCB (**hpfnfcb)[];
+extern int fnMac;
+extern struct WWD rgwwd[];
+extern int wwMac;
+extern struct DOD (**hpdocdod)[];
+extern int docCur; /* Document in current ww */
+extern int vfExtScrap;
+extern int rgval[];
+extern int docMac;
+extern int vfBuffersDirty;
+extern int vdxaPaper;
+extern int vdyaPaper;
+extern int ferror;
+extern int docScrap;
+extern struct PAP vpapAbs;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern int vfScrapIsPic;
+extern typeCP vcpLimParaCache;
+
+
+FMmwClose( hwnd )
+HWND hwnd;
+{ /* Handle WM_CLOSE message sent to parent window. Return FALSE if
+ the CLOSE should be aborted, TRUE if it is OK to go ahead
+ and CLOSE (DestroyWindow is called in this case). */
+
+ extern int vfDead;
+ extern VOID (FAR PASCAL *lpfnRegisterPenApp)(WORD, BOOL);
+extern WORD fPrintOnly;
+
+ if (fPrintOnly || FConfirmSave())
+ {
+ extern int vfOwnClipboard;
+
+ FreeMemoryDC( FALSE ); /* To give FRenderAll max memory */
+
+ /* Render Data BEFORE the world collapses around our ears */
+ if (vfOwnClipboard)
+ { /* We are the clipboard owner -- render the clipboard contents in
+ all datatypes that we know about */
+ if (!FRenderAll())
+ /* Render failed; abort close */
+ return FALSE;
+ }
+
+#if defined(OLE)
+ if (ObjClosingDoc(docCur,NULL)) // do this *after* call to RenderAll!
+ return FALSE;
+#endif
+
+ /* pen windows */
+ if (lpfnRegisterPenApp) // global
+ (*lpfnRegisterPenApp)((WORD)1, fFalse); // deregister
+
+ if (PD.hDevMode)
+ {
+ /* We'd opened a Win3 printer driver before, now discard */
+ GlobalFree(PD.hDevMode);
+ PD.hDevMode = NULL;
+ }
+ vfDead = TRUE; /* So we don't repaint or idle anymore */
+
+ DestroyWindow( hwnd );
+ KillTempFiles( FALSE );
+ return TRUE; /* OK to close window */
+ }
+
+ return FALSE; /* ABort the close */
+}
+
+
+
+
+MmwDestroy()
+{ /* Parent window is being destroyed */
+ extern HWND hParentWw;
+ extern HWND vhWndPageInfo;
+ extern HDC vhDCRuler;
+ extern HBRUSH hbrBkgrnd;
+ extern HFONT vhfPageInfo;
+ extern HBITMAP hbmBtn;
+ extern HBITMAP hbmMark;
+ extern HANDLE hszNoMemory;
+ extern HANDLE hszDirtyDoc;
+ extern HANDLE hszCantPrint;
+ extern HANDLE hszPRFAIL;
+
+ HBRUSH hbr = GetStockObject( WHITE_BRUSH );
+ HDC hDC = GetDC( vhWndPageInfo );
+
+#ifdef WIN30
+ {
+ /* We use the help engine so advise it we're going far far away */
+
+ CHAR sz[cchMaxFile];
+ PchFillPchId(sz, IDSTRHELPF, sizeof(sz));
+ WinHelp(hParentWw, (LPSTR)sz, HELP_QUIT, NULL);
+ }
+#endif
+
+ FreeMemoryDC( TRUE );
+ SelectObject( GetDC( hParentWw ), hbr );
+ SelectObject( wwdCurrentDoc.hDC, hbr );
+ if (vhDCRuler != NULL)
+ {
+ SelectObject( vhDCRuler, hbr );
+ }
+ DeleteObject( hbrBkgrnd );
+
+ DeleteObject( SelectObject( hDC, hbr ) );
+ if (vhfPageInfo != NULL)
+ {
+ DeleteObject( SelectObject( hDC, GetStockObject( SYSTEM_FONT ) ) );
+ }
+
+ if (hbmBtn != NULL)
+ {
+ DeleteObject( hbmBtn );
+ }
+ if (hbmMark != NULL)
+ {
+ DeleteObject( hbmMark );
+ }
+
+ if (hszNoMemory != NULL)
+ {
+ GlobalFree( hszNoMemory );
+ }
+ if (hszDirtyDoc != NULL)
+ {
+ GlobalFree( hszDirtyDoc );
+ }
+ if (hszCantPrint != NULL)
+ {
+ GlobalFree( hszCantPrint );
+ }
+ if (hszPRFAIL != NULL)
+ {
+ GlobalFree( hszPRFAIL );
+ }
+
+#if defined(JAPAN) & defined(DBCS_IME)
+ /* Release Ime communication memory */
+ {
+ extern HANDLE hImeMem;
+
+ if (hImeMem)
+ GlobalFree(hImeMem);
+ }
+#endif
+
+#ifdef FONT_KLUDGE
+ RemoveFontResource( (LPSTR)"helv.fon" );
+#endif /* FONT_KLUDGE */
+
+#if defined(OLE)
+ ObjShutDown();
+#endif
+
+ PostQuitMessage( 0 );
+}
+
+
+
+
+KillTempFiles( fEndSession )
+int fEndSession;
+{ /* Kill off all of the temp files. MEMO cannot run after this is done */
+int f;
+int fn, fnT;
+
+CloseEveryRfn( TRUE );
+
+/* Delete all temp files */
+
+/* loop thru the FCB table looking for files that should be deleted before
+ we quit. */
+for (fn = 0; fn < fnMac; fn++)
+ {
+ int fpe;
+ struct FCB *pfcb = &(**hpfnfcb)[fn];
+ if (pfcb->rfn != rfnFree && pfcb->fDelete)
+ /* Having found a file that must be deleted, delete it */
+ {
+ /* This should be FDeleteFile all of the time, but we don't
+ want to add a window enumeration during End Session
+ at this very late stage of the project */
+
+ if (fEndSession)
+ FpeDeleteSzFfname( **pfcb->hszFile );
+ else
+ FDeleteFile( **pfcb->hszFile );
+ (**hpfnfcb) [fn].rfn = rfnFree;
+ }
+ }
+}
+
+
+
+
+
+
+#ifdef ENABLE /* Part of "Save All", not needed */
+int CnfrmSz(sz)
+CHAR *sz;
+{
+extern AlertBoxSz2();
+int cch;
+
+cch = CchFillSzId(&stBuf[1], IDPMTSaveChanges);
+stBuf[++cch] = chSpace;
+cch += CchCopySz(sz, &stBuf[cch+1]);
+stBuf[++cch] = chQMark;
+stBuf[0] = cch;
+return(AlertBoxSz2(stBuf));
+}
+#endif /* ENABLE */
+
+
+
+#ifdef ENABLE /* Not needed, only 1 document in MEMO */
+int
+FAllDocsClean()
+{
+int fAllClean = true;
+int dty;
+int doc;
+
+if (vfBuffersDirty)
+ return false;
+
+for (doc = 0; doc < docMac; ++doc)
+ {
+ dty = (**hpdocdod)[doc].dty;
+ if ((dty != dtyNormal && dty != dtySsht) ||
+ (**hpdocdod)[doc].hpctb == 0 || !(**hpdocdod)[doc].fDirty)
+ continue;
+ fAllClean = false;
+ }
+return fAllClean;
+}
+#endif
+
+
+
+#ifdef ENABLE /* We don't support saving between-session state info */
+WriteStateInfo()
+{ /* Write out state information into Word resource file */
+ struct STATEINFO stiTemp;
+ HANDLE hRes, hData;
+
+ UseResFile(vresSystem);
+
+ SetWords(&stiTemp,0,cwSTATEINFO);
+
+ stiTemp.sf.fScrnDraftStor = vfScrnDraft;
+ stiTemp.sf.fPrintModeStor = vfPrintMode;
+ stiTemp.sf.fDriverDefaultOK = vfDriverDefaultOK;
+ stiTemp.utCurStor = utCur;
+ stiTemp.vcDaisyPitchStor = vcDaisyPitch;
+ stiTemp.vBaudRateStor =vBaudRate;
+ stiTemp.vPortNumStor = vPortNum;
+ if (hszPrdFile != 0)
+ {/* User has a Word printer driver selected currently */
+ int cch = CchCopySz(**hszPrdFile,stiTemp.rgchPrd);
+ stiTemp.vdxaPaperStor = vdxaPaper;
+ stiTemp.vdyaPaperStor = vdyaPaper;
+ stiTemp.sf.fPrintStateOK = true;
+ }
+ else
+ stiTemp.sf.fPrintStateOK = false;
+ hRes = GetResource(WINF, 1);
+ if (hRes != 0L)
+ RmveResource(hRes);
+ hData = NewHandle(0);
+ if (HandleAppendQ(hData,&stiTemp,sizeof(stiTemp)))
+ AddResource(hData, WINF, 1, "");
+ }
+#endif /* ENABLE */
+
+
+fnQuit(hWnd)
+/* user has selected Quit menu item... */
+HWND hWnd;
+{
+ SendMessage(hWnd, WM_CLOSE, 0, 0L);
+}
+
+
diff --git a/private/mvdm/wow16/write/rare.c b/private/mvdm/wow16/write/rare.c
new file mode 100644
index 000000000..61542bfd4
--- /dev/null
+++ b/private/mvdm/wow16/write/rare.c
@@ -0,0 +1,325 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This routine sets up the screen position used by Word relative to the
+current device. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NODRAWTEXT
+#define NOMSG
+#define NOOPENFILE
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "scrndefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "printdef.h"
+#include "str.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "machdefs.h"
+#include "fontdefs.h"
+#include "winddefs.h"
+#include <commdlg.h>
+
+
+MmwWinSysChange(wm)
+int wm;
+ {
+ /* This routine processes the WM_SYSCOLORCHANGE, WM_WININICHANGE,
+ WM_DEVMODECHANGE, and WM_FONTCHANGE messages. */
+
+ extern HDC vhDCRuler;
+ extern HBRUSH hbrBkgrnd;
+ extern long rgbBkgrnd;
+ extern long rgbText;
+ extern struct WWD rgwwd[];
+ extern HDC vhMDC;
+ extern BOOL vfMonochrome;
+ extern HWND hParentWw;
+ extern HWND vhWndPageInfo;
+ extern HBITMAP vhbmBitmapCache;
+ extern BOOL vfBMBitmapCache;
+ extern int vfPrinterValid;
+ extern CHAR szWindows[];
+ extern CHAR szDevices[];
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+ extern CHAR (**hszDevmodeChangeParam)[];
+ extern CHAR (**hszWininiChangeParam)[];
+ extern HFONT vhfPageInfo;
+ extern int docMode;
+ extern HWND vhWndCancelPrint;
+ extern BOOL vfIconic;
+ extern BOOL vfWarnMargins;
+ extern int wWininiChange;
+
+ BOOL FSetWindowColors(void);
+
+ CHAR szPrinter[cchMaxProfileSz];
+ CHAR (**hszPrinterSave)[];
+ CHAR (**hszPrDriverSave)[];
+ CHAR (**hszPrPortSave)[];
+ BOOL fNotPrinting = (vhWndCancelPrint == NULL);
+ RECT rc;
+
+ switch (wm)
+ {
+ case WM_SYSCOLORCHANGE:
+ /* Someone is changing the system colors. */
+ if (FSetWindowColors())
+ {
+ /* Change the colors of the ruler. */
+ if (vhDCRuler != NULL)
+ {
+ HPEN hpen;
+
+ /* Set the background and foreground colors of the ruler. */
+ SetBkColor(vhDCRuler, rgbBkgrnd);
+ SetTextColor(vhDCRuler, rgbText);
+
+ /* Set the pen for the ruler. */
+ if ((hpen = CreatePen(0, 0, rgbText)) == NULL)
+ {
+ hpen = GetStockObject(BLACK_PEN);
+ }
+ DeleteObject(SelectObject(vhDCRuler, hpen));
+
+ /* Set the background brush for the ruler. */
+ SelectObject(vhDCRuler, hbrBkgrnd);
+ }
+
+ if (wwdCurrentDoc.hDC != NULL)
+ {
+ /* Set the background and foreground colors. */
+ SetBkColor(wwdCurrentDoc.hDC, rgbBkgrnd);
+ SetTextColor(wwdCurrentDoc.hDC, rgbText);
+
+ /* Set the background brush. */
+ SelectObject(wwdCurrentDoc.hDC, hbrBkgrnd);
+
+ if (vhMDC != NULL && vfMonochrome)
+ {
+ /* If the display is a monochrome device, then set the text
+ color for the memory DC. Monochrome bitmaps will not be
+ converted to the foreground and background colors in this
+ case, we must do the conversion. */
+ SetTextColor(vhMDC, rgbText);
+ }
+ }
+
+ if (hParentWw != NULL)
+ {
+ /* Set the background brush for the parent window. */
+ DeleteObject(SelectObject(GetDC(hParentWw), hbrBkgrnd));
+ }
+ }
+
+ if (vhWndPageInfo != NULL)
+ {
+ HBRUSH hbr;
+ HDC hDC = GetDC(vhWndPageInfo);
+
+ /* Set the colors for the page info window. */
+ if ((hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) ==
+ NULL)
+ {
+ hbr = GetStockObject(BLACK_BRUSH);
+ }
+ DeleteObject(SelectObject(hDC, hbr));
+#ifdef WIN30
+ /* If the user has their colors set with a TextCaption color of
+ black then this becomes hard to read! We just hardcode this
+ to be white since the background defaults to being black */
+ SetTextColor(hDC, (DWORD) -1);
+#else
+ SetTextColor(hDC, GetSysColor(COLOR_CAPTIONTEXT));
+#endif
+ }
+
+ /* If the bitmap cache is holding a resized metafile, then free the
+ cache because the bitmap might contain part of the background that might
+ have changed. */
+ if (vhbmBitmapCache != NULL && !vfBMBitmapCache)
+ {
+ FreeBitmapCache();
+ }
+ break;
+
+ case WM_WININICHANGE:
+ /* We only care if the "windows", "devices", or "intl" fields have
+ changed -- this has been taken care of already, see mmw.c */
+
+ if (wWininiChange & wWininiChangeToIntl)
+ {
+ extern HWND vhDlgRunning;
+ extern int utCur;
+ extern CHAR vchDecimal; /* decimal point character */
+ CHAR bufT[3]; /* to hold decimal point string */
+ extern CHAR szsDecimal[];
+ extern CHAR szsDecimalDefault[];
+ extern CHAR szIntl[];
+ extern HWND vhWndRuler;
+ extern int viDigits;
+ extern BOOL vbLZero;
+
+ if (GetProfileInt((LPSTR)szIntl, (LPSTR)"iMeasure", 1) == 1)
+ utCur = utInch;
+ else
+ utCur = utCm;
+
+ viDigits = GetProfileInt((LPSTR)szIntl, (LPSTR)"iDigits", 2);
+ vbLZero = GetProfileInt((LPSTR)szIntl, (LPSTR)"iLZero", 0);
+
+ /* Get the decimal point character from the user profile. */
+ GetProfileString((LPSTR)szIntl, (LPSTR)szsDecimal, (LPSTR)szsDecimalDefault,
+ (LPSTR)bufT, 2);
+ vchDecimal = *bufT;
+
+ InvalidateRect(vhWndRuler, (LPRECT)NULL, FALSE);
+ UpdateRuler();
+ }
+
+ if ((wWininiChange & wWininiChangeToDevices) ||
+ (wWininiChange & wWininiChangeToWindows))
+ {
+ /* Reestablish the printer from the profile in case it was the
+ printer that was changed. */
+ hszPrinterSave = hszPrinter;
+ hszPrDriverSave = hszPrDriver;
+ hszPrPortSave = hszPrPort;
+
+ if (FGetPrinterFromProfile())
+ {
+ BOOL fPrChange = FALSE;
+
+ if (hszPrinterSave == NULL || hszPrDriverSave == NULL ||
+ hszPrPortSave == NULL || hszPrinter == NULL || hszPrDriver ==
+ NULL || hszPrPort == NULL || WCompSz(&(**hszPrinter)[0],
+ &(**hszPrinterSave)[0]) != 0 || WCompSz(&(**hszPrDriver)[0],
+ &(**hszPrDriverSave)[0]) != 0 || WCompSz(&(**hszPrPort)[0],
+ &(**hszPrPortSave)[0]) != 0)
+ {
+ /* If we are not printing, then we can reflect the change of
+ the printer on the screen. */
+ if (!(fPrChange = fNotPrinting))
+ {
+ /* We are printing while the printer has changed, set
+ the flags so that the next time we get a printer DC we
+ will assume that it is valid. */
+ Assert(vfPrinterValid);
+ vfWarnMargins = TRUE;
+ }
+ }
+
+ /* Delete the saved copies of the printer strings. */
+ if (hszPrinterSave != NULL)
+ {
+ FreeH(hszPrinterSave);
+ }
+ if (hszPrDriverSave != NULL)
+ {
+ FreeH(hszPrDriverSave);
+ }
+ if (hszPrPortSave != NULL)
+ {
+ FreeH(hszPrPortSave);
+ }
+
+ if (fPrChange)
+ {
+ /* Get the new printer DC and update the world. */
+ goto GetNewPrinter;
+ }
+ }
+ else
+ {
+ Error(IDPMTNoMemory);
+ hszPrinter = hszPrinterSave;
+ hszPrDriver = hszPrDriverSave;
+ hszPrPort = hszPrPortSave;
+ }
+ }
+ break;
+
+ case WM_DEVMODECHANGE:
+ /* The device mode for some printer has changed; check to see if it was
+ our printer. */
+ if (fNotPrinting && hszPrinter != NULL &&
+ (hszDevmodeChangeParam == NULL ||
+ (bltszx(*hszDevmodeChangeParam, (LPSTR)szPrinter ),
+ WCompSz(szPrinter, &(**hszPrinter)[0]) == 0)))
+ {
+ extern PRINTDLG PD; /* Common print dlg structure, initialized in the init code */
+GetNewPrinter:
+ if (PD.hDevMode)
+ GlobalFree(PD.hDevMode);
+ if (PD.hDevNames)
+ GlobalFree(PD.hDevNames);
+ PD.hDevMode = PD.hDevNames = NULL;
+
+ /* The printer has changed, so get rid of the old one. */
+ FreePrinterDC();
+
+ fnPrGetDevmode();
+
+#if defined(OLE)
+ ObjSetTargetDevice(TRUE);
+#endif
+
+ /* The printer description has changed; assume the new printer is
+ valid. */
+ vfPrinterValid = vfWarnMargins = TRUE;
+ GetPrinterDC(FALSE);
+ ResetFontTables();
+
+RedrawWindow:
+ /* Everything must be redisplayed because the world may have
+ changed. */
+ if (!vfIconic)
+ {
+ InvalidateRect(wwdCurrentDoc.wwptr, (LPRECT)NULL, FALSE);
+ }
+ }
+
+ if (hszDevmodeChangeParam != NULL)
+ FreeH(hszDevmodeChangeParam);
+ hszDevmodeChangeParam = NULL;
+ break;
+
+ case WM_FONTCHANGE:
+ /* The font used to display the page number may have changed. */
+ if (vhfPageInfo != NULL)
+ {
+ DeleteObject(SelectObject(GetDC(vhWndPageInfo),
+ GetStockObject(SYSTEM_FONT)));
+ vhfPageInfo = NULL;
+ }
+ docMode = docNil;
+ DrawMode();
+
+ ResetFontTables();
+
+ goto RedrawWindow;
+ } /* end switch */
+ }
+
diff --git a/private/mvdm/wow16/write/readme.txt b/private/mvdm/wow16/write/readme.txt
new file mode 100644
index 000000000..79493bb81
--- /dev/null
+++ b/private/mvdm/wow16/write/readme.txt
@@ -0,0 +1,148 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1990 Microsoft Corporation */
+/************************************************************/
+
+ ** 21-January-1988
+
+ MS-WRITE for version 2.0 of Windows is a weird bird in that it
+cannot be compiled with standard tools (ie: MASM 5.0 etc.). You will
+need to set up a separate environment from which to make it using the
+tools in the \WRITE\TOOLS subdirectory. We are sorry for this inconvenience
+and will attempt to remedy this in future versions of MS-WINDOWS.
+
+Sincerely,
+
+OEM Support Group
+
+ ** 27-February-1989
+ pault
+
+I am trying to remove the above restriction. The Win "DEV" SLM project is
+being used to build MS-WRITE for Windows 3.0, currently without problems.
+Make sure autoexec references are made/added as follows:
+ set path=\dev;\dev\tools
+ set include=\dev\inc
+ set lib=\dev\lib
+
+WRITE is the makefile for this project. DO NOT USE MAKEFILE -- I do not
+know where it came from or why it's here, and of course we may learn that
+things are not currently as rosy as we believe, but this is how I *THINK*
+the product has been made in the past...
+
+ MAKE WRITE MAKE "DEBUGDEF=-DDEBUG" "DFLAGS=/Zd" WRITE
+ builds the standard builds a debugging version
+ release version
+
+
+ ** 28-March-1989
+ pault
+
+The above procedure was not generating quite the same WRITE.EXE as we've
+previously had (Win 2.x). In talking with anyone who's ever been involved
+at all, this is the information I have learned:
+
+ 1. Nobody wants this product or claims responsibility for it.
+ 2. It has been a nightmare for everyone who has worked on, with,
+ or around it.
+ 3. The international version was incorporated at some time during
+ 2.x and is now "built in".
+ 4. There was at one time an online help system designed which was
+ never included in a shipped version.
+ 5. The 6 or 8 batch files, .libs, and makefiles "makefile" and
+ "wrtmake" are for the 2.x version; since we have since grown up
+ I am removing them...
+ 6. The K*.* files (or *.K* files) apply to the Kanji make process and
+ they have N-O-T been updated yet, but are being left in the project
+ (i.e. they must be modified or add to the "write" makefile). Also
+ see the file EDM.EDM (hey, file naming is our specialty here at MS).
+
+I have made mods to the project and "write" makefile to incorporate the
+subtle changes from 2.x. Variations of the make process are/will be
+documented inside the makefile.
+
+
+ ** 8-June-1989
+ pault
+
+In order to ease localization of this product, all string-related info
+in GLOBDEFS.H should really be moved to WRITE.RC because that's where
+it belongs and it'll also make things a lot cleaner. [True for Kanji?]
+
+
+ ** 31-August-1989
+ pault
+
+Due to major changes in Write.rc and the split into Write.dlg, whoever
+takes on the task of localization to Intl or Kanji should be sure to
+start over with the new Write.rc and Write.dlg.
+
+
+ ** 18-October-1989
+ pault
+
+I've just made a major revision with regard to font handling in Write.
+The first one was to make sure that the endmark is always displayed in
+the system font. The Kanji version already ensured this so I grouped
+all the code concerning this under the define 'SYSENDMARK', and enabled
+it in the Z version.
+
+The second one was to revamp font enumeration... (under 'NEWFONTENUM')
+
+Old method: Call EnumFonts to get a list of fonts available, and "filter
+ out" fonts which did not match our desired aspect ratio (based
+ on the overall display dimensions). In addition, any fonts
+ which were not the ANSI character set (i.e. the tmCharSet or
+ lfCharSet fields in the TEXTMETRICS and LOGFONT structures,
+ respectively) were "swallowed". A specific byproduct of this
+ was that screen fonts such as Modern, Script, Symbol, etc.
+ could not be used in Write.
+
+New method: Call EnumFonts to get a list of fonts available. No filtering-
+ out is done. The major problem here became an issue with the
+ Write file format: the font name and font family are stored in
+ the document but naturally not the appropriate character set
+ value (since only ANSI had been previously allowed). So now
+ when we read a new document in, we enumerate all the fonts and
+ then for each font in the doc we try to match up the correct
+ character set value.
+
+ This slows things down ever-so-slightly and we also have the
+ possibility of getting confused if someone names a font of one
+ character set the same as one of a different character set, but
+ there wasn't much alternative -- it was either make this kind
+ of guess or revise the file format which would have created a
+ lot more problems at this point.
+
+
+ ** 23-October-1989
+
+FernandD has worked on the localization issue mentioned above and checked
+in changes for Rel 1.46
+
+
+ ** 24-October-1989
+ pault
+
+One change involved in the above NEWFONTENUM was to use FORM1.C instead
+of the (presumably) faster FORMAT.ASM. So this sparks the idea to keep
+a list of some performance ideas for future use...
+
+done? task
+----- ----
+ 1) handcode critical routines (including the use format.asm
+ instead of form1.c)
+ 2) make use of register vars
+ 3) chipa suggests breaking up really large segments, and eliminating
+ very small ones
+ X 4) remove inefficient lockdown of dialog procs, etc. not sure
+ why this is currently done but it forces a large amount of
+ code to be fixed at write startup, and this hampers the general
+ idea of movable segments in a winapp!
+ 5) remove use of C run-time libs
+
+ ** 25-October-1989
+
+It has just been decided to remove support for ExtDeviceMode from Write
+(primarily because none of the other apps had it!) This means that when
+you change Printer.Setup inside Write, that affects the global Windows
+printer settings (rather than just those for the current Write session).
diff --git a/private/mvdm/wow16/write/right.bms b/private/mvdm/wow16/write/right.bms
new file mode 100644
index 000000000..acaefb68a
--- /dev/null
+++ b/private/mvdm/wow16/write/right.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/rmargin.bms b/private/mvdm/wow16/write/rmargin.bms
new file mode 100644
index 000000000..5395d53e7
--- /dev/null
+++ b/private/mvdm/wow16/write/rmargin.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/ruler.c b/private/mvdm/wow16/write/ruler.c
new file mode 100644
index 000000000..f2b763104
--- /dev/null
+++ b/private/mvdm/wow16/write/ruler.c
@@ -0,0 +1,1677 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains the routines for creating, displaying, and manipulating
+the ruler for Memo. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOATOM
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOMSG
+#define NOOPENFILE
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "rulerdef.h"
+#include "propdefs.h"
+#include "prmdefs.h"
+#include "docdefs.h"
+#include "bitmaps.h"
+
+#define MERGEMARK 0x00990066
+
+extern HWND hParentWw;
+extern HANDLE hMmwModInstance;
+extern HCURSOR vhcIBeam;
+extern struct DOD (**hpdocdod)[];
+extern struct WWD *pwwdCur;
+extern struct PAP vpapAbs;
+extern struct SEP vsepAbs;
+extern struct SEL selCur;
+extern typeCP cpMacCur;
+extern int docCur;
+extern int vdocParaCache;
+extern int dypRuler;
+extern int dxpLogInch;
+extern int dypLogInch;
+extern int dxpLogCm;
+extern int dypLogCm;
+extern int xpSelBar;
+extern HWND vhWndRuler;
+extern int vdxaTextRuler;
+extern int mprmkdxa[rmkMARGMAX];
+extern int vfTabsChanged;
+extern int vfMargChanged;
+extern struct WWD rgwwd[];
+extern long rgbBkgrnd;
+extern long rgbText;
+extern HBRUSH hbrBkgrnd;
+extern long ropErase;
+extern BOOL vfMonochrome;
+extern BOOL vfEraseWw;
+extern int vfIconic;
+
+#ifdef RULERALSO
+extern HWND vhDlgIndent;
+#endif /* RULERALSO */
+
+HDC vhDCRuler = NULL;
+HDC hMDCBitmap = NULL;
+HDC hMDCScreen = NULL;
+HBITMAP hbmBtn = NULL;
+HBITMAP hbmMark = NULL;
+HBITMAP hbmNullRuler = NULL;
+int dxpRuler;
+
+int viBmRuler = -1; /* Index into [CGA/EGA/VGA/8514] bitmaps (see
+ WRITE.RC). Set appropriately in FCreateRuler(). */
+
+static RECT rgrcRulerBtn[btnMaxUsed];
+static int mprlcbtnDown[rlcBTNMAX] = {btnNIL, btnNIL, btnNIL};
+static struct TBD rgtbdRuler[itbdMax];
+static int xpMinCur;
+static int dxpMark;
+static int dypMark;
+static int btnTabSave = btnLTAB;
+
+
+near UpdateRulerBtn(int, int);
+BOOL near FCreateRuler(void);
+int near DestroyRuler(void);
+int near RulerStateFromPt(POINT, int *, int *);
+int near MergeRulerMark(int, int, BOOL);
+BOOL near FPointNear(unsigned, unsigned);
+unsigned near XaQuantize(int);
+int near DeleteRulerTab(struct TBD *);
+int near InsertRulerTab(struct TBD *);
+BOOL near FCloseXa(unsigned, unsigned);
+#ifdef KINTL
+unsigned near XaKickBackXa(unsigned);
+near XpKickBackXp(int);
+unsigned near XaQuantizeXa(unsigned);
+#endif /* KINTL */
+
+fnShowRuler()
+ {
+ /* This routine toggles the creation and the destruction of the ruler
+ window. */
+
+ StartLongOp();
+ if (pwwdCur->fRuler)
+ {
+ /* Take down the existing ruler. */
+ DestroyRuler();
+ SetRulerMenu(TRUE);
+ }
+ else
+ {
+ /* There is no ruler, bring one up. */
+ if (FCreateRuler())
+ {
+ SetRulerMenu(FALSE);
+ }
+ }
+ EndLongOp(vhcIBeam);
+ }
+
+
+BOOL near FCreateRuler()
+ {
+ /* This routine creates the ruler child window and positions it on the
+ screen. */
+
+ extern CHAR szRulerClass[];
+ int xpMac = pwwdCur->xpMac;
+ int ypMac = pwwdCur->ypMac;
+ LOGFONT lf;
+ HFONT hf;
+ int dyp;
+ HPEN hpen;
+ RECT rc;
+ TEXTMETRIC tmSys;
+ HDC hdcSys;
+
+
+ /* Create the ruler window. */
+ if ((vhWndRuler = CreateWindow((LPSTR)szRulerClass, (LPSTR)NULL,
+ WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0, hParentWw, NULL, hMmwModInstance,
+ (LPSTR)NULL)) == NULL)
+ {
+ goto Error2;
+ }
+
+ /* Save the DC and the memory DC. */
+ if ((vhDCRuler = GetDC(vhWndRuler)) == NULL || (hMDCBitmap =
+ CreateCompatibleDC(vhDCRuler)) == NULL || (hMDCScreen =
+ CreateCompatibleDC(vhDCRuler)) == NULL)
+ {
+ goto Error1;
+ }
+
+ /* Create a null bitmap for the ruler. */
+ if ((hbmNullRuler = CreateBitmap(1, 1, 1, 1, (LPSTR)NULL)) == NULL)
+ {
+ goto Error1;
+ }
+
+ /* New for Write 3.0: we have a variety of bitmaps for the ruler buttons
+ and marks -- loaded depending on the resolution of the user's display.
+ All we really want to do here is set viBmRuler, which indexes into the
+ appropriate bitmaps (see bitmaps.h) ..pault 7/13/89 */
+
+ if (viBmRuler < 0)
+ {
+ /* This idea of passing NULL to GetDC borrowed from WinWord ..pt */
+ if ((hdcSys = GetDC(NULL)) == NULL)
+ goto Error1;
+ else
+ {
+ int tmHeight;
+
+ GetTextMetrics(hdcSys, (LPTEXTMETRIC) &tmSys);
+ tmHeight = tmSys.tmHeight;
+ ReleaseDC(NULL, hdcSys);
+
+ viBmRuler = 0;
+ if (tmHeight > 8)
+ viBmRuler++;
+ if (tmHeight > 12)
+ viBmRuler++;
+ if (tmHeight > 16)
+ viBmRuler++;
+ }
+
+ Diag(CommSzNum("FCreateRuler: index into [CGA/EGA/VGA/8514] bitmaps==", viBmRuler));
+ Assert(idBmBtns + viBmRuler < idBmBtnsMax);
+ Assert(idBmMarks + viBmRuler < idBmMarksMax);
+ }
+
+ /* Get the bitmaps for the ruler buttons and the ruler marks. */
+ if (hbmBtn == NULL || SelectObject(hMDCBitmap, hbmBtn) == NULL)
+ {
+ if (NULL == (hbmBtn = LoadBitmap(hMmwModInstance,
+ MAKEINTRESOURCE(idBmBtns+viBmRuler))))
+ {
+ goto Error1;
+ }
+ }
+ if (hbmMark == NULL || SelectObject(hMDCBitmap, hbmMark) == NULL)
+ {
+ if (NULL == (hbmMark = LoadBitmap(hMmwModInstance,
+ MAKEINTRESOURCE(idBmMarks+viBmRuler))))
+ {
+ goto Error1;
+ }
+ }
+
+ /* Get the font for labelling the ruler ticks. */
+ bltbc(&lf, 0, sizeof(LOGFONT));
+ lf.lfHeight = -MultDiv(czaPoint * 8, dypLogInch, czaInch);
+ if ((hf = CreateFontIndirect(&lf)) != NULL)
+ {
+ if (SelectObject(vhDCRuler, hf) == NULL)
+ {
+ DeleteObject(hf);
+ }
+ }
+
+ /* If this is the first time the ruler is created, then initialize the
+ static variables. */
+ if (dypRuler == 0)
+ {
+ int dxpMajor;
+ int dxpMinor;
+ BITMAP bm;
+ int xp;
+ int dxpBtn;
+ int btn;
+ PRECT prc;
+ TEXTMETRIC tm;
+
+ /* Initialize the starting position of the buttons. */
+ dxpMinor = (dxpMajor = dxpLogInch >> 1) >> 2;
+ xp = xpSelBar + dxpMajor + (dxpMajor >> 1);
+
+ /* Get the width and height of the buttons. */
+ GetObject(hbmBtn, sizeof(BITMAP), (LPSTR)&bm);
+ /* Factor of 2 since we have positive and negative images
+ of each button embedded in the bitmap now ..pault */
+ dxpBtn = bm.bmWidth / (btnMaxReal*2);
+ dypRuler = bm.bmHeight;
+
+ /* Position the buttons. */
+ for (prc = &rgrcRulerBtn[btn = btnMIN]; btn < btnMaxUsed; btn++, prc++)
+ {
+ prc->left = xp;
+ prc->top = 1;
+ prc->right = (xp += dxpBtn);
+ prc->bottom = bm.bmHeight + 1;
+ xp += (btn == btnTABMAX || btn == btnSPACEMAX) ? dxpMajor :
+ dxpMinor;
+ }
+
+ /* Get the width and height of the tab marks. */
+ GetObject(hbmMark, sizeof(BITMAP), (LPSTR)&bm);
+ dxpMark = bm.bmWidth / rmkMAX;
+ dypMark = bm.bmHeight;
+
+ /* Lastly, initialize the height of the ruler. (Four is for the two
+ lines at the bottom of the ruler plus two blank lines.) */
+ GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
+ dypRuler += dypMark + (tm.tmAscent - tm.tmInternalLeading) + 4;
+ }
+
+ /* Move the document window to make room for the ruler. */
+ pwwdCur->fRuler = TRUE;
+ dyp = dypRuler - (pwwdCur->ypMin - 1);
+ MoveWindow(wwdCurrentDoc.wwptr, 0, dyp, xpMac, ypMac - dyp, FALSE);
+
+ /* Erase the top of the document window. */
+ PatBlt(wwdCurrentDoc.hDC, 0, 0, xpMac, wwdCurrentDoc.ypMin, ropErase);
+ rc.left = rc.top = 0;
+ rc.right = xpMac;
+ rc.bottom = wwdCurrentDoc.ypMin;
+ ValidateRect(wwdCurrentDoc.wwptr, (LPRECT)&rc);
+ UpdateWindow(wwdCurrentDoc.wwptr);
+
+ /* Move the ruler into position. */
+ MoveWindow(vhWndRuler, 0, 0, xpMac, dypRuler, FALSE);
+ BringWindowToTop(vhWndRuler);
+
+ /* Set the DC to transparent mode. */
+ SetBkMode(vhDCRuler, TRANSPARENT);
+
+ /* Set the background and foreground colors for the ruler. */
+ SetBkColor(vhDCRuler, rgbBkgrnd);
+ SetTextColor(vhDCRuler, rgbText);
+
+ /* Set the brush and the pen for the ruler. */
+ SelectObject(vhDCRuler, hbrBkgrnd);
+ if ((hpen = CreatePen(0, 0, rgbText)) == NULL)
+ {
+ hpen = GetStockObject(BLACK_PEN);
+ }
+ SelectObject(vhDCRuler, hpen);
+
+ /* Lastly, ensure that the ruler is painted. */
+ ShowWindow(vhWndRuler, SHOW_OPENWINDOW);
+ UpdateWindow(vhWndRuler);
+ return (TRUE);
+
+Error1:
+ DestroyWindow(vhWndRuler);
+ vhWndRuler = NULL;
+Error2:
+ WinFailure();
+ return (FALSE);
+ }
+
+
+near DestroyRuler()
+ {
+ /* This routine destroys the ruler window and refreshes the screen. */
+
+ /* First, erase the ruler. */
+ PatBlt(vhDCRuler, 0, 0, dxpRuler, dypRuler, ropErase);
+
+ /* Clean up the ruler window. */
+ DestroyWindow(vhWndRuler);
+ vhWndRuler = NULL;
+ ResetRuler();
+
+ /* Move the document window back to the top of the window. */
+ pwwdCur->fRuler = FALSE;
+ vfEraseWw = TRUE;
+ MoveWindow(wwdCurrentDoc.wwptr, 0, 0, dxpRuler, wwdCurrentDoc.ypMac +
+ dypRuler - (wwdCurrentDoc.ypMin - 1), FALSE);
+ vfEraseWw = FALSE;
+
+ /* Validate the area in the document window above the text. */
+ PatBlt(wwdCurrentDoc.hDC, 0, 0, dxpRuler, wwdCurrentDoc.ypMin, ropErase);
+ ValidateRect(hParentWw, (LPRECT)NULL);
+ }
+
+
+UpdateRuler()
+ {
+ /* This routine will redraw as much of the ruler as necessary to reflect the
+ current selection. */
+
+ /* Only repaint the ruler if it exists and it is not currently being
+ changed. */
+ if (vhWndRuler != NULL)
+ {
+ RulerPaint(FALSE, FALSE, FALSE);
+ }
+ }
+
+ReframeRuler()
+ {
+ /* This routine will cause the ruler window to be redrawn,
+ when units change - leave update out, since dialog box
+ will repaint */
+
+ /* Only repaint the ruler if it exists . */
+ if (vhWndRuler != NULL)
+ {
+ InvalidateRect(vhWndRuler, (LPRECT)NULL, FALSE);
+ }
+ }
+
+
+
+ResetRuler()
+ {
+ /* Reset the values of the ruler buttons and the ruler margins and tabs so
+ they redrawn during the next paint message. */
+ if ((btnTabSave = mprlcbtnDown[rlcTAB]) == btnNIL)
+ {
+ btnTabSave = btnLTAB;
+ }
+
+ /* Reset the buttons. */
+ if (vfIconic)
+ {
+ /* All we have to do is reset our internal state. */
+ bltc(mprlcbtnDown, btnNIL, rlcBTNMAX);
+ }
+ else
+ {
+ /* We had best reset the buttons on the screen as well. */
+ UpdateRulerBtn(rlcTAB, btnNIL);
+ UpdateRulerBtn(rlcSPACE, btnNIL);
+ UpdateRulerBtn(rlcJUST, btnNIL);
+ }
+
+ /* Reset the margins and the tabs. */
+ bltc(mprmkdxa, -1, rmkMARGMAX);
+ bltc(rgtbdRuler, 0, cwTBD * itbdMax);
+ }
+
+
+ResetTabBtn()
+ {
+ /* This routine resets the tab button on the ruler to the left tab button.
+ */
+ if (mprlcbtnDown[rlcTAB] != btnLTAB)
+ {
+ UpdateRulerBtn(rlcTAB, btnLTAB);
+ }
+ }
+
+
+RulerPaint(fContentsOnly, fFrameOnly, fInit)
+BOOL fContentsOnly;
+BOOL fInit;
+ {
+ /* This routine draws the ruler in the ruler window. If fContentsOnly is
+ set, then only the tabs as they currently exist in rgtbdRuler, and the
+ button settings are drawn. If fFrameOnly is set, then only the ruler frame
+ is redrawn. If fInit is set, then the portion of the ruler to be redrawn
+ (tabs, frame or all) is redrawn from scratch. */
+
+
+ int xpMin = pwwdCur->xpMin;
+ HBITMAP hbm;
+
+ /* If fContentsOnly is set, then skip most of this stuff and draw only the
+ tabs and the button settings. */
+ if (!fContentsOnly)
+ {
+ /* We only need to draw the physical ruler itself when the window has
+ scrolled horizontally. */
+ if (fInit || xpMinCur != xpMin)
+ {
+ register int xp;
+ TEXTMETRIC tm;
+ int dypTick;
+ int ypTickEnd;
+ int ypTickStart;
+ int ypTick;
+ int iLevel;
+ CHAR rgchInch[3];
+ int dxpLogUnitInc;
+ int dcNextTick;
+ int dxpLine;
+
+
+ extern int utCur;
+#define cDivisionMax 8 /* max divisions per ruler unit. e.g. 8 per inch */
+ int rgypTick[cDivisionMax];
+ int cxpExtra;
+ int cDivision;
+ int dxpLogUnit;
+ int dxpMeas;
+ int ypT;
+
+ /* Initialize the y-coordinate of the ticks. */
+ GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
+ ypTickEnd = dypRuler - dypMark - 2;
+ ypTickStart = ypTick = ypTickEnd - (dypTick = tm.tmAscent -
+ tm.tmInternalLeading);
+
+ /* set up measurements for the ruler based on current unit -
+ note that only inch and cm are handled in this version */
+
+ if (utCur == utInch)
+ {
+ dxpLogUnit = dxpLogUnitInc = dxpLogInch;
+ cDivision = 8; /* # of divisions */
+ dxpMeas = dxpLogUnit >> 3; /* 1/8" units */
+ /* get extra pixels to distribute if not even multiple */
+ /* note - mod done by hand */
+ cxpExtra = dxpLogUnit - (dxpMeas << 3);
+ dcNextTick = 1;
+ /* fill table of tick lengths */
+ rgypTick[0] = ypT = ypTick;
+ rgypTick[4] = ypT += (dypTick >> 2);
+ rgypTick[2] = rgypTick[6] = ypT += (dypTick >> 2);
+ rgypTick[1] = rgypTick[3] = rgypTick[5] = rgypTick[7] =
+ ypT += (dypTick >> 2);
+ }
+ else
+ /* default to cm */
+ {
+ dxpLogUnit = dxpLogUnitInc = dxpLogCm;
+ cDivision = 2; /* # of divisions */
+ dxpMeas = dxpLogUnit >> 1; /* 1/2 cm units */
+ /* get extra pixels to distribute if not even multiple */
+ cxpExtra = dxpLogUnit - (dxpMeas << 1);
+ dcNextTick = 1;
+ /* fill table of tick lengths */
+ rgypTick[0] = ypTick;
+ rgypTick[1] = ypTick + (dypTick >> 1);
+ }
+
+ if (fInit)
+ {
+ /* Erase the area where the ruler will be drawn. */
+ PatBlt(vhDCRuler, 0, 0, dxpRuler, dypRuler, ropErase);
+
+ /* Draw a line across the bottom of the ruler. */
+ MoveTo(vhDCRuler, xpSelBar, dypRuler - 1);
+ LineTo(vhDCRuler, dxpRuler, dypRuler - 1);
+
+ /* Draw the base of the ruler. */
+ MoveTo(vhDCRuler, xpSelBar, ypTickEnd);
+ LineTo(vhDCRuler, dxpRuler, ypTickEnd);
+ }
+ else
+ {
+ /* Erase the old tick marks. */
+ PatBlt(vhDCRuler, 0, ypTickStart, dxpRuler, ypTickEnd -
+ ypTickStart, ropErase);
+ }
+
+ /* Set the clip region to be only the ruler. */
+ iLevel = SaveDC(vhDCRuler);
+ IntersectClipRect(vhDCRuler, xpSelBar, 0, dxpRuler, dypRuler);
+
+ /* Draw the ticks at the each division mark. */
+ /* iDivision is the current division with in a unit. It is
+ used to determine when extra pixels are distributed and
+ which tick mark to use */
+ {
+ register int iDivision = 0;
+
+ for (xp = (xpSelBar - xpMin); xp < dxpRuler; xp +=
+ dxpMeas)
+ {
+ /* distribute extra pixels at front */
+ if (iDivision < cxpExtra)
+ xp++;
+
+ MoveTo(vhDCRuler, xp, rgypTick[iDivision]);
+ LineTo(vhDCRuler, xp, ypTickEnd);
+
+ if (++iDivision == cDivision)
+ iDivision = 0;
+ }
+ }
+
+
+ /* Label the tick marks. */
+ dxpLine = GetSystemMetrics(SM_CXBORDER);
+ rgchInch[0] = rgchInch[1] = rgchInch[2] = '0';
+ for (xp = xpSelBar - xpMin;
+ xp < dxpRuler;
+ xp += dxpLogUnitInc, rgchInch[2] += dcNextTick)
+ {
+ int isz;
+ int dxpsz;
+
+ if (rgchInch[2] > '9')
+ {
+ rgchInch[1]++;
+ rgchInch[2] = '0' + (rgchInch[2] - (CHAR) ('9' + 1));
+ }
+ if (rgchInch[1] > '9')
+ {
+ rgchInch[0]++;
+ rgchInch[1] = '0' + (rgchInch[1] - (CHAR) ('9' + 1));
+ }
+ isz = rgchInch[0] == '0' ?
+ (rgchInch[1] == '0' ? 2 : 1):
+ 0;
+ dxpsz = LOWORD(GetTextExtent(vhDCRuler,
+ (LPSTR)&rgchInch[isz],
+ 3 - isz));
+ if (dxpsz + dxpLine >= dxpMeas)
+ {
+ PatBlt(vhDCRuler, xp + dxpLine, ypTickStart,
+ dxpsz, ypTickEnd - ypTickStart, ropErase);
+ }
+ TextOut(vhDCRuler, xp + dxpLine, ypTickStart -
+ tm.tmInternalLeading, (LPSTR)&rgchInch[isz],
+ 3 - isz);
+ }
+
+
+ /* Set the clip region back. */
+ RestoreDC(vhDCRuler, iLevel);
+ }
+
+ /* Draw the buttons on the ruler. */
+ if (fInit)
+ {
+ register PRECT prc = &rgrcRulerBtn[btnMIN];
+ int btn;
+
+ /* Ensure that we have the bitmap for the buttons. */
+ if (SelectObject(hMDCBitmap, hbmBtn) == NULL)
+ {
+ if (NULL == (hbmBtn = LoadBitmap(hMmwModInstance,
+ MAKEINTRESOURCE(idBmBtns+viBmRuler)))
+ || SelectObject(hMDCBitmap, hbmBtn) == NULL)
+ {
+ WinFailure();
+ goto NoBtns;
+ }
+ }
+
+ /* Now, draw the buttons. */
+ for (btn = btnMIN; btn < btnMaxUsed; btn++)
+ {
+ int dxpBtn = prc->right - prc->left;
+
+ BitBlt(vhDCRuler, prc->left, prc->top, dxpBtn, prc->bottom -
+ prc->top, hMDCBitmap, (btn - btnMIN) * dxpBtn, 0, vfMonochrome
+ ? MERGEMARK : SRCCOPY);
+ prc++;
+ }
+ SelectObject(hMDCBitmap, hbmNullRuler);
+NoBtns:;
+ }
+ }
+
+ /* If fFrame only is set, then we're finished. */
+ if (!fFrameOnly)
+ {
+ /* Lastly, draw the button settings, the margins and the tabs. */
+ TSV rgtsv[itsvparaMax];
+ register struct TBD *ptbd1;
+ int rmk;
+ int xpMarkMin = xpSelBar - (dxpMark >> 1);
+ int dxpMarkMax = dxpRuler - xpSelBar - (dxpMark >> 1);
+ unsigned dxa;
+
+ if (mprlcbtnDown[rlcTAB] == btnNIL)
+ {
+ /* Initalize the tab button to be left tab. */
+ UpdateRulerBtn(rlcTAB, btnTabSave);
+ }
+
+ /* Now for the spacing and justification. */
+ GetRgtsvPapSel(rgtsv);
+ UpdateRulerBtn(rlcSPACE, (rgtsv[itsvSpacing].fGray != 0) ? btnNIL :
+ (rgtsv[itsvSpacing].wTsv - czaLine) / (czaLine / 2) + btnSINGLE);
+ UpdateRulerBtn(rlcJUST, (rgtsv[itsvJust].fGray != 0) ? btnNIL :
+ (rgtsv[itsvJust].wTsv - jcLeft) + btnLEFT);
+
+ /* The margins and the tabs are based off of the first cp of the
+ selection. */
+ CacheSect(docCur, selCur.cpFirst);
+ CachePara(docCur, selCur.cpFirst);
+
+ /* If the window has scrolled horizontally or become wider, we must
+ redraw the margins and the tabs. */
+ if (!fInit && xpMinCur == xpMin)
+ {
+ /* Compare to see if the margins have changed. */
+ if (mprmkdxa[rmkINDENT] != vpapAbs.dxaLeft + vpapAbs.dxaLeft1)
+ {
+ goto DrawMargins;
+ }
+ if (mprmkdxa[rmkLMARG] != vpapAbs.dxaLeft)
+ {
+ goto DrawMargins;
+ }
+ if (mprmkdxa[rmkRMARG] != vsepAbs.dxaText - vpapAbs.dxaRight)
+ {
+ goto DrawMargins;
+ }
+
+ /* Compare to see if the tabs has changed. */
+ {
+ register struct TBD *ptbd2;
+
+ for (ptbd1 = &rgtbdRuler[0], ptbd2 = &vpapAbs.rgtbd[0];
+ ptbd1->dxa == ptbd2->dxa; ptbd1++, ptbd2++)
+ {
+ /* If the end of the list of tabs, then the lists are equal.
+ */
+ if (ptbd1->dxa == 0)
+ {
+ goto SkipTabs;
+ }
+
+ /* The justification codes must match if they are decimal
+ tabs (everything else collaspes to left tabs). */
+ if (ptbd1->jc != ptbd2->jc && (ptbd1->jc == (jcTabDecimal
+ - jcTabMin) || (ptbd2->jc == (jcTabDecimal - jcTabMin))))
+ {
+ goto DrawMargins;
+ }
+ }
+ }
+ }
+
+DrawMargins:
+#ifdef KINTL
+ /* This is really an extra. xpMinCur will get updated later on.
+ But, we need this variable set up right for the MergeRulerMark()
+ to draw a mark at the right place.... Oh well. */
+ xpMinCur = xpMin;
+#endif /* ifdef KINTL */
+
+ /* Redraw the margins from scratch. Set up the bitmap for hMDCScreen,
+ the ruler bar in monochrome format. */
+ if ((hbm = CreateBitmap(dxpRuler + dxpMark, dypMark, 1, 1,
+ (LPSTR)NULL)) == NULL)
+ {
+ WinFailure();
+ goto SkipTabs;
+ }
+ DeleteObject(SelectObject(hMDCScreen, hbm));
+ PatBlt(hMDCScreen, 0, 0, dxpRuler + dxpMark, dypMark, vfMonochrome ?
+ ropErase : WHITENESS);
+ PatBlt(vhDCRuler, 0, dypRuler - dypMark - 1, dxpRuler + dxpMark,
+ dypMark, ropErase);
+
+ /* Determine the margin positions. */
+ mprmkdxa[rmkINDENT] = vpapAbs.dxaLeft + vpapAbs.dxaLeft1;
+ mprmkdxa[rmkLMARG] = vpapAbs.dxaLeft;
+ mprmkdxa[rmkRMARG] = (vdxaTextRuler = vsepAbs.dxaText) -
+ vpapAbs.dxaRight;
+
+ /* Draw the margins marks. */
+ for (rmk = rmkMARGMIN; rmk < rmkMARGMAX; rmk++)
+ {
+ register int dxp = MultDiv(mprmkdxa[rmk], dxpLogInch, czaInch) -
+ xpMin;
+
+ /* If the margin mark would not appear on the ruler, scrolled off to
+ either end, then don't try to draw it. */
+ if (dxp >= 0 && dxp < dxpMarkMax)
+ {
+ MergeRulerMark(rmk, xpMarkMin + dxp, FALSE);
+ }
+ }
+
+ /* Redraw the tabs. */
+ ptbd1 = &rgtbdRuler[0];
+ if (!fInit)
+ {
+ /* If fInit is set, then rgtbdRuler is not changed. */
+ blt(vpapAbs.rgtbd, ptbd1, cwTBD * itbdMax);
+ }
+ while ((dxa = ptbd1->dxa) != 0)
+ {
+ register int dxp = MultDiv(dxa, dxpLogInch, czaInch) - xpMin;
+
+ /* If the tab mark would not appear on the ruler, scrolled off to
+ either end, then don't try to draw it. */
+ if (dxp >= 0 && dxp < dxpMarkMax)
+ {
+ MergeRulerMark(ptbd1->jc == (jcTabDecimal - jcTabMin) ? rmkDTAB
+ : rmkLTAB, xpMarkMin + dxp, FALSE);
+ }
+ ptbd1++;
+ }
+SkipTabs:;
+ }
+
+ /* Record the edges of the current window. */
+ xpMinCur = xpMin;
+ }
+
+
+RulerMouse(pt)
+POINT pt;
+ {
+ /* Process all mouse messages from a down-click at point pt until the
+ corresponding mouse up-click. */
+
+ int btn;
+ int rlc;
+ int rlcCur;
+ int rmkCur;
+ int xp;
+ int xpCur;
+ unsigned xa;
+ struct TBD *ptbd;
+ struct TBD tbd;
+ BOOL fMarkMove = FALSE;
+ BOOL fDeleteMark = FALSE;
+ BOOL fBtnChanged = FALSE;
+
+ if (!FWriteOk(fwcNil))
+ {
+ return;
+ }
+
+ /* Translate the point into a button group and a button. */
+ RulerStateFromPt(pt, &rlcCur, &btn);
+
+ /* Down clicking on the tab rule is a special case. */
+ if (rlcCur == rlcRULER)
+ {
+ unsigned dxa = MultDiv(pt.x - xpSelBar + xpMinCur, czaInch, dxpLogInch);
+ int rmk;
+ int itbd;
+
+ /* Have we moused down on a margin? */
+ for (rmk = rmkMARGMIN; rmk < rmkMARGMAX; rmk++)
+ {
+#ifdef KINTL
+ if (FPointNear(mprmkdxa[rmk], dxa - XaKickBackXa(dxa)))
+#else
+ if (FPointNear(mprmkdxa[rmk], dxa))
+#endif /* if-else-def KINTL */
+ {
+ int xpT;
+
+ /* Remember this mark and its position. */
+ rmkCur = rmk;
+ xpCur = xpSelBar + MultDiv(mprmkdxa[rmk], dxpLogInch, czaInch) -
+ (dxpMark >> 1) - xpMinCur;
+
+InvertMark:
+#ifdef KINTL
+ /* Adjust for the kick-backs. */
+ /* But don't modify the xpCur. */
+ xpT = xpCur + XpKickBackXp(xpCur);
+#else
+ xpT = xpCur;
+#endif /* if-else-def KINTL */
+
+ /* Time to invert the selected mark. */
+ PatBlt(vhDCRuler, xpT, dypRuler - dypMark - 1, dxpMark,
+ dypMark, DSTINVERT);
+ goto GotMark;
+ }
+ }
+
+ /* Have we moused down on an existing tab? */
+ for (itbd = 0, ptbd = &rgtbdRuler[0]; ; itbd++, ptbd++)
+ {
+ /* The end of the tabs have been found. */
+ if (ptbd->dxa == 0)
+ {
+ break;
+ }
+
+ /* Have we moused down on this tab? */
+#ifdef KINTL
+ if (FPointNear(ptbd->dxa, dxa - XaKickBackXa(dxa)))
+#else
+ if (FPointNear(ptbd->dxa, dxa))
+#endif /* if-else-def KANJI */
+ {
+ /* Save this tab descriptor and its location. */
+ tbd = *ptbd;
+ rmkCur = (tbd.jc + jcTabMin) == jcTabDecimal ? rmkDTAB :
+ rmkLTAB;
+ xpCur = xpSelBar + MultDiv(tbd.dxa, dxpLogInch, czaInch) -
+ (dxpMark >> 1) - xpMinCur;
+ goto InvertMark;
+ }
+ }
+
+ /* If one more tab would be too many, then beep and return. */
+ if (itbd >= itbdMax - 1)
+ {
+ _beep();
+ return;
+ }
+
+ /* Create a tab descriptor for this new tab. */
+ bltc(&tbd, 0, cwTBD);
+ tbd.dxa = XaQuantize(pt.x);
+ tbd.jc = (mprlcbtnDown[rlcTAB] == btnLTAB ? jcTabLeft : jcTabDecimal) -
+ jcTabMin;
+ rmkCur = (mprlcbtnDown[rlcTAB] - btnLTAB) + rmkLTAB;
+
+ /* A mark for the new tab needs to be drawn. */
+ MergeRulerMark(rmkCur, xpCur = xpSelBar + MultDiv(tbd.dxa, dxpLogInch,
+ czaInch) - (dxpMark >> 1) - xpMinCur, TRUE);
+
+ /* Inserting a tab is like moving an existing tab. */
+ fMarkMove = TRUE;
+
+GotMark:;
+
+#ifdef RULERALSO
+ /* Update dialog box */
+ if (vhDlgIndent && rmkCur < rmkMARGMAX)
+ {
+ SetIndentText(rmkCur, dxa);
+ }
+#endif /* RULERALSO */
+
+ }
+ else if (rlcCur != rlcNIL)
+ {
+ /* Otherwise, if a button has been selected, the reflect the change on
+ the ruler. */
+ UpdateRulerBtn(rlcCur, btn);
+ }
+ else
+ {
+ /* The user has moused down on nothing of importance. */
+ return;
+ }
+
+ /* Get all of the mouse events until further notice. */
+ SetCapture(vhWndRuler);
+
+ /* Process all of the mouse move messages. */
+ while (FStillDown(&pt))
+ {
+ /* Movement on the tab ruler must be handled special. */
+ if (rlcCur == rlcRULER)
+ {
+#ifdef KINTL
+ unsigned xaT;
+#endif /* ifdef KINTL */
+
+ /* Guarantee that xp is in the range xpSelBar <= xp <= dxpRuler. */
+ if ((xp = pt.x) > dxpRuler)
+ {
+ xp = dxpRuler;
+ }
+ else if (xp < xpSelBar)
+ {
+ xp = xpSelBar;
+ }
+
+ /* Convert the mouse position to twips. */
+#ifdef KINTL
+ if ((xa = XaQuantize(xp)) > (xaT = XaQuantizeXa(vdxaTextRuler))
+#else
+ if ((xa = XaQuantize(xp)) > vdxaTextRuler
+#endif /* if-else-def KINTL */
+ && rmkCur < rmkMARGMAX)
+ {
+ /* Margins are confined to the page. */
+#ifdef KINTL
+ xa = xaT;
+#else
+ xa = vdxaTextRuler;
+#endif
+ }
+
+ /* If the cursor is on the ruler, then we may move a tab, but we
+ always move the margins. */
+ if ((rmkCur < rmkMARGMAX) || (pt.y >= 0 && pt.y < dypRuler + dypMark
+ && xa != 0))
+ {
+ /* If the current mark has not moved, then there is nothing to
+ do. */
+ if (fDeleteMark || xa != XaQuantize(xpCur + (dxpMark >> 1)))
+ {
+ /* Indicate that the mark has moved. */
+ fMarkMove = TRUE;
+
+ /* Restore the screen under the current mark. */
+ if (!fDeleteMark)
+ {
+ MergeRulerMark(rmkCur, xpCur, FALSE);
+ }
+
+ /* Draw the mark at the new location. */
+ MergeRulerMark(rmkCur, xpCur = MultDiv(xa, dxpLogInch,
+ czaInch) + xpSelBar - xpMinCur - (dxpMark >> 1), TRUE);
+
+ /* Show this is a valid mark. */
+ fDeleteMark = FALSE;
+
+#ifdef RULERALSO
+ /* Update dialog box */
+ if (vhDlgIndent && rmkCur < rmkMARGMAX)
+ {
+ SetIndentText(rmkCur, xa);
+ }
+#endif /* RULERALSO */
+
+ }
+ }
+ else
+ {
+ /* Restore the screen under the current mark. */
+ if (!fDeleteMark)
+ {
+ MergeRulerMark(rmkCur, xpCur, FALSE);
+ }
+
+ /* This mark is being deleted. */
+ fDeleteMark = TRUE;
+ }
+ }
+ else
+ {
+ /* If the mouse is on a button within the same button group, then
+ reflect the change. */
+ RulerStateFromPt(pt, &rlc, &btn);
+ if (rlc == rlcCur)
+ {
+ UpdateRulerBtn(rlc, btn);
+ }
+ }
+ }
+
+ /* We are capturing all mouse events; we can now release them. */
+ ReleaseCapture();
+
+ /* Up-clicking on the tab ruler is a special case. */
+ if (rlcCur == rlcRULER)
+ {
+ if (!fDeleteMark)
+ {
+ /* Restore the screen under the current mark. */
+ MergeRulerMark(rmkCur, xpCur, FALSE);
+ }
+
+ if (fMarkMove)
+ {
+ /* Guarantee that xp is in the range xpSelBar <= xp <= dxpRuler. */
+ if ((xp = pt.x) > dxpRuler)
+ {
+ xp = dxpRuler;
+ }
+ else if (xp < xpSelBar)
+ {
+ xp = xpSelBar;
+ }
+ }
+ else
+ {
+ xp = xpCur + (dxpMark >> 1);
+ }
+
+ /* Convert the mouse position to twips. */
+ if ((xa = XaQuantize(xp)) > vdxaTextRuler && rmkCur < rmkMARGMAX)
+ {
+ /* Margins are confined to the page. */
+ xa = vdxaTextRuler;
+ }
+
+ /* If the cursor is on the ruler then we may insert/move a tab, but we
+ always move the margins. */
+ if ((rmkCur < rmkMARGMAX) || (pt.y >= 0 && pt.y < dypRuler + dypMark &&
+ xa != 0))
+ {
+ /* Draw the mark at the new location. */
+ MergeRulerMark(rmkCur, MultDiv(xa, dxpLogInch, czaInch) + xpSelBar -
+ xpMinCur - (dxpMark >> 1), FALSE);
+
+ /* We are moving one of the margins. */
+ if (rmkCur < rmkMARGMAX)
+ {
+ if (vfMargChanged = mprmkdxa[rmkCur] != xa)
+ {
+ mprmkdxa[rmkCur] = xa;
+ }
+
+#ifdef RULERALSO
+ /* Update dialog box */
+ if (vhDlgIndent)
+ {
+ SetIndentText(rmkCur, xa);
+ }
+#endif /* RULERALSO */
+
+ }
+
+ /* It is a tab we are inserting/deleting. */
+ else
+ {
+ tbd.dxa = xa;
+
+ /* Is this a new tab? */
+ if (ptbd->dxa == 0)
+ {
+ /* Insert the new tab. */
+ InsertRulerTab(&tbd);
+ }
+
+ /* We are moving a tab; if it hasn't really moved, then do
+ nothing. */
+ else if (!FCloseXa(ptbd->dxa, xa))
+ {
+ DeleteRulerTab(ptbd);
+ InsertRulerTab(&tbd);
+ }
+ }
+ }
+
+ /* We are deleting the tab; if its a new, there's nothing to do. */
+ else if (ptbd->dxa != 0)
+ {
+ DeleteRulerTab(ptbd);
+ }
+ }
+ else
+ {
+ /* If the mouse is on a button within the same button group, then
+ reflect the change. */
+
+ int btnT;
+
+ RulerStateFromPt(pt, &rlc, &btnT);
+ if (rlc == rlcCur)
+ {
+ UpdateRulerBtn(rlc, btn = btnT);
+ }
+ fBtnChanged = btn != mprlcbtnDown[btn];
+ }
+
+ /* Do the format only if a button changed */
+ if ((fBtnChanged && rlcCur != rlcTAB) || vfMargChanged || vfTabsChanged)
+ {
+ struct SEL selSave;
+ typeCP dcp;
+ typeCP dcp2;
+ CHAR rgb[1 + cchINT];
+ CHAR *pch;
+ int sprm;
+ int val;
+ struct TBD (**hgtbd)[];
+
+ /* Set the selection to cover all of the paragraphs selected. */
+ ExpandCurSel(&selSave);
+ dcp2 = (dcp = selCur.cpLim - selCur.cpFirst) - (selCur.cpLim > cpMacCur
+ ? ccpEol : 0);
+ SetUndo(uacRulerChange, docCur, selCur.cpFirst, (rlcCur != rlcRULER ||
+ rmkCur < rmkMARGMAX) ? dcp : dcp2, docNil, cpNil, dcp2, 0);
+
+ /* Set the sprm and it's value for the ruler change. */
+ switch (rlcCur)
+ {
+ case rlcSPACE:
+ sprm = sprmPDyaLine;
+ val = (mprlcbtnDown[rlcSPACE] - btnSINGLE) * (czaLine / 2) +
+ czaLine;
+ break;
+
+ case rlcJUST:
+ sprm = sprmPJc;
+ val = mprlcbtnDown[rlcJUST] - btnLEFT + jcLeft;
+ break;
+
+ case rlcRULER:
+ switch (rmkCur)
+ {
+ case rmkINDENT:
+ sprm = sprmPFIndent;
+ val = mprmkdxa[rmkINDENT] - mprmkdxa[rmkLMARG];
+ break;
+
+ case rmkLMARG:
+ /* Changing the left margin changes the first indent as well.
+ First, the indent... */
+ val = mprmkdxa[rmkINDENT] - mprmkdxa[rmkLMARG];
+ pch = &rgb[0];
+ *pch++ = sprmPFIndent;
+ bltbyte(&val, pch, cchINT);
+ AddOneSprm(rgb, FALSE);
+
+ /* Now for the left margin... */
+ sprm = sprmPLMarg;
+ val = mprmkdxa[rmkLMARG];
+ break;
+
+ case rmkRMARG:
+ sprm = sprmPRMarg;
+ val = vdxaTextRuler - mprmkdxa[rmkRMARG];
+ break;
+
+ case rmkLTAB:
+ case rmkDTAB:
+ /* Tabs are different. The change is made by blting the new tab
+ table on top of the old. */
+ vfTabsChanged = FALSE;
+ if ((hgtbd = (**hpdocdod)[docCur].hgtbd) == NULL)
+ {
+ if (FNoHeap(hgtbd = (struct TBD (**)[])HAllocate(itbdMax *
+ cwTBD)))
+ {
+ return;
+ }
+ (**hpdocdod)[docCur].hgtbd = hgtbd;
+ }
+ blt(rgtbdRuler, *hgtbd, itbdMax * cwTBD);
+
+ /* Changing the tabs makes everything dirty. */
+ (**hpdocdod)[docCur].fDirty = TRUE;
+ vdocParaCache = docNil;
+ TrashAllWws();
+ goto ChangeMade;
+ }
+
+ /* Indicate that the margins have been set. */
+ vfMargChanged = FALSE;
+ }
+
+ /* Now, lets set the sprm to the new value. */
+ pch = &rgb[0];
+ *pch++ = sprm;
+ bltbyte(&val, pch, cchINT);
+ AddOneSprm(rgb, FALSE);
+
+ChangeMade:
+ /* Reset the selection to it's old value. */
+ EndLookSel(&selSave, TRUE);
+ }
+ }
+
+
+near RulerStateFromPt(pt, prlc, pbtn)
+POINT pt;
+int *prlc;
+int *pbtn;
+ {
+ /* This routine return in *prlc and *pbtn, the button group and the button
+ at point pt. The only button in group rlcRULER is btnNIL. */
+
+ int btn;
+
+ /* First check if the point is in a button. */
+ for (btn = btnMIN; btn < btnMaxUsed; btn++)
+ {
+ if (PtInRect((LPRECT)&rgrcRulerBtn[btn], pt))
+ {
+ goto ButtonFound;
+ }
+ }
+
+ /* The point is either on the tab ruler or nowhere of any interest. */
+ *prlc = (pt.y >= dypRuler - dypMark - 2 && pt.x > xpSelBar - (dxpMark >> 1)
+ && pt.x < dxpRuler + (dxpMark >> 1)) ? rlcRULER : rlcNIL;
+ *pbtn = btnNIL;
+ return;
+
+ButtonFound:
+ /* The point is in a button, we just have to decide which button group. */
+ switch (btn)
+ {
+ case btnLTAB:
+ case btnDTAB:
+ *prlc = rlcTAB;
+ break;
+
+ case btnSINGLE:
+ case btnSP15:
+ case btnDOUBLE:
+ *prlc = rlcSPACE;
+ break;
+
+ case btnLEFT:
+ case btnCENTER:
+ case btnRIGHT:
+ case btnJUST:
+ *prlc = rlcJUST;
+ break;
+ }
+ *pbtn = btn;
+ }
+
+
+void near HighlightButton(fOn, btn)
+BOOL fOn; /* true if we should highlight this button, false = unhighlight */
+int btn;
+ {
+ register PRECT prc = &rgrcRulerBtn[btn];
+ int dxpBtn = prc->right - prc->left;
+
+ /* If we're highlighting, then get the black-on-white button from
+ the right group; otherwise copy the white-on-black button ..pt */
+ int btnFromBM = btn - btnMIN + (fOn ? btnMaxReal : 0);
+
+ /* Ensure that we have the bitmap for the buttons. */
+ if (SelectObject(hMDCBitmap, hbmBtn) == NULL)
+ {
+ if ((hbmBtn = LoadBitmap(hMmwModInstance, MAKEINTRESOURCE(idBmBtns+viBmRuler))) ==
+ NULL || SelectObject(hMDCBitmap, hbmBtn) == NULL)
+ {
+ WinFailure();
+ goto NoBtns;
+ }
+ }
+
+ BitBlt(vhDCRuler, prc->left, prc->top, dxpBtn, prc->bottom - prc->top,
+ hMDCBitmap, btnFromBM * dxpBtn, 0, SRCCOPY);
+
+ SelectObject(hMDCBitmap, hbmNullRuler);
+NoBtns:;
+ }
+
+
+near UpdateRulerBtn(rlc, btn)
+int rlc;
+int btn;
+ {
+ /* This routine turns off the currently selected button in button group rlc
+ and turns on button btn. It is assumed that rlc is neither rlcNIL nor
+ rlcRULER, since neither group has buttons to update. */
+
+ int *pbtnOld = &mprlcbtnDown[rlc];
+ int btnOld = *pbtnOld;
+
+ Assert(rlc != rlcNIL && rlc != rlcRULER);
+
+ /* If the button hasn't changed, then there is nothing to do. */
+ if (btn != btnOld)
+ {
+ if (vhDCRuler != NULL)
+ {
+ /* Invert the old button (back to normal), and then invert the new
+ button. */
+ if (btnOld != btnNIL)
+ {
+ /* If there is no old button, then, of course, we can't invert
+ it. */
+ HighlightButton(fFalse, btnOld);
+ }
+
+ if (btn != btnNIL)
+ {
+ /* If the new button is not btnNIL, then invert it. */
+ HighlightButton(fTrue, btn);
+ }
+ }
+
+ /* Record whic button is now set. */
+ *pbtnOld = btn;
+ }
+ }
+
+#ifdef KINTL
+/* Given xa for a mouse position in a ruler, return the amount of xa for
+ a display adjustment. */
+unsigned near XaKickBackXa(xa)
+ unsigned xa;
+{
+ extern int utCur;
+ extern int dxaAdjustPerCm;
+ int cCm, cCh;
+
+ switch (utCur) {
+ case utCm:
+ cCm = xa / czaCm;
+ return (dxaAdjustPerCm * cCm);
+ case utInch:
+ return (0);
+ default:
+ Assert(FALSE);
+ return (0);
+ }
+}
+
+near XpKickBackXp(xp)
+ int xp;
+{
+ /* Computes the amount of a necessary kick-back in xp, if
+ a ruler marker is to be drawn at a given xp. */
+ extern int utCur;
+ extern int dxaAdjustPerCm;
+
+ int cCm, cCh;
+
+ switch (utCur) {
+ case utInch:
+ return 0;
+ case utCm:
+ /* For every cm, we are off by dxaAdjustPerCm twips. */
+ cCm = (xp - xpSelBar + xpMinCur + (dxpMark >> 1)) / dxpLogCm;
+ return (MultDiv(dxaAdjustPerCm * cCm, dxpLogInch, czaInch));
+ default:
+ Assert(FALSE);
+ return 0;
+ }
+}
+#endif /* ifdef KINTL */
+
+
+near MergeRulerMark(rmk, xpMark, fHighlight)
+int rmk;
+int xpMark;
+BOOL fHighlight;
+ {
+ /* This routine merges the ruler mark, rmk, with the contents of the ruler
+ bar at xpMark. To accomodate color, the merging of the mark with the
+ background must be done first in a monochrome memory bitmap, then converted
+ back to color. The mark is highlighed if fHighlight is set. */
+
+ int ypMark = dypRuler - dypMark - 1;
+
+ /* Ensure that we have the bitmap for the ruler marks. */
+ if (SelectObject(hMDCBitmap, hbmMark) == NULL)
+ {
+ if ((hbmMark = LoadBitmap(hMmwModInstance, MAKEINTRESOURCE(idBmMarks+viBmRuler))) == NULL
+ || SelectObject(hMDCBitmap, hbmMark) == NULL)
+ {
+ WinFailure();
+ return;
+ }
+ }
+
+#ifdef KINTL
+ /* Adjust for the kick back */
+ xpMark += XpKickBackXp(xpMark);
+#endif /* ifdef KINTL */
+
+ /* Merge the mark into the monochrome bitmap. */
+ BitBlt(hMDCScreen, xpMark, 0, dxpMark, dypMark, hMDCBitmap, (rmk - rmkMIN) *
+ dxpMark, 0, MERGEMARK);
+
+ /* Display the bitmap on the ruler bar. */
+ BitBlt(vhDCRuler, xpMark, ypMark, dxpMark, dypMark, hMDCScreen, xpMark, 0,
+ fHighlight ? NOTSRCCOPY : SRCCOPY);
+
+ SelectObject(hMDCBitmap, hbmNullRuler);
+ }
+
+
+BOOL near FPointNear(xaTarget, xaProbe)
+unsigned xaTarget;
+unsigned xaProbe;
+ {
+ /* This routine returns TRUE if and only if xaProbe is sufficiently close to
+ xaTarget for selection purposes. */
+
+ int dxa;
+
+ if ((dxa = xaTarget - xaProbe) < 0)
+ {
+ dxa = -dxa;
+ }
+ return (dxa < MultDiv(dxpMark, czaInch, dxpLogInch) >> 1);
+ }
+
+
+unsigned near XaQuantize(xp)
+int xp;
+ {
+#ifdef KINTL
+ /* This routine converts an x-coordinate from the ruler to twips
+ rounding it to the nearest sixteenth of an inch if utCur = utInch,
+ or to the nearest eighth of a centimeter if utCur = utCm. */
+ unsigned xa = MultDiv(xp - xpSelBar + xpMinCur, czaInch, dxpLogInch);
+ return (XaQuantizeXa(xa));
+#else
+ /* This routine converts an x-coordinate from the ruler to twips rounding it
+ to the nearest sixteenth of an inch. */
+
+ unsigned xa = MultDiv(xp - xpSelBar + xpMinCur, czaInch, dxpLogInch);
+
+ /* NOTE: This code has been simplified because we "know" czaInch is a
+ multiple of 32. */
+ return ((xa + czaInch / 32) / (czaInch / 16) * (czaInch / 16));
+#endif /* not KINTL */
+ }
+
+#ifdef KINTL
+unsigned near XaQuantizeXa(xa)
+ unsigned xa;
+{
+ extern int utCur;
+ long xaL;
+
+ switch (utCur) {
+ case utInch:
+ /* NOTE: This code has been simplified because we "know" czaInch is a
+ multiple of 32. */
+ return ((xa + czaInch / 32) / (czaInch / 16) * (czaInch / 16));
+ case utCm:
+ /* NOTE: Actually, we are calculating:
+ (xa + czaCm / 16) / (czaCm / 8) * (czaCm / 8)
+ but calculated in 16*twips, so that there will
+ be the least rounding error. */
+ xaL = ((long) xa) << 4;
+ xaL = (xaL + czaCm) / (czaCm << 1) * (czaCm << 1);
+ /* Kick back is adjusted in MergeRulerMark. */
+ return ((unsigned) (xaL >> 4));
+ default:
+ Assert(FALSE);
+ return (xa); /* Heck, it's better than nothing. */
+ }
+}
+#endif /* KINTL */
+
+
+near DeleteRulerTab(ptbd)
+struct TBD *ptbd;
+ {
+ /* This routine removes the tab at ptbd from its table. */
+
+ vfTabsChanged = TRUE;
+ do
+ {
+ *ptbd = *(ptbd + 1);
+ }
+ while ((ptbd++)->dxa != 0);
+ }
+
+
+near InsertRulerTab(ptbd)
+struct TBD *ptbd;
+ {
+ /* This routine inserts the tab *ptbd into rgtbdRuler unless there is one
+ close to it already. */
+
+ register struct TBD *ptbdT;
+ unsigned dxa = ptbd->dxa;
+ unsigned dxaT;
+
+ /* Search the table for a tab that is close to the tab to be inserted. */
+ for (ptbdT = &rgtbdRuler[0]; ptbdT->dxa != 0; ptbdT++)
+ {
+ if (FCloseXa(ptbdT->dxa, dxa))
+ {
+ /* Overwrite the old tab iff the tab has changed. */
+ if (ptbdT->jc != ptbd->jc)
+ {
+ *ptbdT = *ptbd;
+ vfTabsChanged = TRUE;
+ }
+
+ /* Clean up the ruler and exit. */
+ RulerPaint(TRUE, FALSE, TRUE);
+ return;
+ }
+ }
+
+ vfTabsChanged = TRUE;
+
+ /* Insert the tab at the correctly sorted place. */
+ for (ptbdT = &rgtbdRuler[0]; (dxaT = ptbdT->dxa) != 0; ptbdT++)
+ {
+ if (dxa <= dxaT)
+ {
+ /* Insert the tab in front of ptbdT and move the remaining tabs up
+ one slot. The last tab will be overwritten to avoid table overflow.
+ */
+ blt(ptbdT, ptbdT + 1, ((&rgtbdRuler[0] - ptbdT) + (itbdMax - 2)) *
+ cwTBD);
+ *ptbdT = *ptbd;
+ return;
+ }
+ }
+
+ /* Insert the tab at the end of the table unless the table is full. */
+ if (ptbdT - &rgtbdRuler[0] < itbdMax - 1)
+ {
+ *ptbdT = *ptbd;
+ (ptbdT + 1)->dxa = 0;
+ }
+ }
+
+
+BOOL near FCloseXa(xa1, xa2)
+unsigned xa1;
+unsigned xa2;
+ {
+#ifdef KINTL
+ /* This function returns TRUE if xa1 is "close" to xa2;
+ FALSE otherwise. Threshold is determined by utCur. */
+ int dxa;
+ int dxaThreshold;
+
+ extern int utCur;
+
+ if ((dxa = xa1 - xa2) < 0)
+ {
+ dxa = -dxa;
+ }
+ switch (utCur) {
+ case utInch:
+ dxaThreshold = czaInch / 16;
+ break;
+ case utCm:
+ dxaThreshold = czaCm / 8;
+ break;
+ default:
+ Assert(FALSE);
+ dxaThreshold = 0; /* Heck. It doesn't matter at this point. */
+ break;
+ }
+ return (dxa < dxaThreshold);
+#else /* not KINTL */
+ /* This function returns TRUE if xa1 is "close" to xa2; FALSE otherwise. */
+
+ int dxa;
+
+ if ((dxa = xa1 - xa2) < 0)
+ {
+ dxa = -dxa;
+ }
+ return (dxa < czaInch / 16);
+#endif /* not KINTL */
+ }
+
+
+
+#ifdef DEBUG
+RulerMarquee()
+ {
+ /* This routine displays and scrolls the "marquee" message in the ruler mark
+ area. */
+
+ static CHAR szMarquee[] = "Dz}w|d`3Dazgv3{r`3qvv}3qa|ft{g3g|3j|f3qj3Q|q?3Q|q?3Qajr}?3P{z>P{fv}?3r}w3Crg";
+ LOGFONT lf;
+ HFONT hf;
+ HFONT hfOld;
+
+ /* Decode the marquee message. */
+ if (szMarquee[0] == 'D')
+ {
+ int ich;
+
+ for (ich = 0; ich < sizeof(szMarquee) - 1; ich++)
+ {
+ szMarquee[ich] ^= 0x13;
+ }
+ }
+
+ /* Get a logical font that will fit in the ruler mark area. */
+ bltbc(&lf, 0, sizeof(LOGFONT));
+ lf.lfHeight = -dypMark;
+ lf.lfPitchAndFamily = FIXED_PITCH;
+
+ /* Can we create such a font. */
+ if ((hf = CreateFontIndirect(&lf)) != NULL)
+ {
+ if ((hfOld = SelectObject(vhDCRuler, hf)) != NULL)
+ {
+ int xp;
+ int yp = dypRuler - dypMark - 1;
+ int dxp = LOWORD(GetTextExtent(vhDCRuler, (LPSTR)szMarquee,
+ sizeof(szMarquee) - 1));
+ int dxpScroll = MultDiv(GetSystemMetrics(SM_CXSCREEN), dypMark,
+ 2048);
+ int iLevel;
+ TEXTMETRIC tm;
+
+ /* Erase what is in the ruler mark area. */
+ PatBlt(vhDCRuler, 0, yp, dxpRuler, dypMark, ropErase);
+
+ /* Scroll the marquee across the screen. */
+ iLevel = SaveDC(vhDCRuler);
+ IntersectClipRect(vhDCRuler, xpSelBar, yp, dxpRuler, dypRuler - 1);
+ GetTextMetrics(vhDCRuler, (LPTEXTMETRIC)&tm);
+ for (xp = dxpRuler; xp > xpSelBar - dxp; xp -= dxpScroll)
+ {
+ BitBlt(vhDCRuler, xp, yp, min(dxpRuler - (xp + dxpScroll), dxp),
+ dypMark, vhDCRuler, xp + dxpScroll, yp, SRCCOPY);
+ PatBlt(vhDCRuler, min(dxpRuler - dxpScroll, xp + dxp), yp,
+ dxpScroll, dypMark, ropErase);
+ if (xp + dxp >= dxpRuler)
+ {
+ int dxpch = (dxpRuler - xp) % tm.tmAveCharWidth;
+ int ich = (dxpRuler - xp) / tm.tmAveCharWidth;
+
+ if (dxpch == 0 && xp < dxpRuler)
+ {
+ dxpch = tm.tmAveCharWidth;
+ ich--;
+ }
+ TextOut(vhDCRuler, dxpRuler - dxpch, yp -
+ tm.tmInternalLeading, (LPSTR)&szMarquee[ich], 1);
+ }
+ }
+ RestoreDC(vhDCRuler, iLevel);
+
+ /* Cleanup the font and the screen. */
+ SelectObject(vhDCRuler, hfOld);
+ RulerPaint(TRUE, FALSE, TRUE);
+ }
+ DeleteObject(hf);
+ }
+ }
+#endif
diff --git a/private/mvdm/wow16/write/ruler2.c b/private/mvdm/wow16/write/ruler2.c
new file mode 100644
index 000000000..6cfb89918
--- /dev/null
+++ b/private/mvdm/wow16/write/ruler2.c
@@ -0,0 +1,88 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains routines that change dialog boxes or the menu for the
+ruler. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#include <windows.h>
+#include "mw.h"
+#include "menudefs.h"
+#include "str.h"
+
+
+extern HMENU vhMenu;
+extern CHAR stBuf[256];
+extern int utCur;
+
+SetRulerMenu(fShowRuler)
+BOOL fShowRuler;
+ {
+ /* This routine puts "Ruler On" into the menu if fShowRuler is true; else,
+ "Ruler Off" is put into the menu. */
+
+ FillStId(stBuf, fShowRuler ? IDSTRShowRuler : IDSTRHideRuler, sizeof(stBuf));
+ ChangeMenu(vhMenu, imiShowRuler, (LPSTR)&stBuf[1], imiShowRuler, MF_CHANGE);
+ }
+
+
+#ifdef RULERALSO
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "rulerdef.h"
+#include "dlgdefs.h"
+
+extern HWND vhDlgIndent;
+extern int mprmkdxa[];
+extern int vdxaTextRuler;
+
+SetIndentText(rmk, dxa)
+int rmk; /* ruler mark */
+unsigned dxa;
+ {
+ /* This routine reflects the changes made on the ruler in the Indentd dialog
+ box. */
+
+ unsigned dxaShow;
+ int idi;
+ CHAR sz[cchMaxNum];
+ CHAR *pch = &sz[0];
+
+ /* Get the dialog item number and the measurement. */
+ switch (rmk)
+ {
+ case rmkLMARG:
+ dxaShow = dxa;
+ idi = idiParLfIndent;
+ break;
+
+ case rmkINDENT:
+ dxaShow = dxa - mprmkdxa[rmkLMARG];
+ idi = idiParFirst;
+ break;
+
+ case rmkRMARG:
+ dxaShow = vdxaTextRuler - dxa;
+ idi = idiParRtIndent;
+ break;
+ }
+ CchExpZa(&pch, dxaShow, utCur, cchMaxNum);
+ SetDlgItemText(vhDlgIndent, idi, (LPSTR)sz);
+
+ if (rmk == rmkLMARG)
+ {
+ /* If the left indent changes, then we need to update the first line
+ indent. */
+ dxaShow = mprmkdxa[rmkINDENT] - dxaShow;
+ pch = sz;
+ CchExpZa(&pch, dxaShow, utCur, cchMaxNum);
+ idi = idiParFirst;
+ SetDlgItemText(vhDlgIndent, idi, (LPSTR)sz);
+ }
+ }
+#endif /* RULERALSO */
diff --git a/private/mvdm/wow16/write/ruler3.c b/private/mvdm/wow16/write/ruler3.c
new file mode 100644
index 000000000..8320e456b
--- /dev/null
+++ b/private/mvdm/wow16/write/ruler3.c
@@ -0,0 +1,113 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* The file contains the message handler for the ruler. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOCLIPBOARD
+#define NOMENUS
+#define NOCTLMGR
+#include <windows.h>
+
+extern HBITMAP hbmNull;
+
+extern HWND vhWndRuler;
+extern HDC vhDCRuler;
+extern HDC hMDCBitmap;
+extern HDC hMDCScreen;
+extern HBITMAP hbmBtn;
+extern HBITMAP hbmMark;
+extern HBITMAP hbmNullRuler;
+extern int dxpRuler;
+extern int dypRuler;
+
+
+long FAR PASCAL RulerWndProc(hWnd, message, wParam, lParam)
+HWND hWnd;
+unsigned message;
+WORD wParam;
+LONG lParam;
+ {
+ /* This routine processes the messages sent to the ruler window. */
+
+ extern vfCloseFilesInDialog;
+
+ PAINTSTRUCT ps;
+
+ switch (message)
+ {
+ case WM_PAINT:
+ /* Time for the ruler to draw itself. */
+ ResetRuler();
+ BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
+ RulerPaint(FALSE, TRUE, TRUE);
+ EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
+ RulerPaint(TRUE, FALSE, FALSE);
+ break;
+
+ case WM_SIZE:
+ /* We are saving the length of the ruler; we already know it's
+ height. */
+ dxpRuler = MAKEPOINT(lParam).x;
+ break;
+
+ case WM_DESTROY:
+ /* Destroy the ruler window. */
+ if (hMDCBitmap != NULL)
+ {
+ DeleteDC(hMDCBitmap);
+ }
+ if (hMDCScreen != NULL)
+ {
+ DeleteObject(SelectObject(hMDCScreen, hbmNull));
+ DeleteDC(hMDCScreen);
+ }
+ if (vhDCRuler != NULL)
+ {
+ DeleteObject(SelectObject(vhDCRuler,
+ GetStockObject(SYSTEM_FONT)));
+ SelectObject(vhDCRuler, GetStockObject(WHITE_BRUSH));
+ DeleteObject(SelectObject(vhDCRuler,
+ GetStockObject(BLACK_PEN)));
+ ReleaseDC(vhWndRuler, vhDCRuler);
+ }
+ if (hbmNullRuler != NULL)
+ {
+ DeleteObject(hbmNullRuler);
+ hbmNullRuler = NULL;
+ }
+ vhDCRuler = hMDCScreen = hMDCBitmap = NULL;
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ /* Process mouse events on the ruler. */
+ RulerMouse(MAKEPOINT(lParam));
+ break;
+
+#ifdef DEBUG
+ case WM_RBUTTONDBLCLK:
+ /* This the trap door that displays the "marquee" message. */
+ if (wParam & MK_SHIFT && wParam & MK_CONTROL)
+ {
+ RulerMarquee();
+ break;
+ }
+#endif
+
+ default:
+ /* All of the messages we are not interested in. */
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ break;
+ }
+
+ if (vfCloseFilesInDialog)
+ CloseEveryRfn( FALSE );
+
+ /* A window procedure should always return something. */
+ return (0L);
+ }
diff --git a/private/mvdm/wow16/write/rulerdef.h b/private/mvdm/wow16/write/rulerdef.h
new file mode 100644
index 000000000..04653d2e8
--- /dev/null
+++ b/private/mvdm/wow16/write/rulerdef.h
@@ -0,0 +1,52 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+/* These statments define indexes into the ruler button table. They must agree
+with the order the bitmaps are read in mmw.c. */
+
+#define btnNIL (-1)
+#define btnMIN 0
+#define btnLTAB 0
+#define btnDTAB 1
+#define btnTABMAX 1
+#define btnSINGLE 2
+#define btnSP15 3
+#define btnDOUBLE 4
+#define btnSPACEMAX 4
+#define btnLEFT 5
+#define btnCENTER 6
+#define btnRIGHT 7
+#define btnJUST 8
+
+/* Whereas Write 2.x inverted the above-mentioned buttons, the Write 3.x
+ buttons have been changed to have rounded corners so can't do that.
+ Instead we "follow" the first 8 buttons with 8 more that are "filled-in"
+ so we blt back and forth between the two ..pault 7/7/89 */
+
+#define btnMaxReal 9
+#define btnMaxUsed 9
+
+/* These statements define the different type of places a mouse might button
+down on the ruler. */
+#define rlcNIL (-1)
+#define rlcTAB 0
+#define rlcSPACE 1
+#define rlcJUST 2
+#define rlcRULER 3
+#define rlcBTNMAX 3
+#define rlcMAX 4
+
+/* These statements define the different types of marks that can appear on the
+ruler. */
+#define rmkMIN 0
+#define rmkMARGMIN 0
+#define rmkINDENT 0
+#define rmkLMARG 1
+#define rmkRMARG 2
+#define rmkMARGMAX 3
+#define rmkLTAB 3
+#define rmkDTAB 4
+#define rmkMAX 5
+
diff --git a/private/mvdm/wow16/write/running.c b/private/mvdm/wow16/write/running.c
new file mode 100644
index 000000000..da63fa010
--- /dev/null
+++ b/private/mvdm/wow16/write/running.c
@@ -0,0 +1,692 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* running.c -- code to handle editing of running header and footer */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+//#define NOATOM
+//#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "machdefs.h"
+#define NOKCCODES
+#include "ch.h"
+#include "docdefs.h"
+#include "cmddefs.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "prmdefs.h"
+#include "wwdefs.h"
+#include "dlgdefs.h"
+#include "menudefs.h"
+#include "str.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+
+int NEAR EditHeaderFooter();
+
+ /* Current allowable cp range for display/edit/scroll */
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+
+extern struct DOD (**hpdocdod)[];
+extern struct WWD rgwwd[];
+extern int docCur;
+extern int docScrap;
+extern int vfSeeSel;
+extern struct SEL selCur;
+extern struct PAP vpapAbs;
+extern struct SEP vsepNormal;
+extern HANDLE vhWnd;
+extern HANDLE hMmwModInstance;
+extern HANDLE hParentWw;
+#ifdef INEFFLOCKDOWN
+extern FARPROC lpDialogRunningHead;
+#else
+BOOL far PASCAL DialogRunningHead(HWND, unsigned, WORD, LONG);
+FARPROC lpDialogRunningHead = NULL;
+#endif
+extern HANDLE vhDlgRunningHead;
+extern CHAR stBuf[255];
+extern int utCur;
+extern int ferror;
+extern int vccpFetch;
+extern int vcchFetch;
+extern CHAR *vpchFetch;
+extern struct CHP vchpFetch;
+extern typeCP vcpLimParaCache;
+extern HWND vhWndMsgBoxParent;
+
+ /* Min, Max cp's for header, footer */
+typeCP cpMinHeader=cp0;
+typeCP cpMacHeader=cp0;
+typeCP cpMinFooter=cp0;
+typeCP cpMacFooter=cp0;
+
+ /* Min cp for document less header, footer */
+ /* Header & footer always appear at the beginning */
+typeCP cpMinDocument=cp0;
+
+ /* The following variables are used in this module only */
+
+#define cchWinTextSave 80
+static CHAR (**hszWinTextSave)[]=NULL;
+static struct PAP *ppapDefault;
+
+ /* cpFirst and selection are saved in these during header/footer edit */
+typeCP cpFirstDocSave;
+struct SEL selDocSave;
+
+
+HWND vhDlgRunning;
+
+
+
+fnEditRunning(imi)
+{ /* Enter mode so that user is editing the current document's
+ running header or footer in the same window as he was editing
+ the document, with the header/footer info in the dialog box
+ NOT currently in focus ..pault */
+
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogRunningHead)
+ if (!(lpDialogRunningHead = MakeProcInstance(DialogRunningHead, hMmwModInstance)))
+ {
+ WinFailure();
+ return;
+ }
+#endif
+
+ Assert(imi == imiHeader || imi == imiFooter);
+
+ if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
+ {
+ SetFocus(vhDlgRunningHead);
+ return;
+ }
+
+ if (imi == imiHeader)
+ wwdCurrentDoc.fEditHeader = TRUE;
+ else
+ wwdCurrentDoc.fEditFooter = TRUE;
+
+ EditHeaderFooter();
+ if (ferror)
+ { /* Not enough memory to stabilize the running head environs */
+ if (wwdCurrentDoc.fEditHeader)
+ wwdCurrentDoc.fEditHeader = FALSE;
+ else
+ wwdCurrentDoc.fEditFooter = FALSE;
+ return;
+ }
+ vhDlgRunningHead = CreateDialog(hMmwModInstance,
+ MAKEINTRESOURCE(wwdCurrentDoc.fEditHeader ?
+ dlgRunningHead : dlgFooter),
+ hParentWw, lpDialogRunningHead);
+ if (vhDlgRunningHead)
+ {
+ SetFocus(wwdCurrentDoc.wwptr);
+ }
+ else
+ { /* recover and bail out */
+ fnEditDocument();
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+}
+
+
+
+int NEAR EditHeaderFooter()
+{ /* Setup for edit of header or footer */
+ extern HWND hParentWw;
+
+ int fHeader=wwdCurrentDoc.fEditHeader;
+ CHAR szWinTextSave[ cchWinTextSave ];
+ typeCP cpFirst;
+ typeCP cpLim;
+#ifdef DEBUG
+ /* TEST Assumption: No changes take place in running head/foot cp range
+ during an interval in which no head/foot edits take place */
+ typeCP cpMinDocT=cpMinDocument;
+
+ ValidateHeaderFooter( docCur );
+ Assert( cpMinDocT == cpMinDocument );
+#endif
+
+ if (fHeader)
+ {
+ cpFirst = cpMinHeader;
+ cpLim = cpMacHeader;
+ }
+ else
+ {
+ cpFirst = cpMinFooter;
+ cpLim = cpMacFooter;
+ }
+
+ Assert( wwdCurrentDoc.fEditHeader != wwdCurrentDoc.fEditFooter );
+
+ /* Save the cpFirst of the document window so we get a clean
+ transition back to where we were in the document*/
+ cpFirstDocSave = wwdCurrentDoc.cpFirst;
+ selDocSave = selCur;
+
+ TrashCache();
+ TrashWw( wwDocument );
+
+ if (!FWriteOk( fwcNil ))
+ goto DontEdit;
+
+ if ( cpFirst == cpLim )
+ {
+ /* If we are editing the header/footer for the first time in this document,
+ insert a para end mark to hold the running h/f properties */
+ extern struct PAP *vppapNormal;
+ struct PAP papT;
+
+ blt( vppapNormal, &papT, cwPAP );
+ papT.rhc = (wwdCurrentDoc.fEditHeader) ?
+ rhcDefault : rhcDefault + RHC_fBottom;
+
+ InsertEolPap( docCur, cpFirst, &papT );
+ if (ferror)
+ return;
+ ValidateHeaderFooter( docCur );
+ cpLim += ccpEol;
+ }
+ else
+ {
+ extern int vccpFetch;
+ typeCP cp;
+
+ /* Test for a special case: loading a WORD document which has been
+ properly set up to have running head/foot under MEMO. We must
+ force the para end mark at the end of the header/footer to be
+ a fresh run. This is so we will see an end mark when editing one
+ of these. FormatLine only checks for cpMacCur at the start of a run. */
+
+ Assert( cpLim - cpFirst >= ccpEol );
+
+ if ( (cp = cpLim - ccpEol) > cpFirst )
+ {
+ FetchCp( docCur, cp - 1, 0, fcmBoth );
+
+ if ( vccpFetch > 1)
+ { /* char run does not end with char before EOL */
+ /* Insert a char, then delete it */
+ extern struct CHP vchpNormal;
+ CHAR ch='X';
+
+ InsertRgch( docCur, cp, &ch, 1, &vchpNormal, NULL );
+ if (ferror)
+ return;
+ Replace( docCur, cp, (typeCP) 1, fnNil, fc0, fc0 );
+ if (ferror)
+ return;
+ }
+ }
+ }
+
+DontEdit:
+
+ /* Save current window text; set string */
+
+ GetWindowText( hParentWw, (LPSTR)szWinTextSave, cchWinTextSave );
+ if (FNoHeap(hszWinTextSave=HszCreate( (PCH)szWinTextSave )))
+ {
+ hszWinTextSave = NULL;
+ }
+ else
+ {
+ extern CHAR szHeader[];
+ extern CHAR szFooter[];
+
+ SetWindowText( hParentWw, fHeader ? (LPSTR)szHeader:(LPSTR)szFooter );
+ }
+
+ /* Set editing limits to just the cp range of the header/footer,
+ minus the "invisible" terminating EOL */
+ wwdCurrentDoc.cpFirst = wwdCurrentDoc.cpMin = cpMinCur = cpFirst;
+ wwdCurrentDoc.cpMac = cpMacCur = CpMax( cpMinCur, cpLim - ccpEol );
+
+ /* Leave the cursor at the beginning of the header/footer regardless */
+ Select( cpMinCur, cpMinCur );
+ /* Show the display here instead of waiting for Idle() because it looks
+ better to have the head/foot text come up right away instead of waiting
+ for the dialog box to come up */
+ UpdateDisplay( FALSE );
+ vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
+ NoUndo();
+ ferror = FALSE; /* If we got this far, we want to go into running
+ head mode regardless of errors */
+}
+
+
+
+
+fnEditDocument()
+{ /* Return to editing document after editing header/footer */
+ extern HWND hParentWw;
+
+ Assert( wwdCurrentDoc.fEditFooter != wwdCurrentDoc.fEditHeader );
+
+ /* Restore original window name */
+ if (hszWinTextSave != NULL)
+ {
+ SetWindowText( hParentWw, (LPSTR) (**hszWinTextSave) );
+ FreeH( hszWinTextSave );
+ hszWinTextSave = NULL;
+ }
+
+ TrashCache();
+
+ ValidateHeaderFooter( docCur ); /* This will update from the results of
+ the header/footer edit */
+ TrashCache();
+ wwdCurrentDoc.cpMin = cpMinCur = cpMinDocument;
+ wwdCurrentDoc.cpMac = cpMacCur = CpMacText( docCur );
+
+ TrashWw( wwDocument );
+ wwdCurrentDoc.fEditHeader = FALSE;
+ wwdCurrentDoc.fEditFooter = FALSE;
+
+ /* Restore saved selection, cpFirst for document */
+ wwdCurrentDoc.cpFirst = cpFirstDocSave;
+ Select( selDocSave.cpFirst, selDocSave.cpLim );
+
+ Assert( wwdCurrentDoc.cpFirst >= cpMinCur &&
+ wwdCurrentDoc.cpFirst <= cpMacCur );
+
+ NoUndo();
+ vhDlgRunningHead = (HANDLE)NULL;
+}
+
+
+
+
+BOOL far PASCAL DialogRunningHead( hDlg, message, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+ /* This routine handles input to the Header/Footer dialog box. */
+
+ extern BOOL vfPrinterValid;
+
+ RECT rc;
+ CHAR *pch = &stBuf[0];
+ struct SEP **hsep = (**hpdocdod)[docCur].hsep;
+ struct SEP *psep;
+ static int fChecked;
+ typeCP dcp;
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ vhDlgRunning = hDlg; /* Put dialog handle in a global for
+ ESC key in document functionality */
+ CachePara(docCur, selCur.cpFirst);
+ ppapDefault = &vpapAbs;
+
+ FreezeHp();
+ /* Get a pointer to the section properties. */
+ psep = (hsep == NULL) ? &vsepNormal : *hsep;
+
+ CheckDlgButton(hDlg, idiRHFirst, (ppapDefault->rhc & RHC_fFirst));
+ if (wwdCurrentDoc.fEditHeader)
+ {
+ CchExpZa(&pch, psep->yaRH1, utCur, cchMaxNum);
+ }
+ else /* footer dialog box */
+ {
+#ifdef KOREA /* 91.3.17 want to guarantee Default >= MIN, Sangl */
+ if (vfPrinterValid)
+ { extern int dyaPrOffset;
+ extern int dyaPrPage;
+ CchExpZa(&pch, imax(psep->yaMac - psep->yaRH2,
+ vsepNormal.yaMac - dyaPrOffset - dyaPrPage),utCur, cchMaxNum);
+ }
+ else
+ CchExpZa(&pch, psep->yaMac - psep->yaRH2, utCur, cchMaxNum);
+#else
+ CchExpZa( &pch, psep->yaMac - psep->yaRH2, utCur, cchMaxNum);
+#endif
+ }
+ SetDlgItemText(hDlg, idiRHDx, (LPSTR)stBuf);
+ MeltHp();
+ break;
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ int dya;
+
+ case idiRHFirst:
+ CheckDlgButton( hDlg, idiRHFirst, !IsDlgButtonChecked(hDlg, idiRHFirst));
+ (**hpdocdod) [docCur].fDirty = TRUE;
+ break;
+ case idiRHInsertPage:
+ if (FWriteOk( fwcInsert ))
+ { /* Insert page # at insertion pt */
+ extern struct CHP vchpFetch, vchpSel;
+ extern int vfSeeSel;
+ CHAR ch=schPage;
+ struct CHP chp;
+
+ if (selCur.cpFirst == selCur.cpLim)
+ { /* Sel is insertion point -- get props from
+ the vchpSel kludge */
+ blt( &vchpSel, &chp, cwCHP );
+ }
+ else
+ {
+ FetchCp( docCur, selCur.cpFirst, 0, fcmProps );
+ blt( &vchpFetch, &chp, cwCHP );
+ }
+
+ chp.fSpecial = TRUE;
+
+ SetUndo( uacInsert, docCur, selCur.cpFirst, (typeCP) 1,
+ docNil, cpNil, cp0, 0 );
+ InsertRgch( docCur, selCur.cpFirst, &ch, 1, &chp, NULL );
+
+ vfSeeSel = TRUE;
+ }
+ break;
+
+ case idiRHClear:
+ /* Clear running head/foot */
+ dcp = cpMacCur-cpMinCur;
+
+#if defined(OLE)
+ {
+ BOOL bIsOK;
+
+ ObjPushParms(docCur);
+ Select(cpMinCur,cpMacCur);
+ bIsOK = ObjDeletionOK(OBJ_DELETING);
+ ObjPopParms(TRUE);
+
+ if (!bIsOK)
+ break;
+ }
+#endif
+
+ if (dcp > 0 && FWriteOk( fwcDelete ))
+ {
+ NoUndo();
+ SetUndo( uacDelNS, docCur, cpMinCur, dcp,
+ docNil, cpNil, cp0, 0 );
+ Replace( docCur, cpMinCur, dcp, fnNil, fc0, fc0 );
+ }
+ break;
+
+ case idiOk: /* return to document */
+BackToDoc:
+ if (!FPdxaPosIt(&dya, hDlg, idiRHDx))
+ {
+ break;
+ }
+ else if (vfPrinterValid)
+ {
+ extern struct SEP vsepNormal;
+ extern int dxaPrOffset;
+ extern int dyaPrOffset;
+ extern int dxaPrPage;
+ extern int dyaPrPage;
+ extern struct WWD rgwwd[];
+
+ int dyaPrBottom = imax(0, vsepNormal.yaMac - dyaPrOffset -
+ dyaPrPage);
+
+
+ if (FUserZaLessThanZa(dya, (wwdCurrentDoc.fEditHeader ?
+ dyaPrOffset : dyaPrBottom)))
+ {
+ int dxaPrRight = imax(0, vsepNormal.xaMac - dxaPrOffset
+ - dxaPrPage);
+
+ EnableExcept(vhDlgRunningHead, FALSE);
+ ErrorBadMargins(hDlg, dxaPrOffset, dxaPrRight,
+ dyaPrOffset, dyaPrBottom);
+ EnableExcept(vhDlgRunningHead, TRUE);
+ SelectIdiText(hDlg, idiRHDx);
+ SetFocus(GetDlgItem(hDlg, idiRHDx));
+ break;
+ }
+ }
+
+
+ DoFormatRHText( dya, IsDlgButtonChecked( hDlg, idiRHFirst ) );
+ fnEditDocument();
+ /* force repaint to the whole client area */
+ GetClientRect(vhWnd, (LPRECT)&rc);
+ InvalidateRect(vhWnd, (LPRECT)&rc, FALSE);
+ vhWndMsgBoxParent = (HWND)NULL;
+ DestroyWindow(hDlg);
+ break;
+
+ case idiCancel:
+ goto BackToDoc;
+ default:
+ return(FALSE);
+ }
+ break;
+
+#if WINVER < 0x300
+ /* Don't really need to process this */
+ case WM_CLOSE:
+ goto BackToDoc;
+#endif
+
+#ifndef INEFFLOCKDOWN
+ case WM_NCDESTROY:
+ FreeProcInstance(lpDialogRunningHead);
+ lpDialogRunningHead = NULL;
+ /* fall through to return false */
+#endif
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/* end of DialogRunningHead */
+
+
+
+
+DoFormatRHText( dya, fFirstPage)
+int dya;
+int fFirstPage;
+{ /* Format cp range for running head/foot currently being edited
+ to have the passed running head properties */
+extern typeCP vcpLimParaCache;
+
+CHAR rgb[4];
+int fHeader=wwdCurrentDoc.fEditHeader;
+
+ /* Note that the Min value for the part we were editing has not changed
+ as a result of the edit, so no ValidateHeaderFooter is required */
+typeCP cpMin=fHeader ? cpMinHeader : cpMinFooter;
+int rhc;
+struct SEP **hsep = (**hpdocdod)[docCur].hsep;
+struct SEP *psep;
+
+ if (!FWriteOk( fwcNil ))
+ return;
+
+/* Ensure that this document has a valid section property
+descriptor. */
+if (hsep == NULL)
+ {
+ if (FNoHeap(hsep = (struct SEP **)HAllocate(cwSEP)))
+ {
+ return;
+ }
+ blt(&vsepNormal, *hsep, cwSEP);
+ (**hpdocdod)[docCur].hsep = hsep;
+ }
+psep = *hsep;
+
+/* Set running head distance from top/bottom; this is a Section
+ property. This assumes the MEMO model: one section */
+if (fHeader)
+ psep->yaRH1 = dya;
+else
+ psep->yaRH2 = psep->yaMac - dya;
+
+/* For MEMO, running heads appear on both odd and even pages;
+ appearance on first page is optional */
+rhc = RHC_fOdd + RHC_fEven;
+if (fFirstPage)
+ rhc += RHC_fFirst;
+if (!fHeader)
+ rhc += RHC_fBottom;
+
+/* Set running head PARA properties by adding an appropriate sprm */
+
+ /* Set CpMacCur to include the "hidden" Eol; this will prevent
+ AddOneSprm from adding an extraneous EOL */
+CachePara( docCur, CpMax( cpMinCur, cpMacCur-1 ) );
+Assert( vpapAbs.rhc != 0 );
+cpMacCur = CpMax( cpMacCur, vcpLimParaCache );
+
+selCur.cpFirst = cpMinCur; /* Expand selection to entire area so sprm */
+selCur.cpLim = cpMacCur; /* applies to it all */
+
+rgb [0] = sprmPRhc;
+rgb [1] = rhc;
+AddOneSprm(rgb, FALSE);
+
+} /* end of DoFormatRHText */
+
+
+
+
+MakeRunningCps( doc, cp, dcp )
+int doc;
+typeCP cp;
+typeCP dcp;
+{ /* Make the cp range suitable for inclusion in a runninng head or foot.
+ This means: (1) Apply a Sprm to the whole thing so it is formatted
+ as a running head/foot, (2) Remove any chSects, replacing them
+ with Eol's */
+ extern struct UAB vuab;
+ CHAR rgb [4];
+ int rhc;
+ int fAdjCpMacCur;
+ typeCP cpLimPara;
+ typeCP cpT;
+ struct SEL selSave;
+
+ if (dcp==cp0 || !FWriteOk( fwcNil ))
+ return;
+
+ selSave = selCur;
+
+ /* Scan the cp range, replacing chSects with Eols */
+
+ for ( cpT = cp;
+ CachePara( doc, cpT ), (cpLimPara=vcpLimParaCache) <= cp + dcp;
+ cpT = cpLimPara )
+ {
+ typeCP cpLastPara=cpLimPara-1;
+
+ Assert( cpLimPara > cpT ); /* Otherwise we are locked in the loop */
+
+ FetchCp( doc, cpLastPara, 0, fcmChars );
+ if (*vpchFetch == chSect)
+ {
+ struct PAP papT;
+
+ CachePara( doc, cpT );
+ papT = vpapAbs;
+
+ Replace( doc, cpLastPara+ccpEol, (typeCP)1, fnNil, fc0, fc0 );
+ InsertEolPap( doc, cpLastPara, &papT );
+
+ if (ferror)
+ {
+ NoUndo();
+ break;
+ }
+
+ /* Adjust Undo count to account for extra insertion */
+ vuab.dcp += (typeCP)(ccpEol-1);
+ CachePara( doc, cpT );
+ cpLimPara = vcpLimParaCache;
+ }
+ }
+
+ /* Apply a Sprm that makes everything a running head/foot */
+
+ rhc = RHC_fOdd + RHC_fEven;
+ if (wwdCurrentDoc.fEditFooter)
+ rhc += RHC_fBottom;
+
+ selCur.cpFirst = cp; /* OK to just assign to selCur */
+ selCur.cpLim = cp + dcp; /* because AddOneSprm will handle */
+
+ /* We must temporarily set cpMacCur so that it includes the Eol
+ at the end of the header/footer range. Otherwise, AddOneSprm
+ may decide it needs to insert a superfluous Eol */
+
+ CachePara( docCur, selCur.cpLim-1 );
+ if (fAdjCpMacCur = (vcpLimParaCache > cpMacCur))
+ cpMacCur += ccpEol;
+
+ rgb [0] = sprmPRhc;
+ rgb [1] = rhc;
+ AddOneSprm(rgb, FALSE); /* Do not set UNDO; we want to undo the paste,
+ which will take care of undoing the sprm */
+ if (fAdjCpMacCur)
+ cpMacCur -= ccpEol;
+
+ Select( selSave.cpFirst, selCur.cpLim );
+}
+
+
diff --git a/private/mvdm/wow16/write/screen.c b/private/mvdm/wow16/write/screen.c
new file mode 100644
index 000000000..503d0204d
--- /dev/null
+++ b/private/mvdm/wow16/write/screen.c
@@ -0,0 +1,195 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This routine sets up the screen position used by Word relative to the
+current device. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOMENUS
+/* HEY! if you change this to wwsmall.h, talk to bobm!
+ (see Assert(LF_FACESIZE == LocalFaceSize)) */
+#include <windows.h>
+#include "mw.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "fontdefs.h"
+
+
+int viffnDefault = -1;
+CHAR rgffnFontFamily[6][ibFfnMax];
+
+
+struct FFN *PffnDefault(ffid)
+/* returns pointer to default font structure for this font family ID, which
+ is set up when we started the program */
+
+FFID ffid;
+ {
+ int iffn;
+ struct FFN *pffn;
+
+ if (ffid == FF_DONTCARE)
+ {
+ Assert(viffnDefault >= 0);
+ iffn = viffnDefault;
+ }
+ else
+ iffn = MpFfidIffn(ffid);
+
+ pffn = (struct FFN *)(rgffnFontFamily[iffn]);
+ if (pffn->szFfn[0] == 0)
+ /* haven't gotten this one yet - must be old word document */
+ GetDefaultFonts(TRUE, FALSE);
+
+ Assert(pffn->szFfn[0] != 0);
+ return(pffn);
+ }
+
+
+
+GetDefaultFonts(fExtraFonts, fGetAspect)
+/* We set up our table of default fonts in two steps. First we choose a single
+ font, to use as the default font for a new document. Perhaps later, we
+ are asked for a set of default fonts for different families to help
+ make sense out of an old, word document. That case is differentiated
+ by fExtraFonts being TRUE */
+
+int fExtraFonts, fGetAspect;
+
+ {
+ extern int aspectXFont;
+ extern int aspectYFont;
+ extern HDC vhDCPrinter;
+ struct FFN *pffn;
+ CHAR rgb[ibFfnMax];
+
+ Assert(LF_FACESIZE == LocalFaceSize);
+#ifndef NEWFONTENUM
+ Assert(vhDCPrinter);
+ if (fGetAspect && vhDCPrinter != NULL)
+ {
+ extern FARPROC lpFontFaceEnum;
+ int rgw[6];
+
+ rgw[0] = enumFindAspectRatio;
+ rgw[1] = rgw[2] = 0xFFFF;
+ rgw[3] = GetDeviceCaps(vhDCPrinter, LOGPIXELSY);
+ rgw[4] = GetDeviceCaps(vhDCPrinter, LOGPIXELSX);
+ rgw[5] = TRUE;
+
+ EnumFonts(vhDCPrinter, 0L, lpFontFaceEnum, (LPSTR)MAKELONG(&rgw[0], 0));
+ aspectXFont = rgw[1];
+ aspectYFont = rgw[2];
+ }
+#endif
+
+ if (FInitFontEnum(docNil, fExtraFonts ? 32767 : 1, TRUE))
+ {
+ pffn = (struct FFN *)rgb;
+ while (FEnumFont(pffn))
+#ifdef NEWFONTENUM
+ DefaultFamilyCheck(pffn->ffid, pffn->szFfn, pffn->chs);
+#else
+ DefaultFamilyCheck(pffn->ffid, pffn->szFfn);
+#endif
+ EndFontEnum();
+ }
+
+ /* Fill in just in case we missed some. The order here is important, if
+ there are no fonts at all, the default font will be the first one. */
+ {
+ extern CHAR szModern[];
+ extern CHAR szRoman[];
+ extern CHAR szSwiss[];
+ extern CHAR szScript[];
+ extern CHAR szDecorative[];
+
+ DefaultFamilyCheck(FF_MODERN, szModern, NULL);
+ if (fExtraFonts)
+ {
+ DefaultFamilyCheck(FF_ROMAN, szRoman, NULL);
+ DefaultFamilyCheck(FF_SWISS, szSwiss, NULL);
+ DefaultFamilyCheck(FF_SCRIPT, szScript, NULL);
+ DefaultFamilyCheck(FF_DECORATIVE, szDecorative, NULL);
+ DefaultFamilyCheck(FF_DONTCARE, szSwiss, NULL);
+ }
+ }
+
+ }
+
+
+
+DefaultFamilyCheck(ffid, sz, chsIfKnown)
+FFID ffid;
+CHAR *sz;
+BYTE chsIfKnown;
+ {
+ int iffn;
+ struct FFN *pffn;
+
+ iffn = MpFfidIffn(ffid);
+ pffn = (struct FFN *)(rgffnFontFamily[iffn]);
+ if (pffn->szFfn[0] == 0)
+ {
+#ifdef NEWFONTENUM
+ pffn->chs = chsIfKnown;
+#endif
+ pffn->ffid = ffid;
+ bltszLimit(sz, pffn->szFfn, LF_FACESIZE);
+ if (viffnDefault < 0)
+ /* this font will be chosen for new documents */
+ viffnDefault = iffn;
+ }
+ }
+
+
+#define iffnSwiss 0
+#define iffnRoman 1
+#define iffnModern 2
+#define iffnScript 3
+#define iffnDecorative 4
+#define iffnDontCare 5
+
+
+MpFfidIffn(ffid)
+FFID ffid;
+ {
+ switch (ffid)
+ {
+ default:
+ Assert( FALSE );
+ /* FALL THROUGH */
+ case FF_DONTCARE:
+ return(iffnDontCare);
+ case FF_SWISS:
+ return(iffnSwiss);
+ case FF_ROMAN:
+ return(iffnRoman);
+ case FF_MODERN:
+ return(iffnModern);
+ case FF_SCRIPT:
+ return(iffnScript);
+ case FF_DECORATIVE:
+ return(iffnDecorative);
+ }
+ }
+
+
+ResetDefaultFonts(fGetAspect)
+int fGetAspect;
+ {
+ /* This routine resets the default mapping from a font family to a font face
+ name. */
+ bltbc(rgffnFontFamily, 0, 6 * ibFfnMax);
+ viffnDefault = -1;
+ GetDefaultFonts(FALSE, fGetAspect);
+ }
+
+
+
diff --git a/private/mvdm/wow16/write/scrnchng.c b/private/mvdm/wow16/write/scrnchng.c
new file mode 100644
index 000000000..9fec2eb0a
--- /dev/null
+++ b/private/mvdm/wow16/write/scrnchng.c
@@ -0,0 +1,853 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This routine sets up the screen position used by Word relative to the
+current device. */
+
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOMENUS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NODRAWTEXT
+#define NOMSG
+#define NOOPENFILE
+#define NOSCROLL
+#define NOSOUND
+/*#define NOTEXTMETRIC*/
+#define NOWH
+#define NOWINOFFSETS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "ch.h"
+#include "cmddefs.h"
+#include "scrndefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "printdef.h"
+#include "str.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "machdefs.h"
+#include "fontdefs.h"
+#include "commdlg.h"
+
+#ifdef DBCS
+#include "kanji.h"
+#endif
+
+unsigned dxaPrOffset;
+unsigned dyaPrOffset;
+extern HCURSOR vhcIBeam;
+
+
+BOOL FSetWindowColors()
+ {
+ /* This routine sets up the global variables rgbBkgrnd, rgbText, hbrBkgrnd,
+ and ropErase, depending on what the current system colors are. hWnd is a
+ handle to a window on top. */
+
+ extern long ropErase;
+ extern long rgbBkgrnd;
+ extern long rgbText;
+ extern HBRUSH hbrBkgrnd;
+
+ long rgbWindow;
+ long rgbWindowText;
+ HDC hDC;
+
+ /* Get the color of the background and the text. */
+ rgbWindow = GetSysColor(COLOR_WINDOW);
+ rgbWindowText = GetSysColor(COLOR_WINDOWTEXT);
+
+ /* If the colors haven't changed, then there is nothing to do. */
+ if (rgbWindow == rgbBkgrnd && rgbWindowText == rgbText)
+ {
+ return (FALSE);
+ }
+
+ /* Convert the window colors into "pure" colors. */
+ if ((hDC = GetDC(NULL)) == NULL)
+ {
+ return (FALSE);
+ }
+ rgbBkgrnd = GetNearestColor(hDC, rgbWindow);
+ rgbText = GetNearestColor(hDC, rgbWindowText);
+ ReleaseDC(NULL, hDC);
+ Assert((rgbBkgrnd & 0xFF000000) == 0 && (rgbText & 0xFF000000) == 0);
+
+ /* Set up the brush for the background. */
+ if ((hbrBkgrnd = CreateSolidBrush(rgbBkgrnd)) == NULL)
+ {
+ /* Can't make the background brush; use the white brush. */
+ hbrBkgrnd = GetStockObject(WHITE_BRUSH);
+ rgbBkgrnd = RGB(0xff, 0xff, 0xff);
+ }
+
+ /* Compute the raster op to erase the screen. */
+ if (rgbBkgrnd == RGB(0xff, 0xff, 0xff))
+ {
+ /* WHITENESS is faster than copying a white brush. */
+ ropErase = WHITENESS;
+ }
+ else if (rgbBkgrnd == RGB(0, 0, 0))
+ {
+ /* BLACKNESS is faster than copying a black brush. */
+ ropErase = BLACKNESS;
+ }
+ else
+ {
+ /* For everything else, we have to copy the brush. */
+ ropErase = PATCOPY;
+ }
+ return (TRUE);
+ }
+
+
+int FSetScreenConstants()
+ {
+ /* This routine sets the value of a variety of global variables that used to
+ be constants in Mac Word, but are now varibles because screen resolution can
+ only be determined at run time. */
+
+ extern HWND hParentWw;
+ extern HDC vhDCPrinter;
+ extern HBITMAP hbmNull;
+ extern int dxpLogInch;
+ extern int dypLogInch;
+ extern int dxpLogCm;
+ extern int dypLogCm;
+ extern int dypMax;
+ extern int xpRightMax;
+ extern int xpSelBar;
+ extern int xpMinScroll;
+ extern int xpRightLim;
+ extern int dxpInfoSize;
+ extern int ypMaxWwInit;
+ extern int ypMaxAll;
+ extern int dypMax;
+ extern int dypAveInit;
+ extern int dypWwInit;
+ extern int dypBand;
+ extern int ypSubSuper;
+#ifdef KINTL
+ extern int dxaAdjustPerCm;
+#endif /* ifdef KINTL */
+
+ HDC hDC;
+#ifdef KINTL
+ int xaIn16CmFromA, xaIn16CmFromP;
+#endif /* ifdef KINTL */
+
+
+ /* First, let's create and save an empty bitmap. */
+ if ((hbmNull = CreateBitmap(1, 1, 1, 1, (LPSTR)NULL)) == NULL)
+ {
+ return (FALSE);
+ }
+
+ /* Get the DC of the parent window to play with. */
+ if ((hDC = GetDC(hParentWw)) == NULL)
+ {
+ return (FALSE);
+ }
+
+ /* Save away the height of the screen. */
+ dypMax = GetDeviceCaps(hDC, VERTRES);
+
+ /* determine screen pixel dimensions */
+ dxpLogInch = GetDeviceCaps(hDC, LOGPIXELSX);
+ dypLogInch = GetDeviceCaps(hDC, LOGPIXELSY);
+
+ /* convert above to centimeters */
+ dxpLogCm = MultDiv(dxpLogInch, czaCm, czaInch);
+ dypLogCm = MultDiv(dypLogInch, czaCm, czaInch);
+
+#ifdef KINTL
+ /* Now, calculate the kick back amount of xa per cm. */
+ xaIn16CmFromA = 16 * czaCm;
+ xaIn16CmFromP = MultDiv(16 * dxpLogCm, czaInch, dxpLogInch);
+ dxaAdjustPerCm = (xaIn16CmFromP - xaIn16CmFromA) / 16;
+#endif /* ifdef KINTL */
+
+#ifdef SYSENDMARK
+ {
+ extern HFONT vhfSystem;
+ extern struct FMI vfmiSysScreen;
+ extern int vrgdxpSysScreen[];
+ TEXTMETRIC tm;
+
+ /* The use of height below is OK, because we are
+ just trying to get the reference height. */
+ GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
+
+ /* Set up the fields in vfmiSysScreen for the later use. */
+ vfmiSysScreen.dxpOverhang = tm.tmOverhang;
+ vfmiSysScreen.dxpSpace = LOWORD(GetTextExtent(hDC,
+ (LPSTR)" ", 1)) - tm.tmOverhang;
+ vfmiSysScreen.dypAscent = tm.tmAscent;
+ vfmiSysScreen.dypDescent = tm.tmDescent;
+ vfmiSysScreen.dypBaseline = tm.tmAscent;
+ vfmiSysScreen.dypLeading = tm.tmExternalLeading;
+
+#ifdef DBCS /* KenjiK '90-10-29 */
+ /* We must setup appended members of structure. */
+ vfmiSysScreen.dxpDBCS = dxpNil;
+#endif /* DBCS */
+
+ bltc(vrgdxpSysScreen, dxpNil, chFmiMax - chFmiMin);
+ vfmiSysScreen.mpchdxp = vrgdxpSysScreen - chFmiMin;
+
+ /* This is as good a place to get a handle to the system font as
+ any other for LoadFont().....? */
+ /* Throw away the old one first, if applicable. */
+ if (vhfSystem != NULL) {
+ DeleteObject((HANDLE) vhfSystem);
+ }
+ vhfSystem = GetStockObject(SYSTEM_FONT);
+ Assert(vhfSystem != NULL);
+ }
+#endif /* SYSENDMARK */
+
+ /* We don't need the DC any more. */
+ ReleaseDC(hParentWw, hDC);
+
+ /* Calculate the positions. */
+ xpSelBar = MultDiv(xaSelBar, dxpLogInch, czaInch);
+ xpRightMax = MultDiv(xaRightMax, dxpLogInch, czaInch);
+ xpRightLim = xpRightMax - (GetSystemMetrics(SM_CXFULLSCREEN) - xpSelBar -
+ GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER));
+ xpMinScroll = ((MultDiv(xaMinScroll, dxpLogInch, czaInch)+7)/8)*8;
+ dxpInfoSize = MultDiv(dxaInfoSize, dxpLogInch, czaInch);
+ ypMaxWwInit = MultDiv(yaMaxWwInit, dypLogInch, czaInch);
+ ypMaxAll = MultDiv(yaMaxAll, dypLogInch, czaInch);
+ dypWwInit = MultDiv(dyaWwInit, dypLogInch, czaInch);
+ dypBand = MultDiv(dyaBand, dypLogInch, czaInch);
+ ypSubSuper = MultDiv(yaSubSuper, dypLogInch, czaInch);
+
+ /* dypAveInit is a very rough guess as to the height + leading of a 12 point
+ font. */
+ dypAveInit = MultDiv(cya12pt, dypLogInch, czaInch);
+
+ /* Time to search the user profile to find a printer. */
+ if (!FGetPrinterFromProfile())
+ {
+ return (FALSE);
+ }
+ GetPrinterDC(FALSE);
+
+ return (TRUE);
+ }
+
+
+BOOL FGetPrinterFromProfile()
+ {
+ /* This routine searches the user profile for the name of a printer to use
+ and records the name in the printer heap strings. FALSE is returned iff a
+ memory error is encountered. */
+
+ extern HWND hParentWw;
+ extern CHAR szWindows[];
+ extern CHAR szDevice[];
+ extern CHAR szDevices[];
+ extern BOOL vfPrDefault;
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+
+ CHAR *index(CHAR *, int);
+ CHAR *bltbyte(CHAR *, CHAR *, int);
+
+ CHAR szPrinter[cchMaxProfileSz];
+ CHAR szDevSpec[cchMaxProfileSz];
+ CHAR chNull = '\0';
+ CHAR *pch;
+ CHAR *pchDriver;
+ CHAR *pchPort;
+ int cwsz;
+
+ if (!vfPrDefault && hszPrinter != NULL && hszPrPort != NULL)
+ {
+ /* If the user has selected a printer, then look for that printer in the
+ user profile. */
+
+ int cPort;
+ int iPort;
+
+ bltsz(&(**hszPrinter)[0], szPrinter);
+ GetProfileString((LPSTR)szDevices, (LPSTR)szPrinter, (LPSTR)&chNull,
+ (LPSTR)szDevSpec, cchMaxProfileSz);
+ cPort = ParseDeviceSz(szDevSpec, &pchPort, &pchDriver);
+
+ /* See if we can find the old port in the list. */
+ for (iPort = 0, pch = pchPort; iPort < cPort; iPort++)
+ {
+ if (WCompSz(&(**hszPrPort)[0], pch) == 0)
+ {
+ pchPort = pch;
+ goto GotPrinter;
+ }
+ pch += CchSz(pch);
+ }
+
+ /* If the port for the current printer has changed, then it must have
+ been done by the control panel and we haven't the foggiest idea what
+ it is, so grab the first port. */
+ goto UnknownPort;
+ }
+
+ /* Is there a default Windows printer? */
+ GetProfileString((LPSTR)szWindows, (LPSTR)szDevice, (LPSTR)&chNull,
+ (LPSTR)szPrinter, cchMaxProfileSz);
+
+#ifdef WIN30
+ /* Don't make the assumption like Write 2 did and just grab ANY printer.
+ I know, I know -- there's unnecessary code left down below but didn't
+ want to screw any special case code up ..pault */
+ if ((pch = index(szPrinter, ',')) == 0)
+ goto BailOut;
+#endif
+
+ /* Does this entry contain the port and driver information. */
+ if ((pch = index(szPrinter, ',')) != 0)
+ {
+ /* Remove any trailing spaces from the printer name. */
+ CHAR *pchT;
+
+ for (pchT = pch; *pchT == ' ' && pchT > &szPrinter[0]; pchT--);
+ *pchT = '\0';
+
+ /* Parse out the port and the driver names. */
+ ParseDeviceSz(pch + 1, &pchPort, &pchDriver);
+ }
+
+ else
+ {
+ if (szPrinter[0] == '\0')
+ {
+ /* No default printer; grab the first one in the list. */
+ GetProfileString((LPSTR)szDevices, (LPSTR)NULL, (LPSTR)&chNull,
+ (LPSTR)szPrinter, cchMaxProfileSz);
+
+ if (szPrinter[0] == '\0')
+ {
+BailOut:
+ hszPrinter = hszPrDriver = hszPrPort = NULL;
+ return (TRUE);
+ }
+ }
+
+UnknownPort:
+ /* Find the device driver and the port of the printer. */
+ GetProfileString((LPSTR)szDevices, (LPSTR)szPrinter, (LPSTR)&chNull,
+ (LPSTR)szDevSpec, cchMaxProfileSz);
+ if (szPrinter[0] == '\0')
+ {
+ goto BailOut;
+ }
+ ParseDeviceSz(szDevSpec, &pchPort, &pchDriver);
+ }
+
+GotPrinter:
+ /* Save the names of the printer, printer driver, and the port. */
+ if (FNoHeap(hszPrinter = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(szPrinter)))))
+ {
+ goto NoHszPrinter;
+ }
+ blt(szPrinter, &(**hszPrinter)[0], cwsz);
+ if (FNoHeap(hszPrDriver = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(pchDriver)))))
+ {
+ goto NoHszPrDriver;
+ }
+ blt(pchDriver, &(**hszPrDriver)[0], cwsz);
+ if (FNoHeap(hszPrPort = (CHAR (**)[])HAllocate(cwsz =
+ CwFromCch(CchSz(pchPort)))))
+ {
+ FreeH(hszPrDriver);
+NoHszPrDriver:
+ FreeH(hszPrinter);
+NoHszPrinter:
+ hszPrinter = hszPrDriver = hszPrPort = NULL;
+ return (FALSE);
+ }
+ blt(pchPort, &(**hszPrPort)[0], cwsz);
+
+ return (TRUE);
+ }
+
+
+int ParseDeviceSz(sz, ppchPort, ppchDriver)
+CHAR sz[];
+CHAR **ppchPort;
+CHAR **ppchDriver;
+ {
+ /* This routine takes a string that came from the "device" entry in the user
+ profile and returns in *ppchPort and *ppchDriver pointers to the port and
+ driver sutible for a CreateDC() call. If no port is found in the string,
+ *ppchPort will point to a string containing the name of the null device.
+ This routine returns the number of ports for this printer (separated by null
+ characters in the string pointed at by *ppchPort). NOTE: sz may be modified
+ by this routine, and the string at *ppchPort may not be a substring of sz
+ and should not be modified by the caller. */
+
+ extern CHAR stBuf[];
+ extern CHAR szNul[];
+ CHAR *index(CHAR *, int);
+ CHAR *bltbyte(CHAR *, CHAR *, int);
+
+ register CHAR *pch;
+ int cPort = 0;
+
+ /* Remove any leading spaces from the string. */
+ for (pch = &sz[0]; *pch == ' '; pch++);
+
+ /* The string starts with the driver name. */
+ *ppchDriver = pch;
+
+ /* The next space or comma terminates the driver name. */
+ for ( ; *pch != ' ' && *pch != ',' && *pch != '\0'; pch++);
+
+ /* If the string does not have a port associated with it, then the port
+ must be the null device. */
+ if (*pch == '\0')
+ {
+ /* Set the port name to "None". */
+ *ppchPort = &szNul[0];
+ cPort = 1;
+ }
+ else
+ {
+ /* As far as we can tell, the port name is valid; parse it from the
+ driver name. */
+ if (*pch == ',')
+ {
+ *pch++ = '\0';
+ }
+ else
+ {
+ /* Find that comma separating the driver and the port. */
+ *pch++ = '\0';
+ for ( ; *pch != ',' && *pch != '\0'; pch++);
+ if (*pch == ',')
+ {
+ pch++;
+ }
+ }
+
+ /* Remove any leading spaces from the port name. */
+ for ( ; *pch == ' '; pch++);
+
+ /* Check to see if there is really a port name. */
+ if (*pch == '\0')
+ {
+ /* Set the port name to "None". */
+ *ppchPort = &szNul[0];
+ cPort = 1;
+ }
+ else
+ {
+ /* Set the pointer to the port name. */
+ *ppchPort = pch;
+
+ while (*pch != '\0')
+ {
+ register CHAR *pchT = pch;
+
+ /* Increment the number of ports found for this printer. */
+ cPort++;
+
+ /* Remove any trailing spaces from the port name. */
+ for ( ; *pchT != ' ' && *pchT != ','; pchT++)
+ {
+ if (*pchT == '\0')
+ {
+ goto EndFound;
+ }
+ }
+ *pchT++ = '\0';
+ pch = pchT;
+
+ /* Remove any leading spaces in the next port name. */
+ for ( ; *pchT == ' '; pchT++);
+
+ /* Throw out the leading spaces. */
+ bltbyte(pchT, pch, CchSz(pchT));
+ }
+EndFound:;
+ }
+ }
+
+ /* Parse the ".drv" out of the driver. */
+ {
+ extern CHAR szExtDrv[];
+ if ((pch = index(*ppchDriver, '.')) != 0
+ && FRgchSame(pch, szExtDrv, CchSz (szExtDrv) - 1))
+ {
+ *pch = '\0';
+ }
+ }
+
+ return (cPort);
+ }
+
+
+SetPrintConstants()
+ {
+ /* This routine sets the scaling/aspect constants for the printer described
+ in vhDCPrinter. */
+
+ extern HDC vhDCPrinter;
+ extern BOOL vfPrinterValid;
+ extern int dxpPrPage;
+ extern int dypPrPage;
+ extern int dxaPrPage;
+ extern int dyaPrPage;
+ extern int dxpLogInch;
+ extern int dypLogInch;
+ extern int ypSubSuperPr;
+
+ if (vfPrinterValid && vhDCPrinter != NULL)
+ {
+ POINT rgpt[2];
+
+ /* Get the dimensions of the printer in pixels. */
+ dxpPrPage = rgpt[1].x = GetDeviceCaps(vhDCPrinter, HORZRES);
+ dypPrPage = rgpt[1].y = GetDeviceCaps(vhDCPrinter, VERTRES);
+
+ /* Put the printer in twips mode to find the dimensions in twips. */
+ SetMapMode(vhDCPrinter, MM_TWIPS);
+ rgpt[0].x = rgpt[0].y = 0;
+ DPtoLP(vhDCPrinter, (LPPOINT)rgpt, 2);
+
+#if WINVER >= 0x300
+/* Weird Win bug that we can't decide on the corrective action -- sometimes
+ DPtoLP returns x8000 here! What's that mean? Well it's SUPPOSED to be
+ a large negative number ..pault */
+
+ if (rgpt[1].x == 0x8000)
+ rgpt[1].x = -(0x7fff);
+ if (rgpt[1].y == 0x8000)
+ rgpt[1].y = -(0x7fff);
+#endif
+
+ if ((dxaPrPage = rgpt[1].x - rgpt[0].x) < 0)
+ {
+ dxaPrPage = -dxaPrPage;
+ }
+ if ((dyaPrPage = rgpt[0].y - rgpt[1].y) < 0)
+ {
+ dyaPrPage = -dyaPrPage;
+ }
+ SetMapMode(vhDCPrinter, MM_TEXT);
+ }
+ else
+ {
+ /* Pretend the printer is just like the screen. */
+ dxaPrPage = dyaPrPage = czaInch;
+ dxpPrPage = dxpLogInch;
+ dypPrPage = dypLogInch;
+ }
+
+ /* ypSubSuperPr is the offset for subscript and supercript font on the
+ printer. */
+ ypSubSuperPr = MultDiv(yaSubSuper, dypPrPage, dyaPrPage);
+ }
+
+
+GetPrinterDC(fDC)
+BOOL fDC;
+ {
+ /* This routine sets vhDCPrinter to a new printer DC or IC. If fDC is TRUE,
+ a new DC is created; otherwise, a new IC is created. In addition, all
+ global variables dependent on the printer DC are changed. */
+
+ extern HDC vhDCPrinter;
+ extern BOOL vfPrinterValid;
+ extern CHAR (**hszPrinter)[];
+ extern CHAR (**hszPrDriver)[];
+ extern CHAR (**hszPrPort)[];
+ extern HWND hParentWw;
+ extern int docCur;
+ extern struct DOD (**hpdocdod)[];
+ extern BOOL vfWarnMargins;
+ extern BOOL vfInitializing;
+ extern PRINTDLG PD;
+
+ BOOL fCreateError = FALSE;
+
+
+ /* We now pass the local PrinterSetup settings to CreateDC/CreateIC
+ since Write's settings can differ from the global ones ..pault */
+ LPSTR lpDevmodeData=NULL;
+
+ Assert(vhDCPrinter == NULL);
+
+ /* Get a new printer DC. */
+#ifdef WIN30
+ if (hszPrinter != NULL && hszPrDriver != NULL && hszPrPort != NULL)
+ /* We used to only do this check if vfPrinterValid -- don't
+ now because otherwise one has no way to get Write to believe
+ it has a valid printer! ..pt */
+#else
+ if (vfPrinterValid && hszPrinter != NULL && hszPrDriver != NULL &&
+ hszPrPort != NULL)
+#endif
+ {
+ HDC (far PASCAL *fnCreate)() = fDC ? CreateDC : CreateIC;
+
+ StartLongOp();
+
+ if (PD.hDevMode == NULL)
+ fnPrGetDevmode(); // get PD.hDevMode
+
+ lpDevmodeData = MAKELP(PD.hDevMode,0);
+
+ if ((vhDCPrinter = (*fnCreate)((LPSTR)&(**hszPrDriver)[0],
+ (LPSTR)&(**hszPrinter)[0], (LPSTR)&(**hszPrPort)[0], lpDevmodeData)) !=
+ NULL)
+ {
+ EndLongOp(vhcIBeam);
+ vfPrinterValid = TRUE;
+ }
+ else
+ {
+ /* If we thought the DC was valid, then we better tell the user it
+ is not. */
+ EndLongOp(vhcIBeam);
+ fCreateError = TRUE;
+ goto NoDC;
+ }
+ }
+ else
+ {
+NoDC:
+ /* We don't have a printer DC, so use the DC for the screen. */
+ vhDCPrinter = GetDC(hParentWw);
+ vfPrinterValid = FALSE;
+
+ /* Warn the user if necessary. This is done after creating the printer
+ DC because Error() may force the DC to be created if we had not already
+ done so. */
+ if (fCreateError)
+ {
+ BOOL fInit = vfInitializing;
+
+ vfInitializing = FALSE;
+#ifdef DBCS /* was in JAPAN */
+/* We have to answer to WM_WININICHANGE immidiately to ReleaseDC with
+** 'dispatch' printer driver.
+** So It's possible for us opening MessageBox deep in SendMessage
+** call. This code avoid that.. Yutakan.
+*/
+ if( !InSendMessage() )
+#endif
+ Error(IDPMTCantPrint);
+ vfInitializing = fInit;
+ }
+ }
+
+ /* Set new values for the "constants" used by this printer. */
+ SetPrintConstants();
+
+ /* Set the size of the paper for this printer. */
+ SetPageSize();
+ vfWarnMargins = FALSE;
+
+ /* The printer may have changed in such a way that it's fonts have changed
+ (i.e. portrait to landscape). We must re-initialize our list of fonts. */
+ ResetDefaultFonts(TRUE);
+ if (hpdocdod != NULL)
+ {
+ Assert((**hpdocdod)[docCur].hffntb != NULL);
+ (*(**hpdocdod)[docCur].hffntb)->fFontMenuValid = FALSE;
+ }
+ }
+
+
+SetPageSize()
+ {
+ /* Change the size of the paper to the printer described by vhDCPrinter. */
+
+ extern HDC vhDCPrinter;
+ extern HWND vhWndMsgBoxParent;
+ extern BOOL vfPrinterValid;
+ extern typeCP cpMinHeader;
+ extern typeCP cpMacHeader;
+ extern typeCP cpMinFooter;
+ extern typeCP cpMacFooter;
+ extern int dxpPrPage;
+ extern int dypPrPage;
+ extern int dxaPrPage;
+ extern int dyaPrPage;
+ extern HWND hParentWw;
+ extern struct SEP vsepNormal;
+ extern struct DOD (**hpdocdod)[];
+ extern int docMac;
+ extern int docScrap;
+ extern int docUndo;
+ extern BOOL vfWarnMargins;
+
+ unsigned xaMac;
+ unsigned yaMac;
+ unsigned dxaRight;
+ unsigned dyaBottom;
+ unsigned dyaRH2;
+ unsigned dxaPrRight = 0;
+ unsigned dyaPrBottom = 0;
+ BOOL fRH;
+ register struct DOD *pdod;
+ int doc;
+ HWND hWnd;
+
+ if (hpdocdod == NULL || docMac == 0)
+ {
+ /* Nothing to do if there are no documents. */
+ return;
+ }
+
+ Assert(vhDCPrinter);
+ if (vfPrinterValid && vhDCPrinter != NULL)
+ {
+ POINT pt;
+
+ /* Get the page size of the printer. */
+ if (Escape(vhDCPrinter, GETPHYSPAGESIZE, 0, (LPSTR)NULL, (LPSTR)&pt))
+ {
+ xaMac = MultDiv(pt.x, dxaPrPage, dxpPrPage);
+ yaMac = MultDiv(pt.y, dyaPrPage, dypPrPage);
+ }
+ else
+ {
+ /* The printer won't tell us it page size; we'll have to settle
+ for the printable area. */
+ xaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter, HORZSIZE));
+ yaMac = ZaFromMm(GetDeviceCaps(vhDCPrinter, VERTSIZE));
+ }
+
+ /* The page size cannot be smaller than the printable area. */
+ if (xaMac < dxaPrPage)
+ {
+ xaMac = dxaPrPage;
+ }
+ if (yaMac < dyaPrPage)
+ {
+ yaMac = dyaPrPage;
+ }
+
+ /* Determine the offset of the printable area on the page. */
+ if (Escape(vhDCPrinter, GETPRINTINGOFFSET, 0, (LPSTR)NULL, (LPSTR)&pt))
+ {
+ dxaPrOffset = MultDiv(pt.x, dxaPrPage, dxpPrPage);
+ dyaPrOffset = MultDiv(pt.y, dyaPrPage, dypPrPage);
+ }
+ else
+ {
+ /* The printer won't tell us what the offset is; assume the
+ printable area is centered on the page. */
+ dxaPrOffset = (xaMac - dxaPrPage) >> 1;
+ dyaPrOffset = (yaMac - dyaPrPage) >> 1;
+ }
+ }
+ else
+ {
+ /* Assume standard page size for now. */
+ xaMac = cxaInch * 8 + cxaInch / 2;
+ yaMac = cyaInch * 11;
+ dxaPrOffset = dyaPrOffset = 0;
+ }
+
+ /* Determine the right and bottom margins for the "normal" page. */
+ dxaRight = vsepNormal.xaMac - vsepNormal.xaLeft - vsepNormal.dxaText;
+ dyaBottom = vsepNormal.yaMac - vsepNormal.yaTop - vsepNormal.dyaText;
+ dyaRH2 = vsepNormal.yaMac - vsepNormal.yaRH2;
+
+ /* Determine the minimum dimensions of the printed page. */
+ if (vfPrinterValid)
+ {
+ dxaPrRight = imax(0, xaMac - dxaPrOffset - dxaPrPage);
+ dyaPrBottom = imax(0, yaMac - dyaPrOffset - dyaPrPage);
+
+ hWnd = vhWndMsgBoxParent == NULL ? hParentWw : vhWndMsgBoxParent;
+
+#ifdef BOGUS
+ /* Check the margins of the "normal" page. */
+ fRH = cpMacHeader - cpMacHeader > ccpEol || cpMacFooter - cpMinFooter >
+ ccpEol;
+ if (vfWarnMargins && (FUserZaLessThanZa(vsepNormal.xaLeft, dxaPrOffset)
+ || FUserZaLessThanZa(dxaRight, dxaPrRight) ||
+ FUserZaLessThanZa(vsepNormal.yaTop, dyaPrOffset) ||
+ FUserZaLessThanZa(dyaBottom, dyaPrBottom) || (fRH &&
+ (FUserZaLessThanZa(vsepNormal.yaRH1, dyaPrOffset) ||
+ FUserZaLessThanZa(dyaRH2, dyaPrBottom)))))
+ {
+ /* One of the margins is bad, tell the user about it. */
+ ErrorBadMargins(hWnd, dxaPrOffset, dxaPrRight, dyaPrOffset,
+ dyaPrBottom);
+ vfWarnMargins = FALSE;
+ }
+#endif /* BOGUS */
+
+ }
+
+ /* Reset the dimensions of the "normal" page. */
+ vsepNormal.xaMac = xaMac;
+ vsepNormal.dxaText = xaMac - vsepNormal.xaLeft - umax(dxaRight, dxaPrRight);
+ vsepNormal.yaMac = yaMac;
+ vsepNormal.dyaText = yaMac - vsepNormal.yaTop - umax(dyaBottom,
+ dyaPrBottom);
+ vsepNormal.yaRH2 = yaMac - umax(dyaRH2, dyaPrBottom);
+
+ /* Reset the page dimensions for all documents. */
+ for (doc = 0, pdod = &(**hpdocdod)[0]; doc < docMac; doc++, pdod++)
+ {
+ if (pdod->hpctb != NULL && pdod->hsep != NULL)
+ {
+ /* Reset the existing section properties. */
+ register struct SEP *psep = *(pdod->hsep);
+
+ /* Determine the right and bottom margins for this page. */
+ dxaRight = psep->xaMac - psep->xaLeft - psep->dxaText;
+ dyaBottom = psep->yaMac - psep->yaTop - psep->dyaText;
+ dyaRH2 = psep->yaMac - psep->yaRH2;
+
+ /* Check the margins for this document. */
+ if (vfWarnMargins && vfPrinterValid && doc != docScrap && doc !=
+ docUndo && (FUserZaLessThanZa(psep->xaLeft, dxaPrOffset) ||
+ FUserZaLessThanZa(dxaRight, dxaPrRight) ||
+ FUserZaLessThanZa(psep->yaTop, dyaPrOffset) ||
+ FUserZaLessThanZa(dyaBottom, dyaPrBottom) || (fRH &&
+ (FUserZaLessThanZa(psep->yaRH1, dyaPrOffset) ||
+ FUserZaLessThanZa(dyaRH2, dyaPrBottom)))))
+ {
+ ErrorBadMargins(hWnd, dxaPrOffset, dxaPrRight, dyaPrOffset,
+ dyaPrBottom);
+ vfWarnMargins = FALSE;
+ pdod = &(**hpdocdod)[doc];
+ psep = *(pdod->hsep);
+ }
+
+ /* Set the dimensions of this page. */
+ psep->xaMac = xaMac;
+ psep->dxaText = xaMac - psep->xaLeft - dxaRight;
+ psep->yaMac = yaMac;
+ psep->dyaText = yaMac - psep->yaTop - dyaBottom;
+ psep->yaRH2 = yaMac - dyaRH2;
+ }
+
+ /* Invalidate any caches for this document. */
+ InvalidateCaches(doc);
+ }
+ }
+
+
diff --git a/private/mvdm/wow16/write/scrndefs.h b/private/mvdm/wow16/write/scrndefs.h
new file mode 100644
index 000000000..3d6e72a77
--- /dev/null
+++ b/private/mvdm/wow16/write/scrndefs.h
@@ -0,0 +1,39 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* This file contains definitions for screen dependent positions in twips which
+will be converted to pixels later. */
+
+#define cch12pt 80 /* number of "12 pt" chars across the screen */
+#define cxa12pt 144 /* width of a 12 pt fixed font in twips */
+#define cya12pt 240 /* height of a 12 pt fixed font in twips */
+
+/* size of lines for dnMax estimation purposes */
+#define dyaAveInit 240
+
+/* width of the selection bar area to the left of lines */
+#define xaSelBar 288
+
+#define dxaScrlBar 270
+#define dyaScrlBar 300
+
+#define xaMinScroll 180
+
+/* these define the initial window size and amount of white space above
+the first line */
+#define yaMaxWwInit 5580
+
+/* should be > than largest window height + height of blank line after
+the endmark */
+#define yaMaxAll 20000 /* used for invalidation */
+#define dyaWwInit 60
+
+#define dyaBand 320 /* formerly dpxyLineSizeMin */
+
+/* height of left portion of a split line */
+#define dyaSplitLine 60
+
+#define yaSubSuper 60
+
+#define dxaInfoSize 1800
diff --git a/private/mvdm/wow16/write/scrollhz.c b/private/mvdm/wow16/write/scrollhz.c
new file mode 100644
index 000000000..814995f14
--- /dev/null
+++ b/private/mvdm/wow16/write/scrollhz.c
@@ -0,0 +1,385 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOICON
+#define NOATOM
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMETAFILE
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSOUND
+#define NOWH
+#define NOWNDCLASS
+#define NOCOMM
+#define NOFONT
+#define NOBRUSH
+#include <windows.h>
+#include "mw.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "dispdefs.h"
+#include "fmtdefs.h"
+
+extern long ropErase;
+extern struct WWD *pwwdCur;
+extern struct WWD rgwwd[];
+extern int wwCur;
+extern int docCur;
+extern typeCP cpMacCur;
+extern struct FLI vfli;
+
+int NEAR FOnScreenRect(RECT *);
+
+
+/* P U T C P I N W W H Z */
+PutCpInWwHz(cp)
+typeCP cp;
+ /* Ensure that cp is in wwCur */
+ /* Make sure it's not off to left or right, too. */
+
+ { /* Just check for horizontal bounding; vertical is done
+ by call to CpBeginLine below. */
+ int dxpRoom, xp, xpMin;
+ int dlT;
+ typeCP cpBegin;
+
+ UpdateWw(wwCur, false);
+ cpBegin = CpBeginLine(&dlT, cp);
+ FormatLine(docCur, cpBegin, (**(pwwdCur->hdndl))[dlT].ichCpMin, cpMacCur, flmSandMode);
+/* xpMin is a dummy here */
+ xp = DxpDiff(0, (int)(cp - vfli.cpMin), &xpMin) + vfli.xpLeft;
+ xpMin = pwwdCur->xpMin;
+/* we have: xp = desired position, xpMin = amount of horizontal scroll */
+/* width of space in window for text */
+ dxpRoom = (pwwdCur->xpMac - xpSelBar);
+ if (xp < xpMin )
+ { /* cp is left of screen */
+ AdjWwHoriz(max(0, xp - min(dxpRoom - 1, cxpAuto)) - xpMin);
+ }
+ else if (xp >= xpMin + dxpRoom)
+ { /* cp is right of screen */
+ register int dxpRoomT = min(xpRightMax, xp + min(dxpRoom - 1, cxpAuto))
+ - dxpRoom + 1;
+
+ AdjWwHoriz(max(0, dxpRoomT) - xpMin);
+ }
+ }
+
+
+/* A D J W W H O R I Z */
+AdjWwHoriz(dxpScroll)
+int dxpScroll;
+ {
+ /* Scroll a window horizontally */
+ if (dxpScroll != 0)
+ {
+ RECT rc;
+
+/* Reset the value of the horizontal scroll bar */
+ SetScrollPos( pwwdCur->hHScrBar,
+ pwwdCur->sbHbar,
+ pwwdCur->xpMin + dxpScroll,
+ TRUE);
+
+#ifdef ENABLE /* HideSel() */
+ HideSel();
+#endif /* ENABLE */
+
+ ClearInsertLine();
+
+ SetRect( (LPRECT)&rc, xpSelBar, 0, pwwdCur->xpMac, pwwdCur->ypMac );
+ ScrollCurWw( &rc, -dxpScroll, 0 );
+ TrashWw(wwCur);
+ pwwdCur->xpMin += dxpScroll;
+
+ if (pwwdCur->fRuler)
+ {
+ UpdateRuler();
+ }
+
+ }
+ }
+
+
+
+
+/* Scroll specified subrectangle of current window by specified amount */
+#include <stdlib.h>
+ScrollCurWw( prc, dxp, dyp )
+register RECT *prc;
+int dxp,dyp;
+{
+
+ extern int vfScrollInval;
+ RECT rcClear;
+ if (dxp && dyp)
+ return; /* Scroll in both dimensions is an illegal case */
+
+ if (!(dxp || dyp))
+ return; /* no scrolling to do */
+
+#if 1
+ /**
+ The previous old, old code was getting flaky. (7.14.91) v-dougk
+ **/
+ if (ScrollDC(pwwdCur->hDC,dxp,dyp,(LPRECT)prc,(LPRECT)prc,NULL,&rcClear))
+ {
+ PatBlt( pwwdCur->hDC, rcClear.left, rcClear.top,
+ rcClear.right-rcClear.left+1, rcClear.bottom-rcClear.top+1, ropErase );
+
+ if (dxp)
+ vfScrollInval = FALSE;
+ else
+ vfScrollInval = (rcClear.bottom-rcClear.top+1) > abs(dyp);
+
+ if (vfScrollInval)
+ {
+ InvalidateRect(pwwdCur->wwptr,&rcClear,FALSE);
+ UpdateInvalid();
+ }
+ }
+ else
+ vfScrollInval = FALSE;
+ return;
+#else
+
+ int FCheckPopupRect( HWND, LPRECT );
+ extern int vfScrollInval;
+ HDC hDC;
+ int dxpAbs = (dxp < 0) ? -dxp : dxp;
+ int dypAbs = (dyp < 0) ? -dyp : dyp;
+ struct RS { int left, top, cxp, cyp; }
+ rsSource, rsDest, rsClear;
+ /* Set rsSource, rsDest, rsClear == prc */
+
+ if ((rsSource.cxp = imin( prc->right, pwwdCur->xpMac ) -
+ (rsSource.left = imax( 0, prc->left ))) <= 0)
+ /* Rectangle is null or illegal in X-dimension */
+ return;
+ if ((rsSource.cyp = imin( prc->bottom, pwwdCur->ypMac ) -
+ (rsSource.top = imax( pwwdCur->ypMin, prc->top ))) <= 0)
+ /* Rectangle is null or illegal in Y-dimension */
+ return;
+ bltbyte( &rsSource, &rsDest, sizeof (struct RS ));
+ bltbyte( &rsSource, &rsClear, sizeof (struct RS ));
+
+ hDC = pwwdCur->hDC;
+
+ if ((dxpAbs < rsSource.cxp) && (dypAbs < rsSource.cyp))
+ { /* A Real scroll, not the bogus case when we just clear exposed area */
+ /* NOTE: We do not bother to compute rsSource.cxp or rsSource.cyp,
+ as they are not needed by BitBlt or PatBlt */
+
+ /* If there are PopUp windows, use ScrollWindow to avoid getting
+ bogus bits from some popup. Since this is slow, only do it if there
+ is some popup that overlaps the scroll rect */
+ if ( AnyPopup() )
+ {
+ extern HANDLE hMmwModInstance;
+ static FARPROC lpFCheckPopupRect = (FARPROC)NULL;
+
+ /* First time through, inz ptr to thunk */
+
+ if (lpFCheckPopupRect == NULL)
+ lpFCheckPopupRect = MakeProcInstance( (FARPROC) FCheckPopupRect,
+ hMmwModInstance );
+ EnumWindows( lpFCheckPopupRect, (LONG) (LPRECT) prc );
+ }
+
+ /* Under windows 2.0, must also check for any part of the scroll
+ rectangle being off the screen (not possible in tiling environment).
+ If so, use ScrollWindow to avoid getting bogus bits from outside
+ the screen. */
+ if (!FOnScreenRect( prc ))
+ vfScrollInval = TRUE;
+
+ if (vfScrollInval)
+ { /* vfScrollInval also tells UpdateWw that invalid region
+ may have changed */
+
+ extern BOOL vfEraseWw;
+
+ ScrollWindow( pwwdCur->wwptr, dxp, dyp, (LPRECT)prc, (LPRECT)prc );
+ vfEraseWw = TRUE;
+ UpdateInvalid(); /* Marks repaint area as invalid in our
+ structures so we don't think bits grabbed
+ from a popup are valid */
+ vfEraseWw = FALSE;
+ return;
+ }
+
+ if (dxp != 0)
+ rsDest.cxp -= (rsClear.cxp = dxpAbs);
+ else
+ /* dxp==dyp==0 case is caught below */
+ rsDest.cyp -= (rsClear.cyp = dypAbs);
+
+ if (dxp < 0)
+ {
+ rsSource.left += dxpAbs;
+ rsClear.left += rsDest.cxp;
+ }
+ else if (dxp > 0)
+ {
+ rsDest.left += dxpAbs;
+ }
+ else if (dyp < 0)
+ {
+ rsSource.top += dypAbs;
+ rsClear.top += rsDest.cyp;
+ }
+ else if (dyp > 0)
+ {
+ rsDest.top += dypAbs;
+ }
+ else
+ return;
+
+ BitBlt( hDC,
+ rsDest.left, rsDest.top,
+ rsDest.cxp, rsDest.cyp,
+ hDC,
+ rsSource.left, rsSource.top,
+ SRCCOPY );
+ }
+
+
+#ifdef SMFONT
+ /* Vertical refresh will be so bindingly fast, that we do not need to erase the
+ old text. */
+ if (dxp != 0)
+ {
+ PatBlt(hDC, rsClear.left, rsClear.top, rsClear.cxp, rsClear.cyp, ropErase);
+ }
+#else /* not SMFONT */
+ PatBlt( hDC, rsClear.left, rsClear.top, rsClear.cxp, rsClear.cyp, ropErase );
+#endif /* SMFONT */
+#endif
+}
+
+
+
+int FCheckPopupRect( hwnd, lprc )
+HWND hwnd;
+LPRECT lprc;
+{ /* If the passed window is not a popup, return TRUE;
+ If the passed window is a popup, and its coordinates overlap
+ those of the passed rect, set vfScrollInval to TRUE and return FALSE.
+ Otherwise, return TRUE.
+ This is a window enumeration function: a return of TRUE means
+ continue enumerating windows, a return of FALSE means
+ stop the enumeration */
+
+ extern int vfScrollInval;
+ RECT rc;
+ POINT ptTopLeft, ptBottomRight;
+ RECT rcResult;
+
+ if ( !(GetWindowLong( hwnd, GWL_STYLE ) & WS_POPUP) )
+ /* Window is not a popup */
+ return TRUE;
+
+ /* Get popup rectangle in screen coordinates */
+
+ GetWindowRect( hwnd, (LPRECT) &rc );
+
+ /* Convert rc from screen coordinates to current document window coordinates */
+
+ ptTopLeft.x = rc.left;
+ ptTopLeft.y = rc.top;
+ ptBottomRight.x = rc.right;
+ ptBottomRight.y = rc.bottom;
+
+ ScreenToClient( pwwdCur->wwptr, (LPPOINT) &ptTopLeft );
+ ScreenToClient( pwwdCur->wwptr, (LPPOINT) &ptBottomRight );
+
+ rc.left = ptTopLeft.x;
+ rc.top = ptTopLeft.y;
+ rc.right = ptBottomRight.x;
+ rc.bottom = ptBottomRight.y;
+
+ IntersectRect( (LPRECT) &rcResult, (LPRECT) &rc, (LPRECT)lprc );
+ if ( !IsRectEmpty( (LPRECT) &rcResult ) )
+ { /* Popup overlaps passed rectangle */
+ vfScrollInval = TRUE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+/* S C R O L L L E F T */
+ScrollLeft(dxp)
+int dxp;
+ { /* Scroll current window left dxp pixels */
+ if ((dxp = min(xpRightLim - pwwdCur->xpMin, dxp)) >0)
+ AdjWwHoriz(dxp);
+ else
+ _beep();
+ }
+
+
+/* S C R O L L R I G H T */
+ScrollRight(dxp)
+int dxp;
+ {
+ if ((dxp = min(pwwdCur->xpMin, dxp)) > 0)
+ AdjWwHoriz(-dxp);
+ else
+ _beep();
+ }
+
+
+
+
+
+
+/* F O N S C R E E N R E C T
+
+ Returns TRUE iff the rectangle is entirely within the screen
+ boundaries.
+ Assumes the rectangle belongs to the current window.
+
+ */
+
+int NEAR
+FOnScreenRect(prc)
+register RECT *prc;
+{
+
+ POINT ptTopLeft, ptBottomRight;
+ int cxScreen = GetSystemMetrics( SM_CXSCREEN );
+ int cyScreen = GetSystemMetrics( SM_CYSCREEN );
+
+ ptTopLeft.x = prc->left;
+ ptTopLeft.y = prc->top;
+ ptBottomRight.x = prc->right;
+ ptBottomRight.y = prc->bottom;
+
+ ClientToScreen( pwwdCur->wwptr, (LPPOINT) &ptTopLeft );
+ ClientToScreen( pwwdCur->wwptr, (LPPOINT) &ptBottomRight );
+
+ if ((ptTopLeft.x <= 0) || (ptTopLeft.y <= 0) ||
+ (ptBottomRight.x >= cxScreen) || (ptBottomRight.y >= cyScreen))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/private/mvdm/wow16/write/scrollvt.c b/private/mvdm/wow16/write/scrollvt.c
new file mode 100644
index 000000000..9551acfca
--- /dev/null
+++ b/private/mvdm/wow16/write/scrollvt.c
@@ -0,0 +1,531 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOWNDCLASS
+#define NOICON
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOBITMAP
+#define NOBRUSH
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOMB
+#define NOPOINT
+#define NOMSG
+#include <windows.h>
+#include "mw.h"
+#include "docdefs.h"
+#include "dispdefs.h"
+#include "fmtdefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "propdefs.h"
+
+/* Globals used here only */
+struct TR { /* Text Row info for CtrBackDyp Cache */
+ typeCP cp;
+ int dcpDepend; /* dcpDepend for PREVIOUS edl */
+ int ichCp;
+ int dyp;
+ };
+struct TR rgtrCache[ itrMaxCache ];
+int wwCache=wwNil;
+
+
+extern struct PAP vpapAbs;
+extern typeCP vcpFirstParaCache;
+extern struct WWD *pwwdCur;
+extern struct SEL selCur;
+extern int docCur;
+extern typeCP cpCacheHint;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct FLI vfli;
+extern int wwCur;
+extern int ctrCache;
+extern int itrFirstCache;
+extern int itrLimCache;
+extern int vfOutOfMemory;
+
+
+
+
+/* P U T C P I N W W V E R T*/
+PutCpInWwVert(cp)
+typeCP cp;
+
+ {
+/* vertical case */
+ typeCP cpMac;
+ struct EDL (**hdndl) [] = pwwdCur->hdndl;
+ int dlMac=pwwdCur->dlMac;
+ struct EDL *pedl = &(**hdndl) [dlMac - 1];
+ struct EDL *pedlFirst = &(**hdndl) [0];
+
+ if ((pedl->yp > pwwdCur->ypMac) && (pedl > pedlFirst))
+ /* Partial line at the bottom of the window -- this doesn't count
+ unless it's all we've got */
+ { pedl--; dlMac--; }
+ if (cp < pwwdCur->cpFirst ||
+ cp > (cpMac = pedl->cpMin + pedl->dcpMac) ||
+ (cp == cpMac && !pedl->fIchCpIncr) ||
+ /* Covers insertion points before pictures reached via curs keys */
+ (CachePara( docCur, cp ),
+ (vpapAbs.fGraphics &&
+ (selCur.cpFirst == selCur.cpLim) &&
+ (pedlFirst->cpMin == selCur.cpFirst) &&
+ (pedlFirst->ichCpMin > 0))))
+ {
+ DirtyCache(pwwdCur->cpFirst = cp);
+ pwwdCur->ichCpFirst = 0;
+ CtrBackDypCtr( 9999, dlMac >> 1 );
+ }
+ }
+
+
+
+
+SetCurWwVScrollPos( )
+{
+ typeCP cp;
+ int dr;
+ struct EDL (**hdndl)[] = pwwdCur->hdndl;
+
+/* calculate desired elevator position dr */
+
+ if ((cp = pwwdCur->cpMac - pwwdCur->cpMin) == (typeCP) 0)
+ dr = 0;
+ else
+ {
+ typeCP CpWinGraphic();
+ typeCP cpWinFirst = ((**hdndl) [0].fGraphics && !pwwdCur->fDirty) ?
+ CpWinGraphic( pwwdCur ) : pwwdCur->cpFirst;
+
+ dr = min(drMax - 1,
+ (int)(((cpWinFirst - pwwdCur->cpMin) * (drMax - 1) + (cp >> 1)) / cp));
+ }
+
+/* Contemplating this 'if' statement should elevate one to a higher plane
+of existence. */
+ if (dr != pwwdCur->drElevator)
+ /* reset the value of the vertical scroll bar */
+ SetScrollPos( pwwdCur->hVScrBar,
+ pwwdCur->sbVbar,
+ pwwdCur->drElevator = dr,
+ TRUE);
+}
+
+
+
+
+/* A D J W W V E R T */
+/* Scroll a window down vertically so that UpdateWw can re-use the text
+that is still visible. Otherwise, UpdateWw would write over the very
+lines it will need later on near the bottom of the window.
+*/
+AdjWwVert(cdl, dyp)
+int cdl;
+{
+#if defined(JAPAN) & defined(DBCS_IME)
+extern void IMEManage( );
+#endif
+ struct EDL *pedl;
+ int dl;
+
+ if (cdl == 0) return;
+
+ cdl = umin( cdl, pwwdCur->dlMac ); /* ! don't let it run off the end */
+
+ Assert( dyp > 0 );
+
+ ClearInsertLine();
+ DypScroll(wwCur, 0, cdl, pwwdCur->ypMin + dyp);
+/* invalidate the first cdl dl's */
+ pedl = &(**(pwwdCur->hdndl))[0];
+ for (dl = 0; dl < cdl; dl++)
+ (pedl++)->fValid = FALSE;
+ pwwdCur->fDirty = fTrue;
+#if defined(JAPAN) & defined(DBCS_IME)
+ IMEManage( FALSE );
+#endif
+}
+
+
+
+
+ScrollDownCtr(ddr)
+int ddr;
+{ /* Scroll down in the document by ddr text lines (but < 1 screenful) */
+ struct EDL *pedl;
+
+ UpdateWw(wwCur, FALSE); /* Dl's must be correct */
+
+ ddr = min(ddr, max(1, pwwdCur->dlMac - 1));
+
+ pedl = &(**(pwwdCur->hdndl))[ddr - 1]; /* pedl is first line above new screen */
+ while (ddr > 0 && pedl->cpMin + pedl->dcpMac > cpMacCur)
+ { /* Don't scroll the endmark off the screen */
+ --pedl;
+ --ddr;
+ }
+
+ /* Change the cpFirst of the window and dirty it */
+ if (ddr > 0)
+ {
+ struct TR tr;
+ int dcpDepend;
+
+ if (wwCur != wwCache)
+ { /* If window has changed, invalidate cache here
+ so cp's cached below will be used */
+ TrashCacheS();
+ wwCache = wwCur;
+ }
+
+ HideSel(); /* Don't scroll selection if machine can't handle it */
+ ClearInsertLine();
+
+ pwwdCur->cpFirst = pedl->cpMin + pedl->dcpMac;
+ pwwdCur->ichCpFirst = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0;
+ pwwdCur->dcpDepend = pedl->dcpDepend; /* Remember hot spot */
+
+ /* Make tr cache entries for the disappearing lines */
+ pedl = &(**(pwwdCur->hdndl))[0];
+ if (ctrCache == 0) /* We don't have top line yet */
+ {
+ tr.cp = pedl->cpMin;
+ tr.ichCp = pedl->ichCpMin;
+ tr.dyp = pedl->dyp;
+ tr.dcpDepend = pwwdCur->dcpDepend;
+ AppendCachePtr( &tr );
+ }
+
+ while ( ddr-- )
+ {
+ tr.cp = pedl->cpMin + pedl->dcpMac;
+ tr.ichCp = pedl->fIchCpIncr ? pedl->ichCpMin + 1 : 0;
+ tr.dcpDepend = pedl->dcpDepend;
+ tr.dyp = (++pedl)->dyp;
+ AppendCachePtr( &tr );
+ }
+
+ pwwdCur->fDirty = true;
+ SetCurWwVScrollPos();
+ CheckMode();
+ }
+ else
+ {
+ _beep();
+ }
+}
+
+
+
+
+ScrollUpDypWw()
+{ /* Scroll up in the document by one screenfull less 1 line */
+int dypKeep=8;
+struct EDL *pedl = &(**pwwdCur->hdndl) [0];
+
+if (pedl->fValid)
+ {
+ dypKeep = pedl->dyp;
+ }
+
+if (CtrBackDypCtr( pwwdCur->ypMac - pwwdCur->ypMin - dypKeep,9999 ) == 0)
+ {
+ _beep();
+ }
+else
+ CheckMode();
+}
+
+
+
+ScrollUpCtr( ctr )
+int ctr;
+{ /* Scroll Up ctr text rows in the doc (scroll window down) */
+ if (CtrBackDypCtr( 9999, ctr ) == 0)
+ {
+ _beep();
+ }
+ else
+ CheckMode();
+}
+
+
+
+
+int CtrBackDypCtr( dypLim, ctrLim )
+int dypLim;
+int ctrLim;
+{ /* Set pwwdCur->cpFirst to the cpFirst of the text line
+ dypLim pixels or ctrLim text rows before the value of
+ pwwdCur->cpFirst, whichever limit is reached first.
+ Adjust the position of the vert scroll bar according to the new cpFirst.
+ Return the number of text rows (tr) we went back. */
+
+ int fAdj = ( (pwwdCur->cpFirst == (**(pwwdCur->hdndl))[0].cpMin) ||
+ !(**(pwwdCur->hdndl))[0].fValid );
+ typeCP cpFirst = pwwdCur->cpFirst;
+ int ichCpFirst = pwwdCur->ichCpFirst;
+ int ctrGrant = 0; /* ctr we've backed over so far */
+ int dypGrant = 0; /* dyp we've backed over so far */
+ int ichFake = 0;
+
+ pwwdCur->fCpBad = false; /* Reset hot spot warning */
+ pwwdCur->fDirty = true;
+
+/* Cache is only valid for one ww -- invalidate if ww has changed */
+ if (wwCur != wwCache)
+ {
+ TrashCacheS();
+ wwCache = wwCur;
+ }
+
+ if (ctrCache == 0)
+ /* Don't have cache entry for first line in Ww -- force formatting
+ THROUGH first line of Ww instead of TO it. */
+ ++ichFake;
+
+ for ( ;; )
+ {
+ /* If there is no info in the cache, must replenish it. */
+
+ if (ctrCache <= 1) /* <=: also replenish if 1st line of Ww is only entry */
+ {
+ typeCP cpStart; /* cp to start formatting from */
+ int dcpDepend; /* Dependency of line containing cpStart */
+ typeCP cp;
+ int ichCp;
+ int itrTempCacheLim = 0;
+ struct TR rgtrTempCache[ itrMaxCache ];
+ int fTempCacheOverflow = false;
+
+ if ((cpFirst <= cpMinCur) && (ichCpFirst == 0))
+ { /* Reached top of document */
+ if (fAdj)
+ AdjWwVert( ctrGrant, dypGrant );
+ pwwdCur->cpFirst = cpMinCur;
+ pwwdCur->ichCpFirst = 0;
+ pwwdCur->dcpDepend = 0;
+ goto SetScroll;
+ }
+
+ /* Want to go back BEFORE the earliest point we have in the cache */
+
+ if (ichFake > 0)
+ /* Force formatting THROUGH { cpFirst, ichCpFirst }
+ instead of TO */
+ --ichFake;
+ else if (ichCpFirst > 0)
+ --ichCpFirst;
+ else
+ --cpFirst;
+
+ cpStart = CpHintCache( cpFirst );
+ if ( ( CachePara( docCur, cpFirst ), vcpFirstParaCache ) >= cpStart )
+ {
+ cpStart = vcpFirstParaCache;
+ dcpDepend = 0; /* At para start; we know dependency is 0 */
+ }
+ else
+ dcpDepend = cpMaxTl; /* real value unknown; use max */
+
+ /* Add TR info for lines from { cpStart, 0 } THROUGH
+ { cpFirst, ichCpFirst } to temporary cache */
+
+ for ( cp = cpStart, ichCp = 0;
+ (cp < cpFirst) || ((cp == cpFirst) && (ichCp <= ichCpFirst)); )
+ {
+ struct TR *ptr;
+
+ if (itrTempCacheLim == itrMaxCache)
+ { /* Overflowed the temp cache */
+ fTempCacheOverflow = fTrue;
+ itrTempCacheLim = 0;
+ }
+
+ /* Add one tr to the cache */
+
+ FormatLine( docCur, cp, ichCp, cpMacCur, flmSandMode );
+ if (vfOutOfMemory)
+ return ctrGrant;
+ ptr = &rgtrTempCache[ itrTempCacheLim++ ];
+ ptr->cp = cp;
+ ptr->ichCp = ichCp;
+ ptr->dyp = vfli.dypLine;
+ ptr->dcpDepend = dcpDepend; /* Save dcpDepend for prev line */
+ dcpDepend = vfli.dcpDepend;
+
+ /* Continue with next line */
+
+ cp = vfli.cpMac;
+ ichCp = vfli.ichCpMac;
+ } /* end for */
+
+ /* Add our temporary cache in front of the real one */
+ PrependCacheRgtr( rgtrTempCache, itrTempCacheLim );
+ if (fTempCacheOverflow)
+ /* We wrapped around the end of the temp cache; include the
+ rest of the circle */
+ PrependCacheRgtr( &rgtrTempCache[ itrTempCacheLim ],
+ itrMaxCache - itrTempCacheLim );
+ } /* end for */
+
+ /* Walk backward in the cache, eliminating entries,
+ until: (1) We have run through enough yp's or tr's (return) OR
+ (2) We have exhausted the cache (loop back to refill it)
+ NOTE: Case 2 catches the case when we hit the beginning of the doc */
+
+ Assert( ctrCache >= 1 );
+ Assert( itrLimCache > 0 );
+ for ( ;; )
+ {
+ struct TR *ptr = &rgtrCache[ itrLimCache - 1 ];
+
+ if (ctrCache == 1)
+ { /* Only one thing left in cache: the 1st line of the Ww */
+ cpFirst = ptr->cp;
+ ichCpFirst = ptr->ichCp;
+ break; /* Exhausted cache; loop back to refill it */
+ }
+
+ if ( (dypGrant >= dypLim) || (ctrGrant >= ctrLim) )
+ { /* Passed through enough yp's or tr's -- we're done */
+ if (fAdj)
+ AdjWwVert( ctrGrant, dypGrant );
+ pwwdCur->cpFirst = ptr->cp;
+ pwwdCur->ichCpFirst = ptr->ichCp;
+ pwwdCur->dcpDepend = ptr->dcpDepend;
+ goto SetScroll;
+ }
+
+ /* Remove end entry from the cache */
+ if (--itrLimCache <= 0)
+ itrLimCache = itrMaxCache;
+ ctrCache--;
+
+ /* Update ctrGrant, dypGrant -- we've granted 1 line of scrollback */
+
+ ctrGrant++;
+ dypGrant += rgtrCache [itrLimCache - 1].dyp;
+ } /* end for */
+
+ Assert( ctrCache == 1 );
+ } /* end for */
+
+SetScroll: /* All done; set vert scroll bar according to new cpFirstWw */
+ SetCurWwVScrollPos();
+ return ctrGrant;
+}
+
+
+
+
+/* A P P E N D C A C H E P T R */
+AppendCachePtr( ptr )
+struct TR *ptr;
+{ /* Say we are scrolling up a line, append *ptr to tr cache */
+
+ if (++ctrCache > itrMaxCache)
+ { /* Have to push one off the top */
+ if (++itrFirstCache == itrMaxCache)
+ itrFirstCache = 0;
+ --ctrCache;
+ }
+ /* Now add one onto the end */
+ if (itrLimCache++ == itrMaxCache)
+ itrLimCache = 1;
+ rgtrCache[ itrLimCache - 1 ] = *ptr;
+}
+
+
+
+
+/* P R E P E N D C A C H E R G T R */
+PrependCacheRgtr( rgtr, ctr )
+struct TR rgtr[];
+int ctr;
+{ /* PREPEND one or more lines JUST BEFORE the ones in the cache */
+ /* The tr cache is a ring buffer. rgtrCache[ itrLimCache - 1 ] is the
+ tr entry describing the cpFirst of wwCur; rgtrCache[ itrFirstCache ]
+ is the tr for the earliest line we know of. All between are
+ contiguous. ctrCache is the number of tr's we have cached. */
+
+ struct TR *ptr = &rgtr[ ctr ];
+
+ ctrCache += (ctr = min(ctr, itrMaxCache - ctrCache));
+
+ /* Compensate for state introduced by TrashCache -- itrLimCache == 0 */
+ if (itrLimCache == 0)
+ itrLimCache = itrMaxCache;
+
+ while (ctr-- != 0)
+ { /* Now add each tr */
+ if (itrFirstCache-- == 0)
+ itrFirstCache = itrMaxCache - 1;
+ rgtrCache[ itrFirstCache ] = *(--ptr);
+ }
+}
+
+
+
+
+/* T R A S H C A C H E s */
+TrashCacheS()
+{ /* Invalidate scrolling cache */
+ ctrCache = 0;
+ cpCacheHint = cp0;
+ itrFirstCache = itrLimCache = 0;
+}
+
+
+
+
+
+/* C P H I N T C A C H E */
+typeCP CpHintCache(cp)
+typeCP cp;
+{ /* Give the latest cp <= arg cp that begins a line */
+ return (cpCacheHint <= cp) ? cpCacheHint : cpMinCur;
+}
+
+
+
+
+DirtyCache(cp)
+typeCP cp;
+{ /* Invalidate cache beyond cp */
+ while (ctrCache-- > 1)
+ {
+ typeCP cpT = rgtrCache[itrLimCache - 1].cp;
+ if (--itrLimCache == 0)
+ itrLimCache = itrMaxCache;
+ if (cpT < cp)
+ { /* Found our hint; dirty one extra line for word wrap */
+ cpCacheHint = rgtrCache [itrLimCache - 1].cp;
+ itrLimCache = itrFirstCache;
+ ctrCache = 0;
+ return;
+ }
+ }
+
+ TrashCacheS();
+}
+
diff --git a/private/mvdm/wow16/write/search.c b/private/mvdm/wow16/write/search.c
new file mode 100644
index 000000000..72ebadde1
--- /dev/null
+++ b/private/mvdm/wow16/write/search.c
@@ -0,0 +1,2015 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* search.c Search/Replace */
+/* Brodie Nov 25 83 */
+/* Lipkie Nov 15 83 */
+#define NOATOM
+#define NOBITMAP
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCOMM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOFONT
+#define NOGDI
+#define NOGDICAPMASKS
+#define NOHDC
+#define NOICON
+#define NOKEYSTATE
+#define NOMEMMGR
+#define NOMENUS
+#define NOMETAFILE
+#define NOOPENFILE
+#define NOPEN
+#define NORASTEROPS
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOSHOWWINDOW
+#define NOSOUND
+#define NOSYSCOMMANDS
+#define NOSYSMETRICS
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINSTYLES
+#define NOWNDCLASS
+#include <windows.h>
+
+#define NOIDISAVEPRINT
+#include "mw.h"
+#include "dlgdefs.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "str.h"
+#define NOKCCODES
+#include "ch.h"
+#include "editdefs.h"
+#include "propdefs.h"
+#include "filedefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "fkpdefs.h"
+#include "fmtdefs.h"
+
+#ifdef INEFFLOCKDOWN
+extern FARPROC lpDialogFind;
+extern FARPROC lpDialogChange;
+#else
+FARPROC lpDialogFind = NULL;
+FARPROC lpDialogChange = NULL;
+BOOL far PASCAL DialogFind(HWND, unsigned, WORD, LONG);
+BOOL far PASCAL DialogChange(HWND, unsigned, WORD, LONG);
+#endif
+
+extern HANDLE hMmwModInstance;
+extern HWND vhDlgFind;
+extern HWND vhDlgChange;
+extern HANDLE hParentWw; /* Handle to the parent window */
+extern int vfCursorVisible;
+extern int vfOutOfMemory;
+extern struct WWD rgwwd[];
+extern int wwMac;
+#ifdef ENABLE /* no pDialogCur and ActiveWindow */
+extern WINDOWPTR windowSearch;
+extern WINDOWPTR windowRep;
+extern WINDOWPTR pDialogCur;
+extern WINDOWPTR ActiveWindow;
+extern int cxEditScroll;/* not sure how cxEditScroll is used */
+extern struct SEL selSearch;
+#endif
+extern struct FKPD vfkpdParaIns;
+extern struct PAP *vppapNormal;
+extern typeFC fcMacPapIns;
+extern int wwCur;
+extern struct WWD *pwwdCur;
+extern struct CHP vchpInsert;
+extern struct PAP vpapPrevIns;
+extern int vfSelecting;
+extern typeCP cpMacCur;
+extern typeCP cpMinCur;
+extern int vfSeeSel;
+extern int vfSeeEdgeSel;
+extern int docCur;
+extern struct SEL selCur;
+extern typeCP vcpFetch;
+extern int vccpFetch;
+extern CHAR *vpchFetch;
+extern struct UAB vuab;
+extern int vfSysFull;
+extern struct PAP vpapAbs;
+extern struct CHP vchpFetch;
+extern int ferror;
+extern typeCP cpWall;
+/* Globals used to store settings of flags. Used to propose responses. */
+extern BOOL fParaReplace /* = false initially */;
+extern BOOL fReplConfirm /* = TRUE initially */;
+extern BOOL fSearchWord /* = false initially */;
+extern BOOL fSearchCase /* = false initially */;
+extern BOOL fSpecialMatch;
+extern BOOL fMatchedWhite /* = false initially */;
+extern CHAR (**hszSearch)[]; /* Default search string */
+extern CHAR (**hszReplace)[]; /* Default replace string */
+extern CHAR (**hszFlatSearch)[]; /* All lower case version of search string */
+extern CHAR (**hszRealReplace)[]; /* used for building replacement text */
+extern CHAR (**hszCaseReplace)[]; /* used for building replacement text with
+ appropriate capitalization. */
+extern typeCP cpMatchLim;
+extern int vfDidSearch;
+extern CHAR *szSearch;
+extern CHAR (**HszCreate())[];
+extern HWND vhWndMsgBoxParent;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcArrow;
+#ifdef INTL
+extern CHAR szAppName[];
+extern CHAR szSepName[];
+#endif
+
+
+NEAR DoSearch(void);
+NEAR DoReplace(int, int);
+typeCP NEAR CpSearchSz(typeCP, typeCP, CHAR *);
+NEAR FMakeFlat(int);
+NEAR SetSpecialMatch(void);
+NEAR FSetParaReplace(int);
+NEAR WCaseCp(typeCP, typeCP);
+NEAR SetChangeString(HANDLE, int);
+NEAR PutCpInWwVertSrch(typeCP);
+#ifndef NOLA
+BOOL (NEAR FAbort(void));
+#endif
+BOOL (NEAR FWordCp(typeCP, typeCP));
+BOOL (NEAR FChMatch(int, int *, BOOL));
+NEAR InsertPapsForReplace(typeFC);
+NEAR DestroyModeless(HWND *);
+NEAR FDlgSzTooLong(HWND, int, CHAR *, int);
+NEAR idiMsgResponse(HWND, int, int);
+
+BOOL CheckEnableButton(HANDLE, HANDLE);
+
+BOOL bInSearchReplace = FALSE; // avoid close when we are searching!
+
+
+#define CmdReplace(fThenFind) bInSearchReplace = TRUE; \
+ DoReplace(false, fThenFind); \
+ bInSearchReplace = FALSE
+
+#define CmdReplaceAll() bInSearchReplace = TRUE; \
+ DoReplace(true, false); \
+ bInSearchReplace = FALSE
+#ifndef NOLA
+static int fAbortSearch = FALSE;
+#endif
+static int fChangeSel;
+static int fSelSave = FALSE;
+static struct SEL selSave;
+
+#ifdef DBCS
+/* Additional variables to handle white-space matching
+ for the DBCS space. */
+
+#ifndef KOREA
+static int cbLastMatch;
+#endif
+
+/* Since CpFirstSty(, styChar) calls on FetchCp(), any assumption
+ made about the validity of global variables set by FetchCp()
+ is no longer valid. We explicitly save those variables after
+ each FetchCp and use those instead. (Used in CpSearchSz().)*/
+static typeCP cpFetchSave;
+static int ccpFetchSave;
+static CHAR *pchFetchSave;
+
+/* Also, we move some of the local variables out from
+ CpSearchSz() so that they can be changed by FChMatch(). */
+/*
+int ichDoc;
+int cchMatched;
+typeCP cpFetchNext;
+*/
+#endif
+
+
+NEAR DoSearch()
+{
+int cch;
+typeCP cpSearch;
+typeCP cpSearchLim;
+typeCP cpSearchNext;
+typeCP cpWallActual;
+typeCP cpMatchFirst;
+typeCP CpMin();
+int idpmt;
+int fDidSearch;
+
+if (docCur == docNil)
+ return;
+cch = CchSz(**hszSearch)-1;
+if(cch == 0)
+ {
+ /* this should only occur if the user execute Repeat last find without having
+ previously defined a search string. */
+ Error(IDPMTNotFound);
+ return;
+ }
+
+SetSpecialMatch();
+if(!FMakeFlat(cch))
+ return;
+
+fDidSearch = vfDidSearch;
+cpWallActual = fDidSearch ? CpMin(cpWall, cpMacCur) : cpMacCur;
+cpSearchNext = fDidSearch ? selCur.cpLim : selCur.cpFirst;
+cpSearchLim = (cpSearchNext <= cpWallActual) ? cpWallActual : cpMacCur;
+
+ {
+ do
+ {
+ContinueSearch:
+ cpSearch=CpSearchSz(cpSearchNext,cpSearchLim,**hszFlatSearch);
+ if (cpSearch == cpNil)
+ {
+#ifndef NOLA
+ if (fAbortSearch)
+ {
+ Error(IDPMTCancelSearch);
+ fAbortSearch = FALSE;
+ vfDidSearch = FALSE;
+ FreeH(hszFlatSearch);
+ return;
+ }
+#endif
+ if (cpSearchLim == cpWall && fDidSearch)
+
+ {
+SearchFail: Error(vfDidSearch ? IDPMTSearchDone :
+ IDPMTNotFound);
+ if (vfDidSearch) /* did we previously have a match?*/
+ { /* Yes, do setup for next pass */
+
+ /* clear flag so we can search some more */
+ vfDidSearch = false;
+ /* set "Wall" to immediately after last match */
+ cpWall = selCur.cpLim;
+ /* ask that selection be displayed */
+ vfSeeSel = vfSeeEdgeSel = TRUE;
+ }
+
+ FreeH(hszFlatSearch);
+ return;
+ }
+ else
+ {
+ cpSearchNext = cpMinCur;
+ cpSearchLim = cpWall;
+ fDidSearch = true;
+ goto ContinueSearch;
+ }
+ }
+#ifdef DBCS /* was in JAPAN */
+ cpSearchNext = CpLastStyChar( cpSearch ) + 1;
+#else
+ cpSearchNext = CpLastStyChar( cpSearch + 1 );
+#endif
+ }
+/*--- while (fSearchWord && !FWordCp(cpSearch, cpMatchLim-cpSearch));--*/
+ while (!FCpValid(cpSearch, cpMatchLim - cpSearch));
+ }
+
+if (!vfDidSearch)
+ {
+ cpWall = cpSearch;
+ vfDidSearch = true;
+ }
+
+/*Select( CpFirstSty( cpSearch, styChar ), CpLastStyChar( cpMatchLim ) );*/
+if ( (cpMatchFirst = CpFirstSty( cpSearch, styChar )) != cpMatchLim )
+ Select( cpMatchFirst, cpMatchLim );
+PutCpInWwVertSrch(selCur.cpFirst);
+vfSeeSel = vfSeeEdgeSel = TRUE;
+FreeH(hszFlatSearch);
+}
+
+
+NEAR DoReplace(fReplaceAll, fThenFind)
+int fReplaceAll;
+int fThenFind;
+{
+/* Replace now works as follows:
+ if the current selection is the search text, then replace it with
+ the replace text and jump to the next occurrence of the search text.
+ Otherwise, just jump to the next occurrence of the search text.
+ If fReplaceAll is true, then repeat this operation until the end
+ of the document. */
+int cch;
+typeCP cpSearchStart;
+typeCP cpSearch;
+typeCP cpSearchNext;
+typeCP cpSearchLim;
+typeCP cpSearchNow;
+typeCP cpSearchLimNow;
+typeCP dcp;
+BOOL f1CharSel;
+BOOL fFirstTime;
+int ich;
+int cchReplace;
+int cwReplace;
+int iCurCase;
+int iLastCase;
+typeFC fcCaseSz;
+typeCP cpMacTextT;
+typeCP cpWallActual;
+int fDidSearch = vfDidSearch;
+struct CHP chp;
+typeCP cpMacSave;
+
+iLastCase = -1; /* indicate that the string pointed to by hszCaseReplace
+ has not been given a value yet. */
+
+if (!FWriteOk(fwcNil) || docCur == docNil)
+ /* Out of memory, read only document, etc */
+ return;
+
+cch = CchSz(**hszSearch)-1;
+if(cch == 0)
+ {
+ Error(IDPMTNotFound);
+ return;
+ }
+
+SetSpecialMatch();
+
+if(!FMakeFlat(cch))
+ return;
+
+cwReplace = CwFromCch(cchReplace = CchSz(**hszReplace));
+if(FNoHeap(hszRealReplace = (CHAR (**) [])HAllocate(cwReplace)))
+ {
+ FreeH(hszFlatSearch);
+ return;
+ }
+bltbyte(**hszReplace, **hszRealReplace, cchReplace);
+
+if(FNoHeap(hszCaseReplace = (CHAR (**) [])HAllocate(cwReplace)))
+ {
+ FreeH(hszFlatSearch);
+ FreeH(hszRealReplace);
+ return;
+ }
+
+if(!FSetParaReplace(cchReplace))
+ {
+ FreeH(hszFlatSearch);
+ FreeH(hszCaseReplace);
+ FreeH(hszRealReplace);
+ return;
+ }
+
+cch = CchSz(**hszRealReplace)-1;
+fFirstTime = TRUE;
+cpWallActual = fDidSearch ? CpMin(cpWall, cpMacCur) : cpMacCur;
+
+cpSearchNow = cpSearchStart = selCur.cpFirst;
+if (fReplaceAll || !fThenFind)
+ cpSearchLim = selCur.cpLim;
+else
+ cpSearchLim = (cpSearchStart < cpWallActual) ? cpWallActual : cpMacCur;
+cpSearchLimNow = selCur.cpLim;
+
+if (fReplaceAll)
+ {
+ cpWallActual = cpSearchLim;
+ fDidSearch = true;
+ }
+
+NoUndo(); /* Prevent the SetUndo from getting merged with adjacent stuff */
+cpMacTextT = CpMacText(docCur);
+if(cpSearchLimNow > cpMacTextT)
+ SetUndo(uacDelNS, docCur, cp0, cpMacTextT, docNil, cpNil, cp0, 0);
+else
+ SetUndo(uacDelNS, docCur, cpSearchStart, cpSearchLimNow - cpSearchStart,
+ docNil, cpNil, cp0, 0);
+
+if (ferror) goto MemoryError;
+cpSearchNext = cpSearchStart;
+ {
+ do
+ {
+/* ForcePmt(IDPMTSearching);*/
+ do
+ {
+ContinueSearch:
+ cpSearch = CpSearchSz(cpSearchNext, cpSearchLim, **hszFlatSearch);
+ if (cpSearch == cpNil)
+ if ((cpSearchLim == cpWallActual && fDidSearch) || fAbortSearch)
+
+DoneReplacingN:
+ {
+DoneReplacingP:
+ FreeH(hszFlatSearch);
+ FreeH(hszCaseReplace);
+ FreeH(hszRealReplace);
+ cpMacTextT = CpMacText(docCur);
+ if (fReplaceAll || fFirstTime)
+ {
+ if(cpSearchLimNow > cpMacTextT)
+ SetUndo(uacInsert,docCur,cp0,
+ cpMacTextT,docNil,cpNil,cp0,0);
+ else
+ SetUndo(uacInsert,docCur,cpSearchStart,
+ cpSearchLimNow - cpSearchStart,
+ docNil,cpNil,cp0,0);
+ if (ferror) goto MemoryError;
+ vuab.uac = uacReplGlobal;
+ SetUndoMenuStr(IDSTRUndoBase);
+ /*Select( CpFirstSty( cpSearchStart, styChar ),
+ CpLastStyChar( cpSearchLimNow ) );*/
+ Select( CpFirstSty( cpSearchStart, styChar ),
+ (fReplaceAll ? cpSearchStart : cpSearchLimNow) );
+ vfSeeSel = fReplaceAll;
+ if (fReplaceAll)
+ { /* reestablish the search after a changeall in case of a F3 next time */
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ }
+ }
+ else if (!fReplaceAll)
+ {
+ if (cpSearch == cpNil)
+ /*Select( CpFirstSty( cpSearchStart, styChar ),
+ CpLastStyChar( cpSearchLimNow ) );*/
+ Select( CpFirstSty( cpSearchStart, styChar ),
+ cpSearchLimNow );
+ else if (!fFirstTime)
+ /*Select( CpFirstSty( cpSearch, styChar ),
+ CpLastStyChar( cpMatchLim ) );*/
+ Select( CpFirstSty( cpSearch, styChar ),
+ cpMatchLim );
+ PutCpInWwVertSrch(selCur.cpFirst);
+ vfSeeSel = vfSeeEdgeSel = TRUE;
+ }
+
+ if (fAbortSearch)
+ {
+ fAbortSearch = FALSE;
+ Error(IDPMTCancelSearch);
+ }
+ else if (fFirstTime)
+ Error(fReplaceAll ? IDPMTNoReplace : (vfDidSearch ? IDPMTSearchDone : IDPMTNotFound));
+ return;
+ }
+ else
+ {
+ cpSearchNext = cpMinCur;
+ cpSearchLim = cpWallActual;
+ fDidSearch = true;
+ goto ContinueSearch;
+ }
+#ifdef DBCS /* was in JAPAN */
+ cpSearchNext = CpLastStyChar( cpSearch ) + 1;
+#else
+ cpSearchNext = CpLastStyChar( cpSearch + 1 );
+#endif
+ }
+/* while(fSearchWord && !FWordCp(cpSearch,cpMatchLim - cpSearch));*/
+ while(!FCpValid(cpSearch, cpMatchLim - cpSearch));
+
+ if (!fReplaceAll && (cpSearch != cpSearchNow || cpMatchLim != cpSearchLimNow))
+ {
+ if (fThenFind)
+ { /* Get here if: Did a Change, then Find. Could not
+ do the change, but did find a next occurence */
+ cpSearchNow = cpSearchNext = cpSearchStart = cpSearch;
+ cpSearchLimNow = cpMatchLim;
+ fFirstTime = false; /* suppress error message */
+ SetUndo(uacInsert, docCur, cpSearchStart,
+ cpSearchLimNow - cpSearchStart, docNil, cpNil, cp0, 0);
+ if (ferror) goto MemoryError;
+ if (!vfDidSearch)
+ {
+ cpWall = cpSearch;
+ vfDidSearch = true;
+ }
+/*---- continue;----*/
+ goto DoneReplacingN;
+ }
+ fFirstTime = true; /* Cause error message */
+ cpSearchStart = cpSearchNow;
+ cpSearchLim = cpSearchLimNow;
+ goto DoneReplacingN;
+ }
+
+/*----- vfDidSearch = true;----*/
+
+#ifdef FOOTNOTES
+ if(FEditFtn(cpSearch, cpMatchLim))
+ {
+ ferror = false; /* Reset error condition so that we don't
+ deallocate strings twice (KJS) */
+ continue;
+ }
+#endif
+
+ fFirstTime = FALSE;
+ if (vfOutOfMemory || vfSysFull)
+ { /* Out of memory (heap or disk) */
+ Error(IDPMTNoMemory);
+ FreeH(hszFlatSearch);
+ FreeH(hszRealReplace);
+ FreeH(hszCaseReplace);
+ cpMacTextT = CpMacText(docCur);
+ if(cpSearchLim > cpMacTextT)
+ SetUndo(uacInsert,docCur,cp0,cpMacTextT,docNil,cpNil,cp0,0);
+ else
+ SetUndo(uacInsert,docCur,cpSearchStart,
+ cpSearchLimNow - cpSearchStart,docNil,cpNil,cp0,0);
+ if (ferror)
+ NoUndo();
+ else
+ vuab.uac = uacReplGlobal;
+ return;
+ }
+ FetchCp(docCur, cpSearch, 0, fcmProps); /* Get props of first char
+ that we are replacing */
+ blt(&vchpFetch, &chp, cwCHP);
+ chp.fSpecial = false;
+
+ iCurCase = 0; /* assume that the replacement string doesn't
+ require special capitalization */
+
+ /* if we're not matching upper/lower case call WCaseCp to determine
+ the capitalization pattern of the matched string */
+ if (!fSearchCase)
+ iCurCase = WCaseCp(cpSearch, cpMatchLim - cpSearch);
+
+ /* if the new capitalization pattern of the matched string
+ doesn't match the current contents of hszCaseReplace,
+ copy the replacement string to hszCaseReplace and transform
+ hszCaseReplace to conform to the new pattern */
+ if (iCurCase != iLastCase)
+ switch (iCurCase)
+ {
+ default:
+ case 0: /* no special capitalization required */
+ bltbyte(**hszRealReplace, **hszCaseReplace, cch+1);
+ break;
+ case 1: /* first character of string must be capitalized */
+ bltbyte(**hszRealReplace, **hszCaseReplace, cch+1);
+ ***hszCaseReplace = ChUpper(***hszRealReplace);
+ break;
+ case 2: /* all characters must be capitalized */
+ for (ich = 0; ich < cch; ich++)
+ (**hszCaseReplace)[ich] = ChUpper((**hszRealReplace)[ich]);
+ break;
+ }
+
+ /* do CachePara to find the current para props. CachePara has the
+ side effect of setting vpapAbs */
+ CachePara(docCur, cpSearch);
+
+ /* if the capitalization pattern has changed OR
+ the character properties of the replacement text don't match
+ those of the last insert OR
+ the paragraph properties of the replacement text don't match
+ those of the last insert, THEN
+
+ 1) call NewChpIns to write a run describing the character
+ properties of the previous insertion text,
+ 2) call FcWScratch to write the characters of the replacement
+ string to the scratch file,
+ 3) if we are replacing paragraph marks, call InsertPapsForReplace
+ to write runs describing each paragraph in the replacement
+ string */
+ if (iCurCase != iLastCase ||
+ CchDiffer(&vchpInsert,&chp,cchCHP) != 0 ||
+ (fParaReplace && CchDiffer(&vpapPrevIns, &vpapAbs, cchPAP) != 0))
+ {
+ NewChpIns(&chp);
+ fcCaseSz = FcWScratch(**hszCaseReplace,cch);
+ if (fParaReplace)
+ InsertPapsForReplace(fcCaseSz);
+ }
+
+ /* Now since we have written the proper replacement text to
+ the scratch file and have setup the character and paragraph runs to
+ describe that text, simply do a replace to insert the replacement
+ text into the piece table */
+ Replace(docCur, cpSearch, cp0, fnScratch, fcCaseSz, (typeFC) cch);
+ if (ferror) goto MemoryError;
+
+ iLastCase = iCurCase; /* record new capitalization pattern */
+
+ /* Now delete the found text from the piece table*/
+ cpMacSave = cpMacCur;
+ Replace(docCur, cpSearch+cch, cpMatchLim - cpSearch, fnNil, fc0, fc0);
+ dcp = cpMacSave - cpMacCur; /* Calculate dcp here because picture
+ paragraphs may have interfered with deleting */
+ if (ferror) goto MemoryError;
+ if (!fReplaceAll)
+ {
+ SetUndo(uacInsert, docCur, cpSearch, (typeCP) cch,
+ docNil, cpNil, cp0, 0);
+ if (ferror) goto MemoryError;
+ SetUndoMenuStr(IDSTRUndoBase);
+ }
+ cpSearchLim += cch - dcp;
+ cpMatchLim += cch - dcp;
+ cpWallActual += cch - dcp;
+#ifdef DBCS /* was in JAPAN */
+ cpSearchNext = cpMatchLim;
+#else
+ cpSearchNext = CpLastStyChar( cpMatchLim );
+#endif
+ if (fReplaceAll)
+ cpSearchLimNow = cpSearchLim;
+ }
+ while (fReplaceAll);
+ }
+if (fThenFind)
+ {
+ do
+ {
+ContinueSearch2:
+ if ((cpSearch = CpSearchSz(cpSearchNext, cpSearchLim,
+ **hszFlatSearch)) == cpNil)
+ {
+ if ((cpSearchLim == cpWallActual && fDidSearch) ||
+ fAbortSearch)
+ {
+ fFirstTime = false; /* Supress error message */
+ /*Select( CpFirstSty( cpSearchStart, styChar ),
+ CpLastStyChar( cpMatchLim ) );*/
+ Select( CpFirstSty( cpSearchStart, styChar ),
+ cpMatchLim );
+ PutCpInWwVertSrch(selCur.cpFirst);
+ cpSearchLimNow = cpMatchLim;
+ Error(fAbortSearch ?
+ IDPMTCancelSearch : IDPMTSearchDone);
+ fAbortSearch = FALSE;
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ goto DoneReplacingP;
+ }
+ else
+ {
+ cpSearchNext = cpMinCur;
+ cpSearchLim = cpWallActual;
+ fDidSearch = true;
+ goto ContinueSearch2;
+ }
+ }
+#ifdef DBCS /* was in JAPAN */
+ cpSearchNext = CpLastStyChar( cpSearch ) + 1;
+#else
+ cpSearchNext = CpLastStyChar( cpSearch + 1 );
+#endif
+ }
+/*-- while(fSearchWord && !FWordCp(cpSearch,cpMatchLim - cpSearch));*/
+ while(!FCpValid(cpSearch, cpMatchLim - cpSearch));
+ if (!vfDidSearch)
+ {
+ cpWall = cpSearch;
+ vfDidSearch = true;
+ }
+ }
+goto DoneReplacingP;
+
+MemoryError:
+ FreeH(hszFlatSearch);
+ FreeH(hszCaseReplace);
+ FreeH(hszRealReplace);
+ NoUndo();
+
+ /* counter off the losing insertion point after incomplete change all */
+ if (fReplaceAll && fSelSave)
+ {
+ selCur.cpFirst = selSave.cpFirst;
+ selCur.cpLim = selSave.cpLim;
+ }
+}
+#ifdef DBCS
+BOOL fDBCS = FALSE;
+#endif
+
+typeCP NEAR CpSearchSz(cpFirst, cpMacSearch, sz)
+typeCP cpFirst;
+typeCP cpMacSearch;
+CHAR *sz;
+{{ /* Finds first occurrence of sz in docCur starting at cpFirst */
+ /* Returns cpNil if not found */
+ /* Ignore case of letters if fSearchCase is FALSE. This assumes that the
+ pattern has already been folded to lower case. */
+
+ CHAR ch;
+ BOOL fMatched;
+ int ichPat = 0;
+ int ichDoc = 0;
+ int cchMatched = 0;
+ typeCP cpFetchNext;
+ /*EVENT event;*/
+
+#ifdef DBCS
+ typeCP cpFound;
+ CHAR rgchT[dcpAvgSent];
+#endif
+
+
+ szSearch = sz;
+#ifdef DBCS
+ /* Initialize those local variables moved out from this
+ function. */
+ ichDoc = 0;
+ cchMatched = 0;
+ pchFetchSave = &rgchT[0];
+
+#ifndef KOREA
+ cbLastMatch = 1;
+#endif
+
+#endif
+
+
+#ifdef DBCS
+ FetchCp(docCur, cpFirst, 0, fcmChars + fcmNoExpand);
+ cpFetchSave = vcpFetch;
+ bltbyte(vpchFetch, rgchT,
+ ccpFetchSave = ((vccpFetch > dcpAvgSent) ? dcpAvgSent : vccpFetch));
+
+ Assert(cpFetchSave == cpFirst);
+
+ cpFetchNext = cpFetchSave + ccpFetchSave;
+#else
+ FetchCp(docCur, cpFirst, 0, fcmChars + fcmNoExpand);
+ Assert(vcpFetch == cpFirst);
+
+ cpFetchNext = vcpFetch + vccpFetch;
+#endif
+
+ fMatchedWhite = false;
+
+ for (; ;)
+ {
+ if (szSearch[ichPat] == '\0' )
+ {{ /* Found it */
+#ifdef DBCS
+ typeCP cpFound;
+
+ cpMatchLim = vcpFetch+ichDoc - (fMatchedWhite ? 1 : 0);
+ cpFound = cpFetchSave + ichDoc - cchMatched;
+ if (CpFirstSty(cpFound, styChar) == cpFound) {
+ /* It is on a Kanji boundary. We really found it. */
+ return (cpFound);
+ }
+ else {
+ /* The last character did not match, try again
+ excluding the last byte match. */
+#ifndef KOREA
+ cchMatched -= cbLastMatch;
+ cbLastMatch = 1;
+#endif
+
+ fMatchedWhite = false;
+ goto lblNextMatch;
+ }
+#else
+ cpMatchLim = vcpFetch+ichDoc - (fMatchedWhite ? 1 : 0);
+
+ return vcpFetch + ichDoc - cchMatched;
+#endif
+ }}
+
+#ifdef DBCS
+ if (cpFetchSave + ichDoc >= cpMacSearch)
+#else
+ if (vcpFetch + ichDoc >= cpMacSearch)
+#endif
+ {{ /* Not found */
+ if(fMatchedWhite && szSearch[ichPat+2] == '\0')
+ { /* Found it */
+#ifdef DBCS
+ cpMatchLim = cpFetchSave + ichDoc;
+ cpFound = cpFetchSave + ichDoc - cchMatched;
+ if (CpFirstSty(cpFound, styChar) == cpFound) {
+ /* It is on a Kanji boundary, We really found it. */
+ return (cpFound);
+ }
+ else {
+ /* The last character did not match, try again
+ excluding the last byte match. */
+#ifndef KOREA
+ cchMatched -= cbLastMatch;
+ cbLastMatch = 1;
+#endif
+
+ fMatchedWhite = false;
+ goto lblNextMatch;
+ }
+#else
+ cpMatchLim = vcpFetch+ichDoc;
+ return vcpFetch + ichDoc - cchMatched;
+#endif
+ }
+ else
+ return cpNil;
+ }}
+
+#if defined(DBCS) && !defined(KOREA)
+ if (ichDoc + cbLastMatch - 1 >= ccpFetchSave)
+#else
+ if (ichDoc >= vccpFetch)
+#endif
+ { /* Need more cp's */
+ {{
+#ifndef NOLA /* no look ahead */
+/* check if abort search */
+ if (FAbort())
+ {
+ fAbortSearch = TRUE;
+ return cpNil;
+ }
+#endif /* NOLA */
+
+/* FetchCp(docNil, cpNil, 0, fcmChars + fcmNoExpand); */
+/* we changed from a sequential fetch to a random fetch because a resize of the
+window may cause another FetchCp before we reach here */
+#ifdef DBCS
+ FetchCp(docCur, cpFetchNext, 0, fcmChars + fcmNoExpand);
+ cpFetchSave = vcpFetch;
+ bltbyte(vpchFetch, rgchT,
+ ccpFetchSave = ((vccpFetch > dcpAvgSent) ?
+ dcpAvgSent : vccpFetch));
+
+ cpFetchNext = cpFetchSave + ccpFetchSave;
+#else
+ FetchCp(docCur, cpFetchNext, 0, fcmChars + fcmNoExpand);
+ cpFetchNext = vcpFetch + vccpFetch;
+#endif
+ ichDoc = 0;
+ }}
+ continue;
+ }
+
+#ifdef DBCS
+ ch = pchFetchSave[ichDoc++];
+#ifndef KOREA
+ cbLastMatch = 1;
+#endif
+
+#else
+ ch = vpchFetch[ichDoc++];
+#endif
+ if(!fSpecialMatch)
+ {
+ /* NOTE: this is just ChLower() brought in-line for speed */
+#ifdef DBCS
+ if( fDBCS )
+ fDBCS = FALSE;
+ else
+ if(!fSearchCase)
+#ifdef TAIWAN
+ if ( !( fDBCS = IsDBCSLeadByte( ch )))
+#endif
+ { /* avoid proc call for common cases */
+ if(ch >= 'A' && ch <= 'Z') ch += 'a' - 'A';
+ else if(ch < 'a' || ch > 'z') ch = ChLower(ch);
+ }
+#else
+ if(!fSearchCase)
+ { /* avoid proc call for common cases */
+ if(ch >= 'A' && ch <= 'Z') ch += 'a' - 'A';
+ else if(ch < 'a' || ch > 'z') ch = ChLower(ch);
+ }
+#endif
+
+ if(szSearch[ichPat] == ch)
+ {
+ ichPat++;
+ fMatched = true;
+ }
+ else if(ch == chReturn || ch == chNRHFile)
+ fMatched = true;
+ else
+ fMatched = false;
+ }
+ else
+ fMatched = FChMatch(ch, &ichPat, true);
+
+#ifdef DBCS
+ fDBCS = IsDBCSLeadByte( ch );
+#endif
+
+ if(fMatched)
+ {
+#if defined(DBCS) && !defined(KOREA)
+ cchMatched += cbLastMatch;
+#else
+ cchMatched++;
+#endif
+ }
+ else
+ { /* No match; try again */
+#ifdef DBCS
+lblNextMatch:
+#endif
+ if ((ichDoc -= cchMatched) < 0) /* Go back # of matched chars */
+ {{ /* Overshot the mark */
+#ifdef DBCS
+ FetchCp(docCur, cpFetchSave + ichDoc, 0, fcmChars + fcmNoExpand);
+ cpFetchSave = vcpFetch;
+ bltbyte(vpchFetch, rgchT,
+ ccpFetchSave = ((vccpFetch > dcpAvgSent) ?
+ dcpAvgSent : vccpFetch));
+
+ cpFetchNext = cpFetchSave + ccpFetchSave;
+#else
+ FetchCp(docCur, vcpFetch + ichDoc, 0, fcmChars + fcmNoExpand);
+
+/* this is for the next FetchCp in this forever loop that used to depend
+on a sequential fetch */
+ cpFetchNext = vcpFetch + vccpFetch;
+#endif
+ ichDoc = 0;
+ }}
+ ichPat = 0;
+ cchMatched = 0;
+ }
+ }
+}}
+
+
+/* set up in hszFlatSearch a copy of hszSearch that is all lower case.
+ Note that we assume the old contents of hszFlatSearch were freed.
+ Return True if success, False if out of memory.
+*/
+NEAR FMakeFlat(cch)
+int cch; /*CchSz(**hszSearch)-1*/
+{
+ CHAR *pch1;
+ CHAR *pch2;
+
+ hszFlatSearch = (CHAR (**) [])HAllocate(CwFromCch(cch+1));
+ if(FNoHeap(hszFlatSearch))
+ return(FALSE);
+
+ if(!fSearchCase)
+ {
+#ifdef DBCS
+ for(pch1= **hszSearch, pch2 = **hszFlatSearch;*pch1!='\0';)
+ if( IsDBCSLeadByte(*pch1) ) {
+ *pch2++ = *pch1++;
+ *pch2++ = *pch1++;
+ } else
+ *pch2++ = ChLower(*pch1++);
+#else
+ for(pch1= **hszSearch, pch2 = **hszFlatSearch;*pch1!='\0';pch1++,pch2++)
+ *pch2 = ChLower(*pch1);
+#endif
+ *pch2 = '\0';
+ }
+ else
+ bltbyte(**hszSearch, **hszFlatSearch, cch+1);
+ return(TRUE);
+}
+
+
+/* sets the global fSpecialMatch if the more complicated character matching
+ code is needed */
+NEAR SetSpecialMatch()
+{
+ CHAR *pch = **hszSearch;
+ CHAR ch;
+
+#ifdef DBCS
+ for( ch = *pch ; ch != '\0'; pch = AnsiNext(pch), ch = *pch )
+#else
+ while((ch = *pch++) != '\0')
+#endif
+ {
+ switch(ch)
+ {
+ default:
+ continue;
+ case chMatchAny:
+ case chPrefixMatch:
+ case chSpace:
+ case chHyphen:
+ fSpecialMatch = true;
+ return;
+ }
+ }
+ fSpecialMatch = false;
+ return;
+}
+
+/* Sets the global fParaReplace if the user wants to insert Paragraph breaks
+ (since special insertion code must be run). Also sets up the global
+ hszRealReplace to reflect any meta characters in hszReplace */
+NEAR FSetParaReplace(cch)
+int cch; /*CchSz(**hszReplace)*/
+{
+ CHAR *rgch = **hszRealReplace;
+ int ich = 0;
+ CHAR ch;
+ CHAR chNew;
+
+ fParaReplace = false;
+
+ while((ch = rgch[ich]) != '\0')
+ {
+#ifdef DBCS
+ if(IsDBCSLeadByte(ch)){
+ ich +=2;
+ continue;
+ }
+#endif
+ switch(ch)
+ {
+ default:
+ break;
+ case chPrefixMatch:
+ switch(rgch[ich+1])
+ {
+ default:
+ /* just escaping the next char */
+ if(rgch[ich+1] == '\0')
+ chNew = chPrefixMatch;
+ else
+ chNew = rgch[ich+1];
+ break;
+ case chMatchNBSFile:
+ chNew = chNBSFile;
+ break;
+ case chMatchTab:
+ chNew = chTab;
+ break;
+ case chMatchNewLine:
+ chNew = chNewLine;
+ break;
+ case chMatchNRHFile:
+ chNew = chNRHFile;
+ break;
+ case chMatchSect:
+ chNew = chSect;
+ break;
+ case chMatchEol:
+ chNew = chEol;
+ break;
+ }
+#ifdef CRLF
+ if(chNew != chEol)
+ bltbyte(&(rgch[ich+1]),&(rgch[ich]), cch-ich-1);
+#else
+ bltbyte(&(rgch[ich+1]),&(rgch[ich]), cch-ich-1);
+#endif /*CRLF*/
+ if(chNew == chEol)
+ {
+ fParaReplace = true;
+#ifdef CRLF
+ rgch[ich++] = chReturn;
+#endif /*CRLF*/
+ }
+ rgch[ich] = chNew;
+ break;
+ case chEol:
+#ifdef CRLF
+ if(ich == 0 || rgch[ich-1] != chReturn)
+ /* they didn't put in a return! */
+ {
+ CHAR (**hsz)[];
+
+ hsz = (CHAR (**) [])HAllocate(CwFromCch(cch+1));
+ if(FNoHeap(hsz))
+ {
+ return false;
+ }
+ bltbyte(**hszRealReplace, **hsz, ich);
+ (**hsz)[ich] = chReturn;
+ bltbyte((**hszRealReplace)+ich, (**hsz)+ich+1,
+ cch - ich);
+ FreeH(hszRealReplace);
+ hszRealReplace = hsz;
+ rgch = **hszRealReplace;
+ cch++;
+ ich++;
+ }
+#endif /*CRLF*/
+ fParaReplace = true;
+ break;
+ }
+ ich++;
+ }
+ return true;
+}
+
+NEAR WCaseCp(cp,dcp)
+typeCP cp;
+typeCP dcp;
+{
+ /* Determines capitalization pattern in a piece of text. Used when doing
+ replace to match existing pattern. returns an int which is one of:
+ 0 - Not initial capital
+ 1 - Initial Capital but lower case appears later
+ 2 - Initial Capital and no lower case in the string
+ Assumes a valid cp, dcp pair.
+ */
+ int ichDoc;
+
+ FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
+ if(!isupper(vpchFetch[0]))
+ return(0);
+
+ /* we now know there is an initial cap. Are there any lower case chars? */
+ for(ichDoc=1; vcpFetch+ichDoc < cp + dcp;)
+ {
+ if(ichDoc >= vccpFetch)
+ {
+ FetchCp(docNil, cpNil, 0, fcmChars + fcmNoExpand);
+ ichDoc = 0;
+ continue;
+ }
+ if(islower(vpchFetch[ichDoc++]))
+ return(1);
+ }
+
+ /* No lower case letters were found. */
+ return(2);
+}
+
+int
+FCpValid(cp, dcp)
+typeCP cp, dcp;
+{
+CachePara(docCur, cp);
+if (vpapAbs.fGraphics)
+ return false;
+if (fSearchWord)
+ return FWordCp(cp, dcp);
+return true;
+}
+
+NEAR DestroyModeless(phDlg)
+HWND * phDlg;
+{
+ HWND hDlg = *phDlg;
+
+ *phDlg = (HWND)NULL;
+ vhWndMsgBoxParent = (HANDLE)NULL;
+ DestroyWindow(hDlg);
+} /* end of DestroyModeless */
+
+
+BOOL far PASCAL DialogFind( hDlg, message, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+CHAR szBuf[257];
+int cch = 0;
+HANDLE hCtlFindNext = GetDlgItem(hDlg, idiFindNext);
+
+/* This routine handles input to the Find dialog box. */
+switch (message)
+ {
+ case WM_INITDIALOG:
+#ifdef ENABLE /* not sure how cxEditScroll is used */
+ cxEditScroll = 0;
+#endif
+ CheckDlgButton(hDlg, idiWholeWord, fSearchWord);
+ CheckDlgButton(hDlg, idiMatchCase, fSearchCase);
+ cch = CchCopySz(**hszSearch, szBuf);
+ if (cch == 0)
+ {
+ EnableWindow(hCtlFindNext, false);
+ }
+ else
+ {
+ SetDlgItemText(hDlg, idiFind, (LPSTR)szBuf);
+ SelectIdiText(hDlg, idiFind);
+ }
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ return( TRUE ); /* ask windows to set focus to the first item also */
+
+ case WM_ACTIVATE:
+ if (wParam) /* turns active */
+ {
+ vhWndMsgBoxParent = hDlg;
+ }
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiFind:
+ if (HIWORD(lParam) == EN_CHANGE)
+ {
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ CheckEnableButton(LOWORD(lParam), hCtlFindNext);
+ }
+ break;
+
+ case idiWholeWord:
+ case idiMatchCase:
+ CheckDlgButton(hDlg, wParam, !IsDlgButtonChecked(hDlg, wParam));
+ break;
+ case idiFindNext:
+ if (IsWindowEnabled(hCtlFindNext))
+ {
+ CHAR (**hszSearchT)[] ;
+
+ if (FDlgSzTooLong(hDlg, idiFind, szBuf, 257))
+ {
+ switch (idiMsgResponse(hDlg, idiFind, IDPMTTruncateSz))
+ {
+ case idiOk:
+ /* show truncated text to user */
+ SetDlgItemText(hDlg, idiFind, (LPSTR)szBuf);
+ break;
+ case idiCancel:
+ default:
+ return(TRUE);
+ }
+ }
+ if (FNoHeap(hszSearchT = HszCreate(szBuf)))
+ break;
+ /* fSearchForward = 1; search direction -- always forward */
+ PostStatusInCaption(IDSTRSearching);
+ StartLongOp();
+ FreeH(hszSearch);
+ hszSearch = hszSearchT;
+ fSearchCase = IsDlgButtonChecked(hDlg, idiMatchCase);
+ fSearchWord = IsDlgButtonChecked(hDlg, idiWholeWord);
+ EnableExcept(vhDlgFind, FALSE);
+ DoSearch();
+ EnableExcept(vhDlgFind, TRUE);
+ EndLongOp(vhcIBeam);
+ PostStatusInCaption(NULL);
+ }
+ break;
+ case idiCancel:
+LCancelFind:
+ DestroyModeless(&vhDlgFind);
+ break;
+ default:
+ return(FALSE);
+ }
+ break;
+
+ case WM_CLOSE:
+ if (bInSearchReplace)
+ return TRUE;
+
+ goto LCancelFind;
+
+#ifndef INEFFLOCKDOWN
+ case WM_NCDESTROY:
+ FreeProcInstance(lpDialogFind);
+ lpDialogFind = NULL;
+ /* fall through to return false */
+#endif
+
+ default:
+ return(FALSE);
+ }
+return(TRUE);
+} /* end of DialogFind */
+
+
+BOOL far PASCAL DialogChange( hDlg, message, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned message;
+WORD wParam;
+LONG lParam;
+{
+CHAR szBuf[257]; /* max 255 char + '\0' + 1 so as to detact too long string */
+int cch = 0;
+HANDLE hCtlFindNext = GetDlgItem(hDlg, idiFindNext);
+CHAR (**hszSearchT)[];
+CHAR (**hszReplaceT)[];
+
+/* This routine handles input to the Change dialog box. */
+
+switch (message)
+ {
+ case WM_INITDIALOG:
+#ifdef ENABLE /* not sure how cxEditScroll is used */
+ cxEditScroll = 0;
+#endif
+ szBuf[0] = '\0';
+ CheckDlgButton(hDlg, idiWholeWord, fSearchWord);
+ CheckDlgButton(hDlg, idiMatchCase, fSearchCase);
+ cch = CchCopySz(**hszSearch, szBuf);
+ SetDlgItemText(hDlg, idiFind, (LPSTR)szBuf);
+ if (cch > 0)
+ {
+ SelectIdiText(hDlg, idiFind);
+ }
+ else
+ {
+ EnableWindow(hCtlFindNext, false);
+ EnableWindow(GetDlgItem(hDlg, idiChangeThenFind), false);
+ //EnableWindow(GetDlgItem(hDlg, idiChange), false);
+ EnableWindow(GetDlgItem(hDlg, idiChangeAll), false);
+ }
+ cch = CchCopySz(**hszReplace, szBuf);
+ SetDlgItemText(hDlg, idiChangeTo, (LPSTR)szBuf);
+ fChangeSel = false;
+ vfDidSearch = false;
+ SetChangeString(hDlg, selCur.cpFirst == selCur.cpLim);
+ cpWall = selCur.cpLim;
+ return( TRUE ); /* ask windows to set focus to the first item also */
+
+ case WM_ACTIVATE:
+ if (wParam)
+ {
+ vhWndMsgBoxParent = hDlg;
+ SetChangeString(hDlg, (selCur.cpFirst == selCur.cpLim) || vfDidSearch);
+ }
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to
+ the dialog manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case idiFind: /* edittext */
+ if (HIWORD(lParam) == EN_CHANGE)
+ {
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+ if (!CheckEnableButton(LOWORD(lParam), hCtlFindNext))
+ {
+ EnableWindow(GetDlgItem(hDlg, idiChangeThenFind), false);
+ //EnableWindow(GetDlgItem(hDlg, idiChange), false);
+ EnableWindow(GetDlgItem(hDlg, idiChangeAll), false);
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hDlg, idiChangeThenFind), true);
+ //EnableWindow(GetDlgItem(hDlg, idiChange), true);
+ EnableWindow(GetDlgItem(hDlg, idiChangeAll), true);
+ }
+ return(TRUE);
+ }
+ else
+ return(FALSE);
+
+ case idiChangeTo: /* edittext */
+ return(FALSE);
+
+ case idiFindNext: /* Button for Find Next */
+ /* Windows did not check if the default button is disabled
+ or not, so we have to check that! */
+ if (!IsWindowEnabled(hCtlFindNext))
+ break;
+ //case idiChange: /* Change, and stay put */
+ case idiChangeThenFind: /* Change, then Find button */
+ case idiChangeAll: /* Button for Replace All */
+ if (wwCur < 0)
+ break;
+ if (FDlgSzTooLong(hDlg, idiFind, szBuf, 257))
+ {
+ switch (idiMsgResponse(hDlg, idiFind, IDPMTTruncateSz))
+ {
+ case idiOk:
+ /* show truncated text to user */
+ SetDlgItemText(hDlg, idiFind, (LPSTR)szBuf);
+ break;
+ case idiCancel:
+ default:
+ return(TRUE);
+ }
+ }
+ if (FNoHeap(hszSearchT = HszCreate(szBuf)))
+ break;
+ if (FDlgSzTooLong(hDlg, idiChangeTo, szBuf, 257))
+ {
+ switch (idiMsgResponse(hDlg, idiChangeTo, IDPMTTruncateSz))
+ {
+ case idiOk:
+ /* show truncated text to user */
+ SetDlgItemText(hDlg, idiChangeTo, (LPSTR)szBuf);
+ break;
+ case idiCancel:
+ default:
+ return(TRUE);
+ }
+ }
+ if (FNoHeap(hszReplaceT = HszCreate(szBuf)))
+ break;
+ PostStatusInCaption(IDSTRSearching);
+ StartLongOp();
+ FreeH(hszSearch);
+ hszSearch = hszSearchT;
+ FreeH(hszReplace);
+ hszReplace = hszReplaceT;
+ /* fReplConfirm = 1;*/
+ fSearchCase = IsDlgButtonChecked(hDlg, idiMatchCase);
+ fSearchWord = IsDlgButtonChecked(hDlg, idiWholeWord);
+ EnableExcept(vhDlgChange, FALSE);
+ switch (wParam)
+ {
+ case idiFindNext:
+ DoSearch();
+ break;
+ //case idiChange:
+ case idiChangeThenFind:
+ CmdReplace(wParam == idiChangeThenFind);
+ break;
+ case idiChangeAll:
+ TurnOffSel();
+ if (!fChangeSel)
+ {
+ fSelSave = TRUE;
+ selSave.cpFirst = selCur.cpFirst;
+ selSave.cpLim = selCur.cpLim;
+ selCur.cpFirst = cpMinCur;
+ selCur.cpLim = cpMacCur;
+ }
+ CmdReplaceAll();
+ fSelSave = FALSE; /* reset */
+ break;
+ default:
+ Assert(FALSE);
+ break;
+ }
+ EnableExcept(vhDlgChange, TRUE);
+ SetChangeString(hDlg, vfDidSearch ? true : selCur.cpFirst == selCur.cpLim);
+ EndLongOp(vhcIBeam);
+ PostStatusInCaption(NULL);
+ break;
+
+ case idiWholeWord:
+ case idiMatchCase:
+ CheckDlgButton(hDlg, wParam, !IsDlgButtonChecked(hDlg, wParam));
+ break;
+
+ case idiCancel:
+LCancelChange:
+ DestroyModeless(&vhDlgChange);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ break;
+
+#if WINVER < 0x300
+ /* Don't really need to process this */
+ case WM_CLOSE:
+ goto LCancelChange;
+#endif
+
+#ifndef INEFFLOCKDOWN
+ case WM_NCDESTROY:
+ FreeProcInstance(lpDialogChange);
+ lpDialogChange = NULL;
+ /* fall through to return false */
+#endif
+ default:
+ return(FALSE);
+ }
+return(TRUE);
+} /* end of DialogChange */
+
+
+NEAR SetChangeString(hDlg, fAll)
+HANDLE hDlg;
+int fAll;
+{ /* set the last control button in CHANGE to "Change All" or "Change Selection" */
+CHAR sz[256];
+
+if (fAll == fChangeSel)
+ {
+ PchFillPchId(sz, (fAll ? IDSTRChangeAll : IDSTRChangeSel), sizeof(sz));
+ SetDlgItemText(hDlg, idiChangeAll, (LPSTR)sz);
+ fChangeSel = !fAll;
+ }
+}
+
+
+fnFindText()
+ {/* create dialog window only when it is not already created. */
+ if (!IsWindow(vhDlgFind))
+ {
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogFind)
+ if (!(lpDialogFind = MakeProcInstance(DialogFind, hMmwModInstance)))
+ {
+ WinFailure();
+ return;
+ }
+#endif
+ vhDlgFind = CreateDialog(hMmwModInstance, MAKEINTRESOURCE(dlgFind),
+ hParentWw, lpDialogFind);
+ if (!vhDlgFind)
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+ else
+ {
+ SendMessage(vhDlgFind, WM_ACTIVATE, true, (LONG)NULL);
+ }
+ }
+
+
+fnFindAgain()
+{
+register HWND hDlg = wwdCurrentDoc.wwptr;
+register HWND hWndFrom;
+
+ hWndFrom = GetActiveWindow();
+
+/* Find out where the F3 was executed from */
+/* assemble hszSearch if called from Find or Change dialog box */
+ if (vhDlgFind || vhDlgChange)
+ {
+ if (((hDlg = vhDlgFind) && (vhDlgFind == hWndFrom ||
+ vhDlgFind == (HANDLE)GetWindowWord(hWndFrom, GWW_HWNDPARENT)))
+ ||
+ ((hDlg = vhDlgChange) && (vhDlgChange == hWndFrom ||
+ vhDlgChange == (HANDLE)GetWindowWord(hWndFrom, GWW_HWNDPARENT))))
+ {
+ SendMessage(hDlg, WM_COMMAND, idiFindNext, (LONG)0);
+ goto Out;
+ }
+ }
+ PostStatusInCaption(IDSTRSearching);
+ StartLongOp();
+ DoSearch();
+ EndLongOp(vhcIBeam);
+ PostStatusInCaption(NULL);
+Out:
+ if (!IsWindowEnabled(wwdCurrentDoc.wwptr))
+ EnableWindow(wwdCurrentDoc.wwptr, true);
+ if (!IsWindowEnabled(hParentWw))
+ EnableWindow(hParentWw, true);
+ SendMessage(hParentWw, WM_ACTIVATE, true, (LONG)NULL);
+} /* end of fnFindAgain */
+
+
+fnReplaceText()
+{/* create dialog window only when it is not already created. */
+ if (!IsWindow(vhDlgChange))
+ {
+#ifndef INEFFLOCKDOWN
+ if (!lpDialogChange)
+ if (!(lpDialogChange = MakeProcInstance(DialogChange, hMmwModInstance)))
+ {
+ WinFailure();
+ return;
+ }
+#endif
+ vhDlgChange = CreateDialog(hMmwModInstance, MAKEINTRESOURCE(dlgChange),
+ hParentWw, lpDialogChange);
+ if (!vhDlgChange)
+#ifdef WIN30
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+ else
+ {
+ SendMessage(vhDlgChange, WM_ACTIVATE, true, (LONG)NULL);
+ }
+}
+
+
+/* P U T C P I N W W V E R T S R C H*/
+NEAR PutCpInWwVertSrch(cp)
+typeCP cp;
+
+ {
+/* vertical case */
+ typeCP cpMac;
+ int ypMac;
+ struct EDL *pedl;
+ int dl;
+ int dlMac;
+
+ UpdateWw(wwCur, false);
+ dlMac = pwwdCur->dlMac - (vfSelecting ? 0 : 1);
+ if (dlMac <= 0)
+ return;
+ pedl = &(**(pwwdCur->hdndl))[dlMac - 1];
+ if (cp < pwwdCur->cpFirst ||
+ cp > (cpMac = pedl->cpMin + pedl->dcpMac) ||
+ cp == cpMac && pedl->fIchCpIncr)
+ {
+ DirtyCache(pwwdCur->cpFirst = cp);
+ pwwdCur->ichCpFirst = 0;
+ /* This call places the search cp vertically on the screen
+ by scrolling. */
+ CtrBackDypCtr( (pwwdCur->ypMac - pwwdCur->ypMin) >> 1, 2 );
+
+#ifdef ENABLE /* no ActiveWindow concept yet */
+ if (pwwdCur->wwptr != ActiveWindow)
+#endif
+ TrashWw(wwCur);
+ }
+ else
+ {
+ ypMac = pwwdCur->ypMac / 2;
+
+/* Make sure that cp is still visible (scrolling if neccesary) */
+ pedl = &(**(pwwdCur->hdndl))[dl = DlFromYp(ypMac, pwwdCur)];
+ if (cp >= pedl->cpMin + pedl->dcpMac)
+ {
+ ScrollDownCtr( max( 1, dl ) );
+ TrashWw(wwCur);
+ UpdateWw(wwCur, false);
+ }
+ /* If cp is on bottom dl of the window and the dl is split by the
+ split bar, scroll down in doc by one line, to make insertion point
+ completely visible */
+ else if (cp >= pedl->cpMin & pedl->yp > ypMac)
+ {
+ ScrollDownCtr( 1 );
+ TrashWw(wwCur);
+ UpdateWw(wwCur,false);
+ }
+ }
+ }
+
+
+#ifndef NOLA /* no look ahead */
+BOOL (NEAR FAbort())
+{
+MSG msg;
+register WORD vk_key;
+register HANDLE hwndMsg;
+HANDLE hwndPeek = (vhWndMsgBoxParent) ? vhWndMsgBoxParent : hParentWw;
+
+if (PeekMessage((LPMSG)&msg, (HANDLE)NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE))
+ {
+ hwndMsg = msg.hwnd;
+ if ((hwndPeek == (HANDLE)GetWindowWord(hwndMsg, GWW_HWNDPARENT)) ||
+ (hwndMsg == hwndPeek))
+ {
+#ifdef DBCS
+// It can be true at DBCS that WM_CHAR is the last message.
+//
+ PeekMessage((LPMSG)&msg, hwndMsg, WM_KEYFIRST,WM_KEYLAST,PM_REMOVE);
+#else
+ GetMessage((LPMSG)&msg, hwndMsg, WM_KEYFIRST, WM_KEYLAST);
+#endif
+ if (msg.message == WM_KEYDOWN &&
+ (((vk_key = msg.wParam) == VK_ESCAPE) || (vk_key == VK_CANCEL)))
+ {
+ while (true)
+ {
+ GetMessage((LPMSG)&msg, hwndMsg, WM_KEYFIRST, WM_KEYLAST);
+ if (msg.message == WM_KEYUP && msg.wParam == vk_key)
+ return(TRUE);
+ }
+ }
+ else if (msg.message >= WM_SYSKEYDOWN && msg.message <= WM_SYSDEADCHAR)
+ DispatchMessage((LPMSG)&msg);
+ }
+ }
+return(FALSE);
+} /* end of FAbort */
+#endif /* NOLA */
+
+
+BOOL (NEAR FWordCp(cp, dcp))
+typeCP cp;
+typeCP dcp;
+ {
+ /* sees if the word starting at cp (with dcp chars) is a separate
+ word. */
+ int ich;
+
+
+ /* check the start of the word */
+ if(cp != cp0)
+ {
+ int wbPrev;
+ int wbStart;
+ FetchCp(docCur,cp-1,0,fcmChars + fcmNoExpand);
+ ich = 0;
+ wbPrev = WbFromCh(vpchFetch[ich]);
+ if(vcpFetch+vccpFetch <= cp)
+ {
+ FetchCp(docCur,cp,0,fcmChars + fcmNoExpand);
+ ich = 0;
+ }
+ else
+ ich++;
+#ifdef DBCS /* was in JAPAN; KenjiK '90-12-20 */
+ /* word break is meanless. */
+ if(!IsDBCSLeadByte(vpchFetch[ich]))
+#endif
+ if(wbPrev == (wbStart = WbFromCh(vpchFetch[ich])))
+ {
+ if (wbPrev != wbWhite && wbStart != wbWhite)
+ return(false);
+ }
+ }
+
+ /* check the end of the word */
+ if(cp+dcp-1 != cp0)
+ {
+ int wbEnd;
+ int wbLim;
+
+ if(vcpFetch+vccpFetch <= cp+dcp-1 || vcpFetch > cp+dcp-1)
+ {
+ FetchCp(docCur,cp+dcp-1,0,fcmChars + fcmNoExpand);
+ ich = 0;
+ }
+ else
+ ich = (dcp-1) - (vcpFetch-cp);
+ wbEnd = WbFromCh(vpchFetch[ich]);
+ if(vcpFetch+vccpFetch <= cp+dcp)
+ {
+ FetchCp(docCur,cp+dcp,0,fcmChars + fcmNoExpand);
+ ich = 0;
+ }
+ else
+ ich++;
+#ifdef DBCS /* was in JAPAN; KenjiK '90-12-20 */
+ /* word break is meanless. */
+ if(!IsDBCSLeadByte(vpchFetch[ich]))
+#endif
+ if(vccpFetch != 0 && (wbEnd == (wbLim = WbFromCh(vpchFetch[ich]))))
+ {
+ if (wbEnd != wbWhite && wbLim != wbWhite)
+ return(false);
+ }
+ }
+
+ return(true);
+ }
+
+
+BOOL (NEAR FChMatch(ch, pichPat, fFwd))
+int ch;
+int *pichPat;
+BOOL fFwd;
+ {
+ int ich = *pichPat;
+ int chSearch = szSearch[ich];
+ BOOL fPrefixed = false;
+ BOOL fMatched = false;
+
+#ifdef DEBUG
+ Assert(fSpecialMatch);
+#endif /*DEBUG*/
+#ifdef DBCS
+ Assert(fFwd);
+#ifndef KOREA
+ cbLastMatch = 1; /* Unless DBCS space. */
+#endif
+
+#endif
+
+ /* NOTE: this is just ChLower() brought in-line for speed */
+#ifdef DBCS
+// No need to make lower char for DBCS second byte
+ if(!fDBCS && !fSearchCase && ch >= 'A' && ch <= 'Z' )
+#else
+ if(!fSearchCase && ch >= 'A' && ch <= 'Z' )
+#endif
+ ch += 'a' - 'A';
+ if(!fFwd && ich > 0 && szSearch[ich-1] == chPrefixMatch)
+ /* see if the char is prefixed by a chPrefixMatch */
+ {
+ chSearch = chPrefixMatch;
+ --ich;
+ }
+
+ for(;;)
+ {
+ switch(chSearch)
+ {
+ default:
+
+#if defined(DBCS) && !defined(KOREA)
+ if(IsDBCSLeadByte(chSearch))
+ cbLastMatch = 2;
+#endif
+ if(ch == chSearch)
+ goto GoodMatch;
+ else if(ch == chReturn || ch == chNRHFile)
+ goto EasyMatch;
+ break;
+ case chSpace:
+ if(ch == chSpace || ch == chNBSFile)
+ goto GoodMatch;
+ break;
+ case chHyphen:
+ if(ch == chHyphen || ch == chNRHFile || ch == chNBH)
+ goto GoodMatch;
+ break;
+ case chMatchAny:
+ if(ch == chReturn || ch == chNRHFile)
+ goto EasyMatch;
+ if(!fPrefixed || ch == chMatchAny)
+ goto GoodMatch;
+ break;
+ case chPrefixMatch:
+ if(fPrefixed)
+ {
+ if(ch == chPrefixMatch)
+ goto GoodMatch;
+ else
+ break;
+ }
+ else
+ {
+ chSearch = szSearch[ich+1];
+ if(fFwd)
+ ++ich;
+ fPrefixed = true;
+ switch(chSearch)
+ {
+ default:
+ continue;
+ case chMatchEol:
+ chSearch = chEol;
+ continue;
+ case chMatchTab:
+ chSearch = chTab;
+ continue;
+ case chMatchWhite:
+ switch(ch)
+ {
+ default:
+#ifdef DBCS
+lblNonWhite:
+#endif
+ if(fMatchedWhite)
+ {
+ if(fFwd)
+ {
+ if(szSearch[++ich] =='\0')
+ {
+ *pichPat = ich;
+ goto EasyMatch;
+ }
+ }
+ else
+ {
+ ich -= 1;
+ if(ich < 0)
+ {
+ *pichPat = ich;
+ goto EasyMatch;
+ }
+ }
+ *pichPat = ich;
+ fMatchedWhite = false;
+ chSearch = szSearch[ich];
+ continue;
+ }
+ break;
+ case chSpace:
+ case chReturn:
+ case chEol:
+ case chTab:
+ case chNBSFile:
+ case chNewLine:
+ case chSect:
+ fMatchedWhite = true;
+ goto EasyMatch;
+ }
+ break;
+ case chMatchNBSFile:
+ chSearch = chNBSFile;
+ continue;
+ case chMatchNewLine:
+ chSearch = chNewLine;
+ continue;
+ case chMatchNRHFile:
+ chSearch = chNRHFile;
+ continue;
+ case chMatchSect:
+ chSearch = chSect;
+ continue;
+ }
+ }
+ break;
+ }
+ fMatchedWhite = false;
+ return false;
+ }
+GoodMatch:
+ *pichPat = ich + ((fFwd) ? 1 : (-1));
+EasyMatch:
+ return true;
+ }
+
+/* I N S E R T P A P S F O R R E P L A C E */
+/* do AddRunScratch for every distinct paragraph in hszCaseReplace */
+/* This is only needed when hszCaseReplace contains one or more chEols */
+NEAR InsertPapsForReplace(fc)
+typeFC fc;
+ {
+ int cchInsTotal = 0;
+ CHAR *pchTail;
+ CHAR *pchHead;
+
+ for(;;)
+ {
+ int cch;
+
+ pchHead = **hszCaseReplace + cchInsTotal;
+ pchTail = (CHAR *)index(pchHead, chEol);
+ if (pchTail == 0) return;
+ cch = pchTail - pchHead + 1; /* cch is count including chEol */
+
+ fc += cch;
+ cchInsTotal += cch;
+ AddRunScratch(&vfkpdParaIns, &vpapAbs, vppapNormal,
+ FParaEq(&vpapAbs, &vpapPrevIns) && vfkpdParaIns.brun != 0 ? -cchPAP : cchPAP,
+ fcMacPapIns = fc);
+ blt(&vpapAbs, &vpapPrevIns, cwPAP);
+ }
+ }
+
+
+NEAR FDlgSzTooLong(hDlg, idi, pch, cchMax)
+HWND hDlg;
+int idi;
+CHAR *pch;
+int cchMax;
+{
+int cchGet = GetDlgItemText(hDlg, idi, (LPSTR)pch, cchMax);
+
+*(pch+cchMax-2) = '\0'; /* just in case the string is too long */
+if (cchGet > (cchMax - 2))
+ return(TRUE);
+else
+ return(FALSE);
+}
+
+
+NEAR idiMsgResponse(hDlg, idi, idpmt)
+HWND hDlg;
+int idi;
+int idpmt;
+{
+CHAR szT[cchMaxSz];
+
+PchFillPchId(szT, idpmt, sizeof(szT));
+SetFocus(GetDlgItem(hDlg, idi));
+SendDlgItemMessage(hDlg, idi, EM_SETSEL, (WORD)NULL, MAKELONG(255, 32767));
+return(IdPromptBoxSz(hDlg, szT, MB_OKCANCEL | MB_ICONASTERISK));
+}
+
+
+PostStatusInCaption(idstr)
+int idstr;
+{
+
+extern HWND hParentWw;
+extern CHAR szCaptionSave[];
+
+CHAR *pchCaption = &szCaptionSave[0];
+CHAR *pchLast;
+int cch;
+CHAR szT[256];
+
+if (idstr == NULL)
+ {
+ /* restore the caption */
+ SetWindowText(hParentWw, (LPSTR)pchCaption);
+ }
+else
+ {
+ /* save caption */
+ GetWindowText(hParentWw, (LPSTR)pchCaption, cchMaxFile);
+
+ /* append status message after app name */
+#ifndef INTL
+ pchLast = pchCaption + CchSz(pchCaption) - 1;
+ while (pchLast-- > pchCaption)
+ {
+ if (*pchLast == ' ')
+ break;
+ }
+ PchFillPchId(bltbyte(pchCaption, szT, (cch = pchLast - pchCaption + 1)),
+ IDSTRSearching, 13);
+#else
+ pchLast = pchCaption + CchSz(szAppName) + CchSz(szSepName) - 2;
+ PchFillPchId(bltbyte(pchCaption, szT, (cch = pchLast - pchCaption)),
+ IDSTRSearching, 13);
+#endif
+ SetWindowText(hParentWw, (LPSTR)szT);
+ }
+}
+
diff --git a/private/mvdm/wow16/write/select.c b/private/mvdm/wow16/write/select.c
new file mode 100644
index 000000000..892d3f6c5
--- /dev/null
+++ b/private/mvdm/wow16/write/select.c
@@ -0,0 +1,800 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* select.c -- MW selection routines */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOWNDCLASS
+#define NOICON
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOBITMAP
+#define NOBRUSH
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOMB
+#define NOPOINT
+#define NOMSG
+#include <windows.h>
+#include "mw.h"
+#include "toolbox.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "ch.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+#ifdef DBCS
+#include "DBCS.h"
+#endif
+
+extern int vfSeeSel;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int docCur;
+extern struct FLI vfli;
+extern struct WWD rgwwd[];
+extern int vfSelHidden;
+extern int wwCur;
+extern struct CHP vchpFetch;
+extern struct PAP vpapAbs;
+extern struct WWD *pwwdCur;
+extern int vfInsEnd;
+extern typeCP CpBeginLine();
+extern int vfPictSel;
+extern int vfSizeMode;
+extern struct CHP vchpNormal;
+extern int vfInsertOn;
+extern struct CHP vchpSel; /* Holds the props when the selection
+ is an insert point */
+extern int vfMakeInsEnd;
+extern typeCP vcpSelect;
+extern int vfSelAtPara;
+/* true iff the last selection was made by an Up/Down cursor key */
+extern int vfLastCursor;
+extern int vfDidSearch;
+extern typeCP cpWall;
+
+
+/* C P L I M S T Y */
+typeCP CpLimSty(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp which is not part of the same sty unit */
+ typeCP CpLastStyChar(), CpLimStySpecial();
+ int wb, ch, ich;
+ struct EDL *pedl;
+
+ if (cp >= cpMacCur)
+ { /* Endmark is own unit */
+ return cpMacCur;
+ }
+
+ if (cp < cpMinCur)
+ cp = cpMinCur;
+
+ switch (sty)
+ {
+ int dl;
+ default:
+ Assert( FALSE );
+ case styNil:
+ return cp;
+
+ case styPara:
+ CachePara(docCur, cp);
+ if (vcpLimParaCache > cpMacCur)
+ { /* No EOL at end of doc */
+ return cpMacCur;
+ }
+ return vcpLimParaCache;
+ case styChar:
+ /* Because CpLastStyChar() could be returning cpMacCur already. */
+ cp = CpLastStyChar( cp ) + 1;
+ return ((cp <= cpMacCur) ? cp : cpMacCur);
+#ifdef BOGUS
+ /* This portion never gets executed... Why is it in here! */
+ CachePara(docCur, cp);
+ if (vpapAbs.fGraphics /* && cp > vcpFirstParaCache */)
+ return vcpLimParaCache;
+#ifdef CRLF
+ FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
+ return *vpchFetch == chReturn ? cp + 2 : cp + 1;
+#else /* not CRLF */
+ return cp + 1;
+#endif
+#endif
+
+ case styLine:
+ CpBeginLine(&dl, cp); /* Scrolls cp vertically into view */
+ pedl = &(**wwdCurrentDoc.hdndl) [dl];
+ return CpMin(pedl->cpMin + pedl->dcpMac, cpMacCur);
+ case styDoc:
+ return cpMacCur;
+ case styWord:
+ case stySent:
+#ifdef DBCS
+ return CpLimStySpecial( CpFirstSty(cp, styChar), sty );
+#else
+ return CpLimStySpecial( cp, sty );
+#endif /* DBCS */
+ }
+
+ Assert( FALSE );
+}
+
+
+
+
+typeCP CpLastStyChar( cp )
+typeCP cp;
+{ /* Return the last cp of the styChar containing cp */
+ /* This will be == cp except for pictures & CR-LF */
+ /* And the second byte of DBCS char's. */
+
+#ifdef DBCS
+ typeCP CpFirstSty();
+ CHAR chRetained;
+#endif
+
+ if (cp >= cpMacCur)
+ /* Endmark is own unit */
+ return cpMacCur;
+
+ if (cp < cpMinCur)
+ cp = cpMinCur;
+
+ /* Check for picture */
+ CachePara(docCur, cp);
+ if (vpapAbs.fGraphics)
+ return vcpLimParaCache-1;
+
+ /* Check for CR-LF */
+ /* This checking for CR-LF first based on the carriage return */
+ /* works only becasue the chReturn is outside of the DBCS */
+ /* range. */
+#ifdef CRLF
+ FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
+#ifdef DBCS
+ if ((chRetained = *vpchFetch) == chReturn) {
+ return cp + 1;
+ }
+ else {
+ if (CpFirstSty(cp, styChar) != cp) {
+ return cp; /* cp is pointing to the second byte of DBCS. */
+ }
+ else {
+ /* First byte of DBCS or a regular ASCII char. */
+ return (IsDBCSLeadByte(chRetained) ? cp + 1 : cp);
+ }
+ }
+#else
+ return *vpchFetch == chReturn ? cp + 1 : cp;
+#endif /* DBCS */
+#else
+ return cp;
+#endif
+
+}
+
+
+
+/* C P F I R S T S T Y */
+typeCP CpFirstSty(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp of this sty unit. */
+ typeCP CpFirstStySpecial();
+ typeCP cpBegin;
+ int wb, ch, dcpChunk;
+ typeCP cpSent;
+ CHAR rgch[dcpAvgSent];
+ int ich;
+ typeCP cpT;
+
+ if (cp <= cpMinCur)
+ return cpMinCur;
+ else if (cp >= cpMacCur)
+ switch(sty)
+ {
+ case styNil:
+ case styChar:
+ return cpMacCur; /* Endmark is own unit */
+ default:
+ break;
+ }
+
+ CachePara( docCur, cp );
+
+ switch (sty)
+ {
+ default:
+ Assert( FALSE );
+ case styNil:
+ return cp;
+ case styPara:
+ return vcpFirstParaCache;
+ case styChar:
+ if (vpapAbs.fGraphics)
+ return vcpFirstParaCache;
+#ifdef CRLF
+ {
+ typeCP cpCheckReturn;
+ typeCP cpMinScan;
+
+ cpCheckReturn = CpMax( cp, (typeCP) 1) - 1;
+#ifdef DBCS
+ /* Save vcpFirstParaCache, because it could be changed
+ by FetchCp() */
+ cpMinScan = vcpFirstParaCache;
+#endif /* DBCS */
+ FetchCp( docCur, cpCheckReturn, 0, fcmChars + fcmNoExpand );
+#ifdef DBCS
+ /* This works because chReturn is outside of DBCS range. */
+ if (*vpchFetch == chReturn) {
+ return cpCheckReturn;
+ }
+ else {
+ typeCP cpT;
+ typeCP cpRgMin;
+ int ichMacRgch;
+ BOOL fBreakFound;
+ int fkCur;
+
+ cpT = cp;
+ do {
+ cpRgMin = CpMax( cpT - dcpAvgSent, cpMinScan);
+ FetchRgch(&ichMacRgch, rgch, docCur, cpRgMin, cpT,
+ dcpAvgSent);
+ ich = ichMacRgch - 1;
+ fBreakFound = FALSE;
+ while (ich >= 0 && !fBreakFound) {
+ if (!IsDBCSLeadByte(rgch[ich])) {
+ fBreakFound = TRUE;
+ }
+ else {
+ ich--;
+ }
+ }
+ cpT = cpRgMin;
+ } while (!fBreakFound && cpRgMin > cpMinScan);
+ if (fBreakFound) {
+ ich++;
+ }
+ else {
+ ich = 0;
+ }
+ fkCur = fkNonDBCS;
+ cpT = cpRgMin + ichMacRgch;
+ do {
+ while (ich < ichMacRgch) {
+ if (fkCur == fkDBCS1) {
+ /* Last rgch[] ended with the first byte
+ of a DBCS character. */
+ fkCur = fkNonDBCS;
+ }
+ else if (IsDBCSLeadByte(rgch[ich])) {
+ if (ich + 1 < ichMacRgch) {
+ fkCur = fkNonDBCS;
+ ich++;
+ }
+ else {
+ fkCur = fkDBCS1;
+ }
+ }
+ else {
+ fkCur = fkNonDBCS;
+ }
+ ich++;
+ }
+ cpRgMin = cpT;
+ cpT += dcpAvgSent;
+ if (cpT <= cp) { /* Saves some time. */
+ FetchRgch(&ichMacRgch, rgch, docCur, cpRgMin, cpT,
+ dcpAvgSent);
+ ich = 0;
+ }
+ } while (cpT <= cp);
+
+ if (fkCur == fkDBCS1) {
+ Assert(cp - 1 <= cpMacCur);
+ return (cp - 1);
+ }
+ else {
+ Assert(cp <= cpMacCur);
+ return (cp);
+ }
+ }
+#else
+ return *vpchFetch == chReturn ? cpCheckReturn : cp;
+#endif /* DBCS */
+ }
+#else
+ return cp;
+#endif
+ case styDoc:
+ return cpMinCur;
+ case styLine:
+ {
+ int dlJunk;
+
+ return CpBeginLine( &dlJunk, cp );
+ }
+ case styWord:
+ case stySent:
+#ifdef DBCS
+ return CpFirstStySpecial( CpFirstSty(cp, styChar), sty );
+#else
+ return CpFirstStySpecial( cp, sty );
+#endif /* DBCS */
+ }
+ Assert( FALSE );
+}
+
+
+
+
+/* S E L E C T */
+/* used to make a selection from a cp-interval, for example after a find. */
+Select(cpFirst, cpLim)
+typeCP cpFirst, cpLim;
+{ /* Make a selection */
+ typeCP cpFirstOld = selCur.cpFirst;
+ typeCP cpLimOld = selCur.cpLim;
+ int fOldCursorLine;
+
+ if (cpFirst > cpLim)
+ /* The only time this condition should be true is when we have
+ run out of memory. The following is a senario where
+ such is the case (and actually, the reason for this code change).
+ Let us suppose that we have cut, pasted to the end of the
+ document, and are now executing a "command a" (repeat last
+ operation). The procedure CmdAgain is invoked. CmdAgain first
+ calls replace in order to add the text to the document. Now it
+ must position the cursor properly by calling select.
+ A SetUndo operation called by the prior paste gave us the
+ number of bytes that were added to the document. In its call
+ to Select, CmdAgain assumes that where it wants to position the
+ cursor is at the old last char position plus the SetUndo quantity
+ mentioned above. But, if the replace operation failed (due to
+ lack of memory), CmdAgain may be trying to place the cursor beyond
+ the physical end of the document.
+ Other fixes of this problem, at the caller level (CmdAgain)
+ instead of within Select, are probably "better" in the sense of
+ programming clarity. The chosen solution has the one advantage
+ of programming expediency. */
+ cpFirst = cpLim;
+ /* This statement replaces "Assert(cpFirst <= cpLim);" */
+
+ vfInsEnd = fFalse;
+/* notation: + add highlight
+ - remove highlight
+ .. leave alone
+ 00 common portion
+*/
+ if (!vfSelHidden)
+ {
+ if (cpFirst < cpFirstOld)
+ { /* +++... */
+ if (cpLim <= cpFirstOld)
+ { /* +++ --- */
+ goto SeparateSels;
+ }
+ else
+ { /* +++000... */
+ ToggleSel(cpFirst, cpFirstOld, true);
+ if (cpLim < cpLimOld)
+ { /* +++000--- */
+ ToggleSel(cpLim, cpLimOld, false);
+ }
+ else if (cpLim > cpLimOld)
+ { /* +++000+++ */
+ ToggleSel(cpLimOld, cpLim, true);
+ }
+/* Handle the case when old selection was an insert bar */
+ if (cpFirstOld == cpLimOld)
+ ToggleSel(cpFirstOld, cpLimOld, false);
+ }
+ }
+ else
+ { /* ---... */
+ if (cpLimOld <= cpFirst)
+ { /* --- +++ */
+SeparateSels:
+ fOldCursorLine = cpFirstOld == cpLimOld;
+/* prevent flashing if insert point which is ON is repeatedly selected */
+/* conditions are: not repeated, not insert point, not ON, not at desired end of line */
+ vfInsEnd = vfMakeInsEnd;
+ if ( cpFirst != cpFirstOld || cpLim != cpLimOld ||
+ !fOldCursorLine || !vfInsertOn ||
+ selCur.fEndOfLine != vfMakeInsEnd)
+ {
+ selCur.fEndOfLine = vfMakeInsEnd;
+ if (fOldCursorLine)
+ ClearInsertLine();
+/* old selection is off if it was a cursor line */
+ ToggleSel(cpFirst, cpLim, fTrue);
+/* otherwise the old selection is turned off AFTER the new one is made to
+make it look faster */
+ if (!fOldCursorLine)
+ ToggleSel(cpFirstOld, cpLimOld, fFalse);
+ }
+ }
+ else
+ { /* ---000... */
+ if (cpLimOld < cpLim)
+ { /* ---000+++ */
+ ToggleSel(cpLimOld, cpLim, true);
+ }
+ else if (cpLimOld > cpLim)
+ { /* ---000--- */
+ ToggleSel(cpLim, cpLimOld, false);
+ }
+ ToggleSel(cpFirstOld, cpFirst, false);
+ }
+ }
+ }
+
+ selCur.cpFirst = cpFirst;
+ selCur.cpLim = cpLim;
+ selCur.fForward = cpFirst != cpMacCur;
+ if (cpFirst == cpLim)
+ {
+ GetInsPtProps(cpFirst);
+ vfDidSearch = FALSE; /* reestablish for searching */
+ cpWall = cpLim;
+ }
+ vfLastCursor = vfSizeMode = vfPictSel = vfMakeInsEnd = false;
+
+ /* Set vfPictSel iff the selection is exactly one picture */
+
+ CachePara( docCur, selCur.cpFirst );
+ if (vpapAbs.fGraphics && selCur.cpLim == vcpLimParaCache)
+ vfPictSel = TRUE;
+
+}
+
+
+
+
+/* G E T I N S P T P R O P S */
+GetInsPtProps(cp)
+typeCP cp;
+{ /* determine properties of the insertion point */
+
+if (cpMacCur != cpMinCur)
+ {
+ CachePara(docCur, cp);
+ if (vcpFirstParaCache == cpMacCur)
+ {
+ /* cp is in the last para--use preceding para props */
+ CachePara(docCur, vcpFirstParaCache - 1);
+ if (vpapAbs.fGraphics)
+ { /* Yet another 10 point kludge -- get default props
+ when typing after a picture at doc end */
+
+ goto Default;
+ }
+ }
+ if (vpapAbs.fGraphics)
+ /* 10 point kludge: make typing before picture non-vchpNormal */
+ goto Default;
+
+ FetchCp(docCur, CpMax(vcpFirstParaCache, cp - 1), 0, fcmProps);
+ blt(&vchpFetch, &vchpSel, cwCHP);
+ if (vchpFetch.fSpecial && vchpFetch.hpsPos != 0)
+ { /* if this char is a footnote or page marker, then ignore */
+ vchpSel.hpsPos = 0; /* super/subscript stuff. */
+ vchpSel.hps = HpsAlter(vchpSel.hps, 1);
+ }
+ vchpSel.fSpecial = FALSE;
+ }
+else
+ {
+Default:
+ /* force default character properties, font size to be 10 point */
+ blt(&vchpNormal, &vchpSel, cwCHP);
+ vchpSel.hps = hpsDefault;
+ }
+}
+
+
+
+
+/* C H A N G E S E L */
+ChangeSel(cp, sty)
+typeCP cp;
+int sty;
+{ /* Make selCur move, expand or contract to cp */
+ /* sty is unit to keep in case of movement or flipped selection */
+ /* styChar is not supported; it is munged to styNil */
+ /* This is because the Write/Word user interface never asks us to */
+ /* pivot the selection around a single character, we pivot around */
+ /* an insertion point ("styNil") instead */
+ int fNullSelection = (selCur.cpFirst == selCur.cpLim);
+ typeCP cpFirst = selCur.cpFirst;
+ typeCP cpLim = selCur.cpLim;
+ int fForward = selCur.fForward;
+ typeCP cpOffFirst, cpOffLim, cpOnFirst, cpOnLim;
+
+ if (sty == styChar)
+ sty = styNil;
+
+ if (cp == cpMinCur - 1 || cp > cpMacCur)
+ { /* Trying to flip off the beginning or end */
+ _beep();
+ return;
+ }
+
+ cpOffFirst = cpOffLim = cpOnFirst = cpOnLim = cpNil;
+
+ if (cp <= cpFirst)
+ { /* Extend backwards */
+ if (cp == cpLim)
+ return;
+ if (fForward && !fNullSelection)
+ { /* Selection flipped */
+ if (vfPictSel)
+ /* stuck this in to 'correct' behaviour when select pict and
+ drag up. Don't want to unselect first pict (4.22.91) v-dougk */
+ {
+ cpOnFirst = CpFirstSty( cp, sty);
+ cpOffFirst = cpOffLim = cpLim;
+ }
+ else
+ {
+ cpOffFirst = selCur.cpLim = CpMin(cpLim, CpLimSty(cpFirst, sty));
+ cpOnFirst = CpFirstSty( cp, sty);
+ cpOffLim = cpLim;
+ }
+ }
+ else
+ {
+ if ( fNullSelection )
+ cpOffLim = cpOffFirst = selCur.cpFirst;
+ cpOnFirst = CpFirstSty( cp, styChar );
+ if (cpFirst == cpOnFirst)
+ return;
+ }
+ selCur.fForward = false;
+
+ cpOnLim = cpFirst;
+ selCur.cpFirst = cpOnFirst;
+ }
+ else if (cp >= cpLim)
+ { /* Extend forwards */
+ if (cp == cpFirst)
+ return;
+ if (!fForward && !fNullSelection)
+ { /* Selection flipped */
+ cpOffLim = selCur.cpFirst =
+ CpMax( cpFirst, CpFirstSty( (sty ==styNil) ? cpLim : cpLim-1,
+ sty ));
+ cpOnLim = CpLimSty(cp, sty);
+ cpOffFirst = cpFirst;
+ }
+ else
+ {
+ if ( fNullSelection )
+ cpOffLim = cpOffFirst = selCur.cpFirst;
+ cpOnLim = cp;
+ if (cpLim == cpOnLim)
+ return;
+ }
+ selCur.fForward = true;
+
+ cpOnFirst = cpLim;
+ selCur.cpLim = cpOnLim;
+ if (cpOnLim == cpLim && cpOffLim != cpLim)
+ cpOnLim = cpNil;
+ }
+ else if (fForward)
+ { /* Shrink a forward selection */
+ cpOffFirst = cp;
+ if (selCur.cpLim == cpOffFirst)
+ return;
+ selCur.cpLim = cpOffFirst;
+ cpOffLim = cpLim;
+ }
+ else
+ { /* Shrink a backward selection */
+ cpOffLim = cp;
+ if (selCur.cpFirst == cpOffLim)
+ return;
+ selCur.cpFirst = cpOffLim;
+ cpOffFirst = cpFirst;
+ }
+
+ ToggleSel(cpOnFirst, cpOnLim, true);
+ ToggleSel(cpOffFirst, cpOffLim, false);
+
+ /* Check for a stray insert point */
+
+ if (selCur.cpFirst != selCur.cpLim)
+ ClearInsertLine();
+
+ /* Set vfPictSel iff the selection is exactly one picture */
+
+ CachePara( docCur, selCur.cpFirst );
+ vfPictSel = vpapAbs.fGraphics && (selCur.cpLim == vcpLimParaCache);
+}
+
+
+
+
+/* S E L E C T D L X P */
+SelectDlXp(dl, xp, sty, fDrag)
+int dl, xp, sty;
+int fDrag;
+{ /* Move cursor to the nearest valid CP and select unit */
+ typeCP cp;
+ typeCP cpFirst;
+ typeCP cpLim;
+ register struct EDL *pedl;
+ int xpStart = xpSelBar - wwdCurrentDoc.xpMin;
+ int itcMin, itcLim;
+ int xpLeft;
+ int xpPos;
+ int fPictInsertPoint=FALSE; /* Setting an insert point before a pict */
+
+ UpdateWw(wwCur, false); /* Synchronize cursor & text */
+
+ xp = max(0, xp - xpStart);
+ dl = min( wwdCurrentDoc.dlMax - 1, dl );
+
+ pedl = &(**wwdCurrentDoc.hdndl) [dl];
+ cp = pedl->cpMin;
+
+ /* At or Below EMark */
+ if (cp >= cpMacCur)
+ {
+ cp = cpMacCur;
+ goto FoundCp;
+ }
+
+ if (pedl->fGraphics)
+ { /*
+ Special kludge for selecting a picture:
+ Select the whole picture (if the hit is inside or to the
+ right of the picture)
+ Select an insert point just before the picture if the hit
+ is to the left of the picture OR in the selection bar
+ when the picture is left-justified) */
+ if ( (xp < pedl->xpLeft) || (sty == styLine && xp == 0) )
+ fPictInsertPoint = TRUE;
+
+ goto FoundCp;
+ }
+
+ if (sty >= styPara)
+ { /* Selecting a paragraph, line, doc */
+ goto FoundCp;
+ }
+
+ /* Must Format to figure out the right cp */
+
+ FormatLine(docCur, cp, pedl->ichCpMin, cpMacCur, flmSandMode); /*HM*/
+
+ CachePara(docCur, cp);
+ pedl = &(**wwdCurrentDoc.hdndl) [dl];
+
+ if (vfli.fSplat) /* Selecting in division/page break */
+ {
+ cp = vfli.cpMin;
+ goto FoundCp;
+ }
+
+ xpLeft = pedl->xpLeft;
+
+ if (vfli.xpLeft != xpLeft)
+ /* This indicates that we are in lo memory conditions; in trouble */
+ return;
+ /* Assert (vfli.xpLeft == xpLeft); May not be true in lo memory */
+
+ if (xp <= xpLeft)
+ {
+ itcMin = 0;
+ goto FoundCp;
+ }
+
+ /* Out of bounds right */
+ if (xp >= pedl->xpMac)
+ {
+ itcMin = vfli.cpMac - cp - 1;
+ cp = vfli.cpMac - 1;
+ goto CheckPastPara;
+ }
+
+ /* Search through the line for the cp at position xp */
+ xpPos = xpLeft;
+ itcMin = 0;
+ itcLim = vfli.cpMac - cp;
+
+ while (itcMin < itcLim && xpPos < xp)
+ xpPos += vfli.rgdxp[itcMin++];
+
+ if (itcMin >= 1)
+ /* This may not be true if we are so low on memory that
+ FormatLine could not do its job */
+ itcMin--;
+
+ cp += itcMin;
+
+ CachePara(docCur, cp);
+ if ((xpPos < xp + vfli.rgdxp[itcMin] / 2) &&
+ (sty == styChar /* || !fDrag */) )
+ { /* Actually selecting next character */
+ CheckPastPara:
+ if (cp + 1 == vcpLimParaCache && !vpapAbs.fGraphics &&
+ (vfSelAtPara || vcpSelect == cpNil))
+ /* Return insert point before paragraph mark */
+ {
+ if (vcpSelect == cpNil)
+ vfSelAtPara = true;
+ goto FoundCp;
+ }
+ itcMin++;
+ cp++;
+ }
+
+FoundCp:
+ /* Set up selection limits */
+ cpFirst = CpFirstSty( cp, sty );
+ cpLim = CpLimSty( cp, sty );
+
+ if (sty == styChar)
+ {
+ if ( !pedl->fGraphics || fPictInsertPoint )
+ /* In text or before a pic: don't extend to end of styChar */
+ cpLim = cpFirst;
+
+ if ( vcpSelect == cpNil )
+ { /* First time through, remember where we started */
+
+ /* Set if we want to kludge the insert point at the end of *pedl */
+
+ vfMakeInsEnd = (cp == pedl->cpMin + pedl->dcpMac &&
+ cp <= cpMacCur &&
+ !pedl->fGraphics &&
+ !pedl->fSplat);
+ vcpSelect = cpFirst;
+ }
+ }
+
+ if (fDrag)
+ ChangeSel( selCur.fForward ? cpLim : cpFirst, sty );
+ else
+ Select( cpFirst, cpLim );
+}
+
+
+
+
+typeCP CpEdge()
+{ /* Return edge of selection */
+ return selCur.fForward ?
+ CpMax( CpFirstSty( selCur.cpLim - 1, styChar ), selCur.cpFirst ) :
+ selCur.cpFirst;
+}
diff --git a/private/mvdm/wow16/write/select2.c b/private/mvdm/wow16/write/select2.c
new file mode 100644
index 000000000..04c8f4648
--- /dev/null
+++ b/private/mvdm/wow16/write/select2.c
@@ -0,0 +1,295 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* Select2.c -- Less-frequently-used selection routines */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOSOUND
+#define NOCOMM
+#define NOPEN
+#define NOWNDCLASS
+#define NOICON
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOBITMAP
+#define NOBRUSH
+#define NOCOLOR
+#define NODRAWTEXT
+#define NOMB
+#define NOPOINT
+#define NOMSG
+#include <windows.h>
+#include "mw.h"
+#include "toolbox.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "dispdefs.h"
+#include "cmddefs.h"
+#include "wwdefs.h"
+#include "ch.h"
+#include "fmtdefs.h"
+#include "propdefs.h"
+
+extern int vfSeeSel;
+extern typeCP vcpFirstParaCache;
+extern typeCP vcpLimParaCache;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern struct SEL selCur;
+extern int docCur;
+extern struct FLI vfli;
+extern struct WWD rgwwd[];
+extern int vfSelHidden;
+extern int wwCur;
+extern struct CHP vchpFetch;
+extern struct PAP vpapAbs;
+extern struct WWD *pwwdCur;
+extern int vfInsEnd;
+extern typeCP CpBeginLine();
+extern int vfPictSel;
+extern int vfSizeMode;
+extern struct CHP vchpNormal;
+extern int vfInsertOn;
+extern struct CHP vchpSel; /* Holds the props when the selection
+ is an insert point */
+extern int vfMakeInsEnd;
+extern typeCP vcpSelect;
+extern int vfSelAtPara;
+/* true iff the last selection was made by an Up/Down cursor key */
+extern int vfLastCursor;
+
+
+
+/* C P L I M S T Y S P E C I A L */
+typeCP CpLimStySpecial(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp which is not part of the same sty unit */
+ int wb, ch, ich;
+ struct EDL *pedl;
+
+ /* Other cases covered in CpLimSty, our only caller */
+
+ Assert( cp < cpMacCur );
+ Assert( cp >= cpMinCur );
+ Assert( sty == styWord || sty == stySent );
+
+/* Special kludge for picture paragraphs */
+ CachePara(docCur, cp);
+ if (vpapAbs.fGraphics)
+ return vcpLimParaCache;
+
+ FetchCp(docCur, cp, 0, fcmChars + fcmNoExpand);
+
+ Assert(vccpFetch != 0);
+
+ /* Must be word or sentence */
+ wb = WbFromCh(ch = vpchFetch[ich = 0]);
+#ifdef CRLF
+ if (ch == chReturn)
+ return vcpFetch + 2;
+#endif
+ if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab)
+ /* EOL is its own unit */
+ return vcpFetch + 1;
+
+ if (wb == wbWhite && sty == stySent)
+ { /* Might be between sentences; go back to text */
+ FetchCp(docCur, CpFirstSty(cp, styWord), 0, fcmChars + fcmNoExpand);
+ wb = WbFromCh(ch = vpchFetch[ich = 0]);
+ }
+
+ for (;;)
+ {
+ if (++ich >= vccpFetch)
+ { /* Get next line and set up */
+ FetchCp(docNil, cpNil, 0, fcmChars);
+ if (vcpFetch == cpMacCur)
+ return cpMacCur; /* End of doc */
+ ich = 0;
+ }
+ if (sty == stySent)
+ switch (ch)
+ {
+ case chDot:
+ case chBang:
+ case chQMark:
+ sty = styWord;
+ wb = wbPunct;
+ }
+ switch (ch = vpchFetch[ich])
+ {
+ case chTab:
+ case chEol:
+ case chSect:
+ case chNewLine:
+#ifdef CRLF
+ case chReturn:
+#endif
+ goto BreakFor;
+ }
+ if (sty == styWord)
+ { /* Word ends after white space or on text/punct break */
+ int wbT = WbFromCh(ch);
+ if (wb != wbT && (wb = wbT) != wbWhite)
+ break;
+ }
+ }
+ BreakFor:
+ return vcpFetch + ich;
+}
+
+
+
+/* C P F I R S T S T Y S P E C I A L */
+typeCP CpFirstStySpecial(cp, sty)
+typeCP cp;
+int sty;
+{ /* Return the first cp of this sty unit. */
+ typeCP cpBegin;
+ int wb, ch, dcpChunk;
+ typeCP cpSent;
+ CHAR rgch[dcpAvgSent];
+ int ich;
+ typeCP cpT;
+
+ /* Other cases were covered by CpFirstSty, our only caller */
+
+ Assert( cp > cpMinCur );
+ Assert( sty == stySent || sty == styWord );
+
+ if (cp >= cpMacCur)
+ cpT = cp = cpMacCur;
+ else
+ cpT = cp++;
+
+ CachePara(docCur, cpT );
+ if ((vcpFirstParaCache == cpT) || vpapAbs.fGraphics)
+ return vcpFirstParaCache;
+
+ dcpChunk = (sty == styWord) ? dcpAvgWord : dcpAvgSent;
+ cpBegin = (cp > dcpChunk) ? cp - dcpChunk : cp0;
+
+ FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
+ wb = WbFromCh(ch = rgch[--ich]);
+
+#ifdef CRLF
+ if(cpBegin + ich == 0)
+ return cp0;
+
+ if (ch == chEol && rgch[ich-1] == chReturn) /* EOL is its own unit */
+ return cpBegin + ich - 1;
+ if (ch == chEol || ch == chReturn || ch == chSect || ch == chNewLine || ch == chTab)
+ return cpBegin + ich;
+#else /* not CRLF */
+ if (ch == chEol || ch == chSect || ch == chNewLine || ch == chTab) /* EOL is its own unit */
+ return cpBegin + ich;
+#endif /* CRLF */
+
+ if (wb == wbText)
+ cpSent = cpBegin + ich;
+ else
+ cpSent = cpNil;
+
+ for (;;)
+ {
+ if (ich == 0)
+ {
+ if (cpBegin == cpMinCur)
+ return cpMinCur; /* beginning of doc */
+ cpBegin = (cpBegin > dcpChunk) ? cpBegin - dcpChunk : cp0;
+ FetchRgch(&ich, rgch, docCur, cpBegin, cp, dcpChunk);
+ }
+ ch = rgch[--ich];
+ CachePara( docCur, cpBegin + ich ); /* Needed for pictures */
+ if (ch == chEol || ch == chSect || ch == chNewLine ||
+ ch == chTab || vpapAbs.fGraphics )
+ break; /* EOL Always ends a unit */
+ if (sty == styWord)
+ {
+ if (wb != wbWhite)
+ {
+ if (WbFromCh(ch) != wb)
+ break;
+ }
+ else
+ wb = WbFromCh(ch);
+ }
+ else
+ { /* Test for sentence. */
+ switch (ch)
+ {
+ case chDot:
+ case chBang:
+ case chQMark:
+ if (cpSent != cpNil)
+ return cpSent;
+ }
+ switch (WbFromCh(ch))
+ {
+ case wbText:
+ cpSent = cpBegin + ich;
+ wb = wbText;
+ break;
+ case wbPunct:
+ switch (wb)
+ {
+ case wbWhite:
+ wb = wbPunct;
+ break;
+ case wbText:
+ cpSent = cpBegin + ich;
+ }
+ break;
+ case wbWhite:
+ if (wb == wbPunct)
+ cpSent = cpBegin + ich + 1;
+ wb = wbWhite;
+ break;
+ }
+ }
+ }
+ return cpBegin + ich + 1;
+}
+
+
+
+/* W B F R O M C H */
+int WbFromCh(ch)
+int ch;
+{ /* Return word-breakness of ch */
+
+ switch (ch)
+ {
+ case chSpace:
+ case chEol:
+#ifdef CRLF
+ case chReturn:
+#endif
+ case chSect:
+ case chTab:
+ case chNewLine:
+ case chNBSFile:
+ return wbWhite;
+ case chNRHFile:
+ return wbText;
+ default: /* we are using the ANSI char set that windows used */
+ return ((isalpha(ch) || isdigit(ch))? wbText : wbPunct);
+ }
+}
+
+
diff --git a/private/mvdm/wow16/write/selectsp.c b/private/mvdm/wow16/write/selectsp.c
new file mode 100644
index 000000000..ca539c4a7
--- /dev/null
+++ b/private/mvdm/wow16/write/selectsp.c
@@ -0,0 +1,278 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCTLMGR
+#define NOWINMESSAGES
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#include "windows.h"
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "fmtdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "prmdefs.h"
+#include "editdefs.h"
+#include "macro.h"
+#include "str.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+/* E X T E R N A L S */
+
+extern int vstyCur;
+extern int docCur;
+extern typeCP vcpLimParaCache;
+extern struct SEL selCur;
+extern struct PAP vpapAbs;
+extern struct SEL selPend;
+extern struct UAB vuab;
+extern struct CHP vchpFetch;
+extern struct CHP vchpSel;
+extern int docUndo;
+extern int ferror;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern int vfObjSel;
+
+
+
+
+/* L O O K S M O U S E */
+LooksMouse()
+{
+ int cch;
+ char rgb[cchPAP + 2];
+
+ if (vstyCur == styPara || vstyCur == styLine)
+ { /* Copy paragraph looks */
+ /* MEMO Version: no effect on tab table */
+ int itbd;
+ CachePara(docCur, selCur.cpFirst);
+
+#ifdef CASHMERE
+ for (itbd = 0; vpapAbs.rgtbd[itbd].dxa != 0; itbd++);
+ rgb[1] = (cwPAPBase + (itbd + 1) * cwTBD) * cchINT;
+ bltbyte(&vpapAbs, &rgb[2], rgb[1]);
+#else
+ blt( &vpapAbs, &rgb[2], rgb[1] = cwPAPBase );
+#endif
+ rgb[0] = sprmPSame;
+ Select(selPend.cpFirst, selPend.cpLim);
+ AddOneSprm(rgb, fTrue);
+ vuab.uac = uacLookParaMouse;
+ }
+ else
+ { /* Copy character looks */
+ struct CHP chpT;
+ FetchCp(docCur, CpMax(cp0, selCur.cpFirst - 1), 0, fcmProps);
+ chpT = vchpFetch;
+ Select(selPend.cpFirst, selPend.cpLim);
+ vchpSel = chpT;
+ if (selPend.cpFirst == selPend.cpLim)
+ return;
+ bltbyte(&vchpSel, &rgb[1], cwCHP * cchINT);
+ rgb[0] = sprmCSame;
+ AddOneSprm(rgb, fTrue);
+ vuab.uac = uacLookCharMouse;
+ }
+
+ SetUndoMenuStr(IDSTRUndoLook);
+}
+
+
+
+
+/* C O P Y M O U S E */
+CopyMouse()
+{
+ typeCP cpDest, cpSrc, dcp;
+ int fKludge = false;
+
+ if (selPend.cpFirst == selPend.cpLim)
+ return;
+
+ if (FWriteOk(fwcInsert))
+ {
+ cpDest = selCur.cpFirst;
+ dcp = selPend.cpLim - (cpSrc = selPend.cpFirst);
+
+/*----- SetUndo(uacInsert, docCur, cpDest, dcp, docNil, cpNil, cp0, 0);--*/
+ /* ReplaceCps can't deal with copies from/to the same doc, so use undo
+ buffer as intermediate storage */
+ NoUndo();
+
+ ClobberDoc(docUndo, docCur, cpSrc, dcp);
+ if (ferror)
+ return;
+ else if (!FCheckPicture(&cpDest, dcp, true, docCur))
+ SetUndo(uacInsert, docCur, cpDest, dcp, docNil, cpNil, cp0, 0);
+
+ ReplaceCps(docCur, cpDest, cp0, docUndo, cp0, dcp);
+ if (ferror)
+ {
+ NoUndo();
+ return;
+ }
+ else
+ {
+#if defined(OLE)
+ ObjEnumInRange(docCur,cpDest,cpDest+dcp,ObjCloneObjectInDoc);
+#endif
+ if (cpDest >= cpMinCur && cpDest + dcp <= cpMacCur)
+ Select(cpDest, cpDest + dcp);
+ }
+ }
+
+
+ SetUndoMenuStr(IDSTRUndoEdit);
+}
+
+
+
+
+/* M O V E M O U S E */
+MoveMouse()
+{
+ typeCP cpSrc, dcp, cpDest;
+
+ if (selPend.cpFirst == selPend.cpLim)
+ return;
+
+ if (FWriteOk(fwcInsert))
+ {
+ cpDest = selCur.cpFirst;
+ dcp = selPend.cpLim - (cpSrc = selPend.cpFirst);
+ if (FMoveText(docCur, cpSrc, dcp, docCur, &cpDest, fTrue))
+ SetUndoMenuStr(IDSTRUndoEdit);
+ }
+}
+
+
+
+
+
+/* F M O V E T E X T */
+int FMoveText(docSrc, cpSrc, dcp, docDest, pcpDest, fSetUndo)
+int docSrc, docDest, fSetUndo;
+typeCP cpSrc, dcp, *pcpDest;
+{ /* returns true unless moving into yourself */
+ int fT;
+ typeCP cpT, cpMacT;
+
+ Assert(docSrc == docDest);
+
+ /* Same document; use undo buffer as intermediary */
+ if (*pcpDest >= cpSrc && *pcpDest < cpSrc + dcp
+#ifdef FOOTNOTES
+ || *pcpDest >= CpFirstFtn(docSrc, cpSrc, &fT) &&
+ *pcpDest < CpFirstFtn(docSrc, cpSrc + dcp, &fT)
+#endif
+ )
+ {
+ Error(IDPMTBadMove);
+ return false;
+ }
+ ClobberDoc(docUndo, docSrc, cpSrc, dcp);
+ if (ferror)
+ return false;
+
+ if (FCheckPicture(pcpDest, dcp, false, docDest))
+ if (cpSrc >= *pcpDest)
+ cpSrc += (typeCP)ccpEol;
+
+/* cpMacT will measure the total adjustment incurred by the following replace
+as it may be different from dcp-cp0 (e.g. due to Eol inserted in front of
+a picture
+*/
+ cpMacT = cpMacCur;
+ ReplaceCps(docDest, *pcpDest, cp0, docUndo, cp0, dcp);
+ cpT = *pcpDest;
+ if (docDest == docSrc)
+ {
+ if (cpT < cpSrc)
+ cpSrc += cpMacCur - cpMacT;
+ else /* cpT >= cpSrc */
+ cpT -= cpMacCur - cpMacT;
+ }
+ /* Now delete old text */
+ Replace(docSrc, cpSrc, dcp, fnNil, fc0, fc0);
+
+ if (ferror)
+ {
+ NoUndo();
+ return FALSE;
+ }
+ else
+ {
+ if (docDest == docCur && cpT >= cpMinCur && cpT + dcp <= cpMacCur)
+ Select(cpT, cpT + dcp);
+ if (fSetUndo)
+ SetUndo(uacMove, docCur, cpSrc, dcp, docCur, cpT, cp0, 0);
+ }
+ return true;
+}
+
+
+
+
+/* F C H E C K P I C T U R E */
+
+int FCheckPicture(pcpDest, dcp, fSetUndo, doc)
+typeCP *pcpDest, dcp;
+int fSetUndo;
+int doc;
+{
+ typeCP cpDest = *pcpDest;
+ CachePara(docUndo, cp0);
+ if (vpapAbs.fGraphics && cpDest > cp0)
+ { /* Special case for inserting a picture paragraph */
+ CachePara(doc, cpDest - 1);
+ if (vcpLimParaCache == cpDest + 1 && vcpLimParaCache < cpMacCur)
+/* this special case is here to move the insertion point from 1 char away
+from a para boundary (a common point to select) to the boundary so that
+we do not have to insert an ugly extra cr. This does not apply at the
+end of the document */
+ {
+ *pcpDest += 1;
+ return fFalse;
+ }
+ if (vcpLimParaCache != cpDest)
+ {
+ if (fSetUndo)
+ SetUndo(uacInsert, doc, cpDest, dcp + (typeCP)ccpEol,
+ docNil, cpNil, cp0, 0);
+ InsertEolPap(doc, cpDest, &vpapAbs);
+ *pcpDest += (typeCP)ccpEol;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+/* C H E C K M O V E */
+CheckMove()
+{
+if(vuab.doc == vuab.doc2)
+ {
+ /* same doc means we might have to worry about shifting cp's */
+ if (vuab.cp < vuab.cp2)
+ vuab.cp2 -= vuab.dcp;
+ else if (vuab.cp > vuab.cp2)
+ vuab.cp += vuab.dcp;
+#ifdef DEBUG
+ else
+ Assert(false);
+#endif
+ }
+}
diff --git a/private/mvdm/wow16/write/single.bms b/private/mvdm/wow16/write/single.bms
new file mode 100644
index 000000000..0368cac7e
--- /dev/null
+++ b/private/mvdm/wow16/write/single.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/sp15.bms b/private/mvdm/wow16/write/sp15.bms
new file mode 100644
index 000000000..ce1a008ad
--- /dev/null
+++ b/private/mvdm/wow16/write/sp15.bms
Binary files differ
diff --git a/private/mvdm/wow16/write/state.rst b/private/mvdm/wow16/write/state.rst
new file mode 100644
index 000000000..efe754208
--- /dev/null
+++ b/private/mvdm/wow16/write/state.rst
@@ -0,0 +1,12 @@
+[edit-]
+screen=80 25
+toggles=1 1 0 1 0 0
+srch=QueryRelease
+src=
+rpl=
+file=p:\src\apps\write\obj.c 1 244 24 244
+[brief]
+file=p:\src\apps\write\obj.c 1 244 24 244 1 22 78 1 c=0
+file=p:\src\apps\write\obj2.c 1 1 1 1
+[shared-]
+pmark=p:\src\apps\write\obj.c 24 244
diff --git a/private/mvdm/wow16/write/stcdefs.h b/private/mvdm/wow16/write/stcdefs.h
new file mode 100644
index 000000000..7b91eaf03
--- /dev/null
+++ b/private/mvdm/wow16/write/stcdefs.h
@@ -0,0 +1,59 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* stcdefs.h -- definitions of styles */
+
+#define usgCharMin 0
+#define usgParaMin 11
+#define usgSectMin 26
+#define usgMax 33
+#define usgCharNormal 0
+
+#define stcNormal 0
+#define stcParaMin 30
+#define stcSectMin 105
+#define stcMax 128
+
+#define stcFtnRef 13
+#define stcFolio 19
+#define stcFtnText 39
+#define stcRunningHead 93
+
+#define cchMaxRemark 28
+#define ccpSshtEntry (1 + 2 + cchMaxRemark + 1)
+#define cchMaxStc 40 /* Length of longest usage-variant pair */
+
+/* Fetch Style Modes */
+#define fsmDiffer 0
+#define fsmSame 1
+#define fsmAny 2
+
+struct CHP *PchpFromStc();
+struct PAP *PpapFromStc();
+struct SEP *PsepFromStc();
+
+
+struct SYTB
+ { /* Style table */
+ int mpstcbchFprop[stcMax];
+ CHAR grpchFprop[2]; /* Variable size */
+ };
+
+#define cwSYTBBase stcMax
+
+struct SYTB **HsytbCreate();
+
+
+struct AKD
+ { /* ALT-Key Descriptor */
+ CHAR ch;
+ unsigned fMore : 1;
+ unsigned ustciakd : 7;
+ };
+
+#define cchAKD (sizeof (struct AKD))
+#define cwAKD (cchAKD / sizeof (int))
+
+/* max length of strings used in usages and font names */
+#define cchIdstrMax 32
diff --git a/private/mvdm/wow16/write/str.h b/private/mvdm/wow16/write/str.h
new file mode 100644
index 000000000..f9b81fc22
--- /dev/null
+++ b/private/mvdm/wow16/write/str.h
@@ -0,0 +1,232 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* IDSTRs and IDPMTs are in 5 different groups,
+ the high byte is for masking, see MB_ERRxxxx definitions */
+
+#define MB_ERRMASK 0xf000
+#define MB_ERRASTR 0x1000
+#define MB_ERREXCL 0x2000
+#define MB_ERRQUES 0x3000
+#define MB_ERRHAND 0x4000
+
+#ifndef NOSTRUNDO
+/* NONERROR group, from 0x0001 -- 0x0fff */
+/* Menu and Undo strings */
+#define IDSTRUndoBase 0x0001
+#define IDSTRUndoEdit 0x0002
+#define IDSTRUndoLook 0x0003
+#define IDSTRUndoTyping 0x0004
+#define IDSTRShowRuler 0x0005
+#define IDSTRHideRuler 0x0006
+#define IDSTRAbout 0x0007
+#define IDSTREdit 0x0008
+#define IDSTRCancel 0x0009
+#define IDSTRPopupVerbs 0x000A
+#define IDSTRSingleVerb 0x0010
+
+ /* UNDO menu string lengths, including terminator */
+#define cchSzUndo (25)
+
+#endif /* NOSTRUNDO */
+
+
+
+#define IDSTRHELPF 0x000b
+#define IDSTRChangeSel 0x000c
+#define IDSTRChangeAll 0x000d
+
+#define IDSTRChPage 0x000e
+#define IDSTRLoading 0x000f
+
+#define IDSTROn 0x0013
+#define IDSTRReplaceFile 0x0016
+#define IDSTRChars 0x0017
+#define IDSTRSearching 0x0018
+
+#define IDS_MERGE1 0x0019
+
+#define IDSTRConvertText 0x001a
+#define IDSTRConvertWord 0x001b
+
+/* OLE strings */
+#if defined(OLE)
+#define IDSTRMenuVerb 0x0020
+#define IDSTRLinkProperties 0x0021
+#define IDSTRAuto 0x0022
+#define IDSTRManual 0x0023
+#define IDSTRFrozen 0x0024
+#define IDSTREmbedded 0x0025
+#define IDSTRFilter 0x0026
+#define IDSTRExtension 0x0027
+#define IDSTRAllFilter 0x0028
+#define IDSTRRename 0x0029
+#define IDSTRServer 0x002A
+#define IDSTRInsertfile 0x0032
+#define IDSTRChangelink 0x0033
+#define IDSTRUpdate 0x0034
+#define IDSTRMenuVerbP 0x0035
+#endif
+
+/* commdlg strings */
+#define IDSTROpenfile 0x0060
+#define IDSTRSavefile 0x0061
+#define IDSTRDefWriExtension 0x0062
+#define IDSTRDefDocExtension 0x0063
+#define IDSTRDefTxtExtension 0x0064
+#define IDSTRTxtDescr 0x0065
+#define IDSTRWriDescr 0x0066
+#define IDSTRDocDescr 0x0067
+#define IDSTRDocTextDescr 0x0068
+#define IDSTROldWriteDescr 0x0069
+#define IDSTRAllFilesDescr 0x006a
+
+
+#define IDSTRBitmap 0x006b
+#define IDSTRPicture 0x006c
+#define IDSTRDIB 0x006d
+#define IDSTRText 0x006e
+#define IDSTRBackup 0x006f
+#define IDSTRObject 0x0070
+
+/* See ErrorLevel() -- error messages are grouped as follows and then
+ we can quickly determine the severity of an error */
+
+/***** FOLLOWING MESSAGES ARE "*" LEVEL MESSAGES */
+/* MB_ERRASTR group, from 0x1000 -- 0x1fff */
+
+#define IDPMTSearchDone 0x1000
+#define IDPMTNotFound 0x1001
+#define IDPMTNoReplace 0x1002
+#define IDPMTCancelSearch 0x1003
+
+
+/***** FOLLOWING MESSAGES ARE "?" LEVEL MESSAGES */
+/* MB_ERRQUES group, from 0x3000 -- 0x3fff */
+
+#define IDPMTAddFont 0x3000
+#define IDPMTTruncateSz 0x3001
+#define IDPMTConvert 0x3002
+
+/***** FOLLOWING MESSAGES ARE "!" LEVEL MESSAGES */
+/* MB_ERREXCL group, from 0x2000 -- 0x2fff */
+
+#ifndef NOSTRERRORS
+#define IDPMTBadFileName 0x202c
+#define IDPMTRottenFile 0x202b
+#define IDPMTBadFile 0x2006
+#define IDPMTCantOpen 0x2019
+#define IDPMTDirtyDoc 0x201a
+#define IDPMTCantRunM 0x201b
+#define IDPMTCantRunF 0x2021
+#define IDPMTNoPath 0x201c
+#define IDPMTFileNotFound 0x201f
+#define IDPMTReadOnly 0x2020
+#define IDPMTCantRead 0x202d
+#define IDPMTDelObjects 0x2029
+#define IDPMTDelPicture 0x202a
+#define IDPMTRenameFail 0x2023
+#define IDPMTOverwrite 0x2026
+#define IDPMTCantShare 0x2027
+#if defined(OLE)
+#define IDPMTGetFromClipboardFailed 0x2102
+#define IDPMTFailedToFreeze 0x2103
+#define IDPMTFailedToLaunchServer 0x2104
+#define IDPMTFailedToActivate 0x2105
+#define IDPMTFailedToUpdate 0x2106
+#define IDPMTFailedToDeleteObject 0x2108
+#define IDPMTServerBusy 0x2109
+#define IDPMTFailedToUpdateLink 0x210b
+#define IDPMTImproperLinkOptionsError 0x210c
+#define IDPMTFailedToCommWithServer 0x210d
+#define IDPMTFailedToReadObject 0x210e
+#define IDPMTFailedToCreateObject 0x210f
+#define IDPMTFailedToDraw 0x2110
+#define IDPMTInsufficientResources 0x2111
+#define IDPMTOLEError 0x2112
+#define IDPMTFileContainsObjects 0x2113
+#define IDPMTFailedToLoadObject 0x2114
+#define IDSTRFinishObject 0x2115
+#define IDPMTLinkUnavailable 0x2116
+#define IDPMTFormat 0x2117
+#define IDPMTStatic 0x2118
+#define IDSTRUpdateObject 0x2119
+#define IDPMTLinksUnavailable 0x211b
+#define IDPMTCutOpenEmb 0x211c
+#define IDPMTExitOpenEmb 0x211d
+#define IDPMTSaveOpenEmb 0x211e
+#define IDPMTDeleteOpenEmb 0x211f
+#define IDPMTInsertOpenEmb 0x2120
+#endif
+
+/* Dialog field errors */
+
+#define IDPMTNoPage 0x2007
+#define IDPMTNOTNUM 0x2008
+#define IDPMTBFS 0x2009
+#define IDPMTNPI 0x200a
+#define IDPMTNOTDXA 0x200b
+#define IDPMTNPDXA 0x200c
+#define IDPMTMTL 0x200d
+#define IDPMTBadFilename 0x200e
+
+#define IDPMT2Complex 0x200f
+#define IDPMTBadMove 0x2010
+#define IDPMTDFULL 0x2012
+#define IDPMTPRFAIL 0x2013
+#define IDPMTClipLarge 0x2017
+#define IDPMTClipQuest 0x201e
+#define IDPMTBadPrinter 0x2018
+#define IDPMTCantPrint 0x2022
+#define IDPMTPrPictErr 0x2024
+#define IDPMTPrDiskErr 0x2025
+#define IDPMTDFULLScratch 0x2028
+
+/***** FOLLOWING MESSAGES ARE "<hand>" LEVEL MESSAGES */
+/* MB_ERRHAND group, from 0x4000 -- 0x4fff */
+
+#define IDPMTSDE 0x4000
+#define IDPMTSDN 0x4001
+#define IDPMTNoMemory 0x4002
+#define IDPMTSFER 0x4003
+#define IDPMTMEM 0x4004
+#define IDPMTWinFailure 0x4005
+#define IDPMTSDE2 0x4006
+#define IDPMTFloppyback 0x4007
+#define IDPMTFileback 0x4008
+#endif /* NOSTRERRORS */
+
+
+/***** FOLLOWING MESSAGES ARE EX-GLOBDEFS.H MESSAGES */
+
+#define IDSTRModeDef 0x7000
+
+#define IDSTRWriteDocPromptDef 0x7001
+#define IDSTRScratchFilePromptDef 0x7002
+#define IDSTRSaveFilePromptDef 0x7003
+#define IDSTRAppNameDef 0x7004
+#define IDSTRUntitledDef 0x7005
+
+#define IDSTRiCountryDefaultDef 0x7006
+
+#define IDSTRWRITETextDef 0x7007
+
+#define IDSTRFreeDef 0x7008
+
+#define IDSTRNoneDef 0x7009
+
+#define IDSTRHeaderDef 0x700a
+#define IDSTRFooterDef 0x700b
+
+#define IDSTRLoadFileDef 0x700c
+#define IDSTRCvtLoadFileDef 0x700d
+
+#define IDSTRInchDef 0x700e
+#define IDSTRCmDef 0x700f
+#define IDSTRP10Def 0x7010
+#define IDSTRP12Def 0x7011
+#define IDSTRPointDef 0x7012
+#define IDSTRLineDef 0x7013
+#define IDSTRAltBSDef 0x7014
+
diff --git a/private/mvdm/wow16/write/tags b/private/mvdm/wow16/write/tags
new file mode 100644
index 000000000..faa550e69
--- /dev/null
+++ b/private/mvdm/wow16/write/tags
@@ -0,0 +1,842 @@
+ABS c:\dev\inc\printer.h ?^#define ABS(x) (((x) >= 0) ? (x) : (-(x))?
+Abort c:diaalert.c ?^int far Abort(response)$?
+AddFtns c:editftn.c ?^AddFtns(docDest, cpDest, docSrc, cpFirst, cpLim, h?
+AddOneSprm c:addprm.c ?^AddOneSprm(psprm, fSetUndo)$?
+AddRunScratch c:insertco.c ?^AddRunScratch(pfkpd, pchProp, pchStd, cchProp, fcL?
+AddSects c:editsect.c ?^AddSects(docDest, cpDest, docSrc, cpFirst, cpLim, ?
+AddSprm c:addprm.c ?^AddSprm(psprm)$?
+AddSprmCps c:addprm.c ?^AddSprmCps(psprm, doc, cpFirst, cpLim)$?
+AddVisiSpaces c:mainloop.c ?^AddVisiSpaces(ww, pedl, dypBaseline, dypFontSize)$?
+AdjParas c:edit.c ?^AdjParas(docDest, cpDest, docSrc, cpFirstSrc, dcpL?
+AdjRg c:edit.c ?^AdjRg(pfoo, cchFoo, bcp, ccp, cp, dcpAdj)$?
+AdjWwHoriz c:scrollhz.c ?^AdjWwHoriz(dxpScroll)$?
+AdjWwVert c:scrollvt.c ?^AdjWwVert(cdl, dyp)$?
+AdjustCp c:edit.c ?^AdjustCp(doc, cpFirst, dcpDel, dcpIns)$?
+AlignFn c:file.c ?^AlignFn(fn, cch, fEven)$?
+AlphaMode c:insert.c ?^AlphaMode( kc )$?
+AppendCachePtr c:scrollvt.c ?^AppendCachePtr( ptr )$?
+AppendSzExt c:fileutil.c ?^AppendSzExt( szFile, szExt, fOverride )$?
+ApplyCLooks c:addprm.c ?^ApplyCLooks(pchp, sprm, val)$?
+ApplyLooksPara c:addprm.c ?^ApplyLooksPara(pchp, sprm, val)$?
+ApplyLooksParaS c:addprm.c ?^ApplyLooksParaS(pchp, sprm, val)$?
+ApplyRHMarginSprm c:createww.c ?^ApplyRHMarginSprm( doc )$?
+Assert c:mw.h ?^#define Assert(f) _Assert(__FILE__, __LINE__, f)$?
+BFromFc c:cache.c ?^int BFromFc( pfkp, fc, pfcFirst, pfcLim )$?
+BOOL c:search.c ?^BOOL (NEAR FAbort(void));$?
+BStructMember c:mw.h ?^#define BStructMember( s, field ) ((unsigned)&(((?
+BroadcastAllEnum c:trans3.c ?^int FAR PASCAL BroadcastAllEnum( hwnd, lParam )$?
+BroadcastChildEnum c:trans3.c ?^int FAR PASCAL BroadcastChildEnum( hwnd, lParam )$?
+CachePage c:mainloop.c ?^CachePage(doc,cp)$?
+CachePara c:cache.c ?^CachePara(doc, cp)$?
+CacheSect c:cache.c ?^CacheSect(doc, cp)$?
+CacheSectPic c:picture.c ?^CacheSectPic(doc, cp)$?
+CancelSpecialDialog c:diapara.c ?^CancelSpecialDialog(phDlg)$?
+CbFfn c:fontdefs.h ?^#define CbFfn(cch) (sizeof(struct FFN) - cchFfnMin?
+CbFromPffn c:fontdefs.h ?^#define CbFromPffn(pffn) (sizeof(FFID)+sizeof(B?
+CchChStuff c:format2.c ?^int CchChStuff(ppch, ch, cchMax)$?
+CchCopySz c:util.c ?^int CchCopySz(pchFrom, pchTo)$?
+CchCopyUpperSz c:trans3.c ?^int CchCopyUpperSz(pch1, pch2)$?
+CchCurGlosFile c:transbuf.c ?^int CchCurGlosFile(pfld, pch, fNew, ival)$?
+CchCurSzPath DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*CchCurSzPath
+CchDiffer LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*CchDiffer
+CchDiffer c:util.c ?^int CchDiffer(rgch1, rgch2, cch)$?
+CchExpCp c:trans2.c ?^int NEAR CchExpCp(pch, cp)$?
+CchExpFtn c:format2.c ?^int CchExpFtn(pch, cp, flm, cchMax)$?
+CchExpPgn c:format2.c ?^int CchExpPgn(pch, pgn, nfc, flm, cchMax)$?
+CchExpUnknown c:format2.c ?^int CchExpUnknown(pch, flm, cchMax)$?
+CchExpZa c:util2.c ?^CchExpZa(ppch, za, ut, cchMax, fVertical)$?
+CchPageIn c:file.c ?^int CchPageIn(fn, pn, rgbBuf, cpnRead)$?
+CchPsprm c:doprm.c ?^CchPsprm(psprm)$?
+CchReadAtPage c:file.c ?^CchReadAtPage( fn, pn, rgb, dfc, fSeriousErr )$?
+CchReadDoshnd DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*CchReadDoshnd
+CchReadLineExt c:clipbrd2.c ?^CchReadLineExt( lpch, cbRead, rgch, pfEol)$?
+CchStuff c:util2.c ?^int CchStuff(ppch, sz, cchMax)$?
+CchStuffIdstr c:format2.c ?^int CchStuffIdstr(ppch, idstr, cchMax)$?
+CchStuffRoman c:format2.c ?^int CchStuffRoman(ppch, u, rgch, cchMax)$?
+CchSz c:util.c ?^int CchSz(sz)$?
+CchWriteDoshnd DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*CchWriteDoshnd
+ChGetKanji2 c:insert.c ?^CHAR near ChGetKanji2()$?
+ChInpWait c:chlook.c ?^int ChInpWait()$?
+ChLower c:util.c ?^ChLower(ch)$?
+ChLowerC c:open.c ?^ChLowerC(ch)$?
+ChUpper c:util.c ?^int ChUpper(ch)$?
+ChVisible c:mainloop.c ?^int ChVisible(ch)$?
+ChangeClipboard c:clipbord.c ?^ChangeClipboard()$?
+ChangeSel c:select.c ?^ChangeSel(cp, sty)$?
+ChangeWwDoc c:createww.c ?^ChangeWwDoc( szDoc )$?
+CheckEnableButton c:trans3.c ?^BOOL CheckEnableButton(hCtlEdit, hCtlEnable)$?
+CheckGraphic c:edit.c ?^CheckGraphic(doc, cp)$?
+CheckIbp c:file.c ?^CheckIbp()$?
+CheckMode c:mainloop.c ?^CheckMode()$?
+CheckMove c:selectsp.c ?^CheckMove()$?
+CheckPctb c:debug.c ?^CheckPctb()$?
+ChsInferred c:fontenum.c ?^int ChsInferred( pffn )$?
+CksmFromIbp c:file.c ?^unsigned CksmFromIbp( ibp )$?
+CleanBuffers c:transbuf.c ?^CleanBuffers()$?
+CleanDoc c:trans2.c ?^CleanDoc(doc, dty, szFile, fFormatted, fBackup )$?
+CleanUpHelpPopUp c:help.c ?^NEAR CleanUpHelpPopUp()$?
+ClearGlosBuf c:transbuf.c ?^ClearGlosBuf ()$?
+ClearInsertLine c:disp.c ?^ClearInsertLine()$?
+ClobberDoc c:edit.c ?^ClobberDoc(docDest, docSrc, cp, dcp)$?
+CloseEveryRfn c:fileres.c ?^CloseEveryRfn( fHardToo )$?
+CloseEveryRfnTB c:transbuf.c ?^CloseEveryRfnTB(fRetry)$?
+CloseFn c:file.c ?^CloseFn( fn )$?
+CloseHelpDoc c:help.c ?^NEAR CloseHelpDoc()$?
+CloseRfn c:fileres.c ?^CloseRfn( rfn )$?
+CloseWw c:wwactde.c ?^CloseWw(ww)$?
+CmdAgain c:undo.c ?^CmdAgain()$?
+CmdEatMemory c:cmd.c ?^CmdEatMemory()$?
+CmdEatWinMemory c:cmd.c ?^CmdEatWinMemory()$?
+CmdFreeMemory c:cmd.c ?^CmdFreeMemory()$?
+CmdFreeWinMemory c:cmd.c ?^CmdFreeWinMemory()$?
+CmdInsScrap c:clipbord.c ?^CmdInsScrap( fUnFormattedText )$?
+CmdJumpPage c:jumppage.c ?^CmdJumpPage()$?
+CmdReplace c:search.c ?^#define CmdReplace(fThenFind) DoReplace(false, fTh?
+CmdReplaceAll c:search.c ?^#define CmdReplaceAll() DoReplace(true, fals?
+CmdShowMemory c:cmd.c ?^CmdShowMemory()$?
+CmdUndo c:undo.c ?^CmdUndo()$?
+CmdUnscalePic c:pictdrag.c ?^CmdUnscalePic()$?
+CmdXfBufClear c:transbuf.c ?^CmdXfBufClear()$?
+CmdXfBufLoad c:transbuf.c ?^CmdXfBufLoad()$?
+CmdXfBufSave c:transbuf.c ?^CmdXfBufSave(szFile)$?
+CmdXfSave c:trans2.c ?^CmdXfSave(szFile, fFormatted, fBackup, hcAfterward?
+CnfrmSz c:quit.c ?^int CnfrmSz(sz)$?
+CommSz DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*CommSz
+CommSz c:debug.c ?^void CommSz( psz )$?
+CommSzNum c:debug.c ?^CommSzNum( sz, num )$?
+CommSzNumNum c:debug.c ?^CommSzNumNum( sz, num, num2 )$?
+CommSzRgNum c:debug.c ?^CommSzRgNum( sz, rgw, cw)$?
+CommSzSz c:debug.c ?^CommSzSz( sz1, sz2 )$?
+CompactHeap c:heapinit.c ?^CompactHeap()$?
+CompressRgbp c:heaprare.c ?^NEAR CompressRgbp()$?
+ComputePictRect c:picture.c ?^ComputePictRect( prc, ppicInfo, pedl, ww )$?
+ConvertFromWord c:trans3.c ?^void ConvertFromWord ()$?
+CopyChUpper c:fileutil.c ?^CopyChUpper( szSource, szDest, cch )$?
+CopyHeapTableHandle c:edit.c ?^CopyHeapTableHandle( hBase, bhSrc, bhDest, cwHandl?
+CopyMouse c:selectsp.c ?^CopyMouse()$?
+CpBeginLine c:disp.c ?^typeCP CpBeginLine(pdl, cp)$?
+CpEdge c:select.c ?^typeCP CpEdge()$?
+CpFirstSty c:select.c ?^typeCP CpFirstSty(cp, sty)$?
+CpFirstStySpecial c:select2.c ?^typeCP CpFirstStySpecial(cp, sty)$?
+CpHintCache c:scrollvt.c ?^typeCP CpHintCache(cp)$?
+CpLastStyChar c:select.c ?^typeCP CpLastStyChar( cp )$?
+CpLimNoSpaces c:menu.c ?^typeCP CpLimNoSpaces(cpFirst, cpLim)$?
+CpLimSty c:select.c ?^typeCP CpLimSty(cp, sty)$?
+CpLimStySpecial c:select2.c ?^typeCP CpLimStySpecial(cp, sty)$?
+CpMacText c:util.c ?^typeCP CpMacText(doc)$?
+CpMax c:util.c ?^typeCP CpMax(cp1, cp2)$?
+CpMin c:util.c ?^typeCP CpMin(cp1, cp2)$?
+CpSearchSz c:search.c ?^typeCP NEAR CpSearchSz(cpFirst, cpMacSearch, sz)$?
+CpToDlXp c:curskeys.c ?^CpToDlXp(cp, pdl, pxp)$?
+CpWinGraphic c:picture.c ?^typeCP CpWinGraphic(pwwd)$?
+CreateHeapI c:initmmw.c ?^CreateHeapI()$?
+CtrBackDypCtr c:scrollvt.c ?^int CtrBackDypCtr( dypLim, ctrLim )$?
+CwFromCch c:mw.h ?^#define CwFromCch(cch) (((cch) + sizeof (int) - 1?
+DWORD c:\dev\inc\printer.h ?^typedef DWORD (FAR * DWORDFARPROC)();$?
+DaGetFileModeSz DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*DaGetFileModeSz
+DefaultFamilyCheck c:screen.c ?^DefaultFamilyCheck(ffid, sz, chsIfKnown)$?
+DefaultPaps c:cache.c ?^DefaultPaps( doc )$?
+DelChars c:insert.c ?^void NEAR DelChars( cp, cch )$?
+DelFtns c:edit.c ?^DelFtns(doc, cpFirst, cpLim)$?
+DeleteRulerTab c:ruler.c ?^near DeleteRulerTab(ptbd)$?
+DeleteSel c:edit.c ?^DeleteSel()$?
+DestroyModeless c:search.c ?^NEAR DestroyModeless(phDlg)$?
+DestroyRuler c:ruler.c ?^near DestroyRuler()$?
+Dfli c:form1.c ?^#define Dfli(x) x /* Enable debug-format-line inf?
+Diag c:mw.h ?^#define Diag(s) s$?
+DialogBadMargins c:diaalert.c ?^BOOL far PASCAL DialogBadMargins(hDlg, message, wP?
+DialogCancelPrint c:print.c ?^BOOL far PASCAL DialogCancelPrint(hWnd, message, w?
+DialogChange c:search.c ?^BOOL far PASCAL DialogChange( hDlg, message, wPara?
+DialogCharFormats c:fontdlg.c ?^BOOL far PASCAL DialogCharFormats(hDlg, message, w?
+DialogConfirm c:diasubs.c ?^BOOL far PASCAL DialogConfirm(hDlg, message, wPara?
+DialogDivision c:diadiv.c ?^BOOL far PASCAL DialogDivision(hDlg, message, wPar?
+DialogFind c:search.c ?^BOOL far PASCAL DialogFind( hDlg, message, wParam,?
+DialogGoTo c:jumppage.c ?^BOOL far PASCAL DialogGoTo( hDlg, message, wParam,?
+DialogHelp c:help.c ?^BOOL far PASCAL DialogHelp( hDlg, code, wParam, lP?
+DialogHelpInner c:help.c ?^BOOL far PASCAL DialogHelpInner( hDlg, code, wPara?
+DialogOpen c:trans3.c ?^BOOL far PASCAL DialogOpen( hDlg, code, wParam, lP?
+DialogPageMark c:diarepag.c ?^BOOL far PASCAL DialogPageMark(hWnd, message, wPar?
+DialogParaFormats c:diapara.c ?^BOOL far PASCAL DialogParaFormats( hDlg, message, ?
+DialogPrint c:diaprint.c ?^BOOL far PASCAL DialogPrint( hDlg, message, wParam?
+DialogPrinterSetup c:diachgpr.c ?^BOOL far PASCAL DialogPrinterSetup( hDlg, message,?
+DialogRepaginate c:diarepag.c ?^BOOL far PASCAL DialogRepaginate(hDlg, code, wPara?
+DialogRunningHead c:running.c ?^BOOL far PASCAL DialogRunningHead( hDlg, message, ?
+DialogSaveAs c:trans3.c ?^BOOL far PASCAL DialogSaveAs( hDlg, code, wParam, ?
+DialogSetPage c:diarepag.c ?^BOOL far PASCAL DialogSetPage(hWnd, message, wPara?
+DialogTabs c:diadiv.c ?^BOOL far PASCAL DialogTabs(hDlg, message, wParam, ?
+DialogWordCvt c:trans3.c ?^BOOL far PASCAL DialogWordCvt( hDlg, code, wParam,?
+DirtyCache c:scrollvt.c ?^DirtyCache(cp)$?
+DiskError c:diaalert.c ?^DiskError(idpmt)$?
+DiskErrorWithMsg c:diaalert.c ?^DiskErrorWithMsg(idpmt, szMessage)$?
+DispatchPaintMsg c:print.c ?^DispatchPaintMsg()$?
+DisplayFli c:disp.c ?^DisplayFli(ww, dl, fDontDisplay)$?
+DisplayGraphics c:picture.c ?^DisplayGraphics( ww, dl, fDontDisplay )$?
+DlFromYp c:mouse.c ?^int DlFromYp(yp, pwwd)$?
+DlgAddCorrectExtension c:trans3.c ?^NEAR DlgAddCorrectExtension(szEdit, fSearching)$?
+DoChLook c:chlook.c ?^DoChLook(ch, pchp)$?
+DoContentHit c:mouse.c ?^DoContentHit(pt)$?
+DoContentHitEnd c:mouse.c ?^DoContentHitEnd(pt)$?
+DoFormatPara c:diapara.c ?^DoFormatPara(rgval)$?
+DoFormatRHText c:running.c ?^DoFormatRHText( dya, fFirstPage)$?
+DoPrm c:doprm.c ?^DoPrm(pchp, ppap, prm)$?
+DoReplace c:search.c ?^NEAR DoReplace(fReplaceAll, fThenFind)$?
+DoSearch c:search.c ?^NEAR DoSearch()$?
+DoSprm c:doprm.c ?^DoSprm(pchp, ppap, sprm, pval)$?
+Do_Assert c:debug.c ?^Do_Assert(pch, line, f)$?
+DocAlloc c:createww.c ?^int DocAlloc()$?
+DocCreate c:createww.c ?^int DocCreate(fn, hszFile, dty)$?
+DocFromSz c:doc.c ?^int DocFromSz(sz, dty)$?
+DoshndGrabUniqueSzFile c:fileutil.c ?^DoshndGrabUniqueSzFile( szFile, fLeaveOpen )$?
+DosxError DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*DosxError
+DrawInsertLine c:disp.c ?^DrawInsertLine()$?
+DrawMode c:pageinfo.c ?^DrawMode()$?
+DrawPMSFrameIcon c:pictdrag.c ?^void NEAR DrawPMSFrameIcon( mdIcon, pt )$?
+DwSeekDw DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*DwSeekDw
+DxaFromDxp c:picture2.c ?^int DxaFromDxp( dxp, fPrinter )$?
+DxaFromItem c:util2.c ?^int DxaFromItem(it)$?
+DxaFromSt c:util2.c ?^int DxaFromSt(st, ut)$?
+DxpDiff c:disp.c ?^DxpDiff(dcpFirst, dcp, pdxpFirst)$?
+DxpFromCh FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*DxpFromCh
+DxpFromCh FORMAT.ASM /^DxpFromCh
+DxpFromCh c:form1.c ?^int DxpFromCh(ch, fPrinter)$?
+DxpFromDxa c:picture2.c ?^int DxpFromDxa( dxa, fPrinter )$?
+DyaFromDyp c:picture2.c ?^int DyaFromDyp( dyp, fPrinter )$?
+DyaFromHps c:loadfont.c ?^unsigned DyaFromHps(hps)$?
+DypFromDya c:picture2.c ?^int DypFromDya( dya, fPrinter )$?
+DypScroll c:disp.c ?^DypScroll(ww, dlFirst, ddl, ypTo)$?
+EditHeaderFooter c:running.c ?^int NEAR EditHeaderFooter()$?
+EnableExcept c:diaalert.c ?^EnableExcept(hWnd, fEnable)$?
+EnableOtherModeless c:diasubs.c ?^EnableOtherModeless(fEnable)$?
+EndFontEnum c:fontenum.c ?^EndFontEnum()$?
+EndInsert c:insert.c ?^void NEAR EndInsert()$?
+EndLongOp c:util.c ?^EndLongOp(hc)$?
+EndLookSel c:addprm.c ?^EndLookSel(pselSave, fPara)$?
+EndPMS c:pictdrag.c ?^void NEAR EndPMS()$?
+Error c:diaalert.c ?^Error(idpmt)$?
+ErrorBadMargins c:diaalert.c ?^ErrorBadMargins(hWnd, xaLeft, xaRight, yaTop, yaBo?
+ErrorLevel c:diaalert.c ?^ErrorLevel(idpmt)$?
+ErrorWithMsg c:diaalert.c ?^ErrorWithMsg(idpmt, szMessage)$?
+ExpandCurSel c:addprm.c ?^ExpandCurSel(pselSave)$?
+FAccessFn c:file.c ?^FAccessFn( fn )$?
+FAddEnumFont c:fontenum.c ?^FAddEnumFont(pffn)$?
+FAddFontSize c:fontdlg.c ?^BOOL FAddFontSize(ps)$?
+FAddProfileFonts c:fontenum.c ?^int NEAR FAddProfileFonts()$?
+FAddRun c:insertco.c ?^int FAddRun(fn, pfkp, ppchFprop, pprun, pchProp, p?
+FAdmitCh1 c:form1.c ?^BOOL near FAdmitCh1(ch)$?
+FAdmitCh2 c:form1.c ?^BOOL near FAdmitCh2(ch1, ch2)$?
+FAllDocsClean c:quit.c ?^FAllDocsClean()$?
+FAllZeroPpchPch c:diasubs.c ?^FAllZeroPpchPch(ppch, pchMax)$?
+FApplyOldWordSprm c:open.c ?^FApplyOldWordSprm(doc)$?
+FBackupSzFile c:trans2.c ?^FBackupSzFile( szFile, fBackup, szBak )$?
+FBeginInsert c:insert.c ?^int NEAR FBeginInsert()$?
+FCharBoundaryPchPch c:util2.c ?^BOOL FCharBoundaryPchPch(pchFirst, pchTarget)$?
+FCheckFont c:fontenum.c ?^#define FCheckFont(lptm) (1)$?
+FCheckPicture c:selectsp.c ?^int FCheckPicture(pcpDest, dcp, fSetUndo, doc)$?
+FCheckPopupRect c:scrollhz.c ?^int FCheckPopupRect( hwnd, lprc )$?
+FCheckToggleKeyMessage c:cmd.c ?^FCheckToggleKeyMessage( pmsg )$?
+FChngSizeH c:heapmain.c ?^FChngSizeH(pfgrChng, cwRequest, fShrink)$?
+FCloseDoshnd DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FCloseDoshnd
+FCloseXa c:ruler.c ?^BOOL near FCloseXa(xa1, xa2)$?
+FComputePictSize c:clipbrd2.c ?^FComputePictSize( pmfp, pdxa, pdya )$?
+FConfirmSave c:trans3.c ?^FConfirmSave()$?
+FCopyPgtb c:undo.c ?^BOOL near FCopyPgtb(doc, phpgtb)$?
+FCpInsertInDl c:insert2.c ?^int NEAR FCpInsertInDl( cp, pedl )$?
+FCpValid c:search.c ?^FCpValid(cp, dcp)$?
+FCreateFile c:file.c ?^FCreateFile( szFile, fn )$?
+FCreateRgbp c:initmmw.c ?^FCreateRgbp()$?
+FCreateRuler c:ruler.c ?^BOOL near FCreateRuler()$?
+FDeleteFile c:trans3.c ?^FDeleteFile( szFileName )$?
+FDeleteFileMessage c:trans3.c ?^FDeleteFileMessage( hName )$?
+FDeleteFn c:trans3.c ?^int FDeleteFn(fn)$?
+FDirtyDoc c:util2.c ?^int FDirtyDoc(doc)$?
+FDlgSzTooLong c:search.c ?^NEAR FDlgSzTooLong(hDlg, idi, pch, cchMax)$?
+FEditFtn c:insert2.c ?^int FEditFtn(cpFirst, cpLim)$?
+FEnsureOnLineFn c:file.c ?^FEnsureOnLineFn( fn )$?
+FEnsurePffn c:fontutil.c ?^FEnsurePffn(hffntb, pffn)$?
+FEnumFont c:fontenum.c ?^BOOL FEnumFont(pffn)$?
+FEnumFontSize c:fontdlg.c ?^BOOL NEAR FEnumFontSize(sz)$?
+FExistsSzFile c:trans2.c ?^int FExistsSzFile(dty, szFile)$?
+FExpandFgrTbl c:heapinit.c ?^FExpandFgrTbl()$?
+FFirst DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FFirst
+FFirstIch FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FFirstIch
+FFirstIch FORMAT.ASM /^FFirstIch
+FFirstIch c:form1.c ?^int near FFirstIch(ich)$?
+FFlushFn c:file.c ?^int FFlushFn(fn)$?
+FFormatSpecials c:format2.c ?^int FFormatSpecials(pifi, flm, nfc)$?
+FGetClipboardDC c:clipdisp.c ?^int NEAR FGetClipboardDC()$?
+FGetPictPedl c:picture.c ?^FGetPictPedl(ppedl)$?
+FGetPrinterFromProfile c:scrnchng.c ?^BOOL FGetPrinterFromProfile()$?
+FGiveupFreeBps c:heaprare.c ?^NEAR FGiveupFreeBps(cb, pCPage)$?
+FGrabExtMemoScrap c:clipbord.c ?^int FGrabExtMemoScrap()$?
+FGrowFormatHeap FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FGrowFormatHeap
+FGrowFormatHeap FORMAT.ASM /^FGrowFormatHeap
+FGrowFormatHeap c:form1.c ?^int near FGrowFormatHeap()$?
+FGrowRgbp c:diaalert.c ?^FGrowRgbp(cbp)$?
+FImportantMsgPresent c:disp.c ?^FImportantMsgPresent()$?
+FInModeless c:diaalert.c ?^#define FInModeless(hWnd) (hWnd == vhDlgFind || hW?
+FInWordFormat c:trans3.c ?^BOOL FInWordFormat(fn)$?
+FInitArgs c:initmmw.c ?^int FInitArgs(sz)$?
+FInitBufs c:initmmw.c ?^FInitBufs()$?
+FInitDocs c:initmmw.c ?^STATIC int NEAR FInitDocs()$?
+FInitFarprocs c:initwin.c ?^STATIC int NEAR FInitFarprocs( hInstance )$?
+FInitFiles c:initmmw.c ?^STATIC int NEAR FInitFiles()$?
+FInitFontEnum c:fontenum.c ?^FInitFontEnum(doc, cffnInteresting, fOrder)$?
+FInitHeaderFooter c:diaprint.c ?^BOOL FInitHeaderFooter(fHeader, ppgn, phrgpld, pcp?
+FInitIntlStrings c:initwin.c ?^BOOL FInitIntlStrings(hInstance)$?
+FInitMapSave c:trans2.c ?^FInitMapSave(doc, phffntb, mpftcftc)$?
+FInitMemory c:initmmw.c ?^int FInitMemory()$?
+FInitPctb c:createww.c ?^FInitPctb(doc, fn)$?
+FInitProps c:initmmw.c ?^STATIC int NEAR FInitProps()$?
+FInitWinInfo c:initwin.c ?^int FInitWinInfo( hInstance, hPrevInstance, lpszCm?
+FInzHelpPopUp c:help.c ?^FInzHelpPopUp( hDlg )$?
+FIsCaughtDwSeekErr c:doslib.h ?^#define FIsCaughtDwSeekErr(dw) FIsCaughtFpe((int)?
+FIsCaughtFpe c:doslib.h ?^#define FIsCaughtFpe(fpe) FIsCaughtOfe(-(fpe))$?
+FIsCaughtOfe c:doslib.h ?^#define FIsCaughtOfe(ofe) (((ofe)>=ofeCaughtFirs?
+FIsCommandKc c:ch.h ?^#define FIsCommandKc(kc) ((int)(kc) < 0) /* or, te?
+FIsErrCchDisk c:doslib.h ?^#define FIsErrCchDisk(cch) ((int)(cch) < 0)$?
+FIsErrDoshnd c:doslib.h ?^#define FIsErrDoshnd(doshnd) ((int)(doshnd)?
+FIsErrDwSeek c:doslib.h ?^#define FIsErrDwSeek(dw) ((long)(dw) < (long)0)?
+FIsErrFpe c:doslib.h ?^#define FIsErrFpe(fpe) ((int)(fpe) < 0)$?
+FIsMenuItemEnabled c:menu.c ?^FIsMenuItemEnabled ( id )$?
+FKana c:kanji.h ?^#define FKana(_ch) (0xA0 <= ((int) (_ch)) && ?
+FKanaPunct c:kanji.h ?^#define FKanaPunct(_ch) ((0xA0 <= ((int) (_ch)) &&?
+FKanaText c:kanji.h ?^#define FKanaText(_ch) (0xA6 <= ((int) (_ch)) && ?
+FKanji1 c:kanji.h ?^#define FKanji1(_ch) ((((int) (_ch))>=0x0081 && ((?
+FKanjiBang c:kanji.h ?^#define FKanjiBang(_ch1, _ch2) (((int) (_ch1)) =?
+FKanjiKuten c:kanji.h ?^#define FKanjiKuten(_ch1, _ch2) (((int) (_ch1)) =?
+FKanjiPeriod c:kanji.h ?^#define FKanjiPeriod(_ch1, _ch2) (((int) (_ch1)) =?
+FKanjiQMark c:kanji.h ?^#define FKanjiQMark(_ch1, _ch2) (((int) (_ch1)) ==?
+FKanjiSpace c:kanji.h ?^#define FKanjiSpace(_ch1, _ch2) (((int) (_ch1)) ==?
+FMakeFlat c:search.c ?^NEAR FMakeFlat(cch)$?
+FMakeRunTables c:open.c ?^int FMakeRunTables(fn)$?
+FMapFtcSave c:trans2.c ?^FMapFtcSave(doc, hffntb, pchp, mpftcftc)$?
+FMdocClipboardMsg c:clipbord.c ?^FMdocClipboardMsg( message, wParam, lParam )$?
+FMenuUnchecked c:chlook.c ?^FMenuUnchecked(imi)$?
+FMmwClose c:quit.c ?^FMmwClose( hwnd )$?
+FMoveText c:selectsp.c ?^int FMoveText(docSrc, cpSrc, dcp, docDest, pcpDest?
+FNeedToGrowRgbp c:mainloop.c ?^NEAR FNeedToGrowRgbp()$?
+FNext DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FNext
+FNoHeap c:mw.h ?^#define FNoHeap(h) ((int)(h) == hOverflow)$?
+FNoSearchStr c:menu.c ?^NEAR FNoSearchStr(hDlg)$?
+FNonAlphaKeyMessage c:cmd.c ?^FNonAlphaKeyMessage( pmsg, fAct )$?
+FNormSzFile c:fileutil.c ?^FNormSzFile( szNormal, szFile, dty )$?
+FOnScreenRect c:scrollhz.c ?^FOnScreenRect(prc)$?
+FOpenHelpDoc c:help.c ?^NEAR FOpenHelpDoc()$?
+FOptAdmitCh c:form1.c ?^BOOL FOptAdmitCh(ch1, ch2)$?
+FOptAdmitCh1 c:form1.c ?^BOOL near FOptAdmitCh1(ch)$?
+FOptAdmitCh2 c:form1.c ?^BOOL near FOptAdmitCh2(ch1, ch2)$?
+FParaEq c:insertco.c ?^FParaEq(ppap1, ppap2)$?
+FParseUtBackPpch c:util2.c ?^BOOL FParseUtBackPpch(ppchMac, put)$?
+FPasteTooLarge c:clipbord.c ?^BOOL FPasteTooLarge(cb)$?
+FPdxaPosBIt c:diasubs.c ?^FPdxaPosBIt(pdxa, hDlg, it, fVertical)$?
+FPdxaPosIt c:diasubs.c ?^FPdxaPosIt(pdxa, hDlg, it, fVertical)$?
+FPointInPict c:picture.c ?^FPointInPict(pt)$?
+FPointNear c:ruler.c ?^BOOL near FPointNear(xaTarget, xaProbe)$?
+FPrContinue c:print.c ?^BOOL far PASCAL FPrContinue(hDC, iCode)$?
+FPrintBand c:print2.c ?^BOOL FPrintBand(doc, hrgpld, cpld, prcBand)$?
+FPromptPgMark c:diarepag.c ?^BOOL FPromptPgMark(cp)$?
+FPutExtMemoScrap c:clipbord.c ?^int FPutExtMemoScrap()$?
+FPwParsePpchPch c:diasubs.c ?^FPwParsePpchPch(pw, ppch, pchMax, pfOverflow)$?
+FPwPosIt c:diasubs.c ?^FPwPosIt(pw, hDlg, it)$?
+FReadExtScrap c:clipbrd2.c ?^int FReadExtScrap()$?
+FRegisterWnd c:initwin.c ?^STATIC BOOL NEAR FRegisterWnd(hInstance)$?
+FRenderAll c:clipbrd2.c ?^FRenderAll()$?
+FRgchSame c:util.c ?^BOOL FRgchSame(rgch1, rgch2, cch)$?
+FSameClassHwndSz c:trans3.c ?^FSameClassHwndSz( hwnd, szClass )$?
+FSearchChRgch c:form1.c ?^BOOL near FSearchChRgch(ch, rgch, ichLim)$?
+FSetHelpList c:help.c ?^FSetHelpList( hWndListBox )$?
+FSetModeForSection c:mainloop.c ?^FSetModeForSection(pgn)$?
+FSetPage c:diarepag.c ?^BOOL FSetPage()$?
+FSetParaReplace c:search.c ?^NEAR FSetParaReplace(cch)$?
+FSetPsm c:mouse.c ?^int FSetPsm()$?
+FSetScreenConstants c:scrnchng.c ?^int FSetScreenConstants()$?
+FSetWindowColors c:scrnchng.c ?^BOOL FSetWindowColors()$?
+FStartPMS c:pictdrag.c ?^int NEAR FStartPMS( fSize )$?
+FStillDown c:mouse.c ?^FStillDown( ppt )$?
+FStillOutOfMemory c:diaalert.c ?^FStillOutOfMemory()$?
+FSzSame LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FSzSame
+FSzSame c:macro.h ?^#define FSzSame(sz1, sz2) (WCompSz(sz1, sz2)?
+FThrowPages c:heaprare.c ?^NEAR FThrowPages(cPage)$?
+FTryGrow c:heaprare.c ?^FTryGrow(cb)$?
+FUndirtyFn c:trans2.c ?^FUndirtyFn(fn)$?
+FUpdateOneDl c:insert.c ?^FUpdateOneDl( dl )$?
+FUserZaLessThanZa c:cmddefs.h ?^#define FUserZaLessThanZa(zaUser, za) ((zaUser) ?
+FValidFile c:fileutil.c ?^FValidFile(rgch, ichMax, pichError)$?
+FValidIntFromDlg c:diasubs.c ?^BOOL FValidIntFromDlg(hDlg, idi, fSigned, wMin, wM?
+FValidateEnumFfid c:fontdlg.c ?^BOOL NEAR FValidateEnumFfid(pffn)$?
+FWriteCk c:diapara.c ?^ if (!FWriteCk(fwcNil))$?
+FWriteExtScrap c:clipbrd2.c ?^FWriteExtScrap()$?
+FWriteExtTextScrap c:clipbrd2.c ?^int NEAR FWriteExtTextScrap()$?
+FWriteFn c:trans2.c ?^int FWriteFn(fn, doc, fFormatted)$?
+FWriteOk c:edit.c ?^FWriteOk( fwc )$?
+FZaFromSs c:util2.c ?^int FZaFromSs(pza, ss, cch, ut, fVertical)$?
+FcMacFromUnformattedFn c:file.c ?^typeFC FcMacFromUnformattedFn( fn )$?
+FcMin c:transfer.c ?^#define FcMin(a,b) CpMin(a,b)$?
+FcParaFirst c:cache.c ?^typeFC FcParaFirst(fn, fc, fcMin)$?
+FcParaLim c:cache.c ?^typeFC FcParaLim(fn, fc, fcMac, ppap)$?
+FcWScratch c:fileres.c ?^typeFC FcWScratch(pch, cch)$?
+FetchCp c:fetch.c ?^FetchCp(doc, cp, ich, fcm)$?
+FetchRgch c:fetch.c ?^FetchRgch(pcch, pch, doc, cp, cpMac, cchMax)$?
+FillBuf c:macro.h ?^#define FillBuf(pb, cb, ch) bltbc((pb), (CHAR)?
+FillStId c:util2.c ?^FillStId(st, idpmt)$?
+FillWidthTable c:loadfont.c ?^void NEAR FillWidthTable(hdc, rgdxp, ptm)$?
+FlushInsert c:insert.c ?^void NEAR FlushInsert()$?
+FnAlloc c:createww.c ?^int FnAlloc()$?
+FnCreateSz c:createww.c ?^int FnCreateSz(szT, cpMac, dty )$?
+FnFromSz c:open.c ?^int FnFromSz( sz )$?
+FnOpenSz c:open.c ?^int FnOpenSz( szT, dty, fSearchPath )$?
+FontFaceEnum c:fontenum.c ?^BOOL far PASCAL FontFaceEnum(lplf, lptm, fty, lPar?
+FontSizeEnum c:fontenum.c ?^BOOL far PASCAL FontSizeEnum(lplf, lptm, fty, lPar?
+FormatGraphics c:picture2.c ?^FormatGraphics(doc, cp, ichCp, cpMac, flm)$?
+FormatInsLine c:insert.c ?^void NEAR FormatInsLine()$?
+FormatLine FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FormatLine
+FormatLine FORMAT.ASM /^FormatLine
+FormatLine c:form1.c ?^FormatLine(doc, cp, ichCp, cpMac, flm)$?
+FpeDeleteSzFfname DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FpeDeleteSzFfname
+FpeFromCchDisk c:doslib.h ?^#define FpeFromCchDisk(cch) (cch)$?
+FpeRenameFile c:trans3.c ?^int FpeRenameFile(szFileCur, szFileNew)$?
+FpeRenameSzFfname DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*FpeRenameSzFfname
+FpeSeekFnPn c:file.c ?^STATIC int near FpeSeekFnPn( fn, pn )$?
+FreeBitmapCache c:picture.c ?^FreeBitmapCache()$?
+FreeBufferPage c:file.c ?^FreeBufferPage( fn, pn )$?
+FreeFfntb c:fontutil.c ?^FreeFfntb(hffntb)$?
+FreeFn c:trans2.c ?^FreeFn( fn )$?
+FreeFonts c:loadfnt2.c ?^FreeFonts(fScreen, fPrinter)$?
+FreeH c:mw.h ?^#define FreeH(h) LocalFree((HANDLE)h)$?
+FreeMemoryDC c:chngwin.c ?^FreeMemoryDC( fPrinterToo )$?
+FreePfce c:loadfnt2.c ?^FreePfce(pfce)$?
+FreePrinterDC c:chngwin.c ?^FreePrinterDC()$?
+FreeUnreferencedFns c:trans4.c ?^void FreeUnreferencedFns()$?
+FreeWw c:wwactde.c ?^FreeWw( ww )$?
+FreezeHp c:mw.h ?^#define FreezeHp() LocalFreeze(0)$?
+FtcAddDocFfn c:fontutil.c ?^FtcAddDocFfn(doc, pffn)$?
+FtcAddFfn c:fontutil.c ?^int FtcAddFfn(hffntb, pffn)$?
+FtcChkDocFfn c:fontutil.c ?^FtcChkDocFfn(doc, pffn)$?
+FtcFromPchp c:mw.h ?^#define FtcFromPchp(pchp) (((pchp)->ftcXtra << 6) ?
+FtcMapOldFtc c:doprm.c ?^FtcMapOldFtc(ftc, ftctb)$?
+FtcScanDocFfn c:fontutil.c ?^FtcScanDocFfn(doc, pffn)$?
+FtcScanFfn c:fontutil.c ?^FtcScanFfn(hffntb, pffn)$?
+GetBValue c:\dev\inc\windows.h ?^#define GetBValue(rgb) ((BYTE)((rgb)>>16))$?
+GetBitmapMultipliers c:picture2.c ?^long GetBitmapMultipliers( hDC, dxpOrig, dypOrig, ?
+GetBitmapSize c:picture2.c ?^GetBitmapSize( pdxp, pdyp, ppicInfo, fPrinting )$?
+GetChpVals c:menu.c ?^NEAR GetChpVals (pchp,prgtsv) /* load chp values ?
+GetCursorClientPos c:pictdrag.c ?^void NEAR GetCursorClientPos( ppt )$?
+GetDefaultFonts c:screen.c ?^GetDefaultFonts(fExtraFonts, fGetAspect)$?
+GetGValue c:\dev\inc\windows.h ?^#define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >?
+GetHffn c:menu.c ?^NEAR GetHffn (pchp,prgtsv) /* load font name hand?
+GetInsPtProps c:select.c ?^GetInsPtProps(cp)$?
+GetKanjiMeasurement c:ruler.c ?^GetKanjiMeasurement()$?
+GetPapVals c:menu.c ?^NEAR GetPapVals (ppap,prgtsv) /* load pap values ?
+GetPicInfo c:picture2.c ?^GetPicInfo(cp, cpMac, doc, ppicInfo)$?
+GetPrinterDC c:scrnchng.c ?^GetPrinterDC(fDC)$?
+GetRValue c:\dev\inc\windows.h ?^#define GetRValue(rgb) ((BYTE)(rgb))$?
+GetRgtsvChpSel c:menu.c ?^GetRgtsvChpSel (prgtsv)$?
+GetRgtsvPapSel c:menu.c ?^GetRgtsvPapSel (prgtsv)$?
+GetTabsForDoc c:cache.c ?^GetTabsForDoc( doc )$?
+GivePages c:heaprare.c ?^NEAR GivePages(cPage)$?
+GlobalDiscard c:\dev\inc\windows.h ?^#define GlobalDiscard(h) GlobalReAlloc(h, 0L, GMEM?
+HAllocate c:heapmain.c ?^PFGR HAllocate(cwRequest)$?
+HIBYTE c:\dev\inc\printer.h ?^#define HIBYTE(w) (((WORD)w >> 8) & 0xff)$?
+HIWORD c:\dev\inc\windows.h ?^#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) &?
+HWORD c:\dev\inc\printer.h ?^#define HWORD(y) ((short)(((y)>>16)&0xFFFF)?
+HbmMonoFromHbmColor c:clipbrd2.c ?^HbmMonoFromHbmColor( hbmSrc )$?
+HelpDocWndProc c:help.c ?^long FAR PASCAL HelpDocWndProc( hwnd, message, wPa?
+HffntbAlloc c:fontutil.c ?^struct FFNTB **HffntbAlloc()$?
+HffntbCreateForFn c:createww.c ?^struct FFNTB **HffntbCreateForFn(fn, pfOldWord)$?
+HffntbGet c:fontdefs.h ?^#define HffntbGet(doc) ((**hpdocdod)[(doc)].hffntb?
+HffntbNewDoc c:createww.c ?^struct FFNTB **HffntbNewDoc(fFullSet)$?
+HfntbCreate c:editftn.c ?^struct FNTB **HfntbCreate(fn)$?
+HfntbGet c:util.c ?^struct FNTB **HfntbGet(doc)$?
+HgfcCollect c:mw.h ?^typeFC (**HgfcCollect())[];$?
+HgfcCollect c:open.c ?^typeFC (**HgfcCollect(fn, pnFirst, pnLim))[]$?
+HgtbdCreate c:open.c ?^struct TBD (**HgtbdCreate(fn))[]$?
+HideSel c:mw.h ?^#define HideSel()$?
+HighlightButton c:ruler.c ?^void near HighlightButton(fOn, btn)$?
+HpgtbCreate c:open.c ?^struct PGTB **HpgtbCreate(fn)$?
+HpgtbGet c:trans2.c ?^struct PGTB **HpgtbGet(doc)$?
+HpsAlter c:doprm.c ?^int HpsAlter(hps, ialter)$?
+HpsFromDya c:loadfont.c ?^int HpsFromDya(dya)$?
+HsepCreate c:open.c ?^struct SEP **HsepCreate(fn)$?
+HsetbCreate c:editsect.c ?^struct SETB **HsetbCreate(fn)$?
+HsetbGet c:fkpdefs.h ?^#define HsetbGet(doc) ((**hpdocdod)[doc].hsetb)$?
+HsytbCreate c:doc.c ?^struct SYTB **HsytbCreate(doc)$?
+HszCreate c:createww.c ?^CHAR (**HszCreate())[];$?
+HszCreate c:mw.h ?^CHAR (**HszCreate())[];$?
+HszCreateIdpmt c:initwin.c ?^STATIC HANDLE NEAR HszCreateIdpmt(idpmt)$?
+HszGlobalCreate c:util2.c ?^HANDLE HszGlobalCreate( sz )$?
+IFromFc c:cache.c ?^int IFromFc(pfcLim, fc)$?
+IbpEnsureValid c:fileres.c ?^int IbpEnsureValid(fn, pn)$?
+IbpFindSlot c:diaalert.c ?^IbpFindSlot(fn)$?
+IbpLru c:file.c ?^IbpLru(ibpStarting)$?
+IbpMakeValid c:file.c ?^int IbpMakeValid(fn, pn)$?
+IbpWriting c:trans2.c ?^IbpWriting(fn)$?
+IchIndexLp LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*IchIndexLp
+IcpSearch c:edit.c ?^int IcpSearch(cp, rgfoo, cchFoo, bcp, ifooLim)$?
+IdConfirmDirty c:trans3.c ?^IdConfirmDirty()$?
+IdPromptBoxSz c:diaalert.c ?^IdPromptBoxSz( hWndParent, sz, mb )$?
+Idle c:mainloop.c ?^Idle()$?
+IibpHash c:file.c ?^#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1?
+InitBps c:initmmw.c ?^InitBps()$?
+InitFontSizeEnum c:fontdlg.c ?^NEAR InitFontSizeEnum(struct FFN *, CHAR (*) [cchF?
+InitSpecialDialog c:diapara.c ?^InitSpecialDialog(phDlg, hDlg)$?
+InsertEolInsert c:insertco.c ?^InsertEolInsert(doc,cp)$?
+InsertEolPap c:insertco.c ?^InsertEolPap(doc, cp, ppap)$?
+InsertPapsForReplace c:search.c ?^NEAR InsertPapsForReplace(fc)$?
+InsertRgch c:insertco.c ?^InsertRgch(doc, cp, rgch, cch, pchp, ppap)$?
+InsertRulerTab c:ruler.c ?^near InsertRulerTab(ptbd)$?
+InvalBand c:disp.c ?^InvalBand(pwwd, ypFirst, ypLast)$?
+InvalidateCaches c:cache.c ?^InvalidateCaches(doc)$?
+InvertPMSFrame c:pictdrag.c ?^void NEAR InvertPMSFrame()$?
+IpcdFromCp c:fetch.c ?^int IpcdFromCp(ppctb, cp)$?
+IpcdSplit c:edit.c ?^int IpcdSplit(hpctb, cp)$?
+Justify FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*Justify
+Justify FORMAT.ASM /^Justify
+Justify c:form1.c ?^near Justify(pifi, xpTab, flm)$?
+KT c:debug.c ?^KT(cp1, cp2, cch1, cch2, ich)$?
+KTS c:debug.c ?^KTS()$?
+KTS1 c:debug.c ?^KTS1()$?
+KTS2 c:debug.c ?^KTS2()$?
+KTS3 c:debug.c ?^KTS3()$?
+KTSSpecial c:debug.c ?^KTSSpecial()$?
+KanjiGetDC c:form1.c ?^HDC KanjiGetDC(hWnd)$?
+KcAlphaKeyMessage c:cmd.c ?^KcAlphaKeyMessage( pmsg )$?
+KcFromKk c:ch.h ?^#define KcFromKk(kk) ( (kk) + 0x100 )$?
+KcFromKks c:ch.h ?^#define KcFromKks(kks) ( (kks) + 0x200 )$?
+KcInputNextKey c:insert2.c ?^KcInputNextKey()$?
+KillDoc c:doc.c ?^KillDoc(doc)$?
+KillTempFiles c:quit.c ?^KillTempFiles( fEndSession )$?
+LOBYTE c:\dev\inc\printer.h ?^#define LOBYTE(w) ((BYTE)w)$?
+LOWORD c:\dev\inc\windows.h ?^#define LOWORD(l) ((WORD)(l))$?
+LWORD c:\dev\inc\printer.h ?^#define LWORD(x) ((short)((x)&0xFFFF))$?
+LoadF c:preload.h ?^#define LoadF(f) { int f(); GetCodeH?
+LoadFcid c:loadfont.c ?^NEAR LoadFcid(pfcid, pchp)$?
+LoadFont c:loadfont.c ?^LoadFont( doc, pchp, mdFont )$?
+LoadWindowsF c:preload.h ?^#define LoadWindowsF(f) GetCodeHandle( (FARPR?
+LocalDiscard c:\dev\inc\windows.h ?^#define LocalDiscard(h) LocalReAlloc(h, 0, LME?
+LocalFreeze c:\dev\inc\windows.h ?^#define LocalFreeze(dummy) (*(pLocalHeap+1) += 1)?
+LocalHandleDelta c:\dev\inc\windows.h ?^#define LocalHandleDelta(d) ((d) ? (*(pLocalHeap+9?
+LocalMelt c:\dev\inc\windows.h ?^#define LocalMelt(dummy) (*(pLocalHeap+1) -= 1)?
+LockData c:\dev\inc\windows.h ?^#define LockData(dummy) LockSegment(0xFFFF)$?
+LooksMouse c:selectsp.c ?^LooksMouse()$?
+MAKEINTATOM c:\dev\inc\windows.h ?^#define MAKEINTATOM(i) (LPSTR)((DWORD)((WORD)(?
+MAKEINTRESOURCE c:\dev\inc\windows.h ?^#define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)?
+MAKELONG c:\dev\inc\printer.h ?^#define MAKELONG(h,l) ((long)(((WORD)l)|(((long)h?
+MAKEPOINT c:\dev\inc\printer.h ?^#define MAKEPOINT(l) (*((POINT *)&l))$?
+MAKEWORD c:kanji.h ?^#define MAKEWORD(_bHi, _bLo) ((((WORD) _bHi) << 8)?
+MAX c:\dev\inc\printer.h ?^#define MAX(a,b) ((a)>(b)?(a):(b))$?
+MIN c:\dev\inc\printer.h ?^#define MIN(a,b) ((a)<=(b)?(a):(b))$?
+MainLoop c:mainloop.c ?^MainLoop()$?
+MakeRunningCps c:running.c ?^MakeRunningCps( doc, cp, dcp )$?
+MakeScrapUnRunning c:clipbord.c ?^MakeScrapUnRunning()$?
+MarkInvalidDlPict c:picture.c ?^MarkInvalidDlPict( ww, dlPict )$?
+MdInsUpdInsertCh c:insert.c ?^int NEAR MdInsUpdInsertCh( chInsert, chShow, prcSc?
+MdInsUpdInsertW c:insert.c ?^int NEAR MdInsUpdInsertW(wInsert, wShow, prcScroll?
+MdocAskCBFormatName c:clipdisp.c ?^MdocAskCBFormatName( lpchName, cchNameMax )$?
+MdocCreate c:initwin.c ?^void MdocCreate(hWnd, lParam)$?
+MdocDestroyClip c:clipbord.c ?^MdocDestroyClip()$?
+MdocGetFocus c:chngwin.c ?^void MdocGetFocus(hWnd, hWndPrevFocus)$?
+MdocHScrollClipboard c:clipdisp.c ?^MdocHScrollClipboard( hWnd, sbMessage, wNewThumb ?
+MdocLoseFocus c:chngwin.c ?^void MdocLoseFocus(hWnd, hWndNewFocus)$?
+MdocMouse c:mdoc.c ?^void MdocMouse(hWnd, message, wParam, pt)$?
+MdocPaintClipboard c:clipdisp.c ?^MdocPaintClipboard( hWnd, hPS )$?
+MdocRenderFormat c:clipbord.c ?^MdocRenderFormat( wCf )$?
+MdocSize c:chngwin.c ?^void MdocSize(hWnd, cxpNew, cypNew, code)$?
+MdocSizeClipboard c:clipdisp.c ?^MdocSizeClipboard( hWnd, hRC )$?
+MdocTimer c:mdoc.c ?^void MdocTimer(hWnd, id)$?
+MdocVScrollClipboard c:clipdisp.c ?^MdocVScrollClipboard( hWnd, sbMessage, wNewThumb ?
+MdocWndProc c:mdoc.c ?^long FAR PASCAL MdocWndProc(hWnd, message, wParam,?
+MeltHp c:mw.h ?^#define MeltHp() LocalMelt(0)$?
+MergeFfntb c:edit.c ?^MergeFfntb(docSrc, docDest, cpMin, cpLim)$?
+MergeInit c:trans3.c ?^VOID MergeInit()$?
+MergeRulerMark c:ruler.c ?^near MergeRulerMark(rmk, xpMark, fHighlight)$?
+MergeStrings c:trans3.c ?^BOOL MergeStrings (idSrc, szMerge, szDst)$?
+MergeTxbsFn c:transbuf.c ?^MergeTxbsFn(fn)$?
+MmwCommand c:menu.c ?^void MmwCommand(hWnd, wParam, hWndCtl, codeCtl)$?
+MmwCreate c:initwin.c ?^void MmwCreate(hWnd, lParam)$?
+MmwDestroy c:quit.c ?^MmwDestroy()$?
+MmwHorzScroll c:mmw.c ?^void near MmwHorzScroll(hWnd, code, posNew)$?
+MmwPaint c:mmw.c ?^void NEAR MmwPaint(hWnd)$?
+MmwSize c:chngwin.c ?^void MmwSize(hWnd, cxpNew, cypNew, code)$?
+MmwVertScroll c:mmw.c ?^void MmwVertScroll(hWnd, code, posNew)$?
+MmwWinSysChange c:rare.c ?^MmwWinSysChange(wm)$?
+MmwWndProc c:mmw.c ?^long FAR PASCAL MmwWndProc(hWnd, message, wParam, ?
+ModifyPicInfoDxa c:pictdrag.c ?^STATIC NEAR ModifyPicInfoDxa( xaOffset, xaSize, ya?
+ModifyPicInfoDxp c:pictdrag.c ?^STATIC NEAR ModifyPicInfoDxp( xpOffset, xpSize, yp?
+MoveHelpCtl c:help.c ?^NEAR MoveHelpCtl( hDlg, id, left, top, right, bott?
+MoveLeftRight c:curskeys.c ?^MoveLeftRight( kc )$?
+MoveMouse c:selectsp.c ?^MoveMouse()$?
+MoveUpDown c:curskeys.c ?^MoveUpDown(kc)$?
+MpFcidHffn c:loadfnt2.c ?^struct FFN **MpFcidHffn(pfcid)$?
+MpFfidIffn c:screen.c ?^MpFfidIffn(ffid)$?
+MultDiv LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*MultDiv
+MxRoundMx c:pictdrag.c ?^unsigned NEAR MxRoundMx( mx )$?
+NMultDiv c:macro.h ?^#define NMultDiv(w1, w2, w3) MultDiv(w1, w2, w3?
+NewChpIns c:insert.c ?^NewChpIns(pchp)$?
+NewCurWw c:wwactde.c ?^NewCurWw(ww, fHighlight)$?
+NoUndo c:util.c ?^NoUndo()$?
+OpenEveryHardFn c:file.c ?^OpenEveryHardFn()$?
+OsTime LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*OsTime
+OsfnEnsureValid c:file.c ?^STATIC typeOSFN near OsfnEnsureValid(fn)$?
+OsfnReopenFn c:file.c ?^STATIC typeOSFN near OsfnReopenFn( fn )$?
+OurDialogBox c:diasubs.c ?^OurDialogBox(hInst, lpstr, hWndParent, lpProc)$?
+OurDialogBox c:mw.h ?^#define OurDialogBox(a,b,c,d) DialogBox(a,b,c,d)$?
+OurEndDialog c:diasubs.c ?^OurEndDialog(hDlg, wParam)$?
+OurGetCharWidth c:loadfont.c ?^BOOL OurGetCharWidth(hdc, chFirst, chLast, lpw)$?
+OutSaved c:trans2.c ?^OutSaved(doc)$?
+PALETTEINDEX c:\dev\inc\windows.h ?^#define PALETTEINDEX(i) ((DWORD)(0x01000000 | ?
+PALETTERGB c:\dev\inc\windows.h ?^#define PALETTERGB(r,g,b) (0x02000000 | RGB(r,g,?
+PageInfoWndProc c:pageinfo.c ?^long FAR PASCAL PageInfoWndProc(hWnd, message, wPa?
+ParseDeviceSz c:scrnchng.c ?^int ParseDeviceSz(sz, ppchPort, ppchDriver)$?
+PchBaseNameInUpper c:createww.c ?^CHAR * PchBaseNameInUpper(szName)$?
+PchCvtMx c:pictdrag.c ?^CHAR *PchCvtMx( mx, pch )$?
+PchFillPchId c:util2.c ?^CHAR *PchFillPchId(sz, idstr)$?
+PchFromFc c:fileres.c ?^CHAR *PchFromFc(fn, fc, pcch)$?
+PchGetPn c:fileres.c ?^CHAR *PchGetPn(fn, pn, pcch, fWrite)$?
+PchLastSzCh c:util.c ?^CHAR *PchLastSzCh(sz, ch)$?
+PchSkipSpacesPch c:fontenum.c ?^CHAR * (NEAR PchSkipSpacesPch( CHAR * ));$?
+PchStartBaseNameSz c:util.c ?^CHAR *PchStartBaseNameSz(sz)$?
+PchStripTrailingSpacesPch c:util2.c ?^CHAR *PchStripTrailingSpacesPch(pch, pchMac)$?
+PctDiffUl c:picture2.c ?^int PctDiffUl( ul1, ul2 )$?
+PfceFcidScan c:loadfnt2.c ?^struct FCE * (PfceFcidScan(union FCID *));$?
+PfceLruGet c:loadfnt2.c ?^struct FCE * (PfceLruGet(void));$?
+PffnDefault c:screen.c ?^struct FFN *PffnDefault(ffid)$?
+PhonyMenuAccelerator c:menu.c ?^PhonyMenuAccelerator( menu, imi, lpfn )$?
+PnAlloc c:file.c ?^typePN PnAlloc(fn)$?
+PnFkpFromFcScr c:fetch.c ?^typePN PnFkpFromFcScr(pfkpd, fc)$?
+PostStatusInCaption c:search.c ?^PostStatusInCaption(idstr)$?
+PpcdOpen c:edit.c ?^struct PCD *PpcdOpen(hpctb, ppcd, cpcd)$?
+PreloadCodeTsk c:mainloop.c ?^void PreloadCodeTsk( tsk )$?
+PreloadSaveSegs c:trans3.c ?^PreloadSaveSegs()$?
+PrependCacheRgtr c:scrollvt.c ?^PrependCacheRgtr( rgtr, ctr )$?
+PrintDoc c:print.c ?^PrintDoc(doc, fPrint)$?
+PrintFli c:print2.c ?^void near PrintFli(xpPrint, ypPrint)$?
+PrintGraphics c:print3.c ?^PrintGraphics(xpPrint, ypPrint)$?
+PrmAppend c:addprm.c ?^int PrmAppend(prm, psprm)$?
+PurgeTemps c:trans4.c ?^PurgeTemps()$?
+PushRadioButton c:diasubs.c ?^PushRadioButton(hDlg, idiFirst, idiLast, idiPushed?
+PutCpInWwHz c:scrollhz.c ?^PutCpInWwHz(cp)$?
+PutCpInWwVert c:scrollvt.c ?^PutCpInWwVert(cp)$?
+PutCpInWwVertSrch c:search.c ?^NEAR PutCpInWwVertSrch(cp)$?
+PutParaNum c:diapara.c ?^PutParaNum(n, ut)$?
+PutSzUndoInMenu c:menu.c ?^NEAR PutSzUndoInMenu()$?
+PxlConvert c:picture2.c ?^int PxlConvert( mm, val, pxlDeviceRes, milDeviceRe?
+RGB c:\dev\inc\windows.h ?^#define RGB(r,g,b) ((DWORD)(((BYTE)(r)|((?
+ReadFilePages c:transfer.c ?^ReadFilePages(fn)$?
+RecalcSepText c:cache.c ?^RecalcSepText()$?
+ReduceFnScratchFn c:trans2.c ?^ReduceFnScratchFn( fn )$?
+ReframeRuler c:ruler.c ?^ReframeRuler()$?
+RehashRgibpHash c:transfer.c ?^RehashRgibpHash()$?
+ReleaseClipboardDC c:clipdisp.c ?^int NEAR ReleaseClipboardDC()$?
+RemoveDelFtnText c:editftn.c ?^RemoveDelFtnText(doc, cpFirst, cpLim, hfntb)$?
+RemoveDelPgd c:editpgtb.c ?^RemoveDelPgd(doc, cpFirst, cpLim, hpgtb)$?
+RemoveDelSeds c:editsect.c ?^RemoveDelSeds(doc, cpFirst, cpLim, hsetb)$?
+RenameFileMessage c:trans3.c ?^RenameFileMessage( hName, hNewName )$?
+Repl1 c:edit.c ?^Repl1(doc, cp, dcp, fn, fc, dfc)$?
+Replace c:edit.c ?^Replace(doc, cp, dcp, fn, fc, dfc)$?
+ReplaceCps c:edit.c ?^ReplaceCps(docDest, cpDel, dcpDel, docSrc, cpIns, ?
+ResetDefaultFonts c:screen.c ?^ResetDefaultFonts(fGetAspect)$?
+ResetFn c:trans2.c ?^ResetFn(fn)$?
+ResetFont c:loadfont.c ?^ResetFont(fPrint)$?
+ResetRuler c:ruler.c ?^ResetRuler()$?
+ResetTabBtn c:ruler.c ?^ResetTabBtn()$?
+RfnGrab c:file.c ?^STATIC int near RfnGrab()$?
+RulerMarquee c:ruler.c ?^RulerMarquee()$?
+RulerMouse c:ruler.c ?^RulerMouse(pt)$?
+RulerPaint c:ruler.c ?^RulerPaint(fContentsOnly, fFrameOnly, fInit)$?
+RulerStateFromPt c:ruler.c ?^near RulerStateFromPt(pt, prlc, pbtn)$?
+RulerWndProc c:ruler3.c ?^long FAR PASCAL RulerWndProc(hWnd, message, wParam?
+SaveFontProfile c:trans2.c ?^SaveFontProfile(doc)$?
+Scribble c:debug.h ?^#define Scribble(a, b) fnScribble(a, b)$?
+ScribbleHex c:cmd.c ?^ScribbleHex( dch, wHex, cDigits )$?
+ScrollCurWw c:scrollhz.c ?^ScrollCurWw( prc, dxp, dyp )$?
+ScrollDownCtr c:scrollvt.c ?^ScrollDownCtr(ddr)$?
+ScrollLeft c:scrollhz.c ?^ScrollLeft(dxp)$?
+ScrollRight c:scrollhz.c ?^ScrollRight(dxp)$?
+ScrollUpCtr c:scrollvt.c ?^ScrollUpCtr( ctr )$?
+ScrollUpDypWw c:scrollvt.c ?^ScrollUpDypWw()$?
+Select c:select.c ?^Select(cpFirst, cpLim)$?
+SelectDlXp c:select.c ?^SelectDlXp(dl, xp, sty, fDrag)$?
+SelectFont c:loadfont.c ?^void NEAR SelectFont(fPrint, phfont)$?
+SelectFontName c:fontdlg.c ?^NEAR SelectFontName(hDlg)$?
+SelectFontSize c:fontdlg.c ?^NEAR SelectFontSize(hDlg)$?
+SelectIdiText c:diasubs.c ?^SelectIdiText(hDlg, idi)$?
+SetAppMenu c:menu.c ?^SetAppMenu(hMenu, index)$?
+SetBytes c:macro.h ?^#define SetBytes(pb, b, cb) bltbc((CHAR *)(pb)?
+SetChUndef c:menu.c ?^NEAR SetChUndef(prgtsv, pchp, pcchGray)$?
+SetChangeString c:search.c ?^NEAR SetChangeString(hDlg, fAll)$?
+SetChp c:fetch.c ?^SetChp(pchp, pcfcChp, fn, fc, prm)$?
+SetCurWwVScrollPos c:scrollvt.c ?^SetCurWwVScrollPos( )$?
+SetCursorClientPos c:pictdrag.c ?^void NEAR SetCursorClientPos( pt )$?
+SetDefaultLSChls c:createww.c ?^SetDefaultLSChls(chls)$?
+SetHelpTopic c:help.c ?^SetHelpTopic( hDlg, iTopic )$?
+SetIndentText c:ruler2.c ?^SetIndentText(rmk, dxa)$?
+SetPageSize c:scrnchng.c ?^SetPageSize()$?
+SetParaUndef c:menu.c ?^NEAR SetParaUndef(prgtsv, ppap, pcparaGray)$?
+SetPrintConstants c:scrnchng.c ?^SetPrintConstants()$?
+SetRadValue c:diasubs.c ?^SetRadValue(hDlg, idiFirst, idiLast, idiRad)$?
+SetRfnMac c:file.c ?^SetRfnMac( crfn )$?
+SetRgvalAgain c:diasubs.c ?^SetRgvalAgain(rgvalLocal, uac)$?
+SetRulerMenu c:ruler2.c ?^SetRulerMenu(fShowRuler)$?
+SetShiftFlags c:cmd.c ?^SetShiftFlags()$?
+SetSpaceExtra c:macro.h ?^#define SetSpaceExtra(dxp) SetTextJustificati?
+SetSpecialMatch c:search.c ?^NEAR SetSpecialMatch()$?
+SetTitle c:createww.c ?^SetTitle(szSource)$?
+SetUndo c:edit.c ?^SetUndo(uac, doc, cp, dcp, doc2, cp2, dcp2, itxb)$?
+SetUndoMenuStr c:util.c ?^SetUndoMenuStr(idstr)$?
+SetWords c:macro.h ?^#define SetWords(pw, w, cw) bltc((CHAR *)(pw),?
+SetupClipboardDC c:clipdisp.c ?^int NEAR SetupClipboardDC()$?
+SetupDCForPMS c:pictdrag.c ?^void NEAR SetupDCForPMS()$?
+ShowDocPcd c:debug.c ?^ShowDocPcd(szID, doc)$?
+ShowPictMultipliers c:pictdrag.c ?^STATIC NEAR ShowPictMultipliers( )$?
+ShowPpcd c:debug.c ?^ShowPpcd(szID, ppcd)$?
+SmashDocFce c:fontutil.c ?^SmashDocFce(doc)$?
+SplitSzFilename c:trans3.c ?^SplitSzFilename( szFile, szPath, szName )$?
+StartLongOp c:util.c ?^StartLongOp()$?
+StyFromPt c:mouse.c ?^int StyFromPt(pt)$?
+SzPromptFromFn c:file.c ?^STATIC CHAR *(near SzPromptFromFn( int ));$?
+SzSpacePaddedInt c:fontdlg.c ?^NEAR SzSpacePaddedInt(w, sz, cch)$?
+TestFormat c:debug.c ?^TestFormat()$?
+TestWordCvt c:trans3.c ?^TestWordCvt (fn, hWnd)$?
+TextWidth c:macro.h ?^#define TextWidth(rgch, w, cch) LOWORD(GetTextExte?
+ToggleSel c:disp.c ?^ToggleSel(cpFirst, cpLim, fOn)$?
+TrashAllWws c:disp.c ?^TrashAllWws()$?
+TrashCache c:cache.c ?^TrashCache()$?
+TrashCacheS c:scrollvt.c ?^TrashCacheS()$?
+TrashWw c:disp.c ?^TrashWw(ww)$?
+TurnOffSel c:disp.c ?^TurnOffSel()$?
+UnlockData c:\dev\inc\windows.h ?^#define UnlockData(dummy) UnlockSegment(0xFFFF)$?
+UnlockResource c:\dev\inc\windows.h ?^#define UnlockResource(h) GlobalUnlock(h)$?
+UpdateDisplay c:disp.c ?^UpdateDisplay(fAbortOK)$?
+UpdateInvalid c:mainloop.c ?^UpdateInvalid()$?
+UpdateOtherWws c:insert2.c ?^UpdateOtherWws(fInval)$?
+UpdateRuler c:ruler.c ?^UpdateRuler()$?
+UpdateRulerBtn c:ruler.c ?^near UpdateRulerBtn(rlc, btn)$?
+UpdateWw c:disp.c ?^UpdateWw(ww, fAbortOK)$?
+ValidateHeaderFooter c:createww.c ?^ValidateHeaderFooter( doc )$?
+ValidateMemoryDC FORMAT.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*ValidateMemoryDC
+ValidateMemoryDC FORMAT.ASM /^ValidateMemoryDC
+ValidateMemoryDC c:form1.c ?^ValidateMemoryDC()$?
+ValidateTextBlt c:insert2.c ?^ValidateTextBlt()$?
+Visify c:mainloop.c ?^Visify(pch, pcch)$?
+WBroadcastMsg c:trans3.c ?^WBroadcastMsg( message, wParam, lParam, wStop )$?
+WCaseCp c:search.c ?^NEAR WCaseCp(cp,dcp)$?
+WCompSz c:util.c ?^WCompSz(psz1,psz2)$?
+WCompSzC c:open.c ?^WCompSzC(psz1,psz2)$?
+WCreateNewSzFfname DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*WCreateNewSzFfname
+WCreateSzFfname DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*WCreateSzFfname
+WDosVersion DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*WDosVersion
+WFromCh c:mw.h ?^#define WFromCh(ch) ((ch) - '0')$?
+WFromSzNumber c:fontenum.c ?^int WFromSzNumber( ppch )$?
+WHsecGetTime c:insert2.c ?^unsigned WHsecGetTime()$?
+WOpenSzFfname DOSLIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*WOpenSzFfname
+WPdxaFromItDxa2WId c:diasubs.c ?^WPdxaFromItDxa2WId(pdxa, hDlg, it, dxaMin, dxaMax,?
+WPwFromItW3Id c:diasubs.c ?^WPwFromItW3Id(pw, hDlg, it, wMin, wMax, wMask, id)?
+WPwFromItW3IdFUt c:diasubs.c ?^WPwFromItW3IdFUt(pw, hDlg, it, wMin, wMax, wMask, ?
+WaitBeforePostMsg c:diaalert.c ?^NEAR WaitBeforePostMsg(errlevel)$?
+WbFromCh c:select2.c ?^int WbFromCh(ch)$?
+WbFromKanjiChCh c:select2.c ?^int WbFromKanjiChCh(ch1, ch2)$?
+WinFailure c:diaalert.c ?^WinFailure()$?
+WinMain c:mmw.c ?^int PASCAL WinMain( hInstance, hPrevInstance, lpsz?
+WriteBftb c:transbuf.c ?^WriteBftb(fn)$?
+WriteDirtyPages c:transfer.c ?^WriteDirtyPages()$?
+WriteFfntb c:trans2.c ?^WriteFfntb(fn, hffntb)$?
+WriteRgch c:fileres.c ?^WriteRgch(fn, pch, cch)$?
+WriteStateInfo c:quit.c ?^WriteStateInfo()$?
+WriteUnformatted c:trans4.c ?^WriteUnformatted(fn, doc)$?
+WwAlloc c:wwactde.c ?^WwAlloc( hWnd, doc )$?
+WwNew c:createww.c ?^WwNew(doc, ypMin, ypMax)$?
+XaKickBackXa c:ruler.c ?^unsigned near XaKickBackXa(xa)$?
+XaQuantize c:ruler.c ?^unsigned near XaQuantize(xp)$?
+XaQuantizeXa c:ruler.c ?^unsigned near XaQuantizeXa(xa)$?
+XpKickBackXp c:ruler.c ?^near XpKickBackXp(xp)$?
+XpValidateInsertCache c:insert.c ?^int NEAR XpValidateInsertCache( rgdxp )$?
+ZaFromMm c:cmddefs.h ?^#define ZaFromMm(mm) (unsigned)MultDiv(mm, 1440?
+ZeroFtns c:edit.c ?^ZeroFtns(doc)$?
+_Assert c:util.c ?^_Assert(pch, line, f)$?
+_beep c:mouse.c ?^_beep()$?
+_malloc c:aaa.c ?^_malloc()$?
+beep c:mouse.c ?^beep()$?
+blt LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*blt
+bltbc LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltbc
+bltbcx LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltbcx
+bltbh c:clipbrd2.c ?^void bltbh(HPCH hpchFrom, HPCH hpchTo, int cch)$?
+bltbx LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltbx
+bltbx c:clipbrd2.c ?^#define bltbx(from,to,count) bltbh(from,to,c?
+bltbyte LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltbyte
+bltc LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltc
+bltcx LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltcx
+bltsz c:mw.h ?^#define bltsz(pFrom, pTo) CchCopySz((pFrom), (pTo)?
+bltszLimit c:mw.h ?^#define bltszLimit(pFrom, pTo, cchMax) \\$?
+bltszx c:mw.h ?^#define bltszx(lpFrom, lpTo) \\$?
+bltx LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*bltx
+cPageUnused c:heaprare.c ?^cPageUnused()$?
+dbgWait c:debug.c ?^dbgWait()$?
+dummy c:mainloop.c ?^dummy()$?
+fnCharBold c:chlook.c ?^void fnCharBold()$?
+fnCharItalic c:chlook.c ?^void fnCharItalic()$?
+fnCharOutline c:chlook.c ?^fnCharOutline()$?
+fnCharPlain c:chlook.c ?^void fnCharPlain()$?
+fnCharSelectFont c:menu.c ?^void NEAR fnCharSelectFont(iffn)$?
+fnCharShadow c:chlook.c ?^fnCharShadow()$?
+fnCharSmallcaps c:chlook.c ?^fnCharSmallcaps()$?
+fnCharSubscript c:chlook.c ?^void fnCharSubscript()$?
+fnCharSuperscript c:chlook.c ?^void fnCharSuperscript()$?
+fnCharUnderline c:chlook.c ?^void fnCharUnderline()$?
+fnClearEdit c:edit.c ?^fnClearEdit()$?
+fnCopyEdit c:clipbord.c ?^fnCopyEdit()$?
+fnCutEdit c:clipbord.c ?^fnCutEdit()$?
+fnEditDocument c:running.c ?^fnEditDocument()$?
+fnEditRunning c:running.c ?^fnEditRunning(imi)$?
+fnFindAgain c:search.c ?^fnFindAgain()$?
+fnFindText c:search.c ?^fnFindText()$?
+fnHelp c:help.c ?^fnHelp()$?
+fnMovePicture c:pictdrag.c ?^fnMovePicture()$?
+fnNewFile c:createww.c ?^fnNewFile()$?
+fnOpenFile c:trans3.c ?^fnOpenFile()$?
+fnParaCentered c:chlook.c ?^void fnParaCentered()$?
+fnParaDoublespace c:chlook.c ?^void fnParaDoublespace()$?
+fnParaJustified c:chlook.c ?^void fnParaJustified()$?
+fnParaLeft c:chlook.c ?^void fnParaLeft()$?
+fnParaNormal c:chlook.c ?^void fnParaNormal()$?
+fnParaOneandhalfspace c:chlook.c ?^void fnParaOneandhalfspace()$?
+fnParaOpenspace c:chlook.c ?^fnParaOpenspace()$?
+fnParaRight c:chlook.c ?^void fnParaRight()$?
+fnParaSinglespace c:chlook.c ?^void fnParaSinglespace()$?
+fnPasteEdit c:clipbord.c ?^fnPasteEdit()$?
+fnPrPrinter c:diaprint.c ?^fnPrPrinter()$?
+fnQuit c:quit.c ?^fnQuit(hWnd)$?
+fnRepaginate c:diarepag.c ?^fnRepaginate()$?
+fnReplaceText c:search.c ?^fnReplaceText()$?
+fnSave c:trans3.c ?^fnSave()$?
+fnSaveAs c:trans3.c ?^fnSaveAs()$?
+fnScribble c:util2.c ?^fnScribble( dchPos, ch )$?
+fnShowRuler c:ruler.c ?^fnShowRuler()$?
+fnSizePicture c:pictdrag.c ?^fnSizePicture()$?
+fnSpecial c:pageinfo.c ?^fnSpecial(hWnd, hDC, rgfp, sz)$?
+fnTest c:debug.c ?^fnTest()$?
+fnUndoEdit c:undo.c ?^fnUndoEdit()$?
+fnVisiMode c:chlook.c ?^fnVisiMode()$?
+for c:diapara.c ?^ for (ival = 0; ival <= 8; ival++)$?
+iabs c:mw.h ?^#define iabs(w) ((w) < 0 ? (-(w)) : (w))$?
+idiMsgResponse c:search.c ?^NEAR idiMsgResponse(hDlg, idi, idpmt)$?
+if c:diapara.c ?^ if (docRulerSprm != docNil) ClearRulerSprm();$?
+imax c:util.c ?^int imax( i1, i2 )$?
+imin c:util.c ?^int imin( i1, i2 )$?
+index c:util.c ?^CHAR *index(pch, ch)$?
+int c:\dev\inc\printer.h ?^typedef int (FAR * FARPROC)();$?
+isalnum c:util.c ?^isalnum(ch)$?
+isalpha c:util.c ?^isalpha(ch)$?
+isdigit c:util.c ?^isdigit(ch)$?
+islower c:util.c ?^islower(ch)$?
+isupper c:util.c ?^isupper(ch)$?
+low c:mw.h ?^#define low(ch) ((ch) & 0377)$?
+max c:\dev\inc\windows.h ?^#define max(a,b) ((a) > (b) ? (a) : (b))$?
+min c:\dev\inc\windows.h ?^#define min(a,b) ((a) < (b) ? (a) : (b))$?
+name MSSEQDS.ASM /^name
+ncvtu c:util2.c ?^int ncvtu(n, ppch)$?
+panic c:mw.h ?^#define panic() Assert(false)$?
+szFileExtract c:trans3.c ?^szFileExtract(szNormFileName, szExtFileName)$?
+toggleProf LIB.ASM /\[cC]\[pP]\[rR]\[oO]\[cC]\[ ]\[ ]\*toggleProf
+umax c:util.c ?^unsigned umax( w1, w2 )$?
+umin c:util.c ?^unsigned umin( w1, w2 )$?
+walign c:mw.h ?^#define walign(pb) {if ((unsigned)(pb) & 1) \\$?
diff --git a/private/mvdm/wow16/write/toolbox.h b/private/mvdm/wow16/write/toolbox.h
new file mode 100644
index 000000000..db7373303
--- /dev/null
+++ b/private/mvdm/wow16/write/toolbox.h
@@ -0,0 +1,35 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* extracted from original toolbox.h */
+
+#define srcCopy 0 /* Destination = Source */
+#define srcOr 1 /* Destination = Source OR Destination */
+#define srcXor 2 /* Destination = Source XOR Destination */
+#define srcBic 3 /* Destination = Source BIC Destination */
+#define notSrcCopy 4 /* Destination = NOT(Source) */
+#define notSrcOr 5 /* Destination = NOT(Source) OR Dest */
+#define notSrcXor 6 /* Destination = NOT(Source) XOR Dest */
+#define notSrcBic 7 /* Destination = NOT(Source) BIC Dest */
+#define patCopy 8 /* Destination = Pattern */
+#define patOr 9 /* Destination = Pattern OR Dest */
+#define patXor 10 /* Destination = Pattern XOR Dest */
+#define patBic 11 /* Destination = Pattern BIC Dest */
+#define notPatCopy 12 /* Destination = NOT(Pattern) */
+#define notPatOr 13 /* Destination = NOT(Pattern) OR Dest */
+#define notPatXor 14 /* Destination = NOT(Pattern) XOR Dest */
+#define notPatBic 15 /* Destination = NOT(Pattern) BIC Dest */
+
+typedef int *WORDPTR;
+typedef WORDPTR WINDOWPTR;
+typedef WORDPTR MENUHANDLE;
+typedef HANDLE RGNHANDLE;
+typedef HANDLE CTRLHANDLE;
+
+typedef struct {
+ int ascent;
+ int descent;
+ int widMax;
+ int leading;
+} FONTINFO;
diff --git a/private/mvdm/wow16/write/trans2.c b/private/mvdm/wow16/write/trans2.c
new file mode 100644
index 000000000..d1f863ca2
--- /dev/null
+++ b/private/mvdm/wow16/write/trans2.c
@@ -0,0 +1,1949 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* trans2.c -- Save routines for WRITE (also see trans4.c; routines were
+ moved because of compiler heap overflows) */
+
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+//#define NOATOM
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+//#define NOGDI
+//#define NOMETAFILE
+#define NOBRUSH
+#define NOPEN
+#define NOFONT
+#define NOWNDCLASS
+#define NOWH
+#define NOWINOFFSETS
+#define NOICON
+#define NOCOMM
+#define NOSOUND
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "propdefs.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "printdef.h"
+#include "code.h"
+#include "heapdefs.h"
+#include "heapdata.h"
+#define NOSTRUNDO
+#include "str.h"
+#include "debug.h"
+#include "fontdefs.h"
+#include "obj.h"
+#include "winddefs.h"
+
+CHAR *PchGetPn();
+CHAR *PchFromFc();
+typePN PnAlloc();
+struct PGTB **HpgtbGet();
+
+#ifdef DEBUG
+ /* Make these variables during debug so testers can force limits */
+typeFC fcBound = (pnMaxScratch >> 2) * ((typeFC)cbSector);
+int cpBound = 512;
+#else
+#define fcBound ((typeFC) ((pnMaxScratch >> 2) * ((typeFC)cbSector)))
+#define cpBound (512)
+#endif
+
+extern CHAR *PchFillPchId();
+
+extern int vfOldWriteFmt; /* delete objects before saving */
+extern HANDLE hParentWw;
+extern int vfnWriting;
+extern struct BPS *mpibpbps;
+extern typeTS tsMruBps;
+extern int vibpWriting;
+extern CHAR (**vhrgbSave)[];
+extern struct DOD (**hpdocdod)[];
+extern int docCur;
+extern int docMac;
+extern int docScrap;
+extern int docUndo;
+extern struct FCB (**hpfnfcb)[];
+extern int fnMac;
+extern int wwMac;
+/* extern ENV vEnvMainLoop; */
+extern int vfBuffersDirty;
+extern int vfDiskFull;
+extern int vfDiskError;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeFC fcMacPapIns;
+extern typeFC fcMacChpIns;
+extern typeCP vcpLimParaCache;
+extern struct FKPD vfkpdCharIns;
+extern struct FKPD vfkpdParaIns;
+extern struct PAP vpapPrevIns;
+extern struct PAP vpapAbs;
+extern struct PAP *vppapNormal;
+extern struct CHP vchpNormal;
+extern struct CHP vchpInsert;
+extern struct CHP vchpFetch;
+extern struct FPRM fprmCache;
+extern HCURSOR vhcIBeam;
+
+extern int ferror;
+extern CHAR szExtBackup[]; /* extension for Write backup files */
+extern CHAR szExtWordBak[]; /* extension for Word backup files */
+extern CHAR (**hszTemp)[];
+extern CHAR szExtDoc[];
+
+
+#ifdef INTL /* International version */
+
+extern int vfTextOnlySave;
+extern int vWordFmtMode; /* used during saves. If false, no conversion is
+ done. True is convert to Word format,CVTFROMWORD
+ is translate chars from Word character set at
+ save */
+#endif /* International version */
+
+
+
+
+/*** CmdXfSave - Save document to passed filename (TRANSFER SAVE)
+ *
+ * ENTRY: szFile - a normalized filename
+ * fFormatted - TRUE = save as formatted file
+ * FALSE = save as unformatted file
+ * fBackup - TRUE = keep a backup copy of the file
+ * FALSE = don't (but see below)
+ *
+ * EXIT:
+ *
+ * NOTE: A backup file may be kept even if fBackup is FALSE.
+ * This is because piece tables in documents other than docCur
+ * may refer to the information. If a backup file is kept for
+ * this reason, the following holds: (1) The file has an fn,
+ * (2) the file's hpfnfcb entry has its fDelete field set to TRUE,
+ * indicating that the file should be deleted when WORD exits,
+ * (3) the file is, in fact, referenced in some document
+ * (PurgeTemps assures that unreferenced files are deleted)
+ *
+ * Note 2: Non-formatted save code modified (bz 12/2/85) to allow
+ * similar saving in Word format. The calls to FnCreate and
+ * FWriteFn were changed to allow for formatted saving, but
+ * FWriteFn is changed to convert text from ANSI to OEM character
+ * sets, to not put out the font table and to mark
+ * the file header (fib) so the file will be treated as a Word
+ * file, but, like a non-formatted save, the piece table is not
+ * cleaned up. Note that the backup file is saved in the original,
+ * Write format.
+ *
+ */
+
+CmdXfSave(szFile, fFormatted, fBackup, hcAfterward)
+CHAR szFile[];
+int fFormatted;
+int fBackup;
+HCURSOR hcAfterward; /* handle to cursor to display after hourglass */
+{
+ extern int vfnSaving; /* Set this so we prompt for "Write Save File"
+ if disk change is necessary */
+ extern int vfDiskError;
+ extern int vfSysFull;
+ extern int vfOutOfMemory;
+
+ int fSave = vfDiskError;
+ int fDidBackup;
+ CHAR szFileT [cchMaxFile];
+ int fOutOfMemory=vfOutOfMemory;
+ int docTemp;
+
+ /* Make a local copy of string parm in case it is in the heap */
+
+#ifdef DFILE
+ CommSzSz("CmdXfSave----szFile (presumed ANSI) ", szFile);
+#endif
+ StartLongOp();
+ bltsz( szFile, szFileT );
+ szFileT[ cchMaxFile - 1] = '\0';
+
+ /* Reset error conditions to give us a chance */
+
+ vfOutOfMemory = vfDiskFull = vfSysFull = vfDiskError = ferror = FALSE;
+
+ SetRfnMac( rfnMacSave ); /* Increase # of DOS handles used to speed save */
+
+ /* Memory kludge: To assure that we can actually save this file under low
+ memory conditions, free the bogus heap block */
+ if (vhrgbSave != 0)
+ {
+ FreeH(vhrgbSave); /* Return this memory to free pool. */
+ vhrgbSave = 0;
+ }
+ /* In-Line version of FreeBitmapCache (so we don't have to swap in
+ picture.c) */
+
+ /*FreeBitmapCache(); */ /* Give us even more memory */
+
+ {
+ extern int vdocBitmapCache;
+ extern HBITMAP vhbmBitmapCache;
+
+ vdocBitmapCache = docNil;
+ if (vhbmBitmapCache != NULL)
+ {
+ DeleteObject( vhbmBitmapCache );
+ vhbmBitmapCache = NULL;
+ }
+ }
+
+
+ /* Can't undo save -- set "Can't Undo"; also clear out docUndo
+ for heap space reclamation and to aid PurgeTemps */
+
+ ClobberDoc(docUndo, docNil, cp0, cp0);
+ NoUndo();
+
+ (**hpdocdod)[docCur].fBackup = fBackup;
+
+ /* Note: Non-formatted save code modified (bz 12/2/85) to allow
+ * similar saving in Word format. The calls to FnCreate and
+ * FWriteFn were changed to allow for formatted saving, but
+ * FWriteFn is changed to convert text from ANSI to OEM character
+ * sets, to not put out the font table and to mark
+ * the file header (fib) so the file will be treated as a Word
+ * file, but, like a non-formatted save, the piece table is not
+ * cleaned up. Note that the backup file is saved in the original,
+ * Write format.
+ * Note that a file CAN be saved both unformatted and in Word format
+ * - in that case, Word format means convert to OEM character set.
+ */
+
+#if defined(OLE)
+ ObjSavingDoc(fFormatted);
+#endif
+
+ if (((**hpdocdod)[docCur].fFormatted && !fFormatted)
+#ifdef INTL /* International version */
+ || (vWordFmtMode == TRUE) /* convert To Word format? */
+#endif /* International version */
+ || (vfOldWriteFmt))
+ {
+
+ int fn;
+ CHAR (**hsz)[];
+ CHAR szT [cchMaxFile];
+ CHAR szWriteFile [cchMaxFile];
+ CHAR szBak [cchMaxFile];
+
+ /* Set szFileT's path name into szWriteFile, so the temp file
+ gets created in the right place when we call FnCreateSz */
+ SplitSzFilename( szFileT, szWriteFile, szT );
+
+ /* Create szWrite: a new, uniquely named file */
+ if ((fn=FnCreateSz( szWriteFile,
+ fFormatted?(**hpdocdod)[docCur].cpMac:cpNil,
+ dtyNetwork ))==fnNil)
+ /* Couldn't create the write file */
+ goto SaveDone;
+ /* Make backup of szFileT (if it exists); purge all unneeded backups
+ which were kept for their pieces but are no longer referenced */
+ fDidBackup = FBackupSzFile( szFileT, fBackup, szBak );
+ if (ferror)
+ goto LXFRet; /* Backup failed */
+
+ PurgeTemps();
+
+ vfnSaving = fn;
+
+ /* ForcePmt(IDPMTSaving);*/
+
+#ifdef INTL /* International version */
+
+ if ((vWordFmtMode == TRUE) /* converting To Word format? */
+ || (vfTextOnlySave == TRUE) /* converting To Text format? */
+ || (vfOldWriteFmt))
+ /* Delete all pictures. To do this, make a copy
+ of docCur in docTemp, the go through docTemp, deleting all picture
+ paragraphs. Write out this document, then kill it. */
+ {
+ extern typeCP vcpLimParaCache, vcpFirstParaCache;
+ extern typeCP cpMinCur, cpMacCur, cpMinDocument;
+ typeCP cpMinCurT = cpMinCur;
+ typeCP cpMacCurT = cpMacCur;
+ typeCP cpMinDocumentT = cpMinDocument;
+ typeCP cpNow;
+ typeCP cpLimPara, dcp;
+ typeCP cpMac = (**hpdocdod) [docCur].cpMac;
+
+ /* Create copy of document */
+ docTemp = DocCreate(fnNil, HszCreate(""), dtyNormal);
+ if (docTemp == docNil)
+ goto SaveDone; /* Out of memory */
+ ClobberDoc(docTemp, docCur, cp0, CpMacText(docCur));
+ if (ferror)
+ return TRUE;
+
+ /* Expand range of interest to whole document (for CachePara) */
+
+ cpMinCur = cp0;
+ cpMacCur = cpMac;
+
+ /* Loop on paras */
+
+ for ( cpNow = cp0; cpNow < cpMac; cpNow = cpLimPara )
+ {
+ CachePara( docTemp, cpNow );
+ if (!vpapAbs.fGraphics)
+ /* update to next cplim only if not deleting. If deleting,
+ next time will be at same cp */
+ {
+ cpLimPara = vcpLimParaCache;
+ continue;
+ }
+
+ /* Now delete graphics paragraph */
+ Replace(docTemp, vcpFirstParaCache,
+ dcp = (vcpLimParaCache - vcpFirstParaCache),
+ fnNil, fc0, fc0);
+ cpMac -= dcp; /* size of doc has been reduced */
+ }
+
+ /* Restore cpMinCur, cpMacCur */
+
+ cpMinCur = cpMinCurT;
+ cpMacCur = cpMacCurT;
+ /* destroyed possibly by DocCreate */
+ cpMinDocument = cpMinDocumentT;
+ vcObjects = 0; // OLE object count
+ }
+ else
+#endif /* International version */
+
+ {
+ docTemp = docCur; // note the else, above #endif (2.7.91) D. Kent
+ }
+
+ if (FWriteFn(fn, docTemp, fFormatted))
+ {
+ int fpe = FpeRenameFile( szWriteFile, szFileT );
+
+ if ( FIsErrFpe( fpe ) )
+ { /* Rename failed -- might be nonexistent path */
+ Error( (fpe == fpeBadPathError) ? IDPMTNoPath : IDPMTSDE2 );
+ }
+ else
+ OutSaved(docTemp);
+
+ }
+ else
+ { /* Write failed */
+ if (fDidBackup && !FIsErrFpe(FpeRenameFile(szBak, szFileT)))
+ {
+ int fn = FnFromSz(szFileT);
+ struct FCB *pfcb;
+ if (fn != fnNil)
+ {
+ (pfcb = &(**hpfnfcb)[fn])->fDelete = false;
+ }
+ }
+ FDeleteFn( fn );
+ }
+
+
+#ifdef INTL /* International version */
+ if (vWordFmtMode == TRUE) /* converting To Word format? */
+ KillDoc (docTemp);
+#endif /* International version */
+
+
+ (**hpdocdod)[docCur].fDirty = false; /* document should not
+ be dirty after T-S.*/
+ FreeH((**hpdocdod)[docCur].hszFile);
+ hsz = HszCreate((PCH)szFileT);
+ (**hpdocdod)[docCur].hszFile = hsz;
+ }
+else
+ { /* Save Formatted document */
+ CleanDoc( docCur, (**hpdocdod)[docCur].dty, szFileT, fFormatted, fBackup );
+ }
+
+ OpenEveryHardFn(); /* Reopen files on nonremoveable media so other net
+ users can't steal them away */
+
+SaveDone:
+
+ SetRfnMac( rfnMacEdit ); /* Reduce # of file handles used */
+ vfnSaving = fnNil;
+
+#ifdef NEVER
+ /* It doesn't do us much good to Assert here that an error didn't happen.
+ After-the-fact checking doesn't make up for ignoring real-time errors.
+ ..pault 10/31/89 */
+
+ Assert( !vfOutOfMemory ); /* Our reserved space block was sufficient
+ to get us through the save */
+#endif
+ vfOutOfMemory = fOutOfMemory;
+
+/* vhrgbSave is a pointer a clump on the heap used during the save operation.
+ By freeing it in the beginning of the save operation, we are assured
+ that we will have enough memory to actually do the save.
+ At the present point
+ in the code, we are finished with the save and wish to reclaim vhrgbSave
+ so the next Save operation may perform properly. The net memory usage
+ caused by a save should be minimal. It only temporarily requires a
+ significant chunk of memory. */
+ vhrgbSave = (CHAR (**)[]) HAllocate( cwSaveAlloc +
+ ( (wwMac-1) * cwHeapMinPerWindow ));
+
+/* Restore previous disk err state */
+
+#if WINVER >= 0x300
+ /* We currently have no way to FORGET they had a disk error.
+ So if this whole operation did not have an error and we
+ felt there was one beforehand, we do it now ..pault */
+ vfDiskError = (!vfDiskError && fSave) ? fFalse : fSave;
+#else
+ vfDiskError = fSave;
+#endif
+
+LXFRet:
+ EndLongOp(hcAfterward);
+}
+
+
+
+
+CleanDoc(doc, dty, szFile, fFormatted, fBackup )
+int doc, fFormatted;
+int dty;
+CHAR szFile[];
+int fBackup;
+{ /* Write the contents of doc into szFile and clean up piece table */
+ /* if dty == dtyNetwork, writes the doc to a unique file & returns the */
+ /* filename through szFile */
+ /* Returns the fn of the file it wrote to */
+
+/* *************************************
+ In the normal backup processing, we rename the existing file. When
+ saving in CONVFROMWORD mode, we want to keep the original Word file around,
+ so we bypass the backup phase and then skip the renaming phase below.
+ This leaves the original file around. At save time we may write over it
+ or rename the saving file, as we wish, but this way we have the Word file
+ around in case we don't save out of Write.
+************************************** */
+
+extern int vdocParaCache;
+extern int vfnSaving; /* Set this so we prompt for "Save" disk if disk
+ changes are necessary */
+int fDidBackup=FALSE;
+int fn;
+CHAR (**hsz)[];
+
+CHAR szBak [cchMaxFile];
+CHAR szWrite [cchMaxFile];
+int fDummy;
+
+#if WINVER >= 0x300
+/* I don't understand WHY the following resets to ROOT directory, but
+ changing it causes problems -- so I'm leaving it! Obviously code
+ somewhere else expects file to be there and I don't see it ..pault */
+#endif
+ /* Set path name of szFile into szWrite so the temp file gets created
+ in the right place */
+ if (dty == dtyNetwork)
+ {
+ szWrite [0] = '\0'; /* Create temp file on Temp drive in the root */
+ }
+ else
+ {
+ CHAR szT [cchMaxFile];
+
+ SplitSzFilename( szFile, szWrite, szT );
+ }
+
+ /* Create szWrite: a new, uniquely named file */
+ if ((fn=FnCreateSz( szWrite, fFormatted ? (**hpdocdod)[doc].cpMac : cpNil,
+ dtyNetwork )) == fnNil)
+ /* Couldn't create the write file */
+ return fnNil;
+
+ vfnSaving = fn;
+
+/* *************************************
+ In the normal backup processing, we rename the existing file. When
+ saving in CONVFROMWORD mode, we want to keep the original Word file around,
+ so we bypass the backup phase and then skip the renaming phase below.
+ This leaves the original file around. At save time we may write over it
+ or rename the saving file, as we wish, but this way we have the Word file
+ around in case we don't save out of Write.
+************************************** */
+
+ if (doc != docScrap)
+ {
+ /* Make a backup of szFile (if szFile exists) */
+
+#ifdef INTL /* International version */
+ if (vWordFmtMode == CONVFROMWORD) /* converting from a Word document */
+ fDidBackup = false;
+ else
+#endif /* International version */
+ {
+ fDidBackup = FBackupSzFile( szFile, fBackup, szBak );
+ if (ferror)
+ return; /* Backup failed */
+ }
+
+ PurgeTemps();
+
+ }
+
+ if ( dty == dtyNetwork )
+ bltsz( szWrite, szFile );
+
+ if (!FWriteFn(fn, doc, fFormatted))
+ { /* Save failed; rename backup file back to original */
+ /* note in intl CONVFROMWORD case, fDidBackup will be false
+ and this renaming won't happen, which is ok */
+ if (fDidBackup && !FIsErrFpe(FpeRenameFile(szBak, szFile)))
+ {
+ int fn = FnFromSz(szFile);
+ struct FCB *pfcb;
+ if (fn != fnNil)
+ {
+ (pfcb = &(**hpfnfcb)[fn])->fDelete = false;
+ }
+ }
+ FDeleteFn( fn );
+ return fnNil; /* Disk full or write error */
+ }
+
+/* *************************************
+ Here we rename our temp file szWrite to have the name of the "save as"
+ file. In FBackupSzFile, the fdelete flag for the fn of szfile was set
+ on so we don't have to explicitly delete the original file.
+
+ When a CONVFROMWORD save is done, we do not rename and did not go
+ through the backup procedure, so the original Word file is still
+ out there with its original name. We do, however, set the delete bit to
+ true, so the file will get deleted after the next save, when a true rename
+ will be done.
+************************************** */
+
+ if ( dty != dtyNetwork )
+
+#ifdef INTL /* International version */
+ if (vWordFmtMode == CONVFROMWORD) /* converting from a Word document */
+ {
+ (**hpfnfcb)[fn].fDelete = true;
+ }
+ else
+#endif /* International version */
+
+ {
+ int fpe=FpeRenameFile( szWrite, szFile );
+
+ if (FIsErrFpe( fpe ))
+ {
+ Error( (fpe == fpeBadPathError) ? IDPMTNoPath : IDPMTSDE2 );
+ return fnNil;
+ }
+ }
+
+if (doc == docScrap)
+ (**hpfnfcb)[fn].fDelete = true;
+else
+ OutSaved(doc);
+
+FreeH((**hpdocdod)[doc].hpctb); /* Free old piece table */
+FInitPctb(doc, fn);
+(**hpdocdod)[doc].fFormatted = fFormatted;
+FreeH((**hpdocdod)[doc].hszFile);
+hsz = HszCreate((PCH)szFile);
+(**hpdocdod)[doc].hszFile = hsz;
+
+if (fFormatted)
+ {
+ /* reload font table, which may have changed */
+
+ SmashDocFce(doc);
+ FreeFfntb(HffntbGet(doc));
+ (**hpdocdod)[doc].hffntb = HffntbCreateForFn(fn, &fDummy);
+ //SaveFontProfile(doc);
+ ResetDefaultFonts(FALSE);
+ }
+
+ /* By diddling the document attributes on save, we have invalidated caches */
+
+ InvalidateCaches( doc );
+ vdocParaCache = docNil;
+
+ if (!ferror && !vfBuffersDirty && doc != docScrap)
+ ReduceFnScratchFn( fn );
+
+ if (fFormatted)
+ { /* Readjust the running head margins. We munged them back to the
+ paper-relative measurements in FWriteFn, so we'll remunge them
+ to margin-relative here. */
+
+ /* With the test for doc != docScrap we fix a major bug, and knowingly at the
+ last minute introduce a minor one. The old problem was that we would apply
+ a sprm to docScrap, then mash the scratch file in ReduceFnScratch, our
+ caller, rendering the bfprm bogus, causing rare crashes. The new problem
+ will be that running head text in the scrap will have incorrect margins
+ after a save. */
+
+ if (doc != docScrap)
+ ApplyRHMarginSprm( doc );
+ InvalidateCaches( doc );
+ vdocParaCache = docNil;
+ }
+
+ return fn;
+}
+
+
+
+
+
+/*** FWriteFn - write a file
+ *
+ * Note: Modified (bz 12/2/85) to allow saving in Word format.
+ * FWriteFn is changed to convert text from ANSI to OEM character
+ * sets, to not put out the font table and to mark
+ * the file header (fib) so the file will be treated as a Word
+ * file.
+ *
+ */
+
+int FWriteFn(fn, doc, fFormatted)
+int fn, doc, fFormatted;
+{ /* Write characters from a doc to fn */
+/* Return true if successful */
+#ifdef CASHMERE
+extern int docBuffer;
+#endif
+
+typeCP cpMac;
+CHAR *pchFprop;
+struct RUN *prun;
+struct FIB *pfib;
+struct FCB *pfcb;
+int cchT;
+struct FNTB **hfntb;
+struct FFNTB **hffntb=(struct FFNTB **)NULL;
+
+#ifdef CASHMERE
+struct SETB **hsetb = 0, **hsetbT;
+#else
+struct SEP **hsep;
+#endif
+
+struct PGTB **hpgtb;
+int ised, csed;
+struct SED *psed, *psedT;
+int cw;
+int fFileFlushed;
+int rfn;
+CHAR mpftcftc[iffnMax];
+
+struct PAP pap;
+struct CHP chp;
+struct FKP fkp;
+
+vfnWriting = fn;
+vibpWriting = IbpEnsureValid(fn, (typePN)0);
+
+cpMac = (**hpdocdod)[doc].cpMac;
+
+/* FIB has already been written. */
+if (fFormatted)
+ {
+
+/* KLUDGE: If the doc does not contain at least one complete para,
+ and it has a nonnull tab table,
+ add an Eol to its end to hold the tabs in a FPAP */
+
+ CachePara( doc, cp0 );
+ if (vcpLimParaCache > cpMac && (doc != docScrap) &&
+ (**hpdocdod) [doc].hgtbd != NULL )
+ {
+ extern int vdocParaCache;
+
+ InsertEolInsert( doc, cpMac );
+ vdocParaCache = docNil;
+ cpMac = (**hpdocdod) [doc].cpMac;
+ }
+
+ /* Write characters */
+ /* Modified to handle ANSI to OEM conversion for Word docs */
+ FetchCp(doc, cp0, 0, fcmChars + fcmNoExpand);
+
+ {
+ Scribble(4, 'T');
+
+ while (vcpFetch < cpMac && !(vfDiskFull || vfDiskError))
+ {
+#ifdef INTL /* International version */
+
+ if (vWordFmtMode == FALSE) /* no conversion */
+#endif /* International version */
+
+ WriteRgch(fn, vpchFetch, (int)vccpFetch);
+
+#ifdef INTL /* International version */
+ else
+ {
+ /* bufT is a buffer for translating from ANSI to
+ OEM chars. The amount of data from FetchCp
+ must be no > than a disk page, which is
+ cfcFetch, which is itself cbSector. We use
+ bufT to hold the translated chars, then write
+ them out with WriteRgch. */
+
+ CHAR bufT[cbSector + 1];
+ CHAR *pch;
+
+ Assert ((int)vccpFetch <= cbSector);
+ /* load chars into bufT and translate to OEM
+ chars, and write out */
+ pch = (CHAR *) bltbyte(vpchFetch, bufT,
+ (int)vccpFetch);
+ *pch = '\0';
+ if (vWordFmtMode == TRUE)
+ /* from Write/ANSI to Word/OEM */
+ AnsiToOem((LPSTR)bufT, (LPSTR)bufT);
+ else
+ /* from Word/OEM to Write/ANSI */
+ OemToAnsi((LPSTR)bufT, (LPSTR)bufT);
+ WriteRgch(fn, bufT, (int)vccpFetch);
+ }
+#endif /* International version */
+
+
+ FetchCp(docNil, cpNil, 0, fcmChars + fcmNoExpand);
+ }
+ Scribble(4,' ');
+ }
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Go to beginning of next page */
+ AlignFn(fn, cbSector, false);
+ (**hpfnfcb)[fn].pnChar = (**hpfnfcb)[fn].pnMac;
+
+ /* Now write char props */
+ Scribble(4, 'C');
+ fkp.fcFirst = cfcPage; /* first fkp starts with first valid fc */
+ fkp.crun = 0;
+ prun = (struct RUN *) fkp.rgb;
+ pchFprop = &fkp.rgb[cbFkp];
+ CachePara(doc, cp0);
+
+ /* set up font mapping and new font table */
+ if (!FInitMapSave(doc, &hffntb, mpftcftc))
+ goto AbortWrite;
+
+ FetchCp(doc, cp0, 0, fcmProps);
+ if (!FMapFtcSave(doc, hffntb, &vchpFetch, mpftcftc))
+ goto AbortWrite;
+
+ blt(&vchpFetch, &chp, cwCHP);
+
+ while (vcpFetch < cpMac && !(vfDiskFull || vfDiskError))
+ { /* This could be optimized by allowing multiple runs to point */
+ /* to one fchp. */
+
+ if (CchDiffer(&vchpFetch, &chp, cchCHP) != 0)
+ {
+ FAddRun(fn, &fkp, &pchFprop, &prun, &chp,
+ &vchpNormal, cchCHP, vcpFetch + cfcPage);
+ blt(&vchpFetch, &chp, cwCHP);
+ }
+ FetchCp(docNil, cpNil, 0, fcmProps);
+ if (!FMapFtcSave(doc, hffntb, &vchpFetch, mpftcftc))
+ goto AbortWrite;
+ }
+ Scribble(4,' ');
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Write out last char run. */
+ FAddRun(fn, &fkp, &pchFprop, &prun, &chp, &vchpNormal,
+ cchCHP, cpMac + cfcPage);
+ WriteRgch(fn, &fkp, cbSector);
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Now write para runs; one for every para */
+ Scribble(4,'C');
+ (**hpfnfcb)[fn].pnPara = (**hpfnfcb)[fn].pnMac;
+ fkp.fcFirst = cfcPage; /* first fkp starts with first valid fc */
+ fkp.crun = 0;
+ prun = (struct RUN *) fkp.rgb;
+ pchFprop = &fkp.rgb[cbFkp];
+ CachePara(doc, cp0);
+
+ /* KLUDGE: We have running head indents relative to the
+ margins -- subtract out the margins now, because
+ our (WORD-compatible) file format is PAPER-relative */
+
+ if (vpapAbs.rhc)
+ {
+ struct SEP *psep = *(**hpdocdod)[ doc ].hsep;
+
+ vpapAbs.dxaLeft += psep->xaLeft;
+ vpapAbs.dxaRight += psep->xaMac -
+ (psep->xaLeft + psep->dxaText);
+ }
+
+#ifdef INTL
+ /* Ensure no pictures in Word documents. This is necessary
+ because Word 4.0 uses the fGraphics bit as part of the
+ new border type code (btc) property. */
+ if (vWordFmtMode == CONVFROMWORD)
+ vpapAbs.fGraphics = FALSE;
+#endif
+ FAddRun(fn, &fkp, &pchFprop, &prun, &vpapAbs, vppapNormal,
+ cchPAP, vcpLimParaCache + cfcPage);
+ blt(&vpapAbs, &pap, cwPAP);
+
+ while (vcpLimParaCache <= cpMac && !(vfDiskFull || vfDiskError))
+ {
+ CachePara(doc, vcpLimParaCache);
+
+ /* KLUDGE: We have running head indents relative to the
+ margins -- subtract out the margins now, because
+ our (WORD-compatible) file format is PAPER-relative */
+
+ if (vpapAbs.rhc)
+ {
+ struct SEP *psep = *(**hpdocdod)[ doc ].hsep;
+
+ vpapAbs.dxaLeft += psep->xaLeft;
+ vpapAbs.dxaRight += psep->xaMac -
+ (psep->xaLeft + psep->dxaText);
+ }
+#ifdef INTL
+ /* Ensure no pictures in Word documents. This is necessary
+ because Word 4.0 uses the fGraphics bit as part of the
+ new border type code (btc) property. */
+ if (vWordFmtMode == CONVFROMWORD)
+ vpapAbs.fGraphics = FALSE;
+#endif
+#ifdef BOGUS
+ /* this would have erased all tab setting if saving back a Word document */
+
+ /* For MEMO: the only tabs we write are in the first para run;
+ override all other tab tables to keep files compact */
+ if (vpapAbs.rgtbd [0].dxa != 0)
+ bltc( vpapAbs.rgtbd, 0, cwTBD * itbdMax );
+#endif
+ FAddRun(fn, &fkp, &pchFprop, &prun, &vpapAbs, vppapNormal,
+ FParaEq( &vpapAbs, &pap ) ? -cchPAP : cchPAP,
+ vcpLimParaCache + cfcPage);
+ blt(&vpapAbs, &pap, cwPAP);
+ }
+ WriteRgch(fn, &fkp, cbSector);
+ Scribble(4,' ');
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Output footnote table */
+ Scribble(4,'F');
+ (**hpfnfcb)[fn].pnFntb = (**hpfnfcb)[fn].pnMac;
+
+#ifdef FOOTNOTES /* In MEMO, we NEVER write a footnote table */
+ if ((hfntb = HfntbGet(doc)) != 0)
+ {
+ WriteRgch(fn, *hfntb,
+ ((**hfntb).cfnd * cwFND + cwFNTBBase) * sizeof (int));
+ AlignFn(fn, cbSector, false);
+ }
+
+ Scribble(4,' ');
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+#endif /* FOOTNOTES */
+
+#ifdef CASHMERE /* Output section properties, table from hsetb */
+ /* Output section properties */
+ Scribble(4,'S');
+ (**hpfnfcb)[fn].pnSep = (**hpfnfcb)[fn].pnMac;
+ if ((hsetb = HsetbGet(doc)) != 0)
+ { /* Write out section props */
+ cw = cwSETBBase + (**hsetb).csedMax * cwSED;
+ csed = (**hsetb).csed;
+ hsetbT = (struct SETB **) HAllocate(cw);
+ if (FNoHeap(hsetbT))
+ return false; /* SHOULD REALLY GOTO ABORTWRITE */
+ blt(*hsetb, *hsetbT, cw);
+ FreezeHp();
+ for (psed = &(**hsetb).rgsed[0], psedT = &(**hsetbT).rgsed[0],
+ ised = 0;
+ ised < csed; psed++, psedT++, ised++)
+ if (psed->fc != fcNil)
+ { /* Copy props to file and update setb */
+ int cch;
+ pchFprop = PchFromFc(psed->fn, psed->fc, &cch);
+ Assert(cch >= *pchFprop + 1);
+ psedT->fn = fn;
+ AlignFn(fn, cch = *pchFprop + 1, false);
+ psedT->fc = (**hpfnfcb)[fn].fcMac;
+ WriteRgch(fn, pchFprop, cch);
+ }
+ MeltHp();
+ AlignFn(fn, cbSector, false);
+ }
+
+ Scribble(4,' ');
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Output section table */
+ (**hpfnfcb)[fn].pnSetb = (**hpfnfcb)[fn].pnMac;
+ if (hsetb != 0)
+ {
+ if (csed != 1 || (**hsetb).rgsed[0].fc != fcNil)
+ {
+ WriteRgch(fn, *hsetbT,
+ ((**hsetb).csed * cwSED + cwSETBBase) * sizeof (int));
+ AlignFn(fn, cbSector, false);
+ }
+ }
+#else /* MEMO VERSION: Write out a section table, 1 element long,
+ if we had nonstandard section properties */
+ {
+ typeFC fcSect;
+
+ /* Output section properties */
+ fcSect = (long)( cfcPage *
+ ((**hpfnfcb)[fn].pnSep = (**hpfnfcb)[fn].pnMac));
+
+ if ((hsep = (**hpdocdod)[doc].hsep) != 0)
+ {
+ struct {
+ CHAR cch;
+ struct SEP sep;
+ } fsep;
+ fsep.cch = cchSEP;
+ blt( *hsep, &fsep.sep, cwSEP );
+ WriteRgch( fn, &fsep, sizeof( fsep ) );
+ AlignFn( fn, cbSector, false );
+ }
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Output section table */
+ (**hpfnfcb)[fn].pnSetb = (**hpfnfcb)[fn].pnMac;
+ if (hsep != 0)
+ { /* Section table has 1 real + 1 dummy entry with cp==cpMac+1
+ This duplicates the output of PC Word 1.15 */
+ struct {
+ int csed;
+ int csedMax;
+ struct SED rgsed [2];
+ } setb;
+
+ setb.csed = setb.csedMax = 2;
+ setb.rgsed [1].cp = 1 +
+ (setb.rgsed [0].cp = (**hpdocdod)[doc].cpMac);
+ setb.rgsed [0].fn = fn;
+ setb.rgsed [0].fc = fcSect;
+ setb.rgsed [1].fn = fnNil;
+ setb.rgsed [1].fc = fcNil;
+
+ WriteRgch( fn, &setb, sizeof( setb ) );
+ AlignFn( fn, cbSector, false );
+ }
+ }
+#endif /* not CASHMERE */
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Output buffer or page table */
+ (**hpfnfcb)[fn].pnBftb = (**hpfnfcb)[fn].pnMac;
+
+#ifdef CASHMERE /* No docBuffer in WRITE */
+ if(doc == docBuffer)
+ {
+ WriteBftb(fn);
+ AlignFn(fn, cbSector, false);
+ }
+ else
+#endif
+ if ((hpgtb = HpgtbGet(doc)) != 0)
+ {
+ WriteRgch(fn, *hpgtb,
+ ((**hpgtb).cpgd * cwPGD + cwPgtbBase) * sizeof (int));
+ AlignFn(fn, cbSector, false);
+ }
+
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+
+ /* Output font table */
+
+#ifdef INTL /* International version */
+
+ /* no font table if saving in Word format */
+ if (vWordFmtMode != TRUE) /* no conv or conv from word */
+#endif /* International version */
+
+ {
+ Scribble(4,'N');
+ (**hpfnfcb)[fn].pnFfntb = (**hpfnfcb)[fn].pnMac;
+ WriteFfntb(fn, hffntb); /* hffntb gets freed below */
+ AlignFn(fn, cbSector, false);
+
+ Scribble(4,' ');
+ if ((vfDiskFull || vfDiskError))
+ goto AbortWrite;
+ }
+
+ /* Now update FIB at beginning of file */
+ pfib = (struct FIB *) PchGetPn(fn, pn0, &cchT, true);
+ pfib->pnPara = (pfcb = &(**hpfnfcb)[fn])->pnPara;
+ pfib->pnFntb = pfcb->pnFntb;
+ pfib->pnSep = pfcb->pnSep;
+ pfib->pnSetb = pfcb->pnSetb;
+ pfib->pnBftb = pfcb->pnBftb;
+
+ /* mark file type if objects are in there */
+ if (vcObjects)
+ pfib->wIdent = wOleMagic;
+ else
+ pfib->wIdent = wMagic;
+
+#ifdef INTL /* International version */
+
+ if (vWordFmtMode != TRUE) /* saving in Write format */
+#endif /* International version */
+
+ {
+ pfib->pnFfntb = pfcb->pnFfntb;
+ pfib->pnMac = pfcb->pnMac;
+ }
+
+#ifdef INTL /* International version */
+
+ else
+ {
+ /* in Word format there is no font table. pnFfntb is the
+ end of the file,so is set to pnMac. The Write pnMac field
+ is not used in Word and is set to 0. */
+ pfib->pnFfntb = pfcb->pnMac;
+ pfib->pnMac = 0;
+ }
+#endif /* International version */
+
+ pfib->fcMac = pfcb->fcMac = cpMac + cfcPage;
+ if ((**hpdocdod)[doc].dty == dtyNormal)
+ {
+ CHAR (**hszSsht)[];
+#ifdef STYLES
+#ifdef DEBUG
+ Assert((**hpdocdod)[doc].docSsht != docNil);
+#endif
+ hszSsht = (**hpdocdod)[(**hpdocdod)[doc].docSsht].hszFile;
+#else
+ hszSsht = HszCreate((PCH)"");
+#endif /* STYLES */
+ if (!FNoHeap(hszSsht))
+ {
+ bltbyte(**hszSsht, pfib->szSsht, CchSz(**hszSsht));
+#ifndef STYLES
+#if WINVER >= 0x300
+ /* Here we WERE allowing the hszSsht from just above
+ to be overwritten by another alloc! This code
+ really shouldn't even be here because Write knows
+ nothing about style sheets but we want to make as
+ few changes now as possible ..pault 2/12/90 */
+ FreeH(hszSsht);
+#endif
+#endif
+ hszSsht = HszCreate((PCH)pfib->szSsht); /* HEAP MOVES */
+#if WINVER >= 0x300
+ /* Just in case hszSsht has already been assigned
+ here, we'll free it up ..pault 2/12/90 */
+ if ((**hpfnfcb)[fn].hszSsht != NULL)
+ FreeH((**hpfnfcb)[fn].hszSsht);
+#endif
+ (**hpfnfcb)[fn].hszSsht = hszSsht;
+ }
+ else
+ (**hpfnfcb)[fn].hszSsht = 0;
+ }
+
+AbortWrite:
+ vfnWriting = fnNil;
+
+ FreeFfntb(hffntb);
+
+ if (vfDiskFull || vfDiskError)
+ fFileFlushed = FALSE;
+ else
+ fFileFlushed = FFlushFn(fn);
+ CloseEveryRfn( TRUE );
+
+ if (!fFileFlushed) /* Writing the file has failed due to disk full */
+ {
+#ifdef CASHMERE
+ if (hsetb != 0)
+ FreeH(hsetbT);
+#endif
+LFlushFailed:
+ FUndirtyFn(fn); /* Undirty all of the buffer pages
+ holding parts of the unsuccessfully
+ written file. */
+ return false;
+ }
+
+ if (!FMakeRunTables(fn)) /* HM */
+ (**hpfnfcb)[fn].fFormatted = false;
+
+ /* Success! */
+#ifdef CASHMERE
+ if (hsetb != 0)
+ { /* HM */
+ FreeH(hsetb);
+ (**hpdocdod)[doc].hsetb = hsetbT;
+ }
+#endif
+ }
+else
+ {
+ WriteUnformatted(fn, doc);
+ vfnWriting = fnNil;
+ if (vfDiskFull || vfDiskError)
+ fFileFlushed = FALSE;
+ else
+ fFileFlushed = FFlushFn(fn);
+ CloseEveryRfn( TRUE );
+
+ if (!fFileFlushed)
+ goto LFlushFailed;
+ }
+CloseEveryRfn( TRUE ); /* Be real sure the save file is closed */
+ /* This fixes the "pasting between Write
+ instances with the sharer loaded" bug */
+
+
+return true;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------
+-- Routine: ReduceFnScratchFn
+-- Description: this routine is called after successful TS, TGS, GTS and
+ !vfBuffersDirty. Its purpose is to make sure that no doc has pointers
+ to fnScratch and that we can empty fnScratch so as to reduce program
+ disk space
+-- Arguments: none
+-- Returns: none
+-- Side Effects: docScrap is cleaned up and becomes a new doc that has no
+ pointers into fnScratch. FnScratch is emptied, all global variables
+ associated with this new fnScratch are initialized.
+-- Bugs:
+-- History:
+ Apr 16 '84 -- created (chic)
+ Aug 9 '85 -- modified it so it puts the scratch file on the same disk
+ as the passed fn to reduce disk swapping on floppy
+ systems.
+----------------------------------------------------------------------------*/
+
+ReduceFnScratchFn( fn )
+{
+int doc;
+struct DOD *pdod;
+
+CHAR sz[cchMaxFile];
+
+int cchT;
+struct FCB *pfcb;
+
+#ifdef BOGUSBL /* Because of disk switching, always worth doing */
+if ((**hpfnfcb)[fnScratch].fcMac > fcBound) /* worth doing */
+#endif
+
+ {
+ for (pdod = &(**hpdocdod)[0],doc = 0; doc < docMac; pdod++,doc++)
+ {
+ /* don't do anything if any of the allocated doc (hpctb != 0)
+ except docScrap is dirty */
+ /* docUndo may be dirty, but it also should be empty */
+
+ if (doc != docScrap && pdod->hpctb != 0 && pdod->fDirty &&
+ doc != docUndo)
+ {
+ Assert(0);
+ return;
+ }
+ } /* end of for loop */
+
+ Assert( (**hpdocdod) [docUndo].cpMac == cp0 );
+
+ /* now no doc can possibly has pointers to fnScratch except docScrap */
+ pdod = &(**hpdocdod)[docScrap];
+
+
+#if 0
+ This check was only for speed considerations. With the 64K
+ transcendence we *must* clean docScrap no matter what.
+ (7.10.91) v-dougk
+
+ if (pdod->cpMac > cpBound) /* too big to be cleaned up */
+ {
+ Assert(0);
+ /**
+ But we don't know if docScrap points into fnScratch. We only need
+ to clear docScrap if it points into fnScratch. We shouldn't
+ abort here unless we know that docScrap does indeed point into
+ fnScratch. If it doesn't then we needn't clear it and can proceed
+ to clear fnScratch.
+
+ We know that docScratch will not point to any large
+ OLE object data in fnScratch because object data is never put
+ into fnScratch at a time that the user could select it.
+ That is, it is unlikely that the size of docScratch will
+ exceed cpBound on account of object data alone.
+
+ Only the presence of large textual data in docScratch
+ is likely to cause this failure.
+ (7.10.91) v-dougk
+ **/
+ return;
+ }
+ else /* small enough to be cleaned up */
+#endif
+ {
+ if (pdod->cpMac > cp0)
+ {
+#ifdef STYLES
+ /* doc has to have a valid style sheet before CleanDoc */
+ pdod->docSsht = (**hpdocdod)[docCur].docSsht;
+#endif /* STYLES */
+ CachePara(docScrap,cp0);
+
+ /* Save docScrap to new, unique file; name in sz */
+ CleanDoc( docScrap, dtyNetwork, sz, true, false );
+#ifdef STYLES
+ (**hpdocdod)[docScrap].docSsht = docNil;
+#endif /* STYLES */
+ }
+ if (!ferror) /* in case something went wrong in rename or make backup file in CleanDoc */
+ {
+ typePN pnMacScratch;
+
+ pfcb = &(**hpfnfcb)[fnScratch];
+ pnMacScratch = pfcb->pnMac;
+ ResetFn(fnScratch); /* empty FnScratch */
+
+#ifdef DEBUG
+ OutputDebugString("*** Reduced scratch file ***\n\r");
+#endif
+
+ /* Put the scratch file on the same disk as the save file,
+ to reduce disk swapping in floppy environments */
+
+ if ( (fn != fnNil) &&
+ !((POFSTRUCT)(**hpfnfcb) [fnScratch].rgbOpenFileBuf)->fFixedDisk )
+ { /* fnScratch is on removable media */
+ extern CHAR szExtDoc[];
+ CHAR szNewScratch[ cchMaxFile ];
+ CHAR (**hszScratch)[] = (**hpfnfcb) [fnScratch].hszFile;
+ CHAR chDrive = (**(**hpfnfcb) [fn].hszFile) [0];
+
+ Assert( fn != fnScratch );
+ if (FEnsureOnLineFn( fn ))
+ if (GetTempFileName( TF_FORCEDRIVE | chDrive,
+ (LPSTR)(szExtDoc+1), 0, (LPSTR) szNewScratch))
+ { /* Created new file on same disk as fn */
+ CHAR (**hsz)[];
+ CHAR szNew [cchMaxFile];
+
+#if WINVER >= 0x300
+ /* Currently: FNormSzFile *TAKES* an OEM sz, and
+ *RETURNS* an ANSI sz ..pault */
+#endif
+ FNormSzFile( szNew, szNewScratch, dtyNormal );
+ if (!FNoHeap( hsz = HszCreate(szNew)))
+ {
+ struct FCB *pfcb = &(**hpfnfcb)[fnScratch];
+
+ /* Delete old scratch file */
+
+ if (FEnsureOnLineFn( fnScratch ))
+ FDeleteFile( &(**hszScratch)[0] );
+
+ /* Put new scratch file back on line and
+ open it, so OpenFile gets its buffer info */
+
+ pfcb->hszFile = hsz;
+ pfcb->fOpened = FALSE;
+
+ FEnsureOnLineFn( fn );
+ FAccessFn( fnScratch, dtyNormal);
+ }
+ }
+ }
+
+ pfcb->pnMac = pnMacScratch;
+ /* reset all global varibales associated with an empty fnScratch */
+ fprmCache.cch = 0;
+ fcMacPapIns = 0;
+ fcMacChpIns = 0;
+ /* just in case */
+ pfcb->pnChar = pfcb->pnPara = pfcb->pnFntb = pfcb->pnSep = pfcb->pnSetb = pfcb->pnBftb = pn0;
+ vfkpdParaIns.brun = vfkpdCharIns.brun = 0;
+ vfkpdParaIns.bchFprop = vfkpdCharIns.bchFprop = cbFkp;
+ vfkpdParaIns.pn = PnAlloc(fnScratch);
+ ((struct FKP *)PchGetPn(fnScratch, vfkpdParaIns.pn,
+ &cchT, true))->fcFirst = fc0;
+ vfkpdCharIns.pn = PnAlloc(fnScratch);
+ ((struct FKP *)PchGetPn(fnScratch, vfkpdCharIns.pn,
+ &cchT, true))->fcFirst = fc0;
+ vfkpdParaIns.ibteMac = vfkpdCharIns.ibteMac = 0;
+ blt(&vchpNormal, &vchpInsert, cwCHP);
+ blt(vppapNormal, &vpapPrevIns, cwPAPBase + cwTBD);
+ } /* end of ferror */
+ else
+ Assert(0);
+ } /* end of small enough to be cleaned up */
+ } /* end of worth doing */
+} /* end of ReduceFnScratchFn */
+
+
+
+
+
+
+ResetFn(fn)
+{ /* make fn look as if no characters have been written */
+ /* but don't try to reuse fn (in that case, must rehash) */
+int ibp;
+register struct BPS *pbps;
+struct FCB *pfcb;
+
+Assert( fn != fnNil );
+(pfcb = &(**hpfnfcb)[fn])->fcMac = fc0;
+pfcb->pnMac = pn0;
+for (ibp = 0, pbps = &mpibpbps [0]; ibp < ibpMax; ++ibp, ++pbps)
+ { /* find all buffer pages and "clear" them */
+ if (pbps->fn == fn)
+ {
+#ifdef CKSM
+#ifdef DEBUG
+ extern unsigned (**hpibpcksm) [];
+
+ if (!pbps->fDirty)
+ Assert( (**hpibpcksm) [ibp] == CksmFromIbp( ibp ) );
+#endif
+#endif
+ pbps->fDirty = false;
+ pbps->cch = 0;
+#ifdef CKSM
+#ifdef DEBUG
+ /* Recompute checksum to account for cch change */
+ (**hpibpcksm) [ibp] = CksmFromIbp( ibp );
+#endif
+#endif
+ }
+ }
+}
+
+
+
+/*** FBackupSzFile - Make a backup copy of the passed szFile
+ *
+ * ENTRY: szFile - the (assumed normalized) name of the
+ * file to back up
+ * fBackup - whether the user is interested in seeing
+ * a backup copy of szFile
+ * EXIT: szBak - the (normalized) name of the backup
+ * file is returned through here
+ * RETURNS: TRUE=We made a backup copy, szBak of szFile
+ * FALSE=We didn't/couldn't make a backup copy
+ *
+ * NOTE: We try to put the backup file into the directory used
+ * as the default by GetTempFileName; in general, this
+ * effort will succeed if the directory is on the same
+ * physical drive as the original.
+ * NOTE: we may keep around a backup copy regardless of the
+ * setting of fBackup, to have access to pieces in it.
+ * However, the file's fDelete flag will be set to TRUE, marking
+ * it for eventual deletion
+ */
+
+FBackupSzFile( szFile, fBackup, szBak ) /* filenames taken as ANSI */
+CHAR szFile[];
+int fBackup;
+CHAR szBak[];
+{ /* Copy szFile into a backup copy, and give backup old fn. */
+ /* Also, return name of backup file */
+int fnOld;
+int f;
+int fDelete = false;
+int rfn;
+int fTryAgain=FALSE;
+CHAR chDriveTempFile;
+int fn;
+CHAR rgbBuf[ cbOpenFileBuf ];
+
+#ifdef ENABLE
+ if ((fn = FnFromSz( szFile )) != fnNil)
+ /* Avoid share violations while checking for existence */
+ CloseFn( fn );
+ if (OpenFile( (LPSTR) szFile, (LPOFSTRUCT) rgbBuf, OF_EXIST ) != -1)
+#endif
+
+ if (FExistsSzFile( dtyAny, szFile ))
+ { /* File exists; make backup (even if it's on another floppy) */
+ int fSame;
+
+ /* szBak <-- backup file name (it'll be normalized since szFile is) */
+ bltsz( szFile, szBak );
+
+#ifdef INTL /* International version */
+ /* if file has .WRI extension, put Write .BKP extension on,
+ otherwise put Word backup extension (.BAK) on instead. */
+
+ AppendSzExt( szBak, szExtDoc, TRUE );
+ fSame = FSzSame( szFile, szBak ); /* Whether file is .WRI */
+ AppendSzExt( szBak, (fSame ? szExtBackup : szExtWordBak),
+ TRUE );
+#else
+ AppendSzExt( szBak, szExtBackup, TRUE );
+#endif /* International version */
+
+
+ fSame = FSzSame( szFile, szBak ); /* Whether file is .BAK already */
+
+ Assert( szBak [1] == ':' );
+ chDriveTempFile = szBak[0]; /* Drive on which to create temp file */
+
+ for( ;; )
+ {
+
+ if (!fBackup || fSame )
+ { /* This is just being kept for its pieces OR the file
+ happens to be .BAK already: give backup a unique name */
+ CHAR szBakT [cchMaxFile];
+
+ if (!fTryAgain)
+ { /* First time through; try not forcing the drive
+ letter to see how we fare. The advantage is that
+ if we succeed, the temp file is in a more standard
+ place. If the rename fails, we end up at the
+ branch below. */
+
+ fTryAgain = TRUE; /* Try a second time if we fail */
+ if (!GetTempFileName( chDriveTempFile,
+ (LPSTR)(szExtDoc+1), 0, (LPSTR)szBakT))
+ continue;
+ }
+ else
+ { /* Second time through -- try forcing the drive */
+ /* Grab a temp file on the same drive as the original */
+
+ fTryAgain = FALSE; /* No more tries */
+ if (!GetTempFileName( chDriveTempFile | TF_FORCEDRIVE,
+ (LPSTR)(szExtDoc+1), 0, (LPSTR) szBakT))
+ {
+ Error( IDPMTSDE2 ); /* should probably GOTO HARDCORE instead */
+ return FALSE;
+ }
+ }
+
+ /* szBakT <-- Temp name in OEM */
+ /* szBak <-- Normalized temporary name in ANSI */
+ FNormSzFile( szBak, szBakT, dtyNormal );
+ fDelete = TRUE;
+ }
+
+ if ((fnOld = FnFromSz(szBak)) != fnNil)
+ { /* We have backup open */
+ CHAR szT[cchMaxFile];
+
+ FBackupSzFile( szBak, false, szT );
+ }
+
+ if ((fnOld = FnFromSz(szFile)) != fnNil)
+ { /* We have file open */
+/* ? */ FFlushFn(fnOld);
+ CloseFn( fnOld );
+ }
+
+ /* Rename szFile to be temp name (must delete the empty temp file) */
+
+ if (!FDeleteFile( szBak ) || FIsErrFpe(FpeRenameFile( szFile, szBak )))
+ {
+ extern HWND vhWnd;
+ CHAR szT [cchMaxSz];
+ CHAR *pchSrc;
+
+ if (fTryAgain)
+ /* Failed with temp name on the default drive; try again */
+ continue;
+
+ /* HARDCORE FAILURE: Could not rename file */
+HardCore:
+ /* pchSrc <-- ptr to start of filename (sans path) */
+
+ pchSrc = &szFile [CchSz( szFile ) - 1];
+ while (pchSrc > szFile)
+ if (*(--pchSrc) == '\\')
+ {
+ pchSrc++;
+ break;
+ }
+ Assert( pchSrc > szFile ); /* Always "X:\" in normalized name */
+
+ MergeStrings (IDPMTRenameFail, pchSrc, szT);
+ IdPromptBoxSz( vhWnd, szT, ErrorLevel( IDPMTRenameFail ) );
+
+ return FALSE; /* We couldn't rename this file to the backup name */
+ }
+
+ if (fnOld != fnNil)
+ { /* We had an fn for the renamed file; must update fcb */
+ CHAR (**hszBak)[];
+ struct FCB *pfcb;
+
+ FreeH((**hpfnfcb)[fnOld].hszFile); /* HM */
+ hszBak = HszCreate((PCH)szBak);
+
+ pfcb = &(**hpfnfcb)[fnOld];
+ pfcb->hszFile = hszBak;
+ pfcb->fDelete = fDelete;
+ }
+
+ else if (!fBackup)
+ { /* Delete this sucker NOW. (!fBackup indicates that the user
+ doesn't care about the backup copy, and Word can't care
+ about its pieces since it doesn't have an fn. So nobody
+ wants it, so we get rid of it) */
+ FDeleteFile( szBak );
+ return false;
+ }
+
+ return true;
+ } /* end for( ;; ) */
+ } /* end if (FExists... */
+
+
+return false; /* file did not exist; make no backup */
+}
+
+
+
+
+
+int FExistsSzFile(dty, szFile)
+int dty;
+CHAR szFile[];
+{ /* Return true iff file exists */
+CHAR rgbBuf[ 128 ]; /* Buffer used by OpenFile */
+int bRetval;
+
+#ifdef DEBUG
+ {
+ int junk;
+ Assert(FValidFile(szFile, CchSz(szFile)-1, &junk));
+ }
+#endif /*DEBUG*/
+
+/* Use FnFromSz to avoid share violations on files we have open */
+
+ if (FnFromSz( szFile ) != fnNil)
+ return TRUE;
+
+ SetErrorMode(1);
+ bRetval = OpenFile( (LPSTR) szFile, (LPOFSTRUCT) rgbBuf, OF_EXIST ) != -1;
+ SetErrorMode(0);
+ return bRetval;
+}
+
+
+
+
+
+struct PGTB **HpgtbGet(doc)
+int doc;
+{ /* Return hpgtb if doc has one, 0 if none */
+struct DOD *pdod;
+
+if ((pdod = &(**hpdocdod)[doc])->dty != dtyNormal)
+ return 0;
+else
+ return pdod->hpgtb;
+}
+
+
+
+
+
+FreeFn( fn )
+int fn;
+{ /* Forget about the existence of file fn. Assumes no document holds
+ pieces from fn. Frees all heap items in (**hpfnfcb) [fn] and
+ marks the fcb as free (rfn == rfnNil).
+ */
+#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax
+
+ extern int iibpHashMax;
+ extern CHAR *rgibpHash;
+ extern struct BPS *mpibpbps;
+
+ register struct BPS *pbps;
+ int pn;
+
+ extern CHAR (**hszTemp)[];
+
+ register struct FCB *pfcb = &(**hpfnfcb)[fn];
+ CHAR (**hsz)[] = pfcb->hszFile;
+ CHAR (**hszSsht)[] = pfcb->hszSsht;
+ typeFC (**hgfcChp)[]=pfcb->hgfcChp;
+ typeFC (**hgfcPap)[]=pfcb->hgfcPap;
+
+ FreezeHp();
+
+ CloseFn( fn );
+
+/* Purge buffer slots holding pages of fn; maintain integrity of hash chains */
+
+ for ( pn = 0; pn < pfcb->pnMac; pn++ )
+ FreeBufferPage( fn, pn );
+
+#ifdef DEBUG
+ CheckIbp();
+#endif
+
+ pfcb->fDelete = FALSE;
+ pfcb->hszFile = hszTemp;
+ pfcb->rfn = rfnFree;
+ MeltHp();
+
+ if ( hsz != hszTemp )
+ FreeH( hsz );
+#if WINVER >= 0x300
+ /* Previously we allocated a small block ("") for the
+ style sheet but never freed it! ..pault 2/12/90 */
+ if (hszSsht != NULL)
+ FreeH(hszSsht);
+#endif
+ if (hgfcChp)
+ FreeH( hgfcChp );
+ if (hgfcPap)
+ FreeH( hgfcPap );
+}
+
+
+
+
+/*** FUndirtyFn
+ *
+ *
+ */
+
+FUndirtyFn(fn)
+int fn;
+/*
+ Description: Mark all buffer pages holding parts of this file
+ as non-dirty.
+ Called after a disk full caused writing a file
+ to fail (in FWriteFn).
+ Returns: nothing.
+*/
+{
+#ifdef CKSM
+#ifdef DEBUG
+ extern unsigned (**hpibpcksm) [];
+#endif
+#endif
+ int ibp;
+ struct BPS *pbps;
+ for (ibp = 0, pbps = mpibpbps; ibp < ibpMax; ibp++,
+ pbps++)
+ {
+ if (pbps->fn == fn)
+ {
+ pbps->fDirty = FALSE;
+#ifdef CKSM
+#ifdef DEBUG
+ /* Update checksum */
+ (**hpibpcksm) [ibp] = CksmFromIbp( ibp );
+#endif
+#endif
+ }
+ }
+
+}
+
+
+
+
+/*** IbpWriting - Find buffer page while writing file
+ *
+ *
+ *
+ */
+
+IbpWriting(fn)
+int fn;
+/* called when trying to find a slot in the file page "cache" buffer and */
+/* vfnWriting != fnNil (currently in the process of writing some file) */
+{
+ typeTS dTs;
+ int ibp;
+
+ if (fn == vfnWriting)
+ { /* writing a piece of the vfnWriting file */
+ /* vibpWriting is the previous slot used to hold file */
+ /* contents. Keep slots contiguous and in the first */
+ /* (upper) half of the buffer area. */
+ if (vibpWriting > 0)
+ { /* We may have read multiple pages last time */
+ /* Advance past all slots holding contiguous pages */
+ struct BPS *pbps=&mpibpbps[ vibpWriting ];
+ int pn=(pbps-1)->pn;
+
+ while ( pbps->fn == fn && pbps->pn == ++pn )
+ {
+ pbps++;
+ vibpWriting++;
+ }
+ vibpWriting--;
+ }
+
+ if (++vibpWriting >= (ibpMax >> 1))
+ vibpWriting = 0;
+
+ /* We must abide by the restriction that */
+ /* we do not clobber the cbpMustKeep most recently used */
+ /* slots in the process. */
+ dTs = tsMruBps - mpibpbps[vibpWriting].ts;
+ dTs = ((dTs & 0x8000) ? (~dTs + 1) : dTs);/* absolute value */
+ if (dTs < cbpMustKeep)
+ vibpWriting = ibp = IbpLru(0);
+ else /* adjacent slot is o.k. - not too recently used */
+ ibp = vibpWriting;
+ }
+ else
+ /* If currently writing a file (but the current page is */
+ /* not part of it), try to find a slot in the lower half */
+ /* of the buffer. This decreases the possibility that the */
+ /* adjacent slot to vibpWriting will be too recently used. */
+ ibp = IbpLru(ibpMax >> 1);
+ return(ibp);
+}
+
+
+
+
+WriteFfntb(fn, hffntb)
+int fn;
+struct FFNTB **hffntb;
+{ /* Append a font table (ffntb) to fn */
+struct FFNTB *pffntb;
+struct FFN *pffn;
+int iffn, cbffn;
+int cchPageSpace = cbSector;
+int cchWrite;
+int wEndOfPage = -1;
+int wEndOfTable = 0;
+int cbT;
+
+pffntb = *hffntb;
+cbT = pffntb->iffnMac;
+WriteRgch( fn, &cbT, sizeof (int) );
+cchPageSpace = cbSector - sizeof (int);
+
+for (iffn = 0; iffn < pffntb->iffnMac; iffn++)
+ {
+ pffn = *pffntb->mpftchffn[iffn];
+ cchWrite = (cbffn = CbFfn(CchSz(pffn->szFfn))) + (2 * sizeof(int));
+
+ if (cchWrite > cchPageSpace)
+ { /* This entry will not fit on the page; start new page */
+
+ Assert( cchPageSpace >= sizeof (int ));
+ WriteRgch( fn, &wEndOfPage, sizeof (int) );
+ AlignFn( fn, cbSector, false );
+ cchPageSpace = cbSector;
+ }
+
+ Assert( cchWrite <= cchPageSpace );
+
+#ifdef NEWFONTENUM
+ /* let's just pretend we never added a charset field... pault */
+ cbffn -= sizeof(BYTE);
+ WriteRgch( fn, &cbffn, sizeof (int) ); /* Write entry size in bytes */
+ WriteRgch( fn, &pffn->ffid, cbffn ); /* Write the entry */
+#else
+ WriteRgch( fn, &cbffn, sizeof (int) ); /* Write entry size in bytes */
+ WriteRgch( fn, pffn, cbffn ); /* Write the entry */
+#endif
+ cchPageSpace -= cbffn + sizeof (int);
+ }
+
+Assert( cchPageSpace >= sizeof (int) );
+WriteRgch( fn, &wEndOfTable, sizeof(int) ); /* Table is terminated with 0000 */
+}
+
+
+
+FMapFtcSave(doc, hffntb, pchp, mpftcftc)
+/* attempt to map the ftc for this chp into it's new ftc in hffntb, according
+ to the mapping in mpftcftc. If there's no entry yet for this ftc, then
+ add it to the table. Returns FALSE if there was some problem */
+
+int doc;
+struct FFNTB **hffntb;
+struct CHP *pchp;
+CHAR *mpftcftc;
+{
+int ftc, ftcNew;
+struct FFN *pffn;
+CHAR rgbFfn[ibFfnMax];
+
+ftc = pchp->ftc + (pchp->ftcXtra << 6);
+ftcNew = mpftcftc[ftc];
+if (ftcNew == ftcNil)
+ {
+ /* haven't encountered this font yet - add it to hffntb and mpftcftc */
+ pffn = *(*HffntbGet(doc))->mpftchffn[ftc];
+ bltbyte(pffn, rgbFfn, CbFromPffn(pffn));
+ ftcNew = FtcAddFfn(hffntb, pffn);
+ if (ftcNew == ftcNil)
+ /* some problem adding the font */
+ return(FALSE);
+ mpftcftc[ftc] = ftcNew;
+ }
+
+pchp->ftc = ftcNew & 0x003f;
+pchp->ftcXtra = (ftcNew & 0x00c0) >> 6;
+return(TRUE);
+}
+
+
+
+FInitMapSave(doc, phffntb, mpftcftc)
+/* sets up for ftc mapping */
+
+int doc;
+struct FFNTB ***phffntb;
+CHAR *mpftcftc;
+{
+bltbc( mpftcftc, ftcNil, iffnMax );
+return(FNoHeap(*phffntb = HffntbAlloc()) == FALSE);
+}
+
+
+
+
+/* O U T S A V E D */
+OutSaved(doc)
+int doc;
+{
+ extern int docMode;
+ extern CHAR szMode[];
+ int NEAR CchExpCp( CHAR *, typeCP );
+ char szTmp[cchMaxSz];
+
+ LoadString(hINSTANCE, IDSTRChars, szTmp, sizeof(szTmp));
+ wsprintf(szMode,szTmp,(DWORD)(**hpdocdod)[doc].cpMac);
+ docMode = docNil;
+ DrawMode();
+}
+
+
+
+
+/* C C H E X P C P */
+int NEAR CchExpCp(pch, cp)
+CHAR *pch;
+typeCP cp;
+{
+ int cch = 0;
+
+ if (cp >= 10)
+ {
+ cch = CchExpCp(pch, cp / 10);
+ pch += cch;
+ cp %= 10;
+ }
+ *pch = '0' + cp;
+ return cch + 1;
+}
+
+
+
+#if 0
+
+SaveFontProfile(doc)
+/* updates our mru font entries in win.ini */
+
+int doc;
+ {
+ extern CHAR szWriteProduct[];
+ extern CHAR szFontEntry[];
+ int iffn;
+ struct FFN *pffn;
+ CHAR *pchFontNumber, *pchT;
+ CHAR rgbProf[LF_FACESIZE + 10]; /* for good measure */
+ CHAR rgbFfn[ibFfnMax];
+
+ if (FInitFontEnum(doc, iffnProfMax, FALSE))
+ {
+ pffn = (struct FFN *)rgbFfn;
+ pchFontNumber = szFontEntry + CchSz(szFontEntry) - 2;
+ for (iffn = 0; iffn < iffnProfMax; iffn++)
+ {
+ if (!FEnumFont(pffn))
+ break;
+#ifdef NEWFONTENUM
+#endif
+ pchT = (CHAR *)bltbyte(pffn->szFfn, rgbProf, CchSz(pffn->szFfn))-1;
+ *pchT++ = ',';
+ ncvtu(pffn->ffid, &pchT);
+#ifdef NEWFONTENUM
+ /* Save the font's charset value as well */
+ *pchT++ = ',';
+ ncvtu(pffn->chs, &pchT);
+#endif
+ *pchT = '\0';
+
+ *pchFontNumber = '1' + iffn;
+ WriteProfileString((LPSTR)szWriteProduct, (LPSTR)szFontEntry,
+ (LPSTR)rgbProf);
+ }
+ EndFontEnum();
+ }
+ }
+
+#endif
+
diff --git a/private/mvdm/wow16/write/trans3.c b/private/mvdm/wow16/write/trans3.c
new file mode 100644
index 000000000..10adbb263
--- /dev/null
+++ b/private/mvdm/wow16/write/trans3.c
@@ -0,0 +1,1846 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* trans3.c: more save routines, moved here from trans2.c because of compiler
+ heap space errors */
+
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOMSG
+#define NOKEYSTATE
+#define NOSHOWWINDOW
+//#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOBITMAP
+//#define NOATOM
+#define NOMETAFILE
+#define NOPEN
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOHRGN
+#define NOCOLOR
+#define NODRAWTEXT
+//#define NOTEXTMETRIC
+#define NOWINOFFSETS
+#define NOCREATESTRUCT
+#define NOWH
+#define NOSOUND
+#define NOSCROLL
+#define NOCOMM
+#define NOWNDCLASS
+/* need memmgr, mb */
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "editdefs.h"
+#include "printdef.h"
+#define NOSTRUNDO
+#include "str.h"
+#include "debug.h"
+#include "fontdefs.h"
+#include "dlgdefs.h"
+#include "winddefs.h"
+#include "macro.h"
+#include "preload.h"
+#include "io.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#define WRITE_PERMISSION 02 /* flag to access() */
+
+CHAR *index( CHAR *, CHAR );
+CHAR *PchGetPn();
+CHAR *PchFromFc();
+static int fOpenedFormatted = TRUE;
+int vfOldWriteFmt=FALSE; /* delete objects before saving */
+DoFileOpen( LPSTR );
+
+BOOL CheckEnableButton(HANDLE, HANDLE);
+BOOL NEAR PASCAL CanReadEveryFile(char *szFilename);
+
+extern CHAR szExtSearch[]; /* store default search spec */
+extern CHAR szWriteProduct[];
+extern CHAR szBackup[];
+extern int vfTextOnlySave;
+
+extern int vfCursorVisible;
+extern int vfDiskError;
+extern int vfSysFull;
+extern HWND vhWndMsgBoxParent;
+extern int vfnWriting;
+extern CHAR (**vhrgbSave)[];
+extern struct DOD (**hpdocdod)[];
+extern int docCur;
+extern int docScrap;
+extern int docUndo;
+extern struct FCB (**hpfnfcb)[];
+extern int vfBuffersDirty;
+extern int vfDiskFull;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeCP vcpLimParaCache;
+extern int vfDeactByOtherApp;
+extern BOOL vfWarnMargins;
+
+#ifdef INTL /* International version */
+extern int vWordFmtMode;
+#ifdef INEFFLOCKDOWN
+extern FARPROC lpDialogWordCvt;
+#else
+extern BOOL far PASCAL DialogWordCvt(HWND, unsigned, WORD, LONG);
+#endif
+#endif /* International version */
+
+static unsigned wMerge; /* for message merge code */
+
+extern int vfBackupSave;
+
+extern int ferror;
+extern CHAR szExtBackup[];
+extern CHAR (**hszTemp)[];
+#ifdef INEFFLOCKDOWN
+extern FARPROC lpDialogOpen;
+extern FARPROC lpDialogSaveAs;
+#endif
+
+
+extern HANDLE hMmwModInstance;
+extern HANDLE hParentWw;
+extern HCURSOR vhcHourGlass;
+extern HCURSOR vhcIBeam;
+extern HCURSOR vhcArrow;
+
+ /* Used in this module only */
+static CHAR *pchSet;
+static CHAR szUser[ cchMaxFile ]; /* store whatever is in idiOpenFile (ANSI) */
+
+#define SF_OLDWRITE 0
+#define SF_WORD 1
+BOOL WannaDeletePictures(int doc, int fWhichFormat);
+BOOL DocHasPictures(int doc);
+NEAR DlgAddCorrectExtension(CHAR *, int);
+BOOL (NEAR FSearchSpec(CHAR *));
+BOOL far PASCAL DialogOpen(HWND, unsigned, WORD, LONG);
+BOOL far PASCAL DialogSaveAs(HWND, unsigned, WORD, LONG);
+
+
+#ifdef INTL /* International version */
+BOOL FInWordFormat(int);
+void ConvertFromWord();
+#endif /* International version */
+
+
+fnOpenFile(LPSTR lpstrFileName) // filename may be NULL
+{
+ extern int vfCloseFilesInDialog;
+ extern int docCur;
+ extern HANDLE hMmwModInstance;
+ extern HANDLE hParentWw;
+ extern struct SEL selCur;
+ extern typeCP cpMinDocument;
+
+ /* Close all files on removable media for every message we get */
+ vfCloseFilesInDialog = TRUE;
+
+ /* Close all files on removable media so changing disks is safe */
+ CloseEveryRfn( TRUE );
+
+ /* test for dirty file and offer opportunity to save */
+
+ if (FConfirmSave())
+ DoFileOpen(lpstrFileName);
+
+ vfCloseFilesInDialog = FALSE;
+}
+
+DoFileOpen( LPSTR lpstrFileName ) // filename may be NULL )
+{
+ /* return whether error. Use CommDlg for open dialog (3.8.91) D. Kent */
+ /* ********* International version changes bz 2/21/86 *************
+ For files opened in Word format and converted to Write format
+ the following changes are made:
+ the vWordFmtMode flag is left set to CONVFROMWORD. The file is
+ saved, effecting the change to Word format, but the original
+ Word file in not renamed, so it is left untouched, with no need to
+ make a backup. On the next save, we ask if the file with that name
+ (the Word document) should be replaced, so any file with that
+ name that existed will be protected.
+ *************************************************************** */
+
+ extern int vfDiskError;
+ int fn=fnNil;
+ int doc;
+ CHAR (**hsz)[] = NULL;
+ int nRetval=FALSE;
+ CHAR rgch[cchMaxFile];
+ extern DoOpenFilenameGet(LPSTR);
+ BOOL bOpened=TRUE, // ObjOpenedDoc has succeeded
+ bCancelled=FALSE;
+
+#ifdef INTL /* International version */
+int fWordDoc;
+#endif /* International version */
+
+ EnableOtherModeless(FALSE);
+
+ /* prevent WM_PAINT from painting a doc that isn't defined */
+
+ while(1)
+ {
+ bCancelled = FALSE;
+
+ if (lpstrFileName)
+ lstrcpy(rgch,lpstrFileName);
+ else if (!DoOpenFilenameGet(rgch))
+ {
+ bCancelled = TRUE;
+ goto KeepTrying;
+ }
+ else if (rgch[0] == '\0')
+ {
+ bCancelled = TRUE;
+ goto KeepTrying;
+ }
+
+#if defined(OLE)
+ if (bOpened)
+ if (ObjClosingDoc(docCur,rgch))
+ /*
+ If this failed, then we could't close this document, much less
+ open a new one.
+ */
+ break; // from while
+ else
+ /**
+ At this point, docCur is OLE-closed!!! Gotta be sure we
+ open a new one!!!
+ **/
+ bOpened = FALSE;
+#endif
+
+
+ if ((fn = FnOpenSz( rgch, dtyNormNoExt, FALSE)) == fnNil)
+ /* this has side effect of setting &(**(**hpfnfcb) [fn].hszFile) [0]
+ to "normalized" filename. */
+ {
+ /* Open failed */
+ goto KeepTrying;
+ }
+ else
+ { /* Opened file OK */
+ /* Set caption to "Loading file..." */
+
+ extern CHAR szLoadFile[];
+ extern CHAR szCvtLoadFile[];
+
+#ifdef INTL /* International version */
+ /* **************************************
+ * added check for international version to
+ do Word format conversion. If Word format,
+ bring up another dialog box.
+ * ************************************** */
+
+ /* TestWordCvt return values:
+
+ -1 means dialog box failed (error already sent)
+ -2 means cancel without conversion.
+ FALSE means not a word document.
+ TRUE means convert this word document.
+ *** as of 2/14/86, we changed the conversion
+ to not make a backup, but to save the file
+ in write format without renaming the Word
+ file, so the word file is effectively
+ backed up under its original name. See
+ CleanDoc in trans2.c for explanations.
+ */
+
+ switch ((fWordDoc = TestWordCvt (fn, hParentWw)))
+ {
+ case -2: // CANCEL
+ bCancelled = TRUE;
+ // fall through..
+
+ case -1: // ERROR
+ /* Release this fn! */
+ FreeFn(fn);
+ CloseEveryRfn( TRUE );
+ goto KeepTrying;
+ }
+
+ /* if true, will convert soon */
+ if (fWordDoc)
+ {
+ SetWindowText(hParentWw, (LPSTR)szCvtLoadFile);
+ }
+ else
+#endif /* International version */
+ SetWindowText(hParentWw, (LPSTR)szLoadFile);
+
+ StartLongOp();
+
+ ReadFilePages( fn );
+ }
+
+ Assert( fn != fnNil );
+ bltsz( &(**(**hpfnfcb) [fn].hszFile) [0], rgch );
+
+ CchCopySz(rgch, szUser);
+
+ hsz=NULL;
+
+ if ( !FNoHeap(hsz = HszCreate( (PCH) rgch )) )
+ {
+ if ((doc = DocCreate( fn, hsz, dtyNormal )) != docNil)
+ { /* Succeeded in creating document */
+
+ KillDoc( docCur );
+ docCur = doc;
+ hsz = NULL; // don't free cause used by doc
+
+#ifdef INTL /* International version */
+ /* if a word document to be converted, save it doing conversion. */
+ if (fWordDoc)
+ {
+ /* save file in write format. */
+ ConvertFromWord();
+ vfTextOnlySave = FALSE;
+ (**hpdocdod)[docCur].fDirty = TRUE;
+ }
+#endif /* International version */
+
+ ChangeWwDoc( szUser );
+ /* Ensure that the margins of this document is right
+ for the printer. */
+ vfWarnMargins = TRUE;
+ SetPageSize();
+ vfWarnMargins = FALSE;
+#if defined(OLE)
+ if (ObjOpenedDoc(docCur))
+ /* Couldn't open. Must try to open a new one */
+ goto KeepTrying;
+ else
+ {
+ bOpened = TRUE;
+ break; // from while loop 'cause we're done
+ }
+#endif
+ }
+ }
+
+ KeepTrying:
+ /* get to here either because error or cancelled */
+
+ vfDiskError = ferror = FALSE;
+ SetTitle( **(**hpdocdod)[ docCur ].hszFile );
+
+ if (hsz)
+ {
+ FreeH( hsz );
+ hsz=NULL;
+ }
+
+ CloseEveryRfn( TRUE );
+
+ EndLongOp(vhcArrow);
+
+ if (bCancelled)
+ /* can't cancel unless we have an opened document */
+ {
+ if (!bOpened) // currently no open doc
+ {
+ if (bOpened = !ObjOpenedDoc(docCur)) // returns FALSE if success
+ break;
+ }
+ else
+ break;
+ }
+
+ } // end of while(1)
+
+
+#if WINVER >= 0x300
+ FreeUnreferencedFns();
+#endif
+
+ EndLongOp(vhcArrow);
+ EnableOtherModeless(TRUE);
+ return !bOpened;
+
+} /* end of DoFileOpen */
+
+
+
+
+fnSave()
+{ /* Entry point for the "Save" command */
+ extern int vfCloseFilesInDialog;
+ extern int vfOutOfMemory;
+ extern HANDLE vhReservedSpace;
+
+ struct DOD *pdod = &(**hpdocdod)[docCur];
+ CHAR *psz = &(**(pdod->hszFile))[0];
+
+ if (!CanReadEveryFile(psz))
+ return;
+
+#if WINVER >= 0x300
+ if (pdod->fReadOnly)
+ {
+ /* Read-only doc: tell the user to save under a different name */
+
+ Error( IDPMTReadOnly );
+ ferror = FALSE; /* Not really an error */
+
+ fnSaveAs(); /* May as well take them there now! ..pault 10/20/89 */
+ }
+ else if (psz [0] == '\0' || vWordFmtMode == CONVFROMWORD)
+ /* Any time the user has converted the current Write document
+ from a Word or Text document, we force them through the
+ FileSaveAs dlg box when Saving. In this way we remind them
+ that they might want to change the name -- but if they don't
+ want to, that's ok and we'll not bother them any more about it
+ (fnSaveAs dialog box will reset vWordFmtMode) ..pault 9/18/89 */
+#else /* old windows */
+ else if (psz [0] == '\0')
+#endif
+ fnSaveAs();
+ else
+ {
+
+ if (vfOldWriteFmt || (vWordFmtMode & ~CONVFROMWORD) || vfTextOnlySave)
+ /* then deleting pictures */
+ {
+ if (vfOldWriteFmt || vfTextOnlySave)
+ vcObjects = ObjEnumInDoc(docCur,NULL);
+ if (!WannaDeletePictures(docCur,vfOldWriteFmt ? SF_OLDWRITE : SF_WORD))
+ return;
+ }
+
+ vfCloseFilesInDialog = TRUE;
+
+ /* Close all files on removable media so changing disks is safe */
+
+ CloseEveryRfn( TRUE );
+
+ /* Free the reserved block, to give us memory for the save dialog box
+ and for CmdXfSave */
+ if (vhReservedSpace != NULL)
+ {
+ LocalFree(vhReservedSpace);
+ vhReservedSpace = NULL;
+ }
+
+ PreloadSaveSegs(); /* Advance loading of code to avoid disk swaps */
+
+ CmdXfSave(psz, pdod->fFormatted, pdod->fBackup, vhcIBeam);
+
+ if (vfDiskFull || vfSysFull)
+ ferror = FALSE;
+#if defined(OLE)
+ else
+ ObjSavedDoc();
+#endif
+
+ if ((vhReservedSpace = LocalAlloc( LHND, cbReserve )) == NULL)
+ /* we were unable to re-establish our block of reserved space. */
+ Error(IDPMTNoMemory);
+
+ vfCloseFilesInDialog = FALSE;
+ }
+}
+
+
+fnSaveAs()
+{ /* Entry point for the "Save As..." command */
+extern int vfCloseFilesInDialog;
+extern int vfOutOfMemory;
+extern HANDLE vhReservedSpace;
+
+ if (!CanReadEveryFile((**((**hpdocdod)[docCur].hszFile))))
+ return;
+
+ vfCloseFilesInDialog = TRUE;
+
+ /* Close all files on removable media so changing disks is safe */
+ CloseEveryRfn( TRUE );
+
+ /* Free the reserved block, to give us memory for the save dialog box
+ and for CmdXfSave */
+ if (vhReservedSpace != NULL)
+ {
+ LocalFree(vhReservedSpace);
+ vhReservedSpace = NULL;
+ }
+
+ PreloadSaveSegs(); /* Advance loading of code to avoid disk swaps */
+
+ DoFileSaveAs();
+
+ if ((vhReservedSpace = LocalAlloc( LHND, cbReserve )) == NULL)
+ { /* Either we were unable to bring up the save dialog
+ box, or we were unable to re-establish our
+ block of reserved space. */
+
+#if WINVER >= 0x300
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+
+ UpdateInvalid(); /* Assure screen gets updated */
+
+ vfCloseFilesInDialog = FALSE;
+}
+
+
+DoFileSaveAs(void)
+{
+ /* This routine handles input to the Save dialog box. */
+ static CHAR szDefault[ cchMaxFile ];
+ extern int vfTextOnlySave;
+ extern DoSaveAsFilenameGet(LPSTR,LPSTR,int *,int *,int * ,int *);
+ BOOL bDontDelPictures=FALSE;
+ int fWordFmt, fTextOnly, fBackup, fOldWrite;
+ CHAR szFullNameNewDoc[ cchMaxFile ]; // full name of selection
+ CHAR szShortNameNewDoc[ cchMaxFile ]; // file name of selection
+ CHAR szDocName[ cchMaxFile ]; // file name of current
+ #define szFullNameCurDoc (**((**hpdocdod)[docCur].hszFile)) // full name of current
+ #define pDod ((struct DOD *)&(**hpdocdod)[docCur])
+
+ {
+ int cch = 0;
+ CHAR szDOSPath[ cchMaxFile ];
+ if (FNormSzFile( szDOSPath, "", dtyNormal ))
+ {
+ if ((cch=CchSz( szDOSPath )-2) > 2)
+ {
+ Assert( szDOSPath[ cch ] == '\\');
+ szDOSPath [cch] = '\0';
+ }
+
+#if 0
+ if (cch > 3)
+ szDOSPath [cch] = '\\';
+#endif
+ }
+ else
+ szDOSPath[0] = '\0';
+
+ if (szFullNameCurDoc [0] != '\0')
+ { /* Set default string for filename edit area */
+ CHAR szDocPath[ cchMaxFile ]; // path to current
+
+ FreezeHp();
+ SplitSzFilename( szFullNameCurDoc, szDocPath, szDocName );
+
+ /* Default filename does not include the document's path if
+ it is == the current directory path */
+ if (WCompSz( szDOSPath, szDocPath ) == 0)
+ bltsz(szDocName, szDefault);
+ else
+ bltsz(szFullNameCurDoc, szDefault);
+
+ MeltHp();
+ }
+ else
+ {
+ szDefault[0] = szDocName[0] = '\0';
+ }
+ }
+
+ fTextOnly = vfTextOnlySave;
+ fBackup = vfBackupSave;
+ fWordFmt = vWordFmtMode & ~CONVFROMWORD;
+ fOldWrite = vfOldWriteFmt;
+
+ EnableOtherModeless(FALSE);
+
+ while(1)
+ {
+ if (!DoSaveAsFilenameGet(szDefault,szFullNameNewDoc,&fBackup,&fTextOnly,&fWordFmt,&fOldWrite))
+ goto end;
+ else
+ {
+ int dty;
+
+ if (szFullNameNewDoc[0] == '\0')
+ goto end;
+
+ if (fOldWrite || fWordFmt || fTextOnly)
+ {
+ if (!WannaDeletePictures(docCur,fOldWrite ? SF_OLDWRITE : SF_WORD))
+ continue;
+ }
+
+ StartLongOp();
+
+ szFileExtract(szFullNameNewDoc, szShortNameNewDoc);
+
+#ifdef INTL /* International version */
+ /* Read the "Microsoft Word Format" button */
+
+ /* vWordFmtMode is used in WriteFn. If true, will convert
+ to Word format, if false, no conversion is done.
+ Another value, CONVFROMWORD, can be given during an open
+ to allow saving a Word document in Write format. */
+
+ if (fWordFmt)
+ /* if set, make the default extension be doc instead of
+ wri for word docs */
+
+ dty = dtyWordDoc;
+ else
+#endif /* International version */
+
+ dty = dtyNormal;
+
+#if WINVER >= 0x300
+/* Currently: FNormSzFile *TAKES* an OEM sz, and
+ *RETURNS* an ANSI sz ..pault */
+#endif
+ if ( pDod->fReadOnly &&
+ WCompSz( szFullNameNewDoc, szFullNameCurDoc ) == 0)
+ { /* Must save read-only file under a different name */
+ Error( IDPMTReadOnly );
+ goto NSerious; /* Error not serious, stay in dialog */
+ }
+#if WINVER >= 0x300
+ else if (WCompSz(szFullNameCurDoc, szFullNameNewDoc) == 0 &&
+ vWordFmtMode == CONVFROMWORD &&
+ vfTextOnlySave == fTextOnly)
+ /* User has loaded a text file and is going
+ to save under the same name without changing
+ formats, *OR* has loaded a Word document and
+ is going to save in the same format -- don't
+ prompt "replace file?" ..pault 1/17/90 */
+ ;
+#endif
+ else if ((WCompSz(szFullNameCurDoc, szFullNameNewDoc) != 0
+#ifdef INTL /* International version */
+ /* vWordFmtMode hasn't be reset yet */
+ || ( vWordFmtMode == CONVFROMWORD)
+#endif /* International version */
+ )
+ && FExistsSzFile( dtyNormal, szFullNameNewDoc ) )
+ {
+ /* User changed the default string and specified
+ a filename for which the file already exists.
+ Or, we did a Word format conversion, forcing the .WRI
+ extension on the file, and a file with that name
+ exists.(International version only).o
+
+ Note that vfWordFmtMode will be set to True or False
+ below, so this check is made only on the first save
+ after a Word conversion.
+
+ Prompt to make sure it's ok to trash the existing one */
+
+ CHAR szFileUp[ cchMaxFile ];
+ CHAR szUserOEM[cchMaxFile]; /* ..converted to OEM */
+ CHAR szT[ cchMaxSz ];
+
+ CchCopyUpperSz( szShortNameNewDoc, szFileUp );
+ MergeStrings (IDSTRReplaceFile, szFileUp, szT);
+
+#if WINVER >= 0x300
+ /* access() expects OEM! */
+ AnsiToOem((LPSTR) szFullNameNewDoc, (LPSTR) szUserOEM);
+
+ /* Make sure we don't let someone try to save to
+ a file to which we do not have r/w permission */
+ Diag(CommSzNum("fnSaveAs: access(write_perm)==", access(szUserOEM, WRITE_PERMISSION)));
+ Diag(CommSzNum(" szExists()==", FExistsSzFile( dtyNormal, szFullNameNewDoc )));
+ if (access(szUserOEM, WRITE_PERMISSION) == -1)
+ {
+ /* THIS COULD BE A CASE OF WRITING TO A FILE
+ WITH R/O ATTRIBUTE, *OR* A SHARING ERROR!
+ IMPROVE ERROR MESSAGE HERE ..pault 11/2/89 */
+ //Error( IDPMTSDE2 );
+ Error( IDPMTReadOnly );
+ goto NSerious; /* Error not serious, stay in dialog */
+ }
+#endif
+ }
+
+ vfTextOnlySave = fTextOnly;
+ vfBackupSave = fBackup;
+ vfOldWriteFmt = fOldWrite;
+
+#ifdef INTL /* International version */
+ /* vWordFmtMode is used in WriteFn. If true, will convert
+ to Word format, if false, no conversion is done.
+ Another value, CONVFROMWORD, can be given during an open
+ to allow saving a Word document in Write format. */
+
+ vWordFmtMode = fWordFmt;
+
+#endif /* International version */
+
+ /* Record whether a backup was made or not. */
+
+ WriteProfileString( (LPSTR)szWriteProduct, (LPSTR)szBackup,
+ vfBackupSave ? (LPSTR)"1" : (LPSTR)"0" );
+
+ /* Save the document */
+
+ CmdXfSave( szFullNameNewDoc,!vfTextOnlySave, vfBackupSave, vhcArrow);
+
+ if (vfDiskFull || vfSysFull)
+ goto NSerious;
+
+ /* Case 1: Serious error. Leave the dialog. */
+ if (vfDiskError)
+ {
+ EndLongOp( vhcArrow );
+ goto end;
+ }
+
+ /* Case 2: Saved OK: set the new title, leave the dialog. */
+ else if (!WCompSz( szFullNameNewDoc, szFullNameCurDoc ))
+ {
+#if defined(OLE)
+ ObjRenamedDoc(szFullNameNewDoc);
+ ObjSavedDoc();
+#endif
+
+ SetTitle(szShortNameNewDoc);
+#if WINVER >= 0x300
+ FreeUnreferencedFns();
+#endif
+
+ /* Update the fReadOnly attribute (9.10.91) v-dougk */
+ pDod->fReadOnly = FALSE; // can't be readonly if just saved
+
+ EndLongOp( vhcArrow );
+ goto end;
+ }
+
+ /* Case 3: Nonserious error (disk full, bad path, etc.).
+ stay in dialog. */
+ else
+ {
+NSerious:
+ ferror = FALSE;
+ EndLongOp( vhcArrow );
+StayInDialog:
+ CloseEveryRfn( TRUE );
+ }
+ }
+ } // end of while(1)
+
+
+ end:
+ EnableOtherModeless(FALSE);
+
+
+} /* end of DoFileSaveAs */
+
+
+#ifdef INTL /* International version */
+
+BOOL far PASCAL DialogWordCvt( hDlg, code, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned code;
+WORD wParam;
+LONG lParam;
+{
+
+ /* This routine handles input to the Convert From Word Format dialog box. */
+
+ switch (code) {
+
+ case WM_INITDIALOG:
+ {
+ char szFileDescrip[cchMaxSz];
+ char szPrompt[cchMaxSz];
+
+ /* do not allow no convert for formatted file */
+ if (fOpenedFormatted)
+ {
+ //EnableWindow(GetDlgItem(hDlg, idiNo), false);
+ PchFillPchId(szFileDescrip, IDSTRConvertWord, sizeof(szFileDescrip));
+ }
+ else
+ PchFillPchId(szFileDescrip, IDSTRConvertText, sizeof(szFileDescrip));
+
+ MergeStrings(IDPMTConvert, szFileDescrip, szPrompt);
+ SetDlgItemText(hDlg, idiConvertPrompt, (LPSTR)szPrompt);
+ EnableOtherModeless(FALSE);
+ break;
+ }
+
+ case WM_SETVISIBLE:
+ if (wParam)
+ EndLongOp(vhcArrow);
+ return(FALSE);
+
+ case WM_ACTIVATE:
+ if (wParam)
+ vhWndMsgBoxParent = hDlg;
+ if (vfCursorVisible)
+ ShowCursor(wParam);
+ return(FALSE); /* so that we leave the activate message to the dialog
+ manager to take care of setting the focus correctly */
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ /* return one of these values:
+ idiOk - convert
+ idiCancel - cancel, no conversion
+ idiNo - read in without conversion */
+
+ case idiNo: /* User hit the "No Conversion" button */
+ if (!IsWindowEnabled(GetDlgItem(hDlg, idiNo)))
+ /* No convert is grayed -- ignore */
+ return(TRUE);
+ /* fall in */
+ case idiOk: /* User hit the "Convert" button */
+ case idiCancel:
+ break;
+ default:
+ return(FALSE);
+ }
+ /* here after ok, cancel, no */
+ OurEndDialog(hDlg, wParam);
+ break;
+
+ default:
+ return(FALSE);
+ }
+ return(TRUE);
+} /* end of DialogWordCvt */
+
+/* International version */
+#else
+BOOL far PASCAL DialogWordCvt( hDlg, code, wParam, lParam )
+HWND hDlg; /* Handle to the dialog box */
+unsigned code;
+WORD wParam;
+LONG lParam;
+{
+ Assert(FALSE);
+} /* end of DialogWordCvt */
+#endif /* Non Iternational version */
+
+
+
+
+IdConfirmDirty()
+{ /* Put up a message box saying docCur "Has changed. Save changes?
+ Yes/No/Cancel". Return IDYES, IDNO, or IDCANCEL. */
+ extern HWND vhWnd;
+ extern CHAR szUntitled[];
+ extern HANDLE hszDirtyDoc;
+ LPSTR szTmp = MAKELP(hszDirtyDoc,0);
+ CHAR szPath[ cchMaxFile ];
+ CHAR szName[ cchMaxFile ];
+ CHAR szMsg[ cchMaxSz ];
+ CHAR (**hszFile)[]=(**hpdocdod)[docCur].hszFile;
+
+ if ((**hszFile)[0] == '\0')
+ CchCopySz( szUntitled, szName );
+ else
+ SplitSzFilename( *hszFile, szPath, szName );
+
+ wsprintf(szMsg,szTmp,(LPSTR)szName);
+
+ return IdPromptBoxSz( vhWnd, szMsg, MB_YESNOCANCEL | MB_ICONEXCLAMATION );
+}
+
+
+
+
+SplitSzFilename( szFile, szPath, szName )
+CHAR *szFile;
+CHAR *szPath;
+CHAR *szName;
+{ /* Split a normalized filename into path and bare name components.
+ By the rules of normalized filenames, the path will have a drive
+ letter, and the name will have an extension. If the name is null,
+ we provide the default DOS path and a null szName */
+
+ szPath [0] = '\0';
+ szName [0] = '\0';
+
+ if (szFile[0] == '\0')
+ {
+#if WINVER >= 0x300
+ /* Currently: FNormSzFile *TAKES* an OEM sz, and
+ *RETURNS* an ANSI sz ..pault */
+#endif
+ FNormSzFile( szPath, "", dtyNormal ); /* Use default DOS drive & path */
+ }
+ else
+ {
+ CHAR *pch;
+ int cch;
+
+ lstrcpy(szPath,(LPSTR)szFile);
+
+ pch = szPath + lstrlen(szPath) - 1; // point to last character
+
+#ifdef DBCS
+ do{
+ CHAR *szptr;
+ szptr = (CHAR near *)AnsiPrev(szFile,pch);
+ if(szptr == pch)
+ {
+ break; /* not to get halted. */
+ }
+ pch = szptr;
+ } while(*pch != '\\');
+#else /* DBCS */
+ while (pch != szPath)
+ if (*(pch-1) == '\\')
+ break;
+ else
+ --pch;
+
+#endif
+
+ lstrcpy(szName,(LPSTR)pch);
+
+#ifdef DBCS
+ pch=(CHAR near *)AnsiPrev(szFile,pch);
+ *pch = '\0';
+#else
+ *(pch-1) = '\0';
+#endif
+
+ }
+}
+
+
+BOOL CheckEnableButton(hCtlEdit, hCtlEnable)
+HANDLE hCtlEdit; /* handle to edit item */
+HANDLE hCtlEnable; /* handle to control which is to enable or disable */
+{
+register BOOL fEnable = SendMessage(hCtlEdit, WM_GETTEXTLENGTH, 0, 0L);
+
+ EnableWindow(hCtlEnable, fEnable);
+ return(fEnable);
+} /* end of CheckEnableButton */
+
+
+
+
+/*** FDeleteFn - Delete a file
+ *
+ *
+ *
+ */
+
+int FDeleteFn(fn)
+int fn;
+{ /* Delete a file & free its fn slot */
+ /* Returns TRUE if the file was successfully deleted or if it was not
+ found in the first place; FALSE if the file exists but
+ cannot be deleted */
+
+int f = FALSE;
+
+if (FEnsureOnLineFn( fn )) /* Ensure disk w/ file is in drive */
+ {
+ CloseFn( fn ); /* Ensure file closed */
+
+ f = FDeleteFile( &(**(**hpfnfcb) [fn].hszFile) [0] );
+ }
+
+FreeFn( fn ); /* We free the fn even if the file delete failed */
+
+return f;
+}
+
+
+
+FDeleteFile( szFileName )
+CHAR szFileName[];
+{ /* Delete szFilename. Return TRUE if the file was deleted,
+ or there was no file by that name; FALSE otherwise.
+ Before deleting the file, we ask all other WRITE instances whether
+ they need it; if one does, we do not delete and return FALSE */
+
+HANDLE HszGlobalCreate( CHAR * );
+int fpe=0;
+int fOk;
+ATOM a;
+
+if ((a = GlobalAddAtom( szFileName )) != NULL)
+ {
+ fOk = WBroadcastMsg( wWndMsgDeleteFile, a, (LONG) 0, FALSE );
+ if (fOk)
+ { /* Ok to delete, no other instance needs it */
+ fpe = FpeDeleteSzFfname( szFileName );
+ }
+#ifdef DEBUG
+ else
+ Assert( !FIsErrFpe( fpe ) );
+#endif
+ GlobalDeleteAtom( a );
+ }
+
+ /* OK if: (1) Deleted OK (2) Error was "File not found" */
+return (!FIsErrFpe(fpe)) || fpe == fpeFnfError;
+}
+
+
+
+
+FDeleteFileMessage( a )
+ATOM a;
+{ /* We are being notified that the file hName is being deleted.
+ a is a global atom. (Was global handle before fixing for NT 3.5)
+ Return TRUE = Ok to delete; FALSE = Don't delete, this instance
+ needs the file */
+
+ LPCH lpch;
+ CHAR sz[ cchMaxFile ];
+
+ Scribble( 5, 'D' );
+
+ if (GlobalGetAtomName( a, sz, sizeof(sz)) != 0)
+ {
+ if (FnFromSz( sz ) != fnNil)
+ {
+ Scribble( 4, 'F' );
+ return FALSE;
+ }
+ }
+
+ Scribble( 4, 'T' );
+ return TRUE;
+}
+
+
+
+
+/*** FpeRenameFile - rename a file
+ *
+ */
+
+int FpeRenameFile(szFileCur, szFileNew) /* Both filenames expected in ANSI */
+CHAR *szFileCur, *szFileNew;
+{
+ /* Rename a file. Return fpeNoErr if successful; error code if not. */
+int fn = FnFromSz( szFileCur );
+int fpe;
+CHAR (**hsz)[];
+HANDLE hName;
+HANDLE hNewName;
+
+#if WINVER >= 0x300
+/* The szPathName field in rgbOpenFileBuf is now treated as OEM
+ as opposed to ANSI, so we must do a conversion. 12/5/89..pault */
+CHAR szFileOem[cchMaxFile];
+AnsiToOem((LPSTR)szFileNew, (LPSTR)szFileOem);
+#define sz4OpenFile szFileOem
+#else
+#define sz4OpenFile szFileNew
+#endif
+
+/* If this is a file we know about, try to make sure it's on line */
+
+if (fn != fnNil)
+ if (FEnsureOnLineFn( fn ))
+ {
+ FFlushFn( fn ); /* just in case */
+ CloseFn( fn );
+ }
+ else
+ return fpeHardError;
+
+/* if the file exists on disk then try to rename it */
+if (szFileCur[0] != 0 && FExistsSzFile(dtyAny, szFileCur))
+ {
+ int fpe=FpeRenameSzFfname( szFileCur, szFileNew );
+
+ if ( FIsErrFpe( fpe ) )
+ /* Rename failed -- return error code */
+ return fpe;
+ }
+else
+ return fpeNoErr;
+
+ /* Inform other instances of WRITE */
+if ((hName = HszGlobalCreate( szFileCur )) != NULL)
+ {
+ if ((hNewName = HszGlobalCreate( szFileNew )) != NULL)
+ {
+ WBroadcastMsg( wWndMsgRenameFile, hName, (LONG)hNewName, -1 );
+ GlobalFree( hNewName );
+ }
+ GlobalFree( hName );
+ }
+
+if (fn != fnNil)
+ { /* Rename current FCB for file if there is one */
+ struct FCB *pfcb;
+
+ FreeH((**hpfnfcb)[fn].hszFile);
+ hsz = HszCreate((PCH)szFileNew);
+ pfcb = &(**hpfnfcb) [fn];
+ pfcb->hszFile = hsz;
+
+ bltbyte( sz4OpenFile, ((POFSTRUCT)pfcb->rgbOpenFileBuf)->szPathName,
+ umin( CchSz( sz4OpenFile ), cchMaxFile ) );
+
+#ifdef DFILE
+CommSzSz("FpeRenameFile szFileNew==",szFileNew);
+CommSzSz(" szFileCur==",szFileCur);
+CommSzSz(" szFileNewOem==",szFileOem);
+#endif
+
+#ifdef ENABLE
+ pfcb->fOpened = FALSE; /* Signal OpenFile that it must open
+ from scratch, not OF_REOPEN */
+#endif
+ }
+
+return fpeNoErr;
+}
+
+
+
+
+RenameFileMessage( hName, hNewName )
+HANDLE hName;
+HANDLE hNewName;
+{ /* We are being notified by another instance of WRITE that the name
+ of file hName is being changed to hNewName. hName and hNewName
+ are WINDOWS global handles */
+
+ LPCH lpchName;
+ LPCH lpchNewName;
+
+ Scribble( 5, 'R' );
+ Scribble( 4, ' ' );
+
+ if ((lpchName = GlobalLock( hName )) != NULL)
+ {
+ if ((lpchNewName = GlobalLock( hNewName )) != NULL)
+ {
+ CHAR (**hsz) [];
+ CHAR szName[ cchMaxFile ];
+ CHAR szNewName[ cchMaxFile ];
+ int fn;
+
+ bltszx( lpchName, (LPCH) szName );
+ bltszx( lpchNewName, (LPCH) szNewName );
+
+ if ((fn=FnFromSz( szName )) != fnNil &&
+ !FNoHeap(hsz = HszCreate( szNewName )))
+ {
+#if WINVER >= 0x300
+ /* The szPathName field in rgbOpenFileBuf is now treated as OEM
+ as opposed to ANSI, so we must do a conversion. 12/5/89..pault */
+ CHAR szNewOem[cchMaxFile];
+ AnsiToOem((LPSTR)szNewName, (LPSTR)szNewOem);
+ bltsz( szNewOem, ((POFSTRUCT)((**hpfnfcb) [fn].rgbOpenFileBuf))->szPathName );
+#else
+ bltsz( szNewName, ((POFSTRUCT)((**hpfnfcb) [fn].rgbOpenFileBuf))->szPathName );
+#endif
+
+#ifdef ENABLE
+ (**hpfnfcb) [fn].fOpened = FALSE;
+#endif
+ FreeH( (**hpfnfcb) [fn].hszFile );
+ (**hpfnfcb) [fn].hszFile = hsz;
+ }
+ GlobalUnlock( hNewName );
+ }
+ GlobalUnlock( hName );
+ }
+}
+
+
+
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+STATIC int messageBR;
+STATIC WORD wParamBR;
+STATIC LONG lParamBR;
+STATIC int wStopBR;
+
+STATIC int wResponseBR;
+
+STATIC FARPROC lpEnumAll=NULL;
+STATIC FARPROC lpEnumChild=NULL;
+
+
+WBroadcastMsg( message, wParam, lParam, wStop )
+int message;
+WORD wParam;
+LONG lParam;
+WORD wStop;
+{ /* Send a message to the document child windows (MDOC) of all
+ currently active instances of WRITE (except ourselves).
+ Continue sending until all instances have been notified, or until
+ one returns the value wStop as a response to the message.
+ Return the response given by the last window notified, or
+ -1 if no other instances of WRITE were found */
+
+extern HANDLE hMmwModInstance;
+int FAR PASCAL BroadcastAllEnum( HWND, LONG );
+int FAR PASCAL BroadcastChildEnum( HWND, LONG );
+
+ messageBR = message;
+ wParamBR = wParam;
+ lParamBR = lParam;
+ wStopBR = wStop;
+ wResponseBR = -1;
+
+ if (lpEnumAll == NULL)
+ {
+ lpEnumAll = MakeProcInstance( (FARPROC) BroadcastAllEnum, hMmwModInstance );
+ lpEnumChild = MakeProcInstance( (FARPROC) BroadcastChildEnum, hMmwModInstance );
+ }
+
+ EnumWindows( lpEnumAll, (LONG)0 );
+ return wResponseBR;
+}
+
+
+
+int FAR PASCAL BroadcastAllEnum( hwnd, lParam )
+HWND hwnd;
+LONG lParam;
+{ /* If hwnd has the class of a WRITE parent (menu) window, call
+ (*lpEnumChild)() for each of its children and return
+ the value returned by EnumChildWindows
+ If the window does not have the class of a WRITE parent, do nothing
+ and return TRUE */
+ extern CHAR szParentClass[];
+ extern HWND hParentWw;
+
+ if ( (hwnd != hParentWw) && FSameClassHwndSz( hwnd, szParentClass ) )
+ return EnumChildWindows( hwnd, lpEnumChild, (LONG) 0 );
+ else
+ return TRUE;
+}
+
+
+
+int FAR PASCAL BroadcastChildEnum( hwnd, lParam )
+HWND hwnd;
+LONG lParam;
+{ /* If hwnd is of the same class as a WRITE child (document) window,
+ send the message { messageBR, wParamBR, lParamBR } to it, else
+ return TRUE;
+ If the message is sent, return FALSE if the message return value
+ matched wStopBR; TRUE if it did not match.
+ Set wMessageBR to the message return value.
+ */
+ extern CHAR szDocClass[];
+ extern HWND vhWnd;
+
+ Assert( hwnd != vhWnd );
+
+ if (FSameClassHwndSz( hwnd, szDocClass ))
+ { /* WRITE DOCUMENT WINDOW: pass message along */
+ wResponseBR = SendMessage( hwnd, messageBR, wParamBR, lParamBR );
+ return wResponseBR != wStopBR;
+ }
+ else
+ return TRUE;
+}
+
+
+
+FSameClassHwndSz( hwnd, szClass )
+HWND hwnd;
+CHAR szClass[];
+{ /* Compare the Class name of hWnd with szClass; return TRUE
+ if they match, FALSE otherwise. */
+
+#define cchClassMax 40 /* longest class name (for compare purposes) */
+
+ CHAR rgchWndClass[ cchClassMax ];
+ int cbCopied;
+
+ /* Count returned by GetClassName does not include terminator */
+ /* But, the count passed in to it does. */
+ cbCopied = GetClassName( hwnd, (LPSTR) rgchWndClass, cchClassMax ) + 1;
+ if (cbCopied <= 1)
+ return FALSE;
+
+ rgchWndClass[ cbCopied - 1 ] = '\0';
+
+ return WCompSz( rgchWndClass, szClass ) == 0;
+}
+
+
+FConfirmSave()
+{ /* Give the user the opportunity to save docCur, if it is dirty.
+ Return 1 - Document Saved OR user elected not to save changes
+ OR document was not dirty
+ 0 - User selected "Cancel" or Error during SAVE */
+extern HANDLE hMmwModInstance;
+extern HANDLE hParentWw;
+extern int vfTextOnlySave, vfBackupSave;
+struct DOD *pdod=&(**hpdocdod)[docCur];
+
+#if defined(OLE)
+ if (CloseUnfinishedObjects(FALSE) == FALSE)
+ return FALSE;
+#endif
+
+ if (pdod->fDirty)
+ { /* doc has been edited, offer confirm/save before quitting */
+ switch ( IdConfirmDirty() )
+ {
+ case IDYES:
+ {
+#if 0
+#if defined(OLE)
+ if (CloseUnfinishedObjects(TRUE) == FALSE)
+ return FALSE;
+#endif
+#endif
+
+ if ( (**(pdod->hszFile))[0] == '\0' )
+ goto SaveAs;
+
+#ifdef INTL /* International version */
+ /* if saving after a Word conversion, bring up dialog
+ box to allow backup/ rename. */
+
+ else if ( vWordFmtMode == CONVFROMWORD)
+ goto SaveAs;
+#endif /* International version */
+
+ else if (pdod->fReadOnly)
+ {
+ extern int ferror;
+
+ /* Read-only doc: tell the user to save under a different name */
+
+ Error( IDPMTReadOnly );
+ ferror = FALSE; /* Not really an error */
+
+SaveAs:
+ fnSaveAs(); /* Bring up "save as" dialog box */
+ pdod = &(**hpdocdod)[docCur];
+ if (pdod->fDirty)
+ /* Save failed or was aborted */
+ return FALSE;
+ }
+ else
+ {
+ CmdXfSave( *pdod->hszFile, !vfTextOnlySave, vfBackupSave, vhcArrow);
+
+#if defined(OLE)
+ if (!ferror)
+ ObjSavedDoc();
+#endif
+ }
+ if (ferror)
+ /* Don't quit if we got a disk full error */
+ return FALSE;
+ }
+ break;
+
+ case IDNO:
+#if 0
+#if defined(OLE)
+ if (CloseUnfinishedObjects(FALSE) == FALSE)
+ return FALSE;
+#endif
+#endif
+ break;
+
+ case IDCANCEL:
+ default:
+ return FALSE;
+ }
+ }
+#if 0
+#if defined(OLE)
+ else /* not dirty */
+ if (CloseUnfinishedObjects(FALSE) == FALSE)
+ return FALSE;
+#endif
+#endif
+
+ return TRUE;
+}
+
+
+
+
+PreloadSaveSegs()
+{
+#ifdef GREGC /* kludge to get around the windows kernel bug for now */
+ LoadF( PurgeTemps ); /* TRANS4 */
+ LoadF( IbpEnsureValid ); /* FILE (includes doslib) */
+ LoadF( FnCreateSz ); /* CREATEWW */
+ LoadF( ClobberDoc ); /* EDIT */
+ LoadF( FNormSzFile ); /* FILEUTIL */
+ LoadF( CmdXfSave ); /* TRANS2 */
+#endif
+}
+
+
+
+
+int CchCopyUpperSz(pch1, pch2)
+register PCH pch1;
+register PCH pch2;
+{
+int cch = 0;
+while ((*pch2 = ChUpper(*pch1++)) != 0)
+ {
+#ifdef DBCS /* KenjiK '90-11-20 */
+ if(IsDBCSLeadByte(*pch2))
+ {
+ pch2++;
+ *pch2 = *pch1++;
+ cch++;
+ }
+#endif
+ pch2++;
+ cch++;
+ }
+return cch;
+} /* end of C c h C o p y U p p e r S z */
+
+#ifdef DBCS // AnsiNext for near call.
+static char NEAR *MyAnsiNext(char *sz)
+{
+ if(!*sz) return sz;
+
+ sz++;
+ if(IsDBCSLeadByte(*sz)) return (sz+1);
+ else return sz;
+}
+#endif
+
+#if 0
+/* ** Given filename or partial filename or search spec or partial
+ search spec, add appropriate extension. */
+
+/*
+ fSearching is true when we want to add \*.DOC to the string -
+ i.e., we are seeing if string szEdit is a directory. If the string
+ is .. or ends in: or \, we know we have a directory name, not a file
+ name, and so add \*.DOC or *.DOC to the string. Otherwise, if
+ fSearching is true ans szEdit has no wildcard characters,
+ add \*.DOC to the string, even if the string contains a period
+ (directories can have extensions). If fSearching is false, we will
+ add .DOC to the string if no period is found in the last file/directory
+ name.
+
+ Note the implicit assumption here that \ and not / will be used as the
+ path character. It is held in the defined variable PATHCHAR, but we
+ don't handle DOS setups where the / is path and - is the switch character.
+*/
+
+#define PATHCHAR ('\\')
+
+NEAR DlgAddCorrectExtension(szEdit, fSearching)
+CHAR *szEdit;
+BOOL fSearching;
+{
+ register CHAR *pchLast;
+ register CHAR *pchT;
+ int ichExt;
+ BOOL fDone = FALSE;
+ int cchEdit;
+
+ pchT = pchLast = (szEdit + (cchEdit = CchSz(szEdit) - 1) - 1);
+
+ /* Is szEdit a drive letter followed by a colon (not a filename) ? */
+ if (cchEdit == 2
+ && *pchLast == ':')
+ /* don't use 0 or will interpret "z:" incorrectly as "z:\" ..pault */
+ ichExt = 1;
+ /* how about ".." (also not a file name)? */
+ else if (cchEdit == 2
+ && (*pchLast == '.' && *(pchLast-1) == '.'))
+ ichExt = 0;
+ else if (*pchLast == PATHCHAR) /* path character */
+ ichExt = 1;
+ else
+ {
+ if (fSearching)
+ {
+ /* any wild card chars? if so, is really a file name */
+ if (FSearchSpec(szEdit))
+ return;
+ ichExt = 0;
+ }
+ else
+ {
+ ichExt = 2;
+ for (; pchT > szEdit; pchT--) {
+ if (*pchT == '.') {
+ return;
+ }
+ if (*pchT == PATHCHAR) {
+ /* path character */
+ break;
+ }
+ }
+ }
+
+ }
+ if (CchSz(szExtSearch+ichExt) + cchEdit > cchMaxFile)
+ Error(IDPMTBadFilename);
+ else
+#ifdef DBCS
+ CchCopySz((szExtSearch+ichExt), AnsiNext(pchLast));
+#else
+ CchCopySz((szExtSearch+ichExt), (pchLast+1));
+#endif
+}
+
+
+/* ** return TRUE iff 0 terminated string contains a '*' or '\' */
+BOOL (NEAR FSearchSpec(sz))
+register CHAR *sz;
+{
+
+#ifdef DBCS
+ for (; *sz;sz=AnsiNext(sz)) {
+#else
+ for (; *sz;sz++) {
+#endif
+ if (*sz == '*' || *sz == '?')
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#endif
+
+szFileExtract(szNormFileName, szExtFileName)
+CHAR *szNormFileName; /* input: normalized file name */
+CHAR *szExtFileName; /* output: simple file name with extension added to */
+{
+ CHAR *pchLast, *pchT;
+#ifdef DBCS /* KenjiK(MSKK) '90-11-20 */
+ for(pchT=szNormFileName;*pchT;pchT++);
+ pchLast = pchT;
+ do {
+ pchT = AnsiPrev(szNormFileName,pchT);
+ if (*pchT == '\\')
+ break;
+ } while(pchT > szNormFileName);
+
+#else /* not DBCS */
+
+ pchLast = pchT = szNormFileName + CchSz(szNormFileName) - 1;
+
+ while (pchT > szNormFileName)
+ {
+ if (*pchT == '\\')
+ break;
+ pchT --;
+ }
+#endif
+
+ bltbyte(pchT + 1, szExtFileName, pchLast - pchT);
+ //DlgAddCorrectExtension(szExtFileName, FALSE);
+}
+
+
+
+
+#ifdef INTL /* International version */
+
+/* ** return TRUE if file opened is in Microsoft Word format */
+BOOL FInWordFormat(fn)
+int fn;
+{
+register struct FCB *pfcb;
+int cchT;
+ /* Assumption: this routine has been called after FnOpenSz, which
+ has already determined whether the file is formatted,
+ and if the pnMac entry was 0, it set pnMac to be the same
+ as pnFfntb in the file's fcb. So a Word file is a formatted
+ file whose pnMac and pnFfntb are the same.
+
+ We are also pretending that unformatted files are word format files
+ so we will bring up a dialog box allowing character set conversion. */
+
+ pfcb = &(**hpfnfcb)[fn];
+ if (pfcb->fFormatted == false) /* unformatted treated as a word file */
+ return (true);
+
+ return (pfcb->pnMac == pfcb->pnFfntb);
+}
+#endif /* International version */
+
+
+#ifdef INTL /* International version */
+void ConvertFromWord ()
+{
+
+ /* vWordFmtMode is used by FnWriteFile to translate the
+ Word file character set to ANSI. We leave it set to
+ CONVFROMWORD so that the next save can check if there was a
+ file with extension of szExtDoc.If there is no such file,
+ vWordFmtMode is set to true or false by the save dialog code.
+
+ *** as of 2/14/86, no backup is made, but code in CleanDoc checks for
+ vWordFmtMode=CONVFROMWORD, and saves without renaming the word
+ file instead of making an optional backup
+
+ *** as of 12/3/89, FreeUnreferencedFns() is removing the
+ lock on files not referenced by pieces in any documents, so
+ the word doc or text file being converted FROM is not being
+ "locked" and another app can grab it! I'm correcting this
+ in FreeUnreferencedFns() ..pault
+ */
+
+ extern CHAR szExtDoc[];
+ struct DOD *pdod=&(**hpdocdod)[docCur];
+
+ vWordFmtMode = CONVFROMWORD; /* will stay this value until save */
+ vfBackupSave = 1; /* force next save to default to backing up */
+ /* always a formatted save, no backup. */
+ CmdXfSave( *pdod->hszFile, true, false, vhcArrow);
+
+#if defined(OLE)
+ if (!ferror)
+ ObjSavedDoc();
+#endif
+}
+#endif /* International version */
+
+
+#ifdef INTL /* International version */
+TestWordCvt (fn, hWnd)
+int fn;
+HWND hWnd;
+{
+int wordVal;
+#ifndef INEFFLOCKDOWN
+FARPROC lpDialogWordCvt = MakeProcInstance(DialogWordCvt, hMmwModInstance);
+ if (!lpDialogWordCvt)
+ {
+ WinFailure();
+ return(fFalse);
+ }
+#endif
+
+/* This routine returns the following values:
+-1 means dialog box failed (error already sent)
+-2 means cancel without conversion.
+FALSE means not a word document.
+TRUE means convert this word document.
+Its parent may change depending on the caller.
+*/
+
+if (!(wordVal = FInWordFormat (fn)))
+return (FALSE); /* not a word doc */
+
+/* in word format - ask for conversion */
+/* the cvt to word dialog returns 3 values
+ other than -1:
+ idiOk - convert
+ idiCancel - cancel, no conversion
+ idiNo - read in without conversion
+ vfBackupSave set to reflect whether backup is made */
+ /* Note it is a child of this dialog */
+
+fOpenedFormatted = (**hpfnfcb)[fn].fFormatted; /* used in dialog func */
+
+#ifdef DBCS /* was in KKBUGFIX */
+// [yutakan:05/17/91] (I don't know why) sometimes hWnd would be invalid.
+if (!IsWindow(hWnd)) hWnd = hParentWw;
+#endif
+
+if ((wordVal = (OurDialogBox( hMmwModInstance,
+ MAKEINTRESOURCE(dlgWordCvt), hWnd,
+ lpDialogWordCvt))) == -1)
+ {
+#if WINVER >= 0x300
+ WinFailure();
+#else
+ Error(IDPMTNoMemory);
+#endif
+ }
+
+#ifndef INEFFLOCKDOWN
+ FreeProcInstance(lpDialogWordCvt);
+#endif
+
+ /* return -1 if either out of memory or no conversion desired */
+ /* will convert an unformatted file if No is the dialog response */
+ switch (wordVal)
+
+ {
+ case idiNo: /* User hit the "No Conversion" button */
+ return(FALSE); /* treat as non-word file */
+ case idiOk: /* User hit the "Convert" button */
+ return(TRUE);
+
+ case idiCancel:
+ return (-2);
+
+ case -1:
+ default:
+ return (-1);
+ }
+
+}
+#endif /* Kanji / International version */
+
+
+/* ********** routines for doing message relocation ******* */
+
+VOID MergeInit()
+/* get merge spec, guaranteed to be 2 characters, into variable wMerge */
+{
+char sz[10];
+
+ PchFillPchId( sz, IDS_MERGE1, sizeof(sz) );
+ wMerge = *(unsigned *)sz;
+}
+
+
+BOOL MergeStrings (idSrc, szMerge, szDst)
+IDPMT idSrc;
+CHAR *szMerge;
+CHAR *szDst;
+{
+/* get message from idSrc. Scan it for merge spec. If found, insert string
+ szMerge at that point, then append the rest of the message. NOTE!
+ merge spec guaranteed to be 2 characters. wMerge loaded at init by
+ MergeInit. Returns true if merge done, false otherwise.
+*/
+
+CHAR szSrc[cchMaxSz];
+register CHAR *pchSrc;
+register CHAR *pchDst;
+
+/* get message from resource file */
+
+ PchFillPchId( szSrc, idSrc, sizeof(szSrc) );
+ pchSrc = szSrc;
+ pchDst = szDst;
+
+ /* find merge spec if any */
+
+ while (*(unsigned *)pchSrc != wMerge)
+ {
+ *pchDst++ = *pchSrc;
+
+ /* if we reach the end of string before merge spec, just return false */
+
+ if (!*pchSrc++)
+ return FALSE;
+ }
+
+
+ /* if merge spec found, insert szMerge there. (check for null merge str */
+
+ if (szMerge)
+ while (*szMerge)
+ *pchDst++ = *szMerge++;
+
+ /* jump over merge spec */
+ pchSrc++;
+ pchSrc++;
+
+ /* append rest of string */
+
+ while (*pchDst++ = *pchSrc++)
+ ;
+ return TRUE;
+
+}
+
+#include "propdefs.h"
+BOOL DocHasPictures(int doc)
+{
+ extern struct PAP vpapAbs;
+ typeCP cpMac = CpMacText(doc),cpNow;
+ for ( cpNow = cp0; cpNow < cpMac; cpNow = vcpLimParaCache )
+ {
+ CachePara( doc, cpNow );
+ if (vpapAbs.fGraphics)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL WannaDeletePictures(int doc, int fWhichFormat)
+/* assume if SF_OLDWRITE that vcObjects is set */
+{
+ CHAR szBuf[cchMaxSz];
+ BOOL bDoPrompt;
+
+ if (fWhichFormat == SF_OLDWRITE)
+ /* warn that OLE pictures will be deleted */
+ {
+ if (bDoPrompt = (vcObjects > 0))
+ PchFillPchId( szBuf, IDPMTDelObjects, sizeof(szBuf) );
+ }
+ else if (fWhichFormat == SF_WORD)
+ /* warn that all pictures will be deleted */
+ {
+ if (bDoPrompt = DocHasPictures(docCur))
+ PchFillPchId( szBuf, IDPMTDelPicture, sizeof(szBuf) );
+ }
+ else
+ return TRUE;
+
+ if (bDoPrompt)
+ return (IdPromptBoxSz( vhWnd, szBuf, MB_YESNO | MB_ICONEXCLAMATION ) == IDYES);
+ else
+ return TRUE;
+}
+
+BOOL NEAR PASCAL CanReadEveryFile(char *szFilename)
+{
+ extern int fnMac;
+ int fn;
+ BOOL bRetval=TRUE;
+
+ FreezeHp();
+ for (fn = 0; fn < fnMac; fn++)
+ {
+ if ((**hpfnfcb)[fn].fDisableRead)
+ {
+ /* see if still can't read */
+ if (!FAccessFn( fn, dtyNormal ))
+ {
+ char szMsg[cchMaxSz];
+ ferror = FALSE;
+ MergeStrings (IDPMTCantRead, szFilename, szMsg);
+ IdPromptBoxSz(vhWndMsgBoxParent ? vhWndMsgBoxParent : hParentWw,
+ szMsg, MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
+ {
+ bRetval = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ MeltHp();
+ return bRetval;
+}
+
+
diff --git a/private/mvdm/wow16/write/trans4.c b/private/mvdm/wow16/write/trans4.c
new file mode 100644
index 000000000..1a48fabd1
--- /dev/null
+++ b/private/mvdm/wow16/write/trans4.c
@@ -0,0 +1,441 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* trans4.c -- routines brought from trans2.c due to compiler stack overflow */
+
+#define NOWINMESSAGES
+#define NOVIRTUALKEYCODES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "propdefs.h"
+#define NOUAC
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "fkpdefs.h"
+#include "editdefs.h"
+#include "printdef.h"
+#define NOKCCODES
+#include "ch.h"
+#define NOSTRUNDO
+#define NOSTRERRORS
+#include "str.h"
+#include "debug.h"
+#include "fontdefs.h"
+
+
+CHAR *PchGetPn();
+CHAR *PchFromFc();
+typePN PnAllocT2();
+struct PGTB **HpgtbGet();
+
+
+extern int vfnWriting;
+extern struct BPS *mpibpbps;
+extern typeTS tsMruBps;
+extern int vibpWriting;
+extern CHAR (**vhrgbSave)[];
+extern struct DOD (**hpdocdod)[];
+extern int docCur;
+extern int docMac;
+extern int docScrap;
+extern int docUndo;
+extern struct FCB (**hpfnfcb)[];
+extern int fnMac;
+extern int wwMac;
+extern int vfBuffersDirty;
+extern int vfDiskFull;
+extern int vfDiskError;
+extern typeCP vcpFetch;
+extern CHAR *vpchFetch;
+extern int vccpFetch;
+extern typeFC fcMacPapIns;
+extern typeFC fcMacChpIns;
+extern typeCP vcpLimParaCache;
+extern struct FKPD vfkpdCharIns;
+extern struct FKPD vfkpdParaIns;
+extern struct PAP vpapPrevIns;
+extern struct PAP vpapAbs;
+extern struct PAP *vppapNormal;
+extern struct CHP vchpNormal;
+extern struct CHP vchpInsert;
+extern struct CHP vchpFetch;
+extern unsigned cwHeapFree;
+extern struct FPRM fprmCache;
+
+extern int ferror;
+extern CHAR szExtBackup[];
+extern CHAR (**hszTemp)[];
+
+#ifdef INTL /* International version */
+
+extern int vWordFmtMode; /* used during saves. If false, no conversion is
+ done. True is convert to Word format,CVTFROMWORD
+ is translate chars from Word character set at
+ save */
+#endif /* International version */
+
+
+/*** WriteUnformatted - Write unformatted document to file
+ *
+ *
+ *
+ */
+
+
+WriteUnformatted(fn, doc)
+int fn;
+int doc;
+{
+ extern typeCP vcpLimParaCache;
+ extern typeCP cpMinCur, cpMacCur;
+ typeCP cpMinCurT = cpMinCur;
+ typeCP cpMacCurT = cpMacCur;
+ typeCP cpNow;
+ typeCP cpLimPara;
+ typeCP cpMac = (**hpdocdod) [doc].cpMac;
+
+ /* Expand range of interest to whole document (for CachePara) */
+
+ cpMinCur = cp0;
+ cpMacCur = cpMac;
+
+ /* Loop on paras */
+
+ cpNow = cp0;
+ for ( cpNow = cp0; cpNow < cpMac; cpNow = cpLimPara )
+ {
+LRestart:
+ CachePara( doc, cpNow );
+ cpLimPara = vcpLimParaCache;
+ if (vpapAbs.fGraphics)
+ continue;
+
+ /* Now write out the para, a run at a time */
+
+
+ while ((cpNow < cpLimPara && cpNow < cpMacCur)
+ && !(vfDiskFull || vfDiskError))
+ {
+ extern typeCP CpMin();
+ extern int vccpFetch;
+ int ccpAccept;
+ CHAR bufT[cbSector + 1];
+ CHAR *pch;
+
+ FetchCp( doc, cpNow, 0, fcmChars + fcmNoExpand );
+ Assert (vccpFetch <= cbSector);
+#ifdef WINVER >= 0x300
+ if (vccpFetch == 0)
+ {
+ /* In this case we've had an error with a "hole" in the
+ the piece table due to hitting a mem-alloc error -- we
+ won't ever advance cpNow! To get around this we bump
+ cpNow to the cpMin of the next piece and continue by
+ doing a CachePara on the next piece 3/14/90..pault */
+
+ struct PCTB *ppctb = *(**hpdocdod)[doc].hpctb;
+ int ipcd = IpcdFromCp(ppctb, cpNow);
+ struct PCD *ppcd = &ppctb->rgpcd[ipcd + 1]; /* NEXT piece */
+
+ cpNow = ppcd->cpMin;
+ goto LRestart;
+ }
+#endif
+ ccpAccept = (int) CpMin( (typeCP)vccpFetch, (cpLimPara - cpNow));
+
+#ifdef INTL /* International version */
+ if (vWordFmtMode != TRUE) /* no character set conversion */
+#endif /* International version */
+
+ WriteRgch( fn, vpchFetch, ccpAccept );
+
+#ifdef INTL /* International version */
+ else /* convert to OEM set */
+ {
+ /* convert ANSI chars to OEM for Word format file */
+ /* load chars into bufT and translate to OEM
+ chars, and write out */
+ pch = (CHAR *) bltbyte(vpchFetch, bufT,
+ (int)ccpAccept);
+ *pch = '\0';
+ AnsiToOem((LPSTR)bufT, (LPSTR)bufT);
+ WriteRgch(fn, bufT, (int)ccpAccept);
+ }
+#endif /* International version */
+
+ cpNow += ccpAccept;
+ }
+ if ((vfDiskFull || vfDiskError))
+ break;
+
+ }
+
+ /* Restore cpMinCur, cpMacCur */
+
+ cpMinCur = cpMinCurT;
+ cpMacCur = cpMacCurT;
+}
+
+
+
+
+/*** PurgeTemps - Delete all temporary files not referenced in any doc
+ *
+ */
+
+PurgeTemps()
+{ /* Delete all temporary files not referenced in any doc */
+int fn;
+struct FCB *pfcb, *mpfnfcb;
+struct DOD *pdod;
+struct PCD *ppcd;
+int doc;
+
+Assert(fnScratch == 0);
+FreezeHp();
+mpfnfcb = &(**hpfnfcb)[0];
+
+#ifdef DFILE
+ CommSz("PurgeTemps:\n\r");
+#endif
+
+/* Prime the doc/piece table loop */
+/* Find the first valid doc (there is guaranteed to be one) */
+/* Set up doc, pdod, ppcd */
+for (doc = 0, pdod = &(**hpdocdod)[0]; pdod->hpctb == 0; doc++, pdod++)
+ continue;
+ppcd = &(**pdod->hpctb).rgpcd[0];
+
+/* Now go through the deletable files, looking for references */
+for (fn = fnScratch + 1, pfcb = &mpfnfcb[fnScratch + 1];
+ fn < fnMac; fn++, pfcb++)
+ { /* For each file (don't bother with scratch file) */
+ /* Fn must be valid, deletable, and not previously referenced */
+ /* if (pfcb->rfn != rfnFree && pfcb->fDelete && !pfcb->fReferenced &&
+ fn != fnPrint) */
+ if (pfcb->rfn != rfnFree && pfcb->fDelete && !pfcb->fReferenced)
+ { /* For each deletable fn */
+ int fnT;
+
+ for (;;)
+ { /* Until we determine there is or isn't a ref */
+ if (doc >= docMac)
+ goto OutOfDocs;
+ while ((fnT = ppcd->fn) == fnNil)
+ { /* End of pctb */
+#ifdef CASHMERE
+ struct SETB **hsetb = pdod->hsetb;
+ if (hsetb != 0)
+ { /* Check section table. Doesn't need to be quite
+ as smart as piece table checker; smaller. */
+ int csed = (**hsetb).csed;
+ struct SED *psed = &(**hsetb).rgsed[0];
+ while (csed--)
+ {
+ fnT = psed->fn;
+ if (fnT == fn) /* Referenced. */
+ goto NextFn;
+ if (fnT > fn) /* Future fn referenced */
+ mpfnfcb[fnT].fReferenced = true;
+ psed++;
+ }
+ }
+#endif
+ while (++doc < docMac && (++pdod)->hpctb == 0)
+ continue;
+ if (doc >= docMac)
+ {
+OutOfDocs: /* No references to this fn, delete it */
+ MeltHp();
+#ifdef DFILE
+ {
+ char rgch[200];
+ wsprintf(rgch," fn %d, %s \n\r", fn,(LPSTR)(**pfcb->hszFile));
+ CommSz(rgch);
+ }
+#endif
+ FDeleteFn(fn); /* HEAP MOVEMENT */
+ FreezeHp();
+
+ /* NOTE: Once we get here, there is no */
+ /* further use of pdod or ppcd; we zip */
+ /* through the remaining fn's and just */
+ /* test fcb fields. Therefore, pdod */
+ /* and ppcd are not updated although */
+ /* there was (maybe) heap movement above */
+
+ mpfnfcb = &(**hpfnfcb)[0];
+ pfcb = &mpfnfcb[fn];
+
+ goto NextFn;
+ }
+ ppcd = &(**pdod->hpctb).rgpcd[0];
+ }
+ if (fnT == fn) /* A reference to this fn */
+ goto NextFn;
+ if (fnT > fn) /* Ref to a future fn */
+ mpfnfcb[fnT].fReferenced = true;
+ ++ppcd;
+ }
+ }
+ else
+ pfcb->fReferenced = false;
+NextFn: ;
+ }
+MeltHp();
+}
+
+
+#if WINVER >= 0x300
+/* We only use one document at a time, thus in general we won't have
+ doc's referencing pieces from multiple fns (unless they've been
+ pasted and reference docscrap or something).
+
+ In any case we want to free up these files esp. for network user
+ convenience. The dilemma in particular is when someone's opened
+ a file on the net and then does a File.New, File.SaveAs, or File.Open
+ and is using another file -- we don't release the previous one so
+ another user will get a sharing error even though it seems that file
+ should be free!
+
+ Modeled after PurgeTemps() above ..pault 10/23/89 */
+
+void FreeUnreferencedFns()
+ {
+ int fn;
+ struct FCB *pfcb, *mpfnfcb;
+ struct DOD *pdod;
+ struct PCD *ppcd;
+ int doc;
+
+ Assert(fnScratch == 0);
+ FreezeHp();
+ mpfnfcb = &(**hpfnfcb)[0];
+
+ /* Prime the doc/piece table loop */
+ /* Find the first valid doc (there is guaranteed to be one) */
+ /* Set up doc, pdod, ppcd */
+ for (doc = 0, pdod = &(**hpdocdod)[0]; pdod->hpctb == 0; doc++, pdod++)
+ continue;
+ ppcd = &(**pdod->hpctb).rgpcd[0];
+#ifdef DFILE
+ CommSz("FreeUnreferencedFns: \n\r");
+#endif
+
+ for (fn = fnScratch + 1, pfcb = &mpfnfcb[fnScratch + 1]; fn < fnMac; fn++, pfcb++)
+ { /* For each file (don't bother with scratch file) */
+
+#ifdef DFILE
+ {
+ char rgch[200];
+ wsprintf(rgch," fn %d, %s \trfnFree %d fRefd %d fDelete %d ",
+ fn,(LPSTR)(**pfcb->hszFile),pfcb->rfn==rfnFree,pfcb->fReferenced,pfcb->fDelete);
+ CommSz(rgch);
+ }
+#endif
+ /* For each unreferenced fn, we ask: is this file the current
+ document being edited? If so then we definitely don't want
+ to free up the file. However PREVIOUS documents that were
+ being edited can now "be free". Temp files are not freed
+ here because we want them to be remembered so they are deleted
+ at the end of the Write session 2/1/90 ..pault */
+
+ if ((WCompSz(*(**hpdocdod)[ docCur ].hszFile,**pfcb->hszFile)==0)
+ || pfcb->fDelete)
+ goto LRefd;
+ else if (pfcb->rfn != rfnFree && !pfcb->fReferenced)
+ {
+ int fnT;
+
+ for (;;)
+ { /* Until we determine there is or isn't a ref */
+ if (doc >= docMac)
+ {
+ goto OutOfDocs;
+ }
+ while ((fnT = ppcd->fn) == fnNil)
+ { /* End of pctb */
+ while (++doc < docMac && (++pdod)->hpctb == 0)
+ continue;
+ if (doc >= docMac)
+ {
+OutOfDocs: /* No references to this fn, delete it */
+
+ MeltHp();
+#ifdef DFILE
+ CommSz(" FREEING!");
+#endif
+ FreeFn(fn); /* HEAP MOVEMENT */
+ FreezeHp();
+
+ /* NOTE: Once we get here, there is no */
+ /* further use of pdod or ppcd; we zip */
+ /* through the remaining fn's and just */
+ /* test fcb fields. Therefore, pdod */
+ /* and ppcd are not updated although */
+ /* there was (maybe) heap movement above */
+
+ mpfnfcb = &(**hpfnfcb)[0];
+ pfcb = &mpfnfcb[fn];
+
+ goto NextFn;
+ }
+ ppcd = &(**pdod->hpctb).rgpcd[0];
+ }
+ if (fnT == fn) /* A reference to this fn */
+ {
+ goto NextFn;
+ }
+ if (fnT > fn) /* Ref to a future fn */
+ {
+ mpfnfcb[fnT].fReferenced = true;
+ }
+ ++ppcd;
+ }
+ }
+ else
+ {
+LRefd:
+ pfcb->fReferenced = false;
+ }
+NextFn: ;
+#ifdef DFILE
+ CommSz("\n\r");
+#endif
+ }
+ MeltHp();
+ }
+#endif /* WIN30 */
diff --git a/private/mvdm/wow16/write/transbuf.c b/private/mvdm/wow16/write/transbuf.c
new file mode 100644
index 000000000..0cba8ef74
--- /dev/null
+++ b/private/mvdm/wow16/write/transbuf.c
@@ -0,0 +1,450 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NORECT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "code.h"
+#include "txb.h"
+#include "str.h"
+#include "docdefs.h"
+#include "cmddefs.h"
+#include "filedefs.h"
+#include "ch.h"
+#include "propdefs.h"
+#include "fmtdefs.h"
+#include "dispdefs.h"
+#include "stcdefs.h"
+/*#include "toolbox.h"*/
+#include "wwdefs.h"
+
+/* New functionality for Sand: Jan 17, 1984
+ Kenneth J. Shapiro */
+
+/*---------------------------------------------------------------------------
+The following routines form the interface between the buffer code and the
+rest of multi-word:
+ CmdXfBufClear() - used by "Transfer Buffer Clear"
+ CmdXfBufLoad() - used by "Transfer Buffer Load"
+ CmdXfBufSave() - used by "Transfer Buffer Save"
+----------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+External global references:
+----------------------------------------------------------------------------*/
+extern int vfSeeSel;
+extern struct DOD (**hpdocdod)[];
+extern VAL rgval[];
+extern int docCur;
+extern struct SEL selCur;
+extern int YCOCMD;
+extern typeCP cpMacCur;
+extern int docScrap;
+/*extern WINDOWPTR ActiveWindow;
+extern WINDOWPTR windowGlos;
+*/
+extern CHAR stBuf[];
+extern struct WWD *pwwdCur;
+
+extern struct TXB (**hgtxb)[]; /* array of txbs. Sorted for binary search */
+extern short itxbMac; /* indicates current size of hgtxb */
+extern int docBuffer; /* doc containing all buffer text */
+extern int vfBuffersDirty;
+extern int rfnMac;
+extern struct ERFN dnrfn[];
+
+#ifdef ENABLE
+/*---------------------------------------------------------------------------
+-- Routine: CmdXfBufClear()
+-- Description and Usage:
+ Called by the menu routines to execute "Transfer Buffer Clear"
+ rgval[0] contains a list of buffer names, stored in an hsz.
+ The list is just as the user typed it.
+ Makes the user confirm the action, and then removes all of the named
+ buffers. If no buffers are named, it clear ALL buffers.
+-- Arguments: none
+-- Returns: nothing
+-- Side-effects:
+ Clears some subset of the named buffers.
+-- Bugs:
+-- History:
+ 3/25/83 - created (tsr)
+ 4/27/83 - modified to handle list of names (tsr)
+----------------------------------------------------------------------------*/
+CmdXfBufClear()
+ {
+#ifdef DEMOA
+ DemoErr();
+#else
+ int ich;
+ int itxb;
+
+ if(!cnfrm(IDPMTBufCnfrm))
+ return;
+ NoUndo();
+ if(CchSz(**(CHAR(**)[])rgval[0])==1)
+ {
+ for(itxb=0; itxb < itxbMac ; itxb++)
+ {
+ FreeH((**hgtxb)[itxb].hszName);
+ }
+ FreeH(hgtxb);
+ hgtxb = HAllocate(cwTxb);
+#ifdef DEBUG
+ /* We just freed the space, so it shouldn't be bad now */
+ Assert(!FNoHeap(hgtxb));
+#endif /*DEBUG*/
+ (**hgtxb)[0].hszName = hszNil;
+ itxbMac = 0;
+ KillDoc(docBuffer);
+ docBuffer = DocCreate(fnNil, (CHAR (**)[]) 0, dtyBuffer);
+ }
+ else
+ FClearBuffers(**(CHAR(**)[])rgval[0], CchSz(**(CHAR(**)[])rgval[0])-1,
+ TRUE, &ich);
+#endif /* DEMOA */
+ }
+#endif /* ENABLE */
+
+#ifdef ENABLE
+/*---------------------------------------------------------------------------
+-- Routine: CmdXfBufLoad()
+-- Description and Usage:
+ Called by the menu routines to execute "Transfer Buffer Load"
+ rgval[0] contains the name of the file to load.
+ Merges references to the loaded buffers into the buffer list stored in
+ hgtxb. Requires additions to docBuffer for each newly one.
+-- Arguments: none
+-- Returns: nothing
+-- Side-effects:
+ Can define/clobber many buffers.
+-- Bugs:
+-- History:
+ 3/22/83 - created (tsr)
+----------------------------------------------------------------------------*/
+CmdXfBufLoad()
+ {
+#ifdef DEMOA
+ DemoErr();
+#else
+ extern CHAR (**hszGlosFile)[];
+ /* for each buffer definition in the file:
+ a) add the related text to the end of docBuffer
+ b) insert or replace the reference for that buffer name
+ */
+ CHAR (**hszFile)[] = (CHAR (**)[]) rgval[0];
+ int fn;
+ if ((fn = FnOpenSz(**hszFile, dtyBuffer, TRUE)) == fnNil)
+ {
+ Error(IDPMTBadFile);
+ return;
+ }
+ NoUndo();
+ MergeTxbsFn(fn);
+ if ((**hszGlosFile)[0] == 0)
+ {
+ FreeH(hszGlosFile);
+ hszGlosFile = hszFile;
+ }
+ vfBuffersDirty = true;
+#endif /* DEMOA */
+ }
+#endif /* ENABLE */
+
+
+#ifdef ENABLE
+/*---------------------------------------------------------------------------
+-- Routine: MergeTxbsFn(fn)
+-- Description and Usage:
+ Given an fn which contains a buffer document, this function reads in
+ the text of the file, appending it to docBuffer. It also reads
+ the Bftb from the file in order to build the appropriate mapping
+ from buffer name to text.
+-- Arguments:
+ fn - file containing buffer definitions.
+-- Returns:
+ nothing
+-- Side-effects:
+ builds new buffers onto docBuffer and hgtxb
+-- Bugs:
+-- History:
+ 3/24/83 - created (tsr)
+----------------------------------------------------------------------------*/
+MergeTxbsFn(fn)
+int fn;
+ {
+ extern struct FCB (**hpfnfcb)[];
+ extern short ItxbFromHsz();
+ unsigned pbftbFile;
+ typePN pn;
+ int cchT;
+ CHAR (**hbftb)[];
+ int *pwBftb;
+ int cw;
+ int ich;
+ short itxbNew;
+ struct TXB *ptxbNew;
+ typeCP cp, dcp;
+ typeCP cpBufMac;
+ CHAR(**hszNew)[];
+ int docNew;
+
+ CHAR sz[cchMaxSz];
+
+#ifdef DEBUG
+ Assert(fn != fnNil && (**hpfnfcb)[fn].fFormatted);
+#endif
+ if ((pn = (**hpfnfcb)[fn].pnBftb) ==(**hpfnfcb)[fn].pnFfntb)
+ return;
+ pbftbFile = (unsigned) PchGetPn(fn, pn, &cchT, false);
+
+ hbftb = (CHAR (**) []) HAllocate(cw=((**hpfnfcb)[fn].pnFfntb - (**hpfnfcb)[fn].pnBftb)*cwSector);
+ if (FNoHeap((int)hbftb))
+ return;
+ pwBftb = *(int **)hbftb;
+
+ blt(pbftbFile, pwBftb, min(cwSector, cw));
+
+ while ((cw -= cwSector) > 0)
+ { /* Copy the records to heap */
+ blt(PchGetPn(fn, ++pn, &cchT, false), pwBftb += cwSector,
+ min(cwSector, cw));
+ }
+
+ ich = 0;
+ cp = cp0;
+ cpBufMac = CpMacText(docBuffer);
+ bltsz(**(**hpfnfcb)[fn].hszFile, sz);
+ docNew = DocCreate(fn, HszCreate(sz), dtyBuffer); /* HEAP MOVES */
+ while((**hbftb)[ich] != '\0')
+ {
+ bltsz(&(**hbftb)[ich], sz);
+ sz[cchMaxSz - 1] = 0;
+ hszNew = (CHAR(**)[]) HszCreate(sz); /*** HEAP MOVES ***/
+ ich += CchSz(sz);
+ bltbyte(&(**hbftb)[ich], &dcp, sizeof(typeCP));
+ ich += sizeof(typeCP);
+ itxbNew = ItxbFromHsz(hszNew);
+#ifdef DEBUG
+ Assert(itxbNew >= 0);
+#endif /* DEBUG */
+ ReplaceCps(docBuffer, cpBufMac, cp0, docNew, cp, dcp); /*HEAP MOVES*/
+ ptxbNew = &(**hgtxb)[itxbNew];
+ ptxbNew->cp=cpBufMac;
+ ptxbNew->dcp=dcp;
+ cpBufMac += dcp;
+ cp += dcp;
+ }
+ KillDoc(docNew);
+ FreeH((int **)hbftb);
+ }
+#endif /* ENABLE */
+
+#ifdef ENABLE
+/*---------------------------------------------------------------------------
+-- Routine: CmdXfBufSave()
+-- Description and Usage:
+ Called by the menu routines to execute "Transfer Buffer Save"
+ rgval[0] contains the name of the file to save the buffers in.
+ Creates a single doc to contain all of the buffers and updates
+ hgtxb to reference that doc, cleaning up all of the temporary
+ docs that were around.
+ Stores that doc in the file, putting a table at the end of the file
+ which maps buffer names to locations within the file.
+-- Arguments: none
+-- Returns: nothing
+-- Side-effects:
+-- Bugs:
+-- History:
+ 3/22/83 - created (tsr)
+----------------------------------------------------------------------------*/
+CmdXfBufSave(szFile)
+CHAR szFile[];
+{
+#ifndef WDEMO
+ CHAR (**hszFile)[];
+ CHAR szBak[cchMaxFile];
+ long ltype;
+
+ /* Move file name to local */
+/* bltbyte(**hszFile, szFile, cchMaxFile);*/
+
+ BackupSzFile(szFile, true, szBak, &ltype);
+/* ForcePmt(IDPMTSaving);*/
+ NoUndo();
+#ifdef STYLES
+ (**hpdocdod)[docBuffer].docSsht = (**hpdocdod)[docCur].docSsht;
+#endif
+ CachePara(docBuffer, cp0);
+ CleanDoc(docBuffer, szFile, true, true);
+ (**hpdocdod)[docBuffer].docSsht = docNil;
+ if (!FNoHeap(hszFile = HszCreate(szFile)))
+ {
+ FreeH(hszGlosFile);
+ hszGlosFile = hszFile;
+ }
+
+ vfBuffersDirty = false;
+#endif /* not WDEMO */
+}
+#endif /* ENABLE */
+
+
+#ifdef ENABLE
+/*---------------------------------------------------------------------------
+-- Routine: CleanBuffers()
+-- Description and Usage:
+ Creates a new docBuffer containing only currently referenced buffer text.
+ This is to keep old buffer values from lying around through
+ eternity.
+-- Arguments: none
+-- Returns: nothing
+-- Side-effects:
+ creates a new doc for docBuffer.
+ kills old docBuffer.
+-- Bugs:
+-- History:
+ 3/24/83 - create (tsr)
+----------------------------------------------------------------------------*/
+CleanBuffers()
+ {
+#ifdef DEMOA
+
+#else
+ int docNew;
+ short itxb;
+ struct TXB *ptxb;
+ typeCP cp, cpOld;
+ typeCP dcp;
+
+
+ docNew = DocCreate(fnNil, (CHAR (**)[]) 0, dtyBuffer);
+ for(cp=0, itxb=0;itxb<itxbMac;itxb++, cp+=dcp)
+ {
+ ptxb = &(**hgtxb)[itxb];
+ cpOld = ptxb->cp;
+ ptxb->cp = cp;
+ /* HEAP MOVEMENT */
+ ReplaceCps(docNew, cp, cp0, docBuffer, cpOld, dcp = ptxb->dcp);
+ }
+ KillDoc(docBuffer);
+ docBuffer = docNew;
+ NoUndo();
+#endif /* DEMOA */
+ }
+#endif /* ENABLE */
+
+
+/*---------------------------------------------------------------------------
+-- Routine: WriteBftb(fn)
+-- Description and Usage:
+ Given an fn for a buffer file that is being written, this routine
+ actually writes out the Bftb which maps buffer names to pieces of
+ text stored in the file.
+-- Arguments:
+ fn - file being written.
+-- Returns: nothing
+-- Side-effects:
+ Writes to the file described by fn.
+-- Bugs:
+-- History:
+ 3/24/83 - created (tsr)
+----------------------------------------------------------------------------*/
+WriteBftb(fn)
+int fn;
+ {
+#ifdef DEMOA
+
+#else
+ short itxb;
+ struct TXB *ptxb;
+
+ for(itxb = 0 ; itxb < itxbMac ; itxb ++ )
+ {
+ ptxb = &(**hgtxb)[itxb];
+ WriteRgch(fn, &(**(ptxb->hszName))[0], CchSz(**(ptxb->hszName)));
+ ptxb = &(**hgtxb)[itxb];
+ WriteRgch(fn, (CHAR *)&(ptxb->dcp), sizeof(typeCP));
+ }
+ WriteRgch(fn, "", sizeof(CHAR));
+#endif /* DEMOA */
+ }
+
+#ifdef ENABLE
+int CchCurGlosFile(pfld, pch, fNew, ival)
+struct fld *pfld;
+CHAR *pch;
+int fNew, ival;
+{
+int cch;
+extern CHAR (**hszGlosFile)[];
+
+CleanBuffers();
+CloseEveryRfnTB(true);
+if((cch = CchSz(**hszGlosFile)-1) == 0)
+ cch = CchFillSzId(pch, IDSTRGLYN);
+else
+ bltbyte(**hszGlosFile, pch, cch);
+return(cch);
+}
+#endif /* ENABLE */
+
+#ifdef ENABLE
+/* F N N E W F I L E */
+ClearGlosBuf ()
+{
+
+ rgval[0] = HszCreate("");
+ CmdXfBufClear();
+ RecreateListbox(cidstrRsvd + itxbMac);
+ return;
+}
+#endif /* ENABLE */
+
+#ifdef ENABLE
+CloseEveryRfnTB(fRetry)
+int fRetry;
+ {
+ int rfn;
+
+ for(rfn = 0; rfn < rfnMac; rfn++)
+ {
+ if(dnrfn[rfn].fn != fnNil)
+ CloseRfn( rfn );
+ }
+ }
+#endif /* ENABLE */
diff --git a/private/mvdm/wow16/write/transfer.c b/private/mvdm/wow16/write/transfer.c
new file mode 100644
index 000000000..89a6cabe5
--- /dev/null
+++ b/private/mvdm/wow16/write/transfer.c
@@ -0,0 +1,222 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#include <windows.h>
+#include "mw.h"
+#include "doslib.h"
+#include "cmddefs.h"
+#include "docdefs.h"
+#include "filedefs.h"
+#include "str.h"
+#include "debug.h"
+
+extern int vfnWriting;
+
+
+#define IibpHash(fn,pn) ((int) ((fn + 1) * (pn + 1)) & 077777) % iibpHashMax
+
+#define FcMin(a,b) CpMin(a,b)
+
+extern CHAR *rgibpHash;
+extern int vfSysFull;
+extern struct BPS *mpibpbps;
+extern struct FCB (**hpfnfcb)[];
+extern typeTS tsMruBps;
+extern CHAR (*rgbp)[cbSector];
+#ifdef CKSM
+#ifdef DEBUG
+extern unsigned (**hpibpcksm) [];
+#endif
+#endif
+
+/* WriteDirtyPages kicks out of memory as much of the previous files as it can
+ in order to fill the page buffers with a new file. This is called on
+ every transfer load of a file. */
+WriteDirtyPages()
+{/*
+ Description: Cleans the buffer pool of all dirty pages by writing them
+ out to disk. If a disk full condition is reached, only
+ pages which actually made it to disk are marked as non
+ dirty.
+ Returns: nothing.
+ */
+ int ibp;
+ struct BPS *pbps = &mpibpbps [0];
+
+ for (ibp = 0; ibp < ibpMax; ++ibp, ++pbps)
+ {
+#ifdef CKSM
+#ifdef DEBUG
+ if (pbps->fn != fnNil && !pbps->fDirty)
+ Assert( (**hpibpcksm) [ibp] == CksmFromIbp( ibp ) );
+#endif
+#endif
+ if (pbps->fn != fnNil && pbps->fDirty)
+ {
+ FFlushFn(pbps->fn);
+ /* keep on flushing if failure ? */
+ }
+ }
+}
+
+
+ReadFilePages(fn)
+int fn;
+ {
+/*
+ Description: ReadFilePages tries to read in as much of a file as
+ it can. The idea is to fill the page buffers in anticipation of
+ much access. This is called on every Transfer Load of a file.
+ If fn == fnNil or there are no characters in the file, ReadFilePages
+ simply returns.
+ Returns: nothing
+ */
+ int ibp;
+ int cfcRead;
+ int cpnRead;
+ int dfcMac;
+ typeFC fcMac;
+ int ibpReadMax;
+ int cfcLastPage;
+ int iibp;
+ struct FCB *pfcb;
+ typeTS ts;
+
+ if (fn == fnNil)
+ return;
+
+ /* Write ALL dirty pages to disk */
+ WriteDirtyPages(); /* Just in case */
+
+ pfcb = &(**hpfnfcb)[fn];
+
+ /* we read as much of the file as will fit in the page buffers */
+ /* Note that we assume that fcMax is coercable to an integer. This
+ is valid as long as ibpMax*cbSector < 32k */
+ dfcMac = (int) FcMin(pfcb->fcMac, (typeFC) (ibpMax * cbSector));
+ if (dfcMac == 0)
+ return;
+ if (vfSysFull) /* call to FFlushFn in WriteDirtyPages failed.
+ the buffer algorithm assures us that the first
+ cbpMustKeep ibp's do not contain scratch file
+ information. Thus, there is no danger in overwriting
+ these ibps. */
+ dfcMac = imin( dfcMac, (cbpMustKeep * cbSector) );
+
+ Assert( ((int)dfcMac) >= 0 );
+
+ /* Read pages from the file */
+
+ cfcRead = CchReadAtPage( fn, (typePN) 0, rgbp [0], (int) dfcMac, FALSE );
+
+ /* cfcRead contains a count of bytes read from the file */
+ ibpReadMax = ((cfcRead-1) / cbSector) + 1;
+ cfcLastPage = cfcRead - (ibpReadMax-1)*cbSector;
+ ts = ibpMax;
+
+ /* order time stamps so the beginning slots have the greatest ts.
+ Lru allocation will start at the end of the buffer table and work
+ backward. Thus, the first page of the current file is considered
+ the most recently used item.
+ */
+
+ /* describe the newly filled pages */
+ for(ibp = 0; ibp < ibpReadMax; ++ibp)
+ {
+ struct BPS *pbps = &mpibpbps[ibp];
+ pbps->fn = fn;
+ pbps->pn = ibp;
+ pbps->ts = --ts;
+ pbps->fDirty = false;
+ pbps->cch = cbSector;
+ pbps->ibpHashNext = ibpNil;
+ }
+
+#ifdef CKSM
+#ifdef DEBUG
+ {
+ int ibpT;
+
+ for ( ibpT = 0; ibpT < ibpReadMax; ibpT++ )
+ (**hpibpcksm) [ibpT] = CksmFromIbp( ibpT );
+ }
+#endif
+#endif
+
+ /* fix some boundary conditions */
+ mpibpbps[ibpReadMax-1].cch = cfcLastPage; /* ?????? */
+#ifdef CKSM
+#ifdef DEBUG
+ (**hpibpcksm) [ibpReadMax - 1] = CksmFromIbp( ibpReadMax - 1 );
+#endif
+#endif
+
+ /* update descriptions of untouched page buffers */
+ for (ibp=ibpReadMax; ibp < ibpMax; ibp++)
+ {
+ struct BPS *pbps = &mpibpbps[ibp];
+ pbps->ts = --ts;
+ pbps->fDirty = false;
+ pbps->ibpHashNext = ibpNil;
+
+#ifdef CKSM
+#ifdef DEBUG
+ if (pbps->fn != fnNil)
+ (**hpibpcksm) [ibp] = CksmFromIbp( ibp );
+#endif
+#endif
+ }
+
+ tsMruBps = ibpMax - 1;
+
+ /* recalculate the hash table */
+ RehashRgibpHash();
+
+} /* end of R e a d F i l e P a g e s */
+
+
+RehashRgibpHash()
+{
+int iibp;
+register struct BPS *pbps;
+struct BPS *pbpsMax = &mpibpbps[ibpMax];
+int iibpHash;
+int ibpT;
+int ibpPrev;
+int ibp;
+
+ for (iibp = 0; iibp < iibpHashMax; iibp++)
+ rgibpHash[iibp] = ibpNil;
+
+ for (ibp = 0, pbps = &mpibpbps[0]; pbps < pbpsMax; pbps++, ibp++)
+ {
+ if (pbps->fn == fnNil)
+ continue;
+ iibpHash = IibpHash(pbps->fn, pbps->pn);
+ ibpT = rgibpHash[iibpHash];
+ ibpPrev = ibpNil;
+ while (ibpT != ibpNil)
+ {
+ ibpPrev = ibpT;
+ ibpT = mpibpbps[ibpT].ibpHashNext;
+ }
+ if (ibpPrev == ibpNil)
+ rgibpHash[iibpHash] = ibp;
+ else
+ mpibpbps[ibpPrev].ibpHashNext = ibp;
+ }
+#ifdef DEBUG
+ CheckIbp();
+#endif
+} /* end of RehashRgibpHash */
+
+
diff --git a/private/mvdm/wow16/write/txb.h b/private/mvdm/wow16/write/txb.h
new file mode 100644
index 000000000..e37a30001
--- /dev/null
+++ b/private/mvdm/wow16/write/txb.h
@@ -0,0 +1,28 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/*---------------------------------------------------------------------------
+-- Structure: TXB
+-- Description and Usage:
+ Describes a buffer.
+ Maps the name of a buffer to the associated text, which is stored in
+ docBuffer.
+-- Fields:
+ hszName - pointer to a null terminated string in the heap which is
+ the name of this buffer.
+ cp - location in docBuffer
+ dcp - amount of interest in docBuffer
+----------------------------------------------------------------------------*/
+struct TXB
+ {
+ CHAR (**hszName)[];
+ typeCP cp;
+ typeCP dcp;
+ };
+
+
+#define cbTxb (sizeof(struct TXB))
+#define cwTxb (cbTxb / sizeof(int))
+#define hszNil (0)
+#define cidstrRsvd (2)
diff --git a/private/mvdm/wow16/write/undo.c b/private/mvdm/wow16/write/undo.c
new file mode 100644
index 000000000..0c09a2754
--- /dev/null
+++ b/private/mvdm/wow16/write/undo.c
@@ -0,0 +1,873 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* NOTE: the routines in this file are not written in a manner which minimizes
+ code space. It is anticipated that these routines will be swappable
+ and that a reasonable optimizer will be used when compiling the code */
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOKEYSTATE
+//#define NOGDI
+#define NORASTEROPS
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOCOLOR
+//#define NOATOM
+#define NOBITMAP
+#define NOICON
+#define NOBRUSH
+#define NOCREATESTRUCT
+#define NOMB
+#define NOFONT
+#define NOMSG
+#define NOOPENFILE
+#define NOPEN
+#define NOPOINT
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+
+#include "mw.h"
+#include "docdefs.h"
+#include "editdefs.h"
+#include "cmddefs.h"
+#include "str.h"
+#include "txb.h"
+#include "ch.h"
+#include "code.h"
+#include "wwdefs.h"
+#include "printdef.h"
+#if defined(OLE)
+#include "obj.h"
+#endif
+
+#ifndef CASHMERE
+#include "propdefs.h"
+#endif /* not CASHMERE */
+
+struct UAB vuab;
+
+#ifdef ENABLE
+VAL rgvalAgain[ivalMax];
+#endif
+
+extern struct WWD *pwwdCur;
+extern typeCP cpMacCur;
+extern typeCP cpMinCur;
+extern int vfSeeSel;
+extern int docMac;
+extern int docCur;
+extern int docScrap;
+extern int docUndo;
+extern int docBuffer;
+extern int vdocPageCache;
+extern struct DOD (**hpdocdod)[];
+extern struct SEL selCur;
+extern CHAR (**hszReplace)[];
+extern struct TXB (**hgtxb)[];
+/*extern int idstrUndoBase;*/
+extern int vfPictSel;
+extern int ferror;
+extern int docMode;
+extern int vfOwnClipboard; /* Whether this instance owns the clip contents */
+
+#ifndef CASHMERE
+extern int vdocSectCache;
+#endif /* not CASHMERE */
+
+
+fnUndoEdit()
+ {
+ extern HCURSOR vhcIBeam;
+ StartLongOp();
+ CmdUndo();
+ EndLongOp(vhcIBeam);
+ }
+
+
+/*
+The routines in this file implement the "undo" and "again" features in
+Multi-Tool Word. The basic idea is that whenever an editing operation is
+about to be done, the global structure "vuab" will be updated to contain
+information sufficient to undo or repeat that operation. The structure
+(defined in editdefs.h, declared in this file) looks like this:
+ struct UAB
+ { UNDO Action Block
+ int uac; UNDO Action Code (see cmddefs.h)
+ int doc;
+ typeCP cp;
+ typeCP dcp;
+ int doc2;
+ typeCP cp2;
+ typeCP dcp2;
+ short itxb;
+ };
+Setting up this structure is taken care of by "SetUndo()" which does a lot
+of plugging in of values and a couple pseudo-smart things. These smartish
+things are:
+ a) If an insert is made and the last operation was a delete
+ the two are combined into one "replace" operation.
+ This means that undo-ing and again-ing apply to the replace and
+ not just the insertion.
+
+ b) When needed (see the code for details) the undo buffer (docUndo)
+ is filled with any text that needs preservation for future
+ undo-ing or again-ing. The main example of this is storing away
+ the old value of the scrap when an operation is about to clobber
+ the scrap.
+
+Here is a list of the various uac values and what info is stored
+ other info may be clobbered by the process.
+ are defined in cmddefs.h. Note that none of the "undo" codes
+ (those starting with "uacU...") should be set outside of CmdUndo(),
+ since they may assume things like contents of docUndo which could
+ be wrong.
+Note: This list store information used by the again and undo commands.
+ Other info may be clobbered by the process.
+
+uacNil No action stored.
+uacInsert
+ doc = document text was inserted into
+ cp = location at which text was inserted
+ dcp = length of inserted text
+uacUInsert
+ doc = document from which text was removed (un-inserted)
+ cp = location at which text was removed
+ docUndo = text which was removed
+uacReplNS
+ doc = document in which replacement occurred
+ cp = location at which replacement occurred
+ dcp = length of inserted text
+ dcp2 = length of deleted text
+ docUndo = deleted text
+uacUReplNS
+ doc = document in which replace occrred
+ cp = location of the replace
+ dcp = length of re-inserted text
+ dcp2 = length of un-inserted text
+ docUndo = un-inserted text
+uacReplGlobal
+uacChLook
+uacChLookSect
+uacFormatChar
+uacFormatPara
+uacFormatSection
+uacGalFormatChar
+uacGalFormatPara
+uacGalFormatSection
+uacFormatCStyle
+uacFormatPStyle
+uacFormatSStyle
+uacFormatRHText
+uacLookCharMouse
+uacLookParaMouse
+uacClearAllTab
+uacFormatTabs
+uacClearTab
+uacOvertype
+ Similar to uacReplNS except that they are agained differently.
+uacDelNS
+ doc = document from which text was deleted
+ cp = location at which text was deleted
+ dcp = length of deleted text
+ docUndo = deleted text
+uacUDelNS
+ doc = document in which text was re-inserted
+ cp = location at which text was re-inserted
+ dcp = length of re-inserted text
+uacMove
+ doc = document from which text was deleted
+ cp = location at which text was deleted
+ dcp = length of deleted text
+ (also serves as length of inserted text)
+ doc2 = document in which text was inserted
+ cp2 = location at which text was inserted
+uacDelScrap
+ doc = document from which text was deleted
+ cp = location at which text was deleted
+ dcp = length of deleted text
+ docUndo = old contents of scrap
+uacUDelScrap
+ doc = document in which text was re-inserted
+ cp = location at which text was re-inserted
+ dcp = length of re-inserted text
+uacReplScrap
+ doc = document in which replacement occurred
+ cp = location at which replacement occurred
+ dcp = length of inserted text
+ docUndo = old contents of scrap
+uacUReplScrap
+ doc = document in which replacement was undone
+ cp = location at which replacement was undone
+ dcp = length of re-inserted text
+ docUndo = deleted text (was originally inserted)
+uacDelBuf
+ doc = document from which text was deleted
+ cp = location at which text was deleted
+ cp2 = location in docBuffer of old contents of buffer
+ dcp2 = size of old contents of buffer
+ itxb = index of buffer in question
+uacUDelBuf
+ doc = document in which text was re-inserted
+ cp = location of re-insertion
+ dcp = amount of text re-inserted
+ itxb = index of buffer involved
+uacReplBuf
+ doc = document in which replace took place
+ cp = location of replace
+ dcp = length of inserted text
+ cp2 = location of old buffer contents in docBuffer
+ dcp2 = length of old buffer contents
+ itxb = index of buffer involved
+uacUReplBuf
+ doc = document in which original replace took place
+ cp = location of replace
+ dcp = length of text which was restored in document
+ itxb = index of buffer involved
+ docUndo = un-inserted text
+uacCopyBuf
+ cp = location of old buffer contents in docBuffer
+ dcp = length of old buffer contents
+ itxb = index of buffer involved
+uacUCopyBuf
+ cp = location of undone buffer contents in docBuffer
+ dcp = length of undone buffer contents
+ itxb = index of buffer involved
+*/
+
+
+CmdUndo()
+{ /* UNDO */
+ typeCP dcpT,cpT,dcpT2;
+ int docT;
+ int f;
+ struct DOD *pdod, *pdodUndo;
+ int uac;
+
+#ifndef CASHMERE
+ struct SEP **hsep;
+ struct TBD (**hgtbd)[];
+ struct PGTB **hpgtb;
+ struct PGTB **hpgtbUndo;
+ struct PGTB **hpgtbT;
+
+ BOOL near FCopyPgtb(int, struct PGTB ***);
+#endif /* not CASHMERE */
+
+ TurnOffSel();
+ ClearInsertLine();
+ switch (uac = vuab.uac)
+ {
+ struct TXB *ptxb;
+ default:/* case uacNil: */
+ Assert(false); /* Won't get here cause menu should be greyed */
+ return;
+ case uacInsert:
+ case uacInsertFtn:
+ case uacUDelNS:
+ ClobberDoc(docUndo, vuab.doc, vuab.cp, vuab.dcp);
+ Replace(vuab.doc, vuab.cp, vuab.dcp, fnNil, fc0, fc0);
+ dcpT = cp0;
+ vuab.uac = (uac == uacUDelNS) ? uacDelNS : uacUInsert;
+/* idstrUndoBase = uac == uacUDelNS ? IDSTRUndoBase : IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ if (uac == uacInsertFtn)
+ TrashAllWws(); /* Simple, but effective */
+ break;
+ case uacUInsert:
+ case uacDelNS:
+ ReplaceCps(vuab.doc, vuab.cp, cp0, docUndo, cp0, dcpT = vuab.dcp);
+ vuab.uac = (uac == uacUInsert) ? uacInsert : uacUDelNS;
+/* idstrUndoBase = uac == uacUInsert ? IDSTRUndoBase : IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ break;
+
+ case uacDelScrap: /* UNDO CUT */
+ if ( !vfOwnClipboard )
+ ferror = TRUE;
+ else
+ {
+ ReplaceCps(vuab.doc, vuab.cp, cp0, docScrap, cp0,
+ dcpT = CpMacText(docScrap));
+ vuab.uac = uacUDelScrap;
+/* idstrUndoBase = IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ ClobberDoc( docScrap, docUndo, cp0, CpMacText( docUndo ) );
+ ChangeClipboard();
+ }
+ break;
+
+ case uacUDelScrap: /* REDO CUT */
+ ClobberDoc( docUndo, docScrap, cp0, CpMacText( docScrap ) );
+/* idstrUndoBase = IDSTRUndoBase;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ vuab.uac = uacDelScrap;
+
+ ClobberDoc(docScrap, vuab.doc, vuab.cp, vuab.dcp);
+ Replace(vuab.doc, vuab.cp, vuab.dcp, fnNil, fc0, fc0);
+ ChangeClipboard();
+
+ dcpT = 0;
+ break;
+ case uacReplScrap: /* UNDO COPY */
+ if (!vfOwnClipboard)
+ ferror = TRUE;
+ else
+ {
+ dcpT = CpMacText(docScrap);
+ ReplaceCps(vuab.doc, vuab.cp + vuab.dcp, cp0,
+ docScrap, cp0, dcpT);
+
+ ClobberDoc( docScrap, docUndo, cp0, CpMacText( docUndo ) );
+
+/* idstrUndoBase = IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ vuab.uac = uacUReplScrap;
+
+ ClobberDoc(docUndo, vuab.doc, vuab.cp, vuab.dcp);
+ Replace(vuab.doc, vuab.cp, vuab.dcp, fnNil, fc0, fc0);
+ vuab.dcp = dcpT;
+ ChangeClipboard();
+ }
+ break;
+ case uacUReplScrap: /* REDO COPY */
+ dcpT = CpMacText(docUndo);
+ ReplaceCps(vuab.doc, vuab.cp + vuab.dcp, cp0,
+ docUndo, cp0, dcpT);
+
+ ClobberDoc( docUndo, docScrap, cp0, CpMacText( docScrap ));
+/* idstrUndoBase = IDSTRUndoBase;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ vuab.uac = uacReplScrap;
+
+ ClobberDoc(docScrap, vuab.doc, vuab.cp, vuab.dcp);
+ Replace(vuab.doc, vuab.cp, vuab.dcp, fnNil, fc0, fc0);
+ vuab.dcp = dcpT;
+
+ ChangeClipboard();
+ break;
+#ifdef DEBUG
+ case uacUCopyBuf:
+ case uacCopyBuf:
+ case uacUReplBuf:
+ case uacReplBuf:
+ case uacUDelBuf:
+ case uacDelBuf:
+
+ Assert( FALSE ); /* No buffers in MEMO */
+#ifdef ENABLE
+ DoUndoTxb(); /* Moved to txb.c */
+#endif
+ break;
+#endif /* DEBUG */
+ case uacMove:
+ if (!FMoveText(vuab.doc2, vuab.cp2, vuab.dcp, vuab.doc, &vuab.cp, fFalse))
+ return;
+ dcpT = vuab.dcp;
+ cpT = vuab.cp;
+ vuab.cp = vuab.cp2;
+ vuab.cp2 = cpT;
+ docT = vuab.doc;
+ vuab.doc = vuab.doc2;
+ vuab.doc2 = docT;
+ CheckMove();
+ break;
+ case uacUReplNS:
+ case uacChLook:
+ case uacChLookSect:
+ case uacReplNS:
+ case uacFormatChar:
+ case uacFormatPara:
+ case uacGalFormatChar:
+ case uacGalFormatPara:
+ case uacGalFormatSection:
+ case uacReplGlobal:
+ case uacFormatCStyle:
+ case uacFormatPStyle:
+ case uacFormatSStyle:
+ case uacFormatRHText:
+ case uacLookCharMouse:
+ case uacLookParaMouse:
+ case uacClearAllTab:
+ case uacClearTab:
+ case uacOvertype:
+
+#ifdef CASHMERE
+ case uacFormatTabs:
+ case uacFormatSection:
+#endif /* CASHMERE */
+
+#ifdef BOGUS
+ /* Must do insertion first, in front, in case footnote */
+/* if (uac == uacOvertype)
+ vuab.dcp2 = CpMin(vuab.dcp, vuab.dcp2);*/
+ dcpT = vuab.dcp2;
+ ReplaceCps(vuab.doc, vuab.cp, cp0, docUndo, cp0, dcpT);
+ ClobberDoc(docUndo, vuab.doc, vuab.cp + dcpT, vuab.dcp);
+ Replace(vuab.doc, vuab.cp + dcpT, vuab.dcp, fnNil, fc0, fc0);
+ vuab.dcp2 = vuab.dcp;
+ vuab.dcp = dcpT;
+ if(uac == uacReplNS)
+ vuab.uac = uacUReplNS;
+ else if(uac == uacUReplNS)
+ vuab.uac = uacReplNS;
+/* idstrUndoBase = uac != uacUReplNS ? IDSTRUndoRedo : IDSTRUndoBase;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ break;
+#endif
+ case uacReplPic:
+ case uacUReplPic:
+ case uacPictSel:
+ dcpT = uac != uacPictSel ? vuab.dcp2 : vuab.dcp;
+ ReplaceCps(docUndo, dcpT, cp0, vuab.doc, vuab.cp, vuab.dcp);
+ ReplaceCps(vuab.doc, vuab.cp, vuab.dcp, docUndo, cp0, dcpT);
+ Replace(docUndo, cp0, dcpT, fnNil, fc0, fc0);
+ if (uac != uacPictSel)
+ {
+ vuab.dcp2 = vuab.dcp;
+ vuab.dcp = dcpT;
+ }
+ if (uac == uacPictSel)
+ {
+ dcpT = (**hpdocdod)[vuab.doc].cpMac - vuab.cp;
+ AdjustCp(vuab.doc, vuab.cp, dcpT, dcpT);
+ }
+ if(uac == uacReplPic)
+ vuab.uac = uacUReplPic;
+ else if(uac == uacUReplPic)
+ vuab.uac = uacReplPic;
+ else if(uac == uacReplNS)
+ vuab.uac = uacUReplNS;
+ else if(uac == uacUReplNS)
+ vuab.uac = uacReplNS;
+/* switch(uac) */
+/* { */
+/* case uacUReplPic: */
+/* case uacUReplNS: */
+/* idstrUndoBase = IDSTRUndoBase; */
+/* break; */
+/* case uacReplPic: */
+/* case uacReplNS: */
+/* idstrUndoBase = IDSTRUndoRedo; */
+/* break; */
+/* default: */
+/* idstrUndoBase = (idstrUndoBase == */
+/* IDSTRUndoRedo) ? IDSTRUndoBase : IDSTRUndoRedo;*/
+/* break; */
+/* } */
+/*--- idstrUndoBase = (uac != uacUReplPic && uac != uacUReplNS) ?
+ IDSTRUndoRedo : IDSTRUndoBase;---*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ Select( CpFirstSty( selCur.cpFirst, styChar ),
+ CpLastStyChar( selCur.cpLim ) );
+ break;
+
+#ifndef CASHMERE
+ case uacRepaginate:
+ /* Make a copy of the document's page table. */
+ if (!FCopyPgtb(vuab.doc, &hpgtb) || !FCopyPgtb(docUndo, &hpgtbUndo))
+ {
+ break;
+ }
+
+ /* Swap the contents of the entire document with docUndo. */
+ dcpT = CpMacText(vuab.doc);
+ dcpT2 = CpMacText(docUndo);
+ ReplaceCps(docUndo, dcpT2, cp0, vuab.doc, cp0, dcpT);
+ ReplaceCps(vuab.doc, cp0, dcpT, docUndo, cp0, dcpT2);
+ Replace(docUndo, cp0, dcpT2, fnNil, fc0, fc0);
+
+ /* Swap the page tables of the two documents. */
+ if ((hpgtbT = (**hpdocdod)[vuab.doc].hpgtb) != NULL)
+ {
+ FreeH(hpgtbT);
+ }
+ (**hpdocdod)[vuab.doc].hpgtb = hpgtbUndo;
+ if ((hpgtbT = (**hpdocdod)[docUndo].hpgtb) != NULL)
+ {
+ FreeH(hpgtbT);
+ }
+ (**hpdocdod)[docUndo].hpgtb = hpgtb;
+ vdocPageCache = docNil;
+ break;
+ case uacFormatSection:
+ pdod = &(**hpdocdod)[vuab.doc];
+ pdodUndo = &(**hpdocdod)[docUndo];
+ hsep = pdod->hsep;
+ pdod->hsep = pdodUndo->hsep;
+ pdodUndo->hsep = hsep;
+ hpgtb = pdod->hpgtb;
+ pdod->hpgtb = pdodUndo->hpgtb;
+ pdodUndo->hpgtb = hpgtb;
+/* idstrUndoBase = (idstrUndoBase == IDSTRUndoRedo) ? IDSTRUndoBase :*/
+/* IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ vdocSectCache = vdocPageCache = docMode = docNil;
+ TrashAllWws();
+ break;
+ case uacRulerChange:
+ ReplaceCps(docUndo, vuab.dcp2, cp0, vuab.doc, vuab.cp, vuab.dcp);
+ ReplaceCps(vuab.doc, vuab.cp, vuab.dcp, docUndo, cp0, vuab.dcp2);
+ Replace(docUndo, cp0, vuab.dcp2, fnNil, fc0, fc0);
+ dcpT = vuab.dcp;
+ vuab.dcp = vuab.dcp2;
+ vuab.dcp2 = dcpT;
+
+ /* This is a kludge to indicate that this is an undone ruler change.
+ */
+ vuab.itxb = 1 - vuab.itxb;
+ case uacFormatTabs:
+ pdod = &(**hpdocdod)[vuab.doc];
+ pdodUndo = &(**hpdocdod)[docUndo];
+ hgtbd = pdod->hgtbd;
+ pdod->hgtbd = pdodUndo->hgtbd;
+ pdodUndo->hgtbd = hgtbd;
+/* idstrUndoBase = (idstrUndoBase == IDSTRUndoRedo) ? IDSTRUndoBase :*/
+/* IDSTRUndoRedo;*/
+ SetUndoMenuStr(IDSTRUndoBase);
+ TrashAllWws();
+ break;
+#endif /* not CASHMERE */
+
+#if UPDATE_UNDO
+#if defined(OLE)
+ case uacObjUpdate:
+ case uacUObjUpdate:
+ ObjDoUpdateUndo(vuab.doc,vuab.cp);
+ if (uac == uacObjUpdate)
+ {
+ vuab.uac = uacUObjUpdate;
+ SetUndoMenuStr(IDSTRUndoBase);
+ }
+ break;
+#endif
+#endif
+ }
+ if (ferror)
+ NoUndo();
+ pdod = &(**hpdocdod)[vuab.doc];
+ pdodUndo = &(**hpdocdod)[docUndo];
+ f = pdod->fDirty;
+ pdod->fDirty = pdodUndo->fDirty;
+ pdodUndo->fDirty = f;
+ f = pdod->fFormatted;
+ pdod->fFormatted = pdodUndo->fFormatted;
+ pdodUndo->fFormatted = f;
+
+#ifdef CASHMERE
+ if (uac != uacMove
+#else /* not CASHMERE */
+ if (uac != uacMove && uac != uacFormatTabs && uac != uacFormatSection &&
+ uac != uacRulerChange
+#endif /* not CASHMERE */
+
+ && docCur != docNil && vuab.doc == docCur && vuab.cp >= cpMinCur &&
+ vuab.cp + dcpT <= cpMacCur)
+ {
+ if (uac == uacPictSel)
+ {
+ Select(vuab.cp, CpLimSty(vuab.cp, styPara));
+ vfPictSel = true;
+ }
+ else
+#ifdef BOGUS
+ Select( vuab.cp,
+ (dcpT == cp0) ? CpLastStyChar( vuab.cp ) :
+ vuab.cp + dcpT );
+#endif
+ Select( vuab.cp, vuab.cp + dcpT );
+ vfSeeSel = true;
+ }
+}
+
+
+BOOL near FCopyPgtb(doc, phpgtb)
+int doc;
+struct PGTB ***phpgtb;
+ {
+ /* This sets *phpgtb to a copy of the page table associated with doc. FALSE
+ is returned iff an error occurs in creating the copy of the page table. */
+
+ struct PGTB **hpgtbT;
+
+ if ((hpgtbT = (**hpdocdod)[doc].hpgtb) == NULL)
+ {
+ *phpgtb = NULL;
+ }
+ else
+ {
+ int cwpgtb = cwPgtbBase + (**hpgtbT).cpgdMax * cwPGD;
+
+ if (FNoHeap(*phpgtb = (struct PGTB **)HAllocate(cwpgtb)))
+ {
+ return (FALSE);
+ }
+ blt(*hpgtbT, **phpgtb, cwpgtb);
+ }
+ return (TRUE);
+ }
+
+
+#ifdef CASHMERE /* No Repeat-last-command in MEMO */
+CmdAgain()
+{ /* use the undo action block to repeat a command */
+ int uac;
+ typeCP dcpT;
+ typeCP cpFirst;
+ typeCP cpLim;
+ typeCP dcp;
+ struct DOD *pdod, *pdodUndo;
+
+ /* First check error conditions; this may change selCur */
+ switch (uac = vuab.uac)
+ {
+ case uacReplBuf:
+ case uacUReplBuf:
+ case uacDelBuf:
+ case uacUDelBuf:
+ case uacUDelNS:
+ case uacDelNS:
+ case uacUDelScrap:
+ case uacDelScrap:
+ case uacUReplNS:
+ case uacOvertype:
+ case uacReplNS:
+ case uacReplGlobal:
+ case uacReplScrap:
+ case uacUReplScrap:
+ /* Ensure OK to delete here */
+ if (!FWriteOk(fwcDelete))
+ return;
+ break;
+ case uacUCopyBuf:
+ case uacCopyBuf:
+ if (false)
+ return;
+ break;
+ case uacUInsert:
+ case uacInsert:
+ if (!FWriteOk(fwcInsert))
+ return;
+ break;
+ case uacMove:
+ /* Ensure OK to edit here */
+ if (!FWriteOk(fwcInsert))
+ return;
+ break;
+ default:
+ break;
+ }
+
+ /* Now set up cp's and dispatch */
+ cpFirst = selCur.cpFirst;
+ cpLim = selCur.cpLim;
+ dcp = cpLim - cpFirst;
+ switch (uac = vuab.uac)
+ {
+ struct TXB *ptxb;
+ default:
+ /* case uacNil: */
+ _beep();
+ return;
+#ifdef ENABLE /* NO GLOSSARY IN MEMO */
+ case uacReplBuf:
+ case uacUReplBuf:
+ case uacDelBuf:
+ case uacUDelBuf:
+ case uacUCopyBuf:
+ case uacCopyBuf:
+ DoAgainTxb(dcp, cpFirst);
+ break;
+#endif /* ENABLE */
+ case uacUInsert:
+ ReplaceCps(docCur, cpFirst, cp0, docUndo, cp0, vuab.dcp);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst+vuab.dcp));
+ vuab.uac = uacInsert;
+ break;
+ case uacInsert:
+ ClobberDoc(docUndo, vuab.doc, vuab.cp, vuab.dcp);
+ ReplaceCps(docCur, cpFirst, cp0, docUndo, cp0, vuab.dcp);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst+vuab.dcp));
+ break;
+ case uacUDelNS:
+ case uacDelNS:
+ ClobberDoc(docUndo, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ vuab.dcp = dcp;
+ vuab.uac = uacDelNS;
+ Select(cpFirst,CpLastStyChar(cpFirst));
+ break;
+ case uacUDelScrap:
+ case uacDelScrap:
+ ClobberDoc(docUndo,docScrap,cp0,CpMacText(docScrap));
+ ClobberDoc(docScrap, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ vuab.dcp = dcp;
+ vuab.uac = uacDelScrap;
+ Select(cpFirst, CpLastStyChar(cpFirst));
+ break;
+ case uacUReplNS:
+ vuab.dcp2 = vuab.dcp;
+ ReplaceCps(docCur, cpLim, cp0, docUndo, cp0,
+ vuab.dcp = CpMacText(docUndo));
+ ClobberDoc(docUndo, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst + vuab.dcp));
+ vuab.uac = uacReplNS;
+ break;
+ case uacOvertype:
+ /* for this one vuab.cp2 is the DCP of how much was actually
+ inserted */
+ vuab.dcp = vuab.cp2;
+ /* fall through...*/
+ case uacReplNS:
+ ClobberDoc(docUndo, vuab.doc, vuab.cp, vuab.dcp);
+ ReplaceCps(docCur, cpLim, cp0, docUndo, cp0, vuab.dcp);
+ ClobberDoc(docUndo, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ dcpT = vuab.dcp;
+ vuab.dcp2 = dcp;
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ vuab.uac = uacReplNS;
+ if (ferror) /* the operation (cmd "a") could not be completed
+ due to out of memory */
+ NoUndo();
+ else
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst + dcpT));
+ break;
+ case uacChLook:
+ case uacChLookSect:
+#ifdef ENABLE /* ChLook stuff is not hooked up yet */
+
+ DoChLook(chAgain,0);
+#endif
+ break;
+ case uacReplGlobal:
+ ClobberDoc(docUndo, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.dcp2 = dcp;
+ dcp = (typeCP)(CchSz(**hszReplace) - 1);
+ InsertRgch(docCur, cpFirst, **hszReplace, dcp, 0, 0);
+ vuab.dcp = dcp;
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst + vuab.dcp));
+ vuab.uac = uacReplNS;
+ break;
+ case uacReplScrap:
+ ClobberDoc(docUndo, vuab.doc, vuab.cp, vuab.dcp);
+ ReplaceCps(docCur, cpLim, cp0, docUndo, cp0, vuab.dcp);
+ ClobberDoc(docUndo,docScrap,cp0,CpMacText(docScrap));
+ ClobberDoc(docScrap, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst + vuab.dcp));
+ break;
+#ifdef ENABLE /* Not used in SAND */
+ case uacFormatCStyle:
+ DoFormatCStyle(rgvalAgain);
+ break;
+ case uacFormatPStyle:
+ DoFormatPStyle(rgvalAgain);
+ break;
+ case uacFormatSStyle:
+ DoFormatSStyle(rgvalAgain);
+ break;
+#endif /* ENABLE */
+#ifdef ENABLE /* Not hooked up yet */
+ case uacLookCharMouse:
+ AgainLookCharMouse();
+ break;
+ case uacLookParaMouse:
+ AgainLookParaMouse();
+ break;
+#endif /* ENABLE */
+#ifdef ENABLE /* Not used in SAND */
+ case uacClearTab:
+ DoClearTab(true);
+ vuab.uac = uac;
+ break;
+ case uacClearAllTab:
+ CmdClearAllTab();
+ vuab.uac = uac;
+ break;
+#endif /* ENABLE */
+#ifdef ENABLE /* Formatting menu stuff is not hooked up yet */
+ case uacFormatTabs:
+ DoFormatTabs(true);
+ vuab.uac = uac;
+ break;
+ case uacFormatRHText:
+ DoFormatRHText(rgvalAgain);
+ break;
+ case uacFormatChar:
+ DoFormatChar(rgvalAgain);
+ break;
+ case uacFormatPara:
+ DoFormatPara(rgvalAgain);
+ break;
+ case uacFormatSection:
+ DoFormatSection(rgvalAgain);
+ break;
+#endif /* ENABLE */
+#ifdef STYLES
+ case uacGalFormatChar:
+ DoGalFormatChar(rgvalAgain);
+ break;
+ case uacGalFormatPara:
+ DoGalFormatPara(rgvalAgain);
+ break;
+ case uacGalFormatSection:
+ DoGalFormatSection(rgvalAgain);
+ break;
+#endif /* STYLES */
+ case uacUReplScrap:
+ ReplaceCps(docCur, cpLim, cp0, docUndo, cp0,
+ vuab.dcp = CpMacText(docUndo));
+ ClobberDoc(docUndo,docScrap,cp0,CpMacText(docScrap));
+ ClobberDoc(docScrap, docCur, cpFirst, dcp);
+ Replace(docCur, cpFirst, dcp, fnNil, fc0, fc0);
+ vuab.doc = docCur;
+ vuab.cp = cpFirst;
+ Select(cpFirst+vuab.dcp, CpLastStyChar(cpFirst + vuab.dcp));
+ vuab.uac = uacReplScrap;
+ break;
+ case uacMove:
+ if (!FMoveText(vuab.doc2, vuab.cp2, vuab.dcp, docCur, &cpFirst, fFalse))
+ return;
+ vuab.cp = vuab.cp2;
+ vuab.cp2 = cpFirst;
+ vuab.doc = vuab.doc2;
+ vuab.doc2 = docCur;
+ CheckMove();
+ break;
+ }
+ vfSeeSel = true;
+}
+#endif /* CASHMERE */
+
diff --git a/private/mvdm/wow16/write/util.c b/private/mvdm/wow16/write/util.c
new file mode 100644
index 000000000..38bb7d4c1
--- /dev/null
+++ b/private/mvdm/wow16/write/util.c
@@ -0,0 +1,556 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* util.c -- more frequently used utility routines */
+#define NOCOLOR
+#define NOCOMM
+#define NOCLIPBOARD
+#define NOCTLMGR
+#define NOGDICAPMASKS
+#define NOMENUS
+#define NOSOUND
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#include <windows.h>
+
+#if WINVER < 0x300
+#define SM_CURSORLEVEL 25
+#endif
+
+#include "mw.h"
+#include "doslib.h"
+#include "str.h"
+#include "machdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "docdefs.h"
+#include "debug.h"
+#include "editdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES
+#include "ch.h"
+
+extern struct DOD (**hpdocdod)[];
+extern HANDLE hMmwModInstance;
+
+CHAR *PchFillPchId(PCH, int);
+
+typeCP CpMax(cp1, cp2)
+typeCP cp1, cp2;
+{{ /* return larger of two cps */
+ return((cp1 > cp2) ? cp1 : cp2);
+}} /* end of C p M a x */
+
+
+typeCP CpMin(cp1, cp2)
+typeCP cp1, cp2;
+{{ /* return smaller of two cps */
+ return((cp1 < cp2) ? cp1 : cp2);
+}} /* end of C p M i n */
+
+
+unsigned umin( w1, w2 )
+register unsigned w1, w2;
+{ return (w1 < w2) ? w1 : w2; }
+
+
+unsigned umax( w1, w2 )
+register unsigned w1, w2;
+{ return (w1 > w2) ? w1 : w2; }
+
+
+int imin( i1, i2 )
+register int i1, i2;
+{ return (i1 < i2) ? i1 : i2; }
+
+
+int imax( i1, i2 )
+register int i1, i2;
+{ return (i1 > i2) ? i1 : i2; }
+
+
+#define BZNATIVE
+#ifndef BZNATIVE
+/* C C H D I F F E R */
+/* commented out, moved to native code in lib.asm bz 6/20/85 */
+int CchDiffer(rgch1, rgch2, cch)
+register CHAR *rgch1, *rgch2;
+int cch;
+{{ /* Return cch of shortest prefix leaving a common remainder */
+int ich;
+
+for (ich = cch - 1; ich >= 0; ich--)
+ if (rgch1[ich] != rgch2[ich])
+ break;
+return ich + 1;
+}}
+#endif
+
+
+int CchSz(sz)
+register CHAR sz[];
+{ /* Returns length of string in bytes, including trailing 0 */
+ register int cch = 1;
+ while (*sz++ != 0)
+ cch++;
+ return cch;
+} /* end of C c h S z */
+
+
+
+typeCP CpMacText(doc)
+register int doc;
+{
+#ifdef FOOTNOTES
+ struct FNTB **hfntb;
+ if ((hfntb = HfntbGet(doc)) != 0)
+ return((**hfntb).rgfnd[0].cpFtn - ccpEol);
+ else
+#endif /* FOOTNOTES */
+ return((**hpdocdod)[doc].cpMac);
+
+} /* end of C p M a c T e x t */
+
+
+struct FNTB **HfntbGet(doc)
+register int doc;
+{ /* Return hfntb if doc has one, 0 if none or style sheet */
+#ifdef STYLES
+ register struct DOD *pdod;
+
+ if ((pdod = &(**hpdocdod)[doc])->dty == dtySsht)
+ return 0;
+ else
+#endif
+ return (**hpdocdod)[doc].hfntb;
+} /* end of H F n t b G e t */
+
+
+/* N O U N D O */
+NoUndo()
+{
+ extern struct UAB vuab;
+ vuab.uac = uacNil;
+ SetUndoMenuStr(IDSTRUndoBase);
+} /* end of N o U n d o */
+
+
+
+
+SetUndoMenuStr(idstr)
+int idstr;
+{
+ extern int idstrCurrentUndo;
+
+ idstrCurrentUndo = idstr;
+}
+
+
+/* Returns number chars copied EXCLUDING zero terminator */
+
+int CchCopySz(pchFrom, pchTo)
+register PCH pchFrom;
+register PCH pchTo;
+{
+int cch = 0;
+while ((*pchTo = *pchFrom++) != 0)
+ {
+ pchTo++;
+ cch++;
+ }
+return cch;
+} /* end of C c h C o p y S z */
+
+
+
+
+/*---------------------------------------------------------------------------
+-- Routine: WCompSz(psz1,psz2)
+-- Description and Usage:
+ Alphabetically compares the two null-terminated strings lpsz1 and lpsz2.
+ Upper case alpha characters are mapped to lower case.
+ Comparison of non-alpha characters is by ascii code.
+ Returns 0 if they are equal, a negative number if lpsz1 precedes lpsz2, and
+ a non-zero positive number if lpsz2 precedes lpsz1.
+-- Arguments:
+ psz1, psz2 - pointers to two null-terminated strings to compare
+-- Returns:
+ a short - 0 if strings are equal, negative number if lpsz1 precedes lpsz2,
+ and non-zero positive number if psz2 precedes psz1.
+-- Side-effects: none
+-- Bugs:
+-- History:
+ 3/14/83 - created (tsr)
+ 6/12/86 - Kanji Version (yxy)
+----------------------------------------------------------------------------*/
+short
+
+WCompSz(psz1,psz2)
+register PCH psz1;
+register PCH psz2;
+{
+ int ch1;
+ int ch2;
+
+ for(ch1=ChLower(*psz1++),ch2=ChLower(*psz2++);
+ ch1==ch2;
+ ch1=ChLower(*psz1++),ch2=ChLower(*psz2++))
+ {
+ if(ch1 == '\0')
+ return(0);
+ }
+ return(ch1-ch2);
+} /* end of W C o m p S z */
+
+
+/*---------------------------------------------------------------------------
+-- Routine: ChLower(ch)
+-- Description and Usage:
+ Converts its argument to lower case iff its argument is upper case.
+ Returns the de-capitalized character or the initial char if it wasn't caps.
+-- Arguments:
+ ch - character to be de-capitalized
+-- Returns:
+ a character - initial character, de-capitalized if needed.
+-- Side-effects:
+-- Bugs:
+-- History:
+ 3/14/83 - created (tsr)
+----------------------------------------------------------------------------*/
+int
+ChLower(ch)
+register CHAR ch;
+{ /* use Windows' ANSI char set, the difference of upper/lower case
+ is also 20 (HEX) for foreign chars */
+#ifdef JAPAN
+// check for half-size katakana.
+ extern struct WWD rgwwd[];
+ extern BOOL IsKanaInDBCS(int);
+ static TEXTMETRIC tm;
+ if(IsWindow(wwdCurrentDoc.wwptr)
+ && GetTextMetrics(wwdCurrentDoc.hDC,(LPTEXTMETRIC)&tm)){
+ if(tm.tmCharSet == SHIFTJIS_CHARSET && IsKanaInDBCS((int)ch))
+ return (int)(0x00ff&ch);
+ }
+#endif
+
+#ifdef KOREA
+ if(isupper(ch) && !((ch > 0xa1) && (ch < 0xfe)))
+#else
+ if(isupper(ch))
+#endif
+
+ return(ch + ('a' - 'A')); /* foreign is taken care of */
+ else
+ return ch;
+} /* end of C h L o w e r */
+
+
+
+static int cLongOpCount = 0; /* to ensure we don't do too much hide cursor */
+
+StartLongOp()
+{
+extern int vfInLongOperation;
+extern int vfCursorVisible;
+extern int vfMouseExist;
+extern HCURSOR vhcHourGlass;
+
+int cursorlevel;
+
+if (cLongOpCount++ == 0)
+ {
+ vfInLongOperation = TRUE;
+ vfCursorVisible = TRUE;
+
+ if (!vfMouseExist)
+ { /* in a mouseless system, set the cursor to middle of window */
+ extern HWND vhWndMsgBoxParent;
+ extern HWND hParentWw;
+ extern int vfInitializing;
+ RECT rect;
+ POINT pt;
+ HWND hWnd = vhWndMsgBoxParent;
+
+ if (vhWndMsgBoxParent == NULL)
+ hWnd = hParentWw; /* next choice */
+ if (!vfInitializing && hWnd != NULL && IsWindow(hWnd))
+ { /* we have a good window to put in */
+ GetClientRect(hWnd, (LPRECT)&rect);
+ pt.x = (rect.right - rect.left) / 2;
+ pt.y = (rect.bottom - rect.top) / 2;
+ ClientToScreen(hWnd, (LPPOINT)&pt);
+ }
+ else
+ { /* put in the middle of screen */
+ HDC hDCScreen = GetDC(NULL);
+ if (hDCScreen == NULL)
+ goto Out; /* the worst, setcursor only */
+ pt.x = GetDeviceCaps(hDCScreen, HORZRES) / 2;
+ pt.y = GetDeviceCaps(hDCScreen, VERTRES) / 2;
+ ReleaseDC(NULL, hDCScreen);
+ }
+ SetCursorPos(pt.x, pt.y);
+ }
+Out:
+ SetCursor(vhcHourGlass);
+#if WINVER < 0x300
+ ShowCursor(TRUE);
+
+ /* precaution - make sure the cusor is visible */
+ cursorlevel = GetSystemMetrics(SM_CURSORLEVEL);
+#else
+ /* use a supported method to get cursor level! ..pault 2/6/90 */
+ cursorlevel = ShowCursor(TRUE);
+#endif
+ while (cursorlevel++ < 0)
+ ShowCursor(TRUE);
+ }
+}
+
+
+EndLongOp(hc)
+HCURSOR hc; /* cursor to be changed to */
+{
+extern int vfInLongOperation;
+extern int vfCursorVisible;
+extern int vfMouseExist;
+extern int vfDeactByOtherApp;
+
+int cursorlevel;
+
+if (cLongOpCount > 0)
+ {
+ if (vfDeactByOtherApp && (cLongOpCount == 1)) // OLE presents this case
+ {
+ vfInLongOperation = FALSE;
+ vfCursorVisible = FALSE;
+ SetCursor(vfMouseExist ? hc : NULL);
+ }
+ else if (--cLongOpCount == 0)
+ {
+ vfInLongOperation = FALSE;
+ vfCursorVisible = FALSE;
+#if WINVER < 0x300
+ ShowCursor(FALSE);
+ SetCursor(vfMouseExist ? hc : NULL);
+
+ /* make sure the cursor is still visible in a mouse system
+ and invisible in a mouseless system */
+ cursorlevel = GetSystemMetrics(SM_CURSORLEVEL);
+#else
+ /* use a supported method to get cursor level! ..pault 2/6/90 */
+ cursorlevel = ShowCursor(FALSE);
+ SetCursor(vfMouseExist ? hc : NULL);
+#endif
+ if (vfMouseExist)
+ {
+ while (cursorlevel++ < 0)
+ ShowCursor(TRUE);
+ }
+ else /* no mouse */
+ {
+ while (cursorlevel-- >= 0)
+ ShowCursor(FALSE);
+ }
+ }
+ }
+}
+
+
+/* String utility functions - moved here from string.c */
+
+/* I N D E X */
+/* ** Returns pointer to first occurrence of character ch found in null-
+ terminated string pch, or 0 if ch does not appear. If ch==0, we
+ return a pointer to the null terminator. */
+/* In Kanji version, a kanji character is excluded from the search. */
+
+CHAR *index(pch, ch)
+REG1 CHAR *pch;
+REG2 CHAR ch; // fixed bug, previously int (2.11.91) D. Kent
+ {
+ while (low(*pch)!=ch)
+ {
+#ifdef DBCS /* KenjiK '90-11-20 */
+ if (*pch=='\0')
+#else
+ if (*pch++=='\0')
+#endif
+ return(NULL);
+#ifdef DBCS /* KenjiK '90-11-20 */
+ pch = AnsiNext(pch);
+#endif
+ }
+ return(pch);
+ }
+
+/* We may want to make these 'type' functions into macros */
+/* These are designed for ANSI character set (used by windows) only */
+
+/* I S A L P H A */
+/* ** TRUE if ch is a letter, FALSE otherwise */
+
+isalpha(ch)
+REG1 CHAR ch;
+ {/* Note: even though DF and FF are lowercase, they have no
+ corresponding uppercase, so they are excluded from the
+ lowercase class, and simply mapped to themselves */
+ return(islower(ch) || isupper(ch) || ch == 0x00FF || ch == 0x00DF);
+ }
+
+
+/* ** TRUE if ch is a lowercase letter, FALSE otherwise */
+
+/* I S L O W E R */
+islower(ch)
+REG1 CHAR ch;
+ {/* Note: even though DF and FF are lowercase, they have no
+ corresponding uppercase, so they are excluded from the
+ lowercase class, and simply mapped to themselves */
+ return((ch >= 'a' && ch <= 'z') ||
+ /* foreign */
+ (ch >= 0x00E0 && ch <= 0x00F6) ||
+ (ch >= 0x00F8 && ch <= 0x00FE) );
+ }
+
+/* ** TRUE if ch is an uppercase letter, FALSE otherwise */
+
+isupper(ch)
+REG1 CHAR ch;
+ {
+ return((ch >= 'A' && ch <= 'Z') ||
+ /* foreign */
+ (ch >= 0x00C0 && ch <= 0x00D6) ||
+ (ch >= 0x00D8 && ch <= 0x00DE));
+ }
+
+/* ** TRUE if ch is a digit, FALSE otherwise */
+
+isdigit(ch)
+REG1 CHAR ch;
+ {
+ return(ch>='0' && ch<='9');
+ }
+
+
+#ifdef ENABLE
+/* ** TRUE if ch is a character or a digit, FALSE otherwise */
+
+isalnum(ch)
+REG1 CHAR ch;
+ {
+ return(isalpha(ch) || isdigit(ch));
+ }
+#endif
+
+
+
+int ChUpper(ch)
+REG1 CHAR ch;
+{
+#ifdef DBCS
+ return AnsiUpper( ch );
+#else
+#ifdef BOGUS
+return (ch >= 'a' && ch <= 'z') ? ch + ('A' - 'a') : ch;
+#endif
+/* use Windows' ANSI char set, the difference of upper/lower case
+ is also 20 (HEX) for foreign chars */
+
+ if (islower(ch))
+ return(ch + ('A' - 'a')); /* foreign is taken care of */
+ else return(ch);
+#endif
+}
+
+
+
+
+/* similar to blcomp except compares by bytes and is not case sensitive */
+BOOL FRgchSame(rgch1, rgch2, cch)
+CHAR rgch1[], rgch2[];
+int cch;
+ {
+ short ich;
+
+ for(ich = 0; ich < cch; ich++)
+ {
+ if(ChLower(rgch1[ich]) != ChLower(rgch2[ich]))
+ return(FALSE);
+ }
+ return(TRUE);
+ }
+
+/* PchStartBaseNameSz() ---- returns a character pointer to the
+ beginning of a base file name. If
+ the name only consists of a base
+ name, sz is returned.
+
+ Note: If sz ends with a back-slash or a colon, pch returned
+ is pointing to the null terminator of the given string. */
+
+CHAR *PchStartBaseNameSz(sz)
+ CHAR *sz;
+{
+ CHAR *pchBS, *pchC, *pchLast;
+ CHAR *PchLastSzCh();
+
+ pchBS = PchLastSzCh(sz, '\\');
+ pchC = PchLastSzCh(sz, ':');
+ pchLast = (pchBS > pchC) ? pchBS : pchC;
+ if (pchLast == NULL) {
+ pchLast = sz;
+ }
+ else {
+ pchLast++;
+ }
+ return (pchLast);
+}
+
+/* PchLastSzCh() ----- returns a pointer to the last occurrence of a given
+ character in a given string. If it does not occur
+ in the string, it returns NULL. If the given
+ character is '\0', it returns sz itself.
+ Note: All kanji characters are excluded from the search. */
+
+CHAR *PchLastSzCh(sz, ch)
+ CHAR *sz;
+ CHAR ch;
+{
+ if (ch == '\0') {
+ return (sz);
+ }
+ else {
+ CHAR *pchCur, *pchLast;
+
+#ifdef DBCS
+ for (pchLast = pchCur = sz; *pchCur != '\0'; pchCur = AnsiNext(pchCur))
+#else
+ for (pchLast = pchCur = sz; *pchCur != '\0'; pchCur++)
+#endif
+ {
+ {
+ if (low(*pchCur) == ch) {
+ pchLast = pchCur;
+ }
+ }
+ }
+ return ((pchLast == sz) ? NULL : pchLast);
+ }
+}
+
+#ifdef DEBUG
+_Assert(pch, line, f)
+PCH pch;
+int line;
+BOOL f;
+ {
+ if (!f)
+ Do_Assert(pch, line, f);
+ }
+#endif
+
diff --git a/private/mvdm/wow16/write/util2.c b/private/mvdm/wow16/write/util2.c
new file mode 100644
index 000000000..75e7cf1d1
--- /dev/null
+++ b/private/mvdm/wow16/write/util2.c
@@ -0,0 +1,418 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* util2.c -- less frequently used utility routines */
+#define NOVIRTUALKEYCODES
+#define NOCTLMGR
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOCOMM
+#define NOSOUND
+#include <windows.h>
+
+#include "mw.h"
+#include "doslib.h"
+#include "str.h"
+#include "machdefs.h"
+#include "cmddefs.h"
+#include "propdefs.h"
+#include "fkpdefs.h"
+#include "docdefs.h"
+#include "debug.h"
+#include "editdefs.h"
+#include "wwdefs.h"
+#define NOKCCODES
+#include "ch.h"
+
+extern struct DOD (**hpdocdod)[];
+extern HANDLE hMmwModInstance;
+extern CHAR vchDecimal; /* "decimal point" character */
+extern int viDigits;
+extern BOOL vbLZero;
+CHAR *PchFillPchId(PCH, int, int);
+
+
+
+FillStId(st, idpmt, cchIn)
+CHAR *st;
+IDPMT idpmt;
+int cchIn;
+{ /* load string from resource file to buffer, the string is zero
+ terminated, make it into a st, i.e. cch (excluding '\0' is stored
+ in the 1st byte of the string) */
+
+ int cch = LoadString(hMmwModInstance, idpmt, (LPSTR)&st[1], cchIn-1);
+ Assert(cch != 0);
+ st[0] = cch;
+} /* FillStId */
+
+
+CHAR *PchFillPchId(sz, idstr, cchIn)
+register CHAR * sz;
+register int idstr;
+int cchIn;
+{ /*
+ Description: load string from resource file to buffer, the
+ string loaded is zero terminated
+ Returns: pointer to '\0' last loaded
+*/
+ int cch = LoadString(hMmwModInstance, idstr, (LPSTR)sz, cchIn);
+ /* Note: cch does not include the '\0' */
+{
+ char msg[80];
+ if (cch == 0)
+ {
+ wsprintf(msg,"bad resource id: 0x%x\n\r",idstr);
+ OutputDebugString(msg);
+ }
+ Assert(cch != 0);
+}
+ return(sz + cch);
+} /* end of PchFillPchId */
+
+
+int FDirtyDoc(doc)
+register int doc;
+{ /* Return true if killing this doc would lose editing */
+ register struct DOD *pdod;
+ return ((pdod = &(**hpdocdod)[doc])->fDirty && pdod->cref == 1);
+} /* end of F D i r t y D o c */
+
+
+int ncvtu(n, ppch)
+register int n;
+CHAR **ppch;
+{
+ register int cch = 0;
+
+ if (n < 0)
+ {
+ *(*ppch)++ = '-';
+ n = -n;
+ ++cch;
+ }
+
+ if (n >= 10)
+ {
+ cch += ncvtu(n / 10, ppch);
+ n %= 10;
+ }
+ else if ((n == 0) && !vbLZero) // then no leading zero
+ return 0;
+
+ *(*ppch)++ = '0' + n;
+ return cch + 1;
+} /* end of n c v t uR */
+
+
+HANDLE HszGlobalCreate( sz )
+CHAR *sz;
+{ /* Create handle for string in global windows heap. return the handle. */
+ HANDLE h;
+ LPCH lpch;
+ int cch=CchSz( sz );
+
+ if ((h=GlobalAlloc( GMEM_MOVEABLE, (LONG)cch )) != NULL)
+ {
+ if ((lpch = GlobalLock( h )) != NULL )
+ {
+ bltbx( (LPSTR) sz, lpch, cch );
+ GlobalUnlock( h );
+ }
+ else
+ {
+ GlobalFree( h );
+ return NULL;
+ }
+ }
+ return h;
+}
+
+
+
+
+#ifdef DEBUG
+fnScribble( dchPos, ch )
+int dchPos;
+CHAR ch;
+{ /* Scribble a char dchPos char positions from the UR screen corner */
+ /* We create a special device context to avoid interfering with the */
+ /* ones MEMO uses */
+ extern struct WWD rgwwd[];
+
+ static unsigned dxpScribbleChar=0;
+ static unsigned dypScribbleChar;
+ static unsigned ypScribble;
+
+ int xp = wwdCurrentDoc.xpMac - (dxpScribbleChar * (dchPos+1));
+ int ilevel = SaveDC( wwdCurrentDoc.hDC );
+
+ SelectObject( wwdCurrentDoc.hDC, GetStockObject(ANSI_FIXED_FONT) );
+
+ if ( dxpScribbleChar == 0 )
+ { /* First time through */
+ TEXTMETRIC tm;
+
+ GetTextMetrics( wwdCurrentDoc.hDC, (LPTEXTMETRIC)&tm );
+ dxpScribbleChar = tm.tmAveCharWidth;
+ dypScribbleChar = tm.tmHeight + tm.tmInternalLeading;
+ ypScribble = (dypScribbleChar >> 2) + wwdCurrentDoc.ypMin;
+ }
+ PatBlt( wwdCurrentDoc.hDC, xp, ypScribble, dxpScribbleChar, dypScribbleChar,
+ WHITENESS );
+ TextOut( wwdCurrentDoc.hDC, xp, ypScribble, (LPSTR) &ch, 1 );
+ RestoreDC( wwdCurrentDoc.hDC, ilevel );
+}
+#endif /* DEBUG */
+
+
+/* original util3.c starts from here */
+
+#define iMaxOver10 3276
+extern int utCur;
+
+/* Must agree with cmddefs.h */
+extern CHAR *mputsz[];
+
+/* Must agree with cmddefs.h */
+unsigned mputczaUt[utMax] =
+ {
+ czaInch, czaCm, czaP10, czaP12, czaPoint,
+ czaLine
+ };
+
+
+
+int FZaFromSs(pza, ss, cch, ut)
+int *pza;
+CHAR ss[];
+int cch,
+ ut;
+{ /* Return za in *pza from string representation in ss. True if valid za */
+long lza = 0;
+register CHAR *pch = ss;
+register CHAR *pchMac = &ss[cch];
+int ch;
+unsigned czaUt;
+int fNeg;
+
+if (cch <= 0)
+ return false;
+
+switch (*--pchMac)
+ { /* Check for units */
+case 'n': /* inch */
+ if (*--pchMac != 'i')
+ goto NoUnits;
+case '"': /* inch */
+ ut = utInch;
+ break;
+
+#ifdef CASHMERE /* units such as pt, pt12, pt10 */
+case '0': /* pt10 */
+ if (*--pchMac != '1' || *--pchMac != 'p')
+ goto NoUnits;
+ ut = utP10;
+ break;
+case '2': /* pt12 */
+ if (*--pchMac != '1' || *--pchMac != 'p')
+ goto NoUnits;
+ ut = utP12;
+ break;
+case 'i': /* line */
+ if (*--pchMac != 'l')
+ goto NoUnits;
+ ut = utLine;
+ break;
+case 't': /* pt */
+ if (*--pchMac != 'p')
+ goto NoUnits;
+ ut = utPoint;
+ break;
+#endif /* CASHMERE */
+
+case 'm': /* cm */
+ if (*--pchMac != 'c')
+ goto NoUnits;
+ ut = utCm;
+ break;
+default:
+ ++pchMac;
+ break;
+NoUnits:
+ pchMac = &ss[cch];
+ }
+
+while (pch < pchMac && *(pchMac - 1) == chSpace)
+ --pchMac;
+
+czaUt = mputczaUt[ut];
+
+/* extract leading blanks */
+while (*pch == ' ')
+ pch++;
+
+fNeg = *pch == '-';
+if (fNeg) ++pch; /* skip past minus sign */
+while ((ch = *pch++) != vchDecimal)
+ {
+ if ((ch < '0' || ch > '9') || lza >= iMaxOver10)
+ return false;
+ lza = lza * 10 + (ch - '0') * czaUt;
+ if (pch >= pchMac)
+ goto GotNum;
+ }
+
+while (pch < pchMac)
+ {
+ ch = *pch++;
+ if (ch < '0' || ch > '9')
+ return false;
+ lza += ((ch - '0') * czaUt + 5) / 10;
+ czaUt = (czaUt + 5) / 10;
+ }
+
+GotNum:
+if (lza > ((long) (22 * czaInch)))
+ return false;
+
+*pza = fNeg ? (int) -lza : (int) lza;
+return true;
+}
+
+
+
+int
+CchExpZa(ppch, za, ut, cchMax)
+CHAR **ppch;
+int ut, cchMax;
+register int za;
+{ /* Stuff the expansion of linear measure za in unit ut into pch.
+ Return # of chars stuffed. Don't exceed cchMax. */
+register int cch = 0;
+unsigned czaUt;
+int zu;
+
+/* If not in point mode and even half line, display as half lines v. points */
+if (ut == utPoint && utCur != utPoint &&
+ (za / (czaLine / 2) * (czaLine / 2)) == za)
+ ut = utLine;
+
+
+czaUt = mputczaUt[ut];
+if (cchMax < cchMaxNum)
+ return 0;
+
+if (za < 0)
+ { /* Output minus sign and make positive */
+ *(*ppch)++ = '-';
+ za = -za;
+ cch++;
+ }
+
+/* round off to two decimal places */
+za += czaUt / 200;
+
+zu = za / czaUt; /* Get integral part */
+
+cch += ncvtu(zu, ppch); /* Expand integral part */
+
+za -= zu * czaUt; /* Retain fraction part */
+
+if (((za *= 10) >= czaUt || za * 10 >= czaUt) && (viDigits > 0))
+ { /* Check *10 first because of possible overflow */
+ zu = za / czaUt;
+
+ *(*ppch)++ = vchDecimal;
+ cch++;
+
+ *(*ppch)++ = '0' + zu;
+ cch++;
+ zu = ((za - zu * czaUt) * 10) / czaUt;
+ if ((zu != 0) && (viDigits > 1))
+ {
+ *(*ppch)++ = '0' + zu;
+ cch++;
+ }
+ }
+
+if (cch <= 1)
+/* force zeroes */
+{
+ if ((cch == 0) && vbLZero) // then no leading zero
+ {
+ *(*ppch)++ = '0';
+ cch++;
+ }
+ *(*ppch)++ = vchDecimal;
+ cch++;
+ if (viDigits > 0)
+ {
+ *(*ppch)++ = '0';
+ cch++;
+ }
+ if (viDigits > 1)
+ {
+ *(*ppch)++ = '0';
+ cch++;
+ }
+}
+
+cch += CchStuff(ppch, mputsz[ut], cchMax - cch);
+
+return cch;
+}
+
+
+#ifdef KEEPALL /* Use FPdxaFromItDxa2Id */
+int DxaFromSt(st, ut)
+register CHAR *st;
+int ut;
+{
+int za;
+
+if (*st > 0 && FZaFromSs(&za, st+1, *st, ut)) /* see util.c */
+ return za;
+else
+ return valNil;
+}
+
+int DxaFromItem(it)
+int it;
+{
+int za;
+register CHAR stBuf[32];
+
+GetItTextValue(it, stBuf);
+
+if (*stBuf > 0 && FZaFromSs(&za, stBuf+1, *stBuf, utCur)) /* see util.c */
+ return (za == valNil) ? 0 : za;
+else
+ return valNil;
+}
+#endif
+
+int CchStuff(ppch, sz, cchMax)
+CHAR **ppch, sz[];
+int cchMax;
+{
+register int cch = 0;
+register CHAR *pch = *ppch;
+
+while (cchMax-- > 0 && (*pch = *sz++) != 0)
+ {
+ cch++;
+ pch++;
+ }
+
+if (cchMax < 0)
+ bltbyte("...", pch - 3, 3);
+
+*ppch = pch;
+return cch;
+}
diff --git a/private/mvdm/wow16/write/vgabtns.bmp b/private/mvdm/wow16/write/vgabtns.bmp
new file mode 100644
index 000000000..7f01da87a
--- /dev/null
+++ b/private/mvdm/wow16/write/vgabtns.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/vgamarks.bmp b/private/mvdm/wow16/write/vgamarks.bmp
new file mode 100644
index 000000000..df5407af0
--- /dev/null
+++ b/private/mvdm/wow16/write/vgamarks.bmp
Binary files differ
diff --git a/private/mvdm/wow16/write/winddefs.h b/private/mvdm/wow16/write/winddefs.h
new file mode 100644
index 000000000..9cea46df4
--- /dev/null
+++ b/private/mvdm/wow16/write/winddefs.h
@@ -0,0 +1,78 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+/* MS-Windows specific definitions */
+
+#define tidCaret 7734 /* Timer ID for caret blink (stand on your
+ head to read it) */
+
+/* dwHsecKeyDawdle is the number of hundredths of seconds that we loop,
+ waiting for keys, before we update the display. See insert.c */
+
+#define dwHsecKeyDawdle 35
+
+/* File rename/deletion coordination messages sent btwn WRITE instances */
+
+#define wWndMsgDeleteFile (WM_USER + 36)
+#define wWndMsgRenameFile (WM_USER + 37)
+
+/* System information message posted to self */
+
+#define wWndMsgSysChange (WM_USER + 38)
+
+#define wWininiChangeToWindows 1 /* used in posting above message */
+#define wWininiChangeToDevices 2
+#define wWininiChangeToIntl 4
+#define wWininiChangeMax ((1|2|4) + 1)
+
+#ifndef NOMETAFILE
+/* *** PICTURE THINGS *** */
+
+#define dypPicSizeMin 16 /* Smallest y-extent of a picture, in pixels */
+ /* Also the dl height in a picture */
+
+#define MM_NIL -1
+#define MM_BITMAP 99 /* A Phony mapping mode code used within MEMO */
+ /* xExt, yExt must be filled out as for MM_TEXT */
+#define MM_OLE 100 /* Another phony mapping mode code used
+ with Objects/Links */
+
+#define MM_EXTENDED 0x80 /* Bit set for New file format */
+
+/* A Bitmap or Picture appears in a file as a PICINFO or PICINFOX
+ + an Array of Bits,
+ if it's a bitmap, or the contents of a memory metafile, if it's a picture.
+ This all appears in the cp stream
+ A PICINFO is a PICINFOX without the extended format fields.
+ a PICINFO has the mfp.mm MM_EXTENDED bit cleared
+ a PICINFOX has the mfp.mm MM_EXTENDED bit set
+*/
+
+/* If you change this, you must change "cchOldPICINFO" */
+
+struct PICINFOX {
+ METAFILEPICT mfp;
+ int dxaOffset;
+ int dxaSize;
+ int dyaSize;
+ unsigned cbOldSize; /* For old file support only */
+ BITMAP bm; /* Additional info for bitmaps only */
+
+ /* Extended format -- add these fields */
+
+ unsigned cbHeader; /* Size of this header (sizeof (struct PICINFOX)) */
+ unsigned long cbSize; /* This field replaces cbOldSize on new files */
+
+ unsigned mx, my; /* Multiplier for scaled bitmap */
+};
+
+#define mxMultByOne 1000 /* mx == 1 implies same size; 2 doubles, etc. */
+#define myMultByOne 1000
+
+
+#define cchOldPICINFO (sizeof(struct PICINFOX) - sizeof(long) - \
+ sizeof(unsigned) - 2 * sizeof (int))
+
+#define cchPICINFOX (sizeof(struct PICINFOX))
+#endif /* ifndef NOMETAFILE */
diff --git a/private/mvdm/wow16/write/write.def b/private/mvdm/wow16/write/write.def
new file mode 100644
index 000000000..18f998ded
--- /dev/null
+++ b/private/mvdm/wow16/write/write.def
@@ -0,0 +1,79 @@
+;************************************************************/
+;* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+;************************************************************/
+
+NAME write WINDOWAPI
+DESCRIPTION 'Microsoft WRITE'
+EXETYPE WINDOWS
+PROTMODE
+STUB 'WINSTUB.EXE'
+
+CODE LOADONCALL MOVEABLE DISCARDABLE
+DATA MULTIPLE PRELOAD MOVEABLE
+
+SEGMENTS
+ _TEXT PRELOAD MOVEABLE DISCARDABLE
+ INITWIN_TEXT PRELOAD MOVEABLE DISCARDABLE
+ UTIL_TEXT PRELOAD MOVEABLE DISCARDABLE
+ UTIL2_TEXT PRELOAD MOVEABLE DISCARDABLE
+ INITMMW_TEXT PRELOAD MOVEABLE DISCARDABLE
+ SCRNCHNG_TEXT PRELOAD MOVEABLE DISCARDABLE
+ SCREEN_TEXT PRELOAD MOVEABLE DISCARDABLE
+ FONTENUM_TEXT PRELOAD MOVEABLE DISCARDABLE
+ FONTUTIL_TEXT PRELOAD MOVEABLE DISCARDABLE
+ CREATEWW_TEXT PRELOAD MOVEABLE DISCARDABLE
+ PAGEINFO_TEXT PRELOAD MOVEABLE DISCARDABLE
+ MDOC_TEXT PRELOAD MOVEABLE DISCARDABLE
+ CHNGWIN_TEXT PRELOAD MOVEABLE DISCARDABLE
+ HEAPMAIN_TEXT PRELOAD MOVEABLE DISCARDABLE
+ FILE_TEXT PRELOAD MOVEABLE DISCARDABLE
+ FILEUTIL_TEXT PRELOAD MOVEABLE DISCARDABLE
+ FILERES_TEXT PRELOAD MOVEABLE DISCARDABLE
+ MMW_TEXT PRELOAD MOVEABLE DISCARDABLE
+
+HEAPSIZE 12000
+STACKSIZE 8000
+
+EXPORTS
+ MmwWndProc @1
+ MdocWndProc @2
+ RulerWndProc @3
+ PageInfoWndProc @4
+ ;DialogOpen @5
+ ;DialogSaveAs @6
+ ;DialogPrint @7
+ DialogCancelPrint @8
+ DialogRepaginate @9
+ DialogSetPage @10
+ DialogPageMark @11
+ ;DialogPrinterSetup @12
+ ;DialogHelp @13
+ ;DialogCharFormats @14
+ DialogParaFormats @15
+ DialogGoTo @16
+ DialogFind @17
+ DialogChange @18
+ DialogRunningHead @19
+ DialogTabs @20
+ DialogDivision @21
+ DialogBadMargins @22
+ FontFaceEnum @23
+ BroadcastAllEnum @24
+ BroadcastChildEnum @25
+ FCheckPopupRect @26
+ FPrContinue @27
+ DialogWordCvt @28
+
+; OLE functions
+;
+ CallBack @29
+ BufReadStream @30
+ BufWriteStream @31
+ fnProperties @32
+ fnInvalidLink @33
+ fnInsertNew @34
+ fnOFNHook @35
+ fnObjWait @36
+ fnPasteSpecial @37
+
+
diff --git a/private/mvdm/wow16/write/write.ico b/private/mvdm/wow16/write/write.ico
new file mode 100644
index 000000000..e056c47a0
--- /dev/null
+++ b/private/mvdm/wow16/write/write.ico
Binary files differ
diff --git a/private/mvdm/wow16/write/write.itl b/private/mvdm/wow16/write/write.itl
new file mode 100644
index 000000000..fc8a549c4
--- /dev/null
+++ b/private/mvdm/wow16/write/write.itl
@@ -0,0 +1,641 @@
+/* This is the source file for the resource file for Windows Write. The
+resource file is generated by running this file through the resouce compiler
+RC.EXE. */
+
+
+
+#define INTL /* International version */
+
+#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "menudefs.h"
+#include "dlgdefs.h"
+#include "str.h"
+#define DI_QUESTION 32514 /* have to match windows.h MAKEINTRESOURCE(n) */
+#define DI_EXCLAMATION 32515 /* have to match windows.h MAKEINTRESOURCE(n) */
+
+STRINGTABLE
+BEGIN
+
+IDS_MERGE1 "%%" /* relocatable message symbol */
+
+/* Menu and Undo strings */
+/* WARNING: The length of the longest UNDO string is kept as a constant
+ in str.h. This constant must be updated along with the strings */
+IDSTRUndoBase,"~Undo "
+IDSTRUndoEdit,"Editing"
+IDSTRUndoLook,"Formatting"
+IDSTRUndoTyping,"Typing"
+IDSTRShowRuler,"Ruler On"
+IDSTRHideRuler,"Ruler Off"
+
+#ifdef ONLINEHELP
+IDSTRAbout, "About...\tF1"
+#else /* not ONLINEHELP */
+IDSTRAbout, "About..."
+#endif /* not ONLINEHELP */
+
+/* File names */
+IDSTRHELPF,"WRITE.HLP"
+
+/* Search/Change strings */
+IDSTRChangeSel,"Change Selection"
+IDSTRChangeAll,"Change All"
+
+/* String for "(page)" and "Page nnnn" */
+IDSTRChPage,"page"
+
+IDSTROn, " on "
+IDSTRReplaceFile,"Replace Existing %%?"
+IDSTRChars, " Chars."
+IDSTRSearching, "Searching..."
+
+
+/***** FOLLOWING MESSAGES ARE "*" LEVEL MESSAGES */
+
+IDPMTSearchDone,"Search complete."
+IDPMTNotFound,"Search text not found."
+IDPMTNoReplace,"No changes were made."
+IDPMTCancelSearch, "Search canceled."
+IDPMTDelPicture, "Any pictures will be deleted."
+
+/***** FOLLOWING MESSAGES ARE "?" LEVEL MESSAGES */
+
+IDPMTAddFont "Add font to list?"
+IDPMTTruncateSz,"String is too long. Proceed with the first 255 characters?"
+
+/***** FOLLOWING MESSAGES ARE "!" LEVEL MESSAGES */
+
+IDPMTBadFile,"Not a valid Write document."
+IDPMTCantOpen,"Cannot find document."
+IDPMTDirtyDoc,"%% has changed. Save current changes?"
+IDPMTCantRunM,"Not enough memory to run Write."
+IDPMTCantRunD,"Not enough disk space to run Write."
+IDPMTCantRunF,"Cannot run Write. Unable to create temporary file."
+IDPMTNoPath,"Directory does not exist."
+IDPMTNoAvail,"File is not available."
+IDPMTReadOnly,"Read-only file must be saved under a different name."
+
+/* Dialog field errors */
+
+IDPMTNoPage,"No such page."
+IDPMTNOTNUM,"Not a valid number."
+IDPMTBFS,"Font sizes must be between 4 and 127."
+IDPMTNPI,"Number must be a whole number between 1 and 32767."
+IDPMTNOTDXA,"Not a valid measurement."
+IDPMTNPDXA,"Measurement must be larger than zero."
+IDPMTMTL,"Margin too large."
+IDPMTBadFilename,"Not a valid filename."
+
+IDPMT2Complex,"Formatting too complex."
+IDPMTBadMove,"Cannot move text to that position."
+IDPMTNoHelpFile,"The help file WRITE.HLP is incorrect or missing."
+IDPMTDFULL,"Disk is full. Please save document on a different disk."
+IDPMTPRFAIL, "Insufficient memory to repaginate/print this document."
+IDPMTWPR, "Disk is write protected. Please remove write protect tab."
+IDPMTDRFULL, "Disk directory is full. Please use a different disk."
+IDPMTClipLarge,"Clipboard too big for available memory."
+IDPMTClipQuest," Discard Clipboard?"
+IDPMTBadPrinter, "Printer error"
+IDPMTCantPrint, "Unable to print "
+IDPMTRenameFail, "Unable to replace %%"
+IDPMTPrPictErr, "Error while printing picture. Picture ignored."
+IDPMTPrDiskErr, "Insufficient disk space to print this document."
+
+
+/***** FOLLOWING MESSAGES ARE "<hand>" LEVEL MESSAGES */
+
+IDPMTSDE,"Disk error on file."
+/* IDPMTSDN,"Unrecoverable disk error on file:" */
+IDPMTNoMemory,"Low on memory. Save your document."
+IDPMTSFER,"Session too long. Save now, then quit."
+IDPMTWinFailure, "Low on memory. Please close an application."
+
+END
+
+
+/* Windows WRITE accelerator table */
+
+/* WARNING: The Accelerator table is duplicated in a switch statement in
+cmd.c. If the accelerator table is changed, the switch statement must
+be changed */
+mw_acctb ACCELERATORS
+BEGIN
+#ifdef ONLINEHELP
+ VK_F1, imiHelp, VIRTKEY
+#endif /* ONLINEHELP */
+ VK_F2, imiCopy, VIRTKEY
+ VK_F3, imiFindAgain, VIRTKEY
+ VK_F4, imiGoTo, VIRTKEY
+ VK_F5, imiCharNormal, VIRTKEY
+ VK_F6, imiBold, VIRTKEY
+ VK_F7, imiItalic, VIRTKEY
+ VK_F8, imiUnderline, VIRTKEY
+ VK_F9, imiSmFont, VIRTKEY
+ VK_F10, imiLgFont, VIRTKEY
+END
+
+/* Windows WRITE Icon */
+
+mw_icon ICON write.ico
+
+/* Windows WRITE Cursors */
+
+mwlores CURSOR mwlores.cur
+mwhires CURSOR mwhires.cur
+pmscur CURSOR pmscur.cur
+
+/* Windows WRITE Bitmaps */
+
+rbutton BITMAP rbutton.bmp
+rmark BITMAP rmark.bmp
+
+/* Windows WRITE Command Menu */
+
+mw_menu MENU
+ begin
+ popup "~File"
+ begin
+ menuitem "~New", imiNew
+ menuitem "~Open...", imiOpen
+ menuitem "~Save", imiSave
+ menuitem "Save ~As...", imiSaveAs
+ menuitem SEPARATOR
+ menuitem "~Print...", imiPrint
+ menuitem "C~hange Printer...", imiPrintSetup
+ menuitem "~Repaginate...", imiRepaginate
+ menuitem SEPARATOR
+ menuitem "E~xit", imiQuit
+ menuitem SEPARATOR
+ menuitem "A~bout Write...", imiAbout
+ end
+
+ popup "~Edit"
+ begin
+
+ menuitem "~Undo\tAlt+Bksp", imiUndo
+ menuitem SEPARATOR
+ menuitem "Cu~t\tDel", imiCut
+ menuitem "~Copy\tCtrl+Ins", imiCopy
+ menuitem "~Paste\tShift+Ins", imiPaste
+ menuitem SEPARATOR
+ menuitem "~Move Picture", imiMovePicture
+ menuitem "~Size Picture", imiSizePicture
+ end
+
+ popup "~Search"
+ begin
+ menuitem "~Find...", imiFind
+ menuitem "~Repeat Last Find\tF3", imiFindAgain
+ menuitem "~Change...", imiChange
+ menuitem SEPARATOR
+ menuitem "~Go To Page...\tF4", imiGoTo
+ end
+
+ popup "~Character"
+ begin
+ menuitem "~Normal\tF5", imiCharNormal
+ menuitem SEPARATOR
+ menuitem "~Bold\tF6", imiBold
+ menuitem "~Italic\tF7", imiItalic
+ menuitem "~Underline\tF8", imiUnderline
+ menuitem "Su~perscript", imiSuper
+ menuitem "Subs~cript", imiSub
+ menuitem SEPARATOR
+ menuitem "", imiFont1
+ menuitem "", imiFont2
+ menuitem "", imiFont3
+ menuitem SEPARATOR
+ menuitem "~Reduce Font\tF9", imiSmFont
+ menuitem "~Enlarge Font\tF10", imiLgFont
+ menuitem SEPARATOR
+ menuitem "~Fonts...", imiCharFormats
+ end
+
+ popup "~Paragraph"
+ begin
+ menuitem "~Normal", imiParaNormal
+ menuitem SEPARATOR
+ menuitem "~Left", imiLeft
+ menuitem "~Centered", imiCenter
+ menuitem "~Right", imiRight
+ menuitem "~Justified", imiJustified
+ menuitem SEPARATOR
+ menuitem "~Single Space", imiSingleSpace
+ menuitem "~1 1/2 Space", imiOneandhalfSpace
+ menuitem "~Double Space", imiDoubleSpace
+ menuitem SEPARATOR
+ menuitem "~Indents...", imiParaFormats
+ end
+
+ popup "~Document"
+ begin
+ menuitem "~Header...", imiHeader
+ menuitem "~Footer...", imiFooter
+ menuitem SEPARATOR
+ menuitem "~Ruler On", imiShowRuler
+ menuitem "~Tabs...", imiTabs
+ menuitem SEPARATOR
+ menuitem "~Page Layout...", imiDivFormats
+ end
+ end
+
+/* Windows Word Dialog Boxes */
+
+#define WS_TABONLY (WS_TABSTOP | WS_GROUP) /* only tab can get to the item */
+
+dlgOpen DIALOG 30, 40, 160, 118
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "Open File ~Name:", idiNil, 6, 4, 64, 12
+ edittext idiOpenFile, 6, 16, 110, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Files in", idiNil, 6, 34, 32, 12
+ listbox idiOpenLB, 6, 48, 70, 64, LBS_NOTIFY | WS_VSCROLL | WS_BORDER | WS_VISIBLE | WS_TABSTOP
+ ltext "", idiOpenDir, 42, 34, 76, 12
+ defpushbutton "~Open", idiOk, 96, 67, 50, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 96, 89, 50, 14, WS_TABONLY
+ end
+
+#ifdef INTL /* International version */
+
+dlgSaveAs DIALOG 30, 40, 210, 70
+
+#else
+
+dlgSaveAs DIALOG 30, 40, 210, 53
+
+#endif /* International version */
+
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "Save File ~Name As:", idiNil, 5, 5, 72, 10
+ edittext idiSavFile, 5, 17, 122, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ control "", idiSavDir, static, WS_VISIBLE | SS_CENTER, 78, 5, 76, 12
+ checkbox "~Make Backup", idiSavBackup, 5, 35, 60, 12, WS_TABONLY
+ checkbox "~Text Only", idiSavTextOnly, 5, 52, 52, 12, WS_TABONLY
+
+#ifdef INTL /* International version */
+
+ checkbox "Microsoft ~Word Format", idiSavWordFmt, 70, 52, 100, 12, WS_TABONLY
+
+#endif /* International version */
+
+ defpushbutton "OK", idiOk, 155, 17, 50, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 155, 34, 50, 14, WS_TABONLY
+ end
+
+
+ /* note this may be a child of dlgOpen, so its start is based on its parent */
+dlgWordCvt DIALOG 02, 05, 171, 54
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "Convert Text to", idiNil, 5, 5, 138, 12
+ ltext "Microsoft Write Format", idiNil, 5, 13, 138, 12
+ defpushbutton "~Convert", idiOk, 100, 5, 48, 14, WS_TABONLY
+ pushbutton "~No Conversion", idiNo, 100, 20, 65, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 100, 35, 40, 14, WS_TABONLY
+ end
+
+
+/* By popular demand, this dialog box bites the dust
+dlgSaveScrap DIALOG 66, 63, 192, 60
+STYLE WS_BORDER | WS_POPUP | WS_CAPTION
+CAPTION "Write"
+ begin
+ icon DI_QUESTION, idiNil, 5, 5, 0, 0
+ ctext "Large Clipboard", idiNil, 30, 12, 90, 12
+ defpushbutton "~Save", idiOk, 18, 35, 40, 14, WS_TABONLY
+ pushbutton "~Discard", idiNo, 76, 35, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 134, 35, 40, 14, WS_TABONLY
+ end
+*/
+
+#ifdef ONLINEHELP
+dlgHelp DIALOG 30, 20, 280, 120
+ style WS_POPUP | WS_DLGFRAME | WS_VISIBLE
+ begin
+ ltext "Windows Write V0.53", idiNil, 180, 10, 90, 12
+ ltext "June 19, 1985", idiNil, 180, 20, 90, 12
+ ltext "", idiMemFree, 180, 30, 16, 12
+ ltext "% free memory", idiNil, 200, 30, 70, 12
+ listbox idiHelp, 5, 5, 160, 112, LBS_NOTIFY | WS_VSCROLL | WS_VISIBLE | WS_TABSTOP | WS_BORDER
+ defpushbutton "~Help", idiOk, 180, 90, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 230, 90, 40, 14, WS_TABONLY
+ end
+
+/* The real size of this dialog box and its children is calculated in help. c */
+
+dlgHelpInner DIALOG 30, 40, 110, 80
+ style WS_POPUP | WS_BORDER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+ caption "About Windows Write"
+ begin
+ ltext "", idiHelpName, 5, 5, 1, 1
+ control "", idiHelpScroll, "ScrollBar",
+ WS_TABONLY | SBS_VERT, 1,1,1,1
+ defpushbutton "Topics", idiHelpTopics, 1, 1, 1, 1, WS_TABONLY
+ pushbutton "Next", idiHelpNext, 2, 2, 1, 1, WS_TABONLY
+ pushbutton "Previous", idiHelpPrev, 3, 3, 1, 1, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 4, 4, 1, 1, WS_TABONLY
+ end
+
+#else
+dlgHelp DIALOG 30, 20, 150, 100
+ style WS_POPUP | WS_DLGFRAME
+ begin
+ ctext "Microsoft Windows", idiNil, 0, 5, 150, 8
+ icon "mw_icon", idiNil, 9, 23, 0, 0
+ ctext "Write", idiNil, 0, 14, 150, 8
+ ctext "Version 2.0", idiNil, 35, 34, 80, 8
+ ctext "Copyright (c) 1985, 1986, 1987, Microsoft Corp." idiNil, 0, 47, 150, 8
+ defpushbutton "Ok", idiOk, 55, 80, 40, 14, WS_TABONLY
+ end
+#endif
+
+dlgPrint DIALOG 17, 50, 130, 77
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "~Copies:", idiNil, 5, 7, 30, 12
+ edittext idiPrtCopies, 35, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "~Draft Quality", idiPrtDraft, 5, 20, 74, 12, WS_TABONLY
+ ltext "Page Range:", idiNil, 5, 37, 50, 12
+ radiobutton "~All", idiPrtAll, 10, 47, 50, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "~From:", idiPrtFrom, 10, 60, 30, 12
+ edittext idiPrtPageFrom, 41, 61, 30, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "~To:", idiNil, 78, 63, 12, 12
+ edittext idiPrtPageTo, 92, 61, 30, 12, WS_TABONLY | ES_AUTOHSCROLL
+ defpushbutton "Ok", idiOk, 85, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 85, 25, 40, 14, WS_TABONLY
+ end
+
+dlgCancelPrint DIALOG 15, 50, 134, 52
+STYLE WS_BORDER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Printing"
+ begin
+ ltext "Write is sending your document", idiNil, 5, 5, 128, 8
+ ltext "to the printer.", idiNil, 5, 14, 128, 8
+ defpushbutton "Cancel", idiCancel, 47, 30, 40, 14, WS_TABONLY
+ end
+
+dlgRepaginate DIALOG 90, 100, 155, 45
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "Repaginate Document", idiNil, 5, 5, 80, 12
+ checkbox "Confirm Page ~Breaks", idiRepageConfirm, 5, 25, 100, 12, WS_TABONLY
+ defpushbutton "Ok", idiOk, 110, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 110, 25, 40, 14, WS_TABONLY
+ end
+
+dlgCancelRepage DIALOG 15, 50, 94, 50
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Repaginating"
+ begin
+ ltext "Write is repaginating", idiNil, 5, 5, 84, 8
+ ltext "your document", idiNil, 5, 14, 52, 8
+ defpushbutton "Cancel", idiCancel, 27, 28, 40, 14, WS_TABONLY
+ end
+
+dlgSetPage DIALOG 90, 120, 192, 50
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "Repaginating"
+ begin
+ ltext "Use up and down buttons", idiNil, 5, 5, 92, 8
+ ltext "to move page break", idiNil, 5, 14, 72, 8
+ ltext "if necessary,", idiNil, 5, 23, 52, 8
+ ltext "then confirm.", idiNil, 5, 32, 52, 8
+ pushbutton "Up", idiRepUp, 102, 8, 40, 14, WS_TABONLY
+ pushbutton "Down", idiRepDown, 102, 28, 40, 14, WS_TABONLY
+ defpushbutton "~Confirm", idiOk, 147, 8, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 147, 28, 40, 14, WS_TABONLY
+ end
+
+dlgPageMark DIALOG 90, 100, 135, 58
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "Repaginating"
+ begin
+ icon DI_QUESTION, idiNil, 5, 5, 0, 0
+ ltext "Would you like to keep", idiNil, 30, 7, 92, 12
+ ltext "this existing page break?", idiNil, 30, 19, 100, 12
+ pushbutton "Cancel", idiCancel, 7, 35, 35, 14, WS_TABONLY
+ defpushbutton "Keep", idiKeepPgMark, 49, 35, 35, 14, WS_TABONLY
+ pushbutton "Remove", idiRemovePgMark, 91, 35, 35, 14, WS_TABONLY
+ end
+
+dlgPrinterSetup DIALOG 30, 40, 190, 80
+STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE
+ begin
+ ltext "~Select a Printer:", idiNil, 5, 5, 70, 12
+ listbox idiPrterName, 5, 20, 132, 56, LBS_STANDARD | WS_VISIBLE | WS_TABONLY
+ defpushbutton "Ok", idiOk, 145, 20, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 145, 50, 40, 14, WS_TABONLY
+ end
+
+dlgFind DIALOG 40, 165, 200, 55
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Find"
+ begin
+ ltext "~Find What:", idiNil, 5, 7, 45, 12
+ edittext idiFind, 50, 5, 140, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "~Whole Word", idiWholeWord, 5, 20, 60, 12, WS_TABONLY
+ checkbox "~Match Upper/Lowercase", idiMatchCase, 100, 20, 95, 12, WS_TABONLY
+ defpushbutton "Find ~Next", idiFindNext, 70, 35, 60, 14, WS_TABONLY
+ end
+
+dlgChange DIALOG 60, 150, 249, 70
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Change"
+ begin
+ ltext "~Find What:", idiNil, 5, 7, 45, 12
+ edittext idiFind, 50, 5, 150, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Change ~To:", idiNil, 5, 22, 45, 12
+ edittext idiChangeTo, 50, 20, 150, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "~Whole Word", idiWholeWord, 5, 35, 60, 12, WS_TABONLY
+ checkbox "~Match Upper/Lowercase", idiMatchCase, 100, 35, 195, 12, WS_TABONLY
+ defpushbutton "Find ~Next", idiFindNext, 5, 50, 44, 14, WS_TABONLY
+ pushbutton "C~hange, then Find", idiChangeThenFind, 54, 50, 76, 14, WS_TABONLY
+ pushbutton "~Change", idiChange, 135, 50, 32, 14, WS_TABONLY
+ pushbutton " Change ~All ", idiChangeAll, 172, 50, 72, 14, WS_TABONLY
+ end
+
+dlgGoTo DIALOG 87, 63, 95, 40
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "~Page Number:", idiNil, 5, 7, 50, 12
+ edittext idiGtoPage, 56, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "Ok", idiOk, 5, 22, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 50, 22, 40, 14, WS_TABONLY
+ end
+
+dlgCharFormats DIALOG 80, 36, 180, 100
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "Fonts"
+ begin
+ ltext "Font ~Name:", idiNil, 5, 5, 45, 12
+ edittext idiChrFontName, 5, 16, 125, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Fonts:", idiNil, 5, 33, 24, 12
+ listbox idiChrLBFontName, 5, 47, 105, 48, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ ltext "~Sizes:", idiNil, 115, 42, 24, 12
+ listbox idiChrLBFontSize, 115, 55, 24, 40, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ ltext "~Point", idiNil, 144, 61, 20, 12
+ edittext idiChrFontSize, 144, 83, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Size:", idiNil, 144, 71, 20, 12
+ defpushbutton "Ok", idiOk, 135, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 135, 25, 40, 14, WS_TABONLY
+ end
+
+dlgParaFormats DIALOG 28, 36, 150, 52
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "Indents"
+ begin
+ ltext "~Left Indent:", idiNil, 3, 7, 48, 12
+ edittext idiParLfIndent, 56, 5, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~First Line:", idiNil, 3, 22, 44, 12
+ edittext idiParFirst, 56, 20, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Right Indent:", idiNil, 3, 37, 52, 12
+ edittext idiParRtIndent, 56, 35, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "Ok", idiOk, 105, 8, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 105, 27, 40, 14, WS_TABONLY
+ end
+
+dlgRunningHead DIALOG 80, 110, 228, 42
+STYLE WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+CAPTION "Page Header"
+ begin
+ ltext "~Distance from Top: ", idiNil, 5, 7, 76, 12
+ edittext idiRHDx, 80, 5, 38, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "~Print on First Page", idiRHFirst, 133, 5, 90, 12, WS_TABONLY
+ pushbutton "~Insert Page #", idiRHInsertPage, 12, 22, 64, 14, WS_TABONLY
+ pushbutton "~Clear", idiRHClear, 88, 22, 30, 14, WS_TABONLY
+ defpushbutton "~Return to Document", idiOk, 130, 22, 85, 14, WS_TABONLY
+ end
+
+dlgFooter DIALOG 80, 110, 228, 42
+STYLE WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+CAPTION "Page Footer"
+ begin
+ ltext "~Distance from Bottom: ", idiNil, 5, 7, 88, 12
+ edittext idiRHDx, 90, 5, 38, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "~Print on First Page", idiRHFirst, 133, 5, 90, 12, WS_TABONLY
+ pushbutton "~Insert Page #", idiRHInsertPage, 12, 22, 64, 14, WS_TABONLY
+ pushbutton "~Clear", idiRHClear, 88, 22, 30, 14, WS_TABONLY
+ defpushbutton "~Return to Document", idiOk, 130, 22, 85, 14, WS_TABONLY
+ end
+
+dlgTabs DIALOG 26, 41, 278, 97
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "Tabs"
+ begin
+ ltext "~Positions:", idiNil, 3, 7, 40, 12
+ edittext idiTabPos0, 45, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "~Decimal:", idiNil, 3, 22, 40, 12
+ checkbox ".", idiTabDec0, 51, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos1, 83, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec1, 89, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos2, 121, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec2, 127, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos3, 159, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec3, 165, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos4, 197, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec4, 203, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos5, 235, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec5, 241, 20, 18, 12, WS_TABONLY
+
+ ltext "~Positions:", idiNil, 3, 42, 40, 12
+ edittext idiTabPos6, 45, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "~Decimal:", idiNil, 3, 57, 40, 12
+ checkbox ".", idiTabDec6, 51, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos7, 83, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec7, 89, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos8, 121, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec8, 127, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos9, 159, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec9, 165, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos10, 197, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec10, 203, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos11, 235, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec11, 241, 55, 18, 12, WS_TABONLY
+ defpushbutton "Ok", idiOk, 20, 75, 50, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 90, 75, 50, 14, WS_TABONLY
+ pushbutton "Clear ~All", idiTabClearAll, 160, 75, 50, 14, WS_TABONLY
+ end
+
+
+#ifdef INTL /* International version */
+
+dlgDivision DIALOG 26, 30, 180, 110
+
+#else
+
+dlgDivision DIALOG 26, 30, 180, 80
+
+#endif /* International version */
+
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "~Start Page Numbers At:", idiNil, 5, 7, 88, 12
+ edittext idiDivPNStart, 95, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "Margins:", idiNil, 5, 33, 40, 12
+ ltext "~Left:", idiNil, 12, 48, 20, 12
+ edittext idiDivLMarg, 35, 46, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Right:", idiNil, 85, 48, 30, 12
+ edittext idiDivRMarg, 117, 46, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Top:", idiNil, 12, 65, 20, 12
+ edittext idiDivTMarg, 35, 63, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "~Bottom:", idiNil, 85, 65, 30, 12
+ edittext idiDivBMarg, 117, 63, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+
+#ifdef INTL /* International version */
+
+ ltext "Measurements:", idiNil, 5, 84, 63, 12
+ radiobutton "~inch", idiDivInch, 12, 94, 27, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "~cm", idiDivCm, 44, 94, 26, 12
+
+#endif /* International version */
+
+ defpushbutton "Ok", idiOk, 135, 5, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 135, 23, 40, 14, WS_TABONLY
+ end
+
+dlgBadMargins DIALOG 50, 20, 235, 65
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION
+CAPTION "Write"
+ begin
+ icon DI_EXCLAMATION, idiNil, 5, 5, 0, 0
+ ltext "Current printer cannot print outside these margins", idiNil, 30, 5, 200, 12
+ ltext "Left:", idiNil, 30, 17, 20, 12
+ ltext "", idiBMrgLeft, 60, 17, 40, 12
+ ltext "Right:", idiNil, 130, 17, 24, 12
+ ltext "", idiBMrgRight, 168, 17, 40, 12
+ ltext "Top:", idiNil, 30, 29, 16, 12
+ ltext "", idiBMrgTop, 60, 29, 40, 12
+ ltext "Bottom:", idiNil, 130, 29, 28, 12
+ ltext "", idiBMrgBottom, 168, 29, 40, 12
+ defpushbutton "Ok", idiOk, 97, 44, 40, 14, WS_TABSTOP
+ end
diff --git a/private/mvdm/wow16/write/write.knj b/private/mvdm/wow16/write/write.knj
new file mode 100644
index 000000000..16c6f0501
--- /dev/null
+++ b/private/mvdm/wow16/write/write.knj
@@ -0,0 +1,678 @@
+/* This is the source file for the resource file for Windows Write. The
+resource file is generated by running this file through the resouce compiler
+RC.EXE. */
+
+
+
+/*#define INTL International version */
+#define KANJI /* Kanji version */
+#define KINTL /* Kanji/International version */
+
+#define NOGDICAPMASKS
+#define NOWINMESSAGES
+#define NOSYSMETRICS
+#define NOICON
+#define NOKEYSTATE
+#define NOSYSCOMMANDS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOGDI
+#define NOFONT
+#define NOBRUSH
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCREATESTRUCT
+#define NODRAWTEXT
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMINMAX
+#define NOOPENFILE
+#define NOPEN
+#define NOREGION
+#define NOSCROLL
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOWNDCLASS
+#define NOCOMM
+#include <windows.h>
+#include "menudefs.h"
+#include "dlgdefs.h"
+#include "str.h"
+#include "kanji.h"
+#define DI_QUESTION 32514 /* have to match windows.h MAKEINTRESOURCE(n) */
+#define DI_EXCLAMATION 32515 /* have to match windows.h MAKEINTRESOURCE(n) */
+
+kanji 0x81, 0x9f, 0xe0, 0xfc
+
+STRINGTABLE
+BEGIN
+
+IDS_MERGE1 "%%" /* relocatable message symbol */
+
+/* Menu and Undo strings */
+/* WARNING: The length of the longest UNDO string is kept as a constant
+ in str.h. This constant must be updated along with the strings */
+IDSTRUndoBase, "取消し"
+IDSTRUndoEdit, " - 編集"
+IDSTRUndoLook, " - 書式"
+IDSTRUndoTyping," - 文字入力"
+IDSTRShowRuler, "ルーラー表示"
+IDSTRHideRuler, "ルーラー消去"
+
+#ifdef ONLINEHELP
+IDSTRAbout, "プロフィール\tF1"
+#else /* not ONLINEHELP */
+IDSTRAbout, "プロフィール"
+#endif /* not ONLINEHELP */
+
+/* File names */
+IDSTRHELPF,"WRITE.HLP"
+
+/* Search/Change strings */
+IDSTRChangeSel,"指定範囲一括置換"
+IDSTRChangeAll,"一括置換"
+
+/* String for "(page)" and "Page nnnn" */
+IDSTRChPage,"ページ"
+
+IDSTROn, " on "
+IDSTRReplaceFile, "既存のファイルと置き換えますか"
+IDSTRChars, " 文字"
+IDSTRSearching, "検索中"
+
+
+/***** FOLLOWING MESSAGES ARE "*" LEVEL MESSAGES */
+
+IDPMTSearchDone, "検索は終了しました"
+IDPMTNotFound, "文字列が見つかりません"
+IDPMTNoReplace, "変更されませんでした"
+IDPMTCancelSearch, "検索は取り消されました"
+IDPMTDelPicture, "図形は削除されます"
+
+/***** FOLLOWING MESSAGES ARE "?" LEVEL MESSAGES */
+
+IDPMTAddFont "フォントを追加しますか"
+IDPMTTruncateSz,"文字列が長すぎます - 先頭の255文字で検索しますか"
+
+/***** FOLLOWING MESSAGES ARE "!" LEVEL MESSAGES */
+
+IDPMTBadFile, "正しいライトの文書ではありません"
+IDPMTCantOpen, "文書が見つかりません"
+IDPMTDirtyDoc, "%% は修正されました - セーブしますか"
+IDPMTCantRunM, "ライトを実行するのに十分なメモリがありません"
+IDPMTCantRunD, "ライトを実行するのに十分なディスク容量がありません"
+IDPMTCantRunF, "ライトを実行できません - 一時的なファイルは作成できません"
+IDPMTNoPath, "ディレクトリがありません"
+IDPMTNoAvail, "そのファイルは使用できません"
+IDPMTReadOnly, "書き込み禁止ファイルです - 違う名前でセーブしてください"
+
+/* Dialog field errors */
+
+IDPMTNoPage, "指定されたページがありません"
+IDPMTNOTNUM, "数値が正しくありません"
+IDPMTBFS, "4 から 127 までの数値を使用してください"
+IDPMTNPI, "1 から 32767 までの数値を使用してください"
+IDPMTNOTDXA, "数値が正しくありません"
+IDPMTNPDXA, "0 以上の数値を使用してください"
+IDPMTMTL, "マージンが大きすぎます"
+IDPMTBadFilename,"ファイル名が正しくありません"
+
+IDPMT2Complex, "書式の設定に矛盾があります"
+IDPMTBadMove, "その位置にテキストを移動することはできません"
+IDPMTNoHelpFile,"ヘルプファイルが正しくありません"
+IDPMTDFULL, "ディスクがいっぱいです - 他のディスクにセーブしてください"
+IDPMTPRFAIL, "改ページ/印刷するのに十分なメモリがありません"
+IDPMTWPR, "書き込み禁止ディスクです - プロテクトシールを剥してください"
+IDPMTDRFULL, "ディレクトリがいっぱいです - 他のディスクを使用してください"
+IDPMTClipLarge, "クリップボードを使用するのに十分なメモリがありません"
+IDPMTClipQuest, "クリップボードをあきらめますか"
+IDPMTBadPrinter,"プリンタエラー"
+IDPMTCantPrint, "印刷できません"
+IDPMTRenameFail,"%% を置き換えられません"
+IDPMTPrPictErr, "図形印刷中にエラーが生じました - 図形は無視されました"
+IDPMTPrDiskErr, "文書を印刷するのに十分なディスク容量がありません"
+#ifdef KANJI
+IDPMTLargePaste, "貼付けできません - クリップボードが大きすぎます"
+IDPMTLongEdit, "文書をセーブしてください"
+#endif /*KANJI*/
+
+
+
+/***** FOLLOWING MESSAGES ARE "<hand>" LEVEL MESSAGES */
+
+IDPMTSDE, "ディスクエラーが生じました"
+/* IDPMTSDN, "Unrecoverable disk error on file:" */
+IDPMTNoMemory, "十分なメモリがありません - 文書をセーブしてください"
+IDPMTSFER, "実行時間が長すぎます - 一度セーブし,終了してください"
+IDPMTWinFailure,"十分なメモリがありません - アプリケーションを終了してください"
+
+END
+
+
+/* Windows WRITE accelerator table */
+
+/* WARNING: The Accelerator table is duplicated in a switch statement in
+cmd.c. If the accelerator table is changed, the switch statement must
+be changed */
+mw_acctb ACCELERATORS
+BEGIN
+#ifdef ONLINEHELP
+ VK_F1, imiHelp, VIRTKEY
+#endif /* ONLINEHELP */
+#ifdef KANJI
+ VK_COPY, imiCopy, VIRTKEY
+#else
+ VK_F2, imiCopy, VIRTKEY
+#endif
+ VK_F3, imiFindAgain, VIRTKEY
+ VK_F4, imiGoTo, VIRTKEY
+ VK_F5, imiCharNormal, VIRTKEY
+ VK_F6, imiBold, VIRTKEY
+ VK_F7, imiItalic, VIRTKEY
+ VK_F8, imiUnderline, VIRTKEY
+ VK_F9, imiSmFont, VIRTKEY
+ VK_F10, imiLgFont, VIRTKEY
+END
+
+/* Windows WRITE Icon */
+
+mw_icon ICON write.ico
+
+/* Windows WRITE Cursors */
+
+mwlores CURSOR mwlores.cur
+mwhires CURSOR mwhires.cur
+pmscur CURSOR pmscur.cur
+
+/* Windows WRITE Bitmaps */
+
+rbutton BITMAP rbutton.bmp
+rmark BITMAP rmark.bmp
+
+/* Windows WRITE Command Menu */
+
+mw_menu MENU
+ begin
+ popup "ファイル"
+ begin
+ menuitem "新規", imiNew
+ menuitem "オープン", imiOpen
+ menuitem "セーブ", imiSave
+ menuitem SEPARATOR
+ menuitem "印刷", imiPrint
+ menuitem "プリンタ設定", imiPrintSetup
+ menuitem "改ページ設定", imiRepaginate
+ end
+
+ popup "編集"
+ begin
+ menuitem "取消し\tSh Esc", imiUndo
+ menuitem SEPARATOR
+ menuitem "切取り\tDel", imiCut
+#ifdef NONECKEYBOARD
+ menuitem "複写\tF2", imiCopy
+#else
+ menuitem "複写\tCopy", imiCopy
+#endif
+ menuitem "貼付け\tIns", imiPaste
+ menuitem SEPARATOR
+ menuitem "図形移動", imiMovePicture
+ menuitem "図形拡大/縮小", imiSizePicture
+ end
+
+ popup "検索"
+ begin
+ menuitem "検索", imiFind
+ menuitem "次を検索\tF3", imiFindAgain
+ menuitem "置換", imiChange
+ menuitem SEPARATOR
+ menuitem "ページ指定\tF4", imiGoTo
+ end
+
+ popup "文字"
+ begin
+ menuitem "ノーマル\tF5", imiCharNormal
+ menuitem SEPARATOR
+ menuitem "ボールド\tF6", imiBold
+ menuitem "イタリック\tF7", imiItalic
+ menuitem "アンダーライン\tF8", imiUnderline
+ menuitem "上付き文字", imiSuper
+ menuitem "下付き文字", imiSub
+ menuitem SEPARATOR
+ menuitem "", imiFont1
+ menuitem "", imiFont2
+ menuitem "", imiFont3
+ menuitem SEPARATOR
+ menuitem "フォント縮小\tF9", imiSmFont
+ menuitem "フォント拡大\tF10", imiLgFont
+ menuitem SEPARATOR
+ menuitem "フォント選択", imiCharFormats
+ end
+
+ popup "段落"
+ begin
+ menuitem "標準", imiParaNormal
+ menuitem SEPARATOR
+ menuitem "左寄せ", imiLeft
+ menuitem "センタリング", imiCenter
+ menuitem "右寄せ", imiRight
+#ifndef KANJI
+ menuitem "行末揃え", imiJustified
+#endif /* ifdef KANJI */
+ menuitem SEPARATOR
+ menuitem "行間 1", imiSingleSpace
+ menuitem "行間 1.5", imiOneandhalfSpace
+ menuitem "行間 2", imiDoubleSpace
+ menuitem SEPARATOR
+ menuitem "インデント", imiParaFormats
+ end
+
+ popup "その他"
+ begin
+ menuitem "ヘッダー", imiHeader
+ menuitem "フッター", imiFooter
+ menuitem SEPARATOR
+ menuitem "ルーラー表示", imiShowRuler
+ menuitem "タブ設定", imiTabs
+ menuitem SEPARATOR
+ menuitem "ページレイアウト", imiDivFormats
+ end
+ end
+
+/* Windows Word Dialog Boxes */
+
+#define WS_TABONLY (WS_TABSTOP | WS_GROUP) /* only tab can get to the item */
+
+dlgOpen DIALOG 30, 40, 168, 95
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ rtext "ファイル名",idiNil, 4, 7, 40, 12
+ edittext idiOpenFile, 48, 5,110, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ listbox idiOpenLB, 6, 25, 70, 64, LBS_NOTIFY | WS_VSCROLL | WS_BORDER | WS_VISIBLE | WS_TABSTOP
+ ctext "", idiOpenDir, 80, 25, 76, 12
+ defpushbutton "オープン", idiOk, 97, 44, 50, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 97, 66, 50, 14, WS_TABONLY
+ end
+
+
+#ifdef INTL /* International version */
+
+dlgSaveAs DIALOG 30, 40, 210, 70
+
+#else
+
+dlgSaveAs DIALOG 30, 40, 210, 53
+
+#endif /* International version */
+
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "ファイル名", idiNil, 5, 5,110, 10
+ edittext idiSavFile, 5, 17, 122, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ control "", idiSavDir, static, WS_VISIBLE | SS_CENTER, 129, 5, 76, 12
+ checkbox "バックアップ", idiSavBackup, 5, 35, 60, 12, WS_TABONLY
+ checkbox "テキスト", idiSavTextOnly, 72, 35, 52, 12, WS_TABONLY
+
+#ifdef INTL /* International version */
+
+ checkbox "マイクロソフト・ワード・データMicrosoft Word Format", idiSavWordFmt, 70, 52, 100, 12, WS_TABONLY
+
+#endif /* International version */
+
+ defpushbutton "セーブ", idiOk, 151, 17, 50, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 151, 34, 50, 14, WS_TABONLY
+ end
+
+
+ /* note this may be a child of dlgOpen, so its start is based on its parent */
+dlgWordCvt DIALOG 02, 05, 171, 54
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "ワードの書式をライトの", idiNil, 5, 5,138, 12
+ ltext "書式に変換します", idiNil, 5, 13,138, 12
+ defpushbutton "変換", idiOk, 100, 5, 48, 14, WS_TABONLY
+ pushbutton "無変換", idiNo, 100, 20, 65, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 100, 35, 40, 14, WS_TABONLY
+ end
+
+
+/* By popular demand, this dialog box bites the dust
+dlgSaveScrap DIALOG 66, 63, 192, 60
+STYLE WS_BORDER | WS_POPUP | WS_CAPTION
+CAPTION "ライト"
+ begin
+ icon DI_QUESTION, idiNil, 5, 5, 0, 0
+ ctext "Large Clipboard", idiNil, 30, 12, 90, 12
+ defpushbutton "Save", idiOk, 18, 35, 40, 14, WS_TABONLY
+ pushbutton "Discard", idiNo, 76, 35, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel,134, 35, 40, 14, WS_TABONLY
+ end
+*/
+
+#ifdef ONLINEHELP
+dlgHelp DIALOG 30, 20, 280, 120
+ style WS_POPUP | WS_DLGFRAME | WS_VISIBLE
+ begin
+ ltext "Windows Write V0.53", idiNil, 180, 10, 90, 12
+ ltext "June 19, 1985", idiNil, 180, 20, 90, 12
+ ltext "", idiMemFree, 180, 30, 16, 12
+ ltext "% free memory", idiNil, 200, 30, 70, 12
+ listbox idiHelp, 5, 5, 160, 112, LBS_NOTIFY | WS_VSCROLL | WS_VISIBLE | WS_TABSTOP | WS_BORDER
+ defpushbutton "Help", idiOk, 180, 90, 40, 14, WS_TABONLY
+ pushbutton "Cancel", idiCancel,230, 90, 40, 14, WS_TABONLY
+ end
+
+/* The real size of this dialog box and its children is calculated in help. c */
+
+dlgHelpInner DIALOG 30, 40, 110, 80
+ style WS_POPUP | WS_BORDER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+ caption "About Windows Write"
+ begin
+ ltext "", idiHelpName, 5, 5, 1, 1
+ control "", idiHelpScroll, "ScrollBar", WS_TABONLY | SBS_VERT,1,1,1,1
+ defpushbutton "Topics", idiHelpTopics, 1, 1, 1, 1, WS_TABONLY
+ pushbutton "Next", idiHelpNext, 2, 2, 1, 1, WS_TABONLY
+ pushbutton "Previous", idiHelpPrev, 3, 3, 1, 1, WS_TABONLY
+ pushbutton "Cancel", idiCancel, 4, 4, 1, 1, WS_TABONLY
+ end
+
+#else
+dlgHelp DIALOG 20, 17, 160, 75
+ style WS_POPUP | WS_DLGFRAME
+ begin
+ ctext "マイクロソフト・ウィンドウズ", idiNil, 0, 5,160, 8
+ icon "mw_icon", idiNil, 9, 23, 0, 0
+ ctext "ライト", idiNil, 30, 17,100, 8
+ ctext "Version 1.03 Kanji", idiNil, 30, 34,100, 8
+ ctext "Copyright (C) 1985 Microsoft Corp." idiNil, 0, 47, 150, 8
+ defpushbutton "確認", idiOk, 61, 59, 32, 14, WS_TABONLY
+ end
+#endif
+
+dlgPrint DIALOG 17, 50, 130, 77
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "枚数", idiNil, 5, 7, 16, 12
+ edittext idiPrtCopies, 25, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "テスト印字", idiPrtDraft, 5, 20, 74, 12, WS_TABONLY
+ ltext "印刷ページ", idiNil, 5, 37, 40, 12
+ radiobutton "全部", idiPrtAll, 10, 47, 50, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "", idiPrtFrom, 10, 60, 10, 12
+ edittext idiPrtPageFrom, 22, 61, 30, 12, WS_TABONLY | ES_AUTOHSCROLL
+ ltext "から", idiNil, 54, 63, 16, 12
+ ltext "まで", idiNil, 106, 63, 16, 12
+ edittext idiPrtPageTo, 74, 61, 30, 12, WS_TABONLY | ES_AUTOHSCROLL
+ defpushbutton "確認", idiOk, 85, 5, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 85, 25, 40, 14, WS_TABONLY
+ end
+
+dlgCancelPrint DIALOG 15, 50, 134, 52
+STYLE WS_BORDER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "印刷"
+ begin
+ ctext "プリンタに文書を", idiNil, 5, 5,124, 8
+ ctext "送っています", idiNil, 5, 15,124, 8
+ defpushbutton "取消し", idiCancel, 47, 30, 40, 14, WS_TABONLY
+ end
+
+dlgRepaginate DIALOG 90, 100, 139, 45
+STYLE WS_DLGFRAME | WS_POPUP
+ begin
+ ltext "改ページ設定", idiNil, 5, 9, 48, 12
+ checkbox "ページロック解除",idiRepageConfirm, 5, 25, 80, 12, WS_TABONLY
+ defpushbutton "確認", idiOk, 94, 5, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 94, 25, 40, 14, WS_TABONLY
+ end
+
+dlgCancelRepage DIALOG 15, 50, 94, 50
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "改ページ設定"
+ begin
+ ctext "改ページ位置を", idiNil, 7, 5, 80, 8
+ ctext "設定しています", idiNil, 7, 14, 80, 8
+ defpushbutton "取消し", idiCancel,27, 28, 40, 14, WS_TABONLY
+ end
+
+dlgSetPage DIALOG 80, 120, 205, 50
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "改ページ再設定"
+ begin
+ ltext "改ページ位置を変更するには", idiNil, 5, 9,104, 8
+ ltext "<上方向>,<下方向>キー", idiNil, 5, 21,104, 8
+ ltext "を使用してください", idiNil, 5, 33, 72, 8
+ pushbutton "上方向", idiRepUp, 115, 8, 40, 14, WS_TABONLY
+ pushbutton "下方向", idiRepDown, 115, 28, 40, 14, WS_TABONLY
+ defpushbutton "確認", idiOk, 160, 8, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 160, 28, 40, 14, WS_TABONLY
+ end
+
+dlgPageMark DIALOG 90, 100, 135, 58
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "改ページ再設定"
+ begin
+ icon DI_QUESTION, idiNil, 5, 5, 0, 0
+ ctext "改ページ位置を変更しますか", idiNil, 25, 7,105, 12
+ /* ltext "this existing page break?", idiNil, 30, 19,100, 12 */
+ pushbutton "取消し", idiCancel, 7, 35, 35, 14, WS_TABONLY
+ defpushbutton "次ページ", idiKeepPgMark, 49, 35, 35, 14, WS_TABONLY
+ pushbutton "変更", idiRemovePgMark,91, 35, 35, 14, WS_TABONLY
+ end
+
+dlgPrinterSetup DIALOG 30, 40, 190, 80
+STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE
+ begin
+ ltext "プリンタ設定", idiNil, 5, 5, 70, 12
+ listbox idiPrterName, 5, 20,132, 56, LBS_STANDARD | WS_VISIBLE | WS_TABONLY
+ defpushbutton "確認", idiOk, 145, 20, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 145, 50, 40, 14, WS_TABONLY
+ end
+
+#ifdef KANJI
+dlgFind DIALOG 40, 180, 200, 40
+#else
+dlgFind DIALOG 40, 165, 200, 55
+#endif /* if-else-def KANJI */
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "検索"
+ begin
+ ltext "検索文字列:", idiNil, 5, 7, 45, 12
+ edittext idiFind, 50, 5, 140, 12, WS_TABSTOP | ES_AUTOHSCROLL
+#ifdef KANJI
+ defpushbutton "次候補", idiFindNext, 70, 20, 60, 14, WS_TABONLY
+#else
+ checkbox "Whole Word", idiWholeWord, 5, 20, 60, 12, WS_TABONLY
+ checkbox "Match Upper/Lowercase", idiMatchCase, 100, 20, 95, 12, WS_TABONLY
+ defpushbutton "Find Next", idiFindNext, 70, 35, 60, 14, WS_TABONLY
+#endif /* if-else-def KANJI */
+ end
+
+#ifdef KANJI
+dlgChange DIALOG 60, 165, 249, 55
+#else
+dlgChange DIALOG 60, 150, 249, 70
+#endif /* if-else-def KANJI */
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "置換"
+ begin
+ ltext "置換前:", idiNil, 9, 7, 30, 12
+ edittext idiFind, 42, 5,180, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "置換後:", idiNil, 9, 22, 30, 12
+ edittext idiChangeTo, 42, 20,180, 12, WS_TABSTOP | ES_AUTOHSCROLL
+#ifdef KANJI
+ defpushbutton "次候補", idiFindNext, 5, 35, 44, 14, WS_TABONLY
+ pushbutton "置換 - 次候補", idiChangeThenFind, 54, 35, 76, 14, WS_TABONLY
+ pushbutton "置換", idiChange, 135, 35, 32, 14, WS_TABONLY
+ pushbutton " 一括置換 ",idiChangeAll, 172, 35, 72, 14, WS_TABONLY
+#else
+ checkbox "Whole Word", idiWholeWord, 5, 35, 60, 12, WS_TABONLY
+ checkbox "Match Upper/Lowercase",idiMatchCase,100, 35,195, 12, WS_TABONLY
+ defpushbutton "次候補", idiFindNext, 5, 50, 44, 14, WS_TABONLY
+ pushbutton "Change, then Find",idiChangeThenFind,54, 50, 76, 14, WS_TABONLY
+ pushbutton "Change", idiChange, 135, 50, 32, 14, WS_TABONLY
+ pushbutton " Change All ", idiChangeAll,172, 50, 72, 14, WS_TABONLY
+#endif /* if-else-def KANJI */
+ end
+
+dlgGoTo DIALOG 87, 63, 95, 40
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "ページ番号:", idiNil, 5, 7, 50, 12
+ edittext idiGtoPage, 54, 5, 32, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "確認", idiOk, 5, 22, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 50, 22, 40, 14, WS_TABONLY
+ end
+
+dlgCharFormats DIALOG 80, 36, 180, 88
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "フォント"
+ begin
+ ltext "フォント名", idiNil, 5, 5, 45, 12
+ edittext idiChrFontName, 5, 16,125, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ listbox idiChrLBFontName, 5, 35,105, 48, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ listbox idiChrLBFontSize, 115, 43, 24, 40, LBS_STANDARD | WS_VISIBLE | WS_TABSTOP
+ ltext "フォント",idiNil, 144, 49, 32, 10
+ ltext "サイズ", idiNil, 144, 59, 32, 12
+ edittext idiChrFontSize, 144, 71, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "確認", idiOk, 135, 5, 40, 14, WS_TABONLY
+ pushbutton "取消し",idiCancel,135, 25, 40, 14, WS_TABONLY
+ end
+
+dlgParaFormats DIALOG 28, 36, 126, 52
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "インデント"
+ begin
+ ltext "左端", idiNil, 7, 7, 20, 12
+ edittext idiParLfIndent, 32, 5, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "上端", idiNil, 7, 22, 20, 12
+ edittext idiParFirst, 32, 20, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "右端", idiNil, 7, 37, 20, 12
+ edittext idiParRtIndent, 32, 35, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ defpushbutton "確認",idiOk, 81, 8, 40, 14, WS_TABONLY
+ pushbutton "取消し",idiCancel,81, 27, 40, 14, WS_TABONLY
+ end
+
+dlgRunningHead DIALOG 80, 110, 176, 42
+STYLE WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+CAPTION "ヘッダー"
+ begin
+ ltext "上部余白", idiNil, 12, 7, 32, 12
+ edittext idiRHDx, 46, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "1ページ目に印刷",idiRHFirst, 90, 5, 90, 12, WS_TABONLY
+ pushbutton "ページ番号印刷", idiRHInsertPage, 13, 22, 64, 14, WS_TABONLY
+ pushbutton "消去", idiRHClear, 89, 22, 30, 14, WS_TABONLY
+ defpushbutton "確認", idiOk, 131, 22, 30, 14, WS_TABONLY
+ end
+
+dlgFooter DIALOG 80, 110, 176, 42
+STYLE WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE
+CAPTION "フッター"
+ begin
+ ltext "下部余白", idiNil, 12, 7, 32, 12
+ edittext idiRHDx, 46, 5, 30, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ checkbox "1ページ目に印刷",idiRHFirst, 90, 5, 90, 12, WS_TABONLY
+ pushbutton "ページ番号印刷", idiRHInsertPage, 12, 22, 64, 14, WS_TABONLY
+ pushbutton "消去", idiRHClear, 89, 22, 30, 14, WS_TABONLY
+ defpushbutton "確認", idiOk, 131, 22, 30, 14, WS_TABONLY
+ end
+
+dlgTabs DIALOG 26, 41, 278, 97
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION | WS_SYSMENU
+CAPTION "タブ"
+ begin
+ ltext "タブ位置", idiNil, 3, 7, 40, 12
+ ltext "タブ位置", idiNil, 3, 42, 40, 12
+ ltext "デシマル", idiNil, 3, 22, 40, 12
+ ltext "デシマル", idiNil, 3, 57, 40, 12
+ edittext idiTabPos0, 45, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec0, 51, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos1, 83, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec1, 89, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos2, 121, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec2, 127, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos3, 159, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec3, 165, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos4, 197, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec4, 203, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos5, 235, 5, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec5, 241, 20, 18, 12, WS_TABONLY
+ edittext idiTabPos6, 45, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec6, 51, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos7, 83, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec7, 89, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos8, 121, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec8, 127, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos9, 159, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec9, 165, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos0, 197, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec10,203, 55, 18, 12, WS_TABONLY
+ edittext idiTabPos11, 235, 40, 38, 12, WS_TABONLY | ES_AUTOHSCROLL
+ checkbox ".", idiTabDec11,241, 55, 18, 12, WS_TABONLY
+ defpushbutton "確認", idiOk, 44, 75, 50, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 114, 75, 50, 14, WS_TABONLY
+ pushbutton "クリア", idiTabClearAll, 184, 75, 50, 14, WS_TABONLY
+ end
+
+
+#ifdef KINTL /* Kanji/International version */
+
+dlgDivision DIALOG 26, 10, 126, 128
+
+#else
+
+dlgDivision DIALOG 26, 20, 160, 90
+
+#endif /* International version */
+
+STYLE WS_POPUP | WS_DLGFRAME
+ begin
+ ltext "ページ番号初期値", idiNil, 8, 7, 64, 12
+ edittext idiDivPNStart, 82, 5, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ groupbox "マージン", idiNil, 4, 25, 72, 75
+ ltext "左側", idiNil, 10, 40, 16, 12
+ edittext idiDivLMarg, 30, 38, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "右側", idiNil, 10, 54, 16, 12
+ edittext idiDivRMarg, 30, 52, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "上部", idiNil, 10, 68, 16, 12
+ edittext idiDivTMarg, 30, 66, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+ ltext "下部", idiNil, 10, 82, 16, 12
+ edittext idiDivBMarg, 30, 80, 40, 12, WS_TABSTOP | ES_AUTOHSCROLL
+
+#ifdef INTL /* International version */
+
+ ltext "Measurements:", idiNil, 5, 84, 63, 12
+ radiobutton "inch", idiDivInch, 12, 94, 27, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "cm", idiDivCm, 44, 94, 26, 12
+
+#endif /* International version */
+#ifdef KANJI /* Kanji version */
+
+ groupbox "単位", idiNil, 82, 25, 40, 75
+ radiobutton "字数", idiDivCch, 88, 40, 27, 12, WS_TABSTOP | WS_GROUP
+ radiobutton "cm", idiDivCm, 88, 54, 19, 12
+ radiobutton "inch", idiDivInch, 88, 68, 27, 12
+
+#endif /* ifdef KANJI */
+
+ defpushbutton "確認", idiOk, 19,107, 40, 14, WS_TABONLY
+ pushbutton "取消し", idiCancel, 70,107, 40, 14, WS_TABONLY
+ end
+
+dlgBadMargins DIALOG 50, 20, 235, 65
+STYLE WS_POPUP | WS_BORDER | WS_CAPTION
+CAPTION "マージン"
+ begin
+ icon DI_EXCLAMATION, idiNil, 5, 5, 0, 0
+ ltext "マージンは以下の値より大きい数値を使用してください", idiNil, 30, 5, 200, 12
+ ltext "左側", idiNil, 30, 17, 20, 12
+ ltext "", idiBMrgLeft, 60, 17, 40, 12
+ ltext "右側", idiNil, 130, 17, 24, 12
+ ltext "", idiBMrgRight, 168, 17, 40, 12
+ ltext "上部", idiNil, 30, 29, 16, 12
+ ltext "", idiBMrgTop, 60, 29, 40, 12
+ ltext "下部", idiNil, 130, 29, 28, 12
+ ltext "", idiBMrgBottom, 168, 29, 40, 12
+ defpushbutton "確認", idiOk, 97, 44, 40, 14, WS_TABSTOP
+ end
diff --git a/private/mvdm/wow16/write/write.sed b/private/mvdm/wow16/write/write.sed
new file mode 100644
index 000000000..47c59be03
--- /dev/null
+++ b/private/mvdm/wow16/write/write.sed
@@ -0,0 +1,11 @@
+/^OBJ. = /,/^$/{
+s/^OBJ. = //
+s/^ //
+s/\\$/+/
+s/%$//
+t output
+b end
+:output
+p
+:end
+}
diff --git a/private/mvdm/wow16/write/wwactde.c b/private/mvdm/wow16/write/wwactde.c
new file mode 100644
index 000000000..72b20951a
--- /dev/null
+++ b/private/mvdm/wow16/write/wwactde.c
@@ -0,0 +1,372 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#define NOCLIPBOARD
+#define NOGDICAPMASKS
+#define NOCTLMGR
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#include <windows.h>
+
+#include "mw.h"
+#include "cmddefs.h"
+#include "dispdefs.h"
+#include "wwdefs.h"
+#include "docdefs.h"
+#include "propdefs.h"
+#include "fmtdefs.h"
+#include "printdef.h" /* printdefs.h */
+
+/* E X T E R N A L S */
+
+extern int wwCur;
+extern struct WWD rgwwd[];
+extern struct DOD (**hpdocdod)[];
+extern struct SEL selCur;
+extern int docCur;
+extern int vdocPageCache;
+extern typeCP vcpMinPageCache;
+extern typeCP vcpMacPageCache;
+extern int vipgd;
+extern struct WWD *pwwdCur;
+extern typeCP cpMinCur;
+extern typeCP cpMacCur;
+extern int docMode;
+extern int vfPictSel;
+extern int vfSizeMode;
+extern struct PAP vpapAbs;
+extern typeCP vcpLimParaCache;
+extern struct CHP vchpFetch;
+extern struct CHP vchpSel;
+extern struct FLI vfli;
+extern int ichpMacFormat;
+extern struct CHP (**vhgchpFormat)[];
+extern int wwMac;
+extern int docScrap;
+extern int docUndo;
+
+extern CHAR (**vhrgbSave)[];
+
+
+
+
+/* N E W C U R W W */
+NewCurWw(ww, fHighlight)
+int ww, fHighlight;
+ {
+ extern HWND vhWnd;
+ struct PGTB **hpgtb;
+
+ Assert( (ww >= 0) && (ww < wwMac) );
+
+ if ( wwCur != wwNil )
+ { /* Clean up from old window */
+ /* Discard the screen fonts. */
+ FreeFonts( TRUE, FALSE );
+ pwwdCur->sel = selCur;
+ }
+
+ if (ww >= 0)
+ {
+ docCur = (pwwdCur = &rgwwd[wwCur = ww])->doc;
+
+ vhWnd = pwwdCur->wwptr;
+
+/* If the new current document has no page table or has no page descriptors */
+/* in its page table, all text in the document is considered to be on */
+/* page 1 of the document. In this case, preload the cache used by */
+/* procedure CachePage. */
+ hpgtb = (**hpdocdod)[docCur].hpgtb;
+ if (hpgtb == 0 || (**hpgtb).cpgd == 0)
+ {
+ vdocPageCache = docCur;
+ vcpMinPageCache = cp0;
+ vcpMacPageCache = cpMax;
+ vipgd = -1;
+ }
+
+#ifdef ENABLE /* we now do if in ChangeWwDoc where it is more appropriate */
+/* Since we are changing windows, ensure that we don't use parameters
+ set by a search in a previous window by setting flag false */
+ vfDidSearch = false;
+ cpWall = selCur.cpLim;
+#endif
+
+/* active bit is valid only in upper panes. Means when window is active
+upper pane is active. False means lower pane is active */
+#ifdef SPLITTERS
+ if (pwwdCur->fLower)
+ rgwwd[pwwdCur->ww].fActive = fFalse;
+ else
+#endif
+ pwwdCur->fActive = fTrue;
+
+ selCur = pwwdCur->sel;
+#ifdef ENABLE
+ if (pwwdCur->fFtn)
+ { /* It's a footnote window */
+ cpMinCur = pwwdCur->cpMin;
+ cpMacCur = pwwdCur->cpMac;
+ if (fHighlight &&
+ ((selCur.cpFirst < cpMinCur) ||
+ (selCur.cpLim > cpMacCur)))
+ {
+ Select(cpMinCur, CpLastStyChar(cpMinCur));
+ }
+ }
+ else
+#endif
+#ifdef ONLINEHELP
+ if (ww == wwHelp)
+ { /* It's the help document window */
+ /* Limit cp range to the current help topic */
+ cpMinCur = pwwdCur->cpMin;
+ cpMacCur = pwwdCur->cpMac;
+ }
+ else
+#endif
+
+ if (ww == wwClipboard)
+ { /* Displaying the clipboard contents */
+ cpMinCur = cp0;
+ cpMacCur = CpMacText( docScrap );
+ Assert( docCur == docScrap );
+ goto SetWwCps;
+ }
+ else
+ { /* Normal window -- editing document, header, or footer */
+ Assert( !(pwwdCur->fEditFooter && pwwdCur->fEditHeader) );
+ ValidateHeaderFooter( docCur );
+
+ if (pwwdCur->fEditHeader)
+ {
+ extern typeCP cpMinHeader, cpMacHeader;
+
+ cpMinCur = cpMinHeader;
+ cpMacCur = cpMacHeader - ccpEol;
+ }
+ else if (pwwdCur->fEditFooter)
+ {
+ extern typeCP cpMinFooter, cpMacFooter;
+
+ cpMinCur = cpMinFooter;
+ cpMacCur = cpMacFooter - ccpEol;
+ }
+ else
+ { /* Editing document */
+ extern typeCP cpMinDocument;
+
+ cpMinCur = cpMinDocument;
+ cpMacCur = CpMacText( docCur );
+ }
+ SetWwCps:
+ cpMacCur = CpMax( cpMacCur, cpMinCur );
+ pwwdCur->cpMin = cpMinCur;
+ pwwdCur->cpMac = cpMacCur;
+ }
+ }
+#ifdef ENABLE /* wwCur change is sensed in CtrBackTrs so we don't
+ trash the cache until we really have to */
+ TrashCache(); /* Cache valid for wwCur only */
+#endif
+#ifdef ENABLE /* We only switch among doc, clipbrd, help - no need */
+ docMode = docNil; /* Invalidate page display */
+#endif
+ vfSizeMode = false;
+
+ if (selCur.cpFirst >= cp0)
+ {
+ if ((selCur.cpFirst == selCur.cpLim) && (docCur != docScrap) )
+ GetInsPtProps(selCur.cpFirst);
+ CachePara(docCur, selCur.cpFirst);
+ vfPictSel = vpapAbs.fGraphics &&
+ (selCur.cpLim == vcpLimParaCache);
+ }
+#ifdef ENABLE
+ if (fHighlight)
+ { /* Shrink heap blocks for FormatLine. Call this when it's
+ possible that the contents of the screen have gotten less complex */
+ if (ichpMacFormat > 2 * ichpMacInitFormat)
+ { /* If it's not that big, don't worry about it */
+ vfli.doc = docNil;
+ ichpMacFormat = ichpMacInitFormat;
+ FChngSizeH(vhgchpFormat, ichpMacInitFormat * cwCHP, true);
+ }
+ }
+#endif /* ENABLE */
+ }
+
+
+
+
+WwAlloc( hWnd, doc )
+HWND hWnd;
+int doc;
+{ /* Allocate a new ww entry. This is used in MEMO for the clipboard
+ and for the HELP document window. Some of the code is specific
+ to these windows (e.g. "style" scroll bars used instead of controls)
+ WARNING: The caller must set the scroll bar range 0-drMax;
+ MEMO does NOT use the windows default values and we don't set them
+ here because of the clipboard */
+
+#define dlMaxGuess 10
+
+ extern int wwMac;
+ extern int wwCur;
+ extern struct WWD rgwwd[];
+ extern struct WWD *pwwdCur;
+ extern int docScrap;
+ int ww;
+ register struct WWD *pwwd;
+
+ if (wwMac >= wwMax)
+ {
+ Assert( FALSE );
+ return wwNil;
+ }
+ pwwd = &rgwwd[ ww = wwMac ];
+
+ /* Start with all fields == 0 */
+ bltc( pwwd, 0, cwWWDclr );
+
+ pwwd->doc = doc;
+
+ /* Set the remaining fields as in [CREATEWW] WwNew */
+ if (FNoHeap( pwwd->hdndl=(struct EDL (**)[])HAllocate(dlMaxGuess * cwEDL) ))
+ return wwNil;
+ bltc( *(pwwd->hdndl), 0, dlMaxGuess * cwEDL );
+ pwwd->dlMac = pwwd->dlMax = dlMaxGuess;
+ pwwd->hHScrBar = pwwd->hVScrBar = pwwd->wwptr = hWnd;
+ pwwd->sbHbar = SB_HORZ;
+ pwwd->sbVbar = SB_VERT;
+ pwwd->fDirty = TRUE;
+ pwwd->fActive = TRUE;
+ pwwd->sel.fForward = TRUE;
+ pwwd->cpMac = CpMacText( pwwd->doc );
+ pwwd->ypFirstInval = ypMaxAll; /* See WwNew() */
+
+ wwMac++;
+
+ return ww;
+}
+
+
+
+FreeWw( ww )
+register int ww;
+{ /* Free the wwd entry for the clipboard or help window. Close up
+ rgwwd & null out wwClipboard or wwHelp, as appropriate */
+ if (ww == wwDocument)
+ {
+ Assert( FALSE );
+ return;
+ }
+
+ FreeH( rgwwd [ww].hdndl );
+ if (ww == wwClipboard)
+ wwClipboard = wwNil;
+#ifdef ONLINEHELP
+ else if (ww == wwHelp)
+ wwHelp = wwNil;
+#endif
+ else
+ Assert( FALSE );
+
+
+ if (ww < --wwMac)
+ { /* Left hole in wwd structure, close it up */
+ bltbyte( &rgwwd[ ww + 1], &rgwwd[ ww ],
+ sizeof( struct WWD ) * (wwMac - ww) );
+
+ if (wwClipboard > ww)
+ wwClipboard--;
+#ifdef ONLINEHELP
+ else if (wwHelp > ww)
+ wwHelp--;
+#endif
+ else
+ Assert( FALSE );
+ }
+}
+
+
+
+
+
+#ifdef CASHMERE
+/* C L O S E W W */
+CloseWw(ww)
+int ww;
+{ /* Close a window */
+ struct WWD *pwwd, *pwwdT;
+ int wwCurNew = wwCur;
+ int wwT;
+ int cdl;
+/* note ww and wwCur are not necessarily the same because of the scrap */
+ if (wwCur > 0)
+ blt(&selCur, &(rgwwd[wwCur].sel), cwSEL);
+ pwwd = &rgwwd[ww];
+ --wwMac;
+ if (!pwwd->fLower && !pwwd->fSplit)
+ {
+ KillDoc(pwwd->doc);
+ if (wwCurNew >= wwMac)
+ wwCurNew = wwMac - 1;
+ }
+ else
+ { /* split or lower */
+ wwCurNew = pwwd->ww;
+ }
+
+/* Free up the space that was used by this window */
+ FreeH(pwwd->hdndl);
+ /* Deallocate part of the emergency space reserved for save operations
+ since we now have one less window and thus one less potential
+ save to do. */
+ FChngSizeH(vhrgbSave, max((cwSaveAlloc+(wwMac-1)*cwHeapMinPerWindow),
+ cwSaveAlloc), true);
+
+
+/* Close up the gap in wwd's */
+ if (ww != wwMac && wwMac > 0)
+ blt(pwwd + 1, pwwd, cwWWD * (wwMac - ww));
+ else
+ rgwwd[wwMac].wwptr = 0l;
+
+ if (wwCurNew > ww)
+ --wwCurNew;
+
+ /* Update links to windows above the closure */
+ for (pwwd = &rgwwd[0], wwT = 0; wwT < wwMac; pwwd++, wwT++)
+ {
+ if ((pwwd->fSplit || pwwd->fLower) && pwwd->ww > ww)
+ pwwd->ww--;
+ }
+
+/* Don't make the Clipboard window into the current window */
+ if (wwCurNew >= 0)
+ {
+ if (rgwwd[wwCurNew].doc == docScrap)
+ {
+ if (wwCurNew > 0) /* Try the one before this */
+ wwCurNew--;
+ else if (wwMac > 1) /* 0 is scrap, try higher one */
+ wwCurNew++;
+ else
+ goto NoWw;
+ }
+ NewCurWw(wwCurNew, true);
+ }
+ else
+ {
+NoWw: wwCur = -1;
+ }
+ /* Really stomp this sucker! */
+ ClobberDoc(docUndo, docNil, cp0, cp0);
+ NoUndo();
+}
+#endif /* CASHMERE */
diff --git a/private/mvdm/wow16/write/wwdefs.h b/private/mvdm/wow16/write/wwdefs.h
new file mode 100644
index 000000000..10777662c
--- /dev/null
+++ b/private/mvdm/wow16/write/wwdefs.h
@@ -0,0 +1,107 @@
+/************************************************************/
+/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
+/************************************************************/
+
+#ifdef ONLINEHELP
+#define wwMax 3
+#else
+#define wwMax 2
+#endif
+
+#define wwNil (15)
+
+#define itrMaxCache 32
+
+/* Window create modes */
+#define wcmHoriz 0
+#define wcmVert 1
+#define wcmFtn 2
+
+typeCP CpSelectCursor(), CpGetCache(), CpHintCache(), CpParaBounds();
+typeCP CpFirstSty(), CpLimSty(), CpBeginLine(), CpFromDlTc();
+typeCP CpFromCursor(), CpEdge(), CpInsPoint();
+typeCP CpFirstFtn(), CpMacText();
+
+/* WWD reorg. CS Sept 1 */
+struct WWD
+ { /* Window descriptor */
+ unsigned char fDirty : 1; /* ww needs updating */
+ unsigned char fCpBad : 1; /* cpFirst needs updating */
+ unsigned char fWrite : 1; /* Can edit this window */
+/* true iff lower of a split pair. False means window is not split */
+ unsigned char fLower : 1;
+/* true means window is split and this is the upper pane */
+ unsigned char fSplit : 1;
+/* in the top window false means the bottom half has the active selection */
+/* used for window activation. remembered at deactivation */
+ unsigned char fActive : 1;
+ unsigned char fFtn : 1; /* This is a footnote window */
+ unsigned char fRuler : 1; /* Draw tab and margin ruler */
+#ifdef SPLITTERS /* Only if we have split windows */
+/* points to lower ww if fSplit, to upper ww if fLower */
+ unsigned char ww;
+#endif
+ unsigned char fEditHeader: 1; /* We are editing the running head */
+ unsigned char fEditFooter: 1; /* We are editing the running foot */
+
+ unsigned char dcpDepend; /* hot spot for first line */
+ unsigned char dlMac; /* number of actual dls for this ww */
+ unsigned char dlMax; /* number of allocated dls for this ww */
+ unsigned char doc;
+
+ int xpMac; /* window rel position of last displayable pixel +1 */
+/* note: area starts at: xpSelBar, see dispdefs */
+ int ichCpFirst; /* ich within cpFirst */
+
+/* first pixel pos to display; determines horizontal scroll */
+ int xpMin;
+/* these will be changed to yp's later */
+ int ypMac; /* pos of bottom of window */
+ int ypMin; /* pos of top of writeable area of window */
+
+/* invalid band in the window */
+ int ypFirstInval;
+ int ypLastInval;
+
+ typeCP cpFirst; /* First cp in ww */
+ typeCP cpMin; /* Min cp for this ww if fFtn */
+ typeCP cpMac; /* Mac cp for this ww if fFtn */
+ unsigned char drElevator; /* dr where elevator is currently */
+ unsigned char fScrap : 1; /* on for scrap window */
+/* new fields, consolidating various arrays */
+ struct SEL sel; /* current selection in ww */
+/* must be at end of struct, see cwWWDclr kludge below */
+
+#ifndef SAND /* MEMO fields */
+ HWND wwptr; /* window handle */
+ HWND hHScrBar; /* Handle to horiz scroll bar */
+ HWND hVScrBar; /* Handle to vert scroll bar */
+ HDC hDC; /* Handle to device context */
+ unsigned char sbHbar; /* Type of horiz scroll bar (SB_CTL or SB_HORIZ) */
+ unsigned char sbVbar; /* Type of vert scroll bar (SB_CTL or SB_VERT) */
+#else
+ WINDOWPTR wwptr; /* Sand window handle */
+#endif
+/* heap pointer to array of edl's. */
+ struct EDL (**hdndl)[];
+ };
+
+#define cwWWD (sizeof(struct WWD) / sizeof(int))
+#define cwWWDclr ((sizeof(struct WWD) - (4*sizeof(HANDLE)) - (2*sizeof(char)) - sizeof(int)) / sizeof(int))
+
+/* These macros will gain code size advantage from the fixed usage
+ of rgwwd in MEMO, while permitting easy conversion to multiple
+ document windows in CASHMERE. Only code that does not have to support both
+ the clipboard and the document should use these macros */
+
+extern int wwClipboard;
+
+#ifdef ONLINEHELP
+extern int wwHelp;
+#define wwdHelp (rgwwd [ wwHelp ])
+#endif
+
+#define wwDocument 0
+
+#define wwdCurrentDoc (rgwwd [wwDocument])
+#define wwdClipboard (rgwwd [wwClipboard])